From b2f5af5259ec708fe1a19edca869a9cad27c2c29 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Thu, 26 Jan 2006 21:53:03 +0000 Subject: [PATCH] temp commit git-svn-id: svn://anonsvn.mit.edu/krb5/users/tlyu/branches/mechglue@17626 dc483132-0cff-0310-8789-dd5450dbe970 --- mechglue/.Sanitize | 34 + mechglue/README | 1185 ++ mechglue/doc/.Sanitize | 46 + mechglue/doc/.cvsignore | 20 + mechglue/doc/ChangeLog | 924 ++ mechglue/doc/Makefile | 183 + mechglue/doc/admin.texinfo | 3782 +++++ mechglue/doc/api/.Sanitize | 48 + mechglue/doc/api/.cvsignore | 10 + mechglue/doc/api/ChangeLog | 192 + mechglue/doc/api/Makefile | 40 + mechglue/doc/api/ccache.tex | 239 + mechglue/doc/api/errors.tex | 310 + mechglue/doc/api/fancyheadings.sty | 233 + mechglue/doc/api/fixunder.sty | 48 + mechglue/doc/api/free.tex | 266 + mechglue/doc/api/functions.sty | 70 + mechglue/doc/api/intro.tex | 299 + mechglue/doc/api/keytab.tex | 221 + mechglue/doc/api/krb5.ist | 26 + mechglue/doc/api/krb5.tex | 1827 +++ mechglue/doc/api/krb5idx.sty | 10 + mechglue/doc/api/libdes.tex | 38 + mechglue/doc/api/libos.tex | 486 + mechglue/doc/api/library.tex | 114 + mechglue/doc/api/rcache.tex | 207 + mechglue/doc/api/tables.tex | 79 + mechglue/doc/bug-report.texinfo | 10 + mechglue/doc/build.texinfo | 1029 ++ mechglue/doc/coding-style | 563 + mechglue/doc/copyright.texinfo | 203 + mechglue/doc/definitions.texinfo | 193 + mechglue/doc/dnssrv.texinfo | 97 + mechglue/doc/dnstxt.texinfo | 38 + mechglue/doc/document-list.texinfo | 24 + mechglue/doc/glossary.texinfo | 64 + mechglue/doc/implement/.Sanitize | 46 + mechglue/doc/implement/.cvsignore | 7 + mechglue/doc/implement/ChangeLog | 20 + mechglue/doc/implement/Makefile | 38 + mechglue/doc/implement/ccache-i.tex | 224 + mechglue/doc/implement/cksum-i.tex | 31 + mechglue/doc/implement/crc-32-i.tex | 20 + mechglue/doc/implement/encrypt-i.tex | 164 + mechglue/doc/implement/fancyheadings.sty | 233 + mechglue/doc/implement/fixunder.sty | 48 + mechglue/doc/implement/functions.sty | 70 + mechglue/doc/implement/implement.tex | 94 + mechglue/doc/implement/kdb-i.tex | 242 + mechglue/doc/implement/keytab-i.tex | 204 + mechglue/doc/implement/libos-i.tex | 34 + mechglue/doc/implement/rcache-i.tex | 142 + mechglue/doc/implementor.texinfo | 1192 ++ mechglue/doc/install-old.texi | 2239 +++ mechglue/doc/install.texinfo | 1445 ++ mechglue/doc/kadm5/adb-unit-test.tex | 134 + mechglue/doc/kadm5/api-funcspec.tex | 2015 +++ mechglue/doc/kadm5/api-server-design.tex | 1042 ++ mechglue/doc/kadm5/api-unit-test.tex | 2679 ++++ mechglue/doc/kadm5/fullpage.sty | 9 + mechglue/doc/kadm5/rcsid.sty | 5 + mechglue/doc/kadm5acl.texinfo | 113 + mechglue/doc/kadmin/.Sanitize | 33 + mechglue/doc/kadmin/ChangeLog | 14 + mechglue/doc/kadmin/README | 46 + .../draft-ietf-cat-kerb-chg-password-02.txt | 311 + mechglue/doc/kadmin/kadmin.protocol | 382 + mechglue/doc/kadmin/kpasswd.protocol | 303 + mechglue/doc/kdcconf.texinfo | 24 + mechglue/doc/krb4-xrealm.txt | 143 + mechglue/doc/krb425.texinfo | 317 + mechglue/doc/krb5-protocol/.Sanitize | 35 + mechglue/doc/krb5-protocol/3-des.txt | 81 + mechglue/doc/krb5-protocol/krb5.constants | 156 + mechglue/doc/krb5-protocol/rfc1510.errata | 105 + mechglue/doc/krb5-protocol/rfc1510.txt | 6275 ++++++++ mechglue/doc/krb5conf.texinfo | 83 + mechglue/doc/man2html | 608 + mechglue/doc/man2html.M | 761 + mechglue/doc/man2ps | 60 + mechglue/doc/man2ps.M | 50 + mechglue/doc/old-V4-docs/.Sanitize | 36 + mechglue/doc/old-V4-docs/README | 4 + mechglue/doc/old-V4-docs/installation.PS | 2338 +++ mechglue/doc/old-V4-docs/installation.mss | 681 + mechglue/doc/old-V4-docs/operation.PS | 2669 ++++ mechglue/doc/old-V4-docs/operation.mss | 799 + mechglue/doc/procedures.txt | 157 + mechglue/doc/rpc/design.tex | 1037 ++ mechglue/doc/salts.texinfo | 19 + mechglue/doc/send-pr.texinfo | 144 + mechglue/doc/support-enc.texinfo | 33 + mechglue/doc/texinfo-suppl.tex | 7 + mechglue/doc/texinfo.tex | 4355 ++++++ mechglue/doc/thread-safe.txt | 257 + mechglue/doc/threads.txt | 101 + mechglue/doc/user-guide.texinfo | 1700 +++ mechglue/src/.Sanitize | 65 + mechglue/src/.rconf | 48 + mechglue/src/BADSYMS | 282 + mechglue/src/ChangeLog | 3114 ++++ mechglue/src/Makefile.in | 586 + mechglue/src/aclocal.m4 | 1795 +++ mechglue/src/appl/.Sanitize | 48 + mechglue/src/appl/.rconf | 4 + mechglue/src/appl/ChangeLog | 101 + mechglue/src/appl/Makefile.in | 7 + mechglue/src/appl/bsd/.Sanitize | 56 + mechglue/src/appl/bsd/ChangeLog | 3060 ++++ mechglue/src/appl/bsd/Makefile.in | 175 + mechglue/src/appl/bsd/compat_recv.c | 581 + mechglue/src/appl/bsd/configure.in | 195 + mechglue/src/appl/bsd/defines.h | 100 + mechglue/src/appl/bsd/forward.c | 77 + mechglue/src/appl/bsd/getdtablesize.c | 19 + mechglue/src/appl/bsd/kcmd.c | 1369 ++ mechglue/src/appl/bsd/klogind.M | 196 + mechglue/src/appl/bsd/krcp.c | 1447 ++ mechglue/src/appl/bsd/krlogin.c | 1857 +++ mechglue/src/appl/bsd/krlogind.c | 1575 ++ mechglue/src/appl/bsd/krsh.c | 635 + mechglue/src/appl/bsd/krshd.c | 2054 +++ mechglue/src/appl/bsd/kshd.M | 209 + mechglue/src/appl/bsd/login.M | 97 + mechglue/src/appl/bsd/login.c | 2502 ++++ mechglue/src/appl/bsd/loginpaths.h | 113 + mechglue/src/appl/bsd/rcp.M | 160 + mechglue/src/appl/bsd/rlogin.M | 160 + mechglue/src/appl/bsd/rpaths.h | 31 + mechglue/src/appl/bsd/rsh.M | 173 + mechglue/src/appl/bsd/setenv.c | 166 + mechglue/src/appl/bsd/v4rcp.M | 52 + mechglue/src/appl/bsd/v4rcp.c | 1108 ++ mechglue/src/appl/configure.in | 21 + mechglue/src/appl/gss-sample/.Sanitize | 40 + mechglue/src/appl/gss-sample/ChangeLog | 477 + mechglue/src/appl/gss-sample/Makefile.in | 45 + mechglue/src/appl/gss-sample/README | 163 + mechglue/src/appl/gss-sample/gss-client.c | 808 + mechglue/src/appl/gss-sample/gss-misc.c | 425 + mechglue/src/appl/gss-sample/gss-misc.h | 60 + mechglue/src/appl/gss-sample/gss-server.c | 793 + mechglue/src/appl/gssftp/.Sanitize | 40 + mechglue/src/appl/gssftp/ChangeLog | 129 + mechglue/src/appl/gssftp/Makefile.in | 6 + mechglue/src/appl/gssftp/README.gssftp | 45 + mechglue/src/appl/gssftp/arpa/.Sanitize | 34 + mechglue/src/appl/gssftp/arpa/ChangeLog | 5 + mechglue/src/appl/gssftp/arpa/ftp.h | 128 + mechglue/src/appl/gssftp/arpa/telnet.h | 310 + mechglue/src/appl/gssftp/configure.in | 71 + mechglue/src/appl/gssftp/ftp/.Sanitize | 51 + mechglue/src/appl/gssftp/ftp/ChangeLog | 740 + mechglue/src/appl/gssftp/ftp/Makefile.in | 101 + mechglue/src/appl/gssftp/ftp/cmds.c | 2523 ++++ mechglue/src/appl/gssftp/ftp/cmdtab.c | 209 + mechglue/src/appl/gssftp/ftp/domacro.c | 162 + mechglue/src/appl/gssftp/ftp/ftp.M | 1131 ++ mechglue/src/appl/gssftp/ftp/ftp.c | 2365 +++ mechglue/src/appl/gssftp/ftp/ftp_var.h | 284 + mechglue/src/appl/gssftp/ftp/getpass.c | 154 + mechglue/src/appl/gssftp/ftp/glob.c | 784 + mechglue/src/appl/gssftp/ftp/main.c | 633 + mechglue/src/appl/gssftp/ftp/pathnames.h | 37 + mechglue/src/appl/gssftp/ftp/pclose.c | 128 + mechglue/src/appl/gssftp/ftp/radix.c | 166 + mechglue/src/appl/gssftp/ftp/ruserpass.c | 296 + mechglue/src/appl/gssftp/ftp/secure.c | 481 + mechglue/src/appl/gssftp/ftp/secure.h | 15 + mechglue/src/appl/gssftp/ftpd/.Sanitize | 45 + mechglue/src/appl/gssftp/ftpd/CHANGES | 31 + mechglue/src/appl/gssftp/ftpd/ChangeLog | 920 ++ mechglue/src/appl/gssftp/ftpd/Makefile.in | 107 + mechglue/src/appl/gssftp/ftpd/ftpcmd.y | 1557 ++ mechglue/src/appl/gssftp/ftpd/ftpd.M | 513 + mechglue/src/appl/gssftp/ftpd/ftpd.c | 3000 ++++ mechglue/src/appl/gssftp/ftpd/ftpd_var.h | 97 + mechglue/src/appl/gssftp/ftpd/logwtmp.c | 90 + mechglue/src/appl/gssftp/ftpd/pathnames.h | 36 + mechglue/src/appl/gssftp/ftpd/popen.c | 194 + mechglue/src/appl/gssftp/ftpd/secure.h | 19 + mechglue/src/appl/gssftp/ftpd/vers.c | 38 + mechglue/src/appl/sample/.Sanitize | 39 + mechglue/src/appl/sample/ChangeLog | 60 + mechglue/src/appl/sample/Makefile.in | 5 + mechglue/src/appl/sample/sample.h | 36 + mechglue/src/appl/sample/sclient/.Sanitize | 38 + mechglue/src/appl/sample/sclient/ChangeLog | 160 + mechglue/src/appl/sample/sclient/Makefile.in | 19 + mechglue/src/appl/sample/sclient/sclient.M | 38 + mechglue/src/appl/sample/sclient/sclient.c | 253 + mechglue/src/appl/sample/sserver/.Sanitize | 38 + mechglue/src/appl/sample/sserver/ChangeLog | 152 + mechglue/src/appl/sample/sserver/Makefile.in | 19 + mechglue/src/appl/sample/sserver/sserver.M | 130 + mechglue/src/appl/sample/sserver/sserver.c | 237 + mechglue/src/appl/simple/.Sanitize | 39 + mechglue/src/appl/simple/ChangeLog | 64 + mechglue/src/appl/simple/Makefile.in | 5 + mechglue/src/appl/simple/client/.Sanitize | 37 + mechglue/src/appl/simple/client/ChangeLog | 175 + mechglue/src/appl/simple/client/Makefile.in | 19 + mechglue/src/appl/simple/client/sim_client.c | 332 + mechglue/src/appl/simple/server/.Sanitize | 37 + mechglue/src/appl/simple/server/ChangeLog | 141 + mechglue/src/appl/simple/server/Makefile.in | 20 + mechglue/src/appl/simple/server/sim_server.c | 279 + mechglue/src/appl/simple/simple.h | 32 + mechglue/src/appl/telnet/.Sanitize | 47 + mechglue/src/appl/telnet/.rconf | 1 + mechglue/src/appl/telnet/ChangeLog | 73 + mechglue/src/appl/telnet/Config.generic | 830 ++ mechglue/src/appl/telnet/Makefile.in | 5 + mechglue/src/appl/telnet/README | 679 + mechglue/src/appl/telnet/arpa/.Sanitize | 32 + mechglue/src/appl/telnet/arpa/telnet.h | 327 + mechglue/src/appl/telnet/configure.in | 175 + mechglue/src/appl/telnet/kern.diff | 308 + mechglue/src/appl/telnet/libtelnet/.Sanitize | 70 + mechglue/src/appl/telnet/libtelnet/ChangeLog | 756 + .../src/appl/telnet/libtelnet/Makefile.4.4 | 33 + .../appl/telnet/libtelnet/Makefile.generic | 67 + .../src/appl/telnet/libtelnet/Makefile.in | 140 + .../src/appl/telnet/libtelnet/auth-proto.h | 107 + mechglue/src/appl/telnet/libtelnet/auth.c | 669 + mechglue/src/appl/telnet/libtelnet/auth.h | 85 + .../src/appl/telnet/libtelnet/enc-proto.h | 144 + mechglue/src/appl/telnet/libtelnet/enc_des.c | 780 + mechglue/src/appl/telnet/libtelnet/encrypt.c | 1014 ++ mechglue/src/appl/telnet/libtelnet/encrypt.h | 103 + mechglue/src/appl/telnet/libtelnet/forward.c | 78 + mechglue/src/appl/telnet/libtelnet/genget.c | 102 + mechglue/src/appl/telnet/libtelnet/getent.c | 71 + mechglue/src/appl/telnet/libtelnet/getopt.c | 126 + mechglue/src/appl/telnet/libtelnet/gettytab.c | 307 + mechglue/src/appl/telnet/libtelnet/gettytab.h | 120 + mechglue/src/appl/telnet/libtelnet/herror.c | 68 + mechglue/src/appl/telnet/libtelnet/kerberos.c | 744 + .../src/appl/telnet/libtelnet/kerberos5.c | 898 ++ .../src/appl/telnet/libtelnet/key-proto.h | 66 + mechglue/src/appl/telnet/libtelnet/krb5forw.h | 4 + mechglue/src/appl/telnet/libtelnet/mem.c | 190 + .../src/appl/telnet/libtelnet/misc-proto.h | 88 + mechglue/src/appl/telnet/libtelnet/misc.c | 96 + mechglue/src/appl/telnet/libtelnet/misc.h | 46 + mechglue/src/appl/telnet/libtelnet/parsetos.c | 42 + mechglue/src/appl/telnet/libtelnet/setenv.c | 172 + mechglue/src/appl/telnet/libtelnet/setsid.c | 49 + mechglue/src/appl/telnet/libtelnet/spx.c | 594 + .../src/appl/telnet/libtelnet/strcasecmp.c | 121 + mechglue/src/appl/telnet/libtelnet/strchr.c | 47 + mechglue/src/appl/telnet/libtelnet/strdup.c | 62 + mechglue/src/appl/telnet/libtelnet/strerror.c | 69 + mechglue/src/appl/telnet/libtelnet/strftime.c | 307 + mechglue/src/appl/telnet/libtelnet/strrchr.c | 47 + mechglue/src/appl/telnet/stty.diff | 72 + mechglue/src/appl/telnet/telnet.state | 80 + mechglue/src/appl/telnet/telnet/.Sanitize | 59 + mechglue/src/appl/telnet/telnet/ChangeLog | 614 + mechglue/src/appl/telnet/telnet/Makefile.4.4 | 73 + .../src/appl/telnet/telnet/Makefile.generic | 89 + mechglue/src/appl/telnet/telnet/Makefile.in | 110 + mechglue/src/appl/telnet/telnet/authenc.c | 115 + mechglue/src/appl/telnet/telnet/commands.c | 3191 ++++ mechglue/src/appl/telnet/telnet/defines.h | 61 + mechglue/src/appl/telnet/telnet/externs.h | 531 + mechglue/src/appl/telnet/telnet/fdset.h | 49 + mechglue/src/appl/telnet/telnet/general.h | 45 + mechglue/src/appl/telnet/telnet/main.c | 350 + mechglue/src/appl/telnet/telnet/network.c | 179 + mechglue/src/appl/telnet/telnet/ring.c | 367 + mechglue/src/appl/telnet/telnet/ring.h | 98 + mechglue/src/appl/telnet/telnet/sys_bsd.c | 1208 ++ mechglue/src/appl/telnet/telnet/telnet.0.ps | 1008 ++ mechglue/src/appl/telnet/telnet/telnet.0.txt | 718 + mechglue/src/appl/telnet/telnet/telnet.1 | 1339 ++ mechglue/src/appl/telnet/telnet/telnet.c | 2756 ++++ mechglue/src/appl/telnet/telnet/terminal.c | 241 + mechglue/src/appl/telnet/telnet/tmac.doc | 4102 +++++ mechglue/src/appl/telnet/telnet/tn3270.c | 410 + mechglue/src/appl/telnet/telnet/types.h | 52 + mechglue/src/appl/telnet/telnet/utilities.c | 949 ++ mechglue/src/appl/telnet/telnetd/.Sanitize | 57 + mechglue/src/appl/telnet/telnetd/ChangeLog | 815 + mechglue/src/appl/telnet/telnetd/ISSUES | 7 + mechglue/src/appl/telnet/telnetd/Makefile.4.4 | 36 + .../src/appl/telnet/telnetd/Makefile.generic | 71 + mechglue/src/appl/telnet/telnetd/Makefile.in | 144 + mechglue/src/appl/telnet/telnetd/authenc.c | 86 + mechglue/src/appl/telnet/telnetd/defs.h | 323 + mechglue/src/appl/telnet/telnetd/ext.h | 225 + mechglue/src/appl/telnet/telnetd/global.c | 46 + mechglue/src/appl/telnet/telnetd/pathnames.h | 55 + mechglue/src/appl/telnet/telnetd/slc.c | 491 + mechglue/src/appl/telnet/telnetd/state.c | 1675 +++ mechglue/src/appl/telnet/telnetd/sys_term.c | 1475 ++ .../src/appl/telnet/telnetd/telnetd-ktd.c | 1462 ++ mechglue/src/appl/telnet/telnetd/telnetd.0.ps | 555 + .../src/appl/telnet/telnetd/telnetd.0.txt | 322 + mechglue/src/appl/telnet/telnetd/telnetd.8 | 631 + mechglue/src/appl/telnet/telnetd/telnetd.c | 1714 +++ mechglue/src/appl/telnet/telnetd/telnetd.h | 48 + mechglue/src/appl/telnet/telnetd/termio-tn.c | 33 + mechglue/src/appl/telnet/telnetd/termios-tn.c | 35 + mechglue/src/appl/telnet/telnetd/termstat.c | 652 + mechglue/src/appl/telnet/telnetd/utility.c | 1300 ++ mechglue/src/appl/user_user/.Sanitize | 38 + mechglue/src/appl/user_user/ChangeLog | 174 + mechglue/src/appl/user_user/Makefile.in | 25 + mechglue/src/appl/user_user/client.c | 278 + mechglue/src/appl/user_user/server.c | 231 + mechglue/src/clients/.Sanitize | 40 + mechglue/src/clients/ChangeLog | 128 + mechglue/src/clients/Makefile.in | 55 + mechglue/src/clients/configure.in | 24 + mechglue/src/clients/kcpytkt/ChangeLog | 4 + mechglue/src/clients/kcpytkt/Makefile.in | 28 + mechglue/src/clients/kcpytkt/kcpytkt.M | 37 + mechglue/src/clients/kcpytkt/kcpytkt.c | 182 + mechglue/src/clients/kdeltkt/ChangeLog | 8 + mechglue/src/clients/kdeltkt/Makefile.in | 28 + mechglue/src/clients/kdeltkt/kdeltkt.M | 37 + mechglue/src/clients/kdeltkt/kdeltkt.c | 174 + mechglue/src/clients/kdestroy/.Sanitize | 38 + mechglue/src/clients/kdestroy/ChangeLog | 172 + mechglue/src/clients/kdestroy/Makefile.in | 27 + mechglue/src/clients/kdestroy/kdestroy.M | 104 + mechglue/src/clients/kdestroy/kdestroy.c | 227 + mechglue/src/clients/kinit/.Sanitize | 38 + mechglue/src/clients/kinit/ChangeLog | 394 + mechglue/src/clients/kinit/Makefile.in | 30 + mechglue/src/clients/kinit/kinit.M | 200 + mechglue/src/clients/kinit/kinit.c | 1129 ++ mechglue/src/clients/klist/.Sanitize | 38 + mechglue/src/clients/klist/ChangeLog | 376 + mechglue/src/clients/klist/Makefile.in | 42 + mechglue/src/clients/klist/klist.M | 154 + mechglue/src/clients/klist/klist.c | 837 ++ mechglue/src/clients/kpasswd/ChangeLog | 121 + mechglue/src/clients/kpasswd/Makefile.in | 29 + mechglue/src/clients/kpasswd/kpasswd.M | 75 + mechglue/src/clients/kpasswd/kpasswd.c | 150 + mechglue/src/clients/kpasswd/ksetpwd.c | 313 + mechglue/src/clients/ksu/.Sanitize | 43 + mechglue/src/clients/ksu/ChangeLog | 557 + mechglue/src/clients/ksu/Makefile.in | 90 + mechglue/src/clients/ksu/authorization.c | 730 + mechglue/src/clients/ksu/ccache.c | 819 + mechglue/src/clients/ksu/heuristic.c | 769 + mechglue/src/clients/ksu/krb_auth_su.c | 584 + mechglue/src/clients/ksu/ksu.M | 481 + mechglue/src/clients/ksu/ksu.h | 254 + mechglue/src/clients/ksu/main.c | 997 ++ mechglue/src/clients/ksu/setenv.c | 171 + mechglue/src/clients/ksu/xmalloc.c | 68 + mechglue/src/clients/kvno/ChangeLog | 89 + mechglue/src/clients/kvno/Makefile.in | 27 + mechglue/src/clients/kvno/kvno.M | 76 + mechglue/src/clients/kvno/kvno.c | 265 + mechglue/src/config-files/.Sanitize | 43 + mechglue/src/config-files/ChangeLog | 227 + mechglue/src/config-files/Makefile.in | 12 + .../src/config-files/convert-config-files | 84 + mechglue/src/config-files/kdc.conf | 13 + mechglue/src/config-files/kdc.conf.M | 241 + mechglue/src/config-files/krb5.conf | 33 + mechglue/src/config-files/krb5.conf.M | 555 + mechglue/src/config-files/services.append | 32 + mechglue/src/config/.Sanitize | 49 + mechglue/src/config/ChangeLog | 1489 ++ mechglue/src/config/ac-archive/README | 51 + mechglue/src/config/ac-archive/acx_pthread.m4 | 239 + mechglue/src/config/config.guess | 1410 ++ mechglue/src/config/config.sub | 1510 ++ mechglue/src/config/install-sh | 295 + mechglue/src/config/lib.in | 164 + mechglue/src/config/libnover.in | 112 + mechglue/src/config/libobj.in | 39 + mechglue/src/config/mkinstalldirs | 40 + mechglue/src/config/move-if-changed | 17 + mechglue/src/config/post.in | 183 + mechglue/src/config/pre.in | 546 + mechglue/src/config/ren2long | 9 + mechglue/src/config/ren2long.awk | 75 + mechglue/src/config/rm.bat | 32 + mechglue/src/config/shlib.conf | 448 + mechglue/src/config/win-post.in | 102 + mechglue/src/config/win-pre.in | 226 + mechglue/src/config/winexclude.sed | 20 + mechglue/src/configure.in | 550 + mechglue/src/gen-manpages/ChangeLog | 43 + mechglue/src/gen-manpages/Makefile.in | 9 + mechglue/src/gen-manpages/header.doc | 1 + mechglue/src/gen-manpages/k5login.M | 55 + mechglue/src/gen-manpages/kerberos.M | 143 + mechglue/src/include/.Sanitize | 46 + mechglue/src/include/.rconf | 1 + mechglue/src/include/ChangeLog | 3236 ++++ mechglue/src/include/Makefile.in | 76 + mechglue/src/include/cm.h | 41 + mechglue/src/include/fake-addrinfo.h | 233 + mechglue/src/include/foreachaddr.h | 64 + mechglue/src/include/k5-int.h | 1895 +++ mechglue/src/include/k5-platform.h | 715 + mechglue/src/include/k5-thread.h | 777 + mechglue/src/include/k5-util.h | 87 + mechglue/src/include/kerberosIV/.Sanitize | 56 + mechglue/src/include/kerberosIV/ChangeLog | 567 + mechglue/src/include/kerberosIV/Makefile.in | 22 + mechglue/src/include/kerberosIV/addr_comp.h | 52 + .../src/include/kerberosIV/admin_server.h | 58 + mechglue/src/include/kerberosIV/des.h | 195 + mechglue/src/include/kerberosIV/kadm.h | 194 + mechglue/src/include/kerberosIV/kdc.h | 55 + mechglue/src/include/kerberosIV/klog.h | 57 + mechglue/src/include/kerberosIV/kparse.h | 106 + mechglue/src/include/kerberosIV/krb.h | 787 + mechglue/src/include/kerberosIV/krb_db.h | 119 + mechglue/src/include/kerberosIV/krbports.h | 27 + .../src/include/kerberosIV/lsb_addr_cmp.h | 47 + .../src/include/kerberosIV/mit-copyright.h | 23 + mechglue/src/include/kerberosIV/prot.h | 323 + mechglue/src/include/krb5.hin | 2550 ++++ mechglue/src/include/krb5/.Sanitize | 50 + mechglue/src/include/krb5/.rconf | 5 + mechglue/src/include/krb5/ChangeLog | 1309 ++ mechglue/src/include/krb5/Makefile.in | 74 + mechglue/src/include/krb5/adm.h | 217 + mechglue/src/include/krb5/adm_defs.h | 209 + mechglue/src/include/krb5/adm_proto.h | 132 + mechglue/src/include/krb5/copyright.h | 40 + mechglue/src/include/krb5/kdb.h | 498 + mechglue/src/include/krb5/kdb_dbc.h | 86 + mechglue/src/include/krb5/kdb_kt.h | 42 + mechglue/src/include/krb5/stock/.Sanitize | 33 + mechglue/src/include/krb5/stock/ChangeLog | 190 + mechglue/src/include/krb5/stock/osconf.h | 128 + mechglue/src/include/krb54proto.h | 18 + mechglue/src/include/port-sockets.h | 187 + mechglue/src/include/socket-utils.h | 108 + mechglue/src/include/spnego-asn1.h | 89 + mechglue/src/include/syslog.h | 102 + mechglue/src/include/win-mac.h | 213 + mechglue/src/kadmin/.Sanitize | 44 + mechglue/src/kadmin/ChangeLog | 189 + mechglue/src/kadmin/Makefile.in | 8 + mechglue/src/kadmin/cli/ChangeLog | 524 + mechglue/src/kadmin/cli/Makefile.in | 39 + mechglue/src/kadmin/cli/getdate.y | 1033 ++ mechglue/src/kadmin/cli/k5srvutil.M | 58 + mechglue/src/kadmin/cli/k5srvutil.sh | 117 + mechglue/src/kadmin/cli/kadmin.M | 797 + mechglue/src/kadmin/cli/kadmin.c | 1736 +++ mechglue/src/kadmin/cli/kadmin.h | 73 + mechglue/src/kadmin/cli/kadmin.local.M | 1 + mechglue/src/kadmin/cli/kadmin_ct.ct | 85 + mechglue/src/kadmin/cli/keytab.c | 467 + mechglue/src/kadmin/cli/memmove.c | 144 + mechglue/src/kadmin/cli/ss_wrapper.c | 64 + mechglue/src/kadmin/cli/strftime.c | 464 + mechglue/src/kadmin/configure.in | 65 + mechglue/src/kadmin/dbutil/ChangeLog | 956 ++ mechglue/src/kadmin/dbutil/Makefile.in | 33 + mechglue/src/kadmin/dbutil/dump.c | 2343 +++ mechglue/src/kadmin/dbutil/dumpv4.c | 462 + mechglue/src/kadmin/dbutil/import_err.et | 26 + mechglue/src/kadmin/dbutil/kadm5_create.c | 296 + mechglue/src/kadmin/dbutil/kdb5_create.c | 441 + mechglue/src/kadmin/dbutil/kdb5_destroy.c | 112 + mechglue/src/kadmin/dbutil/kdb5_edit.M | 182 + mechglue/src/kadmin/dbutil/kdb5_stash.c | 182 + mechglue/src/kadmin/dbutil/kdb5_util.M | 265 + mechglue/src/kadmin/dbutil/kdb5_util.c | 600 + mechglue/src/kadmin/dbutil/kdb5_util.h | 87 + mechglue/src/kadmin/dbutil/loadv4.c | 981 ++ mechglue/src/kadmin/dbutil/nstrtok.h | 3 + mechglue/src/kadmin/dbutil/ovload.c | 212 + mechglue/src/kadmin/dbutil/string_table.c | 84 + mechglue/src/kadmin/dbutil/string_table.h | 39 + mechglue/src/kadmin/dbutil/strtok.c | 105 + mechglue/src/kadmin/dbutil/tcl_wrapper.c | 241 + mechglue/src/kadmin/dbutil/util.c | 158 + mechglue/src/kadmin/kdbkeys/ChangeLog | 54 + mechglue/src/kadmin/kdbkeys/Makefile.in | 18 + mechglue/src/kadmin/kdbkeys/do-test.pl | 56 + mechglue/src/kadmin/ktutil/.Sanitize | 40 + mechglue/src/kadmin/ktutil/ChangeLog | 183 + mechglue/src/kadmin/ktutil/Makefile.in | 58 + mechglue/src/kadmin/ktutil/ktutil.M | 63 + mechglue/src/kadmin/ktutil/ktutil.c | 295 + mechglue/src/kadmin/ktutil/ktutil.h | 75 + mechglue/src/kadmin/ktutil/ktutil_ct.ct | 59 + mechglue/src/kadmin/ktutil/ktutil_funcs.c | 556 + mechglue/src/kadmin/passwd/ChangeLog | 178 + mechglue/src/kadmin/passwd/Kpasswd | 46 + mechglue/src/kadmin/passwd/Makefile.in | 24 + mechglue/src/kadmin/passwd/kpasswd.M | 70 + mechglue/src/kadmin/passwd/kpasswd.c | 281 + mechglue/src/kadmin/passwd/kpasswd.h | 46 + mechglue/src/kadmin/passwd/kpasswd_strings.et | 76 + mechglue/src/kadmin/passwd/tty_kpasswd.c | 81 + .../src/kadmin/passwd/unit-test/ChangeLog | 62 + .../src/kadmin/passwd/unit-test/Makefile.in | 27 + .../kadmin/passwd/unit-test/config/unix.exp | 74 + .../passwd/unit-test/kpasswd.0/changing.exp | 105 + .../passwd/unit-test/kpasswd.0/connecting.exp | 29 + .../passwd/unit-test/kpasswd.0/principal.exp | 60 + .../passwd/unit-test/kpasswd.0/usage.exp | 26 + .../kadmin/passwd/unit-test/lib/helpers.exp | 217 + mechglue/src/kadmin/passwd/xm_kpasswd.c | 452 + mechglue/src/kadmin/scripts/inst-hdrs.sh | 14 + mechglue/src/kadmin/server/ChangeLog | 480 + mechglue/src/kadmin/server/Makefile.in | 26 + mechglue/src/kadmin/server/acls.l | 190 + mechglue/src/kadmin/server/kadm_rpc_svc.c | 335 + mechglue/src/kadmin/server/kadmind.M | 243 + mechglue/src/kadmin/server/misc.c | 173 + mechglue/src/kadmin/server/misc.h | 47 + mechglue/src/kadmin/server/ovsec_kadmd.c | 1215 ++ mechglue/src/kadmin/server/schpw.c | 406 + mechglue/src/kadmin/server/server_glue_v1.c | 32 + mechglue/src/kadmin/server/server_stubs.c | 1916 +++ mechglue/src/kadmin/testing/ChangeLog | 42 + mechglue/src/kadmin/testing/Makefile.in | 10 + mechglue/src/kadmin/testing/proto/ChangeLog | 63 + .../src/kadmin/testing/proto/kdc.conf.proto | 16 + .../src/kadmin/testing/proto/krb5.conf.proto | 30 + .../src/kadmin/testing/proto/ovsec_adm.dict | 3 + mechglue/src/kadmin/testing/scripts/ChangeLog | 277 + .../src/kadmin/testing/scripts/Makefile.in | 37 + .../kadmin/testing/scripts/compare_dump.plin | 242 + .../src/kadmin/testing/scripts/env-setup.shin | 118 + .../src/kadmin/testing/scripts/find-make.sh | 18 + .../testing/scripts/fixup-conf-files.plin | 344 + mechglue/src/kadmin/testing/scripts/init_db | 227 + .../testing/scripts/make-host-keytab.plin | 144 + .../src/kadmin/testing/scripts/qualname.plin | 20 + .../src/kadmin/testing/scripts/save_files.sh | 62 + .../kadmin/testing/scripts/simple_dump.plin | 88 + .../src/kadmin/testing/scripts/start_servers | 72 + .../testing/scripts/start_servers_local | 212 + .../src/kadmin/testing/scripts/stop_servers | 62 + .../kadmin/testing/scripts/stop_servers_local | 53 + .../scripts/verify_xrunner_report.plin | 38 + mechglue/src/kadmin/testing/tcl/util.t | 61 + mechglue/src/kadmin/testing/util/ChangeLog | 220 + mechglue/src/kadmin/testing/util/Makefile.in | 70 + mechglue/src/kadmin/testing/util/bsddb_dump.c | 64 + mechglue/src/kadmin/testing/util/tcl_kadm5.c | 2554 ++++ mechglue/src/kadmin/testing/util/tcl_kadm5.h | 4 + .../src/kadmin/testing/util/tcl_krb5_hash.c | 167 + .../src/kadmin/testing/util/tcl_ovsec_kadm.c | 2029 +++ .../kadmin/testing/util/tcl_ovsec_kadm_syntax | 57 + mechglue/src/kadmin/testing/util/test.c | 37 + mechglue/src/kdc/.Sanitize | 58 + mechglue/src/kdc/.rconf | 5 + mechglue/src/kdc/.saberinit | 35 + mechglue/src/kdc/ChangeLog | 2118 +++ mechglue/src/kdc/Makefile.in | 192 + mechglue/src/kdc/dispatch.c | 115 + mechglue/src/kdc/do_as_req.c | 532 + mechglue/src/kdc/do_tgs_req.c | 816 + mechglue/src/kdc/extern.c | 42 + mechglue/src/kdc/extern.h | 99 + mechglue/src/kdc/fakeka.c | 1395 ++ mechglue/src/kdc/kdc5_err.et | 35 + mechglue/src/kdc/kdc_preauth.c | 1604 ++ mechglue/src/kdc/kdc_util.c | 1578 ++ mechglue/src/kdc/kdc_util.h | 194 + mechglue/src/kdc/kerberos_v4.c | 1203 ++ mechglue/src/kdc/krb5kdc.M | 154 + mechglue/src/kdc/main.c | 755 + mechglue/src/kdc/migration.doc | 59 + mechglue/src/kdc/network.c | 1088 ++ mechglue/src/kdc/policy.c | 75 + mechglue/src/kdc/policy.h | 39 + mechglue/src/kdc/replay.c | 190 + mechglue/src/kdc/rtest.c | 116 + mechglue/src/kdc/rtest.good | 26 + mechglue/src/kdc/rtscript | 54 + mechglue/src/krb5-config.M | 74 + mechglue/src/krb5-config.in | 221 + mechglue/src/krb524/.Sanitize | 45 + mechglue/src/krb524/ChangeLog | 1014 ++ mechglue/src/krb524/Makefile.in | 149 + mechglue/src/krb524/README | 154 + mechglue/src/krb524/cnv_tkt_skey.c | 208 + mechglue/src/krb524/conv_princ.c | 39 + mechglue/src/krb524/k524init.c | 182 + mechglue/src/krb524/krb524.c | 47 + mechglue/src/krb524/krb524.def | 13 + mechglue/src/krb524/krb524_prot | 11 + mechglue/src/krb524/krb524d.M | 74 + mechglue/src/krb524/krb524d.c | 634 + mechglue/src/krb524/krb524d.h | 55 + mechglue/src/krb524/libinit.c | 27 + mechglue/src/krb524/test.c | 353 + mechglue/src/lib/.Sanitize | 56 + mechglue/src/lib/.rconf | 2 + mechglue/src/lib/ChangeLog | 824 ++ mechglue/src/lib/Makefile.in | 180 + mechglue/src/lib/apputils/ChangeLog | 14 + mechglue/src/lib/apputils/Makefile.in | 48 + mechglue/src/lib/apputils/configure.in | 6 + mechglue/src/lib/apputils/daemon.c | 95 + mechglue/src/lib/apputils/dummy.c | 1 + mechglue/src/lib/ccapi/ChangeLog | 4 + mechglue/src/lib/ccapi/client/ChangeLog | 4 + mechglue/src/lib/ccapi/client/NTMakefile | 22 + mechglue/src/lib/ccapi/client/cacheapi.c | 118 + mechglue/src/lib/ccapi/client/ccache.c | 1098 ++ mechglue/src/lib/ccapi/client/ccache.h | 146 + .../src/lib/ccapi/client/ccache_iterator.c | 179 + .../src/lib/ccapi/client/ccache_iterator.h | 85 + mechglue/src/lib/ccapi/client/ccstring.c | 94 + mechglue/src/lib/ccapi/client/ccstring.h | 65 + mechglue/src/lib/ccapi/client/context.c | 849 ++ mechglue/src/lib/ccapi/client/context.h | 131 + mechglue/src/lib/ccapi/client/credentials.c | 181 + mechglue/src/lib/ccapi/client/credentials.h | 94 + .../lib/ccapi/client/credentials_iterator.c | 187 + .../lib/ccapi/client/credentials_iterator.h | 72 + mechglue/src/lib/ccapi/client/mac/ChangeLog | 4 + .../src/lib/ccapi/client/windows/ChangeLog | 4 + mechglue/src/lib/ccapi/include/ChangeLog | 4 + .../src/lib/ccapi/include/CredentialsCache.h | 567 + .../src/lib/ccapi/include/CredentialsCache2.h | 308 + mechglue/src/lib/ccapi/include/marshall.h | 93 + mechglue/src/lib/ccapi/include/msg.h | 146 + mechglue/src/lib/ccapi/include/msg_headers.h | 429 + mechglue/src/lib/ccapi/mac/ChangeLog | 4 + mechglue/src/lib/ccapi/marshall.c | 378 + mechglue/src/lib/ccapi/msg.c | 582 + mechglue/src/lib/ccapi/server/ChangeLog | 4 + mechglue/src/lib/ccapi/server/NTMakefile | 30 + mechglue/src/lib/ccapi/server/ccache.c | 703 + mechglue/src/lib/ccapi/server/context.c | 325 + mechglue/src/lib/ccapi/server/datastore.h | 231 + mechglue/src/lib/ccapi/server/lists.c | 996 ++ mechglue/src/lib/ccapi/server/mac/ChangeLog | 4 + mechglue/src/lib/ccapi/server/rpc_auth.c | 63 + mechglue/src/lib/ccapi/server/rpc_auth.h | 71 + mechglue/src/lib/ccapi/server/serv_ops.c | 1500 ++ mechglue/src/lib/ccapi/server/serv_ops.h | 321 + .../src/lib/ccapi/server/windows/ChangeLog | 4 + mechglue/src/lib/ccapi/unit-test/ChangeLog | 4 + mechglue/src/lib/ccapi/unit-test/t_ccache.c | 115 + mechglue/src/lib/ccapi/unit-test/t_context.c | 115 + mechglue/src/lib/ccapi/unit-test/t_lists.c | 100 + mechglue/src/lib/ccapi/unit-test/t_msg.c | 88 + mechglue/src/lib/ccapi/unit-test/t_server.c | 185 + mechglue/src/lib/ccapi/windows/ChangeLog | 4 + mechglue/src/lib/comerr32.def | 10 + mechglue/src/lib/crypto/.Sanitize | 50 + mechglue/src/lib/crypto/ChangeLog | 1117 ++ mechglue/src/lib/crypto/ISSUES | 16 + mechglue/src/lib/crypto/Makefile.in | 643 + mechglue/src/lib/crypto/aes/ChangeLog | 82 + mechglue/src/lib/crypto/aes/Makefile.in | 89 + mechglue/src/lib/crypto/aes/aes-gen.c | 326 + mechglue/src/lib/crypto/aes/aes-test.c | 138 + mechglue/src/lib/crypto/aes/aes.h | 97 + mechglue/src/lib/crypto/aes/aes.txt | 70 + mechglue/src/lib/crypto/aes/aes_s2k.c | 93 + mechglue/src/lib/crypto/aes/aes_s2k.h | 4 + mechglue/src/lib/crypto/aes/aescpp.h | 55 + mechglue/src/lib/crypto/aes/aescrypp.c | 487 + mechglue/src/lib/crypto/aes/aescrypt.asm | 402 + mechglue/src/lib/crypto/aes/aescrypt.c | 421 + mechglue/src/lib/crypto/aes/aeskey.c | 363 + mechglue/src/lib/crypto/aes/aeskeypp.c | 399 + mechglue/src/lib/crypto/aes/aesopt.h | 849 ++ mechglue/src/lib/crypto/aes/aessrc.url | 1 + mechglue/src/lib/crypto/aes/aestab.c | 494 + mechglue/src/lib/crypto/aes/expect-vk.txt | 1548 ++ mechglue/src/lib/crypto/aes/expect-vt.txt | 1036 ++ mechglue/src/lib/crypto/aes/test/Readme.txt | 22 + mechglue/src/lib/crypto/aes/test/cbc_d_m.txt | 7224 +++++++++ mechglue/src/lib/crypto/aes/test/cbc_e_m.txt | 7224 +++++++++ mechglue/src/lib/crypto/aes/test/ecb_d_m.txt | 6024 ++++++++ mechglue/src/lib/crypto/aes/test/ecb_e_m.txt | 6024 ++++++++ .../src/lib/crypto/aes/test/ecb_iv.readme | 19 + mechglue/src/lib/crypto/aes/test/ecb_iv.txt | 123 + mechglue/src/lib/crypto/aes/test/ecb_tbl.txt | 1955 +++ mechglue/src/lib/crypto/aes/test/ecb_vk.txt | 2334 +++ mechglue/src/lib/crypto/aes/test/ecb_vt.txt | 1566 ++ mechglue/src/lib/crypto/aes/test/katmct.pdf | Bin 0 -> 100812 bytes mechglue/src/lib/crypto/aes/uitypes.h | 81 + mechglue/src/lib/crypto/aes/vb.txt | 87 + mechglue/src/lib/crypto/arcfour/ChangeLog | 115 + mechglue/src/lib/crypto/arcfour/Makefile.in | 58 + mechglue/src/lib/crypto/arcfour/arcfour-int.h | 31 + mechglue/src/lib/crypto/arcfour/arcfour.c | 318 + mechglue/src/lib/crypto/arcfour/arcfour.h | 36 + mechglue/src/lib/crypto/arcfour/arcfour_s2k.c | 70 + mechglue/src/lib/crypto/block_size.c | 47 + mechglue/src/lib/crypto/checksum_length.c | 53 + mechglue/src/lib/crypto/cksumtype_to_string.c | 46 + mechglue/src/lib/crypto/cksumtypes.c | 98 + mechglue/src/lib/crypto/cksumtypes.h | 30 + mechglue/src/lib/crypto/coll_proof_cksum.c | 50 + mechglue/src/lib/crypto/combine_keys.c | 349 + mechglue/src/lib/crypto/configure.in | 11 + mechglue/src/lib/crypto/crc32/.Sanitize | 40 + mechglue/src/lib/crypto/crc32/CRC.pm | 156 + mechglue/src/lib/crypto/crc32/ChangeLog | 254 + mechglue/src/lib/crypto/crc32/Makefile.in | 52 + mechglue/src/lib/crypto/crc32/Poly.pm | 182 + mechglue/src/lib/crypto/crc32/crc-32.h | 71 + mechglue/src/lib/crypto/crc32/crc.pl | 111 + mechglue/src/lib/crypto/crc32/crc32.c | 192 + mechglue/src/lib/crypto/crc32/t_crc.c | 213 + mechglue/src/lib/crypto/crypto_libinit.c | 33 + mechglue/src/lib/crypto/decrypt.c | 52 + mechglue/src/lib/crypto/default_state.c | 63 + mechglue/src/lib/crypto/des/.Sanitize | 71 + mechglue/src/lib/crypto/des/ChangeLog | 765 + mechglue/src/lib/crypto/des/ISSUES | 13 + mechglue/src/lib/crypto/des/Makefile.in | 176 + mechglue/src/lib/crypto/des/afsstring2key.c | 570 + mechglue/src/lib/crypto/des/d3_cbc.c | 226 + mechglue/src/lib/crypto/des/d3_kysched.c | 50 + mechglue/src/lib/crypto/des/des_int.h | 305 + mechglue/src/lib/crypto/des/destest.c | 247 + mechglue/src/lib/crypto/des/doc/.Sanitize | 32 + mechglue/src/lib/crypto/des/doc/libdes.doc | 208 + mechglue/src/lib/crypto/des/f_cbc.c | 255 + mechglue/src/lib/crypto/des/f_cksum.c | 120 + mechglue/src/lib/crypto/des/f_parity.c | 56 + mechglue/src/lib/crypto/des/f_sched.c | 344 + mechglue/src/lib/crypto/des/f_tables.c | 351 + mechglue/src/lib/crypto/des/f_tables.h | 260 + mechglue/src/lib/crypto/des/key_sched.c | 61 + mechglue/src/lib/crypto/des/keytest.data | 171 + mechglue/src/lib/crypto/des/string2key.c | 261 + mechglue/src/lib/crypto/des/t_afss2k.c | 136 + mechglue/src/lib/crypto/des/t_verify.c | 418 + mechglue/src/lib/crypto/des/weak_key.c | 85 + mechglue/src/lib/crypto/dk/ChangeLog | 181 + mechglue/src/lib/crypto/dk/Makefile.in | 97 + mechglue/src/lib/crypto/dk/checksum.c | 103 + mechglue/src/lib/crypto/dk/derive.c | 217 + mechglue/src/lib/crypto/dk/dk.h | 90 + mechglue/src/lib/crypto/dk/dk_decrypt.c | 203 + mechglue/src/lib/crypto/dk/dk_encrypt.c | 362 + mechglue/src/lib/crypto/dk/dk_prf.c | 64 + mechglue/src/lib/crypto/dk/stringtokey.c | 96 + .../src/lib/crypto/enc_provider/ChangeLog | 149 + .../src/lib/crypto/enc_provider/Makefile.in | 74 + mechglue/src/lib/crypto/enc_provider/aes.c | 208 + mechglue/src/lib/crypto/enc_provider/des.c | 117 + mechglue/src/lib/crypto/enc_provider/des3.c | 140 + .../lib/crypto/enc_provider/enc_provider.h | 33 + mechglue/src/lib/crypto/enc_provider/rc4.c | 216 + mechglue/src/lib/crypto/encrypt.c | 52 + mechglue/src/lib/crypto/encrypt_length.c | 49 + mechglue/src/lib/crypto/enctype_compare.c | 55 + mechglue/src/lib/crypto/enctype_to_string.c | 46 + mechglue/src/lib/crypto/etypes.c | 214 + mechglue/src/lib/crypto/etypes.h | 30 + .../src/lib/crypto/hash_provider/ChangeLog | 73 + .../src/lib/crypto/hash_provider/Makefile.in | 69 + .../src/lib/crypto/hash_provider/hash_crc32.c | 59 + .../src/lib/crypto/hash_provider/hash_md4.c | 55 + .../src/lib/crypto/hash_provider/hash_md5.c | 55 + .../lib/crypto/hash_provider/hash_provider.h | 32 + .../src/lib/crypto/hash_provider/hash_sha1.c | 60 + mechglue/src/lib/crypto/hmac.c | 127 + mechglue/src/lib/crypto/keyblocks.c | 79 + .../src/lib/crypto/keyed_checksum_types.c | 89 + mechglue/src/lib/crypto/keyed_cksum.c | 55 + .../src/lib/crypto/keyhash_provider/ChangeLog | 148 + .../lib/crypto/keyhash_provider/Makefile.in | 93 + .../src/lib/crypto/keyhash_provider/descbc.c | 70 + .../lib/crypto/keyhash_provider/hmac_md5.c | 96 + .../lib/crypto/keyhash_provider/k5_md4des.c | 190 + .../lib/crypto/keyhash_provider/k5_md5des.c | 187 + .../keyhash_provider/keyhash_provider.h | 32 + .../src/lib/crypto/keyhash_provider/t_cksum.c | 139 + mechglue/src/lib/crypto/libk5crypto.exports | 156 + mechglue/src/lib/crypto/make_checksum.c | 114 + mechglue/src/lib/crypto/make_random_key.c | 83 + mechglue/src/lib/crypto/mandatory_sumtype.c | 41 + mechglue/src/lib/crypto/md4/.Sanitize | 42 + mechglue/src/lib/crypto/md4/ChangeLog | 311 + mechglue/src/lib/crypto/md4/ISSUES | 3 + mechglue/src/lib/crypto/md4/Makefile.in | 68 + mechglue/src/lib/crypto/md4/md4.c | 257 + mechglue/src/lib/crypto/md4/rsa-md4.h | 94 + mechglue/src/lib/crypto/md5/.Sanitize | 42 + mechglue/src/lib/crypto/md5/ChangeLog | 319 + mechglue/src/lib/crypto/md5/ISSUES | 3 + mechglue/src/lib/crypto/md5/Makefile.in | 58 + mechglue/src/lib/crypto/md5/md5.c | 355 + mechglue/src/lib/crypto/md5/rsa-md5.h | 60 + mechglue/src/lib/crypto/md5/t_cksum.c | 206 + mechglue/src/lib/crypto/md5/t_mddriver.c | 323 + mechglue/src/lib/crypto/nfold.c | 130 + mechglue/src/lib/crypto/old/ChangeLog | 122 + mechglue/src/lib/crypto/old/Makefile.in | 60 + mechglue/src/lib/crypto/old/des_stringtokey.c | 58 + mechglue/src/lib/crypto/old/old.h | 52 + mechglue/src/lib/crypto/old/old_decrypt.c | 143 + mechglue/src/lib/crypto/old/old_encrypt.c | 110 + mechglue/src/lib/crypto/old_api_glue.c | 326 + mechglue/src/lib/crypto/pbkdf2.c | 268 + mechglue/src/lib/crypto/prf.c | 87 + mechglue/src/lib/crypto/prng.c | 215 + mechglue/src/lib/crypto/raw/ChangeLog | 51 + mechglue/src/lib/crypto/raw/Makefile.in | 51 + mechglue/src/lib/crypto/raw/raw.h | 46 + mechglue/src/lib/crypto/raw/raw_decrypt.c | 38 + mechglue/src/lib/crypto/raw/raw_encrypt.c | 50 + mechglue/src/lib/crypto/sha1/ChangeLog | 98 + mechglue/src/lib/crypto/sha1/ISSUES | 7 + mechglue/src/lib/crypto/sha1/Makefile.in | 63 + mechglue/src/lib/crypto/sha1/shs.c | 386 + mechglue/src/lib/crypto/sha1/shs.h | 45 + mechglue/src/lib/crypto/sha1/t_shs.c | 135 + mechglue/src/lib/crypto/sha1/t_shs3.c | 592 + mechglue/src/lib/crypto/state.c | 72 + mechglue/src/lib/crypto/string_to_cksumtype.c | 43 + mechglue/src/lib/crypto/string_to_enctype.c | 43 + mechglue/src/lib/crypto/string_to_key.c | 99 + mechglue/src/lib/crypto/t_cts.c | 177 + mechglue/src/lib/crypto/t_encrypt.c | 153 + mechglue/src/lib/crypto/t_hmac.c | 271 + mechglue/src/lib/crypto/t_nfold.c | 165 + mechglue/src/lib/crypto/t_pkcs5.c | 105 + mechglue/src/lib/crypto/t_prf.c | 89 + mechglue/src/lib/crypto/t_prng.c | 87 + mechglue/src/lib/crypto/t_prng.comments | 14 + mechglue/src/lib/crypto/t_prng.expected | 4 + mechglue/src/lib/crypto/t_prng.reseedtest | 31 + .../src/lib/crypto/t_prng.reseedtest-comments | 21 + .../src/lib/crypto/t_prng.reseedtest-expected | 1 + mechglue/src/lib/crypto/t_prng.seed | 25 + mechglue/src/lib/crypto/valid_cksumtype.c | 47 + mechglue/src/lib/crypto/valid_enctype.c | 47 + mechglue/src/lib/crypto/vectors.c | 457 + mechglue/src/lib/crypto/verify_checksum.c | 80 + mechglue/src/lib/crypto/yarrow/ASSUMPTIONS | 101 + mechglue/src/lib/crypto/yarrow/ChangeLog | 150 + mechglue/src/lib/crypto/yarrow/LICENSE | 21 + mechglue/src/lib/crypto/yarrow/Makefile.in | 59 + mechglue/src/lib/crypto/yarrow/README | 94 + mechglue/src/lib/crypto/yarrow/TODO | 9 + mechglue/src/lib/crypto/yarrow/yarrow.c | 955 ++ mechglue/src/lib/crypto/yarrow/yarrow.h | 186 + mechglue/src/lib/crypto/yarrow/yarrow.man | 315 + mechglue/src/lib/crypto/yarrow/yarrow.pod | 112 + mechglue/src/lib/crypto/yarrow/ycipher.c | 96 + mechglue/src/lib/crypto/yarrow/ycipher.h | 42 + mechglue/src/lib/crypto/yarrow/yexcep.h | 107 + mechglue/src/lib/crypto/yarrow/yhash.h | 33 + mechglue/src/lib/crypto/yarrow/ylock.h | 24 + mechglue/src/lib/crypto/yarrow/ystate.h | 28 + mechglue/src/lib/crypto/yarrow/ytest.c | 389 + mechglue/src/lib/crypto/yarrow/ytypes.h | 27 + mechglue/src/lib/des425/.Sanitize | 54 + mechglue/src/lib/des425/ChangeLog | 583 + mechglue/src/lib/des425/ISSUES | 28 + mechglue/src/lib/des425/Makefile.in | 216 + mechglue/src/lib/des425/cksum.c | 68 + mechglue/src/lib/des425/configure.in | 12 + mechglue/src/lib/des425/des.c | 44 + mechglue/src/lib/des425/enc_dec.c | 47 + mechglue/src/lib/des425/key_parity.c | 52 + mechglue/src/lib/des425/key_sched.c | 40 + mechglue/src/lib/des425/libdes425.exports | 18 + mechglue/src/lib/des425/mac_des_glue.c | 104 + mechglue/src/lib/des425/new_rnd_key.c | 96 + mechglue/src/lib/des425/pcbc_encrypt.c | 218 + mechglue/src/lib/des425/quad_cksum.c | 200 + mechglue/src/lib/des425/random_key.c | 74 + mechglue/src/lib/des425/read_passwd.c | 129 + mechglue/src/lib/des425/str_to_key.c | 168 + mechglue/src/lib/des425/string2key.c | 174 + mechglue/src/lib/des425/t_pcbc.c | 123 + mechglue/src/lib/des425/t_quad.c | 101 + mechglue/src/lib/des425/unix_time.c | 46 + mechglue/src/lib/des425/util.c | 33 + mechglue/src/lib/des425/verify.c | 317 + mechglue/src/lib/des425/weak_key.c | 41 + mechglue/src/lib/glue4.c | 19 + mechglue/src/lib/gssapi/.Sanitize | 42 + mechglue/src/lib/gssapi/ChangeLog | 416 + mechglue/src/lib/gssapi/Makefile.in | 135 + mechglue/src/lib/gssapi/README_SAMPLE_APP | 4 + mechglue/src/lib/gssapi/configure.in | 19 + mechglue/src/lib/gssapi/generic/.Sanitize | 53 + mechglue/src/lib/gssapi/generic/ChangeLog | 907 ++ mechglue/src/lib/gssapi/generic/Makefile.in | 208 + .../lib/gssapi/generic/disp_com_err_status.c | 65 + .../lib/gssapi/generic/disp_major_status.c | 312 + mechglue/src/lib/gssapi/generic/gssapi.hin | 796 + .../src/lib/gssapi/generic/gssapiP_generic.h | 259 + .../lib/gssapi/generic/gssapi_err_generic.et | 49 + .../src/lib/gssapi/generic/gssapi_generic.c | 148 + .../src/lib/gssapi/generic/gssapi_generic.h | 55 + mechglue/src/lib/gssapi/generic/oid_ops.c | 388 + mechglue/src/lib/gssapi/generic/rel_buffer.c | 57 + mechglue/src/lib/gssapi/generic/rel_oid_set.c | 61 + mechglue/src/lib/gssapi/generic/util_buffer.c | 48 + .../src/lib/gssapi/generic/util_canonhost.c | 71 + .../src/lib/gssapi/generic/util_localhost.c | 50 + mechglue/src/lib/gssapi/generic/util_oid.c | 78 + .../src/lib/gssapi/generic/util_ordering.c | 245 + mechglue/src/lib/gssapi/generic/util_set.c | 105 + mechglue/src/lib/gssapi/generic/util_token.c | 231 + .../src/lib/gssapi/generic/util_validate.c | 320 + .../lib/gssapi/generic/utl_nohash_validate.c | 121 + mechglue/src/lib/gssapi/gss_libinit.c | 71 + mechglue/src/lib/gssapi/gss_libinit.h | 9 + mechglue/src/lib/gssapi/krb5/.Sanitize | 74 + mechglue/src/lib/gssapi/krb5/3des.txt | 395 + mechglue/src/lib/gssapi/krb5/ChangeLog | 2284 +++ mechglue/src/lib/gssapi/krb5/Makefile.in | 642 + .../src/lib/gssapi/krb5/accept_sec_context.c | 995 ++ mechglue/src/lib/gssapi/krb5/acquire_cred.c | 652 + mechglue/src/lib/gssapi/krb5/add_cred.c | 368 + mechglue/src/lib/gssapi/krb5/canon_name.c | 44 + mechglue/src/lib/gssapi/krb5/compare_name.c | 60 + mechglue/src/lib/gssapi/krb5/context_time.c | 67 + mechglue/src/lib/gssapi/krb5/copy_ccache.c | 59 + .../src/lib/gssapi/krb5/delete_sec_context.c | 119 + mechglue/src/lib/gssapi/krb5/disp_name.c | 74 + mechglue/src/lib/gssapi/krb5/disp_status.c | 68 + mechglue/src/lib/gssapi/krb5/duplicate_name.c | 79 + mechglue/src/lib/gssapi/krb5/export_name.c | 96 + .../src/lib/gssapi/krb5/export_sec_context.c | 102 + mechglue/src/lib/gssapi/krb5/get_tkt_flags.c | 55 + mechglue/src/lib/gssapi/krb5/gssapiP_krb5.h | 664 + .../src/lib/gssapi/krb5/gssapi_err_krb5.et | 40 + mechglue/src/lib/gssapi/krb5/gssapi_krb5.c | 251 + mechglue/src/lib/gssapi/krb5/gssapi_krb5.hin | 271 + mechglue/src/lib/gssapi/krb5/import_name.c | 237 + .../src/lib/gssapi/krb5/import_sec_context.c | 126 + mechglue/src/lib/gssapi/krb5/indicate_mechs.c | 43 + .../src/lib/gssapi/krb5/init_sec_context.c | 968 ++ mechglue/src/lib/gssapi/krb5/inq_context.c | 132 + mechglue/src/lib/gssapi/krb5/inq_cred.c | 267 + mechglue/src/lib/gssapi/krb5/inq_names.c | 99 + mechglue/src/lib/gssapi/krb5/k5seal.c | 399 + mechglue/src/lib/gssapi/krb5/k5sealv3.c | 502 + mechglue/src/lib/gssapi/krb5/k5unseal.c | 547 + mechglue/src/lib/gssapi/krb5/krb5_gss_glue.c | 1057 ++ mechglue/src/lib/gssapi/krb5/lucid_context.c | 309 + .../lib/gssapi/krb5/process_context_token.c | 63 + mechglue/src/lib/gssapi/krb5/rel_cred.c | 87 + mechglue/src/lib/gssapi/krb5/rel_name.c | 54 + mechglue/src/lib/gssapi/krb5/rel_oid.c | 85 + mechglue/src/lib/gssapi/krb5/seal.c | 63 + mechglue/src/lib/gssapi/krb5/ser_sctx.c | 676 + .../lib/gssapi/krb5/set_allowable_enctypes.c | 131 + mechglue/src/lib/gssapi/krb5/set_ccache.c | 91 + mechglue/src/lib/gssapi/krb5/sign.c | 57 + mechglue/src/lib/gssapi/krb5/unseal.c | 66 + mechglue/src/lib/gssapi/krb5/util_cksum.c | 108 + mechglue/src/lib/gssapi/krb5/util_crypt.c | 240 + mechglue/src/lib/gssapi/krb5/util_seed.c | 54 + mechglue/src/lib/gssapi/krb5/util_seqnum.c | 105 + mechglue/src/lib/gssapi/krb5/val_cred.c | 98 + mechglue/src/lib/gssapi/krb5/verify.c | 64 + .../src/lib/gssapi/krb5/wrap_size_limit.c | 163 + .../src/lib/gssapi/libgssapi_krb5.exports | 108 + mechglue/src/lib/gssapi/mechglue/.Sanitize | 71 + mechglue/src/lib/gssapi/mechglue/ChangeLog | 372 + mechglue/src/lib/gssapi/mechglue/Makefile.in | 102 + .../gssapi/mechglue/g_accept_sec_context.c | 312 + .../src/lib/gssapi/mechglue/g_acquire_cred.c | 437 + .../src/lib/gssapi/mechglue/g_canon_name.c | 155 + .../src/lib/gssapi/mechglue/g_compare_name.c | 177 + .../src/lib/gssapi/mechglue/g_context_time.c | 78 + .../gssapi/mechglue/g_delete_sec_context.c | 90 + mechglue/src/lib/gssapi/mechglue/g_dsp_name.c | 108 + .../src/lib/gssapi/mechglue/g_dsp_status.c | 325 + mechglue/src/lib/gssapi/mechglue/g_dup_name.c | 118 + .../lib/gssapi/mechglue/g_exp_sec_context.c | 108 + .../src/lib/gssapi/mechglue/g_export_name.c | 55 + mechglue/src/lib/gssapi/mechglue/g_glue.c | 584 + mechglue/src/lib/gssapi/mechglue/g_imp_name.c | 328 + .../lib/gssapi/mechglue/g_imp_sec_context.c | 135 + .../lib/gssapi/mechglue/g_indicate_mechs.c | 90 + .../lib/gssapi/mechglue/g_init_sec_context.c | 212 + .../src/lib/gssapi/mechglue/g_initialize.c | 985 ++ .../src/lib/gssapi/mechglue/g_inq_context.c | 144 + mechglue/src/lib/gssapi/mechglue/g_inq_cred.c | 255 + .../src/lib/gssapi/mechglue/g_inq_names.c | 157 + mechglue/src/lib/gssapi/mechglue/g_mechname.c | 112 + mechglue/src/lib/gssapi/mechglue/g_oid_ops.c | 88 + .../lib/gssapi/mechglue/g_process_context.c | 78 + .../src/lib/gssapi/mechglue/g_rel_buffer.c | 58 + mechglue/src/lib/gssapi/mechglue/g_rel_cred.c | 98 + mechglue/src/lib/gssapi/mechglue/g_rel_name.c | 81 + .../src/lib/gssapi/mechglue/g_rel_oid_set.c | 63 + mechglue/src/lib/gssapi/mechglue/g_seal.c | 163 + mechglue/src/lib/gssapi/mechglue/g_sign.c | 107 + .../src/lib/gssapi/mechglue/g_store_cred.c | 136 + mechglue/src/lib/gssapi/mechglue/g_unseal.c | 116 + mechglue/src/lib/gssapi/mechglue/g_userok.c | 112 + mechglue/src/lib/gssapi/mechglue/g_utils.c | 281 + mechglue/src/lib/gssapi/mechglue/g_verify.c | 102 + mechglue/src/lib/gssapi/mechglue/gen_oids.c | 55 + .../lib/gssapi/mechglue/gssd_pname_to_uid.c | 65 + mechglue/src/lib/gssapi/mechglue/mech.conf | 7 + mechglue/src/lib/gssapi/mechglue/mechglue.h | 41 + mechglue/src/lib/gssapi/mechglue/mglueP.h | 565 + mechglue/src/lib/gssapi/mechglue/oid_ops.c | 502 + mechglue/src/lib/gssapi32.def | 96 + mechglue/src/lib/kadm5/ChangeLog | 734 + mechglue/src/lib/kadm5/Makefile.in | 187 + mechglue/src/lib/kadm5/adb.h | 149 + mechglue/src/lib/kadm5/admin.h | 734 + mechglue/src/lib/kadm5/admin_internal.h | 80 + mechglue/src/lib/kadm5/admin_xdr.h | 64 + mechglue/src/lib/kadm5/alt_prof.c | 1026 ++ mechglue/src/lib/kadm5/chpass_util.c | 254 + mechglue/src/lib/kadm5/chpass_util_strings.et | 58 + mechglue/src/lib/kadm5/clnt/ChangeLog | 357 + mechglue/src/lib/kadm5/clnt/Makefile.in | 160 + mechglue/src/lib/kadm5/clnt/client_handle.c | 9 + mechglue/src/lib/kadm5/clnt/client_init.c | 749 + mechglue/src/lib/kadm5/clnt/client_internal.h | 97 + .../src/lib/kadm5/clnt/client_principal.c | 566 + mechglue/src/lib/kadm5/clnt/client_rpc.c | 307 + .../src/lib/kadm5/clnt/clnt_chpass_util.c | 16 + mechglue/src/lib/kadm5/clnt/clnt_policy.c | 173 + mechglue/src/lib/kadm5/clnt/clnt_privs.c | 100 + mechglue/src/lib/kadm5/clnt/err_handle.c | 197 + mechglue/src/lib/kadm5/clnt/err_handle.h | 38 + .../src/lib/kadm5/clnt/libkadm5clnt.exports | 130 + mechglue/src/lib/kadm5/configure.in | 23 + mechglue/src/lib/kadm5/kadm_err.et | 63 + mechglue/src/lib/kadm5/kadm_rpc.h | 312 + mechglue/src/lib/kadm5/kadm_rpc_xdr.c | 1128 ++ mechglue/src/lib/kadm5/logger.c | 961 ++ mechglue/src/lib/kadm5/misc_free.c | 115 + mechglue/src/lib/kadm5/ovsec_glue.c | 193 + mechglue/src/lib/kadm5/server_internal.h | 141 + mechglue/src/lib/kadm5/srv/ChangeLog | 581 + mechglue/src/lib/kadm5/srv/Makefile.in | 220 + mechglue/src/lib/kadm5/srv/adb_xdr.c | 110 + .../src/lib/kadm5/srv/libkadm5srv.exports | 160 + mechglue/src/lib/kadm5/srv/server_acl.c | 807 + mechglue/src/lib/kadm5/srv/server_acl.h | 103 + mechglue/src/lib/kadm5/srv/server_dict.c | 203 + mechglue/src/lib/kadm5/srv/server_handle.c | 9 + mechglue/src/lib/kadm5/srv/server_init.c | 422 + mechglue/src/lib/kadm5/srv/server_kdb.c | 410 + mechglue/src/lib/kadm5/srv/server_misc.c | 182 + mechglue/src/lib/kadm5/srv/svr_chpass_util.c | 16 + mechglue/src/lib/kadm5/srv/svr_iters.c | 270 + mechglue/src/lib/kadm5/srv/svr_misc_free.c | 37 + mechglue/src/lib/kadm5/srv/svr_policy.c | 316 + mechglue/src/lib/kadm5/srv/svr_principal.c | 2097 +++ mechglue/src/lib/kadm5/str_conv.c | 417 + mechglue/src/lib/kadm5/unit-test/ChangeLog | 442 + mechglue/src/lib/kadm5/unit-test/Makefile.in | 139 + .../src/lib/kadm5/unit-test/README.new-tests | 12 + .../unit-test/api.0/chpass-principal.exp | 176 + .../lib/kadm5/unit-test/api.0/crte-policy.exp | 991 ++ .../kadm5/unit-test/api.0/crte-principal.exp | 1336 ++ .../src/lib/kadm5/unit-test/api.0/destroy.exp | 203 + .../lib/kadm5/unit-test/api.0/dlte-policy.exp | 207 + .../kadm5/unit-test/api.0/dlte-principal.exp | 329 + .../lib/kadm5/unit-test/api.0/get-policy.exp | 199 + .../kadm5/unit-test/api.0/get-principal.exp | 346 + .../src/lib/kadm5/unit-test/api.0/init.exp | 728 + .../lib/kadm5/unit-test/api.0/mod-policy.exp | 703 + .../kadm5/unit-test/api.0/mod-principal.exp | 1942 +++ .../unit-test/api.0/randkey-principal.exp | 319 + .../unit-test/api.0/rename-principal.exp | 509 + .../src/lib/kadm5/unit-test/api.1/lock.exp | 287 + .../unit-test/api.2/chpass-principal-v2.exp | 68 + .../unit-test/api.2/chpass-principal.exp | 176 + .../lib/kadm5/unit-test/api.2/crte-policy.exp | 991 ++ .../kadm5/unit-test/api.2/crte-principal.exp | 1335 ++ .../src/lib/kadm5/unit-test/api.2/destroy.exp | 203 + .../lib/kadm5/unit-test/api.2/dlte-policy.exp | 207 + .../kadm5/unit-test/api.2/dlte-principal.exp | 329 + .../lib/kadm5/unit-test/api.2/get-policy.exp | 199 + .../unit-test/api.2/get-principal-v2.exp | 250 + .../kadm5/unit-test/api.2/get-principal.exp | 346 + .../src/lib/kadm5/unit-test/api.2/init-v2.exp | 648 + .../src/lib/kadm5/unit-test/api.2/init.exp | 732 + .../lib/kadm5/unit-test/api.2/mod-policy.exp | 703 + .../unit-test/api.2/mod-principal-v2.exp | 114 + .../kadm5/unit-test/api.2/mod-principal.exp | 1942 +++ .../unit-test/api.2/randkey-principal-v2.exp | 62 + .../unit-test/api.2/randkey-principal.exp | 319 + .../src/lib/kadm5/unit-test/config/unix.exp | 179 + .../src/lib/kadm5/unit-test/destroy-test.c | 42 + .../lib/kadm5/unit-test/diff-files/destroy-1 | 2 + .../lib/kadm5/unit-test/diff-files/no-diffs | 2 + .../src/lib/kadm5/unit-test/handle-test.c | 130 + mechglue/src/lib/kadm5/unit-test/init-test.c | 29 + mechglue/src/lib/kadm5/unit-test/iter-test.c | 47 + mechglue/src/lib/kadm5/unit-test/lib/lib.t | 305 + mechglue/src/lib/kadm5/unit-test/lock-test.c | 111 + .../src/lib/kadm5/unit-test/randkey-test.c | 44 + .../src/lib/kadm5/unit-test/setkey-test.c | 233 + mechglue/src/lib/kadm5/unit-test/site.exp | 2 + mechglue/src/lib/kdb/.Sanitize | 48 + mechglue/src/lib/kdb/ChangeLog | 1159 ++ mechglue/src/lib/kdb/Makefile.in | 108 + mechglue/src/lib/kdb/adb_err.et | 16 + mechglue/src/lib/kdb/configure.in | 15 + mechglue/src/lib/kdb/decrypt_key.c | 138 + mechglue/src/lib/kdb/encrypt_key.c | 135 + mechglue/src/lib/kdb/err_handle.c | 209 + mechglue/src/lib/kdb/err_handle.h | 37 + mechglue/src/lib/kdb/kdb5.c | 1960 +++ mechglue/src/lib/kdb/kdb5.h | 219 + mechglue/src/lib/kdb/kdb_cpw.c | 648 + mechglue/src/lib/kdb/kdb_default.c | 329 + mechglue/src/lib/kdb/keytab.c | 236 + mechglue/src/lib/kdb/libkdb5.exports | 50 + mechglue/src/lib/krb4/.Sanitize | 131 + mechglue/src/lib/krb4/CCache-glue.c | 741 + mechglue/src/lib/krb4/ChangeLog | 2904 ++++ mechglue/src/lib/krb4/FSp-glue.c | 112 + mechglue/src/lib/krb4/Makefile.in | 604 + mechglue/src/lib/krb4/Password.c | 436 + mechglue/src/lib/krb4/RealmsConfig-glue.c | 697 + mechglue/src/lib/krb4/ad_print.c | 85 + mechglue/src/lib/krb4/change_password.c | 127 + mechglue/src/lib/krb4/configure.in | 23 + mechglue/src/lib/krb4/cr_auth_repl.c | 136 + mechglue/src/lib/krb4/cr_ciph.c | 136 + mechglue/src/lib/krb4/cr_death_pkt.c | 78 + mechglue/src/lib/krb4/cr_err_repl.c | 110 + mechglue/src/lib/krb4/cr_tkt.c | 254 + mechglue/src/lib/krb4/debug.c | 15 + mechglue/src/lib/krb4/decomp_tkt.c | 295 + mechglue/src/lib/krb4/dest_tkt.c | 160 + mechglue/src/lib/krb4/err_txt.c | 87 + mechglue/src/lib/krb4/et_errtxt.awk | 71 + mechglue/src/lib/krb4/fakeenv.c | 88 + mechglue/src/lib/krb4/fgetst.c | 38 + mechglue/src/lib/krb4/g_ad_tkt.c | 383 + mechglue/src/lib/krb4/g_cnffile.c | 123 + mechglue/src/lib/krb4/g_cred.c | 58 + mechglue/src/lib/krb4/g_in_tkt.c | 535 + mechglue/src/lib/krb4/g_phost.c | 92 + mechglue/src/lib/krb4/g_pw_in_tkt.c | 383 + mechglue/src/lib/krb4/g_pw_tkt.c | 68 + mechglue/src/lib/krb4/g_svc_in_tkt.c | 152 + mechglue/src/lib/krb4/g_tf_fname.c | 67 + mechglue/src/lib/krb4/g_tf_realm.c | 44 + mechglue/src/lib/krb4/g_tkt_svc.c | 174 + mechglue/src/lib/krb4/gethostname.c | 36 + mechglue/src/lib/krb4/getst.c | 40 + mechglue/src/lib/krb4/in_tkt.c | 199 + mechglue/src/lib/krb4/kadm_err.et | 58 + mechglue/src/lib/krb4/kadm_net.c | 392 + mechglue/src/lib/krb4/kadm_stream.c | 325 + mechglue/src/lib/krb4/klog.c | 124 + mechglue/src/lib/krb4/kname_parse.c | 411 + mechglue/src/lib/krb4/kntoln.c | 62 + mechglue/src/lib/krb4/kparse.c | 784 + mechglue/src/lib/krb4/krb4int.h | 118 + mechglue/src/lib/krb4/krb_err.et | 776 + mechglue/src/lib/krb4/kuserok.c | 258 + mechglue/src/lib/krb4/libkrb4.exports | 165 + mechglue/src/lib/krb4/lifetime.c | 62 + mechglue/src/lib/krb4/log.c | 148 + mechglue/src/lib/krb4/mac_glue.c | 48 + mechglue/src/lib/krb4/mac_store.c | 731 + mechglue/src/lib/krb4/mac_store.h | 56 + mechglue/src/lib/krb4/mac_stubs.c | 525 + mechglue/src/lib/krb4/mac_time.c | 152 + mechglue/src/lib/krb4/memcache.c | 891 ++ mechglue/src/lib/krb4/memcache.h | 36 + mechglue/src/lib/krb4/mk_auth.c | 249 + mechglue/src/lib/krb4/mk_err.c | 83 + mechglue/src/lib/krb4/mk_preauth.c | 78 + mechglue/src/lib/krb4/mk_priv.c | 301 + mechglue/src/lib/krb4/mk_req.c | 281 + mechglue/src/lib/krb4/mk_safe.c | 167 + mechglue/src/lib/krb4/month_sname.c | 28 + mechglue/src/lib/krb4/netread.c | 69 + mechglue/src/lib/krb4/netwrite.c | 65 + mechglue/src/lib/krb4/password_to_key.c | 152 + mechglue/src/lib/krb4/pkt_cipher.c | 35 + mechglue/src/lib/krb4/pkt_clen.c | 47 + mechglue/src/lib/krb4/prot_client.c | 370 + mechglue/src/lib/krb4/prot_common.c | 136 + mechglue/src/lib/krb4/prot_kdc.c | 461 + mechglue/src/lib/krb4/put_svc_key.c | 94 + mechglue/src/lib/krb4/rd_err.c | 78 + mechglue/src/lib/krb4/rd_preauth.c | 62 + mechglue/src/lib/krb4/rd_priv.c | 233 + mechglue/src/lib/krb4/rd_req.c | 543 + mechglue/src/lib/krb4/rd_safe.c | 208 + mechglue/src/lib/krb4/rd_svc_key.c | 344 + mechglue/src/lib/krb4/recvauth.c | 308 + mechglue/src/lib/krb4/ren-cyg.sh | 11 + mechglue/src/lib/krb4/ren-pc.bat | 29 + mechglue/src/lib/krb4/ren-pc.sh | 7 + mechglue/src/lib/krb4/ren-pl10.sh | 7 + mechglue/src/lib/krb4/ren.msg | 117 + mechglue/src/lib/krb4/ren2dos.sh | 7 + mechglue/src/lib/krb4/ren2long.sh | 7 + mechglue/src/lib/krb4/save_creds.c | 87 + mechglue/src/lib/krb4/sed-cyg.sh | 13 + mechglue/src/lib/krb4/sed-pc.sh | 11 + mechglue/src/lib/krb4/sed-pl10.sh | 10 + mechglue/src/lib/krb4/send_to_kdc.c | 206 + mechglue/src/lib/krb4/sendauth.c | 282 + mechglue/src/lib/krb4/setenv.c | 164 + mechglue/src/lib/krb4/stime.c | 57 + mechglue/src/lib/krb4/strcasecmp.c | 83 + mechglue/src/lib/krb4/strnlen.c | 50 + mechglue/src/lib/krb4/swab.c | 18 + mechglue/src/lib/krb4/tf_shm.c | 171 + mechglue/src/lib/krb4/tf_util.c | 788 + mechglue/src/lib/krb4/tkt_string.c | 100 + mechglue/src/lib/krb4/unix_glue.c | 40 + mechglue/src/lib/krb4/unix_time.c | 26 + mechglue/src/lib/krb4/vmslink.com | 79 + mechglue/src/lib/krb4/vmsswab.c | 34 + mechglue/src/lib/krb4/win_glue.c | 51 + mechglue/src/lib/krb4/win_store.c | 150 + mechglue/src/lib/krb4/win_time.c | 121 + mechglue/src/lib/krb4_32.def | 86 + mechglue/src/lib/krb5.rc | 44 + mechglue/src/lib/krb5.saber.warnings | 294 + mechglue/src/lib/krb5/.Sanitize | 45 + mechglue/src/lib/krb5/ChangeLog | 597 + mechglue/src/lib/krb5/Makefile.in | 147 + mechglue/src/lib/krb5/asn.1/.Sanitize | 59 + mechglue/src/lib/krb5/asn.1/.rconf | 8 + mechglue/src/lib/krb5/asn.1/.saberinit | 4 + mechglue/src/lib/krb5/asn.1/ChangeLog | 1293 ++ mechglue/src/lib/krb5/asn.1/KRB5-asn.py | 436 + mechglue/src/lib/krb5/asn.1/Makefile.in | 132 + mechglue/src/lib/krb5/asn.1/asn1_decode.c | 261 + mechglue/src/lib/krb5/asn.1/asn1_decode.h | 92 + mechglue/src/lib/krb5/asn.1/asn1_encode.c | 297 + mechglue/src/lib/krb5/asn.1/asn1_encode.h | 159 + mechglue/src/lib/krb5/asn.1/asn1_get.c | 118 + mechglue/src/lib/krb5/asn.1/asn1_get.h | 77 + mechglue/src/lib/krb5/asn.1/asn1_k_decode.c | 1094 ++ mechglue/src/lib/krb5/asn.1/asn1_k_decode.h | 192 + mechglue/src/lib/krb5/asn.1/asn1_k_encode.c | 961 ++ mechglue/src/lib/krb5/asn.1/asn1_k_encode.h | 272 + mechglue/src/lib/krb5/asn.1/asn1_make.c | 160 + mechglue/src/lib/krb5/asn.1/asn1_make.h | 134 + mechglue/src/lib/krb5/asn.1/asn1_misc.c | 37 + mechglue/src/lib/krb5/asn.1/asn1_misc.h | 39 + mechglue/src/lib/krb5/asn.1/asn1buf.c | 384 + mechglue/src/lib/krb5/asn.1/asn1buf.h | 231 + mechglue/src/lib/krb5/asn.1/asn1glue.h | 46 + mechglue/src/lib/krb5/asn.1/krb5_decode.c | 935 ++ mechglue/src/lib/krb5/asn.1/krb5_encode.c | 889 ++ mechglue/src/lib/krb5/asn.1/krbasn1.h | 81 + mechglue/src/lib/krb5/ccache/.Sanitize | 43 + mechglue/src/lib/krb5/ccache/ChangeLog | 1069 ++ mechglue/src/lib/krb5/ccache/Makefile.in | 159 + mechglue/src/lib/krb5/ccache/cc-int.h | 48 + mechglue/src/lib/krb5/ccache/cc_file.c | 2371 +++ mechglue/src/lib/krb5/ccache/cc_memory.c | 617 + mechglue/src/lib/krb5/ccache/cc_mslsa.c | 2613 ++++ mechglue/src/lib/krb5/ccache/cc_retr.c | 289 + mechglue/src/lib/krb5/ccache/ccapi/ChangeLog | 232 + .../src/lib/krb5/ccache/ccapi/Makefile.in | 25 + mechglue/src/lib/krb5/ccache/ccapi/stdcc.c | 772 + mechglue/src/lib/krb5/ccache/ccapi/stdcc.h | 80 + .../src/lib/krb5/ccache/ccapi/stdcc_util.c | 555 + .../src/lib/krb5/ccache/ccapi/stdcc_util.h | 27 + mechglue/src/lib/krb5/ccache/ccapi/winccld.c | 96 + mechglue/src/lib/krb5/ccache/ccapi/winccld.h | 184 + mechglue/src/lib/krb5/ccache/ccbase.c | 194 + mechglue/src/lib/krb5/ccache/cccopy.c | 62 + mechglue/src/lib/krb5/ccache/ccdefault.c | 109 + mechglue/src/lib/krb5/ccache/ccdefops.c | 50 + mechglue/src/lib/krb5/ccache/ccfns.c | 130 + mechglue/src/lib/krb5/ccache/fcc.h | 36 + mechglue/src/lib/krb5/ccache/scc.h | 101 + mechglue/src/lib/krb5/ccache/ser_cc.c | 202 + mechglue/src/lib/krb5/ccache/t_cc.c | 292 + mechglue/src/lib/krb5/ccache/t_memory.c | 140 + mechglue/src/lib/krb5/ccache/t_stdio.c | 169 + mechglue/src/lib/krb5/configure.in | 23 + mechglue/src/lib/krb5/error_tables/.Sanitize | 44 + mechglue/src/lib/krb5/error_tables/.rconf | 4 + mechglue/src/lib/krb5/error_tables/ChangeLog | 468 + .../src/lib/krb5/error_tables/Makefile.in | 81 + .../src/lib/krb5/error_tables/asn1_err.et | 15 + mechglue/src/lib/krb5/error_tables/init_ets.c | 50 + .../src/lib/krb5/error_tables/kdb5_err.et | 71 + .../src/lib/krb5/error_tables/krb524_err.et | 34 + .../src/lib/krb5/error_tables/krb5_err.et | 345 + .../src/lib/krb5/error_tables/kv5m_err.et | 90 + mechglue/src/lib/krb5/keytab/.Sanitize | 45 + mechglue/src/lib/krb5/keytab/ChangeLog | 676 + mechglue/src/lib/krb5/keytab/Makefile.in | 118 + mechglue/src/lib/krb5/keytab/kt-int.h | 39 + mechglue/src/lib/krb5/keytab/kt_file.c | 1717 +++ mechglue/src/lib/krb5/keytab/kt_srvtab.c | 482 + mechglue/src/lib/krb5/keytab/ktadd.c | 39 + mechglue/src/lib/krb5/keytab/ktbase.c | 244 + mechglue/src/lib/krb5/keytab/ktdefault.c | 45 + mechglue/src/lib/krb5/keytab/ktfns.c | 79 + mechglue/src/lib/krb5/keytab/ktfr_entry.c | 50 + mechglue/src/lib/krb5/keytab/ktremove.c | 39 + mechglue/src/lib/krb5/keytab/read_servi.c | 81 + mechglue/src/lib/krb5/krb/.Sanitize | 116 + mechglue/src/lib/krb5/krb/ChangeLog | 3615 +++++ mechglue/src/lib/krb5/krb/Makefile.in | 933 ++ mechglue/src/lib/krb5/krb/addr_comp.c | 48 + mechglue/src/lib/krb5/krb/addr_order.c | 63 + mechglue/src/lib/krb5/krb/addr_srch.c | 46 + mechglue/src/lib/krb5/krb/appdefault.c | 166 + mechglue/src/lib/krb5/krb/auth_con.c | 563 + mechglue/src/lib/krb5/krb/auth_con.h | 36 + mechglue/src/lib/krb5/krb/bld_pr_ext.c | 102 + mechglue/src/lib/krb5/krb/bld_princ.c | 110 + mechglue/src/lib/krb5/krb/brand.c | 72 + mechglue/src/lib/krb5/krb/chk_trans.c | 441 + mechglue/src/lib/krb5/krb/chpw.c | 515 + mechglue/src/lib/krb5/krb/cleanup.h | 29 + mechglue/src/lib/krb5/krb/conv_creds.c | 294 + mechglue/src/lib/krb5/krb/conv_princ.c | 352 + mechglue/src/lib/krb5/krb/copy_addrs.c | 143 + mechglue/src/lib/krb5/krb/copy_athctr.c | 85 + mechglue/src/lib/krb5/krb/copy_auth.c | 86 + mechglue/src/lib/krb5/krb/copy_cksum.c | 55 + mechglue/src/lib/krb5/krb/copy_creds.c | 98 + mechglue/src/lib/krb5/krb/copy_data.c | 82 + mechglue/src/lib/krb5/krb/copy_key.c | 55 + mechglue/src/lib/krb5/krb/copy_princ.c | 95 + mechglue/src/lib/krb5/krb/copy_tick.c | 134 + mechglue/src/lib/krb5/krb/cp_key_cnt.c | 47 + mechglue/src/lib/krb5/krb/decode_kdc.c | 77 + mechglue/src/lib/krb5/krb/decrypt_tk.c | 73 + mechglue/src/lib/krb5/krb/deltat.c | 1455 ++ mechglue/src/lib/krb5/krb/enc_helper.c | 50 + mechglue/src/lib/krb5/krb/encode_kdc.c | 128 + mechglue/src/lib/krb5/krb/encrypt_tk.c | 67 + mechglue/src/lib/krb5/krb/free_rtree.c | 41 + mechglue/src/lib/krb5/krb/fwd_tgt.c | 197 + mechglue/src/lib/krb5/krb/gc_frm_kdc.c | 850 ++ mechglue/src/lib/krb5/krb/gc_via_tkt.c | 244 + mechglue/src/lib/krb5/krb/gen_seqnum.c | 67 + mechglue/src/lib/krb5/krb/gen_subkey.c | 52 + mechglue/src/lib/krb5/krb/get_creds.c | 333 + mechglue/src/lib/krb5/krb/get_in_tkt.c | 1118 ++ mechglue/src/lib/krb5/krb/gic_keytab.c | 201 + mechglue/src/lib/krb5/krb/gic_opt.c | 65 + mechglue/src/lib/krb5/krb/gic_pwd.c | 487 + mechglue/src/lib/krb5/krb/in_tkt_sky.c | 112 + mechglue/src/lib/krb5/krb/init_ctx.c | 494 + mechglue/src/lib/krb5/krb/init_keyblock.c | 41 + mechglue/src/lib/krb5/krb/int-proto.h | 52 + mechglue/src/lib/krb5/krb/kdc_rep_dc.c | 80 + mechglue/src/lib/krb5/krb/kfree.c | 715 + mechglue/src/lib/krb5/krb/mk_cred.c | 307 + mechglue/src/lib/krb5/krb/mk_error.c | 51 + mechglue/src/lib/krb5/krb/mk_priv.c | 233 + mechglue/src/lib/krb5/krb/mk_rep.c | 96 + mechglue/src/lib/krb5/krb/mk_req.c | 91 + mechglue/src/lib/krb5/krb/mk_req_ext.c | 281 + mechglue/src/lib/krb5/krb/mk_safe.c | 259 + mechglue/src/lib/krb5/krb/parse.c | 285 + mechglue/src/lib/krb5/krb/pr_to_salt.c | 86 + mechglue/src/lib/krb5/krb/preauth.c | 581 + mechglue/src/lib/krb5/krb/preauth2.c | 1031 ++ mechglue/src/lib/krb5/krb/princ_comp.c | 67 + mechglue/src/lib/krb5/krb/rd_cred.c | 247 + mechglue/src/lib/krb5/krb/rd_error.c | 49 + mechglue/src/lib/krb5/krb/rd_priv.c | 272 + mechglue/src/lib/krb5/krb/rd_rep.c | 115 + mechglue/src/lib/krb5/krb/rd_req.c | 117 + mechglue/src/lib/krb5/krb/rd_req_dec.c | 393 + mechglue/src/lib/krb5/krb/rd_safe.c | 275 + mechglue/src/lib/krb5/krb/recvauth.c | 266 + mechglue/src/lib/krb5/krb/send_tgs.c | 309 + mechglue/src/lib/krb5/krb/sendauth.c | 233 + mechglue/src/lib/krb5/krb/ser_actx.c | 563 + mechglue/src/lib/krb5/krb/ser_adata.c | 199 + mechglue/src/lib/krb5/krb/ser_addr.c | 203 + mechglue/src/lib/krb5/krb/ser_auth.c | 350 + mechglue/src/lib/krb5/krb/ser_cksum.c | 202 + mechglue/src/lib/krb5/krb/ser_ctx.c | 637 + mechglue/src/lib/krb5/krb/ser_eblk.c | 258 + mechglue/src/lib/krb5/krb/ser_key.c | 200 + mechglue/src/lib/krb5/krb/ser_princ.c | 181 + mechglue/src/lib/krb5/krb/serialize.c | 278 + mechglue/src/lib/krb5/krb/set_realm.c | 52 + mechglue/src/lib/krb5/krb/srv_rcache.c | 132 + mechglue/src/lib/krb5/krb/str_conv.c | 376 + mechglue/src/lib/krb5/krb/strftime.c | 415 + mechglue/src/lib/krb5/krb/strptime.c | 386 + mechglue/src/lib/krb5/krb/t_deltat.c | 158 + mechglue/src/lib/krb5/krb/t_expand.c | 2 + mechglue/src/lib/krb5/krb/t_kerb.c | 231 + mechglue/src/lib/krb5/krb/t_krb5.conf | 52 + mechglue/src/lib/krb5/krb/t_ref_kerb.out | 19 + mechglue/src/lib/krb5/krb/t_ser.c | 729 + mechglue/src/lib/krb5/krb/t_walk_rtree.c | 58 + mechglue/src/lib/krb5/krb/tgtname.c | 42 + mechglue/src/lib/krb5/krb/transit-tests | 54 + mechglue/src/lib/krb5/krb/unparse.c | 200 + mechglue/src/lib/krb5/krb/v4lifetime.c | 149 + mechglue/src/lib/krb5/krb/valid_times.c | 64 + mechglue/src/lib/krb5/krb/vfy_increds.c | 222 + mechglue/src/lib/krb5/krb/vic_opt.c | 14 + mechglue/src/lib/krb5/krb/walk_rtree.c | 384 + mechglue/src/lib/krb5/krb/x-deltat.y | 229 + mechglue/src/lib/krb5/krb5_libinit.c | 108 + mechglue/src/lib/krb5/krb5_libinit.h | 9 + mechglue/src/lib/krb5/libkrb5.exports | 728 + mechglue/src/lib/krb5/os/.Sanitize | 79 + mechglue/src/lib/krb5/os/ChangeLog | 3022 ++++ mechglue/src/lib/krb5/os/Makefile.in | 557 + mechglue/src/lib/krb5/os/accessor.c | 69 + mechglue/src/lib/krb5/os/an_to_ln.c | 831 ++ mechglue/src/lib/krb5/os/c_ustime.c | 117 + mechglue/src/lib/krb5/os/ccdefname.c | 299 + mechglue/src/lib/krb5/os/changepw.c | 429 + mechglue/src/lib/krb5/os/def_realm.c | 193 + mechglue/src/lib/krb5/os/dnsglue.c | 333 + mechglue/src/lib/krb5/os/dnsglue.h | 156 + mechglue/src/lib/krb5/os/dnssrv.c | 184 + mechglue/src/lib/krb5/os/free_hstrl.c | 42 + mechglue/src/lib/krb5/os/free_krbhs.c | 45 + mechglue/src/lib/krb5/os/full_ipadr.c | 86 + mechglue/src/lib/krb5/os/gen_port.c | 49 + mechglue/src/lib/krb5/os/gen_rname.c | 50 + mechglue/src/lib/krb5/os/genaddrs.c | 130 + mechglue/src/lib/krb5/os/get_krbhst.c | 128 + mechglue/src/lib/krb5/os/gmt_mktime.c | 127 + mechglue/src/lib/krb5/os/hostaddr.c | 137 + mechglue/src/lib/krb5/os/hst_realm.c | 385 + mechglue/src/lib/krb5/os/init_os_ctx.c | 484 + mechglue/src/lib/krb5/os/krbfileio.c | 103 + mechglue/src/lib/krb5/os/ktdefname.c | 83 + mechglue/src/lib/krb5/os/kuserok.c | 164 + mechglue/src/lib/krb5/os/localaddr.c | 1565 ++ mechglue/src/lib/krb5/os/locate_kdc.c | 653 + mechglue/src/lib/krb5/os/lock_file.c | 139 + mechglue/src/lib/krb5/os/mk_faddr.c | 88 + mechglue/src/lib/krb5/os/net_read.c | 65 + mechglue/src/lib/krb5/os/net_write.c | 61 + mechglue/src/lib/krb5/os/os-proto.h | 72 + mechglue/src/lib/krb5/os/osconfig.c | 46 + mechglue/src/lib/krb5/os/port2ip.c | 84 + mechglue/src/lib/krb5/os/prompter.c | 327 + mechglue/src/lib/krb5/os/promptusr.c | 160 + mechglue/src/lib/krb5/os/read_msg.c | 63 + mechglue/src/lib/krb5/os/read_pwd.c | 297 + mechglue/src/lib/krb5/os/realm_dom.c | 67 + mechglue/src/lib/krb5/os/realm_iter.c | 60 + mechglue/src/lib/krb5/os/ref_std_conf.out | 13 + mechglue/src/lib/krb5/os/send524.c | 109 + mechglue/src/lib/krb5/os/sendto_kdc.c | 1163 ++ mechglue/src/lib/krb5/os/sn2princ.c | 191 + mechglue/src/lib/krb5/os/t_an_to_ln.c | 41 + mechglue/src/lib/krb5/os/t_gifconf.c | 134 + mechglue/src/lib/krb5/os/t_locate_kdc.c | 129 + mechglue/src/lib/krb5/os/t_realm_iter.c | 44 + mechglue/src/lib/krb5/os/t_std_conf.c | 247 + mechglue/src/lib/krb5/os/td_krb5.conf | 19 + mechglue/src/lib/krb5/os/thread_safe.c | 40 + mechglue/src/lib/krb5/os/timeofday.c | 52 + mechglue/src/lib/krb5/os/toffset.c | 115 + mechglue/src/lib/krb5/os/unlck_file.c | 37 + mechglue/src/lib/krb5/os/ustime.c | 66 + mechglue/src/lib/krb5/os/write_msg.c | 47 + mechglue/src/lib/krb5/posix/.Sanitize | 47 + mechglue/src/lib/krb5/posix/ChangeLog | 264 + mechglue/src/lib/krb5/posix/Makefile.in | 17 + mechglue/src/lib/krb5/posix/getuid.c | 6 + mechglue/src/lib/krb5/posix/memmove.c | 146 + mechglue/src/lib/krb5/posix/sscanf.c | 788 + mechglue/src/lib/krb5/posix/strcasecmp.c | 115 + mechglue/src/lib/krb5/posix/strdup.c | 38 + mechglue/src/lib/krb5/posix/strerror.c | 65 + mechglue/src/lib/krb5/posix/syslog.c | 257 + mechglue/src/lib/krb5/posix/vfprintf.c | 44 + mechglue/src/lib/krb5/posix/vsprintf.c | 38 + mechglue/src/lib/krb5/rcache/.Sanitize | 48 + mechglue/src/lib/krb5/rcache/.rconf | 2 + mechglue/src/lib/krb5/rcache/ChangeLog | 505 + mechglue/src/lib/krb5/rcache/Makefile.in | 106 + mechglue/src/lib/krb5/rcache/README | 82 + mechglue/src/lib/krb5/rcache/RELEASE | 17 + mechglue/src/lib/krb5/rcache/rc-int.h | 77 + mechglue/src/lib/krb5/rcache/rc_base.c | 173 + mechglue/src/lib/krb5/rcache/rc_base.h | 15 + mechglue/src/lib/krb5/rcache/rc_conv.c | 38 + mechglue/src/lib/krb5/rcache/rc_dfl.c | 711 + mechglue/src/lib/krb5/rcache/rc_dfl.h | 56 + mechglue/src/lib/krb5/rcache/rc_io.c | 453 + mechglue/src/lib/krb5/rcache/rc_io.h | 70 + mechglue/src/lib/krb5/rcache/rc_none.c | 88 + mechglue/src/lib/krb5/rcache/rcdef.c | 49 + mechglue/src/lib/krb5/rcache/rcfns.c | 95 + mechglue/src/lib/krb5/rcache/ser_rc.c | 208 + mechglue/src/lib/krb5_32.def | 285 + mechglue/src/lib/rpc/ChangeLog | 1342 ++ mechglue/src/lib/rpc/Makefile.in | 567 + mechglue/src/lib/rpc/auth.h | 219 + mechglue/src/lib/rpc/auth_gss.c | 632 + mechglue/src/lib/rpc/auth_gss.h | 149 + mechglue/src/lib/rpc/auth_gssapi.c | 812 + mechglue/src/lib/rpc/auth_gssapi.h | 153 + mechglue/src/lib/rpc/auth_gssapi_misc.c | 328 + mechglue/src/lib/rpc/auth_none.c | 145 + mechglue/src/lib/rpc/auth_unix.c | 330 + mechglue/src/lib/rpc/auth_unix.h | 80 + mechglue/src/lib/rpc/authgss_prot.c | 366 + mechglue/src/lib/rpc/authunix_prot.c | 64 + mechglue/src/lib/rpc/bindresvport.c | 83 + mechglue/src/lib/rpc/clnt.h | 344 + mechglue/src/lib/rpc/clnt_generic.c | 114 + mechglue/src/lib/rpc/clnt_perror.c | 343 + mechglue/src/lib/rpc/clnt_raw.c | 268 + mechglue/src/lib/rpc/clnt_simple.c | 128 + mechglue/src/lib/rpc/clnt_tcp.c | 496 + mechglue/src/lib/rpc/clnt_udp.c | 484 + mechglue/src/lib/rpc/configure.in | 175 + mechglue/src/lib/rpc/dyn.c | 577 + mechglue/src/lib/rpc/dyn.h | 79 + mechglue/src/lib/rpc/dynP.h | 50 + mechglue/src/lib/rpc/dyntest.c | 216 + mechglue/src/lib/rpc/get_myaddress.c | 116 + mechglue/src/lib/rpc/getrpcent.c | 236 + mechglue/src/lib/rpc/getrpcport.c | 65 + mechglue/src/lib/rpc/libgssrpc.exports | 141 + mechglue/src/lib/rpc/netdb.h | 51 + mechglue/src/lib/rpc/pmap_clnt.c | 115 + mechglue/src/lib/rpc/pmap_clnt.h | 81 + mechglue/src/lib/rpc/pmap_getmaps.c | 87 + mechglue/src/lib/rpc/pmap_getport.c | 92 + mechglue/src/lib/rpc/pmap_prot.c | 55 + mechglue/src/lib/rpc/pmap_prot.h | 101 + mechglue/src/lib/rpc/pmap_prot2.c | 114 + mechglue/src/lib/rpc/pmap_rmt.c | 417 + mechglue/src/lib/rpc/pmap_rmt.h | 63 + mechglue/src/lib/rpc/rename.h | 307 + mechglue/src/lib/rpc/rpc.h | 99 + mechglue/src/lib/rpc/rpc_callmsg.c | 194 + mechglue/src/lib/rpc/rpc_commondata.c | 47 + mechglue/src/lib/rpc/rpc_dtablesize.c | 62 + mechglue/src/lib/rpc/rpc_msg.h | 205 + mechglue/src/lib/rpc/rpc_prot.c | 293 + mechglue/src/lib/rpc/svc.c | 526 + mechglue/src/lib/rpc/svc.h | 337 + mechglue/src/lib/rpc/svc_auth.c | 109 + mechglue/src/lib/rpc/svc_auth.h | 117 + mechglue/src/lib/rpc/svc_auth_gss.c | 724 + mechglue/src/lib/rpc/svc_auth_gssapi.c | 1094 ++ mechglue/src/lib/rpc/svc_auth_none.c | 75 + mechglue/src/lib/rpc/svc_auth_unix.c | 140 + mechglue/src/lib/rpc/svc_raw.c | 160 + mechglue/src/lib/rpc/svc_run.c | 74 + mechglue/src/lib/rpc/svc_simple.c | 149 + mechglue/src/lib/rpc/svc_tcp.c | 503 + mechglue/src/lib/rpc/svc_udp.c | 530 + mechglue/src/lib/rpc/types.hin | 175 + mechglue/src/lib/rpc/unit-test/ChangeLog | 337 + mechglue/src/lib/rpc/unit-test/Makefile.in | 69 + mechglue/src/lib/rpc/unit-test/client.c | 272 + .../src/lib/rpc/unit-test/config/unix.exp | 125 + mechglue/src/lib/rpc/unit-test/configure.in | 29 + .../src/lib/rpc/unit-test/lib/helpers.exp | 236 + .../lib/rpc/unit-test/rpc_test.0/expire.exp | 46 + .../lib/rpc/unit-test/rpc_test.0/fullrun.exp | 95 + .../lib/rpc/unit-test/rpc_test.0/gsserr.exp | 27 + mechglue/src/lib/rpc/unit-test/rpc_test.h | 13 + mechglue/src/lib/rpc/unit-test/rpc_test.x | 30 + .../src/lib/rpc/unit-test/rpc_test_clnt.c | 22 + .../src/lib/rpc/unit-test/rpc_test_setup.sh | 59 + mechglue/src/lib/rpc/unit-test/rpc_test_svc.c | 74 + mechglue/src/lib/rpc/unit-test/server.c | 289 + mechglue/src/lib/rpc/xdr.c | 637 + mechglue/src/lib/rpc/xdr.h | 334 + mechglue/src/lib/rpc/xdr_alloc.c | 151 + mechglue/src/lib/rpc/xdr_array.c | 158 + mechglue/src/lib/rpc/xdr_float.c | 289 + mechglue/src/lib/rpc/xdr_mem.c | 182 + mechglue/src/lib/rpc/xdr_rec.c | 570 + mechglue/src/lib/rpc/xdr_reference.c | 137 + mechglue/src/lib/rpc/xdr_stdio.c | 170 + mechglue/src/lib/win_glue.c | 489 + mechglue/src/lib/xpprof32.def | 28 + mechglue/src/patchlevel.h | 58 + mechglue/src/plugins/kdb/db2/ChangeLog | 142 + mechglue/src/plugins/kdb/db2/Makefile.in | 147 + mechglue/src/plugins/kdb/db2/adb_openclose.c | 412 + mechglue/src/plugins/kdb/db2/adb_policy.c | 389 + mechglue/src/plugins/kdb/db2/configure.in | 27 + mechglue/src/plugins/kdb/db2/db2.exports | 1 + mechglue/src/plugins/kdb/db2/db2_exp.c | 64 + mechglue/src/plugins/kdb/db2/kdb_compat.h | 81 + mechglue/src/plugins/kdb/db2/kdb_db2.c | 1561 ++ mechglue/src/plugins/kdb/db2/kdb_db2.h | 216 + mechglue/src/plugins/kdb/db2/kdb_xdr.c | 493 + mechglue/src/plugins/kdb/db2/kdb_xdr.h | 32 + .../src/plugins/kdb/db2/libdb2/CHANGELOG.db2 | 123 + mechglue/src/plugins/kdb/db2/libdb2/ChangeLog | 513 + .../src/plugins/kdb/db2/libdb2/Makefile.in | 41 + .../src/plugins/kdb/db2/libdb2/Makefile.inc | 10 + mechglue/src/plugins/kdb/db2/libdb2/README | 17 + .../kdb/db2/libdb2/README.NOT.SLEEPYCAT.DB | 2 + .../src/plugins/kdb/db2/libdb2/README.db2 | 41 + .../plugins/kdb/db2/libdb2/btree/Makefile.in | 14 + .../plugins/kdb/db2/libdb2/btree/Makefile.inc | 7 + .../plugins/kdb/db2/libdb2/btree/bt_close.c | 183 + .../plugins/kdb/db2/libdb2/btree/bt_conv.c | 221 + .../plugins/kdb/db2/libdb2/btree/bt_debug.c | 377 + .../plugins/kdb/db2/libdb2/btree/bt_delete.c | 657 + .../src/plugins/kdb/db2/libdb2/btree/bt_get.c | 105 + .../plugins/kdb/db2/libdb2/btree/bt_open.c | 476 + .../kdb/db2/libdb2/btree/bt_overflow.c | 228 + .../plugins/kdb/db2/libdb2/btree/bt_page.c | 100 + .../src/plugins/kdb/db2/libdb2/btree/bt_put.c | 328 + .../plugins/kdb/db2/libdb2/btree/bt_search.c | 297 + .../src/plugins/kdb/db2/libdb2/btree/bt_seq.c | 901 ++ .../plugins/kdb/db2/libdb2/btree/bt_split.c | 828 ++ .../plugins/kdb/db2/libdb2/btree/bt_utils.c | 260 + .../src/plugins/kdb/db2/libdb2/btree/btree.h | 383 + .../src/plugins/kdb/db2/libdb2/btree/extern.h | 110 + .../plugins/kdb/db2/libdb2/clib/Makefile.in | 11 + .../src/plugins/kdb/db2/libdb2/clib/memmove.c | 142 + .../src/plugins/kdb/db2/libdb2/clib/mkstemp.c | 126 + .../plugins/kdb/db2/libdb2/clib/strerror.c | 71 + .../src/plugins/kdb/db2/libdb2/configure.in | 97 + .../src/plugins/kdb/db2/libdb2/db/Makefile.in | 11 + .../plugins/kdb/db2/libdb2/db/Makefile.inc | 5 + mechglue/src/plugins/kdb/db2/libdb2/db/db.c | 99 + .../plugins/kdb/db2/libdb2/docs/btree.3.ps | 366 + .../plugins/kdb/db2/libdb2/docs/dbopen.3.ps | 508 + .../src/plugins/kdb/db2/libdb2/docs/hash.3.ps | 292 + .../kdb/db2/libdb2/docs/hash.usenix.ps | 12209 +++++++++++++++ .../kdb/db2/libdb2/docs/libtp.usenix.ps | 12340 ++++++++++++++++ .../plugins/kdb/db2/libdb2/docs/mpool.3.ps | 320 + .../plugins/kdb/db2/libdb2/docs/recno.3.ps | 341 + .../plugins/kdb/db2/libdb2/hash/Makefile.in | 13 + .../plugins/kdb/db2/libdb2/hash/Makefile.inc | 6 + .../src/plugins/kdb/db2/libdb2/hash/dbm.c | 356 + .../src/plugins/kdb/db2/libdb2/hash/extern.h | 109 + .../src/plugins/kdb/db2/libdb2/hash/hash.c | 1068 ++ .../plugins/kdb/db2/libdb2/hash/hash.c.patch | 109 + .../src/plugins/kdb/db2/libdb2/hash/hash.h | 196 + .../plugins/kdb/db2/libdb2/hash/hash_bigkey.c | 483 + .../plugins/kdb/db2/libdb2/hash/hash_debug.c | 105 + .../plugins/kdb/db2/libdb2/hash/hash_func.c | 201 + .../plugins/kdb/db2/libdb2/hash/hash_log2.c | 55 + .../plugins/kdb/db2/libdb2/hash/hash_page.c | 1387 ++ .../src/plugins/kdb/db2/libdb2/hash/hsearch.c | 107 + .../src/plugins/kdb/db2/libdb2/hash/page.h | 178 + .../plugins/kdb/db2/libdb2/hash/page.h.patch | 42 + .../src/plugins/kdb/db2/libdb2/hash/search.h | 55 + .../plugins/kdb/db2/libdb2/include/ChangeLog | 74 + .../kdb/db2/libdb2/include/db-config.h.in | 16 + .../plugins/kdb/db2/libdb2/include/db-dbm.h | 23 + .../plugins/kdb/db2/libdb2/include/db-int.h | 283 + .../plugins/kdb/db2/libdb2/include/db-ndbm.h | 91 + .../plugins/kdb/db2/libdb2/include/db-queue.h | 245 + .../src/plugins/kdb/db2/libdb2/include/db.h | 175 + .../src/plugins/kdb/db2/libdb2/libdb.exports | 99 + .../plugins/kdb/db2/libdb2/man/Makefile.inc | 7 + .../src/plugins/kdb/db2/libdb2/man/db.man.ps | 2295 +++ .../src/plugins/kdb/db2/libdb2/man/db_btree.3 | 246 + .../src/plugins/kdb/db2/libdb2/man/db_hash.3 | 138 + .../src/plugins/kdb/db2/libdb2/man/db_lock.3 | 462 + .../src/plugins/kdb/db2/libdb2/man/db_log.3 | 290 + .../src/plugins/kdb/db2/libdb2/man/db_mpool.3 | 403 + .../src/plugins/kdb/db2/libdb2/man/db_open.3 | 574 + .../src/plugins/kdb/db2/libdb2/man/db_recno.3 | 268 + .../src/plugins/kdb/db2/libdb2/man/db_txn.3 | 373 + .../src/plugins/kdb/db2/libdb2/man/spell.ok | 170 + .../plugins/kdb/db2/libdb2/mpool/Makefile.in | 11 + .../plugins/kdb/db2/libdb2/mpool/Makefile.inc | 5 + .../src/plugins/kdb/db2/libdb2/mpool/README | 7 + .../src/plugins/kdb/db2/libdb2/mpool/mpool.c | 514 + .../src/plugins/kdb/db2/libdb2/mpool/mpool.h | 117 + .../plugins/kdb/db2/libdb2/recno/Makefile.in | 13 + .../plugins/kdb/db2/libdb2/recno/Makefile.inc | 6 + .../src/plugins/kdb/db2/libdb2/recno/extern.h | 72 + .../plugins/kdb/db2/libdb2/recno/rec_close.c | 187 + .../plugins/kdb/db2/libdb2/recno/rec_delete.c | 197 + .../plugins/kdb/db2/libdb2/recno/rec_get.c | 311 + .../plugins/kdb/db2/libdb2/recno/rec_open.c | 243 + .../plugins/kdb/db2/libdb2/recno/rec_put.c | 280 + .../plugins/kdb/db2/libdb2/recno/rec_search.c | 126 + .../plugins/kdb/db2/libdb2/recno/rec_seq.c | 131 + .../plugins/kdb/db2/libdb2/recno/rec_utils.c | 122 + .../src/plugins/kdb/db2/libdb2/recno/recno.h | 39 + .../src/plugins/kdb/db2/libdb2/test/ChangeLog | 85 + .../plugins/kdb/db2/libdb2/test/Makefile.in | 36 + .../src/plugins/kdb/db2/libdb2/test/README | 74 + .../plugins/kdb/db2/libdb2/test/SEQ_TEST/data | 8 + .../plugins/kdb/db2/libdb2/test/SEQ_TEST/mbox | 399 + .../plugins/kdb/db2/libdb2/test/SEQ_TEST/t.c | 85 + .../kdb/db2/libdb2/test/btree.tests/ChangeLog | 17 + .../kdb/db2/libdb2/test/btree.tests/main.c | 832 ++ .../src/plugins/kdb/db2/libdb2/test/dbtest.c | 768 + .../plugins/kdb/db2/libdb2/test/dictionary | 308 + .../kdb/db2/libdb2/test/hash1.tests/Makefile | 43 + .../kdb/db2/libdb2/test/hash1.tests/driver2.c | 114 + .../kdb/db2/libdb2/test/hash1.tests/makedb.sh | 13 + .../kdb/db2/libdb2/test/hash1.tests/tcreat3.c | 105 + .../kdb/db2/libdb2/test/hash1.tests/tdel.c | 122 + .../kdb/db2/libdb2/test/hash1.tests/testit | 154 + .../kdb/db2/libdb2/test/hash1.tests/thash4.c | 131 + .../kdb/db2/libdb2/test/hash1.tests/tread2.c | 105 + .../kdb/db2/libdb2/test/hash1.tests/tseq.c | 88 + .../kdb/db2/libdb2/test/hash1.tests/tverify.c | 107 + .../kdb/db2/libdb2/test/hash2.tests/README | 72 + .../kdb/db2/libdb2/test/hash2.tests/bigtest.c | 76 + .../db2/libdb2/test/hash2.tests/passtest.c | 184 + .../libdb2/test/hash2.tests/passwd/genpass.c | 23 + .../src/plugins/kdb/db2/libdb2/test/run.test | 746 + mechglue/src/plugins/kdb/db2/pol_xdr.c | 88 + mechglue/src/plugins/kdb/db2/policy_db.h | 101 + mechglue/src/prototype/.Sanitize | 34 + mechglue/src/prototype/ChangeLog | 20 + mechglue/src/prototype/getopt.c | 29 + mechglue/src/prototype/prototype.c | 30 + mechglue/src/prototype/prototype.h | 33 + mechglue/src/slave/.Sanitize | 42 + mechglue/src/slave/ChangeLog | 373 + mechglue/src/slave/Makefile.in | 56 + mechglue/src/slave/kprop.M | 67 + mechglue/src/slave/kprop.c | 759 + mechglue/src/slave/kprop.h | 37 + mechglue/src/slave/kpropd.M | 130 + mechglue/src/slave/kpropd.c | 992 ++ mechglue/src/slave/kslave_update | 30 + mechglue/src/t_krbconf | 38 + mechglue/src/tests/.Sanitize | 46 + mechglue/src/tests/ChangeLog | 206 + mechglue/src/tests/Makefile.in | 57 + mechglue/src/tests/asn.1/.Sanitize | 49 + mechglue/src/tests/asn.1/ChangeLog | 498 + mechglue/src/tests/asn.1/Makefile.in | 95 + mechglue/src/tests/asn.1/README | 28 + mechglue/src/tests/asn.1/debug.h | 20 + mechglue/src/tests/asn.1/krb5_decode_test.c | 904 ++ mechglue/src/tests/asn.1/krb5_encode_test.c | 681 + mechglue/src/tests/asn.1/ktest.c | 1291 ++ mechglue/src/tests/asn.1/ktest.h | 204 + mechglue/src/tests/asn.1/ktest_equal.c | 669 + mechglue/src/tests/asn.1/ktest_equal.h | 93 + mechglue/src/tests/asn.1/reference_encode.out | 53 + mechglue/src/tests/asn.1/trval.c | 840 ++ mechglue/src/tests/asn.1/trval_reference.out | 1198 ++ mechglue/src/tests/asn.1/utility.c | 125 + mechglue/src/tests/asn.1/utility.h | 31 + mechglue/src/tests/configure.in | 30 + mechglue/src/tests/create/.Sanitize | 38 + mechglue/src/tests/create/ChangeLog | 226 + mechglue/src/tests/create/Makefile.in | 32 + mechglue/src/tests/create/kdb5_mkdums.M | 141 + mechglue/src/tests/create/kdb5_mkdums.c | 430 + mechglue/src/tests/dejagnu/.Sanitize | 43 + mechglue/src/tests/dejagnu/ChangeLog | 149 + mechglue/src/tests/dejagnu/Makefile.in | 54 + mechglue/src/tests/dejagnu/config/.Sanitize | 33 + mechglue/src/tests/dejagnu/config/ChangeLog | 666 + mechglue/src/tests/dejagnu/config/default.exp | 2681 ++++ mechglue/src/tests/dejagnu/krb-root/.Sanitize | 34 + mechglue/src/tests/dejagnu/krb-root/ChangeLog | 91 + .../src/tests/dejagnu/krb-root/rlogin.exp | 320 + .../src/tests/dejagnu/krb-root/telnet.exp | 449 + .../tests/dejagnu/krb-standalone/.Sanitize | 39 + .../tests/dejagnu/krb-standalone/ChangeLog | 467 + .../tests/dejagnu/krb-standalone/gssapi.exp | 328 + .../tests/dejagnu/krb-standalone/gssftp.exp | 453 + .../tests/dejagnu/krb-standalone/kadmin.exp | 1075 ++ .../tests/dejagnu/krb-standalone/pwhist.exp | 215 + .../src/tests/dejagnu/krb-standalone/rcp.exp | 232 + .../src/tests/dejagnu/krb-standalone/rsh.exp | 294 + .../tests/dejagnu/krb-standalone/sample.exp | 210 + .../dejagnu/krb-standalone/standalone.exp | 156 + .../tests/dejagnu/krb-standalone/v4gssftp.exp | 505 + .../dejagnu/krb-standalone/v4krb524d.exp | 168 + .../dejagnu/krb-standalone/v4standalone.exp | 95 + mechglue/src/tests/dejagnu/t_inetd.c | 139 + mechglue/src/tests/dump.c | 43 + mechglue/src/tests/gss-threads/ChangeLog | 22 + mechglue/src/tests/gss-threads/Makefile.in | 54 + mechglue/src/tests/gss-threads/README | 165 + mechglue/src/tests/gss-threads/gss-client.c | 883 ++ mechglue/src/tests/gss-threads/gss-misc.c | 425 + mechglue/src/tests/gss-threads/gss-misc.h | 60 + mechglue/src/tests/gss-threads/gss-server.c | 850 ++ mechglue/src/tests/gssapi/.Sanitize | 37 + mechglue/src/tests/gssapi/ChangeLog | 66 + mechglue/src/tests/gssapi/Makefile.in | 27 + mechglue/src/tests/gssapi/t_imp_name.c | 148 + mechglue/src/tests/hammer/.Sanitize | 38 + mechglue/src/tests/hammer/ChangeLog | 205 + mechglue/src/tests/hammer/Makefile.in | 30 + mechglue/src/tests/hammer/kdc5_hammer.c | 530 + mechglue/src/tests/hammer/pp.c | 28 + mechglue/src/tests/misc/.Sanitize | 32 + mechglue/src/tests/misc/ChangeLog | 21 + mechglue/src/tests/misc/Makefile.in | 35 + mechglue/src/tests/misc/test_getpw.c | 25 + mechglue/src/tests/misc/test_getsockname.c | 91 + mechglue/src/tests/misc/test_nfold.c | 65 + mechglue/src/tests/resolve/.Sanitize | 37 + mechglue/src/tests/resolve/ChangeLog | 132 + mechglue/src/tests/resolve/Makefile.in | 44 + mechglue/src/tests/resolve/addrinfo-test.c | 302 + .../src/tests/resolve/fake-addrinfo-test.c | 2 + mechglue/src/tests/resolve/resolve.c | 170 + mechglue/src/tests/shlib/ChangeLog | 31 + mechglue/src/tests/shlib/Makefile.in | 39 + mechglue/src/tests/shlib/t_loader.c | 372 + mechglue/src/tests/test1.c | 195 + mechglue/src/tests/threads/ChangeLog | 18 + mechglue/src/tests/threads/Makefile.in | 44 + mechglue/src/tests/threads/prof1.c | 79 + mechglue/src/tests/threads/t_rcache.c | 174 + mechglue/src/tests/verify/.Sanitize | 38 + mechglue/src/tests/verify/ChangeLog | 196 + mechglue/src/tests/verify/Makefile.in | 31 + mechglue/src/tests/verify/kdb5_verify.c | 469 + mechglue/src/tests/verify/pkey.c | 24 + mechglue/src/util/.Sanitize | 55 + mechglue/src/util/ChangeLog | 758 + mechglue/src/util/Makefile.in | 61 + mechglue/src/util/Sanitize | 418 + mechglue/src/util/ac_check_krb5.m4 | 58 + mechglue/src/util/def-check.pl | 246 + mechglue/src/util/depfix.pl | 189 + mechglue/src/util/et/.Sanitize | 60 + mechglue/src/util/et/ChangeLog | 964 ++ mechglue/src/util/et/ISSUES | 60 + mechglue/src/util/et/Makefile.in | 262 + mechglue/src/util/et/com_err.3 | 96 + mechglue/src/util/et/com_err.c | 169 + mechglue/src/util/et/com_err.h | 72 + mechglue/src/util/et/com_err.texinfo | 555 + mechglue/src/util/et/compile_et.1 | 79 + mechglue/src/util/et/compile_et.c | 348 + mechglue/src/util/et/compile_et.sh | 24 + mechglue/src/util/et/compiler.h | 14 + mechglue/src/util/et/config_script | 22 + mechglue/src/util/et/configure.in | 27 + mechglue/src/util/et/error_message.c | 368 + mechglue/src/util/et/error_table.h | 39 + mechglue/src/util/et/error_table.y | 231 + mechglue/src/util/et/et.exp | 8 + mechglue/src/util/et/et.pbexp | 10 + mechglue/src/util/et/et1.et | 11 + mechglue/src/util/et/et2.et | 11 + mechglue/src/util/et/et_c.awk | 213 + mechglue/src/util/et/et_c.pl | 289 + mechglue/src/util/et/et_h.awk | 168 + mechglue/src/util/et/et_h.pl | 234 + mechglue/src/util/et/et_lex.lex.l | 23 + mechglue/src/util/et/et_name.c | 56 + mechglue/src/util/et/init_et.c | 108 + mechglue/src/util/et/internal.h | 15 + mechglue/src/util/et/libcom_err.exports | 9 + mechglue/src/util/et/mit-sipb-copyright.h | 22 + mechglue/src/util/et/t_com_err.c | 143 + mechglue/src/util/et/test1.et | 69 + mechglue/src/util/et/test2.et | 9 + mechglue/src/util/et/test_et.c | 75 + mechglue/src/util/et/texinfo.tex | 2077 +++ mechglue/src/util/et/vfprintf.c | 50 + mechglue/src/util/exitsleep.c | 47 + mechglue/src/util/getsyms | 63 + mechglue/src/util/getsyms.sed | 42 + mechglue/src/util/kbuild | 168 + mechglue/src/util/kfrags/.Sanitize | 40 + mechglue/src/util/kfrags/ChangeLog | 37 + mechglue/src/util/kfrags/athena.conf | 1 + mechglue/src/util/kfrags/base.conf | 16 + mechglue/src/util/kfrags/cns.conf | 1 + mechglue/src/util/kfrags/gcc.conf | 2 + mechglue/src/util/kfrags/ranlib.conf | 1 + mechglue/src/util/kfrags/shared.conf | 4 + mechglue/src/util/kfrags/sunpro.conf | 1 + mechglue/src/util/kfrags/svr4.conf | 1 + mechglue/src/util/kfrags/ucb.conf | 2 + mechglue/src/util/lndir | 103 + mechglue/src/util/makedepend/.Sanitize | 42 + mechglue/src/util/makedepend/ChangeLog | 5 + mechglue/src/util/makedepend/cpp.ed | 75 + mechglue/src/util/makedepend/cppsetup.c | 242 + mechglue/src/util/makedepend/def.h | 135 + mechglue/src/util/makedepend/ifparser.c | 451 + mechglue/src/util/makedepend/ifparser.h | 76 + mechglue/src/util/makedepend/include.c | 295 + mechglue/src/util/makedepend/main.c | 688 + mechglue/src/util/makedepend/mkdepend.man | 370 + mechglue/src/util/makedepend/parse.c | 567 + mechglue/src/util/makedepend/pr.c | 127 + mechglue/src/util/mkrel | 220 + mechglue/src/util/profile/.Sanitize | 49 + mechglue/src/util/profile/ChangeLog | 1306 ++ mechglue/src/util/profile/Makefile.in | 191 + mechglue/src/util/profile/argv_parse.c | 168 + mechglue/src/util/profile/argv_parse.h | 43 + mechglue/src/util/profile/configure.in | 21 + mechglue/src/util/profile/dosshell.ini | 537 + mechglue/src/util/profile/krb5.conf | 57 + mechglue/src/util/profile/libprofile.exports | 55 + mechglue/src/util/profile/prof_FSp_glue.c | 91 + mechglue/src/util/profile/prof_err.et | 66 + mechglue/src/util/profile/prof_file.c | 607 + mechglue/src/util/profile/prof_get.c | 462 + mechglue/src/util/profile/prof_init.c | 372 + mechglue/src/util/profile/prof_int.h | 248 + mechglue/src/util/profile/prof_parse.c | 492 + mechglue/src/util/profile/prof_set.c | 286 + mechglue/src/util/profile/prof_test1 | 154 + mechglue/src/util/profile/prof_tree.c | 714 + mechglue/src/util/profile/profile.5 | 71 + mechglue/src/util/profile/profile.exp | 35 + mechglue/src/util/profile/profile.hin | 125 + mechglue/src/util/profile/profile.pbexp | 33 + mechglue/src/util/profile/profile.swg | 258 + mechglue/src/util/profile/profile_tcl.c | 2159 +++ mechglue/src/util/profile/prtest.in | 36 + mechglue/src/util/profile/prtest.script | 11 + mechglue/src/util/profile/test.ini | 47 + mechglue/src/util/profile/test_parse.c | 54 + mechglue/src/util/profile/test_profile.c | 169 + mechglue/src/util/pty/.Sanitize | 52 + mechglue/src/util/pty/ChangeLog | 934 ++ mechglue/src/util/pty/Makefile.in | 157 + mechglue/src/util/pty/README | 108 + mechglue/src/util/pty/cleanup.c | 112 + mechglue/src/util/pty/configure.in | 261 + mechglue/src/util/pty/dump-utmp.c | 281 + mechglue/src/util/pty/getpty.c | 150 + mechglue/src/util/pty/init.c | 33 + mechglue/src/util/pty/init_slave.c | 100 + mechglue/src/util/pty/libpty.h | 54 + mechglue/src/util/pty/logwtmp.c | 112 + mechglue/src/util/pty/open_ctty.c | 67 + mechglue/src/util/pty/open_slave.c | 101 + mechglue/src/util/pty/pty-int.h | 136 + mechglue/src/util/pty/pty_err.et | 50 + mechglue/src/util/pty/pty_paranoia.c | 650 + mechglue/src/util/pty/sane_hostname.c | 116 + mechglue/src/util/pty/update_utmp.c | 706 + mechglue/src/util/pty/update_wtmp.c | 127 + mechglue/src/util/pty/vhangup.c | 50 + mechglue/src/util/pty/void_assoc.c | 49 + mechglue/src/util/reconf | 106 + mechglue/src/util/send-pr/COPYING | 339 + mechglue/src/util/send-pr/ChangeLog | 31 + mechglue/src/util/send-pr/INSTALL | 83 + mechglue/src/util/send-pr/MANIFEST | 20 + mechglue/src/util/send-pr/Makefile.in | 48 + mechglue/src/util/send-pr/README | 43 + mechglue/src/util/send-pr/categories | 11 + mechglue/src/util/send-pr/install-sid.sh | 86 + mechglue/src/util/send-pr/send-pr.1 | 289 + mechglue/src/util/send-pr/send-pr.sh | 542 + mechglue/src/util/ss/.Sanitize | 64 + mechglue/src/util/ss/ChangeLog | 430 + mechglue/src/util/ss/Makefile.in | 223 + mechglue/src/util/ss/cmd_tbl.lex.l | 81 + mechglue/src/util/ss/config_script | 28 + mechglue/src/util/ss/configure.in | 17 + mechglue/src/util/ss/copyright.h | 22 + mechglue/src/util/ss/ct.y | 81 + mechglue/src/util/ss/ct_c_awk.in | 77 + mechglue/src/util/ss/ct_c_sed.in | 161 + mechglue/src/util/ss/data.c | 16 + mechglue/src/util/ss/error.c | 69 + mechglue/src/util/ss/execute_cmd.c | 220 + mechglue/src/util/ss/help.c | 154 + mechglue/src/util/ss/invocation.c | 78 + mechglue/src/util/ss/list_rqs.c | 120 + mechglue/src/util/ss/listen.c | 169 + mechglue/src/util/ss/mit-sipb-copyright.h | 22 + mechglue/src/util/ss/mk_cmds.c | 102 + mechglue/src/util/ss/mk_cmds.sh | 29 + mechglue/src/util/ss/options.c | 32 + mechglue/src/util/ss/pager.c | 108 + mechglue/src/util/ss/parse.c | 135 + mechglue/src/util/ss/prompt.c | 28 + mechglue/src/util/ss/request_tbl.c | 65 + mechglue/src/util/ss/requests.c | 47 + mechglue/src/util/ss/ss.h | 67 + mechglue/src/util/ss/ss_err.et | 39 + mechglue/src/util/ss/ss_internal.h | 121 + mechglue/src/util/ss/std_rqs.ct | 46 + mechglue/src/util/ss/test_ss.c | 99 + mechglue/src/util/ss/utils.c | 136 + mechglue/src/util/support/ChangeLog | 226 + mechglue/src/util/support/Makefile.in | 86 + mechglue/src/util/support/cache-addrinfo.h | 128 + mechglue/src/util/support/fake-addrinfo.c | 1342 ++ mechglue/src/util/support/init-addrinfo.c | 70 + .../src/util/support/libkrb5support.exports | 13 + mechglue/src/util/support/threads.c | 608 + mechglue/src/util/windows/ChangeLog | 16 + mechglue/src/util/windows/Makefile.in | 14 + mechglue/src/util/windows/getopt.c | 152 + mechglue/src/util/windows/getopt.h | 33 + mechglue/src/util/windows/getopt_long.c | 236 + mechglue/src/util/windows/libecho.c | 76 + mechglue/src/wconfig.c | 219 + mechglue/src/windows/.Sanitize | 37 + mechglue/src/windows/ChangeLog | 174 + mechglue/src/windows/Makefile.in | 63 + mechglue/src/windows/README | 308 + mechglue/src/windows/ccapi/ChangeLog | 4 + mechglue/src/windows/ccapi/server/ChangeLog | 5 + mechglue/src/windows/cns/.Sanitize | 57 + mechglue/src/windows/cns/ChangeLog | 313 + mechglue/src/windows/cns/Makefile.in | 75 + mechglue/src/windows/cns/clock00.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock05.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock10.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock15.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock20.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock25.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock30.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock35.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock40.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock45.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock50.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock55.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clock60.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clockexp.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/clocktkt.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/cns-help.doc | Bin 0 -> 22528 bytes mechglue/src/windows/cns/cns-help.hlp | Bin 0 -> 11944 bytes mechglue/src/windows/cns/cns-help.hpj | 133 + mechglue/src/windows/cns/cns.c | 2208 +++ mechglue/src/windows/cns/cns.h | 249 + mechglue/src/windows/cns/cns.ico | Bin 0 -> 1086 bytes mechglue/src/windows/cns/cns_reg.c | 230 + mechglue/src/windows/cns/cns_reg.h | 33 + mechglue/src/windows/cns/cnsres4.rc | 108 + mechglue/src/windows/cns/cnsres5.rc | 215 + mechglue/src/windows/cns/debug.c | 91 + mechglue/src/windows/cns/heap.c | 33 + mechglue/src/windows/cns/kerbnet.doc | Bin 0 -> 22528 bytes mechglue/src/windows/cns/kerbnet.hlp | Bin 0 -> 16334 bytes mechglue/src/windows/cns/kerbnet.hpj | 133 + mechglue/src/windows/cns/kpasswd.c | 90 + mechglue/src/windows/cns/krb5.def | 9 + mechglue/src/windows/cns/krbini.h | 37 + mechglue/src/windows/cns/options.c | 232 + mechglue/src/windows/cns/password.c | 323 + mechglue/src/windows/cns/tktlist.c | 442 + mechglue/src/windows/cns/tktlist.h | 27 + mechglue/src/windows/gina/ChangeLog | 20 + mechglue/src/windows/gina/Makefile.in | 35 + mechglue/src/windows/gina/gina.def | 21 + mechglue/src/windows/gina/ginastub.c | 365 + mechglue/src/windows/gina/ginastub.h | 39 + mechglue/src/windows/gss/.Sanitize | 40 + mechglue/src/windows/gss/ChangeLog | 177 + mechglue/src/windows/gss/Makefile.in | 48 + mechglue/src/windows/gss/gss-client.c | 615 + mechglue/src/windows/gss/gss-misc.c | 429 + mechglue/src/windows/gss/gss-misc.h | 60 + mechglue/src/windows/gss/gss.c | 722 + mechglue/src/windows/gss/gss.def | 15 + mechglue/src/windows/gss/gss.h | 43 + mechglue/src/windows/gss/gss.ico | Bin 0 -> 766 bytes mechglue/src/windows/gss/gss.rc | 148 + mechglue/src/windows/gss/resource.h | 50 + mechglue/src/windows/gss/ver_serv.txt | 11 + mechglue/src/windows/identity/ChangeLog | 19 + mechglue/src/windows/identity/Makefile | 190 + mechglue/src/windows/identity/apiversion.txt | 57 + mechglue/src/windows/identity/config/Makefile | 125 + .../src/windows/identity/config/Makefile.w32 | 277 + mechglue/src/windows/identity/config/ccsv.pl | 124 + .../src/windows/identity/config/csvschema.cfg | 67 + .../identity/config/netidmgr_intver.h.in | 34 + .../identity/config/netidmgr_version.h.in | 62 + mechglue/src/windows/identity/doc/Makefile | 68 + .../windows/identity/doc/cred_aquisition.h | 208 + .../windows/identity/doc/cred_data_types.h | 246 + mechglue/src/windows/identity/doc/cred_main.h | 35 + mechglue/src/windows/identity/doc/cred_msgs.h | 47 + .../windows/identity/doc/cred_prop_pages.h | 83 + .../src/windows/identity/doc/doxyfile.cfg | 1000 ++ mechglue/src/windows/identity/doc/footer.html | 19 + mechglue/src/windows/identity/doc/header.html | 5 + .../doc/images/credview-select-outline.jpg | Bin 0 -> 16084 bytes .../identity/doc/images/khimaira_logo.png | Bin 0 -> 3970 bytes .../doc/images/khimaira_logo_small.png | Bin 0 -> 3970 bytes mechglue/src/windows/identity/doc/main_page.h | 110 + .../src/windows/identity/doc/netidmgr.doc | Bin 0 -> 1199616 bytes .../src/windows/identity/doc/netidmgr.pdf | Bin 0 -> 1070358 bytes .../windows/identity/doc/plugin_framework.h | 131 + .../src/windows/identity/doc/plugin_locale.h | 107 + .../src/windows/identity/doc/plugin_main.h | 126 + .../windows/identity/doc/plugin_structure.h | 50 + .../src/windows/identity/doc/stylesheet.css | 271 + .../src/windows/identity/doc/ui_actions.h | 29 + .../src/windows/identity/doc/ui_context.h | 187 + mechglue/src/windows/identity/doc/ui_main.h | 34 + mechglue/src/windows/identity/doc/ui_menus.h | 29 + mechglue/src/windows/identity/help/Index.hhk | 9 + mechglue/src/windows/identity/help/Makefile | 36 + .../identity/help/html/about_netidmgr.htm | 68 + .../windows/identity/help/html/act_chpw.htm | 30 + .../identity/help/html/act_destroy_creds.htm | 33 + .../identity/help/html/act_import_creds.htm | 27 + .../identity/help/html/act_new_creds.htm | 114 + .../identity/help/html/act_renew_creds.htm | 11 + .../identity/help/html/act_set_default.htm | 11 + .../src/windows/identity/help/html/bugs.htm | 34 + .../identity/help/html/concept_cred_pro.htm | 11 + .../identity/help/html/concept_ident_pro.htm | 11 + .../identity/help/html/concept_identity.htm | 11 + .../windows/identity/help/html/concepts.htm | 11 + .../windows/identity/help/html/copyright.htm | 48 + .../src/windows/identity/help/html/howdoi.htm | 37 + .../identity/help/html/images/logo.jpg | Bin 0 -> 2014 bytes .../identity/help/html/images/logo_shade.jpg | Bin 0 -> 1641 bytes .../help/html/images/screen_app_icon.bmp | Bin 0 -> 144666 bytes .../help/html/images/screen_main_wnd.bmp | Bin 0 -> 915894 bytes .../help/html/images/screen_menu_bar.bmp | Bin 0 -> 12374 bytes .../html/images/screen_menu_credential.bmp | Bin 0 -> 129846 bytes .../help/html/images/screen_menu_file.bmp | Bin 0 -> 36838 bytes .../help/html/images/screen_menu_help.bmp | Bin 0 -> 51414 bytes .../help/html/images/screen_menu_options.bmp | Bin 0 -> 29494 bytes .../help/html/images/screen_menu_view.bmp | Bin 0 -> 64854 bytes .../help/html/images/screen_new_creds.bmp | Bin 0 -> 414558 bytes .../html/images/screen_new_creds_err01.bmp | Bin 0 -> 211690 bytes .../help/html/images/screen_new_creds_exp.bmp | Bin 0 -> 534694 bytes .../help/html/images/screen_tb_standard.bmp | Bin 0 -> 52634 bytes .../help/html/images/screen_tray_icon.bmp | Bin 0 -> 40122 bytes .../windows/identity/help/html/menu_all.htm | 41 + .../identity/help/html/menu_credential.htm | 86 + .../windows/identity/help/html/menu_file.htm | 46 + .../windows/identity/help/html/menu_help.htm | 57 + .../identity/help/html/menu_options.htm | 52 + .../windows/identity/help/html/menu_view.htm | 86 + .../src/windows/identity/help/html/nidmgr.css | 72 + .../identity/help/html/tb_standard.htm | 68 + .../windows/identity/help/html/template.htm | 11 + .../windows/identity/help/html/use_start.htm | 65 + .../src/windows/identity/help/html/using.htm | 46 + .../windows/identity/help/html/welcome.htm | 70 + .../windows/identity/help/html/wnd_main.htm | 89 + mechglue/src/windows/identity/help/khhelp.h | 33 + .../src/windows/identity/help/netidmgr.hhp | 35 + mechglue/src/windows/identity/help/popups.txt | 1 + .../windows/identity/help/popups_newcreds.txt | 30 + mechglue/src/windows/identity/help/toc.hhc | 130 + .../src/windows/identity/include/Makefile | 38 + .../src/windows/identity/include/khdefs.h | 235 + .../src/windows/identity/include/kherror.h | 180 + .../src/windows/identity/include/khlist.h | 173 + .../src/windows/identity/include/khmsgtypes.h | 733 + .../src/windows/identity/include/netidmgr.h | 43 + .../src/windows/identity/kconfig/Makefile | 51 + mechglue/src/windows/identity/kconfig/api.c | 2363 +++ .../src/windows/identity/kconfig/kconfig.h | 879 ++ .../identity/kconfig/kconfiginternal.h | 129 + .../windows/identity/kconfig/kconfigmain.c | 37 + .../src/windows/identity/kconfig/registry.c | 28 + .../windows/identity/kconfig/test/utiltest.c | 207 + .../src/windows/identity/kcreddb/Makefile | 52 + .../src/windows/identity/kcreddb/attrib.c | 869 ++ .../src/windows/identity/kcreddb/attrib.h | 55 + mechglue/src/windows/identity/kcreddb/buf.c | 391 + mechglue/src/windows/identity/kcreddb/buf.h | 78 + .../src/windows/identity/kcreddb/credential.c | 1073 ++ .../src/windows/identity/kcreddb/credential.h | 71 + .../src/windows/identity/kcreddb/credset.c | 1151 ++ .../src/windows/identity/kcreddb/credset.h | 75 + .../src/windows/identity/kcreddb/credtype.c | 415 + .../src/windows/identity/kcreddb/credtype.h | 55 + .../src/windows/identity/kcreddb/identity.c | 1582 ++ .../src/windows/identity/kcreddb/identity.h | 60 + mechglue/src/windows/identity/kcreddb/init.c | 91 + .../windows/identity/kcreddb/kcdbconfig.csv | 15 + .../src/windows/identity/kcreddb/kcreddb.h | 3245 ++++ .../identity/kcreddb/kcreddbinternal.h | 61 + .../windows/identity/kcreddb/kcreddbmain.c | 40 + .../identity/kcreddb/lang/en_us/kcredres.rc | 130 + .../src/windows/identity/kcreddb/langres.h | 48 + .../src/windows/identity/kcreddb/resource.h | 27 + mechglue/src/windows/identity/kcreddb/type.c | 1363 ++ mechglue/src/windows/identity/kcreddb/type.h | 216 + mechglue/src/windows/identity/kherr/Makefile | 43 + mechglue/src/windows/identity/kherr/kherr.c | 1246 ++ mechglue/src/windows/identity/kherr/kherr.h | 1008 ++ .../windows/identity/kherr/kherrinternal.h | 69 + .../src/windows/identity/kherr/kherrmain.c | 52 + mechglue/src/windows/identity/kmm/Makefile | 54 + mechglue/src/windows/identity/kmm/kmm.c | 192 + mechglue/src/windows/identity/kmm/kmm.h | 1038 ++ .../src/windows/identity/kmm/kmm_module.c | 667 + .../src/windows/identity/kmm/kmm_plugin.c | 379 + mechglue/src/windows/identity/kmm/kmm_reg.c | 293 + .../src/windows/identity/kmm/kmm_registrar.c | 922 ++ .../src/windows/identity/kmm/kmmconfig.csv | 43 + .../src/windows/identity/kmm/kmminternal.h | 240 + mechglue/src/windows/identity/kmm/kmmmain.c | 159 + mechglue/src/windows/identity/kmm/kplugin.h | 146 + .../src/windows/identity/kmm/lang/kmm_msgs.mc | 214 + mechglue/src/windows/identity/kmq/Makefile | 48 + mechglue/src/windows/identity/kmq/consumer.c | 441 + mechglue/src/windows/identity/kmq/init.c | 251 + mechglue/src/windows/identity/kmq/kmq.h | 743 + .../src/windows/identity/kmq/kmqconfig.csv | 5 + .../src/windows/identity/kmq/kmqinternal.h | 112 + mechglue/src/windows/identity/kmq/kmqmain.c | 47 + mechglue/src/windows/identity/kmq/msgtype.c | 367 + mechglue/src/windows/identity/kmq/publisher.c | 483 + .../src/windows/identity/nidmgrdll/Makefile | 110 + .../src/windows/identity/nidmgrdll/dllmain.c | 114 + .../windows/identity/nidmgrdll/nidmgrdll.rc | 74 + .../windows/identity/plugins/common/Makefile | 43 + .../identity/plugins/common/dynimport.c | 436 + .../identity/plugins/common/dynimport.h | 346 + .../identity/plugins/common/krb5common.c | 440 + .../identity/plugins/common/krb5common.h | 52 + .../windows/identity/plugins/krb4/Makefile | 81 + .../identity/plugins/krb4/errorfuncs.c | 226 + .../identity/plugins/krb4/errorfuncs.h | 65 + .../identity/plugins/krb4/images/plugin.ico | Bin 0 -> 7278 bytes .../identity/plugins/krb4/krb4configdlg.c | 247 + .../windows/identity/plugins/krb4/krb4funcs.c | 801 + .../windows/identity/plugins/krb4/krb4funcs.h | 114 + .../windows/identity/plugins/krb4/krb4main.c | 151 + .../identity/plugins/krb4/krb4newcreds.c | 676 + .../identity/plugins/krb4/krb4plugin.c | 285 + .../identity/plugins/krb4/krbconfig.csv | 16 + .../windows/identity/plugins/krb4/krbcred.h | 135 + .../plugins/krb4/lang/en_us/langres.rc | 204 + .../windows/identity/plugins/krb4/langres.h | 97 + .../windows/identity/plugins/krb4/version.rc | 66 + .../windows/identity/plugins/krb5/Makefile | 98 + .../windows/identity/plugins/krb5/datarep.c | 269 + .../windows/identity/plugins/krb5/datarep.h | 37 + .../identity/plugins/krb5/errorfuncs.c | 263 + .../identity/plugins/krb5/errorfuncs.h | 75 + .../identity/plugins/krb5/images/deleted.ico | Bin 0 -> 1406 bytes .../plugins/krb5/images/krb5plugin.ico | Bin 0 -> 7278 bytes .../identity/plugins/krb5/images/modified.ico | Bin 0 -> 1406 bytes .../identity/plugins/krb5/images/new.ico | Bin 0 -> 1406 bytes .../identity/plugins/krb5/images/normal.ico | Bin 0 -> 1406 bytes .../identity/plugins/krb5/krb5configcc.c | 573 + .../identity/plugins/krb5/krb5configdlg.c | 1856 +++ .../identity/plugins/krb5/krb5configid.c | 261 + .../identity/plugins/krb5/krb5configids.c | 250 + .../windows/identity/plugins/krb5/krb5funcs.c | 2042 +++ .../windows/identity/plugins/krb5/krb5funcs.h | 130 + .../identity/plugins/krb5/krb5identpro.c | 1570 ++ .../windows/identity/plugins/krb5/krb5main.c | 405 + .../identity/plugins/krb5/krb5newcreds.c | 2240 +++ .../identity/plugins/krb5/krb5plugin.c | 242 + .../windows/identity/plugins/krb5/krb5props.c | 176 + .../windows/identity/plugins/krb5/krb5util.c | 1362 ++ .../identity/plugins/krb5/krbconfig.csv | 39 + .../windows/identity/plugins/krb5/krbcred.h | 230 + .../plugins/krb5/lang/en_us/langres.rc | 503 + .../identity/plugins/krb5/lang/krb5_msgs.mc | 158 + .../windows/identity/plugins/krb5/langres.h | 187 + .../windows/identity/plugins/krb5/version.rc | 64 + mechglue/src/windows/identity/ui/Makefile | 90 + mechglue/src/windows/identity/ui/aboutwnd.c | 145 + mechglue/src/windows/identity/ui/aboutwnd.h | 33 + mechglue/src/windows/identity/ui/addrchange.c | 92 + mechglue/src/windows/identity/ui/addrchange.h | 36 + mechglue/src/windows/identity/ui/appglobal.h | 82 + mechglue/src/windows/identity/ui/appver.rc | 40 + .../src/windows/identity/ui/cfg_general_wnd.c | 238 + .../windows/identity/ui/cfg_identities_wnd.c | 1102 ++ .../src/windows/identity/ui/cfg_notif_wnd.c | 326 + .../src/windows/identity/ui/cfg_plugins_wnd.c | 316 + mechglue/src/windows/identity/ui/configwnd.c | 861 ++ mechglue/src/windows/identity/ui/configwnd.h | 80 + mechglue/src/windows/identity/ui/credfuncs.c | 1029 ++ mechglue/src/windows/identity/ui/credfuncs.h | 82 + mechglue/src/windows/identity/ui/credwnd.c | 3608 +++++ mechglue/src/windows/identity/ui/credwnd.h | 249 + mechglue/src/windows/identity/ui/htmlwnd.h | 0 mechglue/src/windows/identity/ui/htwnd.c | 1070 ++ mechglue/src/windows/identity/ui/htwnd.h | 55 + .../identity/ui/images/app_notify_error.ico | Bin 0 -> 2862 bytes .../identity/ui/images/app_notify_info.ico | Bin 0 -> 2862 bytes .../identity/ui/images/app_notify_none.ico | Bin 0 -> 25214 bytes .../identity/ui/images/app_notify_warn.ico | Bin 0 -> 2862 bytes .../identity/ui/images/app_state_exp.ico | Bin 0 -> 2862 bytes .../identity/ui/images/app_state_ok.ico | Bin 0 -> 2862 bytes .../identity/ui/images/app_state_warn.ico | Bin 0 -> 2862 bytes .../identity/ui/images/cfg_applied.ico | Bin 0 -> 1406 bytes .../identity/ui/images/cfg_default.ico | Bin 0 -> 1406 bytes .../identity/ui/images/cfg_deleted.ico | Bin 0 -> 1406 bytes .../windows/identity/ui/images/cfg_mod.ico | Bin 0 -> 1406 bytes .../windows/identity/ui/images/cfg_plugin.ico | Bin 0 -> 10134 bytes .../identity/ui/images/chpw-dis-sm.bmp | Bin 0 -> 822 bytes .../windows/identity/ui/images/chpw-dis.bmp | Bin 0 -> 2430 bytes .../windows/identity/ui/images/chpw-sm.bmp | Bin 0 -> 822 bytes .../src/windows/identity/ui/images/chpw.bmp | Bin 0 -> 2430 bytes .../windows/identity/ui/images/disabled.ico | Bin 0 -> 2166 bytes .../windows/identity/ui/images/enabled.ico | Bin 0 -> 2166 bytes .../identity/ui/images/flag-critical.bmp | Bin 0 -> 822 bytes .../identity/ui/images/flag-warning.bmp | Bin 0 -> 822 bytes .../identity/ui/images/flag_expired.bmp | Bin 0 -> 774 bytes .../identity/ui/images/flag_renewable.bmp | Bin 0 -> 1334 bytes .../windows/identity/ui/images/help-sm.bmp | Bin 0 -> 822 bytes .../src/windows/identity/ui/images/help.bmp | Bin 0 -> 2430 bytes .../identity/ui/images/id-delete-dis-sm.bmp | Bin 0 -> 1014 bytes .../identity/ui/images/id-delete-dis.bmp | Bin 0 -> 3186 bytes .../identity/ui/images/id-delete-sm.bmp | Bin 0 -> 1014 bytes .../windows/identity/ui/images/id-delete.bmp | Bin 0 -> 3186 bytes .../windows/identity/ui/images/id-dis-sm.bmp | Bin 0 -> 822 bytes .../src/windows/identity/ui/images/id-dis.bmp | Bin 0 -> 3186 bytes .../identity/ui/images/id-new-dis-sm.bmp | Bin 0 -> 1014 bytes .../windows/identity/ui/images/id-new-dis.bmp | Bin 0 -> 3186 bytes .../windows/identity/ui/images/id-new-sm.bmp | Bin 0 -> 1014 bytes .../src/windows/identity/ui/images/id-new.bmp | Bin 0 -> 3186 bytes .../identity/ui/images/id-refresh-dis.bmp | Bin 0 -> 3186 bytes .../identity/ui/images/id-refresh-sm-dis.bmp | Bin 0 -> 1014 bytes .../identity/ui/images/id-refresh-sm.bmp | Bin 0 -> 1014 bytes .../windows/identity/ui/images/id-refresh.bmp | Bin 0 -> 3186 bytes .../src/windows/identity/ui/images/id-sm.bmp | Bin 0 -> 822 bytes .../src/windows/identity/ui/images/id.bmp | Bin 0 -> 3186 bytes .../src/windows/identity/ui/images/id.ico | Bin 0 -> 2862 bytes .../src/windows/identity/ui/images/ident.png | Bin 0 -> 423 bytes .../windows/identity/ui/images/import-dis.bmp | Bin 0 -> 2430 bytes .../identity/ui/images/import-sm-dis.bmp | Bin 0 -> 774 bytes .../windows/identity/ui/images/import-sm.bmp | Bin 0 -> 822 bytes .../src/windows/identity/ui/images/import.bmp | Bin 0 -> 2430 bytes .../identity/ui/images/khimaira-cfg.bmp | Bin 0 -> 30056 bytes .../windows/identity/ui/images/logo_shade.bmp | Bin 0 -> 30056 bytes .../windows/identity/ui/images/main_app.ico | Bin 0 -> 25214 bytes .../identity/ui/images/tb-blank-small.bmp | Bin 0 -> 774 bytes .../windows/identity/ui/images/tb-blank.bmp | Bin 0 -> 2430 bytes .../windows/identity/ui/images/tb-space.bmp | Bin 0 -> 2430 bytes .../identity/ui/images/tk-delete-dis-sm.bmp | Bin 0 -> 1014 bytes .../identity/ui/images/tk-delete-dis.bmp | Bin 0 -> 3186 bytes .../identity/ui/images/tk-delete-sm.bmp | Bin 0 -> 822 bytes .../windows/identity/ui/images/tk-delete.bmp | Bin 0 -> 2430 bytes .../windows/identity/ui/images/tk-dis-sm.bmp | Bin 0 -> 1014 bytes .../src/windows/identity/ui/images/tk-dis.bmp | Bin 0 -> 3186 bytes .../identity/ui/images/tk-new-dis-sm.bmp | Bin 0 -> 1014 bytes .../windows/identity/ui/images/tk-new-dis.bmp | Bin 0 -> 3186 bytes .../windows/identity/ui/images/tk-new-sm.bmp | Bin 0 -> 822 bytes .../src/windows/identity/ui/images/tk-new.bmp | Bin 0 -> 2430 bytes .../identity/ui/images/tk-refresh-dis-sm.bmp | Bin 0 -> 1014 bytes .../identity/ui/images/tk-refresh-dis.bmp | Bin 0 -> 3186 bytes .../identity/ui/images/tk-refresh-sm.bmp | Bin 0 -> 822 bytes .../windows/identity/ui/images/tk-refresh.bmp | Bin 0 -> 2430 bytes .../src/windows/identity/ui/images/tk-sm.bmp | Bin 0 -> 1014 bytes .../src/windows/identity/ui/images/tk.bmp | Bin 0 -> 3186 bytes .../identity/ui/images/vw-refresh-sm.bmp | Bin 0 -> 822 bytes .../windows/identity/ui/images/vw-refresh.bmp | Bin 0 -> 2430 bytes .../identity/ui/images/wdg_collapsed.bmp | Bin 0 -> 774 bytes .../identity/ui/images/wdg_collapsed_hi.bmp | Bin 0 -> 774 bytes .../identity/ui/images/wdg_credtype.bmp | Bin 0 -> 1014 bytes .../identity/ui/images/wdg_expanded.bmp | Bin 0 -> 774 bytes .../identity/ui/images/wdg_expanded_hi.bmp | Bin 0 -> 774 bytes .../windows/identity/ui/images/wdg_flag.bmp | Bin 0 -> 1014 bytes .../windows/identity/ui/images/wdg_stick.bmp | Bin 0 -> 774 bytes .../identity/ui/images/wdg_stick_hi.bmp | Bin 0 -> 774 bytes .../windows/identity/ui/images/wdg_stuck.bmp | Bin 0 -> 774 bytes .../identity/ui/images/wdg_stuck_hi.bmp | Bin 0 -> 774 bytes mechglue/src/windows/identity/ui/khmapp.h | 72 + .../windows/identity/ui/lang/en_us/khapp.rc | 712 + mechglue/src/windows/identity/ui/main.c | 556 + mechglue/src/windows/identity/ui/mainmenu.c | 662 + mechglue/src/windows/identity/ui/mainmenu.h | 59 + mechglue/src/windows/identity/ui/mainwnd.c | 727 + mechglue/src/windows/identity/ui/mainwnd.h | 60 + .../src/windows/identity/ui/makeacceldef.pl | 29 + .../src/windows/identity/ui/makeactiondef.pl | 29 + .../identity/ui/netidmgr.exe.manifest.i386 | 22 + .../identity/ui/netidmgr.manifest.i386.vc7 | 22 + .../ui/netidmgr.manifest.i386.vc7.debug | 22 + .../identity/ui/netidmgr.manifest.i386.vc8 | 31 + .../ui/netidmgr.manifest.i386.vc8.debug | 31 + mechglue/src/windows/identity/ui/newcredwnd.c | 1858 +++ mechglue/src/windows/identity/ui/newcredwnd.h | 103 + mechglue/src/windows/identity/ui/notifier.c | 1234 ++ mechglue/src/windows/identity/ui/notifier.h | 57 + mechglue/src/windows/identity/ui/passwnd.c | 133 + mechglue/src/windows/identity/ui/passwnd.h | 39 + .../src/windows/identity/ui/propertywnd.c | 248 + .../src/windows/identity/ui/propertywnd.h | 36 + mechglue/src/windows/identity/ui/reqdaemon.c | 451 + mechglue/src/windows/identity/ui/reqdaemon.h | 42 + mechglue/src/windows/identity/ui/resource.h | 332 + mechglue/src/windows/identity/ui/statusbar.c | 182 + mechglue/src/windows/identity/ui/statusbar.h | 54 + mechglue/src/windows/identity/ui/timer.c | 702 + mechglue/src/windows/identity/ui/timer.h | 100 + mechglue/src/windows/identity/ui/toolbar.c | 373 + mechglue/src/windows/identity/ui/toolbar.h | 52 + mechglue/src/windows/identity/ui/uiconfig.csv | 114 + mechglue/src/windows/identity/uilib/Makefile | 62 + mechglue/src/windows/identity/uilib/accel.csv | 21 + .../src/windows/identity/uilib/acceldef.cfg | 50 + mechglue/src/windows/identity/uilib/action.c | 1021 ++ .../src/windows/identity/uilib/actiondef.cfg | 64 + .../src/windows/identity/uilib/actions.csv | 39 + mechglue/src/windows/identity/uilib/alert.c | 362 + .../src/windows/identity/uilib/configui.c | 1048 ++ .../src/windows/identity/uilib/configui.h | 74 + mechglue/src/windows/identity/uilib/creddlg.c | 675 + .../src/windows/identity/uilib/khaction.h | 566 + .../src/windows/identity/uilib/khactiondef.h | 137 + .../src/windows/identity/uilib/khalerts.h | 382 + .../src/windows/identity/uilib/khconfigui.h | 601 + .../src/windows/identity/uilib/khhtlink.h | 58 + .../src/windows/identity/uilib/khnewcred.h | 906 ++ mechglue/src/windows/identity/uilib/khprops.h | 207 + .../src/windows/identity/uilib/khremote.h | 84 + .../src/windows/identity/uilib/khrescache.h | 100 + .../src/windows/identity/uilib/khtracker.h | 114 + .../src/windows/identity/uilib/khuidefs.h | 94 + .../src/windows/identity/uilib/propsheet.c | 230 + mechglue/src/windows/identity/uilib/propwnd.c | 37 + .../src/windows/identity/uilib/rescache.c | 301 + .../src/windows/identity/uilib/trackerwnd.c | 472 + .../src/windows/identity/uilib/uilibmain.c | 44 + mechglue/src/windows/identity/uilib/version.c | 83 + mechglue/src/windows/identity/util/Makefile | 48 + .../src/windows/identity/util/hashtable.c | 168 + .../src/windows/identity/util/hashtable.h | 223 + mechglue/src/windows/identity/util/mstring.c | 510 + mechglue/src/windows/identity/util/mstring.h | 361 + mechglue/src/windows/identity/util/perfstat.c | 265 + mechglue/src/windows/identity/util/perfstat.h | 71 + mechglue/src/windows/identity/util/sync.c | 126 + mechglue/src/windows/identity/util/sync.h | 128 + mechglue/src/windows/identity/util/utils.h | 37 + mechglue/src/windows/installer/nsis/ChangeLog | 77 + .../windows/installer/nsis/KfWConfigPage.ini | 59 + .../windows/installer/nsis/KfWConfigPage2.ini | 20 + .../src/windows/installer/nsis/kfw-fixed.nsi | 1866 +++ mechglue/src/windows/installer/nsis/kfw.ico | Bin 0 -> 25214 bytes mechglue/src/windows/installer/nsis/kfw.nsi | 16 + .../src/windows/installer/nsis/killer.cpp | 380 + .../src/windows/installer/nsis/licenses.rtf | 98 + .../windows/installer/nsis/nsi-includes.nsi | 8 + .../src/windows/installer/nsis/site-local.nsi | 13 + mechglue/src/windows/installer/nsis/utils.nsi | 825 ++ .../windows/installer/wix/Binary/ChangeLog | 3 + .../windows/installer/wix/Binary/bannrbmp.bmp | Bin 0 -> 94554 bytes .../windows/installer/wix/Binary/completi.ico | Bin 0 -> 2998 bytes .../windows/installer/wix/Binary/custicon.ico | Bin 0 -> 2998 bytes .../windows/installer/wix/Binary/dlgbmp.bmp | Bin 0 -> 474822 bytes .../windows/installer/wix/Binary/exclamic.ico | Bin 0 -> 766 bytes .../src/windows/installer/wix/Binary/info.bmp | Bin 0 -> 1078 bytes .../windows/installer/wix/Binary/insticon.ico | Bin 0 -> 2998 bytes .../src/windows/installer/wix/Binary/new.bmp | Bin 0 -> 318 bytes .../windows/installer/wix/Binary/removico.ico | Bin 0 -> 2998 bytes .../windows/installer/wix/Binary/repairic.ico | Bin 0 -> 2998 bytes .../src/windows/installer/wix/Binary/up.bmp | Bin 0 -> 318 bytes mechglue/src/windows/installer/wix/ChangeLog | 43 + mechglue/src/windows/installer/wix/Makefile | 59 + mechglue/src/windows/installer/wix/config.wxi | 161 + .../windows/installer/wix/custom/ChangeLog | 3 + .../windows/installer/wix/custom/custom.cpp | 741 + .../src/windows/installer/wix/custom/custom.h | 81 + .../src/windows/installer/wix/features.wxi | 277 + mechglue/src/windows/installer/wix/files.wxi | 936 ++ mechglue/src/windows/installer/wix/kfw.wxs | 237 + .../src/windows/installer/wix/lang/ChangeLog | 12 + .../installer/wix/lang/config_1033.wxi | 68 + .../windows/installer/wix/lang/license.rtf | 102 + .../installer/wix/lang/strings_1033.wxl | 64 + .../windows/installer/wix/lang/ui_1033.wxi | 1243 ++ .../installer/wix/msi-deployment-guide.txt | 524 + .../src/windows/installer/wix/property.wxi | 94 + .../src/windows/installer/wix/site-local.wxi | 99 + mechglue/src/windows/kfwlogon/Makefile.in | 37 + mechglue/src/windows/kfwlogon/kfwcommon.c | 927 ++ mechglue/src/windows/kfwlogon/kfwcpcc.c | 39 + mechglue/src/windows/kfwlogon/kfwcpcc.rc | 10 + mechglue/src/windows/kfwlogon/kfwlogon.c | 354 + mechglue/src/windows/kfwlogon/kfwlogon.def | 12 + mechglue/src/windows/kfwlogon/kfwlogon.h | 200 + mechglue/src/windows/kfwlogon/kfwlogon.rc | 10 + mechglue/src/windows/lib/ChangeLog | 53 + mechglue/src/windows/lib/Makefile.in | 17 + mechglue/src/windows/lib/cacheapi.h | 458 + mechglue/src/windows/lib/gic.c | 157 + mechglue/src/windows/lib/gic.h | 28 + mechglue/src/windows/lib/registry.c | 231 + mechglue/src/windows/lib/registry.h | 40 + mechglue/src/windows/lib/vardlg.c | 453 + mechglue/src/windows/lib/vardlg.h | 32 + mechglue/src/windows/ms2mit/ChangeLog | 113 + mechglue/src/windows/ms2mit/Makefile.in | 25 + mechglue/src/windows/ms2mit/mit2ms.c | 149 + mechglue/src/windows/ms2mit/ms2mit.c | 171 + mechglue/src/windows/version.rc | 222 + mechglue/src/windows/wintel/.Sanitize | 56 + mechglue/src/windows/wintel/ChangeLog | 213 + mechglue/src/windows/wintel/Makefile.in | 45 + mechglue/src/windows/wintel/auth.c | 867 ++ mechglue/src/windows/wintel/auth.h | 28 + mechglue/src/windows/wintel/dialog.h | 42 + mechglue/src/windows/wintel/edit.c | 444 + mechglue/src/windows/wintel/emul.c | 766 + mechglue/src/windows/wintel/enc_des.c | 725 + mechglue/src/windows/wintel/enc_des.h | 120 + mechglue/src/windows/wintel/encrypt.c | 999 ++ mechglue/src/windows/wintel/encrypt.h | 178 + mechglue/src/windows/wintel/font.c | 100 + mechglue/src/windows/wintel/genget.c | 101 + mechglue/src/windows/wintel/ini.h | 16 + mechglue/src/windows/wintel/intern.c | 815 + mechglue/src/windows/wintel/k5stream.c | 119 + mechglue/src/windows/wintel/k5stream.h | 57 + mechglue/src/windows/wintel/ktelnet.doc | Bin 0 -> 16384 bytes mechglue/src/windows/wintel/ktelnet.hlp | Bin 0 -> 9204 bytes mechglue/src/windows/wintel/ktelnet.hpj | 92 + mechglue/src/windows/wintel/ncsa.ico | Bin 0 -> 766 bytes mechglue/src/windows/wintel/negotiat.c | 865 ++ mechglue/src/windows/wintel/resource.h | 17 + mechglue/src/windows/wintel/screen.c | 1147 ++ mechglue/src/windows/wintel/screen.h | 325 + mechglue/src/windows/wintel/struct.h | 29 + mechglue/src/windows/wintel/telnet.c | 904 ++ mechglue/src/windows/wintel/telnet.def | 39 + mechglue/src/windows/wintel/telnet.h | 41 + mechglue/src/windows/wintel/telnet.rc | 247 + mechglue/src/windows/wintel/telnet_arpa.h | 327 + mechglue/src/windows/wintel/telopts.h | 164 + mechglue/src/windows/wintel/terminal.ico | Bin 0 -> 766 bytes mechglue/src/windows/wintel/wt-proto.h | 63 + 2533 files changed, 707561 insertions(+) create mode 100644 mechglue/.Sanitize create mode 100644 mechglue/README create mode 100644 mechglue/doc/.Sanitize create mode 100644 mechglue/doc/.cvsignore create mode 100644 mechglue/doc/ChangeLog create mode 100644 mechglue/doc/Makefile create mode 100644 mechglue/doc/admin.texinfo create mode 100644 mechglue/doc/api/.Sanitize create mode 100644 mechglue/doc/api/.cvsignore create mode 100644 mechglue/doc/api/ChangeLog create mode 100644 mechglue/doc/api/Makefile create mode 100644 mechglue/doc/api/ccache.tex create mode 100644 mechglue/doc/api/errors.tex create mode 100644 mechglue/doc/api/fancyheadings.sty create mode 100644 mechglue/doc/api/fixunder.sty create mode 100644 mechglue/doc/api/free.tex create mode 100644 mechglue/doc/api/functions.sty create mode 100644 mechglue/doc/api/intro.tex create mode 100644 mechglue/doc/api/keytab.tex create mode 100644 mechglue/doc/api/krb5.ist create mode 100644 mechglue/doc/api/krb5.tex create mode 100644 mechglue/doc/api/krb5idx.sty create mode 100644 mechglue/doc/api/libdes.tex create mode 100644 mechglue/doc/api/libos.tex create mode 100644 mechglue/doc/api/library.tex create mode 100644 mechglue/doc/api/rcache.tex create mode 100644 mechglue/doc/api/tables.tex create mode 100644 mechglue/doc/bug-report.texinfo create mode 100644 mechglue/doc/build.texinfo create mode 100644 mechglue/doc/coding-style create mode 100644 mechglue/doc/copyright.texinfo create mode 100644 mechglue/doc/definitions.texinfo create mode 100644 mechglue/doc/dnssrv.texinfo create mode 100644 mechglue/doc/dnstxt.texinfo create mode 100644 mechglue/doc/document-list.texinfo create mode 100644 mechglue/doc/glossary.texinfo create mode 100644 mechglue/doc/implement/.Sanitize create mode 100644 mechglue/doc/implement/.cvsignore create mode 100644 mechglue/doc/implement/ChangeLog create mode 100644 mechglue/doc/implement/Makefile create mode 100644 mechglue/doc/implement/ccache-i.tex create mode 100644 mechglue/doc/implement/cksum-i.tex create mode 100644 mechglue/doc/implement/crc-32-i.tex create mode 100644 mechglue/doc/implement/encrypt-i.tex create mode 100644 mechglue/doc/implement/fancyheadings.sty create mode 100644 mechglue/doc/implement/fixunder.sty create mode 100644 mechglue/doc/implement/functions.sty create mode 100644 mechglue/doc/implement/implement.tex create mode 100644 mechglue/doc/implement/kdb-i.tex create mode 100644 mechglue/doc/implement/keytab-i.tex create mode 100644 mechglue/doc/implement/libos-i.tex create mode 100644 mechglue/doc/implement/rcache-i.tex create mode 100644 mechglue/doc/implementor.texinfo create mode 100644 mechglue/doc/install-old.texi create mode 100644 mechglue/doc/install.texinfo create mode 100644 mechglue/doc/kadm5/adb-unit-test.tex create mode 100644 mechglue/doc/kadm5/api-funcspec.tex create mode 100644 mechglue/doc/kadm5/api-server-design.tex create mode 100644 mechglue/doc/kadm5/api-unit-test.tex create mode 100644 mechglue/doc/kadm5/fullpage.sty create mode 100644 mechglue/doc/kadm5/rcsid.sty create mode 100644 mechglue/doc/kadm5acl.texinfo create mode 100644 mechglue/doc/kadmin/.Sanitize create mode 100644 mechglue/doc/kadmin/ChangeLog create mode 100644 mechglue/doc/kadmin/README create mode 100644 mechglue/doc/kadmin/draft-ietf-cat-kerb-chg-password-02.txt create mode 100644 mechglue/doc/kadmin/kadmin.protocol create mode 100644 mechglue/doc/kadmin/kpasswd.protocol create mode 100644 mechglue/doc/kdcconf.texinfo create mode 100644 mechglue/doc/krb4-xrealm.txt create mode 100644 mechglue/doc/krb425.texinfo create mode 100644 mechglue/doc/krb5-protocol/.Sanitize create mode 100644 mechglue/doc/krb5-protocol/3-des.txt create mode 100644 mechglue/doc/krb5-protocol/krb5.constants create mode 100644 mechglue/doc/krb5-protocol/rfc1510.errata create mode 100644 mechglue/doc/krb5-protocol/rfc1510.txt create mode 100644 mechglue/doc/krb5conf.texinfo create mode 100755 mechglue/doc/man2html create mode 100644 mechglue/doc/man2html.M create mode 100755 mechglue/doc/man2ps create mode 100644 mechglue/doc/man2ps.M create mode 100644 mechglue/doc/old-V4-docs/.Sanitize create mode 100644 mechglue/doc/old-V4-docs/README create mode 100644 mechglue/doc/old-V4-docs/installation.PS create mode 100644 mechglue/doc/old-V4-docs/installation.mss create mode 100644 mechglue/doc/old-V4-docs/operation.PS create mode 100644 mechglue/doc/old-V4-docs/operation.mss create mode 100644 mechglue/doc/procedures.txt create mode 100644 mechglue/doc/rpc/design.tex create mode 100644 mechglue/doc/salts.texinfo create mode 100644 mechglue/doc/send-pr.texinfo create mode 100644 mechglue/doc/support-enc.texinfo create mode 100644 mechglue/doc/texinfo-suppl.tex create mode 100644 mechglue/doc/texinfo.tex create mode 100644 mechglue/doc/thread-safe.txt create mode 100644 mechglue/doc/threads.txt create mode 100644 mechglue/doc/user-guide.texinfo create mode 100644 mechglue/src/.Sanitize create mode 100644 mechglue/src/.rconf create mode 100644 mechglue/src/BADSYMS create mode 100644 mechglue/src/ChangeLog create mode 100644 mechglue/src/Makefile.in create mode 100644 mechglue/src/aclocal.m4 create mode 100644 mechglue/src/appl/.Sanitize create mode 100644 mechglue/src/appl/.rconf create mode 100644 mechglue/src/appl/ChangeLog create mode 100644 mechglue/src/appl/Makefile.in create mode 100644 mechglue/src/appl/bsd/.Sanitize create mode 100644 mechglue/src/appl/bsd/ChangeLog create mode 100644 mechglue/src/appl/bsd/Makefile.in create mode 100644 mechglue/src/appl/bsd/compat_recv.c create mode 100644 mechglue/src/appl/bsd/configure.in create mode 100644 mechglue/src/appl/bsd/defines.h create mode 100644 mechglue/src/appl/bsd/forward.c create mode 100644 mechglue/src/appl/bsd/getdtablesize.c create mode 100644 mechglue/src/appl/bsd/kcmd.c create mode 100644 mechglue/src/appl/bsd/klogind.M create mode 100644 mechglue/src/appl/bsd/krcp.c create mode 100644 mechglue/src/appl/bsd/krlogin.c create mode 100644 mechglue/src/appl/bsd/krlogind.c create mode 100644 mechglue/src/appl/bsd/krsh.c create mode 100644 mechglue/src/appl/bsd/krshd.c create mode 100644 mechglue/src/appl/bsd/kshd.M create mode 100644 mechglue/src/appl/bsd/login.M create mode 100644 mechglue/src/appl/bsd/login.c create mode 100644 mechglue/src/appl/bsd/loginpaths.h create mode 100644 mechglue/src/appl/bsd/rcp.M create mode 100644 mechglue/src/appl/bsd/rlogin.M create mode 100644 mechglue/src/appl/bsd/rpaths.h create mode 100644 mechglue/src/appl/bsd/rsh.M create mode 100644 mechglue/src/appl/bsd/setenv.c create mode 100644 mechglue/src/appl/bsd/v4rcp.M create mode 100644 mechglue/src/appl/bsd/v4rcp.c create mode 100644 mechglue/src/appl/configure.in create mode 100644 mechglue/src/appl/gss-sample/.Sanitize create mode 100644 mechglue/src/appl/gss-sample/ChangeLog create mode 100644 mechglue/src/appl/gss-sample/Makefile.in create mode 100644 mechglue/src/appl/gss-sample/README create mode 100644 mechglue/src/appl/gss-sample/gss-client.c create mode 100644 mechglue/src/appl/gss-sample/gss-misc.c create mode 100644 mechglue/src/appl/gss-sample/gss-misc.h create mode 100644 mechglue/src/appl/gss-sample/gss-server.c create mode 100644 mechglue/src/appl/gssftp/.Sanitize create mode 100644 mechglue/src/appl/gssftp/ChangeLog create mode 100644 mechglue/src/appl/gssftp/Makefile.in create mode 100644 mechglue/src/appl/gssftp/README.gssftp create mode 100644 mechglue/src/appl/gssftp/arpa/.Sanitize create mode 100644 mechglue/src/appl/gssftp/arpa/ChangeLog create mode 100644 mechglue/src/appl/gssftp/arpa/ftp.h create mode 100644 mechglue/src/appl/gssftp/arpa/telnet.h create mode 100644 mechglue/src/appl/gssftp/configure.in create mode 100644 mechglue/src/appl/gssftp/ftp/.Sanitize create mode 100644 mechglue/src/appl/gssftp/ftp/ChangeLog create mode 100644 mechglue/src/appl/gssftp/ftp/Makefile.in create mode 100644 mechglue/src/appl/gssftp/ftp/cmds.c create mode 100644 mechglue/src/appl/gssftp/ftp/cmdtab.c create mode 100644 mechglue/src/appl/gssftp/ftp/domacro.c create mode 100644 mechglue/src/appl/gssftp/ftp/ftp.M create mode 100644 mechglue/src/appl/gssftp/ftp/ftp.c create mode 100644 mechglue/src/appl/gssftp/ftp/ftp_var.h create mode 100644 mechglue/src/appl/gssftp/ftp/getpass.c create mode 100644 mechglue/src/appl/gssftp/ftp/glob.c create mode 100644 mechglue/src/appl/gssftp/ftp/main.c create mode 100644 mechglue/src/appl/gssftp/ftp/pathnames.h create mode 100644 mechglue/src/appl/gssftp/ftp/pclose.c create mode 100644 mechglue/src/appl/gssftp/ftp/radix.c create mode 100644 mechglue/src/appl/gssftp/ftp/ruserpass.c create mode 100644 mechglue/src/appl/gssftp/ftp/secure.c create mode 100644 mechglue/src/appl/gssftp/ftp/secure.h create mode 100644 mechglue/src/appl/gssftp/ftpd/.Sanitize create mode 100644 mechglue/src/appl/gssftp/ftpd/CHANGES create mode 100644 mechglue/src/appl/gssftp/ftpd/ChangeLog create mode 100644 mechglue/src/appl/gssftp/ftpd/Makefile.in create mode 100644 mechglue/src/appl/gssftp/ftpd/ftpcmd.y create mode 100644 mechglue/src/appl/gssftp/ftpd/ftpd.M create mode 100644 mechglue/src/appl/gssftp/ftpd/ftpd.c create mode 100644 mechglue/src/appl/gssftp/ftpd/ftpd_var.h create mode 100644 mechglue/src/appl/gssftp/ftpd/logwtmp.c create mode 100644 mechglue/src/appl/gssftp/ftpd/pathnames.h create mode 100644 mechglue/src/appl/gssftp/ftpd/popen.c create mode 100644 mechglue/src/appl/gssftp/ftpd/secure.h create mode 100644 mechglue/src/appl/gssftp/ftpd/vers.c create mode 100644 mechglue/src/appl/sample/.Sanitize create mode 100644 mechglue/src/appl/sample/ChangeLog create mode 100644 mechglue/src/appl/sample/Makefile.in create mode 100644 mechglue/src/appl/sample/sample.h create mode 100644 mechglue/src/appl/sample/sclient/.Sanitize create mode 100644 mechglue/src/appl/sample/sclient/ChangeLog create mode 100644 mechglue/src/appl/sample/sclient/Makefile.in create mode 100644 mechglue/src/appl/sample/sclient/sclient.M create mode 100644 mechglue/src/appl/sample/sclient/sclient.c create mode 100644 mechglue/src/appl/sample/sserver/.Sanitize create mode 100644 mechglue/src/appl/sample/sserver/ChangeLog create mode 100644 mechglue/src/appl/sample/sserver/Makefile.in create mode 100644 mechglue/src/appl/sample/sserver/sserver.M create mode 100644 mechglue/src/appl/sample/sserver/sserver.c create mode 100644 mechglue/src/appl/simple/.Sanitize create mode 100644 mechglue/src/appl/simple/ChangeLog create mode 100644 mechglue/src/appl/simple/Makefile.in create mode 100644 mechglue/src/appl/simple/client/.Sanitize create mode 100644 mechglue/src/appl/simple/client/ChangeLog create mode 100644 mechglue/src/appl/simple/client/Makefile.in create mode 100644 mechglue/src/appl/simple/client/sim_client.c create mode 100644 mechglue/src/appl/simple/server/.Sanitize create mode 100644 mechglue/src/appl/simple/server/ChangeLog create mode 100644 mechglue/src/appl/simple/server/Makefile.in create mode 100644 mechglue/src/appl/simple/server/sim_server.c create mode 100644 mechglue/src/appl/simple/simple.h create mode 100644 mechglue/src/appl/telnet/.Sanitize create mode 100644 mechglue/src/appl/telnet/.rconf create mode 100644 mechglue/src/appl/telnet/ChangeLog create mode 100644 mechglue/src/appl/telnet/Config.generic create mode 100644 mechglue/src/appl/telnet/Makefile.in create mode 100644 mechglue/src/appl/telnet/README create mode 100644 mechglue/src/appl/telnet/arpa/.Sanitize create mode 100644 mechglue/src/appl/telnet/arpa/telnet.h create mode 100644 mechglue/src/appl/telnet/configure.in create mode 100644 mechglue/src/appl/telnet/kern.diff create mode 100644 mechglue/src/appl/telnet/libtelnet/.Sanitize create mode 100644 mechglue/src/appl/telnet/libtelnet/ChangeLog create mode 100644 mechglue/src/appl/telnet/libtelnet/Makefile.4.4 create mode 100644 mechglue/src/appl/telnet/libtelnet/Makefile.generic create mode 100644 mechglue/src/appl/telnet/libtelnet/Makefile.in create mode 100644 mechglue/src/appl/telnet/libtelnet/auth-proto.h create mode 100644 mechglue/src/appl/telnet/libtelnet/auth.c create mode 100644 mechglue/src/appl/telnet/libtelnet/auth.h create mode 100644 mechglue/src/appl/telnet/libtelnet/enc-proto.h create mode 100644 mechglue/src/appl/telnet/libtelnet/enc_des.c create mode 100644 mechglue/src/appl/telnet/libtelnet/encrypt.c create mode 100644 mechglue/src/appl/telnet/libtelnet/encrypt.h create mode 100644 mechglue/src/appl/telnet/libtelnet/forward.c create mode 100644 mechglue/src/appl/telnet/libtelnet/genget.c create mode 100644 mechglue/src/appl/telnet/libtelnet/getent.c create mode 100644 mechglue/src/appl/telnet/libtelnet/getopt.c create mode 100644 mechglue/src/appl/telnet/libtelnet/gettytab.c create mode 100644 mechglue/src/appl/telnet/libtelnet/gettytab.h create mode 100644 mechglue/src/appl/telnet/libtelnet/herror.c create mode 100644 mechglue/src/appl/telnet/libtelnet/kerberos.c create mode 100644 mechglue/src/appl/telnet/libtelnet/kerberos5.c create mode 100644 mechglue/src/appl/telnet/libtelnet/key-proto.h create mode 100644 mechglue/src/appl/telnet/libtelnet/krb5forw.h create mode 100644 mechglue/src/appl/telnet/libtelnet/mem.c create mode 100644 mechglue/src/appl/telnet/libtelnet/misc-proto.h create mode 100644 mechglue/src/appl/telnet/libtelnet/misc.c create mode 100644 mechglue/src/appl/telnet/libtelnet/misc.h create mode 100644 mechglue/src/appl/telnet/libtelnet/parsetos.c create mode 100644 mechglue/src/appl/telnet/libtelnet/setenv.c create mode 100644 mechglue/src/appl/telnet/libtelnet/setsid.c create mode 100644 mechglue/src/appl/telnet/libtelnet/spx.c create mode 100644 mechglue/src/appl/telnet/libtelnet/strcasecmp.c create mode 100644 mechglue/src/appl/telnet/libtelnet/strchr.c create mode 100644 mechglue/src/appl/telnet/libtelnet/strdup.c create mode 100644 mechglue/src/appl/telnet/libtelnet/strerror.c create mode 100644 mechglue/src/appl/telnet/libtelnet/strftime.c create mode 100644 mechglue/src/appl/telnet/libtelnet/strrchr.c create mode 100644 mechglue/src/appl/telnet/stty.diff create mode 100644 mechglue/src/appl/telnet/telnet.state create mode 100644 mechglue/src/appl/telnet/telnet/.Sanitize create mode 100644 mechglue/src/appl/telnet/telnet/ChangeLog create mode 100644 mechglue/src/appl/telnet/telnet/Makefile.4.4 create mode 100644 mechglue/src/appl/telnet/telnet/Makefile.generic create mode 100644 mechglue/src/appl/telnet/telnet/Makefile.in create mode 100644 mechglue/src/appl/telnet/telnet/authenc.c create mode 100644 mechglue/src/appl/telnet/telnet/commands.c create mode 100644 mechglue/src/appl/telnet/telnet/defines.h create mode 100644 mechglue/src/appl/telnet/telnet/externs.h create mode 100644 mechglue/src/appl/telnet/telnet/fdset.h create mode 100644 mechglue/src/appl/telnet/telnet/general.h create mode 100644 mechglue/src/appl/telnet/telnet/main.c create mode 100644 mechglue/src/appl/telnet/telnet/network.c create mode 100644 mechglue/src/appl/telnet/telnet/ring.c create mode 100644 mechglue/src/appl/telnet/telnet/ring.h create mode 100644 mechglue/src/appl/telnet/telnet/sys_bsd.c create mode 100644 mechglue/src/appl/telnet/telnet/telnet.0.ps create mode 100644 mechglue/src/appl/telnet/telnet/telnet.0.txt create mode 100644 mechglue/src/appl/telnet/telnet/telnet.1 create mode 100644 mechglue/src/appl/telnet/telnet/telnet.c create mode 100644 mechglue/src/appl/telnet/telnet/terminal.c create mode 100644 mechglue/src/appl/telnet/telnet/tmac.doc create mode 100644 mechglue/src/appl/telnet/telnet/tn3270.c create mode 100644 mechglue/src/appl/telnet/telnet/types.h create mode 100644 mechglue/src/appl/telnet/telnet/utilities.c create mode 100644 mechglue/src/appl/telnet/telnetd/.Sanitize create mode 100644 mechglue/src/appl/telnet/telnetd/ChangeLog create mode 100644 mechglue/src/appl/telnet/telnetd/ISSUES create mode 100644 mechglue/src/appl/telnet/telnetd/Makefile.4.4 create mode 100644 mechglue/src/appl/telnet/telnetd/Makefile.generic create mode 100644 mechglue/src/appl/telnet/telnetd/Makefile.in create mode 100644 mechglue/src/appl/telnet/telnetd/authenc.c create mode 100644 mechglue/src/appl/telnet/telnetd/defs.h create mode 100644 mechglue/src/appl/telnet/telnetd/ext.h create mode 100644 mechglue/src/appl/telnet/telnetd/global.c create mode 100644 mechglue/src/appl/telnet/telnetd/pathnames.h create mode 100644 mechglue/src/appl/telnet/telnetd/slc.c create mode 100644 mechglue/src/appl/telnet/telnetd/state.c create mode 100644 mechglue/src/appl/telnet/telnetd/sys_term.c create mode 100644 mechglue/src/appl/telnet/telnetd/telnetd-ktd.c create mode 100644 mechglue/src/appl/telnet/telnetd/telnetd.0.ps create mode 100644 mechglue/src/appl/telnet/telnetd/telnetd.0.txt create mode 100644 mechglue/src/appl/telnet/telnetd/telnetd.8 create mode 100644 mechglue/src/appl/telnet/telnetd/telnetd.c create mode 100644 mechglue/src/appl/telnet/telnetd/telnetd.h create mode 100644 mechglue/src/appl/telnet/telnetd/termio-tn.c create mode 100644 mechglue/src/appl/telnet/telnetd/termios-tn.c create mode 100644 mechglue/src/appl/telnet/telnetd/termstat.c create mode 100644 mechglue/src/appl/telnet/telnetd/utility.c create mode 100644 mechglue/src/appl/user_user/.Sanitize create mode 100644 mechglue/src/appl/user_user/ChangeLog create mode 100644 mechglue/src/appl/user_user/Makefile.in create mode 100644 mechglue/src/appl/user_user/client.c create mode 100644 mechglue/src/appl/user_user/server.c create mode 100644 mechglue/src/clients/.Sanitize create mode 100644 mechglue/src/clients/ChangeLog create mode 100644 mechglue/src/clients/Makefile.in create mode 100644 mechglue/src/clients/configure.in create mode 100644 mechglue/src/clients/kcpytkt/ChangeLog create mode 100644 mechglue/src/clients/kcpytkt/Makefile.in create mode 100644 mechglue/src/clients/kcpytkt/kcpytkt.M create mode 100644 mechglue/src/clients/kcpytkt/kcpytkt.c create mode 100644 mechglue/src/clients/kdeltkt/ChangeLog create mode 100644 mechglue/src/clients/kdeltkt/Makefile.in create mode 100644 mechglue/src/clients/kdeltkt/kdeltkt.M create mode 100644 mechglue/src/clients/kdeltkt/kdeltkt.c create mode 100644 mechglue/src/clients/kdestroy/.Sanitize create mode 100644 mechglue/src/clients/kdestroy/ChangeLog create mode 100644 mechglue/src/clients/kdestroy/Makefile.in create mode 100644 mechglue/src/clients/kdestroy/kdestroy.M create mode 100644 mechglue/src/clients/kdestroy/kdestroy.c create mode 100644 mechglue/src/clients/kinit/.Sanitize create mode 100644 mechglue/src/clients/kinit/ChangeLog create mode 100644 mechglue/src/clients/kinit/Makefile.in create mode 100644 mechglue/src/clients/kinit/kinit.M create mode 100644 mechglue/src/clients/kinit/kinit.c create mode 100644 mechglue/src/clients/klist/.Sanitize create mode 100644 mechglue/src/clients/klist/ChangeLog create mode 100644 mechglue/src/clients/klist/Makefile.in create mode 100644 mechglue/src/clients/klist/klist.M create mode 100644 mechglue/src/clients/klist/klist.c create mode 100644 mechglue/src/clients/kpasswd/ChangeLog create mode 100644 mechglue/src/clients/kpasswd/Makefile.in create mode 100644 mechglue/src/clients/kpasswd/kpasswd.M create mode 100644 mechglue/src/clients/kpasswd/kpasswd.c create mode 100644 mechglue/src/clients/kpasswd/ksetpwd.c create mode 100644 mechglue/src/clients/ksu/.Sanitize create mode 100644 mechglue/src/clients/ksu/ChangeLog create mode 100644 mechglue/src/clients/ksu/Makefile.in create mode 100644 mechglue/src/clients/ksu/authorization.c create mode 100644 mechglue/src/clients/ksu/ccache.c create mode 100644 mechglue/src/clients/ksu/heuristic.c create mode 100644 mechglue/src/clients/ksu/krb_auth_su.c create mode 100644 mechglue/src/clients/ksu/ksu.M create mode 100644 mechglue/src/clients/ksu/ksu.h create mode 100644 mechglue/src/clients/ksu/main.c create mode 100644 mechglue/src/clients/ksu/setenv.c create mode 100644 mechglue/src/clients/ksu/xmalloc.c create mode 100644 mechglue/src/clients/kvno/ChangeLog create mode 100644 mechglue/src/clients/kvno/Makefile.in create mode 100644 mechglue/src/clients/kvno/kvno.M create mode 100644 mechglue/src/clients/kvno/kvno.c create mode 100644 mechglue/src/config-files/.Sanitize create mode 100644 mechglue/src/config-files/ChangeLog create mode 100644 mechglue/src/config-files/Makefile.in create mode 100644 mechglue/src/config-files/convert-config-files create mode 100644 mechglue/src/config-files/kdc.conf create mode 100644 mechglue/src/config-files/kdc.conf.M create mode 100644 mechglue/src/config-files/krb5.conf create mode 100644 mechglue/src/config-files/krb5.conf.M create mode 100644 mechglue/src/config-files/services.append create mode 100644 mechglue/src/config/.Sanitize create mode 100644 mechglue/src/config/ChangeLog create mode 100644 mechglue/src/config/ac-archive/README create mode 100644 mechglue/src/config/ac-archive/acx_pthread.m4 create mode 100755 mechglue/src/config/config.guess create mode 100755 mechglue/src/config/config.sub create mode 100755 mechglue/src/config/install-sh create mode 100644 mechglue/src/config/lib.in create mode 100644 mechglue/src/config/libnover.in create mode 100644 mechglue/src/config/libobj.in create mode 100755 mechglue/src/config/mkinstalldirs create mode 100755 mechglue/src/config/move-if-changed create mode 100644 mechglue/src/config/post.in create mode 100644 mechglue/src/config/pre.in create mode 100755 mechglue/src/config/ren2long create mode 100644 mechglue/src/config/ren2long.awk create mode 100644 mechglue/src/config/rm.bat create mode 100644 mechglue/src/config/shlib.conf create mode 100644 mechglue/src/config/win-post.in create mode 100644 mechglue/src/config/win-pre.in create mode 100644 mechglue/src/config/winexclude.sed create mode 100644 mechglue/src/configure.in create mode 100644 mechglue/src/gen-manpages/ChangeLog create mode 100644 mechglue/src/gen-manpages/Makefile.in create mode 100644 mechglue/src/gen-manpages/header.doc create mode 100644 mechglue/src/gen-manpages/k5login.M create mode 100644 mechglue/src/gen-manpages/kerberos.M create mode 100644 mechglue/src/include/.Sanitize create mode 100644 mechglue/src/include/.rconf create mode 100644 mechglue/src/include/ChangeLog create mode 100644 mechglue/src/include/Makefile.in create mode 100644 mechglue/src/include/cm.h create mode 100644 mechglue/src/include/fake-addrinfo.h create mode 100644 mechglue/src/include/foreachaddr.h create mode 100644 mechglue/src/include/k5-int.h create mode 100644 mechglue/src/include/k5-platform.h create mode 100644 mechglue/src/include/k5-thread.h create mode 100644 mechglue/src/include/k5-util.h create mode 100644 mechglue/src/include/kerberosIV/.Sanitize create mode 100644 mechglue/src/include/kerberosIV/ChangeLog create mode 100644 mechglue/src/include/kerberosIV/Makefile.in create mode 100644 mechglue/src/include/kerberosIV/addr_comp.h create mode 100644 mechglue/src/include/kerberosIV/admin_server.h create mode 100644 mechglue/src/include/kerberosIV/des.h create mode 100644 mechglue/src/include/kerberosIV/kadm.h create mode 100644 mechglue/src/include/kerberosIV/kdc.h create mode 100644 mechglue/src/include/kerberosIV/klog.h create mode 100644 mechglue/src/include/kerberosIV/kparse.h create mode 100644 mechglue/src/include/kerberosIV/krb.h create mode 100644 mechglue/src/include/kerberosIV/krb_db.h create mode 100644 mechglue/src/include/kerberosIV/krbports.h create mode 100644 mechglue/src/include/kerberosIV/lsb_addr_cmp.h create mode 100644 mechglue/src/include/kerberosIV/mit-copyright.h create mode 100644 mechglue/src/include/kerberosIV/prot.h create mode 100644 mechglue/src/include/krb5.hin create mode 100644 mechglue/src/include/krb5/.Sanitize create mode 100644 mechglue/src/include/krb5/.rconf create mode 100644 mechglue/src/include/krb5/ChangeLog create mode 100644 mechglue/src/include/krb5/Makefile.in create mode 100644 mechglue/src/include/krb5/adm.h create mode 100644 mechglue/src/include/krb5/adm_defs.h create mode 100644 mechglue/src/include/krb5/adm_proto.h create mode 100644 mechglue/src/include/krb5/copyright.h create mode 100644 mechglue/src/include/krb5/kdb.h create mode 100644 mechglue/src/include/krb5/kdb_dbc.h create mode 100644 mechglue/src/include/krb5/kdb_kt.h create mode 100644 mechglue/src/include/krb5/stock/.Sanitize create mode 100644 mechglue/src/include/krb5/stock/ChangeLog create mode 100644 mechglue/src/include/krb5/stock/osconf.h create mode 100644 mechglue/src/include/krb54proto.h create mode 100644 mechglue/src/include/port-sockets.h create mode 100644 mechglue/src/include/socket-utils.h create mode 100644 mechglue/src/include/spnego-asn1.h create mode 100644 mechglue/src/include/syslog.h create mode 100644 mechglue/src/include/win-mac.h create mode 100644 mechglue/src/kadmin/.Sanitize create mode 100644 mechglue/src/kadmin/ChangeLog create mode 100644 mechglue/src/kadmin/Makefile.in create mode 100644 mechglue/src/kadmin/cli/ChangeLog create mode 100644 mechglue/src/kadmin/cli/Makefile.in create mode 100644 mechglue/src/kadmin/cli/getdate.y create mode 100644 mechglue/src/kadmin/cli/k5srvutil.M create mode 100755 mechglue/src/kadmin/cli/k5srvutil.sh create mode 100644 mechglue/src/kadmin/cli/kadmin.M create mode 100644 mechglue/src/kadmin/cli/kadmin.c create mode 100644 mechglue/src/kadmin/cli/kadmin.h create mode 100644 mechglue/src/kadmin/cli/kadmin.local.M create mode 100644 mechglue/src/kadmin/cli/kadmin_ct.ct create mode 100644 mechglue/src/kadmin/cli/keytab.c create mode 100644 mechglue/src/kadmin/cli/memmove.c create mode 100644 mechglue/src/kadmin/cli/ss_wrapper.c create mode 100644 mechglue/src/kadmin/cli/strftime.c create mode 100644 mechglue/src/kadmin/configure.in create mode 100644 mechglue/src/kadmin/dbutil/ChangeLog create mode 100644 mechglue/src/kadmin/dbutil/Makefile.in create mode 100644 mechglue/src/kadmin/dbutil/dump.c create mode 100644 mechglue/src/kadmin/dbutil/dumpv4.c create mode 100644 mechglue/src/kadmin/dbutil/import_err.et create mode 100644 mechglue/src/kadmin/dbutil/kadm5_create.c create mode 100644 mechglue/src/kadmin/dbutil/kdb5_create.c create mode 100644 mechglue/src/kadmin/dbutil/kdb5_destroy.c create mode 100644 mechglue/src/kadmin/dbutil/kdb5_edit.M create mode 100644 mechglue/src/kadmin/dbutil/kdb5_stash.c create mode 100644 mechglue/src/kadmin/dbutil/kdb5_util.M create mode 100644 mechglue/src/kadmin/dbutil/kdb5_util.c create mode 100644 mechglue/src/kadmin/dbutil/kdb5_util.h create mode 100644 mechglue/src/kadmin/dbutil/loadv4.c create mode 100644 mechglue/src/kadmin/dbutil/nstrtok.h create mode 100644 mechglue/src/kadmin/dbutil/ovload.c create mode 100644 mechglue/src/kadmin/dbutil/string_table.c create mode 100644 mechglue/src/kadmin/dbutil/string_table.h create mode 100644 mechglue/src/kadmin/dbutil/strtok.c create mode 100644 mechglue/src/kadmin/dbutil/tcl_wrapper.c create mode 100644 mechglue/src/kadmin/dbutil/util.c create mode 100644 mechglue/src/kadmin/kdbkeys/ChangeLog create mode 100644 mechglue/src/kadmin/kdbkeys/Makefile.in create mode 100755 mechglue/src/kadmin/kdbkeys/do-test.pl create mode 100644 mechglue/src/kadmin/ktutil/.Sanitize create mode 100644 mechglue/src/kadmin/ktutil/ChangeLog create mode 100644 mechglue/src/kadmin/ktutil/Makefile.in create mode 100644 mechglue/src/kadmin/ktutil/ktutil.M create mode 100644 mechglue/src/kadmin/ktutil/ktutil.c create mode 100644 mechglue/src/kadmin/ktutil/ktutil.h create mode 100644 mechglue/src/kadmin/ktutil/ktutil_ct.ct create mode 100644 mechglue/src/kadmin/ktutil/ktutil_funcs.c create mode 100644 mechglue/src/kadmin/passwd/ChangeLog create mode 100644 mechglue/src/kadmin/passwd/Kpasswd create mode 100644 mechglue/src/kadmin/passwd/Makefile.in create mode 100644 mechglue/src/kadmin/passwd/kpasswd.M create mode 100644 mechglue/src/kadmin/passwd/kpasswd.c create mode 100644 mechglue/src/kadmin/passwd/kpasswd.h create mode 100644 mechglue/src/kadmin/passwd/kpasswd_strings.et create mode 100644 mechglue/src/kadmin/passwd/tty_kpasswd.c create mode 100644 mechglue/src/kadmin/passwd/unit-test/ChangeLog create mode 100644 mechglue/src/kadmin/passwd/unit-test/Makefile.in create mode 100644 mechglue/src/kadmin/passwd/unit-test/config/unix.exp create mode 100644 mechglue/src/kadmin/passwd/unit-test/kpasswd.0/changing.exp create mode 100644 mechglue/src/kadmin/passwd/unit-test/kpasswd.0/connecting.exp create mode 100644 mechglue/src/kadmin/passwd/unit-test/kpasswd.0/principal.exp create mode 100644 mechglue/src/kadmin/passwd/unit-test/kpasswd.0/usage.exp create mode 100644 mechglue/src/kadmin/passwd/unit-test/lib/helpers.exp create mode 100644 mechglue/src/kadmin/passwd/xm_kpasswd.c create mode 100755 mechglue/src/kadmin/scripts/inst-hdrs.sh create mode 100644 mechglue/src/kadmin/server/ChangeLog create mode 100644 mechglue/src/kadmin/server/Makefile.in create mode 100644 mechglue/src/kadmin/server/acls.l create mode 100644 mechglue/src/kadmin/server/kadm_rpc_svc.c create mode 100644 mechglue/src/kadmin/server/kadmind.M create mode 100644 mechglue/src/kadmin/server/misc.c create mode 100644 mechglue/src/kadmin/server/misc.h create mode 100644 mechglue/src/kadmin/server/ovsec_kadmd.c create mode 100644 mechglue/src/kadmin/server/schpw.c create mode 100644 mechglue/src/kadmin/server/server_glue_v1.c create mode 100644 mechglue/src/kadmin/server/server_stubs.c create mode 100644 mechglue/src/kadmin/testing/ChangeLog create mode 100644 mechglue/src/kadmin/testing/Makefile.in create mode 100644 mechglue/src/kadmin/testing/proto/ChangeLog create mode 100644 mechglue/src/kadmin/testing/proto/kdc.conf.proto create mode 100644 mechglue/src/kadmin/testing/proto/krb5.conf.proto create mode 100644 mechglue/src/kadmin/testing/proto/ovsec_adm.dict create mode 100644 mechglue/src/kadmin/testing/scripts/ChangeLog create mode 100644 mechglue/src/kadmin/testing/scripts/Makefile.in create mode 100755 mechglue/src/kadmin/testing/scripts/compare_dump.plin create mode 100755 mechglue/src/kadmin/testing/scripts/env-setup.shin create mode 100755 mechglue/src/kadmin/testing/scripts/find-make.sh create mode 100755 mechglue/src/kadmin/testing/scripts/fixup-conf-files.plin create mode 100755 mechglue/src/kadmin/testing/scripts/init_db create mode 100755 mechglue/src/kadmin/testing/scripts/make-host-keytab.plin create mode 100755 mechglue/src/kadmin/testing/scripts/qualname.plin create mode 100755 mechglue/src/kadmin/testing/scripts/save_files.sh create mode 100755 mechglue/src/kadmin/testing/scripts/simple_dump.plin create mode 100755 mechglue/src/kadmin/testing/scripts/start_servers create mode 100755 mechglue/src/kadmin/testing/scripts/start_servers_local create mode 100755 mechglue/src/kadmin/testing/scripts/stop_servers create mode 100755 mechglue/src/kadmin/testing/scripts/stop_servers_local create mode 100755 mechglue/src/kadmin/testing/scripts/verify_xrunner_report.plin create mode 100644 mechglue/src/kadmin/testing/tcl/util.t create mode 100644 mechglue/src/kadmin/testing/util/ChangeLog create mode 100644 mechglue/src/kadmin/testing/util/Makefile.in create mode 100644 mechglue/src/kadmin/testing/util/bsddb_dump.c create mode 100644 mechglue/src/kadmin/testing/util/tcl_kadm5.c create mode 100644 mechglue/src/kadmin/testing/util/tcl_kadm5.h create mode 100644 mechglue/src/kadmin/testing/util/tcl_krb5_hash.c create mode 100644 mechglue/src/kadmin/testing/util/tcl_ovsec_kadm.c create mode 100644 mechglue/src/kadmin/testing/util/tcl_ovsec_kadm_syntax create mode 100644 mechglue/src/kadmin/testing/util/test.c create mode 100644 mechglue/src/kdc/.Sanitize create mode 100644 mechglue/src/kdc/.rconf create mode 100644 mechglue/src/kdc/.saberinit create mode 100644 mechglue/src/kdc/ChangeLog create mode 100644 mechglue/src/kdc/Makefile.in create mode 100644 mechglue/src/kdc/dispatch.c create mode 100644 mechglue/src/kdc/do_as_req.c create mode 100644 mechglue/src/kdc/do_tgs_req.c create mode 100644 mechglue/src/kdc/extern.c create mode 100644 mechglue/src/kdc/extern.h create mode 100644 mechglue/src/kdc/fakeka.c create mode 100644 mechglue/src/kdc/kdc5_err.et create mode 100644 mechglue/src/kdc/kdc_preauth.c create mode 100644 mechglue/src/kdc/kdc_util.c create mode 100644 mechglue/src/kdc/kdc_util.h create mode 100644 mechglue/src/kdc/kerberos_v4.c create mode 100644 mechglue/src/kdc/krb5kdc.M create mode 100644 mechglue/src/kdc/main.c create mode 100644 mechglue/src/kdc/migration.doc create mode 100644 mechglue/src/kdc/network.c create mode 100644 mechglue/src/kdc/policy.c create mode 100644 mechglue/src/kdc/policy.h create mode 100644 mechglue/src/kdc/replay.c create mode 100644 mechglue/src/kdc/rtest.c create mode 100644 mechglue/src/kdc/rtest.good create mode 100755 mechglue/src/kdc/rtscript create mode 100644 mechglue/src/krb5-config.M create mode 100755 mechglue/src/krb5-config.in create mode 100644 mechglue/src/krb524/.Sanitize create mode 100644 mechglue/src/krb524/ChangeLog create mode 100644 mechglue/src/krb524/Makefile.in create mode 100644 mechglue/src/krb524/README create mode 100644 mechglue/src/krb524/cnv_tkt_skey.c create mode 100644 mechglue/src/krb524/conv_princ.c create mode 100644 mechglue/src/krb524/k524init.c create mode 100644 mechglue/src/krb524/krb524.c create mode 100644 mechglue/src/krb524/krb524.def create mode 100644 mechglue/src/krb524/krb524_prot create mode 100644 mechglue/src/krb524/krb524d.M create mode 100644 mechglue/src/krb524/krb524d.c create mode 100644 mechglue/src/krb524/krb524d.h create mode 100644 mechglue/src/krb524/libinit.c create mode 100644 mechglue/src/krb524/test.c create mode 100644 mechglue/src/lib/.Sanitize create mode 100644 mechglue/src/lib/.rconf create mode 100644 mechglue/src/lib/ChangeLog create mode 100644 mechglue/src/lib/Makefile.in create mode 100644 mechglue/src/lib/apputils/ChangeLog create mode 100644 mechglue/src/lib/apputils/Makefile.in create mode 100644 mechglue/src/lib/apputils/configure.in create mode 100644 mechglue/src/lib/apputils/daemon.c create mode 100644 mechglue/src/lib/apputils/dummy.c create mode 100644 mechglue/src/lib/ccapi/ChangeLog create mode 100644 mechglue/src/lib/ccapi/client/ChangeLog create mode 100644 mechglue/src/lib/ccapi/client/NTMakefile create mode 100644 mechglue/src/lib/ccapi/client/cacheapi.c create mode 100644 mechglue/src/lib/ccapi/client/ccache.c create mode 100644 mechglue/src/lib/ccapi/client/ccache.h create mode 100644 mechglue/src/lib/ccapi/client/ccache_iterator.c create mode 100644 mechglue/src/lib/ccapi/client/ccache_iterator.h create mode 100644 mechglue/src/lib/ccapi/client/ccstring.c create mode 100644 mechglue/src/lib/ccapi/client/ccstring.h create mode 100644 mechglue/src/lib/ccapi/client/context.c create mode 100644 mechglue/src/lib/ccapi/client/context.h create mode 100644 mechglue/src/lib/ccapi/client/credentials.c create mode 100644 mechglue/src/lib/ccapi/client/credentials.h create mode 100644 mechglue/src/lib/ccapi/client/credentials_iterator.c create mode 100644 mechglue/src/lib/ccapi/client/credentials_iterator.h create mode 100644 mechglue/src/lib/ccapi/client/mac/ChangeLog create mode 100644 mechglue/src/lib/ccapi/client/windows/ChangeLog create mode 100644 mechglue/src/lib/ccapi/include/ChangeLog create mode 100644 mechglue/src/lib/ccapi/include/CredentialsCache.h create mode 100644 mechglue/src/lib/ccapi/include/CredentialsCache2.h create mode 100644 mechglue/src/lib/ccapi/include/marshall.h create mode 100644 mechglue/src/lib/ccapi/include/msg.h create mode 100644 mechglue/src/lib/ccapi/include/msg_headers.h create mode 100644 mechglue/src/lib/ccapi/mac/ChangeLog create mode 100644 mechglue/src/lib/ccapi/marshall.c create mode 100644 mechglue/src/lib/ccapi/msg.c create mode 100644 mechglue/src/lib/ccapi/server/ChangeLog create mode 100644 mechglue/src/lib/ccapi/server/NTMakefile create mode 100644 mechglue/src/lib/ccapi/server/ccache.c create mode 100644 mechglue/src/lib/ccapi/server/context.c create mode 100644 mechglue/src/lib/ccapi/server/datastore.h create mode 100644 mechglue/src/lib/ccapi/server/lists.c create mode 100644 mechglue/src/lib/ccapi/server/mac/ChangeLog create mode 100644 mechglue/src/lib/ccapi/server/rpc_auth.c create mode 100644 mechglue/src/lib/ccapi/server/rpc_auth.h create mode 100644 mechglue/src/lib/ccapi/server/serv_ops.c create mode 100644 mechglue/src/lib/ccapi/server/serv_ops.h create mode 100644 mechglue/src/lib/ccapi/server/windows/ChangeLog create mode 100644 mechglue/src/lib/ccapi/unit-test/ChangeLog create mode 100644 mechglue/src/lib/ccapi/unit-test/t_ccache.c create mode 100644 mechglue/src/lib/ccapi/unit-test/t_context.c create mode 100644 mechglue/src/lib/ccapi/unit-test/t_lists.c create mode 100644 mechglue/src/lib/ccapi/unit-test/t_msg.c create mode 100644 mechglue/src/lib/ccapi/unit-test/t_server.c create mode 100644 mechglue/src/lib/ccapi/windows/ChangeLog create mode 100644 mechglue/src/lib/comerr32.def create mode 100644 mechglue/src/lib/crypto/.Sanitize create mode 100644 mechglue/src/lib/crypto/ChangeLog create mode 100644 mechglue/src/lib/crypto/ISSUES create mode 100644 mechglue/src/lib/crypto/Makefile.in create mode 100644 mechglue/src/lib/crypto/aes/ChangeLog create mode 100644 mechglue/src/lib/crypto/aes/Makefile.in create mode 100644 mechglue/src/lib/crypto/aes/aes-gen.c create mode 100644 mechglue/src/lib/crypto/aes/aes-test.c create mode 100644 mechglue/src/lib/crypto/aes/aes.h create mode 100644 mechglue/src/lib/crypto/aes/aes.txt create mode 100644 mechglue/src/lib/crypto/aes/aes_s2k.c create mode 100644 mechglue/src/lib/crypto/aes/aes_s2k.h create mode 100644 mechglue/src/lib/crypto/aes/aescpp.h create mode 100644 mechglue/src/lib/crypto/aes/aescrypp.c create mode 100644 mechglue/src/lib/crypto/aes/aescrypt.asm create mode 100644 mechglue/src/lib/crypto/aes/aescrypt.c create mode 100644 mechglue/src/lib/crypto/aes/aeskey.c create mode 100644 mechglue/src/lib/crypto/aes/aeskeypp.c create mode 100644 mechglue/src/lib/crypto/aes/aesopt.h create mode 100644 mechglue/src/lib/crypto/aes/aessrc.url create mode 100644 mechglue/src/lib/crypto/aes/aestab.c create mode 100644 mechglue/src/lib/crypto/aes/expect-vk.txt create mode 100644 mechglue/src/lib/crypto/aes/expect-vt.txt create mode 100644 mechglue/src/lib/crypto/aes/test/Readme.txt create mode 100644 mechglue/src/lib/crypto/aes/test/cbc_d_m.txt create mode 100644 mechglue/src/lib/crypto/aes/test/cbc_e_m.txt create mode 100644 mechglue/src/lib/crypto/aes/test/ecb_d_m.txt create mode 100644 mechglue/src/lib/crypto/aes/test/ecb_e_m.txt create mode 100644 mechglue/src/lib/crypto/aes/test/ecb_iv.readme create mode 100644 mechglue/src/lib/crypto/aes/test/ecb_iv.txt create mode 100644 mechglue/src/lib/crypto/aes/test/ecb_tbl.txt create mode 100644 mechglue/src/lib/crypto/aes/test/ecb_vk.txt create mode 100644 mechglue/src/lib/crypto/aes/test/ecb_vt.txt create mode 100644 mechglue/src/lib/crypto/aes/test/katmct.pdf create mode 100644 mechglue/src/lib/crypto/aes/uitypes.h create mode 100644 mechglue/src/lib/crypto/aes/vb.txt create mode 100644 mechglue/src/lib/crypto/arcfour/ChangeLog create mode 100644 mechglue/src/lib/crypto/arcfour/Makefile.in create mode 100644 mechglue/src/lib/crypto/arcfour/arcfour-int.h create mode 100644 mechglue/src/lib/crypto/arcfour/arcfour.c create mode 100644 mechglue/src/lib/crypto/arcfour/arcfour.h create mode 100644 mechglue/src/lib/crypto/arcfour/arcfour_s2k.c create mode 100644 mechglue/src/lib/crypto/block_size.c create mode 100644 mechglue/src/lib/crypto/checksum_length.c create mode 100644 mechglue/src/lib/crypto/cksumtype_to_string.c create mode 100644 mechglue/src/lib/crypto/cksumtypes.c create mode 100644 mechglue/src/lib/crypto/cksumtypes.h create mode 100644 mechglue/src/lib/crypto/coll_proof_cksum.c create mode 100644 mechglue/src/lib/crypto/combine_keys.c create mode 100644 mechglue/src/lib/crypto/configure.in create mode 100644 mechglue/src/lib/crypto/crc32/.Sanitize create mode 100644 mechglue/src/lib/crypto/crc32/CRC.pm create mode 100644 mechglue/src/lib/crypto/crc32/ChangeLog create mode 100644 mechglue/src/lib/crypto/crc32/Makefile.in create mode 100644 mechglue/src/lib/crypto/crc32/Poly.pm create mode 100644 mechglue/src/lib/crypto/crc32/crc-32.h create mode 100644 mechglue/src/lib/crypto/crc32/crc.pl create mode 100644 mechglue/src/lib/crypto/crc32/crc32.c create mode 100644 mechglue/src/lib/crypto/crc32/t_crc.c create mode 100644 mechglue/src/lib/crypto/crypto_libinit.c create mode 100644 mechglue/src/lib/crypto/decrypt.c create mode 100644 mechglue/src/lib/crypto/default_state.c create mode 100644 mechglue/src/lib/crypto/des/.Sanitize create mode 100644 mechglue/src/lib/crypto/des/ChangeLog create mode 100644 mechglue/src/lib/crypto/des/ISSUES create mode 100644 mechglue/src/lib/crypto/des/Makefile.in create mode 100644 mechglue/src/lib/crypto/des/afsstring2key.c create mode 100644 mechglue/src/lib/crypto/des/d3_cbc.c create mode 100644 mechglue/src/lib/crypto/des/d3_kysched.c create mode 100644 mechglue/src/lib/crypto/des/des_int.h create mode 100644 mechglue/src/lib/crypto/des/destest.c create mode 100644 mechglue/src/lib/crypto/des/doc/.Sanitize create mode 100644 mechglue/src/lib/crypto/des/doc/libdes.doc create mode 100644 mechglue/src/lib/crypto/des/f_cbc.c create mode 100644 mechglue/src/lib/crypto/des/f_cksum.c create mode 100644 mechglue/src/lib/crypto/des/f_parity.c create mode 100644 mechglue/src/lib/crypto/des/f_sched.c create mode 100644 mechglue/src/lib/crypto/des/f_tables.c create mode 100644 mechglue/src/lib/crypto/des/f_tables.h create mode 100644 mechglue/src/lib/crypto/des/key_sched.c create mode 100644 mechglue/src/lib/crypto/des/keytest.data create mode 100644 mechglue/src/lib/crypto/des/string2key.c create mode 100644 mechglue/src/lib/crypto/des/t_afss2k.c create mode 100644 mechglue/src/lib/crypto/des/t_verify.c create mode 100644 mechglue/src/lib/crypto/des/weak_key.c create mode 100644 mechglue/src/lib/crypto/dk/ChangeLog create mode 100644 mechglue/src/lib/crypto/dk/Makefile.in create mode 100644 mechglue/src/lib/crypto/dk/checksum.c create mode 100644 mechglue/src/lib/crypto/dk/derive.c create mode 100644 mechglue/src/lib/crypto/dk/dk.h create mode 100644 mechglue/src/lib/crypto/dk/dk_decrypt.c create mode 100644 mechglue/src/lib/crypto/dk/dk_encrypt.c create mode 100644 mechglue/src/lib/crypto/dk/dk_prf.c create mode 100644 mechglue/src/lib/crypto/dk/stringtokey.c create mode 100644 mechglue/src/lib/crypto/enc_provider/ChangeLog create mode 100644 mechglue/src/lib/crypto/enc_provider/Makefile.in create mode 100644 mechglue/src/lib/crypto/enc_provider/aes.c create mode 100644 mechglue/src/lib/crypto/enc_provider/des.c create mode 100644 mechglue/src/lib/crypto/enc_provider/des3.c create mode 100644 mechglue/src/lib/crypto/enc_provider/enc_provider.h create mode 100644 mechglue/src/lib/crypto/enc_provider/rc4.c create mode 100644 mechglue/src/lib/crypto/encrypt.c create mode 100644 mechglue/src/lib/crypto/encrypt_length.c create mode 100644 mechglue/src/lib/crypto/enctype_compare.c create mode 100644 mechglue/src/lib/crypto/enctype_to_string.c create mode 100644 mechglue/src/lib/crypto/etypes.c create mode 100644 mechglue/src/lib/crypto/etypes.h create mode 100644 mechglue/src/lib/crypto/hash_provider/ChangeLog create mode 100644 mechglue/src/lib/crypto/hash_provider/Makefile.in create mode 100644 mechglue/src/lib/crypto/hash_provider/hash_crc32.c create mode 100644 mechglue/src/lib/crypto/hash_provider/hash_md4.c create mode 100644 mechglue/src/lib/crypto/hash_provider/hash_md5.c create mode 100644 mechglue/src/lib/crypto/hash_provider/hash_provider.h create mode 100644 mechglue/src/lib/crypto/hash_provider/hash_sha1.c create mode 100644 mechglue/src/lib/crypto/hmac.c create mode 100644 mechglue/src/lib/crypto/keyblocks.c create mode 100644 mechglue/src/lib/crypto/keyed_checksum_types.c create mode 100644 mechglue/src/lib/crypto/keyed_cksum.c create mode 100644 mechglue/src/lib/crypto/keyhash_provider/ChangeLog create mode 100644 mechglue/src/lib/crypto/keyhash_provider/Makefile.in create mode 100644 mechglue/src/lib/crypto/keyhash_provider/descbc.c create mode 100644 mechglue/src/lib/crypto/keyhash_provider/hmac_md5.c create mode 100644 mechglue/src/lib/crypto/keyhash_provider/k5_md4des.c create mode 100644 mechglue/src/lib/crypto/keyhash_provider/k5_md5des.c create mode 100644 mechglue/src/lib/crypto/keyhash_provider/keyhash_provider.h create mode 100644 mechglue/src/lib/crypto/keyhash_provider/t_cksum.c create mode 100644 mechglue/src/lib/crypto/libk5crypto.exports create mode 100644 mechglue/src/lib/crypto/make_checksum.c create mode 100644 mechglue/src/lib/crypto/make_random_key.c create mode 100644 mechglue/src/lib/crypto/mandatory_sumtype.c create mode 100644 mechglue/src/lib/crypto/md4/.Sanitize create mode 100644 mechglue/src/lib/crypto/md4/ChangeLog create mode 100644 mechglue/src/lib/crypto/md4/ISSUES create mode 100644 mechglue/src/lib/crypto/md4/Makefile.in create mode 100644 mechglue/src/lib/crypto/md4/md4.c create mode 100644 mechglue/src/lib/crypto/md4/rsa-md4.h create mode 100644 mechglue/src/lib/crypto/md5/.Sanitize create mode 100644 mechglue/src/lib/crypto/md5/ChangeLog create mode 100644 mechglue/src/lib/crypto/md5/ISSUES create mode 100644 mechglue/src/lib/crypto/md5/Makefile.in create mode 100644 mechglue/src/lib/crypto/md5/md5.c create mode 100644 mechglue/src/lib/crypto/md5/rsa-md5.h create mode 100644 mechglue/src/lib/crypto/md5/t_cksum.c create mode 100644 mechglue/src/lib/crypto/md5/t_mddriver.c create mode 100644 mechglue/src/lib/crypto/nfold.c create mode 100644 mechglue/src/lib/crypto/old/ChangeLog create mode 100644 mechglue/src/lib/crypto/old/Makefile.in create mode 100644 mechglue/src/lib/crypto/old/des_stringtokey.c create mode 100644 mechglue/src/lib/crypto/old/old.h create mode 100644 mechglue/src/lib/crypto/old/old_decrypt.c create mode 100644 mechglue/src/lib/crypto/old/old_encrypt.c create mode 100644 mechglue/src/lib/crypto/old_api_glue.c create mode 100644 mechglue/src/lib/crypto/pbkdf2.c create mode 100644 mechglue/src/lib/crypto/prf.c create mode 100644 mechglue/src/lib/crypto/prng.c create mode 100644 mechglue/src/lib/crypto/raw/ChangeLog create mode 100644 mechglue/src/lib/crypto/raw/Makefile.in create mode 100644 mechglue/src/lib/crypto/raw/raw.h create mode 100644 mechglue/src/lib/crypto/raw/raw_decrypt.c create mode 100644 mechglue/src/lib/crypto/raw/raw_encrypt.c create mode 100644 mechglue/src/lib/crypto/sha1/ChangeLog create mode 100644 mechglue/src/lib/crypto/sha1/ISSUES create mode 100644 mechglue/src/lib/crypto/sha1/Makefile.in create mode 100644 mechglue/src/lib/crypto/sha1/shs.c create mode 100644 mechglue/src/lib/crypto/sha1/shs.h create mode 100644 mechglue/src/lib/crypto/sha1/t_shs.c create mode 100644 mechglue/src/lib/crypto/sha1/t_shs3.c create mode 100644 mechglue/src/lib/crypto/state.c create mode 100644 mechglue/src/lib/crypto/string_to_cksumtype.c create mode 100644 mechglue/src/lib/crypto/string_to_enctype.c create mode 100644 mechglue/src/lib/crypto/string_to_key.c create mode 100644 mechglue/src/lib/crypto/t_cts.c create mode 100644 mechglue/src/lib/crypto/t_encrypt.c create mode 100644 mechglue/src/lib/crypto/t_hmac.c create mode 100644 mechglue/src/lib/crypto/t_nfold.c create mode 100644 mechglue/src/lib/crypto/t_pkcs5.c create mode 100644 mechglue/src/lib/crypto/t_prf.c create mode 100644 mechglue/src/lib/crypto/t_prng.c create mode 100644 mechglue/src/lib/crypto/t_prng.comments create mode 100644 mechglue/src/lib/crypto/t_prng.expected create mode 100644 mechglue/src/lib/crypto/t_prng.reseedtest create mode 100644 mechglue/src/lib/crypto/t_prng.reseedtest-comments create mode 100644 mechglue/src/lib/crypto/t_prng.reseedtest-expected create mode 100644 mechglue/src/lib/crypto/t_prng.seed create mode 100644 mechglue/src/lib/crypto/valid_cksumtype.c create mode 100644 mechglue/src/lib/crypto/valid_enctype.c create mode 100644 mechglue/src/lib/crypto/vectors.c create mode 100644 mechglue/src/lib/crypto/verify_checksum.c create mode 100644 mechglue/src/lib/crypto/yarrow/ASSUMPTIONS create mode 100644 mechglue/src/lib/crypto/yarrow/ChangeLog create mode 100644 mechglue/src/lib/crypto/yarrow/LICENSE create mode 100644 mechglue/src/lib/crypto/yarrow/Makefile.in create mode 100644 mechglue/src/lib/crypto/yarrow/README create mode 100644 mechglue/src/lib/crypto/yarrow/TODO create mode 100644 mechglue/src/lib/crypto/yarrow/yarrow.c create mode 100644 mechglue/src/lib/crypto/yarrow/yarrow.h create mode 100644 mechglue/src/lib/crypto/yarrow/yarrow.man create mode 100644 mechglue/src/lib/crypto/yarrow/yarrow.pod create mode 100644 mechglue/src/lib/crypto/yarrow/ycipher.c create mode 100644 mechglue/src/lib/crypto/yarrow/ycipher.h create mode 100644 mechglue/src/lib/crypto/yarrow/yexcep.h create mode 100644 mechglue/src/lib/crypto/yarrow/yhash.h create mode 100644 mechglue/src/lib/crypto/yarrow/ylock.h create mode 100644 mechglue/src/lib/crypto/yarrow/ystate.h create mode 100644 mechglue/src/lib/crypto/yarrow/ytest.c create mode 100644 mechglue/src/lib/crypto/yarrow/ytypes.h create mode 100644 mechglue/src/lib/des425/.Sanitize create mode 100644 mechglue/src/lib/des425/ChangeLog create mode 100644 mechglue/src/lib/des425/ISSUES create mode 100644 mechglue/src/lib/des425/Makefile.in create mode 100644 mechglue/src/lib/des425/cksum.c create mode 100644 mechglue/src/lib/des425/configure.in create mode 100644 mechglue/src/lib/des425/des.c create mode 100644 mechglue/src/lib/des425/enc_dec.c create mode 100644 mechglue/src/lib/des425/key_parity.c create mode 100644 mechglue/src/lib/des425/key_sched.c create mode 100644 mechglue/src/lib/des425/libdes425.exports create mode 100644 mechglue/src/lib/des425/mac_des_glue.c create mode 100644 mechglue/src/lib/des425/new_rnd_key.c create mode 100644 mechglue/src/lib/des425/pcbc_encrypt.c create mode 100644 mechglue/src/lib/des425/quad_cksum.c create mode 100644 mechglue/src/lib/des425/random_key.c create mode 100644 mechglue/src/lib/des425/read_passwd.c create mode 100644 mechglue/src/lib/des425/str_to_key.c create mode 100644 mechglue/src/lib/des425/string2key.c create mode 100644 mechglue/src/lib/des425/t_pcbc.c create mode 100644 mechglue/src/lib/des425/t_quad.c create mode 100644 mechglue/src/lib/des425/unix_time.c create mode 100644 mechglue/src/lib/des425/util.c create mode 100644 mechglue/src/lib/des425/verify.c create mode 100644 mechglue/src/lib/des425/weak_key.c create mode 100644 mechglue/src/lib/glue4.c create mode 100644 mechglue/src/lib/gssapi/.Sanitize create mode 100644 mechglue/src/lib/gssapi/ChangeLog create mode 100644 mechglue/src/lib/gssapi/Makefile.in create mode 100644 mechglue/src/lib/gssapi/README_SAMPLE_APP create mode 100644 mechglue/src/lib/gssapi/configure.in create mode 100644 mechglue/src/lib/gssapi/generic/.Sanitize create mode 100644 mechglue/src/lib/gssapi/generic/ChangeLog create mode 100644 mechglue/src/lib/gssapi/generic/Makefile.in create mode 100644 mechglue/src/lib/gssapi/generic/disp_com_err_status.c create mode 100644 mechglue/src/lib/gssapi/generic/disp_major_status.c create mode 100644 mechglue/src/lib/gssapi/generic/gssapi.hin create mode 100644 mechglue/src/lib/gssapi/generic/gssapiP_generic.h create mode 100644 mechglue/src/lib/gssapi/generic/gssapi_err_generic.et create mode 100644 mechglue/src/lib/gssapi/generic/gssapi_generic.c create mode 100644 mechglue/src/lib/gssapi/generic/gssapi_generic.h create mode 100644 mechglue/src/lib/gssapi/generic/oid_ops.c create mode 100644 mechglue/src/lib/gssapi/generic/rel_buffer.c create mode 100644 mechglue/src/lib/gssapi/generic/rel_oid_set.c create mode 100644 mechglue/src/lib/gssapi/generic/util_buffer.c create mode 100644 mechglue/src/lib/gssapi/generic/util_canonhost.c create mode 100644 mechglue/src/lib/gssapi/generic/util_localhost.c create mode 100644 mechglue/src/lib/gssapi/generic/util_oid.c create mode 100644 mechglue/src/lib/gssapi/generic/util_ordering.c create mode 100644 mechglue/src/lib/gssapi/generic/util_set.c create mode 100644 mechglue/src/lib/gssapi/generic/util_token.c create mode 100644 mechglue/src/lib/gssapi/generic/util_validate.c create mode 100644 mechglue/src/lib/gssapi/generic/utl_nohash_validate.c create mode 100644 mechglue/src/lib/gssapi/gss_libinit.c create mode 100644 mechglue/src/lib/gssapi/gss_libinit.h create mode 100644 mechglue/src/lib/gssapi/krb5/.Sanitize create mode 100644 mechglue/src/lib/gssapi/krb5/3des.txt create mode 100644 mechglue/src/lib/gssapi/krb5/ChangeLog create mode 100644 mechglue/src/lib/gssapi/krb5/Makefile.in create mode 100644 mechglue/src/lib/gssapi/krb5/accept_sec_context.c create mode 100644 mechglue/src/lib/gssapi/krb5/acquire_cred.c create mode 100644 mechglue/src/lib/gssapi/krb5/add_cred.c create mode 100644 mechglue/src/lib/gssapi/krb5/canon_name.c create mode 100644 mechglue/src/lib/gssapi/krb5/compare_name.c create mode 100644 mechglue/src/lib/gssapi/krb5/context_time.c create mode 100644 mechglue/src/lib/gssapi/krb5/copy_ccache.c create mode 100644 mechglue/src/lib/gssapi/krb5/delete_sec_context.c create mode 100644 mechglue/src/lib/gssapi/krb5/disp_name.c create mode 100644 mechglue/src/lib/gssapi/krb5/disp_status.c create mode 100644 mechglue/src/lib/gssapi/krb5/duplicate_name.c create mode 100644 mechglue/src/lib/gssapi/krb5/export_name.c create mode 100644 mechglue/src/lib/gssapi/krb5/export_sec_context.c create mode 100644 mechglue/src/lib/gssapi/krb5/get_tkt_flags.c create mode 100644 mechglue/src/lib/gssapi/krb5/gssapiP_krb5.h create mode 100644 mechglue/src/lib/gssapi/krb5/gssapi_err_krb5.et create mode 100644 mechglue/src/lib/gssapi/krb5/gssapi_krb5.c create mode 100644 mechglue/src/lib/gssapi/krb5/gssapi_krb5.hin create mode 100644 mechglue/src/lib/gssapi/krb5/import_name.c create mode 100644 mechglue/src/lib/gssapi/krb5/import_sec_context.c create mode 100644 mechglue/src/lib/gssapi/krb5/indicate_mechs.c create mode 100644 mechglue/src/lib/gssapi/krb5/init_sec_context.c create mode 100644 mechglue/src/lib/gssapi/krb5/inq_context.c create mode 100644 mechglue/src/lib/gssapi/krb5/inq_cred.c create mode 100644 mechglue/src/lib/gssapi/krb5/inq_names.c create mode 100644 mechglue/src/lib/gssapi/krb5/k5seal.c create mode 100644 mechglue/src/lib/gssapi/krb5/k5sealv3.c create mode 100644 mechglue/src/lib/gssapi/krb5/k5unseal.c create mode 100644 mechglue/src/lib/gssapi/krb5/krb5_gss_glue.c create mode 100644 mechglue/src/lib/gssapi/krb5/lucid_context.c create mode 100644 mechglue/src/lib/gssapi/krb5/process_context_token.c create mode 100644 mechglue/src/lib/gssapi/krb5/rel_cred.c create mode 100644 mechglue/src/lib/gssapi/krb5/rel_name.c create mode 100644 mechglue/src/lib/gssapi/krb5/rel_oid.c create mode 100644 mechglue/src/lib/gssapi/krb5/seal.c create mode 100644 mechglue/src/lib/gssapi/krb5/ser_sctx.c create mode 100644 mechglue/src/lib/gssapi/krb5/set_allowable_enctypes.c create mode 100644 mechglue/src/lib/gssapi/krb5/set_ccache.c create mode 100644 mechglue/src/lib/gssapi/krb5/sign.c create mode 100644 mechglue/src/lib/gssapi/krb5/unseal.c create mode 100644 mechglue/src/lib/gssapi/krb5/util_cksum.c create mode 100644 mechglue/src/lib/gssapi/krb5/util_crypt.c create mode 100644 mechglue/src/lib/gssapi/krb5/util_seed.c create mode 100644 mechglue/src/lib/gssapi/krb5/util_seqnum.c create mode 100644 mechglue/src/lib/gssapi/krb5/val_cred.c create mode 100644 mechglue/src/lib/gssapi/krb5/verify.c create mode 100644 mechglue/src/lib/gssapi/krb5/wrap_size_limit.c create mode 100644 mechglue/src/lib/gssapi/libgssapi_krb5.exports create mode 100644 mechglue/src/lib/gssapi/mechglue/.Sanitize create mode 100644 mechglue/src/lib/gssapi/mechglue/ChangeLog create mode 100644 mechglue/src/lib/gssapi/mechglue/Makefile.in create mode 100644 mechglue/src/lib/gssapi/mechglue/g_accept_sec_context.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_acquire_cred.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_canon_name.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_compare_name.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_context_time.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_delete_sec_context.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_dsp_name.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_dsp_status.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_dup_name.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_exp_sec_context.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_export_name.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_glue.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_imp_name.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_imp_sec_context.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_indicate_mechs.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_init_sec_context.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_initialize.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_inq_context.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_inq_cred.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_inq_names.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_mechname.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_oid_ops.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_process_context.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_rel_buffer.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_rel_cred.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_rel_name.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_rel_oid_set.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_seal.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_sign.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_store_cred.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_unseal.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_userok.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_utils.c create mode 100644 mechglue/src/lib/gssapi/mechglue/g_verify.c create mode 100644 mechglue/src/lib/gssapi/mechglue/gen_oids.c create mode 100644 mechglue/src/lib/gssapi/mechglue/gssd_pname_to_uid.c create mode 100644 mechglue/src/lib/gssapi/mechglue/mech.conf create mode 100644 mechglue/src/lib/gssapi/mechglue/mechglue.h create mode 100644 mechglue/src/lib/gssapi/mechglue/mglueP.h create mode 100644 mechglue/src/lib/gssapi/mechglue/oid_ops.c create mode 100644 mechglue/src/lib/gssapi32.def create mode 100644 mechglue/src/lib/kadm5/ChangeLog create mode 100644 mechglue/src/lib/kadm5/Makefile.in create mode 100644 mechglue/src/lib/kadm5/adb.h create mode 100644 mechglue/src/lib/kadm5/admin.h create mode 100644 mechglue/src/lib/kadm5/admin_internal.h create mode 100644 mechglue/src/lib/kadm5/admin_xdr.h create mode 100644 mechglue/src/lib/kadm5/alt_prof.c create mode 100644 mechglue/src/lib/kadm5/chpass_util.c create mode 100644 mechglue/src/lib/kadm5/chpass_util_strings.et create mode 100644 mechglue/src/lib/kadm5/clnt/ChangeLog create mode 100644 mechglue/src/lib/kadm5/clnt/Makefile.in create mode 100644 mechglue/src/lib/kadm5/clnt/client_handle.c create mode 100644 mechglue/src/lib/kadm5/clnt/client_init.c create mode 100644 mechglue/src/lib/kadm5/clnt/client_internal.h create mode 100644 mechglue/src/lib/kadm5/clnt/client_principal.c create mode 100644 mechglue/src/lib/kadm5/clnt/client_rpc.c create mode 100644 mechglue/src/lib/kadm5/clnt/clnt_chpass_util.c create mode 100644 mechglue/src/lib/kadm5/clnt/clnt_policy.c create mode 100644 mechglue/src/lib/kadm5/clnt/clnt_privs.c create mode 100644 mechglue/src/lib/kadm5/clnt/err_handle.c create mode 100644 mechglue/src/lib/kadm5/clnt/err_handle.h create mode 100644 mechglue/src/lib/kadm5/clnt/libkadm5clnt.exports create mode 100644 mechglue/src/lib/kadm5/configure.in create mode 100644 mechglue/src/lib/kadm5/kadm_err.et create mode 100644 mechglue/src/lib/kadm5/kadm_rpc.h create mode 100644 mechglue/src/lib/kadm5/kadm_rpc_xdr.c create mode 100644 mechglue/src/lib/kadm5/logger.c create mode 100644 mechglue/src/lib/kadm5/misc_free.c create mode 100644 mechglue/src/lib/kadm5/ovsec_glue.c create mode 100644 mechglue/src/lib/kadm5/server_internal.h create mode 100644 mechglue/src/lib/kadm5/srv/ChangeLog create mode 100644 mechglue/src/lib/kadm5/srv/Makefile.in create mode 100644 mechglue/src/lib/kadm5/srv/adb_xdr.c create mode 100644 mechglue/src/lib/kadm5/srv/libkadm5srv.exports create mode 100644 mechglue/src/lib/kadm5/srv/server_acl.c create mode 100644 mechglue/src/lib/kadm5/srv/server_acl.h create mode 100644 mechglue/src/lib/kadm5/srv/server_dict.c create mode 100644 mechglue/src/lib/kadm5/srv/server_handle.c create mode 100644 mechglue/src/lib/kadm5/srv/server_init.c create mode 100644 mechglue/src/lib/kadm5/srv/server_kdb.c create mode 100644 mechglue/src/lib/kadm5/srv/server_misc.c create mode 100644 mechglue/src/lib/kadm5/srv/svr_chpass_util.c create mode 100644 mechglue/src/lib/kadm5/srv/svr_iters.c create mode 100644 mechglue/src/lib/kadm5/srv/svr_misc_free.c create mode 100644 mechglue/src/lib/kadm5/srv/svr_policy.c create mode 100644 mechglue/src/lib/kadm5/srv/svr_principal.c create mode 100644 mechglue/src/lib/kadm5/str_conv.c create mode 100644 mechglue/src/lib/kadm5/unit-test/ChangeLog create mode 100644 mechglue/src/lib/kadm5/unit-test/Makefile.in create mode 100644 mechglue/src/lib/kadm5/unit-test/README.new-tests create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/chpass-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/crte-policy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/crte-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/destroy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/dlte-policy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/dlte-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/get-policy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/get-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/init.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/mod-policy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/mod-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/randkey-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.0/rename-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.1/lock.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/chpass-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/crte-policy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/crte-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/destroy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/dlte-policy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/dlte-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/get-policy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/get-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/init-v2.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/init.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/mod-policy.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/mod-principal-v2.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/mod-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/api.2/randkey-principal.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/config/unix.exp create mode 100644 mechglue/src/lib/kadm5/unit-test/destroy-test.c create mode 100644 mechglue/src/lib/kadm5/unit-test/diff-files/destroy-1 create mode 100644 mechglue/src/lib/kadm5/unit-test/diff-files/no-diffs create mode 100644 mechglue/src/lib/kadm5/unit-test/handle-test.c create mode 100644 mechglue/src/lib/kadm5/unit-test/init-test.c create mode 100644 mechglue/src/lib/kadm5/unit-test/iter-test.c create mode 100644 mechglue/src/lib/kadm5/unit-test/lib/lib.t create mode 100644 mechglue/src/lib/kadm5/unit-test/lock-test.c create mode 100644 mechglue/src/lib/kadm5/unit-test/randkey-test.c create mode 100644 mechglue/src/lib/kadm5/unit-test/setkey-test.c create mode 100644 mechglue/src/lib/kadm5/unit-test/site.exp create mode 100644 mechglue/src/lib/kdb/.Sanitize create mode 100644 mechglue/src/lib/kdb/ChangeLog create mode 100644 mechglue/src/lib/kdb/Makefile.in create mode 100644 mechglue/src/lib/kdb/adb_err.et create mode 100644 mechglue/src/lib/kdb/configure.in create mode 100644 mechglue/src/lib/kdb/decrypt_key.c create mode 100644 mechglue/src/lib/kdb/encrypt_key.c create mode 100644 mechglue/src/lib/kdb/err_handle.c create mode 100644 mechglue/src/lib/kdb/err_handle.h create mode 100644 mechglue/src/lib/kdb/kdb5.c create mode 100644 mechglue/src/lib/kdb/kdb5.h create mode 100644 mechglue/src/lib/kdb/kdb_cpw.c create mode 100644 mechglue/src/lib/kdb/kdb_default.c create mode 100644 mechglue/src/lib/kdb/keytab.c create mode 100644 mechglue/src/lib/kdb/libkdb5.exports create mode 100644 mechglue/src/lib/krb4/.Sanitize create mode 100644 mechglue/src/lib/krb4/CCache-glue.c create mode 100644 mechglue/src/lib/krb4/ChangeLog create mode 100644 mechglue/src/lib/krb4/FSp-glue.c create mode 100644 mechglue/src/lib/krb4/Makefile.in create mode 100644 mechglue/src/lib/krb4/Password.c create mode 100644 mechglue/src/lib/krb4/RealmsConfig-glue.c create mode 100644 mechglue/src/lib/krb4/ad_print.c create mode 100644 mechglue/src/lib/krb4/change_password.c create mode 100644 mechglue/src/lib/krb4/configure.in create mode 100644 mechglue/src/lib/krb4/cr_auth_repl.c create mode 100644 mechglue/src/lib/krb4/cr_ciph.c create mode 100644 mechglue/src/lib/krb4/cr_death_pkt.c create mode 100644 mechglue/src/lib/krb4/cr_err_repl.c create mode 100644 mechglue/src/lib/krb4/cr_tkt.c create mode 100644 mechglue/src/lib/krb4/debug.c create mode 100644 mechglue/src/lib/krb4/decomp_tkt.c create mode 100644 mechglue/src/lib/krb4/dest_tkt.c create mode 100644 mechglue/src/lib/krb4/err_txt.c create mode 100755 mechglue/src/lib/krb4/et_errtxt.awk create mode 100644 mechglue/src/lib/krb4/fakeenv.c create mode 100644 mechglue/src/lib/krb4/fgetst.c create mode 100644 mechglue/src/lib/krb4/g_ad_tkt.c create mode 100644 mechglue/src/lib/krb4/g_cnffile.c create mode 100644 mechglue/src/lib/krb4/g_cred.c create mode 100644 mechglue/src/lib/krb4/g_in_tkt.c create mode 100644 mechglue/src/lib/krb4/g_phost.c create mode 100644 mechglue/src/lib/krb4/g_pw_in_tkt.c create mode 100644 mechglue/src/lib/krb4/g_pw_tkt.c create mode 100644 mechglue/src/lib/krb4/g_svc_in_tkt.c create mode 100644 mechglue/src/lib/krb4/g_tf_fname.c create mode 100644 mechglue/src/lib/krb4/g_tf_realm.c create mode 100644 mechglue/src/lib/krb4/g_tkt_svc.c create mode 100644 mechglue/src/lib/krb4/gethostname.c create mode 100644 mechglue/src/lib/krb4/getst.c create mode 100644 mechglue/src/lib/krb4/in_tkt.c create mode 100644 mechglue/src/lib/krb4/kadm_err.et create mode 100644 mechglue/src/lib/krb4/kadm_net.c create mode 100644 mechglue/src/lib/krb4/kadm_stream.c create mode 100644 mechglue/src/lib/krb4/klog.c create mode 100644 mechglue/src/lib/krb4/kname_parse.c create mode 100644 mechglue/src/lib/krb4/kntoln.c create mode 100644 mechglue/src/lib/krb4/kparse.c create mode 100644 mechglue/src/lib/krb4/krb4int.h create mode 100644 mechglue/src/lib/krb4/krb_err.et create mode 100644 mechglue/src/lib/krb4/kuserok.c create mode 100644 mechglue/src/lib/krb4/libkrb4.exports create mode 100644 mechglue/src/lib/krb4/lifetime.c create mode 100644 mechglue/src/lib/krb4/log.c create mode 100644 mechglue/src/lib/krb4/mac_glue.c create mode 100644 mechglue/src/lib/krb4/mac_store.c create mode 100644 mechglue/src/lib/krb4/mac_store.h create mode 100644 mechglue/src/lib/krb4/mac_stubs.c create mode 100644 mechglue/src/lib/krb4/mac_time.c create mode 100644 mechglue/src/lib/krb4/memcache.c create mode 100644 mechglue/src/lib/krb4/memcache.h create mode 100644 mechglue/src/lib/krb4/mk_auth.c create mode 100644 mechglue/src/lib/krb4/mk_err.c create mode 100644 mechglue/src/lib/krb4/mk_preauth.c create mode 100644 mechglue/src/lib/krb4/mk_priv.c create mode 100644 mechglue/src/lib/krb4/mk_req.c create mode 100644 mechglue/src/lib/krb4/mk_safe.c create mode 100644 mechglue/src/lib/krb4/month_sname.c create mode 100644 mechglue/src/lib/krb4/netread.c create mode 100644 mechglue/src/lib/krb4/netwrite.c create mode 100644 mechglue/src/lib/krb4/password_to_key.c create mode 100644 mechglue/src/lib/krb4/pkt_cipher.c create mode 100644 mechglue/src/lib/krb4/pkt_clen.c create mode 100644 mechglue/src/lib/krb4/prot_client.c create mode 100644 mechglue/src/lib/krb4/prot_common.c create mode 100644 mechglue/src/lib/krb4/prot_kdc.c create mode 100644 mechglue/src/lib/krb4/put_svc_key.c create mode 100644 mechglue/src/lib/krb4/rd_err.c create mode 100644 mechglue/src/lib/krb4/rd_preauth.c create mode 100644 mechglue/src/lib/krb4/rd_priv.c create mode 100644 mechglue/src/lib/krb4/rd_req.c create mode 100644 mechglue/src/lib/krb4/rd_safe.c create mode 100644 mechglue/src/lib/krb4/rd_svc_key.c create mode 100644 mechglue/src/lib/krb4/recvauth.c create mode 100755 mechglue/src/lib/krb4/ren-cyg.sh create mode 100644 mechglue/src/lib/krb4/ren-pc.bat create mode 100644 mechglue/src/lib/krb4/ren-pc.sh create mode 100644 mechglue/src/lib/krb4/ren-pl10.sh create mode 100644 mechglue/src/lib/krb4/ren.msg create mode 100644 mechglue/src/lib/krb4/ren2dos.sh create mode 100644 mechglue/src/lib/krb4/ren2long.sh create mode 100644 mechglue/src/lib/krb4/save_creds.c create mode 100755 mechglue/src/lib/krb4/sed-cyg.sh create mode 100755 mechglue/src/lib/krb4/sed-pc.sh create mode 100755 mechglue/src/lib/krb4/sed-pl10.sh create mode 100644 mechglue/src/lib/krb4/send_to_kdc.c create mode 100644 mechglue/src/lib/krb4/sendauth.c create mode 100644 mechglue/src/lib/krb4/setenv.c create mode 100644 mechglue/src/lib/krb4/stime.c create mode 100644 mechglue/src/lib/krb4/strcasecmp.c create mode 100644 mechglue/src/lib/krb4/strnlen.c create mode 100644 mechglue/src/lib/krb4/swab.c create mode 100644 mechglue/src/lib/krb4/tf_shm.c create mode 100644 mechglue/src/lib/krb4/tf_util.c create mode 100644 mechglue/src/lib/krb4/tkt_string.c create mode 100644 mechglue/src/lib/krb4/unix_glue.c create mode 100644 mechglue/src/lib/krb4/unix_time.c create mode 100644 mechglue/src/lib/krb4/vmslink.com create mode 100644 mechglue/src/lib/krb4/vmsswab.c create mode 100644 mechglue/src/lib/krb4/win_glue.c create mode 100644 mechglue/src/lib/krb4/win_store.c create mode 100644 mechglue/src/lib/krb4/win_time.c create mode 100644 mechglue/src/lib/krb4_32.def create mode 100644 mechglue/src/lib/krb5.rc create mode 100644 mechglue/src/lib/krb5.saber.warnings create mode 100644 mechglue/src/lib/krb5/.Sanitize create mode 100644 mechglue/src/lib/krb5/ChangeLog create mode 100644 mechglue/src/lib/krb5/Makefile.in create mode 100644 mechglue/src/lib/krb5/asn.1/.Sanitize create mode 100644 mechglue/src/lib/krb5/asn.1/.rconf create mode 100644 mechglue/src/lib/krb5/asn.1/.saberinit create mode 100644 mechglue/src/lib/krb5/asn.1/ChangeLog create mode 100644 mechglue/src/lib/krb5/asn.1/KRB5-asn.py create mode 100644 mechglue/src/lib/krb5/asn.1/Makefile.in create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_decode.c create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_decode.h create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_encode.c create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_encode.h create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_get.c create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_get.h create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_k_decode.c create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_k_decode.h create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_k_encode.c create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_k_encode.h create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_make.c create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_make.h create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_misc.c create mode 100644 mechglue/src/lib/krb5/asn.1/asn1_misc.h create mode 100644 mechglue/src/lib/krb5/asn.1/asn1buf.c create mode 100644 mechglue/src/lib/krb5/asn.1/asn1buf.h create mode 100644 mechglue/src/lib/krb5/asn.1/asn1glue.h create mode 100644 mechglue/src/lib/krb5/asn.1/krb5_decode.c create mode 100644 mechglue/src/lib/krb5/asn.1/krb5_encode.c create mode 100644 mechglue/src/lib/krb5/asn.1/krbasn1.h create mode 100644 mechglue/src/lib/krb5/ccache/.Sanitize create mode 100644 mechglue/src/lib/krb5/ccache/ChangeLog create mode 100644 mechglue/src/lib/krb5/ccache/Makefile.in create mode 100644 mechglue/src/lib/krb5/ccache/cc-int.h create mode 100644 mechglue/src/lib/krb5/ccache/cc_file.c create mode 100644 mechglue/src/lib/krb5/ccache/cc_memory.c create mode 100644 mechglue/src/lib/krb5/ccache/cc_mslsa.c create mode 100644 mechglue/src/lib/krb5/ccache/cc_retr.c create mode 100644 mechglue/src/lib/krb5/ccache/ccapi/ChangeLog create mode 100644 mechglue/src/lib/krb5/ccache/ccapi/Makefile.in create mode 100644 mechglue/src/lib/krb5/ccache/ccapi/stdcc.c create mode 100644 mechglue/src/lib/krb5/ccache/ccapi/stdcc.h create mode 100644 mechglue/src/lib/krb5/ccache/ccapi/stdcc_util.c create mode 100644 mechglue/src/lib/krb5/ccache/ccapi/stdcc_util.h create mode 100644 mechglue/src/lib/krb5/ccache/ccapi/winccld.c create mode 100644 mechglue/src/lib/krb5/ccache/ccapi/winccld.h create mode 100644 mechglue/src/lib/krb5/ccache/ccbase.c create mode 100644 mechglue/src/lib/krb5/ccache/cccopy.c create mode 100644 mechglue/src/lib/krb5/ccache/ccdefault.c create mode 100644 mechglue/src/lib/krb5/ccache/ccdefops.c create mode 100644 mechglue/src/lib/krb5/ccache/ccfns.c create mode 100644 mechglue/src/lib/krb5/ccache/fcc.h create mode 100644 mechglue/src/lib/krb5/ccache/scc.h create mode 100644 mechglue/src/lib/krb5/ccache/ser_cc.c create mode 100644 mechglue/src/lib/krb5/ccache/t_cc.c create mode 100644 mechglue/src/lib/krb5/ccache/t_memory.c create mode 100644 mechglue/src/lib/krb5/ccache/t_stdio.c create mode 100644 mechglue/src/lib/krb5/configure.in create mode 100644 mechglue/src/lib/krb5/error_tables/.Sanitize create mode 100644 mechglue/src/lib/krb5/error_tables/.rconf create mode 100644 mechglue/src/lib/krb5/error_tables/ChangeLog create mode 100644 mechglue/src/lib/krb5/error_tables/Makefile.in create mode 100644 mechglue/src/lib/krb5/error_tables/asn1_err.et create mode 100644 mechglue/src/lib/krb5/error_tables/init_ets.c create mode 100644 mechglue/src/lib/krb5/error_tables/kdb5_err.et create mode 100644 mechglue/src/lib/krb5/error_tables/krb524_err.et create mode 100644 mechglue/src/lib/krb5/error_tables/krb5_err.et create mode 100644 mechglue/src/lib/krb5/error_tables/kv5m_err.et create mode 100644 mechglue/src/lib/krb5/keytab/.Sanitize create mode 100644 mechglue/src/lib/krb5/keytab/ChangeLog create mode 100644 mechglue/src/lib/krb5/keytab/Makefile.in create mode 100644 mechglue/src/lib/krb5/keytab/kt-int.h create mode 100644 mechglue/src/lib/krb5/keytab/kt_file.c create mode 100644 mechglue/src/lib/krb5/keytab/kt_srvtab.c create mode 100644 mechglue/src/lib/krb5/keytab/ktadd.c create mode 100644 mechglue/src/lib/krb5/keytab/ktbase.c create mode 100644 mechglue/src/lib/krb5/keytab/ktdefault.c create mode 100644 mechglue/src/lib/krb5/keytab/ktfns.c create mode 100644 mechglue/src/lib/krb5/keytab/ktfr_entry.c create mode 100644 mechglue/src/lib/krb5/keytab/ktremove.c create mode 100644 mechglue/src/lib/krb5/keytab/read_servi.c create mode 100644 mechglue/src/lib/krb5/krb/.Sanitize create mode 100644 mechglue/src/lib/krb5/krb/ChangeLog create mode 100644 mechglue/src/lib/krb5/krb/Makefile.in create mode 100644 mechglue/src/lib/krb5/krb/addr_comp.c create mode 100644 mechglue/src/lib/krb5/krb/addr_order.c create mode 100644 mechglue/src/lib/krb5/krb/addr_srch.c create mode 100644 mechglue/src/lib/krb5/krb/appdefault.c create mode 100644 mechglue/src/lib/krb5/krb/auth_con.c create mode 100644 mechglue/src/lib/krb5/krb/auth_con.h create mode 100644 mechglue/src/lib/krb5/krb/bld_pr_ext.c create mode 100644 mechglue/src/lib/krb5/krb/bld_princ.c create mode 100644 mechglue/src/lib/krb5/krb/brand.c create mode 100644 mechglue/src/lib/krb5/krb/chk_trans.c create mode 100644 mechglue/src/lib/krb5/krb/chpw.c create mode 100644 mechglue/src/lib/krb5/krb/cleanup.h create mode 100644 mechglue/src/lib/krb5/krb/conv_creds.c create mode 100644 mechglue/src/lib/krb5/krb/conv_princ.c create mode 100644 mechglue/src/lib/krb5/krb/copy_addrs.c create mode 100644 mechglue/src/lib/krb5/krb/copy_athctr.c create mode 100644 mechglue/src/lib/krb5/krb/copy_auth.c create mode 100644 mechglue/src/lib/krb5/krb/copy_cksum.c create mode 100644 mechglue/src/lib/krb5/krb/copy_creds.c create mode 100644 mechglue/src/lib/krb5/krb/copy_data.c create mode 100644 mechglue/src/lib/krb5/krb/copy_key.c create mode 100644 mechglue/src/lib/krb5/krb/copy_princ.c create mode 100644 mechglue/src/lib/krb5/krb/copy_tick.c create mode 100644 mechglue/src/lib/krb5/krb/cp_key_cnt.c create mode 100644 mechglue/src/lib/krb5/krb/decode_kdc.c create mode 100644 mechglue/src/lib/krb5/krb/decrypt_tk.c create mode 100644 mechglue/src/lib/krb5/krb/deltat.c create mode 100644 mechglue/src/lib/krb5/krb/enc_helper.c create mode 100644 mechglue/src/lib/krb5/krb/encode_kdc.c create mode 100644 mechglue/src/lib/krb5/krb/encrypt_tk.c create mode 100644 mechglue/src/lib/krb5/krb/free_rtree.c create mode 100644 mechglue/src/lib/krb5/krb/fwd_tgt.c create mode 100644 mechglue/src/lib/krb5/krb/gc_frm_kdc.c create mode 100644 mechglue/src/lib/krb5/krb/gc_via_tkt.c create mode 100644 mechglue/src/lib/krb5/krb/gen_seqnum.c create mode 100644 mechglue/src/lib/krb5/krb/gen_subkey.c create mode 100644 mechglue/src/lib/krb5/krb/get_creds.c create mode 100644 mechglue/src/lib/krb5/krb/get_in_tkt.c create mode 100644 mechglue/src/lib/krb5/krb/gic_keytab.c create mode 100644 mechglue/src/lib/krb5/krb/gic_opt.c create mode 100644 mechglue/src/lib/krb5/krb/gic_pwd.c create mode 100644 mechglue/src/lib/krb5/krb/in_tkt_sky.c create mode 100644 mechglue/src/lib/krb5/krb/init_ctx.c create mode 100644 mechglue/src/lib/krb5/krb/init_keyblock.c create mode 100644 mechglue/src/lib/krb5/krb/int-proto.h create mode 100644 mechglue/src/lib/krb5/krb/kdc_rep_dc.c create mode 100644 mechglue/src/lib/krb5/krb/kfree.c create mode 100644 mechglue/src/lib/krb5/krb/mk_cred.c create mode 100644 mechglue/src/lib/krb5/krb/mk_error.c create mode 100644 mechglue/src/lib/krb5/krb/mk_priv.c create mode 100644 mechglue/src/lib/krb5/krb/mk_rep.c create mode 100644 mechglue/src/lib/krb5/krb/mk_req.c create mode 100644 mechglue/src/lib/krb5/krb/mk_req_ext.c create mode 100644 mechglue/src/lib/krb5/krb/mk_safe.c create mode 100644 mechglue/src/lib/krb5/krb/parse.c create mode 100644 mechglue/src/lib/krb5/krb/pr_to_salt.c create mode 100644 mechglue/src/lib/krb5/krb/preauth.c create mode 100644 mechglue/src/lib/krb5/krb/preauth2.c create mode 100644 mechglue/src/lib/krb5/krb/princ_comp.c create mode 100644 mechglue/src/lib/krb5/krb/rd_cred.c create mode 100644 mechglue/src/lib/krb5/krb/rd_error.c create mode 100644 mechglue/src/lib/krb5/krb/rd_priv.c create mode 100644 mechglue/src/lib/krb5/krb/rd_rep.c create mode 100644 mechglue/src/lib/krb5/krb/rd_req.c create mode 100644 mechglue/src/lib/krb5/krb/rd_req_dec.c create mode 100644 mechglue/src/lib/krb5/krb/rd_safe.c create mode 100644 mechglue/src/lib/krb5/krb/recvauth.c create mode 100644 mechglue/src/lib/krb5/krb/send_tgs.c create mode 100644 mechglue/src/lib/krb5/krb/sendauth.c create mode 100644 mechglue/src/lib/krb5/krb/ser_actx.c create mode 100644 mechglue/src/lib/krb5/krb/ser_adata.c create mode 100644 mechglue/src/lib/krb5/krb/ser_addr.c create mode 100644 mechglue/src/lib/krb5/krb/ser_auth.c create mode 100644 mechglue/src/lib/krb5/krb/ser_cksum.c create mode 100644 mechglue/src/lib/krb5/krb/ser_ctx.c create mode 100644 mechglue/src/lib/krb5/krb/ser_eblk.c create mode 100644 mechglue/src/lib/krb5/krb/ser_key.c create mode 100644 mechglue/src/lib/krb5/krb/ser_princ.c create mode 100644 mechglue/src/lib/krb5/krb/serialize.c create mode 100644 mechglue/src/lib/krb5/krb/set_realm.c create mode 100644 mechglue/src/lib/krb5/krb/srv_rcache.c create mode 100644 mechglue/src/lib/krb5/krb/str_conv.c create mode 100644 mechglue/src/lib/krb5/krb/strftime.c create mode 100644 mechglue/src/lib/krb5/krb/strptime.c create mode 100644 mechglue/src/lib/krb5/krb/t_deltat.c create mode 100644 mechglue/src/lib/krb5/krb/t_expand.c create mode 100644 mechglue/src/lib/krb5/krb/t_kerb.c create mode 100644 mechglue/src/lib/krb5/krb/t_krb5.conf create mode 100644 mechglue/src/lib/krb5/krb/t_ref_kerb.out create mode 100644 mechglue/src/lib/krb5/krb/t_ser.c create mode 100644 mechglue/src/lib/krb5/krb/t_walk_rtree.c create mode 100644 mechglue/src/lib/krb5/krb/tgtname.c create mode 100755 mechglue/src/lib/krb5/krb/transit-tests create mode 100644 mechglue/src/lib/krb5/krb/unparse.c create mode 100644 mechglue/src/lib/krb5/krb/v4lifetime.c create mode 100644 mechglue/src/lib/krb5/krb/valid_times.c create mode 100644 mechglue/src/lib/krb5/krb/vfy_increds.c create mode 100644 mechglue/src/lib/krb5/krb/vic_opt.c create mode 100644 mechglue/src/lib/krb5/krb/walk_rtree.c create mode 100644 mechglue/src/lib/krb5/krb/x-deltat.y create mode 100644 mechglue/src/lib/krb5/krb5_libinit.c create mode 100644 mechglue/src/lib/krb5/krb5_libinit.h create mode 100644 mechglue/src/lib/krb5/libkrb5.exports create mode 100644 mechglue/src/lib/krb5/os/.Sanitize create mode 100644 mechglue/src/lib/krb5/os/ChangeLog create mode 100644 mechglue/src/lib/krb5/os/Makefile.in create mode 100644 mechglue/src/lib/krb5/os/accessor.c create mode 100644 mechglue/src/lib/krb5/os/an_to_ln.c create mode 100644 mechglue/src/lib/krb5/os/c_ustime.c create mode 100644 mechglue/src/lib/krb5/os/ccdefname.c create mode 100644 mechglue/src/lib/krb5/os/changepw.c create mode 100644 mechglue/src/lib/krb5/os/def_realm.c create mode 100644 mechglue/src/lib/krb5/os/dnsglue.c create mode 100644 mechglue/src/lib/krb5/os/dnsglue.h create mode 100644 mechglue/src/lib/krb5/os/dnssrv.c create mode 100644 mechglue/src/lib/krb5/os/free_hstrl.c create mode 100644 mechglue/src/lib/krb5/os/free_krbhs.c create mode 100644 mechglue/src/lib/krb5/os/full_ipadr.c create mode 100644 mechglue/src/lib/krb5/os/gen_port.c create mode 100644 mechglue/src/lib/krb5/os/gen_rname.c create mode 100644 mechglue/src/lib/krb5/os/genaddrs.c create mode 100644 mechglue/src/lib/krb5/os/get_krbhst.c create mode 100644 mechglue/src/lib/krb5/os/gmt_mktime.c create mode 100644 mechglue/src/lib/krb5/os/hostaddr.c create mode 100644 mechglue/src/lib/krb5/os/hst_realm.c create mode 100644 mechglue/src/lib/krb5/os/init_os_ctx.c create mode 100644 mechglue/src/lib/krb5/os/krbfileio.c create mode 100644 mechglue/src/lib/krb5/os/ktdefname.c create mode 100644 mechglue/src/lib/krb5/os/kuserok.c create mode 100644 mechglue/src/lib/krb5/os/localaddr.c create mode 100644 mechglue/src/lib/krb5/os/locate_kdc.c create mode 100644 mechglue/src/lib/krb5/os/lock_file.c create mode 100644 mechglue/src/lib/krb5/os/mk_faddr.c create mode 100644 mechglue/src/lib/krb5/os/net_read.c create mode 100644 mechglue/src/lib/krb5/os/net_write.c create mode 100644 mechglue/src/lib/krb5/os/os-proto.h create mode 100644 mechglue/src/lib/krb5/os/osconfig.c create mode 100644 mechglue/src/lib/krb5/os/port2ip.c create mode 100644 mechglue/src/lib/krb5/os/prompter.c create mode 100644 mechglue/src/lib/krb5/os/promptusr.c create mode 100644 mechglue/src/lib/krb5/os/read_msg.c create mode 100644 mechglue/src/lib/krb5/os/read_pwd.c create mode 100644 mechglue/src/lib/krb5/os/realm_dom.c create mode 100644 mechglue/src/lib/krb5/os/realm_iter.c create mode 100644 mechglue/src/lib/krb5/os/ref_std_conf.out create mode 100644 mechglue/src/lib/krb5/os/send524.c create mode 100644 mechglue/src/lib/krb5/os/sendto_kdc.c create mode 100644 mechglue/src/lib/krb5/os/sn2princ.c create mode 100644 mechglue/src/lib/krb5/os/t_an_to_ln.c create mode 100644 mechglue/src/lib/krb5/os/t_gifconf.c create mode 100644 mechglue/src/lib/krb5/os/t_locate_kdc.c create mode 100644 mechglue/src/lib/krb5/os/t_realm_iter.c create mode 100644 mechglue/src/lib/krb5/os/t_std_conf.c create mode 100644 mechglue/src/lib/krb5/os/td_krb5.conf create mode 100644 mechglue/src/lib/krb5/os/thread_safe.c create mode 100644 mechglue/src/lib/krb5/os/timeofday.c create mode 100644 mechglue/src/lib/krb5/os/toffset.c create mode 100644 mechglue/src/lib/krb5/os/unlck_file.c create mode 100644 mechglue/src/lib/krb5/os/ustime.c create mode 100644 mechglue/src/lib/krb5/os/write_msg.c create mode 100644 mechglue/src/lib/krb5/posix/.Sanitize create mode 100644 mechglue/src/lib/krb5/posix/ChangeLog create mode 100644 mechglue/src/lib/krb5/posix/Makefile.in create mode 100644 mechglue/src/lib/krb5/posix/getuid.c create mode 100644 mechglue/src/lib/krb5/posix/memmove.c create mode 100644 mechglue/src/lib/krb5/posix/sscanf.c create mode 100644 mechglue/src/lib/krb5/posix/strcasecmp.c create mode 100644 mechglue/src/lib/krb5/posix/strdup.c create mode 100644 mechglue/src/lib/krb5/posix/strerror.c create mode 100644 mechglue/src/lib/krb5/posix/syslog.c create mode 100644 mechglue/src/lib/krb5/posix/vfprintf.c create mode 100644 mechglue/src/lib/krb5/posix/vsprintf.c create mode 100644 mechglue/src/lib/krb5/rcache/.Sanitize create mode 100644 mechglue/src/lib/krb5/rcache/.rconf create mode 100644 mechglue/src/lib/krb5/rcache/ChangeLog create mode 100644 mechglue/src/lib/krb5/rcache/Makefile.in create mode 100644 mechglue/src/lib/krb5/rcache/README create mode 100644 mechglue/src/lib/krb5/rcache/RELEASE create mode 100644 mechglue/src/lib/krb5/rcache/rc-int.h create mode 100644 mechglue/src/lib/krb5/rcache/rc_base.c create mode 100644 mechglue/src/lib/krb5/rcache/rc_base.h create mode 100644 mechglue/src/lib/krb5/rcache/rc_conv.c create mode 100644 mechglue/src/lib/krb5/rcache/rc_dfl.c create mode 100644 mechglue/src/lib/krb5/rcache/rc_dfl.h create mode 100644 mechglue/src/lib/krb5/rcache/rc_io.c create mode 100644 mechglue/src/lib/krb5/rcache/rc_io.h create mode 100644 mechglue/src/lib/krb5/rcache/rc_none.c create mode 100644 mechglue/src/lib/krb5/rcache/rcdef.c create mode 100644 mechglue/src/lib/krb5/rcache/rcfns.c create mode 100644 mechglue/src/lib/krb5/rcache/ser_rc.c create mode 100644 mechglue/src/lib/krb5_32.def create mode 100644 mechglue/src/lib/rpc/ChangeLog create mode 100644 mechglue/src/lib/rpc/Makefile.in create mode 100644 mechglue/src/lib/rpc/auth.h create mode 100644 mechglue/src/lib/rpc/auth_gss.c create mode 100644 mechglue/src/lib/rpc/auth_gss.h create mode 100644 mechglue/src/lib/rpc/auth_gssapi.c create mode 100644 mechglue/src/lib/rpc/auth_gssapi.h create mode 100644 mechglue/src/lib/rpc/auth_gssapi_misc.c create mode 100644 mechglue/src/lib/rpc/auth_none.c create mode 100644 mechglue/src/lib/rpc/auth_unix.c create mode 100644 mechglue/src/lib/rpc/auth_unix.h create mode 100644 mechglue/src/lib/rpc/authgss_prot.c create mode 100644 mechglue/src/lib/rpc/authunix_prot.c create mode 100644 mechglue/src/lib/rpc/bindresvport.c create mode 100644 mechglue/src/lib/rpc/clnt.h create mode 100644 mechglue/src/lib/rpc/clnt_generic.c create mode 100644 mechglue/src/lib/rpc/clnt_perror.c create mode 100644 mechglue/src/lib/rpc/clnt_raw.c create mode 100644 mechglue/src/lib/rpc/clnt_simple.c create mode 100644 mechglue/src/lib/rpc/clnt_tcp.c create mode 100644 mechglue/src/lib/rpc/clnt_udp.c create mode 100644 mechglue/src/lib/rpc/configure.in create mode 100644 mechglue/src/lib/rpc/dyn.c create mode 100644 mechglue/src/lib/rpc/dyn.h create mode 100644 mechglue/src/lib/rpc/dynP.h create mode 100644 mechglue/src/lib/rpc/dyntest.c create mode 100644 mechglue/src/lib/rpc/get_myaddress.c create mode 100644 mechglue/src/lib/rpc/getrpcent.c create mode 100644 mechglue/src/lib/rpc/getrpcport.c create mode 100644 mechglue/src/lib/rpc/libgssrpc.exports create mode 100644 mechglue/src/lib/rpc/netdb.h create mode 100644 mechglue/src/lib/rpc/pmap_clnt.c create mode 100644 mechglue/src/lib/rpc/pmap_clnt.h create mode 100644 mechglue/src/lib/rpc/pmap_getmaps.c create mode 100644 mechglue/src/lib/rpc/pmap_getport.c create mode 100644 mechglue/src/lib/rpc/pmap_prot.c create mode 100644 mechglue/src/lib/rpc/pmap_prot.h create mode 100644 mechglue/src/lib/rpc/pmap_prot2.c create mode 100644 mechglue/src/lib/rpc/pmap_rmt.c create mode 100644 mechglue/src/lib/rpc/pmap_rmt.h create mode 100644 mechglue/src/lib/rpc/rename.h create mode 100644 mechglue/src/lib/rpc/rpc.h create mode 100644 mechglue/src/lib/rpc/rpc_callmsg.c create mode 100644 mechglue/src/lib/rpc/rpc_commondata.c create mode 100644 mechglue/src/lib/rpc/rpc_dtablesize.c create mode 100644 mechglue/src/lib/rpc/rpc_msg.h create mode 100644 mechglue/src/lib/rpc/rpc_prot.c create mode 100644 mechglue/src/lib/rpc/svc.c create mode 100644 mechglue/src/lib/rpc/svc.h create mode 100644 mechglue/src/lib/rpc/svc_auth.c create mode 100644 mechglue/src/lib/rpc/svc_auth.h create mode 100644 mechglue/src/lib/rpc/svc_auth_gss.c create mode 100644 mechglue/src/lib/rpc/svc_auth_gssapi.c create mode 100644 mechglue/src/lib/rpc/svc_auth_none.c create mode 100644 mechglue/src/lib/rpc/svc_auth_unix.c create mode 100644 mechglue/src/lib/rpc/svc_raw.c create mode 100644 mechglue/src/lib/rpc/svc_run.c create mode 100644 mechglue/src/lib/rpc/svc_simple.c create mode 100644 mechglue/src/lib/rpc/svc_tcp.c create mode 100644 mechglue/src/lib/rpc/svc_udp.c create mode 100644 mechglue/src/lib/rpc/types.hin create mode 100644 mechglue/src/lib/rpc/unit-test/ChangeLog create mode 100644 mechglue/src/lib/rpc/unit-test/Makefile.in create mode 100644 mechglue/src/lib/rpc/unit-test/client.c create mode 100644 mechglue/src/lib/rpc/unit-test/config/unix.exp create mode 100644 mechglue/src/lib/rpc/unit-test/configure.in create mode 100644 mechglue/src/lib/rpc/unit-test/lib/helpers.exp create mode 100644 mechglue/src/lib/rpc/unit-test/rpc_test.0/expire.exp create mode 100644 mechglue/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp create mode 100644 mechglue/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp create mode 100644 mechglue/src/lib/rpc/unit-test/rpc_test.h create mode 100644 mechglue/src/lib/rpc/unit-test/rpc_test.x create mode 100644 mechglue/src/lib/rpc/unit-test/rpc_test_clnt.c create mode 100755 mechglue/src/lib/rpc/unit-test/rpc_test_setup.sh create mode 100644 mechglue/src/lib/rpc/unit-test/rpc_test_svc.c create mode 100644 mechglue/src/lib/rpc/unit-test/server.c create mode 100644 mechglue/src/lib/rpc/xdr.c create mode 100644 mechglue/src/lib/rpc/xdr.h create mode 100644 mechglue/src/lib/rpc/xdr_alloc.c create mode 100644 mechglue/src/lib/rpc/xdr_array.c create mode 100644 mechglue/src/lib/rpc/xdr_float.c create mode 100644 mechglue/src/lib/rpc/xdr_mem.c create mode 100644 mechglue/src/lib/rpc/xdr_rec.c create mode 100644 mechglue/src/lib/rpc/xdr_reference.c create mode 100644 mechglue/src/lib/rpc/xdr_stdio.c create mode 100644 mechglue/src/lib/win_glue.c create mode 100644 mechglue/src/lib/xpprof32.def create mode 100644 mechglue/src/patchlevel.h create mode 100644 mechglue/src/plugins/kdb/db2/ChangeLog create mode 100644 mechglue/src/plugins/kdb/db2/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/adb_openclose.c create mode 100644 mechglue/src/plugins/kdb/db2/adb_policy.c create mode 100644 mechglue/src/plugins/kdb/db2/configure.in create mode 100644 mechglue/src/plugins/kdb/db2/db2.exports create mode 100644 mechglue/src/plugins/kdb/db2/db2_exp.c create mode 100644 mechglue/src/plugins/kdb/db2/kdb_compat.h create mode 100644 mechglue/src/plugins/kdb/db2/kdb_db2.c create mode 100644 mechglue/src/plugins/kdb/db2/kdb_db2.h create mode 100644 mechglue/src/plugins/kdb/db2/kdb_xdr.c create mode 100644 mechglue/src/plugins/kdb/db2/kdb_xdr.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/CHANGELOG.db2 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/ChangeLog create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/Makefile.inc create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/README create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/README.NOT.SLEEPYCAT.DB create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/README.db2 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/Makefile.inc create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_close.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_conv.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_debug.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_delete.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_get.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_open.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_overflow.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_page.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_put.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_search.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_seq.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_split.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/bt_utils.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/btree.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/btree/extern.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/clib/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/clib/memmove.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/clib/mkstemp.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/clib/strerror.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/configure.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/db/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/db/Makefile.inc create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/db/db.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/docs/btree.3.ps create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/docs/dbopen.3.ps create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/docs/hash.3.ps create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/docs/hash.usenix.ps create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/docs/libtp.usenix.ps create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/docs/mpool.3.ps create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/docs/recno.3.ps create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/Makefile.inc create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/dbm.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/extern.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hash.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hash.c.patch create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hash.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hash_debug.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hash_func.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hash_log2.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hash_page.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/hsearch.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/page.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/page.h.patch create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/hash/search.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/include/ChangeLog create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/include/db-config.h.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/include/db-dbm.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/include/db-int.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/include/db-ndbm.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/include/db-queue.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/include/db.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/libdb.exports create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/Makefile.inc create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db.man.ps create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db_btree.3 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db_hash.3 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db_lock.3 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db_log.3 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db_mpool.3 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db_open.3 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db_recno.3 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/db_txn.3 create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/man/spell.ok create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/mpool/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/mpool/Makefile.inc create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/mpool/README create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/mpool/mpool.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/mpool/mpool.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/Makefile.inc create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/extern.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/rec_close.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/rec_delete.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/rec_get.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/rec_open.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/rec_put.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/rec_search.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/rec_seq.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/rec_utils.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/recno/recno.h create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/ChangeLog create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/Makefile.in create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/README create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/data create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/mbox create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/t.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/btree.tests/ChangeLog create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/dbtest.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/dictionary create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/Makefile create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/driver2.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/makedb.sh create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tcreat3.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tdel.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/testit create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/thash4.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tread2.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tseq.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tverify.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/README create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/bigtest.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/passtest.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/passwd/genpass.c create mode 100644 mechglue/src/plugins/kdb/db2/libdb2/test/run.test create mode 100644 mechglue/src/plugins/kdb/db2/pol_xdr.c create mode 100644 mechglue/src/plugins/kdb/db2/policy_db.h create mode 100644 mechglue/src/prototype/.Sanitize create mode 100644 mechglue/src/prototype/ChangeLog create mode 100644 mechglue/src/prototype/getopt.c create mode 100644 mechglue/src/prototype/prototype.c create mode 100644 mechglue/src/prototype/prototype.h create mode 100644 mechglue/src/slave/.Sanitize create mode 100644 mechglue/src/slave/ChangeLog create mode 100644 mechglue/src/slave/Makefile.in create mode 100644 mechglue/src/slave/kprop.M create mode 100644 mechglue/src/slave/kprop.c create mode 100644 mechglue/src/slave/kprop.h create mode 100644 mechglue/src/slave/kpropd.M create mode 100644 mechglue/src/slave/kpropd.c create mode 100644 mechglue/src/slave/kslave_update create mode 100644 mechglue/src/t_krbconf create mode 100644 mechglue/src/tests/.Sanitize create mode 100644 mechglue/src/tests/ChangeLog create mode 100644 mechglue/src/tests/Makefile.in create mode 100644 mechglue/src/tests/asn.1/.Sanitize create mode 100644 mechglue/src/tests/asn.1/ChangeLog create mode 100644 mechglue/src/tests/asn.1/Makefile.in create mode 100644 mechglue/src/tests/asn.1/README create mode 100644 mechglue/src/tests/asn.1/debug.h create mode 100644 mechglue/src/tests/asn.1/krb5_decode_test.c create mode 100644 mechglue/src/tests/asn.1/krb5_encode_test.c create mode 100644 mechglue/src/tests/asn.1/ktest.c create mode 100644 mechglue/src/tests/asn.1/ktest.h create mode 100644 mechglue/src/tests/asn.1/ktest_equal.c create mode 100644 mechglue/src/tests/asn.1/ktest_equal.h create mode 100644 mechglue/src/tests/asn.1/reference_encode.out create mode 100644 mechglue/src/tests/asn.1/trval.c create mode 100644 mechglue/src/tests/asn.1/trval_reference.out create mode 100644 mechglue/src/tests/asn.1/utility.c create mode 100644 mechglue/src/tests/asn.1/utility.h create mode 100644 mechglue/src/tests/configure.in create mode 100644 mechglue/src/tests/create/.Sanitize create mode 100644 mechglue/src/tests/create/ChangeLog create mode 100644 mechglue/src/tests/create/Makefile.in create mode 100644 mechglue/src/tests/create/kdb5_mkdums.M create mode 100644 mechglue/src/tests/create/kdb5_mkdums.c create mode 100644 mechglue/src/tests/dejagnu/.Sanitize create mode 100644 mechglue/src/tests/dejagnu/ChangeLog create mode 100644 mechglue/src/tests/dejagnu/Makefile.in create mode 100644 mechglue/src/tests/dejagnu/config/.Sanitize create mode 100644 mechglue/src/tests/dejagnu/config/ChangeLog create mode 100644 mechglue/src/tests/dejagnu/config/default.exp create mode 100644 mechglue/src/tests/dejagnu/krb-root/.Sanitize create mode 100644 mechglue/src/tests/dejagnu/krb-root/ChangeLog create mode 100644 mechglue/src/tests/dejagnu/krb-root/rlogin.exp create mode 100644 mechglue/src/tests/dejagnu/krb-root/telnet.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/.Sanitize create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/ChangeLog create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/gssapi.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/gssftp.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/kadmin.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/pwhist.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/rcp.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/rsh.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/sample.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/standalone.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/v4gssftp.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/v4krb524d.exp create mode 100644 mechglue/src/tests/dejagnu/krb-standalone/v4standalone.exp create mode 100644 mechglue/src/tests/dejagnu/t_inetd.c create mode 100644 mechglue/src/tests/dump.c create mode 100644 mechglue/src/tests/gss-threads/ChangeLog create mode 100644 mechglue/src/tests/gss-threads/Makefile.in create mode 100644 mechglue/src/tests/gss-threads/README create mode 100644 mechglue/src/tests/gss-threads/gss-client.c create mode 100644 mechglue/src/tests/gss-threads/gss-misc.c create mode 100644 mechglue/src/tests/gss-threads/gss-misc.h create mode 100644 mechglue/src/tests/gss-threads/gss-server.c create mode 100644 mechglue/src/tests/gssapi/.Sanitize create mode 100644 mechglue/src/tests/gssapi/ChangeLog create mode 100644 mechglue/src/tests/gssapi/Makefile.in create mode 100644 mechglue/src/tests/gssapi/t_imp_name.c create mode 100644 mechglue/src/tests/hammer/.Sanitize create mode 100644 mechglue/src/tests/hammer/ChangeLog create mode 100644 mechglue/src/tests/hammer/Makefile.in create mode 100644 mechglue/src/tests/hammer/kdc5_hammer.c create mode 100644 mechglue/src/tests/hammer/pp.c create mode 100644 mechglue/src/tests/misc/.Sanitize create mode 100644 mechglue/src/tests/misc/ChangeLog create mode 100644 mechglue/src/tests/misc/Makefile.in create mode 100644 mechglue/src/tests/misc/test_getpw.c create mode 100644 mechglue/src/tests/misc/test_getsockname.c create mode 100644 mechglue/src/tests/misc/test_nfold.c create mode 100644 mechglue/src/tests/resolve/.Sanitize create mode 100644 mechglue/src/tests/resolve/ChangeLog create mode 100644 mechglue/src/tests/resolve/Makefile.in create mode 100644 mechglue/src/tests/resolve/addrinfo-test.c create mode 100644 mechglue/src/tests/resolve/fake-addrinfo-test.c create mode 100644 mechglue/src/tests/resolve/resolve.c create mode 100644 mechglue/src/tests/shlib/ChangeLog create mode 100644 mechglue/src/tests/shlib/Makefile.in create mode 100644 mechglue/src/tests/shlib/t_loader.c create mode 100644 mechglue/src/tests/test1.c create mode 100644 mechglue/src/tests/threads/ChangeLog create mode 100644 mechglue/src/tests/threads/Makefile.in create mode 100644 mechglue/src/tests/threads/prof1.c create mode 100644 mechglue/src/tests/threads/t_rcache.c create mode 100644 mechglue/src/tests/verify/.Sanitize create mode 100644 mechglue/src/tests/verify/ChangeLog create mode 100644 mechglue/src/tests/verify/Makefile.in create mode 100644 mechglue/src/tests/verify/kdb5_verify.c create mode 100644 mechglue/src/tests/verify/pkey.c create mode 100644 mechglue/src/util/.Sanitize create mode 100644 mechglue/src/util/ChangeLog create mode 100644 mechglue/src/util/Makefile.in create mode 100755 mechglue/src/util/Sanitize create mode 100644 mechglue/src/util/ac_check_krb5.m4 create mode 100644 mechglue/src/util/def-check.pl create mode 100644 mechglue/src/util/depfix.pl create mode 100644 mechglue/src/util/et/.Sanitize create mode 100644 mechglue/src/util/et/ChangeLog create mode 100644 mechglue/src/util/et/ISSUES create mode 100644 mechglue/src/util/et/Makefile.in create mode 100644 mechglue/src/util/et/com_err.3 create mode 100644 mechglue/src/util/et/com_err.c create mode 100644 mechglue/src/util/et/com_err.h create mode 100644 mechglue/src/util/et/com_err.texinfo create mode 100644 mechglue/src/util/et/compile_et.1 create mode 100644 mechglue/src/util/et/compile_et.c create mode 100755 mechglue/src/util/et/compile_et.sh create mode 100644 mechglue/src/util/et/compiler.h create mode 100755 mechglue/src/util/et/config_script create mode 100644 mechglue/src/util/et/configure.in create mode 100644 mechglue/src/util/et/error_message.c create mode 100644 mechglue/src/util/et/error_table.h create mode 100644 mechglue/src/util/et/error_table.y create mode 100644 mechglue/src/util/et/et.exp create mode 100644 mechglue/src/util/et/et.pbexp create mode 100644 mechglue/src/util/et/et1.et create mode 100644 mechglue/src/util/et/et2.et create mode 100644 mechglue/src/util/et/et_c.awk create mode 100644 mechglue/src/util/et/et_c.pl create mode 100644 mechglue/src/util/et/et_h.awk create mode 100644 mechglue/src/util/et/et_h.pl create mode 100644 mechglue/src/util/et/et_lex.lex.l create mode 100644 mechglue/src/util/et/et_name.c create mode 100644 mechglue/src/util/et/init_et.c create mode 100644 mechglue/src/util/et/internal.h create mode 100644 mechglue/src/util/et/libcom_err.exports create mode 100644 mechglue/src/util/et/mit-sipb-copyright.h create mode 100644 mechglue/src/util/et/t_com_err.c create mode 100644 mechglue/src/util/et/test1.et create mode 100644 mechglue/src/util/et/test2.et create mode 100644 mechglue/src/util/et/test_et.c create mode 100644 mechglue/src/util/et/texinfo.tex create mode 100644 mechglue/src/util/et/vfprintf.c create mode 100644 mechglue/src/util/exitsleep.c create mode 100755 mechglue/src/util/getsyms create mode 100644 mechglue/src/util/getsyms.sed create mode 100755 mechglue/src/util/kbuild create mode 100644 mechglue/src/util/kfrags/.Sanitize create mode 100644 mechglue/src/util/kfrags/ChangeLog create mode 100644 mechglue/src/util/kfrags/athena.conf create mode 100644 mechglue/src/util/kfrags/base.conf create mode 100644 mechglue/src/util/kfrags/cns.conf create mode 100644 mechglue/src/util/kfrags/gcc.conf create mode 100644 mechglue/src/util/kfrags/ranlib.conf create mode 100644 mechglue/src/util/kfrags/shared.conf create mode 100644 mechglue/src/util/kfrags/sunpro.conf create mode 100644 mechglue/src/util/kfrags/svr4.conf create mode 100644 mechglue/src/util/kfrags/ucb.conf create mode 100755 mechglue/src/util/lndir create mode 100644 mechglue/src/util/makedepend/.Sanitize create mode 100644 mechglue/src/util/makedepend/ChangeLog create mode 100644 mechglue/src/util/makedepend/cpp.ed create mode 100644 mechglue/src/util/makedepend/cppsetup.c create mode 100644 mechglue/src/util/makedepend/def.h create mode 100644 mechglue/src/util/makedepend/ifparser.c create mode 100644 mechglue/src/util/makedepend/ifparser.h create mode 100644 mechglue/src/util/makedepend/include.c create mode 100644 mechglue/src/util/makedepend/main.c create mode 100644 mechglue/src/util/makedepend/mkdepend.man create mode 100644 mechglue/src/util/makedepend/parse.c create mode 100644 mechglue/src/util/makedepend/pr.c create mode 100755 mechglue/src/util/mkrel create mode 100644 mechglue/src/util/profile/.Sanitize create mode 100644 mechglue/src/util/profile/ChangeLog create mode 100644 mechglue/src/util/profile/Makefile.in create mode 100644 mechglue/src/util/profile/argv_parse.c create mode 100644 mechglue/src/util/profile/argv_parse.h create mode 100644 mechglue/src/util/profile/configure.in create mode 100644 mechglue/src/util/profile/dosshell.ini create mode 100644 mechglue/src/util/profile/krb5.conf create mode 100644 mechglue/src/util/profile/libprofile.exports create mode 100644 mechglue/src/util/profile/prof_FSp_glue.c create mode 100644 mechglue/src/util/profile/prof_err.et create mode 100644 mechglue/src/util/profile/prof_file.c create mode 100644 mechglue/src/util/profile/prof_get.c create mode 100644 mechglue/src/util/profile/prof_init.c create mode 100644 mechglue/src/util/profile/prof_int.h create mode 100644 mechglue/src/util/profile/prof_parse.c create mode 100644 mechglue/src/util/profile/prof_set.c create mode 100644 mechglue/src/util/profile/prof_test1 create mode 100644 mechglue/src/util/profile/prof_tree.c create mode 100644 mechglue/src/util/profile/profile.5 create mode 100644 mechglue/src/util/profile/profile.exp create mode 100644 mechglue/src/util/profile/profile.hin create mode 100644 mechglue/src/util/profile/profile.pbexp create mode 100644 mechglue/src/util/profile/profile.swg create mode 100644 mechglue/src/util/profile/profile_tcl.c create mode 100644 mechglue/src/util/profile/prtest.in create mode 100644 mechglue/src/util/profile/prtest.script create mode 100644 mechglue/src/util/profile/test.ini create mode 100644 mechglue/src/util/profile/test_parse.c create mode 100644 mechglue/src/util/profile/test_profile.c create mode 100644 mechglue/src/util/pty/.Sanitize create mode 100644 mechglue/src/util/pty/ChangeLog create mode 100644 mechglue/src/util/pty/Makefile.in create mode 100644 mechglue/src/util/pty/README create mode 100644 mechglue/src/util/pty/cleanup.c create mode 100644 mechglue/src/util/pty/configure.in create mode 100644 mechglue/src/util/pty/dump-utmp.c create mode 100644 mechglue/src/util/pty/getpty.c create mode 100644 mechglue/src/util/pty/init.c create mode 100644 mechglue/src/util/pty/init_slave.c create mode 100644 mechglue/src/util/pty/libpty.h create mode 100644 mechglue/src/util/pty/logwtmp.c create mode 100644 mechglue/src/util/pty/open_ctty.c create mode 100644 mechglue/src/util/pty/open_slave.c create mode 100644 mechglue/src/util/pty/pty-int.h create mode 100644 mechglue/src/util/pty/pty_err.et create mode 100644 mechglue/src/util/pty/pty_paranoia.c create mode 100644 mechglue/src/util/pty/sane_hostname.c create mode 100644 mechglue/src/util/pty/update_utmp.c create mode 100644 mechglue/src/util/pty/update_wtmp.c create mode 100644 mechglue/src/util/pty/vhangup.c create mode 100644 mechglue/src/util/pty/void_assoc.c create mode 100755 mechglue/src/util/reconf create mode 100644 mechglue/src/util/send-pr/COPYING create mode 100644 mechglue/src/util/send-pr/ChangeLog create mode 100644 mechglue/src/util/send-pr/INSTALL create mode 100644 mechglue/src/util/send-pr/MANIFEST create mode 100644 mechglue/src/util/send-pr/Makefile.in create mode 100644 mechglue/src/util/send-pr/README create mode 100644 mechglue/src/util/send-pr/categories create mode 100644 mechglue/src/util/send-pr/install-sid.sh create mode 100644 mechglue/src/util/send-pr/send-pr.1 create mode 100644 mechglue/src/util/send-pr/send-pr.sh create mode 100644 mechglue/src/util/ss/.Sanitize create mode 100644 mechglue/src/util/ss/ChangeLog create mode 100644 mechglue/src/util/ss/Makefile.in create mode 100644 mechglue/src/util/ss/cmd_tbl.lex.l create mode 100755 mechglue/src/util/ss/config_script create mode 100644 mechglue/src/util/ss/configure.in create mode 100644 mechglue/src/util/ss/copyright.h create mode 100644 mechglue/src/util/ss/ct.y create mode 100644 mechglue/src/util/ss/ct_c_awk.in create mode 100644 mechglue/src/util/ss/ct_c_sed.in create mode 100644 mechglue/src/util/ss/data.c create mode 100644 mechglue/src/util/ss/error.c create mode 100644 mechglue/src/util/ss/execute_cmd.c create mode 100644 mechglue/src/util/ss/help.c create mode 100644 mechglue/src/util/ss/invocation.c create mode 100644 mechglue/src/util/ss/list_rqs.c create mode 100644 mechglue/src/util/ss/listen.c create mode 100644 mechglue/src/util/ss/mit-sipb-copyright.h create mode 100644 mechglue/src/util/ss/mk_cmds.c create mode 100755 mechglue/src/util/ss/mk_cmds.sh create mode 100644 mechglue/src/util/ss/options.c create mode 100644 mechglue/src/util/ss/pager.c create mode 100644 mechglue/src/util/ss/parse.c create mode 100644 mechglue/src/util/ss/prompt.c create mode 100644 mechglue/src/util/ss/request_tbl.c create mode 100644 mechglue/src/util/ss/requests.c create mode 100644 mechglue/src/util/ss/ss.h create mode 100644 mechglue/src/util/ss/ss_err.et create mode 100644 mechglue/src/util/ss/ss_internal.h create mode 100644 mechglue/src/util/ss/std_rqs.ct create mode 100644 mechglue/src/util/ss/test_ss.c create mode 100644 mechglue/src/util/ss/utils.c create mode 100644 mechglue/src/util/support/ChangeLog create mode 100644 mechglue/src/util/support/Makefile.in create mode 100644 mechglue/src/util/support/cache-addrinfo.h create mode 100644 mechglue/src/util/support/fake-addrinfo.c create mode 100644 mechglue/src/util/support/init-addrinfo.c create mode 100644 mechglue/src/util/support/libkrb5support.exports create mode 100644 mechglue/src/util/support/threads.c create mode 100644 mechglue/src/util/windows/ChangeLog create mode 100644 mechglue/src/util/windows/Makefile.in create mode 100644 mechglue/src/util/windows/getopt.c create mode 100644 mechglue/src/util/windows/getopt.h create mode 100644 mechglue/src/util/windows/getopt_long.c create mode 100644 mechglue/src/util/windows/libecho.c create mode 100644 mechglue/src/wconfig.c create mode 100644 mechglue/src/windows/.Sanitize create mode 100644 mechglue/src/windows/ChangeLog create mode 100644 mechglue/src/windows/Makefile.in create mode 100644 mechglue/src/windows/README create mode 100644 mechglue/src/windows/ccapi/ChangeLog create mode 100644 mechglue/src/windows/ccapi/server/ChangeLog create mode 100644 mechglue/src/windows/cns/.Sanitize create mode 100644 mechglue/src/windows/cns/ChangeLog create mode 100644 mechglue/src/windows/cns/Makefile.in create mode 100644 mechglue/src/windows/cns/clock00.ico create mode 100644 mechglue/src/windows/cns/clock05.ico create mode 100644 mechglue/src/windows/cns/clock10.ico create mode 100644 mechglue/src/windows/cns/clock15.ico create mode 100644 mechglue/src/windows/cns/clock20.ico create mode 100644 mechglue/src/windows/cns/clock25.ico create mode 100644 mechglue/src/windows/cns/clock30.ico create mode 100644 mechglue/src/windows/cns/clock35.ico create mode 100644 mechglue/src/windows/cns/clock40.ico create mode 100644 mechglue/src/windows/cns/clock45.ico create mode 100644 mechglue/src/windows/cns/clock50.ico create mode 100644 mechglue/src/windows/cns/clock55.ico create mode 100644 mechglue/src/windows/cns/clock60.ico create mode 100644 mechglue/src/windows/cns/clockexp.ico create mode 100644 mechglue/src/windows/cns/clocktkt.ico create mode 100644 mechglue/src/windows/cns/cns-help.doc create mode 100644 mechglue/src/windows/cns/cns-help.hlp create mode 100644 mechglue/src/windows/cns/cns-help.hpj create mode 100644 mechglue/src/windows/cns/cns.c create mode 100644 mechglue/src/windows/cns/cns.h create mode 100644 mechglue/src/windows/cns/cns.ico create mode 100644 mechglue/src/windows/cns/cns_reg.c create mode 100644 mechglue/src/windows/cns/cns_reg.h create mode 100644 mechglue/src/windows/cns/cnsres4.rc create mode 100644 mechglue/src/windows/cns/cnsres5.rc create mode 100644 mechglue/src/windows/cns/debug.c create mode 100644 mechglue/src/windows/cns/heap.c create mode 100644 mechglue/src/windows/cns/kerbnet.doc create mode 100644 mechglue/src/windows/cns/kerbnet.hlp create mode 100644 mechglue/src/windows/cns/kerbnet.hpj create mode 100644 mechglue/src/windows/cns/kpasswd.c create mode 100644 mechglue/src/windows/cns/krb5.def create mode 100644 mechglue/src/windows/cns/krbini.h create mode 100644 mechglue/src/windows/cns/options.c create mode 100644 mechglue/src/windows/cns/password.c create mode 100644 mechglue/src/windows/cns/tktlist.c create mode 100644 mechglue/src/windows/cns/tktlist.h create mode 100644 mechglue/src/windows/gina/ChangeLog create mode 100644 mechglue/src/windows/gina/Makefile.in create mode 100644 mechglue/src/windows/gina/gina.def create mode 100644 mechglue/src/windows/gina/ginastub.c create mode 100644 mechglue/src/windows/gina/ginastub.h create mode 100644 mechglue/src/windows/gss/.Sanitize create mode 100644 mechglue/src/windows/gss/ChangeLog create mode 100644 mechglue/src/windows/gss/Makefile.in create mode 100644 mechglue/src/windows/gss/gss-client.c create mode 100644 mechglue/src/windows/gss/gss-misc.c create mode 100644 mechglue/src/windows/gss/gss-misc.h create mode 100644 mechglue/src/windows/gss/gss.c create mode 100644 mechglue/src/windows/gss/gss.def create mode 100644 mechglue/src/windows/gss/gss.h create mode 100644 mechglue/src/windows/gss/gss.ico create mode 100644 mechglue/src/windows/gss/gss.rc create mode 100644 mechglue/src/windows/gss/resource.h create mode 100644 mechglue/src/windows/gss/ver_serv.txt create mode 100644 mechglue/src/windows/identity/ChangeLog create mode 100644 mechglue/src/windows/identity/Makefile create mode 100644 mechglue/src/windows/identity/apiversion.txt create mode 100644 mechglue/src/windows/identity/config/Makefile create mode 100644 mechglue/src/windows/identity/config/Makefile.w32 create mode 100644 mechglue/src/windows/identity/config/ccsv.pl create mode 100644 mechglue/src/windows/identity/config/csvschema.cfg create mode 100644 mechglue/src/windows/identity/config/netidmgr_intver.h.in create mode 100644 mechglue/src/windows/identity/config/netidmgr_version.h.in create mode 100644 mechglue/src/windows/identity/doc/Makefile create mode 100644 mechglue/src/windows/identity/doc/cred_aquisition.h create mode 100644 mechglue/src/windows/identity/doc/cred_data_types.h create mode 100644 mechglue/src/windows/identity/doc/cred_main.h create mode 100644 mechglue/src/windows/identity/doc/cred_msgs.h create mode 100644 mechglue/src/windows/identity/doc/cred_prop_pages.h create mode 100644 mechglue/src/windows/identity/doc/doxyfile.cfg create mode 100644 mechglue/src/windows/identity/doc/footer.html create mode 100644 mechglue/src/windows/identity/doc/header.html create mode 100644 mechglue/src/windows/identity/doc/images/credview-select-outline.jpg create mode 100644 mechglue/src/windows/identity/doc/images/khimaira_logo.png create mode 100644 mechglue/src/windows/identity/doc/images/khimaira_logo_small.png create mode 100644 mechglue/src/windows/identity/doc/main_page.h create mode 100755 mechglue/src/windows/identity/doc/netidmgr.doc create mode 100755 mechglue/src/windows/identity/doc/netidmgr.pdf create mode 100644 mechglue/src/windows/identity/doc/plugin_framework.h create mode 100644 mechglue/src/windows/identity/doc/plugin_locale.h create mode 100644 mechglue/src/windows/identity/doc/plugin_main.h create mode 100644 mechglue/src/windows/identity/doc/plugin_structure.h create mode 100644 mechglue/src/windows/identity/doc/stylesheet.css create mode 100644 mechglue/src/windows/identity/doc/ui_actions.h create mode 100644 mechglue/src/windows/identity/doc/ui_context.h create mode 100644 mechglue/src/windows/identity/doc/ui_main.h create mode 100644 mechglue/src/windows/identity/doc/ui_menus.h create mode 100644 mechglue/src/windows/identity/help/Index.hhk create mode 100644 mechglue/src/windows/identity/help/Makefile create mode 100644 mechglue/src/windows/identity/help/html/about_netidmgr.htm create mode 100644 mechglue/src/windows/identity/help/html/act_chpw.htm create mode 100644 mechglue/src/windows/identity/help/html/act_destroy_creds.htm create mode 100644 mechglue/src/windows/identity/help/html/act_import_creds.htm create mode 100644 mechglue/src/windows/identity/help/html/act_new_creds.htm create mode 100644 mechglue/src/windows/identity/help/html/act_renew_creds.htm create mode 100644 mechglue/src/windows/identity/help/html/act_set_default.htm create mode 100644 mechglue/src/windows/identity/help/html/bugs.htm create mode 100644 mechglue/src/windows/identity/help/html/concept_cred_pro.htm create mode 100644 mechglue/src/windows/identity/help/html/concept_ident_pro.htm create mode 100644 mechglue/src/windows/identity/help/html/concept_identity.htm create mode 100644 mechglue/src/windows/identity/help/html/concepts.htm create mode 100644 mechglue/src/windows/identity/help/html/copyright.htm create mode 100644 mechglue/src/windows/identity/help/html/howdoi.htm create mode 100644 mechglue/src/windows/identity/help/html/images/logo.jpg create mode 100644 mechglue/src/windows/identity/help/html/images/logo_shade.jpg create mode 100644 mechglue/src/windows/identity/help/html/images/screen_app_icon.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_main_wnd.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_menu_bar.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_menu_credential.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_menu_file.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_menu_help.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_menu_options.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_menu_view.bmp create mode 100755 mechglue/src/windows/identity/help/html/images/screen_new_creds.bmp create mode 100755 mechglue/src/windows/identity/help/html/images/screen_new_creds_err01.bmp create mode 100755 mechglue/src/windows/identity/help/html/images/screen_new_creds_exp.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_tb_standard.bmp create mode 100644 mechglue/src/windows/identity/help/html/images/screen_tray_icon.bmp create mode 100644 mechglue/src/windows/identity/help/html/menu_all.htm create mode 100644 mechglue/src/windows/identity/help/html/menu_credential.htm create mode 100644 mechglue/src/windows/identity/help/html/menu_file.htm create mode 100644 mechglue/src/windows/identity/help/html/menu_help.htm create mode 100644 mechglue/src/windows/identity/help/html/menu_options.htm create mode 100644 mechglue/src/windows/identity/help/html/menu_view.htm create mode 100644 mechglue/src/windows/identity/help/html/nidmgr.css create mode 100644 mechglue/src/windows/identity/help/html/tb_standard.htm create mode 100644 mechglue/src/windows/identity/help/html/template.htm create mode 100644 mechglue/src/windows/identity/help/html/use_start.htm create mode 100644 mechglue/src/windows/identity/help/html/using.htm create mode 100644 mechglue/src/windows/identity/help/html/welcome.htm create mode 100644 mechglue/src/windows/identity/help/html/wnd_main.htm create mode 100644 mechglue/src/windows/identity/help/khhelp.h create mode 100644 mechglue/src/windows/identity/help/netidmgr.hhp create mode 100644 mechglue/src/windows/identity/help/popups.txt create mode 100644 mechglue/src/windows/identity/help/popups_newcreds.txt create mode 100644 mechglue/src/windows/identity/help/toc.hhc create mode 100644 mechglue/src/windows/identity/include/Makefile create mode 100644 mechglue/src/windows/identity/include/khdefs.h create mode 100644 mechglue/src/windows/identity/include/kherror.h create mode 100644 mechglue/src/windows/identity/include/khlist.h create mode 100644 mechglue/src/windows/identity/include/khmsgtypes.h create mode 100644 mechglue/src/windows/identity/include/netidmgr.h create mode 100644 mechglue/src/windows/identity/kconfig/Makefile create mode 100644 mechglue/src/windows/identity/kconfig/api.c create mode 100644 mechglue/src/windows/identity/kconfig/kconfig.h create mode 100644 mechglue/src/windows/identity/kconfig/kconfiginternal.h create mode 100644 mechglue/src/windows/identity/kconfig/kconfigmain.c create mode 100644 mechglue/src/windows/identity/kconfig/registry.c create mode 100644 mechglue/src/windows/identity/kconfig/test/utiltest.c create mode 100644 mechglue/src/windows/identity/kcreddb/Makefile create mode 100644 mechglue/src/windows/identity/kcreddb/attrib.c create mode 100644 mechglue/src/windows/identity/kcreddb/attrib.h create mode 100644 mechglue/src/windows/identity/kcreddb/buf.c create mode 100644 mechglue/src/windows/identity/kcreddb/buf.h create mode 100644 mechglue/src/windows/identity/kcreddb/credential.c create mode 100644 mechglue/src/windows/identity/kcreddb/credential.h create mode 100644 mechglue/src/windows/identity/kcreddb/credset.c create mode 100644 mechglue/src/windows/identity/kcreddb/credset.h create mode 100644 mechglue/src/windows/identity/kcreddb/credtype.c create mode 100644 mechglue/src/windows/identity/kcreddb/credtype.h create mode 100644 mechglue/src/windows/identity/kcreddb/identity.c create mode 100644 mechglue/src/windows/identity/kcreddb/identity.h create mode 100644 mechglue/src/windows/identity/kcreddb/init.c create mode 100644 mechglue/src/windows/identity/kcreddb/kcdbconfig.csv create mode 100644 mechglue/src/windows/identity/kcreddb/kcreddb.h create mode 100644 mechglue/src/windows/identity/kcreddb/kcreddbinternal.h create mode 100644 mechglue/src/windows/identity/kcreddb/kcreddbmain.c create mode 100644 mechglue/src/windows/identity/kcreddb/lang/en_us/kcredres.rc create mode 100644 mechglue/src/windows/identity/kcreddb/langres.h create mode 100644 mechglue/src/windows/identity/kcreddb/resource.h create mode 100644 mechglue/src/windows/identity/kcreddb/type.c create mode 100644 mechglue/src/windows/identity/kcreddb/type.h create mode 100644 mechglue/src/windows/identity/kherr/Makefile create mode 100644 mechglue/src/windows/identity/kherr/kherr.c create mode 100644 mechglue/src/windows/identity/kherr/kherr.h create mode 100644 mechglue/src/windows/identity/kherr/kherrinternal.h create mode 100644 mechglue/src/windows/identity/kherr/kherrmain.c create mode 100644 mechglue/src/windows/identity/kmm/Makefile create mode 100644 mechglue/src/windows/identity/kmm/kmm.c create mode 100644 mechglue/src/windows/identity/kmm/kmm.h create mode 100644 mechglue/src/windows/identity/kmm/kmm_module.c create mode 100644 mechglue/src/windows/identity/kmm/kmm_plugin.c create mode 100644 mechglue/src/windows/identity/kmm/kmm_reg.c create mode 100644 mechglue/src/windows/identity/kmm/kmm_registrar.c create mode 100644 mechglue/src/windows/identity/kmm/kmmconfig.csv create mode 100644 mechglue/src/windows/identity/kmm/kmminternal.h create mode 100644 mechglue/src/windows/identity/kmm/kmmmain.c create mode 100644 mechglue/src/windows/identity/kmm/kplugin.h create mode 100644 mechglue/src/windows/identity/kmm/lang/kmm_msgs.mc create mode 100644 mechglue/src/windows/identity/kmq/Makefile create mode 100644 mechglue/src/windows/identity/kmq/consumer.c create mode 100644 mechglue/src/windows/identity/kmq/init.c create mode 100644 mechglue/src/windows/identity/kmq/kmq.h create mode 100644 mechglue/src/windows/identity/kmq/kmqconfig.csv create mode 100644 mechglue/src/windows/identity/kmq/kmqinternal.h create mode 100644 mechglue/src/windows/identity/kmq/kmqmain.c create mode 100644 mechglue/src/windows/identity/kmq/msgtype.c create mode 100644 mechglue/src/windows/identity/kmq/publisher.c create mode 100644 mechglue/src/windows/identity/nidmgrdll/Makefile create mode 100644 mechglue/src/windows/identity/nidmgrdll/dllmain.c create mode 100644 mechglue/src/windows/identity/nidmgrdll/nidmgrdll.rc create mode 100644 mechglue/src/windows/identity/plugins/common/Makefile create mode 100644 mechglue/src/windows/identity/plugins/common/dynimport.c create mode 100644 mechglue/src/windows/identity/plugins/common/dynimport.h create mode 100644 mechglue/src/windows/identity/plugins/common/krb5common.c create mode 100644 mechglue/src/windows/identity/plugins/common/krb5common.h create mode 100644 mechglue/src/windows/identity/plugins/krb4/Makefile create mode 100644 mechglue/src/windows/identity/plugins/krb4/errorfuncs.c create mode 100644 mechglue/src/windows/identity/plugins/krb4/errorfuncs.h create mode 100644 mechglue/src/windows/identity/plugins/krb4/images/plugin.ico create mode 100644 mechglue/src/windows/identity/plugins/krb4/krb4configdlg.c create mode 100644 mechglue/src/windows/identity/plugins/krb4/krb4funcs.c create mode 100644 mechglue/src/windows/identity/plugins/krb4/krb4funcs.h create mode 100644 mechglue/src/windows/identity/plugins/krb4/krb4main.c create mode 100644 mechglue/src/windows/identity/plugins/krb4/krb4newcreds.c create mode 100644 mechglue/src/windows/identity/plugins/krb4/krb4plugin.c create mode 100644 mechglue/src/windows/identity/plugins/krb4/krbconfig.csv create mode 100644 mechglue/src/windows/identity/plugins/krb4/krbcred.h create mode 100644 mechglue/src/windows/identity/plugins/krb4/lang/en_us/langres.rc create mode 100644 mechglue/src/windows/identity/plugins/krb4/langres.h create mode 100644 mechglue/src/windows/identity/plugins/krb4/version.rc create mode 100644 mechglue/src/windows/identity/plugins/krb5/Makefile create mode 100644 mechglue/src/windows/identity/plugins/krb5/datarep.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/datarep.h create mode 100644 mechglue/src/windows/identity/plugins/krb5/errorfuncs.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/errorfuncs.h create mode 100644 mechglue/src/windows/identity/plugins/krb5/images/deleted.ico create mode 100644 mechglue/src/windows/identity/plugins/krb5/images/krb5plugin.ico create mode 100644 mechglue/src/windows/identity/plugins/krb5/images/modified.ico create mode 100644 mechglue/src/windows/identity/plugins/krb5/images/new.ico create mode 100644 mechglue/src/windows/identity/plugins/krb5/images/normal.ico create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5configcc.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5configdlg.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5configid.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5configids.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5funcs.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5funcs.h create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5identpro.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5main.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5newcreds.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5plugin.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5props.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krb5util.c create mode 100644 mechglue/src/windows/identity/plugins/krb5/krbconfig.csv create mode 100644 mechglue/src/windows/identity/plugins/krb5/krbcred.h create mode 100644 mechglue/src/windows/identity/plugins/krb5/lang/en_us/langres.rc create mode 100644 mechglue/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc create mode 100644 mechglue/src/windows/identity/plugins/krb5/langres.h create mode 100644 mechglue/src/windows/identity/plugins/krb5/version.rc create mode 100644 mechglue/src/windows/identity/ui/Makefile create mode 100644 mechglue/src/windows/identity/ui/aboutwnd.c create mode 100644 mechglue/src/windows/identity/ui/aboutwnd.h create mode 100644 mechglue/src/windows/identity/ui/addrchange.c create mode 100644 mechglue/src/windows/identity/ui/addrchange.h create mode 100644 mechglue/src/windows/identity/ui/appglobal.h create mode 100644 mechglue/src/windows/identity/ui/appver.rc create mode 100644 mechglue/src/windows/identity/ui/cfg_general_wnd.c create mode 100644 mechglue/src/windows/identity/ui/cfg_identities_wnd.c create mode 100644 mechglue/src/windows/identity/ui/cfg_notif_wnd.c create mode 100644 mechglue/src/windows/identity/ui/cfg_plugins_wnd.c create mode 100644 mechglue/src/windows/identity/ui/configwnd.c create mode 100644 mechglue/src/windows/identity/ui/configwnd.h create mode 100644 mechglue/src/windows/identity/ui/credfuncs.c create mode 100644 mechglue/src/windows/identity/ui/credfuncs.h create mode 100644 mechglue/src/windows/identity/ui/credwnd.c create mode 100644 mechglue/src/windows/identity/ui/credwnd.h create mode 100644 mechglue/src/windows/identity/ui/htmlwnd.h create mode 100644 mechglue/src/windows/identity/ui/htwnd.c create mode 100644 mechglue/src/windows/identity/ui/htwnd.h create mode 100644 mechglue/src/windows/identity/ui/images/app_notify_error.ico create mode 100644 mechglue/src/windows/identity/ui/images/app_notify_info.ico create mode 100644 mechglue/src/windows/identity/ui/images/app_notify_none.ico create mode 100644 mechglue/src/windows/identity/ui/images/app_notify_warn.ico create mode 100644 mechglue/src/windows/identity/ui/images/app_state_exp.ico create mode 100644 mechglue/src/windows/identity/ui/images/app_state_ok.ico create mode 100644 mechglue/src/windows/identity/ui/images/app_state_warn.ico create mode 100644 mechglue/src/windows/identity/ui/images/cfg_applied.ico create mode 100644 mechglue/src/windows/identity/ui/images/cfg_default.ico create mode 100644 mechglue/src/windows/identity/ui/images/cfg_deleted.ico create mode 100644 mechglue/src/windows/identity/ui/images/cfg_mod.ico create mode 100644 mechglue/src/windows/identity/ui/images/cfg_plugin.ico create mode 100644 mechglue/src/windows/identity/ui/images/chpw-dis-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/chpw-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/chpw-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/chpw.bmp create mode 100644 mechglue/src/windows/identity/ui/images/disabled.ico create mode 100644 mechglue/src/windows/identity/ui/images/enabled.ico create mode 100644 mechglue/src/windows/identity/ui/images/flag-critical.bmp create mode 100644 mechglue/src/windows/identity/ui/images/flag-warning.bmp create mode 100644 mechglue/src/windows/identity/ui/images/flag_expired.bmp create mode 100644 mechglue/src/windows/identity/ui/images/flag_renewable.bmp create mode 100644 mechglue/src/windows/identity/ui/images/help-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/help.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-delete-dis-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-delete-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-delete-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-delete.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-dis-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-new-dis-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-new-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-new-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-new.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-refresh-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-refresh-sm-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-refresh-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-refresh.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id.bmp create mode 100644 mechglue/src/windows/identity/ui/images/id.ico create mode 100644 mechglue/src/windows/identity/ui/images/ident.png create mode 100644 mechglue/src/windows/identity/ui/images/import-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/import-sm-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/import-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/import.bmp create mode 100644 mechglue/src/windows/identity/ui/images/khimaira-cfg.bmp create mode 100644 mechglue/src/windows/identity/ui/images/logo_shade.bmp create mode 100644 mechglue/src/windows/identity/ui/images/main_app.ico create mode 100644 mechglue/src/windows/identity/ui/images/tb-blank-small.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tb-blank.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tb-space.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-delete-dis-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-delete-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-delete-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-delete.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-dis-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-new-dis-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-new-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-new-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-new.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-refresh-dis.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-refresh-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-refresh.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/tk.bmp create mode 100644 mechglue/src/windows/identity/ui/images/vw-refresh-sm.bmp create mode 100644 mechglue/src/windows/identity/ui/images/vw-refresh.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_collapsed.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_collapsed_hi.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_credtype.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_expanded.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_expanded_hi.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_flag.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_stick.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_stick_hi.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_stuck.bmp create mode 100644 mechglue/src/windows/identity/ui/images/wdg_stuck_hi.bmp create mode 100644 mechglue/src/windows/identity/ui/khmapp.h create mode 100644 mechglue/src/windows/identity/ui/lang/en_us/khapp.rc create mode 100644 mechglue/src/windows/identity/ui/main.c create mode 100644 mechglue/src/windows/identity/ui/mainmenu.c create mode 100644 mechglue/src/windows/identity/ui/mainmenu.h create mode 100644 mechglue/src/windows/identity/ui/mainwnd.c create mode 100644 mechglue/src/windows/identity/ui/mainwnd.h create mode 100644 mechglue/src/windows/identity/ui/makeacceldef.pl create mode 100644 mechglue/src/windows/identity/ui/makeactiondef.pl create mode 100644 mechglue/src/windows/identity/ui/netidmgr.exe.manifest.i386 create mode 100644 mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc7 create mode 100644 mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug create mode 100644 mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc8 create mode 100644 mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug create mode 100644 mechglue/src/windows/identity/ui/newcredwnd.c create mode 100644 mechglue/src/windows/identity/ui/newcredwnd.h create mode 100644 mechglue/src/windows/identity/ui/notifier.c create mode 100644 mechglue/src/windows/identity/ui/notifier.h create mode 100644 mechglue/src/windows/identity/ui/passwnd.c create mode 100644 mechglue/src/windows/identity/ui/passwnd.h create mode 100644 mechglue/src/windows/identity/ui/propertywnd.c create mode 100644 mechglue/src/windows/identity/ui/propertywnd.h create mode 100644 mechglue/src/windows/identity/ui/reqdaemon.c create mode 100644 mechglue/src/windows/identity/ui/reqdaemon.h create mode 100644 mechglue/src/windows/identity/ui/resource.h create mode 100644 mechglue/src/windows/identity/ui/statusbar.c create mode 100644 mechglue/src/windows/identity/ui/statusbar.h create mode 100644 mechglue/src/windows/identity/ui/timer.c create mode 100644 mechglue/src/windows/identity/ui/timer.h create mode 100644 mechglue/src/windows/identity/ui/toolbar.c create mode 100644 mechglue/src/windows/identity/ui/toolbar.h create mode 100644 mechglue/src/windows/identity/ui/uiconfig.csv create mode 100644 mechglue/src/windows/identity/uilib/Makefile create mode 100644 mechglue/src/windows/identity/uilib/accel.csv create mode 100644 mechglue/src/windows/identity/uilib/acceldef.cfg create mode 100644 mechglue/src/windows/identity/uilib/action.c create mode 100644 mechglue/src/windows/identity/uilib/actiondef.cfg create mode 100644 mechglue/src/windows/identity/uilib/actions.csv create mode 100644 mechglue/src/windows/identity/uilib/alert.c create mode 100644 mechglue/src/windows/identity/uilib/configui.c create mode 100644 mechglue/src/windows/identity/uilib/configui.h create mode 100644 mechglue/src/windows/identity/uilib/creddlg.c create mode 100644 mechglue/src/windows/identity/uilib/khaction.h create mode 100644 mechglue/src/windows/identity/uilib/khactiondef.h create mode 100644 mechglue/src/windows/identity/uilib/khalerts.h create mode 100644 mechglue/src/windows/identity/uilib/khconfigui.h create mode 100644 mechglue/src/windows/identity/uilib/khhtlink.h create mode 100644 mechglue/src/windows/identity/uilib/khnewcred.h create mode 100644 mechglue/src/windows/identity/uilib/khprops.h create mode 100644 mechglue/src/windows/identity/uilib/khremote.h create mode 100644 mechglue/src/windows/identity/uilib/khrescache.h create mode 100644 mechglue/src/windows/identity/uilib/khtracker.h create mode 100644 mechglue/src/windows/identity/uilib/khuidefs.h create mode 100644 mechglue/src/windows/identity/uilib/propsheet.c create mode 100644 mechglue/src/windows/identity/uilib/propwnd.c create mode 100644 mechglue/src/windows/identity/uilib/rescache.c create mode 100644 mechglue/src/windows/identity/uilib/trackerwnd.c create mode 100644 mechglue/src/windows/identity/uilib/uilibmain.c create mode 100644 mechglue/src/windows/identity/uilib/version.c create mode 100644 mechglue/src/windows/identity/util/Makefile create mode 100644 mechglue/src/windows/identity/util/hashtable.c create mode 100644 mechglue/src/windows/identity/util/hashtable.h create mode 100644 mechglue/src/windows/identity/util/mstring.c create mode 100644 mechglue/src/windows/identity/util/mstring.h create mode 100644 mechglue/src/windows/identity/util/perfstat.c create mode 100644 mechglue/src/windows/identity/util/perfstat.h create mode 100644 mechglue/src/windows/identity/util/sync.c create mode 100644 mechglue/src/windows/identity/util/sync.h create mode 100644 mechglue/src/windows/identity/util/utils.h create mode 100644 mechglue/src/windows/installer/nsis/ChangeLog create mode 100644 mechglue/src/windows/installer/nsis/KfWConfigPage.ini create mode 100644 mechglue/src/windows/installer/nsis/KfWConfigPage2.ini create mode 100644 mechglue/src/windows/installer/nsis/kfw-fixed.nsi create mode 100644 mechglue/src/windows/installer/nsis/kfw.ico create mode 100644 mechglue/src/windows/installer/nsis/kfw.nsi create mode 100644 mechglue/src/windows/installer/nsis/killer.cpp create mode 100644 mechglue/src/windows/installer/nsis/licenses.rtf create mode 100644 mechglue/src/windows/installer/nsis/nsi-includes.nsi create mode 100644 mechglue/src/windows/installer/nsis/site-local.nsi create mode 100644 mechglue/src/windows/installer/nsis/utils.nsi create mode 100644 mechglue/src/windows/installer/wix/Binary/ChangeLog create mode 100644 mechglue/src/windows/installer/wix/Binary/bannrbmp.bmp create mode 100644 mechglue/src/windows/installer/wix/Binary/completi.ico create mode 100644 mechglue/src/windows/installer/wix/Binary/custicon.ico create mode 100644 mechglue/src/windows/installer/wix/Binary/dlgbmp.bmp create mode 100644 mechglue/src/windows/installer/wix/Binary/exclamic.ico create mode 100644 mechglue/src/windows/installer/wix/Binary/info.bmp create mode 100644 mechglue/src/windows/installer/wix/Binary/insticon.ico create mode 100644 mechglue/src/windows/installer/wix/Binary/new.bmp create mode 100644 mechglue/src/windows/installer/wix/Binary/removico.ico create mode 100644 mechglue/src/windows/installer/wix/Binary/repairic.ico create mode 100644 mechglue/src/windows/installer/wix/Binary/up.bmp create mode 100644 mechglue/src/windows/installer/wix/ChangeLog create mode 100644 mechglue/src/windows/installer/wix/Makefile create mode 100644 mechglue/src/windows/installer/wix/config.wxi create mode 100644 mechglue/src/windows/installer/wix/custom/ChangeLog create mode 100644 mechglue/src/windows/installer/wix/custom/custom.cpp create mode 100644 mechglue/src/windows/installer/wix/custom/custom.h create mode 100644 mechglue/src/windows/installer/wix/features.wxi create mode 100644 mechglue/src/windows/installer/wix/files.wxi create mode 100644 mechglue/src/windows/installer/wix/kfw.wxs create mode 100644 mechglue/src/windows/installer/wix/lang/ChangeLog create mode 100644 mechglue/src/windows/installer/wix/lang/config_1033.wxi create mode 100644 mechglue/src/windows/installer/wix/lang/license.rtf create mode 100644 mechglue/src/windows/installer/wix/lang/strings_1033.wxl create mode 100644 mechglue/src/windows/installer/wix/lang/ui_1033.wxi create mode 100644 mechglue/src/windows/installer/wix/msi-deployment-guide.txt create mode 100644 mechglue/src/windows/installer/wix/property.wxi create mode 100644 mechglue/src/windows/installer/wix/site-local.wxi create mode 100644 mechglue/src/windows/kfwlogon/Makefile.in create mode 100644 mechglue/src/windows/kfwlogon/kfwcommon.c create mode 100644 mechglue/src/windows/kfwlogon/kfwcpcc.c create mode 100644 mechglue/src/windows/kfwlogon/kfwcpcc.rc create mode 100644 mechglue/src/windows/kfwlogon/kfwlogon.c create mode 100644 mechglue/src/windows/kfwlogon/kfwlogon.def create mode 100644 mechglue/src/windows/kfwlogon/kfwlogon.h create mode 100644 mechglue/src/windows/kfwlogon/kfwlogon.rc create mode 100644 mechglue/src/windows/lib/ChangeLog create mode 100644 mechglue/src/windows/lib/Makefile.in create mode 100644 mechglue/src/windows/lib/cacheapi.h create mode 100644 mechglue/src/windows/lib/gic.c create mode 100644 mechglue/src/windows/lib/gic.h create mode 100644 mechglue/src/windows/lib/registry.c create mode 100644 mechglue/src/windows/lib/registry.h create mode 100644 mechglue/src/windows/lib/vardlg.c create mode 100644 mechglue/src/windows/lib/vardlg.h create mode 100644 mechglue/src/windows/ms2mit/ChangeLog create mode 100644 mechglue/src/windows/ms2mit/Makefile.in create mode 100644 mechglue/src/windows/ms2mit/mit2ms.c create mode 100644 mechglue/src/windows/ms2mit/ms2mit.c create mode 100644 mechglue/src/windows/version.rc create mode 100644 mechglue/src/windows/wintel/.Sanitize create mode 100644 mechglue/src/windows/wintel/ChangeLog create mode 100644 mechglue/src/windows/wintel/Makefile.in create mode 100644 mechglue/src/windows/wintel/auth.c create mode 100644 mechglue/src/windows/wintel/auth.h create mode 100644 mechglue/src/windows/wintel/dialog.h create mode 100644 mechglue/src/windows/wintel/edit.c create mode 100644 mechglue/src/windows/wintel/emul.c create mode 100644 mechglue/src/windows/wintel/enc_des.c create mode 100644 mechglue/src/windows/wintel/enc_des.h create mode 100644 mechglue/src/windows/wintel/encrypt.c create mode 100644 mechglue/src/windows/wintel/encrypt.h create mode 100644 mechglue/src/windows/wintel/font.c create mode 100644 mechglue/src/windows/wintel/genget.c create mode 100644 mechglue/src/windows/wintel/ini.h create mode 100644 mechglue/src/windows/wintel/intern.c create mode 100644 mechglue/src/windows/wintel/k5stream.c create mode 100644 mechglue/src/windows/wintel/k5stream.h create mode 100644 mechglue/src/windows/wintel/ktelnet.doc create mode 100644 mechglue/src/windows/wintel/ktelnet.hlp create mode 100644 mechglue/src/windows/wintel/ktelnet.hpj create mode 100644 mechglue/src/windows/wintel/ncsa.ico create mode 100644 mechglue/src/windows/wintel/negotiat.c create mode 100644 mechglue/src/windows/wintel/resource.h create mode 100644 mechglue/src/windows/wintel/screen.c create mode 100644 mechglue/src/windows/wintel/screen.h create mode 100644 mechglue/src/windows/wintel/struct.h create mode 100644 mechglue/src/windows/wintel/telnet.c create mode 100644 mechglue/src/windows/wintel/telnet.def create mode 100644 mechglue/src/windows/wintel/telnet.h create mode 100644 mechglue/src/windows/wintel/telnet.rc create mode 100644 mechglue/src/windows/wintel/telnet_arpa.h create mode 100644 mechglue/src/windows/wintel/telopts.h create mode 100644 mechglue/src/windows/wintel/terminal.ico create mode 100644 mechglue/src/windows/wintel/wt-proto.h diff --git a/mechglue/.Sanitize b/mechglue/.Sanitize new file mode 100644 index 000000000..d2ddc3c35 --- /dev/null +++ b/mechglue/.Sanitize @@ -0,0 +1,34 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +doc +src +README + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/mechglue/README b/mechglue/README new file mode 100644 index 000000000..2bfe2473c --- /dev/null +++ b/mechglue/README @@ -0,0 +1,1185 @@ + Kerberos Version 5, Release 1.3.5 + + Release Notes + The MIT Kerberos Team + +Unpacking the Source Distribution +--------------------------------- + +The source distribution of Kerberos 5 comes in a gzipped tarfile, +krb5-1.3.5.tar.gz. Instructions on how to extract the entire +distribution follow. + +If you have the GNU tar program and gzip installed, you can simply do: + + gtar zxpf krb5-1.3.5.tar.gz + +If you don't have GNU tar, you will need to get the FSF gzip +distribution and use gzcat: + + gzcat krb5-1.3.5.tar.gz | tar xpf - + +Both of these methods will extract the sources into krb5-1.3.5/src and +the documentation into krb5-1.3.5/doc. + +Building and Installing Kerberos 5 +---------------------------------- + +The first file you should look at is doc/install-guide.ps; it contains +the notes for building and installing Kerberos 5. The info file +krb5-install.info has the same information in info file format. You +can view this using the GNU emacs info-mode, or by using the +standalone info file viewer from the Free Software Foundation. This +is also available as an HTML file, install.html. + +Other good files to look at are admin-guide.ps and user-guide.ps, +which contain the system administrator's guide, and the user's guide, +respectively. They are also available as info files +kerberos-admin.info and krb5-user.info, respectively. These files are +also available as HTML files. + +If you are attempting to build under Windows, please see the +src/windows/README file. + +Reporting Bugs +-------------- + +Please report any problems/bugs/comments using the krb5-send-pr +program. The krb5-send-pr program will be installed in the sbin +directory once you have successfully compiled and installed Kerberos +V5 (or if you have installed one of our binary distributions). + +If you are not able to use krb5-send-pr because you haven't been able +compile and install Kerberos V5 on any platform, you may send mail to +krb5-bugs@mit.edu. + +You may view bug reports by visiting + +http://krbdev.mit.edu/rt/ + +and logging in as "guest" with password "guest". + +Major changes in 1.3.5 +---------------------- + +* [2682] Fix ftpd hang caused by empty PASS command. + +* [2686] Fix double-free errors. [MITKRB5-SA-2004-002] + +* [2687] Fix denial-of-service vulnerability in ASN.1 + decoder. [MITKRB5-SA-2004-003] + +Minor changes in 1.3.5 +---------------------- + +* [2016] Fix build problem in fake-addrinfo.h by including stdio.h so + that sprintf() gets prototyped where needed on some platforms. + +* [2353] Add missing prototype for gss_krb5int_unseal_token_v3(). + +* [2607] Fix enctype filtering and some memory leaks in MSLSA ccache. + +* [2608] Remove incorrect localization in MSLSA ccache which was + resulting in crashes. + +* [2619] Update MSLSA ccache to support new LSA flag. + +* [2623] Update MSLSA ccache to reflect differences in registry layout + between Windows client and server OSes. + +* [2624] Do not ignore the cache when obtaining TGTs from the MSLSA if + the requested enctype is the NULL enctype. + +* [2626] Add Terminal Server compatibility for KfW. + +* [2627] Fix cc_mslsa thread safety. + +* [2634] Remove the caching of the ccache principal name from + krb5_context. + +* [2643] Fix another problem with krb4 ticket backdating. + +* [2675] Add new WiX-based MSI installer for KfW. + +* [2677] Add "-c ccache" option to kvno; use consistent memory + management to avoid crashes on Windows. + +* [2689] Misc MSLSA ccache fixes. + +* [2691] Improve documentation of ANSI C requirement. + +Major changes in 1.3.4 +---------------------- + +* [2024, 2583, 2584] Fixed buffer overflows in + krb5_aname_to_localname(). [MITKRB-SA-2004-001] + +Minor changes in 1.3.4 +---------------------- + +* [957] The auth_to_local rules now allow for the client realm to be + examined. + +* [2527, 2528, 2531] Keytab file names lacking a "FILE:" prefix now work + under Windows. + +* [2533] Updated installer scripts for Windows. + +* [2534] Fixed memory leak for when an incorrect password is input to + krb5_get_init_creds_password(). + +* [2535] Added missing newline to dnssrv.c. + +* [2551, 2564] Use compile-time checks to determine endianness. + +* [2558] krb5_send_tgs() now correctly sets message_type after + receiving a KRB_ERROR message. + +* [2561, 2574] Fixed memory allocation errors in the MSLSA ccache. + +* [2562] The Windows installer works around cases where DLLs cannot be + unloaded. + +* [2585] Documentation correctly describes AES support in GSSAPI. + +Major changes in 1.3.3 +---------------------- + +* [2284] Fixed accept_sec_context to use a replay cache in the + GSS_C_NO_CREDENTIAL case. Reported by Cesar Garcia. + +* [2426] Fixed a spurious SIGPIPE that happened in the TCP sendto_kdc + code on AIX. Thanks to Bill Dodd. + +* [2430] Fixed a crash in the MSLSA ccache. + +* [2453] The AES string-to-key function no longer returns a pointer to + stack memory when given a password longer than 64 characters. + +Minor changes in 1.3.3 +---------------------- + +* [2277] In sendto_kdc, a socket leak on connection failure was fixed. + Thanks to Bill Dodd. + +* [2384] A memory leak in the TCP handling code in the KDC has been + fixed. Thanks to Will Fiveash. + +* [2521] The Windows NSIS installer scripts are in the source tree. + +* [2522] The MSLSA ccache now supports Windows 9x. + +Major changes in 1.3.2 +---------------------- + +* [2040, 1471, 2067, 2077, 2079, 2166, 2167, 2220, 2266] Support for + AES in GSSAPI has been implemented. This corresponds to the + in-progress work in the IETF (CFX). + +* [2049, 2139, 2148, 2153, 2182, 2183, 2184, 2190, 2202] Added a new + ccache type "MSLSA:" for read-only access to the MS Windows LSA + cache. + +* [982] On windows, krb5.exe now has a checkbox to request addressless + tickets. + +* [2189, 2234] To avoid compatibility problems, unrecognized TGS + options will now be ignored. Thanks to Wyllys Ingersoll for finding + a problem with a previous fix. + +* [2218] 128-bit AES has been added to the default enctypes. + +* [2223, 2229] AES cryptosystem now chains IVs. This WILL break + backwards compatibility for the kcmd applications, if they are using + AES session keys. Thanks to Wyllys Ingersoll for finding a problem + with a previous fix. + +Minor changes in 1.3.2 +---------------------- + +* [1437] Applied patch from Stephen Grau so kinit returns non-zero + status under certain failure conditions where it had previously + returned zero. + +* [1586] On Windows, the krb4 CREDENTIALS structure has been changed + to align with KfW's version of the structure. + +* [1613] Applied patch from Dave Shrimpton to avoid truncation of + dates output from the kadmin CLI when long time zone names are + used. + +* [1622] krshd no longer calls syslog from inside a signal handler, in + an effort to avoid deadlocks on exit. + +* [1649] A com_err test program compiles properly on Darwin now. + +* [1692] A new configuration file tag "master_kdc" has been added to + allow master KDCs to be designated separately from admin servers. + +* [1702] krb5_get_host_realm() and krb5_free_host_realm() are no + longer marked as KRB5_PRIVATE. + +* [1711] Applied patch from Harry McGavran Jr to allow fake-addrinfo.h + to compile on libc5 Linux platforms. + +* [1712] Applied patch from Cesar Garcia to fix lifetime computation + in krb524 ticket conversion. + +* [1714] Fixed a 64-bit endianness bug in ticket starttime encoding in + krb524d. Found by Cesar Garcia. + +* [1715] kadmind4 and v5passwdd are no longer installed on Mac OS X. + +* [1718] The krb4 library configure script now recognizes + OpenDarwin/x86. Bug found by Rob Braun. + +* [1721] krb5_get_init_creds_password() no longer returns a spurious + KRB5_REALM_UNKNOWN if DNS SRV record support is turned off. + +* [1730] krb_mk_auth() no longer overzealously clears the key + schedule. + +* [1731] A double-free related to reading forwarded credentials has + been fixed. Found by Joseph Galbraith. + +* [1770] Applied patch from Maurice Massar to fix a foreachaddr() + problem that was causing the KDC to segfault on startup. + +* [1790] The Linux build uses $(CC) to create shared libraries, + avoiding a libgcc problem when building libdb. + +* [1792] The lib/kadm5 unit tests now work around a Solaris 9 + pty-close bug. + +* [1793] The test suite works around some Tru64 and Irix RPATH + issues, which previously could prevent tests from running on a build + with shared libraries enabled. + +* [1799] kadmind supports callouts to the Apple password server. + +* [1893] KRB-SAFE messages from older releases can now be read + successfully. Prior 1.3.x releases did not save the encoded + KRB-SAFE message, and experienced problems when re-encoding. Found + by Scooter Morris. + +* [1962] MS LSA tickets with short remaining lifetimes will be + rejected in favor of retrieving tickets bypassing the LSA cache. + +* [1973] sendto_kdc.c now closes sockets with closesocket() instead of + close(), avoiding a descriptor leak on Windows. + +* [1979] An erroneously short initial sequence number mask has been + fixed. + +* [2028] KfW now displays a kinit dialog when GSS fails to find + tickets. + +* [2051] Missing exports have been added to krb4_32.def on Windows. + +* [2058] Some problems with krb4 ticket lifetime backdating have + fixed. + +* [2060] GSSAPI's idea of the default ccache is less sticky now. + +* [2068] The profile library includes prof-int.h before conditionals + that rely on it. + +* [2084] The resolver library is no longer referenced by library code + if not building with DNS SRV record support. + +* [2085] Updated Windows README file to reflect current compilation + requirements, etc. + +* [2104] On Windows, only define strcasecmp and strncasecmp + replacement macros if said functions are missing. + +* [2106] Return an error for unimplemented ccache functions, rather + than calling through a null pointer. + +* [2118] Applied patch from Will Fiveash to use correct parameter for + KDC TCP listening sockets. + +* [2144,2230] Memory management errors in the Windows gss.exe test + client have been fixed. + +* [2171] krb5_locate_kpasswd() now correctly calls htons() on the + kpasswd port number. Found by Arlene Berry. + +* [2180] The profile library now includes pthread.h when compiled with + USE_PTHREADS. + +* [2181, 2224] A timeout has been added to gss-server, and a missing + parameter to sign_server() has been added. + +* [2196] config.{guess,sub} have been updated from autoconf-2.59. + +* [2204] Windows gss.exe now has support for specifying credentials + cache, as well as some minor bugfixes. + +* [2210] GSSAPI accept_sec_context() no longer unconditionally sets + INTEG and CONF flags in contradiction to what the initiator sent. + +* [2212] The GSS sample application has some additional options to + support testing of SSPI vs GSSAPI. + +* [2217] Windows gss.exe has new UI elements to support more flag + settings. + +* [2225] In the gss sample client, some extraneous parameters have + been removed from client_establish_context(). + +* [2228] Copyright notices updated in GSS sample apps. + +* [2233] On Windows compiles with KRB5_KFW_COMPILE, the lib path for + krbcc32.lib is now correct. + +* [2195, 2236, 2241, 2245] The Solaris 9 pty-close bug, which was + affecting the test suite, has been worked around by hacking + scheduler priorities. See the installation notes for details. + Thanks to Bill Sommerfeld for some useful hints. + +* [2258] An incorrect memcpy() statement in fakeka has been fixed. + Reported by David Thompson. + +Notes, Major Changes, and Known Bugs for 1.3.1 +---------------------------------------------- + +* [1681] The incorrect encoding of the ETYPE-INFO2 preauthentication + hint is no longer emitted, and the both the incorrect and the + correct encodings of ETYPE-INFO2 are now accepted. We STRONGLY + encourage deploying krb5-1.3.1 in preference to 1.3, especially on + client installations, as the 1.3 release did not conform to the + internet-draft for the revised Kerberos protocol in its encoding of + ETYPE-INFO2. + +* [1683] The non-caching getaddrinfo() API on Mac OS X, which was + causing significant slowdowns under some circumstances, has been + worked around. + +Minor changes in 1.3.1 +---------------------- + +* [1015] gss_accept_sec_context() now passes correct arguments to + TREAD_STR() when reading options beyond the forwarded credential + option. Thanks to Emily Ratliff. + +* [1365] The GSSAPI initiator credentials are no longer cached inside + the GSSAPI library. + +* [1651] A buffer overflow in krb_get_admhst() has been fixed. + +* [1655] krb5_get_permitted_enctypes() and krb5_set_real_time() are + now exported for use by Samba. + +* [1656] gss_init_sec_context() no longer leaks credentials under some + error conditions. + +* [1657] krb_get_lrealm() no longer returns "ATHENA.MIT.EDU" + inappropriately. + +* [1664] The crypto library no longer has bogus dependencies on + com_err. + +* [1665] krb5_init_context() no longer multiply registers error tables + when called more than once, preventing a memory leak. + +* [1666] The GSS_C_NT_* symbols are now exported from gssapi32.dll on + Windows. + +* [1667] ms2mit now imports any tickets with supported enctypes, and + does not import invalid tickets. + +* [1677] krb5_gss_register_acceptor_identity() no longer has an + off-by-one in its memory allocation. + +* [1679] krb5_principal2salt is now exported on all platforms. + +* [1684] The file credentials cache is now supported if USE_CCAPI is + defined, i.e., for KfM and KfW. + +* [1691] Documentation for the obsolete kdc_supported_enctypes config + variable has been removed. + +Notes, Major Changes, and Known Bugs for 1.3 +-------------------------------------------- + +* We now install the compile_et program, so other packages can use the + installed com_err library with their own error tables. (If you use + our com_err code, that is; see below.) + +* The header files we install now assume ANSI/ISO C ('89, not '99). + We have stopped testing on SunOS 4, even with gcc. Some of our code + now has C89-based assumptions, like free(NULL) being well defined, + that will probably frustrate any attempts to run this code under SunOS + 4 or other pre-C89 systems. + +* Some new code, bug fixes, and cleanup for IPv6 support. Most of the + code should support IPv6 transparently now. The RPC code (and + therefore the admin system, which is based on it) does not yet + support IPv6. The support for Kerberos 4 may work with IPv6 in very + limited ways, if the address checking is turned off. The FTP client + and server do not have support for the new protocol messages needed + for IPv6 support (RFC 2428). + +* We have upgraded to autoconf 2.52 (or later), and the syntax for + specifying certain configuration options have changed. For example, + autoconf 2.52 configure scripts let you specify command-line options + like "configure CC=/some/path/foo-cc", so we have removed some of + our old options like --with-cc in favor of this approach. + +* The client libraries can now use TCP to connect to the KDC. This + may be necessary when talking to Microsoft KDCs (domain controllers), + if they issue you tickets with lots of PAC data. + +* If you have versions of the com_err or ss installed locally, you can + use the --with-system-et and --with-system-ss configure options to + use them rather than using the versions supplied here. Note that + the interfaces are assumed to be similar to those we supply; in + particular, some older, divergent versions of the com_err library + may not work with the krb5 sources. Many configure-time variables + can be used to help the compiler and linker find the installed + packages; see the build documentation for details. + +* The AES cryptosystem has been implemented. However, support in the + Kerberos GSSAPI mechanism has not been written (or even fully + specified), so it's not fully enabled. See the documentation for + details. + +Major changes listed by ticket ID +--------------------------------- + +* [492] PRNG breakage on 64-bit platforms no longer an issue due to + new PRNG implementation. + +* [523] Client library is now compatible with the RC4-based + cryptosystem used by Windows 2000. + +* [709] krb4 long lifetime support has been implemented. + +* [880] krb5_gss_register_acceptor_identity() implemented (is called + gsskrb5_register_acceptor_identity() by Heimdal). + +* [1087] ftpd no longer requires channel bindings, allowing easier use + of ftp from behind a NAT. + +* [1156, 1209] It is now possible to use the system com_err to build + this release. + +* [1174] TCP support added to client library. + +* [1175] TCP support added to the KDC, but is disabled by default. + +* [1176] autoconf-2.5x is now required by the build system. + +* [1184] It is now possible to use the system Berkeley/Sleepycat DB + library to build this release. + +* [1189, 1251] The KfM krb4 library source base has been merged. + +* [1190] The default KDC master key type is now triple-DES. KDCs + being updated may need their config files updated if they are not + already specifying the master key type. + +* [1190] The default ticket lifetime and default maximum renewable + ticket lifetime have been extended to one day and one week, + respectively. + +* [1191] A new script, k5srvutil, may be used to manipulate keytabs in + ways similar to the krb4 ksrvutil utility. + +* [1281] The "fakeka" program, which emulates the AFS kaserver, has + been integrated. Thanks to Ken Hornstein. + +* [1343] The KDC now defaults to not answering krb4 requests. + +* [1344] Addressless tickets are requested by default now. + +* [1372] There is no longer a need to create a special keytab for + kadmind. The legacy administration daemons "kadmind4" and + "v5passwdd" will still require a keytab, though. + +* [1377, 1442, 1443] The Microsoft set-password protocol has been + implemented. Thanks to Paul Nelson. + +* [1385, 1395, 1410] The krb4 protocol vulnerabilities + [MITKRB5-SA-2003-004] have been worked around. Note that this will + disable krb4 cross-realm functionality, as well as krb4 triple-DES + functionality. Please see doc/krb4-xrealm.txt for details of the + patch. + +* [1393] The xdrmem integer overflows [MITKRB5-SA-2003-003] have + been fixed. + +* [1397] The krb5_principal buffer bounds problems + [MITKRB5-SA-2003-005] have been fixed. Thanks to Nalin Dahyabhai. + +* [1415] Subsession key negotiation has been fixed to allow for + server-selected subsession keys in the future. + +* [1418, 1429, 1446, 1484, 1486, 1487, 1535, 1621] The AES + cryptosystem has been implemented. It is not usable for GSSAPI, + though. + +* [1491] The client-side functionality of the krb524 library has been + moved into the krb5 library. + +* [1550] SRV record support exists for Kerberos v4. + +* [1551] The heuristic for locating the Kerberos v4 KDC by prepending + "kerberos." to the realm name if no config file or DNS information + is available has been removed. + +* [1568, 1067] A krb524 stub library is built on Windows. + +Minor changes listed by ticket ID +--------------------------------- + +* [90] default_principal_flags documented. + +* [175] Docs refer to appropriate example domains/IPs now. + +* [299] kadmin no longer complains about missing kdc.conf parameters + when it really means krb5.conf parameters. + +* [318] Run-time load path for tcl is set now when linking test + programs. + +* [443] --includedir honored now. + +* [479] unused argument in try_krb4() in login.c deleted. + +* [590] The des_read_pw_string() function in libdes425 has been + aligned with the original krb4 and CNS APIs. + +* [608] login.krb5 handles SIGHUP more sanely now and thus avoids + getting the session into a weird state w.r.t. job control. + +* [620] krb4 encrypted rcp should work a little better now. Thanks to + Greg Hudson. + +* [647] libtelnet/kerberos5.c no longer uses internal include files. + +* [673] Weird echoing of admin password in kadmin client worked around + by not using buffered stdio calls to read passwords. + +* [677] The build system has been reworked to allow the user to set + CFLAGS, LDFLAGS, CPPFLAGS, etc. reasonably. + +* [680] Related to [673], rewrite krb5_prompter_posix() to no longer + use longjmp(), thus avoiding some bugs relating to non-restoration + of terminal settings. + +* [697] login.krb5 no longer zeroes out the terminal window size. + +* [710] decomp_ticket() in libkrb4 now looks up the local realm name + more correctly. Thanks to Booker Bense. + +* [771] .rconf files are excluded from the release now. + +* [772] LOG_AUTHPRIV syslog facility is now usable for logging on + systems that support it. + +* [844] krshd now syslogs using the LOG_AUTH facility. + +* [850] Berekely DB build is better integrated into the krb5 library + build process. + +* [866] lib/krb5/os/localaddr.c and kdc/network.c use a common source + for local address enumeration now. + +* [882] gss-client now correctly deletes the context on error. + +* [919] kdc/network.c problems relating to SIOCGIFCONF have been + fixed. + +* [922] An overflow in the string-to-time conversion routines has been + fixed. + +* [933] krb524d now handles single-DES session keys other than of type + des-cbc-crc. + +* [935] des-cbc-md4 now included in default enctypes. + +* [939] A minor grammatical error has been fixed in a telnet client + error message. + +* [953] des3 no longer failing on Windows due to SHA1 implementation + problems. + +* [964] kdb_init_hist() no longer fails if master_key_enctype is not + in supported_enctypes. + +* [970] A minor inconsistency in ccache.tex has been fixed. + +* [971] option parsing bugs rendered irrelevant by removal of unused + gss mechanism. + +* [976] make install mentioned in build documentation. + +* [986] Related to [677], problems with the ordering of LDFLAGS + initialization rendered irrelevant by use of native autoconf + idioms. + +* [992] Related to [677], quirks with --with-cc no longer relevant as + AC_PROG_CC is used instead now. + +* [999] The kdc_default_options configuration variable is now honored. + Thanks to Emily Ratliff. + +* [1006] Client library, as well as KDC, now perform reasonable + sorting of ETYPE-INFO preauthentication data. + +* [1055] NULL pointer dereferences in code calling + krb5_change_password() have been fixed. + +* [1063] Initial credentials acquisition failures related to client + host having a large number of local network interfaces should be + fixed now. + +* [1064] Incorrect option parsing in the gssapi library is no longer + relevant due to removal of the "v2" mechanism. + +* [1065, 1225] krb5_get_init_creds_password() should properly warn about + password expiration. + +* [1066] printf() argument mismatches in rpc unit tests fixed. + +* [1085] The krb5.conf manpage has been re-synchronized with other + documentation. + +* [1102] gssapi_generic.h should now work with C++. + +* [1135] The kadm5 ACL system is better documented. + +* [1136] Some documentation for the setup of cross-realm + authentication has been added. + +* [1164] krb5_auth_con_gen_addrs() now properly returns errno instead + of -1 if getpeername() fails. + +* [1173] Address-less forwardable tickets will remain address-less + when forwarded. + +* [1178, 1228, 1244, 1246, 1249] Test suite has been stabilized + somewhat. + +* [1188] As part of the modernization of our usage of autoconf, + AC_CONFIG_FILES is now used instead of passing a list of files to + AC_OUTPUT. + +* [1194] configure will no longer recurse out of the top of the source + tree when attempting to locate the top of the source tree. + +* [1192] Documentation for the krb5 afs functionality of krb524d has + been written. + +* [1195] Example krb5.conf file modified to include all enctypes + supported by the release. + +* [1202] The KDC no longer rejects unrecognized flags. + +* [1203] krb5_get_init_creds_keytab() no longer does a double-free. + +* [1211] The ASN.1 code no longer passes (harmless) uninitialized + values around. + +* [1212] libkadm5 now allows for persistent exclusive database locks. + +* [1217] krb5_read_password() and des_read_password() are now + implemented via krb5_prompter_posix(). + +* [1224] For SAM challenges, omitted optional strings are no longer + encoded as zero-length strings. + +* [1226] Client-side support for SAM hardware-based preauth + implemented. + +* [1229] The keytab search logic no longer fails prematurely if an + incorrect encryption type is found. Thanks to Wyllys Ingersoll. + +* [1232] If the master KDC cannot be resolved, but a slave is + reachable, the client library now returns the real error from the + slave rather than the resolution failure from the master. Thanks to + Ben Cox. + +* [1234] Assigned numbers for SAM preauth have been corrected. + sam-pk-for-sad implementation has been aligned. + +* [1237] Profile-sharing optimizations from KfM have been merged. + +* [1240] Windows calling conventions for krb5int_c_combine_keys() have + been aligned. + +* [1242] Build system incompatibilities with Debian's chimeric + autoconf installation have been worked around. + +* [1256] Incorrect sizes passed to memset() in combine_keys() + operations have been corrected. + +* [1260] Client credential lookup now gets new service tickets in + preference to attempting to use expired ticketes. Thanks to Ben + Cox. + +* [1262, 1572] Sequence numbers are now unsigned; negative sequence + numbers will be accepted for the purposes of backwards + compatibility. + +* [1263] A heuristic for matching the incorrectly encoded sequence + numbers emitted by Heimdal implementations has been written. + +* [1284] kshd accepts connections by IPv6 now. + +* [1292] kvno manpage title fixed. + +* [1293] Source files no longer explicitly attempt to declare errno. + +* [1304] kadmind4 no longer leaves sa_flags uninitialized. + +* [1305] Expired tickets now cause KfM to pop up a password dialog. + +* [1309] krb5_send_tgs() no longer leaks the storage associated with + the TGS-REQ. + +* [1310] kadm5_get_either() no longer leaks regexp library memory. + +* [1311] Output from krb5-config no longer contains spurious uses of + $(PURE). + +* [1324] The KDC no longer logs an inappropriate "no matching key" + error when an encrypted timestamp preauth password is incorrect. + +* [1334] The KDC now returns a clockskew error when the timestamp in + the encrypted timestamp preauth is out of bounds, rather than just + returning a preauthentcation failure. + +* [1342] gawk is no longer required for building kerbsrc.zip for the + Windows build. + +* [1346] gss_krb5_ccache_name() no longer attempts to return a pointer + to freed memory. + +* [1351] The filename globbing vulnerability [CERT VU#258721] in the + ftp client's handling of filenames beginning with "|" or "-" + returned from the "mget" command has been fixed. + +* [1352] GSS_C_PROT_READY_FLAG is no longer asserted inappropriately + during GSSAPI context establishment. + +* [1356] krb5_gss_accept_sec_context() no longer attempts to validate + a null credential if one is passed in. + +* [1362] The "-a user" option to telnetd now does the right thing. + Thanks to Nathan Neulinger. + +* [1363] ksu no longer inappropriately syslogs to stderr. + +* [1357] krb__get_srvtab_name() no longer leaks memory. + +* [1370] GSS_C_NO_CREDENTIAL now accepts any principal in the keytab. + +* [1373] Handling of SAM preauth no longer attempts to stuff a size_t + into an unsigned int. + +* [1387] BIND versions later than 8 now supported. + +* [1392] The getaddrinfo() wrapper should work better on AIX. + +* [1400] If DO_TIME is not set in the auth_context, and no replay + cache is available, no replay cache will be used. + +* [1406, 1108] libdb is no longer installed. If you installed + krb5-1.3-alpha1, you should ensure that no spurious libdb is left in + your install tree. + +* [1412] ETYPE_INFO handling no longer goes into an infinite loop. + +* [1414] libtelnet is now built using the same library build framework + as the rest of the tree. + +* [1417] A minor memory leak in krb5_read_password() has been fixed. + +* [1419] A memory leak in asn1_decode_kdc_req_body() has been fixed. + +* [1435] inet_ntop() is now emulated when needed. + +* [1439] krb5_free_pwd_sequences() now correctly frees the entire + sequence of elements. + +* [1440] errno is no longer explicitly declared. + +* [1441] kadmind should now return useful errors if an unrecognized + version is received in a changepw request. + +* [1454, 1480, 1517, 1525] The etype-info2 preauth type is now + supported. + +* [1459] (KfM/KLL internal) config file resolution can now be + prevented from accessing the user's homedir. + +* [1463] Preauth handling in the KDC has been reorganized. + +* [1470] Double-free in client-side preauth code fixed. + +* [1473] Ticket forwarding when the TGS and the end service have + different enctypes should work somewhat better now. + +* [1474] ASN.1 testsuite memory management has been cleaned up a + little to allow for memory leak checking. + +* [1476] Documentation updated to reflect default krb4 mode. + +* [1482] RFC-1964 OIDs now provided using the suggested symbolic + names. + +* [1483, 1528] KRB5_DEPRECATED is now false by default on all + platforms. + +* [1488] The KDC will now return integrity errors if a decryption + error is responsible for preauthentication failure. + +* [1492] The autom4te.cache directories are now deleted from the + release tarfiles. + +* [1501] Writable keytabs are registered by default. + +* [1515] The check for cross-realm TGTs no longer reads past the end + of an array. + +* [1518] The kdc_default_options option is now actually honored. + +* [1519] The changepw protocol implementation in kadmind now logs + password changes. + +* [1520] Documentation of OS-specific build options has been updated. + +* [1536] A missing prototype for krb5_db_iterate_ext() has been + added. + +* [1537] An incorrect path to kdc.conf show in the kdc.conf manpage + has been fixed. + +* [1540] verify_as_reply() will only check the "renew-till" time + against the "till" time if the RENEWABLE is not set in the request. + +* [1547] gssftpd no longer uses vfork(), as this was causing problems + under RedHat 9. + +* [1549] SRV records with a value of "." are now interpreted as a lack + of support for the protocol. + +* [1553] The undocumented (and confusing!) kdc_supported_enctypes + kdc.conf variable is no longer used. + +* [1560] Some spurious double-colons in password prompts have been + fixed. + +* [1571] The test suite tries a little harder to get a root shell. + +* [1573] The KfM build process now sets localstatedir=/var/db. + +* [1576, 1575] The client library no longer requests RENEWABLE_OK if + the renew lifetime is greater than the ticket lifetime. + +* [1587] A more standard autoconf test to locate the C compiler allows + for gcc to be found by default without additional configuration + arguments. + +* [1593] Replay cache filenames are now escaped with hyphens, not + backslashes. + +* [1598] MacOS 9 support removed from in-tree com_err. + +* [1602] Fixed a memory leak in make_ap_req_v1(). Thanks to Kent Wu. + +* [1604] Fixed a memory leak in krb5_gss_init_sec_context(), and an + uninitialized memory reference in kg_unseal_v1(). Thanks to Kent + Wu. + +* [1607] kerberos-iv SRV records are now documented. + +* [1610] Fixed AES credential delegation under GSSAPI. + +* [1618] ms2mit no longer inserts local addresses into tickets + converted from the MS ccache if they began as addressless tickets. + +* [1619] etype_info parser (once again) accepts extra field emitted by + Heimdal. + +* [1643] Some typos in kdc.conf.M have been fixed. + +* [1648] For consistency, leading spaces before preprocessor + directives in profile.h have been removed. + +--[ DELETE BEFORE RELEASE ---changes to unreleased code, etc.--- ]-- + +* [1054] KRB-CRED messages for RC4 are encrypted now. + +* [1177] krb5-1-2-2-branch merged onto trunk. + +* [1193] Punted comment about reworking key storage architecture. + +* [1208] install-headers target implemented. + +* [1223] asn1_decode_oid, asn1_encode_oid implemented + +* [1248] RC4 is explicitly excluded from combine_keys. + +* [1276] Generated dependencies handle --without-krb4 properly now. + +* [1339] An inadvertent change to the krb4 get_adm_hst API (strcpy vs + strncpy etc.) has been fixed. + +* [1384, 1413] Use of autoconf-2.52 in util/reconf will now cause a + warning. + +* [1388] DNS support is turned on in KfM. + +* [1391] Fix kadmind startup failure with krb4 vuln patch. + +* [1409] get_ad_tkt() now prompts for password if there are no tickets + (in KfM). + +* [1447] vts_long() and vts_short() work now. + +* [1462] KfM adds exports of set_pw calls. + +* [1477] compile_et output not used in err_txt.c. + +* [1495] KfM now exports string_to_key_with_params. + +* [1512, 1522] afs_string_to_key now works with etype_info2. + +* [1514] krb5int_populate_gic_opt returns void now. + +* [1521] Using an afs3 salt for an AES key no longer causes + segfaults. + +* [1533] krb524.h no longer contains invalid Mac pragmas. + +* [1546] krb_mk_req_creds() no longer zeros the session key. + +* [1554] The krb4 string-to-key iteration now accounts correctly for + the decrypt-in-place semantics of libdes425. + +* [1557] KerberosLoginPrivate.h is now correctly included for the use + of __KLAllowHomeDirectoryAccess() in init_os_ctx.c (for KfM). + +* [1558] KfM exports the new krb524 interface. + +* [1563] krb__get_srvtaname() no longer returns a pointer that is + free()d upon a subsequent call. + +* [1569] A debug statement has been removed from krb524init. + +* [1592] Document possible file rename lossage when building against + system libdb. + +* [1594] Darwin gets an explicit dependency of err_txt.o on + krb_err.c. + +* [1596] Calling conventions, etc. tweaked for KfW build of + krb524.dll. + +* [1600] Minor tweaks to README to improve notes on IPv6, etc. + +* [1605] Fixed a leak of subkeys in krb5_rd_rep(). + +* [1630] krb5_get_in_tkt_with_keytab() works now; previously borken by + reimplementation in terms of krb5_get_init_creds(). + +* [1642] KfM build now inherits CFLAGS and LDFLAGS from parent project. + +Copyright Notice and Legal Administrivia +---------------------------------------- + +Copyright (C) 1985-2004 by the Massachusetts Institute of Technology. + +All rights reserved. + +Export of this software from the United States of America may require +a specific license from the United States Government. It is the +responsibility of any person or organization contemplating export to +obtain such a license before exporting. + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +distribute this software and its documentation for any purpose and +without fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, and that +the name of M.I.T. not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. Furthermore if you modify this software you must label +your software as modified software and not distribute it in such a +fashion that it might be confused with the original MIT software. +M.I.T. makes no representations about the suitability of this software +for any purpose. It is provided "as is" without express or implied +warranty. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +Individual source code files are copyright MIT, Cygnus Support, +OpenVision, Oracle, Sun Soft, FundsXpress, and others. + +Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira, +and Zephyr are trademarks of the Massachusetts Institute of Technology +(MIT). No commercial use of these trademarks may be made without +prior written permission of MIT. + +"Commercial use" means use of a name in a product or other for-profit +manner. It does NOT prevent a commercial firm from referring to the +MIT trademarks in order to convey information (although in doing so, +recognition of their trademark status should be given). + +---- + +The following copyright and permission notice applies to the +OpenVision Kerberos Administration system located in kadmin/create, +kadmin/dbutil, kadmin/passwd, kadmin/server, lib/kadm5, and portions +of lib/rpc: + + Copyright, OpenVision Technologies, Inc., 1996, All Rights Reserved + + WARNING: Retrieving the OpenVision Kerberos Administration system + source code, as described below, indicates your acceptance of the + following terms. If you do not agree to the following terms, do not + retrieve the OpenVision Kerberos administration system. + + You may freely use and distribute the Source Code and Object Code + compiled from it, with or without modification, but this Source + Code is provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY, + INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR + FITNESS FOR A PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER + EXPRESS OR IMPLIED. IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY + FOR ANY LOST PROFITS, LOSS OF DATA OR COSTS OF PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES, OR FOR ANY SPECIAL, INDIRECT, OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, INCLUDING, + WITHOUT LIMITATION, THOSE RESULTING FROM THE USE OF THE SOURCE + CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR ANY + OTHER REASON. + + OpenVision retains all copyrights in the donated Source Code. OpenVision + also retains copyright to derivative works of the Source Code, whether + created by OpenVision or by a third party. The OpenVision copyright + notice must be preserved if derivative works are made based on the + donated Source Code. + + OpenVision Technologies, Inc. has donated this Kerberos + Administration system to MIT for inclusion in the standard + Kerberos 5 distribution. This donation underscores our + commitment to continuing Kerberos technology development + and our gratitude for the valuable work which has been + performed by MIT and the Kerberos community. + +---- + + Portions contributed by Matt Crawford were + work performed at Fermi National Accelerator Laboratory, which is + operated by Universities Research Association, Inc., under + contract DE-AC02-76CHO3000 with the U.S. Department of Energy. + +---- The implementation of the Yarrow pseudo-random number generator +in src/lib/crypto/yarrow has the following copyright: + +Copyright 2000 by Zero-Knowledge Systems, Inc. + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Zero-Knowledge Systems, +Inc. not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. Zero-Knowledge Systems, Inc. makes no representations +about the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. + +ZERO-KNOWLEDGE SYSTEMS, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL ZERO-KNOWLEDGE SYSTEMS, INC. BE LIABLE FOR +ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +---- The implementation of the AES encryption algorithm in +src/lib/crypto/aes has the following copyright: + + Copyright (c) 2001, Dr Brian Gladman , Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explcit or implied warranties + in respect of any properties, including, but not limited to, correctness + and fitness for purpose. + + + +Acknowledgements +---------------- + +Appreciation Time!!!! There are far too many people to try to thank +them all; many people have contributed to the development of Kerberos +V5. This is only a partial listing.... + +Thanks to Paul Vixie and the Internet Software Consortium for funding +the work of Barry Jaspan. This funding was invaluable for the OV +administration server integration, as well as the 1.0 release +preparation process. + +Thanks to John Linn, Scott Foote, and all of the folks at OpenVision +Technologies, Inc., who donated their administration server for use in +the MIT release of Kerberos. + +Thanks to Jeff Bigler, Mark Eichin, Marc Horowitz, Nancy Gilman, Ken +Raeburn, and all of the folks at Cygnus Support, who provided +innumerable bug fixes and portability enhancements to the Kerberos V5 +tree. Thanks especially to Jeff Bigler, for the new user and system +administrator's documentation. + +Thanks to Doug Engert from ANL for providing many bug fixes, as well +as testing to ensure DCE interoperability. + +Thanks to Ken Hornstein at NRL for providing many bug fixes and +suggestions, and for working on SAM preauthentication. + +Thanks to Matt Crawford at FNAL for bugfixes and enhancements. + +Thanks to Sean Mullan and Bill Sommerfeld from Hewlett Packard for +their many suggestions and bug fixes. + +Thanks to Nalin Dahyabhai of RedHat and Chris Evans for locating and +providing patches for numerous buffer overruns. + +Thanks to Christopher Thompson and Marcus Watts for discovering the +ftpd security bug. + +Thanks to Paul Nelson of Thursby Software Systems for implementing the +Microsoft set password protocol. + +Thanks to the members of the Kerberos V5 development team at MIT, both +past and present: Danilo Almeida, Jeffrey Altman, Jay Berkenbilt, +Richard Basch, Mitch Berger, John Carr, Don Davis, Alexandra Ellwood, +Nancy Gilman, Matt Hancher, Sam Hartman, Paul Hill, Marc Horowitz, Eva +Jacobus, Miroslav Jurisic, Barry Jaspan, Geoffrey King, John Kohl, +Peter Litwack, Scott McGuire, Kevin Mitchell, Cliff Neuman, Paul Park, +Ezra Peisach, Chris Provenzano, Ken Raeburn, Jon Rochlis, Jeff +Schiller, Jen Selby, Brad Thompson, Harry Tsai, Ted Ts'o, Marshall +Vale, Tom Yu. diff --git a/mechglue/doc/.Sanitize b/mechglue/doc/.Sanitize new file mode 100644 index 000000000..89b441370 --- /dev/null +++ b/mechglue/doc/.Sanitize @@ -0,0 +1,46 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +ChangeLog +HOW_TO_BUILD +INCOMPATIBILITY +Makefile +OS-notes +SOURCE-TREE +TREE-GRAPH +api +implement +install.texi +install.ps +kadmin +krb5-protocol +old-V4-docs +texinfo.tex + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/mechglue/doc/.cvsignore b/mechglue/doc/.cvsignore new file mode 100644 index 000000000..c865798db --- /dev/null +++ b/mechglue/doc/.cvsignore @@ -0,0 +1,20 @@ +*.html +*.info +*.info-* +*.log +*.dvi +*.aux +*.toc +*.cp +*.fn +*.vf +*.tp +*.ky +*.pg +*.vr +*.ps +*.fns +*.tps +*.vrs +*.pdf +krb5-install diff --git a/mechglue/doc/ChangeLog b/mechglue/doc/ChangeLog new file mode 100644 index 000000000..0489c358d --- /dev/null +++ b/mechglue/doc/ChangeLog @@ -0,0 +1,924 @@ +2005-10-20 Ken Raeburn + + * coding-style: Modern (gnu) indent requires a number with -ip. + +2005-08-29 Sam Hartman + + * kadm5/api-server-design.tex kadm5/api-funcspec.tex: Avoid using changebar.sty + +2005-08-25 Ken Raeburn + + * kadm5/adb-unit-test.tex: Use RCS Id keyword instead of Header. + * kadm5/api-unit-test.tex: Likewise. + (ovsec_kadm_create_principal): Fix missing closing brace that + prevent latex from finishing. + +2005-04-21 Ken Raeburn + + * implementor.texinfo (Local Addresses): Drop Mac OS 9, add + Solaris 9, HP-UX 11. + (IPv6 Support, Host Address Lookup): Update for fake getaddrinfo + code moved to support library. + (Thread System Requirements): Use @code when listing function + names. Add a couple notes about some problematic routines. + (Internal Thread API): Update k5_mutex_t description to indicate + there's always non-OS data included. Describe case where thread + support is disabled. + (Advanced Shared Library Requirements): Describe recently raised + Windows DllMain issues. Describe finalization code. Multiple + init/fini functions are now allowed in a library. Describe + LIBINITFUNC and LIBFINIFUNC makefile variables. Mention lib.in + can have rules for generating temporary files for dealing with + export lists. + (Thread Shim Layer Implementation): New node. + (Internal Thread API): Move the k5_os_ descriptions there. + (Networking): New chapter node, incorporates Socket API, IPv6 + Support, Local Addresses, and Host Address Lookup. + (Porting Issues): Fix up formatting. + + * Makefile (clean-tex): Delete *.fns, *.vrs, *.tps too. + (implementor.pdf, implementor.ps, implementor.info): New targets. + + * build.texinfo (HPUX): Add some notes about the thread support + and gcc. + + * defintions.texinfo (RELEASE, PREVRELEASE): Updated. + +2005-03-03 Ken Raeburn + + * build.texinfo (HPUX): Update with current state of shared + library and thread support. + + * Makefile (PSPDF): New variable. + (admin-guide.pdf, install-guide.pdf, user-guide.pdf): New + targets. + (clean-final): Delete PDF files. + +2005-02-11 Tom Yu + + * kadm5/api-unit-test.tex (ovsec_kadm_init): Update to reflect + changed expected error codes for init 152, 153 tests. + +2005-01-03 Ken Raeburn + + * implementor.texinfo (Porting Issues): New chapter with a bunch + of notes from email I sent regarding porting to pSOS. + + * build.texinfo (The util Directory): Add the new support + library. + (Installing the Binaries): Discuss parallel builds under GNU + make. + + * implementor.texinfo (Host Address Lookup): Document Mac OS X + issues. + + * threads.txt, thread-safety.txt: Updates. + +2004-11-19 Tom Yu + + * build.texinfo (Solaris 9): Document Solaris patches for pty + close bug. + +2004-10-06 Ken Raeburn + + * implementor.texinfo, thread-safe.txt, threads.txt: Various + updates relating to thread support. + +2004-09-07 Tom Yu + + * install.texinfo (Propagate the Database to Each Slave KDC): + Remove spurious "-R" flag from kdb5_util invocation. + +2004-09-02 Tom Yu + + * build.texinfo: Fix some typos. + (Build Requirements): Note ANSI C (c89) requirement. + (Alpha OSF/1 V4.0): Document "-std0" vs "-std" cc behavior. + +2004-07-20 Ken Raeburn + + * implementor.texinfo: Changed @code to @file where files are + referenced. + (NetBSD Shared Library Support, Solaris Shared Library Support): + Outdated sections deleted. + (Shared Library Theory): Fixed typo. + (Advanced Shared Library Requirements): New section. + (Thread Safety): Rewrite; add subsections. + (Compiler and OS Requirements): New section. + +2004-06-10 Ken Raeburn + + * admin.texinfo (Supported Encryption Types): Reflect new AES + support in GSSAPI, but keep a warning about interoperability with + old versions. + +2004-06-02 Ken Raeburn + + * threads.txt, thread-safe.txt: New files. + +2004-02-13 Tom Yu + + * build.texinfo (Solaris 9): Add section describing workaround for + Solaris 9 pty-close kernel bug. + +2003-07-25 Ken Raeburn + + * admin.texinfo (realms (krb5.conf)): Add description of + master_kdc tag. + (Sample krb5.conf File): Add it to the example. + +2003-07-24 Sam Hartman + + * admin.texinfo (realms (kdc.conf)): Remove references to kdc_supported_enctypes + (Sample kdc.conf File): Remove kdc_supported_enctypes here too + +2003-06-20 Tom Yu + + * build.texinfo (Installing the Binaries): New node; describe + basic "make install", along with "DESTDIR=...". + +2003-06-19 Tom Yu + + * build.texinfo (HPUX): Fix typo. + (Options to Configure): Note that --with-system-db is unsupported, + concerning possible lossage with loading dumpfiles. + +2003-06-18 Tom Yu + + * dnssrv.texinfo: Add note about _kerberos-iv._udp SRV records. + +2003-06-05 Tom Yu + + * procedures.txt: New file. Draft of current procedures. + Currently mostly contains a few email messages from Sam. More + clarification should follow later. + +2003-05-30 Ken Raeburn + + * definitions.texinfo (DefaultCcacheType, DefaultKDCTimesync, + DefaultMasterKeyType, DefaultTktLifetime): Updated for code + changes. + (DefaultCcacheTypeMac, DefaultKDCTimesyncMac): Deleted. + + * admin.texinfo (libdefaults): Update kdc_timesync and ccache_type + descriptions to not separate Mac case. + +2003-05-30 Sam Hartman + + * admin.texinfo (Supported Encryption Types): Document AES interop issues. + + * support-enc.texinfo: Add AES enctypes + +2003-05-27 Tom Yu + + * admin.texinfo (realms (kdc.conf)): Update to reflect that + kadm5.keytab is only used by legacy admin daemons. + + * install.texinfo (Create a kadmind Keytab (optional)): Update to + reflect that kadm5.keytab is only used by legacy admin daemons. + + * build.texinfo (HPUX): Make HPUX compiler flags simpler. + +2003-05-23 Ken Raeburn + + * build.texinfo (HPUX, Solaris 2.X, Ultrix 4.2/3 [notdef]): + Replace descriptions of old --with- options with VAR=. + (Solaris 2.X): Suggest that defining _XOPEN_SOURCE and + __EXTENSIONS__ might help for 64-bit mode. + +2003-05-23 Tom Yu + + * admin.texinfo (appdefaults): Clarify afs_krb5 slightly. + +2003-05-22 Sam Hartman + + * admin.texinfo (appdefaults): Describe afs_krb5 + + * krb425.texinfo (AFS and the Appdefaults Section): Note about AFS and 2b tokens + +2003-05-13 Ken Raeburn + + * definitions.texinfo: Updated DefaultSupportedEnctypes. + +2003-05-12 Sam Hartman + + * definitions.texinfo: Default v4 mode is now none + +2003-04-18 Ken Raeburn + + * definitions.texinfo (DefaultETypeList, + DefaultSupportedEnctypes): Update for AES. + * install.texinfo (Client Machine Configuration Files): Fix typo + in variable reference. + +2003-04-08 Tom Yu + + * krb4-xrealm.txt: New file. Describe the krb4 cross-realm + patchkit. Copied from 2003-004-krb4_patchkit. + +2003-02-07 Ken Raeburn + + * copyright.texinfo: Add Yarrow, AES licenses. + +2003-02-04 Sam Hartman + + * krb425.texinfo (Upgrading KDCs): Note that -4 needs to be specified + +2003-01-30 Sam Hartman + + * definitions.texinfo: Remove bogus sample IPs and domains. + +2002-09-20 Ken Raeburn + + * admin.texinfo, dnssrv.texinfo: Documented config file variables + and SRV records to use for Kerberos TCP service, if it's enabled, + which it isn't by default. Removed UDP port 750 from the DNS SRV + recommendations. + +2002-09-20 Jen Selby + + * Makefile: made the list of manpages a variable + * admin.texinfo: took out second inclusion of copyright notice, + changed some section names, updated initial synopsis of file, + added explanation of encryption types and the [login] section of + krb5.conf, added documentation on various tags in the configuration + files, added some more examples, fixed some typos, updated usage + statements for various kadmin and kdb5_util commands, updated the + sample output from the commands, updated the infotex for use with + makeinfo --html, added a section about getting shared-realm keys, + updated the error codes + * build.texinfo: added a section describing the structure of the + source code tree, updated documentation of options to configure + script, added information about defaults for various variable + settings, updated information about shared library support, + added discussion of valid kerberos principals + * definitions.texinfo: added some new default variables, + corrected some pathnames of default values + * dnssrv.texinfo: made the information about default port numbers + reference a variable + * glossary.texinfo: updated definition of principal + * install.texinfo: fixed typos and formatting errors, removed old + sample config files from appendix (samples are in the sections about + the config files), added information about supporting RC4 keys + * kadm5.acl: new file. describes the kadm5.acl file. included by + both admin.texinfo and install.texinfo. text is made up mostly of + text that was split between those two documents. documentation + of backreferences was added + * kdcconf.texinfo: made defaults reference variables + * krb425.texinfo: deleted second inclusion of copyright info, + made defaults reference variable, fixed typos, took out redundant + part about editing inetd.conf and replaced it with reference to + install guide + * krb5conf.texinfo: documented the "final variable" feature, + added mention of the [login] section, + * send-pr.texinfo: minor change in wording for clarity + * user-guide.texinfo: made various minor wording changes, updated + some of the sample output, updated documention of command options + + +2002-09-13 Ken Raeburn + + * build.texinfo (Options to Configure): Update for new options + --with-system-db, DB_HEADER=, DB_LIB=. + +2002-09-03 Ken Raeburn + + * build.texinfo (Options to Configure): Update for new options + --with-system-et, --with-system-ss, SS_DIR=. + +2002-09-02 Ken Raeburn + + * build.texinfo (Options to Configure): Update for new "CC=" style + options replacing "--with-cc=" options. + +2002-07-03 Ezra Peisach + + * user-guide.texinfo: Change `@end rawhtml' to `@end html' Texinfo + 4 is more particular about matching @ifhtml (texinfo 3 did not + check). klist, ftp, and rcp postscript man pages have an + additional page now. + +2002-06-26 Jen Selby + + * Makefile: changed the way html output is generated, made "make all" + remove generated tex files + * admin.texinfo: added sections about encryption types and salts, + updated the configuration file sections, revised the example + configuration files, updated dates on output strings, added an + explanation of destroying a Kerberos database + * build.texinfo: changed the description of the tarball + * definitions.texinfo: added variables for all the default values + so that they can all be updated in one place, changed the release + from 1.2 to 1.3 + * dnstxt.texinfo updated the information + * install.texinfo added more description of the configuration files + and the minimum needed in the files to set up a kerberos realm, + revised the examples of the configuration file sections, took out + old encryption type and salt information + * kdcconf.texinfo: new file, taken from the admin guide and included + in both the admin and install guides, provides descriptions of the + sections in kdc.conf + * krb425.texinfo: moved a texinfo tag so that makeinfo --html would + work + * krb5conf.texinfo: new file, take from the admin guide and included + in both the admin and install guides, provides descriptions of the + sections in krb5.conf + * man2html, man2html.M: new files, a perl program to create html pages + from the output of the man command + * salts.texinfo: new file, a description of the different salt types + that are currently supported + * support-enc.texinfo: new file, a description of the currently + supported encryptions types + * user-guide.texinfo: added a section describing different ticket + flags, added a way to have the man pages in the reference section + accessible in the html version of the documentation + +2002-06-21 Ezra Eeisach + + * implementor.texinfo (IPv6 Support): Update fact that IRIX 6.5.16 + has enough support for configure to believe IPv6 support works, + but the libraries fail to provide a definition of in6addr_any + (although netinet/in.h implies it foes). + +2002-06-20 Sam Hartman + + * implementor.texinfo (Operating System Notes for Shared Libraries): Update why we don't use libtool + (Solaris Shared Library Support): Update + +2002-06-18 Ken Raeburn + + * implementor.texinfo: Don't use @smallbook. + (IPv6 Support): New chapter. + (Socket API): New placeholder chapter. + (Local Addresses, Host Address Lookup): Specify more precisely the + IRIX version we use at MIT. + (Thread Safety): Delete quoted email, since we don't actually have + this API yet. Refer people to the mailing list archives. + (Operating System Notes for Shared Libraries): Add an introduction + mentioning why we can't use libtool. + + * copyright.texinfo: Update copyright year. + +2002-05-30 Jen Selby + + * admin.texinfo, install.texinfo, dnssrv.texinfo, dnstxt.texinfo: + I corrected some minor typos. Moved DNS information to separate + files. Included these files in install guide (where they had + been) and in new sections in the admin guide. + +2002-05-08 Ken Raeburn + + * implementor.texinfo: Formatting updates. Tru64 5.1 SIOCGIFCONF + and getaddrinfo update. Description of fake-addrinfo.h and thread + safety problems. + +2002-03-13 Ken Raeburn + + * implementor.texinfo: Add chapters on local addresses, hostname + address lookups, and thread safety. + +2001-09-25 Ken Raeburn + + * admin.texinfo (realms (kdc.conf)): Add description of + reject_bad_transit realm option. + +2001-06-26 Ezra Peisach + + * user-guide.texinfo, install.texinfo: Cleanup makeinfo warning of + not having `.' or `,' after @xref. + +2001-01-19 Ken Raeburn + + * coding-style: Assume ANSI C '89. Use krb5int_ for internal + names. + +2000-07-12 Tom Yu + + * coding-style: Update after some discussion. Add sections + comparing to BSD KNF and GNU coding standards. + +2000-07-11 Tom Yu + + * coding-style: Some minor tweaks. Require do-while to always be + braced. Note some aspects of function pointer and array pointer + usage. Elaborate on function declaration practices. Add + placeholders for sections on Makefiles and test suites. + +2000-07-10 Tom Yu + + * coding-style: Another pass. Add secion on namespaces. + Elaborate some on null pointers. + +2000-07-10 Tom Yu + + * coding-style: First pass draft of coding standards. + +2000-06-30 Ken Raeburn + + * admin.texinfo (Kerberos V5 Database Library Error Codes): + Replace RCS Id strings with comments indicating that the RCS Id + string of the error table is used. + +2000-06-22 Tom Yu + + * build.texinfo (HPUX): Update note for HPUX compiler flags. + (Shared Library Support): Update shared lib support info. + +2000-06-16 Ken Raeburn + + * admin.texinfo: Update descriptions to indicate full support for + des3. Describe new DNS-related libdefaults tags for krb5.conf. + + * build.texinfo (Options to Configure): Fix @item labels. + + * install.texinfo: Update descriptions to indicate full support + for des3, and describe "v4" salt as being useful only with + des-cbc-crc. + +2000-06-15 Tom Yu + + * admin.texinfo: Note in multiple places that the current default + dump format doesn't include the per-principal policy information, + and some means of working around this problem. + + * install.texinfo (Switching Master and Slave KDCs): Note that + in the process of swapping KDCs, it is necessary to do a ov format + dump in order to preserve per-principal policy information. + +2000-06-13 Tom Yu + + * install.texinfo (Upgrading Existing Kerberos V5 Installations): + Add info describing how to preserve policy information while + upgrading. Also needs to go into other sections, possibly. + +2000-06-13 Ken Raeburn + + * build.texinfo: Enter correct xref info for DNS data + descriptions. Fix up text around some xrefs. + * install.texinfo: Describe SRV and TXT DNS records. Fix up text + around some xrefs. + +2000-06-09 Tom Yu + + * admin.texinfo: Add descriptions of the kadmin {ank,cpw,ktadd} -e + flag. + +2000-06-06 Ken Raeburn + + * install.texinfo: Describe new DNS support, and 3DES upgrade + path. Update "enctypes" config file sample lines. + + * build.texinfo: No kpasswd directory. Describe new configure + options. + + * send-pr.texinfo: Suggest caution regarding tab expansion for + patches. + +2000-06-02 Ken Raeburn + + * definitions.texinfo: Update for 1.2 release. + +2000-05-31 Ken Raeburn + + * krb425.texinfo (libdefaults): Add description of v4_realm. + +1999-09-22 Tom Yu + + * copyright.texinfo: Update copyright again. + +1999-09-17 Tom Yu + + * copyright.texinfo: Update copyright notice somewhat. + + * install.texinfo: Update info on upgrading a KDC for 1.1. + +1999-09-08 Ken Raeburn + + * install.texinfo (Mac OS X Configuration): Revised text from + Alexis, with more explanations of what's going on. + +1999-09-07 Ken Raeburn + + * definitions.texinfo: Update for 1.1 release. + + * admin.texinfo (Adding or Modifying Principals): Mention des3 + enctype for host keys. + + * build.texinfo: Replace "krb5-1.0" with "krb5-@value{RELEASE}" + throughout. + (Shared Library Support): Cut supported-OS list down to Solaris + and Irix for now. + + * install.texinfo: Update EDITION to 1.1. + (MacOS X Configuration): New node, with info from Brad Thompson. + (Encryption Types and Salt Types): Mention des3. + +1999-08-31 Ken Raeburn + + * admin.texinfo (Kadmin Options): Describe -e option. + (The User/Kerberos Interaction): Renamed from User--Kerberos to + avoid an apparent makeinfo 1.68 bug. + (realms (kdc.conf)): Document kdc_supported_enctypes, and mention + how des3 can be used there. Add des-cbc-crc:v4 to both enctype + lists, in the descriptions and in the examples. Delete + encryption_type, which doesn't exist. + (Date Format): Avoid 2-digit years, and add a warning about them. + +Fri Dec 13 15:10:44 1996 Tom Yu + + * admin.texinfo (The User--Kerberos Interaction): The environment + variable is KRB5CCNAME, not KRB5_CCNAME. + (Getting DNS Information Correct): It's Domain Name System, not + Distributed Name Service. + +Thu Dec 12 18:36:20 1996 Tom Yu + + * user-guide.texinfo: Bump edition to 1.0. Nuke gratuitous + vfills. Change @value{PRODUCT} to explicit reference, to avoid + makeinfo bug that introduces a nul character. + + * krb425.texinfo: Bump edition to 1.0. + + * build.texinfo (OS Incompatibilities): Refer to krb5-send-pr + instead of mail to krb5-bugs. + (Options to Configure): Change options to indicate meta-names, + e.g. "--prefix=PREFIX"; also nuke leading slash on some + descriptions of options. + + * admin.texinfo: Add more explicit linebreaks to prevent overruns; + also break up a few long lines in example program output. + +Fri Dec 6 13:58:19 1996 Tom Yu + + * .cvsignore: Ignore by suffix rather than by file. + + * Makefile (admin-guide-info): + (admin-guide-info): Update to reflect new info file name. + + * admin.texinfo: Change info file name to krb5-admin.info for + consistency. + (Administrating Kerberos Database Entries): "-c credentials_cache" + -> "-c ccache" to avoid overrun. + (Privileges): Null instance example is joeuser@REALM, not + joeuser/null@REALM. + + * install.texinfo (Kerberos Realms): SAN_FRANCISCO.FUBAR.ORG -> + HOUSTON.FUBAR.ORG to prevent margin overrun. + (Create a kadmind Keytab): Add explicit linebreak to prevent + margin overrun. + (Overview of This Guide): + (Installing Kerberos V5): Remove references to windows and mac + client machines for now. + + * krb425.texinfo: Use krb425.info instead of + Kerberos-V4-to-V5.info in the interest of shorter filenames. + + * user-guide.texinfo (Introduction): Eliminate "Kerberos V5 is + based on Kerberos V5". + (Ticket Management): Fix ref to "/rsh". + (rsh): Add explicit linebreak to avoid margin overrun. + + * krb425.texinfo (Upgrading KDCs): Use ROOTDIR rather than + INSTALLDIR to get the proper pathname. + + * send-pr.texinfo: Fix some misspellings, also remove references + to things that are only really applicable for Cygnus. + +Wed Dec 4 23:47:28 1996 Tom Yu + + * krb425.texinfo (Upgrading Application Servers): v5srvtab -> + krb5.keytab + +Mon Dec 2 13:00:26 1996 Barry Jaspan + + * build.texinfo (The DejaGnu Tests): info about .k5login for + krb-root tests [krb5-doc/261] + + * install.texinfo (Add Administrators to the Kerberos Database): + note relationship between acl file and admin principals + [krb5-doc/251] + (Edit the Configuration Files): mention the logging stanza here, + too, and tell people to check it when they start the daemons + [krb5-doc/253] + + * build.texinfo (The KADM5 Tests): add section for the kadm5 tests + [krb5-doc/247] + +Fri Nov 29 19:47:38 1996 Tom Yu + + * build.texinfo (Unpacking the Sources): Mention that ./krb5-1.0 + is the default directory that the tarballs will unpack into. + Also, "/u1/krb5" -> "/u1/krb5-1.0". + (osconf.h): Remove reference to DEFAULT_LNAME_FILENAME, as we're + no longer using the aname database code. + (Options to Configure): Add mention of --localstatedir + (Shared Library Support): It's Solaris 2.4/SunOS 5.4, not Solaris + 5.4. + (Solaris 2.X): Shared libs work with gcc. + + * install.texinfo (Mapping Hostnames onto Kerberos Realms): Fix + spacing error. + + * admin.texinfo: Fix up old references to "/krb5". + + * send-pr.texinfo: krb5-send-pr is in PREFIX/sbin, not PREFIX/bin. + + * admin.texinfo: "/lib/krb5kdc" -> "/var/krb5kdc" + + * krb425.texinfo (Upgrading Application Servers): Change flag + "cygnus" to "CYGNUS". + + * install.texinfo (Please Read the Documentation): Change flag + "cygnus" to "CYGNUS". + + * admin.texinfo (domain_realm): Change flag "cygnus" to "CYGNUS". + + * definitions.texinfo: Change /usr/@value{LCPRODUCT} to /usr/local + to sync with default paths. + + * admin.texinfo (domain_realm): Conditionalize "COM" vs "EDU" in + example. + + * install.texinfo (Create Host Keys for the Slave KDCs): Change + -randpass to -randkey. [244] + +Thu Nov 28 18:54:02 1996 Tom Yu + + * krb425.texinfo: Change to use "@chapternewpage odd", also frob + copyright page as per other docs. Also, remove footnote claiming + that "Kerberos V5 is based on the MIT beta7 release". + + * admin.texinfo (capaths): Fix unquoted braces. + (appdefaults): Fix unquoted braces. + +Wed Nov 27 18:27:18 1996 Jeffrey C. G. Bigler + + * Makefile: Added send-pr.texinfo to ADMIN_INCLUDES and + INSTALL_INCLUDES. + + * admin.texinfo: Added chapter on config files. Changed bug + reporting section to include send-pr file. + + * install.texinfo: Changed bug reporting section to include + send-pr file. Added reference to Sysadmin Guide chapter on config + files. + + * send-pr.texinfo: Fixed this up to match our version of + krb5-send-pr. + +Tue Nov 26 18:34:11 1996 Tom Yu + + * install.texinfo: Fix a couple of references to "@value{COMPANY}" + so they don't commit MIT to doing user support; also fixed some + punctuation errors. + +Mon Nov 25 23:39:53 1996 Theodore Y. Ts'o + + * copyright.texinfo: Change lib/kadm to lib/kadm5, and add the + kadmin/passwd to the list of directories containing OV + code. + +Sun Nov 24 23:55:52 1996 Ezra Peisach (epeisach@mit.edu) + + * build.texinfo: Remove --with-kdb-db section as it does not + exist. Add --with-tcl info. + +Tue Nov 19 13:42:00 1996 Barry Jaspan + + * install.texinfo, build.texinfo: misc suggestions from jhawk + [krb5-doc/55] + +Fri Nov 15 17:52:39 1996 Jeff Bigler + + * Makefile (krb425-guide): added section to make krb425 guide. + + * krb425.texinfo: brought in this document from Cygnus. + +Fri Nov 15 00:06:53 1996 Tom Yu + + * user-guide.texinfo: Changes to put copyright page in its own + node in the info file. + + * install.texinfo: Changes to put copyright page in its own node + in the info file. + + * admin.texinfo: Changes to put copyright page in its own node in + the info file, plus more krb5.keytab name updates. + + * install.texinfo (The Keytab File): + (Extract Host Keytabs for the KDCs): + (The Keytab File): + (Some Advice about Secure Hosts): Update filename to krb5.keytab. + (Upgrading the application servers): Add node to explain keytab + rename. + +Wed Nov 13 15:17:22 1996 Barry Jaspan + + * install.texinfo (kdc.conf): remove profile relation from + krb5.conf and kdc.conf [PR 124] + +Mon Nov 11 12:45:39 1996 Barry Jaspan + + * install.texinfo (kdc.conf): remove admin_database_name and + lockfile fields from sample kdc.conf + +Sun Nov 10 21:20:05 1996 Sam Hartman + + * bug-report.texinfo: We have krb5-send-pr now. + + * install.texinfo (Edit the Configuration Files): kdc.conf lives + in var/krb5kdc/kdc.conf + (krb5.conf): No, we will not tell people to log to /dev/ttyp9; + default to /var/log + (Slave KDCs): Avoid over committing MIT to random things that + other vendors might want to do. + (Limit Access to the KDCs): If you are running klogind -c you want -5 not -k + (Some Advice about Secure Hosts): We disable things in /etc/inetd.conf not /etc/services + +Tue Nov 5 16:14:06 1996 Barry Jaspan + + * install.texinfo (Upgrading existing Master and Slave KDCs to the + current release): added section on upgrading to new db format with + dump/load [krb5-doc/119] + +Mon Nov 4 16:50:51 1996 Barry Jaspan + + * admin.texinfo (Adding or Modifying Principals): update kadmin + "default" policy semantics [krb5-doc/84] + + * install.texinfo: various minor comments from jhawk [krb5-doc/55] + +Fri Nov 1 19:05:15 1996 Tom Yu + + * .cvsignore: Ignore the .html files. + + * copyright.texinfo: Add call to "@pagealignmacro" to force a + blank page after copyright spewage. [krb5-doc/54] + + * Makefile: Apply jik's changes for dependencies [krb5-doc/101] + + * install.texinfo (krb5.conf): Fixed extra + closebrace. [krb5-doc/92] + +Fri Oct 18 13:42:49 1996 Barry Jaspan + + * install.texinfo (Create a kadmind Keytab): use kadmin.local + instead of kadmin to perform pre-kadmind setup [krb5-admin/28] + +Tue Sep 10 20:47:41 1996 Theodore Y. Ts'o + + * user-guide.texinfo: The telnet man page only has 9 pages; the + rcp man page only has 1 page. + +Mon Sep 9 19:35:37 1996 Theodore Ts'o + + * build.texinfo: Updated to reflect latest OS inconsistencies; + removed shared library theory section to a new file, + implementor.texinfo, which will have information that only + developers will care about. + +Mon Sep 9 13:25:06 1996 Jeff Bigler + + * texinfo-suppl.tex: extracted @doubleleftarrow{} hack into + separate file so we don't have to ship a modified version of + texinfo.tex. + + * user-guide.texinfo (Reference): changed offset to -700 for + PostScript man pages for full page printing. + + * man2ps: changed scale from 0.7 to 0.85 for full page printing. + Piped csplit output to /dev/null, to make it a bit neater. + +Fri Sep 6 19:59:12 1996 Theodore Y. Ts'o + + * copyright.texinfo: Updated copyright dates and modify copyright + text to have non-commital words about export licenses. + + * admin.texinfo, install.texinfo: Set edition to "b7-1". + + * user-guide.texinfo: Set edition to "b7-1". Fix the hoffset and + voffsets for the included man page poscript files so that + the images are lined up correctly (at least using MIT's + dvips). + + * Makefile (user-guide): Make sure the kpasswd man page's + postscript is built. Add new target "clean-temp-ps" which + cleans up the temporary postscript files. + + * man2ps: Changes to make man2ps more portable. Remove bash + specific constructs, and replace with calls to expr. + Since the arguments to "troff" require groff, just try to + run groff explicitly (someone can always edit the ROFF and + ROFF_OPTIONS at the top of the script). Try to + automatically detect whether csplit or gcsplit should be + used, by grovelling through the user's path. + + * texinfo.tex: Check in version of texinfo.tex that has Jeff's + magic doubleleft arrow hack. + +Fri Sep 6 12:59:43 1996 Jeff Bigler + + * install.texinfo: new name for cyg-install.texinfo + + * install-old.texi: new name for install.texi (so we know what's + what.) + + * Makefile (install-guide): renamed cyg-install.texinfo to + install.texinfo. + + * man2ps: shell script to create postscript include files for + user's guide. + + * man2ps.M: man page for above shell script + + * build.texinfo: this is now included by cyg-install.texinfo + (which should eventually replace install.texi.) + + * definitions.texinfo: added flags "MIT" and "CYGNUS". + + * cyg-install.texinfo: added @ifset and @ifclear sections to + separate MIT-specific and Cygnus-specific sections. + + * admin.texinfo: added @ifset and @ifclear sections as with + cyg-install.texinfo + + * Makefile: rewrote entire contents of file. + +Fri Sep 6 01:22:56 1996 Theodore Y. Ts'o + + * build.texinfo: Remove --enable options which are no longer + valid. Updated reference to dejagnu. + +Thu Apr 18 14:38:42 1996 Theodore Y. Ts'o + + * install.texi (Building using lndir): Minor grammer fix. + +Sun Apr 21 14:01:29 1996 Sam Hartman + + * install.texi (Installing Kerberos Applications): Updated to fix + jhawk's comments to this section. + +Sat Apr 20 03:27:27 1996 Sam Hartman + + * install.texi (Top): Remade master menu. + (Installing Kerberos Applications): New section. + +Fri Apr 19 22:55:36 1996 Sam Hartman + + * install.texi (Shared Library Support): Update to better reflect + reality on AIX. + +Tue Mar 19 10:34:20 1996 Ezra Peisach + + * Makefile (clean): Remove *.info-? now. + + * install.texi: Changes to allow emacs M-X texinfo-format-buffer + to work. (The problem was @item used within @enumerate). + +Fri Mar 8 09:43:13 1996 Ezra Peisach + + * install.texi (The DejaGnu Tests): Describe the DejaGnu tests. + +Mon Oct 30 16:58:54 1995 Ezra Peisach + + * install.texi: Fix all path names, spelling check, convert tabs + to spaces. + +Fri Oct 20 14:06:35 1995 Ezra Peisach + + * install.texi (Shared Library Support): Document shared library + specifics. + +Tue Oct 17 19:23:50 1995 Ezra Peisach + + * .Sanitize (Things-to-keep): Add Makefile + + * Makefile: Simple file to build both dvi and info versions of + install and allow for easy cleaning. + + * install.texi (Options to Configure): Updated to reflect current + major configuration options. + +Wed Oct 11 16:20:58 1995 Ezra Peisach (epeisach@kangaroo.mit.edu) + + * install.texi: Remove config.h descriptions, describe krb5.conf. + +Tue Jul 11 13:07:00 1995 + + * install.texi: BSDI fixes. + +Fri May 5 13:10:38 1995 Theodore Y. Ts'o (tytso@dcl) + + * install.texi: Minor fixups for beta 5 release. Mainly points + that the krb.conf and krb.realms section need to be + updated and should be ignored in favor of the krb5.conf + manual page. + +Fri Apr 28 16:59:41 EDT 1995 Paul Park (pjpark@mit.edu) + Add new kadmin.protocol. + +Wed Feb 22 18:56:06 1995 John Gilmore (gnu at toad.com) + + * install.texi: Minor corrections. Add info about bare source + trees (without configure scripts). + diff --git a/mechglue/doc/Makefile b/mechglue/doc/Makefile new file mode 100644 index 000000000..652cf9da2 --- /dev/null +++ b/mechglue/doc/Makefile @@ -0,0 +1,183 @@ +SRCDIR=../src +DVI=texi2dvi +DVIPS=dvips -o "$@" +PSPDF=ps2pdf +INFO=makeinfo +HTML=makeinfo --html +RM=rm -f +TAR=tar -chvf +GZIP=gzip -9 +MANPS=./man2ps +MANTXT=nroff -man +MANHTML=./man2html + +ADMIN_INCLUDES=definitions.texinfo copyright.texinfo document-list.texinfo \ + glossary.texinfo support-enc.texinfo salts.texinfo krb5conf.texinfo \ + kdcconf.texinfo dnstxt.texinfo dnssrv.texinfo send-pr.texinfo +ADMIN_DEPS=admin.texinfo $(ADMIN_INCLUDES) + +INSTALL_INCLUDES=definitions.texinfo copyright.texinfo document-list.texinfo \ + dnstxt.texinfo dnssrv.texinfo build.texinfo bug-report.texinfo \ + krb5conf.texinfo kdcconf.texinfo send-pr.texinfo +INSTALL_DEPS=install.texinfo $(INSTALL_INCLUDES) + +MANPAGES=$(SRCDIR)/appl/gssftp/ftp/ftp.M $(SRCDIR)/clients/kdestroy/kdestroy.M $(SRCDIR)/clients/kinit/kinit.M $(SRCDIR)/clients/klist/klist.M $(SRCDIR)/clients/ksu/ksu.M $(SRCDIR)/appl/bsd/rcp.M $(SRCDIR)/appl/bsd/rlogin.M $(SRCDIR)/appl/bsd/rsh.M $(SRCDIR)/appl/telnet/telnet/telnet.1 $(SRCDIR)/kadmin/passwd/kpasswd.M + +USER_GUIDE_INCLUDES=definitions.texinfo copyright.texinfo glossary.texinfo +USER_GUIDE_DEPS=user-guide.texinfo $(USER_GUIDE_INCLUDES) + +KRB425_INCLUDES=definitions.texinfo copyright.texinfo +KRB425_DEPS=krb425.texinfo $(KRB425_INCLUDES) + +.PHONY: all +all:: admin-guide-full install-guide-full user-guide-full krb425-guide-full clean-temp-ps clean-tex + +.PHONY: admin-guide-full +admin-guide-full:: admin-guide admin-guide-info admin-guide-html + +.PHONY: admin-guide +admin-guide:: admin-guide.ps + +admin-guide.ps: $(ADMIN_DEPS) + $(DVI) admin.texinfo + $(DVIPS) admin + +admin-guide.pdf: admin-guide.ps + $(PSPDF) admin-guide.ps admin-guide.pdf + +.PHONY: admin-guide-html +admin-guide-html:: admin.html + +admin.html: $(ADMIN_DEPS) + $(HTML) admin.texinfo + +.PHONY: admin-guide-info +admin-guide-info:: krb5-admin.info + +krb5-admin.info: $(ADMIN_DEPS) + $(INFO) admin.texinfo + +.PHONY: install-guide-full +install-guide-full:: install-guide install-guide-info install-guide-html + +.PHONY: install-guide +install-guide:: install-guide.ps + +install-guide.ps: $(INSTALL_DEPS) + $(DVI) install.texinfo + $(DVIPS) install + +install-guide.pdf: install-guide.ps + $(PSPDF) install-guide.ps install-guide.pdf + +.PHONY: install-guide-html +install-guide-html:: install.html + +install.html:: $(INSTALL_DEPS) + $(HTML) install.texinfo + +.PHONY: install-guide-info +install-guide-info:: krb5-install.info + +krb5-install.info: $(INSTALL_DEPS) + $(INFO) install.texinfo + +.PHONY: user-guide-full +user-guide-full:: user-guide user-guide-info user-guide-html + +.PHONY: user-guide +user-guide:: user-guide.ps + +user-guide.ps: $(USER_GUIDE_DEPS) + $(DVI) user-guide.texinfo + $(MANPS) $(MANPAGES) + $(DVIPS) user-guide + +user-guide.pdf: user-guide.ps + $(PSPDF) user-guide.ps user-guide.pdf + +.PHONY: user-guide-info +user-guide-info:: krb5-user.info + +krb5-user.info: $(USER_GUIDE_DEPS) + $(INFO) user-guide.texinfo + +.PHONY: user-guide-html +user-guide-html:: user-guide.html + +user-guide.html: $(USER_GUIDE_DEPS) + $(MANTXT) $(SRCDIR)/appl/gssftp/ftp/ftp.M | $(MANHTML) > ftp.html + $(MANTXT) $(SRCDIR)/clients/kdestroy/kdestroy.M | $(MANHTML) > kdestroy.html + $(MANTXT) $(SRCDIR)/clients/kinit/kinit.M | $(MANHTML) > kinit.html + $(MANTXT) $(SRCDIR)/clients/klist/klist.M | $(MANHTML) > klist.html + $(MANTXT) $(SRCDIR)/clients/ksu/ksu.M | $(MANHTML) > ksu.html + $(MANTXT) $(SRCDIR)/appl/bsd/rcp.M | $(MANHTML) > rcp.html + $(MANTXT) $(SRCDIR)/appl/bsd/rlogin.M | $(MANHTML) > rlogin.html + $(MANTXT) $(SRCDIR)/appl/bsd/rsh.M | $(MANHTML) > rsh.html + $(MANTXT) $(SRCDIR)/appl/telnet/telnet/telnet.1 | $(MANHTML) > telnet.html + $(MANTXT) $(SRCDIR)/kadmin/passwd/kpasswd.M | $(MANHTML) > kpasswd.html + $(HTML) user-guide.texinfo + +.PHONY: krb425-guide-full +krb425-guide-full:: krb425-guide krb425-guide-info krb425-guide-html + +.PHONY: krb425-guide +krb425-guide:: krb425-guide.ps + +krb425-guide.ps: $(KRB425_DEPS) + $(DVI) krb425.texinfo + $(DVIPS) krb425 + +.PHONY: krb425-guide-html +krb425-guide-html:: krb425.html + +krb425.html:: $(KRB425_DEPS) + $(HTML) krb425.texinfo + +.PHONY: krb425-guide-info +krb425-guide-info:: krb425.info + +krb425.info: $(KRB425_DEPS) + $(INFO) krb425.texinfo + +.PHONY: implementor.ps implementor.pdf implementor.info +implementor.pdf: implementor.ps + $(PSPDF) implementor.ps +implementor.ps: implementor.texinfo + $(DVI) implementor.texinfo + $(DVIPS) implementor +implementor.info: implementor.texinfo + $(INFO) implementor.texinfo + +.PHONY: clean +clean:: clean-all + +.PHONY: clean-all +clean-all:: clean-tex clean-backup clean-final clean-tarfiles + +.PHONY: clean-final +clean-final:: + $(RM) *.ps *.info *.info-? *.html *.pdf + +.PHONY: clean-tex +clean-tex:: + $(RM) *.aux *.cp *.dvi *.fn *.ky *.log *.pg *.toc *.tp *.vr *.fns *.vrs *.tps + +.PHONY: clean-backup +clean-backup:: + $(RM) *~ #* + +.PHONY: clean-tarfiles +clean-tarfiles:: + $(RM) *.tar *.tar.gz *.tgz + +.PHONY: clean-temp-ps +clean-temp-ps:: + $(RM) ftp?.ps kinit?.ps klist?.ps kdestroy?.ps ksu?.ps rlogin?.ps \ + rcp?.ps rsh?.ps telnet?.ps kpasswd?.ps + +.PHONY: tgz +tgz:: + $(TAR) krb5-docs.tar admin.texinfo build.texinfo copyright.texinfo definitions.texinfo document-list.texinfo glossary.texinfo install.texinfo texinfo.tex user-guide.texinfo *-guide.ps *.info *.info-? *.html + $(GZIP) krb5-docs.tar + $(MV) krb5-docs.tar.gz krb5-docs.tgz diff --git a/mechglue/doc/admin.texinfo b/mechglue/doc/admin.texinfo new file mode 100644 index 000000000..ec20a89d0 --- /dev/null +++ b/mechglue/doc/admin.texinfo @@ -0,0 +1,3782 @@ +\input texinfo-suppl.tex % contains @doubleleftarrow{} definition + % this line must come *before* \input texinfo +\input texinfo @c -*-texinfo-*- +@c %**start of header +@c guide +@setfilename krb5-admin.info +@settitle Kerberos V5 System Administrator's Guide +@setchapternewpage odd @c chapter begins on next odd page +@c @setchapternewpage on @c chapter begins on next page +@c @smallbook @c Format for 7" X 9.25" paper +@c %**end of header +@paragraphindent 0 +@iftex +@parskip 6pt plus 6pt +@end iftex + +@include definitions.texinfo +@set EDITION 1.0 +@set UPDATED June 16, 2000 + +@finalout @c don't print black warning boxes + +@titlepage +@title @value{PRODUCT} System Administrator's Guide +@subtitle Release: @value{RELEASE} +@subtitle Document Edition: @value{EDITION} +@subtitle Last updated: @value{UPDATED} +@author @value{COMPANY} + +@page +@vskip 0pt plus 1filll + +@end titlepage + +@comment node-name, next, previous, up +@node Top, Copyright, (dir), (dir) + +@ifinfo +This document describes how to administrate a @value{PRODUCT} +installation. +@end ifinfo + +@c The master menu is updated using emacs19's M-x texinfo-all-menus-update +@c function. Don't forget to run M-x texinfo-every-node-update after +@c you add a new section or subsection, or after you've rearranged the +@c order of sections or subsections. Also, don't forget to add an @node +@c comand before each @section or @subsection! All you need to enter +@c is: +@c +@c @node New Section Name +@c @section New Section Name +@c +@c M-x texinfo-every-node-update will take care of calculating the +@c node's forward and back pointers. +@c +@c --------------------------------------------------------------------- + +@menu +* Copyright:: +* Introduction:: +* How Kerberos Works:: +* Configuration Files:: +* Using DNS:: +* Administrating the Kerberos Database:: +* Application Servers:: +* Backups of Secure Hosts:: +* Bug Reporting:: +* Appendix:: +@end menu + +@node Copyright, Introduction, Top, Top +@unnumbered Copyright +@include copyright.texinfo + + +@node Introduction, How Kerberos Works, Copyright, Top +@chapter Introduction + +@menu +* Why Should I use Kerberos?:: +* Documentation for Kerberos V5:: +* Overview of This Guide:: +@end menu + +@node Why Should I use Kerberos?, Documentation for Kerberos V5, Introduction, Introduction +@section Why Should I use Kerberos? + +Since Kerberos negotiates authenticated, and optionally encrypted, +communications between two points anywhere on the internet, it provides +a layer of security that is not dependent on which side of a firewall +either client is on. Since studies have shown that half of the computer +security breaches in industry happen from @i{inside} firewalls, +@value{PRODUCT} from @value{COMPANY} will play a vital role in the +security of your network. + +@node Documentation for Kerberos V5, Overview of This Guide, Why Should I use Kerberos?, Introduction +@section Documentation for @value{PRODUCT} + +@include document-list.texinfo + +@node Overview of This Guide, , Documentation for Kerberos V5, Introduction +@section Overview of This Guide + +The next chapter describes how Kerberos works. + +Chapter three describes administration of the principals in the Kerberos +database. + +Chapter four describes how you can use DNS in configuring your Kerberos realm. + +Chapter five describes administrative programs for manipulating the +Kerberos database as a whole. + +Chapter six describes issues to consider when adding an application +server to the database. + +Chapter seven describes our problem reporting system. + +The appendices include the list of Kerberos error messages, and a +complete list of the time zones understood by @code{kadmin}. + +@node How Kerberos Works, Configuration Files, Introduction, Top +@chapter How Kerberos Works + +This section provides a simplified description of a general user's +interaction with the Kerberos system. This interaction happens +transparently---users don't need to know and probably don't care about +what's going on---but Kerberos administrators might find a schematic +description of the process useful. This description glosses over a lot +of details; for more information, see @i{Kerberos: An Authentication +Service for Open Network Systems}, a paper presented at Winter USENIX +1988, in Dallas, Texas. This paper can be retreived by FTP from +@code{athena-dist.mit.edu}, in the location: +@code{/pub/ATHENA/kerberos/doc/usenix.PS}. + +@menu +* Network Services and Their Client Programs:: +* Kerberos Tickets:: +* The Kerberos Database:: +* Kerberos Realms:: +* The Ticket-Granting Ticket:: +* Network Services and the Master Database:: +* The User/Kerberos Interaction:: +* Definitions:: +@end menu + +@node Network Services and Their Client Programs, Kerberos Tickets, How Kerberos Works, How Kerberos Works +@section Network Services and Their Client Programs + +In an environment that provides network services, you use @dfn{client} +programs to request @dfn{services} from @dfn{server} programs that are +somewhere on the network. Suppose you have logged in to a workstation +and you want to @samp{rlogin} to a typical UNIX host. You use the local +@samp{rlogin} client program to contact the remote machine's +@samp{rlogind} daemon. + +@node Kerberos Tickets, The Kerberos Database, Network Services and Their Client Programs, How Kerberos Works +@section Kerberos Tickets + +Under Kerberos, the @samp{klogind} daemon allows you to login to a +remote machine if you can provide @samp{klogind} a Kerberos ticket +which proves your identity. In addition to the ticket, you must also +have possession of the corresponding ticket session key. The +combination of a ticket and the ticket's session key is known as a credential. + +Typically, a client program automatically obtains credentials +identifying the person using the client program. The credentials are +obtained from a Kerberos server that resides somewhere on the network. +A Kerberos server maintains a database of user, server, and password +information. + +@node The Kerberos Database, Kerberos Realms, Kerberos Tickets, How Kerberos Works +@section The Kerberos Database + +Kerberos will give you credentials only if you have an entry in the +Kerberos server's @dfn{Kerberos database}. Your database entry includes +your Kerberos @dfn{principal} (an identifying string, which is often +just your username), and your Kerberos password. Every Kerberos user +must have an entry in this database. + +@node Kerberos Realms, The Ticket-Granting Ticket, The Kerberos Database, How Kerberos Works +@section Kerberos Realms + +Each administrative domain will have its own Kerberos database, which +contains information about the users and services for that particular +site or administrative domain. This administrative domain is the +@dfn{Kerberos realm}. + +Each Kerberos realm will have at least one Kerberos server, where the +master Kerberos database for that site or administrative domain is +stored. A Kerberos realm may also have one or more @dfn{slave servers}, +which have read-only copies of the Kerberos database that are +periodically propagated from the master server. For more details on how +this is done, see the ``Set Up the Slave KDCs for Database Propagation'' +and ``Propagate the Database to Each Slave KDC'' sections of the +@value{PRODUCT} Installation Guide. + +@node The Ticket-Granting Ticket, Network Services and the Master Database, Kerberos Realms, How Kerberos Works +@section The Ticket-Granting Ticket + +The @samp{kinit} command prompts for your password. If you enter it +successfully, you will obtain a @dfn{ticket-granting ticket} and a +@dfn{ticket session key} which gives you the right to use the ticket. +This combination of the ticket and its associated key is known as your +@dfn{credentials}. As illustrated below, client programs use your +ticket-granting ticket credentials in order to obtain client-specific +credentials as needed. + +Your credentials are stored in a @dfn{credentials cache}, which is often +just a file in @code{/tmp}. The credentials cache is also called the +@dfn{ticket file}, especially in Kerberos V4 documentation. Note, +however, that a credentials cache does not have to be stored in a file. + +@node Network Services and the Master Database, The User/Kerberos Interaction, The Ticket-Granting Ticket, How Kerberos Works +@section Network Services and the Master Database + +The master database also contains entries for all network services that +require Kerberos authentication. Suppose that your site has a machine, +@samp{laughter.@value{PRIMARYDOMAIN}}, that requires Kerberos +authentication from anyone who wants to @samp{rlogin} to it. The host's +Kerberos realm is @samp{@value{PRIMARYREALM}}. + +This service must be registered in the Kerberos database, using the +proper service name, which in this case is the @dfn{principal}: + +@smallexample +host/laughter.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} +@end smallexample + +@noindent +The @samp{/} character separates the Kerberos @dfn{primary} (in this +case, @samp{host}) from the @dfn{instance} (in this case, +@samp{laughter.@value{PRIMARYDOMAIN}}); the @samp{@@} character separates +the realm name (in this case, @samp{@value{PRIMARYREALM}}) from the rest +of the principal. The primary, @samp{host}, denotes the name or type of +the service that is being offered: generic host-level access to the +machine. The instance, @samp{laughter.@value{PRIMARYDOMAIN}}, names the +specific machine that is offering this service. There will generally be +many different machines, each offering one particular type of service, +and the instance serves to give each one of these servers a different +Kerberos principal. + +@menu +* The Keytab File:: +@end menu + +@node The Keytab File, , Network Services and the Master Database, Network Services and the Master Database +@subsection The Keytab File + +For each service, there must also be a @dfn{service key} known only by +Kerberos and the service. On the Kerberos server, the service key is +stored in the Kerberos database. + +On the server host, these service keys are stored in @dfn{key tables}, +which are files known as @dfn{keytabs}.@footnote{Keytabs were called +@dfn{srvtabs} in Kerberos V4.} For example, the service keys used by +services that run as root are usually stored in the keytab file +@code{/etc/krb5.keytab}. @b{N.B.:} This service key is the equivalent +of the service's password, and must be kept secure. Data which is meant +to be read only by the service is encrypted using this key. + +@node The User/Kerberos Interaction, Definitions, Network Services and the Master Database, How Kerberos Works +@section The User/Kerberos Interaction + +Suppose that you walk up to a host intending to login to it, and then +@samp{rlogin} to the machine @samp{laughter}. Here's what happens: + +@enumerate +@item +You login to the workstation and use the @samp{kinit} command to get a +ticket-granting ticket. This command prompts you for your Kerberos +password. (On systems running the @value{PRODUCT} @samp{login} program, +this may be done as part of the login process, not requiring the user to +run a separate program.) + +@enumerate A +@item +The @samp{kinit} command sends your request to the Kerberos master +server machine. The server software looks for your principal name's +entry in the Kerberos database. + +@item +If this entry exists, the Kerberos server creates and returns a +ticket-granting ticket and the key which allows you to use it, encrypted +by your password. If @samp{kinit} can decrypt the Kerberos reply using +the password you provide, it stores this ticket in a credentials cache +on your local machine for later use. The name of the credentials cache +can be specified in the @samp{KRB5CCNAME} environment variable. If this +variable is not set, the name of the file will be +@file{/tmp/krb5cc_}, where is your UNIX user-id, represented +in decimal format. +@end enumerate + +@need 1500 +@item +Now you use the @samp{rlogin} client to access the machine +@samp{laughter}. + +@example +host% @b{rlogin laughter} +@end example + +@enumerate A +@item +The @samp{rlogin} client checks your ticket file to see if you have a +ticket for the @samp{host} service for @samp{laughter}. You don't, so +@samp{rlogin} uses the credential cache's ticket-granting ticket to make +a request to the master server's ticket-granting service. + +@item +This ticket-granting service receives the request for a ticket for +@samp{host/laughter.@value{PRIMARYDOMAIN}}, and looks in the master +database for an entry for @samp{host/laughter.@value{PRIMARYDOMAIN}}. +If the entry exists, the ticket-granting service issues you a ticket for +that service. That ticket is also cached in your credentials cache. + +@item +The @samp{rlogin} client now sends that ticket to the @samp{laughter} +@samp{klogind} service program. The service program checks the ticket +by using its own service key. If the ticket is valid, it now knows your +identity. If you are allowed to login to @samp{laughter} (because your +username matches one in /etc/passwd, or your Kerberos principal is in +the appropriate @file{.k5login} file), @code{klogind} will let you +login. +@end enumerate +@end enumerate + +@node Definitions, , The User/Kerberos Interaction, How Kerberos Works +@section Definitions + +Following are definitions of some of the Kerberos terminology. + +@include glossary.texinfo + +@node Configuration Files, Using DNS, How Kerberos Works, Top +@chapter Configuration Files + +@menu +* Supported Encryption Types:: +* Salts:: +* krb5.conf:: +* kdc.conf:: +@end menu + +@node Supported Encryption Types, Salts, Configuration Files, Configuration Files +@section Supported Encryption Types + +Any tag in the configuration files which requires a list of encryption +types can be set to some combination of the following strings. + +@include support-enc.texinfo + +While aes128-cts and aes256-cts are supported for all Kerberos +operations, they are not supported by older versions of our GSSAPI +implementation (krb5-1.3.1 and earlier). + +By default, AES is enabled in this release. Sites wishing to use AES +encryption types on their KDCs need to be careful not to give GSSAPI +services AES keys if the servers have not been updated. If older +GSSAPI services are given AES keys, then services may fail when +clients supporting AES for GSSAPI are used. Sites may wish to use AES +for user keys and for the ticket granting ticket key, although doing +so requires specifying what encryption types are used as each +principal is created. + +If all GSSAPI-based services have been updated before or with the KDC, +this is not an issue. + +@node Salts, krb5.conf, Supported Encryption Types, Configuration Files +@section Salts + +Your Kerberos key is derived from your password. To ensure that people +who happen to pick the same password do not have the same key, Kerberos +5 incorporates more information into the key using something called a +salt. The supported values for salts are as follows. + +@include salts.texinfo + +@node krb5.conf, kdc.conf, Salts, Configuration Files +@section krb5.conf + +@include krb5conf.texinfo + +@menu +* libdefaults:: +* appdefaults:: +* login:: +* realms (krb5.conf):: +* domain_realm:: +* logging:: +* capaths:: +* Sample krb5.conf File:: +@end menu + +@node libdefaults, appdefaults, krb5.conf, krb5.conf +@subsection [libdefaults] + +The @code{libdefaults} section may contain any of the following +relations: + +@table @b +@itemx default_keytab_name +This relation specifies the default keytab name to be used by +application servers such as telnetd and rlogind. The default is +@value{DefaultDefaultKeytabName}. + +@itemx default_realm +Identifies the default Kerberos realm for the client. Set its value to +your Kerberos realm. If this is not specified and the TXT record +lookup is enabled (see @ref{Using DNS}), then that information will be +used to determine the default realm. If this tag is not set in this +configuration file and there is no DNS information found, then an error +will be returned. + +@itemx default_tgs_enctypes +Identifies the supported list of session key encryption types that +should be returned by the KDC. The list may be delimited with commas +or whitespace. Kerberos supports many different encryption types, and +support for more is planned in the future. (see @ref{Supported Encryption +Types} for a list of the accepted values for this tag). The default +value is @value{DefaultDefaultTgsEnctypes}. + +@itemx default_tkt_enctypes +Identifies the supported list of session key encryption types that +should be requested by the client. The format is the same as for +@emph{default_tgs_enctypes}. The default value for this tag is +@value{DefaultDefaultTktEnctypes}. + +@itemx permitted_enctypes +Identifies all encryption types that are permitted for use in session +key encryption. The default value for this tag is +@value{DefaultPermittedEnctypes}. + +@itemx clockskew +Sets the maximum allowable amount of clockskew in seconds that the +library will tolerate before assuming that a Kerberos message is +invalid. The default value is @value{DefaultClockskew}. + +@itemx kdc_timesync +If this is set to 1 (for true), then client machines will compute the +difference between their time and the time returned by the KDC in the +timestamps in the tickets and use this value to correct for an +inaccurate system clock. This corrective factor is only used by the +Kerberos library. The default is @value{DefaultKDCTimesync}. + +@itemx kdc_req_checksum_type +@itemx ap_req_checksum_type +@itemx safe_checksum_type +An integer which specifies the type of checksum to use. Used for +compatability with DCE security servers which do not support the +default @value{DefaultChecksumType} used by this version of Kerberos. +The possible values and their meanings are as follows. + +@comment taken from krb5/src/include/krb5.h[in] +@table @b +@item 1 +CRC32 +@item 2 +RSA MD4 +@item 3 +RSA MD4 DES +@item 4 +DES CBC +@item 7 +RSA MD5 +@item 8 +RSA MD5 DES +@item 9 +NIST SHA +@item 12 +HMAC SHA1 DES3 +@item -138 +Microsoft MD5 HMAC checksum type +@end table + +@comment see lib/krb5/ccache/fcc.h +@itemx ccache_type +Use this parameter on systems which are DCE clients, to specify the +type of cache to be created by kinit, or when forwarded tickets are +received. DCE and Kerberos can share the cache, but some versions of +DCE do not support the default cache as created by this version of +Kerberos. Use a value of 1 on DCE 1.0.3a systems, and a value of 2 on +DCE 1.1 systems. The default value is @value{DefaultCcacheType}. + +@ignore +@itemx tkt_lifetime +The default lifetime of a ticket. The default is +@value{DefaultTktLifetime}. This is currently not supported by the +code. +@end ignore + +@itemx krb4_srvtab +Specifies the location of the Kerberos V4 srvtab file. Default is +@value{DefaultKrb4Srvtab}. + +@itemx krb4_config +Specifies the location of hte Kerberos V4 configuration file. Default +is @value{DefaultKrb4Config}. + +@itemx krb4_realms +Specifies the location of the Kerberos V4 domain/realm translation +file. Default is @value{DefaultKrb4Realms}. + +@itemx dns_lookup_kdc +Indicate whether DNS SRV records should be used to locate the KDCs and +other servers for a realm, if they are not listed in the information for +the realm. (Note that the @samp{admin_server} entry must be in the +file, because the DNS implementation for it is incomplete.) + +Enabling this option does open up a type of denial-of-service attack, if +someone spoofs the DNS records and redirects you to another server. +However, it's no worse than a denial of service, because that fake KDC +will be unable to decode anything you send it (besides the initial +ticket request, which has no encrypted data), and anything the fake KDC +sends will not be trusted without verification using some secret that it +won't know. + +If this option is not specified but @samp{dns_fallback} is, that value +will be used instead. If neither option is specified, the behavior +depends on configure-time options; if none were given, the default is to +enable this option. If the DNS support is not compiled in, this entry +has no effect. + +@itemx dns_lookup_realm +Indicate whether DNS TXT records should be used to determine the +Kerberos realm of a host. + +Enabling this option may permit a redirection attack, where spoofed DNS +replies persuade a client to authenticate to the wrong realm, when +talking to the wrong host (either by spoofing yet more DNS records or by +intercepting the net traffic). Depending on how the client software +manages hostnames, however, it could already be vulnerable to such +attacks. We are looking at possible ways to minimize or eliminate this +exposure. For now, we encourage more adventurous sites to try using +Secure DNS. + +If this option is not specified but @samp{dns_fallback} is, that value +will be used instead. If neither option is specified, the behavior +depends on configure-time options; if none were given, the default is to +disable this option. If the DNS support is not compiled in, this entry +has no effect. + +@itemx dns_fallback +General flag controlling the use of DNS for Kerberos information. If +both of the preceding options are specified, this option has no effect. + +@itemx extra_addresses +This allows a computer to use multiple local addresses, in order to +allow Kerberos to work in a network that uses NATs. The addresses +should be in a comma-separated list. + +@itemx udp_preference_limit +When sending a message to the KDC, the library will try using TCP before +UDP if the size of the message is above @code{udp_preference_list}. +If the message is smaller than @code{udp_preference_list}, then UDP +will be tried before TCP. Regardless of the size, both protocols will +be tried if the first attempt fails. + +@itemx verify_ap_req_nofail +If this flag is set, then an attempt to get initial credentials will +fail if the client machine does not have a keytab. The default for the +flag is @value{DefaultVerifyApReqNofail}. + +@itemx renew_lifetime +The value of this tag is the default renewable lifetime for +initial tickets. The default value for the tag is +@value{DefaultRenewLifetime}. + +@itemx noaddresses +Setting this flag causes the initial Kerberos ticket to be addressless. +The default for the flag is @value{DefaultNoaddresses}. + +@itemx forwardable +If this flag is set, initial tickets by default will be forwardable. +The default value for this flag is @value{DefaultForwardable}. + +@itemx proxiable +If this flag is set, initial tickets by default will be proxiable. +The default value for this flag is @value{DefaultProxiable}. + +@end table + +@node appdefaults, login, libdefaults, krb5.conf +@subsection [appdefaults] + +Each tag in the [appdefaults] section names a Kerberos V5 application +or an option that is used by some Kerberos V5 application[s]. The +value of the tag defines the default behaviors for that application. + +For example: + +@smallexample +@group +[appdefaults] + telnet = @{ + @value{PRIMARYREALM} = @{ + option1 = false + @} + @} + telnet = @{ + option1 = true + option2 = true + @} + @value{PRIMARYREALM} = @{ + option2 = false + @} + option2 = true + +@end group +@end smallexample + +The above four ways of specifying the value of an option are shown +in order of decreasing precedence. In this example, if telnet is +running in the realm @value{SECONDREALM}, it should, by default, have +option1 and option2 set to true. However, a telnet program in the realm +@value{PRIMARYREALM} should have option1 set to false and option2 set +to true. Any other programs in @value{PRIMARYREALM} should have option2 +set to false by default. Any programs running in other realms should +have option2 set to true. + +The list of specifiable options for each application may be found in +that application's man pages. The application defaults specified here +are overridden by those specified in the [realms] section. + +A special application name (afs_krb5) is used by the krb524 service to +know whether new format AFS tokens based on Kerberos 5 can be used +rather than the older format which used a converted Kerberos 4 ticket. +The new format allows for cross-realm authentication without +introducing a security hole. It is used by default. Older AFS +servers (before OpenAFS 1.2.8) will not support the new format. If +servers in your cell do not support the new format, you will need to +add an @code{afs_krb5} relation to the @code{appdefaults} section. +The following config file shows how to disable new format AFS tickets +for the @code{afs.example.com} cell in the @code{EXAMPLE.COM} realm. + +@smallexample +@group +[appdefaults] + afs_krb5 = @{ + EXAMPLE.COM = @{ + afs/afs.example.com = false + @} + @} + +@end group +@end smallexample + + + + + +@node login, realms (krb5.conf), appdefaults, krb5.conf +@subsection [login] + +Each tag in the [login] section of the file is an option for +login.krb5. This section may contain any of the following relations: + +@table @b +@itemx krb5_get_tickets +Indicate whether or not to use a user's password to get V5 tickets. +The default value is @value{DefaultKrb5GetTickets}. + +@itemx krb4_get_tickets +Indicate whether or not to user a user's password to get V4 tickets. +The default value is @value{DefaultKrb4GetTickets}. + +@itemx krb4_convert +Indicate whether or not to use the Kerberos conversion daemon to get V4 +tickets. The default value is @value{DefaultKrb4Convert}. If this is +set to false and krb4_get_tickets is true, then login will get the V5 +tickets directly using the Kerberos V4 protocol directly. This does +not currently work with non-MIT-V4 salt types (such as the AFS3 salt +type). Note that if this is set to true and krb524d is not running, +login will hang for approximately a minute under Solaris, due to a +Solaris socket emulation bug. + +@itemx krb_run_aklog +Indicate whether or not to run aklog. The default value is +@value{DefaultKrbRunAklog}. + +@itemx aklog_path +Indicate where to find aklog. The default value is +@value{DefaultAklogPath}. + +@itemx accept_passwd +A true value will cause login not to accept plaintext passwords. The +default value is @value{DefaultAcceptPasswd}. This is not yet +implemented. +@end table + +@node realms (krb5.conf), domain_realm, login, krb5.conf +@subsection [realms] + +Each tag in the [realms] section of the file is the name of a Kerberos +realm. The value of the tag is a subsection with relations that define +the properties of that particular realm. For each realm, the following +tags may be specified in the realm's subsection: + +@table @b +@itemx kdc +The name of a host running a KDC for that realm. An optional port +number (separated from the hostname by a colon) may be included. For +your computer to be able to communicate with the KDC for each realm, +this tag must be given a value in each realm subsection in the +configuration file, or there must be DNS SRV records specifying the +KDCs (see @ref{Using DNS}). + +@itemx master_kdc +Identifies the master KDC(s). Currently, this tag is used in only one +case: If an attempt to get credentials fails because of an invalid +password, the client software will attempt to contact the master KDC, +in case the user's password has just been changed, and the updated +database has not been propagated to the slave servers yet. (We don't +currently check whether the KDC from which the initial response came +is on the master KDC list. That may be fixed in the future.) + +@itemx admin_server +Identifies the host where the administration server is running. +Typically, this is the master Kerberos server. This tag must be given +a value in order to communicate with the kadmin server for the realm. + +@ignore +this doesn't seem to be used in the code +@itemx application defaults +Application defaults that are specific to a particular realm may be +specified within that realm's tag. Realm-specific application defaults +override the global defaults specified in the [appdefaults] section. +@end ignore + +@itemx default_domain +This tag is used for Kerberos 4 compatibility. Kerberos 4 does not +require the entire hostname of a server to be in its principal like +Kerberos 5 does. This tag provides the domain name needed to produce a +full hostname when translating V4 principal names into V5 principal +names. All servers in this realm are assumed to be in the domain given +as the value of this tag + +@itemx v4_instance_convert +This subsection allows the administrator to configure exceptions to the +default_domain mapping rule. It contains V4 instances (the tag name) +which should be translated to some specific hostname (the tag value) as +the second component in a Kerberos V5 principal name. + +@itemx v4_realm +This relation is used by the krb524 library routines when converting a +V5 principal name to a V4 principal name. It is used when the V4 realm +name and the V5 realm name are not the same, but still share the same +principal names and passwords. The tag value is the Kerberos V4 realm +name. + +@itemx auth_to_local_names +This subsection allows you to set explicit mappings from principal +names to local user names. The tag is the mapping name, and the value +is the corresponding local user name. + +@itemx auth_to_local +This tag allows you to set a general rule for mapping principal names +to local user names. It will be used if there is not an explicit +mapping for the principal name that is being translated. The possible +values are: + +@table @b + +@item DB:@i{filename} +The principal will be looked up in the database @i{filename}. Support +for this is not currently compiled in by default. + +@item RULE:@i{exp} +The local name will be formulated from @i{exp}. + +The format for @i{exp} is +@code{[@i{n}:$@i{d}..@i{string}](@i{regexp})s/@i{pattern}/@i{replacement}/g}. +The integer @i{n} indicates how many components the target principal +should have. If this matches, then a string will be formed by putting +together the components of the principal in the order indicated by each +integer @i{d}, and the arbitrary string @i{string} (i.e. if the +principal was @value{RANDOMUSER}/admin then [2:$2$1foo] would result in +the string "admin@value{RANDOMUSER}foo". If this string matches +@i{regexp}, then the @code{s//[g]} substitution command will be run over the +string. The optional g will cause the substitution to be global over +the string, instead of replacing only the first match in the string. + +@item DEFAULT +The principal name will be used as the local user name. If the +principal has more than one component or is not in the default realm, +this rule is not applicable and the conversion will fail. + +@end table + +For example: + +@smallexample +@group +[realms] + @value{PRIMARYREALM} = @{ + auth_to_local = @{ + RULE:[2:$1](@value{RANDOMUSER})s/^.*$/guest/ + RULE:[2:$1;$2](^.*;admin$)s/;admin$// + RULE:[2:$2](^.*;root)s/^.*$/root/ + DEFAULT + @} + @} +@end group +@end smallexample + +would result in any principal without @code{root} or @code{admin} as +the second component to be translated with the default rule. A +principal with a second component of @code{admin} will become its first +component. @code{root} will be used as the local name for any +principal with a second component of @code{root}. The exception to +these two rules are any principals @value{RANDOMUSER}/*, which will +always get the local name @code{guest}. + +@end table + +@node domain_realm, logging, realms (krb5.conf), krb5.conf +@subsection [domain_realm] + +The [domain_realm] section provides a translation from a domain name or +hostname to a Kerberos realm name. The tag name can be a host name, or +a domain name, where domain names are indicated by a prefix of a period +(@samp{.}). The value of the relation is the Kerberos realm name for +that particular host or domain. Host names and domain names should be +in lower case. + +If no translation entry applies, the host's realm is considered to be +the hostname's domain portion converted to upper case. For example, the +following [domain_realm] section: + +@smallexample +@group +[domain_realm] +@ifset MIT + .mit.edu = ATHENA.MIT.EDU +@end ifset + @value{PRIMARYDOMAIN} = @value{PRIMARYREALM} + crash.@value{PRIMARYDOMAIN} = TEST.@value{PRIMARYREALM} + @value{SECONDDOMAIN} = @value{SECONDREALM} +@end group +@end smallexample + +@noindent +maps crash.@value{PRIMARYDOMAIN} into the TEST.@value{PRIMARYREALM} +realm. All other hosts in the @value{PRIMARYDOMAIN} domain will map by +default to the @value{PRIMARYREALM} realm, and all hosts in the +@value{SECONDDOMAIN} domain will map by default into the +@value{SECONDREALM} realm. Note the entries for the hosts +@value{PRIMARYDOMAIN} and @value{SECONDDOMAIN}. Without these entries, +@ifset CYGNUS +these hosts would be mapped into the Kerberos realms @samp{COM} and +@end ifset +@ifclear CYGNUS +these hosts would be mapped into the Kerberos realms @samp{EDU} and +@end ifclear +@samp{ORG}, respectively. + +@node logging, capaths, domain_realm, krb5.conf +@subsection [logging] +The [logging] section indicates how a particular entity is to perform +its logging. The relations in this section assign one or more values to +the entity name. Currently, the following entities are used: + +@table @b + +@itemx kdc +These entries specify how the KDC is to perform its logging. + +@itemx admin_server +These entries specify how the administrative server +is to perform its logging. + +@itemx default +These entries specify how to perform logging in the +absence of explicit specifications otherwise. +@end table + +Values are of the following forms: + +@table @b +@itemx FILE= + +@itemx FILE: +This value causes the entity's logging messages to go to the specified +file. If the @samp{=} form is used, the file is overwritten. If the +@samp{:} form is used, the file is appended to. + +@itemx STDERR +This value causes the entity's logging messages to go to its standard +error stream. + +@itemx CONSOLE +This value causes the entity's logging messages to go to the console, if +the system supports it. + +@itemx DEVICE= +This causes the entity's logging messages to go to the specified device. + +@itemx SYSLOG[:[:]] +This causes the entity's logging messages to go to the system log. + +The @dfn{severity} argument specifies the default severity of system log +messages. This may be any of the following severities supported by the +@code{syslog(3)} call, minus the LOG_ prefix: LOG_EMERG, LOG_ALERT, +LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, and LOG_DEBUG. +For example, a value of @samp{CRIT} would specify LOG_CRIT severity. + +The facility argument specifies the facility under which the messages +are logged. This may be any of the following facilities supported by +the syslog(3) call minus the LOG_ prefix: LOG_KERN, LOG_USER, LOG_MAIL, +LOG_DAEMON, LOG_AUTH, LOG_LPR, LOG_NEWS, LOG_UUCP, LOG_CRON, and +LOG_LOCAL0 through LOG_LOCAL7. + +If no severity is specified, the default is ERR. If no facility is +specified, the default is AUTH. +@end table + +In the following example, the logging messages from the KDC will go to +the console and to the system log under the facility LOG_DAEMON with +default severity of LOG_INFO; and the logging messages from the +administrative server will be appended to the file /var/adm/kadmin.log +and sent to the device /dev/tty04. + +@smallexample +@group +[logging] + kdc = CONSOLE + kdc = SYSLOG:INFO:DAEMON + admin_server = FILE:/var/adm/kadmin.log + admin_server = DEVICE=/dev/tty04 +@end group +@end smallexample + +@node capaths, Sample krb5.conf File, logging, krb5.conf +@subsection [capaths] + +In order to perform direct (non-hierarchical) cross-realm +authentication, a database is needed to construct the authentication +paths between the realms. This section defines that database. + +A client will use this section to find the authentication path between +its realm and the realm of the server. The server will use this section +to verify the authentication path used by the client, by checking the +transited field of the received ticket. + +There is a tag for each participating realm, and each tag has subtags +for each of the realms. The value of the subtags is an intermediate +realm which may participate in the cross-realm authentication. The +subtags may be repeated if there is more then one intermediate realm. A +value of "." means that the two realms share keys directly, and no +intermediate realms should be allowd to participate. + +There are n**2 possible entries in this table, but only those entries +which will be needed on the client or the server need to be present. +The client needs a tag for its local realm, with subtags for all the +realms of servers it will need to authenticate with. A server needs a +tag for each realm of the clients it will serve. + +For example, ANL.GOV, PNL.GOV, and NERSC.GOV all wish to use the ES.NET +realm as an intermediate realm. ANL has a sub realm of TEST.ANL.GOV +which will authenticate with NERSC.GOV but not PNL.GOV. The [capaths] +section for ANL.GOV systems would look like this: + +@smallexample +@group +[capaths] + ANL.GOV = @{ + TEST.ANL.GOV = . + PNL.GOV = ES.NET + NERSC.GOV = ES.NET + ES.NET = . + @} + TEST.ANL.GOV = @{ + ANL.GOV = . + @} + PNL.GOV = @{ + ANL.GOV = ES.NET + @} + NERSC.GOV = @{ + ANL.GOV = ES.NET + @} + ES.NET = @{ + ANL.GOV = . + @} +@end group +@end smallexample + +The [capaths] section of the configuration file used on NERSC.GOV systems +would look like this: + +@smallexample +@group +[capaths] + NERSC.GOV = @{ + ANL.GOV = ES.NET + TEST.ANL.GOV = ES.NET + TEST.ANL.GOV = ANL.GOV + PNL.GOV = ES.NET + ES.NET = . + @} + ANL.GOV = @{ + NERSC.GOV = ES.NET + @} + PNL.GOV = @{ + NERSC.GOV = ES.NET + @} + ES.NET = @{ + NERSC.GOV = . + @} + TEST.ANL.GOV = @{ + NERSC.GOV = ANL.GOV + NERSC.GOV = ES.NET + @} +@end group +@end smallexample + +In the above examples, the ordering is not important, except when the +same subtag name is used more then once. The client will use this to +determine the path. (It is not important to the server, since the +transited field is not sorted.) + +This feature is not currently supported by DCE. DCE security servers +can be used with Kerberized clients and servers, but versions prior to +DCE 1.1 did not fill in the transited field, and should be used with +caution. + +@node Sample krb5.conf File, , capaths, krb5.conf +@subsection Sample krb5.conf File + +Here is an example of a generic @code{krb5.conf} file: + +@smallexample +@group +[libdefaults] + default_realm = @value{PRIMARYREALM} + default_tkt_enctypes = des3-hmac-sha1 des-cbc-crc + default_tgs_enctypes = des3-hmac-sha1 des-cbc-crc + dns_lookup_kdc = true + dns_lookup_realm = false + +[realms] + @value{PRIMARYREALM} = @{ + kdc = @value{KDCSERVER}.@value{PRIMARYDOMAIN} + kdc = @value{KDCSLAVE1}.@value{PRIMARYDOMAIN} + kdc = @value{KDCSLAVE2}.@value{PRIMARYDOMAIN}:750 + admin_server = @value{KDCSERVER}.@value{PRIMARYDOMAIN} + master_kdc = @value{KDCSERVER}.@value{PRIMARYDOMAIN} + default_domain = @value{PRIMARYDOMAIN} + @} + @value{SECONDREALM} = @{ + kdc = @value{KDCSERVER}.@value{SECONDDOMAIN} + kdc = @value{KDCSLAVE1}.@value{SECONDDOMAIN} + admin_server = @value{KDCSERVER}.@value{SECONDDOMAIN} + @} + +[domain_realm] +@ifset MIT + .mit.edu = ATHENA.MIT.EDU +@end ifset + @value{PRIMARYDOMAIN} = @value{PRIMARYREALM} + +[capaths] + @value{PRIMARYREALM} = @{ + @value{SECONDREALM} = . + @} + @value{SECONDREALM} = @{ + @value{PRIMARYREALM} = . + @} + +[logging] + kdc = SYSLOG:INFO + admin_server = FILE=/var/kadm5.log + +@end group +@end smallexample + +@iftex +@vfill +@end iftex + +@node kdc.conf, , krb5.conf, Configuration Files +@section kdc.conf + +@include kdcconf.texinfo + +@menu +* kdcdefaults:: +* realms (kdc.conf):: +* Sample kdc.conf File:: +@end menu + +@node kdcdefaults, realms (kdc.conf), kdc.conf, kdc.conf +@subsection [kdcdefaults] + +The following relation is defined in the [kdcdefaults] section: + +@table @b +@itemx kdc_ports +This relation lists the ports on which the Kerberos server should +listen for UDP requests by default. This list is a comma separated +list of integers. +If this relation is not specified, the compiled-in default is +@value{DefaultKdcPorts}, the first being the assigned Kerberos port +and the second which was used by Kerberos V4. + +@itemx kdc_tcp_ports +This relation lists the ports on which the Kerberos server should +listen for TCP connections by default. This list is a comma separated +list of integers. +If this relation is not specified, the compiled-in default is not to +listen for TCP connections at all. + +If you wish to change this (which we do not recommend, because the +current implementation has little protection against denial-of-service +attacks), the standard port number assigned for Kerberos TCP traffic +is port 88. + +@itemx v4_mode +This string specifies how the KDC should respond to Kerberos 4 +packets. The possible values are none, disable, full, and nopreauth. +The default value is @value{DefaultV4Mode}. +@comment these values found in krb5/src/kdc/kerberos_v4.c in v4mode_table +@end table + +@node realms (kdc.conf), Sample kdc.conf File, kdcdefaults, kdc.conf +@subsection [realms] + +Each tag in the [realms] section of the file names a Kerberos realm. +The value of the tag is a subsection where the relations in that +subsection define KDC parameters for that particular realm. + +For each realm, the following tags may be specified in the [realms] +subsection: + +@table @b +@itemx acl_file +(String.) Location of the access control list (acl) file that kadmin +uses to determine which principals are allowed which permissions on the +database. The default is @code{@value{DefaultAclFile}}. + +@itemx admin_keytab +(String.) Location of the keytab file that the legacy administration +daemons @code{kadmind4} and @code{v5passwdd} use to authenticate to +the database. The default is @code{@value{DefaultAdminKeytab}}. + +@itemx database_name +(String.) Location of the Kerberos database for this realm. The +default is @* @code{@value{DefaultDatabaseName}}. + +@itemx default_principal_expiration +(Absolute time string.) Specifies the default expiration date of +principals created in this realm. The default value for this tag is +@value{DefaultDefaultPrincipalExpiration}. + +@itemx default_principal_flags +(Flag string.) Specifies the default attributes of principals created +in this realm. The format for this string is a comma-separated list of +flags, with '+' before each flag that should be enabled and '-' before +each flag that should be disabled. The default is +@value{DefaultDefaultPrincipalFlags}. + +There are a number of possible flags: + +@table @b +@itemx postdateable +Enabling this flag allows the principal to obtain postdateable tickets. + +@itemx forwardable +Enabling this flag allows the principal to obtain forwardable tickets. + +@itemx tgt-based +Enabling this flag allows a principal to obtain tickets based on a +ticket-granting-ticket, rather than repeating the authentication +process that was used to obtain the TGT. + +@itemx renewable +Enabling this flag allows the principal to obtain renewable tickets. + +@itemx proxiable +Enabling this flag allows the principal to obtain proxy tickets. + +@itemx dup-skey +Enabling this flag allows the principal to obtain a session key for +another user, permitting user-to-user authentication for this principal. + +@itemx allow-tickets +Enabling this flag means that the KDC will issue tickets for this +principal. Disabling this flag essentially deactivates the principal +within this realm. + +@itemx preauth +If this flag is enabled on a client principal, then that principal is +required to preauthenticate to the KDC before receiving any tickets. +On a service principal, enabling this flag means that service tickets +for this principal will only be issued to clients with a TGT that has +the preauthenticated ticket set. + +@itemx hwauth +If this flag is enabled, then the principal is required to +preauthenticate using a hardware device before receiving any tickets. + +@itemx pwchange +Enabling this flag forces a password change for this principal. + +@itemx service +Enabling this flag allows the the KDC to issue service tickets for this +principal. + +@itemx pwservice +If this flag is enabled, it marks this principal as a password change +service. This should only be used in special cases, for example, if a +user's password has expired, then the user has to get tickets for that +principal without going through the normal password authentication in +order to be able to change the password. + +@end table + +@itemx dict_file +(String.) Location of the dictionary file containing strings that are +not allowed as passwords. If none is specified or if there is no +policy assigned to the principal, no dictionary checks of passwords +will be performed. + +@itemx kadmind_port +(Port number.) Specifies the port on which the kadmind daemon is to +listen for this realm. The assigned port for kadmind is +@value{DefaultKadmindPort}. + +@itemx kpasswd_port +(Port number.) Specifies the port on which the kpasswd daemon is to +listen for this realm. The default is @value{DefaultKpasswdPort}. + +@itemx key_stash_file +(String.) Specifies the location where the master key has been stored +(via @code{kdb5_util stash}). The default is +@code{@value{DefaultKeyStashFileStub}@i{REALM}}, where @i{REALM} is the +Kerberos realm. + +@itemx kdc_ports +(String.) Specifies the list of ports that the KDC is to listen to +for UDP requests for this realm. By default, the value of kdc_ports +as specified in the [kdcdefaults] section is used. + +@itemx kdc_tcp_ports +(String.) Specifies the list of ports that the KDC is to listen to +for TCP requests for this realm. By default, the value of +kdc_tcp_ports as specified in the [kdcdefaults] section is used. + +@itemx master_key_name +(String.) Specifies the name of the principal associated with the +master key. The default is @value{DefaultMasterKeyName}. + +@itemx master_key_type +(Key type string.) Specifies the master key's key type. The default +value for this is @value{DefaultMasterKeyType}. For a list of all +possible values, see @ref{Supported Encryption Types}. + +@itemx max_life +(Delta time string.) Specifes the maximum time period for which a +ticket may be valid in this realm. The default value is +@value{DefaultMaxLife}. + +@itemx max_renewable_life +(Delta time string.) Specifies the maximum time period during which a +valid ticket may be renewed in this realm. The default value is +@value{DefaultMaxRenewableLife}. + +@itemx supported_enctypes +List of key:salt strings. Specifies the default key/salt combinations of +principals for this realm. Any principals created through @code{kadmin} +will have keys of these types. The default value for this tag is +@value{DefaultSupportedEnctypes}. For lists of possible values, see +@ref{Supported Encryption Types} and @ref{Salts}. + +@itemx reject_bad_transit +A boolean value (@code{true}, @code{false}). If set to @code{true}, the +KDC will check the list of transited realms for cross-realm tickets +against the transit path computed from the realm names and the +@code{capaths} section of its @code{krb5.conf} file; if the path in the +ticket to be issued contains any realms not in the computed path, the +ticket will not be issued, and an error will be returned to the client +instead. If this value is set to @code{false}, such tickets will be +issued anyways, and it will be left up to the application server to +validate the realm transit path. + +If the @code{disable-transited-check} flag is set in the incoming +request, this check is not performed at all. Having the +@code{reject_bad_transit} option will cause such ticket requests to be +rejected always. + +This transit path checking and config file option currently apply only +to TGS requests. + +Earlier versions of the MIT release (before 1.2.3) had bugs in the +application server support such that the server-side checks may not be +performed correctly. We recommend turning this option on, unless you +know that all application servers in this realm have been updated to +fixed versions of the software, and for whatever reason, you don't want +the KDC to do the validation. + +This is a per-realm option so that multiple-realm KDCs may control it +separately for each realm, in case (for example) one realm has had the +software on its application servers updated but another has not. + +This option defaults to @code{true}. + +@end table + +@node Sample kdc.conf File, , realms (kdc.conf), kdc.conf +@subsection Sample kdc.conf File + +Here's an example of a @code{kdc.conf} file: + +@smallexample +@group +[kdcdefaults] + kdc_ports = 88 + +[realms] + @value{PRIMARYREALM} = @{ + kadmind_port = 749 + max_life = 12h 0m 0s + max_renewable_life = 7d 0h 0m 0s + master_key_type = des3-hmac-sha1 + supported_enctypes = des3-hmac-sha1:normal des-cbc-crc:normal des-cbc-crc:v4 + @} + +[logging] + kdc = FILE:@value{ROOTDIR}/var/krb5kdc/kdc.log + admin_server = FILE:@value{ROOTDIR}/var/krb5kdc/kadmin.log + +@end group +@end smallexample + +@node Using DNS, Administrating the Kerberos Database, Configuration Files, Top +@chapter Using DNS + +@menu +* Mapping Hostnames onto Kerberos Realms:: +* Hostnames for KDCs:: +@end menu + +@node Mapping Hostnames onto Kerberos Realms, Hostnames for KDCs, Using DNS, Using DNS +@section Mapping Hostnames onto Kerberos Realms + +@include dnstxt.texinfo + +@node Hostnames for KDCs, , Mapping Hostnames onto Kerberos Realms, Using DNS +@section Hostnames for KDCs + +@include dnssrv.texinfo + +@node Administrating the Kerberos Database, Application Servers, Using DNS, Top +@chapter Administrating the Kerberos Database + +Your Kerberos database contains all of your realm's Kerberos principals, +their passwords, and other administrative information about each +principal. For the most part, you will use the @code{kdb5_util} program +to manipulate the Kerberos database as a whole, and the @code{kadmin} +program to make changes to the entries in the database. (One notable +exception is that users will use the @code{kpasswd} program to change +their own passwords.) The @code{kadmin} program has its own +command-line interface, to which you type the database administrating +commands. + +@code{Kdb5_util} provides a means to create, delete, load, or dump a +Kerberos database. It also includes a command to stash a copy of the +master database key in a file on a KDC, so that the KDC can authenticate +itself to the @code{kadmind} and @code{krb5kdc} daemons at boot time. + +@code{Kadmin} provides for the maintenance of Kerberos principals, KADM5 +policies, and service key tables (keytabs). It exists as both a +Kerberos client, @code{kadmin}, using Kerberos authentication and an +RPC, to operate securely from anywhere on the network, and as a local +client, @code{kadmin.local}, intended to run directly on the KDC without +Kerberos authentication. Other than the fact that the remote client +uses Kerberos to authenticate the person using it, the functionalities +of the two versions are identical. The local version is necessary to +enable you to set up enough of the database to be able to use the remote +version. It replaces the now obsolete @code{kdb5_edit} (except for +database dump and load, which are provided by @code{kdb5_util}). + +The remote version authenticates to the KADM5 server using the service +principal @code{kadmin/admin}. If the credentials cache contains a +ticket for the @code{kadmin/admin} principal, and the @samp{-c ccache} +option is specified, that ticket is used to authenticate to KADM5. +Otherwise, the @samp{-p} and @samp{-k} options are used to specify the +client Kerberos principal name used to authenticate. Once kadmin has +determined the principal name, it requests a @code{kadmin/admin} +Kerberos service ticket from the KDC, and uses that service ticket to +authenticate to KADM5. + +@menu +* Kadmin Options:: +* Date Format:: +* Principals:: +* Policies:: +* Global Operations on the Kerberos Database:: +* Cross-realm Authentication:: +@end menu + +@node Kadmin Options, Date Format, Administrating the Kerberos Database, Administrating the Kerberos Database +@section Kadmin Options + +You can invoke @code{kadmin} or @code{kadmin.local} with any of the +following options: + +@table @b +@item @b{-r} @i{REALM} +Use @i{REALM} as the default Kerberos realm for the database. + +@item @b{-p} @i{principal} +Use the Kerberos principal @i{principal} to authenticate to Kerberos. +If this option is not given, @code{kadmin} will append @code{admin} to +either the primary principal name, the environment variable USER, or to +the username obtained from @code{getpwuid}, in order of preference. + +@item @b{-q} @i{query} +Pass @i{query} directly to @code{kadmin}. This is useful for writing +scripts that pass specific queries to @code{kadmin}. + +@noindent +You can invoke @code{kadmin} with any of the following options: + +@item @b{-k} [@b{-t} @i{keytab}] +Use the keytab @i{keytab} to decrypt the KDC response instead of +prompting for a password on the TTY. In this case, the principal will +be @samp{host/@i{hostname}}. If @b{-t} is not used to specify a keytab, +then the default keytab will be used. + +@item @b{-c} @i{credentials cache} +Use @i{credentials_cache} as the credentials cache. The credentials +cache should contain a service ticket for the @code{kadmin/admin} +service, which can be acquired with the @code{kinit} program. If this +option is not specified, @code{kadmin} requests a new service ticket +from the KDC, and stores it in its own temporary ccache. + +@item @b{-w} @i{password} +Use @i{password} as the password instead of prompting for one on the +TTY. Note: placing the password for a Kerberos principal with +administration access into a shell script can be dangerous if +unauthorized users gain read access to the script. + +@item @b{-s} @i{admin_server[:port]} +Specifies the admin server that kadmin should contact. + +@noindent +You can invoke @code{kadmin.local} with an of the follwing options: + +@item @b{-d_ @i{dbname}} +Specifies the name of the Kerberos database. + +@item @b{-e} @i{"enctypes ..."} +Sets the list of cryptosystem and salt types to be used for any new +keys created. See @ref{Supported Encryption Types} and @ref{Salts} for +available types. + +@item @b{-m} +Do not authenticate using a keytab. This option will cause kadmin to +prompt for the master database password. + +@end table + +@node Date Format, Principals, Kadmin Options, Administrating the Kerberos Database +@section Date Format + +Many of the @code{kadmin} commands take a duration or time as an +argument. The date can appear in a wide variety of formats, such as: + +@smallexample +@group +"15 minutes" +"7 days" +"1 month" +"2 hours" +"400000 seconds" +"next year" +"this Monday" +"next Monday" +yesterday +tomorrow +now +"second Monday" +fortnight +"3/31/1992 10:00:07 PST" +"January 23, 2007 10:05pm" +"22:00 GMT" +@end group +@end smallexample + +Note that if the date specification contains spaces, you must enclose it +in double quotes. Note also that you cannot use a number without a +unit. (I.e., ``"60 seconds"'' is correct, but ``60'' is incorrect.) +All keywords are case-insensitive. The following is a list of all of +the allowable keywords. + +@table @b +@item Months +january, jan, february, feb, march, mar, april, apr, may, june, jun, +july, jul, august, aug, september, sep, sept, october, oct, november, +nov, december, dec + +@item Days +sunday, sun, monday, mon, tuesday, tues, tue, wednesday, wednes, wed, +thursday, thurs, thur, thu, friday, fri, saturday, sat + +@item Units +year, month, fortnight, week, day, hour, minute, min, second, sec + +@item Relative +tomorrow, yesterday, today, now, last, this, next, first, second, +third, fourth, fifth, sixth, seventh, eighth, ninth, tenth, eleventh, +twelfth, ago + +@item Time Zones +@code{kadmin} recognizes abbreviations for most of the world's time +zones. A complete listing appears in @ref{kadmin Time Zones}. + +@item 12-hour Time Delimiters +am, pm +@end table + +@node Principals, Policies, Date Format, Administrating the Kerberos Database +@section Principals + +Each entry in the Kerberos database contains a Kerberos principal +(@pxref{Definitions}) and the attributes and policies associated with +that principal. + +@menu +* Retrieving Information About a Principal:: +* Privileges:: +* Adding or Modifying Principals:: +* Deleting Principals:: +* Changing Passwords:: +@end menu + +@node Retrieving Information About a Principal, Privileges, Principals, Principals +@subsection Retrieving Information About a Principal + +@menu +* Attributes:: +* Retrieving a List of Principals:: +@end menu + +@node Attributes, Retrieving a List of Principals, Retrieving Information About a Principal, Retrieving Information About a Principal +@subsubsection Attributes + +To retrieve a listing of the attributes and/or policies associated with +a principal, use the @code{kadmin} @code{get_principal} command, which +requires the ``inquire'' administrative privilege. The syntax is: + +@smallexample +@b{get_principal} @i{principal} +@end smallexample + +@noindent +The @code{get_principal} command has the alias @code{getprinc}. + +For example, suppose you wanted to view the attributes of the +principal @* @code{@value{RANDOMUSER1}/root@@@value{PRIMARYREALM}}. + You would type: + +@smallexample +@group +@b{shell%} kadmin +@b{kadmin:} getprinc @value{RANDOMUSER1}/root +@b{Principal: @value{RANDOMUSER1}/root@@@value{PRIMARYREALM} +Expiration date: [never] +Last password change: Mon Jan 31 02:06:40 EDT 2002 +Password Expiration date: [none] +Maximum ticket life: 0 days 10:00:00 +Maximum renewable life: 7 days 00:00:00 +Last modified: Wed Jul 24 14:46:25 EDT 2002 (@value{ADMINUSER}/admin@@@value{PRIMARYREALM}) +Last successful authentication: Mon Jul 29 18:20:17 EDT 2002 +Last failed authentication: Mon Jul 29 18:18:54 EDT 2002 +Failed password attempts: 3 +Number of keys: 2 +Key: vno 2, Triple DES cbc mode with HMAC/sha1, no salt +Key: vno 2, DES cbc mode with CRC-32, no salt +Attributes: DISALLOW_FORWARDABLE, DISALLOW_PROXIABLE +Policy: [none] +kadmin:} +@end group +@end smallexample + +The @code{get_principal} command has a @code{-terse} option, which lists +the fields as a quoted, tab-separated string. For example: + +@smallexample +@group +@b{kadmin:} getprinc -terse @value{RANDOMUSER1}/root +@b{@value{RANDOMUSER1}/root@@@value{PRIMARYREALM} 0 1027458564 +0 36000 (@value{ADMINUSER}/admin@@@value{PRIMARYREALM} +1027536385 18 2 0 [none] 604800 1027980137 +1027980054 3 2 1 2 16 0 1 +2 1 0 +kadmin:} +@end group +@end smallexample + +@node Retrieving a List of Principals, , Attributes, Retrieving Information About a Principal +@subsubsection Retrieving a List of Principals + +To generate a listing of principals, use the @code{kadmin} +@code{list_principals} command, which requires the ``list'' privilege. +The syntax is: + +@smallexample +@b{list_principals} [@i{expression}] +@end smallexample + +@noindent where @i{expression} is a shell-style glob expression that +can contain the characters @samp{*}, @samp{?}, @samp{[}, and @samp{]}. +All policy names matching the expression are displayed. The +@code{list_principals} command has the aliases @code{listprincs}, +@code{get_principals}, and @code{getprincs}. For example: + +@smallexample +@group +@b{kadmin:} listprincs test* +@b{test3@@@value{PRIMARYREALM} +test2@@@value{PRIMARYREALM} +test1@@@value{PRIMARYREALM} +testuser@@@value{PRIMARYREALM} +kadmin:} +@end group +@end smallexample + +@noindent +If no expression is provided, all principals are printed. + +@node Privileges, Adding or Modifying Principals, Retrieving Information About a Principal, Principals +@subsection Privileges + +Administrative privileges for the Kerberos database are stored in the +file @code{kadm5.acl}. + +@include kadm5acl.texinfo + +@node Adding or Modifying Principals, Deleting Principals, Privileges, Principals +@subsection Adding or Modifying Principals + +To add a principal to the database, use the kadmin @code{add_principal} +command, which requires the ``add'' administrative privilege. This +function creates the new principal, prompting twice for a password, and, +if neither the -policy nor -clearpolicy options are specified and the +policy ``default'' exists, assigns it that policy. The syntax is: + +@smallexample +@b{kadmin:} add_principal [@i{options}] @i{principal} +@end smallexample + +To modify attributes of a principal, use the kadmin +@code{modify_principal} command, which requires the ``modify'' +administrative privilege. The syntax is: + +@smallexample +@b{kadmin:} modify_principal [@i{options}] @i{principal} +@end smallexample + +@noindent +@code{add_principal} has the aliases @code{addprinc} and +@code{ank}@footnote{@code{ank} was the short form of the equivalent +command using the deprecated @code{kadmin5} database administrative tool. +It has been kept}. @code{modify_principal} has the alias @code{modprinc}. + +The @code{add_principal} and @code{modify_principal} commands take the +following switches: + +@table @b +@item -expire @i{date} +Sets the expiration date of the principal to @i{date}. + +@item -pwexpire @i{date} +Sets the expiration date of the password to @i{date}. + +@item -maxlife @i{maxlife} +Sets the maximum ticket life of the principal to @i{maxlife}. + +@item -maxrenewlife @i{maxrenewlife} +Sets the maximum renewable life of tickets for the principal to +@i{maxrenewlife}. + +@item -kvno @i{number} +Explicity sets the key version number to @i{number}. @value{COMPANY} +does not recommend doing this unless there is a specific reason. + +@item -policy @i{policy} +Sets the policy used by this principal. (@xref{Policies}.) With +@code{modify_principal}, the current policy assigned to the principal is +set or changed. With @code{add_principal}, if this option is not +supplied, the -clearpolicy is not specified, and the policy ``default'' +exists, that policy is assigned. If a principal is created with no +policy, @code{kadmin} will print a warning message. + +@item -clearpolicy +For @code{modify_principal}, removes the current policy from a +principal. For @code{add_principal}, suppresses the automatic +assignment of the policy ``default''. + +@item @{-|+@}allow_postdated +The ``-allow_postdated'' option prohibits this principal from obtaining +postdated tickets. ``+allow_postdated'' clears this flag. In effect, +``-allow_postdated'' sets the KRB5_KDB_DISALLOW_POSTDATED flag on the +principal in the database. + +@item @{-|+@}allow_forwardable +The ``-allow_forwardable'' option prohibits this principal from +obtaining forwardable tickets. ``+allow_forwardable'' clears this flag. +In effect, ``-allow_forwardable'' sets the KRB5_KDB_DISALLOW_FORWARDABLE +flag on the principal in the database. + +@item @{-|+@}allow_renewable +The ``-allow_renewable'' option prohibits this principal from obtaining +renewable tickets. ``+allow_renewable'' clears this flag. In effect, +``-allow_renewable'' sets the KRB5_KDB_DISALLOW_RENEWABLE flag on the +principal in the database. + +@item @{-|+@}allow_proxiable +The ``-allow_proxiable'' option prohibits this principal from obtaining +proxiable tickets. ``+allow_proxiable'' clears this flag. In effect, +``-allow_proxiable'' sets the @* KRB5_KDB_DISALLOW_PROXIABLE flag. on +the principal in the database. + +@item @{-|+@}allow_dup_skey +The ``-allow_dup_skey'' option disables user-to-user authentication for +this principal by prohibiting this principal from obtaining a session +key for another user. ``+allow_dup_skey'' clears this flag. In effect, +``-allow_dup_skey'' sets the @* KRB5_KDB_DISALLOW_DUP_SKEY flag on the +principal in the database. + +@item @{-|+@}requires_preauth +The ``+requires_preauth'' option requires this principal to +preauthenticate before being allowed to kinit. -requires_preauth clears +this flag. In effect, +requires_preauth sets the +KRB5_KDB_REQUIRES_PRE_AUTH flag on the principal in the database. + +@item @{-|+@}requires_hwauth +The ``+requires_hwauth'' flag requires the principal to preauthenticate +using a hardware device before being allowed to kinit. +``-requires_hwauth'' clears this flag. In effect, ``+requires_hwauth'' +sets the KRB5_KDB_REQUIRES_HW_AUTH flag on the principal in the +database. + +@item @{-|+@}allow_svr +The ``-allow_svr'' flag prohibits the issuance of service tickets for +this principal. ``+allow_svr'' clears this flag. In effect, +``-allow_svr'' sets the @* KRB5_KDB_DISALLOW_SVR flag on the principal +in the database. + +@item @{-|+@}allow_tgs_req +The ``-allow_tgs_req'' option specifies that a Ticket-Granting Service +(TGS) request for a service ticket for this principal is not permitted. +You will probably never need to use this option. ``+allow_tgs_req'' +clears this flag. The default is ``+allow_tgs_req''. In effect, +``-allow_tgs_req'' sets the KRB5_KDB_DISALLOW_TGT_BASED flag on the +principal in the database. + +@item @{-|+@}allow_tix +The ``-allow_tix'' option forbids the issuance of any tickets for this +principal. ``+allow_tix'' clears this flag. The default is +``+allow_tix''. In effect, ``-allow_tix'' sets the @* +KRB5_KDB_DISALLOW_ALL_TIX flag on the principal in the database. + +@item @{-|+@}needchange +The ``+needchange'' option sets a flag in attributes field to force a +password change; ``-needchange'' clears it. The default is +``-needchange''. In effect, ``+needchange'' sets the +KRB5_KDB_REQUIRES_PWCHANGE flag on the principal in the database. + +@item @{-|+@}password_changing_service +The ``+password_changing_service'' option sets a flag in the attributes +field marking this principal as a password change service. (Again, you +will probably never need to use this option.) +``-password_changing_service'' clears the flag. The default is +``-password_changing_service''. In effect, the +``+password_changing_service'' option sets the KRB5_KDB_PWCHANGE_SERVICE +flag on the principal in the database. + +@item -randkey +Sets the key for the principal to a random value (@code{add_principal} +only). @value{COMPANY} recommends using this option for host keys. + +@item -pw @i{password} +Sets the key of the principal to the specified string and does not +prompt for a password (@code{add_principal} only). @value{COMPANY} does +not recommend using this option. + +@item -e @i{enc:salt...} +Uses the specified list of enctype-salttype pairs for setting the key +of the principal. The quotes are necessary if there are multiple +enctype-salttype pairs. This will not function against kadmin daemons +earlier than krb5-1.2. See @ref{Supported Encryption Types} and +@ref{Salts} for available types. +@end table + +If you want to just use the default values, all you need to do is: + +@smallexample +@group +@b{kadmin:} addprinc @value{RANDOMUSER1} +@b{WARNING: no policy specified for "@value{RANDOMUSER1}@@@value{PRIMARYREALM}"; +defaulting to no policy.} +@iftex +@b{Enter password for principal @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{@doubleleftarrow{} Type the password.} +@b{Re-enter password for principal @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{@doubleleftarrow{} Type it again.} +@end iftex +@ifinfo +@b{Enter password for principal @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{<= Type the password.} +@b{Re-enter password for principal @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{<=Type it again.} +@end ifinfo +@ifhtml +@b{Enter password for principal @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{<= Type the password.} +@b{Re-enter password for principal @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{<=Type it again.} +@end ifhtml +@b{Principal "@value{RANDOMUSER1}@@@value{PRIMARYREALM}" created. +kadmin:} +@end group +@end smallexample + +If, on the other hand, you want to set up an account that expires on +January 1, 2000, that uses a policy called ``stduser'', with a temporary +password (which you want the user to change immediately), you would type +the following. (Note: each line beginning with @result{} is a +continuation of the previous line.) + +@smallexample +@group + +@b{kadmin:} addprinc @value{RANDOMUSER2} -expire "1/1/2000 12:01am EST" -policy stduser +@result{} +needchange +@iftex +@b{Enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{@doubleleftarrow{} Type the password.} +@b{Re-enter password for principal +@value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{@doubleleftarrow{} Type it again.} +@end iftex +@ifinfo +@b{Enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{<= Type the password.} +@b{Re-enter password for principal +@value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{<= Type it again.} +@end ifinfo +@ifhtml +@b{Enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{<= Type the password.} +@b{Re-enter password for principal +@value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{<= Type it again.} +@end ifhtml +@b{Principal "@value{RANDOMUSER2}@@@value{PRIMARYREALM}" created. +kadmin:} + +@end group +@end smallexample + +If you will need cross-realm authentication, you need to add principals +for the other realm's TGT to each realm. For example, if you need to +do cross-realm authentication between the realms @value{PRIMARYREALM} +and @value{SECONDREALM}, you would need to add the principals @* +@samp{krbtgt/@value{SECONDREALM}@@@value{PRIMARYREALM}} and +@samp{krbtgt/@value{PRIMARYREALM}@@@value{SECONDREALM}} to both +databases. You need to be sure the passwords and the key version +numbers (kvno) are the same in both databases. This may require +explicitly setting the kvno with the @samp{-kvno} option. See +@ref{Cross-realm Authentication} for more details. + +@node Deleting Principals, Changing Passwords, Adding or Modifying Principals, Principals +@subsection Deleting Principals + +To delete a principal, use the kadmin @code{delete_principal} command, +which requires the ``delete'' administrative privilege. The syntax is: + +@smallexample +@b{delete_principal} [@b{-force}] @i{principal} +@end smallexample + +@noindent @code{delete_principal} has the alias @code{delprinc}. The +@code{-force} option causes @code{delete_principal} not to ask if you're +sure. For example: + +@smallexample +@group +@b{kadmin:} delprinc @value{RANDOMUSER1} +@b{Are you sure you want to delete the principal +"@value{RANDOMUSER1}@@@value{PRIMARYREALM}"? (yes/no):} yes +@b{Principal "@value{RANDOMUSER1}@@@value{PRIMARYREALM}" deleted. +Make sure that you have removed this principal from +all ACLs before reusing. +kadmin:} +@end group +@end smallexample + +@node Changing Passwords, , Deleting Principals, Principals +@subsection Changing Passwords + +To change a principal's password use the kadmin @code{change_password} +command, which requires the ``modify'' administrative privilege (unless +the principal is changing his/her own password). The syntax is: + +@smallexample +@b{change_password} [@i{options}] @i{principal} +@end smallexample + +@noindent The @code{change_password} option has the alias @code{cpw}. +@code{change_password} takes the following options: + +@table @b +@item -randkey +Sets the key of the principal to a random value. + +@item @b{-pw} @i{password} +Sets the password to the string @i{password}. @value{COMPANY} does not +recommend using this option. + +@item @b{-e} @i{"enc:salt..."} +Uses the specified list of enctype-salttype pairs for setting the key +of the principal. The quotes are necessary if there are multiple +enctype-salttype pairs. This will not function against kadmin daemons +earlier than krb5-1.2. See @ref{Supported Encryption Types} and +@ref{Salts} for possible values. + +@item @b{-keepold} +Keeps the previous kvno's keys around. There is no easy way to delete +the old keys, and this flag is usually not necessary except perhaps for +TGS keys. Don't use this flag unless you know what you're doing. + +@end table + +For example: + +@smallexample +@group +@b{kadmin:} cpw @value{RANDOMUSER2} +@iftex +@b{Enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{@doubleleftarrow{} Type the new password.} +@b{Re-enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{@doubleleftarrow{} Type it again.} +@end iftex +@ifinfo +@b{Enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{<= Type the new password.} +@b{Re-enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{<= Type it again.} +@end ifinfo +@ifhtml +@b{Enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{<= Type the new password.} +@b{Re-enter password for principal @value{RANDOMUSER2}@@@value{PRIMARYREALM}:} @i{<= Type it again.} +@end ifhtml +@b{Password for @value{RANDOMUSER2}@@@value{PRIMARYREALM} changed. +kadmin:} +@end group +@end smallexample + +Note that @code{change_password} will not let you change the password to +one that is in the principal's password history. + +@node Policies, Global Operations on the Kerberos Database, Principals, Administrating the Kerberos Database +@section Policies + +A policy is a set of rules governing passwords. Policies can dictate +minimum and maximum password lifetimes, minimum number of characters and +character classes a password must contain, and the number of old +passwords kept in the database. + +@menu +* Retrieving Policies:: +* Retrieving the List of Policies:: +* Adding or Modifying Policies:: +* Deleting Policies:: +@end menu + +@node Retrieving Policies, Retrieving the List of Policies, Policies, Policies +@subsection Retrieving Policies + +To retrieve a policy, use the kadmin @code{get_policy} command, which +requires the ``inquire'' administrative privilege. The syntax is: + +@smallexample +@b{get_policy} [@b{-terse}] @i{policy} +@end smallexample + +The @code{get_policy} command has the alias @code{getpol}. For example: + +@smallexample +@group +@b{kadmin:} get_policy admin +@b{Policy: admin +Maximum password life: 180 days 00:00:00 +Minimum password life: 00:00:00 +Minimum password length: 6 +Minimum number of password character classes: 2 +Number of old keys kept: 5 +Reference count: 17 +kadmin:} +@end group +@end smallexample + +@noindent The @dfn{reference count} is the number of principals using +that policy. + +The @code{get_policy} command has a @code{-terse} option, which lists +each field as a quoted, tab-separated string. For example: + +@smallexample +@group +@b{kadmin:} get_policy -terse admin +@b{admin 15552000 0 6 2 5 17 +kadmin:} +@end group +@end smallexample + +@node Retrieving the List of Policies, Adding or Modifying Policies, Retrieving Policies, Policies +@subsection Retrieving the List of Policies + +You can retrieve the list of policies with the kadmin +@code{list_policies} command, which requires the ``list'' privilege. The +syntax is: + +@smallexample +@b{list_policies} [@i{expression}] +@end smallexample + +@noindent where @i{expression} is a shell-style glob expression that can +contain the characters *, ?, and []. All policy names matching the +expression are displayed. The @code{list_policies} command has the aliases +@code{listpols}, @code{get_policies}, and @code{getpols}. For example: + +@smallexample +@group +@b{kadmin:} listpols +@b{test-pol +dict-only +once-a-min +test-pol-nopw} + +@b{kadmin:} listpols t* +@b{test-pol +test-pol-nopw +kadmin:} +@end group +@end smallexample + +@node Adding or Modifying Policies, Deleting Policies, Retrieving the List of Policies, Policies +@subsection Adding or Modifying Policies + +To add a new policy, use the kadmin @code{add_policy} command, which +requires the ``add'' administrative privilege. The syntax is: + +@smallexample +@b{add_policy} [@i{options}] @i{policy_name} +@end smallexample + +To modify attributes of a principal, use the kadmin @code{modify_policy} +command, which requires the ``modify'' administrative privilege. The +syntax is: + +@smallexample +@b{modify_policy} [@i{options}] @i{policy_name} +@end smallexample + +@noindent @code{add_policy} has the alias @code{addpol}. +@code{modify_poilcy} has the alias @code{modpol}. + +The @code{add_policy} and @code{modify_policy} commands take the +following switches: + +@table @b +@item -maxlife @i{time} +Sets the maximum lifetime of a password to @i{time}. + +@item -minlife @i{time} +Sets the minimum lifetime of a password to @i{time}. + +@item -minlength @i{length} +Sets the minimum length of a password to @i{length} characters. + +@item -minclasses @i{number} +Requires at least @i{number} of character classes in a password. + +@item -history @i{number} +Sets the number of past keys kept for a principal to @i{number}. +@end table + +@c **** An example here would be nice. **** + +@node Deleting Policies, , Adding or Modifying Policies, Policies +@subsection Deleting Policies + +To delete a policy, use the @code{kadmin} @code{delete_policy} command, +which requires the ``delete'' administrative privilege. The syntax is: + +@smallexample +@b{delete_policy [-force]} @i{policy_name} +@end smallexample + +@noindent The @code{delete_policy} command has the alias @code{delpol}. +It prompts for confirmation before deletion. +For example: + +@smallexample +@group +@b{kadmin:} delete_policy guests +@b{Are you sure you want to delete the policy "guests"? +(yes/no):} yes +@b{kadmin:} +@end group +@end smallexample + +Note that you must cancel the policy from all principals before deleting +it. The @code{delete_policy} command will fail if it is in use by any +principals. + +@node Global Operations on the Kerberos Database, Cross-realm Authentication, Policies, Administrating the Kerberos Database +@section Global Operations on the Kerberos Database + +@menu +* Dumping a Kerberos Database to a File:: +* Restoring a Kerberos Database from a Dump File:: +* Creating a Stash File:: +* Creating and Destroying a Kerberos Database:: +@end menu + +The @code{kdb5_util} command is the primary tool for administrating the +Kerberos database. The syntax is: + +@smallexample +@b{kdb5_util} @i{command} [@i{kdb5_util_options}] [@i{command_options}] +@end smallexample + +The @code{kdb5_util} command takes the following options, which override +the defaults specified in the configuration files: + +@table @b +@itemx -r @i{realm} +specifies the the Kerberos realm of the database. + +@itemx -d @i{database_name} +specifies the name under which the principal database is stored. + +@itemx -k @i{master_key_type} +specifies the key type of the master key in the database. + +@itemx -M @i{master_key_name} +specifies the principal name of the master key in the database. + +@itemx -m +indicates that the master database password should be read from the TTY +rather than fetched from a file on disk. + +@itemx -sf @i{stash_file} +specifies the stash file of the master database password + +@itemx -P @i{password} +specifies the master database password. @value{COMPANY} does not +recommend using this option. + +@end table + +@node Dumping a Kerberos Database to a File, Restoring a Kerberos Database from a Dump File, Global Operations on the Kerberos Database, Global Operations on the Kerberos Database +@subsection Dumping a Kerberos Database to a File + +To dump a Kerberos database into a file, use the @code{kdb5_util} +@code{dump} command on one of the KDCs. The syntax is: + +@smallexample +@b{kdb5_util dump} [@b{-old}] [@b{-b6}] [@b{-b7}] [@b{-ov}] +[@b{-verbose}] [-mkey_convert] [-new_mkey_file] [@i{filename} +[@i{principals...}]] +@end smallexample + +The @code{kdb5_util dump} command takes the following options: + +@table @b +@itemx -old +causes the dump to be in the Kerberos 5 Beta 5 and earlier dump format +(``kdb5_edit load_dump version 2.0''). +@itemx -b6 +causes the dump to be in the Kerberos 5 Beta 6 format (``kdb5_edit +load_dump version 3.0''). +@itemx -b7 +causes the dump to be in the Kerberos 5 Beta 7 format (``kdbt_edit +load_dump version 4''). +@itemx -ov +causes the dump to be in ovsec_adm_export format. Currently, the only +way to preserve per-principal policy information is to use this in +conjunction with a normal dump. +@itemx -verbose +causes the name of each principal and policy to be printed as it is +dumped. +@itemx -mkey_convert +prompts for a new master password, and then dumps the database with +all keys reencrypted in this new master key +@itemx -new_mkey_file +reads a new key from the default keytab and then dumps the database +with all keys reencrypted in this new master key +@end table + +For example: + +@smallexample +@group +@b{shell%} kdb5_util dump dumpfile +@b{shell%} +@end group +@end smallexample + +@smallexample +@group +@b{shell%} kbd5_util dump -verbose dumpfile +@b{kadmin/admin@@@value{PRIMARYREALM} +krbtgt/@value{PRIMARYREALM}@@@value{PRIMARYREALM} +kadmin/history@@@value{PRIMARYREALM} +K/M@@@value{PRIMARYREALM} +kadmin/changepw@@@value{PRIMARYREALM} +shell%} +@end group +@end smallexample + +@noindent +If you specify which principals to dump, you must use the full +principal, as in the following example. (The line beginning with +@result{} is a continuation of the previous line.): + +@smallexample +@group +@b{shell%} kdb5_util dump -verbose dumpfile K/M@@@value{PRIMARYREALM} +@result{} kadmin/admin@@@value{PRIMARYREALM} +@b{kadmin/admin@@@value{PRIMARYREALM} +K/M@@@value{PRIMARYREALM} +shell%} +@end group +@end smallexample + +@noindent +Otherwise, the principals will not match those in the database and will +not be dumped: + +@smallexample +@group +@b{shell%} kdb5_util dump -verbose dumpfile K/M kadmin/admin +@b{shell%} +@end group +@end smallexample + +@noindent +If you do not specify a dump file, @code{kdb5_util} will dump the +database to the standard output. + +There is currently a bug where the default dump format omits the +per-principal policy information. In order to dump all the data +contained in the Kerberos database, you must perform a normal dump (with +no option flags) and an additional dump using the ``-ov'' flag to a +different file. + +@node Restoring a Kerberos Database from a Dump File, Creating a Stash File, Dumping a Kerberos Database to a File, Global Operations on the Kerberos Database +@subsection Restoring a Kerberos Database from a Dump File + +To restore a Kerberos database dump from a file, use the +@code{kdb5_util} @code{load} command on one of the KDCs. The syntax +is: + +@smallexample +@b{kdb5_util load} [@b{-old}] [@b{-b6}] [@b{-b7}] [@b{-ov}] [@b{-verbose}] +[@b{-update}] [@b{-hash}] @i{dumpfilename} @i{dbname} [@i{admin_dbname}] +@end smallexample + +The @code{kdb5_util load} command takes the following options: + +@table @b +@itemx -old +requires the dump to be in the Kerberos 5 Beta 5 and earlier dump format +(``kdb5_edit load_dump version 2.0''). +@itemx -b6 +requires the dump to be in the Kerberos 5 Beta 6 format (``kdb5_edit +load_dump version 3.0''). +@itemx -b7 +requires the dump to be in the Kerberos 5 Beta 7 format (``kdb5_edit +load_dump version 4''). +@itemx -ov +requires the dump to be in ovsec_adm_export format. +@itemx -verbose +causes the name of each principal and policy to be printed as it is +loaded. +@itemx -update +causes records from the dump file to be updated in or added to the +existing database. This is useful in conjunction with an +ovsec_adm_export format dump if you want to preserve per-principal +policy information, since the current default format does not contain +this data. +@itemx -hash +causes the database to be stored as a hash rather than a binary tree. +@end table + +For example: + +@smallexample +@group +@b{shell%} kdb5_util load dumpfile principal +@b{shell%} +@end group +@end smallexample + +@smallexample +@group +@b{shell%} kdb5_util load -update dumpfile principal +@b{shell%} +@end group +@end smallexample + +@noindent +If the database file exists, and the @b{-update} flag was not given, +@code{kdb5_util} will overwrite the existing database. + +@node Creating a Stash File, Creating and Destroying a Kerberos Database, Restoring a Kerberos Database from a Dump File, Global Operations on the Kerberos Database +@subsection Creating a Stash File + +A stash file allows a KDC to authenticate itself to the database +utilities, such as @code{kadmin}, @code{kadmind}, @code{krb5kdc}, and +@code{kdb5_util}. + +To create a stash file, use the @code{kdb5_util} @code{stash} command. +The syntax is: + +@smallexample +@b{kdb5_util stash} [@b{-f} @i{keyfile}] +@end smallexample + +For example: + +@smallexample +@group +@b{shell%} kdb5_util stash +@b{kdb5_util: Cannot find/read stored master key while reading master key +kdb5_util: Warning: proceeding without master key} +@iftex +@b{Enter KDC database master key:} @i{@doubleleftarrow{} Type the KDC database master password.} +@end iftex +@ifinfo +@b{Enter KDC database master key:} @i{<= Type the KDC database master password.} +@end ifinfo +@ifhtml +@b{Enter KDC database master key:} @i{<= Type the KDC database master password.} +@end ifhtml +@b{shell%} +@end group +@end smallexample + +@noindent +If you do not specify a stash file, @code{kdb5_util} will stash the key +in the file specified in your @code{kdc.conf} file. + +@node Creating and Destroying a Kerberos Database, , Creating a Stash File, Global Operations on the Kerberos Database +@subsection Creating and Destroying a Kerberos Database + +If you need to create a new Kerberos database, use the @code{kdb5_util} +@code{create} command. The syntax is: + +@smallexample +@b{kdb5_util create} [@b{-s}] +@end smallexample + +If you specify the @samp{-s} option, @code{kdb5_util} will stash a copy +of the master key in a stash file. (@xref{Creating a Stash File}.) For +example: + +@smallexample +@group +@b{shell%} @value{ROOTDIR}/sbin/kdb5_util -r @value{PRIMARYREALM} create -s +@b{kdb5_util: No such file or directory while setting active database to +@result{} '@value{ROOTDIR}/var/krb5kdc/principal' +Initializing database '@value{ROOTDIR}/var/krb5kdc/principal' for +@result{} realm '@value{PRIMARYREALM}', +master key name 'K/M@@@value{PRIMARYREALM}' +You will be prompted for the database Master Password. +It is important that you NOT FORGET this password.} +@iftex +@b{Enter KDC database master key:} @i{@doubleleftarrow{} Type the master password.} +@b{Re-enter KDC database master key to verify:} @i{@doubleleftarrow{} Type it again.} +@end iftex +@ifinfo +@b{Enter KDC database master key:} @i{<= Type the master password.} +@b{Re-enter KDC database master key to verify:} @i{<= Type it again.} +@end ifinfo +@ifhtml +@b{Enter KDC database master key:} @i{<= Type the master password.} +@b{Re-enter KDC database master key to verify:} @i{<= Type it again.} +@end ifhtml +@b{shell%} +@end group +@end smallexample + +If you need to destroy the current Kerberos database, use the +@code{kdb5_util} @code{destroy} command. The syntax is: + +@smallexample +@b{kdb5_util destroy} [@b{-f}] +@end smallexample + +The @code{destroy} command destroys the database, first overwriting the +disk sectors and then unlinking the files. If you specify the +@samp{-f} option, @code{kdb5_util} will not prompt you for a +confirmation before destroying the database. + +@smallexample +@group +@b{shell%} @value{ROOTDIR}/sbin/kdb5_util -r @value{PRIMARYREALM} destroy +@iftex +@b{kdb5_util: Deleting KDC database stored in @value{DefaultDatabaseName}, are you sure +(type yes to confirm)?} @i{@doubleleftarrow{}yes} +@end iftex +@ifinfo +@b{kdb5_util: Deleting KDC database stored in @value{DefaultDatabaseName}, are you sure +(type yes to confirm)?} @i{<== yes} +@end ifinfo +@ifhtml +@b{kdb5_util: Deleting KDC database stored in @value{DefaultDatabaseName}, are you sure +(type yes to confirm)?} @i{<== yes} +@end ifhtml +@b{OK, deleting database '@value{DefaultDatabaseName}'...} + +@b{shell%} +@end group +@end smallexample + +@ignore +@c @node The KDC Logs, , Creating and Destroying a Kerberos Database, Administrating the Kerberos Database +@c @section The KDC Logs + +This will have to wait until the next release. *sigh* +@end ignore + +@node Cross-realm Authentication, , Global Operations on the Kerberos Database, Administrating the Kerberos Database +@section Cross-realm Authentication + +In order for a KDC in one realm to authenticate Kerberos users in a +different realm, it must share a key with the KDC in the other realm. +In both databases, there must be krbtgt service principals for realms. +These principals should all have the same passwords, key version +numbers, and encryption types. For example, if the administrators of +@value{PRIMARYREALM} and @value{SECONDREALM} wanted to authenticate +across the realms, they would run the following commands on the KDCs in +@i{both} realms: + +@smallexample +@group +@b{shell%:} kadmin.local -e "des3-hmac-sha1:normal des-cbc-crc:v4" +@b{kadmin:} add_princ -requires_preauth krbtgt/@value{PRIMARYREALM}@@@value{SECONDREALM} +@b{Enter password for principal krbtgt/@value{PRIMARYREALM}@@@value{SECONDREALM}:} +@b{Re-enter password for principal krbtgt/@value{PRIMARYREALM}@@@value{SECONDREALM}:} +@b{kadmin:} add_princ -requires_preauth krbtgt/@value{SECONDREALM}@@@value{PRIMARYREALM} +@b{Enter password for principal krbtgt/@value{SECONDREALM}@@@value{PRIMARYREALM}:} +@b{Enter password for principal krbtgt/@value{SECONDREALM}@@@value{PRIMARYREALML}:} +@b{kadmin:} +@end group +@end smallexample + +Even if most principals in a realm are generally created with the +requires_preauth flag enabled, this flag is not desirable on +cross-realm authentication keys because doing so makes it impossible to +disable preauthentication on a service-by-service basis. Disabling it +as in the example above is recommended. + +It is also very important that these principals have good passwords. +@value{COMPANY} recommends that TGT principal passwords be at least 26 +characters of random ASCII text. + +@node Application Servers, Backups of Secure Hosts, Administrating the Kerberos Database, Top +@chapter Application Servers + +If you need to install the @value{PRODUCT} programs on an application +server, please refer to the @value{PRODUCT} Installation Guide. Once +you have installed the software, you need to add that host to the +Kerberos database (@pxref{Adding or Modifying Principals}), and generate +a @dfn{keytab} for that host, that contains the host's key. You also +need to make sure the host's clock is within your maximum clock skew of +the KDCs. + +@menu +* Keytabs:: +* Clock Skew:: +* Getting DNS Information Correct:: +* Configuring Your Firewall to Work With Kerberos V5:: +@end menu + +@node Keytabs, Clock Skew, Application Servers, Application Servers +@section Keytabs + +A @dfn{keytab} is a host's copy of its own keylist, which is analogous +to a user's password. An application server that needs to authenticate +itself to the KDC has to have a keytab that contains its own principal +and key. Just as it is important for users to protect their passwords, +it is equally important for hosts to protect their keytabs. You should +always store keytab files on local disk, and make them readable only by +root, and you should never send a keytab file over a network in the +clear. Ideally, you should run the @code{kadmin} command to extract a +keytab on the host on which the keytab is to reside. + +@menu +* Adding Principals to Keytabs:: +* Removing Principals from Keytabs:: +@end menu + +@node Adding Principals to Keytabs, Removing Principals from Keytabs, Keytabs, Keytabs +@subsection Adding Principals to Keytabs + +To generate a keytab, or to add a principal to an existing keytab, use +the @code{ktadd} command from @code{kadmin}, which requires the +``inquire'' administrative privilege. (If you use the @b{-glob} +@i{princ_exp} option, it also requires the ``list'' administrative +privilege.) The syntax is: + +@smallexample +@b{ktadd} [@b{-k[eytab]} @i{keytab}] [@b{-q}] [@b{-e} +@i{key:salt_list}] [@i{principal} | @b{-glob} @i{princ_exp}] +[@i{@dots{}}] +@end smallexample + +The @code{ktadd} command takes the following switches: + +@table @b +@item -k[eytab] @i{keytab} +use @i{keytab} as the keytab file. Otherwise, @code{ktadd} will use the +default keytab file (@code{@value{DefaultDefaultKeytabName}}). + +@item @b{-e} @i{"enc:salt..."} +Uses the specified list of enctype-salttype pairs for setting the key +of the principal. The quotes are necessary if there are multiple +enctype-salttype pairs. This will not function against kadmin daemons +earlier than krb5-1.2. See @ref{Supported Encryption Types} and +@ref{Salts} for all possible values. + +@item -q +run in quiet mode. This causes @code{ktadd} to display less verbose +information. + +@item @i{principal} | -glob @i{principal expression} +add @i{principal}, or all principals matching @i{principal expression} +to the keytab. The rules for @i{principal expression} are the same as +for the kadmin @code{list_principals} (@pxref{Retrieving a List of +Principals}) command. +@end table + +Here is a sample session, using configuration files that enable only +@samp{des-cbc-crc} encryption. (The line beginning with @result{} is a +continuation of the previous line.) + +@smallexample +@group +@b{kadmin:} ktadd host/@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} +@b{kadmin: Entry for principal host/@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} with + kvno 2, encryption type DES-CBC-CRC added to keytab + WRFILE:/etc/krb5.keytab. +kadmin:} +@end group +@end smallexample + +@smallexample +@group +@b{kadmin:} ktadd -k @value{ROOTDIR}/var/krb5kdc/kadmind.keytab +@result{} kadmin/admin kadmin/changepw +@b{kadmin: Entry for principal kadmin/admin@@@value{PRIMARYREALM} with + kvno 3, encryption type DES-CBC-CRC added to keytab + WRFILE:@value{ROOTDIR}/var/krb5kdc/kadmind.keytab. +kadmin:} +@end group +@end smallexample + +@node Removing Principals from Keytabs, , Adding Principals to Keytabs, Keytabs +@subsection Removing Principals from Keytabs + +To remove a principal from an existing keytab, use the kadmin +@code{ktremove} command. The syntax is: + +@smallexample +@b{ktremove} [@b{-k[eytab]} @i{keytab}] [@b{-q}] @i{principal} [@i{kvno} | @b{all} | @b{old}] +@end smallexample + +The @code{ktremove} command takes the following switches: + +@table @b +@item -k[eytab] @i{keytab} +use @i{keytab} as the keytab file. Otherwise, @code{ktremove} will use +the default keytab file (@code{/etc/krb5.keytab}). + +@item -q +run in quiet mode. This causes @code{ktremove} to display less verbose +information. + +@item @i{principal} +the principal to remove from the keytab. (Required.) + +@item @i{kvno} +remove all entries for the specified principal whose Key Version Numbers +match @i{kvno}. + +@item all +remove all entries for the specified principal + +@item old +remove all entries for the specified principal except those with the +highest kvno. +@end table + +For example: + +@smallexample +@group +@b{kadmin:} ktremove -k @value{ROOTDIR}/var/krb5kdc/kadmind.keytab kadmin/admin +@b{kadmin: Entry for principal kadmin/admin with kvno 3 removed + from keytab WRFILE:@value{ROOTDIR}/var/krb5kdc/kadmind.keytab. +kadmin:} +@end group +@end smallexample + +@node Clock Skew, Getting DNS Information Correct, Keytabs, Application Servers +@section Clock Skew + +In order to prevent intruders from resetting their system clocks in +order to continue to use expired tickets, @value{PRODUCT} is set up to +reject ticket requests from any host whose clock is not within the +specified maximum clock skew of the KDC (as specified in the +@code{kdc.conf} file). Similarly, hosts are configured to reject +responses from any KDC whose clock is not within the specified maximum +clock skew of the host (as specified in the @code{krb5.conf} file). The +default value for maximum clock skew is @value{DefaultClockskew}. + +@value{COMPANY} suggests that you add a line to client machines' +@code{/etc/rc} files to synchronize the machine's clock to your KDC at +boot time. On UNIX hosts, assuming you had a kdc called +@code{@value{KDCSERVER}} in your realm, this would be: + +@smallexample +gettime -s @value{KDCSERVER} +@end smallexample + +If the host is not likely to be rebooted frequently, you may also want +to set up a cron job that adjusts the time on a regular basis. + +@node Getting DNS Information Correct, Configuring Your Firewall to Work With Kerberos V5, Clock Skew, Application Servers +@section Getting DNS Information Correct + +Several aspects of Kerberos rely on name service. In order for Kerberos +to provide its high level of security, it is less forgiving of name +service problems than some other parts of your network. It is important +that your Domain Name System (DNS) entries and your hosts have the +correct information. + +Each host's canonical name must be the fully-qualified host name +(including the domain), and each host's IP address must reverse-resolve +to the canonical name. + +Other than the @code{localhost} entry, make all entries in each +machine's @code{/etc/hosts} file in the following form: + +@smallexample +IP address fully-qualified hostname aliases +@end smallexample + +Here is a sample @code{/etc/hosts} file: + +@smallexample +@group +# this is a comment +127.0.0.1 localhost localhost@@@value{PRIMARYDOMAIN} +@value{RANDOMHOST1IP} @value{RANDOMHOST1}.@value{PRIMARYDOMAIN} trillium wake-robin +@end group +@end smallexample + +Additionally, on Solaris machines, you need to be sure the ``hosts'' +entry in the file @* @code{/etc/nsswitch.conf} includes the source +``dns'' as well as ``file''. + +Finally, each host's keytab file must include a host/key pair for the +host's canonical name. You can list the keys in a keytab file by +issuing the command @code{klist -k}. For example: + +@smallexample +@group +viola# klist -k +Keytab name: /etc/krb5.keytab +KVNO Principal +---- ------------------------------------------------------------ + 1 host/@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} +@end group +@end smallexample + +If you telnet to the host with a fresh credentials cache (ticket file), +and then @code{klist}, the host's service principal should be +@i{host/fully-qualified-hostname@@REALM_NAME}. + +@node Configuring Your Firewall to Work With Kerberos V5, , Getting DNS Information Correct, Application Servers +@section Configuring Your Firewall to Work With @value{PRODUCT} + +If you need off-site users to be able to get Kerberos tickets in your +realm, they must be able to get to your KDC. This requires either that +you have a slave KDC outside your firewall, or you configure your +firewall to allow UDP requests into at least one of your KDCs, on +whichever port the KDC is running. (The default is port +@value{DefaultPort}; other ports may be specified in the KDC's kdc.conf +file.) Similarly, if you need off-site users to be able to change +their passwords in your realm, they must be able to get to your +Kerberos admin server. The default port for the admin server is +@value{DefaultKadmindPort}. + +If your on-site users inside your firewall will need to get to KDCs in +other realms, you will also need to configure your firewall to allow +outgoing TCP and UDP requests to port @value{DefaultPort}. +Additionally, if they will need to get to any Kerberos V4 KDCs, you may +also need to allow TCP and UDP requests to port +@value{DefaultSecondPort}. If your on-site users inside your firewall +will need to get to Kerberos admin servers in other realms, you will +also need to allow outgoing TCP and UDP requests to port +@value{DefaultKadmindPort}. + +If any of your KDCs are outside your firewall, you will need to allow +@code{kprop} requests to get through to the remote KDC. @code{Kprop} +uses the krb5_prop service on port @value{DefaultKrbPropPort} (tcp). + +If you need your off-site users to have access to machines inside your +firewall, you need to allow TCP connections from their off-site hosts on +the appropriate ports for the programs they will be using. The +following lines from @code{/etc/services} show the default port numbers +for the @value{PRODUCT} programs: + +@smallexample +@group +ftp @value{DefaultFTPPort}/tcp # Kerberos ftp and telnet use the +telnet @value{DefaultTelnetPort}/tcp # default ports +kerberos @value{DefaultPort}/udp kdc # Kerberos V5 KDC +kerberos @value{DefaultPort}/tcp kdc # Kerberos V5 KDC +klogin @value{DefaultKloginPort}/tcp # Kerberos authenticated rlogin +kshell @value{DefaultKshellPort}/tcp cmd # and remote shell +kerberos-adm @value{DefaultKadmindPort}/tcp # Kerberos 5 admin/changepw +kerberos-adm @value{DefaultKadmindPort}/udp # Kerberos 5 admin/changepw +krb5_prop @value{DefaultKrbPropPort}/tcp # Kerberos slave propagation +@c kpop 1109/tcp # Pop with Kerberos +eklogin @value{DefaultEkloginPort}/tcp # Kerberos auth. & encrypted rlogin +krb524 @value{DefaultKrb524Port}/tcp # Kerberos 5 to 4 ticket translator +@end group +@end smallexample + +By default, @value{PRODUCT} @code{telnet} and @code{ftp} use the same +ports as the standard @code{telnet} and @code{ftp} programs, so if you +already allow telnet and ftp connections through your firewall, the +@value{PRODUCT} versions will get through as well. If you do not +already allow telnet and ftp connections through your firewall, but need +your users to be able to use @value{PRODUCT} telnet and ftp, you can +either allow ftp and telnet connections on the standard ports, or switch +these programs to non-default port numbers and allow ftp and telnet +connections on those ports to get through. + +@value{PRODUCT} @code{rlogin} uses the @code{klogin} service, which by +default uses port @value{DefaultKloginPort}. Encrypted @value{PRODUCT} +rlogin uses the @code{eklogin} service, which by default uses port +@value{DefaultEkloginPort}. + +@value{PRODUCT} @code{rsh} uses the @code{kshell} service, which by +default uses port @value{DefaultKshellPort}. However, the server must +be able to make a TCP connection from the kshell port to an arbitrary +port on the client, so if your users are to be able to use @code{rsh} +from outside your firewall, the server they connect to must be able to +send outgoing packets to arbitrary port numbers. Similarly, if your +users need to run @code{rsh} from inside your firewall to hosts outside +your firewall, the outside server needs to be able to connect to an +arbitrary port on the machine inside your firewall. Because +@value{PRODUCT} @code{rcp} uses @code{rsh}, the same issues apply. If +you need to use @code{rsh} (or @code{rcp}) through your firewall and +are concerned with the security implications of allowing connections to +arbitrary ports, @value{COMPANY} suggests that you have rules that +specifically name these applications and, if possible, list the allowed +hosts. + +The book @cite{UNIX System Security}, by David Curry, is a good +starting point for learning to configure firewalls. + +@ignore +@c @node Enabling Users to Connect from Off-Site, , Configuring Your Firewall to Work With @value{PRODUCT}, Application Servers +@c @section Enabling Users to Connect from Off-Site + +This will have to wait until the next release. *sigh* +@end ignore + +@node Backups of Secure Hosts, Bug Reporting, Application Servers, Top +@chapter Backups of Secure Hosts + +When you back up a secure host, you should exclude the host's keytab +file from the backup. If someone obtained a copy of the keytab from a +backup, that person could make any host masquerade as the host whose +keytab was compromised. This could be particularly dangerous if the +compromised keytab was from one of your KDCs. If the machine has a disk +crash and the keytab file is lost, it is easy to generate another keytab +file. (@xref{Adding Principals to Keytabs}.) If you are unable to +exclude particular files from backups, you should ensure that the +backups are kept as secure as the host's root password. + +@menu +* Backing Up the Kerberos Database:: +@end menu + +@node Backing Up the Kerberos Database, , Backups of Secure Hosts, Backups of Secure Hosts +@section Backing Up the Kerberos Database + +As with any file, it is possible that your Kerberos database could +become corrupted. If this happens on one of the slave KDCs, you might +never notice, since the next automatic propagation of the database would +install a fresh copy. However, if it happens to the master KDC, the +corrupted database would be propagated to all of the slaves during the +next propagation. For this reason, @value{COMPANY} recommends that you +back up your Kerberos database regularly. Because the master KDC is +continuously dumping the database to a file in order to propagate it to +the slave KDCs, it is a simple matter to have a cron job periodically +copy the dump file to a secure machine elsewhere on your network. (Of +course, it is important to make the host where these backups are stored +as secure as your KDCs, and to encrypt its transmission across your +network.) Then if your database becomes corrupted, you can load the +most recent dump onto the master KDC. (@xref{Restoring a Kerberos +Database from a Dump File}.) + +@node Bug Reporting, Appendix, Backups of Secure Hosts, Top +@chapter Bug Reporting + +@include send-pr.texinfo + +@node Appendix, , Bug Reporting, Top +@appendix Appendix + +@menu +* Errors:: +* kadmin Time Zones:: +@end menu + +@node Errors, kadmin Time Zones, Appendix, Appendix +@appendixsec Kerberos Error Messages + +@menu +* Kerberos V5 Library Error Codes:: +* Kerberos V5 Database Library Error Codes:: +* Kerberos V5 Magic Numbers Error Codes:: +* ASN.1 Error Codes:: +* GSSAPI Error Codes:: +@end menu + +@node Kerberos V5 Library Error Codes, Kerberos V5 Database Library Error Codes, Errors, Errors +@appendixsubsec Kerberos V5 Library Error Codes + +This is the Kerberos v5 library error code table. Protocol error codes +are @* ERROR_TABLE_BASE_krb5 + the protocol error code number; other +error codes start at ERROR_TABLE_BASE_krb5 + 128. + +@c error table numbering starts at 0 +@enumerate 0 +@item +KRB5KDC_ERR_NONE: No error +@item +KRB5KDC_ERR_NAME_EXP: Client's entry in database has expired +@item +KRB5KDC_ERR_SERVICE_EXP: Server's entry in database has expired +@item +KRB5KDC_ERR_BAD_PVNO: Requested protocol version not supported +@item +KRB5KDC_ERR_C_OLD_MAST_KVNO: Client's key is encrypted in an old master +key +@item +KRB5KDC_ERR_S_OLD_MAST_KVNO: Server's key is encrypted in an old master +key +@item +KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: Client not found in Kerberos database +@item +KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: Server not found in Kerberos database +@item +KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE: Principal has multiple entries in +Kerberos database +@item +KRB5KDC_ERR_NULL_KEY: Client or server has a null key +@item +KRB5KDC_ERR_CANNOT_POSTDATE: Ticket is ineligible for postdating +@item +KRB5KDC_ERR_NEVER_VALID: Requested effective lifetime is negative or +too short +@item +KRB5KDC_ERR_POLICY: KDC policy rejects request +@item +KRB5KDC_ERR_BADOPTION: KDC can't fulfill requested option +@item +KRB5KDC_ERR_ETYPE_NOSUPP: KDC has no support for encryption type +@item +KRB5KDC_ERR_SUMTYPE_NOSUPP: KDC has no support for checksum type +@item +KRB5KDC_ERR_PADATA_TYPE_NOSUPP: KDC has no support for padata type +@item +KRB5KDC_ERR_TRTYPE_NOSUPP: KDC has no support for transited type +@item +KRB5KDC_ERR_CLIENT_REVOKED: Clients credentials have been revoked +@item +KRB5KDC_ERR_SERVICE_REVOKED: Credentials for server have been revoked +@item +KRB5KDC_ERR_TGT_REVOKED: TGT has been revoked +@item +KRB5KDC_ERR_CLIENT_NOTYET: Client not yet valid - try again later +@item +KRB5KDC_ERR_SERVICE_NOTYET: Server not yet valid - try again later +@item +KRB5KDC_ERR_KEY_EXP: Password has expired +@item +KRB5KDC_ERR_PREAUTH_FAILED: Preauthentication failed +@item +KRB5KDC_ERR_PREAUTH_REQUIRED: Additional pre-auth@-en@-ti@-ca@-tion required +@item +KRB5KDC_ERR_SERVER_NOMATCH: Requested server and ticket don't match +@item +KRB5PLACEHOLD_27: KRB5 error code 27 +@item +KRB5PLACEHOLD_28: KRB5 error code 28 +@item +KRB5PLACEHOLD_29: KRB5 error code 29 +@item +KRB5PLACEHOLD_30: KRB5 error code 30 +@item +KRB5KRB_AP_ERR_BAD_INTEGRITY: Decrypt integrity check failed +@item +KRB5KRB_AP_ERR_TKT_EXPIRED: Ticket expired +@item +KRB5KRB_AP_ERR_TKT_NYV: Ticket not yet valid +@item +KRB5KRB_AP_ERR_REPEAT: Request is a replay +@item +KRB5KRB_AP_ERR_NOT_US: The ticket isn't for us +@item +KRB5KRB_AP_ERR_BADMATCH: Ticket/authenticator don't match +@item +KRB5KRB_AP_ERR_SKEW: Clock skew too great +@item +KRB5KRB_AP_ERR_BADADDR: Incorrect net address +@item +KRB5KRB_AP_ERR_BADVERSION: Protocol version mismatch +@item +KRB5KRB_AP_ERR_MSG_TYPE: Invalid message type +@item +KRB5KRB_AP_ERR_MODIFIED: Message stream modified +@item +KRB5KRB_AP_ERR_BADORDER: Message out of order +@item +KRB5KRB_AP_ERR_ILL_CR_TKT: Illegal cross-realm ticket +@item +KRB5KRB_AP_ERR_BADKEYVER: Key version is not available +@item +KRB5KRB_AP_ERR_NOKEY: Service key not available +@item +KRB5KRB_AP_ERR_MUT_FAIL: Mutual authentication failed +@item +KRB5KRB_AP_ERR_BADDIRECTION: Incorrect message direction +@item +KRB5KRB_AP_ERR_METHOD: Alternative authentication method required +@item +KRB5KRB_AP_ERR_BADSEQ: Incorrect sequence number in message +@item +KRB5KRB_AP_ERR_INAPP_CKSUM: Inappropriate type of checksum in message +@item +KRB5KRB_AP_PATH_NOT_ACCEPTED: Policy rejects transited path +@item +KRB5KRB_ERR_RESPONSE_TOO_BIG: Response too big for UDP, retry with TCP +@item +KRB5PLACEHOLD_53: KRB5 error code 53 +@item +KRB5PLACEHOLD_54: KRB5 error code 54 +@item +KRB5PLACEHOLD_55: KRB5 error code 55 +@item +KRB5PLACEHOLD_56: KRB5 error code 56 +@item +KRB5PLACEHOLD_57: KRB5 error code 57 +@item +KRB5PLACEHOLD_58: KRB5 error code 58 +@item +KRB5PLACEHOLD_59: KRB5 error code 59 +@item +KRB5KRB_ERR_GENERIC: Generic error (see e-text) +@item +KRB5KRB_ERR_FIELD_TOOLONG: Field is too long for this implementation +@item +KRB5PLACEHOLD_62: KRB5 error code 62 +@item +KRB5PLACEHOLD_63: KRB5 error code 63 +@item +KRB5PLACEHOLD_64: KRB5 error code 64 +@item +KRB5PLACEHOLD_65: KRB5 error code 65 +@item +KRB5PLACEHOLD_66: KRB5 error code 66 +@item +KRB5PLACEHOLD_67: KRB5 error code 67 +@item +KRB5PLACEHOLD_68: KRB5 error code 68 +@item +KRB5PLACEHOLD_69: KRB5 error code 69 +@item +KRB5PLACEHOLD_70: KRB5 error code 70 +@item +KRB5PLACEHOLD_71: KRB5 error code 71 +@item +KRB5PLACEHOLD_72: KRB5 error code 72 +@item +KRB5PLACEHOLD_73: KRB5 error code 73 +@item +KRB5PLACEHOLD_74: KRB5 error code 74 +@item +KRB5PLACEHOLD_75: KRB5 error code 75 +@item +KRB5PLACEHOLD_76: KRB5 error code 76 +@item +KRB5PLACEHOLD_77: KRB5 error code 77 +@item +KRB5PLACEHOLD_78: KRB5 error code 78 +@item +KRB5PLACEHOLD_79: KRB5 error code 79 +@item +KRB5PLACEHOLD_80: KRB5 error code 80 +@item +KRB5PLACEHOLD_81: KRB5 error code 81 +@item +KRB5PLACEHOLD_82: KRB5 error code 82 +@item +KRB5PLACEHOLD_83: KRB5 error code 83 +@item +KRB5PLACEHOLD_84: KRB5 error code 84 +@item +KRB5PLACEHOLD_85: KRB5 error code 85 +@item +KRB5PLACEHOLD_86: KRB5 error code 86 +@item +KRB5PLACEHOLD_87: KRB5 error code 87 +@item +KRB5PLACEHOLD_88: KRB5 error code 88 +@item +KRB5PLACEHOLD_89: KRB5 error code 89 +@item +KRB5PLACEHOLD_90: KRB5 error code 90 +@item +KRB5PLACEHOLD_91: KRB5 error code 91 +@item +KRB5PLACEHOLD_92: KRB5 error code 92 +@item +KRB5PLACEHOLD_93: KRB5 error code 93 +@item +KRB5PLACEHOLD_94: KRB5 error code 94 +@item +KRB5PLACEHOLD_95: KRB5 error code 95 +@item +KRB5PLACEHOLD_96: KRB5 error code 96 +@item +KRB5PLACEHOLD_97: KRB5 error code 97 +@item +KRB5PLACEHOLD_98: KRB5 error code 98 +@item +KRB5PLACEHOLD_99: KRB5 error code 99 +@item +KRB5PLACEHOLD_100: KRB5 error code 100 +@item +KRB5PLACEHOLD_101: KRB5 error code 101 +@item +KRB5PLACEHOLD_102: KRB5 error code 102 +@item +KRB5PLACEHOLD_103: KRB5 error code 103 +@item +KRB5PLACEHOLD_104: KRB5 error code 104 +@item +KRB5PLACEHOLD_105: KRB5 error code 105 +@item +KRB5PLACEHOLD_106: KRB5 error code 106 +@item +KRB5PLACEHOLD_107: KRB5 error code 107 +@item +KRB5PLACEHOLD_108: KRB5 error code 108 +@item +KRB5PLACEHOLD_109: KRB5 error code 109 +@item +KRB5PLACEHOLD_110: KRB5 error code 110 +@item +KRB5PLACEHOLD_111: KRB5 error code 111 +@item +KRB5PLACEHOLD_112: KRB5 error code 112 +@item +KRB5PLACEHOLD_113: KRB5 error code 113 +@item +KRB5PLACEHOLD_114: KRB5 error code 114 +@item +KRB5PLACEHOLD_115: KRB5 error code 115 +@item +KRB5PLACEHOLD_116: KRB5 error code 116 +@item +KRB5PLACEHOLD_117: KRB5 error code 117 +@item +KRB5PLACEHOLD_118: KRB5 error code 118 +@item +KRB5PLACEHOLD_119: KRB5 error code 119 +@item +KRB5PLACEHOLD_120: KRB5 error code 120 +@item +KRB5PLACEHOLD_121: KRB5 error code 121 +@item +KRB5PLACEHOLD_122: KRB5 error code 122 +@item +KRB5PLACEHOLD_123: KRB5 error code 123 +@item +KRB5PLACEHOLD_124: KRB5 error code 124 +@item +KRB5PLACEHOLD_125: KRB5 error code 125 +@item +KRB5PLACEHOLD_126: KRB5 error code 126 +@item +KRB5PLACEHOLD_127: KRB5 error code 127 +@item +KRB5_ERR_RCSID: (RCS Id string for the krb5 error table) +@item +KRB5_LIBOS_BADLOCKFLAG: Invalid flag for file lock mode +@item +KRB5_LIBOS_CANTREADPWD: Cannot read password +@item +KRB5_LIBOS_BADPWDMATCH: Password mismatch +@item +KRB5_LIBOS_PWDINTR: Password read interrupted +@item +KRB5_PARSE_ILLCHAR: Illegal character in component name +@item +KRB5_PARSE_MALFORMED: Malformed representation of principal +@item +KRB5_CONFIG_CANTOPEN: Can't open/find Kerberos configuration file +@item +KRB5_CONFIG_BADFORMAT: Improper format of Kerberos configuration file +@item +KRB5_CONFIG_NOTENUFSPACE: Insufficient space to return complete +information +@item +KRB5_BADMSGTYPE: Invalid message type specified for encoding +@item +KRB5_CC_BADNAME: Credential cache name malformed +@item +KRB5_CC_UNKNOWN_TYPE: Unknown credential cache type +@item +KRB5_CC_NOTFOUND: Matching credential not found +@item +KRB5_CC_END: End of credential cache reached +@item +KRB5_NO_TKT_SUPPLIED: Request did not supply a ticket +@item +KRB5KRB_AP_WRONG_PRINC: Wrong principal in request +@item +KRB5KRB_AP_ERR_TKT_INVALID: Ticket has invalid flag set +@item +KRB5_PRINC_NOMATCH: Requested principal and ticket don't match +@item +KRB5_KDCREP_MODIFIED: KDC reply did not match expectations +@item +KRB5_KDCREP_SKEW: Clock skew too great in KDC reply +@item +KRB5_IN_TKT_REALM_MISMATCH: Client/server realm mismatch in initial +ticket request +@item +KRB5_PROG_ETYPE_NOSUPP: Program lacks support for encryption type +@item +KRB5_PROG_KEYTYPE_NOSUPP: Program lacks support for key type +@item +KRB5_WRONG_ETYPE: Requested encryption type not used in message +@item +KRB5_PROG_SUMTYPE_NOSUPP: Program lacks support for checksum type +@item +KRB5_REALM_UNKNOWN: Cannot find KDC for requested realm +@item +KRB5_SERVICE_UNKNOWN: Kerberos service unknown +@item +KRB5_KDC_UNREACH: Cannot contact any KDC for requested realm +@item +KRB5_NO_LOCALNAME: No local name found for principal name +@item +KRB5_MUTUAL_FAILED: Mutual authentication failed +@item +KRB5_RC_TYPE_EXISTS: Replay cache type is already registered +@item +KRB5_RC_MALLOC: No more memory to allocate (in replay cache code) +@item +KRB5_RC_TYPE_NOTFOUND: Replay cache type is unknown +@item +KRB5_RC_UNKNOWN: Generic unknown RC error +@item +KRB5_RC_REPLAY: Message is a replay +@item +KRB5_RC_IO: Replay I/O operation failed XXX +@item +KRB5_RC_NOIO: Replay cache type does not support non-volatile storage +@item +KRB5_RC_PARSE: Replay cache name parse/format error +@item +KRB5_RC_IO_EOF: End-of-file on replay cache I/O +@item +KRB5_RC_IO_MALLOC: No more memory to allocate (in replay cache I/O +code) +@item +KRB5_RC_IO_PERM: Permission denied in replay cache code +@item +KRB5_RC_IO_IO: I/O error in replay cache i/o code +@item +KRB5_RC_IO_UNKNOWN: Generic unknown RC/IO error +@item +KRB5_RC_IO_SPACE: Insufficient system space to store replay information +@item +KRB5_TRANS_CANTOPEN: Can't open/find realm translation file +@item +KRB5_TRANS_BADFORMAT: Improper format of realm translation file +@item +KRB5_LNAME_CANTOPEN: Can't open/find lname translation database +@item +KRB5_LNAME_NOTRANS: No translation available for requested principal +@item +KRB5_LNAME_BADFORMAT: Improper format of translation database entry +@item +KRB5_CRYPTO_INTERNAL: Cryptosystem internal error +@item +KRB5_KT_BADNAME: Key table name malformed +@item +KRB5_KT_UNKNOWN_TYPE: Unknown Key table type +@item +KRB5_KT_NOTFOUND: Key table entry not found +@item +KRB5_KT_END: End of key table reached +@item +KRB5_KT_NOWRITE: Cannot write to specified key table +@item +KRB5_KT_IOERR: Error writing to key table +@item +KRB5_NO_TKT_IN_RLM: Cannot find ticket for requested realm +@item +KRB5DES_BAD_KEYPAR: DES key has bad parity +@item +KRB5DES_WEAK_KEY: DES key is a weak key +@item +KRB5_BAD_ENCTYPE: Bad encryption type +@item +KRB5_BAD_KEYSIZE: Key size is incompatible with encryption type +@item +KRB5_BAD_MSIZE: Message size is incompatible with encryption type +@item +KRB5_CC_TYPE_EXISTS: Credentials cache type is already registered. +@item +KRB5_KT_TYPE_EXISTS: Key table type is already registered. +@item +KRB5_CC_IO: Credentials cache I/O operation failed XXX +@item +KRB5_FCC_PERM: Credentials cache file permissions incorrect +@item +KRB5_FCC_NOFILE: No credentials cache found +@item +KRB5_FCC_INTERNAL: Internal credentials cache error +@item +KRB5_CC_WRITE: Error writing to credentials cache +@item +KRB5_CC_NOMEM: No more memory to allocate (in credentials cache code) +@item +KRB5_CC_FORMAT: Bad format in credentials cache +@item +KRB5_INVALID_FLAGS: Invalid KDC option combination (library internal +error) [for dual tgt library calls] +@item +KRB5_NO_2ND_TKT: Request missing second ticket [for dual tgt library +calls] +@item +KRB5_NOCREDS_SUPPLIED: No credentials supplied to library routine +@item +KRB5_SENDAUTH_BADAUTHVERS: Bad sendauth version was sent +@item +KRB5_SENDAUTH_BADAPPLVERS: Bad application version was sent (via +sendauth) +@item +KRB5_SENDAUTH_BADRESPONSE: Bad response (during sendauth exchange) +@item +KRB5_SENDAUTH_REJECTED: Server rejected authentication (during sendauth +exchange) +@item +KRB5_PREAUTH_BAD_TYPE: Unsupported preauthentication type +@item +KRB5_PREAUTH_NO_KEY: Required preauthentication key not supplied +@item +KRB5_PREAUTH_FAILED: Generic preauthentication failure +@item +KRB5_RCACHE_BADVNO: Unsupported replay cache format version number +@item +KRB5_CCACHE_BADVNO: Unsupported credentials cache format version number +@item +KRB5_KEYTAB_BADVNO: Unsupported key table format version number +@item +KRB5_PROG_ATYPE_NOSUPP: Program lacks support for address type +@item +KRB5_RC_REQUIRED: Message replay detection requires rcache parameter +@item +KRB5_ERR_BAD_HOSTNAME: Hostname cannot be canonicalized +@item +KRB5_ERR_HOST_REALM_UNKNOWN: Cannot determine realm for host +@item +KRB5_SNAME_UNSUPP_NAMETYPE: Conversion to service principal undefined +for name type +@item +KRB5KRB_AP_ERR_V4_REPLY: Initial Ticket response appears to be Version +4 error +@item +KRB5_REALM_CANT_RESOLVE: Cannot resolve KDC for requested realm +@item +KRB5_TKT_NOT_FORWARDABLE: Requesting ticket can't get forwardable +tickets +@item +KRB5_FWD_BAD_PRINCIPAL: Bad principal name while trying to forward +credentials +@item +KRB5_GET_IN_TKT_LOOP: Looping detected inside krb5_get_in_tkt +@item +KRB5_CONFIG_NODEFREALM: Configuration file does not specify default realm +@item +KRB5_SAM_UNSUPPORTED: Bad SAM flags in obtain_sam_padata +@item +KRB5_KT_NAME_TOOLONG: Keytab name too long +@item +KRB5_KT_KVNONOTFOUND: Key version number for principal in key table is incorrect +@item +KRB5_APPL_EXPIRED: This application has expired +@item +KRB5_LIB_EXPIRED: This Krb5 library has expired +@item +KRB5_CHPW_PWDNULL: New password cannot be zero length +@item +KRB5_CHPW_FAIL: Password change failed +@item +KRB5_KT_FORMAT: Bad format in keytab +@item +KRB5_NOPERM_ETYPE: Encryption type not permitted +@item +KRB5_CONFIG_ETYPE_NOSUPP: No supported encryption types (config file error?) +@item +KRB5_OBSOLETE_FN: Program called an obsolete, deleted function +@item +KRB5_EAI_FAIL: unknown getaddrinfo failure +@item +KRB5_EAI_NODATA: no data available for host/domain name +@item +KRB5_EAI_NONAME: host/domain name not found +@item +KRB5_EAI_SERVICE: service name unknown +@item +KRB5_ERR_NUMERIC_REALM: Cannot determine realm for numeric host address +@end enumerate + +@node Kerberos V5 Database Library Error Codes, Kerberos V5 Magic Numbers Error Codes, Kerberos V5 Library Error Codes, Errors +@appendixsubsec Kerberos V5 Database Library Error Codes + +This is the Kerberos v5 database library error code table. + +@c error table numbering starts at 0 +@enumerate 0 +@item +KRB5_KDB_RCSID: (RCS Id string for the kdb error table) +@item +KRB5_KDB_INUSE: Entry already exists in database +@item +KRB5_KDB_UK_SERROR: Database store error +@item +KRB5_KDB_UK_RERROR: Database read error +@item +KRB5_KDB_UNAUTH: Insufficient access to perform requested operation +@item +KRB5_KDB_NOENTRY: No such entry in the database +@item +KRB5_KDB_ILL_WILDCARD: Illegal use of wildcard +@item +KRB5_KDB_DB_INUSE: Database is locked or in use--try again later +@item +KRB5_KDB_DB_CHANGED: Database was modified during read +@item +KRB5_KDB_TRUNCATED_RECORD: Database record is incomplete or corrupted +@item +KRB5_KDB_RECURSIVELOCK: Attempt to lock database twice +@item +KRB5_KDB_NOTLOCKED: Attempt to unlock database when not locked +@item +KRB5_KDB_BADLOCKMODE: Invalid kdb lock mode +@item +KRB5_KDB_DBNOTINITED: Database has not been initialized +@item +KRB5_KDB_DBINITED: Database has already been initialized +@item +KRB5_KDB_ILLDIRECTION: Bad direction for converting keys +@item +KRB5_KDB_NOMASTERKEY: Cannot find master key record in database +@item +KRB5_KDB_BADMASTERKEY: Master key does not match database +@item +KRB5_KDB_INVALIDKEYSIZE: Key size in database is invalid +@item +KRB5_KDB_CANTREAD_STORED: Cannot find/read stored master key +@item +KRB5_KDB_BADSTORED_MKEY: Stored master key is corrupted +@item +KRB5_KDB_CANTLOCK_DB: Insufficient access to lock database +@item +KRB5_KDB_DB_CORRUPT: Database format error +@item +KRB5_KDB_BAD_VERSION: Unsupported version in database entry +@item +KRB5_KDB_BAD_SALTTYPE: Unsupported salt type +@item +KRB5_KDB_BAD_ENCTYPE: Unsupported encryption type +@item +KRB5_KDB_BAD_CREATEFLAGS: Bad database creation flags +@item +KRB5_KDB_NO_PERMITTED_KEY: No matching key in entry having a permitted enc type +@item +KRB5_KDB_NO_MATCHING_KEY: No matching key in entry +@end enumerate + +@node Kerberos V5 Magic Numbers Error Codes, ASN.1 Error Codes, Kerberos V5 Database Library Error Codes, Errors +@appendixsubsec Kerberos V5 Magic Numbers Error Codes + +This is the Kerberos v5 magic numbers error code table. + +@c error table numbering starts at 0 +@enumerate 0 +@item +KV5M_NONE: Kerberos V5 magic number table +@item +KV5M_PRINCIPAL: Bad magic number for krb5_principal structure +@item +KV5M_DATA: Bad magic number for krb5_data structure +@item +KV5M_KEYBLOCK: Bad magic number for krb5_keyblock structure +@item +KV5M_CHECKSUM: Bad magic number for krb5_checksum structure +@item +KV5M_ENCRYPT_BLOCK: Bad magic number for krb5_encrypt_block structure +@item +KV5M_ENC_DATA: Bad magic number for krb5_enc_data structure +@item +KV5M_CRYPTOSYSTEM_ENTRY: Bad magic number for krb5_cryp@-to@-sys@-tem_entry +structure +@item +KV5M_CS_TABLE_ENTRY: Bad magic number for krb5_cs_table_entry structure +@item +KV5M_CHECKSUM_ENTRY: Bad magic number for krb5_check@-sum_en@-try structure +@item +KV5M_AUTHDATA: Bad magic number for krb5_authdata structure +@item +KV5M_TRANSITED: Bad magic number for krb5_transited structure +@item +KV5M_ENC_TKT_PART: Bad magic number for krb5_enc_tkt_part structure +@item +KV5M_TICKET: Bad magic number for krb5_ticket structure +@item +KV5M_AUTHENTICATOR: Bad magic number for krb5_authenticator structure +@item +KV5M_TKT_AUTHENT: Bad magic number for krb5_tkt_authent structure +@item +KV5M_CREDS: Bad magic number for krb5_creds structure +@item +KV5M_LAST_REQ_ENTRY: Bad magic number for krb5_last_req_entry structure +@item +KV5M_PA_DATA: Bad magic number for krb5_pa_data structure +@item +KV5M_KDC_REQ: Bad magic number for krb5_kdc_req structure +@item +KV5M_ENC_KDC_REP_PART: Bad magic number for @* +krb5_enc_kdc_rep_part structure +@item +KV5M_KDC_REP: Bad magic number for krb5_kdc_rep structure +@item +KV5M_ERROR: Bad magic number for krb5_error structure +@item +KV5M_AP_REQ: Bad magic number for krb5_ap_req structure +@item +KV5M_AP_REP: Bad magic number for krb5_ap_rep structure +@item +KV5M_AP_REP_ENC_PART: Bad magic number for @* +krb5_ap_rep_enc_part structure +@item +KV5M_RESPONSE: Bad magic number for krb5_response structure +@item +KV5M_SAFE: Bad magic number for krb5_safe structure +@item +KV5M_PRIV: Bad magic number for krb5_priv structure +@item +KV5M_PRIV_ENC_PART: Bad magic number for krb5_priv_enc_part structure +@item +KV5M_CRED: Bad magic number for krb5_cred structure +@item +KV5M_CRED_INFO: Bad magic number for krb5_cred_info structure +@item +KV5M_CRED_ENC_PART: Bad magic number for krb5_cred_enc_part structure +@item +KV5M_PWD_DATA: Bad magic number for krb5_pwd_data structure +@item +KV5M_ADDRESS: Bad magic number for krb5_address structure +@item +KV5M_KEYTAB_ENTRY: Bad magic number for krb5_keytab_entry structure +@item +KV5M_CONTEXT: Bad magic number for krb5_context structure +@item +KV5M_OS_CONTEXT: Bad magic number for krb5_os_context structure +@item +KV5M_ALT_METHOD: Bad magic number for krb5_alt_method structure +@item +KV5M_ETYPE_INFO_ENTRY: Bad magic number for @* +krb5_etype_info_entry structure +@item +KV5M_DB_CONTEXT: Bad magic number for krb5_db_context structure +@item +KV5M_AUTH_CONTEXT: Bad magic number for krb5_auth_context structure +@item +KV5M_KEYTAB: Bad magic number for krb5_keytab structure +@item +KV5M_RCACHE: Bad magic number for krb5_rcache structure +@item +KV5M_CCACHE: Bad magic number for krb5_ccache structure +@item +KV5M_PREAUTH_OPS: Bad magic number for krb5_preauth_ops +@item +KV5M_SAM_CHALLENGE: Bad magic number for krb5_sam_challenge +@item +KV5M_SAM_KEY: Bad magic number for krb5_sam_key +@item +KV5M_ENC_SAM_RESPONSE_ENC: Bad magic number for @* +krb5_enc_sam_response_enc +@item +KV5M_SAM_RESPONSE: Bad magic number for krb5_sam_response +@item +KV5M_PREDICTED_SAM_RESPONSE: Bad magic number for +krb5_predicted_sam_response +@item +KV5M_PASSWD_PHRASE_ELEMENT: Bad magic number for passwd_phrase_element +@item +KV5M_GSS_OID: Bad magic number for GSSAPI OID +@item +KV5M_GSS_QUEUE: Bad magic number for GSSAPI QUEUE +@end enumerate + +@node ASN.1 Error Codes, GSSAPI Error Codes, Kerberos V5 Magic Numbers Error Codes, Errors +@appendixsubsec ASN.1 Error Codes + +@c error table numbering starts at 0 +@enumerate 0 +@item +ASN1_BAD_TIMEFORMAT: ASN.1 failed call to system time library +@item +ASN1_MISSING_FIELD: ASN.1 structure is missing a required field +@item +ASN1_MISPLACED_FIELD: ASN.1 unexpected field number +@item +ASN1_TYPE_MISMATCH: ASN.1 type numbers are inconsistent +@item +ASN1_OVERFLOW: ASN.1 value too large +@item +ASN1_OVERRUN: ASN.1 encoding ended unexpectedly +@item +ASN1_BAD_ID: ASN.1 identifier doesn't match expected value +@item +ASN1_BAD_LENGTH: ASN.1 length doesn't match expected value +@item +ASN1_BAD_FORMAT: ASN.1 badly-formatted encoding +@item +ASN1_PARSE_ERROR: ASN.1 parse error +@item +ASN1_BAD_GMTIME: ASN.1 bad return from gmtime +@item +ASN1_MISMATCH_INDEF: ASN.1 non-constructed indefinite encoding +@item +ASN1_MISSING_EOC: ASN.1 missing expected EOC +@end enumerate + +@node GSSAPI Error Codes, , ASN.1 Error Codes, Errors +@appendixsubsec GSSAPI Error Codes + +Generic GSSAPI Errors: + +@c error table numbering starts at 0 +@enumerate 0 +@item +G_BAD_SERVICE_NAME: No @ in SERVICE-NAME name string +@item +G_BAD_STRING_UID: STRING-UID-NAME contains nondigits +@item +G_NOUSER: UID does not resolve to username +@item +G_VALIDATE_FAILED: Validation error +@item +G_BUFFER_ALLOC: Couldn't allocate gss_buffer_t data +@item +G_BAD_MSG_CTX: Message context invalid +@item +G_WRONG_SIZE: Buffer is the wrong size +@item +G_BAD_USAGE: Credential usage type is unknown +@item +G_UNKNOWN_QOP: Unknown quality of protection specified +@item +G_BAD_HOSTNAME: Hostname in SERVICE-NAME string could not be +canonicalized +@item +G_WRONG_MECH: Mechanism is incorrect +@item +G_BAD_TOK_HEADER: Token header is malformed or corrupt +@item +G_BAD_DIRECTION: Packet was replayed in wrong direction +@item +G_TOK_TRUNC: Token is missing data +@item +G_REFLECT: Token was reflected +@item +G_WRONG_TOKID: Received token ID does not match expected token ID +@end enumerate + +Kerberos 5 GSSAPI Errors: + +@c error table numbering starts at 0 +@enumerate 0 +@item +KG_CCACHE_NOMATCH: Principal in credential cache does not match desired +name +@item +KG_KEYTAB_NOMATCH: No principal in keytab matches desired name +@item +KG_TGT_MISSING: Credential cache has no TGT +@item +KG_NO_SUBKEY: Authenticator has no subkey +@item +KG_CONTEXT_ESTABLISHED: Context is already fully established +@item +KG_BAD_SIGN_TYPE: Unknown signature type in token +@item +KG_BAD_LENGTH: Invalid field length in token +@item +KG_CTX_INCOMPLETE: Attempt to use incomplete security context +@item +KG_CONTEXT: Bad magic number for krb5_gss_ctx_id_t +@item +KG_CRED: Bad magic number for krb5_gss_cred_id_t +@item +KG_ENC_DESC: Bad magic number for krb5_gss_enc_desc +@item +KG_BAD_SEQ: Sequence number in token is corrupt +@item +KG_EMPTY_CCACHE: Credential cache is empty +@item +KG_NO_CTYPES: Acceptor and Initiator share no checksum types +@end enumerate + +@node kadmin Time Zones, , Errors, Appendix +@appendixsec kadmin Time Zones + +This is a complete listing of the time zones recognized by the +@code{kadmin} command. + +@table @b +@itemx gmt +Greenwich Mean Time +@itemx ut, utc +Universal Time (Coordinated). +@itemx wet +Western European Time. (Same as GMT.) +@itemx bst +British Summer Time. (1 hour ahead of GMT.) +@itemx wat +West Africa Time. (1 hour behind GMT.) +@itemx at +Azores Time. (2 hours behind GMT.) +@itemx bst +Brazil Standard Time. (3 hours behind GMT.) Note that the abbreviation +BST also stands for British Summer Time. +@itemx gst +Greenland Standard Time. (3 hours behind GMT.) Note that the +abbreviation GST also stands for Guam Standard Time. +@itemx nft +Newfoundland Time. (3.5 hours behind GMT.) +@itemx nst +Newfoundland Standard Time. (3.5 hours behind GMT.) +@itemx ndt +Newfoundland Daylight Time. (2.5 hours behind GMT.) +@itemx ast +Atlantic Standard Time. (4 hours behind GMT.) +@itemx adt +Atlantic Daylight Time. (3 hours behind GMT.) +@itemx est +Eastern Standard Time. (5 hours behind GMT.) +@itemx edt +Eastern Daylight Time. (4 hours behind GMT.) +@itemx cst +Central Standard Time. (6 hours behind GMT.) +@itemx cdt +Central Daylight Time. (5 hours behind GMT.) +@itemx mst +Mountain Standard Time. (7 hours behind GMT.) +@itemx mdt +Mountain Daylight Time. (6 hours behind GMT.) +@itemx pst +Pacific Standard Time. (8 hours behind GMT.) +@itemx pdt +Pacific Daylight Time. (7 hours behind GMT.) +@itemx yst +Yukon Standard Time. (9 hours behind GMT.) +@itemx ydt +Yukon Daylight Time. (8 hours behind GMT.) +@itemx hst +Hawaii Standard Time. (10 hours behind GMT.) +@itemx hdt +Hawaii Daylight Time. (9 hours behind GMT.) +@itemx cat +Central Alaska Time. (10 hours behind GMT.) +@itemx ahst +Alaska-Hawaii Standard Time. (10 hours behind GMT.) +@itemx nt +Nome Time. (11 hours behind GMT.) +@itemx idlw +International Date Line West Time. (12 hours behind GMT.) +@itemx cet +Central European Time. (1 hour ahead of GMT.) +@itemx met +Middle European Time. (1 hour ahead of GMT.) +@itemx mewt +Middle European Winter Time. (1 hour ahead of GMT.) +@itemx mest +Middle European Summer Time. (2 hours ahead of GMT.) +@itemx swt +Swedish Winter Time. (1 hour ahead of GMT.) +@itemx sst +Swedish Summer Time. (1 hours ahead of GMT.) +@itemx fwt +French Winter Time. (1 hour ahead of GMT.) +@itemx fst +French Summer Time. (2 hours ahead of GMT.) +@itemx eet +Eastern Europe Time; Russia Zone 1. (2 hours ahead of GMT.) +@itemx bt +Baghdad Time; Russia Zone 2. (3 hours ahead of GMT.) +@itemx it +Iran Time. (3.5 hours ahead of GMT.) +@itemx zp4 +Russia Zone 3. (4 hours ahead of GMT.) +@itemx zp5 +Russia Zone 4. (5 hours ahead of GMT.) +@itemx ist +Indian Standard Time. (5.5 hours ahead of GMT.) +@itemx zp6 +Russia Zone 5. (6 hours ahead of GMT.) +@itemx nst +North Sumatra Time. (6.5 hours ahead of GMT.) Note that the +abbreviation NST is also used for Newfoundland Stanard Time. +@itemx sst +South Sumatra Time; Russia Zone 6. (7 hours ahead of GMT.) Note that +SST is also Swedish Summer Time. +@itemx wast +West Australian Standard Time. (7 hours ahead of GMT.) +@itemx wadt +West Australian Daylight Time. (8 hours ahead of GMT.) +@itemx jt +Java Time. (7.5 hours ahead of GMT.) +@itemx cct +China Coast Time; Russia Zone 7. (8 hours ahead of GMT.) +@itemx jst +Japan Standard time; Russia Zone 8. (9 hours ahead of GMT.) +@itemx kst +Korean Standard Time. (9 hours ahead of GMT.) +@itemx cast +Central Australian Standard Time. (9.5 hours ahead of GMT.) +@itemx cadt +Central Australian Daylight Time. (10.5 hours ahead of GMT.) +@itemx east +Eastern Australian Standard Time. (10 hours ahead of GMT.) +@itemx eadt +Eastern Australian Daylight Time. (11 hours ahead of GMT.) +@itemx gst +Guam Standard Time; Russia Zone 9. (10 hours ahead of GMT.) +@itemx kdt +Korean Daylight Time. (10 hours ahead of GMT.) +@itemx nzt +New Zealand Time. (12 hours ahead of GMT.) +@itemx nzst +New Zealand Standard Time. (12 hours ahead of GMT.) +@itemx nzdt +New Zealand Daylight Time. (13 hours ahead of GMT.) +@itemx idle +International Date Line East. (12 hours ahead of GMT.) +@end table + +@contents +@bye + diff --git a/mechglue/doc/api/.Sanitize b/mechglue/doc/api/.Sanitize new file mode 100644 index 000000000..e778459b9 --- /dev/null +++ b/mechglue/doc/api/.Sanitize @@ -0,0 +1,48 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +ChangeLog +Makefile +ccache.tex +changebar.sty +errors.tex +fancyheadings.sty +fixunder.sty +free.tex +functions.sty +intro.tex +keytab.tex +krb5.tex +libdes.tex +libos.tex +library.tex +rcache.tex +tables.tex + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/mechglue/doc/api/.cvsignore b/mechglue/doc/api/.cvsignore new file mode 100644 index 000000000..8625a6f31 --- /dev/null +++ b/mechglue/doc/api/.cvsignore @@ -0,0 +1,10 @@ +library.ps +library.ind +library.log +library.idx +library.aux +library.toc +lib1.stamp +library.dvi +libdes.dvi +libdes.ps diff --git a/mechglue/doc/api/ChangeLog b/mechglue/doc/api/ChangeLog new file mode 100644 index 000000000..25a0d4185 --- /dev/null +++ b/mechglue/doc/api/ChangeLog @@ -0,0 +1,192 @@ +2005-08-29 Sam Hartman + + * library.tex: Don't use changebar.sty + +2003-05-09 Tom Yu + + * krb5.tex: Update subkey-related information to match code. + +2002-01-15 Sam Hartman + + * krb5.tex (subsubsection{Principal access functions}): krb5_princ_realm returns a pointer. + + +2001-11-06 Ken Raeburn + + * Makefile (clean): Delete *.ilg. + +2001-06-22 Ken Raeburn + + * ccache.tex (krb5_cc_default): Fix "equivalent to" example code. + Patch from Michael Gerdts . + +2001-06-19 Mitchell Berger + + * krb5.tex: Silly typo fixed. + +Wed Oct 18 09:55:25 2000 Ezra Peisach + + * library.tex: Update to latex2e. Include krb5idx.sty. + + * Makefile (lib1.stamp): Use makeindex to generate index instead + of an antiquated texindex program - which is not the same texindex + as in the texinfo package. + + * krb5idx.sty: Style for generating indexes. Provides definitions + for use with krb5.ist. + + * krb5.ist: makeindex macros. Based on gind.ist. + +2000-10-17 Ezra Peisach + + * krb5.tex: krb5_unparse_name_ext(), krb5_build_principal(), + krb5_build_principal_va, krb5_build_printicpal_ext() use unsigned + ints. + + * libos.tex: krb5_read_password() takes an unsigned int * as the + final argument. + + * keytab.tex: krb5_kt_get_name() takes an unsigned int. + +2000-10-16 Ezra Peisach + + * krb5.tex (krb5_init_context): Parameter is output only. + +2000-06-22 Ken Raeburn + + * Makefile (lib1.stamp): Use texindex instead of index. + +1999-08-30 Ken Raeburn + + * libdes.tex: Don't use ncs style; it's availability is dependent + on the local TeX installation. + +1999-01-20 Theodore Ts'o + + * krb5.tex (krb5_mk_safe): Fix reference to a non-existent flag. + (KRB5_AUTH_CONTEXT_DO_TIME_NOTIME should have been + KRB5_AUTH_CONTEXT_DO_TIME). [krb5-doc/528] + +Thu Jun 6 15:50:39 1996 Theodore Y. Ts'o + + * krb5.tex: Update function prototype for krb5_encrypt_tkt_part + +Mon Sep 4 21:13:36 1995 Ezra Peisach + + * libos.tex: Update krb5_lock_file and krb5_unlock_file no longer + take FILE *. + +Sun Jun 11 09:17:10 1995 Ezra Peisach + + * krb5.tex: Update krb5_auth_context usage. + +Sat May 13 17:40:32 1995 Ezra Peisach + + * ccache.tex: Add krb5_get_notification_message. + + * krb5.tex: Add krb5_get_cred_via_tkt. + +Sun May 7 13:56:43 1995 Ezra Peisach + + * krb5.tex (subsubsection{The krb5_auth_context}): Some function + names were misformed. + + * errors.tex (subsection{error_table kv5m}): Reformatting nits. + + * tables.tex: Formatting fixes. + +Thu May 4 14:29:45 1995 Ezra Peisach + + * krb5.tex: Reorganized into subsubsections. Added principal + access macros. + + * libos.tex: Added missing functions (os_context) and reorganized + into subsubsections. + +Wed May 3 01:22:11 1995 Ezra Peisach + + * krb5.tex: Added auth_context routines. + + * free.tex: Add krb5_xfree and krb5_free_data. + + * rcache.tex: Add krb5_rc_get_type, krb5_rc_resolve_type. + + * krb5.tex: API changes finished. + +Tue May 2 15:26:11 1995 Ezra Peisach (epeisach@kangaroo.mit.edu) + + * ccache.tex: krb5_cc_gen_new instead of krb5_cc_generate_new. + +Sun Apr 30 15:37:31 1995 Ezra Peisach + + * errors.tex: Formatting fixes + + * intro.tex: Formatting fixes + + * Makefile: Add free.tex to list. + + * rcache.tex: Update to current API specs. + + * ccache.tex: Update to current API specs. + + * keytab.tex: Update to current API specs. + + * free.tex: Finished first version. + +Tue Apr 18 10:42:03 1995 Ezra Peisach + + * intro.tex: spell checked + +Tue Apr 11 14:21:21 1995 Ezra Peisach (epeisach@kangaroo.mit.edu) + + * Makefile Cleaned up two pass processing through latex of library + document. + +Tue Apr 4 15:22:11 1995 Ezra Peisach + + * errors.tex Added missing entries in existing tables. Removed + isode table. Added asn.1 table and magic number table. + +Tue Feb 07 18:31:58 1995 Chris Provenzano (proven@mit.edu) + + * krb5.tex Documented API changes to krb5_get_in_tkt*() routines + and added krb5_get_in_tkt_with_keytab(). The explanation of + each of these routines still needs appropriate changes. + +Thu Feb 02 22:59:41 1995 Chris Provenzano (proven@mit.edu) + + * krb5.tex Documented change of krb5_enctype to krb5_enctypes + to krb5_send_tgs(). + + * krb5.tex Documented added krb5_keytype arg to (*keyproc)() arg + for krb5_rd_req(), krb5_rd_req_decoded(), and krb5_recvauth(). + +Fri Jan 27 22:15:23 1995 Chris Provenzano (proven@mit.edu) + + * keytab.tex Documented added krb5_keytab argunment to + krb5_kt_read_service_key() and krb5_kt_get_entry(). + +Mon Nov 21 14:17:50 1994 Theodore Y. Ts'o (tytso@dcl) + + * library.tex (internalfunc): Define \internalfunc, which prints a + disclaimer in front of "internal functions". We should + move them somewhere else, but for now, let's start marking + those functions which we believe are internal. + + * krb5.tex: Documented changed interfaces to krb5_encode_kdc_rep + and krb5_encrypt_tkt_part. Document krb5_encode_kdc_rep, + krb5_decode_kdc_rep, krb5_encrypt_tkt_part, + krb5_decrypt_tkt_part, and krb5_send_tgs as all internal + functions. + +Thu Oct 13 13:14:48 1994 Theodore Y. Ts'o (tytso@dcl) + + * krb5.tex: Fixed typo; extra space in \funcname{ krb5_recvauth}. + +Wed Oct 12 02:03:37 1994 Theodore Y. Ts'o (tytso@dcl) + + * Makefile: Added better dependencies to do two-pass latex runs + automatically. Make "make clean" clean up the tex temp + files. + + diff --git a/mechglue/doc/api/Makefile b/mechglue/doc/api/Makefile new file mode 100644 index 000000000..2d5d6b784 --- /dev/null +++ b/mechglue/doc/api/Makefile @@ -0,0 +1,40 @@ +.SUFFIXES: .tex .dvi .ps + +SHELL=/bin/sh + +STYLES= fixunder.sty functions.sty krb5idx.sty +LIBTEX= library.tex intro.tex tables.tex errors.tex krb5.tex ccache.tex \ + rcache.tex keytab.tex libos.tex free.tex + +DESTEX= libdes.tex + +all: library.ps libdes.ps + + +libdes.dvi: $(DESTEX) $(STYLES) + +library.ps: library.dvi + +clean: + rm -f *.toc *.log *.idx *.ind *.aux *.ilg lib1.stamp + +really-clean: clean + rm -f *.dvi *.ps + + +library.dvi: lib1.stamp $(LIBTEX) $(STYLES) + latex library + +lib1.stamp: $(LIBTEX) $(STYLES) + touch library.ind + latex library + makeindex -s krb5.ist library.idx + date > lib1.stamp + +.tex.dvi: + latex $* + + +.dvi.ps: + dvips $*.dvi -o + diff --git a/mechglue/doc/api/ccache.tex b/mechglue/doc/api/ccache.tex new file mode 100644 index 000000000..d6e24e834 --- /dev/null +++ b/mechglue/doc/api/ccache.tex @@ -0,0 +1,239 @@ +The credentials cache functions (some of which are macros which call to +specific types of credentials caches) deal with storing credentials +(tickets, session keys, and other identifying information) in a +semi-permanent store for later use by different programs. + +\begin{funcdecl}{krb5_cc_resolve}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{char *}{string_name} +\funcout +\funcarg{krb5_ccache *}{id} +\end{funcdecl} + +Fills in \funcparam{id} with a ccache identifier which corresponds to +the name in \funcparam{string_name}. + +Requires that \funcparam{string_name} be of the form ``type:residual'' and +``type'' is a type known to the library. + +\begin{funcdecl}{krb5_cc_gen_new}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_cc_ops *}{ops} +\funcout +\funcarg{krb5_ccache *}{id} +\end{funcdecl} + + +Fills in \funcparam{id} with a unique ccache identifier of a type defined by +\funcparam{ops}. The cache is left unopened. + +\begin{funcdecl}{krb5_cc_register}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_cc_ops *}{ops} +\funcarg{krb5_boolean}{override} +\end{funcdecl} + +Adds a new cache type identified and implemented by \funcparam{ops} to +the set recognized by \funcname{krb5_cc_resolve}. +If \funcparam{override} is FALSE, a ticket cache type named +\funcparam{ops{\ptsto}prefix} must not be known. + +\begin{funcdecl}{krb5_cc_get_name}{char *}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_ccache}{id} +\end{funcdecl} + +Returns the name of the ccache denoted by \funcparam{id}. + +\begin{funcdecl}{krb5_cc_default_name}{char *}{\funcinout} +\funcarg{krb5_context}{context} +\end{funcdecl} + +Returns the name of the default credentials cache; this may be equivalent to +\funcnamenoparens{getenv}({\tt "KRB5CCACHE"}) with an appropriate fallback. + +\begin{funcdecl}{krb5_cc_default}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_ccache *}{ccache} +\end{funcdecl} + +Equivalent to +\funcnamenoparens{krb5_cc_resolve}(\funcparam{context}, +\funcname{krb5_cc_default_name}, +\funcparam{ccache}). + +\begin{funcdecl}{krb5_cc_initialize}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ccache}{id} +\funcin +\funcarg{krb5_principal}{primary_principal} +\end{funcdecl} + +Creates/refreshes a credentials cache identified by \funcparam{id} with +primary principal set to \funcparam{primary_principal}. +If the credentials cache already exists, its contents are destroyed. + +Errors: permission errors, system errors. + +Modifies: cache identified by \funcparam{id}. + +\begin{funcdecl}{krb5_cc_destroy}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ccache}{id} +\end{funcdecl} + +Destroys the credentials cache identified by \funcparam{id}, invalidates +\funcparam{id}, and releases any other resources acquired during use of +the credentials cache. Requires that \funcparam{id} identifies a valid +credentials cache. After return, \funcparam{id} must not be used unless +it is first reinitialized using \funcname{krb5_cc_resolve} or +\funcname{krb5_cc_gen_new}. + +Errors: permission errors. + +\begin{funcdecl}{krb5_cc_close}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ccache}{id} +\end{funcdecl} + +Closes the credentials cache \funcparam{id}, invalidates +\funcparam{id}, and releases \funcparam{id} and any other resources +acquired during use of the credentials cache. Requires that +\funcparam{id} identifies a valid credentials cache. After return, +\funcparam{id} must not be used unless it is first reinitialized using +\funcname{krb5_cc_resolve} or \funcname{krb5_cc_gen_new}. + + +\begin{funcdecl}{krb5_cc_store_cred}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_ccache}{id} +\funcarg{krb5_creds *}{creds} +\end{funcdecl} + +Stores \funcparam{creds} in the cache \funcparam{id}, tagged with +\funcparam{creds{\ptsto}client}. +Requires that \funcparam{id} identifies a valid credentials cache. + +Errors: permission errors, storage failure errors. + +\begin{funcdecl}{krb5_cc_retrieve_cred}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_ccache}{id} +\funcarg{krb5_flags}{whichfields} +\funcarg{krb5_creds *}{mcreds} +\funcout +\funcarg{krb5_creds *}{creds} +\end{funcdecl} + +Searches the cache \funcparam{id} for credentials matching +\funcparam{mcreds}. The fields which are to be matched are specified by +set bits in \funcparam{whichfields}, and always include the principal +name \funcparam{mcreds{\ptsto}server}. +Requires that \funcparam{id} identifies a valid credentials cache. + +If at least one match is found, one of the matching credentials is +returned in \funcparam{*creds}. The credentials should be freed using +\funcname{krb5_free_credentials}. + +Errors: error code if no matches found. + +\begin{funcdecl}{krb5_cc_get_principal}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_ccache}{id} +\funcarg{krb5_principal *}{principal} +\end{funcdecl} + +Retrieves the primary principal of the credentials cache (as +set by the \funcname{krb5_cc_initialize} request) +The primary principal is filled into \funcparam{*principal}; the caller +should release this memory by calling \funcname{krb5_free_principal} on +\funcparam{*principal} when finished. + +Requires that \funcparam{id} identifies a valid credentials cache. + +\begin{funcdecl}{krb5_cc_start_seq_get}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ccache}{id} +\funcout +\funcarg{krb5_cc_cursor *}{cursor} +\end{funcdecl} + +Prepares to sequentially read every set of cached credentials. +\funcparam{cursor} is filled in with a cursor to be used in calls to +\funcname{krb5_cc_next_cred}. + +\begin{funcdecl}{krb5_cc_next_cred}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ccache}{id} +\funcout +\funcarg{krb5_creds *}{creds} +\funcinout +\funcarg{krb5_cc_cursor *}{cursor} +\end{funcdecl} + +Fetches the next entry from \funcparam{id}, returning its values in +\funcparam{*creds}, and updates \funcparam{*cursor} for the next request. +Requires that \funcparam{id} identifies a valid credentials cache and +\funcparam{*cursor} be a cursor returned by +\funcname{krb5_cc_start_seq_get} or a subsequent call to +\funcname{krb5_cc_next_cred}. + +Errors: error code if no more cache entries. + +\begin{funcdecl}{krb5_cc_end_seq_get}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ccache}{id} +\funcarg{krb5_cc_cursor *}{cursor} +\end{funcdecl} + +Finishes sequential processing mode and invalidates \funcparam{*cursor}. +\funcparam{*cursor} must never be re-used after this call. + +Requires that \funcparam{id} identifies a valid credentials cache and +\funcparam{*cursor} be a cursor returned by +\funcname{krb5_cc_start_seq_get} or a subsequent call to +\funcname{krb5_cc_next_cred}. + +Errors: may return error code if \funcparam{*cursor} is invalid. + + +\begin{funcdecl}{krb5_cc_remove_cred}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_ccache}{id} +\funcarg{krb5_flags}{which} +\funcarg{krb5_creds *}{cred} +\end{funcdecl} + +Removes any credentials from \funcparam{id} which match the principal +name {cred{\ptsto}server} and the fields in \funcparam{cred} masked by +\funcparam{which}. +Requires that \funcparam{id} identifies a valid credentials cache. + +Errors: returns error code if nothing matches; returns error code if +couldn't delete. + +\begin{funcdecl}{krb5_cc_set_flags}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ccache}{id} +\funcin +\funcarg{krb5_flags}{flags} +\end{funcdecl} + +Sets the flags on the cache \funcparam{id} to \funcparam{flags}. Useful +flags are defined in {\tt }. + +\begin{funcdecl}{krb5_get_notification_message}{unsigned int}{\funcvoid} +\end{funcdecl} + +Intended for use by Windows. Will register a unique message type using +\funcname{RegisterWindowMessage} which will be notified whenever the +cache changes. This will allow all processes to recheck their caches. diff --git a/mechglue/doc/api/errors.tex b/mechglue/doc/api/errors.tex new file mode 100644 index 000000000..ad90cac53 --- /dev/null +++ b/mechglue/doc/api/errors.tex @@ -0,0 +1,310 @@ +\subsection{error_table krb5} + +% $Source$ +% $Author$ + +The Kerberos v5 library error code table follows. +Protocol error codes are ERROR_TABLE_BASE_krb5 + the protocol error +code number. Other error codes start at ERROR_TABLE_BASE_krb5 + 128. + +\begin{small} +\begin{tabular}{ll} +{\sc krb5kdc_err_none }& No error \\ +{\sc krb5kdc_err_name_exp }& Client's entry in database has expired \\ +{\sc krb5kdc_err_service_exp }& Server's entry in database has expired \\ +{\sc krb5kdc_err_bad_pvno }& Requested protocol version not supported \\ +{\sc krb5kdc_err_c_old_mast_kvno }& \parbox[t]{2in}{Client's key is encrypted in an old master key} \\ +{\sc krb5kdc_err_s_old_mast_kvno }& \parbox[t]{2in}{Server's key is encrypted in an old master key} \\ +{\sc krb5kdc_err_c_principal_unknown }& Client not found in Kerberos database \\ +{\sc krb5kdc_err_s_principal_unknown }& Server not found in Kerberos database \\ +{\sc krb5kdc_err_principal_not_unique }&\parbox[t]{2in}{\raggedright{Principal has multiple entries in Kerberos database}} \\ +{\sc krb5kdc_err_null_key }& Client or server has a null key \\ +{\sc krb5kdc_err_cannot_postdate }& Ticket is ineligible for postdating \\ +{\sc krb5kdc_err_never_valid }& \parbox[t]{2in}{Requested effective lifetime is negative or too short} \\ +{\sc krb5kdc_err_policy }& KDC policy rejects request \\ +{\sc krb5kdc_err_badoption }& KDC can't fulfill requested option \\ +{\sc krb5kdc_err_etype_nosupp }& KDC has no support for encryption type \\ +{\sc krb5kdc_err_sumtype_nosupp }& KDC has no support for checksum type \\ +{\sc krb5kdc_err_padata_type_nosupp }& KDC has no support for padata type \\ +{\sc krb5kdc_err_trtype_nosupp }& KDC has no support for transited type \\ +{\sc krb5kdc_err_client_revoked }& Clients credentials have been revoked \\ +{\sc krb5kdc_err_service_revoked }& Credentials for server have been revoked \\ +{\sc krb5kdc_err_tgt_revoked }& TGT has been revoked \\ +{\sc krb5kdc_err_client_notyet }& Client not yet valid - try again later \\ +{\sc krb5kdc_err_service_notyet }& Server not yet valid - try again later \\ +{\sc krb5kdc_err_key_exp }& Password has expired \\ +{\sc krb5kdc_preauth_failed }& Preauthentication failed \\ +{\sc krb5kdc_err_preauth_require }& Additional pre-authentication required \\ +{\sc krb5kdc_err_server_nomatch }& Requested server and ticket don't match \\ +\multicolumn{2}{c}{error codes 27-30 are currently placeholders}\\ + +\end{tabular} + +\begin{tabular}{ll} +{\sc krb5krb_ap_err_bad_integrity }& Decrypt integrity check failed \\ +{\sc krb5krb_ap_err_tkt_expired }& Ticket expired \\ +{\sc krb5krb_ap_err_tkt_nyv }& Ticket not yet valid \\ +{\sc krb5krb_ap_err_repeat }& Request is a replay \\ +{\sc krb5krb_ap_err_not_us }& The ticket isn't for us \\ +{\sc krb5krb_ap_err_badmatch }& Ticket/authenticator don't match \\ +{\sc krb5krb_ap_err_skew }& Clock skew too great \\ +{\sc krb5krb_ap_err_badaddr }& Incorrect net address \\ +{\sc krb5krb_ap_err_badversion }& Protocol version mismatch \\ +{\sc krb5krb_ap_err_msg_type }& Invalid message type \\ +{\sc krb5krb_ap_err_modified }& Message stream modified \\ +{\sc krb5krb_ap_err_badorder }& Message out of order \\ +{\sc krb5placehold_43 }& KRB5 error code 43 \\ +{\sc krb5krb_ap_err_badkeyver }& Key version is not available \\ +{\sc krb5krb_ap_err_nokey }& Service key not available \\ +{\sc krb5krb_ap_err_mut_fail }& Mutual authentication failed \\ +{\sc krb5krb_ap_err_baddirection }& Incorrect message direction \\ +{\sc krb5krb_ap_err_method }& Alternative authentication method required \\ +{\sc krb5krb_ap_err_badseq }& Incorrect sequence number in message \\ +{\sc krb5krb_ap_err_inapp_cksum }& Inappropriate type of checksum in message \\ +\multicolumn{2}{c}{error codes 51-59 are currently placeholders} \\ + +{\sc krb5krb_err_generic }& Generic error (see e-text) \\ +{\sc krb5krb_err_field_toolong }& Field is too long for this implementation \\ +\multicolumn{2}{c}{error codes 62-127 are currently placeholders} \\ +\end{tabular} + +\begin{tabular}{ll} +{\sc krb5_libos_badlockflag }& Invalid flag for file lock mode \\ +{\sc krb5_libos_cantreadpwd }& Cannot read password \\ +{\sc krb5_libos_badpwdmatch }& Password mismatch \\ +{\sc krb5_libos_pwdintr }& Password read interrupted \\ +{\sc krb5_parse_illchar }& Illegal character in component name \\ +{\sc krb5_parse_malformed }& Malformed representation of principal \\ +{\sc krb5_config_cantopen }& Can't open/find configuration file \\ +{\sc krb5_config_badformat }& Improper format of configuration file \\ +{\sc krb5_config_notenufspace }& Insufficient space to return complete information \\ +{\sc krb5_badmsgtype }& Invalid message type specified for encoding \\ +{\sc krb5_cc_badname }& Credential cache name malformed \\ +{\sc krb5_cc_unknown_type }& Unknown credential cache type \\ +{\sc krb5_cc_notfound }& Matching credential not found \\ +{\sc krb5_cc_end }& End of credential cache reached \\ +{\sc krb5_no_tkt_supplied }& Request did not supply a ticket \\ +{\sc krb5krb_ap_wrong_princ }& Wrong principal in request \\ +{\sc krb5krb_ap_err_tkt_invalid }& Ticket has invalid flag set \\ +{\sc krb5_princ_nomatch }& Requested principal and ticket don't match \\ +{\sc krb5_kdcrep_modified }& KDC reply did not match expectations \\ +{\sc krb5_kdcrep_skew }& Clock skew too great in KDC reply \\ +{\sc krb5_in_tkt_realm_mismatch }&\parbox[t]{2.5 in}{Client/server realm +mismatch in initial ticket requst}\\ + +{\sc krb5_prog_etype_nosupp }& Program lacks support for encryption type \\ +{\sc krb5_prog_keytype_nosupp }& Program lacks support for key type \\ +{\sc krb5_wrong_etype }& Requested encryption type not used in message \\ +{\sc krb5_prog_sumtype_nosupp }& Program lacks support for checksum type \\ +{\sc krb5_realm_unknown }& Cannot find KDC for requested realm \\ +{\sc krb5_service_unknown }& Kerberos service unknown \\ +{\sc krb5_kdc_unreach }& Cannot contact any KDC for requested realm \\ +{\sc krb5_no_localname }& No local name found for principal name \\ + +%\multicolumn{1}{c}{some of these should be combined/supplanted by system codes} \\ +\end{tabular} + +\begin{tabular}{ll} +{\sc krb5_rc_type_exists }& Replay cache type is already registered \\ +{\sc krb5_rc_malloc }& No more memory to allocate (in replay cache code) \\ +{\sc krb5_rc_type_notfound }& Replay cache type is unknown \\ +{\sc krb5_rc_unknown }& Generic unknown RC error \\ +{\sc krb5_rc_replay }& Message is a replay \\ +{\sc krb5_rc_io }& Replay I/O operation failed XXX \\ +{\sc krb5_rc_noio }& \parbox[t]{3in}{Replay cache type does not support non-volatile storage} \\ +{\sc krb5_rc_parse }& Replay cache name parse/format error \\ +{\sc krb5_rc_io_eof }& End-of-file on replay cache I/O \\ +{\sc krb5_rc_io_malloc }& \parbox[t]{3in}{No more memory to allocate (in replay cache I/O code)}\\ +{\sc krb5_rc_io_perm }& Permission denied in replay cache code \\ +{\sc krb5_rc_io_io }& I/O error in replay cache i/o code \\ +{\sc krb5_rc_io_unknown }& Generic unknown RC/IO error \\ +{\sc krb5_rc_io_space }& Insufficient system space to store replay information \\ +{\sc krb5_trans_cantopen }& Can't open/find realm translation file \\ +{\sc krb5_trans_badformat }& Improper format of realm translation file \\ +{\sc krb5_lname_cantopen }& Can't open/find lname translation database \\ +{\sc krb5_lname_notrans }& No translation available for requested principal \\ +{\sc krb5_lname_badformat }& Improper format of translation database entry \\ +{\sc krb5_crypto_internal }& Cryptosystem internal error \\ +{\sc krb5_kt_badname }& Key table name malformed \\ +{\sc krb5_kt_unknown_type }& Unknown Key table type \\ +{\sc krb5_kt_notfound }& Key table entry not found \\ +{\sc krb5_kt_end }& End of key table reached \\ +{\sc krb5_kt_nowrite }& Cannot write to specified key table \\ +{\sc krb5_kt_ioerr }& Error writing to key table \\ +{\sc krb5_no_tkt_in_rlm }& Cannot find ticket for requested realm \\ +{\sc krb5des_bad_keypar }& DES key has bad parity \\ +{\sc krb5des_weak_key }& DES key is a weak key \\ +{\sc krb5_bad_keytype }& Keytype is incompatible with encryption type \\ +{\sc krb5_bad_keysize }& Key size is incompatible with encryption type \\ +{\sc krb5_bad_msize }& Message size is incompatible with encryption type \\ +{\sc krb5_cc_type_exists }& Credentials cache type is already registered. \\ +{\sc krb5_kt_type_exists }& Key table type is already registered. \\ +{\sc krb5_cc_io }& Credentials cache I/O operation failed XXX \\ +{\sc krb5_fcc_perm }& Credentials cache file permissions incorrect \\ +{\sc krb5_fcc_nofile }& No credentials cache file found \\ +{\sc krb5_fcc_internal }& Internal file credentials cache error \\ +{\sc krb5_cc_nomem }& \parbox[t]{3in}{No more memory to allocate (in credentials cache code)}\\ +\end{tabular} + +\begin{tabular}{ll} +\multicolumn{2}{c}{errors for dual TGT library calls} \\ + +{\sc krb5_invalid_flags }& Invalid KDC option combination (library internal error) \\ +{\sc krb5_no_2nd_tkt }& Request missing second ticket \\ +{\sc krb5_nocreds_supplied }& No credentials supplied to library routine \\ + +\end{tabular} + +\begin{tabular}{ll} +\multicolumn{2}{c}{errors for sendauth and recvauth} \\ + +{\sc krb5_sendauth_badauthvers }& Bad sendauth version was sent \\ +{\sc krb5_sendauth_badapplvers }& Bad application version was sent (via sendauth) \\ +{\sc krb5_sendauth_badresponse }& Bad response (during sendauth exchange) \\ +{\sc krb5_sendauth_rejected }& Server rejected authentication\\ +& \ (during sendauth exchange) \\ +{\sc krb5_sendauth_mutual_failed }& Mutual authentication failed\\&\ (during sendauth exchange) \\ + +\end{tabular} + +\begin{tabular}{ll} +\multicolumn{2}{c}{errors for preauthentication} \\ + +{\sc krb5_preauth_bad_type }& Unsupported preauthentication type \\ +{\sc krb5_preauth_no_key }& Required preauthentication key not supplied \\ +{\sc krb5_preauth_failed }& Generic preauthentication failure \\ + +\end{tabular} + +\begin{tabular}{ll} +\multicolumn{2}{c}{version number errors} \\ + +{\sc krb5_rcache_badvno }& Unsupported replay cache format version number \\ +{\sc krb5_ccache_badvno }& Unsupported credentials cache format version number \\ +{\sc krb5_keytab_badvno }& Unsupported key table format version number \\ + +\end{tabular} + +\begin{tabular}{ll} +\multicolumn{2}{c}{other errors} \\ + +{\sc krb5_prog_atype_nosupp }& Program lacks support for address type \\ +{\sc krb5_rc_required }& Message replay detection requires\\&\ rcache parameter \\ +{\sc krb5_err_bad_hostname }& Hostname cannot be canonicalized \\ +{\sc krb5_err_host_realm_unknown }& Cannot determine realm for host \\ +{\sc krb5_sname_unsupp_nametype }& Conversion to service principal undefined\\&\ for name type \\ +{\sc krb5krb_ap_err_v4_reply }& Initial Ticket Response appears to be\\ +&\ Version 4 error \\ +{\sc krb5_realm_cant_resolve }& Cannot resolve KDC for requested realm \\ +{\sc krb5_tkt_not_forwardable }& Requesting ticket can't get forwardable tickets \\ +\end{tabular} +\end{small} + +\subsection{error_table kdb5} + +% $Source$ +% $Author$ + +The Kerberos v5 database library error code table + +\begin{small} +\begin{tabular}{ll} +\multicolumn{2}{c}{From the server side routines} \\ +{\sc krb5_kdb_inuse }& Entry already exists in database\\ +{\sc krb5_kdb_uk_serror }& Database store error\\ +{\sc krb5_kdb_uk_rerror }& Database read error\\ +{\sc krb5_kdb_unauth }& Insufficient access to perform requested operation\\ +{\sc krb5_kdb_noentry }& No such entry in the database\\ +{\sc krb5_kdb_ill_wildcard }& Illegal use of wildcard\\ +{\sc krb5_kdb_db_inuse }& Database is locked or in use--try again later\\ +{\sc krb5_kdb_db_changed }& Database was modified during read\\ +{\sc krb5_kdb_truncated_record }& Database record is incomplete or corrupted\\ +{\sc krb5_kdb_recursivelock }& Attempt to lock database twice\\ +{\sc krb5_kdb_notlocked }& Attempt to unlock database when not locked\\ +{\sc krb5_kdb_badlockmode }& Invalid kdb lock mode\\ +{\sc krb5_kdb_dbnotinited }& Database has not been initialized\\ +{\sc krb5_kdb_dbinited }& Database has already been initialized\\ +{\sc krb5_kdb_illdirection }& Bad direction for converting keys\\ +{\sc krb5_kdb_nomasterkey }& Cannot find master key record in database\\ +{\sc krb5_kdb_badmasterkey }& Master key does not match database\\ +{\sc krb5_kdb_invalidkeysize }& Key size in database is invalid\\ +{\sc krb5_kdb_cantread_stored }& Cannot find/read stored master key\\ +{\sc krb5_kdb_badstored_mkey }& Stored master key is corrupted\\ +{\sc krb5_kdb_cantlock_db }& Insufficient access to lock database \\ +{\sc krb5_kdb_db_corrupt }& Database format error\\ +{\sc krb5_kdb_bad_version }& Unsupported version in database entry \\ +\end{tabular} +\end{small} + +% $Source$ +% $Author$ + +\subsection{error_table kv5m} + +The Kerberos v5 magic numbers errorcode table follows. These are used +for the magic numbers found in data structures. + +\begin{small} +\begin{tabular}{ll} +{\sc kv5m_none }& Kerberos V5 magic number table \\ +{\sc kv5m_principal }& Bad magic number for krb5_principal structure \\ +{\sc kv5m_data }& Bad magic number for krb5_data structure \\ +{\sc kv5m_keyblock }& Bad magic number for krb5_keyblock structure \\ +{\sc kv5m_checksum }& Bad magic number for krb5_checksum structure \\ +{\sc kv5m_encrypt_block }& Bad magic number for krb5_encrypt_block structure \\ +{\sc kv5m_enc_data }& Bad magic number for krb5_enc_data structure \\ +{\sc kv5m_cryptosystem_entry }& Bad magic number for krb5_cryptosystem_entry\\&\ structure \\ +{\sc kv5m_cs_table_entry }& Bad magic number for krb5_cs_table_entry structure \\ +{\sc kv5m_checksum_entry }& Bad magic number for krb5_checksum_entry structure \\ + +{\sc kv5m_authdata }& Bad magic number for krb5_authdata structure \\ +{\sc kv5m_transited }& Bad magic number for krb5_transited structure \\ +{\sc kv5m_enc_tkt_parT }& Bad magic number for krb5_enc_tkt_part structure \\ +{\sc kv5m_ticket }& Bad magic number for krb5_ticket structure \\ +{\sc kv5m_authenticator }& Bad magic number for krb5_authenticator structure \\ +{\sc kv5m_tkt_authent }& Bad magic number for krb5_tkt_authent structure \\ +{\sc kv5m_creds }& Bad magic number for krb5_creds structure \\ +{\sc kv5m_last_req_entry }& Bad magic number for krb5_last_req_entry structure \\ +{\sc kv5m_pa_data }& Bad magic number for krb5_pa_data structure \\ +{\sc kv5m_kdc_req }& Bad magic number for krb5_kdc_req structure \\ +{\sc kv5m_enc_kdc_rep_part }& Bad magic number for krb5_enc_kdc_rep_part structure \\ +{\sc kv5m_kdc_rep }& Bad magic number for krb5_kdc_rep structure \\ +{\sc kv5m_error }& Bad magic number for krb5_error structure \\ +{\sc kv5m_ap_req }& Bad magic number for krb5_ap_req structure \\ +{\sc kv5m_ap_rep }& Bad magic number for krb5_ap_rep structure \\ +{\sc kv5m_ap_rep_enc_part }& Bad magic number for krb5_ap_rep_enc_part structure \\ +{\sc kv5m_response }& Bad magic number for krb5_response structure \\ +{\sc kv5m_safe }& Bad magic number for krb5_safe structure \\ +{\sc kv5m_priv }& Bad magic number for krb5_priv structure \\ +{\sc kv5m_priv_enc_part }& Bad magic number for krb5_priv_enc_part structure \\ +{\sc kv5m_cred }& Bad magic number for krb5_cred structure \\ +{\sc kv5m_cred_info }& Bad magic number for krb5_cred_info structure \\ +{\sc kv5m_cred_enc_part }& Bad magic number for krb5_cred_enc_part structure \\ +{\sc kv5m_pwd_data }& Bad magic number for krb5_pwd_data structure \\ +{\sc kv5m_address }& Bad magic number for krb5_address structure \\ +{\sc kv5m_keytab_entry }& Bad magic number for krb5_keytab_entry structure \\ +{\sc kv5m_context }& Bad magic number for krb5_context structure \\ +{\sc kv5m_os_context }& Bad magic number for krb5_os_context structure \\ + +\end{tabular} +\end{small} + +\subsection{error_table asn1} + +The Kerberos v5/ASN.1 error table mappings + +\begin{small} +\begin{tabular}{ll} +{\sc asn1_bad_timeformat }& ASN.1 failed call to system time library \\ +{\sc asn1_missing_field }& ASN.1 structure is missing a required field \\ +{\sc asn1_misplaced_field }& ASN.1 unexpected field number \\ +{\sc asn1_type_mismatch }& ASN.1 type numbers are inconsistent \\ +{\sc asn1_overflow }& ASN.1 value too large \\ +{\sc asn1_overrun }& ASN.1 encoding ended unexpectedly \\ +{\sc asn1_bad_id }& ASN.1 identifier doesn't match expected value \\ +{\sc asn1_bad_length }& ASN.1 length doesn't match expected value \\ +{\sc asn1_bad_format }& ASN.1 badly-formatted encoding \\ +{\sc asn1_parse_error }& ASN.1 parse error \\ +\end{tabular} +\end{small} + diff --git a/mechglue/doc/api/fancyheadings.sty b/mechglue/doc/api/fancyheadings.sty new file mode 100644 index 000000000..a71de0fb5 --- /dev/null +++ b/mechglue/doc/api/fancyheadings.sty @@ -0,0 +1,233 @@ +% fancyheadings.sty version 1.0 +% Fancy headers and footers. +% Piet van Oostrum, Dept of Computer Science, University of Utrecht +% Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands +% Telephone: +31-30-531806. piet@cs.ruu.nl (mcvax!hp4nl!ruuinf!piet) +% March, 1989. + +% Here is a documentstylestyle option that allows you to customize your +% page headers and footers in an easy way. It combines features that were +% separately available in other pagestyles, without introducing much +% complexity. You can define: +% - three-part headers and footers +% - rules in header and footer +% - headers and footers wider than \textwidth +% - multiline headers and footers +% - separate headers and footers for even and odd pages +% - separate headers and footers for chapter pages +% +% To use this pagestyle, you must include the ``fancyheadings'' style +% option in your \documentstyle, and issue the \pagestyle{fancy} command. +% The \pagestyle{fancy} command should be issued after any changes made to +% \textwidth. +% +% The page layout will be as follows: +% +% LHEAD CHEAD RHEAD +% ----------------------------------- (rule) +% +% page body +% +% +% ----------------------------------- (rule) +% LFOOT CFOOT RFOOT +% +% The L-fields will be leftadjusted, the C-fields centered and the +% R-fields rightadjusted. +% Each of the six fields and the two rules can be defined separately. +% +% Simple use: +% +% The header and footer fields can be defined by commands \lhead{LHEAD} +% and so on for the other fields. If the field depends on something in the +% document (e.g. section titles) you must in general use the \markboth and +% \markright commands, otherwise a title may end on the wrong page. You +% can do this e.g. by redefining the commands \chaptermark, \sectionmark +% and so on (see example below). The defaults for these marks are as in +% the standard pagestyles. The marks can be put into a header or footer +% field by referencing \leftmark and \rightmark. +% +% Rules in header and footer +% +% The thickness of the rules below the header and above the footer can be +% changed by redefining the length parameters \headrulewidth (default +% 0.4pt) and \footrulewidth (default 0). These may be redefined by the +% \setlength command. A thickness of 0pt makes the rule invisible. +% If you want to make more complicated changes, you have to redefine the +% commands \headrule and/or \footrule. +% +% Headers and footers wider than \textwidth +% +% The headers and footers are set in a box of width \headwidth. The +% default for this is the value of \textwidth. You can make it wider (or +% smaller) by redefining \headwidth with the \setlength or \addtolength +% command. The headers and footers will stick out the page on the same +% side as the marginal notes. For example to include the marginal notes, +% add both \marginparsep and \marginparwidth to \headwidth (see also the +% example below). +% +% Multiline headers and footers +% +% Each of the six fields is set in an appropriate parbox, so you can put a +% multiline part in it with the \\ command. It is also possible to put +% extra space in it with the \vspace command. Note that if you do this you +% will probably have to increase the \headheight or \footskip lengths. +% +% Separate headers and footers for even and odd pages +% +% If you want the headers and footers to be different on even- and +% odd-numbered pages in the ``twoside'' style, the field-defining macros +% can be given an optional argument, to be used on the even-numbered +% pages, like \lhead[EVEN-LHEAD]{ODD-RHEAD}. +% +% Separate headers and footers for chapter pages +% +% LaTeX gives a \thispagestyle{plain} command for the first page of the +% document, the first page of each chapter and a couple of other pages. It +% might be incompatible with your pagestyle. In this case you can use a +% slightly different version of the pagestyle, called \pagestyle{fancyplain}. +% This pagestyle redefines the pagestyle ``plain'' to also use pagestyle +% ``fancy'' with the following modifications: +% - the thicknesses of the rules is defined by \plainheadrulewidth and +% \plainfootrulewidth (both default 0). +% - the 6 fields may be defined separately for the plain pages by +% giving them the value \fancyplain{PLAIN-VALUE}{NORMAL-VALUE}. This +% construct may be used in both the optional argument and the normal +% argument. Thus \lhead[\fancyplain{F1}{F2}]{\fancyplain{F3}{F4}} +% specifies the LHEAD value in a two-sided document: +% F1 on an even-numbered ``plain'' page +% F2 on an even-numbered normal page +% F3 on an odd-numbered ``plain'' page +% F4 on an odd-numbered normal page. +% +% Defaults: +% +% \headrulewidth 0.4pt +% \footrulewidth 0pt +% \plainheadrulewidth 0pt +% \plainfootrulewidth 0pt +% +% \lhead[\fancyplain{}{\sl\rightmark}]{\fancyplain{}{\sl\leftmark}} +% % i.e. empty on ``plain'' pages \rightmark on even, \leftmark on odd pages +% \chead{} +% \rhead[\fancyplain{}{\sl\leftmark}]{\fancyplain{}{\sl\rightmark}} +% % i.e. empty on ``plain'' pages \leftmark on even, \rightmark on odd pages +% \lfoot{} +% \cfoot{\rm\thepage} % page number +% \rfoot{} +% +% Examples: +% +% To put two lines containing the section title and the subsection title +% in the righthandside corner, use: +% +% \documentstyle[fancyheadings]{article} +% \pagestyle{fancy} +% \renewcommand{\sectionmark}[1]{\markboth{#1}{}} +% \renewcommand{\subsectionmark}[1]{\markright{#1}} +% \rfoot{\leftmark\\\rightmark} +% +% The following definitions give an approximation of the style used in the +% LaTeX book: +% +% \documentstyle[fancyheadings]{book} +% \pagestyle{fancyplain} +% \addtolength{\headwidth}{\marginparsep} +% \addtolength{\headwidth}{\marginparwidth} +% \renewcommand{\chaptermark}[1]{\markboth{#1}{#1}} % remember chapter title +% \renewcommand{\sectionmark}[1]{\markright{\thesection\ #1}} +% % section number and title +% \lhead[\fancyplain{}{\bf\thepage}]{\fancyplain{}{\bf\rightmark}} +% \rhead[\fancyplain{}{\bf\leftmark}]{\fancyplain{}{\bf\thepage}} +% \cfoot{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\def\lhead{\@ifnextchar[{\@xlhead}{\@ylhead}} +\def\@xlhead[#1]#2{\gdef\@elhead{#1}\gdef\@olhead{#2}} +\def\@ylhead#1{\gdef\@elhead{#1}\gdef\@olhead{#1}} + +\def\chead{\@ifnextchar[{\@xchead}{\@ychead}} +\def\@xchead[#1]#2{\gdef\@echead{#1}\gdef\@ochead{#2}} +\def\@ychead#1{\gdef\@echead{#1}\gdef\@ochead{#1}} + +\def\rhead{\@ifnextchar[{\@xrhead}{\@yrhead}} +\def\@xrhead[#1]#2{\gdef\@erhead{#1}\gdef\@orhead{#2}} +\def\@yrhead#1{\gdef\@erhead{#1}\gdef\@orhead{#1}} + +\def\lfoot{\@ifnextchar[{\@xlfoot}{\@ylfoot}} +\def\@xlfoot[#1]#2{\gdef\@elfoot{#1}\gdef\@olfoot{#2}} +\def\@ylfoot#1{\gdef\@elfoot{#1}\gdef\@olfoot{#1}} + +\def\cfoot{\@ifnextchar[{\@xcfoot}{\@ycfoot}} +\def\@xcfoot[#1]#2{\gdef\@ecfoot{#1}\gdef\@ocfoot{#2}} +\def\@ycfoot#1{\gdef\@ecfoot{#1}\gdef\@ocfoot{#1}} + +\def\rfoot{\@ifnextchar[{\@xrfoot}{\@yrfoot}} +\def\@xrfoot[#1]#2{\gdef\@erfoot{#1}\gdef\@orfoot{#2}} +\def\@yrfoot#1{\gdef\@erfoot{#1}\gdef\@orfoot{#1}} + +\newdimen\headrulewidth +\newdimen\footrulewidth +\newdimen\plainheadrulewidth +\newdimen\plainfootrulewidth +\newdimen\headwidth +\newif\if@fancyplain \@fancyplainfalse +\def\fancyplain#1#2{\if@fancyplain#1\else#2\fi} + +% Initialization of the head and foot text. + +\headrulewidth 0.4pt +\footrulewidth\z@ +\plainheadrulewidth\z@ +\plainfootrulewidth\z@ + +\lhead[\fancyplain{}{\sl\rightmark}]{\fancyplain{}{\sl\leftmark}} +% i.e. empty on ``plain'' pages \rightmark on even, \leftmark on odd pages +\chead{} +\rhead[\fancyplain{}{\sl\leftmark}]{\fancyplain{}{\sl\rightmark}} +% i.e. empty on ``plain'' pages \leftmark on even, \rightmark on odd pages +\lfoot{} +\cfoot{\rm\thepage} % page number +\rfoot{} + +% Put together a header or footer given the left, center and +% right text, fillers at left and right and a rule. +% The \lap commands put the text into an hbox of zero size, +% so overlapping text does not generate an errormessage. + +\def\@fancyhead#1#2#3#4#5{#1\hbox to\headwidth{\vbox{\hbox +{\rlap{\parbox[b]{\headwidth}{\raggedright#2\strut}}\hfill +\parbox[b]{\headwidth}{\centering#3\strut}\hfill +\llap{\parbox[b]{\headwidth}{\raggedleft#4\strut}}}\headrule}}#5} + + +\def\@fancyfoot#1#2#3#4#5{#1\hbox to\headwidth{\vbox{\footrule +\hbox{\rlap{\parbox[t]{\headwidth}{\raggedright#2\strut}}\hfill +\parbox[t]{\headwidth}{\centering#3\strut}\hfill +\llap{\parbox[t]{\headwidth}{\raggedleft#4\strut}}}}}#5} + +\def\headrule{{\if@fancyplain\headrulewidth\plainheadrulewidth\fi +\hrule\@height\headrulewidth\@width\headwidth \vskip-\headrulewidth}} + +\def\footrule{{\if@fancyplain\footrulewidth\plainfootrulewidth\fi +\vskip-0.3\normalbaselineskip\vskip-\footrulewidth +\hrule\@width\headwidth\@height\footrulewidth\vskip0.3\normalbaselineskip}} + +\def\ps@fancy{ +\let\@mkboth\markboth +\@ifundefined{chapter}{\def\sectionmark##1{\markboth +{\uppercase{\ifnum \c@secnumdepth>\z@ + \thesection\hskip 1em\relax \fi ##1}}{}} +\def\subsectionmark##1{\markright {\ifnum \c@secnumdepth >\@ne + \thesubsection\hskip 1em\relax \fi ##1}}} +{\def\chaptermark##1{\markboth {\uppercase{\ifnum \c@secnumdepth>\m@ne + \@chapapp\ \thechapter. \ \fi ##1}}{}} +\def\sectionmark##1{\markright{\uppercase{\ifnum \c@secnumdepth >\z@ + \thesection. \ \fi ##1}}}} +\def\@oddhead{\@fancyhead\relax\@olhead\@ochead\@orhead\hss} +\def\@oddfoot{\@fancyfoot\relax\@olfoot\@ocfoot\@orfoot\hss} +\def\@evenhead{\@fancyhead\hss\@elhead\@echead\@erhead\relax} +\def\@evenfoot{\@fancyfoot\hss\@elfoot\@ecfoot\@erfoot\relax} +\headwidth\textwidth} +\def\ps@fancyplain{\ps@fancy \let\ps@plain\ps@plain@fancy} +\def\ps@plain@fancy{\@fancyplaintrue\ps@fancy} diff --git a/mechglue/doc/api/fixunder.sty b/mechglue/doc/api/fixunder.sty new file mode 100644 index 000000000..b7ae58dbf --- /dev/null +++ b/mechglue/doc/api/fixunder.sty @@ -0,0 +1,48 @@ +% fixunder.sty, 31 May 1990, John T. Kohl +% +% The contents of this file are in the public domain. +% +% +% play games with _ to make it active and to provide a reasonable _ +% character (from \tt in most cases), and a discretionary word-break point. + +% +% Some \makeunder... macros for convenience in setting catcodes. +% +\def\makeunderactive{\catcode`\_=\active\relax} +\def\makeunderother{\catcode`\_=12\relax} +\def\makeunderletter{\catcode`\_=11\relax} +\def\makeundernormal{\catcode`\_=8\relax} +\makeunderother +\def\cctwlunder{_} + +% +% The hair here is to allow things like \index to work reasonably with +% the new definition of underscore when the argument to index is part of +% a macro replacement and as such gets tokenized before \index is +% evaluated. +% [in the normal case at top-level, \index{foo_bar} works since \index +% does some hair to make _ into a reasonable character code, and \index +% does NOT use a macro expansion. If you have something like +% \def\foo#1#2{\index{#1} bar #2} +% then \foo{baz_quux}{frobnitz} will result in baz_quux getting +% tokenized BEFORE \foo is expanded, so that the catcode hair in \index +% is to no avail.] +% +% \underrealfalse declares that you want to replace with the \tt _; +% \underrealtrue declares that you want to replace with \char95 (ASCII _). +% +% for things like \index which write things out to files, set +% \underrealfalse before evaluating the \index macro, and what actually +% gets written to the file is an _, rather than something like +% {\leavemode \kern... } (the typical definition of \_). +% +% the above example would then be +% \def\foo#1#2{\underrealfalse\index{#1}\underrealtrue bar #2} +% + +\newif\ifunderreal +\underrealfalse +\makeunderactive +\def_{\ifunderreal\cctwlunder\else\leavevmode {\tt \cctwlunder}\discretionary{}{}{}\fi} +\let\_=_ diff --git a/mechglue/doc/api/free.tex b/mechglue/doc/api/free.tex new file mode 100644 index 000000000..02733b702 --- /dev/null +++ b/mechglue/doc/api/free.tex @@ -0,0 +1,266 @@ +The free functions deal with deallocation of memory that has been +allocated by various routines. It is recommended that the developer use +these routines as they will know about the contents of the structures. + +\begin{funcdecl}{krb5_xfree}{void}{\funcinout} +\funcarg{void *}{ptr} +\end{funcdecl} + +Frees the pointer \funcarg{ptr}. This is a wrapper macro to +\funcname{free} that is designed to keep lint ``happy.'' + +\begin{funcdecl}{krb5_free_data}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_data *}{val} +\end{funcdecl} + +Frees the data structure \funcparam{val}, including the pointer +\funcparam{val} which has been allocate by any of numerous routines. + + +\begin{funcdecl}{krb5_free_princial}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_principal}{val} +\end{funcdecl} + +Frees the pwd_data \funcparam{val} that has been allocated from +\funcname{krb5_copy_principal}. + +\begin{funcdecl}{krb5_free_authenticator}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_authenticator *}{val} +\end{funcdecl} + +Frees the authenticator \funcparam{val}, including the pointer +\funcparam{val}. + +\begin{funcdecl}{krb5_free_authenticator_contents}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_authenticator *}{val} +\end{funcdecl} + +Frees the authenticator contents of \funcparam{val}. The pointer +\funcparam{val} is not freed. + + +\begin{funcdecl}{krb5_free_addresses}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_address **}{val} +\end{funcdecl} + +Frees the series of addresses \funcparam{*val} that have been allocated from +\funcname{krb5_copy_addresses}. + +\begin{funcdecl}{krb5_free_address}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_address *}{val} +\end{funcdecl} + +Frees the address \funcparam{val}. + +\begin{funcdecl}{krb5_free_authdata}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_authdata **}{val} +\end{funcdecl} + +Frees the authdata structure pointed to by \funcparam{val} that has been +allocated from +\funcname{krb5_copy_authdata}. + +\begin{funcdecl}{krb5_free_enc_tkt_part}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_enc_tkt_part *}{val} +\end{funcdecl} + +Frees \funcparam{val} that has been allocated from +\funcname{krb5_enc_tkt_part} and \funcname{krb5_decrypt_tkt_part}. + +\begin{funcdecl}{krb5_free_ticket}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ticket *}{val} +\end{funcdecl} + +Frees the ticket \funcparam{val} that has been allocated from +\funcname{krb5_copy_ticket} and other routines. + +\begin{funcdecl}{krb5_free_tickets}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ticket **}{val} +\end{funcdecl} + +Frees the tickets pointed to by \funcparam{val}. + +\begin{funcdecl}{krb5_free_kdc_req}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_kdc_req *}{val} +\end{funcdecl} + +Frees the kdc_req \funcparam{val} and all substructures. The pointer +\funcparam{val} is freed as well. + +\begin{funcdecl}{krb5_free_kdc_rep}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_kdc_rep *}{val} +\end{funcdecl} + +Frees the kdc_rep \funcparam{val} that has been allocated from +\funcname{krb5_get_in_tkt}. + +\begin{funcdecl}{krb5_free_kdc_rep_part}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_enc_kdc_rep_part *}{val} +\end{funcdecl} + +Frees the kdc_rep_part \funcparam{val}. + +\begin{funcdecl}{krb5_free_error}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_error *}{val} +\end{funcdecl} + +Frees the error \funcparam{val} that has been allocated from +\funcname{krb5_read_error} or \funcname{krb5_sendauth}. + +\begin{funcdecl}{krb5_free_ap_req}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ap_req *}{val} +\end{funcdecl} + +Frees the ap_req \funcparam{val}. + +\begin{funcdecl}{krb5_free_ap_rep}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ap_rep *}{val} +\end{funcdecl} + +Frees the ap_rep \funcparam{val}. + +\begin{funcdecl}{krb5_free_safe}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_safe *}{val} +\end{funcdecl} + +Frees the safe application data \funcparam{val} that is allocated with +\funcparam{decode_krb5_safe}. + + +\begin{funcdecl}{krb5_free_priv}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_priv *}{val} +\end{funcdecl} + +Frees the private data \funcparam{val} that has been allocated from +\funcname{decode_krb5_priv}. + +\begin{funcdecl}{krb5_free_priv_enc_part}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_priv_enc_part *}{val} +\end{funcdecl} + +Frees the private encoded part \funcparam{val} that has been allocated from +\funcname{decode_krb5_enc_priv_part}. + +\begin{funcdecl}{krb5_free_cred}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_cred *}{val} +\end{funcdecl} + +Frees the credential \funcparam{val}. + +\begin{funcdecl}{krb5_free_creds}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_creds *}{val} +\end{funcdecl} + +Calls \funcname{krb5_free_cred_contents} with \funcparam{val} as the +argument. \funcparam{val} is freed as well. + +\begin{funcdecl}{krb5_free_cred_contents}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_creds *}{val} +\end{funcdecl} + +The function zeros out the session key stored in the credential and then +frees the credentials structures. The argument \funcparam{val} is +{\bf not} freed. + + +\begin{funcdecl}{krb5_free_cred_enc_part}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_cred_enc_part *}{val} +\end{funcdecl} + +Frees the addresses and ticket_info elements of +\funcparam{val}. \funcparam{val} is {\bf not} freed by this routine. + +\begin{funcdecl}{krb5_free_checksum}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_checksum *}{val} +\end{funcdecl} + +The checksum and the pointer \funcparam{val} are both freed. + +\begin{funcdecl}{krb5_free_keyblock}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_keyblock *}{val} +\end{funcdecl} + +The keyblock contents of \funcparam{val} are zeroed and the memory +freed. The pointer \funcparam{val} is freed as well. + +\begin{funcdecl}{krb5_free_pa_data}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_pa_data **}{val} +\end{funcdecl} + +Frees the contents of \funcparam{*val}. \funcparam{val} is freed as +well. + +\begin{funcdecl}{krb5_free_ap_rep_enc_part}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_ap_rep_enc_part *}{val} +\end{funcdecl} + +Frees the subkey keyblock (if set) as well as \funcparam{val} that has +been allocated from \funcname{krb5_rd_rep} or \funcname{krb5_send_auth}. + +\begin{funcdecl}{krb5_free_tkt_authent}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_tkt_authent *}{val} +\end{funcdecl} + +Frees the ticket and authenticator portions of \funcparam{val}. The +pointer \funcparam{val} is freed as well. + +\begin{funcdecl}{krb5_free_pwd_data}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{passwd_pwd_data *}{val} +\end{funcdecl} + +Frees the pwd_data \funcparam{val} that has been allocated from +\funcname{decode_krb5_pwd_data}. + +\begin{funcdecl}{krb5_free_pwd_sequences}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{passwd_phrase_element **}{val} +\end{funcdecl} + +Frees the passwd_phrase_element \funcparam{val}. This is usually called +from \funcname{krb5_free_pwd_data}. + +\begin{funcdecl}{krb5_free_realm_tree}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_principal *}{realms} +\end{funcdecl} + +Frees the realms tree \funcparam{realms} returned by +\funcname{krb5_walk_realm_tree}. + +\begin{funcdecl}{krb5_free_tgt_creds}{void}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_creds **}{tgts} +\end{funcdecl} + +Frees the TGT credentials \funcparam{tgts} returned by +\funcname{krb5_get_cred_from_kdc}. + diff --git a/mechglue/doc/api/functions.sty b/mechglue/doc/api/functions.sty new file mode 100644 index 000000000..a3165f811 --- /dev/null +++ b/mechglue/doc/api/functions.sty @@ -0,0 +1,70 @@ +% +% definitions related to function declarations/displays +% +\ifx\undefined\@psfonts +\def\argfont{\tt} +\else +\font\argfont = pcrb +\hyphenchar\argfont = -1 +\fi +\let\funcfont=\bf +\newcount\argc@ount +%\setlength{\marginparsep}{0.05in} +%\setlength{\marginparwidth}{1.45in} +% +% This function fixes up the function name to be displayed in the +% margin so that the krb5_, if any, is stripped. +% +% Note: this is a hack; what's really happening is that name beginning with +% krb5 will have its first five characters stripped from it. +% This means that 'Krb5abc' will get rewritten to be 'bc'. +% Unfortunately, we can't do better because of the underscore +% hacks that are going on elsewhere. +% +% WARNING: This is ugly; don't look at it too soon after lunch! +% [tytso:19900920.2231EDT] +\newif\if@krbfunc +\def\endkrb{} +\def\fix@parname#1{\expandafter\parse@krb#1\endkrb% +\endkrb\endkrb\endkrb\endkrb}% In case the argument is less +% than five letters, we don't want to +% lose on the argument parsing. +\def\parse@krb#1#2#3#4#5#6\endkrb{\@krbfuncfalse% +\if#1k\if#2r\if#3b\if#45\@krbfunctrue\fi\fi\fi\fi% +\if@krbfunc#6\else#1#2#3#4#5#6\fi} +% +% funcdecl is used as \begin{funcdecl}{funcname}{return type}{firstline} +% +% see fixunder.sty for comments on why the \underrealtrue & \underrealfalse +% stuff is here. +\newenvironment{funcdecl}[3]{\underrealtrue\index{#1}\underrealfalse% +\medbreak +\gdef\funcn@me{#1} +\argc@ount=0\noindent% +%the \mbox{} is to prevent the line/paragraph breaking from eating the +%fill space. +\marginpar[{{\sloppy \hfil\fix@parname{\funcn@me}\hfill\mbox{}}}]% +{{\sloppy \hfill\fix@parname{\funcn@me}\hfil\mbox{}}}% +\vbox\bgroup\begin{minipage}[t]{\textwidth}\begin{tabbing} +#2 \\ +{\bf #1}(\= \+ #3% +}{) +\end{tabbing}\vfil\end{minipage}\egroup\par\nopagebreak +} +\newcommand{\docomm@}{\ifnum\argc@ount >0, \\\fi} +\newcommand{\funcvoid}{\argc@ount=0} +\newcommand{\funcin}{\docomm@\argc@ount=0{\sl /* IN */}\\} +\newcommand{\funcinout}{\docomm@\argc@ount=0{\sl /* IN/OUT */}\\} +\newcommand{\funcout}{\docomm@\argc@ount=0{\sl /* OUT */}\\} +\newcommand{\funcarg}[2]{\docomm@#1 {\argfont #2}\advance\argc@ount by1} +\newcommand{\funcparam}[1]{{\argfont #1}} +\newcommand{\funcfuncarg}[2]{\docomm@#1 {\argfont #2}(\= \+ \argc@ount=0} +\newcommand{\funcendfuncarg}{), \- \\ \argc@ount=0} +\newcommand{\libname}[1]{{\argfont #1}} +\newcommand{\globalname}[1]{{\argfont #1}} +\newcommand{\ptsto}{->\discretionary{}{}{}} +\newcommand{\datatype}[1]{{\bf #1}} +\newcommand{\filename}[1]{{\sl #1\/}} + +\newcommand{\funcname}[1]{\underrealtrue\index{#1}\underrealfalse{\funcfont #1}()} +\newcommand{\funcnamenoparens}[1]{\underrealtrue\index{#1}\underrealfalse{\funcfont #1}} diff --git a/mechglue/doc/api/intro.tex b/mechglue/doc/api/intro.tex new file mode 100644 index 000000000..370775b02 --- /dev/null +++ b/mechglue/doc/api/intro.tex @@ -0,0 +1,299 @@ + This document describes the routines that make up the Kerberos +V5 application programming interface. It is geared towards +programmers who already have a basic familiarity with Kerberos and are +in the process of including Kerberos authentication as part of +applications being developed. + + The function descriptions included are up to date, even if the +description of the functions may be hard to understand for the novice +Kerberos programmer. + +\subsection{Acknowledgments} + + +The Kerberos model is based in part on Needham and Schroeder's trusted +third-party authentication protocol and on modifications suggested by +Denning and Sacco. The original design and implementation of Kerberos +Versions 1 through 4 was the work of Steve Miller of Digital Equipment +Corporation and Clifford Neuman (now at the Information Sciences +Institute of the University of Southern California), along with Jerome +Saltzer, Technical Director of Project Athena, and Jeffrey Schiller, +MIT Campus Network Manager. Many other members of Project Athena have +also contributed to the work on Kerberos. Version 4 is publicly +available, and has seen wide use across the Internet. + +Version 5 (described in this document) has evolved from Version 4 based +on new requirements and desires for features not available in Version 4. + +%nlg- a bunch more probably needs to be added here to credit all +%those that have contributed to V5 -nlg + +\subsection{Kerberos Basics} + +Kerberos performs authentication as a trusted third-party +authentication service by using conventional (shared secret +key\footnote{ {\em Secret} and {\em private} are often used +interchangeably in the literature. In our usage, it takes two (or +more) to share a secret, thus a shared DES key is a {\em secret} key. +Something is only private when no one but its owner knows it. Thus, +in public key cryptosystems, one has a public and a {\em private} key. +}) cryptography. Kerberos provides a means of verifying the +identities of principals, without relying on authentication by the +host operating system, without basing trust on host addresses, without +requiring physical security of all the hosts on the network, and under +the assumption that packets traveling along the network can be read, +modified, and inserted at will. + +When integrating Kerberos into an application it is important to +review how and when Kerberos functions are used to ensure that the +application's design does not compromise the authentication. For +instance, an application which uses Kerberos' functions only upon the +{\em initiation} of a stream-based network connection, and assumes the +absence of any active attackers who might be able to ``hijack'' the +stream connection. + +%{\Huge nlg- It would be nice to include more examples here of common +%mistakes one can make in designing kerberized systems -nlg} + +The Kerberos protocol code libraries, whose API is described in this +document, can be used to provide encryption to any application. In +order to add authentication to its transactions, a typical network +application adds one or two calls to the Kerberos library, which +results in the transmission of the necessary messages to achieve +authentication. + +The two methods for obtaining credentials, the initial ticket exchange +and the ticket granting ticket exchange, use slightly different +protocols and require different API routines. The basic difference an +API programmer will see is that the initial request does not require a +ticket granting ticket (TGT) but does require the client's secret key +because the reply is sent back encrypted in the client's secret key. +Usually this request is for a TGT and TGT based exchanges are used +from then on. In a TGT exchange the TGT is sent as part of the +request for tickets and the reply is encrypted in the session key from +the TGT. For example, once a user's password is used to obtain a TGT, +it is not required for subsequent TGT exchanges. + +The reply consists of a ticket and a session key, encrypted either in +the user's secret key (i.e., password), or the TGT session key. The +combination of a ticket and a session key is known as a set of {\em +credentials}.\footnote{In Kerberos V4, the ``ticket file'' was a bit of +a misnomer, since it contained both tickets and their associated session +keys. In Kerberos V5, the ``ticket file'' has been renamed to be the +{\em credentials cache}.} An application client can use these +credentials to authenticate to the application server by sending the +ticket and an {\em authenticator} to the server. The authenticator is +encrypted in the session key of the ticket, and contains the name of the +client, the name of the server, the time the authenticator was created. + +In order to verify the authentication, the application server decrypts +the ticket using its service key, which is only known by the application +server and the Kerberos server. Inside the ticket, the Kerberos server +had placed the name of the client, the name of the server, a DES key +associated with this ticket, and some additional information. The +application server then uses the ticket session key to decrypt the +authenticator, and verifies that the information in the authenticator +matches the information in the ticket, and that the timestamp in the +authenticator is recent (to prevent reply attacks). Since the session +key was generated randomly by the Kerberos server, and delivered only +encrypted in the service key, and in a key known only by the user, the +application server can be confident that user is really who he or she +claims to be, by virtue of the fact that the user was able to encrypt +the authenticator in the correct key. + +To provide detection of both replay +attacks and message stream modification attacks, the integrity of all +the messages exchanged between principals can also be +guar\-an\-teed\footnote{Using +\funcname{krb5_mk_safe} and \funcname{krb5_rd_safe} to create and +verify KRB5_SAFE messages} by generating and transmitting a +collision-proof checksum\footnote{aka cryptographic checksum, +elsewhere this is called a hash or digest function} of the client's +message, keyed with the session key. Privacy and integrity of the +messages exchanged between principals can be secured\footnote{Using +\funcname{krb5_mk_priv} and \funcname{krb5_rd_priv} to create and +verify KRB5_PRIV messages} by encrypting the data to be passed using +the session key. + +\subsubsection{The purpose of Realms} + +The Kerberos protocol is designed to operate across organizational +boundaries. Each organization wishing to run a Kerberos +server establishes its own {\em realm}. The name of the realm in which a +client is registered is part of the client's name, and can be used by the +end-service to decide whether to honor a request. + +By establishing {\em inter-realm} keys, the administrators of two +realms can allow a client authenticated in the local realm to use its +credentials remotely. The exchange of inter-realm keys (a separate +key may be used for each direction) registers the ticket-granting +service of each realm as a principal in the other realm. A client is +then able to obtain a ticket-granting ticket for the remote realm's +ticket-granting service from its local realm. When that +ticket-granting ticket is used, the remote ticket-granting service +uses the inter-realm key (which usually differs from its own normal +TGS key) to decrypt the ticket-granting ticket, and is thus certain +that it was issued by the client's own TGS. Tickets issued by the +remote ticket-granting service will indicate to the end-service that +the client was authenticated from another realm. + + +This method can be repeated to authenticate throughout an organization +across multiple realms. To build a valid authentication +path\footnote{An {\em authentication path} is the sequence of +intermediate realms that are transited in communicating from one realm +to another.} to a distant realm, the local realm must share an +inter-realm key with an intermediate realm which +communicates\footnote{A realm is said to {\em communicate} with +another realm if the two realms share an inter-realm key} with either +the distant remote realm or yet another intermediate realm. + +Realms are typically organized hierarchically. Each realm shares a +key with its parent and a different key with each child. If an +inter-realm key is not directly shared by two realms, the hierarchical +organization allows an authentication path to be easily constructed. +If a hierarchical organization is not used, it may be necessary to +consult some database in order to construct an authentication path +between realms. + +Although realms are typically hierarchical, intermediate realms may be +bypassed to achieve cross-realm authentication through alternate +authentication paths\footnote{These might be established to make communication +between two realms more efficient}. It is important for the +end-service to know which realms were transited when deciding how much +faith to place in the authentication process. To facilitate this +decision, a field in each ticket contains the names of the realms that +were involved in authenticating the client. + +\subsubsection{Fundamental assumptions about the environment} + +Kerberos has certain limitations that should be kept in mind when +designing security measures: + +\begin{itemize} +\item +Kerberos does not address ``Denial of service'' attacks. There are +places in these protocols where an intruder can prevent an application +from participating in the proper authentication steps. Detection and +solution of such attacks (some of which can appear to be not-uncommon +``normal'' failure modes for the system) is usually best left to +the human administrators and users. + +\item +Principals must keep their secret keys secret. If an intruder somehow +steals a principal's key, it will be able to masquerade as that +principal or impersonate any server to the legitimate principal. + +\item +``Password guessing'' attacks are not solved by Kerberos. If a user +chooses a poor password, it is possible for an attacker to +successfully mount an offline dictionary attack by repeatedly +attempting to decrypt, with successive entries from a dictionary, +messages obtained which are encrypted under a key derived from the +user's password. + +\end{itemize} + +\subsection{Glossary of terms} + +Below is a list of terms used throughout this document. + +\begin{description} +\item [Authentication] +Verifying the claimed identity of a principal. + +\item [Authentication header] +A record containing a Ticket and an Authenticator to be presented to a +server as part of the authentication process. + +\item [Authentication path] +A sequence of intermediate realms transited in the authentication +process when communicating from one realm to another. + +\item [Authenticator] +A record containing information that can be shown to +have been recently generated using the session key known only by the +client and server. + +\item [Authorization] +The process of determining whether a client may use a +service, which objects the client is allowed to access, and the +type of access allowed for each. + +\item [Ciphertext] +The output of an encryption function. Encryption transforms plaintext +into ciphertext. + +\item [Client] +A process that makes use of a network service on behalf of a +user. Note that in some cases a {\em Server} may itself be a client of +some other server (e.g. a print server may be a client of a file server). + +\item [Credentials] +A ticket plus the secret session key necessary to +successfully use that ticket in an authentication exchange. + +\item [KDC] +Key Distribution Center, a network service that supplies +tickets and temporary session keys; or an +instance of that service or the host on which it runs. +The KDC services both initial ticket and ticket-granting ticket +requests. +The initial ticket portion is sometimes referred to as the +Authentication Server (or service). +The ticket-granting ticket portion is sometimes referred to as the +ticket-granting server (or service). + +\item [Kerberos] +Aside from the 3-headed dog guarding Hades, the name given +to Project Athena's authentication service, the protocol used by that +service, or the code used to implement the authentication service. + +\item [Plaintext] +The input to an encryption function or the output of a decryption +function. Decryption transforms ciphertext into plaintext. + +\item [Principal] +A uniquely named client or server instance that participates in +a network communication. + +\item [Principal identifier] +The name used to uniquely identify each different +principal. + +\item [Seal] +To encipher a record containing several fields in such a way +that the fields cannot be individually replaced without either +knowledge of the encryption key or leaving evidence of tampering. + +\item [Secret key] +An encryption key shared by a principal and the KDC, +distributed outside the bounds of the system, with a long lifetime. +In the case of a human user's principal, the secret key is derived from a +password. + +\item [Server] +A particular Principal which provides a resource to network clients. + +\item [Service] +A resource provided to network clients; often provided by more than one +server (for example, remote file service). + +\item [Session key] +A temporary encryption key used between two principals, +with a lifetime limited to the duration of a single login +{\em session}. + +\item [Sub-session key] +A temporary encryption key used between two +principals, selected and exchanged by the principals using the session +key, and with a lifetime limited to the duration of a single +association. + +\item [Ticket] +A record that helps a client authenticate itself to a server; it contains +the client's identity, a session key, a timestamp, and other +information, all sealed using the server's secret key. It only serves to +authenticate a client when presented along with a fresh Authenticator. + +\end{description} diff --git a/mechglue/doc/api/keytab.tex b/mechglue/doc/api/keytab.tex new file mode 100644 index 000000000..63e27e538 --- /dev/null +++ b/mechglue/doc/api/keytab.tex @@ -0,0 +1,221 @@ +The key table functions deal with storing and retrieving service keys +for use by unattended services which participate in authentication exchanges. + +Keytab routines are all be atomic. Every routine that acquires +a non-sharable resource releases it before it returns. + +All keytab types support multiple concurrent sequential scans. + +The order of values returned from \funcname{krb5_kt_next_entry} is +unspecified. + +Although the ``right thing'' should happen if the program aborts +abnormally, a close routine, \funcname{krb5_kt_free_entry}, is provided +for freeing resources, etc. People should use the close routine when +they are finished. + +\begin{funcdecl}{krb5_kt_register}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_kt_ops *}{ops} +\end{funcdecl} + + +Adds a new ticket cache type to the set recognized by +\funcname{krb5_kt_resolve}. +Requires that a keytab type named \funcparam{ops{\ptsto}prefix} is not +yet known. + +An error is returned if \funcparam{ops{\ptsto}prefix} is already known. + +\begin{funcdecl}{krb5_kt_resolve}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const char *}{string_name} +\funcout +\funcarg{krb5_keytab *}{id} +\end{funcdecl} + +Fills in \funcparam{*id} with a handle identifying the keytab with name +``string_name''. The keytab is not opened. +Requires that \funcparam{string_name} be of the form ``type:residual'' and +``type'' is a type known to the library. + +Errors: badly formatted name. + +\begin{funcdecl}{krb5_kt_default_name}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{char *}{name} +\funcarg{int}{namesize} +\end{funcdecl} + +\funcparam{name} is filled in with the first \funcparam{namesize} bytes of +the name of the default keytab. +If the name is shorter than \funcparam{namesize}, then the remainder of +\funcparam{name} will be zeroed. + + +\begin{funcdecl}{krb5_kt_default}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_keytab *}{id} +\end{funcdecl} + +Fills in \funcparam{id} with a handle identifying the default keytab. + +\begin{funcdecl}{krb5_kt_read_service_key}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_pointer}{keyprocarg} +\funcarg{krb5_principal}{principal} +\funcarg{krb5_kvno}{vno} +\funcarg{krb5_keytype}{keytype} +\funcout +\funcarg{krb5_keyblock **}{key} +\end{funcdecl} + +If \funcname{keyprocarg} is not NULL, it is taken to be a +\datatype{char *} denoting the name of a keytab. Otherwise, the default +keytab will be used. +The keytab is opened and searched for the entry identified by +\funcparam{principal}, \funcparam{keytype}, and \funcparam{vno}, +returning the resulting key +in \funcparam{*key} or returning an error code if it is not found. + +\funcname{krb5_free_keyblock} should be called on \funcparam{*key} when +the caller is finished with the key. + +Returns an error code if the entry is not found. + +\begin{funcdecl}{krb5_kt_add_entry}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_keytab}{id} +\funcarg{krb5_keytab_entry *}{entry} +\end{funcdecl} + +Calls the keytab-specific add routine \funcname{krb5_kt_add_internal} +with the same function arguments. If this routine is not available, +then KRB5_KT_NOWRITE is returned. + +\begin{funcdecl}{krb5_kt_remove_entry}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_keytab}{id} +\funcarg{krb5_keytab_entry *}{entry} +\end{funcdecl} + +Calls the keytab-specific remove routine +\funcname{krb5_kt_remove_internal} with the same function arguments. +If this routine is not available, then KRB5_KT_NOWRITE is returned. + +\begin{funcdecl}{krb5_kt_get_name}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_keytab}{id} +\funcout +\funcarg{char *}{name} +\funcin +\funcarg{unsigned int}{namesize} +\end{funcdecl} + +\funcarg{name} is filled in with the first \funcparam{namesize} bytes of +the name of the keytab identified by \funcname{id}. +If the name is shorter than \funcparam{namesize}, then \funcarg{name} +will be null-terminated. + +\begin{funcdecl}{krb5_kt_close}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_keytab}{id} +\end{funcdecl} + +Closes the keytab identified by \funcparam{id} and invalidates +\funcparam{id}, and releases any other resources acquired during use of +the key table. + +Requires that \funcparam{id} identifies a keytab. + +\begin{funcdecl}{krb5_kt_get_entry}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_keytab}{id} +\funcin +\funcarg{krb5_principal}{principal} +\funcarg{krb5_kvno}{vno} +\funcarg{krb5_keytype}{keytype} +\funcout +\funcarg{krb5_keytab_entry *}{entry} +\end{funcdecl} + +\begin{sloppypar} +Searches the keytab identified by \funcparam{id} for an entry whose +principal matches \funcparam{principal}, whose keytype matches +\funcparam{keytype}, and +whose key version number matches \funcparam{vno}. If \funcparam{vno} is +zero, the first entry whose principal matches is returned. +\end{sloppypar} + +Returns an error code if no suitable entry is found. If an entry is +found, the entry is returned in \funcparam{*entry}; its contents should +be deallocated by calling \funcname{krb5_kt_free_entry} when no longer +needed. + +\begin{funcdecl}{krb5_kt_free_entry}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_keytab_entry *}{entry} +\end{funcdecl} + +Releases all storage allocated for \funcparam{entry}, which must point +to a structure previously filled in by \funcname{krb5_kt_get_entry} or +\funcname{krb5_kt_next_entry}. + +\begin{funcdecl}{krb5_kt_start_seq_get}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_keytab}{id} +\funcout +\funcarg{krb5_kt_cursor *}{cursor} +\end{funcdecl} + +Prepares to read sequentially every key in the keytab identified by +\funcparam{id}. +\funcparam{cursor} is filled in with a cursor to be used in calls to +\funcname{krb5_kt_next_entry}. + +\begin{funcdecl}{krb5_kt_next_entry}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_keytab}{id} +\funcout +\funcarg{krb5_keytab_entry *}{entry} +\funcinout +\funcarg{krb5_kt_cursor *}{cursor} +\end{funcdecl} + +Fetches the ``next'' entry in the keytab, returning it in +\funcparam{*entry}, and updates \funcparam{*cursor} for the next +request. If the keytab changes during the sequential get, an error is +guaranteed. \funcparam{*entry} should be freed after use by calling +\funcname{krb5_kt_free_entry}. + +Requires that \funcparam{id} identifies a valid keytab. and +\funcparam{*cursor} be a cursor returned by +\funcname{krb5_kt_start_seq_get} or a subsequent call to +\funcname{krb5_kt_next_entry}. + +Errors: error code if no more cache entries or if the keytab changes. + +\begin{funcdecl}{krb5_kt_end_seq_get}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_keytab}{id} +\funcarg{krb5_kt_cursor *}{cursor} +\end{funcdecl} + +Finishes sequential processing mode and invalidates \funcparam{cursor}, +which must never be re-used after this call. + +Requires that \funcparam{id} identifies a valid keytab and +\funcparam{*cursor} be a cursor returned by +\funcname{krb5_kt_start_seq_get} or a subsequent call to +\funcname{krb5_kt_next_entry}. + +May return error code if \funcparam{cursor} is invalid. + + diff --git a/mechglue/doc/api/krb5.ist b/mechglue/doc/api/krb5.ist new file mode 100644 index 000000000..36e9adb2b --- /dev/null +++ b/mechglue/doc/api/krb5.ist @@ -0,0 +1,26 @@ +%% +%% This is based on the gind.ist +%% +actual '=' +quote '!' +level '>' +preamble +"\n \\begin{theindex} \n" +postamble +"\n\n \\end{theindex}\n" +item_x1 "\\efill \n \\subitem " +item_x2 "\\efill \n \\subsubitem " +delim_0 "\\pfill " +delim_1 "\\pfill " +delim_2 "\\pfill " +% The next lines will produce some warnings when +% running Makeindex as they try to cover two different +% versions of the program: +lethead_prefix "{\\bfseries\\hfil " +lethead_suffix "\\hfil}\\nopagebreak\n" +lethead_flag 1 +heading_prefix "{\\bfseries\\hfil " +heading_suffix "\\hfil}\\nopagebreak\n" +headings_flag 1 +%% +%% diff --git a/mechglue/doc/api/krb5.tex b/mechglue/doc/api/krb5.tex new file mode 100644 index 000000000..d70910ec0 --- /dev/null +++ b/mechglue/doc/api/krb5.tex @@ -0,0 +1,1827 @@ +The main functions deal with the nitty-gritty details: verifying +tickets, creating authenticators, and the like. + +\subsubsection{The krb5_context} +The \datatype{krb5_context} is designed to represent the per process +state. When the library is made thread-safe, the context will represent +the per-thread state. Global parameters which are ``context'' specific +are stored in this structure, including default realm, default +encryption type, default configuration files and the like. Functions +exist to provide full access to the data structures stored in the +context and should not be accessed directly by developers. + +\begin{funcdecl}{krb5_init_context}{krb5_error_code}{\funcout} +\funcarg{krb5_context *}{context} +\end{funcdecl} + +Initializes the context \funcparam{*context} for the +application. Currently the context contains the encryption types, a +pointer to operating specific data and the default realm. In the future, +the context may be also contain thread specific data. The data in the +context should be freed with \funcname{krb5_free_context}. + +Returns system errors. + +\begin{funcdecl}{krb5_free_context}{void}{\funcinout} +\funcarg{krb5_context}{context} +\end{funcdecl} + +Frees the context returned by \funcname{krb5_init_context}. Internally +calls \funcname{krb5_os_free_context}. + +\begin{funcdecl}{krb5_set_default_in_tkt_etypes}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_enctype *}{etypes} +\end{funcdecl} + +Sets the desired default encryption type \funcparam{etypes} for the context +if valid. + +Returns {\sc enomem}, {\sc krb5_prog_etype_nosupp}. + +\begin{funcdecl}{krb5_get_default_in_tkt_etypes}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_enctype **}{etypes} +\end{funcdecl} + +Retrieves the default encryption types from the context and stores them +in \funcarg{etypes} which should be freed by the caller. + +Returns {\sc enomem}. + +\subsubsection{The krb5_auth_context} + +While the \datatype{krb5_context} represents a per-process or per-thread +context, the \datatype{krb5_auth_context} represents a per-connection +context are are used by the various functions involved directly in +client/server authentication. Some of the data stored in this context +include keyblocks, addresses, sequence numbers, authenticators, checksum +type, and replay cache pointer. + +\begin{funcdecl}{krb5_auth_con_init}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_auth_context *}{auth_context} +\end{funcdecl} + +The auth_context may be described as a per connection context. This +context contains all data pertinent to the the various authentication +routines. This function initializes the auth_context. + +The default flags for the context are set to enable the use of the replay cache +(KRB5_AUTH_CONTEXT_DO_TIME) but no sequence numbers. The function +\funcname{krb5_auth_con_setflags} allows the flags to be changed. + +The default checksum type is set to CKSUMTYPE_RSA_MD4_DES. This may be +changed with \funcname{krb5_auth_con_setcksumtype}. + +The auth_context structure should be freed with +\funcname{krb5_auth_con_free}. + +\begin{funcdecl}{krb5_auth_con_free}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\end{funcdecl} + +Frees the auth_context \funcparam{auth_context} returned by +\funcname{krb5_auth_con_init}. + +% perhaps some comment about which substructures are freed and which are not? + +\begin{funcdecl}{krb5_auth_con_setflags}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{krb5_int32}{flags} +\end{funcdecl} + +Sets the flags of \funcparam{auth_context} to funcparam{flags}. Valid +flags are: + +\begin{tabular}{ll} +\multicolumn{1}{c}{Symbol} & Meaning \\ +KRB5_AUTH_CONTEXT_DO_TIME & Use timestamps \\ +KRB5_AUTH_CONTEXT_RET_TIME & Save timestamps\\ &\ to output structure\\ +KRB5_AUTH_CONTEXT_DO_SEQUENCE & Use sequence numbers \\ +KRB5_AUTH_CONTEXT_RET_SEQUENCE & Copy sequence numbers \\ &\ to output structure\\ +\end{tabular} + + +\begin{funcdecl}{krb5_auth_con_getflags}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_int32 *}{flags} +\end{funcdecl} + +Retrievs the flags of \funcparam{auth_context}. + +\begin{funcdecl}{krb5_auth_con_setaddrs}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{krb5_address *}{local_addr} +\funcarg{krb5_address *}{remote_addr} +\end{funcdecl} + +Copies the \funcparam{local_addr} and \funcparam{remote_addr} into the +\funcparam{auth_context}. If either address is NULL, the previous +address remains in place. + +\begin{funcdecl}{krb5_auth_con_getaddrs}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_address **}{local_addr} +\funcarg{krb5_address **}{remote_addr} +\end{funcdecl} + +Retrieves \funcparam{local_addr} and \funcparam{remote_addr} from the +\funcparam{auth_context}. If \funcparam{local_addr} or +\funcparam{remote_addr} is not NULL, the memory is first freed with +\funcname{krb5_free_address} and then newly allocated. It is the callers +responsibility to free the returned addresses in this way. + + +\begin{funcdecl}{krb5_auth_con_setports}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{krb5_address *}{local_port} +\funcarg{krb5_address *}{remote_port} +\end{funcdecl} + +Copies the \funcparam{local_port} and \funcparam{remote_port} addresses +into the \funcparam{auth_context}. If either address is NULL, the previous +address remains in place. These addresses are set by +\funcname{krb5_auth_con_genaddrs}. + +\begin{funcdecl}{krb5_auth_con_setuserkey}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{krb5_keyblock *}{keyblock} +\end{funcdecl} + +This function overloads the keyblock field. It is only useful prior to a +\funcname{krb5_rd_req_decode} call for user to user authentication where +the server has the key and needs to use it to decrypt the incoming +request. Once decrypted this key is no longer necessary and is then +overwritten with the session key sent by the client. + +\begin{funcdecl}{krb5_auth_con_getkey}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_keyblock **}{keyblock} +\end{funcdecl} + +Retrieves the keyblock stored in \funcparam{auth_context}. The memory +allocated in this function should be freed with a call to +\funcname{krb5_free_keyblock}. + +\begin{funcdecl}{krb5_auth_con_getrecvsubkey}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_keyblock **}{keyblock} +\end{funcdecl} + +Retrieves the recv\_subkey keyblock stored in +\funcparam{auth_context}. The memory allocated in this function should +be freed with a call to \funcname{krb5_free_keyblock}. + +\begin{funcdecl}{krb5_auth_con_getsendsubkey}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_keyblock **}{keyblock} +\end{funcdecl} + +Retrieves the send\_subkey keyblock stored in +\funcparam{auth_context}. The memory allocated in this function should +be freed with a call to \funcname{krb5_free_keyblock}. + +\begin{funcdecl}{krb5_auth_con_setrecvsubkey}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_keyblock *}{keyblock} +\end{funcdecl} + +Sets the recv\_subkey keyblock stored in \funcparam{auth_context}. + +\begin{funcdecl}{krb5_auth_con_setsendsubkey}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_keyblock *}{keyblock} +\end{funcdecl} + +Sets the send\_subkey keyblock stored in \funcparam{auth_context}. + +\begin{funcdecl}{krb5_auth_setcksumtype}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{krb5_cksumtype}{cksumtype} +\end{funcdecl} + +Sets the checksum type used by the other functions in the library. + +\begin{funcdecl}{krb5_auth_getlocalseqnumber}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{krb5_int32 *}{seqnumber} +\end{funcdecl} + +Retrieves the local sequence number that was used during authentication +and stores it in \funcparam{seqnumber}. + +\begin{funcdecl}{krb5_auth_getremoteseqnumber}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{krb5_int32 *}{seqnumber} +\end{funcdecl} + +Retrieves the remote sequence number that was used during authentication +and stores it in \funcparam{seqnumber}. + +\begin{funcdecl}{krb5_auth_getauthenticator}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_authenticator **}{authenticator} +\end{funcdecl} + +Retrieves the authenticator that was used during mutual +authentication. It is the callers responsibility to free the memory +allocated to \funcparam{authenticator} by calling +\funcname{krb5_free_authenticator}. + +\begin{funcdecl}{krb5_auth_con_initivector}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\end{funcdecl} + +Allocates memory for and zeros the initial vector in the +\funcparam{auth_context} keyblock. + +\begin{funcdecl}{krb5_auth_con_setivector}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context *}{auth_context} +\funcin +\funcarg{krb5_pointer}{ivector} +\end{funcdecl} + +Sets the i_vector portion of \funcparam{auth_context} to +\funcparam{ivector}. + +\begin{funcdecl}{krb5_auth_con_setrcache}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{krb5_rcache}{rcache} +\end{funcdecl} + +Sets the replay cache that is used by the authentication routines to \funcparam{rcache}. + +%% +%% The following prototypes exist, but there is no code at this time +%% krb5_auth_con_getcksumtype, krb5_auth_con_getivector, +%% krb5_auth_con_getrcache. -- Ezra + +\subsubsection{Principal access functions} + +Principals define a uniquely named client or server instance that +participates in a network communication. The following functions allow +one to create, modify and access portions of the +\datatype{krb5_principal}. + +Other functions found in orther portions of the manual include +\funcname{krb5_sname_to_principal}, \funcname{krb5_free_principal}, + +While it is possible to directly access the data structure in the +structure, it is recommended that the functions be used. + +\begin{funcdecl}{krb5_parse_name}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const char *}{name} +\funcout +\funcarg{krb5_principal *}{principal} +\end{funcdecl} + +Converts a single-string representation \funcparam{name} of the +principal name to the multi-part principal format used in the protocols. + +A single-string representation of a Kerberos name consists of one or +more principal name components, separated by slashes, optionally +followed by the ``@'' character and a realm name. If the realm name +is not specified, the local realm is used. + +The slash and ``@'' characters may be quoted (i.e., included as part +of a component rather than as a component separator or realm prefix) +by preceding them with a backslash (``$\backslash$'') character. +Similarly, newline, tab, backspace, and null characters may be +included in a component by using $\backslash{}n$, $\backslash{}t$, +$\backslash{}b$ or $\backslash{}0$, respectively. + +The realm in a Kerberos name may not contain the slash, colon or null +characters. + +\funcparam{*principal} will point to allocated storage which should be freed by +the caller (using \funcname{krb5_free_principal}) after use. + +\funcname{krb5_parse_name} returns KRB5_PARSE_MALFORMED if the string is + badly formatted, or ENOMEM if space for the return value can't be +allocated. + +\begin{funcdecl}{krb5_unparse_name}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_const_principal}{principal} +\funcout +\funcarg{char **}{name} +\end{funcdecl} + +Converts the multi-part principal name \funcparam{principal} from the +format used in the protocols to a single-string representation of the +name. The resulting single-string representation will use the format +and quoting conventions described for \funcname{krb5_parse_name} +above. + +\funcparam{*name} points to allocated storage and should be freed by the caller +when finished. + +\funcname{krb5_unparse_name} returns {\sc KRB_PARSE_MALFORMED} if the principal +does not contain at least 2 components, and system errors ({\sc ENOMEM} if +unable to allocate memory). + +\begin{funcdecl}{krb5_unparse_name_ext}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_const_principal}{principal} +\funcinout +\funcarg{char **}{name} +\funcarg{unsigned int *}{size} +\end{funcdecl} + +\funcname{krb5_unparse_name_ext} is designed for applications which +must unparse a large number of principals, and are concerned about the +speed impact of needing to do a lot of memory allocations and +deallocations. It functions similarly to \funcname{krb5_unparse_name} +except if \funcparam{*name} is non-null, in which case, it is assumed +to contain an allocated buffer of size \funcparam{*size} and this +buffer will be resized with \funcname{realloc} to hold the unparsed +name. Note that in this case, +\funcparam{size} must not be null. + +If \funcparam{size} is non-null (whether or not \funcparam{*name} is +null when the function is called), it will be filled in with the size +of the unparsed name upon successful return. + +\begin{funcdecl}{krb5_princ_realm}{krb5_data *}{\funcinout} +\funcparam{krb5_context}{context} +\funcparam{krb5_principal}{principal} +\end{funcdecl} + +A macro which returns the realm of \funcparam{principal}. + +\begin{funcdecl}{krb5_princ_set_realm}{void}{\funcinout} +\funcparam{krb5_context}{context} +\funcparam{krb5_principal}{principal} +\funcparam{krb5_data *}{realm} +\end{funcdecl} + +A macro which returns sets the realm of \funcparam{principal} to +\funcparam{realm}. + +\begin{funcdecl}{krb5_princ_set_realm_data}{void}{\funcinout} +\funcparam{krb5_context}{context} +\funcparam{krb5_principal}{principal} +\funcparam{char *}{data} +\end{funcdecl} + +\internalfunc + +A macro which returns sets the data portion of the realm of +\funcparam{principal} to \funcparam{data}. + +\begin{funcdecl}{krb5_princ_set_realm_length}{void}{\funcinout} +\funcparam{krb5_context}{context} +\funcparam{krb5_principal}{principal} +\funcparam{int}{length} +\end{funcdecl} + +\internalfunc + +A macro which returns sets the length \funcparam{principal} to +\funcparam{length}. + +\begin{funcdecl}{krb5_princ_size}{void}{\funcinout} +\funcparam{krb5_context}{context} +\funcparam{krb5_principal}{principal} +\end{funcdecl} + +\internalfunc + +A macro which gives the number of elements in the principal. +May also be used on the left size of an assignment. + +\begin{funcdecl}{krb5_princ_type}{void}{\funcinout} +\funcparam{krb5_context}{context} +\funcparam{krb5_principal}{principal} +\end{funcdecl} + +\internalfunc + +A macro which gives the type of the principal. +May also be used on the left size of an assignment. + +\begin{funcdecl}{krb5_princ_data}{} +\funcparam{krb5_context}{context} +\funcparam{krb5_principal}{principal} +\end{funcdecl} + +\internalfunc + +A macro which gives the pointer to data portion of the principal. +May also be used on the left size of an assignment. + + +\begin{funcdecl}{krb5_princ_component}{} +\funcparam{krb5_context}{context} +\funcparam{krb5_principal}{principal} +\funcparam{int}{i} +\end{funcdecl} + +\internalfunc + +A macro which gives the pointer to ith element of the principal. +May also be used on the left size of an assignment. + +\begin{funcdecl}{krb5_build_principal}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_principal *}{princ} +\funcin +\funcarg{unsigned int}{rlen} +\funcarg{const char *}{realm} +\funcarg{char}{*s1, *s2, ..., 0} +\end{funcdecl} +\begin{funcdecl}{krb5_build_principal_va}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_principal *}{princ} +\funcin +\funcarg{unsigned int}{rlen} +\funcarg{const char *}{realm} +\funcarg{va_list}{ap} +\end{funcdecl} + +\begin{sloppypar} +\funcname{krb5_build_principal} and +\funcname{krb5_build_principal_va} +perform the same function; the former takes variadic arguments, while +the latter takes a pre-computed varargs pointer. +\end{sloppypar} + +Both functions take a realm name \funcparam{realm}, realm name length +\funcparam{rlen}, and a list of null-terminated strings, and fill in a +pointer to a principal structure \funcparam{princ}, making it point to a +structure representing the named principal. +The last string must be followed in the argument list by a null pointer. + + +\begin{funcdecl}{krb5_build_principal_ext}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_principal *}{princ} +\funcin +\funcarg{unsigned int}{rlen} +\funcarg{const char *}{realm} +\funcarg{}{int len1, char *s1, int len2, char *s2, ..., 0} +\end{funcdecl} + +\funcname{krb5_build_principal_ext} is similar to +\funcname{krb5_build_principal} but it takes its components as a list of +(length, contents) pairs rather than a list of null-terminated strings. +A length of zero indicates the end of the list. + +\begin{funcdecl}{krb5_copy_principal}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_const_principal}{inprinc} +\funcout +\funcarg{krb5_principal *}{outprinc} +\end{funcdecl} + +Copy a principal structure, filling in \funcparam{*outprinc} to point to +the newly allocated copy, which should be freed with +\funcname{krb5_free_principal}. + +\begin{funcdecl}{krb5_principal_compare}{krb5_boolean}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_const_principal}{princ1} +\funcarg{krb5_const_principal}{princ2} +\end{funcdecl} + +If the two principals are the same, return TRUE, else return FALSE. + +\begin{funcdecl}{krb5_realm_compare}{krb5_boolean}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_const_principal}{princ1} +\funcarg{krb5_const_principal}{princ2} +\end{funcdecl} + +If the realms of the two principals are the same, return TRUE, else +return FALSE. + + +\begin{funcdecl}{krb5_425_conv_principal}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const char *}{name} +\funcarg{const char *}{instance} +\funcarg{const char *}{realm} +\funcout +\funcarg{krb5_principal *}{princ} +\end{funcdecl} + +Build a principal \funcparam{princ} from a V4 specification made up of +\funcparam{name}.\funcparam{instance}@\funcparam{realm}. The routine is +site-customized to convert the V4 naming scheme to a V5 one. For +instance, the V4 ``rcmd'' is changed to ``host''. + +The returned principal should be freed with +\funcname{krb5_free_principal}. + +\subsubsection{The application functions} + +\begin{funcdecl}{krb5_encode_kdc_rep}{krb5_error_code}{\funcin} +\funcarg{const krb5_msgtype}{type} +\funcarg{const krb5_enc_kdc_rep_part *}{encpart} +\funcarg{krb5_encrypt_block *}{eblock} +\funcarg{const krb5_keyblock *}{client_key} +\funcinout +\funcarg{krb5_kdc_rep *}{dec_rep} +\funcout +\funcarg{krb5_data **}{enc_rep} +\end{funcdecl} + +\internalfunc + +Takes KDC rep parts in \funcparam{*rep} and \funcparam{*encpart}, and +formats it into \funcparam{*enc_rep}, using message type +\funcparam{type} and encryption key \funcparam{client_key} and +encryption block \funcparam{eblock}. + +\funcparam{enc_rep{\ptsto}data} will point to allocated storage upon +non-error return; the caller should free it when finished. + +Returns system errors. + +\begin{funcdecl}{krb5_decode_kdc_rep}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_data *}{enc_rep} +\funcarg{const krb5_keyblock *}{key} +\funcarg{const krb5_enctype}{etype} +\funcout +\funcarg{krb5_kdc_rep **}{dec_rep} +\end{funcdecl} + +\internalfunc + +Takes a KDC_REP message and decrypts encrypted part using +\funcparam{etype} and \funcparam{*key}, putting result in \funcparam{*dec_rep}. +The pointers in \funcparam{dec_rep} +are all set to allocated storage which should be freed by the caller +when finished with the response (by using \funcname{krb5_free_kdc_rep}). + + +If the response isn't a KDC_REP (tgs or as), it returns an error from +the decoding routines. + +Returns errors from encryption routines, system errors. + +\begin{funcdecl}{krb5_kdc_rep_decrypt_proc}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_keyblock *}{key} +\funcarg{krb5_const_pointer}{decryptarg} +\funcinout +\funcarg{krb5_kdc_rep *}{dec_rep} +\end{funcdecl} + +Decrypt the encrypted portion of \funcparam{dec_rep}, using the +encryption key \funcparam{key}. The parameter \funcparam{decryptarg} is +ignored. + +The result is in allocated storage pointed to by +\funcparam{dec_rep{\ptsto}enc_part2}, unless some error occurs. + +This function is suitable for use as the \funcparam{decrypt_proc} +argument to \funcname{krb5_get_in_tkt}. + +\begin{funcdecl}{krb5_encrypt_tkt_part}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_keyblock *}{srv_key} +\funcinout +\funcarg{krb5_ticket *}{dec_ticket} +\end{funcdecl} + +\internalfunc + +\begin{sloppypar} +Encrypts the unecrypted part of the ticket found in +\funcparam{dec_ticket{\ptsto}enc_part2} using +\funcparam{srv_key}, and places result in +\funcparam{dec_ticket{\ptsto}enc_part}. +The \funcparam{dec_ticket{\ptsto}enc_part} will be allocated by this +function. +\end{sloppypar} + +Returns errors from encryption routines, system errors + +\funcparam{enc_part{\ptsto}data} is allocated and filled in with +encrypted stuff. + +\begin{funcdecl}{krb5_decrypt_tkt_part}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_keyblock *}{srv_key} +\funcinout +\funcarg{krb5_ticket *}{dec_ticket} +\end{funcdecl} + +\internalfunc + +Takes encrypted \funcparam{dec_ticket{\ptsto}enc_part}, decrypts with +\funcparam{dec_ticket{\ptsto}etype} +using \funcparam{srv_key}, and places result in +\funcparam{dec_ticket{\ptsto}enc_part2}. The storage of +\funcparam{dec_ticket{\ptsto}enc_part2} will be allocated before return. + +Returns errors from encryption routines, system errors + +\begin{funcdecl}{krb5_send_tgs}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_flags}{kdcoptions} +\funcarg{const krb5_ticket_times *}{timestruct} +\funcarg{const krb5_enctype *}{etypes} +\funcarg{const krb5_cksumtype}{sumtype} +\funcarg{krb5_const_principal}{sname} +\funcarg{krb5_address * const *}{addrs} +\funcarg{krb5_authdata * const *}{authorization_data} +\funcarg{krb5_pa_data * const *}{padata} +\funcarg{const krb5_data *}{second_ticket} +\funcinout +\funcarg{krb5_creds *}{in_cred} +\funcout +\funcarg{krb5_response *}{rep} +\end{funcdecl} + +\internalfunc + +Sends a request to the TGS and waits for a response. +\funcparam{kdcoptions} is used for the options in the KRB_TGS_REQ. +\funcparam{timestruct} values are used for from, till, and rtime in the +KRB_TGS_REQ. +\funcparam{etypes} is a list of etypes used in the KRB_TGS_REQ. +\funcparam{sumtype} is used for the checksum in the AP_REQ in the KRB_TGS_REQ. +\funcparam{sname} is used for sname in the KRB_TGS_REQ. +\funcparam{addrs}, if non-NULL, is used for addresses in the KRB_TGS_REQ. +\funcparam{authorization_data}, if non-NULL, is used for +\funcparam{authorization_data} in the KRB_TGS_REQ. +\funcparam{padata}, if non-NULL, is combined with any other supplied +pre-authentication data for the KRB_TGS_REQ. +\funcparam{second_ticket}, if required by options, is used for the 2nd +ticket in the KRB_TGS_REQ. +\funcparam{in_cred} is used for the ticket and session key in the KRB_AP_REQ header in the KRB_TGS_REQ. + +The KDC realm is extracted from \funcparam{in_cred{\ptsto}server}'s realm. + +The response is placed into \funcparam{*rep}. +\funcparam{rep{\ptsto}response.data} is set to point at allocated storage +which should be freed by the caller when finished. + +Returns system errors. + +\begin{funcdecl}{krb5_get_cred_from_kdc}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_ccache}{ccache} +\funcarg{krb5_creds *}{in_cred} +\funcout +\funcarg{krb5_cred **}{out_cred} +\funcarg{krb5_creds ***}{tgts} +\end{funcdecl} + + +Retrieve credentials for principal \funcparam{in_cred{\ptsto}client}, +server \funcparam{creds{\ptsto}server}, possibly +\funcparam{creds{\ptsto}second_ticket} if needed by the ticket flags. + +\funcparam{ccache} is used to fetch initial TGT's to start the authentication +path to the server. + +Credentials are requested from the KDC for the server's realm. Any +TGT credentials obtained in the process of contacting the KDC are +returned in an array of credentials; \funcparam{tgts} is filled in to +point to an array of pointers to credential structures (if no TGT's were +used, the pointer is zeroed). TGT's may be returned even if no useful +end ticket was obtained. + +The returned credentials are NOT cached. + +If credentials are obtained, \funcparam{creds} is filled in with the results; +\funcparam{creds{\ptsto}ticket} and +\funcparam{creds{\ptsto}keyblock{\ptsto}key} are set to allocated storage, +which should be freed by the caller when finished. + +Returns errors, system errors. + +\begin{funcdecl}{krb5_get_cred_via_tkt}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_creds *}{tkt} +\funcarg{const krb5_flags}{kdcoptions} +\funcarg{krb5_address *const *}{address} +\funcarg{krb5_creds *}{in_cred} +\funcout +\funcarg{krb5_creds **}{out_cred} +\end{funcdecl} + +Takes a ticket \funcparam{tkt} and a target credential +\funcparam{in_cred}, attempts to fetch a TGS from the KDC. Upon +success the resulting is stored in \funcparam{out_cred}. The memory +allocated in \funcparam{out_cred} should be freed by the called when +finished by using \funcname{krb5_free_creds}. + +\funcparam{kdcoptions} refers to the options as listed in Table +\ref{KDCOptions}. The optional \funcparam{address} is used for addressed +in the KRB_TGS_REQ (see \funcname{krb5_send_tgs}). + +Returns errors, system errors. + + +\begin{funcdecl}{krb5_get_credentials}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_flags}{options} +\funcarg{krb5_ccache}{ccache} +\funcarg{krb5_creds *}{in_creds} +\funcout +\funcarg{krb5_creds *}{out_creds} +\end{funcdecl} + +This routine attempts to use the credentials cache \funcparam{ccache} or a TGS +exchange to get an additional ticket for the client identified by +\funcparam{in_creds{\ptsto}client}, with following information: +\begin{itemize} +\item {\bf The server} identified by \funcparam{in_creds{\ptsto}server} +\item {\bf The options} in \funcparam{options}. +Valid choices are KRB5_GC_USER_USER and KRB5_GC_GC_CACHED +\item {\bf The expiration date} specified in +\funcparam{in_creds{\ptsto}times.endtime} +\item {\bf The session key type} specified in +\funcparam{in_creds{\ptsto}keyblock.keytype} if it is non-zero. +\end{itemize} + +If \funcparam{options} specifies KRB5_GC_CACHED, +then \funcname{krb5_get_credentials} will only search the credentials cache +for a ticket. + +If \funcparam{options} specifies KRB5_GC_USER_USER, then +\funcname{krb5_get_credentials} will get credentials for a user to user +authentication. In a user to user authentication, the secret key for +the server +is the session key from the server's ticket-granting-ticket +(TGT). The TGT is passed from the server to the client over the +network --- this is safe since the TGT is encrypted in a key +known only by the Kerberos server --- and the client must pass +this TGT to \funcname{krb5_get_credentials} in +\funcparam{in_creds{\ptsto}second_ticket}. The Kerberos server will use +this TGT to construct a user to user ticket which can be verified by +the server by using the session key from its TGT. + +The effective {\bf expiration date} is the minimum of the following: +\begin{itemize} +\item The expiration date as specified in +\funcparam{in_creds{\ptsto}times.endtime} +\item The requested start time plus the maximum lifetime of the +server as specified by the server's entry in the +Kerberos database. +\item The requested start time plus the maximum lifetime of tickets +allowed in the local site, as specified by the KDC. +This is currently a compile-time option, +KRB5_KDB_MAX_LIFE in config.h, and is by default 1 day. +\end{itemize} + +If any special authorization data needs to be included in the ticket, +--- for example, restrictions on how the ticket can be used --- +they should be specified in \funcparam{in_creds{\ptsto}authdata}. If there +is no special authorization data to be passed, +\funcparam{in_creds{\ptsto}authdata} should be NULL. + +Any returned ticket and intermediate ticket-granting tickets are +stored in \funcparam{ccache}. + +Returns errors from encryption routines, system errors. + +\begin{funcdecl}{krb5_get_in_tkt}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_flags}{options} +\funcarg{krb5_address * const *}{addrs} +\funcarg{const krb5_enctype *}{etypes} +\funcarg{const krb5_preauthtype *}{ptypes} +\funcfuncarg{krb5_error_code}{(*key_proc)} + \funcarg{krb5_context}{context} + \funcarg{const krb5_keytype}{type} + \funcarg{krb5_data *}{salt} + \funcarg{krb5_const_pointer}{keyseed} + \funcarg{krb5_keyblock **}{key} +\funcendfuncarg +\funcarg{krb5_const_pointer}{keyseed} +\funcfuncarg{krb5_error_code}{(*decrypt_proc)} + \funcarg{krb5_context}{context} + \funcarg{const krb5_keyblock *}{key} + \funcarg{krb5_const_pointer}{decryptarg} + \funcarg{krb5_kdc_rep *}{dec_rep} +\funcendfuncarg +\funcarg{krb5_const_pointer}{decryptarg} +\funcinout +\funcarg{krb5_creds *}{creds} +\funcarg{krb5_ccache}{ccache} +\funcarg{krb5_kdc_rep **}{ret_as_reply} +\end{funcdecl} + +This all-purpose initial ticket routine, usually called via +\funcname{krb5_get_in_tkt_with_skey} or +\funcname{krb5_get_in_tkt_with_password} or +\funcname{krb5_get_in_tkt_with_keytab}. + + +Attempts to get an initial ticket for \funcparam{creds{\ptsto}client} +to use server \funcparam{creds{\ptsto}server}, using the following: +the realm from \funcparam{creds{\ptsto}client}; the options in +\funcparam{options} (listed in Table \ref{KDCOptions}); +and \funcparam{ptypes}, the preauthentication +method (valid preauthentication methods are listed in Table +\ref{padata-types}). +\funcname{krb5_get_in_tkt} requests encryption type +\funcparam{etypes} (valid encryption types are ETYPE_DES_CBC_CRC and +ETYPE_RAW_DES_CBC), +using \funcparam{creds{\ptsto}times.starttime}, +\funcparam{creds{\ptsto}times.endtime}, +\funcparam{creds{\ptsto}times.renew_till} +as from, till, and rtime. \funcparam{creds{\ptsto}times.renew_till} is +ignored unless the RENEWABLE option is requested. + +\funcparam{key_proc} is called, with \funcparam{context}, \funcparam{keytype}, +\funcparam{keyseed} and\funcparam{padata} as arguments, to fill in \funcparam{key} to be used for +decryption. The valid key types for \funcparam{keytype} are +KEYTYPE_NULL,\footnote{See RFC section 6.3.1} and +KEYTYPE_DES.\footnote{See RFC section 6.3.4} However, KEYTYPE_DES is +the only key type supported by MIT kerberos. +The content of \funcparam{keyseed} +depends on the \funcparam{key_proc} being used. %nlg - need a ref here +The \funcparam{padata} passed +to \funcparam{key_proc} is the preauthentication data returned by the +KDC as part of the reply to the initial ticket request. It may +contain an element of type KRB5_PADATA_PW_SALT, which +\funcparam{key_proc} should use to determine what salt to use when +generating the key. \funcparam{key_proc} should fill in +\funcparam{key} with a key for the client, or return an error code. + +\funcparam{decrypt_proc} is called to perform the decryption of the +response (the encrypted part is in +\funcparam{dec_rep{\ptsto}enc_part}; the decrypted part should be +allocated and filled into +\funcparam{dec_rep{\ptsto}enc_part2}. +\funcparam{decryptarg} is passed on to \funcparam{decrypt_proc}, and +its content depends on the \funcparam{decrypt_proc} being used. + +If \funcparam{addrs} is non-NULL, it is used for the addresses +requested. If it is null, the system standard addresses are used. + +If \funcparam{ret_as_reply} is non-NULL, it is filled in with a +pointer to a structure containing the reply packet from the KDC. Some +programs may find it useful to have direct access to this information. +For example, it can be used to obtain the pre-authentication data +passed back from the KDC. The caller is responsible for freeing this +structure by using \funcname{krb5_free_kdc_rep}. + +If \funcparam{etypes} is non-NULL, the it is used as for the list of +valid encyrption types. Otherwise, the context default is used (as +returned by \funcname{krb5_get_default_in_tkt_etypes}. + +A succesful call will place the ticket in the credentials cache +\funcparam{ccache} and fill in \funcparam{creds} with the ticket +information used/returned. + +Returns system errors, preauthentication errors, encryption errors. + +% XXX Right now, uses creds->addresses before it's copied into from +% the reply -- it's passed to krb5_obtain_padata. I think that's +% wrong, and it should be using either addrs or the result of +% krb5_os_localaddr instead. If I'm wrong, then this spec has to be +% updated to document that creds->addresses is used. On the other +% hand, if I'm right, then the bug in get_in_tkt needs to be fixed. +% See ov-cambridge PR 1525. + +\begin{funcdecl}{krb5_get_in_tkt_with_password}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_flags}{options} +\funcarg{krb5_address * const *}{addrs} +\funcarg{const krb5_enctype *}{etypes} +\funcarg{const krb5_preauthtype *}{pre_auth_types} +\funcarg{const char *}{password} +\funcarg{krb5_ccache}{ccache} +\funcinout +\funcarg{krb5_creds *}{creds} +\funcarg{krb5_kdc_rep **}{ret_as_reply} +\end{funcdecl} + +Attempts to get an initial ticket using the null-terminated string +\funcparam{password}. If \funcparam{password} is NULL, the password +is read from the terminal using as a prompt the globalname +\globalname{krb5_default_pwd_prompt1}. + +The password is converted into a key using the appropriate +string-to-key conversion function for the specified +\funcparam{keytype}, and using any salt data returned by the KDC in +response to the authentication request. + +See \funcname{krb5_get_in_tkt} for documentation of the +\funcparam{options}, \funcparam{addrs}, \funcparam{pre_auth_type}, +\funcparam{etype}, \funcparam{keytype}, \funcparam{ccache}, +\funcparam{creds} and \funcparam{ret_as_reply} arguments. + +Returns system errors, preauthentication errors, encryption errors. + +\begin{funcdecl}{krb5_get_in_tkt_with_keytab}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_flags}{options} +\funcarg{krb5_address * const *}{addrs} +\funcarg{const krb5_enctype *}{etypes} +\funcarg{const krb5_preauthtype *}{pre_auth_types} +\funcarg{const krb5_keytab *}{keytab} +\funcarg{krb5_ccache}{ccache} +\funcinout +\funcarg{krb5_creds *}{creds} +\funcarg{krb5_kdc_rep **}{ret_as_reply} +\end{funcdecl} + +Attempts to get an initial ticket using \funcparam{keytab}. If +\funcparam{keytab} is NULL, the default keytab is used +(e.g., \filename{/etc/v5srvtab}). + +See \funcname{krb5_get_in_tkt} for documentation of the +\funcparam{options}, \funcparam{addrs}, \funcparam{pre_auth_type}, +\funcparam{etype}, \funcparam{ccache}, \funcparam{creds} and +\funcparam{ret_as_reply} arguments. + +Returns system errors, preauthentication errors, encryption errors. + +\begin{funcdecl}{krb5_get_in_tkt_with_skey}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_flags}{options} +\funcarg{krb5_address * const *}{addrs} +\funcarg{const krb5_enctype *}{etypes} +\funcarg{const krb5_preauthtype *}{pre_auth_types} +\funcarg{const krb5_keyblock *}{key} +\funcarg{krb5_ccache}{ccache} +\funcinout +\funcarg{krb5_creds *}{creds} +\funcarg{krb5_kdc_rep **}{ret_as_reply} +\end{funcdecl} + +Attempts to get an initial ticket using \funcparam{key}. If +\funcparam{key} is NULL, an appropriate key is retrieved from the +system key store (e.g., \filename{/etc/v5srvtab}). + +See \funcname{krb5_get_in_tkt} for documentation of the +\funcparam{options}, \funcparam{addrs}, \funcparam{pre_auth_type}, +\funcparam{etype}, \funcparam{ccache}, \funcparam{creds} and +\funcparam{ret_as_reply} arguments. + +Returns system errors, preauthentication errors, encryption errors. + +\begin{funcdecl}{krb5_mk_req}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context *}{auth_context} +\funcin +\funcarg{const krb5_flags}{ap_req_options} +\funcarg{char *}{service} +\funcarg{char *}{hostname} +\funcarg{krb5_data *}{in_data} +\funcinout +\funcarg{krb5_ccache}{ccache} +\funcout +\funcarg{krb5_data *}{outbuf} +\end{funcdecl} + +Formats a KRB_AP_REQ message into \funcparam{outbuf}. + +The server to receive the message is specified by +\funcparam{hostname}. The principal of the server to receive the message +is specified by \funcparam{hostname} and \funcparam{service}. +If credentials are not present in the credentials cache +\funcparam{ccache} for this server, the TGS request with default +parameters is used in an attempt to obtain such credentials, and they +are stored in \funcparam{ccache}. + +\funcparam{ap_req_options} specifies the KRB_AP_REQ options desired. +Valid options are: + +\begin{tabular}{ll} +AP_OPTS_USE_SESSION_KEY&\\ +AP_OPTS_MUTUAL_REQUIRED&\\ +\end{tabular} +\label{ap-req-options} + +The checksum method to be used is as specified in \funcparam{auth_context}. + +% XXX Not sure if it's legal in the protocol for no checksum to be +% included, or if so, how the server reacts to a request with no +% checksum. + +\funcparam{outbuf} should point to an existing \datatype{krb5_data} +structure. \funcparam{outbuf{\ptsto}length} and +\funcparam{outbuf{\ptsto}data} will be filled in on success, and the latter +should be freed by the caller when it is no longer needed; if an error +is returned, however, no storage is allocated and {\tt +outbuf{\ptsto}data} does not need to be freed. + +Returns system errors, error getting credentials for +\funcparam{server}. + +\begin{funcdecl}{krb5_mk_req_extended}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context *}{auth_context} +\funcin +\funcarg{const krb5_flags}{ap_req_options} +\funcarg{krb5_data *}{in_data} +\funcarg{krb5_creds *}{in_creds} +\funcout +\funcarg{krb5_data *}{outbuf} +\end{funcdecl} + +Formats a KRB_AP_REQ message into \funcparam{outbuf}, with more complete +options than \funcname{krb5_mk_req}. + +\funcparam{outbuf}, \funcparam{ap_req_options}, \funcparam{auth_context}, +and \funcparam{ccache} are used in the same fashion as for +\funcname{krb5_mk_req}. + +\funcparam{in_creds} is used to supply the credentials (ticket and session +key) needed to form the request. + +If \funcparam{in_creds{\ptsto}ticket} has no data (length == 0), then an +error is returned. + +During this call, the structure elements in \funcparam{in_creds} may be +freed and reallocated. Hence all of the structure elements which are +pointers should point to allocated memory, and there should be no other +pointers aliased to the same memory, since it may be deallocated during +this procedure call. + + +If \funcparam{ap_req_options} specifies AP_OPTS_USE_SUBKEY, then a +subkey will be generated if need be by \funcname{krb5_generate_subkey}. + +A copy of the authenticator will be stored in the +\funcparam{auth_context}, with the principal and checksum fields nulled +out, unless an error is returned. (This is to prevent pointer sharing +problems; the caller shouldn't need these fields anyway, since the +caller supplied them.) + +Returns system errors, errors contacting the KDC, KDC errors getting +a new ticket for the authenticator. + +\begin{funcdecl}{krb5_generate_subkey}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_keyblock *}{key} +\funcout +\funcarg{krb5_keyblock **}{subkey} +\end{funcdecl} + +Generates a pseudo-random sub-session key using the encryption system's +random key functions, based on the input \funcparam{key}. + +\funcparam{subkey} is filled in to point to the generated subkey, unless +an error is returned. The returned key (i.e., \funcparam{*subkey}) is +allocated and should be freed by the caller with +\funcname{krb5_free_keyblock} when it is no longer needed. + +\begin{funcdecl}{krb5_rd_req}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context *}{auth_context} +\funcin +\funcarg{const krb5_data *}{inbuf} +\funcarg{krb5_const_principal}{server} +\funcarg{krb5_keytab}{keytab} +\funcinout +\funcarg{krb5_flags *}{ap_req_options} +\funcout +\funcarg{krb5_ticket **}{ticket} +\end{funcdecl} + +Parses a KRB_AP_REQ message, returning its contents. Upon successful +return, if \funcparam{ticket} is non-NULL, \funcparam{*ticket} will be +modified to point to allocated storage containing the ticket +information. The caller is responsible for deallocating this space by +using \funcname{krb5_free_ticket}. + +\funcparam{inbuf} should contain the KRB_AP_REQ message to be parsed. + +If \funcparam{auth_context} is NULL, one will be generated and freed +internally by the function. + +\funcparam{server} specifies the expected server's name for the ticket. +If \funcparam{server} is NULL, then any server name will be accepted if +the appropriate key can be found, and the caller should verify that the +server principal matches some trust criterion. + +If \funcparam{server} is not NULL, and a replay detaction cache has not been +established with the \funcparam{auth_context}, one will be generated. + +\funcparam{keytab} specifies a keytab containing generate a decryption key. If +NULL, \funcparam{krb5_kt_default} will be used to find the default +keytab and the key taken from there\footnote{i.e., srvtab file in +Kerberos V4 parlance}. + + +If a keyblock is present in the \funcparam{auth_context}, it will be +used to decrypt the ticket request and the keyblock freed with +\funcname{krb5_free_keyblock}. This is useful for user to user +authentication. If no keyblock is specified, the \funcparam{keytab} is +consulted for an entry matching the requested keytype, server and +version number and used instead. + +The authentcator in the request is decrypted and stored in the +\funcparam{auth_context}. The client specified in the decrypted +authenticator is compared to the client specified in the decoded ticket +to ensure that the compare. + +If the remote_addr portion of the \funcparam{auth_context} is set, +then this routine checks if the request came from the right client. + +\funcparam{sender_addr} specifies the address(es) expected to be present +in the ticket. + +The replay cache is checked to see if the ticket and authenticator have +been seen and if so, returns an error. If not, the ticket and +authenticator are entered into the cache. + +Various other checks are made of the decoded data, including, +cross-realm policy, clockskew and ticket validation times. + +The keyblock, subkey, and sequence number of the request are all stored +in the \funcparam{auth_context} for future use. + +If the request has the AP_OPTS_MUTUAL_REQUIRED bit set, the local +sequence number, which is stored in the auth_context, is XORed with the +remote sequence number in the request. + +If \funcparam{ap_req_options} is non-NULL, it will be set to contain the +application request flags. + +Returns system errors, encryption errors, replay errors. + +\begin{funcdecl}{krb5_rd_req_decoded}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context *}{auth_context} +\funcin +\funcarg{const krb5_ap_req *}{req} +\funcarg{krb5_const_principal}{server} +\funcinout +\funcarg{krb5_keytab}{keytab} +\funcout +\funcarg{krb5_ticket **}{ticket} +\end{funcdecl} + +Essentially the same as \funcname{krb5_rd_req}, but uses a decoded AP_REQ +as the input rather than an encoded input. + +\begin{funcdecl}{krb5_mk_rep}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcout +\funcarg{krb5_data *}{outbuf} +\end{funcdecl} + +Formats and encrypts an AP_REP message, including in it the data in the +authentp portion of \funcparam{auth_context}, encrypted using the +keyblock portion of \funcparam{auth_context}. + +When successful, \funcparam{outbuf{\ptsto}length} and +\funcparam{outbuf{\ptsto}data} are filled in with the length of the +AP_REQ message and allocated data holding it. +\funcparam{outbuf{\ptsto}data} should be freed by the +caller when it is no longer needed. + +If the flags in \funcparam{auth_context} indicate that a sequence number +should be used (either {\sc KRB5_AUTH_CONTEXT_DO_SEQUENCE} or +{\sc KRB5_AUTH_CONTEXT_RET_SEQUENCE}) and the local sequqnce number in the +\funcparam{auth_context} is 0, a new number will be generated with +\funcname{krb5_generate_seq_number}. + +Returns system errors. + +\begin{funcdecl}{krb5_rd_rep}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{const krb5_data *}{inbuf} +\funcout +\funcarg{krb5_ap_rep_enc_part **}{repl} +\end{funcdecl} + +Parses and decrypts an AP_REP message from \funcparam{*inbuf}, filling in +\funcparam{*repl} with a pointer to allocated storage containing the +values from the message. The caller is responsible for freeing this +structure with \funcname{krb5_free_ap_rep_enc_part}. + +The keyblock stored in \funcparam{auth_context} is used to decrypt the +message after establishing any key pre-processing with +\funcname{krb5_process_key}. + +Returns system errors, encryption errors, replay errors. + +\begin{funcdecl}{krb5_mk_error}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_error *}{dec_err} +\funcout +\funcarg{krb5_data *}{enc_err} +\end{funcdecl} + +Formats the error structure \funcparam{*dec_err} into an error buffer +\funcparam{*enc_err}. + +The error buffer storage (\funcparam{enc_err{\ptsto}data}) is +allocated, and should be freed by the caller when finished. + +Returns system errors. + +\begin{funcdecl}{krb5_rd_error}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_data *}{enc_errbuf} +\funcout +\funcarg{krb5_error **}{dec_error} +\end{funcdecl} + +Parses an error protocol message from \funcparam{enc_errbuf} and fills in +\funcparam{*dec_error} with a pointer to allocated storage containing +the error message. The caller is reponsible for freeing this structure by +using \funcname{krb5_free_error}. + +Returns system errors. + +\begin{funcdecl}{krb5_generate_seq_number}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_keyblock *}{key} +\funcout +\funcarg{krb5_int32 *}{seqno} +\end{funcdecl} + +Generates a pseudo-random sequence number suitable for use as an initial +sequence number for the KRB_SAFE and KRB_PRIV message processing +routines. + +\funcparam{key} parameterizes the choice of the random sequence number, +which is filled into \funcparam{*seqno} upon return. + +\begin{funcdecl}{krb5_sendauth}{krb5_error_code} +\funcinout +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context *}{auth_context} +\funcin +\funcarg{krb5_pointer}{fd} +\funcarg{char *}{appl_version} +\funcarg{krb5_principal}{client} +\funcarg{krb5_principal}{server} +\funcarg{krb5_flags}{ap_req_options} +\funcarg{krb5_data *}{in_data} +\funcarg{krb5_creds *}{in_creds} +\funcinout +\funcarg{krb5_ccache}{ccache} +\funcout +\funcarg{krb5_error **}{error} +\funcarg{krb5_ap_rep_enc_part **}{rep_result} +\funcarg{krb5_creds **}{out_creds} +\end{funcdecl} + +\funcname{krb5_sendauth} provides a convenient means for client and +server programs to send authenticated messages to one another through +network connections. \funcname{krb5_sendauth} sends an authenticated +ticket from the client program to the server program using the network +connection specified by \funcparam{fd}. In the MIT Unix implementation, +\funcparam{fd} should be a pointer to a file descriptor describing the +network socket. This can be changed in other implementations, however, +if the routines \funcname{krb5_read_message}, +\funcname{krb5_write_message}, \funcname{krb5_net_read}, and +\funcname{krb5_net_write} are changed. + +The paramter \funcparam{appl_version} is a string describing the +application protocol version which the client is expecting to use for +this exchange. If the server is using a different application protocol, +an error will be returned. + +The parameters \funcparam{client} and \funcparam{server} specify the +kerberos principals for the client and the server. They are +ignored if \funcparam{in_creds} is non-null. Otherwise, +\funcparam{server} must be non-null, but \funcparam{client} may be +null, in which case the client principal used is the one in the +credential cache's default principal. + +The \funcparam{ap_req_options} parameters specifies the options which +should be passed to \funcname{krb5_mk_req}. Valid options are listed +in Table \ref{ap-req-options}. If \funcparam{ap_req_options} +specifies MUTUAL_REQUIRED, then \funcname{krb5_sendauth} will perform +a mutual authentication exchange, and if \funcparam{rep_result} is +non-null, it will be filled in with the result of the mutual +authentication exchange; the caller should free +\funcparam{*rep_result} with +\funcname{krb5_free_ap_rep_enc_part} when done with it. + +If \funcparam{in_creds} is non-null, then +\funcparam{in_creds{\ptsto}client} and +\funcparam{in_creds{\ptsto}server} must be filled in, and either +the other structure fields should be filled in with valid credentials, +or \funcparam{in_creds{\ptsto}ticket.length} should be zero. If +\funcparam{in_creds{\ptsto}ticket.length} is non-zero, then +\funcparam{in_creds} will be used as-is as the credentials to send to +the server, and \funcparam{ccache} is ignored; otherwise, +\funcparam{ccache} is used as described below, and \funcparam{out_creds} +, if not NULL, is filled in with the retrieved credentials. + +\funcname{ccache} specifies the credential cache to use when one is +needed (i.e., when \funcname{in_creds} is null or +\funcparam{in_creds{\ptsto}ticket.length} is zero). When a credential +cache is not needed, \funcname{ccache} is ignored. When a credential +cache is needed and \funcname{ccache} is null, the default credential +cache is used. Note that if the credential cache is needed and does +not contain the needed credentials, they will be retrieved from the +KDC and stored in the credential cache. + +If mutual authentication is used and \funcparam{rep_result} is non-null, +the sequence number for the server is available to the caller in +\funcparam{*rep_result->seq_number}. (If mutual authentication is not +used, there is no way to negotiate a sequence number for the server.) + +If an error occurs during the authenticated ticket exchange and +\funcparam{error} is non-null, the error packet (if any) that was sent +from the server will be placed in it. This error should be freed with +\funcname{krb5_free_error}. + +\begin{funcdecl}{krb5_recvauth}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context *}{auth_context} +\funcin +\funcarg{krb5_pointer}{fd} +\funcarg{char *}{appl_version} +\funcarg{krb5_principal}{server} +\funcarg{char *}{rc_type} +\funcarg{krb5_int32}{flags} +\funcarg{krb5_keytab}{keytab} +\funcout +\funcarg{krb5_ticket **}{ticket} +\end{funcdecl} + +\funcname{krb5_recvauth} provides a convenient means for client and +server programs to send authenticated messages to one another through +network connections. \funcname{krb5_sendauth} is the matching routine +to \funcname{krb5_recvauth} for the server. \funcname{krb5_recvauth} +will engage in an authentication dialogue with the +client program running \funcname{krb5_sendauth} to authenticate the +client to the server. In addition, if requested by the client, +\funcname{krb5_recvauth} will provide mutual authentication to +prove to the client that the server represented by +\funcname{krb5_recvauth} is legitimate. + +\funcparam{fd} is a pointer to the network connection. As in +\funcname{krb5_sendauth}, in the MIT Unix implementation +\funcparam{fd} is a pointer to a file descriptor. + +The parameter \funcparam{appl_version} is a string describing the +application protocol version which the server is expecting to use for +this exchange. If the client is using a different application protocol, +an error will be returned and the authentication exchange will be +aborted. + +If \funcparam{server} is non-null, then \funcname{krb5_recvauth} +verifies that the server principal requested by the client matches +\funcparam{server}. If not, an error will be returned and the +authentication exchange will be aborted. + +The parameters \funcparam{server}, \funcparam{auth_context}, +and \funcparam{keytab} are used by \funcname{krb5_rd_req} to obtain the +server's private key. + +If \funcparam{server} is non-null, the princicpal component of it is +ysed to determine the replay cache to use. Otherwise, +\funcname{krb5_recvauth} will use a default replay cache. + +The \funcparam{flags} argument allows the caller to modify the behavior of +\funcname{krb5_recvauth}. For non-library callers, \funcparam{flags} +should be 0. + +% XXX Note that if the bug I submitted entitled ``"flags" argument +% should not have been added to krb5_recvauth'' (OpenVision Cambridge +% bug number 1585) causes code changes, this will have to be updated. + +\funcparam{ticket} is optional and is only filled in if non-null. It is +filled with the data from the ticket sent by the client, and should be +freed with +\funcname{krb5_free_ticket} when it is no longer needed. + +\begin{funcdecl}{krb5_mk_safe}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{const krb5_data *}{userdata} +\funcout +\funcarg{krb5_data *}{outbuf} +\funcinout +\funcarg{krb5_replay_data *}{outdata} +\end{funcdecl} + +Formats a KRB_SAFE message into \funcparam{outbuf}. + +\funcparam{userdata} is formatted as the user data in the message. +Portions of \funcparam{auth_context} specify the checksum type; the +keyblockm which might be used to seed the checksum; +full addresses (host and port) for the sender and receiver. +The \funcparam{local_addr} portion of \funcparam{*auth_context} +is used to form the addresses usedin the KRB_SAFE message. The \funcparam{remote_addr} is optional; if the +receiver's address is not known, it may be replaced by NULL. +\funcparam{local_addr}, however, is mandatory. + +The \funcparam{auth_context} flags select whether sequence numbers or +timestamps should be used to identify the message. Valid flags are +listed below. + +\begin{tabular}{ll} +\multicolumn{1}{c}{Symbol} & Meaning \\ +KRB5_AUTH_CONTEXT_DO_TIME & Use timestamps\\ + &\ and replay cache\\ +KRB5_AUTH_CONTEXT_RET_TIME & Copy timestamp \\ + &\ to \funcparam{*outdata} \\ +KRB5_AUTH_CONTEXT_DO_SEQUENCE & Use sequence numbers \\ +KRB5_AUTH_CONTEXT_RET_SEQUENCE & Copy sequence numbers\\ + &\ to \funcparam{*outdata} \\ +\end{tabular} + +If timestamps are to be used (i.e., if KRB5_AUTH_CONTEXT_DO_TIME is +set), an entry describing the message will be entered in the replay +cache so that the caller may detect if this message is sent +back to him by an attacker. If KRB5_AUTH_CONTEXT_DO_TIME is not set, +the \funcparam{auth_context} replay cache is not used. + +If sequence numbers are to be used (i.e., if either +KRB5_AUTH_CONTEXT_DO_SEQUENCE or KRB5_AUTH_CONTEXT_RET_SEQUENEC is +set), then \funcparam{auth_context} local sequence number will be +placed in the protected message as its sequence number. + +The \funcparam{outbuf} buffer storage (i.e., +\funcparam{outbuf{\ptsto}data}) is allocated, and should be freed by +the caller when finished. + +Returns system errors, encryption errors. + +\begin{funcdecl}{krb5_rd_safe}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{const krb5_data *}{inbuf} +\funcout +\funcarg{krb5_data *}{outbuf} +\funcinout +\funcarg{krb5_replay_data *}{outdata} +\end{funcdecl} + +Parses a KRB_SAFE message from \funcparam{inbuf}, placing the +data in \funcparam{*outbuf} after verifying its integrity. + +The keyblock used for verifying the integrity of the message is taken +from the \funcparam{auth_context} recv\_subkey or keyblock. The +keyblock is chosen in the above order by the first one which is not +NULL. + +The remote_addr and localaddr portions of the \funcparam{*auth_context} +specify the full addresses (host and port) of the sender and receiver, +and must be of type \datatype{ADDRTYPE_ADDRPORT}. + + +The \funcparam{remote_addr} parameter is mandatory; it +specifies the address of the sender. If the address of the sender in +the message does not match \funcparam{remote_addr}, the error +KRB5KRB_AP_ERR_BADADDR will be returned. + +If \funcparam{local_addr} is non-NULL, then the address of the receiver +in the message much match it. If it is null, the receiver address in +the message will be checked against the list of local addresses as +returned by \funcname{krb5_os_localaddr}. If the check fails, +KRB5KRB_AP_ERR_BADARRD is returned. + +The \funcparam{outbuf} buffer storage (i.e., +\funcparam{outbuf{\ptsto}data} is allocated storage which the caller +should free when it is no longer needed. + +If auth_context_flags portion of \funcparam{auth_context} indicates +that sequence numbers are to be used (i.e., if KRB5_AUTH_CONTEXT_DOSEQUENCE is +set in it), The \funcparam{remote_seq_number} portion of +\funcparam{auth_context} is compared to the sequence number for the +message, and KRB5_KRB_AP_ERR_BADORDER is returned if it does not match. +Otherwise, the sequence number is not used. + + +If timestamps are to be used (i.e., if KRB5_AUTH_CONTEXT_DO_TIME is set +in the \funcparam{auth_context}), then two additional checks are performed: +\begin{itemize} +\item The timestamp in the message must be within the permitted clock + skew (which is usually five minutes), or KRB5KRB_AP_ERR_SKEW + is returned. +\item The message must not be a replayed message, according to + \funcparam{rcache}. +\end{itemize} + +Returns system errors, integrity errors. + +\begin{funcdecl}{krb5_mk_priv}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{const krb5_data *}{userdata} +\funcout +\funcarg{krb5_data *}{outbuf} +\funcarg{krb5_replay_data *}{outdata} +\end{funcdecl} + +Formats a KRB_PRIV message into \funcparam{outbuf}. Behaves similarly +to \funcname{krb5_mk_safe}, but the message is encrypted and +integrity-protected rather than just integrity-protected. + +\funcparam{inbuf}, \funcparam{auth_context}, +\funcparam{outdata} and +\funcparam{outbuf} function as in \funcname{krb5_mk_safe}. + +As in \funcname{krb5_mk_safe}, the remote_addr and remote_port part of +the \funcparam{auth_context} is optional; if the receiver's address is +not known, it may be replaced by NULL. The local_addr, however, is +mandatory. + +The encryption type is taken from the \funcparam{auth_context} keyblock +portion. If i_vector portion of the \funcparam{auth_context} +is non-null, it is used as an initialization vector for the encryption +(if the chosen encryption type supports initialization vectors) +and its contents are replaced with the last block of encrypted data +upon return. + +The flags from the \funcparam{auth_context} selects whether sequence numbers or timestamps +should be used to identify the message. Valid flags are listed below. + +\begin{tabular}{ll} +\multicolumn{1}{c}{Symbol} & Meaning \\ +KRB5_AUTH_CONTEXT_DO_TIME& Use timestamps in replay cache\\ +KRB5_AUTH_CONTEXT_RET_TIME& Use timestamps in output data\\ +KRB5_AUTH_CONTEXT_DO_SEQUENCE& Use sequence numbers\\ + &\ in replay cache\\ +KRB5_AUTH_CONTEXT_RET_SEQUENCE& Use sequence numbers\\ + &\ in replay cache and output data \\ +\end{tabular} + +Returns system errors, encryption errors. + +\begin{funcdecl}{krb5_rd_priv}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_auth_context}{auth_context} +\funcin +\funcarg{const krb5_data *}{inbuf} +\funcout +\funcarg{krb5_data *}{outbuf} +\funcarg{krb5_data *}{outdata} +\end{funcdecl} + +Parses a KRB_PRIV message from \funcparam{inbuf}, placing the data in +\funcparam{*outbuf} after decrypting it. Behaves similarly to +\funcname{krb5_rd_safe}, but the message is decrypted rather than +integrity-checked. + +\funcparam{inbuf}, \funcparam{auth_context}, +\funcparam{outdata} and \funcparam{outbuf} +function as in \funcname{krb5_rd_safe}. + + +The remote_addr part of the \funcparam{auth_context} as set by +\funcname{krb5_auth_con_setaddrs} is mandatory; it +specifies the address of the sender. If the address of the sender in +the message does not match the remote_addr, the error +KRB5KRB_AP_ERR_BADADDR will be returned. + +If local_addr portion of the auth_context is non-NULL, then the address +of the receiver in the message much match it. If it is null, the +receiver address in the message will be checked against the list of +local addresses as returned by \funcname{krb5_os_localaddr}. + +The \funcparam{keyblock} portion of \funcparam{auth_context} specifies +the key to be used for decryption of the message. If the +\funcparam{i_vector} element, is non-null, it is used as an +initialization vector for the decryption (if the encryption type of the +message supports initialization vectors) and its contents are replaced +with the last block of encrypted data in the message. + +The \funcparam{auth_context} flags specify whether timestamps +(KRB5_AUTH_CONTEXT_DO_TIME) and sequence numbers +(KRB5_AUTH_CONTEXT_DO_SEQUENCE) are to be used. + +Returns system errors, integrity errors. + +\subsubsection{Miscellaneous main functions} + +\begin{funcdecl}{krb5_address_search}{krb5_boolean}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_address *}{addr} +\funcarg{krb5_address * const *}{addrlist} +\end{funcdecl} + +If \funcparam{addr} is listed in \funcparam{addrlist}, or +\funcparam{addrlist} is null, return TRUE. If not listed, return FALSE. + +\begin{funcdecl}{krb5_address_compare}{krb5_boolean}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_address *}{addr1} +\funcarg{const krb5_address *}{addr2} +\end{funcdecl} + +If the two addresses are the same, return TRUE, else return FALSE. + +\begin{funcdecl}{krb5_fulladdr_order}{int}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_fulladdr *}{addr1} +\funcarg{const krb5_fulladdr *}{addr2} +\end{funcdecl} + +Return an ordering on the two full addresses: 0 if the same, +$< 0$ if first is less than 2nd, $> 0$ if first is greater than 2nd. + +\begin{funcdecl}{krb5_address_order}{int}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_address *}{addr1} +\funcarg{const krb5_address *}{addr2} +\end{funcdecl} + +Return an ordering on the two addresses: 0 if the same, +$< 0$ if first is less than 2nd, $> 0$ if first is greater than 2nd. + +\begin{funcdecl}{krb5_copy_addresses}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_address * const *}{inaddr} +\funcout +\funcarg{krb5_address ***}{outaddr} +\end{funcdecl} + +Copy addresses in \funcparam{inaddr} to \funcparam{*outaddr} which is +allocated memory and should be freed with \funcname{krb5_free_addresses}. + +\begin{funcdecl}{krb5_copy_authdata}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_authdata * const *}{inauthdat} +\funcout +\funcarg{krb5_authdata ***}{outauthdat} +\end{funcdecl} + +Copy an authdata structure, filling in \funcparam{*outauthdat} to point to the +newly allocated copy, which should be freed with +\funcname{krb5_free_authdata}. + +\begin{funcdecl}{krb5_copy_authenticator}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_authenticator *}{authfrom} +\funcout +\funcarg{krb5_authenticator **}{authto} +\end{funcdecl} + +Copy an authenticator structure, filling in \funcparam{*outauthdat} to +point to the newly allocated copy, which should be freed with +\funcname{krb5_free_authenticator}. + +\begin{funcdecl}{krb5_copy_keyblock}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_keyblock *}{from} +\funcout +\funcarg{krb5_keyblock **}{to} +\end{funcdecl} + +Copy a keyblock, filling in \funcparam{*to} to point to the newly +allocated copy, which should be freed with +\funcname{krb5_free_keyblock}. + +\begin{funcdecl}{krb5_copy_keyblock_contents}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_keyblock *}{from} +\funcout +\funcarg{krb5_keyblock *}{to} +\end{funcdecl} + +Copy keyblock contents from \funcparam{from} to \funcparam{to}, including +allocated storage. The allocated storage in \funcparam{to} should be +freed by using {\bf free}(\funcparam{to->contents}). + +\begin{funcdecl}{krb5_copy_checksum}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_checksum *}{ckfrom} +\funcout +\funcarg{krb5_checksum **}{ckto} +\end{funcdecl} + +Copy a checksum structure, filling in \funcparam{*ckto} to point to +the newly allocated copy, which should be freed with +\funcname{krb5_free_checksum}. + +\begin{funcdecl}{krb5_copy_creds}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_creds *}{incred} +\funcout +\funcarg{krb5_creds **}{outcred} +\end{funcdecl} + +Copy a credentials structure, filling in \funcparam{*outcred} to point +to the newly allocated copy, which should be freed with +\funcname{krb5_free_creds}. + +\begin{funcdecl}{krb5_copy_data}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_data *}{indata} +\funcout +\funcarg{krb5_data **}{outdata} +\end{funcdecl} + +Copy a data structure, filling in \funcparam{*outdata} to point to the +newly allocated copy, which should be freed with \funcname{krb5_free_data}. + +\begin{funcdecl}{krb5_copy_ticket}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_ticket *}{from} +\funcout +\funcarg{krb5_ticket **}{pto} +\end{funcdecl} + +Copy a ticket structure, filling in \funcparam{*pto} to point to +the newly allocated copy, which should be freed with +\funcname{krb5_free_ticket}. + + +\begin{funcdecl}{krb5_get_server_rcache}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const krb5_data *}{piece} +\funcout +\funcarg{krb5_rcache *}{ret_rcache} +\end{funcdecl} + +Generate a replay cache name, allocate space for its handle, and open +it. \funcparam{piece} is used to distinguish this replay cache from +others currently in use on the system. Typically, \funcparam{piece} +is the first component of the principal name for the client or server +which is calling \funcname{krb5_get_server_rcache}. + +Upon successful return, \funcparam{ret_rcache} is filled in to contain a +handle to an open rcache, which should be closed with +\funcname{krb5_rc_close}. + + diff --git a/mechglue/doc/api/krb5idx.sty b/mechglue/doc/api/krb5idx.sty new file mode 100644 index 000000000..729ed9779 --- /dev/null +++ b/mechglue/doc/api/krb5idx.sty @@ -0,0 +1,10 @@ +\usepackage{makeidx} + +% The following defintions are for our indexing scheme. Stolen from +% doc.sty. +\def\dotfill{\leaders\hbox to.6em{\hss .\hss}\hskip\z@ plus 1fill}% +\def\dotfil{\leaders\hbox to.6em{\hss .\hss}\hfil}% +\def\efill{\hfill\nopagebreak}% +\def\pfill{\unskip~\dotfill\penalty500\strut\nobreak + \dotfil~\ignorespaces}% +%% diff --git a/mechglue/doc/api/libdes.tex b/mechglue/doc/api/libdes.tex new file mode 100644 index 000000000..71e75c59b --- /dev/null +++ b/mechglue/doc/api/libdes.tex @@ -0,0 +1,38 @@ +\documentstyle[fixunder,functions,twoside]{article} +\setlength{\oddsidemargin}{0.25in} +\setlength{\evensidemargin}{-0.25in} +\setlength{\topmargin}{-.5in} +\setlength{\textheight}{9in} +\setlength{\parskip}{.1in} +\setlength{\parindent}{2em} +\setlength{\textwidth}{6.25in} + +\pagestyle{headings} +\begin{document} +\begin{center} +{\Huge Kerberos V5 Data Encryption Standard library} \\ +{\Large DRAFT} +\end{center} +\section{DES functions} +The DES functions conform to the encryption interface required by the +Kerberos version 5 library, and provide an encryption mechanism based on +the DES Cipher-block chaining mode (CBC), with the addition of a +cyclical redundancy check (CRC-32) for integrity checking upon +decryption. + +The functions have the same signatures as those described by the main +library document; the names are: +{\obeylines +\funcname{mit_des_encrypt_func} +\funcname{mit_des_decrypt_func} +\funcname{mit_des_process_key} +\funcname{mit_des_finish_key} +\funcname{mit_des_string_to_key} +\funcname{mit_des_init_random_key} +\funcname{mit_des_finish_random_key} +\funcname{mit_des_random_key} +} +The \datatype{krb5_cryptosystem_entry} for this cryptosystem is +\globalname{mit_des_cryptosystem_entry}. + +\end{document} diff --git a/mechglue/doc/api/libos.tex b/mechglue/doc/api/libos.tex new file mode 100644 index 000000000..447044fec --- /dev/null +++ b/mechglue/doc/api/libos.tex @@ -0,0 +1,486 @@ +The operating-system specific functions provide an interface between the +other parts of the \libname{libkrb5.a} libraries and the operating system. + +Beware! Any of the functions below are allowed to be implemented as +macros. Prototypes for functions can be found in {\tt +}; other definitions (including macros, if used) are +in {\tt }. + +The following global symbols are provided in \libname{libos.a}. If you +wish to substitute for any of them, you must substitute for all of them +(they are all declared and initialized in the same object file): +\begin{description} +% These come from src/lib/osconfig.c +\item[extern char *\globalname{krb5_defkeyname}:] default name of key +table file +\item[extern char *\globalname{krb5_lname_file}:] name of aname/lname +translation database +\item[extern int \globalname{krb5_max_dgram_size}:] maximum allowable +datagram size +\item[extern int \globalname{krb5_max_skdc_timeout}:] maximum +per-message KDC reply timeout +\item[extern int \globalname{krb5_skdc_timeout_shift}:] shift factor +(bits) to exponentially back-off the KDC timeouts +\item[extern int \globalname{krb5_skdc_timeout_1}:] initial KDC timeout +\item[extern char *\globalname{krb5_kdc_udp_portname}:] name of KDC UDP port +\item[extern char *\globalname{krb5_default_pwd_prompt1}:] first prompt +for password reading. +\item[extern char *\globalname{krb5_default_pwd_prompt2}:] second prompt + +\end{description} + +\subsubsection{Operating specific context} +The \datatype{krb5_context} has space for operating system specific +data. These functions are called from \funcname{krb5_init_context} and +\funcname{krb5_free_context}, but are included here for completeness. + +\begin{funcdecl}{krb5_os_init_context}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\end{funcdecl} + +\internalfunc + +Initializes \funcparam{context{\ptsto}os_context} and establishes the +location of the initial configuration files. + +\begin{funcdecl}{krb5_os_free_context}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\end{funcdecl} + +\internalfunc + +Frees the operating system specific portion of \funcparam{context}. + +\subsubsection{Configuration based functions} +These functions allow access to configuration specific information. In +some cases, the configuration may be overriden by program control. + + +\begin{funcdecl}{krb5_set_config_files}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const char **}{filenames} +\end{funcdecl} + +Sets the list of configuration files to be examined in determining +machine defaults. \funcparam{filenames} is an array of files to check in +order. The array must have a NULL entry as the last element. + +Returns system errors. + +\begin{funcdecl}{krb5_get_krbhst}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{const krb5_data *}{realm} +\funcout +\funcarg{char ***}{hostlist} +\end{funcdecl} + +Figures out the Kerberos server names for the given \funcparam{realm}, +filling in \funcparam{hostlist} with a null terminated array of +pointers to hostnames. + +If \funcparam{realm} is unknown, the filled-in pointer is set to NULL. + +The pointer array and strings pointed to are all in allocated storage, +and should be freed by the caller when finished. + +Returns system errors. + +\begin{funcdecl}{krb5_free_krbhst}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{char * const *}{hostlist} +\end{funcdecl} + +Frees the storage taken by a host list returned by \funcname{krb5_get_krbhst}. + +\begin{funcdecl}{krb5_get_default_realm}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcout +\funcarg{char **}{lrealm} +\end{funcdecl} + +Retrieves the default realm to be used if no user-specified realm is +available (e.g. to interpret a user-typed principal name with the +realm omitted for convenience), filling in \funcparam{lrealm} with a +pointer to the default realm in allocated storage. + +It is the caller's responsibility for freeing the allocated storage +pointed to be \funcparam{lream} when it is finished with it. + +Returns system errors. + +\begin{funcdecl}{krb5_set_default_realm}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{char *}{realm} +\end{funcdecl} + +Sets the default realm to be used if no user-specified realm is +available (e.g. to interpret a user-typed principal name with the +realm omitted for convenience). (c.f. krb5_get_default_realm) + +If \funcparam{realm} is NULL, then the operating system default value +will used. + +Returns system errors. + +\begin{funcdecl}{krb5_get_host_realm}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{const char *}{host} +\funcout +\funcarg{char ***}{realmlist} +\end{funcdecl} + +Figures out the Kerberos realm names for \funcparam{host}, filling in +\funcparam{realmlist} with a +pointer to an argv[] style list of names, terminated with a null pointer. + +If \funcparam{host} is NULL, the local host's realms are determined. + +If there are no known realms for the host, the filled-in pointer is set +to NULL. + +The pointer array and strings pointed to are all in allocated storage, +and should be freed by the caller when finished. + +Returns system errors. + +\begin{funcdecl}{krb5_free_host_realm}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{char * const *}{realmlist} +\end{funcdecl} + +Frees the storage taken by a \funcparam{realmlist} returned by +\funcname{krb5_get_local_realm}. + +\begin{funcdecl}{krb5_get_realm_domain}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{const char *}{realm} +\funcout +\funcarg{char **}{domain} +\end{funcdecl} + +Determines the proper name of a realm. This is mainly so that a krb4 +principal can be converted properly into a krb5 one. If +\funcparam{realm} is null, the function will assume the default realm of +the host. The returned \funcparam{*domain} is allocated and must be +freed by the caller. + +\subsubsection{Disk based functions} +These functions all relate to disk based I/O. + +\begin{funcdecl}{krb5_lock_file}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{in}{fd} +\funcarg{int}{mode} +\end{funcdecl} + +Attempts to lock the file in the given \funcparam{mode}; returns 0 for a +successful lock, or an error code otherwise. + +The caller should arrange for the file referred by \funcparam{fd} to be +opened in such a way as to allow the required lock. + +Modes are given in {\tt } + +\begin{funcdecl}{krb5_unlock_file}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{int}{fd} +\end{funcdecl} + +Attempts to (completely) unlock the file. Returns 0 if successful, +or an error code otherwise. + + +\begin{funcdecl}{krb5_create_secure_file}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{const char *}{pathname} +\end{funcdecl} + +Creates a file named pathname which can only be read by the current +user. + +\begin{funcdecl}{krb5_sync_disk_file}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{FILE *}{fp} +\end{funcdecl} + +Assures that the changes made to the file pointed to by the file +handle +fp are forced out to disk. + +\subsubsection{Network based routines} + +These routines send and receive network data the specifics +of addresses and families on a given operating system. + +\begin{funcdecl}{krb5_os_localaddr}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_address ***}{addr} +\end{funcdecl} + +Return all the protocol addresses of this host. + +Compile-time configuration flags will indicate which protocol family +addresses might be returned. +\funcparam{*addr} is filled in to point to an array of address pointers, +terminated by a null pointer. All the storage pointed to is allocated +and should be freed by the caller with \funcname{krb5_free_address} +when no longer needed. + +\begin{funcdecl}{krb5_gen_portaddr}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{const krb5_address *}{adr} +\funcarg{krb5_const_pointer}{ptr} +\funcout +\funcarg{krb5_address **}{outaddr} +\end{funcdecl} + +Given an address \funcparam{adr} and an additional address-type specific +portion pointed to by +\funcparam{port} this routine +combines them into a freshly-allocated +\datatype{krb5_address} with type \datatype{ADDRTYPE_ADDRPORT} and fills in +\funcparam{*outaddr} to point to this address. For IP addresses, +\funcparam{ptr} should point to a network-byte-order TCP or UDP port +number. Upon success, \funcparam{*outaddr} will point to an allocated +address which should be freed with \funcname{krb5_free_address}. + + +\begin{funcdecl}{krb5_sendto_kdc}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{const krb5_data *}{send} +\funcarg{const krb5_data *}{realm} +\funcout +\funcarg{krb5_data *}{receive} +\end{funcdecl} + +Send the message \funcparam{send} to a KDC for realm \funcparam{realm} and +return the response (if any) in \funcparam{receive}. + +If the message is sent and a response is received, 0 is returned, +otherwise an error code is returned. + +The storage for \funcparam{receive} is allocated and should be freed by +the caller when finished. + + +\begin{funcdecl}{krb5_net_read}{int}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{int}{fd} +\funcout +\funcarg{char *}{buf} +\funcin +\funcarg{int}{len} +\end{funcdecl} + +Like read(2), but guarantees that it reads as much as was requested +or returns -1 and sets errno. + +(make sure your sender will send all the stuff you are looking for!) +Only useful on stream sockets and pipes. + +\begin{funcdecl}{krb5_net_write}{int}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{int}{fd} +\funcarg{const char *}{buf} +\funcarg{int}{len} +\end{funcdecl} + +Like write(2), but guarantees that it writes as much as was requested +or returns -1 and sets errno. + +Only useful on stream sockets and pipes. + +\begin{funcdecl}{krb5_write_message}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_pointer}{fd} +\funcarg{krb5_data *}{data} +\end{funcdecl} + + +\funcname{krb5_write_message} writes data to the network as a message, +using the network connection pointed to by \funcparam{fd}. + +\begin{funcdecl}{krb5_read_message}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_pointer}{fd} +\funcout +\funcarg{krb5_data *}{data} +\end{funcdecl} + +Reads data from the network as a message, using the network connection +pointed to by fd. + +\subsubsection{Operating specific access functions} +These functions are involved with access control decisions and policies. + +\begin{funcdecl}{krb5_aname_to_localname}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_const_principal}{aname} +\funcarg{int}{lnsize} +\funcout +\funcarg{char *}{lname} +\end{funcdecl} + +Converts a principal name \funcparam{aname} to a local name suitable for use by +programs wishing a translation to an environment-specific name (e.g. +user account name). + +\funcparam{lnsize} specifies the maximum length name that is to be filled into +\funcparam{lname}. +The translation will be null terminated in all non-error returns. + +Returns system errors. + +\begin{funcdecl}{krb5_kuserok}{krb5_boolean}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_principal}{principal} +\funcarg{const char *}{luser} +\end{funcdecl} + +Given a Kerberos principal \funcparam{principal}, and a local username +\funcparam{luser}, +determine whether user is authorized to login to the account \funcparam{luser}. +Returns TRUE if authorized, FALSE if not authorized. + +\begin{funcdecl}{krb5_sname_to_principal}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{const char *}{hostname} +\funcarg{const char *}{sname} +\funcarg{krb5_int32}{type} +\funcout +\funcarg{krb5_principal *}{ret_princ} +\end{funcdecl} + +Given a hostname \funcparam{hostname} and a generic service name +\funcparam{sname}, this function generates a full principal name to be +used when authenticating with the named service on the host. The full +prinicpal name is returned in \funcparam{ret_princ}. + +The realm of the +principal is determined internally by calling \funcname{krb5_get_host_realm}. + +The \funcparam{type} argument controls how +\funcname{krb5_sname_to_principal} generates the principal name, +\funcparam{ret_princ}, for the named service, \funcparam{sname}. +Currently, two values are supported: KRB5_NT_SRV_HOST, and +KRB5_NT_UNKNOWN. + +If \funcparam{type} is set to +KRB5_NT_SRV_HOST, the hostname will be +canonicalized, i.e. a fully qualified lowercase hostname using +the primary name and the domain name, before \funcparam{ret_princ} is +generated in the form +"sname/hostname@LOCAL.REALM." Most applications should use +KRB5_NT_SRV_HOST. + +However, if \funcparam{type} is set to KRB5_NT_UNKNOWN, +while the generated principal name will have the form +"sname/hostname@LOCAL.REALM" the hostname will not be canonicalized +first. It will appear exactly as it was passed in \funcparam{hostname}. + +The caller should release \funcparam{ret_princ}'s storage by calling +\funcname{krb5_free_principal} when it is finished with the principal. + + + +\subsubsection{Miscellaneous operating specific functions} +These functions handle the other operating specific functions that do +not fall into any other major class. + +\begin{funcdecl}{krb5_timeofday}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_context}{context} +\funcarg{krb5_int32 *}{timeret} +\end{funcdecl} + +Retrieves the system time of day, in seconds since the local system's +epoch. +[The ASN.1 encoding routines must convert this to the standard ASN.1 +encoding as needed] + +\begin{funcdecl}{krb5_us_timeofday}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcout +\funcarg{krb5_int32 *}{seconds} +\funcarg{krb5_int32 *}{microseconds} +\end{funcdecl} + +Retrieves the system time of day, in seconds since the local system's +epoch. +[The ASN.1 encoding routines must convert this to the standard ASN.1 +encoding as needed] + +{\raggedright The seconds portion is returned in \funcparam{*seconds}, the +microseconds portion in \funcparam{*microseconds}.} + +\begin{funcdecl}{krb5_read_password}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{const char *}{prompt} +\funcarg{const char *}{prompt2} +\funcout +\funcarg{char *}{return_pwd} +\funcinout +\funcarg{unsigned int *}{size_return} +\end{funcdecl} + +Read a password from the keyboard. The first \funcparam{*size_return} +bytes of the password entered are returned in \funcparam{return_pwd}. +If fewer than \funcparam{*size_return} bytes are typed as a password, +the remainder of \funcparam{return_pwd} is zeroed. Upon success, the +total number of bytes filled in is stored in \funcparam{*size_return}. + +\funcparam{prompt} is used as the prompt for the first reading of a password. +It is printed to the terminal, and then a password is read from the +keyboard. No newline or spaces are emitted between the prompt and the +cursor, unless the newline/space is included in the prompt. + +If \funcparam{prompt2} is a null pointer, then the password is read +once. If \funcparam{prompt2} is set, then it is used as a prompt to +read another password in the same manner as described for +\funcparam{prompt}. After the second password is read, the two +passwords are compared, and an error is returned if they are not +identical. + +Echoing is turned off when the password is read. + +If there is an error in reading or verifying the password, an error code +is returned; else zero is returned. + + +\begin{funcdecl}{krb5_random_confounder}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{int}{size} +\funcout +\funcarg{krb5_pointer}{fillin} +\end{funcdecl} + +Given a length and a pointer, fills in the area pointed to by +\funcparam{fillin} with \funcparam{size} random octets suitable for use +in a confounder. + +\begin{funcdecl}{krb5_gen_replay_name}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{const krb5_address *}{inaddr} +\funcarg{const char *}{uniq} +\funcout +\funcarg{char **}{string} +\end{funcdecl} + +Given a \datatype{krb5_address} with type \datatype{ADDRTYPE_ADDRPORT} +in \funcparam{inaddr}, this function unpacks its component address and +additional type, and uses them along with \funcparam{uniq} to allocate a +fresh string to represent the address and additional information. The +string is suitable for use as a replay cache tag. This string is +allocated and should be freed with \funcname{free} when the caller has +finished using it. When using IP addresses, the components in +\funcparam{inaddr{\ptsto}contents} must be of type +\datatype{ADDRTYPE_INET} and \datatype{ADDRTYPE_PORT}. + +% XXX Note that if the bug I sent in entitled ``krb5_gen_replay_name +% outputs char * when krb5_get_server_rcache expects krb5_data'' +% (OpenVision Cambridge bug number 1582) causes the code of this +% function to change, the documentation above will have to be updated. diff --git a/mechglue/doc/api/library.tex b/mechglue/doc/api/library.tex new file mode 100644 index 000000000..713ce482f --- /dev/null +++ b/mechglue/doc/api/library.tex @@ -0,0 +1,114 @@ +\documentclass[twoside]{article} +\usepackage{fixunder,functions,fancyheadings} +\usepackage{krb5idx} +%\usepackage{hyperref} + +%\hypersetup{letterpaper, +% bookmarks=true, +%pdfpagemode=UseOutlines, +%} + +% +%\setlength{\oddsidemargin}{1in} +%\setlength{\evensidemargin}{1.00in} +%\setlength{\textwidth}{6.5in} +\setlength{\oddsidemargin}{0in} +\setlength{\evensidemargin}{1.50in} +\setlength{\textwidth}{5.25in} +\setlength{\marginparsep}{0.0in} +\setlength{\marginparwidth}{1.95 in} +\setlength{\topmargin}{-.5in} +\setlength{\textheight}{9in} +\setlength{\parskip}{.1in} +\setlength{\parindent}{2em} +\setlength{\footrulewidth}{0.4pt} +\setlength{\plainfootrulewidth}{0.4pt} +\setlength{\plainheadrulewidth}{0.4pt} +\makeindex +\newif\ifdraft +\draftfalse +% +% Far, far too inconvenient... it's still very draft-like anyway.... +% [tytso:19900921.0018EDT] +% +%\typein{Draft flag? (type \noexpand\draftfalse if not draft...)} +\ifdraft +\pagestyle{fancyplain} +\addtolength{\headwidth}{\marginparsep} +\addtolength{\headwidth}{\marginparwidth} +\makeatletter +\renewcommand{\sectionmark}[1]{\markboth {\uppercase{\ifnum \c@secnumdepth >\z@ + \thesection\hskip 1em\relax \fi #1}}{}}% +\renewcommand{\subsectionmark}[1]{\markright {\ifnum \c@secnumdepth >\@ne + \thesubsection\hskip 1em\relax \fi #1}} +\makeatother +\lhead[\thepage]{\fancyplain{}{\sl\rightmark}} +\rhead[\fancyplain{}{\sl\rightmark}]{\thepage} +\lfoot[]{{\bf DRAFT---DO NOT REDISTRIBUTE}} +\rfoot[{\bf DRAFT---DO NOT REDISTRIBUTE}]{} +\cfoot{\thepage} +\else\pagestyle{headings}\fi + +\def\internalfunc{NOTE: This is an internal function, which is not +necessarily intended for use by application programs. Its interface may +change at any time.\par} + +%nlg- time to make this a real document + +\title{\Huge Kerberos V5 application programming library} +\date{\ifdraft \\ {\Large DRAFT---}\fi\today} +\author{MIT Information Systems} + +\begin{document} +\maketitle +\tableofcontents + +%\thispagestyle{empty} +%\begin{center} +%{\Huge Kerberos V5 application programming library} +%\ifdraft \\ {\Large DRAFT---\today}\fi +%\end{center} + +\section{Introduction} +\input{intro.tex} + +\section{Useful KDC parameters to know about} +\input{tables.tex} + +\section{Error tables} +\input{errors.tex} + +%\addtolength{\oddsidemargin}{-1in} +%\addtolength{\evensidemargin}{1.00in} +%\addtolength{\textwidth}{-1.75in} +\newpage + +\section{libkrb5.a functions} +This section describes the functions provided in the \libname{libkrb5.a} +library. The library is built from several pieces, mostly for convenience in +programming, maintenance, and porting. + +\ifdraft\sloppy\fi + +\subsection{Main functions} +\input{krb5.tex} + +\subsection{Credentials cache functions} +\input{ccache.tex} + +\subsection{Replay cache functions} +\input{rcache.tex} + +\subsection{Key table functions} +\input{keytab.tex} + +\subsection{Free functions} +\input{free.tex} + +\subsection{Operating-system specific functions} +\input{libos.tex} + +\appendix +\cleardoublepage +\printindex +\end{document} diff --git a/mechglue/doc/api/rcache.tex b/mechglue/doc/api/rcache.tex new file mode 100644 index 000000000..28bad36ab --- /dev/null +++ b/mechglue/doc/api/rcache.tex @@ -0,0 +1,207 @@ +The replay cache functions deal with verifying that AP_REQ's do not +contain duplicate authenticators; the storage must be non-volatile for +the site-determined validity period of authenticators. + +Each replay cache has a string ``name'' associated with it. The use of +this name is dependent on the underlying caching strategy (for +file-based things, it would be a cache file name). The +caching strategy uses non-volatile storage so that replay +integrity can be maintained across system failures. + +\begin{funcdecl}{krb5_auth_to_rep}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcin +\funcarg{krb5_tkt_authent *}{auth} +\funcout +\funcarg{krb5_donot_replay *}{rep} +\end{funcdecl} +Extract the relevant parts of \funcparam{auth} and fill them into the +structure pointed to by \funcparam{rep}. \funcparam{rep{\ptsto}client} +and \funcparam{rep{\ptsto}server} are set to allocated storage and +should be freed when \funcparam{*rep} is no longer needed. + +\begin{funcdecl}{krb5_rc_resolve_full}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache *}{id} +\funcin +\funcarg{char *}{string_name} +\end{funcdecl} + +\begin{sloppypar} +\funcparam{id} is filled in to identify a replay cache which +corresponds to the name in \funcparam{string_name}. The cache is not opened. +Requires that \funcparam{string_name} be of the form ``type:residual'' +and that ``type'' is a type known to the library. +\end{sloppypar} + +Before the cache can be used \funcname{krb5_rc_initialize} or +\funcname{krb5_rc_recover} must be called. + +Errors: error if cannot resolve name. + + +\begin{funcdecl}{krb5_rc_resolve_type}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache *}{id} +\funcin +\funcarg{char *}{type} +\end{funcdecl} + +\internalfunc + +Looks up \funcparam{type} in the list of knows cache types and if found +attaches the operations to \funcparam{*id} which must be previously +allocated. + +If \funcparam{type} is not found, {\sc krb5_rc_type_notfound} is returned. + +\begin{funcdecl}{krb5_rc_register_type}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rc_ops *}{ops} +\end{funcdecl} +Adds a new replay cache type implemented and identified by +\funcparam{ops} to the set recognized by +\funcname{krb5_rc_resolve}. This function requires that a ticket +cache of the type named in +\funcparam{ops{\ptsto}prefix} has not been previously registered. + + +\begin{funcdecl}{krb5_rc_default_name}{char *}{\funcin} +\funcarg{krb5_context}{context} +\end{funcdecl} + +\begin{sloppypar} +Returns the name of the default replay cache; this may be equivalent to +\funcnamenoparens{getenv}({\tt "KRB5RCACHE"}) with an appropriate fallback. +\end{sloppypar} + +\begin{funcdecl}{krb5_rc_default_type}{char *}{\funcin} +\funcarg{krb5_context}{context} +\end{funcdecl} + +Returns the type of the default replay cache. + +\begin{funcdecl}{krb5_rc_default}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache *}{id} +\end{funcdecl} + +This function returns an unopened replay cache of the default type and +default name (as would be returned by \funcname{krb5_rc_default_type} +and \funcname{krb5_rc_default_name}). Before the cache can be used +\funcname{krb5_rc_initialize} or \funcname{krb5_rc_recover} must be +called. + + +\begin{funcdecl}{krb5_rc_initialize}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\funcarg{krb5_deltat}{auth_lifespan} +\end{funcdecl} + +Creates/refreshes the replay cache identified by \funcparam{id} and sets its +authenticator lifespan to \funcparam{auth_lifespan}. If the +replay cache already exists, its contents are destroyed. + +Errors: permission errors, system errors + +\begin{funcdecl}{krb5_rc_recover}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\end{funcdecl} +Attempts to recover the replay cache \funcparam{id}, (presumably after a +system crash or server restart). + +Errors: error indicating that no cache was found to recover + +\begin{funcdecl}{krb5_rc_destroy}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\end{funcdecl} + +Destroys the replay cache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + +Errors: permission errors. + +\begin{funcdecl}{krb5_rc_close}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\end{funcdecl} + +Closes the replay cache \funcparam{id}, invalidates \funcparam{id}, +and releases any other resources acquired during use of the replay cache. +Requires that \funcparam{id} identifies a valid replay cache. + +Errors: permission errors + +\begin{funcdecl}{krb5_rc_store}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\funcarg{krb5_donot_replay *}{rep} +\end{funcdecl} +Stores \funcparam{rep} in the replay cache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + +Returns KRB5KRB_AP_ERR_REPEAT if \funcparam{rep} is already in the +cache. May also return permission errors, storage failure errors. + +\begin{funcdecl}{krb5_rc_expunge}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\end{funcdecl} +Removes all expired replay information (i.e. those entries which are +older than then authenticator lifespan of the cache) from the cache +\funcparam{id}. Requires that \funcparam{id} identifies a valid replay +cache. + +Errors: permission errors. + +\begin{funcdecl}{krb5_rc_get_lifespan}{krb5_error_code}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\funcout +\funcarg{krb5_deltat *}{auth_lifespan} +\end{funcdecl} +Fills in \funcparam{auth_lifespan} with the lifespan of +the cache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + +\begin{funcdecl}{krb5_rc_resolve}{krb5_error_code}{\funcinout} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\funcin +\funcarg{char *}{name} +\end{funcdecl} + +Initializes private data attached to \funcparam{id}. This function MUST +be called before the other per-replay cache functions. + +Requires that \funcparam{id} points to allocated space, with an +initialized \funcparam{id{\ptsto}ops} field. + +Since \funcname{krb5_rc_resolve} allocates memory, +\funcname{krb5_rc_close} must be called to free the allocated memory, +even if neither \funcname{krb5_rc_initialize} or +\funcname{krb5_rc_recover} were successfully called by the application. + +Returns: allocation errors. + + +\begin{funcdecl}{krb5_rc_get_name}{char *}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\end{funcdecl} + +Returns the name (excluding the type) of the rcache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + +\begin{funcdecl}{krb5_rc_get_type}{char *}{\funcin} +\funcarg{krb5_context}{context} +\funcarg{krb5_rcache}{id} +\end{funcdecl} + +Returns the type (excluding the name) of the rcache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + + diff --git a/mechglue/doc/api/tables.tex b/mechglue/doc/api/tables.tex new file mode 100644 index 000000000..b272a07b9 --- /dev/null +++ b/mechglue/doc/api/tables.tex @@ -0,0 +1,79 @@ +The following is a list of options which can be passed to the Kerberos +server (also known as the Key Distribution Center or KDC). These +options affect what sort of tickets the KDC will return to the +application program. The KDC options can be passed to +\funcname{krb5_get_in_tkt}, \funcname{krb5_get_in_tkt_with_password}, +\funcname{krb5_get_in_tkt_with_skey}, and \funcname{krb5_send_tgs}. + + +\begin{center} +\begin{tabular}{llc} +\multicolumn{1}{c}{Symbol}&\multicolumn{1}{c}{RFC}& Valid for \\ +&\multicolumn{1}{c}{section}&get_in_tkt? \\ \hline +KDC_OPT_FORWARDABLE & 2.6 & yes \\ +KDC_OPT_FORWARDED & 2.6 & \\ +KDC_OPT_PROXIABLE & 2.5 & yes \\ +KDC_OPT_PROXY & 2.5 & \\ +KDC_OPT_ALLOW_POSTDATE & 2.4 & yes \\ +KDC_OPT_POSTDATED & 2.4 & yes \\ +KDC_OPT_RENEWABLE & 2.3 & yes \\ +KDC_OPT_RENEWABLE_OK & 2.7 & yes \\ +KDC_OPT_ENC_TKT_IN_SKEY & 2.7 & \\ +KDC_OPT_RENEW & 2.3 & \\ +KDC_OPT_VALIDATE & 2.2 & \\ +\end{tabular} +\end{center} +\label{KDCOptions} + +The following is a list of preauthentication methods which are supported +by Kerberos. Most preauthentication methods are used by +\funcname{krb5_get_in_tkt}, \funcname{krb5_get_in_tkt_with_password}, and +\funcname{krb5_get_in_tkt_with_skey}; at some sites, the Kerberos server can be +configured so that during the initial ticket transation, it will only +return encrypted tickets after the user has proven his or her identity +using a supported preauthentication mechanism. This is done to make +certain password guessing attacks more difficult to carry out. + + + +\begin{center} +\begin{tabular}{lcc} +\multicolumn{1}{c}{Symbol}&In & Valid for \\ +&RFC?&get_in_tkt? \\ \hline +KRB5_PADATA_NONE & yes & yes \\ +KRB5_PADATA_AP_REQ & yes & \\ +KRB5_PADATA_TGS_REQ & yes & \\ +KRB5_PADATA_PW_SALT & yes & \\ +KRB5_PADATA_ENC_TIMESTAMP & yes & yes \\ +KRB5_PADATA_ENC_SECURID & & yes \\ +\end{tabular} +\end{center} +\label{padata-types} + +KRB5_PADATA_TGS_REQ is rarely used by a programmer; it is used to pass +the ticket granting ticket to the Ticket Granting Service (TGS) during a +TGS transaction (as opposed to an initial ticket transaction). + +KRB5_PW_SALT is not really a preauthentication method at all. It is +passed back from the Kerberos server to application program, and it +contains a hint to the proper password salting algorithm which should be +used during the initial ticket exchange. + +%The encription type can also be specified in +%\funcname{krb5_get_in_tkt}, however normally only one keytype is used +%in any one database. +% +%\begin{center} +%\begin{tabular}{llc} +%\multicolumn{1}{c}{Symbol}&\multicolumn{1}{c}{RFC}& Supported? \\ +%& \multicolumn{1}{c}{section} & \\ \hline +%ETYPE_NULL & 6.3.1 & \\ +%ETYPE_DES_CBC_CRC & 6.3.2 & yes \\ +%ETYPE_DES_CBC_MD4 & 6.3.3 & \\ +%ETYPE_DES_CBC_MD5 & 6.3.4 & \\ +%ETYPE_RAW_DES_CBC & & yes \\ +%\end{tabular} +%\end{center} +%\label{etypes} + + diff --git a/mechglue/doc/bug-report.texinfo b/mechglue/doc/bug-report.texinfo new file mode 100644 index 000000000..9a1767d56 --- /dev/null +++ b/mechglue/doc/bug-report.texinfo @@ -0,0 +1,10 @@ +In any complex software, there will be bugs. Please send bug reports or +other problems you may uncover using the @code{krb5-send-pr} program +installed with the distribution. In case @code{krb5-send-pr} fails to +work, send bug reports to @samp{krb5-bugs@@mit.edu}. Please mention +which version of the Kerberos V5 distribution you are using, and whether +you have made any private changes. Bug reports that include proposed +fixes are especially welcome. If you do include fixes, please send them +using either context diffs or unified diffs (using @samp{diff -c} or +@samp{diff -u}, respectively). + diff --git a/mechglue/doc/build.texinfo b/mechglue/doc/build.texinfo new file mode 100644 index 000000000..0c97da4cc --- /dev/null +++ b/mechglue/doc/build.texinfo @@ -0,0 +1,1029 @@ +@value{PRODUCT} uses a configuration system built using the Free +Software Foundation's @samp{autoconf} program. This system makes +Kerberos V5 much simpler to build and reduces the amount of effort +required in porting Kerberos V5 to a new platform. + +@menu +* Organization of the Source Directory:: Description of the source tree. +* Build Requirements:: How much disk space, etc. you need to + build Kerberos. +* Unpacking the Sources:: Preparing the source tree. +* Doing the Build:: Compiling Kerberos. +* Installing the Binaries:: Installing the compiled binaries. +* Testing the Build:: Making sure Kerberos built correctly. +* Options to Configure:: Command-line options to Configure +* osconf.h:: Header file-specific configurations +* Shared Library Support:: Building Shared Libraries for Kerberos V5 +* OS Incompatibilities:: Special cases to watch for. +* Using Autoconf:: Modifying Kerberos V5's + configuration scripts. +@end menu + +@node Organization of the Source Directory, Build Requirements, Building Kerberos V5, Building Kerberos V5 +@section Organization of the Source Directory + +Below is a brief overview of the organization of the complete source +directory. More detailed descriptions follow. + +@table @b +@itemx appl +applications with @value{PRODUCT} extensions +@itemx clients +@value{PRODUCT} user programs +@itemx gen-manpages +manpages for @value{PRODUCT} and the @value{PRODUCT} login program +@itemx include +include files +@itemx kadmin +administrative interface to the Kerberos master database +@itemx kdc +the @value{PRODUCT} Authentication Service and Key Distribution Center +@itemx krb524 +utilities for converting between Kerberos 4 and Kerberos 5 +@itemx lib +libraries for use with/by @value{PRODUCT} +@itemx mac +source code for building @value{PRODUCT} on MacOS +@itemx prototype +templates for source code files +@itemx slave +utilities for propagating the database to slave KDCs +@itemx tests +test suite +@itemx util +various utilities for building/configuring the code, sending bug reports, etc. +@itemx windows +source code for building @value{PRODUCT} on Windows (see windows/README) +@end table + +@menu +* The appl Directory:: +* The clients Directory:: +* The gen-manpages Directory:: +* The include Directory:: +* The kadmin Directory:: +* The kdc Directory:: +* The krb524 Directory:: +* The lib Directory:: +* The prototype Directory:: +* The slave Directory:: +* The util Directory:: +@end menu + +@node The appl Directory, The clients Directory, Organization of the Source Directory, Organization of the Source Directory +@subsection The appl Directory + +The Kerberos release provides certain UNIX utilities, modified to use +Kerberos authentication. In the @i{appl/bsd} directory are the +Berkeley utilities @i{login}, @i{rlogin}, @i{rsh}, and @i{rcp}, as well as +the associated daemons @i{kshd} and @i{klogind}. The @i{login} program +obtains ticket-granting tickets for users upon login; the other utilities +provide authenticated Unix network services. + +The @i{appl} directory also contains Kerberized telnet and ftp programs, +as well as sample Kerberos application client and server programs. + +@node The clients Directory, The gen-manpages Directory, The appl Directory, Organization of the Source Directory +@subsection The clients Directory + +This directory contains the code for several user-oriented programs. + +@table @b +@itemx kdestroy +This program destroys the user's active Kerberos authorization tickets. +@value{COMPANY} recommends that users @code{kdestroy} before logging out. + +@itemx kinit +This program prompts users for their Kerberos principal name and password, +and attempts to get an initial ticket-granting-ticket for that principal. + +@itemx klist +This program lists the Kerberos principal and Kerberos tickets held in +a credentials cache, or the keys held in a keytab file. + +@itemx kpasswd +This program changes a user's Kerberos password. + +@itemx ksu +This program is a Kerberized version of the @code{su} program that is +meant to securely change the real and effective user ID to that of the +target user and to create a new security context. + +@itemx kvno +This program acquires a service ticket for the specified Kerberos +principals and prints out the key version numbers of each. +@end table + +@node The gen-manpages Directory, The include Directory, The clients Directory, Organization of the Source Directory +@subsection The gen-manpages Directory + +There are two manual pages in this directory. One is an introduction +to the Kerberos system. The other describes the @code{.k5login} file +which allows users to give access with their UID to other users +authenticated by the Kerberos system. + +@node The include Directory, The kadmin Directory, The gen-manpages Directory, Organization of the Source Directory +@subsection The include Directory + +This directory contains the @i{include} files needed to build the +Kerberos system. + +@node The kadmin Directory, The kdc Directory, The include Directory, Organization of the Source Directory +@subsection The kadmin Directory + +In this directory is the code for the utilities @code{kadmin}, +@code{kadmin.local}, @code{kdb5_util}, and @code{ktutil}. +@code{ktutil} is the Kerberos keytab file maintenance utility from +which a Kerberos administrator can read, write, or edit entries in a +Kerberos V5 keytab or Kerberos V4 srvtab. @code{kadmin} and +@code{kadmin.local} are command-line interfaces to the Kerberos V5 KADM5 +administration system. @code{kadmin.local} runs on the master KDC and +does not use Kerberos to authenticate to the database, while +@code{kadmin} uses Kerberos authentication and an encrypted RPC. The +two provide identical functionalities, which allow administrators to +modify the database of Kerberos principals. @code{kdb5_util} allows +administrators to perform low-level maintenance procedures on Kerberos +and the KADM5 database. With this utility, databases can be created, +destroyed, or dumped to and loaded from ASCII files. It can also be +used to create master key stash files. + +@node The kdc Directory, The krb524 Directory, The kadmin Directory, Organization of the Source Directory +@subsection The kdc Directory + +This directory contains the code for the @code{krb5kdc} daemon, the +Kerberos Authentication Service and Key Distribution Center. + +@node The krb524 Directory, The lib Directory, The kdc Directory, Organization of the Source Directory +@subsection The krb524 Directory + +This directory contains the code for @code{krb524}, a service that +converts Kerberos V5 credentials into Kerberos V4 credentials suitable +for use with applications that for whatever reason do not use V5 +directly. + +@node The lib Directory, The prototype Directory, The krb524 Directory, Organization of the Source Directory +@subsection The lib Directory + +The @i{lib} directory contain 10 subdirectories as well as some +definition and glue files. The @i{crypto} subdirectory contains the +Kerberos V5 encryption library. The @i{des425} subdirectory exports +the Kerberos V4 encryption API, and translates these functions into +calls to the Kerberos V5 encryption API. The @i{gssapi} library +contains the Generic Security Services API, which is a library of +commands to be used in secure client-server communication. The +@i{kadm5} directory contains the libraries for the KADM5 administration +utilities. The Kerberos 5 database libraries are contained in +@i{kdb}. The directories @i{krb4} and @i{krb5} contain the Kerberos 4 +and Kerberos 5 APIs, respectively. The @i{rpc} directory contains the +API for the Kerberos Remote Procedure Call protocol. + +@node The prototype Directory, The slave Directory, The lib Directory, Organization of the Source Directory +@subsection The prototype Directory + +This directory contains several template files. The @code{prototype.h} +and @code{prototype.c} files contain the MIT copyright message and a +placeholder for the title and description of the file. +@code{prototype.h} also has a short template for writing @code{ifdef} +and @code{ifndef} preprocessor statements. The @code{getopt.c} file +provides a template for writing code that will parse the options with +which a program was called. + +@node The slave Directory, The util Directory, The prototype Directory, Organization of the Source Directory +@subsection The slave Directory + +This directory contains code which allows for the propagation of the +Kerberos principal database from the master KDC to slave KDCs over an +encrypted, secure channel. @code{kprop} is the program which actually +propagates the database dump file. @code{kpropd} is the Kerberos V5 +slave KDC update server which accepts connections from the @code{kprop} +program. @code{kslave_update} is a script that takes the name of a +slave server, and propagates the database to that server if the +database has been modified since the last dump or if the database has +been dumped since the last propagation. + +@node The util Directory, , The slave Directory, Organization of the Source Directory +@subsection The util Directory + +This directory contains several utility programs and libraries. The +programs used to configure and build the code, such as @code{autoconf}, +@code{lndir}, @code{kbuild}, @code{reconf}, and @code{makedepend}, +are in this directory. The @i{profile} directory contains most of the +functions which parse the Kerberos configuration files (@code{krb5.conf} +and @code{kdc.conf}). Also in this directory are the Kerberos error table +library and utilities (@i{et}), the Sub-system library and utilities +(@i{ss}), database utilities (@i{db2}), pseudo-terminal utilities +(@i{pty}), bug-reporting program @code{send-pr}, and a generic +support library @code{support} used by several of our other libraries. + +@node Build Requirements, Unpacking the Sources, Organization of the Source Directory, Building Kerberos V5 +@section Build Requirements + +In order to build Kerberos V5, you will need approximately 60-70 +megabytes of disk space. The exact amount will vary depending on the +platform and whether the distribution is compiled with debugging symbol +tables or not. + +Your C compiler must conform to ANSI C (ISO/IEC 9899:1990, ``c89''). +Some operating systems do not have an ANSI C compiler, or their +default compiler requires extra command-line options to enable ANSI C +conformance. + +If you wish to keep a separate @dfn{build tree}, which contains the compiled +@file{*.o} file and executables, separate from your source tree, you +will need a @samp{make} program which supports @samp{VPATH}, or +you will need to use a tool such as @samp{lndir} to produce a symbolic +link tree for your build tree. + +@c Library support... + +@node Unpacking the Sources, Doing the Build, Build Requirements, Building Kerberos V5 +@section Unpacking the Sources + +The first step in each of these build procedures is to unpack the +source distribution. The Kerberos V5 distribution comes in a tar file, +generally named @file{krb5-@value{RELEASE}.tar}, which contains a +compressed tar file consisting of the sources for all of Kerberos +(generally @file{krb5-@value{RELEASE}.tar.gz}) and a PGP signature for +this source tree (generally @file{krb5-@value{RELEASE}.tar.gz.asc}). +@value{COMPANY} highly recommends that you verify the integrity of the +source code using this signature. + +Unpack the compressed tar file in some directory, such as +@file{/u1/krb5-@value{RELEASE}}. (In the rest of this document, we +will assume that you have chosen to unpack the Kerberos V5 source +distribution in this directory. Note that the tarfiles will by default +all unpack into the @file{./krb5-@value{RELEASE}} directory, so that if +your current directory is @file{/u1} when you unpack the tarfiles, you +will get @file{/u1/krb5-@value{RELEASE}/src}, etc.) + + +@node Doing the Build, Installing the Binaries, Unpacking the Sources, Building Kerberos V5 +@section Doing the Build + +You have a number of different options in how to build Kerberos. If you +only need to build Kerberos for one platform, using a single directory +tree which contains both the source files and the object files is the +simplest. However, if you need to maintain Kerberos for a large number +of platforms, you will probably want to use separate build trees for +each platform. We recommend that you look at @ref{OS +Incompatibilities}, for notes that we have on particular operating +systems. + +@menu +* Building Within a Single Tree:: +* Building with Separate Build Directories:: +* Building using lndir:: +@end menu + +@node Building Within a Single Tree, Building with Separate Build Directories, Doing the Build, Doing the Build +@subsection Building Within a Single Tree + +If you don't want separate build trees for each architecture, then +use the following abbreviated procedure. + +@enumerate +@item + @code{cd /u1/krb5-@value{RELEASE}/src} +@item + @code{./configure} +@item + @code{make} +@end enumerate + +That's it! + +@node Building with Separate Build Directories, Building using lndir, Building Within a Single Tree, Doing the Build +@subsection Building with Separate Build Directories + +If you wish to keep separate build directories for each platform, you +can do so using the following procedure. (Note, this requires that your +@samp{make} program support @samp{VPATH}. GNU's make will provide this +functionality, for example.) If your @samp{make} program does not +support this, see the next section. + +For example, if you wish to create a build directory for @code{pmax} binaries +you might use the following procedure: + +@enumerate +@item +@code{mkdir /u1/krb5-@value{RELEASE}/pmax} +@item + @code{cd /u1/krb5-@value{RELEASE}/pmax} +@item + @code{../src/configure} +@item + @code{make} +@end enumerate + +@node Building using lndir, , Building with Separate Build Directories, Doing the Build +@subsection Building Using @samp{lndir} + +If you wish to keep separate build directories for each platform, and +you do not have access to a @samp{make} program which supports @samp{VPATH}, +all is not lost. You can use the @samp{lndir} program to create +symbolic link trees in your build directory. + +For example, if you wish to create a build directory for solaris binaries +you might use the following procedure: + +@enumerate +@item + @code{mkdir /u1/krb5-@value{RELEASE}/solaris} +@item + @code{cd /u1/krb5-@value{RELEASE}/solaris} +@item + @code{/u1/krb5-@value{RELEASE}/src/util/lndir `pwd`/../src} +@item + @code{./configure} +@item + @code{make} +@end enumerate + +You must give an absolute pathname to @samp{lndir} because it has a bug that +makes it fail for relative pathnames. Note that this version differs +from the latest version as distributed and installed by the XConsortium +with X11R6. Either version should be acceptable. + +@node Installing the Binaries, Testing the Build, Doing the Build, Building Kerberos V5 +@section Installing the Binaries + +Once you have built Kerberos, you should install the binaries. You +can do this by running: + +@example +% make install +@end example + +If you want to install the binaries into a destination directory that +is not their final destination, which may be convenient if you want to +build a binary distribution to be deployed on multiple hosts, you may +use: + +@example +% make install DESTDIR=/path/to/destdir +@end example + +This will install the binaries under @code{DESTDIR/PREFIX}, e.g., the +user programs will install into @code{DESTDIR/PREFIX/bin}, the +libraries into @code{DESTDIR/PREFIX/lib}, etc. + +Note that if you want to test the build (see @ref{Testing the Build}), +you usually do not need to do a @code{make install} first. + +Some implementations of @samp{make} allow multiple commands to be run in +parallel, for faster builds. We test our Makefiles in parallel builds with +GNU @samp{make} only; they may not be compatible with other parallel build +implementations. + +@node Testing the Build, Options to Configure, Installing the Binaries, Building Kerberos V5 +@section Testing the Build + +The Kerberos V5 distribution comes with built-in regression tests. To +run them, simply type the following command while in the top-level build +directory (i.e., the directory where you sent typed @samp{make} to start +building Kerberos; see @ref{Doing the Build}.): + +@example +% make check +@end example + +@menu +* The DejaGnu Tests:: +* The KADM5 Tests:: +@end menu + +@node The DejaGnu Tests, The KADM5 Tests, Testing the Build, Testing the Build +@subsection The DejaGnu Tests + +Some of the built-in regression tests are setup to use the DejaGnu +framework for running tests. These tests tend to be more comprehensive +than the normal built-in tests as they setup test servers and test +client/server activities. + +DejaGnu may be found wherever GNU software is archived. + +Most of the tests are setup to run as a non-privileged user. For some +of the krb-root tests to work properly, either (a) the user running the +tests must not have a .k5login file in the home directory or (b) the +.k5login file must contain an entry for @code{@@KRBTEST.COM}. +There are two series of tests (@samp{rlogind} and @samp{telnetd}) which +require the ability to @samp{rlogin} as root to the local +machine. Admittedly, this does require the use of a @file{.rhosts} file +or some authenticated means. @footnote{If you are fortunate enough to +have a previous version of Kerberos V5 or V4 installed, and the Kerberos +rlogin is first in your path, you can setup @file{.k5login} or +@file{.klogin} respectively to allow you access.} + +If you cannot obtain root access to your machine, all the other tests +will still run. Note however, with DejaGnu 1.2, the "untested testcases" +will cause the testsuite to exit with a non-zero exit status which +@samp{make} will consider a failure of the testing process. Do not worry +about this, as these tests are the last run when @samp{make check} is +executed from the top level of the build tree. This problem does not +exist with DejaGnu 1.3. + +@node The KADM5 Tests, , The DejaGnu Tests, Testing the Build +@subsection The KADM5 Tests + +Regression tests for the KADM5 system, including the GSS-RPC, KADM5 +client and server libraries, and kpasswd, are also included in this +release. Each set of KADM5 tests is contained in a sub-directory called +@code{unit-test} directly below the system being tested. For example, +lib/rpc/unit-test contains the tests for GSS-RPC. The tests are all +based on DejaGnu (but they are not actually called part of "The DejaGnu +tests," whose naming predates the inclusion of the KADM5 system). In +addition, they require the Tool Command Language (TCL) header files and +libraries to be available during compilation and some of the tests also +require Perl in order to operate. If all of these resources are not +available during configuration, the KADM5 tests will not run. The TCL +installation directory can be specified with the @code{--with-tcl} +configure option. (See @xref{Options to Configure}.) The runtest and +perl programs must be in the current execution path. + +If you install DejaGnu, TCL, or Perl after configuring and building +Kerberos and then want to run the KADM5 tests, you will need to +re-configure the tree and run @code{make} at the top level again to make +sure all the proper programs are built. To save time, you actually only +need to reconfigure and build in the directories src/kadmin/testing, +src/lib/rpc, src/lib/kadm5. + +@node Options to Configure, osconf.h, Testing the Build, Building Kerberos V5 +@section Options to Configure + +There are a number of options to @samp{configure} which you can use to +control how the Kerberos distribution is built. The following table +lists the most commonly used options to Kerberos V5's @samp{configure} +program. + +@table @code + +@item --help + +Provides help to configure. This will list the set of commonly used +options for building Kerberos. + +@item --prefix=PREFIX + +By default, Kerberos will install the package's files rooted at +`/usr/local' as in `/usr/local/bin', `/usr/local/sbin', etc. If you +desire a different location, use this option. + +@item --exec-prefix=EXECPREFIX + +This option allows one to separate the architecture independent programs +from the configuration files and manual pages. + +@item --localstatedir=LOCALSTATEDIR + +This option sets the directory for locally modifiable single-machine +data. In Kerberos, this mostly is useful for setting a location for the +KDC data files, as they will be installed in +@code{LOCALSTATEDIR/krb5kdc}, which is by default +@code{PREFIX/var/krb5kdc}. + +@item CC=COMPILER + +Use @code{COMPILER} as the C compiler. + +@item CFLAGS=FLAGS + +Use @code{FLAGS} as the default set of C compiler flags. + +Note that if you use the native Ultrix compiler on a +DECstation you are likely to lose if you pass no flags to cc; md4.c +takes an estimated 3,469 billion years to compile if you provide neither +the @samp{-g} flag nor the @samp{-O} flag to @samp{cc}. + +@item CPPFLAGS=CPPOPTS + +Use @code{CPPOPTS} as the default set of C preprocessor flags. The most +common use of this option is to select certain @code{#define}'s for use +with the operating system's include files. + +@item LD=LINKER + +Use @code{LINKER} as the default loader if it should be different from C +compiler as specified above. + +@item LDFLAGS=LDOPTS + +This option allows one to specify optional arguments to be passed to the +linker. This might be used to specify optional library paths. + +@item --with-krb4 + +This option enables Kerberos V4 backwards compatibility using the +builtin Kerberos V4 library. + +@item --with-krb4=KRB4DIR + +This option enables Kerberos V4 backwards compatibility using a +pre-existing Kerberos V4 installation. The directory specified by +@code{KRB4DIR} specifies where the V4 header files should be found +(@file{KRB4DIR/include}) as well as where the V4 Kerberos library should +be found (@file{KRB4DIR/lib}). + +@item --without-krb4 + +Disables Kerberos V4 backwards compatibility. This prevents Kerberos V4 +clients from using the V5 services including the KDC. This would be +useful if you know you will never install or need to interact with V4 +clients. + +@item --with-netlib[=libs] + +Allows for suppression of or replacement of network libraries. By +default, Kerberos V5 configuration will look for @code{-lnsl} and +@code{-lsocket}. If your operating system has a broken resolver library +(see @ref{Solaris versions 2.0 through 2.3}) or fails to pass the tests in +@file{src/tests/resolv} you will need to use this option. + +@item --with-tcl=TCLPATH + +Some of the unit-tests in the build tree rely upon using a program in +Tcl. The directory specified by @code{TCLPATH} specifies where the Tcl +header file (@file{TCLPATH/include/tcl.h} as well as where the Tcl +library should be found (@file{TCLPATH/lib}). + +@item --enable-shared + +This option will turn on the building and use of shared library objects +in the Kerberos build. This option is only supported on certain +platforms. + +@item --enable-dns +@item --enable-dns-for-kdc +@item --enable-dns-for-realm + +Enable the use of DNS to look up a host's Kerberos realm, or a realm's +KDCs, if the information is not provided in krb5.conf. See @ref{Hostnames +for the Master and Slave KDCs} for information about using DNS to +locate the KDCs, and @ref{Mapping Hostnames onto Kerberos Realms} for +information about using DNS to determine the default realm. By default, +DNS lookups are enabled for the former but not for the latter. + +@item --enable-kdc-replay-cache + +Enable a cache in the KDC to detect retransmitted messages, and resend +the previous responses to them. This protects against certain types of +attempts to extract information from the KDC through some of the +hardware preauthentication systems. + +@item --with-system-et + +Use an installed version of the error-table support software, the +@samp{compile_et} program, the @file{com_err.h} header file and the +@file{com_err} library. If these are not in the default locations, +you may wish to specify @code{CPPFLAGS=-I/some/dir} and +@code{LDFLAGS=-L/some/other/dir} options at configuration time as +well. + +If this option is not given, a version supplied with the Kerberos +sources will be built and installed along with the rest of the +Kerberos tree, for Kerberos applications to link against. + +@item --with-system-ss + +Use an installed version of the subsystem command-line interface +software, the @samp{mk_cmds} program, the @file{ss/ss.h} header file +and the @file{ss} library. If these are not in the default locations, +you may wish to specify @code{CPPFLAGS=-I/some/dir} and +@code{LDFLAGS=-L/some/other/dir} options at configuration time as +well. See also the @samp{SS_LIB} option. + +If this option is not given, the @file{ss} library supplied with the +Kerberos sources will be compiled and linked into those programs that +need it; it will not be installed separately. + +@item SS_LIB=libs... + +If @samp{-lss} is not the correct way to link in your installed +@file{ss} library, for example if additional support libraries are +needed, specify the correct link options here. Some variants of this +library are around which allow for Emacs-like line editing, but +different versions require different support libraries to be +explicitly specified. + +This option is ignored if @samp{--with-system-ss} is not specified. + +@item --with-system-db + +Use an installed version of the Berkeley DB package, which must +provide an API compatible with version 1.85. This option is +@emph{unsupported} and untested. In particular, we do not know if the +database-rename code used in the dumpfile load operation will behave +properly. + +If this option is not given, a version supplied with the Kerberos +sources will be built and installed. (We are not updating this +version at this time because of licensing issues with newer versions +that we haven't investigated sufficiently yet.) + +@item DB_HEADER=headername.h + +If @samp{db.h} is not the correct header file to include to compile +against the Berkeley DB 1.85 API, specify the correct header file name +with this option. For example, @samp{DB_HEADER=db3/db_185.h}. + +@item DB_LIB=libs... + +If @samp{-ldb} is not the correct library specification for the +Berkeley DB library version to be used, override it with this option. +For example, @samp{DB_LIB=-ldb-3.3}. + +@end table + +For example, in order to configure Kerberos on a Solaris machine using +the @samp{suncc} compiler with the optimizer turned on, run the configure +script with the following options: + +@example +% ./configure CC=suncc CFLAGS=-O +@end example + +For a slightly more complicated example, consider a system where +several packages to be used by Kerberos are installed in +@samp{/usr/foobar}, including Berkeley DB 3.3, and an @samp{ss} +library that needs to link against the @samp{curses} library. The +configuration of Kerberos might be done thus: + +@example +% ./configure CPPFLAGS=-I/usr/foobar/include LDFLAGS=-L/usr/foobar/lib \ + --with-system-et --with-system-ss --with-system-db \ + SS_LIB='-lss -lcurses' \ + DB_HEADER=db3/db_185.h DB_LIB=-ldb-3.3 +@end example + +In previous releases, @code{--with-} options were used to specify the +compiler and linker and their options. + +@node osconf.h, Shared Library Support, Options to Configure, Building Kerberos V5 +@section @file{osconf.h} + +There is one configuration file which you may wish to edit to control +various compile-time parameters in the Kerberos distribution: +@file{include/krb5/stock/osconf.h}. The list that follows is by no means +complete, just some of the more interesting variables. + +Please note: The former configuration file @file{config.h} no longer +exists as its functionality has been merged into the auto-configuration +process. @xref{Options to Configure}. + + +@table @code + +@item DEFAULT_PROFILE_PATH + +The pathname to the file which contains the profiles for the known realms, +their KDCs, etc. The default value is @value{DefaultDefaultProfilePath}. + +The profile file format is no longer the same format as Kerberos V4's +@file{krb.conf} file. + +@item DEFAULT_KEYTAB_NAME + +The type and pathname to the default server keytab file (the +equivalent of Kerberos V4's @file{/etc/srvtab}). The default is +@value{DefaultDefaultKeytabName}. + +@item DEFAULT_KDC_ENCTYPE + +The default encryption type for the KDC. The default value is +@value{DefaultMasterKeyType}. + +@item KDCRCACHE + +The name of the replay cache used by the KDC. The default value is +@value{DefaultKDCRCache}. + +@item RCTMPDIR + +The directory which stores replay caches. The default is to try +@value{DefaultRCTmpDirs}. + +@item DEFAULT_KDB_FILE + +The location of the default database. The default value is +@value{DefaultDatabaseName}. + +@end table + +@node Shared Library Support, OS Incompatibilities, osconf.h, Building Kerberos V5 +@section Shared Library Support + +Shared library support is provided for a few operating systems. There +are restrictions as to which compiler to use when using shared +libraries. In all cases, executables linked with the shared libraries in +this build process will have built in the location of the libraries, +therefore obliterating the need for special LD_LIBRARY_PATH, et al environment +variables when using the programs. Except where noted, multiple versions +of the libraries may be installed on the same system and continue to +work. + +Currently the supported platforms are Solaris 2.6-2.9 (aka SunOS +5.6-5.9), Irix 6.5, Redhat Linux, MacOS 8-10, and Microsoft Windows +(using DLLs). + +Shared library support has been tested on the following platforms but +not exhaustively (they have been built but not necessarily tested in an +installed state): Tru64 (aka Alpha OSF/1 or Digital Unix) 4.0, and +HP/UX 10.20. + +Platforms for which there is shared library support but not significant +testing include FreeBSD, OpenBSD, AIX (4.3.3), Linux, NetBSD 1.4.x +(i386), and SunOS 4.x. + +To enable shared libraries on the above platforms, run the configure +script with the option @samp{--enable-shared}. + +@ifset notdef + +XXX What does this mean? + +One special note is that if the Kerberos V4 compatibility is compiled +in, you @b{must not} specify an alternate Kerberos V4 library from the +one in the tree or you will be missing references. + +@end ifset + +@node OS Incompatibilities, Using Autoconf, Shared Library Support, Building Kerberos V5 +@section Operating System Incompatibilities + +This section details operating system incompatibilities with Kerberos V5 +which have been reported to the developers at MIT. If you find +additional incompatibilities, and/or discover workarounds to such +problems, please send a report via the @code{krb5-send-pr} program. +Thanks! + +@menu +* AIX:: +* Alpha OSF/1 V1.3:: +* Alpha OSF/1 V2.0:: +* Alpha OSF/1 V4.0:: +* BSDI:: +* HPUX:: +* Solaris versions 2.0 through 2.3:: +* Solaris 2.X:: +* Solaris 9:: +* SGI Irix 5.X:: +* Ultrix 4.2/3:: +@end menu + +@node AIX, Alpha OSF/1 V1.3, OS Incompatibilities, OS Incompatibilities +@subsection AIX + +The AIX 3.2.5 linker dumps core trying to build a shared +@samp{libkrb5.a} produced with the GNU C compiler. The native AIX +compiler works fine. This problem is fixed using the AIX 4.1 linker. + +@node Alpha OSF/1 V1.3, Alpha OSF/1 V2.0, AIX, OS Incompatibilities +@subsection Alpha OSF/1 V1.3 + +Using the native compiler, compiling with the @samp{-O} compiler flag +causes the @code{asn.1} library to be compiled incorrectly. + +Using GCC version 2.6.3 or later instead of the native compiler will also work +fine, both with or without optimization. + +@node Alpha OSF/1 V2.0, Alpha OSF/1 V4.0, Alpha OSF/1 V1.3, OS Incompatibilities +@subsection Alpha OSF/1 V2.0 + +There used to be a bug when using the native compiler in compiling +@file{md4.c} when compiled without either the @samp{-O} or @samp{-g} +compiler options. We have changed the code and there is no problem +under V2.1, but we do not have access to V2.0 to test and see if the +problem would exist there. (We welcome feedback on this issue). There +was never a problem in using GCC version 2.6.3. + +In version 3.2 and beyond of the operating system, we have not seen +this sort of problem with the native compiler. + +@node Alpha OSF/1 V4.0, BSDI, Alpha OSF/1 V2.0, OS Incompatibilities +@subsection Alpha OSF/1 (Digital UNIX) V4.0 + +The C compiler provided with Alpha OSF/1 V4.0 (a.k.a. Digital UNIX) +defaults to an extended K&R C mode, not ANSI C. You need to provide +the @samp{-std} argument to the compiler (i.e., @samp{./configure +CC='cc -std'}) to enable extended ANSI C mode. More recent versions +of the operating system, such as 5.0, seem to have C compilers which +default to @samp{-std}. + +@c @node Alpha Tru64 UNIX 5.0 +@c @subsection Alpha Tru64 UNIX 5.0 +@c ... login.krb5 problems + +@node BSDI, HPUX, Alpha OSF/1 V4.0, OS Incompatibilities +@subsection BSDI + +BSDI versions 1.0 and 1.1 reportedly has a bad @samp{sed} which causes +it to go into an infinite loop during the build. The work around is +to use a @samp{sed} from somewhere else, such as GNU. (This may be +true for some versions of other systems derived from BSD 4.4, such as +NetBSD and FreeBSD.) + +@node HPUX, Solaris versions 2.0 through 2.3, BSDI, OS Incompatibilities +@subsection HPUX + +The native (bundled) compiler for HPUX currently will not work, +because it is not a full ANSI C compiler. The optional ANSI C +compiler should work as long as you give it the @samp{-Ae} flag +(i.e. @samp{./configure CC='cc -Ae'}). This is equivalent to +@samp{./configure CC='c89 -D_HPUX_SOURCE'}, which was the previous +recommendation. This has only been tested recently for HPUX 10.20. + +You will need to configure with @samp{--disable-shared +--enable-static}, because as of 1.4 we don't have support for HPUX +shared library finalization routines, nor the option (yet) to ignore +that lack of support (which means repeated +@code{dlopen}/@code{dlclose} cycles on the Kerberos libraries may not +be safe) and build the shared libraries anyways. + +You will also need to configure the build tree with +@samp{--disable-thread-support} if you are on HPUX 10 and do not have +the DCE development package installed, because that's where the +@code{pthread.h} header file is found. (We don't know if our code +will work with such a package installed, because according to some HP +documentation, their @code{pthread.h} has to be included before any +other header files, and our code doesn't do that.) + +If you use GCC, it may work, but some versions of GCC have omitted +certain important preprocessor defines, like @code{__STDC_EXT__} and +@code{__hpux}. + +@node Solaris versions 2.0 through 2.3, Solaris 2.X, HPUX, OS Incompatibilities +@subsection Solaris versions 2.0 through 2.3 + +The @code{gethostbyname()} routine is broken; it does not return a fully +qualified domain name, even if you are using the Domain Name Service +routines. Since Kerberos V5 uses the fully qualified domain name as the +second component of a service principal (i.e, +@samp{host/tsx-11.mit.edu@@ATHENA.MIT.EDU}), this causes problems for servers +who try to figure out their own fully qualified domain name. + +Workarounds: + +@enumerate + +@item + Supply your own resolver library. (such as bind-4.9.3pl1 available +from ftp.vix.com) + +@item + Upgrade to Solaris 2.4 + +@item + Make sure your /etc/nsswitch.conf has `files' before `dns' like: + +@example +hosts: files dns +@end example + +and then in /etc/hosts, make sure there is a line with your +workstation's IP address and hostname, with the fully qualified domain +name first. Example: + +@example +18.172.1.4 dcl.mit.edu dcl +@end example + +Note that making this change may cause other programs in your +environment to break or behave differently. + +@end enumerate + +@node Solaris 2.X, Solaris 9, Solaris versions 2.0 through 2.3, OS Incompatibilities +@subsection Solaris 2.X + +You @b{must} compile Kerberos V5 without the UCB compatibility +libraries. This means that @file{/usr/ucblib} must not be in the +LD_LIBRARY_PATH environment variable when you compile it. Alternatively +you can use the @code{-i} option to @samp{cc}, by using the specifying +@code{CFLAGS=-i} option to @samp{configure}. + +If you are compiling for a 64-bit execution environment, you may need +to configure with the option @code{CFLAGS="-D_XOPEN_SOURCE=500 +-D__EXTENSIONS__"}. This is not well tested; at MIT we work primarily +with the 32-bit execution environment. + +@node Solaris 9, SGI Irix 5.X, Solaris 2.X, OS Incompatibilities +@subsection Solaris 9 + +Solaris 9 has a kernel race condition which causes the final output +written to the slave side of a pty to be lost upon the final close() +of the slave device. This causes the dejagnu-based tests to fail +intermittently. A workaround exists, but requires some help from the +scheduler, and the ``make check'' must be executed from a shell with +elevated priority limits. + +Run something like + +@code{priocntl -s -c FX -m 30 -p 30 -i pid nnnn} + +as root, where @code{nnnn} is the pid of the shell whose priority +limit you wish to raise. + +Sun has released kernel patches for this race condition. Apply patch +117171-11 for sparc, or patch 117172-11 for x86. Later revisions of +the patches should also work. It is not necessary to run ``make +check'' from a shell with elevated priority limits once the patch has +been applied. + +@node SGI Irix 5.X, Ultrix 4.2/3, Solaris 9, OS Incompatibilities +@subsection SGI Irix 5.X + +If you are building in a tree separate from the source tree, the vendors +version of make does not work properly with regards to +@samp{VPATH}. It also has problems with standard inference rules in 5.2 +(not tested yet in 5.3) so one needs to use GNU's make. + +Under 5.2, there is a bug in the optional System V @code{-lsocket} +library in which the routine @code{gethostbyname()} is broken. The +system supplied version in @code{-lc} appears to work though so one may +simply specify @code{--with-netlib} option to @samp{configure}. + +In 5.3, @code{gethostbyname()} is no longer present in @code{-lsocket} and +is no longer an issue. + +@node Ultrix 4.2/3, , SGI Irix 5.X, OS Incompatibilities +@subsection Ultrix 4.2/3 + +The DEC MIPS platform currently will not support the native compiler, +since the Ultrix compiler is not a full ANSI C compiler. You should use +GCC instead. + +@ifset notdef + +On the DEC MIPS platform, using the native compiler, @file{md4.c} and +@file{md5.c} can not be compiled with the optimizer set at level 1. +That is, you must specify either @samp{CFLAGS=-O} and +@samp{CFLAGS=-g} to configure. If you don't specify either, the +compile will never complete. + +The optimizer isn't hung; it just takes an exponentially long time. +Compiling 6 out of the 48 algorithmic steps takes 3 seconds; compiling 7 +steps takes 9 seconds; compiling 8 steps takes 27 seconds, and so on. +Calculations estimate it will finish in approximately 3,469 billion +years.... + +Using GCC instead of the native compiler will also work fine, both with +or without optimization. + +@end ifset + +@node Using Autoconf, , OS Incompatibilities, Building Kerberos V5 +@section Using @samp{Autoconf} + +(If you are not a developer, you can skip this section.) + +In most of the Kerberos V5 source directories, there is a +@file{configure} script which automatically determines the compilation +environment and creates the proper Makefiles for a particular +platform. These @file{configure} files are generated using +@samp{autoconf}, which can be found in the @file{src/util/autoconf} +directory in the distribution. + +Normal users will not need to worry about running @samp{autoconf}; the +distribution comes with the @file{configure} files already prebuilt. +Developers who wish to modify the @file{configure.in} files should see +@ref{Top, , Overview, autoconf, The Autoconf Manual}. + +Note that in order to run @samp{autoconf}, you must have GNU @samp{m4} +in your path. Before you use the @samp{autoconf} in the Kerberos V5 +source tree, you may also need to run @samp{configure}, and then run +@samp{make} in the @file{src/util/autoconf} directory in order to +properly set up @samp{autoconf}. + +One tool which is provided for the convenience of developers can be +found in @file{src/util/reconf}. This program should be run while the +current directory is the top source directory. It will automatically +rebuild any @file{configure} files which need rebuilding. If you know +that you have made a change that will require that all the +@file{configure} files need to be rebuilt from scratch, specify the +@code{--force} option: + +@example +% cd /u1/krb5-@value{RELEASE}/src +% ./util/reconf --force +@end example + +The developmental sources are a raw source tree (before it's been packaged +for public release), without the pre-built @file{configure} files. +In order to build from such a source tree, you must do: + +@example +% cd krb5/util/autoconf +% ./configure +% make +% cd ../.. +% util/reconf +@end example + +Then follow the instructions for building packaged source trees (above). +To install the binaries into a binary tree, do: + +@example +% cd /u1/krb5-@value{RELEASE}/src +% make all +% make install DESTDIR=somewhere-else +@end example + diff --git a/mechglue/doc/coding-style b/mechglue/doc/coding-style new file mode 100644 index 000000000..87a918f64 --- /dev/null +++ b/mechglue/doc/coding-style @@ -0,0 +1,563 @@ +WRITING C CODE +============== + +The code in the krb5 source tree largely follows BSD KNF +(/usr/share/misc/style on NetBSD) except that it uses a four column +basic offset. The style described here is a synthesis of BSD KNF and +the GNU coding standards for the C language. The formatting described +in the "Formatting Your Source Code" section of the GNU coding +standards is mostly what we want, except we use BSD brace style and +BSD-ish conventions for the spacing around operators. + +Formatting style for C code +--------------------------- + +In general, use a four column basic offset, tab stops at eight +columns. Indents should be tabified, i.e. continuous tabs followed by +spaces if necessary if the indent isn't a multiple of eight columns. +The "bsd" style in emacs cc-mode mostly does the right thing. You can +use "M-x c-set-style" "bsd" to get this. Alternatively, you can use +the "krb5" style that is included here. + +Labels, including case labels, are outdented by four columns. +Continuations of statements are indented by an additional four +columns. When continuing expressions this way, split the expression +so that the newline goes before a binary operator rather than after +it. + +Continuations of argument lists or parenthesized expressions should +line up with the column after the opening parenthesis. Note that this +may create width problems if you call a fuction deep in a bunch of +nested control flow statements. Regardless, any expression split +between lines should stil be split so that the newline goes before a +binary operator rather than after it. + +The maximum width should be 79 columns. If you need more than this, +consider rewriting the code so that it fits in 79 columns, since +control flow that is nested deeply enough to require excessive width +is also likely to be difficult to understand if not broken up. +Exceptions may be made for long strings, though ANSI C string +concatenation should work around that as well. + +Function names for definitions should start on column zero, on the +line following their return type name, e.g. + + char * + foo(int a) + { + /* ... */ + } + +[just pretend that's really at column zero] + +The opening brace of a function definition should also be on column +zero. + +Braces that open substatements, such as those following "if", "else", +"while", "for", "do", and "switch", should be on the same line as the +begining of the statement. This is sometimes called "hanging" braces. +The corresponding closing brace should be at the same indentation +level as the beginning of the statement. + +The "while" keyword in a do-while construct should sit on the same +line as the closing brace of the substatement following "do": + + do { + foo(); + } while (0); + +If there is an "if" statement immediately following an "else" keyword, +it should go on the same line immediately after the "else": + + if (x) { + foo(); + } else if (y) { + bar(); + } + +Comments to the right of code start in column 32. Comments not to the +right of code are indented at the prevailing indent for the +surrounding code. Make the comments complete sentences. If you need +more than one line, make them into block comments, like this: + + /* + * This is a block comment. It should consist of complete + * sentences. + * + * Paragraphs should be separated by blank lines so that emacs + * fill commands will work properly. + */ + +Really important single-line comments should also be done in block +form: + + /* + * This is a really important one-line comment. + */ + +In order to get the start and end delimiters for block comments to +stay when you use emacs to fill paragraphs in the comments, set both +the c-hanging-comment-starter-p and the c-hanging-comment-ender-p +variables to nil. This will be done by the tentative "krb5" style for +the emacs cc-mode. + +Spaces go after keywords, but not after function names. Do not, +however, put a space after sizeof. Don't put a space after a cast +operator, either. Spaces also do not go before parentheses that are +argument lists for function calls even if the function call is through +a pointer. Spaces go after commas in argument lists, as well as +commas that are comma operators. Spaces also go between parts in a +for loop, except for "forever" type loops. Use for statements rather +than while statements to create forever loops. + + if (x) { + p = calloc(1024, sizeof(int)); + } + cp = (*elem->fp)(1024); + for (i = 0; i < 10; i++); + for (;;) { + /* ... */ + } + +Binary operators get spaces, unary ones do not. Prefix and postfix +operators also do not get spaces. The structure member operators "." +and "->" count as postfix operators syntactically, not as binary +operators. + + x = --a + b / c - d++; + y = p->z.v[x]; + +Put spaces around the "?" and ":" in a conditional expression. + + x = y ? f() : g(); + +In general, do not parenthesize the argument of "return". + +Coding practices for C +---------------------- + +Assume, for most purposes, working ANSI/ISO C ('89, not '99) support, +both for internal use and for applications compiling against Kerberos +header files and libraries. Some exceptions are noted below. + +Do not use assignments as truth values. Rather than this: + + /* bad style */ + if ((retval = krb5_foo())) + /* ... */; + +do this: + + /* better style */ + retval = krb5_foo(); + if (retval) + /* ... */; + +This makes the code easier to read, and also makes it easier to use +debuggers. It may be excusable to put assignments into the +conditional espression of a "while" statement, though, like: + + while ((ch = getopt(argc, argv, "abn")) != -1) + /* ... */; + +Using assignments as truth values in conditional expressions may make +code particularly impenetrable. + +There are at least three types of "zero" known to C. These are the +integer zero (0), the null pointer constant (NULL), and the character +constant zero ('\0'). Yes, these are usually all technically the +integer zero. Use them in their correct contexts. (Purists will +point out that 0 is a valid null pointer constant; still, do not use 0 +to specify a null pointer constant. For further unconfusion, read the +section on null pointer constants in the C FAQ.) Do not use a lone +variable as a truth value unless it's of integer type. Thus: + + int i; + char *cp; + /* ... */ + if (i) + /* ... */; + if (cp != NULL) { + while (*cp != '\0') + /* ... */; + } + +Do not cast uses of NULL unless you're calling a function with a +variable number of arguments, in which case you should cast it to to +the appropriate pointer type. Likewise, do not cast the return value +from malloc() and friends; the prototype should declare them properly +as returning a void * and thus shouldn't require an explicit cast. + +Do not assume that realloc(NULL, size) will do the right thing, or +that free(NULL) will do the right thing. ANSI guarantees that it +will, but some old libraries (hopefully becoming obsolete) don't. +Also, don't assume that malloc(0) will return a non-NULL pointer. +Typically, though, the output of malloc(0) will be safe to pass to +realloc() and free(). + +In any case, reading the section in the C FAQ on null pointers is +highly recommended to remove confusion regarding null pointers in C, +since this is a subject of much confusion to even experienced +programmers. In particular, if you do not understand why using +calloc() to allocate a struct that contains pointer members or why +calling memset() to initialize such a struct to all-bytes-zero is +wrong, reread that section again. (Note that there are *lots* of +examples of code in the krb5 source tree that erroneously calls +memset() to zero a struct, and we should fix these somehow +eventually.) + +Control flow statements that have a single statement as their body +should nevertheless have braces around their bodies if the body is +more than one line long, especially in the case of stacked multiple +if-else clauses; use: + + if (x) { + if (y) + foo(); + else + bar(); + } + +instead of: + + /* bad style */ + if (x) + if (y) + foo(); + else + bar(); + +which, while legible to the compiler, may confuse human readers and +make the code less maintainable, especially if new branches get added +to any of the clauses. + +Also, you should almost never intersperse conditional compilation +directives with control flow statements, as some combination of +#define'd symbols may result in statements getting eaten by dangling +bits of control flow statements. When it is not possible to avoid +this questionable practice (you really should rewrite the relevant +code section), make use of redundant braces to ensure that a compiler +error will result in preference to incorrect runtime behavior (such as +inadvertantly providing someone with a root shell). + +Do not intersperse conditional compilation directives with control +flow statements in such a way that confuses emacs cc-mode. Not only +does emacs get confused, but the code becomes more difficult to read +and maintain. Therefore, avoid code like this: + + /* bad style */ + if (x) { + f(); + } + #ifdef FOO + else if (y) { + #else + else { + #endif + g(); + } + +Put comments after conditional compilation directives such as "#else" +and "#endif". Make them correspond to the sense of the value that +controls the compilation of the section they are closing, i.e. + + #ifdef FOO + /* ... */ + #else /* !FOO */ + /* ... */ + #endif /* !FOO */ + +Also, in the case of more complex conditional compilation directives, +write the comments like this: + + #if defined(FOO) || defined(BAR) + /* ... */ + #else /* !(defined(FOO) || defined(BAR)) */ + /* ... */ + #endif /* !(defined(FOO) || defined(BAR)) */ + +If you are writing a do-while loop that has only one statement in its +body, put braces around it anyway, since the while clause may be +mistaken for a while loop with an empty body. Don't do this: + + /* bad style */ + do + foo(); + while (x); + +Instead, write this: + + /* better style */ + do { + foo(); + } while (x); + +While it is syntactically correct to call through a function pointer +without applying a dereference operator to it, do not write code that +does this. It is easier to see that the function call is actually +taking place through a function pointer if you write an explicit +dereference. However, do not explicitly take the address of a +function in order to assign it to a function pointer, since a function +name degrades into a pointer. Thus: + + int (*fp)(void); + int foofunc(void); + fp = foofunc; + x = (*fp)(); + +In general, do not take the address of an array. It does not return a +pointer to the first element; it returns a pointer to the array +itself. These are often identical when cast to an integral type, but +they are inherently of different types themselves. Functions that +take array types or pointers to array types as arguments can be +particularly trouble-prone. + +If a function is declared to return a value, do not call "return" +without an argument or allow the flow of control to fall off the end +of the function. + +Always declare the return type of a function, even if it returns int. +Yes, this means declaring main() to return int, since main() is +required to return int by the standard. If a function is not supposed +to return a value, declare it as returning void rather than omitting +the return type, which will default the return type to int. + +Try to use ANSI C prototype-style function definitions in preference +to K&R style definitions. When using K&R style function definitions, +declare all the argument types, even those that are int, but beware of +any narrow types in the argument list. + +Do not declare variables in an inner scope, e.g. inside the compound +substatement of an if statement, unless the complexity of the code +really demands that the variables be declared that way. In such +situations, the function could probably stand to be broken up into +smaller chunks anyway. Do not declare variables in an inner scope +that shadow ones in an outer scope, since this leads to confusion. +Also, some debugging environments, such as gdb under Solaris, can't +see variables declared in an inner scope, so declaring such variables +will make maintenance more difficult as well. + +Parenthesize expressions that may be confusing, particularly where C's +precedences are broken. For example, the shift operators have lower +precedence than the +, -, *, /, and % operators. Perhaps the most +familiar C precedence quirk is that equality and relational operators +are of higher precedence than assignment operators. Less well known +is that the bitwise operators are of a lower precedence than equality +and relational operators. + +The sizeof operator takes either a unary expression or a parenthesized +type name. It is not necessary to parenthesize the operand of sizeof +if it is applied to a unary expression, but still, always parenthesize +the operand of the sizeof operator. The sizeof operator does not +evaluate its operand if it is a unary expression, so usages such as + + s = sizeof(++foo); + +should be avoided for the sake of sanity and readability. + +Don't pass around structures except by address. We may relax this +restriction for non-API function, though. + +For new functions, input parameters should go before output parameters +in the call signature. There are exceptions, such as a context-like +parameter. + +Every function should have block comment preceding it describing +briefly in complete sentences what it does, what inputs and outputs it +has, and what error codes it can return. It should also describe any +unsual aspects of the function. At some point we will want to put +some of this information into a machine-parsable form. + +Macros should have all-uppercase names. If it is necessary to use +multiple statements, use braces, and wrap the whole thing in a +do-while(0) construct, such as + + #define FOOMACRO(x, y) do { \ + foo = (x) + (y); \ + f(y); \ + } while (0) + +Leave off the semicolon at the end of a function-like macro, so that +it can be mostly used like a call to a function without a return +value. Line up the backslashes to make it more readable. Use M-x +c-backslash-region in emacs to do neat lined-up backslashes. +Parenthesize uses of arguments in the replacement text of a macro in +order to prevent weird interactions. + +Strive to make your code capable of compiling using "gcc -Wall +-Wmissing-prototypes -Wtraditional -Wcast-qual -Wcast-align +-Wconversion -Waggregate-return -pedantic" [XXX need to rethink this +somewhat] without generating any errors or warnings. Do not, however, +compile using the "-ansi" flag to gcc, since that can result in odd +behavior with header files on some systems, causing some necessary +symbols to not be defined. + +Namespaces +---------- + +The C standard reserves a bunch of namespaces for the implementation. +Don't stomp on them. For practical purposes, any identifier with a +leading underscore should not be used. (Technically, ^_[a-z].* are +reserved only for file scope, so should be safe for things smaller +than file scope, but it's better to be paranoid in this case.) + +POSIX reserves typedef names ending with _t as well. + +Recall that errno is a reserved identifier, and is permitted to be a +macro. Therefore, do not use errno as the name of a structure member, +etc. + +Reserved namespaces are somewhat more restricted than this; read the +appropriate section of the C standard if you have questions. + +If you're writing new library code, pick a short prefix and stick with +it for any identifier with external linkage. If for some reason a +library needs to have external symbols that should not be visible to +the application, pick another (related) prefix to use for the internal +globals. This applies to typedef names, tag names, and preprocessor +identifiers as well. + +For the krb5 library, the prefix for public global symbols is "krb5_". +Use "krb5int_" as a prefix for library internal globals. Avoid using +"__" in symbol names, as it may confuse C++ implementations. There +are admittedly a number of places where we leak thing into the +namespace; we should try to fix these. + +Header files should also not leak symbols. Usually using the upcased +version of the prefix you've picked will suffice, e.g. "KRB5_" as a +CPP symbol prefix corresponding to "krb5_". In general, do not define +macros that are lowercase, in order to avoid confusion and to prevent +namespace collisions. + +The C standard only guarantees six case-insensitive characters to be +significant in external identifiers; this is largely regarded as +obsolescent even in 1989 and we will ignore it. It does, however, +only guarantee 31 case-sensitive characters to be signficant in +internal identifiers, so do not use identifiers that differ beyond the +31st character. This is unlikely to be a problem, though. + +Aspects of C style in GNU coding std but not here +------------------------------------------------- + +* redundant parens to force extra indent of operators of different + precedences + +* redundant parens to force general extra indent of expressions that + are broken between lines + +* use of ^L characters to break up source files into pages + +* nitpicking about capitalization in comments of variable names when + their values are meant + +* commenting usages of static variables + +* casts to void + +* separation of word in names with underscores vs case change + +* enum vs #define'd integer constants + +* 14 char filename limits, MS-DOS filename limits + +* portability + +* system library function quirks + +* internationalization + +* mmap() + +Aspects of C style in BSD KNF but not here +------------------------------------------ + +* sorting of header files + +* sorting of struct members + +* separating struct tag decl and struct typedef + +* sorting of var decl + +* lining up var names in decls + +* newline after decls + +* usage of __P + +* usage of getopt + +* not initializing vars in decls + +* stdarg/varargs handling + +Emacs cc-mode style +------------------- + +Putting the following code in your .emacs file will result in mostly +the right thing happening with respect to formatting style. Note that +you may want to turn on auto-newline feature of cc-mode, though that +seems to have some bugs with brace-elseif-brace handling at least in +the version of cc-mode that comes with emacs 20.3. + + (defconst krb5-c-style + '("bsd" + (c-cleanup-list + brace-elseif-brace brace-else-brace defun-close-semi) + (c-comment-continuation-stars . "* ") + (c-electric-pound-behavior alignleft) + (c-hanging-braces-alist + (brace-list-open) + (class-open after) + (substatement-open after) + (block-close . c-snug-do-while) + (extern-lang-open after)) + (c-hanging-colons-alist + (case-label after) + (label after)) + (c-hanging-comment-starter-p) + (c-hanging-comment-ender-p) + (c-indent-comments-syntactically-p . t) + (c-label-minimum-indentation . 0) + (c-special-indent-hook))) + (defun krb5-c-hook () + (c-add-style "krb5" krb5-c-style t)) + (add-hook 'c-mode-common-hook 'krb5-c-hook) + +indent.pro settings +------------------- + +The following settings for the indent program should produce a +reasonable approximation to the C coding style described here, though +some manual cleanup may be necessary. Note that the gindent installed +in the gnu locker does not currently handle -psl correctly though. + +-bap +-br +-ce +-ci4 +-cli0 +-d0 +-di8 +-i4 +-ip4 +-l79 +-nbc +-ncdb +-ndj +-nfc1 +-lp +-npcs +-psl +-sc +-sob + +MAKEFILES +========= + +[XXX needs to be written] + +TEST SUITES +=========== + +[XXX needs to be written] diff --git a/mechglue/doc/copyright.texinfo b/mechglue/doc/copyright.texinfo new file mode 100644 index 000000000..8eacbb682 --- /dev/null +++ b/mechglue/doc/copyright.texinfo @@ -0,0 +1,203 @@ +Copyright @copyright{} 1985-2002,2005 by the Massachusetts Institute of Technology. + +@quotation +Export of software employing encryption from the United States of +America may require a specific license from the United States +Government. It is the responsibility of any person or organization +contemplating export to obtain such a license before exporting. +@end quotation + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute +this software and its documentation for any purpose and without fee is +hereby granted, provided that the above copyright notice appear in all +copies and that both that copyright notice and this permission notice +appear in supporting documentation, and that the name of M.I.T. not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. Furthermore if you +modify this software you must label your software as modified software +and not distribute it in such a fashion that it might be confused with +the original MIT software. M.I.T. makes no representations about the +suitability of this software for any purpose. It is provided ``as is'' +without express or implied warranty. + +@iftex +@vskip 12pt +@hrule +@vskip 12pt +@end iftex + +The following copyright and permission notice applies to the OpenVision +Kerberos Administration system located in kadmin/create, kadmin/dbutil, +kadmin/passwd, kadmin/server, lib/kadm5, and portions of lib/rpc: + +@quotation +Copyright, OpenVision Technologies, Inc., 1996, All Rights Reserved + +WARNING: Retrieving the OpenVision Kerberos Administration system source +code, as described below, indicates your acceptance of the following +terms. If you do not agree to the following terms, do not retrieve the +OpenVision Kerberos administration system. + +You may freely use and distribute the Source Code and Object Code +compiled from it, with or without modification, but this Source Code is +provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY, INCLUDING, WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A +PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER EXPRESS OR IMPLIED. +IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY FOR ANY LOST PROFITS, +LOSS OF DATA OR COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR +FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS +AGREEMENT, INCLUDING, WITHOUT LIMITATION, THOSE RESULTING FROM THE USE +OF THE SOURCE CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR +ANY OTHER REASON. + +OpenVision retains all copyrights in the donated Source Code. OpenVision +also retains copyright to derivative works of the Source Code, whether +created by OpenVision or by a third party. The OpenVision copyright +notice must be preserved if derivative works are made based on the +donated Source Code. + +OpenVision Technologies, Inc. has donated this Kerberos Administration +system to MIT for inclusion in the standard Kerberos 5 distribution. +This donation underscores our commitment to continuing Kerberos +technology development and our gratitude for the valuable work which has +been performed by MIT and the Kerberos community. +@end quotation + +@iftex +@vskip 12pt +@hrule +@vskip 12pt +@end iftex + +The implementation of the Yarrow pseudo-random number generator +in src/lib/crypto/yarrow has the following copyright: + +@quotation + +Copyright 2000 by Zero-Knowledge Systems, Inc. + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Zero-Knowledge Systems, +Inc. not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. Zero-Knowledge Systems, Inc. makes no representations +about the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. + +ZERO-KNOWLEDGE SYSTEMS, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL ZERO-KNOWLEDGE SYSTEMS, INC. BE LIABLE FOR +ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +@end quotation + +@iftex +@vskip 12pt +@hrule +@vskip 12pt +@end iftex + +The implementation of the AES encryption algorithm in +src/lib/crypto/aes has the following copyright: + +@quotation + +Copyright (c) 2001, Dr Brian Gladman , Worcester, UK. +All rights reserved. + +LICENSE TERMS + +The free distribution and use of this software in both source and binary +form is allowed (with or without changes) provided that: + +@enumerate +@item +distributions of this source code include the above copyright +notice, this list of conditions and the following disclaimer; +@item +distributions in binary form include the above copyright +notice, this list of conditions and the following disclaimer +in the documentation and/or other associated materials; +@item +the copyright holder's name is not used to endorse products +built using this software without specific written permission. +@end enumerate + +DISCLAIMER + +This software is provided 'as is' with no explcit or implied warranties +in respect of any properties, including, but not limited to, correctness +and fitness for purpose. + +@end quotation + +@iftex +@vskip 12pt +@hrule +@vskip 12pt +@end iftex + +@value{PRODUCT} includes documentation and software developed at the +University of California at Berkeley, which includes this copyright +notice: + +Copyright @copyright{} 1983 Regents of the University of California.@* +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +@enumerate +@item +Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +@item +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +@item +All advertising materials mentioning features or use of this software +must display the following acknowledgement: +@quotation +This product includes software developed by the University of +California, Berkeley and its contributors. +@end quotation +@item +Neither the name of the University nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. +@end enumerate + +@iftex +@vskip 12pt +@hrule +@vskip 12pt +@end iftex + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notices and this permission notice are +preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries a copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions. +@iftex +@pagealignmacro +@end iftex diff --git a/mechglue/doc/definitions.texinfo b/mechglue/doc/definitions.texinfo new file mode 100644 index 000000000..ac7ca5a07 --- /dev/null +++ b/mechglue/doc/definitions.texinfo @@ -0,0 +1,193 @@ +@c Set the "MIT" flag for the MIT edition; set the "CYGNUS" flag for +@c the Cygnus edition. +@clear CYGNUS +@set MIT +@set ADMINUSER joeadmin +@set COMPANY MIT +@set KDCSERVER kerberos +@set KDCSLAVE1 @value{KDCSERVER}-1 +@set KDCSLAVE2 @value{KDCSERVER}-2 +@set PRIMARYDOMAIN mit.edu +@set PRIMARYREALM ATHENA.MIT.EDU +@set PRODUCT Kerberos V5 +@set CPRODUCT Kerberos +@set LCPRODUCT krb5 +@set RANDOMHOST1 daffodil +@set RANDOMHOST1IP 10.0.0.6 +@set RANDOMHOST2 trillium +@set RANDOMHOST2IP 10.1.2.3 +@set RANDOMUSER johndoe +@set RANDOMUSER1 jennifer +@set RANDOMUSER2 david +@set RELEASE post-1.4 +@set PREVRELEASE 1.4 +@set INSTALLDIR /usr/@value{LCPRODUCT} +@set PREVINSTALLDIR @value{INSTALLDIR} +@set ROOTDIR /usr/local +@set BINDIR /usr/local/bin +@set LOCALSTATEDIR @value{ROOTDIR}/var +@set SECONDDOMAIN example.com +@set SECONDREALM EXAMPLE.COM +@set UPDATED @today + +@ignore +The rest of the variables in this file are defaults for tags in the +configuration files. Each group of defaults come from the same file in +the code, which is specified in the ignore comment above the group. +After each variable, there should be a comment specifying the variable +in the code that holds the default variable, or the line in which the +default was set. +@end ignore + +@ignore +the following should be consistent with the variables set in +krb5/src/lib/krb5/krb/init_ctx.c +@end ignore +@set DefaultETypeList aes256-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac-md5 des-cbc-crc des-cbc-md5 des-cbc-md4 +@comment DEFAULT_ETYPE_LIST +@set DefaultDefaultTgsEnctypes @value{DefaultETypeList} +@set DefaultDefaultTktEnctypes @value{DefaultETypeList} +@set DefaultPermittedEnctypes @value{DefaultETypeList} +@set DefaultClockskew 300 seconds, or five minutes +@comment libdefaults, clockskew +@set DefaultChecksumType RSA MD5 +@comment libdefaults, kdc_req_checksum_type, ap_req_checksum_type, safe_checksum_type +@set DefaultCcacheType 4 +@comment DEFAULT_CCACHE_TYPE +@set DefaultTktLifetime 1 day +@comment libdefaults, tkt_lifetime +@comment -- actually, that's not implemented; see +@comment lib/krb5/krb/get_in_tkt.c, and clients/kinit/kinit.c for krb4 +@comment fallback +@set DefaultKDCTimesync 1 +@comment DEFAULT_KDC_TIMESYNC +@set DefaultKDCDefaultOptions KDC_OPT_RENEWABLE_OK +@comment line 194 + +@ignore +the following defaults should be consistent with default variables set +in krb5/src/include/krb5/stock/osconf.h +@end ignore +@set DefaultMasterKeyType des3-cbc-sha1 +@comment DEFAULT_KDC_ENCTYPE +@set DefaultKadmindPort 749 +@comment DEFAULT_KADM5_PORT +@set DefaultAclFile @value{LOCALSTATEDIR}/krb5kdc/kadm5.acl +@comment DEFAULT_KADM5_ACL_FILE +@set DefaultAdminKeytab @value{LOCALSTATEDIR}/krb5kdc/kadm5.keytab +@comment DEFAULT_KADM5_KEYTAB +@set DefaultDatabaseName @value{LOCALSTATEDIR}/krb5kdc/principal +@comment DEFAULT_KDB_FILE +@set DefaultKdcPorts 88,750 +@comment DEFAULT_KDC_PORTLIST +@set DefaultKpasswdPort 464 +@comment DEFAULT_KPASSWD_PORT +@set DefaultSecondPort 750 +@comment KRB5_DEFAULT_SEC_PORT +@set DefaultPort 88 +@comment KRB5_DEFAULT_PORT +@set DefaultKeyStashFileStub @value{LOCALSTATEDIR}/krb5kdc/.k5. +@comment DEFAULT_KEYFILE_STUB +@set DefaultDefaultKeytabName /etc/krb5.keytab +@comment DEFAULT_KEYTAB_NAME +@set DefaultKpasswdPort 464 +@comment DEFAULT_KPASSWD_PORT +@set DefaultDefaultProfilePath /etc/krb5.conf +@comment DEFAULT_PROFILE_PATH +@set DefaultKDCRCache krb5kdc_rcache +@comment KDCRCACHE +@set DefaultRCTmpDirs /var/tmp, /usr/tmp, /var/usr/tmp, and /tmp + +@ignore +the following defaults should be consistent with the numbers set in +krb5/src/lib/kadm5/alt_prof.c +@end ignore +@set DefaultMaxLife 10 hours +@comment line 608 +@set DefaultMaxRenewableLife 0 +@comment line 622 +@set DefaultDefaultPrincipalExpiration 0 +@comment line 639 +@set DefaultSupportedEnctypes des3-hmac-sha1:normal des-cbc-crc:normal +@comment line 705 + +@ignore +the following defaults should be consistent with the values set in +krb5/src/include/krb5/kdb.h +@end ignore +@set DefaultDefaultPrincipalFlags postdateable, forwardable, tgt-based, renewable, proxiable, dup-skey, allow-tickets, and service enabled. +@comment KRB_KDC_DEFAULT_FLAGS set to 0 + +@ignore +the following defaults should be consistent with the values set in +include/krb5/kdb.h +@end ignore +@set DefaultMasterKeyName K/M +@comment KRB5_KDB_M_NAME + +@ignore +the following defaults should be consistent with the values set in +krb5/src/appl/bsd/login.c +@end ignore +@set DefaultKrb5GetTickets true +@comment login_krb5_get_tickets +@set DefaultKrb4GetTickets false +@comment login_krb4_get_tickets +@set DefaultKrb4Convert false +@comment login_krb4_convert +@set DefaultKrbRunAklog false +@comment login_krb_run_aklog +@set DefaultAklogPath $(prefix)/bin/aklog +@comment lines 955-956 +@set DefaultAcceptPasswd false +@comment login_accept_password + +@ignore +the following defaults should be consistent with the values set in +krb5/src/kdc/kerberos_v4 +@end ignore +@set DefaultV4Mode none +@comment KDC_V4_DEFAULT_MODE + +@ignore +these defaults are based on code in krb5/src/aclocal.m4 +@end ignore +@set DefaultDNSLookupKDC true +@set DefaultDNSLookupRealm false +@comment lines 1259-1300 + +@ignore +the following are based on variables in krb5/src/include/kerberosIV/krbports.h +@end ignore +@set DefaultKrbPropPort 754 +@comment KRB_PROP_PORT +@set DefaultKloginPort 543 +@comment KLOGIN_PORT +@set DefaultEkloginPort 2105 +@comment EKLOGIN_PORT +@set DefaultKshellPort 544 +@comment KRB_SHELL_PORT + +@ignore +/etc/services +@end ignore +@set DefaultTelnetPort 23 +@set DefaultFTPPort 21 +@set DefaultKrb524Port 4444 + +@comment src/include/kerberosIV/krb.h +@set DefaultKrb4Srvtab /etc/srvtab +@comment line 131 +@set DefaultKrb4Config /etc/krb.conf +@comment KRB_CONF +@set DefaultKrb4Realms /etc/krb.realms +@comment KRB_RLM_TRANS + +@comment krb5/src/lib/krb5/krb/get_in_tkt.c +@set DefaultRenewLifetime 0 +@set DefaultNoaddresses set +@set DefaultForwardable not set +@set DefaultProxiable not set + +@comment lib/krb5/krb/vfy_increds.c +@set DefaultVerifyApReqNofail not set diff --git a/mechglue/doc/dnssrv.texinfo b/mechglue/doc/dnssrv.texinfo new file mode 100644 index 000000000..c969fb269 --- /dev/null +++ b/mechglue/doc/dnssrv.texinfo @@ -0,0 +1,97 @@ +@value{COMPANY} recommends that your KDCs have a predefined set of +CNAME records (DNS hostname aliases), such as @code{@value{KDCSERVER}} +for the master KDC and +@code{@value{KDCSLAVE1}}, @code{@value{KDCSLAVE2}}, @dots{} for the +slave KDCs. This way, if you need to swap a machine, you only need to +change a DNS entry, rather than having to change hostnames. + +A new mechanism for locating KDCs of a realm through DNS has been added +to the @value{COMPANY} @value{PRODUCT} distribution. A relatively new +record type called @code{SRV} has been added to DNS. Looked up by a +service name and a domain name, these records indicate the hostname and +port number to contact for that service, optionally with weighting and +prioritization. (See RFC 2782 if you want more information. You can +follow the example below for straightforward cases.) + +The use with Kerberos is fairly straightforward. The domain name used +in the SRV record name is the domain-style Kerberos realm name. (It is +possible to have Kerberos realm names that are not DNS-style names, but +we don't recommend it for Internet use, and our code does not support it +well.) Several different Kerberos-related service names are used: + +@table @code +@item _kerberos._udp +This is for contacting any KDC by UDP. This entry will be used the most +often. Normally you should list port 88 on each of your KDCs. +@c Don't encourage continued use of port 750 for krb5. +@c It should be only for backwards compatibility with krb4. +@c Do the Mac/Windows krb4 libraries use this DNS entry? +@c The UNIX code does not. + +@item _kerberos._tcp +This is for contacting any KDC by TCP. The MIT KDC by default will not +listen on any TCP ports, so unless you've changed the configuration or +you're running another KDC implementation, you should leave this +unspecified. If you do enable TCP support, normally you should use +port 88. + +@item _kerberos-master._udp +This entry should refer to those KDCs, if any, that will immediately see +password changes to the Kerberos database. This entry is used only in +one case, when the user is logging in and the password appears to be +incorrect; the master KDC is then contacted, and the same password used +to try to decrypt the response, in case the user's password had recently +been changed and the first KDC contacted hadn't been updated. Only if +that fails is an ``incorrect password'' error given. + +If you have only one KDC, or for whatever reason there is no accessible +KDC that would get database changes faster than the others, you do not +need to define this entry. + +@item _kerberos-adm._tcp +This should list port @value{DefaultKadmindPort} on your master KDC. +Support for it is not complete at this time, but it will eventually be +used by the @code{kadmin} program and related utilities. For now, you +will also need the @code{admin_server} entry in @code{krb5.conf}. +(@xref{krb5.conf}.) + +@item _kpasswd._udp +This should list port @value{DefaultKpasswdPort} on your master KDC. +It is used when a user changes her password. + +@item _kerberos-iv._udp +This should refer to your KDCs that serve Kerberos version 4 requests, +if you have Kerberos v4 enabled. + +@end table + +Be aware, however, that the DNS SRV specification requires that the +hostnames listed be the canonical names, not aliases. So, for example, +you might include the following records in your (BIND-style) zone file: + +@smallexample +$ORIGIN foobar.com. +_kerberos TXT "FOOBAR.COM" +kerberos CNAME daisy +kerberos-1 CNAME use-the-force-luke +kerberos-2 CNAME bunny-rabbit +_kerberos._udp SRV 0 0 88 daisy + SRV 0 0 88 use-the-force-luke + SRV 0 0 88 bunny-rabbit +_kerberos-master._udp SRV 0 0 88 daisy +_kerberos-adm._tcp SRV 0 0 749 daisy +_kpasswd._udp SRV 0 0 464 daisy +@end smallexample + +As with the DNS-based mechanism for determining the Kerberos realm of a +host, we recommend distributing the information this way for use by +other sites that may want to interact with yours using Kerberos, even if +you don't immediately make use of it within your own site. If you +anticipate installing a very large number of machines on which it will +be hard to update the Kerberos configuration files, you may wish to do +all of your Kerberos service lookups via DNS and not put the information +(except for @code{admin_server} as noted above) in future versions of +your @code{krb5.conf} files at all. Eventually, we hope to phase out +the listing of server hostnames in the client-side configuration files; +making preparations now will make the transition easier in the future. + diff --git a/mechglue/doc/dnstxt.texinfo b/mechglue/doc/dnstxt.texinfo new file mode 100644 index 000000000..e06d220cf --- /dev/null +++ b/mechglue/doc/dnstxt.texinfo @@ -0,0 +1,38 @@ +Mapping hostnames onto Kerberos realms is done in one of two ways. + +The first mechanism, which has been in use for years in MIT-based +Kerberos distributions, works through a set of rules in +the @code{krb5.conf} configuration file. (@xref{krb5.conf}.) You can +specify mappings for an entire domain or subdomain, and/or on a +hostname-by-hostname basis. Since greater specificity takes precedence, +you would do this by specifying the mappings for a given domain or +subdomain and listing the exceptions. + +The second mechanism works by looking up the information in special +@code{TXT} records in the Domain Name Service. This is currently not +used by default because security holes could result if the DNS TXT +records were spoofed. If this mechanism is enabled on the client, +it will try to look up a @code{TXT} record for the DNS name formed by +putting the prefix @code{_kerberos} in front of the hostname in question. +If that record is not found, it will try using @code{_kerberos} and the +host's domain name, then its parent domain, and so forth. So for the +hostname BOSTON.ENGINEERING.FOOBAR.COM, the names looked up would be: + +@smallexample +_kerberos.boston.engineering.foobar.com +_kerberos.engineering.foobar.com +_kerberos.foobar.com +_kerberos.com +@end smallexample + +The value of the first TXT record found is taken as the realm name. +(Obviously, this doesn't work all that well if a host and a subdomain +have the same name, and different realms. For example, if all the hosts +in the ENGINEERING.FOOBAR.COM domain are in the ENGINEERING.FOOBAR.COM +realm, but a host named ENGINEERING.FOOBAR.COM is for some reason in +another realm. In that case, you would set up TXT records for all +hosts, rather than relying on the fallback to the domain name.) + +Even if you do not choose to use this mechanism within your site, you +may wish to set it up anyway, for use when interacting with other sites. + diff --git a/mechglue/doc/document-list.texinfo b/mechglue/doc/document-list.texinfo new file mode 100644 index 000000000..65058b96d --- /dev/null +++ b/mechglue/doc/document-list.texinfo @@ -0,0 +1,24 @@ +This document is one piece of the document set for @value{PRODUCT}. The +documents, and their intended audiences, are: + +@itemize @bullet +@item +@b{@value{PRODUCT} Installation Guide}: a concise guide for installing +@value{PRODUCT}. Kerberos administrators (particularly whoever will be +making site-wide decisions about the installation) and the system +administrators who will be installing the software should read this +guide. + +@item +@b{@value{PRODUCT} System Administrator's Guide}: a sysadmin's guide to +administering a Kerberos installation. The System Administrator's Guide +describes the administration software and suggests policies and +procedures for administering a Kerberos installation. Anyone who will +have administrative access to your Kerberos database should read this +guide. + +@item +@b{@value{PRODUCT} UNIX User's Guide}: a guide to using the Kerberos +UNIX client programs. All users on UNIX systems should read this guide, +particularly the ``Tutorial'' section. +@end itemize diff --git a/mechglue/doc/glossary.texinfo b/mechglue/doc/glossary.texinfo new file mode 100644 index 000000000..d49a56a7f --- /dev/null +++ b/mechglue/doc/glossary.texinfo @@ -0,0 +1,64 @@ +@table @b +@item client +an entity that can obtain a ticket. This entity is usually either a +user or a host. + +@item host +a computer that can be accessed over a network. + +@item Kerberos +in Greek mythology, the three-headed dog that guards the entrance to the +underworld. In the computing world, Kerberos is a network security +package that was developed at MIT. + +@item KDC +Key Distribution Center. A machine that issues Kerberos tickets. + +@item keytab +a @b{key tab}le file containing one or more keys. A host or service +uses a @dfn{keytab} file in much the same way as a user uses his/her +password. + +@item principal +a string that names a specific entity to which a set of credentials may +be assigned. It can have an arbitrary number of components, but +generally has three: + +@table @b +@item primary +the first part of a Kerberos @i{principal}. In the case of a user, it +is the username. In the case of a service, it is the name of the +service. + +@item instance +the second part of a Kerberos @i{principal}. It gives information that +qualifies the primary. The instance may be null. In the case of a +user, the instance is often used to describe the intended use of the +corresponding credentials. In the case of a host, the instance is the +fully qualified hostname. + +@item realm +the logical network served by a single Kerberos database and a set of +Key Distribution Centers. By convention, realm names are generally all +uppercase letters, to differentiate the realm from the internet domain. +@end table + +@noindent +The typical format of a typical Kerberos principal is +primary/instance@@REALM. + +@item service +any program or computer you access over a network. Examples of services +include ``host'' (a host, @i{e.g.}, when you use @code{telnet} and +@code{rsh}), ``ftp'' (FTP), ``krbtgt'' (authentication; +cf. @i{ticket-granting ticket}), and ``pop'' (email). + +@item ticket +a temporary set of electronic credentials that verify the identity of a +client for a particular service. + +@item TGT +Ticket-Granting Ticket. A special Kerberos ticket that permits the +client to obtain additional Kerberos tickets within the same Kerberos +realm. +@end table diff --git a/mechglue/doc/implement/.Sanitize b/mechglue/doc/implement/.Sanitize new file mode 100644 index 000000000..1847a88d1 --- /dev/null +++ b/mechglue/doc/implement/.Sanitize @@ -0,0 +1,46 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +ChangeLog +Makefile +ccache-i.tex +changebar.sty +cksum-i.tex +crc-32-i.tex +encrypt-i.tex +fancyheadings.sty +fixunder.sty +functions.sty +implement.tex +kdb-i.tex +keytab-i.tex +libos-i.tex +rcache-i.tex + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/mechglue/doc/implement/.cvsignore b/mechglue/doc/implement/.cvsignore new file mode 100644 index 000000000..67a81b831 --- /dev/null +++ b/mechglue/doc/implement/.cvsignore @@ -0,0 +1,7 @@ +implement.ind +implement.log +implement.idx +implement.aux +implement.toc +implement.dvi +implement.ps diff --git a/mechglue/doc/implement/ChangeLog b/mechglue/doc/implement/ChangeLog new file mode 100644 index 000000000..3bd06aae7 --- /dev/null +++ b/mechglue/doc/implement/ChangeLog @@ -0,0 +1,20 @@ +2005-08-29 Sam Hartman + + * implement.tex: Avoid use of changebar.sty + +2001-11-06 Ken Raeburn + + * Makefile (clean): Delete *.ilg. + (implement.ind): Use makeindex not index. + +2000-02-25 Ken Raeburn + + * encrypt-i.tex (subsection{Functional interface}): Comment out + combine_keys until/unless it gets implemented. + +Wed Oct 12 02:19:07 1994 Theodore Y. Ts'o (tytso@dcl) + + * Makefile: Added better dependencies to do two-pass latex runs + automatically. Make "make clean" clean up the tex temp + files. + diff --git a/mechglue/doc/implement/Makefile b/mechglue/doc/implement/Makefile new file mode 100644 index 000000000..4c5116132 --- /dev/null +++ b/mechglue/doc/implement/Makefile @@ -0,0 +1,38 @@ +.SUFFIXES: .tex .dvi .ps + +STYLES= fixunder.sty functions.sty +LIBTEX= implement.tex ccache-i.tex rcache-i.tex keytab-i.tex libos-i.tex \ + kdb-i.tex encrypt-i.tex cksum-i.tex crc-32-i.tex implement.ind + + +all: implement.ps + + +implement.ps: implement.dvi + +# hard to capture two-pass semantics in Makefiles... +# implement.ind: implement.dvi +implement.ind: implement.idx + makeindex implement.idx + +implement.idx: + touch implement.ind + latex implement.tex + rm implement.ind + +clean: + rm -f *.toc *.log *.idx *.ind *.aux *.ilg + +really-clean: clean + rm -f *.dvi *.ps + + +implement.dvi: $(LIBTEX) $(STYLES) + +.tex.dvi: + latex $* + + +.dvi.ps: + dvips $*.dvi -o + diff --git a/mechglue/doc/implement/ccache-i.tex b/mechglue/doc/implement/ccache-i.tex new file mode 100644 index 000000000..66d7b61bf --- /dev/null +++ b/mechglue/doc/implement/ccache-i.tex @@ -0,0 +1,224 @@ +The credentials cache functions (some of which are macros which call to +specific types of credentials caches) deal with storing credentials +(tickets, session keys, and other identifying information) in a +semi-permanent store for later use by different programs. + +\subsubsection{The krb5_cc_ops structure} +In order to implement a new credentials cache type, the programmer should +declare a {\bf krb5_cc_ops} structure, and fill in the elements of the +structure appropriately, by implementing each of the credential cache +functions for the new credentials cache type. + +The prefix element specifies the prefix name of the the new credential +cache type. For example, if the prefix name is ``FILE'', then if the +program calls \funcname{krb5_cc_resolve} with a credential cache name +such as ``FILE:/tmp/krb5_cc_15806'', then \funcname{krb5_cc_resolve} +will call the resolve function (as defined by the {\bf krb5_cc_ops} +structure where the prefix element is ``FILE'') and pass it the +argument ``/tmp/krb5_cc_15806''. + +Before a new credentials cache type can be recognized by +\funcname{krb5_cc_resolve}, it must be registered with the Kerberos +library by calling \funcname{krb5_cc_register}. + +\begin{verbatim} +typedef struct _krb5_cc_ops { + char *prefix; + char *(*get_name)((krb5_ccache)); + krb5_error_code (*resolve)((krb5_ccache *, char *)); + krb5_error_code (*gen_new)((krb5_ccache *)); + krb5_error_code (*init)((krb5_ccache, krb5_principal)); + krb5_error_code (*destroy)((krb5_ccache)); + krb5_error_code (*close)((krb5_ccache)); + krb5_error_code (*store)((krb5_ccache, krb5_creds *)); + krb5_error_code (*retrieve)((krb5_ccache, krb5_flags, + krb5_creds *, krb5_creds *)); + krb5_error_code (*get_princ)((krb5_ccache, + krb5_principal *)); + krb5_error_code (*get_first)((krb5_ccache, + krb5_cc_cursor *)); + krb5_error_code (*get_next)((krb5_ccache, krb5_cc_cursor *, + krb5_creds *)); + krb5_error_code (*end_get)((krb5_ccache, krb5_cc_cursor *)); + krb5_error_code (*remove_cred)((krb5_ccache, krb5_flags, + krb5_creds *)); + krb5_error_code (*set_flags)((krb5_ccache, krb5_flags)); +} krb5_cc_ops; +\end{verbatim} + + +\subsubsection{Per-type functions} +The following entry points must be implemented for each type of +credentials cache. However, \funcname{resolve} and +\funcname{gen_new} are only called by the credentials cache glue code. +They are not called directly by the application. + + +\begin{funcdecl}{resolve}{krb5_error_code}{\funcout} +\funcarg{krb5_ccache *}{id} +\funcin +\funcarg{char *}{residual} +\end{funcdecl} + +Creates a credentials cache named by \funcparam{residual} (which may be +interpreted differently by each type of ccache). The cache is not +opened, but the cache name is held in reserve. + +\begin{funcdecl}{gen_new}{krb5_error_code}{\funcout} +\funcarg{krb5_ccache *}{id} +\end{funcdecl} + +Creates a new credentials cache whose name is guaranteed to be +unique. The cache is not opened. \funcparam{*id} is +filled in with a \datatype{krb5_ccache} which may be used in subsequent +calls to ccache functions. + +\begin{funcdecl}{init}{krb5_error_code}{\funcinout} +\funcarg{krb5_ccache}{id} +\funcin +\funcarg{krb5_principal}{primary_principal} +\end{funcdecl} + +Creates/refreshes a credentials cache identified by \funcparam{id} with +primary principal set to \funcparam{primary_principal}. +If the credentials cache already exists, its contents are destroyed. + +%Errors: permission errors, system errors. + +Modifies: cache identified by \funcparam{id}. + +\begin{funcdecl}{destroy}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\end{funcdecl} + +Destroys the credentials cache identified by \funcparam{id}, invalidates +\funcparam{id}, and releases any other resources acquired during use of +the credentials cache. Requires that \funcparam{id} identifies a valid +credentials cache. After return, \funcparam{id} must not be used unless +it is first reinitialized. + +%Errors: permission errors. + +\begin{funcdecl}{close}{krb5_error_code}{\funcinout} +\funcarg{krb5_ccache}{id} +\end{funcdecl} + +Closes the credentials cache \funcparam{id}, invalidates +\funcparam{id}, and releases \funcparam{id} and any other resources +acquired during use of the credentials cache. Requires that +\funcparam{id} identifies a valid credentials cache. After return, +\funcparam{id} must not be used unless it is first reinitialized. + + +\begin{funcdecl}{store}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\funcarg{krb5_creds *}{creds} +\end{funcdecl} + +Stores \funcparam{creds} in the cache \funcparam{id}, tagged with +\funcparam{creds{\ptsto}client}. +Requires that \funcparam{id} identifies a valid credentials cache. + +%Errors: permission errors, storage failure errors. + +\begin{funcdecl}{retrieve}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\funcarg{krb5_flags}{whichfields} +\funcarg{krb5_creds *}{mcreds} +\funcout +\funcarg{krb5_creds *}{creds} +\end{funcdecl} + +Searches the cache \funcparam{id} for credentials matching +\funcparam{mcreds}. The fields which are to be matched are specified by +set bits in \funcparam{whichfields}, and always include the principal +name \funcparam{mcreds{\ptsto}server}. +Requires that \funcparam{id} identifies a valid credentials cache. + +If at least one match is found, one of the matching credentials is +returned in \funcparam{*creds}. The credentials should be freed using +\funcname{krb5_free_credentials}. + +%Errors: error code if no matches found. + +\begin{funcdecl}{get_princ}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\funcarg{krb5_principal *}{principal} +\end{funcdecl} + +Retrieves the primary principal of the credentials cache (as +set by the \funcname{init} request) +The primary principal is filled into \funcparam{*principal}; the caller +should release this memory by calling \funcname{krb5_free_principal} on +\funcparam{*principal} when finished. + +Requires that \funcparam{id} identifies a valid credentials cache. + +\begin{funcdecl}{get_first}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\funcout +\funcarg{krb5_cc_cursor *}{cursor} +\end{funcdecl} + +Prepares to sequentially read every set of cached credentials. +Requires that \funcparam{id} identifies a valid credentials cache opened by +\funcname{krb5_cc_open}. +\funcparam{cursor} is filled in with a cursor to be used in calls to +\funcname{get_next}. + +\begin{funcdecl}{get_next}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\funcout +\funcarg{krb5_creds *}{creds} +\funcinout +\funcarg{krb5_cc_cursor *}{cursor} +\end{funcdecl} + +Fetches the next entry from \funcparam{id}, returning its values in +\funcparam{*creds}, and updates \funcparam{*cursor} for the next request. +Requires that \funcparam{id} identifies a valid credentials cache and +\funcparam{*cursor} be a cursor returned by +\funcname{get_first} or a subsequent call to +\funcname{get_next}. + +%Errors: error code if no more cache entries. + +\begin{funcdecl}{end_get}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\funcarg{krb5_cc_cursor *}{cursor} +\end{funcdecl} + +Finishes sequential processing mode and invalidates \funcparam{*cursor}. +\funcparam{*cursor} must never be re-used after this call. + +Requires that \funcparam{id} identifies a valid credentials cache and +\funcparam{*cursor} be a cursor returned by +\funcname{get_first} or a subsequent call to +\funcname{get_next}. + +%Errors: may return error code if \funcparam{*cursor} is invalid. + + +\begin{funcdecl}{remove_cred}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\funcarg{krb5_flags}{which} +\funcarg{krb5_creds *}{cred} +\end{funcdecl} + +Removes any credentials from \funcparam{id} which match the principal +name {cred{\ptsto}server} and the fields in \funcparam{cred} masked by +\funcparam{which}. +Requires that \funcparam{id} identifies a valid credentials cache. + +%Errors: returns error code if nothing matches; returns error code if +%couldn't delete. + +\begin{funcdecl}{set_flags}{krb5_error_code}{\funcin} +\funcarg{krb5_ccache}{id} +\funcarg{krb5_flags}{flags} +\end{funcdecl} + +Sets the flags on the cache \funcparam{id} to \funcparam{flags}. Useful +flags are defined in {\tt }. + + diff --git a/mechglue/doc/implement/cksum-i.tex b/mechglue/doc/implement/cksum-i.tex new file mode 100644 index 000000000..c7f763738 --- /dev/null +++ b/mechglue/doc/implement/cksum-i.tex @@ -0,0 +1,31 @@ +Kerberos v5 has the ability to use multiple checksum algorithms. Any +checksum implementation which desires to link with and be usable from the MIT +Kerberos v5 implementation must implement this interface: + +\subsection{Functional interface} + +\begin{funcdecl}{sum_func}{krb5_error_code}{\funcin} +\funcarg{krb5_pointer}{in} +\funcarg{size_t}{in_length} +\funcarg{krb5_pointer}{seed} +\funcarg{size_t}{seed_length} +\funcout +\funcarg{krb5_checksum *}{outcksum} +\end{funcdecl} + +This routine computes the desired checksum over \funcparam{in_length} bytes +at \funcparam{in}. \funcparam{seed_length} bytes of a seed (usually an +encryption key) are pointed to by \funcparam{seed}. Some checksum +algorithms may choose to ignore \funcparam{seed}. If +\funcparam{seed_length} is zero, then there is no seed available. +The routine places the resulting value into \funcparam{outcksum{\ptsto}contents}. + +\funcparam{outcksum{\ptsto}contents} must be set by the caller to point +to enough storage to contain the checksum; the size necessary is an +element of the \datatype{krb5_checksum_entry} structure. + +\subsection{Other data elements} +In addition to the above listed function entry point, each checksum algorithm +should have an entry in \globalname{krb5_cksumarray} and a +\datatype{krb5_checksum_entry} structure describing the entry points +and checksum size for the algorithm. diff --git a/mechglue/doc/implement/crc-32-i.tex b/mechglue/doc/implement/crc-32-i.tex new file mode 100644 index 000000000..c5d07a33d --- /dev/null +++ b/mechglue/doc/implement/crc-32-i.tex @@ -0,0 +1,20 @@ +The \libname{libcrc32.a} library provides an implementation of the +CRC-32 checksum algorithm which conforms to the interface required by +the Kerberos library. + +\begin{funcdecl}{crc32_sum_func}{static krb5_error_code}{\funcin} +\funcarg{krb5_pointer}{in} +\funcarg{size_t}{in_length} +\funcarg{krb5_pointer}{seed} +\funcarg{size_t}{seed_length} +\funcout +\funcarg{krb5_checksum *}{outcksum} +\end{funcdecl} + +This routine computes a CRC-32 checksum over \funcparam{in_length} bytes +at \funcparam{in}, and places the resulting value into +\funcparam{outcksum{\ptsto}contents}. \funcparam{seed} is ignored. + +\funcparam{outcksum{\ptsto}contents} must be set by the caller to point +to at least 4 bytes of storage. + diff --git a/mechglue/doc/implement/encrypt-i.tex b/mechglue/doc/implement/encrypt-i.tex new file mode 100644 index 000000000..57e8c833a --- /dev/null +++ b/mechglue/doc/implement/encrypt-i.tex @@ -0,0 +1,164 @@ +Kerberos v5 has the ability to use multiple encryption systems. Any +encryption system which desires to link with and be usable from the MIT +Kerberos v5 implementation must implement at least this interface: + +\subsection{Functional interface} + +\begin{funcdecl}{encrypt_func}{krb5_error_code}{\funcvoid} +\funcarg{krb5_const_pointer}{in} +\funcarg{krb5_pointer}{out} +\funcarg{const size_t}{size} +\funcarg{krb5_encrypt_block *}{eblock} +\funcarg{krb5_pointer}{ivec} +\end{funcdecl} +Encrypts \funcparam{size} bytes at \funcparam{in}, storing result in +\funcparam{out}. \funcparam{eblock} points to an encrypt block which +has been initialized by \funcname{process_key}. + +\funcparam{in} must include sufficient space beyond the \funcparam{size} +bytes of input data to hold pad and redundancy check bytes; the macro +\funcname{krb5_encrypt_size} can be used to compute this size. + +\funcparam{out} must be preallocated by the caller to contain sufficient +storage to hold the output; the macro \funcname{krb5_encrypt_size} can +be used to compute this size. + +\funcparam{ivec} points to an initial vector/seed to be used in the encryption. +If null, the cryptosystem may choose an appropriate initialization vector. + +%Errors: Returns errors. + +\begin{funcdecl}{decrypt_func}{krb5_error_code}{\funcvoid} +\funcarg{krb5_const_pointer}{in} +\funcarg{krb5_pointer}{out} +\funcarg{const size_t}{size} +\funcarg{krb5_encrypt_block *}{eblock} +\funcarg{krb5_pointer}{ivec} +\end{funcdecl} +Decrypts \funcparam{size} bytes at \funcparam{in}, storing result in +\funcparam{out}. +\funcparam{eblock} points to an encrypt block which has been initialized +by \funcname{process_key}. + +\funcparam{size} must be a multiple of the encryption block size. + +\funcparam{out} must be preallocated by the caller to contain sufficient +storage to hold the output; this is guaranteed to be no more than +the input size. + +\funcparam{ivec} points to an initial vector/seed to be used in the decryption. +If null, the cryptosystem may choose an appropriate ivec. + +%Errors: Returns errors. + +\begin{funcdecl}{process_key}{krb5_error_code}{\funcvoid} +\funcarg{krb5_encrypt_block *}{eblock} +\funcarg{const krb5_keyblock *}{keyblock} +\end{funcdecl} +Does any necessary key preprocessing (such as computing key +schedules for DES). +\funcparam{eblock{\ptsto}crypto_entry} must be set by the caller; the +other elements of \funcparam{eblock} are to be assigned by this function. +[In particular, \funcparam{eblock{\ptsto}key} must be set by this +function if the key is needed in raw form by the encryption routine.] + +The caller may not move or reallocate \funcparam{keyblock} before calling +\funcname{finish_key} on \funcparam{eblock}. + +%Errors: Returns errors. + +\begin{funcdecl}{finish_key}{krb5_error_code}{\funcvoid} +\funcarg{krb5_encrypt_block *}{eblock} +\end{funcdecl} +Does any necessary clean-up on \funcparam{eblock} (such as releasing +resources held by \funcparam{eblock{\ptsto}priv}. + +%Errors: Returns errors. + +\begin{funcdecl}{string_to_key}{krb5_error_code}{\funcvoid} +\funcarg{const krb5_keytype}{keytype} +\funcarg{krb5_keyblock *}{keyblock} +\funcarg{const krb5_data *}{data} +\funcarg{const krb5_data}{salt} +\end{funcdecl} +Converts the string pointed to by \funcparam{data} into an encryption key +of type \funcparam{keytype}. \funcparam{*keyblock} is filled in with +the key info; in particular, \funcparam{keyblock{\ptsto}contents} is to +be set to allocated storage. It is the responsibility of the caller to +release this storage when the generated key no longer needed. + +The routine may use \funcparam{salt} to seed or alter the conversion +algorithm. + +If the particular function called does not know how to make a +key of type \funcparam{keytype}, an error may be returned. + +%Errors: Returns errors. + +\begin{funcdecl}{init_random_key}{krb5_error_code}{\funcvoid} +\funcarg{const krb5_keyblock *}{seedblock} +\funcarg{krb5_pointer *}{seed} +\end{funcdecl} + +Initialize the random key generator using the encryption key +\funcparam{seedblock} and allocating private sequence information, filling +in \funcparam{*seed} with the address of such information. +\funcparam{*seed} is to be passed to \funcname{random_key} to provide +sequence information. + +\begin{funcdecl}{finish_random_key}{krb5_error_code}{\funcvoid} +\funcarg{krb5_pointer *}{seed} +\end{funcdecl} + +Free any resources held by \funcparam{seed} and assigned by +\funcname{init_random_key}. + +\begin{funcdecl}{random_key}{krb5_error_code}{\funcvoid} +\funcarg{krb5_pointer *}{seed} +\funcarg{krb5_keyblock **}{keyblock} +\end{funcdecl} + +Generate a random encryption key, allocating storage for it and +filling in the keyblock address in \funcparam{*keyblock}. +When the caller has finished using the keyblock, he should call +\funcname{krb5_free_keyblock} to release its storage. + +%\begin{funcdecl}{combine_keys}{krb5_error_code}{\funcin} +%\funcarg{const krb5_keyblock *}{key1} +%\funcarg{const krb5_keyblock *}{key2} +%\funcout +%\funcarg{krb5_keyblock **}{outkey} +%\end{funcdecl} +%Combine the two encryption keys \funcparam{key1} and \funcparam{key2} to +%generate a new output key \funcparam{outkey}. \funcparam{outkey} is +%filled in to point to the freshly-allocated key. When the caller is +%finished using the \funcparam{*outkey}, it should be freed with +%\funcname{krb5_free_keyblock}. + +\subsection{Other data elements} +In addition to the above listed function entry points, each encryption +system should have an entry in \globalname{krb5_csarray} and a +\datatype{krb5_cryptosystem_entry} structure describing the entry points +and key and padding sizes for the encryption system. + +\subsection{DES functions} +The DES functions conform to the encryption interface required by the +Kerberos version 5 library, and provide an encryption mechanism based on +the DES Cipher-block chaining mode (CBC), with the addition of a +cyclical redundancy check (CRC-32) for integrity checking upon +decryption. + +The functions have the same signatures as those described by the main +library document; the names are: +{\obeylines +\funcname{mit_des_encrypt_func} +\funcname{mit_des_decrypt_func} +\funcname{mit_des_process_key} +\funcname{mit_des_finish_key} +\funcname{mit_des_string_to_key} +\funcname{mit_des_init_random_key} +\funcname{mit_des_finish_random_key} +\funcname{mit_des_random_key} +} +The \datatype{krb5_cryptosystem_entry} for this cryptosystem is +\globalname{mit_des_cryptosystem_entry}. diff --git a/mechglue/doc/implement/fancyheadings.sty b/mechglue/doc/implement/fancyheadings.sty new file mode 100644 index 000000000..a71de0fb5 --- /dev/null +++ b/mechglue/doc/implement/fancyheadings.sty @@ -0,0 +1,233 @@ +% fancyheadings.sty version 1.0 +% Fancy headers and footers. +% Piet van Oostrum, Dept of Computer Science, University of Utrecht +% Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands +% Telephone: +31-30-531806. piet@cs.ruu.nl (mcvax!hp4nl!ruuinf!piet) +% March, 1989. + +% Here is a documentstylestyle option that allows you to customize your +% page headers and footers in an easy way. It combines features that were +% separately available in other pagestyles, without introducing much +% complexity. You can define: +% - three-part headers and footers +% - rules in header and footer +% - headers and footers wider than \textwidth +% - multiline headers and footers +% - separate headers and footers for even and odd pages +% - separate headers and footers for chapter pages +% +% To use this pagestyle, you must include the ``fancyheadings'' style +% option in your \documentstyle, and issue the \pagestyle{fancy} command. +% The \pagestyle{fancy} command should be issued after any changes made to +% \textwidth. +% +% The page layout will be as follows: +% +% LHEAD CHEAD RHEAD +% ----------------------------------- (rule) +% +% page body +% +% +% ----------------------------------- (rule) +% LFOOT CFOOT RFOOT +% +% The L-fields will be leftadjusted, the C-fields centered and the +% R-fields rightadjusted. +% Each of the six fields and the two rules can be defined separately. +% +% Simple use: +% +% The header and footer fields can be defined by commands \lhead{LHEAD} +% and so on for the other fields. If the field depends on something in the +% document (e.g. section titles) you must in general use the \markboth and +% \markright commands, otherwise a title may end on the wrong page. You +% can do this e.g. by redefining the commands \chaptermark, \sectionmark +% and so on (see example below). The defaults for these marks are as in +% the standard pagestyles. The marks can be put into a header or footer +% field by referencing \leftmark and \rightmark. +% +% Rules in header and footer +% +% The thickness of the rules below the header and above the footer can be +% changed by redefining the length parameters \headrulewidth (default +% 0.4pt) and \footrulewidth (default 0). These may be redefined by the +% \setlength command. A thickness of 0pt makes the rule invisible. +% If you want to make more complicated changes, you have to redefine the +% commands \headrule and/or \footrule. +% +% Headers and footers wider than \textwidth +% +% The headers and footers are set in a box of width \headwidth. The +% default for this is the value of \textwidth. You can make it wider (or +% smaller) by redefining \headwidth with the \setlength or \addtolength +% command. The headers and footers will stick out the page on the same +% side as the marginal notes. For example to include the marginal notes, +% add both \marginparsep and \marginparwidth to \headwidth (see also the +% example below). +% +% Multiline headers and footers +% +% Each of the six fields is set in an appropriate parbox, so you can put a +% multiline part in it with the \\ command. It is also possible to put +% extra space in it with the \vspace command. Note that if you do this you +% will probably have to increase the \headheight or \footskip lengths. +% +% Separate headers and footers for even and odd pages +% +% If you want the headers and footers to be different on even- and +% odd-numbered pages in the ``twoside'' style, the field-defining macros +% can be given an optional argument, to be used on the even-numbered +% pages, like \lhead[EVEN-LHEAD]{ODD-RHEAD}. +% +% Separate headers and footers for chapter pages +% +% LaTeX gives a \thispagestyle{plain} command for the first page of the +% document, the first page of each chapter and a couple of other pages. It +% might be incompatible with your pagestyle. In this case you can use a +% slightly different version of the pagestyle, called \pagestyle{fancyplain}. +% This pagestyle redefines the pagestyle ``plain'' to also use pagestyle +% ``fancy'' with the following modifications: +% - the thicknesses of the rules is defined by \plainheadrulewidth and +% \plainfootrulewidth (both default 0). +% - the 6 fields may be defined separately for the plain pages by +% giving them the value \fancyplain{PLAIN-VALUE}{NORMAL-VALUE}. This +% construct may be used in both the optional argument and the normal +% argument. Thus \lhead[\fancyplain{F1}{F2}]{\fancyplain{F3}{F4}} +% specifies the LHEAD value in a two-sided document: +% F1 on an even-numbered ``plain'' page +% F2 on an even-numbered normal page +% F3 on an odd-numbered ``plain'' page +% F4 on an odd-numbered normal page. +% +% Defaults: +% +% \headrulewidth 0.4pt +% \footrulewidth 0pt +% \plainheadrulewidth 0pt +% \plainfootrulewidth 0pt +% +% \lhead[\fancyplain{}{\sl\rightmark}]{\fancyplain{}{\sl\leftmark}} +% % i.e. empty on ``plain'' pages \rightmark on even, \leftmark on odd pages +% \chead{} +% \rhead[\fancyplain{}{\sl\leftmark}]{\fancyplain{}{\sl\rightmark}} +% % i.e. empty on ``plain'' pages \leftmark on even, \rightmark on odd pages +% \lfoot{} +% \cfoot{\rm\thepage} % page number +% \rfoot{} +% +% Examples: +% +% To put two lines containing the section title and the subsection title +% in the righthandside corner, use: +% +% \documentstyle[fancyheadings]{article} +% \pagestyle{fancy} +% \renewcommand{\sectionmark}[1]{\markboth{#1}{}} +% \renewcommand{\subsectionmark}[1]{\markright{#1}} +% \rfoot{\leftmark\\\rightmark} +% +% The following definitions give an approximation of the style used in the +% LaTeX book: +% +% \documentstyle[fancyheadings]{book} +% \pagestyle{fancyplain} +% \addtolength{\headwidth}{\marginparsep} +% \addtolength{\headwidth}{\marginparwidth} +% \renewcommand{\chaptermark}[1]{\markboth{#1}{#1}} % remember chapter title +% \renewcommand{\sectionmark}[1]{\markright{\thesection\ #1}} +% % section number and title +% \lhead[\fancyplain{}{\bf\thepage}]{\fancyplain{}{\bf\rightmark}} +% \rhead[\fancyplain{}{\bf\leftmark}]{\fancyplain{}{\bf\thepage}} +% \cfoot{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\def\lhead{\@ifnextchar[{\@xlhead}{\@ylhead}} +\def\@xlhead[#1]#2{\gdef\@elhead{#1}\gdef\@olhead{#2}} +\def\@ylhead#1{\gdef\@elhead{#1}\gdef\@olhead{#1}} + +\def\chead{\@ifnextchar[{\@xchead}{\@ychead}} +\def\@xchead[#1]#2{\gdef\@echead{#1}\gdef\@ochead{#2}} +\def\@ychead#1{\gdef\@echead{#1}\gdef\@ochead{#1}} + +\def\rhead{\@ifnextchar[{\@xrhead}{\@yrhead}} +\def\@xrhead[#1]#2{\gdef\@erhead{#1}\gdef\@orhead{#2}} +\def\@yrhead#1{\gdef\@erhead{#1}\gdef\@orhead{#1}} + +\def\lfoot{\@ifnextchar[{\@xlfoot}{\@ylfoot}} +\def\@xlfoot[#1]#2{\gdef\@elfoot{#1}\gdef\@olfoot{#2}} +\def\@ylfoot#1{\gdef\@elfoot{#1}\gdef\@olfoot{#1}} + +\def\cfoot{\@ifnextchar[{\@xcfoot}{\@ycfoot}} +\def\@xcfoot[#1]#2{\gdef\@ecfoot{#1}\gdef\@ocfoot{#2}} +\def\@ycfoot#1{\gdef\@ecfoot{#1}\gdef\@ocfoot{#1}} + +\def\rfoot{\@ifnextchar[{\@xrfoot}{\@yrfoot}} +\def\@xrfoot[#1]#2{\gdef\@erfoot{#1}\gdef\@orfoot{#2}} +\def\@yrfoot#1{\gdef\@erfoot{#1}\gdef\@orfoot{#1}} + +\newdimen\headrulewidth +\newdimen\footrulewidth +\newdimen\plainheadrulewidth +\newdimen\plainfootrulewidth +\newdimen\headwidth +\newif\if@fancyplain \@fancyplainfalse +\def\fancyplain#1#2{\if@fancyplain#1\else#2\fi} + +% Initialization of the head and foot text. + +\headrulewidth 0.4pt +\footrulewidth\z@ +\plainheadrulewidth\z@ +\plainfootrulewidth\z@ + +\lhead[\fancyplain{}{\sl\rightmark}]{\fancyplain{}{\sl\leftmark}} +% i.e. empty on ``plain'' pages \rightmark on even, \leftmark on odd pages +\chead{} +\rhead[\fancyplain{}{\sl\leftmark}]{\fancyplain{}{\sl\rightmark}} +% i.e. empty on ``plain'' pages \leftmark on even, \rightmark on odd pages +\lfoot{} +\cfoot{\rm\thepage} % page number +\rfoot{} + +% Put together a header or footer given the left, center and +% right text, fillers at left and right and a rule. +% The \lap commands put the text into an hbox of zero size, +% so overlapping text does not generate an errormessage. + +\def\@fancyhead#1#2#3#4#5{#1\hbox to\headwidth{\vbox{\hbox +{\rlap{\parbox[b]{\headwidth}{\raggedright#2\strut}}\hfill +\parbox[b]{\headwidth}{\centering#3\strut}\hfill +\llap{\parbox[b]{\headwidth}{\raggedleft#4\strut}}}\headrule}}#5} + + +\def\@fancyfoot#1#2#3#4#5{#1\hbox to\headwidth{\vbox{\footrule +\hbox{\rlap{\parbox[t]{\headwidth}{\raggedright#2\strut}}\hfill +\parbox[t]{\headwidth}{\centering#3\strut}\hfill +\llap{\parbox[t]{\headwidth}{\raggedleft#4\strut}}}}}#5} + +\def\headrule{{\if@fancyplain\headrulewidth\plainheadrulewidth\fi +\hrule\@height\headrulewidth\@width\headwidth \vskip-\headrulewidth}} + +\def\footrule{{\if@fancyplain\footrulewidth\plainfootrulewidth\fi +\vskip-0.3\normalbaselineskip\vskip-\footrulewidth +\hrule\@width\headwidth\@height\footrulewidth\vskip0.3\normalbaselineskip}} + +\def\ps@fancy{ +\let\@mkboth\markboth +\@ifundefined{chapter}{\def\sectionmark##1{\markboth +{\uppercase{\ifnum \c@secnumdepth>\z@ + \thesection\hskip 1em\relax \fi ##1}}{}} +\def\subsectionmark##1{\markright {\ifnum \c@secnumdepth >\@ne + \thesubsection\hskip 1em\relax \fi ##1}}} +{\def\chaptermark##1{\markboth {\uppercase{\ifnum \c@secnumdepth>\m@ne + \@chapapp\ \thechapter. \ \fi ##1}}{}} +\def\sectionmark##1{\markright{\uppercase{\ifnum \c@secnumdepth >\z@ + \thesection. \ \fi ##1}}}} +\def\@oddhead{\@fancyhead\relax\@olhead\@ochead\@orhead\hss} +\def\@oddfoot{\@fancyfoot\relax\@olfoot\@ocfoot\@orfoot\hss} +\def\@evenhead{\@fancyhead\hss\@elhead\@echead\@erhead\relax} +\def\@evenfoot{\@fancyfoot\hss\@elfoot\@ecfoot\@erfoot\relax} +\headwidth\textwidth} +\def\ps@fancyplain{\ps@fancy \let\ps@plain\ps@plain@fancy} +\def\ps@plain@fancy{\@fancyplaintrue\ps@fancy} diff --git a/mechglue/doc/implement/fixunder.sty b/mechglue/doc/implement/fixunder.sty new file mode 100644 index 000000000..b7ae58dbf --- /dev/null +++ b/mechglue/doc/implement/fixunder.sty @@ -0,0 +1,48 @@ +% fixunder.sty, 31 May 1990, John T. Kohl +% +% The contents of this file are in the public domain. +% +% +% play games with _ to make it active and to provide a reasonable _ +% character (from \tt in most cases), and a discretionary word-break point. + +% +% Some \makeunder... macros for convenience in setting catcodes. +% +\def\makeunderactive{\catcode`\_=\active\relax} +\def\makeunderother{\catcode`\_=12\relax} +\def\makeunderletter{\catcode`\_=11\relax} +\def\makeundernormal{\catcode`\_=8\relax} +\makeunderother +\def\cctwlunder{_} + +% +% The hair here is to allow things like \index to work reasonably with +% the new definition of underscore when the argument to index is part of +% a macro replacement and as such gets tokenized before \index is +% evaluated. +% [in the normal case at top-level, \index{foo_bar} works since \index +% does some hair to make _ into a reasonable character code, and \index +% does NOT use a macro expansion. If you have something like +% \def\foo#1#2{\index{#1} bar #2} +% then \foo{baz_quux}{frobnitz} will result in baz_quux getting +% tokenized BEFORE \foo is expanded, so that the catcode hair in \index +% is to no avail.] +% +% \underrealfalse declares that you want to replace with the \tt _; +% \underrealtrue declares that you want to replace with \char95 (ASCII _). +% +% for things like \index which write things out to files, set +% \underrealfalse before evaluating the \index macro, and what actually +% gets written to the file is an _, rather than something like +% {\leavemode \kern... } (the typical definition of \_). +% +% the above example would then be +% \def\foo#1#2{\underrealfalse\index{#1}\underrealtrue bar #2} +% + +\newif\ifunderreal +\underrealfalse +\makeunderactive +\def_{\ifunderreal\cctwlunder\else\leavevmode {\tt \cctwlunder}\discretionary{}{}{}\fi} +\let\_=_ diff --git a/mechglue/doc/implement/functions.sty b/mechglue/doc/implement/functions.sty new file mode 100644 index 000000000..a3165f811 --- /dev/null +++ b/mechglue/doc/implement/functions.sty @@ -0,0 +1,70 @@ +% +% definitions related to function declarations/displays +% +\ifx\undefined\@psfonts +\def\argfont{\tt} +\else +\font\argfont = pcrb +\hyphenchar\argfont = -1 +\fi +\let\funcfont=\bf +\newcount\argc@ount +%\setlength{\marginparsep}{0.05in} +%\setlength{\marginparwidth}{1.45in} +% +% This function fixes up the function name to be displayed in the +% margin so that the krb5_, if any, is stripped. +% +% Note: this is a hack; what's really happening is that name beginning with +% krb5 will have its first five characters stripped from it. +% This means that 'Krb5abc' will get rewritten to be 'bc'. +% Unfortunately, we can't do better because of the underscore +% hacks that are going on elsewhere. +% +% WARNING: This is ugly; don't look at it too soon after lunch! +% [tytso:19900920.2231EDT] +\newif\if@krbfunc +\def\endkrb{} +\def\fix@parname#1{\expandafter\parse@krb#1\endkrb% +\endkrb\endkrb\endkrb\endkrb}% In case the argument is less +% than five letters, we don't want to +% lose on the argument parsing. +\def\parse@krb#1#2#3#4#5#6\endkrb{\@krbfuncfalse% +\if#1k\if#2r\if#3b\if#45\@krbfunctrue\fi\fi\fi\fi% +\if@krbfunc#6\else#1#2#3#4#5#6\fi} +% +% funcdecl is used as \begin{funcdecl}{funcname}{return type}{firstline} +% +% see fixunder.sty for comments on why the \underrealtrue & \underrealfalse +% stuff is here. +\newenvironment{funcdecl}[3]{\underrealtrue\index{#1}\underrealfalse% +\medbreak +\gdef\funcn@me{#1} +\argc@ount=0\noindent% +%the \mbox{} is to prevent the line/paragraph breaking from eating the +%fill space. +\marginpar[{{\sloppy \hfil\fix@parname{\funcn@me}\hfill\mbox{}}}]% +{{\sloppy \hfill\fix@parname{\funcn@me}\hfil\mbox{}}}% +\vbox\bgroup\begin{minipage}[t]{\textwidth}\begin{tabbing} +#2 \\ +{\bf #1}(\= \+ #3% +}{) +\end{tabbing}\vfil\end{minipage}\egroup\par\nopagebreak +} +\newcommand{\docomm@}{\ifnum\argc@ount >0, \\\fi} +\newcommand{\funcvoid}{\argc@ount=0} +\newcommand{\funcin}{\docomm@\argc@ount=0{\sl /* IN */}\\} +\newcommand{\funcinout}{\docomm@\argc@ount=0{\sl /* IN/OUT */}\\} +\newcommand{\funcout}{\docomm@\argc@ount=0{\sl /* OUT */}\\} +\newcommand{\funcarg}[2]{\docomm@#1 {\argfont #2}\advance\argc@ount by1} +\newcommand{\funcparam}[1]{{\argfont #1}} +\newcommand{\funcfuncarg}[2]{\docomm@#1 {\argfont #2}(\= \+ \argc@ount=0} +\newcommand{\funcendfuncarg}{), \- \\ \argc@ount=0} +\newcommand{\libname}[1]{{\argfont #1}} +\newcommand{\globalname}[1]{{\argfont #1}} +\newcommand{\ptsto}{->\discretionary{}{}{}} +\newcommand{\datatype}[1]{{\bf #1}} +\newcommand{\filename}[1]{{\sl #1\/}} + +\newcommand{\funcname}[1]{\underrealtrue\index{#1}\underrealfalse{\funcfont #1}()} +\newcommand{\funcnamenoparens}[1]{\underrealtrue\index{#1}\underrealfalse{\funcfont #1}} diff --git a/mechglue/doc/implement/implement.tex b/mechglue/doc/implement/implement.tex new file mode 100644 index 000000000..7b709f56f --- /dev/null +++ b/mechglue/doc/implement/implement.tex @@ -0,0 +1,94 @@ +\documentstyle[fixunder,functions,twoside,fancyheadings]{article} +\setlength{\oddsidemargin}{0in} +\setlength{\evensidemargin}{2.00in} +\setlength{\marginparsep}{0.05in} +\setlength{\marginparwidth}{1.95 in} +\setlength{\textwidth}{4.75in} +\setlength{\topmargin}{-.5in} +\setlength{\textheight}{9in} +\setlength{\parskip}{.1in} +\setlength{\parindent}{2em} +\setlength{\footrulewidth}{0.4pt} +\setlength{\plainfootrulewidth}{0.4pt} +\setlength{\plainheadrulewidth}{0.4pt} +\makeindex +\newif\ifdraft +\draftfalse +% +% Far, far too inconvenient... it's still very draft-like anyway.... +% [tytso:19900921.0018EDT] +% +%\typein{Draft flag? (type \noexpand\draftfalse if not draft...)} +\ifdraft +\pagestyle{fancyplain} +\addtolength{\headwidth}{\marginparsep} +\addtolength{\headwidth}{\marginparwidth} +\makeatletter +\renewcommand{\sectionmark}[1]{\markboth {\uppercase{\ifnum \c@secnumdepth >\z@ + \thesection\hskip 1em\relax \fi #1}}{}}% +\renewcommand{\subsectionmark}[1]{\markright {\ifnum \c@secnumdepth >\@ne + \thesubsection\hskip 1em\relax \fi #1}} +\makeatother +\lhead[\thepage]{\fancyplain{}{\sl\rightmark}} +\rhead[\fancyplain{}{\sl\rightmark}]{\thepage} +\lfoot[]{{\bf DRAFT---DO NOT REDISTRIBUTE}} +\rfoot[{\bf DRAFT---DO NOT REDISTRIBUTE}]{} +\cfoot{\thepage} +\else\pagestyle{headings}\fi + +%nlg- time to make this a real document + +\title{\Huge Kerberos V5 Implementer's Guide} +\date{\ifdraft \\ {\Large DRAFT---}\fi\today} +\author{MIT Information Systems} + +\begin{document} +\maketitle +\tableofcontents + +\section{Introduction} + + This document is designed to aide the programmer who plans to +change MIT's implementation of Kerberos significantly. It is geared towards +programmers who are already familiar with Kerberos and how MIT's +implementation is structured. + + Some of the more basic information needed can be found in the +API document, although many functions have been repeated where +additional information has been included for the implementer. The +function descriptions included are up to date, even if the description +of the functions may not be very verbose. + +\ifdraft\sloppy\fi + +\section{Cache and Key table functions} + +\subsection{Credentials cache functions} +\input{ccache-i.tex} + +\subsection{Replay cache functions} +\input{rcache-i.tex} + +\subsection{Key table functions} +\input{keytab-i.tex} + +\section{Operating-system specific functions} +\input{libos-i.tex} + +\section{Principal database functions} + +\input{kdb-i.tex} + +\section{Encryption system interface} +\input{encrypt-i.tex} + +\section{Checksum interface} +\input{cksum-i.tex} + +\section{CRC-32 checksum functions} +\input{crc-32-i.tex} + +\appendix +\cleardoublepage +\input{\jobname.ind} +\end{document} diff --git a/mechglue/doc/implement/kdb-i.tex b/mechglue/doc/implement/kdb-i.tex new file mode 100644 index 000000000..dc81971bb --- /dev/null +++ b/mechglue/doc/implement/kdb-i.tex @@ -0,0 +1,242 @@ +The \libname{libkdb.a} library provides a principal database interface +to be used by the Key Distribution center and other database +manipulation tools. + + +\begin{funcdecl}{krb5_db_set_name}{krb5_error_code}{\funcin} +\funcarg{char *}{name} +\end{funcdecl} + +Set the name of the database to \funcparam{name}. +%Errors: If it doesn't exist, an error code is returned. + +Must be called before \funcname{krb5_db_init} or after +\funcname{krb5_db_fini}; must not be called while db functions are active. + +\begin{funcdecl}{krb5_db_set_nonblocking}{krb5_error_code}{\funcin} +\funcarg{krb5_boolean}{newmode} +\funcout +\funcarg{krb5_boolean *}{oldmode} +\end{funcdecl} + +Changes the locking mode of the database functions, returning the previous +mode in \funcparam{*oldmode}. + +If \funcparam{newmode} is TRUE, then the database is put into +non-blocking mode, which may result in ``database busy'' error codes from +the get, put, and iterate routines. + +If \funcparam{newmode} is FALSE, then the database is put into blocking mode, +which may result in delays from the get, put and iterate routines. + +The default database mode is blocking mode. + +\begin{funcdecl}{krb5_db_init}{krb5_error_code}{\funcvoid} +\end{funcdecl} + +Called before using \funcname{krb5_db_get_principal}, +\funcname{krb5_db_put_principal}, \funcname{krb5_db_iterate}, and +\funcname{krb5_db_set_nonblocking}. + +Does any required initialization. + +%Errors: init errors, system errors. + +\begin{funcdecl}{krb5_db_fini}{krb5_error_code}{\funcvoid} +\end{funcdecl} + +Called after all database operations are complete, to perform any required +clean-up. + +%Errors: sysytem errors. + + +\begin{funcdecl}{krb5_db_get_age}{krb5_error_code}{\funcin} +\funcarg{char *}{db_name} +\funcout +\funcarg{time_t *}{age} +\end{funcdecl} + +Retrieves the age of the database \funcname{db_name} (or the current +default database if \funcname{db_name} is NULL). + +\funcparam{*age} is filled in in local system time units, and represents +the last modification time of the database. + +%Errors: system errors. + + +\begin{funcdecl}{krb5_db_create}{krb5_error_code}{\funcin} +\funcarg{char *}{db_name} +\end{funcdecl} + +Creates a new database named \funcname{db_name}. Will not create a +database by that name if it already exists. The database must be +populated by the caller by using \funcname{krb5_db_put_principal}. + +%Errors: db exists, system errors. + +\begin{funcdecl}{krb5_db_rename}{krb5_error_code}{\funcin} +\funcarg{char *}{source} +\funcarg{char *}{dest} +\end{funcdecl} +Renames the database \funcarg{source} to \funcarg{dest} + +Any database named \funcarg{dest} is destroyed. + +%Errors: system errors. + +\begin{funcdecl}{krb5_db_get_principal}{krb5_error_code}{\funcin} +\funcarg{krb5_principal}{searchfor} +\funcout +\funcarg{krb5_db_entry *}{entries} +\funcinout +\funcarg{int *}{nentries} +\funcout +\funcarg{krb5_boolean *}{more} +\end{funcdecl} + +Retrieves the principal records named by \funcparam{searchfor}. + +\funcparam{entries} must point to an array of \funcparam{*nentries} +krb5_db_entry structures. +At most \funcparam{*nentries} structures are filled in, and +\funcparam{*nentries} is modified to reflect the number actually returned. + +\funcparam{*nentries} must be at least one (1) when this function is called. + +\funcparam{*more} is set to TRUE if there are more records that wouldn't fit +in the available space, and FALSE otherwise. + +The principal structures filled in have pointers to allocated storage; +\funcname{krb5_db_free_principal} should be called with +\funcparam{entries} and \funcparam{*nentries} +in order to free this storage when no longer needed. + + +\begin{funcdecl}{krb5_db_free_principal}{void}{\funcin} +\funcarg{krb5_db_entry *}{entries} +\funcarg{int}{nentries} +\end{funcdecl} + +Frees allocated storage held by \funcparam{entries} as filled in by +\funcname{krb5_db_get_principal}. + + +\begin{funcdecl}{krb5_db_put_principal}{krb5_error_code}{\funcin} +\funcarg{krb5_db_entry *}{entries} +\funcarg{int *}{nentries} +\end{funcdecl} + +Stores the \funcparam{*nentries} principal structures pointed to by +\funcparam{entries} in the database. + +\funcparam{*nentries} is updated upon return to reflect the number of records +acutally stored; the first \funcparam{*nentries} records will have been +stored in the database. + +%Errors: Returns error code if not all entries were stored. + +\begin{funcdecl}{krb5_db_iterate}{krb5_error_code}{\funcin} +\funcfuncarg{krb5_error_code}{(*func)} +\funcarg{krb5_pointer}{} +\funcarg{krb5_db_entry *}{} +\funcendfuncarg +\funcarg{krb5_pointer}{iterate_arg} +\end{funcdecl} + +Iterates over the database, fetching every entry in an unspecified order +and calling \funcparam{(*func)}(\funcparam{iterate_arg}, +\funcparam{principal}) where \funcparam{principal} points to a record from the +database. + +If \funcparam{(*func)}() ever returns an error code, the iteration +should be +aborted and that error code is returned by this function. + +\begin{funcdecl}{krb5_db_store_mkey}{krb5_error_code}{\funcin} +\funcarg{char *}{keyfile} +\funcarg{krb5_principal}{mname} +\funcarg{krb5_keyblock *}{key} +\end{funcdecl} + +Put the KDC database master key into the file \funcparam{keyfile}. If +\funcparam{keyfile} is NULL, then a default file name derived from the +principal name \funcparam{mname} is used. + +\begin{funcdecl}{krb5_db_fetch_mkey}{krb5_error_code}{\funcin} +\funcarg{krb5_principal}{mname} +\funcarg{krb5_encrypt_block *}{eblock} +\funcarg{krb5_boolean}{fromkeyboard} +\funcarg{krb5_boolean}{twice} +\funcarg{krb5_data }{salt} +\funcinout +\funcarg{krb5_keyblock *}{key} +\end{funcdecl} + +Get the KDC database master key from somewhere, filling it into +\funcparam{*key}. +\funcparam{key{\ptsto}keytype} should be set to the desired key type. + +If \funcparam{fromkeyboard} is TRUE, then the master key is read as a password +from the user's terminal. In this case: +\funcparam{eblock} should point to a block with an appropriate +\funcname{string_to_key} function; if \funcparam{twice} is TRUE, the +password is read twice for verification; and if \funcparam{salt} is +non-NULL, it is used as the salt when converting the typed +password to the master key. + + +If \funcparam{fromkeyboard} is false, then the key is read from +a file whose name is derived from the principal name \funcparam{mname}. +Therefore, \funcparam{eblock}, \funcparam{twice} and \funcparam{salt} +are ignored. + + +\funcparam{mname} is the name of the key sought; this is often used by +\funcname{string_to_key} to aid in conversion of the password to a key. + +\begin{funcdecl}{krb5_kdb_encrypt_key}{krb5_error_code}{\funcin} +\funcarg{krb5_encrypt_block *}{eblock} +\funcarg{const krb5_keyblock *}{in} +\funcinout +\funcarg{krb5_encrypted_keyblock *}{out} +\end{funcdecl} + +Encrypt a key for storage in the database. \funcparam{eblock} is used +to encrypt the key in \funcparam{in} into \funcparam{out}; the storage +pointed to by \funcparam{*out} is allocated before use and should be +freed when the caller is finished with it. + +\begin{funcdecl}{krb5_kdb_decrypt_key}{krb5_error_code}{\funcin} +\funcarg{krb5_encrypt_block *}{eblock} +\funcarg{const krb5_encrypted_keyblock *}{in} +\funcinout +\funcarg{krb5_keyblock *}{out} +\end{funcdecl} + +Decrypt a key from storage in the database. \funcparam{eblock} is used +to decrypt the key in \funcparam{in} into \funcparam{out}; the storage +pointed to by \funcparam{*out} is allocated before use and should be +freed when the caller is finished with it. + +\begin{funcdecl}{krb5_db_setup_mkey_name}{krb5_error_code}{\funcin} +\funcarg{const}{char *keyname} +\funcarg{const}{char *realm} +\funcout +\funcarg{char **}{fullname} +\funcarg{krb5_principal *}{principal} +\end{funcdecl} + +Given a key name \funcparam{keyname} and a realm name \funcparam{realm}, +construct a principal which can be used to fetch the master key from the +database. This principal is filled into \funcparam{*principal}; +\funcparam{*principal} should be freed by \funcname{krb5_free_principal} +when the caller is finished. + +If \funcparam{keyname} is NULL, the default key name will be used. + +If \funcparam{fullname} is not NULL, it is set to point to a string +representation of the complete principal name; its storage may be freed +by calling \funcname{free} on \funcparam{*fullname}. + diff --git a/mechglue/doc/implement/keytab-i.tex b/mechglue/doc/implement/keytab-i.tex new file mode 100644 index 000000000..697728721 --- /dev/null +++ b/mechglue/doc/implement/keytab-i.tex @@ -0,0 +1,204 @@ +The key table functions deal with storing and retrieving service keys +for use by unattended services which participate in authentication exchanges. + +Keytab routines should all be atomic. Before a routine returns it +must make sure that all non-sharable resources it acquires are +released and in a consistent state. For example, an implementation is not +allowed to leave a file open for writing or to have a lock on a file. + +Note that all keytab implementations must support multiple concurrent +sequential scans. Another detail to note is that +the order of values returned from \funcname{get_next} is +unspecified and may be sorted to the implementor's convenience. + +\subsubsection{The krb5_kt_ops structure} +In order to implement a new key table type, the programmer should +declare a {\bf krb5_kt_ops} structure, and fill in the elements of the +structure appropriately, by implementing each of the key table +functions for the new key table type. + +In order to reduce the size of binary programs when static linking is +used, it is common to provide two \datatype{krb5_kt_ops} structures for +each key table type, one for reading only in which the pointers to the +add and delete functions are zero, and one for reading and writing. + +\begin{verbatim} +typedef struct _krb5_kt_ops { + char *prefix; + /* routines always present */ + krb5_error_code (*resolve)((char *, + krb5_keytab *)); + krb5_error_code (*get_name)((krb5_keytab, + char *, + int)); + krb5_error_code (*close)((krb5_keytab)); + krb5_error_code (*get)((krb5_keytab, + krb5_principal, + krb5_kvno, + krb5_keytab_entry *)); + krb5_error_code (*start_seq_get)((krb5_keytab, + krb5_kt_cursor *)); + krb5_error_code (*get_next)((krb5_keytab, + krb5_keytab_entry *, + krb5_kt_cursor *)); + krb5_error_code (*end_get)((krb5_keytab, + krb5_kt_cursor *)); + /* routines to be included on extended version (write routines) */ + krb5_error_code (*add)((krb5_keytab, + krb5_keytab_entry *)); + krb5_error_code (*remove)((krb5_keytab, + krb5_keytab_entry *)); +} krb5_kt_ops; +\end{verbatim} + +\subsubsection{Per-type functions that are always present} +The following entry points must be implemented for each type of +key table. However, \funcname{resolve}, \funcname{remove} and +\funcname{add} are only called by the key table glue code. +They are not called directly by the application. + + however, application programs are not expected to call +\funcname{resolve}, \funcname{remove}, +or \funcname{add} directly. + +\begin{funcdecl}{resolve}{krb5_error_code}{\funcin} +\funcarg{char *}{residual} +\funcout +\funcarg{krb5_keytab *}{id} +\end{funcdecl} + +Fills in \funcparam{*id} with a handle identifying the keytab with name +``residual''. The interpretation of ``residual'' is dependent on the +type of keytab. + +\begin{funcdecl}{get_name}{krb5_error_code}{\funcin} +\funcarg{krb5_keytab}{id} +\funcout +\funcarg{char *}{name} +\funcin +\funcarg{int}{namesize} +\end{funcdecl} + +\funcarg{name} is filled in with the first \funcparam{namesize} bytes of +the name of the keytab identified by \funcname{id}. +If the name is shorter than \funcparam{namesize}, then \funcarg{name} +will be null-terminated. + +\begin{funcdecl}{close}{krb5_error_code}{\funcin} +\funcarg{krb5_keytab}{id} +\end{funcdecl} + +Closes the keytab identified by \funcparam{id} and invalidates +\funcparam{id}, and releases any other resources acquired during use of +the key table. + +Requires that \funcparam{id} identifies a valid credentials cache. + +\begin{funcdecl}{get}{krb5_error_code}{\funcin} +\funcarg{krb5_keytab}{id} +\funcarg{krb5_principal}{principal} +\funcarg{krb5_kvno}{vno} +\funcout +\funcarg{krb5_keytab_entry *}{entry} +\end{funcdecl} + +Searches the keytab identified by \funcparam{id} for an entry whose +principal matches \funcparam{principal} and +whose key version number matches \funcparam{vno}. If \funcparam{vno} is +zero, the first entry whose principal matches is returned. + +%Errors: +This routine should return an error code if no suitable entry is +found. If an entry is found, the entry is returned in +\funcparam{*entry}; its contents should be deallocated by calling +\funcname{close} when no longer needed. + +\begin{funcdecl}{close}{krb5_error_code}{\funcinout} +\funcarg{krb5_keytab_entry *}{entry} +\end{funcdecl} + +Releases all storage allocated for \funcparam{entry}, which must point +to a structure previously filled in by \funcname{get} or +\funcname{get_next}. + +\begin{funcdecl}{start_seq_get}{krb5_error_code}{\funcin} +\funcarg{krb5_keytab}{id} +\funcout +\funcarg{krb5_kt_cursor *}{cursor} +\end{funcdecl} + +Prepares to read sequentially every key in the keytab identified by +\funcparam{id}. +\funcparam{cursor} is filled in with a cursor to be used in calls to +\funcname{get_next}. + +\begin{funcdecl}{get_next}{krb5_error_code}{\funcin} +\funcarg{krb5_keytab}{id} +\funcout +\funcarg{krb5_keytab_entry *}{entry} +\funcinout +\funcarg{krb5_kt_cursor}{cursor} +\end{funcdecl} + +Fetches the ``next'' entry in the keytab, returning it in +\funcparam{*entry}, and updates \funcparam{*cursor} for the next +request. If the keytab changes during the sequential get, an error +must be +%Errors: +guaranteed. \funcparam{*entry} should be freed after use by +calling +\funcname{close}. + +Requires that \funcparam{id} identifies a valid credentials cache. and +\funcparam{*cursor} be a cursor returned by +\funcname{start_seq_get} or a subsequent call to +\funcname{get_next}. + +%Errors: error code if no more cache entries or if the keytab changes. + +\begin{funcdecl}{end_get}{krb5_error_code}{\funcin} +\funcarg{krb5_keytab}{id} +\funcarg{krb5_kt_cursor *}{cursor} +\end{funcdecl} + +Finishes sequential processing mode and invalidates \funcparam{cursor}, +which must never be re-used after this call. + +Requires that \funcparam{id} identifies a valid credentials cache. and +\funcparam{*cursor} be a cursor returned by +\funcname{start_seq_get} or a subsequent call to +\funcname{get_next}. + +%Errors: May return error code if \funcparam{cursor} is invalid. + +\subsubsection{Per-type functions to be included for write routines} + +\begin{funcdecl}{add}{krb5_error_code}{\funcin} +\funcarg{krb5_keytab}{id} +\funcarg{krb5_keytab_entry *}{entry} +\end{funcdecl} + +Stores \funcparam{entry} in the keytab \funcparam{id}. +Fails if the entry already exists. + +This operation must, within the constraints of the operating system, not +return until it can verify that the write has completed succesfully. +For example, in a UNIX file-based implementation, this routine (or the part +of the underlying implementation that it calls) would be responsible for +doing an \funcname{fsync} on the file before returning. + +%Errors: +This routine should return an error code if \funcparam{entry} is +already present in the keytab or if the key could not be stored (quota +problem, etc). + +\begin{funcdecl}{remove}{krb5_error_code}{\funcin} +\funcarg{krb5_keytab}{id} +\funcarg{krb5_keytab_entry *}{entry} +\end{funcdecl} + +Searches the keytab \funcparam{id} for an entry that exactly matches +\funcparam{entry}. If one is found, it is removed from the keytab. + +%Errors: Returns an error code if not found. + diff --git a/mechglue/doc/implement/libos-i.tex b/mechglue/doc/implement/libos-i.tex new file mode 100644 index 000000000..cdd4861ff --- /dev/null +++ b/mechglue/doc/implement/libos-i.tex @@ -0,0 +1,34 @@ +The operating-system specific functions provide an interface between the +other parts of the \libname{libkrb5.a} libraries and the operating system. + +Beware! Any of the functions below are allowed to be implemented as +macros. Prototypes for functions can be found in {\tt +}; other definitions (including macros, if used) are +in {\tt }. + +The following global symbols are provided in \libname{libos.a}. If you +wish to substitute for any of them, you must substitute for all of them +(they are all declared and initialized in the same object file): +\begin{description} +% These come from src/lib/osconfig.c +\item[extern char *\globalname{krb5_config_file}:] name of configuration file +\item[extern char *\globalname{krb5_trans_file}:] name of hostname/realm +name translation file +\item[extern char *\globalname{krb5_defkeyname}:] default name of key +table file +\item[extern char *\globalname{krb5_lname_file}:] name of aname/lname +translation database +\item[extern int \globalname{krb5_max_dgram_size}:] maximum allowable +datagram size +\item[extern int \globalname{krb5_max_skdc_timeout}:] maximum +per-message KDC reply timeout +\item[extern int \globalname{krb5_skdc_timeout_shift}:] shift factor +(bits) to exponentially back-off the KDC timeouts +\item[extern int \globalname{krb5_skdc_timeout_1}:] initial KDC timeout +\item[extern char *\globalname{krb5_kdc_udp_portname}:] name of KDC UDP port +\item[extern char *\globalname{krb5_default_pwd_prompt1}:] first prompt +for password reading. +\item[extern char *\globalname{krb5_default_pwd_prompt2}:] second prompt + +\end{description} + diff --git a/mechglue/doc/implement/rcache-i.tex b/mechglue/doc/implement/rcache-i.tex new file mode 100644 index 000000000..e00a639da --- /dev/null +++ b/mechglue/doc/implement/rcache-i.tex @@ -0,0 +1,142 @@ +The replay cache functions deal with verifying that AP_REQ's do not +contain duplicate authenticators; the storage must be non-volatile for +the site-determined validity period of authenticators. + +Each replay cache has a string {\bf name} associated with it. The use of +this name is dependent on the underlying caching strategy (for +file-based things, it would be a cache file name). The +caching strategy should use non-volatile storage so that replay +integrity can be maintained across system failures. + +\subsubsection{The krb5_rc_ops structure} +In order to implement a new replay cache type, the programmer should +declare a {\bf krb5_rc_ops} structure, and fill in the elements of the +structure appropriately, by implementing each of the replay cache +functions for the new replay cache type. + +The prefix element specifies the prefix {bf name} of the the new replay +cache type. For example, if the prefix {\bf name} is ``dfl'', then if the +program calls \funcname{krb5_rc_resolve} with a credential cache name +such as ``dfl:host'', then \funcname{krb5_rc_resolve} +will call the resolve function (as defined by the {\bf krb5_rc_ops} +structure where the prefix element is ``dfl'') and pass it the +argument ``host''. + +Before a new replay cache type can be recognized by +\funcname{krb5_rc_resolve}, it must be registered with the Kerberos +library by calling \funcname{krb5_rc_register}. + +\begin{verbatim} +typedef struct _krb5_rc_ops { + char *type; + krb5_error_code (*init)((krb5_rcache,krb5_deltat)); + krb5_error_code (*recover)((krb5_rcache)); + krb5_error_code (*destroy)((krb5_rcache)); + krb5_error_code (*close)((krb5_rcache)); + krb5_error_code (*store)((krb5_rcache,krb5_donot_replay *)); + krb5_error_code (*expunge)((krb5_rcache)); + krb5_error_code (*get_span)((krb5_rcache,krb5_deltat *)); + char *(*get_name)((krb5_rcache)); + krb5_error_code (*resolve)((krb5_rcache, char *)); +} krb5_rc_ops; +\end{verbatim} + + +\subsubsection{Per-type functions} +The following entry points must be implemented for each type of +replay cache. + +\begin{funcdecl}{init}{krb5_error_code}{\funcin} +\funcarg{krb5_rcache}{id} +\funcarg{krb5_deltat}{auth_lifespan} +\end{funcdecl} + +Creates/refreshes the replay cache identified by \funcparam{id} and sets its +authenticator lifespan to \funcparam{auth_lifespan}. If the +replay cache already exists, its contents are destroyed. + +%Errors: permission errors, system errors + +\begin{funcdecl}{recover}{krb5_error_code}{\funcin} +\funcarg{krb5_rcache}{id} +\end{funcdecl} +Attempts to recover the replay cache \funcparam{id}, (presumably after a +system crash or server restart). + +%Errors: error indicating that no cache was found to recover + +\begin{funcdecl}{destroy}{krb5_error_code}{\funcin} +\funcarg{krb5_rcache}{id} +\end{funcdecl} + +Destroys the replay cache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + +%Errors: permission errors. + +\begin{funcdecl}{close}{krb5_error_code}{\funcin} +\funcarg{krb5_rcache}{id} +\end{funcdecl} + +Closes the replay cache \funcparam{id}, invalidates \funcparam{id}, +and releases any other resources acquired during use of the replay cache. +Requires that \funcparam{id} identifies a valid replay cache. + +%Errors: permission errors + +\begin{funcdecl}{store}{krb5_error_code}{\funcin} +\funcarg{krb5_rcache}{id} +\funcarg{krb5_donot_replay *}{rep} +\end{funcdecl} +Stores \funcparam{rep} in the replay cache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + +Returns KRB5KRB_AP_ERR_REPEAT if \funcparam{rep} is already in the +cache. May also return permission errors, storage failure errors. + +\begin{funcdecl}{expunge}{krb5_error_code}{\funcin} +\funcarg{krb5_rcache}{id} +\end{funcdecl} +Removes all expired replay information (i.e. those entries which are +older than then authenticator lifespan of the cache) from the cache +\funcparam{id}. Requires that \funcparam{id} identifies a valid replay +cache. + +%Errors: permission errors. + +\begin{funcdecl}{get_span}{krb5_error_code}{\funcin} +\funcarg{krb5_rcache}{id} +\funcout +\funcarg{krb5_deltat *}{auth_lifespan} +\end{funcdecl} +Fills in \funcparam{auth_lifespan} with the lifespan of +the cache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + +\begin{funcdecl}{resolve}{krb5_error_code}{\funcinout} +\funcarg{krb5_rcache}{id} +\funcin +\funcarg{char *}{name} +\end{funcdecl} + +Initializes private data attached to \funcparam{id}. This function MUST +be called before the other per-replay cache functions. + +Requires that \funcparam{id} points to allocated space, with an +initialized \funcparam{id{\ptsto}ops} field. + +Since \funcname{resolve} allocates memory, +\funcname{close} must be called to free the allocated memory, +even if neither \funcname{init} or +\funcname{recover} were successfully called by the application. + +%Returns: allocation errors. + + +\begin{funcdecl}{krb5_rc_get_name}{char *}{\funcin} +\funcarg{krb5_rcache}{id} +\end{funcdecl} + +Returns the name (excluding the type) of the rcache \funcparam{id}. +Requires that \funcparam{id} identifies a valid replay cache. + diff --git a/mechglue/doc/implementor.texinfo b/mechglue/doc/implementor.texinfo new file mode 100644 index 000000000..95b703076 --- /dev/null +++ b/mechglue/doc/implementor.texinfo @@ -0,0 +1,1192 @@ +\input texinfo @c -*-texinfo-*- +@c +@c Note: the above texinfo file must include the "doubleleftarrow" +@c definitions added by jcb. +@c %**start of header +@c guide +@setfilename krb5-implement.info +@settitle Kerberos V5 Installation Guide +@setchapternewpage odd @c chapter begins on next odd page +@c @setchapternewpage on @c chapter begins on next page +@c @smallbook @c Format for 7" X 9.25" paper +@c %**end of header + +@paragraphindent 0 +@iftex +@parskip 6pt plus 6pt +@end iftex + +@include definitions.texinfo +@c @set EDITION b7-1 +@set EDITION [working copy] + +@finalout @c don't print black warning boxes + +@titlepage +@title @value{PRODUCT} Implementor's Guide +@subtitle Release: @value{RELEASE} +@subtitle Document Edition: @value{EDITION} +@subtitle Last updated: @value{UPDATED} +@author @value{COMPANY} + +@page +@vskip 0pt plus 1filll + +@iftex +@include copyright.texinfo +@end iftex +@end titlepage + +@node Top, Introduction, (dir), (dir) +@comment node-name, next, previous, up + +@ifinfo +This file contains internal implementor's information for the +@value{RELEASE} release of @value{PRODUCT}. + +@include copyright.texinfo + +@end ifinfo + +@c The master menu is updated using emacs19's M-x texinfo-all-menus-update +@c function. Don't forget to run M-x texinfo-every-node-update after +@c you add a new section or subsection, or after you've rearranged the +@c order of sections or subsections. Also, don't forget to add an @node +@c comand before each @section or @subsection! All you need to enter +@c is: +@c +@c @node New Section Name +@c @section New Section Name +@c +@c M-x texinfo-every-node-update will take care of calculating the +@c node's forward and back pointers. +@c +@c --------------------------------------------------------------------- + +@menu +* Introduction:: +* Compiler and OS Requirements:: +* Networking:: +* Thread Safety:: +* Shared Libraries:: +* Porting Issues:: +@end menu + +@node Introduction, Compiler and OS Requirements, Top, Top +@chapter Introduction + +This file contains internal implementor's information for +@value{PRODUCT}. It is currently contains information that was removed +from install.texi; eventually it will have more detailed information on +the internals of the @value{PRODUCT}. + +@node Compiler and OS Requirements, Networking, Introduction, Top +@chapter Compiler and OS Requirements + +The basic Kerberos libraries are entirely written in C. +However, we do assume full ANSI C (1989) support, typical 32- or +64-bit twos-complement architectures (@code{char} is 8 bits, +@code{short} is 16 bits, @code{int} is 32 bits, byte order is 1234 or +4321), and a few aspects of ISO C 1999: + +@itemize @bullet +@item +support for inline functions, even if the keyword isn't @code{inline} +@item +64-bit arithmetic types (needed for sequence numbers in GSSAPI) +@end itemize + +These are handled through the internal header file +@file{k5-platform.h}. + +We also conditionally tailor code for the GNU C compiler in a few +places where it helps performance or debugging, but the code should +still work fine with other C compilers. + +On UNIX platforms, ... @i{(should outline what POSIX stuff we +require)}. + +See also @ref{Advanced Shared Library Requirements}, for UNIX and +Windows systems. + +Our makefiles are intended to support building from the top level with +a POSIX-compliant version of @code{make}, and parallel builds using +GNU @code{make}. The latter sometimes comes at the cost of efficiency with +non-GNU versions; for example, some targets in some directories will +always be rebuilt with certain versions of @code{make}, even though +the real dependencies are not out of date, because some versions of +@code{make} don't understand how we're using phony intermediate +targets to manage building in subdirectories in parallel builds. +(Actually, this is more my view of how we've been doing things than +official policy. ---Ken) + +@node Networking, Thread Safety, Compiler and OS Requirements, Top +@chapter Networking + +@menu +* Socket API:: +* IPv6 Support:: +* Local Addresses:: +* Host Address Lookup:: +@end menu + +@node Socket API, IPv6 Support, Networking, Networking +@section Socket API + +Someone should describe the API subset we're allowed to use with +sockets, how and when to use @code{SOCKET_ERRNO}, @i{etc}. + +Note that all new code doing hostname and address translation should +use @code{getaddrinfo} and friends. (@xref{Host Address Lookup}.) + +@node IPv6 Support, Local Addresses, Socket API, Networking +@section IPv6 Support + +Most of the IPv6 support is keyed on the macro @code{KRB5_USE_INET6}. +If this macro is not defined, there should be no references to +@code{AF_INET6}, @code{struct sockaddr_in6}, @i{etc}. + +The @code{configure} scripts will check for the existence of various +functions, macros and structure types to decide whether to enable the +IPv6 support. You can also use the @samp{--enable-ipv6} or +@samp{--disable-ipv6} options to override this decision. + +Regardless of the setting of @code{KRB5_USE_INET6}, some aspects of +the new APIs devised for IPv6 are used throughout the code, because it +would be too difficult maintain code for the IPv6 APIs and for the old +APIs at the same time. But for backwards compatibility, we try to +fake them if the system libraries don't provide them, at least for +now. This means we sometimes use slightly modified versions of the +APIs, but we try to keep the modifications as non-intrusive as +possible. Macros are used to rename struct tags and function names, +so don't @code{#undef} any of these names. + +@table @code + +@item getaddrinfo +@itemx getnameinfo +@itemx freeaddrinfo +@itemx gai_strerror +@itemx struct addrinfo +Always include the header file @file{fake-addrinfo.h} before using +these. If the native system doesn't provide them, the header file +will, using support functions that will call @code{gethostbyname} and +the like in the native libraries. (This is similar to how the Winsock +2 headers work, depending on some of the predefined macros indicating +the target OS version, though they define the support functions +directly in the header, as our code used to do.) + +We also provide ``wrapper'' versions on some systems where a native +implementation exists but the data it returns is broken in some way. + +So these may not always be thread-safe, and they may not always +provide IPv6 support, but the API will be consistent. + +@item struct sockaddr_storage +@itemx socklen_t +These are provided by @file{socket-utils.h}, if the native headers +don't provide them. @code{sockaddr_storage} contains a +@code{sockaddr_in}, so by definition it's big enough to hold one; it +also has some extra padding which will probably make it big enough to +hold a @code{sockaddr_in6} if the resulting binary should get run on a +kernel with IPv6 support. + +Question: Should these simply be moved into @file{port-sockets.h}? + +@end table + +IRIX 6.5.7 has no IPv6 support. Of the systems most actively in the +MIT's Athena environment (used by MIT's Kerberos UNIX developers), +this is the only one without built-in IPv6 support. In another year +or so we probably won't be using those systems any more, and we may +consider dropping support for systems without IPv6 support. + +Somewhere between IRIX 6.5.14 and 6.5.16, partial IPv6 support was +introduced to the extent that the configuration system detects the +IPv6 support and attempts to use it. Code compiles, but then upon +linking, one discovers that ``in6addr_any'' is not defined in any +system library. The header file @file{fake-addrinfo.h} provides a +static copy as a workaround. This run time IPv6 code has still not +been tested. + +Some utility functions or macros are also provided to give a +convenient shorthand for some operations, and to retain compile-time +type checking when possible (generally using inline functions but only +when compiling with GCC). + +@table @code + +@item socklen(struct sockaddr *) +Returns the length of the @code{sockaddr} structure, by looking at the +@code{sa_len} field if it exists, or by returning the known sizes of +@code{AF_INET} and @code{AF_INET6} address structures. + +@item sa2sin(struct sockaddr *) +@itemx sa2sin6(struct sockaddr *) +@itemx ss2sa(struct sockaddr_storage *) +@itemx ss2sin(struct sockaddr_storage *) +@itemx ss2sin6(struct sockaddr_storage *) +Pointer type conversions. Use these instead of plain casts, to get +type checking under GCC. + +@end table + +@node Local Addresses, Host Address Lookup, IPv6 Support, Networking +@section Local Addresses + +(Last update: 2005-04-21, but most of the information dates back to +early 2002.) + +Different systems have different ways of finding the local network +addresses. + +On Windows, @code{gethostbyname} is called on the local host name to get a +set of addresses. If that fails, a UDP socket is ``connected'' to a +particular IPv4 address, and the local socket name is retrieved, its +address being treated as the one local network address. Future +versions of the Windows code should be able to actually examine local +interfaces. + +On (most?) UNIX systems, there is an @code{ioctl} called +@code{SIOCGIFCONF} which gets interface configuration information. +The behavior of this @code{ioctl} varies across UNIX systems though. +It takes as input a buffer to fill with data structures, but if the +buffer isn't big enough, the behavior isn't well defined. Sometimes +you get an error, sometimes you get incomplete data. Sometimes you +get a clear indication that more space was needed, sometimes not. A +couple of systems have additional @code{ioctl}s that can be used to +determine or at least estimate the correct size for the buffer. In +Solaris, Sun has introduced @code{SIOCGLIFCONF} for querying IPv6 +addresses, and restricts @code{SIOCGIFCONF} to IPv4 only. (** We +should actually check if that's true.) They also added +@code{SIOCGIFNUM} and @code{SIOCGLIFNUM} for querying the number of +interfaces. HP-UX 11 also has @code{SIOCGLIFCONF}, but it requires a +different data structure, and we haven't finished that support yet. + +We (Ken Raeburn in particular) ran some tests on various systems to +see what would happen with buffers of various sizes from much smaller +to much larger than needed for the actual data. The buffers were +filled with specific byte values, and then checked to see how much of +the buffer was actually written to. The ``largest gap'' values listed +below are the largest number of bytes we've seen left unused at the +end of the supplied buffer when there were more entries to return. +These values may of coures be dependent on the configurations of the +particular systems we wre testing with. (See +@file{lib/krb5/os/t_gifconf.c} for the test program.) + +NetBSD 1.5-alpha: The returned @code{ifc_len} is the desired amount of +space, always. The returned list may be truncated if there isn't +enough room; no overrun. Largest gap: 43. However, NetBSD has +@code{getifaddrs}, which hides all the ugliness within the C library. + +BSD/OS 4.0.1 (courtesy djm): The returned @code{ifc_len} is equal to +or less than the supplied @code{ifc_len}. Sometimes the entire buffer +is used; sometimes N-1 bytes; occasionally, the buffer must have quite +a bit of extra room before the next structure will be added. Largest +gap: 39. + +Solaris 7,8,9: Return @code{EINVAL} if the buffer space is too small +for all the data to be returned, including when @code{ifc_len} is 0. +Solaris is the only system I've found so far that actually returns an +error. No gap. However, @code{SIOCGIFNUM} may be used to query the +number of interfaces. + +Linux 2.2.12 (Red Hat 6.1 distribution, x86), 2.4.9 (RH 7.1, x86): The +buffer is filled in with as many entries as will fit, and the size +used is returned in @code{ifc_len}. The list is truncated if needed, +with no indication. Largest gap: 31. @emph{However}, this interface +does not return any IPv6 addresses. They must be read from a file +under @file{/proc}. (This appears to be what the @samp{ifconfig} +program does.) + +IRIX 6.5.7: The buffer is filled in with as many entries as will fit +in N-1 bytes, and the size used is returned in @code{ifc_len}. +Providing exactly the desired number of bytes is inadequate; the +buffer must be @emph{bigger} than needed. (E.g., 32->0, 33->32.) The +returned @code{ifc_len} is always less than the supplied one. Largest +gap: 32. + +AIX 4.3.3: Sometimes the returned @code{ifc_len} is bigger than the +supplied one, but it may not be big enough for @emph{all} the +interfaces. Sometimes it's smaller than the supplied value, even if +the returned list is truncated. The list is filled in with as many +entries as will fit; no overrun. Largest gap: 143. + +Older AIX: We're told by W. David Shambroom in RT ticket 919 that +older versions of AIX have a bug in the @code{SIOCGIFCONF} +@code{ioctl} which can cause them to overrun the supplied buffer. +However, we don't yet have details as to which version, whether the +overrun amount was bounded (e.g., one @code{ifreq}'s worth) or not, +whether it's a real buffer overrun or someone assuming it was because +@code{ifc_len} was increased, @i{etc}. Once we've got details, we can +try to work around the problem. + +Digital UNIX 4.0F: If input @code{ifc_len} is zero, return an +@code{ifc_len} that's big enough to include all entries. (Actually, +on our system, it appears to be larger than that by 32.) If input +@code{ifc_len} is nonzero, fill in as many entries as will fit, and +set @code{ifc_len} accordingly. (Tested only with buffer previously +filled with zeros.) + +Tru64 UNIX 5.1A: Like Digital UNIX 4.0F, except the ``extra'' space +indicated when the input @code{ifc_len} is zero is larger. (We got +400 out when 320 appeared to be needed.) + +So... if the returned @code{ifc_len} is bigger than the supplied one, +we'll need at least that much space -- but possibly more -- to hold +all the results. If the returned value is a little smaller or the +same, we may still need more space. + +The heuristic we're using on most systems now is to keep growing the +buffer until the unused space is larger than an @code{ifreq} structure +by some safe margin. + +@node Host Address Lookup, , Local Addresses, Networking +@section Host Address Lookup + +The traditional @code{gethostbyname} function is not thread-safe, and +does not support looking up IPv6 addresses, both of which are becoming +more important. New standards have been in development that should +address both of these problems. The most promising is +@code{getaddrinfo} and friends, which is part of the Austin Group and +UNIX 98(?) specifications. Code in the MIT tree has mostly been +converted to use this interface. + +@quotation +(Question: What about @code{inet_ntop} and @code{inet_pton}? We're +not using them at the moment, but some bits of code would be +simplified if we were to do so, when plain addresses and not socket +addresses are already presented to us.) +@end quotation + +The @code{getaddrinfo} function takes a host name and service name and +returns a linked list of structures indicating the address family, +length, and actual data in ``sockaddr'' form. (That is, it includes a +pointer to a @code{sockaddr_in} or @code{sockaddr_in6} structure.) +Depending on options set via the @code{hints} input argument, the results +can be limited to a single address family (@i{e.g.}, for IPv4 +applications), and the canonical name of the indicated host can be +returned. Either the host or service can be a null pointer, in which +case only the other is looked up; they can also be expressed in +numeric form. This interface is extensible to additional address +families in the future. The returned linked list can be freed with +the @code{freeaddrinfo} function. + +The @code{getnameinfo} function does the reverse -- given an address +in ``sockaddr'' form, it converts the address and port values into +printable forms. + +Errors returned by either of these functions -- as return values, not +global variables -- can be translated into printable form with the +@code{gai_strerror} function. + +Some vendors are starting to implement @code{getaddrinfo} and friends, +however, some of the implementations are deficient in one way or +another. + +@table @asis + +@item AIX +As of AIX 4.3.3, @code{getaddrinfo} returns sockaddr structures +without the family and length fields filled in. + +@item GNU libc +The GNU C library, used on GNU/Linux systems, has had a few problems +in this area. One version would drop some IPv4 addresses for some +hosts that had multiple IPv4 and IPv6 addresses. + +In GNU libc 2.2.4, when the DNS is used, the name referred to by PTR +records for each of the addresses is looked up and stored in the +@code{ai_canonname} field, or the printed numeric form of the address +is, both of which are wrong. + +@item IRIX +No known bugs here, but as of IRIX 6.5.7, the version we're using at +MIT, these functions had not been implemented. + +@item Mac OS X +Two problems have been found with @code{getaddrinfo} on Mac OS X, at +least under version 10.3. First, while @code{gethostbyname} data is +cached to make multiple lookups of the same name (@i{e.g.}, by +different parts of the code that need to know about the same server +host), @code{getaddrinfo} results are not cached, so multiple queries +mean multiple DNS requests, which means more delays if the DNS servers +are not close by and fast to respond. We've implemented a cache of +our own to work around this, though it only applies to multiple +lookups in a short period of time within the same application process, +and it's only implemented for the Mac at the moment. + +Second, the Mac libraries will generate a DNS SRV RR query; as far as +I [Ken] can tell this is a bug, but Apple seems to consider it a +feature. (Call @code{getaddrinfo("example.com", "telnet", ...)} and +you get a SRV record query, but the spec on SRV records says you must +not use them unless the specification for the service in question says +to.) Yet more network traffic for each name to look up. + +@item NetBSD +As of NetBSD 1.5, this function is not thread-safe. In 1.5X +(intermediate code snapshot between 1.5 and 1.6 releases), the +@code{ai_canonname} field can be empty, even if the +@code{AI_CANONNAME} flag was passed. In particular, this can happen +if a numeric host address string is provided. Also, numeric service +names appear not to work unless the stream type is given; specifying +the TCP protocol is not enough. + +@item Tru64 UNIX +In Tru64 UNIX 5.0, @code{getaddrinfo} is available, but requires that +@code{} be included before its use; that header file defines +@code{getaddrinfo} as a macro expanding to either @code{ogetaddrinfo} +or @code{ngetaddrinfo}, and apparently the symbol @code{getaddrinfo} +is not present in the system library, causing the @code{configure} +test for it to fail. Technically speaking, I [Ken] think Compaq has +it wrong here, I think the symbol is supposed to be available even if +the application uses @code{#undef}, but I have not confirmed it in the +spec. + +@item Windows +According to Windows documentation, the returned @code{ai_canonname} +field can be null even if the @code{AI_CANONNAME} flag is given. + +@end table + +For most systems where @code{getaddrinfo} returns incorrect data, +we've provided wrapper versions that call the system version and then +try to fix up the returned data. + +For systems that don't provide these functions at all, we've provided +replacement versions that neither are thread-safe nor support IPv6, +but will allow us to convert the rest of our code to assume the +availability of @code{getaddrinfo}, rather than having to use two +branches everywhere, one for @code{getaddrinfo} and one for +@code{gethostbyname}. These replacement functions do use +@code{gethostbyname} and the like; for some systems it would be +possible to use @code{gethostbyname2} or @code{gethostbyname_r} or +other such functions, to provide thread safety or IPv6 support, but +this has not been a priority for us, since most modern systems have +these functions anyways. And if they don't, they probably don't have +real IPv6 support either. + +Including @file{fake-addrinfo.h} will enable the wrapper or +replacement versions when needed. The functions are actually defined +in the support library in @file{src/util/support}, added in the 1.4 +release. + +Do not assume that @code{ai_canonname} will be set when the +@code{AI_CANONNAME} flag is set. Check for a null pointer before +using it. + +@node Thread Safety, Shared Libraries, Networking, Top +@chapter Thread Safety + +Work is still needed as this section is being written. However, we've +made a lot of progress. + +@menu +* Kerberos API Thread Safety:: +* Thread System Requirements:: +* Internal Thread API:: +* Thread Shim Layer Implementation:: +@end menu + +@node Kerberos API Thread Safety, Thread System Requirements, Thread Safety, Thread Safety +@section Kerberos API Thread Safety + +We assume that a @code{krb5_context} or a @code{krb5_auth_context} +will be used in only one thread at a time, and any non-opaque object +clearly being modified by the application code (@i{e.g.}, a +@code{krb5_principal} having a field replaced) is not being used in +another thread at the same time. + +A credentials cache, key table, or replay cache object, once the C +object is created, may be used in multiple threads simultaneously; +internal locking is done by the implementations of those objects. (We +assume that object destructors are invoked only when all other threads +are finished with the object.) @i{(Iterators? Probably okay now, but +needs review.)} However, this doesn't mean that we've fixed any +problems there may be regarding simultaneous access to on-disk files +from multiple processes, and in fact if a process opens a disk file +multiple times, the same problems may come up. + +Any file locking issues may become worse, actually. UNIX file locking +with @code{flock} is done on a per-process basis, and closing a file +descriptor that was opened on a file releases any locks the process +may have on that file, even if they were obtained using other, +still-open file descriptors. UNIX file locks are used for credentials +caches and keytab files; the replay cache implementation is already +known to be unsafe in not using file locking. + +We MAY implement --- but haven't yet --- a ``fix'' whereby open files +are tracked by name (and per object type), and a new attempt to open +one gets a handle that uses the same open file descriptor, even if it +appears as two objects to the application. This won't address the +problem of getting the same file via two names that look different, +but it may be ``good enough.'' + +GSSAPI .... + +Strictly speaking, the GSSAPI specification says nothing about thread +safety, so for best portability, a GSSAPI application probably should +not assume that a GSSAPI implementation is thread-safe in any way. On +the other hand, the GSSAPI specification doesn't explicitly say that +it's safe to use in a program that uses the Berkeley sockets API, +either; at some point, you have to start making some assumptions. + +A GSSAPI security context, like a @code{krb5_context}, may be used +only in one thread at a time. The GSSAPI specification gives precise +definitions of C data structures for buffers, object identifiers, OID +sets, and channel bindings, that do not allow for the addition of a +mutex. Thus, these objects must not be modified by one thread while +in use by another. (All of the GSSAPI functions that modify these +types of objects should be obvious; they're listed as ``modify'' +parameters in the specification. In fact, aside from the case of +@code{gss_add_oid_set_member}, they're generally output arguments, +with the previous value ignored.) + +The function @code{gss_add_cred} can modify the +@code{input_cred_handle} object, if a null @code{output_cred_handle} +argument is supplied. Thus, all @code{gss_cred_id_t} objects must +have mutexes, and all accesses (except in the functions creating or +destroying them) must acquire the mutex first. + +Note that the use of @code{const} in the GSSAPI C bindings is not a +useful guide to when an object might or might not be modified. In +most cases, @code{const} is applied to handle arguments, which are +defined as arithmetic or pointer types. It applies to the argument +itself, not the data pointed to @i{if} the type is a pointer; this +would mean that the GSSAPI function in question cannot modify the +value of its handle parameter, and puts no constraints on +modifications to the object indicated by the handle. And according to +the C type compatibility rules, the function definition can omit those +@code{const} qualifiers anyways.@footnote{If you're thinking that this +means the use of @code{const} in the GSSAPI C bindings is confusing +and/or useless, you're right.} + + + + +@node Thread System Requirements, Internal Thread API, Kerberos API Thread Safety, Thread Safety +@section Thread System Requirements + +We support a few types of environments with regard to thread support: + +@itemize @bullet + +@item +Windows native threads. The objects used by the Windows thread +support functions generally need run-time initialization; this is done +through the library initialization function. (@xref{Advanced Shared +Library Requirements}.) + +@item +POSIX threads, with weak reference support so we can tell whether the +thread code was actually linked into the current executable. If the +functions aren't available, we assume the process is single-threaded +and ignore locks. (We do assume that the thread support functions +won't show up half-way through execution of the program.) In order to +support single-threaded programs wanting to load Kerberos or GSSAPI +modules through a plug-in mechanism, we don't list the pthread library +in the dependencies of our shared libraries. + +@item +POSIX threads, with the library functions always available, even if +they're stub versions that behave normally but don't permit the +creation of new threads. + +On AIX 4.3.3, we do not get weak references or useful stub functions, +and calling @code{dlopen} apparently causes the pthread library to get +loaded, so we've decided to link against the pthread library always. + +On Tru64 UNIX 5.1, we again do not get weak references or useful stub +functions. Rather than look for yet another approach for this one +platform, we decided to always link against the pthread library on +this platform as well. This may break single-threaded applications +that load the Kerberos libraries after startup. A clean solution, +even if platform-dependent, would be welcome. + +@item +Single-threaded. No locking is performed, any ``thread-local'' +storage is in fact global, @i{etc}. + +@end itemize + +If @code{pthread_once} is not provided in functional form in the +default libraries, and weak references are not supported, we always +link against the pthread libraries. (Tru64, AIX.) + +System routines: @code{getaddrinfo} (not always implemented +thread-safe), @code{gethostbyname_r}, @code{gmtime_r}, +@code{getpwnam_r} (but interfaces vary, see @file{k5-platform.h}), +@code{res_nsearch} (but watch for resource leaks). + +Unsafe system routines: @code{setenv}, @code{setlocale}. + +@node Internal Thread API, Thread Shim Layer Implementation, Thread System Requirements, Thread Safety +@section Internal Thread API + +Some ideas were discussed on the @samp{krbdev} mailing list, and while +the current implementation does largely resemble the scheme Ken +Raeburn proposed, some details have changed. + +The following macros in @file{k5-thread.h} implement a locking scheme +similar to POSIX threads, with fewer features. + +@deftp {Data type} k5_mutex_t +This is the type of a mutex to be used by the Kerberos libraries. Any +object of this type needs initialization. If the object is +dynamically allocated, @code{k5_mutex_init} must be used; if the +object is allocated statically, it should be initialized at compile +time with @code{K5_MUTEX_PARTIAL_INITIALIZER} and then +@code{k5_mutex_finish_init} should be called at run time. (In +general, one of these will do the work, and the other will do nothing +interesting, depending on the platform. When the debugging code is +turned on, it will check that both were done. However, as far as I +know, it should work to use just @code{k5_mutex_init} on a mutex in +static storage.) + +The mutex may be used only within the current process. It should not +be created in memory shared between processes. (Will it work in a +child process after @code{fork()}? I think so.) + +The @code{k5_mutex_t} object contains more than an operating-system +mutex; it may also contain debugging information such as the file and +line number in the Kerberos code where the last mutex operation was +performed, information for gathering statistics on mutex usage, +@i{etc}., depending on compile-time options. + +This type @emph{is not} a simple typedef for the native OS mutex +object, to prevent programmers from accidentally assuming that +arbitrary features of the native thread system will always be +available. (If someone wishes to make use of native thread system +features in random library code, they'll have to go further out of +their way to do it, and such changes probably won't be accepted in the +main Kerberos code base at MIT.) + +If thread support is disabled, a simple flag will be stored in place +of the operating-system mutex. This flag indicates the ``locked'' +state, and is checked in the @code{k5_mutex_lock} and +@code{k5_mutex_unlock} macros so that we can detect some cases of +improperly written code even if thread support is not built in. The +other debugging fields will still be present as well. + +If POSIX thread support and weak references are available, both the +POSIX mutex and a flag will be included; which one is used is +determined at run time depending on whether the thread support +routines are available. +@end deftp + +@defvr Macro K5_MUTEX_PARTIAL_INITIALIZER +Value to be used for compile-time initialization of a mutex in static +storage. +@end defvr + +@deftypefn Macro int k5_mutex_finish_init (k5_mutex_t *@var{m}) +Finishes run-time initialization, if such is needed, of a mutex that +was initialized with @code{K5_MUTEX_PARTIAL_INITIALIZER}. This macro +must be called before the mutex can be locked; usually this is done +from library initialization functions. +@end deftypefn + +@deftypefn Macro int k5_mutex_init (k5_mutex_t *@var{m}) +Initializes a mutex. +@end deftypefn + +@deftypefn Macro int k5_mutex_destroy (k5_mutex_t *@var{m}) +Destroys a mutex, whether allocated in static or heap storage. All +mutexes should be destroyed before the containing storage is freed, in +case additional system resources have been allocated to manage them. +@end deftypefn + +@deftypefn Macro int k5_mutex_lock (k5_mutex_t *@var{m}) +@deftypefnx Macro int k5_mutex_unlock (k5_mutex_t *@var{m}) +Lock or unlock a mutex, returning a system error code if an error +happened, or zero for success. (Typically, the return code from +@code{k5_mutex_unlock} is ignored.) +@end deftypefn + +@deftypefn Macro void k5_mutex_assert_locked (k5_mutex_t *@var{m}) +@deftypefnx Macro void k5_mutex_assert_unlocked (k5_mutex_t *@var{m}) +These macros may be used in functions that require that a certain +mutex be locked by the current thread, or not, at certain points +(typically on entry to the function). They may generate error +messages or debugger traps, or abort the program, if the mutex is not +in the expected state. Or, they may simply do nothing. + +It is not required that the OS mutex interface let the application +code determine the state of a mutex; hence these are not specified as +a single macro returning the current state, to be checked with +@code{assert}. +@end deftypefn + +Mutexes should be assumed not to be recursive; if a thread has the +mutex locked already, attempting to lock it again is an error and may +have unpredictable results (error return, abort, data corruption). +There is also no support assumed for ``trylock'' or ``lock with +timeout'' operations. + +Kerberos library code should use the macros above, and ports to new +thread systems should be done through the @code{k5_os_} layer. +(@xref{Thread Shim Layer Implementation}.) + +Thread-local storage is managed through another interface layer: + +@deftp {Enumerator} k5_key_t +This is an enumeration type which indicates which of the per-thread +data objects is to be referenced. +@end deftp + +@deftypefn Macro int k5_key_register (k5_key_t @var{key}, void (*@var{destructor})(void*)) +Registers a thread-local storage key and a function to destroy a +stored object if the thread exits. This function must be called +before @code{k5_setspecific} can be used. Currently @var{destructor} +must not be a null pointer; note, however, that the standard library +function @code{free} is of the correct type to be used here if the +allocated data doesn't require any special cleanup besides releasing +one block of storage. +@end deftypefn + +@deftypefn Macro void *k5_getspecific (k5_key_t @var{key}) +@deftypefnx Macro int k5_setspecific (k5_key_t @var{key}, void *@var{value}) +As with the POSIX interface, retrieve or store the value for the +current thread. Storing a value may return an error indication. If +an error occurs retrieving a value, @code{NULL} is returned. +@end deftypefn + +@deftypefn Macro int k5_key_delete (k5_key_t @var{key}) +Called to indicate that the key value will no longer be used, for +example if the library is in the process of being unloaded. The +destructor function should be called on objects of this type currently +allocated in any thread. (XXX Not implemented yet.) +@end deftypefn + +If support functions are needed to implement any of these macros, +they'll be in the Kerberos support library, and any exported symbols +will use the @code{krb5int_} prefix. The shorter @code{k5_} prefix is +just for convenience, and should not be visible to any application +code. + +@node Thread Shim Layer Implementation, , Internal Thread API, Thread Safety +@section Thread Shim Layer Implementation + +Each of the @code{k5_mutex_} macros has a corresponding +@code{k5_os_mutex_} macro which incorporates the operating system's +mutex object, a flag for non-threaded systems, or both if the use of +the OS pthread support is left until run time. The @code{k5_mutex_} +wrappers add debugging information like the file and line number of +the last lock or unlock call, where the mutex was created, @i{etc}. +There may also be statistical information gathered, such as how long a +thread waits for a mutex or how long the mutex is held. This is all +defined in @file{k5-thread.h}. + +The thread-specific storage support is defined as macros expanding to +similar function names with the @code{krb5int_} prefix, which +functions are defined in @file{util/support/threads.c}. POSIX, +Windows, and non-threaded versions are defined so far. + +The code for collecting and reporting statistics is also mainly in +that file. Macros defined in @file{k5-thread.h} will expand to +include calls to these functions, if @code{DEBUG_THREADS_STATS} is +defined, or do nothing. + +@node Shared Libraries, Porting Issues, Thread Safety, Top +@chapter Shared Libraries + +(These sections are old -- they should get updated.) + +@menu +* Shared Library Theory:: +* Advanced Shared Library Requirements:: +* Operating System Notes for Shared Libraries:: +@end menu + +@node Shared Library Theory, Advanced Shared Library Requirements, Shared Libraries, Shared Libraries +@section Theory of How Shared Libraries are Used + +An explanation of how shared libraries are implemented on a given +platform is too broad a topic for this manual. Instead this will touch +on some of the issues that the Kerberos V5 tree uses to support version +numbering and alternate install locations. + +Normally when one builds a shared library and then links with it, the +name of the shared library is stored in the object +(i.e. libfoo.so). Most operating systems allows one to change name that +is referenced and we have done so, placing the version number into the +shared library (i.e. libfoo.so.0.1). At link time, one would reference +libfoo.so, but when one executes the program, the shared library loader +would then look for the shared library with the alternate name. Hence +multiple versions of shared libraries may be supported relatively +easily. @footnote{Under AIX for the RISC/6000, multiple versions of +shared libraries are supported by combining two or more versions of the +shared library into one file. The Kerberos build procedure produces +shared libraries with version numbers in the internal module names, so +that the shared libraries are compatible with this scheme. +Unfortunately, combining two shared libraries requires internal +knowledge of the AIX shared library system beyond the scope of this +document. Practically speaking, only one version of AIX shared libraries +can be supported on a system, unless the multi-version library is +constructed by a programmer familiar with the AIX internals.} + +All operating systems (that we have seen) provide a means for programs +to specify the location of shared libraries. On different operating +systems, this is either specified when creating the shared library, and +link time, or both.@footnote{Both are necessary sometimes as the shared +libraries are dependent on other shared libraries.} The build process +will hardwire a path to the installed destination. + +@node Advanced Shared Library Requirements, Operating System Notes for Shared Libraries, Shared Library Theory, Shared Libraries +@section Advanced Shared Library Requirements + +In order to better support some multithreading models, and permit the +libraries to clean up internally maintained caches of information, +we've imposed new requirements on the OS shared library support. + +Specifically, we want the ability to run certain bits of code in a +thread-safe manner at library load time, on multithreading platforms +not supporting @code{pthread_once}, and we want the ability to run +cleanup code when the library is unloaded. + +In general, where platforms have initialization functions, we don't +always get an opportunity to return an error from them. However, the +system functions we call can return errors. So a framework has been +built that attempts to combine the @code{pthread_once} and load-time +initialization approaches, and add the ability to store an error code +indicating success or failure of the initialization routine. + +The main implementation of this framework is in @file{k5-platform.h}. +Some additional information, specifically the names of the +initialization and finalization functions, are stored in the makefiles +used to generate each of the UNIX libraries, in @file{win_glue.c}, and +somewhere in the Mac OS X support (XXX not added yet?). How the +information is used depends on the platform: + +@itemize @bullet + +@item +On platforms without any thread support, a simple flag is used, on the +assumption that the library code will have sole control over the +process execution until the initialization function returns. (It's +generally a bad idea to call any ``interesting'' function like +@code{longjmp} or Kerberos functions from signal handlers; now it's a +slightly worse idea.) + +@item +On platforms supporting @code{pthread_once}, library initialization is +generally delayed until the point where the library code needs to +verify that the initialization succeeded. If @code{pthread_once} may +not have been linked into the executable and we can tell (for example, +with weak symbol references), this is combined with the simple-flag +approach above. + +@item +On Windows, the library initialization function is run from +@file{win_glue.c} at load time; it should complete before the +library's symbol table is made accessible to the calling process. + +Windows note: There are limitations on what @code{DllMain} should do +in the initialization and finalization cases, and unfortunately we've +found that we do some of these things (specifically, calling +@code{WSAStartup} and @code{WSACleanup}, and loading other libraries +which do so also). Until we can rectify this problem, there is a +chance that explicitly unloading an MIT Kerberos library from an +application (more specifically, from within the @code{DllMain} of +another library) may cause a deadlock. +@end itemize + +Library finalization is similarly dependent on the platform and +configuration: + +@itemize @bullet + +@item +In static-library builds, since the library will be unloaded only when +the entire process calls @code{exit} or @code{exec} or otherwise +ceases to exist in its current form, freeing up memory resources in +the process, finalization can be skipped. + +@item +On UNIX platforms with library finalization support in shared +libraries, the (OS-level) finalization function is specified to run +the library's (shim-level) finalization function. If @code{gcc}'s +``destructor'' attribute appears to work, we use that. + +@item +On UNIX platforms without library finalization function support, +the finalization functions won't get called if the library is +unloaded. Resources (probably just memory) will be leaked. + +@item +On Windows, the finalization code is run out of @code{DllMain} in +@file{win_glue.c} at unload time. See the warnings above. + +@end itemize + +If there are other limitations on what operations can be performed in +shared library initialization and finalization routines on some +systems, the MIT Kerberos team would appreciate specific information +on these limitations. + +The internal interface currently used within the code of the Kerberos +libraries consists of four macros: + +@defmac MAKE_INIT_FUNCTION (@var{fname}) +Used at the top level of the file (@i{i.e.}, not within a function), +with a semicolon after it, declares @var{fname}, a function taking no +arguments and returning @code{int}, to be an initialization function. +This macro must be used before the function is declared, and it must +be defined in the current file as: +@example +int @var{fname} (void) @{ ... @} +@end example +This macro may define additional data and function objects, +and will declare @var{fname}, though it may or may not declare +@var{fname} as @code{static}. (Under C rules, the declaration above +is compatible with a declaration of the function as @code{static}, and +@code{static} linkage does apply, as long as the @code{static} declaration +comes first.) + +When the function is invoked, the return value --- zero or an error +code --- will be saved away, and returned any time +@code{CALL_INIT_FUNCTION} is used. + +There can be multiple initialization functions defined this way in a +library. +@end defmac + +@defmac MAKE_FINI_FUNCTION (@var{fname}) +This is similar to @code{MAKE_INIT_FUNCTION} except that @var{fname} +is to be a library finalization function, called when the library is +no longer in use and is being unloaded from the address space. +@example +void @var{fname} (void) @{ ... @} +@end example + +There may be multiple finalization functions defined for a library. +@end defmac + +@deftypefn Macro int CALL_INIT_FUNCTION (@var{fname}) +This macro ensures that the initialization function @var{fname} is +called at this point, if it has not been called already. The macro +returns an error code that indicates success (zero), an error in the +OS support (@i{e.g.}, if @code{pthread_once} returns an error), or an +error returned by the initialization function. + +Currently, all uses of @code{CALL_INIT_FUNCTION} must be in the same +file as the use of @code{MAKE_INIT_FUNCTION}, and must come after it. +@end deftypefn + +@deftypefn Macro int INITIALIZER_RAN (@var{fname}) +This macro returns non-zero iff the initialization function designated +by @var{fname} (and previously declared in the current file with +@code{MAKE_INIT_FUNCTION}) has been run, and returned no error +indication. + +Since the finalization function might always be invoked through linker +support and initialization functions only sometimes invoked via +@code{pthread_once} in other functions that may not ever be called, +finalization functions should check whether the objects to be +destroyed have actually been created. This macro provides one way of +doing that. +@end deftypefn + +The @file{Makefile.in} for the library must define two variables, +@code{LIBINITFUNC} and @code{LIBFINIFUNC}, containing a (possibly +empty) list of the names of the initialization and finalization +functions for the library as built under UNIX, ordered from +lowest-level (initialized first, finalized last) to highest-level. +(Windows and Mac OS X builds work differently.) + +Note that all of this assumes shared libraries. If static linking is +done, our options are a bit more limited. We assume +@code{pthread_once} is available if there is any thread support +(@i{i.e.}, we don't support static linking on Windows), and we assume +that finalization code would be called only when the process is +exiting, at which point all resources should be freed up anyways, so +it doesn't really matter whether our cleanup code gets called. In +fact, it should be more efficient if it does not. + +While one of our goals is to be able to repeatedly load, use, and +unload the MIT Kerberos libraries under a plugin architecture without +memory or other resource leaks, the main goal was to provide hooks +through which the library threading support could be properly +initialized on various platforms. The hooks we've added should be +sufficient for each library to free up any internal caches of +information at unload time, and we have added some of that support, +but it is not complete at this time. + + +We have also started limiting the list of exported symbols from shared +libraries on some UNIX platforms, and intend to start doing symbol +versioning on platforms that support it. The symbol lists we use for +UNIX at the moment are fairly all-inclusive, because we need more +symbols exported than are in the lists used for Windows and Mac +platforms, and we have not yet narrowed them down. The current lists +should not be taken as an indication of what we intend to export and +support in the future; see @file{krb5.h} for that. + +The export lists are stored in the directories in which each UNIX +library is built, and the commands set up at configuration time by +@file{shlib.conf} can specify any processing to be done on those files +(@i{e.g.}, insertion of leading underscores or linker command-line +arguments). + +For some systems with somewhat non-trivial commands that need to be +run to convert the export list into the proper form, file targets can be +defined in @file{config/lib.in}. + +@node Operating System Notes for Shared Libraries, , Advanced Shared Library Requirements, Shared Libraries +@section Operating System Notes for Shared Libraries + +From time to time users or developers suggest using GNU @code{Libtool} +or some other mechanism to generate shared libraries. Experience +with other packages suggests that Libtool tends to be difficult to +debug and when it works incorrectly, patches are required to generated +scripts to work around problems. So far, the Kerberos shared library +build mechanism, which sets a variety of makefile variables based on +operating system type and then uses those variables in the build +process has proven to be easier to debug and adequate to the task of +building shared libraries for Kerberos. + +@menu +* AIX Shared Library Support:: +* Alpha OSF/1 Shared Library Support:: +@end menu + +@node AIX Shared Library Support, Alpha OSF/1 Shared Library Support, Operating System Notes for Shared Libraries, Operating System Notes for Shared Libraries +@subsection AIX Shared Library Support + + AIX specifies shared library versions by combining multiple +versions into a single file. Because of the complexity of this process, +no automatic procedure for building multi-versioned shared libraries is +provided. Therefore, supporting multiple versions of the Kerberos shared +libraries under AIX will require significant work on the part of a +programmer famiiliar with AIX internals. + + AIX allows a single library to be used both as a static library +and as a shared library. For this reason, the @samp{--enable-shared} +switch to configure builds only shared libraries. On other operating +systems, both shared and static libraries are built when this switch is +specified. As with all other operating systems, only non-shared static +libraries are built when @samp{--enable-shared} is not specified. + + The AIX 3.2.5 linker dumps core trying to build a shared +@samp{libkrb5.a} produced with the GNU C compiler. The native AIX +compiler works fine. In addition, the AIX 4.1 linker is able to build a +shared @samp{libkrb5.a} when GNU C is used. + + +@node Alpha OSF/1 Shared Library Support, , AIX Shared Library Support, Operating System Notes for Shared Libraries +@subsection Alpha OSF/1 Shared Library Support + +Shared library support has been tested with V2.1 and higher of the +operating system. Shared libraries may be compiled both with GCC and the +native compiler. + +One of the nice features on this platform is that the paths to the +shared libraries is specified in the library itself without requiring +that one specify the same at link time. + +We are using the @samp{-rpath} option to @samp{ld} to place the library +load path into the executables. The one disadvantage of this is during +testing where we want to make sure that we are using the build tree +instead of a possibly installed library. The loader uses the contents of +@samp{-rpath} before LD_LIBRARY_PATH so we must specify a dummy _RLD_ROOT +and complete LD_LIBRARY_PATH in our tests. + +The one disadvantage with the method we are using.... + +@node Porting Issues, , Shared Libraries, Top +@chapter Porting Issues + +[Snipped from email from Ken Raeburn in reply to email asking about +porting MIT Kerberos to pSOS; maybe it'll be of use to someone else.] + +> - Any Porting issues to be considered? + +Yes. Our build procedure currently assumes that the machine used for +building is either a UNIX (or similar) system, or running Windows; it +also assumes that it's a native compilation, not a cross compilation. +I'm not familiar with pSOS, but assuming that you do cross compilation +on another OS, how you deal with that depends on the host system. + +UNIX host: The configure script attempts to learn a bunch of +attributes about the host system (program names, availability of +header files and functions and libraries) and uses them to decide how +to build the krb5 libraries and programs. Many attributes are tested +by running the compiler with various options and test source files, so +if you tell the configure script to run a cross compiler, it may come +up with most of the right answers, if you can arrange for success and +failure indications to be given at compile/link time. (This probably +wouldn't work well for VxWorks, for example, where symbol resolution +is done when the object code is loaded into the OS.) + +The configure script generates include/krb5/autoconf.h to influence +whether certain calls are made or certain headers are included, and +Makefile in each directory to indicate compilation options. Each +source directory has a Makefile.in, and config/pre.in and +config/post.in are incorporated into each generate Makefile. Various +@@FOO@@ sequences are substituted based on the system attributes or +configure options. (Aside from always using the config/ fragments, +this is typical of GNU Autoconf based software configuration.) + +Windows host: The ``wconfig'' program generates the Makefiles in +subdirectories, with config/win-pre.in and config/win-post.in used in +combination with each Makefile.in, and lines starting @code{##WIN32##} +are uncommented, but @code{@@FOO@@} substitutions are not done. +Instead of generating @file{autoconf.h}, it's copied from +@file{include/win-mac.h}, where we've hardcoded some of the parameters +we care about, and just left a bunch of others out. If you work with +a Windows host, you may want to provide your own makefile fragments, +and a replacement for @file{win-mac.h} or some additional data to go +into it conditionalized on some preprocessor symbol for pSOS. + +There are also places where we assume that certain header files or +functions are available, because both (most) UNIX and Windows +platforms (that we care about currently) provide them. And probably a +handful of places where we check for @code{_WIN32} to decide between ``the +Windows way'' and ``everything else'' (i.e., UNIX); you might need to add +a third branch for pSOS. And some places where we've got hooks for +Kerberos for Mac support, which you can probably ignore. + +Our build environment assumes that Perl is available, but it's only +needed in the build process, not for run time. If Tcl is available, +on UNIX, a few more programs may be built that are used for testing +some interfaces, but a cross compiler should notice that it can't link +against the native Tcl libraries, and configure should choose not to +build those programs. + +In the current 1.4 beta code, our library wants to find routines for +making DNS queries (SRV and TXT RR queries specifically) that are +outside the scope of getaddrinfo and friends. We also look for +@file{/dev/random} as a strong random number source, and text files +for configuration information. Our code assumes that allocating and +reallocating lots of little (or not so little) bits of memory isn't +too horribly expensive, and we don't take any special pains to keep +our stack size small. Depending how pSOS works, you may need to add +to the thread support code. (The MIT code doesn't create threads, but +will do locking and such to allow multiple threads to share global +data. The code in @file{include/k5-thread.h} is, uh, kind of +involved, and some pains have been taken to use macros whenever +possible to allow @code{assert()} calls during debugging to report +useful line numbers.) There are probably other minor issues to deal +with, I'm just making some guesses. + +> - what type of Data formats exchanged between Client and Server? + +If you're aiming for a server implementation only, it'll depend on the +exact protocol you wish to use, but typically the Kerberos application +server needs to accept the AP-REQ message and generate the AP-REP +message. Protection for the data to be transferred depends on on the +application protocol. For example, Kerberos provides some message +types for encapsulating application data with or without encryption; +the Kerberos mechanism for GSSAPI uses the Kerberos session key to +protect application data in a different message format. + +The server implementation would also need some secure means of getting +the service principal's key stored away. + +If you want client code support as well under pSOS, then you may have +to deal with DNS queries to find the KDC, +AS-REQ/AS-REP/TGS-REQ/TGS-REP message exchanges, and generating AP-REQ +and accepting AP-REP messages, etc. + +@contents +@bye diff --git a/mechglue/doc/install-old.texi b/mechglue/doc/install-old.texi new file mode 100644 index 000000000..079590824 --- /dev/null +++ b/mechglue/doc/install-old.texi @@ -0,0 +1,2239 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename install.info +@settitle Kerberos V5 +@c For double-sided printing, uncomment: +@setchapternewpage odd +@c %**end of header + +@set EDITION BETA 6 +@set VERSION BETA 6 +@set UPDATED Mar 20, 1996 + +@ignore +@iftex +@finalout +@end iftex +@end ignore + +@ifinfo +This file documents how to build and install the Kerberos V5 +distribution. + +Copyright (C) 1995, 1996 Massachusetts Institute of Technology. + +All Rights Reserved. + +Export of this software from the United States of America may require a +specific license from the United States Government. It is the +responsibility of any person or organization contemplating export to +obtain any necessary licenses before exporting. + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +distribute this software and its documentation for any purpose and +without fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, and that +the name of M.I.T. not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. M.I.T. makes no representations about the suitability of +this software for any purpose. It is provided "as is" without express +or implied warranty. + +Athena(r), Hesiod(r), Moira(r), and Discuss(r) are registered trademarks of +the Massachusetts Institute of Technology (MIT). Project Athena, Athena +Dashboard, Athena MUSE, Kerberos, X Window System, and Zephyr are trademarks +of MIT. No commercial use of these trademarks may be made without prior +written permission of MIT. + +All other product names are trademarks of their respective companies. + +@end ifinfo + +@titlepage +@title Kerberos V5 +@subtitle Notes on Building and Installing Kerberos +@subtitle Edition @value{EDITION}, for Kerberos version @value{VERSION} +@subtitle @value{UPDATED} +@author by Theodore Ts'o + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1995, 1996 Massachusetts Institute of Technology + +All Rights Reserved. + +Export of this software from the United States of America may require a +specific license from the United States Government. It is the +responsibility of any person or organization contemplating export to +obtain any necessary licenses before exporting. + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +distribute this software and its documentation for any purpose and +without fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, and that +the name of M.I.T. not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. M.I.T. makes no representations about the suitability of +this software for any purpose. It is provided "as is" without express +or implied warranty. + +Athena(r), Hesiod(r), Moira(r), and Discuss(r) are registered trademarks of +the Massachusetts Institute of Technology (MIT). Project Athena, Athena +Dashboard, Athena MUSE, Kerberos, X Window System, and Zephyr are trademarks +of MIT. No commercial use of these trademarks may be made without prior +written permission of MIT. + +All other product names are trademarks of their respective companies. + +@end titlepage + +@node Top, Introduction, (dir), (dir) +@comment node-name, next, previous, up + +@ifinfo +This file documents how to build and install the Kerberos V5 +distribution. + +This is edition @value{EDITION}, for Kerberos V5 version @value{VERSION}. + +@end ifinfo + +@c The master menu is updated using emacs19's M-x texinfo-all-menus-update +@c function. Don't forget to run M-x texinfo-every-node-update after +@c you add a new section or subsection, or after you've rearranged the +@c order of sections or subsections. Also, don't forget to add an @node +@c command before each @section or @subsection! All you need to enter +@c is: +@c +@c @node New Section Name + +@c @section New Section Name +@c +@c M-x texinfo-every-node-update will take care of calculating the +@c node's forward and back pointers. +@c + +@menu +* Introduction:: +* How Kerberos Works:: +* Building Kerberos:: +* Installation:: +* Troubleshooting:: + + --- The Detailed Node Listing --- + +How Kerberos Works: A Schematic Description + +* Network Services:: +* Kerberos Tickets:: +* The Kerberos Database:: +* Kerberos Realms:: +* The Ticket-Granting Ticket:: +* Network Services and the Master Database:: +* The User-Kerberos Interaction:: + +Network Services and the Master Database + +* The Keytab File:: + +Building Kerberos + +* Build Requirements:: How much disk space, etc. you need to + build Kerberos. +* Unpacking the Sources:: Preparing the source tree. +* Doing the Build:: Compiling Kerberos. +* Testing the Build:: Making sure Kerberos built correctly. +* Options to Configure:: +* osconf.h:: +* Shared Library Support:: +* OS Incompatibilities:: Special cases to watch for. +* Using Autoconf:: Modifying Kerberos V5's + configuration scripts. + +Doing the Build + +* Building Within a Single Tree:: +* Building with Separate Build Directories:: +* Building using lndir:: + +Testing the Build + +* The DejaGnu Tests:: + +Shared Library Support + +* Shared Library Theory:: +* NetBSD Shared Library Support:: +* AIX Shared Library Support:: +* Solaris 5.3 Shared Library Support:: +* Alpha OSF/1 Shared Library Support:: + +Operating System Incompatibilities + +* Ultrix 4.2/3:: +* Alpha OSF/1 V1.3:: +* Alpha OSF/1 V2.0++:: +* BSDI:: +* Solaris versions 2.0 through 2.3:: +* Solaris 2.X:: +* SGI Irix 5.X:: + +Installation + +* Background:: +* Installation on any Machine:: +* Installing the KDC:: +* Migrating from V4 to V5 Kerberos:: +* A Sample Application:: +* Installing Kerberos Applications:: +* Common Kerberos Service Names:: + +Installation on any Machine + +* Picking a Realm Name:: +* Configuration files:: +* Recommended Programs:: + +Configuration files + +* krb5.conf:: +* Converting V4 configuration files:: +* /etc/services:: + +Installing the KDC + +* kdc.conf:: +* Initializing the KDB:: +* Storing the Master Password:: +* Adding Users to the Database:: +* Starting the Kerberos Server:: +* Setting up Slave Kerberos Servers:: +* Inter-realm Kerberos Operation:: +* The Administration Server:: +* Testing the Kerberos Server:: + +Setting up Slave Kerberos Servers + +* Kerberos Slave Database Propagation:: +* Installing a Slave Server:: + +A Sample Application + +* Installing the Sample Application:: +* Testing the Sample Server:: + +Installing Kerberos Applications + +* Levels of Security:: +* Preparing a Workstation for Kerberos Application Servers:: +* BSD Utilities:: +* Telnet and FTP:: + +BSD Utilities + +* Checksums:: Checksum facility for dealing with active attacks. +* BSD Utility Configuration Example:: Sample @file{inetd.conf} entries for BSD utilities. +@end menu + +@node Introduction, How Kerberos Works, Top, Top +@chapter Introduction + +This document describes the procedures necessary to compile Kerberos V5 +from the source distribution, and then to install it at a particular +site. The reader is assumed to be familiar with C/UNIX development +tools. + +In any complex software, there will be bugs. Please send bug reports +or other problems you may uncover to the e-mail address +@b{krb5-bugs@@mit.edu}. Please mention which version of the Kerberos +V5 distribution you are using, and whether you have made any private +changes. Bug reports that include proposed fixes are especially +welcome. If you do include fixes, please send them using either +context diffs or unified diffs (using @samp{diff -c} or @samp{diff +-u}, respectively). + +Please note that there are still a number of aspects of Kerberos V5 +which will likely change before the 1.0 release. +As these changes occur, we will update the documentation accordingly. + +@c As of this release, all the databases, including the aname to localname +@c ones now use version 1.85 of the Berkeley DB code. This may imply +@c database conversions for those running earlier releases of Kerberos +@c V5. We recommend that you dump your database with the old kdb5_edit and +@c restore with the new one. + + +@node How Kerberos Works, Building Kerberos, Introduction, Top +@chapter How Kerberos Works: A Schematic Description + +This section provides a simplified description of a general user's +interaction with the Kerberos system. This interaction happens +transparently--users don't need to know and probably don't care about +what's going on--but Kerberos administrators might find a schematic +description of the process useful. This description glosses over a lot +of details; for more information, see @i{Kerberos: An Authentication +Service for Open Network Systems}, a paper presented at Winter USENIX +1988, in Dallas, Texas. + +@menu +* Network Services:: +* Kerberos Tickets:: +* The Kerberos Database:: +* Kerberos Realms:: +* The Ticket-Granting Ticket:: +* Network Services and the Master Database:: +* The User-Kerberos Interaction:: +@end menu + +@node Network Services, Kerberos Tickets, How Kerberos Works, How Kerberos Works +@section Network Services and Their Client Programs + +In an environment that provides network services, you use @dfn{client} +programs to request service from @dfn{server} programs that are +somewhere on the network. Suppose you have logged in to a workstation +and you want to @samp{rlogin} to another machine. You use the local +@samp{rlogin} client program to contact the remote machine's +@samp{rlogind} daemon. + +@node Kerberos Tickets, The Kerberos Database, Network Services, How Kerberos Works +@section Kerberos Tickets + +Under Kerberos, the @samp{rlogind} daemon allows you to login to a +remote machine if you can provide @samp{rlogind} a Kerberos ticket +which proves your identity. In addition to the ticket, you must also +have possession of the corresponding ticket session key. The +combination of a ticket and the ticket's session key is known as a credential. + +Typically, a client program automatically obtains credentials +identifying the person using the client program. The credentials are +obtained from a Kerberos server that resides somewhere on the network. +A Kerberos server maintains a database of user, server, and password +information. + +@node The Kerberos Database, Kerberos Realms, Kerberos Tickets, How Kerberos Works +@section The Kerberos Database + +Kerberos will give you credentials only if you have an entry in the Kerberos +server's @dfn{Kerberos database}. Your database entry includes your +Kerberos @dfn{principal} (which is often just your username), and +your Kerberos password. Every Kerberos user must have an entry in this +database. + +@node Kerberos Realms, The Ticket-Granting Ticket, The Kerberos Database, How Kerberos Works +@section Kerberos Realms + +Each site (or administrative domain within a site) will have their own +Kerberos database, which contains information about the users and +services for that particular site or administrative domain. +A @dfn{Kerberos Realm} is used to distinguish the users and services in +one particular area of administrative control from another area of +administrative control. + +Each Kerberos realm will have at least one Kerberos server, where the +master Kerberos database for that site or administrative domain is +stored. A Kerberos realm may also have one or more @dfn{slave servers}, +which have read-only copies of the Kerberos database which are +periodically propagated from the master server. For more details on how +this is done, see @ref{Setting up Slave Kerberos Servers}. + +@node The Ticket-Granting Ticket, Network Services and the Master Database, Kerberos Realms, How Kerberos Works +@section The Ticket-Granting Ticket + +The @samp{kinit} command prompts for your password, and if you enter +it successfully, you will obtain a @dfn{ticket-granting ticket} and a +@dfn{ticket session key} which gives you the right to use the ticket. +This combination of the ticket and its associated key is also known as +your @dfn{credentials}. As illustrated below, client programs use +your ticket-granting ticket credentials in order to obtain +client-specific credentials as needed. + +Your credentials are stored in a @dfn{credentials cache}, which is often +simply just a file in @file{/tmp}. The credentials cache is also +referred to as the @dfn{ticket file}, especially in Kerberos V4 +documentation. It should be noted, however, that a credentials cache +does not have to be stored in a file. + +@node Network Services and the Master Database, The User-Kerberos Interaction, The Ticket-Granting Ticket, How Kerberos Works +@section Network Services and the Master Database + +The master database also contains entries for all network services that +require Kerberos authentication. Suppose that your site +has a machine, @samp{laughter.mit.edu}, that requires Kerberos +authentication from anyone who wants to @samp{rlogin} to it. The host's +Kerberos realm is @samp{ATHENA.MIT.EDU}. + +This service must be registered in the Kerberos database, using the +proper service name, which in this case is +@samp{host/laughter.mit.edu@@ATHENA.MIT.EDU}. The @kbd{/} character +separates the various @dfn{components} of the Kerberos principal; the +@kbd{@@} character separates the realm name from the rest of the +principal name. The first component, @samp{host}, denotes the name or +type of the service that is being offered: generic host-level access to +the machine. The second component, @samp{laughter.mit.edu}, names the +specific machine which is offering this service. There will generally +be many different machines, each offering one particular type of +service, and the second component serves to give each one of these +servers a different Kerberos name. + +@menu +* The Keytab File:: +@end menu + +@node The Keytab File, , Network Services and the Master Database, Network Services and the Master Database +@subsection The Keytab File + +For each service, there must also be a @dfn{service key} known only by +Kerberos and the service. On the Kerberos server, the service key is +stored in the Kerberos database. + +On the server host, these service keys are stored in the @dfn{Key +tables}, or @dfn{keytab files}. (Keytab files were previously +referred to as @dfn{srvtab files} in the V4 literature.) The service +keys that are used by services which run as root are often stored in +the file @file{/etc/v5srvtab}. + +@b{WARNING:} This service key is the equivalent of the service's +password, and must be kept secure. Data which is meant to be read only +by the service is encrypted using this key. + +@node The User-Kerberos Interaction, , Network Services and the Master Database, How Kerberos Works +@section The User--Kerberos Interaction + +Suppose that you (in the guise of a general user) walk up to a workstation +intending to login to it, and then @samp{rlogin} to the machine @samp{laughter}. +Here's what happens: + +@enumerate + +@item +You login to the workstation and use the @samp{kinit} command +to get a ticket-granting ticket. +This command prompts you for your Kerberos password. (On some systems +which have a modified @samp{/bin/login} program, this may be done as +part of the login process, not requiring the user to run a separate +program.) + +@enumerate A + +@item +The @samp{kinit} command sends your request to the Kerberos master +server machine. The server software looks for your principal name's +entry in the Kerberos database. + +@item +If this entry exists, the Kerberos server creates and returns a +ticket-granting ticket and the key which allows you to use it, encrypted +by your password. If @samp{kinit} can decrypt the Kerberos reply using +the password you provide, it stores this ticket in a credentials cache +on your local machine for later use. The name of the credentials cache +can be specified in the @samp{KRB5_CCNAME} environment variable. If +this variable is not set, the name of the file will be +@file{/tmp/krb5cc_}, where is your UNIX user-id, represented +in decimal format. +@end enumerate + +@item +Now you use the @samp{rlogin} client to access the machine +@samp{laughter}. + +@example +host% @b{rlogin laughter} +@end example + +@enumerate A + +@item +The @samp{rlogin} client checks your ticket file to see if you +have a ticket for the @samp{host} service for @samp{laughter}. +You don't, so @samp{rlogin} uses the credential cache's ticket-granting +ticket to make a request to the master server's ticket-granting service. + +@item +This ticket-granting service receives the +@samp{host/laughter.mit.edu} request and looks in the master database +for an @samp{host/laughter.mit.edu} entry. If the entry exists, the +ticket-granting service issues you a ticket for that service. That +ticket is also cached in your credentials cache. + +@item +The @samp{rlogin} client now sends that ticket to +the @samp{laughter} @samp{rlogind} service program. The service program +checks the ticket by using its own service key. If the ticket is valid, +it now knows your identity. If the ticket is valid and you are allowed +to login to @samp{laughter} (because the your name matches one in +/etc/passwd, or you are in the @file{.k5login} file), you will find +yourself logged into the machine. + +@end enumerate +@end enumerate + +@node Building Kerberos, Installation, How Kerberos Works, Top +@chapter Building Kerberos + +Starting with the Beta 4 distribution, we are using a new configuration +system, which was built using the Free Software Foundation's +@samp{autoconf} program. This system will hopefully make Kerberos V5 +much simpler to build and reduce the amount of effort required in +porting Kerberos V5 to a new platform. + +@menu +* Build Requirements:: How much disk space, etc. you need to + build Kerberos. +* Unpacking the Sources:: Preparing the source tree. +* Doing the Build:: Compiling Kerberos. +* Testing the Build:: Making sure Kerberos built correctly. +* Options to Configure:: +* osconf.h:: +* Shared Library Support:: +* OS Incompatibilities:: Special cases to watch for. +* Using Autoconf:: Modifying Kerberos V5's + configuration scripts. +@end menu + +@node Build Requirements, Unpacking the Sources, Building Kerberos, Building Kerberos +@section Build Requirements + +In order to build Kerberos V5, you will need approximately 60-70 +megabytes of disk space. The exact amount will vary depending on the +platform and whether the distribution is compiled with debugging symbol +tables or not. + +If you wish to keep a separate @dfn{build tree}, which contains the compiled +@file{*.o} file and executables, separate from your source tree, you +will need a @samp{make} program which supports @samp{VPATH}, or +you will need to use a tool such as @samp{lndir} to produce a symbolic +link tree for your build tree. + +@node Unpacking the Sources, Doing the Build, Build Requirements, Building Kerberos +@section Unpacking the Sources + +The first step in each of these build procedures is to unpack the source +distribution. The Kerberos V5 distribution comes in two compressed tar +files. The first file, which is generally named @file{krb5.src.tar.gz}, +contains the sources for all of Kerberos except for the crypto library, +which is found in the file @file{krb5.crypto.tar.gz}. + +Both files should be unpacked in the same directory, such as +@file{/u1/krb5}. (In the rest of this document, we will assume that you +have chosen to unpack the Kerberos V5 source distribution in this +directory.) + + +@node Doing the Build, Testing the Build, Unpacking the Sources, Building Kerberos +@section Doing the Build + +You have a number of different options in how to build Kerberos. If you +only need to build Kerberos for one platform, using a single directory +tree which contains both the source files and the object files is the +simplest. However, if you need to maintain Kerberos for a large number +of platforms, you will probably want to use separate build trees for +each platform. We recommend that you look at see @ref{OS +Incompatibilities} for notes that we have on particular operating +systems. + +@menu +* Building Within a Single Tree:: +* Building with Separate Build Directories:: +* Building using lndir:: +@end menu + +@node Building Within a Single Tree, Building with Separate Build Directories, Doing the Build, Doing the Build +@subsection Building Within a Single Tree + +If you don't want separate build trees for each architecture, then +use the following abbreviated procedure. + +@enumerate +@item + @code{cd /u1/krb5/src} +@item + @code{./configure} +@item + @code{make} +@end enumerate + +That's it! + +@node Building with Separate Build Directories, Building using lndir, Building Within a Single Tree, Doing the Build +@subsection Building with Separate Build Directories + +If you wish to keep separate build directories for each platform, you +can do so using the following procedure. (Note, this requires that your +@samp{make} program support @samp{VPATH}. GNU's make will provide this +functionality, for example.) If your @samp{make} program does not +support this, see the next section. + +For example, if you wish to create a build directory for @code{pmax} binaries +you might use the following procedure: + +@enumerate +@item +@code{mkdir /u1/krb5/pmax} +@item + @code{cd /u1/krb5/pmax} +@item + @code{../src/configure} +@item + @code{make} +@end enumerate + +@node Building using lndir, , Building with Separate Build Directories, Doing the Build +@subsection Building Using @samp{lndir} + +If you wish to keep separate build directories for each platform, and +you do not have access to a @samp{make} program which supports @samp{VPATH}, +all is not lost. You can use the @samp{lndir} program to create +symbolic link trees in your build directory. + +For example, if you wish to create a build directory for solaris binaries +you might use the following procedure: + +@enumerate +@item + @code{mkdir /u1/krb5/solaris} +@item + @code{cd /u1/krb5/solaris} +@item + @code{/u1/krb5/src/util/lndir `pwd`/../src} +@item + @code{./configure} +@item + @code{make} +@end enumerate + +You must give an absolute pathname to @samp{lndir} because it has a bug that +makes it fail for relative pathnames. Note that this version differs +from the latest version as distributed and installed by the XConsortium +with X11R6. Either version should be acceptable. + +@node Testing the Build, Options to Configure, Doing the Build, Building Kerberos +@section Testing the Build + +The Kerberos V5 distribution comes with built-in regression tests. To +run them, simply type the following command while in the top-level build +directory (i.e., the directory where you sent typed @samp{make} to start +building Kerberos; see @ref{Doing the Build}.): + +@example +% make check +@end example + +@menu +* The DejaGnu Tests:: +@end menu + +@node The DejaGnu Tests, , Testing the Build, Testing the Build +@subsection The DejaGnu Tests + +Some of the built-in regression tests are setup to use the DejaGnu +framework for running tests. These tests tend to be more comprehensive +than the normal built-in tests as they setup test servers and test +client/server activities. + +DejaGnu may be found wherever GNU software is archived. + +Most of the tests are setup to run as a non-privledged user. There are +two series of tests (@samp{rlogind} and @samp{telnetd}) which require +the ability to @samp{rlogin} as root to the local machine. Admittedly, +this does require the use of a @file{.rhosts} file or some other +authenticated means. @footnote{If you are fortunate enough to have a +previous version of Kerberos V5 or V4 installed, and the Kerberos rlogin +is first in your path, you can setup @file{.k5login} or @file{.klogin} +respectively to allow you access.} + +If you cannot obtain root access to your machine, all the other tests +will still run. Note however, with DejaGnu 1.2, the "untested testcases" +will cause the testsuite to exit with a non-zero exit status which +@samp{make} will consider a failure of the testing process. Do not worry +about this, as these tests are the last run when @samp{make check} is +executed from the top level of the build tree. + + +@node Options to Configure, osconf.h, Testing the Build, Building Kerberos +@section Options to Configure + +There are a number of options to @samp{configure} which you can use to +control how the Kerberos distribution is built. The following table +lists the most commonly used options to Kerberos V5's @samp{configure} +program. + +@table @code + +@item --help + +Provides help to configure. This will list the set of commonly used +options for building Kerberos. + +@item --prefix=DIR + +By default, Kerberos will install the package's files rooted at +`/usr/local' as in `/usr/local/bin', `/usr/local/sbin', etc. If you +desire a different location use this option. + +@item --exec-prefix=DIR + +This option allows one to separate the architecture independent programs +from the configuration files and manual pages. + +@item --with-cc=COMPILER + +Use @code{COMPILER} as the C compiler. + +@item --with-ccopts=FLAGS + +Use @code{FLAGS} as the default set of C compiler flags. + +Note that if you use the native Ultrix compiler on a +DECstation you are likely to lose if you pass no flags to cc; md4.c +takes an estimated 3,469 billion years to compile if you provide neither +the @samp{-g} flag nor the @samp{-O} flag to @samp{cc}. + +@item --with-cppopts=CPPOPTS + +Use @code{CPPOPTS} as the default set of C preprocessor flags. The most +common use of this option is to select certain @code{#define}'s for use +with the operating system's include files. + +@item --with-linker=LINKER + +Use @code{LINKER} as the default loader if it should be different from C +compiler as specified above. + +@item --with-ldopts=LDOPTS + +This option allows one to specify optional arguments to be passed to the +linker. This might be used to specify optional library paths. + +@item --with-krb4 + +This option enables Kerberos V4 backwards compatibility using the +builtin Kerberos V4 library. + +@item --with-krb4=KRB4DIR + +This option enables Kerberos V4 backwards compatibility. The directory +specified by @code{KRB4DIR} specifies where the V4 header files should +be found (@file{/KRB4DIR/include}) as well as where the V4 Kerberos +library should be found (@file{/KRB4DIR/lib}). + +@item --without-krb4 + +Disables Kerberos V4 backwards compatibility. This prevents Kerberos V4 +clients from using the V5 services including the KDC. This would be +useful if you know you will never install or need to interact with V4 +clients. + +@item --with-netlib[=libs] + +Allows for suppression of or replacement of network libraries. By +default, Kerberos V5 configuration will look for @code{-lnsl} and +@code{-lsocket}. If your operating system has a broken resolver library +(see @ref{Solaris versions 2.0 through 2.3}) or fails to pass the tests in +@file{src/tests/resolv} you will need to use this option. + +@item --enable-shared + +This option will turn on the building and use of shared library objects +in the Kerberos build. This option is only supported on certain +platforms. + +@item --with-vague-errors + +If enabled, gives vague and unhelpful error messages to the client... er, +attacker. (Needed to meet silly government regulations; most other +sites will want to keep this undefined.) + +@item --with-kdc-kdb-update + +Set this option if you want to allow the KDC to modify the Kerberos +database; this allows the last request information to be updated, as +well as the failure count information. Note that this doesn't work if +you're using slave servers!!! It also causes the database to be +modified (and thus needing to be locked) frequently. Please note that +the implementors do not regularly test this feature. + +@item --with-kdb-db=database + +The configuration process will try to determine a working set of +libraries required to implement the Kerberos database. Configure will +look for interfaces that use or emulate a @samp{ndbm} or @samp{dbm} +library. Failing that, a build in copy of the Berkeley DB code will be +used. You may decide to compile a different interface than the default +by specifying one of "ndbm", "dbm", or "db". + +An important note on platforms where the @samp{ndbm} implementation is +based on @sc{GDBM} (such as the Linux Slackware distribution). @sc{GDBM} +has its own built in file locking which prevents simultaneous access to +the database from two separate processes in which one wants to modify +the database while the otherone only wants to read. (i.e. the KDC and +administrative servers). In this case, you will need to specify the use +of the Berkeley DB. + +@end table + +For example, in order to configure Kerberos on a Solaris machine using +the @samp{suncc} with the optimizer turned on, run the configure +script with the following options: + +@example +% ./configure --with-cc=suncc --with-ccopts=-O +@end example + +@node osconf.h, Shared Library Support, Options to Configure, Building Kerberos +@section @file{osconf.h} + +There is one configuration file which you may wish to edit to control +various compile-time parameters in the Kerberos distribution: +@file{include/krb5/stock/osconf.h}. The list that follows is by no means +complete, just some of the more interesting variables. + +Please note: The former configuration file @file{config.h} no longer +exists as its functionality has been merged into the auto-configuration +process. @xref{Options to Configure}. + + +@table @code + +@item DEFAULT_PROFILE_PATH + +The pathname to the file which contains the profiles for the known +realms, their KDCs, etc. + +The profile file format is no longer the same format as Kerberos V4's +@file{krb.conf} file. + +@item DEFAULT_LNAME_FILENAME + +The pathname to the database that maps authentication names to local +account names. See kdb5_anadd(8). + +@item DEFAULT_KEYTAB_NAME + +The type and pathname to the default server keytab file (the equivalent +of Kerberos V4's @file{/etc/srvtab}). + +@item DEFAULT_KDC_ENCTYPE + +The default encryption type for the KDC. + +@item KDCRCACHE + +The name of the replay cache used by the KDC. + +@item RCTMPDIR + +The directory which stores replay caches. + +@item DEFAULT_KDB_FILE + +The location of the default database + +@end table + +@node Shared Library Support, OS Incompatibilities, osconf.h, Building Kerberos +@section Shared Library Support + +Shared library support is provided for a few operating systems. There +are restrictions as to which compiler to use when using shared +libraries. In all cases, executables linked with the shared libraries in +this build process will have built in the location of the libraries, +therefore obliterating the need for special LD_LIBRARY_PATH, et al environment +variables when using the programs. Except where noted, multiple versions +of the libraries may be installed on the same system and continue to +work. + +Currently the supported platforms are: NetBSD 1.0A, AIX 3.2.5, AIX 4.1, +Solaris 5.3, Alpha OSF/1 >= 2.1, HP-UX >= 9.X. + +To enable shared libraries on the above platforms, run the configure +script with the option @samp{--enable-shared}. + +One special note is that if the Kerberos V4 compatibility is compiled +in, you @b{must not} specify an alternate Kerberos V4 library from the +one in the tree or you will be missing references. + +@menu +* Shared Library Theory:: +* NetBSD Shared Library Support:: +* AIX Shared Library Support:: +* Solaris 5.3 Shared Library Support:: +* Alpha OSF/1 Shared Library Support:: +@end menu + +@node Shared Library Theory, NetBSD Shared Library Support, Shared Library Support, Shared Library Support +@subsection Theory of How Shared Libraries are Used + +An explanation of how shared libraries are implemented on a given +platform is too broad a topic for this manual. Instead this will touch +on some of the issues that the Kerberos V5 tree uses to support version +numbering and alternate install locations. + +Normally when one builds a shared library and then links with it, the +name of the shared library is stored in the object +(i.e. libfoo.so). Most operating systems allows one to change name that +is referenced and we have done so, placing the version number into the +shared library (i.e. libfoo.so.0.1). At link time, one would reference +libfoo.so, but when one executes the program, the shared library loader +would then look for the shared library with the alternate name. Hence +multiple versions of shared libraries may be supported relatively +easily. @footnote{Under AIX for the RISC/6000, multiple versions of +shared libraries are supported by combining two or more versions of the +shared library into one file. The Kerberos build procedure produces +shared libraries with version numbers in the internal module names, so +that the shared libraries are compatible with this scheme. +Unfortunately, combining two shared libraries requires internal +knowledge of the AIX shared library system beyond the scope of this +document. Practicallyspeaking, only one version of AIX shared libraries +can be supported on a system, unless the multi-version library is +constructed by a programmer familiar with the AIX internals.} + +All operating systems (that we have seen) provide a means for programs +to specify the location of shared libraries. On different operating +systems, this is either specified when creating the shared library, and +link time, or both.@footnote{Both are necessary sometimes as the shared +libraries are dependent on other shared libraries} The build process +will hardwire a path to the installed destination. + + +@node NetBSD Shared Library Support, AIX Shared Library Support, Shared Library Theory, Shared Library Support +@subsection NetBSD Shared Library Support + +Shared library support has been tested under NetBSD 1.0A using +GCC 2.4.5. Due to the vagaries of the loader in the operating system, +the library load path needs to be specified in building libraries and in +linking with them. Unless the library is placed in a standard location +to search for libraries, this may make it difficult for developers to +work with the shared libraries. + +@node AIX Shared Library Support, Solaris 5.3 Shared Library Support, NetBSD Shared Library Support, Shared Library Support +@subsection AIX Shared Library Support + + AIX specifies shared library versions by combining multiple +versions into a single file. Because of the complexity of this process, +no automatic procedure for building multi-versioned shared libraries is +provided. Therefore, supporting multiple versions of the Kerberos shared +libraries under AIX will require significant work on the part of a +programmer famiiliar with AIX internals. + + AIX allows a single library to be used both as a static library +and as a shared library. For this reason, the @samp{--enable-shared} +switch to configure builds only shared libraries. On other operating +systems, both shared and static libraries are built when this switch is +specified. As with all other operating systems, only non-shared static +libraries are built when @samp{--enable-shared} is not specified. + + The AIX 3.2.5 linker dumps core trying to build a shared +@samp{libkrb5.a} produced with the GNU C compiler. The native AIX +compiler works fine. In addition, the AIX 4.1 linker is able to build a +shared @samp{libkrb5.a} when GNU C is used. + + +@node Solaris 5.3 Shared Library Support, Alpha OSF/1 Shared Library Support, AIX Shared Library Support, Shared Library Support +@subsection Solaris 5.3 Shared Library Support + +Shared library support only works when using the Sunsoft C compiler. We +are currently using version 3.0.1. + +The path to the shared library must be specified at link time as well as +when creating libraries. + +@node Alpha OSF/1 Shared Library Support, , Solaris 5.3 Shared Library Support, Shared Library Support +@subsection Alpha OSF/1 Shared Library Support + +Shared library support has been tested with V2.1 and higher of the +operating system. Shared libraries may be compiled both with GCC and the +native compiler. + +One of the nice features on this platform is that the paths to the +shared libraries is specified in the library itself without requiring +that one specify the same at link time. + +We are using the @samp{-rpath} option to @samp{ld} to place the library +load path into the executables. The one disadvantage of this is during +testing where we want to make sure that we are using the build tree +instead of a possibly installed library. The loader uses the contents of +@samp{-rpath} before LD_LIBRARY_PATH so we must specify a dummy _RLD_ROOT +and complete LD_LIBRARY_PATH in our tests. + +The one disadvantage with the +method we are using + +@node OS Incompatibilities, Using Autoconf, Shared Library Support, Building Kerberos +@section Operating System Incompatibilities + +This section details operating system incompatibilities with Kerberos V5 +which have been reported to the developers at MIT. If you find additional +incompatibilities, and/or discover work arounds to such problems, please +send a report to @b{krb5-bugs@@mit.edu}. Thanks! + +@menu +* Ultrix 4.2/3:: +* Alpha OSF/1 V1.3:: +* Alpha OSF/1 V2.0++:: +* BSDI:: +* Solaris versions 2.0 through 2.3:: +* Solaris 2.X:: +* SGI Irix 5.X:: +@end menu + +@node Ultrix 4.2/3, Alpha OSF/1 V1.3, OS Incompatibilities, OS Incompatibilities +@subsection Ultrix 4.2/3 + +On the DEC MIPS platform, using the native compiler, @file{md4.c} and +@file{md5.c} can not be compiled with the optimizer set at level 1. +That is, you must specify either @samp{--with-ccopts=-O} and +@samp{--with-ccopts=-g} to configure. If you don't specify either, the +compile will never complete. + +The optimizer isn't hung; it just takes an exponentially long time. +Compiling 6 out of the 48 algorithmic steps takes 3 seconds; compiling 7 +steps takes 9 seconds; compiling 8 steps takes 27 seconds, and so on. +Calculations estimate it will finish in approximately 3,469 billion +years.... + +Using GCC instead of the native compiler will also work fine, both with +or without optimization. + +@node Alpha OSF/1 V1.3, Alpha OSF/1 V2.0++, Ultrix 4.2/3, OS Incompatibilities +@subsection Alpha OSF/1 V1.3 + +Using the native compiler, compiling with the @samp{-O} compiler flag +causes the @code{asn.1} library to be compiled incorrectly. + +Using GCC version 2.6.3 or later instead of the native compiler will also work +fine, both with or without optimization. + +@node Alpha OSF/1 V2.0++, BSDI, Alpha OSF/1 V1.3, OS Incompatibilities +@subsection Alpha OSF/1 V2.0++ + +There used to be a bug when using the native compiler in compiling +@file{md4.c} when compiled without either the @samp{-O} or @samp{-g} +compiler options. We have changed the code and there is no problem +under V2.1, but we do not have access to V2.0 to test and see if the +problem would exist there. (We welcome feedback on this issue). There +was never a problem in using GCC version 2.6.3. + +In version 3.2 and beyond of the operating system, we have not seen any +problems with the native compiler. + +@node BSDI, Solaris versions 2.0 through 2.3, Alpha OSF/1 V2.0++, OS Incompatibilities +@subsection BSDI + +BSDI versions 1.0 and 1.1 reportedly has a bad @samp{sed} which causes +it to go into an infinite loop during the build. The work around is +to use a @samp{sed} from somewhere else, such as GNU. (This may be +true for some versions of other systems derived from BSD 4.4, such as +NetBSD and FreeBSD.) + +@node Solaris versions 2.0 through 2.3, Solaris 2.X, BSDI, OS Incompatibilities +@subsection Solaris versions 2.0 through 2.3 + +The @code{gethostbyname()} routine is broken; it does not return a fully +qualified domain name, even if you are using the Domain Name Service +routines. Since Kerberos V5 uses the fully qualified domain name as the +second component of a service principal (i.e, +@samp{host/tsx-11.mit.edu@@ATHENA.MIT.EDU}), this causes problems for servers +who try to figure out their own fully qualified domain name. + +Workarounds: + +@enumerate + +@item + Supply your own resolver library. (such as bind-4.9.3pl1 availavle +from ftp.vix.com) + +@item + Upgrade to Solaris 2.4 + +@item + Make sure your /etc/nsswitch.conf has `files' before `dns' like: + +@example +hosts: files dns +@end example + +and then in /etc/hosts, make sure there is a line with your +workstation's IP address and hostname, with the fully qualified domain +name first. Example: + +@example +18.172.1.4 dcl.mit.edu dcl +@end example + +Note that making this change may cause other programs in your +environment to break or behave differently. + +@end enumerate + +@node Solaris 2.X, SGI Irix 5.X, Solaris versions 2.0 through 2.3, OS Incompatibilities +@subsection Solaris 2.X + +You @b{must} compile Kerberos V5 without the UCB compatibility +libraries. This means that @file{/usr/ucblib} must not be in the +LD_LIBRARY_PATH environment variable when you compile it. Alternatively +you can use the @code{-i} option to @samp{cc}, by using the specifying +@code{--with-ccopts=-i} option to @samp{configure}. + +@node SGI Irix 5.X, , Solaris 2.X, OS Incompatibilities +@subsection SGI Irix 5.X + +If you are building in a tree separate from the source tree, the vendors +version of make does not work properly with regards to +@samp{VPATH}. It also has problems with standard inference rules in 5.2 +(not tested yet in 5.3) so one needs to use GNU's make. + +Under 5.2, there is a bug in the optional System V @code{-lsocket} +library in which the routine @code{gethostbyname()} is broken. The +system supplied version in @code{-lc} appears to work though so one may +simply specify @code{--with-netlib} option to @samp{configure}. + +In 5.3, @code{gethostbyname()} is no longer present in @code{-lsocket} and +is no longer an issue. + +@node Using Autoconf, , OS Incompatibilities, Building Kerberos +@section Using @samp{Autoconf} + +(If you are not a developer, you can skip this section.) + +In most of the Kerberos V5 source directories, there is a +@file{configure} script which automatically determines the compilation +environment and creates the proper Makefiles for a particular platform. +These @file{configure} files are generated using @samp{autoconf} version +2.4, which can be found in the @file{src/util/autoconf} directory in the +distribution. + +Normal users will not need to worry about running @samp{autoconf}; the +distribution comes with the @file{configure} files already prebuilt. +Developers who wish to modify the @file{configure.in} files should see +@ref{Top, , Overview, autoconf, The Autoconf Manual}. + +Note that in order to run @samp{autoconf}, you must have GNU @samp{m4} +in your path. Before you use the @samp{autoconf} in the Kerberos V5 +source tree, you may also need to run @samp{configure}, and then run +@samp{make} in the @file{src/util/autoconf} directory in order to +properly set up @samp{autoconf}. + +One tool which is provided for the convenience of developers can be +found in @file{src/util/reconf}. This program should be run while the +current directory is the top source directory. It will automatically +rebuild any @file{configure} files which need rebuilding. If you know +that you have made a change that will require that all the +@file{configure} files need to be rebuilt from scratch, specify the +@code{--force} option: + +@example +% cd /u1/krb5/src +% ./util/reconf --force +@end example + +The developmental sources are a raw source tree (before it's been packaged +for public release), without the pre-built @file{configure} files. +In order to build from such a source tree, you must do: + +@example +% cd krb5/util/autoconf +% ./configure +% make +% cd ../.. +% util/reconf +@end example + +Then follow the instructions for building packaged source trees (above). +To install the binaries into a binary tree, do: + +@example +% cd /u1/krb5/src +% make all +% make install DESTDIR=somewhere-else +@end example + +@node Installation, Troubleshooting, Building Kerberos, Top +@chapter Installation + +When you are installing Kerberos for the first time at a site, you must +first decide on the realm name you will use for your site, and select a +machine to host the @dfn{Kerberos server}, which is also known as the +@dfn{KDC} (@dfn{Key Distribution Center}). The KDC must be located on a +secure machine, since its database contains the keys for the entire +realm. It is extremely important that the database be kept secure, if +the realm's Kerberos service is to remain secure. + +Once a KDC is installed and configured, you may then set up one or more +client machines, and one or more application machines. + +@menu +* Background:: +* Installation on any Machine:: +* Installing the KDC:: +* Migrating from V4 to V5 Kerberos:: +* A Sample Application:: +* Installing Kerberos Applications:: +* Common Kerberos Service Names:: +@end menu + +@node Background, Installation on any Machine, Installation, Installation +@section Background Information + +Your system's security is only as good as the security of your +@samp{root} password. You should take other precautions to protect your +system security in addition to installing Kerberos. Kerberos cannot +protect you from someone who is able to steal @samp{root} privileges. +Kerberos also does not protect you from break-ins caused by bugs in your +daemons (e.g., @samp{fingerd} or @samp{sendmail}). On almost all UNIX +systems, if intruders can break in as an ordinary users, they can obtain +superuser privileges by exploiting bugs or imperfect configuration files. + + +@node Installation on any Machine, Installing the KDC, Background, Installation +@section Installation on any Machine + +The following steps must be performed no matter what type of +machine (KDC, Client, or Application server) you are installing. All +machines functioning within the same administrative domain must use the +same Kerberos realm name; and all machines which are using Kerberos must +have the Kerberos configuration files properly installed. + +If you are installing Kerberos on a machine that will act only as a +Kerberos client, this section describes all that you need to do. If you +are installing a KDC, or an Kerberos Application server, you will also +need to complete the procedures detailed in @ref{Installing the KDC}, or +@ref{A Sample Application}, after you finish with the procedures found +in this section. + +@menu +* Picking a Realm Name:: +* Configuration files:: +* Recommended Programs:: +@end menu + +@node Picking a Realm Name, Configuration files, Installation on any Machine, Installation on any Machine +@subsection Picking a Realm Name + +Before you install Kerberos V5 at your site, you have to choose a +@dfn{realm name}, the name that specifies the system's administrative +domain. By convention, we suggest that you use your internet domain +name, in capital letters. (Kerberos realm names are case-sensitive, so +it's important that your realm name be in all upper case.) For example, +if your internet domain is @code{cygnus.com} (so that you have hostnames +such as @code{ftp.cygnus.com} and @code{tweedledum.cygnus.com}), then +your Kerberos realm should be @code{CYGNUS.COM}. Please note that +changing realm names is hard. Get it right the first time. + +@node Configuration files, Recommended Programs, Picking a Realm Name, Installation on any Machine +@comment node-name, next, previous, up@section +@subsection Configuration files + + +@menu +* krb5.conf:: +* Converting V4 configuration files:: +* /etc/services:: +@end menu + +@node krb5.conf, Converting V4 configuration files, Configuration files, Configuration files +@subsubsection The @file{krb5.conf} File + +The @file{krb5.conf} file contains information needed by the Kerberos V5 +library including a system's default Kerberos +realm, and the locations of the Kerberos servers. + +The @file{krb5.conf} uses an INI-style format. Sections are delimited by +square braces; within each section, there are relations where tags can +be assigned to have specific values. Tags can also contain a +subsection, which contains further relations or subsections. A tag can +be assigned to multiple values. + +Create a @file{/etc/krb5.conf} file using the following format: + +@example +[libdefaults] + default_realm = + +[realms] + = @{ + kdc = + admin_server = + default_domain = + @} + +[domain_realm] + <.domain.name> = +@end example + +Where @samp{realm_name} specifies the default realm to be used by that +particular system, and @samp{master_server_name} specifies the machine +name on which you will run the master server. The keywords @samp{kdc} +and @samp{admin_server} lists the location of the realms KDC and +administration servers. + +For example, if your realm name is @samp{ATHENA.MIT.EDU} and your master +server's name is @samp{kerberos.mit.edu}, the file should have these +contents: + +@example +[libdefaults] + default_realm = ATHENA.MIT.EDU + +[realms] + ATHENA.MIT.EDU = @{ + kdc = KERBEROS.MIT.EDU + admin_server = KERBEROS.MIT.EDU + default_domain = MIT.EDU + @} + +[domain_realm] + .mit.edu = ATHENA.MIT.EDU + mit.edu = ATHENA.MIT.EDU +@end example + + +In many situations, the default realm in which a host operates will be +identical to its Internet domain name, with the first component removed +and all letters capitalized. For example, @code{ftp.cygnus.com} is +traditionally in the realm @code{CYGNUS.COM}. +If this is not the case, you will need to establish a translation from +host name or domain name to realm name. This is accomplished with the +@samp{[domain_realm]} stanza. + +Each line of the translation file specifies either a host name or domain +name, and its associated realm: + +@example +[domain_realm] + <.domain.name> = KERBEROS.REALM1 + = KERBEROS.REALM2 +@end example + +For example, to map all hosts in the domain LSC.MIT.EDU to LSC.MIT.EDU +but the host FILMS.LSC.MIT.EDU to MIT.EDU your file would read: +@example +[domain_realm] + .LSC.MIT.EDU = LSC.MIT.EDU + FILMS.LSC.MIT.EDU = MIT.EDU +@end example + +If a particular host name matches both a domain name and a host name in +@samp{[domain_realm]}, the entry containing the host name takes precedence. + +See the @file{[SOURCE_DIR]/config-files/krb5.conf} file for an example +@file{krb5.conf} file. That file has examples of how to provide backup +servers for a given realm (additional lines with the same leading realm +name) and how to designate servers for remote realms. + +@node Converting V4 configuration files, /etc/services, krb5.conf, Configuration files +@subsubsection Conversion of V4 configuration files + +Kerberos V4's @file{krb.conf} and @file{krb.realms} files formats are no +longer used by the V5 library. A @sc{PERL} script has been provided to allow +for "easy" generation of an initial @file{krb5.conf}. It is located in +@file{[SOURCE_DIR]/config-files/convert-config-files}. The produced file +should be checked for errors. + +Note that if you are planning on using certain applications with +Kerberos V4 compatibility compiled in, the V4 library still needs the +files @file{krb.conf} and @file{krb.realms}. + + +@node /etc/services, , Converting V4 configuration files, Configuration files +@subsubsection /etc/services + +All hosts which will use Kerberos will need to have certain ports +defined in the system's @file{/etc/services} file. The file +@file{[SOURCEDIR]/config-files/services.append} contains the entries +which should be appended to the @file{/etc/services} file. Please note +that not all of the entries are required as several of the programs have +defaults built into the programs. This will be documented sometime in +the future. + +If you are using the Network Information Services (NIS) or Yellow +Pages (YP), you will need to add the services in the +@file{services.append} file to the services exported in the NIS or YP +server. + +@node Recommended Programs, , Configuration files, Installation on any Machine +@subsection Recommended Programs + +The following files should be installed on all machines which are +running Kerberos, either as a client, a KDC, or an application server: + +If you used the default @samp{make install} without using the +@samp{--prefix} argument to @file{configure}, then [K_USER] refers to +@file{/usr/local/bin}. + +@itemize @bullet +@item @file{/etc/krb5.conf} --- This files contains information required +by Kerberos V5 giving system defaults as well as locations of Kerberos +servers. +@item @file{[K_USER]/kinit} --- This program allows you to obtain +Kerberos credentials. +@item @file{[K_USER]/kdestroy} --- This program allows you to destroy +Kerberos credentials which are no longer needed. +@item @file{[K_USER]/klist} ---- This program allows you to list the +credentials found in your credentials cache. +@end itemize + +@node Installing the KDC, Migrating from V4 to V5 Kerberos, Installation on any Machine, Installation +@section Installing the KDC + +@menu +* kdc.conf:: +* Initializing the KDB:: +* Storing the Master Password:: +* Adding Users to the Database:: +* Starting the Kerberos Server:: +* Setting up Slave Kerberos Servers:: +* Inter-realm Kerberos Operation:: +* The Administration Server:: +* Testing the Kerberos Server:: +@end menu + +@node kdc.conf, Initializing the KDB, Installing the KDC, Installing the KDC +@subsection The optional @file{kdc.conf} profile + +There is an optional configuration file @file{kdc.conf} that allows one +to specify per-realm configuration data to be used by the Kerberos V5 +Authentication Service and Key Distribution Center. This information +includes database locations, key and per-realm defaults, port numbers, +ticket life times, etc. The location of the configuration file is +@file{/usr/local/lib/krb5kdc/kdc.conf}. + +See the man page or @file{[SOURCEDIR]/config-files/kdc.conf.M} for more +details. + +This document assumes that you do not have the @file{kdc.conf} +configuration file installed. + +Note also that @code{[logging]} subsection to @file{/etc/krb5.conf} can +be used to specify where to syslog messages regarding server activity. + +@node Initializing the KDB, Storing the Master Password, kdc.conf, Installing the KDC +@subsection Initializing the Kerberos Database + +Login to the Kerberos KDC, and use the @samp{su} command to become root. +If you installed the Kerberos administration tools +with the @samp{make install} command and the default pathnames, +they should be in the @file{/usr/local/admin} directory. +If you installed the tools in a different directory, +hopefully you know what it is. +From now on, we will refer to this directory as [ADMIN_DIR]. + +The default database will be located in the directory +@file{/usr/local/lib/krb5kdc} unless changed in the configuration +process. From now on, we will call this [DB_DIR]. + +The @samp{kdb5_create} command creates and initializes the master database. +It asks you to the database's master password. +Do not forget this password. +If you do, the database becomes useless. +(Your realm name should be substituted for [REALMNAME] below.) +@xref{Storing the Master Password} for an alternative way of dealing +with this master password. + +Because the install process does not create [DB_DIR] you need to do so +yourself. + +Use @samp{kdb5_create} as follows: + +@example +# @b{mkdir [DB_DIR]} +# @b{[ADMIN_DIR]/kdb5_create} +Initializing database '[DB_DIR]/principal' for realm '[REALMNAME]', +master key name 'K/M@@[REALMNAME]' +You will be prompted for the database Master Password. +It is important that you NOT FORGET this password. +Enter KDC database master key: @b{<-- [Enter the master password.]} +Re-enter KDC database master key to verify: @b{<-- [Re-enter it.]} +@end example + + +@node Storing the Master Password, Adding Users to the Database, Initializing the KDB, Installing the KDC +@subsection Storing the Master Password + +The @samp{kdb5_stash} command "stashes" the master password in the file +@file{[DB_DIR]/.k5.[REALM.NAME]} so that the Kerberos server can be started +automatically during an unattended reboot of the master server. Other +administrative programs use this hidden password so that they can access +the master database without someone having to manually provide the +master password. This command is an optional one; if you'd rather enter +the master password each time you start the Kerberos server, don't use +@samp{kdb5_stash}. + +On the one hand, if you use @samp{kdb5_stash}, a copy of the master key +will reside on a disk, which may not be acceptable; on the other hand, +if you don't use @samp{kdb5_stash}, the server cannot be started unless +someone is around to type the password manually. + +The command merely prompts for the master password: + +@example +# @b{[ADMIN_DIR]/kdb5_stash} +Enter KDC database master key: @b{<-- [Enter the master password.]} +@end example + +WARNING: If your Kerberos database master key is compromised and the +database is obtained, the security of your entire authentication system +is compromised. (If this happens to you, all of your user's passwords must +be set to new values manually --- i.e., not using Kerberos.) The master +key must be a carefully kept secret. If you keep backups, you must +guard all the master keys you use, in case someone has stolen an old +backup and wants to attack users' whose passwords haven't changed since +the backup was stolen. This is why we provide the option not to store +it on disk. + +@node Adding Users to the Database, Starting the Kerberos Server, Storing the Master Password, Installing the KDC +@subsection Adding Users to the Database + +The @samp{kdb5_edit} program may be used to add new users and services to +the master database, and to modify existing database +information. @xref{The Administration Server} for an alternative method +once the Kerberos environment is up and running. + +For example, to add yourself to the newly created database: (replace +@samp{[USERNAME]} with your username with. + +@example +# @b{[ADMIN_DIR]/kdb5_edit} +kdb5_edit: @b{ank [USERNAME]} +Enter password: @b{<-- [Enter your password.]} +Re-enter password for verification: @b{<-- [Re-enter it.]} +kdb5_edit: @b{quit} +@end example + +The @samp{ank} command is short for "add_new_key"; this command adds a +new user to the database. To see what other commands which @samp{kdb5_edit} +supports, type @kbd{? @key{RET}} at the @samp{kdb5_edit} prompt. + +@node Starting the Kerberos Server, Setting up Slave Kerberos Servers, Adding Users to the Database, Installing the KDC +@subsection Starting the Kerberos Server + +Assuming that you didn't use the @samp{--prefix} argument to +@file{configure}, then [K_SERVER] refers to @file{/usr/local/sbin}. + +In order to start the Kerberos server, simply run it. It will fork and +disassociate from the terminal unless the @samp{-n} argument is used. + +@example +# @b{[K_SERVER]/krb5kdc} +@end example + +If you have used the @samp{kdb5_stash} command to store the master database password, +the server will start automatically. +If you did not use @samp{kdb5_stash}, +use the following command: + +@example +# @b{[K_SERVER]/krb5kdc -m} +@end example + +The server will prompt you to enter the master password before actually +starting itself. + +@node Setting up Slave Kerberos Servers, Inter-realm Kerberos Operation, Starting the Kerberos Server, Installing the KDC +@subsection Setting up Slave Kerberos Servers + +Slave Kerberos servers allow clients to be able to get Kerberos tickets +even when the Master server is not available. Users will not be able to +change their passwords --- changes can only be made to database on the +Master server; however, users will be able to authenticate to +application servers, which is critically important in a distributed +client-server environment. The current implementation of the client code +does not provide load sharing in that the order of servers contacted is +the same as those listed in the @file{krb5.conf} file. + +@menu +* Kerberos Slave Database Propagation:: +* Installing a Slave Server:: +@end menu + +@node Kerberos Slave Database Propagation, Installing a Slave Server, Setting up Slave Kerberos Servers, Setting up Slave Kerberos Servers +@subsubsection Kerberos Slave Database Propagation + +In order to propagate the Kerberos database from the Master server to +the slaves, the @samp{kprop} and @samp{kpropd} client/server programs +are used. Periodically, the Master server will dump the Kerberos +database out into an ASCII format, using the @samp{kdb5_edit} program. +The master server will then run @samp{kprop} to propagate the dumped +database file to each slave server. + +On the slave server, the @samp{kpropd} program is invoked out of +@samp{inetd} server. After @samp{kprop} and @samp{kpropd} have +mutually authenticated with one another, and @samp{kpropd} is satisfied +with the identity of the Master server, then the dumped ASCII database +is transferred to the slave server in an encrypted fashion. After the +database is transfered, @samp{kpropd} will then run @samp{kdb5_edit} +with the appropriate arguments in order to undump the database into a +usable form by the KDC on the slave server. + +@node Installing a Slave Server, , Kerberos Slave Database Propagation, Setting up Slave Kerberos Servers +@subsubsection Installing a Slave Server + +@b{To be written.} + + +@node Inter-realm Kerberos Operation, The Administration Server, Setting up Slave Kerberos Servers, Installing the KDC +@subsection Inter-realm Kerberos Operation + +@b{To be written.} + +@node The Administration Server, Testing the Kerberos Server, Inter-realm Kerberos Operation, Installing the KDC +@subsection The Administration Server + +There is currently an administration server in the Kerberos source tree. +It is, however, very rough, and it will likely be significantly changed +or replaced before the 1.0 release. Hence, this manual does not +document the current administration server. Changes to the database can +be made by logging in to the KDC directly, and using the +@samp{kdb5_edit} program; see @ref{Adding Users to the Database}. + +@node Testing the Kerberos Server, , The Administration Server, Installing the KDC +@subsection Testing the Kerberos Server + +Use the @samp{kinit} command to obtain Kerberos credentials. This command +creates your credentials cache and stores your credentials in it. + +If you used the default @samp{make install} command and directories to +install the Kerberos user utilities, @samp{kinit} will be in the +@file{/usr/local/bin} directory. From now on, we'll refer to the Kerberos user +commands directory as [K_USER]. + +Use @samp{kinit} as follows: + +@example +% @b{[K_USER]/kinit [USERNAME]} +Password for [USERNAME]@@[REALMNAME]: @b{<-- enter your password} +@end example + + +Use the @samp{klist} program to list the contents of your ticket file. + +@example +% @b{[K_USER]/klist} +Ticket cache: /tmp/krb5cc_15806 +Default principal: [USERNAME]@@[REALMNAME] + + Valid starting Expires Service principal +31-Jan-95 21:58:32 1-Feb-95 05:57:39 krbtgt/[REALMMNAME]@@[REALMNAME] + +@end example + +@ignore +@c not yet... +If you have any problems, you can examine the log file +@file{/krb5/kerberos.log} on the Kerberos server machine to see if +there was some sort of error. +@end ignore + +@node Migrating from V4 to V5 Kerberos, A Sample Application, Installing the KDC, Installation +@section Migrating from V4 to V5 Kerberos + +@b{To be written.} A rough idea of the procedure that one may follow is +in @file{[SOURCE_DIR]/kdc/migration.doc}. + +@node A Sample Application, Installing Kerberos Applications, Migrating from V4 to V5 Kerberos, Installation +@section A Sample Application + +This release of Kerberos comes with a sample application server and a +corresponding client program. You will find this software +@file{[K_SERVER]/sserver} and @file{[K_USER]/sclient}, which is the +server's executable, and the client program's executable, respectively. + +The programs are rudimentary. +When they have been installed (the installation procedure is described +in detail later), they work as follows: + +@enumerate + +@item + The user starts @samp{sclient} and provides as arguments +to the command the name of the server machine and an optional port on +which to contact the server. + +@item + @samp{sclient} contacts the server machine and +authenticates the user to @samp{sserver}. + +@item + @samp{sserver} authenticates itself to @samp{sclient} (thus +performing mutual authentication), and +then returns a message to the client program. +This message contains the name of the Kerberos principal that was used +to authenticate to @samp{sserver}. + +@item + @samp{sclient} displays the server's message on the user's +terminal screen. + +@end enumerate + +@menu +* Installing the Sample Application:: +* Testing the Sample Server:: +@end menu + +@node Installing the Sample Application, Testing the Sample Server, A Sample Application, A Sample Application +@subsection Installing the Sample Application + +In general, +you use the following procedure to install a Kerberos-authenticated +server-client system. + +@enumerate + +@item + Add the appropriate entry to the Kerberos database using @samp{kdb_edit} + +@item + Create a @file{/etc/v5srvtab} file for the server machine. + +@item + Install the service program and the @file{/etc/v5srvtab} +file on the server machine. + +@item + Install the client program on the client machine. + +@item + Update the @file{/etc/services} file on the client and server machines. +@end enumerate + +We will use the sample application as an example, although programs +which do not take requests via the @samp{inetd} program may have +slightly different installation procedures. @samp{Inetd} starts +@samp{sserver} each time a client process contacts the server machine. +@samp{sserver} processes the request, terminates, then is restarted +when @samp{inetd} receives another @samp{sserver} request. When you +install the program on the server, you must add a @samp{sample} entry to +the server machine's @file{/etc/inetd.conf} file. + +The following description assumes that you are installing +@samp{sserver} on the machine @samp{jimi.mit.edu}. +Here's the process, step by step: + +@enumerate + +@item + Login as root or @samp{su} to root on the Kerberos server machine. +Use the @samp{kdb5_edit} program to create an entry for +@code{sample} in the Kerberos database: + +@example +# @b{[ADMIN_DIR]/kdb5_edit} +kdb5_edit: @b{add_random_key sample/jimi.mit.edu} +kdb5_edit: @b{quit} +@end example + +(Note: @samp{add_random_key} may be abbreviated as @samp{ark}.) + +@item + Use @samp{kdb5_edit} to create a @file{srvtab} file +for @samp{sserver}'s host machine: + +@example +# @b{[ADMIN_DIR]/kdb5_edit} +kdb5_edit: @b{extract_srvtab jimi.mit.edu sample} +'sample/jimi.mit.edu@@ATHENA.MIT.EDU' added to keytab 'WRFILE:jimi.mit.edu-new-srvtab' +kdb5_edit: @b{quit} +@end example + +(Note: @samp{extract_srvtab} may be abbreviated as @samp{xst}.) + +Transfer the @file{jimi.mit.edu-new-srvtab} file to @samp{jimi.mit.edu} +and install it as @file{/etc/v5srvtab}. + +@b{WARNING}: Note that this file is equivalent to the service's password and +should be treated with care. For example, it could be transferred by +removable media, but should not be sent over an open network in the +clear. This file should installed such that only the root user can read +it. + +@item + Add the following line to the @file{/etc/services} file on +@samp{jimi.mit.edu}, and on all machines that will run the +@samp{sample_client} program: + +@example +sample 906/tcp # Kerberos sample app server +@end example + +@item + Add a line similar to the following line to the @file{/etc/inetd.conf} +file on @samp{sample_server}'s machine: + +@example +sample stream tcp nowait switched root + [K_SERVER]/sserver sample_server +@end example + +where [K_SERVER] should be substituted with +the path to the @samp{sserver} program. +(This @file{inetd.conf} information should be placed on one line.) +You should examine existing lines in @file{/etc/inetd.conf} and use the +same format used by other entries (e.g. for telnet). Most systems do +not have a column for the `switched' keyword, and some do not have a +column for the username (usually `root', as above). + +@item + Restart @samp{inetd} by sending the current @samp{inetd} process +a hangup signal: + +@example +# @b{kill -HUP} @i{process_id_number} +@end example + +@item + The @samp{sserver} is now ready to take @samp{sclient} requests. + +@end enumerate + +@node Testing the Sample Server, , Installing the Sample Application, A Sample Application +@subsection Testing the Sample Server + +Assume that you have installed @samp{sserver} on @samp{jimi.mit.edu}. + +Login to your workstation and use the @samp{kinit} command to +obtain a Kerberos ticket-granting ticket: + +@example +% @b{[K_USER]/kinit [USERNAME]} +Password for [USERNAME]@@[REALMNAME]: @b{<--- Enter your password} +@end example + +Now use the @samp{sclient} program as follows: + +@example +% @b{[K_USER]/sclient jimi} +@end example + +The command should display something like the following: + +@example +sendauth succeeded, reply is: +reply len 29, contents: +You are [USERNAME]@@[REALMNAME] +@end example + +@node Installing Kerberos Applications, Common Kerberos Service Names, A Sample Application, Installation +@section Installing Kerberos Applications + + In addition to the sample application, Kerberos comes with +several servers that can be installed on workstations to provide secure +network services such as FTP, Telnet, and Rlogin. This section +describes these services and how to install them. First, a general +procedure is outlined for configuring a workstation to run Kerberos +application servers. Then, details of the particular configuration +options required by each server are presented. + + +@menu +* Levels of Security:: +* Preparing a Workstation for Kerberos Application Servers:: +* BSD Utilities:: +* Telnet and FTP:: +@end menu + +@node Levels of Security, Preparing a Workstation for Kerberos Application Servers, Installing Kerberos Applications, Installing Kerberos Applications +@subsection Levels of Security + + Before installing Kerberized servers, it is a good idea to +decide on a security policy for your environment. While developing a +comprehensive security policy is beyond the scope of these instructions, +there are several interactions between Kerberos servers and non-Kerberos +servers, as well as different modes in which Kerberos servers can run +that should be considered. In general, there are three levels of +connections: + +@enumerate + +@item +Encrypted Kerberos connections are the most secure services provided by +the Kerberos environment. Only encrypted services provide +confidentiality---encryption is required to make sure a passive +eavesdropper does not collect sensitive data, such as passwords, sent +over connections. Besides providing confidentiality, encryption +provides protection against active attacks. Without encryption or some +other form of integrity, an attacker may be able to insert commands or +change data in an authenticated session. + + +@item +The next level of security is Kerberos-authenticated services without +encryption. Without encryption, there is no confidentiality, and some +active attacks are possible. However, unencrypted services are faster +and are available commercially outside the United States. In addition, +the window of exposure to attack is generally limited to the lifetime of +a session---it is difficult for an attacker who does not have tickets to +start a new session if a Kerberos authentication exchange must take +place at the beginning of every session. + +@item +Passworded services provide the next lower level of security. +Unfortunately, it is all-to-easy for a passive attacker to use software +such as a packet sniffer to find passwords traveling over a network. +Additionally, once an attacker knows a password, they can start +additional sessions at future times until the password is changed from a +secure location. Despite the disadvantages of password-based network +services, there are some common reasons for enabling them. First, most +clients only support password-based services; not everyone has Kerberos +or other cryptographically-secure network services. Second, in some +environments, where the network is secure, passwords may be a reasonable +solution. Also, particularly on public-access systems, it is common to +enable password-based services for normal users, while using more-secure +services such as Kerberos for root logins by administrators. + +@item +The least secure common category of services are trust or host-based +services. These services use an IP address or client-supplied assertion +to provide authentication. Examples of host-based services include +@samp{rlogin}, @samp{rsh}, and the @samp{on} or @samp{rexd} service. It +is generally sufficient to know that a user exists on a target system, +and to know that a host-based or trust-based service is enabled in order +to exploit the service. Whenever possible, these services should be +disabled; there are few situations in which an a security policy is both +compatible with Kerberos and host-based services. +@end enumerate + + Next, decide whether Kerberos V4 compatibility is necessary. +Unencrypted Kerberos V4 services suffer from all the problems of +unencrypted Kerberos V5 services: lack of confidentiality and +susceptibility to active attack. In addition, the lack of a replay cache +in Kerberos V4 makes these active attacks much easier. Also, design bugs +in the Kerberos V4 BSD utilities such as @samp{rlogin}, @samp{rsh} and +@samp{rcp} cause the availability of an unencrypted service to +significantly decrease the security of a system, even if only the +encrypted service is ever used. For example, a system that runs both +encrypted and unencrypted Kerberos V4 @samp{rlogin} servers is less secure +than a system only running the encrypted service, even if users only +ever connect to the encrypted service. + + Therefore, if Kerberos V4 interoperability is desired or required, +try to avoid running unencrypted Kerberos V4 services wherever possible. +In particular, only enable encrypted @samp{rlogin} if at all possible. +Naturally, some environments will require additional Kerberos V4 +functionality, like @samp{rsh}. The Kerberos V5 versions of these services, +with Kerberos V4 interoperability enabled, are not any weaker than their +Kerberos V4 counterparts. So, if the existing Kerberos V4 security policy +allows these services, then enabling them under the Kerberos V5 security +policy should not be a problem. + + In addition, the issue of compatibility with older Kerberos V5 +clients must be considered. For the most part, this compatibility is +automatic, and has few security implications. The major exception to +this is the BSD utilities. Until Kerberos V5 Beta6, these utilities +inherited a few design defects from the Kerberos V4 BSD utilities. In +particular, the presence of an unencrypted service that was never used +adversely effected the security of an encrypted service. The solution +that was adopted preserves compatibility with Kerberos V5 Beta5 clients. +Unfortunately, older clients are incompatible with this scheme. If +interoperability with older clients is necessary, then the new scheme +for checksums can be disabled on the server. If these checksums are +disabled, there is a short window between when a connection is opened +and when the replay cache is updated where an active attack is possible. +Alternatively, sites wishing to enable all security features may wish to +disable compatibility with Kerberos V5 Beta5 BSD utilities. +@xref{Checksums}, for full details. + + In conclusion, as you prepare to install Kerberos application +servers, you should have answers to the following questions: + +@enumerate + +@item +What levels of services are appropriate for your security policy: +encrypted services, authenticated but not encrypted services, +password-based services, or host-based services? + +@item +Do you wish to enable Kerberos V4 compatibility? If so, do you need to +enable unencrypted services? + +@item +Do you need compatibility with Kerberos V5 clients before Beta5 +(released in May, 1995)? Do you wish to disable compatibility with +Beta5 clients for slightly enhanced security? +@end enumerate + + + +@node Preparing a Workstation for Kerberos Application Servers, BSD Utilities, Levels of Security, Installing Kerberos Applications +@subsection Preparing a Workstation for Kerberos Application Servers + + + The following procedure is very similar to the installation +procedure for the sample Kerberos server. @xref{Installing +the Sample Application}. However, instead of using the sample service, +this configuration is designed to set up host-based services. + +The following description assumes that you are installing @samp{sserver} +on the machine @samp{jimi.mit.edu}. Repeat these steps for each +workstation that will be running host-based servers. Note that it is +not necessary to run these procedures on client machines--machines used +only to connect to secure network services, but that do not run any +servers of their own. Here's the process, step by step: + +@enumerate + +@item + Login as root or @samp{su} to root on the Kerberos server machine. +Use the @samp{kdb5_edit} program to create a service entry for +@code{host} in the Kerberos database: + +@example +# @b{[ADMIN_DIR]/kdb5_edit} +kdb5_edit: @b{add_random_key host/jimi.mit.edu} +kdb5_edit: @b{quit} +@end example + +(Note: @samp{add_random_key} may be abbreviated as @samp{ark}.) + +@item + Use @samp{kdb5_edit} to create a @file{srvtab} file +for @samp{sserver}'s host machine: + +@example +# @b{[ADMIN_DIR]/kdb5_edit} +kdb5_edit: @b{extract_srvtab jimi.mit.edu host} +'host/jimi.mit.edu@@ATHENA.MIT.EDU' added to keytab 'WRFILE:jimi.mit.edu-new-srvtab' +kdb5_edit: @b{quit} +@end example + +(Note: @samp{extract_srvtab} may be abbreviated as @samp{xst}. Also, +additional services can be listed after @samp{host} on the +@samp{extract_srvtab} line; for example if the host jimi also runs the +sample server, the @samp{sample} service might have been listed after +host.) + +Transfer the @file{jimi.mit.edu-new-srvtab} file to @samp{jimi.mit.edu} +and install it as @file{/etc/v5srvtab}. + +@b{WARNING}: Note that this file is equivalent to the service's password and +should be treated with care. For example, it could be transferred by +removable media, but should not be sent over an open network in the +clear. This file should be installed such that only the root user can read +it. + +@item +Make sure that the @samp{/etc/services} file has been updated to include +Kerberos services. In particular, look for @samp{klogin}, +@samp{eklogin}, and @samp{kshell}. + +@item +For each server you plan to run, add a line to @file{/etc/inetd.conf}. +The following sections will give details on what this line should look +like for each Kerberos application service. + +@item +Consider removing non-Kerberized services like @samp{rlogin}, +@samp{rsh}, @samp{rexd}, and others, in accordance with the security policy you decided on in the last section. + +@item + Restart @samp{inetd}. On most systems, this is done by sending the current @samp{inetd} process +a hangup signal: + +@example +# @b{kill -HUP} @i{process_id_number} +@end example + +@item +Try using the Kerberos applications to connect to the host. + +@end enumerate + +@node BSD Utilities, Telnet and FTP, Preparing a Workstation for Kerberos Application Servers, Installing Kerberos Applications +@subsection BSD Utilities + + This section describes installing servers for the BSD utilities: +@samp{kshd} and @samp{klogind}. The @samp{klogind} server implements the +protocol used by the Kerberized @samp{rlogin} client. The @samp{kshd} +server implements the protocol used by the @samp{rsh} and @samp{rcp} +clients. + + These daemons take a common set of options to enable support for +different versions of Kerberos. The @samp{-5} option enables Kerberos +V5 support, and the @samp{-4} option enables Kerberos V4 support. At +least one of these options must be supplied or the server will refuse +all connections. Both options can be supplied if compatibility with +both versions of Kerberos is desired. + + Both the @samp{klogind} and @samp{kshd} take an @samp{-e} option +to control encryption; because of the design of the servers, it works +slightly differently. The Kerberos login service listens on two +different ports, one for encrypted connections, and one for unencrypted +connections. Because @samp{klogind} is started by @samp{inetd}, it +needs to know whether it is servicing an encrypted or unencrypted +connection. Thus, the @samp{-e} option tells @samp{klogind} that it is +listening to the encrypted port. Typically, systems that allow both +encrypted and unencrypted logins have two lines in @file{inetd.conf}, +one for the @samp{klogin} service and one for the @samp{eklogin} +service. The line for the @samp{eklogin} service uses the @samp{-e} +option, while the line for the @samp{klogin} service does not. Systems +only supporting encrypted logins simply have the @samp{eklogin} line. + + On the other hand, @samp{kshd} listens to encrypted and +unencrypted requests on the same port; information from the client +identifies the connection's encryption status. So, @samp{kshd} +interprets the @samp{-e} option to mean that encryption is required. If +this option is specified, unencrypted connections are dropped. Thus, +specifying @samp{-e} to @samp{kshd} is like only having a line for +@samp{eklogin}. + +@menu +* Checksums:: Checksum facility for dealing with active attacks. +* BSD Utility Configuration Example:: Sample @file{inetd.conf} entries for BSD utilities. +@end menu + +@node Checksums, BSD Utility Configuration Example, BSD Utilities, BSD Utilities +@subsubsection Checksums + + Under previous versions of Kerberos, it was possible for an active +attacker to change certain information in the initial authentication +exchange without this change being detected. Starting with Kerberos V5, +Beta6, this information is protected by a checksum passed in the +Kerberos authenticator. Ideally, the server could detect the presence +of this checksum and use it if it were present. This way, +administrators could be sure to use new clients that produced the +checksum, while users who were not as concerned about security could use +a wider range of clients. + + This is how the checksum feature works by default. +Unfortunately, clients previous to Kerberos V5, Beta5 used the checksum +field to incorporate semi-random data into the Kerberos authentication +exchange. It is impossible to distinguish these bogus checksums from +checksums that have been produced by modern clients, but modified by an +active attacker. Thus, the checksum feature is incompatible with +previous releases of Kerberos V5. Three modes of operation are provided +to meet the configuration needs of different sites: + +@enumerate + +@item +The @samp{-c} option to both @samp{kshd} and @samp{klogind} requires +that checksums be present and valid. This only works with clients more +recent than Kerberos V5, Beta6. An error will be given when an older +client tries to connect. This option is incompatible with Kerberos V4; +Kerberos V4 clients do not include a checksum. If this option is used +in conjunction with the @samp{-4} option for Kerberos V4 compatibility, +a warning about the configuration error will be logged on each +connection. + +@item +If no checksum-related option is specified, then checksums will be +validated if they are present, but not required. This is compatible with +Kerberos V4 and Kerberos V5 clients as early as Kerberos V5, Beta5. + +@item +If the @samp{-i} option is provided, then checksums are ignored, even if +present. This option is required to maintain compatibility with clients +older than Kerberos V5 Beta5. Site should upgrade to newer clients so +this option is not required. + +@end enumerate + +@node BSD Utility Configuration Example, , Checksums, BSD Utilities +@subsubsection BSD Utility Configuration Example + + This section includes sample entries for @file{/etc/inetd.conf}. +Sample configuration are presented for three systems. Note that while +the examples stretch over multiple lines, an entry for a single service +should be placed on only one line in @file{inetd.conf}. Also, not all +systems have all of the columns shown in the example. @xref{Installing +the Sample Application}, for details on adding services to +@file{inetd.conf}. + + The first system enables all security features. Only Kerberos +V5 encrypted connections are enabled, and checksums are required. +@example +eklogin stream tcp nowait root + [K_SERVER]/klogind klogind -5 -e -c +kshell stream tcp nowait root + [K_SERVER]/kshd kshd -5 -e -c +@end example + + + The second system enables encrypted services for both Kerberos +V5 and Kerberos V4. Checksums are not required, but since no V5 clients +earlier than Beta5 are used, they are not ignored. + +@example +eklogin stream tcp nowait root + [K_SERVER]/klogind klogind -5 -4 -e +kshell stream tcp nowait root + [K_SERVER]/kshd kshd -5 -4 -e +@end example + + + The final example has both encrypted and unencrypted services +enabled for both Kerberos V5 and Kerberos V4. Checksums are disabled to +preserve compatability with older V5 clients. + +@example +eklogin stream tcp nowait root + [K_SERVER]/klogind klogind -5 -4 -i -e +klogin stream tcp nowait root + [K_SERVER]/klogind klogind -5 -4 -i +kshell stream tcp nowait root + [K_SERVER]/kshd kshd -5 -4 -i +@end example + +@node Telnet and FTP, , BSD Utilities, Installing Kerberos Applications +@subsection Telnet and FTP + + The following are example entries for @file{inetd.conf} for the +@samp{telnetd} and @samp{ftpd} servers. @xref{Installing the Sample +Application}, for details on adding services to @file{inetd.conf}. Note +that unlike other @file{inetd.conf} examples in this document, these +line should replace existing lines for password-based services of the +same name. + + The first example only allows encrypted or authenticated connections. + +@example +telnet stream tcp nowait root + [K_SERVER]/telnetd telnetd -a user +ftp stream tcp nowait root + [K_server]/ftpd ftpd -a +@end example + + The second example also allows password-based connections to be +made. + +@example +telnet stream tcp nowait root + [K_SERVER]/telnetd telnetd +ftp stream tcp nowait root + [K_server]/ftpd ftpd +@end example + +@node Common Kerberos Service Names, , Installing Kerberos Applications, Installation +@section Common Kerberos Service Names + +The following service names are used by Kerberos client/server +applications. + +@table @code + +@item host +Used by @samp{telnet}, @samp{rlogin}, @samp{rsh}, @samp{rcp}, @samp{ftp} +and other services which generally give login access to the host. + +@item pop +Used by the Post Office Protocol. + +@item sample +Used by the Kerberos sample applications. + +@end table + +These service names are used as the first component of the server's +principal name, with the second component being the server's fully +qualified domain name, in lower case. + +@node Troubleshooting, , Installation, Top +@chapter Troubleshooting + +@b{To be written.} + +@contents +@bye diff --git a/mechglue/doc/install.texinfo b/mechglue/doc/install.texinfo new file mode 100644 index 000000000..e04e0a45a --- /dev/null +++ b/mechglue/doc/install.texinfo @@ -0,0 +1,1445 @@ +\input texinfo-suppl.tex % contains @doubleleftarrow{} definition + % this line must come *before* \input texinfo +\input texinfo @c -*-texinfo-*- +@c %**start of header +@c guide +@setfilename krb5-install.info +@settitle Kerberos V5 Installation Guide +@setchapternewpage odd @c chapter begins on next odd page +@c @setchapternewpage on @c chapter begins on next page +@c @smallbook @c Format for 7" X 9.25" paper +@c %**end of header + +@paragraphindent 0 +@iftex +@parskip 6pt plus 6pt +@end iftex + +@include definitions.texinfo +@set EDITION 1.1 + +@finalout @c don't print black warning boxes + +@titlepage +@title @value{PRODUCT} Installation Guide +@subtitle Release: @value{RELEASE} +@subtitle Document Edition: @value{EDITION} +@subtitle Last updated: @value{UPDATED} +@author @value{COMPANY} + +@page +@vskip 0pt plus 1filll + +@end titlepage + +@node Top, Copyright, (dir), (dir) +@comment node-name, next, previous, up + +@ifinfo +This file documents how to install the @value{RELEASE} release of +@value{PRODUCT}. + +@end ifinfo + +@c The master menu is updated using emacs19's M-x texinfo-all-menus-update +@c function. Don't forget to run M-x texinfo-every-node-update after +@c you add a new section or subsection, or after you've rearranged the +@c order of sections or subsections. Also, don't forget to add an @node +@c comand before each @section or @subsection! All you need to enter +@c is: +@c +@c @node New Section Name + +@c @section New Section Name +@c +@c M-x texinfo-every-node-update will take care of calculating the +@c node's forward and back pointers. +@c +@c --------------------------------------------------------------------- + +@menu +* Copyright:: +* Introduction:: +* Realm Configuration Decisions:: +* Building Kerberos V5:: +* Installing Kerberos V5:: +* Upgrading Existing Kerberos V5 Installations:: +* Bug Reports for Kerberos V5:: +@end menu + +@node Copyright, Introduction, Top, Top +@unnumbered Copyright +@include copyright.texinfo + +@node Introduction, Realm Configuration Decisions, Copyright, Top +@chapter Introduction + +@menu +* What is Kerberos and How Does it Work?:: +* Why Should I use Kerberos?:: +* Please Read the Documentation:: +* Overview of This Guide:: +@end menu + +@node What is Kerberos and How Does it Work?, Why Should I use Kerberos?, Introduction, Introduction +@section What is Kerberos and How Does it Work? + +@value{PRODUCT} is based on the Kerberos authentication system developed +at MIT. Under Kerberos, a client (generally either a user or a service) +sends a request for a ticket to the Key Distribution Center (KDC). The +KDC creates a @dfn{ticket-granting ticket} (TGT) for the client, +encrypts it using the client's password as the key, and sends the +encrypted TGT back to the client. The client then attempts to decrypt +the TGT, using its password. If the client successfully decrypts the +TGT (@i{i.e.}, if the client gave the correct password), it keeps the +decrypted TGT, which indicates proof of the client's identity. + +The TGT, which expires at a specified time, permits the client to obtain +additional tickets, which give permission for specific services. The +requesting and granting of these additional tickets is user-transparent. + +@node Why Should I use Kerberos?, Please Read the Documentation, What is Kerberos and How Does it Work?, Introduction +@section Why Should I use Kerberos? + +Since Kerberos negotiates authenticated, and optionally encrypted, +communications between two points anywhere on the Internet, it provides +a layer of security that is not dependent on which side of a firewall +either client is on. Since studies have shown that half of the computer +security breaches in industry happen from @i{inside} firewalls, +@value{PRODUCT} from @value{COMPANY} will play a vital role in the +security of your network. + +@node Please Read the Documentation, Overview of This Guide, Why Should I use Kerberos?, Introduction +@section Please Read the Documentation + +As with any software package that uses a centrallized database, the +installation procedure is somewhat involved, and requires forethought +and planning. @value{COMPANY} has attempted to make this +@value{PRODUCT} Installation Guide as concise as possible, rather than +making it an exhaustive description of the details of Kerberos. +@ifset CYGNUS +Consequently, everything in this guide appears because @value{COMPANY} +believes that it is important. Please read and follow these +instructions carefully, and if there is anything you do not understand +or are not sure of, please don't hesitate to call us. +@end ifset +@ifset MIT +Consequently, everything in this guide appears because @value{COMPANY} +believes that it is important. Please read and follow these +instructions carefully. +@end ifset + +@include document-list.texinfo + +@node Overview of This Guide, , Please Read the Documentation, Introduction +@section Overview of This Guide + +@noindent +The next chapter describes the decisions you need to make before +installing @value{PRODUCT}. + +@noindent +Chapter three provided instructions for building the Kerberos sources. + +@noindent +Chapter four describes installation procedures for each class of +Kerberos machines: + +@enumerate +@item +Key Distribution Centers (KDCs). + +@enumerate A +@item +The Master KDC. + +@item +Slave KDCs. +@end enumerate + +@item +UNIX client machines + +@item +UNIX application server machines +@end enumerate + +@noindent +Note that a machine can be both a client machine and an application +server. + +@noindent +Chapter five describes procedure for updating previous installations of +@value{PRODUCT}. + +@noindent +Chapter six describes our problem reporting system. + +@node Realm Configuration Decisions, Building Kerberos V5, Introduction, Top +@chapter Realm Configuration Decisions + +Before installing @value{PRODUCT}, it is necessary to consider the +following issues: + +@itemize @bullet +@item +The name of your Kerberos realm (or the name of each realm, if you need +more than one). + +@item +How you will map your hostnames onto Kerberos realms. + +@item +Which ports your KDC and and kadmin (database access) services will use. + +@item +How many slave KDCs you need and where they should be located. + +@item +The hostnames of your master and slave KDCs. + +@item +How frequently you will propagate the database from the master KDC to +the slave KDCs. + +@item +Whether you need backward compatibility with Kerberos V4. +@end itemize + +@menu +* Kerberos Realms:: +* Mapping Hostnames onto Kerberos Realms:: +* Ports for the KDC and Admin Services:: +* Slave KDCs:: +* Hostnames for the Master and Slave KDCs:: +* Database Propagation:: +@end menu + +@node Kerberos Realms, Mapping Hostnames onto Kerberos Realms, Realm Configuration Decisions, Realm Configuration Decisions +@section Kerberos Realms + +Although your Kerberos realm can be any ASCII string, convention is to +make it the same as your domain name, in upper-case letters. For +example, hosts in the domain @value{SECONDDOMAIN} would be in the +Kerberos realm @value{SECONDREALM}. + +If you need multiple Kerberos realms, @value{COMPANY} recommends that +you use descriptive names which end with your domain name, such as +BOSTON.@value{SECONDREALM} and HOUSTON.@value{SECONDREALM}. + +@node Mapping Hostnames onto Kerberos Realms, Ports for the KDC and Admin Services, Kerberos Realms, Realm Configuration Decisions +@section Mapping Hostnames onto Kerberos Realms + +@include dnstxt.texinfo + +@node Ports for the KDC and Admin Services, Slave KDCs, Mapping Hostnames onto Kerberos Realms, Realm Configuration Decisions +@section Ports for the KDC and Admin Services + +The default ports used by Kerberos are port @value{DefaultPort} for the +KDC@footnote{Kerberos V4 used port @value{DefaultSecondPort}. If +necessary, you can run on both ports for backward compatibility.} and +port @value{DefaultKadmindPort} for the admin server. You can, however, +choose to run on other ports, as long as they are specified in each +host's @code{/etc/services} and @code{krb5.conf} files, and the +@code{kdc.conf} file on each KDC. For a more thorough treatment of +port numbers used by the @value{PRODUCT} programs, refer to the +``Configuring Your Firewall to Work With @value{PRODUCT}'' section of +the @cite{@value{PRODUCT} System Administrator's Guide}. + +@node Slave KDCs, Hostnames for the Master and Slave KDCs, Ports for the KDC and Admin Services, Realm Configuration Decisions +@section Slave KDCs + +Slave KDCs provide an additional source of Kerberos ticket-granting +services in the event of inaccessibility of the master KDC. The number +of slave KDCs you need and the decision of where to place them, both +physically and logically, depends on the specifics of your network. + +All of the Kerberos authentication on your network requires that each +client be able to contact a KDC. Therefore, you need to anticipate any +likely reason a KDC might be unavailable and have a slave KDC to take up +the slack. + +Some considerations include: + +@itemize @bullet +@item +Have at least one slave KDC as a backup, for when the master KDC is +down, is being upgraded, or is otherwise unavailable. + +@item +If your network is split such that a network outage is likely to cause a +network partition (some segment or segments of the network to become cut +off or isolated from other segments), have a slave KDC accessible to +each segment. + +@item +If possible, have at least one slave KDC in a different building from +the master, in case of power outages, fires, or other localized +disasters. +@end itemize + + + +@node Hostnames for the Master and Slave KDCs, Database Propagation, Slave KDCs, Realm Configuration Decisions +@section Hostnames for the Master and Slave KDCs + +@include dnssrv.texinfo + +@node Database Propagation, , Hostnames for the Master and Slave KDCs, Realm Configuration Decisions +@section Database Propagation + +The Kerberos database resides on the master KDC, and must be propagated +regularly (usually by a cron job) to the slave KDCs. In deciding how +frequently the propagation should happen, you will need to balance the +amount of time the propagation takes against the maximum reasonable +amount of time a user should have to wait for a password change to take +effect. + +If the propagation time is longer than this maximum reasonable time +(@i{e.g.,} you have a particularly large database, you have a lot of +slaves, or you experience frequent network delays), you may wish to +cut down on your propagation delay by performing the propagation in +parallel. To do this, have the master KDC propagate the database to one +set of slaves, and then have each of these slaves propagate the database +to additional slaves. + +@node Building Kerberos V5, Installing Kerberos V5, Realm Configuration Decisions, Top +@chapter Building @value{PRODUCT} + +@include build.texinfo + +@node Installing Kerberos V5, Upgrading Existing Kerberos V5 Installations, Building Kerberos V5, Top +@chapter Installing @value{PRODUCT} + +The sections of this chapter describe procedures for installing +@value{PRODUCT} on: + +@enumerate +@item +The KDCs + +@item +UNIX client machines + +@item +UNIX Application Servers +@end enumerate + +@menu +* Installing KDCs:: +* Installing and Configuring UNIX Client Machines:: +* UNIX Application Servers:: +@end menu + +@node Installing KDCs, Installing and Configuring UNIX Client Machines, Installing Kerberos V5, Installing Kerberos V5 +@section Installing KDCs + +The Key Distribution Centers (KDCs) issue Kerberos tickets. Each KDC +contains a copy of the Kerberos database. The master KDC contains the +master copy of the database, which it propagates to the slave KDCs at +regular intervals. All database changes (such as password changes) are +made on the master KDC. + +Slave KDCs provide Kerberos ticket-granting services, but not database +administration. This allows clients to continue to obtain tickets when +the master KDC is unavailable. + +@value{COMPANY} recommends that you install all of your KDCs to be able +to function as either the master or one of the slaves. This will enable +you to easily switch your master KDC with one of the slaves if +necessary. (@xref{Switching Master and Slave KDCs}.) This installation +procedure is based on that recommendation. + +@menu +* Install the Master KDC:: +* Install the Slave KDCs:: +* Back on the Master KDC:: +* Finish Installing the Slave KDCs:: +* Add Kerberos Principals to the Database:: +* Limit Access to the KDCs:: +* Switching Master and Slave KDCs:: +@end menu + +@node Install the Master KDC, Install the Slave KDCs, Installing KDCs, Installing KDCs +@subsection Install the Master KDC + +This installation procedure will require you to go back and forth a +couple of times between the master KDC and each of the slave KDCs. The +first few steps must be done on the master KDC. + +@menu +* Edit the Configuration Files:: +* krb5.conf:: +* kdc.conf:: +* Create the Database:: +* Add Administrators to the Acl File:: +* Add Administrators to the Kerberos Database:: +* Create a kadmind Keytab (optional):: +* Start the Kerberos Daemons:: +@end menu + +@node Edit the Configuration Files, krb5.conf, Install the Master KDC, Install the Master KDC +@subsubsection Edit the Configuration Files + +Modify the configuration files, @code{/etc/krb5.conf} and +@code{@value{ROOTDIR}/var/krb5kdc/kdc.conf} to reflect the correct +information (such as the hostnames and realm name) for your realm. +@value{COMPANY} recommends that you keep @code{krb5.conf} in @code{/etc}. + +Most of the tags in the configuration have default values that will +work well for most sites. There are some tags in the @code{krb5.conf} +file whose values must be specified, and this section will explain +those as well as give an overview of all of the sections in both +configuration files. For more information on changing defaults with +the configuration files, see the @value{PRODUCT} System Administrator's +Guide sections on configuration files. + +@node krb5.conf, kdc.conf, Edit the Configuration Files, Install the Master KDC +@subsubsection krb5.conf + +@include krb5conf.texinfo + +If you are not using DNS TXT records, you must specify the +@code{default_realm} in the @code{libdefaults} section. If you are not +using DNS SRV records, you must include the @code{kdc} tag for each +realm in the @code{realms} section. To communicate with the kadmin +server in each realm, the @code{admin_server} tag must be set in the +@code{realms} section. If your domain name and realm name are not the +same, you must provide a translation in @code{domain_realm}. It is +also higly recommeneded that you create a @code{[logging]} stanza if +the computer will be functioning as a KDC so that the KDC and kadmind +will generate logging output. + +An example @code{krb5.conf} file: + +@smallexample +@group +[libdefaults] + default_realm = @value{PRIMARYREALM} + +[realms] + @value{PRIMARYREALM} = @{ + kdc = @value{KDCSERVER}.@value{PRIMARYDOMAIN} + kdc = @value{KDCSLAVE1}.@value{PRIMARYDOMAIN} + kdc = @value{KDCSLAVE2}.@value{PRIMARYDOMAIN} + admin_server = @value{KDCSERVER}.@value{PRIMARYDOMAIN} + @{ + +[logging] + kdc = FILE:/var/log/krb5kdc.log + admin_server = FILE:/var/log/kadmin.log + default = FILE:/var/log/krb5lib.log +@end group +@end smallexample + +@node kdc.conf, Create the Database, krb5.conf, Install the Master KDC +@subsubsection kdc.conf + +@include kdcconf.texinfo + +@node Create the Database, Add Administrators to the Acl File, kdc.conf, Install the Master KDC +@subsubsection Create the Database + +You will use the @code{kdb5_util} command @emph{on the Master KDC} to +create the Kerberos database and the optional stash file. The +@dfn{stash file} is a local copy of the master key that resides in +encrypted form on the KDC's local disk. The stash file is used to +authenticate the KDC to itself automatically before starting the +@code{kadmind} and @code{krb5kdc} daemons (@i{e.g.,} as part of the +machine's boot sequence). The stash file, like the keytab file +(see @xref{The Keytab File}, for more information) is a potential +point-of-entry for a break-in, +and if compromised, would allow unrestricted access to the Kerberos +database. If you choose to install a stash file, it should be readable +only by root, and should exist only on the KDC's local disk. The file +should not be part of any backup of the machine, unless access to the +backup data is secured as tightly as access to the master password +itself. + +Note that @code{kdb5_util} will prompt you for the master key for the +Kerberos database. This key can be any string. A good key is one you +can remember, but that no one else can guess. Examples of bad keys are +words that can be found in a dictionary, any common or popular name, +especially a famous person (or cartoon character), your username in any +form (@i{e.g.}, forward, backward, repeated twice, @i{etc.}), and any of +the sample keys that appear in this manual. One example of a key which +might be good if it did not appear in this manual is ``MITiys4K5!'', +which represents the sentence ``MIT is your source for Kerberos 5!'' +(It's the first letter of each word, substituting the numeral ``4'' for +the word ``for'', and includes the punctuation mark at the end.) + +The following is an example of how to create a Kerberos database and +stash file on the master KDC, using the @code{kdb5_util} command. (The +line that begins with @result{} is a continuation of the previous line.) +Replace @i{@value{PRIMARYREALM}} with the name of your Kerberos realm. + +@smallexample +@group +@b{shell%} @value{ROOTDIR}/sbin/kdb5_util create -r @value{PRIMARYREALM} -s +@b{Initializing database '@value{ROOTDIR}/var/krb5kdc/principal' for +@result{} realm '@value{PRIMARYREALM}', +master key name 'K/M@@@value{PRIMARYREALM}' +You will be prompted for the database Master Password. +It is important that you NOT FORGET this password.} +@iftex +@b{Enter KDC database master key:} @i{@doubleleftarrow{} Type the master password.} +@b{Re-enter KDC database master key to verify:} @i{@doubleleftarrow{} Type it again.} +@end iftex +@ifinfo +@b{Enter KDC database master key:} @i{<= Type the master password.} +@b{Re-enter KDC database master key to verify:} @i{<= Type it again.} +@end ifinfo +@ifhtml +@b{Enter KDC database master key:} @i{<= Type the master password.} +@b{Re-enter KDC database master key to verify:} @i{<= Type it again.} +@end ifhtml +@b{shell%} +@end group +@end smallexample + +This will create five files in the directory specified in your +@code{kdc.conf} file: two Kerberos database files, @code{principal.db}, +and @code{principal.ok}; the Kerberos administrative database file, +@code{principal.kadm5}; the administrative database lock file, +@code{principal.kadm5.lock}; and the stash file, @code{.k5stash}. (The +default directory is @code{@value{ROOTDIR}/var/krb5kdc}.) If you do not +want a stash file, run the above command without the @code{-s} option. + +@node Add Administrators to the Acl File, Add Administrators to the Kerberos Database, Create the Database, Install the Master KDC +@subsubsection Add Administrators to the Acl File + +Next, you need create an Access Control List (acl) file, and put the +Kerberos principal of at least one of the administrators into it. The +filename should match the value you have set for ``acl_file'' in your +@code{kdc.conf} file. The default file name is +@samp{@value{DefaultAclFile}}. + +@include kadm5acl.texinfo + +@node Add Administrators to the Kerberos Database, Create a kadmind Keytab (optional), Add Administrators to the Acl File, Install the Master KDC +@subsubsection Add Administrators to the Kerberos Database + +Next you need to add administrative principals to the Kerberos database. +(You must add at least one now.) To do this, use @code{kadmin.local} +@emph{on the master KDC}. The administrative principals you create +should be the ones you added to the ACL file. (See @xref{Add +Administrators to the Acl File}.) In the following example, the +administration principal @code{admin/admin} is created: + +@smallexample +@group +@b{shell%} @value{ROOTDIR}/sbin/kadmin.local +@b{kadmin.local:} addprinc admin/admin@@@value{PRIMARYREALM} +@b{NOTICE: no policy specified for "admin/admin@@@value{PRIMARYREALM}"; +assigning "default".} +@iftex +@b{Enter password for principal admin/admin@@@value{PRIMARYREALM}:} @i{@doubleleftarrow{} Enter a password.} +Re-enter password for principal admin/admin@@@value{PRIMARYREALM}: @i{@doubleleftarrow{} Type it again.} +@end iftex +@ifinfo +@b{Enter password for principal admin/admin@@@value{PRIMARYREALM}:} @i{<= Enter a password.} +Re-enter password for principal admin/admin@@@value{PRIMARYREALM}: @i{<= Type it again.} +@end ifinfo +@ifhtml +@b{Enter password for principal admin/admin@@@value{PRIMARYREALM}:} @i{<= Enter a password.} +Re-enter password for principal admin/admin@@@value{PRIMARYREALM}: @i{<= Type it again.} +@end ifhtml +@b{Principal "admin/admin@@@value{PRIMARYREALM}" created. +kadmin.local:} +@end group +@end smallexample + + + +@node Create a kadmind Keytab (optional), Start the Kerberos Daemons, Add Administrators to the Kerberos Database, Install the Master KDC +@subsubsection Create a kadmind Keytab (optional) + +The kadmind keytab is the key that the legacy admininstration daemons +@code{kadmind4} and @code{v5passwdd} will use to decrypt +administrators' or clients' Kerberos tickets to determine whether or +not they should have access to the database. You need to create the +kadmin keytab with entries for the principals @code{kadmin/admin} and +@code{kadmin/changepw}. (These principals are placed in the Kerberos +database automatically when you create it.) To create the kadmin +keytab, run @code{kadmin.local} and use the @code{ktadd} command, as +in the following example. (The line beginning with @result{} is a +continuation of the previous line.): + +@smallexample +@group +@b{shell%} @value{ROOTDIR}/sbin/kadmin.local +@b{kadmin.local:} ktadd -k @value{ROOTDIR}/var/krb5kdc/kadm5.keytab +@result{} kadmin/admin kadmin/changepw +@b{ Entry for principal kadmin/admin with kvno 5, encryption + type Triple DES cbc mode with HMAC/sha1 added to keytab + WRFILE:/usr/local/var/krb5kdc/kadm5.keytab. +Entry for principal kadmin/admin with kvno 5, encryption type DES cbc mode + with CRC-32 added to keytab + WRFILE:/usr/local/var/krb5kdc/kadm5.keytab. +Entry for principal kadmin/changepw with kvno 5, encryption + type Triple DES cbc mode with HMAC/sha1 added to keytab + WRFILE:/usr/local/var/krb5kdc/kadm5.keytab. +Entry for principal kadmin/changepw with kvno 5, + encryption type DES cbc mode with CRC-32 added to keytab + WRFILE:/usr/local/var/krb5kdc/kadm5.keytab. +kadmin.local:} quit +@b{shell%} +@end group +@end smallexample + +@noindent +As specified in the @samp{-k} argument, @code{ktadd} will save the +extracted keytab as @* @code{@value{ROOTDIR}/var/krb5kdc/kadm5.keytab}. +The filename you use must be the one specified in your @code{kdc.conf} +file. + +@need 2000 +@node Start the Kerberos Daemons, , Create a kadmind Keytab (optional), Install the Master KDC +@subsubsection Start the Kerberos Daemons on the Master KDC + +At this point, you are ready to start the Kerberos daemons on the Master +KDC. To do so, type: + +@smallexample +@b{shell%} @value{ROOTDIR}/sbin/krb5kdc +@b{shell%} @value{ROOTDIR}/sbin/kadmind +@end smallexample + +@noindent +Each daemon will fork and run in the background. Assuming you want +these daemons to start up automatically at boot time, you can add them +to the KDC's @code{/etc/rc} or @code{/etc/inittab} file. You need to +have a stash file in order to do this. + +You can verify that they started properly by checking for their startup +messages in the logging locations you defined in @code{/etc/krb5.conf}. +(@xref{Edit the Configuration Files}.) For example: + +@smallexample +@b{shell%} tail /var/log/krb5kdc.log +Dec 02 12:35:47 beeblebrox krb5kdc[3187](info): commencing operation +@b{shell%} tail /var/log/kadmin.log +Dec 02 12:35:52 beeblebrox kadmind[3189](info): starting +@end smallexample + +Any errors the daemons encounter while starting will also be listed in +the logging output. + + +@node Install the Slave KDCs, Back on the Master KDC, Install the Master KDC, Installing KDCs +@subsection Install the Slave KDCs + +You are now ready to start configuring the slave KDCs. Assuming you are +setting the KDCs up so that you can easily switch the master KDC with +one of the slaves, you should perform each of these steps on the master +KDC as well as the slave KDCs, unless these instructions specify +otherwise. + + +@menu +* Create Host Keys for the Slave KDCs:: +* Extract Host Keytabs for the KDCs:: +* Set Up the Slave KDCs for Database Propagation:: +@end menu + +@node Create Host Keys for the Slave KDCs, Extract Host Keytabs for the KDCs, Install the Slave KDCs, Install the Slave KDCs +@subsubsection Create Host Keys for the Slave KDCs + +Each KDC needs a host principal in the Kerberos database. You can enter +these from any host, once the @code{kadmind} daemon is running. For +example, if your master KDC were called +@value{KDCSERVER}.@value{PRIMARYDOMAIN}, and you had two KDC slaves +named @value{KDCSLAVE1}.@value{PRIMARYDOMAIN} and +@value{KDCSLAVE2}.@value{PRIMARYDOMAIN}, you would type the following: + +@smallexample +@group +@b{shell%} @value{ROOTDIR}/sbin/kadmin +@b{kadmin:} addprinc -randkey host/@value{KDCSERVER}.@value{PRIMARYDOMAIN} +@b{NOTICE: no policy specified for "host/@value{KDCSERVER}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}"; +assigning "default" +Principal "host/@value{KDCSERVER}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}" created. +kadmin:} addprinc -randkey host/@value{KDCSLAVE1}.@value{PRIMARYDOMAIN} +@b{NOTICE: no policy specified for "host/@value{KDCSLAVE1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}"; +assigning "default" +Principal "host/@value{KDCSLAVE1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}" created.} +@b{kadmin:} addprinc -randkey host/@value{KDCSLAVE2}.@value{PRIMARYDOMAIN} +@b{NOTICE: no policy specified for "host/@value{KDCSLAVE2}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}"; +assigning "default" +Principal "host/@value{KDCSLAVE2}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}" created. +kadmin:} +@end group +@end smallexample + +@noindent +It is not actually necessary to have the master KDC server in the +Kerberos database, but it can be handy if: + +@itemize @bullet +@item +anyone will be logging into the machine as something other than root + +@item +you want to be able to swap the master KDC with one of the slaves if +necessary. +@end itemize + +@node Extract Host Keytabs for the KDCs, Set Up the Slave KDCs for Database Propagation, Create Host Keys for the Slave KDCs, Install the Slave KDCs +@subsubsection Extract Host Keytabs for the KDCs + +Each KDC (including the master) needs a keytab to decrypt tickets. +Ideally, you should extract each keytab locally on its own KDC. If this +is not feasible, you should use an encrypted session to send them across +the network. To extract a keytab on a KDC called +@value{KDCSERVER}.@value{PRIMARYDOMAIN}, you would execute the following +command: + +@smallexample +@group +@b{kadmin:} ktadd host/@value{KDCSERVER}.@value{PRIMARYDOMAIN} +@b{kadmin: Entry for principal host/@value{KDCSERVER}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} with + kvno 1, encryption type DES-CBC-CRC added to keytab + WRFILE:/etc/krb5.keytab. +kadmin:} +@end group +@end smallexample + +@noindent +Note that the principal must exist in the Kerberos database in order to +extract the keytab. + +@node Set Up the Slave KDCs for Database Propagation, , Extract Host Keytabs for the KDCs, Install the Slave KDCs +@subsubsection Set Up the Slave KDCs for Database Propagation + +The database is propagated from the master KDC to the slave KDCs via the +@code{kpropd} daemon. To set up propagation, create a file on each KDC, +named @code{@value{ROOTDIR}/var/krb5kdc/kpropd.acl}, containing the +principals for each of the KDCs. +@need 1200 +For example, if the master KDC were +@code{@value{KDCSERVER}.@value{PRIMARYDOMAIN}}, the slave KDCs were +@code{@value{KDCSLAVE1}.@value{PRIMARYDOMAIN}} and +@code{@value{KDCSLAVE2}.@value{PRIMARYDOMAIN}}, and the realm were +@code{@value{PRIMARYREALM}}, then the file's contents would be: + +@smallexample +@group +host/@value{KDCSERVER}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} +host/@value{KDCSLAVE1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} +host/@value{KDCSLAVE2}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} +@end group +@end smallexample + +@need 1000 +Then, add the following lines to @code{/etc/inetd.conf} file on each KDC +(the line beginnng with @result{} is a continuation of the previous +line): + +@smallexample +@group +krb5_prop stream tcp nowait root @value{ROOTDIR}/sbin/kpropd kpropd +eklogin stream tcp nowait root @value{ROOTDIR}/sbin/klogind +@result{} klogind -k -c -e +@end group +@end smallexample + +@noindent +The first line sets up the @code{kpropd} database propagation daemon. +The second line sets up the @code{eklogin} daemon, allowing +Kerberos-authenticated, encrypted rlogin to the KDC. + +You also need to add the following lines to @code{/etc/services} on each +KDC: + +@smallexample +@group +kerberos 88/udp kdc # Kerberos authentication (udp) +kerberos 88/tcp kdc # Kerberos authentication (tcp) +krb5_prop 754/tcp # Kerberos slave propagation +kerberos-adm 749/tcp # Kerberos 5 admin/changepw (tcp) +kerberos-adm 749/udp # Kerberos 5 admin/changepw (udp) +eklogin 2105/tcp # Kerberos encrypted rlogin +@end group +@end smallexample + +@node Back on the Master KDC, Finish Installing the Slave KDCs, Install the Slave KDCs, Installing KDCs +@subsection Back on the Master KDC + +Now that the slave KDCs are able to accept database propagation, you'll +need to propagate the database to each of them. + +@menu +* Propagate the Database to Each Slave KDC:: +@end menu + +@node Propagate the Database to Each Slave KDC, , Back on the Master KDC, Back on the Master KDC +@subsubsection Propagate the Database to Each Slave KDC + +First, create a dump of the database on the master KDC, as follows: + +@smallexample +@group +@b{shell%} @value{ROOTDIR}/sbin/kdb5_util dump @value{ROOTDIR}/var/krb5kdc/slave_datatrans +@b{shell%} +@end group +@end smallexample + +Next, you need to manually propagate the database to each slave KDC, as +in the following example. (The lines beginning with @result{} are +continuations of the previous line.): + +@smallexample +@group +@value{ROOTDIR}/sbin/kprop -f @value{ROOTDIR}/var/krb5kdc/slave_datatrans +@result{} @value{KDCSLAVE1}.@value{PRIMARYDOMAIN} +@value{ROOTDIR}/sbin/kprop -f @value{ROOTDIR}/var/krb5kdc/slave_datatrans +@result{} @value{KDCSLAVE2}.@value{PRIMARYDOMAIN} +@end group +@end smallexample + +You will need a script to dump and propagate the database. The +following is an example of a bourne shell script that will do this. +(Note that the line that begins with @result{} is a continuation of the +previous line. Remember that you need to replace @value{ROOTDIR} with +the name of the directory in which you installed @value{PRODUCT}.) + +@smallexample +@group +#!/bin/sh + +kdclist = "@value{KDCSLAVE1}.@value{PRIMARYDOMAIN} @value{KDCSLAVE2}.@value{PRIMARYDOMAIN}" + +@value{ROOTDIR}/sbin/kdb5_util "dump +@result{} @value{ROOTDIR}/var/krb5kdc/slave_datatrans" + +for kdc in $kdclist +do +@value{ROOTDIR}/sbin/kprop -f @value{ROOTDIR}/var/krb5kdc/slave_datatrans $kdc +done +@end group +@end smallexample + +@noindent +You will need to set up a cron job to run this script at the intervals +you decided on earlier (@xref{Database Propagation}.) + +@node Finish Installing the Slave KDCs, Add Kerberos Principals to the Database, Back on the Master KDC, Installing KDCs +@subsection Finish Installing the Slave KDCs + +Now that the slave KDCs have copies of the Kerberos database, you can +create stash files for them and start the @code{krb5kdc} daemon. + +@menu +* Create Stash Files on the Slave KDCs:: +* Start the krb5kdc Daemon on Each KDC:: +@end menu + +@node Create Stash Files on the Slave KDCs, Start the krb5kdc Daemon on Each KDC, Finish Installing the Slave KDCs, Finish Installing the Slave KDCs +@subsubsection Create Stash Files on the Slave KDCs + +Create stash files, by issuing the following commands on each slave KDC: + +@smallexample +@group +@b{shell%} kdb5_util stash +@b{kdb5_util: Cannot find/read stored master key while reading master key +kdb5_util: Warning: proceeding without master key} +@iftex +@b{Enter KDC database master key:} @i{@doubleleftarrow{} Enter the database master key.} +@end iftex +@ifinfo +@b{Enter KDC database master key:} @i{<= Enter the database master key.} +@end ifinfo +@ifhtml +@b{Enter KDC database master key:} @i{<= Enter the database master key.} +@end ifhtml +@b{shell%} +@end group +@end smallexample + +As mentioned above, the stash file is necessary for your KDCs to be able +authenticate to themselves, such as when they reboot. You could run +your KDCs without stash files, but you would then need to type in the +Kerberos database master key by hand every time you start a KDC daemon. + +@node Start the krb5kdc Daemon on Each KDC, , Create Stash Files on the Slave KDCs, Finish Installing the Slave KDCs +@subsubsection Start the krb5kdc Daemon on Each KDC + +The final step in configuing your slave KDCs is to run the KDC daemon: + +@smallexample +@group +@b{shell%} @value{ROOTDIR}/sbin/krb5kdc +@end group +@end smallexample + +As with the master KDC, you will probably want to add this command to +the KDCs' @code{/etc/rc} or @code{/etc/inittab} files, so they will +start the krb5kdc daemon automatically at boot time. + +@node Add Kerberos Principals to the Database, Limit Access to the KDCs, Finish Installing the Slave KDCs, Installing KDCs +@subsection Add Kerberos Principals to the Database + +@need 1800 +Once your KDCs are set up and running, you are ready to use +@code{kadmin} to load principals for your users, hosts, and other +services into the Kerberos database. This procedure is described fully in the +``Adding or Modifying Principals'' section of the @value{PRODUCT} System +Administrator's Guide. (@xref{Create Host Keys for the Slave KDCs}, for a +brief description.) The keytab is generated by running @code{kadmin} +and issuing the @code{ktadd} command. + +@node Limit Access to the KDCs, Switching Master and Slave KDCs, Add Kerberos Principals to the Database, Installing KDCs +@subsection Limit Access to the KDCs + +To limit the possibility that your Kerberos database could be +compromised, @value{COMPANY} recommends that each KDC be a dedicated +host, with limited access. If your KDC is also a file server, FTP +server, Web server, or even just a client machine, someone who obtained +root access through a security hole in any of those areas could gain +access to the Kerberos database. + +@need 4700 +@value{COMPANY} recommends that your KDCs use the following +@code{/etc/inetd.conf} file. (Note: each line beginning with @result{} +is a continuation of the previous line.): + +@smallexample +@group +# +# Configuration file for inetd(1M). See inetd.conf(4). +# +# To re-configure the running inetd process, edit this file, then +# send the inetd process a SIGHUP. +# +# Syntax for socket-based Internet services: +# +@result{} +# +# Syntax for TLI-based Internet services: +# +# tli +# +# Ftp and telnet are standard Internet services. +# +# This machine is a secure Kerberos Key Distribution Center (KDC). +# Services are limited. +# +# +# Time service is used for clock synchronization. +# +time stream tcp nowait root internal +time dgram udp wait root internal +# +# Limited Kerberos services +# +krb5_prop stream tcp nowait root @value{ROOTDIR}/sbin/kpropd kpropd +eklogin stream tcp nowait root @value{ROOTDIR}/sbin/klogind +@result{} klogind -5 -c -e +@end group +@end smallexample + +@node Switching Master and Slave KDCs, , Limit Access to the KDCs, Installing KDCs +@subsection Switching Master and Slave KDCs + +You may occasionally want to use one of your slave KDCs as the master. +This might happen if you are upgrading the master KDC, or if your master +KDC has a disk crash. + +Assuming you have configured all of your KDCs to be able to function as +either the master KDC or a slave KDC (as this document recommends), all +you need to do to make the changeover is: + +If the master KDC is still running, do the following on the @emph{old} +master KDC: + +@enumerate +@item +Kill the @code{kadmind} process. + +@item +Disable the cron job that propagates the database. + +@item +Run your database propagation script manually, to ensure that the slaves +all have the latest copy of the database. (@xref{Propagate the Database +to Each Slave KDC}.) If there is a need to preserve per-principal +policy information from the database, you should do a ``kdb5_util dump +-ov'' in order to preserve that information and propogate that dump file +securely by some means to the slave so that its database has the correct +state of the per-principal policy information. +@end enumerate + +On the @emph{new} master KDC: + +@enumerate +@item +Create a database keytab. (@xref{Create a kadmind Keytab (optional)}.) + +@item +Start the @code{kadmind} daemon. (@xref{Start the Kerberos Daemons}.) + +@item +Set up the cron job to propagate the database. (@xref{Propagate the +Database to Each Slave KDC}.) + +@item +Switch the CNAMEs of the old and new master KDCs. (If you don't do +this, you'll need to change the @code{krb5.conf} file on every client +machine in your Kerberos realm.) + +@end enumerate + +@node Installing and Configuring UNIX Client Machines, UNIX Application Servers, Installing KDCs, Installing Kerberos V5 +@section Installing and Configuring UNIX Client Machines + +Client machine installation is much more straightforward than +installation of the KDCs. + +@menu +* Client Programs:: +* Client Machine Configuration Files:: +@end menu + +@node Client Programs, Client Machine Configuration Files, Installing and Configuring UNIX Client Machines, Installing and Configuring UNIX Client Machines +@subsection Client Programs + +The Kerberized client programs are @code{login.krb5}, @code{rlogin}, +@code{telnet}, @code{ftp}, @code{rcp}, @code{rsh}, @code{kinit}, +@code{klist}, @code{kdestroy}, @code{kpasswd}, @code{ksu}, and +@code{krb524init}. All of these programs are in the directory +@code{@value{ROOTDIR}/bin}, except for @code{login.krb5} which is in +@code{@value{ROOTDIR}/sbin}. + +You will probably want to have your users put @code{@value{ROOTDIR}/bin} +ahead of @code{/bin} and @code{/usr/bin} in their paths, so they will by +default get the @value{PRODUCT} versions of @code{rlogin}, +@code{telnet}, @code{ftp}, @code{rcp}, and @code{rsh}. + +@value{COMPANY} recommends that you use @code{login.krb5} in place of +@code{/bin/login} to give your users a single-sign-on system. You will +need to make sure your users know to use their Kerberos passwords when +they log in. + +You will also need to educate your users to use the ticket management +programs @code{kinit}, +@c @code{krb524init}, +@code{klist}, @code{kdestroy}, and to use the Kerberos programs +@c @code{pfrom}, +@code{ksu}, and @code{kpasswd} in place of their non-Kerberos +counterparts +@c @code{from} +@code{su}, @code{passwd}, and @code{rdist}. + +@node Client Machine Configuration Files, , Client Programs, Installing and Configuring UNIX Client Machines +@subsection Client Machine Configuration Files + +Each machine running Kerberos must have a @code{/etc/krb5.conf} file. +(@xref{krb5.conf}.) + +@need 4000 +Also, for most UNIX systems, you must add the appropriate Kerberos +services to each client machine's @code{/etc/services} file. If you are +using the default configuration for @value{PRODUCT}, you should be able +to just insert the following code: + +@smallexample +@group +# +# Note --- if you are using Kerberos V4 and you either: +# +# (a) haven't converted all your master or slave KDCs to V5, or +# +# (b) are worried about inter-realm interoperability with other KDC's +# that are still using V4 +# +# you will need to switch the "kerberos" service to port 750 and create a +# "kerberos-sec" service on port 88. +# +kerberos @value{DefaultPort}/udp kdc # Kerberos V5 KDC +kerberos @value{DefaultPort}/tcp kdc # Kerberos V5 KDC +klogin @value{DefaultKloginPort}/tcp # Kerberos authenticated rlogin +kshell @value{DefaultKshellPort}/tcp cmd # and remote shell +kerberos-adm @value{DefaultKadmindPort}/tcp # Kerberos 5 admin/changepw +kerberos-adm @value{DefaultKadmindPort}/udp # Kerberos 5 admin/changepw +krb5_prop @value{DefaultKrbPropPort}/tcp # Kerberos slave propagation +@c kpop 1109/tcp # Pop with Kerberos +eklogin @value{DefaultEkloginPort}/tcp # Kerberos auth. & encrypted rlogin +krb524 @value{DefaultKrb524Port}/tcp # Kerberos 5 to 4 ticket translator +@end group +@end smallexample + +@noindent As described in the comments in the above code, if your master +KDC or any of your slave KDCs is running Kerberos V4, (or if you will be +authenticating to any Kerberos V4 KDCs in another realm) you will need +to switch the port number for @code{kerberos} to 750 and create a +@code{kerberos-sec} service (tcp and udp) on port 88, so the Kerberos +V4 KDC(s) will continue to work properly. + +@menu +* Mac OS X Configuration:: +@end menu + +@node Mac OS X Configuration, , Client Machine Configuration Files, Client Machine Configuration Files +@subsubsection Mac OS X Configuration + +To install Kerberos V5 on Mac OS X and Mac OS X Server, follow the +directions for generic Unix-based OS's, except for the +@code{/etc/services} updates described above. + +Mac OS X and Mac OS X Server use a database called NetInfo to store +the contents of files normally found in @code{/etc}. Instead of +modifying @code{/etc/services}, you should run the following commands +to add the Kerberos service entries to NetInfo: + +@smallexample +@group +$ niutil -create . /services/kerberos +$ niutil -createprop . /services/kerberos name kerberos kdc +$ niutil -createprop . /services/kerberos port 750 +$ niutil -createprop . /services/kerberos protocol tcp udp +$ niutil -create . /services/krbupdate +$ niutil -createprop . /services/krbupdate name krbupdate kreg +$ niutil -createprop . /services/krbupdate port 760 +$ niutil -createprop . /services/krbupdate protocol tcp +$ niutil -create . /services/kpasswd +$ niutil -createprop . /services/kpasswd name kpasswd kpwd +$ niutil -createprop . /services/kpasswd port 761 +$ niutil -createprop . /services/kpasswd protocol tcp +$ niutil -create . /services/klogin +$ niutil -createprop . /services/klogin port 543 +$ niutil -createprop . /services/klogin protocol tcp +$ niutil -create . /services/eklogin +$ niutil -createprop . /services/eklogin port 2105 +$ niutil -createprop . /services/eklogin protocol tcp +$ niutil -create . /services/kshell +$ niutil -createprop . /services/kshell name kshell krcmd +$ niutil -createprop . /services/kshell port 544 +$ niutil -createprop . /services/kshell protocol tcp +@end group +@end smallexample + +In addition to adding services to NetInfo, you must also modify the +resolver configuration in NetInfo so that the machine resolves its own +hostname as a FQDN (fully qualified domain name). By default, Mac OS X +and Mac OS X Server machines query NetInfo to resolve hostnames before +falling back to DNS. Because NetInfo has an unqualified name for all +the machines in the NetInfo database, the machine's own hostname will +resolve to an unqualified name. Kerberos needs a FQDN to look up keys +in the machine's keytab file. + +Fortunately, you can change the @code{lookupd} caching order to query +DNS first. Run the following NetInfo commands and reboot the machine: + +@smallexample +@group +$ niutil -create . /locations/lookupd/hosts +$ niutil -createprop . /locations/lookupd/hosts LookupOrder CacheAgent DNSAgent + NIAgent NILAgent +@end group +@end smallexample + +Once you have rebooted, you can verify that the resolver now behaves +correctly. Compile the Kerberos 5 distribution and run: + +@smallexample +@group +$ cd .../src/tests/resolve +$ ./resolve +@end group +@end smallexample + +This will tell you whether or not your machine returns FQDNs on name +lookups. If the test still fails, you can also try turning off DNS +caching. Run the following commands and reboot: + +@smallexample +@group +$ niutil -create . /locations/lookupd/hosts +$ niutil -createprop . /locations/lookupd/hosts LookupOrder DNSAgent + CacheAgent NIAgent NILAgent +@end group +@end smallexample + +The remainder of the setup of a Mac OS X client machine or application +server should be the same as for other UNIX-based systems. + +@node UNIX Application Servers, , Installing and Configuring UNIX Client Machines, Installing Kerberos V5 +@section UNIX Application Servers + +An application server is a host that provides one or more services over +the network. Application servers can be ``secure'' or ``insecure.'' A +``secure'' host is set up to require authentication from every client +connecting to it. An ``insecure'' host will still provide Kerberos +authentication, but will also allow unauthenticated clients to connect. + +If you have @value{PRODUCT} installed on all of your client machines, +@value{COMPANY} recommends that you make your hosts secure, to take +advantage of the security that Kerberos authentication affords. +However, if you have some clients that do not have @value{PRODUCT} +installed, you can run an insecure server, and still take advantage of +@value{PRODUCT}'s single sign-on capability. + +@menu +* Server Programs:: +* Server Configuration Files:: +* The Keytab File:: +* Some Advice about Secure Hosts:: +@end menu + +@node Server Programs, Server Configuration Files, UNIX Application Servers, UNIX Application Servers +@subsection Server Programs + +Just as @value{PRODUCT} provided its own Kerberos-enhanced versions of +client UNIX network programs, @value{PRODUCT} also provides +Kerberos-enhanced versions of server UNIX network daemons. These are +@code{ftpd}, @code{klogind}, @code{kshd}, and @code{telnetd}. +@c @code{popper}, +These programs are installed in the directory +@code{@value{ROOTDIR}/sbin}. You may want to add this directory to +root's path. + +@node Server Configuration Files, The Keytab File, Server Programs, UNIX Application Servers +@subsection Server Configuration Files + +For a @emph{secure} server, make the following changes to +@code{/etc/inetd.conf}: + +Find and comment out any lines for the services @code{ftp}, +@code{telnet}, @code{shell}, @code{login}, and @code{exec}. + +@need 1800 +Add the following lines. (Note: each line beginning with @result{} is +a continuation of the previous line.) + +@smallexample +@group +klogin stream tcp nowait root @value{ROOTDIR}/sbin/klogind +@result{} klogind -k -c +eklogin stream tcp nowait root @value{ROOTDIR}/sbin/klogind +@result{} klogind -k -c -e +kshell stream tcp nowait root @value{ROOTDIR}/sbin/kshd +@result{} kshd -k -c -A +ftp stream tcp nowait root @value{ROOTDIR}/sbin/ftpd +@result{} ftpd -a +telnet stream tcp nowait root @value{ROOTDIR}/sbin/telnetd +@result{} telnetd -a valid +@end group +@end smallexample + +For an @emph{insecure} server, make the following changes instead to +@code{/etc/inetd.conf}: + +@need 1800 +Find and comment out any lines for the services @code{ftp} and +@code{telnet}. + +Add the following lines. (Note: each line beginning with @result{} is +a continuation of the previous line.) +@smallexample +@group +klogin stream tcp nowait root @value{ROOTDIR}/sbin/klogind +@result{} klogind -k -c +eklogin stream tcp nowait root @value{ROOTDIR}/sbin/klogind +@result{} klogind -k -c -e +kshell stream tcp nowait root @value{ROOTDIR}/sbin/kshd +@result{} kshd -k -c -A +ftp stream tcp nowait root @value{ROOTDIR}/sbin/ftpd +@result{} ftpd +telnet stream tcp nowait root @value{ROOTDIR}/sbin/telnetd +@result{} telnetd -a none +@end group +@end smallexample + +@node The Keytab File, Some Advice about Secure Hosts, Server Configuration Files, UNIX Application Servers +@subsection The Keytab File + +All Kerberos server machines need a @dfn{keytab} file, called +@code{/etc/krb5.keytab}, to authenticate to the KDC. The keytab file is +an encrypted, local, on-disk copy of the host's key. The keytab file, +like the stash file (@ref{Create the Database}) is a potential +point-of-entry for a break-in, and if compromised, would allow +unrestricted access to its host. The keytab file should be readable +only by root, and should exist only on the machine's local disk. The +file should not be part of any backup of the machine, unless access to +the backup data is secured as tightly as access to the machine's root +password itself. + +In order to generate a keytab for a host, the host must have a principal +in the Kerberos database. The procedure for adding hosts to the +database is described fully in the ``Adding or Modifying Principals'' +section of the @cite{@value{PRODUCT} System Administrator's Guide}. +@xref{Create Host Keys for the Slave KDCs}. for a brief description.) +The keytab is generated by running @code{kadmin} and issuing the +@code{ktadd} command. + +@need 1100 +For example, to generate a keytab file to allow the host +trillium.@value{PRIMARYDOMAIN} to authenticate for the services +@code{host}, @code{ftp}, and @code{pop}, the administrator +@code{@value{ADMINUSER}} would issue the command (on +trillium.@value{PRIMARYDOMAIN}): + +@smallexample +@group +@b{trillium%} @value{ROOTDIR}/sbin/kadmin +@b{kadmin5:} ktadd host/trillium.@value{PRIMARYDOMAIN} ftp/trillium.@value{PRIMARYDOMAIN} +@result{} pop/trillium.@value{PRIMARYDOMAIN} +@b{kadmin: Entry for principal host/trillium.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} with +kvno 3, encryption type DES-CBC-CRC added to keytab +WRFILE:/etc/krb5.keytab. +kadmin: Entry for principal ftp/trillium.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} with +kvno 3, encryption type DES-CBC-CRC added to keytab +WRFILE:/etc/krb5.keytab. +kadmin: Entry for principal pop/trillium.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM} with +kvno 3, encryption type DES-CBC-CRC added to keytab +WRFILE:/etc/krb5.keytab. +kadmin5:} quit +@b{trillium%} +@end group +@end smallexample + +If you generate the keytab file on another host, you need to get a copy +of the keytab file onto the destination host (@code{trillium}, in the +above example) without sending it unencrypted over the network. If you +have installed the @value{PRODUCT} client programs, you can use +encrypted @code{rcp}. + +@node Some Advice about Secure Hosts, , The Keytab File, UNIX Application Servers +@subsection Some Advice about Secure Hosts + +@value{PRODUCT} can protect your host from certain types of break-ins, +but it is possible to install @value{PRODUCT} and still leave your host +vulnerable to attack. Obviously an installation guide is not the place +to try to include an exhaustive list of countermeasures for every +possible attack, but it is worth noting some of the larger holes and how +to close them. + +As stated earlier in this section, @value{COMPANY} recommends that on a +secure host, you disable the standard @code{ftp}, @code{login}, +@code{telnet}, @code{shell}, and @code{exec} services in +@code{/etc/inetd.conf}. We also recommend that secure hosts have an empty +@code{/etc/hosts.equiv} file and that there not be a @code{.rhosts} file +in @code{root}'s home directory. You can grant Kerberos-authenticated +root access to specific Kerberos principals by placing those principals +in the file @code{.k5login} in root's home directory. + +We recommend that backups of secure machines exclude the keytab file +(@code{/etc/krb5.keytab}). If this is not possible, the backups should +at least be done locally, rather than over a network, and the backup +tapes should be physically secured. + +Finally, the keytab file and any programs run by root, including the +@value{PRODUCT} binaries, should be kept on local disk. The keytab file +should be readable only by root. + +@node Upgrading Existing Kerberos V5 Installations, Bug Reports for Kerberos V5, Installing Kerberos V5, Top +@chapter Upgrading Existing @value{PRODUCT} Installations + +If you already have an existing Kerberos database that you created with +a prior release of Kerberos 5, you can upgrade it to work with the +current release with the @code{kdb5_util} command. It is only +necessary to perform this dump/undump procedure if you were running a +krb5-1.0.x KDC and are migrating to a krb5-1.1.x or newer KDC or if you +were running a krb5-1.1.x KDC and are migrating to a krb5-1.2.x or newer +KDC. The process for upgrading a Master KDC involves the following +steps: + +@enumerate + +@item Stop your current KDC and administration +server processes, if any. + +@item Dump your existing Kerberos database to an ASCII file with +@code{kdb5_util}'s ``dump'' command: + +@smallexample +@group +@b{shell%} cd @value{ROOTDIR}/var/krb5kdc +@b{shell%} kdb5_util dump old-kdb-dump +@b{shell%} kdb5_util dump -ov old-kdb-dump.ov +@b{shell%} +@end group +@end smallexample + +@item Create a new Master KDC installation (@xref{Install the Master +KDC}.). If you have a stash file for your current database, choose any +new master password but then copy your existing stash file to the +location specified by your kdc.conf; if you do not have a stash file for +your current database, you must choose the same master password. + +@item Load your old Kerberos database into the new system with +@code{kdb5_util}'s ``load'' command: + +@smallexample +@group +@b{shell%} cd @value{ROOTDIR}/var/krb5kdc +@b{shell%} kdb5_util load old-kdb-dump +@b{shell%} kdb5_util load -update old-kdb-dump.ov +@b{shell%} +@end group +@end smallexample + +@end enumerate + +The ``dump -ov'' and ``load -update'' commands are necessary in order to +preserve per-principal policy information, since the default dump format +filters out that information. If you omit those steps, the loaded +database database will lose the policy information for each principal +that has a policy. + +To update a Slave KDC, you must stop the old server processes on the +Slave KDC, install the new server binaries, reload the most recent slave +dump file, and re-start the server processes. + +@menu +* Upgrading to Triple-DES and RC4 Encryption Keys:: +@end menu + +@node Upgrading to Triple-DES and RC4 Encryption Keys, , Upgrading Existing Kerberos V5 Installations, Upgrading Existing Kerberos V5 Installations +@section Upgrading to Triple-DES Encryption Keys + +Beginning with the 1.2 release from @value{COMPANY}, Kerberos includes +a stronger encryption algorithm called ``triple DES'' -- essentially, +three applications of the basic DES encryption algorithm, greatly +increasing the resistance to a brute-force search for the key by an +attacker. This algorithm is more secure, but encryption is much +slower. + +Release 1.1 had some support for triple-DES service keys, but with +release 1.2 we have added support for user keys and session keys as +well. Release 1.0 had very little support for multiple cryptosystems, +and some of that software may not function properly in an environment +using triple-DES as well as plain DES. + +In the 1.3 release from @value{COMPANY}, Kerberos also includes the RC4 +encryption alogorithm, a stream cipher symmetric key algorithm +developed in 1987 by Ronald Rivest at RSA Data Security. Please note +that RC4 is not part of the IETF standard. + +Because of the way the MIT Kerberos database is structured, the KDC +will assume that a service supports only those encryption types for +which keys are found in the database. Thus, if a service has only a +single-DES key in the database, the KDC will not issue tickets for that +service that use triple-DES or RC4 session keys; it will instead issue +only single-DES session keys, even if other services are already +capable of using triple-DES or RC4. So if you make sure your +application server software is updated before adding a triple-DES or +RC4 key for the service, clients should be able to talk to services at +all times during the updating process. + +Normally, the listed @code{supported_enctypes} in @code{kdc.conf} are +all used when a new key is generated. You can control this with +command-line flags to @code{kadmin} and @code{kadmin.local}. You may +want to exclude triple-DES and RC4 by default until you have updated a +lot of your application servers, and then change the default to include +triple-DES and RC4. We recommend that you always include +@code{des-cbc-crc} in the default list. + +@node Bug Reports for Kerberos V5, , Upgrading Existing Kerberos V5 Installations, Top +@chapter Bug Reports for @value{PRODUCT} + +@include send-pr.texinfo + +@contents +@bye diff --git a/mechglue/doc/kadm5/adb-unit-test.tex b/mechglue/doc/kadm5/adb-unit-test.tex new file mode 100644 index 000000000..d401342df --- /dev/null +++ b/mechglue/doc/kadm5/adb-unit-test.tex @@ -0,0 +1,134 @@ +\documentstyle[times,fullpage,rcsid]{article} + +\rcs$Id$ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make _ actually generate an _, and allow line-breaking after it. +\let\underscore=\_ +\catcode`_=13 +\def_{\underscore\penalty75\relax} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand{\test}[1]{\begin{description} +\setlength{\itemsep}{0pt} +#1 +\end{description} + +} + +\newcommand{\numtest}[2]{\begin{description} +\setlength{\itemsep}{0pt} +\Number{#1} +#2 +\end{description} + +} + +\newcommand{\Number}[1]{\item[Number:] #1} +\newcommand{\Reason}[1]{\item[Reason:] #1} +%\newcommand{\Call}[1]{\item[Call:] #1} +\newcommand{\Expected}[1]{\item[Expected:] #1} +\newcommand{\Conditions}[1]{\item[Conditions:] #1} +\newcommand{\Priority}[1]{\item[Priority:] #1} +\newcommand{\Status}[1]{\item[Status:] #1} +%\newcommand{\Number}[1]{} +%\newcommand{\Reason}[1]{} +\newcommand{\Call}[1]{} +%\newcommand{\Expected}[1]{} +%\newcommand{\Conditions}[1]{} +%\newcommand{\Priority}[1]{} + +\title{OpenV*Secure Admin Database API\\ +Unit Test Description\footnote{\rcsId}} +\author{Jonathan I. Kamens} + +\begin{document} + +\maketitle + +%\tableofcontents + +\section{Introduction} + +The following is a description of a black-box unit test of the +OpenV*Secure Admin Database API (osa_adb). Each API function is +listed, followed by the tests that shoud be performed on it. + +The tests described here are based on the ``OV*Secure Admin Server +Implementation Design'' revision 1.14. + +\section{osa_adb_get_lock and osa_adb_release_lock} + +\numtest{1}{ +\Reason{A shared lock can be acquired.} +\Status{Implemented} +} + +\numtest{2}{ +\Reason{An exclusive lock can be acquired and released.} +\Status{Implemented} +} + +\numtest{3}{ +\Reason{A permanent lock can be acquired and released.} +\Status{Implemented} +} + +\numtest{4}{ +\Reason{Attempting to release a lock when none is held fails with +NOTLOCKED.} +\Status{Implemented} +} + +\numtest{5}{ +\Reason{Two processes can both acquire a shared lock.} +\Status{Implemented} +} + +\numtest{6}{ +\Reason{An attempt to acquire a shared lock while another process holds an +exclusive lock fails with CANTLOCK_DB.} +\Status{Implemented} +} + +\numtest{7}{ +\Reason{An attempt to acquire an exclusive lock while another process holds a +shared lock fails with CANTLOCK_DB.} +\Status{Implemented} +} + +\numtest{8}{ +\Reason{An attempt to open the database while a process holds a +permanent lock fails with NO_LOCKFILE.} +\Status{Implemented} +} + +\numtest{9}{ +\Reason{An attempt to acquire an exclusive lock while a process holds a +permanent lock fails with NO_LOCKFILE.} +\Status{Implemented} +} + +\numtest{10}{ +\Reason{Acquiring a permanent lock deletes the lockfile.} +\Status{Implemented} +} + +\numtest{11}{ +\Reason{Releasing a permanent lock re-creates the lockfile.} +\Status{Implemented} +} + +\numtest{12}{ +\Reason{A process can perform a get operation while another process holds a +shared lock.} +\Status{Implemented} +} + +\numtest{13}{ +\Reason{A process that is running and has opened the adb principal database +can retrieve a principal created after the open occurred.} +\Status{Implemented, but not working} +} + +\end{document} diff --git a/mechglue/doc/kadm5/api-funcspec.tex b/mechglue/doc/kadm5/api-funcspec.tex new file mode 100644 index 000000000..bf885b464 --- /dev/null +++ b/mechglue/doc/kadm5/api-funcspec.tex @@ -0,0 +1,2015 @@ +\documentstyle[12pt,fullpage,rcsid]{article} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make _ actually generate an _, and allow line-breaking after it. +\let\underscore=\_ +\catcode`_=13 +\def_{\underscore\penalty75\relax} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\rcs$Id$ + +\setlength{\parskip}{.7\baselineskip} +\setlength{\parindent}{0pt} + +\def\v#1{\verb+#1+} + +\title{Kerberos Administration System \\ + KADM5 API Functional Specifications\thanks{\rcsId}} +\author{Barry Jaspan} + +\begin{document} + +\sloppy +\maketitle + +{\setlength{\parskip}{0pt}\tableofcontents} + +\section{Introduction} + +This document describes the Admin API that can be used to maintain +principals and policies. It describes the data structures used for +each function and the interpretation of each data type field, the +semantics of each API function, and the possible return codes. + +The Admin API is intended to be used by remote clients using an RPC +interface. It is implemented by the admin server running on the +Kerberos master server. It is also possible for a program running on +the Kerberos master server to use the Admin API directly, without +going through the admin server. + +\section{Versions of the API} + +The versions of this API and a brief description of the changes for +each are: + +\begin{description} +\item[KADM5_API_VERSION_1] The initial version of this API, written by +OpenVision Technologies and donated to MIT for including in the public +release. Originally called OVSEC_KADM_API_VERSION_1. Most everything +has been renamed in one way or another, including functions, header +files, and data structures. Where possible, the old OVSEC_KADM names +have been left behind for compatibility with version 1, and +KADM5_API_VERSION_1 is compatible with OVSEC_KADM_API_VERSION_1 at +compile-, link-, and run-time. + +The OVSEC_KADM name compatibility will not be extended to new +functionality in future versions because no existing OVSEC_KADM +clients will use that functionality; new clients should be written to +the KADM5 API. + +\item[KADM5_API_VERSION_2] This version contains the initial changes +necessary to make the OpenVision administration system work with the +mid-1996 MIT version of Kerberos 5. Changes include +\begin{enumerate} +\item The kadm5_init functions now take a structure of parameters +instead of just a realm name, allowing the calling program to specify +non-default values for various configuration options. See section +\ref{sec:configparams} for details. + +\item The KADM5 API has been extended to support new features of the +Kerberos database, including multiple encryption and salt types per +principal. See section \ref{sec:keys} for details. + +\item kadm5_get_principal now allows a principal's keys to be +retrieved {\it by local clients only}. This is necessary in order for +the kadm5 API to provide the primary Kerberos database interface. + +\item The KADM5 authorization system has been completely changed. + +\item The functions kadm5_flush, kadm5_get_principals, and +kadm5_get_policies have been added. + +\item The KADM5 API now obeys a caller-allocates rather than +callee-allocates system. kadm5_get_principal and kadm5_get_policy are +affected. +\end{enumerate} +\end{description} + +\section{Policies and Password Quality} + +The Admin API Password Quality mechanism provides the following +controls. Note that two strings are defined to be ``significantly +different'' if they differ by at least one character. The compare is not +case sensitive. + +\begin{itemize} +\item A minimum length can be required; a password with +fewer than the specified number of characters will not be accepted. + +\item A minimum number of character classes can be required; a +password that does not contain at least one character from at least +the specified number of character classes will not be accepted. The +character classes are defined by islower(), isupper(), isdigit(), +ispunct(), and other. + +\item Passwords can be required to be different from +previous passwords; a password that generates the same encryption key +as any of the principal's specified previous number of passwords will +not be accepted. This comparison is performed on the encryption keys +generated from the passwords, not on the passwords themselves. + +\item A single ``forbidden password'' dictionary can be specified for all +users; a password that is not significantly different from every word +in the dictionary will not be accepted. +\end{itemize} + +\section{Data Structures} + +This section describes the data structures used by the Admin API. +They are defined in $<$kadm5/admin.h$>$. + +\subsection{Principals, kadm5_principal_ent_t} +\label{sec:principal-structure} + +A Kerberos principal entry is represented by a kadm5_principal_ent_t. +It contains a subset of the information stored in the master Kerberos +database as well as the additional information maintained by the admin +system. In the current version, the only additional information is +the principal's policy and the aux_attributes flags. + +The principal may or may not have a policy enforced on it. If the +POLICY bit (see section \ref{sec:masks}) is set in aux_attributes, the +policy field names the principal's policy. If the POLICY bit is not +set in aux_attributes, no policy is enforced on the principal and the +value of the policy field is undefined. + +\begin{figure}[htbp] +\begin{verbatim} +typedef struct _kadm5_principal_ent_t { + krb5_principal principal; + + krb5_timestamp princ_expire_time; + krb5_timestamp last_pwd_change; + krb5_timestamp pw_expiration; + krb5_deltat max_life; + krb5_principal mod_name; + krb5_timestamp mod_date; + krb5_flags attributes; + krb5_kvno kvno; + krb5_kvno mkvno; + + char * policy; + u_int32 aux_attributes; + + krb5_deltat max_renewable_life; + krb5_timestamp last_success; + krb5_timestamp last_failed; + krb5_kvno fail_auth_count; + krb5_int16 n_key_data; + krb5_int16 n_tl_data; + krb5_tl_data *tl_data; + krb5_key_data *key_data; +} kadm5_principal_ent_rec, *kadm5_principal_ent_t; +\end{verbatim} +\caption{Definition of kadm5_principal_ent_t.} +\label{fig:princ-t} +\end{figure} + +The fields of an kadm5_principal_ent_t are interpreted as +follows. + +\begin{description} +\item[principal] The name of the principal; must conform to Kerberos +naming specifications. + +\item[princ_expire_time] The expire time of the principal as a Kerberos +timestamp. No Kerberos tickets will be issued for a principal after +its expire time. + +\item[last_pwd_change] The time this principal's password was last +changed, as a Kerberos timestamp. + +\item[pw_expiration] The expire time of the user's current password, as a +Kerberos timestamp. No application service tickets will be issued for the +principal once the password expire time has passed. Note that the user can +only obtain tickets for services that have the PW_CHANGE_SERVICE bit set in +the attributes field. + +\item[max_life] The maximum lifetime of any Kerberos ticket issued to +this principal. + +\item[attributes] A bitfield of attributes for use by the KDC. The +symbols and constant values are defined below; their interpretation +appears in the libkdb functional specification. + +\begin{tabular}{clr} +{\bf Name} & {\bf Value} \\ +KRB5_KDB_DISALLOW_POSTDATED & 0x00000001 \\ +KRB5_KDB_DISALLOW_FORWARDABLE & 0x00000002 \\ +KRB5_KDB_DISALLOW_TGT_BASED & 0x00000004 \\ +KRB5_KDB_DISALLOW_RENEWABLE & 0x00000008 \\ +KRB5_KDB_DISALLOW_PROXIABLE & 0x00000010 \\ +KRB5_KDB_DISALLOW_DUP_SKEY & 0x00000020 \\ +KRB5_KDB_DISALLOW_ALL_TIX & 0x00000040 \\ +KRB5_KDB_REQUIRES_PRE_AUTH & 0x00000080 \\ +KRB5_KDB_REQUIRES_HW_AUTH & 0x00000100 \\ +KRB5_KDB_REQUIRES_PWCHANGE & 0x00000200 \\ +KRB5_KDB_DISALLOW_SVR & 0x00001000 \\ +KRB5_KDB_PWCHANGE_SERVICE & 0x00002000 \\ +KRB5_KDB_SUPPORT_DESMD5 & 0x00004000 \\ +KRB5_KDB_NEW_PRINC & 0x00008000 +\end{tabular} + +\item[mod_name] The name of the Kerberos principal that most recently +modified this principal. + +\item[mod_date] The time this principal was last modified, as a Kerberos +timestamp. + +\item[kvno] The version of the principal's current key. + +\item[mkvno] The version of the Kerberos Master Key in effect when +this principal's key was last changed. In KADM5_API_VERSION_2, this +field is always zero. + +\item[policy] If the POLICY bit is set in aux_attributes, the name +of the policy controlling this principal. + +\item[aux_attributes] A bitfield of flags for use by the +administration system. Currently, the only valid flag is POLICY, and +it indicates whether or not the principal has a policy enforced on it. + +\item[max_renewable_life] The maximum renewable lifetime of any +Kerberos ticket issued to or for this principal. This field only +exists in KADM5_API_VERSION_2. + +\item[last_success] The KDC time of the last successful AS_REQ. This +is only updated if KRBCONF_KDC_MODIFIES_KDB is defined during +compilation of the KDC. This field only exists in +KADM5_API_VERSION_2. + +\item[last_failed] The KDC time of the last failed AS_REQ. This is +only updated if KRBCONF_KDC_MODIFIES_KDB is defined during compilation +of the KDC. This field only exists in KADM5_API_VERSION_2. + +\item[fail_auth_count] The number of consecutive failed AS_REQs. When +this number reaches KRB5_MAX_FAIL_COUNT, the KRB5_KDC_DISALLOW_ALL_TIX +is set on the principal. This is only updated if +KRBCONF_KDC_MODIFIES_KDB is defined during compilation. This field +only exists in KADM5_API_VERSION_2. + +\item[n_tl_data] The number of elements in the \v{tl_data} linked +list. This field only exists in KADM5_API_VERSION_2. + +\item[n_key_data] The number of elements in the \v{key_data} +array. This field only exists in KADM5_API_VERSION_2. + +\item[tl_data] A linked list of tagged data. This list is a mechanism +by which programs can store extended information in a principal entry, +without having to modify the database API. Each element is of type +krb5_tl_data: +\begin{verbatim} +typedef struct _krb5_tl_data { + struct _krb5_tl_data* tl_data_next; + krb5_int16 tl_data_type; + krb5_int16 tl_data_length; + krb5_octet * tl_data_contents; +} krb5_tl_data; +\end{verbatim} +% +The KADM5 API only allows elements whose tl_data_type is greater than +or equal to 256. Values less than 256 are reserved for internal use +by the KADM5 or kdb system. They are filtered out of the list +returned by kadm5_get_principal, and generate an error if given to +kadm5_modify_principal. + +The libkdb library defines the tagged data types +KRB5_TL_LAST_PWD_CHANGE, KRB5_TL_MOD_PRINC, and KRB5_TL_KADM_DATA, all +with values less than 256, which store the last password modification +time, time and modifier of last principal modification, and +administration system data. All of these entries are expected by the +administration system and parsed out into fields of the +kadm5_principal_ent_rec structure; as described above, they are not +included in the tl_data list. + +Tagged data elements with types greater than 256 are handled without +interpretation by KADM5. Note that an application that calls +kadm5_modify_principal with the KADM5_TL_DATA mask bit set is +responsible for providing the {\it complete} tl_data list, which it +necessarily must obtain from kadm5_get_principal. It is {\it never} +possible for an application to construct a complete tl_data list from +scratch. + +\item[key_data] An array of the principal's keys. The keys contained +in this array are encrypted in the Kerberos master key. See section +\ref{sec:keys} for a discussion of the krb5_key_data structure. +\end{description} + +\subsection{Policies, kadm5_policy_ent_t} +\label{sec:policy-fields} + +If the POLICY bit is set in aux_attributes, the \v{policy} name field +in the kadm5_principal_ent_t structure refers to a password policy +entry defined in a \v{kadm5_policy_ent_t}. + +\begin{verbatim} +typedef struct _kadm5_policy_ent_t { + char *policy; + + u_int32 pw_min_life; + u_int32 pw_max_life; + u_int32 pw_min_length; + u_int32 pw_min_classes; + u_int32 pw_history_num; + u_int32 policy_refcnt; +} kadm5_policy_ent_rec, *kadm5_policy_ent_t; +\end{verbatim} + +The fields of an kadm5_policy_ent_t are interpreted as follows. +Note that a policy's values only apply to a principal using that +policy. + +\begin{description} +\item[policy] The name of this policy, as a NULL-terminated string. +The ASCII characters between 32 (space) and 126 (tilde), inclusive, +are legal. + +\item[pw_min_life] The minimum password lifetime, in seconds. +A principal cannot change its password before pw_min_life seconds have +passed since last_pwd_change. + +\item[pw_max_life] The default duration, in seconds, used to compute +pw_expiration when a principal's password is changed. + +\item[pw_min_length] The minimum password length, in characters. A +principal cannot set its password to anything with fewer than this +number of characters. This value must be greater than zero. + +\item[pw_min_classes] The minimum number of character classes in the +password. This value can only be 1, 2, 3, 4, or 5. A principal cannot +set its password to anything with fewer than this number of character +classes in it. + +\item[pw_history_num] The number of past passwords that are +stored for the principal; the minimum value is 1 and the maximum value +is 10. A principal cannot set its password to any of its previous +pw_history_num passwords. The first ``previous'' password is the +current password; thus, a principal with a policy can never reset its +password to its current value. + +\item[policy_refcnt] The number of principals currently using this policy. +A policy cannot be deleted unless this number is zero. +\end{description} + +\subsection{Configuration parameters} +\label{sec:configparams} + +The KADM5 API acquires configuration information from the Kerberos +configuration file (\$KRB5_CONFIG or DEFAULT_PROFILE_PATH) and from +the KDC configuration file (\$KRB5_KDC_CONFIG or DEFAULT_KDC_PROFILE). +In KADM5_API_VERSION_2, some of the configuration parameters used by +the KADM5 API can be controlled by the caller by providing a +kadm5_config_params structure to kadm5_init: +% +\begin{verbatim} +typedef struct _kadm5_config_params { + u_int32 mask; + + /* Client and server fields */ + char *realm; + char *profile; + int kadmind_port; + + /* client fields */ + char *admin_server; + + /* server fields */ + char *dbname; + char *admin_dbname; + char *admin_lockfile; + char *acl_file; + char *dict_file; + char *admin_keytab; + + /* server library (database) fields */ + int mkey_from_kbd; + char *stash_file; + char *mkey_name; + krb5_enctype enctype; + krb5_deltat max_life; + krb5_deltat max_rlife; + krb5_timestamp expiration; + krb5_flags flags; + krb5_key_salt_tuple *keysalts; + krb5_int32 num_keysalts; +} kadm5_config_params; +\end{verbatim} +% +The following list describes each of the fields of the structure, +along with the profile relation it overrides, its mask value, its +default value, and whether it is valid on the client, server, or both, +or neither. +\begin{description} +\item[mask] No variable. No mask value. A bitfield specifying which +fields of the structure contain valid information. A caller sets this +mask before calling kadm5_init_*, indicating which parameters are +specified. The mask values are defined in $<$kadm5/admin.h$>$ and are +all prefixed with KADM5_CONFIG_; the prefix is not included in the +descriptions below. + +\item[realm] No variable. REALM. Client and server. The realm to +which these parameters apply, and the realm for which additional +parameters are to be acquired, if any. If this field is not specified +in the mask, the default local realm is used. + +\item[profile] Variable: profile (server only). PROFILE. Client and +server. The Kerberos profile to use. On the client, the default is +the value of the KRB5_CONFIG environment variable, or +DEFAULT_PROFILE_PATH if that is not set. On the server, the value of +the ``profile'' variable of the KDC configuration file will be used as +the first default if it exists; otherwise, the default is the value of +the KRB5_KDC_PROFILE environment variable or DEFAULT_KDC_PROFILE. + +\item[kadmind_port] Variable: kadmind_port. KADMIND_PORT. Client and +server. The port number the kadmind server listens on. The client +uses this field to determine where to connect, and the server to +determine where to listen. The default is 749, which has been +assigned by IANA. + +\item[admin_server] Variable: admin_server. ADMIN_SERVER. Client. +The host name of the admin server to which to connect. There is no +default. If the value of this field contains a colon (:), the text +following the colon is treated as an integer and assigned to the +kadmind_port field, overriding any value of the kadmind_port variable. + +\item[dbname] Variable: dbname. DBNAME. Server. The Kerberos +database name to use; the Kerberos database stores principal +information. The default is DEFAULT_KDB_FILE. + +\item[admin_dbname] Variable: admin_database_name. ADBNAME. +Neither. If the dbname field is set, this field is set to the value +of dbname followed by ``.kadm5''. + +\item[admin_lockfile] Variable: admin_database_lockfile. +ADB_LOCKFILE. Neither. If the admin_dbname field is set, this field +is set to the value of admin_dbname followed by ``.lock''. + +\item[acl_file] Variable: acl_file. ACL_FILE. Server. The admin +server's ACL file. The default is DEFAULT_KADM5_ACL_FILE. + +\item[dict_file] Variable: admin_dict_file. DICT_FILE. Server. The +admin server's dictionary file of passwords to disallow. No default. + +\item[admin_keytab] Variable: admin_keytab. ADMIN_KEYTAB. Server. +The keytab file containing the kadmin/admin and kadmin/changepw +entries for the server to use. The default is the value of the +KRB5_KTNAME environment variable, if defined, else +DEFAULT_KADM5_KEYTAB. + +\item[mkey_from_keyboard] No variable. MKEY_FROM_KEYBOARD. Server. +If non-zero, prompt for the master password via the tty instead of +using the stash file. If this mask bit is not set, or is set and the +value is zero, the stash file is used. + +\item[stash_file] Variable: key_stash_file. STASH_FILE. Server. The +file name containing the master key stash file. No default; libkdb +will work with a NULL value. + +\item[mkey_name] Variable: master_key_name. MKEY_NAME. Server. The +name of the master principal for the realm. No default; lbkdb will +work with a NULL value. + +\item[enctype] Variable: master_key_type. ENCTYPE. Server. The +encryption type of the master principal. The default is +DEFAULT_KDC_ENCTYPE. + +\item[max_life] Variable: max_life. MAX_LIFE. Maximum lifetime for +all tickets issued to the principal. The default is 28800, which is 8 +hours. + +\item[max_rlife, expiration, flags] Variables: max_renewable_life, +default_principal_expiration, default_principal_flags. MAX_LIFE, +MAX_RLIFE, EXPIRATION, FLAGS. Server. Default values for new +principals. All default to 0. + +\item[keysalts, num_keysalts] Variable: supported_enctypes. ENCTYPES. +Server. The list of supported encryption type/salt type tuples; both +fields must be assigned if ENCTYPES is set. The default is a list +containing one enctype, DES-CBC-CRC with normal salt. +\end{description} + +\subsection{Principal keys} +\label{sec:keys} + +In KADM5_API_VERSION_1, all principals had a single key. The +encryption method was always DES, and the salt type was determined +outside the API (by command-line options to the administration +server). + +In KADM5_API_VERSION_2, principals can have multiple keys, each with +its own encryption type and salt. Each time a principal's key is +changed with kadm5_create_principal, kadm5_chpass_principal or +kadm5_randkey_principal, existing key entries are removed and a key +entry for each encryption and salt type tuple specified in the +configuration parameters is added. There is no provision for +specifying encryption and salt type information on a per-principal +basis; in a future version, this will probably be part of the admin +policy. There is also presently no provision for keeping multiple key +versions for a single principal active in the database. + +A single key is represented by a krb5_key_data: +% +\begin{verbatim} +typedef struct _krb5_key_data { + krb5_int16 key_data_ver; /* Version */ + krb5_int16 key_data_kvno; /* Key Version */ + krb5_int16 key_data_type[2]; /* Array of types */ + krb5_int16 key_data_length[2]; /* Array of lengths */ + krb5_octet * key_data_contents[2]; /* Array of pointers */ +} krb5_key_data; +\end{verbatim} +% +\begin{description} +\item[key_data_ver] The verion number of the structure. Versions 1 +and 2 are currently defined. If key_data_ver is 1 then the key is +either a random key (not requiring a salt) or the salt is the normal +v5 salt which is the same as the realm and therefore doesn't need to +be saved in the database. + +\item[key_data_kvno] The key version number of this key. + +\item[key_data_type] The first element is the enctype of this key. In +a version 2 structure, the second element is the salttype of this key. +The legal encryption types are defined in $<$krb5.h$>$. The legal +salt types are defined in $<$k5-int.h$>$. + +\item[key_data_length] The first element is length this key. In a +version 2 structure, the second element is length of the salt for this +key. + +\item[key_data_contents] The first element is the content of this key. +In a version 2 structure, the second element is the contents of the +salt for this key. +\end{description} + +\subsection{Field masks} +\label{sec:masks} + +The API functions for creating, retrieving, and modifying principals +and policies allow for a relevant subset of the fields of the +kadm5_principal_ent_t and kadm5_policy_ent_t to be specified or +changed. The chosen fields are determined by a bitmask that is passed +to the relevant function. Each API function has different rules for +which mask values can be specified, and can specify whether a given +mask value is mandatory, optional, or forbidden. Mandatory fields +must be present and forbidden fields must not be present or an error +is generated. When creating a principal or policy, optional fields +have a default value if they are not specified. When modifying a +principal or policy, optional fields are unchanged if they are not +specified. When retrieving a principal, optional fields are simply +not provided if they are not specified; not specifying undeeded fields +for retrieval may improve efficiency. The values for forbidden fields +are defined in the function semantics. + +The masks for principals are in table \ref{tab:princ-bits} and the +masks for policies are in table \ref{tab:policy-bits}. They are +defined in $<$kadm5/admin.h$>$. The KADM5_ prefix has been removed +from the Name fields. In the Create and Modify fields, M means +mandatory, F means forbidden, and O means optional. Create fields +that are optional specify the default value. The notation ``K/M +value'' means that the field inherits its value from the corresponding +field in the Kerberos master principal, for KADM5_API_VERSION_1, and +from the configuration parameters for KADM5_API_VERSION_2. + +All masks for principals are optional for retrevial, {\it except} that +the KEY_DATA mask is illegal when specified by a remote client; for +details, see the function semantics for kadm5_get_principal. + +Note that the POLICY and POLICY_CLR bits are special. When POLICY is +set, the policy is assigned to the principal. When POLICY_CLR is +specified, the policy is unassigned to the principal and as a result +no policy controls the principal. + +For convenience, the mask KADM5_PRINCIPAL_NORMAL_MASK contains all of +the principal masks {\it except} KADM5_KEY_DATA and KADM5_TL_DATA, and +the mask KADM5_POLICY_NORMAL_MASK contains all of the policy masks. + +\begin{table}[htbp] +\begin{tabular}{@{}lclll} +{\bf Name} & {\bf Value} & {\bf Fields Affected} & {\bf Create} & + {\bf Modify} \\ +PRINCIPAL & 0x000001 & principal & M & F \\ +PRINC_EXPIRE_TIME & 0x000002 & princ_expire_time & O, K/M value & O \\ +PW_EXPIRATION & 0x000004 & pw_expiration & O, now+pw_max_life & O \\ +LAST_PWD_CHANGE & 0x000008 & last_pwd_change & F & F \\ +ATTRIBUTES & 0x000010 & attributes & O, 0 & O \\ +MAX_LIFE & 0x000020 & max_life & O, K/M value & O \\ +MOD_TIME & 0x000040 & mod_date & F & F \\ +MOD_NAME & 0x000080 & mod_name & F & F \\ +KVNO & 0x000100 & kvno & O, 1 & O \\ +MKVNO & 0x000200 & mkvno & F & F \\ +AUX_ATTRIBUTES & 0x000400 & aux_attributes & F & F \\ +POLICY & 0x000800 & policy & O, none & O \\ +POLICY_CLR & 0x001000 & policy & F & O \\ +MAX_RLIFE & 0x002000 & max_renewable_life & O, K/M value & O \\ +LAST_SUCCESS & 0x004000 & last_success & F & F \\ +LAST_FAILED & 0x008000 & last_failed & F & F \\ +FAIL_AUTH_COUNT & 0x010000 & fail_auth_count & F & O \\ +KEY_DATA & 0x020000 & n_key_data, key_data & F & F \\ +TL_DATA & 0x040000 & n_tl_data, tl_data & O, 0, NULL & O +\end{tabular} +\caption{Mask bits for creating, retrieving, and modifying principals.} +\label{tab:princ-bits} +\end{table} + +\begin{table}[htbp] +\begin{tabular}{@{}lclll} +Name & Value & Field Affected & Create & Modify \\ +POLICY & same & policy & M & F \\ +PW_MAX_LIFE & 0x004000 & pw_max_life & O, 0 (infinite) & O \\ +PW_MIN_LIFE & 0x008000 & pw_min_life & O, 0 & O \\ +PW_MIN_LENGTH & 0x010000 & pw_min_length & O, 1 & O \\ +PW_MIN_CLASSES & 0x020000 & pw_min_classes & O, 1 & O \\ +PW_HISTORY_NUM & 0x040000 & pw_history_num & O, 0 & O \\ +REF_COUNT & 0x080000 & pw_refcnt & F & F +\end{tabular} +\caption{Mask bits for creating/modifying policies.} +\label{tab:policy-bits} +\end{table} + +\section{Constants, Header Files, Libraries} + +$<$kadm5/admin.h$>$ includes a number of required header files, +including RPC, Kerberos 5, com_err, and admin com_err +defines. It contains prototypes for all kadm5 routines mentioned +below, as well as all Admin API data structures, type definitions and +defines mentioned in this document. + +Before \v{\#include}ing $<$kadm5/admin.h$>$, the programmer can +specify the API version number that the program will use by +\v{\#define}ing USE_KADM5_API_VERSION; for example, define that symbol +to be 1 to use KADM5_API_VERSION_1. This will ensure that the correct +functional protoypes and data structures are defined. If no version +symbol is defined, the most recent version supported by the header +files will be used. + +Some of the defines and their values contained in $<$kadm5/admin.h$>$ +include the following, whose KADM5_ prefixes have been removed. +Symbols that do not exist in KADM5_API_VERSION_2 do not have a KADM5_ +prefix, but instead retain only with OVSEC_KADM_ prefix for +compatibility. +\begin{description} +\item[admin service principal] ADMIN_SERVICE (``kadmin/admin'') +\item[admin history key] HIST_PRINCIPAL (``kadmin/history'') +\item[change password principal] CHANGEPW_SERVICE (``kadmin/changepw'') +\item[server acl file path] ACLFILE (``/krb5/ovsec_adm.acl''). In +KADM5_API_VERSION 2, this is controlled by configuration parameters. +\item[dictionary] WORDFILE (``/krb5/kadmind.dict''). In +KADM5_API_VERSION 2, this is controlled by configuration parameters. +\end{description} + +KADM5 errors are described in $<$kadm5/kadm_err.h$>$, which +is included by $<$kadm5/admin.h$>$. + +The locations of the admin policy and principal databases, as well as +defines and type definitions for the databases, are defined in +$<$kadm5/adb.h$>$. Some of the defines in that file are: +\begin{description} +\item[admin policy database] POLICY_DB (``/krb5/kadm5_policy.db''). In +KADM5_API_VERSION 2, this is controlled by configuration parameters. +\item[admin principal database] PRINCIPAL_DB +(``/krb5/ovsec_principal.db''). In KADM5_API_VERSION 2, this is +controlled by configuration parameters. +\end{description} + +Client applications will link against libkadm5clnt.a and server +programs against libkadm5srv.a. Client applications must also link +against: libgssapi_krb5.a, libkrb5.a, libcrypto.a, libgssrpc.a, +libcom_err.a, and libdyn.a. Server applications must also link +against: libkdb5.a, libkrb5.a, libcrypto.a, libgssrpc.a, libcom_err.a, +and libdyn.a. + +\section{Error Codes} + +The error codes that can be returned by admin functions are listed +below. Error codes indicated with a ``*'' can be returned by every +admin function and always have the same meaning; these codes are +omitted from the list presented with each function. + +The admin system guarantees that a function that returns an error code +has no other side effect. + +The Admin system will use \v{com_err} for error codes. Note that this +means \v{com_err} codes may be returned from functions that the admin +routines call (e.g. the kerberos library). Callers should not expect +that only KADM5 errors will be returned. The Admin system error code +table name will be ``ovk'', and the offsets will be the same as the +order presented here. As mentioned above, the error table include file +will be $<$kadm5/kadm_err.h$>$. + +Note that these error codes are also used as protocol error code +constants and therefore must not change between product releases. +Additional codes should be added at the end of the list, not in the +middle. The integer value of KADM5_FAILURE is 43787520; the +remaining values are assigned in sequentially increasing order. + +\begin{description} +\item[* KADM5_FAILURE] Operation failed for unspecified reason +\item[* KADM5_AUTH_GET] Operation requires ``get'' privilege +\item[* KADM5_AUTH_ADD] Operation requires ``add'' privilege +\item[* KADM5_AUTH_MODIFY] Operation requires ``modify'' privilege +\item[* KADM5_AUTH_DELETE] Operation requires ``delete'' privilege +\item[* KADM5_AUTH_INSUFFICIENT] Insufficient authorization for +operation +\item[* KADM5_BAD_DB] Database inconsistency detected +\item[KADM5_DUP] Principal or policy already exists +\item[KADM5_RPC_ERROR] Communication failure with server +\item[KADM5_NO_SRV] No administration server found for realm +\item[KADM5_BAD_HIST_KEY] Password history principal key version +mismatch +\item[KADM5_NOT_INIT] Connection to server not initialized +\item[KADM5_UNK_PRINC] Principal does not exist +\item[KADM5_UNK_POLICY] Policy does not exist +\item[KADM5_BAD_MASK] Invalid field mask for operation +\item[KADM5_BAD_CLASS] Invalid number of character classes +\item[KADM5_BAD_LENGTH] Invalid password length +\item[KADM5_BAD_POLICY] Illegal policy name +\item[KADM5_BAD_PRINCIPAL] Illegal principal name. +\item[KADM5_BAD_AUX_ATTR] Invalid auxillary attributes +\item[KADM5_BAD_HISTORY] Invalid password history count +\item[KADM5_BAD_MIN_PASS_LIFE] Password minimum life is greater +then password maximum life +\item[KADM5_PASS_Q_TOOSHORT] Password is too short +\item[KADM5_PASS_Q_CLASS] Password does not contain enough +character classes +\item[KADM5_PASS_Q_DICT] Password is in the password dictionary +\item[KADM5_PASS_REUSE] Cannot resuse password +\item[KADM5_PASS_TOOSOON] Current password's minimum life has not +expired +\item[KADM5_POLICY_REF] Policy is in use +\item[KADM5_INIT] Connection to server already initialized +\item[KADM5_BAD_PASSWORD] Incorrect password +\item[KADM5_PROTECT_PRINCIPAL] Cannot change protected principal +\item[* KADM5_BAD_SERVER_HANDLE] Programmer error! Bad Admin server handle +\item[* KADM5_BAD_STRUCT_VERSION] Programmer error! Bad API structure version +\item[* KADM5_OLD_STRUCT_VERSION] API structure version specified by application is no longer supported (to fix, recompile application against current Admin API header files and libraries) +\item[* KADM5_NEW_STRUCT_VERSION] API structure version specified by application is unknown to libraries (to fix, obtain current Admin API header files and libraries and recompile application) +\item[* KADM5_BAD_API_VERSION] Programmer error! Bad API version +\item[* KADM5_OLD_LIB_API_VERSION] API version specified by application is no longer supported by libraries (to fix, update application to adhere to current API version and recompile) +\item[* KADM5_OLD_SERVER_API_VERSION] API version specified by application is no longer supported by server (to fix, update application to adhere to current API version and recompile) +\item[* KADM5_NEW_LIB_API_VERSION] API version specified by application is unknown to libraries (to fix, obtain current Admin API header files and libraries and recompile application) +\item[* KADM5_NEW_SERVER_API_VERSION] API version specified by +application is unknown to server (to fix, obtain and install newest +Admin Server) +\item[KADM5_SECURE_PRINC_MISSING] Database error! Required principal missing +\item[KADM5_NO_RENAME_SALT] The salt type of the specified principal +does not support renaming +\item[KADM5_BAD_CLIENT_PARAMS] Illegal configuration parameter for +remote KADM5 client +\item[KADM5_BAD_SERVER_PARAMS] Illegal configuration parameter for +local KADM5 client. +\item[KADM5_AUTH_LIST] Operation requires ``list'' privilege +\item[KADM5_AUTH_CHANGEPW] Operation requires ``change-password'' privilege +\item[KADM5_BAD_TL_TYPE] Programmer error! Illegal tagged data list +element type +\item[KADM5_MISSING_CONF_PARAMS] Required parameters in kdc.conf missing +\item[KADM5_BAD_SERVER_NAME] Bad krb5 admin server hostname +\item[KADM5_AUTH_SETKEY] Operation requires ``set-key'' privilege +\item[KADM5_SETKEY_DUP_ENCTYPES] Multiple values for single or folded enctype +\end{description} + +\section{Authentication and Authorization} +\label{sec:auth} + +Two Kerberos principals exist for use in communicating with the Admin +system: kadmin/admin and kadmin/changepw. Both principals +have the KRB5_KDB_DISALLOW_TGT_BASED bit set in their attributes so +that service tickets for them can only be acquired via a +password-based (AS_REQ) request. Additionally, kadmin/changepw +has the KRB5_KDB_PWCHANGE_SERVICE bit set so that a principal with an +expired password can still obtain a service ticket for it. + +The Admin system accepts requests that are authenticated to either +service principal, but the sets of operations that can be performed by +a request authenticated to each service are different. In particular, +only the functions chpass_principal, randkey_principal, get_principal, +and get_policy can be performed by a request authenticated to the +kadmin/changepw service, and they can only be performed when the +target principal of the operation is the same as the authenticated +client principal; the function semantics descriptions below give the +precise details. This means that administrative operations can only +be performed when authenticated to the kadmin/admin service. The +reason for this distinction is that tickets for kadmin/changepw can be +acquired with an expired password, and the KADM system does not want +to allow an administrator with an expired password to perform +administrative operations on arbitrary principals. + +Each Admin API operation authenticated to the kadmin/admin service +requires a specific authorization to run. This version uses a simple +named privilege system with the following names and meanings: + +\begin{description} +\item[Get] Able to examine the attributes (NOT key data) of principals +and policies. +\item[Add] Able to add principals and policies. +\item[Modify] Able to modify attributes of existing principals and +policies; this does not include changing passwords. +\item[Delete] Able to remove principals and policies. +\item[List] Able to retrieve a list of principals and policies. +\item[Changepw] Able to change the password of principals. +\item[Setkey] Able to set principal keys directly. +\end{description} + +Privileges are specified via an external configuration file on the +Kerberos master server. + +Table \ref{tab:func-overview} summarizes the authorization +requirements of each function. Additionally, each API function +description identifies the privilege required to perform it. The +Authorization checks only happen if you are using the RPC mechanism. +If you are using the server-side API functions locally on the admin +server, the only authorization check is if you can access the +approporiate local files. + +\section{Functions} + +\subsection{Overview} + +The functions provided by the Admin API, and the authorization they +require, are listed in the table \ref{tab:func-overview}. The +``kadm5_'' prefix has been removed from each function name. + +The function semantics in the following sections omit details that are +the same for every function. + +\begin{itemize} +\item The effects of every function are atomic. + +\item Every function performs an authorization check and returns +the appropriate KADM5_AUTH_* error code if the caller does not +have the required privilege. No other information or error code is +ever returned to an unauthorized user. + +\item Every function checks its arguments for NULL pointers or other +obviously invalid values, and returns EINVAL if any are detected. + +\item Any function that performs a policy check uses the policy named +in the principal's policy field. If the POLICY bit is not set in the +principal's aux_attributes field, however, the principal has no +policy, so the policy check is not performed. + +\item Unless otherwise specified, all functions return KADM5_OK. +\end{itemize} + +\begin{table}[htbp] +\caption{Summary of functions and required authorization.} +\label{tab:func-overview} +\begin{tabular}{@{}llp{3.24in}} +\\ +{\bf Function Name} & {\bf Authorization} & {\bf Operation} \\ + +init & none & Open a connection with the kadm5 library. OBSOLETE +but still provided---use init_with_password instead. \\ +init_with_password & none & Open a connection with the kadm5 +library using a password to obtain initial credentials. \\ +init_with_skey & none & Open a connection with the kadm5 library +using the keytab entry to obtain initial credentials. \\ +destroy & none & Close the connection with the kadm5 library. \\ +flush & none & Flush all database changes to disk; no-op when called +remotely. \\ +create_principal & add & Create a new principal. \\ +delete_principal & delete & Delete a principal. \\ +modify_principal & modify & Modify the attributes of an existing + principal (not password). \\ +rename_principal & add and delete & Rename a principal. \\ +get_principal & get\footnotemark & Retrieve a principal. \\ +get_principals & list & Retrieve some or all principal names. \\ +chpass_principal & changepw\footnotemark[\thefootnote] & + Change a principal's password. \\ +chpass_principal_util & changepw\footnotemark[\thefootnote] & Utility wrapper around chpass_principal. \\ +randkey_principal & changepw\footnotemark[\thefootnote] & + Randomize a principal's key. \\ +setkey_principal & setkey & Explicitly set a principal's keys. \\ +decrypt_key & none & Decrypt a principal key. \\ +create_policy & add & Create a new policy. \\ +delete_policy & delete & Delete a policy. \\ +modify_policy & modify & Modify the attributes of a policy. \\ +get_policy & get & Retrieve a policy. \\ +get_policies & list & Retrieve some or all policy names. \\ +free_principal_ent & none & Free the memory associated with an + kadm5_principal_ent_t. \\ +free_policy_ent & none & Free the memory associated with an + kadm5_policy_ent_t. \\ +get_privs & none & Return the caller's admin server privileges. +\end{tabular} +\end{table} +\footnotetext[\thefootnote]{These functions also allow a principal to +perform the operation on itself; see the function's semantics for +details.} + +\subsection{kadm5_init_*} + +In KADM5_API_VERSION 1: + +\begin{verbatim} +kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass, + char *service_name, char *realm, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) + +kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, + char *service_name, char *realm, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) + +kadm5_ret_t kadm5_init(char *client_name, char *pass, + char *service_name, char *realm, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) +\end{verbatim} + +In KADM5_API_VERSION 2: + +\begin{verbatim} +kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass, + char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) + +kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, + char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) + +kadm5_ret_t kadm5_init(char *client_name, char *pass, + char *service_name, + kadm5_config_params *realm_params, + unsigned long struct_version, + unsigned long api_version, + void **server_handle) + +kadm5_ret_t kadm5_init_with_creds(char *client_name, + krb5_ccache ccache, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +\end{verbatim} + +AUTHORIZATION REQUIRED: none + +NOTE: kadm5_init is an obsolete function provided for backwards +compatibility. It is identical to kadm5_init_with_password. + +These three functions open a connection to the kadm5 library and +initialize any neccessary state information. They behave differently +when called from local and remote clients. + +In KADM5_API_VERSION_2, these functions take a kadm5_config_params +structure instead of a realm name as an argument. The semantics are +similar: if a NULL pointer is passed for the realm_params argument, +the default realm and default parameters for that realm, as specified +in the krb5 configuration file (e.g. /etc/krb5.conf) are used. If a +realm_params structure is provided, the fields that are set override +the default values. If a parameter is specified to the local or +remote libraries that does not apply to that side, an error code +(KADM5_BAD_CLIENT_PARAMS or KADM5_BAD_SERVER_PARAMS) is returned. See +section \ref{sec:configparams} for a discussion of configuration +parameters. + +For remote clients, the semantics are: + +\begin{enumerate} +\item Initializes all the com_err error tables used by the Admin +system. + +\item Acquires configuration parameters. In KADM5_API_VERSION_1, all +the defaults specified in the configuration file are used, according +to the realm. In KADM5_API_VERSION_2, the values in params_in are +merged with the default values. If an illegal mask value is +specified, KADM5_BAD_CLIENT_PARAMS is returned. + +\item Acquires a Kerberos ticket for the specified service. + +\begin{enumerate} +\item The ticket's client is client_name, which can be any valid +Kerberos principal. If client_name does not include a realm, the +default realm of the local host is used +\item The ticket's service is service_name@realm. service_name must +be one of the constants KADM5_ADMIN_SERVICE or +KADM5_CHANGEPW_SERVICE. +\item If realm is NULL, client_name's realm is used. + +\item For init_with_password, an initial ticket is acquired and +decoded with the password pass, which must be client_name's password. +If pass is NULL or an empty string, the user is prompted (via the tty) +for a password. + +\item For init_with_skey, an initial ticket is acquired and decoded +with client_name's key obtained from the specified keytab. If keytab +is NULL or an empty string the default keytab is used. + +\item For init_with_creds, ccache must be an open credential cache +that already has a ticket for the specified client and server. +Alternatively, if a site chooses to disable the DISALLOW_TGT_BASED +flag on the admin and changepw principals, the ccache can contain a +ticket-granting ticket for client_name. +\end{enumerate} + +\item Creates a GSS-API authenticated connection to the Admin server, +using the just-acquired Kerberos ticket. + +\item Verifies that the struct_version and api_version specified by +the caller are valid and known to the library. + +\item Sends the specified api_version to the server. + +\item Upon successful completion, fills in server_handle with a handle +for this connection, to be used in all subsequent API calls. +\end{enumerate} + +The caller should always specify KADM5_STRUCT_VERSION for the +struct_version argument, a valid and supported API version constant +for the api_version argument (currently, KADM5_API_VERSION_1 or +KADM5_API_VERSION_2), and a valid pointer in which the server handle +will be stored. + +If any kadm5_init_* is invoked locally its semantics are: + +\begin{enumerate} +\item Initializes all the com_err error tables used by the Admin +system. + +\item Acquires configuration parameters. In KADM5_API_VERSION_1, all +the defaults specified in the configuration file are used, according +to the realm. In KADM5_API_VERSION_2, the values in params_in are +merged with the default values. If an illegal mask value is +specified, KADM5_BAD_SERVER_PARAMS is returned. + +\item Initializes direct access to the KDC database. In +KADM5_API_VERISON_1, if pass (or keytab) is NULL or an empty string, +reads the master password from the stash file; otherwise, the non-NULL +password is ignored and the user is prompted for it via the tty. In +KADM5_API_VERSION_2, if the MKEY_FROM_KEYBOARD parameter mask is set +and the value is non-zero, reads the master password from the user via +the tty; otherwise, the master key is read from the stash file. +Calling init_with_skey or init_with_creds with the MKEY_FROM_KEYBOARD +mask set with a non-zero field is illegal, and calling them without +the mask set is exactly like calling init_with_password. + +\item Initializes the dictionary (if present) for dictionary checks. + +\item Parses client_name as a Kerberos principal. client_name should +usually be specified as the name of the program. + +\item Verifies that the struct_version and api_version specified by +the caller are valid. + +\item Fills in server_handle with a handle containing all state +information (version numbers and client name) for this ``connection.'' +\end{enumerate} +The service_name argument is not used. + +RETURN CODES: + +\begin{description} +\item[KADM5_NO_SRV] No Admin server can be found for the +specified realm. + +\item[KADM5_RPC_ERROR] The RPC connection to the server cannot be +initiated. + +\item[KADM5_BAD_PASSWORD] Incorrect password. + +\item[KADM5_SECURE_PRINC_MISSING] The principal +KADM5_ADMIN_SERVICE or KADM5_CHANGEPW_SERVICE does not +exist. This is a special-case replacement return code for ``Server +not found in database'' for these required principals. + +\item[KADM5_BAD_CLIENT_PARAMS] A field in the parameters mask was +specified to the remote client library that is not legal for remote +clients. + +\item[KADM5_BAD_SERVER_PARAMS] A field in the parameters mask was +specified to the local client library that is not legal for local +clients. +\end{description} + +\subsection{kadm5_flush} + +\begin{verbatim} +kadm5_ret_t kadm5_flush(void *server_handle) +\end{verbatim} + +AUTHORIZATION REQUIRED: none + +Flush all changes to the Kerberos databases, leaving the connection to +the Admin API open. This function behaves differently when called by +local and remote clients. + +For local clients, the function closes and reopens the Kerberos +database with krb5_db_fini() and krb5_db_init(), and closes and +reopens the Admin policy database with adb_policy_close() and +adb_policy_open(). Although it is unlikely, any other these functions +could return errors; in that case, this function calls +kadm5_destroy and returns the error code. Therefore, if +kadm5_flush does not return KADM5_OK, the connection to the +Admin server has been terminated and, in principle, the databases +might be corrupt. + +For remote clients, the function is a no-op. + +\subsection{kadm5_destroy} + +\begin{verbatim} +kadm5_ret_t kadm5_destroy(void *server_handle) +\end{verbatim} + +AUTHORIZATION REQUIRED: none + +Close the connection to the Admin server and releases all related +resources. This function behaves differently when called by local and +remote clients. + +For remote clients, the semantics are: + +\begin{enumerate} +\item Destroy the temporary credential cache created by +kadm5_init. + +\item Tear down the GSS-API context negotiated with the server. + +\item Close the RPC connection. + +\item Free storage space associated with server_handle, after erasing +its magic number so it won't be mistaken for a valid handle by the +library later. +\end{enumerate} + +For local clients, this function just frees the storage space +associated with server_handle after erasing its magic number. + +RETURN CODES: + +\subsection{kadm5_create_principal} + +\begin{verbatim} +kadm5_ret_t +kadm5_create_principal(void *server_handle, + kadm5_principal_ent_t princ, u_int32 mask, + char *pw); +\end{verbatim} + +AUTHORIZATION REQUIRED: add + +\begin{enumerate} + +\item Return KADM5_BAD_MASK if the mask is invalid. +\item If the named principal exists, return KADM5_DUP. +\item If the POLICY bit is set and the named policy does not exist, +return KADM5_UNK_POLICY. +\item If KADM5_POLICY bit is set in aux_attributes check to see if +the password does not meets quality standards, return the appropriate +KADM5_PASS_Q_* error code if it fails. +\item Store the principal, set the key; see section \ref{sec:keys}. +\item If the POLICY bit is set, increment the named policy's reference +count by one. + +\item Set the pw_expiration field. +\begin{enumerate} +\item If the POLICY bit is set in mask, then if pw_max_life is non-zero, +set pw_expiration to now + pw_maxlife, otherwise set pw_max_life to +never. +\item If the PW_EXPIRATION bit is set in mask, set pw_expiration to +the requested value, overriding the value set above. +\end{enumerate} +NOTE: This is a change from the original semantics, in which policy +expiration was enforced even on administrators. The old semantics are +not preserved, even for version 1 callers, because this is a +server-specific policy decision; besides, the new semantics are less +restrictive, so all previous callers should continue to function +properly. + +\item Set mod_date to now and set mod_name to caller. +\item Set last_pwd_change to now. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_BAD_MASK] The field mask is invalid for a create +operation. +\item[KADM5_DUP] Principal already exists. +\item[KADM5_UNK_POLICY] Policy named in entry does not exist. +\item[KADM5_PASS_Q_*] Specified password does not meet policy +standards. +\end{description} + +\subsection{kadm5_delete_principal} + +\begin{verbatim} +kadm5_ret_t +kadm5_delete_principal(void *server_handle, krb5_principal princ); +\end{verbatim} + +AUTHORIZATION REQUIRED: delete + +\begin{enumerate} +\item Return KADM5_UNK_PRINC if the principal does not exist. +\item If the POLICY bit is set in aux_attributes, decrement the named +policy's reference count by one. +\item Delete principal. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_UNK_PRINC] Principal does not exist. +\end{description} + +\subsection{kadm5_modify_principal} + +\begin{verbatim} +kadm5_ret_t +kadm5_modify_principal(void *server_handle, + kadm5_principal_ent_t princ, u_int32 mask); +\end{verbatim} + +Modify the attributes of the principal named in +kadm5_principal_ent_t. This does not allow the principal to be +renamed or for its password to be changed. + +AUTHORIZATION REQUIRED: modify + +Although a principal's pw_expiration is usually computed based on its +policy and the time at which it changes its password, this function +also allows it to be specified explicitly. This allows an +administrator, for example, to create a principal and assign it to a +policy with a pw_max_life of one month, but to declare that the new +principal must change its password away from its initial value +sometime within the first week. + +\begin{enumerate} +\item Return KADM5_UNK_PRINC if the principal does not exist. +\item Return KADM5_BAD_MASK if the mask is invalid. +\item If POLICY bit is set but the new policy does not exist, return +KADM5_UNK_POLICY. +\item If either the POLICY or POLICY_CLR bits are set, update the +corresponding bits in aux_attributes. + +\item Update policy reference counts. +\begin{enumerate} +\item If the POLICY bit is set, then increment policy count on new +policy. +\item If the POLICY or POLICY_CLR bit is set, and the POLICY bit in +aux_attributes is set, decrement policy count on old policy. +\end{enumerate} + +\item Set pw_expiration appropriately. pw_expiration can change if: +the POLICY bit is set in mask, so the principal is changing to a +policy (either from another policy or no policy); the POLICY_CLR bit +is set in mask, so the principal is changing to no policy; or +PW_EXPIRATION is set. +\begin{enumerate} +\item If the POLICY bit is set in mask, set pw_expiration to +last_pwd_change + pw_max_life if pw_max_life is non-zero, otherwise +set pw_expiration to never. +\item If the POLICY_CLR biti s set in mask, set pw_expiration to +never. +\item If PW_EXPIRATION is set, set pw_expiration to the requested +value, overriding the value from the previous two cases. NOTE: This +is a change from the original semantics, in which policy expiration +was enforced even on administrators. The old semantics are not +preserved, even for version 1 callers, because this is a +server-specific policy decision; besides, the new semantics are less +restrictive, so all previous callers should continue to function +properly. +\end{enumerate} + +% Here is the previous, and confusing, text of pw_expiration semantics: +%\begin{enumerate} +%\item If the POLICY bit is not set in aux_attributes, then +%\begin{enumerate} +%\item if the PW_EXPIRATION bit is set, set pw_expiration to the given +%value, else +%\item set pw_expiration to never. +%\end{enumerate} +%\item Otherwise, if the PW_EXPIRATION bit is set, set pw_expiration to +%the sooner of the given value and last_pwd_change + pw_max_life. +%\item Otherwise, set pw_expiration to last_pwd_change + pw_max_life. +%\end{enumerate} + +\item Update the remaining fields specified in the mask. +\item Update mod_name field to caller and mod_date to now. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_UNK_PRINC] Entry does not exist. +\item[KADM5_BAD_MASK] The mask is not valid for a modify +operation. +\item[KADM5_UNK_POLICY] The POLICY bit is set but the new +policy does not exist. +\item[KADM5_BAD_TL_TYPE] The KADM5_TL_DATA bit is set in mask, and the +given tl_data list contains an element whose type is less than 256. +\end{description} + +\subsection{kadm5_rename_principal} + +\begin{verbatim} +kadm5_ret_t +kadm5_rename_principal(void *server_handle, krb5_principal source, + krb5_principal target); +\end{verbatim} + +AUTHORIZATION REQUIRED: add and delete + +\begin{enumerate} +\item Check to see if source principal exists, if not return +KADM5_UNK_PRINC error. +\item Check to see if target exists, if so return KADM5_DUP error. +\item Create the new principal named target, then delete the old +principal named source. All of target's fields will be the same as +source's fields, except that mod_name and mod_date will be updated to +reflect the current caller and time. +\end{enumerate} + +Note that since the principal name may have been used as the salt for +the principal's key, renaming the principal may render the principal's +current password useless; with the new salt, the key generated by +string-to-key on the password will suddenly be different. Therefore, +an application that renames a principal must also require the user to +specify a new password for the principal (and administrators should +notify the affected party). + +Note also that, by the same argument, renaming a principal will +invalidate that principal's password history information; since the +salt will be different, a user will be able to select a previous +password without error. + +RETURN CODES: + +\begin{description} +\item[KADM5_UNK_PRINC] Source principal does not exist. +\item[KADM5_DUP] Target principal already exist. +\end{description} + +\subsection{kadm5_chpass_principal} + +\begin{verbatim} +kadm5_ret_t +kadm5_chpass_principal(void *server_handle, krb5_principal princ, + char *pw); +\end{verbatim} + +AUTHORIZATION REQUIRED: changepw, or the calling principal being the +same as the princ argument. If the request is authenticated to the +kadmin/changepw service, the changepw privilege is disregarded. + +Change a principal's password. See section \ref{sec:keys} for a +description of how the keys are determined. + +This function enforces password policy and dictionary checks. If the new +password specified is in the password dictionary, and the policy bit is set +KADM5_PASS_DICT is returned. If the principal's POLICY bit is set in +aux_attributes, compliance with each of the named policy fields is verified +and an appropriate error code is returned if verification fails. + +Note that the policy checks are only be performed if the POLICY bit is +set in the principal's aux_attributes field. + +\begin{enumerate} +\item Make sure principal exists, if not return KADM5_UNK_PRINC error. +\item If caller does not have modify privilege, (now - last_pwd_change) $<$ +pw_min_life, and the KRB5_KDB_REQUIRES_PWCHANGE bit is not set in the +principal's attributes, return KADM5_PASS_TOOSOON. +\item If the principal your are trying to change is kadmin/history +return KADM5_PROTECT_PRINCIPAL. +\item If the password does not meet the quality +standards, return the appropriate KADM5_PASS_Q_* error code. +\item Convert password to key; see section \ref{sec:keys}. +\item If the new key is in the principal's password history, return +KADM5_PASS_REUSE. +\item Store old key in history. +\item Update principal to have new key. +\item Increment principal's key version number by one. +\item If the POLICY bit is set, set pw_expiration to now + +max_pw_life. If the POLICY bit is not set, set pw_expiration to +never. +\item If the KRB5_KDB_REQUIRES_PWCHANGE bit is set in the principal's +attributes, clear it. +\item Update last_pwd_change and mod_date to now, update mod_name to +caller. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_UNK_PRINC] Principal does not exist. +\item[KADM5_PASS_Q_*] Requested password does not meet quality +standards. +\item[KADM5_PASS_REUSE] Requested password is in user's +password history. +\item[KADM5_PASS_TOOSOON] Current password has not reached minimum life +\item[KADM5_PROTECT_PRINCIPAL] Cannot change the password of a special principal +\end{description} + + +\subsection{kadm5_chpass_principal_util} + +\begin{verbatim} +kadm5_ret_t +kadm5_chpass_principal_util(void *server_handle, krb5_principal princ, + char *new_pw, char **pw_ret, + char *msg_ret); +\end{verbatim} + +AUTHORIZATION REQUIRED: changepw, or the calling principal being the +same as the princ argument. If the request is authenticated to the +kadmin/changepw service, the changepw privilege is disregarded. + +This function is a wrapper around kadm5_chpass_principal. It can +read a new password from a user, change a principal's password, and +return detailed error messages. msg_ret should point to a char buffer +in the caller's space of sufficient length for the error messages +described below. 1024 bytes is recommended. It will also return the +new password to the caller if pw_ret is non-NULL. + +\begin{enumerate} +\item If new_pw is NULL, this routine will prompt the user for the new +password (using the strings specified by KADM5_PW_FIRST_PROMPT and +KADM5_PW_SECOND_PROMPT) and read (without echoing) the password input. +Since it is likely that this will simply call krb5_read_password only +terminal-based applications will make use of the password reading +functionality. If the passwords don't match the string ``New passwords do +not match - password not changed.'' will be copied into msg_ret, and the +error code KRB5_LIBOS_BADPWDMATCH will be returned. For other errors that +ocurr while reading the new password, copy the string ``$ +occurred while trying to read new password.'' followed by a blank line and +the string specified by CHPASS_UTIL_PASSWORD_NOT_CHANGED into msg_ret and +return the error code returned by krb5_read_password. + +\item If pw_ret is non-NULL, and the password was prompted, set *pw_ret to +point to a static buffer containing the password. If pw_ret is non-NULL +and the password was supplied, set *pw_ret to the supplied password. + +\item Call kadm5_chpass_principal with princ, and new_pw. + +\item If successful copy the string specified by CHPASS_UTIL_PASSWORD_CHANGED +into msg_ret and return zero. + +\item For a policy related failure copy the appropriate message (from below) +followed by a newline and ``Password not changed.'' into msg_ret +filling in the parameters from the principal's policy information. If +the policy information cannot be obtained copy the generic message if +one is specified below. Return the error code from +kadm5_chpass_principal. + +Detailed messages: +\begin{description} + +\item[PASS_Q_TOO_SHORT] +New password is too short. Please choose a +password which is more than $<$pw-min-len$>$ characters. + +\item[PASS_Q_TOO_SHORT - generic] +New password is too short. Please choose a longer password. + +\item[PASS_REUSE] +New password was used previously. Please choose a +different password. + +\item[PASS_Q_CLASS] +New password does not have enough character classes. Classes include +lower class letters, upper case letters, digits, punctuation and all +other characters. Please choose a password with at least +$<$min-classes$>$ character classes. + +\item[PASS_Q_CLASS - generic] +New password does not have enough character classes. Classes include +lower class letters, upper case letters, digits, punctuation and all +other characters. + +\item[PASS_Q_DICT] +New password was found in a dictionary of possible passwords and +therefore may be easily guessed. Please choose another password. See +the kpasswd man page for help in choosing a good password. + +\item[PASS_TOOSOON] +Password cannot be changed because it was changed too recently. Please +wait until $<$last-pw-change+pw-min-life$>$ before you change it. If you +need to change your password before then, contact your system +security administrator. + +\item[PASS_TOOSOON - generic] +Password cannot be changed because it was changed too recently. If you +need to change your now please contact your system security +administrator. +\end{description} + +\item For other errors copy the string ``$<$com_err message$>$ +occurred while trying to change password.'' following by a blank line +and ``Password not changed.'' into msg_ret. Return the error code +returned by kadm5_chpass_principal. +\end{enumerate} + + +RETURN CODES: + +\begin{description} +\item[KRB5_LIBOS_BADPWDMATCH] Typed new passwords did not match. +\item[KADM5_UNK_PRINC] Principal does not exist. +\item[KADM5_PASS_Q_*] Requested password does not meet quality +standards. +\item[KADM5_PASS_REUSE] Requested password is in user's +password history. +\item[KADM5_PASS_TOOSOON] Current password has not reached minimum +life. +\end{description} + +\subsection{kadm5_randkey_principal} + +In KADM5_API_VERSION_1: + +\begin{verbatim} +kadm5_ret_t +kadm5_randkey_principal(void *server_handle, krb5_principal princ, + krb5_keyblock **new_key) +\end{verbatim} + +In KADM5_API_VERSION_2: + +\begin{verbatim} +kadm5_ret_t +kadm5_randkey_principal(void *server_handle, krb5_principal princ, + krb5_keyblock **new_keys, int *n_keys) +\end{verbatim} + +AUTHORIZATION REQUIRED: changepw, or the calling principal being the +same as the princ argument. If the request is authenticated to the +kadmin/changepw service, the changepw privilege is disregarded. + +Generate and assign a new random key to the named principal, and +return the generated key in allocated storage. In +KADM5_API_VERSION_2, multiple keys may be generated and returned as an +array, and n_new_keys is filled in with the number of keys generated. +See section \ref{sec:keys} for a description of how the keys are +chosen. In KADM5_API_VERSION_1, the caller must free the returned +krb5_keyblock * with krb5_free_keyblock. In KADM5_API_VERSION_2, the +caller must free each returned keyblock with krb5_free_keyblock. + +If the principal's POLICY bit is set in aux_attributes and the caller does +not have modify privilege , compliance with the password minimum life +specified by the policy is verified and an appropriate error code is returned +if verification fails. + +\begin{enumerate} +\item If the principal does not exist, return KADM5_UNK_PRINC. +\item If caller does not have modify privilege, (now - last_pwd_change) $<$ +pw_min_life, and the KRB5_KDB_REQUIRES_PWCHANGE bit is not set in the +principal's attributes, return KADM5_PASS_TOOSOON. +\item If the principal you are trying to change is kadmin/history return +KADM5_PROTECT_PRINCIPAL. +\item Store old key in history. +\item Update principal to have new key. +\item Increment principal's key version number by one. +\item If the POLICY bit in aux_attributes is set, set pw_expiration to +now + max_pw_life. +\item If the KRB5_KDC_REQUIRES_PWCHANGE bit is set in the principal's +attributes, clear it. +\item Update last_pwd_change and mod_date to now, update mod_name to +caller. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_UNK_PRINC] Principal does not exist. +\item[KADM5_PASS_TOOSOON] The minimum lifetime for the current +key has not expired. +\item[KADM5_PROTECT_PRINCIPAL] Cannot change the password of a special +principal +\end{description} + +This function can also be used as part of a sequence to create a new +principal with a random key. The steps to perform the operation +securely are + +\begin{enumerate} +\item Create the principal with kadm5_create_principal with a +random password string and with the KRB5_KDB_DISALLOW_ALL_TIX bit set +in the attributes field. + +\item Randomize the principal's key with kadm5_randkey_principal. + +\item Call kadm5_modify_principal to reset the +KRB5_KDB_DISALLOW_ALL_TIX bit in the attributes field. +\end{enumerate} + +The three steps are necessary to ensure secure creation. Since an +attacker might be able to guess the initial password assigned by the +client program, the principal must be disabled until the key can be +truly randomized. + +\subsection{kadm5_setkey_principal} + +\begin{verbatim} +kadm5_ret_t +kadm5_setkey_principal(void *server_handle, krb5_principal princ, + krb5_keyblock *new_keys, int n_keys) +\end{verbatim} + +AUTHORIZATION REQUIRED: setkey. This function does not allow the use +of regular changepw authorization because it bypasses the password +policy mechanism. + +This function only exists in KADM5_API_VERSION_2. + +Explicitly sets the specified principal's keys to the n_keys keys in +the new_keys array. The keys in new_keys should not be encrypted in +the Kerberos master key; this function will perform that operation +itself (the keys will be protected during transmission from the +calling client to the kadmind server by the AUTH_GSSAPI RPC layer). +This function completely bypasses the principal's password policy, if +set. + +\begin{enumerate} +\item If the principal does not exist, return KADM5_UNK_PRINC. +\item If the principal you are trying to change is kadmin/history return +KADM5_PROTECT_PRINCIPAL. +\item If new_keys contains more than one key of any ENCTYPE_DES_CBC_* +type that is folded, return KADM5_SETKEY_DUP_ENCTYPES. +\item Store old key in history. +\item Update principal to have new key. +\item Increment principal's key version number by one. +\item If the POLICY bit in aux_attributes is set, set pw_expiration to +now + max_pw_life. +\item If the KRB5_KDC_REQUIRES_PWCHANGE bit is set in the principal's +attributes, clear it. +\item Update last_pwd_change and mod_date to now, update mod_name to +caller. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_UNK_PRINC] Principal does not exist. +\item[KADM5_PROTECT_PRINCIPAL] Cannot change the password of a special +principal +\end{description} + +This function can also be used as part of a sequence to create a new +principal with an explicitly key. The steps to perform the operation +securely are + +\begin{enumerate} +\item Create the principal with kadm5_create_principal with a +random password string and with the KRB5_KDB_DISALLOW_ALL_TIX bit set +in the attributes field. + +\item Set the principal's key with kadm5_setkey_principal. + +\item Call kadm5_modify_principal to reset the +KRB5_KDB_DISALLOW_ALL_TIX bit in the attributes field. +\end{enumerate} + +The three steps are necessary to ensure secure creation. Since an +attacker might be able to guess the initial password assigned by the +client program, the principal must be disabled until the key can be +truly randomized. + +\subsection{kadm5_get_principal} + +In KADM5_API_VERSION_1: + +\begin{verbatim} +kadm5_ret_t +kadm5_get_principal(void *server_handle, krb5_principal princ, + kadm5_principal_ent_t *ent); +\end{verbatim} + +In KADM5_API_VERSION_2: + +\begin{verbatim} +kadm5_ret_t +kadm5_get_principal(void *server_handle, krb5_principal princ, + kadm5_principal_ent_t ent, u_int32 mask); +\end{verbatim} + +AUTHORIZATION REQUIRED: get, or the calling principal being the same +as the princ argument. If the request is authenticated to the +kadmin/changepw service, the get privilege is disregarded. + +In KADM5_API_VERSION_1, return all of the principal's attributes in +allocated memory; if an error is returned entry is set to NULL. In +KADM5_API_VERSION_2, fill in the fields of the principal structure +specified in the mask; memory for the structure is not allocated. +Typically, a caller will specify the mask KADM5_PRINCIPAL_NORMAL_MASK, +which includes all the fields {\it except} key_data and tl_data to +improve time and memory efficiency. A caller that wants key_data and +tl_data can bitwise-OR those masks onto NORMAL_MASK. Note that even +if KADM5_TL_DATA is specified, this function will not return internal +tl_data elements whose type is less than 256. + +The caller must free the returned entry with kadm5_free_principal_ent. + +The function behaves differently for local and remote clients. For +remote clients, the KEY_DATA mask is illegal and results in a +KADM5_BAD_MASK error. + +RETURN CODES: + +\begin{description} +\item[KADM5_UNK_PRINC] Principal does not exist. +\item[KADM5_BAD_MASK] The mask is not valid for a get operation. + +\end{description} + +\subsection{kadm5_decyrpt_key} + +\begin{verbatim} +kadm5_ret_t kadm5_decrypt_key(void *server_handle, + kadm5_principal_ent_t entry, krb5_int32 + ktype, krb5_int32 stype, krb5_int32 + kvno, krb5_keyblock *keyblock, + krb5_keysalt *keysalt, int *kvnop) +\end{verbatim} + +AUTHORIZATION REQUIRED: none, local function + +Searches a principal's key_data array to find a key with the specified +enctype, salt type, and kvno, and decrypts the key into keyblock and +keysalt if found. entry must have been returned by +kadm5_get_principal with at least the KADM5_KEY_DATA mask set. +Returns ENOENT if the key cannot be found, EINVAL if the key_data +array is empty (as it always is in an RPC client). + +If ktype or stype is -1, it is ignored for the search. If kvno is -1, +ktype and stype are ignored and the key with the max kvno is returned. +If kvno is 0, only the key with the max kvno is returned and only if +it matches the ktype and stype; otherwise, ENOENT is returned. + +\subsection{kadm5_get_principals} + +\begin{verbatim} +kadm5_ret_t +kadm5_get_principals(void *server_handle, char *exp, + char ***princs, int *count) +\end{verbatim} + +Retrieves the list of principal names. + +AUTHORIZATION REQUIRED: list + +If \v{exp} is NULL, all principal names are retrieved; otherwise, +principal names that match the expression exp are retrieved. +\v{princs} is filled in with a pointer to a NULL-terminated array of +strings, and \v{count} is filled in with the number of principal names +in the array. \v{princs} must be freed with a call to +\v{kadm5_free_name_list}. + +All characters in the expression match themselves except ``?'' which +matches any single character, ``*'' which matches any number of +consecutive characters, and ``[chars]'' which matches any single +character of ``chars''. Any character which follows a ``$\backslash$'' +matches itself exactly, and a ``$\backslash$'' cannot be the last +character in the string. + +\subsection{kadm5_create_policy} + +\begin{verbatim} +kadm5_ret_t +kadm5_create_policy(void *server_handle, + kadm5_policy_ent_t policy, u_int32 mask); +\end{verbatim} + +Create a new policy. + +AUTHORIZATION REQUIRED: add + +\begin{enumerate} +\item Check to see if mask is valid, if not return KADM5_BAD_MASK error. +\item Return KADM5_BAD_POLICY if the policy name contains illegal +characters. + +\item Check to see if the policy already exists, if so return +KADM5_DUP error. +\item If the PW_MIN_CLASSES bit is set and pw_min_classes is not 1, 2, +3, 4, or 5, return KADM5_BAD_CLASS. +\item Create a new policy setting the appropriate fields determined +by the mask. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_DUP] Policy already exists +\item[KADM5_BAD_MASK] The mask is not valid for a create +operation. +\item[KADM5_BAD_CLASS] The specified number of character classes +is invalid. +\item[KADM5_BAD_POLICY] The policy name contains illegal characters. +\end{description} + +\subsection{kadm5_delete_policy} + +\begin{verbatim} +kadm5_ret_t +kadm5_delete_policy(void *server_handle, char *policy); +\end{verbatim} + +Deletes a policy. + +AUTHORIZATION REQUIRED: delete + +\begin{enumerate} +\item Return KADM5_BAD_POLICY if the policy name contains illegal +characters. +\item Return KADM5_UNK_POLICY if the named policy does not exist. +\item Return KADM5_POLICY_REF if the named policy's refcnt is not 0. +\item Delete policy. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_BAD_POLICY] The policy name contains illegal characters. +\item[KADM5_UNK_POLICY] Policy does not exist. +\item[KADM5_POLICY_REF] Policy is being referenced. +\end{description} + +\subsection{kadm5_modify_policy} + +\begin{verbatim} +kadm5_ret_t +kadm5_modify_policy(void *server_handle, + kadm5_policy_ent_t policy, u_int32 mask); +\end{verbatim} + +Modify an existing policy. Note that modifying a policy has no affect +on a principal using the policy until the next time the principal's +password is changed. + +AUTHORIZATION REQUIRED: modify + +\begin{enumerate} +\item Return KADM5_BAD_POLICY if the policy name contains illegal +characters. +\item Check to see if mask is legal, if not return KADM5_BAD_MASK error. +\item Check to see if policy exists, if not return +KADM5_UNK_POLICY error. +\item If the PW_MIN_CLASSES bit is set and pw_min_classes is not 1, 2, +3, 4, or 5, return KADM5_BAD_CLASS. +\item Update the fields specified in the mask. +\end{enumerate} + +RETURN CODES: + +\begin{description} +\item[KADM5_BAD_POLICY] The policy name contains illegal characters. +\item[KADM5_UNK_POLICY] Policy not found. +\item[KADM5_BAD_MASK] The mask is not valid for a modify +operation. +\item[KADM5_BAD_CLASS] The specified number of character classes +is invalid. +\end{description} + +\subsection{kadm5_get_policy} + +In KADM5_API_VERSION_1: + +\begin{verbatim} +kadm5_ret_t +kadm5_get_policy(void *server_handle, char *policy, kadm5_policy_ent_t *ent); +\end{verbatim} + +In KADM5_API_VERSION_2: + +\begin{verbatim} +kadm5_ret_t +kadm5_get_policy(void *server_handle, char *policy, kadm5_policy_ent_t ent); +\end{verbatim} + +AUTHORIZATION REQUIRED: get, or the calling principal's policy being +the same as the policy argument. If the request is authenticated to +the kadmin/changepw service, the get privilege is disregarded. + +In KADM5_API_VERSION_1, return the policy's attributes in allocated +memory; if an error is returned entry is set to NULL. In +KADM5_API_VERSION_2, fill in fields of the policy structure allocated +by the caller. The caller must free the returned entry with +kadm5_free_policy_ent + +RETURN CODES: + +\begin{description} +\item[KADM5_BAD_POLICY] The policy name contains illegal characters. +\item[KADM5_UNK_POLICY] Policy not found. +\end{description} + +\subsection{kadm5_get_policies} + +\begin{verbatim} +kadm5_ret_t +kadm5_get_policies(void *server_handle, char *exp, + char ***pols, int *count) +\end{verbatim} + +Retrieves the list of principal names. + +AUTHORIZATION REQUIRED: list + +If \v{exp} is NULL, all principal names are retrieved; otherwise, +principal names that match the expression exp are retrieved. \v{pols} +is filled in with a pointer to a NULL-terminated array of strings, and +\v{count} is filled in with the number of principal names in the +array. \v{pols} must be freed with a call to +\v{kadm5_free_name_list}. + +All characters in the expression match themselves except ``?'' which +matches any single character, ``*'' which matches any number of +consecutive characters, and ``[chars]'' which matches any single +character of ``chars''. Any character which follows a ``$\backslash$'' +matches itself exactly, and a ``$\backslash$'' cannot be the last +character in the string. + +\subsection{kadm5_free_principal_ent, _policy_ent} + +\begin{verbatim} +void kadm5_free_principal_ent(void *server_handle, + kadm5_principal_ent_t princ); +\end{verbatim} + +In KADM5_API_VERSION_1, free the structure and contents allocated by a +call to kadm5_get_principal. In KADM5_API_VERSION_2, free the +contents allocated by a call to kadm5_get_principal. + +AUTHORIZATION REQUIRED: none (local operation) + +\begin{verbatim} +void kadm5_free_policy_ent(kadm5_policy_ent_t policy); +\end{verbatim} + +Free memory that was allocated by a call to kadm5_get_policy. If +the argument is NULL, the function returns succesfully. + +AUTHORIZATION REQUIRED: none (local operation) + +\subsection{kadm5_free_name_list} + +\begin{verbatim} +void kadm5_free_name_list(void *server_handle, + char **names, int *count); +\end{verbatim} + +Free the memory that was allocated by kadm5_get_principals or +kadm5_get_policies. names and count must be a matched pair of +values returned from one of those two functions. + +\subsection{kadm5_free_key_data} + +\begin{verbatim} +void kadm5_free_key_data(void *server_handle, + krb5_int16 *n_key_data, krb5_key_data *key_data) +\end{verbatim} + +Free the memory that was allocated by kadm5_randkey_principal. +n_key_data and key_data must be a matched pair of values returned from +that function. + +\subsection{kadm5_get_privs} + +\begin{verbatim} +kadm5_ret_t +kadm5_get_privs(void *server_handle, u_int32 *privs); +\end{verbatim} + +Return the caller's admin server privileges in the integer pointed to +by the argument. The Admin API does not define any way for a +principal's privileges to be set. Note that this function will +probably be removed or drastically changed in future versions of this +system. + +The returned value is a bitmask indicating the caller's privileges: + +\begin{tabular}{llr} +{\bf Privilege} & {\bf Symbol} & {\bf Value} \\ +Get & KADM5_PRIV_GET & 0x01 \\ +Add & KADM5_PRIV_ADD & 0x02 \\ +Modify & KADM5_PRIV_MODIFY & 0x04 \\ +Delete & KADM5_PRIV_DELETE & 0x08 \\ +List & KADM5_PRIV_LIST & 0x10 \\ +Changepw & KADM5_PRIV_CPW & 0x20 +\end{tabular} + +There is no guarantee that a caller will have a privilege indicated by +this function for any length of time or for any particular target; +applications using this function must still be prepared to handle all +possible KADM5_AUTH_* error codes. + +In the initial MIT Kerberos version of the admin server, permissions +depend both on the caller and the target; this function returns a +bitmask representing all privileges the caller can possibly have for +any possible target. + +\end{document} diff --git a/mechglue/doc/kadm5/api-server-design.tex b/mechglue/doc/kadm5/api-server-design.tex new file mode 100644 index 000000000..61fc868fe --- /dev/null +++ b/mechglue/doc/kadm5/api-server-design.tex @@ -0,0 +1,1042 @@ +\documentstyle[12pt,fullpage,rcsid]{article} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make _ actually generate an _, and allow line-breaking after it. +\let\underscore=\_ +\catcode`_=13 +\def_{\underscore\penalty75\relax} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\rcs$Id$ + +\setlength{\parskip}{.7\baselineskip} +\setlength{\parindent}{0pt} + +\def\v#1{\verb+#1+} +\def\k#1{K$_#1$} + +\title{KADM5 Library and Server \\ Implementation Design\thanks{\rcsId}} +\author{Barry Jaspan} + +\begin{document} + +\sloppy +\maketitle + +{\setlength{\parskip}{0pt}\tableofcontents} + +\section{Overview} + +The KADM5 administration system is designed around the KADM5 API. The +``server-side'' library libkadm5srv.a implements the KADM5 API by +operating directly on the underlying KDC and admin databases. The +``client-side'' library libkadm5clnt.a implements the KADM5 API via an +RPC mechanism. The administration server kadmind accepts RPC requests +from the client-side library and translates them into calls to the +server-side library, performing authentication, authorization, and +logging along the way. + +The two libraries, libkadm5clnt.a and libkadm5srv.a, export the +identical kadm5 interface; for example, both contain definitions for +kadm5_get_principal, and all other kadm5 functions. In most cases, +the client library function just marshalls arguments and results into +and out of an RPC call, whereas the server library function performs +the actual operation on the database file. kadm5_init_*, however, are +substantially different even though they export the same interface: on +the client, they establish the RPC connection and GSS-API context, +whereas on the server side the open the database files, read in the +password dictionary, and the like. Also, the kadm5_free functions +operate on local process memory in both libraries. + +The admin server is implemented as a nearly-stateless transaction +server, where each admin API function represents a single transaction. +No per-client or per-connection information is stored; only local +database handles are maintained between requests. The RPC mechanism +provides access to remote callers' authentication credentials for +authorization purposes. + +The admin API is exported via an RPC interface that hides all details +about network encoding, authentication, and encryption of data on the +wire. The RPC mechanism does, however, allow the server to access the +underlying authentication credentials for authorization purposes. + +The admin system maintains two databases: +% +\begin{itemize} +\item The master Kerberos (KDC) database is used to store all the +information that the Kerberos server understands, thus allowing the +greatest functionality with no modifications to a standard KDC. + +\item The KDC database also stores kadm5-specific per-principal +information in each principal's krb5_tl_data list. In a prior +version, this data was stored in a separate admin principal database; +thus, when this document refers to ``the admin principal database,'' +it now refers to the appropriate krb5_tl_data entries in the KDC +database. + +\item The policy database stores kadm5 policy information. +\end{itemize} + +The per-principal information stored in the admin principal database +consists of the principal's policy name and an array of the +principal's previous keys. The old keys are stored encrypted in the +key of the special principal ``kadmin/history'' that is created by the +server library when it is first needed. Since a change in +kadmin/history's key renders every principal's key history array +useless, it can only be changed using the ovsec_adm_edit utility; that +program will reencrypt every principal's key history in the new +key.\footnote{ovsec_adm_edit has not yet been implemented, and there +are currently no plans to implement it; thus, the history cannot +currently be changed.} The server library refuses all requests to +change kadmin/history's key. + +\section{API Handles} + +Each call to kadm5_init_* on the client or server creates a new API +handle. The handles encapsulate the API and structure versions +specified by kadm5_init_*'s caller and all other internal data needed +by the library. A process can have multiple open API handles +simultaneously by calling kadm5_init_* multiple times, and call can +specify a different version, client or service principal, and so +forth. + +Each kadm5 function verifies the handle it is given with the +CHECK_HANDLE or _KADM5_CHECK_HANDLE macros. The CHECK_HANDLE macro +differs for the client and server library because the handle types +used by those libraries differ, so it is defined in both +$<$client_internal.h$>$ and $<$server_internal.h$>$ in the library +source directory. In each header file, CHECK_HANDLE first calls +GENERIC_CHECK_HANDLE, defined in $<$admin_internal.h$>$, which +verifies the magic number, API version, and structure version that is +contained in both client and server handles. CHECK_HANDLE then calls +either CLIENT_CHECK_HANDLE or SERVER_CHECK_HANDLE respectively to +verify the client- or server-library specific handle fields. + +The CHECK_HANDLE macro is useful because it inlines the handle check +instead of requiring a separate function call. However, using +CHECK_HANDLE means that a source file cannot be compiled once and +included into both the client and server library, because CHECK_HANDLE +is always either specific to either the client or server library, not +both. There are a number of functions that can be implemented with +the same code in both the client and server libraries, however, +including all of the kadm5_free functions and +kadm5_chpass_principal_util. The _KADM5_CHECK_HANDLE macro solves +this problem; instead of inlining the handle check, it calls the +function _kadm5_check_handle which is defined separately in both the +client and server library, in client_init.c and server_init.c. +Since these two files are only compiled once and put in a single +library, they simply verify the handle they are passed with +CHECK_HANDLE and return the result. + +\section{API Versioning} + +The KADM5 system is designed to support multiple versions of the KADM5 +API. Presently, two versions exist: KADM5_API_VERSION_1 and +KADM5_API_VERSION_2. The former is equivalant to the initial +OpenVision API, OVSEC_KADM_API_VERSION_1; the latter was created +during the initial integration of the OpenVision system into the MIT +release. + +Implementing a versioned API in C via with both local and RPC access +presents a number of design issues, some of them quite subtle. The +contexts in which versioning considerations must be made include: + +\begin{enumerate} +\item Typedefs, function declarations, and defined constants depend on +the API version a client is written to and must be correct at compile +time. + +\item Each function in the server library must behave according to the +API version specified by the caller at runtime to kadm5_init_*. + +\item The XDR functions used by the RPC layer to transmit function +arguments and results must encode data structures correctly depending +on the API version specified by the client at runtime. + +\item Each function in the client library must behave according to the +API version specified by the caller at runtime to kadm5_init_*. + +\item The RPC server (kadmind) must accept calls from a client using +any supported API version, and must then invoke the function in the +server library corresponding to the RPC with the API version indicated +by the client caller. + +\item When a first API function is invoked that needs to call a second +function in the API on its own behalf, and that second API function's +behavior depends on the API version specified, the first API function +must either be prepared to call the second API function at whatever +version its caller specifies or have a means of always calling the +second API function at a pre-determined version. +\end{enumerate} + +The following functions describe how each context is handled. + +\subsection{Designing for future compatibility} + +Any code whose behavior depends on the API version should be written +so as to be compatible with future, currently unknown API versions on +the grounds that any particuarly piece of API behavior will most +likely not change between versions. For example, in the current +system, the code is not written as ``if this is VERSION_1, do X, else +if this is VERSION_2, do Y''; instead, it is written as ``if this is +VERSION_1, do X; else, do Y.'' The former will require additional +work when VERSION_3 is defined, even if ``do Y'' is still the correct +action, whereas the latter will work without modification in that +case. + +\subsection{Header file declarations} + +Typedefs, defined constants and macros, and function declarations may +change between versions. A client is always written to a single, +specific API version, and thus expects the header files to define +everything according to that API. Failure of a header file to define +values correctly will result in either compiler warnings (e.g. if the +pointer type of a function argument changes) or fatal errors (e.g. if +the number of arguments to a function changes, or the fields of a +structure change). For example, in VERSION_1, kadm5_get_policy took a +pointer to a pointer to a structure, and in VERSION_2 it takes a +pointer to a structure; that would generate a warning if not correct. +In VERSION_1, kadm5_randkey_principal accepted three arguments but in +VERSION_2 accepts four; that would generate a fatal error. + +The header file defines everything correctly based on the value of the +USE_KADM5_API_VERSION constant. The constant can be assigned to an +integer corresponding to any supported API version, and defaults to +the newest version. The header files then simply use an \#ifdef to +include the right definitions: +% +\begin{verbatim} +#if USE_KADM5_API_VERSION == 1 +kadm5_ret_t kadm5_get_principal(void *server_handle, + krb5_principal principal, + kadm5_principal_ent_t *ent); +#else +kadm5_ret_t kadm5_get_principal(void *server_handle, + krb5_principal principal, + kadm5_principal_ent_t ent, + long mask); +#endif +\end{verbatim} + +\subsection{Server library functions} + +Server library functions must know how many and what type of arguments +to expect, and must operate on those arguments correctly, based on the +API version with which they are invoked. The API version is contained +in the handle that is alwasy passed as their first argument, generated +by kadm5_init_* (to which the client specified the API version to use +at run-time). + +In general, it is probably unsafe for a compiled function in a library +to re-interpret the number and type of defined arguments at run-time +since the calling conventions may not allow it; for example, a +function whose first argument was a short in one version and a pointer +in the next might fail if it simply typed-casted the argument. In +that case, the function would have to written to take variable +arguments (i.e. use $<$stdarg.h$>$) and extract them from the stack +based on the API version. Alternatively, a separate function for each +API version could be defined, and $<$kadm5/admin.h$>$ could be written +to \v{\#define} the exported function name based on the value of +USE_KADM5_API_VERSION. + +In the current system, it turns out, that isn't necessary, and future +implementors should take try to ensure that no version has semantics +that will cause such problems in the future. All the functions in +KADM5 that have different arguments or results between VERSION_1 and +VERSION_2 do so simply by type-casting their arguments to the +appropriate version and then have separate code paths to handle each +one correctly. kadm5_get_principal, in svr_principal.c, is a good +example. In VERSION_1, it took the address of a pointer to a +kadm5_principal_ent_t to fill in with a pointer to allocated memory; +in VERSION_2, it takes a pointer to a structure to fill in, and a mask +of which fields in that structure should be filled in. Also, the +contents of the kadm5_principal_ent_t changed slightly between the two +versions. kadm5_get_principal handles versioning as follows +(following along in the source code will be helpful): + +\begin{enumerate} +\item If VERSION_1, it saves away its entry argument (address of a +pointer to a structure) and resets its value to contain the address of +a locally stack-allocated entry structure; this allows most of the +function to written once, in terms of VERSION_2 semantics. If +VERSION_1, it also resets its mask argument to be +KADM5_PRINCIPAL_NORMAL_MASK, because that is the equivalent to +VERSION_1 behavior, which was to return all the fields of the +structure. + +\item The bulk of the function is implemented as expected for +VERSION_2. + +\item The new fields in the VERSION_2 entry structure are assigned +inside a block that is only execute if the caller specified +VERSION_2. This saves a little time for a VERSION_1 caller. + +\item After the entry structure is filled, the function checks again +if it was called as VERSION_1. If so, it allocates a new +kadm5_principal_ent_t_v1 structure (which is conveniently defined in +the header file) with malloc, copies the appropriate values from the +entry structure into the VERSION_1 entry structure, and then writes +the address of the newly allocated memory into address specified by +the original entry argument which it had previously saved away. +\end{enumerate} + +There is another complication involved in a function re-interpreting +the number of arguments it receives at compile time---it cannot assign +any value to an argument for which the client did not pass a value. +For example, a VERSION_1 client only passes three arguments to +kadm5_get_principal. If the implementation of kadm5_get_principal +notices that the caller is VERSION_1 and therefore assigns its fourth +argument, mask, to a value that mimics the VERSION_1 behavior, it may +inadvertently overwrite data on its caller's stack. This problem can +be avoided simply by using a true local variable in such cases, +instead of treating an unpassed argument as a local variable. + +\subsection{XDR functions} + +The XDR functions used to encode function arguments and results must +know how to encode the data for any API version. This is important +both so that all the data gets correctly transmitted and so that +protocol compatibility between clients or servers using the new +library but an old API version is maintained; specific, new kadmind +servers should support old kadm5 clients. + +The signature of all XDR functions is strictly defined: they take the +address of an XDR function and the address of the data object to be +encoded or decoded. It is thus impossible to provide the API version +of the data object as an additional argument to an XDR function. +There are two other means to convey the information, storing the API +version to use as a field in the data object itself and creating +separate XDR functions to handle each different version of the data +object, and both of them are used in KADM5. + +In the client library, each kadm5 function collects its arguments into +a single structure to be passed by the RPC; similarly, it expects all +of the results to come back as a single structure from the RPC that it +will then decode back into its constituent pieces (these are the +standard ONC RPC semantics). In order to pass versioning information +to the XDR functions, each function argument and result datatype has a +filed to store the API version. For example, consider +kadm5_get_principal's structures: +% +\begin{verbatim} +struct gprinc_arg { + krb5_ui_4 api_version; + krb5_principal princ; + long mask; +}; +typedef struct gprinc_arg gprinc_arg; +bool_t xdr_gprinc_arg(); + +struct gprinc_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + kadm5_principal_ent_rec rec; +}; +typedef struct gprinc_ret gprinc_ret; +bool_t xdr_gprinc_ret(); +\end{verbatim} +% +kadm5_get_principal (in client_principal.c) assigns the api_version +field of the gprinc_arg to the version specified by its caller, +assigns the princ field based on its arguments, and assigns the mask +field from its argument if the caller specified VERSION_2. It then +calls the RPC function clnt_call, specifying the XDR functions +xdr_gprinc_arg and xdr_gprinc_ret to handle the arguments and results. + +xdr_gprinc_arg is invoked with a pointer to the gprinc_arg structure +just described. It first encodes the api_version field; this allows +the server to know what to expect. It then encodes the krb5_principal +structure and, if api_version is VERSION_2, the mask. If api_version +is not VERSION_2, it does not encode {\it anything} in place of the +mask, because an old VERSION_1 server will not expect any other data +to arrive on the wire there. + +The server performs the kadm5_get_principal call and returns its +results in an XDR encoded gprinc_ret structure. clnt_call, which has +been blocking until the results arrived, invokes xdr_gprinc_ret with a +pointer to the encoded data for it to decode. xdr_gprinc_ret first +decodes the api_version field, and then the code field since that is +present in all versions to date. The kadm5_principal_ent_rec presents +a problem, however. The structure does not itself contain an +api_version field, but the structure is different between the two +versions. Thus, a single XDR function cannot decode both versions of +the structure because it will have no way to decide which version to +expect. The solution is to have two functions, +kadm5_principal_ent_rec_v1 and kadm5_principal_ent_rec, which always +decode according to VERSION_1 or VERSION_2, respectively. gprinc_ret +knows which one to invoke because it has the api_version field +returned by the server (which is always the same as that specified by +the client in the gpring_arg). + +In hindsight, it probably would have been better to encode the API +version of all structures directly in a version field in the structure +itself; then multiple XDR functions for a single data type wouldn't be +necessary, and the data objects would stand complete on their own. +This can be added in a future API version if desired. + +\subsection{Client library functions} + +Just as with server library functions, client library functions must +be able to interpret their arguments and provide result according to +the API version specified by the caller. Again, kadm5_get_principal +(in client_principal.c) is a good example. The gprinc_ret structure +that it gets back from clnt_call contains a kadm5_principal_ent_rec or +a kadm5_principal_ent_rec_v1 (the logic is simplified somewhat because +the VERSION_2 structure only has new fields added on the end). If +kadm5_get_principal was invoked with VERSION_2, that structure should +be copied into the pointer provided as the entry argument; if it was +invoked with VERSION_1, however, the structure should be copied into +allocated memory whose address is then written into the pointer +provided by the entry argument. Client library functions make this +determination based on the API version specified in the provided +handle, just like server library functions do. + +\subsection{Admin server stubs} + +When an RPC call arrives at the server, the RPC layer authenticates +the call using the GSS-API, decodes the arguments into their +single-structure form (ie: a gprinc_arg) and dispatches the call to a +stub function in the server (in server_stubs.c). The stub function +first checks the caller's authorization to invoke the function and, if +authorized, calls the kadm5 function corresponding to the RPC function +with the arguments specified in the single-structure argument. + +Once again, kadm5_get_principal is a good example for the issues +involved. The contents of the gprinc_arg given to the stub +(get_principal_1) depends on the API version the caller on the client +side specified; that version is available to the server in the +api_version field of the gprinc_arg. When the server calls +kadm5_get_principal in the server library, it must give that function +an API handle that contains the API version requested by the client; +otherwise the function semantics might not be correct. One +possibility would be for the server to call kadm5_init for each client +request, specifing the client's API version number and thus generating +an API handle with the correct version, but that would be +prohibitively inefficient. Instead, the server dips down in the +server library's internal abstraction barrier, using the function +new_server_handle to cons up a server handle based on the server's own +global_server_handle but using the API version specified by the +client. The server then passes the newly generated handle to +kadm5_get_principal, ensuring the right behavior, and creates the +gprinc_ret structure in a manner similar to that described above. + +Although new_server_handle solves the problem of providing the server +with an API handle containing the right API version number, it does +not solve another problem: that a single source file, server_stubs.c, +needs to be able to invoke functions with arguments appropriate for +multiple API versions. If the client specifies VERSION_1, for +example, the server must invoke kadm5_get_principal with three +arguments, but if the client specifies VERSION_2 the server must +invoke kadm5_get_principal with four arguments. The compiler will not +allow this inconsistency. The server defines wrapper functions in a +separate source file that match the old version, and the separate +source file is compiled with USE_KADM5_API_VERSION set to the old +version; see kadm5_get_principal_v1 in server_glue_v1.c. The server +then calls the correct variant of kadm5_get_principal_* based on the +API version and puts the return values into the gprinc_ret in a manner +similar to that described above. + +Neither of these solutions are necessarily correct. new_server_handle +violates the server library's abstraction barrier and is at best a +kludge; the server library should probably export a function to +provide this behavior without violating the abstraction; +alternatively, the librar should be modified so that having the server +call kadm5_init for each client RPC request would not be too +inefficient. The glue functions in server_glue_v1.c really are not +necessary, because the server stubs could always just pass dummy +arguments for the extra arguments; after all, the glue functions pass +{\it nothing} for the extra arguments, so they just end up as stack +garbage anyway. + +Another alternative to the new_server_handle problem is to have the +server always invoke server library functions at a single API version, +and then have the stubs take care of converting the function arguments +and results back into the form expected by the caller. In general, +however, this might require the stubs to duplicate substantial logic +already present in the server library and further violate the server +library's abstraction barrier. + +\subsection{KADM5 self-reference} + +Some kadm5 functions call other kadm5 functions ``on their own +behalf'' to perform functionality that is necessary but that does not +directly affect what the client sees. For example, +kadm5_chpass_principal has to enforce password policies; thus, it +needs to call kadm5_get_principal and, if the principal has a policy, +kadm5_get_policy and kadm5_modify_principal in the process of changing +a principal's password. This leads to a complication: what API handle +should kadm5_chpass_principal pass to the other kadm5 functions it +calls? + +The ``obvious,'' but wrong, answer is that it should pass the handle +it was given by its caller. The caller may provide an API handle +specifying any valid API version. Although the semantics of +kadm5_chpass_principal did not change between VERSION_1 and VERSION_2, +the declarations of both kadm5_get_principal and kadm5_get_policy +did. Thus, to use the caller's API handle, kadm5_chpass_principal +will have to have a separate code path for each API version, even +though it itself did not change bewteen versions, and duplicate a lot +of logic found elsewhere in the library. + +Instead, each API handle contains a ``local-use handle,'' or lhandle, +that kadm5 functions should use to call other kadm5 functions. For +example, the client-side library's handle structure is: +% +\begin{verbatim} +typedef struct _kadm5_server_handle_t { + krb5_ui_4 magic_number; + krb5_ui_4 struct_version; + krb5_ui_4 api_version; + char * cache_name; + int destroy_cache; + CLIENT * clnt; + krb5_context context; + kadm5_config_params params; + struct _kadm5_server_handle_t *lhandle; +} kadm5_server_handle_rec, *kadm5_server_handle_t; +\end{verbatim} +% +The lhandle field is allocated automatically when the handle is +created. All of the fields of the API handle that are accessed +outside kadm5_init are also duplicated in the lhandle; however, the +api_version field of the lhandle is always set to a {\it constant} +value, regardless of the API version specified by the caller to +kadm5_init. In the current implementation, the lhandle's api_version +is always VERSION_2. + +By passing the caller's handle's lhandle to recursively called kadm5 +functions, a kadm5 function is assured of invoking the second kadm5 +function with a known API version. Additionally, the lhandle's +lhandle field points back to the lhandle, in case kadm5 functions call +themselves more than one level deep; handle$->$lhandle always points +to the same lhandle, no matter how many times the indirection is +performed. + +This scheme might break down if a kadm5 function has to call another +kadm5 function to perform operations that they client will see and for +its own benefit, since the semantics of the recursively-called kadm5 +function may depend on the API version specified and the client may be +depending on a particular version's behavior. Future implementators +should avoid creating a situation in which this is possible. + +\section{Server Main} + +The admin server starts by trapping all fatal signals and directing +them to a cleanup-and-exit function. It then creates and exports the +RPC interface and enters its main loop. + +The main loop dispatches all incoming requests to the RPC mechanism. +In a previous version, after 15 seconds of inactivity, the server +closed all open databases; each database was be automatically reopened +by the API function implementations as necessary. That behavior +existed to protect against loss of written data before the process +exited. The current database libraries write all changes out to disk +immediately, however, so this behavior is no longer required or +performed. + +\section{Remote Procedure Calls} + +The RPC for the Admin system will be based on ONC RPC. ONC RPC is +used because it is a well-known, portable RPC mechanism. The +underlying external data representation (xdr) mechanisms for wire +encapsulation are well-known and extensible. Authentication to the +admin server and encryption of all RPC functional arguments and +results are be handled via the AUTH_GSSAPI authentication flavor of +ONC RPC. + +\section{Database Record Types} +\label{sec:db-types} + +\subsection{Admin Principal, osa_princ_ent_t} + +The admin principal database stores records of the type +osa_princ_ent_t (declared in $<$kadm5/adb.h$>$), which is the +subset of the kadm5_principal_ent_t structure that is not stored +in the Kerberos database plus the necessary bookkeeping information. +The records are keyed by the ASCII representation of the principal's +name, including the trailing NULL. + +\begin{verbatim} +typedef struct _osa_pw_hist_t { + int n_key_data; + krb5_key_data *key_data; +} osa_pw_hist_ent, *osa_pw_hist_t; + +typedef struct _osa_princ_ent_t { + char * policy; + u_int32 aux_attributes; + + unsigned int old_key_len; + unsigned int old_key_next; + krb5_kvno admin_history_kvno; + osa_pw_hist_ent *old_keys; + + + u_int32 num_old_keys; + u_int32 next_old_key; + krb5_kvno admin_history_kvno; + osa_pw_hist_ent *old_keys; +} osa_princ_ent_rec, *osa_princ_ent_t; +\end{verbatim} + +The fields that are different from kadm5_principal_ent_t are: + +\begin{description} +\item[num_old_keys] The number of previous keys in the old_keys array. +This value must be 0 $\le$ num_old_keys $<$ pw_history_num. + +\item[old_key_next] The index into old_keys where the next key should +be inserted. This value must be 0 $\le$ old_key_next $\le$ +num_old_keys. + +\item[admin_history_kvno] The key version number of the kadmin/history +principal's key used to encrypt the values in old_keys. If the server +library finds that kadmin/history's kvno is different from the value +in this field, it returns KADM5_BAD_HIST_KEY. + +\item[old_keys] The array of the principal's previous passwords, each +encrypted in the kadmin/history key. There are num_old_keys +elements. Each ``password'' in the array is itself an array of +n_key_data krb5_key_data structures, one for each keysalt type the +password was encoded in. +\end{description} + +\subsection{Policy, osa_policy_ent_t} + +The policy database stores records of the type osa_policy_ent_t +(declared in $<$kadm5/adb.h$>$) , which is all of +kadm5_policy_ent_t plus necessary bookkeeping information. The +records are keyed by the policy name. + +\begin{verbatim} +typedef struct _osa_policy_ent_t { + char *policy; + + u_int32 pw_min_life; + u_int32 pw_max_life; + u_int32 pw_min_length; + u_int32 pw_min_classes; + u_int32 pw_history_num; + + u_int32 refcnt; +} osa_policy_ent_rec, *osa_policy_ent_t; +\end{verbatim} + +\subsection{Kerberos, krb5_db_entry} + +The Kerberos database stores records of type krb5_db_entry, which is +defined in the $<$k5-int.h$>$ header file. The semantics of each +field are defined in the libkdb functional specification. + +\section{Database Access Methods} + +\subsection{Principal and Policy Databases} + +This section describes the database abstraction used for the admin +policy database; the admin principal database used to be treated in +the same manner but is now handled more directly as krb5_tl_data; +thus, nothing in this section applies to it any more. Since both +databases export equivalent functionality, the API is only described +once. The character T is used to represent both ``princ'' and +``policy''. The location of the principal database is defined by the +configuration parameters given to any of the kadm5_init functions in +the server library. + +Note that this is {\it only} a database abstraction. All functional +intelligence, such as maintaining policy reference counts or sanity +checking, must be implemented above this layer. + +Prototypes for the osa functions are supplied in +$<$kadm5/adb.h$>$. The routines are defined in libkadm5srv.a. They +require linking with the Berkely DB library. + +\subsubsection{Error codes} + +The database routines use com_err for error codes. The error code +table name is ``adb'' and the offsets are the same as the order +presented here. The error table header file is +$<$kadm5/adb_err.h$>$. Callers of the OSA routines should first call +init_adb_err_tbl() to initialize the database table. + +\begin{description} +\item[OSA_ADB_OK] Operation successful. +\item[OSA_ADB_FAILURE] General failure. +\item[OSA_ADB_DUP] Operation would create a duplicate database entry. +\item[OSA_ADB_NOENT] Named entry not in database. +\item[OSA_ADB_BAD_PRINC] The krb5_principal structure is invalid. +\item[OSA_ADB_BAD_POLICY] The specified policy name is invalid. +\item[OSA_ADB_XDR_FAILURE] The principal or policy structure cannot be +encoded for storage. +\item[OSA_ADB_BADLOCKMODE] Bad lock mode specified. +\item[OSA_ADB_CANTLOCK_DB] Cannot lock database, presumably because it +is already locked. +\item[OSA_ADB_NOTLOCKED] Internal error, database not locked when +unlock is called. +\item[OSA_ADB_NOLOCKFILE] KADM5 administration database lock file missing. +\end{description} + +Database functions can also return system errors. Unless otherwise +specified, database functions return OSA_ADB_OK. + +\subsubsection{Locking} + +All of the osa_adb functions except open and close lock and unlock the +database to prevent concurrency collisions. The overall locking +algorithm is as follows: + +\begin{enumerate} +\item osa_adb_open_T calls osa_adb_init_db to allocate the osa_adb_T_t +structure and open the locking file for further use. + +\item Each osa_adb functions locks the locking file and opens the +appropriate database with osa_adb_open_and_lock, performs its action, +and then closes the database and unlocks the locking file with +osa_adb_close_and_unlock. + +\item osa_adb_close_T calls osa_adb_fini_db to close the locking file +and deallocate the db structure. +\end{enumerate} + +Functions which modify the database acquire an exclusive lock, others +acqure a shared lock. osa_adb_iter_T acquires an exclusive lock for +safety but as stated below consequences of modifying the database in +the iteration function are undefined. + +\subsubsection{Function descriptions} + +\begin{verbatim} +osa_adb_ret_t osa_adb_create_T_db(kadm5_config_params *params) +\end{verbatim} +% +Create the database and lockfile specified in params. The database +must not already exist, or EEXIST is returned. The lock file is only +created after the database file has been created successfully. + +\begin{verbatim} +osa_adb_ret_t osa_adb_rename_T_db(kadm5_config_params *fromparams, + kadm5_config_params *toparams) +\end{verbatim} +% +Rename the database named by fromparams to that named by toparams. +The fromparams database must already exist; the toparams database may +exist or not. When the function returns, the database named by +fromparams no longer exists, and toparams has been overwritten with +fromparams. This function acquires a permanent lock on both databases +for the duration of its operation, so a failure is likely to leave the +databases unusable. + +\begin{verbatim} +osa_adb_ret_t osa_adb_destroy_policy_db(kadm5_config_params *params) +\end{verbatim} +% +Destroy the database named by params. The database file and lock file +are deleted. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_open_T(osa_adb_T_t *db, char *filename); +\end{verbatim} +% +Open the database named filename. Returns OSA_ADB_NOLOCKFILE if the +database does not exist or if the lock file is missing. The database +is not actually opened in the operating-system file sense until a lock +is acquire. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_close_T(osa_adb_T_t db); +\end{verbatim} +% +Release all shared or exclusive locks (on BOTH databases, since they +use the same lock file) and close the database. + +It is an error to exit while a permanent lock is held; +OSA_ADB_NOLOCKFILE is returned in this case. + +\begin{verbatim} +osa_adb_ret_t osa_adb_get_lock(osa_adb_T_t db, int mode) +\end{verbatim} + +Acquire a lock on the administration databases; note that both +databases are locked simultaneously by a single call. The mode +argument can be OSA_ADB_SHARED, OSA_ADB_EXCLUSIVE, or +OSA_ADB_PERMANENT. The first two and the third are really disjoint +locking semantics and should not be interleaved. + +Shared and exclusive locks have the usual semantics, and a program can +upgrade a shared lock to an exclusive lock by calling the function +again. A reference count of open locks is maintained by this function +and osa_adb_release_lock so the functions can be called multiple +times; the actual lock is not released until the final +osa_adb_release_lock. Note, however, that once a lock is upgraded +from shared to exclusive, or from exclusive to permanent, it is not +downgraded again until released completely. In other words, +get_lock(SHARED), get_lock(EXCLUSIVE), release_lock() leaves the +process with an exclusive lock with a reference count of one. An +attempt to get a shared or exclusive lock that conflicts with another +process results in the OSA_ADB_CANLOCK_DB error code. + +This function and osa_adb_release_lock are called automatically as +needed by all other osa_adb functions to acquire shared and exclusive +locks and so are not normally needed. They can be used explicitly by +a program that wants to perform multiple osa_adb functions within the +context of a single lock. + +Acquiring an OSA_ADB_PERMANENT lock is different. A permanent lock +consists of first acquiring an exclusive lock and then {\it deleting +the lock file}. Any subsequent attempt to acquire a lock by a +different process will fail with OSA_ADB_NOLOCKFILE instead of +OSA_ADB_CANTLOCK_DB (attempts in the same process will ``succeed'' +because only the reference count gets incremented). The lock file is +recreated by osa_adb_release_lock when the last pending lock is released. + +The purpose of a permanent lock is to absolutely ensure that the +database remain locked during non-atomic operations. If the locking +process dies while holding a permanent lock, all subsequent osa_adb +operations will fail, even through a system reboot. This is useful, +for example, for ovsec_adm_import which creates both new database +files in a temporary location and renames them into place. If both +renames do not fully complete the database will probably be +inconsistent and everything should stop working until an administrator +can clean it up. + +\begin{verbatim} +osa_adb_ret_t osa_adb_release_lock(osa_adb_T_t db) +\end{verbatim} + +Releases a shared, exclusive, or permanent lock acquired with +osa_adb_get_lock, or just decrements the reference count if multiple +locks are held. When a permanent lock is released, the lock file is +re-created. + +All of a process' shared or exclusive database locks are released when +the process terminates. A permanent lock is {\it not} released when +the process exits (although the exclusive lock it begins with +obviously is). + +\begin{verbatim} +osa_adb_ret_t +osa_adb_create_T(osa_adb_T_t db, osa_T_ent_t entry); +\end{verbatim} +% +Adds the entry to the database. All fields are defined. Returns +OSA_ADB_DUP if it already exists. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_destroy_T(osa_adb_T_t db, osa_T_t name); +\end{verbatim} + +Removes the named entry from the database. Returns OSA_ADB_NOENT if +it does not exist. + +\begin{verbatim} +osa_adb_ret_t +osa_adb_get_T(osa_adb_T_t db, osa_T_t name, + osa_princ_ent_t *entry); +\end{verbatim} + +Looks up the named entry in the db, and returns it in *entry in +allocated storage that must be freed with osa_adb_free_T. Returns +OSA_ADB_NOENT if name does not exist, OSA_ADB_MEM if memory cannot be +allocated. + +\begin{verbatim} +osa_adb_ret_t +osadb_adb_put_T(osa_adb_T_t db, osa_T_ent_t entry); +\end{verbatim} + +Modifies the existing entry named in entry. All fields must be filled +in. Returns OSA_DB_NOENT if the named entry does not exist. Note +that this cannot be used to rename an entry; rename is implemented by +deleting the old name and creating the new one (NOT ATOMIC!). + +\begin{verbatim} +void osa_adb_free_T(osa_T_ent_t); +\end{verbatim} + +Frees the memory associated with an osa_T_ent_t allocated by +osa_adb_get_T. + +\begin{verbatim} +typedef osa_adb_ret_t (*osa_adb_iter_T_func)(void *data, + osa_T_ent_t entry); + +osa_adb_ret_t osa_adb_iter_T(osa_adb_T_t db, osa_adb_iter_T_func func, + void *data); +\end{verbatim} + +Iterates over every entry in the database. For each entry ent in the +database db, the function (*func)(data, ent) is called. If func +returns an error code, osa_adb_iter_T returns an error code. If all +invokations of func return OSA_ADB_OK, osa_adb_iter_T returns +OSA_ADB_OK. The function func is permitted to access the database, +but the consequences of modifying the database during the iteration +are undefined. + +\subsection{Kerberos Database} + +Kerberos uses the libkdb interface to store krb5_db_entry records. It +can be accessed and modified in parallel with the Kerberos server, +using functions that are defined inside the KDC and the libkdb.a. The +libkdb interface is defined in the libkdb functional specifications. + +\subsubsection{Initialization and Key Access} + +Keys stored in the Kerberos database are encrypted in the Kerberos +master key. The admin server will therefore have to acquire the key +before it can perform any key-changing operations, and will have to +decrypt and encrypt the keys retrieved from and placed into the +database via krb5_db_get_principal and _put_principal. This section +describes the internal admin server API that will be used to perform +these functions. + +\begin{verbatim} +krb5_principal master_princ; +krb5_encrypt_block master_encblock; +krb5_keyblock master_keyblock; + +void kdc_init_master() +\end{verbatim} + +kdc_init_master opens the database and acquires the master key. It +also sets the global variables master_princ, master_encblock, and +master_keyblock: + +\begin{itemize} +\item master_princ is set to the name of the Kerberos master principal +(\v{K/M@REALM}). + +\item master_encblock is something I have no idea about. + +\item master_keyblock is the Kerberos master key +\end{itemize} + +\begin{verbatim} +krb5_error_code kdb_get_entry_and_key(krb5_principal principal, + krb5_db_entry *entry, + krb5_keyblock *key) +\end{verbatim} + +kdb_get_entry_and_key retrieves the named principal's entry from the +database in entry, and decrypts its key into key. The caller must +free entry with krb5_dbm_db_free_principal and free key-$>$contents with +free.\footnote{The caller should also \v{memset(key-$>$contents, 0, +key-$>$length)}. There should be a function krb5_free_keyblock_contents +for this, but there is not.} + +\begin{verbatim} +krb5_error_code kdb_put_entry_pw(krb5_db_entry *entry, char *pw) +\end{verbatim} + +kdb_put_entry_pw stores entry in the database. All the entry values +must already be set; this function does not change any of them except +the key. pw, the NULL-terminated password string, is converted to a +key using string-to-key with the salt type specified in +entry-$>$salt_type.\footnote{The salt_type should be set based on the +command line arguments to the kadmin server (see the ``Command Line'' +section of the functional specification).} + +\section{Admin Principal and Policy Database Implementation} + +The admin principal and policy databases will each be stored in a +single hash table, implemented by the Berkeley 4.4BSD db library. +Each record will consist of an entire osa_T_ent_t. The key into the +hash table is the entry name (for principals, the ASCII representation +of the name). The value is the T entry structure. Since the key and +data must be self-contained, with no pointers, the Sun xdr mechanisms +will be used to marshal and unmarshal data in the database. + +The server in the first release will be single-threaded in that a +request will run to completion (or error) before the next will run, +but multiple connections will be allowed simultaneously. + +\section{ACLs, acl_check} + +The ACL mechanism described in the ``Authorization ACLs'' section of +the functional specifications will be implemented by the acl_check +function. + +\begin{verbatim} +enum access_t { + ACCESS_DENIED = 0, + ACCESS_OK = 1, +}; + +enum access_t acl_check(krb5_principal princ, char *priv); +\end{verbatim} + +The priv argument must be one of ``get'', ``add'', ``delete'', or +``modify''. acl_check returns 1 if the principal princ has the named +privilege, 0 if it does not. + +\section{Function Details} + +This section discusses specific design issues for Admin API functions +that are not addresed by the functional specifications. + +\subsection{kadm5_create_principal} + +If the named principal exists in either the Kerberos or admin +principal database, but not both, return KADM5_BAD_DB. + +The principal's initial key is not stored in the key history array at +creation time. + +\subsection{kadm5_delete_principal} + +If the named principal exists in either the Kerberos or admin +principal database, but not both, return KADM5_BAD_DB. + +\subsection{kadm5_modify_principal} + +If the named principal exists in either the Kerberos or admin +principal database, but not both, return KADM5_BAD_DB. + +If pw_history_num changes and the new value $n$ is smaller than the +current value of num_old_keys, old_keys should end up with the $n$ +most recent keys; these are found by counting backwards $n$ elements +in old_keys from old_key_next. old_key_nexts should then be reset to +0, the oldest of the saved keys, and num_old_keys set to $n$, the +new actual number of old keys in the array. + +\subsection{kadm5_chpass_principal, randkey_principal} + +The algorithm for determining whether a password is in the principal's +key history is complicated by the use of the kadmin/history \k{h} +encrypting key. + +\begin{enumerate} +\item For kadm5_chpass_principal, convert the password to a key +using string-to-key and the salt method specified by the command line +arguments. + +\item If the POLICY bit is set and pw_history_num is not zero, check +if the new key is in the history. +\begin{enumerate} +\item Retrieve the principal's current key and decrypt it with \k{M}. +If it is the same as the new key, return KADM5_PASS_REUSE. +\item Retrieve the kadmin/history key \k{h} and decrypt it with \k{M}. +\item Encrypt the principal's new key in \k{h}. +\item If the principal's new key encrypted in \k{h} is in old_keys, +return KADM5_PASS_REUSE. +\item Encrypt the principal's current key in \k{h} and store it in +old_keys. +\item Erase the memory containing \k{h}. +\end{enumerate} + +\item Encrypt the principal's new key in \k{M} and store it in the +database. +\item Erase the memory containing \k{M}. +\end{enumerate} + +To store the an encrypted key in old_keys, insert it as the +old_key_next element of old_keys, and increment old_key_next by one +modulo pw_history_num. + +\subsection{kadm5_get_principal} + +If the named principal exists in either the Kerberos or admin +principal database, but not both, return KADM5_BAD_DB. + +\end{document} diff --git a/mechglue/doc/kadm5/api-unit-test.tex b/mechglue/doc/kadm5/api-unit-test.tex new file mode 100644 index 000000000..3e0eb503e --- /dev/null +++ b/mechglue/doc/kadm5/api-unit-test.tex @@ -0,0 +1,2679 @@ +\documentstyle[times,fullpage,rcsid]{article} + +\rcs$Id$ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Make _ actually generate an _, and allow line-breaking after it. +\let\underscore=\_ +\catcode`_=13 +\def_{\underscore\penalty75\relax} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand{\test}[1]{\begin{description} +\setlength{\itemsep}{0pt} +#1 +\end{description} + +} + +\newcommand{\numtest}[2]{\begin{description} +\setlength{\itemsep}{0pt} +\Number{#1} +#2 +\end{description} + +} + +\newcommand{\Number}[1]{\item[Number:] #1} +\newcommand{\Reason}[1]{\item[Reason:] #1} +\newcommand{\Expected}[1]{\item[Expected:] #1} +\newcommand{\Conditions}[1]{\item[Conditions:] #1} +\newcommand{\Priority}[1]{\item[Priority:] #1} +\newcommand{\Status}[1]{\item[Status:] #1} +\newcommand{\Vtwonote}[1]{\item[V2 note:] #1} +\newcommand{\Version}[1]{\item[Version:] #1} +\newcommand{\Call}[1]{} +%\newcommand{\Call}[1]{\item[Call:] #1} +%\newcommand{\Number}[1]{} +%\newcommand{\Reason}[1]{} +%\newcommand{\Expected}[1]{} +%\newcommand{\Conditions}[1]{} +%\newcommand{\Priority}[1]{} + +\title{KADM5 Admin API\\ +Unit Test Description\footnote{\rcsId}} +\author{Jonathan I. Kamens} + +\begin{document} + +\maketitle + +%\tableofcontents + +\section{Introduction} + +The following is a description of a black-box unit test of the KADM5 +API. Each API function is listed, followed by the tests that shoud be +performed on it. + +The tests described here are based on the ``Kerberos Administration +System KADM5 API Functional Specifications'', revision 1.68. This +document was originally written based on the OpenVision API functional +specifications, version 1.41, dated August 18, 1994, and many +indications of the original version remain. + +All tests which test for success should verify, using some means other +than the return value of the function being tested, that the requested +operation was successfully performed. For example: for init, test +that other operations can be performed after init; for destroy, test +that other operations can't be performed after destroy; for modify +functions, verify that all modifications to the database which should +have taken place did, and that the new, modified data is in effect; +for get operations, verify that the data retrieved is the data that +should actually be in the database. + +The tests would be better if they compared the actual contents of the +database before and after each test, rather than relying on the KADM5 +API to report the results of changes. + +Similarly, all tests which test for failure should verify that the +no component of the requested operation took place. For example: if +init fails, other operations should not work. If a modify fails, all +data in the database should be the same as it was before the attempt +to modify, and the old data should still be what is enforced. +Furthermore, tests which test for failure should verify that the +failure code returned is correct for the specific failure condition +tested. + +Most of the tests listed below should be run twice -- once locally on +the server after linking against the server API library, and once +talking to the server via authenticated Sun RPC after linking against +the client API library. Tests which should only be run locally or via +RPC are labelled with a ``local'' or ``RPC''. + +Furthermore, in addition to the tests labelled below, a test should be +implemented to verify that a client can't perform operations on the +server through the client API library when it's linked against +standard Sun RPC instead of OpenV*Secure's authenticated Sun RPC. +This will require a client with a modified version of ovsec_kadm_init +which doesn't call auth_gssapi_create. This client should call this +modified ovsec_kadm_init and then call some other admin API function, +specifying arguments to both functions that would work if the +authenticated Sun RPC had been used, but shouldn't if authentication +wasn't used. The test should verify that the API function call after +the init doesn't succeed. + +There is also another test to see if all the API functions handle getting an +invalid server handle correctly. This is not done as part of the tests that +are run through the TCL program cause the TCL program has no way of +invalidating a server handle. So there is a program that calls init and +changes the handle magic number, and then attempts to call each API function +with the corrupted server handle. + +A number of tests have been added or changed to correspond with KADM5 +API version 2. Tests which are only performed against the newer +version specify the version number in the test description. + +\section{ovsec_kadm_init} + +\numtest{1}{ +\Reason{An empty string realm is rejected.} +\Status{Implemented} +\Vtwonote{The empty string is now passed as the realm field of the +parameters structure.} +} + +\numtest{2}{ +\Reason{A realm containing invalid characters is rejected.} +\Status{Implemented} +\Vtwonote{The invalid character is now passed as the realm field of the +parameters structure.} +} + +\numtest{2.5}{ +\Reason{A non-existent realm is rejected.} +\Status{Implemented} +\Vtwonote{The non-existent realm is now passed as the realm field of the +parameters structure.} +} + +\numtest{3}{ +\Reason{A bad service name representing an existing principal + (different from the client principal) is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{4}{ +\Reason{A bad service name representing a non-existent + principal is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{5}{ +\Reason{A bad service name identical to the (existing) client + name is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{6}{ +\Reason{A null password causes password prompting.} +\Status{Implemented} +} + +\numtest{7}{ +\Reason{An empty-string causes password prompting} +\Status{Implemented} +} + +\numtest{8}{ +\Reason{An incorrect password which is the password of another + user is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{9}{ +\Reason{An incorrect password which isn't the password of any + user is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{10}{ +\Reason{A null client_name is rejected.} +\Status{Implemented} +} + +% Empty string client name is legal. +%\numtest{11}{ +%\Reason{An empty-string client_name is rejected.} +%} + +\numtest{12}{ +\Reason{A client_name referring to a non-existent principal in + the default realm is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{13}{ +\Reason{A client_name referring to a non-existent principal + with the local realm specified explicitly is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{14}{ +\Reason{A client_name referring to a non-existent principal in + a nonexistent realm is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{15}{ +\Reason{A client_name referring to an existing principal in a + nonexistent realm is rejected.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{16}{ +\Reason{Valid invocation.} +\Status{Implemented} +} + +\numtest{17}{ +\Reason{Valid invocation (explicit client realm).} +\Status{Implemented} +} + +\numtest{18}{ +\Reason{Valid invocation (CHANGEPW_SERVICE).} +\Status{Implemented} +} + +\numtest{19}{ +\Reason{Valid invocation (explicit service realm).} +\Status{Implemented} +\Vtwonote{The explicit realm is now passed as the realm field of the +configuration parameters.} +} + +\numtest{20}{ +\Reason{Valid invocation (database access allowed after init).} +\Status{Implemented} +} + +%\numtest{21}{ +%\Reason{Init fails when called twice in a row.} +%\Status{Implemented} +%} + +\numtest{22}{ +\Reason{A null password causes master-key prompting.} +\Conditions{local} +\Status{Implemented} +\Vtwonote{Obsolete.} +} + +\numtest{22.5}{ +\Reason{A empty string password causes master-key prompting.} +\Conditions{local} +\Status{Implemented} +\Vtwonote{Obsolete.} +} + +%\numtest{23}{ +%\Reason{A non-null password causes reading from the kstash.} +%\Conditions{local} +%\Status{Implemented} +%} + +\numtest{24}{ +\Reason{Null service name is ignored in local invocation.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{25}{ +\Reason{Non-null service name is ignored in local invocation.} +\Conditions{local} +\Status{Implemented} +} + +%\numtest{26}{ +%\Reason{Can't do ``get'' operation before calling init.} +%\Status{Implemented} +%} + +%\numtest{27}{ +%\Reason{Can't do ``add'' operation before calling init.} +%\Status{Implemented} +%} + +%\numtest{28}{ +%\Reason{Can't do ``modify'' operation before calling init.} +%\Status{Implemented} +%} + +%\numtest{29}{ +%\Reason{Can't do ``delete'' operation before calling init.} +%\Status{Implemented} +%} + +\numtest{30}{ +\Reason{Can init after failed init attempt.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{31}{ +\Priority{High} +\Reason{Return BAD_STRUCT_VERSION when the mask bits are set to invalid values} +\Status{Implemented} +} + +\numtest{32}{ +\Priority{High} +\Reason{Return BAD_STRUCT_VERSION when the mask bits are not set} +\Status{Implemented} +} + +\numtest{33}{ +\Priority{High} +\Reason{Return OLD_STRUCT_VERSION when attempting to use an old/unsupported + structure version} +\Status{Implemented} +} + +\numtest{34}{ +\Priority{High} +\Reason{Return NEW_STRUCT_VERSION when attempting to use a newer version of + of the structure then what is supported} +\Status{Implemented} +} + +\numtest{35}{ +\Priority{High} +\Reason{Return BAD_API_VERSION when the mask bits are set to invalid values} +\Status{Implemented} +} + +\numtest{36}{ +\Priority{High} +\Reason{Return BAD_API_VERSION when the mask bits are not set} +\Status{Implemented} +} + +\numtest{37}{ +\Priority{High} +\Reason{Return OLD_LIB_API_VERSION when using an old/unsuppored + api version number} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{38}{ +\Priority{High} +\Reason{Return OLD_SERVER_API_VERSION attempting to use an + old/unsupported api version number} +\Conditions{local} +\Status{Implemented} +} + +\numtest{39}{ +\Priority{High} +\Reason{Return NEW_LIB_API_VERSION when using a newer api + version number then supported} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{40}{ +\Priority{High} +\Reason{Return NEW_SERVER_API_VERSION when using a newer api version + number then supported} +\Conditions{local} +\Status{Implemented} +} + +\numtest{41}{ +\Priority{High} +\Reason{Return BAD_XXX_VERSION when the API and the structure + version numbers are reversed} +\Status{Implemented} +} + +\numtest{42}{ +\Priority{High} +\Reason{Succeeds when using valid api and struct version numbers and masks} +\Status{Implemented} +} + +\numtest{43}{ +\Priority{Low} +\Reason{Returns two different server handle when called twice with same info} +} + +\numtest{44}{ +\Priority{Low} +\Reason{Returns two different server handles when called twice with + different info} +} + +\numtest{45}{ +\Priority{Bug fix, secure-install/3390} +\Reason{Returns SECURE_PRINC_MISSING when ADMIN_SERVICE does not +exist.} +\Status{Implemented} +} + +\numtest{46}{ +\Priority{Bug fix, secure-install/3390} +\Reason{Returns SECURE_PRINC_MISSING when CHANGEPW_SERVICE does not +exist.} +\Status{Implemented} +} + +\numtest{100}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the profile field of the configuration parameters, if +set.} +\Status{Implemented} +} + +\numtest{101}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the kadmind_port field of the configuration parameters, +if set.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{102}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the admin_server field of the configuration parameters, +if set with only an admin server name.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{102.5}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the admin_server field of the configuratin parameters, +if set with a host name and port number.} +\Conditions{RPC} +} + +\numtest{103}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the dbname field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{104}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the admin_dbname field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{105}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the admin_lockfile field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{106}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the mkey_from_kbd field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{107}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the stash_file field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{108}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the mkey_name field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{109}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the max_life field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{110}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the max_rlife field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{111}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the expiration field of the configuration parameters, if +set.} +\Status{Implemented} +\Conditions{local} +} + +\numtest{112}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the flags field of the configuration parameters, if +set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{113}{ +\Version{KADM5_API_VERSION_2} +\Reason{Obeys the keysalts and num_keysalts field of the configuration +parameters, if set.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{114}{ +\Version{KADM5_API_VERSION_2} +\Reason{Returns KADM5_BAD_SERVER_PARAMS if any client-only parameters +are specified to server-side init.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{115}{ +\Version{KADM5_API_VERSION_2} +\Reason{Returns KADM5_BAD_CLIENT_PARAMS if any client-only parameters +are specified to server-side init.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{116}{ +\Version{KADM5_API_VERSION_2} +\Reason{Two calls to init with clients having different privileges +succeedes, and both clients maintain their correct privileges.} +\Priority{Bug fix} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{117}{ +\Version{KADM5_API_VERSION_2} +\Reason{The max_life field defaults to value specified in the API +Functional Specification when kdc.conf is unreadable.} +\Priority{Bug fix, krb5-admin/18} +\Conditions{local} +\Status{Implemented} +} + +\numtest{150}{ +\Version{KADM5_API_VERSION_2} +\Reason{init_with_creds works when given an open ccache with a valid +credential for ADMIN_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{151}{ +\Version{KADM5_API_VERSION_2} +\Reason{init_with_creds works when given an open ccache with a valid +credential for CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{152}{ +\Version{KADM5_API_VERSION_2} +\Reason{init_with_creds fails with KRB5_FCC_NOFILE (was + KADM5_GSS_ERROR) when given an open +ccache with no credentials.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{153}{ +\Version{KADM5_API_VERSION_2} +\Reason{init_with_creds fails with KRB5_CC_NOTFOUND (was + KADM5_GSS_ERROR) when given an open +ccache without credentials for ADMIN_SERVICE or CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{154}{ +\Version{KADM5_API_VERSION_2} +\Reason{If the KRB5_KDC_PROFILE environment variable is set to a filename +that does not exist, init fails with ENOENT.} +\Conditions{RPC} +\Status{Implemented} +} + +\section{ovsec_kadm_destroy} + +\numtest{1}{ +\Reason{Valid invocation.} +\Status{Implemented} +} + +%\numtest{2}{ +%\Reason{Valid invocation (``get'' not allowed after destroy).} +%\Status{Implemented} +%} + +%\numtest{3}{ +%\Reason{Valid invocation (``add'' not allowed after destroy).} +%\Status{Implemented} +%} + +%\numtest{4}{ +%\Reason{Valid invocation (``modify'' not allowed after destroy).} +%\Status{Implemented} +%} + +%\numtest{5}{ +%\Reason{Valid invocation (``delete'' not allowed after destroy).} +%\Status{Implemented} +%} + +%\numtest{6}{ +%\Reason{Fails if database not initialized.} +%\Status{Implemented} +%} + +%\numtest{7}{ +%\Reason{Fails if invoked twice in a row.} +%\Status{Implemented} +%} + +\numtest{8}{ +\Reason{Database can be reinitialized after destroy.} +\Status{Implemented} +} + +\numtest{9}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{10}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{client} +} + +\section{ovsec_kadm_create_principal} + +%In the tests below, ``getu'' refers to a user who has only ``get'' access, +%''addu'' refers to a user who has only ``add'' access, ``modifyu'' refers to +%a user who has only ``modify'' access, and ``deleteu'' refers to a user +%who has only ``delete'' access. ``amu'' refers to a user with ``add'' and +%''modify'' access. ``new_princ'' refers to a principal entry structure +%filled in as follows: +% +% krb5_parse_name("newuser", \&new_princ.principal); +% krb5_timeofday(\&new_princ.princ_expire_time); +% new_princ.princ_expire_time += 130; +% krb5_timeofday(\&new_princ.last_pwd_change); +% new_princ.last_pwd_change += 140; +% krb5_timeofday(\&new_princ.pw_expiration); +% new_princ.pw_expiration += 150; +% new_princ.max_life = 160; +% krb5_parse_name("usera", \&new_princ.mod_name); +% krb5_timeofday(\&new_princ.mod_date); +% new_princ.mod_date += 170; +% new_princ.attributes = 0xabcdabcd; +% new_princ.kvno = 180; +% new_princ.mkvno = 190; +% new_princ.policy = null; +% new_princ.aux_attributes = 0xdeadbeef; +% +%The offsets of 130 through 190 above are used to ensure that the +%fields are all known to be different from each other, so that +%accidentally switched fields can be detected. Some of the fields in +%this structure may be changed by the tests, but they should clean up +%after themselves. + +%\numtest{1}{ +%\Reason{Fails if database not initialized.} +%\Status{Implemented} +%} + +\numtest{2}{ +\Reason{Fails on null princ argument.} +\Status{Implemented} +} + +\numtest{3}{ +\Reason{Fails on null password argument.} +\Status{Implemented} +} + +\numtest{4}{ +\Reason{Fails on empty-string password argument.} +\Status{Implemented} +} + +\numtest{5}{ +\Reason{Fails when mask contains undefined bit.} +\Status{Implemented} +} + +\numtest{6}{ +\Reason{Fails when mask contains LAST_PWD_CHANGE bit.} +\Status{Implemented} +} + +\numtest{7}{ +\Reason{Fails when mask contains MOD_TIME bit.} +\Status{Implemented} +} + +\numtest{8}{ +\Reason{Fails when mask contains MOD_NAME bit.} +\Status{Implemented} +} + +\numtest{9}{ +\Reason{Fails when mask contains MKVNO bit.} +\Status{Implemented} +} + +\numtest{10}{ +\Reason{Fails when mask contains AUX_ATTRIBUTES bit.} +\Status{Implemented} +} + +\numtest{11}{ +\Reason{Fails when mask contains POLICY_CLR bit.} +\Status{Implemented} +} + +\numtest{12}{ +\Reason{Fails for caller with no access bits.} +\Status{Implemented} +} + +\numtest{13}{ +\Reason{Fails when caller has ``get'' access and not ``add''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{14}{ +\Reason{Fails when caller has ``modify'' access and not ``add''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{15}{ +\Reason{Fails when caller has ``delete'' access and not ``add''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{16}{ +\Reason{Fails when caller connected with CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{17}{ +\Reason{Fails on attempt to create existing principal.} +\Status{Implemented} +} + +\numtest{18}{ +\Reason{Fails when password is too short.} +\Status{Implemented} +} + +\numtest{19}{ +\Reason{Fails when password has too few classes.} +\Status{Implemented} +} + +\numtest{20}{ +\Reason{Fails when password is in dictionary.} +\Status{Implemented} +} + +\numtest{21}{ +\Reason{Nonexistent policy is rejected.} +\Status{Implemented} +} + +\numtest{22}{ +\Reason{Fails on invalid principal name.} +\Status{Implemented} +} + +\numtest{23}{ +\Reason{Valid invocation.} +\Status{Implemented} +} + +\numtest{24}{ +\Reason{Succeeds when caller has ``add'' access and another one.} +\Status{Implemented} +} + +%\numtest{25}{ +%\Reason{Fails when password is too short, when override_qual is true.} +%} + +%\numtest{26}{ +%\Reason{Fails when password has too few classes, when +% override_qual is true.} +%} + +%\numtest{27}{ +%\Reason{Fails when password is in dictionary, when override_qual is +% true.} +%} + +\numtest{28}{ +\Reason{Succeeds when assigning policy.} +\Status{Implemented} +} + +\numtest{29}{ +\Priority{High} +\Reason{Allows 0 (never) for princ_expire_time.} +\Status{Implemented} +} + +\numtest{30}{ +\Reason{Allows 0 (never) for pw_expiration when there's no policy.} +\Status{Implemented} +} + +\numtest{31}{ +\Reason{Allows 0 (never) for pw_expiration when there's a policy with + 0 for pw_max_life.} +\Status{Implemented} +} + +\numtest{32}{ +\Reason{Accepts 0 (never) for pw_expiration when there's a policy with + non-zero pw_max_life, and sets pw_expiration to zero.} +\Status{Implemented} +} + +\numtest{33}{ +\Reason{Accepts and sets non-zero pw_expiration when no policy.} +\Status{Implemented} +} + +\numtest{34}{ +\Reason{Accepts and sets non-zero pw_expiration when there's a policy + with zero pw_max_life.} +\Status{Implemented} +} + +\numtest{35}{ +\Reason{Accepts and sets non-zero pw_expiration when there's a policy + with pw_max_life later than the specified pw_expiration.} +\Status{Implemented} +} + +\numtest{36}{ +\Reason{Accepts and sets non-zero pw_expiration greater than now_pw_max_life.} +\Status{Implemented} +} + +\numtest{37}{ +\Priority{High} +\Reason{Sets pw_expiration to 0 (never) if there's no policy and no + specified pw_expiration.} +\Status{Implemented} +} + +\numtest{38}{ +\Priority{High} +\Reason{Sets pw_expiration to 0 (never) if it isn't specified and the + policy has a 0 (never) pw_max_life.} +\Status{Implemented} +} + +\numtest{39}{ +\Priority{High} +\Reason{Sets pw_expiration to now + pw_max_life if it isn't specified + and the policy has a non-zero pw_max_life.} +\Status{Implemented} +} + +\numtest{40}{ +\Priority{High} +\Reason{Allows 0 (forever) for max_life.} +\Status{Implemented} +} + +\numtest{41}{ +\Priority{High} +\Reason{Doesn't modify or free mod_name on success.} +} + +\numtest{42}{ +\Priority{High} +\Reason{Doesn't modify or free mod_name on failure.} +} + +\numtest{43}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{44}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + + +\section{ovsec_kadm_delete_principal} + +%\numtest{1}{ +%\Reason{Fails if database not initialized.} +%\Status{Implemented} +%} + +\numtest{2}{ +\Reason{Fails on null principal.} +\Status{Implemented} +} + +% Empty string principal is legal. +%\numtest{3}{ +%\Reason{Fails on empty-string principal.} +%} + +% There is not invalid principal names +%\numtest{4}{ +%\Reason{Fails on invalid principal name.} +%} + +\numtest{5}{ +\Priority{High} +\Reason{Fails on nonexistent principal.} +\Status{Implemented} +} + +\numtest{6}{ +\Priority{High} +\Reason{Fails when caller connected with CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{7}{ +\Priority{High} +\Reason{Fails if caller has ``add'' access and not ``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{8}{ +\Priority{High} +\Reason{Fails if caller has ``modify'' access and not ``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{9}{ +\Priority{High} +\Reason{Fails if caller has ``get'' access and not ``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{10}{ +\Priority{High} +\Reason{Fails if caller has no access bits.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{11}{ +\Priority{High} +\Reason{Valid invocation.} +\Status{Implemented} +} + +\numtest{12}{ +\Priority{High} +\Reason{Valid invocation (on principal with policy).} +\Status{Implemented} +} + +\numtest{13}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{14}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + + +\section{ovsec_kadm_modify_principal} + +%\numtest{1}{ +%\Reason{Fails if database not initialized.} +%\Status{Implemented} +%} + +\numtest{2}{ +\Priority{High} +\Reason{Fails if user connected with CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{3}{ +\Reason{Fails on mask with undefined bit set.} +\Status{Implemented} +} + +\numtest{4}{ +\Reason{Fails on mask with PRINCIPAL set.} +\Status{Implemented} +} + +\numtest{5}{ +\Priority{High} +\Reason{Fails on mask with LAST_PWD_CHANGE set.} +\Status{Implemented} +} + +\numtest{6}{ +\Reason{Fails on mask with MOD_TIME set.} +\Status{Implemented} +} + +\numtest{7}{ +\Reason{Fails on mask with MOD_NAME set.} +\Status{Implemented} +} + +\numtest{8}{ +\Reason{Fails on mask with MKVNO set.} +\Status{Implemented} +} + +\numtest{9}{ +\Priority{High} +\Reason{Fails on mask with AUX_ATTRIBUTES set.} +\Status{Implemented} +} + +\numtest{10}{ +\Reason{Fails on nonexistent principal.} +\Status{Implemented} +} + +\numtest{11}{ +\Priority{High} +\Reason{Fails for user with no access bits.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{12}{ +\Priority{High} +\Reason{Fails for user with ``get'' access.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{13}{ +\Priority{High} +\Reason{Fails for user with ``add'' access.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{14}{ +\Priority{High} +\Reason{Fails for user with ``delete'' access.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{15}{ +\Priority{High} +\Reason{Succeeds for user with ``modify'' access.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{16}{ +\Reason{Succeeds for user with ``modify'' and another access.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{17}{ +\Priority{High} +\Reason{Fails when nonexistent policy is specified.} +\Status{Implemented} +} + +\numtest{18}{ +\Priority{High} +\Reason{Succeeds when existent policy is specified.} +\Status{Implemented} +} + +\numtest{19}{ +\Reason{Updates policy count when setting policy from none.} +\Status{Implemented} +} + +\numtest{20}{ +\Reason{Updates policy count when clearing policy from set.} +\Status{Implemented} +} + +\numtest{21}{ +\Reason{Updates policy count when setting policy from other policy.} +\Status{Implemented} +} + +\numtest{21.5}{ +\Reason{Policy reference count remains unchanged when policy is + changed to itself.} +\Status{Implemented.} +} + +\numtest{22}{ +\Reason{Allows 0 (never) for pw_expiration when there's no policy.} +\Status{Implemented} +} + +\numtest{23}{ +\Reason{Allows 0 (never) for pw_expiration when there's a policy with + 0 for pw_max_life.} +\Status{Implemented} +} + +\numtest{24}{ +\Reason{Accepts 0 (never) for pw_expiration when there's a policy with + non-zero pw_max_life, but actually sets pw_expiration to + last_pwd_change + pw_max_life.} +\Status{Implemented} +} + +\numtest{25}{ +\Reason{Accepts and sets non-zero pw_expiration when no policy.} +\Status{Implemented} +} + +\numtest{26}{ +\Reason{Accepts and sets non-zero pw_expiration when there's a policy + with zero pw_max_life.} +\Status{Implemented} +} + +\numtest{27}{ +\Reason{Accepts and sets non-zero pw_expiration when there's a policy + with pw_max_life later than the specified pw_expiration.} +\Status{Implemented} +} + +\numtest{28}{ +\Reason{Accepts non-zero pw_expiration and limits it to last_pwd_change + + pw_max_life when it's later than last_pwd_change + non-zero + pw_max_life in policy.} +\Status{Implemented} +} + +\numtest{29}{ +\Priority{High} +\Reason{Sets pw_expiration to 0 (never) when a policy is cleared and +no pw_expiration is specified.} +\Status{Implemented} +} + +\numtest{30}{ +\Priority{High} +\Reason{Sets pw_expiration to 0 (never) if it isn't specified and the + new policy has a 0 (never) pw_max_life.} +\Status{Implemented} +} + +\numtest{31}{ +\Priority{High} +\Reason{Sets pw_expiration to now + pw_max_life if it isn't specified + and the new policy has a non-zero pw_max_life.} +\Status{Implemented} +} + +\numtest{32}{ +\Priority{High} +\Reason{Accepts princ_expire_time change.} +\Status{Implemented} +} + + + +\numtest{33}{ +\Priority{High} +\Reason{Accepts attributes change.} +\Status{Implemented} +} + +\numtest{33.25}{ +\Priority{High} +\Reason{Accepts attributes change (KRB5_KDB_REQUIRES_PW_CHANGE).} +\Status{Implemented} +} + +\numtest{33.5}{ +\Priority{High} +\Reason{Accepts attributes change (KRB5_DISALLOW_TGT_BASE).} +\Status{Implemented} +} + +\numtest{33.75}{ +\Priority{High} +\Reason{Accepts attributes change (KRB5_PW_CHANGE_SERVICE).} +\Status{Implemented} +} + +\numtest{34}{ +\Priority{High} +\Reason{Accepts max_life change.} +\Status{Implemented} +} + +\numtest{35}{ +\Priority{High} +\Reason{Accepts kvno change.} +\Status{Implemented} +} + +\numtest{36}{ +\Reason{Behaves correctly when policy is set to the same as it was + before.} +\Status{Implemented} +} + +\numtest{37}{ +\Reason{Behaves properly when POLICY_CLR is specified and there was no + policy before.} +\Status{Implemented} +} + +\numtest{38}{ +\Priority{High} +\Reason{Accepts 0 (never) for princ_expire_time.} +\Status{Implemented} +} + +\numtest{39}{ +\Priority{High} +\Reason{Accepts 0 for max_life.} +\Status{Implemented} +} + +\numtest{40}{ +\Reason{Rejects null principal argument.} +\Status{Implemented} +} + +\numtest{41}{ +\Priority{High} +\Reason{Doesn't modify or free mod_name on success.} +} + +\numtest{42}{ +\Priority{High} +\Reason{Doesn't modify or free mod_name on failure.} +} + +\numtest{43}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{44}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + +\numtest{100}{ +\Version{KADM5_API_VERSION_2} +\Priority{bug-fix} +\Reason{Accepts max_rlife change.} +\Status{Implemented} +} + +\numtest{101}{ +\Version{KADM5_API_VERSION_2} +\Reason{Rejects last_success change.} +\Status{Implemented} +} + +\numtest{102}{ +\Version{KADM5_API_VERSION_2} +\Reason{Rejects last_failed change.} +\Status{Implemented} +} + +\numtest{103}{ +\Version{KADM5_API_VERSION_2} +\Reason{Rejects fail_auth_count change.} +\Status{Implemented} +} + +\numtest{103.5}{ +\Version{KADM5_API_VERSION_2} +\Reason{Rejects key_data change.} +\Status{Implemented} +} + +\numtest{104}{ +\Version{KADM5_API_VERSION_2} +\Reason{Accepts tl_data change when all types are greater than 256.} +\Status{Implemented} +} + +\numtest{105}{ +\Version{KADM5_API_VERSION_2} +\Reason{Returns KADM5_BAD_TL_TYPE when given tl_data with a type less +than 256.} +\Status{Implemented} +} + +\section{ovsec_kadm_rename_principal} + +%\numtest{1}{ +%\Reason{Fails if database not initialized.} +%\Status{Implemented} +%} + +\numtest{2}{ +\Priority{High} +\Reason{Fails if user connected with CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{3}{ +\Priority{High} +\Reason{Fails for user with no access bits.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{4}{ +\Reason{Fails for user with ``modify'' access and not ``add'' or +``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{5}{ +\Reason{Fails for user with ``get'' access and not ``add'' or +``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{6}{ +\Reason{Fails for user with ``modify'' and ``add'' but not ``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{7}{ +\Reason{Fails for user with ``modify'' and ``delete'' but not ``add''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{8}{ +\Reason{Fails for user with ``get'' and ``add'' but not ``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{9}{ +\Reason{Fails for user with ``get'' and ``delete'' but not ``add.''} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{10}{ +\Reason{Fails for user with ``modify'', ``get'' and ``add'', but not + ``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{11}{ +\Reason{Fails for user with ``modify'', ``get'' and ``delete'', but + not ``add''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{12}{ +\Priority{High} +\Reason{Fails for user with ``add'' but not ``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{13}{ +\Priority{High} +\Reason{Fails for user with ``delete'' but not ``add''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{14}{ +\Priority{High} +\Reason{Succeeds for user with ``add'' and ``delete'', when that user +has non-name-based salt.} +\Status{Implemented} +} + +\numtest{15}{ +\Priority{High} +\Reason{Fails if target principal name exists.} +\Status{Implemented} +} + +\numtest{16}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{17}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + +\numtest{18}{ +\Priority{bug fix} +\Reason{Returns NO_RENAME_SALT when asked to rename a principal whose +salt depends on the principal name.} +\Status{Implemented} +} + +\section{ovsec_kadm_chpass_principal} +\label{ovseckadmchpassprincipal} + +\subsection{Quality/history enforcement tests} + +This section lists a series of tests which will be run a number of +times, with various parameter settings (e.g., which access bits user +has, whether user connected with ADMIN_SERVICE or CHANGEPW_SERVICE, +etc.). The table following the +list of tests gives the various parameter settings under which the +tests should be run, as well which should succeed and which should +fail for each choice of parameter settings. + +\subsubsection{List of tests} + +The test number of each of these tests is an offset from the base +given in the table below. + +\numtest{1}{ +\Priority{High} +\Reason{With history setting of 1, change password to itself.} +} + +\numtest{2}{ +\Reason{With history setting of 2 but no password changes since + principal creation, change password to itself.} +} + +\numtest{3}{ +\Reason{With history setting of 2 and one password change since + principal creation, change password to itself + and directly previous password.} +} + +\numtest{4}{ +\Priority{High} +\Reason{With a history setting of 3 and no password changes, + change password to itself.} +} + +\numtest{5}{ +\Priority{High} +\Reason{With a history setting of 3 and 1 password change, + change password to itself or previous password.} +} + +\numtest{6}{ +\Priority{High} +\Reason{With a history setting of 3 and 2 password changes, + change password to itself and the two previous passwords.} +} + +\numtest{7}{ +\Priority{High} +\Reason{Change to previously unused password when now - + last_pwd_change $<$ pw_min_life.} +} + +\numtest{8}{ +\Priority{High} +\Reason{Change to previously unused password that doesn't contain enough + character classes.} +} + +\numtest{9}{ +\Priority{High} +\Reason{Change to previously unused password that's too short.} +} + +\numtest{10}{ +\Priority{High} +\Reason{Change to previously unused password that's in the dictionary.} +} + +\subsubsection{List of parameter settings} + +In the table below, ``7 passes'' means that test 7 above passes and +the rest of the tests fail. + +\begin{tabular}{llllll} +Base & Modify access? & Own password? & Service & Pass/Fail \\ \hline +0 & No & Yes & ADMIN & all fail \\ +20 & No & Yes & CHANGEPW & all fail \\ +40 & No & No & ADMIN & all fail \\ +60 & No & No & CHANGEPW & all fail \\ +80 & Yes & Yes & ADMIN & 7 passes \\ +100 & Yes & Yes & CHANGEPW & all fail \\ +120 & Yes & No & ADMIN & 7 passes \\ +140 & Yes & No & CHANGEPW & all fail \\ +\end{tabular} + +\subsection{Other quality/history tests} + +\numtest{161}{ +\Priority{High} +\Reason{With history of 1, can change password to anything other than + itself that doesn't conflict with other quality + rules.} +} + +\numtest{162}{ +\Reason{With history of 2 and 2 password changes, can change password + to original password.} +} + +\numtest{163}{ +\Priority{High} +\Reason{With history of 3 and 3 password changes, can change password + to original password.} +} + +\numtest{164}{ +\Priority{High} +\Reason{Can change password when now - last_pwd_change $>$ pw_min_life.} +} + +\numtest{165}{ +\Priority{High} +\Reason{Can change password when it contains exactly the number of + classes required by the policy.} +} + +\numtest{166}{ +\Priority{High} +\Reason{Can change password when it is exactly the length required by + the policy.} +} + +\numtest{167}{ +\Priority{High} +\Reason{Can change password to a word that isn't in the dictionary.} +} + + +\subsection{Other tests} + +%\numtest{168}{ +%\Reason{Fails if database not initialized.} +%} + +\numtest{169}{ +\Reason{Fails for non-existent principal.} +} + +\numtest{170}{ +\Reason{Fails for null password.} +} + +\numtest{171}{ +\Priority{High} +\Reason{Fails for empty-string password.} +} + +\numtest{172}{ +\Priority{High} +\Reason{Pw_expiration is set to now + max_pw_life if policy exists and + has non-zero max_pw_life.} +} + +\numtest{173}{ +\Priority{High} +\Reason{Pw_expiration is set to 0 if policy exists and has zero + max_pw_life.} +} + +\numtest{174}{ +\Priority{High} +\Reason{Pw_expiration is set to 0 if no policy.} +} + +\numtest{175}{ +\Priority{High} +\Reason{KRB5_KDC_REQUIRES_PWCHANGE bit is cleared when password is + successfully changed.} +} + +\numtest{176}{ +\Priority{High} +\Reason{Fails for user with no access bits, on other's password.} +} + +\numtest{177}{ +\Priority{High} +\Reason{Fails for user with ``get'' but not ``modify'' access, on + other's password.} +} + +\numtest{178}{ +\Reason{Fails for user with ``delete'' but not ``modify'' access, on + other's password.} +} + +\numtest{179}{ +\Reason{Fails for user with ``add'' but not ``modify'' access, on + other's password.} +} + +\numtest{180}{ +\Reason{Succeeds for user with ``get'' and ``modify'' access, on + other's password.} +\Status{Implemented} +} + +\numtest{180.5}{ +\Priority{High} +\Reason{Succeeds for user with ``modify'' but not ``get'' access, on + other's password.} +\Conditions{RPC} +\Status{Implemented} +} +\numtest{180.625}{ +\Priority{High} +\Reason{Fails for user with modify when connecting with CHANGEPW_SERVICE on + others password} +\Conditions{RPC} +\Status{Implemented} +} +\numtest{180.75}{ +\Priority{High} +\Reason{Fails for user with modify when connecting with CHANGEPW_SERVICE + on other's password which has expired} +\Conditions{RPC} +\Status{Implemented} +} + +%\numtest{181}{ +%\Reason{Password that would succeed if override_qual were false fails +% if override_qual is true.} +%\Expected{Returns CANNOT_OVERRIDE.} +%} + +\numtest{182}{ +\Priority{High} +\Reason{Can not change key of ovsec_adm/history principal.} +\Status{Implemented} +} + +\numtest{183}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{184}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + +\numtest{200}{ +\Version{KADM5_API_VERSION_2} +\Reason{Creates a key for the principal for each unique encryption +type/salt type in use.} +\Status{Implemented} +} + +\section{ovsec_kadm_chpass_principal_util} + +Rerun all the tests listed for ovsec_kadm_chpass_principal above in +Section \ref{ovseckadmchpassprincipal}. Verify that they succeed +and fail in the same circumstances. Also verify that in each failure +case, the error message returned in msg_ret is as specified in the +functional specification. + +Also, run the following additional tests. + +\numtest{1}{ +\Reason{Null msg_ret is rejected.} +} + +\numtest{2}{ +\Priority{High} +\Reason{New password is put into pw_ret, when it's prompted for.} +} + +\numtest{3}{ +\Priority{High} +Reason{New password is put into pw_ret, when it's supplied by the + caller.} +} + +\numtest{4}{ +\Priority{High} +\Reason{Successful invocation when pw_ret is null.} +} + + + +\section{ovsec_kadm_randkey_principal} + +\subsection{TOOSOON enforcement tests} + +This test should be run a number of times, as indicated in the table +following it. The table also indicates the expected result of each +run of the test. + +\test{ +\Reason{Change key when now - last_pwd_change $<$ pw_min_life.} +} + +\subsubsection{List of parameter settings} + +\begin{tabular}{llllll} +Number & Modify Access? & Own Key? & Service & Pass/Fail & Implemented? \\ \hline +1 & No & Yes & ADMIN & fail & Yes \\ +3 & No & Yes & CHANGEPW & fail & Yes \\ +5 & No & No & ADMIN & fail \\ +7 & No & No & CHANGEPW & fail \\ +9 & Yes & Yes & ADMIN & pass \\ +11 & Yes & Yes & CHANGEPW & fail \\ +13 & Yes & No & ADMIN & pass & Yes \\ +15 & Yes & No & CHANGEPW & fail & Yes \\ +\end{tabular} + +\subsection{Other tests} + +\numtest{17}{ +\Reason{Fails if database not initialized.} +} + +\numtest{18}{ +\Reason{Fails for non-existent principal.} +} + +\numtest{19}{ +\Reason{Fails for null keyblock pointer.} +} + +\numtest{20}{ +\Priority{High} +\Reason{Pw_expiration is set to now + max_pw_life if policy exists and + has non-zero max_pw_life.} +} + +\numtest{21}{ +\Priority{High} +\Reason{Pw_expiration is set to 0 if policy exists and has zero + max_pw_life.} +} + +\numtest{22}{ +\Priority{High} +\Reason{Pw_expiration is set to 0 if no policy.} +} + +\numtest{23}{ +\Priority{High} +\Reason{KRB5_KDC_REQUIRES_PWCHANGE bit is cleared when key is + successfully changed.} +} + +\numtest{24}{ +\Priority{High} +\Reason{Fails for user with no access bits, on other's password.} +} + +\numtest{25}{ +\Priority{High} +\Reason{Fails for user with ``get'' but not ``modify'' access, on + other's password.} +\Vtwonote{Change-password instead of modify access.} +} + +\numtest{26}{ +\Reason{Fails for user with ``delete'' but not ``modify'' access, on + other's password.} +\Vtwonote{Change-password instead of modify access.} +} + +\numtest{27}{ +\Reason{Fails for user with ``add'' but not ``modify'' access, on + other's password.} +\Vtwonote{Change-password instead of modify access.} +} + +\numtest{28}{ +\Reason{Succeeds for user with ``get'' and ``modify'' access, on + other's password.} +\Status{Implemented} +\Vtwonote{Change-password instead of modify access.} +} + +\numtest{28.25}{ +\Priority{High} +\Reason{Fails for user with get and modify access on others password + When conneceted with CHANGEPW_SERVICE} +\Status{Implemented} +\Vtwonote{Change-password instead of modify access.} +} + +\numtest{28.5}{ +\Priority{High} +\Reason{Succeeds for user with ``modify'' but not ``get'' access, on + other's password.} +\Status{Implemented} +\Vtwonote{Change-password instead of modify access.} +} + +\numtest{29}{ +\Reason{The new key that's assigned is truly random. XXX not sure how + to test this.} +} + +\numtest{30}{ +\Reason{Succeeds for own key, no other access bits when connecting with CHANGEPW service} +\Status{Implemented} +} +\numtest{31}{ +\Reason{Succeeds for own key, no other access bits when connecting with ADMIM service} +\Status{Implemented} +} + +\numtest{32}{ +\Reason{Cannot change ovsec_adm/history key} +\Status{Implemented} +} + +\numtest{33}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{34}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + +\numtest{100}{ +\Version{KADM5_API_VERSION_2} +\Reason{Returns a key for each unique encryption type specified in the +keysalts.} +} + +\section{ovsec_kadm_get_principal} + +\numtest{1}{ +\Reason{Fails for null ent.} +\Status{Implemented} +} + +\numtest{2}{ +\Reason{Fails for non-existent principal.} +\Status{Implemented} +} + +\numtest{3}{ +\Priority{High} +\Reason{Fails for user with no access bits, retrieving other principal.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{4}{ +\Priority{High} +\Reason{Fails for user with ``add'' but not ``get'', getting principal + other than his own, using ADMIN_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{5}{ +\Reason{Fails for user with ``modify'' but not ``get'', getting + principal other than his own, using ADMIN_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{6}{ +\Reason{Fails for user with ``delete'' but not ``get'', getting + principal other than his own, using ADMIN_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{7}{ +\Reason{Fails for user with ``delete'' but not ``get'', getting + principal other than his own, using CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{8}{ +\Priority{High} +\Reason{Fails for user with ``get'', getting principal other than his + own, using CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{9}{ +\Priority{High} +\Reason{Succeeds for user without ``get'', retrieving self, using + ADMIN_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{10}{ +\Reason{Succeeds for user without ``get'', retrieving self, using + CHANGEPW_SERVICE.} +\Status{Implemented} +} + +\numtest{11}{ +\Reason{Succeeds for user with ``get'', retrieving self, using + ADMIN_SERVICE.} +\Status{Implemented} +} + +\numtest{12}{ +\Reason{Succeeds for user with ``get'', retrieving self, using + CHANGEPW_SERVICE.} +\Status{Implemented} +} + +\numtest{13}{ +\Priority{High} +\Reason{Succeeds for user with ``get'', retrieving other user, using + ADMIN_SERVICE.} +\Status{Implemented} +} + +\numtest{14}{ +\Reason{Succeeds for user with ``get'' and ``modify'', retrieving + other principal, using ADMIN_SERVICE.} +\Status{Implemented} +} + +\numtest{15}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{16}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + +\numtest{100}{ +\Version{KADM5_API_VERSION_2} +\Reason{If KADM5_PRINCIPAL_NORMAL_MASK is specified, the key_data and +tl_data fields are NULL/zero.} +\Status{Implemented} +} + +\numtest{101}{ +\Version{KADM5_API_VERSION_2} +\Reason{If KADM5_KEY_DATA is specified, the key_data fields contain +data but the contents are all NULL.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{102}{ +\Version{KADM5_API_VERSION_2} +\Reason{If KADM5_KEY_DATA is specified, the key_data fields contain +data and the contents are all non-NULL.} +\Conditions{local} +\Status{Implemented} +} + +\numtest{103}{ +\Version{KADM5_API_VERSION_2} +\Reason{If KADM5_TL_DATA is specified, the tl_data field contains the +correct tl_data and no entries whose type is less than 256.} +\Status{Implemented} +} + + +\section{ovsec_kadm_create_policy} + +\numtest{1}{ +\Reason{Fails for mask with undefined bit set.} +\Status{Implemented - untested} +} + +\numtest{2}{ +\Priority{High} +\Reason{Fails if caller connected with CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{3}{ +\Reason{Fails for mask without POLICY bit set.} +\Status{Implemented - untested} +} + +\numtest{4}{ +\Reason{Fails for mask with REF_COUNT bit set.} +\Status{Implemented} +} + +\numtest{5}{ +\Reason{Fails for invalid policy name.} +\Status{Implemented - untested} +} + +\numtest{6}{ +\Priority{High} +\Reason{Fails for existing policy name.} +\Status{Implemented} +} + +\numtest{7}{ +\Reason{Fails for null policy name.} +\Status{Implemented - untested} +} + +\numtest{8}{ +\Priority{High} +\Reason{Fails for empty-string policy name.} +\Status{Implemented} +} + +\numtest{9}{ +\Priority{High} +\Reason{Accepts 0 for pw_min_life.} +\Status{Implemented} +} + +\numtest{10}{ +\Priority{High} +\Reason{Accepts non-zero for pw_min_life.} +\Status{Implemented} +} + +\numtest{11}{ +\Priority{High} +\Reason{Accepts 0 for pw_max_life.} +\Status{Implemented} +} + +\numtest{12}{ +\Priority{High} +\Reason{Accepts non-zero for pw_max_life.} +\Status{Implemented} +} + +\numtest{13}{ +\Priority{High} +\Reason{Rejects 0 for pw_min_length.} +\Status{Implemented} +} + +\numtest{14}{ +\Priority{High} +\Reason{Accepts non-zero for pw_min_length.} +\Status{Implemented} +} + +\numtest{15}{ +\Priority{High} +\Reason{Rejects 0 for pw_min_classes.} +\Status{Implemented} +} + +\numtest{16}{ +\Priority{High} +\Reason{Accepts 1 for pw_min_classes.} +\Status{Implemented} +} + +\numtest{17}{ +\Priority{High} +\Reason{Accepts 4 for pw_min_classes.} +\Status{Implemented} +} + +\numtest{18}{ +\Priority{High} +\Reason{Rejects 5 for pw_min_classes.} +\Status{Implemented} +} + +\numtest{19}{ +\Priority{High} +\Reason{Rejects 0 for pw_history_num.} +\Status{Implemented} +} + +\numtest{20}{ +\Priority{High} +\Reason{Accepts 1 for pw_history_num.} +\Status{Implemented} +} + +\numtest{21}{ +\Priority{High} +\Reason{Accepts 10 for pw_history_num.} +\Status{Implemented} +} + +\numtest{21.5}{ +\Reason{Rejects 11 for pw_history_num.} +\Status{Implemented - untested} +} + +\numtest{22}{ +\Priority{High} +\Reason{Fails for user with no access bits.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{23}{ +\Priority{High} +\Reason{Fails for user with ``get'' but not ``add''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{24}{ +\Reason{Fails for user with ``modify'' but not ``add.''} +\Conditions{RPC} +\Status{Implemented - untested} +} + +\numtest{25}{ +\Reason{Fails for user with ``delete'' but not ``add.''} +\Conditions{RPC} +\Status{Implemented - untested} +} + +\numtest{26}{ +\Priority{High} +\Reason{Succeeds for user with ``add.''} +\Status{Implemented} +} + +\numtest{27}{ +\Reason{Succeeds for user with ``get'' and ``add.''} +\Status{Implemented - untested} +} + +\numtest{28}{ +\Reason{Rejects null policy argument.} +\Status{Implemented - untested} +} + +\numtest{29}{ +\Reason{Rejects pw_min_life greater than pw_max_life.} +} + +\numtest{30}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{31}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + + +\section{ovsec_kadm_delete_policy} + +\numtest{1}{ +\Reason{Fails for null policy name.} +} + +\numtest{2}{ +\Priority{High} +\Reason{Fails for empty-string policy name.} +\Status{Implemented} +} + +\numtest{3}{ +\Reason{Fails for non-existent policy name.} +} + +\numtest{4}{ +\Reason{Fails for bad policy name.} +} + +\numtest{5}{ +\Priority{High} +\Reason{Fails if caller connected with CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{6}{ +\Priority{High} +\Reason{Fails for user with no access bits.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{7}{ +\Priority{High} +\Reason{Fails for user with ``add'' but not ``delete''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{8}{ +\Reason{Fails for user with ``modify'' but not ``delete''.} +\Conditions{RPC} +} + +\numtest{9}{ +\Reason{Fails for user with ``get'' but not ``delete.''} +\Conditions{RPC} +} + +\numtest{10}{ +\Priority{High} +\Reason{Succeeds for user with only ``delete''.} +\Status{Implemented} +} + +\numtest{11}{ +\Reason{Succeeds for user with ``delete'' and ``add''.} +} + +\numtest{12}{ +\Priority{High} +\Reason{Fails for policy with non-zero reference count.} +\Status{Implemented} +} + +\numtest{13}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{14}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + + +\section{ovsec_kadm_modify_policy} + +\numtest{1}{ +\Reason{Fails for mask with undefined bit set.} +\Conditions{RPC} +} + +\numtest{2}{ +\Priority{High} +\Reason{Fails if caller connected with CHANGEPW_SERVICE.} +\Status{Implemented} +} + +\numtest{3}{ +\Reason{Fails for mask with POLICY bit set.} +} + +\numtest{4}{ +\Reason{Fails for mask with REF_COUNT bit set.} +\Status{Implemented} +} + +\numtest{5}{ +\Reason{Fails for invalid policy name.} +} + +\numtest{6}{ +\Reason{Fails for non-existent policy name.} +} + +\numtest{7}{ +\Reason{Fails for null policy name.} +} + +\numtest{8}{ +\Priority{High} +\Reason{Fails for empty-string policy name.} +\Status{Implemented} +} + +\numtest{9}{ +\Priority{High} +\Reason{Accepts 0 for pw_min_life.} +\Status{Implemented} +} + +\numtest{10}{ +\Priority{High} +\Reason{Accepts non-zero for pw_min_life.} +\Status{Implemented} +} + +\numtest{11}{ +\Priority{High} +\Reason{Accepts 0 for pw_max_life.} +\Status{Implemented} +} + +\numtest{12}{ +\Priority{High} +\Reason{Accepts non-zero for pw_max_life.} +\Status{Implemented} +} + +\numtest{13}{ +\Priority{High} +\Reason{Accepts 0 for pw_min_length.} +\Status{Implemented} +} + +\numtest{14}{ +\Priority{High} +\Reason{Accepts non-zero for pw_min_length.} +\Status{Implemented} +} + +\numtest{15}{ +\Priority{High} +\Reason{Rejects 0 for pw_min_classes.} +\Status{Implemented} +} + +\numtest{16}{ +\Priority{High} +\Reason{Accepts 1 for pw_min_classes.} +\Status{Implemented} +} + +\numtest{17}{ +\Priority{High} +\Reason{Accepts 4 for pw_min_classes.} +\Status{Implemented} +} + +\numtest{18}{ +\Priority{High} +\Reason{Rejects 5 for pw_min_classes.} +\Status{Implemented} +} + +\numtest{19}{ +\Priority{High} +\Reason{Rejects 0 for pw_history_num.} +\Status{Implemented} +} + +\numtest{20}{ +\Priority{High} +\Reason{Accepts 1 for pw_history_num.} +\Status{Implemented} +} + +\numtest{21}{ +\Priority{High} +\Reason{Accepts 10 for pw_history_num.} +\Status{Implemented} +} + +\numtest{22}{ +\Priority{High} +\Reason{Fails for user with no access bits.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{23}{ +\Priority{High} +\Reason{Fails for user with ``get'' but not ``modify''.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{24}{ +\Reason{Fails for user with ``add'' but not ``modify.''} +\Conditions{RPC} +} + +\numtest{25}{ +\Reason{Fails for user with ``delete'' but not ``modify.''} +\Conditions{RPC} +} + +\numtest{26}{ +\Priority{High} +\Reason{Succeeds for user with ``modify.''} +\Status{Implemented} +} + +\numtest{27}{ +\Reason{Succeeds for user with ``get'' and ``modify.''} +} + +\numtest{28}{ +\Reason{Rejects null policy argument.} +} + +\numtest{29}{ +\Reason{Rejects change which makes pw_min_life greater than + pw_max_life.} +} + +\numtest{30}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{31}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + +\section{ovsec_kadm_get_policy} + +\numtest{1}{ +\Reason{Fails for null policy.} +} + +\numtest{2}{ +\Reason{Fails for invalid policy name.} +} + +\numtest{3}{ +\Priority{High} +\Reason{Fails for empty-string policy name.} +\Status{Implemented} +} + +\numtest{4}{ +\Reason{Fails for non-existent policy name.} +} + +\numtest{5}{ +\Reason{Fails for null ent.} +} + +\numtest{6}{ +\Priority{High} +\Reason{Fails for user with no access bits trying to get other's + policy, using ADMIN_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{7}{ +\Priority{High} +\Reason{Fails for user with ``add'' but not ``get'' trying to get + other's policy, using ADMIN_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{8}{ +\Reason{Fails for user with ``modify'' but not ``get'' trying to get + other's policy, using ADMIN_SERVICE.} +\Conditions{RPC} +} + +\numtest{9}{ +\Reason{Fails for user with ``delete'' but not ``get'' trying to get + other's policy, using ADMIN_SERVICE.} +\Conditions{RPC} +} + +\numtest{10}{ +\Reason{Fails for user with ``delete'' but not ``get'' trying to get + other's policy, using CHANGEPW_SERVICE.} +\Conditions{RPC} +} + +\numtest{11}{ +\Priority{High} +\Reason{Succeeds for user with only ``get'', trying to get own policy, + using ADMIN_SERVICE.} +\Status{Implemented} +} + +\numtest{12}{ +\Priority{High} +\Reason{Succeeds for user with only ``get'', trying to get own policy, + using CHANGEPW_SERVICE.} +\Status{Implemented} +} + +\numtest{13}{ +\Reason{Succeeds for user with ``add'' and ``get'', trying to get own + policy, using ADMIN_SERVICE.} +} + +\numtest{14}{ +\Reason{Succeeds for user with ``add'' and ``get'', trying to get own + policy, using CHANGEPW_SERVICE.} +} + +\numtest{15}{ +\Reason{Succeeds for user without ``get'', trying to get own policy, + using ADMIN_SERVICE.} +} + +\numtest{16}{ +\Priority{High} +\Reason{Succeeds for user without ``get'', trying to get own policy, + using CHANGEPW_SERVICE.} +\Status{Implemented} +} + +\numtest{17}{ +\Priority{High} +\Reason{Succeeds for user with ``get'', trying to get other's policy, + using ADMIN_SERVICE.} +\Status{Implemented} +} + +\numtest{18}{ +\Priority{High} +\Reason{Fails for user with ``get'', trying to get other's policy, + using CHANGEPW_SERVICE.} +\Conditions{RPC} +\Status{Implemented} +} + +\numtest{19}{ +\Reason{Succeeds for user with ``modify'' and ``get'', trying to get + other's policy, using ADMIN_SERVICE.} +} + +\numtest{20}{ +\Reason{Fails for user with ``modify'' and ``get'', trying to get + other's policy, using CHANGEPW_SERVICE.} +} + +\numtest{21}{ +\Priority{High} +\Reason{Returns BAD_SERVER_HANDLE when a null server handle is passed in} +\Status{Implemented} +} + +\numtest{22}{ +\Priority{Low} +\Reason{Connects to correct server when mutliple handles exist} +\Conditions{RPC} +} + + +\section{ovsec_kadm_free_principal_ent} + +In addition to the tests listed here, a memory-leak detector such as +TestCenter, Purify or dbmalloc should be used to verify that the +memory freed by this function is really freed. + +\numtest{1}{ +\Reason{Null princ succeeds.} +} + +\numtest{2}{ +\Reason{Non-null princ succeeds.} +} + + +\section{ovsec_kadm_free_policy_ent} + +In addition to the tests listed here, a memory-leak detector such as +TestCenter, Purify or dbmalloc should be used to verify that the +memory freed by this function is really freed. + +\numtest{1}{ +\Reason{Null policy succeeds.} +} + +\numtest{2}{ +\Reason{Non-null policy succeeds.} +} + + + +\section{ovsec_kadm_get_privs} + +\numtest{1}{ +\Reason{Fails for null pointer argument.} +} + +This test should be run with the 16 possible combinations of access +bits (since there are 4 access bits, there are $2^4 = 16$ possible +combinations of them): + +\numtest{2}{ +\Priority{High} +\Reason{Returns correct bit mask for access bits of user.} +\Conditions{RPC} +} + +This test should be run locally: + +\numtest{3}{ +\Priority{High} +\Reason{Returns 0x0f.} +\Conditions{local} +} + +\end{document} diff --git a/mechglue/doc/kadm5/fullpage.sty b/mechglue/doc/kadm5/fullpage.sty new file mode 100644 index 000000000..d5a2bf5b0 --- /dev/null +++ b/mechglue/doc/kadm5/fullpage.sty @@ -0,0 +1,9 @@ +\marginparwidth 0pt +\oddsidemargin 0pt +\evensidemargin 0pt +\marginparsep 0pt + +\topmargin 0pt + +\textwidth 6.5in +\textheight 8.5 in diff --git a/mechglue/doc/kadm5/rcsid.sty b/mechglue/doc/kadm5/rcsid.sty new file mode 100644 index 000000000..3ad7826ff --- /dev/null +++ b/mechglue/doc/kadm5/rcsid.sty @@ -0,0 +1,5 @@ +\def\rcs$#1: #2${\expandafter\def\csname rcs#1\endcsname{#2}} + +% example usage: +% \rcs$Version$ +% Version \rcsVersion diff --git a/mechglue/doc/kadm5acl.texinfo b/mechglue/doc/kadm5acl.texinfo new file mode 100644 index 000000000..468a9b93a --- /dev/null +++ b/mechglue/doc/kadm5acl.texinfo @@ -0,0 +1,113 @@ +The format of the file is: + +@smallexample +Kerberos_principal permissions [target_principal] [restrictions] +@end smallexample + +The Kerberos principal (and optional target principal) can include the +``@b{*}'' wildcard, so if you want any principal with the instance +``admin'' to have full permissions on the database, you could use the +principal ``@code{*/admin@@REALM}'' where ``REALM'' is your Kerberos +realm. @code{target_principal} can also include backreferences to +@code{Kerberos_principal}, in which "@b{*@i{number}}" matches the +component @i{number} in the @code{Kerberos_principal}. + +Note: a common use of an @i{admin} instance is so you can grant +separate permissions (such as administrator access to the Kerberos +database) to a separate Kerberos principal. For example, the user +@code{@value{ADMINUSER}} might have a principal for his administrative +use, called @code{@value{ADMINUSER}/admin}. This way, +@code{@value{ADMINUSER}} would obtain @code{@value{ADMINUSER}/admin} +tickets only when he actually needs to use those permissions. + +The permissions are represented by single letters; UPPER-CASE letters +represent negative permissions. The permissions are: + +@table @b +@itemx a +allows the addition of principals or policies in the database. +@itemx A +disallows the addition of principals or policies in the database. +@itemx d +allows the deletion of principals or policies in the database. +@itemx D +disallows the deletion of principals or policies in the database. +@itemx m +allows the modification of principals or policies in the database. +@itemx M +disallows the modification of principals or policies in the database. +@itemx c +allows the changing of passwords for principals in the database. +@itemx C +disallows the changing of passwords for principals in the database. +@itemx i +allows inquiries to the database. +@itemx I +disallows inquiries to the database. +@itemx l +allows the listing of principals or policies in the database. +@itemx L +disallows the listing of principals or policies in the database. +@itemx s +allows the explicit setting of the key for a principal +@itemx S +disallows the explicit setting of the key for a principal +@itemx * +All privileges (admcil). +@itemx x +All privileges (admcil); identical to ``*''. +@end table + +The restrictions are a string of flags. Allowed restrictions are: + +@table @b +@itemx [+ -]@i{flagname} +flag is forced to indicated value. The permissible flags are the same +as the @code{+} and @code{-} flags for the @code{kadmin addprinc} and +@code{modprinc} commands. +@itemx -clearpolicy +policy is forced to clear +@itemx -policy @i{pol} +policy is forced to be @i{pol} +@itemx expire @i{time} +@itemx pwexpire @i{time} +@itemx maxlife @i{time} +@itemx maxrenewlife @i{time} +associated value will be forced to MIN(@i{time}, requested value) +@end table + +The above flags act as restrictions on any add or modify operation +which is allowed due to that ACL line. + +Here is an example of a @code{kadm5.acl} file. Note that order is +important; permissions are determined by the first matching entry. + +@smallexample +@group +*/admin@@@value{PRIMARYREALM} * +@value{ADMINUSER}@@@value{PRIMARYREALM} ADMCIL +@value{ADMINUSER}/*@@@value{PRIMARYREALM} il */root@@@value{PRIMARYREALM} +*@@@value{PRIMARYREALM} cil *1/admin@@@value{PRIMARYREALM} +*/*@@@value{PRIMARYREALM} i +*/admin@@@value{SECONDREALM} * -maxlife 9h -postdateable +@end group +@end smallexample + +@noindent In the above file, any principal in the +@value{PRIMARYREALM} realm with an @code{admin} instance has all +administrative privileges. The user @code{@value{ADMINUSER}} +has all permissions with his @code{admin} instance, +@code{@value{ADMINUSER}/admin@@@value{PRIMARYREALM}} (matches the first +line). He has no permissions at all with his @code{null} instance, +@code{@value{ADMINUSER}@@@value{PRIMARYREALM}} (matches the second line). +His root instance has @i{inquire} and @i{list} permissions with any +other principal that has the instance @code{root}. Any principal +in @value{PRIMARYREALM} can inquire, list, or change the password of +their @code{admin} instance, but not any other @code{admin} instance. +Any principal in the realm @code{@value{PRIMARYREALM}} (except for +@code{@value{ADMINUSER}@@@value{PRIMARYREALM}}, as mentioned above) has +@i{inquire} privileges. Finally, any principal with an admin instance +in @value{SECONDREALM} has all permissions, but any principal that they +create or modify will not be able to get postdateable tickets or tickets +with a life of longer than 9 hours. + diff --git a/mechglue/doc/kadmin/.Sanitize b/mechglue/doc/kadmin/.Sanitize new file mode 100644 index 000000000..148fae1be --- /dev/null +++ b/mechglue/doc/kadmin/.Sanitize @@ -0,0 +1,33 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +kpasswd.protocol +kadmin.protocol + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/mechglue/doc/kadmin/ChangeLog b/mechglue/doc/kadmin/ChangeLog new file mode 100644 index 000000000..5599867c9 --- /dev/null +++ b/mechglue/doc/kadmin/ChangeLog @@ -0,0 +1,14 @@ +2001-06-22 Ezra Peisach + + * draft-ietf-cat-kerb-chg-password-02.txt: Describes protocol in + use by krb5_change_password(). + + * README: Describes which admin protocol is used with which server. + +Thu Sep 7 15:51:56 1995 Theodore Y. Ts'o + + * kpasswd.protocol: Added official IANA port assignment. (We've + actually had it for quite a while, but I never got around + to adding it to the document.) + + diff --git a/mechglue/doc/kadmin/README b/mechglue/doc/kadmin/README new file mode 100644 index 000000000..b3e53bfc8 --- /dev/null +++ b/mechglue/doc/kadmin/README @@ -0,0 +1,46 @@ +There are several different admin protocols in our source tree. + +a) V4 server protocol - not documented + +b) Old kadmin protocol - which was in the beta code (kadmin/v5passwdd) + +c) Newer kadm5 gssrpc based code (kadmin/server) + +d) Simple password changing protocol implemented in our kadmin server +with client in clients/kpasswd. + + + +This file will attempt to link the files in this directory with where +the code is used in the source tree. + + +- kpasswd.protocol: Describes the password changing protocol in + src/kadmin/v5passwdd. + include/krb5/adm.h has some defintions. + + Client and server provided + +- kadmin.protocol: Describes other administrative protocol options that + src/kadmin/v5passwdd supports + + No client in the source tree uses it. + +- draft-ietf-cat-kerb-chg-password-02.txt: Describes the + password changing service that + clients/kpasswd uses through krb5_change_password() + located in lib/krb5/os/changepw.c + + kadmin/server/schpw.c implements this as part of + the kadmin server. + + This is version 1 of the protocol. Version 2 is + in the IETF draft stage and is very different. + + Currently: Version 1 is supported - but we may not + be implementing the TCP handling aspects. + +- ../doc/kadm5: Describes the current protocol. + + kadmin/passwd (which is not installed) uses + the kadm5 protocol for password changing. diff --git a/mechglue/doc/kadmin/draft-ietf-cat-kerb-chg-password-02.txt b/mechglue/doc/kadmin/draft-ietf-cat-kerb-chg-password-02.txt new file mode 100644 index 000000000..e235bec58 --- /dev/null +++ b/mechglue/doc/kadmin/draft-ietf-cat-kerb-chg-password-02.txt @@ -0,0 +1,311 @@ + + + + +Network Working Group M. Horowitz + Stonecast, Inc. +Internet-Draft August, 1998 + + Kerberos Change Password Protocol + +Status of this Memo + + This document is an Internet-Draft. Internet-Drafts are working + documents of the Internet Engineering Task Force (IETF), its areas, + and its working groups. Note that other groups may also distribute + working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as ``work in progress.'' + + To learn the current status of any Internet-Draft, please check the + ``1id-abstracts.txt'' listing contained in the Internet-Drafts Shadow + Directories on ftp.ietf.org (US East Coast), nic.nordu.net + (Europe), ftp.isi.edu (US West Coast), or munnari.oz.au (Pacific + Rim). + + Distribution of this memo is unlimited. Please send comments to the + mailing list. + +Abstract + + The Kerberos V5 protocol [RFC1510] does not describe any mechanism + for users to change their own passwords. In order to promote + interoperability between workstations, personal computers, terminal + servers, routers, and KDC's from multiple vendors, a common password + changing protocol is required. + + + +Overview + + When a user wishes to change his own password, or is required to by + local policy, a simple request of a password changing service is + necessary. This service must be implemented on at least one host for + each Kerberos realm, probably on one of the kdc's for that realm. + The service must accept requests on UDP port 464 (kpasswd), and may + accept requests on TCP port 464 as well. + + The protocol itself consists of a single request message followed by + a single reply message. For UDP transport, each message must be + fully contained in a single UDP packet. + + + + + + + + +Horowitz [Page 1] + +Internet Draft Kerberos Change Password Protocol August, 1998 + + +Request Message + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | message length | protocol version number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AP_REQ length | AP-REQ data / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / KRB-PRIV message / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + message length (16 bits) + Contains the length of the message, including this field, in bytes + (big-endian integer) + protocol version number (16 bits) + Contains the hex constant 0x0001 (big-endian integer) + AP-REQ length (16 bits) + length (big-endian integer) of AP-REQ data, in bytes. + AP-REQ data, as described in RFC1510 (variable length) + This AP-REQ must be for the service principal + kadmin/changepw@REALM, where REALM is the REALM of the user who + wishes to change his password. The Ticket in the AP-REQ must be + derived from an AS request (thus having the INITIAL flag set), and + must include a subkey in the Authenticator. + KRB-PRIV message, as described in RFC1510 (variable length) + This KRB-PRIV message must be generated using the subkey in the + Authenticator in the AP-REQ data. The user-data component of the + message must consist of the user's new password. + + The server must verify the AP-REQ message, decrypt the new password, + perform any local policy checks (such as password quality, history, + authorization, etc.) required, then set the password to the new value + specified. + + The principal whose password is to be changed is the principal which + authenticated to the password changing service. This protocol does + not address administrators who want to change passwords of principal + besides their own. + + +Reply Message + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | message length | protocol version number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AP_REP length | AP-REP data / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / KRB-PRIV or KRB-ERROR message / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + message length (16 bits) + + + +Horowitz [Page 2] + +Internet Draft Kerberos Change Password Protocol August, 1998 + + + Contains the length of the message, including this field, in bytes + (big-endian integer), + protocol version number (16 bits) + Contains the hex constant 0x0001 (big-endian integer) + AP-REP length (16 bits) + length of AP-REP data, in bytes. If the the length is zero, then + the last field will contain a KRB-ERROR message instead of a KRB- + PRIV message. + AP-REP data, as described in RFC1510 (variable length) + The AP-REP corresponding to the AP-REQ in the request packet. + KRB-PRIV or KRB-ERROR message, as described in RFC1510 (variable + length) + If the AP-REP length is zero, then this field contains a KRB-ERROR + message. Otherwise, it contains a KRB-PRIV message. This KRB- + PRIV message must be generated using the subkey in the + Authenticator in the AP-REQ data. + + The user-data component of the KRB-PRIV message, or e-data + component of the KRB-ERROR message, must consist of the following + data: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | result code | result string / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + result code (16 bits) + The result code must have one of the following values (big- + endian integer): + 0x0000 if the request succeeds. (This value is not permitted + in a KRB-ERROR message.) + 0x0001 if the request fails due to being malformed + 0x0002 if the request fails due to a "hard" error processing + the request (for example, there is a resource or other + problem causing the request to fail) + 0x0003 if the request fails due to an error in authentication + processing + 0x0004 if the request fails due to a "soft" error processing + the request (for example, some policy or other similar + consideration is causing the request to be rejected). + 0xFFFF if the request fails for some other reason. + Although only a few non-zero result codes are specified here, + the client should accept any non-zero result code as indicating + failure. + result string (variable length) + This field should contain information which the server thinks + might be useful to the user, such as feedback about policy + failures. The string must be encoded in UTF-8. It may be + omitted if the server does not wish to include it. If it is + present, the client should display the string to the user. + This field is analogous to the string which follows the numeric + code in SMTP, FTP, and similar protocols. + + + + +Horowitz [Page 3] + +Internet Draft Kerberos Change Password Protocol August, 1998 + + +Dropped and Modified Messages + + An attacker (or simply a lossy network) could cause either the + request or reply to be dropped, or modified by substituting a KRB- + ERROR message in the reply. + + If a request is dropped, no modification of the password/key database + will take place. If a reply is dropped, the server will (assuming a + valid request) make the password change. However, the client cannot + distinguish between these two cases. + + In this situation, the client should construct a new authenticator, + re-encrypt the request, and retransmit. If the original request was + lost, the server will treat this as a valid request, and the password + will be changed normally. If the reply was lost, then the server + should take care to notice that the request was a duplicate of the + prior request, because the "new" password is the current password, + and the password change time is within some implementation-defined + replay time window. The server should then return a success reply + (an AP-REP message with result code == 0x0000) without actually + changing the password or any other information (such as modification + timestamps). + + If a success reply was replaced with an error reply, then the + application performing the request would return an error to the user. + In this state, the user's password has been changed, but the user + believes that it has not. If the user attempts to change the + password again, this will probably fail, because the user cannot + successfully provide the old password to get an INITIAL ticket to + make the request. This situation requires administrative + intervention as if a password was lost. This situation is, + unfortunately, impossible to prevent. + + +Security Considerations + + This document deals with changing passwords for Kerberos. Because + Kerberos is used for authentication and key distribution, it is + important that this protocol use the highest level of security + services available to a particular installation. Mutual + authentication is performed, so that the server knows the request is + valid, and the client knows that the request has been received and + processed by the server. + + There are also security issues relating to dropped or modified + messages which are addressed explicitly. + + +References + + [RFC1510] Kohl, J. and Neuman, C., "The Kerberos Network + Authentication Service (V5)", RFC 1510, September 1993. + + + + + +Horowitz [Page 4] + +Internet Draft Kerberos Change Password Protocol August, 1998 + + +Author's Address + + Marc Horowitz + Stonecast, Inc. + 108 Stow Road + Harvard, MA 01451 + + Phone: +1 978 456 9103 + Email: marc@stonecast.net + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Horowitz [Page 5] + diff --git a/mechglue/doc/kadmin/kadmin.protocol b/mechglue/doc/kadmin/kadmin.protocol new file mode 100644 index 000000000..5e48945f6 --- /dev/null +++ b/mechglue/doc/kadmin/kadmin.protocol @@ -0,0 +1,382 @@ + +This document references, accompanies and extends the password changing +protocol document, "A Proposal for a Standardized Kerberos Password +Changing Protocol" by Theodore Ts'o. + +Administrative Command Extensions to the Password Changing Protocol +=================================================================== +The following commands and their accompanying definitions are an +extension to the password changing protocol which allow remote +administrative clients to perform functions analogous to those which +are performed using the local database editing utility. These +commands are encoded in the "command request" PDU described in the +password changing protocol, and the server's responses to these +commands are encoded in the "command reply" PDU. + +These commands are (optional commands are marked with an asterisk, new +or changed commands are marked with a plus sign): + ADD-PRINCIPAL + DELETE-PRINCIPAL + RENAME-PRINCIPAL + MODIFY-PRINCIPAL + OTHER-CHANGEPW + OTHER-RANDOM-CHANGEPW + INQUIRE-PRINCIPAL + EXTRACT-KEY (*+) + ADD-KEY (+) + DELETE-KEY (+) + +In order to support these additional commands, the following additional +status codes are also defined: + +Number Symbolic Name Meaning +64 P_ALREADY_EXISTS The specified principal already exists. +65 P_DOES_NOT_EXIST The specified principal does not exist. +66 NOT_AUTHORIZED The access control list on the server prevents + this operation. +67 BAD_OPTION Either: 1) A bad option was specified; 2) A + conflicting set of options would result from + this operation; or 3) Existing options prevent + this type of operation. +68 VALUE_REQUIRED The specified option requires a value. +69 SYSTEM_ERROR A system error occurred while processing a + request. +70(+) KEY_ALREADY_EXISTS The specified key already exists. +71(+) KEY_DOES_NOT_EXIST The specified key does not exist. + +The add principal operation +--------------------------- +o Command String "ADD-PRINCIPAL" +o Arguments + - name of new principal + - either "KEYWORD=value" or "KEYWORD". + . + . + . +o Returns + SUCCESS - operation successful + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not allowed to perform this + P_ALREADY_EXISTS - new principal already exists + BAD_OPTION - bad option supplied + VALUE_REQUIRED - value required with keyword +o Supplemental Returns + NONE - if successful + error message text - if failure +o Description + If the specified principal does not exist, the arguments parse + correctly, and the arguments when combined with defaulted values + do not produce a conflicting set of options then add the specified + principal with the specified attributes. See below for the list of + settable attributes. +o Access Required + Client principal must have ADD_PRINCIPAL permission. + +The delete principal operation +------------------------------ +o Command String "DELETE-PRINCIPAL" +o Argument + - principal to delete +o Returns + SUCCESS - operation successful + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not allowed to perform this + P_DOES_NOT_EXIST - old principal does not exist +o Supplemental returns + NONE - if successful + error message text - if failure +o Description + If the specified principal exists, then delete it from the database. +o Access Required + Client principal must have DELETE_PRINCIPAL permission. + +The rename principal operation +------------------------------ +o Command String "RENAME-PRINCIPAL" +o Arguments + - original name + - new name +o Returns + SUCCESS - operation successful + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not allowed to perform this + P_DOES_NOT_EXIST - old principal does not exist + P_ALREADY_EXISTS - new principal already exists +o Supplemental Returns + NONE - if successful + error message text - if failure +o Description + If the original principal exists and the new principal name does not + exist, rename the original principal to the specified name. +o Access Required + Client principal must have ADD_PRINCIPAL and DELETE_PRINCIPAL + permission. + +The modify principal operation +------------------------------ +o Command String "MODIFY-PRINCIPAL" +o Arguments + - name of principal + - either KEYWORD=value or KEYWORD. + . + . + . +o Returns + SUCCESS - operation successful + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not allowed to perform this + P_DOES_NOT_EXIST - principal doesn't exist + BAD_OPTION - bad option supplied + VALUE_REQUIRED - value required with keyword +o Supplemental returns + NONE - if successful + error message text - if failure +o Description + If the specified principal exists, the arguments parse correctly, and + the arguments when combined with existing values do not produce a + conflicting set of options, then modify the specified principal with + the specified attributes. See below for the list of settable + attributes. +o Access Required + Client principal must have MODIFY_PRINCIPAL permission. + +The change password operation +----------------------------- +o Command String "OTHER-CHANGEPW" +o Arguments + - principal to change password for + - new password +o Returns + SUCCESS - operation successful + PW_UNACCEPT - specified password is bad + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not allowed to perform this + P_DOES_NOT_EXIST - old principal does not exist + BAD_OPTION - principal has a random key +o Supplemental returns + NONE - if successful + error message text - if failure +o Description + If the specified principal exists, and does not have a random key, + then change the password to the specified password. The original + password is NOT required. +o Access Required + Client principal must have CHANGEPW permission. + +The change random password command +---------------------------------- +o Command String "OTHER-RANDOM-CHANGEPW" +o Argument + - principal to change password for +o Returns + SUCCESS - operation successful + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not allowed to perform this + P_DOES_NOT_EXIST - old principal does not exist + BAD_OPTION - principal does not have a random key +o Supplemental Returns + NONE - if successful + error message text - if failure +o Description + If the specified principal exists, and has a random key, then + generate a new random password. The original password is NOT + required. +o Access Required + Client principal must have CHANGEPW permission. + +The inquire principal command +----------------------------- +o Command String "INQUIRE-PRINCIPAL" +o Argument + - name of principal or null argument +o Returns + SUCCESS - operation successful + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not allowed to perform this + P_DOES_NOT_EXIST - principal doesn't exist +o Supplemental Returns + If the return is SUCCESS + - name of next principal in database + - KEYWORD=value list + . + . + . + Otherwise + error message text - if failure +o Description + If a principal is specified, then the database is searched for that + particular principal and its attributes are returned as keyword-value + pairs. If no principal is specified, then the first database entry + is returned. The name of the next principal in the database is always + returned to allow for scanning. See below for the list of attributes + that can be returned. +o Access Required + Client principal must have INQUIRE_PRINCIPAL permission. + +The OPTIONAL extract service key table entry command +---------------------------------------------------- +o Command String "EXTRACT-KEY" +o Arguments + - instance to extract for + - name to extract for +o Returns + SUCCESS - operation successful + CMD_UNKNOWN - operation not supported by server + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not allowed to perform this + P_DOES_NOT_EXIST - principal does not exist +o Supplemental Returns + - if successful + error message text - if failure +o Description + If the specified name/instance exists in the database, then + extract the service key entry and return it in . + The description of follows below. +o Access Required + Client principal must have EXTRACT permission. + +The add key operation +--------------------- +o Command String "ADD-KEY" +o Arguments + - name of the principal + - current password value + - name of the key in the form + :. + . + . + . +o Returns + SUCCESS - operation successful + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not authorized to perform this + KEY_ALREADY_EXISTS - one or more of the specified + keytypes already exist. + BAD_OPTION - bad keytype:saltype specified + BAD_PW - supplied password is incorrect +o Supplemental Returns + NONE - if successful + error message text - if failure +o Description + If the specified principal exists, the keyname(s) parse + correctly the specified password is successfully verified + against the existing key(s), and the specified keyname(s) do + not exist, then these keytype(s) are added to the principal. +o Access Required + Client principal must have MODIFY_PRINCIPAL permission. + +The delete key operation +------------------------ +o Command String "DELETE-KEY" +o Arguments + - name of the principal + - current password value + - name of the key in the form + :, or name of the + key in the form :: + + . + . + . +o Returns + SUCCESS - operation successful + SYSTEM_ERROR - system error + NOT_AUTHORIZED - not authorized to perform this + KEY_DOES_NOT_EXIST - one or more of the specified + keytypes do not exist. + BAD_OPTION - bad keytype:saltype specified + BAD_PW - supplied password is incorrect +o Supplemental Returns + NONE - if successful + error message text - if failure +o Description + If the specified principal exists, the keyname(s) parse + correctly the specified password is successfully verified + against the existing key(s), and the specified keyname(s) + exist, then they are deleted from the principal. +o Access Required + Client principal must have MODIFY_PRINCIPAL permission. + +Keywords +-------- +The following list of keywords are used for the ADD-PRINCIPAL and +MODIFY-PRINCIPAL commands and are returned from the +INQUIRE-PRINCIPAL command. + +Valid Keyword Value Type Value +------- --------------- --------------- -------------------------------------- + (S) PASSWORD New password. + (SR) MAXLIFE The maximum lifetime of tickets for + this principal in seconds. + (SR) MAXRENEWLIFE The maximum renewable lifetime of + tickets for this principal in seconds. + (SR) EXPIRATION When the new principal expires. + (SR) PWEXPIRATION When the password expires for this + principal. + (SR) RANDOMKEY Specifies that this is to have a + random key generated for it. + (SR) FLAGS Specifies flag value for this + principal's attributes field in the + database. + (R) LASTSUCCESS Last successful password entry. + (R) LASTFAILED Last failed password attempt. + (R) FAILCOUNT Number of failed password attempts. + (SR) AUXDATA Tagged auxiliary value (see below) + (R) KEYDATA Key value (see below) + (SR) EXTRADATA Extra data (see below) + +The valid field indicates whether an attribute is Settable (e.g. appropriate +for use with ADD-PRINCIPAL, et. al.; Returnable (e.g. returned by +INQUIRE-PRINCIPAL); or both Settable and Returnable. + +o +The type denotes data which is stored in the database as a +tagged value. The protocol representation consists of a 4-byte network order +integer to denote the tag with the remaining data providing the value. If +encoded data is to be encapsulated, it must be in network order. In summary: + AUXDATA= +For example, to encode the value for tag 1 with a 4-byte value of 32 71 1e 30 +in network order, the encoding would be: + AUXDATA=00 00 00 01 32 71 1e 30 + +o +The type denotes data which is stored in the database on a per-key +basis. The protocol representation is consists of a 4-byte network order +integer to denote a particular key. This integer is implementation dependent +and is only used to correlate different entries. This integer +is followed by a 4-byte network order integer which denotes the attribute type. +Currently, only three are supported: -1 denotes the key version; 1 denotes the +key type and 2 denotes the salt type. This attribute type integer is followed +by the attribute value and an optional per-attribute value. In summary: + KEYDATA=[] +For example, to encode the value of a key with keytype 3, salttype 5, with key +version number 32, key data of 12 34 56 78 90 ab cd ef and salt data of f0 e1 +d2 c3 b4 a5 96 87, the encoding would be (using key-tag de ad be ef): + (key version number 32) + KEYDATA=de ad be ef ff ff ff ff 00 00 00 20 + (key keytype 3, value 1234567890abcdef) + KEYDATA=de ad be ef 00 00 00 01 00 00 00 03 12 34 56 78 90 ab cd ef + (key salttype 5, value f0e1d2c3b4a59687) + KEYDATA=de ad be ef 00 00 00 02 00 00 00 05 f0 e1 d2 c3 b4 a5 96 87 + +o +The type is exactly that. Unspecified. Any data may be encoded +here without restriction. + +Keytab Entry +------------ +If the EXTRACT SERVICE KEY function is supported, then the successful +response to this command is the key entry. This is a series of 6 +reply components as follows: + +component type value +--------- --------------- ----------------------------------------- + 1 Principal name + 2 Key entry timestamp + 3 Key's version number. + 4 Key's keytype. + 5 Key's encryption type. + 6 Key's key value. + +All of these components are mandatory. + diff --git a/mechglue/doc/kadmin/kpasswd.protocol b/mechglue/doc/kadmin/kpasswd.protocol new file mode 100644 index 000000000..7d77a2183 --- /dev/null +++ b/mechglue/doc/kadmin/kpasswd.protocol @@ -0,0 +1,303 @@ + + + + A Proposal for a Standardized + Kerberos Password Changing Protocol + + **DRAFT** **DRAFT** **DRAFT** + + by Theodore Ts'o + September 7, 1995 + +Rationale +========= + +Currently, the Kerberos administration server which is being shipped +with the Beta Kerberos V5 distributions from MIT has not been of +sufficient quality for vendors to ship it in their products. Hence, +many vendors are creating and deploying proprietary administration +servers. In general, this is not a big problem --- relatively few +users are Kerberos administrators and thus the Kerberos administration +clients are used by relatively few users. + +There is a big exception to this, however, which is the functionality of +a user being able to change his or her own password. Application +programs may want to include this functionality in their programs; it +would be desireable for there to be a standardized protocol for doing +this. Standardized Kerberos desktop management programs (such as +Cornell's Authman) would also benefit from a standardized protocol; this +way, they will do not need to implement many vendor-specific Kerberos +administration protocols. Similarily, at least one terminal server +vendor has come to expressing their concern that there was not a +standardized password changing protocol, since they wanted their product +to offer this functionality. + +This protocol is designed to address these concerns. + + +Protocol Description +==================== + +The protocol used by the password changing protocol is intentionally +very simple. This is to encourage its widespread implementation, even +in cases where there are size constraints (i.e., in a terminal server). + +The protocol will use a TCP stream connection using port 464. The +symbolic name of this port is kpasswd: + + kpasswd 464/tcp + + +The following encoding standards are used throughout. + +Integers are sent as 4 byte objects, where the most significant byte +is sent first, and the least signifcant byte is sent last. (i.e., +standard Internet network byte order.) + +Protocol data units (PDU's) are sent across using the following +encoding. First, the size of the PDU is sent as a 4 byte integer, +followed by the PDU itself. PDU's used by the protocol will be either a +KRB_AP_REQ message, a KRB_AP_REP message, a "command request" PDU, or a +"command response" PDU. (The last two PDU's are encoded using a +KRB_PRIV message. For definitions of the KRB_AP_REQ, KRB_AP_REP, and +KRB_PRIV message, see the Kerberos V5 protocol specification found in +RFC 1510.) + +The PDU's which are encoded using the KRB_PRIV message must include the +sequence number field --- the client and server must fill in each +successive PDU that it sends with a monotonically increasing sequence +number. The initial sequence number in each direction are negotiated in +the KRB_AP_REQ and KRB_AP_REP messages. + +The size of a Protoocl Data Unit SHOULD not exceed 16,384 bytes. If an +implementation receives a PDU which is larger that 16,384 bytes, the +implementation MAY consider this a fatal error and terminate the TCP +connection. An implementation MUST be able to receive PDU's of at least +16,384 bytes. + +The "command request" PDU +------------------------- + +The "command request" PDU is sent from the client to server. This PDU +uses the following structure: First, the number of arguments, sent +across as an integer. The number of arguments MUST be greater than +zero. It is then followed by the arguments themselves, which are +encoded as an integer length followed by the value of the argument. + +The first argument is "command name". The command name is a NETASCII +string, and it may not contain an ASCII null. Command names are case +insentive. Valid command names are defined below; any site-, or vendor- +specific extensions to this protocol should use command names which +begin with the letter 'X'. + +The other arguments (if any) are dependent on the command specified by +the first argument. + +In other words: + + Number of Arguments (integer, must be greater than zero) + Arg size 1 (integer) + Arg data 1 (octet string, command name) + ... + Arg size N (integer) + Arg data N (octet string) + +This structure is then encrypted using the Kerberos V5 KRB_PRIV message. + +The "command reply" PDU +----------------------- + +In response to a "command request" PDU, the server will send to the +client a "command reply" PDU. The structure of a "command reply" PDU is +as follows: + + status code (integer) + Number of reply components (integer, may be zero) + Arg size 1 (integer) + Arg data 1 (octet string) + ... + Arg size N (integer) + Arg data N (octet string) + +This structure is then encrypted using the Kerberos V5 KRB_PRIV message. + +The status code may be one of the following values: + +# Symbolic name Meaning + +0 SUCCESS The command was executed without any errors +1 CMD_UNKNOWN Command not recognized +2 PW_UNACCEPT The password chosen by the user is unnacceptable. +3 BAD_PW The old password furnished by the user is not correct. +4 NOT_IN_TKT The ticket used to authenticate to the server + did not have the TKT_FLAG_INITIAL flag set. +5 CANT_CHANGE The server is not able to change the password + due to no fault of the user. (For + example, the database may be in + read-only mode for maintance reasons.) +6 LANG_NOT_SUPPORTED The requested language is not supported. + +The error codes below 127, and above 256 are reserved for future +expansion. Local extensions of this protocol should use error codes +between 128 and 255. + +The user text in the reply message is generally some sort of +explanatory text, which should be displayed to the user. + + +Connection Establishment +======================== + +When a connection is made the password changing client exchanges the +following PDU's: + +Client Server +------ ------ + +KRB_AP_REQ -------> + + <------- KRB_AP_REP + +KRB_AP_REQ and KRB_AP_REP are the respective Kerberos V5 messages. The +client will autenticate to the server using the service name +changepw/@, where should be +substituted with the name of the Kerberos realm of the password changing +server. The client MUST set the MUTUAL-REQUIRED flag in the KRB_AP_REQ +message, which indicates that server shall send a KRB_AP_REP message for +the purposes of establishing mutual authentication between the client +and the server. + +Protocol Commands +================== + +After the connection is established, the client may then send any +number of "command request" PDUs; after each command request PDU is +sent, the client should wait for a "command reply" PDU from the +server. + +If after 30 seconds inactivity, the client does not send a "command +request" PDU, the server MAY elect to terminate the TCP connection. + +The following commands defined in this standard: + + QUIT + CHECKPW + CHANGEPW + MOTD (*) + MIME (*) + LANGUAGE (*) + +The commands marked with a (*) are optional; servers may or may not +elect to support these commands. If the commands are not supported, the +server shall return a status code of CMD_UNKNOWN. + +The quit command +---------------- + +The name of this command is "QUIT", and it takes no arguments. The +response to this command must be the error code "NO_ERROR". There may +be an optional reply component, which will consist of user text which +should be displayed to the user. After processing this command, the +server will terminate the connection. + +Kerberos password changing servers MUST implement this command. + + +The check password command +--------------------------- + +The name of this command is "CHECKPW", and it takes one argument, +which is a proposed password. The server will evaluate this password +according to its criteria and return either an NO_ERROR or PW_UNACCEPT +error code. + +There may be an optional reply component which consists of user text +which should be displayed to the user. It will typically explain why +the password was unacceptable. + +Kerberos password changing servers MUST implement this command. + + +The change password command +--------------------------- + +The name of this command is "CHANGEPW", and it takes two arguments. The +first argument is the old password, and the second password is the new +password. The response from this command will generally be one of the +following error codes: NO_ERROR, PW_UNACCEPT, BAD_PW, NOT_IN_TKT, +CANT_CHANGE. + +This command changes the password of the Kerberos principal which the +client used to authenticate to the server. For security reasons, the +server should check to make sure that the ticket used to authenticate to +the server had the TKT_FLG_INITIAL flag set; if this flag is not set in +the ticket, then when the client attempts to use the "CHANGEPW" command, +the server should return the NOT_IN_TKT error. + +There may be an optional reply component which consists of user text +which should be displayed to the user, explaining why the password was +unacceptable or why the user's password could not be changed. + +Kerberos password changing servers MUST implement this command. + + +The Message of the Day command +------------------------------ + +The name of this command is "MOTD", and it takes zero or one additional +arguments. The optional argument is a magic token passed back from a +previous MOTD command. If this magic token is sent, the server MAY use +it to determine use it to determine what (if any) messages should be +displayed to the user. + +This command returns one or two reply components. The first reply +component is a magic token; the magic token shall be a NETASCII string +which may not contain an ASCII null character, and its length shall be +less than 64 characters. A client MAY store this magic token between +invocations of the client, and send it to the server the next time the +MOTD command is requested. + +The second (optional) reply component contains text which should be +displayed to the user. + +Kerberos password changing servers MAY optionally implement this command. + + +The MIME command +---------------- + +The name of this command is "MIME", and it takes zero additional +arguments. + +This command indicates that the client is willing to accept +MIME-enhanced textual messages in place of the standard NETASCII textual +messages. + +If this command is not sent, the server MUST send all textual messages +using NETASCII, with used as a line breaks, and line lengths no +more than 80 characters. If this command is sent, and the server +returns a status code of SUCCESS, the server MUST send textual messages +as MIME-enhanced textual messages. The server may refuse to send MIME +messages by sending a status code of CMD_UNKNOWN. + +Kerberos password changing servers MAY optionally implement this command. + + +The Language Command +--------------------- + +The name of this command is "LANGUAGE", and it takes one additional +argument, which indicates the language that the textual messages should +be sent back in. This additional argument must be consist of NETASCII +characters, with ASCII nulls not allowed. The argument shall be case +insensitive. What constitute valid arguments to this command are a +local matter. [Since ISO apparently doesn't have a standard way of +referring to different languages or dialects.] + +This command indicates that the client would prefer that textual +messages be sent back using the requested language. If the server does +not support the requested language, the server may refuse the request by +sending the error code LANG_NOT_SUPPORTED. + +Kerberos password changing servers MAY optionally implement this command. + diff --git a/mechglue/doc/kdcconf.texinfo b/mechglue/doc/kdcconf.texinfo new file mode 100644 index 000000000..51583714e --- /dev/null +++ b/mechglue/doc/kdcconf.texinfo @@ -0,0 +1,24 @@ +The @code{kdc.conf} file contains KDC configuration information, +including defaults used when issuing Kerberos tickets. Normally, you +should install your @code{kdc.conf} file in the directory +@code{@value{ROOTDIR}/var/krb5kdc}. You can override the default +location by setting the environment variable @samp{KRB5_KDC_PROFILE}. + +The @code{kdc.conf} file is set up in the same format as the +@code{krb5.conf} file. (@xref{krb5.conf}.) The @code{kdc.conf} file +may contain any or all of the following three sections: + +@table @b +@item kdcdefaults +Contains default values for overall behavior of the KDC. + +@item realms +Contains subsections keyed by Kerberos realm names. Each subsection +describes realm-specific information, including where to find the +Kerberos servers for that realm. + +@item logging +Contains relations which determine how Kerberos programs are to perform +logging. +@end table + diff --git a/mechglue/doc/krb4-xrealm.txt b/mechglue/doc/krb4-xrealm.txt new file mode 100644 index 000000000..f8c4566e5 --- /dev/null +++ b/mechglue/doc/krb4-xrealm.txt @@ -0,0 +1,143 @@ +The following text was taken from the patchkit disabling cross-realm +authentication and triple-DES in krb4. + +PATCH KIT DESCRIPTION +===================== + +** FLAG DAY REQUIRED ** + +One of the things we decided to do (and must do for security reasons) +was drop support for the 3DES krb4 TGTs. Unfortunately the current +code will only accept 3DES TGTs if it issues 3DES TGTs. Since the new +code issues only DES TGTs, the old code will not understand its v4 +TGTs if the site has a 3DES key available for the krbtgt principal. +The new code will understand and accept both DES and 3DES v4 TGTs. + +So, the easiest upgrade option is to deploy the code on all KDCs at +once, being sure to deploy it on the master KDC last. Under this +scenario, a brief window exists where slaves may be able to issue +tickets that the master will not understand. However, the slaves will +understand tickets issued by the master throughout the upgrade. + +An alternate and more annoying upgrade strategy exists. At least one +max TGT life time before the upgrade, the TGT key can be changed to be +a single-des key. Since we support adding a new TGT key while +preserving the old one, this does not create an interruption in +service. Since no 3DES key is available then both the old and new +code will issue and accept DES v4 TGTs. After the upgrade, the TGT +key can again be rekeyed to add 3DES keys. This does require two TGT +key changes and creates a window where DES is used for the v5 TGT, but +creates no window in which slaves will issue TGTs the master cannot +accept. + +* What the patch does +===================== + +1) Kerberos 4 cross-realm authentication is disabled by default. A + "-X" switch is added to both krb524d and krb5kdc to enable v4 + cross-realm. This switch logs a note that a security hole has been + opened in the KDC log. We said while designing the patch, that we + were going to try to allow per-realm configuration; because of a + design problem in the kadm5 library, we could not do this without + bumping the ABI version of that library. We are unwilling to bump + an ABI version in a security patch release to get that feature, so + the configuration of v4 cross-realm is a global switch. + +2) Code responsible for v5 TGTs has been changed to require that the + enctype of the ticket service key be the same as the enctype that + would currently be issued for that kvno. This means that even if a + service has multiple keys, you cannot use a weak key to fake the + KDC into accepting tickets for that service. If you have a non-DES + TGT key, this separates keys used for v4 and v5. We actually relax + this requirement for cross-realm TGT keys (which in the new code + are only used for v5) because we cannot guarantee other Kerberos + implementations will choose keys the same way. + +3) We no longer issue 3DES v4 tickets either in the KDC or krb524d. + We add code to accept either DES or 3DES tickets for v4. None of + the attacks discovered so far can be implemented given a KDC that + accepts but does not issue 3DES tickets, so we believe that leaving + this functionality in as compatibility for a version or two is + reasonable. Note however that the attacks described do allow + successful attackers to print future tickets, so sites probably + want to rekey important keys after installing this update. Note + also that even if issuance of 3DES v4 tickets has been disabled, + outstanding tickets may be used to perform the 3DES cut-and-paste + attack. + +* Test Cases +============ + +This code is difficult to test for two reasons. First, you need a +cross-realm relationship between two KDCs. Secondly, you need a KDC +that will issue 3DES v4 tickets even though the code with the patch +applied can no longer do this. + +I propose to meet these requirements by setting up a cross-realm 3DES +key between a realm I control and the test environment. In order to +provide concrete examples of what I plan to test with the automated +tests, I assume a shared key between a realm PREPATCH.KRBTEST.COM and the +test realm PATCH. + +In all of the following tests I assume the following configuration. +A principal v4test@PREPATCH.KRBTEST.COM exists with known password and +without requiring preauthentication. The PREPATCH.KRBTEST.COM KDC will +issue v4 tickets for this principal. A principal test@PATCH exists +with known password and without requiring preauthentication. A +principal service@PATCH exists. The TGT for the PATCH realm has a +3des and des key. The shared TGT keys between PATCH and +PREPATCH.KRBTEST.COM are identical in both directions (required for v4) and +support both 3DES and DES keys. + +1) Run krb524d and krb5kdc for PATCH with no special options using a + krb5.conf without permitted_enctypes (fully permissive). + + +A) Get v4 tickets as v4test@PREPATCH.KRBTEST.COM. Confirm that kvno -4 +service@PATCH fails with an unknown principal error and logs an error +about cross-realm being denied to the PATCH KDC log. This confirms +that v4 cross-realm is not accepted. + +B) Get v5 tickets as v4test@PREPATCH.KRBTEST.COM. Confirm that krb524init +-p service@PATCH fails with a prohibited by policy error, but that +klist -5 includes a ticket for service@PATCH. This confirms that v5 +cross-realm works but the krb524d denies converting such a ticket into +a cross-realm ticket. Note that the krb524init currently in the +mainline source tree will not be useful for this test because the +client denies cross-realm for the simple reason that the v4 ticket +file format is not flexible enough to support it. The krb524init in +the 1.2.x release is useful for this test. + + +2) Restart the krb5kdc and krb524d for PATCH with the -X option + enabling v4 cross-realm. + +A) Confirm that the security warning is written to kdc.log. + +B) Get v4 tickets as v4test@PREPATCH.KRBTEST.COM. Confirm that kvno -4 +service@PATCH works and leaves a service@PATCH ticket in the cache. +This confirms that v4 cross-realm works in the KDC. It also confirms +that the KDC can accept 3DES v4 TGTs. The code path for decrypting a +TGT is the same for the local realm and for foreign realms, so I don't +see a need to test local 3DES TGTs in an automated manner although I +did test it manually. + +C) Get v5 tickets as v4test@PREPATCH.KRBTEST.COM. Confirm that krb524init +-p service@PATCH works. This confirms that krb524d will issue +cross-realm tickets. They're completely useless because the v4 ticket +file can't represent them, but that's not our problem today. + +3) Start the kdc and krb524d with a krb5.conf that includes + permitted_enctypes only listing des-cbc-crc. Get tickets as + test@PATCH. Restart the KDC and confirm that kvno service fails + logging an error about permitted enctypes. This confirms that if + you manage to obtain a ticket of the wrong enctype it will not be + accepted later. + +These tests do not check to make sure that 3DES tickets are not +issued by the v4 code. I'm fairly certain that is true as I've +physically remove the calls to the routine that generates 3DES tickets +from the code in both the KDC and krb524d. These tests also do not +check to make sure that cross-realm TGTs are not required to follow +the strict enctype policy. I've tested that manually but don't know +how to test that without significantly complicating the test setup. diff --git a/mechglue/doc/krb425.texinfo b/mechglue/doc/krb425.texinfo new file mode 100644 index 000000000..7a7a80862 --- /dev/null +++ b/mechglue/doc/krb425.texinfo @@ -0,0 +1,317 @@ +\input texinfo @c -*-texinfo-*- +@c Note: the above texinfo file must include the "doubleleftarrow" +@c definitions added by jcb. +@c %**start of header +@c guide +@setfilename krb425.info +@settitle Upgrading to Kerberos V5 from Kerberos V4 +@c @setchapternewpage odd @c chapter begins on next odd page +@c @setchapternewpage on @c chapter begins on next page +@c @smallbook @c Format for 7" X 9.25" paper +@c %**end of header + +@paragraphindent 0 +@iftex +@parskip 6pt plus 6pt +@end iftex + +@include definitions.texinfo +@set EDITION 1.0 +@set UPDATED May 22, 2003 + +@finalout @c don't print black warning boxes + +@titlepage +@title Upgrading to @value{PRODUCT} from Kerberos V4 +@subtitle Release: @value{RELEASE} +@subtitle Document Edition: @value{EDITION} +@subtitle Last updated: @value{UPDATED} +@author @value{COMPANY} + +@page +@vskip 0pt plus 1filll + +@end titlepage + +@node Top, Copyright, (dir), (dir) + +@ifinfo +This document describes how to convert to @value{PRODUCT} from Kerberos V4. +@end ifinfo + +@menu +* Copyright:: +* Introduction:: +* Configuration Files:: +* Upgrading KDCs:: +* Upgrading Application Servers:: +* Upgrading Client machines:: +* Firewall Considerations:: +@end menu + +@node Copyright, Introduction, Top, Top +@unnumbered Copyright +@include copyright.texinfo + +@node Introduction, Configuration Files, Copyright, Top +@chapter Introduction + +As with most software upgrades, @value{PRODUCT} is generally backward +compatible but not necessarily forward compatible. The @value{PRODUCT} +daemons can interoperate with Kerberos V4 clients, but most of the +Kerberos V4 daemons can not interoperate with Kerberos V5 clients. This +suggests the following strategy for performing the upgrade: + +@enumerate +@item +@strong{Upgrade your KDCs.} This must be done first, so that +interactions with the Kerberos database, whether by Kerberos V5 clients +or by Kerberos V4 clients, will succeed. + +@item +@strong{Upgrade your servers.} This must be done before upgrading +client machines, so that the servers are able to respond to both +Kerberos V5 and Kerberos V4 queries. + +@item +@strong{Upgrade your client machines.} Do this only after your KDCs and +application servers are upgraded, so that all of your Kerberos V5 +clients will be talking to Kerberos V5 daemons. +@end enumerate + +@node Configuration Files, Upgrading KDCs, Introduction, Top +@chapter Configuration Files + +The Kerberos @code{krb5.conf} and KDC @code{kdc.conf} configuration +files allow additional tags for Kerberos V4 compatibility. + +@menu +* krb5.conf:: +* kdc.conf:: +@end menu + +@node krb5.conf, kdc.conf, Configuration Files, Configuration Files +@section krb5.conf + +If you used the defaults, both when you installed Kerberos V4 and when +you installed @value{PRODUCT}, you should not need to include any of +these tags. However, some or all of them may be necessary for +nonstandard installations. + +@menu +* libdefaults:: +* realms (krb5.conf):: +* AFS and the Appdefaults Section:: +@end menu + +@node libdefaults, realms (krb5.conf), krb5.conf, krb5.conf +@subsection [libdefaults] + +In the [libdefaults] section, the following additional tags may be used: + +@table @b +@item krb4_srvtab +Specifies the location of the Kerberos V4 srvtab file. Default is +@value{DefaultKrb4Srvtab}. + +@item krb4_config +Specifies the location of the Kerberos V4 configuration file. Default +is @value{DefaultKrb4Config}. + +@item krb4_realms +Specifies the location of the Kerberos V4 domain/realm translation +file. Default is @value{DefaultKrb4Realms}. +@end table + +@node realms (krb5.conf), AFS and the Appdefaults Section, libdefaults, krb5.conf +@subsection [realms] + +In the [realms] section, the following Kerberos V4 tags may be used: +@table @b +@itemx default_domain +Identifies the default domain for hosts in this realm. This is needed +for translating V4 principal names (which do not contain a domain name) +to V5 principal names. The default is your Kerberos realm name, +converted to lower case. + +@itemx v4_instance_convert +This subsection allows the administrator to configure exceptions to the +default_domain mapping rule. It contains V4 instances (tag name) which +should be translated to some specific hostname (tag value) as the second +component in a Kerberos V5 principal name. + +@itemx v4_realm +This relation allows the administrator to configure a different +realm name to be used when converting V5 principals to V4 +ones. This should only be used when running separate V4 and V5 +realms, with some external means of password sychronization +between the realms. + +@end table + +@node AFS and the Appdefaults Section, , realms (krb5.conf), krb5.conf +@subsection AFS and the Appdefaults Section + +Many Kerberos 4 sites also run the Andrew File System (AFS). + +Modern AFS servers (OpenAFS > 1.2.8) support the AFS 2b token format. +This allows AFS to use Kerberos 5 tickets rather than version 4 +tickets, enabling cross-realm authentication. By default, the +@file{krb524d} service will issue the new AFS 2b tokens. If you are +using old AFS servers, you will need to disable these new tokens. +Please see the documentation of the @code{appdefaults} section of +@file{krb5.conf} in the Kerberos Administration guide. + + + +@node kdc.conf, , krb5.conf, Configuration Files +@section kdc.conf + +Because Kerberos V4 requires a different type of salt for the encryption +type, you will need to change the @code{supported_enctypes} line in the +[realms] section to: + +@smallexample +supported_enctypes = des-cbc-crc:normal des-cbc-crc:v4 +@end smallexample + +This is the only change needed to the @code{kdc.conf} file. + +@node Upgrading KDCs, Upgrading Application Servers, Configuration Files, Top +@chapter Upgrading KDCs + +To convert your KDCs from Kerberos V4 to @value{PRODUCT}, do the +following: + +@enumerate +@item +Install @value{PRODUCT} on each KDC, according to the instructions in +the @value{PRODUCT} Installation Guide, up to the point where it tells +you to create the database. + +@item +Find the @code{kadmind} (V4) daemon process on the master KDC and kill +it. This will prevent changes to the Kerberos database while you +convert the database to the new Kerberos V5 format. + +@item +Create a dump of the V4 database in the directory where your V5 database +will reside by issuing the command: + +@smallexample +% kdb_util dump @value{ROOTDIR}/var/krb5kdc/v4-dump +@end smallexample + +@item +Load the V4 dump into a Kerberos V5 database, by issuing the command: + +@smallexample +% kdb5_util load_v4 v4-dump +@end smallexample + +@item +Create a Kerberos V5 stash file, if desired, by issuing the command: + +@smallexample +% kdb5_util stash +@end smallexample + +@item +Proceed with the rest of the @value{PRODUCT} installation as described +in the @value{PRODUCT} Installation Guide. When you get to the section +that tells you to start the @code{krb5kdc} and @code{kadmind} daemons, +first find and kill the Kerberos V4 @code{kerberos} daemon on each of +the KDCs. Then start the @code{krb5kdc} and @code{kadmind} daemons as +You will need to specify an argument to the @code{-4} command line option to enable Kerberos 4 compatibility. +See the @code{krb5kdc} man page for details. +directed. Finally, start the Kerberos V5 to V4 ticket translator +daemon, @code{krb524d}, by issuing the command: + +@smallexample +% @value{ROOTDIR}/sbin/krb524d -m > /dev/null & +@end smallexample + +If you have a stash file and you start the @code{krb5kdc} and +@code{kadmind} daemons at boot time, you should add the above line to +your @code{/etc/rc} (or @code{/etc/rc.local}) file on each KDC. +@end enumerate + +@node Upgrading Application Servers, Upgrading Client machines, Upgrading KDCs, Top +@chapter Upgrading Application Servers + +Install @value{PRODUCT} on each application server, according to the +instructions in the @value{PRODUCT} Installation Guide, with the +following exceptions: + +@itemize @bullet +@item +In the file @code{/etc/services}, add or edit the lines described in the +@value{PRODUCT} Installation Guide, with the following exception: + +in place of: + +@smallexample +@group +kerberos @value{DefaultPort}/udp kdc # Kerberos V5 KDC +kerberos @value{DefaultPort}/tcp kdc # Kerberos V5 KDC +@end group +@end smallexample + +@noindent +add instead: + +@smallexample +@group +kerberos-sec @value{DefaultPort}/udp kdc # Kerberos V5 KDC +kerberos-sec @value{DefaultPort}/tcp kdc # Kerberos V5 KDC +@end group +@end smallexample + +@item +Convert your Kerberos V4 srvtab file to Kerberos V5 keytab file as +follows: + +@smallexample +@group +@b{#} @value{ROOTDIR}/sbin/ktutil +@b{ktutil:} rst /etc/krb-srvtab +@b{ktutil:} wkt /etc/krb5.keytab +@b{ktutil:} q +@b{#} +@end group +@end smallexample +@end itemize + +@node Upgrading Client machines, Firewall Considerations, Upgrading Application Servers, Top +@chapter Upgrading Client machines + +Install @value{PRODUCT} on each client machine, according to the +instructions in the @value{PRODUCT} Installation Guide. + +Tell your users to add the appropriate directory to their paths. On +UNIX machines, this will probably be @code{@value{BINDIR}}. + +Note that if you upgrade your client machines before all of your +application servers are upgraded, your users will need to use the +Kerberos V4 programs to connect to application servers that are still +running Kerberos V4. (The one exception is the UNIX version of +@value{PRODUCT} telnet, which can connect to a Kerberos V4 and Kerberos +V5 application servers.) Users can use either the Kerberos V4 or +@value{PRODUCT} programs to connect to Kerberos V5 servers. + +@node Firewall Considerations, , Upgrading Client machines, Top +@chapter Firewall Considerations + +@value{PRODUCT} uses port @value{DefaultPort}, which is the port +assigned by the IETF, for KDC requests. Kerberos V4 used port +@value{DefaultSecondPort}. If your users will need to get to any KDCs +outside your firewall, you will need to allow TCP and UDP requests on +port @value{DefaultPort} for your users to get to off-site Kerberos V5 +KDCs, and on port @value{DefaultSecondPort} for your users to get to +off-site Kerberos V4 KDCs. + +@contents +@c second page break makes sure right-left page alignment works right +@c with a one-page toc, even though we don't have setchapternewpage odd. +@c end of texinfo file +@bye diff --git a/mechglue/doc/krb5-protocol/.Sanitize b/mechglue/doc/krb5-protocol/.Sanitize new file mode 100644 index 000000000..d37d1b7f1 --- /dev/null +++ b/mechglue/doc/krb5-protocol/.Sanitize @@ -0,0 +1,35 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +krb5.constants +rfc1510.errata +rfc1510.txt +3-des.txt + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/mechglue/doc/krb5-protocol/3-des.txt b/mechglue/doc/krb5-protocol/3-des.txt new file mode 100644 index 000000000..ce6484547 --- /dev/null +++ b/mechglue/doc/krb5-protocol/3-des.txt @@ -0,0 +1,81 @@ +For inclusion into RFC 1510 +--------------------------- +The assigned encryption type designating the use of triple DES is 5. + +The assigned checksum type designating the use of encrypting and MD5 +checksum with triple DES keys is 9. + +Triple DES is implemented using three DES keys. An Electronic CodeBook +encryption (3-DES ECB) is done by doing a DES ECB encryption of an eight +octet data block with the first DES key, performing a DES ECB decryption +of the resulting data block with the second key and performing a DES ECB +encryption of the result with the third key. + +The encryption of a data stream in Cipher Block Chaining mode is +accomplished by eXclusive-ORing each eight-octet data block with the +cipher computed from the previous data block, and then performing a +3-DES ECB encryption. The first data block is eXclusive-ORed with an +initial vector, which is commonly zero prior to performing the 3-DES +ECB. + +The string-to-key algorithm that is used for converting a user's +password into a 3-DES key is a one-way function, evenly distributing the +user's input in the resulting key. The user's input is appended with +the salt information (typically the realm name), and 168-folded to +produce three DES keys sans parity. The 168 bits are then expanded to +include odd parity, for use within the DES routines. If any of the keys +are weak or semi-weak, they are strengthened by eXclusive-ORing the +questionable key with the constant 00000000000000F0. The three DES keys +are then used to encrypt themselves in 3-DES CBC mode with a zero +initial vector. This result is once again encrypted using the same keys +and key schedule and an initial vector of the last eight octets. The +result is then parity adjusted. If the final result yields weak or +semi-weak keys, they are also strengthened in the same manner as the +input keys. + +The n-fold operation used by the string-to-key algorithm +replicates the input bit array X until its length is the least common +multiple of n bits and the length of X. Before each replication, the +input is circularly rotated to the right by 13 bit positions. The +successive n-bit chunks of the resulting bit array are then added +together with end-around carry to yield a n-bit result. The first bit +position in the arrays is treated as the most significant bit. + + + +Glossary +-------- +n-fold + To n-fold a bit array X into n bits, replicate the input value to a length + that is the least common multiple of n bits and the length of X. Before + each successive repetition, circularly rotate the input X to the right by + 13 bit positions. The successive n-bit chunks are added together (where + the first bit is the most significant bit) with end-around carry (that is, + adding the carry result from the most significant bits to the least + significant bits) to yield a n-bit result. + +Triple-DES ECB mode: + + Three DES keys are used in turn to perform a DES ECB encryption of an + eight-octet data block with the first key, followed by a DES ECB + decryption of the resulting data block with the second key, followed + by a DES ECB encryption of the resulting data block with the last key. + +Triple-DES CBC mode: + An input data stream is padded on the right by zeroes to an eight-octet + boundary. The first eight octet block is eXclusive-ORed with an initial + vector eight-octet block. This result is triple-DES ECB encrypted with + three DES keys. Subsequent eight-octet data blocks are eXclusive-ORed + with the cipher text produced from the 3-DES ECB encryption of the previous + block and then the data block is 3-DES ECB encrypted with the same DES keys. + +Triple-DES String to key computation: + The input string (appended with any salt data) is 168-folded into a 21 octet + (168 bit) string. Each successive set of 7 octets is treated as a DES key + sans parity. The DES keys are then adjusted to include parity by computing + a parity bit for each successive seven bits to form eight octets. + The resulting DES keys including parity are then used to encrypt themselves + using Triple-DES CBC encryption with a zero initial vector. The result + is then adjusted for parity to produce three valid DES keys. Each key is + checked for weakness, and if it is determined to be weak or semi-weak, the + first octet of each weak key is eXclusive-ORed with the value 0xF0. diff --git a/mechglue/doc/krb5-protocol/krb5.constants b/mechglue/doc/krb5-protocol/krb5.constants new file mode 100644 index 000000000..e7cc5b80e --- /dev/null +++ b/mechglue/doc/krb5-protocol/krb5.constants @@ -0,0 +1,156 @@ +8.3. Protocol constants and associated values + + The following tables list constants used in the protocol and defines + their meanings. + + +---------------+-----------+----------+----------------+--------------- +Encryption type|etype value|block size|minimum pad size|confounder size +---------------+-----------+----------+----------------+--------------- +NULL 0 1 0 0 +des-cbc-crc 1 8 4 8 +des-cbc-md4 2 8 0 8 +des-cbc-md5 3 8 0 8 + 4 +des3-cbc-md5 5 8 0 8 + 6 +des3-cbc-sha1 7 8 0 8 + 0x8003 + +-------------------------------+-------------------+------------- +Checksum type |sumtype value |checksum size +-------------------------------+-------------------+------------- +CRC32 1 4 +rsa-md4 2 16 +rsa-md4-des 3 24 +des-mac 4 16 +des-mac-k 5 8 +rsa-md4-des-k 6 16 +rsa-md5 7 16 +rsa-md5-des 8 24 + 9 + 10 +nist-sha1 11 20 +hmac-sha1-des3 12 20 + +-------------------------------+----------------- +padata type |padata-type value +-------------------------------+----------------- +PA-TGS-REQ 1 +PA-ENC-TIMESTAMP 2 +PA-PW-SALT 3 + 4 +PA-ENC-UNIX-TIME 5 +PA-SANDIA-SECUREID 6 +PA-SESAME 7 +PA-OSF-DCE 8 +PA-CYBERSAFE-SECUREID 9 +PA-AFS3-SALT 10 +PA-ETYPE-INFO 11 +PAM-SAM-CHALLENGE 12 +PAM-SAM-RESPONSE 13 + +-------------------------------+------------- +authorization data type |ad-type value +-------------------------------+------------- +reserved values 0-63 +AD-OSF-DCE 64 +AD-SESAME 65 + +-------------------------------+----------------- +alternate authentication type |method-type value +-------------------------------+----------------- +reserved values 0-63 +ATT-CHALLENGE-RESPONSE 64 + +-------------------------------+------------- +transited encoding type |tr-type value +-------------------------------+------------- +DOMAIN-X500-COMPRESS 1 +reserved values all others + + +--------------+-------+----------------------------------------- +Label |Value |Meaning or MIT code +--------------+-------+----------------------------------------- + +pvno 5 current Kerberos protocol version number + +message types + +KRB_AS_REQ 10 Request for initial authentication +KRB_AS_REP 11 Response to KRB_AS_REQ request +KRB_TGS_REQ 12 Request for authentication based on TGT +KRB_TGS_REP 13 Response to KRB_TGS_REQ request +KRB_AP_REQ 14 application request to server +KRB_AP_REP 15 Response to KRB_AP_REQ_MUTUAL +KRB_SAFE 20 Safe (checksummed) application message +KRB_PRIV 21 Private (encrypted) application message +KRB_CRED 22 Private (encrypted) message to forward credentials +KRB_ERROR 30 Error response + +name types + +KRB_NT_UNKNOWN 0 Name type not known +KRB_NT_PRINCIPAL 1 Just the name of the principal as in DCE, or for users +KRB_NT_SRV_INST 2 Service and other unique instance (krbtgt) +KRB_NT_SRV_HST 3 Service with host name as instance (telnet, rcommands) +KRB_NT_SRV_XHST 4 Service with host as remaining components +KRB_NT_UID 5 Unique ID + +error codes + +KDC_ERR_NONE 0 No error +KDC_ERR_NAME_EXP 1 Client's entry in database has expired +KDC_ERR_SERVICE_EXP 2 Server's entry in database has expired +KDC_ERR_BAD_PVNO 3 Requested protocol version # not supported +KDC_ERR_C_OLD_MAST_KVNO 4 Client's key encrypted in old master key +KDC_ERR_S_OLD_MAST_KVNO 5 Server's key encrypted in old master key +KDC_ERR_C_PRINCIPAL_UNKNOWN 6 Client not found in Kerberos database +KDC_ERR_S_PRINCIPAL_UNKNOWN 7 Server not found in Kerberos database +KDC_ERR_PRINCIPAL_NOT_UNIQUE 8 Multiple principal entries in database +KDC_ERR_NULL_KEY 9 The client or server has a null key +KDC_ERR_CANNOT_POSTDATE 10 Ticket not eligible for postdating +KDC_ERR_NEVER_VALID 11 Requested start time is later than end time +KDC_ERR_POLICY 12 KDC policy rejects request +KDC_ERR_BADOPTION 13 KDC cannot accommodate requested option +KDC_ERR_ETYPE_NOSUPP 14 KDC has no support for encryption type +KDC_ERR_SUMTYPE_NOSUPP 15 KDC has no support for checksum type +KDC_ERR_PADATA_TYPE_NOSUPP 16 KDC has no support for padata type +KDC_ERR_TRTYPE_NOSUPP 17 KDC has no support for transited type +KDC_ERR_CLIENT_REVOKED 18 Clients credentials have been revoked +KDC_ERR_SERVICE_REVOKED 19 Credentials for server have been revoked +KDC_ERR_TGT_REVOKED 20 TGT has been revoked +KDC_ERR_CLIENT_NOTYET 21 Client not yet valid - try again later +KDC_ERR_SERVICE_NOTYET 22 Server not yet valid - try again later +KDC_ERR_KEY_EXPIRED 23 Password has expired - change to reset +KDC_ERR_PREAUTH_FAILED 24 Pre-authentication information was invalid +KDC_ERR_PREAUTH_REQUIRED 25 Additional pre-authentication required* +KDC_ERR_SERVER_NOMATCH 26 Requested server and ticket don't match +KDC_ERR_MUST_USE_USER2USER 27 Server principal valid for user2user only +KRB_AP_ERR_BAD_INTEGRITY 31 Integrity check on decrypted field failed +KRB_AP_ERR_TKT_EXPIRED 32 Ticket expired +KRB_AP_ERR_TKT_NYV 33 Ticket not yet valid +KRB_AP_ERR_REPEAT 34 Request is a replay +KRB_AP_ERR_NOT_US 35 The ticket isn't for us +KRB_AP_ERR_BADMATCH 36 Ticket and authenticator don't match +KRB_AP_ERR_SKEW 37 Clock skew too great +KRB_AP_ERR_BADADDR 38 Incorrect net address +KRB_AP_ERR_BADVERSION 39 Protocol version mismatch +KRB_AP_ERR_MSG_TYPE 40 Invalid msg type +KRB_AP_ERR_MODIFIED 41 Message stream modified +KRB_AP_ERR_BADORDER 42 Message out of order +KRB_AP_ERR_BADKEYVER 44 Specified version of key is not available +KRB_AP_ERR_NOKEY 45 Service key not available +KRB_AP_ERR_MUT_FAIL 46 Mutual authentication failed +KRB_AP_ERR_BADDIRECTION 47 Incorrect message direction +KRB_AP_ERR_METHOD 48 Alternative authentication method required* +KRB_AP_ERR_BADSEQ 49 Incorrect sequence number in message +KRB_AP_ERR_INAPP_CKSUM 50 Inappropriate type of checksum in message +KRB_ERR_GENERIC 60 Generic error (description in e-text) +KRB_ERR_FIELD_TOOLONG 61 Field is too long for this implementation + + *This error carries additional information in the e-data field. The + contents of the e-data field for this message is described in section + 5.9.1. + diff --git a/mechglue/doc/krb5-protocol/rfc1510.errata b/mechglue/doc/krb5-protocol/rfc1510.errata new file mode 100644 index 000000000..602325b27 --- /dev/null +++ b/mechglue/doc/krb5-protocol/rfc1510.errata @@ -0,0 +1,105 @@ +---rfc1510.eratta---as of Auguest 10, 1994--- + +1. [19940312] The following lines describes corrections to pseudocode + in rfc1510 as of March 12, 1994. + + A: Throughout the pseudocode (section A), flags.ALLOW-POSTDATE should be + replaced by flags.MAY-POSTDATE. kdc-options.ALLOW-POSTDATE is + correct, however. + +A.2: In the processing for the kdc-options.POSTDATE (imperitive), both + the POSTDATED and the INVALID flag should be set. The setting of the + POSTDATE flag was inadvertantly omitted. + + You should change: + + if (req.kdc-options.POSTDATED is set) then + if (against_postdate_policy(req.from)) then + error_out(KDC_ERR_POLICY); + endif + set new_tkt.flags.INVALID; + new_tkt.starttime := req.from; + else + omit new_tkt.starttime; /* treated as authtime when + + To: + if (req.kdc-options.POSTDATED is set) then + if (against_postdate_policy(req.from)) then + error_out(KDC_ERR_POLICY); + endif + set new_tkt.flags.POSTDATED; <**** + set new_tkt.flags.INVALID; + new_tkt.starttime := req.from; + else + omit new_tkt.starttime; /* treated as authtime when + +A.6: In section A.6, all occursences of kdc-options.POSTDATE (imperitive) + should be replaced by kdc-options.ALLOW-POSTDATE and tgt.flags.POSTDATE + should be replaced by tgt.flags.MAY-POSTDATE. + + Note that instances of POSTDATED (adjective) are correct. + + +--- +2. [19940614] Processing of the etype filed, described in 3.1.3, and 5.4.1. + +If a there are multiple encryption keys registered for a client in the +Kerberos database (or if the key registered supports multiple +encryption types; e.g. DES-CBC-CRC and DES-CBC-MD5), then the etype +field from the AS request is used by the KDC to select the encryption +method to be used for encrypting the response to the client. If there +is more than one supported, strong encryption type in the etype list, +the first valid etype for which an encryption key is available is +used. The encryption method used to respond to a TGS request is taken +from the keytype of the session key found in the ticket granting +ticket. + +When the etype field is present in a KDC request, whether an AS or TGS +request, the KDC will attempt to assign the type of the random session +key from the list of methods in the etype field. The KDC will select +the appropriate type using the list of methods provided together with +information from the Kerberos database indicating acceptable +encryption methods for the application server. The KDC will not issue +tickets with a weak session key encryption type. + +--- +3. [19940707] Case of realm names for DNS based realm names, + + The following should appear in section 7.1 before the description + of the four classed of realm names (before "There are presently...") + + Kerberos realm names are case sensitive. Realm names that differ + only in the case of the characters are not equivalent. + + The domain example should be changes from: + domain: host.subdomain.domain (example) + + To: + + domain: ATHENA.MIT.EDU (example) + + The following should be append to the domain name paragraph of + section 7.1 (following "nor slashes (/).") + + Domain names must be converted to upper case when used as realm names. + +--- +4. [19940707] Official name of host is instance for NT-SRV-HST + + Append to paragraph 7.2.1: + + When a host has an official name and one or more aliases, the + official name of the host must be used when constructing the name + of the server principal. + +--- + +5. [19940722] The protocol is standards track + + In the 3rd paragraph of the overview delete: + + ", and are not being submitted for consideration as + an Internet standard at this time" + + as it contradicts the first sentence of the RFC. + diff --git a/mechglue/doc/krb5-protocol/rfc1510.txt b/mechglue/doc/krb5-protocol/rfc1510.txt new file mode 100644 index 000000000..bc810cc50 --- /dev/null +++ b/mechglue/doc/krb5-protocol/rfc1510.txt @@ -0,0 +1,6275 @@ + + + + + + +Network Working Group J. Kohl +Request for Comments: 1510 Digital Equipment Corporation + C. Neuman + ISI + September 1993 + + + The Kerberos Network Authentication Service (V5) + +Status of this Memo + + This RFC specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" for the standardization state and status + of this protocol. Distribution of this memo is unlimited. + +Abstract + + This document gives an overview and specification of Version 5 of the + protocol for the Kerberos network authentication system. Version 4, + described elsewhere [1,2], is presently in production use at MIT's + Project Athena, and at other Internet sites. + +Overview + + Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, + Moira, and Zephyr are trademarks of the Massachusetts Institute of + Technology (MIT). No commercial use of these trademarks may be made + without prior written permission of MIT. + + This RFC describes the concepts and model upon which the Kerberos + network authentication system is based. It also specifies Version 5 + of the Kerberos protocol. + + The motivations, goals, assumptions, and rationale behind most design + decisions are treated cursorily; for Version 4 they are fully + described in the Kerberos portion of the Athena Technical Plan [1]. + The protocols are under review, and are not being submitted for + consideration as an Internet standard at this time. Comments are + encouraged. Requests for addition to an electronic mailing list for + discussion of Kerberos, kerberos@MIT.EDU, may be addressed to + kerberos-request@MIT.EDU. This mailing list is gatewayed onto the + Usenet as the group comp.protocols.kerberos. Requests for further + information, including documents and code availability, may be sent + to info-kerberos@MIT.EDU. + + + + + +Kohl & Neuman [Page 1] + +RFC 1510 Kerberos September 1993 + + +Background + + The Kerberos model is based in part on Needham and Schroeder's + trusted third-party authentication protocol [3] and on modifications + suggested by Denning and Sacco [4]. The original design and + implementation of Kerberos Versions 1 through 4 was the work of two + former Project Athena staff members, Steve Miller of Digital + Equipment Corporation and Clifford Neuman (now at the Information + Sciences Institute of the University of Southern California), along + with Jerome Saltzer, Technical Director of Project Athena, and + Jeffrey Schiller, MIT Campus Network Manager. Many other members of + Project Athena have also contributed to the work on Kerberos. + Version 4 is publicly available, and has seen wide use across the + Internet. + + Version 5 (described in this document) has evolved from Version 4 + based on new requirements and desires for features not available in + Version 4. Details on the differences between Kerberos Versions 4 + and 5 can be found in [5]. + +Table of Contents + + 1. Introduction ....................................... 5 + 1.1. Cross-Realm Operation ............................ 7 + 1.2. Environmental assumptions ........................ 8 + 1.3. Glossary of terms ................................ 9 + 2. Ticket flag uses and requests ...................... 12 + 2.1. Initial and pre-authenticated tickets ............ 12 + 2.2. Invalid tickets .................................. 12 + 2.3. Renewable tickets ................................ 12 + 2.4. Postdated tickets ................................ 13 + 2.5. Proxiable and proxy tickets ...................... 14 + 2.6. Forwardable tickets .............................. 15 + 2.7. Other KDC options ................................ 15 + 3. Message Exchanges .................................. 16 + 3.1. The Authentication Service Exchange .............. 16 + 3.1.1. Generation of KRB_AS_REQ message ............... 17 + 3.1.2. Receipt of KRB_AS_REQ message .................. 17 + 3.1.3. Generation of KRB_AS_REP message ............... 17 + 3.1.4. Generation of KRB_ERROR message ................ 19 + 3.1.5. Receipt of KRB_AS_REP message .................. 19 + 3.1.6. Receipt of KRB_ERROR message ................... 20 + 3.2. The Client/Server Authentication Exchange ........ 20 + 3.2.1. The KRB_AP_REQ message ......................... 20 + 3.2.2. Generation of a KRB_AP_REQ message ............. 20 + 3.2.3. Receipt of KRB_AP_REQ message .................. 21 + 3.2.4. Generation of a KRB_AP_REP message ............. 23 + 3.2.5. Receipt of KRB_AP_REP message .................. 23 + + + +Kohl & Neuman [Page 2] + +RFC 1510 Kerberos September 1993 + + + 3.2.6. Using the encryption key ....................... 24 + 3.3. The Ticket-Granting Service (TGS) Exchange ....... 24 + 3.3.1. Generation of KRB_TGS_REQ message .............. 25 + 3.3.2. Receipt of KRB_TGS_REQ message ................. 26 + 3.3.3. Generation of KRB_TGS_REP message .............. 27 + 3.3.3.1. Encoding the transited field ................. 29 + 3.3.4. Receipt of KRB_TGS_REP message ................. 31 + 3.4. The KRB_SAFE Exchange ............................ 31 + 3.4.1. Generation of a KRB_SAFE message ............... 31 + 3.4.2. Receipt of KRB_SAFE message .................... 32 + 3.5. The KRB_PRIV Exchange ............................ 33 + 3.5.1. Generation of a KRB_PRIV message ............... 33 + 3.5.2. Receipt of KRB_PRIV message .................... 33 + 3.6. The KRB_CRED Exchange ............................ 34 + 3.6.1. Generation of a KRB_CRED message ............... 34 + 3.6.2. Receipt of KRB_CRED message .................... 34 + 4. The Kerberos Database .............................. 35 + 4.1. Database contents ................................ 35 + 4.2. Additional fields ................................ 36 + 4.3. Frequently Changing Fields ....................... 37 + 4.4. Site Constants ................................... 37 + 5. Message Specifications ............................. 38 + 5.1. ASN.1 Distinguished Encoding Representation ...... 38 + 5.2. ASN.1 Base Definitions ........................... 38 + 5.3. Tickets and Authenticators ....................... 42 + 5.3.1. Tickets ........................................ 42 + 5.3.2. Authenticators ................................. 47 + 5.4. Specifications for the AS and TGS exchanges ...... 49 + 5.4.1. KRB_KDC_REQ definition ......................... 49 + 5.4.2. KRB_KDC_REP definition ......................... 56 + 5.5. Client/Server (CS) message specifications ........ 58 + 5.5.1. KRB_AP_REQ definition .......................... 58 + 5.5.2. KRB_AP_REP definition .......................... 60 + 5.5.3. Error message reply ............................ 61 + 5.6. KRB_SAFE message specification ................... 61 + 5.6.1. KRB_SAFE definition ............................ 61 + 5.7. KRB_PRIV message specification ................... 62 + 5.7.1. KRB_PRIV definition ............................ 62 + 5.8. KRB_CRED message specification ................... 63 + 5.8.1. KRB_CRED definition ............................ 63 + 5.9. Error message specification ...................... 65 + 5.9.1. KRB_ERROR definition ........................... 66 + 6. Encryption and Checksum Specifications ............. 67 + 6.1. Encryption Specifications ........................ 68 + 6.2. Encryption Keys .................................. 71 + 6.3. Encryption Systems ............................... 71 + 6.3.1. The NULL Encryption System (null) .............. 71 + 6.3.2. DES in CBC mode with a CRC-32 checksum (descbc-crc)71 + + + +Kohl & Neuman [Page 3] + +RFC 1510 Kerberos September 1993 + + + 6.3.3. DES in CBC mode with an MD4 checksum (descbc-md4) 72 + 6.3.4. DES in CBC mode with an MD5 checksum (descbc-md5) 72 + 6.4. Checksums ........................................ 74 + 6.4.1. The CRC-32 Checksum (crc32) .................... 74 + 6.4.2. The RSA MD4 Checksum (rsa-md4) ................. 75 + 6.4.3. RSA MD4 Cryptographic Checksum Using DES + (rsa-md4-des) ......................................... 75 + 6.4.4. The RSA MD5 Checksum (rsa-md5) ................. 76 + 6.4.5. RSA MD5 Cryptographic Checksum Using DES + (rsa-md5-des) ......................................... 76 + 6.4.6. DES cipher-block chained checksum (des-mac) + 6.4.7. RSA MD4 Cryptographic Checksum Using DES + alternative (rsa-md4-des-k) ........................... 77 + 6.4.8. DES cipher-block chained checksum alternative + (des-mac-k) ........................................... 77 + 7. Naming Constraints ................................. 78 + 7.1. Realm Names ...................................... 77 + 7.2. Principal Names .................................. 79 + 7.2.1. Name of server principals ...................... 80 + 8. Constants and other defined values ................. 80 + 8.1. Host address types ............................... 80 + 8.2. KDC messages ..................................... 81 + 8.2.1. IP transport ................................... 81 + 8.2.2. OSI transport .................................. 82 + 8.2.3. Name of the TGS ................................ 82 + 8.3. Protocol constants and associated values ......... 82 + 9. Interoperability requirements ...................... 86 + 9.1. Specification 1 .................................. 86 + 9.2. Recommended KDC values ........................... 88 + 10. Acknowledgments ................................... 88 + 11. References ........................................ 89 + 12. Security Considerations ........................... 90 + 13. Authors' Addresses ................................ 90 + A. Pseudo-code for protocol processing ................ 91 + A.1. KRB_AS_REQ generation ............................ 91 + A.2. KRB_AS_REQ verification and KRB_AS_REP generation 92 + A.3. KRB_AS_REP verification .......................... 95 + A.4. KRB_AS_REP and KRB_TGS_REP common checks ......... 96 + A.5. KRB_TGS_REQ generation ........................... 97 + A.6. KRB_TGS_REQ verification and KRB_TGS_REP generation 98 + A.7. KRB_TGS_REP verification ......................... 104 + A.8. Authenticator generation ......................... 104 + A.9. KRB_AP_REQ generation ............................ 105 + A.10. KRB_AP_REQ verification ......................... 105 + A.11. KRB_AP_REP generation ........................... 106 + A.12. KRB_AP_REP verification ......................... 107 + A.13. KRB_SAFE generation ............................. 107 + A.14. KRB_SAFE verification ........................... 108 + + + +Kohl & Neuman [Page 4] + +RFC 1510 Kerberos September 1993 + + + A.15. KRB_SAFE and KRB_PRIV common checks ............. 108 + A.16. KRB_PRIV generation ............................. 109 + A.17. KRB_PRIV verification ........................... 110 + A.18. KRB_CRED generation ............................. 110 + A.19. KRB_CRED verification ........................... 111 + A.20. KRB_ERROR generation ............................ 112 + +1. Introduction + + Kerberos provides a means of verifying the identities of principals, + (e.g., a workstation user or a network server) on an open + (unprotected) network. This is accomplished without relying on + authentication by the host operating system, without basing trust on + host addresses, without requiring physical security of all the hosts + on the network, and under the assumption that packets traveling along + the network can be read, modified, and inserted at will. (Note, + however, that many applications use Kerberos' functions only upon the + initiation of a stream-based network connection, and assume the + absence of any "hijackers" who might subvert such a connection. Such + use implicitly trusts the host addresses involved.) Kerberos + performs authentication under these conditions as a trusted third- + party authentication service by using conventional cryptography, + i.e., shared secret key. (shared secret key - Secret and private are + often used interchangeably in the literature. In our usage, it takes + two (or more) to share a secret, thus a shared DES key is a secret + key. Something is only private when no one but its owner knows it. + Thus, in public key cryptosystems, one has a public and a private + key.) + + The authentication process proceeds as follows: A client sends a + request to the authentication server (AS) requesting "credentials" + for a given server. The AS responds with these credentials, + encrypted in the client's key. The credentials consist of 1) a + "ticket" for the server and 2) a temporary encryption key (often + called a "session key"). The client transmits the ticket (which + contains the client's identity and a copy of the session key, all + encrypted in the server's key) to the server. The session key (now + shared by the client and server) is used to authenticate the client, + and may optionally be used to authenticate the server. It may also + be used to encrypt further communication between the two parties or + to exchange a separate sub-session key to be used to encrypt further + communication. + + The implementation consists of one or more authentication servers + running on physically secure hosts. The authentication servers + maintain a database of principals (i.e., users and servers) and their + secret keys. Code libraries provide encryption and implement the + Kerberos protocol. In order to add authentication to its + + + +Kohl & Neuman [Page 5] + +RFC 1510 Kerberos September 1993 + + + transactions, a typical network application adds one or two calls to + the Kerberos library, which results in the transmission of the + necessary messages to achieve authentication. + + The Kerberos protocol consists of several sub-protocols (or + exchanges). There are two methods by which a client can ask a + Kerberos server for credentials. In the first approach, the client + sends a cleartext request for a ticket for the desired server to the + AS. The reply is sent encrypted in the client's secret key. Usually + this request is for a ticket-granting ticket (TGT) which can later be + used with the ticket-granting server (TGS). In the second method, + the client sends a request to the TGS. The client sends the TGT to + the TGS in the same manner as if it were contacting any other + application server which requires Kerberos credentials. The reply is + encrypted in the session key from the TGT. + + Once obtained, credentials may be used to verify the identity of the + principals in a transaction, to ensure the integrity of messages + exchanged between them, or to preserve privacy of the messages. The + application is free to choose whatever protection may be necessary. + + To verify the identities of the principals in a transaction, the + client transmits the ticket to the server. Since the ticket is sent + "in the clear" (parts of it are encrypted, but this encryption + doesn't thwart replay) and might be intercepted and reused by an + attacker, additional information is sent to prove that the message + was originated by the principal to whom the ticket was issued. This + information (called the authenticator) is encrypted in the session + key, and includes a timestamp. The timestamp proves that the message + was recently generated and is not a replay. Encrypting the + authenticator in the session key proves that it was generated by a + party possessing the session key. Since no one except the requesting + principal and the server know the session key (it is never sent over + the network in the clear) this guarantees the identity of the client. + + The integrity of the messages exchanged between principals can also + be guaranteed using the session key (passed in the ticket and + contained in the credentials). This approach provides detection of + both replay attacks and message stream modification attacks. It is + accomplished by generating and transmitting a collision-proof + checksum (elsewhere called a hash or digest function) of the client's + message, keyed with the session key. Privacy and integrity of the + messages exchanged between principals can be secured by encrypting + the data to be passed using the session key passed in the ticket, and + contained in the credentials. + + The authentication exchanges mentioned above require read-only access + to the Kerberos database. Sometimes, however, the entries in the + + + +Kohl & Neuman [Page 6] + +RFC 1510 Kerberos September 1993 + + + database must be modified, such as when adding new principals or + changing a principal's key. This is done using a protocol between a + client and a third Kerberos server, the Kerberos Administration + Server (KADM). The administration protocol is not described in this + document. There is also a protocol for maintaining multiple copies of + the Kerberos database, but this can be considered an implementation + detail and may vary to support different database technologies. + +1.1. Cross-Realm Operation + + The Kerberos protocol is designed to operate across organizational + boundaries. A client in one organization can be authenticated to a + server in another. Each organization wishing to run a Kerberos + server establishes its own "realm". The name of the realm in which a + client is registered is part of the client's name, and can be used by + the end-service to decide whether to honor a request. + + By establishing "inter-realm" keys, the administrators of two realms + can allow a client authenticated in the local realm to use its + authentication remotely (Of course, with appropriate permission the + client could arrange registration of a separately-named principal in + a remote realm, and engage in normal exchanges with that realm's + services. However, for even small numbers of clients this becomes + cumbersome, and more automatic methods as described here are + necessary). The exchange of inter-realm keys (a separate key may be + used for each direction) registers the ticket-granting service of + each realm as a principal in the other realm. A client is then able + to obtain a ticket-granting ticket for the remote realm's ticket- + granting service from its local realm. When that ticket-granting + ticket is used, the remote ticket-granting service uses the inter- + realm key (which usually differs from its own normal TGS key) to + decrypt the ticket-granting ticket, and is thus certain that it was + issued by the client's own TGS. Tickets issued by the remote ticket- + granting service will indicate to the end-service that the client was + authenticated from another realm. + + A realm is said to communicate with another realm if the two realms + share an inter-realm key, or if the local realm shares an inter-realm + key with an intermediate realm that communicates with the remote + realm. An authentication path is the sequence of intermediate realms + that are transited in communicating from one realm to another. + + Realms are typically organized hierarchically. Each realm shares a + key with its parent and a different key with each child. If an + inter-realm key is not directly shared by two realms, the + hierarchical organization allows an authentication path to be easily + constructed. If a hierarchical organization is not used, it may be + necessary to consult some database in order to construct an + + + +Kohl & Neuman [Page 7] + +RFC 1510 Kerberos September 1993 + + + authentication path between realms. + + Although realms are typically hierarchical, intermediate realms may + be bypassed to achieve cross-realm authentication through alternate + authentication paths (these might be established to make + communication between two realms more efficient). It is important + for the end-service to know which realms were transited when deciding + how much faith to place in the authentication process. To facilitate + this decision, a field in each ticket contains the names of the + realms that were involved in authenticating the client. + +1.2. Environmental assumptions + + Kerberos imposes a few assumptions on the environment in which it can + properly function: + + + "Denial of service" attacks are not solved with Kerberos. There + are places in these protocols where an intruder intruder can + prevent an application from participating in the proper + authentication steps. Detection and solution of such attacks + (some of which can appear to be not-uncommon "normal" failure + modes for the system) is usually best left to the human + administrators and users. + + + Principals must keep their secret keys secret. If an intruder + somehow steals a principal's key, it will be able to masquerade + as that principal or impersonate any server to the legitimate + principal. + + + "Password guessing" attacks are not solved by Kerberos. If a + user chooses a poor password, it is possible for an attacker to + successfully mount an offline dictionary attack by repeatedly + attempting to decrypt, with successive entries from a + dictionary, messages obtained which are encrypted under a key + derived from the user's password. + + + Each host on the network must have a clock which is "loosely + synchronized" to the time of the other hosts; this + synchronization is used to reduce the bookkeeping needs of + application servers when they do replay detection. The degree + of "looseness" can be configured on a per-server basis. If the + clocks are synchronized over the network, the clock + synchronization protocol must itself be secured from network + attackers. + + + Principal identifiers are not recycled on a short-term basis. A + typical mode of access control will use access control lists + (ACLs) to grant permissions to particular principals. If a + + + +Kohl & Neuman [Page 8] + +RFC 1510 Kerberos September 1993 + + + stale ACL entry remains for a deleted principal and the + principal identifier is reused, the new principal will inherit + rights specified in the stale ACL entry. By not re-using + principal identifiers, the danger of inadvertent access is + removed. + +1.3. Glossary of terms + + Below is a list of terms used throughout this document. + + + Authentication Verifying the claimed identity of a + principal. + + + Authentication header A record containing a Ticket and an + Authenticator to be presented to a + server as part of the authentication + process. + + + Authentication path A sequence of intermediate realms transited + in the authentication process when + communicating from one realm to another. + + Authenticator A record containing information that can + be shown to have been recently generated + using the session key known only by the + client and server. + + + Authorization The process of determining whether a + client may use a service, which objects + the client is allowed to access, and the + type of access allowed for each. + + + Capability A token that grants the bearer permission + to access an object or service. In + Kerberos, this might be a ticket whose + use is restricted by the contents of the + authorization data field, but which + lists no network addresses, together + with the session key necessary to use + the ticket. + + + + + + +Kohl & Neuman [Page 9] + +RFC 1510 Kerberos September 1993 + + + Ciphertext The output of an encryption function. + Encryption transforms plaintext into + ciphertext. + + + Client A process that makes use of a network + service on behalf of a user. Note that + in some cases a Server may itself be a + client of some other server (e.g., a + print server may be a client of a file + server). + + + Credentials A ticket plus the secret session key + necessary to successfully use that + ticket in an authentication exchange. + + + KDC Key Distribution Center, a network service + that supplies tickets and temporary + session keys; or an instance of that + service or the host on which it runs. + The KDC services both initial ticket and + ticket-granting ticket requests. The + initial ticket portion is sometimes + referred to as the Authentication Server + (or service). The ticket-granting + ticket portion is sometimes referred to + as the ticket-granting server (or service). + + Kerberos Aside from the 3-headed dog guarding + Hades, the name given to Project + Athena's authentication service, the + protocol used by that service, or the + code used to implement the authentication + service. + + + Plaintext The input to an encryption function or + the output of a decryption function. + Decryption transforms ciphertext into + plaintext. + + + Principal A uniquely named client or server + instance that participates in a network + communication. + + + + +Kohl & Neuman [Page 10] + +RFC 1510 Kerberos September 1993 + + + Principal identifier The name used to uniquely identify each + different principal. + + + Seal To encipher a record containing several + fields in such a way that the fields + cannot be individually replaced without + either knowledge of the encryption key + or leaving evidence of tampering. + + + Secret key An encryption key shared by a principal + and the KDC, distributed outside the + bounds of the system, with a long lifetime. + In the case of a human user's + principal, the secret key is derived + from a password. + + + Server A particular Principal which provides a + resource to network clients. + + + Service A resource provided to network clients; + often provided by more than one server + (for example, remote file service). + + + Session key A temporary encryption key used between + two principals, with a lifetime limited + to the duration of a single login "session". + + + Sub-session key A temporary encryption key used between + two principals, selected and exchanged + by the principals using the session key, + and with a lifetime limited to the duration + of a single association. + + + Ticket A record that helps a client authenticate + itself to a server; it contains the + client's identity, a session key, a + timestamp, and other information, all + sealed using the server's secret key. + It only serves to authenticate a client + when presented along with a fresh + Authenticator. + + + +Kohl & Neuman [Page 11] + +RFC 1510 Kerberos September 1993 + + +2. Ticket flag uses and requests + + Each Kerberos ticket contains a set of flags which are used to + indicate various attributes of that ticket. Most flags may be + requested by a client when the ticket is obtained; some are + automatically turned on and off by a Kerberos server as required. + The following sections explain what the various flags mean, and gives + examples of reasons to use such a flag. + +2.1. Initial and pre-authenticated tickets + + The INITIAL flag indicates that a ticket was issued using the AS + protocol and not issued based on a ticket-granting ticket. + Application servers that want to require the knowledge of a client's + secret key (e.g., a passwordchanging program) can insist that this + flag be set in any tickets they accept, and thus be assured that the + client's key was recently presented to the application client. + + The PRE-AUTHENT and HW-AUTHENT flags provide addition information + about the initial authentication, regardless of whether the current + ticket was issued directly (in which case INITIAL will also be set) + or issued on the basis of a ticket-granting ticket (in which case the + INITIAL flag is clear, but the PRE-AUTHENT and HW-AUTHENT flags are + carried forward from the ticket-granting ticket). + +2.2. Invalid tickets + + The INVALID flag indicates that a ticket is invalid. Application + servers must reject tickets which have this flag set. A postdated + ticket will usually be issued in this form. Invalid tickets must be + validated by the KDC before use, by presenting them to the KDC in a + TGS request with the VALIDATE option specified. The KDC will only + validate tickets after their starttime has passed. The validation is + required so that postdated tickets which have been stolen before + their starttime can be rendered permanently invalid (through a hot- + list mechanism). + +2.3. Renewable tickets + + Applications may desire to hold tickets which can be valid for long + periods of time. However, this can expose their credentials to + potential theft for equally long periods, and those stolen + credentials would be valid until the expiration time of the + ticket(s). Simply using shortlived tickets and obtaining new ones + periodically would require the client to have long-term access to its + secret key, an even greater risk. Renewable tickets can be used to + mitigate the consequences of theft. Renewable tickets have two + "expiration times": the first is when the current instance of the + + + +Kohl & Neuman [Page 12] + +RFC 1510 Kerberos September 1993 + + + ticket expires, and the second is the latest permissible value for an + individual expiration time. An application client must periodically + (i.e., before it expires) present a renewable ticket to the KDC, with + the RENEW option set in the KDC request. The KDC will issue a new + ticket with a new session key and a later expiration time. All other + fields of the ticket are left unmodified by the renewal process. + When the latest permissible expiration time arrives, the ticket + expires permanently. At each renewal, the KDC may consult a hot-list + to determine if the ticket had been reported stolen since its last + renewal; it will refuse to renew such stolen tickets, and thus the + usable lifetime of stolen tickets is reduced. + + The RENEWABLE flag in a ticket is normally only interpreted by the + ticket-granting service (discussed below in section 3.3). It can + usually be ignored by application servers. However, some + particularly careful application servers may wish to disallow + renewable tickets. + + If a renewable ticket is not renewed by its expiration time, the KDC + will not renew the ticket. The RENEWABLE flag is reset by default, + but a client may request it be set by setting the RENEWABLE option + in the KRB_AS_REQ message. If it is set, then the renew-till field + in the ticket contains the time after which the ticket may not be + renewed. + +2.4. Postdated tickets + + Applications may occasionally need to obtain tickets for use much + later, e.g., a batch submission system would need tickets to be valid + at the time the batch job is serviced. However, it is dangerous to + hold valid tickets in a batch queue, since they will be on-line + longer and more prone to theft. Postdated tickets provide a way to + obtain these tickets from the KDC at job submission time, but to + leave them "dormant" until they are activated and validated by a + further request of the KDC. If a ticket theft were reported in the + interim, the KDC would refuse to validate the ticket, and the thief + would be foiled. + + The MAY-POSTDATE flag in a ticket is normally only interpreted by the + ticket-granting service. It can be ignored by application servers. + This flag must be set in a ticket-granting ticket in order to issue a + postdated ticket based on the presented ticket. It is reset by + default; it may be requested by a client by setting the ALLOW- + POSTDATE option in the KRB_AS_REQ message. This flag does not allow + a client to obtain a postdated ticket-granting ticket; postdated + ticket-granting tickets can only by obtained by requesting the + postdating in the KRB_AS_REQ message. The life (endtime-starttime) + of a postdated ticket will be the remaining life of the ticket- + + + +Kohl & Neuman [Page 13] + +RFC 1510 Kerberos September 1993 + + + granting ticket at the time of the request, unless the RENEWABLE + option is also set, in which case it can be the full life (endtime- + starttime) of the ticket-granting ticket. The KDC may limit how far + in the future a ticket may be postdated. + + The POSTDATED flag indicates that a ticket has been postdated. The + application server can check the authtime field in the ticket to see + when the original authentication occurred. Some services may choose + to reject postdated tickets, or they may only accept them within a + certain period after the original authentication. When the KDC issues + a POSTDATED ticket, it will also be marked as INVALID, so that the + application client must present the ticket to the KDC to be validated + before use. + +2.5. Proxiable and proxy tickets + + At times it may be necessary for a principal to allow a service to + perform an operation on its behalf. The service must be able to take + on the identity of the client, but only for a particular purpose. A + principal can allow a service to take on the principal's identity for + a particular purpose by granting it a proxy. + + The PROXIABLE flag in a ticket is normally only interpreted by the + ticket-granting service. It can be ignored by application servers. + When set, this flag tells the ticket-granting server that it is OK to + issue a new ticket (but not a ticket-granting ticket) with a + different network address based on this ticket. This flag is set by + default. + + This flag allows a client to pass a proxy to a server to perform a + remote request on its behalf, e.g., a print service client can give + the print server a proxy to access the client's files on a particular + file server in order to satisfy a print request. + + In order to complicate the use of stolen credentials, Kerberos + tickets are usually valid from only those network addresses + specifically included in the ticket (It is permissible to request or + issue tickets with no network addresses specified, but we do not + recommend it). For this reason, a client wishing to grant a proxy + must request a new ticket valid for the network address of the + service to be granted the proxy. + + The PROXY flag is set in a ticket by the TGS when it issues a + proxy ticket. Application servers may check this flag and require + additional authentication from the agent presenting the proxy in + order to provide an audit trail. + + + + + +Kohl & Neuman [Page 14] + +RFC 1510 Kerberos September 1993 + + +2.6. Forwardable tickets + + Authentication forwarding is an instance of the proxy case where the + service is granted complete use of the client's identity. An example + where it might be used is when a user logs in to a remote system and + wants authentication to work from that system as if the login were + local. + + The FORWARDABLE flag in a ticket is normally only interpreted by the + ticket-granting service. It can be ignored by application servers. + The FORWARDABLE flag has an interpretation similar to that of the + PROXIABLE flag, except ticket-granting tickets may also be issued + with different network addresses. This flag is reset by default, but + users may request that it be set by setting the FORWARDABLE option in + the AS request when they request their initial ticket-granting + ticket. + + This flag allows for authentication forwarding without requiring the + user to enter a password again. If the flag is not set, then + authentication forwarding is not permitted, but the same end result + can still be achieved if the user engages in the AS exchange with the + requested network addresses and supplies a password. + + The FORWARDED flag is set by the TGS when a client presents a ticket + with the FORWARDABLE flag set and requests it be set by specifying + the FORWARDED KDC option and supplying a set of addresses for the new + ticket. It is also set in all tickets issued based on tickets with + the FORWARDED flag set. Application servers may wish to process + FORWARDED tickets differently than non-FORWARDED tickets. + +2.7. Other KDC options + + There are two additional options which may be set in a client's + request of the KDC. The RENEWABLE-OK option indicates that the + client will accept a renewable ticket if a ticket with the requested + life cannot otherwise be provided. If a ticket with the requested + life cannot be provided, then the KDC may issue a renewable ticket + with a renew-till equal to the the requested endtime. The value of + the renew-till field may still be adjusted by site-determined limits + or limits imposed by the individual principal or server. + + The ENC-TKT-IN-SKEY option is honored only by the ticket-granting + service. It indicates that the to-be-issued ticket for the end + server is to be encrypted in the session key from the additional + ticket-granting ticket provided with the request. See section 3.3.3 + for specific details. + + + + + +Kohl & Neuman [Page 15] + +RFC 1510 Kerberos September 1993 + + +3. Message Exchanges + + The following sections describe the interactions between network + clients and servers and the messages involved in those exchanges. + +3.1. The Authentication Service Exchange + + Summary + + Message direction Message type Section + 1. Client to Kerberos KRB_AS_REQ 5.4.1 + 2. Kerberos to client KRB_AS_REP or 5.4.2 + KRB_ERROR 5.9.1 + + The Authentication Service (AS) Exchange between the client and the + Kerberos Authentication Server is usually initiated by a client when + it wishes to obtain authentication credentials for a given server but + currently holds no credentials. The client's secret key is used for + encryption and decryption. This exchange is typically used at the + initiation of a login session, to obtain credentials for a Ticket- + Granting Server, which will subsequently be used to obtain + credentials for other servers (see section 3.3) without requiring + further use of the client's secret key. This exchange is also used + to request credentials for services which must not be mediated + through the Ticket-Granting Service, but rather require a principal's + secret key, such as the password-changing service. (The password- + changing request must not be honored unless the requester can provide + the old password (the user's current secret key). Otherwise, it + would be possible for someone to walk up to an unattended session and + change another user's password.) This exchange does not by itself + provide any assurance of the the identity of the user. (To + authenticate a user logging on to a local system, the credentials + obtained in the AS exchange may first be used in a TGS exchange to + obtain credentials for a local server. Those credentials must then + be verified by the local server through successful completion of the + Client/Server exchange.) + + The exchange consists of two messages: KRB_AS_REQ from the client to + Kerberos, and KRB_AS_REP or KRB_ERROR in reply. The formats for these + messages are described in sections 5.4.1, 5.4.2, and 5.9.1. + + In the request, the client sends (in cleartext) its own identity and + the identity of the server for which it is requesting credentials. + The response, KRB_AS_REP, contains a ticket for the client to present + to the server, and a session key that will be shared by the client + and the server. The session key and additional information are + encrypted in the client's secret key. The KRB_AS_REP message + contains information which can be used to detect replays, and to + + + +Kohl & Neuman [Page 16] + +RFC 1510 Kerberos September 1993 + + + associate it with the message to which it replies. Various errors + can occur; these are indicated by an error response (KRB_ERROR) + instead of the KRB_AS_REP response. The error message is not + encrypted. The KRB_ERROR message also contains information which can + be used to associate it with the message to which it replies. The + lack of encryption in the KRB_ERROR message precludes the ability to + detect replays or fabrications of such messages. + + In the normal case the authentication server does not know whether + the client is actually the principal named in the request. It simply + sends a reply without knowing or caring whether they are the same. + This is acceptable because nobody but the principal whose identity + was given in the request will be able to use the reply. Its critical + information is encrypted in that principal's key. The initial + request supports an optional field that can be used to pass + additional information that might be needed for the initial exchange. + This field may be used for preauthentication if desired, but the + mechanism is not currently specified. + +3.1.1. Generation of KRB_AS_REQ message + + The client may specify a number of options in the initial request. + Among these options are whether preauthentication is to be performed; + whether the requested ticket is to be renewable, proxiable, or + forwardable; whether it should be postdated or allow postdating of + derivative tickets; and whether a renewable ticket will be accepted + in lieu of a non-renewable ticket if the requested ticket expiration + date cannot be satisfied by a nonrenewable ticket (due to + configuration constraints; see section 4). See section A.1 for + pseudocode. + + The client prepares the KRB_AS_REQ message and sends it to the KDC. + +3.1.2. Receipt of KRB_AS_REQ message + + If all goes well, processing the KRB_AS_REQ message will result in + the creation of a ticket for the client to present to the server. + The format for the ticket is described in section 5.3.1. The + contents of the ticket are determined as follows. + +3.1.3. Generation of KRB_AS_REP message + + The authentication server looks up the client and server principals + named in the KRB_AS_REQ in its database, extracting their respective + keys. If required, the server pre-authenticates the request, and if + the pre-authentication check fails, an error message with the code + KDC_ERR_PREAUTH_FAILED is returned. If the server cannot accommodate + the requested encryption type, an error message with code + + + +Kohl & Neuman [Page 17] + +RFC 1510 Kerberos September 1993 + + + KDC_ERR_ETYPE_NOSUPP is returned. Otherwise it generates a "random" + session key ("Random" means that, among other things, it should be + impossible to guess the next session key based on knowledge of past + session keys. This can only be achieved in a pseudo-random number + generator if it is based on cryptographic principles. It would be + more desirable to use a truly random number generator, such as one + based on measurements of random physical phenomena.). + + If the requested start time is absent or indicates a time in the + past, then the start time of the ticket is set to the authentication + server's current time. If it indicates a time in the future, but the + POSTDATED option has not been specified, then the error + KDC_ERR_CANNOT_POSTDATE is returned. Otherwise the requested start + time is checked against the policy of the local realm (the + administrator might decide to prohibit certain types or ranges of + postdated tickets), and if acceptable, the ticket's start time is set + as requested and the INVALID flag is set in the new ticket. The + postdated ticket must be validated before use by presenting it to the + KDC after the start time has been reached. + + The expiration time of the ticket will be set to the minimum of the + following: + + +The expiration time (endtime) requested in the KRB_AS_REQ + message. + + +The ticket's start time plus the maximum allowable lifetime + associated with the client principal (the authentication + server's database includes a maximum ticket lifetime field + in each principal's record; see section 4). + + +The ticket's start time plus the maximum allowable lifetime + associated with the server principal. + + +The ticket's start time plus the maximum lifetime set by + the policy of the local realm. + + If the requested expiration time minus the start time (as determined + above) is less than a site-determined minimum lifetime, an error + message with code KDC_ERR_NEVER_VALID is returned. If the requested + expiration time for the ticket exceeds what was determined as above, + and if the "RENEWABLE-OK" option was requested, then the "RENEWABLE" + flag is set in the new ticket, and the renew-till value is set as if + the "RENEWABLE" option were requested (the field and option names are + described fully in section 5.4.1). If the RENEWABLE option has been + requested or if the RENEWABLE-OK option has been set and a renewable + ticket is to be issued, then the renew-till field is set to the + minimum of: + + + +Kohl & Neuman [Page 18] + +RFC 1510 Kerberos September 1993 + + + +Its requested value. + + +The start time of the ticket plus the minimum of the two + maximum renewable lifetimes associated with the principals' + database entries. + + +The start time of the ticket plus the maximum renewable + lifetime set by the policy of the local realm. + + The flags field of the new ticket will have the following options set + if they have been requested and if the policy of the local realm + allows: FORWARDABLE, MAY-POSTDATE, POSTDATED, PROXIABLE, RENEWABLE. + If the new ticket is postdated (the start time is in the future), its + INVALID flag will also be set. + + If all of the above succeed, the server formats a KRB_AS_REP message + (see section 5.4.2), copying the addresses in the request into the + caddr of the response, placing any required pre-authentication data + into the padata of the response, and encrypts the ciphertext part in + the client's key using the requested encryption method, and sends it + to the client. See section A.2 for pseudocode. + +3.1.4. Generation of KRB_ERROR message + + Several errors can occur, and the Authentication Server responds by + returning an error message, KRB_ERROR, to the client, with the + error-code and e-text fields set to appropriate values. The error + message contents and details are described in Section 5.9.1. + +3.1.5. Receipt of KRB_AS_REP message + + If the reply message type is KRB_AS_REP, then the client verifies + that the cname and crealm fields in the cleartext portion of the + reply match what it requested. If any padata fields are present, + they may be used to derive the proper secret key to decrypt the + message. The client decrypts the encrypted part of the response + using its secret key, verifies that the nonce in the encrypted part + matches the nonce it supplied in its request (to detect replays). It + also verifies that the sname and srealm in the response match those + in the request, and that the host address field is also correct. It + then stores the ticket, session key, start and expiration times, and + other information for later use. The key-expiration field from the + encrypted part of the response may be checked to notify the user of + impending key expiration (the client program could then suggest + remedial action, such as a password change). See section A.3 for + pseudocode. + + Proper decryption of the KRB_AS_REP message is not sufficient to + + + +Kohl & Neuman [Page 19] + +RFC 1510 Kerberos September 1993 + + + verify the identity of the user; the user and an attacker could + cooperate to generate a KRB_AS_REP format message which decrypts + properly but is not from the proper KDC. If the host wishes to + verify the identity of the user, it must require the user to present + application credentials which can be verified using a securely-stored + secret key. If those credentials can be verified, then the identity + of the user can be assured. + +3.1.6. Receipt of KRB_ERROR message + + If the reply message type is KRB_ERROR, then the client interprets it + as an error and performs whatever application-specific tasks are + necessary to recover. + +3.2. The Client/Server Authentication Exchange + + Summary + + Message direction Message type Section + Client to Application server KRB_AP_REQ 5.5.1 + [optional] Application server to client KRB_AP_REP or 5.5.2 + KRB_ERROR 5.9.1 + + The client/server authentication (CS) exchange is used by network + applications to authenticate the client to the server and vice versa. + The client must have already acquired credentials for the server + using the AS or TGS exchange. + +3.2.1. The KRB_AP_REQ message + + The KRB_AP_REQ contains authentication information which should be + part of the first message in an authenticated transaction. It + contains a ticket, an authenticator, and some additional bookkeeping + information (see section 5.5.1 for the exact format). The ticket by + itself is insufficient to authenticate a client, since tickets are + passed across the network in cleartext(Tickets contain both an + encrypted and unencrypted portion, so cleartext here refers to the + entire unit, which can be copied from one message and replayed in + another without any cryptographic skill.), so the authenticator is + used to prevent invalid replay of tickets by proving to the server + that the client knows the session key of the ticket and thus is + entitled to use it. The KRB_AP_REQ message is referred to elsewhere + as the "authentication header." + +3.2.2. Generation of a KRB_AP_REQ message + + When a client wishes to initiate authentication to a server, it + obtains (either through a credentials cache, the AS exchange, or the + + + +Kohl & Neuman [Page 20] + +RFC 1510 Kerberos September 1993 + + + TGS exchange) a ticket and session key for the desired service. The + client may re-use any tickets it holds until they expire. The client + then constructs a new Authenticator from the the system time, its + name, and optionally an application specific checksum, an initial + sequence number to be used in KRB_SAFE or KRB_PRIV messages, and/or a + session subkey to be used in negotiations for a session key unique to + this particular session. Authenticators may not be re-used and will + be rejected if replayed to a server (Note that this can make + applications based on unreliable transports difficult to code + correctly, if the transport might deliver duplicated messages. In + such cases, a new authenticator must be generated for each retry.). + If a sequence number is to be included, it should be randomly chosen + so that even after many messages have been exchanged it is not likely + to collide with other sequence numbers in use. + + The client may indicate a requirement of mutual authentication or the + use of a session-key based ticket by setting the appropriate flag(s) + in the ap-options field of the message. + + The Authenticator is encrypted in the session key and combined with + the ticket to form the KRB_AP_REQ message which is then sent to the + end server along with any additional application-specific + information. See section A.9 for pseudocode. + +3.2.3. Receipt of KRB_AP_REQ message + + Authentication is based on the server's current time of day (clocks + must be loosely synchronized), the authenticator, and the ticket. + Several errors are possible. If an error occurs, the server is + expected to reply to the client with a KRB_ERROR message. This + message may be encapsulated in the application protocol if its "raw" + form is not acceptable to the protocol. The format of error messages + is described in section 5.9.1. + + The algorithm for verifying authentication information is as follows. + If the message type is not KRB_AP_REQ, the server returns the + KRB_AP_ERR_MSG_TYPE error. If the key version indicated by the Ticket + in the KRB_AP_REQ is not one the server can use (e.g., it indicates + an old key, and the server no longer possesses a copy of the old + key), the KRB_AP_ERR_BADKEYVER error is returned. If the USE- + SESSION-KEY flag is set in the ap-options field, it indicates to the + server that the ticket is encrypted in the session key from the + server's ticket-granting ticket rather than its secret key (This is + used for user-to-user authentication as described in [6]). Since it + is possible for the server to be registered in multiple realms, with + different keys in each, the srealm field in the unencrypted portion + of the ticket in the KRB_AP_REQ is used to specify which secret key + the server should use to decrypt that ticket. The KRB_AP_ERR_NOKEY + + + +Kohl & Neuman [Page 21] + +RFC 1510 Kerberos September 1993 + + + error code is returned if the server doesn't have the proper key to + decipher the ticket. + + The ticket is decrypted using the version of the server's key + specified by the ticket. If the decryption routines detect a + modification of the ticket (each encryption system must provide + safeguards to detect modified ciphertext; see section 6), the + KRB_AP_ERR_BAD_INTEGRITY error is returned (chances are good that + different keys were used to encrypt and decrypt). + + The authenticator is decrypted using the session key extracted from + the decrypted ticket. If decryption shows it to have been modified, + the KRB_AP_ERR_BAD_INTEGRITY error is returned. The name and realm + of the client from the ticket are compared against the same fields in + the authenticator. If they don't match, the KRB_AP_ERR_BADMATCH + error is returned (they might not match, for example, if the wrong + session key was used to encrypt the authenticator). The addresses in + the ticket (if any) are then searched for an address matching the + operating-system reported address of the client. If no match is + found or the server insists on ticket addresses but none are present + in the ticket, the KRB_AP_ERR_BADADDR error is returned. + + If the local (server) time and the client time in the authenticator + differ by more than the allowable clock skew (e.g., 5 minutes), the + KRB_AP_ERR_SKEW error is returned. If the server name, along with + the client name, time and microsecond fields from the Authenticator + match any recently-seen such tuples, the KRB_AP_ERR_REPEAT error is + returned (Note that the rejection here is restricted to + authenticators from the same principal to the same server. Other + client principals communicating with the same server principal should + not be have their authenticators rejected if the time and microsecond + fields happen to match some other client's authenticator.). The + server must remember any authenticator presented within the allowable + clock skew, so that a replay attempt is guaranteed to fail. If a + server loses track of any authenticator presented within the + allowable clock skew, it must reject all requests until the clock + skew interval has passed. This assures that any lost or re-played + authenticators will fall outside the allowable clock skew and can no + longer be successfully replayed (If this is not done, an attacker + could conceivably record the ticket and authenticator sent over the + network to a server, then disable the client's host, pose as the + disabled host, and replay the ticket and authenticator to subvert the + authentication.). If a sequence number is provided in the + authenticator, the server saves it for later use in processing + KRB_SAFE and/or KRB_PRIV messages. If a subkey is present, the + server either saves it for later use or uses it to help generate its + own choice for a subkey to be returned in a KRB_AP_REP message. + + + + +Kohl & Neuman [Page 22] + +RFC 1510 Kerberos September 1993 + + + The server computes the age of the ticket: local (server) time minus + the start time inside the Ticket. If the start time is later than + the current time by more than the allowable clock skew or if the + INVALID flag is set in the ticket, the KRB_AP_ERR_TKT_NYV error is + returned. Otherwise, if the current time is later than end time by + more than the allowable clock skew, the KRB_AP_ERR_TKT_EXPIRED error + is returned. + + If all these checks succeed without an error, the server is assured + that the client possesses the credentials of the principal named in + the ticket and thus, the client has been authenticated to the server. + See section A.10 for pseudocode. + +3.2.4. Generation of a KRB_AP_REP message + + Typically, a client's request will include both the authentication + information and its initial request in the same message, and the + server need not explicitly reply to the KRB_AP_REQ. However, if + mutual authentication (not only authenticating the client to the + server, but also the server to the client) is being performed, the + KRB_AP_REQ message will have MUTUAL-REQUIRED set in its ap-options + field, and a KRB_AP_REP message is required in response. As with the + error message, this message may be encapsulated in the application + protocol if its "raw" form is not acceptable to the application's + protocol. The timestamp and microsecond field used in the reply must + be the client's timestamp and microsecond field (as provided in the + authenticator). [Note: In the Kerberos version 4 protocol, the + timestamp in the reply was the client's timestamp plus one. This is + not necessary in version 5 because version 5 messages are formatted + in such a way that it is not possible to create the reply by + judicious message surgery (even in encrypted form) without knowledge + of the appropriate encryption keys.] If a sequence number is to be + included, it should be randomly chosen as described above for the + authenticator. A subkey may be included if the server desires to + negotiate a different subkey. The KRB_AP_REP message is encrypted in + the session key extracted from the ticket. See section A.11 for + pseudocode. + +3.2.5. Receipt of KRB_AP_REP message + + If a KRB_AP_REP message is returned, the client uses the session key + from the credentials obtained for the server (Note that for + encrypting the KRB_AP_REP message, the sub-session key is not used, + even if present in the Authenticator.) to decrypt the message, and + verifies that the timestamp and microsecond fields match those in the + Authenticator it sent to the server. If they match, then the client + is assured that the server is genuine. The sequence number and subkey + (if present) are retained for later use. See section A.12 for + + + +Kohl & Neuman [Page 23] + +RFC 1510 Kerberos September 1993 + + + pseudocode. + +3.2.6. Using the encryption key + + After the KRB_AP_REQ/KRB_AP_REP exchange has occurred, the client and + server share an encryption key which can be used by the application. + The "true session key" to be used for KRB_PRIV, KRB_SAFE, or other + application-specific uses may be chosen by the application based on + the subkeys in the KRB_AP_REP message and the authenticator + (Implementations of the protocol may wish to provide routines to + choose subkeys based on session keys and random numbers and to + orchestrate a negotiated key to be returned in the KRB_AP_REP + message.). In some cases, the use of this session key will be + implicit in the protocol; in others the method of use must be chosen + from a several alternatives. We leave the protocol negotiations of + how to use the key (e.g., selecting an encryption or checksum type) + to the application programmer; the Kerberos protocol does not + constrain the implementation options. + + With both the one-way and mutual authentication exchanges, the peers + should take care not to send sensitive information to each other + without proper assurances. In particular, applications that require + privacy or integrity should use the KRB_AP_REP or KRB_ERROR responses + from the server to client to assure both client and server of their + peer's identity. If an application protocol requires privacy of its + messages, it can use the KRB_PRIV message (section 3.5). The KRB_SAFE + message (section 3.4) can be used to assure integrity. + +3.3. The Ticket-Granting Service (TGS) Exchange + + Summary + + Message direction Message type Section + 1. Client to Kerberos KRB_TGS_REQ 5.4.1 + 2. Kerberos to client KRB_TGS_REP or 5.4.2 + KRB_ERROR 5.9.1 + + The TGS exchange between a client and the Kerberos Ticket-Granting + Server is initiated by a client when it wishes to obtain + authentication credentials for a given server (which might be + registered in a remote realm), when it wishes to renew or validate an + existing ticket, or when it wishes to obtain a proxy ticket. In the + first case, the client must already have acquired a ticket for the + Ticket-Granting Service using the AS exchange (the ticket-granting + ticket is usually obtained when a client initially authenticates to + the system, such as when a user logs in). The message format for the + TGS exchange is almost identical to that for the AS exchange. The + primary difference is that encryption and decryption in the TGS + + + +Kohl & Neuman [Page 24] + +RFC 1510 Kerberos September 1993 + + + exchange does not take place under the client's key. Instead, the + session key from the ticket-granting ticket or renewable ticket, or + sub-session key from an Authenticator is used. As is the case for + all application servers, expired tickets are not accepted by the TGS, + so once a renewable or ticket-granting ticket expires, the client + must use a separate exchange to obtain valid tickets. + + The TGS exchange consists of two messages: A request (KRB_TGS_REQ) + from the client to the Kerberos Ticket-Granting Server, and a reply + (KRB_TGS_REP or KRB_ERROR). The KRB_TGS_REQ message includes + information authenticating the client plus a request for credentials. + The authentication information consists of the authentication header + (KRB_AP_REQ) which includes the client's previously obtained ticket- + granting, renewable, or invalid ticket. In the ticket-granting + ticket and proxy cases, the request may include one or more of: a + list of network addresses, a collection of typed authorization data + to be sealed in the ticket for authorization use by the application + server, or additional tickets (the use of which are described later). + The TGS reply (KRB_TGS_REP) contains the requested credentials, + encrypted in the session key from the ticket-granting ticket or + renewable ticket, or if present, in the subsession key from the + Authenticator (part of the authentication header). The KRB_ERROR + message contains an error code and text explaining what went wrong. + The KRB_ERROR message is not encrypted. The KRB_TGS_REP message + contains information which can be used to detect replays, and to + associate it with the message to which it replies. The KRB_ERROR + message also contains information which can be used to associate it + with the message to which it replies, but the lack of encryption in + the KRB_ERROR message precludes the ability to detect replays or + fabrications of such messages. + +3.3.1. Generation of KRB_TGS_REQ message + + Before sending a request to the ticket-granting service, the client + must determine in which realm the application server is registered + [Note: This can be accomplished in several ways. It might be known + beforehand (since the realm is part of the principal identifier), or + it might be stored in a nameserver. Presently, however, this + information is obtained from a configuration file. If the realm to + be used is obtained from a nameserver, there is a danger of being + spoofed if the nameservice providing the realm name is not + authenticated. This might result in the use of a realm which has + been compromised, and would result in an attacker's ability to + compromise the authentication of the application server to the + client.]. If the client does not already possess a ticket-granting + ticket for the appropriate realm, then one must be obtained. This is + first attempted by requesting a ticket-granting ticket for the + destination realm from the local Kerberos server (using the + + + +Kohl & Neuman [Page 25] + +RFC 1510 Kerberos September 1993 + + + KRB_TGS_REQ message recursively). The Kerberos server may return a + TGT for the desired realm in which case one can proceed. + Alternatively, the Kerberos server may return a TGT for a realm which + is "closer" to the desired realm (further along the standard + hierarchical path), in which case this step must be repeated with a + Kerberos server in the realm specified in the returned TGT. If + neither are returned, then the request must be retried with a + Kerberos server for a realm higher in the hierarchy. This request + will itself require a ticket-granting ticket for the higher realm + which must be obtained by recursively applying these directions. + + Once the client obtains a ticket-granting ticket for the appropriate + realm, it determines which Kerberos servers serve that realm, and + contacts one. The list might be obtained through a configuration file + or network service; as long as the secret keys exchanged by realms + are kept secret, only denial of service results from a false Kerberos + server. + + As in the AS exchange, the client may specify a number of options in + the KRB_TGS_REQ message. The client prepares the KRB_TGS_REQ + message, providing an authentication header as an element of the + padata field, and including the same fields as used in the KRB_AS_REQ + message along with several optional fields: the enc-authorization- + data field for application server use and additional tickets required + by some options. + + In preparing the authentication header, the client can select a sub- + session key under which the response from the Kerberos server will be + encrypted (If the client selects a sub-session key, care must be + taken to ensure the randomness of the selected subsession key. One + approach would be to generate a random number and XOR it with the + session key from the ticket-granting ticket.). If the sub-session key + is not specified, the session key from the ticket-granting ticket + will be used. If the enc-authorization-data is present, it must be + encrypted in the sub-session key, if present, from the authenticator + portion of the authentication header, or if not present in the + session key from the ticket-granting ticket. + + Once prepared, the message is sent to a Kerberos server for the + destination realm. See section A.5 for pseudocode. + +3.3.2. Receipt of KRB_TGS_REQ message + + The KRB_TGS_REQ message is processed in a manner similar to the + KRB_AS_REQ message, but there are many additional checks to be + performed. First, the Kerberos server must determine which server + the accompanying ticket is for and it must select the appropriate key + to decrypt it. For a normal KRB_TGS_REQ message, it will be for the + + + +Kohl & Neuman [Page 26] + +RFC 1510 Kerberos September 1993 + + + ticket granting service, and the TGS's key will be used. If the TGT + was issued by another realm, then the appropriate inter-realm key + must be used. If the accompanying ticket is not a ticket granting + ticket for the current realm, but is for an application server in the + current realm, the RENEW, VALIDATE, or PROXY options are specified in + the request, and the server for which a ticket is requested is the + server named in the accompanying ticket, then the KDC will decrypt + the ticket in the authentication header using the key of the server + for which it was issued. If no ticket can be found in the padata + field, the KDC_ERR_PADATA_TYPE_NOSUPP error is returned. + + Once the accompanying ticket has been decrypted, the user-supplied + checksum in the Authenticator must be verified against the contents + of the request, and the message rejected if the checksums do not + match (with an error code of KRB_AP_ERR_MODIFIED) or if the checksum + is not keyed or not collision-proof (with an error code of + KRB_AP_ERR_INAPP_CKSUM). If the checksum type is not supported, the + KDC_ERR_SUMTYPE_NOSUPP error is returned. If the authorization-data + are present, they are decrypted using the sub-session key from the + Authenticator. + + If any of the decryptions indicate failed integrity checks, the + KRB_AP_ERR_BAD_INTEGRITY error is returned. + +3.3.3. Generation of KRB_TGS_REP message + + The KRB_TGS_REP message shares its format with the KRB_AS_REP + (KRB_KDC_REP), but with its type field set to KRB_TGS_REP. The + detailed specification is in section 5.4.2. + + The response will include a ticket for the requested server. The + Kerberos database is queried to retrieve the record for the requested + server (including the key with which the ticket will be encrypted). + If the request is for a ticket granting ticket for a remote realm, + and if no key is shared with the requested realm, then the Kerberos + server will select the realm "closest" to the requested realm with + which it does share a key, and use that realm instead. This is the + only case where the response from the KDC will be for a different + server than that requested by the client. + + By default, the address field, the client's name and realm, the list + of transited realms, the time of initial authentication, the + expiration time, and the authorization data of the newly-issued + ticket will be copied from the ticket-granting ticket (TGT) or + renewable ticket. If the transited field needs to be updated, but + the transited type is not supported, the KDC_ERR_TRTYPE_NOSUPP error + is returned. + + + + +Kohl & Neuman [Page 27] + +RFC 1510 Kerberos September 1993 + + + If the request specifies an endtime, then the endtime of the new + ticket is set to the minimum of (a) that request, (b) the endtime + from the TGT, and (c) the starttime of the TGT plus the minimum of + the maximum life for the application server and the maximum life for + the local realm (the maximum life for the requesting principal was + already applied when the TGT was issued). If the new ticket is to be + a renewal, then the endtime above is replaced by the minimum of (a) + the value of the renew_till field of the ticket and (b) the starttime + for the new ticket plus the life (endtimestarttime) of the old + ticket. + + If the FORWARDED option has been requested, then the resulting ticket + will contain the addresses specified by the client. This option will + only be honored if the FORWARDABLE flag is set in the TGT. The PROXY + option is similar; the resulting ticket will contain the addresses + specified by the client. It will be honored only if the PROXIABLE + flag in the TGT is set. The PROXY option will not be honored on + requests for additional ticket-granting tickets. + + If the requested start time is absent or indicates a time in the + past, then the start time of the ticket is set to the authentication + server's current time. If it indicates a time in the future, but the + POSTDATED option has not been specified or the MAY-POSTDATE flag is + not set in the TGT, then the error KDC_ERR_CANNOT_POSTDATE is + returned. Otherwise, if the ticket-granting ticket has the + MAYPOSTDATE flag set, then the resulting ticket will be postdated and + the requested starttime is checked against the policy of the local + realm. If acceptable, the ticket's start time is set as requested, + and the INVALID flag is set. The postdated ticket must be validated + before use by presenting it to the KDC after the starttime has been + reached. However, in no case may the starttime, endtime, or renew- + till time of a newly-issued postdated ticket extend beyond the + renew-till time of the ticket-granting ticket. + + If the ENC-TKT-IN-SKEY option has been specified and an additional + ticket has been included in the request, the KDC will decrypt the + additional ticket using the key for the server to which the + additional ticket was issued and verify that it is a ticket-granting + ticket. If the name of the requested server is missing from the + request, the name of the client in the additional ticket will be + used. Otherwise the name of the requested server will be compared to + the name of the client in the additional ticket and if different, the + request will be rejected. If the request succeeds, the session key + from the additional ticket will be used to encrypt the new ticket + that is issued instead of using the key of the server for which the + new ticket will be used (This allows easy implementation of user-to- + user authentication [6], which uses ticket-granting ticket session + keys in lieu of secret server keys in situations where such secret + + + +Kohl & Neuman [Page 28] + +RFC 1510 Kerberos September 1993 + + + keys could be easily compromised.). + + If the name of the server in the ticket that is presented to the KDC + as part of the authentication header is not that of the ticket- + granting server itself, and the server is registered in the realm of + the KDC, If the RENEW option is requested, then the KDC will verify + that the RENEWABLE flag is set in the ticket and that the renew_till + time is still in the future. If the VALIDATE option is rqeuested, + the KDC will check that the starttime has passed and the INVALID flag + is set. If the PROXY option is requested, then the KDC will check + that the PROXIABLE flag is set in the ticket. If the tests succeed, + the KDC will issue the appropriate new ticket. + + Whenever a request is made to the ticket-granting server, the + presented ticket(s) is(are) checked against a hot-list of tickets + which have been canceled. This hot-list might be implemented by + storing a range of issue dates for "suspect tickets"; if a presented + ticket had an authtime in that range, it would be rejected. In this + way, a stolen ticket-granting ticket or renewable ticket cannot be + used to gain additional tickets (renewals or otherwise) once the + theft has been reported. Any normal ticket obtained before it was + reported stolen will still be valid (because they require no + interaction with the KDC), but only until their normal expiration + time. + + The ciphertext part of the response in the KRB_TGS_REP message is + encrypted in the sub-session key from the Authenticator, if present, + or the session key key from the ticket-granting ticket. It is not + encrypted using the client's secret key. Furthermore, the client's + key's expiration date and the key version number fields are left out + since these values are stored along with the client's database + record, and that record is not needed to satisfy a request based on a + ticket-granting ticket. See section A.6 for pseudocode. + +3.3.3.1. Encoding the transited field + + If the identity of the server in the TGT that is presented to the KDC + as part of the authentication header is that of the ticket-granting + service, but the TGT was issued from another realm, the KDC will look + up the inter-realm key shared with that realm and use that key to + decrypt the ticket. If the ticket is valid, then the KDC will honor + the request, subject to the constraints outlined above in the section + describing the AS exchange. The realm part of the client's identity + will be taken from the ticket-granting ticket. The name of the realm + that issued the ticket-granting ticket will be added to the transited + field of the ticket to be issued. This is accomplished by reading + the transited field from the ticket-granting ticket (which is treated + as an unordered set of realm names), adding the new realm to the set, + + + +Kohl & Neuman [Page 29] + +RFC 1510 Kerberos September 1993 + + + then constructing and writing out its encoded (shorthand) form (this + may involve a rearrangement of the existing encoding). + + Note that the ticket-granting service does not add the name of its + own realm. Instead, its responsibility is to add the name of the + previous realm. This prevents a malicious Kerberos server from + intentionally leaving out its own name (it could, however, omit other + realms' names). + + The names of neither the local realm nor the principal's realm are to + be included in the transited field. They appear elsewhere in the + ticket and both are known to have taken part in authenticating the + principal. Since the endpoints are not included, both local and + single-hop inter-realm authentication result in a transited field + that is empty. + + Because the name of each realm transited is added to this field, + it might potentially be very long. To decrease the length of this + field, its contents are encoded. The initially supported encoding is + optimized for the normal case of inter-realm communication: a + hierarchical arrangement of realms using either domain or X.500 style + realm names. This encoding (called DOMAIN-X500-COMPRESS) is now + described. + + Realm names in the transited field are separated by a ",". The ",", + "\", trailing "."s, and leading spaces (" ") are special characters, + and if they are part of a realm name, they must be quoted in the + transited field by preceding them with a "\". + + A realm name ending with a "." is interpreted as being prepended to + the previous realm. For example, we can encode traversal of EDU, + MIT.EDU, ATHENA.MIT.EDU, WASHINGTON.EDU, and CS.WASHINGTON.EDU as: + + "EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.". + + Note that if ATHENA.MIT.EDU, or CS.WASHINGTON.EDU were endpoints, + that they would not be included in this field, and we would have: + + "EDU,MIT.,WASHINGTON.EDU" + + A realm name beginning with a "/" is interpreted as being appended to + the previous realm (For the purpose of appending, the realm preceding + the first listed realm is considered to be the null realm ("")). If + it is to stand by itself, then it should be preceded by a space (" + "). For example, we can encode traversal of /COM/HP/APOLLO, /COM/HP, + /COM, and /COM/DEC as: + + "/COM,/HP,/APOLLO, /COM/DEC". + + + +Kohl & Neuman [Page 30] + +RFC 1510 Kerberos September 1993 + + + Like the example above, if /COM/HP/APOLLO and /COM/DEC are endpoints, + they they would not be included in this field, and we would have: + + "/COM,/HP" + + A null subfield preceding or following a "," indicates that all + realms between the previous realm and the next realm have been + traversed (For the purpose of interpreting null subfields, the + client's realm is considered to precede those in the transited field, + and the server's realm is considered to follow them.). Thus, "," + means that all realms along the path between the client and the + server have been traversed. ",EDU, /COM," means that that all realms + from the client's realm up to EDU (in a domain style hierarchy) have + been traversed, and that everything from /COM down to the server's + realm in an X.500 style has also been traversed. This could occur if + the EDU realm in one hierarchy shares an inter-realm key directly + with the /COM realm in another hierarchy. + +3.3.4. Receipt of KRB_TGS_REP message + + When the KRB_TGS_REP is received by the client, it is processed in + the same manner as the KRB_AS_REP processing described above. The + primary difference is that the ciphertext part of the response must + be decrypted using the session key from the ticket-granting ticket + rather than the client's secret key. See section A.7 for pseudocode. + +3.4. The KRB_SAFE Exchange + + The KRB_SAFE message may be used by clients requiring the ability to + detect modifications of messages they exchange. It achieves this by + including a keyed collisionproof checksum of the user data and some + control information. The checksum is keyed with an encryption key + (usually the last key negotiated via subkeys, or the session key if + no negotiation has occured). + +3.4.1. Generation of a KRB_SAFE message + + When an application wishes to send a KRB_SAFE message, it collects + its data and the appropriate control information and computes a + checksum over them. The checksum algorithm should be some sort of + keyed one-way hash function (such as the RSA-MD5-DES checksum + algorithm specified in section 6.4.5, or the DES MAC), generated + using the sub-session key if present, or the session key. Different + algorithms may be selected by changing the checksum type in the + message. Unkeyed or non-collision-proof checksums are not suitable + for this use. + + The control information for the KRB_SAFE message includes both a + + + +Kohl & Neuman [Page 31] + +RFC 1510 Kerberos September 1993 + + + timestamp and a sequence number. The designer of an application + using the KRB_SAFE message must choose at least one of the two + mechanisms. This choice should be based on the needs of the + application protocol. + + Sequence numbers are useful when all messages sent will be received + by one's peer. Connection state is presently required to maintain + the session key, so maintaining the next sequence number should not + present an additional problem. + + If the application protocol is expected to tolerate lost messages + without them being resent, the use of the timestamp is the + appropriate replay detection mechanism. Using timestamps is also the + appropriate mechanism for multi-cast protocols where all of one's + peers share a common sub-session key, but some messages will be sent + to a subset of one's peers. + + After computing the checksum, the client then transmits the + information and checksum to the recipient in the message format + specified in section 5.6.1. + +3.4.2. Receipt of KRB_SAFE message + + When an application receives a KRB_SAFE message, it verifies it as + follows. If any error occurs, an error code is reported for use by + the application. + + The message is first checked by verifying that the protocol version + and type fields match the current version and KRB_SAFE, respectively. + A mismatch generates a KRB_AP_ERR_BADVERSION or KRB_AP_ERR_MSG_TYPE + error. The application verifies that the checksum used is a + collisionproof keyed checksum, and if it is not, a + KRB_AP_ERR_INAPP_CKSUM error is generated. The recipient verifies + that the operating system's report of the sender's address matches + the sender's address in the message, and (if a recipient address is + specified or the recipient requires an address) that one of the + recipient's addresses appears as the recipient's address in the + message. A failed match for either case generates a + KRB_AP_ERR_BADADDR error. Then the timestamp and usec and/or the + sequence number fields are checked. If timestamp and usec are + expected and not present, or they are present but not current, the + KRB_AP_ERR_SKEW error is generated. If the server name, along with + the client name, time and microsecond fields from the Authenticator + match any recently-seen such tuples, the KRB_AP_ERR_REPEAT error is + generated. If an incorrect sequence number is included, or a + sequence number is expected but not present, the KRB_AP_ERR_BADORDER + error is generated. If neither a timestamp and usec or a sequence + number is present, a KRB_AP_ERR_MODIFIED error is generated. + + + +Kohl & Neuman [Page 32] + +RFC 1510 Kerberos September 1993 + + + Finally, the checksum is computed over the data and control + information, and if it doesn't match the received checksum, a + KRB_AP_ERR_MODIFIED error is generated. + + If all the checks succeed, the application is assured that the + message was generated by its peer and was not modified in transit. + +3.5. The KRB_PRIV Exchange + + The KRB_PRIV message may be used by clients requiring confidentiality + and the ability to detect modifications of exchanged messages. It + achieves this by encrypting the messages and adding control + information. + +3.5.1. Generation of a KRB_PRIV message + + When an application wishes to send a KRB_PRIV message, it collects + its data and the appropriate control information (specified in + section 5.7.1) and encrypts them under an encryption key (usually the + last key negotiated via subkeys, or the session key if no negotiation + has occured). As part of the control information, the client must + choose to use either a timestamp or a sequence number (or both); see + the discussion in section 3.4.1 for guidelines on which to use. + After the user data and control information are encrypted, the client + transmits the ciphertext and some "envelope" information to the + recipient. + +3.5.2. Receipt of KRB_PRIV message + + When an application receives a KRB_PRIV message, it verifies it as + follows. If any error occurs, an error code is reported for use by + the application. + + The message is first checked by verifying that the protocol version + and type fields match the current version and KRB_PRIV, respectively. + A mismatch generates a KRB_AP_ERR_BADVERSION or KRB_AP_ERR_MSG_TYPE + error. The application then decrypts the ciphertext and processes + the resultant plaintext. If decryption shows the data to have been + modified, a KRB_AP_ERR_BAD_INTEGRITY error is generated. The + recipient verifies that the operating system's report of the sender's + address matches the sender's address in the message, and (if a + recipient address is specified or the recipient requires an address) + that one of the recipient's addresses appears as the recipient's + address in the message. A failed match for either case generates a + KRB_AP_ERR_BADADDR error. Then the timestamp and usec and/or the + sequence number fields are checked. If timestamp and usec are + expected and not present, or they are present but not current, the + KRB_AP_ERR_SKEW error is generated. If the server name, along with + + + +Kohl & Neuman [Page 33] + +RFC 1510 Kerberos September 1993 + + + the client name, time and microsecond fields from the Authenticator + match any recently-seen such tuples, the KRB_AP_ERR_REPEAT error is + generated. If an incorrect sequence number is included, or a + sequence number is expected but not present, the KRB_AP_ERR_BADORDER + error is generated. If neither a timestamp and usec or a sequence + number is present, a KRB_AP_ERR_MODIFIED error is generated. + + If all the checks succeed, the application can assume the message was + generated by its peer, and was securely transmitted (without + intruders able to see the unencrypted contents). + +3.6. The KRB_CRED Exchange + + The KRB_CRED message may be used by clients requiring the ability to + send Kerberos credentials from one host to another. It achieves this + by sending the tickets together with encrypted data containing the + session keys and other information associated with the tickets. + +3.6.1. Generation of a KRB_CRED message + + When an application wishes to send a KRB_CRED message it first (using + the KRB_TGS exchange) obtains credentials to be sent to the remote + host. It then constructs a KRB_CRED message using the ticket or + tickets so obtained, placing the session key needed to use each + ticket in the key field of the corresponding KrbCredInfo sequence of + the encrypted part of the the KRB_CRED message. + + Other information associated with each ticket and obtained during the + KRB_TGS exchange is also placed in the corresponding KrbCredInfo + sequence in the encrypted part of the KRB_CRED message. The current + time and, if specifically required by the application the nonce, s- + address, and raddress fields, are placed in the encrypted part of the + KRB_CRED message which is then encrypted under an encryption key + previosuly exchanged in the KRB_AP exchange (usually the last key + negotiated via subkeys, or the session key if no negotiation has + occured). + +3.6.2. Receipt of KRB_CRED message + + When an application receives a KRB_CRED message, it verifies it. If + any error occurs, an error code is reported for use by the + application. The message is verified by checking that the protocol + version and type fields match the current version and KRB_CRED, + respectively. A mismatch generates a KRB_AP_ERR_BADVERSION or + KRB_AP_ERR_MSG_TYPE error. The application then decrypts the + ciphertext and processes the resultant plaintext. If decryption shows + the data to have been modified, a KRB_AP_ERR_BAD_INTEGRITY error is + generated. + + + +Kohl & Neuman [Page 34] + +RFC 1510 Kerberos September 1993 + + + If present or required, the recipient verifies that the operating + system's report of the sender's address matches the sender's address + in the message, and that one of the recipient's addresses appears as + the recipient's address in the message. A failed match for either + case generates a KRB_AP_ERR_BADADDR error. The timestamp and usec + fields (and the nonce field if required) are checked next. If the + timestamp and usec are not present, or they are present but not + current, the KRB_AP_ERR_SKEW error is generated. + + If all the checks succeed, the application stores each of the new + tickets in its ticket cache together with the session key and other + information in the corresponding KrbCredInfo sequence from the + encrypted part of the KRB_CRED message. + +4. The Kerberos Database + + The Kerberos server must have access to a database containing the + principal identifiers and secret keys of principals to be + authenticated (The implementation of the Kerberos server need not + combine the database and the server on the same machine; it is + feasible to store the principal database in, say, a network name + service, as long as the entries stored therein are protected from + disclosure to and modification by unauthorized parties. However, we + recommend against such strategies, as they can make system management + and threat analysis quite complex.). + +4.1. Database contents + + A database entry should contain at least the following fields: + + Field Value + + name Principal's identifier + key Principal's secret key + p_kvno Principal's key version + max_life Maximum lifetime for Tickets + max_renewable_life Maximum total lifetime for renewable + Tickets + + The name field is an encoding of the principal's identifier. The key + field contains an encryption key. This key is the principal's secret + key. (The key can be encrypted before storage under a Kerberos + "master key" to protect it in case the database is compromised but + the master key is not. In that case, an extra field must be added to + indicate the master key version used, see below.) The p_kvno field is + the key version number of the principal's secret key. The max_life + field contains the maximum allowable lifetime (endtime - starttime) + for any Ticket issued for this principal. The max_renewable_life + + + +Kohl & Neuman [Page 35] + +RFC 1510 Kerberos September 1993 + + + field contains the maximum allowable total lifetime for any renewable + Ticket issued for this principal. (See section 3.1 for a description + of how these lifetimes are used in determining the lifetime of a + given Ticket.) + + A server may provide KDC service to several realms, as long as the + database representation provides a mechanism to distinguish between + principal records with identifiers which differ only in the realm + name. + + When an application server's key changes, if the change is routine + (i.e., not the result of disclosure of the old key), the old key + should be retained by the server until all tickets that had been + issued using that key have expired. Because of this, it is possible + for several keys to be active for a single principal. Ciphertext + encrypted in a principal's key is always tagged with the version of + the key that was used for encryption, to help the recipient find the + proper key for decryption. + + When more than one key is active for a particular principal, the + principal will have more than one record in the Kerberos database. + The keys and key version numbers will differ between the records (the + rest of the fields may or may not be the same). Whenever Kerberos + issues a ticket, or responds to a request for initial authentication, + the most recent key (known by the Kerberos server) will be used for + encryption. This is the key with the highest key version number. + +4.2. Additional fields + + Project Athena's KDC implementation uses additional fields in its + database: + + Field Value + + K_kvno Kerberos' key version + expiration Expiration date for entry + attributes Bit field of attributes + mod_date Timestamp of last modification + mod_name Modifying principal's identifier + + The K_kvno field indicates the key version of the Kerberos master key + under which the principal's secret key is encrypted. + + After an entry's expiration date has passed, the KDC will return an + error to any client attempting to gain tickets as or for the + principal. (A database may want to maintain two expiration dates: + one for the principal, and one for the principal's current key. This + allows password aging to work independently of the principal's + + + +Kohl & Neuman [Page 36] + +RFC 1510 Kerberos September 1993 + + + expiration date. However, due to the limited space in the responses, + the KDC must combine the key expiration and principal expiration date + into a single value called "key_exp", which is used as a hint to the + user to take administrative action.) + + The attributes field is a bitfield used to govern the operations + involving the principal. This field might be useful in conjunction + with user registration procedures, for site-specific policy + implementations (Project Athena currently uses it for their user + registration process controlled by the system-wide database service, + Moira [7]), or to identify the "string to key" conversion algorithm + used for a principal's key. (See the discussion of the padata field + in section 5.4.2 for details on why this can be useful.) Other bits + are used to indicate that certain ticket options should not be + allowed in tickets encrypted under a principal's key (one bit each): + Disallow issuing postdated tickets, disallow issuing forwardable + tickets, disallow issuing tickets based on TGT authentication, + disallow issuing renewable tickets, disallow issuing proxiable + tickets, and disallow issuing tickets for which the principal is the + server. + + The mod_date field contains the time of last modification of the + entry, and the mod_name field contains the name of the principal + which last modified the entry. + +4.3. Frequently Changing Fields + + Some KDC implementations may wish to maintain the last time that a + request was made by a particular principal. Information that might + be maintained includes the time of the last request, the time of the + last request for a ticket-granting ticket, the time of the last use + of a ticket-granting ticket, or other times. This information can + then be returned to the user in the last-req field (see section 5.2). + + Other frequently changing information that can be maintained is the + latest expiration time for any tickets that have been issued using + each key. This field would be used to indicate how long old keys + must remain valid to allow the continued use of outstanding tickets. + +4.4. Site Constants + + The KDC implementation should have the following configurable + constants or options, to allow an administrator to make and enforce + policy decisions: + + + The minimum supported lifetime (used to determine whether the + KDC_ERR_NEVER_VALID error should be returned). This constant + should reflect reasonable expectations of round-trip time to the + + + +Kohl & Neuman [Page 37] + +RFC 1510 Kerberos September 1993 + + + KDC, encryption/decryption time, and processing time by the client + and target server, and it should allow for a minimum "useful" + lifetime. + + + The maximum allowable total (renewable) lifetime of a ticket + (renew_till - starttime). + + + The maximum allowable lifetime of a ticket (endtime - starttime). + + + Whether to allow the issue of tickets with empty address fields + (including the ability to specify that such tickets may only be + issued if the request specifies some authorization_data). + + + Whether proxiable, forwardable, renewable or post-datable tickets + are to be issued. + +5. Message Specifications + + The following sections describe the exact contents and encoding of + protocol messages and objects. The ASN.1 base definitions are + presented in the first subsection. The remaining subsections specify + the protocol objects (tickets and authenticators) and messages. + Specification of encryption and checksum techniques, and the fields + related to them, appear in section 6. + +5.1. ASN.1 Distinguished Encoding Representation + + All uses of ASN.1 in Kerberos shall use the Distinguished Encoding + Representation of the data elements as described in the X.509 + specification, section 8.7 [8]. + +5.2. ASN.1 Base Definitions + + The following ASN.1 base definitions are used in the rest of this + section. Note that since the underscore character (_) is not + permitted in ASN.1 names, the hyphen (-) is used in its place for the + purposes of ASN.1 names. + + Realm ::= GeneralString + PrincipalName ::= SEQUENCE { + name-type[0] INTEGER, + name-string[1] SEQUENCE OF GeneralString + } + + Kerberos realms are encoded as GeneralStrings. Realms shall not + contain a character with the code 0 (the ASCII NUL). Most realms + will usually consist of several components separated by periods (.), + in the style of Internet Domain Names, or separated by slashes (/) in + + + +Kohl & Neuman [Page 38] + +RFC 1510 Kerberos September 1993 + + + the style of X.500 names. Acceptable forms for realm names are + specified in section 7. A PrincipalName is a typed sequence of + components consisting of the following sub-fields: + + name-type This field specifies the type of name that follows. + Pre-defined values for this field are + specified in section 7.2. The name-type should be + treated as a hint. Ignoring the name type, no two + names can be the same (i.e., at least one of the + components, or the realm, must be different). + This constraint may be eliminated in the future. + + name-string This field encodes a sequence of components that + form a name, each component encoded as a General + String. Taken together, a PrincipalName and a Realm + form a principal identifier. Most PrincipalNames + will have only a few components (typically one or two). + + KerberosTime ::= GeneralizedTime + -- Specifying UTC time zone (Z) + + The timestamps used in Kerberos are encoded as GeneralizedTimes. An + encoding shall specify the UTC time zone (Z) and shall not include + any fractional portions of the seconds. It further shall not include + any separators. Example: The only valid format for UTC time 6 + minutes, 27 seconds after 9 pm on 6 November 1985 is 19851106210627Z. + + HostAddress ::= SEQUENCE { + addr-type[0] INTEGER, + address[1] OCTET STRING + } + + HostAddresses ::= SEQUENCE OF SEQUENCE { + addr-type[0] INTEGER, + address[1] OCTET STRING + } + + + The host adddress encodings consists of two fields: + + addr-type This field specifies the type of address that + follows. Pre-defined values for this field are + specified in section 8.1. + + + address This field encodes a single address of type addr-type. + + The two forms differ slightly. HostAddress contains exactly one + + + +Kohl & Neuman [Page 39] + +RFC 1510 Kerberos September 1993 + + + address; HostAddresses contains a sequence of possibly many + addresses. + + AuthorizationData ::= SEQUENCE OF SEQUENCE { + ad-type[0] INTEGER, + ad-data[1] OCTET STRING + } + + + ad-data This field contains authorization data to be + interpreted according to the value of the + corresponding ad-type field. + + ad-type This field specifies the format for the ad-data + subfield. All negative values are reserved for + local use. Non-negative values are reserved for + registered use. + + APOptions ::= BIT STRING { + reserved(0), + use-session-key(1), + mutual-required(2) + } + + + TicketFlags ::= BIT STRING { + reserved(0), + forwardable(1), + forwarded(2), + proxiable(3), + proxy(4), + may-postdate(5), + postdated(6), + invalid(7), + renewable(8), + initial(9), + pre-authent(10), + hw-authent(11) + } + + KDCOptions ::= BIT STRING { + reserved(0), + forwardable(1), + forwarded(2), + proxiable(3), + proxy(4), + allow-postdate(5), + postdated(6), + + + +Kohl & Neuman [Page 40] + +RFC 1510 Kerberos September 1993 + + + unused7(7), + renewable(8), + unused9(9), + unused10(10), + unused11(11), + renewable-ok(27), + enc-tkt-in-skey(28), + renew(30), + validate(31) + } + + + LastReq ::= SEQUENCE OF SEQUENCE { + lr-type[0] INTEGER, + lr-value[1] KerberosTime + } + + lr-type This field indicates how the following lr-value + field is to be interpreted. Negative values indicate + that the information pertains only to the + responding server. Non-negative values pertain to + all servers for the realm. + + If the lr-type field is zero (0), then no information + is conveyed by the lr-value subfield. If the + absolute value of the lr-type field is one (1), + then the lr-value subfield is the time of last + initial request for a TGT. If it is two (2), then + the lr-value subfield is the time of last initial + request. If it is three (3), then the lr-value + subfield is the time of issue for the newest + ticket-granting ticket used. If it is four (4), + then the lr-value subfield is the time of the last + renewal. If it is five (5), then the lr-value + subfield is the time of last request (of any + type). + + lr-value This field contains the time of the last request. + The time must be interpreted according to the contents + of the accompanying lr-type subfield. + + See section 6 for the definitions of Checksum, ChecksumType, + EncryptedData, EncryptionKey, EncryptionType, and KeyType. + + + + + + + + +Kohl & Neuman [Page 41] + +RFC 1510 Kerberos September 1993 + + +5.3. Tickets and Authenticators + + This section describes the format and encryption parameters for + tickets and authenticators. When a ticket or authenticator is + included in a protocol message it is treated as an opaque object. + +5.3.1. Tickets + + A ticket is a record that helps a client authenticate to a service. + A Ticket contains the following information: + +Ticket ::= [APPLICATION 1] SEQUENCE { + tkt-vno[0] INTEGER, + realm[1] Realm, + sname[2] PrincipalName, + enc-part[3] EncryptedData +} +-- Encrypted part of ticket +EncTicketPart ::= [APPLICATION 3] SEQUENCE { + flags[0] TicketFlags, + key[1] EncryptionKey, + crealm[2] Realm, + cname[3] PrincipalName, + transited[4] TransitedEncoding, + authtime[5] KerberosTime, + starttime[6] KerberosTime OPTIONAL, + endtime[7] KerberosTime, + renew-till[8] KerberosTime OPTIONAL, + caddr[9] HostAddresses OPTIONAL, + authorization-data[10] AuthorizationData OPTIONAL +} +-- encoded Transited field +TransitedEncoding ::= SEQUENCE { + tr-type[0] INTEGER, -- must be registered + contents[1] OCTET STRING +} + + The encoding of EncTicketPart is encrypted in the key shared by + Kerberos and the end server (the server's secret key). See section 6 + for the format of the ciphertext. + + tkt-vno This field specifies the version number for the ticket + format. This document describes version number 5. + + realm This field specifies the realm that issued a ticket. It + also serves to identify the realm part of the server's + principal identifier. Since a Kerberos server can only + issue tickets for servers within its realm, the two will + + + +Kohl & Neuman [Page 42] + +RFC 1510 Kerberos September 1993 + + + always be identical. + + sname This field specifies the name part of the server's + identity. + + enc-part This field holds the encrypted encoding of the + EncTicketPart sequence. + + flags This field indicates which of various options were used or + requested when the ticket was issued. It is a bit-field, + where the selected options are indicated by the bit being + set (1), and the unselected options and reserved fields + being reset (0). Bit 0 is the most significant bit. The + encoding of the bits is specified in section 5.2. The + flags are described in more detail above in section 2. The + meanings of the flags are: + + Bit(s) Name Description + + 0 RESERVED Reserved for future expansion of this + field. + + 1 FORWARDABLE The FORWARDABLE flag is normally only + interpreted by the TGS, and can be + ignored by end servers. When set, + this flag tells the ticket-granting + server that it is OK to issue a new + ticket- granting ticket with a + different network address based on + the presented ticket. + + 2 FORWARDED When set, this flag indicates that + the ticket has either been forwarded + or was issued based on authentication + involving a forwarded ticket-granting + ticket. + + 3 PROXIABLE The PROXIABLE flag is normally only + interpreted by the TGS, and can be + ignored by end servers. The PROXIABLE + flag has an interpretation identical + to that of the FORWARDABLE flag, + except that the PROXIABLE flag tells + the ticket-granting server that only + non- ticket-granting tickets may be + issued with different network + addresses. + + + + +Kohl & Neuman [Page 43] + +RFC 1510 Kerberos September 1993 + + + 4 PROXY When set, this flag indicates that a + ticket is a proxy. + + 5 MAY-POSTDATE The MAY-POSTDATE flag is normally + only interpreted by the TGS, and can + be ignored by end servers. This flag + tells the ticket-granting server that + a post- dated ticket may be issued + based on this ticket-granting ticket. + + 6 POSTDATED This flag indicates that this ticket + has been postdated. The end-service + can check the authtime field to see + when the original authentication + occurred. + + 7 INVALID This flag indicates that a ticket is + invalid, and it must be validated by + the KDC before use. Application + servers must reject tickets which + have this flag set. + + 8 RENEWABLE The RENEWABLE flag is normally only + interpreted by the TGS, and can + usually be ignored by end servers + (some particularly careful servers + may wish to disallow renewable + tickets). A renewable ticket can be + used to obtain a replacement ticket + that expires at a later date. + + 9 INITIAL This flag indicates that this ticket + was issued using the AS protocol, and + not issued based on a ticket-granting + ticket. + + 10 PRE-AUTHENT This flag indicates that during + initial authentication, the client + was authenticated by the KDC before a + ticket was issued. The strength of + the preauthentication method is not + indicated, but is acceptable to the + KDC. + + 11 HW-AUTHENT This flag indicates that the protocol + employed for initial authentication + required the use of hardware expected + to be possessed solely by the named + + + +Kohl & Neuman [Page 44] + +RFC 1510 Kerberos September 1993 + + + client. The hardware authentication + method is selected by the KDC and the + strength of the method is not + indicated. + + 12-31 RESERVED Reserved for future use. + + key This field exists in the ticket and the KDC response and is + used to pass the session key from Kerberos to the + application server and the client. The field's encoding is + described in section 6.2. + + crealm This field contains the name of the realm in which the + client is registered and in which initial authentication + took place. + + cname This field contains the name part of the client's principal + identifier. + + transited This field lists the names of the Kerberos realms that took + part in authenticating the user to whom this ticket was + issued. It does not specify the order in which the realms + were transited. See section 3.3.3.1 for details on how + this field encodes the traversed realms. + + authtime This field indicates the time of initial authentication for + the named principal. It is the time of issue for the + original ticket on which this ticket is based. It is + included in the ticket to provide additional information to + the end service, and to provide the necessary information + for implementation of a `hot list' service at the KDC. An + end service that is particularly paranoid could refuse to + accept tickets for which the initial authentication + occurred "too far" in the past. + + This field is also returned as part of the response from + the KDC. When returned as part of the response to initial + authentication (KRB_AS_REP), this is the current time on + the Kerberos server (It is NOT recommended that this time + value be used to adjust the workstation's clock since the + workstation cannot reliably determine that such a + KRB_AS_REP actually came from the proper KDC in a timely + manner.). + + starttime This field in the ticket specifies the time after which the + ticket is valid. Together with endtime, this field + specifies the life of the ticket. If it is absent from + the ticket, its value should be treated as that of the + + + +Kohl & Neuman [Page 45] + +RFC 1510 Kerberos September 1993 + + + authtime field. + + endtime This field contains the time after which the ticket will + not be honored (its expiration time). Note that individual + services may place their own limits on the life of a ticket + and may reject tickets which have not yet expired. As + such, this is really an upper bound on the expiration time + for the ticket. + + renew-till This field is only present in tickets that have the + RENEWABLE flag set in the flags field. It indicates the + maximum endtime that may be included in a renewal. It can + be thought of as the absolute expiration time for the + ticket, including all renewals. + + caddr This field in a ticket contains zero (if omitted) or more + (if present) host addresses. These are the addresses from + which the ticket can be used. If there are no addresses, + the ticket can be used from any location. The decision + by the KDC to issue or by the end server to accept zero- + address tickets is a policy decision and is left to the + Kerberos and end-service administrators; they may refuse to + issue or accept such tickets. The suggested and default + policy, however, is that such tickets will only be issued + or accepted when additional information that can be used to + restrict the use of the ticket is included in the + authorization_data field. Such a ticket is a capability. + + Network addresses are included in the ticket to make it + harder for an attacker to use stolen credentials. Because + the session key is not sent over the network in cleartext, + credentials can't be stolen simply by listening to the + network; an attacker has to gain access to the session key + (perhaps through operating system security breaches or a + careless user's unattended session) to make use of stolen + tickets. + + It is important to note that the network address from which + a connection is received cannot be reliably determined. + Even if it could be, an attacker who has compromised the + client's workstation could use the credentials from there. + Including the network addresses only makes it more + difficult, not impossible, for an attacker to walk off with + stolen credentials and then use them from a "safe" + location. + + + + + + +Kohl & Neuman [Page 46] + +RFC 1510 Kerberos September 1993 + + + authorization-data The authorization-data field is used to pass + authorization data from the principal on whose behalf a + ticket was issued to the application service. If no + authorization data is included, this field will be left + out. The data in this field are specific to the end + service. It is expected that the field will contain the + names of service specific objects, and the rights to those + objects. The format for this field is described in section + 5.2. Although Kerberos is not concerned with the format of + the contents of the subfields, it does carry type + information (ad-type). + + By using the authorization_data field, a principal is able + to issue a proxy that is valid for a specific purpose. For + example, a client wishing to print a file can obtain a file + server proxy to be passed to the print server. By + specifying the name of the file in the authorization_data + field, the file server knows that the print server can only + use the client's rights when accessing the particular file + to be printed. + + It is interesting to note that if one specifies the + authorization-data field of a proxy and leaves the host + addresses blank, the resulting ticket and session key can + be treated as a capability. See [9] for some suggested + uses of this field. + + The authorization-data field is optional and does not have + to be included in a ticket. + +5.3.2. Authenticators + + An authenticator is a record sent with a ticket to a server to + certify the client's knowledge of the encryption key in the ticket, + to help the server detect replays, and to help choose a "true session + key" to use with the particular session. The encoding is encrypted + in the ticket's session key shared by the client and the server: + +-- Unencrypted authenticator +Authenticator ::= [APPLICATION 2] SEQUENCE { + authenticator-vno[0] INTEGER, + crealm[1] Realm, + cname[2] PrincipalName, + cksum[3] Checksum OPTIONAL, + cusec[4] INTEGER, + ctime[5] KerberosTime, + subkey[6] EncryptionKey OPTIONAL, + seq-number[7] INTEGER OPTIONAL, + + + +Kohl & Neuman [Page 47] + +RFC 1510 Kerberos September 1993 + + + authorization-data[8] AuthorizationData OPTIONAL + } + + authenticator-vno This field specifies the version number for the + format of the authenticator. This document specifies + version 5. + + crealm and cname These fields are the same as those described for the + ticket in section 5.3.1. + + cksum This field contains a checksum of the the application data + that accompanies the KRB_AP_REQ. + + cusec This field contains the microsecond part of the client's + timestamp. Its value (before encryption) ranges from 0 to + 999999. It often appears along with ctime. The two fields + are used together to specify a reasonably accurate + timestamp. + + ctime This field contains the current time on the client's host. + + subkey This field contains the client's choice for an encryption + key which is to be used to protect this specific + application session. Unless an application specifies + otherwise, if this field is left out the session key from + the ticket will be used. + + seq-number This optional field includes the initial sequence number + to be used by the KRB_PRIV or KRB_SAFE messages when + sequence numbers are used to detect replays (It may also be + used by application specific messages). When included in + the authenticator this field specifies the initial sequence + number for messages from the client to the server. When + included in the AP-REP message, the initial sequence number + is that for messages from the server to the client. When + used in KRB_PRIV or KRB_SAFE messages, it is incremented by + one after each message is sent. + + For sequence numbers to adequately support the detection of + replays they should be non-repeating, even across + connection boundaries. The initial sequence number should + be random and uniformly distributed across the full space + of possible sequence numbers, so that it cannot be guessed + by an attacker and so that it and the successive sequence + numbers do not repeat other sequences. + + + + + + +Kohl & Neuman [Page 48] + +RFC 1510 Kerberos September 1993 + + + authorization-data This field is the same as described for the ticket + in section 5.3.1. It is optional and will only appear when + additional restrictions are to be placed on the use of a + ticket, beyond those carried in the ticket itself. + +5.4. Specifications for the AS and TGS exchanges + + This section specifies the format of the messages used in exchange + between the client and the Kerberos server. The format of possible + error messages appears in section 5.9.1. + +5.4.1. KRB_KDC_REQ definition + + The KRB_KDC_REQ message has no type of its own. Instead, its type is + one of KRB_AS_REQ or KRB_TGS_REQ depending on whether the request is + for an initial ticket or an additional ticket. In either case, the + message is sent from the client to the Authentication Server to + request credentials for a service. + +The message fields are: + +AS-REQ ::= [APPLICATION 10] KDC-REQ +TGS-REQ ::= [APPLICATION 12] KDC-REQ + +KDC-REQ ::= SEQUENCE { + pvno[1] INTEGER, + msg-type[2] INTEGER, + padata[3] SEQUENCE OF PA-DATA OPTIONAL, + req-body[4] KDC-REQ-BODY +} + +PA-DATA ::= SEQUENCE { + padata-type[1] INTEGER, + padata-value[2] OCTET STRING, + -- might be encoded AP-REQ +} + +KDC-REQ-BODY ::= SEQUENCE { + kdc-options[0] KDCOptions, + cname[1] PrincipalName OPTIONAL, + -- Used only in AS-REQ + realm[2] Realm, -- Server's realm + -- Also client's in AS-REQ + sname[3] PrincipalName OPTIONAL, + from[4] KerberosTime OPTIONAL, + till[5] KerberosTime, + rtime[6] KerberosTime OPTIONAL, + nonce[7] INTEGER, + + + +Kohl & Neuman [Page 49] + +RFC 1510 Kerberos September 1993 + + + etype[8] SEQUENCE OF INTEGER, -- EncryptionType, + -- in preference order + addresses[9] HostAddresses OPTIONAL, + enc-authorization-data[10] EncryptedData OPTIONAL, + -- Encrypted AuthorizationData encoding + additional-tickets[11] SEQUENCE OF Ticket OPTIONAL +} + + The fields in this message are: + + pvno This field is included in each message, and specifies the + protocol version number. This document specifies protocol + version 5. + + msg-type This field indicates the type of a protocol message. It + will almost always be the same as the application + identifier associated with a message. It is included to + make the identifier more readily accessible to the + application. For the KDC-REQ message, this type will be + KRB_AS_REQ or KRB_TGS_REQ. + + padata The padata (pre-authentication data) field contains a of + authentication information which may be needed before + credentials can be issued or decrypted. In the case of + requests for additional tickets (KRB_TGS_REQ), this field + will include an element with padata-type of PA-TGS-REQ and + data of an authentication header (ticket-granting ticket + and authenticator). The checksum in the authenticator + (which must be collisionproof) is to be computed over the + KDC-REQ-BODY encoding. In most requests for initial + authentication (KRB_AS_REQ) and most replies (KDC-REP), the + padata field will be left out. + + This field may also contain information needed by certain + extensions to the Kerberos protocol. For example, it might + be used to initially verify the identity of a client before + any response is returned. This is accomplished with a + padata field with padata-type equal to PA-ENC-TIMESTAMP and + padata-value defined as follows: + + padata-type ::= PA-ENC-TIMESTAMP + padata-value ::= EncryptedData -- PA-ENC-TS-ENC + + PA-ENC-TS-ENC ::= SEQUENCE { + patimestamp[0] KerberosTime, -- client's time + pausec[1] INTEGER OPTIONAL + } + + + + +Kohl & Neuman [Page 50] + +RFC 1510 Kerberos September 1993 + + + with patimestamp containing the client's time and pausec + containing the microseconds which may be omitted if a + client will not generate more than one request per second. + The ciphertext (padata-value) consists of the PA-ENC-TS-ENC + sequence, encrypted using the client's secret key. + + The padata field can also contain information needed to + help the KDC or the client select the key needed for + generating or decrypting the response. This form of the + padata is useful for supporting the use of certain + "smartcards" with Kerberos. The details of such extensions + are beyond the scope of this specification. See [10] for + additional uses of this field. + + padata-type The padata-type element of the padata field indicates the + way that the padata-value element is to be interpreted. + Negative values of padata-type are reserved for + unregistered use; non-negative values are used for a + registered interpretation of the element type. + + req-body This field is a placeholder delimiting the extent of the + remaining fields. If a checksum is to be calculated over + the request, it is calculated over an encoding of the KDC- + REQ-BODY sequence which is enclosed within the req-body + field. + + kdc-options This field appears in the KRB_AS_REQ and KRB_TGS_REQ + requests to the KDC and indicates the flags that the client + wants set on the tickets as well as other information that + is to modify the behavior of the KDC. Where appropriate, + the name of an option may be the same as the flag that is + set by that option. Although in most case, the bit in the + options field will be the same as that in the flags field, + this is not guaranteed, so it is not acceptable to simply + copy the options field to the flags field. There are + various checks that must be made before honoring an option + anyway. + + The kdc_options field is a bit-field, where the selected + options are indicated by the bit being set (1), and the + unselected options and reserved fields being reset (0). + The encoding of the bits is specified in section 5.2. The + options are described in more detail above in section 2. + The meanings of the options are: + + + + + + + +Kohl & Neuman [Page 51] + +RFC 1510 Kerberos September 1993 + + + Bit(s) Name Description + + 0 RESERVED Reserved for future expansion of this + field. + + 1 FORWARDABLE The FORWARDABLE option indicates that + the ticket to be issued is to have its + forwardable flag set. It may only be + set on the initial request, or in a + subsequent request if the ticket- + granting ticket on which it is based + is also forwardable. + + 2 FORWARDED The FORWARDED option is only specified + in a request to the ticket-granting + server and will only be honored if the + ticket-granting ticket in the request + has its FORWARDABLE bit set. This + option indicates that this is a + request for forwarding. The + address(es) of the host from which the + resulting ticket is to be valid are + included in the addresses field of the + request. + + + 3 PROXIABLE The PROXIABLE option indicates that + the ticket to be issued is to have its + proxiable flag set. It may only be set + on the initial request, or in a + subsequent request if the ticket- + granting ticket on which it is based + is also proxiable. + + 4 PROXY The PROXY option indicates that this + is a request for a proxy. This option + will only be honored if the ticket- + granting ticket in the request has its + PROXIABLE bit set. The address(es) of + the host from which the resulting + ticket is to be valid are included in + the addresses field of the request. + + 5 ALLOW-POSTDATE The ALLOW-POSTDATE option indicates + that the ticket to be issued is to + have its MAY-POSTDATE flag set. It + may only be set on the initial + request, or in a subsequent request if + + + +Kohl & Neuman [Page 52] + +RFC 1510 Kerberos September 1993 + + + the ticket-granting ticket on which it + is based also has its MAY-POSTDATE + flag set. + + 6 POSTDATED The POSTDATED option indicates that + this is a request for a postdated + ticket. This option will only be + honored if the ticket-granting ticket + on which it is based has its MAY- + POSTDATE flag set. The resulting + ticket will also have its INVALID flag + set, and that flag may be reset by a + subsequent request to the KDC after + the starttime in the ticket has been + reached. + + 7 UNUSED This option is presently unused. + + 8 RENEWABLE The RENEWABLE option indicates that + the ticket to be issued is to have its + RENEWABLE flag set. It may only be + set on the initial request, or when + the ticket-granting ticket on which + the request is based is also + renewable. If this option is + requested, then the rtime field in the + request contains the desired absolute + expiration time for the ticket. + + 9-26 RESERVED Reserved for future use. + + 27 RENEWABLE-OK The RENEWABLE-OK option indicates that + a renewable ticket will be acceptable + if a ticket with the requested life + cannot otherwise be provided. If a + ticket with the requested life cannot + be provided, then a renewable ticket + may be issued with a renew-till equal + to the the requested endtime. The + value of the renew-till field may + still be limited by local limits, or + limits selected by the individual + principal or server. + + 28 ENC-TKT-IN-SKEY This option is used only by the + ticket-granting service. The ENC- + TKT-IN-SKEY option indicates that the + ticket for the end server is to be + + + +Kohl & Neuman [Page 53] + +RFC 1510 Kerberos September 1993 + + + encrypted in the session key from the + additional ticket-granting ticket + provided. + + 29 RESERVED Reserved for future use. + + 30 RENEW This option is used only by the + ticket-granting service. The RENEW + option indicates that the present + request is for a renewal. The ticket + provided is encrypted in the secret + key for the server on which it is + valid. This option will only be + honored if the ticket to be renewed + has its RENEWABLE flag set and if the + time in its renew till field has not + passed. The ticket to be renewed is + passed in the padata field as part of + the authentication header. + + 31 VALIDATE This option is used only by the + ticket-granting service. The VALIDATE + option indicates that the request is + to validate a postdated ticket. It + will only be honored if the ticket + presented is postdated, presently has + its INVALID flag set, and would be + otherwise usable at this time. A + ticket cannot be validated before its + starttime. The ticket presented for + validation is encrypted in the key of + the server for which it is valid and + is passed in the padata field as part + of the authentication header. + + cname and sname These fields are the same as those described for the + ticket in section 5.3.1. sname may only be absent when the + ENC-TKT-IN-SKEY option is specified. If absent, the name + of the server is taken from the name of the client in the + ticket passed as additional-tickets. + + enc-authorization-data The enc-authorization-data, if present (and it + can only be present in the TGS_REQ form), is an encoding of + the desired authorization-data encrypted under the sub- + session key if present in the Authenticator, or + alternatively from the session key in the ticket-granting + ticket, both from the padata field in the KRB_AP_REQ. + + + + +Kohl & Neuman [Page 54] + +RFC 1510 Kerberos September 1993 + + + realm This field specifies the realm part of the server's + principal identifier. In the AS exchange, this is also the + realm part of the client's principal identifier. + + from This field is included in the KRB_AS_REQ and KRB_TGS_REQ + ticket requests when the requested ticket is to be + postdated. It specifies the desired start time for the + requested ticket. + + till This field contains the expiration date requested by the + client in a ticket request. + + rtime This field is the requested renew-till time sent from a + client to the KDC in a ticket request. It is optional. + + nonce This field is part of the KDC request and response. It it + intended to hold a random number generated by the client. + If the same number is included in the encrypted response + from the KDC, it provides evidence that the response is + fresh and has not been replayed by an attacker. Nonces + must never be re-used. Ideally, it should be gen erated + randomly, but if the correct time is known, it may suffice + (Note, however, that if the time is used as the nonce, one + must make sure that the workstation time is monotonically + increasing. If the time is ever reset backwards, there is + a small, but finite, probability that a nonce will be + reused.). + + etype This field specifies the desired encryption algorithm to be + used in the response. + + addresses This field is included in the initial request for tickets, + and optionally included in requests for additional tickets + from the ticket-granting server. It specifies the + addresses from which the requested ticket is to be valid. + Normally it includes the addresses for the client's host. + If a proxy is requested, this field will contain other + addresses. The contents of this field are usually copied + by the KDC into the caddr field of the resulting ticket. + + additional-tickets Additional tickets may be optionally included in a + request to the ticket-granting server. If the ENC-TKT-IN- + SKEY option has been specified, then the session key from + the additional ticket will be used in place of the server's + key to encrypt the new ticket. If more than one option + which requires additional tickets has been specified, then + the additional tickets are used in the order specified by + the ordering of the options bits (see kdc-options, above). + + + +Kohl & Neuman [Page 55] + +RFC 1510 Kerberos September 1993 + + + The application code will be either ten (10) or twelve (12) depending + on whether the request is for an initial ticket (AS-REQ) or for an + additional ticket (TGS-REQ). + + The optional fields (addresses, authorization-data and additional- + tickets) are only included if necessary to perform the operation + specified in the kdc-options field. + + It should be noted that in KRB_TGS_REQ, the protocol version number + appears twice and two different message types appear: the KRB_TGS_REQ + message contains these fields as does the authentication header + (KRB_AP_REQ) that is passed in the padata field. + +5.4.2. KRB_KDC_REP definition + + The KRB_KDC_REP message format is used for the reply from the KDC for + either an initial (AS) request or a subsequent (TGS) request. There + is no message type for KRB_KDC_REP. Instead, the type will be either + KRB_AS_REP or KRB_TGS_REP. The key used to encrypt the ciphertext + part of the reply depends on the message type. For KRB_AS_REP, the + ciphertext is encrypted in the client's secret key, and the client's + key version number is included in the key version number for the + encrypted data. For KRB_TGS_REP, the ciphertext is encrypted in the + sub-session key from the Authenticator, or if absent, the session key + from the ticket-granting ticket used in the request. In that case, + no version number will be present in the EncryptedData sequence. + + The KRB_KDC_REP message contains the following fields: + + AS-REP ::= [APPLICATION 11] KDC-REP + TGS-REP ::= [APPLICATION 13] KDC-REP + + KDC-REP ::= SEQUENCE { + pvno[0] INTEGER, + msg-type[1] INTEGER, + padata[2] SEQUENCE OF PA-DATA OPTIONAL, + crealm[3] Realm, + cname[4] PrincipalName, + ticket[5] Ticket, + enc-part[6] EncryptedData + } + + EncASRepPart ::= [APPLICATION 25[25]] EncKDCRepPart + EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart + + EncKDCRepPart ::= SEQUENCE { + key[0] EncryptionKey, + last-req[1] LastReq, + + + +Kohl & Neuman [Page 56] + +RFC 1510 Kerberos September 1993 + + + nonce[2] INTEGER, + key-expiration[3] KerberosTime OPTIONAL, + flags[4] TicketFlags, + authtime[5] KerberosTime, + starttime[6] KerberosTime OPTIONAL, + endtime[7] KerberosTime, + renew-till[8] KerberosTime OPTIONAL, + srealm[9] Realm, + sname[10] PrincipalName, + caddr[11] HostAddresses OPTIONAL + } + + NOTE: In EncASRepPart, the application code in the encrypted + part of a message provides an additional check that + the message was decrypted properly. + + pvno and msg-type These fields are described above in section 5.4.1. + msg-type is either KRB_AS_REP or KRB_TGS_REP. + + padata This field is described in detail in section 5.4.1. One + possible use for this field is to encode an alternate + "mix-in" string to be used with a string-to-key algorithm + (such as is described in section 6.3.2). This ability is + useful to ease transitions if a realm name needs to change + (e.g., when a company is acquired); in such a case all + existing password-derived entries in the KDC database would + be flagged as needing a special mix-in string until the + next password change. + + crealm, cname, srealm and sname These fields are the same as those + described for the ticket in section 5.3.1. + + ticket The newly-issued ticket, from section 5.3.1. + + enc-part This field is a place holder for the ciphertext and related + information that forms the encrypted part of a message. + The description of the encrypted part of the message + follows each appearance of this field. The encrypted part + is encoded as described in section 6.1. + + key This field is the same as described for the ticket in + section 5.3.1. + + last-req This field is returned by the KDC and specifies the time(s) + of the last request by a principal. Depending on what + information is available, this might be the last time that + a request for a ticket-granting ticket was made, or the + last time that a request based on a ticket-granting ticket + + + +Kohl & Neuman [Page 57] + +RFC 1510 Kerberos September 1993 + + + was successful. It also might cover all servers for a + realm, or just the particular server. Some implementations + may display this information to the user to aid in + discovering unauthorized use of one's identity. It is + similar in spirit to the last login time displayed when + logging into timesharing systems. + + nonce This field is described above in section 5.4.1. + + key-expiration The key-expiration field is part of the response from + the KDC and specifies the time that the client's secret key + is due to expire. The expiration might be the result of + password aging or an account expiration. This field will + usually be left out of the TGS reply since the response to + the TGS request is encrypted in a session key and no client + information need be retrieved from the KDC database. It is + up to the application client (usually the login program) to + take appropriate action (such as notifying the user) if the + expira tion time is imminent. + + flags, authtime, starttime, endtime, renew-till and caddr These + fields are duplicates of those found in the encrypted + portion of the attached ticket (see section 5.3.1), + provided so the client may verify they match the intended + request and to assist in proper ticket caching. If the + message is of type KRB_TGS_REP, the caddr field will only + be filled in if the request was for a proxy or forwarded + ticket, or if the user is substituting a subset of the + addresses from the ticket granting ticket. If the client- + requested addresses are not present or not used, then the + addresses contained in the ticket will be the same as those + included in the ticket-granting ticket. + +5.5. Client/Server (CS) message specifications + + This section specifies the format of the messages used for the + authentication of the client to the application server. + +5.5.1. KRB_AP_REQ definition + + The KRB_AP_REQ message contains the Kerberos protocol version number, + the message type KRB_AP_REQ, an options field to indicate any options + in use, and the ticket and authenticator themselves. The KRB_AP_REQ + message is often referred to as the "authentication header". + + AP-REQ ::= [APPLICATION 14] SEQUENCE { + pvno[0] INTEGER, + msg-type[1] INTEGER, + + + +Kohl & Neuman [Page 58] + +RFC 1510 Kerberos September 1993 + + + ap-options[2] APOptions, + ticket[3] Ticket, + authenticator[4] EncryptedData + } + + APOptions ::= BIT STRING { + reserved(0), + use-session-key(1), + mutual-required(2) + } + + pvno and msg-type These fields are described above in section 5.4.1. + msg-type is KRB_AP_REQ. + + ap-options This field appears in the application request (KRB_AP_REQ) + and affects the way the request is processed. It is a + bit-field, where the selected options are indicated by the + bit being set (1), and the unselected options and reserved + fields being reset (0). The encoding of the bits is + specified in section 5.2. The meanings of the options are: + + Bit(s) Name Description + + 0 RESERVED Reserved for future expansion of + this field. + + 1 USE-SESSION-KEYThe USE-SESSION-KEY option indicates + that the ticket the client is + presenting to a server is encrypted in + the session key from the server's + ticket-granting ticket. When this + option is not specified, the ticket is + encrypted in the server's secret key. + + 2 MUTUAL-REQUIREDThe MUTUAL-REQUIRED option tells the + server that the client requires mutual + authentication, and that it must + respond with a KRB_AP_REP message. + + 3-31 RESERVED Reserved for future use. + + ticket This field is a ticket authenticating the client to the + server. + + authenticator This contains the authenticator, which includes the + client's choice of a subkey. Its encoding is described in + section 5.3.2. + + + + +Kohl & Neuman [Page 59] + +RFC 1510 Kerberos September 1993 + + +5.5.2. KRB_AP_REP definition + + The KRB_AP_REP message contains the Kerberos protocol version number, + the message type, and an encrypted timestamp. The message is sent in + in response to an application request (KRB_AP_REQ) where the mutual + authentication option has been selected in the ap-options field. + + AP-REP ::= [APPLICATION 15] SEQUENCE { + pvno[0] INTEGER, + msg-type[1] INTEGER, + enc-part[2] EncryptedData + } + + EncAPRepPart ::= [APPLICATION 27] SEQUENCE { + ctime[0] KerberosTime, + cusec[1] INTEGER, + subkey[2] EncryptionKey OPTIONAL, + seq-number[3] INTEGER OPTIONAL + } + + NOTE: in EncAPRepPart, the application code in the encrypted part of + a message provides an additional check that the message was decrypted + properly. + + The encoded EncAPRepPart is encrypted in the shared session key of + the ticket. The optional subkey field can be used in an + application-arranged negotiation to choose a per association session + key. + + pvno and msg-type These fields are described above in section 5.4.1. + msg-type is KRB_AP_REP. + + enc-part This field is described above in section 5.4.2. + + ctime This field contains the current time on the client's host. + + cusec This field contains the microsecond part of the client's + timestamp. + + subkey This field contains an encryption key which is to be used + to protect this specific application session. See section + 3.2.6 for specifics on how this field is used to negotiate + a key. Unless an application specifies otherwise, if this + field is left out, the sub-session key from the + authenticator, or if also left out, the session key from + the ticket will be used. + + + + + +Kohl & Neuman [Page 60] + +RFC 1510 Kerberos September 1993 + + +5.5.3. Error message reply + + If an error occurs while processing the application request, the + KRB_ERROR message will be sent in response. See section 5.9.1 for + the format of the error message. The cname and crealm fields may be + left out if the server cannot determine their appropriate values from + the corresponding KRB_AP_REQ message. If the authenticator was + decipherable, the ctime and cusec fields will contain the values from + it. + +5.6. KRB_SAFE message specification + + This section specifies the format of a message that can be used by + either side (client or server) of an application to send a tamper- + proof message to its peer. It presumes that a session key has + previously been exchanged (for example, by using the + KRB_AP_REQ/KRB_AP_REP messages). + +5.6.1. KRB_SAFE definition + + The KRB_SAFE message contains user data along with a collision-proof + checksum keyed with the session key. The message fields are: + + KRB-SAFE ::= [APPLICATION 20] SEQUENCE { + pvno[0] INTEGER, + msg-type[1] INTEGER, + safe-body[2] KRB-SAFE-BODY, + cksum[3] Checksum + } + + KRB-SAFE-BODY ::= SEQUENCE { + user-data[0] OCTET STRING, + timestamp[1] KerberosTime OPTIONAL, + usec[2] INTEGER OPTIONAL, + seq-number[3] INTEGER OPTIONAL, + s-address[4] HostAddress, + r-address[5] HostAddress OPTIONAL + } + + pvno and msg-type These fields are described above in section 5.4.1. + msg-type is KRB_SAFE. + + safe-body This field is a placeholder for the body of the KRB-SAFE + message. It is to be encoded separately and then have the + checksum computed over it, for use in the cksum field. + + cksum This field contains the checksum of the application data. + Checksum details are described in section 6.4. The + + + +Kohl & Neuman [Page 61] + +RFC 1510 Kerberos September 1993 + + + checksum is computed over the encoding of the KRB-SAFE-BODY + sequence. + + user-data This field is part of the KRB_SAFE and KRB_PRIV messages + and contain the application specific data that is being + passed from the sender to the recipient. + + timestamp This field is part of the KRB_SAFE and KRB_PRIV messages. + Its contents are the current time as known by the sender of + the message. By checking the timestamp, the recipient of + the message is able to make sure that it was recently + generated, and is not a replay. + + usec This field is part of the KRB_SAFE and KRB_PRIV headers. + It contains the microsecond part of the timestamp. + + seq-number This field is described above in section 5.3.2. + + s-address This field specifies the address in use by the sender of + the message. + + r-address This field specifies the address in use by the recipient of + the message. It may be omitted for some uses (such as + broadcast protocols), but the recipient may arbitrarily + reject such messages. This field along with s-address can + be used to help detect messages which have been incorrectly + or maliciously delivered to the wrong recipient. + +5.7. KRB_PRIV message specification + + This section specifies the format of a message that can be used by + either side (client or server) of an application to securely and + privately send a message to its peer. It presumes that a session key + has previously been exchanged (for example, by using the + KRB_AP_REQ/KRB_AP_REP messages). + +5.7.1. KRB_PRIV definition + + The KRB_PRIV message contains user data encrypted in the Session Key. + The message fields are: + + KRB-PRIV ::= [APPLICATION 21] SEQUENCE { + pvno[0] INTEGER, + msg-type[1] INTEGER, + enc-part[3] EncryptedData + } + + + + + +Kohl & Neuman [Page 62] + +RFC 1510 Kerberos September 1993 + + + EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE { + user-data[0] OCTET STRING, + timestamp[1] KerberosTime OPTIONAL, + usec[2] INTEGER OPTIONAL, + seq-number[3] INTEGER OPTIONAL, + s-address[4] HostAddress, -- sender's addr + r-address[5] HostAddress OPTIONAL + -- recip's addr + } + + NOTE: In EncKrbPrivPart, the application code in the encrypted part + of a message provides an additional check that the message was + decrypted properly. + + pvno and msg-type These fields are described above in section 5.4.1. + msg-type is KRB_PRIV. + + enc-part This field holds an encoding of the EncKrbPrivPart sequence + encrypted under the session key (If supported by the + encryption method in use, an initialization vector may be + passed to the encryption procedure, in order to achieve + proper cipher chaining. The initialization vector might + come from the last block of the ciphertext from the + previous KRB_PRIV message, but it is the application's + choice whether or not to use such an initialization vector. + If left out, the default initialization vector for the + encryption algorithm will be used.). This encrypted + encoding is used for the enc-part field of the KRB-PRIV + message. See section 6 for the format of the ciphertext. + + user-data, timestamp, usec, s-address and r-address These fields are + described above in section 5.6.1. + + seq-number This field is described above in section 5.3.2. + +5.8. KRB_CRED message specification + + This section specifies the format of a message that can be used to + send Kerberos credentials from one principal to another. It is + presented here to encourage a common mechanism to be used by + applications when forwarding tickets or providing proxies to + subordinate servers. It presumes that a session key has already been + exchanged perhaps by using the KRB_AP_REQ/KRB_AP_REP messages. + +5.8.1. KRB_CRED definition + + The KRB_CRED message contains a sequence of tickets to be sent and + information needed to use the tickets, including the session key from + + + +Kohl & Neuman [Page 63] + +RFC 1510 Kerberos September 1993 + + + each. The information needed to use the tickets is encryped under an + encryption key previously exchanged. The message fields are: + + KRB-CRED ::= [APPLICATION 22] SEQUENCE { + pvno[0] INTEGER, + msg-type[1] INTEGER, -- KRB_CRED + tickets[2] SEQUENCE OF Ticket, + enc-part[3] EncryptedData + } + + EncKrbCredPart ::= [APPLICATION 29] SEQUENCE { + ticket-info[0] SEQUENCE OF KrbCredInfo, + nonce[1] INTEGER OPTIONAL, + timestamp[2] KerberosTime OPTIONAL, + usec[3] INTEGER OPTIONAL, + s-address[4] HostAddress OPTIONAL, + r-address[5] HostAddress OPTIONAL + } + + KrbCredInfo ::= SEQUENCE { + key[0] EncryptionKey, + prealm[1] Realm OPTIONAL, + pname[2] PrincipalName OPTIONAL, + flags[3] TicketFlags OPTIONAL, + authtime[4] KerberosTime OPTIONAL, + starttime[5] KerberosTime OPTIONAL, + endtime[6] KerberosTime OPTIONAL + renew-till[7] KerberosTime OPTIONAL, + srealm[8] Realm OPTIONAL, + sname[9] PrincipalName OPTIONAL, + caddr[10] HostAddresses OPTIONAL + } + + + pvno and msg-type These fields are described above in section 5.4.1. + msg-type is KRB_CRED. + + tickets + These are the tickets obtained from the KDC specifically + for use by the intended recipient. Successive tickets are + paired with the corresponding KrbCredInfo sequence from the + enc-part of the KRB-CRED message. + + enc-part This field holds an encoding of the EncKrbCredPart sequence + encrypted under the session key shared between the sender + and the intended recipient. This encrypted encoding is + used for the enc-part field of the KRB-CRED message. See + section 6 for the format of the ciphertext. + + + +Kohl & Neuman [Page 64] + +RFC 1510 Kerberos September 1993 + + + nonce If practical, an application may require the inclusion of a + nonce generated by the recipient of the message. If the + same value is included as the nonce in the message, it + provides evidence that the message is fresh and has not + been replayed by an attacker. A nonce must never be re- + used; it should be generated randomly by the recipient of + the message and provided to the sender of the mes sage in + an application specific manner. + + timestamp and usec These fields specify the time that the KRB-CRED + message was generated. The time is used to provide + assurance that the message is fresh. + + s-address and r-address These fields are described above in section + 5.6.1. They are used optionally to provide additional + assurance of the integrity of the KRB-CRED message. + + key This field exists in the corresponding ticket passed by the + KRB-CRED message and is used to pass the session key from + the sender to the intended recipient. The field's encoding + is described in section 6.2. + + The following fields are optional. If present, they can be + associated with the credentials in the remote ticket file. If left + out, then it is assumed that the recipient of the credentials already + knows their value. + + prealm and pname The name and realm of the delegated principal + identity. + + flags, authtime, starttime, endtime, renew-till, srealm, sname, + and caddr These fields contain the values of the + corresponding fields from the ticket found in the ticket + field. Descriptions of the fields are identical to the + descriptions in the KDC-REP message. + +5.9. Error message specification + + This section specifies the format for the KRB_ERROR message. The + fields included in the message are intended to return as much + information as possible about an error. It is not expected that all + the information required by the fields will be available for all + types of errors. If the appropriate information is not available + when the message is composed, the corresponding field will be left + out of the message. + + Note that since the KRB_ERROR message is not protected by any + encryption, it is quite possible for an intruder to synthesize or + + + +Kohl & Neuman [Page 65] + +RFC 1510 Kerberos September 1993 + + + modify such a message. In particular, this means that the client + should not use any fields in this message for security-critical + purposes, such as setting a system clock or generating a fresh + authenticator. The message can be useful, however, for advising a + user on the reason for some failure. + +5.9.1. KRB_ERROR definition + + The KRB_ERROR message consists of the following fields: + + KRB-ERROR ::= [APPLICATION 30] SEQUENCE { + pvno[0] INTEGER, + msg-type[1] INTEGER, + ctime[2] KerberosTime OPTIONAL, + cusec[3] INTEGER OPTIONAL, + stime[4] KerberosTime, + susec[5] INTEGER, + error-code[6] INTEGER, + crealm[7] Realm OPTIONAL, + cname[8] PrincipalName OPTIONAL, + realm[9] Realm, -- Correct realm + sname[10] PrincipalName, -- Correct name + e-text[11] GeneralString OPTIONAL, + e-data[12] OCTET STRING OPTIONAL + } + + pvno and msg-type These fields are described above in section 5.4.1. + msg-type is KRB_ERROR. + + ctime This field is described above in section 5.4.1. + + cusec This field is described above in section 5.5.2. + + stime This field contains the current time on the server. It is + of type KerberosTime. + + susec This field contains the microsecond part of the server's + timestamp. Its value ranges from 0 to 999. It appears + along with stime. The two fields are used in conjunction to + specify a reasonably accurate timestamp. + + error-code This field contains the error code returned by Kerberos or + the server when a request fails. To interpret the value of + this field see the list of error codes in section 8. + Implementations are encouraged to provide for national + language support in the display of error messages. + + crealm, cname, srealm and sname These fields are described above in + + + +Kohl & Neuman [Page 66] + +RFC 1510 Kerberos September 1993 + + + section 5.3.1. + + e-text This field contains additional text to help explain the + error code associated with the failed request (for example, + it might include a principal name which was unknown). + + e-data This field contains additional data about the error for use + by the application to help it recover from or handle the + error. If the errorcode is KDC_ERR_PREAUTH_REQUIRED, then + the e-data field will contain an encoding of a sequence of + padata fields, each corresponding to an acceptable pre- + authentication method and optionally containing data for + the method: + + METHOD-DATA ::= SEQUENCE of PA-DATA + + If the error-code is KRB_AP_ERR_METHOD, then the e-data field will + contain an encoding of the following sequence: + + METHOD-DATA ::= SEQUENCE { + method-type[0] INTEGER, + method-data[1] OCTET STRING OPTIONAL + } + + method-type will indicate the required alternate method; method-data + will contain any required additional information. + +6. Encryption and Checksum Specifications + + The Kerberos protocols described in this document are designed to use + stream encryption ciphers, which can be simulated using commonly + available block encryption ciphers, such as the Data Encryption + Standard [11], in conjunction with block chaining and checksum + methods [12]. Encryption is used to prove the identities of the + network entities participating in message exchanges. The Key + Distribution Center for each realm is trusted by all principals + registered in that realm to store a secret key in confidence. Proof + of knowledge of this secret key is used to verify the authenticity of + a principal. + + The KDC uses the principal's secret key (in the AS exchange) or a + shared session key (in the TGS exchange) to encrypt responses to + ticket requests; the ability to obtain the secret key or session key + implies the knowledge of the appropriate keys and the identity of the + KDC. The ability of a principal to decrypt the KDC response and + present a Ticket and a properly formed Authenticator (generated with + the session key from the KDC response) to a service verifies the + identity of the principal; likewise the ability of the service to + + + +Kohl & Neuman [Page 67] + +RFC 1510 Kerberos September 1993 + + + extract the session key from the Ticket and prove its knowledge + thereof in a response verifies the identity of the service. + + The Kerberos protocols generally assume that the encryption used is + secure from cryptanalysis; however, in some cases, the order of + fields in the encrypted portions of messages are arranged to minimize + the effects of poorly chosen keys. It is still important to choose + good keys. If keys are derived from user-typed passwords, those + passwords need to be well chosen to make brute force attacks more + difficult. Poorly chosen keys still make easy targets for intruders. + + The following sections specify the encryption and checksum mechanisms + currently defined for Kerberos. The encodings, chaining, and padding + requirements for each are described. For encryption methods, it is + often desirable to place random information (often referred to as a + confounder) at the start of the message. The requirements for a + confounder are specified with each encryption mechanism. + + Some encryption systems use a block-chaining method to improve the + the security characteristics of the ciphertext. However, these + chaining methods often don't provide an integrity check upon + decryption. Such systems (such as DES in CBC mode) must be augmented + with a checksum of the plaintext which can be verified at decryption + and used to detect any tampering or damage. Such checksums should be + good at detecting burst errors in the input. If any damage is + detected, the decryption routine is expected to return an error + indicating the failure of an integrity check. Each encryption type is + expected to provide and verify an appropriate checksum. The + specification of each encryption method sets out its checksum + requirements. + + Finally, where a key is to be derived from a user's password, an + algorithm for converting the password to a key of the appropriate + type is included. It is desirable for the string to key function to + be one-way, and for the mapping to be different in different realms. + This is important because users who are registered in more than one + realm will often use the same password in each, and it is desirable + that an attacker compromising the Kerberos server in one realm not + obtain or derive the user's key in another. + + For a discussion of the integrity characteristics of the candidate + encryption and checksum methods considered for Kerberos, the the + reader is referred to [13]. + +6.1. Encryption Specifications + + The following ASN.1 definition describes all encrypted messages. The + enc-part field which appears in the unencrypted part of messages in + + + +Kohl & Neuman [Page 68] + +RFC 1510 Kerberos September 1993 + + + section 5 is a sequence consisting of an encryption type, an optional + key version number, and the ciphertext. + + EncryptedData ::= SEQUENCE { + etype[0] INTEGER, -- EncryptionType + kvno[1] INTEGER OPTIONAL, + cipher[2] OCTET STRING -- ciphertext + } + + etype This field identifies which encryption algorithm was used + to encipher the cipher. Detailed specifications for + selected encryption types appear later in this section. + + kvno This field contains the version number of the key under + which data is encrypted. It is only present in messages + encrypted under long lasting keys, such as principals' + secret keys. + + cipher This field contains the enciphered text, encoded as an + OCTET STRING. + + The cipher field is generated by applying the specified encryption + algorithm to data composed of the message and algorithm-specific + inputs. Encryption mechanisms defined for use with Kerberos must + take sufficient measures to guarantee the integrity of the plaintext, + and we recommend they also take measures to protect against + precomputed dictionary attacks. If the encryption algorithm is not + itself capable of doing so, the protections can often be enhanced by + adding a checksum and a confounder. + + The suggested format for the data to be encrypted includes a + confounder, a checksum, the encoded plaintext, and any necessary + padding. The msg-seq field contains the part of the protocol message + described in section 5 which is to be encrypted. The confounder, + checksum, and padding are all untagged and untyped, and their length + is exactly sufficient to hold the appropriate item. The type and + length is implicit and specified by the particular encryption type + being used (etype). The format for the data to be encrypted is + described in the following diagram: + + +-----------+----------+-------------+-----+ + |confounder | check | msg-seq | pad | + +-----------+----------+-------------+-----+ + + The format cannot be described in ASN.1, but for those who prefer an + ASN.1-like notation: + + + + + +Kohl & Neuman [Page 69] + +RFC 1510 Kerberos September 1993 + + +CipherText ::= ENCRYPTED SEQUENCE { + confounder[0] UNTAGGED OCTET STRING(conf_length) OPTIONAL, + check[1] UNTAGGED OCTET STRING(checksum_length) OPTIONAL, + msg-seq[2] MsgSequence, + pad UNTAGGED OCTET STRING(pad_length) OPTIONAL +} + + In the above specification, UNTAGGED OCTET STRING(length) is the + notation for an octet string with its tag and length removed. It is + not a valid ASN.1 type. The tag bits and length must be removed from + the confounder since the purpose of the confounder is so that the + message starts with random data, but the tag and its length are + fixed. For other fields, the length and tag would be redundant if + they were included because they are specified by the encryption type. + + One generates a random confounder of the appropriate length, placing + it in confounder; zeroes out check; calculates the appropriate + checksum over confounder, check, and msg-seq, placing the result in + check; adds the necessary padding; then encrypts using the specified + encryption type and the appropriate key. + + Unless otherwise specified, a definition of an encryption algorithm + that specifies a checksum, a length for the confounder field, or an + octet boundary for padding uses this ciphertext format (The ordering + of the fields in the CipherText is important. Additionally, messages + encoded in this format must include a length as part of the msg-seq + field. This allows the recipient to verify that the message has not + been truncated. Without a length, an attacker could use a chosen + plaintext attack to generate a message which could be truncated, + while leaving the checksum intact. Note that if the msg-seq is an + encoding of an ASN.1 SEQUENCE or OCTET STRING, then the length is + part of that encoding.). Those fields which are not specified will be + omitted. + + In the interest of allowing all implementations using a particular + encryption type to communicate with all others using that type, the + specification of an encryption type defines any checksum that is + needed as part of the encryption process. If an alternative checksum + is to be used, a new encryption type must be defined. + + Some cryptosystems require additional information beyond the key and + the data to be encrypted. For example, DES, when used in cipher- + block-chaining mode, requires an initialization vector. If required, + the description for each encryption type must specify the source of + such additional information. + + + + + + +Kohl & Neuman [Page 70] + +RFC 1510 Kerberos September 1993 + + +6.2. Encryption Keys + + The sequence below shows the encoding of an encryption key: + + EncryptionKey ::= SEQUENCE { + keytype[0] INTEGER, + keyvalue[1] OCTET STRING + } + + keytype This field specifies the type of encryption key that + follows in the keyvalue field. It will almost always + correspond to the encryption algorithm used to generate the + EncryptedData, though more than one algorithm may use the + same type of key (the mapping is many to one). This might + happen, for example, if the encryption algorithm uses an + alternate checksum algorithm for an integrity check, or a + different chaining mechanism. + + keyvalue This field contains the key itself, encoded as an octet + string. + + All negative values for the encryption key type are reserved for + local use. All non-negative values are reserved for officially + assigned type fields and interpretations. + +6.3. Encryption Systems + +6.3.1. The NULL Encryption System (null) + + If no encryption is in use, the encryption system is said to be the + NULL encryption system. In the NULL encryption system there is no + checksum, confounder or padding. The ciphertext is simply the + plaintext. The NULL Key is used by the null encryption system and is + zero octets in length, with keytype zero (0). + +6.3.2. DES in CBC mode with a CRC-32 checksum (des-cbc-crc) + + The des-cbc-crc encryption mode encrypts information under the Data + Encryption Standard [11] using the cipher block chaining mode [12]. + A CRC-32 checksum (described in ISO 3309 [14]) is applied to the + confounder and message sequence (msg-seq) and placed in the cksum + field. DES blocks are 8 bytes. As a result, the data to be + encrypted (the concatenation of confounder, checksum, and message) + must be padded to an 8 byte boundary before encryption. The details + of the encryption of this data are identical to those for the des- + cbc-md5 encryption mode. + + Note that, since the CRC-32 checksum is not collisionproof, an + + + +Kohl & Neuman [Page 71] + +RFC 1510 Kerberos September 1993 + + + attacker could use a probabilistic chosenplaintext attack to generate + a valid message even if a confounder is used [13]. The use of + collision-proof checksums is recommended for environments where such + attacks represent a significant threat. The use of the CRC-32 as the + checksum for ticket or authenticator is no longer mandated as an + interoperability requirement for Kerberos Version 5 Specification 1 + (See section 9.1 for specific details). + +6.3.3. DES in CBC mode with an MD4 checksum (des-cbc-md4) + + The des-cbc-md4 encryption mode encrypts information under the Data + Encryption Standard [11] using the cipher block chaining mode [12]. + An MD4 checksum (described in [15]) is applied to the confounder and + message sequence (msg-seq) and placed in the cksum field. DES blocks + are 8 bytes. As a result, the data to be encrypted (the + concatenation of confounder, checksum, and message) must be padded to + an 8 byte boundary before encryption. The details of the encryption + of this data are identical to those for the descbc-md5 encryption + mode. + +6.3.4. DES in CBC mode with an MD5 checksum (des-cbc-md5) + + The des-cbc-md5 encryption mode encrypts information under the Data + Encryption Standard [11] using the cipher block chaining mode [12]. + An MD5 checksum (described in [16]) is applied to the confounder and + message sequence (msg-seq) and placed in the cksum field. DES blocks + are 8 bytes. As a result, the data to be encrypted (the + concatenation of confounder, checksum, and message) must be padded to + an 8 byte boundary before encryption. + + Plaintext and DES ciphtertext are encoded as 8-octet blocks which are + concatenated to make the 64-bit inputs for the DES algorithms. The + first octet supplies the 8 most significant bits (with the octet's + MSbit used as the DES input block's MSbit, etc.), the second octet + the next 8 bits, ..., and the eighth octet supplies the 8 least + significant bits. + + Encryption under DES using cipher block chaining requires an + additional input in the form of an initialization vector. Unless + otherwise specified, zero should be used as the initialization + vector. Kerberos' use of DES requires an 8-octet confounder. + + The DES specifications identify some "weak" and "semiweak" keys; + those keys shall not be used for encrypting messages for use in + Kerberos. Additionally, because of the way that keys are derived for + the encryption of checksums, keys shall not be used that yield "weak" + or "semi-weak" keys when eXclusive-ORed with the constant + F0F0F0F0F0F0F0F0. + + + +Kohl & Neuman [Page 72] + +RFC 1510 Kerberos September 1993 + + + A DES key is 8 octets of data, with keytype one (1). This consists + of 56 bits of key, and 8 parity bits (one per octet). The key is + encoded as a series of 8 octets written in MSB-first order. The bits + within the key are also encoded in MSB order. For example, if the + encryption key is: + (B1,B2,...,B7,P1,B8,...,B14,P2,B15,...,B49,P7,B50,...,B56,P8) where + B1,B2,...,B56 are the key bits in MSB order, and P1,P2,...,P8 are the + parity bits, the first octet of the key would be B1,B2,...,B7,P1 + (with B1 as the MSbit). [See the FIPS 81 introduction for + reference.] + + To generate a DES key from a text string (password), the text string + normally must have the realm and each component of the principal's + name appended(In some cases, it may be necessary to use a different + "mix-in" string for compatibility reasons; see the discussion of + padata in section 5.4.2.), then padded with ASCII nulls to an 8 byte + boundary. This string is then fan-folded and eXclusive-ORed with + itself to form an 8 byte DES key. The parity is corrected on the + key, and it is used to generate a DES CBC checksum on the initial + string (with the realm and name appended). Next, parity is corrected + on the CBC checksum. If the result matches a "weak" or "semiweak" + key as described in the DES specification, it is eXclusive-ORed with + the constant 00000000000000F0. Finally, the result is returned as + the key. Pseudocode follows: + + string_to_key(string,realm,name) { + odd = 1; + s = string + realm; + for(each component in name) { + s = s + component; + } + tempkey = NULL; + pad(s); /* with nulls to 8 byte boundary */ + for(8byteblock in s) { + if(odd == 0) { + odd = 1; + reverse(8byteblock) + } + else odd = 0; + tempkey = tempkey XOR 8byteblock; + } + fixparity(tempkey); + key = DES-CBC-check(s,tempkey); + fixparity(key); + if(is_weak_key_key(key)) + key = key XOR 0xF0; + return(key); + } + + + +Kohl & Neuman [Page 73] + +RFC 1510 Kerberos September 1993 + + +6.4. Checksums + + The following is the ASN.1 definition used for a checksum: + + Checksum ::= SEQUENCE { + cksumtype[0] INTEGER, + checksum[1] OCTET STRING + } + + cksumtype This field indicates the algorithm used to generate the + accompanying checksum. + + checksum This field contains the checksum itself, encoded + as an octet string. + + Detailed specification of selected checksum types appear later in + this section. Negative values for the checksum type are reserved for + local use. All non-negative values are reserved for officially + assigned type fields and interpretations. + + Checksums used by Kerberos can be classified by two properties: + whether they are collision-proof, and whether they are keyed. It is + infeasible to find two plaintexts which generate the same checksum + value for a collision-proof checksum. A key is required to perturb + or initialize the algorithm in a keyed checksum. To prevent + message-stream modification by an active attacker, unkeyed checksums + should only be used when the checksum and message will be + subsequently encrypted (e.g., the checksums defined as part of the + encryption algorithms covered earlier in this section). Collision- + proof checksums can be made tamper-proof as well if the checksum + value is encrypted before inclusion in a message. In such cases, the + composition of the checksum and the encryption algorithm must be + considered a separate checksum algorithm (e.g., RSA-MD5 encrypted + using DES is a new checksum algorithm of type RSA-MD5-DES). For most + keyed checksums, as well as for the encrypted forms of collisionproof + checksums, Kerberos prepends a confounder before the checksum is + calculated. + +6.4.1. The CRC-32 Checksum (crc32) + + The CRC-32 checksum calculates a checksum based on a cyclic + redundancy check as described in ISO 3309 [14]. The resulting + checksum is four (4) octets in length. The CRC-32 is neither keyed + nor collision-proof. The use of this checksum is not recommended. + An attacker using a probabilistic chosen-plaintext attack as + described in [13] might be able to generate an alternative message + that satisfies the checksum. The use of collision-proof checksums is + recommended for environments where such attacks represent a + + + +Kohl & Neuman [Page 74] + +RFC 1510 Kerberos September 1993 + + + significant threat. + +6.4.2. The RSA MD4 Checksum (rsa-md4) + + The RSA-MD4 checksum calculates a checksum using the RSA MD4 + algorithm [15]. The algorithm takes as input an input message of + arbitrary length and produces as output a 128-bit (16 octet) + checksum. RSA-MD4 is believed to be collision-proof. + +6.4.3. RSA MD4 Cryptographic Checksum Using DES (rsa-md4des) + + The RSA-MD4-DES checksum calculates a keyed collisionproof checksum + by prepending an 8 octet confounder before the text, applying the RSA + MD4 checksum algorithm, and encrypting the confounder and the + checksum using DES in cipher-block-chaining (CBC) mode using a + variant of the key, where the variant is computed by eXclusive-ORing + the key with the constant F0F0F0F0F0F0F0F0 (A variant of the key is + used to limit the use of a key to a particular function, separating + the functions of generating a checksum from other encryption + performed using the session key. The constant F0F0F0F0F0F0F0F0 was + chosen because it maintains key parity. The properties of DES + precluded the use of the complement. The same constant is used for + similar purpose in the Message Integrity Check in the Privacy + Enhanced Mail standard.). The initialization vector should be zero. + The resulting checksum is 24 octets long (8 octets of which are + redundant). This checksum is tamper-proof and believed to be + collision-proof. + + The DES specifications identify some "weak keys"; those keys shall + not be used for generating RSA-MD4 checksums for use in Kerberos. + + The format for the checksum is described in the following diagram: + + +--+--+--+--+--+--+--+-- + | des-cbc(confounder + +--+--+--+--+--+--+--+-- + + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + rsa-md4(confounder+msg),key=var(key),iv=0) | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The format cannot be described in ASN.1, but for those who prefer an + ASN.1-like notation: + + rsa-md4-des-checksum ::= ENCRYPTED UNTAGGED SEQUENCE { + confounder[0] UNTAGGED OCTET STRING(8), + check[1] UNTAGGED OCTET STRING(16) + } + + + +Kohl & Neuman [Page 75] + +RFC 1510 Kerberos September 1993 + + +6.4.4. The RSA MD5 Checksum (rsa-md5) + + The RSA-MD5 checksum calculates a checksum using the RSA MD5 + algorithm [16]. The algorithm takes as input an input message of + arbitrary length and produces as output a 128-bit (16 octet) + checksum. RSA-MD5 is believed to be collision-proof. + +6.4.5. RSA MD5 Cryptographic Checksum Using DES (rsa-md5des) + + The RSA-MD5-DES checksum calculates a keyed collisionproof checksum + by prepending an 8 octet confounder before the text, applying the RSA + MD5 checksum algorithm, and encrypting the confounder and the + checksum using DES in cipher-block-chaining (CBC) mode using a + variant of the key, where the variant is computed by eXclusive-ORing + the key with the constant F0F0F0F0F0F0F0F0. The initialization + vector should be zero. The resulting checksum is 24 octets long (8 + octets of which are redundant). This checksum is tamper-proof and + believed to be collision-proof. + + The DES specifications identify some "weak keys"; those keys shall + not be used for encrypting RSA-MD5 checksums for use in Kerberos. + + The format for the checksum is described in the following diagram: + + +--+--+--+--+--+--+--+-- + | des-cbc(confounder + +--+--+--+--+--+--+--+-- + + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + rsa-md5(confounder+msg),key=var(key),iv=0) | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The format cannot be described in ASN.1, but for those who prefer an + ASN.1-like notation: + + rsa-md5-des-checksum ::= ENCRYPTED UNTAGGED SEQUENCE { + confounder[0] UNTAGGED OCTET STRING(8), + check[1] UNTAGGED OCTET STRING(16) + } + +6.4.6. DES cipher-block chained checksum (des-mac) + + The DES-MAC checksum is computed by prepending an 8 octet confounder + to the plaintext, performing a DES CBC-mode encryption on the result + using the key and an initialization vector of zero, taking the last + block of the ciphertext, prepending the same confounder and + encrypting the pair using DES in cipher-block-chaining (CBC) mode + using a a variant of the key, where the variant is computed by + + + +Kohl & Neuman [Page 76] + +RFC 1510 Kerberos September 1993 + + + eXclusive-ORing the key with the constant F0F0F0F0F0F0F0F0. The + initialization vector should be zero. The resulting checksum is 128 + bits (16 octets) long, 64 bits of which are redundant. This checksum + is tamper-proof and collision-proof. + + The format for the checksum is described in the following diagram: + + +--+--+--+--+--+--+--+-- + | des-cbc(confounder + +--+--+--+--+--+--+--+-- + + +-----+-----+-----+-----+-----+-----+-----+-----+ + des-mac(conf+msg,iv=0,key),key=var(key),iv=0) | + +-----+-----+-----+-----+-----+-----+-----+-----+ + + The format cannot be described in ASN.1, but for those who prefer an + ASN.1-like notation: + + des-mac-checksum ::= ENCRYPTED UNTAGGED SEQUENCE { + confounder[0] UNTAGGED OCTET STRING(8), + check[1] UNTAGGED OCTET STRING(8) + } + + The DES specifications identify some "weak" and "semiweak" keys; + those keys shall not be used for generating DES-MAC checksums for use + in Kerberos, nor shall a key be used whose veriant is "weak" or + "semi-weak". + +6.4.7. RSA MD4 Cryptographic Checksum Using DES alternative + (rsa-md4-des-k) + + The RSA-MD4-DES-K checksum calculates a keyed collision-proof + checksum by applying the RSA MD4 checksum algorithm and encrypting + the results using DES in cipherblock-chaining (CBC) mode using a DES + key as both key and initialization vector. The resulting checksum is + 16 octets long. This checksum is tamper-proof and believed to be + collision-proof. Note that this checksum type is the old method for + encoding the RSA-MD4-DES checksum and it is no longer recommended. + +6.4.8. DES cipher-block chained checksum alternative (desmac-k) + + The DES-MAC-K checksum is computed by performing a DES CBC-mode + encryption of the plaintext, and using the last block of the + ciphertext as the checksum value. It is keyed with an encryption key + and an initialization vector; any uses which do not specify an + additional initialization vector will use the key as both key and + initialization vector. The resulting checksum is 64 bits (8 octets) + long. This checksum is tamper-proof and collision-proof. Note that + + + +Kohl & Neuman [Page 77] + +RFC 1510 Kerberos September 1993 + + + this checksum type is the old method for encoding the DESMAC checksum + and it is no longer recommended. + + The DES specifications identify some "weak keys"; those keys shall + not be used for generating DES-MAC checksums for use in Kerberos. + +7. Naming Constraints + +7.1. Realm Names + + Although realm names are encoded as GeneralStrings and although a + realm can technically select any name it chooses, interoperability + across realm boundaries requires agreement on how realm names are to + be assigned, and what information they imply. + + To enforce these conventions, each realm must conform to the + conventions itself, and it must require that any realms with which + inter-realm keys are shared also conform to the conventions and + require the same from its neighbors. + + There are presently four styles of realm names: domain, X500, other, + and reserved. Examples of each style follow: + + domain: host.subdomain.domain (example) + X500: C=US/O=OSF (example) + other: NAMETYPE:rest/of.name=without-restrictions (example) + reserved: reserved, but will not conflict with above + + Domain names must look like domain names: they consist of components + separated by periods (.) and they contain neither colons (:) nor + slashes (/). + + X.500 names contain an equal (=) and cannot contain a colon (:) + before the equal. The realm names for X.500 names will be string + representations of the names with components separated by slashes. + Leading and trailing slashes will not be included. + + Names that fall into the other category must begin with a prefix that + contains no equal (=) or period (.) and the prefix must be followed + by a colon (:) and the rest of the name. All prefixes must be + assigned before they may be used. Presently none are assigned. + + The reserved category includes strings which do not fall into the + first three categories. All names in this category are reserved. It + is unlikely that names will be assigned to this category unless there + is a very strong argument for not using the "other" category. + + These rules guarantee that there will be no conflicts between the + + + +Kohl & Neuman [Page 78] + +RFC 1510 Kerberos September 1993 + + + various name styles. The following additional constraints apply to + the assignment of realm names in the domain and X.500 categories: the + name of a realm for the domain or X.500 formats must either be used + by the organization owning (to whom it was assigned) an Internet + domain name or X.500 name, or in the case that no such names are + registered, authority to use a realm name may be derived from the + authority of the parent realm. For example, if there is no domain + name for E40.MIT.EDU, then the administrator of the MIT.EDU realm can + authorize the creation of a realm with that name. + + This is acceptable because the organization to which the parent is + assigned is presumably the organization authorized to assign names to + its children in the X.500 and domain name systems as well. If the + parent assigns a realm name without also registering it in the domain + name or X.500 hierarchy, it is the parent's responsibility to make + sure that there will not in the future exists a name identical to the + realm name of the child unless it is assigned to the same entity as + the realm name. + +7.2. Principal Names + + As was the case for realm names, conventions are needed to ensure + that all agree on what information is implied by a principal name. + The name-type field that is part of the principal name indicates the + kind of information implied by the name. The name-type should be + treated as a hint. Ignoring the name type, no two names can be the + same (i.e., at least one of the components, or the realm, must be + different). This constraint may be eliminated in the future. The + following name types are defined: + + name-type value meaning + NT-UNKNOWN 0 Name type not known + NT-PRINCIPAL 1 Just the name of the principal as in + DCE, or for users + NT-SRV-INST 2 Service and other unique instance (krbtgt) + NT-SRV-HST 3 Service with host name as instance + (telnet, rcommands) + NT-SRV-XHST 4 Service with host as remaining components + NT-UID 5 Unique ID + + When a name implies no information other than its uniqueness at a + particular time the name type PRINCIPAL should be used. The + principal name type should be used for users, and it might also be + used for a unique server. If the name is a unique machine generated + ID that is guaranteed never to be reassigned then the name type of + UID should be used (note that it is generally a bad idea to reassign + names of any type since stale entries might remain in access control + lists). + + + +Kohl & Neuman [Page 79] + +RFC 1510 Kerberos September 1993 + + + If the first component of a name identifies a service and the + remaining components identify an instance of the service in a server + specified manner, then the name type of SRV-INST should be used. An + example of this name type is the Kerberos ticket-granting ticket + which has a first component of krbtgt and a second component + identifying the realm for which the ticket is valid. + + If instance is a single component following the service name and the + instance identifies the host on which the server is running, then the + name type SRV-HST should be used. This type is typically used for + Internet services such as telnet and the Berkeley R commands. If the + separate components of the host name appear as successive components + following the name of the service, then the name type SRVXHST should + be used. This type might be used to identify servers on hosts with + X.500 names where the slash (/) might otherwise be ambiguous. + + A name type of UNKNOWN should be used when the form of the name is + not known. When comparing names, a name of type UNKNOWN will match + principals authenticated with names of any type. A principal + authenticated with a name of type UNKNOWN, however, will only match + other names of type UNKNOWN. + + Names of any type with an initial component of "krbtgt" are reserved + for the Kerberos ticket granting service. See section 8.2.3 for the + form of such names. + +7.2.1. Name of server principals + + The principal identifier for a server on a host will generally be + composed of two parts: (1) the realm of the KDC with which the server + is registered, and (2) a two-component name of type NT-SRV-HST if the + host name is an Internet domain name or a multi-component name of + type NT-SRV-XHST if the name of the host is of a form such as X.500 + that allows slash (/) separators. The first component of the two- or + multi-component name will identify the service and the latter + components will identify the host. Where the name of the host is not + case sensitive (for example, with Internet domain names) the name of + the host must be lower case. For services such as telnet and the + Berkeley R commands which run with system privileges, the first + component will be the string "host" instead of a service specific + identifier. + +8. Constants and other defined values + +8.1. Host address types + + All negative values for the host address type are reserved for local + use. All non-negative values are reserved for officially assigned + + + +Kohl & Neuman [Page 80] + +RFC 1510 Kerberos September 1993 + + + type fields and interpretations. + + The values of the types for the following addresses are chosen to + match the defined address family constants in the Berkeley Standard + Distributions of Unix. They can be found in with + symbolic names AF_xxx (where xxx is an abbreviation of the address + family name). + + + Internet addresses + + Internet addresses are 32-bit (4-octet) quantities, encoded in MSB + order. The type of internet addresses is two (2). + + CHAOSnet addresses + + CHAOSnet addresses are 16-bit (2-octet) quantities, encoded in MSB + order. The type of CHAOSnet addresses is five (5). + + ISO addresses + + ISO addresses are variable-length. The type of ISO addresses is + seven (7). + + Xerox Network Services (XNS) addresses + + XNS addresses are 48-bit (6-octet) quantities, encoded in MSB + order. The type of XNS addresses is six (6). + + AppleTalk Datagram Delivery Protocol (DDP) addresses + + AppleTalk DDP addresses consist of an 8-bit node number and a 16- + bit network number. The first octet of the address is the node + number; the remaining two octets encode the network number in MSB + order. The type of AppleTalk DDP addresses is sixteen (16). + + DECnet Phase IV addresses + + DECnet Phase IV addresses are 16-bit addresses, encoded in LSB + order. The type of DECnet Phase IV addresses is twelve (12). + +8.2. KDC messages + +8.2.1. IP transport + + When contacting a Kerberos server (KDC) for a KRB_KDC_REQ request + using IP transport, the client shall send a UDP datagram containing + only an encoding of the request to port 88 (decimal) at the KDC's IP + + + +Kohl & Neuman [Page 81] + +RFC 1510 Kerberos September 1993 + + + address; the KDC will respond with a reply datagram containing only + an encoding of the reply message (either a KRB_ERROR or a + KRB_KDC_REP) to the sending port at the sender's IP address. + +8.2.2. OSI transport + + During authentication of an OSI client to and OSI server, the mutual + authentication of an OSI server to an OSI client, the transfer of + credentials from an OSI client to an OSI server, or during exchange + of private or integrity checked messages, Kerberos protocol messages + may be treated as opaque objects and the type of the authentication + mechanism will be: + + OBJECT IDENTIFIER ::= {iso (1), org(3), dod(5),internet(1), + security(5), kerberosv5(2)} + + Depending on the situation, the opaque object will be an + authentication header (KRB_AP_REQ), an authentication reply + (KRB_AP_REP), a safe message (KRB_SAFE), a private message + (KRB_PRIV), or a credentials message (KRB_CRED). The opaque data + contains an application code as specified in the ASN.1 description + for each message. The application code may be used by Kerberos to + determine the message type. + +8.2.3. Name of the TGS + + The principal identifier of the ticket-granting service shall be + composed of three parts: (1) the realm of the KDC issuing the TGS + ticket (2) a two-part name of type NT-SRVINST, with the first part + "krbtgt" and the second part the name of the realm which will accept + the ticket-granting ticket. For example, a ticket-granting ticket + issued by the ATHENA.MIT.EDU realm to be used to get tickets from the + ATHENA.MIT.EDU KDC has a principal identifier of "ATHENA.MIT.EDU" + (realm), ("krbtgt", "ATHENA.MIT.EDU") (name). A ticket-granting + ticket issued by the ATHENA.MIT.EDU realm to be used to get tickets + from the MIT.EDU realm has a principal identifier of "ATHENA.MIT.EDU" + (realm), ("krbtgt", "MIT.EDU") (name). + +8.3. Protocol constants and associated values + + The following tables list constants used in the protocol and defines + their meanings. + + + + + + + + + +Kohl & Neuman [Page 82] + +RFC 1510 Kerberos September 1993 + + +---------------+-----------+----------+----------------+--------------- +Encryption type|etype value|block size|minimum pad size|confounder size +---------------+-----------+----------+----------------+--------------- +NULL 0 1 0 0 +des-cbc-crc 1 8 4 8 +des-cbc-md4 2 8 0 8 +des-cbc-md5 3 8 0 8 + +-------------------------------+-------------------+------------- +Checksum type |sumtype value |checksum size +-------------------------------+-------------------+------------- +CRC32 1 4 +rsa-md4 2 16 +rsa-md4-des 3 24 +des-mac 4 16 +des-mac-k 5 8 +rsa-md4-des-k 6 16 +rsa-md5 7 16 +rsa-md5-des 8 24 + +-------------------------------+----------------- +padata type |padata-type value +-------------------------------+----------------- +PA-TGS-REQ 1 +PA-ENC-TIMESTAMP 2 +PA-PW-SALT 3 + +-------------------------------+------------- +authorization data type |ad-type value +-------------------------------+------------- +reserved values 0-63 +OSF-DCE 64 +SESAME 65 + +-------------------------------+----------------- +alternate authentication type |method-type value +-------------------------------+----------------- +reserved values 0-63 +ATT-CHALLENGE-RESPONSE 64 + +-------------------------------+------------- +transited encoding type |tr-type value +-------------------------------+------------- +DOMAIN-X500-COMPRESS 1 +reserved values all others + + + + + + +Kohl & Neuman [Page 83] + +RFC 1510 Kerberos September 1993 + + +--------------+-------+----------------------------------------- +Label |Value |Meaning or MIT code +--------------+-------+----------------------------------------- + +pvno 5 current Kerberos protocol version number + +message types + +KRB_AS_REQ 10 Request for initial authentication +KRB_AS_REP 11 Response to KRB_AS_REQ request +KRB_TGS_REQ 12 Request for authentication based on TGT +KRB_TGS_REP 13 Response to KRB_TGS_REQ request +KRB_AP_REQ 14 application request to server +KRB_AP_REP 15 Response to KRB_AP_REQ_MUTUAL +KRB_SAFE 20 Safe (checksummed) application message +KRB_PRIV 21 Private (encrypted) application message +KRB_CRED 22 Private (encrypted) message to forward + credentials +KRB_ERROR 30 Error response + +name types + +KRB_NT_UNKNOWN 0 Name type not known +KRB_NT_PRINCIPAL 1 Just the name of the principal as in DCE, or + for users +KRB_NT_SRV_INST 2 Service and other unique instance (krbtgt) +KRB_NT_SRV_HST 3 Service with host name as instance (telnet, + rcommands) +KRB_NT_SRV_XHST 4 Service with host as remaining components +KRB_NT_UID 5 Unique ID + +error codes + +KDC_ERR_NONE 0 No error +KDC_ERR_NAME_EXP 1 Client's entry in database has + expired +KDC_ERR_SERVICE_EXP 2 Server's entry in database has + expired +KDC_ERR_BAD_PVNO 3 Requested protocol version number + not supported +KDC_ERR_C_OLD_MAST_KVNO 4 Client's key encrypted in old + master key +KDC_ERR_S_OLD_MAST_KVNO 5 Server's key encrypted in old + master key +KDC_ERR_C_PRINCIPAL_UNKNOWN 6 Client not found in Kerberos database +KDC_ERR_S_PRINCIPAL_UNKNOWN 7 Server not found in Kerberos database +KDC_ERR_PRINCIPAL_NOT_UNIQUE 8 Multiple principal entries in + database + + + +Kohl & Neuman [Page 84] + +RFC 1510 Kerberos September 1993 + + +KDC_ERR_NULL_KEY 9 The client or server has a null key +KDC_ERR_CANNOT_POSTDATE 10 Ticket not eligible for postdating +KDC_ERR_NEVER_VALID 11 Requested start time is later than + end time +KDC_ERR_POLICY 12 KDC policy rejects request +KDC_ERR_BADOPTION 13 KDC cannot accommodate requested + option +KDC_ERR_ETYPE_NOSUPP 14 KDC has no support for encryption + type +KDC_ERR_SUMTYPE_NOSUPP 15 KDC has no support for checksum type +KDC_ERR_PADATA_TYPE_NOSUPP 16 KDC has no support for padata type +KDC_ERR_TRTYPE_NOSUPP 17 KDC has no support for transited type +KDC_ERR_CLIENT_REVOKED 18 Clients credentials have been revoked +KDC_ERR_SERVICE_REVOKED 19 Credentials for server have been + revoked +KDC_ERR_TGT_REVOKED 20 TGT has been revoked +KDC_ERR_CLIENT_NOTYET 21 Client not yet valid - try again + later +KDC_ERR_SERVICE_NOTYET 22 Server not yet valid - try again + later +KDC_ERR_KEY_EXPIRED 23 Password has expired - change + password to reset +KDC_ERR_PREAUTH_FAILED 24 Pre-authentication information + was invalid +KDC_ERR_PREAUTH_REQUIRED 25 Additional pre-authentication + required* +KRB_AP_ERR_BAD_INTEGRITY 31 Integrity check on decrypted field + failed +KRB_AP_ERR_TKT_EXPIRED 32 Ticket expired +KRB_AP_ERR_TKT_NYV 33 Ticket not yet valid +KRB_AP_ERR_REPEAT 34 Request is a replay +KRB_AP_ERR_NOT_US 35 The ticket isn't for us +KRB_AP_ERR_BADMATCH 36 Ticket and authenticator don't match +KRB_AP_ERR_SKEW 37 Clock skew too great +KRB_AP_ERR_BADADDR 38 Incorrect net address +KRB_AP_ERR_BADVERSION 39 Protocol version mismatch +KRB_AP_ERR_MSG_TYPE 40 Invalid msg type +KRB_AP_ERR_MODIFIED 41 Message stream modified +KRB_AP_ERR_BADORDER 42 Message out of order +KRB_AP_ERR_BADKEYVER 44 Specified version of key is not + available +KRB_AP_ERR_NOKEY 45 Service key not available +KRB_AP_ERR_MUT_FAIL 46 Mutual authentication failed +KRB_AP_ERR_BADDIRECTION 47 Incorrect message direction +KRB_AP_ERR_METHOD 48 Alternative authentication method + required* +KRB_AP_ERR_BADSEQ 49 Incorrect sequence number in message +KRB_AP_ERR_INAPP_CKSUM 50 Inappropriate type of checksum in + + + +Kohl & Neuman [Page 85] + +RFC 1510 Kerberos September 1993 + + + message +KRB_ERR_GENERIC 60 Generic error (description in e-text) +KRB_ERR_FIELD_TOOLONG 61 Field is too long for this + implementation + + *This error carries additional information in the e-data field. The + contents of the e-data field for this message is described in section + 5.9.1. + +9. Interoperability requirements + + Version 5 of the Kerberos protocol supports a myriad of options. + Among these are multiple encryption and checksum types, alternative + encoding schemes for the transited field, optional mechanisms for + pre-authentication, the handling of tickets with no addresses, + options for mutual authentication, user to user authentication, + support for proxies, forwarding, postdating, and renewing tickets, + the format of realm names, and the handling of authorization data. + + In order to ensure the interoperability of realms, it is necessary to + define a minimal configuration which must be supported by all + implementations. This minimal configuration is subject to change as + technology does. For example, if at some later date it is discovered + that one of the required encryption or checksum algorithms is not + secure, it will be replaced. + +9.1. Specification 1 + + This section defines the first specification of these options. + Implementations which are configured in this way can be said to + support Kerberos Version 5 Specification 1 (5.1). + + Encryption and checksum methods + + The following encryption and checksum mechanisms must be supported. + Implementations may support other mechanisms as well, but the + additional mechanisms may only be used when communicating with + principals known to also support them: Encryption: DES-CBC-MD5 + Checksums: CRC-32, DES-MAC, DES-MAC-K, and DES-MD5 + + Realm Names + + All implementations must understand hierarchical realms in both the + Internet Domain and the X.500 style. When a ticket granting ticket + for an unknown realm is requested, the KDC must be able to determine + the names of the intermediate realms between the KDCs realm and the + requested realm. + + + + +Kohl & Neuman [Page 86] + +RFC 1510 Kerberos September 1993 + + + Transited field encoding + + DOMAIN-X500-COMPRESS (described in section 3.3.3.1) must be + supported. Alternative encodings may be supported, but they may be + used only when that encoding is supported by ALL intermediate realms. + + Pre-authentication methods + + The TGS-REQ method must be supported. The TGS-REQ method is not used + on the initial request. The PA-ENC-TIMESTAMP method must be supported + by clients but whether it is enabled by default may be determined on + a realm by realm basis. If not used in the initial request and the + error KDC_ERR_PREAUTH_REQUIRED is returned specifying PA-ENCTIMESTAMP + as an acceptable method, the client should retry the initial request + using the PA-ENC-TIMESTAMP preauthentication method. Servers need not + support the PAENC-TIMESTAMP method, but if not supported the server + should ignore the presence of PA-ENC-TIMESTAMP pre-authentication in + a request. + + Mutual authentication + + Mutual authentication (via the KRB_AP_REP message) must be supported. + + Ticket addresses and flags + + All KDC's must pass on tickets that carry no addresses (i.e., if a + TGT contains no addresses, the KDC will return derivative tickets), + but each realm may set its own policy for issuing such tickets, and + each application server will set its own policy with respect to + accepting them. By default, servers should not accept them. + + Proxies and forwarded tickets must be supported. Individual realms + and application servers can set their own policy on when such tickets + will be accepted. + + All implementations must recognize renewable and postdated tickets, + but need not actually implement them. If these options are not + supported, the starttime and endtime in the ticket shall specify a + ticket's entire useful life. When a postdated ticket is decoded by a + server, all implementations shall make the presence of the postdated + flag visible to the calling server. + + User-to-user authentication + + Support for user to user authentication (via the ENC-TKTIN-SKEY KDC + option) must be provided by implementations, but individual realms + may decide as a matter of policy to reject such requests on a per- + principal or realm-wide basis. + + + +Kohl & Neuman [Page 87] + +RFC 1510 Kerberos September 1993 + + + Authorization data + + Implementations must pass all authorization data subfields from + ticket-granting tickets to any derivative tickets unless directed to + suppress a subfield as part of the definition of that registered + subfield type (it is never incorrect to pass on a subfield, and no + registered subfield types presently specify suppression at the KDC). + + Implementations must make the contents of any authorization data + subfields available to the server when a ticket is used. + Implementations are not required to allow clients to specify the + contents of the authorization data fields. + +9.2. Recommended KDC values + + Following is a list of recommended values for a KDC implementation, + based on the list of suggested configuration constants (see section + 4.4). + + minimum lifetime 5 minutes + + maximum renewable lifetime 1 week + + maximum ticket lifetime 1 day + + empty addresses only when suitable restrictions appear + in authorization data + + proxiable, etc. Allowed. + +10. Acknowledgments + + Early versions of this document, describing version 4 of the + protocol, were written by Jennifer Steiner (formerly at Project + Athena); these drafts provided an excellent starting point for this + current version 5 specification. Many people in the Internet + community have contributed ideas and suggested protocol changes for + version 5. Notable contributions came from Ted Anderson, Steve + Bellovin and Michael Merritt [17], Daniel Bernstein, Mike Burrows, + Donald Davis, Ravi Ganesan, Morrie Gasser, Virgil Gligor, Bill + Griffeth, Mark Lillibridge, Mark Lomas, Steve Lunt, Piers McMahon, + Joe Pato, William Sommerfeld, Stuart Stubblebine, Ralph Swick, Ted + T'so, and Stanley Zanarotti. Many others commented and helped shape + this specification into its current form. + + + + + + + +Kohl & Neuman [Page 88] + +RFC 1510 Kerberos September 1993 + + +11. References + + [1] Miller, S., Neuman, C., Schiller, J., and J. Saltzer, "Section + E.2.1: Kerberos Authentication and Authorization System", + M.I.T. Project Athena, Cambridge, Massachusetts, December 21, + 1987. + + [2] Steiner, J., Neuman, C., and J. Schiller, "Kerberos: An + Authentication Service for Open Network Systems", pp. 191-202 in + Usenix Conference Proceedings, Dallas, Texas, February, 1988. + + [3] Needham, R., and M. Schroeder, "Using Encryption for + Authentication in Large Networks of Computers", Communications + of the ACM, Vol. 21 (12), pp. 993-999, December 1978. + + [4] Denning, D., and G. Sacco, "Time stamps in Key Distribution + Protocols", Communications of the ACM, Vol. 24 (8), pp. 533-536, + August 1981. + + [5] Kohl, J., Neuman, C., and T. Ts'o, "The Evolution of the + Kerberos Authentication Service", in an IEEE Computer Society + Text soon to be published, June 1992. + + [6] Davis, D., and R. Swick, "Workstation Services and Kerberos + Authentication at Project Athena", Technical Memorandum TM-424, + MIT Laboratory for Computer Science, February 1990. + + [7] Levine, P., Gretzinger, M, Diaz, J., Sommerfeld, W., and K. + Raeburn, "Section E.1: Service Management System, M.I.T. + Project Athena, Cambridge, Mas sachusetts (1987). + + [8] CCITT, Recommendation X.509: The Directory Authentication + Framework, December 1988. + + [9] Neuman, C., "Proxy-Based Authorization and Accounting for + Distributed Systems," in Proceedings of the 13th International + Conference on Distributed Computing Systems", Pittsburgh, PA, + May 1993. + + [10] Pato, J., "Using Pre-Authentication to Avoid Password Guessing + Attacks", Open Software Foundation DCE Request for Comments 26, + December 1992. + + [11] National Bureau of Standards, U.S. Department of Commerce, "Data + Encryption Standard", Federal Information Processing Standards + Publication 46, Washington, DC (1977). + + + + + +Kohl & Neuman [Page 89] + +RFC 1510 Kerberos September 1993 + + + [12] National Bureau of Standards, U.S. Department of Commerce, "DES + Modes of Operation", Federal Information Processing Standards + Publication 81, Springfield, VA, December 1980. + + [13] Stubblebine S., and V. Gligor, "On Message Integrity in + Cryptographic Protocols", in Proceedings of the IEEE Symposium + on Research in Security and Privacy, Oakland, California, May + 1992. + + [14] International Organization for Standardization, "ISO Information + Processing Systems - Data Communication High-Level Data Link + Control Procedure - Frame Structure", IS 3309, October 1984, 3rd + Edition. + + [15] Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT + Laboratory for Computer Science, April 1992. + + [16] Rivest, R., "The MD5 Message Digest Algorithm", RFC 1321, MIT + Laboratory for Computer Science, April 1992. + + [17] Bellovin S., and M. Merritt, "Limitations of the Kerberos + Authentication System", Computer Communications Review, Vol. + 20(5), pp. 119-132, October 1990. + +12. Security Considerations + + Security issues are discussed throughout this memo. + +13. Authors' Addresses + + John Kohl + Digital Equipment Corporation + 110 Spit Brook Road, M/S ZKO3-3/U14 + Nashua, NH 03062 + + Phone: 603-881-2481 + EMail: jtkohl@zk3.dec.com + + + B. Clifford Neuman + USC/Information Sciences Institute + 4676 Admiralty Way #1001 + Marina del Rey, CA 90292-6695 + + Phone: 310-822-1511 + EMail: bcn@isi.edu + + + + + +Kohl & Neuman [Page 90] + +RFC 1510 Kerberos September 1993 + + +A. Pseudo-code for protocol processing + + This appendix provides pseudo-code describing how the messages are to + be constructed and interpreted by clients and servers. + +A.1. KRB_AS_REQ generation + request.pvno := protocol version; /* pvno = 5 */ + request.msg-type := message type; /* type = KRB_AS_REQ */ + + if(pa_enc_timestamp_required) then + request.padata.padata-type = PA-ENC-TIMESTAMP; + get system_time; + padata-body.patimestamp,pausec = system_time; + encrypt padata-body into request.padata.padata-value + using client.key; /* derived from password */ + endif + + body.kdc-options := users's preferences; + body.cname := user's name; + body.realm := user's realm; + body.sname := service's name; /* usually "krbtgt", + "localrealm" */ + if (body.kdc-options.POSTDATED is set) then + body.from := requested starting time; + else + omit body.from; + endif + body.till := requested end time; + if (body.kdc-options.RENEWABLE is set) then + body.rtime := requested final renewal time; + endif + body.nonce := random_nonce(); + body.etype := requested etypes; + if (user supplied addresses) then + body.addresses := user's addresses; + else + omit body.addresses; + endif + omit body.enc-authorization-data; + request.req-body := body; + + kerberos := lookup(name of local kerberos server (or servers)); + send(packet,kerberos); + + wait(for response); + if (timed_out) then + retry or use alternate server; + endif + + + +Kohl & Neuman [Page 91] + +RFC 1510 Kerberos September 1993 + + +A.2. KRB_AS_REQ verification and KRB_AS_REP generation + decode message into req; + + client := lookup(req.cname,req.realm); + server := lookup(req.sname,req.realm); + get system_time; + kdc_time := system_time.seconds; + + if (!client) then + /* no client in Database */ + error_out(KDC_ERR_C_PRINCIPAL_UNKNOWN); + endif + if (!server) then + /* no server in Database */ + error_out(KDC_ERR_S_PRINCIPAL_UNKNOWN); + endif + + if(client.pa_enc_timestamp_required and + pa_enc_timestamp not present) then + error_out(KDC_ERR_PREAUTH_REQUIRED(PA_ENC_TIMESTAMP)); + endif + + if(pa_enc_timestamp present) then + decrypt req.padata-value into decrypted_enc_timestamp + using client.key; + using auth_hdr.authenticator.subkey; + if (decrypt_error()) then + error_out(KRB_AP_ERR_BAD_INTEGRITY); + if(decrypted_enc_timestamp is not within allowable + skew) then error_out(KDC_ERR_PREAUTH_FAILED); + endif + if(decrypted_enc_timestamp and usec is replay) + error_out(KDC_ERR_PREAUTH_FAILED); + endif + add decrypted_enc_timestamp and usec to replay cache; + endif + + use_etype := first supported etype in req.etypes; + + if (no support for req.etypes) then + error_out(KDC_ERR_ETYPE_NOSUPP); + endif + + new_tkt.vno := ticket version; /* = 5 */ + new_tkt.sname := req.sname; + new_tkt.srealm := req.srealm; + reset all flags in new_tkt.flags; + + + + +Kohl & Neuman [Page 92] + +RFC 1510 Kerberos September 1993 + + + /* It should be noted that local policy may affect the */ + /* processing of any of these flags. For example, some */ + /* realms may refuse to issue renewable tickets */ + + if (req.kdc-options.FORWARDABLE is set) then + set new_tkt.flags.FORWARDABLE; + endif + if (req.kdc-options.PROXIABLE is set) then + set new_tkt.flags.PROXIABLE; + endif + if (req.kdc-options.ALLOW-POSTDATE is set) then + set new_tkt.flags.ALLOW-POSTDATE; + endif + if ((req.kdc-options.RENEW is set) or + (req.kdc-options.VALIDATE is set) or + (req.kdc-options.PROXY is set) or + (req.kdc-options.FORWARDED is set) or + (req.kdc-options.ENC-TKT-IN-SKEY is set)) then + error_out(KDC_ERR_BADOPTION); + endif + + new_tkt.session := random_session_key(); + new_tkt.cname := req.cname; + new_tkt.crealm := req.crealm; + new_tkt.transited := empty_transited_field(); + + new_tkt.authtime := kdc_time; + + if (req.kdc-options.POSTDATED is set) then + if (against_postdate_policy(req.from)) then + error_out(KDC_ERR_POLICY); + endif + set new_tkt.flags.INVALID; + new_tkt.starttime := req.from; + else + omit new_tkt.starttime; /* treated as authtime when + omitted */ + endif + if (req.till = 0) then + till := infinity; + else + till := req.till; + endif + + new_tkt.endtime := min(till, + new_tkt.starttime+client.max_life, + new_tkt.starttime+server.max_life, + new_tkt.starttime+max_life_for_realm); + + + +Kohl & Neuman [Page 93] + +RFC 1510 Kerberos September 1993 + + + if ((req.kdc-options.RENEWABLE-OK is set) and + (new_tkt.endtime < req.till)) then + /* we set the RENEWABLE option for later processing */ + set req.kdc-options.RENEWABLE; + req.rtime := req.till; + endif + + if (req.rtime = 0) then + rtime := infinity; + else + rtime := req.rtime; + endif + + if (req.kdc-options.RENEWABLE is set) then + set new_tkt.flags.RENEWABLE; + new_tkt.renew-till := min(rtime, + new_tkt.starttime+client.max_rlife, + new_tkt.starttime+server.max_rlife, + new_tkt.starttime+max_rlife_for_realm); + else + omit new_tkt.renew-till; /* only present if RENEWABLE */ + endif + + if (req.addresses) then + new_tkt.caddr := req.addresses; + else + omit new_tkt.caddr; + endif + + new_tkt.authorization_data := empty_authorization_data(); + + encode to-be-encrypted part of ticket into OCTET STRING; + new_tkt.enc-part := encrypt OCTET STRING + using etype_for_key(server.key), server.key, server.p_kvno; + + + /* Start processing the response */ + + resp.pvno := 5; + resp.msg-type := KRB_AS_REP; + resp.cname := req.cname; + resp.crealm := req.realm; + resp.ticket := new_tkt; + + resp.key := new_tkt.session; + resp.last-req := fetch_last_request_info(client); + resp.nonce := req.nonce; + resp.key-expiration := client.expiration; + + + +Kohl & Neuman [Page 94] + +RFC 1510 Kerberos September 1993 + + + resp.flags := new_tkt.flags; + + resp.authtime := new_tkt.authtime; + resp.starttime := new_tkt.starttime; + resp.endtime := new_tkt.endtime; + + if (new_tkt.flags.RENEWABLE) then + resp.renew-till := new_tkt.renew-till; + endif + + resp.realm := new_tkt.realm; + resp.sname := new_tkt.sname; + + resp.caddr := new_tkt.caddr; + + encode body of reply into OCTET STRING; + + resp.enc-part := encrypt OCTET STRING + using use_etype, client.key, client.p_kvno; + send(resp); + +A.3. KRB_AS_REP verification + decode response into resp; + + if (resp.msg-type = KRB_ERROR) then + if(error = KDC_ERR_PREAUTH_REQUIRED(PA_ENC_TIMESTAMP)) + then set pa_enc_timestamp_required; + goto KRB_AS_REQ; + endif + process_error(resp); + return; + endif + + /* On error, discard the response, and zero the session key */ + /* from the response immediately */ + + key = get_decryption_key(resp.enc-part.kvno, resp.enc-part.etype, + resp.padata); + unencrypted part of resp := decode of decrypt of resp.enc-part + using resp.enc-part.etype and key; + zero(key); + + if (common_as_rep_tgs_rep_checks fail) then + destroy resp.key; + return error; + endif + + if near(resp.princ_exp) then + + + +Kohl & Neuman [Page 95] + +RFC 1510 Kerberos September 1993 + + + print(warning message); + endif + save_for_later(ticket,session,client,server,times,flags); + +A.4. KRB_AS_REP and KRB_TGS_REP common checks + if (decryption_error() or + (req.cname != resp.cname) or + (req.realm != resp.crealm) or + (req.sname != resp.sname) or + (req.realm != resp.realm) or + (req.nonce != resp.nonce) or + (req.addresses != resp.caddr)) then + destroy resp.key; + return KRB_AP_ERR_MODIFIED; + endif + + /* make sure no flags are set that shouldn't be, and that */ + /* all that should be are set */ + if (!check_flags_for_compatability(req.kdc-options,resp.flags)) + then destroy resp.key; + return KRB_AP_ERR_MODIFIED; + endif + + if ((req.from = 0) and + (resp.starttime is not within allowable skew)) then + destroy resp.key; + return KRB_AP_ERR_SKEW; + endif + if ((req.from != 0) and (req.from != resp.starttime)) then + destroy resp.key; + return KRB_AP_ERR_MODIFIED; + endif + if ((req.till != 0) and (resp.endtime > req.till)) then + destroy resp.key; + return KRB_AP_ERR_MODIFIED; + endif + + if ((req.kdc-options.RENEWABLE is set) and + (req.rtime != 0) and (resp.renew-till > req.rtime)) then + destroy resp.key; + return KRB_AP_ERR_MODIFIED; + endif + if ((req.kdc-options.RENEWABLE-OK is set) and + (resp.flags.RENEWABLE) and + (req.till != 0) and + (resp.renew-till > req.till)) then + destroy resp.key; + return KRB_AP_ERR_MODIFIED; + + + +Kohl & Neuman [Page 96] + +RFC 1510 Kerberos September 1993 + + + endif + +A.5. KRB_TGS_REQ generation + /* Note that make_application_request might have to */ + /* recursivly call this routine to get the appropriate */ + /* ticket-granting ticket */ + + request.pvno := protocol version; /* pvno = 5 */ + request.msg-type := message type; /* type = KRB_TGS_REQ */ + + body.kdc-options := users's preferences; + /* If the TGT is not for the realm of the end-server */ + /* then the sname will be for a TGT for the end-realm */ + /* and the realm of the requested ticket (body.realm) */ + /* will be that of the TGS to which the TGT we are */ + /* sending applies */ + body.sname := service's name; + body.realm := service's realm; + + if (body.kdc-options.POSTDATED is set) then + body.from := requested starting time; + else + omit body.from; + endif + body.till := requested end time; + if (body.kdc-options.RENEWABLE is set) then + body.rtime := requested final renewal time; + endif + body.nonce := random_nonce(); + body.etype := requested etypes; + if (user supplied addresses) then + body.addresses := user's addresses; + else + omit body.addresses; + endif + + body.enc-authorization-data := user-supplied data; + if (body.kdc-options.ENC-TKT-IN-SKEY) then + body.additional-tickets_ticket := second TGT; + endif + + request.req-body := body; + check := generate_checksum (req.body,checksumtype); + + request.padata[0].padata-type := PA-TGS-REQ; + request.padata[0].padata-value := create a KRB_AP_REQ using + the TGT and checksum + + + + +Kohl & Neuman [Page 97] + +RFC 1510 Kerberos September 1993 + + + /* add in any other padata as required/supplied */ + + kerberos := lookup(name of local kerberose server (or servers)); + send(packet,kerberos); + + wait(for response); + if (timed_out) then + retry or use alternate server; + endif + +A.6. KRB_TGS_REQ verification and KRB_TGS_REP generation + /* note that reading the application request requires first + determining the server for which a ticket was issued, and + choosing the correct key for decryption. The name of the + server appears in the plaintext part of the ticket. */ + + if (no KRB_AP_REQ in req.padata) then + error_out(KDC_ERR_PADATA_TYPE_NOSUPP); + endif + verify KRB_AP_REQ in req.padata; + + /* Note that the realm in which the Kerberos server is + operating is determined by the instance from the + ticket-granting ticket. The realm in the ticket-granting + ticket is the realm under which the ticket granting ticket was + issued. It is possible for a single Kerberos server to + support more than one realm. */ + + auth_hdr := KRB_AP_REQ; + tgt := auth_hdr.ticket; + + if (tgt.sname is not a TGT for local realm and is not + req.sname) then error_out(KRB_AP_ERR_NOT_US); + + realm := realm_tgt_is_for(tgt); + + decode remainder of request; + + if (auth_hdr.authenticator.cksum is missing) then + error_out(KRB_AP_ERR_INAPP_CKSUM); + endif + if (auth_hdr.authenticator.cksum type is not supported) then + error_out(KDC_ERR_SUMTYPE_NOSUPP); + endif + if (auth_hdr.authenticator.cksum is not both collision-proof + and keyed) then + error_out(KRB_AP_ERR_INAPP_CKSUM); + endif + + + +Kohl & Neuman [Page 98] + +RFC 1510 Kerberos September 1993 + + + set computed_checksum := checksum(req); + if (computed_checksum != auth_hdr.authenticatory.cksum) then + error_out(KRB_AP_ERR_MODIFIED); + endif + + server := lookup(req.sname,realm); + + if (!server) then + if (is_foreign_tgt_name(server)) then + server := best_intermediate_tgs(server); + else + /* no server in Database */ + error_out(KDC_ERR_S_PRINCIPAL_UNKNOWN); + endif + endif + + session := generate_random_session_key(); + + + use_etype := first supported etype in req.etypes; + + if (no support for req.etypes) then + error_out(KDC_ERR_ETYPE_NOSUPP); + endif + + new_tkt.vno := ticket version; /* = 5 */ + new_tkt.sname := req.sname; + new_tkt.srealm := realm; + reset all flags in new_tkt.flags; + + /* It should be noted that local policy may affect the */ + /* processing of any of these flags. For example, some */ + /* realms may refuse to issue renewable tickets */ + + new_tkt.caddr := tgt.caddr; + resp.caddr := NULL; /* We only include this if they change */ + if (req.kdc-options.FORWARDABLE is set) then + if (tgt.flags.FORWARDABLE is reset) then + error_out(KDC_ERR_BADOPTION); + endif + set new_tkt.flags.FORWARDABLE; + endif + if (req.kdc-options.FORWARDED is set) then + if (tgt.flags.FORWARDABLE is reset) then + error_out(KDC_ERR_BADOPTION); + endif + set new_tkt.flags.FORWARDED; + new_tkt.caddr := req.addresses; + + + +Kohl & Neuman [Page 99] + +RFC 1510 Kerberos September 1993 + + + resp.caddr := req.addresses; + endif + if (tgt.flags.FORWARDED is set) then + set new_tkt.flags.FORWARDED; + endif + + if (req.kdc-options.PROXIABLE is set) then + if (tgt.flags.PROXIABLE is reset) + error_out(KDC_ERR_BADOPTION); + endif + set new_tkt.flags.PROXIABLE; + endif + if (req.kdc-options.PROXY is set) then + if (tgt.flags.PROXIABLE is reset) then + error_out(KDC_ERR_BADOPTION); + endif + set new_tkt.flags.PROXY; + new_tkt.caddr := req.addresses; + resp.caddr := req.addresses; + endif + + if (req.kdc-options.POSTDATE is set) then + if (tgt.flags.POSTDATE is reset) + error_out(KDC_ERR_BADOPTION); + endif + set new_tkt.flags.POSTDATE; + endif + if (req.kdc-options.POSTDATED is set) then + if (tgt.flags.POSTDATE is reset) then + error_out(KDC_ERR_BADOPTION); + endif + set new_tkt.flags.POSTDATED; + set new_tkt.flags.INVALID; + if (against_postdate_policy(req.from)) then + error_out(KDC_ERR_POLICY); + endif + new_tkt.starttime := req.from; + endif + + + if (req.kdc-options.VALIDATE is set) then + if (tgt.flags.INVALID is reset) then + error_out(KDC_ERR_POLICY); + endif + if (tgt.starttime > kdc_time) then + error_out(KRB_AP_ERR_NYV); + endif + if (check_hot_list(tgt)) then + + + +Kohl & Neuman [Page 100] + +RFC 1510 Kerberos September 1993 + + + error_out(KRB_AP_ERR_REPEAT); + endif + tkt := tgt; + reset new_tkt.flags.INVALID; + endif + + if (req.kdc-options.(any flag except ENC-TKT-IN-SKEY, RENEW, + and those already processed) is set) then + error_out(KDC_ERR_BADOPTION); + endif + + new_tkt.authtime := tgt.authtime; + + if (req.kdc-options.RENEW is set) then + /* Note that if the endtime has already passed, the ticket */ + /* would have been rejected in the initial authentication */ + /* stage, so there is no need to check again here */ + if (tgt.flags.RENEWABLE is reset) then + error_out(KDC_ERR_BADOPTION); + endif + if (tgt.renew-till >= kdc_time) then + error_out(KRB_AP_ERR_TKT_EXPIRED); + endif + tkt := tgt; + new_tkt.starttime := kdc_time; + old_life := tgt.endttime - tgt.starttime; + new_tkt.endtime := min(tgt.renew-till, + new_tkt.starttime + old_life); + else + new_tkt.starttime := kdc_time; + if (req.till = 0) then + till := infinity; + else + till := req.till; + endif + new_tkt.endtime := min(till, + new_tkt.starttime+client.max_life, + new_tkt.starttime+server.max_life, + new_tkt.starttime+max_life_for_realm, + tgt.endtime); + + if ((req.kdc-options.RENEWABLE-OK is set) and + (new_tkt.endtime < req.till) and + (tgt.flags.RENEWABLE is set) then + /* we set the RENEWABLE option for later */ + /* processing */ + set req.kdc-options.RENEWABLE; + req.rtime := min(req.till, tgt.renew-till); + + + +Kohl & Neuman [Page 101] + +RFC 1510 Kerberos September 1993 + + + endif + endif + + if (req.rtime = 0) then + rtime := infinity; + else + rtime := req.rtime; + endif + + if ((req.kdc-options.RENEWABLE is set) and + (tgt.flags.RENEWABLE is set)) then + set new_tkt.flags.RENEWABLE; + new_tkt.renew-till := min(rtime, + new_tkt.starttime+client.max_rlife, + new_tkt.starttime+server.max_rlife, + new_tkt.starttime+max_rlife_for_realm, + tgt.renew-till); + else + new_tkt.renew-till := OMIT; + /* leave the renew-till field out */ + endif + if (req.enc-authorization-data is present) then + decrypt req.enc-authorization-data + into decrypted_authorization_data + using auth_hdr.authenticator.subkey; + if (decrypt_error()) then + error_out(KRB_AP_ERR_BAD_INTEGRITY); + endif + endif + new_tkt.authorization_data := + req.auth_hdr.ticket.authorization_data + + decrypted_authorization_data; + + new_tkt.key := session; + new_tkt.crealm := tgt.crealm; + new_tkt.cname := req.auth_hdr.ticket.cname; + + if (realm_tgt_is_for(tgt) := tgt.realm) then + /* tgt issued by local realm */ + new_tkt.transited := tgt.transited; + else + /* was issued for this realm by some other realm */ + if (tgt.transited.tr-type not supported) then + error_out(KDC_ERR_TRTYPE_NOSUPP); + endif + new_tkt.transited + := compress_transited(tgt.transited + tgt.realm) + endif + + + +Kohl & Neuman [Page 102] + +RFC 1510 Kerberos September 1993 + + + encode encrypted part of new_tkt into OCTET STRING; + if (req.kdc-options.ENC-TKT-IN-SKEY is set) then + if (server not specified) then + server = req.second_ticket.client; + endif + if ((req.second_ticket is not a TGT) or + (req.second_ticket.client != server)) then + error_out(KDC_ERR_POLICY); + endif + + new_tkt.enc-part := encrypt OCTET STRING using + using etype_for_key(second-ticket.key), + second-ticket.key; + else + new_tkt.enc-part := encrypt OCTET STRING + using etype_for_key(server.key), server.key, + server.p_kvno; + endif + + resp.pvno := 5; + resp.msg-type := KRB_TGS_REP; + resp.crealm := tgt.crealm; + resp.cname := tgt.cname; + resp.ticket := new_tkt; + + resp.key := session; + resp.nonce := req.nonce; + resp.last-req := fetch_last_request_info(client); + resp.flags := new_tkt.flags; + + resp.authtime := new_tkt.authtime; + resp.starttime := new_tkt.starttime; + resp.endtime := new_tkt.endtime; + + omit resp.key-expiration; + + resp.sname := new_tkt.sname; + resp.realm := new_tkt.realm; + + if (new_tkt.flags.RENEWABLE) then + resp.renew-till := new_tkt.renew-till; + endif + + + encode body of reply into OCTET STRING; + + if (req.padata.authenticator.subkey) + resp.enc-part := encrypt OCTET STRING using use_etype, + + + +Kohl & Neuman [Page 103] + +RFC 1510 Kerberos September 1993 + + + req.padata.authenticator.subkey; + else resp.enc-part := encrypt OCTET STRING + using use_etype, tgt.key; + + send(resp); + +A.7. KRB_TGS_REP verification + decode response into resp; + + if (resp.msg-type = KRB_ERROR) then + process_error(resp); + return; + endif + + /* On error, discard the response, and zero the session key from + the response immediately */ + + if (req.padata.authenticator.subkey) + unencrypted part of resp := + decode of decrypt of resp.enc-part + using resp.enc-part.etype and subkey; + else unencrypted part of resp := + decode of decrypt of resp.enc-part + using resp.enc-part.etype and tgt's session key; + if (common_as_rep_tgs_rep_checks fail) then + destroy resp.key; + return error; + endif + + check authorization_data as necessary; + save_for_later(ticket,session,client,server,times,flags); + +A.8. Authenticator generation + body.authenticator-vno := authenticator vno; /* = 5 */ + body.cname, body.crealm := client name; + if (supplying checksum) then + body.cksum := checksum; + endif + get system_time; + body.ctime, body.cusec := system_time; + if (selecting sub-session key) then + select sub-session key; + body.subkey := sub-session key; + endif + if (using sequence numbers) then + select initial sequence number; + body.seq-number := initial sequence; + endif + + + +Kohl & Neuman [Page 104] + +RFC 1510 Kerberos September 1993 + + +A.9. KRB_AP_REQ generation + obtain ticket and session_key from cache; + + packet.pvno := protocol version; /* 5 */ + packet.msg-type := message type; /* KRB_AP_REQ */ + + if (desired(MUTUAL_AUTHENTICATION)) then + set packet.ap-options.MUTUAL-REQUIRED; + else + reset packet.ap-options.MUTUAL-REQUIRED; + endif + if (using session key for ticket) then + set packet.ap-options.USE-SESSION-KEY; + else + reset packet.ap-options.USE-SESSION-KEY; + endif + packet.ticket := ticket; /* ticket */ + generate authenticator; + encode authenticator into OCTET STRING; + encrypt OCTET STRING into packet.authenticator + using session_key; + +A.10. KRB_AP_REQ verification + receive packet; + if (packet.pvno != 5) then + either process using other protocol spec + or error_out(KRB_AP_ERR_BADVERSION); + endif + if (packet.msg-type != KRB_AP_REQ) then + error_out(KRB_AP_ERR_MSG_TYPE); + endif + if (packet.ticket.tkt_vno != 5) then + either process using other protocol spec + or error_out(KRB_AP_ERR_BADVERSION); + endif + if (packet.ap_options.USE-SESSION-KEY is set) then + retrieve session key from ticket-granting ticket for + packet.ticket.{sname,srealm,enc-part.etype}; + else + retrieve service key for + packet.ticket.{sname,srealm,enc-part.etype,enc-part.skvno}; + endif + if (no_key_available) then + if (cannot_find_specified_skvno) then + error_out(KRB_AP_ERR_BADKEYVER); + else + error_out(KRB_AP_ERR_NOKEY); + endif + + + +Kohl & Neuman [Page 105] + +RFC 1510 Kerberos September 1993 + + + endif + decrypt packet.ticket.enc-part into decr_ticket + using retrieved key; + if (decryption_error()) then + error_out(KRB_AP_ERR_BAD_INTEGRITY); + endif + decrypt packet.authenticator into decr_authenticator + using decr_ticket.key; + if (decryption_error()) then + error_out(KRB_AP_ERR_BAD_INTEGRITY); + endif + if (decr_authenticator.{cname,crealm} != + decr_ticket.{cname,crealm}) then + error_out(KRB_AP_ERR_BADMATCH); + endif + if (decr_ticket.caddr is present) then + if (sender_address(packet) is not in decr_ticket.caddr) + then error_out(KRB_AP_ERR_BADADDR); + endif + elseif (application requires addresses) then + error_out(KRB_AP_ERR_BADADDR); + endif + if (not in_clock_skew(decr_authenticator.ctime, + decr_authenticator.cusec)) then + error_out(KRB_AP_ERR_SKEW); + endif + if (repeated(decr_authenticator.{ctime,cusec,cname,crealm})) + then error_out(KRB_AP_ERR_REPEAT); + endif + save_identifier(decr_authenticator.{ctime,cusec,cname,crealm}); + get system_time; + if ((decr_ticket.starttime-system_time > CLOCK_SKEW) or + (decr_ticket.flags.INVALID is set)) then + /* it hasn't yet become valid */ + error_out(KRB_AP_ERR_TKT_NYV); + endif + if (system_time-decr_ticket.endtime > CLOCK_SKEW) then + error_out(KRB_AP_ERR_TKT_EXPIRED); + endif + /* caller must check decr_ticket.flags for any pertinent */ + /* details */ + return(OK, decr_ticket, packet.ap_options.MUTUAL-REQUIRED); + +A.11. KRB_AP_REP generation + packet.pvno := protocol version; /* 5 */ + packet.msg-type := message type; /* KRB_AP_REP */ + body.ctime := packet.ctime; + body.cusec := packet.cusec; + + + +Kohl & Neuman [Page 106] + +RFC 1510 Kerberos September 1993 + + + if (selecting sub-session key) then + select sub-session key; + body.subkey := sub-session key; + endif + if (using sequence numbers) then + select initial sequence number; + body.seq-number := initial sequence; + endif + + encode body into OCTET STRING; + + select encryption type; + encrypt OCTET STRING into packet.enc-part; + +A.12. KRB_AP_REP verification + receive packet; + if (packet.pvno != 5) then + either process using other protocol spec + or error_out(KRB_AP_ERR_BADVERSION); + endif + if (packet.msg-type != KRB_AP_REP) then + error_out(KRB_AP_ERR_MSG_TYPE); + endif + cleartext := decrypt(packet.enc-part) + using ticket's session key; + if (decryption_error()) then + error_out(KRB_AP_ERR_BAD_INTEGRITY); + endif + if (cleartext.ctime != authenticator.ctime) then + error_out(KRB_AP_ERR_MUT_FAIL); + endif + if (cleartext.cusec != authenticator.cusec) then + error_out(KRB_AP_ERR_MUT_FAIL); + endif + if (cleartext.subkey is present) then + save cleartext.subkey for future use; + endif + if (cleartext.seq-number is present) then + save cleartext.seq-number for future verifications; + endif + return(AUTHENTICATION_SUCCEEDED); + +A.13. KRB_SAFE generation + collect user data in buffer; + + /* assemble packet: */ + packet.pvno := protocol version; /* 5 */ + packet.msg-type := message type; /* KRB_SAFE */ + + + +Kohl & Neuman [Page 107] + +RFC 1510 Kerberos September 1993 + + + body.user-data := buffer; /* DATA */ + if (using timestamp) then + get system_time; + body.timestamp, body.usec := system_time; + endif + if (using sequence numbers) then + body.seq-number := sequence number; + endif + body.s-address := sender host addresses; + if (only one recipient) then + body.r-address := recipient host address; + endif + checksum.cksumtype := checksum type; + compute checksum over body; + checksum.checksum := checksum value; /* checksum.checksum */ + packet.cksum := checksum; + packet.safe-body := body; + +A.14. KRB_SAFE verification + receive packet; + if (packet.pvno != 5) then + either process using other protocol spec + or error_out(KRB_AP_ERR_BADVERSION); + endif + if (packet.msg-type != KRB_SAFE) then + error_out(KRB_AP_ERR_MSG_TYPE); + endif + if (packet.checksum.cksumtype is not both collision-proof + and keyed) then + error_out(KRB_AP_ERR_INAPP_CKSUM); + endif + if (safe_priv_common_checks_ok(packet)) then + set computed_checksum := checksum(packet.body); + if (computed_checksum != packet.checksum) then + error_out(KRB_AP_ERR_MODIFIED); + endif + return (packet, PACKET_IS_GENUINE); + else + return common_checks_error; + endif + +A.15. KRB_SAFE and KRB_PRIV common checks + if (packet.s-address != O/S_sender(packet)) then + /* O/S report of sender not who claims to have sent it */ + error_out(KRB_AP_ERR_BADADDR); + endif + if ((packet.r-address is present) and + (packet.r-address != local_host_address)) then + + + +Kohl & Neuman [Page 108] + +RFC 1510 Kerberos September 1993 + + + /* was not sent to proper place */ + error_out(KRB_AP_ERR_BADADDR); + endif + if (((packet.timestamp is present) and + (not in_clock_skew(packet.timestamp,packet.usec))) or + (packet.timestamp is not present and timestamp expected)) + then error_out(KRB_AP_ERR_SKEW); + endif + if (repeated(packet.timestamp,packet.usec,packet.s-address)) + then error_out(KRB_AP_ERR_REPEAT); + endif + if (((packet.seq-number is present) and + ((not in_sequence(packet.seq-number)))) or + (packet.seq-number is not present and sequence expected)) + then error_out(KRB_AP_ERR_BADORDER); + endif + if (packet.timestamp not present and + packet.seq-number not present) then + error_out(KRB_AP_ERR_MODIFIED); + endif + + save_identifier(packet.{timestamp,usec,s-address}, + sender_principal(packet)); + + return PACKET_IS_OK; + +A.16. KRB_PRIV generation + collect user data in buffer; + + /* assemble packet: */ + packet.pvno := protocol version; /* 5 */ + packet.msg-type := message type; /* KRB_PRIV */ + + packet.enc-part.etype := encryption type; + + body.user-data := buffer; + if (using timestamp) then + get system_time; + body.timestamp, body.usec := system_time; + endif + if (using sequence numbers) then + body.seq-number := sequence number; + endif + body.s-address := sender host addresses; + if (only one recipient) then + body.r-address := recipient host address; + endif + + + + +Kohl & Neuman [Page 109] + +RFC 1510 Kerberos September 1993 + + + encode body into OCTET STRING; + + select encryption type; + encrypt OCTET STRING into packet.enc-part.cipher; + +A.17. KRB_PRIV verification + receive packet; + if (packet.pvno != 5) then + either process using other protocol spec + or error_out(KRB_AP_ERR_BADVERSION); + endif + if (packet.msg-type != KRB_PRIV) then + error_out(KRB_AP_ERR_MSG_TYPE); + endif + + cleartext := decrypt(packet.enc-part) using negotiated key; + if (decryption_error()) then + error_out(KRB_AP_ERR_BAD_INTEGRITY); + endif + + if (safe_priv_common_checks_ok(cleartext)) then + return(cleartext.DATA, PACKET_IS_GENUINE_AND_UNMODIFIED); + else + return common_checks_error; + endif + +A.18. KRB_CRED generation + invoke KRB_TGS; /* obtain tickets to be provided to peer */ + + /* assemble packet: */ + packet.pvno := protocol version; /* 5 */ + packet.msg-type := message type; /* KRB_CRED */ + + for (tickets[n] in tickets to be forwarded) do + packet.tickets[n] = tickets[n].ticket; + done + + packet.enc-part.etype := encryption type; + + for (ticket[n] in tickets to be forwarded) do + body.ticket-info[n].key = tickets[n].session; + body.ticket-info[n].prealm = tickets[n].crealm; + body.ticket-info[n].pname = tickets[n].cname; + body.ticket-info[n].flags = tickets[n].flags; + body.ticket-info[n].authtime = tickets[n].authtime; + body.ticket-info[n].starttime = tickets[n].starttime; + body.ticket-info[n].endtime = tickets[n].endtime; + body.ticket-info[n].renew-till = tickets[n].renew-till; + + + +Kohl & Neuman [Page 110] + +RFC 1510 Kerberos September 1993 + + + body.ticket-info[n].srealm = tickets[n].srealm; + body.ticket-info[n].sname = tickets[n].sname; + body.ticket-info[n].caddr = tickets[n].caddr; + done + + get system_time; + body.timestamp, body.usec := system_time; + + if (using nonce) then + body.nonce := nonce; + endif + + if (using s-address) then + body.s-address := sender host addresses; + endif + if (limited recipients) then + body.r-address := recipient host address; + endif + + encode body into OCTET STRING; + + select encryption type; + encrypt OCTET STRING into packet.enc-part.cipher + using negotiated encryption key; + +A.19. KRB_CRED verification + receive packet; + if (packet.pvno != 5) then + either process using other protocol spec + or error_out(KRB_AP_ERR_BADVERSION); + endif + if (packet.msg-type != KRB_CRED) then + error_out(KRB_AP_ERR_MSG_TYPE); + endif + + cleartext := decrypt(packet.enc-part) using negotiated key; + if (decryption_error()) then + error_out(KRB_AP_ERR_BAD_INTEGRITY); + endif + if ((packet.r-address is present or required) and + (packet.s-address != O/S_sender(packet)) then + /* O/S report of sender not who claims to have sent it */ + error_out(KRB_AP_ERR_BADADDR); + endif + if ((packet.r-address is present) and + (packet.r-address != local_host_address)) then + /* was not sent to proper place */ + error_out(KRB_AP_ERR_BADADDR); + + + +Kohl & Neuman [Page 111] + +RFC 1510 Kerberos September 1993 + + + endif + if (not in_clock_skew(packet.timestamp,packet.usec)) then + error_out(KRB_AP_ERR_SKEW); + endif + if (repeated(packet.timestamp,packet.usec,packet.s-address)) + then error_out(KRB_AP_ERR_REPEAT); + endif + if (packet.nonce is required or present) and + (packet.nonce != expected-nonce) then + error_out(KRB_AP_ERR_MODIFIED); + endif + + for (ticket[n] in tickets that were forwarded) do + save_for_later(ticket[n],key[n],principal[n], + server[n],times[n],flags[n]); + return + +A.20. KRB_ERROR generation + + /* assemble packet: */ + packet.pvno := protocol version; /* 5 */ + packet.msg-type := message type; /* KRB_ERROR */ + + get system_time; + packet.stime, packet.susec := system_time; + packet.realm, packet.sname := server name; + + if (client time available) then + packet.ctime, packet.cusec := client_time; + endif + packet.error-code := error code; + if (client name available) then + packet.cname, packet.crealm := client name; + endif + if (error text available) then + packet.e-text := error text; + endif + if (error data available) then + packet.e-data := error data; + endif + + + + + + + + + + + +Kohl & Neuman [Page 112] + \ No newline at end of file diff --git a/mechglue/doc/krb5conf.texinfo b/mechglue/doc/krb5conf.texinfo new file mode 100644 index 000000000..09825524f --- /dev/null +++ b/mechglue/doc/krb5conf.texinfo @@ -0,0 +1,83 @@ +The @code{krb5.conf} file contains Kerberos configuration information, +including the locations of KDCs and admin servers for the Kerberos +realms of interest, defaults for the current realm and for Kerberos +applications, and mappings of hostnames onto Kerberos realms. Normally, +you should install your @code{krb5.conf} file in the directory +@code{/etc}. You can override the default location by setting the +environment variable @samp{KRB5_CONFIG}. + +The @code{krb5.conf} file is set up in the style of a Windows INI file. +Sections are headed by the section name, in square brackets. Each +section may contain zero or more relations, of the form: + +@smallexample +foo = bar +@end smallexample + +@noindent +or + +@smallexample +@group +fubar = @{ + foo = bar + baz = quux +@} +@end group +@end smallexample + +Placing a `*' at the end of a line indicates that this is the +@dfn{final} value for the tag. This means that neither the remainder +of this configuration file nor any other configuration file will be +checked for any other values for this tag. + +For example, if you have the following lines: + +@smallexample +foo = bar* +foo = baz +@end smallexample + +then the second value of foo (baz) would never be read. + +The @code{krb5.conf} file may contain any or all of the following +sections: + +@table @b +@itemx libdefaults +Contains default values used by the Kerberos V5 library. + +@itemx login +Contains default values used by the Kerberos V5 login program. + +@itemx appdefaults +Contains default values that can be used by Kerberos V5 applications. + +@itemx realms +Contains subsections keyed by Kerberos realm names. Each subsection +describes realm-specific information, including where to find the +Kerberos servers for that realm. + +@itemx domain_realm +Contains relations which map domain names and subdomains onto Kerberos +realm names. This is used by programs to determine what realm a host +should be in, given its fully qualified domain name. + +@itemx logging +Contains relations which determine how Kerberos programs are to perform +logging. + +@itemx capaths +Contains the authentication paths used with direct (nonhierarchical) +cross-realm authentication. Entries in this section are used by the +client to determine the intermediate realms which may be used in +cross-realm authentication. It is also used by the end-service when +checking the transited field for trusted intermediate realms. + +@ignore +this doesn't seem to be used +@itemx kdc +For a KDC, may contain the location of the kdc.conf file. +@end ignore + +@end table diff --git a/mechglue/doc/man2html b/mechglue/doc/man2html new file mode 100755 index 000000000..ea45686b8 --- /dev/null +++ b/mechglue/doc/man2html @@ -0,0 +1,608 @@ +#!/usr/athena/bin/perl +#!/usr/local/bin/perl +##---------------------------------------------------------------------------## +## File: +## @(#) man2html 1.2 97/08/12 12:57:30 @(#) +## Author: +## Earl Hood, ehood@medusa.acs.uci.edu +## Description: +## man2html is a Perl program to convert formatted nroff output +## to HTML. +## +## Recommend command-line options based on platform: +## +## Platform Options +## --------------------------------------------------------------------- +## c2mp +## hp9000s700/800 -leftm 1 -topm 8 +## sun4 -sun +## --------------------------------------------------------------------- +## +##---------------------------------------------------------------------------## +## Copyright (C) 1995-1997 Earl Hood, ehood@medusa.acs.uci.edu +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +## 02111-1307, USA +##---------------------------------------------------------------------------## + +package Man2Html; + +use Getopt::Long; + +($PROG = $0) =~ s/.*\///; +$VERSION = "3.0.1"; + +## Input and outputs filehandles +$InFH = \*STDIN unless $InFH; +$OutFH = \*STDOUT unless $OutFH; + +## Backspace character: Used in overstriking detection +*bs = \"\b"; + +## Hash of section titles and their HTML tag wrapper. +## This list allows customization of what HTML tag is used for +## a given section head. +## +## The section title can be a regular expression. Therefore, one must +## be careful about quoting special characters. +## +%SectionHead = ( + + '\S.*OPTIONS.*' => '

', + 'AUTHORS?' => '

', + 'BUGS' => '

', + 'COMPATIBILITY' => '

', + 'DEPENDENCIES' => '

', + 'DESCRIPTION' => '

', + 'DIAGNOSTICS' => '

', + 'ENVIRONMENT' => '

', + 'ERRORS' => '

', + 'EXAMPLES' => '

', + 'EXTERNAL INFLUENCES' => '

', + 'FILES' => '

', + 'LIMITATIONS' => '

', + 'NAME' => '

', + 'NOTES?' => '

', + 'OPTIONS' => '

', + 'REFERENCES' => '

', + 'RETURN VALUE' => '

', + 'SECTION.*:' => '

', + 'SEE ALSO' => '

', + 'STANDARDS CONFORMANCE' => '

', + 'STYLE CONVENTION' => '

', + 'SYNOPSIS' => '

', + 'SYNTAX' => '

', + 'WARNINGS' => '

', + '\s+Section.*:' => '

', + +); + +## Fallback tag if above is not found +$HeadFallback = '

'; + +## Other gobals + +$Bare = 0; # Skip printing HTML head/foot flag +$BTag = 'B'; # Overstrike tag +$CgiUrl = ''; # CGI URL expression +$Compress = 0; # Do blank line compression flag +$K = 0; # Do keyword search processing flag +$NoDepage = 0; # Do not strip page information +$NoHeads = 0; # Do no header detection flag +$SeeAlso = 0; # Do only SEE ALSO xrefs flag +$Solaris = 0; # Solaris keyword search processing flag +$Sun = 0; # Headers not overstriken flag +$Title = ''; # Title +$UTag = 'I'; # Underline tag +$ftsz = 7; # Bottome margin size +$hdsz = 7; # Top margin size +$leftm = ''; # Left margin pad +$leftmsz = 0; # Left margin size +$pgsz = 66; # Size of page size +$txsz = 52; # Text body length size + +############################################################################# +## Main Block +############################################################################# +{ + if (get_cli_opts()) { + if ($K) { + man_k(); + } else { + do_it(); + } + } else { + usage(); + } +} + +############################################################################# +## Subroutines +############################################################################# + +sub do_it { + + ## Define while loop and then eval it when used. The reason + ## is to avoid the regular expression reevaulation in the + ## section head detection code. + + $doitcode =<<'EndOfDoItCode'; + + my($line, $tmp, $i, $head, $preindent, $see_also, $do); + + $see_also = !$SeeAlso; + print $OutFH "\n"; + LOOP: while(!eof($InFH)) { + $blank = 0; + for ($i=0; $i < $hdsz; $i++) { + last LOOP unless defined($_ = <$InFH>); + } + for ($i=0; $i < $txsz; $i++) { + last LOOP unless defined($_ = <$InFH>); + + ## Check if compress consecutive blank lines + if ($Compress and !/\S/) { + if ($blank) { next; } else { $blank = 1; } + } else { + $blank = 0; + } + + ## Try to check if line space is needed at page boundaries ## + if (!$NoDepage && ($i==0 || $i==($txsz-1)) && !/^\s*$/) { + /^(\s*)/; $tmp = length($1); + if ($do) { + if ($tmp < $preindent) { print $OutFH "\n"; } + } else { + $do = 1; + } + $preindent = $tmp; + } else { + $do = 0; $preindent = 0; + } + + ## Interpret line + $line = $_; + entitize(\$_); # Convert [$<>] to entity references + + ## Check for 'SEE ALSO' link only + if (!$see_also && $CgiUrl && $SeeAlso) { + ($tmp = $line) =~ s/.\010//go; + if ($tmp =~ /^\s*SEE\s+ALSO\s*$/o) { $see_also = 1; } + else { $see_also = 0; } + } + + ## Create anchor links for manpage references + s/((((.\010)+)?[\+_\.\w-])+\(((.\010)+)? + \d((.\010)+)?\w?\)) + /make_xref($1) + /geox if $see_also; + + ## Emphasize underlined words + # s/((_\010[^_])+[\.\(\)_]?(_\010[^_])+\)?)/emphasize($1)/oge; + # s/((_\010[^_])+([\.\(\)_]?(_\010[^_])+)?)/emphasize($1)/oge; + # + # The previous expressions were trying to be clever about + # detecting underlined text which contain non-alphanumeric + # characters. nroff will not underline non-alphanumeric + # characters in an underlined phrase, and the above was trying + # to detect that. It does not work all the time, and it + # screws up other text, so a simplified expression is used. + + s/((_\010[^_])+)/emphasize($1)/oge; + + $secth = 0; + ## Check for strong text and headings + if ($Sun || /.\010./o) { + if (!$NoHeads) { + $line =~ s/.\010//go; + $tmp = $HeadFallback; +EndOfDoItCode + + ## Create switch statement for detecting a heading + ## + $doitcode .= "HEADSW: {\n"; + foreach $head (keys %SectionHead) { + $doitcode .= join("", "\$tmp = '$SectionHead{$head}', ", + "\$secth = 1, last HEADSW ", + "if \$line =~ /^$leftm$head/o;\n"); + } + $doitcode .= "}\n"; + + ## Rest of routine + ## + $doitcode .=<<'EndOfDoItCode'; + if ($secth || $line =~ /^$leftm\S/o) { + chop $line; + $_ = $tmp . $line . $tmp; + s%<([^>]*)>$%%; + $_ = "\n\n" . $_ . "
\n";
+		    } else {
+			s/(((.\010)+.)+)/strongize($1)/oge;
+		    }
+		} else {
+		    s/(((.\010)+.)+)/strongize($1)/oge;
+		}
+	    }
+	    print $OutFH $_;
+	}
+
+	for ($i=0; $i < $ftsz; $i++) {
+	    last LOOP  unless defined($_ = <$InFH>);
+	}
+    }
+EndOfDoItCode
+
+
+    ##	Perform processing.
+
+    printhead()  unless $Bare;
+    print $OutFH "
\n";
+    eval $doitcode;			# $doitcode defined above
+    print $OutFH "
\n"; + printtail() unless $Bare; +} + +##--------------------------------------------------------------------------- +## +sub get_cli_opts { + return 0 unless + GetOptions( + "bare", # Leave out HTML, HEAD, BODY tags. + "belem=s", # HTML Element for overstriked text (def: "B") + "botm=i", # Number of lines for bottom margin (def: 7) + "cgiurl=s", # CGI URL for linking to other manpages + "cgiurlexp=s", # CGI URL Perl expr for linking to other manpages + "compress", # Compress consecutive blank lines + "headmap=s", # Filename of user section head map file + "k", # Process input from 'man -k' output. + "leftm=i", # Character width of left margin (def: 0) + "nodepage", # Do not remove pagination lines + "noheads", # Do not detect for section heads + "pgsize=i", # Number of lines in a page (def: 66) + "seealso", # Link to other manpages only in the SEE ALSO section + "solaris", # Parse 'man -k' output from a solaris system + "sun", # Section heads are not overstriked in input + "title=s", # Title of manpage (def: Not defined) + "topm=i", # Number of lines for top margin (def: 7) + "uelem=s", # HTML Element for underlined text (def: "I") + + "help" # Short usage message + ); + return 0 if defined($opt_help); + + $pgsz = $opt_pgsize || $pgsz; + if (defined($opt_nodepage)) { + $hdsz = 0; + $ftsz = 0; + } else { + $hdsz = $opt_topm if defined($opt_topm); + $ftsz = $opt_botm if defined($opt_botm); + } + $txsz = $pgsz - ($hdsz + $ftsz); + $leftmsz = $opt_leftm if defined($opt_leftm); + $leftm = ' ' x $leftmsz; + + $Bare = defined($opt_bare); + $Compress = defined($opt_compress); + $K = defined($opt_k); + $NoDepage = defined($opt_nodepage); + $NoHeads = defined($opt_noheads); + $SeeAlso = defined($opt_seealso); + $Solaris = defined($opt_solaris); + $Sun = defined($opt_sun); + + $Title = $opt_title || $Title; + $CgiUrl = $opt_cgiurlexp || + ($opt_cgiurl ? qq{return "$opt_cgiurl"} : ''); + + $BTag = $opt_belem || $BTag; + $UTag = $opt_uelem || $UTag; + $BTag =~ s/[<>]//g; + $UTag =~ s/[<>]//g; + + if (defined($opt_headmap)) { + require $opt_headmap or warn "Unable to read $opt_headmap\n"; + } + 1; +} + +##--------------------------------------------------------------------------- +sub printhead { + print $OutFH "\n"; + print $OutFH "\n", + "$Title\n", + "\n" if $Title; + print $OutFH "\n"; + print $OutFH "

$Title

\n", + "
\n" if $Title; +} + +##--------------------------------------------------------------------------- +sub printtail { + print $OutFH < +
+Man(1) output converted with +man2html +
+ + +EndOfRef +} + +##--------------------------------------------------------------------------- +sub emphasize { + my($txt) = shift; + $txt =~ s/.\010//go; + $txt = "<$UTag>$txt"; + $txt; +} + +##--------------------------------------------------------------------------- +sub strongize { + my($txt) = shift; + $txt =~ s/.\010//go; + $txt = "<$BTag>$txt"; + $txt; +} + +##--------------------------------------------------------------------------- +sub entitize { + my($txt) = shift; + + ## Check for special characters in overstrike text ## + $$txt =~ s/_\010\&/strike('_', '&')/geo; + $$txt =~ s/_\010/strike('_', '>')/geo; + + $$txt =~ s/(\&\010)+\&/strike('&', '&')/geo; + $$txt =~ s/(<\010)+\010)+>/strike('>', '>')/geo; + + ## Check for special characters in regular text. Must be careful + ## to check before/after character in expression because it might be + ## a special character. + $$txt =~ s/([^\010]\&[^\010])/htmlize2($1)/geo; + $$txt =~ s/([^\010]<[^\010])/htmlize2($1)/geo; + $$txt =~ s/([^\010]>[^\010])/htmlize2($1)/geo; +} + +##--------------------------------------------------------------------------- +## escape special characters in a string, in-place +## +sub htmlize { + my($str) = shift; + $$str =~ s/&/\&/g; + $$str =~ s//\>/g; + $$str; +} + +##--------------------------------------------------------------------------- +## htmlize2() is used by entitize. +## +sub htmlize2 { + my($str) = shift; + $str =~ s/&/\&/g; + $str =~ s//\>/g; + $str; +} + +##--------------------------------------------------------------------------- +## strike converts HTML special characters in overstriked text +## into entity references. The entities are overstriked so +## strongize() and emphasize() will recognize the entity to be +## wrapped in tags. +## +sub strike { + my($w, $char) = @_; + my($ret); + if ($w eq '_') { + if ($char eq '&') { + $ret = "_$bs\&_${bs}a_${bs}m_${bs}p_${bs};"; + } elsif ($char eq '<') { + $ret = "_$bs\&_${bs}l_${bs}t_${bs};"; + } elsif ($char eq '>') { + $ret = "_$bs\&_${bs}g_${bs}t_${bs};"; + } else { + warn qq|Unrecognized character, "$char", passed to strike()\n|; + } + } else { + if ($char eq '&') { + $ret = "\&$bs\&a${bs}am${bs}mp${bs}p;${bs};"; + } elsif ($char eq '<') { + $ret = "\&$bs\&l${bs}lt${bs}t;${bs};"; + } elsif ($char eq '>') { + $ret = "\&$bs\&g${bs}gt${bs}t;${bs};"; + } else { + warn qq|Unrecognized character, "$char", passed to strike()\n|; + } + } + $ret; +} + +##--------------------------------------------------------------------------- +## make_xref() converts a manpage crossreference into a hyperlink. +## +sub make_xref { + my $str = shift; + $str =~ s/.\010//go; # Remove overstriking + + if ($CgiUrl) { + my($title,$section,$subsection) = + ($str =~ /([\+_\.\w-]+)\((\d)(\w?)\)/); + + $title =~ s/\+/%2B/g; + my($href) = (eval $CgiUrl); + qq|$str|; + } else { + qq|$str|; + } +} + +##--------------------------------------------------------------------------- +## man_k() process a keyword search. The problem we have is there +## is no standard for keyword search results from man. Solaris +## systems have a different enough format to warrent dealing +## with it as a special case. For other cases, we try our best. +## Unfortunately, there are some lines of results that may be +## skipped. +## +sub man_k { + my($line,$refs,$section,$subsection,$desc,$i, + %Sec1, %Sec1sub, %Sec2, %Sec2sub, %Sec3, %Sec3sub, + %Sec4, %Sec4sub, %Sec5, %Sec5sub, %Sec6, %Sec6sub, + %Sec7, %Sec7sub, %Sec8, %Sec8sub, %Sec9, %Sec9sub, + %SecN, %SecNsub, %SecNsec); + + printhead() unless $Bare; + print $OutFH "\n"; + + while ($line = <$InFH>) { + next if $line !~ /\(\d\w?\)\s+-\s/; # check if line can be handled + ($refs,$section,$subsection,$desc) = + $line =~ /^\s*(.*)\((\d)(\w?)\)\s*-\s*(.*)$/; + + if ($Solaris) { + $refs =~ s/^\s*([\+_\.\w-]+)\s+([\+_\.\w-]+)\s*$/$1/; + # + } else { + $refs =~ s/\s(and|or)\s/,/gi; # Convert and/or to commas + $refs =~ s/^[^:\s]:\s*//; # Remove prefixed whatis path + } + $refs =~ s/\s//g; # Remove all whitespace + $refs =~ s/,/, /g; # Put space after comma + htmlize(\$desc); # Check for special chars in desc + $desc =~ s/^(.)/\U$1/; # Uppercase first letter in desc + + if ($section eq '1') { + $Sec1{$refs} = $desc; $Sec1sub{$refs} = $subsection; + } elsif ($section eq '2') { + $Sec2{$refs} = $desc; $Sec2sub{$refs} = $subsection; + } elsif ($section eq '3') { + $Sec3{$refs} = $desc; $Sec3sub{$refs} = $subsection; + } elsif ($section eq '4') { + $Sec4{$refs} = $desc; $Sec4sub{$refs} = $subsection; + } elsif ($section eq '5') { + $Sec5{$refs} = $desc; $Sec5sub{$refs} = $subsection; + } elsif ($section eq '6') { + $Sec6{$refs} = $desc; $Sec6sub{$refs} = $subsection; + } elsif ($section eq '7') { + $Sec7{$refs} = $desc; $Sec7sub{$refs} = $subsection; + } elsif ($section eq '8') { + $Sec8{$refs} = $desc; $Sec8sub{$refs} = $subsection; + } elsif ($section eq '9') { + $Sec9{$refs} = $desc; $Sec9sub{$refs} = $subsection; + } else { # Catch all + $SecN{$refs} = $desc; $SecNsec{$refs} = $section; + $SecNsub{$refs} = $subsection; + } + } + print_mank_sec(\%Sec1, 1, \%Sec1sub); + print_mank_sec(\%Sec2, 2, \%Sec2sub); + print_mank_sec(\%Sec3, 3, \%Sec3sub); + print_mank_sec(\%Sec4, 4, \%Sec4sub); + print_mank_sec(\%Sec5, 5, \%Sec5sub); + print_mank_sec(\%Sec6, 6, \%Sec6sub); + print_mank_sec(\%Sec7, 7, \%Sec7sub); + print_mank_sec(\%Sec8, 8, \%Sec8sub); + print_mank_sec(\%Sec9, 9, \%Sec9sub); + print_mank_sec(\%SecN, 'N', \%SecNsub, \%SecNsec); + + printtail() unless $Bare; +} +##--------------------------------------------------------------------------- +## print_mank_sec() prints out manpage cross-refs of a specific section. +## +sub print_mank_sec { + my($sec, $sect, $secsub, $secsec) = @_; + my(@array, @refs, $href, $item, $title, $subsection, $i, $section, + $xref); + $section = $sect; + + @array = sort keys %$sec; + if ($#array >= 0) { + print $OutFH "

Section $section

\n", + "
\n"; + foreach $item (@array) { + @refs = split(/,/, $item); + $section = $secsec->{$item} if $sect eq 'N'; + $subsection = $secsub->{$item}; + if ($CgiUrl) { + ($title = $refs[0]) =~ s/\(\)//g; # watch out for extra ()'s + $xref = eval $CgiUrl; + } + print $OutFH "
\n"; + $i = 0; + foreach (@refs) { + if ($CgiUrl) { + print $OutFH qq|$_|; + } else { + print $OutFH $_; + } + print $OutFH ", " if $i < $#refs; + $i++; + } + print $OutFH " ($section$subsection)\n", + "
\n", + $sec->{$item}, "
\n"; + } + print $OutFH "
\n"; + } +} + +##--------------------------------------------------------------------------- +## +sub usage { + print $OutFH < outfile +Options: + -bare : Do not put in HTML, HEAD, BODY tags + -belem : HTML Element for overstriked text (def: "B") + -botm <#> : Number of lines for bottom margin (def: 7) + -cgiurl : URL for linking to other manpages + -cgiurlexp : Perl expression URL for linking to other manpages + -compress : Compress consective blank lines + -headmap : Filename of user section head map file + -help : This message + -k : Process a keyword search result + -leftm <#> : Character width of left margin (def: 0) + -nodepage : Do not remove pagination lines + -noheads : Turn off section head detection + -pgsize <#> : Number of lines in a page (def: 66) + -seealso : Link to other manpages only in the SEE ALSO section + -solaris : Process keyword search result in Solaris format + -sun : Section heads are not overstriked in input + -title : Title of manpage (def: Not defined) + -topm <#> : Number of lines for top margin (def: 7) + -uelem : HTML Element for underlined text (def: "I") + +Description: + $PROG takes formatted manpages from STDIN and converts it to HTML sent + to STDOUT. The -topm and -botm arguments are the number of lines to the + main body text and NOT to the running headers/footers. + +Version: + $VERSION + Copyright (C) 1995-1997 Earl Hood, ehood\@medusa.acs.uci.edu + $PROG comes with ABSOLUTELY NO WARRANTY and $PROG may be copied only + under the terms of the GNU General Public License, which may be found in + the $PROG distribution. + +EndOfUsage + exit 0; +} diff --git a/mechglue/doc/man2html.M b/mechglue/doc/man2html.M new file mode 100644 index 000000000..537d6073b --- /dev/null +++ b/mechglue/doc/man2html.M @@ -0,0 +1,761 @@ +.\" sccsid = "@(#) man2html.1 1.2 08/12/97" +.\" +.\" ================================================ +.\" ARGUMENT MACRO: .Ar "arg" [B] +.de Ar +.ie \\$2B \%\fB\\$1\fR +.el \%\fI\\$1\fR +.. +.\" ================================================ +.\" BRACKETED ARGUMENT MACRO: .Br "arg" [B] +.de Br +.ie \\$2B \%[\|\fB\\$1\fR\|] +.el \%[\|\fI\\$1\fR\|] +.. +.\" ================================================ +.\" OPTION FLAG MACRO .Of -x [arg] +.de Of +.ie \\n(.$==1 \%[\|\fB\\$1\fR\|] +.el .if \\n(.$==2 \%[\|\fB\\$1\fR\0\fI\fI\\$2\fR\|] +.. +.\" ================================================ +.\" SYNOPSIS START MACRO +.de Ss .Ss name +.na +.nr aA \w\\$1\\0u +.in +\\n(aAu +'ti -\\n(aAu +.ta \\n(aAu +\&\fB\\$1\fR\t\c +.. +.\" ================================================ +.\" SYNOPSIS END MACRO +.de Se .Se +.ad +.in +.. +.\" ================================================ +.\" +.\" +.TH MAN2HTML 1 "97/08/12" +.SH NAME +.na +man2html \- convert UNIX nroff(1) manual pages to HTML format +.SH SYNOPSIS +.na +.Ss man2html +.Of -bare +.Of -belem name +.Of -botm lines +.Of -cgiurl string +.Of -cgiurlexp expr +.Of -compress +.Of -headmap mapfile +.Of -help +.Of -k +.Of -leftm chars +.Of -nodepage +.Of -noheads +.Of -pgsize lines +.Of -seealso +.Of -solaris +.Of -sun +.Of -title string +.Of -topm lines +.Of -uelem name +.Se +.sp 2 +Typical Usage: +.sp +.Ss man2html +.Of -options +.BI "\0<\0" infile +.BI "\0\0>\0" outfile +.Se +.sp +.B man +.I topic +.B | man2html +.Of -options +.BI "\0>\0" outfile +.\" +.SH DESCRIPTION +.na +The +.B man2html +filter reads formatted nroff text from standard input +.RI ( stdin ) +and writes a \s-1HTML\s+1 document to standard output +.RI ( stdout ). +.LP +The formatted nroff output is surrounded with +.B \s-1
\s+1
+tags with the following exceptions/additions:
+.RS 4n
+.LP
+.na
+'ti -2n
+'ta  2n
+\(bu	Section heads are wrapped in \s-1HTML\s+1
+.I header
+tags.
+See the
+.B "\s-1SECTION\ HEAD\ MAP\ FILE\s+1"
+section below for additional information.
+The
+.B \%-noheads
+option can be used to disable this feature.
+.ad
+.LP
+.na
+'ti -2n
+'ta  2n
+\(bu	Bold words designated by a \%""
+sequences are wrapped in
+.B \s-1\s+1
+tags (or the element specified via the
+.B \%-belem
+option).
+.ad
+.LP
+.na
+'ti -2n
+'ta  2n
+\(bu	Underlined words designated by a \%"_"
+sequences are wrapped in
+.B \s-1\s+1
+tags (or the element specified via the
+.B \%-uelem
+option).
+.ad
+.RE
+.SH OPTIONS
+.na
+.TP 0.5i
+.B -bare
+This option will eliminate \s-1HTML\s+1
+.B \s-1\s+1
+and
+.B \s-1\s+1
+tags from the output.
+This is useful when you wish to incorporate the output into another
+\s-1HTML\s+1 document.
+.TP 0.5i 
+.BI -belem\0 name
+Use
+.I name
+as the name of the element to wrap overstriken characters.
+The default is \fBB\fR.
+.TP 0.5i 
+.BI -botm\0 lines
+The
+.I lines
+argument specifies the number of lines representing the bottom
+margin of the formatted nroff input.
+The line count includes any running footers.
+The default value is 7.
+.TP 0.5i
+.BI -cgiurl\0 string
+The
+.I string
+argument specifies a template \s-1URL\s+1 for creating links to other manpages.
+See the
+.B "\s-1LINKING\ TO\ OTHER\ MANPAGES\s+1"
+section below for additional information.
+.TP 0.5i
+.BI -cgiurlexp\0 expr
+The
+.I expr
+argument specifies a Perl expression evaluting to a \s-1URL\s+1 for
+creating links to other manpages.
+See the
+.B "\s-1LINKING\ TO\ OTHER\ MANPAGES\s+1"
+section below for additional information.
+.TP 0.5i
+.B -compress
+Compress consecutive blank lines into a single line.
+.TP 0.5i
+.BI -headmap\0 mapfile
+The
+.I mapfile
+argument is read to determine which \s-1HTML\s+1
+header tags are to be used for various section heading in the manpage.
+See the
+.B "\s-1SECTION\ HEAD\ MAP\ FILE\s+1"
+section below for information on the format of the map file.
+.TP 0.5i
+.B -help
+Print out a short usage message and then exit immediately.
+.TP 0.5i
+.B -k
+Process input resulting from a manpage keyword search
+.RB ( "man\ -k" ).
+See the
+.B "\s-1KEYWORD\ SEARCH\s+1"
+section below for additional information.
+.TP 0.5i
+.BI -leftm\0 chars
+The
+.I chars
+argument specifies the width of the number of characters making
+up the left margin of the formatted nroff input.
+The default value is 0.
+.TP 0.5i
+.B -nodepage
+By default,
+.B man2html
+merges multi-page formatted nroff into a single page.
+This option may be used to disable depagination, causing
+running headers and footers in the formatted nroff input
+to be carried over into the \s-1HTML\s+1 output.
+.TP 0.5i
+.B -noheads
+By default,
+.B man2html
+wraps section heads in \s-1HTML\s+1
+header tags.
+See the
+.B "\s-1SECTION\ HEAD\ MAP\ FILE\s+1"
+section below for additional information.
+This option may be specified to disabled this feature.
+.TP 0.5i
+.BI -pgsize\0 lines
+The
+.I lines
+argument specifies the number of lines making up the page size (length)
+of the formatted nroff input.
+The default value is 66.
+.TP 0.5i
+.B -seealso
+If the
+.B -cgiurl
+option has been specified, then this option restricts the
+creation of links to other manual pages to the
+.B "\%\s-1SEE\ ALSO\s+1"
+section only.
+.TP 0.5i
+.B -solaris
+If the
+.B -k
+option has been specified, then this option modifies its operation
+to process the alternate manual page keyword search format produced
+by the
+.BR man (1)
+utility on systems running
+.IR Solaris .
+See the
+.B "\s-1KEYWORD\ SEARCH\s+1"
+section below for additional information.
+.TP 0.5i
+.B -sun
+Do not require a section head to have bold overstriking in the
+formatted nroff input.
+The option is called
+.B \%sun
+because it was on a Sun workstation that section heads in
+manpages were found to not be overstruck.
+.TP 0.5i
+.BI -title\0 string
+By default,
+.B man2html
+does not generate a \s-1HTML\s+1 title
+.RB ( \s-1\s+1 ).
+This option sets the title of the \s-1HTML\s+1 output to the specified
+.IR string .
+.TP 0.5i
+.BI -topm\0 lines
+The
+.I lines
+argument specifies number number of lines representing the
+top margin of the formatted nroff input.
+The line count includes any running headers.
+The default value is 7.
+.TP 0.5i 
+.BI -uelem\0 name
+Use
+.I name
+as the name of the element to wrap underscored characters.
+The default is \fBI\fR.
+.\"
+.SH "SECTION HEAD MAP FILE"
+.na
+.LP
+The
+.B \%-headmap
+option may be used to customize which \s-1HTML\s+1 header tags,
+.BR "\s-1<H1>\s+1 ... \s-1<H6>\s+1" ,
+are used in manpage section headings.
+Normally,
+.B man2html
+treats lines that are flush to the left margin
+.RB ( -leftm ),
+and contain overstriking (overstrike check is canceled with the
+.B -sun
+option), as section heads.
+However, you can augment/override what \s-1HTML\s+1 header tags are used for
+any given section head.
+.LP
+In order to write a section head map file, you will need to know about
+.BR perl (1)
+associative arrays.
+You do not need to be an expert in
+.B perl
+to write a map file, however, having knowledge of
+.B perl
+allows you to be more clever.
+.\"
+.SS "Augmenting the Default Map" 
+.LP
+To add to the default mapping defined by
+.BR man2html ,
+your map file will contain lines with the following syntax:
+.sp
+.if t .RS 4n
+.B "$SectionHead{'<section head text>'} = '<html header tag>';"
+.if t .RE
+.sp
+where
+.IP "\fB\%<section\ head\ text>\fR"
+is the text of the manpage section head.
+For example:
+.B  \s-1SYNOPSIS\s+1
+or
+.BR \s-1DESCRIPTION\s+1 .
+.IP "\fB\%<html\ header\ tag>\fR"
+is the \s-1HTML\s+1 header tag to wrap the section head in.
+Legal values are:
+.BR \s-1<H1>\s+1 ,
+.BR \s-1<H2>\s+1 ,
+.BR \s-1<H3>\s+1 ,
+.BR \s-1<H4>\s+1 ,
+.BR \s-1<H5>\s+1 ,
+.BR \s-1<H6>\s+1 .
+.SS "Overriding the Default Map"
+To override the default mapping with your own, then your map file will
+have the following syntax:
+.sp
+.RS 4n
+.ft B
+.nf
+.ne 6v
+%SectionHead = (
+         \&'<section head text>', '<html header tag>',
+         \&'<section head text>', '<html header tag>',
+         \&# ... More section head/tag pairs
+         \&'<section head text>', '<html header tag>',
+);
+.fi
+.ft
+.RE
+.SS "The Default Map"
+.LP
+As of this writing, this is the default map used by
+.BR man2html :
+.RS 4n
+.sp
+.ft C
+.nf
+.ne 29v
+%SectionHead = (
+.ps -1
+    \&'\\S.*OPTIONS.*'             => '<H2>',
+    \&'AUTHORS?'                  => '<H2>',
+    \&'BUGS'                      => '<H2>',
+    \&'COMPATIBILITY'             => '<H2>',
+    \&'DEPENDENCIES'              => '<H2>',
+    \&'DESCRIPTION'               => '<H2>',
+    \&'DIAGNOSTICS'               => '<H2>',
+    \&'ENVIRONMENT'               => '<H2>',
+    \&'ERRORS'                    => '<H2>',
+    \&'EXAMPLES'                  => '<H2>',
+    \&'EXTERNAL INFLUENCES'       => '<H2>',
+    \&'FILES'                     => '<H2>',
+    \&'LIMITATIONS'               => '<H2>',
+    \&'NAME'                      => '<H2>',
+    \&'NOTES?'                    => '<H2>',
+    \&'OPTIONS'                   => '<H2>',
+    \&'REFERENCES'                => '<H2>',
+    \&'RETURN VALUE'              => '<H2>',
+    \&'SECTION.*:'                => '<H2>',
+    \&'SEE ALSO'                  => '<H2>',
+    \&'STANDARDS CONFORMANCE'     => '<H2>',
+    \&'STYLE CONVENTION'          => '<H2>',
+    \&'SYNOPSIS'                  => '<H2>',
+    \&'SYNTAX'                    => '<H2>',
+    \&'WARNINGS'                  => '<H2>',
+    \&'\\s+Section.*:'             => '<H3>',
+.ps +1
+);
+$HeadFallback = '\s-1<H2>\s+1';  # Fallback tag if above is not found.
+.fi
+.ft
+.RE
+.LP
+Check the
+.B perl
+source code of
+.B man2html
+for the latest default mapping.
+.LP 
+You can reassign the
+.B \%$HeadFallback
+variable to a different value if you choose.
+This value is used as the header tag of a section head if
+no matches are found in the \%\fB%SectionHead\fR map.
+.SS "Using Regular Expressions in the Map File"
+.LP
+You may have noticed unusual characters in the default map file, like
+"\\s" or "*".
+The
+.B man2html
+utility actual treats the
+.B "\%<section\ head\ text>"
+as a
+.B perl
+regular expression.
+If you are comfortable with
+.B perl
+regular expressions, then you have their full power to use
+in your map file.
+.LP
+.I Caution:
+The
+.B man2html
+utility already anchors the regular expression to the beginning of the
+line with left margin spacing specified by the
+.B \%-leftm
+option.
+Therefore, do not use the `\fB\fR^' character to anchor your regular
+expression to the beginning.
+However, you may end your expression with a `\fB$\fR' to anchor it to
+the end of the line.
+.LP 
+Since the
+.B "\%<section\ head\ text>"
+is actually a regular expression, you will have to be careful of
+special characters if you want them to be treated literally.
+Any of the characters
+.RB ` "[ ] ( ) . ^ { } $ * ? + \\ |" '
+should be escaped by prefixing them by the
+\&`\fB\\\fR' character if you want
+.B perl
+to treat them "as is".
+.LP
+.I Caution:
+One should use single quotes instead of double quotes to delimit
+.BR "\%<section\ head\ text>" .
+This will preserve any `\fB\\\fR' characters for character escaping
+or when the `\fB\\\fR' is used for special
+.B perl
+character matching sequences (e.g.,  \fB\\s\fR, \fB\\w\fR, \fB\\S\fR).
+.SS "Other Tid-bits on the Map File"
+.LP
+Comments can be inserted in the map file by using the '\fB#\fR'
+character.
+Anything after, and including, the '\fB#\fR' character is ignored,
+up to the end of line.
+.LP 
+You might be thinking that the above is quite-a-bit-of-stuff just for
+doing manpage section heads.
+However, you will be surprised how much better the \s-1HTML\s+1 output looks
+with header tags, even though, everything else is in a
+.B \s-1<PRE>\s+1
+tag.
+.\"
+.SH "LINKING TO OTHER MANPAGES"
+.na
+.LP 
+The
+.B man2html
+utility allows the ability to link to other manpage references.
+If the
+.B \%-cgiurl
+option is specified,
+.B man2html
+will create anchors that link to other manpages.
+.LP 
+The \s-1URL\s+1 entered with the
+.B \%-cgiurl
+option is actually a template that determines the actual \s-1URL\s+1 used to
+link to other manpages.
+The following variables are defined during run time that may be used in
+the template string:
+.sp
+.RS 4n
+.IP \fB$title\fR
+The title of the manual page referenced.
+.IP \fB$section\fR
+The section number of the manual page referenced.
+.IP \fB$subsection\fR
+The subsection of the manual page referenced.
+.RE
+.LP
+Any other text in the template is preserved "as is".
+.LP
+.I Caution:
+The
+.B man2html
+utility evaluates the template string as a
+.B perl
+string expression.
+Therefore, one might need to surround the variable names with
+\&'\fB{\|}\fR' (e.g.,
+.BR ${\|title\|}\| )
+so that
+.B man2html
+properly recognizes the variable.
+.LP
+.I Note:
+If a \s-1CGI\s+1 program calling
+.B man2html
+is actually a shell script or a
+.B perl
+program, make sure to properly escape the '\fB$\fR' character
+in the \s-1URL\s+1 template to avoid variable interpolation by the \s-1CGI\s+1
+program.
+.LP
+Normally, the \s-1URL\s+1 calls a \s-1CGI\s+1 program (hence the option name),
+but the \s-1URL\s+1 can easily link to statically converted documents.
+.SS "Example1:"
+.LP 
+The following template string is specified to call a \s-1CGI\s+1 program to
+retrieve the appropriate manpage linked to:
+.LP
+.nf
+.B "/cgi-bin/man.cgi?section=${section}${subsection}&topic=${title}"
+.fi
+.LP 
+If the
+.BR ls (1)
+manpage is referenced in the
+.B "SEE ALSO"
+section, the above template will translate to the following \s-1URL\s+1:
+.LP
+.B "/cgi-bin/man.cgi?section=1&topic=ls"
+.LP 
+The actual \s-1HTML\s+1 markup will look like the following:
+.LP
+\fB<A\ HREF="/cgi-bin/man.cgi?section=1&topic=ls">ls(1)</A>\fR
+.SS "Example2:"
+.LP 
+The following template string is specified to retrieve pre-converted
+manpages:
+.LP
+.B "http://foo.org/man$section/$title.$section$subsection.html"
+.LP 
+If the
+.BR mount (1M)
+manpage is referenced, the above template will translate to the
+following \s-1URL\s+1:
+.LP
+.B "http://foo.org/man1/mount.1M.html"
+.LP 
+The actual \s-1HTML\s+1 markup will look like the following:
+.LP
+\fB<A HREF="http://foo.org/man1/mount.1M.html">mount(1M)</A>\fR
+.SS "-cgiurlexp"
+The option
+.B \%-cgiurlexp
+is a more general form of the
+.B \%-cgiurl
+option.
+.B \%-cgiurlexp
+allows one to specify a general Perl expression.  For example:
+.LP
+\fB$title=~/^db_/i?"$title.html":"/cgi-bin/man?$title+$section"\fR
+.LP
+A
+.B \%-cgiurl
+.I string
+can be expressed as follows with \fB-cgiurlexp\fR:
+.LP
+\fBreturn "\fIstring\fB"\fR
+.\"
+.SH "KEYWORD SEARCH"
+.na
+.LP
+The
+.B man2html
+utility has the ability to process keyword search output generated
+by the \%\fBman\ -k\fR or \%\fBapropos\fR commands, through the
+use of the
+.B -k
+option.
+The
+.B man2html
+utility will generate an \s-1HTML\s+1 document of the keyword search input
+having the following format:
+.RS 4n 
+.LP
+.na
+'ti -2n
+'ta  2n
+\(bu	All manpage references are listed by section.
+.ad
+.LP
+.na
+'ti -2n
+'ta  2n
+\(bu	Within each section listing, the manpage references
+are sorted alphabetically (case-sensitive) in a
+.B \s-1<DL>\s+1
+tag.
+The manpage references are listed in the
+.B \s-1<DT>\s+1
+section, and the summary text is listed in the
+.B \s-1<DD>\s+1
+section.
+.ad
+.LP
+.na
+'ti -2n
+'ta  2n
+\(bu	Each manpage reference listed is a hyperlink to the
+actual manpage as specified by the
+.B \%-cgiurl
+option.
+.ad
+.RE
+.LP 
+.na
+This ability to process keyword searches gives nice added functionality
+to a \s-1WWW\s+1 forms interface to
+.BR man (1).
+Even if you have statically converted manpages to \s-1HTML\s+1 via another
+man->\s-1HTML\s+1 program, you can use
+.B man2html
+and "\fBman\ -k\fR" to provide keyword search capabilities easily for
+your \s-1HTML\s+1 manpages.
+.SS "Processing Keyword Search Results"
+.na
+.LP 
+Unfortunately, there is no standard controlling the format of keyword
+search results.
+The
+.B man2html
+utility tries it best to handle all the variations.
+However, the keyword search results generated by the
+.I Solaris
+operating system is different enough from other systems that a
+special command-line option
+.RB ( -solaris )
+must be specified to handle its output.
+.SS "Example of raw Solaris-type keyword search results:"
+.LP
+.ft C
+.nf
+.ne 10v
+strcpy        strcpy (9f)  - copy a string from one location to another.
+strcpy        string (3c)  - string operations
+strncpy       strcpy (9f)  - copy a string from one location to another.
+strncpy       string (3c)  - string operations
+.fi
+.ft
+.LP 
+If keyword search results on your systems appear in the following format:
+.LP
+.RS 4n
+.B "<topic>  <actual_manpage> (#) - Description"
+.RE
+.LP
+then you need to specify the
+.B \%-solaris
+option in addition to the
+.B -k
+option.
+.SH "ADDITIONAL NOTES"
+.na
+.LP
+Different systems format manpages differently.
+Here is a list of recommended command-line options for certain systems:
+.RS 4n
+.LP
+.ta 1i
+.nf
+.ne 3v
+\fBConvex\fR:	<defaults should be okay>
+\fBHP\fR:	\fB-leftm 1 -topm 8\fR
+\fBSun\fR:	\fB-sun\fR (and \fB-solaris\fR when using \fB-k\fR)
+.fi
+.RE
+.LP
+Some line spacing gets lost in the formatted nroff since the
+spacing would occur in the middle of a page break.
+This can cause text to be merged that shouldn't be merged when
+.B man2html
+depaginates the text.
+To avoid this problem,
+.B man2html
+keeps track of the margin indent right before and after a page break.
+If the margin width of the line after the page break is less than the
+line before the page break, then
+.B man2html
+inserts a blank line in the \s-1HTML\s+1 output.
+.LP 
+A manpage cross-reference is detected by the following pseudo expression:
+\%\fB[A-z.-+_]+([0-9][A-z]?)\fR
+.LP
+The
+.B man2html
+utility only recognizes lines with "\fB - \fR" (the normal separator
+between manpage references and summary text) while in keyword
+search mode.
+.LP 
+The
+.B man2html
+utility can be hooked in a \s-1CGI\s+1 script/program to convert manpages
+on the fly.
+This is the reason for the
+.B \%-cgiurl
+option.
+.SH LIMITATIONS
+.na
+.LP 
+The order that section head mapping is searched is not defined.
+Therefore, if two or more
+.B "\%<section\ head\ text>"
+can match a give manpage section, there is no way to determine
+which map tag is chosen.
+.LP 
+If
+.B \%-seealso
+is specified, all xrefs are detected after the
+.B "\%SEE\ ALSO"
+heading.
+In other words, sections after
+.B "\%SEE\ ALSO"
+may contain hyperlinked xrefs.
+.SH BUGS
+.na
+.LP 
+Text that is flush to the left margin, but is not actually a
+section head, can be mistaken for a section head.
+This mistake is more likely when the
+.B \%-sun
+option is in affect.
+.SH VERSION
+.na
+This documentation describes
+.B man2html
+version 3.0.1
+.SH "SEE ALSO"
+.na
+.BR man (1),
+.BR nroff (1),
+.BR perl (1)
+.LP
+.I http://www.oac.uci.edu/indiv/ehood/man2html.html
+.SH AUTHOR
+.LP
+.B Earl Hood
+.br
+.I ehood@medusa.acs.uci.edu
+.\"
+.SH "ERRORS AND OMISSIONS"
+.na
+Troff version of this document initially created for version 2.1.0
+by C. Jeffery Small
+.RI ( jeff@cjsa.com )
+by copying, reformatting, rearranging and partially rewriting
+the contents of the ascii text file
+.BR doc/man2html.txt .
diff --git a/mechglue/doc/man2ps b/mechglue/doc/man2ps
new file mode 100755
index 000000000..06240e07c
--- /dev/null
+++ b/mechglue/doc/man2ps
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+com=`basename $0`
+files=$*
+ROFF=groff
+ROFF_FLAGS="-C -man -Tps"
+CSPLIT=
+
+IFS="${IFS= 	}"; save_ifs="$IFS"; IFS="${IFS}:"
+for i in $PATH; do
+  if [ -f $i/gcsplit ]; then
+	CSPLIT=$i/gcsplit
+	break
+  fi
+  if [ -f $i/csplit ]; then
+	CSPLIT=$i/csplit
+	break
+  fi
+done
+IFS="$save_ifs"
+
+if [ "$files" = "" ]; then
+    echo "Usage: $com file [file2 ...]"
+    exit 1
+fi
+
+for file in $files
+do
+    filename=`basename $file | awk -F. '{print $1}'`
+    eval $ROFF $ROFF_FLAGS $file > $filename.ps
+
+    pages=`grep '%%Pages\:' $filename.ps | awk '{print $2}'`
+    pp=`expr $pages - 1`
+
+    echo $filename': '$pages' pages'
+
+    if [ "$CSPLIT"x != x ]; then
+        $CSPLIT -k $filename.ps /Page:/ \{$pp\} > /dev/null
+
+        counter=0
+
+        for number in `ls xx*`
+        do
+            cat xx00 > $filename$counter.ps
+            echo '0.85 dup scale' >> $filename$counter.ps
+            cat $number >> $filename$counter.ps
+            if [ $counter != $pages ];
+                then
+                echo '%%Trailer' >> $filename$counter.ps
+                echo 'end' >> $filename$counter.ps
+                echo '%%EOF' >> $filename$counter.ps
+            fi
+            counter=`expr $counter + 1`
+        done
+
+        rm $filename.ps $filename'0.ps' xx*
+    else
+        echo "Can't find the csplit command.  You'll have to split $filename.ps manually."
+    fi
+done
diff --git a/mechglue/doc/man2ps.M b/mechglue/doc/man2ps.M
new file mode 100644
index 000000000..d9c79032b
--- /dev/null
+++ b/mechglue/doc/man2ps.M
@@ -0,0 +1,50 @@
+.TH MAN2PS 1
+.SH NAME
+man2ps \- create individual PostScript files for each page of a man page
+.SH SYNOPSIS
+.B man2ps
+.I file
+[\fIfile2\fP [\fI...\fP]]
+.SH DESCRIPTION
+.B man2ps
+is a bourne shell script that turns a man page into a set of PostScript
+files, for inclusion in a document.
+.B man2ps
+converts the man page to a PostScript file using
+.IR groff (1), 
+and then uses the
+.IR csplit (1)
+command to split the file into individual pages.
+.B man2ps
+inserts the PostScript command:
+.sp
+.nf
+.in +.5i
+\&0.85 dup scale
+.in -.5i
+.fi
+.sp
+at the beginning of each page, so that the pages will fit onto an
+8.5"x11" page.
+.PP
+The files created by
+.B man2ps
+have the same name as the command, with a sequential number and the
+string ".ps" appended.  For example, running
+.B man2ps
+on the file "kinit.M" would produce the PostScript files "kinit1.ps",
+"kinit2.ps", ...
+.SH SEE ALSO
+troff(1), csplit(1)
+.SH BUGS
+.B man2ps
+requires the user to have
+.I groff
+and either
+.I csplit
+or
+.I gcsplit
+in her path.
+.SH AUTHORS
+.B man2ps
+was written by Jeff Bigler at Cygnus Support and Theodore Ts'o at MIT.
diff --git a/mechglue/doc/old-V4-docs/.Sanitize b/mechglue/doc/old-V4-docs/.Sanitize
new file mode 100644
index 000000000..d36248c95
--- /dev/null
+++ b/mechglue/doc/old-V4-docs/.Sanitize
@@ -0,0 +1,36 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+README
+installation.PS
+installation.mss
+operation.PS
+operation.mss
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/doc/old-V4-docs/README b/mechglue/doc/old-V4-docs/README
new file mode 100644
index 000000000..8858655cb
--- /dev/null
+++ b/mechglue/doc/old-V4-docs/README
@@ -0,0 +1,4 @@
+These documentation files are old --- and refer to the Kerberos V4 
+implementation.  They are included because the equivalent V5 documentation
+set have not been written yet, and the concepts contained in these documents
+may be helpful.
diff --git a/mechglue/doc/old-V4-docs/installation.PS b/mechglue/doc/old-V4-docs/installation.PS
new file mode 100644
index 000000000..7609d4e64
--- /dev/null
+++ b/mechglue/doc/old-V4-docs/installation.PS
@@ -0,0 +1,2338 @@
+%!PS-Adobe-2.0
+%%Title: installation.mss
+%%DocumentFonts: (atend)
+%%Creator: John T Kohl,,E40-351M,31510,6176432831 and Scribe 7(1700)
+%%CreationDate: 4 January 1990 11:56
+%%Pages: (atend)
+%%EndComments
+% PostScript Prelude for Scribe.
+/BS {/SV save def 0.0 792.0 translate .01 -.01 scale} bind def
+/ES {showpage SV restore} bind def
+/SC {setrgbcolor} bind def
+/FMTX matrix def
+/RDF {WFT SLT 0.0 eq 
+  {SSZ 0.0 0.0 SSZ neg 0.0 0.0 FMTX astore}
+  {SSZ 0.0 SLT neg sin SLT cos div SSZ mul SSZ neg 0.0 0.0 FMTX astore}
+  ifelse makefont setfont} bind def
+/SLT 0.0 def
+/SI { /SLT exch cvr def RDF} bind def
+/WFT /Courier findfont def
+/SF { /WFT exch findfont def RDF} bind def
+/SSZ 1000.0 def
+/SS { /SSZ exch 100.0 mul def RDF} bind def
+/AF { /WFT exch findfont def /SSZ exch 100.0 mul def RDF} bind def
+/MT /moveto load def
+/XM {currentpoint exch pop moveto} bind def
+/UL {gsave newpath moveto dup 2.0 div 0.0 exch rmoveto
+   setlinewidth 0.0 rlineto stroke grestore} bind def
+/LH {gsave newpath moveto setlinewidth
+   0.0 rlineto
+   gsave stroke grestore} bind def
+/LV {gsave newpath moveto setlinewidth
+   0.0 exch rlineto
+   gsave stroke grestore} bind def
+/BX {gsave newpath moveto setlinewidth
+   exch
+   dup 0.0 rlineto
+   exch 0.0 exch neg rlineto
+   neg 0.0 rlineto
+   closepath
+   gsave stroke grestore} bind def
+/BX1 {grestore} bind def
+/BX2 {setlinewidth 1 setgray stroke grestore} bind def
+/PB {/PV save def newpath translate
+    100.0 -100.0 scale pop /showpage {} def} bind def
+/PE {PV restore} bind def
+/GB {/PV save def newpath translate rotate
+    div dup scale 100.0 -100.0 scale /showpage {} def} bind def
+/GE {PV restore} bind def
+/FB {dict dup /FontMapDict exch def begin} bind def
+/FM {cvn exch cvn exch def} bind def
+/FE {end /original-findfont /findfont load def  /findfont
+   {dup FontMapDict exch known{FontMapDict exch get} if
+   original-findfont} def} bind def
+/BC {gsave moveto dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath clip} bind def
+/EC /grestore load def
+/SH /show load def
+/MX {exch show 0.0 rmoveto} bind def
+/W {0 32 4 -1 roll widthshow} bind def
+/WX {0 32 5 -1 roll widthshow 0.0 rmoveto} bind def
+/RC {100.0 -100.0 scale
+612.0 0.0 translate
+-90.0 rotate
+.01 -.01 scale} bind def
+/URC {100.0 -100.0 scale
+90.0 rotate
+-612.0 0.0 translate
+.01 -.01 scale} bind def
+/RCC {100.0 -100.0 scale
+0.0 -792.0 translate 90.0 rotate
+.01 -.01 scale} bind def
+/URCC {100.0 -100.0 scale
+-90.0 rotate 0.0 792.0 translate
+.01 -.01 scale} bind def
+%%EndProlog
+%%Page: 0 1
+BS
+0 SI
+20 /Times-Bold AF
+18823 13788 MT
+(Kerberos Installation Notes)SH
+27156 15798 MT
+(DRAFT)SH
+16 /Times-Roman AF
+27021 23502 MT
+(Bill Bryant)SH
+25557 25150 MT
+(Jennifer Steiner)SH
+27289 26798 MT
+(John Kohl)SH
+23957 30444 MT
+(Project Athena, MIT)SH
+/Times-Bold SF
+19489 36042 MT
+(Initial Release, January 24, 1989)SH
+/Times-Italic SF
+17558 37690 MT
+(\050plus later patches through patchlevel 7\051)SH
+11 /Times-Roman AF
+7200 45644 MT
+(The release consists of three parts.)SH
+7200 47942 MT
+(The first part consists of the core Kerberos system, which was developed at MIT and does not require)SH
+7200 49138 MT
+(additional licenses for us to distribute.  Included in this part are the Kerberos authentication server, the)SH
+7200 50334 MT
+(Kerberos library, the)SH
+/Times-Italic SF
+16606 XM
+(ndbm)SH
+/Times-Roman SF
+19325 XM
+(database interface library, user programs, administration programs, manual)SH
+7200 51530 MT
+(pages, some applications which use Kerberos for authentication, and some utilities.)SH
+7200 53828 MT
+(The second part is the Data Encryption Standard \050DES\051 library, which we are distributing only within the)SH
+7200 55024 MT
+(United States.)SH
+7200 57322 MT
+(The third part contains Kerberos modifications to Sun's NFS, which we distribute as ``context diffs'' to)SH
+7200 58518 MT
+(the Sun NFS source code.  Its distribution is controlled to provide an accounting of who has retrieved the)SH
+7200 59714 MT
+(patches, so that Project Athena can comply with its agreements with Sun regarding distribution of these)SH
+7200 60910 MT
+(changes.)SH
+ES
+%%Page: 1 2
+BS
+0 SI
+16 /Times-Bold AF
+7200 8272 MT
+(1. Organization)
+400 W( of the Source Directory)SH
+11 /Times-Roman AF
+7200 10467 MT
+(The Kerberos building and installation process, as described in this document, builds the binaries and)SH
+7200 11663 MT
+(executables from the files contained in the Kerberos source tree, and deposits them in a separate object)SH
+7200 12859 MT
+(tree. This)
+275 W( is intended to easily support several different build trees from a single source tree \050this is useful)SH
+7200 14055 MT
+(if you support several machine architectures\051.  We suggest that you copy the Kerberos sources into a)SH
+/Times-Italic SF
+7200 15251 MT
+(/mit/kerberos/src)SH
+/Times-Roman SF
+14991 XM
+(directory, and create as well a)SH
+/Times-Italic SF
+28396 XM
+(/mit/kerberos/obj)SH
+/Times-Roman SF
+36249 XM
+(directory in which to hold the)SH
+7200 16447 MT
+(executables. In)
+275 W( the rest of this document, we'll refer to the Kerberos source and object directories as)SH
+7200 17643 MT
+([SOURCE_DIR] and [OBJ_DIR], respectively.)SH
+7200 19941 MT
+(Below is a brief overview of the organization of the complete source directory.  More detailed)SH
+7200 21137 MT
+(descriptions follow.)SH
+/Times-Bold SF
+7200 23088 MT
+(admin)SH
+/Times-Roman SF
+18200 XM
+(utilities for the Kerberos administrator)SH
+/Times-Bold SF
+7200 24783 MT
+(appl)SH
+/Times-Roman SF
+18200 XM
+(applications that use Kerberos)SH
+/Times-Bold SF
+7200 26478 MT
+(appl/bsd)SH
+/Times-Roman SF
+18200 XM
+(Berkeley's rsh/rlogin suite, using Kerberos)SH
+/Times-Bold SF
+7200 28173 MT
+(appl/knetd)SH
+/Times-Roman SF
+18200 XM
+(\050old\051 software for inetd-like multiplexing of a single TCP listening port)SH
+/Times-Bold SF
+7200 29868 MT
+(appl/sample)SH
+/Times-Roman SF
+18200 XM
+(sample application servers and clients)SH
+/Times-Bold SF
+7200 31563 MT
+(appl/tftp)SH
+/Times-Roman SF
+18200 XM
+(Trivial File Transfer Protocol, using Kerberos)SH
+/Times-Bold SF
+7200 33258 MT
+(include)SH
+/Times-Roman SF
+18200 XM
+(include files)SH
+/Times-Bold SF
+7200 34953 MT
+(kadmin)SH
+/Times-Roman SF
+18200 XM
+(remote administrative interface to the Kerberos master database)SH
+/Times-Bold SF
+7200 36648 MT
+(kuser)SH
+/Times-Roman SF
+18200 XM
+(assorted user programs)SH
+/Times-Bold SF
+7200 38343 MT
+(lib)SH
+/Times-Roman SF
+18200 XM
+(libraries for use with/by Kerberos)SH
+/Times-Bold SF
+7200 40038 MT
+(lib/acl)SH
+/Times-Roman SF
+18200 XM
+(Access Control List library)SH
+/Times-Bold SF
+7200 41733 MT
+(lib/des)SH
+/Times-Roman SF
+18200 XM
+(Data Encryption Standard library \050US only\051)SH
+/Times-Bold SF
+7200 43428 MT
+(lib/kadm)SH
+/Times-Roman SF
+18200 XM
+(administrative interface library)SH
+/Times-Bold SF
+7200 45123 MT
+(lib/kdb)SH
+/Times-Roman SF
+18200 XM
+(Kerberos server library interface to)SH
+/Times-Italic SF
+33925 XM
+(ndbm)SH
+/Times-Bold SF
+7200 46818 MT
+(lib/knet)SH
+/Times-Roman SF
+18200 XM
+(\050old\051 library for use with)SH
+/Times-Bold SF
+29349 XM
+(knetd)SH
+7200 48513 MT
+(lib/krb)SH
+/Times-Roman SF
+18200 XM
+(Kerberos library)SH
+/Times-Bold SF
+7200 50208 MT
+(man)SH
+/Times-Roman SF
+18200 XM
+(manual pages)SH
+/Times-Bold SF
+7200 51903 MT
+(prototypes)SH
+/Times-Roman SF
+18200 XM
+(sample configuration files)SH
+/Times-Bold SF
+7200 53598 MT
+(server)SH
+/Times-Roman SF
+18200 XM
+(the authentication server)SH
+/Times-Bold SF
+7200 55293 MT
+(slave)SH
+/Times-Roman SF
+18200 XM
+(Kerberos slave database propagation software)SH
+/Times-Bold SF
+7200 56988 MT
+(tools)SH
+/Times-Roman SF
+18200 XM
+(shell scripts for maintaining the source tree)SH
+/Times-Bold SF
+7200 58683 MT
+(util)SH
+/Times-Roman SF
+18200 XM
+(utilities)SH
+/Times-Bold SF
+7200 60378 MT
+(util/imake)SH
+/Times-Roman SF
+18200 XM
+(Imakefile-to-Makefile ``compilation'' tool)SH
+/Times-Bold SF
+7200 62073 MT
+(util/ss)SH
+/Times-Roman SF
+18200 XM
+(Sub-system library \050for command line subsystems\051)SH
+/Times-Bold SF
+7200 63768 MT
+(util/et)SH
+/Times-Roman SF
+18200 XM
+(Error-table library \050for independent, unique error codes\051)SH
+/Times-Bold SF
+7200 65463 MT
+(util/makedepend)SH
+/Times-Roman SF
+18200 XM
+(Makefile dependency generator tool)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(1)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 2 3
+BS
+0 SI
+14 /Times-Bold AF
+7200 8167 MT
+(1.1 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(admin)SH
+/Times-Bold SF
+16340 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 10362 MT
+(This directory contains source for the Kerberos master database administration tools.)SH
+/Times-Bold SF
+7200 12313 MT
+(kdb_init)SH
+/Times-Roman SF
+18200 XM
+(This program creates and initializes the Kerberos master database.  It prompts)SH
+18200 13509 MT
+(for a Kerberos realmname, and the Kerberos master password.)SH
+/Times-Bold SF
+7200 15204 MT
+(kstash)SH
+/Times-Roman SF
+18200 XM
+(This program ``stashes'' the master password in the file)SH
+/Times-Italic SF
+43033 XM
+(/.k)SH
+/Times-Roman SF
+44377 XM
+(so that the master)SH
+18200 16400 MT
+(server machine can restart the Kerberos server automatically after an unattended)SH
+18200 17596 MT
+(reboot. The)
+275 W( hidden password is also available to administrative programs that)SH
+18200 18792 MT
+(have been set to run automatically.)SH
+/Times-Bold SF
+7200 20487 MT
+(kdb_edit)SH
+/Times-Roman SF
+18200 XM
+(This program is a low-level tool for editing the master database.)SH
+/Times-Bold SF
+7200 22182 MT
+(kdb_destroy)SH
+/Times-Roman SF
+18200 XM
+(This program deletes the master database.)SH
+/Times-Bold SF
+7200 23877 MT
+(kdb_util)SH
+/Times-Roman SF
+18200 XM
+(This program can be used to dump the master database into an ascii file, and can)SH
+18200 25073 MT
+(also be used to load the ascii file into the master database.)SH
+/Times-Bold SF
+7200 26768 MT
+(ext_srvtab)SH
+/Times-Roman SF
+18200 XM
+(This program extracts information from the master database and creates a host-)SH
+18200 27964 MT
+(dependent)SH
+/Times-Italic SF
+22995 XM
+(srvtab)SH
+/Times-Roman SF
+26020 XM
+(file. This)
+275 W( file contains the Kerberos keys for the host's)SH
+18200 29160 MT
+(``Kerberized'' services.  These services look up their keys in the)SH
+/Times-Italic SF
+46846 XM
+(srvtab)SH
+/Times-Roman SF
+49871 XM
+(file for)SH
+18200 30356 MT
+(use in the authentication process.)SH
+14 /Times-Bold AF
+7200 34203 MT
+(1.2 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(kuser)SH
+/Times-Bold SF
+15874 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 36398 MT
+(This directory contains the source code for several user-oriented programs.)SH
+/Times-Bold SF
+7200 38349 MT
+(kinit)SH
+/Times-Roman SF
+18200 XM
+(This program prompts users for their usernames and Kerberos passwords, then)SH
+18200 39545 MT
+(furnishes them with Kerberos ticket-granting tickets.)SH
+/Times-Bold SF
+7200 41240 MT
+(kdestroy)SH
+/Times-Roman SF
+18200 XM
+(This program destroys any active tickets.  Users should use)SH
+/Times-Italic SF
+44563 XM
+(kdestroy)SH
+/Times-Roman SF
+48564 XM
+(before they)SH
+18200 42436 MT
+(log off their workstations.)SH
+/Times-Bold SF
+7200 44131 MT
+(klist)SH
+/Times-Roman SF
+18200 XM
+(This program lists a user's active tickets.)SH
+/Times-Bold SF
+7200 45826 MT
+(ksrvtgt)SH
+/Times-Roman SF
+18200 XM
+(This retrieves a ticket-granting ticket with a life time of five minutes, using a)SH
+18200 47022 MT
+(server's secret key in lieu of a password.  It is primarily for use in shell scripts)SH
+18200 48218 MT
+(and other batch facilities.)SH
+/Times-Bold SF
+7200 49913 MT
+(ksu)SH
+/Times-Roman SF
+18200 XM
+(Substitute user id, using Kerberos to mediate attempts to change to ``root''.)SH
+14 /Times-Bold AF
+7200 53760 MT
+(1.3 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(appl)SH
+/Times-Bold SF
+15173 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 55955 MT
+(If your site has the appropriate BSD license, your Kerberos release provides certain Unix utilities The)SH
+7200 57151 MT
+(Berkeley programs that have been modified to use Kerberos authentication are found in the)SH
+/Times-Italic SF
+47640 XM
+(appl/bsd)SH
+/Times-Roman SF
+7200 58347 MT
+(directory. They)
+275 W( include)SH
+/Times-Italic SF
+18043 XM
+(login)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+20855 XM
+(rlogin)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+24095 XM
+(rsh)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+27914 XM
+(rcp)SH
+/Times-Roman SF
+(, as well as the associated daemon programs)SH
+/Times-Italic SF
+49081 XM
+(kshd)SH
+/Times-Roman SF
+51372 XM
+(and)SH
+/Times-Italic SF
+7200 59543 MT
+(klogind)SH
+/Times-Roman SF
+(. The)275 W
+/Times-Italic SF
+13310 XM
+(login)SH
+/Times-Roman SF
+15847 XM
+(program obtains ticket-granting tickets for users upon login; the other utilities provide)SH
+7200 60739 MT
+(authenticated Unix network services.)SH
+7200 63037 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(appl)SH
+/Times-Roman SF
+11416 XM
+(directory also contains samples Kerberos application client and server programs, an)SH
+7200 64233 MT
+(authenticated)SH
+/Times-Italic SF
+13339 XM
+(tftp)SH
+/Times-Roman SF
+15082 XM
+(program,)SH
+/Times-Italic SF
+19358 XM
+(knetd)SH
+/Times-Roman SF
+(, an authenticated inet daemon.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(2)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 3 4
+BS
+0 SI
+14 /Times-Bold AF
+7200 8167 MT
+(1.4 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(server)SH
+/Times-Bold SF
+16185 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 10362 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(server)SH
+/Times-Roman SF
+12208 XM
+(directory contains the Kerberos KDC server, called)SH
+/Times-Italic SF
+35052 XM
+(kerberos)SH
+/Times-Roman SF
+(. This)
+275 W( program manages read-)SH
+7200 11558 MT
+(only requests made to the master database, distributing tickets and encryption keys to clients requesting)SH
+7200 12754 MT
+(authentication service.)SH
+14 /Times-Bold AF
+7200 16601 MT
+(1.5 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(kadmin)SH
+/Times-Bold SF
+17040 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 18796 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(kadmin)SH
+/Times-Roman SF
+12698 XM
+(directory contains the Kerberos administration server and associated client programs.  The)SH
+7200 19992 MT
+(server accepts network requests from the user program)SH
+/Times-Italic SF
+31570 XM
+(kpasswd)SH
+/Times-Roman SF
+35573 XM
+(\050used to change a user's password\051, the)SH
+7200 21188 MT
+(Kerberos administration program)SH
+/Times-Italic SF
+22137 XM
+(kadmin)SH
+/Times-Roman SF
+(, and the srvtab utility program)SH
+/Times-Italic SF
+39276 XM
+(ksrvutil)SH
+/Times-Roman SF
+(. The)
+275 W( administration)SH
+7200 22384 MT
+(server can make modifications to the master database.)SH
+14 /Times-Bold AF
+7200 26231 MT
+(1.6 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(include)SH
+/Times-Bold SF
+16962 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 28426 MT
+(This directory contains the)SH
+/Times-Italic SF
+19236 XM
+(include)SH
+/Times-Roman SF
+22749 XM
+(files needed to build the Kerberos system.)SH
+14 /Times-Bold AF
+7200 32273 MT
+(1.7 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(lib)SH
+/Times-Bold SF
+14162 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 34468 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(lib)SH
+/Times-Roman SF
+10622 XM
+(directory has six subdirectories:)SH
+/Times-Italic SF
+25193 XM
+(acl)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+27087 XM
+(des)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+29103 XM
+(kadm)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+32035 XM
+(kdb)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+34173 XM
+(knet)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+38418 XM
+(krb)SH
+/Times-Roman SF
+(. The)275 W
+/Times-Italic SF
+42694 XM
+(des)SH
+/Times-Roman SF
+44435 XM
+(directory contains)SH
+7200 35664 MT
+(source for the DES encryption library.  The)SH
+/Times-Italic SF
+26595 XM
+(kadm)SH
+/Times-Roman SF
+29252 XM
+(directory contains source for the Kerberos)SH
+7200 36860 MT
+(administration server utility library.  The)SH
+/Times-Italic SF
+25439 XM
+(kdb)SH
+/Times-Roman SF
+27302 XM
+(directory contains source for the Kerberos database routine)SH
+7200 38056 MT
+(library. The)275 W
+/Times-Italic SF
+12942 XM
+(knet)SH
+/Times-Roman SF
+15049 XM
+(directory contains source for a library used by clients of the)SH
+/Times-Italic SF
+41530 XM
+(knetd)SH
+/Times-Roman SF
+44187 XM
+(server. The)275 W
+/Times-Italic SF
+49683 XM
+(krb)SH
+/Times-Roman SF
+7200 39252 MT
+(directory contains source for the)SH
+/Times-Italic SF
+21707 XM
+(libkrb.a)SH
+/Times-Roman SF
+25435 XM
+(library. This)
+275 W( library contains routines that are used by the)SH
+7200 40448 MT
+(Kerberos server program, and by applications programs that require authentication service.)SH
+14 /Times-Bold AF
+7200 44295 MT
+(1.8 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(man)SH
+/Times-Bold SF
+15251 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 46490 MT
+(This directory contains manual pages for Kerberos programs and library routines.)SH
+14 /Times-Bold AF
+7200 50337 MT
+(1.9 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(prototypes)SH
+/Times-Bold SF
+18596 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 52532 MT
+(This directory contains prototype)SH
+/Times-Italic SF
+22108 XM
+(/etc/services)SH
+/Times-Roman SF
+27819 XM
+(and)SH
+/Times-Italic SF
+29682 XM
+(/etc/krb.conf)SH
+/Times-Roman SF
+35486 XM
+(files. New)
+275 W( entries must be added to the)SH
+/Times-Italic SF
+7200 53728 MT
+(/etc/services)SH
+/Times-Roman SF
+12911 XM
+(file for the Kerberos server, and possibly for Kerberized applications \050)SH
+/Times-Italic SF
+(services.append)SH
+/Times-Roman SF
+7200 54924 MT
+(contains the entries used by the Athena-provided servers & applications, and is suitable for appending to)SH
+7200 56120 MT
+(your existing)SH
+/Times-Italic SF
+13250 XM
+(/etc/services)SH
+/Times-Roman SF
+18961 XM
+(file.\051. The)275 W
+/Times-Italic SF
+23878 XM
+(/etc/krb.conf)SH
+/Times-Roman SF
+29682 XM
+(file defines the local Kerberos realm for its host and)SH
+7200 57316 MT
+(lists Kerberos servers for given realms.  The)SH
+/Times-Italic SF
+26961 XM
+(/etc/krb.realms)SH
+/Times-Roman SF
+33865 XM
+(file defines exceptions for mapping machine)SH
+7200 58512 MT
+(names to Kerberos realms.)SH
+14 /Times-Bold AF
+7200 62359 MT
+(1.10 The)350 W
+/Times-BoldItalic SF
+13034 XM
+(tools)SH
+/Times-Bold SF
+16107 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 64554 MT
+(This directory contains a makefile to set up a directory tree for building the software in, and a shell script)SH
+7200 65750 MT
+(to format code in the style we use.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(3)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 4 5
+BS
+0 SI
+14 /Times-Bold AF
+7200 8167 MT
+(1.11 The)350 W
+/Times-BoldItalic SF
+13034 XM
+(util)SH
+/Times-Bold SF
+15329 XM
+(Directory)SH
+11 /Times-Roman AF
+7200 10362 MT
+(This directory contains several utility programs and libraries.  Included are Larry Wall's)SH
+/Times-Italic SF
+46296 XM
+(patch)SH
+/Times-Roman SF
+49015 XM
+(program, a)SH
+/Times-Italic SF
+7200 11558 MT
+(make)SH
+/Times-Roman SF
+9795 XM
+(pre-processor program called)SH
+/Times-Italic SF
+22956 XM
+(imake)SH
+/Times-Roman SF
+(, and a program for generating Makefile dependencies,)SH
+/Times-Italic SF
+7200 12754 MT
+(makedepend)SH
+/Times-Roman SF
+(, as well as the Sub-system library and utilities \050)SH
+/Times-Italic SF
+(ss)SH
+/Times-Roman SF
+(\051, and the Error table library and utilities)SH
+7200 13950 MT
+(\050)SH
+/Times-Italic SF
+(et)SH
+/Times-Roman SF
+(\051.)SH
+16 /Times-Bold AF
+7200 18622 MT
+(2. Preparing)
+400 W( for Installation)SH
+11 /Times-Roman AF
+7200 20817 MT
+(This document assumes that you will build the system on the machine on which you plan to install the)SH
+7200 22013 MT
+(Kerberos master server and its database.  You'll need about 10 megabytes for source and executables.)SH
+7200 24311 MT
+(By default, there must be a)SH
+/Times-Italic SF
+19327 XM
+(/kerberos)SH
+/Times-Roman SF
+23756 XM
+(directory on the master server machine in which to store the)SH
+7200 25507 MT
+(Kerberos database files.  If the master server machine does not have room on its root partition for these)SH
+7200 26703 MT
+(files, create a)SH
+/Times-Italic SF
+13306 XM
+(/kerberos)SH
+/Times-Roman SF
+17735 XM
+(symbolic link to another file system.)SH
+16 /Times-Bold AF
+7200 31375 MT
+(3. Preparing)
+400 W( for the Build)SH
+11 /Times-Roman AF
+7200 33570 MT
+(Before you build the system, you have to choose a)SH
+/Times-Bold SF
+29653 XM
+(realm name)SH
+/Times-Roman SF
+(, the name that specifies the system's)SH
+7200 34766 MT
+(administrative domain.  Project Athena uses the internet domain name ATHENA.MIT.EDU to specify its)SH
+7200 35962 MT
+(Kerberos realm name.  We recommend using a name of this form.)SH
+/Times-Bold SF
+36857 XM
+(NOTE:)SH
+/Times-Roman SF
+40616 XM
+(the realm-name is case)SH
+7200 37158 MT
+(sensitive; by convention, we suggest that you use your internet domain name, in capital letters.)SH
+7200 39456 MT
+(Edit the [SOURCE_DIR]/)SH
+/Times-Italic SF
+(include/krb.h)SH
+/Times-Roman SF
+24860 XM
+(file and look for the following lines of code:)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(4)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 5 6
+BS
+0 SI
+11 /Courier AF
+8520 7886 MT
+(/*)SH
+9180 9000 MT
+(* Kerberos specific definitions)SH
+9180 10114 MT
+(*)SH
+9180 11228 MT
+(* KRBLOG is the log file for the kerberos master server.)SH
+9180 12342 MT
+(* KRB_CONF is the configuration file where different host)SH
+9180 13456 MT
+(* machines running master and slave servers can be found.)SH
+9180 14570 MT
+(* KRB_MASTER is the name of the machine with the master)SH
+9180 15684 MT
+(* database.  The admin_server runs on this machine, and all)SH
+9180 16798 MT
+(* changes to the db \050as opposed to read-only requests, which)SH
+9180 17912 MT
+(* can go to slaves\051 must go to it.)SH
+9180 19026 MT
+(* KRB_HOST is the default machine when looking for a kerberos)SH
+9180 20140 MT
+(* slave server.  Other possibilities are in the KRB_CONF file.)SH
+9180 21254 MT
+(* KRB_REALM is the name of the realm.)SH
+9180 22368 MT
+(*/)SH
+8520 24596 MT
+(#ifdef notdef)SH
+8520 25710 MT
+(this is server-only, does not belong here;)SH
+8520 26824 MT
+(#define KRBLOG)
+3960 W( "/kerberos/kerberos.log")5940 W
+8520 27938 MT
+(are these used anyplace '?';)SH
+8520 29052 MT
+(#define VX_KRB_HSTFILE)
+9240 W( "/etc/krbhst")660 W
+8520 30166 MT
+(#define PC_KRB_HSTFILE)
+9240 W( "\134\134kerberos\134\134krbhst")660 W
+8520 31280 MT
+(#endif)SH
+8520 33508 MT
+(#define KRB_CONF)
+9240 W( "/etc/krb.conf")4620 W
+8520 34622 MT
+(#define KRB_RLM_TRANS)
+9240 W( "/etc/krb.realms")1320 W
+8520 35736 MT
+(#define KRB_MASTER)
+9240 W( "kerberos")3300 W
+8520 36850 MT
+(#define KRB_HOST)
+9240 W( KRB_MASTER)5280 W
+8520 37964 MT
+(#define KRB_REALM)
+9240 W( "ATHENA.MIT.EDU")3960 W
+/Times-Roman SF
+7200 39559 MT
+(Edit the last line as follows:)SH
+9400 41510 MT
+(1.)SH
+10500 XM
+(Change the KRB_REALM definition so that it specifies the realm name you have chosen)SH
+10500 42706 MT
+(for your Kerberos system.  This is a default which is usually overridden by a configuration)SH
+10500 43902 MT
+(file on each machine; however, if that config file is absent, many programs will use this)SH
+10500 45098 MT
+("built-in" realm name.)SH
+14 /Times-Bold AF
+7200 48945 MT
+(3.1 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(/etc/krb.conf)SH
+/Times-Bold SF
+19956 XM
+(File)SH
+11 /Times-Roman AF
+7200 51140 MT
+(Create a)SH
+/Times-Italic SF
+11108 XM
+(/etc/krb.conf)SH
+/Times-Roman SF
+16912 XM
+(file using the following format:)SH
+/Times-BoldItalic SF
+8520 52740 MT
+(realm_name)SH
+8520 53854 MT
+(realm_name master_server_name)1045 W
+/Courier SF
+25594 XM
+(admin server)SH
+/Times-Roman SF
+7200 55449 MT
+(where)SH
+/Times-Italic SF
+10161 XM
+(realm_name)SH
+/Times-Roman SF
+15934 XM
+(specifies the system's realm name, and)SH
+/Times-Italic SF
+33375 XM
+(master_server_name)SH
+/Times-Roman SF
+42874 XM
+(specifies the machine)SH
+7200 56645 MT
+(name on which you will run the master server.  The words 'admin server' must appear next to the name of)SH
+7200 57841 MT
+(the server on which you intend to run the administration server \050which must be a machine with access to)SH
+7200 59037 MT
+(the database\051.)SH
+7200 61335 MT
+(For example, if your realm name is)SH
+/Times-Italic SF
+22962 XM
+(tim.edu)SH
+/Times-Roman SF
+26506 XM
+(and your master server's name is)SH
+/Times-Italic SF
+41288 XM
+(kerberos.tim.edu)SH
+/Times-Roman SF
+(, the file)SH
+7200 62531 MT
+(should have these contents:)SH
+/Courier SF
+8520 64057 MT
+(tim.edu)SH
+8520 65171 MT
+(tim.edu kerberos.tim.edu)
+660 W( admin server)SH
+/Times-Roman SF
+7200 67469 MT
+(See the [SOURCE_DIR]/)SH
+/Times-Italic SF
+(prototypes/etc.krb.conf)SH
+/Times-Roman SF
+28921 XM
+(file for an example)SH
+/Times-Italic SF
+37533 XM
+(/etc/krb.conf)SH
+/Times-Roman SF
+43337 XM
+(file. That)
+275 W( file has)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(5)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 6 7
+BS
+0 SI
+11 /Times-Roman AF
+7200 7955 MT
+(examples of how to provide backup servers for a given realm \050additional lines with the same leading)SH
+7200 9151 MT
+(realm name\051 and how to designate servers for remote realms.)SH
+14 /Times-Bold AF
+7200 12998 MT
+(3.2 The)350 W
+/Times-BoldItalic SF
+12334 XM
+(/etc/krb.realms)SH
+/Times-Bold SF
+21280 XM
+(File)SH
+11 /Times-Roman AF
+7200 15193 MT
+(In many situations, the default realm in which a host operates will be identical to the domain portion its)SH
+7200 16389 MT
+(Internet domain name.)SH
+7200 18687 MT
+(If this is not the case, you will need to establish a translation from host name or domain name to realm)SH
+7200 19883 MT
+(name. This)
+275 W( is accomplished with the)SH
+/Times-Italic SF
+23820 XM
+(/etc/krb.realms)SH
+/Times-Roman SF
+30724 XM
+(file.)SH
+7200 22181 MT
+(Each line of the translation file specifies either a hostname or domain name, and its associated realm:)SH
+/Courier SF
+8520 23707 MT
+(.domain.name kerberos.realm1)SH
+8520 24821 MT
+(host.name kerberos.realm2)SH
+/Times-Roman SF
+7200 26416 MT
+(For example, to map all hosts in the domain LSC.TIM.EDU to KRB.REALM1 but the host)SH
+7200 27612 MT
+(FILMS.LSC.TIM.EDU to KRB.REALM2 your file would read:)SH
+/Courier SF
+8520 29138 MT
+(.LSC.TIM.EDU KRB.REALM1)SH
+8520 30252 MT
+(FILMS.LSC.TIM.EDU KRB.REALM2)SH
+/Times-Roman SF
+7200 31847 MT
+(If a particular host matches both a domain and a host entry, the host entry takes precedence.)SH
+16 /Times-Bold AF
+7200 36519 MT
+(4. Building)
+400 W( the Software)SH
+11 /Times-Roman AF
+7200 38714 MT
+(Before you build the software read the)SH
+/Times-Bold SF
+24395 XM
+(README)SH
+/Times-Roman SF
+29558 XM
+(file in [SOURCE_DIR].  What follows is a more)SH
+7200 39910 MT
+(detailed description of the instructions listed in README.)SH
+9400 41861 MT
+(1.)SH
+10500 XM
+(Create an [OBJ_DIR] directory to hold the tree of Kerberos object files you are about to)SH
+10500 43057 MT
+(build, for example,)SH
+/Times-Italic SF
+19145 XM
+(/mit/kerberos/obj)SH
+/Times-Roman SF
+(.)SH
+9400 44951 MT
+(2.)SH
+10500 XM
+(Change directory to [OBJ_DIR].  The following command creates directories under)SH
+10500 46147 MT
+([OBJ_DIR] and installs Makefiles for the final build.)SH
+/Courier SF
+11820 47724 MT
+(host%)SH
+/Times-Bold SF
+15780 XM
+(make -f [SOURCE_DIR]/tools/makeconfig SRCDIR=[SOURCE_DIR])275 W
+/Times-Roman SF
+9400 49618 MT
+(3.)SH
+10500 XM
+(Change directory to util/imake.includes.  Read through config.Imakefile, turning on)SH
+10500 50814 MT
+(appropriate flags for your installation.  Change SRCTOP so that it is set to the top level of)SH
+10500 52010 MT
+(your source directory.)SH
+9400 53904 MT
+(4.)SH
+10500 XM
+(Check that your machine type has a definition in include/osconf.h & related files in the)SH
+10500 55100 MT
+(source tree \050if it doesn't, then you may need to create your own; if you get successful)SH
+10500 56296 MT
+(results, please post to kerberos@athena.mit.edu\051)SH
+9400 58190 MT
+(5.)SH
+10500 XM
+(Change directory to [OBJ_DIR].  The next command generates new Makefiles based on the)SH
+10500 59386 MT
+(configuration you selected in config.Imakefile, then adds dependency information to the)SH
+10500 60582 MT
+(Makefiles, and finally builds the system:)SH
+/Courier SF
+11820 62159 MT
+(host%)SH
+/Times-Bold SF
+15780 XM
+(make world)275 W
+/Times-Roman SF
+10500 63754 MT
+(This command takes a while to complete; you may wish to redirect the output onto a file)SH
+10500 64950 MT
+(and put the job in the background:)SH
+/Courier SF
+11820 66527 MT
+(host%)SH
+/Times-Bold SF
+15780 XM
+(make world)
+275 W( >&WORLDLOG_891201 &)SH
+/Times-Roman SF
+10500 68122 MT
+(If you need to rebuild the Kerberos programs and libraries after making a change, you can)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(6)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 7 8
+BS
+0 SI
+11 /Times-Roman AF
+10500 7955 MT
+(usually just type:)SH
+/Courier SF
+11820 9532 MT
+(host%)SH
+/Times-Bold SF
+15780 XM
+(make all)275 W
+/Times-Roman SF
+10500 11127 MT
+(However, if you changed the configuration in config.Imakefile or modified the Imakefiles)SH
+10500 12323 MT
+(or Makefiles, you should run)SH
+/Times-Italic SF
+23514 XM
+(make world)SH
+/Times-Roman SF
+28952 XM
+(to re-build all the Makefiles and dependency lists.)SH
+14 /Times-Bold AF
+7200 16141 MT
+(4.1 Testing)
+350 W( the DES Library)SH
+11 /Times-Roman AF
+7200 18336 MT
+(Use the)SH
+/Times-Italic SF
+10804 XM
+(verify)SH
+/Times-Roman SF
+13583 XM
+(command to test the DES library implementation:)SH
+/Courier SF
+8520 19913 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([OBJ_DIR]/lib/des/verify)SH
+/Times-Roman SF
+7200 21508 MT
+(The command should display the following:)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(7)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 8 9
+BS
+0 SI
+11 /Courier AF
+8520 7886 MT
+(Examples per FIPS publication 81, keys ivs and cipher)SH
+8520 9000 MT
+(in hex.  These are the correct answers, see below for)SH
+8520 10114 MT
+(the actual answers.)SH
+8520 12342 MT
+(Examples per Davies and Price.)SH
+8520 14570 MT
+(EXAMPLE ECB)
+SH( key)
+2640 W( = 08192a3b4c5d6e7f)SH
+13800 15684 MT
+(clear = 0)SH
+13800 16798 MT
+(cipher = 25 dd ac 3e 96 17 64 67)SH
+8520 17912 MT
+(ACTUAL ECB)SH
+13800 19026 MT
+(clear "")SH
+13800 20140 MT
+(cipher =)
+660 W( \050low to high bytes\051)SH
+19080 21254 MT
+(25 dd ac 3e 96 17 64 67)SH
+8520 23482 MT
+(EXAMPLE ECB)
+SH( key)
+2640 W( = 0123456789abcdef)SH
+13800 24596 MT
+(clear = "Now is the time for all ")SH
+13800 25710 MT
+(cipher = 3f a4 0e 8a 98 4d 48 15 ...)SH
+8520 26824 MT
+(ACTUAL ECB)SH
+13800 27938 MT
+(clear "Now is the time for all ")SH
+13800 29052 MT
+(cipher =)
+660 W( \050low to high bytes\051)SH
+19080 30166 MT
+(3f a4 0e 8a 98 4d 48 15)SH
+8520 32394 MT
+(EXAMPLE CBC)
+SH( key)
+2640 W( = 0123456789abcdef  iv = 1234567890abcdef)SH
+13800 33508 MT
+(clear = "Now is the time for all ")SH
+13800 34622 MT
+(cipher =)
+SH( e5)
+4620 W( c7 cd de 87 2b f2 7c)SH
+24360 35736 MT
+(43 e9 34 00 8c 38 9c 0f)SH
+24360 36850 MT
+(68 37 88 49 9a 7c 05 f6)SH
+8520 37964 MT
+(ACTUAL CBC)SH
+13800 39078 MT
+(clear "Now is the time for all ")SH
+13800 40192 MT
+(ciphertext = \050low to high bytes\051)SH
+19080 41306 MT
+(e5 c7 cd de 87 2b f2 7c)SH
+19080 42420 MT
+(43 e9 34 00 8c 38 9c 0f)SH
+19080 43534 MT
+(68 37 88 49 9a 7c 05 f6)SH
+19080 44648 MT
+(00 00 00 00 00 00 00 00)SH
+19080 45762 MT
+(00 00 00 00 00 00 00 00)SH
+19080 46876 MT
+(00 00 00 00 00 00 00 00)SH
+19080 47990 MT
+(00 00 00 00 00 00 00 00)SH
+19080 49104 MT
+(00 00 00 00 00 00 00 00)SH
+13800 50218 MT
+(decrypted clear_text = "Now is the time for all ")SH
+8520 51332 MT
+(EXAMPLE CBC checksum)
+SH( key)
+1980 W( =  0123456789abcdef iv =  1234567890abcdef)SH
+13800 52446 MT
+(clear =)
+SH( "7654321)
+5280 W( Now is the time for ")SH
+13800 53560 MT
+(checksum 58)
+4620 W( d2 e7 7e 86 06 27 33  or some part thereof)SH
+8520 54674 MT
+(ACTUAL CBC checksum)SH
+19080 55788 MT
+(encrypted cksum = \050low to high bytes\051)SH
+19080 56902 MT
+(58 d2 e7 7e 86 06 27 33)SH
+/Times-Roman SF
+7200 59200 MT
+(If the)SH
+/Times-Italic SF
+9826 XM
+(verify)SH
+/Times-Roman SF
+12605 XM
+(command fails to display this information as specified above, the implementation of DES for)SH
+7200 60396 MT
+(your hardware needs to be adjusted.  Your Kerberos system cannot work properly if your DES library)SH
+7200 61592 MT
+(fails this test.)SH
+7200 63890 MT
+(When you have finished building the software, you will find the executables in the object tree as follows:)SH
+/Times-Bold SF
+7200 65841 MT
+([OBJ_DIR]/admin)SH
+/Times-Italic SF
+18200 XM
+(ext_srvtab)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+23332 XM
+(kdb_destroy)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+29258 XM
+(kdb_edit)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+33596 XM
+(kdb_init)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+37752 XM
+(kdb_util)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+43771 XM
+(kstash)SH
+/Times-Roman SF
+(.)SH
+/Times-Bold SF
+7200 67536 MT
+([OBJ_DIR]/kuser)SH
+/Times-Italic SF
+18200 XM
+(kdestroy)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+22476 XM
+(kinit)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+24982 XM
+(klist)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+27366 XM
+(ksrvtgt)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+32773 XM
+(ksu)SH
+/Times-Roman SF
+(.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(8)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 9 10
+BS
+0 SI
+11 /Times-Bold AF
+7200 7955 MT
+([OBJ_DIR]/server)SH
+/Times-Italic SF
+18200 XM
+(kerberos)SH
+/Times-Roman SF
+(.)SH
+/Times-Bold SF
+7200 9650 MT
+([OBJ_DIR]/appl/bsd)SH
+/Times-Italic SF
+18200 XM
+(klogind)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+22050 XM
+(kshd)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+24616 XM
+(login.krb)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+29169 XM
+(rcp)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+31185 XM
+(rlogin)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+36288 XM
+(rsh)SH
+/Times-Roman SF
+(.)SH
+/Times-Bold SF
+7200 11345 MT
+([OBJ_DIR]/appl/knetd)SH
+/Times-Italic SF
+18200 XM
+(knetd)SH
+/Times-Roman SF
+(.)SH
+/Times-Bold SF
+7200 13040 MT
+([OBJ_DIR]/appl/sample)SH
+/Times-Italic SF
+18200 14236 MT
+(sample_server)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+25164 XM
+(sample_client)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+31824 XM
+(simple_server)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+40407 XM
+(simple_client)SH
+/Times-Roman SF
+(.)SH
+/Times-Bold SF
+7200 15931 MT
+([OBJ_DIR]/appl/tftp)SH
+/Times-Italic SF
+18200 XM
+(tcom)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+20888 XM
+(tftpd)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+25319 XM
+(tftp)SH
+/Times-Roman SF
+(.)SH
+/Times-Bold SF
+7200 17626 MT
+([OBJ_DIR]/slave)SH
+/Times-Italic SF
+18200 XM
+(kprop)SH
+/Times-Roman SF
+21041 XM
+(and)SH
+/Times-Italic SF
+22904 XM
+(kpropd)SH
+/Times-Roman SF
+(.)SH
+16 /Times-Bold AF
+7200 22298 MT
+(5. Installing)
+400 W( the Software)SH
+11 /Times-Roman AF
+7200 24493 MT
+(To install the software, issue the)SH
+/Times-Italic SF
+21711 XM
+(make install)SH
+/Times-Roman SF
+27333 XM
+(command from the [OBJ_DIR] \050you need to be a privileged)SH
+7200 25689 MT
+(user in order to properly install the programs\051.  Programs can either be installed in default directories, or)SH
+7200 26885 MT
+(under a given root directory, as described below.)SH
+14 /Times-Bold AF
+7200 30703 MT
+(5.1 The)
+350 W( ``Standard'' Places)SH
+11 /Times-Roman AF
+7200 32898 MT
+(If you use the)SH
+/Times-Italic SF
+13492 XM
+(make)SH
+/Times-Roman SF
+16087 XM
+(command as follows:)SH
+/Courier SF
+8520 34475 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+(make install)275 W
+/Times-Roman SF
+7200 36070 MT
+(the installation process will try to install the various parts of the system in ``standard'' directories.  This)SH
+7200 37266 MT
+(process creates the ``standard'' directories as needed.)SH
+7200 39564 MT
+(The standard installation process copies things as follows:)SH
+/Symbol SF
+9169 41640 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The)SH
+/Times-Italic SF
+11935 XM
+(include)SH
+/Times-Roman SF
+15448 XM
+(files)SH
+/Times-Italic SF
+17617 XM
+(krb.h)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+20458 XM
+(des.h)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+23299 XM
+(mit-copyright.h)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+30662 XM
+(kadm.h)SH
+/Times-Roman SF
+34144 XM
+(and)SH
+/Times-Italic SF
+36007 XM
+(kadm_err.h)SH
+/Times-Roman SF
+41383 XM
+(get copied to the)SH
+/Times-Italic SF
+9950 42836 MT
+(/usr/include)SH
+/Times-Roman SF
+15481 XM
+(directory.)SH
+/Symbol SF
+9169 44730 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The Kerberos libraries)SH
+/Times-Italic SF
+20119 XM
+(libdes.a)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+24122 XM
+(libkrb.a)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+28125 XM
+(libkdb.a)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+32250 XM
+(libkadm.a)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+37169 XM
+(libknet.a)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+43401 XM
+(libacl.a)SH
+/Times-Roman SF
+47007 XM
+(get)SH
+9950 45926 MT
+(copied to the)SH
+/Times-Italic SF
+15907 XM
+(/usr/athena/lib)SH
+/Times-Roman SF
+22662 XM
+(\050or wherever you pointed LIBDIR in config.Imakefile\051)SH
+9950 47122 MT
+(directory.)SH
+/Symbol SF
+9169 49016 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The Kerberos master database utilities)SH
+/Times-Italic SF
+27085 XM
+(kdb_init)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+31241 XM
+(kdb_destroy)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+37167 XM
+(kdb_edit)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+41505 XM
+(kdb_util)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+45661 XM
+(kstash)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+9950 50212 MT
+(ext_srvtab)SH
+/Times-Roman SF
+14807 XM
+(get copied to the)SH
+/Times-Italic SF
+22383 XM
+(/usr/etc)SH
+/Times-Roman SF
+25958 XM
+(\050DAEMDIR\051 directory.)SH
+/Symbol SF
+9169 52106 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The Kerberos user utilities)SH
+/Times-Italic SF
+21924 XM
+(kinit)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+24430 XM
+(kdestroy)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+28706 XM
+(klist)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+31090 XM
+(ksrvtgt)SH
+/Times-Roman SF
+34359 XM
+(and)SH
+/Times-Italic SF
+36222 XM
+(ksu)SH
+/Times-Roman SF
+37963 XM
+(get copied to the)SH
+/Times-Italic SF
+45539 XM
+(/usr/athena)SH
+/Times-Roman SF
+9950 53302 MT
+(\050PROGDIR\051 directory.)SH
+/Symbol SF
+9169 55196 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The modified Berkeley utilities)SH
+/Times-Italic SF
+24004 XM
+(rsh)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+25960 XM
+(rlogin)SH
+/Times-Roman SF
+28925 XM
+(get copied to the)SH
+/Times-Italic SF
+36501 XM
+(/usr/ucb)SH
+/Times-Roman SF
+40382 XM
+(\050UCBDIR\051 directory;)SH
+/Times-Italic SF
+9950 56392 MT
+(rcp)SH
+/Times-Roman SF
+11691 XM
+(gets copied to the)SH
+/Times-Italic SF
+19695 XM
+(/bin)SH
+/Times-Roman SF
+21682 XM
+(\050SLASHBINDIR\051 directory; and)SH
+/Times-Italic SF
+36375 XM
+(rlogind)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+40165 XM
+(rshd)SH
+/Times-Roman SF
+(, and)SH
+/Times-Italic SF
+44534 XM
+(login.krb)SH
+/Times-Roman SF
+48812 XM
+(get)SH
+9950 57588 MT
+(copied to the)SH
+/Times-Italic SF
+15907 XM
+(/usr/etc)SH
+/Times-Roman SF
+19482 XM
+(\050DAEMDIR\051 directory.  The old copies of the user programs are)SH
+9950 58784 MT
+(renamed)SH
+/Times-Italic SF
+14011 XM
+(rsh.ucb)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+17830 XM
+(rlogin.ucb)SH
+/Times-Roman SF
+22658 XM
+(and)SH
+/Times-Italic SF
+24521 XM
+(rcp.ucb)SH
+/Times-Roman SF
+(, respectively.  The Kerberos versions of these)SH
+9950 59980 MT
+(programs are designed to fall back and execute the original versions if something prevents)SH
+9950 61176 MT
+(the Kerberos versions from succeeding.)SH
+/Symbol SF
+9169 63070 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The Kerberos version of)SH
+/Times-Italic SF
+20944 XM
+(tftp)SH
+/Times-Roman SF
+22687 XM
+(and)SH
+/Times-Italic SF
+24550 XM
+(tcom)SH
+/Times-Roman SF
+26963 XM
+(get copied to the)SH
+/Times-Italic SF
+34539 XM
+(/usr/athena)SH
+/Times-Roman SF
+39826 XM
+(\050PROGDIR\051 directory;)SH
+/Times-Italic SF
+9950 64266 MT
+(tftpd)SH
+/Times-Roman SF
+12243 XM
+(gets copied to the)SH
+/Times-Italic SF
+20247 XM
+(/etc)SH
+/Times-Roman SF
+22110 XM
+(\050ETCDIR\051 directory.)SH
+/Times-Italic SF
+31884 XM
+(tftp)SH
+/Times-Roman SF
+33627 XM
+(and)SH
+/Times-Italic SF
+35490 XM
+(tftpd)SH
+/Times-Roman SF
+37783 XM
+(are installed set-uid to an)SH
+9950 65462 MT
+(unprivileged user \050user id of DEF_UID\051.)SH
+/Symbol SF
+9169 67356 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The)SH
+/Times-Italic SF
+11935 XM
+(knetd)SH
+/Times-Roman SF
+14592 XM
+(daemon gets copied to the)SH
+/Times-Italic SF
+26353 XM
+(/usr/etc)SH
+/Times-Roman SF
+29928 XM
+(\050DAEMDIR\051 directory.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(9)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 10 11
+BS
+0 SI
+11 /Symbol AF
+9169 8080 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The Kerberos server)SH
+/Times-Italic SF
+19201 XM
+(kerberos)SH
+/Times-Roman SF
+(, the slave propagation software)SH
+/Times-Italic SF
+37343 XM
+(kprop)SH
+/Times-Roman SF
+40184 XM
+(and)SH
+/Times-Italic SF
+42047 XM
+(kpropd)SH
+/Times-Roman SF
+(, and the)SH
+9950 9276 MT
+(administration server)SH
+/Times-Italic SF
+19542 XM
+(kadmind)SH
+/Times-Roman SF
+23605 XM
+(get copied to the)SH
+/Times-Italic SF
+31181 XM
+(/usr/etc)SH
+/Times-Roman SF
+34756 XM
+(\050SVRDIR, SVRDIR, and)SH
+9950 10472 MT
+(DAEMDIR\051 directory.)SH
+/Symbol SF
+9169 12366 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The remote administration tools)SH
+/Times-Italic SF
+24310 XM
+(kpasswd)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+28588 XM
+(ksrvutil)SH
+/Times-Roman SF
+32163 XM
+(and)SH
+/Times-Italic SF
+34026 XM
+(kadmin)SH
+/Times-Roman SF
+37539 XM
+(get copied to the)SH
+/Times-Italic SF
+45115 XM
+(/usr/athena)SH
+/Times-Roman SF
+9950 13562 MT
+(\050PROGDIR\051 directory.)SH
+/Symbol SF
+9169 15456 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The Kerberos manual pages get installed in the appropriate)SH
+/Times-Italic SF
+36187 XM
+(/usr/man)SH
+/Times-Roman SF
+40374 XM
+(directories. Don't)275 W
+9950 16652 MT
+(forget to run)SH
+/Times-Italic SF
+15723 XM
+(makewhatis)SH
+/Times-Roman SF
+21192 XM
+(after installing the manual pages.)SH
+14 /Times-Bold AF
+7200 20470 MT
+(5.2 ``Non-Standard'')
+350 W( Installation)SH
+11 /Times-Roman AF
+7200 22665 MT
+(If you'd rather install the software in a different location, you can use the)SH
+/Times-Italic SF
+39667 XM
+(make)SH
+/Times-Roman SF
+42262 XM
+(command as follows,)SH
+7200 23861 MT
+(where [DEST_DIR] specifies an alternate destination directory which will be used as the root for the)SH
+7200 25057 MT
+(installed programs, i.e. programs that would normally be installed in /usr/athena would be installed in)SH
+7200 26253 MT
+([DEST_DIR]/usr/athena.)SH
+/Courier SF
+8520 27830 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+(make install DESTDIR=[DEST_DIR])275 W
+16 SS 
+7200 32502 MT
+(6. Conclusion)400 W
+11 /Times-Roman AF
+7200 34697 MT
+(Now that you have built and installed your Kerberos system, use the accompanying Kerberos Operation)SH
+4030 50 44224 34897 UL
+4398 50 48529 34897 UL
+7200 35893 MT
+(Notes to create a Kerberos Master database, install authenticated services, and start the Kerberos server.)SH
+2566 50 7200 36093 UL
+16 /Times-Bold AF
+7200 40565 MT
+(7. Acknowledgements)400 W
+11 /Times-Roman AF
+7200 42760 MT
+(We'd like to thank Henry Mensch and Jon Rochlis for helping us debug this document.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30100 XM
+(10)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: i 12
+BS
+0 SI
+14 /Times-Bold AF
+25272 8138 MT
+(Table of Contents)SH
+13 SS 
+7200 9781 MT
+(1. Organization)
+325 W( of the Source Directory)SH
+53350 XM
+(1)SH
+12 /Times-Roman AF
+9000 11136 MT
+(1.1 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(admin)SH
+/Times-Roman SF
+16701 XM
+(Directory)SH
+53400 XM
+(2)SH
+9000 12491 MT
+(1.2 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(kuser)SH
+/Times-Roman SF
+16300 XM
+(Directory)SH
+53400 XM
+(2)SH
+9000 13846 MT
+(1.3 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(appl)SH
+/Times-Roman SF
+15700 XM
+(Directory)SH
+53400 XM
+(2)SH
+9000 15201 MT
+(1.4 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(server)SH
+/Times-Roman SF
+16566 XM
+(Directory)SH
+53400 XM
+(3)SH
+9000 16556 MT
+(1.5 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(kadmin)SH
+/Times-Roman SF
+17301 XM
+(Directory)SH
+53400 XM
+(3)SH
+9000 17911 MT
+(1.6 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(include)SH
+/Times-Roman SF
+17234 XM
+(Directory)SH
+53400 XM
+(3)SH
+9000 19266 MT
+(1.7 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(lib)SH
+/Times-Roman SF
+14834 XM
+(Directory)SH
+53400 XM
+(3)SH
+9000 20621 MT
+(1.8 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(man)SH
+/Times-Roman SF
+15767 XM
+(Directory)SH
+53400 XM
+(3)SH
+9000 21976 MT
+(1.9 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(prototypes)SH
+/Times-Roman SF
+18634 XM
+(Directory)SH
+53400 XM
+(3)SH
+9000 23331 MT
+(1.10 The)300 W
+/Times-BoldItalic SF
+13866 XM
+(tools)SH
+/Times-Roman SF
+16501 XM
+(Directory)SH
+53400 XM
+(3)SH
+9000 24686 MT
+(1.11 The)300 W
+/Times-BoldItalic SF
+13866 XM
+(util)SH
+/Times-Roman SF
+15835 XM
+(Directory)SH
+53400 XM
+(4)SH
+13 /Times-Bold AF
+7200 26329 MT
+(2. Preparing)
+325 W( for Installation)SH
+53350 XM
+(4)SH
+7200 27972 MT
+(3. Preparing)
+325 W( for the Build)SH
+53350 XM
+(4)SH
+12 /Times-Roman AF
+9000 29327 MT
+(3.1 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(/etc/krb.conf)SH
+/Times-Roman SF
+19801 XM
+(File)SH
+53400 XM
+(5)SH
+9000 30682 MT
+(3.2 The)300 W
+/Times-BoldItalic SF
+13266 XM
+(/etc/krb.realms)SH
+/Times-Roman SF
+20936 XM
+(File)SH
+53400 XM
+(6)SH
+13 /Times-Bold AF
+7200 32325 MT
+(4. Building)
+325 W( the Software)SH
+53350 XM
+(6)SH
+12 /Times-Roman AF
+9000 33674 MT
+(4.1 Testing)
+300 W( the DES Library)SH
+53400 XM
+(7)SH
+13 /Times-Bold AF
+7200 35317 MT
+(5. Installing)
+325 W( the Software)SH
+53350 XM
+(9)SH
+12 /Times-Roman AF
+9000 36666 MT
+(5.1 The)
+300 W( ``Standard'' Places)SH
+53400 XM
+(9)SH
+9000 38015 MT
+(5.2 ``Non-Standard'')
+300 W( Installation)SH
+52800 XM
+(10)SH
+13 /Times-Bold AF
+7200 39658 MT
+(6. Conclusion)325 W
+52700 XM
+(10)SH
+7200 41301 MT
+(7. Acknowledgements)325 W
+52700 XM
+(10)SH
+10 /Times-Roman AF
+7200 75600 MT
+(MIT Project Athena)SH
+30461 XM
+(i)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Trailer
+%%Pages: 12
+%%DocumentFonts: Times-Roman Times-Bold Times-Italic Times-BoldItalic Courier Symbol
diff --git a/mechglue/doc/old-V4-docs/installation.mss b/mechglue/doc/old-V4-docs/installation.mss
new file mode 100644
index 000000000..0a2ae7595
--- /dev/null
+++ b/mechglue/doc/old-V4-docs/installation.mss
@@ -0,0 +1,681 @@
+@Comment[	$Source$]
+@Comment[	$Author$]
+@Comment[	$Id$]
+@Comment[]
+@device[postscript]
+@make[report]
+@comment[
+@DefineFont(HeadingFont,
+      P=<RawFont "NewCenturySchlbkBoldItalic">,
+      B=<RawFont "NewCenturySchlbkBold">,
+      I=<RawFont "NewCenturySchlbkBoldItalic">,
+      R=<RawFont "NewCenturySchlbkRoman">)
+]
+@DefineFont(HeadingFont,
+      P=<RawFont "TimesBoldItalic">,
+      B=<RawFont "TimesBold">,
+      I=<RawFont "TimesItalic">,
+      R=<RawFont "TimesRoman">)
+@Counter(MajorPart,TitleEnv HD0,ContentsEnv tc0,Numbered [@I],
+          IncrementedBy Use,Announced)
+@Counter(Chapter,TitleEnv HD1,ContentsEnv tc1,Numbered [@1. ],
+          IncrementedBy Use,Referenced [@1],Announced)
+@Counter(Appendix,TitleEnv HD1,ContentsEnv tc1,Numbered [@A. ],
+          IncrementedBy,Referenced [@A],Announced,Alias Chapter)
+@Counter(UnNumbered,TitleEnv HD1,ContentsEnv tc1,Announced,Alias 
+           Chapter)
+@Counter(Section,Within Chapter,TitleEnv HD2,ContentsEnv tc2,
+          Numbered [@#@:.@1 ],Referenced [@#@:.@1],IncrementedBy
+          Use,Announced)
+@Counter(AppendixSection,Within Appendix,TitleEnv HD2,
+          ContentsEnv tc2,
+          Numbered [@#@:.@1 ],Referenced [@#@:.@1],IncrementedBy 
+          Use,Announced)
+@Counter(SubSection,Within Section,TitleEnv HD3,ContentsEnv tc3,
+          Numbered [@#@:.@1 ],IncrementedBy Use,
+          Referenced [@#@:.@1 ])
+@Counter(AppendixSubSection,Within AppendixSection,TitleEnv HD3,
+          ContentsEnv tc3,
+          Numbered [@#@:.@1 ],IncrementedBy Use,
+          Referenced [@#@:.@1 ])
+@Counter(Paragraph,Within SubSection,TitleEnv HD4,ContentsEnv tc4,
+          Numbered [@#@:.@1 ],Referenced [@#@:.@1],
+          IncrementedBy Use)
+@modify(CopyrightNotice, Fixed -1 inch, Flushright)
+@Modify(Titlebox, Fixed 3.0 inches)
+@Modify(hd1, below .2 inch, facecode B, size 16, spaces kept, pagebreak off)
+@Modify(hd2, below .2 inch, facecode B, size 14, spaces kept)
+@Modify(hd3, below .2 inch, facecode B, size 12, spaces kept)
+@Modify(Description, Leftmargin +20, Indent -20,below 1 line, above 1 line)
+@Modify(Tc1, Above .5,  Facecode B)
+@Modify(Tc2, Above .25, Below .25, Facecode R)
+@Modify(Tc3,Facecode R)
+@Modify(Tc4,Facecode R)
+@Modify(Itemize,Above 1line,Below 1line)
+@Modify(Insert,LeftMargin +2, RightMargin +2)
+@libraryfile[stable]
+@comment[@Style(Font NewCenturySchoolBook, size 11)]
+@Style(Font TimesRoman, size 11)
+@Style(Spacing 1.1, indent 0)
+@Style(leftmargin 1.0inch)
+@Style(justification no)
+@Style(BottomMargin 1.5inch)
+@Style(ChangeBarLocation Right)
+@Style(ChangeBars=off)
+@pageheading[immediate]
+@pagefooting[immediate, left = "MIT Project Athena", center = "@value(page)",
+right = "@value(date)"]
+@set[page = 0]
+@blankspace[.5 inches]
+@begin[group, size 20]
+@begin(center)
+@b[Kerberos Installation Notes]
+@b[DRAFT]
+@end[center]
+@end(group)
+@blankspace[.5 inches]
+@begin[group, size 16]
+@begin(center)
+Bill Bryant
+Jennifer Steiner
+John Kohl
+@blankspace[1 line]
+Project Athena, MIT
+@blankspace[.5 inches]
+@b[Initial Release, January 24, 1989]
+@i[(plus later patches through patchlevel 7)]
+@end[center]
+@end(group)
+@begin[group, size 10]
+@end[group]
+@blankspace[.75 inches]
+
+
+The release consists of three parts.
+
+The first part consists of the core Kerberos system, which was developed
+at MIT and does not require additional licenses for us to distribute.
+Included in this part are the Kerberos authentication server, the
+Kerberos library, the
+@i[ndbm]
+database interface library, user programs, administration programs,
+manual pages, some applications which use Kerberos for authentication,
+and some utilities.
+
+The second part is the Data Encryption Standard (DES) library, which we
+are distributing only within the United States.
+
+The third part contains Kerberos modifications to Sun's NFS, which we
+distribute as ``context diffs'' to the Sun NFS source code.  Its
+distribution is controlled to provide an accounting of who has retrieved
+the patches, so that Project Athena can comply with its agreements with
+Sun regarding distribution of these changes.
+
+@newpage()
+@chapter[Organization of the Source Directory]
+
+The Kerberos building and installation process,
+as described in this document,
+builds the binaries and executables from the files contained in the Kerberos
+source tree, and deposits them in a separate object tree.
+This is intended to easily support several different build trees from a
+single source tree (this is useful if you support several machine
+architectures).
+We suggest that you copy the Kerberos sources into a
+@i[/mit/kerberos/src] directory,
+and create as well a @i[/mit/kerberos/obj] directory in which
+to hold the executables.
+In the rest of this document, we'll refer to the Kerberos
+source and object directories as [SOURCE_DIR]
+and [OBJ_DIR], respectively.
+
+Below is a brief overview of the organization of the complete
+source directory.
+More detailed descriptions follow.
+
+@begin[description]
+
+@b[admin]@\utilities for the Kerberos administrator
+
+@b[appl]@\applications that use Kerberos
+
+@b[appl/bsd]@\Berkeley's rsh/rlogin suite, using Kerberos
+
+@b[appl/knetd]@\(old) software for inetd-like multiplexing of a single
+TCP listening port
+
+@b[appl/sample]@\sample application servers and clients
+
+@b[appl/tftp]@\Trivial File Transfer Protocol, using Kerberos
+
+@b[include]@\include files
+
+@b[kadmin]@\remote administrative interface to the Kerberos master database
+
+@b[kuser]@\assorted user programs
+
+@b[lib]@\libraries for use with/by Kerberos
+
+@b[lib/acl]@\Access Control List library
+
+@b[lib/des]@\Data Encryption Standard library (US only)
+
+@b[lib/kadm]@\administrative interface library
+
+@b[lib/kdb]@\Kerberos server library interface to @i[ndbm]
+
+@b[lib/knet]@\(old) library for use with @b[knetd]
+
+@b[lib/krb]@\Kerberos library
+
+@b[man]@\manual pages
+
+@b[prototypes]@\sample configuration files
+
+@b[server]@\the authentication server
+
+@b[slave]@\Kerberos slave database propagation software
+
+@b[tools]@\shell scripts for maintaining the source tree
+
+@b[util]@\utilities
+
+@b[util/imake]@\Imakefile-to-Makefile ``compilation'' tool
+
+@b[util/ss]@\Sub-system library (for command line subsystems)
+
+@b[util/et]@\Error-table library (for independent, unique error codes)
+
+@b[util/makedepend]@\Makefile dependency generator tool
+
+@end[description]
+
+@section[The @p(admin) Directory]
+
+This directory contains source for
+the Kerberos master database administration tools.
+@begin[description]
+@b[kdb_init]@\This program creates and initializes the
+Kerberos master database.
+It prompts for a Kerberos realmname, and the Kerberos master password.
+
+@b[kstash]@\This program ``stashes'' the master password in the file
+@i[/.k] so that the master server machine can restart the Kerberos
+server automatically after an unattended reboot.
+The hidden password is also available to administrative programs
+that have been set to run automatically.
+
+@b[kdb_edit]@\This program is a low-level tool for editing
+the master database.
+
+@b[kdb_destroy]@\This program deletes the master database.
+
+@b[kdb_util]@\This program can be used to dump the master database
+into an ascii file, and can also be used to load the ascii file
+into the master database.
+
+@b[ext_srvtab]@\This program extracts information from the master
+database and creates a host-dependent @i[srvtab] file.
+This file contains the Kerberos keys for the host's
+``Kerberized'' services.
+These services look up their keys in the @i[srvtab] file
+for use in the authentication process.
+@end[description]
+
+@section[The @p(kuser) Directory]
+
+This directory contains the source code for several user-oriented
+programs.
+@begin[description]
+@b[kinit]@\This program prompts users for their usernames and
+Kerberos passwords, then furnishes them with Kerberos ticket-granting
+tickets.
+
+@b[kdestroy]@\This program destroys any active tickets.
+Users should use @i[kdestroy] before they log off their workstations.
+
+@b[klist]@\This program lists a user's active tickets.
+
+@b[ksrvtgt]@\This retrieves a ticket-granting ticket with a life time
+of five minutes, using a server's secret key in lieu of a password.  It
+is primarily for use in shell scripts and other batch facilities.
+
+@b[ksu]@\Substitute user id, using Kerberos to mediate attempts to
+change to ``root''.
+@end[description]
+
+@section[The @p(appl) Directory]
+
+If your site has the appropriate BSD license,
+your Kerberos release provides certain Unix utilities
+The Berkeley programs that have been modified to use Kerberos
+authentication are found in the @i[appl/bsd] directory.
+They include @i[login], @i[rlogin], @i[rsh], and @i[rcp], as well as the
+associated daemon programs @i[kshd] and @i[klogind].
+The @i[login] program obtains ticket-granting tickets for users
+upon login; the other utilities provide authenticated
+Unix network services.
+
+The @i[appl] directory also contains samples Kerberos application
+client and server programs, an authenticated @i[tftp] program,
+@i[knetd], an authenticated inet daemon.
+
+@section[The @p(server) Directory]
+
+The @i[server] directory contains the Kerberos KDC server, called
+@i[kerberos].
+This program manages read-only requests made to the
+master database,
+distributing tickets and encryption keys to clients requesting
+authentication service.
+
+@section[The @p(kadmin) Directory]
+
+The @i[kadmin] directory contains the Kerberos administration server and
+associated client programs.
+The server accepts network requests from the
+user program @i[kpasswd] (used to change a user's password), the
+Kerberos administration program @i(kadmin), and the srvtab utility
+program @i[ksrvutil].
+The administration server can make modifications to the master database.
+
+@section[The @p(include) Directory]
+
+This directory contains the @i[include] files needed to
+build the Kerberos system.
+
+@section[The @p(lib) Directory]
+
+The @i[lib] directory has six subdirectories:
+@i[acl], @i[des], @i[kadm], @i[kdb], @i[knet], and @i[krb].
+The @i[des] directory contains source for the DES encryption library.
+The @i[kadm] directory contains source for the Kerberos administration
+server utility library.
+The @i[kdb] directory contains source for the Kerberos database
+routine library.
+The @i[knet] directory contains source for a library used by clients of
+the @i[knetd] server.
+The @i[krb] directory contains source for the @i[libkrb.a]
+library.
+This library contains routines that are used by the Kerberos server program,
+and by applications programs that require authentication service.
+
+@section[The @p(man) Directory]
+
+This directory contains manual pages for Kerberos programs and
+library routines.
+
+@section[The @p(prototypes) Directory]
+
+This directory contains prototype
+@i[/etc/services] and @i[/etc/krb.conf] files.
+New entries must be added to the @i[/etc/services] file for
+the Kerberos server, and possibly for Kerberized applications
+(@i[services.append] contains the entries used by the Athena-provided
+servers & applications, and is suitable for appending to your existing
+@i[/etc/services] file.).
+The @i[/etc/krb.conf] file defines the local Kerberos realm
+for its host and lists Kerberos servers for given realms.
+The @i[/etc/krb.realms] file defines exceptions for mapping machine
+names to Kerberos realms.
+
+@section[The @p(tools) Directory]
+
+This directory contains
+a makefile to set up a directory tree
+for building the software in, and
+a shell script to format code in the
+style we use.
+
+
+@section[The @p(util) Directory]
+
+This directory contains several utility programs and libraries.
+Included are Larry Wall's @i[patch] program, a @i[make] pre-processor
+program called
+@i[imake], and a program for generating Makefile dependencies,
+@i[makedepend], as well as the Sub-system library and
+utilities (@i[ss]), and the Error table library and utilities (@i[et]).
+
+@chapter[Preparing for Installation]
+
+This document assumes that you will build the system
+on the machine on which you plan to install
+the Kerberos master server and its database.
+You'll need about 10 megabytes for source and executables.
+
+By default, there must be
+a @i[/kerberos] directory on the master server machine
+in which to store the Kerberos
+database files.
+If the master server machine does not have room on its root partition
+for these files,
+create a @i[/kerberos] symbolic link to another file system.
+
+@chapter[Preparing for the Build]
+
+Before you build the system,
+you have to choose a @b[realm name],
+the name that specifies the system's administrative domain.
+Project Athena uses the internet domain name ATHENA.MIT.EDU
+to specify its Kerberos realm name.
+We recommend using a name of this form.
+@b[NOTE:] the realm-name is case sensitive; by convention, we suggest
+that you use your internet domain name, in capital letters.
+
+Edit the [SOURCE_DIR]/@i[include/krb.h] file and look for the following
+lines of code:
+@begin[example]
+/*
+ * Kerberos specific definitions
+ *
+ * KRBLOG is the log file for the kerberos master server.
+ * KRB_CONF is the configuration file where different host
+ * machines running master and slave servers can be found.
+ * KRB_MASTER is the name of the machine with the master
+ * database.  The admin_server runs on this machine, and all
+ * changes to the db (as opposed to read-only requests, which
+ * can go to slaves) must go to it.
+ * KRB_HOST is the default machine when looking for a kerberos
+ * slave server.  Other possibilities are in the KRB_CONF file.
+ * KRB_REALM is the name of the realm.
+ */
+
+#ifdef notdef
+this is server-only, does not belong here;
+#define       KRBLOG          "/kerberos/kerberos.log"
+are these used anyplace '?';
+#define               VX_KRB_HSTFILE  "/etc/krbhst"
+#define               PC_KRB_HSTFILE  "\\kerberos\\krbhst"
+#endif
+
+#define               KRB_CONF        "/etc/krb.conf"
+#define               KRB_RLM_TRANS   "/etc/krb.realms"
+#define               KRB_MASTER      "kerberos"
+#define               KRB_HOST         KRB_MASTER
+#define               KRB_REALM       "ATHENA.MIT.EDU"
+@end[example]
+Edit the last line as follows:
+@begin[enumerate]
+Change the KRB_REALM definition so that it specifies the realm name
+you have chosen for your Kerberos system.  This is a default which is
+usually overridden by a configuration file on each machine; however, if
+that config file is absent, many programs will use this "built-in" realm
+name.
+@end[enumerate]
+
+@section[The @p(/etc/krb.conf) File]
+
+Create a @i[/etc/krb.conf] file using the following format:
+@begin[example]
+@p[realm_name]
+@p[realm_name]  @p[master_server_name] admin server
+@end[example]
+where @i[realm_name] specifies the system's realm name,
+and @i[master_server_name] specifies the machine name on
+which you will run the master server.  The words 'admin server' must
+appear next to the name of the server on which you intend to run the
+administration server (which must be a machine with access to the database).
+
+For example,
+if your realm name is @i[tim.edu] and your master server's name is
+@i[kerberos.tim.edu], the file should have these contents:
+@begin[example]
+tim.edu
+tim.edu  kerberos.tim.edu admin server
+@end[example]
+
+See the [SOURCE_DIR]/@i[prototypes/etc.krb.conf] file for an
+example @i[/etc/krb.conf] file.  That file has examples of how to
+provide backup servers for a given realm (additional lines with the same
+leading realm name) and how to designate servers for remote realms.
+
+@section[The @p(/etc/krb.realms) File]
+
+In many situations, the default realm in which a host operates will be
+identical to the domain portion its Internet domain name.
+
+If this is not the case, you will need to establish a translation from
+host name or domain name to realm name.  This is accomplished with the
+@i(/etc/krb.realms) file.
+
+Each line of the translation file specifies either a hostname or domain
+name, and its associated realm:
+@begin[example]
+.domain.name kerberos.realm1
+host.name kerberos.realm2
+@end[example]
+For example, to map all hosts in the domain LSC.TIM.EDU to KRB.REALM1
+but the host FILMS.LSC.TIM.EDU to KRB.REALM2 your file would read:
+@begin[example]
+.LSC.TIM.EDU KRB.REALM1
+FILMS.LSC.TIM.EDU KRB.REALM2
+@end[example]
+If a particular host matches both a domain and a host entry, the host
+entry takes precedence.
+
+@chapter[Building the Software]
+
+Before you build the software
+read the @b[README] file in [SOURCE_DIR].
+What follows is a more detailed description of the instructions
+listed in README.
+@begin[enumerate]
+Create an [OBJ_DIR] directory to hold the tree of Kerberos object files you
+are about to build, for example,
+@i[/mit/kerberos/obj].
+
+Change directory to [OBJ_DIR].
+The following command creates directories under [OBJ_DIR]
+and installs Makefiles for the final build.
+@begin[example, rightmargin -7]
+host% @b(make  -f  [SOURCE_DIR]/tools/makeconfig  SRCDIR=[SOURCE_DIR])
+@end[example]
+
+
+
+Change directory to util/imake.includes.  Read through config.Imakefile,
+turning on appropriate flags for your installation.  Change SRCTOP so
+that it is set to the top level of your source directory.
+
+Check that your machine type has a definition in include/osconf.h &
+related files in the source tree (if it doesn't, then you may need to
+create your own; if you get successful results, please post to
+kerberos@@athena.mit.edu)
+
+Change directory to [OBJ_DIR].  The next command generates new Makefiles
+based on the configuration you selected in config.Imakefile, then adds
+dependency information to the Makefiles, and finally builds the system:
+@begin[example, rightmargin -7]
+host% @b(make  world)
+@end[example]
+This command takes a while to complete; you may wish to redirect the
+output onto a file and put the job in the background:
+@begin[example, rightmargin -7]
+host% @b(make  world >&WORLDLOG_891201 &)
+@end[example]
+If you need to rebuild the Kerberos programs and libraries after making
+a change, you can usually just type:
+@begin[example, rightmargin -7]
+host% @b(make  all)
+@end[example]
+However, if you changed the configuration in config.Imakefile or modified
+the Imakefiles or Makefiles, you should run @i[make world] to re-build
+all the Makefiles and dependency lists.
+@end(enumerate)
+
+@section[Testing the DES Library]
+
+Use the @i[verify] command to test the DES library
+implementation:
+@begin[example]
+host% @b([OBJ_DIR]/lib/des/verify)
+@end[example]
+The command should display the following:
+@begin[example, rightmargin -10]
+Examples per FIPS publication 81, keys ivs and cipher
+in hex.  These are the correct answers, see below for
+the actual answers.
+
+Examples per Davies and Price.
+
+EXAMPLE ECB     key = 08192a3b4c5d6e7f
+        clear = 0
+        cipher = 25 dd ac 3e 96 17 64 67
+ACTUAL ECB
+        clear ""
+        cipher  = (low to high bytes)
+                25 dd ac 3e 96 17 64 67 
+
+EXAMPLE ECB     key = 0123456789abcdef
+        clear = "Now is the time for all "
+        cipher = 3f a4 0e 8a 98 4d 48 15 ...
+ACTUAL ECB
+        clear "Now is the time for all "
+        cipher  = (low to high bytes)
+                3f a4 0e 8a 98 4d 48 15 
+
+EXAMPLE CBC     key = 0123456789abcdef  iv = 1234567890abcdef
+        clear = "Now is the time for all "
+        cipher =        e5 c7 cd de 87 2b f2 7c
+                        43 e9 34 00 8c 38 9c 0f
+                        68 37 88 49 9a 7c 05 f6
+ACTUAL CBC
+        clear "Now is the time for all "
+        ciphertext = (low to high bytes)
+                e5 c7 cd de 87 2b f2 7c 
+                43 e9 34 00 8c 38 9c 0f 
+                68 37 88 49 9a 7c 05 f6 
+                00 00 00 00 00 00 00 00 
+                00 00 00 00 00 00 00 00 
+                00 00 00 00 00 00 00 00 
+                00 00 00 00 00 00 00 00 
+                00 00 00 00 00 00 00 00 
+        decrypted clear_text = "Now is the time for all "
+EXAMPLE CBC checksum    key =  0123456789abcdef iv =  1234567890abcdef
+        clear =         "7654321 Now is the time for "
+        checksum        58 d2 e7 7e 86 06 27 33  or some part thereof
+ACTUAL CBC checksum
+                encrypted cksum = (low to high bytes)
+                58 d2 e7 7e 86 06 27 33
+@end[example]
+
+If the @i[verify] command fails to display this information as specified
+above, the implementation of DES for your hardware needs to
+be adjusted.
+Your Kerberos system cannot work properly if your DES library
+fails this test.
+
+When you have finished building the software,
+you will find the executables in the object tree as follows:
+@begin[description]
+@b([OBJ_DIR]/admin)@\@i[ext_srvtab], @i[kdb_destroy],
+@i[kdb_edit], @i[kdb_init], @i[kdb_util], and @i[kstash].
+
+@b([OBJ_DIR]/kuser)@\@i[kdestroy], @i[kinit], @i[klist], @i[ksrvtgt],
+and @i[ksu].
+
+@b([OBJ_DIR]/server)@\@i[kerberos].
+
+@b([OBJ_DIR]/appl/bsd)@\@i[klogind], @i[kshd], @i[login.krb], @i[rcp],
+@i[rlogin], and @i[rsh].
+
+@b([OBJ_DIR]/appl/knetd)@\@i[knetd].
+
+@b([OBJ_DIR]/appl/sample)@\@i[sample_server], @i[sample_client],
+@i[simple_server], and @i[simple_client].
+
+@b([OBJ_DIR]/appl/tftp)@\@i[tcom], @i[tftpd], and @i[tftp].
+
+@b([OBJ_DIR]/slave)@\@i[kprop] and @i[kpropd].
+@end[description]
+
+@chapter[Installing the Software]
+
+To install the software, issue the @i[make install] command from
+the [OBJ_DIR] (you need to be a privileged user in order to
+properly install the programs).
+Programs can either be installed in default directories, or under
+a given root directory, as described below.
+
+@section[The ``Standard'' Places]
+
+If you use the @i[make] command as follows:
+@begin[example]
+host# @b(make  install)
+@end[example]
+the installation process will try to install the various parts of the
+system in ``standard'' directories.
+This process creates the ``standard'' directories as needed.
+
+The standard installation process copies things as follows:
+@begin[itemize]
+The @i[include] files @i[krb.h], @i[des.h], @i[mit-copyright.h],
+@i[kadm.h] and @i[kadm_err.h] get copied to the
+@i[/usr/include] directory.
+
+The Kerberos libraries @i[libdes.a], @i[libkrb.a], @i[libkdb.a],
+@i[libkadm.a], @i[libknet.a], and @i[libacl.a] get copied
+to the @i[/usr/athena/lib] (or wherever you pointed LIBDIR in
+config.Imakefile) directory.
+
+The Kerberos master database utilities @i[kdb_init], @i[kdb_destroy],
+@i[kdb_edit], @i[kdb_util], @i[kstash], and @i[ext_srvtab] get copied to
+the @i[/usr/etc] (DAEMDIR) directory.
+
+The Kerberos user utilities @i[kinit], @i[kdestroy], @i[klist],
+@i[ksrvtgt] and @i[ksu] get copied to the @i[/usr/athena] (PROGDIR)
+directory.
+
+The modified Berkeley utilities @i[rsh], @i[rlogin] get copied to the
+@i[/usr/ucb] (UCBDIR) directory; @i[rcp] gets copied to the @i[/bin]
+(SLASHBINDIR) directory; and @i[rlogind], @i[rshd], and @i[login.krb]
+get copied to the @i[/usr/etc] (DAEMDIR) directory.  The old copies of
+the user programs are renamed @i(rsh.ucb), @i(rlogin.ucb) and
+@i(rcp.ucb), respectively.  The Kerberos versions of these programs are
+designed to fall back and execute the original versions if something
+prevents the Kerberos versions from succeeding.
+
+The Kerberos version of @i[tftp] and @i[tcom] get copied to the
+@i[/usr/athena] (PROGDIR) directory; @i[tftpd] gets copied to the
+@i[/etc] (ETCDIR) directory.  @i[tftp] and @i[tftpd] are installed
+set-uid to an unprivileged user (user id of DEF_UID).
+
+The @i[knetd] daemon gets copied to the @i[/usr/etc] (DAEMDIR) directory.
+
+The Kerberos server @i[kerberos], the slave propagation software
+@i[kprop] and @i[kpropd], and the administration server @i[kadmind] get
+copied to the @i[/usr/etc] (SVRDIR, SVRDIR, and DAEMDIR) directory.
+
+The remote administration tools @i[kpasswd], @i[ksrvutil] and @i[kadmin]
+get copied to the @i[/usr/athena] (PROGDIR) directory.
+
+The Kerberos manual pages get installed in the appropriate
+@i[/usr/man] directories.  Don't forget to run @i[makewhatis]
+after installing the manual pages.
+
+@end[itemize]
+
+@section[``Non-Standard'' Installation]
+
+If you'd rather install the software in a different location,
+you can use the @i[make] command as follows,
+where [DEST_DIR] specifies an alternate destination directory
+which will be used as the root for the installed programs, i.e. programs
+that would normally be installed in /usr/athena would be installed in
+[DEST_DIR]/usr/athena.
+@begin[example]
+host# @b(make  install  DESTDIR=[DEST_DIR])
+@end[example]
+
+@chapter[Conclusion]
+
+Now that you have built and installed your Kerberos system,
+use the accompanying @u[Kerberos Operation Notes]
+to create a Kerberos Master database, install authenticated services,
+and start the Kerberos server.
+
+@chapter [Acknowledgements]
+
+We'd like to thank Henry Mensch and Jon Rochlis for helping us debug
+this document.
diff --git a/mechglue/doc/old-V4-docs/operation.PS b/mechglue/doc/old-V4-docs/operation.PS
new file mode 100644
index 000000000..3afb8cf06
--- /dev/null
+++ b/mechglue/doc/old-V4-docs/operation.PS
@@ -0,0 +1,2669 @@
+%!PS-Adobe-2.0
+%%Title: operation.mss
+%%DocumentFonts: (atend)
+%%Creator: John T Kohl,,E40-351M,31510,6176432831 and Scribe 7(1700)
+%%CreationDate: 4 January 1990 11:55
+%%Pages: (atend)
+%%EndComments
+% PostScript Prelude for Scribe.
+/BS {/SV save def 0.0 792.0 translate .01 -.01 scale} bind def
+/ES {showpage SV restore} bind def
+/SC {setrgbcolor} bind def
+/FMTX matrix def
+/RDF {WFT SLT 0.0 eq 
+  {SSZ 0.0 0.0 SSZ neg 0.0 0.0 FMTX astore}
+  {SSZ 0.0 SLT neg sin SLT cos div SSZ mul SSZ neg 0.0 0.0 FMTX astore}
+  ifelse makefont setfont} bind def
+/SLT 0.0 def
+/SI { /SLT exch cvr def RDF} bind def
+/WFT /Courier findfont def
+/SF { /WFT exch findfont def RDF} bind def
+/SSZ 1000.0 def
+/SS { /SSZ exch 100.0 mul def RDF} bind def
+/AF { /WFT exch findfont def /SSZ exch 100.0 mul def RDF} bind def
+/MT /moveto load def
+/XM {currentpoint exch pop moveto} bind def
+/UL {gsave newpath moveto dup 2.0 div 0.0 exch rmoveto
+   setlinewidth 0.0 rlineto stroke grestore} bind def
+/LH {gsave newpath moveto setlinewidth
+   0.0 rlineto
+   gsave stroke grestore} bind def
+/LV {gsave newpath moveto setlinewidth
+   0.0 exch rlineto
+   gsave stroke grestore} bind def
+/BX {gsave newpath moveto setlinewidth
+   exch
+   dup 0.0 rlineto
+   exch 0.0 exch neg rlineto
+   neg 0.0 rlineto
+   closepath
+   gsave stroke grestore} bind def
+/BX1 {grestore} bind def
+/BX2 {setlinewidth 1 setgray stroke grestore} bind def
+/PB {/PV save def newpath translate
+    100.0 -100.0 scale pop /showpage {} def} bind def
+/PE {PV restore} bind def
+/GB {/PV save def newpath translate rotate
+    div dup scale 100.0 -100.0 scale /showpage {} def} bind def
+/GE {PV restore} bind def
+/FB {dict dup /FontMapDict exch def begin} bind def
+/FM {cvn exch cvn exch def} bind def
+/FE {end /original-findfont /findfont load def  /findfont
+   {dup FontMapDict exch known{FontMapDict exch get} if
+   original-findfont} def} bind def
+/BC {gsave moveto dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath clip} bind def
+/EC /grestore load def
+/SH /show load def
+/MX {exch show 0.0 rmoveto} bind def
+/W {0 32 4 -1 roll widthshow} bind def
+/WX {0 32 5 -1 roll widthshow 0.0 rmoveto} bind def
+/RC {100.0 -100.0 scale
+612.0 0.0 translate
+-90.0 rotate
+.01 -.01 scale} bind def
+/URC {100.0 -100.0 scale
+90.0 rotate
+-612.0 0.0 translate
+.01 -.01 scale} bind def
+/RCC {100.0 -100.0 scale
+0.0 -792.0 translate 90.0 rotate
+.01 -.01 scale} bind def
+/URCC {100.0 -100.0 scale
+-90.0 rotate 0.0 792.0 translate
+.01 -.01 scale} bind def
+%%EndProlog
+%%Page: 0 1
+BS
+0 SI
+20 /Times-Bold AF
+19324 13788 MT
+(Kerberos Operation Notes)SH
+27156 15798 MT
+(DRAFT)SH
+16 /Times-Roman AF
+27021 23502 MT
+(Bill Bryant)SH
+27289 25150 MT
+(John Kohl)SH
+23957 26798 MT
+(Project Athena, MIT)SH
+/Times-Bold SF
+19489 32396 MT
+(Initial Release, January 24, 1989)SH
+/Times-Italic SF
+17558 34044 MT
+(\050plus later patches through patchlevel 7\051)SH
+11 /Times-Roman AF
+7200 43798 MT
+(These notes assume that you have used the)SH
+/Times-Italic SF
+26322 XM
+(Kerberos Installation Notes)SH
+/Times-Roman SF
+38821 XM
+(to build and install your Kerberos)SH
+7200 44994 MT
+(system. As)
+275 W( in that document, we refer to the directory that contains the built Kerberos binaries as)SH
+7200 46190 MT
+([OBJ_DIR].)SH
+7200 48488 MT
+(This document assumes that you are a Unix system manager.)SH
+ES
+%%Page: 1 2
+BS
+0 SI
+16 /Times-Bold AF
+7200 8272 MT
+(1. How)
+400 W( Kerberos Works: A Schematic Description)SH
+11 /Times-Roman AF
+7200 10467 MT
+(This section provides a simplified description of a general user's interaction with the Kerberos system.)SH
+7200 11663 MT
+(This interaction happens transparently--users don't need to know and probably don't care about what's)SH
+7200 12859 MT
+(going on--but Kerberos administrators might find a schematic description of the process useful.  The)SH
+7200 14055 MT
+(description glosses over a lot of details; for more information, see)SH
+/Times-Italic SF
+36404 XM
+(Kerberos: An Authentication Service)SH
+7200 15251 MT
+(for Open Network Systems)SH
+/Times-Roman SF
+(, a paper presented at Winter USENIX 1988, in Dallas, Texas.)SH
+14 /Times-Bold AF
+7200 19069 MT
+(1.1 Network)
+350 W( Services and Their Client Programs)SH
+11 /Times-Roman AF
+7200 21264 MT
+(In an environment that provides network services, you use)SH
+/Times-Italic SF
+33164 XM
+(client)SH
+/Times-Roman SF
+35883 XM
+(programs to request service from)SH
+/Times-Italic SF
+50696 XM
+(server)SH
+/Times-Roman SF
+7200 22460 MT
+(programs that are somewhere on the network.  Suppose you have logged in to a workstation and you want)SH
+7200 23656 MT
+(to)SH
+/Times-Italic SF
+8331 XM
+(rlogin)SH
+/Times-Roman SF
+11296 XM
+(to another machine.  You use the local)SH
+/Times-Italic SF
+28493 XM
+(rlogin)SH
+/Times-Roman SF
+31458 XM
+(client program to contact the remote machine's)SH
+/Times-Italic SF
+7200 24852 MT
+(rlogin)SH
+/Times-Roman SF
+10165 XM
+(service daemon.)SH
+14 /Times-Bold AF
+7200 28670 MT
+(1.2 Kerberos)
+350 W( Tickets)SH
+11 /Times-Roman AF
+7200 30865 MT
+(Under Kerberos, the)SH
+/Times-Italic SF
+16422 XM
+(rlogin)SH
+/Times-Roman SF
+19387 XM
+(service program allows a client to login to a remote machine if it can provide)SH
+7200 32061 MT
+(a Kerberos)SH
+/Times-Bold SF
+12268 XM
+(ticket)SH
+/Times-Roman SF
+15169 XM
+(for the request.  This ticket proves the identity of the person who has used the client)SH
+7200 33257 MT
+(program to access the server program.)SH
+14 /Times-Bold AF
+7200 37075 MT
+(1.3 The)
+350 W( Kerberos Master Database)SH
+11 /Times-Roman AF
+7200 39270 MT
+(Kerberos will give you tickets only if you have an entry in the Kerberos server's)SH
+/Times-Bold SF
+42845 XM
+(master database)SH
+/Times-Roman SF
+(. Your)275 W
+7200 40466 MT
+(database entry includes your Kerberos username \050often referred to as your Kerberos)SH
+/Times-Bold SF
+44394 XM
+(principal)SH
+/Times-Roman SF
+48949 XM
+(name\051, and)SH
+7200 41662 MT
+(your Kerberos password.  Every Kerberos user must have an entry in this database.)SH
+14 /Times-Bold AF
+7200 45480 MT
+(1.4 The)
+350 W( Ticket-Granting Ticket)SH
+11 /Times-Roman AF
+7200 47675 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(kinit)SH
+/Times-Roman SF
+11416 XM
+(command prompts for your Kerberos username and password, and if you enter them)SH
+7200 48871 MT
+(successfully, you will obtain a Kerberos)SH
+/Times-Italic SF
+25131 XM
+(ticket-granting ticket)SH
+/Times-Roman SF
+(. As)
+275 W( illustrated below, client programs use)SH
+7200 50067 MT
+(this ticket to get other Kerberos tickets as needed.)SH
+14 /Times-Bold AF
+7200 53885 MT
+(1.5 Network)
+350 W( Services and the Master Database)SH
+11 /Times-Roman AF
+7200 56080 MT
+(The master database also contains entries for all network services that require Kerberos authentication.)SH
+7200 57276 MT
+(Suppose for instance that your site has a machine)SH
+/Times-Italic SF
+29163 XM
+(laughter)SH
+/Times-Roman SF
+33166 XM
+(that requires Kerberos authentication from)SH
+7200 58472 MT
+(anyone who wants to)SH
+/Times-Italic SF
+16792 XM
+(rlogin)SH
+/Times-Roman SF
+19757 XM
+(to it.  This service must be registered in the master database.  Its entry)SH
+7200 59668 MT
+(includes the service's principal name, and its)SH
+/Times-Bold SF
+27238 XM
+(instance)SH
+/Times-Roman SF
+(.)SH
+7200 61966 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(instance)SH
+/Times-Roman SF
+13126 XM
+(is the name of the service's machine; in this case, the service's instance is the name)SH
+/Times-Italic SF
+7200 63162 MT
+(laughter)SH
+/Times-Roman SF
+(. The)
+275 W( instance provides a means for Kerberos to distinguish between machines that provide the)SH
+7200 64358 MT
+(same service.  Your site is likely to have more than one machine that provides)SH
+/Times-Italic SF
+41840 XM
+(rlogin)SH
+/Times-Roman SF
+44805 XM
+(service.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(1)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 2 3
+BS
+0 SI
+14 /Times-Bold AF
+7200 8138 MT
+(1.6 The)
+350 W( User-Kerberos Interaction)SH
+11 /Times-Roman AF
+7200 10333 MT
+(Suppose that you \050in the guise of a general user\051 walk up to a workstation intending to login to it, and)SH
+7200 11529 MT
+(then)SH
+/Times-Italic SF
+9369 XM
+(rlogin)SH
+/Times-Roman SF
+12334 XM
+(to the machine)SH
+/Times-Italic SF
+19085 XM
+(laughter)SH
+/Times-Roman SF
+(. Here's)
+275 W( what happens.)SH
+9400 13480 MT
+(1.)SH
+10500 XM
+(You login to the workstation and use the)SH
+/Times-Italic SF
+28648 XM
+(kinit)SH
+/Times-Roman SF
+30879 XM
+(command to to get a ticket-granting ticket.)SH
+10500 14676 MT
+(This command prompts you for your username \050your Kerberos Principal Name\051, and your)SH
+10500 15872 MT
+(Kerberos password [on some systems which use the new version of)SH
+/Times-Italic SF
+40465 XM
+(/bin/login)SH
+/Times-Roman SF
+(, this may be)SH
+10500 17068 MT
+(done as part of the login process, not requiring the user to run a separate program].)SH
+12762 19019 MT
+(a.)SH
+13800 XM
+(The)SH
+/Times-Italic SF
+15785 XM
+(kinit)SH
+/Times-Roman SF
+18016 XM
+(command sends your request to the Kerberos master server machine.  The)SH
+13800 20215 MT
+(server software looks for your principal name's entry in the Kerberos)SH
+/Times-Bold SF
+44555 XM
+(master)SH
+13800 21411 MT
+(database)SH
+/Times-Roman SF
+(.)SH
+12700 23305 MT
+(b.)SH
+13800 XM
+(If this entry exists, the Kerberos server creates and returns a)SH
+/Times-Italic SF
+40430 XM
+(ticket-granting ticket)SH
+/Times-Roman SF
+(,)SH
+13800 24501 MT
+(encrypted in your password.  If)SH
+/Times-Italic SF
+27819 XM
+(kinit)SH
+/Times-Roman SF
+30050 XM
+(can decrypt the Kerberos reply using the)SH
+13800 25697 MT
+(password you provide, it stores this ticket in a)SH
+/Times-Bold SF
+34270 XM
+(ticket file)SH
+/Times-Roman SF
+38912 XM
+(on your local machine for)SH
+13800 26893 MT
+(later use.  The ticket file to be used can be specified in the)SH
+/Times-Bold SF
+39609 XM
+(KRBTKFILE)SH
+/Times-Roman SF
+13800 28089 MT
+(environment variable.  If this variable is not set, the name of the file will be)SH
+/Times-Italic SF
+13800 29285 MT
+(/tmp/tkt)SH
+/Times-BoldItalic SF
+(uid)SH
+/Times-Roman SF
+(, where)SH
+/Times-BoldItalic SF
+22141 XM
+(uid)SH
+/Times-Roman SF
+23884 XM
+(is the UNIX user-id, represented in decimal.)SH
+9400 31236 MT
+(2.)SH
+10500 XM
+(Now you use the)SH
+/Times-Italic SF
+18198 XM
+(rlogin)SH
+/Times-Roman SF
+21163 XM
+(client to try to access the machine)SH
+/Times-Italic SF
+36344 XM
+(laughter)SH
+/Times-Roman SF
+(.)SH
+/Courier SF
+11820 32813 MT
+(host%)SH
+/Times-Bold SF
+15780 XM
+(rlogin laughter)275 W
+/Times-Roman SF
+12762 34764 MT
+(a.)SH
+13800 XM
+(The)SH
+/Times-Italic SF
+15785 XM
+(rlogin)SH
+/Times-Roman SF
+18750 XM
+(client checks your ticket file to see if you have a ticket for)SH
+/Times-Italic SF
+44559 XM
+(laughter)SH
+/Times-Roman SF
+('s)SH
+/Times-Italic SF
+13800 35960 MT
+(rcmd)SH
+/Times-Roman SF
+16335 XM
+(service \050the rlogin program uses the)SH
+/Times-Italic SF
+32401 XM
+(rcmd)SH
+/Times-Roman SF
+34936 XM
+(service name, mostly for historical)SH
+13800 37156 MT
+(reasons\051. You)
+275 W( don't, so)SH
+/Times-Italic SF
+24583 XM
+(rlogin)SH
+/Times-Roman SF
+27548 XM
+(uses the ticket file's)SH
+/Times-Italic SF
+36590 XM
+(ticket-granting ticket)SH
+/Times-Roman SF
+46060 XM
+(to make a)SH
+13800 38352 MT
+(request to the master server's ticket-granting service.)SH
+12700 40246 MT
+(b.)SH
+13800 XM
+(This ticket-granting service receives the)SH
+/Times-Italic SF
+31667 XM
+(rcmd-laughter)SH
+/Times-Roman SF
+38296 XM
+(request and looks in the)SH
+13800 41442 MT
+(master database for an)SH
+/Times-Italic SF
+23938 XM
+(rcmd-laughter)SH
+/Times-Roman SF
+30567 XM
+(entry. If)
+275 W( that entry exists, the ticket-granting)SH
+13800 42638 MT
+(service issues you a ticket for that service.  That ticket is also cached in your ticket)SH
+13800 43834 MT
+(file.)SH
+12762 45728 MT
+(c.)SH
+13800 XM
+(The)SH
+/Times-Italic SF
+15785 XM
+(rlogin)SH
+/Times-Roman SF
+18750 XM
+(client now uses that ticket to request service from the)SH
+/Times-Italic SF
+42454 XM
+(laughter rlogin)SH
+/Times-Roman SF
+13800 46924 MT
+(service program.  The service program lets you)SH
+/Times-Italic SF
+34843 XM
+(rlogin)SH
+/Times-Roman SF
+37808 XM
+(if the ticket is valid.)SH
+16 /Times-Bold AF
+7200 51596 MT
+(2. Setting)
+400 W( Up and Testing the Kerberos Server)SH
+11 /Times-Roman AF
+7200 53791 MT
+(The procedure for setting up and testing a Kerberos server is as follows:)SH
+9400 55742 MT
+(1.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(kdb_init)SH
+/Times-Roman SF
+17985 XM
+(command to create and initialize the master database.)SH
+9400 57636 MT
+(2.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(kdb_edit)SH
+/Times-Roman SF
+18167 XM
+(utility to add your username to the master database.)SH
+9400 59530 MT
+(3.)SH
+10500 XM
+(Start the Kerberos server.)SH
+9400 61424 MT
+(4.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(kinit)SH
+/Times-Roman SF
+16335 XM
+(command to obtain a Kerberos ticket-granting ticket.)SH
+9400 63318 MT
+(5.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(klist)SH
+/Times-Roman SF
+16213 XM
+(command to verify that the)SH
+/Times-Italic SF
+28402 XM
+(kinit)SH
+/Times-Roman SF
+30633 XM
+(command authenticated you successfully.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(2)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 3 4
+BS
+0 SI
+14 /Times-Bold AF
+7200 8138 MT
+(2.1 Creating)
+350 W( and Initializing the Master Database)SH
+11 /Times-Roman AF
+7200 10333 MT
+(Login to the Kerberos master server machine, and use the)SH
+/Times-Bold SF
+32825 XM
+(su)SH
+/Times-Roman SF
+34140 XM
+(command to become root.  If you installed)SH
+7200 11529 MT
+(the Kerberos administration tools with the)SH
+/Times-Italic SF
+26020 XM
+(make install)SH
+/Times-Roman SF
+31642 XM
+(command and the default pathnames, they should)SH
+7200 12725 MT
+(be in the)SH
+/Times-Italic SF
+11263 XM
+(/usr/etc)SH
+/Times-Roman SF
+14838 XM
+(directory. If)
+275 W( you installed the tools in a different directory, hopefully you know what it)SH
+7200 13921 MT
+(is. From)
+275 W( now on, we will refer to this directory as [ADMIN_DIR].)SH
+7200 16219 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(kdb_init)SH
+/Times-Roman SF
+13066 XM
+(command creates and initializes the master database.  It asks you to enter the system's realm)SH
+7200 17415 MT
+(name and the database's master password.  Do not forget this password.  If you do, the database becomes)SH
+7200 18611 MT
+(useless. \050Your)
+275 W( realm name should be substituted for [REALMNAME] below.\051)SH
+7200 20909 MT
+(Use)SH
+/Times-Italic SF
+9185 XM
+(kdb_init)SH
+/Times-Roman SF
+13066 XM
+(as follows:)SH
+/Courier SF
+8520 22486 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+([ADMIN_DIR]/kdb_init)SH
+/Courier SF
+8520 23600 MT
+(Realm name \050default XXX\051:)SH
+/Times-Bold SF
+25680 XM
+([REALMNAME])SH
+39600 XM
+(<--)SH
+/Times-BoldItalic SF
+41619 XM
+(Enter your system's realm name.)SH
+/Courier SF
+8520 24714 MT
+(You will be prompted for the database Master Password.)SH
+8520 25828 MT
+(It is important that you NOT FORGET this password.)SH
+8520 28056 MT
+(Enter Kerberos master key:)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter the master password.)SH
+14 /Times-Bold AF
+7200 32988 MT
+(2.2 Storing)
+350 W( the Master Password)SH
+11 /Times-Roman AF
+7200 35183 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(kstash)SH
+/Times-Roman SF
+12210 XM
+(command ``stashes'' the master password in the file)SH
+/Times-Italic SF
+35424 XM
+(/.k)SH
+/Times-Roman SF
+36768 XM
+(so that the Kerberos server can be)SH
+7200 36379 MT
+(started automatically during an unattended reboot of the master server.  Other administrative programs)SH
+7200 37575 MT
+(use this hidden password so that they can access the master database without someone having to manually)SH
+7200 38771 MT
+(provide the master password.  This command is an optional one; if you'd rather enter the master password)SH
+7200 39967 MT
+(each time you start the Kerberos server, don't use)SH
+/Times-Italic SF
+29312 XM
+(kstash)SH
+/Times-Roman SF
+(.)SH
+7200 42265 MT
+(One the one hand, if you use)SH
+/Times-Italic SF
+20090 XM
+(kstash)SH
+/Times-Roman SF
+(, a copy of the master key will reside on disk which may not be)SH
+7200 43461 MT
+(acceptable; on the other hand, if you don't use)SH
+/Times-Italic SF
+27848 XM
+(kstash)SH
+/Times-Roman SF
+(, the server cannot be started unless someone is)SH
+7200 44657 MT
+(around to type the password in manually.)SH
+7200 46955 MT
+(The command prompts you twice for the master password:)SH
+/Courier SF
+8520 48532 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+([ADMIN_DIR]/kstash)SH
+/Courier SF
+8520 50760 MT
+(Enter Kerberos master key:)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter the master password.)SH
+/Courier SF
+8520 51874 MT
+(Current Kerberos master key version is 1.)SH
+8520 54102 MT
+(Master key entered)
+SH( BEWARE!)1320 W
+/Times-Roman SF
+7200 56400 MT
+(A note about the Kerberos database master key:  if your master key is compromised and the database is)SH
+7200 57596 MT
+(obtained, the security of your entire authentication system is compromised.  The master key must be a)SH
+7200 58792 MT
+(carefully kept secret.  If you keep backups, you must guard all the master keys you use, in case someone)SH
+7200 59988 MT
+(has stolen an old backup and wants to attack users' whose passwords haven't changed since the backup)SH
+7200 61184 MT
+(was stolen.  This is why we provide the option not to store it on disk.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(3)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 4 5
+BS
+0 SI
+14 /Times-Bold AF
+7200 8167 MT
+(2.3 Using)350 W
+/Times-BoldItalic SF
+13423 XM
+(kdb_edit)SH
+/Times-Bold SF
+18673 XM
+(to Add Users to the Master Database)SH
+11 /Times-Roman AF
+7200 10362 MT
+(The)SH
+/Times-Italic SF
+9185 XM
+(kdb_edit)SH
+/Times-Roman SF
+13248 XM
+(program is used to add new users and services to the master database, and to modify)SH
+7200 11558 MT
+(existing database information.  The program prompts you to enter a principal's)SH
+/Times-Bold SF
+42177 XM
+(name)SH
+/Times-Roman SF
+45018 XM
+(and)SH
+/Times-Bold SF
+46881 XM
+(instance)SH
+/Times-Roman SF
+(.)SH
+7200 13856 MT
+(A principal name is typically a username or a service program's name.  An instance further qualifies the)SH
+7200 15052 MT
+(principal. If)
+275 W( the principal is a service, the instance is used to specify the name of the machine on which)SH
+7200 16248 MT
+(that service runs.  If the principal is a username that has general user privileges, the instance is usually set)SH
+7200 17444 MT
+(to null.)SH
+7200 19742 MT
+(The following example shows how to use)SH
+/Times-Italic SF
+25805 XM
+(kdb_edit)SH
+/Times-Roman SF
+29868 XM
+(to add the user)SH
+/Times-Italic SF
+36588 XM
+(wave)SH
+/Times-Roman SF
+39123 XM
+(to the Kerberos database.)SH
+/Courier SF
+8520 21319 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+([ADMIN_DIR]/kdb_edit)SH
+/Courier SF
+8520 23547 MT
+(Opening database...)SH
+8520 25775 MT
+(Enter Kerberos master key:)SH
+8520 26889 MT
+(Verifying, please re-enter)SH
+8520 28003 MT
+(Enter Kerberos master key:)SH
+8520 29117 MT
+(Current Kerberos master key version is 1)SH
+8520 31345 MT
+(Master key entered.  BEWARE!)SH
+8520 32459 MT
+(Previous or default values are in [brackets] ,)SH
+8520 33573 MT
+(enter return to leave the same, or new value.)SH
+8520 35801 MT
+(Principal name:)SH
+/Times-Bold SF
+19080 XM
+(wave)SH
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter the username.)SH
+/Courier SF
+8520 36915 MT
+(Instance:)SH
+/Times-BoldItalic SF
+28800 XM
+(<-- Enter a null instance.)SH
+/Courier SF
+8520 39143 MT
+(<Not found>, Create [y] ?)SH
+/Times-Bold SF
+25680 XM
+(y)SH
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(The user-instance does not exist.)SH
+30450 40257 MT
+(Enter y to create the user-instance.)SH
+/Courier SF
+8520 41371 MT
+(Principal: wave  Instance:  m_key_v: 1)SH
+8520 42485 MT
+(New Password:)SH
+/Times-BoldItalic SF
+28800 XM
+(<-- Enter the user-instance's password.)SH
+/Courier SF
+8520 43599 MT
+(Verifying, please re-enter)SH
+8520 44713 MT
+(New Password:)SH
+8520 45827 MT
+(Principal's new key version = 1)SH
+8520 46941 MT
+(Expiration date \050enter dd-mm-yy\051 [ 12/31/99 ] ?)SH
+/Times-Bold SF
+39600 XM
+(<--)SH
+/Times-BoldItalic SF
+41619 XM
+(Enter newlines)SH
+/Courier SF
+8520 48055 MT
+(Max ticket lifetime \050*5 minutes\051 [ 255 ] ?)SH
+/Times-Bold SF
+39600 XM
+(<--)SH
+/Times-BoldItalic SF
+41619 XM
+(to get the)SH
+/Courier SF
+8520 49169 MT
+(Attributes [ 0 ] ?)SH
+/Times-Bold SF
+30120 XM
+(<--)SH
+/Times-BoldItalic SF
+32139 XM
+(default values.)SH
+/Courier SF
+8520 50283 MT
+(Edit O.K.)SH
+8520 52511 MT
+(Principal name:)SH
+/Times-BoldItalic SF
+28800 XM
+(<-- Enter a newline to exit the program.)SH
+/Times-Roman SF
+7200 54809 MT
+(Use the)SH
+/Times-Italic SF
+10804 XM
+(kdb_edit)SH
+/Times-Roman SF
+14867 XM
+(utility to add your username to the master database.)SH
+14 /Times-Bold AF
+7200 58627 MT
+(2.4 Starting)
+350 W( the Kerberos Server)SH
+11 /Times-Roman AF
+7200 60822 MT
+(Change directories to the directory in which you have installed the server program)SH
+/Times-Italic SF
+43701 XM
+(kerberos)SH
+/Times-Roman SF
+47824 XM
+(\050the default)SH
+7200 62018 MT
+(directory is)SH
+/Times-Italic SF
+12454 XM
+(/usr/etc)SH
+/Times-Roman SF
+(\051, and start the program as a background process:)SH
+/Courier SF
+8520 63595 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+(./kerberos &)SH
+/Times-Roman SF
+7200 65190 MT
+(If you have used the)SH
+/Times-Italic SF
+16393 XM
+(kstash)SH
+/Times-Roman SF
+19418 XM
+(command to store the master database password, the server will start)SH
+7200 66386 MT
+(automatically. If)
+275 W( you did not use)SH
+/Times-Italic SF
+22048 XM
+(kstash)SH
+/Times-Roman SF
+(, use the following command:)SH
+/Courier SF
+8520 67963 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+(./kerberos -m)SH
+10 /Times-Roman AF
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(4)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 5 6
+BS
+0 SI
+11 /Times-Roman AF
+7200 7955 MT
+(The server will prompt you to enter the master password before actually starting itself.)SH
+14 /Times-Bold AF
+7200 11773 MT
+(2.5 Testing)
+350 W( the Kerberos Server)SH
+11 /Times-Roman AF
+7200 13968 MT
+(Exit the root account and use the)SH
+/Times-Italic SF
+21893 XM
+(kinit)SH
+/Times-Roman SF
+24124 XM
+(command obtain a Kerberos ticket-granting ticket.  This command)SH
+7200 15164 MT
+(creates your ticket file and stores the ticket-granting ticket in it.)SH
+7200 17462 MT
+(If you used the default)SH
+/Times-Italic SF
+17371 XM
+(make install)SH
+/Times-Roman SF
+22993 XM
+(command and directories to install the Kerberos user utilities,)SH
+/Times-Italic SF
+50365 XM
+(kinit)SH
+/Times-Roman SF
+7200 18658 MT
+(will be in the)SH
+/Times-Italic SF
+13250 XM
+(/usr/athena)SH
+/Times-Roman SF
+18537 XM
+(directory. From now on, we'll refer to the Kerberos user commands directory as)SH
+7200 19854 MT
+([K_USER].)SH
+7200 22152 MT
+(Use)SH
+/Times-Italic SF
+9185 XM
+(kinit)SH
+/Times-Roman SF
+11416 XM
+(as follows:)SH
+/Courier SF
+8520 23729 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([K_USER]/kinit)SH
+/Courier SF
+8520 24843 MT
+(MIT Project Athena, \050ariadne\051)SH
+8520 25957 MT
+(Kerberos Initialization)SH
+8520 27071 MT
+(Kerberos name:)SH
+/Times-BoldItalic SF
+18420 XM
+(yourusername)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter your Kerberos username.)SH
+/Courier SF
+8520 28185 MT
+(Password:)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter your Kerberos password.)SH
+/Times-Roman SF
+7200 30483 MT
+(Use the)SH
+/Times-Italic SF
+10804 XM
+(klist)SH
+/Times-Roman SF
+12913 XM
+(program to list the contents of your ticket file.)SH
+/Courier SF
+8520 32060 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([K_USER]/klist)SH
+/Times-Roman SF
+7200 33655 MT
+(The command should display something like the following:)SH
+/Courier SF
+8520 35181 MT
+(Ticket file:)
+SH( /tmp/tkt5555)1980 W
+8520 36295 MT
+(Principal: yourusername@REALMNAME)3300 W
+9840 38523 MT
+(Issued Expires)
+6600 W( Principal)5940 W
+8520 39637 MT
+(May 6)
+660 W( 10:15:23  May  6 18:15:23  krbtgt.REALMNAME@REALMNAME)SH
+/Times-Roman SF
+7200 41935 MT
+(If you have any problems, you can examine the log file)SH
+/Times-Italic SF
+31758 XM
+(/kerberos/kerberos.log)SH
+/Times-Roman SF
+42022 XM
+(on the Kerberos server)SH
+7200 43131 MT
+(machine to see if there was some sort of error.)SH
+16 /Times-Bold AF
+7200 47803 MT
+(3. Setting)
+400 W( up and testing the Administration server)SH
+11 /Times-Roman AF
+7200 49998 MT
+(The procedure for setting up and testing the Kerberos administration server is as follows:)SH
+9400 51949 MT
+(1.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(kdb_edit)SH
+/Times-Roman SF
+18167 XM
+(utility to add your username with an administration instance to the master)SH
+10500 53145 MT
+(database.)SH
+9400 55039 MT
+(2.)SH
+10500 XM
+(Edit the access control lists for the administration server)SH
+9400 56933 MT
+(3.)SH
+10500 XM
+(Start the Kerberos administration server.)SH
+9400 58827 MT
+(4.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(kpasswd)SH
+/Times-Roman SF
+18107 XM
+(command to change your password.)SH
+9400 60721 MT
+(5.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(kadmin)SH
+/Times-Roman SF
+17617 XM
+(command to add new entries to the database.)SH
+9400 62615 MT
+(6.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(kinit)SH
+/Times-Roman SF
+16335 XM
+(command to verify that the)SH
+/Times-Italic SF
+28524 XM
+(kadmin)SH
+/Times-Roman SF
+32037 XM
+(command correctly added new entries to)SH
+10500 63811 MT
+(the database.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(5)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 6 7
+BS
+0 SI
+14 /Times-Bold AF
+7200 8138 MT
+(3.1 Adding)
+350 W( an administration instance for the administrator)SH
+11 /Times-Roman AF
+7200 10333 MT
+(Login to the Kerberos master server machine, and use the)SH
+/Times-Bold SF
+32825 XM
+(su)SH
+/Times-Roman SF
+34140 XM
+(command to become root.  Use the)SH
+/Times-Italic SF
+49780 XM
+(kdb_edit)SH
+/Times-Roman SF
+7200 11529 MT
+(program to create an entry for each administrator with the instance ``)SH
+/Times-BoldItalic SF
+(admin)SH
+/Times-Roman SF
+(''.)SH
+/Courier SF
+8520 13106 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+([ADMIN_DIR]/kdb_edit)SH
+/Courier SF
+8520 15334 MT
+(Opening database...)SH
+8520 17562 MT
+(Enter Kerberos master key:)SH
+8520 18676 MT
+(Verifying, please re-enter)SH
+8520 19790 MT
+(Enter Kerberos master key:)SH
+8520 20904 MT
+(Current Kerberos master key version is 1)SH
+8520 23132 MT
+(Master key entered.  BEWARE!)SH
+8520 24246 MT
+(Previous or default values are in [brackets] ,)SH
+8520 25360 MT
+(enter return to leave the same, or new value.)SH
+8520 27588 MT
+(Principal name:)SH
+/Times-Bold SF
+19080 XM
+(wave)SH
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter the username.)SH
+/Courier SF
+8520 28702 MT
+(Instance:)SH
+/Times-Bold SF
+(admin)SH
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter ``admin''.)SH
+/Courier SF
+8520 30930 MT
+(<Not found>, Create [y] ?)SH
+/Times-Bold SF
+25680 XM
+(y)SH
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(The user-instance does not exist.)SH
+30450 32044 MT
+(Enter y to create the user-instance.)SH
+/Courier SF
+8520 33158 MT
+(Principal: wave  Instance: admin m_key_v: 1)SH
+8520 34272 MT
+(New Password:)SH
+/Times-BoldItalic SF
+28800 XM
+(<-- Enter the user-instance's password.)SH
+/Courier SF
+8520 35386 MT
+(Verifying, please re-enter)SH
+8520 36500 MT
+(New Password:)SH
+8520 37614 MT
+(Principal's new key version = 1)SH
+8520 38728 MT
+(Expiration date \050enter dd-mm-yy\051 [ 12/31/99 ] ?)SH
+/Times-Bold SF
+39600 XM
+(<--)SH
+/Times-BoldItalic SF
+41619 XM
+(Enter newlines)SH
+/Courier SF
+8520 39842 MT
+(Max ticket lifetime \050*5 minutes\051 [ 255 ] ?)SH
+/Times-Bold SF
+39600 XM
+(<--)SH
+/Times-BoldItalic SF
+41619 XM
+(to get the)SH
+/Courier SF
+8520 40956 MT
+(Attributes [ 0 ] ?)SH
+/Times-Bold SF
+30120 XM
+(<--)SH
+/Times-BoldItalic SF
+32139 XM
+(default values.)SH
+/Courier SF
+8520 42070 MT
+(Edit O.K.)SH
+8520 44298 MT
+(Principal name:)SH
+/Times-BoldItalic SF
+28800 XM
+(<-- Enter a newline to exit the program.)SH
+14 /Times-Bold AF
+7200 48116 MT
+(3.2 The)
+350 W( Access Control Lists)SH
+11 /Times-Roman AF
+7200 50311 MT
+(The Kerberos administration server uses three access control lists to determine who is authorized to make)SH
+7200 51507 MT
+(certain requests.  The access control lists are stored on the master Kerberos server in the same directory as)SH
+7200 52703 MT
+(the principal database,)SH
+/Times-Italic SF
+17340 XM
+(/kerberos)SH
+/Times-Roman SF
+(. The)
+275 W( access control lists are simple ASCII text files, with each line)SH
+7200 53899 MT
+(specifying the name of one principal who is allowed the particular function.  To allow several people to)SH
+7200 55095 MT
+(perform the same function, put their principal names on separate lines in the same file.)SH
+7200 57393 MT
+(The first list,)SH
+/Times-Italic SF
+13128 XM
+(/kerberos/admin_acl.mod)SH
+/Times-Roman SF
+(, is a list of principals which are authorized to change entries in the)SH
+7200 58589 MT
+(database. To)
+275 W( allow the administrator `)SH
+/Times-Bold SF
+(wave)SH
+/Times-Roman SF
+(' to modify entries in the database for the realm `)SH
+/Times-Bold SF
+(TIM.EDU)SH
+/Times-Roman SF
+(',)SH
+7200 59785 MT
+(you would put the following line into the file)SH
+/Times-Italic SF
+27275 XM
+(/kerberos/admin_acl.mod)SH
+/Times-Roman SF
+(:)SH
+/Courier SF
+8520 61311 MT
+(wave.admin@TIM.EDU)SH
+/Times-Roman SF
+7200 63609 MT
+(The second list,)SH
+/Times-Italic SF
+14410 XM
+(/kerberos/admin_acl.get)SH
+/Times-Roman SF
+(, is a list of principals which are authorized to retrieve entries)SH
+7200 64805 MT
+(from the database.)SH
+7200 67103 MT
+(The third list,)SH
+/Times-Italic SF
+13434 XM
+(/kerberos/admin_acl.add)SH
+/Times-Roman SF
+(, is a list of principals which are authorized to add new entries to)SH
+7200 68299 MT
+(the database.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(6)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 7 8
+BS
+0 SI
+14 /Times-Bold AF
+7200 8138 MT
+(3.3 Starting)
+350 W( the administration server)SH
+11 /Times-Roman AF
+7200 10333 MT
+(Change directories to the directory in which you have installed the administration server program)SH
+/Times-Italic SF
+7200 11529 MT
+(kadmind)SH
+/Times-Roman SF
+11263 XM
+(\050the default directory is)SH
+/Times-Italic SF
+21831 XM
+(/usr/etc)SH
+/Times-Roman SF
+(\051, and start the program as a background process:)SH
+/Courier SF
+8520 13106 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+(./kadmind -n&)SH
+/Times-Roman SF
+7200 14701 MT
+(If you have used the)SH
+/Times-Italic SF
+16393 XM
+(kstash)SH
+/Times-Roman SF
+19418 XM
+(command to store the master database password, the server will start)SH
+7200 15897 MT
+(automatically. If)
+275 W( you did not use)SH
+/Times-Italic SF
+22048 XM
+(kstash)SH
+/Times-Roman SF
+(, use the following command:)SH
+/Courier SF
+8520 17474 MT
+(host#)SH
+/Times-Bold SF
+12480 XM
+(./kadmind)SH
+/Times-Roman SF
+7200 19069 MT
+(The server will prompt you to enter the master password before actually starting itself; after it starts, you)SH
+7200 20265 MT
+(should suspend it and put it in the background \050usually this is done by typing control-Z and then)SH
+/Times-Bold SF
+49792 XM
+(bg)SH
+/Times-Roman SF
+(\051.)SH
+14 /Times-Bold AF
+7200 24112 MT
+(3.4 Testing)350 W
+/Times-BoldItalic SF
+14434 XM
+(kpasswd)SH
+11 /Times-Roman AF
+7200 26307 MT
+(To test the administration server, you should try changing your password with the)SH
+/Times-Italic SF
+43494 XM
+(kpasswd)SH
+/Times-Roman SF
+47497 XM
+(command, and)SH
+7200 27503 MT
+(you should try adding new users with the)SH
+/Times-Italic SF
+25592 XM
+(kadmin)SH
+/Times-Roman SF
+29105 XM
+(command \050both commands are installed into)SH
+/Times-Italic SF
+48963 XM
+(/usr/athena)SH
+/Times-Roman SF
+7200 28699 MT
+(by default\051.)SH
+7200 30997 MT
+(Before testing, you should exit the root account.)SH
+7200 33295 MT
+(To change your password, run the)SH
+/Times-Italic SF
+22441 XM
+(kpasswd)SH
+/Times-Roman SF
+26444 XM
+(command:)SH
+/Courier SF
+8520 34872 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([K_USER]/kpasswd)SH
+/Courier SF
+8520 35986 MT
+(Old password for wave@TIM.EDU:)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+(Enter your password)SH
+/Courier SF
+8520 37100 MT
+(New Password for wave@TIM.EDU:)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+(Enter a new password)SH
+/Courier SF
+8520 38214 MT
+(Verifying, please re-enter New Password for wave@TIM.EDU:)SH
+/Times-Bold SF
+28800 39328 MT
+(<--)SH
+/Times-BoldItalic SF
+(Enter new password again)SH
+/Courier SF
+8520 40442 MT
+(Password changed.)SH
+/Times-Roman SF
+7200 42037 MT
+(Once you have changed your password, use the)SH
+/Times-Italic SF
+28365 XM
+(kinit)SH
+/Times-Roman SF
+30596 XM
+(program as shown above to verify that the password)SH
+7200 43233 MT
+(was properly changed.)SH
+14 /Times-Bold AF
+7200 47080 MT
+(3.5 Testing)350 W
+/Times-BoldItalic SF
+14434 XM
+(kadmin)SH
+11 /Times-Roman AF
+7200 49275 MT
+(You should also test the function of the)SH
+/Times-Italic SF
+24798 XM
+(kadmin)SH
+/Times-Roman SF
+28311 XM
+(program, by adding a new user \050here named)SH
+7200 50471 MT
+(``)SH
+/Courier SF
+(username)SH
+/Times-Roman SF
+(''\051:)SH
+/Courier SF
+8520 52048 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([K_USER]/kadmin)SH
+/Courier SF
+8520 53162 MT
+(Welcome to the Kerberos Administration Program, version 2)SH
+8520 54276 MT
+(Type "help" if you need it.)SH
+8520 55390 MT
+(admin:)SH
+/Times-Bold SF
+13800 XM
+(ank username)SH
+/Times-BoldItalic SF
+28800 XM
+(`ank' stands for Add New Key)SH
+/Courier SF
+8520 56504 MT
+(Admin password:)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+(enter the password)SH
+28800 57618 MT
+(you chose above for wave.admin)SH
+/Courier SF
+8520 58732 MT
+(Password for username:)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+(Enter the user's initial password)SH
+/Courier SF
+8520 59846 MT
+(Verifying, please re-enter Password for username:)SH
+/Times-Bold SF
+40920 XM
+(<--)SH
+/Times-BoldItalic SF
+(enter it again)SH
+/Courier SF
+8520 60960 MT
+(username added to database.)SH
+8520 63188 MT
+(admin: quit)660 W
+8520 64302 MT
+(Cleaning up and exiting.)SH
+10 /Times-Roman AF
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(7)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 8 9
+BS
+0 SI
+14 /Times-Bold AF
+7200 8167 MT
+(3.6 Verifying)
+350 W( with)SH
+/Times-BoldItalic SF
+18671 XM
+(kinit)SH
+11 /Times-Roman AF
+7200 10362 MT
+(Once you've added a new user, you should test to make sure it was added properly by using)SH
+/Times-Italic SF
+47917 XM
+(kinit)SH
+/Times-Roman SF
+(, and)SH
+7200 11558 MT
+(trying to get tickets for that user:)SH
+/Courier SF
+8520 13135 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([K_USER]/kinit username)SH
+/Courier SF
+8520 14249 MT
+(MIT Project Athena \050ariadne\051)SH
+8520 15363 MT
+(Kerberos Initialization for "username@TIM.EDU")SH
+8520 16477 MT
+(Password:)SH
+/Times-Bold SF
+15120 XM
+(<--)SH
+/Times-BoldItalic SF
+(Enter the user's password you used above)SH
+/Courier SF
+8520 17591 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([K_USER]/klist)SH
+/Courier SF
+8520 18705 MT
+(Ticket file:)
+SH( /tmp/tkt_5509_spare1)1980 W
+8520 19819 MT
+(Principal: username@TIM.MIT.EDU)3300 W
+9840 22047 MT
+(Issued Expires)
+6600 W( Principal)5940 W
+8520 23161 MT
+(Nov 20 15:58:52  Nov 20 23:58:52  krbtgt.TIM.EDU@TIM.EDU)SH
+/Times-Roman SF
+7200 25459 MT
+(If you have any problems, you can examine the log files)SH
+/Times-Italic SF
+32186 XM
+(/kerberos/kerberos.log)SH
+/Times-Roman SF
+42450 XM
+(and)SH
+/Times-Italic SF
+7200 26655 MT
+(/kerberos/admin_server.syslog)SH
+/Times-Roman SF
+21008 XM
+(on the Kerberos server machine to see if there was some sort of error.)SH
+16 /Times-Bold AF
+7200 31327 MT
+(4. Setting)
+400 W( up and testing slave server\050s\051)SH
+11 /Times-Roman AF
+7200 33522 MT
+([Unfortunately, this chapter is not yet ready.  Sorry. -ed])SH
+16 /Times-Bold AF
+7200 38194 MT
+(5. A)
+400 W( Sample Application)SH
+11 /Times-Roman AF
+7200 40389 MT
+(This release of Kerberos comes with a sample application server and a corresponding client program.)SH
+7200 41585 MT
+(You will find this software in the [OBJ_DIR])SH
+/Times-Italic SF
+(/appl/sample)SH
+/Times-Roman SF
+33170 XM
+(directory. The)
+275 W( file)SH
+/Times-Italic SF
+41691 XM
+(sample_client)SH
+/Times-Roman SF
+48076 XM
+(contains the)SH
+7200 42781 MT
+(client program's executable code, the file)SH
+/Times-Italic SF
+25677 XM
+(sample_server)SH
+/Times-Roman SF
+32366 XM
+(contains the server's executable.)SH
+7200 45079 MT
+(The programs are rudimentary.  When they have been installed \050the installation procedure is described in)SH
+7200 46275 MT
+(detail later\051, they work as follows:)SH
+/Symbol SF
+9169 48351 MT
+(\267)SH
+/Times-Roman SF
+9950 XM
+(The user starts)SH
+/Times-Italic SF
+16639 XM
+(sample_client)SH
+/Times-Roman SF
+23024 XM
+(and provides as arguments to the command the name of the)SH
+9950 49547 MT
+(server machine and a checksum.  For instance:)SH
+/Courier SF
+11270 51147 MT
+(host%)SH
+/Times-Bold SF
+15230 XM
+(sample_client)SH
+/Times-BoldItalic SF
+22966 XM
+(servername 43)385 W
+/Symbol SF
+9169 53041 MT
+(\267)SH
+/Times-Italic SF
+9950 XM
+(Sample_client)SH
+/Times-Roman SF
+16457 XM
+(contacts the server machine and authenticates the user to)SH
+/Times-Italic SF
+41654 XM
+(sample_server)SH
+/Times-Roman SF
+(.)SH
+/Symbol SF
+9169 54935 MT
+(\267)SH
+/Times-Italic SF
+9950 XM
+(Sample_server)SH
+/Times-Roman SF
+16761 XM
+(authenticates itself to)SH
+/Times-Italic SF
+26384 XM
+(sample_client)SH
+/Times-Roman SF
+(, then returns a message to the client)SH
+9950 56131 MT
+(program. This)
+275 W( message contains diagnostic information that includes the user's username,)SH
+9950 57327 MT
+(the Kerberos realm, and the user's workstation address.)SH
+/Symbol SF
+9169 59221 MT
+(\267)SH
+/Times-Italic SF
+9950 XM
+(Sample_client)SH
+/Times-Roman SF
+16457 XM
+(displays the server's message on the user's terminal screen.)SH
+14 /Times-Bold AF
+7200 63039 MT
+(5.1 The)
+350 W( Installation Process)SH
+11 /Times-Roman AF
+7200 65234 MT
+(In general, you use the following procedure to install a Kerberos-authenticated server-client system.)SH
+9400 67185 MT
+(1.)SH
+10500 XM
+(Add the appropriate entry to the Kerberos database using)SH
+/Times-Italic SF
+35881 XM
+(kdb_edit)SH
+/Times-Roman SF
+39944 XM
+(or)SH
+/Times-Italic SF
+41135 XM
+(kadmin)SH
+/Times-Roman SF
+44648 XM
+(\050described)SH
+10500 68381 MT
+(below\051.)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(8)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 9 10
+BS
+0 SI
+11 /Times-Roman AF
+9400 7955 MT
+(2.)SH
+10500 XM
+(Create a)SH
+/Times-Italic SF
+14408 XM
+(/etc/srvtab)SH
+/Times-Roman SF
+19327 XM
+(file for the server machine.)SH
+9400 9849 MT
+(3.)SH
+10500 XM
+(Install the service program and the)SH
+/Times-Italic SF
+26016 XM
+(/etc/srvtab)SH
+/Times-Roman SF
+30935 XM
+(file on the server machine.)SH
+9400 11743 MT
+(4.)SH
+10500 XM
+(Install the client program on the client machine.)SH
+9400 13637 MT
+(5.)SH
+10500 XM
+(Update the)SH
+/Times-Italic SF
+15570 XM
+(/etc/services)SH
+/Times-Roman SF
+21281 XM
+(file on the client and server machines.)SH
+7200 15935 MT
+(We will use the sample application as an example, although the procedure used to install)SH
+/Times-Italic SF
+46484 XM
+(sample_server)SH
+/Times-Roman SF
+7200 17131 MT
+(differs slightly from the general case because the)SH
+/Times-Italic SF
+29006 XM
+(sample_server)SH
+/Times-Roman SF
+35695 XM
+(takes requests via the)SH
+/Times-Italic SF
+45347 XM
+(inetd)SH
+/Times-Roman SF
+47822 XM
+(program.)SH
+/Times-Italic SF
+7200 18327 MT
+(Inetd)SH
+/Times-Roman SF
+9735 XM
+(starts)SH
+/Times-Italic SF
+12332 XM
+(sample_server)SH
+/Times-Roman SF
+19021 XM
+(each time a client process contacts the server machine.)SH
+/Times-Italic SF
+43606 XM
+(Sample_server)SH
+/Times-Roman SF
+7200 19523 MT
+(processes the request, terminiates, then is restarted when)SH
+/Times-Italic SF
+32368 XM
+(inetd)SH
+/Times-Roman SF
+34843 XM
+(receives another)SH
+/Times-Italic SF
+42293 XM
+(sample_client)SH
+/Times-Roman SF
+48678 XM
+(request.)SH
+7200 20719 MT
+(When you install the program on the server, you must add a)SH
+/Times-Italic SF
+33807 XM
+(sample)SH
+/Times-Roman SF
+37198 XM
+(entry to the server machine's)SH
+/Times-Italic SF
+7200 21915 MT
+(/etc/inetd.conf)SH
+/Times-Roman SF
+13738 XM
+(file.)SH
+7200 24213 MT
+(The following description assumes that you are installing)SH
+/Times-Italic SF
+32680 XM
+(sample_server)SH
+/Times-Roman SF
+39369 XM
+(on the machine)SH
+/Times-Italic SF
+46364 XM
+(ariadne.tim.edu)SH
+/Times-Roman SF
+(.)SH
+7200 25409 MT
+(Here's the process, step by step:)SH
+9400 27360 MT
+(1.)SH
+10500 XM
+(Login as or)SH
+/Times-Italic SF
+15785 XM
+(su)SH
+/Times-Roman SF
+17038 XM
+(to root on the Kerberos server machine.  Use the)SH
+/Times-Italic SF
+38631 XM
+(kdb_edit)SH
+/Times-Roman SF
+42694 XM
+(or)SH
+/Times-Italic SF
+43885 XM
+(kadmin)SH
+/Times-Roman SF
+47398 XM
+(program)SH
+10500 28556 MT
+(to create an entry for)SH
+/Times-Italic SF
+19935 XM
+(sample)SH
+/Times-Roman SF
+23326 XM
+(in the Kerberos database:)SH
+/Courier SF
+11820 30133 MT
+(host#)SH
+/Times-Bold SF
+15780 XM
+([ADMIN_DIR]/kdb_edit)SH
+/Courier SF
+11820 32361 MT
+(Opening database...)SH
+11820 34589 MT
+(Enter Kerberos master key:)SH
+11820 35703 MT
+(Verifying, please re-enter)SH
+11820 36817 MT
+(master key entered.  BEWARE!)SH
+11820 37931 MT
+(Previous or default values are in [brackets] ,)SH
+11820 39045 MT
+(enter return to leave the same, or new value.)SH
+11820 41273 MT
+(Principal name:)SH
+/Times-Bold SF
+22380 XM
+(sample)SH
+26220 XM
+(<--)SH
+/Times-BoldItalic SF
+28239 XM
+(Enter the principal name.)SH
+/Courier SF
+11820 42387 MT
+(Instance:)SH
+/Times-Bold SF
+18420 XM
+(ariadne)SH
+26220 XM
+(<--)SH
+/Times-BoldItalic SF
+28239 XM
+(Instances cannot have periods in them.)SH
+/Courier SF
+11820 44615 MT
+(<Not found>, Create [y] ?)SH
+/Times-Bold SF
+28980 XM
+(y)SH
+/Courier SF
+11820 46843 MT
+(Principal: sample_server  Instance: ariadne m_key_v: 1)SH
+11820 47957 MT
+(New Password:)SH
+/Times-Bold SF
+26220 XM
+(<--)SH
+/Times-BoldItalic SF
+28239 XM
+(Enter ``RANDOM'' to get random password.)SH
+/Courier SF
+11820 49071 MT
+(Verifying, please re-enter)SH
+11820 50185 MT
+(New Password:)SH
+/Times-Bold SF
+26220 XM
+(<--)SH
+/Times-BoldItalic SF
+28239 XM
+(Enter ``RANDOM'' again.)SH
+/Courier SF
+11820 51299 MT
+(Random password [y] ?)SH
+/Times-Bold SF
+26340 XM
+(y)SH
+/Courier SF
+11820 53527 MT
+(Principal's new key version = 1)SH
+11820 54641 MT
+(Expiration date \050enter dd-mm-yy\051 [ 12/31/99 ] ?)SH
+11820 55755 MT
+(Max ticket lifetime \050*5 minutes\051 [ 255 ] ?)SH
+11820 56869 MT
+(Attributes [ 0 ] ?)SH
+11820 57983 MT
+(Edit O.K.)SH
+11820 60211 MT
+(Principal name:)SH
+/Times-Bold SF
+26220 XM
+(<--)SH
+/Times-BoldItalic SF
+28239 XM
+(Enter newline to exit kdb_edit.)SH
+/Times-Roman SF
+9400 62105 MT
+(2.)SH
+10500 XM
+(Use the)SH
+/Times-Italic SF
+14104 XM
+(ext_srvtab)SH
+/Times-Roman SF
+18961 XM
+(program to create a)SH
+/Times-Italic SF
+27755 XM
+(srvtab)SH
+/Times-Roman SF
+30780 XM
+(file for)SH
+/Times-Italic SF
+34078 XM
+(sample_server)SH
+/Times-Roman SF
+('s host machine:)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30350 XM
+(9)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 10 11
+BS
+0 SI
+11 /Courier AF
+11820 7937 MT
+(host#)SH
+/Times-Bold SF
+15780 XM
+([ADMIN_DIR]/ext_srvtab ariadne)275 W
+/Courier SF
+11820 10165 MT
+(Enter Kerberos master key:)SH
+11820 11279 MT
+(Current Kerberos master key version is 1.)SH
+11820 13507 MT
+(Generating 'ariadne-new-srvtab'....)SH
+/Times-Roman SF
+10500 15102 MT
+(Transfer the)SH
+/Times-Italic SF
+16118 XM
+(ariadne-new-srvtab)SH
+/Times-Roman SF
+25069 XM
+(file to)SH
+/Times-Italic SF
+27941 XM
+(ariadne)SH
+/Times-Roman SF
+31638 XM
+(and install it as)SH
+/Times-Italic SF
+38544 XM
+(/etc/srvtab)SH
+/Times-Roman SF
+(. Note)
+275 W( that this)SH
+10500 16298 MT
+(file is equivalent to the service's password and should be treated with care.  For example, it)SH
+10500 17494 MT
+(could be transferred by removable media, but should not be sent over an open network in)SH
+10500 18690 MT
+(the clear.  Once installed, this file should be readable only by root.)SH
+9400 20584 MT
+(3.)SH
+10500 XM
+(Add the following line to the)SH
+/Times-Italic SF
+23516 XM
+(/etc/services)SH
+/Times-Roman SF
+29227 XM
+(file on)SH
+/Times-Italic SF
+32343 XM
+(ariadne)SH
+/Times-Roman SF
+(, and on all machines that will run)SH
+10500 21780 MT
+(the)SH
+/Times-Italic SF
+12119 XM
+(sample_client)SH
+/Times-Roman SF
+18504 XM
+(program:)SH
+/Courier SF
+11820 23306 MT
+(sample 906/tcp)
+2640 W( #)
+3960 W( Kerberos sample app server)SH
+/Times-Roman SF
+9400 25200 MT
+(4.)SH
+10500 XM
+(Add a line similar to the following line to the)SH
+/Times-Italic SF
+30666 XM
+(/etc/inetd.conf)SH
+/Times-Roman SF
+37204 XM
+(file on)SH
+/Times-Italic SF
+40320 XM
+(sample_server)SH
+/Times-Roman SF
+('s)SH
+10500 26396 MT
+(machine:)SH
+/Courier SF
+11820 27922 MT
+(sample stream tcp nowait switched root)1320 W
+14460 29036 MT
+([PATH]/sample_server sample_server)SH
+/Times-Roman SF
+10500 30631 MT
+(where [PATH] should be substituted with the path to the)SH
+/Times-Italic SF
+35674 XM
+(sample_server)SH
+/Times-Roman SF
+42363 XM
+(program. \050This)275 W
+/Times-Italic SF
+10500 31827 MT
+(inetd.conf)SH
+/Times-Roman SF
+15144 XM
+(information should be placed on one line.\051  You should examine existing lines in)SH
+/Times-Italic SF
+10500 33023 MT
+(/etc/inetd.conf)SH
+/Times-Roman SF
+17038 XM
+(and use the same format used by other entries \050e.g. for telnet\051.  Most systems)SH
+10500 34219 MT
+(do not have a column for the `switched' keyword, and some do not have a column for the)SH
+10500 35415 MT
+(username \050usually `root', as above\051.)SH
+9400 37309 MT
+(5.)SH
+10500 XM
+(Restart)SH
+/Times-Italic SF
+13891 XM
+(inetd)SH
+/Times-Roman SF
+16366 XM
+(by sending the current)SH
+/Times-Italic SF
+26446 XM
+(inetd)SH
+/Times-Roman SF
+28921 XM
+(process a hangup signal:)SH
+/Courier SF
+11820 38909 MT
+(host#)SH
+/Times-Bold SF
+15780 XM
+(kill -HUP)275 W
+/Times-BoldItalic SF
+21373 XM
+(process_id_number)SH
+/Times-Roman SF
+9400 40803 MT
+(6.)SH
+10500 XM
+(The)SH
+/Times-Italic SF
+12485 XM
+(sample_server)SH
+/Times-Roman SF
+19174 XM
+(is now ready to take)SH
+/Times-Italic SF
+28307 XM
+(sample_client)SH
+/Times-Roman SF
+34692 XM
+(requests.)SH
+14 /Times-Bold AF
+7200 44621 MT
+(5.2 Testing)
+350 W( the Sample Server)SH
+11 /Times-Roman AF
+7200 46816 MT
+(Assume that you have installed)SH
+/Times-Italic SF
+21223 XM
+(sample_server)SH
+/Times-Roman SF
+27912 XM
+(on)SH
+/Times-Italic SF
+29287 XM
+(ariadne)SH
+/Times-Roman SF
+(.)SH
+7200 49114 MT
+(Login to your workstation and use the)SH
+/Times-Italic SF
+24217 XM
+(kinit)SH
+/Times-Roman SF
+26448 XM
+(command to obtain a Kerberos ticket-granting ticket:)SH
+/Courier SF
+8520 50691 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([K_USER]/kinit)SH
+/Courier SF
+8520 51805 MT
+(MIT Project Athena, \050your_workstation\051)SH
+8520 52919 MT
+(Kerberos Initialization)SH
+8520 54033 MT
+(Kerberos name:)SH
+/Times-BoldItalic SF
+18420 XM
+(yourusername)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter your Kerberos username.)SH
+/Courier SF
+8520 55147 MT
+(Password:)SH
+/Times-Bold SF
+28800 XM
+(<--)SH
+/Times-BoldItalic SF
+30819 XM
+(Enter your Kerberos password.)SH
+/Times-Roman SF
+7200 57445 MT
+(Now use the)SH
+/Times-Italic SF
+12973 XM
+(sample_client)SH
+/Times-Roman SF
+19358 XM
+(program as follows:)SH
+/Courier SF
+8520 59022 MT
+(host%)SH
+/Times-Bold SF
+12480 XM
+([PATH]/sample_client ariadne)275 W
+/Times-Roman SF
+7200 60617 MT
+(The command should display something like the following:)SH
+/Courier SF
+8520 62143 MT
+(The server says:)SH
+8520 63257 MT
+(You are)SH
+/Times-BoldItalic SF
+13800 XM
+(yourusername)SH
+/Courier SF
+(.@REALMNAME \050local name)SH
+/Times-BoldItalic SF
+36180 XM
+(yourusername)SH
+/Courier SF
+(\051,)SH
+9180 64371 MT
+(at address)SH
+/Times-BoldItalic SF
+16440 XM
+(yournetaddress)SH
+/Courier SF
+(, version VERSION9, cksum 997)SH
+10 /Times-Roman AF
+7200 75600 MT
+(MIT Project Athena)SH
+30100 XM
+(10)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: 11 12
+BS
+0 SI
+16 /Times-Bold AF
+7200 8272 MT
+(6. Service)
+400 W( names and other services)SH
+14 SS 
+7200 12090 MT
+(6.1 rlogin,)
+350 W( rsh, rcp, tftp, and others)SH
+11 /Times-Roman AF
+7200 14285 MT
+(Many services use a common principal name for authentication purposes.)SH
+/Times-Italic SF
+40128 XM
+(rlogin)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+43368 XM
+(rsh)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+45324 XM
+(rcp)SH
+/Times-Roman SF
+(,)SH
+/Times-Italic SF
+47340 XM
+(tftp)SH
+/Times-Roman SF
+49083 XM
+(and others)SH
+7200 15481 MT
+(use the principal name ``)SH
+/Courier SF
+(rcmd)SH
+/Times-Roman SF
+(''. For)
+275 W( example, to set up the machine)SH
+/Times-Italic SF
+38033 XM
+(ariadne)SH
+/Times-Roman SF
+41730 XM
+(to support Kerberos rlogin,)SH
+7200 16677 MT
+(it needs to have a service key for principal ``)SH
+/Courier SF
+(rcmd)SH
+/Times-Roman SF
+('', instance ``)SH
+/Courier SF
+(ariadne)SH
+/Times-Roman SF
+(''. You)
+275 W( create this key in the)SH
+7200 17873 MT
+(same way as shown above for the sample service.)SH
+7200 20171 MT
+(After creating this key, you need to run the)SH
+/Times-Italic SF
+26382 XM
+(ext_srvtab)SH
+/Times-Roman SF
+31239 XM
+(program again to generate a new srvtab file for)SH
+7200 21367 MT
+(ariadne.)SH
+14 /Times-Bold AF
+7200 25185 MT
+(6.2 NFS)
+350 W( modifications)SH
+11 /Times-Roman AF
+7200 27380 MT
+(The NFS modifications distributed separately use the service name ``)SH
+/Courier SF
+(rvdsrv)SH
+/Times-Roman SF
+('' with the instance set to)SH
+7200 28576 MT
+(the machine name \050as for the sample server and the rlogin, rsh, rcp and tftp services\051.)SH
+14 /Times-Bold AF
+7200 32394 MT
+(6.3 inetd.conf)
+350 W( entries)SH
+11 /Times-Roman AF
+7200 34589 MT
+(The following are the)SH
+/Times-Italic SF
+16974 XM
+(/etc/inetd.conf)SH
+/Times-Roman SF
+23512 XM
+(entries necessary to support rlogin, encrypted rlogin, rsh, and rcp)SH
+7200 35785 MT
+(services on a server machine.  As above, your)SH
+/Times-Italic SF
+27631 XM
+(inetd.conf)SH
+/Times-Roman SF
+32275 XM
+(may not support all the fields shown here.)SH
+/Courier SF
+8520 37311 MT
+(eklogin stream)
+660 W( tcp nowait unswitched root)1320 W
+11160 38425 MT
+([PATH]/klogind eklogind)1320 W
+8520 39539 MT
+(kshell stream tcp nowait unswitched root)1320 W
+11160 40653 MT
+([PATH]/kshd kshd)1320 W
+8520 41767 MT
+(klogin stream tcp nowait unswitched root)1320 W
+11160 42881 MT
+([PATH]/klogind klogind)1320 W
+10 /Times-Roman AF
+7200 75600 MT
+(MIT Project Athena)SH
+30100 XM
+(11)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Page: i 13
+BS
+0 SI
+14 /Times-Bold AF
+25272 8138 MT
+(Table of Contents)SH
+13 SS 
+7200 9781 MT
+(1. How)
+325 W( Kerberos Works: A Schematic Description)SH
+53350 XM
+(1)SH
+12 /Times-Roman AF
+9000 11130 MT
+(1.1 Network)
+300 W( Services and Their Client Programs)SH
+53400 XM
+(1)SH
+9000 12479 MT
+(1.2 Kerberos)
+300 W( Tickets)SH
+53400 XM
+(1)SH
+9000 13828 MT
+(1.3 The)
+300 W( Kerberos Master Database)SH
+53400 XM
+(1)SH
+9000 15177 MT
+(1.4 The)
+300 W( Ticket-Granting Ticket)SH
+53400 XM
+(1)SH
+9000 16526 MT
+(1.5 Network)
+300 W( Services and the Master Database)SH
+53400 XM
+(1)SH
+9000 17875 MT
+(1.6 The)
+300 W( User-Kerberos Interaction)SH
+53400 XM
+(2)SH
+13 /Times-Bold AF
+7200 19518 MT
+(2. Setting)
+325 W( Up and Testing the Kerberos Server)SH
+53350 XM
+(2)SH
+12 /Times-Roman AF
+9000 20867 MT
+(2.1 Creating)
+300 W( and Initializing the Master Database)SH
+53400 XM
+(3)SH
+9000 22216 MT
+(2.2 Storing)
+300 W( the Master Password)SH
+53400 XM
+(3)SH
+9000 23571 MT
+(2.3 Using)300 W
+/Times-BoldItalic SF
+14267 XM
+(kdb_edit)SH
+/Times-Roman SF
+18768 XM
+(to Add Users to the Master Database)SH
+53400 XM
+(4)SH
+9000 24920 MT
+(2.4 Starting)
+300 W( the Kerberos Server)SH
+53400 XM
+(4)SH
+9000 26269 MT
+(2.5 Testing)
+300 W( the Kerberos Server)SH
+53400 XM
+(5)SH
+13 /Times-Bold AF
+7200 27912 MT
+(3. Setting)
+325 W( up and testing the Administration server)SH
+53350 XM
+(5)SH
+12 /Times-Roman AF
+9000 29261 MT
+(3.1 Adding)
+300 W( an administration instance for the administrator)SH
+53400 XM
+(6)SH
+9000 30610 MT
+(3.2 The)
+300 W( Access Control Lists)SH
+53400 XM
+(6)SH
+9000 31959 MT
+(3.3 Starting)
+300 W( the administration server)SH
+53400 XM
+(7)SH
+9000 33314 MT
+(3.4 Testing)300 W
+/Times-BoldItalic SF
+15001 XM
+(kpasswd)SH
+/Times-Roman SF
+53400 XM
+(7)SH
+9000 34669 MT
+(3.5 Testing)300 W
+/Times-BoldItalic SF
+15001 XM
+(kadmin)SH
+/Times-Roman SF
+53400 XM
+(7)SH
+9000 36024 MT
+(3.6 Verifying)
+300 W( with)SH
+/Times-BoldItalic SF
+18501 XM
+(kinit)SH
+/Times-Roman SF
+53400 XM
+(8)SH
+13 /Times-Bold AF
+7200 37667 MT
+(4. Setting)
+325 W( up and testing slave server\050s\051)SH
+53350 XM
+(8)SH
+7200 39310 MT
+(5. A)
+325 W( Sample Application)SH
+53350 XM
+(8)SH
+12 /Times-Roman AF
+9000 40659 MT
+(5.1 The)
+300 W( Installation Process)SH
+53400 XM
+(8)SH
+9000 42008 MT
+(5.2 Testing)
+300 W( the Sample Server)SH
+52800 XM
+(10)SH
+13 /Times-Bold AF
+7200 43651 MT
+(6. Service)
+325 W( names and other services)SH
+52700 XM
+(11)SH
+12 /Times-Roman AF
+9000 45000 MT
+(6.1 rlogin,)
+300 W( rsh, rcp, tftp, and others)SH
+52800 XM
+(11)SH
+9000 46349 MT
+(6.2 NFS)
+300 W( modifications)SH
+52800 XM
+(11)SH
+9000 47698 MT
+(6.3 inetd.conf)
+300 W( entries)SH
+52800 XM
+(11)SH
+10 SS 
+7200 75600 MT
+(MIT Project Athena)SH
+30461 XM
+(i)SH
+47890 XM
+(4 January 1990)SH
+ES
+%%Trailer
+%%Pages: 13
+%%DocumentFonts: Times-Roman Times-Bold Times-Italic Times-BoldItalic Courier Symbol
diff --git a/mechglue/doc/old-V4-docs/operation.mss b/mechglue/doc/old-V4-docs/operation.mss
new file mode 100644
index 000000000..a35bb9f95
--- /dev/null
+++ b/mechglue/doc/old-V4-docs/operation.mss
@@ -0,0 +1,799 @@
+@Comment[	$Source$]
+@Comment[	$Author$]
+@Comment[	$Id$]
+@Comment[]
+@device[postscript]
+@make[report]
+@comment[
+@DefineFont(HeadingFont,
+      P=<RawFont "NewCenturySchlbkBoldItalic">,
+      B=<RawFont "NewCenturySchlbkBold">,
+      I=<RawFont "NewCenturySchlbkBoldItalic">,
+      R=<RawFont "NewCenturySchlbkRoman">)
+]
+@DefineFont(HeadingFont,
+      P=<RawFont "TimesBoldItalic">,
+      B=<RawFont "TimesBold">,
+      I=<RawFont "TimesItalic">,
+      R=<RawFont "TimesRoman">)
+@Counter(MajorPart,TitleEnv HD0,ContentsEnv tc0,Numbered [@I],
+          IncrementedBy Use,Announced)
+@Counter(Chapter,TitleEnv HD1,ContentsEnv tc1,Numbered [@1. ],
+          IncrementedBy Use,Referenced [@1],Announced)
+@Counter(Appendix,TitleEnv HD1,ContentsEnv tc1,Numbered [@A. ],
+          IncrementedBy,Referenced [@A],Announced,Alias Chapter)
+@Counter(UnNumbered,TitleEnv HD1,ContentsEnv tc1,Announced,Alias 
+           Chapter)
+@Counter(Section,Within Chapter,TitleEnv HD2,ContentsEnv tc2,
+          Numbered [@#@:.@1 ],Referenced [@#@:.@1],IncrementedBy
+          Use,Announced)
+@Counter(AppendixSection,Within Appendix,TitleEnv HD2,
+          ContentsEnv tc2,
+          Numbered [@#@:.@1 ],Referenced [@#@:.@1],IncrementedBy 
+          Use,Announced)
+@Counter(SubSection,Within Section,TitleEnv HD3,ContentsEnv tc3,
+          Numbered [@#@:.@1 ],IncrementedBy Use,
+          Referenced [@#@:.@1 ])
+@Counter(AppendixSubSection,Within AppendixSection,TitleEnv HD3,
+          ContentsEnv tc3,
+          Numbered [@#@:.@1 ],IncrementedBy Use,
+          Referenced [@#@:.@1 ])
+@Counter(Paragraph,Within SubSection,TitleEnv HD4,ContentsEnv tc4,
+          Numbered [@#@:.@1 ],Referenced [@#@:.@1],
+          IncrementedBy Use)
+@modify(CopyrightNotice, Fixed -1 inch, Flushright)
+@Modify(Titlebox, Fixed 3.0 inches)
+@Modify(hd1, below .2 inch, facecode B, size 16, spaces kept, pagebreak off)
+@Modify(hd2, below .2 inch, facecode B, size 14, spaces kept)
+@Modify(hd3, below .2 inch, facecode B, size 12, spaces kept)
+@Modify(Description, Leftmargin +20, Indent -20,below 1 line, above 1 line)
+@Modify(Tc1, Above .5,  Facecode B)
+@Modify(Tc2, Above .25, Below .25, Facecode R)
+@Modify(Tc3,Facecode R)
+@Modify(Tc4,Facecode R)
+@Modify(Itemize,Above 1line,Below 1line)
+@Modify(Insert,LeftMargin +2, RightMargin +2)
+@libraryfile[stable]
+@comment[@Style(Font NewCenturySchoolBook, size 11)]
+@Style(Font TimesRoman, size 11)
+@Style(Spacing 1.1, indent 0)
+@Style(leftmargin 1.0inch)
+@Style(justification no)
+@Style(BottomMargin 1.5inch)
+@Style(ChangeBarLocation Right)
+@Style(ChangeBars=off)
+@pageheading[immediate]
+@pagefooting[immediate, left = "MIT Project Athena", center = "@value(page)",
+right = "@value(date)"]
+@set[page = 0]
+@blankspace[.5 inches]
+@begin[group, size 20]
+@begin(center)
+@b[Kerberos Operation Notes]
+@b[DRAFT]
+@end[center]
+@blankspace[.5 inches]
+@end(group)
+@begin[group, size 16]
+@begin(center)
+Bill Bryant
+John Kohl
+Project Athena, MIT
+@blankspace[.5 inches]
+@b[Initial Release, January 24, 1989]
+@i[(plus later patches through patchlevel 7)]
+@end[center]
+@end(group)
+@begin[group, size 10]
+@end[group]
+@blankspace[1inches]
+
+These notes assume that you have used the
+@i[Kerberos Installation Notes] to build and install your
+Kerberos system.
+As in that document, we refer to the directory that contains
+the built Kerberos binaries as [OBJ_DIR].
+
+This document assumes that you are a Unix system manager.
+
+@newpage()
+@chapter[How Kerberos Works: A Schematic Description]
+
+This section provides a simplified description of
+a general user's interaction with the Kerberos system.
+This interaction happens transparently--users don't need to know
+and probably don't care about what's going on--but Kerberos administrators
+might find a schematic description of the process useful.
+The description glosses over a lot of details;
+for more information, see @i[Kerberos: An Authentication
+Service for Open Network Systems],
+a paper presented at Winter USENIX 1988, in Dallas, Texas.
+
+@section[Network Services and Their Client Programs]
+
+In an environment that provides network services,
+you use @i[client] programs to request service from
+@i[server] programs that are somewhere on the network.
+Suppose you have logged in to a workstation
+and you want to @i[rlogin] to another machine.
+You use the local @i[rlogin] client program to
+contact the remote machine's @i[rlogin] service daemon.
+
+@section[Kerberos Tickets]
+
+Under Kerberos, the @i[rlogin] service program
+allows a client to login to a remote machine if it
+can provide
+a Kerberos @b[ticket] for the request.
+This ticket proves the identity of the person who has used
+the client program to access the server program.
+
+@section[The Kerberos Master Database]
+
+Kerberos will give you tickets only if you
+have an entry in the Kerberos server's
+@b[master database].
+Your database entry includes your Kerberos username (often referred to
+as your Kerberos @b[principal] name), and your Kerberos password.
+Every Kerberos user must have an entry in this database.
+
+@section[The Ticket-Granting Ticket]
+
+The @i[kinit] command prompts for your Kerberos username and password,
+and if you enter them successfully, you will obtain a Kerberos
+@i[ticket-granting ticket].
+As illustrated below,
+client programs use this ticket to get other Kerberos tickets as
+needed.
+
+@section[Network Services and the Master Database]
+
+The master database also contains entries for all network services that
+require Kerberos authentication.
+Suppose for instance that your site has a machine @i[laughter]
+that requires Kerberos authentication from anyone who wants
+to @i[rlogin] to it.
+This service must be registered in the master database.
+Its entry includes the service's principal name, and its @b[instance].
+
+The @i[instance] is the name of the service's machine;
+in this case, the service's instance is the name @i[laughter].
+The instance provides a means for Kerberos to distinguish between
+machines that provide the same service.
+Your site is likely to have more than one machine that
+provides @i[rlogin] service.
+
+@section[The User-Kerberos Interaction]
+
+Suppose that you (in the guise of a general user) walk up to a workstation
+intending to login to it, and then @i[rlogin] to the machine @i[laughter].
+Here's what happens.
+@begin[enumerate]
+You login to the workstation and use the @i[kinit] command
+to to get a ticket-granting ticket.
+This command prompts you for your username (your Kerberos Principal Name),
+and your Kerberos password [on some systems which use the new version of
+@i{/bin/login}, this may be done as part of the login process, not
+requiring the user to run a separate program].
+@begin[enumerate]
+The @i[kinit] command sends your request to the Kerberos master server
+machine.
+The server software looks for your principal name's entry in the
+Kerberos @b[master database].
+
+If this entry exists, the
+Kerberos server creates and returns a
+@i[ticket-granting ticket], encrypted in your password.
+If @i[kinit] can decrypt the Kerberos reply using the password you
+provide, it stores this ticket in a @b[ticket file] on your
+local machine for later use.
+The ticket file to be used
+can be specified in the @b[KRBTKFILE] environment
+variable.  If this variable is not set, the name of the file will be
+@i[/tmp/tkt@p(uid)], where @p(uid) is the UNIX user-id, represented in decimal.
+@end[enumerate]
+
+Now you use the @i[rlogin] client to try to access the machine @i[laughter].
+@begin[example]
+host% @b[rlogin  laughter]
+@end[example]
+@begin[enumerate]
+The @i[rlogin] client checks your ticket file to see if you
+have a ticket for @i[laughter]'s @i[rcmd] service (the rlogin program
+uses the @i[rcmd] service name, mostly for historical reasons).
+You don't, so @i[rlogin] uses the ticket file's @i[ticket-granting
+ticket] to make a request to the master server's ticket-granting service.
+
+This ticket-granting service receives the @i[rcmd-laughter] request
+and looks in the master database for an @i[rcmd-laughter] entry.
+If that entry exists, the ticket-granting service issues you a ticket
+for that service.
+That ticket is also cached in your ticket file.
+
+The @i[rlogin] client now uses that ticket to request service from
+the @i[laughter] @i[rlogin] service program.
+The service program
+lets you @i[rlogin] if the ticket is valid.
+@end[enumerate]
+@end[enumerate]
+
+@chapter[Setting Up and Testing the Kerberos Server]
+
+The procedure for setting up and testing a Kerberos server
+is as follows:
+@begin[enumerate]
+Use the @i[kdb_init] command to create and initialize the master database.
+
+Use the @i[kdb_edit] utility to add your username to the
+master database.
+
+Start the Kerberos server.
+
+Use the @i[kinit] command to obtain a Kerberos ticket-granting ticket.
+
+Use the @i[klist] command to verify that the @i[kinit] command
+authenticated you successfully.
+@end[enumerate]
+
+@section[Creating and Initializing the Master Database]
+
+Login to the Kerberos master server machine,
+and use the @b[su] command to become root.
+If you installed the Kerberos administration tools
+with the @i[make install] command and the default pathnames,
+they should be in the @i[/usr/etc] directory.
+If you installed the tools in a different directory,
+hopefully you know what it is.
+From now on, we will refer to this directory as [ADMIN_DIR].
+
+The @i[kdb_init] command creates and initializes the master database.
+It asks you to enter the system's
+realm name and the database's master password.
+Do not forget this password.
+If you do, the database becomes useless.
+(Your realm name should be substituted for [REALMNAME] below.)
+
+Use @i[kdb_init] as follows:
+@tabset[3inches, +1.5inches]
+@begin[example, rightmargin -10]
+host# @b([ADMIN_DIR]/kdb_init)
+Realm name (default XXX): @b([REALMNAME])@\@b[<--] @p[Enter your system's realm name.]
+You will be prompted for the database Master Password.
+It is important that you NOT FORGET this password.
+
+Enter Kerberos master key: @\@b[<--] @p[Enter the master password.]
+@comment(this needs to be re-fixed...:
+Verifying, please re-enter
+Enter Kerberos master key: @\@b[<--] @p[Re-enter it.]
+)
+@end[example]
+
+@section[Storing the Master Password]
+
+The @i[kstash] command ``stashes'' the master password in the file @i[/.k]
+so that the Kerberos server can
+be started automatically during an unattended reboot of the
+master server.
+Other administrative programs use this hidden password so that they
+can access the master database without someone having to manually
+provide the master password.
+This command is an optional one;
+if you'd rather enter the master password each time you
+start the Kerberos server, don't use @i[kstash].
+
+One the one hand, if you use @i[kstash], a copy of the master
+key will reside
+on disk which may not be acceptable; on the other hand, if you don't
+use @i[kstash], the server cannot be started unless someone is around to
+type the password in manually.
+
+The command prompts you twice for the master password:
+@begin[example]
+@tabset[3inches]
+host# @b([ADMIN_DIR]/kstash)
+
+Enter Kerberos master key:@\@b[<--] @p[Enter the master password.]
+Current Kerberos master key version is 1.
+
+Master key entered   BEWARE!
+@end[example]
+
+A note about the Kerberos database master key:
+if your master key is compromised and the database is obtained,
+the security of your entire authentication system is compromised.
+The master key must be a carefully kept secret.  If you keep backups,
+you must guard all the master keys you use, in case someone has stolen
+an old backup and wants to attack users' whose passwords haven't changed
+since the backup was stolen.
+This is why we provide the option not to store it on disk.
+
+@section[Using @p(kdb_edit) to Add Users to the Master Database]
+
+The @i[kdb_edit] program is used to add new users and services
+to the master database, and to modify existing database information.
+The program prompts you to enter a principal's @b[name] and @b[instance].
+
+A principal name is typically a username or a service program's name.
+An instance further qualifies the principal.
+If the principal is a service,
+the instance is used to specify the name of the machine on which that
+service runs.
+If the principal is a username that has general user privileges,
+the instance is usually set to null.
+
+The following example shows how to use @i[kdb_edit] to
+add the user @i[wave] to the Kerberos database.
+@begin[example, rightmargin -10]
+@tabset[3inches, +1.5inches]
+host# @b([ADMIN_DIR]/kdb_edit)
+
+Opening database...
+
+Enter Kerberos master key:
+Verifying, please re-enter
+Enter Kerberos master key:
+Current Kerberos master key version is 1
+
+Master key entered.  BEWARE!
+Previous or default values are in [brackets] ,
+enter return to leave the same, or new value.
+
+Principal name: @b[wave]@\@b[<--] @p[Enter the username.]
+Instance:@\@p[<-- Enter a null instance.]
+
+<Not found>, Create [y] ? @b[y]@\@b[<--] @p[The user-instance does not exist.]
+@\@p[      Enter y to create the user-instance.]
+Principal: wave  Instance:  m_key_v: 1
+New Password: @\@p[<-- Enter the user-instance's password.]
+Verifying, please re-enter 
+New Password:
+Principal's new key version = 1
+Expiration date (enter dd-mm-yy) [ 12/31/99 ] ?@\@b[<--] @p[Enter newlines]
+Max ticket lifetime (*5 minutes) [ 255 ] ? @\@b[<--] @p[to get the]
+Attributes [ 0 ] ? @\@\@b[<--] @p[default values.]
+Edit O.K.
+
+Principal name:@\@p[<-- Enter a newline to exit the program.]
+@end[example]
+
+Use the @i[kdb_edit] utility to add your username to the master database.
+
+@section[Starting the Kerberos Server]
+
+Change directories to the directory in which you have installed
+the server program @i[kerberos]
+(the default directory is @i[/usr/etc]),
+and start the program as a background process:
+@begin[example]
+host# @b[./kerberos &]
+@end[example]
+If you have used the @i[kstash] command to store the master database password,
+the server will start automatically.
+If you did not use @i[kstash],
+use the following command:
+@begin[example]
+host# @b[./kerberos -m]
+@end[example]
+The server will prompt you to enter the master password before actually
+starting itself.
+
+@section[Testing the Kerberos Server]
+
+Exit the root account and use the @i[kinit] command obtain a Kerberos
+ticket-granting ticket.
+This command
+creates your ticket file
+and stores the ticket-granting ticket in it.
+
+If you used the default @i[make install] command and directories to
+install the Kerberos user utilities, @i[kinit] will be in the
+@i[/usr/athena] directory. From now on, we'll refer to the Kerberos user
+commands directory as [K_USER].
+
+Use @i[kinit] as follows:
+@begin[example]
+@tabset[3 inches]
+host% @b([K_USER]/kinit)
+MIT Project Athena, (ariadne)
+Kerberos Initialization
+Kerberos name: @p[yourusername]@\@b[<--] @p[Enter your Kerberos username.]
+Password: @\@b[<--] @p[Enter your Kerberos password.]
+@end[example]
+
+Use the @i[klist] program to list the contents of your ticket file.
+@begin[example]
+host% @b([K_USER]/klist)
+@end[example]
+The command should display something like the following:
+@begin[example]
+Ticket file:    /tmp/tkt5555
+Principal:      yourusername@@REALMNAME
+
+  Issued           Expires          Principal
+May  6 10:15:23  May  6 18:15:23  krbtgt.REALMNAME@@REALMNAME
+@end[example]
+
+If you have any problems, you can examine the log file
+@i[/kerberos/kerberos.log] on the Kerberos server machine to see if
+there was some sort of error.
+
+@chapter[Setting up and testing the Administration server]
+
+The procedure for setting up and testing the Kerberos administration server
+is as follows:
+@begin[enumerate]
+Use the @i[kdb_edit] utility to add your username with an administration
+instance to the master database.
+
+Edit the access control lists for the administration server
+
+Start the Kerberos administration server.
+
+Use the @i[kpasswd] command to change your password.
+
+Use the @i[kadmin] command to add new entries to the database.
+
+Use the @i[kinit] command to verify that the @i[kadmin] command
+correctly added new entries to the database.
+@end(enumerate)
+
+@section[Adding an administration instance for the administrator]
+
+Login to the Kerberos master server machine,
+and use the @b[su] command to become root.
+Use the @i[kdb_edit] program to create an entry for each administrator
+with the instance ``@p(admin)''.
+@begin[example]
+@tabset[3inches, +1.5inches]
+host# @b([ADMIN_DIR]/kdb_edit)
+
+Opening database...
+
+Enter Kerberos master key:
+Verifying, please re-enter
+Enter Kerberos master key:
+Current Kerberos master key version is 1
+
+Master key entered.  BEWARE!
+Previous or default values are in [brackets] ,
+enter return to leave the same, or new value.
+
+Principal name: @b[wave]@\@b[<--] @p[Enter the username.]
+Instance:@b[admin]@\@b[<--] @p[Enter ``admin''.]
+
+<Not found>, Create [y] ? @b[y]@\@b[<--] @p[The user-instance does not exist.]
+@\@p[      Enter y to create the user-instance.]
+Principal: wave  Instance: admin m_key_v: 1
+New Password: @\@p[<-- Enter the user-instance's password.]
+Verifying, please re-enter 
+New Password:
+Principal's new key version = 1
+Expiration date (enter dd-mm-yy) [ 12/31/99 ] ?@\@b[<--] @p[Enter newlines]
+Max ticket lifetime (*5 minutes) [ 255 ] ? @\@b[<--] @p[to get the]
+Attributes [ 0 ] ? @\@\@b[<--] @p[default values.]
+Edit O.K.
+
+Principal name:@\@p[<-- Enter a newline to exit the program.]
+@end[example]
+
+@section[The Access Control Lists]
+The Kerberos administration server uses three access control lists to
+determine who is authorized to make certain requests.  The access
+control lists are stored on the master Kerberos server in the same
+directory as the principal database, @i(/kerberos).  The access control
+lists are simple ASCII text files, with each line specifying the name of
+one principal who is allowed the particular function.  To allow several
+people to perform the same function, put their principal names on
+separate lines in the same file.
+
+The first list, @i(/kerberos/admin_acl.mod), is a list of principals
+which are authorized to change entries in the database.  To allow the
+administrator `@b[wave]' to modify entries in the database for the realm
+`@b[TIM.EDU]', you would put the following line into the file
+@i(/kerberos/admin_acl.mod):
+@begin(example)
+wave.admin@@TIM.EDU
+@end(example)
+
+The second list, @i(/kerberos/admin_acl.get), is a list of principals
+which are authorized to retrieve entries from the database.
+
+The third list, @i(/kerberos/admin_acl.add), is a list of principals
+which are authorized to add new entries to the database.
+
+@section(Starting the administration server)
+Change directories to the directory in which you have installed
+the administration server program @i[kadmind]
+(the default directory is @i[/usr/etc]),
+and start the program as a background process:
+@begin[example]
+host# @b[./kadmind -n&]
+@end[example]
+If you have used the @i[kstash] command to store the master database password,
+the server will start automatically.
+If you did not use @i[kstash],
+use the following command:
+@begin[example]
+host# @b[./kadmind]
+@end[example]
+The server will prompt you to enter the master password before actually
+starting itself; after it starts, you should suspend it and put it in
+the background (usually this is done by typing control-Z and then @b(bg)).
+
+@section(Testing @p[kpasswd])
+
+To test the administration server, you should try changing your password
+with the @i[kpasswd] command, and you should try adding new users with
+the @i[kadmin] command (both commands are installed into @i[/usr/athena]
+by default).
+
+Before testing, you should exit the root account.
+
+To change your password, run the @i[kpasswd] command:
+@begin(example)
+@tabset[3inches, +1.5inches]
+host% @b([K_USER]/kpasswd)
+Old password for wave@@TIM.EDU:@\@b[<--]@p[Enter your password]
+New Password for wave@@TIM.EDU:@\@b[<--]@p[Enter a new password]
+Verifying, please re-enter New Password for wave@@TIM.EDU:
+@\@b[<--]@p[Enter new password again]
+Password changed.
+@end(example)
+Once you have changed your password, use the @i[kinit] program as shown
+above to verify that the password was properly changed.
+
+@section(Testing @p[kadmin])
+You should also test the function of the @i[kadmin] program, by adding a
+new user (here named ``@t[username]''):
+@begin(example)
+@tabset[3inches, +1.5inches]
+host% @b([K_USER]/kadmin)
+Welcome to the Kerberos Administration Program, version 2
+Type "help" if you need it.
+admin:  @b(ank username)@\@p[`ank' stands for Add New Key]
+Admin password: @\@b[<--]@p[enter the password 
+@\you chose above for wave.admin]
+Password for username:@\@b[<--]@p[Enter the user's initial password]
+Verifying, please re-enter Password for username:@\@b[<--]@p[enter it again]
+username added to database.
+
+admin:  quit
+Cleaning up and exiting.
+@end[example]
+
+@section(Verifying with @p[kinit])
+Once you've added a new user, you should test to make sure it was added
+properly by using @i[kinit], and trying to get tickets for that user:
+
+@begin[example]
+@tabset[3inches, +1.5inches]
+host% @b([K_USER]/kinit username)
+MIT Project Athena (ariadne)
+Kerberos Initialization for "username@@TIM.EDU"
+Password: @b[<--]@p[Enter the user's password you used above]
+host% @b([K_USER]/klist)
+Ticket file:    /tmp/tkt_5509_spare1
+Principal:      username@@TIM.MIT.EDU
+
+  Issued           Expires          Principal
+Nov 20 15:58:52  Nov 20 23:58:52  krbtgt.TIM.EDU@@TIM.EDU
+@end[example]
+
+If you have any problems, you can examine the log files
+@i[/kerberos/kerberos.log] and @i[/kerberos/admin_server.syslog] on the
+Kerberos server machine to see if there was some sort of error.
+
+@chapter[Setting up and testing slave server(s)]
+
+[Unfortunately, this chapter is not yet ready.  Sorry. -ed]
+
+@chapter[A Sample Application]
+
+This release of Kerberos comes with a sample application
+server and a corresponding client program.
+You will find this software in the [OBJ_DIR]@i[/appl/sample] directory.
+The file @i[sample_client] contains the client program's executable
+code, the file @i[sample_server] contains the server's executable.
+
+The programs are rudimentary.
+When they have been installed (the installation procedure is described
+in detail later), they work as follows:
+@begin[itemize]
+The user starts @i[sample_client] and provides as arguments
+to the command the name of the server machine and a checksum.
+For instance:
+@begin[example]
+host% @b[sample_client]  @p[servername] @p[43]
+@end[example]
+
+@i[Sample_client] contacts the server machine and
+authenticates the user to @i[sample_server].
+
+@i[Sample_server] authenticates itself to @i[sample_client],
+then returns a message to the client program.
+This message contains diagnostic information
+that includes the user's username, the Kerberos realm,
+and the user's workstation address.
+
+@i[Sample_client] displays the server's message on the user's
+terminal screen.
+@end[itemize]
+
+@section[The Installation Process]
+
+In general,
+you use the following procedure to install a Kerberos-authenticated
+server-client system.
+@begin[enumerate]
+Add the appropriate entry to the Kerberos database using @i[kdb_edit] or
+@i[kadmin] (described below).
+
+Create a @i[/etc/srvtab] file for the server machine.
+
+Install the service program and the @i[/etc/srvtab]
+file on the server machine.
+
+Install the client program on the client machine.
+
+Update the @i[/etc/services] file on the client and server machines.
+@end[enumerate]
+
+We will use the sample application as an example, although
+the procedure used to install @i[sample_server] differs slightly
+from the general case because the @i[sample_server]
+takes requests via the
+@i[inetd] program.
+@i[Inetd] starts @i[sample_server] each time
+a client process contacts the server machine.
+@i[Sample_server] processes the request,
+terminiates, then is restarted when @i[inetd] receives another
+@i[sample_client] request.
+When you install the program on the server,
+you must add a @i[sample] entry to the server machine's
+@i[/etc/inetd.conf] file.
+
+The following description assumes that you are installing
+@i[sample_server] on the machine @i[ariadne.tim.edu].
+Here's the process, step by step:
+@begin[enumerate]
+Login as or @i[su] to root on the Kerberos server machine.
+Use the @i[kdb_edit] or @i[kadmin] program to create an entry for
+@i[sample] in the Kerberos database:
+@begin[example, rightmargin -10]
+@tabset[2.0inches, +.5inches]
+host# @b([ADMIN_DIR]/kdb_edit)
+
+Opening database...
+
+Enter Kerberos master key:
+Verifying, please re-enter
+master key entered.  BEWARE!
+Previous or default values are in [brackets] ,
+enter return to leave the same, or new value.
+
+Principal name: @b[sample]@\@b[<--] @p[Enter the principal name.]
+Instance: @b[ariadne]@\@b[<--] @p[Instances cannot have periods in them.]
+
+<Not found>, Create [y] ? @b[y]
+
+Principal: sample_server  Instance: ariadne m_key_v: 1
+New Password:@\@b[<--] @p[Enter ``RANDOM'' to get random password.]
+Verifying, please re-enter 
+New Password:@\@b[<--] @p[Enter ``RANDOM'' again.]
+Random password [y] ? @b[y]
+
+Principal's new key version = 1
+Expiration date (enter dd-mm-yy) [ 12/31/99 ] ? 
+Max ticket lifetime (*5 minutes) [ 255 ] ? 
+Attributes [ 0 ] ? 
+Edit O.K.
+
+Principal name:@\@b[<--] @p[Enter newline to exit kdb_edit.]
+@end[example]
+
+Use the @i[ext_srvtab] program to create a @i[srvtab] file
+for @i[sample_server]'s host machine:
+@begin[example]
+host# @b([ADMIN_DIR]/ext_srvtab  ariadne)
+
+Enter Kerberos master key: 
+Current Kerberos master key version is 1.
+
+Generating 'ariadne-new-srvtab'....
+@end[example]
+Transfer the @i[ariadne-new-srvtab] file to @i[ariadne] and install it as
+@i[/etc/srvtab].
+Note that this file is equivalent to the service's password and should
+be treated with care.
+For example, it could be transferred by removable media, but should
+not be sent over an open network in the clear.
+Once installed, this file should be readable only by root.
+
+Add the following line to the @i[/etc/services] file on
+@i[ariadne], and on all machines that
+will run the @i[sample_client] program:
+@begin[example]
+sample     906/tcp       # Kerberos sample app server
+@end[example]
+
+Add a line similar to the following line to the @i[/etc/inetd.conf]
+file on @i[sample_server]'s machine:
+@begin[example]
+sample   stream   tcp   nowait   switched   root
+    [PATH]/sample_server sample_server
+@end[example]
+where [PATH] should be substituted with
+the path to the @i[sample_server] program.
+(This @i[inetd.conf] information should be placed on one line.)
+You should examine existing lines in @i[/etc/inetd.conf] and use the
+same format used by other entries (e.g. for telnet).  Most systems do
+not have a column for the `switched' keyword, and some do not have a
+column for the username (usually `root', as above).
+
+Restart @i[inetd] by sending the current @i[inetd] process
+a hangup signal:
+@begin[example]
+host# @b[kill  -HUP   @p(process_id_number)]
+@end[example]
+
+The @i[sample_server] is now ready to take @i[sample_client] requests.
+@end[enumerate]
+
+@section[Testing the Sample Server]
+
+Assume that you have installed @i[sample_server] on @i[ariadne].
+
+Login to your workstation and use the @i[kinit] command to
+obtain a Kerberos ticket-granting ticket:
+@begin[example]
+@tabset[3 inches]
+host% @b([K_USER]/kinit)
+MIT Project Athena, (your_workstation)
+Kerberos Initialization
+Kerberos name: @p[yourusername]@\@b[<--] @p[Enter your Kerberos username.]
+Password: @\@b[<--] @p[Enter your Kerberos password.]
+@end[example]
+
+Now use the @i[sample_client] program as follows:
+@begin[example]
+host% @b([PATH]/sample_client  ariadne)
+@end[example]
+The command should display something like the following:
+@begin[example]
+The server says:
+You are @p[yourusername].@@REALMNAME (local name @p[yourusername]),
+ at address @p[yournetaddress], version VERSION9, cksum 997
+@end[example]
+
+@chapter[Service names and other services]
+
+@section(rlogin, rsh, rcp, tftp, and others)
+
+Many services use a common principal name for authentication purposes.
+@i[rlogin], @i[rsh], @i[rcp], @i[tftp] and others use the principal name
+``@t[rcmd]''.  For example, to set up the machine @i[ariadne] to support
+Kerberos rlogin, it needs to have a service key for principal
+``@t[rcmd]'', instance ``@t[ariadne]''.  You create this key in the same
+way as shown above for the sample service.
+
+After creating this key, you need to run the @i[ext_srvtab] program
+again to generate a new srvtab file for ariadne.
+
+@section(NFS modifications)
+
+The NFS modifications distributed separately use the service name
+``@t[rvdsrv]'' with the instance set to the machine name (as for the
+sample server and the rlogin, rsh, rcp and tftp services).
+
+@section(inetd.conf entries)
+The following are the @i(/etc/inetd.conf) entries necessary to support
+rlogin, encrypted rlogin, rsh, and rcp services on a server machine.  As
+above, your @i(inetd.conf) may not support all the fields shown here.
+@begin[example]
+eklogin  stream   tcp   nowait   unswitched   root
+    [PATH]/klogind   eklogind
+kshell   stream   tcp   nowait   unswitched   root
+    [PATH]/kshd   kshd
+klogin   stream   tcp   nowait   unswitched   root
+    [PATH]/klogind   klogind
+@end[example]
diff --git a/mechglue/doc/procedures.txt b/mechglue/doc/procedures.txt
new file mode 100644
index 000000000..3c31814c7
--- /dev/null
+++ b/mechglue/doc/procedures.txt
@@ -0,0 +1,157 @@
+		    MIT Kerberos Development Team
+			      Procedures
+
+This is a draft of current procedures used by the MIT Kerberos
+Development Team.  They will be refined at some later point.
+
+---Tom
+
+RELEASE BRANCH HYGIENE
+======================
+
+No changes should be committed to a release branch except by the
+release engineer or other approved person.  Changes to be included on
+the release branch must first be committed to the trunk, and must have
+an associated RT ticket.  This ticket should have its "target_version"
+keyword set to the release that the change is targeted at, and should
+have the "pullup" tag set.  This ticket should clearly document the
+changes that are to be pulled up to the release branch; the
+recommended way to do this is to ensure the the CVS commit operations
+corresponding to the changes have automatically updated the ticket --
+see the following section.  The release engineer will pull up the
+change to the release branch and set the "version_fixed" keyword on
+the ticket.
+
+USING CVS COMMITS TO CREATE/UPDATE RT TICKETS
+=============================================
+
+To: krbdev@mit.edu
+Subject: Important: handling commit interactions with bug database
+Message-Id: <20020917204852.4AEFE151FEF@industrial-algebra.mit.edu>
+Date: Tue, 17 Sep 2002 16:48:52 -0400 (EDT)
+From: hartmans@MIT.EDU (Sam Hartman)
+
+Hi.  I've just deployed the integration between the RT bug tracking
+system and our CVS repository.
+
+Per previous discussion, we're moving to a model where any non-trivial
+functionality change needs to be accompanied by a ticket open in the
+bug database.  This will allow us to generate better release notes.
+To accomplish this we have created a syntax for manipulating tickets
+along with commits.  If you are someone who has commit access but is
+not at MIT your commits MUST create or update a ticket.
+
+To manipulate tickets you add some header lines to the top of your log
+message.  The lines can be of the form header: value or rt-header:
+value.  I'll show them without the rt-prefix.
+
+Updating a ticket
+=================
+
+To update a ticket, you include a 
+ ticket: or rt-ticket: line  in your log.  For example:
+
+ticket: 1164
+
+Return errno not retval when getpeername fails.
+
+By default when you update a ticket:
+
+* the ticket it assigned to you
+* The ticket it closed
+
+If these defaults are not appropriate for your action you can override
+them; see below.
+
+Creating a ticket
+=================
+
+You can also create a ticket at the same time as you commit. All you
+have to do is use new instead of a ticket number in a ticket line.
+However you almost certainly want to at least set the  subject.
+
+ticket: new
+subject: Add AES support
+
+Add an implementation of AES to libk5crypto.
+
+In addition to closing the ticket and marking you as the owner of a
+ticket, creating a new ticket makes you the requestor of the ticket.
+
+OTher Things to Change
+======================
+
+
+The following additional commands are supported:
+
+* subject: changes the subject of ticket
+* status: [open|resolved|new|stalled]
+* owner: [username|nobody]
+* cc: [email address]
+* Component: change component of ticket [krb5-libs etc]
+* Version_Reported: 
+* Target_Version:
+* Tags: [enhancement|nochange|noresource]
+
+You could set version_fixed, but it is wrong to do so.
+
+
+Also, note that you can update multiple tickets in one log message;
+updates apply to the most recent ticket: command.
+
+MEANINGS OF RT TAGS AND VERSIONS
+================================
+
+To: krbdev@mit.edu
+Subject: Meaning of RT tags and versions
+Message-Id: <20020821205804.5764E151FEF@industrial-algebra.mit.edu>
+Date: Wed, 21 Aug 2002 16:58:04 -0400 (EDT)
+From: hartmans@MIT.EDU (Sam Hartman)
+
+We're in the middle of migrating away from Gnats for bug tracking and
+to RT.  I sent out some mail describing the bug tracking process we
+were going to use at the beginning of the summer and wanted to follow
+up on that with definitions of fields in the  tickets.
+
+Tickets have three version numbers associated with them:
+version_reported, version_fixed, and target_version.  The
+version_reported should be filled in by the submitter if they are
+using the web interface or by the first person  to edit the bug with
+the web interface; it is the version of Kerberos the bug first
+appeared in.
+
+The version_fixed field is set during the release process; you should
+never change this field  unless you are a release engineer and even
+then you'll probably be using automated scripts.
+
+The target_version field is the version of the software we plan to fix
+a bug in.  It is generally updated after release planning meetings,
+although it is reasonable for people with commit access to update this
+if they believe a particular issues should be considered for the
+specified target version.  If we notice a lot of issues we don't have
+time to deal with, we will drop the target versions as the release
+approaches.
+
+Therer are several tags that can be set on a ticket as well.
+
+The first tag is the enhancement tag; this roughly corresponds to the
+Gnats classification as change-request, distinguished from sw-bug.
+
+
+The next tag is the nochange tag.  This indicates that the ticket has
+been (or will be) closed bwith no code change and thus should not be
+processed by the next round of release scripts.  This is appropriate
+for tickets where the requestor is mistaken or where no bug/change
+exists.
+
+The final tag is the noresource tag; this indicates that MIT does not
+have resources to dedicate to the problem/feature.  We'll set this tag
+on tickets when we evaluate them in release planning discussions so
+that we do not have to continue thinking about then at each
+consecutive release.  In general, if we feel an issue is not a
+problem, we'll just close the ticket.  However if we agree that in an
+ideal world the issue would be fixed but don't ever expect to be able
+to fix it ourselves, we'll set the noresource tag and forget the issue
+unless someone replies to it with a patch or proposed solution.
+
+--Sam
diff --git a/mechglue/doc/rpc/design.tex b/mechglue/doc/rpc/design.tex
new file mode 100644
index 000000000..fbd60f914
--- /dev/null
+++ b/mechglue/doc/rpc/design.tex
@@ -0,0 +1,1037 @@
+\documentstyle[fullpage,12pt]{article}
+
+\title{GSS-API Extensions to Sun RPC}
+\date{Draft---\today}
+\author{Barry Jaspan}
+
+\setlength{\parskip}{.7\baselineskip}
+\setlength{\parindent}{0pt}
+
+\makeatletter
+\newcount\savecnt\savecnt=0
+\def\saveenum#1{\global\savecnt=\csname c@enum#1\endcsname}
+\def\restoreenum#1{\csname c@enum#1\endcsname=\savecnt}
+\makeatother
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Make _ actually generate an _, and allow line-breaking after it.
+\let\underscore=\_
+\catcode`_=13
+\def_{\underscore\penalty75\relax}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\begin{document}
+
+
+{\setlength{\parskip}{0pt}\maketitle\tableofcontents}
+
+\section{Introduction}
+
+This document describes the integration of GSS-API authentication and
+security with Sun RPC.
+
+\section{Requirements}
+
+The requirements of the GSS-API authentication system for Sun RPC are:
+
+\begin{enumerate}
+\item It must provide mutual authentication between RPC clients and
+servers.
+
+\item It must provide for integrity checking and encryption of all
+procedure arguments and results passed over the network.
+\saveenum{i}
+\end{enumerate}
+
+The following features are desired, but not mandatory:
+
+\begin{enumerate}
+\restoreenum{i}
+\item It should provide for integrity checking and encryption of all
+``header information'' that specifies the program and procedure being
+called.
+
+\item It should obey the Sun RPC protocol so that clients using
+it can interoperate with existing servers.  In this case,
+``interoperate'' means that existing servers will return an error code
+indicating that they do not understand the authentication flavor, but
+not that they do not understand the request at all.
+
+\item It should require minimal or no changes to the standard Sun RPC
+programming paradigm for either clients or servers so that existing
+code can use it with little or no effort.
+
+\item It should operate correctly with all the standard Sun RPC
+transport mechansims (e.g. UDP and TCP).
+\saveenum{i}
+\end{enumerate}
+
+\section{Functional Specification}
+
+This section describes the programmer's interface to the GSS-API
+authentication flavor.   Knowledge of standard Sun RPC programming is
+assumed.
+
+\subsection{Client Side}
+
+A RPC client can select the GSS-API authentication flavor in the same
+way it can select any other authentication flavor, by setting the
+cl_auth field of the CLIENT structure to the appropriate value:
+
+\begin{verbatim}
+    clnt = clnt_create(server_host, PROG_NUM, PROG_VERS, protocol);
+    clnt->cl_auth = auth_gssapi_create(clnt, ...);
+\end{verbatim}
+
+There are two functions that create GSS-API authentication flavor
+structures for the cl_auth field, auth_gssapi_create and
+auth_gssapi_create_default.
+
+\begin{verbatim}
+AUTH *auth_gssapi_create(CLIENT         *clnt,
+                        OM_uint32       *major_status,
+                        OM_uint32       *minor_status,
+                        gss_cred_id_t   claimant_cred_handle,
+                        gss_name_t      target_name,
+                        gss_OID         mech_type,
+                        int             req_flags,
+                        int             time_req,
+                        gss_OID         *actual_mech_type,
+                        int             *ret_flags,
+                        OM_uint32       *time_rec);
+\end{verbatim}
+
+auth_gssapi_create creates a GSS-API authentication structure and
+provides most of the flexibility of gss_init_sec_context.  The
+arguments have the same interpretation as those of
+gss_init_sec_context with the same name, except:
+
+\begin{description}
+\item[clnt] The CLIENT structure returned by client_create or one of
+its relatives.  It is not modified.
+\end{description}
+
+auth_gssapi_create calls gss_init_sec_context as needed, passing each
+generated token to and processing each token returned from the RPC
+server specified by the RPC handle clnt.  On return, if major_status
+is GSS_S_COMPLETE, the context has been established, the returned AUTH
+structure is valid, and all of the arguments filled in by
+gss_init_sec_context have the correct values.  If major_status is not
+GSS_S_COMPLETE then it and minor_status contain error codes that can
+be passed to gss_display_status and the returned value is NULL.
+
+\begin{verbatim}
+AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name);
+\end{verbatim}
+
+auth_gssapi_create_default is a shorthand for auth_gssapi_create that
+attempts to create a context that provides procedure call and result
+integrity, using the default credentials and GSS-API mechanism.
+service_name is parsed as a GSS-API ``service'' name and used as the
+target name.  The other arguments to auth_gssapi_create are as follows:
+
+\begin{verbatim}
+auth_gssapi_create(clnt,
+                   &dummy,
+                   &dummy,
+                   GSS_C_NO_CREDENTIAL,
+                   target_name,
+                   GSS_C_NULL_OID,
+                   GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+                   0,
+                   NULL,
+                   NULL,
+                   NULL);
+\end{verbatim}
+
+Note that if the underlying default mechanism does not support data
+integrity (e.g. the trust mechanism), this function will fail.
+
+The GSS-API major and minor status codes can be interpreted with
+auth_gssapi_display_status:
+
+\begin{verbatim}
+void auth_gssapi_display_status(char *msg, OM_uint32 major, 
+                                OM_uint32 minor); 
+\end{verbatim}
+
+All of the error messages associated with the major and minor status
+are displated on the standard error output, preceeded by the message
+``GSS-API authentication error $<$msg$>$:''.
+
+\subsection{Server Side}
+
+\subsubsection{Service Name Registration}
+
+An application server must register the service name(s) that it will
+use for GSS-API connections before any AUTH_GSSAPI requests will
+succeed.
+
+\begin{verbatim}
+typedef struct _auth_gssapi_name {
+     char *name;
+     gss_OID type;
+} auth_gssapi_name;
+
+bool_t _svcauth_gssapi_set_names(auth_gssapi_name *names, int num);
+\end{verbatim}
+
+names is an array of name specifications, each of which consists of a
+null-terminated ASCII representation of a name and the GSS-API name
+type that should be used to import it with gss_import_name.  The
+name type ``gss_nt_service_name'' is recommended.
+
+\subsubsection{Calling Client and Service Identification}
+
+Each application server's dispatch function is passed two arguments,
+the transport mechanism (transp) and the RPC service request (rqstp).
+If the service request's credential flavor (rq_cred.oa_flavor) is
+AUTH_GSSAPI (300001)\footnote{The value 4 was originally used, but
+300001 has been officially assigned by the IETF.}, then the call has
+been authenticated.  The rq_clntcred field of transp contains the
+gss_name_t of the authenticated caller and can be passed to
+gss_display_name to obtain a string represtation or gss_compare_name
+to compare it with other names.  The rq_svccred field of transp
+contains the GSS-API context established with the caller and can be
+passed to gss_inquire_context.
+
+\subsubsection{Error Logging}
+
+An application server can register a function to be called when a
+failure occurs during GSS-API context establishment with
+_svcauth_set_log_badauth_func.
+
+\begin{verbatim}
+typedef void (*auth_gssapi_log_badauth_func)(OM_uint32 major,
+                                             OM_uint32 minor,
+                                             struct sockaddr_in *raddr,
+                                             caddr_t data);
+   
+void _svcauth_set_log_badauth_func(auth_gssapi_log_badauth_func func,
+                                   caddr_t data); 
+\end{verbatim}
+
+The function func is called each time gss_accept_sec_context fails.
+The major and minor arguments indicate the GSS-API major and minor
+status codes returned.  The raddr field contains the INET socket that
+the request came from, and the data field contains the data argument
+of _svcauth_gssapi_set_log_badauth_func.
+
+An application server can register a function to be called when an RPC
+request with an invalid verifier arrives with
+_svcauth_set_log_badverf_func.
+
+\begin{verbatim}
+typedef void (*auth_gssapi_log_badverf_func)(gss_name_t client,
+                                             gss_name_t server,
+                                             struct svc_req *rqst,
+                                             struct rpc_msg *msg,
+                                             caddr_t data);
+
+void _svcauth_set_log_badverf_func(auth_gssapi_log_badverf_func func,
+                                   caddr_t data); 
+\end{verbatim}
+
+The function specified in func is called each time an invalid verifier
+is received.  The client and server fields identify the (falsely
+claimed) originating client and the server it originally authenticated
+to.  The raddr and addrlen fields contain the INET socket that the
+request (claims to have) come from, and data contains the data
+argument of _svcauth_set_log_badverf_func.
+
+\section{Modifications to Sun RPC}
+
+The Sun RPC extensible authentication mechanism is designed to allow
+different authentication systems to be integrated into Sun RPC easily.
+Unfortunately, it has two drawbacks.  First, the existing system has a
+number of non-general design properties that are intended specifically
+for Sun's Secure RPC, and second, the existing system has no concept
+of or ability to perform authentication-flavor-specific operations on
+function arguments and results passed over the wire.  The first
+problem merely makes the system confusing, since a number of features
+touted as ``general'' do not make any sense for arbitrary
+authentication systems.  The second problem is more substantial, and
+can only be corrected by modifications to Sun RPC internals.
+
+The following sections describe the necessary modifications to Sun
+RPC.
+
+\subsection{Client Side Authentication, AUTH Structure}
+
+The AUTH structure (figure \ref{fig:auth}) encapsulates the data and
+function pointers for an authentication flavor instance.  It has been
+changed in two ways.
+
+\begin{figure}[htbp]
+\begin{verbatim}
+typedef struct {
+        struct  opaque_auth     ah_cred;
+        struct  opaque_auth     ah_verf;
+        union   des_block       ah_key;
+        struct auth_ops {
+                void    (*ah_nextverf)();
+                int     (*ah_marshal)();        /* nextverf & serialize */
+                int     (*ah_validate)();       /* validate varifier */
+                int     (*ah_refresh)();        /* refresh credentials */
+                int     (*ah_wrap)();           /* encode data for wire */
+                int     (*ah_unwrap)();         /* decode data from wire */
+                void    (*ah_destroy)();        /* destroy this structure */
+        } *ah_ops;
+        caddr_t ah_private;
+} AUTH;
+\end{verbatim}
+\caption{The AUTH structure, with the new function pointers ah_wrap
+and ah_unwrap.}
+\label{fig:auth}
+\end{figure}
+
+First, the new functions ah_wrap and ah_unwrap prepare function
+arguments and results for transmission over the wire.  The
+authentication mechanism can use them to sign, encrypt, or perform any
+other operation on the data.  Their prototype is:
+
+\begin{verbatim}
+bool_t ah_wrap(AUTH *auth, XDR *out_xdrs, xdrproc_t func, caddr_t ptr);
+bool_t ah_unwrap(AUTH *auth, XDR *in_xdrs, xdrproc_t func, caddr_t ptr);
+\end{verbatim}
+
+ah_wrap encodes function arguments for transmission.  func and ptr are
+the XDR procedure and pointer that serialize the arguments, and
+out_xdrs is the xdr stream that the encoded arguments should be
+written to.  ah_unwrap decodes function arguments received from the
+network.  Its arguments are the converse of those to ah_wrap.
+
+It is the responsibility of RPC transport mechanisms to call an
+authorization flavor's ah_wrap and ah_unwrap functions when function
+arguments or results would normally be written to or read from the
+wire.  Authorization flavors that do not need to perform any encoding
+or decoding can use the provided function authany_wrap for ah_wrap
+and ah_unwrap; it consists of the single statement ``return
+(*func)(out_xdrs, ptr)'' (or in_xdrs, as appropriate).
+
+Second, the function ah_refresh has been changed to take the RPC error
+message that resulted in its being called as an argument.  This is
+necessary since the contents of the error message may dictate how
+ah_refresh should go about correcting the authentication failure.
+
+\subsection{Client Side Transport Mechanisms}
+
+Each client side transport mechanism must be modified to call the
+ah_wrap and ah_unwrap functions from the cl_auth field of the CLIENT
+structure during the call and reply process.  The modification is
+fairly simple.  For example, the UDP transport mechanism used to
+encode procedure calls like this:
+
+\begin{verbatim}
+        if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
+            (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
+            (! (*xargs)(xdrs, argsp)))
+                return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
+\end{verbatim}
+
+The last function call in the conditional serializes the arguments
+onto the xdr stream.  This must be replaced with a call to the
+appropriate ah_wrap function:
+
+\begin{verbatim}
+        if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
+            (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
+            (! AUTH_WRAP(cl->cl_auth, xdrs, xargs, argsp)))
+                return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
+\end{verbatim}
+
+AUTH_WRAP is a macro that takes the four arguments for an ah_wrap
+function and extracts and calls the function pointer from the cl_auth
+structure with the specified arguments.
+
+Similarly, the transport mechanism must unwrap procedure results.
+Again, the UDP mechanism will be instructive.  It used to deserialize
+function results like this:
+
+\begin{verbatim}
+        reply_msg.acpted_rply.ar_results.where = resultsp;
+        reply_msg.acpted_rply.ar_results.proc = xresults;
+
+        ok = xdr_replymsg(&reply_xdrs, &reply_msg);
+\end{verbatim}
+
+The problem here is that xdr_replymsg deserializes an entire reply
+message, including the results.  Since xresults and resultsp are the
+function and pointer to decode the results, they will be automatically
+deserialized {\it without} ah_unwrap being invoked.  The simplest
+solution (which is also the normal method used by the TCP mechanism)
+is to arrange to deserialize the function results explicitly:
+
+\begin{verbatim}
+        reply_msg.acpted_rply.ar_results.where = NULL;
+        reply_msg.acpted_rply.ar_results.proc = xdr_void;
+
+        if ((! xdr_replymsg(&reply_xdrs, &reply_msg)) ||
+            (! AUTH_UNWRAP(cl->cl_auth, reply_xdrs, xresults,
+                           resultsp))) {
+                return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
+        }
+\end{verbatim}
+
+Since xdr_void does not read any data from the XDR stream, the
+function results are still available when AUTH_UNWRAP is called.  Note
+that AUTH_UNWRAP should only be called on {\it successful} calls; if
+the reply message status is not RPC_SUCCESS there are no arguments to
+read.
+
+Currently, the UDP and TCP transport mechanisms has been
+converted.\footnote{The ``raw'' mechanism, for direct connections, has
+not been.}
+
+\subsection{Service Side Authentication, SVCAUTH and XPRT}
+
+Standard Sun RPC service-side authentication consists of a single
+function per authentication flavor; there is no concept of an AUTH
+structure containing function pointers and private data as with the
+client side.  Previously, nothing else was necessary, because each
+flavor only did a single thing (authenticated individual calls in a
+stateless manner).  More functions and state are now required,
+however; they are stored in the SVCAUTH structure, see figure
+\ref{fig:svcauth}.
+
+\begin{figure}[htbp]
+\begin{verbatim}
+typedef struct {
+     struct svc_auth_ops {
+          int   (*svc_ah_wrap)();
+          int   (*svc_ah_unwrap)();
+     } *svc_ah_ops;
+     caddr_t svc_ah_private;
+} SVCAUTH;
+\end{verbatim}
+\caption{The new SVCAUTH structure.}
+\label{fig:svcauth}
+\end{figure}
+
+There is one SVCAUTH structure per authentication flavor (there is a
+default, svc_auth_any, for existing authentication flavors that do not
+need the extra functionality).  The svc_ah_wrap and svc_ah_unwrap
+perform the same logical function as their client-side counterparts.
+
+Just as with the client side, it is the responsibility of the
+transport mechanism to call the svc_ah_wrap and svc_ah_unwrap
+functions associated with the authentication flavor associated with
+each RPC call at the appropriate time.  Unfortunately, the transport
+mechanism code does not have access to the RPC call structure
+containing the authenticator flavor because the RPC call structure
+itself is not passed as an argument to the necessary functions.  The
+present solution is to add another argument to the transport mechanism
+structure, xp_auth, that stores the SVCAUTH of the {\it current} call
+on that mechanism; see figure \ref{fig:xprt}.  xp_auth is initialized
+to svc_auth_any so that existing authentication mechanisms that do not
+set the field will still operate correctly.  \footnote{This is not an
+great solution, because it forces each transport mechanism to be
+single threaded.  The correct solution is to store the SVCAUTH
+associated with each RPC call in the RPC call structure; however,
+doing so would require changing a lot of code to pass around the RPC
+call structure that currently does not do so.  Since other parts of
+Sun RPC use the XPRT structure in a non-reentrant way, the present
+solution does not make the situation any
+worse.}$^{\mbox{,}}$\footnote{A somewhat irrelevant side effect of
+adding SVCAUTH to XPRT is that the standard include file
+$<$rpc/rpc.h$>$ had to be changed to include $<$rpc/svc_auth$>$ before
+$<$rpc/svc.h$>$, whereas they used to be in the opposite order.}
+
+\begin{figure}[htbp]
+\begin{verbatim}
+typedef struct {
+        int             xp_sock;
+        u_short         xp_port;         /* associated port number */
+        struct xp_ops {
+            bool_t      (*xp_recv)();    /* receive incomming requests */
+            enum xprt_stat (*xp_stat)(); /* get transport status */
+            bool_t      (*xp_getargs)(); /* get arguments */
+            bool_t      (*xp_reply)();   /* send reply */
+            bool_t      (*xp_freeargs)();/* free mem allocated for args */
+            void        (*xp_destroy)(); /* destroy this struct */
+        } *xp_ops;
+        int             xp_addrlen;      /* length of remote address */
+        struct sockaddr_in xp_raddr;     /* remote address */
+        struct opaque_auth xp_verf;      /* raw response verifier */
+        SVCAUTH         *xp_auth;        /* auth flavor of current req */
+        caddr_t         xp_p1;           /* private */
+        caddr_t         xp_p2;           /* private */
+} SVCXPRT;
+\end{verbatim}
+\caption{The modified XPRT structure, with the xp_auth field.}
+\label{fig:xprt}
+\end{figure}
+
+Finally, with the modified XPRT structure carrying around the
+authentication flavor structure, the functions that serialize and
+deserialize function arguments and results must be modified to use the
+svc_ah_wrap and svc_ah_unwrap functions.  Each service-side transport
+mechanism has getargs and reply functions that must be modified to use
+the SVCAUTH_UNWRAP and SVCAUTH_WRAP macros, respectively, in a manner
+completely parallel to the client side.
+
+\subsection{Authenticated Service Identification, svc_req}
+
+Sun RPC provides the authenticated credentials of a client to the
+application server via rq_clntcred (``cooked credentials'') field of
+the service request (svc_req) structure.  In many authentication
+systems, services are also named entities, and there is no reason that
+an RPC should be restricted to accepting connections as a single
+authenticated service name.  However, access control decisions may be
+based on the service name a client authenticated to, so that
+information must be available to the application server.
+
+Figure \ref{fig:svc-req} shows the modified service request structure
+that contains a single new field, rq_svccred.  Like rq_clntcred, the
+authentication flavor is responsible for setting rq_svccred to the
+``cooked'' service credentials associated with a given RPC call.
+Authentication flavors that do not have the concept of service names
+can of course leave this field blank.
+
+\begin{figure}[htbp]
+\begin{verbatim}
+struct svc_req {
+        u_long          rq_prog;        /* service program number */
+        u_long          rq_vers;        /* service protocol version */
+        u_long          rq_proc;        /* the desired procedure */
+        struct opaque_auth rq_cred;     /* raw creds from the wire */
+        caddr_t         rq_clntcred;    /* read only cooked client cred */
+        caddr_t         rq_svccred;     /* read only cooked svc cred */
+        SVCXPRT         *rq_xprt;       /* associated transport */
+};
+\end{verbatim}
+\caption{The modified svc_req structure, with the rq_svccred field.}
+\label{fig:svc-req}
+\end{figure}
+
+
+
+\subsection{Authentication Negotiation, no_dispatch}
+
+In order to avoid having to transmit a full set of authentication
+information with every call, the service-side authentication mechanism
+must save state between calls.  Establishing that state may require
+multiple messages between the client-side and service-side
+authentication mechanisms.  The client-side authentication mechanism
+can make arbitrary RPC calls to the server simply by requiring the
+programmer to specify the CLIENT structure to the authentication
+flavor initialization routine.  The service side, however, is more
+complex.  In the normal course of events, an RPC call comes in, is
+authenticated, and is then dispatched to the appropriate procedure.
+For client- and service-side authentication flavors to communicate
+indepedent of the server implemented above the RPC layer, the
+service-side flavor must be able to send a reply to the client
+directly and {\it prevent} the call from being dispatched.
+
+This is implemented by a simple modification to the _authenticate
+routine, which dispatches each RPC call to the appropriate
+authentication flavor; see figure \ref{fig:authenticate}.  It takes an
+additional argument, no_dispatch, that instructs the mechanism not to
+dispatch the RPC call to the specified procedure.
+
+\begin{figure}[htbp]
+\begin{verbatim}
+                why=_authenticate(&r, &msg, &no_dispatch);
+                if (why != AUTH_OK) {
+                     svcerr_auth(xprt, why);
+                     goto call_done;
+                } else if (no_dispatch) {
+                     goto call_done;
+                }
+\end{verbatim}
+\caption{A call to the modified _authenticate.}
+\label{fig:authenticate}
+\end{figure}
+
+If _authenticate sets no_dispatch to true, the call is considered
+finished and no procedure dispatch takes place.  Presumably, an
+authentication flavor that sets no_dispatch to true also replies to
+the RPC call with svc_sendreply.  Authentication flavors that do not
+modify no_dispatch implicitly leave it set to false, so the normal
+dispatch takes place.
+
+\subsection{Affected Files}
+
+Table \ref{tab:modfiles} lists the files that were
+affected for each of the modifications described in previous sections.
+
+\begin{table}[htbp]
+\centering
+\caption{Files modified for each change to Sun RPC.}
+\label{tab:modfiles}
+\begin{tabular}{ll}
+AUTH structure                  & auth.h \\
+                                & auth_none.c \\
+                                & auth_exit.c \\
+                                & auth_any.c \\
+Client Transport Mechanisms     & clnt_udp.c \\
+                                & clnt_tcp.c \\
+SVCAUTH and XPRT structures     & rpc.h \\
+                                & svc.h \\
+                                & svc_auth.h \\
+                                & svc.c \\
+                                & svc_auth.c \\
+                                & svc_auth_any.c \\
+                                & svc_auth_unix.c \\
+Server Transport Mechanisms     & svc_udp.c \\
+                                & svc_tcp.c
+\end{tabular}
+\end{table}
+
+\section{GSS-API Authentication Flavor}
+
+The following sections describe the implemetation of the GSS-API
+authentication flavor for Sun RPC.
+
+\subsection{Authentication Algorithms}
+\label{sec:algorithms}
+
+\subsubsection{Context Initiation}
+
+The client creates a GSS-API context with the server each time it
+calls auth_gssapi_create.  The context is created using the standard
+gss_init_sec_context and gss_accept_sec_context function calls.  The
+generated tokens are passed between the client and server as arguments
+and results of normal RPC calls.
+
+The client side, in auth_gssapi_create, performs the following steps
+to initiate a context:
+
+\begin{enumerate}
+\item\label{item:process-token} The client calls gss_init_sec_context.
+On the first such call, no input token is provided; on subsequent
+calls, the token received from the server is provided.
+
+\item If gss_init_sec_context produces an output token:
+
+\begin{enumerate}
+\item The client transmits the token to the server, identifying itself
+with client_handle if it has already been received (see next step).
+The return value from the server will contain a client_handle and one
+or both of a token and a signed initial sequence number.  
+
+\item If this is the first response from the server, the client_handle
+is stored for subsequent calls.  Otherwise, the client_handle should be
+the same as returned on the previous call.
+
+\item If the response contains a signed initian sequence number but
+the context is not yet established, then the response also contains a
+token that will established the context.  The signed initial sequence
+number is stored.
+
+\item If the response contains a token, step \ref{item:process-token}
+repeated.
+\end{enumerate}
+
+\item The signed initial sequence number is verified using the
+established context.
+\end{enumerate}
+
+The server side, in _svcauth_gssapi, performs the following steps to
+initiate a context:
+
+\begin{enumerate}
+\item If a call arrives with no client_handle, a new client_handle is
+allocated and stored in the database.  Otherwise, the client's
+previous state is is looked up in the database.
+
+\item The received token is passed to gss_accept_sec_context.  If an
+output token is generated, it is returned to the client.  Note that
+since the application server may have registered multiple service
+names and there is no way to determine {\it a priori} which service a
+token is for, _svcauth_gssapi calls gss_accept_sec_context once for
+each registered credential until one of them succeedes.  The code
+assumes that GSS_S_FAILURE is the only error that can result from a
+credential mismatch, so any other error terminates the loop
+immediately.
+
+\item If the context is established, the server signs an initial
+sequence number and returns it to the client.
+\end{enumerate}
+
+Note that these algorithms require context establishment to be
+synchronous.  If gss_init_sec_context returns GSS_S_COMPLETE upon
+processing a token, it will either produce a token or not.  If it
+does, then gss_accept_sec_context will return GSS_S_COMPLETE when that
+token is processed; if it does not, then gss_accept_sec_context
+already returned GSS_S_COMPLETE (and presumably returned the token
+that caused gss_init_sec_context to return GSS_S_COMPLETE when
+processed).  The reverse is also true.
+
+\subsubsection{RPC Calls}
+
+After the GSS-API context is established, both the server and the
+client posess a client handle and a corresponding sequence number.
+Each call from the client contains the client handle as the
+``credential'' so that the server can identify which context to apply
+to the call.
+
+Each client call and server response includes a ``verifier'' that
+contains the sealed current sequence number.\footnote{In a future
+version, the verifier will also contain a signature block for the call
+header, including the procedure number called.} The sequence number
+prevents replay attacks\footnote{Although some GSS-API mechanisms
+provide replay detection themselves, not all of them do; explicitly
+including the sequence number in the RPC therefore provides better
+end-to-end security}, but by itself it does not prevent splicing
+attacks.
+
+Each procedure argument and result block consists of the current
+sequence number and the actual serialized argument string, all sealed
+with gss_seal.  Combining the sequence number with the argument/result
+data prevents splicing attacks.
+
+The sequence number is incremented by one for each RPC call and by one
+for each response.  The client and server will both reject messages
+that do not contain the expected sequence number.  Packets
+retransmitted by the client should use the {\it same} sequence number
+as the original packet, since even if the server receives multiple
+copies only one will be honored.
+
+\subsection{RPC Call Credential Structure}
+
+Every message transmitted from the client to the server has a
+credentials (cb_cred) field of the type auth_gssapi_creds:
+
+\begin{verbatim}
+typedef struct _auth_gssapi_creds {
+        bool_t       auth_msg;
+        gss_buffer_desc client_handle;
+};
+\end{verbatim}
+
+The auth_msg field indicates whether the message is intended for the
+authentication mechanism for the actual server.  Any message whose
+auth_msg field is true is processed by the authentication mechanism;
+any message whose auth_msg is false is passed to the application
+server's dispatch function if authentication suceeds.  All messages
+must have an auth_msg of true until the context is established, since
+authentication cannot succeed until it is.
+
+The client_handle field contains the client handle obtained from the
+first call to the server.  On the first call, this field is empty.
+
+\subsection{GSS-API Authentication Flavor Procedures}
+
+The GSS-API authentication flavor uses standard RPC calls over the
+client handle it is provided for the interactions described in
+\ref{sec:algorithms}.  All of the following procedures require the
+auth_msg field in the credentials to be true; otherwise, the
+server-side authentication flavor will simply attempt to authenticate
+the caller and pass the call to the application server.  The
+server-side authentication flavor uses the no_dispatch variable to
+indicate that it has handled the call.
+
+\subsubsection{AUTH_GSSAPI_INIT, AUTH_GSSAPI_CONTINUE_INIT}
+
+Context initiation is performed via AUTH_GSSAPI_INIT and
+AUTH_GSSAPI_CONTINUE_INIT.  The former is used to transfer the first
+token generated by gss_init_sec_context, when no client handle is
+included in the credentials; the latter is used on subsequent calls,
+when a client handle is included.
+
+Both procedures take an argument of type auth_gssapi_init_arg and
+return results of the type auth_gssapi_init_res.
+
+\begin{verbatim}
+typedef struct _auth_gssapi_init_arg {
+        u_long       version;
+        gss_buffer_desc token;
+} auth_gssapi_init_arg;
+\end{verbatim}
+
+\begin{description}
+\item[version]  Three versions are presently defined.
+
+\begin{description}
+\item[1] The original version, as described in this document
+
+\item[2] In earlier versions of Secure there was a bug in the GSS-API
+library that affected the contents of accept_sec_context output
+tokens.  A client specifies version 2 to indicate that it expects the
+correct (fixed) behavior.  If the server indicates AUTH_BADCRED or
+AUTH_FAILED it does not understand this version, so the client should
+fall back to version 1.
+
+\item[3] Version three indicates that channel bindings are in use.
+The client must specify channel bindings with the version, and the
+server will as well.  If the server indicates AUTH_BADCRED or
+AUTH_FAILED it does not understand this version, so the client should
+fall back to version 2 (and cease specifying channel bindings).
+
+\item[4] The previous versions all used the old GSS-API krb5 mechanism
+oid; this version uses the new one specified in the RFC.  
+\end{description}
+
+\item[token] The token field contains the token generated by
+gss_init_sec_context.
+\end{description}
+
+\begin{verbatim}
+typedef struct _auth_gssapi_init_res {
+        u_long       version;
+        gss_buffer_desc client_handle;
+        gss_buffer_desc token;
+        OM_uint32 gss_major, gss_minor;
+        gss_buffer_desc signed_isn;
+} auth_gssapi_init_res;
+\end{verbatim}
+
+\begin{description}
+\item[version] There are two versions currently defined.
+\begin{description}
+\item[1] The original version, as described in this document.  This is
+the response version for {\it both} versions 1 and 2.  The Secure 1.1
+server will always return this version.
+
+\item[3] Version three indicates that the server specified channel
+bindings in response to a call arg version number of three.  The
+server must not specify this version unless the client does.
+\end{description}
+
+\item[client_handle] The client_handle field contains the client
+handle that the client must use in the credentials field in all
+subsequent RPC calls.  In response to AUTH_GSSAPI_CONTINUE_INIT, it is
+the same client handle that arrived in the credentials.
+
+\item[gss_major, gss_minor] The GSS-API error codes that resulted from
+processing the auth_gssapi_init_arg.  If gss_major is GSS_S_COMPLETE,
+the argument token was processed successfully.  Otherwise, gss_major
+and gss_minor contain the relevant major and minor status codes, and
+the context currently being negotiated is no longer valid.
+
+\item[token] In any response that the client is expecting another
+token (i.e.: gss_init_sec_context last returned GSS_S_CONTINUE), the
+token field contains the output token from gss_accept_sec_context.  If
+the client is not expecting a token and this field is not empty, an
+error has occurred.
+
+\item[signed_isn]  If the client is not expecting another token (i.e.:
+the previous call to gss_init_sec_context yielded a token and returned
+GSS_S_COMPLETE) or the supplied token completes the context, the
+signed_isn field contains the signed initial sequence number.  The
+server expects the first RPC call to have a sequence number one
+greater than the initial sequence number (so that the signed_isn block
+cannot be replayed).  If the client is expecting another token and the
+signed_isn field is not empty, an error has occurred.
+\end{description}
+
+\subsubsection{AUTH_GSSAPI_DESTROY}
+
+Context tear-down is performed via AUTH_GSSAPI_DESTROY.  This
+procedure takes no arguments and returns no results; it merely informs
+the server that the client wishes to destroy the established context.
+
+When a client wishes to tear down an established context between
+itself and a server, auth_gssapi_destroy first calls the
+AUTH_GSSAPI_DESTROY procedure.  The server authenticates the message
+and immediately sends a ``success'' response with no results.  The
+client and server then both independently call gss_delete_sec_context
+and discard the context-destruction token that is generated.
+
+No RPC error checking is performed by either the client or the server.
+The client waits a brief time for a success response from the server,
+but if none arrives it destroys the context anyway since presumably
+the user is waiting for the application to exit.  The server similar
+ignores any RPC errors since it knows that the client will ignore any
+errors that are reported.
+
+\subsection{RPC Call Authentication Implementation}
+
+Once the context has been established, all subsequent RPC calls are
+authenticated via the verifier described in section
+\ref{sec:algorithms}.
+
+auth_gssapi_marshall, invoked via AUTH_MARSHALL while the RPC call is
+being created on the client side, serializes the client_handle
+obtained during context initiation {\it in plaintext} as the
+credentials and serializes the current sequence number, sealed with
+gss_seal, as the verifier.
+
+auth_gssapi_wrap, invoked next via AUTH_WRAP, serializes a sealed
+token containing both the sequence number of the current call and the
+serialized arguments.
+
+_svcauth_gssapi, invoked on the server side by _authenticate, uses the
+client_handle contained in the credentials to look up the correct
+context and verifies the sequence number provided in the verifier; if
+the sequence number is not correct, it declares a potential replay
+attack.\footnote{Retransmitted packets will appear as replay attacks,
+of course.} The response verifier is set to the serialized sealed
+incremented sequence number.
+
+svc_auth_gssapi_unwrap, invoked when either the application server or
+_svcauth_gssapi (in response to an AUTH_GSSAPI authentication flavor
+message) attempts to read its arguments, deserialzes and unseals the
+block containing the current sequence number and serialized arguments.
+If the sequence number is incorrect, it declares a splicing attack;
+otherwise, it unserializes the arguments into the original structure.
+
+svc_auth_gssapi_wrap, invoked when either the application server or
+_svcauth_gssapi attempts to write its response, performs the same
+operation as auth_gssapi_wrap.
+
+auth_gssapi_validate, invoked by the client-side RPC mechanism when
+an RPC_SUCCESS response is received, verifies that the returned sequence
+number is one greater than the previous value sent by
+auth_gssapi_marshall.
+
+Finally, auth_gssapi_unwrap, invokved by the client-side RPC mechanism
+after auth_gssapi_validate succeeds, performs the same operation as
+svc_auth_gssapi_unwrap.
+
+If an RPC request generates an error message (a status of other than
+RPC_SUCCESS), auth_gssapi_refresh is called.  If the error status is
+AUTH_REJECTEDVERF, then the server rejected the sequence number as
+invalid or replayed.  The client guesses that, on some previous call,
+the server received a message but the server's response did not make
+it back to the client; this could happen if the packet got lost or if
+the server was being debugged and the client timed out waiting for it.
+As a result, the server is expected a higher sequence number than the
+client sent.  auth_gssapi_refresh increments the sequence number and
+returns true so that the call will be tried again.  The transport
+mechanism will only call auth_gssapi_refresh twice for each RPC
+request, so if some other error occurred an infinite loop will not
+result; however, it is unlikely the the client and server will be able
+to resynchronize after such an event.
+
+\subsection{Client State Information}
+
+The client-side GSS-API authentication flavor maintains an
+auth_gssapi_data structure for each authentication instance:
+
+\begin{verbatim}
+struct auth_gssapi_data {
+     bool_t established;
+     CLIENT *clnt;
+     gss_ctx_id_t context;
+     gss_buffer_desc client_handle;
+     u_long seq_num;
+     int def_cred;
+
+     /* pre-serialized ah_cred */
+     u_char cred_buf[MAX_AUTH_BYTES];
+     u_long cred_len;
+};
+\end{verbatim}
+
+The established field indicates whether the authentication context
+between the client and server has been established.  It is set to true
+when gss_init_sec_context returns GSS_S_COM\-PLETE.  When this field is
+false, the auth_gssapi functions marshall, validate, wrap, and unwrap
+mimic the ``no authentication'' flavor since there is no context with
+which to perform authentication functions.\footnote{This field is
+necessary because, when auth_gssapi_create calls clnt_call to make an
+RPC call, it has to have set the client's authentication flavor to
+AUTH_GSSAPI; otherwise, the service-side RPC mechanism will not know
+to dispatch the call to _svcauth_gssapi.  However, with the client's
+authentication flavor set, all of the authentication flavor's
+functions will be automatically invoked, even though they are not
+ready to operate.}
+
+The clnt field contains the RPC client structure that can be used to
+communicate with the GSS-API authentication flavor on the server.
+
+The context field contains the context structure created by
+gss_init_sec_context.
+
+The client_handle field contains the client handle used on all RPC
+calls except the first one; the handle is obtained as the result of
+the first call.
+
+The sequence_number field contains the sequence number that will be
+used when transmitting RPC calls to the server and verifing the
+server's responses after the context is initialized.
+
+The def_cred field is true if gss_init_sec_context created a default
+credential, in which case the authentication mechanism is responsible
+for releasing the default credential that gets automatically
+allocated.
+
+The cred_buf and cred_len fields contain the pre-serialized
+credentials structure used in each call.  This provides a small
+performance enhancement since the credentials structure does not
+change very often; the same pre-serialized version can be used on
+virtually every call.
+
+\subsection{Server State Information}
+\label{sec:server-state}
+
+The server-side GSS-API authentication flavor maintains an
+svcauth_gssapi_data structure for each established or partially
+established context:
+
+\begin{verbatim}
+typedef struct _svc_auth_gssapi_data {
+     bool_t established;
+     gss_ctx_id_t context;
+     gss_name_t client_name, server_name;
+     gss_cred_id_t server_creds;
+
+     u_long expiration;
+     u_long seq_num;
+     u_long key;
+
+     SVCAUTH svcauth;
+} svc_auth_gssapi_data;
+\end{verbatim}
+
+The established field indicates whether the context is fully
+established.
+
+The context field contains the context created by
+gss_accept_sec_context.
+
+The client_name field contains the client's authenticated name, as
+returned by gss_accept_sec_context.  _svcauth_gssapi sets the ``cooked
+credentials'' field of the RPC call structure to this value after the
+call is authenticated; the application server can use it to perform
+authorization.
+
+The server_name field contains the service name that the client
+established a context with.  This is useful if the application server
+registered more than one service name with the library; it allows the
+server to determine which service the client chose.
+
+The server_creds field contains the service credentials that the
+client established a context with.  It is used to avoid having to scan
+through the server_creds_list multiple times in the case that context
+establishment requires more than one round-trip to the server.
+
+The expiration field contains the expiration time of the context, as a
+Unix timestamp.  If a context has no expiration (time_rec is
+GSS_C_INDEFINITE), the expiration time is set to 24 hours in the
+future.  When the structure is created, before the context is
+established, the expiration time is initialized to small duration
+(currently 5 minutes) so that partially created and abandoned contexts
+will be expired quickly.
+
+The seq_num field is the current sequence number for the client.
+
+The key field is the client's key into the hash table (see below).
+The client_handle field sent to the client is the key treated as an
+arbitrary four-byte string.
+
+The svcauth field is a kludge that allows the svc_auth_gssapi
+functions to access the per-client data structure while processing a
+call.  One SVCAUTH structure is allocated for each client structure,
+and the svc_ah_private field is set to the corresponding client.  The
+client's svcauth field is then set to the new SVCAUTH structure, so
+that client_data->svcauth->svc_ah_private == client_data.  As each
+request is processed, the transport mechanism's xp_auth field is set
+to the client's svcauth field; thus, the server-side functions that
+dispatch to server-side authentication flavors can access an
+appropriate SVCAUTH structure, and the server-side authentication
+function that is called can determine the appropriate per-client
+structure from the SVCAUTH structure.
+
+The per-client structures are all stored both in a BSD 4.4 db library
+hash table and b-tree.  The hash table maps client handles (key
+fields) the client structures, and is used to look up client
+structures based on the client_handle field of a call's credentials
+structure.  The b-tree stores the client structures as keys, sorted by
+their expiration time.  Each time _svcauth_gssapi is activated, it
+traverses the tree and destroys all client structures that have
+expired.
+
+\end{document}
diff --git a/mechglue/doc/salts.texinfo b/mechglue/doc/salts.texinfo
new file mode 100644
index 000000000..3ed43db0e
--- /dev/null
+++ b/mechglue/doc/salts.texinfo
@@ -0,0 +1,19 @@
+@ignore 
+the information in this file should be consistent with the information
+in krb5/src/lib/krb5/krb/str_conv.c, in the struct salttype_lookup_entry
+@end ignore
+
+@table @code
+@item normal
+default for Kerberos Version 5
+@item v4
+the only type used by Kerberos Version 4, no salt
+@item norealm
+same as the default, without using realm information
+@item onlyrealm
+uses only realm information as the salt
+@item afs3
+AFS version 3, only used for compatibility with Kerberos 4 in AFS
+@item special
+only used in very special cases; not fully supported
+@end table
diff --git a/mechglue/doc/send-pr.texinfo b/mechglue/doc/send-pr.texinfo
new file mode 100644
index 000000000..e34ca935e
--- /dev/null
+++ b/mechglue/doc/send-pr.texinfo
@@ -0,0 +1,144 @@
+In any complex software, there will be bugs.  If you have successfully
+built and installed @value{PRODUCT}, please use the @code{krb5-send-pr}
+program to fill out a Problem Report should you encounter any errors in
+our software.
+
+Bug reports that include proposed fixes are especially welcome.  If you
+do include fixes, please send them using either context diffs or unified
+diffs (using @samp{diff -c} or @samp{diff -u}, respectively).  Please be
+careful when using ``cut and paste'' or other such means to copy a patch
+into a bug report; depending on the system being used, that can result
+in converting TAB characters into spaces, which makes applying the
+patches more difficult.
+
+The @code{krb5-send-pr} program is installed in the directory
+@code{@value{ROOTDIR}/sbin}.
+
+The @code{krb5-send-pr} program enters the problem report into our
+Problem Report Management System (PRMS), which automatically assigns it
+to the engineer best able to help you with problems in the assigned
+category.
+@ifset CYGNUS
+The engineer will work with you via email, telephone, or both, and all
+email related to this Problem Report will be tracked by PRMS for future
+reference.  If you need to talk to someone else in our organization
+about the problem (@i{e.g.}, if the engineer gets hit by a truck), we
+can find out what the current state is through the PR number.
+@end ifset
+
+The @code{krb5-send-pr} program will try to intelligently fill in as
+many fields as it can.  You need to choose the @dfn{category},
+@dfn{class}, @dfn{severity}, and @dfn{priority} of the problem, as well
+as giving us as much information as you can about its exact nature.
+
+@need 1000
+The PR @b{category} will be one of:
+
+@smallexample
+@group
+krb5-admin   krb5-appl    krb5-build   krb5-clients 
+krb5-doc     krb5-kdc     krb5-libs    krb5-misc    
+pty          telnet       test         
+@end group
+@end smallexample
+
+@noindent
+Choose the category that best describes the area under which your
+problem falls.
+
+The @b{class} can be @dfn{sw-bug}, @dfn{doc-bug}, @dfn{change-request},
+or @dfn{support}.  The first two are exactly as their names imply.  Use
+@i{change-request} when the software is behaving according to
+specifications, but you want to request changes in some feature or
+behavior.  The @i{support} class is intended for more general questions
+about building or using @value{PRODUCT}.
+
+The @b{severity} of the problem indicates the problem's impact on the
+usability of @value{PRODUCT}.  If a problem is @dfn{critical}, that
+means the product, component or concept is completely non-operational,
+or some essential functionality is missing, and no workaround is known.
+A @dfn{serious} problem is one in which the product, component or
+concept is not working properly or significant functionality is missing.
+Problems that would otherwise be considered @i{critical} are rated
+@i{serious} when a workaround is known.  A @dfn{non-critical} problem is
+one that is indeed a problem, but one that is having a minimal effect on
+your ability to use @value{PRODUCT}.  @i{E.g.}, The product, component
+or concept is working in general, but lacks features, has irritating
+behavior, does something wrong, or doesn't match its documentation.  The
+default severity is @i{serious}.
+
+The @b{priority} indicates how urgent this particular problem is in
+relation to your work.  Note that low priority does not imply low
+importance.
+@ifset CYGNUS
+@value{COMPANY} considers all problems important, and
+encourages its customers to be realistic about priority ratings.
+@end ifset
+A priority of @dfn{high} means a solution is needed as soon as possible.
+A priority of @dfn{medium} means the problem should be solved no later
+than the next release.  A priority of @dfn{low} means the problem should
+be solved in a future release, but it is not important to your work how
+soon this happens.  The default priority is @i{medium}.
+
+Note that a given severity does not necessarily imply a given priority.
+For example, a non-critical problem might still have a high priority if
+you are faced with a hard deadline.  Conversely, a serious problem might
+have a low priority if the feature it is disabling is one that you do
+not need.
+
+It is important that you fill in the @i{release} field and tell us
+what changes you have made, if any.
+
+@iftex
+@vfill
+@end iftex
+
+@page
+A sample filled-out form from a company named ``Toasters, Inc.'' might
+look like this:
+
+@smallexample
+@group
+To: krb5-bugs@@mit.edu
+Subject: misspelled "Kerberos" in title of installation guide
+From: jcb
+Reply-To: jcb
+Cc: 
+X-send-pr-version: 3.99
+
+
+>Submitter-Id:	mit
+>Originator:	Jeffrey C. Gilman Bigler
+>Organization:
+mit
+>Confidential:	no
+>Synopsis:	Misspelled "Kerberos" in title of installation guide
+>Severity:	non-critical
+>Priority:	low
+>Category:	krb5-doc
+>Class:		doc-bug
+>Release:	1.0-development
+>Environment:
+	<machine, os, target, libraries (multiple lines)>
+System: ULTRIX imbrium 4.2 0 RISC
+Machine: mips
+>Description:
+        Misspelled "Kerberos" in title of "Kerboros V5 Installation Guide"
+>How-To-Repeat:
+        N/A
+>Fix:
+        Correct the spelling.
+@end group        
+@end smallexample
+
+@iftex
+@vfill
+@end iftex
+
+If the @code{krb5-send-pr} program does not work for you, or if you did
+not get far enough in the process to have an installed and working
+@code{krb5-send-pr}, you can generate your own form, using the above as
+an example.
+
+
+
diff --git a/mechglue/doc/support-enc.texinfo b/mechglue/doc/support-enc.texinfo
new file mode 100644
index 000000000..ca4e8faab
--- /dev/null
+++ b/mechglue/doc/support-enc.texinfo
@@ -0,0 +1,33 @@
+@ignore 
+the information in this file should be consistent with the information
+in krb5/src/lib/crypto/etypes.c (and krb5/src/include/krb5.h[in]?)
+@end ignore
+
+@table @code
+@item des-cbc-crc 
+DES cbc mode with CRC-32
+@item des-cbc-md4 
+DES cbc mode with RSA-MD4
+@item des-cbc-md5 
+DES cbc mode with RSA-MD5
+@item des3-cbc-sha1 
+@itemx des3-hmac-sha1
+@itemx des3-cbc-sha1-kd
+triple DES cbc mode with HMAC/sha1
+@item des-hmac-sha1 
+DES with HMAC/sha1
+@item aes256-cts-hmac-sha1-96
+@itemx aes256-cts
+AES-256 CTS mode with 96-bit SHA-1 HMAC
+@item aes128-cts-hmac-sha1-96
+@itemx aes128-cts
+AES-128 CTS mode with 96-bit SHA-1 HMAC
+@item arcfour-hmac 
+@itemx rc4-hmac
+@itemx arcfour-hmac-md5
+RC4 with HMAC/MD5
+@item arcfour-hmac-exp 
+@itemx rc4-hmac-exp
+@itemx arcfour-hmac-md5-exp
+exportable RC4 with HMAC/MD5
+@end table
diff --git a/mechglue/doc/texinfo-suppl.tex b/mechglue/doc/texinfo-suppl.tex
new file mode 100644
index 000000000..4a1c0cdac
--- /dev/null
+++ b/mechglue/doc/texinfo-suppl.tex
@@ -0,0 +1,7 @@
+\def\temp{
+\chapternofonts
+\def\doubleleftarrow{\realbackslash doubleleftarrow}
+}
+\let\chapternofonts=\temp
+
+\def\doubleleftarrow{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Leftarrow$\hfil}}
diff --git a/mechglue/doc/texinfo.tex b/mechglue/doc/texinfo.tex
new file mode 100644
index 000000000..9d4147edc
--- /dev/null
+++ b/mechglue/doc/texinfo.tex
@@ -0,0 +1,4355 @@
+%% TeX macros to handle texinfo files
+
+%   Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
+
+%This texinfo.tex file is free software; you can redistribute it and/or
+%modify it under the terms of the GNU General Public License as
+%published by the Free Software Foundation; either version 2, or (at
+%your option) any later version.
+
+%This texinfo.tex file is distributed in the hope that it will be
+%useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+%of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%General Public License for more details.
+
+%You should have received a copy of the GNU General Public License
+%along with this texinfo.tex file; see the file COPYING.  If not, write
+%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+%USA.
+
+
+%In other words, you are welcome to use, share and improve this program.
+%You are forbidden to forbid anyone else to use, share and improve
+%what you give them.   Help stamp out software-hoarding!
+
+% This automatically updates the version number based on RCS.
+\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}}
+\deftexinfoversion$Revision$
+\message{Loading texinfo package [Version \texinfoversion]:}
+
+% Print the version number if in a .fmt file.
+\everyjob{\message{[Texinfo version \texinfoversion]}\message{}}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptextilde=\~
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexdots=\dots
+\let\ptexdot=\.
+\let\ptexstar=\*
+\let\ptexend=\end
+\let\ptexbullet=\bullet
+\let\ptexb=\b
+\let\ptexc=\c
+\let\ptexi=\i
+\let\ptext=\t
+\let\ptexl=\l
+\let\ptexL=\L
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ \gdef\tie{\leavevmode\penalty\@M\ }
+}
+\let\~ = \tie                  % And make it available as @~.
+
+\message{Basics,}
+\chardef\other=12
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Set up fixed words for English.
+\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi%
+\def\putwordInfo{Info}%
+\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi%
+\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi%
+\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi%
+\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi%
+\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi%
+\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi%
+\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi%
+\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi%
+\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi%
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset  \bindingoffset=0pt
+\newdimen \normaloffset   \normaloffset=\hoffset
+\newdimen\pagewidth \newdimen\pageheight
+\pagewidth=\hsize \pageheight=\vsize
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal.  We don't just call \tracingall here,
+% since that produces some useless output on the terminal.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{\tracingcommands2 \tracingstats2
+   \tracingpages1 \tracingoutput1 \tracinglostchars1
+   \tracingmacros2 \tracingparagraphs1 \tracingrestores1
+   \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+
+%---------------------Begin change-----------------------
+%
+%%%% For @cropmarks command.
+% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\cornerlong \newdimen\cornerthick
+\newdimen \topandbottommargin
+\newdimen \outerhsize \newdimen \outervsize
+\cornerlong=1pc\cornerthick=.3pt	% These set size of cropmarks
+\outerhsize=7in
+%\outervsize=9.5in
+% Alternative @smallbook page size is 9.25in
+\outervsize=9.25in
+\topandbottommargin=.75in
+%
+%---------------------End change-----------------------
+
+% \onepageout takes a vbox as an argument.  Note that \pagecontents
+% does insertions itself, but you have to call it yourself.
+\chardef\PAGE=255  \output={\onepageout{\pagecontents\PAGE}}
+\def\onepageout#1{\hoffset=\normaloffset
+\ifodd\pageno  \advance\hoffset by \bindingoffset
+\else \advance\hoffset by -\bindingoffset\fi
+{\escapechar=`\\\relax % makes sure backslash is used in output files.
+\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
+{\let\hsize=\pagewidth \makefootline}}}%
+\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+
+%%%% For @cropmarks command %%%%
+
+% Here is a modification of the main output routine for Near East Publications
+% This provides right-angle cropmarks at all four corners.
+% The contents of the page are centerlined into the cropmarks,
+% and any desired binding offset is added as an \hskip on either
+% site of the centerlined box.  (P. A. MacKay, 12 November, 1986)
+%
+\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
+{\escapechar=`\\\relax % makes sure backslash is used in output files.
+		 \shipout
+		 \vbox to \outervsize{\hsize=\outerhsize
+                 \vbox{\line{\ewtop\hfill\ewtop}}
+                 \nointerlineskip
+                 \line{\vbox{\moveleft\cornerthick\nstop}
+                       \hfill
+                       \vbox{\moveright\cornerthick\nstop}}
+                 \vskip \topandbottommargin
+                 \centerline{\ifodd\pageno\hskip\bindingoffset\fi
+			\vbox{
+			{\let\hsize=\pagewidth \makeheadline}
+			\pagebody{#1}
+			{\let\hsize=\pagewidth \makefootline}}
+			\ifodd\pageno\else\hskip\bindingoffset\fi}
+		 \vskip \topandbottommargin plus1fill minus1fill
+                 \boxmaxdepth\cornerthick
+                 \line{\vbox{\moveleft\cornerthick\nsbot}
+                       \hfill
+                       \vbox{\moveright\cornerthick\nsbot}}
+                 \nointerlineskip
+                 \vbox{\line{\ewbot\hfill\ewbot}}
+	}}
+  \advancepageno
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+%
+% Do @cropmarks to get crop marks
+\def\cropmarks{\let\onepageout=\croppageout }
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+%
+% Here are the rules for the cropmarks.  Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+  {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+  {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.  The argument is the rest of
+% the input line (except we remove a trailing comment).  #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+%
+\def\parsearg#1{%
+  \let\next = #1%
+  \begingroup
+    \obeylines
+    \futurelet\temp\parseargx
+}
+
+% If the next token is an obeyed space (from an @example environment or
+% the like), remove it and recurse.  Otherwise, we're done.
+\def\parseargx{%
+  % \obeyedspace is defined far below, after the definition of \sepspaces.
+  \ifx\obeyedspace\temp
+    \expandafter\parseargdiscardspace
+  \else
+    \expandafter\parseargline
+  \fi
+}
+
+% Remove a single space (as the delimiter token to the macro call).
+{\obeyspaces %
+ \gdef\parseargdiscardspace {\futurelet\temp\parseargx}}
+
+{\obeylines %
+  \gdef\parseargline#1^^M{%
+    \endgroup % End of the group started in \parsearg.
+    %
+    % First remove any @c comment, then any @comment.
+    % Result of each macro is put in \toks0.
+    \argremovec #1\c\relax %
+    \expandafter\argremovecomment \the\toks0 \comment\relax %
+    %
+    % Call the caller's macro, saved as \next in \parsearg.
+    \expandafter\next\expandafter{\the\toks0}%
+  }%
+}
+
+% Since all \c{,omment} does is throw away the argument, we can let TeX
+% do that for us.  The \relax here is matched by the \relax in the call
+% in \parseargline; it could be more or less anything, its purpose is
+% just to delimit the argument to the \c.
+\def\argremovec#1\c#2\relax{\toks0 = {#1}}
+\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}}
+
+% \argremovec{,omment} might leave us with trailing spaces, though; e.g.,
+%    @end itemize  @c foo
+% will have two active spaces as part of the argument with the
+% `itemize'.  Here we remove all active spaces from #1, and assign the
+% result to \toks0.
+%
+% This loses if there are any *other* active characters besides spaces
+% in the argument -- _ ^ +, for example -- since they get expanded.
+% Fortunately, Texinfo does not define any such commands.  (If it ever
+% does, the catcode of the characters in questionwill have to be changed
+% here.)  But this means we cannot call \removeactivespaces as part of
+% \argremovec{,omment}, since @c uses \parsearg, and thus the argument
+% that \parsearg gets might well have any character at all in it.
+%
+\def\removeactivespaces#1{%
+  \begingroup
+    \ignoreactivespaces
+    \edef\temp{#1}%
+    \global\toks0 = \expandafter{\temp}%
+  \endgroup
+}
+
+% Change the active space to expand to nothing.
+%
+\begingroup
+  \obeyspaces
+  \gdef\ignoreactivespaces{\obeyspaces\let =\empty}
+\endgroup
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment.  Type Return to continue.}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo  is the same as @foo, for now.
+\newhelp\EMsimple{Type <Return> to continue.}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+% @end foo executes the definition of \Efoo.
+%
+\def\end{\parsearg\endxxx}
+\def\endxxx #1{%
+  \removeactivespaces{#1}%
+  \edef\endthing{\the\toks0}%
+  %
+  \expandafter\ifx\csname E\endthing\endcsname\relax
+    \expandafter\ifx\csname \endthing\endcsname\relax
+      % There's no \foo, i.e., no ``environment'' foo.
+      \errhelp = \EMsimple
+      \errmessage{Undefined command `@end \endthing'}%
+    \else
+      \unmatchedenderror\endthing
+    \fi
+  \else
+    % Everything's ok; the right environment has been started.
+    \csname E\endthing\endcsname
+  \fi
+}
+
+% There is an environment #1, but it hasn't been started.  Give an error.
+%
+\def\unmatchedenderror#1{%
+  \errhelp = \EMsimple
+  \errmessage{This `@end #1' doesn't have a matching `@#1'}%
+}
+
+% Define the control sequence \E#1 to give an unmatched @end error.
+%
+\def\defineunmatchedend#1{%
+  \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}%
+}
+
+
+% Single-spacing is done by various environments (specifically, in
+% \nonfillstart and \quotations).
+\newskip\singlespaceskip \singlespaceskip = 12.5pt
+\def\singlespace{%
+  % Why was this kern here?  It messes up equalizing space above and below
+  % environments.  --karl, 6may93
+  %{\advance \baselineskip by -\singlespaceskip
+  %\kern \baselineskip}%
+  \setleading \singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt \char '100}}
+
+% This is turned off because it was never documented
+% and you can use @w{...} around a quote to suppress ligatures.
+%% Define @` and @' to be the same as ` and '
+%% but suppressing ligatures.
+%\def\`{{`}}
+%\def\'{{'}}
+
+% Used to generate quoted braces.
+
+\def\mylbrace {{\tt \char '173}}
+\def\myrbrace {{\tt \char '175}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @enddots{} is an end-of-sentence ellipsis.
+\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000}
+
+% @! is an end-of-sentence bang.
+\gdef\!{!\spacefactor=3000 }
+
+% @? is an end-of-sentence query.
+\gdef\?{?\spacefactor=3000 }
+
+% @w prevents a word break.  Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox.  We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line.  According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0).  If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+\def\group{\begingroup
+  \ifnum\catcode13=\active \else
+    \errhelp = \groupinvalidhelp
+    \errmessage{@group invalid in context where filling is enabled}%
+  \fi
+  %
+  % The \vtop we start below produces a box with normal height and large
+  % depth; thus, TeX puts \baselineskip glue before it, and (when the
+  % next line of text is done) \lineskip glue after it.  (See p.82 of
+  % the TeXbook.)  Thus, space below is not quite equal to space
+  % above.  But it's pretty close.
+  \def\Egroup{%
+    \egroup           % End the \vtop.
+    \endgroup         % End the \group.
+  }%
+  %
+  \vtop\bgroup
+    % We have to put a strut on the last line in case the @group is in
+    % the midst of an example, rather than completely enclosing it.
+    % Otherwise, the interline space between the last line of the group
+    % and the first line afterwards is too small.  But we can't put the
+    % strut in \Egroup, since there it would be on a line by itself.
+    % Hence this just inserts a strut at the beginning of each line.
+    \everypar = {\strut}%
+    %
+    % Since we have a strut on every line, we don't need any of TeX's
+    % normal interline spacing.
+    \offinterlineskip
+    %
+    % OK, but now we have to do something about blank
+    % lines in the input in @example-like environments, which normally
+    % just turn into \lisppar, which will insert no space now that we've
+    % turned off the interline space.  Simplest is to make them be an
+    % empty paragraph.
+    \ifx\par\lisppar
+      \edef\par{\leavevmode \par}%
+      %
+      % Reset ^^M's definition to new definition of \par.
+      \obeylines
+    \fi
+    %
+    % Do @comment since we are called inside an environment such as
+    % @example, where each end-of-line in the input causes an
+    % end-of-line in the output.  We don't want the end-of-line after
+    % the `@group' to put extra space in the output.  Since @group
+    % should appear on a line by itself (according to the Texinfo
+    % manual), we don't worry about eating any user text.
+    \comment
+}
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil  \mil=0.001in
+
+\def\need{\parsearg\needx}
+
+% Old definition--didn't work.
+%\def\needx #1{\par %
+%% This method tries to make TeX break the page naturally
+%% if the depth of the box does not fit.
+%{\baselineskip=0pt%
+%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000
+%\prevdepth=-1000pt
+%}}
+
+\def\needx#1{%
+  % Go into vertical mode, so we don't make a big box in the middle of a
+  % paragraph.
+  \par
+  %
+  % Don't add any leading before our big empty box, but allow a page
+  % break, since the best break might be right here.
+  \allowbreak
+  \nointerlineskip
+  \vtop to #1\mil{\vfil}%
+  %
+  % TeX does not even consider page breaks if a penalty added to the
+  % main vertical list is 10000 or more.  But in order to see if the
+  % empty box we just added fits on the page, we must make it consider
+  % page breaks.  On the other hand, we don't want to actually break the
+  % page after the empty box.  So we use a penalty of 9999.
+  %
+  % There is an extremely small chance that TeX will actually break the
+  % page at this \penalty, if there are no other feasible breakpoints in
+  % sight.  (If the user is using lots of big @group commands, which
+  % almost-but-not-quite fill up a page, TeX will have a hard time doing
+  % good page breaking, for example.)  However, I could not construct an
+  % example where a page broke at this \penalty; if it happens in a real
+  % document, then we can reconsider our strategy.
+  \penalty9999
+  %
+  % Back up by the size of the box, whether we did a page break or not.
+  \kern -#1\mil
+  %
+  % Do not allow a page break right after this kern.
+  \nobreak
+}
+
+% @br   forces paragraph break
+
+\let\br = \par
+
+% @dots{}  output some dots
+
+\def\dots{$\ldots$}
+
+% @page    forces the start of a new page
+
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\def\exdent{\parsearg\exdentyyy}
+\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}}
+
+% This defn is used inside nofill environments such as @example.
+\def\nofillexdent{\parsearg\nofillexdentyyy}
+\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount
+\leftline{\hskip\leftskip{\rm#1}}}}
+
+%\hbox{{\rm#1}}\hfil\break}}
+
+% @include file    insert text of that file as input.
+
+\def\include{\parsearg\includezzz}
+%Use \input\thisfile to avoid blank after \input, which may be an active
+%char (in which case the blank would become the \input argument).
+%The grouping keeps the value of \thisfile correct even when @include
+%is nested.
+\def\includezzz #1{\begingroup
+\def\thisfile{#1}\input\thisfile
+\endgroup}
+
+\def\thisfile{}
+
+% @center line   outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n   outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\par \vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other%
+\parsearg \commentxxx}
+
+\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 }
+
+\let\c=\comment
+
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+\let\chapter=\relax
+\let\unnumbered=\relax
+\let\top=\relax
+\let\unnumberedsec=\relax
+\let\unnumberedsection=\relax
+\let\unnumberedsubsec=\relax
+\let\unnumberedsubsection=\relax
+\let\unnumberedsubsubsec=\relax
+\let\unnumberedsubsubsection=\relax
+\let\section=\relax
+\let\subsec=\relax
+\let\subsubsec=\relax
+\let\subsection=\relax
+\let\subsubsection=\relax
+\let\appendix=\relax
+\let\appendixsec=\relax
+\let\appendixsection=\relax
+\let\appendixsubsec=\relax
+\let\appendixsubsection=\relax
+\let\appendixsubsubsec=\relax
+\let\appendixsubsubsection=\relax
+\let\contents=\relax
+\let\smallbook=\relax
+\let\titlepage=\relax
+}
+
+% Used in nested conditionals, where we have to parse the Texinfo source
+% and so want to turn off most commands, in case they are used
+% incorrectly.
+%
+\def\ignoremorecommands{%
+  \let\defcv = \relax
+  \let\deffn = \relax
+  \let\deffnx = \relax
+  \let\defindex = \relax
+  \let\defivar = \relax
+  \let\defmac = \relax
+  \let\defmethod = \relax
+  \let\defop = \relax
+  \let\defopt = \relax
+  \let\defspec = \relax
+  \let\deftp = \relax
+  \let\deftypefn = \relax
+  \let\deftypefun = \relax
+  \let\deftypevar = \relax
+  \let\deftypevr = \relax
+  \let\defun = \relax
+  \let\defvar = \relax
+  \let\defvr = \relax
+  \let\ref = \relax
+  \let\xref = \relax
+  \let\printindex = \relax
+  \let\pxref = \relax
+  \let\settitle = \relax
+  \let\include = \relax
+  \let\lowersections = \relax
+  \let\down = \relax
+  \let\raisesections = \relax
+  \let\up = \relax
+  \let\set = \relax
+  \let\clear = \relax
+  \let\item = \relax
+  \let\message = \relax
+}
+
+% Ignore @ignore ... @end ignore.
+%
+\def\ignore{\doignore{ignore}}
+
+% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text.
+%
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\html{\doignore{html}}
+\def\menu{\doignore{menu}}
+\def\direntry{\doignore{direntry}}
+
+% Ignore text until a line `@end #1'.
+%
+\def\doignore#1{\begingroup
+  % Don't complain about control sequences we have declared \outer.
+  \ignoresections
+  %
+  % Define a command to swallow text until we reach `@end #1'.
+  \long\def\doignoretext##1\end #1{\enddoignore}%
+  %
+  % Make sure that spaces turn into tokens that match what \doignoretext wants.
+  \catcode32 = 10
+  %
+  % And now expand that command.
+  \doignoretext
+}
+
+% What we do to finish off ignored text.
+%
+\def\enddoignore{\endgroup\ignorespaces}%
+
+\newif\ifwarnedobs\warnedobsfalse
+\def\obstexwarn{%
+  \ifwarnedobs\relax\else
+  % We need to warn folks that they may have trouble with TeX 3.0.
+  % This uses \immediate\write16 rather than \message to get newlines.
+    \immediate\write16{}
+    \immediate\write16{***WARNING*** for users of Unix TeX 3.0!}
+    \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).}
+    \immediate\write16{If you are running another version of TeX, relax.}
+    \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.}
+    \immediate\write16{  Then upgrade your TeX installation if you can.}
+    \immediate\write16{If you are stuck with version 3.0, run the}
+    \immediate\write16{  script ``tex3patch'' from the Texinfo distribution}
+    \immediate\write16{  to use a workaround.}
+    \immediate\write16{}
+    \warnedobstrue
+    \fi
+}
+
+% **In TeX 3.0, setting text in \nullfont hangs tex.  For a
+% workaround (which requires the file ``dummy.tfm'' to be installed),
+% uncomment the following line:
+%%%%%\font\nullfont=dummy\let\obstexwarn=\relax
+
+% Ignore text, except that we keep track of conditional commands for
+% purposes of nesting, up to an `@end #1' command.
+%
+\def\nestedignore#1{%
+  \obstexwarn
+  % We must actually expand the ignored text to look for the @end
+  % command, so that nested ignore constructs work.  Thus, we put the
+  % text into a \vbox and then do nothing with the result.  To minimize
+  % the change of memory overflow, we follow the approach outlined on
+  % page 401 of the TeXbook: make the current font be a dummy font.
+  %
+  \setbox0 = \vbox\bgroup
+    % Don't complain about control sequences we have declared \outer.
+    \ignoresections
+    %
+    % Define `@end #1' to end the box, which will in turn undefine the
+    % @end command again.
+    \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}%
+    %
+    % We are going to be parsing Texinfo commands.  Most cause no
+    % trouble when they are used incorrectly, but some commands do
+    % complicated argument parsing or otherwise get confused, so we
+    % undefine them.
+    %
+    % We can't do anything about stray @-signs, unfortunately;
+    % they'll produce `undefined control sequence' errors.
+    \ignoremorecommands
+    %
+    % Set the current font to be \nullfont, a TeX primitive, and define
+    % all the font commands to also use \nullfont.  We don't use
+    % dummy.tfm, as suggested in the TeXbook, because not all sites
+    % might have that installed.  Therefore, math mode will still
+    % produce output, but that should be an extremely small amount of
+    % stuff compared to the main input.
+    %
+    \nullfont
+    \let\tenrm = \nullfont  \let\tenit = \nullfont  \let\tensl = \nullfont
+    \let\tenbf = \nullfont  \let\tentt = \nullfont  \let\smallcaps = \nullfont
+    \let\tensf = \nullfont
+    % Similarly for index fonts (mostly for their use in
+    % smallexample)
+    \let\indrm = \nullfont  \let\indit = \nullfont  \let\indsl = \nullfont
+    \let\indbf = \nullfont  \let\indtt = \nullfont  \let\indsc = \nullfont
+    \let\indsf = \nullfont
+    %
+    % Don't complain when characters are missing from the fonts.
+    \tracinglostchars = 0
+    %
+    % Don't bother to do space factor calculations.
+    \frenchspacing
+    %
+    % Don't report underfull hboxes.
+    \hbadness = 10000
+    %
+    % Do minimal line-breaking.
+    \pretolerance = 10000
+    %
+    % Do not execute instructions in @tex
+    \def\tex{\doignore{tex}}
+}
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.
+%
+\def\set{\parsearg\setxxx}
+\def\setxxx#1{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+  \def\temp{#2}%
+  \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
+  \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
+  \fi
+}
+\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\def\clear{\parsearg\clearxxx}
+\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax}
+
+% @value{foo} gets the text saved in variable foo.
+%
+\def\value#1{\expandafter
+		\ifx\csname SET#1\endcsname\relax
+			{\{No value for ``#1''\}}
+		\else \csname SET#1\endcsname \fi}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+\def\ifset{\parsearg\ifsetxxx}
+\def\ifsetxxx #1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \expandafter\ifsetfail
+  \else
+    \expandafter\ifsetsucceed
+  \fi
+}
+\def\ifsetsucceed{\conditionalsucceed{ifset}}
+\def\ifsetfail{\nestedignore{ifset}}
+\defineunmatchedend{ifset}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+\def\ifclear{\parsearg\ifclearxxx}
+\def\ifclearxxx #1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \expandafter\ifclearsucceed
+  \else
+    \expandafter\ifclearfail
+  \fi
+}
+\def\ifclearsucceed{\conditionalsucceed{ifclear}}
+\def\ifclearfail{\nestedignore{ifclear}}
+\defineunmatchedend{ifclear}
+
+% @iftex always succeeds; we read the text following, through @end
+% iftex).  But `@end iftex' should be valid only after an @iftex.
+%
+\def\iftex{\conditionalsucceed{iftex}}
+\defineunmatchedend{iftex}
+
+% We can't just want to start a group at @iftex (for example) and end it
+% at @end iftex, since then @set commands inside the conditional have no
+% effect (they'd get reverted at the end of the group).  So we must
+% define \Eiftex to redefine itself to be its previous value.  (We can't
+% just define it to fail again with an ``unmatched end'' error, since
+% the @ifset might be nested.)
+%
+\def\conditionalsucceed#1{%
+  \edef\temp{%
+    % Remember the current value of \E#1.
+    \let\nece{prevE#1} = \nece{E#1}%
+    %
+    % At the `@end #1', redefine \E#1 to be its previous value.
+    \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}%
+  }%
+  \temp
+}
+
+% We need to expand lots of \csname's, but we don't want to expand the
+% control sequences after we've constructed them.
+%
+\def\nece#1{\expandafter\noexpand\csname#1\endcsname}
+
+% @asis just yields its argument.  Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math means output in math mode.
+% We don't use $'s directly in the definition of \math because control
+% sequences like \math are expanded when the toc file is written.  Then,
+% we read the toc file back, the $'s will be normal characters (as they
+% should be, according to the definition of Texinfo).  So we must use a
+% control sequence to switch into and out of math mode.
+%
+% This isn't quite enough for @math to work properly in indices, but it
+% seems unlikely it will ever be needed there.
+%
+\let\implicitmath = $
+\def\math#1{\implicitmath #1\implicitmath}
+
+% @bullet and @minus need the same treatment as @math, just above.
+\def\bullet{\implicitmath\ptexbullet\implicitmath}
+\def\minus{\implicitmath-\implicitmath}
+
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\nwnode=\node
+\let\lastnode=\relax
+
+\def\donoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\setref{\lastnode}\fi
+\global\let\lastnode=\relax}
+
+\def\unnumbnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
+\global\let\lastnode=\relax}
+
+\def\appendixnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi
+\global\let\lastnode=\relax}
+
+\let\refill=\relax
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+   \readauxfile
+   \opencontents
+   \openindices
+   \fixbackslash  % Turn off hack to swallow `\input texinfo'.
+   \global\let\setfilename=\comment % Ignore extra @setfilename cmds.
+   \comment % Ignore the actual filename.
+}
+
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+  node \samp{\ignorespaces#1{}}}
+
+\message{fonts,}
+
+% Font-change commands.
+
+% Texinfo supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf analogous to plain's \rm, etc.
+\newfam\sffam
+\def\sf{\fam=\sffam \tensf}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+%% Try out Computer Modern fonts at \magstephalf
+\let\mainmagstep=\magstephalf
+
+\ifx\bigger\relax
+\let\mainmagstep=\magstep1
+\font\textrm=cmr12
+\font\texttt=cmtt12
+\else
+\font\textrm=cmr10 scaled \mainmagstep
+\font\texttt=cmtt10 scaled \mainmagstep
+\fi
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\font\textbf=cmb10 scaled \mainmagstep
+\font\textit=cmti10 scaled \mainmagstep
+\font\textsl=cmsl10 scaled \mainmagstep
+\font\textsf=cmss10 scaled \mainmagstep
+\font\textsc=cmcsc10 scaled \mainmagstep
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+
+% A few fonts for @defun, etc.
+\font\defbf=cmbx10 scaled \magstep1 %was 1314
+\font\deftt=cmtt10 scaled \magstep1
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
+
+% Fonts for indices and small examples.
+% We actually use the slanted font rather than the italic,
+% because texinfo normally uses the slanted fonts for that.
+% Do not make many font distinctions in general in the index, since they
+% aren't very useful.
+\font\ninett=cmtt9
+\font\indrm=cmr9
+\font\indit=cmsl9
+\let\indsl=\indit
+\let\indtt=\ninett
+\let\indsf=\indrm
+\let\indbf=\indrm
+\let\indsc=\indrm
+\font\indi=cmmi9
+\font\indsy=cmsy9
+
+% Fonts for headings
+\font\chaprm=cmbx12 scaled \magstep2
+\font\chapit=cmti12 scaled \magstep2
+\font\chapsl=cmsl12 scaled \magstep2
+\font\chaptt=cmtt12 scaled \magstep2
+\font\chapsf=cmss12 scaled \magstep2
+\let\chapbf=\chaprm
+\font\chapsc=cmcsc10 scaled\magstep3
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+
+\font\secrm=cmbx12 scaled \magstep1
+\font\secit=cmti12 scaled \magstep1
+\font\secsl=cmsl12 scaled \magstep1
+\font\sectt=cmtt12 scaled \magstep1
+\font\secsf=cmss12 scaled \magstep1
+\font\secbf=cmbx12 scaled \magstep1
+\font\secsc=cmcsc10 scaled\magstep2
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+
+% \font\ssecrm=cmbx10 scaled \magstep1    % This size an font looked bad.
+% \font\ssecit=cmti10 scaled \magstep1    % The letters were too crowded.
+% \font\ssecsl=cmsl10 scaled \magstep1
+% \font\ssectt=cmtt10 scaled \magstep1
+% \font\ssecsf=cmss10 scaled \magstep1
+
+%\font\ssecrm=cmb10 scaled 1315	% Note the use of cmb rather than cmbx.
+%\font\ssecit=cmti10 scaled 1315	% Also, the size is a little larger than
+%\font\ssecsl=cmsl10 scaled 1315	% being scaled magstep1.
+%\font\ssectt=cmtt10 scaled 1315
+%\font\ssecsf=cmss10 scaled 1315
+
+%\let\ssecbf=\ssecrm
+
+\font\ssecrm=cmbx12 scaled \magstephalf
+\font\ssecit=cmti12 scaled \magstephalf
+\font\ssecsl=cmsl12 scaled \magstephalf
+\font\ssectt=cmtt12 scaled \magstephalf
+\font\ssecsf=cmss12 scaled \magstephalf
+\font\ssecbf=cmbx12 scaled \magstephalf
+\font\ssecsc=cmcsc10 scaled \magstep1
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled \magstep1
+% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
+% but that is not a standard magnification.
+
+% Fonts for title page:
+\font\titlerm = cmbx12 scaled \magstep3
+\let\authorrm = \secrm
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.  Since
+% texinfo doesn't allow for producing subscripts and superscripts, we
+% don't bother to reset \scriptfont and \scriptscriptfont (which would
+% also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+  \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy
+  \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf
+  \textfont\ttfam = \tentt \textfont\sffam = \tensf
+}
+
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE.  We do this so that font changes will continue to work
+% in math mode, where it is the current \fam that is relevant in most
+% cases, not the current.  Plain TeX does, for example,
+% \def\bf{\fam=\bffam \tenbf}  By redefining \tenbf, we obviate the need
+% to redefine \bf itself.
+\def\textfonts{%
+  \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+  \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+  \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
+  \resetmathfonts}
+\def\chapfonts{%
+  \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+  \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+  \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
+  \resetmathfonts}
+\def\secfonts{%
+  \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+  \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+  \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
+  \resetmathfonts}
+\def\subsecfonts{%
+  \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+  \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+  \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
+  \resetmathfonts}
+\def\indexfonts{%
+  \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl
+  \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
+  \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy
+  \resetmathfonts}
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\textfonts
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\font\shortcontrm=cmr12
+\font\shortcontbf=cmbx12
+\font\shortcontsl=cmsl12
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi}
+\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\var=\smartitalic
+\let\dfn=\smartitalic
+\let\emph=\smartitalic
+\let\cite=\smartitalic
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph.  Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1  \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+\def\t#1{%
+  {\tt \nohyphenation \rawbackslash \frenchspacing #1}%
+  \null
+}
+\let\ttfont = \t
+%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null}
+\def\samp #1{`\tclose{#1}'\null}
+\def\key #1{{\tt \nohyphenation \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+\let\file=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\def\tclose#1{%
+  {%
+    % Change normal interword space to be same as for the current font.
+    \spaceskip = \fontdimen2\font
+    %
+    % Switch to typewriter.
+    \tt
+    %
+    % But `\ ' produces the large typewriter interword space.
+    \def\ {{\spaceskip = 0pt{} }}%
+    %
+    % Turn off hyphenation.
+    \nohyphenation
+    %
+    \rawbackslash
+    \frenchspacing
+    #1%
+  }%
+  \null
+}
+
+% We *must* turn on hyphenation at `-' and `_' in \code.
+% Otherwise, it is too hard to avoid overful hboxes
+% in the Emacs manual, the Library manual, etc.
+
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate an a dash.
+%  -- rms.
+{
+\catcode`\-=\active
+\catcode`\_=\active
+\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex}
+% The following is used by \doprintindex to insure that long function names
+% wrap around.  It is necessary for - and _ to be active before the index is
+% read from the file, as \entry parses the arguments long before \code is
+% ever called.  -- mycroft
+\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder}
+}
+\def\realdash{-}
+\def\realunder{_}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{\normalunderscore\discretionary{}{}{}}
+\def\codex #1{\tclose{#1}\endgroup}
+
+%\let\exp=\tclose  %Was temporary
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else\tclose{\look}\fi
+\else\tclose{\look}\fi}
+
+% Typeset a dimension, e.g., `in' or `pt'.  The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of
+% @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
+
+\def\l#1{{\li #1}\null}		%
+
+\def\r#1{{\rm #1}}		% roman font
+% Use of \lowercase was suggested.
+\def\sc#1{{\smallcaps#1}}	% smallcaps font
+\def\ii#1{{\it #1}}		% italic font
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page.  Must do @settitle before @titlepage.
+\def\titlefont#1{{\titlerm #1}}
+
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+\def\shorttitlepage{\parsearg\shorttitlepagezzz}
+\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+	\endgroup\page\hbox{}\page}
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+   \let\subtitlerm=\tenrm
+% I deinstalled the following change because \cmr12 is undefined.
+% This change was not in the ChangeLog anyway.  --rms.
+%   \let\subtitlerm=\cmr12
+   \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
+   %
+   \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+   %
+   % Leave some space at the very top of the page.
+   \vglue\titlepagetopglue
+   %
+   % Now you can print the title using @title.
+   \def\title{\parsearg\titlezzz}%
+   \def\titlezzz##1{\leftline{\titlefont{##1}}
+		    % print a rule at the page bottom also.
+		    \finishedtitlepagefalse
+		    \vskip4pt \hrule height 4pt width \hsize \vskip4pt}%
+   % No rule at page bottom unless we print one at the top with @title.
+   \finishedtitlepagetrue
+   %
+   % Now you can put text using @subtitle.
+   \def\subtitle{\parsearg\subtitlezzz}%
+   \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+   %
+   % @author should come last, but may come many times.
+   \def\author{\parsearg\authorzzz}%
+   \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+      {\authorfont \leftline{##1}}}%
+   %
+   % Most title ``pages'' are actually two pages long, with space
+   % at the top of the second.  We don't want the ragged left on the second.
+   \let\oldpage = \page
+   \def\page{%
+      \iffinishedtitlepage\else
+	 \finishtitlepage
+      \fi
+      \oldpage
+      \let\page = \oldpage
+      \hbox{}}%
+%   \def\page{\oldpage \hbox{}}
+}
+
+\def\Etitlepage{%
+   \iffinishedtitlepage\else
+      \finishtitlepage
+   \fi
+   % It is important to do the page break before ending the group,
+   % because the headline and footline are only empty inside the group.
+   % If we use the new definition of \page, we always get a blank page
+   % after the title page, which we certainly don't want.
+   \oldpage
+   \endgroup
+   \HEADINGSon
+}
+
+\def\finishtitlepage{%
+   \vskip4pt \hrule height 2pt width \hsize
+   \vskip\titlepagebottomglue
+   \finishedtitlepagetrue
+}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks \evenheadline    % Token sequence for heading line of even pages
+\newtoks \oddheadline     % Token sequence for heading line of odd pages
+\newtoks \evenfootline    % Token sequence for footing line of even pages
+\newtoks \oddfootline     % Token sequence for footing line of odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+                            \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+                            \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
+\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
+\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+%
+}% unbind the catcode of @.
+
+% @headings double	turns headings on for double-sided printing.
+% @headings single	turns headings on for single-sided printing.
+% @headings off		turns them off.
+% @headings on		same as @headings double, retained for compatibility.
+% @headings after	turns on double-sided headings after this page.
+% @headings doubleafter	turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line...  specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+\message{tables,}
+
+% @tabs -- simple alignment
+
+% These don't work.  For one thing, \+ is defined as outer.
+% So these macros cannot even be defined.
+
+%\def\tabs{\parsearg\tabszzz}
+%\def\tabszzz #1{\settabs\+#1\cr}
+%\def\tabline{\parsearg\tablinezzz}
+%\def\tablinezzz #1{\+#1\cr}
+%\def\&{&}
+
+% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @vtable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\itemxpar \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
+                 \itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
+                 \itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+  \advance\hsize by -\rightskip
+  \advance\hsize by -\tableindent
+  \setbox0=\hbox{\itemfont{#1}}%
+  \itemindex{#1}%
+  \nobreak % This prevents a break before @itemx.
+  %
+  % Be sure we are not still in the middle of a paragraph.
+  %{\parskip = 0in
+  %\par
+  %}%
+  %
+  % If the item text does not fit in the space we have, put it on a line
+  % by itself, and do not allow a page break either before or after that
+  % line.  We do not start a paragraph here because then if the next
+  % command is, e.g., @kindex, the whatsit would get put into the
+  % horizontal list on a line by itself, resulting in extra blank space.
+  \ifdim \wd0>\itemmax
+    %
+    % Make this a paragraph so we get the \parskip glue and wrapping,
+    % but leave it ragged-right.
+    \begingroup
+      \advance\leftskip by-\tableindent
+      \advance\hsize by\tableindent
+      \advance\rightskip by0pt plus1fil
+      \leavevmode\unhbox0\par
+    \endgroup
+    %
+    % We're going to be starting a paragraph, but we don't want the
+    % \parskip glue -- logically it's part of the @item we just started.
+    \nobreak \vskip-\parskip
+    %
+    % Stop a page break at the \parskip glue coming up.  Unfortunately
+    % we can't prevent a possible page break at the following
+    % \baselineskip glue.
+    \nobreak
+    \endgroup
+    \itemxneedsnegativevskipfalse
+  \else
+    % The item text fits into the space.  Start a paragraph, so that the
+    % following text (if any) will end up on the same line.  Since that
+    % text will be indented by \tableindent, we make the item text be in
+    % a zero-width box.
+    \noindent
+    \rlap{\hskip -\tableindent\box0}\ignorespaces%
+    \endgroup%
+    \itemxneedsnegativevskiptrue%
+  \fi
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+%% Contains a kludge to get @end[description] to work
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1        \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1        \endtabley
+\def\Eftable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex}
+{\obeylines\obeyspaces%
+\gdef\vtablex #1^^M{%
+\tabley\vritemindex#1        \endtabley
+\def\Evtable{\endgraf\afterenvbreak\endgroup}%
+\let\Etable=\relax}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+\def\vritemindex #1{\doind {vr}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Neccessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\exdentamount=\tableindent
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\afterenvbreak\endgroup}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{%
+  \begingroup % ended by the @end itemsize
+  \itemizey {#1}{\Eitemize}
+}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\exdentamount=\itemindent
+\parindent = 0pt %
+\parskip = \smallskipamount %
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\afterenvbreak\endgroup}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+% Set sfcode to normal for the chars that usually have another value.
+% These are `.?!:;,'
+\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
+  \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list.  No
+% argument is the same as `1'.
+%
+\def\enumerate{\parsearg\enumeratezzz}
+\def\enumeratezzz #1{\enumeratey #1  \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+  \begingroup % ended by the @end enumerate
+  %
+  % If we were given no argument, pretend we were given `1'.
+  \def\thearg{#1}%
+  \ifx\thearg\empty \def\thearg{1}\fi
+  %
+  % Detect if the argument is a single token.  If so, it might be a
+  % letter.  Otherwise, the only valid thing it can be is a number.
+  % (We will always have one token, because of the test we just made.
+  % This is a good thing, since \splitoff doesn't work given nothing at
+  % all -- the first parameter is undelimited.)
+  \expandafter\splitoff\thearg\endmark
+  \ifx\rest\empty
+    % Only one token in the argument.  It could still be anything.
+    % A ``lowercase letter'' is one whose \lccode is nonzero.
+    % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+    %   not equal to itself.
+    % Otherwise, we assume it's a number.
+    %
+    % We need the \relax at the end of the \ifnum lines to stop TeX from
+    % continuing to look for a <number>.
+    %
+    \ifnum\lccode\expandafter`\thearg=0\relax
+      \numericenumerate % a number (we hope)
+    \else
+      % It's a letter.
+      \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+        \lowercaseenumerate % lowercase letter
+      \else
+        \uppercaseenumerate % uppercase letter
+      \fi
+    \fi
+  \else
+    % Multiple tokens in the argument.  We hope it's a number.
+    \numericenumerate
+  \fi
+}
+
+% An @enumerate whose labels are integers.  The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+  \itemno = \thearg
+  \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more lowercase letters in @enumerate; get a bigger
+                  alphabet}%
+    \fi
+    \char\lccode\itemno
+  }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more uppercase letters in @enumerate; get a bigger
+                  alphabet}
+    \fi
+    \char\uccode\itemno
+  }%
+}
+
+% Call itemizey, adding a period to the first argument and supplying the
+% common last two arguments.  Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+  \advance\itemno by -1
+  \itemizey{#1.}\Eenumerate\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{\in hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 1200}}%
+\flushcr}
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94
+%
+% @multitable ... @endmultitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble. Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize: 
+%   @multitable @percentofhsize .2 .3 .5
+%   @item ...
+%
+%   Numbers following @percentofhsize are the percent of the total
+%   current hsize to be used for each column. You may use as many
+%   columns as desired.
+
+% Or use a template:
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item ...
+%   using the widest term desired in each column.
+
+
+% Each new table line starts with @item, each subsequent new column 
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab, @multicolumn or @endmulticolumn do not need to be on their
+% own lines, but it will not hurt if they are.
+
+% Sample multitable:
+
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item first col stuff @tab second col stuff @tab third col
+%   @item 
+%   first col stuff 
+%   @tab 
+%   second col stuff 
+%   @tab 
+%   third col 
+%   @item first col stuff @tab second col stuff 
+%   @tab Many paragraphs of text may be used in any column.
+%     
+%         They will wrap at the width determined by the template.
+%   @item@tab@tab This will be in third column.
+%   @endmultitable
+
+% Default dimensions may be reset by user.
+% @intableparskip will set vertical space between paragraphs in table.
+% @intableparindent will set paragraph indent in table.
+% @spacebetweencols will set horizontal space to be left between columns.
+% @spacebetweenlines will set vertical space to be left between lines.
+
+%%%%
+% Dimensions 
+
+\newdimen\intableparskip
+\newdimen\intableparindent
+\newdimen\spacebetweencols
+\newdimen\spacebetweenlines
+\intableparskip=0pt
+\intableparindent=6pt
+\spacebetweencols=12pt
+\spacebetweenlines=12pt
+
+%%%%
+% Macros used to set up halign preamble:
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\percentofhsize\relax
+\def\xpercentofhsize{\percentofhsize}
+\newif\ifsetpercent
+
+\newcount\colcount
+\def\setuptable#1{\def\firstarg{#1}%
+\ifx\firstarg\xendsetuptable\let\go\relax%
+\else
+  \ifx\firstarg\xpercentofhsize\global\setpercenttrue%
+  \else
+    \ifsetpercent
+       \if#1.\else%
+       \global\advance\colcount by1 %
+       \expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}%
+       \fi
+    \else
+       \global\advance\colcount by1
+       \setbox0=\hbox{#1}%
+       \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+    \fi%
+  \fi%
+  \let\go\setuptable%
+\fi\go}
+%%%%
+% multitable syntax
+\def\tab{&}
+
+%%%%
+% @multitable ... @endmultitable definitions:
+
+\def\multitable#1\item{\bgroup
+\let\item\cr
+\tolerance=9500
+\hbadness=9500
+\parskip=\intableparskip
+\parindent=\intableparindent
+\overfullrule=0pt
+\global\colcount=0\relax%
+\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}%
+ % To parse everything between @multitable and @item :
+\def\one{#1}\expandafter\setuptable\one\endsetuptable
+ % Need to reset this to 0 after \setuptable.
+\global\colcount=0\relax% 
+ %
+ % This preamble sets up a generic column definition, which will
+ % be used as many times as user calls for columns.
+ % \vtop will set a single line and will also let text wrap and 
+ % continue for many paragraphs if desired.
+\halign\bgroup&\global\advance\colcount by 1\relax%
+\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname
+ % In order to keep entries from bumping into each other
+ % we will add a \leftskip of \spacebetweencols to all columns after
+ % the first one.
+ %  If a template has been used, we will add \spacebetweencols 
+ % to the width of each template entry.
+ %  If user has set preamble in terms of percent of \hsize
+ % we will use that dimension as the width of the column, and
+ % the \leftskip will keep entries from bumping into each other.
+ % Table will start at left margin and final column will justify at
+ % right margin.
+\ifnum\colcount=1
+\else
+  \ifsetpercent
+  \else
+   % If user has <not> set preamble in terms of percent of \hsize
+   % we will advance \hsize by \spacebetweencols 
+  \advance\hsize by \spacebetweencols
+  \fi
+ % In either case we will make \leftskip=\spacebetweencols:
+\leftskip=\spacebetweencols
+\fi
+\noindent##}\cr%
+ % \everycr will reset column counter, \colcount, at the end of
+ % each line. Every column  entry will cause \colcount to advance by one. 
+ % The table preamble
+ % looks at the current \colcount to find the correct column width.
+\global\everycr{\noalign{\nointerlineskip\vskip\spacebetweenlines
+\filbreak%% keeps underfull box messages off when table breaks over pages.
+\global\colcount=0\relax}}}
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that	accumulates this index.  The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+
+\def\newindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1	% Open the file
+\expandafter\xdef\csname#1index\endcsname{%	% Define \xxxindex
+\noexpand\doindex {#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1	% Open the file
+\expandafter\xdef\csname#1index\endcsname{%	% Define \xxxindex
+\noexpand\docodeindex {#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+\def\synindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{%	% Define \xxxindex
+\noexpand\doindex {#2}}%
+}
+
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{%	% Define \xxxindex
+\noexpand\docodeindex {#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+%  and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+% Take care of the plain tex accent commands.
+\def\"{\realbackslash "}%
+\def\`{\realbackslash `}%
+\def\'{\realbackslash '}%
+\def\^{\realbackslash ^}%
+\def\~{\realbackslash ~}%
+\def\={\realbackslash =}%
+\def\b{\realbackslash b}%
+\def\c{\realbackslash c}%
+\def\d{\realbackslash d}%
+\def\u{\realbackslash u}%
+\def\v{\realbackslash v}%
+\def\H{\realbackslash H}%
+% Take care of the plain tex special European modified letters.
+\def\oe{\realbackslash oe}%
+\def\ae{\realbackslash ae}%
+\def\aa{\realbackslash aa}%
+\def\OE{\realbackslash OE}%
+\def\AE{\realbackslash AE}%
+\def\AA{\realbackslash AA}%
+\def\o{\realbackslash o}%
+\def\O{\realbackslash O}%
+\def\l{\realbackslash l}%
+\def\L{\realbackslash L}%
+\def\ss{\realbackslash ss}%
+% Take care of texinfo commands likely to appear in an index entry.
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\char{\realbackslash char}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\copyright{\realbackslash copyright }%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\t##1{\realbackslash r {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+\def\dfn##1{\realbackslash dfn {##1}}%
+\def\emph##1{\realbackslash emph {##1}}%
+}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+% Just ignore accents.
+\let\"=\indexdummyfont
+\let\`=\indexdummyfont
+\let\'=\indexdummyfont
+\let\^=\indexdummyfont
+\let\~=\indexdummyfont
+\let\==\indexdummyfont
+\let\b=\indexdummyfont
+\let\c=\indexdummyfont
+\let\d=\indexdummyfont
+\let\u=\indexdummyfont
+\let\v=\indexdummyfont
+\let\H=\indexdummyfont
+% Take care of the plain tex special European modified letters.
+\def\oe{oe}%
+\def\ae{ae}%
+\def\aa{aa}%
+\def\OE{OE}%
+\def\AE{AE}%
+\def\AA{AA}%
+\def\o{o}%
+\def\O{O}%
+\def\l{l}%
+\def\L{L}%
+\def\ss{ss}%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+@gdef@realbackslash{\}}
+
+\let\indexbackslash=0  %overridden during \printindex.
+
+\def\doind #1#2{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0% Expand all macros now EXCEPT \folio
+\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+% so it will be output as is; and it will print as backslash in the indx.
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2}%
+}%
+% Now produce the complete index entry.  We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}}}%
+\temp }%
+}\penalty\count10}}
+
+\def\dosubind #1#2#3{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0%
+\def\rawbackslashxx{\indexbackslash}%
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2 #3}%
+}%
+% Now produce the complete index entry.  We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
+\temp }%
+}\penalty\count10}}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% This is what you call to cause a particular index to get printed.
+% Write
+% @unnumbered Function Index
+% @printindex fn
+
+\def\printindex{\parsearg\doprintindex}
+
+\def\doprintindex#1{%
+  \tex
+  \dobreak \chapheadingskip {10000}
+  \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
+  \catcode`\$=\other
+  \catcode`\~=\other
+  \indexbreaks
+  %
+  % The following don't help, since the chars were translated
+  % when the raw index was written, and their fonts were discarded
+  % due to \indexnofonts.
+  %\catcode`\"=\active
+  %\catcode`\^=\active
+  %\catcode`\_=\active
+  %\catcode`\|=\active
+  %\catcode`\<=\active
+  %\catcode`\>=\active
+  % %
+  \def\indexbackslash{\rawbackslashxx}
+  \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
+  \begindoublecolumns
+  %
+  % See if the index file exists and is nonempty.
+  \openin 1 \jobname.#1s
+  \ifeof 1
+    % \enddoublecolumns gets confused if there is no text in the index,
+    % and it loses the chapter title and the aux file entries for the
+    % index.  The easiest way to prevent this problem is to make sure
+    % there is some text.
+    (Index is nonexistent)
+    \else
+    %
+    % If the index file exists but is empty, then \openin leaves \ifeof
+    % false.  We have to make TeX try to read something from the file, so
+    % it can discover if there is anything in it.
+    \read 1 to \temp
+    \ifeof 1
+      (Index is empty)
+    \else
+      \input \jobname.#1s
+    \fi
+  \fi
+  \closein 1
+  \enddoublecolumns
+  \Etex
+}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+% Same as \bigskipamount except no shrink.
+% \balancecolumns gets confused if there is any shrink.
+\newskip\initialskipamount \initialskipamount 12pt plus4pt
+
+\def\initial #1{%
+{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+\ifdim\lastskip<\initialskipamount
+\removelastskip \penalty-200 \vskip \initialskipamount\fi
+\line{\secbf#1\hfill}\kern 2pt\penalty10000}}
+
+% This typesets a paragraph consisting of #1, dot leaders, and then #2
+% flush to the right margin.  It is used for index and table of contents
+% entries.  The paragraph is indented by \leftskip.
+%
+\def\entry #1#2{\begingroup
+  %
+  % Start a new paragraph if necessary, so our assignments below can't
+  % affect previous text.
+  \par
+  %
+  % Do not fill out the last line with white space.
+  \parfillskip = 0in
+  %
+  % No extra space above this paragraph.
+  \parskip = 0in
+  %
+  % Do not prefer a separate line ending with a hyphen to fewer lines.
+  \finalhyphendemerits = 0
+  %
+  % \hangindent is only relevant when the entry text and page number
+  % don't both fit on one line.  In that case, bob suggests starting the
+  % dots pretty far over on the line.  Unfortunately, a large
+  % indentation looks wrong when the entry text itself is broken across
+  % lines.  So we use a small indentation and put up with long leaders.
+  %
+  % \hangafter is reset to 1 (which is the value we want) at the start
+  % of each paragraph, so we need not do anything with that.
+  \hangindent=2em
+  %
+  % When the entry text needs to be broken, just fill out the first line
+  % with blank space.
+  \rightskip = 0pt plus1fil
+  %
+  % Start a ``paragraph'' for the index entry so the line breaking
+  % parameters we've set above will have an effect.
+  \noindent
+  %
+  % Insert the text of the index entry.  TeX will do line-breaking on it.
+  #1%
+  % The following is kluged to not output a line of dots in the index if
+  % there are no page numbers.  The next person who breaks this will be
+  % cursed by a Unix daemon.
+  \def\tempa{{\rm }}%
+  \def\tempb{#2}%
+  \edef\tempc{\tempa}%
+  \edef\tempd{\tempb}%
+  \ifx\tempc\tempd\ \else%
+    %
+    % If we must, put the page number on a line of its own, and fill out
+    % this line with blank space.  (The \hfil is overwhelmed with the
+    % fill leaders glue in \indexdotfill if the page number does fit.)
+    \hfil\penalty50
+    \null\nobreak\indexdotfill % Have leaders before the page number.
+    %
+    % The `\ ' here is removed by the implicit \unskip that TeX does as
+    % part of (the primitive) \par.  Without it, a spurious underfull
+    % \hbox ensues.
+    \ #2% The page number ends the paragraph.
+  \fi%
+  \par
+\endgroup}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
+}}
+
+%% Define two-column mode, which is used in indexes.
+%% Adapted from the TeXbook, page 416.
+\catcode `\@=11
+
+\newbox\partialpage
+
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup
+  % Grab any single-column material above us.
+  \output = {\global\setbox\partialpage
+    =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}%
+  \eject
+  %
+  % Now switch to the double-column output routine.
+  \output={\doublecolumnout}%
+  %
+  % Change the page size parameters.  We could do this once outside this
+  % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+  % format, but then we repeat the same computation.  Repeating a couple
+  % of assignments once per index is clearly meaningless for the
+  % execution time, so we may as well do it once.
+  %
+  % First we halve the line length, less a little for the gutter between
+  % the columns.  We compute the gutter based on the line length, so it
+  % changes automatically with the paper format.  The magic constant
+  % below is chosen so that the gutter has the same value (well, +- <
+  % 1pt) as it did when we hard-coded it.
+  %
+  % We put the result in a separate register, \doublecolumhsize, so we
+  % can restore it in \pagesofar, after \hsize itself has (potentially)
+  % been clobbered.
+  %
+  \doublecolumnhsize = \hsize
+    \advance\doublecolumnhsize by -.04154\hsize
+    \divide\doublecolumnhsize by 2
+  \hsize = \doublecolumnhsize
+  %
+  % Double the \vsize as well.  (We don't need a separate register here,
+  % since nobody clobbers \vsize.)
+  \vsize = 2\vsize
+  \doublecolumnpagegoal
+}
+
+\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage}
+
+\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth
+  \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage
+  \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1}
+  \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3}
+  \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi
+  \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi
+}
+\def\doublecolumnpagegoal{%
+  \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@
+}
+\def\pagesofar{\unvbox\partialpage %
+  \hsize=\doublecolumnhsize % have to restore this since output routine
+  \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\doublecolumnout{%
+  \setbox5=\copy255
+  {\vbadness=10000 \doublecolumnsplit}
+  \ifvbox255
+    \setbox0=\vtop to\dimen@{\unvbox0}
+    \setbox2=\vtop to\dimen@{\unvbox2}
+    \onepageout\pagesofar \unvbox255 \penalty\outputpenalty
+  \else
+    \setbox0=\vbox{\unvbox5}
+    \ifvbox0
+      \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+      \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth
+      {\vbadness=10000
+	\loop \global\setbox5=\copy0
+          \setbox1=\vsplit5 to\dimen@
+          \setbox3=\vsplit5 to\dimen@
+          \ifvbox5 \global\advance\dimen@ by1pt \repeat
+        \setbox0=\vbox to\dimen@{\unvbox1}
+        \setbox2=\vbox to\dimen@{\unvbox3}
+        \global\setbox\partialpage=\vbox{\pagesofar}
+        \doublecolumnpagegoal
+      }
+    \fi
+  \fi
+}
+
+\catcode `\@=\other
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount \chapno
+\newcount \secno        \secno=0
+\newcount \subsecno     \subsecno=0
+\newcount \subsubsecno  \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount \appendixno  \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+\newwrite \contentsfile
+% This is called from \setfilename.
+\def\opencontents{\openout \contentsfile = \jobname.toc}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it.  @section does likewise
+
+\def\thischapter{} \def\thissection{}
+\def\seccheck#1{\if \pageno<0 %
+\errmessage{@#1 not allowed after generating table of contents}\fi
+%
+}
+
+\def\chapternofonts{%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\def\result{\realbackslash result}
+\def\equiv{\realbackslash equiv}
+\def\expansion{\realbackslash expansion}
+\def\print{\realbackslash print}
+\def\TeX{\realbackslash TeX}
+\def\dots{\realbackslash dots}
+\def\copyright{\realbackslash copyright}
+\def\tt{\realbackslash tt}
+\def\bf{\realbackslash bf}
+\def\w{\realbackslash w}
+\def\less{\realbackslash less}
+\def\gtr{\realbackslash gtr}
+\def\hat{\realbackslash hat}
+\def\char{\realbackslash char}
+\def\tclose##1{\realbackslash tclose {##1}}
+\def\code##1{\realbackslash code {##1}}
+\def\samp##1{\realbackslash samp {##1}}
+\def\r##1{\realbackslash r {##1}}
+\def\b##1{\realbackslash b {##1}}
+\def\key##1{\realbackslash key {##1}}
+\def\file##1{\realbackslash file {##1}}
+\def\kbd##1{\realbackslash kbd {##1}}
+% These are redefined because @smartitalic wouldn't work inside xdef.
+\def\i##1{\realbackslash i {##1}}
+\def\cite##1{\realbackslash cite {##1}}
+\def\var##1{\realbackslash var {##1}}
+\def\emph##1{\realbackslash emph {##1}}
+\def\dfn##1{\realbackslash dfn {##1}}
+}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raise/lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% Choose a numbered-heading macro
+% #1 is heading level if unmodified by @raisesections or @lowersections
+% #2 is text for heading
+\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \chapterzzz{#2}
+\or
+  \seczzz{#2}
+\or
+  \numberedsubseczzz{#2}
+\or
+  \numberedsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \chapterzzz{#2}
+  \else
+    \numberedsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+% like \numhead, but chooses appendix heading levels
+\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \appendixzzz{#2}
+\or
+  \appendixsectionzzz{#2}
+\or
+  \appendixsubseczzz{#2}
+\or
+  \appendixsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \appendixzzz{#2}
+  \else
+    \appendixsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+% like \numhead, but chooses numberless heading levels
+\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1
+\ifcase\absseclevel
+  \unnumberedzzz{#2}
+\or
+  \unnumberedseczzz{#2}
+\or
+  \unnumberedsubseczzz{#2}
+\or
+  \unnumberedsubsubseczzz{#2}
+\else
+  \ifnum \absseclevel<0
+    \unnumberedzzz{#2}
+  \else
+    \unnumberedsubsubseczzz{#2}
+  \fi
+\fi
+}
+
+
+\def\thischaptername{No Chapter Title}
+\outer\def\chapter{\parsearg\chapteryyy}
+\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz #1{\seccheck{chapter}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{Chapter \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\donoderef %
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+}}
+
+\outer\def\appendix{\parsearg\appendixyyy}
+\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz
+\def\appendixzzz #1{\seccheck{appendix}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1 \message{Appendix \appendixletter}%
+\chapmacro {#1}{\putwordAppendix{} \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry
+  {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\appendixnoderef %
+\global\let\section = \appendixsec
+\global\let\subsection = \appendixsubsec
+\global\let\subsubsection = \appendixsubsubsec
+}}
+
+\outer\def\top{\parsearg\unnumberedyyy}
+\outer\def\unnumbered{\parsearg\unnumberedyyy}
+\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz #1{\seccheck{unnumbered}%
+\secno=0 \subsecno=0 \subsubsecno=0
+%
+% This used to be simply \message{#1}, but TeX fully expands the
+% argument to \message.  Therefore, if #1 contained @-commands, TeX
+% expanded them.  For example, in `@unnumbered The @cite{Book}', TeX
+% expanded @cite (which turns out to cause errors because \cite is meant
+% to be executed, not expanded).
+%
+% Anyway, we don't want the fully-expanded definition of @cite to appear
+% as a result of the \message, we just want `@cite' itself.  We use
+% \the<toks register> to achieve this: TeX expands \the<toks> only once,
+% simply yielding the contents of the <toks register>.
+\toks0 = {#1}\message{(\the\toks0)}%
+%
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\unnumbnoderef %
+\global\let\section = \unnumberedsec
+\global\let\subsection = \unnumberedsubsec
+\global\let\subsubsection = \unnumberedsubsubsec
+}}
+
+\outer\def\numberedsec{\parsearg\secyyy}
+\def\secyyy #1{\numhead1{#1}} % normally calls seczzz
+\def\seczzz #1{\seccheck{section}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appenixsection{\parsearg\appendixsecyyy}
+\outer\def\appendixsec{\parsearg\appendixsecyyy}
+\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz #1{\seccheck{appendixsection}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy}
+\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy}
+\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz #1{\seccheck{subsection}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy}
+\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy}
+\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy}
+\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz #1{\seccheck{subsubsection}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+  {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry %
+  {#1}
+  {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}
+  {\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy}
+\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+  {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry{#1}%
+  {\appendixletter}
+  {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy}
+\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+% Actually, they should now be obsolete; ordinary section commands should work.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\global\let\section = \numberedsec
+\global\let\subsection = \numberedsubsec
+\global\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and
+% such:
+%	1) We use \vbox rather than the earlier \line to permit
+%	   overlong headings to fold.
+%	2) \hyphenpenalty is set to 10000 because hyphenation in a
+%	   heading is obnoxious; this forbids it.
+%       3) Likewise, headings look best if no \parindent is used, and
+%          if justification is not attempted.  Hence \raggedright.
+
+
+\def\majorheading{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                  \parindent=0pt\raggedright
+                  \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                  \parindent=0pt\raggedright
+                  \rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\heading{\parsearg\secheadingi}
+
+\def\subheading{\parsearg\subsecheadingi}
+
+\def\subsubheading{\parsearg\subsubsecheadingi}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain}
+
+\def\chfplain #1#2{%
+  \pchapsepmacro
+  {%
+    \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                     \parindent=0pt\raggedright
+                     \rm #2\enspace #1}%
+  }%
+  \bigskip
+  \penalty5000
+}
+
+\def\unnchfplain #1{%
+\pchapsepmacro %
+{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                  \parindent=0pt\raggedright
+                  \rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                       \parindent=0pt\raggedright
+                       \rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen}
+
+% Parameter controlling skip before section headings.
+
+\newskip \subsecheadingskip  \subsecheadingskip = 17pt plus 8pt minus 4pt
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+
+\newskip \secheadingskip  \secheadingskip = 21pt plus 8pt minus 4pt
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+
+% @paragraphindent  is defined for the Info formatting commands only.
+\let\paragraphindent=\comment
+
+% Section fonts are the base font at magstep2, which produces
+% a size a bit more than 14 points in the default situation.
+
+\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
+\def\plainsecheading #1{\secheadingi {#1}}
+\def\secheadingi #1{{\advance \secheadingskip by \parskip %
+\secheadingbreak}%
+{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                 \parindent=0pt\raggedright
+                 \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+
+% Subsection fonts are the base font at magstep1,
+% which produces a size of 12 points.
+
+\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}}
+\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                     \parindent=0pt\raggedright
+                     \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsubsecfonts{\subsecfonts} % Maybe this should change:
+				  % Perhaps make sssec fonts scaled
+				  % magstep half
+\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}}
+\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                       \parindent=0pt\raggedright
+                       \rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
+
+
+\message{toc printing,}
+
+% Finish up the main text and prepare to read what we've written
+% to \contentsfile.
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\def\startcontents#1{%
+   \pagealignmacro
+   \immediate\closeout \contentsfile
+   \ifnum \pageno>0
+      \pageno = -1		% Request roman numbered pages.
+   \fi
+   % Don't need to put `Contents' or `Short Contents' in the headline.
+   % It is abundantly clear what they are.
+   \unnumbchapmacro{#1}\def\thischapter{}%
+   \begingroup   		% Set up to handle contents files properly.
+      \catcode`\\=0  \catcode`\{=1  \catcode`\}=2  \catcode`\@=11
+      \raggedbottom             % Worry more about breakpoints than the bottom.
+      \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+}
+
+
+% Normal (long) toc.
+\outer\def\contents{%
+   \startcontents{\putwordTableofContents}%
+      \input \jobname.toc
+   \endgroup
+   \vfill \eject
+}
+
+% And just the chapters.
+\outer\def\summarycontents{%
+   \startcontents{\putwordShortContents}%
+      %
+      \let\chapentry = \shortchapentry
+      \let\unnumbchapentry = \shortunnumberedentry
+      % We want a true roman here for the page numbers.
+      \secfonts
+      \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+      \rm
+      \advance\baselineskip by 1pt % Open it up a little.
+      \def\secentry ##1##2##3##4{}
+      \def\unnumbsecentry ##1##2{}
+      \def\subsecentry ##1##2##3##4##5{}
+      \def\unnumbsubsecentry ##1##2{}
+      \def\subsubsecentry ##1##2##3##4##5##6{}
+      \def\unnumbsubsubsecentry ##1##2{}
+      \input \jobname.toc
+   \endgroup
+   \vfill \eject
+}
+\let\shortcontents = \summarycontents
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+
+% See comments in \dochapentry re vbox and related settings
+\def\shortchapentry#1#2#3{%
+  \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}%
+}
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter.
+% We could simplify the code here by writing out an \appendixentry
+% command in the toc file for appendices, instead of using \chapentry
+% for both, but it doesn't seem worth it.
+\setbox0 = \hbox{\shortcontrm \putwordAppendix }
+\newdimen\shortappendixwidth \shortappendixwidth = \wd0
+
+\def\shortchaplabel#1{%
+  % We typeset #1 in a box of constant width, regardless of the text of
+  % #1, so the chapter titles will come out aligned.
+  \setbox0 = \hbox{#1}%
+  \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi
+  %
+  % This space should be plenty, since a single number is .5em, and the
+  % widest letter (M) is 1em, at least in the Computer Modern fonts.
+  % (This space doesn't include the extra space that gets added after
+  % the label; that gets put in in \shortchapentry above.)
+  \advance\dimen0 by 1.1em
+  \hbox to \dimen0{#1\hfil}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+  \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we would want to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+   \penalty-300 \vskip\baselineskip
+   \begingroup
+     \chapentryfonts
+     \tocentry{#1}{\dopageno{#2}}%
+   \endgroup
+   \nobreak\vskip .25\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+  \secentryfonts \leftskip=\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+  \subsecentryfonts \leftskip=2\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+  \subsubsecentryfonts \leftskip=3\tocindent
+  \tocentry{#1}{\dopageno{#2}}%
+\endgroup}
+
+% Final typesetting of a toc entry; we use the same \entry macro as for
+% the index entries, but we want to suppress hyphenation here.  (We
+% can't do that in the \entry macro, since index entries might consist
+% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.)
+%
+\def\tocentry#1#2{\begingroup
+  \hyphenpenalty = 10000
+  \entry{#1}{#2}%
+\endgroup}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% Since these characters are used in examples, it should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox    \newbox\longdblarrowbox
+\newbox\pushcharbox    \newbox\bullbox
+\newbox\equivbox       \newbox\errorbox
+
+\let\ptexequiv = \equiv
+
+%{\tentt
+%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+%                                      depth .1ex\hfil}
+%}
+
+\def\point{$\star$}
+
+\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+
+\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% Adapted from the TeXbook's \boxit.
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+
+\global\setbox\errorbox=\hbox to \dimen0{\hfil
+   \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+   \advance\hsize by -2\dimen2 % Rules.
+   \vbox{
+      \hrule height\dimen2
+      \hbox{\vrule width\dimen2 \kern3pt          % Space to left of text.
+         \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+         \kern3pt\vrule width\dimen2}% Space to right.
+      \hrule height\dimen2}
+    \hfil}
+
+% The @error{} command.
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex    escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+\catcode `\%=14
+\catcode 43=12
+\catcode`\"=12
+\catcode`\==12
+\catcode`\|=12
+\catcode`\<=12
+\catcode`\>=12
+\escapechar=`\\
+%
+\let\~=\ptextilde
+\let\{=\ptexlbrace
+\let\}=\ptexrbrace
+\let\.=\ptexdot
+\let\*=\ptexstar
+\let\dots=\ptexdots
+\def\@{@}%
+\let\bullet=\ptexbullet
+\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
+\let\L=\ptexL
+%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments.  \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% Make each space character in the input produce a normal interword
+% space in the output.  Don't allow a line break at this space, as this
+% is used only in environments like @example, where each line of input
+% should produce a line of output anyway.
+%
+{\obeyspaces %
+\gdef\sepspaces{\obeyspaces\let =\tie}}
+
+% Define \obeyedspace to be our active space, whatever it is.  This is
+% for use in \parsearg.
+{\sepspaces%
+\global\let\obeyedspace= }
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical.  We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip
+%
+\def\aboveenvbreak{{\advance\envskipamount by \parskip
+\endgraf \ifdim\lastskip<\envskipamount
+\removelastskip \penalty-50 \vskip\envskipamount \fi}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag.  If "set", @lisp etc don't narrow margins.
+\let\nonarrowing=\relax
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \cartouche: draw rectangle w/rounded corners around argument
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+	\ctl\leaders\hrule height\circthick\hfil\ctr
+	\hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+	\cbl\leaders\hrule height\circthick\hfil\cbr
+	\hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\long\def\cartouche{%
+\begingroup
+	\lskip=\leftskip \rskip=\rightskip
+	\leftskip=0pt\rightskip=0pt %we want these *outside*.
+	\cartinner=\hsize \advance\cartinner by-\lskip
+		 	  \advance\cartinner by-\rskip
+	\cartouter=\hsize
+	\advance\cartouter by 18pt % allow for 3pt kerns on either
+%				     side, and for 6pt waste from
+%				     each corner char
+	\normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+	% Flag to tell @lisp, etc., not to narrow margin.
+	\let\nonarrowing=\comment
+	\vbox\bgroup
+		\baselineskip=0pt\parskip=0pt\lineskip=0pt
+		\carttop
+		\hbox\bgroup
+			\hskip\lskip
+			\vrule\kern3pt
+			\vbox\bgroup
+				\hsize=\cartinner
+				\kern3pt
+				\begingroup
+					\baselineskip=\normbskip
+					\lineskip=\normlskip
+					\parskip=\normpskip
+					\vskip -\parskip
+\def\Ecartouche{%
+				\endgroup
+				\kern3pt
+			\egroup
+			\kern3pt\vrule
+			\hskip\rskip
+		\egroup
+		\cartbot
+	\egroup
+\endgroup
+}}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\def\nonfillstart{%
+  \aboveenvbreak
+  \inENV % This group ends at the end of the body
+  \hfuzz = 12pt % Don't be fussy
+  \sepspaces % Make spaces be word-separators rather than space tokens.
+  \singlespace
+  \let\par = \lisppar % don't ignore blank lines
+  \obeylines % each line of input is a line of output
+  \parskip = 0pt
+  \parindent = 0pt
+  \emergencystretch = 0pt % don't try to avoid overfull boxes
+  % @cartouche defines \nonarrowing to inhibit narrowing
+  % at next level down.
+  \ifx\nonarrowing\relax
+    \advance \leftskip by \lispnarrowing
+    \exdentamount=\lispnarrowing
+    \let\exdent=\nofillexdent
+    \let\nonarrowing=\relax
+  \fi
+}
+
+% To ending an @example-like environment, we first end the paragraph
+% (via \afterenvbreak's vertical glue), and then the group.  That way we
+% keep the zero \parskip that the environments set -- \parskip glue
+% will be inserted at the beginning of the next paragraph in the
+% document, after the environment.
+%
+\def\nonfillfinish{\afterenvbreak\endgroup}%
+
+% This macro is
+\def\lisp{\begingroup
+  \nonfillstart
+  \let\Elisp = \nonfillfinish
+  \tt
+  \rawbackslash % have \ input char produce \ char from current font
+  \gobble
+}
+
+% Define the \E... control sequence only if we are inside the
+% environment, so the error checking in \end will work.
+%
+% We must call \lisp last in the definition, since it reads the
+% return following the @example (or whatever) command.
+%
+\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp}
+\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp}
+\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp}
+
+% @smallexample and @smalllisp.  This is not used unless the @smallbook
+% command is given.  Originally contributed by Pavel@xerox.
+%
+\def\smalllispx{\begingroup
+  \nonfillstart
+  \let\Esmalllisp = \nonfillfinish
+  \let\Esmallexample = \nonfillfinish
+  %
+  % Smaller interline space and fonts for small examples.
+  \setleading{10pt}%
+  \indexfonts \tt
+  \rawbackslash % make \ output the \ character from the current font (tt)
+  \gobble
+}
+
+% This is @display; same as @lisp except use roman font.
+%
+\def\display{\begingroup
+  \nonfillstart
+  \let\Edisplay = \nonfillfinish
+  \gobble
+}
+
+% This is @format; same as @display except don't narrow margins.
+%
+\def\format{\begingroup
+  \let\nonarrowing = t
+  \nonfillstart
+  \let\Eformat = \nonfillfinish
+  \gobble
+}
+
+% @flushleft (same as @format) and @flushright.
+%
+\def\flushleft{\begingroup
+  \let\nonarrowing = t
+  \nonfillstart
+  \let\Eflushleft = \nonfillfinish
+  \gobble
+}
+\def\flushright{\begingroup
+  \let\nonarrowing = t
+  \nonfillstart
+  \let\Eflushright = \nonfillfinish
+  \advance\leftskip by 0pt plus 1fill
+  \gobble}
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.
+%
+\def\quotation{%
+  \begingroup\inENV %This group ends at the end of the @quotation body
+  {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+  \singlespace
+  \parindent=0pt
+  % We have retained a nonzero parskip for the environment, since we're
+  % doing normal filling. So to avoid extra space below the environment...
+  \def\Equotation{\parskip = 0pt \nonfillfinish}%
+  %
+  % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+  \ifx\nonarrowing\relax
+    \advance\leftskip by \lispnarrowing
+    \advance\rightskip by \lispnarrowing
+    \exdentamount = \lispnarrowing
+    \let\nonarrowing = \relax
+  \fi
+}
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+
+% Be sure that we always have a definition for `(', etc.  For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+\global\let(=\lparen \global\let)=\rparen
+\global\let[=\lbrack \global\let]=\rbrack
+
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
+\global\advance\parencount by 1 }
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+% also in that case restore the outer-level definition of (.
+\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+\global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text.  This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
+\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\dimen3=\rightskip
+\advance\dimen3 by -\defbodyindent
+\noindent        %
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1     %
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2 \advance \hsize by -\dimen3
+\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000
+\advance\leftskip by -\defbodyindent
+\exdentamount=\defbodyindent
+{\df #1}\enskip        % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+%    such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active % 61 is `='
+\obeylines\activeparens\spacesplit#3}
+
+\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% These parsing functions are similar to the preceding ones
+% except that they do not make parens into active characters.
+% These are used for "variables" since they have no arguments.
+
+\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\spacesplit#3}
+
+% This is used for \def{tp,vr}parsebody.  It could probably be used for
+% some of the others, too, with some judicious conditionals.
+% 
+\def\parsebodycommon#1#2#3{%
+  \begingroup\inENV %
+  \medbreak %
+  % Define the end token that this defining construct specifies
+  % so that it will exit this group.
+  \def#1{\endgraf\endgroup\medbreak}%
+  \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}%
+  \parindent=0in
+  \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+  \exdentamount=\defbodyindent
+  \begingroup\obeylines
+}
+
+\def\defvrparsebody#1#2#3#4 {%
+  \parsebodycommon{#1}{#2}{#3}%
+  \spacesplit{#3{#4}}%
+}
+
+% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the
+% type is just `struct', because we lose the braces in `{struct
+% termios}' when \spacesplit reads its undelimited argument.  Sigh.
+% \let\deftpparsebody=\defvrparsebody
+%
+% So, to get around this, we put \empty in with the type name.  That
+% way, TeX won't find exactly `{...}' as an undelimited argument, and
+% won't strip off the braces.
+%
+\def\deftpparsebody #1#2#3#4 {%
+  \parsebodycommon{#1}{#2}{#3}%
+  \spacesplit{\parsetpheaderline{#3{#4}}}\empty
+}
+
+% Fine, but then we have to eventually remove the \empty *and* the
+% braces (if any).  That's what this does, putting the result in \tptemp.
+% 
+\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}%
+
+% After \spacesplit has done its work, this is called -- #1 is the final
+% thing to call, #2 the type name (which starts with \empty), and #3
+% (which might be empty) the arguments.
+% 
+\def\parsetpheaderline#1#2#3{%
+  \removeemptybraces#2\relax
+  #1{\tptemp}{#3}%
+}%
+
+\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\exdentamount=\defbodyindent
+\begingroup\obeylines\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+%  the first is all of #2 before the space token,
+%  the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\hyphenchar\tensl=0
+#1%
+\hyphenchar\tensl=45
+\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\functionparens
+\tclose{#1}% avoid \code because of side effects on active chars
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type.  #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% \defheaderxcond#1\relax$$$
+% puts #1 in @code, followed by a space, but does nothing if #1 is null.
+\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi}
+
+% #1 is the classification.  #2 is the data type.  #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup
+\normalparens % notably, turn off `&' magic, which prevents
+%               at least some C++ text from working
+\defname {\defheaderxcond#2\relax$$$#3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special Form}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop {Funny Method} foo-class frobnicate argument
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defmethod == @defop Method
+
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+
+\def\defmethodheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% entry in function index
+\begingroup\defname {#2}{Method on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype{} of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance Variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type.  #2 is the name.
+\def\deftypevarheader #1#2{%
+\doind {vr}{\code{#2}}% Make entry in variables index
+\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}%
+\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1}
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+\message{cross reference,}
+% Define cross-reference macros
+\newwrite \auxfile
+
+\newif\ifhavexrefs  % True if xref values are known.
+\newif\ifwarnedxrefs  % True if we warned once that they aren't known.
+
+% \setref{foo} defines a cross-reference point named foo.
+
+\def\setref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ysectionnumberandtype}}
+
+\def\unnumbsetref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ynothing}}
+
+\def\appendixsetref#1{%
+\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Yappendixletterandtype}}
+
+% \xref, \pxref, and \ref generate cross-references to specified points.
+% For \xrefX, #1 is the node name, #2 the name of the Info
+% cross-reference, #3 the printed node name, #4 the name of the Info
+% file, #5 the name of the printed manual.  All but the node name can be
+% omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+  \def\printedmanual{\ignorespaces #5}%
+  \def\printednodename{\ignorespaces #3}%
+  \setbox1=\hbox{\printedmanual}%
+  \setbox0=\hbox{\printednodename}%
+  \ifdim \wd0 = 0pt
+    % No printed node name was explicitly given.
+    \ifx\SETxref-automatic-section-title\relax %
+      % Use the actual chapter/section title appear inside
+      % the square brackets.  Use the real section title if we have it.
+      \ifdim \wd1>0pt%
+        % It is in another manual, so we don't have it.
+        \def\printednodename{\ignorespaces #1}%
+      \else
+        \ifhavexrefs
+          % We know the real title if we have the xref values.
+          \def\printednodename{\refx{#1-title}}%
+        \else
+          % Otherwise just copy the Info node name.
+          \def\printednodename{\ignorespaces #1}%
+        \fi%
+      \fi
+      \def\printednodename{#1-title}%
+    \else
+      % Use the node name inside the square brackets.
+      \def\printednodename{\ignorespaces #1}%
+    \fi
+  \fi
+  %
+  % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
+  % insert empty discretionaries after hyphens, which means that it will
+  % not find a line break at a hyphen in a node names.  Since some manuals
+  % are best written with fairly long node names, containing hyphens, this
+  % is a loss.  Therefore, we give the text of the node name again, so it
+  % is as if TeX is seeing it for the first time.
+  \ifdim \wd1 > 0pt
+    \putwordsection{} ``\printednodename'' in \cite{\printedmanual}%
+  \else
+    % _ (for example) has to be the character _ for the purposes of the
+    % control sequence corresponding to the node, but it has to expand
+    % into the usual \leavevmode...\vrule stuff for purposes of
+    % printing. So we \turnoffactive for the \refx-snt, back on for the
+    % printing, back off for the \refx-pg.
+    {\turnoffactive \refx{#1-snt}{}}%
+    \space [\printednodename],\space
+    \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+  \fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \turnoffactive so that punctuation chars such as underscore
+% work in node names.
+\def\dosetq #1#2{{\let\folio=0 \turnoffactive%
+\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
+\next}}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thissection}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 \putwordChapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+  \let\linenumber = \empty % Non-3.0.
+\else
+  \def\linenumber{\the\inputlineno:\space}
+\fi
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+
+\def\refx#1#2{%
+  \expandafter\ifx\csname X#1\endcsname\relax
+    % If not defined, say something at least.
+    $\langle$un\-de\-fined$\rangle$%
+    \ifhavexrefs
+      \message{\linenumber Undefined cross reference `#1'.}%
+    \else
+      \ifwarnedxrefs\else
+        \global\warnedxrefstrue
+        \message{Cross reference values unknown; you must run TeX again.}%
+      \fi
+    \fi
+  \else
+    % It's defined, so just use it.
+    \csname X#1\endcsname
+  \fi
+  #2% Output the suffix in any case.
+}
+
+% Read the last existing aux file, if any.  No error if none exists.
+
+% This is the macro invoked by entries in the aux file.
+\def\xrdef #1#2{
+{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
+
+\def\readauxfile{%
+\begingroup
+\catcode `\^^@=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\=\other
+\catcode `\^^L=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode `\=\other
+\catcode 26=\other
+\catcode `\^^[=\other
+\catcode `\^^\=\other
+\catcode `\^^]=\other
+\catcode `\^^^=\other
+\catcode `\^^_=\other
+\catcode `\@=\other
+\catcode `\^=\other
+\catcode `\~=\other
+\catcode `\[=\other
+\catcode `\]=\other
+\catcode`\"=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode `\$=\other
+\catcode `\#=\other
+\catcode `\&=\other
+% `\+ does not work, so use 43.
+\catcode 43=\other
+% Make the characters 128-255 be printing characters
+{%
+  \count 1=128
+  \def\loop{%
+    \catcode\count 1=\other
+    \advance\count 1 by 1
+    \ifnum \count 1<256 \loop \fi
+  }%
+}%
+% the aux file uses ' as the escape.
+% Turn off \ as an escape so we do not lose on
+% entries which were dumped with control sequences in their names.
+% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+% Reference to such entries still does not work the way one would wish,
+% but at least they do not bomb out when the aux file is read in.
+\catcode `\{=1 \catcode `\}=2
+\catcode `\%=\other
+\catcode `\'=0
+\catcode `\\=\other
+\openin 1 \jobname.aux
+\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue
+\global\warnedobstrue
+\fi
+% Open the new aux file.  Tex will close it automatically at exit.
+\openout \auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed.
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only..
+\let\footnotestyle=\comment
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+%
+% Auto-number footnotes.  Otherwise like plain.
+\gdef\footnote{%
+  \global\advance\footnoteno by \@ne
+  \edef\thisfootno{$^{\the\footnoteno}$}%
+  %
+  % In case the footnote comes at the end of a sentence, preserve the
+  % extra spacing after we do the footnote number.
+  \let\@sf\empty
+  \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+  %
+  % Remove inadvertent blank space before typesetting the footnote number.
+  \unskip
+  \thisfootno\@sf
+  \footnotezzz
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter.  Our footnotes don't need to be so general.
+%
+\long\gdef\footnotezzz#1{\insert\footins{%
+  % We want to typeset this text as a normal paragraph, even if the
+  % footnote reference occurs in (for example) a display environment.
+  % So reset some parameters.
+  \interlinepenalty\interfootnotelinepenalty
+  \splittopskip\ht\strutbox % top baseline for broken footnotes
+  \splitmaxdepth\dp\strutbox
+  \floatingpenalty\@MM
+  \leftskip\z@skip
+  \rightskip\z@skip
+  \spaceskip\z@skip
+  \xspaceskip\z@skip
+  \parindent\defaultparindent
+  %
+  % Hang the footnote text off the number.
+  \hang
+  \textindent{\thisfootno}%
+  %
+  % Don't crash into the line above the footnote text.  Since this
+  % expands into a box, it must come within the paragraph, lest it
+  % provide a place where TeX can split the footnote.
+  \footstrut
+  #1\strut}%
+}
+
+}%end \catcode `\@=11
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly.  There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+\def\setleading#1{%
+  \normalbaselineskip = #1\relax
+  \normallineskip = \lineskipfactor\normalbaselineskip
+  \normalbaselines
+  \setbox\strutbox =\hbox{%
+    \vrule width0pt height\strutheightpercent\baselineskip
+                    depth \strutdepthpercent \baselineskip
+  }%
+}
+
+% @| inserts a changebar to the left of the current line.  It should
+% surround any changed text.  This approach does *not* work if the
+% change spans more than two lines of output.  To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).
+%
+\def\|{%
+  % \vadjust can only be used in horizontal mode.
+  \leavevmode
+  %
+  % Append this vertical mode material after the current line in the output.
+  \vadjust{%
+    % We want to insert a rule with the height and depth of the current
+    % leading; that is exactly what \strutbox is supposed to record.
+    \vskip-\baselineskip
+    %
+    % \vadjust-items are inserted at the left edge of the type.  So
+    % the \llap here moves out into the left-hand margin.
+    \llap{%
+      %
+      % For a thicker or thinner bar, change the `1pt'.
+      \vrule height\baselineskip width1pt
+      %
+      % This is the space between the bar and the text.
+      \hskip 12pt
+    }%
+  }%
+}
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt}
+
+
+% End of control word definitions.
+
+\message{and turning on texinfo input format.}
+
+\def\openindices{%
+   \newindex{cp}%
+   \newcodeindex{fn}%
+   \newcodeindex{vr}%
+   \newcodeindex{tp}%
+   \newcodeindex{ky}%
+   \newcodeindex{pg}%
+}
+
+% Set some numeric style parameters, for 8.5 x 11 format.
+
+%\hsize = 6.5in
+\newdimen\defaultparindent \defaultparindent = 15pt
+\parindent = \defaultparindent
+\parskip 18pt plus 1pt
+\setleading{15pt}
+\advance\topskip by 1.2cm
+
+% Prevent underfull vbox error messages.
+\vbadness=10000
+
+% Following George Bush, just get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything.  We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize.  This makes it come to about 9pt for the 8.5x11 format.
+%
+\ifx\emergencystretch\thisisundefined
+  % Allow us to assign to \emergencystretch anyway.
+  \def\emergencystretch{\dimen0}%
+\else
+  \emergencystretch = \hsize
+  \divide\emergencystretch by 45
+\fi
+
+% Use @smallbook to reset parameters for 7x9.5 format  (or else 7x9.25)
+\def\smallbook{
+
+% These values for secheadingskip and subsecheadingskip are
+% experiments.  RJC 7 Aug 1992
+\global\secheadingskip = 17pt plus 6pt minus 3pt
+\global\subsecheadingskip = 14pt plus 6pt minus 3pt
+
+\global\lispnarrowing = 0.3in
+\setleading{12pt}
+\advance\topskip by -1cm
+\global\parskip 3pt plus 1pt
+\global\hsize = 5in
+\global\vsize=7.5in
+\global\tolerance=700
+\global\hfuzz=1pt
+\global\contentsrightmargin=0pt
+\global\deftypemargin=0pt
+\global\defbodyindent=.5cm
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+
+\global\let\smalllisp=\smalllispx
+\global\let\smallexample=\smalllispx
+\global\def\Esmallexample{\Esmalllisp}
+}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{
+\global\tolerance=700
+\global\hfuzz=1pt
+\setleading{12pt}
+\global\parskip 15pt plus 1pt
+
+\global\vsize= 53\baselineskip
+\advance\vsize by \topskip
+%\global\hsize=   5.85in     % A4 wide 10pt
+\global\hsize=  6.5in
+\global\outerhsize=\hsize
+\global\advance\outerhsize by 0.5in
+\global\outervsize=\vsize
+\global\advance\outervsize by 0.6in
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+}
+
+% Allow control of the text dimensions.  Parameters in order: textheight;
+% textwidth; \voffset; \hoffset (!); binding offset.  All require a dimension;
+% header is additional; added length extends the bottom of the page.
+
+\def\changepagesizes#1#2#3#4#5
+{\global\vsize= #1
+ \advance\vsize by \topskip
+ \global\voffset= #3
+ \global\hsize= #2
+ \global\outerhsize=\hsize
+ \global\advance\outerhsize by 0.5in
+ \global\outervsize=\vsize
+ \global\advance\outervsize by 0.6in
+ \global\pagewidth=\hsize
+ \global\pageheight=\vsize
+ \global\normaloffset= #4
+ \global\bindingoffset= #5}
+
+% This layout is compatible with Latex on A4 paper.
+
+\def\afourlatex{\changepagesizes{22cm}{15cm}{7mm}{4.6mm}{5mm}}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise.  Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt \char '042}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt \char '176}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+% \lvvmode is equivalent in function to \leavevmode.
+% Using \leavevmode runs into trouble when written out to
+% an index file due to the expansion of \leavevmode into ``\unhbox
+% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our
+% magic tricks with @.
+\def\lvvmode{\vbox to 0pt{}}
+
+\catcode`\|=\active
+\def|{{\tt \char '174}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+% \catcode 17=0   % Define control-q
+\catcode`\\=\active
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+@def@turnoffactive{@let"=@normaldoublequote
+@let\=@realbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+@def@normalturnoffactive{@let"=@normaldoublequote
+@let\=@normalbackslash
+@let~=@normaltilde
+@let^=@normalcaret
+@let_=@normalunderscore
+@let|=@normalverticalbar
+@let<=@normalless
+@let>=@normalgreater
+@let+=@normalplus}
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+%
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi}
+
+%% These look ok in all fonts, so just make them not special.  The @rm below
+%% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
+
+@c Local variables:
+@c page-delimiter: "^\\\\message"
+@c End:
diff --git a/mechglue/doc/thread-safe.txt b/mechglue/doc/thread-safe.txt
new file mode 100644
index 000000000..0996b329a
--- /dev/null
+++ b/mechglue/doc/thread-safe.txt
@@ -0,0 +1,257 @@
+In general, it's assumed that the library initialization function (if
+initialization isn't delayed) and the library finalization function
+are run in some thread-safe fashion, with no other parts of the
+library in question in use.  (If dlopen or dlsym in one thread starts
+running the initializer, and then dlopen/dlsym in another thread
+returns and lets you start accessing functions or data in the library
+before the initializer is finished, that really seems like a
+dlopen/dlsym bug.)
+
+It's also assumed that if library A depends on library B, then library
+B's initializer runs first, and its finalizer last, whether loading
+dynamically at run time or at process startup/exit.  (It appears that
+AIX 4.3.3 may violate this, at least when we use gcc's
+constructor/destructor attributes in shared libraries.)
+
+Support for freeing the heap storage allocated by a library has NOT,
+in general, been written.  There are hooks, but often they ignore some
+of the library's local storage, mutexes, etc.
+
+If shared library finalization code doesn't get run at all at dlclose
+time, or if we can't use it because the execution order is wrong, then
+you'll get memory leaks.  Deal with it.
+
+Several debugging variables that are not part of our official API are
+not protected by mutexes.  In general, the only way to set them is by
+changing the sources and recompiling, which obviously has no run-time
+thread safety issues, or by stopping the process under a debugger,
+which we blithely assert is "safe enough".
+
+Debug code that we don't normally enable may be less thread safe than
+might be desired.  For example, multiple printf calls may be made,
+with the assumption that the output will not be intermixed with output
+from some other thread.  Offhand, I'm not aware of any cases where
+debugging code is "really" unsafe, as in likely to crash the program
+or produce insecure results.
+
+Various libraries may call assert() and abort().  This should only be
+for "can't happen" cases, and indicate programming errors.  In some
+cases, the compiler may be able to infer that the "can't happen" cases
+really can't happen, and drop the calls, but in many cases, this is
+not possible.
+
+There are cases (e.g., in the com_err library) where errors arising
+when dealing with other errors are handled by calling abort, for lack
+of anything better.  We should probably clean those up someday.
+
+Various libraries call getenv().  This is perfectly safe, as long as
+nothing is calling setenv or putenv or what have you, while multiple
+threads are executing.  Of course, that severely curtails the ability
+to control our libraries through that "interface".
+
+Various libraries call the ctype functions/macros (isupper, etc).  It
+is assumed that the program does not call setlocale, or does so only
+while the program is still single-threaded or while calls into the
+Kerberos libraries are not in progress.
+
+The Windows thread safety support is unfinished.
+
+I'm assuming that structure fields that are never written to (e.g.,
+after a structure has been initialized and *then* made possibly
+visible to multiple threads) are safe to read from one thread while
+another field is being updated by another thread.  If that's not the
+case, some more work is needed (and I'd like details on why it's not
+safe).
+
+----------------
+
+libcom_err
+
+Issues:
+
+The callback hook support (set_com_err_hook, reset_com_err_hook, and
+calls to com_err and com_err_va) uses a mutex to protect the handle on
+the hook function.  As a side effect of this, if a callback function
+is registered which pops up a window and waits for the users'
+acknowledgement, then other errors cannot be reported by other threads
+until after the acknowledgement.  This could be fixed with
+multiple-reader-one-writer type locks, but that's a bit more
+complicated.
+
+The string returned by error_message may be per-thread storage.  It
+can be passed off between threads, but it shouldn't be in use by any
+thread by the time the originating thread calls error_message again.
+
+Error tables must no longer be in use (including pointers returned by
+error_message) when the library containing them is unloaded.
+
+Temporary: A flag variable has been created in error_message.c which
+is used to try to catch cases where remove_error_table is called after
+the library finalization function.  This generally indicates
+out-of-order execution of the library finalization functions.  The
+handling of this flag is not thread-safe, but if the finalization
+function is called, other threads should in theory be finished with
+this library anyways.
+
+Statics: error_message.c, com_err.c, covered above.
+
+----------------
+
+libprofile (and its use in libkrb5)
+
+Does no checks to see if it's opened multiple instances of the same
+file under different names.  Does not guard against trying to open a
+file while another thread or process is in the process of replacing
+it, or two threads trying to update a file at the same time.  The
+former should be pretty safe on UNIX with atomic rename, but on
+Windows there's a race condition; there's a window (so to speak) where
+the filename does not correspond to an actual file.
+
+Statics: prof_file.c, a list of opened config files and their parse
+trees, and a mutex to protect it.
+
+----------------
+
+libk5crypto
+
+Uses of the Yarrow code from the krb5 crypto interface are protected
+by a single mutex.  Initialization of the Yarrow state will be done
+once, the first time these routines are called.  Calls directly to the
+Yarrow functions are not protected.
+
+Uses ctype macros; what happens if the locale is changed in a
+multi-threaded program?
+
+Debug var in pbkdf2.c.
+
+Statics: pbkdf2.c: debug variable.
+
+Statics: prng.c: Global Yarrow data and mutex.
+
+Statics: crypto_libinit.c: library initializer aux data.
+
+----------------
+
+libkrb5
+
+(TBD)
+
+Uses: ctype macros
+
+Uses: getaddrinfo, getnameinfo.  According to current specifications,
+getaddrinfo should be thread-safe; some implementations are not, and
+we're not attempting to figure out which ones.  NetBSD 1.6, for
+example, had an unsafe implementation.
+
+Uses: res_ninit, res_nsearch.  If these aren't available, the non-'n'
+versions will be used, and they are sometimes not thread-safe.
+
+Uses: mkstemp, mktemp -- Are these, or our uses of them, likely to be
+thread-safe?
+
+Uses: sigaction
+
+The use of sigaction is in the code prompting for a password; we try
+to catch the keyboard interrupt character being used and turn it into
+an error return from that function.  THIS IS NOT THREAD-SAFE.
+
+Uses: tcgetattr, tcsetattr.  This is also in the password-prompting
+code.  These are fine as long as no other threads are accessing the
+same terminal at the same time.
+
+Uses: fopen.  This is thread-safe, actually, but a multi-threaded
+server is likely to be using lots of file descriptors.  On 32-bit
+Solaris platforms, fopen will not work if the next available file
+descriptor number is 256 or higher.  This can cause the keytab code to
+fail.
+
+Statics: prompter.c: interrupt flag
+
+Statics: ccdefops.c: default operations table pointer
+
+Statics: ktdefname.c: variable to override default keytab name, NO
+LOCKING.  DON'T TOUCH THESE VARIABLES, at least in threaded programs.
+
+Statics: conv_creds.c: debug variable
+
+Statics: sendto_kdc.c: debug variable, in export list for KDC
+
+Statics: parse.c: default realm cache, changed to not cache
+
+Statics: krb5_libinit.c: lib init aux data
+
+Statics: osconfig.c: various internal variables, probably should be const
+
+Statics: init_ctx.c: "brand" string; not written.
+
+Statics: cc_memory.c: list of caches, with mutex.
+
+Statics: c_ustime.c: last timestamp, to implement "microseconds must
+always increment"
+
+Statics: ktbase.c, ccbase.c, rc_base.c: type registries and mutexes.
+
+----------------
+
+libgssapi_krb5
+
+(TBD)
+
+Uses: ctype macros
+
+Statics: acquire_cred.c: name of keytab to use, and mutex.
+
+Statics: gssapi_krb5.c:
+
+Statics: init_sec_context.c:
+
+Statics: set_ccache.c:
+
+Statics: gssapi_generic.c: OID definitions, non-const by
+specification.  We probably could make them const anyways.
+
+The keytab name saved away by krb5_gss_register_acceptor_identity is
+global and protected by a mutex; the ccache name stored by
+gss_krb5_ccache_name is per-thread.  This inconsistency is due to the
+anticipated usage patterns.
+
+The old ccache name returned by gss_krb5_ccache_name if the last
+parameter is not a null pointer is also stored per-thread, and will be
+discarded at the next call to that routine from the same thread, or at
+thread termination.
+
+Needs work: check various objects for thread safety
+
+----------------
+
+libkrb4
+libdes425
+
+I don't think we're likely to bother with these.
+
+Part of the krb4 API requires keeping some internal storage across
+calls.
+
+----------------
+
+libgssrpc
+
+New version is in place.  Ignore it for now?
+
+----------------
+
+libkadm5*
+libkdb5
+
+Skip these for now.  We may want the KDC libraries to be thread-safe
+eventually, so the KDC can take better advantage of hyperthreaded or
+multiprocessor systems.
+
+----------------
+
+libapputils
+libpty
+libss
+
+Used by single-threaded programs only (but see above re KDC).  Don't
+bother for now.
diff --git a/mechglue/doc/threads.txt b/mechglue/doc/threads.txt
new file mode 100644
index 000000000..b161dafbc
--- /dev/null
+++ b/mechglue/doc/threads.txt
@@ -0,0 +1,101 @@
+Thread safety in the MIT Kerberos libraries
+
+The return value from krb5_cc_default_name is a handle on internal
+storage from the krb5_context.  It is valid only until
+krb5_cc_set_default_name or krb5_free_context is called.  If
+krb5_cc_set_default_name may be called, the calling code must ensure
+that the storage returned by krb5_cc_default_name is no longer in use
+by that time.
+
+Any use of krb5_context must be confined to one thread at a time by
+the application code.
+
+Uses of credentials caches, replay caches, and keytabs may happen in
+multiple threads simultaneously as long as none of them destroys the
+object while other threads may still be using it.  (Any internal data
+modification in those objects will be protected by mutexes or other
+means, within the krb5 library.)
+
+The simple, exposed data structures in krb5.h like krb5_principal are
+not protected; they should not be used in one thread while another
+thread might be modifying them.  (TO DO: Build a list of which calls
+keep references to supplied data or return references to
+otherwise-referenced data, as opposed to everything making copies.)
+
+
+
+[ This part is a little outdated already. ]
+
+   // Between these two, we should be able to do pure compile-time
+   // and pure run-time initialization.
+   //   POSIX: partial initializer is PTHREAD_MUTEX_INITIALIZER,
+   //          finish does nothing
+   //   Windows: partial initializer is zero/empty,
+   //            finish does the actual work and runs at load time
+   //   debug: partial initializer sets one magic value,
+   //          finish verifies, sets a new magic value
+   k5_mutex_t foo_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+   int k5_mutex_finish_init(k5_mutex_t *);
+   // for dynamic allocation
+   int k5_mutex_init(k5_mutex_t *);
+   // Must work for both kinds of allocation, even if it means adding
+   // a flag.
+   int k5_mutex_destroy(k5_mutex_t *);
+   //
+   // Per library, one function to finish the static mutex
+   // initialization.
+   //
+   // A second function called at various possible "first" entry
+   // points which either calls pthread_once on the first function
+   // (POSIX), or checks some flag set by the first function (Windows,
+   // debug support), and possibly returns an error.
+   //
+   // A third function for library termination calls mutex_destroy on
+   // each mutex for the library.
+   //
+   // 
+   int k5_mutex_lock(k5_mutex_t *);
+   int k5_mutex_unlock(k5_mutex_t *);
+   // Optional (always defined, but need not do anything):
+   void k5_mutex_assert_locked(k5_mutex_t *);
+   void k5_mutex_assert_unlocked(k5_mutex_t *);
+
+
+   k5_key_t key;
+   int k5_key_create(k5_key_t *, void (*destructor)(void *));
+   void *k5_getspecific(k5_key_t);
+   int k5_setspecific(k5_key_t, const void *);
+   ... stuff to signal library termination ...
+
+This is **NOT** an exported interface, and is subject to change.
+
+On many platforms with weak reference support, we can declare certain
+symbols to be weak, and test the addresses before calling them.  The
+references generally will be non-null if the application pulls in the
+pthread support.  Sometimes stubs are present in the C library for
+some of these routines, and sometimes they're not functional; if so,
+we need to figure out which ones, and check for the presence of some
+*other* routines.
+
+AIX 4.3.3 doesn't support weak references.  However, it looks like
+calling dlsym(NULL) causes the pthread library to get loaded, so we're
+going to just go ahead and link against it anyways.
+
+On Tru64 we also link against the thread library always.
+
+
+For now, the basic model is:
+
+  If weak references supported, use them.
+  Else, assume support is present; if that means explicitly pulling in
+  the thread library, so be it.
+
+
+
+The locking described above may not be sufficient, at least for good
+performance.  At some point we may want to switch to read/write locks,
+so multiple threads can grovel over a data structure at once as long
+as they don't change it.
+
+
+See also notes in src/include/k5-thread.h.
diff --git a/mechglue/doc/user-guide.texinfo b/mechglue/doc/user-guide.texinfo
new file mode 100644
index 000000000..c1fe46235
--- /dev/null
+++ b/mechglue/doc/user-guide.texinfo
@@ -0,0 +1,1700 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@c guide
+@setfilename krb5-user.info
+@settitle Kerberos V5 UNIX User's Guide
+@setchapternewpage odd                  @c chapter begins on next odd page
+@c @setchapternewpage on                   @c chapter begins on next page
+@c @smallbook                              @c Format for 7" X 9.25" paper
+@c %**end of header
+
+@paragraphindent 0
+@iftex
+@parskip 6pt plus 6pt
+@end iftex
+
+@include definitions.texinfo
+@set EDITION 1.0
+
+@finalout                               @c don't print black warning boxes
+
+@titlepage
+@title @value{PRODUCT} UNIX User's Guide
+@subtitle Release:  @value{RELEASE}
+@subtitle Document Edition:  @value{EDITION}
+@subtitle Last updated:  @value{UPDATED}
+@author @value{COMPANY}
+
+@page
+@vskip 0pt plus 1filll
+
+@end titlepage
+
+@comment  node-name,  next,  previous,  up
+@node Top, Copyright, (dir), (dir)
+
+@ifinfo
+This file describes how to use the @value{PRODUCT} client programs.
+@end ifinfo
+
+@c The master menu is updated using emacs19's M-x texinfo-all-menus-update
+@c function.  Don't forget to run M-x texinfo-every-node-update after
+@c you add a new section or subsection, or after you've rearranged the
+@c comand before each @section or @subsection!  All you need to enter
+@c is:
+@c
+@c @section New Section Name
+@c
+@c M-x texinfo-every-node-update will take care of calculating the
+@c node's forward and back pointers.
+@c
+@c ---------------------------------------------------------------------
+
+@menu
+* Copyright::                   
+* Introduction::                
+* Kerberos V5 Tutorial::        
+* Kerberos V5 Reference::       
+* Kerberos Glossary::           
+@end menu
+
+@node Copyright, Introduction, Top, Top
+@unnumbered Copyright
+
+@include copyright.texinfo
+
+@node Introduction, Kerberos V5 Tutorial, Copyright, Top
+@chapter Introduction
+
+@ifset CYGNUS
+@value{PRODUCT} is based on the Kerberos V5 authentication system
+developed at MIT.
+@end ifset
+@ifset MIT
+Kerberos V5 is an authentication system developed at MIT.
+@end ifset
+Kerberos is named for the three-headed watchdog from Greek mythology,
+who guarded the entrance to the underworld.
+
+Under Kerberos, a client (generally either a user or a service) sends a
+request for a ticket to the @i{Key Distribution Center} (KDC).  The KDC
+creates a @dfn{ticket-granting ticket} (TGT) for the client, encrypts it
+using the client's password as the key, and sends the encrypted TGT back
+to the client.  The client then attempts to decrypt the TGT, using its
+password.  If the client successfully decrypts the TGT (@i{i.e.}, if the
+client gave the correct password), it keeps the decrypted TGT, which
+indicates proof of the client's identity.
+
+The TGT, which expires at a specified time, permits the client to obtain
+additional tickets, which give permission for specific services.  The
+requesting and granting of these additional tickets is user-transparent.
+
+Since Kerberos negotiates authenticated, and optionally encrypted,
+communications between two points anywhere on the internet, it provides
+a layer of security that is not dependent on which side of a firewall
+either client is on.  Since studies have shown that half of the computer
+security breaches in industry happen from @i{inside} firewalls,
+@value{COMPANY}'s @value{PRODUCT} plays a vital role in maintaining your
+network security.
+
+The @value{PRODUCT} package is designed to be easy to use.  Most of the
+commands are nearly identical to UNIX network programs you already
+use.  @value{PRODUCT} is a @dfn{single-sign-on} system, which means
+that you have to type your password only once per session, and Kerberos
+does the authenticating and encrypting transparently.
+
+@menu
+* What is a Ticket?::           
+* What is a Kerberos Principal?::  
+@end menu
+
+@node What is a Ticket?, What is a Kerberos Principal?, Introduction, Introduction
+@section What is a Ticket?
+
+Your Kerberos @dfn{credentials}, or ``@dfn{tickets}'', are a set of
+electronic information that can be used to verify your identity.  Your
+Kerberos tickets may be stored in a file, or they may exist only in
+memory.
+
+The first ticket you obtain is a @dfn{ticket-granting ticket}, which
+permits you to obtain additional tickets.  These additional tickets give
+you permission for specific services.  The requesting and granting of
+these additional tickets happens transparently.
+
+A good analogy for the ticket-granting ticket is a three-day ski pass
+that is good at four different resorts.  You show the pass at whichever
+resort you decide to go to (until it expires), and you receive a lift
+ticket for that resort.  Once you have the lift ticket, you can ski all
+you want at that resort.  If you go to another resort the next day, you
+once again show your pass, and you get an additional lift ticket for the
+new resort.  The difference is that the @value{PRODUCT} programs notice
+that you have the weekend ski pass, and get the lift ticket for you, so
+you don't have to perform the transactions yourself.
+
+@node What is a Kerberos Principal?,  , What is a Ticket?, Introduction
+@section What is a Kerberos Principal?
+
+A Kerberos @dfn{principal} is a unique identity to which Kerberos can
+assign tickets.  Principals can have an arbitrary number of
+components.  Each component is separated by a component separator,
+generally `/'.  The last component is the realm, separated from the
+rest of the principal by the realm separator, generally `@@'.  If there
+is no realm component in the principal, then it will be assumed that
+the principal is in the default realm for the context in which it is
+being used.
+
+Traditionally, a principal is divided into three parts:  the
+@dfn{primary}, the @dfn{instance}, and the @dfn{realm}.  The format of
+a typical Kerberos V5 principal is @code{primary/instance@@REALM}.
+
+@itemize @bullet
+@item The @dfn{primary} is the first part of the principal.  In the case
+of a user, it's the same as your username.  For a host, the primary is
+the word @code{host}.
+
+@item The @dfn{instance} is an optional string that qualifies the
+primary.  The instance is separated from the primary by a slash
+(@code{/}).  In the case of a user, the instance is usually null, but a
+user might also have an additional principal, with an instance called
+@samp{admin}, which he/she uses to administrate a database.  The
+principal @code{@value{RANDOMUSER1}@@@value{PRIMARYREALM}} is completely
+separate from the principal
+@code{@value{RANDOMUSER1}/admin@@@value{PRIMARYREALM}}, with a separate
+password, and separate permissions.  In the case of a host, the instance
+is the fully qualified hostname, e.g.,
+@code{@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}}.
+
+@item The @dfn{realm} is your Kerberos realm.  In most cases, your
+Kerberos realm is your domain name, in upper-case letters.  For example,
+the machine @code{@value{RANDOMHOST1}.@value{SECONDDOMAIN}} would be in
+the realm @code{@value{SECONDREALM}}.
+@end itemize
+
+@node Kerberos V5 Tutorial, Kerberos V5 Reference, Introduction, Top
+@chapter Kerberos V5 Tutorial
+
+This tutorial is intended to familiarize you with the @value{PRODUCT}
+client programs.  We will represent your prompt as ``@code{shell%}''.
+So an instruction to type the ``@kbd{ls}'' command would be represented as
+follows:
+
+@need 600
+@smallexample
+@group
+@b{shell%} ls
+@end group
+@end smallexample
+
+In these examples, we will use sample usernames, such as
+@code{@value{RANDOMUSER1}} and @code{@value{RANDOMUSER2}}, sample
+hostnames, such as @code{@value{RANDOMHOST1}} and
+@code{@value{RANDOMHOST2}}, and sample domain names, such as
+@code{@value{PRIMARYDOMAIN}} and @code{@value{SECONDDOMAIN}}.  When you
+see one of these, substitute your username, hostname, or domain name
+accordingly.
+
+@menu
+* Setting Up to Use Kerberos V5::  
+* Ticket Management::           
+* Password Management::         
+* Kerberos V5 Applications::    
+@end menu
+
+@node Setting Up to Use Kerberos V5, Ticket Management, Kerberos V5 Tutorial, Kerberos V5 Tutorial
+@section Setting Up to Use @value{PRODUCT}
+
+Your system administrator will have installed the @value{PRODUCT}
+programs in whichever directory makes the most sense for your system.
+We will use @code{@value{ROOTDIR}} throughout this guide to refer to the
+top-level directory @value{PRODUCT} directory.  We will therefor use
+@code{@value{BINDIR}} to denote the location of the @value{PRODUCT} user
+programs.  In your installation, the directory name may be different,
+but whatever the directory name is, you should make sure it is included
+in your path.  You will probably want to put it @i{ahead of} the
+directories @code{/bin} and @code{/usr/bin} so you will get the
+@value{PRODUCT} network programs, rather than the standard UNIX
+versions, when you type their command names.
+
+@node Ticket Management, Password Management, Setting Up to Use Kerberos V5, Kerberos V5 Tutorial
+@section Ticket Management
+
+On many systems, Kerberos is built into the login program, and you get
+tickets automatically when you log in.  Other programs, such as
+@code{rsh}, @code{rcp}, @code{telnet}, and @code{rlogin}, can forward
+copies of your tickets to the remote host.  Most of these programs also
+automatically destroy your tickets when they exit.  However,
+@value{COMPANY} recommends that you explicitly destroy your Kerberos
+tickets when you are through with them, just to be sure.  One way to
+help ensure that this happens is to add the @code{kdestroy} command to
+your @code{.logout} file.  Additionally, if you are going to be away
+from your machine and are concerned about an intruder using your
+permissions, it is safest to either destroy all copies of your tickets,
+or use a screensaver that locks the screen.
+
+@need 2000
+@menu
+* Kerberos Ticket Properties::  
+* Obtaining Tickets with kinit::  
+* Viewing Your Tickets with klist::  
+* Destroying Your Tickets with kdestroy::  
+@end menu
+
+@node Kerberos Ticket Properties, Obtaining Tickets with kinit, Ticket Management, Ticket Management
+@subsection Kerberos Ticket Properties
+
+@noindent
+There are various properties that Kerberos tickets can have:
+
+If a ticket is @dfn{forwardable}, then the KDC can issue a new ticket with
+a different network address based on the forwardable ticket.  This
+allows for authentication forwarding without requiring a password to be
+typed in again.  For example, if a user with a forwardable TGT logs
+into a remote system, the KDC could issue a new TGT for that user with
+the netword address of the remote system, allowing authentication on
+that host to work as though the user were logged in locally.
+
+When the KDC creates a new ticket based on a forwardable ticket, it
+sets the @dfn{forwarded} flag on that new ticket.  Any tickets that are
+created based on a ticket with the forwarded flag set will also have
+their forwarded flags set.
+
+A @dfn{proxiable} ticket is similar to a forwardable ticket in that it
+allows a service to take on the identity of the client.  Unlike a
+forwardable ticket, however, a proxiable ticket is only issued for
+specific services.  In other words, a ticket-granting ticket cannot be
+issued based on a ticket that is proxiable but not forwardable.
+
+A @dfn{proxy} ticket is one that was issued based on a proxiable ticket.
+
+A @dfn{postdated} ticket is issued with the @i{invalid} flag set.
+After the starting time listed on the ticket, it can be presented to
+the KDC to obtain valid tickets.  
+
+Tickets with the @dfn{postdateable} flag set can be used to issue postdated
+tickets.
+
+@dfn{Renewable} tickets can be used to obtain new session keys without
+the user entering their password again.  A renewable ticket has two
+expiration times.  The first is the time at which this particular
+ticket expires.  The second is the latest possible expiration time for
+any ticket issued based on this renewable ticket.
+
+A ticket with the @dfn{initial} flag set was issued based on the
+authentication protocol, and not on a ticket-granting ticket.   Clients
+that wish to ensure that the user's key has been recently presented for
+verification could specify that this flag must be set to accept the
+ticket.
+
+An @dfn{invalid} ticket must be rejected by application servers.  Postdated
+tickets are usually issued with this flag set, and must be validated by
+the KDC before they can be used.
+
+A @dfn{preauthenticated} ticket is one that was only issued after the
+client requesting the ticket had authenticated itself to the KDC.
+
+The @dfn{hardware authentication} flag is set on a ticket which
+required the use of hardware for authentication.  The hardware is
+expected to be possessed only by the client which requested the
+tickets.
+
+If a ticket has the @dfn{transit policy checked} flag set, then the KDC that
+issued this ticket implements the transited-realm check policy and
+checked the transited-realms list on the ticket.  The transited-realms
+list contains a list of all intermediate realms between the realm of the
+KDC that issued the first ticket and that of the one that issued the
+current ticket.  If this flag is not set, then the application server
+must check the transited realms itself or else reject the ticket.
+
+The @dfn{okay as delegate} flag indicates that the server specified in
+the ticket is suitable as a delegate as determined by the policy of
+that realm.  A server that is acting as a delegate has been granted a
+proxy or a forwarded TGT.  This flag is a new addition to the
+@value{PRODUCT} protocol and is not yet implemented on MIT servers.
+
+An @dfn{anonymous}  ticket is one in which the named principal is a generic
+principal for that realm; it does not actually specify the individual
+that will be using the ticket.  This ticket is meant only to securely
+distribute a session key.  This is a new addition to the @value{PRODUCT}
+protocol and is not yet implemented on MIT servers.
+
+@node Obtaining Tickets with kinit, Viewing Your Tickets with klist, Kerberos Ticket Properties, Ticket Management
+@subsection Obtaining Tickets with kinit
+
+If your site is using the @value{PRODUCT} login program, you will get
+Kerberos tickets automatically when you log in.  If your site uses a
+different login program, you may need to explicitly obtain your Kerberos
+tickets, using the @code{kinit} program.  Similarly, if your Kerberos
+tickets expire, use the @code{kinit} program to obtain new ones.
+
+@need 1500
+To use the @code{kinit} program, simply type @kbd{kinit} and then type
+your password at the prompt.  For example, Jennifer (whose username is
+@code{@value{RANDOMUSER1}}) works for Bleep, Inc. (a fictitious company
+with the domain name @code{@value{PRIMARYDOMAIN}} and the Kerberos realm
+@code{@value{PRIMARYREALM}}).  She would type:
+
+@smallexample
+@group
+@b{shell%} kinit
+@b{Password for @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{<-- [Type @value{RANDOMUSER1}'s password here.]}
+@b{shell%}
+@end group
+@end smallexample
+
+@need 1000
+If you type your password incorrectly, kinit will give you the following
+error message:
+
+@smallexample
+@group
+@b{shell%} kinit
+@b{Password for @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{<-- [Type the wrong password here.]}
+@b{kinit: Password incorrect}
+@b{shell%}
+@end group
+@end smallexample
+
+@noindent and you won't get Kerberos tickets.
+
+@noindent Notice that @code{kinit} assumes you want tickets for your own
+username in your default realm.  
+@need 1500
+Suppose Jennifer's friend David is visiting, and he wants to borrow a
+window to check his mail.  David needs to get tickets for himself in his
+own realm, @value{SECONDREALM}.@footnote{Note:  the realm
+@value{SECONDREALM} must be listed in your computer's Kerberos
+configuration file, @code{/etc/krb5.conf}.}  He would type:
+
+@smallexample
+@group
+@b{shell%} kinit @value{RANDOMUSER2}@@@value{SECONDREALM}
+@b{Password for @value{RANDOMUSER2}@@@value{SECONDREALM}:} @i{<-- [Type @value{RANDOMUSER2}'s password here.]}
+@b{shell%}
+@end group
+@end smallexample
+
+@noindent David would then have tickets which he could use to log onto
+his own machine.  Note that he typed his password locally on Jennifer's
+machine, but it never went over the network.  Kerberos on the local host
+performed the authentication to the KDC in the other realm.
+
+@need 1000
+If you want to be able to forward your tickets to another host, you need
+to request @dfn{forwardable} tickets.  You do this by specifying the
+@kbd{-f} option:
+
+@smallexample
+@group
+@b{shell%} kinit -f
+@b{Password for @value{RANDOMUSER1}@@@value{PRIMARYREALM}:} @i{<-- [Type your password here.]}
+@b{shell%}
+@end group
+@end smallexample
+
+@noindent
+Note that @code{kinit} does not tell you that it obtained forwardable
+tickets; you can verify this using the @code{klist} command
+(@pxref{Viewing Your Tickets with klist}).
+
+Normally, your tickets are good for your system's default ticket
+lifetime, which is ten hours on many systems.  You can specify a
+different ticket lifetime with the @samp{-l} option.  Add the letter
+@samp{s} to the value for seconds, @samp{m} for minutes, @samp{h} for
+hours, or @samp{d} for days.
+@need 1500
+For example, to obtain forwardable tickets for
+@code{@value{RANDOMUSER2}@@@value{SECONDREALM}} that would be good for
+three hours, you would type:
+
+@smallexample
+@group
+@b{shell%} kinit -f -l 3h @value{RANDOMUSER2}@@@value{SECONDREALM}
+@b{Password for @value{RANDOMUSER2}@@@value{SECONDREALM}:} @i{<-- [Type @value{RANDOMUSER2}'s password here.]}
+@b{shell%}
+@end group
+@end smallexample
+
+@noindent
+You cannot mix units; specifying a lifetime of @samp{3h30m} would result
+in an error.  Note also that most systems specify a maximum ticket
+lifetime.  If you request a longer ticket lifetime, it will be
+automatically truncated to the maximum lifetime.
+
+@node Viewing Your Tickets with klist, Destroying Your Tickets with kdestroy, Obtaining Tickets with kinit, Ticket Management
+@subsection Viewing Your Tickets with klist
+
+The @code{klist} command shows your tickets.  When you first obtain
+tickets, you will have only the ticket-granting ticket.  (@xref{What is
+a Ticket?}.)  The listing would look like this:
+
+@smallexample
+@group
+@b{shell%} klist
+Ticket cache: /tmp/krb5cc_ttypa
+Default principal: @value{RANDOMUSER1}@@@value{PRIMARYREALM}
+
+Valid starting     Expires            Service principal
+06/07/04 19:49:21  06/08/04 05:49:19  krbtgt/@value{PRIMARYREALM}@@@value{PRIMARYREALM}
+@b{shell%}
+@end group
+@end smallexample
+
+@noindent
+The ticket cache is the location of your ticket file.  In the above
+example, this file is named @code{/tmp/krb5cc_ttypa}.  The default
+principal is your kerberos @dfn{principal}.  (@pxref{What is a Kerberos
+Principal?})
+
+The ``valid starting'' and ``expires'' fields describe the period of
+time during which the ticket is valid.  The @dfn{service principal}
+describes each ticket.  The ticket-granting ticket has the primary
+@code{krbtgt}, and the instance is the realm name.
+
+@need 2000
+Now, if @value{RANDOMUSER1} connected to the machine
+@code{@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}}, and then typed
+@kbd{klist} again, she would have gotten the following result:
+
+@smallexample
+@group
+@b{shell%} klist
+Ticket cache: /tmp/krb5cc_ttypa
+Default principal: @value{RANDOMUSER1}@@@value{PRIMARYREALM}
+
+Valid starting     Expires            Service principal
+06/07/04 19:49:21  06/08/04 05:49:19  krbtgt/@value{PRIMARYREALM}@@@value{PRIMARYREALM}
+06/07/04 20:22:30  06/08/04 05:49:19  host/@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}
+@b{shell%}
+@end group
+@end smallexample
+
+@noindent
+Here's what happened:  when @value{RANDOMUSER1} used telnet to connect
+to the host @code{@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}}, the telnet
+program presented her ticket-granting ticket to the KDC and requested a
+host ticket for the host
+@code{@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}}.  The KDC sent the host
+ticket, which telnet then presented to the host
+@code{@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}}, and she was allowed to
+log in without typing her password.
+
+@need 3000
+Suppose your Kerberos tickets allow you to log into a host in another
+domain, such as @code{@value{RANDOMHOST2}.@value{SECONDDOMAIN}}, which
+is also in another Kerberos realm, @code{@value{SECONDREALM}}.  If you
+telnet to this host, you will receive a ticket-granting ticket for the
+realm @code{@value{SECONDREALM}}, plus the new @code{host} ticket for
+@code{@value{RANDOMHOST2}.@value{SECONDDOMAIN}}.  @kbd{klist} will now
+show:
+
+@smallexample
+@group
+@b{shell%} klist
+Ticket cache: /tmp/krb5cc_ttypa
+Default principal: @value{RANDOMUSER1}@@@value{PRIMARYREALM}
+
+Valid starting     Expires            Service principal
+06/07/04 19:49:21  06/08/04 05:49:19  krbtgt/@value{PRIMARYREALM}@@@value{PRIMARYREALM}
+06/07/04 20:22:30  06/08/04 05:49:19  host/@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}
+06/07/04 20:24:18  06/08/04 05:49:19  krbtgt/@value{SECONDREALM}@@@value{PRIMARYREALM}
+06/07/04 20:24:18  06/08/04 05:49:19  host/@value{RANDOMHOST2}.@value{SECONDDOMAIN}@@@value{PRIMARYREALM}
+@b{shell%}
+@end group
+@end smallexample
+
+You can use the @code{-f} option to view the @dfn{flags} that apply to
+your tickets.  The flags are:
+
+@table @b
+@itemx F
+@b{F}orwardable
+@itemx f
+@b{f}orwarded
+@itemx P
+@b{P}roxiable
+@itemx p
+@b{p}roxy
+@itemx D
+post@b{D}ateable
+@itemx d
+post@b{d}ated
+@itemx R
+@b{R}enewable
+@itemx I
+@b{I}nitial
+@itemx i
+@b{i}nvalid
+@itemx H
+@b{H}ardware authenticated
+@itemx A
+pre@b{A}uthenticated
+@itemx T
+@b{T}ransit policy checked
+@itemx O
+@b{O}kay as delegate
+@itemx a
+@b{a}nonymous
+@end table
+
+@need 1500
+Here is a sample listing.  In this example, the user @value{RANDOMUSER1}
+obtained her initial tickets (@samp{I}), which are forwardable
+(@samp{F}) and postdated (@samp{d}) but not yet validated (@samp{i}).
+(@xref{kinit Reference}, for more information about postdated tickets.)
+
+@smallexample
+@group
+@b{shell%} klist -f
+@b{Ticket cache: /tmp/krb5cc_320
+Default principal: @value{RANDOMUSER1}@@@value{PRIMARYREALM}
+
+Valid starting      Expires             Service principal
+31/07/05 19:06:25  31/07/05 19:16:25  krbtgt/@value{PRIMARYREALM}@@@value{PRIMARYREALM}
+        Flags: FdiI
+shell%}
+@end group
+@end smallexample
+
+@need 1500
+In the following example, the user @value{RANDOMUSER2}'s tickets were
+forwarded (@samp{f}) to this host from another host.  The tickets are
+reforwardable (@samp{F}).
+
+@smallexample
+@group
+@b{shell%} klist -f
+@b{Ticket cache: /tmp/krb5cc_p11795
+Default principal: @value{RANDOMUSER2}@@@value{SECONDREALM}
+
+Valid starting     Expires            Service principal
+07/31/05 11:52:29  07/31/05 21:11:23  krbtgt/@value{SECONDREALM}@@@value{SECONDREALM}
+        Flags: Ff
+07/31/05 12:03:48  07/31/05 21:11:23  host/@value{RANDOMHOST2}.@value{SECONDDOMAIN}@@@value{SECONDREALM}
+        Flags: Ff
+shell%}
+@end group
+@end smallexample
+
+@node Destroying Your Tickets with kdestroy,  , Viewing Your Tickets with klist, Ticket Management
+@subsection Destroying Your Tickets with kdestroy
+
+Your Kerberos tickets are proof that you are indeed yourself, and
+tickets can be stolen.  If this happens, the person who has them can
+masquerade as you until they expire.  For this reason, you should
+destroy your Kerberos tickets when you are away from your computer.
+
+@need 1000
+Destroying your tickets is easy.  Simply type @kbd{kdestroy}.
+
+@smallexample
+@group
+@b{shell%} kdestroy
+@b{shell%}
+@end group
+@end smallexample
+
+@need 1500
+If @code{kdestroy} fails to destroy your tickets, it will beep and give
+an error message.  For example, if @code{kdestroy} can't find any
+tickets to destroy, it will give the following message:
+
+@smallexample
+@group
+@b{shell%} kdestroy
+@b{kdestroy: No credentials cache file found while destroying cache
+shell%}
+@end group
+@end smallexample
+
+@node Password Management, Kerberos V5 Applications, Ticket Management, Kerberos V5 Tutorial
+@section Password Management
+
+Your password is the only way Kerberos has of verifying your identity.
+If someone finds out your password, that person can masquerade as
+you---send email that comes from you, read, edit, or delete your files,
+or log into other hosts as you---and no one will be able to tell the
+difference.  For this reason, it is important that you choose a good
+password (@pxref{Password Advice}), and keep it secret.  If you need to
+give access to your account to someone else, you can do so through
+Kerberos.  (@xref{Granting Access to Your Account}.)  You should
+@i{never} tell your password to anyone, including your system
+administrator, for any reason.  You should change your password
+frequently, particularly any time you think someone may have found out
+what it is.
+
+@menu
+* Changing Your Password::      
+* Password Advice::             
+* Granting Access to Your Account::  
+@end menu
+
+@node Changing Your Password, Password Advice, Password Management, Password Management
+@subsection Changing Your Password
+
+@need 2500
+To change your Kerberos password, use the @code{kpasswd} command.  It
+will ask you for your old password (to prevent someone else from walking
+up to your computer when you're not there and changing your password),
+and then prompt you for the new one twice.  (The reason you have to type
+it twice is to make sure you have typed it correctly.)  For example,
+user @code{@value{RANDOMUSER2}} would do the following:
+
+@smallexample
+@group
+@b{shell%} kpasswd
+@b{Password for @value{RANDOMUSER2}:}    @i{<- Type your old password.}
+@b{Enter new password:}    @i{<- Type your new password.}
+@b{Enter it again:}  @i{<- Type the new password again.}
+@b{Password changed.}
+@b{shell%}
+@end group
+@end smallexample
+
+@need 1800
+If @value{RANDOMUSER2} typed the incorrect old password, he would get
+the following message:
+
+@smallexample
+@group
+@b{shell%} kpasswd
+@b{Password for @value{RANDOMUSER2}:}  @i{<- Type the incorrect old password.}
+@b{kpasswd: Password incorrect while getting initial ticket
+shell%}
+@end group
+@end smallexample
+
+@need 2500
+If you make a mistake and don't type the new password the same way
+twice, @code{kpasswd} will ask you to try again:
+
+@smallexample
+@group
+@b{shell%} kpasswd
+@b{Password for @value{RANDOMUSER2}:}  @i{<- Type the old password.}
+@b{Enter new password:}  @i{<- Type the new password.}
+@b{Enter it again:} @i{<- Type a different new password.}
+@b{kpasswd: Password mismatch while reading password
+shell%}
+@end group
+@end smallexample
+
+Once you change your password, it takes some time for the change to
+propagate through the system.  Depending on how your system is set up,
+this might be anywhere from a few minutes to an hour or more.  If you
+need to get new Kerberos tickets shortly after changing your password,
+try the new password.  If the new password doesn't work, try again using
+the old one.
+
+@node Password Advice, Granting Access to Your Account, Changing Your Password, Password Management
+@subsection Password Advice
+
+Your password can include almost any character you can type (except
+control keys and the ``enter'' key).  A good password is one you can
+remember, but that no one else can easily guess.  Examples of @i{bad}
+passwords are words that can be found in a dictionary, any common or
+popular name, especially a famous person (or cartoon character), your
+name or username in any form (@i{e.g.}, forward, backward, repeated
+twice, @i{etc.}), your spouse's, child's, or pet's name, your birth
+date, your social security number, and any sample password that appears
+in this (or any other) manual.
+
+@need 2200
+@value{COMPANY} recommends that your password be at least 6 characters
+long, and contain UPPER- and lower-case letters, numbers, and/or
+punctuation marks.  Some passwords that would be good if they weren't
+listed in this manual include:
+
+@itemize @bullet
+@item some initials, like ``GykoR-66.'' for ``Get your kicks on Route
+66.''
+
+@item an easy-to-pronounce nonsense word, like ``slaRooBey'' or
+``krang-its''
+
+@item a misspelled phrase, like ``2HotPeetzas!'' or ``ItzAGurl!!!''
+@end itemize
+
+@noindent Note:  don't actually use any of the above passwords.  They're
+only meant to show you how to make up a good password.  Passwords that
+appear in a manual are the first ones intruders will try.
+
+@need 3800 
+@value{PRODUCT} allows your system administrators to automatically
+reject bad passwords, based on certain criteria, such as a password
+dictionary or a minimum length.  For example, if the user
+@code{@value{RANDOMUSER1}}, who had a policy "strict" that required a
+minimum of 8 characaters, chose a password that was less than 8
+characters, Kerberos would give an error message like the following:
+
+@smallexample
+@group
+@b{shell%} kpasswd
+@b{Password for @value{RANDOMUSER1}:}  @i{<- Type your old password here.}
+
+@value{RANDOMUSER1}'s password is controlled by the policy strict, which
+requires a minimum of 8 characters from at least 3 classes (the five classes
+are lowercase, uppercase, numbers, punctuation, and all other characters).
+
+@b{Enter new password:}  @i{<- Type an insecure new password.}
+@b{Enter it again:}  @i{<- Type it again.}
+
+kpasswd: Password is too short while attempting to change password.
+Please choose another password.
+
+@b{Enter new password:}  @i{<- Type a good password here.}
+@b{Enter it again:}  @i{<- Type it again.}
+@b{Password changed.
+shell%}
+@end group
+@end smallexample
+
+@noindent Your system administrators can choose the message that is
+displayed if you choose a bad password, so the message you see may be
+different from the above example.
+
+@node Granting Access to Your Account,  , Password Advice, Password Management
+@subsection Granting Access to Your Account
+
+@need 1800
+If you need to give someone access to log into your account, you can do
+so through Kerberos, without telling the person your password.  Simply
+create a file called @code{.k5login} in your home directory.  This file
+should contain the Kerberos principal (@xref{What is a Kerberos
+Principal?}.) of each person to whom you wish to give access.  Each
+principal must be on a separate line.  Here is a sample @code{.k5login}
+file:
+
+@smallexample
+@group
+@value{RANDOMUSER1}@@@value{PRIMARYREALM}
+@value{RANDOMUSER2}@@@value{SECONDREALM}
+@end group
+@end smallexample
+
+@noindent This file would allow the users @code{@value{RANDOMUSER1}} and
+@code{@value{RANDOMUSER2}} to use your user ID, provided that they had
+Kerberos tickets in their respective realms.  If you will be logging
+into other hosts across a network, you will want to include your own
+Kerberos principal in your @code{.k5login} file on each of these hosts.
+
+@need 1000
+Using a @code{.k5login} file is much safer than giving out your
+password, because:
+
+@itemize @bullet
+@item You can take access away any time simply by removing the principal
+from your @code{.k5login} file.
+
+@item Although the user has full access to your account on one
+particular host (or set of hosts if your @code{.k5login} file is shared,
+@i{e.g.}, over NFS), that user does not inherit your network privileges.
+
+@item Kerberos keeps a log of who obtains tickets, so a system
+administrator could find out, if necessary, who was capable of using
+your user ID at a particular time.
+@end itemize
+
+One common application is to have a @code{.k5login} file in
+@code{root}'s home directory, giving root access to that machine to the
+Kerberos principals listed.  This allows system administrators to allow
+users to become root locally, or to log in remotely as @code{root},
+without their having to give out the root password, and without anyone
+having to type the root password over the network.
+
+@node Kerberos V5 Applications,  , Password Management, Kerberos V5 Tutorial
+@section Kerberos V5 Applications
+
+@value{PRODUCT} is a @dfn{single-sign-on} system.  This means that you
+only have to type your password once, and the @value{PRODUCT} programs
+do the authenticating (and optionally encrypting) for you.  The way this
+works is that Kerberos has been built into each of a suite of network
+programs.  For example, when you use a @value{PRODUCT} program to
+connect to a remote host, the program, the KDC, and the remote host
+perform a set of rapid negotiations.  When these negotiations are
+completed, your program has proven your identity on your behalf to the
+remote host, and the remote host has granted you access, all in the
+space of a few seconds.
+
+The @value{PRODUCT} applications are versions of existing UNIX network
+programs with the Kerberos features added.
+
+@menu
+* Overview of Additional Features::  
+* telnet::                      
+* rlogin::                      
+* FTP::                         
+* rsh::                         
+* rcp::                         
+* ksu::                         
+@end menu
+
+@node Overview of Additional Features, telnet, Kerberos V5 Applications, Kerberos V5 Applications
+@subsection Overview of Additional Features
+
+The @value{PRODUCT} @dfn{network programs} are those programs that
+connect to another host somewhere on the internet.  These programs
+include @code{rlogin}, @code{telnet}, @code{ftp}, @code{rsh},
+@code{rcp}, and @code{ksu}.  These programs have all of the original
+features of the corresponding non-Kerberos @code{rlogin}, @code{telnet},
+@code{ftp}, @code{rsh}, @code{rcp}, and @code{su} programs, plus
+additional features that transparently use your Kerberos tickets for
+negotiating authentication and optional encryption with the remote host.
+In most cases, all you'll notice is that you no longer have to type your
+password, because Kerberos has already proven your identity.
+
+The @value{PRODUCT} network programs allow you the options of forwarding
+your tickets to the remote host (if you obtained forwardable tickets
+with the @code{kinit} program; @pxref{Obtaining Tickets with kinit}), and
+encrypting data transmitted between you and the remote host.
+
+This section of the tutorial assumes you are familiar with the
+non-Kerberos versions of these programs, and highlights the Kerberos
+functions added in the @value{PRODUCT} package.
+
+@node telnet, rlogin, Overview of Additional Features, Kerberos V5 Applications
+@subsection telnet
+
+The @value{PRODUCT} @code{telnet} command works exactly like the
+standard UNIX telnet program, with the following Kerberos options added:
+
+@table @kbd
+@itemx -f
+forwards a copy of your tickets to the remote host.
+
+@itemx -F
+forwards a copy of your tickets to the remote host, and marks them
+re-forwardable from the remote host.
+
+@itemx -k @i{realm}
+requests tickets for the remote host in the specified realm, instead of
+determining the realm itself.
+
+@itemx -K
+uses your tickets to authenticate to the remote host, but does not log
+you in.
+
+@itemx -a
+attempt automatic login using your tickets.  @code{telnet} will assume
+the same username unless you explicitly specify another.
+
+@itemx -x
+turns on encryption.
+
+@end table
+
+@need 4000
+For example, if @code{@value{RANDOMUSER2}} wanted to use the standard
+UNIX telnet to connect to the machine
+@code{@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}}, he would type:
+
+@smallexample
+@group
+@b{shell%} telnet @value{RANDOMHOST1}.@value{SECONDDOMAIN}
+@b{Trying 128.0.0.5 ...
+Connected to @value{RANDOMHOST1}.@value{SECONDDOMAIN}.
+Escape character is '^]'.
+
+NetBSD/i386 (daffodil) (ttyp3)
+
+login:} @value{RANDOMUSER2}
+@b{Password:}    @i{<- @value{RANDOMUSER2} types his password here}
+@b{Last login: Fri Jun 21 17:13:11 from @value{RANDOMHOST2}.@value{PRIMARYDOMAIN}
+Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
+        The Regents of the University of California.   All rights reserved.
+
+NetBSD 1.1: Tue May 21 00:31:42 EDT 1996
+
+Welcome to NetBSD!
+shell%}
+@end group
+@end smallexample
+
+@noindent Note that the machine
+@code{@value{RANDOMHOST1}.@value{SECONDDOMAIN}} asked for
+@code{@value{RANDOMUSER2}}'s password.  When he typed it, his password
+was sent over the network unencrypted.  If an intruder were watching
+network traffic at the time, that intruder would know
+@code{@value{RANDOMUSER2}}'s password.
+
+@need 4000
+If, on the other hand, @code{@value{RANDOMUSER1}} wanted to use the
+@value{PRODUCT} telnet to connect to the machine
+@code{@value{RANDOMHOST2}.@value{PRIMARYDOMAIN}}, she could forward a
+copy of her tickets, request an encrypted session, and log on as herself
+as follows:
+
+@smallexample
+@group
+@b{shell%} telnet -a -f -x @value{RANDOMHOST2}.@value{PRIMARYDOMAIN}
+@b{Trying 128.0.0.5...
+Connected to @value{RANDOMHOST2}.@value{PRIMARYDOMAIN}.
+Escape character is '^]'.
+[ Kerberos V5 accepts you as ``@value{RANDOMUSER1}@@@value{PRIMARYDOMAIN}'' ]
+[ Kerberos V5 accepted forwarded credentials ]
+What you type is protected by encryption.
+Last login: Tue Jul 30 18:47:44 from @value{RANDOMHOST}.@value{SECONDDOMAIN}
+Athena Server (sun4) Version 9.1.11 Tue Jul 30 14:40:08 EDT 2002
+
+shell%}
+@end group
+@end smallexample
+
+@noindent Note that @code{@value{RANDOMUSER1}}'s machine used Kerberos
+to authenticate her to @code{@value{RANDOMHOST2}.@value{PRIMARYDOMAIN}},
+and logged her in automatically as herself.  She had an encrypted
+session, a copy of her tickets already waiting for her, and she never
+typed her password.
+
+If you forwarded your Kerberos tickets, @code{telnet} automatically
+destroys them when it exits.  The full set of options to @value{PRODUCT}
+@code{telnet} are discussed in the Reference section of this manual.
+(@pxref{telnet Reference})
+
+@need 2000
+@node rlogin, FTP, telnet, Kerberos V5 Applications
+@subsection rlogin
+
+@need 1000
+The @value{PRODUCT} @code{rlogin} command works exactly like the
+standard UNIX rlogin program, with the following Kerberos options added:
+
+@table @kbd
+@itemx -f
+forwards a copy of your tickets to the remote host.
+
+@itemx -F
+forwards a copy of your tickets to the remote host, and marks them
+re-forwardable from the remote host.
+
+@itemx -k @i{realm}
+requests tickets for the remote host in the specified realm, instead of
+determining the realm itself.
+
+@itemx -x
+encrypts the input and output data streams (the username is sent unencrypted)
+
+@end table
+
+@need 3000
+For example, if @code{@value{RANDOMUSER2}} wanted to use the standard
+UNIX rlogin to connect to the machine
+@code{@value{RANDOMHOST1}.@value{SECONDDOMAIN}}, he would type:
+
+@smallexample
+@group
+@b{shell%} rlogin @value{RANDOMHOST1}.@value{SECONDDOMAIN} -l @value{RANDOMUSER2}
+@b{Password:}  @i{<- @value{RANDOMUSER2} types his password here}
+@b{Last login: Fri Jun 21 10:36:32 from :0.0
+Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
+        The Regents of the University of California.   All rights reserved.
+
+NetBSD 1.1: Tue May 21 00:31:42 EDT 1996
+
+Welcome to NetBSD!
+shell%}
+@end group
+@end smallexample
+
+@noindent Note that the machine
+@code{@value{RANDOMHOST1}.@value{SECONDDOMAIN}} asked for
+@code{@value{RANDOMUSER2}}'s password.  When he typed it, his password
+was sent over the network unencrypted.  If an intruder were watching
+network traffic at the time, that intruder would know
+@code{@value{RANDOMUSER2}}'s password.
+
+@need 4000
+If, on the other hand, @code{@value{RANDOMUSER1}} wanted to use
+@value{PRODUCT} rlogin to connect to the machine
+@code{@value{RANDOMHOST2}.@value{PRIMARYDOMAIN}}, she could forward a
+copy of her tickets, mark them as not forwardable from the remote host,
+and request an encrypted session as follows:
+
+@smallexample
+@group
+@b{shell%} rlogin @value{RANDOMHOST2}.@value{PRIMARYDOMAIN} -f -x
+@b{This rlogin session is using DES encryption for all data transmissions.
+Last login: Thu Jun 20 16:20:50 from @value{RANDOMHOST1}
+Athena Server (sun4) Version 9.1.11 Tue Jul 30 14:40:08 EDT 2002
+shell%}
+@end group
+@end smallexample
+
+@noindent Note that @code{@value{RANDOMUSER1}}'s machine used Kerberos
+to authenticate her to @code{@value{RANDOMHOST2}.@value{PRIMARYDOMAIN}},
+and logged her in automatically as herself.  She had an encrypted
+session, a copy of her tickets were waiting for her, and she never typed
+her password.
+
+If you forwarded your Kerberos tickets, @code{rlogin} automatically
+destroys them when it exits.  The full set of options to @value{PRODUCT}
+@code{rlogin} are discussed in the Reference section of this manual.
+(@pxref{rlogin Reference})
+
+@node FTP, rsh, rlogin, Kerberos V5 Applications
+@subsection FTP
+
+@need 1000
+The @value{PRODUCT} @code{FTP} program works exactly like the standard
+UNIX FTP program, with the following Kerberos features added:
+
+@table @kbd
+@itemx -k @i{realm}
+requests tickets for the remote host in the specified realm, instead of
+determining the realm itself.
+
+@itemx -f
+requests that your tickets be forwarded to the remote host.  The
+@kbd{-f} argument must be the last argument on the command line.
+
+@itemx protect @i{level}
+(issued at the @code{ftp>} prompt) sets the protection level.  ``Clear''
+is no protection; ``safe'' ensures data integrity by verifying the
+checksum, and ``private'' encrypts the data.  Encryption also ensures
+data integrity.
+@end table
+
+@need 5000
+For example, suppose @code{@value{RANDOMUSER1}} wants to get her
+@code{RMAIL} file from the directory @code{~@value{RANDOMUSER1}/Mail},
+on the host @code{@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}}.  She wants
+to encrypt the file transfer.  The exchange would look like the
+following:
+
+@smallexample
+@group
+@b{shell%} ftp @value{RANDOMHOST1}.@value{PRIMARYDOMAIN}
+Connected to @value{RANDOMHOST1}.@value{PRIMARYDOMAIN}.
+220 @value{RANDOMHOST1}.@value{PRIMARYDOMAIN} FTP server (Version 5.60) ready.
+334 Using authentication type GSSAPI; ADAT must follow
+GSSAPI accepted as authentication type
+GSSAPI authentication succeeded
+200 Data channel protection level set to private.
+Name (@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}:@value{RANDOMUSER1}): 
+232 GSSAPI user @value{RANDOMUSER1}@@@value{PRIMARYREALM} is authorized as @value{RANDOMUSER1}
+230 User @value{RANDOMUSER1} logged in.
+Remote system type is UNIX.
+Using binary mode to transfer files.
+ftp> protect private
+200 Protection level set to Private.
+ftp> cd ~@value{RANDOMUSER1}/MAIL
+250 CWD command successful.
+ftp> get RMAIL
+227 Entering Passive Mode (128,0,0,5,16,49)
+150 Opening BINARY mode data connection for RMAIL (361662 bytes).
+226 Transfer complete.
+361662 bytes received in 2.5 seconds (1.4e+02 Kbytes/s)
+ftp> quit
+@b{shell%}
+@end group
+@end smallexample
+
+The full set of options to @value{PRODUCT} @code{FTP} are discussed
+in the Reference section of this manual.  (@pxref{FTP Reference})
+
+@node rsh, rcp, FTP, Kerberos V5 Applications
+@subsection rsh
+
+The @value{PRODUCT} @code{rsh} program works exactly like the standard
+UNIX rlogin program, with the following Kerberos features added:
+
+@table @kbd
+@itemx -f
+forwards a copy of your tickets to the remote host.
+
+@itemx -F
+forwards a copy of your tickets to the remote host, and marks them
+re-forwardable from the remote host.
+
+@itemx -k @i{realm}
+requests tickets for the remote host in the specified realm, instead of
+determining the realm itself.
+
+@itemx -x
+encrypts the input and output data streams (the command line is not encrypted)
+
+@end table
+
+@need 1800
+For example, if your Kerberos tickets allowed you to run programs on the
+host @* @code{@value{RANDOMHOST2}@@@value{SECONDDOMAIN}} as root, you could
+run the @samp{date} program as follows:
+
+@smallexample
+@group
+@b{shell%} rsh @value{RANDOMHOST2}.@value{SECONDDOMAIN} -l root -x date
+@b{This rsh session is using DES encryption for all data transmissions.
+Tue Jul 30 19:34:21 EDT 2002
+shell%}
+@end group
+@end smallexample
+
+If you forwarded your Kerberos tickets, @code{rsh} automatically
+destroys them when it exits.  The full set of options to @value{PRODUCT}
+@code{rsh} are discussed in the Reference section of this manual.
+(@pxref{rsh Reference})
+
+@node rcp, ksu, rsh, Kerberos V5 Applications
+@subsection rcp
+
+@need 1000
+The @value{PRODUCT} @code{rcp} program works exactly like the standard
+UNIX rcp program, with the following Kerberos features added:
+
+@table @kbd
+@itemx -k @i{realm}
+requests tickets for the remote host in the specified realm, instead of
+determining the realm itself.
+
+@itemx -x
+turns on encryption.
+@end table
+
+
+@need 1500
+For example, if you wanted to copy the file @code{/etc/motd} from the
+host @code{@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}} into the current
+directory, via an encrypted connection, you would simply type:
+
+@smallexample
+@b{shell%} rcp -x @value{RANDOMHOST1}.@value{PRIMARYDOMAIN}:/etc/motd .
+@end smallexample
+
+The @kbd{rcp} program negotiates authentication and encryption
+transparently.  The full set of options to @value{PRODUCT} @code{rcp}
+are discussed in the Reference section of this manual.  (@pxref{rcp
+Reference})
+
+@node ksu,  , rcp, Kerberos V5 Applications
+@subsection ksu
+
+The @value{PRODUCT} @code{ksu} program replaces the standard UNIX su
+program.  @code{ksu} first authenticates you to Kerberos.  Depending on
+the configuration of your system, @code{ksu} may ask for your Kerberos
+password if authentication fails.  @emph{Note that you should never type
+your password if you are remotely logged in using an unencrypted
+connection.}
+
+Once @code{ksu} has authenticated you, if your Kerberos principal
+appears in the target's @code{.k5login} file (@pxref{Granting Access to
+Your Account}) or in the target's @code{.k5users} file (see below), it
+switches your user ID to the target user ID.
+
+@need 2000
+For example, @code{@value{RANDOMUSER2}} has put
+@code{@value{RANDOMUSER1}}'s Kerberos principal in his @code{.k5login}
+file.  If @code{@value{RANDOMUSER1}} uses @code{ksu} to become
+@code{@value{RANDOMUSER2}}, the exchange would look like this.  (To
+differentiate between the two shells, @code{@value{RANDOMUSER1}}'s
+prompt is represented as @code{@value{RANDOMUSER1}%} and
+@code{@value{RANDOMUSER2}}'s prompt is represented as
+@code{@value{RANDOMUSER2}%}.)
+
+@smallexample
+@group
+@b{@value{RANDOMUSER1}%} ksu @value{RANDOMUSER2}
+@b{Account @value{RANDOMUSER2}: authorization for @value{RANDOMUSER1}@@@value{PRIMARYREALM} successful
+Changing uid to @value{RANDOMUSER2} (3382)
+@value{RANDOMUSER2}%}
+@end group
+@end smallexample
+
+@noindent
+Note that the new shell has a copy of @code{@value{RANDOMUSER1}}'s
+tickets.  The ticket filename contains @code{@value{RANDOMUSER2}}'s UID
+with @samp{.1} appended to it:
+
+@smallexample
+@group
+@b{@value{RANDOMUSER2}%} klist
+@b{Ticket cache: /tmp/krb5cc_3382.1
+Default principal: @value{RANDOMUSER1}@@@value{PRIMARYREALM}
+
+Valid starting      Expires             Service principal
+07/31/04 21:53:01  08/01/04 07:52:53  krbtgt/@value{PRIMARYREALM}@@@value{PRIMARYREALM}
+07/31/04 21:53:39  08/01/04 07:52:53  host/@value{RANDOMHOST1}.@value{PRIMARYDOMAIN}@@@value{PRIMARYREALM}
+@value{RANDOMUSER2}%}
+@end group
+@end smallexample
+
+@need 2500
+If @code{@value{RANDOMUSER1}} had not appeared in
+@code{@value{RANDOMUSER2}}'s @code{.k5login} file (and the system was
+configured to ask for a password), the exchange would have looked like
+this (assuming @code{@value{RANDOMUSER2}} has taken appropriate
+precautions in protecting his password):
+
+@smallexample
+@group
+@b{@value{RANDOMUSER1}%} ksu @value{RANDOMUSER2}
+@b{WARNING: Your password may be exposed if you enter it here and are logged 
+         in remotely using an unsecure (non-encrypted) channel. 
+Kerberos password for @value{RANDOMUSER2}@@@value{PRIMARYREALM}:}  @i{<-  @code{@value{RANDOMUSER1}} types the wrong password here.}
+@b{ksu: Password incorrect
+Authentication failed.
+@value{RANDOMUSER1}%}
+@end group
+@end smallexample
+
+Now, suppose @code{@value{RANDOMUSER2}} did not want to give
+@code{@value{RANDOMUSER1}} full access to his account, but wanted to
+give her permission to list his files and use the "more" command to view
+them.  He could create a @code{.k5users} file giving her permission to
+run only those specific commands.
+
+@need 3500
+The @code{.k5users} file is like the @code{.k5login} file, except that
+each principal is optionally followed by a list of commands.  @code{ksu}
+will let those principals execute only the commands listed, using the
+@kbd{-e} option.  @code{@value{RANDOMUSER2}}'s @code{.k5users} file
+might look like the following:
+
+@smallexample
+@group
+@value{RANDOMUSER1}@@@value{PRIMARYREALM}       /bin/ls /usr/bin/more
+@value{ADMINUSER}@@@value{PRIMARYREALM}         /bin/ls
+@value{ADMINUSER}/admin@@@value{PRIMARYREALM}   *
+@value{RANDOMUSER2}@@@value{SECONDREALM}
+@end group
+@end smallexample
+
+@noindent The above @code{.k5users} file would let
+@code{@value{RANDOMUSER1}} run only the commands @code{/bin/ls} and
+@code{/usr/bin/more}.  It would let @code{@value{ADMINUSER}} run only
+the command @code{/bin/ls} if he had regular tickets, but if he had
+tickets for his @code{admin} instance,
+@code{@value{ADMINUSER}/admin@@@value{PRIMARYREALM}}, he would be able
+to execute any command.  The last line gives @code{@value{RANDOMUSER2}}
+in the realm @value{SECONDREALM} permission to execute any command.
+(@i{I.e.}, having only a Kerberos principal on a line is equivalent to
+giving that principal permission to execute @code{*}.)  This is so that
+@value{RANDOMUSER2} can allow himself to execute commands when he logs
+in, using Kerberos, from a machine in the realm @value{SECONDREALM}.
+
+@need 2500
+Then, when @code{@value{RANDOMUSER1}} wanted to list his home directory,
+she would type:
+
+@smallexample
+@group
+@b{@value{RANDOMUSER1}%} ksu @value{RANDOMUSER2} -e ls ~@value{RANDOMUSER2}
+@b{Authenticated @value{RANDOMUSER1}@@@value{PRIMARYREALM}
+Account @value{RANDOMUSER2}: authorization for @value{RANDOMUSER1}@@@value{PRIMARYREALM} for execution of
+               /bin/ls successful
+Changing uid to @value{RANDOMUSER2} (3382)
+Mail            News            Personal        misc            bin
+@value{RANDOMUSER1}%}
+@end group
+@end smallexample
+
+@noindent If @code{@value{RANDOMUSER1}} had tried to give a different
+command to @code{ksu}, it would have prompted for a password as with the
+previous example.
+
+Note that unless the @code{.k5users} file gives the target permission to
+run any command, the user must use @code{ksu} with the @kbd{-e}
+@i{command} option.
+
+@need 1000
+The @code{ksu} options you are most likely to use are:
+
+@table @kbd
+@itemx -n @i{principal}
+specifies which Kerberos principal you want to use for @code{ksu}.
+(@i{e.g.}, the user @code{@value{ADMINUSER}} might want to use his
+@code{admin} instance.  @xref{What is a Ticket?}.)
+
+@itemx -c
+specifies the location of your Kerberos credentials cache (ticket file).
+
+@itemx -k
+tells @code{ksu} not to destroy your Kerberos tickets when @code{ksu} is
+finished.
+
+@itemx -f
+requests forwardable tickets.  (@xref{Obtaining Tickets with kinit}.)  This
+is only applicable if @code{ksu} needs to obtain tickets.
+
+@itemx -l @i{lifetime}
+sets the ticket lifetime.  (@xref{Obtaining Tickets with kinit}.)  This is
+only applicable if @code{ksu} needs to obtain tickets.
+
+@itemx -z
+tells @code{ksu} to copy your Kerberos tickets only if the UID you are
+switching is the same as the Kerberos primary (either yours or the one
+specified by the @kbd{-n} option).
+
+@itemx -Z
+tells @code{ksu} not to copy any Kerberos tickets to the new UID.
+
+@itemx -e @i{command}
+tells @code{ksu} to execute @i{command} and then exit.  See the
+description of the @code{.k5users} file above.
+
+@itemx -a @i{text}
+(at the end of the command line) tells @code{ksu} to pass everything
+after @samp{-a} to the target shell.
+@end table
+
+The full set of options to @value{PRODUCT} @code{ksu} are discussed
+in the Reference section of this manual.  (@pxref{ksu Reference})
+
+@node Kerberos V5 Reference, Kerberos Glossary, Kerberos V5 Tutorial, Top
+@chapter Kerberos V5 Reference
+
+This section will include copies of the manual pages for the
+@value{PRODUCT} client programs.  You can read the manual entry for any
+command by typing @code{man} @i{command}, where @i{command} is the name
+of the command for which you want to read the manual entry.  For
+example, to read the @code{kinit} manual entry, you would type:
+
+@smallexample
+@b{shell%} man kinit
+@end smallexample
+
+Note:  To be able to view the @value{PRODUCT} manual pages on line, you
+may need to add the directory @code{@value{ROOTDIR}/man} to your MANPATH
+environment variable.  (Remember to replace @code{@value{ROOTDIR}} with
+the top-level directory in which @value{PRODUCT} is installed.)  For
+example, if you had the the following line in your @code{.login}
+file@footnote{The MANPATH variable may be specified in a different
+initialization file, depending on your operating system.  Some of the
+files in which you might specify environment variables include
+@code{.login}, @code{.profile}, or @code{.cshrc}.}:
+
+@smallexample
+setenv MANPATH /usr/local/man:/usr/man
+@end smallexample
+
+@noindent
+and the @value{PRODUCT} man pages were in the directory
+@code{/usr/@value{LCPRODUCT}/man}, you would change the line to the following:
+
+@smallexample
+setenv MANPATH /usr/@value{LCPRODUCT}/man:/usr/local/man:/usr/man
+@end smallexample
+
+@ifinfo
+Note to info users:  the manual pages are not available within this info
+tree.  You can read them from emacs with the command:
+
+@smallexample
+M-x manual-entry @emph{command}
+@end smallexample
+@end ifinfo
+
+@page
+
+@menu
+* kinit Reference::             
+* klist Reference::             
+* ksu Reference::               
+* kdestroy Reference::          
+* kpasswd Reference::           
+* telnet Reference::            
+* FTP Reference::               
+* rlogin Reference::            
+* rsh Reference::               
+* rcp Reference::               
+@end menu
+
+@node kinit Reference, klist Reference, Kerberos V5 Reference, Kerberos V5 Reference
+@section kinit Reference
+
+@iftex
+@special{psfile=kinit1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{kinit}}
+@page
+
+@special{psfile=kinit2.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{kinit}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry kinit} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="kinit.html"> kinit manpage</a>
+@end html
+@end ifhtml
+
+@node klist Reference, ksu Reference, kinit Reference, Kerberos V5 Reference
+@section klist Reference
+
+@iftex
+@special{psfile=klist1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{klist}}
+@page
+@end iftex
+
+@iftex
+@special{psfile=klist2.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{klist}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry klist} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="klist.html"> klist manpage</a>
+@end html
+@end ifhtml
+
+@node ksu Reference, kdestroy Reference, klist Reference, Kerberos V5 Reference
+@section ksu Reference
+
+@iftex
+@special{psfile=ksu1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{ksu}}
+@page
+
+@special{psfile=ksu2.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{ksu}}
+@page
+
+@special{psfile=ksu3.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{ksu}}
+@page
+
+@special{psfile=ksu4.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{ksu}}
+@page
+
+@special{psfile=ksu5.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{ksu}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry ksu} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="ksu.html"> ksu manpage</a>
+@end html
+@end ifhtml
+
+@node kdestroy Reference, kpasswd Reference, ksu Reference, Kerberos V5 Reference
+@section kdestroy Reference
+
+@iftex
+@special{psfile=kdestroy1.ps voffset=-700 hoffset=-60}
+@centerline{Reference Manual for @code{kdestroy}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry kdestroy} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="kdestroy.html"> kdestroy manpage</a>
+@end html
+@end ifhtml
+
+@node kpasswd Reference, telnet Reference, kdestroy Reference, Kerberos V5 Reference
+@section kpasswd Reference
+
+@iftex
+@special{psfile=kpasswd1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{kpasswd}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry kpasswd} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="kpasswd.html"> kpasswd manpage</a>
+@end html
+@end ifhtml
+
+@node telnet Reference, FTP Reference, kpasswd Reference, Kerberos V5 Reference
+@section telnet Reference
+
+@iftex
+@special{psfile=telnet1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+
+@special{psfile=telnet2.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+
+@special{psfile=telnet3.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+
+@special{psfile=telnet4.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+
+@special{psfile=telnet5.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+
+@special{psfile=telnet6.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+
+@special{psfile=telnet7.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+
+@special{psfile=telnet8.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+
+@special{psfile=telnet9.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{telnet}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry telnet} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="telnet.html"> telnet manpage</a>
+@end html
+@end ifhtml
+
+@node FTP Reference, rlogin Reference, telnet Reference, Kerberos V5 Reference
+@section FTP Reference
+
+@iftex
+@special{psfile=ftp1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+
+@special{psfile=ftp2.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+
+@special{psfile=ftp3.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+
+@special{psfile=ftp4.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+
+@special{psfile=ftp5.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+
+@special{psfile=ftp6.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+
+@special{psfile=ftp7.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+
+@special{psfile=ftp8.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+
+@special{psfile=ftp9.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{FTP}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry FTP} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="ftp.html"> ftp manpage</a>
+@end html
+@end ifhtml
+
+@node rlogin Reference, rsh Reference, FTP Reference, Kerberos V5 Reference
+@section rlogin Reference
+
+@iftex
+@special{psfile=rlogin1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{rlogin}}
+@page
+
+@special{psfile=rlogin2.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{rlogin}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry rlogin} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="rlogin.html"> rlogin manpage</a>
+@end html
+@end ifhtml
+
+@node rsh Reference, rcp Reference, rlogin Reference, Kerberos V5 Reference
+@section rsh Reference
+
+@iftex
+@special{psfile=rsh1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{rsh}}
+@page
+
+@special{psfile=rsh2.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{rsh}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry rsh} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="rsh.html"> rsh manpage</a>
+@end html
+@end ifhtml
+
+@node rcp Reference, , rsh Reference, Kerberos V5 Reference
+@section rcp Reference
+
+@iftex
+@special{psfile=rcp1.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{rcp}}
+@page
+@end iftex
+
+@iftex
+@special{psfile=rcp2.ps voffset=-700 hoffset=-40}
+@centerline{Reference Manual for @code{rcp}}
+@page
+@end iftex
+
+@ifinfo
+Type @kbd{M-x manual-entry rcp} to read this manual page.
+@end ifinfo
+
+@ifhtml
+@html
+<a href="rcp.html"> rcp manpage</a>
+@end html
+@end ifhtml
+
+@node Kerberos Glossary,  , Kerberos V5 Reference, Top
+@appendix Kerberos Glossary
+
+@include glossary.texinfo
+
+@contents
+@bye
diff --git a/mechglue/src/.Sanitize b/mechglue/src/.Sanitize
new file mode 100644
index 000000000..dc2dfc32f
--- /dev/null
+++ b/mechglue/src/.Sanitize
@@ -0,0 +1,65 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+Makefile
+Makefile.in
+acconfig.h
+aclocal.m4
+admin
+appl
+clients
+config
+config-files
+configure
+configure.in
+include
+kadmin
+kadmin.v4
+kdc
+krb524
+lib
+patchlevel.h
+prototype
+slave
+tests
+util
+wconfig.c
+windows
+
+Things-to-lose:
+
+kadmin.new
+autotools
+isode
+TODO
+BADSYMS
+mac
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/.rconf b/mechglue/src/.rconf
new file mode 100644
index 000000000..aedd20d19
--- /dev/null
+++ b/mechglue/src/.rconf
@@ -0,0 +1,48 @@
+; To build a symlink tree, do:
+;
+; /mit/synctree/synctree -s /mit/krb5/src -d /mit/krb5/build/@sys
+
+map * $
+
+copy *;d
+link *;r
+link include/stdc-incl
+link include/isode-6.8
+;link config
+copy include/isode
+copy include/com_err.h
+copy *Makefile
+ignore rconf
+ignore *~
+ignore *CVS
+ignore *RCS
+ignore *Makefile.bak
+ignore *,v
+ignore *.o
+ignore *.a
+ignore include/isode-5.0
+ignore prototype
+ignore lib/des.v4
+ignore *.rconf
+ignore *.orig
+ignore *.rej
+ignore .saberinit
+ignore TODO
+ignore man
+ignore *TAGS
+ignore *tags
+ignore Link_src.sh
+ignore cat
+ignore RCSFILES
+ignore *.new
+ignore *.old
+ignore CFILES
+ignore mdebug
+ignore API.CHANGES
+ignore *fookrb5
+ignore MAKEFILES
+ignore STDC-grep
+ignore IMAKEFILES
+ignore dtree.out
+ignore RCS.locked
+copy kadmin.old;d
diff --git a/mechglue/src/BADSYMS b/mechglue/src/BADSYMS
new file mode 100644
index 000000000..882bd7b04
--- /dev/null
+++ b/mechglue/src/BADSYMS
@@ -0,0 +1,282 @@
+./appl/bsd/configure.in: const HAVE_KRB_GET_ERR_TEXT HAVE_KRB_SAVE_CREDENTIALS HAVE_REGCOMP HAVE_SETLUID HAVE_SETOWN HAVE_SETUTENT HAVE_SETUTXENT HAVE_SHADOW HAVE_STDARG_H HAVE_STREAMS HAVE_UPDWTMP HAVE_UPDWTMPX HAVE_VARARGS_H HAVE_VFORK_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM krb5_sigtype mode_t NEED_SETENV NO_UT_EXIT NO_UT_HOST NO_UT_PID NO_UT_TYPE pid_t POSIX_SETJMP POSIX_SIGNALS POSIX_SIGTYPE POSIX_TERMIOS SETPAG SETPGRP_TWOARG STDC_HEADERS USE_DIRENT_H vfork WAIT_USES_INT HAVE_COMPILE HAVE_GETDTABLESIZE HAVE_GETENV HAVE_GETTOSBYNAME HAVE_INET_ATON HAVE_INITGROUPS HAVE_ISATTY HAVE_KILLPG HAVE_KRB_GET_ERR_TEXT HAVE_KRB_SAVE_CREDENTIALS HAVE_PTSNAME HAVE_RMUFILE HAVE_SETLOGIN HAVE_SETPGID HAVE_SETPRIORITY HAVE_SETRESUID HAVE_SETREUID HAVE_SETSID HAVE_STEP HAVE_STRSAVE HAVE_TCGETPGRP HAVE_TCSETPGRP HAVE_UTIMES HAVE_WAITPID HAVE_ARPA_NAMESER_H HAVE_KRB4_PROTO_H HAVE_LASTLOG_H HAVE_PATHS_H HAVE_STDLIB_H HAVE_STRING_H HAVE_SYS_FILIO_H HAVE_SYS_IOCTL_COMPAT_H HAVE_SYS_LABEL_H HAVE_SYS_PTYVAR_H HAVE_SYS_SELECT_H HAVE_SYS_SOCKIO_H HAVE_SYS_TIME_H HAVE_SYS_TTY_H HAVE_TTYENT_H HAVE_UNISTD_H HAVE_UTMP_H HAVE_LIBCRYPT HAVE_LIBNSL HAVE_LIBSOCKET HAVE_LIBUTIL
+./appl/bsd/defines.h: KRB5_KRB4_COMPAT SKIP_V4_PROTO
+./appl/bsd/fieldbits.h: KRB5_FIELDBITS__
+./appl/bsd/forward.c: KERBEROS KRB5
+./appl/bsd/getdtablesize.c: _SC_OPEN_MAX
+./appl/bsd/kcmd.c: KRB5_KRB4_COMPAT MAXPATHLEN min roundup sigmask sun SYSV tek tex _TYPES_ ultrix
+./appl/bsd/krcp.c: __cplusplus hpux __hpux KERBEROS KRB5_ATHENA_COMPAT KRB5_KRB4_COMPAT lint NOFCHMOD _TYPES_ UCB_RCP unicos61
+./appl/bsd/krlogin.c: CNUL CRAY hpux __hpux IEXTEN KERBEROS KRB5_ATHENA_COMPAT KRB5_KRB4_COMPAT lint LLITOUT LPASS8 NO_WINSIZE ONOCR _POSIX_VDISABLE __SCO__ sgi sigmask SIGWINCH SYSV TABDLY TIOCFLUSH TIOCGLTC TIOCGWINSZ TIOCPKT_NOSTOP TIOCPKT_WINDOW UCB_RLOGIN ultrix USE_TERMIO VDSUSP VLNEXT
+./appl/bsd/krlogind.c: _AIX ALWAYS_V5_KUSEROK CRYPT DO_NOT_USE_K_LOGIN HEIMDAL_FRIENDLY hpux __hpux i386 ibm032 KERBEROS KRB5_KRB4_COMPAT KRB_SENDAUTH_VLEN lint LOG_ALL_LOGINS LOG_AUTH LOGIN_PROGRAM LOG_NDELAY LOG_OTHER_USERS LOG_REMOTE_REALM MAXDNAME NEED_DAEMON_PROTO NO_WINSIZE roundup __SCO__ solaris20 STDERR_FILENO SunOS __svr4__ sysvimp TIOCFLUSH TIOCPKT TIOCPKT_NOSTOP TIOCPKT_WINDOW TIOCSWINSZ ultrix USE_LOGIN_F UT_NAMESIZE vax
+./appl/bsd/krsh.c: ATHENA KERBEROS KRB5_ATHENA_COMPAT KRB5_KRB4_COMPAT lint RLOGIN_PROGRAM sgi UCB_RLOGIN UCB_RSH
+./appl/bsd/krshd.c: ALWAYS_V5_KUSEROK BSD __cplusplus CRAY CRAY2 DEBUG HEIMDAL_FRIENDLY IP_SECURITY IP_TOS KERBEROS KRB5_KRB4_COMPAT KRB_SENDAUTH_VLEN lint LOG_ALL_LOGINS LOG_CMD LOG_DAEMON LOG_ODELAY LOG_OTHER_USERS LOG_REMOTE_REALM MAX MAXDNAME MIN NCARGS NO_UDB _PATH_NOLOGIN __SCO__ sgi TOS_WARN ULTRIX unicos61
+./appl/bsd/login.c: _AIX BIND_HACK BSD CDISCARD CNUL CSTATUS CSUSP CSWTCH ECHOCTL ECHOKE HAVE_ETC_ENVIRONMENT HAVE_ETC_TIMEZONE __hpux _IBMR2 KRB4 KRB4_CONVERT KRB4_GET_TICKETS KRB4_KLOGIN KRB5_GET_TICKETS KRB5_KRB4_COMPAT KRB_RUN_AKLOG lint linux __linux__ LOG_ODELAY NO_INIT_CC NO_MAILCHECK NO_MOTD NTTYDISC OLD_PASSWD O_NDELAY O_NONBLOCK OQUOTA _PATH_BSHELL _PATH_LASTLOG _PATH_MAILDIR _PATH_NOLOGIN QUOTAWARN sgi SIGSYS __STDC__ __SVR4 SYSLOG42 TAB3 TIOCHPCL TIOCLSET TIOCNOTTY TIOCNXCL TIOCSETD UT_HOSTSIZE UT_NAMESIZE VDISCARD VDISCRD VDSUSP VEOL2 VLNEXT volatile VREPRINT VSTATUS VSUSP VWERASE VWERSE
+./appl/bsd/loginpaths.h: __386BSD__ __alpha __DGUX hpux __hpux _IBMR2 linux LPATH __m88k__ MIPSEB __NetBSD__ NeXT __osf__ _PATH_DEFPATH __pyrsoft RPATH __SCO__ sgi sun __svr4__ __SVR4 __ultrix
+./appl/bsd/rpaths.h: RPROGS_IN_USR_BIN RPROGS_IN_USR_BSD RPROGS_IN_USR_UCB RSH_IS_RCMD RSH_IS_REMSH
+./appl/bsd/v4rcp.c: ATHENA _AUX_SOURCE __cplusplus KERBEROS lint NEED_SYS_FCNTL_H NOENCRYPTION NO_FCHMOD NOSTBLKSIZE NOVFORK roundup __SCO__
+./appl/configure.in: BROKEN_STREAMS_SOCKETS const HAVE_REGCOMP KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_COMPILE HAVE_STEP HAVE_STDLIB_H HAVE_STRING_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./appl/gssftp/configure.in: const HAVE_REGCOMP HAVE_SETLUID HAVE_SETUTENT HAVE_SETUTXENT HAVE_SHADOW HAVE_STDARG_H HAVE_SYS_ERRLIST HAVE_UPDWTMP HAVE_UPDWTMPX HAVE_VARARGS_H HAVE_VFORK_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM krb5_sigtype NEED_SETENV NEED_SYS_ERRLIST NO_UT_EXIT NO_UT_HOST NO_UT_PID NO_UT_TYPE pid_t POSIX_SETJMP POSIX_SIGNALS POSIX_SIGTYPE POSIX_TERMIOS STDC_HEADERS SYS_ERRLIST_DECLARED USE_SIGPROCMASK vfork WAIT_USES_INT HAVE_COMPILE HAVE_GETCWD HAVE_GETDTABLESIZE HAVE_GETENV HAVE_GETUSERSHELL HAVE_SETEUID HAVE_SETRESUID HAVE_SETREUID HAVE_STEP HAVE_STRERROR HAVE_PATHS_H HAVE_STDLIB_H HAVE_STRING_H HAVE_SYS_SELECT_H HAVE_SYS_SOCKIO_H HAVE_UNISTD_H HAVE_LIBCRYPT HAVE_LIBNSL HAVE_LIBSOCKET HAVE_LIBUTIL
+./appl/telnet/configure.in: const KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_LIBNSL HAVE_LIBSOCKET
+./appl/telnet/libtelnet/configure.in: const KRB4 KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM NEED_SETENV HAVE_CGETENT HAVE_GETENV HAVE_GETOPT HAVE_GETTOSBYNAME HAVE_HERROR HAVE_PARSETOS HAVE_SETENV HAVE_SETSID HAVE_STRCASECMP HAVE_STRDUP HAVE_STRERROR HAVE_STRFTIME HAVE_UNSETENV HAVE_STDLIB_H HAVE_STRING_H HAVE_LIBNSL HAVE_LIBSOCKET
+./appl/telnet/libtelnet/auth.c: AUTHENTICATION ENCRYPTION KANNAN KRB5 SPX __STDC__
+./appl/telnet/libtelnet/auth.h: __AUTH__ P __STDC__
+./appl/telnet/libtelnet/auth-proto.h: AUTHENTICATION KRB5 P __STDC__
+./appl/telnet/libtelnet/enc_des.c: AUTHENTICATION DES_ENCRYPTION ENCRYPTION __STDC__
+./appl/telnet/libtelnet/enc-proto.h: ENCRYPTION P __STDC__ TELENTD
+./appl/telnet/libtelnet/encrypt.c: DES_ENCRYPTION ENCRYPTION notdef __STDC__
+./appl/telnet/libtelnet/encrypt.h: ENCRYPTION __ENCRYPTION__ P __STDC__
+./appl/telnet/libtelnet/forward.c: KERBEROS KRB5
+./appl/telnet/libtelnet/getent.c: SOLARIS
+./appl/telnet/libtelnet/getopt.c: __STDC__
+./appl/telnet/libtelnet/gettytab.h: SOLARIS
+./appl/telnet/libtelnet/herror.c: sun
+./appl/telnet/libtelnet/kerberos5.c: ENCRYPTION FORWARD KRB5
+./appl/telnet/libtelnet/kerberos.c: ENCRYPTION notdef __STDC__
+./appl/telnet/libtelnet/key-proto.h: __KEY_PROTO__ P __STDC__
+./appl/telnet/libtelnet/mem.c: BZERO __STDC__ UINT_MAX
+./appl/telnet/libtelnet/misc.c: AUTHENTICATION ENCRYPTION
+./appl/telnet/libtelnet/misc.h: P __STDC__
+./appl/telnet/libtelnet/misc-proto.h: __MISC_PROTO__ NEED_PARSETOS P __STDC__
+./appl/telnet/libtelnet/setenv.c: __STDC__
+./appl/telnet/libtelnet/setsid.c: convex
+./appl/telnet/libtelnet/spx.c: ENCRYPTION notdef SPX __STDC__
+./appl/telnet/libtelnet/strcasecmp.c: __STDC__
+./appl/telnet/libtelnet/strdup.c: __STDC__
+./appl/telnet/libtelnet/strftime.c: notdef __P __STDC__
+./appl/telnet/telnet/configure.in: const HAVE_ HAVE_REGCOMP HAVE_SA_LEN HAVE_STDARG_H HAVE_VARARGS_H HAVE_VFORK_H KRB4 KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM KRB5_USE_INET6 NO_CC_T pid_t POSIX_SIGNALS STDC_HEADERS SYSV_TERMIO TERMCAP USE_TERMIO vfork HAVE_COMPILE HAVE_GETADDRINFO HAVE_GETNAMEINFO HAVE_GETTOSBYNAME HAVE_INET_NTOP HAVE_INET_PTON HAVE_SETUPTERM HAVE_STEP HAVE_ARPA_INET_H HAVE_ARPA_NAMESER_H HAVE_CURSES_H HAVE_MACSOCK_H HAVE_NETDB_H HAVE_NETINET_IN_H HAVE_STDLIB_H HAVE_STRING_H HAVE_SYS_FILIO_H HAVE_SYS_SELECT_H HAVE_SYS_SOCKET_H HAVE_SYS_TYPES_H HAVE_TERM_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./appl/telnet/telnet/authenc.c: AUTHENTICATION ENCRYPTION
+./appl/telnet/telnet/commands.c: AF_INET6 AUTHENTICATION CRAY ENCRYPTION ENV_HACK F_GETOWN FORWARD h_addr hp300 INADDR_NONE IP_OPTIONS IPPROTO_IP IP_TOS KLUDGELINEMODE MAXDNAME NEED_HERROR_PROTO NOT43 notdef OLD_ENVIRON SIGINFO SIGTSTP __STDC__ sysV88 tahoe TN3270 ultrix unix vax
+./appl/telnet/telnet/defines.h: TN3270
+./appl/telnet/telnet/externs.h: BSD CRAY ENCRYPTION KLUDGELINEMODE NO_BSD_SETJMP P _POSIX_VDISABLE __STDC__ sun __svr4__ TN3270 VDISABLE VDISCARD VEOL VEOL2 VFLUSHO VINTR VLNEXT VREPRINT VSTART VSTATUS VSTOP VSUSP VWERASE
+./appl/telnet/telnet/fdset.h: FD_SETSIZE
+./appl/telnet/telnet/main.c: AUTHENTICATION CRAY ENCRYPTION FORWARD IPPROTO_IP IP_TOS KRB5 lint NEED_PARSETOS_PROTO __STDC__ TN3270 unix
+./appl/telnet/telnet/network.c: ENCRYPTION
+./appl/telnet/telnet/ring.c: ENCRYPTION MIN NO_STRING_H notdef size_t
+./appl/telnet/telnet/ring.h: ENCRYPTION LINT_ARGS notdef P __STDC__
+./appl/telnet/telnet/sys_bsd.c: B19200 B38400 CIBAUD CRAY ECHOCTL KLUDGELINEMODE LNOFLSH NOKERNINFO NOT43 notdef OXTABS PUTCHAR SA_INTERRUPT SA_NOMASK SIGINFO SIGTSTP SIGWINCH SO_OOBINLINE sysV88 TABDLY TCSANOW TCSETA TCSETS TIOCFLUSH TIOCGWINSZ TN3270 VDISCARD VDSUSP VEOL2 VLNEXT VREPRINT VSTART VSTATUS VSTOP VSUSP VWERASE
+./appl/telnet/telnet/telnet.c: AUTHENTICATION ENCRYPTION ENV_HACK KLUDGELINEMODE notdef OLD_ENVIRON TN3270 unix
+./appl/telnet/telnet/terminal.c: ENCRYPTION KLUDGELINEMODE VDISCARD VEOL VEOL2 VLNEXT VREPRINT VSTART VSTATUS VSTOP VSUSP VWERASE
+./appl/telnet/telnet/tn3270.c: NOT43 PUTCHAR sun TN3270 unix
+./appl/telnet/telnet/utilities.c: AUTHENTICATION ENCRYPTION ENV_HACK NOT43 OLD_ENVIRON TN3270 unix
+./appl/telnet/telnetd/configure.in: const HAVE_ HAVE_REGCOMP HAVE_SA_LEN KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM KRB5_USE_INET6 NO_CC_T SETPGRP_TWOARG STREAMSPTY SYSV_TERMIO TERMCAP TIME_WITH_SYS_TIME USE_TERMIO HAVE_COMPILE HAVE_GETADDRINFO HAVE_GETNAMEINFO HAVE_GETTOSBYNAME HAVE_INET_NTOP HAVE_INET_PTON HAVE_STEP HAVE_VSNPRINTF HAVE_ARPA_NAMESER_H HAVE_MACSOCK_H HAVE_MEMORY_H HAVE_NETDB_H HAVE_NETINET_IN_H HAVE_SAC_H HAVE_STRING_H HAVE_SYS_FILIO_H HAVE_SYS_PTYVAR_H HAVE_SYS_SOCKET_H HAVE_SYS_STREAM_H HAVE_SYS_TIME_H HAVE_SYS_TTY_H HAVE_SYS_TYPES_H HAVE_SYS_UTSNAME_H HAVE_UTMP_H HAVE_LIBNSL HAVE_LIBSOCKET HAVE_LIBUTIL
+./appl/telnet/telnetd/authenc.c: AUTHENTICATION ENCRYPTION
+./appl/telnet/telnetd/defs.h: __alpha BSD CRAY CRAY1 DIAGNOSTICS ENCRYPTION FD_SET FD_ZERO __hpux LINEMODE LOG_DAEMON LOG_ODELAY NO_SETSID P _POSIX_VDISABLE PRINTOPTIONS __STDC__ TCSETCTTY TIOCSCTTY UNICOS5 UNICOS50 VDISABLE
+./appl/telnet/telnetd/ext.h: AUTHENTICATION BFTPDAEMON convex CRAY2 DIAGNOSTICS ENCRYPTION KLUDGELINEMODE LINEMODE NEED_SETENV_PROTO NEED_UNSETENV_PROTO SecurID UNICOS5
+./appl/telnet/telnetd/pathnames.h: BFTPDAEMON _PATH_LOGIN
+./appl/telnet/telnetd/slc.c: LINEMODE
+./appl/telnet/telnetd/state.c: AUTHENTICATION CRAY2 ENCRYPTION ENV_HACK KLUDGELINEMODE LINEMODE TELOPT_ENVIRON TELOPT_NEW_ENVIRON UNICOS5
+./appl/telnet/telnetd/sys_term.c: _AIX AUTHENTICATION BFTPDAEMON CIBAUD convex CRAY CRAY2 DECCTQ ECHOCTL EXTPROC __hpux KRB5 LINEMODE LOGIN_ARGS LOGIN_CAP_F LOGIN_HOST LOGIN_PROGRAM LOGIN_R NEWINIT NO_LOGIN_F NO_LOGIN_H NO_LOGIN_P O_NOCTTY OXTABS _PATH_UTMP _PATH_WTMP _SC_CRAY_NPTY _SC_CRAY_SECURE_SYS SCM_SECURITY SecurID SOLARIS TABDLY TCSANOW TCSETA TCSETS TCTLECH t_erase TIOCEXT TIOCGSTATE TIOCGWINSZ TIOCPKT_IOCTL UNICOS5 VDISCARD VEOL VEOL2 VFLUSHO VLNEXT VREPRINT VSTART VSTATUS VSTOP VSUSP VWERASE
+./appl/telnet/telnetd/telnetd.c: _AIX AUTHENTICATION BFTPDAEMON convex CRAY CRAY2 DIAGNOSTICS EAGAIN ENCRYPTION IPPROTO_IP IP_TOS KLUDGELINEMODE KRB5 LINEMODE lint MAXDNAME NEWINIT NO_URGENT _SC_CRAY_SECURE_SYS SCM_SECURITY SecurID SIGINFO SIGTSTP SIGTTOU SO_OOBINLINE SO_SEC_MULTI TCSIG TIOCNOTTY TIOCSCTTY TIOCSIG UNICOS5 UNICOS50
+./appl/telnet/telnetd/telnetd.h: DIAGNOSTICS
+./appl/telnet/telnetd/telnetd-ktd.c: AUTHENTICATION BFTPDAEMON convex CRAY CRAY2 DIAGNOSTICS EAGAIN ENCRYPTION IPPROTO_IP IP_TOS KLUDGELINEMODE LINEMODE lint MAXHOSTNAMELEN NEWINIT NO_URGENT _SC_CRAY_SECURE_SYS SecurID SIGINFO SIGTSTP SIGTTOU SO_OOBINLINE TCSIG TIOCNOTTY TIOCSCTTY TIOCSIG UNICOS5 UNICOS50
+./appl/telnet/telnetd/termios-tn.c: _AIX TCSETS
+./appl/telnet/telnetd/termstat.c: CRAY2 ENCRYPTION KLUDGELINEMODE LINEMODE TIOCSWINSZ UNICOS5
+./appl/telnet/telnetd/utility.c: AUTHENTICATION DIAGNOSTICS ENCRYPTION
+./clients/configure.in: const HAVE_REGCOMP HAVE_SETLUID HAVE_STDARG_H HAVE_VARARGS_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_COMPILE HAVE_GETENV HAVE_GETUSERSHELL HAVE_INET_NTOP HAVE_LSTAT HAVE_SETENV HAVE_STEP HAVE_UNSETENV HAVE_ARPA_INET_H HAVE_PWD_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./configure.in: const HAVE_REGCOMP HAVE_TCL_H HAVE_TCL_TCL_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_COMPILE HAVE_MEMMOVE HAVE_STEP HAVE_LIBNSL HAVE_LIBSOCKET
+./wconfig.c: _WIN32
+./include/configure.in: ANSI_STDIO const gid_t HAVE_ HAVE_SA_LEN HAVE_SOCKLEN_T HAVE_STDARG_H HAVE_VARARGS_H KRB5_ATHENA_COMPAT KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM KRB5_KRB4_COMPAT krb5_sigtype KRB5_USE_INET6 NO_YYLINENO POSIX_SIGTYPE POSIX_TERMIOS STDC_HEADERS time_t TIME_WITH_SYS_TIME uid_t USE_DIRENT_H HAVE_BCOPY HAVE_GETADDRINFO HAVE_GETNAMEINFO HAVE_INET_ATON HAVE_INET_NTOA HAVE_INET_NTOP HAVE_INET_PTON HAVE_LABS HAVE_MEMMOVE HAVE_SETVBUF HAVE_STRDUP HAVE_MACSOCK_H HAVE_NETDB_H HAVE_NETINET_IN_H HAVE_STDDEF_H HAVE_STDLIB_H HAVE_STRING_H HAVE_SYS_FILE_H HAVE_SYS_PARAM_H HAVE_SYS_SOCKET_H HAVE_SYS_STAT_H HAVE_SYS_TIME_H HAVE_SYS_TYPES_H HAVE_UNISTD_H HAVE_XOM_H HAVE_LIBNSL HAVE_LIBSOCKET
+./include/bsdlib.h: __BSDLIB__ FILE __STDC__ _WINDOWS
+./include/bstring.h: __BSTRING__ __STDC__ _WINDOWS
+./include/fake-addrinfo.c: NETDB_INTERNAL
+./include/fake-addrinfo.h: AI_NUMERICHOST BROKEN_GETADDRINFO FAI_DEFINED FAI_PREFIX NI_MAXHOST NI_MAXSERV
+./include/fake-stdlib.h: abort abs FD_SETSIZE __GNUC__ hpux ibm032 memcpy memset mips __mips__ __STDC__ SYSTEM_FIVE ultrix __ultrix__ vax __vax__ _WINDOWS
+./include/k5-int.h: applec __CFM68K__ KRB5_ASN1__ KRB5_AUTOCONF__ KRB5_CALLCONV KRB5_CONFIG__ KRB5_ERRORS__ KRB5_EXT_PROTO__ _KRB5_INT_H KRB5_LIBOS__ KRB5_LIBOS_PROTO__ KRB5_OLD_CRYPTO KRB5_PREAUTH__ KRB5_SYSINCL__ KRB5_SYSTYPES__ macintosh MIT_DES_KEYSIZE __MWERKS__ NEED_SOCKETS O_BINARY _SIZET SOCK_DGRAM THINK_C __USING_STATIC_LIBS__ _WIN32
+./include/k5-util.h: KRB_DEFS SOCK_DGRAM
+./include/port-sockets.h: _PORT_SOCKET_H _WIN32
+./include/socket-utils.h: __GNUC__ SOCKET_UTILS_H socklen
+./include/syslog.h: KERNEL va_start
+./include/win-mac.h: CYGNUS KRB4 KRB5_CALLCONV KRB5_SYSTYPES__ _KRB5_WIN_MAC_H macintosh MAXPATHLEN __MWERKS__ NEED_LOWLEVEL_IO NEED_SYSERROR RES_ONLY _WIN32
+./kadmin/configure.in: const HAVE_REGCOMP HAVE_TCL_H HAVE_TCL_TCL_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM NDBM_PW_CHECK POSIX_SETJMP POSIX_SIGNALS TIME_WITH_SYS_TIME WAIT_USES_INT HAVE_COMPILE HAVE_FTIME HAVE_GETCWD HAVE_MEMMOVE HAVE_STEP HAVE_STRFTIME HAVE_STRSTR HAVE_TIMEZONE HAVE_VSPRINTF HAVE_WAITPID HAVE_ALLOCA_H HAVE_ARPA_INET_H HAVE_KDC_H HAVE_KRB_DB_H HAVE_MEMORY_H HAVE_REGEX_H HAVE_STDLIB_H HAVE_SYS_SELECT_H HAVE_SYS_TIME_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./kdc/configure.in: ATHENA_DES3_KLUDGE const HAVE_ HAVE_REGCOMP HAVE_SA_LEN KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM KRB5_USE_INET6 KRBCONF_KDC_MODIFIES_KDB KRBCONF_VAGUE_ERRORS NOCACHE POSIX_SIGNALS USE_RCACHE HAVE_CLOSELOG HAVE_COMPILE HAVE_GETADDRINFO HAVE_GETNAMEINFO HAVE_INET_NTOP HAVE_INET_PTON HAVE_OPENLOG HAVE_STEP HAVE_STRFTIME HAVE_SYSLOG HAVE_VSPRINTF HAVE_IFADDRS_H HAVE_MACSOCK_H HAVE_NETDB_H HAVE_NETINET_IN_H HAVE_STDARG_H HAVE_SYSLOG_H HAVE_SYS_SELECT_H HAVE_SYS_SOCKET_H HAVE_SYS_SOCKIO_H HAVE_SYS_TYPES_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./kdc/dispatch.c: KRB5_KRB4_COMPAT
+./kdc/do_as_req.c: hpux
+./kdc/do_tgs_req.c: hpux
+./kdc/extern.h: __KRB5_KDC_EXTERN__
+./kdc/kdc_preauth.c: DEBUG KRB5INT_DES_TYPES_DEFINED
+./kdc/kdc_util.h: __KRB5_KDC_UTIL__ KRB5_KRB4_COMPAT min
+./kdc/kerberos_v4.c: BACKWARD_COMPAT KRB5_KRB4_COMPAT NEED_SWAB_PROTO NOENCRYPTION notdef notdef_DIE TIME_WITH_SYS_TIME
+./kdc/main.c: KRB5_KRB4_COMPAT NEED_DAEMON_PROTO POSIX_SIGTYPE
+./kdc/network.c: AF_INET6 ARPHRD_ETHER DEBUG IFF_LOOPBACK max SIOCGSIZIFCONF TEST
+./kdc/policy.h: __KRB5_KDC_POLICY__
+./krb524/configure.in: const HAVE_REGCOMP KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM RETSIGTYPE HAVE_COMPILE HAVE_STEP HAVE_SYS_SELECT_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./krb524/cnv_tkt_skey.c: NOENCRYPTION _WIN32
+./krb524/conv_creds.c: _WIN32
+./krb524/encode.c: _WIN32
+./krb524/k524init.c: _WIN32
+./krb524/krb524d.c: NEED_DAEMON_PROTO
+./krb524/krb524.h: __KRB524_H__
+./krb524/libinit.c: _WIN32
+./krb524/misc.c: _WIN32
+./krb524/sendmsg.c: _AIX _WIN32
+./krb524/test.c: _WIN32
+./lib/crypto/configure.in: ATHENA_DES3_KLUDGE const HAVE_REGCOMP KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_COMPILE HAVE_STEP HAVE_MEMORY_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/crypto/crypto_libinit.h: KRB5_LIBINIT_H
+./lib/des425/configure.in: const HAVE_PRAGMA_WEAK HAVE_REGCOMP KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_COMPILE HAVE_STEP HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/des425/quad_cksum.c: DEBUG HAVE_ERRNO
+./lib/des425/read_passwd.c: ECHO_PASSWORD _WIN32
+./lib/des425/string2key.c: DEBUG
+./lib/des425/str_to_key.c: DEBUG
+./lib/des425/unix_time.c: _WIN32
+./lib/gssapi/configure.in: const KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM size_t STDC_HEADERS HAVE_LIMITS_H HAVE_MEMORY_H HAVE_STDLIB_H HAVE_SYS_TYPES_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/gssapi/gss_libinit.h: KRB5_LIBINIT_H
+./lib/kadm5/configure.in: const HAVE_REGCOMP HAVE_TCL_H HAVE_TCL_TCL_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_CLOSELOG HAVE_COMPILE HAVE_OPENLOG HAVE_RE_COMP HAVE_RE_EXEC HAVE_REGEXEC HAVE_SRAND HAVE_SRAND48 HAVE_SRANDOM HAVE_STEP HAVE_STRFTIME HAVE_SYSLOG HAVE_VSPRINTF HAVE_MEMORY_H HAVE_SYSLOG_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/kadm5/adb.h: __ADB_H__
+./lib/kadm5/admin.h: __KADM5_ADMIN_H__ USE_KADM5_API_VERSION
+./lib/kadm5/admin_internal.h: __KADM5_ADMIN_INTERNAL_H__
+./lib/kadm5/chpass_util.c: ZEROPASSWD
+./lib/kadm5/get_admhst.c: lint
+./lib/kadm5/kadm_rpc.h: __KADM_RPC_H__
+./lib/kadm5/logger.c: HAVE_STDARG_H LOG_ALERT LOG_AUTH LOG_AUTHPRIV LOG_CRIT LOG_CRON LOG_DAEMON LOG_DEBUG LOG_EMERG LOG_ERR LOG_FTP LOG_INFO LOG_KERN LOG_LOCAL0 LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_LPR LOG_MAIL LOG_NEWS LOG_NOTICE LOG_USER LOG_UUCP LOG_WARNING MAXHOSTNAMELEN VERBOSE_LOGS
+./lib/kadm5/misc_free.c: __CODECENTER__ lint
+./lib/kadm5/server_internal.h: __KADM5_SERVER_INTERNAL_H__
+./lib/kdb/configure.in: const HAVE_REGCOMP KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM mode_t off_t STDC_HEADERS HAVE_COMPILE HAVE_SRAND HAVE_SRAND48 HAVE_SRANDOM HAVE_STEP HAVE_UMASK HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/kdb/fetch_mkey.c: ANSI_STDIO min
+./lib/kdb/kdb_db2.c: EFTYPE NOFSYNC OLD_COMPAT_VERSION_1
+./lib/kdb/kdb_db2.h: KRB5_KDB_DB2_H
+./lib/kdb/kdb_dbm.c: DEBUG NOFSYNC OLD_COMPAT_VERSION_1
+./lib/kdb/store_mkey.c: ANSI_STDIO MAXPATHLEN min
+./lib/kdb/t_kdb.c: BERK_DB_DBM dbm_clearerr dbm_dirfno dbm_error dbm_pagfno HAVE_DBM_CLEARERR HAVE_DBM_ERROR MISSING_CLEARERR_PROTO MISSING_ERROR_PROTO NDBM ODBM
+./lib/krb4/configure.in: BITS16 BITS32 const gid_t KRB4_USE_KEYTAB KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM LSBFIRST mode_t MSBFIRST STDC_HEADERS uid_t HAVE_SETEUID HAVE_SETRESUID HAVE_SETREUID HAVE_STRDUP HAVE_STDLIB_H HAVE_SYS_SELECT_H HAVE_TIME_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/krb4/ad_print.c: NOENCRYPTION _WINDOWS
+./lib/krb4/cr_ciph.c: NOENCRYPTION
+./lib/krb4/cr_death_pkt.c: DEBUG
+./lib/krb4/cr_tkt.c: NOENCRYPTION
+./lib/krb4/decomp_tkt.c: KRB_CRYPT_DEBUG NOENCRYPTION notdef
+./lib/krb4/dest_tkt.c: NO_FSYNC O_SYNC TKT_SHMEM
+./lib/krb4/err_txt.c: MULTIDIMENSIONAL_ERR_TXT
+./lib/krb4/g_ad_tkt.c: NOENCRYPTION
+./lib/krb4/g_cnffile.c: ATHENA_CONF_FALLBACK
+./lib/krb4/gethostname.c: GETHOSTNAME
+./lib/krb4/g_in_tkt.c: DECRYPT_TKT_TYPE_DEFINED KEY_PROC_TYPE_DEFINED NOENCRYPTION
+./lib/krb4/g_phost.c: DO_REVERSE_RESOLVE
+./lib/krb4/g_pw_in_tkt.c: BSDUNIX CROSSMSDOS INTK_PW_NULL macintosh NOENCRYPTION NULL __svr4__ __SVR4 _WINDOWS
+./lib/krb4/g_svc_in_tkt.c: NULL
+./lib/krb4/in_tkt.c: NO_FSYNC O_SYNC TKT_SHMEM
+./lib/krb4/klog.c: VMS _WINDOWS
+./lib/krb4/kparse.c: DEBUG FALSE GTOK_TEST KVTEST PSTEST
+./lib/krb4/krb4int.h: KRB_DB_DEFS _WINDOWS
+./lib/krb4/kuserok.c: ATHENA_COMPAT ATHENA_OLD_KLOGIN __SCO__ _WINDOWS
+./lib/krb4/lifetime.c: SHORT_LIFETIME
+./lib/krb4/log.c: KRB_CRYPT_DEBUG VMS _WINDOWS
+./lib/krb4/macsock.c: ENOMEM
+./lib/krb4/memcache.c: _AIX unix _WINDOWS
+./lib/krb4/mk_auth.c: ATHENA_COMPAT NOENCRYPTION
+./lib/krb4/mk_preauth.c: NOENCRYPTION
+./lib/krb4/mk_priv.c: NOENCRYPTION notdef
+./lib/krb4/mk_req.c: NOENCRYPTION
+./lib/krb4/mk_safe.c: NOENCRYPTION
+./lib/krb4/netread.c: _WINDOWS
+./lib/krb4/netwrite.c: _WINDOWS
+./lib/krb4/rd_preauth.c: NOENCRYPTION
+./lib/krb4/rd_priv.c: NOENCRYPTION notdef
+./lib/krb4/rd_req.c: KRB_CRYPT_DEBUG lint NOENCRYPTION
+./lib/krb4/rd_safe.c: DEBUG NOENCRYPTION
+./lib/krb4/rd_svc_key.c: ATHENA_COMPAT ATHENA_OLD_SRVTAB __i960__
+./lib/krb4/realmofhost.c: DO_REVERSE_RESOLVE
+./lib/krb4/recvauth.c: max NOENCRYPTION _WINDOWS
+./lib/krb4/sendauth.c: ATHENA_COMPAT
+./lib/krb4/send_to_kdc.c: DEBUG SunOS ULTRIX022
+./lib/krb4/setenv.c: HAVE_GETENV LIBC_SCCS lint
+./lib/krb4/tf_shm.c: _AIX
+./lib/krb4/tf_util.c: NEED_UTIMES __SCO__ __svr4__ __SVR4 TKT_SHMEM
+./lib/krb4/tkt_string.c: _WINDOWS
+./lib/krb4/win_time.c: _WIN32
+./lib/krb5/configure.in: const GETPEERNAME_ARG2_TYPE GETPEERNAME_ARG3_TYPE GETSOCKNAME_ARG2_TYPE GETSOCKNAME_ARG3_TYPE gid_t HAVE_REGCOMP HAVE_SA_LEN HAVE_STDARG_H HAVE_VARARGS_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM off_t STDC_HEADERS uid_t HAVE_CHMOD HAVE_COMPILE HAVE_DAEMON HAVE_FCHMOD HAVE_FLOCK HAVE_GETENV HAVE_GETEUID HAVE_GETHOSTBYNAME2 HAVE_GETIFADDRS HAVE_GETUID HAVE_MEMMOVE HAVE_RE_COMP HAVE_RE_EXEC HAVE_REGEXEC HAVE_SETENV HAVE_SETSID HAVE_SSCANF HAVE_STEP HAVE_STRCASECMP HAVE_STRDUP HAVE_STRERROR HAVE_STRFTIME HAVE_STRPTIME HAVE_SYSLOG HAVE_UNSETENV HAVE_VFPRINTF HAVE_VSPRINTF HAVE_FCNTL_H HAVE_IFADDRS_H HAVE_MEMORY_H HAVE_PATHS_H HAVE_REGEX_H HAVE_REGEXP_H HAVE_REGEXPR_H HAVE_SYS_FILIO_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/krb5/krb5_libinit.c: macintosh _WIN32
+./lib/krb5/krb5_libinit.h: KRB5_LIBINIT_H
+./lib/krb5util/configure.in: const KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_SETEGID HAVE_SETEUID HAVE_SETREGID HAVE_SETRESGID HAVE_SETRESUID HAVE_SETREUID HAVE_STDLIB_H HAVE_SYS_TYPES_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/krb5util/compat_recv.c: KRB5_KRB4_COMPAT _MACINTOSH max NOENCRYPTION
+./lib/rpc/configure.in: const ENDRPCENT_TYPE GETGROUPS_T gid_t HAVE_SYS_ERRLIST KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM NEED_SYS_ERRLIST SETRPCENT_TYPE SYS_ERRLIST_DECLARED uid_t HAVE_STRERROR HAVE_SYS_UIO_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/rpc/auth_gssapi.c: __CODECENTER__ DEBUG_GSSAPI GSSAPI_KRB5
+./lib/rpc/auth_gssapi.h: major minor PROTOTYPE __STDC__ __ultrix _WIN32
+./lib/rpc/auth_gssapi_misc.c: __CODECENTER__ DEBUG_GSSAPI
+./lib/rpc/auth_none.c: lint SCCSIDS
+./lib/rpc/auth_unix.c: KERNEL lint SCCSIDS
+./lib/rpc/authunix_prot.c: lint SCCSIDS
+./lib/rpc/bindresvport.c: lint SCCSIDS
+./lib/rpc/clnt_generic.c: lint SCCSIDS
+./lib/rpc/clnt.h: _CLNT_
+./lib/rpc/clnt_perror.c: lint SCCSIDS
+./lib/rpc/clnt_raw.c: lint SCCSIDS
+./lib/rpc/clnt_simple.c: lint SCCSIDS
+./lib/rpc/clnt_tcp.c: FD_SETSIZE lint SCCSIDS
+./lib/rpc/clnt_udp.c: FD_SETSIZE lint SCCSIDS sun
+./lib/rpc/get_myaddress.c: GSSAPI_KRB5 lint OSF1 SCCSIDS sun
+./lib/rpc/getrpcent.c: lint PROTOTYPE SCCSIDS __STDC__ __ultrix _WIN32
+./lib/rpc/getrpcport.c: lint SCCSIDS
+./lib/rpc/netdb.h: RPC_NETDB_H STRUCT_RPCENT_IN_RPC_NETDB_H
+./lib/rpc/pmap_clnt.c: lint SCCSIDS
+./lib/rpc/pmap_getmaps.c: lint OSF1 SCCSIDS
+./lib/rpc/pmap_getport.c: lint OSF1 SCCSIDS
+./lib/rpc/pmap_prot2.c: lint SCCSIDS
+./lib/rpc/pmap_prot.c: lint SCCSIDS
+./lib/rpc/pmap_rmt.c: __alpha__ FD_SETSIZE hpux lint linux MAX notdef __osf__ OSF1 SCCSIDS SIOCGIFBRDADDR SO_BROADCAST sun __svr4__
+./lib/rpc/rpc_callmsg.c: lint SCCSIDS
+./lib/rpc/rpc_commondata.c: FD_SETSIZE
+./lib/rpc/rpc_dtablesize.c: FD_SETSIZE lint SCCSIDS _SC_OPEN_MAX
+./lib/rpc/rpc.h: __RPC_HEADER__
+./lib/rpc/rpc_prot.c: lint SCCSIDS
+./lib/rpc/svc_auth.c: lint SCCSIDS
+./lib/rpc/svc_auth_gssapi.c: __CODECENTER__ DEBUG_GSSAPI GSSAPI_KRB5 GSS_BACKWARD_HACK PURIFY
+./lib/rpc/svc_auth_unix.c: lint SCCSIDS
+./lib/rpc/svc.c: FD_SETSIZE lint SCCSIDS
+./lib/rpc/svc.h: FD_SETSIZE __SVC_HEADER__
+./lib/rpc/svc_raw.c: lint SCCSIDS
+./lib/rpc/svc_run.c: FD_SETSIZE lint SCCSIDS
+./lib/rpc/svc_simple.c: lint SCCSIDS
+./lib/rpc/svc_tcp.c: FD_SETSIZE lint SCCSIDS
+./lib/rpc/svc_udp.c: lint MAX SCCSIDS
+./lib/rpc/xdr_alloc.c: lint SCCSIDS
+./lib/rpc/xdr_array.c: lint SCCSIDS
+./lib/rpc/xdr.c: lint SCCSIDS
+./lib/rpc/xdr_float.c: IGNORE lint SCCSIDS vax
+./lib/rpc/xdr.h: PROTOTYPE __STDC__ __ultrix _WIN32 __XDR_HEADER__
+./lib/rpc/xdr_mem.c: lint SCCSIDS
+./lib/rpc/xdr_rec.c: lint __osf__ SCCSIDS
+./lib/rpc/xdr_reference.c: lint SCCSIDS
+./lib/rpc/xdr_stdio.c: lint SCCSIDS
+./lib/rpc/unit-test/configure.in: const HAVE_REGCOMP HAVE_TCL_H HAVE_TCL_TCL_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM POSIX_SIGNALS HAVE_COMPILE HAVE_STEP HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./lib/rpc/unit-test/client.c: __CODECENTER__ lint
+./lib/rpc/unit-test/rpc_test.h: _RPC_TEST_H_RPCGEN
+./lib/rpc/unit-test/server.c: __CODECENTER__ lint SERVICE_NAME
+./slave/configure.in: const HAVE_REGCOMP KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM mode_t STDC_HEADERS HAVE_COMPILE HAVE_STEP HAVE_LIBNSL HAVE_LIBSOCKET HAVE_LIBUTIL
+./slave/kpropd.c: NEED_DAEMON_PROTO PID_FILE WEXITSTATUS
+./tests/configure.in: const HAVE_REGCOMP KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM POSIX_SIGNALS RETSIGTYPE STDC_HEADERS HAVE_COMPILE HAVE_STEP HAVE_STRCHR HAVE_STDLIB_H HAVE_SYS_PARAM_H HAVE_SYS_SOCKET_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./util/autoconf/configure.in:
+./util/db2/configure.in: const HAVE_REGCOMP int16_t int32_t int8_t KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM memmove MEMMOVE size_t ssize_t STDC_HEADERS u_char u_int u_int16_t u_int32_t u_int8_t u_long u_short WORDS_BIGENDIAN HAVE_COMPILE HAVE_MKSTEMP HAVE_STEP HAVE_STRERROR HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./util/et/configure.in: const HAVE_STDARG_H HAVE_SYS_ERRLIST HAVE_VARARGS_H HDR_HAS_PERROR KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM NEED_SYS_ERRLIST NO_YYLINENO SYS_ERRLIST_DECLARED HAVE_STRERROR HAVE_STDLIB_H HAVE_LIBNSL HAVE_LIBSOCKET
+./util/et/com_err.c: macintosh _WIN32
+./util/et/com_err.h: __COM_ERR_H __cplusplus KRB5_CALLCONV macintosh _WIN32
+./util/et/compile_et.c: lint NEED_STRCASECMP
+./util/et/error_message.c: DEBUG_TABLE_LIST macintosh __sgi _WIN32
+./util/et/error_table.h: _ET_H macintosh _WIN32
+./util/et/internal.h: __STDC__ WIN32
+./util/et/vfprintf.c: macintosh _WIN32
+./util/profile/configure.in: const HAVE_REGCOMP KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM HAVE_ACCESS HAVE_COMPILE HAVE_STAT HAVE_STEP HAVE_STDLIB_H HAVE_UNISTD_H HAVE_LIBNSL HAVE_LIBSOCKET
+./util/profile/argv_parse.c: DEBUG
+./util/profile/prof_file.c: macintosh NO_SYS_STAT_H NO_SYS_TYPES_H PROFILE_USES_PATHS _WIN32
+./util/profile/prof_init.c: macintosh PROFILE_USES_PATHS
+./util/profile/prof_int.h: macintosh PROFILE_USES_PATHS __STDC__ _WIN32
+./util/profile/prof_parse.c: EOL macintosh _WIN32
+./util/pty/configure.in: const GETPGRP_ONEARG HAS_STRSAVE HAVE_ HAVE_OPENPTY HAVE_REGCOMP HAVE_SA_LEN HAVE_SETLUID HAVE_SETOWN HAVE_STREAMS HAVE_SYS_ERRLIST KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM krb5_sigtype KRB5_USE_INET6 mode_t NEED_SYS_ERRLIST OPEN_CTTY_ONLY_ONCE POSIX_SETJMP POSIX_SIGNALS POSIX_SIGTYPE POSIX_TERMIOS PTY_UTMP_E_EXIT PTY_UTMP_E_TERMINATION PTY_UTMPX_E_EXIT PTY_UTMPX_E_TERMINATION PUSH_LDTERM PUSH_PTEM PUSH_TTCOMPAT REVOKE_NEEDS_OPEN SETPGRP_TWOARG STDC_HEADERS SYS_ERRLIST_DECLARED time_t USE_DIRENT_H HAVE_COMPILE HAVE_FCHMOD HAVE_FCHOWN HAVE_GETADDRINFO HAVE_GETNAMEINFO HAVE__GETPTY HAVE_GETTOSBYNAME HAVE_GETUTMP HAVE_GETUTMPX HAVE_GRANTPT HAVE_INET_NTOP HAVE_INET_PTON HAVE_KILLPG HAVE_LINE_PUSH HAVE_LOGWTMP HAVE_OPENPTY HAVE_PTSNAME HAVE_REVOKE HAVE_SETREUID HAVE_SETSID HAVE_SETUTENT HAVE_SETUTXENT HAVE_STEP HAVE_TTYNAME HAVE_UPDWTMP HAVE_UPDWTMPX HAVE_UTMPNAME HAVE_UTMPXNAME HAVE_VHANGUP HAVE_WAITPID HAVE_LASTLOG_H HAVE_LIBUTIL_H HAVE_MACSOCK_H HAVE_NETDB_H HAVE_NETINET_IN_H HAVE_PTY_H HAVE_STDLIB_H HAVE_STRING_H HAVE_SYS_FILIO_H HAVE_SYS_LABEL_H HAVE_SYS_PTYVAR_H HAVE_SYS_SELECT_H HAVE_SYS_SOCKET_H HAVE_SYS_SOCKIO_H HAVE_SYS_TTY_H HAVE_SYS_TYPES_H HAVE_SYS_WAIT_H HAVE_TTYENT_H HAVE_UNISTD_H HAVE_UTIL_H HAVE_UTMP_H HAVE_UTMPX_H HAVE_LIBNSL HAVE_LIBSOCKET
+./util/pty/cleanup.c: VHANG_LAST
+./util/pty/dump-utmp.c: UTMPX UTN
+./util/pty/init_slave.c: TIOCSPGRP ultrix
+./util/pty/libpty.h: __LIBPTY_H__ SOCK_DGRAM
+./util/pty/logwtmp.c: NEED_LOGWTMP_PROTO
+./util/pty/open_ctty.c: TIOCSCTTY ultrix
+./util/pty/open_slave.c: VHANG_FIRST
+./util/pty/pty-int.h: hpux NEED_GETUTMPX_PROTOTYPE NEED_REVOKE_PROTO __PTY_INT_H__ __SCO__ sysvimp ultrix WTMPX_FILE
+./util/pty/pty_paranoia.c: O_NOCTTY TIOCSCTTY
+./util/pty/update_utmp.c: __hpux _PATH_UTMP UTMP_FILE
+./util/pty/update_wtmp.c: NEED_GETUTMP_PROTO _PATH_WTMP _PATH_WTMPX WTMP_FILE WTMPX_FILE
+./util/pty/void_assoc.c: TIOCNOTTY
+./util/ss/configure.in: const HAVE_STDARG_H HAVE_VARARGS_H KRB5_DNS_LOOKUP KRB5_DNS_LOOKUP_KDC KRB5_DNS_LOOKUP_REALM NO_YYLINENO POSIX_SIGNALS RETSIGTYPE USE_DIRENT_H USE_SIGPROCMASK WAIT_USES_INT HAVE_STRDUP HAVE_STDLIB_H HAVE_LIBNSL HAVE_LIBSOCKET
+./util/ss/error.c: ibm032 NeXT __STDC__
+./util/ss/execute_cmd.c: __SABER__
+./util/ss/invocation.c: silly
+./util/ss/list_rqs.c: lint NO_FORK __STDC__
+./util/ss/pager.c: NO_FORK
+./util/ss/parse.c: DEBUG
+./util/ss/ss.h: _ss_h __STDC__
+./util/ss/ss_internal.h: __GNUC__ __HIGHC__ sigmask _ss_ss_internal_h __STDC__ vax
diff --git a/mechglue/src/ChangeLog b/mechglue/src/ChangeLog
new file mode 100644
index 000000000..a3e3fdb72
--- /dev/null
+++ b/mechglue/src/ChangeLog
@@ -0,0 +1,3114 @@
+2006-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_TRYOLD): Include $LIBS in $TCL_LIBS.
+
+2006-01-06  Tom Yu  <tlyu@mit.edu>
+
+	* krb5-config.in: Cause libs output to match actual required
+	ordering of libraries.
+
+2005-12-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* plugins: Directory renamed from "modules".
+	* Makefile.in (SUBDIRS, fake-install), configure.in: Updated.
+
+2005-11-29  Jeffrey Altman <jaltman@mit.edu>
+
+	* Makefile.in: add src/windows/kfwlogon tree
+
+2005-10-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_BUILD_LIBRARY_WITH_DEPS): Substitute
+	DYNOBJ_EXPDEPS and DYNOBJ_EXPFLAGS.
+	(KRB5_LIB_AUX): If build_dynobj is set to yes, ensure that OBJS.SH
+	is in OBJLISTS and that OBJS.ST is not.
+	(K5_AC_INIT): Initialize build_dynobj to no.
+
+2005-10-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_INET6): Drop enable/disable-ipv6 option;
+	emit a warning for it for now, and always do use-if-available.
+
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_BUILD_LIBRARY_WITH_DEPS): Substitute DYNOBJEXT
+	and MAKE_DYNOBJ_COMMAND.
+	(KRB5_LIB_AUX): Don't define _KDB5_STATIC_LINK.
+
+	* configure.in: Don't configure util/db2.
+
+2005-09-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (fake-install): Do install in modules/kdb/db2.
+	Caught by Michael Calmer.
+
+2005-09-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* modules, modules/kdb: New directories.
+	* modules/kdb/db2: Moved from lib/kdb/kdb_db2.
+	* Makefile.in (SUBDIRS): Add modules/kdb/db2.
+	* configure.in: Configure in that directory.
+
+2005-09-08  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_LIBRARY_NET): Check for a few more libresolv
+	functions.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (K5_AC_INIT, K5_BUGADDR): New macros.
+	(PL_KRB5_MAJOR_RELEASE, PL_KRB5_MINOR_RELEASE, PL_KRB5_PATCHLEVEL,
+	PL_KRB5_RELTAIL): New macros, holding values extracted from
+	patchlevel.h at autoconf time.
+	(K5_VERSION): Define in terms of the PL_* macros.
+	(K5_TOPDIR): If m4exit doesn't work, try builtin(m4exit,1).
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.  Set
+	KRB5_VERSION from K5_VERSION, don't parse patchlevel.h.
+
+2005-08-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (fake-install): New target; create a partially
+	populated install tree.
+	(check-prerecurse): Depend on it.
+
+2005-07-19  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_LIBRARY_NET): Special-case AIX 5.x due to broken
+	res_ninit(), or more precisely, incorrect size of struct
+	__res_state.
+
+2005-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (INSTALLMKDIRS): Add KRB5_DB_MODULE_DIR.
+
+2005-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (libnover_frag): Set and substitute.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (WITH_CC): Don't use -pedantic on Linux.
+	(KRB5_AC_FIND_DLOPEN): New macro.  Set DL_LIB.
+	(CONFIG_RULES, AC_KRB5_TCL_TRYOLD): Use it.
+	(KRB5_AC_ENABLE_THREADS): Override guessed PTHREAD_CFLAGS with
+	correct value for solaris+gcc.
+
+	Novell merge.
+	* aclocal.m4 (KRB5_LIB_AUX): Define _KDB5_STATIC_LINK if static
+	libraries are enabled.
+
+2005-06-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for endian.h.
+
+2005-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for headers byteswap.h, sys/bswap.h,
+	machine/endian.h, machine/byte_order.h, and functions bswap16,
+	bswap64, bswap_16, and bswap_64.
+
+2005-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Put #undef for the PACKAGE_* symbols at the start
+	of autoconf.h.  Use a leading comment to hide the #undef from the
+	autoconf substitutions.
+
+2005-06-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Identify package in AC_INIT call.
+
+2005-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): Provide comment template
+	when defining C macros.
+	(KRB5_GETPEERNAME_ARGS): Likewise.
+	(KRB5_GETSOCKNAME_ARGS): Likewise.  Only define the macros in one
+	place.
+
+	* configure.in: Merged content from include/configure.in.  Don't
+	configure include directory any more; build its makefiles and
+	autoconf.h directly.  Provide comment template when defining C
+	macros.
+
+2005-04-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (fileexists, K5_TOPDIR): New macros.
+	(V5_SET_TOPDIR): Don't test for AC_LOCALDIR any more.  Use
+	K5_TOPDIR computed at autoconf time, but still verify that the
+	contents are what we expect.  Don't use shell variables in the
+	argument to AC_CONFIG_AUX_DIR.
+
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't check for getpwnam_r and getpwuid_r in the
+	thread-safety warnings.  The tests done elsewhere in the tree are
+	stricter and may not agree.
+
+2005-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_THREADS): Expand on error message if
+	failing.  Substitute THREAD_SUPPORT -> 0 or 1 in makefiles.  For
+	HP-UX, set PTHREAD_CFLAGS, not CFLAGS.
+
+2005-02-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (config.status): Depend on shlib.conf.
+
+	* aclocal.m4 (KRB5_AC_ENABLE_THREADS): If thread support is not
+	enabled, zap the PTHREAD_ variables.
+
+2005-01-12  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_LIBRARY_NET): Also check for res_ndestroy.
+
+2004-12-16  Ezra Peisach  <epeisach@bu.edu>
+
+	* krb5-config.in: Add krb5support library.
+
+2004-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * Makefile.in: build/clean/install/etc kcpytkt,kdeltkt,ms2mit
+
+2004-11-19  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_PRIOCNTL_HACK): Check for Solaris patch
+	117171-11 (sparc) or 117172-11 (x86), which fixes the Solaris 9
+	bug which can cause final pty output to be on close.
+
+2004-11-18  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-headers-mkdirs): Create KRB5_INCDIR/gssrpc.
+
+2004-10-06  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (INSTALLMKDIRS): Add EXAMPLEDIR.
+
+2004-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_THREADS): On HP-UX, define some
+	preprocessor symbols that -pthread defines, but don't use -pthread
+	so we can avoid forcing linking against pthread libraries.
+
+2004-09-24  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Update to get RELTAIL from patchlevel.h as well.
+
+	* patchlevel.h: Update to make this the master version stamp file.
+
+2004-09-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): If the config info set by
+	tclConfig.sh doesn't produce a working executable, set TCL_LIBS to
+	be empty explicitly.
+	(KRB5_BUILD_LIBRARY_WITH_DEPS): Substitute SHLIB_EXPORT_FILE_DEP.
+
+2004-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_LIBUTIL): New macro to check for libutil.
+	
+	* aclocal.m4 (WITH_CC): Check for GNU linker.
+
+2004-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* alcocal.m4 (AC_LIBRARY_NET): Additionally, check ns_initparse,
+	since Linux prototypes it but doesn't export it.
+
+2004-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_NEED_BIND_8_COMPAT): Remove.
+	(AC_LIBRARY_NET): Remove KRB5_AC_NEED_BIND_8_COMPAT.  Call
+	_KRB5_AC_CHECK_RES_FUNCS to check declarations and linkability of
+	vairous resolver functions.  Explicitly check linkability of
+	res_search() in case it's not explicitly declared.
+	(_KRB5_AC_CHECK_RES_FUNCS, _KRB5_AC_CHECK_RES_FUNC): New
+	functions.  Check resolver library function prototypes and
+	linkability.
+
+2004-09-17  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-unix): Use $(INSTALL_SCRIPT) for scripts.
+
+	* aclocal.m4 (AC_LIBRARY_NET): Look for res_search() prototype,
+	then for symbol in library, in case there's symbol renaming
+	happening in the headers.  Clean up some style nits.
+
+2004-09-15  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_LIBRARY_NET): Only look for res_search() in
+	libraries, not headers, in case it's present but not prototyped.
+
+2004-09-14  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_LIBRARY_NET): Require the BIND_8_COMPAT check
+	prior to looking for prototypes, as BIND 9 (at least on Panther)
+	turns off some prototypes and typedefs if BIND_8_COMPAT is
+	defined.
+
+2004-09-13  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Fix check for resolv.h; some platforms have
+	prerequisite headers.
+
+2004-09-08  Sam Hartman  <hartmans@krbdev-linux.mit.edu>
+
+	* aclocal.m4 : Remove use of resolv_lib; none of the makefiles
+	actually use it and if we don't set it we can simplify the DNS
+	tests significantly.   If the -lresolv library exists we use it.
+	This may create a bit of a problem for people with nsswitch
+	configurations that don't prefer dns.  We include resolv.h before
+	checking for res_*.
+
+2004-09-08  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Install krb5-config manpage.
+
+2004-09-07  Alexandra Ellwood  <lxs@mit.edu>
+
+	* krb5-config.M: Added a man page for krb5-config.
+
+2004-08-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't test for pthread_rwlock_init.
+
+	* aclocal.m4 (KRB5_AC_PRAGMA_WEAK_REF): Fix to work with AIX
+	compiler when optimizing.
+
+2004-08-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_THREADS): Check for
+	pthread_rwlock_init, with and without the thread library.
+
+2004-08-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_THREADS): On AIX and OSF/1, always
+	add $PTHREAD_CFLAGS to CFLAGS for use in later tests.  Clear
+	PTHREAD_CFLAGS and PTHREAD_LIBS to avoid duplicating the options
+	later.
+	(WITH_CC): If on AIX and not using gcc, add -qhalt=e and -O to
+	CFLAGS if similar options are not already present.  Log messages
+	when doing so.
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_INET6, KRB5_AC_CHECK_SOCKADDR_STORAGE,
+	KRB5_AC_CHECK_INET6): Don't check for macsock.h.
+
+2004-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5-config.in: Substitute $(PTHREAD_CFLAGS).
+
+2004-07-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_THREADS): Use PTHREAD_CFLAGS and
+	PTHREAD_LIBS when checking for pthread_mutexattr_setrobust_np
+	availability with thread support enabled.  Fix typo that caused
+	some code to be omitted.
+
+2004-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_THREADS): Don't test for pthread.h
+	specifically.  Always include the thread library on Tru64 UNIX.
+	(KRB5_AC_CHECK_INET6): If the first test fails, try adding -DINET6
+	and test again; if it works, define INET6 for the build.
+
+2004-07-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_THREADS): Default to enabling
+	support.
+
+2004-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Fix bug in last change that caused a variable to
+	be used before set.  Check for pthread_rwlock_init.
+
+2004-07-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_LIBRARY_NET): Look for res_nsearch.
+	* configure.in: If thread support is enabled and res_nsearch
+	isn't found, issue a warning.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (WITH_CC): Use -Wl,-search_paths_first for linking on
+	Darwin.
+	(KRB5_AC_ENABLE_THREADS): On AIX, add PTHREAD_LIBS to LIBS; don't
+	do it on other platforms.  Override CC with PTHREAD_CC only if CC
+	is not gcc.  Don't add PTHREAD_CFLAGS to CFLAGS; substitute
+	PTHREAD_CFLAGS separately.
+
+	* Makefile.in (all-windows): Make autoconf.h in include\krb5
+	before building anything else.
+	(WINMAKEFILES): Add util\support\Makefile.
+	(util\support\Makefile) [DOS]: New target.
+	(CE): New variable.
+	($(CE)test1.h, $(CE)test2.h, $(CE)test1.c, $(CE)test2.c): New
+	targets.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MACFILES, MAC_SUBDIRS): Don't set.
+	(macfile.list, mac-bin-dirs, krbsrc.mac.tar, Macfile, all-mac,
+	clean-mac): Target deleted.
+	(CLEANUP): Remove macfile.list.
+
+2004-06-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (CONFIG_RULES): Don't set AUTOCONF, AUTOCONFFLAGS,
+	AUTOHEADER, AUTOHEADERFLAGS, AUTOCONFINCFLAGS.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_AUX): Use $(LIBBASE) instead of $(LIB).
+
+2004-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for various _r functions needed for thread
+	safety.  If enable-thread-support is specified, complain about
+	any that aren't found.
+
+2004-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_GCC_ATTRS): On AIX 4, mark the destructor
+	attribute as always not working, until we can construct a good
+	test for the order of destructors in the multiple shared library
+	case.
+
+2004-05-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Generate a makefile in util/support.  Include
+	dependency support for shared library build.
+
+2004-04-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (CONFIG_RULES): Invoke KRB5_LIB_PARAMS and
+	KRB5_AC_INITFINI.
+	(KRB5_AC_INITFINI): New macro.  Define delayed-initialization
+	config option, test for gcc constructor/destructor attribute
+	support, and test whether shlib.conf indicates support for
+	link-time options.
+	(KRB5_AC_GCC_ATTRS): Implement.
+	(CONFIG_RULES): Substitute EXTRA_FILES into pre.in.
+
+2004-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_BUILD_LIBRARY_WITH_DEPS): Report an error if
+	perl cannot be found.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_BUILD_LIBRARY_WITH_DEPS): Look for perl.
+	(KRB5_AC_PRAGMA_WEAK_REF): New macro, tests support for weak
+	references using "#pragma weak".
+	(CONFIG_RULES): Invoke it.
+	(KRB5_AC_ENABLE_THREADS): Test enableval, not withval.  If
+	ACX_PTHREAD can't determine thread support options and thread
+	support was requested, report an error.  Display the options
+	selected by ACX_PTHREAD.  Test for pthread_once without pthread
+	options, and pthread_mutexattr_setrobust_np both with and without
+	pthread options.
+	(KRB5_AC_GCC_ATTRS): New macro, dummy for now.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_BUILD_LIBRARY_WITH_DEPS): Substitute
+	MAKE_SHLIB_COMMAND, not LDCOMBINE and LDCOMBINE_TAIL.
+
+2004-03-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_MAINTAINER_MODE, KRB5_AC_ENABLE_THREADS,
+	KRB5_AC_INET6, WITH_HESIOD, KRB5_LIB_AUX, KRB5_AC_CHOOSE_SS,
+	KRB5_AC_CHOOSE_DB): Express defaults more consistently with other
+	configure output.  Use AC_HELP_STRING.  Shorten up some messages,
+	drop some options that are defaults and obvious counterparts to
+	other documented options.
+	(KRB5_LIB_AUX): Use default_shared and default_static from
+	shlib.conf to decide whether to build shared and static libraries
+	by default.  Update messages to indicate shared libraries are the
+	default for most platforms now.  Use AC_MSG_NOTICE and
+	AC_MSG_WARN instead of AC_MSG_RESULT when there's no "checking"
+	message.
+
+	* configure.in: Likewise.
+
+2004-03-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4: Include acx_pthread.m4.
+	(KRB5_AC_ENABLE_THREADS): New macro.
+	(CONFIG_RULES): Invoke it.  Use AC_REQUIRE to get topdir set
+	early.
+
+2004-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (update-autoconf-h): New target.  Checks that
+	include/krb5/autoconf.h is current.
+	(all-prerecurse): Depend on it.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SUBDIRS): Renamed from MY_SUBDIRS.
+
+2004-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): Look for tclConfig.sh in
+	the specified directory if it's not in a "lib" subdirectory.
+	(AC_KRB5_TCL): If no pathname is supplied and tclConfig.sh isn't
+	found in /usr/lib, try running a script under tclsh to see if it
+	can supply the pathname for tclConfig.sh.
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Integrate config commands from kdc, krb524, and
+	slave directories.  Don't configure those directories; generate
+	their makefiles directly.  Use AC_HELP_STRING in AC_ARG_ENABLE
+	and AC_ARG_WITH messages.  Substitute @LIBUTIL@.
+
+2004-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Configure lib/apputils, not util/apputils.
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_NEED_DAEMON): Don't use AC_REPLACE_FUNCS.
+	* configure.in: Configure util/apputils.
+
+2004-02-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (TRY_PEER_INT): Deleted.
+	(KRB5_GETPEERNAME_ARGS): Map the getpeername arg types to the
+	corresponding getsockname arg types.
+	(KRB5_GETSOCKNAME_ARGS): If nothing matches, assume struct
+	sockaddr and socklen_t.
+	(WITH_CC): Add -fno-common to CFLAGS on Darwin, unless -fcommon or
+	-fno-common is already given.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_PRIOCNTL_HACK): Set PRIOCNTL_HACK=1 on
+	Solaris 9.
+
+	* configure.in: Remove exitsleep.
+
+2003-12-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use AC_HELP_STRING for kdc-replay-cache option
+	info, to tidy up the output.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (WITH_CC): Drop -Wno-comment, since we don't support
+	SunOS 4 any longer.
+
+2003-12-05  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add support for building an LD_PRELOAD object for
+	Solaris, used by util/Makefile.in.
+
+2003-09-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_MAINTAINER_MODE): New macro.
+	(CONFIG_RULES): Invoke it.
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_NEED_DAEMON): New macro.
+
+2003-08-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (WITH_CCOPTS, WITH_CPPOPTS, WITH_LINKER,
+	WITH_LDOPTS, KRB5_INIT_CCOPTS, WITH_CC_DEPRECATED_ARG): Deleted.
+	(CONFIG_RULES): Do the non-useless parts directly here.
+	(V5_SET_TOPDIR): Work quietly.
+	(WITH_KRB4): Use AC_MSG_NOTICE.
+	(KRB5_AC_ENABLE_DNS): Drop --enable-dns and --enable-dns-for-kdc
+	options; turn them on always.
+
+2003-07-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (extra_gcc_warn_opts): Don't turn on -pedantic on
+	Darwin.
+
+2003-05-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KRBHDEP): Add krb524_err header.
+
+2003-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (WITH_KRB4): Don't set or substitute KRB524_DEPLIB,
+	KRB524_LIB, KRB524_H_DEP, or KRB524_ERR_H_DEP.
+	* Makefile.in (ETOUT): Update location of krb524_err files.
+	(krb524/krb524_err.h, krb524/krb524_err.c): Delete.
+	($(INC)krb524_err.h, $(ET)krb524_err.c): New targets.
+
+2003-05-22  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Add -DKRB5_DEPRECATED=1 so stuff in tree builds.
+
+2003-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4: Require autoconf 2.52 only.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4: Require autoconf 2.53.
+	(CONFIG_RULES): Always set AUTOCONFINCFLAGS to --include.
+
+2003-04-10  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Revert requrement of autoconf-2.53, since MacOS X
+	doesn't have it.
+
+2003-04-01  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_CHOOSE_DB): Set new variable KDB5_DB_LIB to
+	empty if using in-tree db.  It is now used to pass -ldb to link
+	commands, if needed, when linking programs with libkdb5.  DB_LIB
+	is now only used for programs that explicitly need the actual
+	libdb independently of libkdb5.
+
+	* krb5-config.in: Use $KDB5_DB_LIB instead of "-ldb" for kdb
+	libraries.
+
+2003-03-31  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Require autoconf-2.53, since 2.52 generates
+	configure scripts that NetBSD /bin/sh doesn't like.
+
+2003-03-18  Alexandra Ellwood  <lxs@mit.edu>
+
+    * aclocal.m4: Define KRB5_AC_NEED_BIND_8_COMPAT to check for bind 9
+    and higher.  When bind 9 is present, BIND_8_COMPAT needs to be defined to
+    get bind 8 types.
+
+2003-03-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (AWK): Default to awk, not gawk.  User can override
+	on make's command line if necessary.  Still, only really useful
+	for building kerbsrc.zip, etc.
+
+2003-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (WINMAKEFILES): Add lib\crypto\aes\Makefile.
+	(lib\crypto\aes\Makefile) [##DOS##]: New target.
+
+2003-03-03  Tom Yu  <tlyu@mit.edu>
+
+	* krb5-config.in (lib_flags): Prune out CFLAGS.
+
+	* aclocal.m4: Remove KRB_INCLUDE; it's now in pre.in.  Remove
+	ADD_DEF and uses thereof, thus allowing CPPFLAGS to be a user
+	parameter.
+
+2003-03-02  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* aclocal.m4 : Substitute in DEPLIBEXT into krb5_build_library_with_deps
+
+2003-02-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (ETOUT): Replace $(S) with "/".
+
+2003-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (lib/krb4/krb_err_txt.c): Replace $(S) with "/" to
+	avoid breakage on Windows.
+
+2003-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add rules for generating lib/krb4/krb_err_txt.c for
+	Windows.
+
+2003-01-14  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (check-unix): Invoke t_krbconf instead of struggling
+	with differing versions of make's quoting of \ and $.
+
+	* t_krbconf: Small shell script to test krb5-config.
+
+2003-01-13  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (check-unix): Test to see if krb5-config outputs
+	variables that require Makefile substitutions. 
+
+	* krb5-config.in: Remore $(PURE) from output. Handle variables
+	$(RPATH_FLAG) and $(LDFLAGS).
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_BUILD_LIBRARY_WITH_DEPS): Require
+	AC_PROG_ARCHIVE, AC_PROG_ARCHIVE_ADD, and AC_PROG_INSTALL.
+	(KRB5_BUILD_LIBRARY): Use KRB5_BUILD_LIBRARY_WITH_DEPS instead of
+	duplicating its contents.
+	* configure.in: Don't explicitly invoke AC_PROG_INSTALL,
+	AC_PROG_ARCHIVE, AC_PROG_ARCHIVE_ADD, AC_PROG_RANLIB.
+
+	* aclocal.m4 (CONFIG_RULES): Substitute files for @lib_frag@ and
+	@libobj_frag@ markers.
+	(V5_SET_TOPDIR): Don't define krb5_append_frags.
+	(KRB5_BUILD_LIBRARY, KRB5_BUILD_LIBRARY_WITH_DEPS,
+	KRB5_BUILD_LIBOBJS): Don't redefine krb5_append_frags.
+	(_V5_AC_OUTPUT_MAKEFILE): Don't use krb5_append_frags.
+	(_K5_GEN_MAKEFILE): Don't process second argument specifying
+	makefile fragments.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+2002-12-23  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (WITH_KRB4): Substitute some variables for generated
+	krb524 and krb4 headers.
+
+2002-12-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_GETSOCKNAME_ARGS, KRB5_GETPEERANME_ARGS): Check
+	for socklen_t pointer as second argument.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-headers-prerecurse): Update to not use
+	double colons.
+
+2002-12-06  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (clean-unix): Remove krb5-config.
+
+2002-12-06  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (clean-unix): Remove krb5-config
+
+2002-12-02  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add rules to build kadm_err.h and kadm_err.c for
+	Windows.
+
+2002-11-18  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove references to kadm_err.et for now; changes
+	to move kadm_err.et to lib/krb4 haven't been commmitted yet.
+
+2002-11-15  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove some missed references to adm_err.et.
+
+2002-11-13  Ezra Peisach  <epeisach@bu.edu>
+
+	* aclocal.m4 (CONFIG_RULES): Define AUTOCONFINCFLAGS as --include
+	or --localdir depending on autoconf version. In autoconf 2.55
+	--localdir disappears.
+
+2002-11-12  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (tcl_lib): Add RPATH_TAIL to TCL_RPATH to handle AIX
+	weirdness with "-blibpath:".
+
+2002-11-04  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): Set TCL_MAYBE_RPATH.
+	(KRB5_BUILD_PROGRAM): Substitute RPATH_FLAG.
+
+2002-10-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): Use 'eval' when setting
+	TCL_LIBS to force variable substitutions to take place.
+
+2002-10-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL): If --with-tcl is given, failure to
+	find a library we can use is now an error.
+
+2002-10-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4: Use dnl after all AC_REQUIRE invocations.
+	(CONFIG_RULES): Comment out code looking for the in-tree version
+	of autoconf that we deleted.
+	(WITH_CC_DEPRECATED_ARG): New macro.
+	(WITH_CC): Require it, and AC_PROG_CC.
+	(KRB5_AC_FORCE_STATIC): New macro.  Warn if invoked after
+	KRB5_LIB_AUX.
+	(KRB5_BUILD_LIBRARY_STATIC): Require it.
+	(CHECK_SIGPROCMASK, AC_PROG_ARCHIVE, AC_PROG_ARCHIVE_ADD,
+	CHECK_DIRENT, CHECK_WAIT_TYPE, CHECK_SIGNALS, KRB5_SIGTYPE,
+	CHECK_SETJMP, WITH_KRB4, ADD_DEF, KRB_INCLUDE, K5_GEN_MAKEFILE,
+	_K5_GEN_MAKEFILE, K5_GEN_FILE, K5_AC_OUTPUT,
+	V5_AC_OUTPUT_MAKEFILE, CHECK_UTMP, WITH_NETLIB,
+	KRB5_BUILD_LIBRARY_STATIC): Define using AC_DEFUN.
+
+2002-10-07  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (install-headers-prerecurse): Create directories in
+	which we install headers
+
+2002-09-24  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (krb5-config): Add argument to invocation of
+	config.status to only generate krb5-config and not any other
+	Makefiles.
+
+	* configure.in (krb5-config): Use AC_CONFIG_FILES to better
+	generate and chmod krb5-config file.
+
+	* aclocal.m4 (V5_AC_OUTPUT_MAKEFILE): Rewrite to use AC_CONFIG_FILES. 
+	krb5_append_frags is now a define instead of a shell variable.
+	
+2002-09-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* aclocal.m4 (V5_SET_TOPDIR): When determining the location of the
+	top of the source tree, stop when reach the top and aclocal.m4
+	file is located instead of continuing up and out of the tree.
+
+2002-09-19  Ezra Peisach  <epeisach@bu.edu>
+
+	* aclocal.m4: Put V5_OUTPUT_MAKEFILE back - still in use. Needs to
+	be rewritten.
+
+2002-09-19  Ezra Peisach  <epeisach@bu.edu>
+
+	* aclocal.m4 (K5_AC_OUTPUT, K5_GEN_MAKEFILE, K5_GEN_FILE): Rewrite
+	to use AC_CONFIG_FILES. Remove unused V5_OUTPUT_MAKEFILE.
+
+2002-09-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_CHOOSE_SS): Check that the indicated system
+	ss package can actually be linked against and will produce
+	programs that run.
+
+2002-09-15  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): Set TCL_LIBPATH and
+	TCL_RPATH.
+
+2002-09-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocale.m4 (WITH_CC): Substitute @HAVE_GCC@.  Set
+	krb5_cv_prog_gcc from ac_cv_compiler_gnu.
+	* configure.in: Don't explicitly set HAVE_GCC or test for gcc
+	here.
+
+	* aclocal.m4 (KRB5_AC_CHOOSE_DB): New macro.
+	(CONFIG_RULES): Invoke it.
+	(KRB5_LIB_PARAMS): Don't substitute LIB_LINK_OPT.
+	(KRB5_LIB_AUX): Don't substitute EXTRA_CLEAN_TARGETS,
+	EXTRA_CLEAN_LINKS, and don't update LIBLIST, LIBLINKS, LIBINSTLIST
+	to add the EXTRA_ values.
+
+	* configure.in: Configure util/db2 only if we're going to use it.
+
+2002-09-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB_INCLUDE): Put in-tree include dirs before
+	previous contents of CPPFLAGS.
+	(KRB5_AC_CHOOSE_SS): Let user specify SS_LIB=..., substitute it
+	into generated makefiles.
+
+2002-09-03  Ezra Peisach  <epeisach@bu.edu>
+
+	* acconfig.h: Remove - no longer necessary.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_CHOOSE_ET, KRB5_AC_CHOOSE_SS): Renamed from
+	non-KRB5_AC_ names.  Change --with-system-com_err to
+	--with-system-et, to avoid confusing mix of '-' and '_'.
+	(WITH_CCOPTS): Describe as deprecated in favor of CFLAGS=...; use
+	AC_REQUIRE_CPP.
+	(WITH_LINKER, WITH_LDOPTS, WITH_CPPOPTS): Describe as deprecated;
+	encourage use of LD= etc instead.
+	(WITH_NETLIB, WITH_HESIOD): Use AC_HELP_STRING.
+	(KRB5_AC_CHECK_FOR_CFLAGS): New macro.
+	(WITH_CC): Mark old configure option deprecated, encourage user
+	to use CC= instead.  Add gcc warning flags only if CFLAGS not set
+	by user.  Don't force default to "cc".
+	(KRB5_LIB_PARAMS): Use AC_CANONICAL_HOST, don't bother with
+	cache.
+
+	* aclocal.m4 (CHOOSE_ET, CHOOSE_SS): New macros.
+	(CONFIG_RULES): Invoke them.
+	* configure.in: Configure util/et and util/ss only if they're
+	going to be used.  Configure lib/krb4 and krb524 only if KRB4_LIB
+	is non-empty; this may not be right for "--with-krb4=/some/dir".
+
+2002-08-26  Ezra Peisach  <epeisach@bu.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Substitute krb5_cv_host in
+	Makefiles. Remove K5_OUTPUT_FILES as nothing depends on it
+	anymore.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4: Require autoconf 2.52 or later.
+
+2002-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't make a Makefile in util/dyn.
+	* krb5-config.in: Don't include "-ldyn".
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_BUILD_LIBRARY_STATIC): Disable installation of
+	library.
+
+2002-07-05  Ezra Peisach  <epeisach@bu.edu>
+
+	* aclocal.m4 (KRB5_AC_INET6): Use the three argument form of
+	AC_DEFINE so that comment will be added to autoconf.h.in without
+	requiring acconfig.h change.
+
+2002-07-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_INET6): Include netdb.h when checking for
+	getaddrinfo, in case it's a macro.
+
+2002-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't configure lib/krb5util.
+
+2002-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (WINMAKEFILES): Remove keytab subdir makefiles, and
+	their build rules.
+
+2002-04-25  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in (AC_CONFIG_SUBDIRS): Always run configure in
+	lib/krb4 and krb524 - but do not build in those directories if
+	krb4 support disabled. Autoconf 2.53 and up cannot handle
+	variables in AC_CONFIG_SUBDIRS directive.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (TRY_PEER_INT): Strip trailing spaces from defined
+	macros.
+
+2002-04-02  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-strip): New rule to pass "-s" to install.
+
+	* aclocal.m4 (CONFIG_RULES): Fix to not define KRB5_DEPRECATED; we
+	set it to 1 in krb5.hin now.
+
+2002-04-01  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (CONFIG_RULES): Add -DKRB5_PRIVATE=1 and
+	-DKRB5_DEPRECATED=1 to the default CPPFLAGS for now, so that stuff
+	in the tree actually builds.
+
+2002-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (TRY_GETSOCK_INT): Strip trailing spaces from defined
+	macros.
+
+2001-11-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Fix up lib/crypto/yarrow for Windows.
+
+2001-11-16  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (FILES): Add lib/crypto/yarrow
+
+2001-10-29  Jeff Altman   <jaltman@columbia.edu>
+
+        * Makefile.in - Windows configuration for src/lib/crypto/arcfour
+          directory
+
+2001-10-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4: Require 2.13 of autoconf.
+	(DECLARE_SYS_ERRLIST, CHECK_SIGPROCMASK, CHECK_DIRENT,
+	CHECK_WAIT_TYPE, CHECK_SIGNALS, KRB5_SIGTYPE, KRB5_AC_CHECK_INET6,
+	HAVE_YYLINENO, KRB5_SOCKADDR_SA_LEN, AC_HEADER_STDARG,
+	KRB5_AC_NEED_LIBGEN, KRB5_AC_ENABLE_DNS): Use of AC_DEFINE
+	modified to provide comment for autoheader generated file.
+
+	* acconfig.h: Remove ANSI_STDIO, NO_YYLINENO, POSIX_FILE_LOCKS,
+	POSIX_SIGTYPE, POSIX_TERMIOS, USE_DIRENT_H, WAIT_USES_INT,
+	krb5_sigtype, HAVE_STDARG_H, HAVE_VARARGS_H, HAV_REGCOMP,
+	HAVE_SA_LEN, HAVE_SOCKLEN_T, KRB5_ATHENA_COMPAT, KRB5_KRB4_COMPAT,
+	KRB5_DNS_LOOKUP, KRB5_DNS_LOOKUP_KDC, KRB5_DNS_LOOKUP_REALM,
+	KRB5_USE_INET6, MEMMOVE, memmove, mkstemp and strerror. All
+	replaced by use of third argument to AC_DEFINE.
+
+2001-10-11  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in (HOST_TYPE): Remove SHLIB_TAIL_COMP; it's no longer
+	needed.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* wconfig.c (main): Delete _MSDOS support.
+
+2001-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_CHECK_TYPE_WITH_HEADERS): Need brackets
+	around arguments to tr.
+
+2001-08-31  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Fix clean-windows target to clean appl/gssftp/ftp.
+
+2001-08-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_CHECK_TYPE_WITH_HEADERS,
+	KRB5_AC_CHECK_SOCKADDR_STORAGE): New macros.
+	(KRB5_AC_CHECK_INET6): Call KRB5_AC_CHECK_SOCKADDR_STORAGE, but
+	don't require success for IPv6 support.
+	(KRB5_SOCKADDR_SA_LEN): Change first letter of checking message to
+	lowercase.
+	* acconfig.h (HAVE_STRUCT_SOCKADDR_STORAGE): Undef.
+
+2001-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): Do put /usr/include/tcl$v
+	in TCL_INCLUDES if that's where tcl.h is found.  Don't include
+	tcl.h when testing to see if Tcl_CreateInterp is available.
+	(KRB5_AC_CHECK_INET6): Don't require getaddrinfo support.
+
+2001-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_CHECK_INET6): Don't check for
+	AI_ADDRCONFIG.
+
+2001-07-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4: Fix typo in last change. Do not get rid of 
+	spaces in definitions.
+	
+2001-07-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4: Add functions KRB5_GETSOCKNAME_ARGS and
+	KRB5_GETPEERNAME_ARGS to elucidate the argument types to
+	getsockname() and getpeername().
+
+2001-07-23  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Build gssftp client on Win32.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (CHECK_WAIT_TYPE): Need to include sys/types.h for
+	initial test or pid_t might not be defined.
+
+2001-07-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (CHECK_WAIT_TYPE): Improved testing if wait uses int
+	or struct union as an argument. Tests if a prototype conflict
+	exists with int being used, and if so, falls back on the old test.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Display test for host type and
+	result so that "cached" is not simply output from configure.
+	(KRB5_NEED_PROTO): Add optional third argument, which if set means 
+	to test for prototype even if configure script does not test for
+	function. 
+	
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* acconfig.h: Add HAVE_REGCOMP.
+
+	* aclocal.m4 (KRB5_AC_NEED_LIBGEN): Determins if libgen is really
+	needed to be linked with executables by determining if regcomp()
+	is missing or non-functionl and then if compile/step will be used.
+	(KRB5_AC_REGEX_FUNCS): Rewritten to require KRB5_AC_NEED_LIBGEN.
+	(KRB5_BUILD_PROGRAM): Use KRB5_AC_NEED_LIBGEN instead of testing
+	for compile in libgen.
+	
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (KRB5_NEED_PROTO): Determines if the OS provides a
+	prototype for a function - and if not, allows us to define it.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5-config.in (CC_LINK): Use ' vs " to prevent bash expansion of
+	variables. 
+	(LIBS): Quote autoconf substitution in case of space being present. 
+
+2001-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (CONFIG_RULES): Set and substitute AUTOHEADER and
+	AUTOHEADERFLAGS.
+
+2001-05-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5-config.in: New script for providing linker and compiler
+	information for applications.
+
+	* patchlevel.h: Update to current release. Mkrel script generates
+	this in distribtions.
+
+	* configure.in: Add support for parsing patchlevel.h into a
+	useable form for krb5-config. Generate krb5-config from
+	krb5-config.in. Add KRB5_BUILD_PROGRAM for variable substitution. 
+ 
+	* Makefile.in: Add support for building and installing krb5-config.
+
+2001-05-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (WITH_CC, WITH_CCOPTS): Autoconf 2.50 fix. Change
+	from define to AC_DEFUN. Autoconf warns of use of AC_REQUIRE
+	outside such as environment.
+
+2001-04-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (DECLARE_SYS_ERRLIST): Check for sys_nerr with an
+	expression that can't be optimized away.
+	(KRB5_INIT_CCOPTS): New macro.
+	(WITH_CC): Add gcc warning flags to CCOPTS instead of CC.  Add
+	option -Wno-comment to stop gcc from complaining about SunOS
+	system header files.  Call AC_REQUIRE on KRB5_INIT_CCOPTS.
+	(WITH_CCOPTS): Add to CCOPTS instead of simply assigning to it.
+	Call AC_REQUIRE on KRB5_INIT_CCOPTS.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* acconfig.h (KRB5_NO_PROTOTYPES, KRB5_PROVIDE_PROTOTYPES,
+	KRB5_NO_NESTED_PROTOTYPES): Deleted.
+	* aclocal.m4 (HAS_ANSI_VOLATILE, KRB5_CHECK_PROTOS): Deleted.
+	(KRB5_AC_INET6): Don't look for getipnodebyname, getipnodebyaddr.
+
+2001-04-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* acconfig.h (HAVE_SOCKLEN_T): Add.
+	(HAS_VOID_TYPE): Delete.
+
+2001-04-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unixmac): Target deleted.
+
+2001-04-11  Ezra Peisach  <epeisach@rna.mit.edu>
+
+	* aclocal.m4 (WITH_CC): Reorganize test: Do not use cache variable
+	that conflicts with an autoconf internal variable (prefix with
+	krb5_ instead of ac_). Ensure that the first time AC_PROG_CC is
+	invoked, is not within a conditional cache block. Autoconf 2.49
+	only include the compiler test code once in the configure script
+	instead of everytime it is seen. 
+
+Fri Feb 16 16:23:25 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Add $(datadir) to INSTALLMKDIRS for util/et.
+
+2001-01-28  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_AUX): Smash some shared lib file extensions
+	so that AIX doesn't break, since static and shared libs are
+	mutually exclusive on AIX.
+
+2001-01-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* acconfig.h (HAVE_SA_LEN): Undef.
+
+	* configure.in: Call AC_REQUIRE_CPP before checking for GCC, to
+	ensure that we always set $CPP.
+
+2000-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_INET6): Ensure that we check for sa_len
+	field.
+
+2000-12-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_INET6): Look for netdb.h.
+	(KRB5_AC_CHECK_INET6): Require <netinet/in.h>, <netdb.h>,
+	inet_ntop, getaddrinfo, AF_INET6, several NI_* macros,
+	AI_ADDRCONFIG, and AI_NUMERICHOST.  This should be a reasonable
+	test for conformance to certain parts of RFC2553, giving us
+	reasonable generic sockaddr/hostname processing.
+	(WITH_CC): Don't use -Wtraditional, we're always assuming ANSI
+	mode now.
+
+2000-11-01  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (CONFIG_RULES): Quote AUTOCONFFLAGS properly.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: If the cache_file is /dev/null (autoconf 2.49),
+	set it to config.cache.
+
+	* aclocal.m4 (V5_SET_TOPDIR): In newer versions of autoconf
+	(2.49), AC_LOCALDIR is not set by the reconfiguration process. If
+	AC_LOCALDIR is not set, try to find the top of the tree by looking
+	for aclocal.m4. If aclocal.m4 ever exists in a subdir, we will
+	need to redo this test.
+
+	* aclocal.m4: Upgrade to autoconf 2 naming schemes - AC_C_CONST,
+	AC_CHECK_HEADER, AC_PROG_LN_S, AC_MSG_ERROR instead of AC_CONST,
+	AC_HEADER_CHECK, AC_LN_S, AC_ERROR. Use AC_DEFUN instead of
+	define() for macro definitions and better quoting of macros within
+	macros.
+	
+2000-10-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (AC_LIBRARY_NET): Newer versions of autoconf are more
+	sensative to using macros within macros without quoting. Quote
+	AC_CHECK_LIB calls within AC_CHECK_LIB macro.
+
+2000-10-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (ac_config_fragdir): Set AUTOCONFFLAGS to use the
+	local util/autoconf macrodir if we are using the shipped autoconf.
+
+2000-08-30  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (LIBLINKS): Fix appending of $EXTRA_LIB_TARGETS to
+	LIBLINKS; previously it was setting LIBLINKS to include $LIBLIST
+	instead, which is Just Wrong.
+
+2000-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_AUX): Fold in values of EXTRA_LIB_TARGETS,
+	EXTRA_LIBLINK_TARGETS, EXTRA_LIBINST_TARGETS set in shlib.conf.
+	Substitute EXTRA_CLEAN_TARGETS and EXTRA_CLEAN_LINKS.
+	(KRB5_LIB_PARAMS): Substitute LIB_LINK_OPT.
+
+2000-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_CHECK_INET6): Require "struct
+	sockaddr_storage" for IPv6 support.
+
+2000-08-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (CHECK_SIGPROCMASK): Check for posix sigprocmask
+	before a potential bsd compatible sigmask.
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Compile .et file for krb524.
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove references to now defunct directories
+	lib/krb5/ccache/{file,memory,stdio}.
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add ms2mit and krb524 Makefile creation to Windows
+	build preparation.
+
+2000-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Moved bulk of the work into
+	config/shlib.conf.
+	(K5_AC_CHECK_FILES): Require AC_PROG_CC be run first.
+	(WITH_CC): If we're using gcc, enable a bunch of warning options.
+
+2000-07-01  Tom Yu  <tlyu@mit.edu>
+
+	* acconfig.h: Add function replacement renaming symbols for
+	util/db2/include/config.h.in.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (CC_LINK_STATIC): Another fix for freebsd shared libs
+	from David Cross.
+
+2000-06-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_DNS): Rewrite to fix logic.  Now
+	--enable-dns-for-XX really will be heeded for setting default
+	behavior.  Also, DNS support can now be compiled in while still
+	turned off by default.  Print out whether the DNS support will be
+	compiled in.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Fix freebsd CC_LINK_SHARED to have correct rpath
+	flags.  Thanks to David Cross.
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Don't need to display "checking"
+	message for AC_CANONICAL_HOST, it does that itself.
+
+2000-06-23  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (CC_LINK_STATIC): Fix to use old library search
+	order; otherwise if there are shared libraries with the same name
+	elsewhere in the search path, they'll take precedence over the
+	static ones in the tree.
+	(AC_KRB5_TCL_TRYOLD): Search by appending stuff to CPPFLAGS and
+	LDFLAGS to notice if there may be problems with stuff earlier
+	along in either variable overriding.
+
+2000-06-23  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* wconfig.c (main): Warn if copying command-line option string
+	will overflow internal buffer.
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_DNS): Set RESOLV_LIB, and substitute
+	it into the Makefile.
+	(AC_LIBRARY_NET): Set RESOLV_LIB.
+
+	* aclocal.m4 (KRB5_AC_ENABLE_DNS): Check for dns, dns-for-kdc, and
+	dns-for-realm separately.  Define KRB5_DNS_LOOKUP if either mode
+	is enabled.  Define KRB5_DNS_LOOKUP_KDC and KRB5_DNS_LOOKUP_REALM
+	if the appropriate modes are enabled.
+	* acconfig.h (KRB5_DNS_LOOKUP_KDC, KRB5_DNS_LOOKUP_REALM): Undef.
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Check for alpha*-dec-osf* instead
+	of alpha-dec-osf*.
+
+2000-05-05  Wilfredo Sanchez <tritan@mit.edu>
+
+	* config/pre.in: Set KRB5_INCDIR from @includedir@ so configure
+	--includedir=foo works.
+
+	* aclocal.m4 (Darwin): Settle on LIBMAJOR as compat
+	version. Change "-dylib_foo=X" options to "-foo X", which actually
+	work. Specify -install_name path.
+
+2000-05-04  Wilfredo Sanchez <tritan@mit.edu>
+
+	* Makefile.in: kadmin server binaries install into SERVER_BINDIR
+	instead of ADMIN_BINDIR. (The default is the same for both, though
+	in BSD layouts SERVER_BINDIR should be /usr/libexec, not
+	/usr/sbin.)
+
+2000-05-02  Wilfredo Sanchez <tritan@mit.edu>
+
+	* config.guess, config.sub: Clean up Rhapsody and Mac OS X guesses.
+	Use powerpc-apple-darwin1.x on Mac OS X.
+
+	* aclocal.m4: Clean up to Rhapsody/Darwin compile options:
+	- Set the compatibility version of libraries to 0.1 for now so
+	binaries don't blow up every time a new library version rolls
+	out. We can add a compat variable to the lib makefiles if we think
+	this is needed.
+	- Don't forget LDFLAGS in CC_LINK_* and LDCOMBINE macros. This is
+	probably a good idea for all platforms. We'll need it in Darwin
+	for building multi-architecture binaries.
+	- The default for SHOBJEXT works, so there is no need to define it
+	again.
+
+2000-04-18  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in (clean-windows): Actually clean gss-sample on Windows.
+
+2000-04-11  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in (clean-windows): Clean gss-sample on Windows.
+
+2000-03-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_AC_ENABLE_DNS): Fix typo that caused the DNS
+	code to never get enabled.
+
+2000-03-01  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Tweak the HPUX shared lib build some more.  Don't
+	use $(INSTALL_PROGRAM) for shared libs, since it strips them!  We
+	should fix this at some point.
+
+	* aclocal.m4: Add support for setting the INSTALL_SHLIB variable.
+	Tweak the HPUX shared lib build somewhat.
+
+2000-02-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Add enable-kdc-replay-cache arg, to make usage
+	message more complete.
+
+2000-02-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4: Define DES425_LIB and DES425_DEPLIB all the time. We
+	build the des425 library all the time and these need to be define
+	for "make check."
+
+2000-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Kludge in the old test for tcl so that we have some
+	prayer of pulling in tcl from the funky installation that goes
+	along with dejagnu.
+
+2000-02-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): Change test syntax a
+	little to keep bash happy.
+
+2000-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Add support to substitute KRB524_LIB in places.
+
+2000-02-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Build gss-sample on Windows.
+
+2000-01-26  Ken Raeburn  <raeburn@raeburn.org>
+
+	* aclocal.m4 (KRB5_AC_REGEX_FUNCS): Require AC_PROG_CC instead of
+	invoking obsolete AC_C_CROSS.
+	(KRB5_LIB_PARAMS): Use AC_MSG_CHECKING, not AC_CHECKING.
+
+	* aclocal.m4 (AC_KRB5_TCL_FIND_CONFIG): New macro, looks for
+	installed tclConfig.sh file and extracts library name and other
+	information from it.
+	(AC_KRB5_TCL): Rewrite, uses AC_KRB5_TCL_FIND_CONFIG.
+
+	* aclocal.m4 (AC_LIBRARY_NET): Require KRB5_AC_ENABLE_DNS, and if
+	it's enabled, pull in res_search from -lresolv if needed.
+	(KRB5_AC_ENABLE_DNS): New macro, just implements argument
+	checking, and may define KRB5_DNS_LOOKUP C macro.
+	* acconfig.h (KRB5_DNS_LOOKUP): Undef.
+
+	* aclocal.m4 (KRB5_AC_INET6): Add enable/disable-ipv6
+	configure-time options; by default, enable it only if support code
+	is available.
+	(KRB5_AC_CHECK_INET6): Moved part of old KRB5_AC_INET6 here.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: On Windows, build error tables if we believe awk
+	is present.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Make Windows Makefile target creation atomic.
+	Build clients/kvno for Windows.  Also pull from 1.1 branch: Add
+	install target for windows.  Remove references to unused mit
+	directory.
+
+1999-11-02  Ken Raeburn  <raeburn@raeburn.org>
+
+	* aclocal.m4 (KRB5_AC_INET6): New macro.
+	* acconfig.h (KRB5_USE_INET6): Undef.
+
+1999-10-26  Wilfredo Sanchez <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Treat Rhapsody like Mac OS 10.
+	For both, add "-undefined warning" when building shared libs, and
+	remove "-static" from CC_LINK_STATIC.
+
+1999-08-27  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add some missing dirs needed for generating a proper
+	kerbsrc.zip.  Make krbsrc83.zip obsolete.
+
+1999-08-13  Brad Thompson  <yak@mit.edu>
+
+	* aclocal.m4: Added MacOS X shared library support.
+
+1999-08-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Build kpasswd under windows.
+
+1999-07-22  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-mkdirs): Use mkinstalldirs rather than
+	mkdir -p for portability reasons.
+
+1999-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Delete old and already disabled code relating to
+	shared library support.
+
+1999-06-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Create Makefile.in for srvtab keytab code during
+		win32 build.
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+		Move definition of WCONFIG into config/win-pre.in.  Use
+		symbolic name for output dir dependency when building
+		wconfig.  Remove wconfig clean stuff since we do it
+		automagically in win-post.in.  Build util instead of
+		directly building util/windows, util/et, util/profile.
+
+Mon May 17 20:45:54 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in, wconfig.c: Rename config/windows.in to 
+		config/win-pre.in.
+
+Mon May 17 12:20:43 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove win16 support for cleaner win32.  Build
+		wconfig under arch-specific subdirs.  Update clean-windows
+		directories to reflect current all-windows directories.
+		Add distclean-windows target.
+
+Mon May 10 18:56:11 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Back out win16/win32 change.  Does not
+		work from clean.  Must wait until win32-only to
+		remove /AL flag.
+
+Mon May 10 15:07:11 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Change wconfig build so win16 flags are not used
+		for win32 build.
+
+Mon Feb  8 21:42:44 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Change Windows kerbsrc.zip target so this now does
+		what kerbsrc-nt.zip used to do.  We no longer support
+		building krb5 on systems with 8.3 limitations.  Also allow
+		binary files in windows/lib to be included into
+		kerbsrc.zip file.
+
+Wed Jan 27 17:10:18 1999  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Fix typo so that lib/crypto actually gets
+ 	configured.
+
+1999-01-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, configure.in: Move the responsibility for
+		generating Makefile files for the following subdirectories
+		to the top-level: util, util/send-pr, util/dyn, lib,
+		config-files, and gen-manpages.  
+
+1999-01-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* wconfig.c: Updated to be more featureful.  It will now save the
+		arguments passed to it and emit it as a makefile variable
+		WCONFIG_FLAGS.  This allows the makefile to be able to
+		preserve wconfig options in the future when updating
+		makefile.  Also added the --win32 and --win16 options to
+		force win16 or win32 makefiles.  An option of the form
+		--enable-foo will cause lines that begin ##FOO## to be
+		uncommented in the Makefile.  The program has also been
+		cleaned up so it can be run (for debugging purposes) under
+		Unix.
+
+Sat Dec  5 01:14:23 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Updated windows configuration rules to work with
+		the new crypto library.  (Including bundling the correct
+		directories into kerbsrc-nt.zip)
+
+1998-11-14  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4: Add support for FreeBSD systems using ELF (and not
+		just a.out systems).  Also remove the definition for
+		the KRB5_POSIX_LOCKS test, since it is no longer needed.
+		(See ChangeLog for lib/krb5/os/lock_file.c for more details.)
+
+1998-09-22  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4 (AC_PROG_LEX): Autoconf "fixed" AC_PROG_LEX long
+		ago.  Our own local version is no longer necessary.
+
+Wed Sep 23 15:24:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_AUX): Do what Sam originally meant to do by
+	moving the explicit resetting of DEPLIB=$SHLIBEXT and forcing
+	SHLIBEXT=.so-nobuild to avoid duplicate rules on AIX and such.
+
+1998-08-24  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Add support to build the lib/krb5/ccache api
+		directory and include it in the Windows kerbsrc-nt.zip
+		file.
+
+Wed Aug 19 20:14:31 1998  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_AUX): Back out Sam's change to reorder the
+ 	"force_static" logic, as it would cause problems where a
+ 	forced-static library is built in the same directory as a
+	program, due to explicit setting of CC_LINK, etc.
+
+Mon Aug 17 18:10:29 1998  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Fix Sam's fixes (variable capitalization).
+
+Wed Jul  8 01:10:44 1998  Matthew D Hancher  <mdh@mit.edu>
+
+	* aclocal.m4: Allow shared libraries to build properly under Irix
+ 	6.x with gcc. (This is actually a fix of a previous fix that
+ 	didn't make it into ChangeLog.)
+
+Thu Jul  2 20:41:02 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Update commands to build the Macintosh MPW Makefile
+
+1998-07-05    <hartmans@fundsxpress.com>
+
+	* aclocal.m4 (enable_shared): If we aren't building shared, then
+	make sure that SHLIBEXT and friends are not set so that we don't
+	break on AIX and anything else where STLIBEXT == SHLIBEXT
+
+1998-05-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Don't depend on $(RM) macro being defined when
+		building kerbsrc-nt.zip
+
+	* Makefile.in: include krb5/ccache/memory and windows/lib in
+		the list of directories built by the Windows build.
+		When building kerbsrc-nt.zip, put a copy of mkbin.bat
+		in the top-level build directory.  Fix bug in
+		kerbsrc-nt.zip building where it wasn't creating the
+		initial Makefile (although the dos-zipfiles target did
+		the right thing).
+
+1998-05-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Remove "untested" comment from
+		freebsd.  Add section for openbsd.
+
+Sun May 24 22:09:12 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Remove lib/kadm and lib/krb5/free from the list of
+ 		directories supported by windows (since they have since
+ 		gone away).
+
+	* aclocal.m4: Added suggested changes to improve HP-UX's support
+	 	for shared libraries.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4 (CONFIG_RELTOPDIR): Add support for generic file
+		existence tests (used to simplify some configure.in
+		files.)
+
+Sun Mar  1 22:22:50 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4: Remove unused variables BUILDTOP and SRCTOP (now
+ 		defined in the individual Makefile.in file.  Define
+ 		@AUTOCONF@ to have the appropriate pathname (either
+ 		internal to our source tree, or in the user's path).  Set
+ 		@CONFIG_RELTOPDIR@ to contain the relative path to the top
+ 		of the build directory from the directory containing the
+		configure script.
+
+Fri Feb 27 21:43:41 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4 (KRB5_AC_REGEX_FUNCS): Take the regular expression
+		function code from lib/krb5/os/configure.in and turn it
+		into a generalized regular expression function tester.
+
+Wed Feb 18 15:23:08 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (thisconfigdir): Remove trailing slash from
+	thisconfigdir.
+
+Fri Feb 13 15:10:41 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4: Rename K5_OUPUT_FILES to K5_AC_OUTPUT, and leave a
+		compatibility macro behind for K5_OUTPUT_FILES.  This is
+		needed because autoreconf greps for AC_OUTPUT.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+Wed Jan 28 18:09:00 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* aclocal.m4: Removed the following (obsolete) functions:
+		LinkFile, LinkFileDir, CopySrcHeader, CopyHeader,
+		Krb5InstallHeaders, AppendRule, AC_PUSH_MAKEFILE,
+		AC_POP_MAKEFILE, CONFIG_DIRS, DO_SUBDIRS, USE_*_LIBRARY
+
+Tue Oct 28 11:49:55 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (WITH_NETLIB): Use AC_LIBRARY_NET.
+	             (AC_LIBRARY_NET): Written by jhawk@mit.edu to 
+		    	better determine if libsocket and libnsl are needed.
+
+Thu Oct 23 12:08:24 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (TCL_WITH): Check for libtcl8.0.
+
+Wed Oct 22 15:03:26 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL): Rewritten for clearer
+	 	understanding. Check for libtcl7.6 and tcl/tcl.h.
+
+Mon Oct 13 10:14:06 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add KRB5_LIB_AUX so configure --help gives info on
+        shared libraries.
+
+Tue Oct  7 08:05:43 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): For the alpha, revert RUN_ENV
+        change as the dejagnu/Makefile.in can now deal with the older
+        quoting scheme and makes this version more readable.
+
+Tue Sep 30 18:56:37 1997  Tom Yu  <tlyu@mit.edu>
+
+	* acconfig.h: Punt HAS_STDLIB_H, NO_STDLIB_H, POSIX_TYPES.
+
+Thu Sep 25 21:06:40 1997  Tom Yu  <tlyu@mit.edu>
+
+	* acconfig.h: Punt HAS_SETVBUF, HAS_UNISTD_H, KRB5_USE_INET.
+
+Thu Sep 18 17:51:39 1997  Tom Yu  <tlyu@mit.edu>
+
+	* acconfig.h: Remove USE_STRING_H, HAS_STRDUP, HAS_LABS
+
+Mon Aug 18 11:28:25 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): For the alpha, RUN_ENV needs to
+ 	have sed expression in single quotes unstead of double to deal
+ 	with a shell quoting bug in the dejagnu test suite.
+
+Tue Aug 12 11:09:30 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (WITH_HESIOD): Fix --with-hesiod support to DTRT if
+	        the option is not specified.
+
+Tue Aug 12 08:58:11 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (MACFILES): Remove mac/gss/* as it does not exist.
+
+Mon Aug 11 21:16:50 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_BUILD_LIBRARY_STATIC): Fix up some things so
+	that this macro actually works; it's still necessary to precede a
+	call to KRB5_BUILD_LIBOBJS with a call to
+	KRB5_BUILD_LIBRARY_STATIC, though.  Basically if you AC_DEFUN
+	something that produces shell code and then calls a macro that
+	AC_REQUIREs something else, then all the AC_REQUIREd stuff ends up
+	coming *before* the shell code in the first macro.  I'm not sure
+	there's a reasonable workaround, or whether this can even be
+	considered to be a bug.
+
+Wed Aug  6 20:25:49 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Add support for --with-hesiod (and add it to
+	CONFIG_RULES, as it's needed almost everywhere kadm5 gets
+	linked).
+
+Wed Jun 11 16:46:47 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (MACFILES): Added the mac/gss files to the Macintosh
+		tar file.
+
+Fri Apr 18 11:38:51 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (CLEANUP): Add MIT files to the windows zip file (if
+		the mit directory exists)
+
+Thu Apr 17 16:15:15 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* wconfig.c (main): Add arguments to allow specification of
+		the --mit, --nomit, --ignore=XXX options.
+
+Fri Mar 28 02:18:20 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_AUX): add lib$(LIB)$(SHLIBVEXT) to the list
+	of libraries that get symlinked into $(TOPLIBD).  This allows
+	linkers that look for libfoo.so.maj.min rather than libfoo.so at
+	link time to work, e.g. NetBSD/i386.
+
+Wed Mar 19 15:43:27 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Fix up Macintosh and Windows build rules now that
+		the top-level Makefile doesn't exist any more.
+
+Mon Mar 24 13:49:15 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: (KRB5_LIB_PARAMS): Add support for HP/UX, FreeBSD,
+	and SNI, ported from the old top-level configure.in.  These are
+	not tested yet.
+
+Fri Mar 21 15:12:46 1997  Tom Yu  <chaoself@avalanche-breakdown.mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Add support for mips-dec-netbsd.
+
+Sun Mar  9 22:29:31 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Add provisions to make major version number
+	compatibility work for shared libaries.
+
+Sat Feb 22 20:50:49 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4 (CC_LINK_STATIC): Added RUN_ENV line for Linux
+
+Fri Feb 21 15:58:55 1997  Sam Hartman  <hartmans@mit.edu>
+
+	* aclocal.m4 (CC_LINK_STATIC): Define appropriate flags to build
+ 	shared libs on AIX.
+
+Fri Feb 21 12:00:53 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* aclocal.m4 (CC_LINK_SHARED): Linux doesn't understand -R; use
+		"-bWl,-rpath -Wl,$(PROG_RPATH)" instead.
+
+
+Sun Feb 16 21:17:11 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Build krb4 library under win16/win32
+
+Fri Feb 14 15:52:14 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Add shared library support for Irix.
+
+	* configure.in: inactivate the old case statement that determined
+	shared lib parameters; keep it around just for reference, though.
+
+Wed Feb 12 16:17:44 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Remove INSTALL_VARIABLE_HACK, as it's no longer
+	needed in autoconf 2.12.
+
+Mon Feb 10 11:30:56 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Set CC_LINK_STATIC for platforms
+		w/o shared library support.
+		     (KRB5_LIB_AUX); Set CC_LINK if --enable-shared is not
+		specified.
+
+Mon Feb  3 00:11:37 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in:
+		awk-windows-mac: Only rebuild based on what has changed
+
+Mon Dec 30 13:39:46 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4: Add AC_PREREQ(2.12) as we now require autoconf 2.12.
+		[krb5-build/289]
+
+Sun Feb  9 01:01:32 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Fix up RUN_ENV for alpha-dec-osf*
+	so that we don't try to set _RLD_ROOT before setting
+	LD_LIBRARY_PATH (which needs to call sed).
+
+Sat Feb  8 15:39:08 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Fix up AC_KRB5_TCL somewhat to deal with
+	--with-tcl=pathname properly.
+
+	* aclocal.m4 (KRB5_RUN_FLAGS): Convert to no longer use old cache
+	variable kludge.
+	(KRB5_LIB_AUX): Set CC_LINK to CC_LINK_SHARED or CC_LINK_STATIC,
+	depending on whether we're building with shared libraries.
+
+Wed Feb  5 21:03:41 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL): Fix up to work better with new program
+	build procedure.
+
+	* aclocal.m4 (WITH_KRB4): Fix up KRB4_INCLUDES to look in the
+	build tree as well.
+
+Mon Feb  3 23:27:57 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Check for -lgen properly.
+
+Sat Feb  1 08:27:19 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4: CC_LINK for alpha changed -R to -Wl,-rpath....
+
+Fri Jan 31 21:48:08 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Some WITH_KRB4 tweaks.
+
+Mon Jan 27 17:12:13 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Add KRB5_BUILD_PROGRAM and
+	KRB5_BUILD_LIBRARY_STATIC.
+
+Sun Jan 26 22:37:16 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4:: Remove V5_MAKE_SHARED_LIB, V5_SHARED_LIB_OBJS
+
+Fri Jan  3 22:30:05 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Alter conventions for libraries with dependencies;
+	make a separate macro, KRB5_BUILD_LIBRARY_WITH_DEPS, that adds in
+	the flags for explicit library dependencies.
+
+Thu Jan  2 18:21:22 1997  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Add SunOS support (untested yet); add support for
+	explicit dependencies in libraries.
+
+Wed Jan  1 23:31:22 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4 (KRB5_LIB_PARAMS): Add linux shared library
+		support. Fix Solaris cc soname naming.
+
+Mon Dec 30 12:58:37 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* aclocal.m4: For alpha*, update the local copy of the
+		so_locations registry.  
+
+Sun Dec 29 21:22:21 1996  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Add support for installing libraries.
+
+Fri Dec 27 16:54:41 1996  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Fix up solaris shared lib generation flags.
+
+	* aclocal.m4: Many changes.  Add KRB5_LIB_PARAMS,
+	KRB5_BUILD_LIBRARY, KRB5_BUILD_LIBOBJS, which do the obvious
+	things.  Change V5_AC_OUTPUT_MAKEFILE to use $krb5_prepend_frags
+	and $krb5_append_frags to make life easier when we have multiple
+	frags that aren't pre.in or post.in.
+
+Tue Dec 24 16:08:05 1996  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (V5_AC_OUTPUT_MAKEFILE): Fix to deal with the
+	autoconf-2.12 syntax for file concatenation.
+
+Tue Dec 17 13:54:48 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (kerbsrc.mac.tar): Automatically make the
+ 		mac-bin-dirs target so that the binary directories are
+ 		correctly created.
+	
+Mon Nov 25 19:42:53 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Comment out distclean and realclean so no one will
+	be tempted to use them. [PR 222]
+
+Fri Nov 22 23:51:07 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: All changes for the Macintosh port.  Translate '%'
+ 		characters in Macfile.tmpl to '/' characters.  Include the
+ 		mac/SAP directory in the kerbsrc.mac.tar tarball.  Rename
+ 		the kerbsrc.tar tarball to kerbsrc.mac.tar, so that the
+ 		target name in the Makefile matches the taget which is
+ 		actually generated.  Use mac/mkbindirs.sh to build the
+ 		binary hierarchy for the Macintosh build process.
+
+Wed Nov 20 13:28:00 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (awk-windows-mac): Copy gssapi.hin to gssapi.h to
+		make Win16 build work.
+
+Thu Nov  7 23:55:02 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* aclocal.m4 (LinkFileDir, LinkFile): AC_REQUIRE the AC_LN_S macro
+	to avoid gratuitous rechecks.
+
+Thu Nov  7 14:26:25 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (Macfile): Correctly build the file lists for the
+		Macintosh 68K and PPC object file lists.
+
+Tue Nov  5 17:27:30 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-recurse): Add dependency of install-recurse
+	on install-mkdirs to force directories to be made first.
+
+Fri Nov  1 20:41:07 1996  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_KRB5_TCL): Check for -ldl when checking for -ltcl
+	or -ltcl7.5 in case the TCL library needs it. [krb5-admin/141]
+
+Thu Oct 31 10:57:29 1996  Ezra Peisach  <epeisach@trane.rose.brandeis.edu>
+
+	* aclocal.m4 (db_lib): Use relative path to libdb.a file.
+
+Mon Oct 21 21:19:53 1996  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4: Fix CopySrcHeader and CopyHeader so they actually
+	generate dependencies for the files they're copying to.  Also, fix
+	up DO_SUBDIRS to work with new recursion methods.
+
+Mon Oct  7 15:07:38 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add AC_KRB5_TCL so configure --help is useful.
+
+	* aclocal.m4 (AC_KRB5_TCL): Added tests for --with-tcl. 
+
+Fri Sep  6 20:23:13 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* patchlevel.h (KRB5_MAJOR_RELEASE): Update patch level file for
+		Beta 7 release.
+
+Fri Sep  6 15:48:05 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: remove admin subdir
+
+Fri Aug 30 22:58:19 1996  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (DECLARE_SYS_ERRLIST): Fix up to look for sys_errlist
+		in both errno.h and libc.
+
+Thu Aug 15 17:10:58 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Remove top-level calls to WITH_ANAME_DB and
+		WITH_KDB_DB. 
+
+	* aclocal.m4 (WITH_ANAME_DB, WITH_KDB_DB): Remove --with-aname-db
+		and --with-kdb-db since we're not using any of them.
+
+Thu Aug 15 20:00:15 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* acconfig.h: Remove line with ODBM as definition no longer is
+		used in the tree.
+
+Fri Jul 26 15:07:51 1996  Marc Horowitz  <marc@mit.edu>
+
+	* aclocal.m4 (LIBS): include -lgen if compile() is present and
+ 	-lkrb5 is used.
+
+Tue Jul 23 00:36:46 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* acconfig.h: Add contents of util/db2/acconfig.h so that
+		util/reconf works correctly.
+
+Thu Jul 18 19:12:02 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: $krb524 works with the admin system, now
+
+Tue Jul  9 14:32:14 1996  Marc Horowitz  <marc@mit.edu>
+
+	* aclocal.m4 (USE_ANAME, USE_KDB5_LIBRARY, KRB5_LIBRARIES): change
+ 	these macros so that db (as provided in util/db2) will *always* be
+ 	used.
+
+	* configure.in (CONFIG_DIRS): removed $kadminv4 and $krb524 for
+ 	now, since they don't work with the new admin system.  this needs
+ 	to be fixed.
+
+	* aclocal.m4 (WITH_KRB4): create new substituted variable
+ 	KRB4_INCLUDES, which is conditional on internal vs external vs no
+ 	krb4.
+	(USE_KADMCLNT_LIBRARY): added.
+	(KRB5_LIBRARIES): this macro didn't have any clue how to deal with
+ 	multiple executeables built in the same dir with different
+ 	libraries.  it does now, at least for what the admin system needs.
+	(V5_MAKE_SHARED_LIB): this macro currently uses the LIB_SUBDIRS
+ 	make var to find the directories to build the shared library in.
+  	This adds an optional fifth argument which is used in conjunction
+ 	with LIB_SUBDIRS for that purpose.  Now, both kadm5 libraries can
+ 	be built in the same directory.
+
+Mon Jun 17 18:34:10 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* aclocal.m4 (CHECK_DB): explicitly set $LIBS before calling
+		AC_CHECK_DBM_PROTO so that if a dbm lib is found it is
+		linked against while checking for function existence.
+		This may need some more testing.
+
+Fri Jun 14 13:10:26 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* aclocal.m4 (USE_KRB4_LIBRARY)): Include appropriate include
+ 	files for the krb4 library we are actually using.  This way,
+ 	KEYFILE is a constant string if we are using Athena Kerberos libs.
+	(LDFLAGS): Force TOPLIBD to be expanded in the configure script
+ 	for LDFLAGS, so they are valid for autoconf AC_HAVE_FUNCS
+	tests. Note you cannot actually use libraries out of the top level
+	library directory; this just gets around some gcc complaints with
+	$(TOPLIBD) not being a bvalid path.
+
+Thu Jun 13 23:03:03 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* aclocal.m4: break some stuff out into pre.in and post.in in
+		preparation for doing away with PUSH_MAKEFILE cruft
+
+
+Wed Jun 12 15:27:14 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (AC_CHECK_DBM_PROTO): Correct to use correct cache
+		variable in test.
+
+Wed Jun 12 19:41:12 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* aclocal.m4: use new AC_OUTPUT syntax for constructing
+		Makefile.tmp
+
+Wed Jun 12 00:23:51 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (makefile-windows): Build the makefiles for
+		windows/cns, windows/gss, and windows/wintel.  Add
+		definition of BUILDTOP when building for DOS, since it's
+		needed for $(RM) to work.  When creating ./Makefile under
+		Unix, run things through sed to strip out ##DOS from the
+		beginning of lines.
+
+Mon Jun 10 17:11:45 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* wconfig.c: Revamp program to make it more extensible.  Now will
+ 	 	uncomment lines that begin "##DOS##" as well as
+ 	 	"##WIN16##" or "##WIN32##", depending on whether we are
+	 	compiling on a Windows 16 or Windows 32 environment.
+		Also, we now perform this transformation on the windows.in
+	 	and win-post.in files as well.
+
+Sat Jun  8 10:01:11 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4: Remove WITH_KDB4 and USE_KDB4_LIBRARY support
+
+Fri Jun  7 17:39:45 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (makefile-windows): Use full directory
+		name "error_tables" when building under Windows so that
+		the build will work correctly under VFAT and NTFS
+		filesystems.  Build the "makefile" file so that it
+		includes config/win-post.in.
+		
+Thu Jun  6 00:04:38 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Don't pass $(LIBCMD) on the command
+		line.  It's set in the windows.in prologue for all Makefiles anyway.
+
+	* patchlevel.h (KRB5_MINOR_RELEASE): Update patchlevel for Beta 6 release.
+
+	* Makefile.in (FILES): Include lib/crypto/sha/* in list of files
+		to be built for Windows and the Macintosh.
+		(makefile-windows): Build lib/crypto/sha/makefile for Windows
+
+Tue Jun  4 12:00:25 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4 (KRB5_LIBRARIES): Always do USE_ANAME if kdbm_deplib
+		is not defined, since in shared library situations we may
+		need to resolve all undefined symbols.  (We don't do
+		USE_ANAME if kdbm_deplib is defined because the db library
+		used for kdb may be different from the one used for the
+		aname work.  This is a bit of an ugly botch, but it will
+		work for now.)
+
+Wed May 29 18:39:21 1996  Tom Yu  <tlyu@mit.edu>
+
+	* aclocal.m4 (AC_CHECK_DBM_PROTO): sense of arguments to be
+		evaluated was reversed
+
+Mon May 20 17:56:15 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4 (CHECK_DB): Remove vestigal support for ODBM.  
+
+Tue May 14 21:56:08 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (AC_CHECK_DBM_PROTO): Arguments were not executed if
+		using cached results.
+
+Tue May  7 22:56:46 1996  Marc Horowitz  <marc@mit.edu>
+
+	* aclocal.m4 (V5_AC_OUTPUT_MAKEFILE): add a second optional
+ 	argument to specify files besides Makefile.in which should be
+ 	configureified.
+	* aclocal.m4 (USE_KADM_LIBRARY): removed.
+	* aclocal.m4 (USE_KADMSRV_LIBRARY, USE_GSSRPC_LIBRARY,
+ 	USE_GSSAPI_LIBRARY, USE_DYN_LIBRARY, USE_DB_LIBRARY): added.
+
+Tue Apr 30 23:25:07 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* Makefile.in (tgz-bin, pkgdir): New targets.
+	(PKGDIR, GZIPPROG): New variables.
+
+	* aclocal.m4 (WITH_NETLIB): Don't look for socket lib on Irix.
+
+	* aclocal.m4 (MAKE_SUBDIRS): Disable hack that tries to determine
+	if "-k" or "-i" was given.
+
+Wed Apr 24 03:49:06 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (V5_USE_SHARED_LIB): Remove another dependency in the
+		executables on the build tree.
+
+Wed Apr 17 13:24:02 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* .Sanitize: Removed kadmin.old from list of things to keep.
+
+Fri Mar 29 12:40:59 1996  Richard Basch  <basch@lehman.com>
+
+	* configure.in: Added SunOS shared library support
+
+Tue Mar 19 22:40:59 1996  Richard Basch  <basch@lehman.com>
+
+	* configure.in: do not bother with kadmin.old
+
+Mon Mar 18 21:33:15 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (KRB5_RUN_FLAGS): Allows for setting of proper paths
+		for executing programs in the build tree with proper
+		overriding of potentially installed libraries.
+
+	* configure.in: Setup for KRB5_RUN_FLAGS
+
+Fri Mar 15 01:45:54 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* aclocal.m4 (V5_OUTPUT_MAKEFILE): nuke some redundant sed rules
+		and also make sure that SRCTOP doesn't get a leading "./".
+
+Thu Mar 14 02:00:10 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* aclocal.m4 (V5_OUTPUT_MAKEFILE): most seds don't deal with
+		"s/\(regex\)*/foo/", so use a loop instead to get rid of
+		extraneous "./" occurences.  Do we want srctop and
+		buildtop to have leading "./"s?  They do currently.  Is
+		this a bug?
+
+Sun Mar 10 23:49:19 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (KRB5_SIGTYPE): quote the body correctly, so the test
+	happens when it should.
+
+Tue Mar 12 18:04:32 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* aclocal.m4 (V5_MAKE_SHARED_LIB): If the cache variables for
+	selecting shared v. archive library support haven't been set,
+	complain, instead of generating a broken Makefile.
+	(WITH_CC): Default to value from cache, if available.  If it
+	differs from name supplied on command line, complain.  When not
+	using a value from the cache, verify that it's a working compiler
+	before proceeding.  At end, use AC_PROG_CC to see if it's gcc
+	we're using.
+	(SubdirLibraryRule): Make DONE depend on Makefile.in, so it
+	doesn't keep getting regenerated in the case of no object files.
+	(CHECK_WAIT_TYPE): Make sure that union wait is acceptable to
+	WEXITSTATUS if that macro is defined.
+
+	* aclocal.m4 (V5_SET_TOPDIR): Don't substitute BUILDTOP, SRCTOP.
+	(CONFIG_RULES): In makefile dependencies, use $(thisconfigdir).
+	(V5_AC_OUTPUT_MAKEFILE): If arguments are given, treat as
+	directories and build pre/Makefile/post in each.  Set
+	thisconfigdir, SRCTOP, BUILDTOP separately in each directory.
+	Tweak Makefile dependencies appropriately.
+
+	* aclocal.m4 (AC_HEADER_STDARG): New macro.  Try compiling some
+	sources with variadic functions; set HAVE_STDARG_H or
+	HAVE_VARARGS_H, or bomb.
+	* acconfig.h (HAVE_STDARG_H, HAVE_VARARGS_H): Undef.
+
+Wed Feb 28 00:00:55 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Modify windows build procedure to include the
+		gssapi/mechglue directory.
+
+Sat Feb 24 19:07:15 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Add support for shared libraries under HPUX and
+	        Sinix (SysVR4 under mips)
+
+Wed Feb 21 23:31:09 1996  Richard Basch  <basch@lehman.com>
+
+	* aclocal.m4:
+		- Do not include build directories in the runtime libpath
+		- Fixed the prefix of some cache variables (krb_ --> krb5_)
+
+Wed Feb  7 00:22:26 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (krbsrc.mac): Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Mon Jan 22 07:55:04 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (KRB5_CHECK_PROTOS): Move prototype checking code
+		from include/krb5. 
+
+	* configure.in: Add in WITH_ANAME_DB and WITH_KDB_DB so that top
+		level configure --help lists options.
+
+	* aclocal.m4 (CHECK_DB): Fix m4 quoting to allow for the autoconf
+		rules to insert the required CPP determination rules
+		automatically. 
+		(WITH_ANAME_DB): Add missing comma. Fix up spacing so
+				configure --help looks pretty.
+
+Mon Jan 15 02:35:02 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (WITH_DBM_LNAME): add --with-dbm-lname for callers of
+	an_to_ln routines that have USE_DBM_LNAME set.
+	* aclocal.m4 (WITH_DBM_KDB): avoid duplicating --with-dbm code all
+	over the place.
+
+Sun Dec 17 19:53:54 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* acconfig.h: Add blank line to work around a misfeature of
+		DecUnix fgrep interacting with autoheader.
+
+Tue Dec 12 01:30:36 1995  Chris Provenzano (proven@mit.edu)
+
+	* TODO: Done: keytab routines to access to database.
+		Todo: Create a real krb5_db_context after 1.0
+
+Tue Dec  5 20:48:56 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (kutil_lib): Add USE_KRB5UTIL_LIBRARY. Change
+		library link order to -lkrb4 -lkrb5.
+
+Sun Nov 12 04:40:02 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (install-mkdirs): bash needs a semicolon between fi
+	and done.
+
+Thu Nov 09 17:04:02 1995  Chris Provenzano (proven@mit.edu)
+
+	* TODO : Remove krb5_enctype argument from string_to_key() is done.
+
+Thu Nov  2 16:57:45 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Added support for Linux shared libraries.
+
+Sat Oct 21 15:03:06 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in (CONFIG_DIRS): Add config-files to list of
+	directories. 
+
+Wed Oct 11 17:23:45 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: For all platforms, set krb5_cv_shlibs_versioned_filenames; no for AIX, yes for all others
+
+	* aclocal.m4 (v5_make_shlib): Add ability not to make versioned archive files for AIX
+
+Tue Oct 10 21:43:15 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* wconfig.c: Use win-post.in instead of post.in.
+
+Mon Oct  9 18:58:34 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: For NetBSD turn back on shlibs_use_dirs
+
+Fri Oct  6 00:57:25 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* wconfig.c: Include the file windows.in instead of pre.in
+
+	* Makefile.in (ekrbsrc.mac): Build the list of files *after*
+		building files using awk-windows-mac.
+
+Sat Sep 30 04:34:51 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (DO_SUBDIRS): Add make Makefiles for broken versions
+			of make.
+		     (V5_MAKE_SHARED_LIB): Changes to support version
+		     	     numbering and library installation.
+
+	* configure.in: change shlib extentsion for netbsd and dirhead
+		rules to allow for shared library path to be included in
+		executable. 
+
+Fri Sep 29 01:39:35 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (awk-windows-mac): Copy stock/osconf.h to osconf.h
+		in include/krb5, and clean it up when we're done building
+		the distribution.
+
+Thu Sep 28 16:00:00 1995  John Rivlin  <jrivlin@fusion.com>
+
+	* Makefile.in: Added mac/gss-sample to tar file.
+
+Wed Sep 27 00:53:08 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Add config/windows.in to the beginning of the
+		Makefile.in when we're building the Makefile.
+
+	* Makefile.in: New scheme for building DOS and Macintosh
+		distribution files; much more forgiving of random cruft in
+		the source tree.
+
+Wed Sep 27 16:00:00 1995  John Rivlin  <jrivlin@fusion.com>
+
+	* Makefile.in: Temporarily move autoconf.h file to include
+		directory while creating kerbsrc.mac tar file.
+
+	* Makefile.in: Include telnet-k5-auth directory in download.
+		Eliminate telnet directory.
+
+Wed Sep 27 11:47:38 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (install-unix): Changed install to install-unix so
+		that the installation directories are created first.
+
+Mon Sep 25 16:32:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+		(FILES): Added missing backslash at the end of one of the
+		lines, missing from the Macintosh integration.
+
+	* aclocal.m4 (MAKE_SUBDIRS, DO_SUBDIRS): MAKE_SUBDIRS now takes
+		three arguments; DO_SUBDIRS now generates target rules of
+		the form: "foo-unix: <for each subdirectory> make foo".
+		All of the macros which generated targets "all",
+		"install", "clean", etc. now generate targets "all-unix",
+		"install-unix", "clean-unix".  
+
+		This scheme allows us to do multiple-platform builds,
+		while preserving ordering constraints that we need in
+		order to build library subdirectories correctly.
+
+Sun Sep 24 12:00:00 1995  John Rivlin <jrivlin@fusion.com>
+
+	* Makefile.in: Update CLEANUP list to clean up files created
+		in the include directory rather than include/krb5
+		directory.  Remove mac/build directory.
+
+Fri Sep 22 19:39:30 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Exclude the MAC and DOS tar/zip files when creating
+	        the Mac tar file.  Adjust the windows NT exclusion file so
+		that it works correctly; zip is a little bit touchy about
+		file specifications.
+
+	* Makefile.in (awk-windows-mac): Build the error table header
+		files into include, not include/krb5; and construct krb5.h
+		from krb5.hin and the error table header files.
+
+Fri Sep 15 05:05:15 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (kerbsrc-nt.zip): Update production rule to be like
+		the modified kerbsrc.zip rule.
+
+Tue Sep 12 22:06:24 1995  John Rivlin (jrivlin@fusion.com)
+
+	* Makefile.in: Added telnet to Mac file list
+
+Mon Sep 11 22:06:24 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: Update macintosh/dos file lists
+
+Thu Aug 24 19:27:04 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Tue Aug 22 18:19:39 1995    <tytso@rsts-11.mit.edu>
+
+	* aclocal.m4 (_MAKE_SUBDIRS): Change subdir recursion so that 
+		a missing subdirectory is skipped.  
+
+Mon Aug 21 16:42:42 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* Makefile.in - Change mkdir to mkdir -p.
+
+Tue Aug 15 16:19:29 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: For OSF/1 specify that the -rpath directive takes
+		a colon separated path.
+
+	* aclocal.m4 (SHLIB_RPATH_DIRS): Allow for directory path to be
+		colon separated for different directories.
+
+
+Tue Aug 15 01:37:19 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* Makefile.in: Change some spaces back to tabs
+
+Mon Aug  7 19:26:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* aclocal.m4 (SS_RULES): Add double quotes around "$}{*.ct"
+
+	* aclocal.m4 (CONFIG_RULES): Add $(SHELL) to invocation of
+		autoconf, so that things work even if the execute bit
+		isn't set on the shell script.
+
+Tue Jul 18 19:20:49 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (KRB5_SOCKADDR_SA_LEN): Add space before = to keep
+		shell happy. 
+
+Sun Jul 16 05:02:41 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* aclocal.m4 : Defined KRB5_SOCKADDR_SA_LEN, a test to determine
+        if sockaddr has the sa_len field.  
+
+Wed Jul 12 11:47:43 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* aclocal.m4 - Add LDFLAGS setting to KRB5_LIBRARIES.  This allows
+		building without using the rule V5_USE_SHARED_LIBS.  Also,
+		don't pass LDFLAGS in recursion because this overrides
+		the values in individual Makefiles.
+
+Sun Jul  9 06:15:33 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* aclocal.m4: backslash '$' characters that go into double-quoted
+		strings so shells that treat $(foo) like `foo` won't barf
+
+Sun Jul  9 01:31:25 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* Makefile.in: remove bogus definitions of prefix, etc.
+
+Fri Jul 7 15:29:43 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* aclocal.m4 - Add ability to set LDFLAGS from --with-ldopts (I know,
+		configure option doesn't coincide with make variable, but it
+		corresponds to --with-ccopts).
+		- Add ability to select libraries to link with from configure
+		script.  This prevents us from having to change every makefile
+		each time there's a library reorganization.  These macros are
+		USE_{KADM,KDB5,KDB4,KRB4}_LIBRARIES and KRB5_LIBRARIES.
+		Makefiles now only need to reference $(LIBS) for the list of
+		libraries to link with and $(DEPLIBS) for the list of
+		library dependencies.
+
+Wed Jul  5 12:00:00 1995 James Mattly <mattly@fusion.com> 
+
+	* Makefile.in: Added kerbsrc.mac target to facilitate easy 
+	downloading pruned source tree to the Mac.
+
+Tue Jul  4 02:11:14 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* configure.in: Add support for NetBSD shared libraries.
+
+Sun Jul  2 20:25:58 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: For paranoid GPL reasons, don't take the Gcc test
+        directly from the autoconf sources.  Instead, borrow my paraphrase
+        of this test from util/configure.in.  It's slightly cleaner
+        anyway.  Also, adjust AIX shared libs to work with Gcc.
+
+Sun Jul  2 04:40:50 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+	* aclocal.m4 (_MAKE_SUBDIRS): Fixed so that error propogates
+		upward if -[ik] not specified.
+
+	* aclocal.m4 (SubdirLibRule): don't recreate DONE if list of objs
+		is null to avoid re-making lotsa stuff.
+		(_MAKE_SUBDIRS): really gross sh hack for subdir
+		recursion; make -[ik] should dtrt now even with broken
+		makes (like Ultrix) that do sh -ce "rule".  Basically,
+		throw an "if" test around the recursion line so that even
+		if the -e option to sh is set by make, an error in a
+		subdir below won't cause for loop to exit unless we want
+		it to.
+
+Fri Jun 30 14:26:01 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* aclocal.m4(V5_SHARED_LIB_OBJS) - Change explicit $(srcdir)/$*.c to
+		$< so that sources which aren't in the source directory can
+		get compiled correctly.
+
+Wed Jun 28 20:13:10 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Proper test for GCC. (based on autoconf test).  
+	 	If using gcc, set shlibs_ldflag and noshlibs_ldflag
+		properly for compiler. (for OSF at least - may be more
+		generic). 
+
+Wed Jun 28 17:07:08 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* aclocal.m4 (KRB_INCLUDE): Search the build directories before
+		the source directories.  (Doesn't hurt anything, and it
+		helps in a few cases of user error.)
+
+	* configure.in: Conditionalize on the name of CC to determine
+		whether to use the gcc or suncc flags for shared
+		libraries.  (This is a little bit ugly; we might want to
+		use a better test later on.)
+
+Wed Jun 28 10:43:10 1995    <tytso@rsx-11.mit.edu>
+
+	* aclocal.m4 (INSTALL_VARIABLE_HACKSRCTOP): Work around bug in
+		autoconf which causes a relative path for dnl
+		AC_PROG_INSTALL to be cached.  We workaround this by
+		unsetting the cache variable if it contains a relative
+		pathname.
+
+Tue Jun 27 16:28:23 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* acconfig.h - Reinstate KRB5_PROVIDE_PROTOTYPES.  This is needed
+		for compilers which recognize prototypes but don't set
+		__STDC__ or _WINDOWS.
+
+Fri Jun 23 20:14:45 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* aclocal.m4 (SHARED_RULE_LOCAL): Use makeshlib out of
+        $(BUILDTOP)/util not $(SRCTOP)/util since it moved.
+
+	* configure.in: Include appropriate binder option to set LIBPATH
+        correctly in generated executables.
+
+Thu Jun 22 16:15:10 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* acconfig.h: NO_NESTED_PROTOTYPES -> KRB5_NO_NESTED_PROTOTYPES;
+		KRB5_PROVIDE_PROTOTYPES -> KRB5_NO_PROTOTYPES
+
+Fri Jun 23 12:13:22 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* configure.in: Enable static library generation for Linux.
+
+Fri Jun 23 11:48:04 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* aclocal.m4 (V5_MAKE_SHARED_RULE) Set STEXT when not making
+		shared library.
+		(CONFIG_RULES): Move AC_CONST from WITH_KRB4 definition. 
+
+Wed Jun 21 18:10:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* aclocal.m4 (V5_SET_TOPDIR): Replace AC_CONFIG_FRAGMENTS,
+		AC_CONFIG_FRAGMENTS_DEFUALT, AC_SET_BUILDTOP,
+		AC_CONFIG_AUX_DIR_DEFAULT with V5_SET_TOPDIR.  This sets
+		up the correct variables for the top of the source tree
+		and the top of the build tree.  It currently depends on
+		AC_LOCALDIR being a relative pathname, but that's a safe
+		assumption to make.  (And we could fix it to be more
+		general if we really needed to.)
+
+		Removed AC__CONFIG_AUX since it doesn't seem to be used at all.
+
+Wed Jun 21 18:03:40 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* aclocal.m4: undefine AC_CONFIGF_AUX_DIR_DEFAULT before
+		redefining it to avoid diversion madness
+
+Wed Jun 21 17:38:34 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4: Add KRB5_SIGTYPE (taken from include/krb5) so that
+		other applications may use defintion. 
+
+
+Wed Jun 21 16:10:09 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* aclocal.m4 (SHARED_RULE_LOCAL): Add support for not making
+        static libs.  Moves the clean and all target for shared libs in
+        shared lib Makefiles into this rule instead of Makefile.in
+
+	* configure.in: Added krb5_cv_noshlibs_ext, the extension for
+        static libraries that have shared counterparts.  Also added
+        krb5_cv_staticlibs_enabled, (set by the code for --enable-shared,
+        not by any extra option) to determine whether static versions of
+        shared libs are compiled on a per-platform basis.
+
+
+ Wed Jun 21 14:57:55 1995    <tytso@rsx-11.mit.edu>
+
+	* aclocal.m4: Removed extra blank lines and added "dnl" to the end
+		of some macro definitions to get rid of extra newlines
+		added at the beginning of configure scripts.
+
+Tue Jun 20 12:23:20 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* BADSYMS: Updated after finding bugs in getsyms
+
+Mon Jun 19 11:23:47 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* BADSYMS: list of bad symbols found in various source files;
+		generated by util/getsyms
+
+Sun Jun 18 20:57:35 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* aclocal.m4: Must protect $(FOO) with a backslash, since $(FOO)
+		is specially interpreted by bash (and Korn shells).
+
+Fri Jun 16 00:45:03 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* aclocal.m4: ARCHIVE gets a "cqv" to shut it up about the warning
+
+	* aclocal.m4: Fix new append.out stuff to work with config.status
+		properly; previously append.out was not getting sucked
+		into the body of config.status.  The EXTRA_RULES macros
+		are deprecated and should not be used anymore.
+
+	* aclocal.m4: people were using AC_DIVERSION_MAKEFILE inside
+		conditionals, not realizing that it would not end up
+		conditionalized.  Define a new macro AC_PUSH_MAKEFILE,
+		along with AC_POP_MAKEFILE, to stuff things into a tmp
+		file (append.out) to unconfuse things.
+
+Thu Jun 15 21:59:22 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* aclocal.m4 (V5_USE_SHARED_LIB): Quote arguments to test in
+		case the values are blank.
+
+Thu Jun 15 18:15:54 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* aclocal.m4 - Separate K4 libraries; Separate library specification
+		from actual library path so we can do a dependency check
+		using the DEP_<lib> and link with the library itself.
+		- Add LinkFileDir(): a macro which generates a symlink in
+		  another directory.
+		- Figure out values for shared library parameters.
+		- Add rules for building with these shared libraries.
+	* configure.in - Add system-specific linker flags.
+
+Wed Jun 14 16:51:28 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* aclocal.m4(_MAKE_SUBDIRS): revert yet again; no workaround since
+		subshells inherit "-e" flag.  Ultrix sucks.
+
+	* aclocal.m4 (_MAKE_SUBDIRS): "-@" was the wrong answer; set a
+		shell variable "e" to "exit 0" and execute it after the
+		make in each subdirectory
+
+Tue Jun 13 01:44:12 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* aclocal.m4 (CopySrcHeader): do a set -x before mkdir
+		_MAKE_SUBDIRS: inserted a "-@" rather than a "@" at the
+		beginning of the rule; Ultrix make does /bin/sh -e
+		ruleline if it's not there, and set +e doesn't work.
+
+Sat Jun 10 08:14:22 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* acconfig.h: Removed HAS_ANSI_CONST, HAS_ANSI_VOLATILE,
+		HAS_SYS_FILE, HAS_SYS_PARAM_H, TM_IN_SYS_TIME.
+		include/krb5/configure.in does not check for these.
+
+Fri Jun  9 18:01:26 1995    <tytso@rsx-11.mit.edu>
+
+	* aclocal.m4 (CONFIG_RULES): CONFIG_RULES now contains the
+		standardized autoconf macros which all configure.in files
+		will include.  
+
+		Removed WITH_KRB5ROOT, since it's no longer used.
+
+		Change name of standardized Kerberos V4 #ifdef variable
+		from KRB4 to KRB5_KRB4_COMPAT.  KRB4 was already in use in
+		the POP clients.
+
+		Added a new macro rule, DO_SUBDIRS, which includes all of
+		the MAKE_SUBDIRS macros.  This makes it easier to add
+		global recursive targets to the tree.
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Jun  8 17:42:40 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in: Remove excess definitions of prefix, exec_prefix,
+		etc. (defined in config/pre.in)
+
+Wed Jun  7 16:10:22 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in (INSTALLMKDIRS): Make sure that the
+		$(INSTALL_PREFIX) directory exists, not $(KRB5ROOT).
+
+Tue Jun  6 12:38:12 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Build the krb524 directory.
+
+Tue May 30 18:53:56 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: removed des425 stuff for Windows.
+
+Fri May 26 21:45:50 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Export $(CC) for the benefit of config.guess
+
+	* Makefile.in: Create kerbsrc-nt.zip with the right filename, and
+		clean up include/krb5.h after making the Windows .zip files.
+
+Fri May 26 15:33:12 1995 Keith Vetter (keithv@fusion.com)
+
+	* wconfig.c: extended so it ignores lines beginning with '@'.
+
+Fri May 26 10:16:02 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: added lib/kadm and deleted lib/krb425 from PC stuff.
+
+Thu May 25 11:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: don't copy profile.h here but do it in include/makefile.
+
+Tue May 23 15:39:40 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Generate krb5.h from krb5.hin in awk-windows, for
+		the Windows port.
+
+		Added kerbsrc-nt.zip, which creates the zip file without
+		the option to truncate the names to the MS-DOS 8.3
+		convention. 
+
+Tue May 16 03:05:30 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* aclocal.m4 (_MAKE_SUBDIRS): fix rule so that MAKEFLAGS gets
+		processed correctly.
+
+Fri May  5 01:50:08 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* patchlevel.h: Update patchlevel for BETA 5 release
+
+	* Makefile.in: Remove all files in ZIPCLEANUP after building
+		kerbsrc.zip.  This keeps the source directory clean after
+		building a Windows source distribution.
+
+		Remove miscellaneous targets left over from the bad old
+		imake days.
+
+Tue May  2 21:26:09 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* .rconf: copy kadmin.old as well
+
+	* Makefile.in: nuke spurious whitespace on blank line
+
+Sat Apr 29 14:13:45 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* aclocal.m4 (WITH_KRB4): fix so configure --help looks nice.
+
+Fri Apr 28 15:27:45 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* aclocal.m4 (WITH_KRB4): fix KDB4_LIB location when --with-krb4
+		has a value.
+
+Fri Apr 28 11:38:09 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: new windows gss app added to the zip target.
+
+Thu Apr 27 18:30:00 1995  Keith Vetter <keithv@fusion.com>
+
+	* Makefile.in: have ZIP exclude any *.zip files it finds.
+
+Fri Apr 28 14:34:17 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (WITH_KRB4): put AC_CONST in, since we always end up
+	needing it.
+
+Fri Apr 28 13:28:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Also compile the kadmin.old directory, at least
+		for now.  (At some point this should be controlled by
+		--enable-old-kadmin).
+
+Fri Apr 28 09:33:52 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Also remove util/profile/prof_err.[ch] after
+		building kerbsrc.zip, since this also screws up the Unix
+		build. 
+
+Fri Apr 28 02:03:56 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (WITH_KRB4): fix quoting in pathname case.
+
+Thu Apr 27 23:21:08 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Remove util/profile/profile.h after building
+		kerbsrc.zip; this file screws up the Unix build.
+
+Thu Apr 27 17:54:05 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: check KRB4_LIB to know if we're building with krb4
+	support enabled and thus want kadmin.v4.
+
+Thu Apr 27 14:00:00 1995  Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: bug fix in makeing makefile on the PC.
+
+Thu Apr 27 15:19:34 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (WITH_KRB4): make --with-krb4 the default, and have
+	it use the included krb4 directories. If a pathname is given, use
+	them instead. To disable krb4 support, use --without-krb4.
+
+Wed Apr 27 11:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: added stuff for new directory: util/profile. This
+	   affects configuring, building, cleaning and zipping.
+	* Makefile.in: added ren2long target to expand 8.3 shortened names.
+
+Wed Apr 26 14:29:03 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (HAS_ANSI_VOLATILE): define it here for kdc and
+	kadmin.old to use.
+
+Mon Apr 24 13:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: Fixed a PC work-around for doing a touch command.
+
+Thu Apr 20 17:55:50 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (.ct.c): use $(RM) instead of plain rm.
+
+Thu Apr 20 12:45:07 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: bug that makefiles were always being reconfigured.
+
+Wed Apr 19 18:32:04 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: 
+           removed need for this file to be configured on the PC.
+           zipping up for PC copies makefile.in to makefile so that on
+	   the PC you just need to type 'nmake' to build it.
+
+Fri Apr 14 21:21:28 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* aclocal.m4 (_MAKE_SUBDIRS): If there is an error while making in
+	        a subdirectory, abort the make in the parent directory.
+	        This makes it more obvious when we have a problem in the
+	        tree.
+
+Fri Apr 14 08:23:52 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* aclocal.m4 (MAKE_SUBDIRS, _MAKE_SUBDIRS): Creatre new macro
+		_MAKE_SUBDIRS which works like MAKE_SUBDIRS except that it
+		is possible for the target name in the parent Makefile and
+		the target name which should be built in each of the
+		subdirectories can be different.  MAKE_SUBDIRS is now a
+		special case of _MAKE_SUBDIRS.
+
+Fri Mar 31 21:27:13 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* aclocal.m4: Use the local autoconf when rebuilding the configure
+		script. 
+
+Tue Mar 28 18:55:12 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in:  Fix up Mac build process somewhat.  Not complete.
+
+Mon Mar 27 20:02:01 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: added making and zipping in windows/wintel.
+
+Wed Mar 24 14:00:00 1995  Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed zip-windows target to kerbsrc.zip, and also
+	   had the windows makefile config clean up any debugging files.
+
+Tue Mar 22 12:00:00 1995  Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: added all-mac target.
+
+Tue Mar 22 12:00:00 1995  Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: zipping up for the PC now handles trees containing
+	   binary files such as *.o and *.a.
+
+Tue Mar 21 18:50:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: oops, missed a directory in zipping up for the PC
+
+Tue Mar 21 18:38:12 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: more PC stuff including zipping up source commands.
+
+Sun Mar 19 12:45:08 1995  John Gilmore  (gnu at toad.com)
+
+	* aclocal.m4 (CHECK_STDARG):  Remove; we're just using AC_HEADER_CHECK.
+	(V5_AC_OUTPUT_MAKEFILE):  Reorder the Makefile output so that it can be
+	run through `sed' for the Macintosh.
+	* acconfig.h:  Remove STDARG_PROTOTYPES.
+
+Thu Mar 16 15:15:00 1995 Keith Vetter <keithv@fusion.com>
+
+	* Makefile.in: added PC stuff so it builds the whole world.
+	* wconfig.h: program to configure makefiles on the PC.
+	* CHANGELOG -> CHANGES: renamed to avoid PC name conflict.
+
+Tue Mar  7 19:49:07 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (UsePepsy, PepsyTarget): removed, not referenced
+	anywhere in the tree.
+	(ISODE_INCLUDE, ISODE_DEFS): removed along with remaining
+	references in the tree. --enable-isode is dead.
+
+Wed Mar  1 16:40:23 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* acconfig.h: Add HAS_LABS defintiion.
+
+	* aclocal.m4 (KRB_INCLUDE): Add $(SRCTOP)/include/krb5 so that it
+		builds when the build tree != the source tree.
+
+	* aclocal.m4, configure.in: Folded in Ezra's changes to support
+		--with-netlib, for support of the SGI's.
+
+Tue Feb 28 00:00:22 1995  John Gilmore  (gnu at toad.com)
+
+	* aclocal.m4 (ADD_DEF):  Add -I...include/krb5 so we won't need
+	pathnames to Kerberos include files in any of the #include lines
+	in the source tree.
+
+Mon Feb 13 23:39:21 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* aclocal.m4 (WITH_LINKER): Add a new configure production which
+		allows a special linker to be specified.  Useful for
+		running programs like Purify, etc.		
+
+Thu Feb 9 15:42:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* acconfig.h: added HAS_SYS_FILE_H & HAS_SYS_PARAM_H for Windows
+
+Thu Feb  2 21:11:24 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* aclocal.m4 (V5_AC_OUTPUT_MAKEFILE): delete pre.out,
+	Makefile.out, and post.out immediately after using them, for
+	cleanliness' sake.
+
+Fri Feb  3 06:47:24 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* acconfig.h: Remove BITS* definitions altogether.
+
+	* aclocal.m4:
+	* configure.in: Remove ISODE defines
+
+Fri Dec 30 17:05:12 1994  Richard Basch  (probe@tardis)
+
+	* aclocal.m4
+	  	CHECK_UTMP needs to #include <sys/types.h> for its tests
+
+Tue Dec 27 06:10:13 1994  Richard Basch  (probe@tardis)
+
+	* aclocal.m4
+	combined KRB5_UTPID, KRB5_UTTYPE, and KRB5_UTHOST
+	into CHECK_UTMP macro (and added additional checks)
+
+
+Wed Nov 30 17:13:02 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* aclocal.m4, configure.in: Add appropriate help text for the
+		--with-* and --enable-* options.  ISODE_INCLUDES should
+		define KRB5_USE_ISODE if necessary.
+
+	* acconfig.h: Add defines for KRB5_ATHENA_COMPAT and
+		KRB5_KRB4_COMPAT.
+
+Fri Nov 18 15:38:42 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (CHECK_WAIT_TYPE, CHECK_SIGNALS, CHECK_SETJMP,
+	KRB5_UTPID, KRB5_UTTYPE, KRB5_UTHOST, KRB5_UTEXIT): use
+	AC_TRY_COMPILE instead of AC_TRY_LINK.
+	(CHECK_FCNTL): check for 1+O_RDONLY so we aren't fooled into
+	declaring it as a local variable.
+	(DECLARE_SYS_ERRLIST): same thing for 1+sys_nerr.
+
+Fri Nov 18 00:31:43 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (ET_RULES): don't define SRCTOP, pre.in already takes
+	care of it.
+	(DECLARE_SYS_ERRLIST, CHECK_SIGPROCMASK, CHECK_FCNTL,
+	CHECK_WAIT_TYPE, CHECK_SIGNALS, CHECK_SETJMP, HAVE_YYLINENO): add
+	caching.
+	(WITH_KRB5ROOT, WITH_KRB4, WITH_CC, WITH_CCOPTS, WITH_CPPOPTS):
+	use AC_MSG_RESULT instead of echo.
+	(KRB5_UTPID, KRB5_UTTYPE, KRB5_UTHOST, KRB5_UTEXT): new functions
+	for appl/bsd and kpasswd common utmp code.
+	(KRB5_POSIX_LOCKS): new functions for include/krb5 and appl/popper
+	common code.
+	(from epeisach.)
+
+Fri Nov 18 00:30:19 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (CONFIG_RULES): handle pre.in, post.in, and pass the
+	rest of the arguments that autoconf needs. (from epeisach.)
+
+Fri Nov 18 00:22:18 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* aclocal.m4 (CopySrcHeader): add clean rule (from epeisach)
+
+Mon Nov  7 21:27:45 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* aclocal.m4 (CHECK_SETJMP, CHECK_SIGNALS): Added checks for POSIX
+		setjmp handling and POSIX signal handling.
+
+Wed Nov  2 20:39:14 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: We're probably not going to be building in the
+		top-level directory, but even so, the CFLAGS should
+		include $(DEFS).
+
+	* aclocal.m4: Don't recursively pass the CPPOPTS makefile variable
+		down to subdirectories.
+
+	* aclocal.m4 (CONFIG_RULES, WITH_CPPOPTS): Add support for a new
+		"--with-cppopts" value where you can put -DXXXXX such that
+		they are found by autoconf tests that use run the
+		preprocessor over header files.
+
+Sat Oct 22 13:25:18 1994    (tytso@rsx-11)
+
+	* aclocal.m4 (CopyHeader): Remove header file from include
+		directory when doing a make clean.
+
+Tue Oct 11 17:07:15 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* aclocal.m4: Make sure we do our feature tests using the CC
+		options specified using CC_OPTS.
+
+Fri Oct  7 16:38:11 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* aclocal.m4: If using isode we need to add -DKRB5_USE_ISODE to
+		$DEFS, not KRB5_USE_ISODE!
+
+Thu Oct  6 20:05:07 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add recursive "make check" target.
+
+Mon Oct  3 22:50:07 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR)
+
+Fri Sep 30 18:49:41 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* aclocal.m4 (CONFIG_RULES): set SHELL=/bin/sh explicitly, as per
+	GCS and to deal with SGI and OSF makes. This should cover all
+	Makefiles.
+
+Thu Aug 18 02:05:14 1994  Mark Eichin  (eichin@perdiem)
+
+	* .../*.[ch]: remove rcsid, sccsid strings; punt all RCS variable
+	expansions; get rid of LIBC_SCCS. Leave the BSD sccs variables in
+	comments, for historical reference.
+
+Thu Aug  4 03:11:13 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* aclocal.m4: fixed up Krb5InstallHeaders to use INSTALL_DATA
+	properly
+	* Makefile.in: fix mkdir breakage for install target
+
+Wed Jul 20 00:00:00 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in (in all relevant subdirs):
+	* configure.in (in all relevant subdirs): changes to fix make
+	install
+	* aclocal.m4: make changes to look for install.sh in the right
+	places
+
+Mon Jul 11 23:32:51 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* aclocal.m4: cleaning up stuff to not echo things like "if
+	foo..."
+
+Sun Jul  3 07:46:25 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* aclocal.m4: fixing things so we don't have to bother ignoring
+	errors.
+
+Fri Jul  1 13:01:19 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* aclocal.m4: added WITH_CC for use when CONFIG_RULES isn't safe.
+	added EXTRA_RULES_IN for chosing the file that the extra rules get
+	appended to (particularly for lib/krb5/asn.1).
+	made CONFIG_RULES use WITH_CC directly.
+
+Fri Jul  1 02:21:51 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* aclocal.m4: fixes for dealing with new version of autoconf, in
+	particular quoting and BUILDTOP
+
+Wed Jun 29 01:36:38 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* aclocal.m4: oops... fixing some problems with the quoter.
+
+	* aclocal.m4: added ISODE_DEFS to define KRB5_USE_ISODE if
+	--enable-isode is given
+
+Mon Jun 27 23:13:16 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* patchlevel.h: Updated to patchlevel 1.
+
+Mon Jun 27 08:21:42 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* aclocal.m4: fixes to do sane quoting of arguments before
+	recursing.  This allows options to be set with values containing
+	whitespace, for instance.
+
+	* configure.in (in all relevant subdirs): move invokations of
+	CONFIG_RULES around so that they preceed anything that even
+	vaguely resembles a compile test.  This is so that $CC will get
+	set properly before any compile tests run.
+
+Sat Jun 25 00:33:56 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in (in all relevant subdirs): make install will dtrt
+	now (mostly)
+	* configure.in (in all relevant subdirs): ditto
+
+Thu Jun 23 01:13:20 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* aclocal.m4 (CONFIG_RULES): make --with-cc= dtrt and default to
+	CC=cc
+
+Wed Jun 22 16:34:46 1994  Mark Eichin  (eichin at tweedledumber.cygnus.com)
+
+	* aclocal.m4 (CONFIG_RULES): add AC_SUBST([CC]) so that CC gets
+	nailed in correctly.
+
+Tue Jun 21 17:46:53 1994  Mark Eichin  (eichin at cygnus.com)
+
+	* Makefile.in (in all subdirs): added CC=@CC@ to nail down the
+	substitution to be sure that configuration matches build. Added
+	CCOPTS to some of them so that it gets nailed in correctly too.
+
+Tue Jun 21 02:08:27 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in (in all relevant subdirs): added CCOPTS=@CCOPTS@ in
+	order to allow for configured default flags
+	* configure.in (in all relevant subdirs): add WITH_CCOPTS
+	* acloca.m4: define WITH_CCOPTS
+
+Fri Jun 17 19:54:00 1994  Mark Eichin  (eichin at cygnus.com)
+
+	* aclocal.m4 (MAKE_SUBDIRS): pass CCOPTS, CC in every make
+	* Makefile.in: change CFLAGS = -g ... to CFALGS = $(CCOPTS) ...
+	  in all Makefile.in's throughout the tree.
diff --git a/mechglue/src/Makefile.in b/mechglue/src/Makefile.in
new file mode 100644
index 000000000..8b9be5d94
--- /dev/null
+++ b/mechglue/src/Makefile.in
@@ -0,0 +1,586 @@
+datadir=@datadir@
+
+thisconfigdir=.
+myfulldir=.
+mydir=.
+SUBDIRS=util include lib @krb524@ kdc kadmin slave clients \
+	plugins/kdb/db2 \
+	appl tests \
+	config-files gen-manpages
+BUILDTOP=$(REL)$(C)
+LOCALINCLUDES = -I$(srcdir) 
+
+SRCS =  
+HDRS = 
+
+DISTFILES = $(SRCS) $(HDRS) COPYING COPYING.LIB ChangeLog Makefile.in
+
+all-unix:: krb5-config
+
+# Lots of things will start to depend on the thread support, which
+# needs autoconf.h, but building "all" in include requires that util/et
+# have been built first.  Until we can untangle this, let's just check
+# that autoconf.h is up to date before going into any of the subdirectories.
+all-prerecurse: update-autoconf-h
+update-autoconf-h:
+	(cd include && $(MAKE) krb5/autoconf.h)
+
+##DOS##!if 0
+# This makefile doesn't use lib.in, but we still need shlib.conf here.
+config.status: $(SRCTOP)/config/shlib.conf
+##DOS##!endif
+
+all-windows:: maybe-awk Makefile-windows
+	@echo Making autoconf.h in include\krb5
+	cd include\krb5
+	$(MAKE) -$(MFLAGS) autoconf.h
+	@echo Making in util
+	cd ..\..\util
+	$(MAKE) -$(MFLAGS)
+	@echo Making in include
+	cd ..\include
+	$(MAKE) -$(MFLAGS) 
+	@echo Making in lib
+	cd ..\lib
+	$(MAKE) -$(MFLAGS) 
+	@echo Making in windows
+	cd ..\windows
+	$(MAKE) -$(MFLAGS) 
+	@echo Making in clients
+	cd ..\clients
+	$(MAKE) -$(MFLAGS)
+	@echo Making in appl\gss-sample
+	cd ..\appl\gss-sample
+	$(MAKE) -$(MFLAGS)
+	@echo Making in appl\gssftp\ftp
+	cd ..\..\appl\gssftp\ftp
+	$(MAKE) -$(MFLAGS)
+	cd ..\..\..
+
+world::
+	date
+	make $(MFLAGS) all
+	date
+
+INSTALLMKDIRS = $(KRB5ROOT) $(KRB5MANROOT) $(KRB5OTHERMKDIRS) \
+		$(ADMIN_BINDIR) $(SERVER_BINDIR) $(CLIENT_BINDIR) \
+		$(ADMIN_MANDIR) $(SERVER_MANDIR) $(CLIENT_MANDIR) \
+		$(FILE_MANDIR) $(KRB5_LIBDIR) $(KRB5_INCDIR) \
+		$(KRB5_DB_MODULE_DIR) \
+		$(KRB5_INCSUBDIRS) $(datadir) $(EXAMPLEDIR)
+
+install-strip:
+	$(MAKE) install INSTALL_STRIP=-s
+
+install-recurse: install-mkdirs
+
+install-mkdirs:
+	@for i in $(INSTALLMKDIRS); do \
+		$(srcdir)/config/mkinstalldirs $(DESTDIR)$$i; \
+	done
+
+install-headers-mkdirs:
+	$(srcdir)/config/mkinstalldirs $(DESTDIR)$(KRB5_INCDIR)
+	$(srcdir)/config/mkinstalldirs $(DESTDIR)$(KRB5_INCDIR)/gssapi
+	$(srcdir)/config/mkinstalldirs $(DESTDIR)$(KRB5_INCDIR)/gssrpc
+	$(srcdir)/config/mkinstalldirs $(DESTDIR)$(KRB5_INCDIR)/kerberosIV
+install-headers-prerecurse: install-headers-mkdirs
+
+# install::
+#	$(MAKE) $(MFLAGS) install.man
+
+fake-install:
+	$(RM) -r $(FAKEPREFIX)
+	@for i in $(INSTALLMKDIRS); do \
+		$(srcdir)/config/mkinstalldirs util/fakedest$$i; \
+	done
+	(w=`pwd`; cd util && $(MAKE) install DESTDIR="$$w/util/fakedest")
+	(w=`pwd`; cd lib && $(MAKE) install DESTDIR="$$w/util/fakedest")
+	(w=`pwd`; cd plugins/kdb/db2 && $(MAKE) install DESTDIR="$$w/util/fakedest")
+
+TAGS: $(SRCS)
+	etags $(SRCS)
+
+clean-:: clean-windows
+clean-unix::
+	$(RM) *.o core krb5-config
+
+mostlyclean: clean
+
+# This doesn't work; if you think you need it, you should use a
+# separate build directory.
+# 
+# distclean: clean
+# 	rm -f Makefile config.status
+# 
+# realclean: distclean
+# 	rm -f TAGS
+
+dist: $(DISTFILES)
+	echo cpio-`sed -e '/version_string/!d' \
+	-e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c` > .fname
+	rm -rf `cat .fname`
+	mkdir `cat .fname`
+	-ln $(DISTFILES) `cat .fname`
+	for file in $(DISTFILES); do \
+	  test -r `cat .fname`/$$file || cp -p $$file `cat .fname`; \
+	done
+	tar chzf `cat .fname`.tar.gz `cat .fname`
+	rm -rf `cat .fname` .fname
+
+GZIPPROG= gzip -9v
+PKGDIR=`pwd`/pkgdir
+pkgdir:
+	if test ! -d $(PKGDIR); then mkdir $(PKGDIR); else true; fi
+tgz-bin: pkgdir
+	rm -rf $(PKGDIR)/install cns5-bin.tgz
+	mkdir $(PKGDIR)/install
+	$(MAKE) install DESTDIR=$(PKGDIR)/install
+	(cd $(PKGDIR)/install && tar cf - usr/cygnus) | $(GZIPPROG) > cns5-bin.tgz
+	rm -rf $(PKGDIR)/install
+
+# Microsoft Windows build process...
+#
+
+config-windows:: Makefile-windows
+#	@echo Making in include
+#	cd include
+#	$(MAKE) -$(MFLAGS)
+#	cd ..
+
+#
+# We need outpre-dir explicitly in here because we may
+# try to build wconfig on a config-windows.
+#
+##DOS##$(WCONFIG_EXE): outpre-dir wconfig.c
+##DOS##	$(CC) -Fe$@ -Fo$*.obj wconfig.c
+
+##DOS##MKFDEP=$(WCONFIG_EXE) config\win-pre.in config\win-post.in
+
+WINMAKEFILES=Makefile \
+	appl\gss-sample\Makefile \
+	appl\gssftp\ftp\Makefile \
+	clients\Makefile clients\kdestroy\Makefile \
+	clients\kinit\Makefile clients\klist\Makefile \
+	clients\kpasswd\Makefile clients\kvno\Makefile \
+	clients\kcpytkt\Makefile clients\kdeltkt\Makefile \
+	include\Makefile include\krb5\Makefile \
+	krb524\Makefile \
+	lib\Makefile lib\crypto\Makefile \
+	lib\crypto\crc32\Makefile lib\crypto\des\Makefile \
+	lib\crypto\dk\Makefile lib\crypto\enc_provider\Makefile \
+	lib\crypto\hash_provider\Makefile \
+	lib\crypto\keyhash_provider\Makefile \
+	lib\crypto\raw\Makefile lib\crypto\old\Makefile \
+	lib\crypto\sha1\Makefile lib\crypto\arcfour\Makefile \
+	lib\crypto\md4\Makefile lib\crypto\md5\Makefile \
+	lib\crypto\yarrow\Makefile lib\crypto\aes\Makefile \
+	lib\des425\Makefile \
+	lib\gssapi\Makefile lib\gssapi\generic\Makefile \
+	lib\gssapi\krb5\Makefile lib\gssapi\mechglue\Makefile \
+	lib\krb4\Makefile lib\krb5\Makefile \
+	lib\krb5\asn.1\Makefile lib\krb5\ccache\Makefile \
+	lib\krb5\ccache\ccapi\Makefile \
+	lib\krb5\error_tables\Makefile \
+	lib\krb5\keytab\Makefile \
+	lib\krb5\krb\Makefile \
+	lib\krb5\os\Makefile lib\krb5\posix\Makefile \
+	lib\krb5\rcache\Makefile \
+	util\Makefile \
+	util\et\Makefile util\profile\Makefile \
+	util\support\Makefile \
+	util\windows\Makefile \
+	windows\Makefile windows\lib\Makefile \
+	windows\cns\Makefile windows\gina\Makefile \
+	windows\gss\Makefile windows\ms2mit\Makefile \
+	windows\wintel\Makefile windows\kfwlogon\Makefile
+
+##DOS##Makefile-windows:: $(MKFDEP) $(WINMAKEFILES)
+
+##DOS##Makefile: Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##appl\gss-sample\Makefile: appl\gss-sample\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##appl\gssftp\ftp\Makefile: appl\gssftp\ftp\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##clients\Makefile: clients\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##clients\kdestroy\Makefile: clients\kdestroy\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##clients\kinit\Makefile: clients\kinit\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##clients\klist\Makefile: clients\klist\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##clients\kpasswd\Makefile: clients\kpasswd\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##clients\kvno\Makefile: clients\kvno\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##clients\kcpytkt\Makefile: clients\kcpytkt\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##clients\kdeltkt\Makefile: clients\kdeltkt\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##include\Makefile: include\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##include\krb5\Makefile: include\krb5\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##krb524\Makefile: krb524\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\Makefile: lib\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\Makefile: lib\crypto\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\crc32\Makefile: lib\crypto\crc32\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\des\Makefile: lib\crypto\des\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\dk\Makefile: lib\crypto\dk\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\enc_provider\Makefile: lib\crypto\enc_provider\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\hash_provider\Makefile: lib\crypto\hash_provider\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\keyhash_provider\Makefile: lib\crypto\keyhash_provider\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\sha1\Makefile: lib\crypto\sha1\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\arcfour\Makefile: lib\crypto\arcfour\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\md4\Makefile: lib\crypto\md4\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\md5\Makefile: lib\crypto\md5\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\yarrow\Makefile: lib\crypto\yarrow\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\aes\Makefile: lib\crypto\aes\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\old\Makefile: lib\crypto\old\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\crypto\raw\Makefile: lib\crypto\raw\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\des425\Makefile: lib\des425\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\gssapi\Makefile: lib\gssapi\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\gssapi\generic\Makefile: lib\gssapi\generic\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\gssapi\mechglue\Makefile: lib\gssapi\mechglue\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\gssapi\krb5\Makefile: lib\gssapi\krb5\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb4\Makefile: lib\krb4\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\Makefile: lib\krb5\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\asn.1\Makefile: lib\krb5\asn.1\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\ccache\Makefile: lib\krb5\ccache\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\ccache\ccapi\Makefile: lib\krb5\ccache\ccapi\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\error_tables\Makefile: lib\krb5\error_tables\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\keytab\Makefile: $$@.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\krb\Makefile: lib\krb5\krb\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\os\Makefile: lib\krb5\os\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\posix\Makefile: lib\krb5\posix\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##lib\krb5\rcache\Makefile: lib\krb5\rcache\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##util\Makefile: util\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##util\et\Makefile: util\et\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##util\profile\Makefile: util\profile\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##util\support\Makefile: util\support\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##util\windows\Makefile: util\windows\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##windows\Makefile: windows\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##windows\lib\Makefile: windows\lib\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##windows\cns\Makefile: windows\cns\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##windows\gina\Makefile: windows\gina\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##windows\gss\Makefile: windows\gss\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##windows\ms2mit\Makefile: windows\ms2mit\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##windows\wintel\Makefile: windows\wintel\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+##DOS##windows\kfwlogon\Makefile: windows\kfwlogon\Makefile.in $(MKFDEP)
+##DOS##	$(WCONFIG) config < $@.in > $@
+
+clean-windows:: Makefile-windows
+	@echo Making clean in util
+	cd util
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in include
+	cd ..\include
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in lib
+	cd ..\lib
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in windows
+	cd ..\windows
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in clients
+	cd ..\clients
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making in appl\gss-sample
+	cd ..\appl\gss-sample
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making in appl\gssftp\ftp
+	cd ..\..\appl\gssftp\ftp
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\..\..
+	@echo Making clean in root
+
+#
+# Renames DOS 8.3 filenames back to their proper, longer names.
+#
+ren2long:
+	-sh config/ren2long
+
+#
+# Builds the file that distributes Kerberos sources for DOS and 
+# Macintosh sites from the source tree on Unix.
+#
+ZIP=zip
+FILES= ./* \
+	clients/* clients/kdestroy/* clients/kinit/* clients/klist/* \
+	clients/kpasswd/* clients/kcpytkt/* clients/kdeltkt/* \
+	config/* include/* include/kerberosIV/* \
+	include/krb5/* include/krb5/stock/* include/sys/* krb524/* lib/* \
+	lib/crypto/* lib/crypto/crc32/* lib/crypto/des/* lib/crypto/dk/* \
+	lib/crypto/enc_provider/* lib/crypto/hash_provider/* \
+	lib/crypto/keyhash_provider/* lib/crypto/old/* lib/crypto/raw/* \
+	lib/crypto/sha1/* lib/crypto/arcfour/* lib/crypto/md4/* \
+	lib/crypto/md5/* lib/crypto/yarrow/* \
+	lib/des425/* lib/gssapi/* lib/gssapi/generic/* lib/gssapi/krb5/* \
+	lib/gssapi/mechglue/* lib/krb4/* \
+	lib/krb5/* lib/krb5/asn.1/* lib/krb5/krb/* \
+	lib/krb5/ccache/* lib/krb5/ccache/ccapi/* \
+	lib/krb5/error_tables/* \
+	lib/krb5/keytab/* lib/krb5/keytab/file/* lib/krb5/keytab/srvtab/* \
+	lib/krb5/os/* lib/krb5/posix/* lib/krb5/rcache/* \
+	util/* util/et/* util/profile/*
+
+WINFILES= util/windows/* windows/* windows/lib/* windows/cns/* \
+	windows/wintel/* windows/gss/* windows/gina/* windows/ms2mit/* \
+	windows/kfwlogon/*
+
+WINBINARYFILES=	windows/*/*.ico windows/*/*.doc windows/*/*.hlp \
+	windows/*/*.hpj windows/lib/*.lib
+
+#
+# Part of building the PC release has to be done on Unix. This includes
+# anything the requires awk.
+#
+AWK = awk
+AH  = util/et/et_h.awk
+AC  = util/et/et_c.awk
+INC = include/
+ET  = lib/krb5/error_tables/
+GG  = lib/gssapi/generic/
+GK  = lib/gssapi/krb5/
+PR  = util/profile/
+CE  = util/et/
+
+ETOUT =	\
+	$(INC)asn1_err.h $(ET)asn1_err.c \
+	$(INC)kdb5_err.h $(ET)kdb5_err.c \
+	$(INC)krb5_err.h $(ET)krb5_err.c \
+	$(INC)kv5m_err.h $(ET)kv5m_err.c \
+	$(INC)krb524_err.h $(ET)krb524_err.c \
+	$(INC)/kerberosIV/kadm_err.h lib/krb4/kadm_err.c \
+	$(INC)/kerberosIV/krb_err.h lib/krb4/krb_err.c \
+	$(PR)prof_err.h $(PR)prof_err.c \
+	$(GG)gssapi_err_generic.h $(GG)gssapi_err_generic.c \
+	$(GK)gssapi_err_krb5.h $(GK)gssapi_err_krb5.c \
+	lib/krb4/krb_err_txt.c
+
+HOUT =	$(INC)krb5.h $(GG)gssapi.h $(PR)profile.h
+
+CLEANUP= Makefile $(ETOUT) $(HOUT) \
+	include/profile.h include/krb5/osconf.h \
+	winfile.list
+
+
+kerbsrc.win: kerbsrc.zip
+
+winfile.list:
+	echo $(FILES) $(WINFILES) | tr ' ' \\012 | \
+		sed -f config/winexclude.sed > winfile.list
+
+dos-Makefile:
+	cat config/win-pre.in Makefile.in config/win-post.in | \
+		sed -e "s/^##DOS##//" -e "s/^##DOS//" > Makefile.tmp
+	mv Makefile.tmp Makefile
+
+prep-windows: dos-Makefile awk-windows-mac
+
+krbsrc83.zip: krbsrc83-is-obsolete
+
+krbsrc83-is-obsolete:
+	@echo "Win16 and krbsrc83.zip are no longer supported."
+	@echo "We don't support building under 8.3 restricted filesystems"
+	@echo "anymore.  You can still build for Win32 on filesystems"
+	@echo "without 8.3 restrictions using kerbsrc.zip"
+	@echo " "
+
+kerbsrc.zip: dos-Makefile awk-windows-mac winfile.list
+	rm -f kerbsrc.zip
+	$(ZIP) -@Dl kerbsrc.zip < winfile.list
+	$(ZIP) -D kerbsrc.zip $(WINBINARYFILES)
+	rm -f $(CLEANUP)
+
+kerbsrc-nt.zip: kerbsrc-nt-is-obsolete
+
+kerbsrc-nt-is-obsolete:
+	@echo "kerbsrc-nt.zip is now obsolete.  Just use and build kerbsrc.zip"
+	@echo "We don't support building under 8.3 restricted filesystems"
+	@echo "anymore, so what was kerbsrc-nt.zip is now kerbsrc.zip."
+	@echo " "
+
+$(INC)asn1_err.h: $(AH) $(ET)asn1_err.et
+	$(AWK) -f $(AH) outfile=$@ $(ET)asn1_err.et
+$(INC)kdb5_err.h: $(AH) $(ET)kdb5_err.et
+	$(AWK) -f $(AH) outfile=$@ $(ET)kdb5_err.et
+$(INC)krb5_err.h: $(AH) $(ET)krb5_err.et
+	$(AWK) -f $(AH) outfile=$@ $(ET)krb5_err.et
+$(INC)kv5m_err.h: $(AH) $(ET)kv5m_err.et
+	$(AWK) -f $(AH) outfile=$@ $(ET)kv5m_err.et
+$(INC)krb524_err.h: $(AH) $(ET)krb524_err.et
+	$(AWK) -f $(AH) outfile=$@ $(ET)krb524_err.et
+$(INC)/kerberosIV/kadm_err.h: $(AH) lib/krb4/kadm_err.et
+	$(AWK) -f $(AH) outfile=$@ lib/krb4/kadm_err.et
+$(INC)/kerberosIV/krb_err.h: $(AH) lib/krb4/krb_err.et
+	$(AWK) -f $(AH) outfile=$@ lib/krb4/krb_err.et
+$(PR)prof_err.h: $(AH) $(PR)prof_err.et
+	$(AWK) -f $(AH) outfile=$@ $(PR)prof_err.et
+$(GG)gssapi_err_generic.h: $(AH) $(GG)gssapi_err_generic.et
+	$(AWK) -f $(AH) outfile=$@ $(GG)gssapi_err_generic.et
+$(GK)gssapi_err_krb5.h: $(AH) $(GK)gssapi_err_krb5.et
+	$(AWK) -f $(AH) outfile=$@ $(GK)gssapi_err_krb5.et
+$(CE)test1.h: $(AH) $(CE)test1.et
+	$(AWK) -f $(AH) outfile=$@ $(CE)test1.et
+$(CE)test2.h: $(AH) $(CE)test2.et
+	$(AWK) -f $(AH) outfile=$@ $(CE)test2.et
+
+$(ET)asn1_err.c: $(AC) $(ET)asn1_err.et
+	$(AWK) -f $(AC) outfile=$@ $(ET)asn1_err.et
+$(ET)kdb5_err.c: $(AC) $(ET)kdb5_err.et
+	$(AWK) -f $(AC) outfile=$@ $(ET)kdb5_err.et
+$(ET)krb5_err.c: $(AC) $(ET)krb5_err.et
+	$(AWK) -f $(AC) outfile=$@ $(ET)krb5_err.et
+$(ET)kv5m_err.c: $(AC) $(ET)kv5m_err.et
+	$(AWK) -f $(AC) outfile=$@ $(ET)kv5m_err.et
+$(ET)krb524_err.c: $(AC) $(ET)krb524_err.et
+	$(AWK) -f $(AC) outfile=$@ $(ET)krb524_err.et
+lib/krb4/kadm_err.c: $(AC) lib/krb4/kadm_err.et
+	$(AWK) -f $(AC) outfile=$@ lib/krb4/kadm_err.et
+lib/krb4/krb_err.c: $(AC) lib/krb4/krb_err.et
+	$(AWK) -f $(AC) outfile=$@ lib/krb4/krb_err.et
+$(PR)prof_err.c: $(AC) $(PR)prof_err.et
+	$(AWK) -f $(AC) outfile=$@ $(PR)prof_err.et
+$(GG)gssapi_err_generic.c: $(AC) $(GG)gssapi_err_generic.et
+	$(AWK) -f $(AC) outfile=$@ $(GG)gssapi_err_generic.et
+$(GK)gssapi_err_krb5.c: $(AC) $(GK)gssapi_err_krb5.et
+	$(AWK) -f $(AC) outfile=$@ $(GK)gssapi_err_krb5.et
+$(CE)test1.c: $(AC) $(CE)test1.et
+	$(AWK) -f $(AC) outfile=$@ $(CE)test1.et
+$(CE)test2.c: $(AC) $(CE)test2.et
+	$(AWK) -f $(AC) outfile=$@ $(CE)test2.et
+
+lib/krb4/krb_err_txt.c: lib/krb4/krb_err.et
+	$(AWK) -f lib/krb4/et_errtxt.awk outfile=$@ \
+		lib/krb4/krb_err.et
+
+KRBHDEP = $(INC)krb5.hin $(INC)krb5_err.h $(INC)kdb5_err.h \
+	$(INC)kv5m_err.h $(INC)krb524_err.h $(INC)asn1_err.h
+
+$(INC)krb5.h: $(KRBHDEP)
+	rm -f $@
+	cat $(KRBHDEP) > $@
+$(PR)profile.h: $(PR)profile.hin $(PR)prof_err.h
+	rm -f $@
+	cat $(PR)profile.hin $(PR)prof_err.h > $@
+$(GG)gssapi.h: $(GG)gssapi.hin
+	rm -f $@
+	cat $(GG)gssapi.hin > $@
+
+awk-windows-mac: $(ETOUT) $(HOUT)
+
+#
+# The maybe-awk target needs to happen after AWK is defined.
+#
+
+##DOS##maybe-awk::
+##DOS##!ifdef WHICH_CMD
+##DOS##!if ![ $(WHICH_CMD) $(AWK) ]
+##DOS##maybe-awk:: awk-windows-mac
+##DOS##!endif
+##DOS##!endif
+
+clean-windows-mac:
+	rm -f $(CLEANUP)
+
+distclean-windows:
+	config\rm.bat $(CLEANUP:^/=^\)
+	config\rm.bat $(WINMAKEFILES)
+	config\rm.bat $(KBINDIR)\*.dll $(KBINDIR)\*.exe
+	@if exist $(KBINDIR)\nul rmdir $(KBINDIR)
+
+install-windows::
+	@if "$(KRB_INSTALL_DIR)"=="" @echo KRB_INSTALL_DIR is not defined!  Please define it.
+	@if "$(KRB_INSTALL_DIR)"=="" @dir /b \nul\nul
+	@if not exist "$(KRB_INSTALL_DIR)\$(NULL)" @echo The directory $(KRB_INSTALL_DIR) does not exist.  Please create it.
+	@if not exist "$(KRB_INSTALL_DIR)\$(NULL)" @dir /b $(KRB_INSTALL_DIR)\nul
+	@if not exist "$(KRB_INSTALL_DIR)\include\$(NULL)" @mkdir "$(KRB_INSTALL_DIR)\include"
+	@if not exist "$(KRB_INSTALL_DIR)\include\gssapi\$(NULL)" @mkdir "$(KRB_INSTALL_DIR)\include\gssapi"
+	@if not exist "$(KRB_INSTALL_DIR)\lib\$(NULL)" @mkdir "$(KRB_INSTALL_DIR)\lib"
+	@if not exist "$(KRB_INSTALL_DIR)\bin\$(NULL)" @mkdir "$(KRB_INSTALL_DIR)\bin"
+	$(CP) include\krb5.h "$(KRB_INSTALL_DIR)\include\."
+	$(CP) include\win-mac.h "$(KRB_INSTALL_DIR)\include\."
+	$(CP) include\profile.h "$(KRB_INSTALL_DIR)\include\."
+	$(CP) include\com_err.h "$(KRB_INSTALL_DIR)\include\."
+	$(CP) include\gssapi\gssapi.h "$(KRB_INSTALL_DIR)\include\gssapi\."
+	$(CP) include\gssapi\gssapi_krb5.h "$(KRB_INSTALL_DIR)\include\gssapi\."
+	$(CP) lib\$(OUTPRE)*.lib "$(KRB_INSTALL_DIR)\lib\."
+	$(CP) lib\$(OUTPRE)*.dll "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) windows\cns\$(OUTPRE)krb5.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) windows\wintel\$(OUTPRE)telnet.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) windows\gss\$(OUTPRE)gss.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) appl\gss-sample\$(OUTPRE)gss-server.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) appl\gss-sample\$(OUTPRE)gss-client.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) windows\ms2mit\$(OUTPRE)ms2mit.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) appl\gssftp\ftp\$(OUTPRE)ftp.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) clients\kvno\$(OUTPRE)kvno.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) clients\klist\$(OUTPRE)klist.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) clients\kinit\$(OUTPRE)kinit.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) clients\kdestroy\$(OUTPRE)kdestroy.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) clients\kcpytkt\$(OUTPRE)kcpytkt.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) clients\kdeltkt\$(OUTPRE)kdeltkt.exe "$(KRB_INSTALL_DIR)\bin\."
+	$(CP) clients\kpasswd\$(OUTPRE)kpasswd.exe "$(KRB_INSTALL_DIR)\bin\."
+	@if exist "$(KRB_INSTALL_DIR)\bin\krb4_32.dll" del "$(KRB_INSTALL_DIR)\bin\krb4_32.dll"
+	@if exist "$(KRB_INSTALL_DIR)\lib\krb4_32.lib" del "$(KRB_INSTALL_DIR)\lib\krb4_32.lib"
+
+install-unix:: 
+	$(INSTALL_SCRIPT) krb5-config \
+		$(DESTDIR)$(CLIENT_BINDIR)/krb5-config
+	$(INSTALL_DATA) $(srcdir)/krb5-config.M $(DESTDIR)$(CLIENT_MANDIR)/krb5-config.1
+
+krb5-config: $(srcdir)/krb5-config.in $(thisconfigdir)/config.status
+	cd $(thisconfigdir) && $(SHELL) config.status krb5-config
+
+# Test to ensure that krb5-config does not spit out things like
+# $(PURE) or $(LDFLAGS) in case someone changes config/shlib.conf
+check-unix:: krb5-config
+	$(SHELL) $(srcdir)/t_krbconf
+check-prerecurse: fake-install
diff --git a/mechglue/src/aclocal.m4 b/mechglue/src/aclocal.m4
new file mode 100644
index 000000000..46a70e69a
--- /dev/null
+++ b/mechglue/src/aclocal.m4
@@ -0,0 +1,1795 @@
+AC_PREREQ(2.52)
+AC_COPYRIGHT([Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Massachusetts Institute of Technology.
+])
+dnl
+dnl Figure out the top of the source and build trees.  We depend on localdir
+dnl being a relative pathname; we could make it general later, but for now 
+dnl this is good enough.
+dnl
+dnl esyscmd([test -r aclocal.m4 && echo YES])
+define([fileexists],[dnl
+pushdef([x],esyscmd([if test -r $1; then echo YES;else echo NO; fi]))dnl
+dnl Strip out newline.
+ifelse(x,[YES
+],[YES],x,[NO
+],[NO],UNKNOWN)[]popdef([x])])
+define([K5_TOPDIR],dnl
+ifelse(fileexists(./aclocal.m4),YES,[.],[dnl
+ifelse(fileexists(../aclocal.m4),YES,[..],[dnl
+ifelse(fileexists(../../aclocal.m4),YES,[../..],[dnl
+ifelse(fileexists(../../../aclocal.m4),YES,[../../..],[dnl
+ifelse(fileexists(../../../../aclocal.m4),YES,[../../../..],[dnl
+errprint(__file__:__line__: Cannot find path to aclocal.m4[
+]) m4exit(1) dnl sometimes that does not work?
+builtin(m4exit,1)UNKNOWN])])])])]))
+dnl
+AC_DEFUN(V5_SET_TOPDIR,[dnl
+ac_reltopdir="K5_TOPDIR"
+if test ! -r "$srcdir/K5_TOPDIR/aclocal.m4"; then
+  AC_MSG_ERROR([Configure could not determine the relative topdir])
+fi
+ac_topdir=$srcdir/$ac_reltopdir
+ac_config_fragdir=$ac_reltopdir/config
+krb5_pre_in=$ac_config_fragdir/pre.in
+krb5_post_in=$ac_config_fragdir/post.in
+# echo "Looking for $srcdir/$ac_config_fragdir"
+if test -d "$srcdir/$ac_config_fragdir"; then
+  AC_CONFIG_AUX_DIR(K5_TOPDIR/config)
+else
+  AC_MSG_ERROR([can not find config/ directory in $ac_reltopdir])
+fi
+])dnl
+dnl
+dnl Version info.
+dnl
+pushdef([x],esyscmd([sed -n 's/#define \([A-Z0-9_]*\)[ \t]*\(.*\)/\1=\2/p' < ]K5_TOPDIR/patchlevel.h))
+define([PL_KRB5_MAJOR_RELEASE],regexp(x,[KRB5_MAJOR_RELEASE=\(.*\)],[\1]))
+ifelse(PL_KRB5_MAJOR_RELEASE,,[errprint([Can't determine KRB5_MAJOR_RELEASE value from patchlevel.h.
+]) m4exit(1) dnl sometimes that does not work?
+builtin(m4exit,1)])
+define([PL_KRB5_MINOR_RELEASE],regexp(x,[KRB5_MINOR_RELEASE=\(.*\)],[\1]))
+ifelse(PL_KRB5_MINOR_RELEASE,,[errprint([Can't determine KRB5_MINOR_RELEASE value from patchlevel.h.
+]) m4exit(1) dnl sometimes that does not work?
+builtin(m4exit,1)])
+define([PL_KRB5_PATCHLEVEL],regexp(x,[KRB5_PATCHLEVEL=\(.*\)],[\1]))
+ifelse(PL_KRB5_PATCHLEVEL,,[errprint([Can't determine KRB5_PATCHLEVEL value from patchlevel.h.
+]) m4exit(1) dnl sometimes that does not work?
+builtin(m4exit,1)])
+define([PL_KRB5_RELTAIL],regexp(x,[KRB5_RELTAIL="\(.*\)"],[\1]))
+dnl RELTAIL is allowed to not be defined.
+popdef([x])
+define([K5_VERSION],PL_KRB5_MAJOR_RELEASE.PL_KRB5_MINOR_RELEASE[]ifelse(PL_KRB5_PATCHLEVEL,0,,.PL_KRB5_PATCHLEVEL)ifelse(PL_KRB5_RELTAIL,,,-PL_KRB5_RELTAIL))
+define([K5_BUGADDR],krb5-bugs@mit.edu)
+define([K5_AC_INIT],[AC_INIT(Kerberos 5, K5_VERSION, K5_BUGADDR, krb5)
+AC_CONFIG_SRCDIR($1)
+build_dynobj=no])
+dnl
+dnl drop in standard rules for all configure files -- CONFIG_RULES
+dnl
+AC_DEFUN(CONFIG_RULES,[dnl
+AC_REQUIRE([V5_SET_TOPDIR]) dnl
+EXTRA_FILES=""
+AC_SUBST(EXTRA_FILES)
+WITH_CC dnl
+AC_REQUIRE_CPP
+if test -z "$LD" ; then LD=$CC; fi
+AC_ARG_VAR(LD,[linker command [CC]])
+AC_SUBST(LDFLAGS) dnl
+WITH_KRB4 dnl
+KRB5_AC_CHOOSE_ET dnl
+KRB5_AC_CHOOSE_SS dnl
+KRB5_AC_CHOOSE_DB dnl
+dnl allow stuff in tree to access deprecated/private stuff for now
+AC_DEFINE([KRB5_PRIVATE], 1, [Define only if building in-tree])
+AC_DEFINE([KRB5_DEPRECATED], 1, [Define only if building in-tree])
+AC_C_CONST dnl
+WITH_NETLIB dnl
+WITH_HESIOD dnl
+KRB5_AC_MAINTAINER_MODE dnl
+AC_ARG_PROGRAM dnl
+dnl
+dnl This identifies the top of the source tree relative to the directory 
+dnl in which the configure file lives.
+dnl
+CONFIG_RELTOPDIR=$ac_reltopdir
+AC_SUBST(CONFIG_RELTOPDIR)
+AC_SUBST(subdirs)
+lib_frag=$srcdir/$ac_config_fragdir/lib.in
+AC_SUBST_FILE(lib_frag)
+libobj_frag=$srcdir/$ac_config_fragdir/libobj.in
+AC_SUBST_FILE(libobj_frag)
+libnover_frag=$srcdir/$ac_config_fragdir/libnover.in
+AC_SUBST_FILE(libnover_frag)
+dnl
+KRB5_AC_PRAGMA_WEAK_REF
+KRB5_LIB_PARAMS
+KRB5_AC_INITFINI
+KRB5_AC_ENABLE_THREADS
+KRB5_AC_FIND_DLOPEN
+])dnl
+
+dnl Maintainer mode, akin to what automake provides, 'cept we don't
+dnl want to use automake right now.
+AC_DEFUN([KRB5_AC_MAINTAINER_MODE],
+[AC_ARG_ENABLE([maintainer-mode],
+AC_HELP_STRING([--enable-maintainer-mode],[enable rebuilding of source files, Makefiles, etc]),
+USE_MAINTAINER_MODE=$enableval,
+USE_MAINTAINER_MODE=no)
+if test "$USE_MAINTAINER_MODE" = yes; then
+  MAINTAINER_MODE_TRUE=
+  MAINTAINER_MODE_FALSE='#'
+  AC_MSG_NOTICE(enabling maintainer mode)
+else
+  MAINTAINER_MODE_TRUE='#'
+  MAINTAINER_MODE_FALSE=
+fi
+MAINT=$MAINTAINER_MODE_TRUE
+AC_SUBST(MAINTAINER_MODE_TRUE)
+AC_SUBST(MAINTAINER_MODE_FALSE)
+AC_SUBST(MAINT)
+])
+
+dnl
+AC_DEFUN([KRB5_AC_INITFINI],[
+dnl Do we want initialization at load time?
+AC_ARG_ENABLE([delayed-initialization],
+AC_HELP_STRING([--disable-delayed-initialization],initialize library code when loaded @<:@delay until first use@:>@), , enable_delayed_initialization=yes)
+case "$enable_delayed_initialization" in
+  yes)
+    AC_DEFINE(DELAY_INITIALIZER,1,[Define if library initialization should be delayed until first use]) ;;
+  no) ;;
+  *)  AC_MSG_ERROR(invalid option $enable_delayed_initialization for delayed-initialization) ;;
+esac
+dnl We always want finalization at unload time.
+dnl
+dnl Can we do things through gcc?
+KRB5_AC_GCC_ATTRS
+dnl How about with the linker?
+if test -z "$use_linker_init_option" ; then
+  AC_MSG_ERROR(ran INITFINI before checking shlib.conf?)
+fi
+if test "$use_linker_init_option" = yes; then
+  AC_DEFINE(USE_LINKER_INIT_OPTION,1,[Define if link-time options for library initialization will be used])
+fi
+if test "$use_linker_fini_option" = yes; then
+  AC_DEFINE(USE_LINKER_FINI_OPTION,1,[Define if link-time options for library finalization will be used])
+fi
+])
+
+dnl find dlopen
+AC_DEFUN([KRB5_AC_FIND_DLOPEN],[
+AC_CHECK_LIB(dl, dlopen, DL_LIB=-ldl)
+AC_CHECK_LIB(ld, main, DL_LIB=-lld)
+AC_SUBST(DL_LIB)
+])
+
+
+dnl Hack for now.
+AC_DEFUN([KRB5_AC_ENABLE_THREADS],[
+AC_ARG_ENABLE([thread-support],
+AC_HELP_STRING([--disable-thread-support],don't enable thread support @<:@enabled@:>@), , enable_thread_support=yes)
+if test "$enable_thread_support" = yes ; then
+  AC_MSG_NOTICE(enabling thread support)
+  AC_DEFINE(ENABLE_THREADS,1,[Define if thread support enabled])
+fi
+dnl Maybe this should be inside the conditional above?  Doesn't cache....
+if test "$enable_thread_support" = yes; then
+  ACX_PTHREAD(,[AC_MSG_ERROR([cannot determine options for enabling thread support; try --disable-thread-support])])
+  AC_MSG_NOTICE(PTHREAD_CC = $PTHREAD_CC)
+  AC_MSG_NOTICE(PTHREAD_CFLAGS = $PTHREAD_CFLAGS)
+  AC_MSG_NOTICE(PTHREAD_LIBS = $PTHREAD_LIBS)
+  dnl Not really needed -- if pthread.h isn't found, ACX_PTHREAD will fail.
+  dnl AC_CHECK_HEADERS(pthread.h)
+  # AIX and Tru64 don't support weak references, and don't have
+  # stub versions of the pthread code in libc.
+  case "${host_os}" in
+    aix* | osf*)
+      # On these platforms, we'll always pull in the thread support.
+      LIBS="$LIBS $PTHREAD_LIBS"
+      CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+      # We don't need to sometimes add the flags we've just folded in...
+      PTHREAD_LIBS=
+      PTHREAD_CFLAGS=
+      ;;
+    hpux*)
+      # These are the flags that "gcc -pthread" adds.  But we don't
+      # want "-pthread" because that has link-time effects, and we
+      # don't exclude CFLAGS when linking.  *sigh*
+      PTHREAD_CFLAGS="-D_REENTRANT -D_THREAD_SAFE -D_POSIX_C_SOURCE=199506L"
+      ;;
+    solaris*)
+      # On Solaris 10 with gcc 3.4.3, the autoconf archive macro doesn't
+      # get the right result.
+      if test "$GCC" = yes ; then
+        PTHREAD_CFLAGS="-D_REENTRANT -pthreads"
+      fi
+      ;;
+  esac
+  THREAD_SUPPORT=1
+else
+  PTHREAD_CC="$CC"
+  PTHREAD_CFLAGS=""
+  PTHREAD_LIBS=""
+  THREAD_SUPPORT=0
+fi
+AC_SUBST(THREAD_SUPPORT)
+dnl We want to know where these routines live, so on systems with weak
+dnl reference support we can figure out whether or not the pthread library
+dnl has been linked in.
+dnl If we don't add any libraries for thread support, don't bother.
+AC_CHECK_FUNCS(pthread_once pthread_mutexattr_setrobust_np pthread_rwlock_init)
+old_CC="$CC"
+test "$PTHREAD_CC" != "" && test "$ac_cv_c_compiler_gnu" = no && CC=$PTHREAD_CC
+old_CFLAGS="$CFLAGS"
+# On Solaris, -pthreads is added to CFLAGS, no extra explicit libraries.
+CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+AC_SUBST(PTHREAD_CFLAGS)
+old_LIBS="$LIBS"
+LIBS="$PTHREAD_LIBS $LIBS"
+AC_MSG_NOTICE(rechecking with PTHREAD_... options)
+AC_CHECK_LIB(c, pthread_mutexattr_setrobust_np,
+  [AC_DEFINE(HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB,1,[Define if pthread_mutexattr_setrobust_np is provided in the thread library.])])
+AC_CHECK_LIB(c, pthread_rwlock_init,
+  [AC_DEFINE(HAVE_PTHREAD_RWLOCK_INIT_IN_THREAD_LIB,1,[Define if pthread_rwlock_init is provided in the thread library.])])
+LIBS="$old_LIBS"
+CC="$old_CC"
+CFLAGS="$old_CFLAGS"
+])
+
+dnl This is somewhat gross and should go away when the build system
+dnl is revamped. -- tlyu
+dnl DECLARE_SYS_ERRLIST - check for sys_errlist in libc
+dnl
+AC_DEFUN([DECLARE_SYS_ERRLIST],
+[AC_CACHE_CHECK([for sys_errlist declaration], krb5_cv_decl_sys_errlist,
+[AC_TRY_COMPILE([#include <stdio.h>
+#include <errno.h>], [1+sys_nerr;],
+krb5_cv_decl_sys_errlist=yes, krb5_cv_decl_sys_errlist=no)])
+# assume sys_nerr won't be declared w/o being in libc
+if test $krb5_cv_decl_sys_errlist = yes; then
+  AC_DEFINE(SYS_ERRLIST_DECLARED,1,[Define if sys_errlist is defined in errno.h])
+  AC_DEFINE(HAVE_SYS_ERRLIST,1,[Define if sys_errlist in libc])
+else
+  # This means that sys_errlist is not declared in errno.h, but may still
+  # be in libc.
+  AC_CACHE_CHECK([for sys_errlist in libc], krb5_cv_var_sys_errlist,
+  [AC_TRY_LINK([extern int sys_nerr;], [if (1+sys_nerr < 0) return 1;],
+  krb5_cv_var_sys_errlist=yes, krb5_cv_var_sys_errlist=no;)])
+  if test $krb5_cv_var_sys_errlist = yes; then
+    AC_DEFINE(HAVE_SYS_ERRLIST,1,[Define if sys_errlist in libc])
+    # Do this cruft for backwards compatibility for now.
+    AC_DEFINE(NEED_SYS_ERRLIST,1,[Define if need to declare sys_errlist])
+  else
+    AC_MSG_WARN([sys_errlist is neither in errno.h nor in libc])
+  fi
+fi])
+
+dnl
+dnl check for sigmask/sigprocmask -- CHECK_SIGPROCMASK
+dnl
+AC_DEFUN(CHECK_SIGPROCMASK,[
+AC_MSG_CHECKING([for use of sigprocmask])
+AC_CACHE_VAL(krb5_cv_func_sigprocmask_use,
+[AC_TRY_LINK([#include <signal.h>], [sigprocmask(SIG_SETMASK,0,0);],
+ krb5_cv_func_sigprocmask_use=yes,
+AC_TRY_LINK([#include <signal.h>], [sigmask(1);], 
+ krb5_cv_func_sigprocmask_use=no, krb5_cv_func_sigprocmask_use=yes))])
+AC_MSG_RESULT($krb5_cv_func_sigprocmask_use)
+if test $krb5_cv_func_sigprocmask_use = yes; then
+ AC_DEFINE(USE_SIGPROCMASK)
+fi
+])dnl
+dnl
+AC_DEFUN(AC_PROG_ARCHIVE, [AC_CHECK_PROG(ARCHIVE, ar, ar cqv, false)])dnl
+AC_DEFUN(AC_PROG_ARCHIVE_ADD, [AC_CHECK_PROG(ARADD, ar, ar cruv, false)])dnl
+dnl
+dnl check for <dirent.h> -- CHECK_DIRENT
+dnl (may need to be more complex later)
+dnl
+AC_DEFUN(CHECK_DIRENT,[
+AC_CHECK_HEADER(dirent.h,AC_DEFINE(USE_DIRENT_H,1,[Define if you have dirent.h functionality]))])dnl
+dnl
+dnl check if union wait is defined, or if WAIT_USES_INT -- CHECK_WAIT_TYPE
+dnl
+AC_DEFUN(CHECK_WAIT_TYPE,[
+AC_MSG_CHECKING([if argument to wait is int *])
+AC_CACHE_VAL(krb5_cv_struct_wait,
+dnl Test for prototype clash - if there is none - then assume int * works
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/wait.h>
+extern pid_t wait(int *);],[], krb5_cv_struct_wait=no,dnl
+dnl Else fallback on old stuff
+[AC_TRY_COMPILE(
+[#include <sys/wait.h>], [union wait i;
+#ifdef WEXITSTATUS
+  WEXITSTATUS (i);
+#endif
+], 
+	krb5_cv_struct_wait=yes, krb5_cv_struct_wait=no)])])
+AC_MSG_RESULT($krb5_cv_struct_wait)
+if test $krb5_cv_struct_wait = no; then
+	AC_DEFINE(WAIT_USES_INT,1,[Define if wait takes int as a argument])
+fi
+])dnl
+dnl
+dnl check for POSIX signal handling -- CHECK_SIGNALS
+dnl
+AC_DEFUN(CHECK_SIGNALS,[
+AC_CHECK_FUNC(sigprocmask,
+AC_MSG_CHECKING(for sigset_t and POSIX_SIGNALS)
+AC_CACHE_VAL(krb5_cv_type_sigset_t,
+[AC_TRY_COMPILE(
+[#include <signal.h>],
+[sigset_t x],
+krb5_cv_type_sigset_t=yes, krb5_cv_type_sigset_t=no)])
+AC_MSG_RESULT($krb5_cv_type_sigset_t)
+if test $krb5_cv_type_sigset_t = yes; then
+  AC_DEFINE(POSIX_SIGNALS,1,[Define if POSIX signal handling is used])
+fi
+)])dnl
+dnl
+dnl check for signal type
+dnl
+dnl AC_RETSIGTYPE isn't quite right, but almost.
+AC_DEFUN(KRB5_SIGTYPE,[
+AC_MSG_CHECKING([POSIX signal handlers])
+AC_CACHE_VAL(krb5_cv_has_posix_signals,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+extern void (*signal ()) ();], [],
+krb5_cv_has_posix_signals=yes, krb5_cv_has_posix_signals=no)])
+AC_MSG_RESULT($krb5_cv_has_posix_signals)
+if test $krb5_cv_has_posix_signals = yes; then
+   stype=void
+   AC_DEFINE(POSIX_SIGTYPE, 1, [Define if POSIX signal handlers are used])
+else
+  if test $ac_cv_type_signal = void; then
+     stype=void
+  else
+     stype=int
+  fi
+fi
+AC_DEFINE_UNQUOTED(krb5_sigtype, $stype, [Define krb5_sigtype to type of signal handler])dnl
+])dnl
+dnl
+dnl check for POSIX setjmp/longjmp -- CHECK_SETJMP
+dnl
+AC_DEFUN(CHECK_SETJMP,[
+AC_CHECK_FUNC(sigsetjmp,
+AC_MSG_CHECKING(for sigjmp_buf)
+AC_CACHE_VAL(krb5_cv_struct_sigjmp_buf,
+[AC_TRY_COMPILE(
+[#include <setjmp.h>],[sigjmp_buf x],
+krb5_cv_struct_sigjmp_buf=yes,krb5_cv_struct_sigjmp_buf=no)])
+AC_MSG_RESULT($krb5_cv_struct_sigjmp_buf)
+if test $krb5_cv_struct_sigjmp_buf = yes; then
+  AC_DEFINE(POSIX_SETJMP)
+fi
+)])dnl
+dnl
+dnl Check for IPv6 compile-time support.
+dnl
+AC_DEFUN(KRB5_AC_INET6,[
+AC_CHECK_HEADERS(sys/types.h sys/socket.h netinet/in.h netdb.h)
+AC_CHECK_FUNCS(inet_ntop inet_pton getnameinfo)
+dnl getaddrinfo test needs netdb.h, for proper compilation on alpha
+dnl under OSF/1^H^H^H^H^HDigital^H^H^H^H^H^H^HTru64 UNIX, where it's
+dnl a macro
+AC_MSG_CHECKING(for getaddrinfo)
+AC_CACHE_VAL(ac_cv_func_getaddrinfo,
+[AC_TRY_LINK([#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif],[
+struct addrinfo *ai;
+getaddrinfo("kerberos.mit.edu", "echo", 0, &ai);
+], ac_cv_func_getaddrinfo=yes, ac_cv_func_getaddrinfo=no)])
+AC_MSG_RESULT($ac_cv_func_getaddrinfo)
+if test $ac_cv_func_getaddrinfo = yes; then
+  AC_DEFINE(HAVE_GETADDRINFO,1,[Define if you have the getaddrinfo function])
+fi
+dnl
+AC_REQUIRE([KRB5_SOCKADDR_SA_LEN])dnl
+AC_ARG_ENABLE([ipv6], , AC_MSG_WARN(enable/disable-ipv6 option is deprecated))dnl
+KRB5_AC_CHECK_INET6
+])dnl
+dnl
+AC_DEFUN(KRB5_AC_CHECK_TYPE_WITH_HEADERS,[
+AC_MSG_CHECKING(for type $1)
+changequote(<<,>>)dnl
+varname=`echo $1 | sed 's,[ -],_,g'`
+changequote([,])dnl
+AC_CACHE_VAL(krb5_cv_$varname,[
+AC_TRY_COMPILE([$2],[ $1 foo; ], eval krb5_cv_$varname=yes, eval krb5_cv_$varname=no)])
+eval x="\$krb5_cv_$varname"
+AC_MSG_RESULT($x)
+if eval test "$x" = yes ; then
+  AC_DEFINE_UNQUOTED(HAVE_`echo $varname | tr [[[a-z]]] [[[A-Z]]]`)
+fi])
+dnl
+dnl
+AC_DEFUN(KRB5_AC_CHECK_SOCKADDR_STORAGE,[
+KRB5_AC_CHECK_TYPE_WITH_HEADERS(struct sockaddr_storage, [
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+])])dnl
+dnl
+dnl
+AC_DEFUN(KRB5_AC_CHECK_INET6,[
+AC_REQUIRE([KRB5_AC_CHECK_SOCKADDR_STORAGE])dnl
+AC_MSG_CHECKING(for IPv6 compile-time support)
+AC_CACHE_VAL(krb5_cv_inet6,[
+if test "$ac_cv_func_inet_ntop" != "yes" ; then
+  krb5_cv_inet6=no
+else
+AC_TRY_COMPILE([
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+],[
+  struct sockaddr_in6 in;
+  AF_INET6;
+  IN6_IS_ADDR_LINKLOCAL (&in.sin6_addr);
+],krb5_cv_inet6=yes,krb5_cv_inet6=no)])
+fi
+AC_MSG_RESULT($krb5_cv_inet6)
+if test "$krb5_cv_inet6" = no && test "$ac_cv_func_inet_ntop" = yes; then
+AC_MSG_CHECKING(for IPv6 compile-time support with -DINET6)
+AC_CACHE_VAL(krb5_cv_inet6_with_dinet6,[
+old_CC="$CC"
+CC="$CC -DINET6"
+AC_TRY_COMPILE([
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+],[
+  struct sockaddr_in6 in;
+  AF_INET6;
+  IN6_IS_ADDR_LINKLOCAL (&in.sin6_addr);
+],krb5_cv_inet6_with_dinet6=yes,krb5_cv_inet6_with_dinet6=no)
+CC="$old_CC"])
+AC_MSG_RESULT($krb5_cv_inet6_with_dinet6)
+fi
+if test $krb5_cv_inet6 = yes || test "$krb5_cv_inet6_with_dinet6" = yes; then
+  if test "$krb5_cv_inet6_with_dinet6" = yes; then
+    AC_DEFINE(INET6,1,[May need to be defined to enable IPv6 support, for example on IRIX])
+  fi
+  AC_DEFINE(KRB5_USE_INET6,1,[Define if we should compile in IPv6 support (even if we can't use it at run time)])
+fi
+])dnl
+dnl
+dnl Generic File existence tests
+dnl 
+dnl K5_AC_CHECK_FILE(FILE, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl
+AC_DEFUN(K5_AC_CHECK_FILE,
+[AC_REQUIRE([AC_PROG_CC])dnl
+dnl Do the transliteration at runtime so arg 1 can be a shell variable.
+ac_safe=`echo "$1" | sed 'y%./+-%__p_%'`
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(ac_cv_file_$ac_safe,
+[if test "$cross_compiling" = yes; then
+  errprint(__file__:__line__: warning: Cannot check for file existence when cross compiling
+)dnl
+  AC_MSG_ERROR(Cannot check for file existence when cross compiling)
+else
+  if test -r $1; then
+    eval "ac_cv_file_$ac_safe=yes"
+  else
+    eval "ac_cv_file_$ac_safe=no"
+  fi
+fi])dnl
+if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then
+  AC_MSG_RESULT(yes)
+  ifelse([$2], , :, [$2])
+else
+  AC_MSG_RESULT(no)
+ifelse([$3], , , [$3
+np])dnl
+fi
+])
+dnl
+dnl K5_AC_CHECK_FILES(FILE... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl
+AC_DEFUN(K5_AC_CHECK_FILES,
+[AC_REQUIRE([AC_PROG_CC])dnl
+for ac_file in $1
+do
+K5_AC_CHECK_FILE($ac_file,
+[changequote(, )dnl
+  ac_tr_file=HAVE`echo $ac_file | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+changequote([, ])dnl
+  AC_DEFINE_UNQUOTED($ac_tr_file) $2], $3)dnl
+done
+])
+dnl
+dnl set $(KRB4) from --with-krb4=value -- WITH_KRB4
+dnl
+AC_DEFUN(WITH_KRB4,[
+AC_ARG_WITH([krb4],
+[  --without-krb4          don't include Kerberos V4 backwards compatibility
+  --with-krb4             use V4 libraries included with V5 (default)
+  --with-krb4=KRB4DIR     use preinstalled V4 libraries],
+,
+withval=yes
+)dnl
+if test $withval = no; then
+	AC_MSG_NOTICE(no krb4 support)
+	KRB4_LIB=
+	KRB4_DEPLIB=
+	KRB4_INCLUDES=
+	KRB4_LIBPATH=
+	KRB_ERR_H_DEP=
+	krb5_cv_build_krb4_libs=no
+	krb5_cv_krb4_libdir=
+else
+ AC_DEFINE([KRB5_KRB4_COMPAT], 1, [Define this if building with krb4 compat])
+ if test $withval = yes; then
+	AC_MSG_NOTICE(enabling built in krb4 support)
+	KRB4_DEPLIB='$(TOPLIBD)/libkrb4$(DEPLIBEXT)'
+	KRB4_LIB=-lkrb4
+	KRB4_INCLUDES='-I$(SRCTOP)/include/kerberosIV -I$(BUILDTOP)/include/kerberosIV'
+	KRB4_LIBPATH=
+	KRB_ERR_H_DEP='$(BUILDTOP)/include/kerberosIV/krb_err.h'
+	krb5_cv_build_krb4_libs=yes
+	krb5_cv_krb4_libdir=
+ else
+	AC_MSG_NOTICE(using preinstalled krb4 in $withval)
+	KRB4_LIB="-lkrb"
+dnl	DEPKRB4_LIB="$withval/lib/libkrb.a"
+	KRB4_INCLUDES="-I$withval/include"
+	KRB4_LIBPATH="-L$withval/lib"
+	KRB_ERR_H_DEP=
+	krb5_cv_build_krb4_libs=no
+	krb5_cv_krb4_libdir="$withval/lib"
+ fi
+fi
+AC_SUBST(KRB4_INCLUDES)
+AC_SUBST(KRB4_LIBPATH)
+AC_SUBST(KRB4_LIB)
+AC_SUBST(KRB4_DEPLIB)
+AC_SUBST(KRB_ERR_H_DEP)
+dnl We always compile the des425 library
+DES425_DEPLIB='$(TOPLIBD)/libdes425$(DEPLIBEXT)'
+DES425_LIB=-ldes425
+AC_SUBST(DES425_DEPLIB)
+AC_SUBST(DES425_LIB)
+])dnl
+dnl
+dnl
+AC_DEFUN(KRB5_AC_CHECK_FOR_CFLAGS,[
+AC_BEFORE([$0],[AC_PROG_CC])
+krb5_ac_cflags_set=${CFLAGS+set}
+])
+dnl
+AC_DEFUN(WITH_CC,[dnl
+AC_REQUIRE([KRB5_AC_CHECK_FOR_CFLAGS])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+krb5_cv_prog_gcc=$ac_cv_c_compiler_gnu
+if test $ac_cv_c_compiler_gnu = yes ; then
+     HAVE_GCC=yes
+     else HAVE_GCC=
+fi
+AC_SUBST(HAVE_GCC)
+AC_CACHE_CHECK([for GNU linker], krb5_cv_prog_gnu_ld,
+[krb5_cv_prog_gnu_ld=no
+if test "$GCC" = yes; then
+  if AC_TRY_COMMAND([$CC -Wl,-v 2>&1 dnl
+			| grep "GNU ld" > /dev/null]); then
+    krb5_cv_prog_gnu_ld=yes
+  fi
+fi])
+# maybe add -Waggregate-return, or can we assume that actually works by now?
+# -Wno-comment used to be used for SunOS system header <sys/stream.h>
+# -Wno-long-long, if needed, for k5-platform.h without inttypes.h etc.
+extra_gcc_warn_opts="-Wall -Wmissing-prototypes -Wcast-qual \
+ -Wcast-align -Wconversion -Wshadow"
+if test "$GCC" = yes ; then
+  if test "x$krb5_ac_cflags_set" = xset ; then
+    AC_MSG_NOTICE(not adding extra gcc warning flags because CFLAGS was set)
+  else
+    AC_MSG_NOTICE(adding extra warning flags for gcc)
+    CFLAGS="$CFLAGS $extra_gcc_warn_opts"
+    if test "`uname -s`" = Darwin ; then
+      AC_MSG_NOTICE(skipping pedantic warnings on Darwin)
+    elif test "`uname -s`" = Linux ; then
+      AC_MSG_NOTICE(skipping pedantic warnings on Linux)
+    else
+      CFLAGS="$CFLAGS -pedantic"
+    fi
+  fi
+  if test "`uname -s`" = Darwin ; then
+    # Someday this should be a feature test.
+    # One current (Jaguar = OS 10.2) problem:
+    # Archive library with foo.o undef sym X and bar.o common sym X,
+    # if foo.o is pulled in at link time, bar.o may not be, causing
+    # the linker to complain.
+    # Dynamic library problems too?
+    case "$CC $CFLAGS" in
+    *-fcommon*) ;; # why someone would do this, I don't know
+    *-fno-common*) ;; # okay, they're already doing the right thing
+    *)
+      AC_MSG_NOTICE(disabling the use of common storage on Darwin)
+      CFLAGS="$CFLAGS -fno-common"
+      ;;
+    esac
+    case "$LD $LDFLAGS" in
+    *-Wl,-search_paths_first*) ;;
+    *) LDFLAGS="${LDFLAGS} -Wl,-search_paths_first" ;;
+    esac
+  fi
+else
+  if test "`uname -s`" = AIX ; then
+    # Using AIX but not GCC, assume native compiler.
+    # The native compiler appears not to give a nonzero exit
+    # status for certain classes of errors, like missing arguments
+    # in function calls.  Let's try to fix that with -qhalt=e.
+    case "$CC $CFLAGS" in
+      *-qhalt=*) ;;
+      *)
+	CFLAGS="$CFLAGS -qhalt=e"
+	AC_MSG_NOTICE(adding -qhalt=e for better error reporting)
+	;;
+    esac
+    # Also, the optimizer isn't turned on by default, which means
+    # the static inline functions get left in random object files,
+    # leading to references to pthread_mutex_lock from anything that
+    # includes k5-int.h whether it uses threads or not.
+    case "$CC $CFLAGS" in
+      *-O*) ;;
+      *)
+	CFLAGS="$CFLAGS -O"
+	AC_MSG_NOTICE(adding -O for inline thread-support function elimination)
+	;;
+    esac
+  fi
+fi
+])dnl
+dnl
+dnl
+dnl check for yylineno -- HAVE_YYLINENO
+dnl
+AC_DEFUN(HAVE_YYLINENO,[dnl
+AC_REQUIRE_CPP()AC_REQUIRE([AC_PROG_LEX])dnl
+AC_MSG_CHECKING([for yylineno declaration])
+AC_CACHE_VAL(krb5_cv_type_yylineno,
+# some systems have yylineno, others don't...
+  echo '%%
+%%' | ${LEX} -t > conftest.out
+  if egrep yylineno conftest.out >/dev/null 2>&1; then
+	krb5_cv_type_yylineno=yes
+  else
+	krb5_cv_type_yylineno=no
+  fi
+  rm -f conftest.out)
+  AC_MSG_RESULT($krb5_cv_type_yylineno)
+  if test $krb5_cv_type_yylineno = no; then
+	AC_DEFINE(NO_YYLINENO, 1, [Define if lex produes code with yylineno])
+  fi
+])dnl
+dnl
+dnl K5_GEN_MAKEFILE([dir, [frags]])
+dnl
+AC_DEFUN(K5_GEN_MAKEFILE,[dnl
+ifelse($1, ,[_K5_GEN_MAKEFILE(.,$2)],[_K5_GEN_MAKEFILE($1,$2)])
+])
+dnl
+dnl _K5_GEN_MAKEFILE(dir, [frags])
+dnl  dir must be present in this case
+dnl  Note: Be careful in quoting. 
+dnl        The ac_foreach generates the list of fragments to include
+dnl        or "" if $2 is empty
+AC_DEFUN(_K5_GEN_MAKEFILE,[dnl
+AC_CONFIG_FILES([$1/Makefile:$krb5_pre_in:$1/Makefile.in:$krb5_post_in])
+])
+dnl
+dnl K5_GEN_FILE( <ac_output arguments> )
+dnl
+AC_DEFUN(K5_GEN_FILE,[AC_CONFIG_FILES($1)])dnl
+dnl
+dnl K5_AC_OUTPUT
+dnl    Note: Adds the variables to config.status for individual 
+dnl          Makefile generation from config.statsu
+AC_DEFUN(K5_AC_OUTPUT,[dnl
+AC_CONFIG_COMMANDS([krb5_config_prefix], [], dnl
+ [krb5_pre_in=$krb5_pre_in
+ ac_config_fragdir=$ac_config_fragdir
+ krb5_post_in=$krb5_post_in])
+AC_OUTPUT])dnl
+dnl
+dnl V5_AC_OUTPUT_MAKEFILE
+dnl
+AC_DEFUN(V5_AC_OUTPUT_MAKEFILE,
+[ifelse($1, , [_V5_AC_OUTPUT_MAKEFILE(.,$2)],[_V5_AC_OUTPUT_MAKEFILE($1,$2)])])
+dnl
+define(_V5_AC_OUTPUT_MAKEFILE,
+[ifelse($2, , ,AC_CONFIG_FILES($2))
+AC_FOREACH([DIR], [$1],dnl
+ [AC_CONFIG_FILES(DIR[/Makefile:$krb5_pre_in:]DIR[/Makefile.in:$krb5_post_in])])
+K5_AC_OUTPUT])dnl
+dnl
+dnl
+dnl KRB5_SOCKADDR_SA_LEN: define HAVE_SA_LEN if sockaddr contains the sa_len
+dnl component
+dnl
+AC_DEFUN([KRB5_SOCKADDR_SA_LEN],[ dnl
+AC_MSG_CHECKING(whether struct sockaddr contains sa_len)
+AC_CACHE_VAL(krb5_cv_sockaddr_sa_len,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+],
+[struct sockaddr sa;
+sa.sa_len;],
+krb5_cv_sockaddr_sa_len=yes,krb5_cv_sockaddr_sa_len=no)])
+AC_MSG_RESULT([$]krb5_cv_sockaddr_sa_len)
+if test $krb5_cv_sockaddr_sa_len = yes; then
+   AC_DEFINE_UNQUOTED(HAVE_SA_LEN,1,[Define if struct sockaddr contains sa_len])
+   fi
+])
+dnl
+dnl
+dnl CHECK_UTMP: check utmp structure and functions
+dnl
+AC_DEFUN(CHECK_UTMP,[
+AC_MSG_CHECKING([ut_pid in struct utmp])
+AC_CACHE_VAL(krb5_cv_struct_ut_pid,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_pid;],
+krb5_cv_struct_ut_pid=yes, krb5_cv_struct_ut_pid=no)])
+AC_MSG_RESULT($krb5_cv_struct_ut_pid)
+if test $krb5_cv_struct_ut_pid = no; then
+  AC_DEFINE(NO_UT_PID)
+fi
+AC_MSG_CHECKING([ut_type in struct utmp])
+AC_CACHE_VAL(krb5_cv_struct_ut_type,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_type;],
+krb5_cv_struct_ut_type=yes, krb5_cv_struct_ut_type=no)])
+AC_MSG_RESULT($krb5_cv_struct_ut_type)
+if test $krb5_cv_struct_ut_type = no; then
+  AC_DEFINE(NO_UT_TYPE)
+fi
+AC_MSG_CHECKING([ut_host in struct utmp])
+AC_CACHE_VAL(krb5_cv_struct_ut_host,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_host;],
+krb5_cv_struct_ut_host=yes, krb5_cv_struct_ut_host=no)])
+AC_MSG_RESULT($krb5_cv_struct_ut_host)
+if test $krb5_cv_struct_ut_host = no; then
+  AC_DEFINE(NO_UT_HOST)
+fi
+AC_MSG_CHECKING([ut_exit in struct utmp])
+AC_CACHE_VAL(krb5_cv_struct_ut_exit,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <utmp.h>],
+[struct utmp ut; ut.ut_exit;],
+krb5_cv_struct_ut_exit=yes, krb5_cv_struct_ut_exit=no)])
+AC_MSG_RESULT($krb5_cv_struct_ut_exit)
+if test $krb5_cv_struct_ut_exit = no; then
+  AC_DEFINE(NO_UT_EXIT)
+fi
+AC_CHECK_FUNC(setutent,AC_DEFINE(HAVE_SETUTENT))
+AC_CHECK_FUNC(setutxent,AC_DEFINE(HAVE_SETUTXENT))
+AC_CHECK_FUNC(updwtmp,AC_DEFINE(HAVE_UPDWTMP))
+AC_CHECK_FUNC(updwtmpx,AC_DEFINE(HAVE_UPDWTMPX))
+])dnl
+dnl
+dnl WITH_NETLIB
+dnl 
+dnl
+AC_DEFUN(WITH_NETLIB,[
+AC_ARG_WITH([netlib],
+AC_HELP_STRING([--with-netlib=LIBS], use user defined resolver library),
+[  if test "$withval" = yes -o "$withval" = no ; then
+	AC_MSG_RESULT("netlib will link with C library resolver only")
+  else
+	LIBS="$LIBS $withval"
+	AC_MSG_RESULT("netlib will use \'$withval\'")
+  fi
+],dnl
+[AC_LIBRARY_NET]
+)])dnl
+dnl
+dnl
+AC_DEFUN(KRB5_AC_NEED_DAEMON, [
+KRB5_NEED_PROTO([#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif],daemon,1)])dnl
+dnl
+dnl Check if stdarg or varargs is available *and compiles*; prefer stdarg.
+dnl (This was sent to djm for incorporation into autoconf 3/12/1996.  KR)
+dnl
+AC_DEFUN(AC_HEADER_STDARG, [
+
+AC_MSG_CHECKING([for stdarg.h])
+AC_CACHE_VAL(ac_cv_header_stdarg_h,
+[AC_TRY_COMPILE([#include <stdarg.h>], [
+  } /* ac_try_compile will have started a function body */
+  int aoeu (char *format, ...) {
+    va_list v;
+    int i;
+    va_start (v, format);
+    i = va_arg (v, int);
+    va_end (v);
+],ac_cv_header_stdarg_h=yes,ac_cv_header_stdarg_h=no)])dnl
+AC_MSG_RESULT($ac_cv_header_stdarg_h)
+if test $ac_cv_header_stdarg_h = yes; then
+  AC_DEFINE(HAVE_STDARG_H, 1, [Define if stdarg available and compiles])
+else
+
+AC_MSG_CHECKING([for varargs.h])
+AC_CACHE_VAL(ac_cv_header_varargs_h,
+[AC_TRY_COMPILE([#include <varargs.h>],[
+  } /* ac_try_compile will have started a function body */
+  int aoeu (va_alist) va_dcl {
+    va_list v;
+    int i;
+    va_start (v);
+    i = va_arg (v, int);
+    va_end (v);
+],ac_cv_header_varargs_h=yes,ac_cv_header_varargs_h=no)])dnl
+AC_MSG_RESULT($ac_cv_header_varargs_h)
+if test $ac_cv_header_varargs_h = yes; then
+  AC_DEFINE(HAVE_VARARGS_H, 1, [Define if varargs available and compiles])
+else
+  AC_MSG_ERROR(Neither stdarg nor varargs compile?)
+fi
+
+fi dnl stdarg test failure
+
+])dnl
+
+dnl
+dnl KRB5_AC_NEED_LIBGEN --- check if libgen needs to be linked in for
+dnl 				compile/step	
+dnl
+dnl
+AC_DEFUN(KRB5_AC_NEED_LIBGEN,[
+AC_REQUIRE([AC_PROG_CC])dnl
+dnl
+dnl regcomp is present but non-functional on Solaris 2.4
+dnl
+AC_MSG_CHECKING(for working regcomp)
+AC_CACHE_VAL(ac_cv_func_regcomp,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <regex.h>
+regex_t x; regmatch_t m;
+int main() { return regcomp(&x,"pat.*",0) || regexec(&x,"pattern",1,&m,0); }
+], ac_cv_func_regcomp=yes, ac_cv_func_regcomp=no, AC_MSG_ERROR([Cannot test regcomp when cross compiling]))])
+AC_MSG_RESULT($ac_cv_func_regcomp)
+test $ac_cv_func_regcomp = yes && AC_DEFINE(HAVE_REGCOMP,1,[Define if regcomp exists and functions])
+dnl
+dnl Check for the compile and step functions - only if regcomp is not available
+dnl
+if test $ac_cv_func_regcomp = no; then
+ save_LIBS="$LIBS"
+ LIBS=-lgen
+dnl this will fail if there's no compile/step in -lgen, or if there's
+dnl no -lgen.  This is fine.
+ AC_CHECK_FUNCS(compile step)
+ LIBS="$save_LIBS"
+dnl
+dnl Set GEN_LIB if necessary 
+dnl
+ AC_CHECK_LIB(gen, compile, GEN_LIB=-lgen, GEN_LIB=)
+ AC_SUBST(GEN_LIB)
+fi
+])
+dnl
+dnl KRB5_AC_REGEX_FUNCS --- check for different regular expression 
+dnl				support functions
+dnl
+AC_DEFUN(KRB5_AC_REGEX_FUNCS,[
+AC_CHECK_FUNCS(re_comp re_exec regexec)
+AC_REQUIRE([KRB5_AC_NEED_LIBGEN])dnl
+])dnl
+dnl
+dnl AC_KRB5_TCL_FIND_CONFIG (uses tcl_dir)
+dnl
+AC_DEFUN(AC_KRB5_TCL_FIND_CONFIG,[
+AC_REQUIRE([KRB5_LIB_AUX])dnl
+AC_MSG_CHECKING(for tclConfig.sh)
+if test -r "$tcl_dir/lib/tclConfig.sh" ; then
+  tcl_conf="$tcl_dir/lib/tclConfig.sh"
+elif test -r "$tcl_dir/tclConfig.sh" ; then
+  tcl_conf="$tcl_dir/tclConfig.sh"
+else
+  tcl_conf=
+  lib="$tcl_dir/lib"
+  changequote(<<,>>)dnl
+  for d in "$lib" "$lib"/tcl7.[0-9] "$lib"/tcl8.[0-9] ; do
+    if test -r "$d/tclConfig.sh" ; then
+      tcl_conf="$tcl_conf $d/tclConfig.sh"
+    fi
+  done
+  changequote([,])dnl
+fi
+if test -n "$tcl_conf" ; then
+  AC_MSG_RESULT($tcl_conf)
+else
+  AC_MSG_RESULT(not found)
+fi
+tcl_ok_conf=
+tcl_vers_maj=
+tcl_vers_min=
+old_CPPFLAGS=$CPPFLAGS
+old_LIBS=$LIBS
+old_LDFLAGS=$LDFLAGS
+if test -n "$tcl_conf" ; then
+  for file in $tcl_conf ; do
+    TCL_MAJOR_VERSION=x ; TCL_MINOR_VERSION=x
+    AC_MSG_CHECKING(Tcl info in $file)
+    . $file
+    v=$TCL_MAJOR_VERSION.$TCL_MINOR_VERSION
+    if test -z "$tcl_vers_maj" \
+	|| test "$tcl_vers_maj" -lt "$TCL_MAJOR_VERSION" \
+	|| test "$tcl_vers_maj" = "$TCL_MAJOR_VERSION" -a "$tcl_vers_min" -lt "$TCL_MINOR_VERSION" ; then
+      for incdir in "$TCL_PREFIX/include/tcl$v" "$TCL_PREFIX/include" ; do
+	if test -r "$incdir/tcl.h" -o -r "$incdir/tcl/tcl.h" ; then
+	  CPPFLAGS="$old_CPPFLAGS -I$incdir"
+	  break
+	fi
+      done
+      LIBS="$old_LIBS `eval echo x $TCL_LIB_SPEC $TCL_LIBS | sed 's/^x//'`"
+      LDFLAGS="$old_LDFLAGS $TCL_LD_FLAGS"
+      AC_TRY_LINK( , [Tcl_CreateInterp ();],
+	tcl_ok_conf=$file
+	tcl_vers_maj=$TCL_MAJOR_VERSION
+	tcl_vers_min=$TCL_MINOR_VERSION
+	AC_MSG_RESULT($v - working),
+	AC_MSG_RESULT($v - compilation failed)
+      )
+    else
+      AC_MSG_RESULT(older version $v)
+    fi
+  done
+fi
+CPPFLAGS=$old_CPPFLAGS
+LIBS=$old_LIBS
+LDFLAGS=$old_LDFLAGS
+tcl_header=no
+tcl_lib=no
+if test -n "$tcl_ok_conf" ; then
+  . $tcl_ok_conf
+  TCL_INCLUDES=
+  for incdir in "$TCL_PREFIX/include/tcl$v" "$TCL_PREFIX/include" ; do
+    if test -r "$incdir/tcl.h" -o -r "$incdir/tcl/tcl.h" ; then
+      if test "$incdir" != "/usr/include" ; then
+        TCL_INCLUDES=-I$incdir
+      fi
+      break
+    fi
+  done
+  # Need eval because the first-level expansion could reference
+  # variables like ${TCL_DBGX}.
+  eval TCL_LIBS='"'$TCL_LIB_SPEC $TCL_LIBS $TCL_DL_LIBS'"'
+  TCL_LIBPATH="-L$TCL_EXEC_PREFIX/lib"
+  TCL_RPATH=":$TCL_EXEC_PREFIX/lib"
+  if test "$DEPLIBEXT" != "$SHLIBEXT" && test -n "$RPATH_FLAG"; then
+    TCL_MAYBE_RPATH='$(RPATH_FLAG)'"$TCL_EXEC_PREFIX/lib$RPATH_TAIL"
+  else
+    TCL_MAYBE_RPATH=
+  fi
+  CPPFLAGS="$old_CPPFLAGS $TCL_INCLUDES"
+  AC_CHECK_HEADER(tcl.h,AC_DEFINE(HAVE_TCL_H,1,[Define if tcl.h is available]) tcl_header=yes)
+  if test $tcl_header=no; then
+     AC_CHECK_HEADER(tcl/tcl.h,AC_DEFINE(HAVE_TCL_TCL_H,1,[Define if tcl/tcl.h is available]) tcl_header=yes)
+  fi
+  CPPFLAGS="$old_CPPFLAGS"
+  tcl_lib=yes
+else
+  # If we read a tclConfig.sh file, it probably set this.
+  TCL_LIBS=
+fi  
+AC_SUBST(TCL_INCLUDES)
+AC_SUBST(TCL_LIBS)
+AC_SUBST(TCL_LIBPATH)
+AC_SUBST(TCL_RPATH)
+AC_SUBST(TCL_MAYBE_RPATH)
+])dnl
+dnl
+dnl AC_KRB5_TCL_TRYOLD
+dnl attempt to use old search algorithm for locating tcl
+dnl
+AC_DEFUN(AC_KRB5_TCL_TRYOLD, [
+AC_REQUIRE([KRB5_AC_FIND_DLOPEN])
+AC_MSG_WARN([trying old tcl search code])
+if test "$with_tcl" != yes -a "$with_tcl" != no; then
+	TCL_INCLUDES=-I$with_tcl/include
+	TCL_LIBPATH=-L$with_tcl/lib
+	TCL_RPATH=:$with_tcl/lib
+fi
+if test "$with_tcl" != no ; then
+	krb5_save_CPPFLAGS="$CPPFLAGS"
+	krb5_save_LDFLAGS="$LDFLAGS"
+	CPPFLAGS="$CPPFLAGS $TCL_INCLUDES"
+	LDFLAGS="$LDFLAGS $TCL_LIBPATH"
+	tcl_header=no
+	AC_CHECK_HEADER(tcl.h,AC_DEFINE(HAVE_TCL_H) tcl_header=yes)
+	if test $tcl_header=no; then
+	   AC_CHECK_HEADER(tcl/tcl.h,AC_DEFINE(HAVE_TCL_TCL_H) tcl_header=yes)
+	fi
+
+	if test $tcl_header = yes ; then
+		tcl_lib=no
+
+		if test $tcl_lib = no; then
+			AC_CHECK_LIB(tcl8.0, Tcl_CreateCommand, 
+				TCL_LIBS="$TCL_LIBS -ltcl8.0 -lm $DL_LIB $LIBS"
+				tcl_lib=yes,,-lm $DL_LIB)
+		fi
+		if test $tcl_lib = no; then
+			AC_CHECK_LIB(tcl7.6, Tcl_CreateCommand, 
+				TCL_LIBS="$TCL_LIBS -ltcl7.6 -lm $DL_LIB $LIBS"
+				tcl_lib=yes,,-lm $DL_LIB)
+		fi
+		if test $tcl_lib = no; then
+			AC_CHECK_LIB(tcl7.5, Tcl_CreateCommand, 
+				TCL_LIBS="$TCL_LIBS -ltcl7.5 -lm $DL_LIB $LIBS"
+				tcl_lib=yes,,-lm $DL_LIB)
+
+		fi
+		if test $tcl_lib = no ; then
+			AC_CHECK_LIB(tcl, Tcl_CreateCommand, 
+				TCL_LIBS="$TCL_LIBS -ltcl -lm $DL_LIB $LIBS"
+				tcl_lib=yes,,-lm $DL_LIB)
+
+		fi
+		if test $tcl_lib = no ; then		
+			AC_MSG_WARN("tcl.h found but not library")
+		fi
+	else
+		AC_MSG_WARN(Could not find Tcl which is needed for the kadm5 tests)
+		TCL_LIBS=
+	fi
+	CPPFLAGS="$krb5_save_CPPFLAGS"
+	LDFLAGS="$krb5_save_LDFLAGS"
+	AC_SUBST(TCL_INCLUDES)
+	AC_SUBST(TCL_LIBS)
+	AC_SUBST(TCL_LIBPATH)
+	AC_SUBST(TCL_RPATH)
+else
+	AC_MSG_RESULT("Not looking for Tcl library")
+fi
+])dnl
+dnl
+dnl AC_KRB5_TCL - determine if the TCL library is present on system
+dnl
+AC_DEFUN(AC_KRB5_TCL,[
+TCL_INCLUDES=
+TCL_LIBPATH=
+TCL_RPATH=
+TCL_LIBS=
+TCL_WITH=
+tcl_dir=
+AC_ARG_WITH(tcl,
+[  --with-tcl=path         where Tcl resides], , with_tcl=try)
+if test "$with_tcl" = no ; then
+  true
+elif test "$with_tcl" = yes -o "$with_tcl" = try ; then
+  tcl_dir=/usr
+  if test ! -r /usr/lib/tclConfig.sh; then
+    cat >> conftest <<\EOF
+puts "tcl_dir=$tcl_library"
+EOF
+    if tclsh conftest >conftest.out 2>/dev/null; then
+      if grep tcl_dir= conftest.out >/dev/null 2>&1; then
+        t=`sed s/tcl_dir=// conftest.out`
+        tcl_dir=$t
+      fi
+    fi # tclsh ran script okay
+  rm -f conftest conftest.out
+  fi # no /usr/lib/tclConfig.sh
+else
+  tcl_dir=$with_tcl
+fi
+if test "$with_tcl" != no ; then
+  AC_KRB5_TCL_FIND_CONFIG
+  if test $tcl_lib = no ; then
+    if test "$with_tcl" != try ; then
+      AC_KRB5_TCL_TRYOLD
+    else
+      AC_MSG_WARN(Could not find Tcl which is needed for some tests)
+    fi
+  fi
+fi
+# If "yes" or pathname, error out if not found.
+if test "$with_tcl" != no -a "$with_tcl" != try ; then
+  if test "$tcl_header $tcl_lib" != "yes yes" ; then
+    AC_MSG_ERROR(Could not find Tcl)
+  fi
+fi
+])dnl
+
+dnl
+dnl WITH_HESIOD
+dnl
+AC_DEFUN(WITH_HESIOD,
+[AC_ARG_WITH(hesiod, AC_HELP_STRING(--with-hesiod[=path], compile with hesiod support @<:@omitted@:>@),
+	hesiod=$with_hesiod, with_hesiod=no)
+if test "$with_hesiod" != "no"; then
+	HESIOD_DEFS=-DHESIOD
+	AC_CHECK_LIB(resolv, res_send, res_lib=-lresolv)
+	if test "$hesiod" != "yes"; then
+		HESIOD_LIBS="-L${hesiod}/lib -lhesiod $res_lib"
+	else
+		HESIOD_LIBS="-lhesiod $res_lib"
+	fi
+else
+	HESIOD_DEFS=
+	HESIOD_LIBS=
+fi
+AC_SUBST(HESIOD_DEFS)
+AC_SUBST(HESIOD_LIBS)])
+
+
+dnl
+dnl KRB5_BUILD_LIBRARY
+dnl
+dnl Pull in the necessary stuff to create the libraries.
+
+AC_DEFUN(KRB5_BUILD_LIBRARY,
+[KRB5_BUILD_LIBRARY_WITH_DEPS
+# null out SHLIB_EXPFLAGS because we lack any dependencies
+SHLIB_EXPFLAGS=])
+
+dnl
+dnl KRB5_BUILD_LIBRARY_STATIC
+dnl
+dnl Force static library build.
+
+AC_DEFUN(KRB5_AC_FORCE_STATIC,[dnl
+AC_BEFORE([$0],[KRB5_LIB_AUX])dnl
+krb5_force_static=yes])
+AC_DEFUN(KRB5_BUILD_LIBRARY_STATIC,
+dnl Use define rather than AC_DEFUN to avoid ordering problems.
+[AC_REQUIRE([KRB5_AC_FORCE_STATIC])dnl
+KRB5_BUILD_LIBRARY
+# If we're only building static libraries, they're for build-time use only,
+# so don't install.
+LIBINSTLIST=])
+
+dnl
+dnl KRB5_BUILD_LIBRARY_WITH_DEPS
+dnl
+dnl Like KRB5_BUILD_LIBRARY, but adds in explicit dependencies in the
+dnl generated shared library.
+
+AC_DEFUN(KRB5_BUILD_LIBRARY_WITH_DEPS,
+[AC_REQUIRE([KRB5_LIB_AUX])dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+AC_REQUIRE([AC_PROG_RANLIB])dnl
+AC_REQUIRE([AC_PROG_ARCHIVE])dnl
+AC_REQUIRE([AC_PROG_ARCHIVE_ADD])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+AC_CHECK_PROG(AR, ar, ar, false)
+AC_CHECK_PROG(PERL, perl, perl, false)
+if test "$ac_cv_prog_PERL" = "false"; then
+  AC_MSG_ERROR(Perl is now required for Kerberos builds.)
+fi
+AC_SUBST(LIBLIST)
+AC_SUBST(LIBLINKS)
+AC_SUBST(MAKE_SHLIB_COMMAND)
+AC_SUBST(SHLIB_EXPFLAGS)
+AC_SUBST(SHLIB_EXPORT_FILE_DEP)
+AC_SUBST(DYNOBJ_EXPDEPS)
+AC_SUBST(DYNOBJ_EXPFLAGS)
+AC_SUBST(INSTALL_SHLIB)
+AC_SUBST(STLIBEXT)
+AC_SUBST(SHLIBEXT)
+AC_SUBST(SHLIBVEXT)
+AC_SUBST(SHLIBSEXT)
+AC_SUBST(DEPLIBEXT)
+AC_SUBST(PFLIBEXT)
+AC_SUBST(LIBINSTLIST)
+AC_SUBST(DYNOBJEXT)
+AC_SUBST(MAKE_DYNOBJ_COMMAND)
+])
+
+dnl
+dnl KRB5_BUILD_LIBOBJS
+dnl
+dnl Pull in the necessary stuff to build library objects.
+
+AC_DEFUN(KRB5_BUILD_LIBOBJS,
+[AC_REQUIRE([KRB5_LIB_AUX])dnl
+AC_SUBST(OBJLISTS)
+AC_SUBST(STOBJEXT)
+AC_SUBST(SHOBJEXT)
+AC_SUBST(PFOBJEXT)
+AC_SUBST(PICFLAGS)
+AC_SUBST(PROFFLAGS)])
+
+dnl
+dnl KRB5_BUILD_PROGRAM
+dnl
+dnl Set variables to build a program.
+
+AC_DEFUN(KRB5_BUILD_PROGRAM,
+[AC_REQUIRE([KRB5_LIB_AUX])dnl
+AC_REQUIRE([KRB5_AC_NEED_LIBGEN])dnl
+AC_SUBST(CC_LINK)
+AC_SUBST(RPATH_FLAG)
+AC_SUBST(DEPLIBEXT)])
+
+dnl
+dnl KRB5_RUN_FLAGS
+dnl
+dnl Set up environment for running dynamic executables out of build tree
+
+AC_DEFUN(KRB5_RUN_FLAGS,
+[AC_REQUIRE([KRB5_LIB_AUX])dnl
+KRB5_RUN_ENV="$RUN_ENV"
+AC_SUBST(KRB5_RUN_ENV)])
+
+dnl
+dnl KRB5_LIB_AUX
+dnl
+dnl Parse configure options related to library building.
+
+AC_DEFUN(KRB5_LIB_AUX,
+[AC_REQUIRE([KRB5_LIB_PARAMS])dnl
+
+# Check whether to build static libraries.
+AC_ARG_ENABLE([static],
+AC_HELP_STRING([--enable-static],[build static libraries @<:@disabled for most platforms@:>@])
+AC_HELP_STRING([--disable-static],[don't build static libraries]), ,
+[enable_static=$default_static])
+
+if test "$enable_static" = no && test "$krb5_force_static" != yes; then
+	AC_MSG_NOTICE([disabling static libraries])
+	LIBLINKS=
+	LIBLIST=
+	OBJLISTS=
+else
+	LIBLIST='lib$(LIBBASE)$(STLIBEXT)'
+	LIBLINKS='$(TOPLIBD)/lib$(LIBBASE)$(STLIBEXT)'
+	OBJLISTS=OBJS.ST
+	LIBINSTLIST=install-static
+	DEPLIBEXT=$STLIBEXT
+#	CFLAGS="$CFLAGS -D_KDB5_STATIC_LINK"
+fi
+
+# Check whether to build shared libraries.
+AC_ARG_ENABLE([shared],
+AC_HELP_STRING([--enable-shared],[build shared libraries @<:@enabled for most platforms@:>@])
+AC_HELP_STRING([--disable-shared],[don't build shared libraries]), ,
+[enable_shared=$default_shared])
+
+if test "$enable_shared" = yes; then
+	case "$SHLIBEXT" in
+	.so-nobuild)
+		AC_MSG_WARN([shared libraries not supported on this architecture])
+		RUN_ENV=
+		CC_LINK="$CC_LINK_STATIC"
+		;;
+	*)
+		# set this now because some logic below may reset SHLIBEXT
+		DEPLIBEXT=$SHLIBEXT
+		if test "$krb5_force_static" = "yes"; then
+			AC_MSG_RESULT([Forcing static libraries.])
+			# avoid duplicate rules generation for AIX and such
+			SHLIBEXT=.so-nobuild
+			SHLIBVEXT=.so.v-nobuild
+			SHLIBSEXT=.so.s-nobuild
+		else
+			AC_MSG_NOTICE([enabling shared libraries])
+			# Clear some stuff in case of AIX, etc.
+			if test "$STLIBEXT" = "$SHLIBEXT" ; then
+				STLIBEXT=.a-nobuild
+				LIBLIST=
+				LIBLINKS=
+				OBJLISTS=
+				LIBINSTLIST=
+			fi
+			LIBLIST="$LIBLIST "'lib$(LIBBASE)$(SHLIBEXT)'
+			LIBLINKS="$LIBLINKS "'$(TOPLIBD)/lib$(LIBBASE)$(SHLIBEXT) $(TOPLIBD)/lib$(LIBBASE)$(SHLIBVEXT)'
+			case "$SHLIBSEXT" in
+			.so.s-nobuild)
+				LIBINSTLIST="$LIBINSTLIST install-shared"
+				;;
+			*)
+				LIBLIST="$LIBLIST "'lib$(LIBBASE)$(SHLIBSEXT)'
+				LIBLINKS="$LIBLINKS "'$(TOPLIBD)/lib$(LIBBASE)$(SHLIBSEXT)'
+				LIBINSTLIST="$LIBINSTLIST install-shlib-soname"
+				;;
+			esac
+			OBJLISTS="$OBJLISTS OBJS.SH"
+		fi
+		CC_LINK="$CC_LINK_SHARED"
+		;;
+	esac
+else
+	RUN_ENV=
+	CC_LINK="$CC_LINK_STATIC"
+	SHLIBEXT=.so-nobuild
+	SHLIBVEXT=.so.v-nobuild
+	SHLIBSEXT=.so.s-nobuild
+fi
+
+if test "$build_dynobj" = yes; then
+	OBJLISTS=`echo $OBJLISTS | sed -e s/OBJS.ST//g -e s/OBJS.SH//g`
+	OBJLISTS="$OBJLISTS OBJS.SH"
+fi
+
+if test -z "$LIBLIST"; then
+	AC_MSG_ERROR([must enable one of shared or static libraries])
+fi
+
+# Check whether to build profiled libraries.
+AC_ARG_ENABLE([profiled],
+[  --enable-profiled       build profiled libraries @<:@disabled@:>@],
+[if test "$enableval" = yes; then
+	case $PFLIBEXT in
+	.po-nobuild)
+		AC_MSG_WARN([Profiled libraries not supported on this architecture.])
+		;;
+	*)
+		AC_MSG_NOTICE([enabling profiled libraries])
+		LIBLIST="$LIBLIST "'lib$(LIBBASE)$(PFLIBEXT)'
+		LIBLINKS="$LIBLINKS "'$(TOPLIBD)/lib$(LIBBASE)$(PFLIBEXT)'
+		OBJLISTS="$OBJLISTS OBJS.PF"
+		LIBINSTLIST="$LIBINSTLIST install-profiled"
+		;;
+	esac
+fi])])
+
+dnl
+dnl KRB5_LIB_PARAMS
+dnl
+dnl Determine parameters related to libraries, e.g. various extensions.
+
+AC_DEFUN(KRB5_LIB_PARAMS,
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+krb5_cv_host=$host
+AC_SUBST(krb5_cv_host)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([V5_SET_TOPDIR])dnl
+. $ac_topdir/config/shlib.conf])
+dnl
+dnl The following was written by jhawk@mit.edu
+dnl
+dnl AC_LIBRARY_NET: Id: net.m4,v 1.4 1997/10/25 20:49:53 jhawk Exp 
+dnl
+dnl This test is for network applications that need socket() and
+dnl gethostbyname() -ish functions.  Under Solaris, those applications need to
+dnl link with "-lsocket -lnsl".  Under IRIX, they should *not* link with
+dnl "-lsocket" because libsocket.a breaks a number of things (for instance:
+dnl gethostbyname() under IRIX 5.2, and snoop sockets under most versions of
+dnl IRIX).
+dnl 
+dnl Unfortunately, many application developers are not aware of this, and
+dnl mistakenly write tests that cause -lsocket to be used under IRIX.  It is
+dnl also easy to write tests that cause -lnsl to be used under operating
+dnl systems where neither are necessary (or useful), such as SunOS 4.1.4, which
+dnl uses -lnsl for TLI.
+dnl 
+dnl This test exists so that every application developer does not test this in
+dnl a different, and subtly broken fashion.
+dnl 
+dnl It has been argued that this test should be broken up into two seperate
+dnl tests, one for the resolver libraries, and one for the libraries necessary
+dnl for using Sockets API. Unfortunately, the two are carefully intertwined and
+dnl allowing the autoconf user to use them independantly potentially results in
+dnl unfortunate ordering dependancies -- as such, such component macros would
+dnl have to carefully use indirection and be aware if the other components were
+dnl executed. Since other autoconf macros do not go to this trouble, and almost
+dnl no applications use sockets without the resolver, this complexity has not
+dnl been implemented.
+dnl
+dnl The check for libresolv is in case you are attempting to link statically
+dnl and happen to have a libresolv.a lying around (and no libnsl.a).
+dnl
+AC_DEFUN(AC_LIBRARY_NET, [
+   # Most operating systems have gethostbyname() in the default searched
+   # libraries (i.e. libc):
+   AC_CHECK_FUNC(gethostbyname, , [
+     # Some OSes (eg. Solaris) place it in libnsl:
+     AC_CHECK_LIB(nsl, gethostbyname, , [
+       # Some strange OSes (SINIX) have it in libsocket:
+       AC_CHECK_LIB(socket, gethostbyname, , [
+          # Unfortunately libsocket sometimes depends on libnsl.
+          # AC_CHECK_LIB's API is essentially broken so the following
+          # ugliness is necessary:
+          AC_CHECK_LIB(socket, gethostbyname,
+             LIBS="-lsocket -lnsl $LIBS",
+               [AC_CHECK_LIB(resolv, gethostbyname,
+			     LIBS="-lresolv $LIBS" )],
+             -lnsl)
+       ])
+     ])
+   ])
+  AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
+    AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)))
+  KRB5_AC_ENABLE_DNS
+  if test "$enable_dns" = yes ; then
+    # We assume that if libresolv exists we can link against it.
+    # This may get us a gethostby* that doesn't respect nsswitch.
+    AC_CHECK_LIB(resolv, main)
+
+_KRB5_AC_CHECK_RES_FUNCS(res_ninit res_nclose res_ndestroy res_nsearch dnl
+ns_initparse ns_name_uncompress dn_skipname res_search)
+    if test $krb5_cv_func_res_nsearch = no \
+      && test $krb5_cv_func_res_search = no; then
+	# Attempt to link with res_search(), in case it's not prototyped.
+	AC_CHECK_FUNC(res_search,
+	  [AC_DEFINE(HAVE_RES_SEARCH, 1,
+	    [Define to 1 if you have the `res_search' function])],
+	  [AC_ERROR([cannot find res_nsearch or res_search])])
+    fi
+  fi
+])
+AC_DEFUN([_KRB5_AC_CHECK_RES_FUNCS],
+[AC_FOREACH([AC_Func], [$1],
+  [AH_TEMPLATE(AS_TR_CPP(HAVE_[]AC_Func),
+               [Define to 1 if you have the `]AC_Func[' function.])])dnl
+for krb5_func in $1; do
+_KRB5_AC_CHECK_RES_FUNC($krb5_func)
+done
+])
+AC_DEFUN([_KRB5_AC_CHECK_RES_FUNC], [
+# Solaris 9 prototypes ns_name_uncompress() in arpa/nameser.h, but
+# doesn't export it from libresolv.so, so we use extreme paranoia here
+# and check both for the declaration and that we can link against the
+# function.
+AC_CACHE_CHECK([for $1], [krb5_cv_func_$1], [AC_TRY_LINK(
+[#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+@%:@include <resolv.h>],
+[/*
+ * Use volatile, or else optimization can cause false positives.
+ */
+void (* volatile p)() = (void (*)())$1;],
+			     [AS_VAR_SET(krb5_cv_func_$1, yes)],
+			     [AS_VAR_SET(krb5_cv_func_$1, no)])])
+AS_IF([test AS_VAR_GET(krb5_cv_func_$1) = yes],
+      [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1]), 1,
+			  [Define to 1 if you have the `$1' function])])[]dnl
+])
+dnl
+dnl
+dnl KRB5_AC_ENABLE_DNS
+dnl
+AC_DEFUN(KRB5_AC_ENABLE_DNS, [
+enable_dns=yes
+enable_dns_for_kdc=yes
+AC_DEFINE(KRB5_DNS_LOOKUP_KDC,1,[Define to enable DNS lookups of Kerberos KDCs])
+
+  AC_ARG_ENABLE([dns-for-realm],
+[  --enable-dns-for-realm  enable DNS lookups of Kerberos realm names], ,
+[enable_dns_for_realm=no])
+  if test "$enable_dns_for_realm" = yes; then
+    AC_DEFINE(KRB5_DNS_LOOKUP_REALM,1,[Define to enable DNS lookups of Kerberos realm names])
+  fi
+
+AC_DEFINE(KRB5_DNS_LOOKUP, 1,[Define for DNS support of locating realms and KDCs])
+
+])
+dnl
+dnl
+dnl Check if we need the prototype for a function - we give it a bogus 
+dnl prototype and if it complains - then a valid prototype exists on the 
+dnl system.
+dnl
+dnl KRB5_NEED_PROTO(includes, function, [bypass])
+dnl if $3 set, don't see if library defined. 
+dnl Useful for case where we will define in libkrb5 the function if need be
+dnl but want to know if a prototype exists in either case on system.
+dnl
+AC_DEFUN([KRB5_NEED_PROTO], [
+ifelse([$3], ,[if test "x$ac_cv_func_$2" = xyes; then])
+AC_CACHE_CHECK([if $2 needs a prototype provided], krb5_cv_func_$2_noproto,
+AC_TRY_COMPILE([$1],
+[struct k5foo {int foo; } xx;
+extern int $2 (struct k5foo*);
+$2(&xx);
+],
+krb5_cv_func_$2_noproto=yes,krb5_cv_func_$2_noproto=no))
+if test $krb5_cv_func_$2_noproto = yes; then
+	AC_DEFINE([NEED_]translit($2, [a-z], [A-Z])[_PROTO], 1, dnl
+[define if the system header files are missing prototype for $2()])
+fi
+ifelse([$3], ,[fi])
+])
+dnl
+dnl =============================================================
+dnl Internal function for testing for getpeername prototype
+dnl
+AC_DEFUN([KRB5_GETPEERNAME_ARGS],[
+AC_DEFINE([GETPEERNAME_ARG2_TYPE],GETSOCKNAME_ARG2_TYPE,[Type of getpeername second argument.])
+AC_DEFINE([GETPEERNAME_ARG3_TYPE],GETSOCKNAME_ARG3_TYPE,[Type of getpeername second argument.])
+])
+dnl
+dnl =============================================================
+dnl Internal function for testing for getsockname arguments
+dnl
+AC_DEFUN([TRY_GETSOCK_INT],[
+krb5_lib_var=`echo "$1 $2" | sed 'y% ./+-*%___p_p%'`
+AC_MSG_CHECKING([if getsockname() takes arguments $1 and $2])
+AC_CACHE_VAL(krb5_cv_getsockname_proto_$krb5_lib_var,
+[
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>
+extern int getsockname(int, $1, $2);
+],,eval "krb5_cv_getsockname_proto_$krb5_lib_var=yes",
+    eval "krb5_cv_getsockname_proto_$krb5_lib_var=no")])
+if eval "test \"`echo '$krb5_cv_getsockname_proto_'$krb5_lib_var`\" = yes"; then
+	AC_MSG_RESULT(yes)
+	sock_set=yes; res1="$1"; res2="$2"
+else
+	AC_MSG_RESULT(no)
+fi
+])
+dnl
+dnl Determines the types of the second and third arguments to getsockname().
+dnl
+AC_DEFUN([KRB5_GETSOCKNAME_ARGS],[
+sock_set=no
+for sock_arg1 in "struct sockaddr *" "void *"
+do
+  for sock_arg2 in "size_t *" "int *" "socklen_t *"
+  do
+	if test $sock_set = no; then
+	  TRY_GETSOCK_INT($sock_arg1, $sock_arg2)
+	fi
+  done 
+done
+if test "$sock_set" = no; then
+  AC_MSG_NOTICE(assuming struct sockaddr and socklen_t for getsockname args)
+  res1="struct sockaddr *"
+  res2="socklen_t *"
+fi
+res1=`echo "$res1" | tr -d '*' | sed -e 's/ *$//'`
+res2=`echo "$res2" | tr -d '*' | sed -e 's/ *$//'`
+AC_DEFINE_UNQUOTED([GETSOCKNAME_ARG2_TYPE],$res1,[Type of pointer target for argument 2 to getsockname])
+AC_DEFINE_UNQUOTED([GETSOCKNAME_ARG3_TYPE],$res2,[Type of pointer target for argument 3 to getsockname])
+])
+dnl
+dnl
+AC_DEFUN([KRB5_AC_CHOOSE_ET],[
+AC_ARG_WITH([system-et],
+AC_HELP_STRING(--with-system-et,use system compile_et and -lcom_err @<:@default: build and install a local version@:>@))
+AC_MSG_CHECKING(which version of com_err to use)
+if test "x$with_system_et" = xyes ; then
+  COM_ERR_VERSION=sys
+  AC_MSG_RESULT(system)
+else
+  COM_ERR_VERSION=k5
+  AC_MSG_RESULT(krb5)
+fi
+if test $COM_ERR_VERSION = sys; then
+  # check for various functions we need
+  AC_CHECK_LIB(com_err, add_error_table, :, AC_MSG_ERROR(cannot find add_error_table in com_err library))
+  AC_CHECK_LIB(com_err, remove_error_table, :, AC_MSG_ERROR(cannot find remove_error_table in com_err library))
+  # make sure compile_et provides "et_foo" name
+  cat >> conf$$e.et <<EOF
+error_table foo
+error_code ERR_FOO, "foo"
+end
+EOF
+  AC_CHECK_PROGS(compile_et,compile_et,false)
+  if test "$compile_et" = false; then
+    AC_MSG_ERROR(cannot find compile_et)
+  fi
+  AC_CACHE_CHECK(whether compile_et is useful,krb5_cv_compile_et_useful,[
+  if compile_et conf$$e.et >/dev/null 2>&1 ; then true ; else
+    AC_MSG_ERROR(execution failed)
+  fi
+  AC_TRY_COMPILE([#include "conf$$e.h"
+      		 ],[ et_foo_error_table; ],:,
+		 [AC_MSG_ERROR(cannot use et_foo_error_table)])
+  # Anything else we need to test for?
+  rm -f conf$$e.et conf$$e.c conf$$e.h
+  krb5_cv_compile_et_useful=yes
+  ])
+fi
+AC_SUBST(COM_ERR_VERSION)
+])
+AC_DEFUN([KRB5_AC_CHOOSE_SS],[
+AC_ARG_WITH(system-ss,
+	    AC_HELP_STRING(--with-system-ss,use system -lss and mk_cmds @<:@private version@:>@))
+AC_ARG_VAR(SS_LIB,[system libraries for 'ss' package [-lss]])
+AC_MSG_CHECKING(which version of subsystem package to use)
+if test "x$with_system_ss" = xyes ; then
+  SS_VERSION=sys
+  AC_MSG_RESULT(system)
+  # todo: check for various libraries we might need
+  # in the meantime...
+  test "x${SS_LIB+set}" = xset || SS_LIB=-lss
+  old_LIBS="$LIBS"
+  LIBS="$LIBS $SS_LIB"
+  AC_CACHE_CHECK(whether system ss package works, krb5_cv_system_ss_okay,[
+  AC_TRY_RUN([
+#include <ss/ss.h>
+int main(int argc, char *argv[]) {
+  if (argc == 42) {
+    int i, err;
+    i = ss_create_invocation("foo","foo","",0,&err);
+    ss_listen(i);
+  }
+  return 0;
+}], krb5_cv_system_ss_okay=yes, AC_MSG_ERROR(cannot run test program),
+  krb5_cv_system_ss_okay="assumed")])
+  LIBS="$old_LIBS"
+else
+  SS_VERSION=k5
+  AC_MSG_RESULT(krb5)
+fi
+AC_SUBST(SS_LIB)
+AC_SUBST(SS_VERSION)
+])
+dnl
+AC_DEFUN([KRB5_AC_CHOOSE_DB],[
+AC_ARG_WITH(system-db,
+	    AC_HELP_STRING(--with-system-db,use system Berkeley db @<:@private version@:>@))
+AC_ARG_VAR(DB_HEADER,[header file for system Berkeley db package [db.h]])
+AC_ARG_VAR(DB_LIB,[library for system Berkeley db package [-ldb]])
+if test "x$with_system_db" = xyes ; then
+  DB_VERSION=sys
+  # TODO: Do we have specific routines we should check for?
+  # How about known, easily recognizable bugs?
+  # We want to use bt_rseq in some cases, but no other version but
+  # ours has it right now.
+  #
+  # Okay, check the variables.
+  test "x${DB_HEADER+set}" = xset || DB_HEADER=db.h
+  test "x${DB_LIB+set}" = xset || DB_LIB=-ldb
+  #
+  if test "x${DB_HEADER}" = xdb.h ; then
+    DB_HEADER_VERSION=sys
+  else
+    DB_HEADER_VERSION=redirect
+  fi
+  KDB5_DB_LIB="$DB_LIB"
+else
+  DB_VERSION=k5
+  AC_DEFINE(HAVE_BT_RSEQ,1,[Define if bt_rseq is available, for recursive btree traversal.])
+  DB_HEADER=db.h
+  DB_HEADER_VERSION=k5
+  # libdb gets sucked into libkdb
+  KDB5_DB_LIB=
+  # needed for a couple of things that need libdb for its own sake
+  DB_LIB=-ldb
+fi
+AC_SUBST(DB_VERSION)
+AC_SUBST(DB_HEADER)
+AC_SUBST(DB_HEADER_VERSION)
+AC_SUBST(DB_LIB)
+AC_SUBST(KDB5_DB_LIB)
+])
+dnl
+dnl KRB5_AC_PRIOCNTL_HACK
+dnl
+dnl
+AC_DEFUN([KRB5_AC_PRIOCNTL_HACK],
+[AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_LANG_COMPILER_REQUIRE])dnl
+AC_CACHE_CHECK([whether to use priocntl hack], [krb5_cv_priocntl_hack],
+[case $krb5_cv_host in
+*-*-solaris2.9*)
+	if test "$cross_compiling" = yes; then
+		krb5_cv_priocntl_hack=yes
+	else
+		# Solaris patch 117171-11 (sparc) or 117172-11 (x86)
+		# fixes the Solaris 9 bug where final pty output
+		# gets lost on close.
+		if showrev -p | $AWK 'BEGIN { e = 1 }
+/Patch: 11717[[12]]/ { x = index[]([$]2, "-");
+if (substr[]([$]2, x + 1, length([$]2) - x) >= 11)
+{ e = 0 } else { e = 1 } }
+END { exit e; }'; then
+			krb5_cv_priocntl_hack=no
+		else
+			krb5_cv_priocntl_hack=yes
+		fi
+	fi
+	;;
+*)
+	krb5_cv_priocntl_hack=no
+	;;
+esac])
+if test "$krb5_cv_priocntl_hack" = yes; then
+	PRIOCNTL_HACK=1
+else
+	PRIOCNTL_HACK=0
+fi
+AC_SUBST(PRIOCNTL_HACK)])
+dnl
+dnl
+dnl KRB5_AC_GCC_ATTRS
+AC_DEFUN([KRB5_AC_GCC_ATTRS],
+[AC_CACHE_CHECK([for constructor/destructor attribute support],krb5_cv_attr_constructor_destructor,
+[rm -f conftest.1 conftest.2
+if test -r conftest.1 || test -r conftest.2 ; then
+  AC_MSG_ERROR(write error in local file system?)
+fi
+true > conftest.1
+true > conftest.2
+if test -r conftest.1 && test -r conftest.2 ; then true ; else
+  AC_MSG_ERROR(write error in local file system?)
+fi
+a=no
+b=no
+# blindly assume we have 'unlink'...
+AC_TRY_RUN([void foo1() __attribute__((constructor));
+void foo1() { unlink("conftest.1"); }
+void foo2() __attribute__((destructor));
+void foo2() { unlink("conftest.2"); }
+int main () { return 0; }],
+[test -r conftest.1 || a=yes
+test -r conftest.2 || b=yes], , AC_MSG_ERROR(Cannot test for constructor/destructor support when cross compiling))
+case $krb5_cv_host in
+*-*-aix4.*)
+	# Under AIX 4.3.3, at least, shared library destructor functions
+	# appear to get executed in reverse link order (right to left),
+	# so that a library's destructor function may run after that of
+	# libraries it depends on, and may still have to access in the
+	# destructor.
+	#
+	# That counts as "not working", for me, but it's a much more
+	# complicated test case to set up.
+	b=no
+	;;
+esac
+krb5_cv_attr_constructor_destructor="$a,$b"
+])
+# Okay, krb5_cv_... should be set now.
+case $krb5_cv_attr_constructor_destructor in
+  yes,*)
+    AC_DEFINE(CONSTRUCTOR_ATTR_WORKS,1,[Define if __attribute__((constructor)) works]) ;;
+esac
+case $krb5_cv_attr_constructor_destructor in
+  *,yes)
+    AC_DEFINE(DESTRUCTOR_ATTR_WORKS,1,[Define if __attribute__((destructor)) works]) ;;
+esac
+dnl End of attributes we care about right now.
+])
+dnl
+dnl
+dnl KRB5_AC_PRAGMA_WEAK_REF
+AC_DEFUN([KRB5_AC_PRAGMA_WEAK_REF],
+[AC_CACHE_CHECK([whether pragma weak references are supported],
+krb5_cv_pragma_weak_ref,
+[AC_TRY_LINK([#pragma weak flurbl
+extern int flurbl(void);],[if (&flurbl != 0) return flurbl();],
+krb5_cv_pragma_weak_ref=yes,krb5_cv_pragma_weak_ref=no)])
+if test $krb5_cv_pragma_weak_ref = yes ; then
+  AC_DEFINE(HAVE_PRAGMA_WEAK_REF,1,[Define if #pragma weak references work])
+fi])
+dnl
+dnl
+m4_include(config/ac-archive/acx_pthread.m4)
+#
+# KRB5_AC_LIBUTIL
+#
+# Check for libutil, for NetBSD, et al.; needed for openpty() and
+# logwtmp() on some platforms.
+#
+AC_DEFUN([KRB5_AC_LIBUTIL],
+	[AC_CHECK_LIB(util, main,
+		[AC_DEFINE(HAVE_LIBUTIL)
+  UTIL_LIB=-lutil])dnl
+AC_SUBST(UTIL_LIB)
+])
diff --git a/mechglue/src/appl/.Sanitize b/mechglue/src/appl/.Sanitize
new file mode 100644
index 000000000..b3f890ad8
--- /dev/null
+++ b/mechglue/src/appl/.Sanitize
@@ -0,0 +1,48 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+Makefile.in
+bsd
+configure
+configure.in
+gss-sample
+gssftp
+mailquery
+movemail
+popper
+sample
+simple
+telnet
+user_user
+zmailnotify
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/.rconf b/mechglue/src/appl/.rconf
new file mode 100644
index 000000000..06f02e132
--- /dev/null
+++ b/mechglue/src/appl/.rconf
@@ -0,0 +1,4 @@
+ignore telnet.90.09.14
+ignore *.TXT
+link arpa
+ignore old-telnet
diff --git a/mechglue/src/appl/ChangeLog b/mechglue/src/appl/ChangeLog
new file mode 100644
index 000000000..277410447
--- /dev/null
+++ b/mechglue/src/appl/ChangeLog
@@ -0,0 +1,101 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2004-07-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use KRB5_AC_INET6.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCAL_SUBDIRS): Renamed from MY_SUBDIRS.
+
+2004-02-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for sys/time.h and time.h.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-11-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add KRB5_GETPEERNAME_ARGS and
+	KRB5_GETSOCKNAME_ARGS for sample apps.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_C_CONST instead of AC_CONST. 
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS definition to control the directories
+		which are recursively descended by the Makefile.
+
+	* configure.in: Fold the autoconf tests from the sample, simple,
+		gss-sample, and user_user directories into this
+		higher-level configure.in file.
+
+Wed Feb 18 15:24:26 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Mon Nov 18 20:57:08 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* configure.in: Remove the popper, mailquery, and movemail
+	 	directories.
+
+Mon Jan 15 02:39:05 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: add gssftp to CONFIG_DIRS so that the GSSAPI
+	implementation of ftp gets built as well.
+
+Fri Jul 7 15:40:00 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit setting of LDFLAGS, it's set by
+		configure scripts.
+
+Fri Jun  9 18:26:09 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Tue Aug  9 20:18:27 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: nuked zmailnotify
+
+Sat Jul 23 08:25:48 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: autoconf'ing telnet
+
+Wed Jul 20 00:10:30 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in: autoconf'ing gss-sample
+
+Thu Jul 14 02:04:07 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in: suck in bsd now
+
diff --git a/mechglue/src/appl/Makefile.in b/mechglue/src/appl/Makefile.in
new file mode 100644
index 000000000..2a7d80aea
--- /dev/null
+++ b/mechglue/src/appl/Makefile.in
@@ -0,0 +1,7 @@
+thisconfigdir=.
+myfulldir=appl
+mydir=.
+BUILDTOP=$(REL)..
+
+LOCAL_SUBDIRS= sample simple user_user gss-sample
+
diff --git a/mechglue/src/appl/bsd/.Sanitize b/mechglue/src/appl/bsd/.Sanitize
new file mode 100644
index 000000000..353b5eb3e
--- /dev/null
+++ b/mechglue/src/appl/bsd/.Sanitize
@@ -0,0 +1,56 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+defines.h
+fieldbits.h
+forward.c
+getdtablesize.c
+kcmd.c
+krcp.c
+krlogin.c
+klogind.M
+krlogind.c
+krsh.c
+kshd.M
+krshd.c
+login.c
+login.M
+loginpaths.h
+rcp.M
+rlogin.M
+rpaths.h
+rsh.M
+setenv.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/bsd/ChangeLog b/mechglue/src/appl/bsd/ChangeLog
new file mode 100644
index 000000000..18da6c869
--- /dev/null
+++ b/mechglue/src/appl/bsd/ChangeLog
@@ -0,0 +1,3060 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* compat_recv.c (NEED_SOCKETS): Don't define.
+
+2005-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogind.c (doit): Change 0 to (char*)NULL in execl* calls.
+	Patch provided by Michael Calmer.
+	* krshd.c (doit): Likewise.
+	* login.c (main): Likewise.
+
+2004-10-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* kcmd.c (kcmd_connect): Set *addrfamilyp with the address family
+	actually used.
+
+2004-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Use KRB5_AC_LIBUTIL.
+
+	* Makefile.in (kshd, klogind): Use UTIL_LIB.
+
+2004-09-08  Tom Yu  <tlyu@mit.edu>
+
+	* login.c (main): Don't overwrite "PATH" environment variable if
+	it's already set.
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* compat_recv.c: Only include sys/select.h if it's available.
+
+2004-07-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use KRB5_AC_INET6.
+
+2004-05-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* setenv.c: Include string.h.
+
+2004-05-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* krsh.c (main): Invoke krb5_free_context at exit.
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (kshd, klogind): Link against apputils lib.
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Call KRB5_AC_NEED_DAEMON instead of checking
+	whether daemon() prototype is needed.
+
+	* krshd.c (ignore_signals): Split out from cleanup().
+	(doit): Call it when the shell process has completed, before
+	calling syslog.
+
+2003-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't use libkrb524.a any more.
+	* login.c: Don't include krb524.h.
+	(try_convert524): Don't call krb524_init_ets.
+
+2003-05-09  Tom Yu  <tlyu@mit.edu>
+
+	* krcp.c (main): Rename getlocalsubkey -> getsendsubkey.
+
+	* krlogin.c (main): Rename getlocalsubkey -> getsendsubkey.
+
+	* krlogind.c (recvauth): Rename getremotesubkey -> getrecvsubkey.
+
+	* krsh.c (main): Rename getlocalsubkey -> getsendsubkey.
+
+	* krshd.c (recvauth): Rename getremotesubkey -> getrecvsubkey.
+
+2003-04-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* krshd.c (main): Use LOG_AUTH syslog facility, not LOG_DAEMON,
+	for consistency with krlogind.c.
+
+2003-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* kcmd.c (kcmd_connect): Log errors if a connect to port 0 is
+	attempted.  Report port number in connection failure.
+	(setup_secondary_channel): Use socklen_t for socket address
+	length.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* compat_recv.c: Only include krb.h if KRB5_KRB4_COMPAT.
+	(krb_v4_recvauth, krb5_compat_recvauth,
+	krb5_compat_recvauth_version): Define only if KRB5_KRB4_COMPAT.
+	* krlogind.c: Include krb.h only if KRB5_KRB4_COMPAT.
+	(v4_kdata, v4_schedule): Define only if KRB5_KRB4_COMPAT.
+	(recvauth) [!KRB5_KRB4_COMPAT]: Skip v4 stuff and call
+	krb5_recvauth_version.
+
+2003-03-03  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (DEFINES): Add -DKERBEROS.
+
+	* configure.in: Delete ADD_DEF.
+
+2003-02-05  Tom Yu  <tlyu@mit.edu>
+
+	* login.c (main): Don't zero out terminal window size.
+
+2003-02-03  Tom Yu  <tlyu@mit.edu>
+
+	* login.c (dofork): Don't dissociate from controlling tty in the
+	parent, since the parent needs to remain the session leader so it
+	can tell when the tty gets hung up.  Make the child wait for the
+	parent to set up a SIGHUP handler to ensure that cleanup happens
+	properly.
+
+2003-01-31  Tom Yu  <tlyu@mit.edu>
+
+	* kcmd.c (v4_des_write): Apply patch from ghudson to fix
+	non-right-justification case.
+
+2003-01-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* login.c (try_krb4): Delete unused krb5 principal name argument.
+	(main): Don't pass it.  Initialize 'hostname'.
+
+2003-01-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogind.c (main, recvauth): Use socklen_t when passing
+	addresses to socket functions.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* login.c: Remove declaration of errno
+
+2003-01-03  Ezra Peisach  <epeisach@bu.edu>
+
+	* compat_recv.c (accept_a_connection): Test if IPv6 socket returns
+	EAFNOSUPPORT as well as EPROTONOSUPPORT. Irix 6.5.16m returns the
+	former.
+
+2003-01-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* compat_recv.c: Include sys/select.h and port-sockets.h.
+	(krb5_compat_recvauth_version): Only attempt krb4 authentication
+	if the source address is an IPv4 one.
+	(accept_a_connection): New function, derived from old krshd.c.
+	Listen on IPv6 as well as IPv4, if possible.
+	* krshd.c (main): Call accept_a_connection.  Change fromlen to a
+	socklen_t.
+	(doit): Initialize s.  Change length passed to getsockname to a
+	socklen_t.
+	(recvauth): Change len to socklen_t.  Cast peer IPv4 address
+	before calling krb5_compat_recvauth_version.
+	* defines.h: Include port-sockets.h.
+	(accept_a_connection): Declare.
+
+2002-12-06  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Quote the argument to AC_CHECK_HEADER. Autoconf
+	2.57 was having problems.
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* login.c (k5_get_password): Remove trailing colon, as new
+	implementation of krb5_read_password() appends it.
+
+2002-09-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (rcp): Fix typo in 06-25 change.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* compat_recv.c: Include defines.h for prototypes.
+
+2002-08-07  Jen Selby  <jenselby@mit.edu>
+	
+	* klogind.M, kshd.M, login.M: changed manual sections 8c, 1c, and
+	3x to 8, 1, and 3, respectively
+	* rcp.M, rlogin.M, rsh.M: added references to the server manpages
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* v4rcp.c: Include port-sockets.h.
+
+2002-07-09  Jen Selby <jenselby@mit.edu>
+
+	* login.M: added information about different command line options;
+	changed defaults given for tags that did not match code
+	* login.c: changed inaccurate comments
+
+2002-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogind.c (protocol): Initialize pbp, fbp.  Change left to type
+	size_t.
+
+2002-06-27  Jen Selby <jenselby@mit.edu>
+
+	* rsh.M: added warning that encryption does not encrypt the
+	command line
+	*rlogin.M: added warning that username is sent unencrypted
+
+2002-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* kcmd.c (kcmd): Don't restrict addresses to IPv4.
+
+	* configure.in: Check for rresvport_af.
+	* krshd.c (recvauth): Take sockaddr pointer argument instead of
+	sockaddr_in.  Use getnameinfo to extract port number string.
+	(remote_addr, remote_port, local_addr, local_port): Make buffers
+	bigger.
+	(doit): Use sockaddr_storage for local address.  Get rid of all
+	settings of non_privileged, since it's never used.  Don't copy
+	remote address to local variable.  Use getnameinfo instead of
+	inet_ntoa to format addresses and port numbers for environment
+	variables.  Create secondary channel socket in same address family
+	as primary channel socket; use rresvport_af if available.
+
+	* kcmd.c (setup_secondary_channel): Use select to time out after
+	10 minutes, or notice the primary channel being closed or
+	receiving data while we wait for the secondary one to be set up.
+
+	* compat_recv.c: New file, moved from lib/krb5util.
+	* Makefile.in (SRCS, OBJS): Include it.
+	(rcp, kshd, klogind): Link against it instead of krb5util
+	library.
+	* defines.h (krb5_compat_recvauth, krb5_compat_recvauth_version):
+	Move declarations here from include/k5-util.h.
+	(princ_maps_to_lname, default_realm): Declare.
+
+	* kcmd.c (kcmd_connect): Use strdup when copying hostname.
+	(princ_maps_to_lname, default_realm): Move functions here...
+	* krlogind.c (princ_maps_to_lname, default_realm): ...from here.
+	(recvauth): Use sockaddr_storage to hold addresses.
+	* krshd.c (default_realm, princ_maps_to_lname): Deleted.
+
+	* krsh.c (SECURE_MESSAGE): Only indicate that input/output data
+	are being encrypted, and don't automatically say it's with DES.
+
+	* krlogind.c: Include fake-addrinfo.h.
+	(SECURE_MESSAGE): Don't say it's DES that's used for encryption.
+	(main): "from" is now sockaddr_storage; cast pointers when calling
+	doit.
+	(doit): Take sockaddr pointer instead of sockaddr_in.  Use
+	getnameinfo instead of inet_ntoa and gethostbyaddr.  Only complain
+	about non-IPv4 addresses if not doing Kerberos, and only right
+	before checking port numbers.
+
+2002-06-17 Jen Selby <jenselby@mit.edu>
+
+	* klogind.M: documented the -D and -f options
+	* ksh.M: documented the -D and -L options
+	* rcp.M: documented the -c and -C options
+
+2002-05-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogin.c (oob): Loop reading data until we actually reach the
+	URG marker.
+
+2002-03-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* defines.h (FAI_PREFIX): Don't define.
+	* kcmd.c (kcmd_connect): Don't include fake-addrinfo.c.
+
+2002-03-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Remove dependencies on krb524_err.h for login.o. If
+	compiling without krb4 support, this file will not be present.
+
+2002-03-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* kcmd.c (kcmd_connect): Don't call fixup_addrinfo, it's been
+	deleted.  Actually save errno value when preparing error text to
+	print.  Free address info before returning.
+
+2002-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* kcmd.c: Include fake-addrinfo.c once again.
+	(kcmd_connect): Use getaddrinfo instead of gethostbyname, but only
+	get AF_INET addresses for now.  Add new argument, pointer to where
+	to store local socket address used; call getsockname to fill it
+	in.  Always call getport with the address family from the current
+	address.  Retry connection to the same remote address if the error
+	returned was EADDRINUSE; that applies to the local address.
+	(setup_socket): New function.
+	(getport): Use setup_socket.  When selecting an address family to
+	use, fall through in the last case instead of calling getport
+	recursively.
+	(kcmd, k4cmd): Don't call getsockname, let kcmd_connect do it.
+	Delete unused variables.  Don't set *fd2p before calling
+	setup_secondary_channel.
+	(setup_secondary_channel): No cleanup is needed, just return error
+	indications rather than branching to end of function.  If fd2p is
+	non-null, initialize the pointed-to value to -1.
+
+	* rcp.M: Document -f and -t options as internal use only.
+
+2002-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* kcmd.c: Revert 2002-02-10 changes except those related to
+	getport.
+	(masktype): New typedef.
+	(block_urgent, restore_sigs, kcmd_connect,
+	setup_secondary_channel): New functions.
+	(kcmd, k4cmd): Use them.  Delete redundant getpid calls.
+
+2002-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* loginpaths.h [_PATH_DEFPATH]: Undefine LPATH and RPATH
+	unconditionally before redefining them.
+
+	* login.c (main): If the supplied name is longer than the utmp
+	buffer, don't bother trying it as a username.
+	(dolastlog): Don't assume lastlog.ll_time is a time_t.
+
+2002-02-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* fieldbits.h: Deleted.
+
+2002-02-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* defines.h: Include fake-addrinfo.h.
+	(FAI_PREFIX): Define.
+	(getport): Update.
+	* kcmd.c: Include fake-addrinfo.c.
+	(kcmd): Use getaddrinfo instead of gethostbyname, but only get
+	AF_INET addresses for now.
+	(k4cmd): Update argument list to getport.
+	(getport): Accept new argument, pointer to address family to use.
+	If zero, try inet6 and then inet.
+	* krshd.c (doit): Update argument list to getport.
+
+2001-12-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* krcp.c, krlogin.c, krlogind.c, krsh.c, krshd.c, login.c,
+	setenv.c, v4rcp.c: Signed v.s unsigned int cleanup.
+
+	* defines.h: rcmd_stream_{read,write} take size_t as length argument.
+
+	* kcmd.c: Use GETSOCKNAME_ARG3_TYPE instead of assuming int. input
+	and output handler take size_t as length argument instead of
+	int. Other signed vs. unsigned fixes.
+
+	* configure.in: Add KRB5_GETSOCKNAME_ARGS.
+
+2001-11-06  Sam Hartman  <hartmans@mit.edu>
+
+	* kcmd.c: Define storage for our key usages
+	(rcmd_stream_init_krb5): Support c_init_state for non-des non-des3 enctypes
+	(v5_des_write v5_des_read):  support variable keyusage
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogin.c: Make prototypes unconditional.
+
+2001-09-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogin.c (try_normal): Permit "rsh" as well as "rlogin" as the
+	program name, for detecting when argv[0] is not the hostname.
+	If argv[0] isn't the hostname, always replace it with the system
+	rlogin pathname.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Use $(srcdir).
+
+2001-07-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* setenv.c (setenv): Include stdlib.h for malloc prototypes. 
+
+2001-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* v4rcp.c (kstream_create_rcp_from_fd, kstream_create_from_fd):
+	Allocate correct amount of space for kstream data.  (Patch from
+	Cygnus KerbNet code, 1997.)
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* login.c (sigint): Declare static.
+
+2001-07-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Link krshd with KRSHDLIBS instead of LOGINLIBS.
+
+	* configure.in: Creare a new variable KRSHDLIBS which differs from
+	LOGINLIBS by not including libkrb524.a. Test for getenv.
+
+	* krcp.c: Prototype lostconn().
+
+	* krlogind.c: Provide prototype for signal handler cleanup. Implied
+	need to add extra argument to function - ensure consistant
+	calling.
+
+	* krsh.c: Provide prototype for signal handler sendsig.
+
+	* krshd.c: Rewrite error() to use stdargs/varargs.
+	(doit): When creating a tty name using getpid. Ensure that does
+	not overflow tty string buffer.
+
+	* login.c: Provide prototype for signal handler timedout.
+
+	* setenv.c: Do not define getenv() unless needed.
+
+	* v4rcp.c: Rewrite error() to use stdargs/varargs. Add signal
+	number argument to lostconn(), include prototype, and ensure
+	called consistantly.
+
+2001-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* v4rcp.c, login.c: Fill in prototypes, declare many functions static. 
+
+2001-06-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* krlogind.c: Provide daemon prototype if needed.
+
+	* configure.in: Test if prototype for daemon necessary.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* login.c: Much cleanup to reduce globals and shadowing.
+
+	* krlogind.c (main): Change sin to sock_in.
+
+	* krshd.c: Change sin to sock_in to not shadow global. Change some
+	local variables to not shadow others.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* login.c (read_env_vars_from_file: Only define if
+	/etc/environment or /etc/timezone exists on machine.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* kcmd.c: Get rid of prototypes for krb5_write_message(),
+	krb5_net_write(), and krb5_net_read(). They are in krb5.h now.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* krcp.c (sink): Cast argument to isdigit() to int.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* loginpaths.h: If _PATH_DEFPATH is defined, undefine LPATH and
+	RPATH before redefining.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in (SETENVOBJ): If setenv is not present on system,
+	define NEED_SETENV as well as linking in local sources.
+
+	* defines.h: Include prototype for setenv() if NEED_SETENV defined.
+
+	* krlogin.c (prf): Declare as void. Used only with one argument -
+	get rid of pseudo-varargs behaviour.
+
+	* krlogind.c (recvauth): Include k5-util.h for
+	krb5_compat_recvauth_version() prototype. Declare sendoob() void.
+
+	* krshd.c: Include k5-util.h for krb5_compat_recvauth_version()
+	prototype.
+
+	* login.c: Include setenv prototype if NEED_SETENV defined. Cast
+	arguments to printf to match format string.
+
+	* v4rcp.c (source): Cast argument to sprintf() to match format string.
+	* krcp.c (rsource): Likewise.
+	* forward.c (rd_and_store_for_creds): Likewise.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* krshd.c: Include <grp.h>, <libpty.h>, and <sys/wait.h> for
+	initgroups(), pty_logwtmp()/pty_make_sane_hostname(), and wait()
+	prototypes. For local initgroups definition, conditionalize on
+	HAVE_INITGROUPS and not __SCO__.
+
+	* krcp.c: Include <sys/wait.h> for wait()/waitpid() prototype.
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* krlogin.c: Always provide prototype for setsignal and not if
+	__STDC__ is defined.
+
+2001-06-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* login.c: Add braces around initializers. Cleanup assignments in
+	conditionals.  Include krb524.h if KRB4_CONVERT defined.
+
+	* krlogind.c (main): Cleanup unused variables.
+	(protocol): Cleanup ambiguous if-if-else warning.
+
+	* krshd.c (main): Cleanup unused variables.
+
+	* krlogin.c (setsignal): Declare as void.
+	(server_message): Cleanup unused variables.
+
+	* setenv.c (setenv): Declare as returning int and clean up
+	assignments in conditionals.
+
+	* kcmd.c (kcmd, rcmd_stream_init_krb5, v5_des_read): Clean up
+	unused variables and assignments in conditionals.
+	* forward.c (rd_and_store_for_creds): Likewise.
+	* krcp.c (rsource): Likewise.
+	* v4rcp.c (answer_auth): Likewise.
+
+	* krsh.c (main): Declare as retuning int.
+
+2001-05-25  Tom Yu  <tlyu@mit.edu>
+
+	* krlogind.c (protocol): Don't do TIOCPKT on systems with STREAMS
+	ptys, even if there is a TIOCPKT, since it may result in hangs on
+	some systems where BSD packet mode is (presumably) not implemented
+	properly, such as AIX 4.3.3.  Should get cleaned up at some later
+	point to actually I_PUSH "pckt" or equivalent and do translation
+	between STREAMS and BSD style packet mode.
+
+2001-05-10  Tom Yu  <tlyu@mit.edu>
+
+	* defines.h: Fix k4cmd prototype to match kcmd.c.
+
+	* kcmd.c (k4cmd): Fix to not use a narrow type.
+
+	* krlogin.c: Fix prototypes so they don't include narrow types.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't use KRB5_CHECK_PROTOS.
+
+2001-04-02  Tom Yu  <tlyu@mit.edu>
+
+	* login.M: Don't include "= 0" as part of the "accept_passwd"
+	config option. [pullup from 1.2.2]
+
+2001-03-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* defines.h: Add prototypes for rcmd_stream_init_normal(),
+	rcmd_stream_init_krb4(), strsave() and rd_and_store_for_creds()
+
+	* Makefile.in: Add dependency of forward.o on defines.h
+
+	* forward.c: Include defines.h for prototypes.
+
+	* kcmd.c, krcp.c, krlogin.c, krlogind.c, krsh.c: Provide full prototype
+	for local functions and move include of kerberosIV/krb.h before
+	defines.h.
+
+2001-01-26  Tom Yu  <tlyu@mit.edu>
+
+	* krshd.c: Get path for NOLOGIN file from paths.h if present,
+	mirroring logic in login.c.  [patch from David MacKenzie
+	krb5-appl/913]
+
+2001-01-23  Tom Yu  <tlyu@mit.edu>
+
+	* forward.c (rd_and_store_for_creds): Overwrite any existing value
+	of the KRB5CCNAME environment variable.
+
+2001-01-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* krcp.c (error): Always declare with ellipsis.
+
+2001-01-13  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: Force SunOS to not use termios.
+
+2001-01-12  Sam Hartman  <hartmans@mit.edu>
+
+	* krlogin.c: Previously, we only used TIOCGLTC  on systems with
+	termios.  This is sort of silly since its a BSD 4.[23] IOCTL.  We
+	then go out of our way not to use it on IRIX, Solaris or HPUX.  I
+	think all this comes about because you really want to use BSD
+	IOCTLS on Sunos rather than termios.  I propose to do that and
+	never use BSD IOCTLs on Sunos.
+
+
+2000-12-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogin.c (main): Add new "-4" option, to use krb4
+	authentication only; useful for testing.
+	* rlogin.M: Updated.
+
+2000-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogind.c (doit): Cast first argument to pty_make_sane_hostname
+	to sockaddr pointer.
+	* krshd.c (doit): Likewise.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Update to autoconf 2 macro names:
+	AC_FORK->AC_FUNC_VFORK, AC_CONST->AC_C_CONST, AC_HEADER_CHECK ->
+	AC_CHECK_HEADER. In addition, conditionally use internal
+	AC_PROG_ECHO_N (autoconf 2.12) or _AC_PROG_ECHO (autoconf 2.49)
+	depending on which is defined.
+
+2000-10-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* login.c (k5_get_password): Declare second argument as unsigned
+	int length.
+
+Tue Oct 10 04:59:04 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* kcmd.c (kcmd): Use krb5_set_principal_realm() instead of freeing the
+	principals realm data and mucking with it ourselves.
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* krlogin.c (main): Declare main as int.
+
+2000-09-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (DEFINES): Define HEIMDAL_FRIENDLY.
+	* krlogind.c (recvauth): Don't complain about a subkey sent for
+	KCMDV0.1 if HEIMDAL_FRIENDLY is defined, just quietly ignore it.
+	* krshd.c (recvauth): Likewise.
+
+Tue Aug  8 13:38:22 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* krlogin.c (read_wrapper): Copy from the current point and not
+ 	the start of the cached buffer.
+
+2000-07-21  Peter S Litwack  <plitwack@mit.edu>
+
+	* krlogin.c (writer): Improved bandwith efficiency by reading 
+        and sending more than one character at a time if multiple 
+        characters are available to be read from the terminal.
+        * krlogin.c (read_wrapper): Added this function as a helper
+        to writer.  It facilitates checking for escape sequences 
+        (~^Z etc.) when reading mulitple characters at a time.
+
+2000-07-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* krcp.c: Provide format attribute for error() for versions of gcc
+	that support it.
+
+	* configure.in (LOGINLIBS): Test for crypt() in crypt library only
+	modifies LOGINLIBS.
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Remove linking of krb5util library from
+	applications that never use it.
+
+2000-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	Patch from Donn Cave and Leonard Peirce from 1.1 release cycle:
+	* login.c (k_init): Call krb5_cc_set_default_name right after
+	setting the environment variable.
+	(main): Likewise.
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* rcp.M, rsh.M, rlogin.M: Add description of new -PO, -PN
+	options.
+
+2000-06-19  Tom Yu  <tlyu@mit.edu>
+
+	* krshd.c (recvauth): Call krb5_recvauth_version() rather than
+	calling krb5_recvauth() with arguments intended for
+	krb5_recvauth_version().
+
+	* kcmd.c: Conditionalize krb_sendauth prototype based on sense of
+	KRB5_KRB4_COMPAT.
+
+2000-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* login.c (try_convert524): Add use_ccache argument.  Handle case
+	where we have gotten v5 creds via password being entered and don't
+	crash in that case, since previous code was assuming that v5 creds
+	were always being provided.  Adapted from patch by Bob Basch.
+
+2000-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* krcp.c (main): Fix logic again, this time in the "success"
+	case.  If there's a problem retrieving the new-protocol subkey,
+	print a message and exit, don't fall back.
+	* krsh.c (main): Ditto; don't look at enctype to try to guess
+	protocol version.  Delete unused variable "similar".
+
+2000-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogin.c (main): Rework fallback logic.  Fall back to k4cmd
+	unless encryption and the new protocol were both requested.
+
+	* krsh.c (main): Rework fallback logic.  Fall back to k4cmd if new
+	protocol wasn't requested.
+
+	* krcp.c (main): Revert setting of AP_OPTS_MUTUAL_REQUIRED
+	unconditionally, which was added by mistake with last set of
+	patches.  If kcmd fails and the new protocol is requested, don't
+	fall back to v4.
+
+2000-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (kcmd.o, krcp.o, krlogin.o, krlogind.o, krsh.o,
+	krshd.o): Depend on defines.h.
+	* krlogind.c: Include defines.h.
+	* krcp.c: Ditto.
+
+	* defines.h (enum kcmd_proto): New type.
+	(rcmd_stream_read, rcmd_stream_write, getport,
+	rcmd_stream_init_krb5): Add prototypes.
+
+	* kcmd.c (use_ivecs): New variable.
+	(encivec_i, encivec_o): Each is now an array of two elements.
+	(input, output, twrite, krb5_write_message, krb5_net_read,
+	krb5_net_write, krb_sendauth): Add prototypes.
+	(kcmd): New argument PROTONUMP points to enum kcmd_proto.  If
+	value is KCMD_PROTOCOL_COMPAT_HACK, set it to KCMD_NEW_PROTOCOL or
+	KCMD_OLD_PROTOCOL depending on session key type.  Use subkeys for
+	new protocol.  Callers updated.
+	(normal_read, v5_des_read, v4_des_read, twrite, v5_des_write,
+	v4_des_write, rcmd_stream_write, rcmd_stream_read): Take
+	additional argument indicating whether the fd is for the secondary
+	channel; ignored except in some v5 cases.  Callers updated.
+	(rcmd_stream_init_krb5): New argument, kcmd protocol version.  Set
+	up ivecs for secondary channel in each direction with values 0x2
+	ior primary channel value.  Callers updated.
+	(v5_des_read, v5_des_write): For new protocol, plaintext now has
+	its length prepended but not counted.
+
+	* krcp.c (main): Set kcmd protocol version based on command line,
+	not on encryption type.  Default to COMPAT_HACK.
+	* krsh.c (main): Ditto.
+	* krlogin.c (main): Ditto.
+
+	* krlogind.c (recvauth): Use new krb5_compat_recvauth_version
+	routine.  Determine client's kcmd protocol version and initialize
+	based on it.
+	* krshd.c (recvauth): Ditto.
+
+2000-05-19  Nalin Dahyabhai  <nalin@redhat.com>
+	    Ken Raeburn  <raeburn@mit.edu>
+
+	* krcp.c (sink): bail if the target directory/file name is too long
+	* krlogind.c (recvauth, krb4 compat): truncate user name if the
+	principal's root would be too long to be valid
+	* v4rcp.c (sink): bail if the target directory/file name is too long
+
+2000-05-18  Tom Yu  <tlyu@mit.edu>
+
+	* krshd.c: Shuffle inclusion of defines.h so that some krb5
+	structures are declared prior to the kcmd() prototype.
+
+2000-05-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* defines.h (kcmd): Add prototype.
+	* krcp.c (main): Add extra arg to a kcmd call I missed yesterday.
+
+2000-05-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* krcp.c (main): Fix some conditionalizations to make proper
+	indentation easier.
+
+	* kcmd.c (encivec_i, encivec_o): New variables replace old single
+	variable encivec.
+	(rcmd_stream_init_krb5): New argument am_client, used to
+	initialize both ivec values.
+	* krcp.c (main, answer_auth): Pass new argument.
+	* krlogin.c (main): Ditto.
+	* krlogind.c (recvauth): Ditto.
+	* krsh.c (main): Ditto.
+	* krshd.c (recvauth): Ditto.
+
+	* defines.h (OPTS_FORWARD_CREDS, OPTS_FORWARDABLE_CREDS): Change
+	numbers so they don't conflict with AP_OPTS_USE_SUBKEY.
+	* kcmd.c (kcmd): New argument authconp, used to return the auth
+	context to the caller if desired.
+	* krlogin.c (auth_context): New variable.
+	(main): Request a subkey from sendauth.  Get the auth context from
+	kcmd so we can retrieve the subkey.  If non-DES session key is
+	being used, pass the subkey to rcmd_stream_init_krb5 instead of
+	the session key; fail if no subkey is found and encryption is
+	required.
+	* krlogind.c (recvauth): If a non-DES session key is being used,
+	pass the client-provided subkey to rcmd_stream_init_krb5.
+	* krcp.c (main): Set up and use subkey as above.
+	* krsh.c (main): Set up and use subkey as above.
+	* krshd.c (recvauth): Accept and use subkey as above.
+
+2000-05-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* v4rcp.c (main, case 'k'): Make sure krb_realm is
+	null-terminated.
+
+2000-04-27  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* krlogin.c (main): Don't overflow buffer "term".
+	* krshd.c (doit): Don't overflow buffer "cmdbuf".
+	* login.c (afs_login): Don't overflow buffer "aklog_path".
+
+2000-03-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for alpha*-dec-osf* instead of
+	alpha-dec-osf*.
+
+2000-03-15  Ken Raeburn  <raeburn@mit.edu>
+	    Mark D. Roth  <roth@uiuc.edu>
+
+	* login.c (update_ref_count): Copy passwd info before calling
+	getuserattr, to keep data from getting clobbered.  Patch from Mark
+	Roth.
+
+2000-02-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogin.c (main): Don't output debugging messages if debugging
+	wasn't turned on.
+
+2000-02-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* login.c (main): Only destroy xtra_creds if non-null.  (Patch
+	from Richard Basch.)
+
+2000-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* login.c (main): Reorder some control flow to avoid security hole
+	if KRB4_GET_TICKETS is not defined.
+
+2000-01-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogin.c (speeds): Added some comments from net recommending
+	not extending the list to higher values.
+
+1999-11-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* login.c (k_init): Call krb5_init_secure_context instead of
+	krb5_init_context and krb5_secure_config_files.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* krlogin.c (main): Error out if -D isn't followed by another
+	argument.  Based on patch from Brad Thompson.
+
+	* krshd.c (v4_kdata, v4_ticket): Don't define if KRB5_KRB4_COMPAT
+	is not defined.  Patch from Brad Thompson.
+
+	* kcmd.c (kcmd): If krb5_get_credentials returns a nonzero error
+	code, print an error message before returning.
+
+	* krlogin.c (main): If ospeed is outside of compiled-in table
+	index range but not high enough to be a baud rate, use the highest
+	rate in the table.
+
+1999-08-24  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (kshd): Remove $(LOGINLIBS) from kshd dependencies.
+
+1999-08-02  Ken Raeburn  <raeburn@mit.edu>
+	and Brad Thompson  <yak@mit.edu>
+
+	Patches from Brad Thompson for building without krb4
+	compatibility:
+	* krshd.c: Include sys/socket.h and netdb.h if KRB5_KRB4_COMPAT
+	isn't defined.
+	(doit): Cast pointer argument to getsockname.
+	(recvauth): Do krb4 stuff only if KRB5_KRB4_COMPAT is defined;
+	otherwise, skip it and call krb5_recvauth.
+	* kcmd.c (do_lencheck): Define even if !KRB5_KRB4_COMPAT.
+
+1999-07-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* login.c (main): Fix typo in computing strncpy length for shell
+	name.
+
+Sat Jul 24 08:50:39 1999  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (kshd): Add $(LOGINLIBS).
+
+1999-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	AIX 4.3.2 changes based on bug report from Joshua Lackey,
+	lackeyj@austin.ibm.com:
+	* configure.in: Check for rmufile function.
+	* login.c (update_ref_count) [! HAVE_RMUFILE]: Call putgroupattr
+	with SEC_DELETE before SEC_COMMIT; don't call rmufile.
+
+Fri Mar 12 19:01:35 1999  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (kshd): Add $(LOGINLIBS).
+
+Mon Mar  8 19:21:23 1999  Tom Yu  <tlyu@mit.edu>
+
+	* kshd.M: Resync manpage.
+
+	* krshd.c: Rework hostname logging.
+
+Wed Feb 24 20:05:40 1999  Tom Yu  <tlyu@mit.edu>
+
+	* klogind.M: Resync manpage.
+
+	* krlogind.c: Rework flags for hostname logging.
+
+Mon Feb 22 22:26:32 1999  Tom Yu  <tlyu@mit.edu>
+
+	* kcmd.c (kcmd): Fix up to not call sname_to_principal until after
+	all the addresses in hp have been iterated through to avoid
+	smashing. [krb5-appl/516]
+
+	* kcmd.c (k4cmd): Move call to krb_realmofhost() to avoid smashing
+	hp.
+
+Wed Feb 17 17:24:11 1999  Tom Yu  <tlyu@mit.edu>
+
+	* klogind.M: Document things a little better, including new
+	options controlling hostname manipulation.
+
+	* krlogind.c: Make use of pty_make_sane_hostname() for purposes of
+	manipulating hostname to pass to login.  Also unconditionally
+	syslog IP address and full hostname of remote host.  Add command
+	line options to control such behavior.
+
+	* configure.in: Add arpa/nameser.h to CHECK_HEADERS.
+
+Wed Jan 20 21:42:41 1999  Tom Yu  <tlyu@mit.edu>
+
+	* login.c (main): Call setluid().
+
+	* krshd.c (doit): Call setluid().
+
+	* configure.in: Check for setluid() rather than main() in
+	libsecurity.
+
+1998-11-28  Sam Hartman  <hartmans@mesas.com>
+
+	* krshd.c krsh.c:  Use RCMD_BUFSIZ not RSH_BUFSIZE [krb5-appl/678]
+
+	* kcmd.c: Move RCMD_BUFSIZ into defines.h
+
+1998-11-16  Geoffrey King  <gjking@mit.edu>
+
+	* login.c (login_get_kconf): Also test whether *kconf_val is null
+ 		rather than just kconf_val before passing *kconf_val to
+ 		conf_affirmative (where strcasecmp will choke on it
+		if it is in fact null).
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+
+1998-10-24  Marc Horowitz  <marc@mit.edu>
+
+	* login.c: update to new get_creds API
+	
+	* krlogin.c (main, oob, server_message, control), krlogind.c
+		(sendoob, protocol, recvauth): If the enctype is not
+		similar to DES, use an inband signalling protocol instead
+		of MSG_OOB data to indicate status changes.
+
+	* kcmd.c (rcmd_stream_init_krb5, v5_des_read, v5_des_write):
+		update to new crypto API.  Add ivec chaining to
+		encryption when the enctype is not similar to DES as part
+		of the new protocol.
+
+1998-10-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krshd.c (doit): Apply ghudson's patch so that rshd passes the
+		port numbers for the local and foreign addresses so that
+		the V4 encrypted RCP will work correctly.  [krb5-appl/638]
+	* v4rcp.c (answer_auth): Apply ghudson's patch so that if
+		KRB5LOCALPORT and KRB5REMOTEPORT are set, use them to set
+		the foreign and local ports so that encrypted rcp for the
+		same machine.  [krb5-appl/638]
+
+Tue Aug 18 16:48:02 1998  Tom Yu  <tlyu@mit.edu>
+
+	* krlogin.c: Add <sys/filio.h> for FIONREAD.
+
+Sat Aug 15 00:01:15 1998  Geoffrey King  <gjking@mit.edu>
+
+	* krcp.c (error): Don't call rcmd_stream_write if iamremote is not
+ 	set, because it expects a valid file descriptor [krb5-appl/359].
+  	Also, remove mistakenly duplicated comment above the function.
+
+Mon Jul 27 00:06:20 1998  Geoffrey King  <gjking@mit.edu>
+
+	* krlogin.c (main): Apply ghudson's patch so that rlogin -a
+	no longer dumps core. [krb5-appl/612]
+
+Sun Jul 26 23:46:36 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* login.c (main): Allow krb524 conversion for forwarded tickets
+	(try_convert524): Don't check to see if we have tickets here; caller  does that and actually gets it right.
+
+1998-05-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* login.c (dolastlog): BSD 4.4 systems don't have lastlog.h, but
+		still define struct lastlog somewhere.  Included from Dima
+		Ruban's FreeBSD patches.
+
+	* krlogin.c: Include sys/ioctl_compat.h if it is present (instead
+		of just for 386BSD).  
+
+	* loginpaths.h (LPATH): If the OS provides _PATH_DEFPATH, use it
+		to define LPATH and RPATH.
+
+	* login.c: #include paths.h if present, and use it to set the
+		pathnames for certain common files.
+
+	* configure.in (withval): Check for <sys/ioctl_compat.h> and
+	   <paths.h>
+
+Sat May 16 16:07:42 1998  Tom Yu  <tlyu@mit.edu>
+
+	* login.c: Replace strcpy with strncpy in places.  Add nul
+	termination to some existing invocations of strncpy.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Add a check for the header file krb4-proto.h.
+		Replace file existence tests for /etc/environment and
+		/etc/TIMEZONE with K5_AC_CHECK_FILES.
+
+	* login.c (main): 
+	* krshd.c (main): 
+	* krlogind.c (main): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Sat Feb 28 10:44:46 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Clean up configure script.  Check $cross_compiling
+		instead of (no longer correct) cache variable; remove
+		obsolete AC_C_CROSS.  Use AC_CHECK_FUNCS instead of
+		individual AC_FUNC_CHECK calls for speed.  Change checks
+		for strsave and utimes to use AC_CHECK_FUNCS
+
+	* krcp.c, v4rcp.c: Change usages of HAS_STRSAVE and HAS_UTIMES to
+	 	HAVE_*.
+
+Tue Feb 24 14:52:33 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kcmd.c: Integrate ghudson's changes for client-side krb4
+	compatibility. [krb5-appl/483]
+	
+	* krcp.c: Integrate ghudson's changes for client-side krb4
+	compatibility. [krb5-appl/483]
+
+	* krlogin.c: Integrate ghudson's changes for client-side krb4
+	compatibility. [krb5-appl/483]
+
+	* krlogind.c: Integrate ghudson's changes for client-side krb4
+	compatibility. [krb5-appl/483]
+
+	* krsh.c: Integrate ghudson's changes for client-side krb4
+	compatibility. [krb5-appl/483]
+
+	* krshd.c: Integrate ghudson's changes for client-side krb4
+	compatibility. [krb5-appl/483]
+
+Sun Feb 22 19:16:12 1998  Tom Yu  <tlyu@mit.edu>
+
+	* v4rcp.c: Punt nastiness to redefine setreuid, as we don't use
+	it.
+
+	* krcp.c: Use krb5_seteuid(). [krb5-libs/505]  Fix up inclusions
+	to use <> rather than "".
+
+Wed Feb 18 15:26:52 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Jan 20 21:42:06 1998  Tom Yu  <tlyu@mit.edu>
+
+	* krlogind.c (protocol): Declare pibuf and fibuf as being BUFSIZ
+	bytes long, rather than 1024.  Fixes an Irix bug. [krb5-appl/527]
+
+Fri Dec 19 18:19:42 1997  Dan Winship  <danw@mit.edu>
+
+	* login.c (try_afscall): try_afscall doesn't work / isn't needed
+	on systems without SIGSYS
+
+Thu Dec 11 23:20:20 1997  Tom Yu  <tlyu@mit.edu>
+
+	* krlogind.c:
+	* krshd.c:
+	* login.c:
+	* v4rcp.c: Don't include netdb.h or sys/socket.h if krb.h is
+	included; this works around an Ultrix bug where those headers
+	aren't protected against multiple inclusion.
+
+Thu Nov 20 16:42:54 1997  Tom Yu  <tlyu@mit.edu>
+
+	* krlogind.c (recvauth): Fix args in call to
+ 	rd_and_store_for_creds. [krb5-appl/502]
+
+Mon Nov 17 20:55:31 1997  Tom Yu  <tlyu@mit.edu>
+
+	* krshd.c: Don't set checksum_ignored to 1 if checksum_required is
+	0; also, if a krb5 client passes in a checksum, check it
+	regardless of whether checksum_required is true. [krb5-appl/500]
+
+Wed Nov 12 19:03:02 1997  Tom Yu  <tlyu@mit.edu>
+
+	* forward.c (rd_and_store_for_creds): Don't do the chown.  Avoids
+	a security hole. [krb5-appl/494]
+
+	* krshd.c (recvauth): chown the ccache explicitly, as
+	rd_and_store_for_creds no longer does so. [krb5-appl/494]
+
+Thu Nov  6 22:04:26 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* v4rcp.c: Use error_message(errno) instead of using
+ 		sys_errlist[errno].  This avoids the hair of deciding
+ 		whether or not we need to declare sys_errlist or use
+ 		strerror(), etc., since com_err has all of that complexity
+ 		anyway.  Also fixed lots of -Wall nits.
+
+Mon Nov  3 15:25:48 1997  Tom Yu  <tlyu@mit.edu>
+
+	* krlogind.c (doit): Fix up potential buffer overrun.
+	[krb5-appl/488]
+
+	* krlogin.c (main): Fix up potential buffer overrun.
+
+	* krcp.c (hosteq): Fix up potential buffer overrun.
+
+Tue Oct  7 18:01:15 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* v4rcp.M: Removed useless .so to a non-existent macro file.
+
+Tue Sep  2 19:44:21 1997  Tom Yu  <tlyu@mit.edu>
+
+	* krlogind.c (main): Changes to allow for standalone daemon
+	operation.  Use the "-f" flag to enable.  This automagically
+	figures out which port to bind to if you don't specify it.
+
+Mon Jun 30 13:21:34 1997  Kevin L Mitchell  <klmitch@mit.edu>
+
+	* login.c (dofork): Solaris 2.4 puts killpg in the bsd compatibility
+		libraries.  Autoconf correctly determined that it wasn't
+		available, but it wasn't conditionalized out.  Added the
+		conditional, using kill(-child, SIGHUP) as a replacement,
+		as suggested by tlyu
+
+Thu Jun  5 15:56:54 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* login.c: Always use the new tty line discpline.  [krb5-appl/428]
+
+	* login.c: If a hangup signal is received, pass it onto the child.
+		[krb5-appl/432]
+
+Fri Mar 28 01:05:27 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* login.c (NO_MOTD): If we're on an SGI machine, don't do the MOTD
+		or MAILCHECK thing, since it's done by /etc/cshrc magic.
+		(SGI's don't define __SVR4, even though it's SVR4
+		derived).  [krb5-appl/158]
+
+	* krlogin.c (try_normal): When falling back to the normal rlogin,
+		clear the signal mask, so that the child rlogin handles
+		SIGUSR1 (which is used for window size changes) correctly.
+		[krb5-appl/335]
+
+Tue Mar 18 12:34:03 1997  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+ [326]	* login.c(doit):  Preserve terminal even without -p.
+
+Thu Feb 27 10:58:07 1997  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+	* krshd.c: Allow user to login with / as home directory if homedir
+ 	not found. [167]
+
+Sat Feb 22 00:54:06 1997  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+	* krlogin.c (mode): Clean up Posix terminal handling for NetBSD.
+
+Tue Feb 18 18:03:55 1997  Richard Basch  <basch@lehman.com>
+
+	* krcp.c: Replace krb5_xfree with krb5_free_data_contents
+	* kcmd.c krlogind.c krshd.c: Use free instead of internal krb5_xfree
+	* krlogin.c: Fixed 8bit character flow under Solaris
+	* kcmd.c: getport() lets the OS pick the port rather than scanning
+	* krshd.c: Don't bother to set lport before calling getport(&lport)
+
+Sat Dec 28 21:06:43 1996  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+	* login.c: Force environment variables like HOME to be set even if
+ 	-p given.
+
+Wed Feb  5 20:56:03 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Tue Dec 24 16:08:41 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Fix up "test $ac_cv_c_cross" to deal with
+	autoconf-2.12, since that variable can be set to a null string.
+
+Fri Dec  6 00:53:08 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* v4rcp.c: Extend the platform-specific braindamage so that
+ 		FreeBSD works.  This whole file is eventually going to
+ 		need serious rototilling to make it even vaguely correct.
+		[PR #284]
+
+Fri Dec  6 00:02:25 1996  Tom Yu  <tlyu@mit.edu>
+
+	* loginpaths.h: Add catch-all entries for LPATH and RPATH in case
+	we run across something that we haven't hardcoded paths for
+	yet. [267]
+
+Thu Dec  5 21:58:28 1996  Tom Yu  <tlyu@mit.edu>
+
+	* login.M: v5srvtab -> krb5.keytab [279]
+
+Sun Nov 24 23:35:22 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* login.c (try_afscall): Change to take pointer to function
+		instead of only calling setpag(). [krb5-appl/190]
+
+Fri Nov 22 15:46:46 1996  unknown  <bjaspan@mit.edu>
+
+	* kcmd.c (kcmd): use sizeof instead of h_length to determine
+ 	number of bytes of addr to copy from DNS response [krb5-misc/211]
+
+Thu Nov 14 14:30:28 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krcp.c: don't print our own error message if kcmd returns -1 (it
+ 	always printed something in that case, and error_message(-1)
+ 	prints a mess [krb5-appl/70]
+
+Mon Nov 11 23:38:05 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krshd "plumbing" fixes
+
+	Tue Jun 25 19:51:07 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krshd.c (doit): ignore SIGPIPE in the child, check the return
+	status of write instead.
+	Added comments labelling the various file descriptors.
+	Cleaned up formatting somewhat.
+	Check for failure of write to child stdin pipe, and stop reading.
+	Check for output from child before checking for input from net, to
+	reduce potential for missed output.
+	(cleanup): moved before doit, to eliminate need for declaration.
+  	Added an argument, to allow reporting of what signal kshd died
+	on, and report that the daemon terminated, not the shell.
+
+	Thu Jun 20 18:54:04 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krshd.c: fix global-change typo in !KERBEROS branch.
+
+Mon Nov 11 15:00:25 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in, configure.in, krshd.c, v4rcp.M, v4rcp.c: added
+	kerberos V4 rcp -x support from Cygnus tree.
+	* Makefile.in, configure.in: added support for not building v4rcp
+	if --without-krb4 is used.
+	
+	Sun Aug 11 17:30:39 1996  Chris Provenzano  <proven@cygnus.com>
+
+	* v4rcp.c : #include <fcntl.h> for O_* flags.
+
+	Mon Jul  8 13:44:39 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* v4rcp.c (getdtablesize): eliminate local copy.
+	(kstream_write): eliminate srandom/random in favor of
+	krb5_random_confounder.
+	Add sys/socket.h to includes (v4 had it internal to krb.h.)
+	(utimes): clone utimes-emulation from v5 krcp.c (should perhaps be
+	changed to use AC_REPLACE_FUNC...)
+	Declare getenv.
+
+	Sat Jul  6 16:39:28 1996  Mark W. Eichin  <eichin@kitten.gen.ma.us>
+
+	* v4rcp.c (answer_auth): use inet_aton only if we have it;
+	otherwise fake it with inet_addr.
+	* configure.in: check_func for inet_aton.
+
+	Tue Jul  2 19:37:52 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krshd.c (envinit): clarified initializations, labeled all slot
+	reservations (SAVEENVPAD, KRBPAD, ADDRPAD are lists of zeroes.)
+	Move TZ to always be slot 5, even on the cray. Added space for the
+	local and remote addresses.
+	(doit): add a getsockname to save the correct local address for
+	the child. Set KRB5LOCALADDR and KRB5REMOTEADDR to literal IP
+	addresses since the child is on the wrong side of a pipe and can't
+	recover them directly.
+	* v4rcp.c (kstream): add common "writelen" field for the length of
+	inbuf and outbuf.
+	(kstream_create_rcp_from_fd): initialze new fields.
+	(kstream_write): grab a big enough buffer (since this is called
+	with chunks that may correspond to the *filesystem* blocksize,
+	which is usually larger than BUFSIZ.) Also skip the first four
+	bytes of outbuf so that the encryption is done on an 8 byte
+	boundary (if malloc is correctly aligned, malloc+8 should also
+	be.)
+	(answer_auth): don't try to getpeername or getsockname, since
+	we're run under a pipe; just use KRB5LOCALADDR and KRB5REMOTEADDR
+	which are now provided by kshd (and fail if they are not present.)
+	This is safe because if they're wrong, it just means that the
+	mutual authentication will fail.
+
+	Thu Jun 27 23:32:41 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (all, clean, install, v4rcp): add v4rcp installation
+	and build rules.
+	* krshd.c: if we got a V4 connection and the command is rcp, use
+	the v4rcp backend to handle encryption.
+	* v4rcp.c: based on Cygnus CNS V4 rcp, stripped down to eliminate
+	user commands (and truncated usage message.)  Includes a fake
+	subset of the kstream interface that only handles "rcp -x" mode.
+	* v4rcp.M: new file, documents v4rcp support.
+
+Sat Nov  9 10:49:36 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* login.c: Re-arrange to deal with compiling without krb4 support. [148]
+
+Fri Nov  8 20:59:27 1996  Tom Yu  <tlyu@mit.edu>
+
+	* login.c (k_init): Set up KRBTKFILE if converting krb5 tickets to
+	krb4 but not getting them via password.
+
+Wed Nov  6 11:32:36 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* login.c (destroy_tickets): Just use global kcontext instead
+		of creating a new krb5 context for no good reason.
+
+	* krshd.c (main): 
+	* krsh.c (main): 
+	* krlogind.c (main): 
+	* krlogin.c (main): 
+	* krcp.c(main): Check the error return from krb5_init_context(),
+ 		and print an error message if necessary.
+
+Fri Nov  1 23:11:21 1996  Sam Hartman  <hartmans@planet-zorp.MIT.EDU>
+
+	* login.c: print out system error if -1 returns.
+	(destroy_tickets): Destroy krb4 tickets if we are converting as
+ 	well as just for initial tickets.
+
+Fri Nov  1 21:00:01 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* login.c: Have the this call must succeed comment before setuid,
+ 	not the AIX login uid setting.
+
+Thu Oct 31 22:14:00 1996  Sam Hartman  <hartmans@planet-zorp.MIT.EDU>
+
+	* krlogind.c (doit): Remove tab3 because it isn't very useful and
+ 	isn't always present.
+
+Thu Oct 31 19:19:54 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* klogind.M kshd.M:  document -r goes away [138]
+
+	* krshd.c (doit): Do not support rhosts authentication.  This was
+ 	never used by any clients and the cruft in kcmd.c was creating
+ 	problems. [138]
+
+	* krlogind.c (do_krb_login): Remove broken rhosts support. [138]
+
+	* kcmd.c: Remove ruserok and associated cruft along with killpg. [138]
+
+Tue Oct 29 10:09:39 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* login.c: Make the defaults be to *not* to get Kerberos V4
+ 		tickets.  There are currently bad interactions between
+ 		defaulting and the default Kerberos V4 realm (which is
+ 		still hard-coded to be ATHENA.MIT.EDU).
+		Also added some miscellaneous code cleanups.
+
+Mon Oct 21 13:44:53 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kcmd.c: don't retry (and waste 7 seconds) on ECONNREFUSED, just
+ 	fail immediately [krb5-appl/120]
+
+Fri Oct 18 17:26:51 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krsh.c, krlogin.c: don't print our own error message if kcmd
+ 	returns -1 (it always printed something in that case, and
+ 	error_message(-1) prints a mess [krb5-appl/70]
+
+Mon Sep 30 17:15:14 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* login.c: Allow login -f to let you log in as root.
+
+Mon Sep 30 16:22:48 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* login.c (stypeof): If TERM environment variable set, use it.
+
+	* krlogind.c (doit): Do not use login -E; no one supports it
+        besides login.krb5which also supports -f.
+
+Sun Sep 29 20:49:47 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* login.c: Fix so it works with --without-krb4 option
+
+Fri Sep 20 18:23:53 1996  Sam Hartman  <hartmans@planet-zorp.MIT.EDU>
+
+	* login.c: Update so that we try to convert krb524 tickets after
+ 	we setuid(), and so that we don't hard fail if cache writeout
+ 	fail.
+
+Fri Sep 20 17:35:22 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* login.c: Check to see if we got krb5 tickets at all times,
+ 	regardless of wether we are converting to krb4.  This helps us
+ 	know when to kdestroy.
+
+Wed Sep 11 17:27:02 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* login.c: fix a security-threating race condition: chown'ing the
+ 	ccache to the user can be bad if the user can delete the file
+ 	first and make it a symlink to something else.  The solution is to
+ 	re-create the ccache after login as setuid() to the user.
+	
+Tue Sep 10 14:03:53 1996  Tom Yu  <tlyu@mit.edu>
+
+	* klogind.M, kshd.M, login.M, rcp.M, rlogin.M, rsh.M: remove ".so
+	 	man1/header.doc"
+
+Fri Sep  6 13:22:46 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* login.M: Document that login_krb4_convert is off by default.
+
+	* login.c: Turn login_krb4_convert off by default, since it causes
+		problems if you don't have krb524d running on the KDC.
+		This is necessary because a Solaris socket bug causes
+		login to hang for 45 seconds if krb524d isn't present on
+		the KDC.
+
+Mon Sep  2 12:03:53 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* krlogind.c rlogin.c (v5_des_write): Write out length plus
+ 	encrypted data as one packet; this reduces latency by one RTT for
+ 	interactive traffic with kernels that support schemes similar to
+ 	RFC896, and reduces the number of packets with most other TCP
+ 	stacks.
+
+Sat Aug 10 16:22:34 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* krcp.c (source): Cast stb.st_size to a long before printing it.
+  	On NetBSD, it's a quad, so the following pointer is ignored and
+ 	all files look null.  We could special case NetBSD, but casting is
+ 	somewhat cleaner if we aren't dealing with 2g+ files.
+e
+Mon Jun 24 09:48:11 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krsh.c (main): Fix typo so that krsh doesn't exit when using the
+		default port.
+
+Fri Jun 21 21:12:52 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in : Make sure it works with the built-in libkrb4.a again.
+
+Fri Jun 14 13:19:30 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* login.c: Add define to deal with krb_save_credentials possibly
+ 	being called save_credentials, and to define krb_get_err_text if
+ 	it is not defined by the krb4 library.
+
+	* configure.in :  check for krb_save_credentials and krb_get_err_text
+
+Thu Jun 13 14:24:50 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* krlogind.c (doit): If using vendor login, make sure output flags
+ 	are reasonable.
+
+
+Sat Jun 15 04:03:32 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Cleanup of tests whose results are not longer used
+		with the pty library in place.
+
+Mon Jun  3 21:26:34 1996  Tom Yu  <tlyu@mit.edu>
+
+	* login.c: Ezra's patches to trim unsed arg from
+		verify_krb_v5_tgt, etc.
+
+	* Makefile.in,configure.in: allow compilation w/o krb4 (Ezra's
+		patches)
+
+Sun May 19 15:22:06 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* login.c (destroy_tickets main):  Use a secure context
+
+Wed May 22 22:46:40 1996  Richard Basch  <basch@lehman.com>
+
+	* login.c (k_init): Set the default KRB5CCNAME environment variable
+	consistently with other applications - FILE:/tmp/krb5cc_p<pid>
+
+Thu May  9 00:09:14 1996  Richard Basch  <basch@lehman.com>
+
+	* krlogind.c krshd.c:
+	Use the replay cache associated with the default server name
+	(rc_host*), like telnetd does.
+
+Mon May  6 14:06:21 1996  Richard Basch  <basch@lehman.com>
+
+	* login.c: SVR4 logins do not do motd or mailcheck normally; that
+	is a function of /etc/profile.  login.krb should act the same...
+
+Mon Apr 29 17:02:44 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	Merge with Cygnus sources, changes from Mark Eichin, Marc
+	Horowitz, Chris Provenzano and me:
+
+	* Makefile.in (install): Install correct set of man pages, and
+	check for failures.
+	* kshd.M, klogind.M: Renamed from kr*.M versions.
+	* login.M: New file. Man page for login with some description of
+	new features.
+
+	* rlogin.M: Remove references to using program with target
+	hostname as argv[0].
+	* rsh.M: Ditto.  Also document -f, -F, -x options.
+
+	* login.c: Massive changes.  Split much functionality out of main
+	and into separate file sections: terminal flag settings, Kerberos
+	4 and 5 support, UNIX password support, mail check, signal handler
+	handling, some other support routines.  Revamp controlling tty and
+	process group handling.  For AFS configuration, use setpag and run
+	aklog.  Try validating password using krb5.  Always set tty flags,
+	not just for rlogin session.  When validating tickets, treat an
+	existing key file that doesn't contain the key we think we want
+	(possibly because DNS was spoofed) as an error condition.
+	* Makefile.in (LOGINLIBS): List libkrb524.a here.
+	(LIBOBJS): Not here.
+	(login.krb5): Reverse the order of LIBOBJS and LOGINLIBS.
+	* configure.in: Check for --with-afs.  Add AFS libs and define
+	SETPAG if supplied.
+
+	* login.c (KRB5_GET_TICKETS, KRB4_GET_TICKETS, KRB_RUN_AKLOG): new
+	macros selecting single signon options.  krb5.conf profile support
+	for control over authentication options, above the compile time
+	selection.
+	(conf_affirmative): new function, recognize yes/no in profile
+	value.
+	(login_get_kconf): new function, look for all [login] flags and
+	set them in appropriate globals (via login_conf_set array.)
+	(main, sleepexit, destroy_tickets): Check the new login_* flags.
+	(main): rename KRB4_USE_524 to KRB4_CONVERT.
+
+	* configure.in: Added checks for tcsetpgrp, tcgetpgrp, setpgid.
+	* krlogind.c (control): Use tcgetpgrp if it's available.
+
+	* loginpaths.h (RPATH, LPATH, LPATH_root): Define HP/UX 9.04
+	versions, conditionalized on __hpux and !hpux.
+
+	* login.c and configure.in: instead of checking _IBMR2 and
+ 	__sgi__, write configure tests to check for the existence of
+ 	/etc/environment and /etc/TIMEZONE files, respectively.
+
+	* forward.c (rd_and_store_for_creds) : If chown fails then only
+	pass failure back if owner is different than intended owner. This
+	is to make rsh.exp test work without requiring root privlidges.
+
+	* login.c (main): Don't set TERM to an empty value.
+	(stypeof) [__hpux]: Return null if unknown.
+
+	* krlogin.c (catchild): remove hp/ux kludge because of aclocal.m4 fix.
+	(speeds): test __hpux for hpux speed list.
+	(main): test __hpux for use of FIOSSAIOSTAT and FIOSSAIOOWN
+	(USE_TERMIO): test __hpux for bsdtty/ptyio headers.
+	* krlogind.c: test __hpux for bsdtty/ptyio headers.
+	(doit): test __hpux for use of setpgrp2.
+	* krcp.c (main): test __hpux as well for remsh vs. rsh.
+
+	* krcp.c (des_write): Make sure the buffer for the encrypted data
+	is large enough. Only return an error in malloc fails.
+
+	* krsh.c (main): Always turn on anyport -A option.
+
+	* krlogind.c (ptsname): Declare if it's going to be used.
+
+	* krshd.c (main): Use basename of argv[0] for progname.
+
+	* login.c (dofork): On linux, TIOCNOTTY causes us to die on a
+	SIGHUP, so don't even try it.
+
+Sun Apr 21 12:52:35 1996  Richard Basch  <basch@lehman.com>
+
+	* krshd.c: If checksumming is required & ALWAYS_V5_KUSEROK is
+	defined, incorrect messages were being displayed for V4 clients.
+	Additionally, various errors were not being displayed with the
+	trailing newline.
+	Also, one could not specify -c in inetd.conf, because of the
+	variable initialization; initialization has been corrected to
+	allow either checksumming or ignoring the checksum.
+
+Sun Apr 21 00:30:28 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* krshd.c krlogind.c: Implement -i.  Rewrite error message having
+ 	to do with checksums.
+
+	* krshd.Mkrlogind.M : Document -i, remove documentation about
+ 	taking options from name of daemon.  Clean up checksum
+ 	documentation.
+
+	* krlogind.c (do_krb_login): Fix up error messages for checksums.
+  	Configuration errors are presented for situations where -c and -i
+ 	are used together, or where -4 and -c are used together.
+
+Thu Apr 18 19:48:47 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in: Fix spaces by converting to tabs.
+
+	* krlogind.c: Take patches from Doug Engert <deengert@anl.gov> to
+ 	allow login to work with vendor logins.  Also, fix packet-mode
+ 	bug; we have some hope of working on non-Solaris streams pty code.
+
+
+Wed Apr 17 13:46:57 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* configure.in (LOGINLIBS): Remove DECLARE_SYS_ERRLIST since it's
+		no longer necessary.
+
+	* krcp.c (verifydir, allocbuf, rsource, source, sink): Don't use
+ 		sys_errlist[]; just call error_message() instead, since we
+ 		depend on com_err anyway.
+
+	* krshd.c (recvauth): 
+	* krlogind.c (recvauth): Don't actually check the checksum unless
+ 		it is required.  Old (pre-beta 5) clients sent a checksum
+ 		of random garbage (such as their pid) which is impossible to
+ 		actually check on the server side.  (Grad student stupidity
+		strikes again.)
+		(fatalperror): Don't use sys_errlist[] to get the right
+		error message; just depend on com_err instead, since we're
+		using it anyway.
+
+	* krshd.c (doit): 
+	* krlogind.c (do_krb_login): Fix logic so that if checksums are
+	 	required, and the checksum is valid, don't syslog the
+	 	stupid warning message about "Checksums are only required
+	 	for v5 clients...."
+  	
+	* krcp.c, krshd.c, krlogind.c: Miscellaneous -Wall cleanups
+
+	* krlogind.c (getpty): Removed dead code.
+
+
+Tue Apr 16 11:33:33 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* krlogind.c kshd.c (main): Drop support for handling options in
+	 	rlogind's name.
+
+Sun Apr 14 03:41:49 1996  Sam Hartman  <hartmans@zygorthian-space-raiders.MIT.EDU>
+
+	* krlogind.c (fatalperror): Only declar sys_errlist if needed.
+
+	
+Sat Apr 13 17:47:36 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* krshd.c (doit): Use setsid instead of setpgrp if you have it.
+  	Note this doesn't work for Ultrix.
+
+	* krlogind.c (doit): Don't call setpgrp or setsid; let pty library do
+ 	that for us.
+
+Fri Apr 12 23:38:25 1996  Richard Basch  <basch@lehman.com>
+
+	* krlogind.c (cleanup): Destroy any forwarded credentials at the
+	end of the login session (they were placed in an unusual location
+	anyway, so the chance that someone will be trying to reuse those
+	credentials is minimal)
+
+Thu Apr 11 00:22:51 1996  Richard Basch  <basch@lehman.com>
+
+	* kcmd.c: Cleaned up whitespace and removed commented & unused cruft
+
+	* krlogind.c, krshd.c: Allow the recvauth routine to find any key
+	in the keytab for which the user is trying to login.  The host may
+	be known as many names.  Additionally, for krlogind, clean up the
+	error handling for bad authentication (potential null dereference
+	and a misleading message because of the wrong authentication system
+	being used)
+
+Sun Apr  7 22:46:07 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krshd.c: Add an option -L to pass certain environment variables
+		to the client.
+
+Wed Apr  3 17:09:19 1996  Richard Basch  <basch@lehman.com>
+
+	* krlogind.c: Under Solaris, when the connection pipe goes away,
+		zero bytes are returned.  Since we are using blocking
+		read calls, and the net_read function deals with
+		interrupted/resumed reads, consider zero bytes to be
+		be a terminated connection, so as not to spin.
+
+Mon Apr  1 10:12:44 1996  Richard Basch  <basch@lehman.com>
+
+	* loginpaths.h: Leading/trailing colons should not be there based
+	on the variable usage in the code.  Also, the tests for Solaris
+	were incorrect.
+
+Fri Mar 29 16:22:18 1996  Richard Basch  <basch@lehman.com>
+
+	* kcmd.c, krlogin.c, krsh.c, krcp.c:
+		Allow for a proxy forwarder to be specified
+
+Sat Mar 23 17:20:00 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krcp.c (des_write): Use krb5_net_write instead of write, because
+ 	most parts of rcp that call this code ignore the return value and
+ 	we want to reblock properly.
+
+	* krshd.c (doit): Don't use non-blocking IO; it is unnecessary and
+ 	may cause problems.
+
+Fri Mar 22 13:27:40 1996  Richard Basch  <basch@lehman.com>
+
+	* krshd.c: use the library routines to do v4 to v5
+	principal translation, for a more accurate representation.
+
+Wed Mar 20 19:36:21 1996  Richard Basch  <basch@lehman.com>
+
+	* krlogind.c: use the library routines to do v4 to v5
+	principal translation, for a more accurate representation.
+
+Tue Mar 19 20:11:28 1996  Richard Basch  <basch@lehman.com>
+
+	* kcmd.c (ruserok): declare the function as taking const char *
+	instead of char * (Solaris 2.5 refuses to compile it, otherwise).
+
+Tue Mar 12 23:42:50 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Use AC_HEADER_STDARG.
+
+Tue Mar 12 17:52:08 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krshd.c (doit): For encrypted rcp, fix logic in determining
+		executable to run. 
+
+Mon Feb 26 03:28:44 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: call USE_ANAME.
+
+Sun Feb 25 18:50:45 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krlogind.c (v5_des_read): Fix server side of bug in detecing eof
+        on the network connection.  Same as client change: v5_des_read
+        needs to return 0 if read returns <= 0, notjust a strict
+        inequality.
+
+Mon Feb 12 22:41:06 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kcmd.c (kcmd): Fix lint flame (added missing cast).
+
+Fri Feb  9 21:43:50 1996  Sam Hartman  <hartmans@hartman.mit.edu>
+
+	* krsh.c (main): Only print secure_message if encrypt_flag set.
+
+Fri Feb  9 20:18:48 1996  <hartmans@mit.edu>
+
+	* krlogind.c (recvauth): Fix v4 incompatability created by
+        checksum code; if using v4, don't try to verify a v5 checksum.
+
+Fri Feb  2 16:10:56 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in (save_path): Look for "ucb" varients in
+	/usr/athena/bin if --enable-athena specified.
+
+	* krsh.c krlogin.c krcp.c (try_normal): If --enable-athena, don't
+	quit just because we are encrypted.
+
+Thu Feb  1 00:09:13 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* rcp.M: Fix typo.
+
+	* krcp.c (des_write): If rcp tries to write to stdin, redirect it
+        to stdout.  That way it works with pipes; the right thing is for
+        rcp to not try and do this, but introducing remread and remwrite
+        as variables is significantly more work for only slightly better
+        code.
+	(main):  Use rsh encryption; not user-to-user. Note that we still
+	support the answer_auth mechanism for incoming connections
+	so older clients work, but this is depricated.
+	(send_auth): expunged with pleasure; answer_auth should go in a
+	a version or two.
+
+Wed Jan 31 16:24:50 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krsh.c (main): Print SECURE_MESSAGE when appropriate.
+
+	* krshd.c (doit): Fork and handle pipes either if stderr signal
+        processing is enabled *or* encryption is enabled.  Rsh always
+        enables stderr, but rcp won't.
+	(SECURE_MESSAGE): Moving to client where it belongs, so the stderr
+	channel doesn't get corrupted for rcp.  Besides, the client can
+	determine if it is talking to a tty and only print this message to
+	a tty.
+
+	* krlogind.c (recvauth): Pas ccache to rd_and_store_for_creds
+
+	* krshd.c (recvauth): Pass address of ccache to rd_and_store_for_creds
+	(ccache): new global variable.
+	(cleanup): Destroy ccache if we have one.
+	(doit): Destroy cache on normal terination.
+
+	* forward.c (rd_and_store_for_creds): Take a pointer to a ccache;
+        we should provide the caller with a way of destroying forwarded
+        credentials.
+
+Tue Jan 30 17:56:49 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krshd.c (envinit): Expand to have space KRB5_CCNAME
+	(doit): Put krb5_ccname at the end of envinit; this is
+	handled differently that other variables, because TZ may or may not
+	beset, so our position cannot be fixed.
+
+
+Sat Jan 27 18:40:31 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* kcmd.c (kcmd): We no longer need F_SETOWN as nothing in appl/bsd
+        handles oob data with signals any more.
+
+Fri Jan 26 00:37:23 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krlogin.c (reader): Deal with exceptions even while writing.
+	(reader): Fix bogus select bug; actually select on writing
+
+Wed Jan 24 00:34:42 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krlogind.M krshd.M: Update to document new options.
+
+	* Makefile.in (install): Install as kshd and klogind not krshd and
+ 	krlogind.
+
+	* krshd.c (main): Use krlogind-style options (-54kce)
+
+	* krlogind.c (main): Change option parsing  to support new format.
+	(do_krb_login): Use auth_ok and auth_sent masks instead of passed_*
+
+Tue Jan 23 18:10:55 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krshd.c (recvauth): Use the correct username in strlen call for
+        allocating chksumbuf.
+
+	* krlogind.c (recvauth): Code to copy checksum verification code.
+
+
+Mon Jan 22 15:14:11 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krshd.c (recvauth): Update to expect port in checksum.
+
+	* kcmd.c (kcmd): Include port in string of checksumed data to
+ 	distinguish between encrypted and unencrypted rlogin.
+
+
+Mon Jan 22 18:14:05 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krcp.c: Use KRB5_STDARG_P.
+
+	* configure.in: Add KRB5_CHECK_PROTOS for prototyps definitions.
+
+
+Fri Jan 19 10:45:29 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krshd.c (recvauth): Verify checksum against command line and
+	remote user.
+	(recvauth): Fix accidental memory leak with authenticator and fix
+	include correct username in checksum
+
+	* kcmd.c: Send authenticator with checksum of command line and
+	remote user.
+
+	* krlogin.c (des_read): Return 0 or -1 on close/error respectively.
+
+Wed Jan 17 15:14:33 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krlogin.c (reader): Use select to find out-of-band data, not signals.
+	(oob): No longer a signal handler; just a function.
+	(writer): get rid of copytochild setup as sigurg no longer needed
+	(main): Don't block SIGURG
+	* configure.in :  Include sys/time.h check
+
+Mon Jan 15 16:16:07 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* login.c (main): ttyslot usable here as well
+
+	* krlogind.c (doit): update_utmp can use ttyslot.
+
+Thu Jan 11 12:40:08 1996  Ezra Peisach  (epeisach@paris)
+
+	* krsh.c, krlogin.c: (main): Ultrix cc does not support automatic
+		aggregate initiailzation of structures. 
+
+Thu Jan 11 11:27:04 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krcp.c (error): Convert to use varargs.
+
+	* configure.in: Check for stdarg.h
+
+Wed Jan 10 21:26:20 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kcmd.c (getport): Clear the sin structure to be zero.  (From
+		Doug Engert.)
+
+	* krsh.c (main): Added code to default port to 544 if service not
+	        found.  (From Doug Engert.)
+
+	* krlogin.c (main): Added code to default port to 543 or 2105 if
+	        service not found.  (From Doug Engert.)
+
+	* login.c (main): Save KRB5CCNAME environment variable, which may
+	        have been set by forward.c.  Add code for SGI to set
+	        environment for its /etc/TIMEZONE (untested).  Don't print
+	        MOTD twice on Suns, added #ifdef NO_MOTD.  (Patches from
+		Doug Engert).
+
+	* kcmd.c: Removed extern global of krb5_kdc_req_sumtype, which
+		wasn't being used anyway.
+
+Tue Jan  9 22:51:16 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* forward.c (get_for_creds): Removed no longer used function.
+
+	* kcmd.c (kcmd): Convert from using get_for_creds() from forward.c
+		to using the official library routine, krb5_fwd_tgt_creds().
+
+Fri Dec 22 17:42:11 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* login.c (main): If HAVE_SHADOW is defined, and no shadow
+		password entry is availble, try using the password entry
+		in the password file.
+
+Tue Dec 19 17:11:37 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kcmd.c: Also include unistd.h, if it's available.
+
+Tue Dec  5 20:44:39 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Use krb5util library.
+
+	* login.c (main): Change two-argument call to syslog to three
+		arguments to handle screw cases in hostnames.
+
+Fri Dec  1 17:25:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* login.c (main, dofork): Applied patch from Scott Schwartz
+	        <schwartz@galapagos.cse.psu.edu>
+
+		Under SunOS, and maybe other systems, there is a a problem
+		with krlogind.c and a similar problem with login.c as
+		distributed with K5.5.
+
+		The bug is that rlogind forks a child but retains a
+		controlling tty.  If the child is in the same process
+		group as the parent, which is will if you don't use a job
+		control shell (chsh /bin/rc), keyboard signals will kill
+		the daemon.  telnetd dissociates itself properly, but then
+		login.krb5 waits for the shell to finish, but login.krb5
+		has the same ctty as the shell and is in the same process
+		group, so it has the same problem.
+
+		In BSD you used to be able to give up your ctty at will,
+		but SunOS seems to have setsid as the only mechanism to
+		perform that action, and setsid can only succeed in
+		limited circumstances.  Rlogind ought to be fixed to
+		behave more like telnetd, but independent of that,
+		login.krb5 needs to be patched if kerberos is to work
+		properly under SunOS.
+
+Sun Nov 12 12:39:23 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krlogind.c (doit): Clear iextn for NetBSD and other 4.4-based
+        systems so that ctrl-o isn't special.
+
+Sat Oct 21 17:33:37 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* login.c (main): Don't set LOGNAME twice.
+
+Sun Nov 12 04:44:50 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* krshd.c (doit): drag TZ= from parent environment into envinit to
+	pass to child.
+	(envinit, TZENV): add one more slot for optional TZ, and mark it.
+
+Thu Nov  2 16:16:47 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krlogin.c, krcp.c, krsh.c (main): If invoked with -D port, do
+		not die if entry is missing from /etc/services.
+
+Mon Oct 16 17:27:43 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* login.c (main): Don't print warning about no tickets obtained if
+	we didn't ask for a password.  Also, define LOGNAME for so sysvish
+	systems are happy.  Patch from ramus@nersc.gov.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * krcp.c, krlogin.c, krlogind.c, krsh.c, krshd.c : 
+		s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Sun Aug 27 15:35:04 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rlogin.M: Document -f and -F options.
+
+Mon Aug  7 17:32:29 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krlogind.c: Close the write side of the syncpipe in the parent
+        so we get SIGPIPE if child dies. 
+
+	* login.c (main): Use new interface to pty_update_utmp
+
+	* configure.in (LOGINLIBS): Check for utmp.h and utmpx.h.
+
+	* krlogind.c (doit): Use new format for pty_update_utmp
+	* Include utmp.h because libpty.h no longer does.
+
+Fri Aug  4 00:50:41 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* krlogind.c: don't include utmp.h, since libty.h grabs it.
+
+Wed Aug  2 13:06:02 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krlogind.c (main): call pty_init()call pty_init()
+
+Tue Aug  1 08:43:22 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in :  Remove references to logutil.c and logutil.o
+
+
+	* krshd.c (doit): Replace logwtmp with pty_logwtmp
+
+	* login.c (main): use pty_update_utmp not update_utmp
+
+	* logutil.c: Removed because all its functionality is incorperated
+        into libpty.
+
+	* krlogind.c (doit): Pass length of line to pty_getpty
+
+Mon Jul 31 17:07:59 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* login.c (main): Don't call TIOCSETD under Posix.
+	 * Include iexten in terminal flags.
+
+
+	* krlogin.c:  Don't include termio.h here either.
+
+	* login.c: Remove special casing of AIX to include termio.h; it
+        breaks almost all terminal handling, because it's the
+        compatibility file for applications written for the RT.  Instead,
+        just define CNUL if not already defined by ttychars.h
+
+
+Sat Jul 29 04:37:33 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* configure.in: Don't link with -lkadm
+
+
+Fri Jul 28 16:49:02 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (LOCAL_LIBRARIES): include -lpty; also included in
+        DEPLOCAL_LIBRARIES.
+
+	* krlogind.c (doit): Use pipe for synchronization so pty can be
+	opened in slave.  Use libpty for pty handling.
+	(cleanup):  Use pty_cleanup to do most work.
+
+Thu Jul 27 15:02:03 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krshd.c - Check for interrupted select.  Should fix bug #1555.
+
+
+Thu Jul 13 17:49:54 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in : Short circuit the streams test for AIX to false
+        because AIX strops.h trashes definition of _IO from sys/ioctl.h.
+        I think this is fixed in AIX4, so the test is only bypassed for
+        AIX3.
+
+Tue Jul 11 12:50:16 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krlogind.c (getpty): Use ptsname before ttyname; it has a higher
+        chance of doing what we want.
+
+Fri Jul 7 15:40:42 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explcitit library handling.
+	* configure.in - Add USE_<mumble> and KRB5_LIBRARIES.
+
+Wed Jul  5 20:03:37 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krcp.c, krlogin.c, krlogind.c, krshd.c, login.c: Remove
+		declaration of errno altoghether.  "extern int errno;" is
+		always wrong.
+
+	* login.c (main): Don't use the TIOCLSET ioctl unless we're not
+		using POSIX_TERMIOS.  Don't just blindly set the file
+		status flags to 0.  Instead, do a fcntl(0, F_GETFL), and
+		then reset the nonblocking flags.
+
+Sun Jul  2 19:48:27 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krcp.c: make errno extern
+
+	* krshd.c: errno should be extern so it doesn't mask the libc
+        definition in AIX.
+
+Tue Jun 27 23:50:56 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* krlogin.c: don't redeclare noltc, defltc if we happen to have
+		TIOCGLTC in addition to POSIX_TERMIOS
+
+Tue Jun 27 16:18:49 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - When checking number/type of arguments to {get,set}pgrp
+		attempt to set __STDC__ in a vain attempt to ensure that we
+		get function prototype checking turned on.  OSF/1's native
+		compiler didn't really care what's passed as arguments unless
+		__STDC__'s set.
+	* krcp.c - Change usage of BUFSIZ to RCP_BUFSIZ.  Remove & from in
+		front of array.  It's redundant.
+	* krlogin.c - Change usage of BUFSIZ to RLOGIN_BUFSIZ.  Add signal
+		name parameter to signal handlers to conform to prototype.
+	* krlogind.c - Change usage of BUFSIZ to RLOGIND_BUFSIZ.  Cast 4th
+		argument to setsockopt(2) to be const char *.
+	* krsh.c - Change usage of BUFSIZ to RSH_BUFSIZ.  Cast 4th argument
+		to setsockopt(2) to be const char *.
+	* krshd.c - Change usage of BUFSIZ to RSHD_BUFSIZ.
+
+Thu Jun 22 14:36:46 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Change AC_HAVE_HEADERS with AC_CHECK_HEADERS, and
+		check for string.h as well.
+
+	* krsh.c: Don't include ext-proto.h; move the #include of the
+		header files which we actually needed into krsh.c, using
+		the autoconf standard define's.
+
+Wed Jun 21 17:29:27 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* login.c: Change RETSIGTYPE to krb5_sigtype to be consistant.
+
+	* configure.in (LOGINLIBS): Add KRB5_SIGTYPE to declare krb5_sigtype.
+
+Tue Jun 20 13:00:25 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* krlogin.c: HAS_STDLIB_H -> HAVE_STDLIB_H
+
+Mon Jun 19 13:34:23 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* login.c - Change setluid call to check for luid and then set it if
+		it fails, also make this logic conditional under HAVE_SETLUID.
+	* configure.in - For OSF/1 systems where libsecurity is present, set
+		HAVE_SETLUID.  We'll need to determine similar tests for other
+		extended security systems that we are to support in the future.
+
+
+Thu Jun 15 17:32:20 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+		Also, remove DBMLIB, it was not used. Also, for K4, use
+		KRB4_LIB and KRB4_CRYPTO_LIB, these were
+                split out.
+	* configure.in - Remove dbm library checks, these are no longer needed
+		with the Berkeley database code.  Also, add shared library
+		usage check.
+
+Sat Jun 10 22:56:10 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* forward.c, kcmd.c, krcp.c, krlogind.c, krshd.c:
+		krb5_auth_context redefinitions
+
+Fri Jun  9 18:26:30 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed May 31 17:16:44 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* loginpaths.h: #ifdef ultrix => #ifdef __ultrix
+
+Sun May 21 16:36:39 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* loginpaths.h: Add NetBSD paths.
+
+	* login.c: Define TAB3 to 0 if non existant
+
+	* krlogin.c (mode): ifdef code based on TABDLY existing on
+		machine. (netbsd lacks this).
+
+	* krcp.c: Declare sys_errlist only if needed by the OS.
+
+	* configure.in: Add DECLARE_SYS_ERRLIST
+		Check for libcrypt defining the function crypt
+
+Mon May 15 10:43:30 1995    <tytso@rsx-11.mit.edu>
+
+	* login.c (main): Only try to use TIOCSETD if it is defined
+		(instead of relying on _IBMR2 *not* being defined).
+
+		Only try to use TIOCNXCL if it is defined.
+
+	* krcp.c: If setreuid() is emulated using setresuid(),
+		#define HAVE_SETREUID so it gets used.
+
+Sat May 13 08:59:38 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krshd.c (recvauth): Use krb5_auth_con_genaddrs to set the port
+		on the connection so that credential forwarding works.
+
+Tue May  9 08:17:18 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* krshd.c (main): Cast a sockaddr_in * to sockaddr * in call to
+		accept. 
+
+	* kcmd.c: Add <stdlib.h>
+
+	* krcp.c: Add <stdlib.h>.
+
+Sat May  6 18:12:37 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krcp.c (answer_auth): Added const declaration to filenames.
+
+Fri May 05 09:16:16 1995  Chris Provenzano (proven@mit.edu)
+
+	* krcp.c (answer_auth()): Requires two new args that are passed
+		from the command line. The first -c is to pass the filename
+		of the remote credential cache. The second -C is to pass
+		the filename of the remote krb5.conf file.
+
+Thu May 04 23:53:23 1995  Chris Provenzano (proven@mit.edu)
+
+	* krcp.c (answer_auth()): Don't destroy the credential cache.
+
+Wed May 03 20:10:39 1995  Chris Provenzano (proven@mit.edu)
+
+	* krcp.c (answer_auth()): Set auth_context = NULL before using it.
+
+Wed May 03 03:30:51 1995  Chris Provenzano (proven@mit.edu)
+
+        * krlogind.c, krshd.c: (krb5_compat_recvauth()): 
+		No longer needs the rc_type arg.
+
+Tue May  2 22:12:39 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krcp.c (main): Don't try to play uid swapping games if the
+		effective uid is not zero.
+
+	* kcmd.c (kcmd): Bug fix to jik's bug fix.  (Caused by our code
+		drift since jik's changes went in, and not sufficiently
+		careful checking of jik's patches before applying it.)
+
+Mon May 01 15:56:32 1995  Chris Provenzano
+
+	* kcmd.c (kcmd()): Bug fixes from jik.
+
+	* krlogind.c (recvauth()): Changes to auth_context to better 
+		support full addresses, for rd_cred() and friends.
+
+Sat Apr 29 01:26:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (login.krb5): Link the libraries twice due to
+		circular dependency in the libraries.  (read_password in
+		libdes425.a depends on krb5_read_password in libkrb5.a)
+
+Fri Apr 28 20:33:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* login.c (main): Don't use setreuid() to play games with the real
+		uid, since not all systems have setreuid().  This method
+		of communicating to in_tkt what the correct owner of the
+		ticket file is completely broken, anyway.  We skip the
+		setreuid() entirely, and then chown the ticket file to the
+		correct owner and group afterwards.
+
+Fri Apr 28 17:59:19 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (KLIB): include KRB4_LIB directly, to satisfy both
+	versions of the dependencies.
+
+Fri Apr 28 16:55:14 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in	- change position of KRB4_LIB for krshd and krlogind
+			  so that it links correctly for both --with-krb4
+			  and --with-krb4=/usr/athena.
+
+Fri Apr 28 16:12:57 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in (PATH): use internal AC_PROG_ECHO_N because change
+	in path might change behavior of echo (example: solaris, native
+	shell, with GNU echo (-n) in user path, but only Solaris echo (\c)
+	in path here.)
+
+Fri Apr 28 07:52:45 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* login.c: Lots of lint cleanup; declare functions before they
+		are used, add appropriate return types (int or void)
+		to functions as necessary, etc.
+	
+Thu Apr 27 21:44:17 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* login.c: Remove definition of krb_err_txt. krb.h defines it.
+
+Thu Apr 27 17:41:06 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (krshd, login.krb5, krlogind): KRB4_LIB needs to
+	appear before KLIB since it uses des425.
+
+Thu Apr 27 14:36:54 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (LOCALINCLUDE): get kerberosIV headers for login.c
+	(login.krb): link against krb4 libs.
+	* configure.in: check AC_CONST so it works.
+
+Thu Apr 27 13:54:21 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: use WITH_KRB4 as-is.
+	* Makefile.in (krshd, krlogind): use KRB4_LIB directly.
+
+Thu Apr 27 01:09:19 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krcp.c (answer_auth): Should not call krb5_cc_close after
+		krb5_cc_destroy. (encrypted rcp failed).
+
+	* krlogind.c (main): -S option was not getting a keytab. (passing
+		a char * to krb5_compat_recvauth).
+
+	* krshd.c (recvauth): extract the client principal from ticket
+		before calling krb5_kuserok on a NULL principal.
+		(main): -S option was not getting a keytab (passing a char *).
+
+	* krcp.c: (main): Missing htons on port number when specified on
+		command line.
+
+Wed Apr 26 21:09:34 1995  Chris Provenzano  (proven@mit.edu)
+
+	* kcmd.c (kcmd()) : Don't use hp->h_name use host_save instead.
+
+Wed Apr 26 17:43:08 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* logutil.c (EMPTY): linux has UT_UNKNOWN, not EMPTY.
+
+Wed Apr 26 09:41:35 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krlogind.c (main): LOG_AUTH in openlog arguments in wrong place.
+		(recvauth): Do not copy principal on a V4 request. The
+		ticket portion is not set by krb5_compat_recvauth for these.
+
+	* configure.in: Check for libutil. Under OSF/1, logwtmp is stored
+		there. 
+
+Wed Apr 26 07:19:18 1995  Chris Provenzano  (proven@mit.edu)
+
+	* krlogind.c (doit()) : If TIOCOTTY is defined unset the 
+		controlling tty before setting it to another tty.
+
+Tue Apr 25 21:23:28 1995  Chris Provenzano  (proven@mit.edu)
+
+	* forward.c (rd_and_store_for_creds()) : Rewritten to use
+		auth_context and the new krb5_rd_creds().
+	* forward.c (get_for_creds()) : New function replacing
+		krb5_get_for_creds() and uses auth_context and new
+		krb5_mk_creds() routine.
+	* kcmd.c (kcmd()): Use new get_for_creds() routine.
+	* krlogind.c (recvauth()): Use new rd_and_store_for_creds() routine.
+
+Sat Apr 22 00:42:22 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rlogind (main, doit): The variable krb5_override_default_realm
+		is obsolete.  Use the krb5_set_default_realm function instead.
+
+	* krshd.c (main, doit): The variable krb5_override_default_realm
+		is obsolete.  Use the krb5_set_default_realm function instead.
+
+Fri Apr 21 21:11:17 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krshd.c: Add #include for <sys/stat.h>, which is now needed.
+
+Fri Apr 21 17:18:57 1995  Mark Eichin  <eichin@cygnus.com>
+
+	rlogin testing changes from ian@cygnus.com.
+
+Fri Apr 21 17:13:48 1995  Mark Eichin  <eichin@cygnus.com>
+
+	More changes from ian@cygnus.com to support testing.
+
+Fri Apr 21 14:07:15 1995  Mark Eichin  <eichin@cygnus.com>
+
+	Added Ian's changes with minor tweaks. These are used by the testsuite.
+
+Fri Apr 07 15:46:54 1995 Chris Provenzano (proven@mit.edu)
+
+	* configure.in, krlogind.c, krsh.c, krshd.c, login.c, logutil.c.
+		A bunch of patches from Ezra to get BSD to work on
+		The Alpha that looked reasonable.
+
+Mon Mar 27 07:56:26 1995 Chris Provenzano (proven@mit.edu)
+
+        * krcp.c (send_auth()): Use new calling convention for krb5_rd_req().
+
+        * krshd.c (recvauth()): Use new calling convention for 
+		krb5_compat_recvauth().
+
+        * krlogind.c (recvauth()): Use new calling convention for 
+		krb5_compat_recvauth().
+
+Fri Mar 24 15:04:25 1995  Ian Lance Taylor  <ian@cygnus.com>
+
+	* krlogind.c (srvtab): New global variable.
+	(krb5_override_default_realm): Declare.
+	(ARGSTR): Add "S:M:L:" to Kerberos version.
+	(login_program): New global variable.
+	(main): Handle -S, -M, and -L arguments.  Call SO_REUSEADDR on
+	socket if debug_port set.
+	(doit): Use login_program instead of LOGIN_PROGRAM.
+	(recvauth): Pass srvtab to krb5_compat_recvauth.
+	* krlogind.M: Document -S, -M, and -L.
+
+Fri Mar 24 15:04:25 1995  Ian Lance Taylor  <ian@cygnus.com>
+
+	* krcp.c (forcenet): New global vraiable.
+	(main): Accept -D and -N arguments.  Pass Kerberos realm to remote
+	rcp execution.
+	(hosteq): If -N specified, always return 0.
+	* rcp.M: Document -D and -N.
+	* krshd.c (ARGSTR): Add "P:" to KERBEROS version.
+	(kprogdir): New global variable.
+	(main): Handle -P.
+	(path): Remove global variable.
+	(path_rest): Remove explicit size.
+	(envinit): Use 0 instead of path.
+	(PATHENV): define.
+	(doit): Use kprogdir variable instead of KPROGDIR macro when
+	setting path.  Build path in allocated memory rather than using a
+	fixed size array.  If the command starts with "rcp ", force use of
+	kprogdir/rcp if it exists.
+	* krshd.M: Document -P.
+
+Thu Mar 23 18:18:31 1995  Ian Lance Taylor  <ian@cygnus.com>
+
+	* krshd.c (ARGSTR): Add S:M:A to KERBEROS version.
+	(srvtab): New global variable.
+	(krb5_override_default_realm): Declare.
+	(main): Handle -S, -M and -A arguments.  Call SO_REUSEADDR on
+	socket if debug_port set.
+	(doit): If -A used, allocate a random port for the stderr stream,
+	rather than allocating a reserved port.  Don't call initgroups if
+	not changing the uid.
+	(recvauth): Pass srvtab to krb5_compat_recvauth.
+	* krshd.M: Document -S, -M, and -A.
+	* krsh.c (main): Accept -A, and pass it to kcmd.
+	* rsh.M: Document -A.
+	* kcmd.c (kcmd): Add new argument anyport.  If it is set, permit
+	any port for the stderr stream, rather than requiring a reserved
+	port.  Initialize ret_cred to NULL.
+	* krcp.c (main): Pass 0 for anyport to kcmd.
+	* krlogin.c (main): Pass 0 for anyport to kcmd.
+
+Thu Mar 23 23:23:25 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (krshd): Move $(K4LIB) after $(KLIB) so that if
+		we're using des425, the V5 crypto library can be picked up.
+
+	* configure.in: Use the correct path to find libdes425
+
+Thu Mar 23 20:22:57 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* logutil.c (update_wtmp): initialize ut from ent the way the V4
+	code did. Appears to handle SunOS case (when nearly all of the
+	ifdef's are off) correctly now.
+
+Tue Mar 14 16:08:08 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in, configure.in: Use the libdes425 library so that the
+		DES code doesn't get dragged in twice.
+
+	* krlogind.c: Include <sys/time.h> so that Linux can get the
+		FD_SET macros.
+
+	* kcmd.c (kcmd): Close the credentials cache when you're done with
+	        it.
+
+	* krlogind.c (doit): Always initialize the Krb5 error table.
+
+	* krlogind.c (main, doit): Minor type fixes to gethostbyname(),
+		accept().
+
+Tue Mar 14 12:30:23 1995  Chris Provenzano (proven@mit.edu)
+
+	* kcmd.c (kcmd()): Don't pass any data to sendauth() to be 
+		checksummed. The remote side doesn't check it anyway.
+
+Fri Mar 10 18:32:22 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kcmd.c (kcmd): Initialize ret_cred to zero so that in case of an
+		error, we don't try to free stack garbage.
+
+Fri Mar 10 11:09:34 1995  Chris Provenzano (proven@mit.edu)
+
+        * kcmd.c (kcmd()) Use new calling convention for krb5_sendauth().
+	* krcp.c () Use new calling convention for krb5_mk_req_extended().
+
+Thu Mar  2 12:26:29 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 11:54:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE and ISODE_DEFS, replace check
+		for -lsocket and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:41:04 1995  John Gilmore  (gnu at toad.com)
+
+	* forward.c, kcmd.c, krcp.c, krlogin.c, krlogind.c, krsh.c,
+	krshd.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Tue Feb 14 15:30:55 1995 Chris Provenzano  (proven@mit.edu)
+
+        * kcmd.c Call krb5_sendauth() and krb5_get_credentials() with 
+		new calling convention.
+
+	* krcp.c (answer_auth()) Call krb5_mk_req_extended90 with new 
+		calling convention.
+
+Fri Feb  3 11:51:55 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krcp.c (tgt_keyproc): Add keytype parameter to field.
+
+Mon Jan 30 07:58:16 1995  Chris Provenzano (proven@mit.edu)
+
+	* Removed all #include <krb5/crc-32.h> 
+
+	* Removed krb5_enctype argument passed to krb5_get_for_creds()
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+        * Removed all narrow types and references to wide.h and narrow.h
+
+Wed Jan 18 14:33:50 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krlogind.c (v4_des_read, v5_des_read): When reading length,
+	ignore everything before a leading zero (MSB first "reasonable"
+	value) to compensate for rlogin (mis)use of BSD-OOB data.
+	* krlogin.c (des_read): same code (in both versions of des_read.)
+
+Wed Jan 18 01:07:56 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: undo streams test. It turns out that we want sunos
+	to *fail* that test, since it doesn't have a streams PTEM module
+	anyhow.
+	* krlogind.c: don't include sys/tty.h and sys/ptyvar.h if we don't
+	HAVE_STREAMS already.
+	* krlogin.c: do the same thing.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+	* krsh.c (main): Use htons(debug_port).
+
+Wed Jan 11 01:25:09 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* logutil.c (update_wtmp): declare missing variables if
+	HAVE_SETUTENT isn't set.
+	(update_utmp): declare tty at top of function.
+
+Tue Jan 10 19:43:18 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* krlogin.c (doit): use exit_handler for signal exits, don't use
+	exit directly.
+	(exit_handler): new function, avoids type collision from misusing
+	exit directly as a signal handler.
+
+Tue Jan 10 15:23:31 1995  Richard Basch  (probe@tardis)
+
+	* configure.in: Streams test needs to include sys/types.h
+
+	* krsh.c: Include sys/time.h (linux)
+
+Mon Jan  9 21:48:54 1995  Theodore Y. Ts'o  (tytso@dcl)
+    
+    	* kcmd.c, krlogin.c, krcp.c: Always include fcntl.h, and never
+		sys/fcntl.h.
+
+	* krshd.c: Always define the Kerberos V4 data structures.
+
+Tue Jan  3 16:54:02 1995  Richard Basch  (probe@tardis)
+
+	* krshd.c
+	  	Cleaned up comments
+
+	* krsh.c
+	  	Removed debugging statement
+
+	* kcmd.c
+	  	Removed old sgi code (it has POSIX_SIGNALS).
+
+Mon Jan  2 12:35:18 1995  Richard Basch  (probe@tardis)
+
+	* krsh.c
+	* krshd.c
+	  	Added encrypted rsh support.
+		It still isn't entirely secure; as the command-line could
+		be spoofed by an active attack, but the data sharing is...
+
+	* krlogind.c
+	  	Ultrix doesn't have a fully functional POSIX termios.
+
+	* krshd.c
+	  	Cleaned up some of the #ifdef's and code duplication.
+		Fixed decl. of return variable for getopt() [int not char]
+
+Fri Dec 30 18:35:50 1994  Richard Basch  (probe@tardis)
+
+	* krlogin.c
+	  	Don't need: #ifdef _AIX, #undef _BSD, #endif
+
+	* Makefile.in
+	  	Fixed man page installation when build tree != source tree
+
+	* configure.in
+	  	No need to do the fcntl check
+		Changed GETPGRP_ONEARG detection (and assign it when it
+			takes one argument, not void).
+
+	* logutil.c
+	* login.c
+	  	Tidied up the code a bit.
+		Do not rely on NO_UT_TYPE (it has problems with AIX headers)
+
+	* krlogind.c
+	  	Tidied up the code a bit.
+	  	Set the controlling tty for Ultrix
+		Do not rely on NO_UT_TYPE (it has problems with AIX headers)
+
+Thu Dec 29 10:12:48 1994  Richard Basch  (probe@tardis)
+
+	* krlogind.c
+	  	Conditionalize grantpt/unlockpt on HAVE_GRANTPT (not just Sun)
+	  	Conditionalized references to ut_type and ut_pid.
+		Try all the methods for getting a pty...
+
+	* logutil.c
+	  	Conditionalized references to ut_type and ut_pid.
+
+	* configure.in
+	  	Conditionalize grantpt/unlockpt on HAVE_GRANTPT
+		Corrected a minor syntactical error with extraneous "],"
+
+Thu Dec 29 01:38:17 1994  Richard Basch  <probe@k9>
+
+	* krlogind.c:
+	  	Error checks for Solaris tty setup routines (grantpt/unlockpt)
+		Commented out the OOB code, as it causes problems currently.
+		Cleaned up some of the #ifdef's for logging incoming users
+		Removed extraneous declaration of malloc()
+		Pass a "" for the hostname rather than NULL to update_utmp.
+		Some additional cosmetic changes.
+		Included/excluded SYSV code (SYSV is not defined anywhere)
+
+Wed Dec 28 14:59:58 1994  Richard Basch  (probe@tardis)
+
+	* krlogin.c
+	* krlogind.c
+	* krsh.c
+	* krshd.c
+	  	Corrected the arguments to select, based on sizeof fd_set.
+		Converted what remained to use FD_* macros, instead of bitshift
+
+	* login.c
+	  	Changed uid_type to uid_t, gid_type to gid_t
+		Added shadow password support
+		Always use cfset*speed when POSIX_TERMIOS is defined
+
+	* configure.in
+		Changed the PATH for looking for BSD r* commands
+		Use AC_TRY_LINK instead of AC_TRY_COMPILE for the setenv test.
+		Cache results of compile/link tests.
+		Added shadow password support.
+	  	Don't bother checking for sys/stream.h; done elsewhere
+		Look for the function ptsname.
+
+	* logutil.c
+	  	Search to the proper position in the utmp/utmpx files.
+	  	Corrected arguments for the utmpx routines.
+
+	* krlogind.c
+	  	Revamped the tty setup routines.
+
+Tue Dec 27 14:42:15 1994  Richard Basch  (probe@tardis)
+
+	* krlogin.c
+	  	Cleaned up some of the includes
+
+	* krlogind.c
+	* krshd.c
+	* logutil.c
+	* login.c
+	  	Revamped the utmp/wtmp handling routines
+
+	* Makefile.in
+	  	Fixed the "krlogin" program define for "krsh"
+
+	* configure.in
+		Changed the HAVE_STREAMS macro to not try <sys/tty.h>
+		Corrected the text for the setpgrp arguments check
+
+Tue Dec 27 06:15:42 1994  Richard Basch  (probe@tardis)
+
+	* krlogind.c
+		Use the file descriptor macros (eg. FD_SET) to handle fd arrays
+		Change #ifdef STREAMS to #ifdef HAVE_STREAMS
+		Started to add SYS-V utmp handling
+		Ripped out the old termio code.
+		Include <unistd.h> and <stdlib.h> where available.
+
+	* configure.in
+		Combined KRB5_UT* macros into CHECK_UTMP, with more checks.
+		Changed obsolete AC_COMPILE_CHECK to use newer macros.
+
+Mon Dec 26 13:51:20 1994  Richard Basch  (probe@tardis)
+
+	* Makefile.in
+	* configure.in
+	* krcp.c
+	* krsh.c
+	* krlogin.c
+	Removed the hard-coded paths for the BSD rlogin/rcp/rsh programs.
+	Let "configure" find the programs for us...
+
+Mon Dec 19 15:09:57 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krcp.c (des_write):
+	* krlogin.c (des_write):
+	* krlogind.c (v5_des_write): Fix byte swapping code (Missing shift
+		instructions).
+
+	* krlogind.c (v4_des_read, v4_des_write): Fixed byte swapping code
+		so that V4 des compatibility works on 64 bit
+		architectures.
+
+Fri Nov 18 01:19:13 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (install): add install rules for krlogind.M,
+	krshd.M, rlogin.M, rcp.M, rsh.M. (Section numbers are explicit,
+	and this should probably be changed.)
+	(from Ted Lemon <mellon@ipd.wellsfargo.com>
+
+Fri Nov 18 01:10:34 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: use new macros KRB5_UTPID, KRB5_UTTYPE, and
+	KRB5_UTHOST (from epeisach).
+
+Wed Nov 16 11:45:01 1994  Richard Basch  (probe@tardis)
+
+	* krlogin.c:
+	If the system includes a SA_RESTART signal flag, use it.
+	We want to be able to resume the read() system call after
+	a SIGURG comes.
+
+Fri Nov 11 00:53:57 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* forward.c (mk_cred, rd_cred): Move mk_cred and rd_cred to
+		libkrb.a.
+
+Tue Nov  8 23:52:58 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krshd.c (setpgrp): Defining setpgrp(a,b) to setpgrp() if
+		SETPGRP_TWOARG is not set can cause infinite macro
+		recursion on some C preprocessors.  Fix by putting the
+		#ifdef for SETPGRP_TWOARG where setpgrp is actually
+		called, instead of trying to redefine setpgrp().
+
+Mon Nov  7 21:22:00 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add check for stdlib.h
+
+	* configure.in: Remove unused check for HAVE_GETDTABLESIZE
+		(especially since we replace it with AC_REPLACE_FUNCS
+		later!)
+
+	* getdtablesize.c:  Use POSIX method of obtaining fd table size,
+		if available. 
+
+Wed Nov 02 22:21:00 1994  Richard Basch  (probe@tardis)
+
+	* configure.in:
+	Moved POSIX signal check to aclocal.m4, and calls it (CHECK_SIGNALS)
+	Added POSIX setjmp check (CHECK_SETJMP).
+	Added checks for waitpid and setsid functions.
+
+	* kcmd.c:
+	Include <signal.h> not <sys/signal.h>.
+	Don't bother declaring sigmask when POSIX_SIGNALS is set.
+	
+	* krcp.c:
+	Replaced the conditionalized BITS64 code with more portable code.
+	Use mode_t instead of int, for file modes.
+	Use waitpid, instead of wait, where available (HAVE_WAITPID).
+	Added POSIX signal handling (POSIX_SIGNALS).
+
+	* krlogin.c:
+	Include <unistd.h> and <stdlib.h> if available
+	Replaced the conditionalized BITS64 code with more portable code.
+	Use cfgetospeed() if POSIX_TERMIOS is defined.  It was already being
+		used, so there is no need to use two methods.
+	Use waitpid, instead of wait, where available (HAVE_WAITPID).
+	Added POSIX setjmp handling (POSIX_SETJMP)
+	Added POSIX signal handling (POSIX_SIGNALS).
+
+	* krlogind.c:
+	Added POSIX signal handling (POSIX_SIGNALS).
+	Corrected an error in the arguments to chmod().
+	Call setsid() if HAVE_SETSID is defined.
+	Try not conditionalizing on __alpha; use other #ifdef's.
+	Replaced the conditionalized BITS64 code with more portable code.
+
+	* krsh.c:
+	Added POSIX signal handling (POSIX_SIGNALS)
+
+	* krshd.c:
+	Declare and manipulate the file descriptor arrays properly,
+		rather than bit shifting and passing them to select as
+		(long *).  Some systems (eg. AIX) declare them to be structs.
+	Added POSIX signal handling (POSIX_SIGNALS)
+
+	* login.c:
+	Include <unistd.h> and <stdlib.h> if available
+	Added POSIX setjmp handling (POSIX_SETJMP)
+	Added POSIX signal handling (POSIX_SIGNALS)
+	Use waitpid, instead of wait, where available (HAVE_WAITPID).
+
+	* logutil.c:
+	Don't redeclare time(); it may conflict with the system header files.
+	Include <unistd.h> first.
+
+Thu Oct 27 20:07:03 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* login.c (main): if CSTATUS is missing, don't set c_cc[VSTATUS]
+	(for sunos.)
+
+Thu Oct 27 16:12:19 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* krlogin.c (des_write): get rid of srandom, since seeding is done
+	directly in krb5_random_confounder. get rid of unused variables.
+	* krlogind.c (v4_des_write): use krb5_random_confounder
+	directly. get rid of unused variables.
+
+Thu Oct 27 14:50:40 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* login.c (main): if CDISCARD is missing, use CFLUSH instead.
+
+Thu Oct 27 14:47:41 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in: fix typo in "use streams interface" test (ttold.h
+	not ttyold.h)
+
+Thu Oct 27 14:31:17 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in: check for srand48, srand, and srandom.
+	* krlogind.c (v4_des_write): use the best available of the three
+	random number systems for padding (based on code from
+	lib/crypto/os/rnd_confoun.c.)
+
+Wed Oct 26 00:04:02 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krsh.c (main):
+	* krlogind.c (protocol, v5_des_read): Check for both EAGAIN in
+		addition to EWOULDBLOCK.
+
+Mon Oct 24 14:46:07 1994    (tytso@rsx-11)
+
+	* Makefile.in: The Kerberos V4 libraries must be linked in after
+		the V5 libraries; compat_recvauth pulls in the V4 routines.
+
+	* kcmd.c (kcmd): Don't free host_save; it's supposed to be
+		returned by kcmd to the caller!
+
+	* configure.in
+	* krlogin.c (des_write): Don't check for srand48 and then try to
+		define srandom to be srand48.  This breaks on machines
+		which have both srandom and srand48.  Instead, use
+		krb5_random_confounder; it will do the right thing.
+
+Wed Oct 19 12:36:47 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krlogind.c (protocol): Change yet another variable to be an
+		unsigned char.
+
+	* login.c (main): Add other termios c_cc initializations for the
+		ALPHA. 
+
+	* krlogind.c (protocol): Make protocol buffers be unsigned, since
+		we're comparing against unsigned data.
+
+Tue Oct 18 15:48:37 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in (HAVE_STREAMS): test for streams interface headers
+	in a way that fails on sunos but works on solaris.
+	* krlogin.c: use HAVE_STREAMS.
+	* krlogind.c: use HAVE_STREAMS, fix TIOCPKT_* test.
+
+Tue Oct  4 17:14:38 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krcp.c (tgt_keyproc): Add widen.h and narrow.h around
+		declaration so that argument types are widened.
+
+Mon Oct  3 13:21:51 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* logutil.c (logwtmp): Remove declaration for strncpy().
+
+Fri Sep 30 17:04:24 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+        * krshd.c: Use ifdef for SETPGRP_TWOARG and HAVE_KILLPG
+
+	* krlogind.c: Use ifdef include of HAVE_SYS_TTY_H and
+		HAVE_SYS_PTYVAR_H (suncc doesn't #define solaris).
+
+Thu Sep 29 22:50:05 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: "make clean" should remove the executables
+
+	* Makefile.in: Relink executables if libraries change
+
+Thu Sep 29 17:55:57 1994  Mark Eichin  (eichin@tweedledumber.cygnus.com)
+
+	* krlogin.c (mode): ifdef VLNEXT instead of svr4 for ^V fixing.
+	(doit): ditto.
+	krlogin.c, configure.in: include sys/tty.h and sys/ttold.h only if
+	they're both there. 
+
+
+Wed Sep 28 20:57:24 1994  Mark Eichin  (eichin@tweedledumber.cygnus.com)
+
+	* configure.in (srand48): check for srand48, and if it exists,
+	substitute it for srandom (and lrand48 for random.)
+	(K4LIB): add libdes.a, needed for des_pcbc_encrypt.
+
+Wed Sep 28 14:36:29 1994  Mark Eichin  (eichin@rtl.cygnus.com)
+
+	* Makefile.in: always put $(K4LIB) before $(KLIB) so that
+	references to libcrypto.a get resolved.
+
+Thu Aug 18 18:57:44 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* Makefile.in:
+	* configure.in: Fix KRB4 handling; do it here in configure.in
+	instead of in Makefile.in
+
+Thu Aug 18 18:55:36 1994  Mark Eichin  (eichin@perdiem)
+
+	* configure.in (LOGINLIBS): always substitute it, even if it isn't
+	set.
+
+Thu Aug 18 17:09:36 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+    	* forward.c (get_for_creds): Fix bug to allow cross-realm
+	forwarded credentials to work.
+
+	* forward.c (rd_and_store_for_creds):  Store the forwarded
+	credentials in a file which is PID dependent, to allow for
+	different sessions in an rlogin session.
+
+	* Makefile: Add $(SETENVOBJ) to all programs that use forward.c
+
+Tue Aug 16 22:41:25 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* krlogind.c: add sys/ioctl.h.
+
+Tue Aug 16 22:36:29 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in: set LOGINLIBS to -lodm -ls -lcfg if the system has
+	all three (and is probably an AIX system.)
+	* Makefile.in: use LOGINLIBS for login.krb5.
+	* krshd.c: use HAVE_SYS_SELECT_H.
+
+Tue Aug 16 17:58:09 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* krcp.c: check HAVE_VFORK_H
+	* configure.in: use AC_VFORK (runtime test -- consider just using
+	fork instead.)
+
+Sat Aug 13 02:04:37 1994  Mark Eichin  (eichin@perdiem)
+
+	* Makefile.in (DEFINES): set LOGIN_PROGRAM correctly.
+
+Thu Aug 11 23:16:31 1994  Mark Eichin  (eichin@perdiem)
+
+	* krsh.c: Don't (mis)declare getpwuid ever.
+
+Sun Aug  7 04:43:24 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* krlogin.c (oob): FWRITE (and out) not needed w/POSIX_TERMIOS
+	* logutil.c: if EMPTY is missing, use UT_UNKNOWN instead.
+	* login.c (main): some systems just don't have TIOCLSET
+
+Fri Aug  5 18:47:00 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in: test for sigprocmask and sigset_t to set POSIX_SIGNALS.
+	* krlogin.c, kcmd.c: use POSIX_SIGNALS.
+
+Fri Aug  5 15:35:54 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in, logutil.c: check for NO_UT_PID, use it.
+
+Wed Jul 27 12:52:04 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* krlogind.c, krlogin.c, krcp.c: define roundup if needed.
+
+	* Makefile.in: add LIBOBJS, dependency for getdtablesize.o.
+	* getdtablesize.c: new file.
+	* configure.in: build getdtablesize.c if needed.
+
+	* login.c: HAVE_TTYENT_H.
+	* configure.in: add ttyent.h to HEADERS test.
+
+	* krshd.c: HAVE_SYS_LABEL_H, which seems to be SunOS 4 specific.
+	* krlogind.c: ditto.
+	* configure.in: test for add sys/label.h to HEADERS test.
+
+	* krcp.c (rsource): USE_DIRENT_H.
+
+	* configure.in: test for HAVE_UNISTD_H.
+	* logutil.c: use HAVE_UNISTD_H.
+
+Tue Jul 26 00:25:57 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* krlogin.c: include <fcntl.h>
+
+	* configure.in: Added tests for NO_UT_HOST, NO_UT_EXIT.
+	* logutil.c: use them.
+
+	* configure.in: add CHECK_DIRENT, CHECK_FCNTL.
+
+	* configure.in: Added tests for HAVE_SETOWN, HAVE_SYS_FILIO_H.
+	* krlogin.c, krsh.c, krshd.c, krlogin.c, krlogind.c: use them.
+
+Sat Jul 23 08:48:50 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* kcmd.c:
+	* krshd.c: include ext-proto.h to avoid type warnings
+
+Sat Jul 16 02:24:31 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* kcmd.c:
+	* krsh.c: index->strchr, rindex->strrchr, add (char *) cast to
+	malloc,	have proper include for the string functions.
+
+Fri Jul 15 15:03:11 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* krcp.c: add utimes() emulation for systems that only have the
+		POSIX utime() call.
+
+Mon Jun 27 22:03:48 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* krlogind.c: remove spurious debugging #undef of KRB5_KRB4_COMPAT
+
diff --git a/mechglue/src/appl/bsd/Makefile.in b/mechglue/src/appl/bsd/Makefile.in
new file mode 100644
index 000000000..711a66fab
--- /dev/null
+++ b/mechglue/src/appl/bsd/Makefile.in
@@ -0,0 +1,175 @@
+thisconfigdir=.
+myfulldir=appl/bsd
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCALINCLUDES=@KRB4_INCLUDES@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+SETENVSRC=@SETENVSRC@
+SETENVOBJ=@SETENVOBJ@
+
+LOGINLIBS=@LOGINLIBS@
+LIBOBJS=@LIBOBJS@
+V4RCP=@V4RCP@
+V4RCPO=@V4RCPO@
+KRSHDLIBS=@KRSHDLIBS@
+
+SRCS= $(srcdir)/krcp.c $(srcdir)/krlogin.c $(srcdir)/krsh.c $(srcdir)/kcmd.c \
+	$(srcdir)/forward.c $(srcdir)/compat_recv.c \
+	$(srcdir)/login.c $(srcdir)/krshd.c $(srcdir)/krlogind.c \
+	$(srcdir)/v4rcp.c
+OBJS= krcp.o krlogin.o krsh.o kcmd.o forward.o compat_recv.o $(SETENVOBJ) \
+	login.o krshd.o krlogind.o $(V4RCPO) $(LIBOBJS)
+
+UCB_RLOGIN = @UCB_RLOGIN@
+UCB_RSH = @UCB_RSH@
+UCB_RCP = @UCB_RCP@
+
+RSH=	-DKRB5_PATH_RLOGIN=\"$(CLIENT_BINDIR)/rlogin\"
+BSD=	-DUCB_RLOGIN=\"$(UCB_RLOGIN)\" \
+	-DUCB_RSH=\"$(UCB_RSH)\" -DUCB_RCP=\"$(UCB_RCP)\"
+
+DEFINES = $(RSH) $(BSD) $(RPROGS) -DKERBEROS \
+	-DLOGIN_PROGRAM=\"$(SERVER_BINDIR)/login.krb5\" -DKPROGDIR=\"$(CLIENT_BINDIR)\" \
+	-DHEIMDAL_FRIENDLY
+
+all:: rsh rcp rlogin kshd klogind login.krb5 $(V4RCP)
+
+clean:: 
+	$(RM) rsh rcp rlogin kshd klogind login.krb5 v4rcp
+
+rsh: krsh.o kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o rsh krsh.o kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(KRB4COMPAT_LIBS)
+
+rcp: krcp.o kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o rcp krcp.o kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(KRB4COMPAT_LIBS)
+
+v4rcp: v4rcp.o $(SETENVOBJ) $(LIBOBJS) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o v4rcp v4rcp.o $(SETENVOBJ) $(LIBOBJS) $(KRB4COMPAT_LIBS)
+
+rlogin: krlogin.o kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o rlogin krlogin.o kcmd.o forward.o $(SETENVOBJ) $(LIBOBJS) $(KRB4COMPAT_LIBS)
+
+install::
+	for f in rsh rcp rlogin; do \
+	 ($(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'` && \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		${DESTDIR}$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1 \
+	  ) || exit 1; \
+	done
+	f=$(V4RCP); \
+	if test -n "$$f" ; then	$(INSTALL_SETUID) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	$(INSTALL_DATA) $(srcdir)/$$f.M \
+		${DESTDIR}$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	fi
+
+kshd: krshd.o kcmd.o forward.o compat_recv.o $(SETENVOBJ) $(LIBOBJS) $(PTY_DEPLIB) $(KRB4COMPAT_DEPLIBS) $(APPUTILS_DEPLIB)
+	$(CC_LINK) -o kshd krshd.o kcmd.o forward.o compat_recv.o $(SETENVOBJ) $(LIBOBJS) $(KRSHDLIBS) $(PTY_LIB) $(UTIL_LIB) $(KRB4COMPAT_LIBS) $(APPUTILS_LIB)
+
+klogind: krlogind.o kcmd.o forward.o compat_recv.o $(SETENVOBJ) $(LIBOBJS) $(PTY_DEPLIB) $(KRB4COMPAT_DEPLIBS) $(APPUTILS_DEPLIB)
+	$(CC_LINK) -o klogind krlogind.o  kcmd.o forward.o compat_recv.o $(SETENVOBJ) $(LIBOBJS) $(PTY_LIB) $(UTIL_LIB) $(KRB4COMPAT_LIBS) $(APPUTILS_LIB)
+
+install::
+	for f in kshd klogind; do \
+	 ($(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(SERVER_BINDIR)/`echo $$f|sed '$(transform)'` && \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		${DESTDIR}$(SERVER_MANDIR)/`echo $$f|sed '$(transform)'`.8 \
+	 ) || exit 1 ; \
+	done
+
+# No program name transformation is done with login.krb5 since it is directly
+# referenced by klogind.
+#
+login.krb5: login.o  $(SETENVOBJ) $(LIBOBJS) $(PTY_DEPLIB) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o login.krb5 login.o $(SETENVOBJ) $(LIBOBJS) $(LOGINLIBS) $(PTY_LIB) $(KRB4COMPAT_LIBS)
+
+install::
+	$(INSTALL_PROGRAM) login.krb5 $(DESTDIR)$(SERVER_BINDIR)/login.krb5
+	$(INSTALL_DATA) $(srcdir)/login.M \
+		${DESTDIR}$(SERVER_MANDIR)/login.krb5.8
+
+getdtablesize.o: $(srcdir)/getdtablesize.c
+
+kcmd.o krcp.o krlogin.o krlogind.o krsh.o krshd.o forward.o: defines.h
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)krcp.$(OBJEXT): krcp.c $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-util.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(BUILDTOP)/include/profile.h defines.h \
+  $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h
+$(OUTPRE)krlogin.$(OBJEXT): krlogin.c $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h defines.h $(SRCTOP)/include/fake-addrinfo.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h rpaths.h
+$(OUTPRE)krsh.$(OBJEXT): krsh.c $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h defines.h $(SRCTOP)/include/fake-addrinfo.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h
+$(OUTPRE)kcmd.$(OBJEXT): kcmd.c $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h defines.h $(SRCTOP)/include/fake-addrinfo.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h
+$(OUTPRE)forward.$(OBJEXT): forward.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h defines.h $(SRCTOP)/include/fake-addrinfo.h
+$(OUTPRE)compat_recv.$(OBJEXT): compat_recv.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  defines.h $(SRCTOP)/include/fake-addrinfo.h
+$(OUTPRE)login.$(OBJEXT): login.c $(BUILDTOP)/include/libpty.h \
+  $(SRCTOP)/include/syslog.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  loginpaths.h
+$(OUTPRE)krshd.$(OBJEXT): krshd.c $(BUILDTOP)/include/libpty.h \
+  $(SRCTOP)/include/syslog.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) loginpaths.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h $(SRCTOP)/include/k5-util.h \
+  $(BUILDTOP)/include/krb5/autoconf.h defines.h $(SRCTOP)/include/fake-addrinfo.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h
+$(OUTPRE)krlogind.$(OBJEXT): krlogind.c $(SRCTOP)/include/syslog.h \
+  $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h $(BUILDTOP)/include/libpty.h \
+  $(SRCTOP)/include/k5-util.h defines.h
+$(OUTPRE)v4rcp.$(OBJEXT): v4rcp.c $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-util.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h $(SRCTOP)/include/kerberosIV/krbports.h \
+  rpaths.h
diff --git a/mechglue/src/appl/bsd/compat_recv.c b/mechglue/src/appl/bsd/compat_recv.c
new file mode 100644
index 000000000..c76c4142c
--- /dev/null
+++ b/mechglue/src/appl/bsd/compat_recv.c
@@ -0,0 +1,581 @@
+/*
+ * lib/krb5/krb/compat_recv.c
+ *
+ * Copyright 1993 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * convenience sendauth/recvauth functions, with compatibility with V4
+ * recvauth.
+ *
+ * NOTE: linking in this function will pull in V4 kerberos routines.
+ *
+ * WARNING: In the V4-style arguments, the ticket and kdata arguments
+ * have different types than the V4 recvauth; in V4, they were KTEXT
+ * and AUTH_DAT *, respectively.  Here, they are KTEXT * and AUTH_DAT **
+ * and they are allocated by recvauth if and only if we end up talking
+ * to a V4 sendauth.
+ */
+
+#include "k5-int.h"
+#if !defined(_MACINTOSH)
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+#include "com_err.h"
+#include <errno.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "defines.h"
+
+#ifdef KRB5_KRB4_COMPAT
+static int krb_v4_recvauth(long options, int fd, KTEXT ticket,
+			   char *service, char *instance, 
+			   struct sockaddr_in *faddr,
+			   struct sockaddr_in *laddr,
+			   AUTH_DAT *kdata,
+			   char *filename,
+			   Key_schedule schedule,
+			   char *version);
+#endif
+
+#define	KRB_V4_SENDAUTH_VERS	"AUTHV0.1" /* MUST be 8 chars long */
+#define KRB_V5_SENDAUTH_VERS	"KRB5_SENDAUTH_V1.0"
+
+#define KRB5_RECVAUTH_V4	4
+#define KRB5_RECVAUTH_V5	5
+
+#ifdef KRB5_KRB4_COMPAT
+krb5_error_code
+krb5_compat_recvauth(context, auth_context,
+	             /* IN */
+		     fdp, appl_version, server, flags, keytab,
+		     v4_options, v4_service, v4_instance, v4_faddr, v4_laddr,
+		     v4_filename, 
+		     /* OUT */
+		     ticket,
+		     auth_sys, v4_kdata, v4_schedule, v4_version)
+    krb5_context context;
+    krb5_auth_context  *auth_context;
+	krb5_pointer	fdp;
+	char	*appl_version;
+	krb5_principal	server;
+	krb5_int32	flags;
+	krb5_keytab    	keytab;
+	krb5_ticket  ** ticket;
+        krb5_int32      *auth_sys;
+
+	/*
+	 * Version 4 arguments
+	 */
+	krb5_int32 v4_options;	 /* bit-pattern of options */
+	char *v4_service;	 /* service expected */
+	char *v4_instance;	 /* inst expected (may be filled in) */
+	struct sockaddr_in *v4_faddr; /* foreign address */
+	struct sockaddr_in *v4_laddr; /* local address */
+	AUTH_DAT **v4_kdata;	 /* kerberos data (returned) */
+	char *v4_filename;	 /* name of file with service keys */
+	Key_schedule v4_schedule; /* key schedule (return) */
+	char *v4_version;		 /* version string (filled in) */
+{
+	union verslen {
+		krb5_int32	len;
+		char		vers[4];
+	} vers;
+	char	*buf;
+	int	len, length;
+	krb5_int32	retval;
+	int		fd = *( (int *) fdp);
+#ifdef KRB5_KRB4_COMPAT
+	KTEXT		v4_ticket;	 /* storage for client's ticket */
+#endif
+		
+	if ((retval = krb5_net_read(context, fd, vers.vers, 4)) != 4)
+		return((retval < 0) ? errno : ECONNABORTED);
+
+#ifdef KRB5_KRB4_COMPAT
+	if (!strncmp(vers.vers, KRB_V4_SENDAUTH_VERS, 4)) {
+		/*
+		 * We must be talking to a V4 sendauth; read in the
+		 * rest of the version string and make sure.
+		 */
+		if ((retval = krb5_net_read(context, fd, vers.vers, 4)) != 4)
+			return((retval < 0) ? errno : ECONNABORTED);
+		
+		if (strncmp(vers.vers, KRB_V4_SENDAUTH_VERS+4, 4))
+			return KRB5_SENDAUTH_BADAUTHVERS;
+
+		*auth_sys = KRB5_RECVAUTH_V4;
+
+		*v4_kdata = (AUTH_DAT *) malloc( sizeof(AUTH_DAT) );
+		v4_ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
+
+		retval = krb_v4_recvauth(v4_options, fd, v4_ticket,
+					 v4_service, v4_instance, v4_faddr,
+					 v4_laddr, *v4_kdata, v4_filename,
+					 v4_schedule, v4_version);
+		krb5_xfree(v4_ticket);
+		/*
+		 * XXX error code translation?
+		 */
+		switch (retval) {
+		case RD_AP_OK:
+		    return 0;
+		case RD_AP_TIME:
+		    return KRB5KRB_AP_ERR_SKEW;
+		case RD_AP_EXP:
+		    return KRB5KRB_AP_ERR_TKT_EXPIRED;
+		case RD_AP_NYV:
+		    return KRB5KRB_AP_ERR_TKT_NYV;
+		case RD_AP_NOT_US:
+		    return KRB5KRB_AP_ERR_NOT_US;
+		case RD_AP_UNDEC:
+		    return KRB5KRB_AP_ERR_BAD_INTEGRITY;
+		case RD_AP_REPEAT:
+		    return KRB5KRB_AP_ERR_REPEAT;
+		case RD_AP_MSG_TYPE:
+		    return KRB5KRB_AP_ERR_MSG_TYPE;
+		case RD_AP_MODIFIED:
+		    return KRB5KRB_AP_ERR_MODIFIED;
+		case RD_AP_ORDER:
+		    return KRB5KRB_AP_ERR_BADORDER;
+		case RD_AP_BADD:
+		    return KRB5KRB_AP_ERR_BADADDR;
+		default:
+		    return KRB5_SENDAUTH_BADRESPONSE;
+		}
+	}
+#endif
+
+	/*
+	 * Assume that we're talking to a V5 recvauth; read in the
+	 * the version string, and make sure it matches.
+	 */
+	
+	len = (int) ntohl(vers.len);
+
+	if (len < 0 || len > 255)
+		return KRB5_SENDAUTH_BADAUTHVERS;
+
+	buf = malloc((unsigned) len);
+	if (!buf)
+		return ENOMEM;
+	
+	length = krb5_net_read(context, fd, buf, len);
+	if (len != length) {
+		krb5_xfree(buf);
+		if (len < 0)
+			return errno;
+		else
+			return ECONNABORTED;
+	}
+
+	if (strcmp(buf, KRB_V5_SENDAUTH_VERS)) {
+		krb5_xfree(buf);
+		return KRB5_SENDAUTH_BADAUTHVERS;
+	}
+	krb5_xfree(buf);
+
+	*auth_sys = KRB5_RECVAUTH_V5;
+	
+	retval = krb5_recvauth(context, auth_context, fdp, appl_version, server,
+			       flags | KRB5_RECVAUTH_SKIP_VERSION, 
+			       keytab, ticket);
+
+	return retval;
+}
+
+krb5_error_code
+krb5_compat_recvauth_version(context, auth_context,
+			     /* IN */
+			     fdp, server, flags, keytab,
+			     v4_options, v4_service, v4_instance, v4_faddr,
+			     v4_laddr,
+			     v4_filename, 
+			     /* OUT */
+			     ticket,
+			     auth_sys, v4_kdata, v4_schedule,
+			     version)
+    krb5_context context;
+    krb5_auth_context  *auth_context;
+	krb5_pointer	fdp;
+	krb5_principal	server;
+	krb5_int32	flags;
+	krb5_keytab    	keytab;
+	krb5_ticket  ** ticket;
+        krb5_int32      *auth_sys;
+
+	/*
+	 * Version 4 arguments
+	 */
+	krb5_int32 v4_options;	 /* bit-pattern of options */
+	char *v4_service;	 /* service expected */
+	char *v4_instance;	 /* inst expected (may be filled in) */
+	struct sockaddr_in *v4_faddr; /* foreign address */
+	struct sockaddr_in *v4_laddr; /* local address */
+	AUTH_DAT **v4_kdata;	 /* kerberos data (returned) */
+	char *v4_filename;	 /* name of file with service keys */
+	Key_schedule v4_schedule; /* key schedule (return) */
+    krb5_data *version;		/* application version filled in */
+{
+	union verslen {
+		krb5_int32	len;
+		char		vers[4];
+	} vers;
+	char	*buf;
+	int	len, length;
+	krb5_int32	retval;
+	int		fd = *( (int *) fdp);
+#ifdef KRB5_KRB4_COMPAT
+	KTEXT		v4_ticket;	 /* storage for client's ticket */
+#endif
+		
+	if ((retval = krb5_net_read(context, fd, vers.vers, 4)) != 4)
+		return((retval < 0) ? errno : ECONNABORTED);
+
+#ifdef KRB5_KRB4_COMPAT
+	if (v4_faddr->sin_family == AF_INET
+	    && !strncmp(vers.vers, KRB_V4_SENDAUTH_VERS, 4)) {
+		/*
+		 * We must be talking to a V4 sendauth; read in the
+		 * rest of the version string and make sure.
+		 */
+		if ((retval = krb5_net_read(context, fd, vers.vers, 4)) != 4)
+			return((retval < 0) ? errno : ECONNABORTED);
+		
+		if (strncmp(vers.vers, KRB_V4_SENDAUTH_VERS+4, 4))
+			return KRB5_SENDAUTH_BADAUTHVERS;
+
+		*auth_sys = KRB5_RECVAUTH_V4;
+
+		*v4_kdata = (AUTH_DAT *) malloc( sizeof(AUTH_DAT) );
+		v4_ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
+
+		version->length = KRB_SENDAUTH_VLEN; /* no trailing \0! */
+		version->data = malloc (KRB_SENDAUTH_VLEN + 1);
+		version->data[KRB_SENDAUTH_VLEN] = 0;
+		if (version->data == 0)
+		    return errno;
+		retval = krb_v4_recvauth(v4_options, fd, v4_ticket,
+					 v4_service, v4_instance, v4_faddr,
+					 v4_laddr, *v4_kdata, v4_filename,
+					 v4_schedule, version->data);
+		krb5_xfree(v4_ticket);
+		/*
+		 * XXX error code translation?
+		 */
+		switch (retval) {
+		case RD_AP_OK:
+		    return 0;
+		case RD_AP_TIME:
+		    return KRB5KRB_AP_ERR_SKEW;
+		case RD_AP_EXP:
+		    return KRB5KRB_AP_ERR_TKT_EXPIRED;
+		case RD_AP_NYV:
+		    return KRB5KRB_AP_ERR_TKT_NYV;
+		case RD_AP_NOT_US:
+		    return KRB5KRB_AP_ERR_NOT_US;
+		case RD_AP_UNDEC:
+		    return KRB5KRB_AP_ERR_BAD_INTEGRITY;
+		case RD_AP_REPEAT:
+		    return KRB5KRB_AP_ERR_REPEAT;
+		case RD_AP_MSG_TYPE:
+		    return KRB5KRB_AP_ERR_MSG_TYPE;
+		case RD_AP_MODIFIED:
+		    return KRB5KRB_AP_ERR_MODIFIED;
+		case RD_AP_ORDER:
+		    return KRB5KRB_AP_ERR_BADORDER;
+		case RD_AP_BADD:
+		    return KRB5KRB_AP_ERR_BADADDR;
+		default:
+		    return KRB5_SENDAUTH_BADRESPONSE;
+		}
+	}
+#endif
+
+	/*
+	 * Assume that we're talking to a V5 recvauth; read in the
+	 * the version string, and make sure it matches.
+	 */
+	
+	len = (int) ntohl(vers.len);
+
+	if (len < 0 || len > 255)
+		return KRB5_SENDAUTH_BADAUTHVERS;
+
+	buf = malloc((unsigned) len);
+	if (!buf)
+		return ENOMEM;
+	
+	length = krb5_net_read(context, fd, buf, len);
+	if (len != length) {
+		krb5_xfree(buf);
+		if (len < 0)
+			return errno;
+		else
+			return ECONNABORTED;
+	}
+
+	if (strcmp(buf, KRB_V5_SENDAUTH_VERS)) {
+		krb5_xfree(buf);
+		return KRB5_SENDAUTH_BADAUTHVERS;
+	}
+	krb5_xfree(buf);
+
+	*auth_sys = KRB5_RECVAUTH_V5;
+	
+	retval = krb5_recvauth_version(context, auth_context, fdp, server,
+				       flags | KRB5_RECVAUTH_SKIP_VERSION, 
+				       keytab, ticket, version);
+
+	return retval;
+}
+#endif /* KRB5_KRB4_COMPAT */
+
+
+#ifndef max
+#define	max(a,b) (((a) > (b)) ? (a) : (b))
+#endif /* max */
+
+#ifdef KRB5_KRB4_COMPAT	
+static int
+krb_v4_recvauth(options, fd, ticket, service, instance, faddr, laddr, kdata,
+		filename, schedule, version)
+long options;			 /* bit-pattern of options */
+int fd;				 /* file descr. to read from */
+KTEXT ticket;			 /* storage for client's ticket */
+char *service;			 /* service expected */
+char *instance;			 /* inst expected (may be filled in) */
+struct sockaddr_in *faddr;	 /* address of foreign host on fd */
+struct sockaddr_in *laddr;	 /* local address */
+AUTH_DAT *kdata;		 /* kerberos data (returned) */
+char *filename;			 /* name of file with service keys */
+Key_schedule schedule;		 /* key schedule (return) */
+char *version;			 /* version string (filled in) */
+{
+    int cc, old_vers = 0;
+    int rem;
+    krb5_int32 tkt_len, priv_len;
+    krb5_ui_4 cksum;
+    u_char tmp_buf[MAX_KTXT_LEN+max(KRB_SENDAUTH_VLEN+1,21)];
+
+    /* read the application version string */
+    if ((krb_net_read(fd, version, KRB_SENDAUTH_VLEN) !=
+	 KRB_SENDAUTH_VLEN))
+	return(errno);
+    version[KRB_SENDAUTH_VLEN] = '\0';
+
+    /* get the length of the ticket */
+    if (krb_net_read(fd, (char *)&tkt_len, sizeof(tkt_len)) !=
+	sizeof(tkt_len))
+	return(errno);
+    
+    /* sanity check */
+    ticket->length = ntohl((unsigned long)tkt_len);
+    if ((ticket->length <= 0) || (ticket->length > MAX_KTXT_LEN)) {
+	if (options & KOPT_DO_MUTUAL) {
+	    rem = KFAILURE;
+	    goto mutual_fail;
+	} else
+	    return(KFAILURE); /* XXX there may still be junk on the fd? */
+    }		
+
+    /* read the ticket */
+    if (krb_net_read(fd, (char *) ticket->dat, ticket->length)
+	!= ticket->length)
+	return(errno);
+
+    /*
+     * now have the ticket.  decrypt it to get the authenticated
+     * data.
+     */
+    rem = krb_rd_req(ticket,service,instance,faddr->sin_addr.s_addr,
+		     kdata,filename);
+
+    if (old_vers) return(rem);	 /* XXX can't do mutual with old client */
+
+    /* if we are doing mutual auth, compose a response */
+    if (options & KOPT_DO_MUTUAL) {
+	if (rem != KSUCCESS)
+	    /* the krb_rd_req failed */
+	    goto mutual_fail;
+
+	/* add one to the (formerly) sealed checksum, and re-seal it
+	   for return to the client */
+	cksum = kdata->checksum + 1;
+	cksum = htonl(cksum);
+#ifndef NOENCRYPTION
+	key_sched(kdata->session,schedule);
+#endif /* !NOENCRYPTION */
+	priv_len = krb_mk_priv((unsigned char *)&cksum,
+			       tmp_buf,
+			       (unsigned long) sizeof(cksum),
+			       schedule,
+			       &kdata->session,
+			       laddr,
+			       faddr);
+	if (priv_len < 0) {
+	    /* re-sealing failed; notify the client */
+	    rem = KFAILURE;	 /* XXX */
+mutual_fail:
+	    priv_len = -1;
+	    tkt_len = htonl((unsigned long) priv_len);
+	    /* a length of -1 is interpreted as an authentication
+	       failure by the client */
+	    if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
+		!= sizeof(tkt_len))
+		return(cc);
+	    return(rem);
+	} else {
+	    /* re-sealing succeeded, send the private message */
+	    tkt_len = htonl((unsigned long)priv_len);
+	    if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
+		 != sizeof(tkt_len))
+		return(cc);
+	    if ((cc = krb_net_write(fd, (char *)tmp_buf, (int) priv_len))
+		!= (int) priv_len)
+		return(cc);
+	}
+    }
+    return(rem);
+}
+#endif
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include "port-sockets.h"
+
+int
+accept_a_connection (int debug_port, struct sockaddr *from,
+		     socklen_t *fromlenp)
+{
+    int n, s, fd, s4 = -1, s6 = -1, on = 1;
+    fd_set sockets;
+
+    FD_ZERO(&sockets);
+
+#ifdef KRB5_USE_INET6
+    {
+	struct sockaddr_in6 sock_in6;
+
+	if ((s = socket(AF_INET6, SOCK_STREAM, PF_UNSPEC)) < 0) {
+	    if ((errno == EPROTONOSUPPORT) || (errno == EAFNOSUPPORT))
+		goto skip_ipv6;
+	    fprintf(stderr, "Error in socket(INET6): %s\n", strerror(errno));
+	    exit(2);
+	}
+
+	memset((char *) &sock_in6, 0,sizeof(sock_in6));
+	sock_in6.sin6_family = AF_INET6;
+	sock_in6.sin6_port = htons(debug_port);
+	sock_in6.sin6_addr = in6addr_any;
+
+	(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+			  (char *)&on, sizeof(on));
+
+	if ((bind(s, (struct sockaddr *) &sock_in6, sizeof(sock_in6))) < 0) {
+	    fprintf(stderr, "Error in bind(INET6): %s\n", strerror(errno));
+	    exit(2);
+	}
+
+	if ((listen(s, 5)) < 0) {
+	    fprintf(stderr, "Error in listen(INET6): %s\n", strerror(errno));
+	    exit(2);
+	}
+	s6 = s;
+	FD_SET(s, &sockets);
+    skip_ipv6:
+	;
+    }
+#endif
+
+    {
+	struct sockaddr_in sock_in;
+
+	if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
+	    fprintf(stderr, "Error in socket: %s\n", strerror(errno));
+	    exit(2);
+	}
+
+	memset((char *) &sock_in, 0,sizeof(sock_in));
+	sock_in.sin_family = AF_INET;
+	sock_in.sin_port = htons(debug_port);
+	sock_in.sin_addr.s_addr = INADDR_ANY;
+
+	(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+			  (char *)&on, sizeof(on));
+
+	if ((bind(s, (struct sockaddr *) &sock_in, sizeof(sock_in))) < 0) {
+	    if (s6 >= 0 && errno == EADDRINUSE)
+		goto try_ipv6_only;
+	    fprintf(stderr, "Error in bind: %s\n", strerror(errno));
+	    exit(2);
+	}
+
+	if ((listen(s, 5)) < 0) {
+	    fprintf(stderr, "Error in listen: %s\n", strerror(errno));
+	    exit(2);
+	}
+	s4 = s;
+	FD_SET(s, &sockets);
+    try_ipv6_only:
+	;
+    }
+    if (s4 == -1 && s6 == -1) {
+	fprintf(stderr, "No valid sockets established, exiting\n");
+	exit(2);
+    }
+    n = select(((s4 < s6) ? s6 : s4) + 1, &sockets, 0, 0, 0);
+    if (n < 0) {
+	fprintf(stderr, "select error: %s\n", strerror(errno));
+	exit(2);
+    } else if (n == 0) {
+	fprintf(stderr, "internal error? select returns 0\n");
+	exit(2);
+    }
+    if (s6 != -1 && FD_ISSET(s6, &sockets)) {
+	if (s4 != -1)
+	    close(s4);
+	s = s6;
+    } else if (FD_ISSET(s4, &sockets)) {
+	if (s6 != -1)
+	    close(s6);
+	s = s4;
+    } else {
+	fprintf(stderr,
+		"internal error? select returns positive, "
+		"but neither fd available\n");
+	exit(2);
+    }
+
+    if ((fd = accept(s, from, fromlenp)) < 0) {
+	fprintf(stderr, "Error in accept: %s\n", strerror(errno));
+	exit(2);
+    }
+
+    close(s);
+    return fd;
+}
diff --git a/mechglue/src/appl/bsd/configure.in b/mechglue/src/appl/bsd/configure.in
new file mode 100644
index 000000000..244adf9cd
--- /dev/null
+++ b/mechglue/src/appl/bsd/configure.in
@@ -0,0 +1,195 @@
+K5_AC_INIT(krlogind.c)
+CONFIG_RULES
+KRB5_AC_INET6
+LOGINLIBS=
+AC_ARG_WITH([afs],
+[  --without-afs        don't have afs libraries to build against (default)
+  --with-afs=AFSDIR    use preinstalled AFS library tree],
+,with_afs=no)dnl
+if test $with_afs != no; then
+	AC_DEFINE(SETPAG)
+	LOGINLIBS="$LOGINLIBS -L$with_afs/lib -L$with_afs/lib/afs -lauth -lsys -lrx -llwp"
+fi
+AC_PROG_INSTALL
+dnl dbm libs for use of an_to_ln
+save_LIBS="$LIBS"
+ LIBS=
+ AC_CHECK_LIB(crypt,crypt)
+ LOGINLIBS="$LOGINLIBS $LIBS"
+LIBS="$save_LIBS"
+dnl
+dnl AIX has them all; SCO might too
+AC_CHECK_LIB(odm,main,
+  AC_CHECK_LIB(s,main,
+    AC_CHECK_LIB(cfg,main, 
+      LOGINLIBS="$LOGINLIBS -lodm -ls -lcfg" 
+      )))
+dnl
+dnl Make our operating system-specific security checks and definitions for
+dnl login.
+dnl
+case $krb5_cv_host in
+*-*-aix3*)
+	# AIX has streams include files but not streams TTY
+	# Moreover, strops.h trashes sys/ioctl.h
+	krb5_cv_has_streams=no
+	;;
+alpha*-dec-osf*)
+	AC_CHECK_LIB(security,setluid,
+		AC_DEFINE(HAVE_SETLUID)
+		LOGINLIBS="$LOGINLIBS -lsecurity"
+	)
+	;;
+*-*-sunos4*)
+	ac_cv_header_termios_h=no
+	;;
+esac
+dnl
+dnl krshd does not use krb524...
+dnl
+KRSHDLIBS="$LOGINLIBS"
+dnl 
+dnl After beta6 this functionality will be integrated with aclocal.m4
+AC_ARG_WITH([krb4],
+[  --without-krb4          don't include Kerberos V4 backwards compatibility
+  --with-krb4             use V4 libraries included with V5 (default)
+  --with-krb4=KRB4DIR     use preinstalled V4 libraries],
+,
+withval=yes
+)dnl
+if test $withval = no; then
+	AC_MSG_RESULT(no krb4 support)
+	V4RCP=
+	V4RCPO=
+else 
+	AC_MSG_RESULT(Adding in krb4 rcp support)
+	V4RCP=v4rcp
+	V4RCPO=v4rcp.o
+fi
+dnl
+dnl
+AC_SUBST(KRSHDLIBS)
+AC_SUBST(LOGINLIBS)
+AC_SUBST(V4RCP)
+AC_SUBST(V4RCPO)
+dnl
+AC_FUNC_VFORK
+AC_TYPE_MODE_T
+AC_CHECK_FUNCS(isatty inet_aton getenv gettosbyname killpg initgroups setpriority setreuid setresuid waitpid setsid ptsname setlogin tcgetpgrp tcsetpgrp setpgid strsave utimes rmufile rresvport_af)
+AC_CHECK_HEADERS(unistd.h stdlib.h string.h sys/filio.h sys/sockio.h sys/label.h sys/tty.h ttyent.h lastlog.h sys/select.h sys/ptyvar.h utmp.h sys/time.h krb4-proto.h sys/ioctl_compat.h paths.h arpa/nameser.h)
+AC_HEADER_STDARG
+AC_REPLACE_FUNCS(getdtablesize)
+dnl
+KRB5_AC_NEED_DAEMON
+dnl
+KRB5_SIGTYPE
+CHECK_SIGNALS
+CHECK_SETJMP
+CHECK_DIRENT
+CHECK_WAIT_TYPE
+AC_CHECK_HEADER(termios.h,[AC_CHECK_FUNC(cfsetispeed,AC_DEFINE(POSIX_TERMIOS))])
+CHECK_UTMP
+KRB5_GETSOCKNAME_ARGS
+dnl
+dnl Check for where the BSD rlogin, rcp, and rsh programs live.
+dnl
+save_path=$PATH
+ifdef([_AC_PROG_ECHO], [_AC_PROG_ECHO])
+ifdef([AC_PROG_ECHO_N], [AC_PROG_ECHO_N])
+AC_ARG_ENABLE([athena],
+[  --enable-athena         build with MIT Project Athena configuration],
+[PATH=/usr/athena/bin:/bin:/usr/bin:/usr/bsd:/usr/ucb],
+[PATH=/bin:/usr/bin:/usr/bsd:/usr/ucb])
+AC_PATH_PROG(UCB_RLOGIN,rlogin,/usr/ucb/rlogin)
+AC_PATH_PROG(UCB_RSH,rsh,/usr/ucb/rsh)
+AC_PATH_PROG(UCB_RCP,rcp,/usr/ucb/rcp)
+PATH=$save_path
+ifdef([_AC_PROG_ECHO], [_AC_PROG_ECHO])
+ifdef([AC_PROG_ECHO_N], [AC_PROG_ECHO_N])
+dnl
+dnl
+AC_MSG_CHECKING([streams interface])
+AC_CACHE_VAL(krb5_cv_has_streams,
+[AC_TRY_COMPILE(
+[#include <sys/stream.h>
+#include <sys/stropts.h>], [],
+krb5_cv_has_streams=yes, krb5_cv_has_streams=no)])
+AC_MSG_RESULT($krb5_cv_has_streams)
+if test $krb5_cv_has_streams = yes; then
+AC_DEFINE(HAVE_STREAMS)
+fi
+dnl
+dnl
+AC_MSG_CHECKING([F_SETOWN])
+AC_CACHE_VAL(krb5_cv_f_setown,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <fcntl.h>], [1+F_SETOWN;],
+krb5_cv_f_setown=yes,krb5_cv_f_setown=no)])
+AC_MSG_RESULT($krb5_cv_f_setown)
+if test $krb5_cv_f_setown = yes; then
+AC_DEFINE(HAVE_SETOWN)
+fi
+dnl
+dnl
+AC_MSG_CHECKING([setenv])
+AC_CACHE_VAL(krb5_cv_setenv,
+[AC_TRY_LINK(
+[],[setenv("PATH","/bin",0);],
+krb5_cv_setenv=yes,krb5_cv_setenv=no)])
+AC_MSG_RESULT($krb5_cv_setenv)
+if test $krb5_cv_setenv = no; then
+SETENVSRC=setenv.c
+SETENVOBJ=setenv.o
+AC_SUBST([SETENVSRC])
+AC_SUBST([SETENVOBJ])
+AC_DEFINE([NEED_SETENV])
+fi
+dnl
+dnl
+AC_MSG_CHECKING([number of arguments to setpgrp])
+AC_CACHE_VAL(krb5_cv_setpgrp_args,
+[AC_TRY_COMPILE(
+[#ifndef __STDC__
+#define __STDC__ 1
+#endif
+#include <unistd.h>],[setpgrp(0,0)],
+krb5_cv_setpgrp_args=two, krb5_cv_setpgrp_args=void)])
+AC_MSG_RESULT($krb5_cv_setpgrp_args)
+if test $krb5_cv_setpgrp_args = two; then
+AC_DEFINE(SETPGRP_TWOARG)
+fi
+dnl
+dnl
+AC_MSG_CHECKING([shadow password support])
+AC_CACHE_VAL(krb5_cv_shadow_pwd,
+[AC_TRY_LINK(
+[#include <sys/types.h>
+#include <pwd.h>
+#include <shadow.h>],
+[struct spwd *sp = getspnam("root")],
+krb5_cv_shadow_pwd=yes, krb5_cv_shadow_pwd=no)])
+AC_MSG_RESULT($krb5_cv_shadow_pwd)
+if test $krb5_cv_shadow_pwd = yes; then
+AC_DEFINE(HAVE_SHADOW)
+fi
+dnl
+dnl
+K5_AC_CHECK_FILES(/etc/environment /etc/TIMEZONE)
+dnl
+dnl
+AC_C_CONST
+if test "$krb5_cv_build_krb4_libs" = yes; then
+	AC_DEFINE(HAVE_KRB_GET_ERR_TEXT)
+	AC_DEFINE(HAVE_KRB_SAVE_CREDENTIALS)
+else
+	oldlibs=$LIBS
+	LIBS=" $KRB4_LIB -lkrb5 -lcrypto -lcom_err"
+	AC_CHECK_FUNCS(krb_get_err_text krb_save_credentials)
+	LIBS=$oldlibs
+fi
+
+AC_CHECK_HEADERS(krb4-proto.h)
+KRB5_AC_LIBUTIL
+KRB5_BUILD_PROGRAM
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/appl/bsd/defines.h b/mechglue/src/appl/bsd/defines.h
new file mode 100644
index 000000000..ac7948ab9
--- /dev/null
+++ b/mechglue/src/appl/bsd/defines.h
@@ -0,0 +1,100 @@
+#define OPTS_FORWARD_CREDS           0x00000020
+#define OPTS_FORWARDABLE_CREDS       0x00000010
+#define RCMD_BUFSIZ	5120
+
+enum kcmd_proto {
+  /* Old protocol: DES encryption only.  No subkeys.  No protection
+     for cleartext length.  No ivec supplied.  OOB hacks used for
+     rlogin.  Checksum may be omitted at connection startup.  */
+  KCMD_OLD_PROTOCOL = 1,
+  /* New protocol: Any encryption scheme.  Client-generated subkey
+     required.  Prepend cleartext-length to cleartext data (but don't
+     include it in count).  Starting ivec defined, chained.  In-band
+     signalling.  Checksum required.  */
+  KCMD_NEW_PROTOCOL,
+  /* Hack: Get credentials, and use the old protocol iff the session
+     key type is single-DES.  */
+  KCMD_PROTOCOL_COMPAT_HACK,
+  /* Using Kerberos version 4.  */
+  KCMD_V4_PROTOCOL,
+  /* ??? */
+  KCMD_UNKNOWN_PROTOCOL
+};
+
+extern int kcmd (int *sock, char **ahost, int /* u_short */ rport,
+		 char *locuser, char *remuser, char *cmd,
+		 int *fd2p, char *service, char *realm,
+		 krb5_creds **cred,
+		 krb5_int32 *seqno, krb5_int32 *server_seqno,
+		 struct sockaddr_in *laddr,
+		 struct sockaddr_in *faddr,
+		 krb5_auth_context *authconp,
+		 krb5_flags authopts,
+		 int anyport, int suppress_err,
+		 enum kcmd_proto *protonum /* input and output */
+		 );
+
+extern int rcmd_stream_read (int fd, char *buf, size_t len, int secondary);
+extern int rcmd_stream_write (int fd, char *buf, size_t len, int secondary);
+extern int getport (int * /* portnum */, int * /* addrfamily */);
+
+extern void rcmd_stream_init_krb5 (krb5_keyblock *in_keyblock,
+				   int encrypt_flag, int lencheck,
+				   int am_client, enum kcmd_proto protonum);
+
+extern void rcmd_stream_init_normal(void);
+
+#if defined(KRB5_KRB4_COMPAT) && !defined(SKIP_V4_PROTO)
+extern void rcmd_stream_init_krb4(C_Block, int, int, int);
+
+extern int k4cmd(int *sock, char **ahost, unsigned int rport,
+		 char *locuser,
+		 char *remuser, char *cmd, int *fd2p, KTEXT ticket,
+		 char *service, char *realm, CREDENTIALS *cred, 
+		 Key_schedule schedule, MSG_DAT *msg_data, 
+		 struct sockaddr_in *laddr, struct sockaddr_in *faddr, 
+		 long authopts, int anyport);
+#endif
+
+#ifndef HAVE_STRSAVE
+extern char *strsave(const char *sp);
+#endif
+
+krb5_error_code rd_and_store_for_creds(krb5_context context, 
+				       krb5_auth_context auth_context,
+				       krb5_data *inbuf, krb5_ticket *ticket,
+				       krb5_ccache *ccache);
+
+
+int princ_maps_to_lname(krb5_principal principal, char *luser);
+int default_realm(krb5_principal principal);
+
+#ifdef NEED_SETENV
+extern int setenv(char *, char *, int);
+#endif
+
+#include "fake-addrinfo.h"
+
+#ifdef KRB_DEFS
+krb5_error_code krb5_compat_recvauth(krb5_context, krb5_auth_context *,
+				     krb5_pointer, char *, krb5_principal, 
+				     krb5_int32, krb5_keytab,
+				     krb5_int32, char *, char *,
+				     struct sockaddr_in *, 
+				     struct sockaddr_in *, char *,
+				     krb5_ticket **, krb5_int32 *, 
+				     AUTH_DAT **, Key_schedule, char *);
+
+krb5_error_code
+krb5_compat_recvauth_version(krb5_context, krb5_auth_context *,
+			     krb5_pointer, krb5_principal, krb5_int32, 
+			     krb5_keytab, krb5_int32, char *, char *,
+			     struct sockaddr_in *, struct sockaddr_in *,
+			     char *, krb5_ticket **, krb5_int32*, 
+			     AUTH_DAT **,  Key_schedule, krb5_data *);
+#endif
+
+#include "port-sockets.h"
+
+int accept_a_connection (int debug_port, struct sockaddr *from,
+			 socklen_t *fromlenp);
diff --git a/mechglue/src/appl/bsd/forward.c b/mechglue/src/appl/bsd/forward.c
new file mode 100644
index 000000000..53f67e667
--- /dev/null
+++ b/mechglue/src/appl/bsd/forward.c
@@ -0,0 +1,77 @@
+/*
+ * appl/bsd/forward.c
+ */
+
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(KERBEROS) || defined(KRB5)
+#include <stdio.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "k5-int.h"
+
+#define SKIP_V4_PROTO /* To skip the krb4 prototypes */
+#include "defines.h"
+
+/* Decode, decrypt and store the forwarded creds in the local ccache. */
+krb5_error_code
+rd_and_store_for_creds(context, auth_context, inbuf, ticket, ccache)
+    krb5_context context;
+    krb5_auth_context auth_context;
+    krb5_data *inbuf;
+    krb5_ticket *ticket;
+    krb5_ccache *ccache;
+{
+    krb5_creds ** creds;
+    krb5_error_code retval;
+    char ccname[35];
+
+    *ccache  = NULL;
+
+    retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL);
+    if (retval) 
+	return(retval);
+
+    /* Set the KRB5CCNAME ENV variable to keep sessions 
+     * seperate. Use the process id of this process which is 
+     * the rlogind or rshd. Set the environment variable as well.
+     */
+  
+    sprintf(ccname, "FILE:/tmp/krb5cc_p%ld", (long) getpid());
+    setenv("KRB5CCNAME", ccname, 1);
+  
+    retval = krb5_cc_resolve(context, ccname, ccache);
+    if (retval) 
+	goto cleanup;
+
+    retval = krb5_cc_initialize(context, *ccache, ticket->enc_part2->client);
+    if (retval)
+	goto cleanup;
+
+    retval = krb5_cc_store_cred(context, *ccache, *creds);
+    if (retval) 
+	goto cleanup;
+
+cleanup:
+    krb5_free_creds(context, *creds);
+    return retval;
+}
+
+#endif /* KERBEROS */
diff --git a/mechglue/src/appl/bsd/getdtablesize.c b/mechglue/src/appl/bsd/getdtablesize.c
new file mode 100644
index 000000000..244616cc9
--- /dev/null
+++ b/mechglue/src/appl/bsd/getdtablesize.c
@@ -0,0 +1,19 @@
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <limits.h>
+
+#ifdef _SC_OPEN_MAX
+int getdtablesize() {
+    return sysconf(_SC_OPEN_MAX);
+}
+#else
+#include <sys/resource.h>
+/* Placed in the Public Domain by Mark Eichin, Cygnus Support 1994 */
+
+int getdtablesize() {
+    struct rlimit rl;
+    getrlimit(RLIMIT_NOFILE, &rl);
+    return rl.rlim_cur;
+}
+#endif
diff --git a/mechglue/src/appl/bsd/kcmd.c b/mechglue/src/appl/bsd/kcmd.c
new file mode 100644
index 000000000..7c00d9746
--- /dev/null
+++ b/mechglue/src/appl/bsd/kcmd.c
@@ -0,0 +1,1369 @@
+/*
+ * appl/bsd/kcmd.c
+ */
+
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* derived from @(#)rcmd.c	5.17 (Berkeley) 6/27/88 */
+     
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/param.h>
+#ifndef _TYPES_
+#include <sys/types.h>
+#define _TYPES_
+#endif
+#include <fcntl.h>
+     
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+#include <signal.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+
+#ifndef POSIX_SIGNALS
+#ifndef sigmask
+#define sigmask(m)    (1 << ((m)-1))
+#endif
+#endif
+     
+#ifndef roundup
+#define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
+#endif
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <errno.h>
+#include <krb5.h>
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+
+#include "defines.h"
+
+extern krb5_context bsd_context;
+#ifdef KRB5_KRB4_COMPAT
+extern Key_schedule v4_schedule;
+#endif
+
+
+#define START_PORT      5120     /* arbitrary */
+char *default_service = "host";
+
+#define KCMD_KEYUSAGE	1026 /* Key usage used   with 3des or any old-protocol enctype*/
+/* New protocol enctypes that use cipher state have keyusage defined later*/
+
+#ifndef GETSOCKNAME_ARG3_TYPE
+#define GETSOCKNAME_ARG3_TYPE int
+#endif
+
+/*
+ * Note that the encrypted rlogin packets take the form of a four-byte
+ * length followed by encrypted data.  On writing the data out, a significant
+ * performance penalty is suffered (at least one RTT per character, two if we
+ * are waiting for a shell to echo) by writing the data separately from the 
+ * length.  So, unlike the input buffer, which just contains the output
+ * data, the output buffer represents the entire packet.
+ */
+
+static char des_inbuf[2*RCMD_BUFSIZ];	 /* needs to be > largest read size */
+static char des_outpkt[2*RCMD_BUFSIZ+4]; /* needs to be > largest write size */
+static krb5_data desinbuf;
+static krb5_data desoutbuf;
+
+/* XXX Overloaded: use_ivecs!=0 -> new protocol, inband signalling, etc.  */
+static int use_ivecs;
+static krb5_keyusage enc_keyusage_i[2], enc_keyusage_o[2];
+static krb5_data encivec_i[2], encivec_o[2];
+
+static krb5_keyblock *keyblock;		 /* key for encrypt/decrypt */
+static int (*input)(int, char *, size_t, int);
+static int (*output)(int, char *, size_t, int);
+static char storage[2*RCMD_BUFSIZ];	 /* storage for the decryption */
+static size_t nstored = 0;
+static char *store_ptr = storage;
+static int twrite(int, char *, size_t, int);
+static int v5_des_read(int, char *, size_t, int), 
+    v5_des_write(int, char *, size_t, int);
+#ifdef KRB5_KRB4_COMPAT
+static int v4_des_read(int, char *, size_t, int), 
+    v4_des_write(int, char *, size_t, int);
+static C_Block v4_session;
+static int right_justify;
+#endif
+static int do_lencheck;
+
+#ifdef KRB5_KRB4_COMPAT
+extern int
+krb_sendauth(long options, int fd, KTEXT ticket,
+	     char *service, char *inst, char *realm,
+	     unsigned KRB4_32 checksum,
+	     MSG_DAT *msg_data,
+	     CREDENTIALS *cred,
+	     Key_schedule schedule,
+	     struct sockaddr_in *laddr,
+	     struct sockaddr_in *faddr,
+	     char *version);
+#endif
+
+#ifdef POSIX_SIGNALS
+typedef sigset_t masktype;
+#else
+typedef sigmasktype masktype;
+#endif
+
+static void
+block_urgent (masktype *oldmask)
+{
+#ifdef POSIX_SIGNALS
+    sigset_t urgmask;
+
+    sigemptyset(&urgmask);
+    sigaddset(&urgmask, SIGURG);
+    sigprocmask(SIG_BLOCK, &urgmask, oldmask);
+#else
+    *oldmask = sigblock(sigmask(SIGURG));
+#endif /* POSIX_SIGNALS */
+}
+
+static void
+restore_sigs (masktype *oldmask)
+{
+#ifdef POSIX_SIGNALS
+    sigprocmask(SIG_SETMASK, oldmask, (sigset_t*)0);
+#else
+    sigsetmask(*oldmask);
+#endif /* POSIX_SIGNALS */
+}
+
+static int
+kcmd_connect (int *sp, int *addrfamilyp, struct sockaddr_in *sockinp,
+	      char *hname, char **host_save, unsigned int rport, int *lportp,
+	      struct sockaddr_in *laddrp)
+{
+    int s, aierr;
+    struct addrinfo *ap, *ap2, aihints;
+    char rport_buf[10];
+    GETSOCKNAME_ARG3_TYPE  sin_len;
+
+    if (rport == 0) {
+	fprintf(stderr, "can't connect to %s port 0\n", hname);
+	return -1;
+    }
+    sprintf(rport_buf, "%d", ntohs(rport));
+    memset(&aihints, 0, sizeof(aihints));
+    aihints.ai_socktype = SOCK_STREAM;
+    aihints.ai_flags = AI_CANONNAME;
+    aihints.ai_family = *addrfamilyp;
+    aierr = getaddrinfo(hname, rport_buf, &aihints, &ap);
+    if (aierr) {
+	const char *msg;
+	/* We want to customize some messages.  */
+	switch (aierr) {
+	case EAI_NONAME:
+	    msg = "host unknown";
+	    break;
+	default:
+	    fprintf(stderr, "foo\n");
+	    msg = gai_strerror(aierr);
+	    break;
+	}
+	fprintf(stderr, "%s: %s\n", hname, msg);
+	return -1;
+    }
+    if (ap == 0) {
+	fprintf(stderr, "%s: no addresses?\n", hname);
+	return -1;
+    }
+
+    *host_save = strdup(ap->ai_canonname ? ap->ai_canonname : hname);
+
+    for (ap2 = ap; ap; ap = ap->ai_next) {
+	char hostbuf[NI_MAXHOST];
+	char portbuf[NI_MAXSERV];
+	int oerrno;
+	int af = ap->ai_family;
+
+	/* @@ Debugging.  Yuck.  */
+	switch (af) {
+	case AF_INET:
+	    if (((struct sockaddr_in *)ap->ai_addr)->sin_port == 0) {
+		fprintf(stderr, "internal error: got ipv4 address but port zero?\n");
+		continue;
+	    }
+	    break;
+#ifdef KRB5_USE_INET6
+	case AF_INET6:
+	    if (((struct sockaddr_in6 *)ap->ai_addr)->sin6_port == 0) {
+		fprintf(stderr, "internal error: got ipv6 address but port zero?\n");
+		continue;
+	    }
+	    break;
+#endif
+	}
+
+	for (;;) {
+	    s = getport(lportp, &af);
+	    if (s < 0) {
+		if (errno == EAGAIN)
+		    fprintf(stderr, "socket: All ports in use\n");
+		else
+		    perror("kcmd: socket");
+		return -1;
+	    }
+	    if (connect(s, ap->ai_addr, ap->ai_addrlen) >= 0)
+		goto connected;
+	    (void) close(s);
+	    if (errno != EADDRINUSE)
+		break;
+	    if (lportp)
+		(*lportp)--;
+	}
+
+	oerrno = errno;
+	aierr = getnameinfo(ap->ai_addr, ap->ai_addrlen,
+			    hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
+			    NI_NUMERICHOST | NI_NUMERICSERV);
+	if (aierr)
+	    fprintf(stderr, "connect to <error formatting address: %s>: ",
+		    gai_strerror (aierr));
+	else
+	    fprintf(stderr, "connect to address %s port %s: ", hostbuf,
+		    portbuf);
+	errno = oerrno;
+	perror(0);
+
+	if (ap->ai_next)
+	    fprintf(stderr, "Trying next address...\n");
+    }
+    freeaddrinfo(ap2);
+    return -1;
+
+connected:
+    sin_len = sizeof(struct sockaddr_in);
+    if (getsockname(s, (struct sockaddr *)laddrp, &sin_len) < 0) {
+	perror("getsockname");
+	close(s);
+	return -1;
+    }
+
+    *sp = s;
+    *sockinp = *(struct sockaddr_in *) ap->ai_addr;
+    *addrfamilyp = ap->ai_family;
+    freeaddrinfo(ap2);
+    return 0;
+}
+
+static int
+setup_secondary_channel (int s, int *fd2p, int *lportp, int *addrfamilyp,
+			 struct sockaddr_in *fromp, int anyport)
+{
+    if (fd2p == 0) {
+    	write(s, "", 1);
+    	*lportp = 0;
+    } else {
+    	char num[8];
+    	socklen_t len = sizeof (*fromp);
+	size_t slen;
+    	int s2 = getport(lportp, addrfamilyp), s3;
+	fd_set rfds, xfds;
+	struct timeval waitlen;
+	int n;
+
+	*fd2p = -1;
+	if (s2 < 0)
+	    return -1;
+	FD_ZERO(&rfds);
+	FD_ZERO(&xfds);
+	FD_SET(s, &rfds);
+	FD_SET(s, &xfds);
+	listen(s2, 1);
+	FD_SET(s2, &rfds);
+    	(void) sprintf(num, "%d", *lportp);
+	slen = strlen(num)+1;
+    	if (write(s, num, slen) != slen) {
+	    perror("write: setting up stderr");
+	    (void) close(s2);
+	    return -1;
+    	}
+	waitlen.tv_sec = 600;	/* long, but better than infinite */
+	waitlen.tv_usec = 0;
+	n = (s < s2) ? s2 : s;
+	n = select(n+1, &rfds, 0, &xfds, &waitlen);
+	if (n <= 0) {
+	    /* timeout or error */
+	    fprintf(stderr, "timeout in circuit setup\n");
+	    close(s2);
+	    *fd2p = -1;
+	    return -1;
+	} else {
+	    if (FD_ISSET(s, &rfds) || FD_ISSET(s, &xfds)) {
+		fprintf(stderr, "socket: protocol error or closed connection in circuit setup\n");
+		close(s2);
+		*fd2p = -1;
+		return -1;
+	    }
+	    /* ready to accept a connection; yay! */
+	}
+    	s3 = accept(s2, (struct sockaddr *)fromp, &len);
+    	(void) close(s2);
+    	if (s3 < 0) {
+	    perror("accept");
+	    *lportp = 0;
+	    return -1;
+    	}
+    	*fd2p = s3;
+    	fromp->sin_port = ntohs(fromp->sin_port);
+	/* This check adds nothing when using Kerberos.  */
+    	if (! anyport &&
+	    (fromp->sin_family != AF_INET ||
+    	     fromp->sin_port >= IPPORT_RESERVED)) {
+	    fprintf(stderr, "socket: protocol failure in circuit setup.\n");
+	    close(s3);
+	    *fd2p = -1;
+	    return -1;
+    	}
+    }
+    return 0;
+}
+
+int
+kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
+     cred, seqno, server_seqno, laddr, faddr, authconp, authopts, anyport,
+     suppress_err, protonump)
+     int *sock;
+     char **ahost;
+     u_short rport;
+     char *locuser, *remuser, *cmd;
+     int *fd2p;
+     char *service;
+     char *realm;
+     krb5_creds **cred; /* output only */
+     krb5_int32 *seqno;
+     krb5_int32 *server_seqno;
+     struct sockaddr_in *laddr, *faddr;
+     krb5_auth_context *authconp;
+     krb5_flags authopts;
+     int anyport;
+     int suppress_err;		/* Don't print if authentication fails */
+     enum kcmd_proto *protonump;
+{
+    int s;
+    masktype oldmask;
+    struct sockaddr_in sockin, from, local_laddr;
+    krb5_creds *get_cred = 0, *ret_cred = 0;
+    char c;
+    int lport;
+    int rc;
+    char *host_save;
+    krb5_error_code status;
+    krb5_ap_rep_enc_part *rep_ret;
+    krb5_error	*error = 0;
+    krb5_ccache cc;
+    krb5_data outbuf;
+    krb5_flags options = authopts;
+    krb5_auth_context auth_context = NULL;
+    char *cksumbuf;
+    krb5_data cksumdat;
+    char *kcmd_version;
+    enum kcmd_proto protonum = *protonump;
+    int addrfamily = /* AF_INET */0;
+
+    if ((cksumbuf = malloc(strlen(cmd)+strlen(remuser)+64)) == 0 ) {
+	fprintf(stderr, "Unable to allocate memory for checksum buffer.\n");
+	return(-1);
+    }
+    sprintf(cksumbuf, "%u:", ntohs(rport));
+    strcat(cksumbuf, cmd);
+    strcat(cksumbuf, remuser);
+    cksumdat.data = cksumbuf;
+    cksumdat.length = strlen(cksumbuf);
+	
+    block_urgent(&oldmask);
+    
+    if (!laddr) laddr = &local_laddr;
+    if (kcmd_connect(&s, &addrfamily, &sockin, *ahost, &host_save, rport, 0, laddr) == -1) {
+	restore_sigs(&oldmask);
+	return -1;
+    }
+    *ahost = host_save;
+    /* If no service is given set to the default service */
+    if (!service) service = default_service;
+    
+    if (!(get_cred = (krb5_creds *)calloc(1, sizeof(krb5_creds)))) {
+        fprintf(stderr,"kcmd: no memory\n");
+        return(-1);
+    }
+    status = krb5_sname_to_principal(bsd_context, host_save, service,
+				     KRB5_NT_SRV_HST, &get_cred->server);
+    if (status) {
+	fprintf(stderr, "kcmd: krb5_sname_to_principal failed: %s\n",
+		error_message(status));
+	return(-1);
+    }
+
+    if (realm && *realm) {
+        status = krb5_set_principal_realm(bsd_context, get_cred->server,
+					  realm);
+	if (status) {
+	  fprintf(stderr, "kcmd: krb5_set_principal_realm failed %s\n", 
+		  error_message(status));
+	  return(-1);
+	}
+    }
+    status = setup_secondary_channel(s, fd2p, &lport, &addrfamily, &from,
+				     anyport);
+    if (status)
+	goto bad;
+
+    if (faddr)
+	*faddr = sockin;
+
+    status = krb5_cc_default(bsd_context, &cc);
+    if (status)
+    	goto bad2;
+
+    status = krb5_cc_get_principal(bsd_context, cc, &get_cred->client);
+    if (status) {
+    	(void) krb5_cc_close(bsd_context, cc);
+    	goto bad2;
+    }
+
+    /* Get ticket from credentials cache or kdc */
+    status = krb5_get_credentials(bsd_context, 0, cc, get_cred, &ret_cred);
+    krb5_free_creds(bsd_context, get_cred);
+    (void) krb5_cc_close(bsd_context, cc);
+    if (status) {
+	fprintf (stderr, "error getting credentials: %s\n",
+		 error_message (status));
+	goto bad2;
+    }
+
+    /* Reset internal flags; these should not be sent. */
+    authopts &= (~OPTS_FORWARD_CREDS);
+    authopts &= (~OPTS_FORWARDABLE_CREDS);
+
+    if (krb5_auth_con_init(bsd_context, &auth_context)) 
+	goto bad2;
+
+    if (krb5_auth_con_setflags(bsd_context, auth_context, 
+			       KRB5_AUTH_CONTEXT_RET_TIME))
+	goto bad2;
+
+    /* Only need local address for mk_cred() to send to krlogind */
+    status = krb5_auth_con_genaddrs(bsd_context, auth_context, s,
+				   KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
+    if (status)
+	goto bad2;
+
+    if (protonum == KCMD_PROTOCOL_COMPAT_HACK) {
+	krb5_boolean is_des;
+	status = krb5_c_enctype_compare (bsd_context, ENCTYPE_DES_CBC_CRC,
+					 ret_cred->keyblock.enctype, &is_des);
+	if (status)
+	    goto bad2;
+	protonum = is_des ? KCMD_OLD_PROTOCOL : KCMD_NEW_PROTOCOL;
+    }
+
+    switch (protonum) {
+    case KCMD_NEW_PROTOCOL:
+	authopts |= AP_OPTS_USE_SUBKEY;
+	kcmd_version = "KCMDV0.2";
+	break;
+    case KCMD_OLD_PROTOCOL:
+	kcmd_version = "KCMDV0.1";
+	break;
+    default:
+	status = EINVAL;
+	goto bad2;
+    }
+
+    /* Call Kerberos library routine to obtain an authenticator,
+       pass it over the socket to the server, and obtain mutual
+       authentication.  */
+    status = krb5_sendauth(bsd_context, &auth_context, (krb5_pointer) &s,
+			   kcmd_version, ret_cred->client, ret_cred->server,
+			   authopts, &cksumdat, ret_cred, 0,
+			   &error, &rep_ret, NULL);
+    free(cksumbuf);
+    if (status) {
+	if (!suppress_err)
+	    fprintf(stderr, "Couldn't authenticate to server: %s\n",
+		    error_message(status));
+	if (error) {
+	    if (!suppress_err) {
+		fprintf(stderr, "Server returned error code %d (%s)\n",
+			error->error,
+			error_message(ERROR_TABLE_BASE_krb5 + 
+				      (int) error->error));
+		if (error->text.length) {
+		    fprintf(stderr, "Error text sent from server: %s\n",
+			    error->text.data);
+		}
+	    }
+	    krb5_free_error(bsd_context, error);
+	    error = 0;
+	}
+    }	
+    if (status) goto bad2;
+    if (rep_ret && server_seqno) {
+	*server_seqno = rep_ret->seq_number;
+	krb5_free_ap_rep_enc_part(bsd_context, rep_ret);
+    }
+    
+    (void) write(s, remuser, strlen(remuser)+1);
+    (void) write(s, cmd, strlen(cmd)+1);
+    (void) write(s, locuser, strlen(locuser)+1);
+    
+    if (options & OPTS_FORWARD_CREDS) {   /* Forward credentials */
+	status = krb5_fwd_tgt_creds(bsd_context, auth_context,
+				    host_save,
+				    ret_cred->client, ret_cred->server,
+				    0, options & OPTS_FORWARDABLE_CREDS,
+				    &outbuf);
+	if (status) {
+	    fprintf(stderr, "kcmd: Error getting forwarded creds\n");
+	    goto bad2;
+	}
+
+	/* Send forwarded credentials */
+	status = krb5_write_message(bsd_context, (krb5_pointer)&s, &outbuf);
+	if (status)
+	  goto bad2;
+    }
+    else { /* Dummy write to signal no forwarding */
+	outbuf.length = 0;
+	status = krb5_write_message(bsd_context, (krb5_pointer)&s, &outbuf);
+	if (status)
+	  goto bad2;
+    }
+
+    if ((rc=read(s, &c, 1)) != 1) {
+	if (rc==-1) {
+	    perror(*ahost);
+	} else {
+	    fprintf(stderr,"kcmd: bad connection with remote host\n");
+	}
+	status = -1;
+	goto bad2;
+    }
+    if (c != 0) {
+	while (read(s, &c, 1) == 1) {
+	    (void) write(2, &c, 1);
+	    if (c == '\n')
+	      break;
+	}
+	status = -1;
+	goto bad2;
+    }
+    restore_sigs(&oldmask);
+    *sock = s;
+    *protonump = protonum;
+    
+    /* pass back credentials if wanted */
+    if (cred) krb5_copy_creds(bsd_context, ret_cred, cred);
+    krb5_free_creds(bsd_context, ret_cred);
+    if (authconp)
+	*authconp = auth_context;
+    
+    return (0);
+  bad2:
+    if (lport)
+      (void) close(*fd2p);
+  bad:
+    (void) close(s);
+    restore_sigs(&oldmask);
+    if (ret_cred)
+      krb5_free_creds(bsd_context, ret_cred);
+    return (status);
+}
+
+
+
+#ifdef KRB5_KRB4_COMPAT
+int
+k4cmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
+      cred, schedule, msg_data, laddr, faddr, authopts, anyport)
+     int *sock;
+     char **ahost;
+     unsigned int rport;
+     char *locuser, *remuser, *cmd;
+     int *fd2p;
+     KTEXT ticket;
+     char *service;
+     char *realm;
+     CREDENTIALS *cred;
+     Key_schedule schedule;
+     MSG_DAT *msg_data;
+     struct sockaddr_in *laddr, *faddr;
+     long authopts;
+     int anyport;
+{
+    int s;
+    masktype oldmask;
+    struct sockaddr_in sockin, from;
+    char c;
+    int lport = START_PORT;
+    int rc;
+    char *host_save;
+    int status;
+    int addrfamily = AF_INET;
+
+    block_urgent(&oldmask);
+    if (kcmd_connect (&s, &addrfamily, &sockin, *ahost, &host_save, rport, &lport, laddr) == -1) {
+	restore_sigs(&oldmask);
+	return -1;
+    }
+    *ahost = host_save;
+    /* If realm is null, look up from table */
+    if ((realm == NULL) || (realm[0] == '\0')) {
+	realm = krb_realmofhost(host_save);
+    }
+    lport--;
+    status = setup_secondary_channel(s, fd2p, &lport, &addrfamily, &from,
+				     anyport);
+    if (status)
+	goto bad;
+
+    /* set up the needed stuff for mutual auth */
+    *faddr = sockin;
+
+    status = krb_sendauth(authopts, s, ticket, service, *ahost,
+			  realm, (unsigned long) getpid(), msg_data,
+			  cred, schedule, laddr, faddr, "KCMDV0.1");
+    if (status != KSUCCESS) {
+	fprintf(stderr, "krb_sendauth failed: %s\n", krb_get_err_text(status));
+	status = -1;
+	goto bad2;
+    }
+    (void) write(s, remuser, strlen(remuser)+1);
+    (void) write(s, cmd, strlen(cmd)+1);
+
+reread:
+    if ((rc=read(s, &c, 1)) != 1) {
+	if (rc==-1) {
+	    perror(*ahost);
+	} else {
+	    fprintf(stderr,"rcmd: bad connection with remote host\n");
+	}
+	status = -1;
+	goto bad2;
+    }
+    if (c != 0) {
+	/* If rlogind was compiled on SunOS4, and it somehow
+	   got the shared library version numbers wrong, it
+	   may give an ld.so warning about an old version of a
+	   shared library.  Just ignore any such warning.
+	   Note that the warning is a characteristic of the
+	   server; we may not ourselves be running under
+	   SunOS4.  */
+	if (c == 'l') {
+	    char *check = "d.so: warning:";
+	    char *p;
+	    char cc;
+
+	    p = check;
+	    while (read(s, &c, 1) == 1) {
+		if (*p == '\0') {
+		    if (c == '\n')
+			break;
+		} else {
+		    if (c != *p)
+			break;
+		    ++p;
+		}
+	    }
+
+	    if (*p == '\0')
+		goto reread;
+
+	    cc = 'l';
+	    (void) write(2, &cc, 1);
+	    if (p != check)
+		(void) write(2, check, (unsigned) (p - check));
+	}
+
+	(void) write(2, &c, 1);
+	while (read(s, &c, 1) == 1) {
+	    (void) write(2, &c, 1);
+	    if (c == '\n')
+		break;
+	}
+	status = -1;
+	goto bad2;
+    }
+    restore_sigs(&oldmask);
+    *sock = s;
+    return (KSUCCESS);
+ bad2:
+    if (lport)
+	(void) close(*fd2p);
+ bad:
+    (void) close(s);
+    restore_sigs(&oldmask);
+    return (status);
+}
+#endif /* KRB5_KRB4_COMPAT */
+
+
+static int
+setup_socket (struct sockaddr *sa, GETSOCKNAME_ARG3_TYPE len)
+{
+    int s;
+
+    s = socket(sa->sa_family, SOCK_STREAM, 0);
+    if (s < 0)
+	return -1;
+
+    if (bind(s, sa, len) < 0)
+	return -1;
+    if (getsockname(s, sa, &len) < 0) {
+	close(s);
+	return -1;
+    }
+    return s;
+}
+
+
+int
+getport(alport, family)
+    int *alport, *family;
+{
+    int s;
+
+    if (*family == 0) {
+#ifdef KRB5_USE_INET6
+	*family = AF_INET6;
+	s = getport (alport, family);
+	if (s >= 0)
+	    return s;
+#endif
+	*family = AF_INET;
+    }
+
+#ifdef KRB5_USE_INET6
+    if (*family == AF_INET6) {
+	struct sockaddr_in6 sockin6;
+
+	memset(&sockin6, 0, sizeof(sockin6));
+	sockin6.sin6_family = AF_INET6;
+	sockin6.sin6_addr = in6addr_any;
+
+	s = setup_socket((struct sockaddr *)&sockin6, sizeof (sockin6));
+	if (s >= 0 && alport)
+	    *alport = ntohs(sockin6.sin6_port);
+	return s;
+    }
+#endif
+
+    if (*family == AF_INET) {
+	struct sockaddr_in sockin;
+
+	memset(&sockin, 0, sizeof(sockin));
+	sockin.sin_family = AF_INET;
+	sockin.sin_addr.s_addr = INADDR_ANY;
+
+	s = setup_socket((struct sockaddr *)&sockin, sizeof (sockin));
+	if (s >= 0 && alport)
+	    *alport = ntohs(sockin.sin_port);
+	return s;
+    }
+
+    return -1;
+}
+
+static int
+normal_read (int fd, char *buf, size_t len, int secondary)
+{
+    return read (fd, buf, len);
+}
+
+void rcmd_stream_init_normal()
+{
+    input = normal_read;
+    output = twrite;
+}
+
+void rcmd_stream_init_krb5(in_keyblock, encrypt_flag, lencheck, am_client,
+			   protonum)
+     krb5_keyblock *in_keyblock;
+     int encrypt_flag;
+     int lencheck;
+     int am_client;
+     enum kcmd_proto protonum;
+{
+    krb5_error_code status;
+    size_t blocksize;
+    int i;
+    krb5_error_code ret;
+
+    if (!encrypt_flag) {
+	rcmd_stream_init_normal();
+	return;
+    }
+    desinbuf.data = des_inbuf;
+    desoutbuf.data = des_outpkt+4;	/* Set up des buffers */
+    keyblock = in_keyblock;
+
+    do_lencheck = lencheck;
+    input = v5_des_read;
+    output = v5_des_write;
+    enc_keyusage_i[0] = KCMD_KEYUSAGE;
+    enc_keyusage_i[1] = KCMD_KEYUSAGE;
+    enc_keyusage_o[0] = KCMD_KEYUSAGE;
+    enc_keyusage_o[1] = KCMD_KEYUSAGE;
+
+    if (protonum == KCMD_OLD_PROTOCOL) {
+	use_ivecs = 0;
+	return;
+    }
+
+    use_ivecs = 1;
+    switch (in_keyblock->enctype) {
+      /* 
+       * For the DES-based enctypes and the 3DES enctype we  want to use
+       *  a non-zero  IV because that's what we did.  In the future we
+       * use different keyusage for each channel and direction and a fresh
+       * cipher state
+       */
+    case ENCTYPE_DES_CBC_CRC:
+    case ENCTYPE_DES_CBC_MD4:
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES3_CBC_SHA1:
+      
+      status = krb5_c_block_size(bsd_context, keyblock->enctype,
+				 &blocksize);
+      if (status) {
+	/* XXX what do I do? */
+	abort();
+      }
+
+      encivec_i[0].length = encivec_i[1].length = encivec_o[0].length
+	= encivec_o[1].length = blocksize;
+
+      if ((encivec_i[0].data = malloc(encivec_i[0].length * 4)) == NULL) {
+	/* XXX what do I do? */
+	abort();
+      }
+      encivec_i[1].data = encivec_i[0].data + encivec_i[0].length;
+      encivec_o[0].data = encivec_i[1].data + encivec_i[0].length;
+      encivec_o[1].data = encivec_o[0].data + encivec_i[0].length;
+
+    /* is there a better way to initialize this? */
+      memset(encivec_i[0].data, am_client, blocksize);
+      memset(encivec_o[0].data, 1 - am_client, blocksize);
+      memset(encivec_i[1].data, 2 | am_client, blocksize);
+      memset(encivec_o[1].data, 2 | (1 - am_client), blocksize);
+      break;
+    default:
+      if (am_client) {
+	enc_keyusage_i[0] = 1028;
+	enc_keyusage_i[1] = 1030;
+	enc_keyusage_o[0] = 1032;
+	enc_keyusage_o[1] = 1034;
+      } else { /*am_client*/
+	enc_keyusage_i[0] = 1032;
+	enc_keyusage_i[1] = 1034;
+	enc_keyusage_o[0] = 1028;
+	enc_keyusage_o[1] = 1030;
+      }
+      for (i = 0; i < 2; i++) {
+	ret = krb5_c_init_state (bsd_context, in_keyblock, enc_keyusage_i[i],
+				 &encivec_i[i]);
+	if (ret)
+	  goto fail;
+	ret = krb5_c_init_state (bsd_context, in_keyblock, enc_keyusage_o[i],
+				 &encivec_o[i]);
+	if (ret)
+	  goto fail;
+      }
+      break;
+    }
+    return;
+ fail:
+    com_err ("kcmd", ret, "Initializing cipher state");
+    abort();
+    }
+
+#ifdef KRB5_KRB4_COMPAT
+void rcmd_stream_init_krb4(session, encrypt_flag, lencheck, justify)
+     C_Block session;
+     int encrypt_flag;
+     int lencheck;
+     int justify;
+{
+    if (!encrypt_flag) {
+	rcmd_stream_init_normal();
+	return;
+    }
+    do_lencheck = lencheck;
+    right_justify = justify;
+    input = v4_des_read;
+    output = v4_des_write;
+    memcpy(v4_session, session, sizeof(v4_session));
+}
+#endif
+
+int rcmd_stream_read(fd, buf, len, sec)
+     int fd;
+     register char *buf;
+     size_t len;
+     int sec;
+{
+    return (*input)(fd, buf, len, sec);
+}
+
+int rcmd_stream_write(fd, buf, len, sec)
+     int fd;
+     register char *buf;
+     size_t len;
+     int sec;
+{
+    return (*output)(fd, buf, len, sec);
+}
+
+/* Because of rcp lossage, translate fd 0 to 1 when writing. */
+static int twrite(fd, buf, len, secondary)
+     int fd;
+     char *buf;
+     size_t len;
+     int secondary;
+{
+    return write((fd == 0) ? 1 : fd, buf, len);
+}
+
+static int v5_des_read(fd, buf, len, secondary)
+     int fd;
+     char *buf;
+     size_t len;
+     int secondary;
+{
+    int nreturned = 0;
+    size_t net_len,rd_len;
+    int cc;
+    unsigned char c;
+    krb5_error_code ret;
+    krb5_data plain;
+    krb5_enc_data cipher;
+    
+    if (nstored >= len) {
+	memcpy(buf, store_ptr, len);
+	store_ptr += len;
+	nstored -= len;
+	return(len);
+    } else if (nstored) {
+	memcpy(buf, store_ptr, nstored);
+	nreturned += nstored;
+	buf += nstored;
+	len -= nstored;
+	nstored = 0;
+    }
+
+    /* See the comment in v4_des_read. */
+    while (1) {
+	cc = krb5_net_read(bsd_context, fd, &c, 1);
+	/* we should check for non-blocking here, but we'd have
+	   to make it save partial reads as well. */
+	if (cc <= 0) return cc; /* read error */
+	if (cc == 1) {
+	    if (c == 0 || !do_lencheck) break;
+	}
+    }
+
+    rd_len = c;
+    if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
+    rd_len = (rd_len << 8) | c;
+    if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
+    rd_len = (rd_len << 8) | c;
+    if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
+    rd_len = (rd_len << 8) | c;
+
+    ret = krb5_c_encrypt_length(bsd_context, keyblock->enctype,
+				use_ivecs ? rd_len + 4 : rd_len,
+				&net_len);
+    if (ret) {
+	errno = ret;
+	return(-1);
+    }
+
+    if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) {
+	/* preposterous length, probably out of sync */
+	errno = EIO;
+	return(-1);
+    }
+    if ((cc = krb5_net_read(bsd_context, fd, desinbuf.data, net_len)) != net_len) {
+	/* probably out of sync */
+	errno = EIO;
+	return(-1);
+    }
+
+    cipher.enctype = ENCTYPE_UNKNOWN;
+    cipher.ciphertext.length = net_len;
+    cipher.ciphertext.data = desinbuf.data;
+    plain.length = sizeof(storage);
+    plain.data = storage;
+
+    /* decrypt info */
+    ret = krb5_c_decrypt(bsd_context, keyblock, enc_keyusage_i[secondary],
+			 use_ivecs ? encivec_i + secondary : 0,
+			 &cipher, &plain);
+    if (ret) {
+	/* probably out of sync */
+	errno = EIO;
+	return(-1);
+    }
+    store_ptr = storage;
+    nstored = rd_len;
+    if (use_ivecs) {
+	int rd_len2;
+	rd_len2 = storage[0] & 0xff;
+	rd_len2 <<= 8; rd_len2 |= storage[1] & 0xff;
+	rd_len2 <<= 8; rd_len2 |= storage[2] & 0xff;
+	rd_len2 <<= 8; rd_len2 |= storage[3] & 0xff;
+	if (rd_len2 != rd_len) {
+	    /* cleartext length trashed? */
+	    errno = EIO;
+	    return -1;
+	}
+	store_ptr += 4;
+    }
+    if (nstored > len) {
+	memcpy(buf, store_ptr, len);
+	nreturned += len;
+	store_ptr += len;
+	nstored -= len;
+    } else {
+	memcpy(buf, store_ptr, nstored);
+	nreturned += nstored;
+	nstored = 0;
+    }
+
+    return(nreturned);
+}
+
+
+
+static int v5_des_write(fd, buf, len, secondary)
+     int fd;
+     char *buf;
+     size_t len;
+     int secondary;
+{
+    krb5_data plain;
+    krb5_enc_data cipher;
+    char tmpbuf[2*RCMD_BUFSIZ+8];
+    unsigned char *len_buf = (unsigned char *) tmpbuf;
+
+    if (use_ivecs) {
+	unsigned char *lenbuf2 = (unsigned char *) tmpbuf;
+	if (len + 4 > sizeof(tmpbuf))
+	    abort ();
+	lenbuf2[0] = (len & 0xff000000) >> 24;
+	lenbuf2[1] = (len & 0xff0000) >> 16;
+	lenbuf2[2] = (len & 0xff00) >> 8;
+	lenbuf2[3] = (len & 0xff);
+	memcpy (tmpbuf + 4, buf, len);
+
+	plain.data = tmpbuf;
+	plain.length = len + 4;
+    } else {
+	plain.data = buf;
+	plain.length = len;
+    }
+
+    cipher.ciphertext.length = sizeof(des_outpkt)-4;
+    cipher.ciphertext.data = desoutbuf.data;
+
+    if (krb5_c_encrypt(bsd_context, keyblock, enc_keyusage_o[secondary],
+		       use_ivecs ? encivec_o + secondary : 0,
+		       &plain, &cipher)) {
+	errno = EIO;
+	return(-1);
+    }
+
+    desoutbuf.length = cipher.ciphertext.length;
+
+    len_buf = (unsigned char *) des_outpkt;
+    len_buf[0] = (len & 0xff000000) >> 24;
+    len_buf[1] = (len & 0xff0000) >> 16;
+    len_buf[2] = (len & 0xff00) >> 8;
+    len_buf[3] = (len & 0xff);
+
+    if (write(fd, des_outpkt,desoutbuf.length+4) != desoutbuf.length+4){
+	errno = EIO;
+	return(-1);
+    }
+
+    else return(len);
+}
+
+
+
+#ifdef KRB5_KRB4_COMPAT
+
+static int
+v4_des_read(fd, buf, len, secondary)
+int fd;
+char *buf;
+size_t len;
+int secondary;
+{
+	int nreturned = 0;
+	krb5_ui_4 net_len, rd_len;
+	int cc;
+	unsigned char c;
+
+	if (nstored >= len) {
+		memcpy(buf, store_ptr, len);
+		store_ptr += len;
+		nstored -= len;
+		return(len);
+	} else if (nstored) {
+		memcpy(buf, store_ptr, nstored);
+		nreturned += nstored;
+		buf += nstored;
+		len -= nstored;
+		nstored = 0;
+	}
+
+	/* We're fetching the length which is MSB first, and the MSB
+	   has to be zero unless the client is sending more than 2^24
+	   (16M) bytes in a single write (which is why this code is used
+	   in rlogin but not rcp or rsh.) The only reasons we'd get
+	   something other than zero are:
+		-- corruption of the tcp stream (which will show up when
+		   everything else is out of sync too)
+		-- un-caught Berkeley-style "pseudo out-of-band data" which
+		   happens any time the user hits ^C twice.
+	   The latter is *very* common, as shown by an 'rlogin -x -d' 
+	   using the CNS V4 rlogin.         Mark EIchin 1/95
+	   */
+	while (1) {
+	    cc = krb_net_read(fd, &c, 1);
+	    if (cc <= 0) return cc; /* read error */
+	    if (cc == 1) {
+		if (c == 0 || !do_lencheck) break;
+	    }
+	}
+
+	net_len = c;
+	if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
+	net_len = (net_len << 8) | c;
+	if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
+	net_len = (net_len << 8) | c;
+	if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
+	net_len = (net_len << 8) | c;
+
+	/* Note: net_len is unsigned */
+	if (net_len > sizeof(des_inbuf)) {
+		errno = EIO;
+		return(-1);
+	}
+	/* the writer tells us how much real data we are getting, but
+	   we need to read the pad bytes (8-byte boundary) */
+	rd_len = roundup(net_len, 8);
+	if ((cc = krb_net_read(fd, des_inbuf, rd_len)) != rd_len) {
+		errno = EIO;
+		return(-1);
+	}
+	(void) pcbc_encrypt((des_cblock *) des_inbuf,
+			    (des_cblock *) storage,
+			    (int) ((net_len < 8) ? 8 : net_len),
+			    v4_schedule,
+			    &v4_session,
+			    DECRYPT);
+	/* 
+	 * when the cleartext block is < 8 bytes, it is "right-justified"
+	 * in the block, so we need to adjust the pointer to the data
+	 */
+	if (net_len < 8 && right_justify)
+		store_ptr = storage + 8 - net_len;
+	else
+		store_ptr = storage;
+	nstored = net_len;
+	if (nstored > len) {
+		memcpy(buf, store_ptr, len);
+		nreturned += len;
+		store_ptr += len;
+		nstored -= len;
+	} else {
+		memcpy(buf, store_ptr, nstored);
+		nreturned += nstored;
+		nstored = 0;
+	}
+	
+	return(nreturned);
+}
+
+static int
+v4_des_write(fd, buf, len, secondary)
+int fd;
+char *buf;
+size_t len;
+int secondary;
+{
+	static char garbage_buf[8];
+	unsigned char *len_buf = (unsigned char *) des_outpkt;
+
+	/* 
+	 * pcbc_encrypt outputs in 8-byte (64 bit) increments
+	 *
+	 * it zero-fills the cleartext to 8-byte padding,
+	 * so if we have cleartext of < 8 bytes, we want
+	 * to insert random garbage before it so that the ciphertext
+	 * differs for each transmission of the same cleartext.
+	 * if len < 8 - sizeof(long), sizeof(long) bytes of random
+	 * garbage should be sufficient; leave the rest as-is in the buffer.
+	 * if len > 8 - sizeof(long), just garbage fill the rest.
+	 */
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a < b) ? a : b)
+
+	if (len < 8) {
+		if (right_justify) {
+			krb5_random_confounder(8 - len, garbage_buf);
+			/* this "right-justifies" the data in the buffer */
+			(void) memcpy(garbage_buf + 8 - len, buf, len);
+		} else {
+			krb5_random_confounder(8 - len, garbage_buf + len);
+			(void) memcpy(garbage_buf, buf, len);
+		}
+	}
+	(void) pcbc_encrypt((des_cblock *) ((len < 8) ? garbage_buf : buf),
+			    (des_cblock *) (des_outpkt+4),
+			    (int) ((len < 8) ? 8 : len),
+			    v4_schedule,
+			    &v4_session,
+			    ENCRYPT);
+
+	/* tell the other end the real amount, but send an 8-byte padded
+	   packet */
+	len_buf[0] = (len & 0xff000000) >> 24;
+	len_buf[1] = (len & 0xff0000) >> 16;
+	len_buf[2] = (len & 0xff00) >> 8;
+	len_buf[3] = (len & 0xff);
+	if (write(fd, des_outpkt, roundup(len,8)+4) != roundup(len,8)+4) {
+		errno = EIO;
+		return(-1);
+	}
+	return(len);
+}
+
+#endif /* KRB5_KRB4_COMPAT */
+
+#ifndef HAVE_STRSAVE
+/* Strsave was a routine in the version 4 krb library: we put it here
+   for compatablilty with version 5 krb library, since kcmd.o is linked
+   into all programs. */
+
+char *
+strsave(sp)
+    const char *sp;
+{
+    register char *ret;
+    
+    if((ret = (char *) malloc((unsigned) strlen(sp)+1)) == NULL) {
+	fprintf(stderr, "no memory for saving args\n");
+	exit(1);
+    }
+    (void) strcpy(ret,sp);
+    return(ret);
+}
+#endif
+
+/* Server side authentication, etc */
+
+int princ_maps_to_lname(principal, luser)	
+     krb5_principal principal;
+     char *luser;
+{
+    char kuser[10];
+    if (!(krb5_aname_to_localname(bsd_context, principal,
+				  sizeof(kuser), kuser))
+	&& (strcmp(kuser, luser) == 0)) {
+	return 1;
+    }
+    return 0;
+}
+
+int default_realm(principal)
+     krb5_principal principal;
+{
+    char *def_realm;
+    unsigned int realm_length;
+    int retval;
+    
+    realm_length = krb5_princ_realm(bsd_context, principal)->length;
+    
+    if ((retval = krb5_get_default_realm(bsd_context, &def_realm))) {
+	return 0;
+    }
+    
+    if ((realm_length != strlen(def_realm)) ||
+	(memcmp(def_realm, krb5_princ_realm(bsd_context, principal)->data, 
+		realm_length))) {
+	free(def_realm);
+	return 0;
+    }	
+    free(def_realm);
+    return 1;
+}
+
diff --git a/mechglue/src/appl/bsd/klogind.M b/mechglue/src/appl/bsd/klogind.M
new file mode 100644
index 000000000..a05406a74
--- /dev/null
+++ b/mechglue/src/appl/bsd/klogind.M
@@ -0,0 +1,196 @@
+.\" Copyright (c) 1983 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"	@(#)rlogind.8	6.3 (Berkeley) 5/24/86
+.\"
+.TH KLOGIND 8
+.SH NAME
+klogind \- remote login server
+.SH SYNOPSIS
+.B klogind
+[
+.B \-kr54cpPef
+]
+[[ \fB\-w\fP[\fBip\fP|\fImaxhostlen\fP[\fB,\fP[\fBno\fP]\fBstriplocal\fP ]] ]
+[ \fB\-D\fP \fIport\fP ]
+.SH DESCRIPTION
+.I Klogind
+is the server for the 
+.IR rlogin (1)
+program.  The server is 
+based on rlogind(8) but uses Kerberos authentication.
+.PP
+The 
+.I klogind
+server is invoked by \fIinetd(8)\fP when it receives a connection on
+the port indicated in /etc/inetd.conf.  A typical /etc/inetd.conf
+configuration line for \fIklogind\fP might be:
+
+klogin stream tcp nowait root /usr/cygnus/sbin/klogind klogind -e5c
+
+When a service request is received, the following protocol is initiated:
+
+.IP 1)
+Check authentication.
+.IP 2)
+Check authorization via the access-control files \fI.k5login\fP, \fI.klogin\fP 
+and \fI.rhosts\fP in the user's home directory.
+.IP 3)
+Prompt for password if any checks fail and the \fI-p\fP option was supplied.
+.PP
+If the authentication succeeds, login the user by calling the accompanying 
+login.krb5 or /bin/login, according to the definition of 
+DO_NOT_USE_K_LOGIN.  
+.PP 
+The configuration of \fIklogind\fP is done
+by command line arguments passed by inetd.  The options are:
+.IP \fB\-5\fP 10
+Allow Kerberos V5 authentication with the \fI.k5login\fP access control
+file to be trusted.  If this authentication system is used by the client
+and the authorization check is passed, then the user is allowed to log
+in.
+
+.IP \fB\-4\fP 
+Allow Kerberos V4 authentication with the \fI.klogin\fP access control
+file to be trusted.  If this authentication system is used by the client
+and the authorization check is passed, then the user is allowed to log
+in.
+
+.IP \fB\-k\fP 
+Allow Kerberos V5 and Kerberos V4 as acceptable authentication
+mechanisms.  This is the same as including \fB\-4\fP and \fB\-5\fP.
+
+
+.IP \fB\-p\fP
+ If all other authorization checks fail, prompt the user
+for a password If this option is not included, access is denied
+without successful authentication and authorization using one of the
+previous mechanisms.
+
+.IP \fB\-P\fP
+Prompt the user for a password.
+If the -P option is passed, then the password is verified in addition
+to all other checks.
+
+.IP \fB\-e\fP
+Create an encrypted session. 
+
+.IP \fB\-c\fP 
+Require Kerberos V5 clients to present a cryptographic checksum of
+initial connection information like the name of the user that the client
+is trying to access in the initial authenticator.  This checksum
+provides additionl security by preventing an attacker from changing the
+initial connection information.  To benefit from this security, only
+Kerberos V5 should be trusted; Kerberos V4 and rhosts authentication do
+not include this checksum.  If this option is specified, older Kerberos
+V5 clients that do not send a checksum in the authenticator will not be
+able to authenticate to this server.  This option is mutually exclusive
+with the \fB-i\fP option.
+
+	If neither the \fB-c\fP or \fB-i\fP options are specified,then
+checksums are validated if presented.  Since it is difficult to remove
+a checksum from an authenticator without making the authenticator
+invalid, this default mode is almost as significant of a security
+improvement as \fB-c\fP if new clients are used.  It has the additional
+advantage of backwards compatability with some clients.
+Unfortunately, clients before Kerberos V5, Beta5, generate invalid
+checksums; if these clients are used, the \fB-i\fP option must be
+used.
+
+.IP \fB\-i\fP 
+Ignore authenticator checksums if provided.  This option
+ignore authenticator checksusm presented by current Kerberos clients
+to protect initial connection information; it is the opposite of
+\fB-c\fP.  This option is provided because some older
+clients--particularly clients predating the release of Kerberos V5
+Beta5 (May 1995)--present bogus checksums that prevent Kerberos
+authentication from succeeding in the default mode.
+
+
+.PP
+If the
+~/.rhosts check is to be used, then the program verifies that the
+client is connecting from a privileged port, before allowing login.
+
+.PP
+The parent of the login process manipulates the master side of the
+pseduo terminal, operating as an intermediary between the login
+process and the client instance of the
+.I rlogin(1)
+program.  In normal operation, the packet protocol described in
+.IR pty (4)
+is invoked to provide ^S/^Q type facilities and propagate interrupt
+signals to the remote programs.  The login process propagates the
+client terminal's baud rate and terminal type, as found in the
+environment variable, ``TERM''; see
+.IR environ (7).
+The screen or
+window size of the terminal is requested from the client, and window
+size changes from the client are propagated to the pseudo terminal.
+
+.PP
+.I Klogind
+supports the following options to control the form of the hostname
+passed to login(1):
+
+.TP
+\fB\-w \fP[\fBip\fP|\fImaxhostlen\fP[\fB,\fP[\fBno\fP]\fBstriplocal\fP]]
+Controls the form of the remote hostname passed to login(1).
+Specifying \fBip\fP results in the numeric IP address always being
+passed to login(1).  Specifying a number, \fImaxhostlen\fP, sets the
+maximum length of the hostname passed to login(1) before it will be
+passed as a numeric IP address.  If \fImaxhostlen\fP is 0, then the
+system default, as determined by the utmp or utmpx structures, is
+used.  The \fBnostriplocal\fP and \fBstriplocal\fP options, which must
+be preceded by a comma, control whether or not the local host domain
+is stripped from the remote hostname.  By default, the equivalent of
+\fBstriplocal\fP is in effect.
+
+.PP
+.I Klogind
+supports five options which are used for testing
+purposes:
+
+.IP \fB\-S\ keytab\fP 10
+Set the \fIkeytab\fP file to use.
+
+.IP \fB\-M\ realm\fP
+Set the Kerberos realm to use.
+
+.IP \fB\-L\ login\fP
+Set the login program to use.  This option only has an effect if
+DO_NOT_USE_K_LOGIN was not defined when
+.I klogind
+was compiled.
+
+.IP \fB\-D\ port\fP
+Run in standalone mode, listening on \fBport\fP.  The daemon will exit
+after one connection and will not background itself.
+
+.IP \fB\-f\fP
+Allows for standalone daemon operation.  A new child is started for
+each incoming connection and waits for it to finish before accepting
+the next connection.  This automagically figures out which port to bind
+to if no port is specified.
+
+.SH DIAGNOSTICS
+All diagnostic messages are returned on the connection
+associated with the
+.BR stderr ,
+after which any network connections are closed.
+An error is indicated by a leading byte with a value of 1.
+.PP
+.B ``Try again.''
+.br
+A
+.I fork
+by the server failed.
+.PP
+.B ``/bin/sh: ...''
+.br
+The user's login shell could not be started.
+.SH SEE ALSO
+rlogind(8), rlogin(1)
+.SH BUGS
+A more extensible protocol should be used.
diff --git a/mechglue/src/appl/bsd/krcp.c b/mechglue/src/appl/bsd/krcp.c
new file mode 100644
index 000000000..707985a5a
--- /dev/null
+++ b/mechglue/src/appl/bsd/krcp.c
@@ -0,0 +1,1447 @@
+/*
+ *	appl/bsd/krcp.c
+ */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)rcp.c	5.10 (Berkeley) 9/20/88 */
+
+     /*
+      * rcp
+      */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <sys/param.h>
+#ifndef _TYPES_
+#include <sys/types.h>
+#define _TYPES_
+#endif
+#include <sys/file.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+     
+#include <netinet/in.h>
+     
+#include <stdio.h>
+#include <signal.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <sys/wait.h>
+
+#ifdef KERBEROS
+#include <krb5.h>
+#include <k5-util.h>
+#include <com_err.h>
+
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+
+#include "defines.h"
+
+#define RCP_BUFSIZ 4096
+     
+int sock;
+struct sockaddr_in local, foreign; /* set up by kcmd used by v4_send_auth */
+char *krb_realm = NULL;
+char *krb_cache = NULL;
+char *krb_config = NULL;
+krb5_encrypt_block eblock;         /* eblock for encrypt/decrypt */
+krb5_context bsd_context;
+
+#ifdef KRB5_KRB4_COMPAT
+Key_schedule v4_schedule;
+CREDENTIALS v4_cred;
+KTEXT_ST v4_ticket;
+MSG_DAT v4_msg_data;
+#endif
+
+void	v4_send_auth(char *, char *), try_normal(char **);
+char	**save_argv(int, char **);
+#ifndef HAVE_STRSAVE
+char	*strsave();
+#endif
+int	rcmd_stream_write(), rcmd_stream_read();
+void 	usage(void), sink(int, char **),
+    source(int, char **), rsource(char *, struct stat *), verifydir(char *), 
+    answer_auth(char *, char *);
+int	response(void), hosteq(char *, char *), okname(char *), 
+    susystem(char *);
+int	encryptflag = 0;
+
+#ifndef UCB_RCP
+#define	UCB_RCP	"/bin/rcp"
+#endif
+
+#endif /* KERBEROS */
+
+int	rem;
+char	*colon(char *);
+int	errs;
+krb5_sigtype	lostconn(int);
+int	iamremote, targetshouldbedirectory;
+int	iamrecursive;
+int	pflag;
+int	forcenet;
+struct	passwd *pwd;
+int	userid;
+int	port = 0;
+
+struct buffer {
+    unsigned int cnt;
+    char	*buf;
+};
+
+struct buffer *allocbuf(struct buffer *, int, int);
+
+#define	NULLBUF	(struct buffer *) 0
+  
+void 	error (char *fmt, ...)
+#if !defined (__cplusplus) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
+       __attribute__ ((__format__ (__printf__, 1, 2)))
+#endif
+     ;
+
+#define	ga()	 	(void) rcmd_stream_write(rem, "", 1, 0)
+
+int main(argc, argv)
+     int argc;
+     char **argv;
+{
+    char *targ, *host, *src;
+    char *suser, *tuser, *thost;
+    int i;
+    unsigned int cmdsiz = 30;
+    char buf[RCP_BUFSIZ], cmdbuf[30];
+    char *cmd = cmdbuf;
+    struct servent *sp;
+    static char curhost[256];
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+#ifdef KERBEROS
+    krb5_flags authopts;
+    krb5_error_code status;	
+    int euid;
+    char **orig_argv = save_argv(argc, argv);
+    krb5_auth_context auth_context;
+    enum kcmd_proto kcmd_proto = KCMD_PROTOCOL_COMPAT_HACK;
+
+    status = krb5_init_context(&bsd_context);
+    if (status) {
+	    com_err(argv[0], status, "while initializing krb5");
+	    exit(1);
+    }
+#endif
+
+    pwd = getpwuid(userid = getuid());
+    if (pwd == 0) {
+	fprintf(stderr, "who are you?\n");
+	exit(1);
+    }
+    
+    for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
+	(*argv)++;
+	while (**argv) switch (*(*argv)++) {
+	    
+	  case 'r':
+	    iamrecursive++;
+	    break;
+	    
+	  case 'p':		/* preserve mtimes and atimes */
+	    pflag++;
+	    break;
+	    
+	  case 'D':
+	    argc--, argv++;
+	    if (argc == 0)
+	      usage();
+	    port = htons(atoi(*argv));
+	    goto next_arg;
+
+	  case 'N':
+	    forcenet++;
+	    break;
+
+#ifdef KERBEROS
+	  case 'x':
+	    encryptflag++;
+	    break;
+	  case 'k':		/* Change kerberos realm */
+	    argc--, argv++;
+	    if (argc == 0) 
+	      usage();
+	    if(!(krb_realm = (char *)malloc(strlen(*argv) + 1))){
+		fprintf(stderr, "rcp: Cannot malloc.\n");
+		exit(1);
+	    }
+	    strcpy(krb_realm, *argv);	
+	    goto next_arg;
+	  case 'c':		/* Change default ccache file */
+	    argc--, argv++;
+	    if (argc == 0) 
+	      usage();
+	    if(!(krb_cache = (char *)malloc(strlen(*argv) + 1))){
+		fprintf(stderr, "rcp: Cannot malloc.\n");
+		exit(1);
+	    }
+	    strcpy(krb_cache, *argv);	
+	    goto next_arg;
+	  case 'C':		/* Change default config file */
+	    argc--, argv++;
+	    if (argc == 0) 
+	      usage();
+	    if(!(krb_config = (char *)malloc(strlen(*argv) + 1))){
+		fprintf(stderr, "rcp: Cannot malloc.\n");
+		exit(1);
+	    }
+	    strcpy(krb_config, *argv);	
+	    goto next_arg;
+	  case 'P':
+	    if (!strcmp (*argv, "O"))
+		kcmd_proto = KCMD_OLD_PROTOCOL;
+	    else if (!strcmp (*argv, "N"))
+		kcmd_proto = KCMD_NEW_PROTOCOL;
+	    else
+		usage ();
+	    goto next_arg;
+#endif /* KERBEROS */
+	    /* The rest of these are not for users. */
+	  case 'd':
+	    targetshouldbedirectory = 1;
+	    break;
+	    
+	  case 'f':		/* "from" */
+	    iamremote = 1;
+	    rcmd_stream_init_normal();
+#if defined(KERBEROS)
+	    if (encryptflag)
+	      answer_auth(krb_config, krb_cache);
+#endif /* KERBEROS */
+
+	    (void) response();
+	    source(--argc, ++argv);
+	    exit(errs);
+	    
+	  case 't':		/* "to" */
+	    iamremote = 1;
+	    rcmd_stream_init_normal();
+#if defined(KERBEROS)
+	    if (encryptflag)
+	      answer_auth(krb_config, krb_cache);
+#endif /* KERBEROS */
+
+	    sink(--argc, ++argv);
+	    exit(errs);
+	    
+	  default:
+	    usage();
+	}
+      next_arg: ;
+    }
+    
+    if (argc < 2)
+      usage();
+    if (argc > 2)
+      targetshouldbedirectory = 1;
+    rem = -1;
+
+
+    if (port == 0) {
+#ifdef KERBEROS
+      sp = getservbyname("kshell", "tcp");
+#else
+      sp = getservbyname("shell", "tcp");
+#endif /* KERBEROS */
+    
+      if (sp == NULL) {
+#ifdef KERBEROS
+	fprintf(stderr, "rcp: kshell/tcp: unknown service\n");
+	try_normal(orig_argv);
+#else
+	fprintf(stderr, "rcp: shell/tcp: unknown service\n");
+	exit(1);
+#endif /* KERBEROS */
+      }
+      port = sp->s_port;
+    }
+
+#ifdef KERBEROS
+    if (krb_realm != NULL)
+	cmdsiz += strlen(krb_realm);
+    if (krb_cache != NULL)
+	cmdsiz += strlen(krb_cache);
+    if (krb_config != NULL)
+	cmdsiz += strlen(krb_config);
+
+    if ((cmd = (char *)malloc(cmdsiz)) == NULL) {
+	fprintf(stderr, "rcp: Cannot malloc.\n");
+	exit(1);
+    }
+    (void) sprintf(cmd, "%srcp %s%s%s%s%s%s%s%s%s",
+		   encryptflag ? "-x " : "",
+
+		   iamrecursive ? " -r" : "", pflag ? " -p" : "", 
+		   targetshouldbedirectory ? " -d" : "",
+		   krb_realm != NULL ? " -k " : "",
+		   krb_realm != NULL ? krb_realm : "",
+		   krb_cache != NULL ? " -c " : "",
+		   krb_cache != NULL ? krb_cache : "",
+		   krb_config != NULL ? " -C " : "",
+		   krb_config != NULL ? krb_config : "");
+
+#else /* !KERBEROS */
+    (void) sprintf(cmd, "rcp%s%s%s",
+		   iamrecursive ? " -r" : "", pflag ? " -p" : "", 
+		   targetshouldbedirectory ? " -d" : "");
+#endif /* KERBEROS */
+    
+#ifdef POSIX_SIGNALS
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = lostconn;
+    (void) sigaction(SIGPIPE, &sa, (struct sigaction *)0);
+#else
+    (void) signal(SIGPIPE, lostconn);
+#endif
+    targ = colon(argv[argc - 1]);
+    
+    /* Check if target machine is the current machine. */
+    
+    gethostname(curhost, sizeof(curhost));
+    if (targ) {				/* ... to remote */
+	*targ++ = 0;
+	if (hosteq(argv[argc - 1], curhost)) {
+	    
+	    /* If so, pretend there wasn't even one given
+	     * check for an argument of just "host:", it
+	     * should become "."
+	     */
+	    
+	    if (*targ == 0) {
+		targ = ".";
+		argv[argc - 1] = targ;
+	    }
+	    else
+	      argv[argc - 1] = targ;
+	    targ = 0;
+	}
+    }
+    if (targ) {
+	/* Target machine is some remote machine */
+	if (*targ == 0)
+	  targ = ".";
+	thost = strchr(argv[argc - 1], '@');
+	if (thost) {
+	    *thost++ = 0;
+	    tuser = argv[argc - 1];
+	    if (*tuser == '\0')
+	      tuser = NULL;
+	    else if (!okname(tuser))
+	      exit(1);
+	} else {
+	    thost = argv[argc - 1];
+	    tuser = NULL;
+	}
+	for (i = 0; i < argc - 1; i++) {
+	    src = colon(argv[i]);
+	    if (src) {		/* remote to remote */
+		*src++ = 0;
+		if (*src == 0)
+		  src = ".";
+		host = strchr(argv[i], '@');
+		if (host) {
+		    *host++ = 0;
+		    suser = argv[i];
+		    if (*suser == '\0')
+		      suser = pwd->pw_name;
+		    else if (!okname(suser))
+		      continue;
+		    (void) sprintf(buf,
+#if defined(hpux) || defined(__hpux)
+				   "remsh %s -l %s -n %s %s '%s%s%s:%s'",
+#else
+				   "rsh %s -l %s -n %s %s '%s%s%s:%s'",
+#endif
+				   host, suser, cmd, src,
+				   tuser ? tuser : "",
+				   tuser ? "@" : "",
+				   thost, targ);
+	       } else
+		   (void) sprintf(buf,
+#if defined(hpux) || defined(__hpux)
+				  "remsh %s -n %s %s '%s%s%s:%s'",
+#else
+				  "rsh %s -n %s %s '%s%s%s:%s'",
+#endif
+				   argv[i], cmd, src,
+				   tuser ? tuser : "",
+				   tuser ? "@" : "",
+				   thost, targ);
+		(void) susystem(buf);
+	    } else {		/* local to remote */
+		krb5_creds *cred;
+		if (rem == -1) {
+		    (void) sprintf(buf, "%s -t %s",
+				   cmd, targ);
+		    host = thost;
+#ifdef KERBEROS
+		    authopts = AP_OPTS_MUTUAL_REQUIRED;
+		    status = kcmd(&sock, &host,
+				  port,
+				  pwd->pw_name,
+				  tuser ? tuser :
+				  pwd->pw_name,
+				  buf,
+				  0,
+				  "host",
+				  krb_realm,
+				  &cred,  
+				  0,  /* No seq # */
+				  0,  /* No server seq # */
+				  &local,
+				  &foreign,
+				  &auth_context, authopts,
+				  0, /* Not any port # */
+				  0,
+				  &kcmd_proto);
+		    if (status) {
+			if (kcmd_proto == KCMD_NEW_PROTOCOL)
+			    /* Don't fall back to less safe methods.  */
+			    exit (1);
+#ifdef KRB5_KRB4_COMPAT
+			fprintf(stderr, "Trying krb4 rcp...\n");
+			if (strncmp(buf, "-x rcp", 6) == 0)
+			    memcpy(buf, "rcp -x", 6);
+			status = k4cmd(&sock, &host, port,
+				       pwd->pw_name,
+				       tuser ? tuser : pwd->pw_name, buf,
+				       0, &v4_ticket, "rcmd", krb_realm,
+				       NULL, NULL, NULL,
+				       &local, &foreign, 0L, 0);
+			if (status)
+			    try_normal(orig_argv);
+			if (encryptflag)
+			    v4_send_auth(host, krb_realm);
+			rcmd_stream_init_krb4(v4_cred.session, encryptflag, 0,
+					      0);
+#else
+			try_normal(orig_argv);
+#endif
+		    }
+		    else {
+			krb5_boolean similar;
+			krb5_keyblock *key = &cred->keyblock;
+
+			status = krb5_c_enctype_compare(bsd_context,
+							ENCTYPE_DES_CBC_CRC,
+							cred->keyblock.enctype,
+							&similar);
+			if (status)
+			    try_normal(orig_argv); /* doesn't return */
+
+			if (!similar) {
+			    status = krb5_auth_con_getsendsubkey (bsd_context,
+								  auth_context,
+								  &key);
+			    if ((status || !key) && encryptflag)
+				try_normal(orig_argv);
+			}
+			if (key == 0)
+			    key = &cred->keyblock;
+
+			rcmd_stream_init_krb5(key, encryptflag, 0, 1,
+					      kcmd_proto);
+		    }
+		    rem = sock;
+#else
+		    rem = rcmd(&host, port, pwd->pw_name,
+			       tuser ? tuser : pwd->pw_name,
+			       buf, 0);
+		    if (rem < 0)
+		      exit(1);
+#endif /* KERBEROS */
+		    if (response() < 0)
+		      exit(1);
+		}
+		source(1, argv+i);
+	    }
+	}
+    } else {				/* ... to local */
+	if (targetshouldbedirectory)
+	  verifydir(argv[argc - 1]);
+	for (i = 0; i < argc - 1; i++) {
+	    src = colon(argv[i]);
+	    /* Check if source machine is current machine */
+	    if (src) {
+		*src++ = 0;
+		if (hosteq(argv[i], curhost)) {
+		    
+		    /* If so, pretend src machine never given */
+		    
+		    if (*src == 0) {
+			error("rcp: no path given in arg: %s:\n",
+			      argv[i]);
+			errs++;
+			continue;
+		    }
+		    argv[i] = src;
+		    src = 0;
+		} else {
+		    /* not equiv, return colon */
+		    *(--src) = ':';
+		}
+	    }
+	    if (src == 0) {		/* local to local */
+		(void) sprintf(buf, "/bin/cp%s%s %s %s",
+			       iamrecursive ? " -r" : "",
+			       pflag ? " -p" : "",
+			       argv[i], argv[argc - 1]);
+		(void) susystem(buf);
+	    } else {		/* remote to local */
+		krb5_creds *cred;
+		*src++ = 0;
+		if (*src == 0)
+		  src = ".";
+		host = strchr(argv[i], '@');
+		if (host) {
+		    *host++ = 0;
+		    suser = argv[i];
+		    if (*suser == '\0')
+		      suser = pwd->pw_name;
+		    else if (!okname(suser))
+		      continue;
+		} else {
+		    host = argv[i];
+		    suser = pwd->pw_name;
+		}
+		(void) sprintf(buf, "%s -f %s", cmd, src);
+#ifdef KERBEROS
+		authopts = AP_OPTS_MUTUAL_REQUIRED;
+		status = kcmd(&sock, &host,
+			      port,
+			      pwd->pw_name,  suser,
+			      buf,
+			      0,
+			      "host",
+			      krb_realm,
+			      &cred,  
+			      0,  /* No seq # */
+			      0,  /* No server seq # */
+			      (struct sockaddr_in *) 0,
+			      &foreign,
+			      &auth_context, authopts,
+			      0, /* Not any port # */
+			      0,
+			      &kcmd_proto);
+		if (status) {
+			if (kcmd_proto == KCMD_NEW_PROTOCOL)
+			    /* Don't fall back to less safe methods.  */
+			    exit (1);
+#ifdef KRB5_KRB4_COMPAT
+			fprintf(stderr, "Trying krb4 rcp...\n");
+			if (strncmp(buf, "-x rcp", 6) == 0)
+			    memcpy(buf, "rcp -x", 6);
+			status = k4cmd(&sock, &host, port,
+				       pwd->pw_name, suser, buf,
+				       0, &v4_ticket, "rcmd", krb_realm,
+				       NULL, NULL, NULL,
+				       &local, &foreign, 0L, 0);
+			if (status)
+			    try_normal(orig_argv);
+			if (encryptflag)
+			    v4_send_auth(host, krb_realm);
+			rcmd_stream_init_krb4(v4_cred.session, encryptflag, 0,
+					      0);
+#else
+			try_normal(orig_argv);
+#endif
+		} else {
+		    krb5_keyblock *key = &cred->keyblock;
+
+		    if (kcmd_proto == KCMD_NEW_PROTOCOL) {
+			status = krb5_auth_con_getsendsubkey (bsd_context,
+							      auth_context,
+							      &key);
+			if (status) {
+			    com_err (argv[0], status,
+				     "determining subkey for session");
+			    exit (1);
+			}
+			if (!key) {
+			    com_err (argv[0], 0,
+				     "no subkey negotiated for connection");
+			    exit (1);
+			}
+		    }
+
+		    rcmd_stream_init_krb5(key, encryptflag, 0, 1, kcmd_proto);
+		}
+		rem = sock; 
+				   
+		euid = geteuid();
+		if (euid == 0) {
+		    (void) setuid(0);
+		    if(krb5_seteuid(userid)) {
+			perror("rcp seteuid user"); errs++; exit(errs);
+		    }
+		}
+		sink(1, argv+argc-1);
+		if (euid == 0) {
+		    if(krb5_seteuid(0)) {
+			perror("rcp seteuid 0"); errs++; exit(errs);
+		    }
+		}
+#else
+		rem = rcmd(&host, port, pwd->pw_name, suser,
+			   buf, 0);
+		if (rem < 0)
+		  continue;
+		rcmd_stream_init_normal();
+#ifdef HAVE_SETREUID
+		(void) setreuid(0, userid);
+		sink(1, argv+argc-1);
+		(void) setreuid(userid, 0);
+#else
+		(void) setuid(0);
+		if(seteuid(userid)) {
+		  perror("rcp seteuid user"); errs++; exit(errs);
+		}
+		sink(1, argv+argc-1);
+		if(seteuid(0)) {
+		  perror("rcp seteuid 0"); errs++; exit(errs);
+		}
+#endif
+#endif /* KERBEROS */
+		(void) close(rem);
+		rem = -1;
+	    }
+	}
+    }
+    exit(errs);
+}
+
+
+
+void verifydir(cp)
+     char *cp;
+{
+    struct stat stb;
+    
+    if (stat(cp, &stb) >= 0) {
+	if ((stb.st_mode & S_IFMT) == S_IFDIR)
+	  return;
+	errno = ENOTDIR;
+    }
+    error("rcp: %s: %s.\n", cp, error_message(errno));
+    exit(1);
+}
+
+
+
+char *colon(cp)
+     char *cp;
+{
+    
+    while (*cp) {
+	if (*cp == ':')
+	  return (cp);
+	if (*cp == '/')
+	  return (0);
+	cp++;
+    }
+    return (0);
+}
+
+
+
+int okname(cp0)
+     char *cp0;
+{
+    register char *cp = cp0;
+    register int c;
+    
+    do {
+	c = *cp;
+	if (c & 0200)
+	  goto bad;
+	if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
+	  goto bad;
+	cp++;
+    } while (*cp);
+    return (1);
+  bad:
+    fprintf(stderr, "rcp: invalid user name %s\n", cp0);
+    return (0);
+}
+
+
+
+int susystem(s)
+     char *s;
+{
+    int status;
+    pid_t pid, w;
+#ifdef POSIX_SIGNALS
+    struct sigaction sa, isa, qsa;
+#else
+    register krb5_sigtype (bsd_context, *istat)(), (*qstat)();
+#endif
+    
+    if ((pid = vfork()) == 0) {
+	execl("/bin/sh", "sh", "-c", s, (char *)0);
+	_exit(127);
+    }
+
+#ifdef POSIX_SIGNALS
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGINT, &sa, &isa);
+    (void) sigaction(SIGQUIT, &sa, &qsa);
+#else
+    istat = signal(SIGINT, SIG_IGN);
+    qstat = signal(SIGQUIT, SIG_IGN);
+#endif
+    
+#ifdef HAVE_WAITPID
+    w = waitpid(pid, &status, 0);
+#else
+    while ((w = wait(&status)) != pid && w != -1) /*void*/ ;
+#endif
+    if (w == (pid_t)-1)
+      status = -1;
+
+#ifdef POSIX_SIGNALS
+    (void) sigaction(SIGINT, &isa, (struct sigaction *)0);
+    (void) sigaction(SIGQUIT, &qsa, (struct sigaction *)0);
+#else    
+    (void) signal(SIGINT, istat);
+    (void) signal(SIGQUIT, qstat);
+#endif
+    
+    return (status);
+}
+
+void source(argc, argv)
+     int argc;
+     char **argv;
+{
+    char *last, *name;
+    struct stat stb;
+    static struct buffer buffer;
+    struct buffer *bp;
+    int x, readerr, f;
+    unsigned int amt;
+    off_t i;
+    char buf[RCP_BUFSIZ];
+    
+    for (x = 0; x < argc; x++) {
+	name = argv[x];
+	if ((f = open(name, 0)) < 0) {
+	    error("rcp: %s: %s\n", name, error_message(errno));
+	    continue;
+	}
+	if (fstat(f, &stb) < 0)
+	  goto notreg;
+	switch (stb.st_mode&S_IFMT) {
+	    
+	  case S_IFREG:
+	    break;
+	    
+	  case S_IFDIR:
+	    if (iamrecursive) {
+		(void) close(f);
+		rsource(name, &stb);
+		continue;
+	    }
+	    /* fall into ... */
+	  default:
+	  notreg:
+	    (void) close(f);
+	    error("rcp: %s: not a plain file\n", name);
+	    continue;
+	}
+	last = strrchr(name, '/');
+	if (last == 0)
+	  last = name;
+	else
+	  last++;
+	if (pflag) {
+	    /*
+	     * Make it compatible with possible future
+	     * versions expecting microseconds.
+	     */
+	    (void) sprintf(buf, "T%ld 0 %ld 0\n",
+			   stb.st_mtime, stb.st_atime);
+	    (void) rcmd_stream_write(rem, buf, strlen(buf), 0);
+	    if (response() < 0) {
+		(void) close(f);
+		continue;
+	    }
+	}
+	(void) sprintf(buf, "C%04o %ld %s\n",
+		       (int) stb.st_mode&07777, (long ) stb.st_size, last);
+	(void) rcmd_stream_write(rem, buf, strlen(buf), 0);
+	if (response() < 0) {
+	    (void) close(f);
+	    continue;
+	}
+	if ((bp = allocbuf(&buffer, f, RCP_BUFSIZ)) == NULLBUF) {
+	    (void) close(f);
+	    continue;
+	}
+	readerr = 0;
+	for (i = 0; i < stb.st_size; i += bp->cnt) {
+	    amt = bp->cnt;
+	    if (i + amt > stb.st_size)
+	      amt = stb.st_size - i;
+	    if (readerr == 0 && read(f, bp->buf, amt) != amt)
+	      readerr = errno;
+	    (void) rcmd_stream_write(rem, bp->buf, amt, 0);
+	}
+	(void) close(f);
+	if (readerr == 0)
+	  ga();
+	else
+	  error("rcp: %s: %s\n", name, error_message(readerr));
+	(void) response();
+    }
+}
+
+
+
+#ifndef USE_DIRENT_H
+#include <sys/dir.h>
+#else
+#include <dirent.h>
+#endif
+
+void rsource(name, statp)
+     char *name;
+     struct stat *statp;
+{
+    DIR *d = opendir(name);
+    char *last;
+#ifdef USE_DIRENT_H
+    struct dirent *dp;
+#else
+    struct direct *dp;
+#endif
+    char buf[RCP_BUFSIZ];
+    char *bufv[1];
+    
+    if (d == 0) {
+	error("rcp: %s: %s\n", name, error_message(errno));
+	return;
+    }
+    last = strrchr(name, '/');
+    if (last == 0)
+      last = name;
+    else
+      last++;
+    if (pflag) {
+	(void) sprintf(buf, "T%ld 0 %ld 0\n",
+		       statp->st_mtime, statp->st_atime);
+	(void) rcmd_stream_write(rem, buf, strlen(buf), 0);
+	if (response() < 0) {
+	    closedir(d);
+	    return;
+	}
+    }
+    (void) sprintf(buf, "D%04lo %d %s\n", (long) statp->st_mode&07777, 0, 
+		   last);
+    (void) rcmd_stream_write(rem, buf, strlen(buf), 0);
+    if (response() < 0) {
+	closedir(d);
+	return;
+    }
+    while ((dp = readdir(d)) != NULL) {
+	if (dp->d_ino == 0)
+	  continue;
+	if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+	  continue;
+	if (strlen(name) + 1 + strlen(dp->d_name) >= RCP_BUFSIZ - 1) {
+	    error("%s/%s: Name too long.\n", name, dp->d_name);
+	    continue;
+	}
+	(void) sprintf(buf, "%s/%s", name, dp->d_name);
+	bufv[0] = buf;
+	source(1, bufv);
+    }
+    closedir(d);
+    (void) rcmd_stream_write(rem, "E\n", 2, 0);
+    (void) response();
+}
+
+
+
+int response()
+{
+    char resp, c, rbuf[RCP_BUFSIZ], *cp = rbuf;
+    if (rcmd_stream_read(rem, &resp, 1, 0) != 1)
+      lostconn(0);
+    switch (resp) {
+	
+      case 0:				/* ok */
+	return (0);
+	
+      default:
+	*cp++ = resp;
+	/* fall into... */
+      case 1:				/* error, followed by err msg */
+      case 2:				/* fatal error, "" */
+	do {
+	    if (rcmd_stream_read(rem, &c, 1, 0) != 1)
+	      lostconn(0);
+	    *cp++ = c;
+	} while (cp < &rbuf[RCP_BUFSIZ] && c != '\n');
+	if (iamremote == 0)
+	  (void) write(2, rbuf, (unsigned) (cp - rbuf));
+	errs++;
+	if (resp == 1)
+	  return (-1);
+	exit(1);
+    }
+    /*NOTREACHED*/
+}
+
+
+
+krb5_sigtype
+  lostconn(signumber)
+    int signumber;
+{
+    if (iamremote == 0)
+      fprintf(stderr, "rcp: lost connection\n");
+    exit(1);
+}
+
+
+#if !defined(HAVE_UTIMES)
+#include <utime.h>
+#include <sys/time.h>
+
+/*
+ * We emulate utimes() instead of utime() as necessary because
+ * utimes() is more powerful than utime(), and rcp actually tries to
+ * set the microsecond values; we don't want to take away
+ * functionality unnecessarily.
+ */
+int utimes(file, tvp)
+const char *file;
+struct timeval *tvp;
+{
+	struct utimbuf times;
+
+	times.actime = tvp[0].tv_sec;
+	times.modtime = tvp[1].tv_sec;
+	return(utime(file, ×));
+}
+#endif
+
+
+void sink(argc, argv)
+     int argc;
+     char **argv;
+{
+    mode_t mode;
+    mode_t mask = umask(0);
+    off_t i, j;
+    char *targ, *whopp, *cp;
+    int of, wrerr, exists, first;
+    off_t size;
+    unsigned int amt, count;
+    struct buffer *bp;
+    static struct buffer buffer;
+    struct stat stb;
+    int targisdir = 0;
+    char *myargv[1];
+    char cmdbuf[RCP_BUFSIZ], nambuf[RCP_BUFSIZ];
+    int setimes = 0;
+    struct timeval tv[2];
+#define atime	tv[0]
+#define mtime	tv[1]
+#define	SCREWUP(str)	{ whopp = str; goto screwup; }
+    
+    if (!pflag)
+      (void) umask(mask);
+    if (argc != 1) {
+	error("rcp: ambiguous target\n");
+	exit(1);
+    }
+    targ = *argv;
+    if (targetshouldbedirectory)
+      verifydir(targ);
+    ga();
+    if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
+      targisdir = 1;
+    for (first = 1; ; first = 0) {
+	cp = cmdbuf;
+	if (rcmd_stream_read(rem, cp, 1, 0) <= 0)
+	  return;
+	if (*cp++ == '\n')
+	  SCREWUP("unexpected '\\n'");
+	do {
+	    if (rcmd_stream_read(rem, cp, 1, 0) != 1)
+	      SCREWUP("lost connection");
+	} while (*cp++ != '\n');
+	*cp = 0;
+	if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
+	    if (iamremote == 0)
+	      (void) write(2, cmdbuf+1, strlen(cmdbuf+1));
+	    if (cmdbuf[0] == '\02')
+	      exit(1);
+	    errs++;
+	    continue;
+	}
+	*--cp = 0;
+	cp = cmdbuf;
+	if (*cp == 'E') {
+	    ga();
+	    return;
+	}
+	
+#define getnum(t) (t) = 0; while (isdigit((int) *cp)) (t) = (t) * 10 + (*cp++ - '0');
+	if (*cp == 'T') {
+	    setimes++;
+	    cp++;
+	    getnum(mtime.tv_sec);
+	    if (*cp++ != ' ')
+	      SCREWUP("mtime.sec not delimited");
+	    getnum(mtime.tv_usec);
+	    if (*cp++ != ' ')
+	      SCREWUP("mtime.usec not delimited");
+	    getnum(atime.tv_sec);
+	    if (*cp++ != ' ')
+	      SCREWUP("atime.sec not delimited");
+	    getnum(atime.tv_usec);
+	    if (*cp++ != '\0')
+	      SCREWUP("atime.usec not delimited");
+	    ga();
+	    continue;
+	}
+	if (*cp != 'C' && *cp != 'D') {
+	    /*
+	     * Check for the case "rcp remote:foo\* local:bar".
+	     * In this case, the line "No match." can be returned
+	     * by the shell before the rcp command on the remote is
+	     * executed so the ^Aerror_message convention isn't
+	     * followed.
+	     */
+	    if (first) {
+		error("%s\n", cp);
+		exit(1);
+	    }
+	    SCREWUP("expected control record");
+	}
+	cp++;
+	mode = 0;
+	for (; cp < cmdbuf+5; cp++) {
+	    if (*cp < '0' || *cp > '7')
+	      SCREWUP("bad mode");
+	    mode = (mode << 3) | (*cp - '0');
+	}
+	if (*cp++ != ' ')
+	  SCREWUP("mode not delimited");
+	size = 0;
+	while (isdigit((int) *cp))
+	  size = size * 10 + (*cp++ - '0');
+	if (*cp++ != ' ')
+	  SCREWUP("size not delimited");
+	if (targisdir) {
+          if(strlen(targ) + strlen(cp) + 2 >= sizeof(nambuf))
+	    SCREWUP("target name too long");
+	  (void) sprintf(nambuf, "%s%s%s", targ,
+			 *targ ? "/" : "", cp);
+	} else {
+	  if (strlen(targ) + 1 >= sizeof (nambuf))
+	    SCREWUP("target name too long");
+	  (void) strncpy(nambuf, targ, sizeof(nambuf) - 1);
+	}
+	nambuf[sizeof(nambuf) - 1] = '\0';
+	exists = stat(nambuf, &stb) == 0;
+	if (cmdbuf[0] == 'D') {
+	    if (exists) {
+		if ((stb.st_mode&S_IFMT) != S_IFDIR) {
+		    errno = ENOTDIR;
+		    goto bad;
+		}
+		if (pflag)
+		  (void) chmod(nambuf, mode);
+	    } else if (mkdir(nambuf, mode) < 0)
+	      goto bad;
+	    myargv[0] = nambuf;
+	    sink(1, myargv);
+	    if (setimes) {
+		setimes = 0;
+		if (utimes(nambuf, tv) < 0)
+		  error("rcp: can't set times on %s: %s\n",
+			nambuf, error_message(errno));
+	    }
+	    continue;
+	}
+	if ((of = open(nambuf, O_WRONLY|O_CREAT, mode)) < 0) {
+	  bad:
+	    error("rcp: %s: %s\n", nambuf, error_message(errno));
+	    continue;
+	}
+	if (exists && pflag) {
+#ifdef NOFCHMOD
+	    (void) chmod(nambuf, mode);
+#else
+	    (void) fchmod(of, mode);
+#endif
+	}
+	ga();
+	if ((bp = allocbuf(&buffer, of, RCP_BUFSIZ)) == NULLBUF) {
+	    (void) close(of);
+	    continue;
+	}
+	cp = bp->buf;
+	count = 0;
+	wrerr = 0;
+	for (i = 0; i < size; i += RCP_BUFSIZ) {
+	    amt = RCP_BUFSIZ;
+	    if (i + amt > size)
+	      amt = size - i;
+	    count += amt;
+	    do {
+		j = rcmd_stream_read(rem, cp, amt, 0);
+		if (j <= 0) {
+		    if (j == 0)
+		      error("rcp: dropped connection");
+		    else
+		      error("rcp: %s\n", error_message(errno));
+		    exit(1);
+		}
+		amt -= j;
+		cp += j;
+	    } while (amt > 0);
+	    if (count == bp->cnt) {
+		if (wrerr == 0 &&
+		    write(of, bp->buf, count) != count)
+		  wrerr++;
+		count = 0;
+		cp = bp->buf;
+	    }
+	}
+	if (count != 0 && wrerr == 0 &&
+	    write(of, bp->buf, count) != count)
+	  wrerr++;
+	if (ftruncate(of, size))
+	  error("rcp: can't truncate %s: %s\n", nambuf, error_message(errno));
+	(void) close(of);
+	(void) response();
+	if (setimes) {
+	    setimes = 0;
+	    if (utimes(nambuf, tv) < 0)
+	      error("rcp: can't set times on %s: %s\n",
+		    nambuf, error_message(errno));
+	}				   
+	if (wrerr)
+	  error("rcp: %s: %s\n", nambuf, error_message(errno));
+	else
+	  ga();
+    }
+  screwup:
+    error("rcp: protocol screwup: %s\n", whopp);
+    exit(1);
+}
+
+
+
+struct buffer *allocbuf(bp, fd, blksize)
+     struct buffer *bp;
+     int fd, blksize;
+{
+    struct stat stb;
+    int size;
+    
+    if (fstat(fd, &stb) < 0) {
+	error("rcp: fstat: %s\n", error_message(errno));
+	return (NULLBUF);
+    }
+
+    size = blksize;
+    if (bp->cnt < size) {
+	if (bp->buf != 0)
+	  free(bp->buf);
+	bp->buf = (char *)malloc((unsigned) size);
+	if (bp->buf == 0) {
+	    error("rcp: malloc: out of memory\n");
+	    return (NULLBUF);
+	}
+    }
+    bp->cnt = size;
+    return (bp);
+}
+
+void
+#ifdef HAVE_STDARG_H
+error(char *fmt, ...)
+#else
+/*VARARGS1*/
+error(fmt, va_alist)
+     char *fmt;
+     va_dcl
+#endif
+{
+    va_list ap;
+    char buf[RCP_BUFSIZ], *cp = buf;
+
+#ifdef HAVE_STDARG_H
+    va_start(ap, fmt);
+#else
+    va_start(ap);
+#endif
+
+    errs++;
+    *cp++ = 1;
+    (void) vsprintf(cp, fmt, ap);
+    va_end(ap);
+
+    if (iamremote)
+      (void) rcmd_stream_write(rem, buf, strlen(buf), 0);
+    else
+      (void) write(2, buf+1, strlen(buf+1));
+}
+
+
+
+void usage()
+{
+#ifdef KERBEROS
+    fprintf(stderr,
+	    "Usage: \trcp [-PN | -PO] [-p] [-x] [-k realm] f1 f2; or:\n\trcp [-PN | -PO] [-r] [-p] [-x] [-k realm] f1 ... fn d2\n");
+#else
+    fputs("usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n", stderr);
+#endif
+    exit(1);
+}
+
+
+
+int hosteq(h1, h2)
+     char *h1, *h2;
+{
+    struct hostent *h_ptr;
+    char hname1[256];
+    
+    if (forcenet)
+      return(0);
+
+    /* get the official names for the two hosts */
+    
+    if ((h_ptr = gethostbyname(h1)) == NULL)
+      return(0);
+    strncpy(hname1, h_ptr->h_name, sizeof (hname1));
+    hname1[sizeof (hname1) - 1] = '\0';
+    if ((h_ptr = gethostbyname(h2)) == NULL)
+      return(0);
+    
+    /*return if they are equal (strcmp returns 0 for equal - I return 1) */
+    
+    return(!strcmp(hname1, h_ptr->h_name));
+}
+
+
+
+#ifdef KERBEROS
+void try_normal(argv)
+     char **argv;
+{
+    register int i;
+#ifndef     KRB5_ATHENA_COMPAT
+    if (!encryptflag)
+#endif
+	{
+	fprintf(stderr,"trying normal rcp (%s)\n", UCB_RCP);
+	fflush(stderr);
+	/* close all but stdin, stdout, stderr */
+	for (i = getdtablesize(); i > 2; i--)
+	  (void) close(i);
+	execv(UCB_RCP, argv);
+	perror("exec");
+    }
+    exit(1);
+}
+
+
+
+char **save_argv(argc, argv)
+     int argc;
+     char **argv;
+{
+    register int i;
+    
+    char **local_argv = (char **)calloc((unsigned) argc+1,
+					(unsigned) sizeof(char *));
+    /* allocate an extra pointer, so that it is initialized to NULL
+       and execv() will work */
+    for (i = 0; i < argc; i++)
+      local_argv[i] = strsave(argv[i]);
+    return(local_argv);
+}
+
+
+
+#ifdef unicos61
+#define SIZEOF_INADDR  SIZEOF_in_addr
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+
+
+/* This function is mostly vestigial, since under normal operation
+ * the -x flag doesn't get set for the server process for encrypted
+ * rcp.  It only gets called by beta clients attempting user-to-user
+ * authentication. */
+void
+  answer_auth(config_file, ccache_file)
+    char *config_file;
+    char *ccache_file;
+{
+    krb5_data pname_data, msg;
+    krb5_creds creds, *new_creds;
+    krb5_ccache cc;
+    krb5_error_code status;
+    krb5_auth_context auth_context = NULL;
+    
+    if (config_file) {
+    	const char * filenames[2];
+    	filenames[1] = NULL;
+    	filenames[0] = config_file;
+    	if ((status = krb5_set_config_files(bsd_context, filenames)))
+	    exit(1);
+    }
+    
+    memset ((char*)&creds, 0, sizeof(creds));
+
+    if ((status = krb5_read_message(bsd_context, (krb5_pointer)&rem,
+				    &pname_data)))
+	exit(1);
+    
+    if ((status = krb5_read_message(bsd_context, (krb5_pointer) &rem,
+				    &creds.second_ticket)))
+	exit(1);
+    
+    if (ccache_file == NULL) {
+    	if ((status = krb5_cc_default(bsd_context, &cc)))
+	    exit(1);
+    } else {
+	if ((status = krb5_cc_resolve(bsd_context, ccache_file, &cc)))
+	    exit(1);
+    }
+
+    if ((status = krb5_cc_get_principal(bsd_context, cc, &creds.client)))
+	exit(1);
+
+    if ((status = krb5_parse_name(bsd_context, pname_data.data,
+				  &creds.server)) )
+	exit(1);
+
+    krb5_free_data_contents(bsd_context, &pname_data);
+
+    if ((status = krb5_get_credentials(bsd_context, KRB5_GC_USER_USER, cc, 
+				       &creds, &new_creds)))
+	exit(1);
+
+    if ((status = krb5_mk_req_extended(bsd_context, &auth_context,
+				       AP_OPTS_USE_SESSION_KEY,
+				       NULL, new_creds, &msg)))
+	exit(1);
+    
+    if ((status = krb5_write_message(bsd_context, (krb5_pointer) &rem,
+				     &msg))) {
+    	krb5_free_data_contents(bsd_context, &msg);
+	exit(1);
+    }
+    
+    rcmd_stream_init_krb5(&new_creds->keyblock, encryptflag, 0, 0,
+			  KCMD_OLD_PROTOCOL);
+    
+    /* cleanup */
+    krb5_free_cred_contents(bsd_context, &creds);
+    krb5_free_creds(bsd_context, new_creds);
+    krb5_free_data_contents(bsd_context, &msg);
+
+    return;
+}
+
+
+
+char storage[2*RCP_BUFSIZ];		/* storage for the decryption */
+int nstored = 0;
+char *store_ptr = storage;
+
+#ifdef KRB5_KRB4_COMPAT
+void
+v4_send_auth(host,realm)
+char *host;
+char *realm;
+{
+	long authopts;
+
+	if ((realm == NULL) || (realm[0] == '\0'))
+	     realm = krb_realmofhost(host);
+	/* this needs to be sent again, because the
+	   rcp process needs the key.  the rshd has
+	   grabbed the first one. */
+	authopts = KOPT_DO_MUTUAL;
+	if ((rem = krb_sendauth(authopts, sock, &v4_ticket,
+				"rcmd", host,
+				realm, (unsigned long) getpid(),
+				&v4_msg_data,
+				&v4_cred, v4_schedule,
+				&local,
+				&foreign,
+				"KCMDV0.1")) != KSUCCESS) {
+		fprintf(stderr,
+			"krb_sendauth mutual fail: %s\n",
+			krb_get_err_text(rem));
+		exit(1);
+	}
+}
+#endif /* KRB5_KRB4_COMPAT */
+
+#endif /* KERBEROS */
diff --git a/mechglue/src/appl/bsd/krlogin.c b/mechglue/src/appl/bsd/krlogin.c
new file mode 100644
index 000000000..a1e63a645
--- /dev/null
+++ b/mechglue/src/appl/bsd/krlogin.c
@@ -0,0 +1,1857 @@
+/*
+ *    appl/bsd/krlogin.c
+ */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)rlogin.c	5.12 (Berkeley) 9/19/88 */
+
+     
+     /*
+      * rlogin - remote login
+      */
+     
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <pwd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <netdb.h>
+     
+#ifdef HAVE_SYS_FILIO_H
+/* Solaris needs <sys/filio.h> for FIONREAD */
+#include <sys/filio.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef POSIX_TERMIOS
+#include <termios.h>
+#ifndef CNUL
+#define CNUL (char) 0
+#endif
+
+#else /* POSIX_TERMIOS */
+#include <sgtty.h>
+#endif /* POSIX_TERMIOS */
+
+#ifdef HAVE_SYS_SOCKIO_H
+/* for SIOCATMARK */
+#include <sys/sockio.h>
+#endif
+
+#ifdef HAVE_STREAMS
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#endif
+
+#ifdef __SCO__
+/* for TIOCPKT_* */
+#include <sys/spt.h>
+/* for struct winsize */
+#include <sys/ptem.h>
+#endif
+
+#ifdef HAVE_STREAMS
+#ifdef HAVE_SYS_PTYVAR_H
+#include <sys/tty.h>
+#include <sys/ttold.h>
+/* solaris actually uses packet mode, so the real macros are needed too */
+#include <sys/ptyvar.h>
+#endif
+#endif
+
+#ifndef TIOCPKT_NOSTOP
+/* These values are over-the-wire protocol, *not* local values */
+#define TIOCPKT_NOSTOP          0x10
+#define TIOCPKT_DOSTOP          0x20
+#define TIOCPKT_FLUSHWRITE      0x02
+#endif
+
+#ifdef HAVE_SYS_IOCTL_COMPAT_H
+#include <sys/ioctl_compat.h>
+#endif
+
+#ifdef CRAY
+#include <sys/ttold.h>
+#endif
+
+
+#ifdef KERBEROS
+#include <krb5.h>
+#include <com_err.h>
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+#include "defines.h"
+     
+#define RLOGIN_BUFSIZ 5120
+
+void try_normal();
+char *krb_realm = (char *)0;
+int encrypt_flag = 0;
+int fflag = 0, Fflag = 0;
+krb5_creds *cred;
+struct sockaddr_in local, foreign;
+krb5_context bsd_context;
+krb5_auth_context auth_context;
+
+#ifdef KRB5_KRB4_COMPAT
+Key_schedule v4_schedule;
+CREDENTIALS v4_cred;
+#endif
+
+#ifndef UCB_RLOGIN
+#define UCB_RLOGIN      "/usr/ucb/rlogin"
+#endif
+
+#include "rpaths.h"
+#endif /* KERBEROS */
+
+# ifndef TIOCPKT_WINDOW
+# define TIOCPKT_WINDOW 0x80
+# endif /* TIOCPKT_WINDOW */
+
+#ifndef ONOCR
+#define ONOCR 0
+#endif
+
+#ifdef POSIX_TERMIOS
+struct termios deftty;
+#endif
+
+char	*getenv();
+
+char	*name;
+int 	rem = -1;		/* Remote socket fd */
+int	do_inband = 0;
+char	cmdchar = '~';
+int	eight = 1;		/* Default to 8 bit transmission */
+int	no_local_escape = 0;
+int	null_local_username = 0;
+int	flow = 1;			/* Default is to allow flow
+					   control at the local terminal */
+int	flowcontrol;			/* Since emacs can alter the
+					   flow control characteristics
+					   of a session we need a
+					   variable to keep track of
+					   the original characteristics */
+int	confirm = 0;			/* ask if ~. is given before dying. */
+int	litout;
+#if defined(hpux) || defined(__hpux)
+char	*speeds[] =
+{ "0", "50", "75", "110", "134", "150", "200", "300", "600",
+    "900", "1200", "1800", "2400", "3600", "4800", "7200", "9600",
+    "19200", "38400", "EXTA", "EXTB" };
+#else
+/* Solaris note: There are higher values we could use.  But Casper Dik
+   <Casper.Dik@Holland.Sun.Com> mentions in article
+   <casper.938167062@uk-usenet.uk.sun.com> in comp.protocols.kerberos
+   on 1999-09-24 some problems in sending higher values to remote
+   systems (for non-Kerberos rlogind?).  So let's stick with this
+   list.  Even if our current klogind doesn't have the problems, older
+   versions are likely to.
+
+   Daniel S. Riley <dsr@mail.lns.cornell.edu> gives 57600, 76800,
+   115200, 153600, 230400, 307200, 460800 as the higher values.
+   (article <sh6711s713.fsf@lnscu4.lns.cornell.edu> in
+   comp.protocols.kerberos, 1999-09-23) */
+char    *speeds[] =
+{ "0", "50", "75", "110", "134", "150", "200", "300",
+    "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
+#endif
+char	term[256] = "network";
+
+#ifndef POSIX_SIGNALS
+#ifndef sigmask
+#define sigmask(m)    (1 << ((m)-1))
+#endif
+#endif /* POSIX_SIGNALS */
+
+#ifdef NO_WINSIZE
+struct winsize {
+    unsigned short ws_row, ws_col;
+    unsigned short ws_xpixel, ws_ypixel;
+};
+#endif /* NO_WINSIZE */
+int	dosigwinch = 0;
+struct	winsize winsize;
+
+char	*host=0;			/* external, so it can be
+					   reached from confirm_death() */
+
+krb5_sigtype	sigwinch (int);
+int server_message (int);
+void oob (void);
+krb5_sigtype	lostpeer (int);
+void setsignal (int sig, krb5_sigtype (*act)());
+static int read_wrapper(int fd, char *buf, int size, int *got_esc);
+static void prf(char *f);
+void try_normal(char **);
+static void mode(int);
+#ifdef POSIX_SIGNALS
+static int reader(sigset_t *);
+static void doit(sigset_t *);
+#else
+static int reader(int);
+static void doit(int);
+#endif
+static int control(char *, unsigned int);
+static void sendwindow(void);
+static void stop(int), echo(int);
+static void writer(void), done(int);
+static int confirm_death (void);
+
+
+/* to allow exits from signal handlers, without conflicting declarations */
+static krb5_sigtype exit_handler() {
+  exit(1);
+}
+
+
+/*
+ * The following routine provides compatibility (such as it is)
+ * between 4.2BSD Suns and others.  Suns have only a `ttysize',
+ * so we convert it to a winsize.
+ */
+#ifdef TIOCGWINSZ
+#define get_window_size(fd, wp)       ioctl(fd, TIOCGWINSZ, wp)
+#else
+#ifdef SYSV
+#ifndef SIGWINCH
+#define SIGWINCH SIGWINDOW
+#endif
+struct ttysize {
+    int ts_lines;
+    int ts_cols;
+};
+#define DEFAULT_LINES 24
+#define DEFAULT_COLS 80
+#endif
+
+
+
+int
+  get_window_size(fd, wp)
+int fd;
+struct winsize *wp;
+{
+    struct ttysize ts;
+    int error;
+#ifdef SYSV
+    char *envbuf;
+    ts.ts_lines = DEFAULT_LINES;
+    ts.ts_cols = DEFAULT_COLS;
+    if (( envbuf = getenv("LINES")) != (char *) 0)
+      ts.ts_lines = atoi(envbuf);
+    if (( envbuf = getenv("COLUMNS")) != (char *) 0)
+      ts.ts_cols = atoi(envbuf);
+#else
+    if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
+      return (error);
+#endif
+    
+    wp->ws_row = ts.ts_lines;
+    wp->ws_col = ts.ts_cols;
+    wp->ws_xpixel = 0;
+    wp->ws_ypixel = 0;
+    return (0);
+}
+#endif /* TIOCGWINSZ */
+
+
+#ifdef POSIX_TERMIOS
+/* Globals for terminal modes and flow control */
+struct  termios defmodes;
+struct  termios ixon_state;
+#else
+#ifdef USE_TERMIO
+/* Globals for terminal modes and flow control */
+struct  termio defmodes;
+struct  termio ixon_state;
+#endif
+#endif
+
+
+int
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+    char *cp = (char *) NULL;
+#ifdef POSIX_TERMIOS
+    struct termios ttyb;
+#else
+#ifdef USE_TERMIO
+    struct termio ttyb;
+#else
+    struct sgttyb ttyb;
+#endif
+#endif
+    struct passwd *pwd;
+    struct servent *sp;
+    struct servent defaultservent;
+    int uid, options = 0;
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+    sigset_t *oldmask, omask, urgmask;
+#else
+    int oldmask;
+#endif
+    int on = 1;
+#ifdef KERBEROS
+    char **orig_argv = argv;
+    int sock;
+    krb5_flags authopts;
+    krb5_error_code status;
+#ifdef KRB5_KRB4_COMPAT
+    KTEXT_ST v4_ticket;
+    MSG_DAT v4_msg_data;
+    int v4only = 0;
+#endif
+#endif
+    int port, debug_port = 0;
+    enum kcmd_proto kcmd_proto = KCMD_PROTOCOL_COMPAT_HACK;
+
+    memset(&defaultservent, 0, sizeof(struct servent));
+    if (strrchr(argv[0], '/'))
+      argv[0] = strrchr(argv[0], '/')+1;
+
+    if ( argc < 2 ) goto usage;
+    argc--;
+    argv++;
+
+  another:
+    if (argc > 0 && host == 0 && strncmp(*argv, "-", 1)) {
+	host = *argv;
+	argv++, argc--;
+	goto another;
+    }
+
+    if (argc > 0 && !strcmp(*argv, "-D")) {
+	argv++; argc--;
+	if (*argv == NULL) {
+	    fprintf (stderr,
+		     "rlogin: -D flag must be followed by the debug port.\n");
+	    exit (1);
+	}
+	debug_port = htons(atoi(*argv));
+	argv++; argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-d")) {
+	argv++, argc--;
+	options |= SO_DEBUG;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-c")) {
+	confirm = 1;
+	argv++; argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-a")) {	   /* ask -- make remote */
+	argv++; argc--;			/* machine ask for password */
+	null_local_username = 1;	/* by giving null local user */
+	goto another;			/* id */
+    }
+    if (argc > 0 && !strcmp(*argv, "-t")) {
+	argv++; argc--;
+	if (argc == 0) goto usage;
+	cp = *argv++; argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-n")) {
+	no_local_escape = 1;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-7")) {  /* Pass only 7 bits */
+	eight = 0;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-noflow")) {
+	flow = 0;		/* Turn off local flow control so
+				   that ^S can be passed to emacs. */
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-l")) {
+	argv++, argc--;
+	if (argc == 0)
+	  goto usage;
+	name = *argv++; argc--;
+	goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-e", 2)) {
+	cmdchar = argv[0][2];
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-8")) {
+	eight = 1;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-L")) {
+	litout = 1;
+	argv++, argc--;
+	goto another;
+    }
+#ifdef KERBEROS
+    if (argc > 0 && !strcmp(*argv, "-k")) {
+	argv++, argc--;
+	if (argc == 0) {
+	    fprintf(stderr,
+		    "rlogin: -k flag must be followed with a realm name.\n");
+	    exit (1);
+	}
+	if(!(krb_realm = (char *)malloc(strlen(*argv) + 1))){
+	    fprintf(stderr, "rlogin: Cannot malloc.\n");
+	    exit(1);
+	}
+	strcpy(krb_realm, *argv);
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-x")) {
+	encrypt_flag++;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-f")) {
+	if (Fflag) {
+	    fprintf(stderr, "rlogin: Only one of -f and -F allowed\n");
+	    goto usage;
+	}
+	fflag++;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-F")) {
+	if (fflag) {
+	    fprintf(stderr, "rlogin: Only one of -f and -F allowed\n");
+	    goto usage;
+	}
+	Fflag++;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-PO")) {
+	kcmd_proto = KCMD_OLD_PROTOCOL;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-PN")) {
+	kcmd_proto = KCMD_NEW_PROTOCOL;
+	argv++, argc--;
+	goto another;
+    }
+#ifdef KRB5_KRB4_COMPAT
+    if (argc > 0 && !strcmp(*argv, "-4")) {
+	v4only++;
+	argv++, argc--;
+	goto another;
+    }
+#endif /* krb4 */
+#endif /* KERBEROS */
+    if (host == 0)
+      goto usage;
+    if (argc > 0)
+      goto usage;
+#ifdef KRB5_KRB4_COMPAT
+    if (kcmd_proto != KCMD_PROTOCOL_COMPAT_HACK && v4only) {
+	com_err (argv[0], 0,
+		 "-4 is incompatible with -PO/-PN");
+	exit(1);
+    }
+#endif
+    pwd = getpwuid(getuid());
+    if (pwd == 0) {
+	fprintf(stderr, "Who are you?\n");
+	exit(1);
+    }
+#ifdef KERBEROS
+    status = krb5_init_context(&bsd_context);
+    if (status) {
+	    com_err(argv[0], status, "while initializing krb5");
+	    exit(1);
+    }
+#endif
+
+
+    if (debug_port)
+      port = debug_port;
+    else {
+#ifdef KERBEROS
+    /*
+     * if there is an entry in /etc/services for Kerberos login,
+     * attempt to login with Kerberos. 
+     * If we fail at any step,  use the standard rlogin
+     */
+      if (encrypt_flag)
+	sp = getservbyname("eklogin","tcp");
+      else 
+	sp = getservbyname("klogin","tcp");
+      if (sp == 0) {
+		sp = &defaultservent;   /* ANL */
+		sp->s_port = encrypt_flag ? htons(2105) : htons(543);
+      }
+#else
+      sp = getservbyname("login", "tcp");
+      if (sp == 0) {
+	fprintf(stderr, "rlogin: login/tcp: unknown service\n");
+	exit(2);
+      }
+#endif /* KERBEROS */
+
+      port = sp->s_port;
+    }
+
+
+    if (cp == (char *) NULL) cp = getenv("TERM");
+    if (cp) {
+      (void) strncpy(term, cp, sizeof (term));
+      term[sizeof (term) - 1] = '\0';
+    }
+#ifdef POSIX_TERMIOS
+	if (tcgetattr(0, &ttyb) == 0) {
+		int ospeed = cfgetospeed (&ttyb);
+
+                term[sizeof(term) - 1] = '\0';
+		(void) strncat(term, "/", sizeof(term) - 1 - strlen(term));
+		if (ospeed >= 50)
+			/* On some systems, ospeed is the baud rate itself,
+			   not a table index.  */
+			sprintf (term + strlen (term), "%d", ospeed);
+		else if (ospeed >= sizeof(speeds)/sizeof(char*))
+			/* Past end of table, but not high enough to
+			   look like a real speed.  */
+			(void) strncat (term, speeds[sizeof(speeds)/sizeof(char*) - 1], sizeof(term) - 1 - strlen(term));
+		else {
+			(void) strncat(term, speeds[ospeed], sizeof(term) - 1 - strlen(term));
+		}
+                term[sizeof (term) - 1] = '\0';
+	}
+#else
+    if (ioctl(0, TIOCGETP, &ttyb) == 0) {
+	(void) strncat(term, "/", sizeof(term) - 1 - strlen(term));
+	(void) strncat(term, speeds[ttyb.sg_ospeed], sizeof(term) - 1 - strlen(term));
+    }
+#endif
+    (void) get_window_size(0, &winsize);
+    
+#ifdef POSIX_TERMIOS
+    tcgetattr(0, &defmodes);
+    tcgetattr(0, &ixon_state);
+#else
+#ifdef USE_TERMIO
+    /**** moved before rcmd call so that if get a SIGPIPE in rcmd **/
+    /**** we will have the defmodes set already. ***/
+    (void)ioctl(fileno(stdin), TIOCGETP, &defmodes);
+    (void)ioctl(fileno(stdin), TIOCGETP, &ixon_state);
+#endif
+#endif
+
+    /* Catch SIGPIPE, as that means we lost the connection */
+    /* will use SIGUSR1 for window size hack, so hold it off */
+#ifdef POSIX_SIGNALS
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = lostpeer;
+    (void) sigaction(SIGPIPE, &sa, (struct sigaction *)0);
+    
+    (void) sigemptyset(&urgmask);
+    (void) sigaddset(&urgmask, SIGUSR1);
+    oldmask = &omask;
+    (void) sigprocmask(SIG_BLOCK, &urgmask, oldmask);
+#else
+    (void) signal(SIGPIPE, lostpeer);
+#ifdef sgi
+    oldmask = sigignore( sigmask(SIGUSR1));
+#else
+    oldmask = sigblock( sigmask(SIGUSR1));
+#endif
+#endif /* POSIX_SIGNALS */
+
+#ifdef KERBEROS
+    authopts = AP_OPTS_MUTUAL_REQUIRED;
+
+    /* Piggy-back forwarding flags on top of authopts; */
+    /* they will be reset in kcmd */
+    if (fflag || Fflag)
+      authopts |= OPTS_FORWARD_CREDS;
+    if (Fflag)
+      authopts |= OPTS_FORWARDABLE_CREDS;
+
+#ifdef KRB5_KRB4_COMPAT
+    if (v4only)
+	goto try_v4;
+#endif
+    status = kcmd(&sock, &host, port,
+		  null_local_username ? "" : pwd->pw_name,
+		  name ? name : pwd->pw_name, term,
+		  0, "host", krb_realm,
+		  &cred,
+		  0,		/* No need for sequence number */
+		  0,		/* No need for server seq # */
+		  &local, &foreign,
+		  &auth_context, authopts,
+		  0,		/* Not any port # */
+		  0,
+		  &kcmd_proto);
+    if (status) {
+	if (kcmd_proto == KCMD_NEW_PROTOCOL && encrypt_flag)
+	    /* Don't fall back to something less secure.  */
+	    exit (1);
+#ifdef KRB5_KRB4_COMPAT
+	fprintf(stderr, "Trying krb4 rlogin...\n");
+    try_v4:
+	status = k4cmd(&sock, &host, port,
+		       null_local_username ? "" : pwd->pw_name,
+		       name ? name : pwd->pw_name, term,
+		       0, &v4_ticket, "rcmd", krb_realm,
+		       &v4_cred, v4_schedule, &v4_msg_data, &local, &foreign,
+		       (encrypt_flag) ? KOPT_DO_MUTUAL : 0L, 0);
+	if (status)
+	    try_normal(orig_argv);
+	rcmd_stream_init_krb4(v4_cred.session, encrypt_flag, 1, 1);
+#else
+	try_normal(orig_argv);
+#endif
+    } else {
+	krb5_keyblock *key = 0;
+
+	if (kcmd_proto == KCMD_NEW_PROTOCOL) {
+	    do_inband = 1;
+
+	    status = krb5_auth_con_getsendsubkey (bsd_context, auth_context,
+						  &key);
+	    if ((status || !key) && encrypt_flag)
+		try_normal(orig_argv);
+	}
+	if (key == 0)
+	    key = &cred->keyblock;
+
+	rcmd_stream_init_krb5(key, encrypt_flag, 1, 1, kcmd_proto);
+    }
+	
+    rem = sock;
+    
+#else
+    rem = rcmd(&host, port,
+	       null_local_username ? "" : pwd->pw_name,
+	       name ? name : pwd->pw_name, term, 0);
+#endif /* KERBEROS */
+
+    if (rem < 0)
+      exit(1);
+    
+    if (options & SO_DEBUG &&
+	setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char*)&on, sizeof (on)) < 0)
+      perror("rlogin: setsockopt (SO_DEBUG)");
+    uid = getuid();
+    if (setuid(uid) < 0) {
+	perror("rlogin: setuid");
+	exit(1);
+    }
+    flowcontrol = flow;  /* Set up really correct non-volatile variable */
+    doit(oldmask);
+    /*NOTREACHED*/
+  usage:
+#ifdef KERBEROS
+    fprintf (stderr,
+	     "usage: rlogin host [-option] [-option...] [-k realm ] [-t ttytype] [-l username]\n");
+#ifdef KRB5_KRB4_COMPAT
+    fprintf (stderr, "     where option is e, 7, 8, noflow, n, a, x, f, F, c, 4, PO, or PN\n");
+#else
+    fprintf (stderr, "     where option is e, 7, 8, noflow, n, a, x, f, F, c, PO, or PN\n");
+#endif
+#else /* !KERBEROS */
+    fprintf (stderr,
+	     "usage: rlogin host [-option] [-option...] [-t ttytype] [-l username]\n");
+    fprintf (stderr, "     where option is e, 7, 8, noflow, n, a, or c\n");
+#endif /* KERBEROS */
+    exit(1);
+}
+
+
+
+static int confirm_death ()
+{
+    char hostname[33];
+    char input;
+    int answer;
+    if (!confirm) return (1);	/* no confirm, just die */
+    
+    if (gethostname (hostname, sizeof(hostname)-1) != 0)
+      strcpy (hostname, "???");
+    else
+      hostname[sizeof(hostname)-1] = '\0';
+    
+    fprintf (stderr, "\r\nKill session on %s from %s (y/n)?  ",
+	     host, hostname);
+    fflush (stderr);
+    if (read(0, &input, 1) != 1)
+      answer = EOF;	/* read from stdin */
+    else
+      answer = (int) input;
+    fprintf (stderr, "%c\r\n", answer);
+    fflush (stderr);
+    return (answer == 'y' || answer == 'Y' || answer == EOF ||
+	    answer == 4);	/* control-D */
+}
+
+
+
+#define CRLF "\r\n"
+
+int	child;
+krb5_sigtype	catchild (int);
+krb5_sigtype	writeroob (int);
+
+int	defflags, tabflag;
+int	deflflags;
+char	deferase, defkill;
+
+#ifdef USE_TERMIO
+char defvtim, defvmin;
+#if defined(hpux) || defined(__hpux)
+#include <sys/bsdtty.h>
+#include <sys/ptyio.h>
+#endif
+struct tchars {
+    char    t_intrc;        /* interrupt */
+    char    t_quitc;        /* quit */
+    char    t_startc;       /* start output */
+    char    t_stopc;        /* stop output */
+    char    t_eofc;         /* end-of-file */
+    char    t_brkc;         /* input delimiter (like nl) */
+};
+#endif
+
+
+#ifndef POSIX_TERMIOS
+#ifdef TIOCGLTC
+/*
+ * POSIX 1003.1-1988 does not define a 'suspend' character.
+ * POSIX 1003.1-1990 does define an optional VSUSP but not a VDSUSP character.
+ * Some termio implementations (A/UX, Ultrix 4.2) include both.
+ *
+ * However, since this is all derived from the BSD ioctl() and ltchars
+ * concept, all these implementations generally also allow for the BSD-style
+ * ioctl().  So we'll simplify the problem by only testing for the ioctl().
+ */
+struct	ltchars defltc;
+struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
+#endif
+struct	tchars deftc;
+struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
+#endif
+
+static void doit(oldmask)
+#ifdef POSIX_SIGNALS
+    sigset_t *oldmask;
+#else
+    int oldmask;
+#endif
+{
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+
+#ifdef POSIX_TERMIOS
+    (void) tcgetattr(0, &deftty);
+#ifdef VLNEXT
+    /* there's a POSIX way of doing this, but do we need it general? */
+    deftty.c_cc[VLNEXT] = 0;
+#endif
+#else
+#ifdef USE_TERMIO
+    struct termio sb;
+#else
+    struct sgttyb sb;
+#endif
+    
+    (void) ioctl(0, TIOCGETP, (char *)&sb);
+    defflags = sb.sg_flags;
+#ifdef USE_TERMIO
+    tabflag = sb.c_oflag & TABDLY;
+    defflags |= ECHO;
+    deferase = sb.c_cc[VERASE];
+    defkill = sb.c_cc[VKILL];
+    sb.c_cc[VMIN] = 1;
+    sb.c_cc[VTIME] = 1;
+    defvtim = sb.c_cc[VTIME];
+    defvmin = sb.c_cc[VMIN];
+    deftc.t_quitc = CQUIT;
+    deftc.t_startc = CSTART;
+    deftc.t_stopc = CSTOP ;
+    deftc.t_eofc = CEOF;
+    deftc.t_brkc =  '\n';
+#else
+    tabflag = defflags & TBDELAY;
+    defflags &= ECHO | CRMOD;
+    deferase = sb.sg_erase;
+    defkill = sb.sg_kill;
+    (void) ioctl(0, TIOCLGET, (char *)&deflflags);
+    (void) ioctl(0, TIOCGETC, (char *)&deftc);
+#endif
+
+    notc.t_startc = deftc.t_startc;
+    notc.t_stopc = deftc.t_stopc;
+    (void) ioctl(0, TIOCGLTC, (char *)&defltc);
+#endif
+#ifdef POSIX_SIGNALS
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGINT, &sa, (struct sigaction *)0);
+#else
+    (void) signal(SIGINT, SIG_IGN);
+#endif
+
+    setsignal(SIGHUP, exit_handler);
+    setsignal(SIGQUIT, exit_handler);
+
+    child = fork();
+    if (child == -1) {
+	perror("rlogin: fork");
+	done(1);
+    }
+    if (child == 0) {
+	mode(1);
+	if (reader(oldmask) == 0) {
+	    prf("Connection closed.");
+	    exit(0);
+	}
+	sleep(1);
+	prf("\007Connection closed.");
+	exit(3);
+    }
+    
+#ifdef POSIX_SIGNALS
+    /* "sa" has already been initialized above. */
+
+    sa.sa_handler = writeroob;
+    (void) sigaction(SIGUSR1, &sa, (struct sigaction *)0);
+    
+    sigprocmask(SIG_SETMASK, oldmask, (sigset_t*)0);
+
+    sa.sa_handler = catchild;
+    (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
+#else
+    (void) signal(SIGUSR1, writeroob);
+#ifndef sgi
+    (void) sigsetmask(oldmask);
+#endif
+    (void) signal(SIGCHLD, catchild);
+#endif /* POSIX_SIGNALS */
+    writer();
+    prf("Closed connection.");
+    done(0);
+}
+
+
+
+/*
+ * Trap a signal, unless it is being ignored.
+ */
+void
+setsignal(sig, act)
+     int sig;
+     krb5_sigtype (*act)();
+{
+#ifdef POSIX_SIGNALS
+    sigset_t omask, igmask;
+    struct sigaction sa;
+    
+    sigemptyset(&igmask);
+    sigaddset(&igmask, sig);
+    sigprocmask(SIG_BLOCK, &igmask, &omask);
+#else
+#ifdef sgi
+    int omask = sigignore(sigmask(sig));
+#else
+    int omask = sigblock(sigmask(sig));
+#endif
+#endif /* POSIX_SIGNALS */
+    
+#ifdef POSIX_SIGNALS
+    (void) sigaction(sig, (struct sigaction *)0, &sa);
+    if (sa.sa_handler != SIG_IGN) {
+	(void) sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	sa.sa_handler = act;
+	(void) sigaction(sig, &sa, (struct sigaction *)0);
+    }
+    sigprocmask(SIG_SETMASK, &omask, (sigset_t*)0);
+#else    
+    if (signal(sig, act) == SIG_IGN)
+	(void) signal(sig, SIG_IGN);
+#ifndef sgi
+    (void) sigsetmask(omask);
+#endif
+#endif
+}
+
+
+
+static void
+done(status)
+     int status;
+{
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+#ifndef HAVE_WAITPID
+    pid_t w;
+#endif
+    
+    mode(0);
+    if (child > 0) {
+	/* make sure catchild does not snap it up */
+#ifdef POSIX_SIGNALS
+	(void) sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	sa.sa_handler = SIG_DFL;
+	(void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
+#else
+	(void) signal(SIGCHLD, SIG_DFL);
+#endif
+	
+	if (kill(child, SIGKILL) >= 0) {
+#ifdef HAVE_WAITPID
+	    (void) waitpid(child, 0, 0);
+#else
+	    while ((w = wait(0)) > 0 && w != child)
+		/*void*/;
+#endif
+	}
+    }
+    exit(status);
+}
+
+
+
+
+
+
+/*
+ * This is called when the reader process gets the out-of-band (urgent)
+ * request to turn on the window-changing protocol.
+ */
+krb5_sigtype
+  writeroob(signo)
+int signo;
+{
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+    
+    if (dosigwinch == 0) {
+	sendwindow();
+#ifdef POSIX_SIGNALS
+	(void) sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	sa.sa_handler = sigwinch;
+	(void) sigaction(SIGWINCH, &sa, (struct sigaction *)0);
+#else
+	(void) signal(SIGWINCH, sigwinch);
+#endif
+    }
+    dosigwinch = 1;
+}
+
+
+
+krb5_sigtype
+  catchild(signo)
+int signo;
+{
+#ifdef WAIT_USES_INT
+    int status;
+#else
+    union wait status;
+#endif
+    int pid;
+    
+  again:
+#ifdef HAVE_WAITPID
+    pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
+#else
+    pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
+#endif
+    if (pid == 0)
+      return;
+    /*
+     * if the child (reader) dies, just quit
+     */
+#ifdef WAIT_USES_INT
+    if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
+      done(status);
+#else
+    if ((pid < 0) || ((pid == child) && (!WIFSTOPPED(status))))
+	done((int)(status.w_termsig | status.w_retcode));
+#endif
+    goto again;
+}
+
+
+
+/*
+ * writer: write to remote: 0 -> line.
+ * ~.	terminate
+ * ~^Z	suspend rlogin process.
+ * ~^Y  suspend rlogin process, but leave reader alone.
+ */
+static void writer()
+{
+    int n_read;
+    char buf[1024];
+    int got_esc; /* set to true by read_wrapper if an escape char
+		    was encountered */
+    char c;
+
+#ifdef ultrix             
+    fd_set waitread;
+    register n;
+    
+    /* we need to wait until the reader() has set up the terminal, else
+       the read() below may block and not unblock when the terminal
+       state is reset.
+       */
+    for (;;) {
+	FD_ZERO(&waitread);
+	FD_SET(0, &waitread);
+	n = select(8*sizeof(waitread), &waitread, 0, 0, 0, 0);
+	if (n < 0 && errno == EINTR)
+	  continue;
+	if (n > 0)
+	  break;
+	else
+	  if (n < 0) {
+	      perror("select");
+	      break;
+	  }
+    }
+#endif /* ultrix */
+
+    /* This loop works as follows.  Call read_wrapper to get data until
+       we would block or until we read a cmdchar at the beginning of a line.
+       If got_esc is false, we just send everything we got back.  If got_esc 
+       is true, we send everything except the cmdchar at the end and look at 
+       the next char.  If its a "." we break out of the loop and terminate.
+       If its ^Z or ^Y we call stop with the value of the char and continue.
+       If its none of those, we send the cmdchar and then send the char we 
+       just read, unless that char is also the cmdchar (in which case we are
+       only supposed to send one of them).  When this loop ends, so does the
+       program.
+    */
+
+    for (;;) {
+
+      /* read until we would block or we get a cmdchar */
+      n_read = read_wrapper(0,buf,sizeof(buf),&got_esc);
+  
+      /* if read returns an error or 0 bytes, just quit */
+      if (n_read <= 0) {
+	break;
+      }
+      
+      if (!got_esc) {
+	if (rcmd_stream_write(rem, buf, (unsigned) n_read, 0) == 0) {
+	  prf("line gone");
+	  break;
+	}
+	continue;
+      }
+      else {
+	/* This next test is necessary to avoid sending 0 bytes of data
+	   in the event that we got just a cmdchar */
+	if (n_read > 1) {
+	  if (rcmd_stream_write(rem, buf, (unsigned) (n_read-1), 0) == 0) {
+	    prf("line gone");
+	    break;
+	  }
+	}
+	if (read_wrapper(0,&c,1,&got_esc) <= 0) {
+	  break;
+	}
+
+#ifdef POSIX_TERMIOS
+	if (c == '.' || c == deftty.c_cc[VEOF]) 
+#else
+	  if (c == '.' || c == deftc.t_eofc) 
+#endif
+	    {
+	      if (confirm_death()) {
+		echo(c);
+		break; 
+	      }
+	    }
+
+#ifdef POSIX_TERMIOS
+	if ( (
+	      (c == deftty.c_cc[VSUSP]) 
+#ifdef VDSUSP
+	      || (c == deftty.c_cc[VDSUSP]) 
+#endif
+	      )
+	     && !no_local_escape) {
+	  echo(c);
+	  stop(c);
+	  continue;
+	}
+#else /*POSIX_TERMIOS*/
+#ifdef TIOCGLTC
+	if ((c == defltc.t_suspc || c == defltc.t_dsuspc)
+	    && !no_local_escape) {
+	  echo(c);
+	  stop(c);
+	  continue;
+	}
+#endif /*TIOCGLTC*/
+#endif
+
+      
+	if (c != cmdchar) {
+	  rcmd_stream_write(rem, &cmdchar, 1, 0);
+	}
+
+	if (rcmd_stream_write(rem,&c,1,0) == 0) {
+	  prf("line gone");
+	  break;
+	}
+      }
+    }
+}
+
+/* This function reads up to size bytes from file desciptor fd into buf.
+   It will copy as much data as it can without blocking, but will never
+   copy more than size bytes.  In addition, if it encounters a cmdchar
+   at the beginning of a line, it will copy everything up to and including
+   the cmdchar, but nothing after that.  In this instance *esc_char is set
+   to true and any remaining data is buffered and copied on a subsequent 
+   call.  Otherwise, *esc_char will be set to false and the minimum of size,
+   1024, and the number of bytes that can be read without blocking will
+   be copied.  In all cases, a non-negative return value indicates the number 
+   of bytes actually copied and a return value of -1 indicates that there
+   was a read error (other than EINTR) and errno is set appropriately. 
+*/
+
+static int read_wrapper(fd,buf,size,got_esc) 
+     int fd;
+     char *buf;
+     int size;
+     int *got_esc;
+{
+  static char tbuf[1024];
+  static char *data_start = tbuf;
+  static char *data_end = tbuf;
+  static int bol = 1;
+  unsigned int return_length = 0;
+  char c;
+
+  /* if we have no data buffered, get more */
+  if (data_start == data_end) {
+    int n_read;
+    while ((n_read = read(fd, tbuf, sizeof(tbuf))) <= 0) {
+      if (n_read < 0 && errno == EINTR)
+	continue;
+      return n_read;
+    }
+    data_start = tbuf;
+    data_end = tbuf+n_read;
+  }
+
+  *got_esc = 0;
+
+  /* We stop when we've fully checked the buffer or have checked size
+     bytes.  We break out and set *got_esc if we encounter a cmdchar
+     at the beginning of a line.
+  */
+
+  while (data_start+return_length < data_end && return_length < size) {
+    
+    c = *(data_start+return_length);
+    return_length++;
+
+    if (bol == 1 && c == cmdchar) {
+      bol = 0;
+      *got_esc = 1;
+      break;
+    }
+
+#ifdef POSIX_TERMIOS
+    bol = (c == deftty.c_cc[VKILL] ||
+	   c == deftty.c_cc[VINTR] ||
+	   c == '\r' || c == '\n');
+	
+#else /* !POSIX_TERMIOS */
+    bol = c == defkill || c == deftc.t_eofc ||
+      c == deftc.t_intrc || c == defltc.t_suspc ||
+      c == '\r' || c == '\n';
+#endif
+  }
+   
+  memcpy(buf, data_start, return_length);
+  data_start = data_start + return_length;
+  return return_length;
+}
+
+static void echo(c)
+     register char c;
+{
+    char buf[8];
+    register char *p = buf;
+    
+    c &= 0177;
+    *p++ = cmdchar;
+    if (c < ' ') {
+	*p++ = '^';
+	*p++ = c + '@';
+    } else if (c == 0177) {
+	*p++ = '^';
+	*p++ = '?';
+    } else
+      *p++ = c;
+    *p++ = '\r';
+    *p++ = '\n';
+    (void) write(1, buf, (unsigned) (p - buf));
+}
+
+
+
+static void stop(cmdc)
+     char cmdc;
+{
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+    
+    mode(0);
+
+#ifdef POSIX_SIGNALS
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
+#else
+    (void) signal(SIGCHLD, SIG_IGN);
+#endif
+    
+#ifdef POSIX_TERMIOS
+    (void) kill(cmdc == deftty.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP);
+#else
+#ifdef TIOCGLTC
+    (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
+#endif
+#endif
+#ifdef POSIX_SIGNALS
+    sa.sa_handler = catchild;
+    (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
+#else
+    (void) signal(SIGCHLD, catchild);
+#endif
+    
+    mode(1);
+    sigwinch(SIGWINCH);		/* check for size changes */
+}
+
+
+
+krb5_sigtype
+  sigwinch(signo)
+int signo;
+{
+    struct winsize ws;
+    
+    if (dosigwinch && get_window_size(0, &ws) == 0 &&
+	memcmp(&winsize, &ws, sizeof (ws))) {
+	winsize = ws;
+	sendwindow();
+    }
+}
+
+
+
+/*
+ * Send the window size to the server via the magic escape
+ */
+static void sendwindow()
+{
+    char obuf[4 + sizeof (struct winsize)];
+    struct winsize *wp = (struct winsize *)(void *)(obuf+4);
+    
+    obuf[0] = 0377;
+    obuf[1] = 0377;
+    obuf[2] = 's';
+    obuf[3] = 's';
+    wp->ws_row = htons(winsize.ws_row);
+    wp->ws_col = htons(winsize.ws_col);
+    wp->ws_xpixel = htons(winsize.ws_xpixel);
+    wp->ws_ypixel = htons(winsize.ws_ypixel);
+    (void) rcmd_stream_write(rem, obuf, sizeof(obuf), 0);
+}
+
+
+
+/*
+ * reader: read from remote: line -> 1
+ */
+#define	READING	1
+#define	WRITING	2
+
+char	rcvbuf[8 * 1024];
+int	rcvcnt;
+int	rcvstate;
+int	ppid;
+
+/* returns 1 if flush, 0 otherwise */
+
+int server_message(mark)
+     int mark;
+{
+#ifndef POSIX_TERMIOS
+    int out = FWRITE;
+#endif
+#ifdef POSIX_TERMIOS
+    struct termios tty;
+#else
+#ifdef USE_TERMIO
+    struct termio sb;
+#else
+    struct sgttyb sb;
+#endif
+#endif
+
+    if (mark & TIOCPKT_WINDOW) {
+	/*
+	 * Let server know about window size changes
+	 */
+	(void) kill(ppid, SIGUSR1);
+    }
+#ifdef POSIX_TERMIOS
+    if (!eight && (mark & TIOCPKT_NOSTOP)) {
+      (void) tcgetattr(0, &tty);
+      tty.c_iflag &= ~IXON;
+      (void) tcsetattr(0, TCSADRAIN, &tty);
+    }
+    if (!eight && (mark & TIOCPKT_DOSTOP)) {
+      (void) tcgetattr(0, &tty);
+      tty.c_iflag |= IXON;
+      (void) tcsetattr(0, TCSADRAIN, &tty);
+    }
+#else
+    if (!eight && (mark & TIOCPKT_NOSTOP)) {
+	(void) ioctl(0, TIOCGETP, (char *)&sb);
+#ifdef USE_TERMIO
+	sb.c_iflag |= IXOFF;
+	sb.sg_flags &= ~ICANON;
+#else
+	sb.sg_flags &= ~CBREAK;
+	sb.sg_flags |= RAW;
+	notc.t_stopc = -1;
+	notc.t_startc = -1;
+	(void) ioctl(0, TIOCSETC, (char *)¬c);
+#endif
+	(void) ioctl(0, TIOCSETN, (char *)&sb);
+    }
+    if (!eight && (mark & TIOCPKT_DOSTOP)) {
+	(void) ioctl(0, TIOCGETP, (char *)&sb);
+#ifdef USE_TERMIO
+	sb.sg_flags  |= ICANON;
+	sb.c_iflag |= IXON;
+#else
+	sb.sg_flags &= ~RAW;
+	sb.sg_flags |= CBREAK;
+	notc.t_stopc = deftc.t_stopc;
+	notc.t_startc = deftc.t_startc;
+	(void) ioctl(0, TIOCSETC, (char *)¬c);
+#endif
+	(void) ioctl(0, TIOCSETN, (char *)&sb);
+    }
+#endif
+    if (mark & TIOCPKT_FLUSHWRITE) {
+#ifdef POSIX_TERMIOS
+        (void) tcflush(1, TCOFLUSH);
+#else
+#ifdef  TIOCFLUSH
+	(void) ioctl(1, TIOCFLUSH, (char *)&out);
+#else
+	(void) ioctl(1, TCFLSH, 1);
+#endif
+#endif
+	return(1);
+    }
+
+    return(0);
+}
+
+void oob()
+{
+    char mark;
+    static char waste[RLOGIN_BUFSIZ];
+    int atmark, n;
+
+    mark = 0;
+    
+    recv(rem, &mark, 1, MSG_OOB);
+
+    if (server_message(mark)) {
+	for (;;) {
+	    if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
+		perror("ioctl");
+		return;
+	    }
+	    if (atmark)
+		break;
+	    n = read(rem, waste, sizeof (waste));
+	    if (n <= 0)
+		break;
+	}
+    }
+}
+
+/* two control messages are defined:
+
+   a double flag byte of 'o' indicates a one-byte message which is
+   identical to what was once carried out of band.  
+
+   a double flag byte of 'q' indicates a zero-byte message.  This
+   message is interpreted as two \377 data bytes.  This is just a
+   quote rule so that binary data from the server does not confuse the
+   client.  */
+
+static int control(cp, n)
+     char *cp;
+     unsigned int n;
+{
+    if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
+	if (server_message(cp[4]))
+	    return(-5);
+	return(5);
+    } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
+	/* this is somewhat of a hack */
+	cp[2] = '\377';
+	cp[3] = '\377';
+	return(2);
+    }
+
+    return(0);
+}
+
+/*
+ * reader: read from remote: line -> 1 
+ */
+static int 
+reader(oldmask)
+#ifdef POSIX_SIGNALS
+    sigset_t *oldmask;
+#else
+     int oldmask;
+#endif
+{
+    fd_set readset, excset, writeset;
+    int n, remaining;
+    unsigned int left;
+    char *bufp = rcvbuf;
+    char *cp;
+
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);
+
+#else    
+    (void) signal(SIGTTOU, SIG_IGN);
+#endif
+    
+    ppid = getppid();
+    FD_ZERO(&readset);
+    FD_ZERO(&excset);
+    FD_ZERO(&writeset);
+#ifdef POSIX_SIGNALS
+    sigprocmask(SIG_SETMASK, oldmask, (sigset_t*)0);
+#else
+#ifndef sgi
+    (void) sigsetmask(oldmask);
+#endif
+#endif /* POSIX_SIGNALS */
+
+    for (;;) {
+	if ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
+	    FD_SET(1,&writeset);
+	    rcvstate = WRITING;
+	    FD_CLR(rem, &readset);
+	} else {
+	    bufp = rcvbuf;
+	    rcvcnt = 0;
+	    rcvstate = READING;
+	    FD_SET(rem,&readset);
+	    FD_CLR(1,&writeset);
+	}
+	if (!do_inband)
+	    FD_SET(rem,&excset);
+	if (select(rem+1, &readset, &writeset, &excset, 0) > 0 ) {
+	    if (!do_inband)
+		if (FD_ISSET(rem, &excset))
+		    oob();
+	    if (FD_ISSET(1,&writeset)) {
+		n = write(1, bufp, remaining);
+		if (n < 0) {
+		    if (errno != EINTR)
+			return (-1);
+		    continue;
+		}
+		bufp += n;
+	    }
+	    if (FD_ISSET(rem, &readset)) {
+	  	rcvcnt = rcmd_stream_read(rem, rcvbuf, sizeof (rcvbuf), 0);
+		if (rcvcnt == 0)
+		    return (0);
+		if (rcvcnt < 0)
+		    goto error;
+
+		if (do_inband) {
+		    for (cp = rcvbuf; cp < rcvbuf+rcvcnt-1; cp++) {
+			if (cp[0] == '\377' &&
+			    cp[1] == '\377') {
+			    left = (rcvbuf+rcvcnt) - cp;
+			    n = control(cp, left);
+			    /* |n| <= left */
+			    if (n < 0) {
+				left -= (-n);
+				rcvcnt = 0;
+				/* flush before, and (-n) bytes */
+				if (left > 0)
+				    memmove(rcvbuf, cp+(-n), left);
+				cp = rcvbuf-1;
+			    } else if (n) {
+				left -= n;
+				rcvcnt -= n;
+				if (left > 0)
+				    memmove(cp, cp+n, left);
+				cp--;
+			    }
+			}
+		    }
+		}
+	    }
+	} else
+error:
+	{
+	    if (errno == EINTR)
+	      continue;
+	    perror("read");
+	    return (-1);
+	}
+    }
+}
+
+
+
+static void mode(f)
+int f;
+{
+#ifdef POSIX_TERMIOS
+    struct termios newtty;
+#ifndef IEXTEN
+#define IEXTEN 0 /* No effect*/
+#endif
+#ifndef _POSIX_VDISABLE
+#define _POSIX_VDISABLE 0 /*A good guess at the disable-this-character character*/
+#endif
+
+    switch(f) {
+    case 0:
+	(void) tcsetattr(0, TCSADRAIN, &deftty);
+	break;
+    case 1:
+	(void) tcgetattr(0, &newtty);
+	/* was __svr4__ */
+#ifdef VLNEXT
+	/* there's a POSIX way of doing this, but do we need it general? */
+	newtty.c_cc[VLNEXT] = _POSIX_VDISABLE;
+#endif
+		
+	newtty.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN);
+	newtty.c_iflag &= ~(ISTRIP|INLCR|ICRNL);
+
+	if (!flow) {
+	    newtty.c_iflag &= ~(BRKINT|IXON|IXANY);
+	    newtty.c_oflag &= ~(OPOST);
+	} else {
+	    /* XXX - should we set ixon ? */
+	    newtty.c_iflag &= ~(IXON|IXANY);
+	    newtty.c_iflag |=  (BRKINT);
+	    newtty.c_oflag &= ~(ONLCR|ONOCR);
+	    newtty.c_oflag |=  (OPOST);
+	}
+#ifdef TABDLY
+	/* preserve tab delays, but turn off XTABS */
+	if ((newtty.c_oflag & TABDLY) == TAB3)
+	    newtty.c_oflag &= ~TABDLY;
+#endif
+	if (!eight)
+	    newtty.c_iflag |= ISTRIP;
+	if (litout)
+	    newtty.c_oflag &= ~OPOST;
+
+	newtty.c_cc[VMIN] = 1;
+	newtty.c_cc[VTIME] = 0;
+	(void) tcsetattr(0, TCSADRAIN, &newtty);
+	break;
+    default:
+	return;
+	/* NOTREACHED */
+    }
+#else
+    struct ltchars *ltc;
+#ifdef USE_TERMIO
+    struct termio sb;
+#else
+    struct tchars *tc;
+    struct sgttyb sb;
+    int	lflags;
+    (void) ioctl(0, TIOCLGET, (char *)&lflags);
+#endif
+    
+    (void) ioctl(0, TIOCGETP, (char *)&sb);
+    switch (f) {
+	
+    case 0:
+#ifdef USE_TERMIO
+	/*
+	**      remember whether IXON was set, so it can be restored
+	**      when mode(1) is next done
+	*/
+	(void) ioctl(fileno(stdin), TIOCGETP, &ixon_state);
+	/*
+	**      copy the initial modes we saved into sb; this is
+	**      for restoring to the initial state
+	*/
+	(void)memcpy(&sb, &defmodes, sizeof(defmodes));
+	
+#else
+	sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
+	sb.sg_flags |= defflags|tabflag;
+	sb.sg_kill = defkill;
+	sb.sg_erase = deferase;
+	lflags = deflflags;
+	tc = &deftc;
+#endif
+	ltc = &defltc;
+	break;
+	
+    case 1:
+#ifdef USE_TERMIO
+	/*
+	**      turn off output mappings
+	*/
+	sb.c_oflag &= ~(ONLCR|OCRNL);
+	/*
+	**      turn off canonical processing and character echo;
+	**      also turn off signal checking -- ICANON might be
+	**      enough to do this, but we're being careful
+	*/
+	sb.c_lflag &= ~(ECHO|ICANON|ISIG);
+	sb.c_cc[VTIME] = 1;
+	sb.c_cc[VMIN] = 1;
+	if (eight)
+	    sb.c_iflag &= ~(ISTRIP);
+#ifdef TABDLY
+	/* preserve tab delays, but turn off tab-to-space expansion */
+	if ((sb.c_oflag & TABDLY) == TAB3)
+	    sb.c_oflag &= ~TAB3;
+#endif
+	/*
+	**  restore current flow control state
+	*/
+	if ((ixon_state.c_iflag & IXON) && flow ) {
+	    sb.c_iflag |= IXON;
+	} else {
+	    sb.c_iflag &= ~IXON;
+	}
+#else /* ! USE_TERMIO */
+	sb.sg_flags &= ~(CBREAK|RAW);
+	sb.sg_flags |= (!flow ? RAW : CBREAK);
+	/* preserve tab delays, but turn off XTABS */
+	if ((sb.sg_flags & TBDELAY) == XTABS)
+	    sb.sg_flags &= ~TBDELAY;
+	sb.sg_kill = sb.sg_erase = -1;
+#ifdef LLITOUT
+	if (litout)
+	    lflags |= LLITOUT;
+#endif
+#ifdef LPASS8
+	if (eight)
+	    lflags |= LPASS8;
+#endif /* LPASS8 */
+	tc = ¬c;
+	sb.sg_flags &= ~defflags;
+#endif /* USE_TERMIO */
+	
+	ltc = &noltc;
+	break;
+	
+    default:
+	return;
+    }
+    (void) ioctl(0, TIOCSLTC, (char *)ltc);
+#ifndef USE_TERMIO
+    (void) ioctl(0, TIOCSETC, (char *)tc);
+    (void) ioctl(0, TIOCLSET, (char *)&lflags);
+#endif
+    (void) ioctl(0, TIOCSETN, (char *)&sb);
+#endif /* !POSIX_TERMIOS */
+}
+
+
+
+static void
+prf(f)
+     char *f;
+{
+    fprintf(stderr, f);
+    fprintf(stderr, CRLF);
+}
+
+
+
+#ifdef KERBEROS
+void try_normal(argv)
+     char **argv;
+{
+    register char *nhost;
+#ifdef POSIX_SIGNALS
+    sigset_t mask;
+#endif
+    
+#ifndef KRB5_ATHENA_COMPAT
+    if (encrypt_flag)
+      exit(1);
+#endif
+    fprintf(stderr,"trying normal rlogin (%s)\n",
+	    UCB_RLOGIN);
+    fflush(stderr);
+    
+    nhost = strrchr(argv[0], '/');
+    if (nhost)
+      nhost++;
+    else
+      nhost = argv[0];
+    if (!strcmp(nhost, "rlogin") || !strcmp(nhost, "rsh"))
+      argv[0] = UCB_RLOGIN;
+    
+#ifdef POSIX_SIGNALS
+    sigemptyset(&mask);
+    sigprocmask(SIG_SETMASK, &mask, NULL);
+#endif
+
+    execv(UCB_RLOGIN, argv);
+    perror("exec");
+    exit(1);
+}
+#endif
+
+
+
+krb5_sigtype lostpeer(signo)
+    int signo;
+{
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGPIPE, &sa, (struct sigaction *)0);
+#else
+    (void) signal(SIGPIPE, SIG_IGN);
+#endif
+    
+    prf("\007Connection closed.");
+    done(1);
+}
diff --git a/mechglue/src/appl/bsd/krlogind.c b/mechglue/src/appl/bsd/krlogind.c
new file mode 100644
index 000000000..02bed8e37
--- /dev/null
+++ b/mechglue/src/appl/bsd/krlogind.c
@@ -0,0 +1,1575 @@
+/*
+ *	appl/bsd/krlogind.c
+ */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)rlogind.c	5.17 (Berkeley) 8/31/88 */
+     
+     /*
+      * remote login server:
+      *	remuser\0
+      *	locuser\0
+      *	terminal info\0
+      *	data
+      */
+     
+/*
+ * This is the rlogin daemon. The very basic protocol for checking 
+ * authentication and authorization is:
+ * 1) Check authentication.
+ * 2) Check authorization via the access-control files: 
+ *    ~/.k5login (using krb5_kuserok) and/or
+ * 3) Prompt for password if any checks fail, or if so configured.
+ * Allow login if all goes well either by calling the accompanying 
+ * login.krb5 or /bin/login, according to the definition of 
+ * DO_NOT_USE_K_LOGIN.l
+ * 
+ * The configuration is done either by command-line arguments passed by 
+ * inetd, or by the name of the daemon. If command-line arguments are
+ * present, they  take priority. The options are:
+ * -k means trust krb4 or krb5
+* -5 means trust krb5
+* -4 means trust krb4
+ * -p and -P means prompt for password.
+ *    If the -P option is passed, then the password is verified in 
+ * addition to all other checks. If -p is not passed with -k or -r,
+ * and both checks fail, then login permission is denied.
+ *    - -e means use encryption.
+ *
+ *    If no command-line arguments are present, then the presence of the 
+ * letters kKrRexpP in the program-name before "logind" determine the 
+ * behaviour of the program exactly as with the command-line arguments.
+ *
+ * If the ruserok check is to be used, then the client should connect
+ * from a privileged port, else deny permission.
+ */ 
+     
+/* DEFINES:
+ *   KERBEROS - Define this if application is to be kerberised.
+ *   CRYPT    - Define this if encryption is to be an option.
+ *   DO_NOT_USE_K_LOGIN - Define this if you want to use /bin/login
+ *              instead  of the accompanying login.krb5. 
+ *   KRB5_KRB4_COMPAT - Define this if v4 rlogin clients are also to be served.
+ *   ALWAYS_V5_KUSEROK - Define this if you want .k5login to be
+ *              checked even for v4 clients (instead of .klogin).
+ *   LOG_ALL_LOGINS - Define this if you want to log all logins.
+ *   LOG_OTHER_USERS - Define this if you want to log all principals
+ *              that do not map onto the local user.
+ *   LOG_REMOTE_REALM - Define this if you want to log all principals from 
+ *              remote realms.
+ *       Note:  Root logins are always logged.
+ */
+
+/*
+ * This is usually done in the Makefile.  Actually, these sources may
+ * not work without the KERBEROS #defined.
+ *
+ * #define KERBEROS
+ */
+#define LOG_REMOTE_REALM
+#define CRYPT
+#define USE_LOGIN_F
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef __SCO__
+#include <sys/unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef KERBEROS
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
+#include <sys/socket.h>
+#endif
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <pwd.h>
+     
+#ifdef HAVE_SYS_LABEL_H
+/* only SunOS 4? */
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+     
+#include <signal.h>
+
+#if defined(hpux) || defined(__hpux)
+#include <sys/ptyio.h>
+#endif
+#ifdef sysvimp
+#include <compat.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_STREAMS
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#endif
+
+#if defined(POSIX_TERMIOS) && !defined(ultrix)
+#include <termios.h>
+#else
+#include <sgtty.h>
+#endif
+
+#ifndef KERBEROS
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
+#include <netdb.h>
+#endif
+#include <syslog.h>
+#include <string.h>
+#include <sys/param.h>
+
+#ifdef HAVE_STREAMS
+/* krlogin doesn't test sys/tty... */
+#ifdef HAVE_SYS_TTY_H
+#include <sys/tty.h>
+#endif
+
+#ifdef HAVE_SYS_PTYVAR_H
+/* Solaris actually uses packet mode, so the real macros are needed too */
+#include <sys/ptyvar.h>
+#endif
+#endif
+
+
+#ifndef TIOCPKT_NOSTOP
+/* These values are over-the-wire protocol, *not* local values */
+#define TIOCPKT_NOSTOP          0x10
+#define TIOCPKT_DOSTOP          0x20
+#define TIOCPKT_FLUSHWRITE      0x02
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+/* get FIONBIO from sys/filio.h, so what if it is a compatibility feature */
+#include <sys/filio.h>
+#endif
+
+#ifndef HAVE_KILLPG
+#define killpg(pid, sig) kill(-(pid), (sig))
+#endif
+
+#ifdef HAVE_PTSNAME
+/* HP/UX 9.04 has but does not declare ptsname.  */
+extern char *ptsname ();
+#endif
+
+#ifdef NO_WINSIZE
+struct winsize {
+    unsigned short ws_row, ws_col;
+    unsigned short ws_xpixel, ws_ypixel;
+};
+#endif /* NO_WINSIZE */
+     
+#ifndef roundup
+#define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
+#endif
+
+#include "fake-addrinfo.h"
+
+#ifdef KERBEROS
+     
+#include <krb5.h>
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+#include <libpty.h>
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#include <k5-util.h>
+#endif
+
+int auth_sys = 0;	/* Which version of Kerberos used to authenticate */
+
+#define KRB5_RECVAUTH_V4	4
+#define KRB5_RECVAUTH_V5	5
+
+int non_privileged = 0; /* set when connection is seen to be from */
+			/* a non-privileged port */
+
+#ifdef KRB5_KRB4_COMPAT
+AUTH_DAT	*v4_kdata;
+Key_schedule v4_schedule;
+#endif
+
+#include "com_err.h"
+#include "defines.h"
+     
+#define SECURE_MESSAGE  "This rlogin session is encrypting all data transmissions.\r\n"
+
+krb5_authenticator      *kdata;
+krb5_ticket     *ticket = 0;
+krb5_context bsd_context;
+krb5_ccache ccache = NULL;
+
+krb5_keytab keytab = NULL;
+
+#define ARGSTR	"k54ciepPD:S:M:L:fw:?"
+#else /* !KERBEROS */
+#define ARGSTR	"rpPD:f?"
+#endif /* KERBEROS */
+
+#ifndef LOGIN_PROGRAM
+#ifdef DO_NOT_USE_K_LOGIN
+#ifdef sysvimp
+#define LOGIN_PROGRAM "/bin/remlogin"
+#else
+#define LOGIN_PROGRAM "/bin/login"
+#endif
+#else /* DO_NOT_USE_K_LOGIN */
+#define LOGIN_PROGRAM KRB5_PATH_LOGIN
+#endif /* DO_NOT_USE_K_LOGIN */
+#endif /* LOGIN_PROGRAM */
+
+char *login_program = LOGIN_PROGRAM;
+
+#define MAXRETRIES 4
+#define MAX_PROG_NAME 16
+
+#ifndef UT_NAMESIZE	/* linux defines it directly in <utmp.h> */
+#define	UT_NAMESIZE	sizeof(((struct utmp *)0)->ut_name)
+#endif
+
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+
+#ifndef MAXDNAME
+#define MAXDNAME 256 /*per the rfc*/
+#endif
+
+char		lusername[UT_NAMESIZE+1];
+char		rusername[UT_NAMESIZE+1];
+char            *krusername = 0;
+char		term[64];
+char            rhost_name[MAXDNAME];
+char		rhost_addra[16];
+krb5_principal  client;
+int		do_inband = 0;
+
+int	reapchild();
+char 	*progname;
+
+static	int Pfd;
+
+#if defined(NEED_DAEMON_PROTO)
+extern int daemon(int, int);
+#endif
+
+#if (defined(_AIX) && defined(i386)) || defined(ibm032) || (defined(vax) && !defined(ultrix)) || (defined(SunOS) && SunOS > 40) || defined(solaris20)
+#define VHANG_FIRST
+#endif
+
+#if defined(ultrix)
+#define VHANG_LAST		/* vhangup must occur on close, not open */
+#endif
+
+void	fatal(int, const char *), fatalperror(int, const char *), doit(int, struct sockaddr *), usage(void), do_krb_login(char *, char *), getstr(int, char *, int, char *);
+void	protocol(int, int);
+int	princ_maps_to_lname(krb5_principal, char *), default_realm(krb5_principal);
+krb5_sigtype	cleanup(int);
+krb5_error_code recvauth(int *);
+
+/* There are two authentication related masks:
+   * auth_ok and auth_sent.
+* The auth_ok mask is the oring of authentication systems any one
+* of which can be used.  
+* The auth_sent mask is the oring of one or more authentication/authorization
+* systems that succeeded.  If the anding
+* of these two masks is true, then authorization is successful.
+*/
+#define AUTH_KRB4 (0x1)
+#define AUTH_KRB5 (0x2)
+int auth_ok = 0, auth_sent = 0;
+int do_encrypt = 0, passwd_if_fail = 0, passwd_req = 0;
+int checksum_required = 0, checksum_ignored = 0;
+
+int stripdomain = 1;
+int maxhostlen = 0;
+int always_ip = 0;
+
+int main(argc, argv)
+     int argc;
+     char **argv;
+{
+    extern int opterr, optind;
+    extern char * optarg;
+    int on = 1, ch;
+    socklen_t fromlen;
+    struct sockaddr_storage from;
+    int debug_port = 0;
+    int fd;
+    int do_fork = 0;
+#ifdef KERBEROS
+    krb5_error_code status;
+#endif
+    
+    progname = *argv;
+    
+    pty_init();
+    
+#ifndef LOG_NDELAY
+#define LOG_NDELAY 0
+#endif
+    
+#ifndef LOG_AUTH /* 4.2 syslog */
+    openlog(progname, LOG_PID | LOG_NDELAY);
+#else
+    openlog(progname, LOG_PID | LOG_NDELAY, LOG_AUTH);
+#endif /* 4.2 syslog */
+    
+#ifdef KERBEROS
+    status = krb5_init_context(&bsd_context);
+    if (status) {
+	    syslog(LOG_ERR, "Error initializing krb5: %s",
+		   error_message(status));
+	    exit(1);
+    }
+#endif
+    
+    /* Analyse parameters. */
+    opterr = 0;
+    while ((ch = getopt(argc, argv, ARGSTR)) != -1)
+      switch (ch) {
+#ifdef KERBEROS
+	case 'k':
+#ifdef KRB5_KRB4_COMPAT
+	auth_ok |= (AUTH_KRB5|AUTH_KRB4);
+#else
+	auth_ok |= AUTH_KRB5;
+#endif /* KRB5_KRB4_COMPAT*/
+	break;
+	
+      case '5':
+	  auth_ok |= AUTH_KRB5;
+	break;
+      case 'c':
+	checksum_required = 1;
+	break;
+      case 'i':
+	checksum_ignored = 1;
+	break;
+	
+#ifdef KRB5_KRB4_COMPAT
+      case '4':
+	auth_ok |= AUTH_KRB4;
+	break;
+#endif
+#ifdef CRYPT
+	case 'x':         /* Use encryption. */
+	case 'X':
+	case 'e':
+	case 'E':
+	  do_encrypt = 1;
+	  break;
+#endif
+	case 'S':
+	  if ((status = krb5_kt_resolve(bsd_context, optarg, &keytab))) {
+		  com_err(progname, status, "while resolving srvtab file %s",
+			  optarg);
+		  exit(2);
+	  }
+	  break;
+	case 'M':
+	  krb5_set_default_realm(bsd_context, optarg);
+	  break;
+#endif
+	case 'p':
+	  passwd_if_fail = 1; /* Passwd reqd if any check fails */
+	  break;
+	case 'P':         /* passwd is a must */
+	  passwd_req = 1;
+	  break;
+	case 'D':
+	  debug_port = atoi(optarg);
+	  break;
+	case 'L':
+	  login_program = optarg;
+	  break;
+        case 'f':
+	  do_fork = 1;
+	  break;
+	case 'w':
+	  if (!strcmp(optarg, "ip"))
+	    always_ip = 1;
+	  else {
+	    char *cp;
+	    cp = strchr(optarg, ',');
+	    if (cp == NULL)
+	      maxhostlen = atoi(optarg);
+	    else if (*(++cp)) {
+	      if (!strcmp(cp, "striplocal"))
+		stripdomain = 1;
+	      else if (!strcmp(cp, "nostriplocal"))
+		stripdomain = 0;
+	      else {
+		usage();
+		exit(1);
+	      }
+	      *(--cp) = '\0';
+	      maxhostlen = atoi(optarg);
+	    }
+	  }
+	  break;
+	case '?':
+	default:
+	  usage();
+	  exit(1);
+	  break;
+      }
+    argc -= optind;
+    argv += optind;
+    
+    fromlen = sizeof (from);
+
+    if (debug_port || do_fork) {
+	int s;
+	struct servent *ent;
+	struct sockaddr_in sock_in;
+
+	if (!debug_port) {
+	    if (do_encrypt) {
+		ent = getservbyname("eklogin", "tcp");
+		if (ent == NULL)
+		    debug_port = 2105;
+		else
+		    debug_port = ent->s_port;
+	    } else {
+		ent = getservbyname("klogin", "tcp");
+		if (ent == NULL)
+		    debug_port = 543;
+		else
+		    debug_port = ent->s_port;
+	    }
+	}
+	if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
+	    fprintf(stderr, "Error in socket: %s\n", strerror(errno));
+	    exit(2);
+	}
+	memset((char *) &sock_in, 0,sizeof(sock_in));
+	sock_in.sin_family = AF_INET;
+	sock_in.sin_port = htons(debug_port);
+	sock_in.sin_addr.s_addr = INADDR_ANY;
+
+	if (!do_fork)
+	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+			      (char *)&on, sizeof(on));
+
+	if ((bind(s, (struct sockaddr *) &sock_in, sizeof(sock_in))) < 0) {
+	    fprintf(stderr, "Error in bind: %s\n", strerror(errno));
+	    exit(2);
+	}
+
+	if ((listen(s, 5)) < 0) {
+	    fprintf(stderr, "Error in listen: %s\n", strerror(errno));
+	    exit(2);
+	}
+
+	if (do_fork) {
+	    if (daemon(0, 0)) {
+		fprintf(stderr, "daemon() failed\n");
+		exit(2);
+	    }
+	    while (1) {
+		int child_pid;
+
+		fd = accept(s, (struct sockaddr *) &from, &fromlen);
+		if (s < 0) {
+		    if (errno != EINTR)
+			syslog(LOG_ERR, "accept: %s", error_message(errno));
+		    continue;
+		}
+		child_pid = fork();
+		switch (child_pid) {
+		case -1:
+		    syslog(LOG_ERR, "fork: %s", error_message(errno));
+		case 0:
+		    (void) close(s);
+		    doit(fd, (struct sockaddr *) &from);
+		    close(fd);
+		    exit(0);
+		default:
+		    wait(0);
+		    close(fd);
+		}
+	    }
+	}
+
+	if ((fd = accept(s, (struct sockaddr *) &from, &fromlen)) < 0) {
+	    fprintf(stderr, "Error in accept: %s\n", strerror(errno));
+	    exit(2);
+	}
+
+	close(s);
+    } else {			/* !do_fork && !debug_port */
+	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+	    syslog(LOG_ERR,"Can't get peer name of remote host: %m");
+#ifdef STDERR_FILENO
+	    fatal(STDERR_FILENO, "Can't get peer name of remote host");
+#else
+	    fatal(2, "Can't get peer name of remote host");
+#endif
+	}
+	fd = 0;
+    }
+
+    doit(fd, (struct sockaddr *) &from);
+    return 0;
+}
+
+
+
+#ifndef LOG_AUTH
+#define LOG_AUTH 0
+#endif
+
+int	child;
+int	netf;
+char	line[MAXPATHLEN];
+extern	char	*inet_ntoa();
+
+#ifdef TIOCSWINSZ
+struct winsize win = { 0, 0, 0, 0 };
+#endif
+
+int pid; /* child process id */
+
+void doit(f, fromp)
+  int f;
+  struct sockaddr *fromp;
+{
+    int p, t, on = 1;
+    char c;
+    char hname[NI_MAXHOST];
+    char buferror[255];
+    struct passwd *pwd;
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+    int retval;
+    char *rhost_sane;
+    int syncpipe[2];
+
+    netf = -1;
+    if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE,
+		   (const char *) &on, sizeof (on)) < 0)
+	syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+    if (auth_ok == 0) {
+	syslog(LOG_CRIT, "No authentication systems were enabled; all connections will be refused.");
+	fatal(f, "All authentication systems disabled; connection refused.");
+    }
+
+    if (checksum_required&&checksum_ignored) {
+	syslog( LOG_CRIT, "Checksums are required and ignored; these options are mutually exclusive--check the documentation.");
+	fatal(f, "Configuration error: mutually exclusive options specified");
+    }
+    
+    alarm(60);
+    read(f, &c, 1);
+    
+    if (c != 0){
+	exit(1);
+    }
+
+    alarm(0);
+    /* Initialize syncpipe */
+    if (pipe( syncpipe ) < 0 )
+	fatalperror ( f , "");
+    
+
+#ifdef POSIX_SIGNALS
+    /* Initialize "sa" structure. */
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+#endif
+
+    retval = getnameinfo(fromp, socklen(fromp), hname, sizeof(hname), 0, 0,
+			 NI_NUMERICHOST);
+    if (retval)
+	fatal(f, gai_strerror(retval));
+    strncpy(rhost_addra, hname, sizeof(rhost_addra));
+    rhost_addra[sizeof (rhost_addra) -1] = '\0';
+    
+    retval = getnameinfo(fromp, socklen(fromp), hname, sizeof(hname), 0, 0, 0);
+    if (retval)
+	fatal(f, gai_strerror(retval));
+    strncpy(rhost_name, hname, sizeof(rhost_name));
+    rhost_name[sizeof (rhost_name) - 1] = '\0';
+
+#ifndef KERBEROS
+    if (fromp->sin_family != AF_INET)
+	/* Not a real problem, we just haven't bothered to update
+	   the port number checking code to handle ipv6.  */
+      fatal(f, "Permission denied - Malformed from address\n");
+    
+    if (fromp->sin_port >= IPPORT_RESERVED ||
+	fromp->sin_port < IPPORT_RESERVED/2)
+      fatal(f, "Permission denied - Connection from bad port");
+#endif /* KERBEROS */
+    
+    /* Set global netf to f now : we may need to drop everything
+       in do_krb_login. */
+    netf = f;
+    
+#if defined(KERBEROS)
+    /* All validation, and authorization goes through do_krb_login() */
+    do_krb_login(rhost_addra, rhost_name);
+#else
+    getstr(f, rusername, sizeof(rusername), "remuser");
+    getstr(f, lusername, sizeof(lusername), "locuser");
+    getstr(f, term, sizeof(term), "Terminal type");
+    rcmd_stream_init_normal();
+#endif
+    
+    write(f, "", 1);
+    if ((retval = pty_getpty(&p,line, sizeof(line)))) {
+	com_err(progname, retval, "while getting master pty");
+	exit(2);
+    }
+    
+    Pfd = p;
+#ifdef TIOCSWINSZ
+    (void) ioctl(p, TIOCSWINSZ, &win);
+#endif
+    
+#ifdef POSIX_SIGNALS
+    sa.sa_handler = cleanup;
+    (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
+    (void) sigaction(SIGTERM, &sa, (struct sigaction *)0);
+#else
+    signal(SIGCHLD, cleanup);
+    signal(SIGTERM, cleanup);
+#endif
+    pid = fork();
+    if (pid < 0)
+      fatalperror(f, "");
+    if (pid == 0) {
+#if defined(POSIX_TERMIOS) && !defined(ultrix)
+	struct termios new_termio;
+#else
+	struct sgttyb b;
+#endif /* POSIX_TERMIOS */
+	if ((retval = pty_open_slave(line, &t))) {
+	    fatal(f, error_message(retval));
+	    exit(1);
+	}
+	
+
+#if defined(POSIX_TERMIOS) && !defined(ultrix)
+	tcgetattr(t,&new_termio);
+#if !defined(USE_LOGIN_F)
+	new_termio.c_lflag &= ~(ICANON|ECHO|ISIG|IEXTEN);
+	new_termio.c_iflag &= ~(IXON|IXANY|BRKINT|INLCR|ICRNL);
+#else
+	new_termio.c_lflag |= (ICANON|ECHO|ISIG|IEXTEN);
+	new_termio.c_oflag |= (ONLCR|OPOST);
+	new_termio.c_iflag |= (IXON|IXANY|BRKINT|INLCR|ICRNL);
+#endif /*Do we need binary stream?*/
+	new_termio.c_iflag &= ~(ISTRIP);
+	/* new_termio.c_iflag = 0; */
+	/* new_termio.c_oflag = 0; */
+	new_termio.c_cc[VMIN] = 1;
+	new_termio.c_cc[VTIME] = 0;
+	tcsetattr(t,TCSANOW,&new_termio);
+#else
+	(void)ioctl(t, TIOCGETP, &b);
+	b.sg_flags = RAW|ANYP;
+	(void)ioctl(t, TIOCSETP, &b);
+#endif /* POSIX_TERMIOS */
+
+	pid = 0;			/*reset pid incase exec fails*/
+	    
+	/*
+	 **      signal the parent that we have turned off echo
+	 **      on the slave side of the pty ... he's waiting
+	 **      because otherwise the rlogin protocol junk gets
+	 **      echo'd to the user (locuser^@remuser^@term/baud)
+	 **      and we don't get the right tty affiliation, and
+	 **      other kinds of hell breaks loose ...
+	 */
+	(void) write(syncpipe[1], &c, 1);
+	(void) close(syncpipe[1]);
+	(void) close(syncpipe[0]);
+		
+	close(f), close(p);
+	dup2(t, 0), dup2(t, 1), dup2(t, 2);
+	if (t > 2)
+	  close(t);
+	
+#if defined(sysvimp)
+	setcompat (COMPAT_CLRPGROUP | (getcompat() & ~COMPAT_BSDTTY));
+#endif
+	
+	/* Log access to account */
+	pwd = (struct passwd *) getpwnam(lusername);
+	if (pwd && (pwd->pw_uid == 0)) {
+	    if (passwd_req)
+	      syslog(LOG_NOTICE, "ROOT login by %s (%s@%s (%s)) forcing password access",
+		     krusername ? krusername : "",
+		     rusername, rhost_addra, rhost_name);
+	    else
+	      syslog(LOG_NOTICE, "ROOT login by %s (%s@%s (%s))", 
+		     krusername ? krusername : "",
+		     rusername, rhost_addra, rhost_name);
+	}
+#ifdef KERBEROS
+#if defined(LOG_REMOTE_REALM) && !defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS)
+	/* Log if principal is from a remote realm */
+        else if (client && !default_realm(client))
+#endif /* LOG_REMOTE_REALM */
+  
+#if defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS) 
+	/* Log if principal name does not map to local username */
+        else if (client && !princ_maps_to_lname(client, lusername))
+#endif /* LOG_OTHER_USERS */
+
+#if defined(LOG_ALL_LOGINS)
+        else
+#endif /* LOG_ALL_LOGINS */
+
+#if defined(LOG_REMOTE_REALM) || defined(LOG_OTHER_USERS) || defined(LOG_ALL_LOGINS)
+	{
+	    if (passwd_req)
+	      syslog(LOG_NOTICE,
+		     "login by %s (%s@%s (%s)) as %s forcing password access",
+		     krusername ? krusername : "", rusername,
+		     rhost_addra, rhost_name, lusername);
+	    else 
+	      syslog(LOG_NOTICE,
+		     "login by %s (%s@%s (%s)) as %s",
+		     krusername ? krusername : "", rusername,
+		     rhost_addra, rhost_name, lusername); 
+	}
+#endif /* LOG_REMOTE_REALM || LOG_OTHER_USERS || LOG_ALL_LOGINS */
+#endif /* KERBEROS */
+
+#ifndef NO_UT_PID
+	{
+
+	    pty_update_utmp(PTY_LOGIN_PROCESS, getpid(), "rlogin", line,
+			    ""/*host*/, PTY_TTYSLOT_USABLE);
+	}
+#endif
+
+#ifdef USE_LOGIN_F
+/* use the vendors login, which has -p and -f. Tested on 
+ * AIX 4.1.4 and HPUX 10 
+ */
+    {
+        char *cp;
+        if ((cp = strchr(term,'/')))
+            *cp = '\0';
+        setenv("TERM",term, 1);
+    }
+
+    retval = pty_make_sane_hostname((struct sockaddr *) fromp, maxhostlen,
+				    stripdomain, always_ip,
+				    &rhost_sane);
+    if (retval)
+        fatalperror(f, "failed make_sane_hostname");
+    if (passwd_req)
+        execl(login_program, "login", "-p", "-h", rhost_sane,
+          lusername, (char *)NULL);
+    else
+        execl(login_program, "login", "-p", "-h", rhost_sane,
+             "-f", lusername, (char *)NULL);
+#else /* USE_LOGIN_F */
+	execl(login_program, "login", "-r", rhost_sane, (char *)NULL);
+#endif /* USE_LOGIN_F */
+	syslog(LOG_ERR, "failed exec of %s: %s",
+	       login_program, error_message(errno));
+	fatalperror(f, login_program);
+	/*NOTREACHED*/
+    } /* if (pid == 0) */
+
+    /*
+     **      wait for child to start ... read one byte
+     **      -- see the child, who writes one byte after
+     **      turning off echo on the slave side ...
+     **      The master blocks here until it reads a byte.
+     */
+    
+(void) close(syncpipe[1]);
+    if (read(syncpipe[0], &c, 1) != 1) {
+	/*
+	 * Problems read failed ...
+	 */
+	sprintf(buferror, "Cannot read slave pty %s ",line);
+	fatalperror(p,buferror);
+    }
+    close(syncpipe[0]);
+
+    
+#if defined(KERBEROS) 
+    if (do_encrypt) {
+	if (rcmd_stream_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE), 0) < 0){
+	    sprintf(buferror, "Cannot encrypt-write network.");
+	    fatal(p,buferror);
+	}
+    }
+    else 
+      /*
+       * if encrypting, don't turn on NBIO, else the read/write routines
+       * will fail to work properly
+       */
+#endif /* KERBEROS */
+      ioctl(f, FIONBIO, &on);
+    ioctl(p, FIONBIO, &on);
+
+    /* FIONBIO doesn't always work on ptys, use fcntl to set O_NDELAY? */
+    (void) fcntl(p,F_SETFL,fcntl(p,F_GETFL,0) | O_NDELAY);
+
+#ifdef POSIX_SIGNALS
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
+#else
+    signal(SIGTSTP, SIG_IGN);
+#endif
+
+    
+#if !defined(USE_LOGIN_F)
+    /* Pass down rusername and lusername to login. */
+    (void) write(p, rusername, strlen(rusername) +1);
+    (void) write(p, lusername, strlen(lusername) +1);
+    /* stuff term info down to login */
+    if ((write(p, term, strlen(term)+1) != (int) strlen(term)+1)) {
+	/*
+	 * Problems write failed ...
+	 */
+	sprintf(buferror,"Cannot write slave pty %s ",line);
+	fatalperror(f,buferror);
+    }
+
+#endif
+    protocol(f, p);
+    signal(SIGCHLD, SIG_IGN);
+    cleanup(0);
+}
+
+unsigned char	magic[2] = { 0377, 0377 };
+#ifdef TIOCSWINSZ
+#ifndef TIOCPKT_WINDOW
+#define TIOCPKT_WINDOW 0x80
+#endif
+unsigned char	oobdata[] = {TIOCPKT_WINDOW};
+#else
+char    oobdata[] = {0};
+#endif
+
+static 
+void sendoob(fd, byte)
+     int fd;
+     char *byte;
+{
+    char message[5];
+    int cc;
+
+    if (do_inband) {
+	message[0] = '\377';
+	message[1] = '\377';
+	message[2] = 'o';
+	message[3] = 'o';
+	message[4] = *byte;
+
+	cc = rcmd_stream_write(fd, message, sizeof(message), 0);
+	while (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+	    /* also shouldn't happen */
+	    sleep(5);
+	    cc = rcmd_stream_write(fd, message, sizeof(message), 0);
+	}
+    } else {
+	send(fd, byte, 1, MSG_OOB);
+    }
+}
+
+/*
+ * Handle a "control" request (signaled by magic being present)
+ * in the data stream.  For now, we are only willing to handle
+ * window size changes.
+ */
+static int control(pty, cp, n)
+     int pty;
+     unsigned char *cp;
+     int n;
+{
+    struct winsize w;
+    int pgrp, got_pgrp;
+    
+    if (n < (int) 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
+      return (0);
+#ifdef TIOCSWINSZ
+    oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
+    memcpy((char *)&w,cp+4, sizeof(w));
+    w.ws_row = ntohs(w.ws_row);
+    w.ws_col = ntohs(w.ws_col);
+    w.ws_xpixel = ntohs(w.ws_xpixel);
+    w.ws_ypixel = ntohs(w.ws_ypixel);
+    (void)ioctl(pty, TIOCSWINSZ, &w);
+#ifdef HAVE_TCGETPGRP
+    pgrp = tcgetpgrp (pty);
+    got_pgrp = pgrp != -1;
+#else
+    got_pgrp = ioctl(pty, TIOCGPGRP, &pgrp) >= 0;
+#endif
+    if (got_pgrp)
+      (void) killpg(pgrp, SIGWINCH);
+#endif
+    return (4+sizeof (w));
+}
+
+
+
+/*
+ * rlogin "protocol" machine.
+ */
+void protocol(f, p)
+     int f, p;
+{
+    unsigned char pibuf[BUFSIZ], qpibuf[BUFSIZ*2], fibuf[BUFSIZ], *pbp=0, *fbp=0;
+    register int pcc = 0, fcc = 0;
+    int cc;
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+#ifdef TIOCPKT
+    register int tiocpkt_on = 0;
+    int on = 1;
+#endif
+    
+#if defined(TIOCPKT) && !(defined(__svr4__) || defined(HAVE_STREAMS)) \
+	|| defined(solaris20)
+    /* if system has TIOCPKT, try to turn it on. Some drivers
+     * may not support it. Save flag for later. 
+     */
+   if ( ioctl(p, TIOCPKT, &on) < 0)
+	tiocpkt_on = 0;
+   else tiocpkt_on = 1;
+#endif
+
+    /*
+     * Must ignore SIGTTOU, otherwise we'll stop
+     * when we try and set slave pty's window shape
+     * (our controlling tty is the master pty).
+     */
+#ifdef POSIX_SIGNALS
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);
+#else
+    signal(SIGTTOU, SIG_IGN);
+#endif
+#ifdef TIOCSWINSZ
+    sendoob(f, oobdata);
+#endif
+    for (;;) {
+	fd_set ibits, obits, ebits;
+
+	FD_ZERO(&ibits);
+	FD_ZERO(&obits);
+	FD_ZERO(&ebits);
+
+	if (fcc)
+	    FD_SET(p, &obits);
+	else
+	    FD_SET(f, &ibits);
+	if (pcc >= 0) {
+	    if (pcc) {
+		FD_SET(f, &obits);
+	    } else {
+		FD_SET(p, &ibits);
+	    }
+	}
+
+	if (select(8*sizeof(ibits), &ibits, &obits, &ebits, 0) < 0) {
+	    if (errno == EINTR)
+	      continue;
+	    fatalperror(f, "select");
+	}
+#define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
+	if (FD_ISSET(f, &ibits)) {
+	    fcc = rcmd_stream_read(f, fibuf, sizeof (fibuf), 0);
+	    if (fcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+		fcc = 0;
+	    } else {
+		register unsigned char *cp;
+		int n;
+		size_t left;
+		
+		if (fcc <= 0)
+		    break;
+		fbp = fibuf;
+		
+		for (cp = fibuf; cp < fibuf+fcc-1; cp++) {
+		    if (cp[0] == magic[0] &&
+			cp[1] == magic[1]) {
+			left = (fibuf+fcc) - cp;
+			n = control(p, cp, left);
+			if (n) {
+			    left -= n;
+			    fcc -= n;
+			    if (left > 0)
+				memmove(cp, cp+n, left);
+			    cp--;
+			}
+		    }
+		}
+	    }
+	}
+	
+	if (FD_ISSET(p, &obits) && fcc > 0) {
+	    cc = write(p, fbp, fcc);
+	    if (cc > 0) {
+		fcc -= cc;
+		fbp += cc;
+	    }
+	}
+	
+	if (FD_ISSET(p, &ibits)) {
+	    pcc = read(p, pibuf, sizeof (pibuf));
+	    pbp = pibuf;
+	    if (pcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+		pcc = 0;
+	    } else if (pcc <= 0) {
+		break;
+	    }
+#ifdef TIOCPKT
+	    else if (tiocpkt_on) {
+		if (pibuf[0] == 0) {
+		    pbp++, pcc--;
+		} else {
+		    if (pkcontrol(pibuf[0])) {
+			pibuf[0] |= oobdata[0];
+			sendoob(f, pibuf);
+		    }
+		    pcc = 0;
+		}
+	    }
+#endif
+
+	    /* quote any double-\377's if necessary */
+
+	    if (do_inband) {
+		unsigned char *qpbp;
+		int qpcc, i;
+
+		qpbp = qpibuf;
+		qpcc = 0;
+
+		for (i=0; i<pcc;) {
+		    if (pbp[i] == 0377u && (i+1)<pcc && pbp[i+1] == 0377u) {
+			qpbp[qpcc] = '\377';
+			qpbp[qpcc+1] = '\377';
+			qpbp[qpcc+2] = 'q';
+			qpbp[qpcc+3] = 'q';
+			i += 2;
+			qpcc += 4;
+		    } else {
+			qpbp[qpcc] = pbp[i];
+			i++;
+			qpcc++;
+		    }
+		}
+
+		pbp = qpbp;
+		pcc = qpcc;
+	    }
+	}
+
+	if (FD_ISSET(f, &obits) && pcc > 0) {
+	    cc = rcmd_stream_write(f, pbp, pcc, 0);
+	    if (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+		/* also shouldn't happen */
+		sleep(5);
+		continue;
+	    }
+	    if (cc > 0) {
+		pcc -= cc;
+		pbp += cc;
+	    }
+	}
+    }
+}
+
+
+
+krb5_sigtype cleanup(signumber)
+    int signumber;
+{
+    pty_cleanup (line, pid, 1);
+    shutdown(netf, 2);
+    if (ccache)
+	krb5_cc_destroy(bsd_context, ccache);
+    exit(1);
+}
+
+
+void fatal(f, msg)
+     int f;
+     const char *msg;
+{
+    char buf[512];
+    int out = 1 ;          /* Output queue of f */
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+    
+    buf[0] = '\01';		/* error indicator */
+    (void) sprintf(buf + 1, "%s: %s.\r\n",progname, msg);
+    if ((f == netf) && (pid > 0))
+      (void) rcmd_stream_write(f, buf, strlen(buf), 0);
+    else
+      (void) write(f, buf, strlen(buf));
+    syslog(LOG_ERR,"%s\n",msg);
+    if (pid > 0) {
+#ifdef POSIX_SIGNALS
+	(void) sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	sa.sa_handler = SIG_IGN;
+	(void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
+#else
+	signal(SIGCHLD,SIG_IGN);
+#endif
+	kill(pid,SIGKILL);
+#ifdef  TIOCFLUSH
+	(void) ioctl(f, TIOCFLUSH, (char *)&out);
+#else
+	(void) ioctl(f, TCFLSH, out);
+#endif
+	cleanup(0);
+    }
+    exit(1);
+}
+
+
+
+void fatalperror(f, msg)
+     int f;
+     const char *msg;
+{
+    char buf[512];
+    
+    (void) sprintf(buf, "%s: %s", msg, error_message(errno));
+    fatal(f, buf);
+}
+
+#ifdef KERBEROS
+
+void
+do_krb_login(host_addr, hostname)
+     char *host_addr, *hostname;
+{
+    krb5_error_code status;
+    char *msg_fail = NULL;
+    int valid_checksum;
+
+    if (getuid()) {
+	exit(1);
+    }
+
+    /* Check authentication. This can be either Kerberos V5, */
+    /* Kerberos V4, or host-based. */
+    if ((status = recvauth(&valid_checksum))) {
+	if (ticket)
+	  krb5_free_ticket(bsd_context, ticket);
+	if (status != 255)
+	  syslog(LOG_ERR,
+		 "Authentication failed from %s (%s): %s\n",host_addr,
+		 hostname,error_message(status));
+	fatal(netf, "Kerberos authentication failed");
+	return;
+    }
+    
+    /* OK we have authenticated this user - now check authorization. */
+    /* The Kerberos authenticated programs must use krb5_kuserok or kuserok*/
+    
+#ifndef KRB5_KRB4_COMPAT
+    if (auth_sys == KRB5_RECVAUTH_V4) {
+	  fatal(netf, "This server does not support Kerberos V4");
+  }
+#endif
+    
+
+#if (defined(ALWAYS_V5_KUSEROK) || !defined(KRB5_KRB4_COMPAT))
+	/* krb5_kuserok returns 1 if OK */
+	if (client && krb5_kuserok(bsd_context, client, lusername))
+	  auth_sent |= ((auth_sys == KRB5_RECVAUTH_V4)?AUTH_KRB4:AUTH_KRB5);
+#else
+	if (auth_sys == KRB5_RECVAUTH_V4) {
+	    /* kuserok returns 0 if OK */
+	    if (!kuserok(v4_kdata, lusername))
+	      auth_sent |= AUTH_KRB4;
+	} else {
+	    /* krb5_kuserok returns 1 if OK */
+	    if (client && krb5_kuserok(bsd_context, client, lusername))
+	      auth_sent |= AUTH_KRB5;
+	}
+#endif
+
+    
+
+    if (checksum_required && !valid_checksum) {
+	if (auth_sent & AUTH_KRB5) {
+	    syslog(LOG_WARNING, "Client did not supply required checksum--connection rejected.");
+	
+	    fatal(netf, "You are using an old Kerberos5 without initial connection support; only newer clients are authorized.");
+	} else {
+	  syslog(LOG_WARNING,
+		 "Configuration error: Requiring checksums with -c is inconsistent with allowing Kerberos V4 connections.");
+	}
+    }
+    if (auth_ok&auth_sent) /* This should be bitwise.*/
+	return;
+    
+    if (ticket)
+	krb5_free_ticket(bsd_context, ticket);
+
+    if (krusername)
+	msg_fail = (char *)malloc(strlen(krusername) + strlen(lusername) + 80);
+    if (!msg_fail)
+	fatal(netf, "User is not authorized to login to specified account");
+
+    if (auth_sent)
+	sprintf(msg_fail, "Access denied because of improper credentials");
+    else
+	sprintf(msg_fail, "User %s is not authorized to login to account %s",
+		krusername, lusername);
+    
+    fatal(netf, msg_fail);
+    /* NOTREACHED */
+}
+
+#endif /* KERBEROS */
+
+
+
+void getstr(fd, buf, cnt, err)
+     int fd;
+     char *buf;
+     int cnt;
+     char *err;
+{
+    
+    char c;
+    
+    do {
+	if (read(fd, &c, 1) != 1) {
+	    exit(1);
+	}
+	if (--cnt < 0) {
+	    printf("%s too long\r\n", err);
+	    exit(1);
+	}
+	*buf++ = c;
+    } while (c != 0);
+}
+
+
+
+void usage()
+{
+#ifdef KERBEROS
+    syslog(LOG_ERR, 
+	   "usage: klogind [-ke45pPf] [-D port] [-w[ip|maxhostlen[,[no]striplocal]]] or [r/R][k/K][x/e][p/P]logind");
+#else
+    syslog(LOG_ERR, 
+	   "usage: rlogind [-rpPf] [-D port] or [r/R][p/P]logind");
+#endif
+}
+
+
+
+#ifdef KERBEROS
+
+#ifndef KRB_SENDAUTH_VLEN
+#define	KRB_SENDAUTH_VLEN 8	    /* length for version strings */
+#endif
+
+#define	KRB_SENDAUTH_VERS	"AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN
+					      chars */
+
+krb5_error_code
+recvauth(valid_checksum)
+    int *valid_checksum;
+{
+    krb5_auth_context auth_context = NULL;
+    krb5_error_code status;
+    struct sockaddr_storage peersin, laddr;
+    socklen_t len;
+    krb5_data inbuf;
+#ifdef KRB5_KRB4_COMPAT
+    char v4_instance[INST_SZ];	/* V4 Instance */
+#endif
+    krb5_data version;
+    krb5_authenticator *authenticator;
+    krb5_rcache rcache;
+    enum kcmd_proto kcmd_proto;
+    krb5_keyblock *key;
+
+    *valid_checksum = 0;
+    len = sizeof(laddr);
+    if (getsockname(netf, (struct sockaddr *)&laddr, &len)) {
+	    exit(1);
+    }
+	
+    len = sizeof(peersin);
+    if (getpeername(netf, (struct sockaddr *)&peersin, &len)) {
+	syslog(LOG_ERR, "get peer name failed %d", netf);
+	exit(1);
+    }
+
+#ifdef KRB5_KRB4_COMPAT
+    strcpy(v4_instance, "*");
+#endif
+
+    if ((status = krb5_auth_con_init(bsd_context, &auth_context)))
+        return status;
+ 
+    /* Only need remote address for rd_cred() to verify client */
+    if ((status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
+		 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
+	return status;
+
+    status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache);
+    if (status) return status;
+
+    if (! rcache) {
+	krb5_principal server;
+
+	status = krb5_sname_to_principal(bsd_context, 0, 0,
+					 KRB5_NT_SRV_HST, &server);
+	if (status) return status;
+
+	status = krb5_get_server_rcache(bsd_context,
+				krb5_princ_component(bsd_context, server, 0),
+				&rcache);
+	krb5_free_principal(bsd_context, server);
+	if (status) return status;
+
+	status = krb5_auth_con_setrcache(bsd_context, auth_context, rcache);
+	if (status) return status;
+    }
+
+#ifdef KRB5_KRB4_COMPAT
+    status = krb5_compat_recvauth_version(bsd_context, &auth_context,
+					       &netf,
+				  NULL, 	/* Specify daemon principal */
+				  0, 		/* no flags */
+				  keytab, /* normally NULL to use v5srvtab */
+
+				  do_encrypt ? KOPT_DO_MUTUAL : 0, /*v4_opts*/
+				  "rcmd", 	/* v4_service */
+				  v4_instance, 	/* v4_instance */
+				  ss2sin(&peersin), /* foriegn address */
+				  ss2sin(&laddr), /* our local address */
+				  "", 		/* use default srvtab */
+
+				  &ticket, 	/* return ticket */
+				  &auth_sys, 	/* which authentication system*/
+				  &v4_kdata, v4_schedule,
+					       &version);
+#else
+    auth_sys = KRB5_RECVAUTH_V5;
+    status = krb5_recvauth_version(bsd_context, &auth_context, &netf,
+				   NULL, 0, keytab, &ticket, &version);
+#endif
+    if (status) {
+	if (auth_sys == KRB5_RECVAUTH_V5) {
+	    /*
+	     * clean up before exiting
+	     */
+	    getstr(netf, lusername, sizeof (lusername), "locuser");
+	    getstr(netf, term, sizeof(term), "Terminal type");
+	    getstr(netf, rusername, sizeof(rusername), "remuser");
+	}
+	return status;
+    }
+
+    getstr(netf, lusername, sizeof (lusername), "locuser");
+    getstr(netf, term, sizeof(term), "Terminal type");
+
+    kcmd_proto = KCMD_UNKNOWN_PROTOCOL;
+    if (auth_sys == KRB5_RECVAUTH_V5) {
+	if (version.length != 9) {
+	    fatal (netf, "bad application version length");
+	}
+	if (!memcmp (version.data, "KCMDV0.1", 9))
+	    kcmd_proto = KCMD_OLD_PROTOCOL;
+	else if (!memcmp (version.data, "KCMDV0.2", 9))
+	    kcmd_proto = KCMD_NEW_PROTOCOL;
+    }
+#ifdef KRB5_KRB4_COMPAT
+    if (auth_sys == KRB5_RECVAUTH_V4)
+	kcmd_proto = KCMD_V4_PROTOCOL;
+#endif
+
+    if ((auth_sys == KRB5_RECVAUTH_V5)
+	&& !(checksum_ignored
+	     && kcmd_proto == KCMD_OLD_PROTOCOL)) {
+      
+      if ((status = krb5_auth_con_getauthenticator(bsd_context, auth_context,
+						   &authenticator)))
+	return status;
+    
+      if (authenticator->checksum) {
+	struct sockaddr_in adr;
+	socklen_t adr_length = sizeof(adr);
+	char * chksumbuf = (char *) malloc(strlen(term)+strlen(lusername)+32);
+	if (getsockname(netf, (struct sockaddr *) &adr, &adr_length) != 0)
+	    goto error_cleanup;
+	if (chksumbuf == 0)
+	    goto error_cleanup;
+
+	sprintf(chksumbuf,"%u:", ntohs(adr.sin_port));
+	strcat(chksumbuf,term);
+	strcat(chksumbuf,lusername);
+
+	status = krb5_verify_checksum(bsd_context,
+				      authenticator->checksum->checksum_type,
+				      authenticator->checksum,
+				      chksumbuf, strlen(chksumbuf),
+				      ticket->enc_part2->session->contents, 
+				      ticket->enc_part2->session->length);
+    error_cleanup:
+	if (chksumbuf)
+	    free(chksumbuf);
+	if (status) {
+	  krb5_free_authenticator(bsd_context, authenticator);
+	  return status;
+	}
+	*valid_checksum = 1;
+      }
+      krb5_free_authenticator(bsd_context, authenticator);
+    }
+
+
+#ifdef KRB5_KRB4_COMPAT
+    if (auth_sys == KRB5_RECVAUTH_V4) {
+
+	rcmd_stream_init_krb4(v4_kdata->session, do_encrypt, 1, 1);
+
+	/* We do not really know the remote user's login name.
+         * Assume it to be the same as the first component of the
+	 * principal's name. 
+         */
+	strncpy(rusername, v4_kdata->pname, sizeof(rusername) - 1);
+	rusername[sizeof(rusername) - 1] = '\0';
+
+	status = krb5_425_conv_principal(bsd_context, v4_kdata->pname,
+					 v4_kdata->pinst, v4_kdata->prealm,
+					 &client);
+	if (status) return status;
+
+	status = krb5_unparse_name(bsd_context, client, &krusername);
+	
+	return status;
+    }
+#endif
+
+    /* Must be V5  */
+	
+    if ((status = krb5_copy_principal(bsd_context, ticket->enc_part2->client, 
+				      &client)))
+	return status;
+
+    key = 0;
+    status = krb5_auth_con_getrecvsubkey (bsd_context, auth_context, &key);
+    if (status)
+	fatal (netf, "Server can't get session subkey");
+    if (!key && do_encrypt && kcmd_proto == KCMD_NEW_PROTOCOL)
+	fatal (netf, "No session subkey sent");
+    if (key && kcmd_proto == KCMD_OLD_PROTOCOL) {
+#ifdef HEIMDAL_FRIENDLY
+	key = 0;
+#else
+	fatal (netf, "Session subkey not permitted under old kcmd protocol");
+#endif
+    }
+    if (key == 0)
+	key = ticket->enc_part2->session;
+
+    rcmd_stream_init_krb5 (key, do_encrypt, 1, 0, kcmd_proto);
+
+    do_inband = (kcmd_proto == KCMD_NEW_PROTOCOL);
+
+    getstr(netf, rusername, sizeof(rusername), "remuser");
+
+    if ((status = krb5_unparse_name(bsd_context, client, &krusername)))
+	return status;
+    
+    if ((status = krb5_read_message(bsd_context, (krb5_pointer)&netf, &inbuf)))
+	fatal(netf, "Error reading message");
+
+    if ((inbuf.length) && /* Forwarding being done, read creds */
+	(status = rd_and_store_for_creds(bsd_context, auth_context, &inbuf, 
+					  ticket, &ccache))) {
+         fatal(netf, "Can't get forwarded credentials");
+    }
+    return 0;
+}
+
+#endif /* KERBEROS */
diff --git a/mechglue/src/appl/bsd/krsh.c b/mechglue/src/appl/bsd/krsh.c
new file mode 100644
index 000000000..08b68fef1
--- /dev/null
+++ b/mechglue/src/appl/bsd/krsh.c
@@ -0,0 +1,635 @@
+/*
+ *	appl/bsd/krsh.c
+ */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)rsh.c	5.7 (Berkeley) 9/20/88 */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+#include <netdb.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+/* get FIONBIO from sys/filio.h, so what if it is a compatibility feature */
+#include <sys/filio.h>
+#endif
+
+#ifdef KERBEROS
+#include <krb5.h>
+#include <com_err.h>
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+#include "defines.h"
+#endif /* KERBEROS */
+
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+Key_schedule v4_schedule;
+#endif
+
+/*
+ * rsh - remote shell
+ */
+#define SECURE_MESSAGE "This rsh session is encrypting input/output data transmissions.\r\n"
+
+int	error();
+     
+int	options;
+int	rfd2;
+int	nflag;
+krb5_sigtype  sendsig(int);
+
+#ifdef KERBEROS
+
+#ifndef UCB_RSH
+#define UCB_RSH "/usr/ucb/rsh"
+#endif
+
+krb5_context bsd_context;
+krb5_creds *cred;
+
+#ifdef KRB5_KRB4_COMPAT
+Key_schedule v4_schedule;
+CREDENTIALS v4_cred;
+#endif
+
+int	encrypt_flag = 0;
+char	*krb_realm = (char *)0;
+void	try_normal(char **);
+
+#endif /* KERBEROS */
+
+#ifndef RLOGIN_PROGRAM
+#ifdef KERBEROS
+#define RLOGIN_PROGRAM KRB5_PATH_RLOGIN
+#else /* KERBEROS */
+#ifndef UCB_RLOGIN
+#define UCB_RLOGIN "/usr/ucb/rlogin"
+#endif
+#define RLOGIN_PROGRAM UCB_RLOGIN
+#endif  /* KERBEROS */
+#endif /* !RLOGIN_PROGRAM */
+     
+#ifndef POSIX_SIGNALS
+#define	mask(s)	(1 << ((s) - 1))
+#endif /* POSIX_SIGNALS */
+     
+int
+main(argc, argv0)
+     int argc;
+     char **argv0;
+{
+    int rem, pid = 0;
+    char *host=0, *cp, **ap, buf[RCMD_BUFSIZ], *args, **argv = argv0, *user = 0;
+    register int cc;
+    struct passwd *pwd;
+    fd_set readfrom, ready;
+    int one = 1;
+    struct servent *sp;
+    struct servent defaultservent;
+    struct sockaddr_in local, foreign;
+    int suppress = 0;
+
+#ifdef POSIX_SIGNALS
+    sigset_t omask, igmask;
+    struct sigaction sa, osa;
+#else
+    int omask;
+#endif
+#ifdef KERBEROS
+    krb5_flags authopts;
+    krb5_error_code status;
+    krb5_auth_context auth_context;
+    int fflag = 0, Fflag = 0;
+#ifdef KRB5_KRB4_COMPAT
+    KTEXT_ST v4_ticket;
+    MSG_DAT v4_msg_data;
+#endif
+#endif  /* KERBEROS */
+    int debug_port = 0;
+    enum kcmd_proto kcmd_proto = KCMD_PROTOCOL_COMPAT_HACK;
+
+    memset(&defaultservent, 0, sizeof(struct servent));
+    if (strrchr(argv[0], '/'))
+      argv[0] = strrchr(argv[0], '/')+1; 
+
+    if ( argc < 2 ) goto usage;
+    argc--;
+    argv++;
+    
+  another:
+    if (argc > 0 && host == 0 && strncmp(*argv, "-", 1)) {
+	host = *argv;
+	argv++, argc--;
+	goto another;
+    }
+
+    if (argc > 0 && !strcmp(*argv, "-D")) {
+	argv++; argc--;
+	debug_port = htons(atoi(*argv));
+	argv++; argc--;
+	goto another;
+    }
+
+    if (argc > 0 && !strcmp(*argv, "-l")) {
+	argv++, argc--;
+	if (argc > 0)
+	  user = *argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-n")) {
+	argv++, argc--;
+	nflag++;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-d")) {
+	argv++, argc--;
+	options |= SO_DEBUG;
+	goto another;
+    }
+#ifdef KERBEROS
+    if (argc > 0 && !strcmp(*argv, "-k")) {
+	argv++, argc--;
+	if (argc == 0) {
+	    fprintf(stderr, "rsh(kerberos): -k flag must have a realm after it.\n");
+	    exit (1);
+	}
+	if(!(krb_realm = (char *)malloc(strlen(*argv) + 1))){
+	    fprintf(stderr, "rsh(kerberos): Cannot malloc.\n");
+	    exit(1);
+	}
+	strcpy(krb_realm, *argv);
+	argv++, argc--;
+	goto another;
+    }
+    /*
+     * Ignore -x from kerberos rlogin
+     */
+    if (argc > 0 && !strncmp(*argv, "-x", 2)) {
+	argv++, argc--;
+	encrypt_flag++;
+	goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-f", 2)) {
+	if (Fflag) {
+	    fprintf(stderr, "rsh: Only one of -f and -F allowed\n");
+	    goto usage;
+	}
+	fflag++;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-F", 2)) {
+	if (fflag) {
+	    fprintf(stderr, "rsh: Only one of -f and -F allowed\n");
+	    goto usage;
+	}
+	Fflag++;
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-A", 2)) {
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-PO")) {
+	argv++, argc--;
+	kcmd_proto = KCMD_OLD_PROTOCOL;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-PN")) {
+	argv++, argc--;
+	kcmd_proto = KCMD_NEW_PROTOCOL;
+	goto another;
+    }
+#endif  /* KERBEROS */
+    /*
+     * Ignore the -L, -w, -e and -8 flags to allow aliases with rlogin
+     * to work
+     *
+     * There must be a better way to do this! -jmb
+     */
+    if (argc > 0 && !strncmp(*argv, "-L", 2)) {
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-w", 2)) {
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-e", 2)) {
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-8", 2)) {
+	argv++, argc--;
+	goto another;
+    }
+#ifdef ATHENA
+    /* additional Athena flags to be ignored */
+    if (argc > 0 && !strcmp(*argv, "-noflow")) {	/* No local flow control option for rlogin */
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-7")) {
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-c")) {
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-a")) {
+	argv++, argc--;
+	goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-n")) {
+	argv++, argc--;
+	goto another;
+    }
+    /*
+     ** Also ignore -t ttytype
+     */
+    if (argc > 0 && !strcmp(*argv, "-t")) {
+	argv++; argv++; argc--; argc--;
+	goto another;
+    }
+#endif /* ATHENA */
+    if (host == 0)
+      goto usage;
+    if (argv[0] == 0) {
+	execv(RLOGIN_PROGRAM, argv0);
+	perror(RLOGIN_PROGRAM);
+	exit(1);
+    }
+
+    pwd = getpwuid(getuid());
+    if (pwd == 0) {
+	fprintf(stderr, "who are you?\n");
+	exit(1);
+    }
+    cc = 0;
+    for (ap = argv; *ap; ap++)
+      cc += strlen(*ap) + 1;
+    if (encrypt_flag)
+      cc += 3;
+    cp = args = (char *) malloc((unsigned) cc);
+    if (encrypt_flag) {
+      strcpy(args, "-x ");
+      cp += 3;
+    }
+    for (ap = argv; *ap; ap++) {
+	(void) strcpy(cp, *ap);
+	while (*cp)
+	  cp++;
+	if (ap[1])
+	  *cp++ = ' ';
+    }
+
+    if(debug_port == 0) {
+#ifdef KERBEROS
+      sp = getservbyname("kshell", "tcp");
+#else 
+      sp = getservbyname("shell", "tcp");
+#endif  /* KERBEROS */
+      if (sp == 0) {
+#ifdef KERBEROS
+	sp = &defaultservent;
+	sp->s_port = htons(544);
+#else 
+	fprintf(stderr, "rsh: shell/tcp: unknown service\n");
+	exit(1);
+#endif /* KERBEROS */
+      }
+
+      debug_port = sp->s_port;
+    }
+
+#ifdef KERBEROS
+    status = krb5_init_context(&bsd_context);
+    if (status) {
+	    com_err(argv[0], status, "while initializing krb5");
+	    exit(1);
+    }
+    authopts = AP_OPTS_MUTUAL_REQUIRED;
+
+    /* Piggy-back forwarding flags on top of authopts; */
+    /* they will be reset in kcmd */
+    if (fflag || Fflag)
+      authopts |= OPTS_FORWARD_CREDS;
+    if (Fflag)
+      authopts |= OPTS_FORWARDABLE_CREDS;    
+#ifdef HAVE_ISATTY
+    suppress = !isatty(fileno(stderr));
+#endif
+    status = kcmd(&rem, &host, debug_port,
+		  pwd->pw_name,
+		  user ? user : pwd->pw_name,
+		  args, &rfd2, "host", krb_realm,
+		  &cred,
+		  0,           /* No need for sequence number */
+		  0,           /* No need for server seq # */
+		  &local, &foreign,
+		  &auth_context, authopts,
+		  1,	/* Always set anyport, there is no need not to. --proven */
+		  suppress,
+		  &kcmd_proto);
+    if (status) {
+	/* If new protocol requested, don't fall back to less secure
+	   ones.  */
+	if (kcmd_proto == KCMD_NEW_PROTOCOL)
+	    exit (1);
+#ifdef KRB5_KRB4_COMPAT
+	/* No encrypted Kerberos 4 rsh. */
+	if (encrypt_flag)
+	    exit(1);
+#ifdef HAVE_ISATTY
+	if (isatty(fileno(stderr)))
+	    fprintf(stderr, "Trying krb4 rsh...\n");
+#endif
+	status = k4cmd(&rem, &host, debug_port,
+		       pwd->pw_name,
+		       user ? user : pwd->pw_name, args,
+		       &rfd2, &v4_ticket, "rcmd", krb_realm,
+		       &v4_cred, v4_schedule, &v4_msg_data,
+		       &local, &foreign, 0L, 0);
+	if (status)
+	    try_normal(argv0);
+	rcmd_stream_init_krb4(v4_cred.session, encrypt_flag, 0, 1);
+#else
+	try_normal(argv0);
+#endif
+    } else {
+	krb5_keyblock *key = &cred->keyblock;
+
+	if (kcmd_proto == KCMD_NEW_PROTOCOL) {
+	    status = krb5_auth_con_getsendsubkey (bsd_context, auth_context,
+						  &key);
+	    if (status) {
+		com_err (argv[0], status, "determining subkey for session");
+		exit (1);
+	    }
+	    if (!key) {
+		com_err (argv[0], 0, "no subkey negotiated for connection");
+		exit (1);
+	    }
+	}
+
+	rcmd_stream_init_krb5(key, encrypt_flag, 0, 1, kcmd_proto);
+    }
+
+#ifdef HAVE_ISATTY
+    if(encrypt_flag&&isatty(2)) {
+	write(2,SECURE_MESSAGE, strlen(SECURE_MESSAGE));
+    }
+#endif
+    
+#else /* !KERBEROS */
+    rem = rcmd(&host, debug_port, pwd->pw_name,
+	       user ? user : pwd->pw_name, args, &rfd2);
+    if (rem < 0)
+      exit(1);
+#endif /* KERBEROS */
+    if (rfd2 < 0) {
+	fprintf(stderr, "rsh: can't establish stderr\n");
+	exit(2);
+    }
+    if (options & SO_DEBUG) {
+	if (setsockopt(rem, SOL_SOCKET, SO_DEBUG,
+		       (const char *) &one, sizeof (one)) < 0)
+	  perror("setsockopt (stdin)");
+	if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG,
+		       (const char *) &one, sizeof (one)) < 0)
+	  perror("setsockopt (stderr)");
+    }
+    (void) setuid(getuid());
+#ifdef POSIX_SIGNALS
+    sigemptyset(&igmask);
+    sigaddset(&igmask, SIGINT);
+    sigaddset(&igmask, SIGQUIT);
+    sigaddset(&igmask, SIGTERM);
+    sigprocmask(SIG_BLOCK, &igmask, &omask);
+
+    (void)sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = sendsig;
+
+    (void)sigaction(SIGINT, (struct sigaction *)0, &osa);
+    if (osa.sa_handler != SIG_IGN)
+	(void)sigaction(SIGINT, &sa, (struct sigaction *)0);
+
+    (void)sigaction(SIGQUIT, (struct sigaction *)0, &osa);
+    if (osa.sa_handler != SIG_IGN)
+	(void)sigaction(SIGQUIT, &sa, (struct sigaction *)0);
+
+    (void)sigaction(SIGTERM, (struct sigaction *)0, &osa);
+    if (osa.sa_handler != SIG_IGN)
+	(void)sigaction(SIGTERM, &sa, (struct sigaction *)0);
+#else
+#ifdef sgi
+    omask = sigignore(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
+#else
+    omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
+#endif
+    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+      signal(SIGINT, sendsig);
+    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
+      signal(SIGQUIT, sendsig);
+    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+      signal(SIGTERM, sendsig);
+#endif /* POSIX_SIGNALS */
+    if (nflag == 0) {
+	pid = fork();
+	if (pid < 0) {
+	    perror("fork");
+	    exit(1);
+	}
+    }
+    if (!encrypt_flag) {
+	ioctl(rfd2, FIONBIO, &one);
+	ioctl(rem, FIONBIO, &one);
+    }
+    if (nflag == 0 && pid == 0) {
+	char *bp;
+	int wc;
+	fd_set rembits;
+	
+	(void) close(rfd2);
+      reread:
+	errno = 0;
+	cc = read(0, buf, sizeof buf);
+	if (cc <= 0)
+	  goto done;
+	bp = buf;
+      rewrite:
+	FD_ZERO(&rembits);
+	FD_SET(rem, &rembits);
+	if (select(8*sizeof(rembits), 0, &rembits, 0, 0) < 0) {
+	    if (errno != EINTR) {
+		perror("select");
+		exit(1);
+	    }
+	    goto rewrite;
+	}
+	if (FD_ISSET(rem, &rembits) == 0)
+	  goto rewrite;
+	wc = rcmd_stream_write(rem, bp, cc, 0);
+	if (wc < 0) {
+	    if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
+	      goto rewrite;
+	    goto done;
+	}
+	cc -= wc; bp += wc;
+	if (cc == 0)
+	  goto reread;
+	goto rewrite;
+      done:
+	(void) shutdown(rem, 1);
+#ifdef KERBEROS 
+	krb5_free_context(bsd_context);
+#endif
+	exit(0);
+    }
+#ifdef POSIX_SIGNALS
+    sigprocmask(SIG_SETMASK, &omask, (sigset_t*)0);
+#else
+#ifndef sgi
+    sigsetmask(omask);
+#endif
+#endif /* POSIX_SIGNALS */
+    FD_ZERO(&readfrom);
+    FD_SET(rfd2, &readfrom);
+    FD_SET(rem, &readfrom);
+    do {
+	ready = readfrom;
+	if (select(8*sizeof(ready), &ready, 0, 0, 0) < 0) {
+	    if (errno != EINTR) {
+		perror("select");
+		exit(1);
+	    }
+	    continue;
+	}
+	if (FD_ISSET(rfd2, &ready)) {
+	    errno = 0;
+	    cc = rcmd_stream_read(rfd2, buf, sizeof buf, 1);
+	    if (cc <= 0) {
+		if ((errno != EWOULDBLOCK) && (errno != EAGAIN))
+		    FD_CLR(rfd2, &readfrom);
+	    } else
+	      (void) write(2, buf, (unsigned) cc);
+	}
+	if (FD_ISSET(rem, &ready)) {
+	    errno = 0;
+	    cc = rcmd_stream_read(rem, buf, sizeof buf, 0);
+	    if (cc <= 0) {
+		if ((errno != EWOULDBLOCK) && (errno != EAGAIN))
+		    FD_CLR(rem, &readfrom);
+	    } else
+	      (void) write(1, buf, (unsigned) cc);
+	}
+    } while (FD_ISSET(rem, &readfrom) || FD_ISSET(rfd2, &readfrom));
+    if (nflag == 0)
+      (void) kill(pid, SIGKILL);
+#ifdef KERBEROS 
+    krb5_free_context(bsd_context);
+#endif
+    exit(0);
+  usage:
+    fprintf(stderr,
+	    "usage: \trsh host [ -PN / -PO ] [ -l login ] [ -n ] [ -x ] [ -f / -F] command\n");
+    fprintf(stderr,
+	    "OR \trsh [ -PN / -PO ] [ -l login ] [-n ] [ -x ] [ -f / -F ] host command\n");
+    exit(1);
+}
+
+
+
+krb5_sigtype sendsig(signo)
+     char signo;
+{
+    (void) rcmd_stream_write(rfd2, &signo, 1, 1);
+}
+
+
+
+#ifdef KERBEROS
+void try_normal(argv)
+     char **argv;
+{
+    char *host;
+    
+#ifndef KRB5_ATHENA_COMPAT
+    if (encrypt_flag)
+	exit(1);
+#endif
+    /*
+     * if we were invoked as 'rsh host mumble', strip off the rsh
+     * from arglist.
+     *
+     * We always want to call the Berkeley rsh as 'host mumble'
+     */
+    host = strrchr(argv[0], '/');
+    if (host)
+      host++;
+    else
+      host = argv[0];
+    
+    if (!strcmp(host, "rsh"))
+      argv++;
+    
+    fprintf(stderr,"trying normal rsh (%s)\n",
+	    UCB_RSH);
+    fflush(stderr);
+    execv(UCB_RSH, argv);
+    perror("exec");
+    exit(1);
+}
+#endif /* KERBEROS */
diff --git a/mechglue/src/appl/bsd/krshd.c b/mechglue/src/appl/bsd/krshd.c
new file mode 100644
index 000000000..808adf5d5
--- /dev/null
+++ b/mechglue/src/appl/bsd/krshd.c
@@ -0,0 +1,2054 @@
+/*
+ *	appl/bsd/krshd.c
+ */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)rshd.c	5.12 (Berkeley) 9/12/88 */
+
+     /*
+      * remote shell server:
+      *	remuser\0
+      *	locuser\0
+      *	command\0
+      *	data
+      */
+     
+/*
+ * This is the rshell daemon. The very basic protocol for checking 
+ * authentication and authorization is:
+ * 1) Check authentication.
+ * 2) Check authorization via the access-control files: 
+ *    ~/.k5login (using krb5_kuserok) and/or
+ * Execute command if configured authoriztion checks pass, else deny 
+ * permission.
+ *
+ * The configuration is done either by command-line arguments passed by inetd, 
+ * or by the name of the daemon. If command-line arguments are present, they 
+ * take priority. The options are:
+ * -k means trust krb4 or krb5
+ * -5 means trust krb5
+ * -4 means trust krb4 (using .klogin)
+ * 
+ */
+     
+/* DEFINES:
+ *   KERBEROS - Define this if application is to be kerberised.
+ *   KRB5_KRB4_COMPAT - Define this if v4 rlogin clients are also to be served.
+ *   ALWAYS_V5_KUSEROK - Define this if you want .k5login to be
+ *              checked even for v4 clients (instead of .klogin).
+ *   LOG_ALL_LOGINS - Define this if you want to log all logins.
+ *   LOG_OTHER_USERS - Define this if you want to log all principals that do
+ *              not map onto the local user.
+ *   LOG_REMOTE_REALM - Define this if you want to log all principals from 
+ *              remote realms.
+ *   LOG_CMD - Define this if you want to log not only the user but also the
+ *             command executed. This only decides the type of information
+ *             logged. Whether or not to log is still decided by the above 
+ *             three DEFINES.
+ *       Note:  Root account access is always logged.
+ */
+     
+#define SERVE_NON_KRB     
+#define LOG_REMOTE_REALM
+#define LOG_CMD
+   
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef __SCO__
+#include <sys/unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#if !defined(KERBEROS) || !defined(KRB5_KRB4_COMPAT)
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
+#include <sys/socket.h>
+#endif
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+     
+#include <netinet/in.h>
+#include <arpa/inet.h>
+     
+#include <stdio.h>
+#include <grp.h>
+#include <errno.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <string.h>
+#include <libpty.h>
+#include <sys/wait.h>
+     
+#ifdef HAVE_SYS_LABEL_H
+/* only SunOS 4? */
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+     
+#include <signal.h>
+#if !defined(KERBEROS) || !defined(KRB5_KRB4_COMPAT)
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
+#include <netdb.h>
+#endif
+
+#ifdef CRAY
+#ifndef NO_UDB
+#include <udb.h>
+#endif  /* !NO_UDB */
+#include <sys/category.h>
+#include <netinet/ip.h>
+#include <sys/tfm.h>
+#include <sys/nal.h>
+#include <sys/secparm.h>
+#include <sys/usrv.h>
+#include <sys/utsname.h>
+#include <sys/sysv.h>
+#include <sys/slrec.h>
+#include <sys/unistd.h>
+#include <path.h>
+#endif /* CRAY */
+     
+#include <syslog.h>
+
+#ifdef POSIX_TERMIOS
+#include <termios.h>
+#endif
+     
+#ifdef HAVE_SYS_FILIO_H
+/* get FIONBIO from sys/filio.h, so what if it is a compatibility feature */
+#include <sys/filio.h>
+#endif
+
+#ifdef KERBEROS
+#include <krb5.h>
+#include <com_err.h>
+#include "loginpaths.h"
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+Key_schedule v4_schedule;
+#endif
+#include <k5-util.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#if defined(_PATH_NOLOGIN)
+#define NOLOGIN		_PATH_NOLOGIN
+#else
+#define NOLOGIN		"/etc/nologin"
+#endif
+
+#include "defines.h"
+
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+
+#ifndef MAXDNAME
+#define MAXDNAME 256 /*per the rfc*/
+#endif
+
+#define ARGSTR	"ek54ciD:S:M:AP:?L:w:"
+
+
+
+
+#define MAXRETRIES 4
+
+krb5_context bsd_context;
+char *srvtab = NULL;
+krb5_keytab keytab = NULL;
+krb5_ccache ccache = NULL;
+
+void fatal(int, const char *);
+
+int require_encrypt = 0;
+int do_encrypt = 0;
+int anyport = 0;
+char *kprogdir = KPROGDIR;
+int netf;
+int maxhostlen = 0;
+int stripdomain = 1;
+int always_ip = 0;
+
+static krb5_error_code recvauth(int netfd, struct sockaddr *peersin,
+				int *valid_checksum);
+
+#else /* !KERBEROS */
+
+#define ARGSTR	"RD:?"
+     
+#endif /* KERBEROS */
+
+     
+#ifndef HAVE_KILLPG
+#define killpg(pid, sig) kill(-(pid), (sig))
+#endif
+
+/* There are two authentication related masks:
+   * auth_ok and auth_sent.
+* The auth_ok mask is the oring of authentication systems any one
+* of which can be used.  
+* The auth_sent mask is the oring of one or more authentication/authorization
+* systems that succeeded.  If the anding
+* of these two masks is true, then authorization is successful.
+*/
+#define AUTH_KRB4 (0x1)
+#define AUTH_KRB5 (0x2)
+int auth_ok = 0, auth_sent = 0;
+int checksum_required = 0, checksum_ignored = 0;
+char *progname;
+
+#define MAX_PROG_NAME 10
+
+/* Leave room for 4 environment variables to be passed */
+#define MAXENV 4
+#define SAVEENVPAD 0,0,0,0 /* padding for envinit slots */
+char *save_env[MAXENV];
+int num_env = 0;
+
+#ifdef CRAY
+int     secflag;
+extern
+#endif /* CRAY */
+
+void 	error (char *fmt, ...)
+#if !defined (__cplusplus) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
+       __attribute__ ((__format__ (__printf__, 1, 2)))
+#endif
+     ;
+
+void usage(void), getstr(int, char *, int, char *), 
+    doit(int, struct sockaddr *);
+
+#ifndef HAVE_INITGROUPS
+int initgroups(char* name, gid_t basegid) {
+  gid_t others[NGROUPS_MAX+1];
+  int ngrps;
+
+  others[0] = basegid;
+  ngrps = getgroups(NGROUPS_MAX, others+1);
+  return setgroups(ngrps+1, others);
+}
+#endif
+
+
+int main(argc, argv)
+     int argc;
+     char **argv;
+{
+#if defined(BSD) && BSD+0 >= 43
+    struct linger linger;
+#endif
+    int on = 1;
+    socklen_t fromlen;
+    struct sockaddr_storage from;
+    extern int opterr, optind;
+    extern char *optarg;
+    int ch;
+    int fd;
+    int debug_port = 0;
+#ifdef KERBEROS
+    krb5_error_code status;
+#endif
+
+#ifdef CRAY
+    secflag = sysconf(_SC_CRAY_SECURE_SYS);
+#endif
+    
+    progname = strrchr (*argv, '/');
+    progname = progname ? progname + 1 : *argv;
+    
+#ifndef LOG_ODELAY /* 4.2 syslog */
+    openlog(progname, LOG_PID);
+#else
+#ifndef LOG_AUTH
+#define LOG_AUTH 0
+#endif
+    openlog(progname, LOG_PID | LOG_ODELAY, LOG_AUTH);
+#endif /* 4.2 syslog */
+    
+#ifdef KERBEROS
+    status = krb5_init_context(&bsd_context);
+    if (status) {
+	    syslog(LOG_ERR, "Error initializing krb5: %s",
+		   error_message(status));
+	    exit(1);
+    }
+#endif
+    
+    /* Analyze parameters. */
+    opterr = 0;
+    while ((ch = getopt(argc, argv, ARGSTR)) != -1)
+      switch (ch) {
+#ifdef KERBEROS
+	case 'k':
+#ifdef KRB5_KRB4_COMPAT
+	auth_ok |= (AUTH_KRB5|AUTH_KRB4);
+#else
+	auth_ok |= AUTH_KRB5;
+#endif /* KRB5_KRB4_COMPAT*/
+	break;
+	
+      case '5':
+	  auth_ok |= AUTH_KRB5;
+	break;
+      case 'c':
+	checksum_required = 1;
+	break;
+      case 'i':
+	checksum_ignored = 1;
+	break;
+	
+#ifdef KRB5_KRB4_COMPAT
+      case '4':
+	auth_ok |= AUTH_KRB4;
+	break;
+#endif
+	  
+        case 'e':
+	require_encrypt = 1;
+	  break;
+
+	case 'S':
+	  if ((status = krb5_kt_resolve(bsd_context, optarg, &keytab))) {
+	      com_err(progname, status, "while resolving srvtab file %s",
+		      optarg);
+	      exit(2);
+	  }
+	  break;
+
+	case 'M':
+	  krb5_set_default_realm(bsd_context, optarg);
+	  break;
+
+	case 'A':
+	  anyport = 1;
+	  break;
+
+	case 'P':
+	  kprogdir = optarg;
+	  break;
+
+        case 'L':
+	  if (num_env < MAXENV) {
+		  save_env[num_env] = strdup(optarg);
+		  if(!save_env[num_env++]) {
+			  com_err(progname, ENOMEM, "in saving environment");
+			  exit(2);
+		  }		  
+	  } else  {
+		  fprintf(stderr, "%s: Only %d -L arguments allowed\n",
+			  progname, MAXENV);
+		  exit(2);
+	  }
+	  break;
+#endif
+	case 'D':
+	  debug_port = atoi(optarg);
+	  break;
+      case 'w':
+	  if (!strcmp(optarg, "ip"))
+	      always_ip = 1;
+	  else {
+	      char *cp;
+	      cp = strchr(optarg, ',');
+	      if (cp == NULL)
+		  maxhostlen = atoi(optarg);
+	      else if (*(++cp)) {
+		  if (!strcmp(cp, "striplocal"))
+		      stripdomain = 1;
+		  else if (!strcmp(cp, "nostriplocal"))
+		      stripdomain = 0;
+		  else {
+		      usage();
+		      exit(1);
+		  }
+		  *(--cp) = '\0';
+		  maxhostlen = atoi(optarg);
+	      }
+	  }
+	  break;
+      case '?':
+      default:
+	  usage();
+	  exit(1);
+	  break;
+      }
+
+    if (optind == 0) {
+	usage();
+	exit(1);
+    }
+    
+    argc -= optind;
+    argv += optind;
+    
+    fromlen = sizeof (from);
+
+    if (debug_port)
+	fd = accept_a_connection(debug_port, (struct sockaddr *)&from,
+				 &fromlen);
+    else {
+	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+	    fprintf(stderr, "%s: ", progname);
+	    perror("getpeername");
+	    _exit(1);
+	}
+
+	fd = 0;
+    }
+
+    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
+		   sizeof (on)) < 0)
+	syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+#if defined(BSD) && BSD+0 >= 43
+    linger.l_onoff = 1;
+    linger.l_linger = 60;			/* XXX */
+    if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&linger,
+		   sizeof (linger)) < 0)
+	syslog(LOG_WARNING , "setsockopt (SO_LINGER): %m");
+#endif
+
+    if (checksum_required&&checksum_ignored) {
+	syslog(LOG_CRIT, "Checksums are required and ignored; these options are mutually exclusive--check the documentation.");
+	fatal(fd, "Configuration error: mutually exclusive options specified");
+    }
+
+    doit(dup(fd), (struct sockaddr *) &from);
+    return 0;
+}
+
+#ifdef CRAY
+char    username[32] = "LOGNAME=";
+#include <tmpdir.h>
+char tmpdir[64] = "TMPDIR=";
+#else
+char	username[20] = "USER=";
+#endif
+
+char	homedir[64] = "HOME=";
+char	shell[64] = "SHELL=";
+char    term[64] = "TERM=network";
+char	path_rest[] = RPATH;
+
+char	remote_addr[64+NI_MAXHOST]; /* = "KRB5REMOTEADDR=" */
+char	remote_port[64+NI_MAXSERV]; /* = "KRB5REMOTEPORT=" */
+char	local_addr[64+NI_MAXHOST]; /* = "KRB5LOCALADDR=" */
+char	local_port[64+NI_MAXSERV]; /* = "KRB5LOCALPORT=" */
+#define ADDRPAD 0,0,0,0
+#define KRBPAD 0		/* KRB5CCNAME, optional */
+
+/* The following include extra space for TZ and MAXENV pointers... */
+#define COMMONVARS homedir, shell, 0/*path*/, username, term
+#ifdef CRAY
+char    *envinit[] = 
+{COMMONVARS, "TZ=GMT0", tmpdir, SAVEENVPAD, KRBPAD, ADDRPAD, 0};
+#define TMPDIRENV 6
+char    *getenv();
+#else /* CRAY */
+#ifdef KERBEROS
+char    *envinit[] = 
+{COMMONVARS, 0/*tz*/, SAVEENVPAD, KRBPAD, ADDRPAD, 0};
+#else /* KERBEROS */
+char	*envinit[] = 
+{COMMONVARS, 0/*tz*/, SAVEENVPAD, ADDRPAD, 0};
+#endif /* KERBEROS */
+#endif /* CRAY */
+
+#define TZENV 5
+#define PATHENV 2
+
+extern char	**environ;
+char ttyn[12];		/* Line string for wtmp entries */
+
+#ifdef CRAY
+#define SIZEOF_INADDR  SIZEOF_in_addr
+int maxlogs;
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+
+#ifndef NCARGS
+/* linux doesn't seem to have it... */
+#define NCARGS 1024
+#endif
+
+#define NMAX   16 
+
+int pid;
+char locuser[NMAX+1];
+char remuser[NMAX +1];
+char cmdbuf[NCARGS+1];
+char *kremuser;
+krb5_principal client;
+krb5_authenticator *kdata;
+
+#ifdef KRB5_KRB4_COMPAT
+AUTH_DAT	*v4_kdata;
+KTEXT		v4_ticket;
+#endif
+
+int auth_sys = 0;	/* Which version of Kerberos used to authenticate */
+
+#define KRB5_RECVAUTH_V4	4
+#define KRB5_RECVAUTH_V5	5
+
+static void
+ignore_signals()
+{
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+
+    (void)sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    (void)sigaction(SIGINT, &sa, (struct sigaction *)0);
+    (void)sigaction(SIGQUIT, &sa, (struct sigaction *)0);
+    (void)sigaction(SIGTERM, &sa, (struct sigaction *)0);
+    (void)sigaction(SIGPIPE, &sa, (struct sigaction *)0);
+    (void)sigaction(SIGHUP, &sa, (struct sigaction *)0);
+
+    (void)kill(-pid, SIGTERM);
+#else
+    signal(SIGINT, SIG_IGN);
+    signal(SIGQUIT, SIG_IGN);
+    signal(SIGTERM, SIG_IGN);
+    signal(SIGPIPE, SIG_IGN);
+    signal(SIGHUP, SIG_IGN);
+    
+    killpg(pid, SIGTERM);
+#endif
+}
+
+static krb5_sigtype
+cleanup(signumber)
+     int signumber;
+{
+    ignore_signals();
+    wait(0);
+    
+    pty_logwtmp(ttyn,"","");
+    syslog(LOG_INFO ,"Daemon terminated via signal %d.", signumber);
+    if (ccache)
+	krb5_cc_destroy(bsd_context, ccache);
+    exit(0);
+}
+
+
+void doit(f, fromp)
+     int f;
+     struct sockaddr *fromp;
+{
+    char *cp;
+#ifdef KERBEROS
+    krb5_error_code status;
+#endif
+    int valid_checksum;
+    int cnt;
+    char *crypt();
+    struct passwd *pwd;
+    char *path;
+#ifdef CRAY
+#ifndef NO_UDB
+    struct udb    *ue;
+    struct udb ue_static;
+    extern struct udb *getudbnam();
+#endif
+    extern struct passwd *getpwnam(), *getpwuid();
+    static int      jid;
+    int error();
+    int paddr;
+    struct  nal nal;
+    int     nal_error;
+    struct usrv usrv;
+    struct  sysv sysv;
+    char    *makejtmp(), *jtmpnam = 0;
+    int packet_level;               /* Packet classification level */
+    long packet_compart;            /* Packet compartments */
+#endif  /* CRAY */
+    
+    int s = -1;
+    char hostname[NI_MAXHOST];
+    char *sane_host;
+    char hostaddra[NI_MAXHOST];
+    int aierr;
+    short port;
+    int pv[2], pw[2], px[2], cc;
+    fd_set ready, readfrom;
+    char buf[RCMD_BUFSIZ], sig;
+    struct sockaddr_storage localaddr;
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+#endif
+
+#ifdef IP_TOS
+/* solaris has IP_TOS, but only IPTOS_* values */
+#ifdef HAVE_GETTOSBYNAME
+    struct tosent *tp;
+
+
+    if ((tp = gettosbyname("interactive", "tcp")) &&
+	(setsockopt(f, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
+#ifdef  TOS_WARN
+      syslog(LOG_NOTICE, "setsockopt (IP_TOS): %m");
+#else
+    ;       /* silently ignore TOS errors in 6E */
+#endif
+#endif
+#endif /* IP_TOS */
+    
+    { 
+	socklen_t sin_len = sizeof (localaddr);
+	if (getsockname(f, (struct sockaddr*)&localaddr, &sin_len) < 0) {
+	    perror("getsockname");
+	    exit(1);
+	}
+    }
+
+#ifdef POSIX_SIGNALS
+    (void)sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_DFL;
+    (void)sigaction(SIGINT, &sa, (struct sigaction *)0);
+    (void)sigaction(SIGQUIT, &sa, (struct sigaction *)0);
+    (void)sigaction(SIGTERM, &sa, (struct sigaction *)0);
+#else
+    signal(SIGINT, SIG_DFL);
+    signal(SIGQUIT, SIG_DFL);
+    signal(SIGTERM, SIG_DFL);
+#endif
+#ifdef DEBUG
+    { int t = open("/dev/tty", 2);
+      if (t >= 0) {
+	  ioctl(t, TIOCNOTTY, (char *)0);
+	  (void) close(t);
+      }
+  }
+#endif
+    if (fromp->sa_family != AF_INET
+#if defined(KRB5_USE_INET6) && defined(KERBEROS)
+	&& fromp->sa_family != AF_INET6
+#endif
+	) {
+	syslog(LOG_ERR , "malformed from address\n");
+	exit(1);
+    }
+#ifdef KERBEROS
+    netf = f;
+#else
+    {
+	struct sockaddr_in *frompin = sa2sin(fromp);
+	frompin->sin_port = ntohs((u_short)frompin->sin_port);
+	if (frompin->sin_port >= IPPORT_RESERVED ||
+	    frompin->sin_port < IPPORT_RESERVED/2) {
+	    syslog(LOG_ERR , "connection from bad port\n");
+	    exit(1);
+	}
+    }
+#endif /* KERBEROS */
+    
+#ifdef CRAY
+    
+    /* If this is a secure system then get the packet classification
+       of f.  ( Note IP_SECURITY is checked in get_packet_classification:
+       if it's not set then the user's (root) default
+       classification level and compartments are returned. )
+       Then set this process to that level/compart so that the stderr
+       connection will be labeled appropriately.
+       */
+    if (secflag) {
+	if (get_packet_classification(f,getuid(),
+				      &packet_level,&packet_compart) < 0) {
+	    syslog(LOG_ERR, "cannot get ip packet level\n");
+	    exit(1);
+	}
+	if(secflag == TFM_UDB_5) {
+	    if(setucmp(packet_compart, C_PROC) != 0) {
+		error("Unable to setucmp.\n");
+		exit(1);
+	    }
+	} else if(secflag == TFM_UDB_6) {
+	    if(setulvl(packet_level,C_PROC) != 0) {
+		error("Unable to setulvl.\n");
+		exit(1);
+	    }
+	    if(setucmp(packet_compart, C_PROC) != 0) {
+		error("Unable to setucmp.\n");
+		exit(1);
+	    }
+	}
+	
+    }
+#endif /* CRAY */
+    
+    (void) alarm(60);
+    port = 0;
+    for (;;) {
+	char c;
+	if ((cc = read(f, &c, 1)) != 1) {
+	    if (cc < 0)
+	      syslog(LOG_NOTICE , "read: %m");
+	    shutdown(f, 1+1);
+	    exit(1);
+	}
+	if (c == 0)
+	  break;
+	port = port * 10 + c - '0';
+    }
+    (void) alarm(0);
+    if (port != 0) {
+	if (anyport) {
+	    int addrfamily = fromp->sa_family;
+	    s = getport(0, &addrfamily);
+	} else {
+	    int lport = IPPORT_RESERVED - 1;
+#ifdef HAVE_RRESVPORT_AF
+	    s = rresvport_af(&lport, fromp->sa_family);
+#else
+	    s = rresvport(&lport);
+#endif
+	}
+	if (s < 0) {
+	    syslog(LOG_ERR ,
+		   "can't get stderr port: %m");
+	    exit(1);
+	}
+#ifndef KERBEROS
+	if (port >= IPPORT_RESERVED) {
+	    syslog(LOG_ERR , "2nd port not reserved\n");
+	    exit(1);
+	}
+#endif /* KERBEROS */
+	switch (fromp->sa_family) {
+	case AF_INET:
+	    sa2sin(fromp)->sin_port = htons((u_short)port);
+	    break;
+#ifdef KRB5_USE_INET6
+	case AF_INET6:
+	    sa2sin6(fromp)->sin6_port = htons((u_short)port);
+	    break;
+#endif
+	}
+	if (connect(s, (struct sockaddr *)fromp, socklen(fromp)) < 0) {
+	    syslog(LOG_INFO ,
+		   "connect second port: %m");
+	    exit(1);
+	}
+    }
+    dup2(f, 0);
+    dup2(f, 1);
+    dup2(f, 2);
+    aierr = getnameinfo(fromp, socklen(fromp), hostname, sizeof(hostname),
+			0, 0, 0);
+    if (aierr) {
+	error("failed to get remote host address: %s", gai_strerror(aierr));
+	exit(1);
+    }
+    aierr = getnameinfo(fromp, socklen(fromp), hostaddra, sizeof(hostaddra),
+			0, 0, NI_NUMERICHOST);
+    if (aierr) {
+	error("failed to get remote host address: %s", gai_strerror(aierr));
+	exit(1);
+    }
+
+#ifdef KERBEROS
+    status = pty_make_sane_hostname((struct sockaddr *) fromp, maxhostlen,
+				    stripdomain, always_ip, &sane_host);
+    if (status) {
+	error("failed make_sane_hostname: %s\n", error_message(status));
+	exit(1);
+    }
+
+    if ((status = recvauth(f, fromp, &valid_checksum))) {
+	error("Authentication failed: %s\n", error_message(status));
+	exit(1);
+    }
+#else
+    getstr(f, remuser, sizeof(remuser), "remuser");
+    getstr(f, locuser, sizeof(locuser), "locuser");
+    getstr(f, cmdbuf, sizeof(cmdbuf), "command");
+    rcmd_stream_init_normal();
+#endif /* KERBEROS */
+    
+#ifdef CRAY
+    paddr = inet_addr(inet_ntoa(fromp->sin_addr));
+    if(secflag){
+	/*
+	 *      check network authorization list
+	 */
+	if (fetchnal(paddr,&nal) < 0) {
+	    /*
+	     *      NAL file inaccessible, abort connection.
+	     */
+	    error("Permission denied.\n");
+	    exit(1);
+	}
+    }
+#endif /* CRAY */
+    
+    pwd = getpwnam(locuser);
+    if (pwd == (struct passwd *) 0 ) {
+	syslog(LOG_ERR ,
+	       "Principal %s (%s@%s (%s)) for local user %s has no account.\n",
+	       kremuser, remuser, hostaddra, hostname,
+	       locuser); /* xxx sprintf buffer in syslog*/
+	error("Login incorrect.\n");
+	exit(1);
+    }
+    
+#ifdef CRAY
+    /* Setup job entry, and validate udb entry. 
+       ( against packet level also ) */
+    if ((jid = setjob(pwd->pw_uid, 0)) < 0) {
+	error("Unable to create new job.\n");
+	exit(1);
+    }
+    if ((jtmpnam = makejtmp(pwd->pw_uid, pwd->pw_gid, jid))) {
+	register int pid, tpid;
+	int status;
+	switch(pid = fork()) {
+	  case -1:
+	    cleanjtmp(locuser, jtmpnam);
+	    envinit[TMPDIRENV] = 0;
+	    break;
+	  case 0:
+	    break;
+	  default:
+	    close(0);
+	    close(1);
+	    close(2);
+	    close(f);
+	    if (port)
+	      close(s);
+	    while ((tpid = wait(&status)) != pid) {
+		if (tpid < 0)
+		  break;
+	    }
+	    cleanjtmp(locuser, jtmpnam);
+	    exit(status>>8);
+	    /* NOTREACHED */
+	}
+    } else {
+	envinit[TMPDIRENV] = 0;
+    }
+#ifndef NO_UDB
+    (void)getsysudb();
+    
+    if ((ue = getudbnam(pwd->pw_name)) == (struct udb *)NULL) {
+	error("Unable to fetch account id.\n");
+	exit(1);
+    }
+    ue_static = *ue;                /* save from setlimits call */
+    endudb();
+    if (secflag) {
+	if(getsysv(&sysv, sizeof(struct sysv)) != 0) {
+	    loglogin(sane_host, SLG_LLERR, 0, ue);
+	    error("Permission denied.\n");
+	    exit(1);
+	}
+	if ((packet_level != ue->ue_deflvl) ||
+	    ((packet_compart & ue->ue_comparts) != packet_compart )){
+	    loglogin(sane_host, SLG_LLERR, 0, ue);
+	    error("Permission denied.\n");
+	    exit(1);
+	}
+	if (ue->ue_disabled != 0) {
+	    loglogin(sane_host,SLG_LOCK,ue->ue_logfails,ue);
+	    error("Permission denied.\n");
+	    exit(1);
+	}
+	maxlogs = sysv.sy_maxlogs;
+    }
+    if (acctid(getpid(), ue->ue_acids[0]) == -1) {
+	error("Unable to set account id.\n");
+	exit(1);
+    }
+    if (setshares(pwd->pw_uid, acctid(0, -1), error, 1, 0)) {
+	error("Unable to set shares.\n");
+	exit(1);
+    }
+    if (setlimits(pwd->pw_name, C_PROC, getpid(), UDBRC_INTER)) {
+	error("Unable to set limits.\n");
+	exit(1);
+    }
+    if (setlimits(pwd->pw_name, C_JOB, jid, UDBRC_INTER)) {
+	error("Unable to set limits.\n");
+	exit(1);
+    }
+    ue = &ue_static;                /* restore after setlimits call */
+    endudb();			/* setlimits opens udb and leaves it
+				   open so close it here. */
+#endif  /* !NO_UDB */
+#endif /*CRAY*/
+    
+    /* Setup wtmp entry : we do it here so that if this is a CRAY
+       the Process Id is correct and we have not lost our trusted
+       privileges. */
+    if (port) {
+	/* Place entry into wtmp */
+	sprintf(ttyn,"krsh%ld",(long) (getpid() % 9999999));
+	pty_logwtmp(ttyn,locuser,sane_host);
+    }
+    /*      We are simply execing a program over rshd : log entry into wtmp,
+	    as kexe(pid), then finish out the session right after that.
+	    Syslog should have the information as to what was exec'd */
+    else {
+	pty_logwtmp(ttyn,locuser,sane_host);
+    }
+    
+#ifdef CRAY
+    
+    /* If  we are a secure system then we need to get rid of our
+       trusted facility, so that MAC on the chdir we work. Before we
+       do this make an entry into wtmp, and any other audit recording. */
+    
+    if (secflag) {
+	if (getusrv(&usrv)){
+	    syslog(LOG_ERR,"Cannot getusrv");
+	    error("Permission denied.\n");
+	    loglogin(sane_host, SLG_LVERR, ue->ue_logfails,ue);
+	    goto signout_please;
+	}
+	/*
+	 *      6.0 no longer allows any form ofTRUSTED_PROCESS logins.
+	 */
+	if((ue->ue_valcat & TFM_TRUSTED) ||
+	   (sysv.sy_oldtfm &&
+	    ((ue->ue_comparts & TRUSTED_SUBJECT) == TRUSTED_SUBJECT))) {
+	    loglogin(sane_host, SLG_TRSUB, ue->ue_logfails,ue);
+	    error("Permission denied.\n");
+	    goto signout_please;
+	}
+	
+	loglogin(sane_host, SLG_OKLOG, ue->ue_logfails,ue);
+	
+	/*	Setup usrv structure with user udb info and 
+		packet_level and packet_compart. */
+	usrv.sv_actlvl = packet_level;
+	usrv.sv_actcmp = packet_compart; /*Note get_packet_level sets
+					   compartment to users default
+					   compartments....*/
+	usrv.sv_permit = ue->ue_permits;
+	usrv.sv_intcls = ue->ue_intcls;
+	usrv.sv_maxcls = ue->ue_maxcls;
+	usrv.sv_intcat = ue->ue_intcat;
+	usrv.sv_valcat = ue->ue_valcat;
+	usrv.sv_savcmp = 0;
+	usrv.sv_savlvl = 0;
+	
+	/*
+	 *      Set user values to workstation boundaries
+	 */
+#ifdef MIN
+#undef MIN
+#endif
+#ifdef MAX
+#undef MAX
+#endif
+	
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+	
+	nal_error = 0;
+	
+	if (nal.na_sort) {
+	    if ((ue->ue_minlvl > nal.na_smax) ||
+		(ue->ue_maxlvl < nal.na_smin))
+	      nal_error++;
+	    else {
+		usrv.sv_minlvl=MAX(ue->ue_minlvl, nal.na_smin);
+		usrv.sv_maxlvl=MIN(ue->ue_maxlvl, nal.na_smax);
+		
+#ifndef IP_SECURITY
+
+		if (usrv.sv_actlvl < usrv.sv_minlvl)
+		    usrv.sv_actlvl = usrv.sv_minlvl;
+		if (usrv.sv_actlvl > usrv.sv_maxlvl)
+		  usrv.sv_actlvl = usrv.sv_maxlvl;
+		
+#else /*IP_SECURITY*/
+		if (usrv.sv_actlvl < usrv.sv_minlvl)
+		  nal_error++;
+		if (usrv.sv_actlvl > usrv.sv_maxlvl)
+		  nal_error++;
+		if (usrv.sv_actlvl != ue->ue_deflvl)
+		  nal_error++;
+		
+		usrv.sv_valcmp = ue->ue_comparts & nal.na_scmp;
+		usrv.sv_actcmp &= nal.na_scmp;
+#endif /*IP_SECURITY*/
+		usrv.sv_valcmp = ue->ue_comparts & nal.na_scmp;
+		usrv.sv_actcmp = (usrv.sv_valcmp &
+				  ue->ue_defcomps);
+	    }
+	} else {
+	    /*
+	     *      If the user's minimum level is greater than
+	     *      zero, they cannot log on from this (ie. an
+	     *      unclassified) host.
+	     */
+	    if (ue->ue_minlvl > 0)
+	      nal_error++;
+	    /*
+	     *      Address not in NAL, if EXEMPT_NAL is not
+	     *      true, then even an unclassified user is
+	     *      not allowed.
+	     */
+	    if (!EXEMPT_NAL)
+		nal_error++;
+	    else {
+		usrv.sv_minlvl = 0;
+		usrv.sv_maxlvl = 0;
+		usrv.sv_valcmp = 0;
+		usrv.sv_actcmp = 0;
+		usrv.sv_actlvl = 0;
+	    }
+	}
+	if (nal_error) {
+	    loglogin(sane_host, SLG_LVERR, ue->ue_logfails,ue);
+	    error("Permission denied.\n");
+	    goto signout_please;
+	}
+#undef  MIN
+#undef  MAX
+	/* Before the setusrv is done then do a sethost for paddr */
+	sethost(paddr);
+	
+	if (setusrv(&usrv) == -1) {
+	    loglogin(sane_host, SLG_LVERR, ue->ue_logfails,ue);
+	    error("Permission denied.\n");
+	    goto signout_please;
+	}
+	if (getusrv(&usrv) == -1) {
+	    error("Getusrv Permission denied.\n");
+	    goto signout_please;
+	}
+	
+    }
+#endif /*CRAY*/
+    
+    if (chdir(pwd->pw_dir) < 0) {
+      if(chdir("/") < 0) {
+      	error("No remote directory.\n");
+	goto signout_please;
+      }
+	   pwd->pw_dir = "/";
+    }
+
+#ifdef KERBEROS
+
+#if defined(KRB5_KRB4_COMPAT) && !defined(ALWAYS_V5_KUSEROK)
+	if (auth_sys == KRB5_RECVAUTH_V4) {
+	    /* kuserok returns 0 if OK */
+	    if (kuserok(v4_kdata, locuser)){
+		syslog(LOG_ERR ,
+		       "Principal %s (%s@%s (%s)) for local user %s failed kuserok.\n",
+		       kremuser, remuser, hostaddra, hostname, locuser);
+		}
+	    else auth_sent |= AUTH_KRB4;
+	} else
+#endif
+	{
+	    /* krb5_kuserok returns 1 if OK */
+	    if (!krb5_kuserok(bsd_context, client, locuser)){
+		syslog(LOG_ERR ,
+		       "Principal %s (%s@%s (%s)) for local user %s failed krb5_kuserok.\n",
+		       kremuser, remuser, hostaddra, hostname, locuser);
+	    }
+	    else
+		auth_sent |=
+		    ((auth_sys == KRB5_RECVAUTH_V4) ? AUTH_KRB4 : AUTH_KRB5);
+	}
+
+	
+#else
+    if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
+	ruserok(hostname[0] ? hostname : hostaddra,
+		pwd->pw_uid == 0, remuser, locuser) < 0) {
+	error("Permission denied.\n");
+	goto signout_please;
+    }
+#endif /* KERBEROS */
+
+
+    if (checksum_required && !valid_checksum) {
+	if (auth_sent & AUTH_KRB5) {
+	    syslog(LOG_WARNING, "Client did not supply required checksum--connection rejected.");
+	    error( "You are using an old Kerberos5 client without checksum support; only newer clients are authorized.\n");
+	    goto signout_please;
+	} else {
+	    syslog(LOG_WARNING,
+   "Configuration error: Requiring checksums with -c is inconsistent with allowing Kerberos V4 connections.");
+	}
+    }
+    if (require_encrypt&&(!do_encrypt)) {
+	error("You must use encryption.\n");
+	goto signout_please;
+    }
+    if (!(auth_ok&auth_sent)) {
+	if (auth_sent)
+	    error("Another authentication mechanism must be used to access this host.\n");
+	else
+	    error("Permission denied.\n");
+	goto signout_please;
+    }
+    
+    if (pwd->pw_uid && !access(NOLOGIN, F_OK)) {
+	error("Logins currently disabled.\n");
+	goto signout_please;
+    }
+    
+    /* Log access to account */
+    pwd = (struct passwd *) getpwnam(locuser);
+    if (pwd && (pwd->pw_uid == 0)) {
+#ifdef LOG_CMD
+	syslog(LOG_NOTICE, "Executing %s for principal %s (%s@%s (%s)) as ROOT", 
+	       cmdbuf, kremuser, remuser, hostaddra, hostname);
+#else
+	syslog(LOG_NOTICE ,"Access as ROOT by principal %s (%s@%s (%s))",
+	       kremuser, remuser, hostaddra, hostname);
+#endif
+    }
+#if defined(KERBEROS) && defined(LOG_REMOTE_REALM) && !defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS)
+    /* Log if principal is from a remote realm */
+    else if (client && !default_realm(client))
+#endif
+  
+#if defined(KERBEROS) && defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS) 
+    /* Log if principal name does not map to local username */
+    else if (client && !princ_maps_to_lname(client, locuser))
+#endif /* LOG_OTHER_USERS */
+  
+#ifdef LOG_ALL_LOGINS /* Log everything */
+    else 
+#endif 
+  
+#if defined(LOG_REMOTE_REALM) || defined(LOG_OTHER_USERS) || defined(LOG_ALL_LOGINS)
+      {
+#ifdef LOG_CMD
+	  syslog(LOG_NOTICE, "Executing %s for principal %s (%s@%s (%s)) as local user %s", 
+		 cmdbuf, kremuser, remuser, hostaddra, hostname, locuser);
+#else
+	  syslog(LOG_NOTICE ,"Access as %s by principal %s (%s@%s (%s))",
+		 locuser, kremuser, remuser, hostaddra, hostname);
+#endif
+      }
+#endif
+    
+    (void) write(2, "", 1);
+    
+    if (port||do_encrypt) {
+	if (port&&(pipe(pv) < 0)) {
+	    error("Can't make pipe.\n");
+	    goto signout_please;
+	}
+	if (pipe(pw) < 0) {
+	    error("Can't make pipe 2.\n");
+	    goto signout_please;
+	}
+	if (pipe(px) < 0) {
+	    error("Can't make pipe 3.\n");
+	    goto signout_please;
+	}
+	pid = fork();
+	if (pid == -1)  {
+	    error("Fork failed.\n");
+	    goto signout_please;
+	}
+	if (pid) {
+#ifdef POSIX_SIGNALS
+	    sa.sa_handler = cleanup;
+	    (void)sigaction(SIGINT, &sa, (struct sigaction *)0);
+	    (void)sigaction(SIGQUIT, &sa, (struct sigaction *)0);
+	    (void)sigaction(SIGTERM, &sa, (struct sigaction *)0);
+	    (void)sigaction(SIGHUP, &sa, (struct sigaction *)0);
+
+	    sa.sa_handler = SIG_IGN;
+	    /* SIGPIPE is a crutch that we don't need if we check 
+	       the exit status of write. */
+	    (void)sigaction(SIGPIPE, &sa, (struct sigaction *)0);
+	    (void)sigaction(SIGCHLD, &sa, (struct sigaction *)0);
+#else
+	    signal(SIGINT, cleanup);
+	    signal(SIGQUIT, cleanup);
+	    signal(SIGTERM, cleanup);
+	    signal(SIGHUP, cleanup);
+	    /* SIGPIPE is a crutch that we don't need if we check 
+	       the exit status of write. */
+	    signal(SIGPIPE, SIG_IGN);
+	    signal(SIGCHLD,SIG_IGN);
+#endif
+	    
+	    (void) close(0); (void) close(1); (void) close(2);
+	    if(port)
+		(void) close(pv[1]);
+	    (void) close(pw[1]);
+	    (void) close(px[0]);
+	    
+	    
+	    
+	    FD_ZERO(&readfrom);
+	    FD_SET(f, &readfrom);
+	    if(port) {
+		FD_SET(s, &readfrom);
+		FD_SET(pv[0], &readfrom);
+	    }
+	    FD_SET(pw[0], &readfrom);
+	    
+	    /* read from f, write to px[1] -- child stdin */
+	    /* read from s, signal child */
+	    /* read from pv[0], write to s -- child stderr */
+	    /* read from pw[0], write to f -- child stdout */
+
+	    do {
+		ready = readfrom;
+		if (select(8*sizeof(ready), &ready, (fd_set *)0,
+			   (fd_set *)0, (struct timeval *)0) < 0) {
+		    if (errno == EINTR) {
+			continue;
+		    } else {
+			break;
+		}
+		}
+
+		if (port&&FD_ISSET(pv[0], &ready)) {
+		    /* read from the child stderr, write to the net */
+		    errno = 0;
+		    cc = read(pv[0], buf, sizeof (buf));
+		    if (cc <= 0) {
+			shutdown(s, 1+1);
+			FD_CLR(pv[0], &readfrom);
+		    } else {
+			(void) rcmd_stream_write(s, buf, (unsigned) cc, 1);
+		    }
+		}
+		if (FD_ISSET(pw[0], &ready)) {
+		    /* read from the child stdout, write to the net */
+		    errno = 0;
+		    cc = read(pw[0], buf, sizeof (buf));
+		    if (cc <= 0) {
+			shutdown(f, 1+1);
+			FD_CLR(pw[0], &readfrom);
+		    } else {
+			(void) rcmd_stream_write(f, buf, (unsigned) cc, 0);
+		    }
+		}
+		if (port&&FD_ISSET(s, &ready)) {
+		    /* read from the alternate channel, signal the child */
+		    if (rcmd_stream_read(s, &sig, 1, 1) <= 0) {
+			FD_CLR(s, &readfrom);
+		    } else {
+#ifdef POSIX_SIGNALS
+			sa.sa_handler = cleanup;
+			(void)sigaction(sig, &sa, (struct sigaction *)0);
+			kill(-pid, sig);
+#else
+			signal(sig, cleanup);
+			killpg(pid, sig);
+#endif
+		    }
+		}
+		if (FD_ISSET(f, &ready)) {
+		    /* read from the net, write to child stdin */
+		    errno = 0;
+		    cc = rcmd_stream_read(f, buf, sizeof(buf), 0);
+		    if (cc <= 0) {
+			(void) close(px[1]);
+			FD_CLR(f, &readfrom);
+		    } else {
+		        int wcc;
+		        wcc = write(px[1], buf, (unsigned) cc);
+			if (wcc == -1) {
+			  /* pipe closed, don't read any more */
+			  /* might check for EPIPE */
+			  (void) close(px[1]);
+			  FD_CLR(f, &readfrom);
+			} else if (wcc != cc) {
+			  syslog(LOG_INFO, "only wrote %d/%d to child", 
+				 wcc, cc);
+			}
+		    }
+		}
+	    } while ((port&&FD_ISSET(s, &readfrom)) ||
+		     FD_ISSET(f, &readfrom) ||
+		     (port&&FD_ISSET(pv[0], &readfrom) )||
+		     FD_ISSET(pw[0], &readfrom));
+	    ignore_signals();
+#ifdef KERBEROS
+	    syslog(LOG_INFO ,
+		   "Shell process completed.");
+#endif
+	    /* Finish session in wmtp */
+	    pty_logwtmp(ttyn,"","");
+	    if (ccache)
+		krb5_cc_destroy(bsd_context, ccache);
+	    exit(0);
+	}
+#if defined(HAVE_SETSID)&&(!defined(ULTRIX))
+	setsid();
+#else
+#ifdef SETPGRP_TWOARG
+	setpgrp(0, getpid());
+#else
+	setpgrp();
+#endif /*setpgrp_twoarg*/
+#endif /*HAVE_SETSID*/
+	(void) close(s);
+	(void) close(f);
+	(void) close(pw[0]);
+	if (port)
+	    (void) close(pv[0]);
+	(void) close(px[1]);
+
+	(void) dup2(px[0], 0);
+	(void) dup2(pw[1], 1);
+	if(port)
+	    (void) dup2(pv[1], 2);
+	else dup2(pw[1], 2);
+
+	(void) close(px[0]);
+	(void) close(pw[1]);
+	if(port)
+	    (void) close(pv[1]);
+    }
+    
+    /*      We are simply execing a program over rshd : log entry into wtmp, 
+	    as kexe(pid), then finish out the session right after that.
+	    Syslog should have the information as to what was exec'd */
+    else {
+	pty_logwtmp(ttyn,"","");
+    }
+    
+    if (*pwd->pw_shell == '\0')
+      pwd->pw_shell = "/bin/sh";
+    (void) close(f);
+    (void) setgid((gid_t)pwd->pw_gid);
+#ifndef sgi
+    if (getuid() == 0 || getuid() != pwd->pw_uid) {
+        /* For testing purposes, we don't call initgroups if we
+           already have the right uid, and it is not root.  This is
+           because on some systems initgroups outputs an error message
+           if not called by root.  */
+        initgroups(pwd->pw_name, pwd->pw_gid);
+    }
+#endif
+#ifdef	HAVE_SETLUID
+    /*
+     * If we're on a system which keeps track of login uids, then
+     * set the login uid. 
+     */
+    setluid((uid_t) pwd->pw_uid);
+#endif	/* HAVE_SETLUID */
+    (void) setuid((uid_t)pwd->pw_uid);
+    /* if TZ is set in the parent, drag it in */
+    {
+      char **findtz = environ;
+      while(*findtz) {
+	if(!strncmp(*findtz,"TZ=",3)) {
+	  envinit[TZENV] = *findtz;
+	  break;
+	}
+	findtz++;
+      }
+    }
+    strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
+    strncat(shell, pwd->pw_shell, sizeof(shell)-7);
+    strncat(username, pwd->pw_name, sizeof(username)-6);
+    path = (char *) malloc(strlen(kprogdir) + strlen(path_rest) + 7);
+    if (path == NULL) {
+        perror("malloc");
+	_exit(1);
+    }
+    sprintf(path, "PATH=%s:%s", kprogdir, path_rest);
+    envinit[PATHENV] = path;
+
+    /* If we have KRB5CCNAME set, then copy into the
+     * child's environment.  This can't really have
+     * a fixed position because tz may or may not be set.
+     */
+    if (getenv("KRB5CCNAME")) {
+	int i;
+	char *buf2 = (char *)malloc(strlen(getenv("KRB5CCNAME"))
+			 		   +strlen("KRB5CCNAME=")+1);
+	if (buf2) {
+	  sprintf(buf2, "KRB5CCNAME=%s",getenv("KRB5CCNAME"));
+
+	  for (i = 0; envinit[i]; i++);
+	  envinit[i] = buf2;
+	}
+    }
+
+    {
+      char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+      int i;
+      /* these four are covered by ADDRPAD */
+
+      for (i = 0; envinit[i]; i++);
+
+      aierr = getnameinfo((struct sockaddr *)&localaddr,
+			  socklen((struct sockaddr *)&localaddr),
+			  hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
+			  NI_NUMERICHOST | NI_NUMERICSERV);
+      if (aierr)
+	  goto skip_localaddr_env;
+      sprintf(local_addr,  "KRB5LOCALADDR=%s", hbuf);
+      envinit[i++] =local_addr;
+
+      sprintf(local_port,  "KRB5LOCALPORT=%s", sbuf);
+      envinit[i++] =local_port;
+    skip_localaddr_env:
+
+      aierr = getnameinfo(fromp, socklen(fromp),
+			  hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
+			  NI_NUMERICHOST | NI_NUMERICSERV);
+      if (aierr)
+	  goto skip_remoteaddr_env;
+      sprintf(remote_addr, "KRB5REMOTEADDR=%s", hbuf);
+      envinit[i++] =remote_addr;
+
+      sprintf(remote_port, "KRB5REMOTEPORT=%s", sbuf);
+      envinit[i++] =remote_port;
+
+    skip_remoteaddr_env:
+      ;
+    }
+
+    /* If we do anything else, make sure there is space in the array. */
+
+    for(cnt=0; cnt < num_env; cnt++) {
+	    int i;
+	    char *buf2;
+
+	    if(getenv(save_env[cnt])) {
+		    buf2 = (char *)malloc(strlen(getenv(save_env[cnt]))
+					 +strlen(save_env[cnt]+2));
+		    if (buf2) {
+			    sprintf(buf2, "%s=%s", save_env[cnt], 
+				    getenv(save_env[cnt]));
+			    for (i = 0; envinit[i]; i++);
+			    envinit[i] = buf2;
+		    }
+	    }
+    }
+
+    /* XXX - If we do anything else, make sure there is space in the array. */
+
+    environ = envinit;
+    
+#ifdef KERBEROS
+    /* To make Kerberos rcp work correctly, we must ensure that we
+       invoke Kerberos rcp on this end, not normal rcp, even if the
+       shell startup files change PATH.  */
+    if (!strncmp(cmdbuf, "rcp ", 4) ||
+	(do_encrypt && !strncmp(cmdbuf, "-x rcp ", 7))) {
+        char *copy;
+	struct stat s2;
+	int offst = 0;
+
+	copy = malloc(strlen(cmdbuf) + 1);
+	if (copy == NULL) {
+	    perror("malloc");
+	    _exit(1);
+	}
+	strcpy(copy, cmdbuf);
+	if (do_encrypt && !strncmp(cmdbuf, "-x ", 3)) {
+		offst = 3;
+	}
+
+        strcpy((char *) cmdbuf + offst, kprogdir);
+	cp = copy + 3 + offst;
+
+	cmdbuf[sizeof(cmdbuf) - 1] = '\0';
+	if (auth_sys == KRB5_RECVAUTH_V4) {
+	  strncat(cmdbuf, "/v4rcp", sizeof(cmdbuf) - 1 - strlen(cmdbuf));
+	} else {
+	  strncat(cmdbuf, "/rcp", sizeof(cmdbuf) - 1 - strlen(cmdbuf));
+	}
+	if (stat((char *)cmdbuf + offst, &s2) >= 0)
+	  strncat(cmdbuf, cp, sizeof(cmdbuf) - 1 - strlen(cmdbuf));
+	else
+	  strncpy(cmdbuf, copy, sizeof(cmdbuf) - 1 - strlen(cmdbuf));
+	free(copy);
+    }
+#endif
+
+    cp = strrchr(pwd->pw_shell, '/');
+    if (cp)
+      cp++;
+    else
+      cp = pwd->pw_shell;
+    
+    if (do_encrypt && !strncmp(cmdbuf, "-x ", 3)) {
+	execl(pwd->pw_shell, cp, "-c", (char *)cmdbuf + 3, (char *)NULL);
+    }
+    else {
+	execl(pwd->pw_shell, cp, "-c", cmdbuf, (char *)NULL);
+    }
+    perror(pwd->pw_shell);
+    perror(cp);
+    exit(1);
+    
+  signout_please:
+    if (ccache)
+	krb5_cc_destroy(bsd_context, ccache);
+    ccache = NULL;
+    pty_logwtmp(ttyn,"","");
+    exit(1);
+}
+
+
+void
+#ifdef HAVE_STDARG_H
+error(char *fmt, ...)
+#else
+/*VARARGS1*/
+error(fmt, va_alist)
+     char *fmt;
+     va_dcl
+#endif
+{
+    va_list ap;
+    char buf[RCMD_BUFSIZ],  *cp = buf;
+    
+#ifdef HAVE_STDARG_H
+    va_start(ap, fmt);
+#else
+    va_start(ap);
+#endif
+
+    *cp++ = 1;
+    (void) sprintf(cp, "%s: ", progname);
+    (void) vsprintf(buf+strlen(buf), fmt, ap);
+    va_end(ap);
+    (void) write(2, buf, strlen(buf));
+    syslog(LOG_ERR ,"%s",buf+1);
+}
+
+
+void getstr(fd, buf, cnt, err)
+    int fd;
+    char *buf;
+    int cnt;
+    char *err;
+{
+    char c;
+    
+    do {
+	if (read(fd, &c, 1) != 1)
+	  exit(1);
+	*buf++ = c;
+	if (--cnt == 0) {
+	    error("%s too long\n", err);
+	    exit(1);
+	}
+    } while (c != 0);
+}
+
+#ifdef	CRAY
+char *makejtmp(uid, gid, jid)
+     register int uid, gid, jid;
+{
+    register char *endc, *tdp = &tmpdir[strlen(tmpdir)];
+    register int i;
+    
+    sprintf(tdp, "%s/jtmp.%06d", JTMPDIR, jid);
+    endc = &tmpdir[strlen(tmpdir)];
+    
+    endc[1] = '\0';
+    for (i = 0; i < 26; i++) {
+	endc[0] = 'a' + i;
+	if (mkdir(tdp, JTMPMODE) != -1) {
+	    chown(tdp, uid, gid);
+	    return (tdp);
+	} else if (errno != EEXIST)
+	  break;
+    }
+    return(NULL);
+}
+
+
+
+cleanjtmp(user, tpath)
+     register char *user, *tpath;
+{
+    switch(fork()) {
+      case -1:
+	break;
+      case 0:
+	if (secflag) {
+	    execl("/bin/rm", "rm", "-rf", tpath, 0);
+	    error("exec of %s failed; errno = %d\n",
+		  "/bin/rm", errno);
+	} else {
+	    execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
+	    error("exec of %s failed; errno = %d\n",
+		  CLEANTMPCMD, errno);
+	}
+	exit(1);
+	break;
+      default:
+	/*
+	 * Just forget about the child, let init will pick it
+	 * up after we exit.
+	 */
+	break;
+    }
+}
+
+
+
+/***get_packet_classification
+ *
+ *
+ *      int get_packet_classification():
+ *      Obtain packet level and compartments from passed fd...
+ *
+ *      Returns:
+ *             -1: If could not get user defaults.
+ *              0: success
+ */
+#ifdef IP_SECURITY
+static int get_packet_classification(fd,useruid,level,comp)
+     int fd;
+     uid_t useruid;
+     int *level;
+     long *comp;
+{
+    struct socket_security pkt_sec;
+    struct udb *udb;
+    int retval;
+    int sockoptlen;
+    
+    retval = 0;
+    getsysudb ();
+    udb = getudbuid ((int) useruid);
+    endudb ();
+    if (udb == (struct udb *) 0) return(-1);
+    /* Get packet IP packet label */
+    sockoptlen = SIZEOF_sec;
+    if ( getsockopt(fd,SOL_SOCKET,SO_SECURITY,
+		    (char *) &pkt_sec,&sockoptlen)){  /* Failed */
+	return(-2);
+    }
+    *level = pkt_sec.sec_level;
+    *comp = udb->ue_defcomps;
+    return(0);
+}
+
+#else  /* If no IP_SECURITY set level to users default */
+
+static int get_packet_classification(fd,useruid,level,comp)
+     int fd;
+     uid_t useruid;
+     int *level;
+     long *comp;
+{
+    struct udb    *udb;
+    getsysudb ();
+    udb = getudbuid ((int) useruid);
+    endudb ();
+    if (udb == (struct udb *) 0) return(-1);
+    *level = udb->ue_deflvl;
+    *comp = udb->ue_defcomps;
+    return(0);
+}
+
+#endif /* IP_SECURITY */
+	
+	
+
+/*
+ * Make a security log entry for the login attempt.
+ *     host = pointer to host id
+ *     flag = status of login
+ *     failures = current losing streak in login attempts
+ */
+/* Make a security log entry for the login attempt.
+ *  host = pointer to host id
+ *  flag = status of login
+ *  failures = current losing streak in login attempts
+ */
+
+loglogin(host, flag, failures, ue)
+     char    *host;
+     int     flag;
+     int     failures;
+     struct udb * ue;
+{
+    char   urec[sizeof(struct slghdr) + sizeof(struct slglogin)];
+    struct slghdr   *uhdr = (struct slghdr *)urec;
+    struct slglogin *ulogin=(struct slglogin *)&urec[sizeof(struct slghdr)];
+    
+    strncpy(ulogin->sl_line, ttyn, sizeof(ulogin->sl_line));
+    strncpy(ulogin->sl_host, host, sizeof(ulogin->sl_host));
+    ulogin->sl_failures = failures;
+    if ( maxlogs && (failures >= maxlogs))
+      flag |= SLG_DSABL;
+    ulogin->sl_result = flag;
+    uhdr->sl_uid = ue->ue_uid;
+    uhdr->sl_ruid = ue->ue_uid;
+    uhdr->sl_juid = ue->ue_uid;
+    uhdr->sl_gid = ue->ue_gids[0];
+    uhdr->sl_rgid = ue->ue_gids[0];
+    uhdr->sl_slvl = ue->ue_deflvl;
+    /*      uhdr->sl_scls = ue->ue_defcls;  enable for integrity policy */
+    uhdr->sl_olvl = 0;
+    uhdr->sl_len = sizeof(urec);
+    
+#ifdef  CRAY2
+    slgentry(SLG_LOGN, (word *)urec);
+#else /*        ! CRAY2 */
+    slgentry(SLG_LOGN, (waddr_t)urec);
+#endif
+    return;
+}
+
+#endif /* CRAY */
+	
+
+
+void usage()
+{
+#ifdef KERBEROS
+    syslog(LOG_ERR, "usage: kshd [-54ecikK]  ");
+#else
+    syslog(LOG_ERR, "usage: rshd");
+#endif
+}
+
+
+#ifdef KERBEROS
+
+#ifndef KRB_SENDAUTH_VLEN
+#define	KRB_SENDAUTH_VLEN 8	    /* length for version strings */
+#endif
+
+#define	KRB_SENDAUTH_VERS	"AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN
+					      chars */
+
+static krb5_error_code
+recvauth(netfd, peersin, valid_checksum)
+     int netfd;
+     struct sockaddr *peersin;
+     int *valid_checksum;
+{
+    krb5_auth_context auth_context = NULL;
+    krb5_error_code status;
+    struct sockaddr_in laddr;
+    socklen_t len;
+    krb5_data inbuf;
+#ifdef KRB5_KRB4_COMPAT
+    char v4_instance[INST_SZ];	/* V4 Instance */
+#endif
+    krb5_authenticator *authenticator;
+    krb5_ticket        *ticket;
+    krb5_rcache		rcache;
+    struct passwd *pwd;
+    uid_t uid;
+    gid_t gid;
+    enum kcmd_proto kcmd_proto;
+    krb5_data version;
+
+    *valid_checksum = 0;
+    len = sizeof(laddr);
+    if (getsockname(netfd, (struct sockaddr *)&laddr, &len)) {
+	    exit(1);
+    }
+	
+#ifdef unicos61
+#define SIZEOF_INADDR  SIZEOF_in_addr
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+
+#ifdef KRB5_KRB4_COMPAT
+    strcpy(v4_instance, "*");
+#endif
+
+    status = krb5_auth_con_init(bsd_context, &auth_context);
+    if (status)
+	return status;
+
+    status = krb5_auth_con_genaddrs(bsd_context, auth_context, netfd,
+			        KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
+    if (status)
+	return status;
+
+    status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache);
+    if (status) return status;
+
+    if (! rcache) {
+	krb5_principal server;
+
+	status = krb5_sname_to_principal(bsd_context, 0, 0,
+					 KRB5_NT_SRV_HST, &server);
+	if (status) return status;
+
+	status = krb5_get_server_rcache(bsd_context,
+				krb5_princ_component(bsd_context, server, 0),
+				&rcache);
+	krb5_free_principal(bsd_context, server);
+	if (status) return status;
+
+	status = krb5_auth_con_setrcache(bsd_context, auth_context, rcache);
+	if (status) return status;
+    }
+
+#ifdef KRB5_KRB4_COMPAT
+    status = krb5_compat_recvauth_version(bsd_context, &auth_context, &netfd,
+				  NULL,		/* Specify daemon principal */
+				  0, 		/* no flags */
+				  keytab, /* normally NULL to use v5srvtab */
+				  0, 		/* v4_opts */
+				  "rcmd", 	/* v4_service */
+				  v4_instance, 	/* v4_instance */
+				  (struct sockaddr_in *)peersin, /* foreign address */
+				  &laddr, 	/* our local address */
+				  "", 		/* use default srvtab */
+
+				  &ticket, 	/* return ticket */
+				  &auth_sys, 	/* which authentication system*/
+				  &v4_kdata, 0, &version);
+#else
+    status = krb5_recvauth_version(bsd_context, &auth_context, &netfd,
+				   NULL,        /* daemon principal */
+				   0,           /* no flags */
+				   keytab,      /* normally NULL to use v5srvtab */
+				   &ticket,    /* return ticket */
+				   &version); /* application version string */
+    auth_sys = KRB5_RECVAUTH_V5;
+#endif
+    if (status) {
+	if (auth_sys == KRB5_RECVAUTH_V5) {
+	    /*
+	     * clean up before exiting
+	     */
+	    getstr(netfd, locuser, sizeof(locuser), "locuser");
+	    getstr(netfd, cmdbuf, sizeof(cmdbuf), "command");
+	    getstr(netfd, remuser, sizeof(locuser), "remuser");
+	}
+	return status;
+    }
+
+    getstr(netfd, locuser, sizeof(locuser), "locuser");
+    getstr(netfd, cmdbuf, sizeof(cmdbuf), "command");
+
+#ifdef KRB5_KRB4_COMPAT
+    if (auth_sys == KRB5_RECVAUTH_V4) {
+	rcmd_stream_init_normal();
+	
+	/* We do not really know the remote user's login name.
+         * Assume it to be the same as the first component of the
+	 * principal's name. 
+         */
+	strcpy(remuser, v4_kdata->pname);
+
+	status = krb5_425_conv_principal(bsd_context, v4_kdata->pname,
+					 v4_kdata->pinst, v4_kdata->prealm,
+					 &client);
+	if (status) return status;
+
+	status = krb5_unparse_name(bsd_context, client, &kremuser);
+	
+	return status;
+    }
+#endif /* KRB5_KRB4_COMPAT */
+
+    /* Must be V5  */
+	
+    kcmd_proto = KCMD_UNKNOWN_PROTOCOL;
+    if (version.length != 9)
+	fatal (netfd, "bad application version length");
+    if (!memcmp (version.data, "KCMDV0.1", 9))
+	kcmd_proto = KCMD_OLD_PROTOCOL;
+    if (!memcmp (version.data, "KCMDV0.2", 9))
+	kcmd_proto = KCMD_NEW_PROTOCOL;
+
+    getstr(netfd, remuser, sizeof(locuser), "remuser");
+
+    if ((status = krb5_unparse_name(bsd_context, ticket->enc_part2->client, 
+				    &kremuser)))
+	return status;
+    
+    if ((status = krb5_copy_principal(bsd_context, ticket->enc_part2->client, 
+				      &client)))
+	return status;
+    if ((status = krb5_auth_con_getauthenticator(bsd_context, auth_context,
+						 &authenticator)))
+      return status;
+    
+    if (authenticator->checksum && !checksum_ignored) {
+	struct sockaddr_storage adr;
+	unsigned int adr_length = sizeof(adr);
+	int e;
+	unsigned int buflen = strlen(cmdbuf)+strlen(locuser)+32;
+	char * chksumbuf = (char *) malloc(buflen);
+
+	if (chksumbuf == 0)
+	    goto error_cleanup;
+	if (getsockname(netfd, (struct sockaddr *) &adr, &adr_length) != 0)
+	    goto error_cleanup;
+
+	e = getnameinfo((struct sockaddr *)&adr, adr_length, 0, 0,
+			chksumbuf, buflen, NI_NUMERICSERV);
+	if (e) {
+	    free(chksumbuf);
+	    fatal(netfd, "local error: can't examine port number");
+	}
+	if (strlen(chksumbuf) > 30) {
+	    free(chksumbuf);
+	    fatal(netfd, "wacky local port number?!");
+	}
+	strcat(chksumbuf, ":");
+	strcat(chksumbuf,cmdbuf);
+	strcat(chksumbuf,locuser);
+
+	status = krb5_verify_checksum(bsd_context,
+				      authenticator->checksum->checksum_type,
+				      authenticator->checksum,
+				      chksumbuf, strlen(chksumbuf),
+				      ticket->enc_part2->session->contents, 
+				      ticket->enc_part2->session->length);
+
+    error_cleanup:
+	if (chksumbuf)
+	    free(chksumbuf);
+	if (status) {
+	    krb5_free_authenticator(bsd_context, authenticator);
+	    return status;
+	}
+	*valid_checksum = 1;
+    }
+    krb5_free_authenticator(bsd_context, authenticator);
+
+
+    if (!strncmp(cmdbuf, "-x ", 3))
+	do_encrypt = 1;
+
+    {
+	krb5_keyblock *key;
+	status = krb5_auth_con_getrecvsubkey (bsd_context, auth_context,
+					      &key);
+	if (status)
+	    fatal (netfd, "Server can't get session subkey");
+	if (!key && do_encrypt && kcmd_proto == KCMD_NEW_PROTOCOL)
+	    fatal (netfd, "No session subkey sent");
+	if (key && kcmd_proto == KCMD_OLD_PROTOCOL) {
+#ifdef HEIMDAL_FRIENDLY
+	    key = 0;
+#else
+	    fatal (netfd, "Session subkey not allowed in old kcmd protocol");
+#endif
+	}
+	if (key == 0)
+	    key = ticket->enc_part2->session;
+	rcmd_stream_init_krb5 (key, do_encrypt, 0, 0, kcmd_proto);
+    }
+
+    /* Null out the "session" because kcmd.c references the session
+     * key here, and we do not want krb5_free_ticket() to destroy it. */
+    ticket->enc_part2->session = 0;
+
+    if ((status = krb5_read_message(bsd_context, (krb5_pointer)&netfd,
+				    &inbuf))) {
+	error("Error reading message: %s\n", error_message(status));
+	exit(1);
+    }
+
+    if (inbuf.length) { /* Forwarding being done, read creds */
+	pwd = getpwnam(locuser);
+	if (!pwd) {
+	    error("Login incorrect.\n");
+	    exit(1);
+	}
+	uid = pwd->pw_uid;
+	gid = pwd->pw_gid;
+	if ((status = rd_and_store_for_creds(bsd_context, auth_context, &inbuf,
+					     ticket, &ccache))) {
+	    error("Can't get forwarded credentials: %s\n",
+		  error_message(status));
+	    exit(1);
+	}
+	if (chown(krb5_cc_get_name(bsd_context, ccache), uid, gid) == -1) {
+	    error("Can't chown forwarded credentials: %s\n",
+		  error_message(errno));
+	    exit(1);
+	}
+    }
+    krb5_free_ticket(bsd_context, ticket);
+    return 0;
+}
+#endif /* KERBEROS */
+
+
+
+void fatal(f, msg)
+     int f;
+     const char *msg;
+{
+    char buf[512];
+#ifndef POSIX_TERMIOS
+    int out = 1 ;          /* Output queue of f */
+#endif
+
+    buf[0] = '\01';             /* error indicator */
+    (void) sprintf(buf + 1, "%s: %s.\r\n",progname, msg);
+    if ((f == netf) && (pid > 0))
+      (void) rcmd_stream_write(f, buf, strlen(buf), 0);
+    else
+      (void) write(f, buf, strlen(buf));
+    syslog(LOG_ERR,"%s\n",msg);
+    if (pid > 0) {
+        signal(SIGCHLD,SIG_IGN);
+        kill(pid,SIGKILL);
+#ifdef POSIX_TERMIOS
+        (void) tcflush(1, TCOFLUSH);
+#else
+        (void) ioctl(f, TIOCFLUSH, (char *)&out);
+#endif
+        cleanup(-1);
+    }
+    exit(1);
+}
diff --git a/mechglue/src/appl/bsd/kshd.M b/mechglue/src/appl/bsd/kshd.M
new file mode 100644
index 000000000..6e2efdb2b
--- /dev/null
+++ b/mechglue/src/appl/bsd/kshd.M
@@ -0,0 +1,209 @@
+.\" Copyright (c) 1983 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"	@(#)rshd.8	6.3 (Berkeley) 5/24/86
+.\"
+.TH KRSHD 8
+.SH NAME
+kshd \- kerberized remote shell server
+.SH SYNOPSIS
+.B /usr/local/sbin/kshd 
+[
+.B \-kr45ec
+]
+[\fB\-D\fP \fIport\fP]
+[\fB\-L\fP \fIvariable\fP]
+.SH DESCRIPTION
+.I Krshd
+is the server for the 
+.IR rcmd (3)
+routine and, consequently, for the
+.IR rsh (1)
+program.  The server provides remote execution facilities
+with authentication based on privileged port numbers from trusted hosts or 
+the Kerberos authentication system.
+.PP
+The
+.I kshd
+server is invoked by \fIinetd(8c)\fP when it receives a connection
+on the port indicated in /etc/inetd.conf.  A typical /etc/inetd.conf
+configuration line for \fIkrshd\fP might be:
+
+kshell	stream	tcp	nowait	root	/usr/local/sbin/kshd	kshd -5c
+
+When a service request is received, the following protocol is initiated:
+
+.IP 1) 
+Authentication is checked
+.IP 2)
+Check authorization via the access-control files \fI.k5login\fP, \fI.klogin\fP 
+and \fI.rhosts\fP in the user's home directory.
+.IP 3)
+A null byte is returned on the initial socket
+and the command line is passed to the normal login
+shell of the user.  The
+shell inherits the network connections established
+by
+.IR krshd .
+
+\fIKrshd\fP can be configured  by command-line arguments passed
+by \fIinetd(8)\fP.
+ The options are:
+
+.IP \fB\-5\fP 10
+Allow Kerberos5 authentication with the \fI.k5login\fP access control file
+to be trusted.  If this authentication system is used by the client and the
+authorization check is passed, then the user is allowed to log in.
+
+.IP \fB\-4\fP 
+Allow Kerberos4 authentication with the \fI.klogin\fP access control file
+to be trusted.  If this authentication system is used by the client and the
+authorization check is passed, then the user is allowed to log in.
+
+.IP \fB\-k\fP 
+Allow Kerberos5 and Kerberos4 as acceptable authentication
+mechanisms.  This is the same as including \fB\-4\fP and \fB\-5\fP.
+
+.IP \fB\-e\fP
+Require the client to encrypt the connection.  Only Kerberos5 clients
+support encryption.
+
+.IP \fB\-L\ variable\fP
+Carry through the current value of the specified variable into the
+environment of the child.  This option can be used to preserve up to
+four variables.
+
+
+.IP \fB\-c\fP 
+Require Kerberos5 clients to present a cryptographic
+checksum of initial connection information like the name of the user
+that the client is trying to access in the initial authenticator.
+This checksum provides additionl security by preventing an attacker
+from changing the initial connection information.  To benefit from
+this security, only Kerberos5 should be trusted; Kerberos4 and rhosts
+authentication do not include this checksum.  If this option is
+specified, older Kerberos5 clients that do not send a checksum in the
+authenticator will not be able to authenticate to this server.  This
+option is mutually exclusive with the \fB-i\fP option.
+
+	If neither the \fB-c\fP or \fB-i\fP options are specified,then
+checksums are validated if presented.  Since it is difficult to remove
+a checksum from an authenticator without making the authenticator
+invalid, this default mode is almost as significant of a security
+improvement as \fB-c\fP if new clients are used.  It has the additional
+advantage of backwards compatability with some clients.
+Unfortunately, clients before Kerberos V5, Beta5, generate invalid
+checksums; if these clients are used, the \fB-i\fP option must be
+used.
+
+.IP \fB\-i\fP 
+Ignore authenticator checksums if provided.  This option
+ignore authenticator checksusm presented by current Kerberos clients
+to protect initial connection information; it is the opposite of
+\fB-c\fP.  This option is provided because some older
+clients--particularly clients predating the release of Kerberos V5
+Beta5 (May 1995)--present bogus checksums that prevent Kerberos
+authentication from succeeding in the default mode.
+
+
+.PP
+If the \fB\-r\fP or \fB\-R\fP options are used, the client must
+connect from a privileged port.
+.PP
+\fIKrshd\fP supports six options which may be used for testing:
+
+.IP \fB\-S\ keytab\fP 10
+Set the \fIkeytab\fP file to use.
+
+.IP \fB\-M\ realm\fP
+Set the Kerberos realm to use.
+
+.IP \fB\-A\fP
+Don't allocate a reserved port for the stderr connection.
+
+.IP \fB\-P\ path\fP
+Use the argument to find the Kerberos binaries.  Normally a compiled
+in argument is used.
+
+.IP \fB\-D\ port \fP
+Run in standalone mode, listening on \fBport\fP.  The daemon will exit
+after one connection and will not background itself.
+
+.TP
+\fB\-w \fP[\fBip\fP|\fImaxhostlen\fP[\fB,\fP[\fBno\fP]\fBstriplocal\fP]]
+Controls the form of the remote hostname passed to login(1).
+Specifying \fBip\fP results in the numeric IP address always being
+passed to login(1).  Specifying a number, \fImaxhostlen\fP, sets the
+maximum length of the hostname passed to login(1) before it will be
+passed as a numeric IP address.  If \fImaxhostlen\fP is 0, then the
+system default, as determined by the utmp or utmpx structures, is
+used.  The \fBnostriplocal\fP and \fBstriplocal\fP options, which must
+be preceded by a comma, control whether or not the local host domain
+is stripped from the remote hostname.  By default, the equivalent of
+\fBstriplocal\fP is in effect.
+
+.SH DIAGNOSTICS
+Except for the last one listed below,
+all diagnostic messages
+are returned on the initial socket,
+after which any network connections are closed.
+An error is indicated by a leading byte with a value of
+1 (0 is returned in step 3 above upon successful completion
+of all the steps prior to the execution of the login shell).
+.PP
+.B ``locuser too long''
+.br
+The name of the user on the client's machine is
+longer than 16 characters.
+.PP
+.B ``remuser too long''
+.br
+The name of the user on the remote machine is
+longer than 16 characters.
+.PP
+.B ``command too long ''
+.br
+The command line passed exceeds the size of the argument
+list (as configured into the system).
+.PP
+.B ``Login incorrect.''
+.br
+No password file entry for the user name existed.
+.PP
+.B ``No remote directory.''
+.br
+The 
+.I chdir
+command to the home directory failed.
+.PP
+.B ``Permission denied.''
+.br
+The authentication procedure described above failed.
+.PP
+.B ``Can't make pipe.''
+.br
+The pipe needed for the 
+.BR stderr ,
+wasn't created.
+.PP
+.B ``Try again.''
+.br
+A
+.I fork
+by the server failed.
+.PP
+.B ``<shellname>: ...''
+.br
+The user's login shell could not be started.  This message is returned
+on the connection associated with the
+.BR stderr ,
+and is not preceded by a flag byte.
+.SH SEE ALSO
+rshd(8), rsh(1),
+rcmd(3)
+.SH BUGS
+A facility to allow all data exchanges to be encrypted should be
+present.
+.PP
+A more extensible protocol should be used.
diff --git a/mechglue/src/appl/bsd/login.M b/mechglue/src/appl/bsd/login.M
new file mode 100644
index 000000000..0fceb3529
--- /dev/null
+++ b/mechglue/src/appl/bsd/login.M
@@ -0,0 +1,97 @@
+.\"	login.1
+.\"
+.TH LOGIN 8
+.SH NAME
+login.krb5 \- kerberos enhanced login program
+.SH SYNOPSIS
+.B login.krb5
+[\fB\-p\fP] [\fB\-fFe\fP \fIusername\fP] 
+[\fB\-r | \-k | \-K | \-h \fP\fIhostname\fP]
+.SH DESCRIPTION
+.I login.krb5
+is a modification of the BSD login program which is used for two
+functions.  It is the sub-process used by krlogind and telnetd to
+initiate a user session and it is a replacement for the command-line
+login program which, when invoked with a password, acquires Kerberos
+tickets for the user.
+.PP
+.I login.krb5 
+will prompt for a username, or take one on the command line, as
+.I login.krb5 username
+and will then prompt for a password. This password will be used to
+acquire Kerberos Version 5 tickets and Kerberos Version 4 tickets (if
+possible.) It will also attempt to run
+.I aklog
+to get \fIAFS\fP tokens for the user. The version 5 tickets will be
+tested against a local 
+.I krb5.keytab
+if it is available, in order to verify the tickets, before letting the
+user in. However, if the password matches the entry in
+\fI/etc/passwd\fP the user will be unconditionally allowed (permitting
+use of the machine in case of network failure.)
+.SH OPTIONS
+.TP
+\fB\-p\fP
+preserve the current environment
+.TP
+\fB\-r\fP \fIhostname\fP
+pass hostname to rlogind.  Must be the last argument.
+.TP
+\fB\-h\fP \fIhostname\fP
+pass hostname to telnetd, etc.  Must be the last argument.
+.TP
+\fB\-k\fP \fIhostname\fP
+Use Kerberos V4 to login.  Must be the last argument.
+.TP
+\fB\-K\fP \fIhostname\fP
+Use Kerberos V4 to login.  Must be the last argument.
+.TP
+\fB\-f\fP \fIname\fP
+Perform pre-authenticated login, e.g., datakit, xterm, etc.; 
+allows preauthenticated login as root.
+.TP
+\fB\-F\fP \fIname\fP
+Perform pre-authenticated login, e.g., datakit, xterm, etc.; allows
+preauthenticated login as root.
+.TP
+\fB\-e\fP \fIname\fP
+Perform pre-authenticated, encrypted login.  Must do term negotiation.
+.SH CONFIGURATION
+.I login.krb5
+is also configured via 
+.I krb5.conf
+using the
+.I login
+stanza. A collection of options dealing with initial authentication are
+provided:
+.IP krb5_get_tickets
+Use password to get V5 tickets. Default value true.
+.IP krb4_get_tickets
+Use password to get V4 tickets. Default value false.
+.IP krb4_convert
+Use Kerberos conversion daemon to get V4 tickets. Default value
+false. If false, and krb4_get_tickets is true, then login will get
+the V5 tickets directly using the Kerberos V4 protocol directly.  
+This does not currently work with non MIT-V4 salt types
+(such as the AFS3 salt type.)  Note that if configuration parameter 
+is true, and the krb524d is not running, login will hang for 
+approximately a minute  under Solaris, 
+due to a Solaris socket emulation bug.
+.IP krb_run_aklog
+Attempt to run aklog. Default value false.
+.IP aklog_path
+Where to find it [not yet implemented.] Default value 
+.I $(prefix)/bin/aklog.
+.IP accept_passwd
+Don't accept plaintext passwords [not yet implemented]. Default value false.
+
+.SH DIAGNOSTICS
+All diagnostic messages are returned on the connection or tty
+associated with
+.BR stderr.
+.PP
+.SH SEE ALSO
+rlogind(8), rlogin(1), telnetd(8)
+.SH BUGS
+Should use a config file to select use of V5, V4, and AFS, as well as
+policy for startup.
diff --git a/mechglue/src/appl/bsd/login.c b/mechglue/src/appl/bsd/login.c
new file mode 100644
index 000000000..b49bababb
--- /dev/null
+++ b/mechglue/src/appl/bsd/login.c
@@ -0,0 +1,2502 @@
+/*
+ *	appl/bsd/login.c
+ */
+
+/*
+ * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)login.c	5.25 (Berkeley) 1/6/89 */
+
+/* The configuration, with defaults as listed, is of the form:
+   [login]
+   # login stanza
+   krb5_get_tickets = 1
+   # use password to get v5 tickets
+   krb4_get_tickets = 0
+   # use password to get v4 tickets
+   krb4_convert = 0
+   # use kerberos conversion daemon to get v4 tickets
+   krb_run_aklog = 0
+   # attempt to run aklog
+   aklog_path = $(prefix)/bin/aklog
+   # where to find it [not yet implemented]
+   accept_passwd = 0
+   # don't accept plaintext passwords [not yet implemented]
+*/
+#define KRB5_GET_TICKETS
+int login_krb5_get_tickets = 1;
+
+#ifdef KRB5_KRB4_COMPAT
+#define KRB4_GET_TICKETS
+int login_krb4_get_tickets = 0;
+#define KRB4_CONVERT
+int login_krb4_convert = 0;
+#define KRB_RUN_AKLOG
+int login_krb_run_aklog = 0;
+#endif /* KRB5_KRB4_COMPAT */
+
+int login_accept_passwd = 0;
+
+/*
+ * login [ name ]
+ * login -r hostname	(for rlogind)
+ * login -h hostname	(for telnetd, etc.)
+ * login -f name	(for pre-authenticated login: datakit, xterm, etc.,
+ *			 does allow preauthenticated login as root)
+ * login -F name	(for pre-authenticated login: datakit, xterm, etc.,
+ *			 allows preauthenticated login as root)
+ * login -e name	(for pre-authenticated encrypted, must do term
+ *			 negotiation)
+ * ifdef KRB4_KLOGIN
+ * login -k hostname (for Kerberos V4 rlogind with password access)
+ * login -K hostname (for Kerberos V4 rlogind with restricted access)
+ * endif KRB4_KLOGIN
+ *
+ * only one of: -r -f -e -k -K -F
+ * only one of: -r -h -k -K
+ */
+
+#include <libpty.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef OQUOTA
+#include <sys/quota.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <utmp.h>
+#include <signal.h>
+
+#include <assert.h>
+
+#ifdef HAVE_LASTLOG_H
+#include <lastlog.h>
+#endif
+
+#ifdef linux
+/* linux has V* but not C* in headers. Perhaps we shouldn't be
+ * initializing these values anyway -- tcgetattr *should* give
+ * them reasonable defaults... */
+#define NO_INIT_CC
+#endif
+
+#include <errno.h>
+#ifdef HAVE_TTYENT_H
+#include <ttyent.h>
+#endif
+#include <syslog.h>
+#include <stdio.h>
+#include <grp.h>
+#include <pwd.h>
+#include <string.h>
+
+#include <setjmp.h>
+#ifndef POSIX_SETJMP
+#undef sigjmp_buf
+#undef sigsetjmp
+#undef siglongjmp
+#define sigjmp_buf	jmp_buf
+#define sigsetjmp(j,s)	setjmp(j)
+#define siglongjmp	longjmp
+#endif
+
+#ifdef POSIX_SIGNALS
+typedef struct sigaction handler;
+#define handler_init(H,F)		(sigemptyset(&(H).sa_mask), \
+					 (H).sa_flags=0, \
+					 (H).sa_handler=(F))
+#define handler_swap(S,NEW,OLD)		sigaction(S, &NEW, &OLD)
+#define handler_set(S,OLD)		sigaction(S, &OLD, NULL)
+#else
+typedef sigtype (*handler)();
+#define handler_init(H,F)		((H) = (F))
+#define handler_swap(S,NEW,OLD)		((OLD) = signal ((S), (NEW)))
+#define handler_set(S,OLD)		(signal ((S), (OLD)))
+#endif
+
+
+#ifdef HAVE_SHADOW
+#include <shadow.h>
+#endif
+
+#ifdef KRB5_GET_TICKETS
+/* #include "krb5.h" */
+/* need k5-int.h to get ->profile from krb5_context */
+#include "k5-int.h"
+#include "com_err.h"
+#include "osconf.h"
+#endif /* KRB5_GET_TICKETS */
+
+#ifdef KRB4_KLOGIN
+/* support for running under v4 klogind, -k -K flags */
+#define KRB4
+#endif
+
+#if (defined(KRB4_GET_TICKETS) || defined(KRB4_CONVERT))
+/* support for prompting for v4 initial tickets */
+#define KRB4
+#endif
+
+#ifdef KRB4
+#include <krb.h>
+#include <netinet/in.h>
+#ifdef HAVE_KRB4_PROTO_H
+#include <krb4-proto.h>
+#endif
+#include <arpa/inet.h>
+#ifdef BIND_HACK
+#include <arpa/nameser.h>
+#include <arpa/resolv.h>
+#endif /* BIND_HACK */
+
+/* Hacks to maintain compatability with Athena libkrb*/
+#ifndef HAVE_KRB_SAVE_CREDENTIALS
+#define krb_save_credentials save_credentials
+#endif /*HAVE_KRB_SAVE_CREDENTIALS*/
+
+#ifndef HAVE_KRB_GET_ERR_TEXT
+
+static const char *krb_get_err_text(kerror)
+     int kerror;
+{
+    return krb_err_txt[kerror];
+}
+
+#endif /*HAVE_KRB_GET_ERR_TEXT*/
+#endif /* KRB4 */
+
+#ifndef __STDC__
+#ifndef volatile
+#define volatile
+#endif
+#endif
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#include "loginpaths.h"
+
+#ifdef POSIX_TERMIOS
+#include <termios.h>
+#ifndef CNUL
+#define CNUL (char) 0
+#endif
+
+#endif
+
+#ifdef _IBMR2
+#include <usersec.h>
+#include <sys/id.h>
+#endif
+
+#if defined(_AIX)
+#define PRIO_OFFSET 20
+#else
+#define PRIO_OFFSET 0
+#endif
+
+#if !defined(TAB3)
+#define TAB3 0
+#endif
+
+#define	TTYGRPNAME	"tty"		/* name of group to own ttys */
+
+#if defined(_PATH_MAILDIR)
+#define MAILDIR		_PATH_MAILDIR
+#else
+#define MAILDIR		"/usr/spool/mail"
+#endif
+#if defined(_PATH_NOLOGIN)
+#define NOLOGIN		_PATH_NOLOGIN
+#else
+#define NOLOGIN		"/etc/nologin"
+#endif
+#if defined(_PATH_LASTLOG)
+#define LASTLOG		_PATH_LASTLOG
+#else
+#define LASTLOG		"/usr/adm/lastlog"
+#endif
+#if defined(_PATH_BSHELL)
+#define BSHELL		_PATH_BSHELL
+#else
+#define BSHELL		"/bin/sh"
+#endif
+
+#if (defined(BSD) && (BSD >= 199103))	/* no /usr/ucb */
+#define QUOTAWARN	"/usr/bin/quota"
+#endif
+
+#define	MOTDFILE	"/etc/motd"
+#define	HUSHLOGIN	".hushlogin"
+
+#if !defined(OQUOTA) && !defined(QUOTAWARN)
+#define QUOTAWARN	"/usr/ucb/quota" /* warn user about quotas */
+#endif
+
+#ifndef NO_UT_HOST
+#ifndef UT_HOSTSIZE
+/* linux defines it directly in <utmp.h> */
+#define	UT_HOSTSIZE	sizeof(((struct utmp *)0)->ut_host)
+#endif /* UT_HOSTSIZE */
+#endif
+#ifndef UT_NAMESIZE
+/* linux defines it directly in <utmp.h> */
+#define	UT_NAMESIZE	sizeof(((struct utmp *)0)->ut_name)
+#endif
+
+#ifndef HAVE_SETPRIORITY
+/* if we don't have it, punt it cleanly */
+#define setpriority(which,who,prio)
+#endif /* HAVE_SETPRIORITY */
+
+#define MAXENVIRON	32
+
+#ifdef NEED_SETENV
+extern int setenv(char *, char *, int);
+#endif
+
+/*
+ * This bounds the time given to login.  Not a define so it can
+ * be patched on machines where it's too small.
+ */
+int	timeout = 300;
+
+#if 0
+char term[64], *hostname, *username;
+#else
+char term[64], *username;
+#endif
+
+
+
+#ifdef KRB4
+#define KRB_ENVIRON	"KRBTKFILE"	/* Ticket file environment variable */
+#define KRB_TK_DIR	"/tmp/tkt_"	/* Where to put the ticket */
+#endif /* KRB4_GET_TICKETS */
+
+#if defined(KRB4_GET_TICKETS) || defined(KRB5_GET_TICKETS)
+#define MAXPWSIZE	128		/* Biggest string accepted for KRB4
+					   passsword */
+#endif
+
+#if defined(__SVR4) || defined(sgi)
+#define NO_MOTD
+#define NO_MAILCHECK
+#endif
+
+char *getenv();
+void dofork(void);
+
+char *stypeof(char *);
+void term_init(int);
+int doremotelogin(char *), do_krb_login(char *, int), rootterm(char *);
+void lgetstr(char *, int, char *), getloginname(void), checknologin(void);
+void dolastlog(char *, int, char *), motd(void), check_mail(void);
+void sleepexit(int);
+
+#ifndef HAVE_STRSAVE
+char * strsave(char *);
+#endif
+
+typedef krb5_sigtype sigtype;
+
+sigtype timedout(int);
+
+
+#ifndef HAVE_INITGROUPS
+static int initgroups(char* name, gid_t basegid) {
+    gid_t others[NGROUPS_MAX+1];
+    int ngrps;
+
+    others[0] = basegid;
+    ngrps = getgroups(NGROUPS_MAX, others+1);
+    return setgroups(ngrps+1, others);
+}
+#endif
+
+static struct login_confs {
+    char *flagname;
+    int *flag;
+} login_conf_set[] = {
+#ifdef KRB5_GET_TICKETS
+    {"krb5_get_tickets", &login_krb5_get_tickets},
+#endif
+#ifdef KRB5_KRB4_COMPAT
+    {"krb4_get_tickets", &login_krb4_get_tickets},
+    {"krb4_convert", &login_krb4_convert},
+    {"krb4_run_aklog", &login_krb_run_aklog},
+#endif /* KRB5_KRB4_COMPAT */
+};
+
+static char *conf_yes[] = {
+    "y", "yes", "true", "t", "1", "on",
+    0
+};
+
+static char *conf_no[] = {
+    "n", "no", "false", "nil", "0", "off",
+    0
+};
+
+/* 1 = true, 0 = false, -1 = ambiguous */
+static int conf_affirmative(s)
+     char *s;
+{
+    char **p;
+
+    for(p=conf_yes; *p; p++) {
+	if (!strcasecmp(*p,s))
+	    return 1;
+    }
+
+    for(p=conf_no; *p; p++) {
+	if (!strcasecmp(*p,s))
+	    return 0;
+    }
+
+    /* ambiguous */
+    return -1;
+}
+
+#ifdef KRB5_GET_TICKETS
+krb5_data tgtname = {
+    0,
+    KRB5_TGS_NAME_SIZE,
+    KRB5_TGS_NAME
+};
+#endif
+
+/* get flags (listed above) from the profile */
+static void login_get_kconf(k)
+     krb5_context k;
+{
+    int i, max_i;
+    const char* kconf_names[3];
+    char **kconf_val;
+    int retval;
+
+    max_i = sizeof(login_conf_set)/sizeof(struct login_confs);
+    for (i = 0; i<max_i; i++) {
+	kconf_names[0] = "login";
+	kconf_names[1] = login_conf_set[i].flagname;
+	kconf_names[2] = 0;
+	retval = profile_get_values(k->profile, 
+				    kconf_names, &kconf_val);
+	if (retval) {
+	    /* ignore most (all?) errors */
+	} else if (kconf_val && *kconf_val) {
+	    switch(conf_affirmative(*kconf_val)) {
+	    case 1:
+		*login_conf_set[i].flag = 1;
+		break;
+	    case 0:
+		*login_conf_set[i].flag = 0;
+		break;
+	    default:
+	    case -1:
+		com_err("login/kconf", 0,
+			"invalid flag value %s for flag %s",
+			*kconf_val, kconf_names[1]);
+		break;
+	    }
+	}
+    }
+}
+
+/* UNIX password support */
+
+struct passwd *pwd;
+static char *salt;
+
+#ifdef HAVE_SHADOW
+struct spwd *spwd;
+#endif
+
+static void lookup_user (name)
+    char *name;
+{
+    pwd = getpwnam (name);
+    salt = pwd ? pwd->pw_passwd : "xx";
+#ifdef HAVE_SHADOW
+    spwd = getspnam (name);
+    if (spwd)
+	salt = spwd->sp_pwdp;
+#endif
+}
+
+static int unix_needs_passwd ()
+{
+#ifdef HAVE_SHADOW
+    if (spwd)
+	return spwd->sp_pwdp[0] != 0;
+#endif
+    if (pwd)
+	return pwd->pw_passwd[0] != 0;
+    return 1;
+}
+
+static int unix_passwd_okay (pass)
+    char *pass;
+{
+    char user_pwcopy[9], *namep;
+    char *crypt ();
+
+    assert (pwd != 0);
+
+    /* copy the first 8 chars of the password for unix crypt */
+    strncpy(user_pwcopy, pass, sizeof(user_pwcopy));
+    user_pwcopy[sizeof(user_pwcopy) - 1]='\0';
+    namep = crypt(user_pwcopy, salt);
+    memset (user_pwcopy, 0, sizeof(user_pwcopy));
+    /* ... and wipe the copy now that we have the string */
+
+    /* verify the local password string */
+#ifdef HAVE_SHADOW
+    if (spwd)
+	return !strcmp(namep, spwd->sp_pwdp);
+#endif
+    return !strcmp (namep, pwd->pw_passwd);
+}
+
+/* Kerberos support */
+#ifdef KRB5_GET_TICKETS
+krb5_context kcontext;
+krb5_ccache ccache;
+krb5_creds my_creds;
+static int got_v5_tickets, forwarded_v5_tickets;
+char ccfile[MAXPATHLEN+6];	/* FILE:path+\0 */
+int krbflag;			/* set if tickets have been obtained */
+#endif /* KRB5_GET_TICKETS */
+
+#ifdef KRB4_GET_TICKETS
+static int got_v4_tickets;
+AUTH_DAT *kdata = (AUTH_DAT *) NULL;
+char tkfile[MAXPATHLEN];
+#endif
+
+#ifdef KRB4_GET_TICKETS
+static void k_init (ttyn, realm)
+    char *ttyn;
+    char *realm;
+#else
+void k_init (ttyn)
+    char *ttyn;
+#endif
+{
+#ifdef KRB5_GET_TICKETS
+    krb5_error_code retval;
+    
+    retval = krb5_init_secure_context(&kcontext);
+    if (retval) {
+	com_err("login", retval, "while initializing krb5");
+	exit(1);
+    }
+
+    login_get_kconf(kcontext);
+
+    /* Set up the credential cache environment variable */
+    if (!getenv(KRB5_ENV_CCNAME)) {
+	sprintf(ccfile, "FILE:/tmp/krb5cc_p%ld", (long) getpid());
+	setenv(KRB5_ENV_CCNAME, ccfile, 1);
+	krb5_cc_set_default_name(kcontext, ccfile);
+	unlink(ccfile+strlen("FILE:"));
+    } else {
+	/* note it correctly */
+	strncpy(ccfile, getenv(KRB5_ENV_CCNAME), sizeof(ccfile));
+	ccfile[sizeof(ccfile) - 1] = '\0';
+    }
+#endif
+
+#ifdef KRB4_GET_TICKETS
+    if (krb_get_lrealm(realm, 1) != KSUCCESS) {
+	strncpy(realm, KRB_REALM, sizeof(realm));
+	realm[sizeof(realm) - 1] = '\0';
+    }
+    if (login_krb4_get_tickets || login_krb4_convert) {
+	/* Set up the ticket file environment variable */
+	strncpy(tkfile, KRB_TK_DIR, sizeof(tkfile));
+	tkfile[sizeof(tkfile) - 1] = '\0';
+	strncat(tkfile, strrchr(ttyn, '/')+1,
+		sizeof(tkfile) - strlen(tkfile));
+	(void) unlink (tkfile);
+	setenv(KRB_ENVIRON, tkfile, 1);
+    }
+#endif
+
+#ifdef BIND_HACK
+    /* Set name server timeout to be reasonable,
+       so that people don't take 5 minutes to
+       log in.  Can you say abstraction violation? */
+    _res.retrans = 1;
+#endif /* BIND_HACK */
+}
+
+#ifdef KRB5_GET_TICKETS
+static int k5_get_password (user_pwstring, pwsize)
+    char *user_pwstring;
+    unsigned int pwsize;
+{
+    krb5_error_code code;
+    char prompt[255];			
+    sprintf(prompt,"Password for %s", username);
+
+    /* reduce opportunities to be swapped out */
+    code = krb5_read_password(kcontext, prompt, 0, user_pwstring, &pwsize);
+    if (code || pwsize == 0) {
+	fprintf(stderr, "Error while reading password for '%s'\n", username);
+	/* reading password failed... */
+	return 0;
+    }
+    if (pwsize == 0) {
+	fprintf(stderr, "No password read\n");
+	/* reading password failed... */
+	return 0;
+    }
+    return 1;
+}
+
+static int try_krb5 (me_p, pass)
+    krb5_principal *me_p;
+    char *pass;
+{
+    krb5_error_code code;
+    krb5_principal me;
+
+    code = krb5_parse_name(kcontext, username, &me);
+    if (code) {
+	com_err ("login", code, "when parsing name %s",username);
+	return 0;
+    }
+
+    *me_p = me;
+
+    code = krb5_get_init_creds_password(kcontext, &my_creds, me, pass,
+					krb5_prompter_posix, NULL,
+					0, NULL, NULL);
+    if (code) {
+	if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+	    fprintf (stderr,
+		     "%s: Kerberos password incorrect\n", 
+		     username);
+	else
+	    com_err ("login", code,
+		     "while getting initial credentials");
+	return 0;
+    }
+
+    krbflag = got_v5_tickets = 1;
+
+    return 1;
+}
+
+static int have_v5_tickets (me)
+    krb5_principal *me;
+{
+    if (krb5_cc_default (kcontext, &ccache))
+	return 0;
+    if (krb5_cc_get_principal (kcontext, ccache, me)) {
+	krb5_cc_close (kcontext, ccache);
+	return 0;
+    }
+    krbflag = 1;
+    return 1;
+}
+#endif /* KRB5_GET_TICKETS */
+
+#ifdef KRB4_CONVERT
+static int
+try_convert524(kctx, me, use_ccache)
+    krb5_context kctx;
+    krb5_principal me;
+    int use_ccache;
+{
+    krb5_principal kpcserver;
+    krb5_error_code kpccode;
+    int kpcval;
+    krb5_creds increds, *v5creds;
+    CREDENTIALS v4creds;
+
+
+    /* If we have forwarded v5 tickets, retrieve the credentials from
+     * the cache; otherwise, the v5 credentials are in my_creds.
+     */
+    if (use_ccache) {
+	/* cc->ccache, already set up */
+	/* client->me, already set up */
+	kpccode = krb5_build_principal(kctx, &kpcserver, 
+				       krb5_princ_realm(kctx, me)->length,
+				       krb5_princ_realm(kctx, me)->data,
+				       "krbtgt",
+				       krb5_princ_realm(kctx, me)->data,
+				       NULL);
+	if (kpccode) {
+	    com_err("login/v4", kpccode,
+		    "while creating service principal name");
+	    return 0;
+	}
+
+	memset((char *) &increds, 0, sizeof(increds));
+	increds.client = me;
+	increds.server = kpcserver;
+	increds.times.endtime = 0;
+	increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+	kpccode = krb5_get_credentials(kctx, 0, ccache,
+				       &increds, &v5creds);
+	krb5_free_principal(kctx, kpcserver);
+	increds.server = NULL;
+	if (kpccode) {
+	    com_err("login/v4", kpccode, "getting V5 credentials");
+	    return 0;
+	}
+
+	kpccode = krb524_convert_creds_kdc(kctx, v5creds, &v4creds);
+	krb5_free_creds(kctx, v5creds);
+    } else
+	kpccode = krb524_convert_creds_kdc(kctx, &my_creds, &v4creds);
+    if (kpccode) {
+	com_err("login/v4", kpccode, "converting to V4 credentials");
+	return 0;
+    }
+    /* this is stolen from the v4 kinit */
+    /* initialize ticket cache */
+    if ((kpcval = in_tkt(v4creds.pname,v4creds.pinst)
+	 != KSUCCESS)) {
+	com_err("login/v4", kpcval,
+		"trying to create the V4 ticket file");
+	return 0;
+    }
+    /* stash ticket, session key, etc. for future use */
+    if ((kpcval = krb_save_credentials(v4creds.service,
+				       v4creds.instance,
+				       v4creds.realm, 
+				       v4creds.session,
+				       v4creds.lifetime,
+				       v4creds.kvno,
+				       &(v4creds.ticket_st), 
+				       v4creds.issue_date))) {
+	com_err("login/v4", kpcval,
+		"trying to save the V4 ticket");
+	return 0;
+    }
+    got_v4_tickets = 1;
+    strncpy(tkfile, tkt_string(), sizeof(tkfile));
+    tkfile[sizeof(tkfile) - 1] = '\0';
+    return 1;
+}
+#endif
+
+#ifdef KRB4_GET_TICKETS
+static int
+try_krb4 (user_pwstring, realm)
+    char *user_pwstring;
+    char *realm;
+{
+    int krbval, kpass_ok = 0;
+
+    krbval = krb_get_pw_in_tkt(username, "", realm,
+			       "krbtgt", realm, 
+			       DEFAULT_TKT_LIFE,
+			       user_pwstring);
+
+    switch (krbval) {
+    case INTK_OK:
+	kpass_ok = 1;
+	krbflag = 1;
+	strncpy(tkfile, tkt_string(), sizeof(tkfile));
+	tkfile[sizeof(tkfile) - 1] = '\0';
+	break;	
+	/* These errors should be silent */
+	/* So the Kerberos database can't be probed */
+    case KDC_NULL_KEY:
+    case KDC_PR_UNKNOWN:
+    case INTK_BADPW:
+    case KDC_PR_N_UNIQUE:
+    case -1:
+	break;
+#if 0 /* I want to see where INTK_W_NOTALL comes from before letting
+	 kpass_ok be set in that case.  KR  */
+	/* These should be printed but are not fatal */
+    case INTK_W_NOTALL:
+	krbflag = 1;
+	kpass_ok = 1;
+	fprintf(stderr, "Kerberos error: %s\n",
+		krb_get_err_text(krbval));
+	break;
+#endif
+    default:
+	fprintf(stderr, "Kerberos error: %s\n",
+		krb_get_err_text(krbval));
+	break;
+    }
+    got_v4_tickets = kpass_ok;
+    return kpass_ok;
+}
+#endif /* KRB4_GET_TICKETS */
+
+/* Kerberos ticket-handling routines */
+
+#ifdef KRB4_GET_TICKETS
+/* call already conditionalized on login_krb4_get_tickets */
+/*
+ * Verify the Kerberos ticket-granting ticket just retrieved for the
+ * user.  If the Kerberos server doesn't respond, assume the user is
+ * trying to fake us out (since we DID just get a TGT from what is
+ * supposedly our KDC).  If the rcmd.<host> service is unknown (i.e.,
+ * the local srvtab doesn't have it), let her in.
+ *
+ * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
+ */
+static int verify_krb_v4_tgt (realm)
+    char *realm;
+{
+    char hostname[MAXHOSTNAMELEN], phost[BUFSIZ];
+    struct hostent *hp;
+    KTEXT_ST ticket;
+    AUTH_DAT authdata;
+    unsigned long addr;
+    static /*const*/ char rcmd_str[] = "rcmd";
+#if 0
+    char key[8];
+#endif
+    int krbval, retval, have_keys;
+
+    if (gethostname(hostname, sizeof(hostname)) == -1) {
+	perror ("cannot retrieve local hostname");
+	return -1;
+    }
+    strncpy (phost, krb_get_phost (hostname), sizeof (phost));
+    phost[sizeof(phost)-1] = 0;
+    hp = gethostbyname (hostname);
+    if (!hp) {
+	perror ("cannot retrieve local host address");
+	return -1;
+    }
+    memcpy ((char *) &addr, (char *)hp->h_addr, sizeof (addr));
+    /* Do we have rcmd.<host> keys? */
+#if 0 /* Be paranoid.  If srvtab exists, assume it must contain the
+	 right key.  The more paranoid mode also helps avoid a
+	 possible DNS spoofing issue.  */
+    have_keys = read_service_key (rcmd_str, phost, realm, 0, KEYFILE, key)
+	? 0 : 1;
+    memset (key, 0, sizeof (key));
+#else
+    have_keys = 0 == access (KEYFILE, F_OK);
+#endif
+    krbval = krb_mk_req (&ticket, rcmd_str, phost, realm, 0);
+    if (krbval == KDC_PR_UNKNOWN) {
+	/*
+	 * Our rcmd.<host> principal isn't known -- just assume valid
+	 * for now?  This is one case that the user _could_ fake out.
+	 */
+	if (have_keys)
+	    return -1;
+	else
+	    return 0;
+    }
+    else if (krbval != KSUCCESS) {
+	printf ("Unable to verify Kerberos TGT: %s\n", 
+		krb_get_err_text(krbval));
+#ifndef SYSLOG42
+	syslog (LOG_NOTICE|LOG_AUTH, "Kerberos TGT bad: %s",
+		krb_get_err_text(krbval));
+#endif
+	return -1;
+    }
+    /* got ticket, try to use it */
+    krbval = krb_rd_req (&ticket, rcmd_str, phost, addr, &authdata, "");
+    if (krbval != KSUCCESS) {
+	if (krbval == RD_AP_UNDEC && !have_keys)
+	    retval = 0;
+	else {
+	    retval = -1;
+	    printf ("Unable to verify `rcmd' ticket: %s\n",
+		    krb_get_err_text(krbval));
+	}
+#ifndef SYSLOG42
+	syslog (LOG_NOTICE|LOG_AUTH, "can't verify rcmd ticket: %s;%s\n",
+		krb_get_err_text(krbval),
+		retval
+		? "srvtab found, assuming failure"
+		: "no srvtab found, assuming success");
+#endif
+	goto EGRESS;
+    }
+    /*
+     * The rcmd.<host> ticket has been received _and_ verified.
+     */
+    retval = 1;
+    /* do cleanup and return */
+EGRESS:
+    memset (&ticket, 0, sizeof (ticket));
+    memset (&authdata, 0, sizeof (authdata));
+    return retval;
+}
+#endif /* KRB4_GET_TICKETS */
+
+static void destroy_tickets()
+{
+#ifdef KRB5_GET_TICKETS
+    krb5_ccache cache;
+
+    if (login_krb5_get_tickets) {
+	if(!krb5_cc_default(kcontext, &cache))
+	  krb5_cc_destroy (kcontext, cache);
+    }
+#endif
+#ifdef KRB4_GET_TICKETS
+    if (login_krb4_get_tickets || login_krb4_convert)
+	dest_tkt();
+#endif /* KRB4_GET_TICKETS */
+}
+
+/* AFS support routines */
+#ifdef SETPAG
+
+int pagflag = 0;			/* true if setpag() has been called */
+
+/* This doesn't seem to be declared in the AFS header files.  */
+extern ktc_ForgetAllTokens (), setpag ();
+
+#ifdef SIGSYS
+static sigjmp_buf setpag_buf;
+
+static sigtype sigsys ()
+{
+    siglongjmp(setpag_buf, 1);
+}
+
+static int try_afscall (scall)
+	int (*scall)();
+{
+    handler sa, osa;
+    volatile int retval = 0;
+
+    (void) &retval;
+    handler_init (sa, sigsys);
+    handler_swap (SIGSYS, sa, osa);
+    if (sigsetjmp(setpag_buf, 1) == 0) {
+	(*scall)();
+	retval = 1;
+    }
+    handler_set (SIGSYS, osa);
+    return retval;
+}
+
+#define try_setpag()	try_afscall(setpag)
+#define try_unlog()	try_afscall(ktc_ForgetAllTokens)
+#else
+#define try_setpag()	(setpag() == 0)
+#define try_unlog()	(ktc_ForgetAllTokens() == 0)
+#endif /* SIGSYS */
+#endif /* SETPAG */
+
+static void
+afs_login ()
+{
+#if defined(KRB4_GET_TICKETS) && defined(SETPAG)
+    if (login_krb4_get_tickets && pwd->pw_uid) {
+	/* Only reset the pag for non-root users. */
+	/* This allows root to become anything. */
+	pagflag = try_setpag ();
+    }
+#endif
+#ifdef KRB_RUN_AKLOG
+    if (got_v4_tickets && login_krb_run_aklog) {
+	/* KPROGDIR is $(prefix)/bin */
+	char aklog_path[MAXPATHLEN];
+	struct stat st;
+	/* construct the name */
+	/* get this from profile later */
+	aklog_path[sizeof(aklog_path) - 1] = '\0';
+	strncpy (aklog_path, KPROGDIR, sizeof(aklog_path) - 1);
+	strncat (aklog_path, "/aklog", sizeof(aklog_path) - 1 - strlen(aklog_path));
+	/* only run it if we can find it */
+	if (stat (aklog_path, &st) == 0) {
+	    system(aklog_path);
+	}
+    }
+#endif /* KRB_RUN_AKLOG */
+}
+
+static void
+afs_cleanup ()
+{
+#ifdef SETPAG
+    if (pagflag)
+      try_unlog ();
+#endif
+}
+
+/* Main routines */
+#define EXCL_AUTH_TEST if (rflag || kflag || Kflag || eflag || fflag ) { \
+    fprintf(stderr, \
+	    "login: only one of -r, -k, -K, -e, -F, and -f allowed.\n"); \
+    exit(1); \
+}
+
+#define EXCL_HOST_TEST if (rflag || kflag || Kflag || hflag) { \
+    fprintf(stderr, \
+	    "login: only one of -r, -k, -K, and -h allowed.\n"); \
+    exit(1); \
+}
+
+#if defined(HAVE_ETC_ENVIRONMENT) || defined(HAVE_ETC_TIMEZONE)
+static void
+read_env_vars_from_file (filename)
+    char *filename;
+{
+    FILE *fp;
+    char *p, *eq;
+    char tbuf[MAXPATHLEN+2];
+
+    if ((fp = fopen(filename, "r")) != NULL) {
+	while (fgets(tbuf, sizeof(tbuf), fp)) {
+	    if (tbuf[0] == '#')
+		continue;
+	    eq = strchr(tbuf, '=');
+	    if (eq == 0)
+		continue;
+	    p = strchr (tbuf, '\n');
+	    if (p)
+		*p = 0;
+	    *eq++ = 0;
+	    /* Don't override, in case -p was used.  */
+	    setenv (tbuf, eq, 0);
+	}
+	fclose(fp);
+    }
+}
+#endif
+
+static void
+log_repeated_failures (tty, hostname)
+    char *tty, *hostname;
+{
+    if (hostname) {
+#ifdef UT_HOSTSIZE
+	syslog(LOG_ERR,
+	       "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
+	       tty, UT_HOSTSIZE, hostname, UT_NAMESIZE,
+	       username);
+#else
+	syslog(LOG_ERR,
+	       "REPEATED LOGIN FAILURES ON %s FROM %s, %.*s",
+	       tty, hostname, UT_NAMESIZE,
+	       username);
+#endif
+    } else {
+	syslog(LOG_ERR,
+	       "REPEATED LOGIN FAILURES ON %s, %.*s",
+	       tty, UT_NAMESIZE, username);
+    }
+}
+
+int main(argc, argv)
+     int argc;
+     char **argv;
+{
+    extern int optind;
+    extern char *optarg, **environ;
+    struct group *gr;
+    int ch;
+    char *p;
+    int fflag, hflag, pflag, rflag, cnt;
+    int kflag, Kflag, eflag;
+    int quietlog, passwd_req, ioctlval;
+    char *domain, **envinit, *ttyn, *tty;
+    char tbuf[MAXPATHLEN + 2];
+    char *ttyname(), *crypt(), *getpass();
+    time_t login_time;
+    int retval;
+    int rewrite_ccache = 1; /*try to write out ccache*/
+#ifdef KRB5_GET_TICKETS
+    krb5_principal me;
+    krb5_creds save_v5creds;
+    krb5_ccache xtra_creds = NULL;
+#endif
+#ifdef KRB4_GET_TICKETS
+    CREDENTIALS save_v4creds;
+    char realm[REALM_SZ];
+#endif
+    char *ccname = 0;   /* name of forwarded cache */
+    char *tz = 0;
+    char *hostname = 0;
+
+    off_t lseek();
+    handler sa;
+
+    handler_init (sa, timedout);
+    handler_set (SIGALRM, sa);
+    (void)alarm((u_int)timeout);
+
+    handler_init (sa, SIG_IGN);
+    handler_set (SIGQUIT, sa);
+    handler_set (SIGINT, sa);
+    setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+#ifdef OQUOTA
+    (void)quota(Q_SETUID, 0, 0, 0);
+#endif
+
+    /*
+     * -p is used by getty to tell login not to destroy the environment
+     * -r is used by rlogind to cause the autologin protocol;
+     * -f is used to skip a second login authentication 
+     * -F is used to skip a second login authentication, allows login as root 
+     * -e is used to skip a second login authentication, but allows
+     * 	login as root.
+     * -h is used by other servers to pass the name of the
+     * remote host to login so that it may be placed in utmp and wtmp
+     * -k is used by klogind to cause the Kerberos V4 autologin protocol;
+     * -K is used by klogind to cause the Kerberos V4 autologin
+     *    protocol with restricted access.
+     */
+    (void)gethostname(tbuf, sizeof(tbuf));
+    domain = strchr(tbuf, '.');
+
+    fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
+    passwd_req = 1;
+    while ((ch = getopt(argc, argv, "Ffeh:pr:k:K:")) != -1)
+	switch (ch) {
+	case 'f':
+	    EXCL_AUTH_TEST;
+	    fflag = 1;
+	    break;
+	case 'F':
+	    EXCL_AUTH_TEST;
+	    fflag = 1;
+	    break;
+	case 'h':
+	    EXCL_HOST_TEST;
+	    if (getuid()) {
+		fprintf(stderr,
+			"login: -h for super-user only.\n");
+		exit(1);
+	    }
+	    hflag = 1;
+	    if (domain && (p = strchr(optarg, '.')) && strcmp(p, domain) == 0)
+		*p = 0;
+	    hostname = optarg;
+	    break;
+	case 'p':
+	    pflag = 1;
+	    break;
+	case 'r':
+	    EXCL_AUTH_TEST;
+	    EXCL_HOST_TEST;
+	    if (getuid()) {
+		fprintf(stderr,
+			"login: -r for super-user only.\n");
+		exit(1);
+	    }
+	    /* "-r hostname" must be last args */
+	    if (optind != argc) {
+		fprintf(stderr, "Syntax error.\n");
+		exit(1);
+	    }
+	    rflag = 1;
+	    passwd_req = (doremotelogin(optarg) == -1);
+	    if (domain && (p = strchr(optarg, '.')) && !strcmp(p, domain))
+		*p = '\0';
+	    hostname = optarg;
+	    break;
+#ifdef KRB4_KLOGIN
+	case 'k':
+	case 'K':
+	    EXCL_AUTH_TEST;
+	    EXCL_HOST_TEST;
+	    if (getuid()) {
+		fprintf(stderr,
+			"login: -%c for super-user only.\n", ch);
+		exit(1);
+	    }
+	    /* "-k hostname" must be last args */
+	    if (optind != argc) {
+		fprintf(stderr, "Syntax error.\n");
+		exit(1);
+	    }
+	    if (ch == 'K')
+		Kflag = 1;
+	    else
+		kflag = 1;
+	    passwd_req = (do_krb_login(optarg, Kflag ? 1 : 0) == -1);
+	    if (domain && 
+		(p = strchr(optarg, '.')) &&
+		(!strcmp(p, domain))) 
+		*p = '\0';
+	    hostname = optarg;
+	    break;
+#endif /* KRB4_KLOGIN */
+	case 'e':
+	    EXCL_AUTH_TEST;
+	    if (getuid()) {
+		fprintf(stderr,
+			"login: -e for super-user only.\n");
+		exit(1);
+	    }
+	    eflag = 1;
+	    passwd_req = 0;
+	    break;
+	case '?':
+	default:
+	    fprintf(stderr, "usage: login [-fp] [username]\n");
+	    exit(1);
+	}
+    argc -= optind;
+    argv += optind;
+    /* Throw away too-long names, they can't be usernames.  */
+    if (*argv) {
+	if (strlen (*argv) <= UT_NAMESIZE)
+	    username = *argv;
+	else
+	    fprintf (stderr, "login name '%s' too long\n", *argv);
+    }
+
+#if !defined(POSIX_TERMIOS) && defined(TIOCLSET)
+    ioctlval = 0;
+    /* Only do this we we're not using POSIX_TERMIOS */
+    (void)ioctl(0, TIOCLSET, (char *)&ioctlval);
+#endif
+	
+#ifdef TIOCNXCL
+    (void)ioctl(0, TIOCNXCL, (char *)0);
+#endif
+	
+    ioctlval = fcntl(0, F_GETFL);
+#ifdef O_NONBLOCK
+    ioctlval &= ~O_NONBLOCK;
+#endif
+#ifdef O_NDELAY
+    ioctlval &= ~O_NDELAY;
+#endif
+    (void)fcntl(0, F_SETFL, ioctlval);
+
+	/*
+	 * If talking to an rlogin process, propagate the terminal type and
+	 * baud rate across the network.
+	 */
+    if (eflag) {
+	lgetstr(term, sizeof(term), "Terminal type");
+    } else if (!(kflag || Kflag)) {/* Preserve terminal if not read over net */
+	if (getenv("TERM")) {
+	    strncpy(term, getenv("TERM"), sizeof(term));
+	    term[sizeof(term) - 1] = '\0';
+	}
+    }
+	
+    term_init (rflag || kflag || Kflag || eflag);
+
+    for (cnt = getdtablesize(); cnt > 2; cnt--)
+	(void) close(cnt);
+
+    ttyn = ttyname(0);
+    if (ttyn == NULL || *ttyn == '\0')
+	ttyn = "/dev/tty??";
+
+    /* This allows for tty names of the form /dev/pts/4 as well */
+    if ((tty = strchr(ttyn, '/')) && (tty = strchr(tty+1, '/')))
+	++tty;
+    else
+	tty = ttyn;
+
+#ifndef LOG_ODELAY /* 4.2 syslog ... */                      
+    openlog("login", 0);
+#else
+    openlog("login", LOG_ODELAY, LOG_AUTH);
+#endif /* 4.2 syslog */
+
+/******* begin askpw *******/
+    /* overall:
+       ask for username if we don't have it already
+       look it up in local pw or shadow file (to get crypt string)
+       ask for password
+       try and get v4, v5 tickets with it
+       try and use the tickets against the local srvtab
+       if the password matches, always let them in
+       if the ticket decrypts, let them in.
+       v5 needs to work, does v4?
+    */
+
+#ifdef KRB4_GET_TICKETS
+    k_init (ttyn, realm);
+#else
+    k_init (ttyn);
+#endif
+
+    for (cnt = 0;; username = NULL) {
+#ifdef KRB5_GET_TICKETS
+	int kpass_ok, lpass_ok;
+	char user_pwstring[MAXPWSIZE];
+#endif /* KRB5_GET_TICKETS */
+
+	if (username == NULL) {
+	    fflag = 0;
+	    getloginname();
+	}
+
+	lookup_user(username);	/* sets pwd */
+
+	/* if user not super-user, check for disabled logins */
+	if (pwd == NULL || pwd->pw_uid)
+	    checknologin();
+
+	/*
+	 * Allows automatic login by root.
+	 * If not invoked by root, disallow if the uid's differ.
+	 */
+
+	if (fflag && pwd) {
+	    int uid = (int) getuid();
+	    passwd_req = (uid && uid != pwd->pw_uid);
+	}
+
+	/*
+	 * If no remote login authentication and a password exists
+	 * for this user, prompt for one and verify it.
+	 */
+	if (!passwd_req)
+	    break;
+
+	if (!unix_needs_passwd())
+	    break;
+
+	/* we have several sets of code:
+	   1) get v5 tickets alone -DKRB5_GET_TICKETS
+	   2) get v4 tickets alone [** don't! only get them *with* v5 **]
+	   3) get both tickets -DKRB5_GET_TICKETS -DKRB4_GET_TICKETS
+	   3a) use krb524 calls to get the v4 tickets -DKRB4_CONVERT plus (3).
+	   4) get no tickets and use the password file (none of thes defined.)
+		   
+	   Likewise we need to (optionally?) test these tickets against
+	   local srvtabs.
+	*/
+
+#ifdef KRB5_GET_TICKETS
+	if (login_krb5_get_tickets) {
+	    /* rename these to something more verbose */
+	    kpass_ok = 0;
+	    lpass_ok = 0;
+
+	    setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
+	    if (! k5_get_password(user_pwstring, sizeof (user_pwstring))) {
+		goto bad_login;
+	    }
+
+	    /* now that we have the password, we've obscured things
+	       sufficiently, and can avoid trying tickets */
+	    if (!pwd)
+		goto bad_login;
+
+	    lpass_ok = unix_passwd_okay(user_pwstring);
+
+	    if (pwd->pw_uid != 0) { /* Don't get tickets for root */
+		try_krb5(&me, user_pwstring);
+
+#ifdef KRB4_GET_TICKETS
+		if (login_krb4_get_tickets &&
+		    !(got_v5_tickets && login_krb4_convert))
+		    try_krb4(user_pwstring, realm);
+#endif
+		krbflag = (got_v5_tickets
+#ifdef KRB4_GET_TICKETS
+			   || got_v4_tickets
+#endif
+			   );
+		memset (user_pwstring, 0, sizeof(user_pwstring));
+		/* password wiped, so we can relax */
+		setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+	    } else {
+		memset(user_pwstring, 0, sizeof(user_pwstring));
+		setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+	    }
+
+	    /* Policy: If local password is good, user is good.
+	       We really can't trust the Kerberos password,
+	       because somebody on the net could spoof the
+	       Kerberos server (not easy, but possible).
+	       Some sites might want to use it anyways, in
+	       which case they should change this line
+	       to:
+	       if (kpass_ok)
+	    */
+
+	    if (lpass_ok)
+		break;
+
+	    if (got_v5_tickets) {
+		retval = krb5_verify_init_creds(kcontext, &my_creds, NULL,
+						NULL, &xtra_creds,
+						NULL);
+		if (retval) {
+		    com_err("login", retval, "while verifying initial ticket");
+#ifndef SYSLOG42
+		    syslog(LOG_NOTICE|LOG_AUTH,
+			   "can't verify v5 ticket: %s\n",
+			   error_message(retval));
+#endif
+		} else {
+		    break;	/* we're ok */
+		}
+	    }
+#ifdef KRB4_GET_TICKETS
+	    else if (got_v4_tickets) {
+		if (login_krb4_get_tickets &&
+		    (verify_krb_v4_tgt(realm) != -1))
+		    break;	/* we're ok */
+	    }
+#endif /* KRB4_GET_TICKETS */
+
+	bad_login:
+	    setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+
+	    if (krbflag)
+		destroy_tickets(); /* clean up tickets if login fails */
+	}
+#endif /* KRB5_GET_TICKETS */
+
+#ifdef OLD_PASSWD
+	p = getpass ("Password:");
+	/* conventional password only */
+	if (unix_passwd_okay (p))
+	    break;
+#endif /* OLD_PASSWD */
+	printf("Login incorrect\n");
+	if (++cnt >= 5) {
+	    log_repeated_failures (tty, hostname);
+	    /* irix has no tichpcl */
+#ifdef TIOCHPCL
+	    (void)ioctl(0, TIOCHPCL, (char *)0);
+#endif
+	    sleepexit(1);
+	}
+    } /* end of password retry loop */
+
+    /* committed to login -- turn off timeout */
+    (void) alarm((u_int) 0);
+
+    /*
+     * If valid so far and root is logging in, see if root logins on
+     * this terminal are permitted.
+     *
+     * We allow authenticated remote root logins (except -r style)
+     */
+
+    if (pwd->pw_uid == 0 && !rootterm(tty) && (passwd_req || rflag)) {
+	if (hostname) {
+#ifdef UT_HOSTSIZE
+	    syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s",
+		   tty, UT_HOSTSIZE, hostname);
+#else
+	    syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %s",
+		   tty, hostname);
+#endif
+	} else {
+	    syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty);
+	}
+	printf("Login incorrect\n");
+	sleepexit(1);
+    }
+
+#ifdef OQUOTA
+    if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
+	switch(errno) {
+	case EUSERS:
+	    fprintf(stderr,
+		    "Too many users logged on already.\nTry again later.\n");
+	    break;
+	case EPROCLIM:
+	    fprintf(stderr,
+		    "You have too many processes running.\n");
+	    break;
+	default:
+	    perror("quota (Q_SETUID)");
+	}
+	sleepexit(0);
+    }
+#endif
+
+    if (chdir(pwd->pw_dir) < 0) {
+	printf("No directory %s!\n", pwd->pw_dir);
+	if (chdir("/"))
+	    exit(0);
+	pwd->pw_dir = "/";
+	printf("Logging in with home = \"/\".\n");
+    }
+
+    /* nothing else left to fail -- really log in */
+    {
+	struct utmp utmp;
+
+	login_time = time(&utmp.ut_time);
+	if ((retval = pty_update_utmp(PTY_USER_PROCESS, getpid(), username,
+				      ttyn, hostname,
+				      PTY_TTYSLOT_USABLE)) < 0)
+	    com_err (argv[0], retval, "while updating utmp");
+    }
+
+    quietlog = access(HUSHLOGIN, F_OK) == 0;
+    dolastlog(hostname, quietlog, tty);
+
+    (void)chown(ttyn, pwd->pw_uid,
+		(gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
+
+    (void)chmod(ttyn, 0620);
+
+#ifdef KRB5_GET_TICKETS
+    /* Maybe telnetd got tickets for us?  */
+    if (!got_v5_tickets && have_v5_tickets (&me))
+	forwarded_v5_tickets = 1;
+#endif /* KRB5_GET_TICKETS */
+
+#if defined(KRB5_GET_TICKETS) && defined(KRB4_CONVERT)
+    if (login_krb4_convert && !got_v4_tickets) {
+	if (got_v5_tickets||forwarded_v5_tickets)
+	    try_convert524(kcontext, me, forwarded_v5_tickets);
+    }
+#endif
+
+#ifdef KRB5_GET_TICKETS
+    if (login_krb5_get_tickets)
+	dofork();
+#endif
+#ifdef KRB4_GET_TICKETS
+    else if (login_krb4_get_tickets)
+	dofork();
+#endif
+
+/* If the user's shell does not do job control we should put it in a
+   different process group than than us, and set the tty process group
+   to match, otherwise stray signals may be delivered to login.krb5 or
+   telnetd or rlogind if they don't properly detach from their
+   controlling tty, which is the case (under SunOS at least.) */
+
+    {
+	int pid = getpid(); 
+	struct sigaction sa2, osa;
+
+	/* this will set the PGID to the PID. */
+#ifdef HAVE_SETPGID
+	if (setpgid(pid,pid) < 0)
+	    perror("login.krb5: setpgid");
+#elif defined(SETPGRP_TWOARG)
+	if (setpgrp(pid,pid) < 0)
+	    perror("login.krb5: setpgrp");
+#else
+	if (setpgrp() < 0)
+	    perror("login.krb5: setpgrp");
+#endif
+
+	/* This will cause SIGTTOU to be ignored for the duration
+	   of the TIOCSPGRP.  If this is not done, and the parent's
+	   process group is the foreground pgrp of the tty, then
+	   this will suspend the child, which is bad. */
+
+	sa2.sa_flags = 0;
+	sa2.sa_handler = SIG_IGN;
+	sigemptyset(&(sa2.sa_mask));
+
+	if (sigaction(SIGTTOU, &sa2, &osa))
+	    perror("login.krb5: sigaction(SIGTTOU, SIG_IGN)");
+
+	/* This will set the foreground process group of the
+	   controlling terminal to this process group (containing
+	   only this process). */
+#ifdef HAVE_TCSETPGRP
+	if (tcsetpgrp(0, pid) < 0)
+	    perror("login.krb5: tcsetpgrp");
+#else
+	if (ioctl(0, TIOCSPGRP, &pid) < 0)
+	    perror("login.krb5: tiocspgrp");
+#endif
+
+	/* This will reset the SIGTTOU handler */
+
+	if (sigaction(SIGTTOU, &osa, NULL))
+	    perror("login.krb5: sigaction(SIGTTOU, [old handler])");
+    }
+
+    (void) setgid((gid_t) pwd->pw_gid);
+    (void) initgroups(username, pwd->pw_gid);
+
+    /*
+     * The V5 ccache and V4 ticket file are both created as root.
+     * They need to be owned by the user, and chown (a) assumes
+     * they are stored in a file and (b) allows a race condition
+     * in which a user can delete the file (if the directory
+     * sticky bit is not set) and make it a symlink to somewhere
+     * else; on some platforms, chown() on a symlink actually
+     * changes the owner of the pointed-to file.  This is Bad.
+     *
+     * So, we suck the V5 and V4 krbtgts into memory here, destroy
+     * the ccache/ticket file, and recreate them later after the
+     * setuid.
+     *
+     * With the new v5 api, v5 tickets are kept in memory until written
+     * out after the setuid.  However, forwarded tickets still
+     * need to be read in and recreated later
+     */
+#ifdef KRB5_GET_TICKETS
+    if (forwarded_v5_tickets) {
+	krb5_creds mcreds;
+
+	memset(&mcreds, 0, sizeof(mcreds));
+	memset(&save_v5creds, 0, sizeof(save_v5creds));
+
+	mcreds.client = me;
+	retval =
+	    krb5_build_principal_ext(kcontext, &mcreds.server,
+				     krb5_princ_realm(kcontext, me)->length,
+				     krb5_princ_realm(kcontext, me)->data,
+				     tgtname.length, tgtname.data,
+				     krb5_princ_realm(kcontext, me)->length,
+				     krb5_princ_realm(kcontext, me)->data,
+				     0);
+	if (retval) {
+	    syslog(LOG_ERR,
+		   "%s while creating V5 krbtgt principal",
+		   error_message(retval));
+	    rewrite_ccache = 0;
+	} else {
+	    mcreds.ticket_flags = 0;
+
+	    retval = krb5_cc_retrieve_cred(kcontext, ccache, 0,
+					   &mcreds, &save_v5creds);
+	    if (retval) {
+		syslog(LOG_ERR,
+		       "%s while retrieiving V5 initial ticket for copy",
+		       error_message(retval));
+		rewrite_ccache = 0;
+	    }
+	}
+
+	krb5_free_principal(kcontext, mcreds.server);
+    }
+#endif /* KRB5_GET_TICKETS */
+
+#ifdef KRB4_GET_TICKETS
+    if (got_v4_tickets) {
+	memset(&save_v4creds, 0, sizeof(save_v4creds));
+	     
+	retval = krb_get_cred("krbtgt", realm, realm, &save_v4creds);
+	if (retval != KSUCCESS) {
+	    syslog(LOG_ERR,
+		   "%s while retrieving V4 initial ticket for copy",
+		   error_message(retval));
+	    rewrite_ccache = 0;
+	}
+    }
+#endif /* KRB4_GET_TICKETS */
+
+#ifdef KRB5_GET_TICKETS
+    if (forwarded_v5_tickets)
+	destroy_tickets();
+#endif
+#ifdef KRB4_GET_TICKETS
+    else if (got_v4_tickets)
+        destroy_tickets();
+#endif
+
+#ifdef OQUOTA
+    quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
+#endif
+#ifdef HAVE_SETLOGIN
+    if (setlogin(pwd->pw_name) < 0)
+	syslog(LOG_ERR, "setlogin() failure %d",errno);
+#endif
+
+#ifdef	HAVE_SETLUID
+  	/*
+  	 * If we're on a system which keeps track of login uids, then
+ 	 * set the login uid. If this fails this opens up a problem on DEC OSF
+ 	 * with C2 enabled.
+	 */
+ 	if (setluid((uid_t) pwd->pw_uid) < 0) {
+	    perror("setuid");
+	    sleepexit(1);
+	}
+#endif	/* HAVE_SETLUID */
+#ifdef _IBMR2
+    setuidx(ID_LOGIN, pwd->pw_uid);
+#endif
+
+    /* This call MUST succeed */
+    if (setuid((uid_t) pwd->pw_uid) < 0) {
+	perror("setuid");
+	sleepexit(1);
+    }
+
+    /*
+     * We are the user now.  Re-create the destroyed ccache and
+     * ticket file.
+     */
+
+#ifdef KRB5_GET_TICKETS
+    if (got_v5_tickets) {
+	/* set up credential cache -- obeying KRB5_ENV_CCNAME 
+	   set earlier */
+	/* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */
+	if ((retval = krb5_cc_default(kcontext, &ccache))) {
+	    com_err(argv[0], retval, "while getting default ccache");
+	} else if ((retval = krb5_cc_initialize(kcontext, ccache, me))) {
+	    com_err(argv[0], retval, "when initializing cache");
+	} else if ((retval = krb5_cc_store_cred(kcontext, ccache, 
+						&my_creds))) {
+	    com_err(argv[0], retval, "while storing credentials");
+	} else if (xtra_creds &&
+		   (retval = krb5_cc_copy_creds(kcontext, xtra_creds,
+						ccache))) {
+	    com_err(argv[0], retval, "while storing credentials");
+	}
+
+	if (xtra_creds)
+	    krb5_cc_destroy(kcontext, xtra_creds);
+    } else if (forwarded_v5_tickets && rewrite_ccache) {
+	if ((retval = krb5_cc_initialize (kcontext, ccache, me))) {
+	    syslog(LOG_ERR,
+		   "%s while re-initializing V5 ccache as user",
+		   error_message(retval));
+	} else if ((retval = krb5_cc_store_cred(kcontext, ccache,
+						&save_v5creds))) {
+	    syslog(LOG_ERR,
+		   "%s while re-storing V5 credentials as user",
+		   error_message(retval));
+	    
+	}
+	krb5_free_cred_contents(kcontext, &save_v5creds);
+    }
+#endif /* KRB5_GET_TICKETS */
+
+#ifdef KRB4_GET_TICKETS
+    if (got_v4_tickets && rewrite_ccache) {
+	if ((retval = in_tkt(save_v4creds.pname, save_v4creds.pinst))
+	    != KSUCCESS) {
+	    syslog(LOG_ERR,
+		   "%s while re-initializing V4 ticket cache as user",
+		   error_message((retval == -1)?errno:retval));
+	} else if ((retval = krb_save_credentials(save_v4creds.service,
+						  save_v4creds.instance,
+						  save_v4creds.realm, 
+						  save_v4creds.session,
+						  save_v4creds.lifetime,
+						  save_v4creds.kvno,
+						  &(save_v4creds.ticket_st), 
+						  save_v4creds.issue_date))
+		   != KSUCCESS) {
+	    syslog(LOG_ERR,
+		   "%s while re-storing V4 tickets as user",
+		   error_message(retval));
+	}
+    }
+#endif /* KRB4_GET_TICKETS */
+
+    if (*pwd->pw_shell == '\0')
+	pwd->pw_shell = BSHELL;
+
+#if defined(NTTYDISC) && defined(TIOCSETD)
+    /* turn on new line discipline for all shells */
+    ioctlval = NTTYDISC;
+    (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+#endif
+
+    ccname = getenv("KRB5CCNAME");  /* save cache */
+    tz = getenv("TZ");	/* and time zone */
+
+    /* destroy environment unless user has requested preservation */
+    if (!pflag) {
+	envinit = (char **) malloc(MAXENVIRON * sizeof(char *));
+	if (envinit == 0) {
+	    fprintf(stderr, "Can't malloc empty environment.\n");
+	    sleepexit(1);
+	}
+	envinit[0] = NULL;
+	environ = envinit;
+    }
+
+    setenv ("LOGNAME", pwd->pw_name, 1);
+    setenv ("LOGIN", pwd->pw_name, 1);
+
+    /* read the /etc/environment file on AIX */
+#ifdef HAVE_ETC_ENVIRONMENT
+    read_env_vars_from_file ("/etc/environment");
+#endif
+
+    /* Set login timezone for date information (sgi PDG) */
+#ifdef HAVE_ETC_TIMEZONE
+    read_env_vars_from_file ("/etc/TIMEZONE");
+#else
+    if (tz)
+	setenv ("TZ", tz, 1);
+#endif
+
+    if (ccname)
+	setenv("KRB5CCNAME", ccname, 1);
+
+    setenv("HOME", pwd->pw_dir, 1);
+    setenv("PATH", LPATH, 0);
+    setenv("USER", pwd->pw_name, 1);
+    setenv("SHELL", pwd->pw_shell, 1);
+
+    if (term[0] == '\0') {
+	(void) strncpy(term, stypeof(tty), sizeof(term));
+	term[sizeof(term) - 1] = '\0';
+    }
+    if (term[0])
+	(void)setenv("TERM", term, 0);
+
+#ifdef KRB4_GET_TICKETS
+    /* tkfile[0] is only set if we got tickets above */
+    if (login_krb4_get_tickets && tkfile[0])
+	(void) setenv(KRB_ENVIRON, tkfile, 1);
+#endif /* KRB4_GET_TICKETS */
+
+#ifdef KRB5_GET_TICKETS
+    /* ccfile[0] is only set if we got tickets above */
+    if (login_krb5_get_tickets && ccfile[0]) {
+	(void) setenv(KRB5_ENV_CCNAME, ccfile, 1);
+	krb5_cc_set_default_name(kcontext, ccfile);
+    }
+#endif /* KRB5_GET_TICKETS */
+
+    if (tty[sizeof("tty")-1] == 'd')
+	syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
+    if (pwd->pw_uid == 0)
+#ifdef KRB4_KLOGIN
+	if (kdata) {
+	    if (hostname) {
+		char buf[BUFSIZ];
+#ifdef UT_HOSTSIZE
+		(void) sprintf(buf,
+			       "ROOT LOGIN (krb) %s from %.*s, %s.%s@%s",
+			       tty, UT_HOSTSIZE, hostname,
+			       kdata->pname, kdata->pinst,
+			       kdata->prealm);
+#else
+		(void) sprintf(buf,
+			       "ROOT LOGIN (krb) %s from %s, %s.%s@%s",
+			       tty, hostname,
+			       kdata->pname, kdata->pinst,
+			       kdata->prealm);
+#endif
+		syslog(LOG_NOTICE, "%s", buf);
+	    } else {
+		syslog(LOG_NOTICE,
+		       "ROOT LOGIN (krb) %s, %s.%s@%s",
+		       tty,
+		       kdata->pname, kdata->pinst,
+		       kdata->prealm);
+	    }
+	} else
+#endif /* KRB4_KLOGIN */
+	    {
+		if (hostname) {
+#ifdef UT_HOSTSIZE
+		    syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
+			   tty, UT_HOSTSIZE, hostname);
+#else
+		    syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %s",
+			   tty, hostname);
+#endif
+		} else {
+		    syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
+		}
+	    }
+
+    afs_login();
+
+    if (!quietlog) {
+#ifdef KRB4_KLOGIN
+	if (!krbflag && !fflag && !eflag )
+	    printf("\nWarning: No Kerberos tickets obtained.\n\n");
+#endif /* KRB4_KLOGIN */
+	motd();
+	check_mail();
+    }
+
+#ifndef OQUOTA
+    if (! access( QUOTAWARN, X_OK))
+	(void) system(QUOTAWARN);
+#endif
+
+    handler_init (sa, SIG_DFL);
+    handler_set (SIGALRM, sa);
+    handler_set (SIGQUIT, sa);
+    handler_set (SIGINT, sa);
+    handler_init (sa, SIG_IGN);
+    handler_set (SIGTSTP, sa);
+
+    tbuf[0] = '-';
+    p = strrchr(pwd->pw_shell, '/');
+    (void) strncpy(tbuf+1, p?(p+1):pwd->pw_shell, sizeof(tbuf) - 1);
+    tbuf[sizeof(tbuf) - 1] = '\0';
+
+    execlp(pwd->pw_shell, tbuf, (char *)NULL);
+    fprintf(stderr, "login: no shell: ");
+    perror(pwd->pw_shell);
+    exit(0);
+}
+
+char *speeds[] = {
+	"0", "50", "75", "110", "134", "150", "200", "300", "600",
+	"1200", "1800", "2400", "4800", "9600", "19200", "38400",
+};
+#define	NSPEEDS	(sizeof(speeds) / sizeof(speeds[0]))
+
+#ifdef POSIX_TERMIOS
+/* this must be in sync with the list above */
+speed_t b_speeds[] = {
+	B0, B50, B75, B110, B134, B150, B200, B300, B600,
+	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+};
+#endif
+
+void
+term_init (do_rlogin)
+int do_rlogin;
+{
+    int line_speed = -1;
+
+    if (do_rlogin) {
+	register char *cp = strchr(term, '/'), **cpp;
+	char *speed;
+
+	if (cp) {
+	    *cp++ = '\0';
+	    speed = cp;
+	    cp = strchr(speed, '/');
+	    if (cp)
+		*cp++ = '\0';
+	    for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
+		if (strcmp(*cpp, speed) == 0) {
+		    line_speed = cpp-speeds;
+		    break;
+		}
+	}
+    }
+#ifdef POSIX_TERMIOS
+    {
+	struct termios tc;
+
+	(void)tcgetattr(0, &tc);
+	if (line_speed != -1) {
+	    cfsetispeed(&tc, b_speeds[line_speed]);
+	    cfsetospeed(&tc, b_speeds[line_speed]);
+	}
+	tc.c_cc[VMIN] = 1;
+	tc.c_cc[VTIME] = 0;
+#ifndef NO_INIT_CC
+	tc.c_cc[VERASE] = CERASE;
+	tc.c_cc[VKILL] = CKILL;
+	tc.c_cc[VEOF] = CEOF;
+	tc.c_cc[VINTR] = CINTR;
+	tc.c_cc[VQUIT] = CQUIT;
+	tc.c_cc[VSTART] = CSTART;
+	tc.c_cc[VSTOP] = CSTOP;
+#ifndef CNUL
+#define CNUL CEOL
+#endif
+	tc.c_cc[VEOL] = CNUL;
+	/* The following are common extensions to POSIX */
+#ifdef VEOL2
+	tc.c_cc[VEOL2] = CNUL;
+#endif
+#ifdef VSUSP
+#if !defined(CSUSP) && defined(CSWTCH)
+#define CSUSP CSWTCH
+#endif
+	tc.c_cc[VSUSP] = CSUSP;
+#endif
+#ifdef VDSUSP
+	tc.c_cc[VDSUSP] = CDSUSP;
+#endif
+#ifdef VLNEXT
+	tc.c_cc[VLNEXT] = CLNEXT;
+#endif
+#ifdef VREPRINT
+	tc.c_cc[VREPRINT] = CRPRNT;
+#endif
+#ifdef VDISCRD
+	tc.c_cc[VDISCRD] = CFLUSH;
+#endif
+#ifdef VDISCARD
+#ifndef CDISCARD
+#define CDISCARD CFLUSH
+#endif
+	tc.c_cc[VDISCARD] = CDISCARD;
+#endif
+#ifdef VWERSE
+	tc.c_cc[VWERSE] = CWERASE;
+#endif
+#ifdef VWERASE
+	tc.c_cc[VWERASE] = CWERASE;
+#endif
+#if defined (VSTATUS) && defined (CSTATUS)
+	tc.c_cc[VSTATUS] = CSTATUS;
+#endif /* VSTATUS && CSTATUS */
+#endif /* NO_INIT_CC */
+	/* set all standard echo, edit, and job control options */
+	/* but leave any extensions */
+	tc.c_lflag |= ECHO|ECHOE|ECHOK|ICANON|ISIG|IEXTEN;
+	tc.c_lflag &= ~(NOFLSH|TOSTOP);
+#ifdef ECHOCTL
+	/* Not POSIX, but if we have it, we probably want it */
+	tc.c_lflag |= ECHOCTL;
+#endif
+#ifdef ECHOKE
+	/* Not POSIX, but if we have it, we probably want it */
+	tc.c_lflag |= ECHOKE;
+#endif
+	tc.c_iflag |= ICRNL|BRKINT;
+	tc.c_oflag |= ONLCR|OPOST|TAB3;
+	tcsetattr(0, TCSANOW, &tc);
+    }
+
+#else /* not POSIX_TERMIOS */
+
+    {
+	struct sgttyb sgttyb;
+	static struct tchars tc = {
+	    CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
+	};
+	static struct ltchars ltc = {
+	    CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
+	};
+
+	(void) ioctl(0, TIOCGETP, (char *)&sgttyb);
+	if (line_speed != -1)
+	    sgttyb.sg_ispeed = sgttyb.sg_ospeed = line_speed;
+	sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS;
+	sgttyb.sg_erase = CERASE;
+	sgttyb.sg_kill = CKILL;
+	(void)ioctl(0, TIOCSLTC, (char *)<c);
+	(void)ioctl(0, TIOCSETC, (char *)&tc);
+	(void)ioctl(0, TIOCSETP, (char *)&sgttyb);
+#if defined(TIOCSETD)
+	{
+	    int ioctlval;
+	    ioctlval = 0;
+	    (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+	}
+#endif
+    }
+#endif
+}
+
+void getloginname()
+{
+    register int ch;
+    register char *p;
+    static char nbuf[UT_NAMESIZE + 1];
+
+    for (;;) {
+	printf("login: ");
+	for (p = nbuf; (ch = getchar()) != '\n'; ) {
+	    if (ch == EOF)
+		exit(0);
+	    if (p < nbuf + UT_NAMESIZE)
+		*p++ = ch;
+	}
+	if (p > nbuf) {
+	    if (nbuf[0] == '-')
+		fprintf(stderr,
+			"login names may not start with '-'.\n");
+	    else {
+		*p = '\0';
+		username = nbuf;
+		break;
+	    }
+	}
+    }
+}
+
+sigtype
+timedout(signumber)
+    int signumber;
+{
+    fprintf(stderr, "Login timed out after %d seconds\n", timeout);
+    exit(0);
+}
+
+#ifndef HAVE_TTYENT_H
+int root_tty_security = 1;
+#endif
+
+int rootterm(tty)
+	char *tty;
+{
+#ifndef HAVE_TTYENT_H
+    return(root_tty_security);
+#else
+    struct ttyent *t;
+
+    return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
+#endif /* HAVE_TTYENT_H */
+}
+
+#ifndef NO_MOTD
+sigjmp_buf motdinterrupt;
+
+static sigtype
+sigint(signum)
+    int signum;
+{
+    siglongjmp(motdinterrupt, 1);
+}
+
+void motd()
+{
+    register int fd, nchars;
+    char tbuf[8192];
+    handler sa, osa;
+
+    if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0)
+	return;
+    handler_init (sa, sigint);
+    handler_swap (SIGINT, sa, osa);
+    if (sigsetjmp(motdinterrupt, 1) == 0)
+	while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+	    (void)write(fileno(stdout), tbuf, nchars);
+    handler_set (SIGINT, osa);
+    (void)close(fd);
+}
+#else
+void motd()
+{
+}
+#endif
+
+#ifndef NO_MAILCHECK
+void check_mail()
+{
+    char tbuf[MAXPATHLEN+2];
+    struct stat st;
+    (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name);
+    if (stat(tbuf, &st) == 0 && st.st_size != 0)
+	printf("You have %smail.\n",
+	       (st.st_mtime > st.st_atime) ? "new " : "");
+}
+#else
+void check_mail()
+{
+}
+#endif
+
+void checknologin()
+{
+    register int fd, nchars;
+    char tbuf[8192];
+
+    if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
+	while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+	    (void)write(fileno(stdout), tbuf, (unsigned) nchars);
+	sleepexit(0);
+    }
+}
+
+void dolastlog(hostname, quiet, tty)
+     char *hostname;
+     int quiet;
+     char *tty;
+{
+#if defined(HAVE_LASTLOG_H) || (defined(BSD) && (BSD >= 199103))
+    struct lastlog ll;
+    time_t lltime;
+    int fd;
+
+    if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) {
+	(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
+	if (!quiet) {
+	    if ((read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll)) &&
+		(ll.ll_time != 0)) {
+
+		/* .ll_time may not be a time_t.  */
+		lltime = ll.ll_time;
+		printf("Last login: %.*s ", 24-5, (char *)ctime(&lltime));
+
+		if (*ll.ll_host != '\0')
+		    printf("from %.*s\n", (int) sizeof(ll.ll_host), 
+			   ll.ll_host);
+		else
+		    printf("on %.*s\n", (int) sizeof(ll.ll_line), ll.ll_line);
+	    }
+	    (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
+	}
+	(void) time(&lltime);
+	ll.ll_time = lltime;
+
+	(void) strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+	ll.ll_line[sizeof(ll.ll_line) - 1] = '\0';
+
+	if (hostname) {
+	    (void) strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
+	    ll.ll_host[sizeof(ll.ll_host) - 1] = '\0';
+	} else {
+	    (void) memset(ll.ll_host, 0, sizeof(ll.ll_host));
+	}
+
+	(void)write(fd, (char *)&ll, sizeof(ll));
+	(void)close(fd);
+    }
+#endif
+}
+
+#undef	UNKNOWN
+#ifdef __hpux
+#define UNKNOWN 0
+#else
+#define	UNKNOWN	"su"
+#endif
+
+char *
+stypeof(ttyid)
+     char *ttyid;
+{
+    char *cp = getenv("term");
+
+#ifndef HAVE_TTYENT_H
+    if (cp)
+	return cp;
+    else
+	return(UNKNOWN);
+#else
+    struct ttyent *t;
+    if (cp)
+	return cp;
+    else
+	return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
+#endif
+}
+
+int doremotelogin(host)
+     char *host;
+{
+    static char lusername[UT_NAMESIZE+1];
+    char rusername[UT_NAMESIZE+1];
+
+    lgetstr(rusername, sizeof(rusername), "Remote user");
+    lgetstr(lusername, sizeof(lusername), "Local user");
+    lgetstr(term, sizeof(term), "Terminal type");
+    username = lusername;
+    pwd = getpwnam(username);
+    if (pwd == NULL)
+	return(-1);
+    return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
+}
+
+#ifdef KRB4_KLOGIN
+int do_krb_login(host, strict)
+     char *host;
+     int strict;
+{
+    int rc;
+    struct sockaddr_in sin;
+    char instance[INST_SZ], version[9];
+    long authoptions = 0L;
+    struct hostent *hp = gethostbyname(host);
+    static char lusername[UT_NAMESIZE+1];
+    
+    /*
+     * Kerberos autologin protocol.
+     */
+
+    (void) memset((char *) &sin, 0, (int) sizeof(sin));
+    
+    if (hp)
+	(void) memcpy ((char *)&sin.sin_addr, hp->h_addr,
+		       sizeof(sin.sin_addr));
+    else
+	sin.sin_addr.s_addr = inet_addr(host);
+    
+    if ((hp == NULL) && (sin.sin_addr.s_addr == -1)) {
+	printf("Hostname did not resolve to an address, so Kerberos authentication failed\r\n");
+	/*
+	 * No host addr prevents auth, so
+	 * punt krb and require password
+	 */
+	if (strict) {
+	    goto paranoid;
+	} else {
+	    pwd = NULL;
+	    return(-1);
+	}
+    }
+
+    kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) );
+    ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
+
+    (void) strcpy(instance, "*");
+    if ((rc=krb_recvauth(authoptions, 0, ticket, "rcmd",
+			 instance, &sin,
+			 (struct sockaddr_in *)0,
+			 kdata, "", (bit_64 *) 0, version))) {
+	printf("Kerberos rlogin failed: %s\r\n",krb_get_err_text(rc));
+	if (strict) {
+paranoid:
+	    /*
+	     * Paranoid hosts, such as a Kerberos server,
+	     * specify the Klogind daemon to disallow
+	     * even password access here.
+	     */
+	    printf("Sorry, you must have Kerberos authentication to access this host.\r\n");
+	    exit(1);
+	}
+    }
+    (void) lgetstr(lusername, sizeof (lusername), "Local user");
+    (void) lgetstr(term, sizeof(term), "Terminal type");
+    username = lusername;
+    if (getuid()) {
+	pwd = NULL;
+	return(-1);
+    }
+    pwd = getpwnam(lusername);
+    if (pwd == NULL) {
+	pwd = NULL;
+	return(-1);
+    }
+
+    /*
+     * if Kerberos login failed because of an error in krb_recvauth,
+     * return the indication of a bad attempt.  User will be prompted
+     * for a password.  We CAN'T check the .rhost file, because we need 
+     * the remote username to do that, and the remote username is in the 
+     * Kerberos ticket.  This affects ONLY the case where there is
+     * Kerberos on both ends, but Kerberos fails on the server end. 
+     */
+    if (rc) {
+	return(-1);
+    }
+
+    if ((rc=kuserok(kdata,lusername))) {
+	printf("login: %s has not given you permission to login without a password.\r\n",lusername);
+	if (strict) {
+	    exit(1);
+	}
+	return(-1);
+    }
+    return(0);
+}
+#endif /* KRB4_KLOGIN */
+
+void lgetstr(buf, cnt, err)
+     char *buf, *err;
+     int cnt;
+{
+    int ocnt = cnt;
+    char *obuf = buf;
+    char ch;
+
+    do {
+	if (read(0, &ch, sizeof(ch)) != sizeof(ch))
+	    exit(1);
+	if (--cnt < 0) {
+	    fprintf(stderr,"%s '%.*s' too long, %d characters maximum.\r\n",
+		    err, ocnt, obuf, ocnt-1);
+	    sleepexit(1);
+	}
+	*buf++ = ch;
+    } while (ch);
+}
+
+void sleepexit(eval)
+     int eval;
+{
+#ifdef KRB4_GET_TICKETS
+    if (login_krb4_get_tickets && krbflag)
+	(void) destroy_tickets();
+#endif /* KRB4_GET_TICKETS */
+    sleep((u_int)5);
+    exit(eval);
+}
+
+#if defined(KRB4_GET_TICKETS) || defined(KRB5_GET_TICKETS)
+static int hungup = 0;
+
+static sigtype
+sighup() {
+    hungup = 1;
+}
+
+/* call already conditionalized on login_krb4_get_tickets */
+/*
+ * This routine handles cleanup stuff, and the like.
+ * It exits only in the child process.
+ */
+#include <sys/wait.h>
+void
+dofork()
+{
+    int child,pid;
+    handler sa;
+    int syncpipe[2];
+    char c;
+    int n;
+    
+#ifdef _IBMR2
+    update_ref_count(1);
+#endif
+    if (pipe(syncpipe) < 0) {
+	perror("login: dofork: setting up syncpipe");
+	exit(1);
+    }
+    if (!(child=fork())) {
+	close(syncpipe[1]);
+	while ((n = read(syncpipe[0], &c, 1)) < 0) {
+	    if (errno != EINTR) {
+		perror("login: dofork: waiting for sync from parent");
+		exit(1);
+	    }
+	}
+	if (n == 0) {
+	    fprintf(stderr, "login: dofork: unexpected EOF waiting for sync\n");
+	    exit(1);
+	}
+	close(syncpipe[0]);
+	return; /* Child process returns */
+    }
+
+    /* The parent continues here */
+
+    /* On receipt of SIGHUP, pass that along to child's process group. */
+    handler_init (sa, sighup);
+    handler_set (SIGHUP, sa);
+    /* Tell child we're ready. */
+    close(syncpipe[0]);
+    write(syncpipe[1], "", 1);
+    close(syncpipe[1]);
+
+    /* Setup stuff?  This would be things we could do in parallel with login */
+    (void) chdir("/");	/* Let's not keep the fs busy... */
+    
+    /* If we're the parent, watch the child until it dies */
+
+    while (1) {
+#ifdef HAVE_WAITPID
+        pid = waitpid(child, 0, 0);
+#elif defined(WAIT_USES_INT)
+        pid = wait((int *)0);
+#else
+        pid = wait((union wait *)0);
+#endif
+
+	if (hungup) {
+#ifdef HAVE_KILLPG
+	    killpg(child, SIGHUP);
+#else
+	    kill(-child, SIGHUP);
+#endif
+	}
+
+	if (pid == child)
+	    break;
+    }
+    
+    /* Cleanup stuff */
+    /* Run destroy_tickets to destroy tickets */
+    (void) destroy_tickets();		/* If this fails, we lose quietly */
+    afs_cleanup ();
+#ifdef _IBMR2
+    update_ref_count(-1);
+#endif
+
+    /* Leave */
+    exit(0);
+}
+#endif /* KRB4_GET_TICKETS */
+
+
+#ifndef HAVE_STRSAVE
+/* Strsave was a routine in the version 4 krb library: we put it here
+   for compatablilty with version 5 krb library, since kcmd.o is linked
+   into all programs. */
+
+char *strsave(sp)
+     char *sp;
+{
+    register char *ret;
+    
+    if ((ret = (char *) malloc((unsigned) strlen(sp)+1)) == NULL) {
+	fprintf(stderr, "no memory for saving args\n");
+	exit(1);
+    }
+    (void) strcpy(ret,sp);
+    return(ret);
+}
+#endif
+
+#ifdef _IBMR2
+update_ref_count(int adj)
+{
+    struct passwd *save_pwd;
+    static char *empty = "\0";
+    char *grp;
+    int i;
+
+    /* save pwd before calling getuserattr() */
+    save_pwd = (struct passwd *)malloc(sizeof(struct passwd));
+    save_pwd->pw_name = strdup(pwd->pw_name);
+    save_pwd->pw_passwd = strdup(pwd->pw_passwd);
+    save_pwd->pw_uid = pwd->pw_uid;
+    save_pwd->pw_gid = pwd->pw_gid;
+    save_pwd->pw_gecos = strdup(pwd->pw_gecos);
+    save_pwd->pw_dir = strdup(pwd->pw_dir);
+    save_pwd->pw_shell = strdup(pwd->pw_shell);
+    pwd = save_pwd;
+
+    /* Update reference count on all user's temporary groups */
+    setuserdb(S_READ|S_WRITE);
+    if (getuserattr(username, S_GROUPS, (void *)&grp, SEC_LIST) == 0) {
+	while (*grp) {
+	    if (getgroupattr(grp, "athena_temp", (void *)&i, SEC_INT) == 0) {
+		i += adj;
+		if (i > 0) {
+		    putgroupattr(grp, "athena_temp", (void *)i, SEC_INT);
+		    putgroupattr(grp, (char *)0, (void *)0, SEC_COMMIT);
+		} else {
+		    putgroupattr(grp, S_USERS, (void *)empty, SEC_LIST);
+#ifdef HAVE_RMUFILE /* pre-4.3.0 AIX */
+		    putgroupattr(grp, (char *)0, (void *)0, SEC_COMMIT);
+		    rmufile(grp, 0, GROUP_TABLE);
+#else
+		    putgroupattr(grp, (char *)0, (void *)0, SEC_DELETE);
+		    putgroupattr(grp, (char *)0, (void *)0, SEC_COMMIT);
+#endif
+		}
+	    }
+	    while (*grp) grp++;
+	    grp++;
+	}
+    }
+    enduserdb();
+}
+#endif
diff --git a/mechglue/src/appl/bsd/loginpaths.h b/mechglue/src/appl/bsd/loginpaths.h
new file mode 100644
index 000000000..0f2580bb9
--- /dev/null
+++ b/mechglue/src/appl/bsd/loginpaths.h
@@ -0,0 +1,113 @@
+/* here are actual path values from each operating system supported. */
+/* LPATH is from rlogin, for login.c; RPATH is from rsh, for rshd.c */
+#ifdef sun
+#ifdef __SVR4
+#define RPATH "/usr/bin"
+#define LPATH "/usr/bin"
+#else
+/* sun3 and sun4 */
+#define LPATH "/usr/ucb:/bin:/usr/bin"
+#define RPATH "/usr/ucb:/bin:/usr/bin"
+#endif
+#endif
+
+#ifdef __ultrix
+#define LPATH "/usr/ucb:/bin:/usr/bin"
+#define RPATH "/usr/ucb:/bin:/usr/bin"
+#endif
+
+#ifdef hpux
+/* hpux 8, both hppa and s300 */
+#define LPATH "/bin:/usr/bin:/usr/contrib/bin:/usr/local/bin"
+#define RPATH "/bin:/usr/bin:/usr/contrib/bin:/usr/local/bin"
+#else
+#ifdef __hpux /* 9.04 */
+#define LPATH_root ":/bin:/usr/bin:/etc"
+#define LPATH "/bin:/usr/bin"
+#define RPATH "/bin:/usr/bin:/usr/contrib/bin:/usr/local/bin"
+#endif
+#endif
+
+#ifdef NeXT
+#define LPATH "/usr/ucb:/bin:/usr/bin:/usr/local/bin"
+#define RPATH "/bin:/usr/ucb:/usr/bin"
+#endif
+
+#ifdef _IBMR2
+/* 3.2.0 */ 
+#define LPATH "/usr/bin:/usr/ucb:/usr/bin/X11"
+#define RPATH "/usr/bin:/usr/ucb:/usr/bin/X11"
+#endif
+
+#ifdef __SCO__
+#define LPATH "/bin:/usr/bin:/usr/dbin:/usr/ldbin"
+#define RPATH "/bin:/usr/bin:/usr/local/bin"
+#endif
+
+#ifdef sgi
+#define LPATH "/usr/sbin:/usr/bsd:/usr/bin:/bin:/usr/bin/X11"
+#define RPATH "/usr/sbin:/usr/bsd:/usr/bin:/bin:/usr/bin/X11"
+#endif
+
+#ifdef linux
+#define LPATH "/local/bin:/usr/bin:/bin:/usr/local/bin:/usr/bin/X11:."
+#define RPATH "/local/bin:/usr/bin:/bin:/usr/local/bin:/usr/bin/X11:."
+#endif
+
+#ifdef __386BSD__
+#define LPATH "/usr/bin:/bin"
+#define RPATH "/usr/bin:/bin"
+#endif
+
+#ifdef __alpha
+#ifdef __osf__
+#define LPATH "/usr/bin:."
+#define RPATH "/usr/bin:/bin"
+#endif
+#endif
+
+#ifdef __pyrsoft
+#ifdef MIPSEB
+#define RPATH "/bin:/usr/bin"
+#define LPATH "/usr/bin:/usr/ccs/bin:/usr/ucb:."
+#endif
+#endif
+
+#ifdef __DGUX
+#ifdef __m88k__
+#define RPATH "/usr/bin"
+#define LPATH "/usr/bin"
+#endif
+#endif
+
+#ifndef LPATH
+#ifdef __svr4__
+/* taken from unixware, sirius... */
+#define RPATH "/bin:/usr/bin:/usr/X/bin"
+#define LPATH "/usr/bin:/usr/dbin:/usr/dbin"
+#endif
+#endif
+
+#ifndef LPATH
+#ifdef __NetBSD__
+#define LPATH "/usr/bin:/bin"
+#define RPATH "/usr/bin:/bin"
+#endif
+#endif
+
+#ifdef _PATH_DEFPATH
+#undef LPATH
+#define LPATH _PATH_DEFPATH
+#undef RPATH
+#define RPATH _PATH_DEFPATH
+#endif
+
+/* catch-all entries for operating systems we haven't looked up
+   hardcoded paths for */
+#ifndef LPATH
+#define LPATH "/usr/bin:/bin"
+#endif
+
+#ifndef RPATH
+#define RPATH "/usr/bin:/bin"
+#endif
diff --git a/mechglue/src/appl/bsd/rcp.M b/mechglue/src/appl/bsd/rcp.M
new file mode 100644
index 000000000..a388e80ed
--- /dev/null
+++ b/mechglue/src/appl/bsd/rcp.M
@@ -0,0 +1,160 @@
+.\" appl/bsd/rcp.M
+.\"
+.\" Copyright (c) 1983 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"	@(#)rcp.1	6.6 (Berkeley) 9/20/88
+.\"
+.TH RCP 1
+.SH NAME
+rcp \- remote file copy
+.SH SYNOPSIS
+.B rcp
+[\fB\-p\fP] [\fB\-x\fP] [\fB\-k\fP \fIrealm\fP ] [\fB-c\fP \fIccachefile\fP] [\fB-C\fP \fIconfigfile\fP] [\fB\-D\fP \fIport\fP]
+[\fB\-N\fP]
+[\fB\-PN | \-PO\fP]
+.I file1 file2
+.sp
+.B rcp
+[\fB\-p\fB] [\fB\-x\fP] [\fP\-k\fP \fIrealm\fP] [\fB\-r\fP] [\fB\-D\fP
+\fIport\fP] [\fB\-N\fP]
+[\fB\-PN | \-PO\fP]
+.I file ... directory
+.sp
+.B rcp
+[\fB\-f | \-t\fP]
+.I ...
+.SH DESCRIPTION
+.B Rcp
+copies files between machines.  Each
+.I file
+or
+.I directory
+argument is either a remote file name of the form ``rhost:path'', or a
+local file name (containing no `:' characters, or a `/' before any
+`:'s).
+.PP
+By default, the mode and owner of
+.I file2
+are preserved if it already existed; otherwise the mode of the source
+file modified by the
+.IR umask (2)
+on the destination host is used.
+.PP
+If
+.I path
+is not a full path name, it is interpreted relative to your login
+directory on
+.IR rhost .
+A 
+.I path
+on a remote host may be quoted (using \e, ", or \(aa) so that the
+metacharacters are interpreted remotely.
+.PP
+.B Rcp
+does not prompt for passwords; it uses Kerberos authentication when
+connecting to
+.IR rhost .
+Each user may have a private authorization list in a file \&.k5login in
+his login directory.  Each line in this file should contain a Kerberos
+principal name of the form
+.IR principal/instance@realm .
+If there is a ~/.k5login file, then access is granted to the account if
+and only if the originater user is authenticated to one of the
+principals named in the ~/.k5login file.  Otherwise, the originating
+user will be granted access to the account if and only if the
+authenticated principal name of the user can be mapped to the local
+account name using the aname -> lname mapping rules (see
+.IR krb5_anadd (8)
+for more details).
+.SH OPTIONS
+.TP
+.B \-p
+attempt to preserve (duplicate) the modification times and modes of the
+source files in the copies, ignoring the
+.IR umask .
+.TP
+\fB\-x\fP
+encrypt all information transferring between hosts.
+.TP
+\fB\-k\fP \fIrealm\fP
+obtain tickets for the remote host in
+.I realm
+instead of the remote host's realm as determined by
+.IR krb_realmofhost (3).
+.TP
+\fB\-c\fP \fIccachefile\fP
+change the default credentials cache file to 
+.I ccachefile
+.TP
+\fB\-C\fP \fIconfigfile\fP
+change the default configuation file to
+.I configfile
+.TP
+.B \-r
+if any of the source files are directories, copy each subtree rooted at
+that name; in this case the destination must be a directory.
+.TP
+\fB-PN\fP
+.TP
+\fB-PO\fP
+Explicitly request new or old version of the Kerberos ``rcmd''
+protocol.  The new protocol avoids many security problems found in the
+old one, but is not interoperable with older servers.  (An
+"input/output error" and a closed connection is the most likely result
+of attempting this combination.)  If neither option is specified, some
+simple heuristics are used to guess which to try.
+.TP
+\fB\-D\fP \fIport\fP
+connect to port
+.I port
+on the remote machine.  
+.TP
+.B \-N
+use a network connection, even when copying files on the local machine
+(used for testing purposes).
+.TP
+.B \-f \-t
+These options are for internal use only.  They tell the
+remotely-running rcp process (started via the Kerberos remote shell
+daemon) which direction files are being sent.  These options should
+not be used by the user.  In particular, \fB-f\fP does \fBnot\fP mean
+that the user's Kerberos ticket should be forwarded!
+.PP
+.B Rcp
+handles third party copies, where neither source nor target files are on
+the current machine.  Hostnames may also take the form ``rname@rhost''
+to use
+.I rname
+rather than the current user name on the remote host.
+.SH FILES
+.TP "\w'~/.k5login\ \ 'u"
+~/.k5login
+(on remote host) - file containing Kerberos principals that are allowed
+access.
+.SH SEE ALSO
+cp(1), ftp(1), rsh(1), rlogin(1), kerberos(3), krb_getrealm(3), kshd(8), rcp(1) 
+[UCB version]
+.SH BUGS
+.B Rcp
+doesn't detect all cases where the target of a copy might be a file in
+cases where only a directory should be legal.
+.PP
+.B Rcp
+is confused by any output generated by commands in a \&.login,
+\&.profile, or \&.cshrc file on the remote host.
+.PP
+Kerberos is only used for the first connection of a third-party copy;
+the second connection uses the standard Berkeley rcp protocol.
diff --git a/mechglue/src/appl/bsd/rlogin.M b/mechglue/src/appl/bsd/rlogin.M
new file mode 100644
index 000000000..97b2a8e7d
--- /dev/null
+++ b/mechglue/src/appl/bsd/rlogin.M
@@ -0,0 +1,160 @@
+.\" appl/bsd/rlogin.M
+.\"
+.\" Copyright (c) 1983 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"	@(#)rlogin.1	6.9 (Berkeley) 9/19/88
+.\" "
+.TH RLOGIN 1
+.SH NAME
+rlogin \- remote login
+.SH SYNOPSIS
+.B rlogin
+.I rhost
+[\fB\-e\fP\fI\|c\fP] [\fB\-8\fP] [\fB\-c\fP] [ \fB\-a\fP] [\fB\-f\fP]
+[\fB\-F\fP] [\fB\-t\fP \fItermtype\fP] [\fB\-n\fP] [\fB\-7\fP]
+[\fB\-PN | \-PO\fP] [\fB\-4\fP]
+[\fB\-d\fP] [\fB\-k\fP \fIrealm\fP] [\fB\-x\fP] [\fB\-L\fP] [\fB\-l\fP
+\fIusername\fP]
+.PP
+.SH DESCRIPTION
+.I Rlogin
+connects your terminal on the current local host system
+.I lhost
+to the remote host system
+.I rhost.
+.PP
+The version built to use Kerberos authentication is very similar to the
+standard Berkeley rlogin(1), except that instead of the \fIrhosts\fP
+mechanism, it uses Kerberos authentication to determine the
+authorization to use a remote account.
+.PP
+Each user may have a private authorization list in a file \&.k5login in
+his login directory.  Each line in this file should contain a Kerberos
+principal name of the form
+.IR principal/instance@realm .
+If the originating user is authenticated to one of the principals named
+in \&.k5login, access is granted to the account.  If there is no
+/.k5login file, the principal will be granted access to the account
+according to the aname\->lname mapping rules.  (See
+.IR krb5_anadd(8) 
+for more details.)  Otherwise a login and password will be prompted for
+on the remote machine as in
+.IR login (1).
+To avoid some security problems, the \&.k5login file must be owned by
+the remote user.
+.PP
+If there is some problem in marshaling the Kerberos authentication
+information, an error message is printed and the standard UCB rlogin is
+executed in place of the Kerberos rlogin.
+.PP
+A line of the form ``~.'' disconnects from the remote host, where ``~''
+is the escape character.  Similarly, the line ``~^Z'' (where ^Z,
+control-Z, is the suspend character) will suspend the rlogin session.
+Substitution of the delayed-suspend character (normally ^Y) for the
+suspend character suspends the send portion of the rlogin, but allows
+output from the remote system.
+.PP
+The remote terminal type is the same as your local terminal type (as
+given in your environment TERM variable), unless the
+.B \-t
+option is specified (see below).  The terminal or window size is also
+copied to the remote system if the server supports the option, and
+changes in size are reflected as well.
+.PP
+All echoing takes place at the remote site, so that (except for delays)
+the rlogin is transparent.  Flow control via ^S and ^Q and flushing of
+input and output on interrupts are handled properly.
+.SH OPTIONS
+.TP
+.B \-8
+allows an eight-bit input data path at all times; otherwise parity bits
+are stripped except when the remote side's stop and start characters are
+other than ^S/^Q.  Eight-bit mode is the default.
+.TP
+.B \-L
+allows the rlogin session to be run in litout mode.
+.TP
+\fB\-e\fP\fIc\fP
+sets the escape character to
+.IR c .
+There is no space separating this option flag and the new escape
+character.
+.TP
+.B \-c
+require confirmation before disconnecting via ``~.''
+.TP
+.B \-a
+force the remote machine to ask for a password by sending a null local
+username.  This option has no effect unless the standard UCB rlogin is
+executed in place of the Kerberos rlogin (see above).
+.TP
+\fB\-f\fP
+forward a copy of the local credentials to the remote system.
+.TP
+\fB\-F\fP
+forward a
+.I forwardable
+copy of the local credentials to the remote system.
+.TP
+\fB\-t\fP \fItermtype\fP
+replace the terminal type passed to the remote host with
+.IR termtype .
+.TP
+.B \-n
+prevent suspension of rlogin via ``~^Z'' or ``~^Y''.
+.TP
+.B \-7
+force seven-bit transmissions.
+.TP
+.B \-d
+turn on socket debugging (via
+.IR setsockopt (2))
+on the TCP sockets used for communication with the remote host.
+.TP
+.B \-k
+request rlogin to obtain tickets for the remote host in realm
+.I realm
+instead of the remote host's realm as determined by 
+.IR krb_realmofhost (3).
+.TP
+\fB\-x\fP
+turn on DES encryption for data passed via the rlogin session.  This
+applies only to input and output streams, so the username is sent
+unencrypted.  This significantly reduces response time and
+significantly increases CPU utilization.
+.TP
+\fB-PN\fP
+.TP
+\fB-PO\fP
+Explicitly request new or old version of the Kerberos ``rcmd''
+protocol.  The new protocol avoids many security problems found in the
+old one, but is not interoperable with older servers.  (An
+"input/output error" and a closed connection is the most likely result
+of attempting this combination.)  If neither option is specified, some
+simple heuristics are used to guess which to try.
+.TP
+\fB\-4\fP
+Use Kerberos V4 authentication only; don't try Kerberos V5.
+.SH SEE ALSO
+rsh(1), kerberos(3), krb_sendauth(3), krb_realmofhost(3), rlogin(1) [UCB
+version], klogind(8)
+.SH FILES
+.TP "\w'~/\&.k5login\ \ 'u"
+~/\&.k5login
+(on remote host) - file containing Kerberos principals that are allowed
+access.
+.SH BUGS
+More of the environment should be propagated.
diff --git a/mechglue/src/appl/bsd/rpaths.h b/mechglue/src/appl/bsd/rpaths.h
new file mode 100644
index 000000000..4925ea33a
--- /dev/null
+++ b/mechglue/src/appl/bsd/rpaths.h
@@ -0,0 +1,31 @@
+/* fallback pathnames */
+
+#ifdef RPROGS_IN_USR_UCB
+#define	UCB_RLOGIN	"/usr/ucb/rlogin"
+#define	UCB_RCP	"/usr/ucb/rcp"
+#define	UCB_RSH	"/usr/ucb/rsh"
+/* all in /usr/ucb/, don't look for /bin/rcp */
+#endif
+
+#ifdef RPROGS_IN_USR_BIN
+#define UCB_RLOGIN "/usr/bin/rlogin"
+#define UCB_RCP "/usr/bin/rcp"
+#define UCB_RSH "/usr/bin/rsh"
+#endif
+
+#ifdef RPROGS_IN_USR_BSD
+#define UCB_RLOGIN "/usr/bsd/rlogin"
+#define UCB_RCP "/usr/bsd/rcp"
+#define UCB_RSH "/usr/bsd/rsh"
+#endif
+
+#ifdef RSH_IS_RCMD
+#undef UCB_RSH
+#define UCB_RSH "/usr/bin/rcmd"
+#endif
+
+#ifdef RSH_IS_REMSH
+#undef UCB_RSH
+#define UCB_RSH "/usr/bin/remsh"
+#endif
+
diff --git a/mechglue/src/appl/bsd/rsh.M b/mechglue/src/appl/bsd/rsh.M
new file mode 100644
index 000000000..ce0ebfb20
--- /dev/null
+++ b/mechglue/src/appl/bsd/rsh.M
@@ -0,0 +1,173 @@
+.\" appl/bsd/rsh.M
+.\"
+.\" Copyright (c) 1983 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"	@(#)rsh.1	6.2 (Berkeley) 9/20/88
+.\" "
+.TH RSH 1
+.SH NAME
+rsh \- remote shell
+.SH SYNOPSIS
+.B rsh
+.I host
+[\fB\-l\fP \fIusername\fP] [\fB\-n\fP] [\fB\-d\fP] [\fB\-k\fP
+\fIrealm\fP] [\fB\-f\fP | \fB\-F\fP] [\fB\-x\fP]
+[\fB\-PN | \-PO\fP]
+.I command
+.SH DESCRIPTION
+.B Rsh
+connects to the specified
+.I host,
+and executes the specified \fIcommand\fR.
+.B Rsh
+copies its standard input to the remote command, the standard output of
+the remote command to its standard output, and the standard error of the
+remote command to its standard error.  This implementation of
+.B rsh
+will accept any port for the standard error stream.  Interrupt, quit and
+terminate signals are propagated to the remote command; \fIrsh\fP
+normally terminates when the remote command does.
+.PP
+Each user may have a private authorization list in a file \&.k5login in
+his login directory.  Each line in this file should contain a Kerberos
+principal name of the form
+.IR principal/instance@realm .
+If there is a ~/.k5login file, then access is granted to the account if
+and only if the originater user is authenticated to one of the
+princiapls named in the ~/.k5login file.  Otherwise, the originating
+user will be granted access to the account if and only if the
+authenticated principal name of the user can be mapped to the local
+account name using the aname -> lname mapping rules (see
+.IR krb5_anadd (8)
+for more details).
+.SH OPTIONS
+.TP
+\fB\-l\fP \fIusername\fP
+sets the remote username to
+.IR username .
+Otherwise, the remote username will be the same as the local username.
+.TP
+\fB\-x\fP
+causes the network session traffic to be encrypted.  This applies only
+to the input and output streams, and not the command line.
+.TP
+\fB\-f\fP
+cause nonforwardable Kerberos credentials to be forwarded to the remote
+machine for use by the specified
+.IR command .
+They will be removed when
+.I command
+finishes.  This option is mutually exclusive with the
+.B \-F
+option.
+.TP
+\fB\-F\fP
+cause
+.I forwardable
+Kerberos credentials to be forwarded to the remote machine for use by
+the specified
+.IR command .
+They will be removed when
+.I command
+finishes.  This option is mutually exclusive with the
+.B \-f
+option.
+.TP
+\fB\-k\fP \fIrealm\fP
+causes 
+.I rsh
+to obtain tickets for the remote host in
+.I realm
+instead of the remote host's realm as determined by
+.IR krb_realmofhost (3).
+.TP
+.B \-d
+turns on socket debugging (via
+.IR setsockopt (2))
+on the TCP sockets used for communication with the remote host.
+.TP
+.B \-n
+redirects input from the special device
+.I /dev/null
+(see the BUGS section below).
+.TP
+\fB-PN\fP
+.TP
+\fB-PO\fP
+Explicitly request new or old version of the Kerberos ``rcmd''
+protocol.  The new protocol avoids many security problems found in the
+old one, but is not interoperable with older servers.  (An
+"input/output error" and a closed connection is the most likely result
+of attempting this combination.)  If neither option is specified, some
+simple heuristics are used to guess which to try.
+.PP
+If you omit
+.IR command ,
+then instead of executing a single command, you will be logged in on the
+remote host using
+.IR rlogin (1).
+.PP
+Shell metacharacters which are not quoted are interpreted on the local
+machine, while quoted metacharacters are interpreted on the remote
+machine.  Thus the command
+.PP
+\ \ \ rsh otherhost cat remotefile >> localfile
+.PP
+appends the remote file
+.I remotefile
+to the local file
+.IR localfile ,
+while
+.PP
+\ \ \ rsh otherhost cat remotefile ">>" otherremotefile
+.PP
+appends
+.I remotefile
+to
+.IR otherremotefile .
+.SH FILES
+.TP "\w'~/.k5login\ \ 'u"
+/etc/hosts
+.sp -1v
+.TP
+~/\&.k5login
+(on remote host) - file containing Kerberos principals that are allowed
+access.
+.SH SEE ALSO
+rlogin(1), kerberos(3), krb_sendauth(3), krb_realmofhost(3), kshd(8)
+.SH BUGS
+If you are using
+.IR csh (1)
+and put a
+.IR rsh (1)
+in the background without redirecting its input away from the terminal,
+it will block even if no reads are posted by the remote command.  If no
+input is desired you should redirect the input of
+.I rsh
+to /dev/null using the
+.B \-n
+option.
+.PP
+You cannot run an interactive command (like
+.IR rogue (6)
+or
+.IR vi (1));
+use
+.IR rlogin (1).
+.PP
+Stop signals stop the local \fIrsh\fP process only; this is arguably
+wrong, but currently hard to fix for reasons too complicated to explain
+here.
diff --git a/mechglue/src/appl/bsd/setenv.c b/mechglue/src/appl/bsd/setenv.c
new file mode 100644
index 000000000..0191d9c8c
--- /dev/null
+++ b/mechglue/src/appl/bsd/setenv.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)setenv.c	5.2 (Berkeley) 6/27/88 */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef NEED_SETENV
+extern int setenv(char *, char *, int);
+extern void unsetenv(char *);
+#endif
+
+static char *_findenv(char *, int*);
+/*
+ * setenv --
+ *	Set the value of the environmental variable "name" to be
+ *	"value".  If rewrite is set, replace any current value.
+ */
+int
+setenv(name, value, rewrite)
+	register char *name, *value;
+	int rewrite;
+{
+	extern char **environ;
+	static int alloced;			/* if allocated space before */
+	register char *C;
+	int l_value, offset;
+
+	if (*value == '=')			/* no `=' in value */
+		++value;
+	l_value = strlen(value);
+	if ((C = _findenv(name, &offset))) {	/* find if already exists */
+		if (!rewrite)
+			return(0);
+		if (strlen(C) >= l_value) {	/* old larger; copy over */
+			while ((*C++ = *value++));
+			return(0);
+		}
+	}
+	else {					/* create new slot */
+		register int	cnt;
+		register char	**P;
+
+		for (P = environ, cnt = 0; *P; ++P, ++cnt);
+		if (alloced) {			/* just increase size */
+			environ = (char **)realloc((char *)environ,
+			    (u_int)(sizeof(char *) * (cnt + 2)));
+			if (!environ)
+				return(-1);
+		}
+		else {				/* get new space */
+			alloced = 1;		/* copy old entries into it */
+			P = (char **)malloc((u_int)(sizeof(char *) *
+			    (cnt + 2)));
+			if (!P)
+				return(-1);
+			memcpy(P, environ, cnt * sizeof(char *));
+			environ = P;
+		}
+		environ[cnt + 1] = NULL;
+		offset = cnt;
+	}
+	for (C = name; *C && *C != '='; ++C);	/* no `=' in name */
+	if (!(environ[offset] =			/* name + `=' + value */
+	    malloc((u_int)((int)(C - name) + l_value + 2))))
+		return(-1);
+	for (C = environ[offset]; (*C = *name++) &&( *C != '='); ++C);
+	for (*C++ = '='; (*C++ = *value++););
+	return(0);
+}
+
+/*
+ * unsetenv(name) --
+ *	Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+	char	*name;
+{
+	extern	char	**environ;
+	register char	**P;
+	int	offset;
+
+	while (_findenv(name, &offset))		/* if set multiple times */
+		for (P = &environ[offset];; ++P)
+			if (!(*P = *(P + 1)))
+				break;
+}
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)getenv.c	5.5 (Berkeley) 6/27/88 */
+
+#ifndef HAVE_GETENV
+/*
+ * getenv --
+ *	Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+	char *name;
+{
+	int offset;
+
+	return(_findenv(name, &offset));
+}
+#endif
+
+/*
+ * _findenv --
+ *	Returns pointer to value associated with name, if any, else NULL.
+ *	Sets offset to be the offset of the name/value combination in the
+ *	environmental array, for use by setenv(3) and unsetenv(3).
+ *	Explicitly removes '=' in argument name.
+ *
+ *	This routine *should* be a static; don't use it.
+ */
+static char *
+_findenv(name, offset)
+	register char *name;
+	int *offset;
+{
+	extern char **environ;
+	register unsigned int len;
+	register char **P, *C;
+
+	for (C = name, len = 0; *C && *C != '='; ++C, ++len);
+	for (P = environ; *P; ++P)
+		if (!strncmp(*P, name, len))
+			if (*(C = *P + len) == '=') {
+				*offset = P - environ;
+				return(++C);
+			}
+	return(NULL);
+}
diff --git a/mechglue/src/appl/bsd/v4rcp.M b/mechglue/src/appl/bsd/v4rcp.M
new file mode 100644
index 000000000..771709fd5
--- /dev/null
+++ b/mechglue/src/appl/bsd/v4rcp.M
@@ -0,0 +1,52 @@
+.\" appl/bsd/v4rcp.M
+.TH RCP 1 \*h
+.SH NAME
+v4rcp \- back end for Kerberos V4 rcp
+.SH SYNOPSIS
+.B v4rcp
+.I not invoked by users
+.SH DESCRIPTION
+This program is
+.B not
+for user execution. The usage message indicates this. 
+.PP
+Kerberos Version 4 
+.I rsh
+did not support encryption. In order to perform
+encrypted file transfer, the version 4
+.I rcp
+program did a second authentication, directly to the 
+.I rcp
+process at the other end. This meant that
+.I rcp
+needed to be
+.IR setuid
+to root in order to read the
+.IR krb-srvtab
+file on the remote end.
+.PP
+Rather than add this complexity into the main Kerberos 5 
+.I rcp
+the Kerberos 5 
+.I kshd
+instead detects the use of Kerberos 4 authentication, and checks the
+command for the program name
+.I rcp
+and then substitutes the full pathname of
+.I v4rcp
+instead.  Since
+.I v4rcp
+is installed
+.IR setuid
+to root, it can perform the the authentication and get the session key
+needed to encrypt the file transfer.
+.PP
+Kerberos 5 
+.I rcp 
+instead uses the encryption support built in to Kerberos 5
+.I rsh
+and
+.I kshd
+directly.
+.SH SEE ALSO
+rsh(1), rcp(1), kshd(8)
diff --git a/mechglue/src/appl/bsd/v4rcp.c b/mechglue/src/appl/bsd/v4rcp.c
new file mode 100644
index 000000000..2354a2c59
--- /dev/null
+++ b/mechglue/src/appl/bsd/v4rcp.c
@@ -0,0 +1,1108 @@
+/* Stripped down Kerberos V4 rcp, for server-side use only */
+/* based on Cygnus CNS V4-96q1 src/appl/bsd/rcp.c. */
+
+/*
+ *	rcp.c
+ */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rcp.c	5.10 (Berkeley) 9/20/88";
+#endif /* not lint */
+
+/*
+ * rcp
+ */
+#ifdef KERBEROS
+#include <krb5.h>
+#include <com_err.h>
+#include <k5-util.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#ifndef KERBEROS
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
+#include <sys/socket.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#ifdef NEED_SYS_FCNTL_H
+#include <sys/fcntl.h>
+#endif
+#include <netinet/in.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <ctype.h>
+#ifndef KERBEROS
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
+#include <netdb.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "port-sockets.h"
+
+#ifdef KERBEROS
+#include <krb.h>
+#include <krbports.h>
+
+
+void sink(int, char **), source(int, char **), 
+    rsource(char *, struct stat *), usage(void);
+/*VARARGS*/
+void 	error (char *fmt, ...)
+#if !defined (__cplusplus) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
+       __attribute__ ((__format__ (__printf__, 1, 2)))
+#endif
+     ;
+int	response(void);
+#if !defined(HAVE_UTIMES)
+int	utimes();
+#endif
+
+
+#if 0
+#include <kstream.h>
+#else
+/* we don't have full kstream in v5, so fake it... */
+
+typedef struct {
+  int encrypting;
+  int read_fd, write_fd;
+  des_key_schedule *sched;
+  des_cblock *ivec;
+  /* used on the read side */
+  char *inbuf;
+  char *outbuf;
+  int writelen;
+  char* retbuf;
+  int retbuflen;
+  int retlen;
+  int returned;
+} *kstream;
+
+static kstream kstream_create_rcp_from_fd(read_fd, write_fd, sched, ivec)
+     int read_fd, write_fd;
+     des_key_schedule *sched;
+     des_cblock *ivec;
+{
+  kstream tmp = (kstream)malloc(sizeof(*tmp));
+  tmp->encrypting = 1;
+  tmp->read_fd = read_fd;
+  tmp->write_fd = write_fd;
+  /* they're static in this file, so just hang on to the pointers */
+  tmp->sched = sched;
+  tmp->ivec = ivec;
+  tmp->inbuf = 0;
+  tmp->outbuf = 0;
+  tmp->writelen = 0;
+  tmp->retbuf = 0;
+  tmp->retbuflen = 0;
+  tmp->returned = 0;
+  tmp->retlen = 0;
+  return tmp;
+}
+
+static kstream kstream_create_from_fd(read_fd, write_fd, sched, session)
+     int read_fd, write_fd;
+     Key_schedule *sched;
+     des_cblock *session;
+{
+  /* just set it up... */
+  kstream tmp = (kstream)malloc(sizeof(*tmp));
+  tmp->encrypting = 0;
+  tmp->read_fd = read_fd;
+  tmp->write_fd = write_fd;
+  return tmp;
+}
+
+
+/* always set to 0 here anyway */
+#define kstream_set_buffer_mode(x,y)
+
+static int kstream_read(krem, buf, len)
+     kstream krem;
+     char *buf;
+     unsigned int len;
+{
+  if(krem->encrypting) {
+    /* when we get a length, we have to read the whole block. However,
+       we have to hand it to the user in the chunks they want, which 
+       may be smaller if BUFSIZ doesn't match. [the caller can deal if
+       the incoming blocks are smaller...] */
+    if (krem->returned) {
+      int remaining = krem->retlen - krem->returned;
+      int returning;
+      
+      if (remaining <= len) {
+	returning = remaining;
+      } else {
+	returning = len;
+      }
+      memcpy(buf, krem->retbuf+krem->returned, returning);
+      krem->returned += returning;
+      if (krem->returned == krem->retlen) krem->returned = 0;
+
+      return returning;
+    }
+
+    /* we need 4 bytes to get a length, and once we have that we know how
+       much to get to fill the buffer. Then we can hand back bits, or loop. */
+    {
+      int cc;
+      unsigned char clen[4];
+      unsigned int x = 0;
+      unsigned int sz, off;
+
+      cc = read(krem->read_fd, clen, 4);
+      if (cc != 4) return cc;
+      x <<= 8; x += clen[0] & 0xff;
+      x <<= 8; x += clen[1] & 0xff;
+      x <<= 8; x += clen[2] & 0xff;
+      x <<= 8; x += clen[3] & 0xff;
+      sz = (x + 7) & (~7U);
+
+      if (krem->retbuflen < sz) {
+	if (krem->retbuflen == 0) 
+	  krem->retbuf = (char*)malloc(sz>(BUFSIZ)?sz:(BUFSIZ));
+	else 
+	  krem->retbuf = (char*)realloc(krem->retbuf, sz);
+	if(!krem->retbuf) { errno = ENOMEM; return -1; }
+	krem->retbuflen = sz>(BUFSIZ)?sz:(BUFSIZ);
+      }
+
+      /* get all of it */
+      off = 0;
+      do {
+	cc = read(krem->read_fd, krem->retbuf+off, sz-off);
+	if (cc <= 0) return cc;
+	off += cc;
+      } while (off < sz);
+      
+      /* decrypt it */
+      des_pcbc_encrypt ((des_cblock *)krem->retbuf, 
+			(des_cblock *)krem->retbuf, 
+			(int) sz, *krem->sched, krem->ivec, 
+			DECRYPT);
+
+      /* now retbuf has sz bytes, return len or x of them to the user */
+      if (x <= len) {
+	memcpy(buf, krem->retbuf, x);
+	return x;
+      } else {
+	memcpy(buf, krem->retbuf, len);
+	/* defer the rest */
+	krem->returned = len;
+	krem->retlen = x;
+	return len;
+      }
+    }
+  } else {
+    return read(krem->read_fd, buf, len);
+  }
+}
+
+static int kstream_write(krem, buf, len)
+     kstream krem;
+     char *buf;
+     unsigned int len;
+{
+  if (krem->encrypting) {
+    unsigned long x;
+    int st;
+    unsigned int outlen = (len + 7) & (~7U);
+
+    if (krem->writelen < outlen) {
+      if (krem->writelen == 0) {
+	krem->inbuf = (char*)malloc(outlen);
+	krem->outbuf = (char*)malloc(outlen+8);
+      } else {
+	krem->inbuf = (char*)realloc(krem->inbuf, outlen);
+	krem->outbuf = (char*)realloc(krem->outbuf, outlen+8);
+      }
+      if(!krem->inbuf || !krem->outbuf) { errno = ENOMEM; return -1; }
+      krem->writelen = outlen;
+    }
+
+    outlen = (len + 7) & (~7U);
+
+    memcpy(krem->inbuf, buf, len);
+    krb5_random_confounder(outlen-len, krem->inbuf+len);
+    buf = krem->inbuf;
+
+    x = len;
+    krem->outbuf[3+4] = x & 0xff; x >>= 8;
+    krem->outbuf[2+4] = x & 0xff; x >>= 8;
+    krem->outbuf[1+4] = x & 0xff; x >>= 8;
+    krem->outbuf[0+4] = x & 0xff; x >>= 8;
+    if (x)
+      abort ();
+    /* memset(outbuf+4+4, 0x42, BUFSIZ); */
+    st = des_pcbc_encrypt ((des_cblock *)buf, (des_cblock *)(krem->outbuf+4+4),
+			   (int) outlen,
+			   *krem->sched, krem->ivec, ENCRYPT);
+
+    if (st) abort();
+    return write(krem->write_fd, krem->outbuf+4, 4+outlen);
+  } else {
+    return write(krem->write_fd, buf, len);
+  }
+}
+
+/* 0 = stdin, read; 1 = stdout, write */
+#define rem 0,1
+
+#endif
+
+
+#ifdef _AUX_SOURCE
+#define vfork fork
+#endif
+#ifdef NOVFORK
+#define vfork fork
+#endif
+
+#ifndef roundup
+#define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
+#endif
+
+int	sock;
+CREDENTIALS cred;
+MSG_DAT msg_data;
+struct sockaddr_in foreign, local;
+Key_schedule schedule;
+
+KTEXT_ST ticket;
+AUTH_DAT kdata;
+static des_cblock crypt_session_key;
+char	krb_realm[REALM_SZ];
+char	**save_argv(int, char **), *krb_realmofhost();
+#ifndef HAVE_STRSAVE
+static char *strsave(char *);
+#endif
+#ifdef NOENCRYPTION
+#define	des_read	read
+#define	des_write	write
+#else /* !NOENCRYPTION */
+void	answer_auth(void);
+int	encryptflag = 0;
+#endif /* NOENCRYPTION */
+#include "rpaths.h"
+#else /* !KERBEROS */
+#define	des_read	read
+#define	des_write	write
+#endif /* KERBEROS */
+
+kstream krem;
+int	errs;
+krb5_sigtype lostconn(int);
+int	iamremote, targetshouldbedirectory;
+int	iamrecursive;
+int	pflag;
+int	force_net;
+struct	passwd *pwd;
+int	userid;
+int	port;
+
+char	*getenv();
+
+struct buffer {
+	int	cnt;
+	char	*buf;
+} *allocbuf(struct buffer *, int, int);
+
+#define	NULLBUF	(struct buffer *) 0
+
+#define	ga()		(void) kstream_write (krem, "", 1)
+
+int main(argc, argv)
+	int argc;
+	char **argv;
+{
+	char portarg[20], rcpportarg[20];
+#ifdef ATHENA
+	static char curhost[256];
+#endif /* ATHENA */
+#ifdef KERBEROS
+	char realmarg[REALM_SZ + 5];
+#endif /* KERBEROS */
+
+	portarg[0] = '\0';
+	rcpportarg[0] = '\0';
+	realmarg[0] = '\0';
+
+	pwd = getpwuid(userid = getuid());
+	if (pwd == 0) {
+		fprintf(stderr, "who are you?\n");
+		exit(1);
+	}
+
+#ifdef KERBEROS
+	krb_realm[0] = '\0';		/* Initially no kerberos realm set */
+#endif /* KERBEROS */
+	for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
+		(*argv)++;
+		while (**argv) switch (*(*argv)++) {
+
+		    case 'r':
+			iamrecursive++;
+			break;
+
+		    case 'p':		/* preserve mtimes and atimes */
+			pflag++;
+			break;
+
+		    case 'P':		/* Set port to use.  */
+			port = atoi(*argv);
+			sprintf(portarg, " -p%d", port);
+			sprintf(rcpportarg, " -P%d", port);
+			port = htons(port);
+			goto next_arg;
+
+		    case 'N':
+			/* Force use of network even on local machine.  */
+			force_net++;
+			break;
+
+#ifdef KERBEROS
+#ifndef NOENCRYPTION
+		    case 'x':
+			encryptflag++;
+			break;
+#endif
+		    case 'k':		/* Change kerberos realm */
+			argc--, argv++;
+			if (argc == 0) 
+			  usage();
+			strncpy(krb_realm,*argv,REALM_SZ);
+			krb_realm[REALM_SZ-1] = 0;
+			sprintf(realmarg, " -k %s", krb_realm);
+			goto next_arg;
+#endif /* KERBEROS */
+		    /* The rest of these are not for users. */
+		    case 'd':
+			targetshouldbedirectory = 1;
+			break;
+
+		    case 'f':		/* "from" */
+			iamremote = 1;
+#if defined(KERBEROS) && !defined(NOENCRYPTION)
+			if (encryptflag) {
+				answer_auth();
+				krem = kstream_create_rcp_from_fd (rem,
+								   &schedule,
+								   &crypt_session_key);
+			} else
+				krem = kstream_create_from_fd (rem, 0, 0);
+			kstream_set_buffer_mode (krem, 0);
+#endif /* KERBEROS && !NOENCRYPTION */
+			(void) response();
+			(void) setuid(userid);
+			source(--argc, ++argv);
+			exit(errs);
+
+		    case 't':		/* "to" */
+			iamremote = 1;
+#if defined(KERBEROS) && !defined(NOENCRYPTION)
+			if (encryptflag) {
+				answer_auth();
+				krem = kstream_create_rcp_from_fd (rem,
+								   &schedule,
+								   &crypt_session_key);
+			} else
+				krem = kstream_create_from_fd (rem, 0, 0);
+			kstream_set_buffer_mode (krem, 0);
+#endif /* KERBEROS && !NOENCRYPTION */
+			(void) setuid(userid);
+			sink(--argc, ++argv);
+			exit(errs);
+
+		    default:
+			usage();
+		}
+#ifdef KERBEROS
+	      next_arg: ;
+#endif /* KERBEROS */
+	}
+	usage();
+	return 1;
+}
+
+static void verifydir(cp)
+	char *cp;
+{
+	struct stat stb;
+
+	if (stat(cp, &stb) >= 0) {
+		if ((stb.st_mode & S_IFMT) == S_IFDIR)
+			return;
+		errno = ENOTDIR;
+	}
+	error("rcp: %s: %s.\n", cp, error_message(errno));
+	exit(1);
+}
+
+void source(argc, argv)
+	int argc;
+	char **argv;
+{
+	char *last, *name;
+	struct stat stb;
+	static struct buffer buffer;
+	struct buffer *bp;
+	int x, readerr, f;
+	unsigned int amt;
+	off_t i;
+	char buf[BUFSIZ];
+
+	for (x = 0; x < argc; x++) {
+		name = argv[x];
+		if ((f = open(name, 0)) < 0) {
+			error("rcp: %s: %s\n", name, error_message(errno));
+			continue;
+		}
+		if (fstat(f, &stb) < 0)
+			goto notreg;
+		switch (stb.st_mode&S_IFMT) {
+
+		case S_IFREG:
+			break;
+
+		case S_IFDIR:
+			if (iamrecursive) {
+				(void) close(f);
+				rsource(name, &stb);
+				continue;
+			}
+			/* fall into ... */
+		default:
+notreg:
+			(void) close(f);
+			error("rcp: %s: not a plain file\n", name);
+			continue;
+		}
+		last = strrchr(name, '/');
+		if (last == 0)
+			last = name;
+		else
+			last++;
+		if (pflag) {
+			/*
+			 * Make it compatible with possible future
+			 * versions expecting microseconds.
+			 */
+			(void) sprintf(buf, "T%ld 0 %ld 0\n",
+			    stb.st_mtime, stb.st_atime);
+			kstream_write (krem, buf, strlen (buf));
+			if (response() < 0) {
+				(void) close(f);
+				continue;
+			}
+		}
+		(void) sprintf(buf, "C%04o %ld %s\n",
+		    (unsigned int) stb.st_mode&07777, (long) stb.st_size, last);
+		kstream_write (krem, buf, strlen (buf));
+		if (response() < 0) {
+			(void) close(f);
+			continue;
+		}
+		if ((bp = allocbuf(&buffer, f, BUFSIZ)) == NULLBUF) {
+			(void) close(f);
+			continue;
+		}
+		readerr = 0;
+		for (i = 0; i < stb.st_size; i += bp->cnt) {
+			amt = bp->cnt;
+			if (i + amt > stb.st_size)
+				amt = stb.st_size - i;
+			if (readerr == 0 && read(f, bp->buf, amt) != amt)
+				readerr = errno;
+			kstream_write (krem, bp->buf, amt);
+		}
+		(void) close(f);
+		if (readerr == 0)
+			ga();
+		else
+			error("rcp: %s: %s\n", name, error_message(readerr));
+		(void) response();
+	}
+}
+
+#ifndef USE_DIRENT_H
+#include <sys/dir.h>
+#else
+#include <dirent.h>
+#endif
+
+void rsource(name, statp)
+	char *name;
+	struct stat *statp;
+{
+	DIR *d = opendir(name);
+	char *last;
+	char buf[BUFSIZ];
+	char *bufv[1];
+#ifdef USE_DIRENT_H
+	struct dirent *dp;
+#else
+	struct direct *dp;
+#endif
+
+	if (d == 0) {
+		error("rcp: %s: %s\n", name, error_message(errno));
+		return;
+	}
+	last = strrchr(name, '/');
+	if (last == 0)
+		last = name;
+	else
+		last++;
+	if (pflag) {
+		(void) sprintf(buf, "T%ld 0 %ld 0\n",
+		    statp->st_mtime, statp->st_atime);
+		kstream_write (krem, buf, strlen (buf));
+		if (response() < 0) {
+			closedir(d);
+			return;
+		}
+	}
+	(void) sprintf(buf, "D%04o %d %s\n",
+		       (unsigned int) statp->st_mode&07777, 0, last);
+	kstream_write (krem, buf, strlen (buf));
+	if (response() < 0) {
+		closedir(d);
+		return;
+	}
+	while ((dp = readdir(d))) {
+		if (dp->d_ino == 0)
+			continue;
+		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+			continue;
+		if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
+			error("%s/%s: Name too long.\n", name, dp->d_name);
+			continue;
+		}
+		(void) sprintf(buf, "%s/%s", name, dp->d_name);
+		bufv[0] = buf;
+		source(1, bufv);
+	}
+	closedir(d);
+	kstream_write (krem, "E\n", 2);
+	(void) response();
+}
+
+int response()
+{
+	char resp, c, rbuf[BUFSIZ], *cp = rbuf;
+
+	if (kstream_read (krem, &resp, 1) != 1)
+		lostconn(0);
+	switch (resp) {
+
+	case 0:				/* ok */
+		return (0);
+
+	default:
+		*cp++ = resp;
+		/* fall into... */
+	case 1:				/* error, followed by err msg */
+	case 2:				/* fatal error, "" */
+		do {
+			if (kstream_read (krem, &c, 1) != 1)
+				lostconn(0);
+			*cp++ = c;
+		} while (cp < &rbuf[BUFSIZ] && c != '\n');
+		if (iamremote == 0)
+			(void) write(2, rbuf, (unsigned) (cp - rbuf));
+		errs++;
+		if (resp == 1)
+			return (-1);
+		exit(1);
+	}
+	/*NOTREACHED*/
+	return -1;
+}
+
+krb5_sigtype lostconn(signum)
+    int signum;
+{
+
+	if (iamremote == 0)
+		fprintf(stderr, "rcp: lost connection\n");
+	exit(1);
+}
+
+#if !defined(HAVE_UTIMES)
+#include <utime.h>
+#include <sys/time.h>
+
+/*
+ * We emulate utimes() instead of utime() as necessary because
+ * utimes() is more powerful than utime(), and rcp actually tries to
+ * set the microsecond values; we don't want to take away
+ * functionality unnecessarily.
+ */
+int utimes(file, tvp)
+const char *file;
+struct timeval *tvp;
+{
+	struct utimbuf times;
+
+	times.actime = tvp[0].tv_sec;
+	times.modtime = tvp[1].tv_sec;
+	return(utime(file, ×));
+}
+#endif
+
+void sink(argc, argv)
+	int argc;
+	char **argv;
+{
+	off_t i, j;
+	char *targ, *whopp, *cp;
+	int of, wrerr, exists, first, amt;
+	mode_t mode;
+	unsigned int count;
+	off_t size;
+	struct buffer *bp;
+	static struct buffer buffer;
+	struct stat stb;
+	int targisdir = 0;
+	mode_t mask = umask(0);
+	char *myargv[1];
+	char cmdbuf[BUFSIZ], nambuf[BUFSIZ];
+	int setimes = 0;
+	struct timeval tv[2];
+#define atime	tv[0]
+#define mtime	tv[1]
+#define	SCREWUP(str)	{ whopp = str; goto screwup; }
+
+	if (!pflag)
+		(void) umask(mask);
+	if (argc != 1) {
+		error("rcp: ambiguous target\n");
+		exit(1);
+	}
+	targ = *argv;
+	if (targetshouldbedirectory)
+		verifydir(targ);
+	ga();
+	if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
+		targisdir = 1;
+	for (first = 1; ; first = 0) {
+		cp = cmdbuf;
+		if (kstream_read (krem, cp, 1) <= 0)
+			return;
+		if (*cp++ == '\n')
+			SCREWUP("unexpected '\\n'");
+		do {
+			if (kstream_read(krem, cp, 1) != 1)
+				SCREWUP("lost connection");
+		} while (*cp++ != '\n');
+		*cp = 0;
+		if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
+			if (iamremote == 0)
+				(void) write(2, cmdbuf+1, strlen(cmdbuf+1));
+			if (cmdbuf[0] == '\02')
+				exit(1);
+			errs++;
+			continue;
+		}
+		*--cp = 0;
+		cp = cmdbuf;
+		if (*cp == 'E') {
+			ga();
+			return;
+		}
+
+#define getnum(t) (t) = 0; while (isdigit((int) *cp)) (t) = (t) * 10 + (*cp++ - '0');
+		if (*cp == 'T') {
+			setimes++;
+			cp++;
+			getnum(mtime.tv_sec);
+			if (*cp++ != ' ')
+				SCREWUP("mtime.sec not delimited");
+			getnum(mtime.tv_usec);
+			if (*cp++ != ' ')
+				SCREWUP("mtime.usec not delimited");
+			getnum(atime.tv_sec);
+			if (*cp++ != ' ')
+				SCREWUP("atime.sec not delimited");
+			getnum(atime.tv_usec);
+			if (*cp++ != '\0')
+				SCREWUP("atime.usec not delimited");
+			ga();
+			continue;
+		}
+		if (*cp != 'C' && *cp != 'D') {
+			/*
+			 * Check for the case "rcp remote:foo\* local:bar".
+			 * In this case, the line "No match." can be returned
+			 * by the shell before the rcp command on the remote is
+			 * executed so the ^Aerror_message convention isn't
+			 * followed.
+			 */
+			if (first) {
+				error("%s\n", cp);
+				exit(1);
+			}
+			SCREWUP("expected control record");
+		}
+		cp++;
+		mode = 0;
+		for (; cp < cmdbuf+5; cp++) {
+			if (*cp < '0' || *cp > '7')
+				SCREWUP("bad mode");
+			mode = (mode << 3) | (*cp - '0');
+		}
+		if (*cp++ != ' ')
+			SCREWUP("mode not delimited");
+		size = 0;
+		while (isdigit((int) *cp))
+			size = size * 10 + (*cp++ - '0');
+		if (*cp++ != ' ')
+			SCREWUP("size not delimited");
+		if (targisdir) {
+			if (strlen(targ) + strlen(cp) + 1 < sizeof(nambuf)) {
+				(void) sprintf(nambuf, "%s%s%s", targ,
+				    *targ ? "/" : "", cp);
+			} else {
+				SCREWUP("target directory name too long");
+			}
+		} else {
+		    if (strlen(targ) + 1 < sizeof(nambuf))
+			(void) strncpy(nambuf, targ, sizeof(nambuf)-1);
+		    else
+			SCREWUP("target pathname too long");
+		}
+		nambuf[sizeof(nambuf)-1] = '\0';
+		exists = stat(nambuf, &stb) == 0;
+		if (cmdbuf[0] == 'D') {
+			if (exists) {
+				if ((stb.st_mode&S_IFMT) != S_IFDIR) {
+					errno = ENOTDIR;
+					goto bad;
+				}
+				if (pflag)
+					(void) chmod(nambuf, mode);
+			} else if (mkdir(nambuf, mode) < 0)
+				goto bad;
+			myargv[0] = nambuf;
+			sink(1, myargv);
+			if (setimes) {
+				setimes = 0;
+				if (utimes(nambuf, tv) < 0)
+					error("rcp: can't set times on %s: %s\n",
+					    nambuf, error_message(errno));
+			}
+			continue;
+		}
+		if ((of = open(nambuf, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) {
+	bad:
+			error("rcp: %s: %s\n", nambuf, error_message(errno));
+			continue;
+		}
+#ifdef NO_FCHMOD
+		if (exists && pflag)
+			(void) chmod(nambuf, mode);
+#else
+		if (exists && pflag)
+			(void) fchmod(of, mode);
+#endif
+		ga();
+		if ((bp = allocbuf(&buffer, of, BUFSIZ)) == NULLBUF) {
+			(void) close(of);
+			continue;
+		}
+		cp = bp->buf;
+		count = 0;
+		wrerr = 0;
+		for (i = 0; i < size; i += BUFSIZ) {
+			amt = BUFSIZ;
+			if (i + amt > size)
+				amt = size - i;
+			count += amt;
+			do {
+				j = kstream_read(krem, cp, amt);
+				if (j <= 0) {
+					if (j == 0)
+					    error("rcp: dropped connection");
+					else
+					    error("rcp: %s\n",
+						error_message(errno));
+					exit(1);
+				}
+				amt -= j;
+				cp += j;
+			} while (amt > 0);
+			if (count == bp->cnt) {
+				if (wrerr == 0 &&
+				    write(of, bp->buf, count) != count)
+					wrerr++;
+				count = 0;
+				cp = bp->buf;
+			}
+		}
+		if (count != 0 && wrerr == 0 &&
+		    write(of, bp->buf, count) != count)
+			wrerr++;
+#ifndef __SCO__
+		if (ftruncate(of, size))
+			error("rcp: can't truncate %s: %s\n",
+			    nambuf, error_message(errno));
+#endif
+		(void) close(of);
+		(void) response();
+		if (setimes) {
+			setimes = 0;
+			if (utimes(nambuf, tv) < 0)
+				error("rcp: can't set times on %s: %s\n",
+				    nambuf, error_message(errno));
+		}				   
+		if (wrerr)
+			error("rcp: %s: %s\n", nambuf, error_message(errno));
+		else
+			ga();
+	}
+screwup:
+	error("rcp: protocol screwup: %s\n", whopp);
+	exit(1);
+}
+
+struct buffer *
+allocbuf(bp, fd, blksize)
+	struct buffer *bp;
+	int fd, blksize;
+{
+	int size;
+#ifndef NOSTBLKSIZE
+	struct stat stb;
+
+	if (fstat(fd, &stb) < 0) {
+		error("rcp: fstat: %s\n", error_message(errno));
+		return (NULLBUF);
+	}
+	size = roundup(stb.st_blksize, blksize);
+	if (size == 0)
+#endif
+		size = blksize;
+	if (bp->cnt < size) {
+		if (bp->buf != 0)
+			free(bp->buf);
+		bp->buf = (char *)malloc((unsigned) size);
+		if (bp->buf == 0) {
+			error("rcp: malloc: out of memory\n");
+			return (NULLBUF);
+		}
+	}
+	bp->cnt = size;
+	return (bp);
+}
+
+void
+#ifdef HAVE_STDARG_H
+error(char *fmt, ...)
+#else
+/*VARARGS1*/
+error(fmt, va_alist)
+     char *fmt;
+     va_dcl
+#endif
+{
+    va_list ap;
+    char buf[BUFSIZ], *cp = buf;
+    
+#ifdef HAVE_STDARG_H
+    va_start(ap, fmt);
+#else
+    va_start(ap);
+#endif
+
+    errs++;
+    *cp++ = 1;
+    (void) vsprintf(cp, fmt, ap);
+    va_end(ap);
+
+    if (krem)
+	(void) kstream_write(krem, buf, strlen(buf));
+    if (iamremote == 0)
+	(void) write(2, buf+1, strlen(buf+1));
+}
+
+void usage()
+{
+  fprintf(stderr,
+"v4rcp: this program only acts as a server, and is not for user function.\n");
+  exit(1);
+}
+
+#ifdef KERBEROS
+
+char **
+save_argv(argc, argv)
+int argc;
+char **argv;
+{
+	register int i;
+
+	char **local_argv = (char **)calloc((unsigned) argc+1,
+					    (unsigned) sizeof(char *));
+	/* allocate an extra pointer, so that it is initialized to NULL
+	   and execv() will work */
+	for (i = 0; i < argc; i++)
+		local_argv[i] = strsave(argv[i]);
+	return(local_argv);
+}
+
+#ifndef HAVE_STRSAVE
+static char *
+strsave(sp)
+char *sp;
+{
+	register char *ret;
+	
+	if((ret = (char *)malloc((unsigned) strlen(sp)+1)) == NULL) {
+		fprintf(stderr, "rcp: no memory for saving args\n");
+		exit(1);
+	}
+	(void) strcpy(ret,sp);
+	return(ret);
+}
+#endif
+
+#ifndef NOENCRYPTION
+#undef rem
+#define rem 0
+
+void
+answer_auth()
+{
+	int status;
+	long authopts = KOPT_DO_MUTUAL;
+	char instance[INST_SZ];
+	char version[9];
+	char *srvtab;
+	char *envaddr;
+
+#if 0
+	int sin_len;
+	
+	sin_len = sizeof (struct sockaddr_in);
+	if (getpeername(rem, &foreign, &sin_len) < 0) {
+		perror("getpeername");
+		exit(1);
+	}
+
+	sin_len = sizeof (struct sockaddr_in);
+	if (getsockname(rem, &local, &sin_len) < 0) {
+		perror("getsockname");
+		exit(1);
+	}
+#else
+	if ((envaddr = getenv("KRB5LOCALADDR"))) {
+#ifdef HAVE_INET_ATON
+	  inet_aton(envaddr,  &local.sin_addr);
+#else
+	  local.sin_addr.s_addr = inet_addr(envaddr);
+#endif
+	  local.sin_family = AF_INET;
+	  envaddr = getenv("KRB5LOCALPORT");
+	  if (envaddr)
+	    local.sin_port = htons(atoi(envaddr));
+	  else
+	    local.sin_port = 0;
+	} else {
+	  fprintf(stderr, "v4rcp: couldn't get local address (KRB5LOCALADDR)\n");
+	  exit(1);
+	}
+	if ((envaddr = getenv("KRB5REMOTEADDR"))) {
+#ifdef HAVE_INET_ATON
+	  inet_aton(envaddr,  &foreign.sin_addr);
+#else
+	  foreign.sin_addr.s_addr = inet_addr(envaddr);
+#endif
+	  foreign.sin_family = AF_INET;
+	  envaddr = getenv("KRB5REMOTEPORT");
+	  if (envaddr)
+	    foreign.sin_port = htons(atoi(envaddr));
+	  else
+	    foreign.sin_port = 0;
+	} else {
+	  fprintf(stderr, "v4rcp: couldn't get remote address (KRB5REMOTEADDR)\n");
+	  exit(1);
+	}
+
+#endif
+	strcpy(instance, "*");
+
+	/* If rshd was invoked with the -s argument, it will set the
+           environment variable KRB_SRVTAB.  We use that to get the
+           srvtab file to use.  If we do use the environment variable,
+           we reset to our real user ID (which will already have been
+           set up by rsh).  Since rcp is setuid root, we would
+           otherwise have a security hole.  If we are using the normal
+           srvtab (KEYFILE in krb.h, normally set to /etc/krb-srvtab),
+           we must keep our effective uid of root, because that file
+           can only be read by root.  */
+	srvtab = (char *) getenv("KRB_SRVTAB");
+	if (srvtab == NULL)
+		srvtab = "";
+	if (*srvtab != '\0')
+		(void) setuid (userid);
+
+	if ((status = krb_recvauth(authopts, rem, &ticket, "rcmd", instance,
+				   &foreign,
+				   &local,
+				   &kdata,
+				   srvtab,
+				   schedule,
+				   version)) != KSUCCESS) {
+		fprintf(stderr, "krb_recvauth mutual fail: %s\n",
+			krb_get_err_text(status));
+		exit(1);
+	}
+	memcpy(&crypt_session_key, &kdata.session, sizeof (crypt_session_key));
+	return;
+}
+#endif /* !NOENCRYPTION */
+
+#endif /* KERBEROS */
diff --git a/mechglue/src/appl/configure.in b/mechglue/src/appl/configure.in
new file mode 100644
index 000000000..e6114f287
--- /dev/null
+++ b/mechglue/src/appl/configure.in
@@ -0,0 +1,21 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+KRB5_AC_INET6
+AC_PROG_INSTALL
+AC_CHECK_HEADERS(unistd.h stdlib.h string.h)
+AC_C_CONST
+dnl gss-misc.c needs this:
+AC_CHECK_HEADERS(sys/time.h time.h)
+dnl
+dnl Kludge for simple server --- FIXME is this the best way to do this?
+dnl
+if test "$ac_cv_lib_socket" = "yes" -a "$ac_cv_lib_nsl" = "yes"; then
+	AC_DEFINE(BROKEN_STREAMS_SOCKETS)
+fi
+dnl
+dnl
+KRB5_GETSOCKNAME_ARGS
+KRB5_GETPEERNAME_ARGS
+KRB5_BUILD_PROGRAM
+AC_CONFIG_SUBDIRS(bsd gssftp telnet)
+V5_AC_OUTPUT_MAKEFILE(. sample sample/sclient sample/sserver simple simple/client simple/server gss-sample user_user)
diff --git a/mechglue/src/appl/gss-sample/.Sanitize b/mechglue/src/appl/gss-sample/.Sanitize
new file mode 100644
index 000000000..a95bfeb39
--- /dev/null
+++ b/mechglue/src/appl/gss-sample/.Sanitize
@@ -0,0 +1,40 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+README
+configure
+configure.in
+gss-client.c
+gss-misc.c
+gss-server.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/gss-sample/ChangeLog b/mechglue/src/appl/gss-sample/ChangeLog
new file mode 100644
index 000000000..15f674580
--- /dev/null
+++ b/mechglue/src/appl/gss-sample/ChangeLog
@@ -0,0 +1,477 @@
+2005-10-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss-client.c, gss-misc.c, gss-server.c: Reindented.
+
+	* gss-server.c (logfile): Renamed from "log", and made static.
+
+2005-10-20  Ken Raeburn  <raeburn@mit.edu>
+	    Jeffrey Altman  <jaltman@mit.edu>
+
+	* gss-server.c [!_WIN32]: Include port-sockets.h instead of the
+	various network-related UNIX header files.
+	(worker_bee): New function.
+	(main): Use it.
+	(max_threads): New variable.
+	(thread_count, hMutex, hEvent) [_WIN32]: New variables.
+	(InitHandles, CleanupHandles, WaitAndIncrementThreadCounter,
+	DecrementAndSignalThreadCounter) [_WIN32]: New functions.
+	(main) [_WIN32]: Accept new option -threads, and keep that many
+	threads going.
+	(usage) [_WIN32]: Document new option.
+
+	* gss-client.c [!_WIN32]: Include assert.h.
+	(max_threads): New variable.
+	(service_name, server_host, msg, mechanism, port, use_file,
+	gss_flags, min_stat, oid, mcount, ccount, auth_flag, wrap_flag,
+	encrypt_flag, mic_flag, v1_format): Moved variables to top level
+	from inside main.
+	(worker_bee): New function, with call_server call moved from
+	main.
+	(main): Call it.
+	(thread_count, hMutex, hEvent) [_WIN32]: New variables.
+	(InitHandles, CleanupHandles, WaitAndIncrementThreadCounter,
+	DecrementAndSignalThreadCounter) [_WIN32]: New functions.
+	(main) [_WIN32]: Accept new option -threads, and keep that many
+	threads going.
+	(usage) [_WIN32]: Document new option.
+
+	* gss-misc.c (send_token): Delete unused variable "len".
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2003-02-26  Jeffrey Altman <jaltman@mit.edu>
+
+    * gss-client.c: merge if (this) if (that) into if (this && that)
+
+2004-02-10  Jeffrey Altman <jaltman@mit.edu>
+
+    * gss-client.c: Remove extraneous parameters from 
+      client_establish_context()
+
+2004-02-06  Jeffrey Altman <jaltman@mit.edu>
+
+    * Update usage() for gss-client
+
+2004-02-06  Jeffrey Altman <jaltman@mit.edu>
+
+    * Add new command line switches to the gss-client
+      to support the use of GSS_C_SEQUENCE_FLAG or to 
+      disable the use of either GSS_C_MUTUAL_FLAG or 
+      GSS_C_REPLAY_FLAG
+
+2004-01-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss-misc.c: Include sys/time.h or time.h, to get struct timeval
+	declaration.
+
+2004-01-30  Jeffrey Altman <jaltman@mit.edu>
+
+    * gss-misc.c (read_all): Add call to select() so we don't block forever
+
+    * gss-server.c (main): Add missing "export" parameter to second sign_server()
+
+2003-01-08  Sam Hartman  <hartmans@mit.edu>
+
+	* gss-misc.c (recv_token): Support reading 0 token flags as part of length
+
+	* gss-client.c :  Support a -v1 argument meaning that no token flags are used,
+
+	* gss-misc.c (send_token): If token flags are null, do not send them.
+
+2002-12-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss-misc.c (send_token, recv_token): Open-code the math to send
+	and receive the length as four bytes in network order, rather than
+	using the first four bytes of a size_t.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(OUTPRE)gss-server.exe, $(OUTPRE)gss-server.exe):
+	Use ws2_32.lib instead of wsock32.lib.
+
+2002-04-30  Sam Hartman  <hartmans@mit.edu>
+
+	* gss-server.c (server_establish_context): Same here.
+
+	* gss-client.c (client_establish_context):  delete the context
+	when it is non-null, not when it is null. 
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* gss-client.c, gss-misc.c, gss-server.c: Cast buffer length to
+	int in length argument for printf.
+
+2001-11-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* gss-server.c (server_establish_context, sign_server): Ensure
+	that memory blocks are only freed once.
+
+2001-11-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* gss-misc.c (recv_token): Do not attempt to malloc 0 bytes.
+
+2001-11-01  Sam Hartman  <hartmans@mit.edu>
+
+	* gss-server.c  gss-client.c:  Only free buffers returned from
+	GSSAPI using  gss_release_buffer
+
+	* gss-client.c (client_establish_context): Trailing null should
+	not be part of service name 
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss-misc.c, gss-misc.h: Make prototypes unconditional.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Use srcdir.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* gss-client.c (parse_oid): Cast argument to isdigit() to int.
+
+	* gss-server.c (sign_server): Cast argument to isspace() to int.
+
+2001-05-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* gss-server.c (usage): Fix usage info *again* to reflect that
+	service_name is required.
+
+Tue Sep 26 18:13:54 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* gss-misc.c: Include <sys/socket.h> for prototype definitions. 
+
+	* gss-client.c gss-server.c: Warning cleanups.
+
+2000-02-11  Tom Yu  <tlyu@mit.edu>
+
+	* README, gss-client.c, gss-misc.c, gss-misc.h, gss-server.c:
+	Patches from jik to make gss-sample more versatile.
+
+2000-01-31  Danilo Almeida  <dalmeida@mit.edu>
+
+	* gss-client.c, gss-server.c, gss-misc.c: Include Windows headers
+	instead of Unix headers under Windows.
+
+	* gss-server.c (usage): Fix usage info to reflect that service_name is
+	required.
+
+	* gss-misc.c (read_all, write_all): Change write to send and read
+	to recv for portability.
+	(gettimeofday): Add an implementation of gettimeofday() for
+	Windows.
+
+	* Makefile.in: Build under Windows.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon Dec 21 22:04:02 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gss-server.c (test_import_export_context): Fix memory leak.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Removed and tests moved up to appl/configure.in
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS macro set to '.' to indicate that there
+		are no subdirectories to be processed by the Makefile.
+
+1998-10-24  Marc Horowitz  <marc@mit.edu>
+
+	* gss-server.c (sign_server): fix the text heuristic to recognize
+		whitespace as text.
+	(main): clean up file descriptors properly after each
+		connection.
+
+	* gss-client.c (read_file): properly handle empty files
+
+	* gss-client.c: (call_server): NUL-terminate the contents
+		of non-empty files on the wire.
+	
+Wed Feb 18 15:27:32 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from BUILDTOP.  Fix up
+	BUILDTOP for new conventions.
+
+Sat Feb 14 10:33:20 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Remove USE_ANAME
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Sep 18 17:52:26 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Replace USE_STRING_H with something more sane.
+
+	* gss-server.c: Replace USE_STRING_H with something more sane.
+
+Fri Jun  6 15:05:57 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gss-server.c (server_establish_context): Rearrange server
+		establish context loop to match with the
+		draft-ietf-gssv2-cbind-04.txt suggestion --- always send
+		the output token even in the case of an error, and call
+		gss_delete_sec_context() if needed.
+
+	* gss-client.c (client_establish_context): Check for error
+		condition after sending the output token, if present.  In
+		case of error, call delete_sec_context if necessary.
+
+Wed Feb  5 20:25:57 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Fri Nov 22 15:48:02 1996  unknown  <bjaspan@mit.edu>
+
+	* gss-client.c (connect_to_server): use sizeof instead of h_length
+ 	to determine number of bytes of addr to copy from DNS response
+ 	[krb5-misc/211]
+
+Sun Oct 27 22:04:59 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add USE_GSSAPI_LIBRARY
+
+	* Makefile.in (LOCAL_LIBRARIES): Remove as -lgssapi_rpc should
+		come from configure.  
+
+Mon Oct 21 20:03:53 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gss-server.c: Re-added code to test import and export security
+ 		context.  Yes, yes, I know this isn't the best place to
+ 		have this test, but DO NOT REMOVE THIS TEST UNTIL WE HAVE
+ 		IT CODED ELSEWHERE.  Better slightly ugly sample server
+ 		code than untested (and broken) library code....  Add code
+ 		to print out the mechanism OID used by accept_sec_context.
+
+	* gss-client.c: Add code to allow user to specify the mechanism
+		OID that gss-client should use.
+
+Wed Jun  5 00:08:32 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gss-client.c (call_server): When reading in the test value from
+ 		a file, don't free free inbuf.value until after the last
+ 		place where we use it.
+
+Wed Apr 17 20:54:37 1996  Marc Horowitz  <marc@mit.edu>
+
+	* all files: integrated changes from OpenVision as of
+	October 1995
+
+Tue Mar 12 23:46:26 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* gss-server.c (timeval_subtract): Use old-style function
+	definition.
+
+Sun Mar  3 12:14:48 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gss-server.c (test_import_export_context): Add second argument
+		to gettimeofday.
+
+Sat Mar  2 03:03:27 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss-server.c (sign_server): Do better import/export security
+		checking.  If the received message to be signed is not
+		printable (at least the first two characters are not),
+		display the message in hex.  Print the hex values of the
+		incoming and outcoming packets, for your information.
+
+	* gss-misc.c (print_token, display_buffer): Two new tokens for
+		displaying GSSAPI buffers, either has hex or as a
+		printable string.
+
+	* gss-client.c (call_server): Add option to support reading in the
+		message to be signed from a file.
+
+Wed Feb 28 11:42:26 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss-client.c (call_server): Get the nametype OID from
+		gss_display_name, print it, and then release the nametype
+		OID.  This tests gss_display_name()'s ability to return a
+		valid nametype, which can then be freed successfully.
+
+Tue Feb 27 17:26:15 1996  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* configure.in: Add USE_ANAME.
+
+Wed Jan  3 21:55:30 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss-client.c (main, client_establish_context): If the -d flag is
+		given to the client, then try to delegate credentials when
+		establishing the context.
+
+Thu Oct 12 11:15:28 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gss-misc.c (recv_token): When continuing partial read, decrease
+		number of bytes to read.
+
+Sun Oct  8 14:26:25 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gss-misc.c (recv_token): When looping for partial read from
+		network, start reading in the middle of the token.
+
+Wed Sep 27 18:36:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss-client.c (main): Set display_file to be stdout.
+
+	* gss-server.c (main): Set display_file to 0 if using inetd;
+		otherwise, set it to be stdout.
+
+	* gss-misc.c (send_token, recv_token, display_status): If
+	        display_file is null, don't set it to stderr; just don't
+		print the log message instead.  Needed for inetd operation.
+
+Sat Sep 16 03:34:59 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss-server.c (sign_server): Only try using gss_export_context
+		and gss_import_context if the dov2 flag has been set.
+		(server_establish_context): Make sure the client
+		gss_name_t is released.
+		(main): Add a -once option which causes the gss-server to
+		exit after processing one client.  Allows purify to report
+		memory leaks.
+
+Thu Sep 14 22:44:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss-server.c (create_socket): add setsockopt SO_REUSEADDR so
+		that the socket can be reused right away.
+
+Mon Sep  4 14:19:03 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gss-misc.c: Either include stdlib.h or declare malloc.
+
+	* configure.in: Check for stdlib.h
+
+Thu Aug 31 11:35:07 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add -DUSE_AUTOCONF_H and -DGSSAPI_V2 to enable usage
+		of autoconf.h in gssapi.h and to enable V2 features in local
+		modules.
+	* gss-client.c, gss-server.c - Add -v2 switch to use V2 features.
+		Clean up V2 argument changes.
+	* gss-misc.c - Clean up V2 argument change.
+
+
+Tue Aug 29 13:24:50 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gss-{client,server}.c - Test gss_{ex,im}port_sec_context().
+
+
+Fri Jul 7 15:41:47 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling.
+	* configure.in - Add KRB5_LIBRARIES.
+
+
+Thu Jun 15 17:35:08 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+		Also, remove DBMLIB, it was not used.
+        * configure.in - Add shared library usage check.
+
+Sat Jun 10 19:06:03 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gss-misc.c (recv_token): Initialize local variable to 0.
+
+Sat Jun 10 00:28:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss-misc.c (recv_token): Allow for partial reads while reading
+		the token.
+
+Fri Jun  9 18:26:50 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed May 24 11:11:45 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gss-client.c: Include string.h or strings.h
+
+	* gss-server.c: Include string.h or strings.h
+
+	* configure.in: Check for string.h
+
+Mon May 22 15:41:33 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gss-server.c	: (server_establish_context) Don't call gss_release_
+			  buffer right after gss_accept_sec_context because
+			  in the event that we choke, we lose the minor status
+
+Fri Apr 28 15:30:00 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (gss-client): Use $(LD) instead of $(CC) so that we can
+		do purify checking.
+
+	* gss-server.c (main, sign_server): Make changes to allow
+		gss-server to be fired out of inetd.  New options: -inetd
+		and -logfile.  The -logfile allows the output of
+		gss-server to be redirected to a file.
+
+	* gss-misc.c (send_token, recv_token, display_status_1): Add
+	        support for -logfile option.  If the external FILE
+		*display_file is set, redirect error messages to
+		display_file instead of stderr.
+
+Wed Apr 26 17:17:22 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: use AC_CONST since we don't learn it from the krb5
+	headers and gssapi.h uses it.
+
+Thu Mar  2 12:29:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 11:55:15 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Fri Feb  3 06:21:02 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* gss-server.c: ret_flags should be an int based on the prototype
+		of gss_accept_sec_context.
+
+Wed Oct 19 12:32:41 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Obey CCOPTS in CFLAGS declaration
+
+Wed Oct 12 02:29:38 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Add OBJS definition so that object files get
+		cleaned out during a "make clean".
+
+Thu Sep 29 22:50:48 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executables if libraries change
+
+Thu Aug  4 13:24:29 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: fix make install
+
+Thu Jul 21 01:02:28 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: fix infinite recursion in rules
+	* gss-client.c:
+	* gss-misc.c:
+	* gss-server.c: downgrade to K&R function definitions
+
+Tue Jul 19 20:28:46 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in:
+	* configre.in: changes to make autoconf work
+
diff --git a/mechglue/src/appl/gss-sample/Makefile.in b/mechglue/src/appl/gss-sample/Makefile.in
new file mode 100644
index 000000000..ab6821c49
--- /dev/null
+++ b/mechglue/src/appl/gss-sample/Makefile.in
@@ -0,0 +1,45 @@
+thisconfigdir=./..
+myfulldir=appl/gss-sample
+mydir=gss-sample
+BUILDTOP=$(REL)..$(S)..
+DEFINES = -DUSE_AUTOCONF_H -DGSSAPI_V2
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+SRCS= $(srcdir)/gss-client.c $(srcdir)/gss-misc.c $(srcdir)/gss-server.c
+
+OBJS= gss-client.o gss-misc.o gss-server.o
+
+all-unix:: gss-server gss-client
+all-windows:: $(OUTPRE)gss-server.exe $(OUTPRE)gss-client.exe
+
+gss-server: gss-server.o gss-misc.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o gss-server gss-server.o gss-misc.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+
+gss-client: gss-client.o gss-misc.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o gss-client gss-client.o gss-misc.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+
+$(OUTPRE)gss-server.exe: $(OUTPRE)gss-server.obj $(OUTPRE)gss-misc.obj $(GLIB) $(KLIB)
+	link $(EXE_LINKOPTS) -out:$@ $** ws2_32.lib
+
+$(OUTPRE)gss-client.exe: $(OUTPRE)gss-client.obj $(OUTPRE)gss-misc.obj $(GLIB) $(KLIB)
+	link $(EXE_LINKOPTS) -out:$@ $** ws2_32.lib
+
+clean-unix::
+	$(RM) gss-server gss-client
+
+install-unix::
+	$(INSTALL_PROGRAM) gss-client $(DESTDIR)$(CLIENT_BINDIR)/gss-client
+	$(INSTALL_PROGRAM) gss-server $(DESTDIR)$(SERVER_BINDIR)/gss-server
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)gss-client.$(OBJEXT): gss-client.c $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gss-misc.h
+$(OUTPRE)gss-misc.$(OBJEXT): gss-misc.c $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gss-misc.h
+$(OUTPRE)gss-server.$(OBJEXT): gss-server.c $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gss-misc.h
diff --git a/mechglue/src/appl/gss-sample/README b/mechglue/src/appl/gss-sample/README
new file mode 100644
index 000000000..dc51fca1b
--- /dev/null
+++ b/mechglue/src/appl/gss-sample/README
@@ -0,0 +1,163 @@
+# Copyright 1993 by OpenVision Technologies, Inc.
+# 
+# Permission to use, copy, modify, distribute, and sell this software
+# and its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appears in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of OpenVision not be used
+# in advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. OpenVision makes no
+# representations about the suitability of this software for any
+# purpose.  It is provided "as is" without express or implied warranty.
+# 
+# OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+This directory contains a sample GSS-API client and server
+application.  In addition to serving as an example of GSS-API
+programming, this application is also intended to be a tool for
+testing the performance of GSS-API implementations.
+
+Each time the client is invoked, it performs one or more exchanges
+with the server.  Each exchange with the server consists primarily of
+the following steps:
+
+	1. A TCP/IP connection is established.
+
+	2. (optional, on by default) The client and server establish a
+	   GSS-API context, and the server prints the identify of the
+	   client.
+
+      /	3. The client sends a message to the server.  The message may
+     /     be plaintext, cryptographically "signed" but not encrypted,
+     |     or encrypted (default).
+     |
+0 or |  4. The server decrypts the message (if necessary), verifies
+more |     its signature (if there is one) and prints it.
+times|
+     |  5. The server sends either a signature block (the default) or an
+     |     empty token back to the client to acknowledge the message.
+     \
+      \ 6. If the server sent a signature block, the client verifies
+           it and prints a message indicating that it was verified.
+  
+	7. The client sends an empty block to the server to tell it
+	   that the exchange is finished.
+  
+	8. The client and server close the TCP/IP connection and
+	   destroy the GSS-API context.
+
+The client also supports the -v1 flag which uses an older exchange
+format compatible with previous releases of Kerberos and with samples
+shipped in the Microsoft SDK.
+  
+The server's command line usage is
+  
+	gss-server [-port port] [-verbose] [-once] [-inetd] [-export]
+		[-logfile file] service_name
+  
+where service_name is a GSS-API service name of the form
+"service@host" (or just "service", in which case the local host name
+is used).  The command-line options have the following meanings:
+  
+-port	The TCP port on which to accept connections.  Default is 4444.
+  
+-once	Tells the server to exit after a single exchange, rather than
+	persisting.
+  
+-inetd	Tells the server that it is running out of inetd, so it should
+	interact with the client on stdin rather than binding to a
+	network port.  Implies "-once".
+  
+-export	Tells the server to test the gss_export_sec_context function
+	after establishing a context with a client.
+
+-logfile
+	The file to which the server should append its output, rather
+	than sending it to stdout.
+  
+The client's command line usage is
+
+	gss-client [-port port] [-mech mechanism] [-d] [-f] [-q]
+        [-seq] [-noreplay] [-nomutual]		
+        [-ccount count] [-mcount count] [-na] [-nw] [-nx] [-nm]
+		host service_name msg
+
+where host is the host running the server, service_name is the service
+name that the server will establish connections as (if you don't
+specify the host name in the service name when running gss-server, and
+it's running on a different machine from gss-client, make sure to
+specify the server's host name in the service name you specify to
+gss-client!) and msg is the message.  The command-line options have
+the following meanings:
+
+-port	The TCP port to which to connect.  Default is 4444.
+
+-mech	The OID of the GSS-API mechanism to use.
+
+-d	Tells the client to delegate credentials to the server.  For
+	the Kerberos GSS-API mechanism, this means that a forwardable
+	TGT will be sent to the server, which will put it in its
+	credential cache (you must have acquired your tickets with
+	"kinit -f" for this to work).
+
+-seq Tells the client to enforce ordered message delivery via
+    sequencing.  
+
+-noreplay Tells the client to disable the use of replay
+    detection.
+
+-nomutual Tells the client to disable the use of mutual authentication.
+
+-f	Tells the client that the "msg" argument is actually the name
+	of a file whose contents should be used as the message.
+
+-q	Tells the client to be quiet, i.e., to only print error
+	messages.
+
+-ccount	Specifies how many sessions the client should initiate with
+	the server (the "connection count").
+
+-mcount	Specifies how many times the message should be sent to the
+	server in each session (the "message count").
+
+-na	Tells the client not to do any authentication with the
+	server.  Implies "-nw", "-nx" and "-nm".
+
+-nw	Tells the client not to "wrap" messages.  Implies "-nx".
+
+-nx	Tells the client not to encrypt messages.
+
+-nm	Tells the client not to ask the server to send back a
+	cryptographic checksum ("MIC").
+
+To run the server on a host, you need to make sure that the principal
+corresponding to service_name is in the default keytab on the server
+host, and that the gss-server process can read the keytab.  For
+example, the service name "host@server" corresponds to the Kerberos
+principal "host/server.domain.com@REALM".
+
+This sample application uses the following GSS-API functions:
+
+	gss_accept_sec_context		gss_inquire_names_for_mech
+	gss_acquire_cred		gss_oid_to_str
+	gss_delete_sec_context		gss_release_buffer
+	gss_display_name		gss_release_cred
+	gss_display_status		gss_release_name
+	gss_export_sec_context		gss_release_oid
+	gss_get_mic			gss_release_oid_set
+	gss_import_name			gss_str_to_oid
+	gss_import_sec_context		gss_unwrap
+	gss_init_sec_context		gss_verify_mic
+	gss_inquire_context		gss_wrap
+  
+This application was originally written by Barry Jaspan of OpenVision
+Technologies, Inc.  It was updated significantly by Jonathan Kamens of
+OpenVision Technologies, Inc.
+
+$Id$
diff --git a/mechglue/src/appl/gss-sample/gss-client.c b/mechglue/src/appl/gss-sample/gss-client.c
new file mode 100644
index 000000000..32cd1bd78
--- /dev/null
+++ b/mechglue/src/appl/gss-sample/gss-client.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 2003, 2004, 2005 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock.h>
+#else
+#include <assert.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+
+#include <gssapi/gssapi_generic.h>
+#include "gss-misc.h"
+
+static int verbose = 1;
+
+static void
+usage()
+{
+    fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] [-d]\n");
+    fprintf(stderr, "       [-seq] [-noreplay] [-nomutual]");
+#ifdef _WIN32
+    fprintf(stderr, " [-threads num]");
+#endif
+    fprintf(stderr, "\n");
+    fprintf(stderr, "       [-f] [-q] [-ccount count] [-mcount count]\n");
+    fprintf(stderr, "       [-v1] [-na] [-nw] [-nx] [-nm] host service msg\n");
+    exit(1);
+}
+
+/*
+ * Function: connect_to_server
+ *
+ * Purpose: Opens a TCP connection to the name host and port.
+ *
+ * Arguments:
+ *
+ * 	host		(r) the target host name
+ * 	port		(r) the target port, in host byte order
+ *
+ * Returns: the established socket file desciptor, or -1 on failure
+ *
+ * Effects:
+ *
+ * The host name is resolved with gethostbyname(), and the socket is
+ * opened and connected.  If an error occurs, an error message is
+ * displayed and -1 is returned.
+ */
+static int
+connect_to_server(host, port)
+    char   *host;
+    u_short port;
+{
+    struct sockaddr_in saddr;
+    struct hostent *hp;
+    int     s;
+
+    if ((hp = gethostbyname(host)) == NULL) {
+	fprintf(stderr, "Unknown host: %s\n", host);
+	return -1;
+    }
+
+    saddr.sin_family = hp->h_addrtype;
+    memcpy((char *) &saddr.sin_addr, hp->h_addr, sizeof(saddr.sin_addr));
+    saddr.sin_port = htons(port);
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	perror("creating socket");
+	return -1;
+    }
+    if (connect(s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
+	perror("connecting to server");
+	(void) close(s);
+	return -1;
+    }
+    return s;
+}
+
+/*
+ * Function: client_establish_context
+ *
+ * Purpose: establishes a GSS-API context with a specified service and
+ * returns the context handle
+ *
+ * Arguments:
+ *
+ * 	s		    (r) an established TCP connection to the service
+ * 	service_name(r) the ASCII service name of the service
+ *	gss_flags	(r) GSS-API delegation flag (if any)
+ *	auth_flag	(r) whether to actually do authentication
+ *  v1_format   (r) whether the v1 sample protocol should be used
+ *	oid		    (r) OID of the mechanism to use
+ * 	context		(w) the established GSS-API context
+ *	ret_flags	(w) the returned flags from init_sec_context
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * service_name is imported as a GSS-API name and a GSS-API context is
+ * established with the corresponding service; the service should be
+ * listening on the TCP connection s.  The default GSS-API mechanism
+ * is used, and mutual authentication and replay detection are
+ * requested.
+ * 
+ * If successful, the context handle is returned in context.  If
+ * unsuccessful, the GSS-API error messages are displayed on stderr
+ * and -1 is returned.
+ */
+static int
+client_establish_context(s, service_name, gss_flags, auth_flag,
+			 v1_format, oid, gss_context, ret_flags)
+    int     s;
+    char   *service_name;
+    gss_OID oid;
+    OM_uint32 gss_flags;
+    int     auth_flag;
+    int     v1_format;
+    gss_ctx_id_t *gss_context;
+    OM_uint32 *ret_flags;
+{
+    if (auth_flag) {
+	gss_buffer_desc send_tok, recv_tok, *token_ptr;
+	gss_name_t target_name;
+	OM_uint32 maj_stat, min_stat, init_sec_min_stat;
+	int     token_flags;
+
+	/*
+	 * Import the name into target_name.  Use send_tok to save
+	 * local variable space.
+	 */
+	send_tok.value = service_name;
+	send_tok.length = strlen(service_name);
+	maj_stat = gss_import_name(&min_stat, &send_tok,
+				   (gss_OID) gss_nt_service_name,
+				   &target_name);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("parsing name", maj_stat, min_stat);
+	    return -1;
+	}
+
+	if (!v1_format) {
+	    if (send_token(s, TOKEN_NOOP | TOKEN_CONTEXT_NEXT, empty_token) <
+		0) {
+		(void) gss_release_name(&min_stat, &target_name);
+		return -1;
+	    }
+	}
+
+	/*
+	 * Perform the context-establishement loop.
+	 *
+	 * On each pass through the loop, token_ptr points to the token
+	 * to send to the server (or GSS_C_NO_BUFFER on the first pass).
+	 * Every generated token is stored in send_tok which is then
+	 * transmitted to the server; every received token is stored in
+	 * recv_tok, which token_ptr is then set to, to be processed by
+	 * the next call to gss_init_sec_context.
+	 * 
+	 * GSS-API guarantees that send_tok's length will be non-zero
+	 * if and only if the server is expecting another token from us,
+	 * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
+	 * and only if the server has another token to send us.
+	 */
+
+	token_ptr = GSS_C_NO_BUFFER;
+	*gss_context = GSS_C_NO_CONTEXT;
+
+	do {
+	    maj_stat = gss_init_sec_context(&init_sec_min_stat, GSS_C_NO_CREDENTIAL, gss_context, target_name, oid, gss_flags, 0, NULL,	/* no channel bindings */
+					    token_ptr, NULL,	/* ignore mech type */
+					    &send_tok, ret_flags, NULL);	/* ignore time_rec */
+
+	    if (token_ptr != GSS_C_NO_BUFFER)
+		free(recv_tok.value);
+
+	    if (send_tok.length != 0) {
+		if (verbose)
+		    printf("Sending init_sec_context token (size=%d)...",
+			   (int) send_tok.length);
+		if (send_token(s, v1_format ? 0 : TOKEN_CONTEXT, &send_tok) <
+		    0) {
+		    (void) gss_release_buffer(&min_stat, &send_tok);
+		    (void) gss_release_name(&min_stat, &target_name);
+		    return -1;
+		}
+	    }
+	    (void) gss_release_buffer(&min_stat, &send_tok);
+
+	    if (maj_stat != GSS_S_COMPLETE
+		&& maj_stat != GSS_S_CONTINUE_NEEDED) {
+		display_status("initializing context", maj_stat,
+			       init_sec_min_stat);
+		(void) gss_release_name(&min_stat, &target_name);
+		if (*gss_context != GSS_C_NO_CONTEXT)
+		    gss_delete_sec_context(&min_stat, gss_context,
+					   GSS_C_NO_BUFFER);
+		return -1;
+	    }
+
+	    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+		if (verbose)
+		    printf("continue needed...");
+		if (recv_token(s, &token_flags, &recv_tok) < 0) {
+		    (void) gss_release_name(&min_stat, &target_name);
+		    return -1;
+		}
+		token_ptr = &recv_tok;
+	    }
+	    if (verbose)
+		printf("\n");
+	} while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+	(void) gss_release_name(&min_stat, &target_name);
+    } else {
+	if (send_token(s, TOKEN_NOOP, empty_token) < 0)
+	    return -1;
+    }
+
+    return 0;
+}
+
+static void
+read_file(file_name, in_buf)
+    char   *file_name;
+    gss_buffer_t in_buf;
+{
+    int     fd, count;
+    struct stat stat_buf;
+
+    if ((fd = open(file_name, O_RDONLY, 0)) < 0) {
+	perror("open");
+	fprintf(stderr, "Couldn't open file %s\n", file_name);
+	exit(1);
+    }
+    if (fstat(fd, &stat_buf) < 0) {
+	perror("fstat");
+	exit(1);
+    }
+    in_buf->length = stat_buf.st_size;
+
+    if (in_buf->length == 0) {
+	in_buf->value = NULL;
+	return;
+    }
+
+    if ((in_buf->value = malloc(in_buf->length)) == 0) {
+	fprintf(stderr, "Couldn't allocate %d byte buffer for reading file\n",
+		(int) in_buf->length);
+	exit(1);
+    }
+
+    /* this code used to check for incomplete reads, but you can't get
+     * an incomplete read on any file for which fstat() is meaningful */
+
+    count = read(fd, in_buf->value, in_buf->length);
+    if (count < 0) {
+	perror("read");
+	exit(1);
+    }
+    if (count < in_buf->length)
+	fprintf(stderr, "Warning, only read in %d bytes, expected %d\n",
+		count, (int) in_buf->length);
+}
+
+/*
+ * Function: call_server
+ *
+ * Purpose: Call the "sign" service.
+ *
+ * Arguments:
+ *
+ * 	host		(r) the host providing the service
+ * 	port		(r) the port to connect to on host
+ * 	service_name	(r) the GSS-API service name to authenticate to
+ *	gss_flags	(r) GSS-API delegation flag (if any)
+ *	auth_flag	(r) whether to do authentication
+ *	wrap_flag	(r) whether to do message wrapping at all
+ *	encrypt_flag	(r) whether to do encryption while wrapping
+ *	mic_flag	(r) whether to request a MIC from the server
+ * 	msg		(r) the message to have "signed"
+ *	use_file	(r) whether to treat msg as an input file name
+ *	mcount		(r) the number of times to send the message
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * call_server opens a TCP connection to <host:port> and establishes a
+ * GSS-API context with service_name over the connection.  It then
+ * seals msg in a GSS-API token with gss_wrap, sends it to the server,
+ * reads back a GSS-API signature block for msg from the server, and
+ * verifies it with gss_verify.  -1 is returned if any step fails,
+ * otherwise 0 is returned.  */
+static int
+call_server(host, port, oid, service_name, gss_flags, auth_flag,
+	    wrap_flag, encrypt_flag, mic_flag, v1_format, msg, use_file,
+	    mcount)
+    char   *host;
+    u_short port;
+    gss_OID oid;
+    char   *service_name;
+    OM_uint32 gss_flags;
+    int     auth_flag, wrap_flag, encrypt_flag, mic_flag;
+    int     v1_format;
+    char   *msg;
+    int     use_file;
+    int     mcount;
+{
+    gss_ctx_id_t context;
+    gss_buffer_desc in_buf, out_buf;
+    int     s, state;
+    OM_uint32 ret_flags;
+    OM_uint32 maj_stat, min_stat;
+    gss_name_t src_name, targ_name;
+    gss_buffer_desc sname, tname;
+    OM_uint32 lifetime;
+    gss_OID mechanism, name_type;
+    int     is_local;
+    OM_uint32 context_flags;
+    int     is_open;
+    gss_qop_t qop_state;
+    gss_OID_set mech_names;
+    gss_buffer_desc oid_name;
+    size_t  i;
+    int     token_flags;
+
+    /* Open connection */
+    if ((s = connect_to_server(host, port)) < 0)
+	return -1;
+
+    /* Establish context */
+    if (client_establish_context(s, service_name, gss_flags, auth_flag,
+				 v1_format, oid, &context, &ret_flags) < 0) {
+	(void) close(s);
+	return -1;
+    }
+
+    if (auth_flag && verbose) {
+	/* display the flags */
+	display_ctx_flags(ret_flags);
+
+	/* Get context information */
+	maj_stat = gss_inquire_context(&min_stat, context,
+				       &src_name, &targ_name, &lifetime,
+				       &mechanism, &context_flags,
+				       &is_local, &is_open);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("inquiring context", maj_stat, min_stat);
+	    return -1;
+	}
+
+	maj_stat = gss_display_name(&min_stat, src_name, &sname, &name_type);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("displaying source name", maj_stat, min_stat);
+	    return -1;
+	}
+	maj_stat = gss_display_name(&min_stat, targ_name, &tname,
+				    (gss_OID *) NULL);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("displaying target name", maj_stat, min_stat);
+	    return -1;
+	}
+	printf("\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
+	       (int) sname.length, (char *) sname.value,
+	       (int) tname.length, (char *) tname.value, lifetime,
+	       context_flags,
+	       (is_local) ? "locally initiated" : "remotely initiated",
+	       (is_open) ? "open" : "closed");
+
+	(void) gss_release_name(&min_stat, &src_name);
+	(void) gss_release_name(&min_stat, &targ_name);
+	(void) gss_release_buffer(&min_stat, &sname);
+	(void) gss_release_buffer(&min_stat, &tname);
+
+	maj_stat = gss_oid_to_str(&min_stat, name_type, &oid_name);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("converting oid->string", maj_stat, min_stat);
+	    return -1;
+	}
+	printf("Name type of source name is %.*s.\n",
+	       (int) oid_name.length, (char *) oid_name.value);
+	(void) gss_release_buffer(&min_stat, &oid_name);
+
+	/* Now get the names supported by the mechanism */
+	maj_stat = gss_inquire_names_for_mech(&min_stat,
+					      mechanism, &mech_names);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("inquiring mech names", maj_stat, min_stat);
+	    return -1;
+	}
+
+	maj_stat = gss_oid_to_str(&min_stat, mechanism, &oid_name);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("converting oid->string", maj_stat, min_stat);
+	    return -1;
+	}
+	printf("Mechanism %.*s supports %d names\n",
+	       (int) oid_name.length, (char *) oid_name.value,
+	       (int) mech_names->count);
+	(void) gss_release_buffer(&min_stat, &oid_name);
+
+	for (i = 0; i < mech_names->count; i++) {
+	    maj_stat = gss_oid_to_str(&min_stat,
+				      &mech_names->elements[i], &oid_name);
+	    if (maj_stat != GSS_S_COMPLETE) {
+		display_status("converting oid->string", maj_stat, min_stat);
+		return -1;
+	    }
+	    printf("  %d: %.*s\n", (int) i,
+		   (int) oid_name.length, (char *) oid_name.value);
+
+	    (void) gss_release_buffer(&min_stat, &oid_name);
+	}
+	(void) gss_release_oid_set(&min_stat, &mech_names);
+    }
+
+    if (use_file) {
+	read_file(msg, &in_buf);
+    } else {
+	/* Seal the message */
+	in_buf.value = msg;
+	in_buf.length = strlen(msg);
+    }
+
+    for (i = 0; i < mcount; i++) {
+	if (wrap_flag) {
+	    maj_stat =
+		gss_wrap(&min_stat, context, encrypt_flag, GSS_C_QOP_DEFAULT,
+			 &in_buf, &state, &out_buf);
+	    if (maj_stat != GSS_S_COMPLETE) {
+		display_status("wrapping message", maj_stat, min_stat);
+		(void) close(s);
+		(void) gss_delete_sec_context(&min_stat, &context,
+					      GSS_C_NO_BUFFER);
+		return -1;
+	    } else if (encrypt_flag && !state) {
+		fprintf(stderr, "Warning!  Message not encrypted.\n");
+	    }
+	} else {
+	    out_buf = in_buf;
+	}
+
+	/* Send to server */
+	if (send_token(s, (v1_format ? 0
+			   : (TOKEN_DATA |
+			      (wrap_flag ? TOKEN_WRAPPED : 0) |
+			      (encrypt_flag ? TOKEN_ENCRYPTED : 0) |
+			      (mic_flag ? TOKEN_SEND_MIC : 0))),
+		       &out_buf) < 0) {
+	    (void) close(s);
+	    (void) gss_delete_sec_context(&min_stat, &context,
+					  GSS_C_NO_BUFFER);
+	    return -1;
+	}
+	if (out_buf.value != in_buf.value)
+	    (void) gss_release_buffer(&min_stat, &out_buf);
+
+	/* Read signature block into out_buf */
+	if (recv_token(s, &token_flags, &out_buf) < 0) {
+	    (void) close(s);
+	    (void) gss_delete_sec_context(&min_stat, &context,
+					  GSS_C_NO_BUFFER);
+	    return -1;
+	}
+
+	if (mic_flag) {
+	    /* Verify signature block */
+	    maj_stat = gss_verify_mic(&min_stat, context, &in_buf,
+				      &out_buf, &qop_state);
+	    if (maj_stat != GSS_S_COMPLETE) {
+		display_status("verifying signature", maj_stat, min_stat);
+		(void) close(s);
+		(void) gss_delete_sec_context(&min_stat, &context,
+					      GSS_C_NO_BUFFER);
+		return -1;
+	    }
+
+	    if (verbose)
+		printf("Signature verified.\n");
+	} else {
+	    if (verbose)
+		printf("Response received.\n");
+	}
+
+	free(out_buf.value);
+    }
+
+    if (use_file)
+	free(in_buf.value);
+
+    /* Send NOOP */
+    if (!v1_format)
+	(void) send_token(s, TOKEN_NOOP, empty_token);
+
+    if (auth_flag) {
+	/* Delete context */
+	maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("deleting context", maj_stat, min_stat);
+	    (void) close(s);
+	    (void) gss_delete_sec_context(&min_stat, &context,
+					  GSS_C_NO_BUFFER);
+	    return -1;
+	}
+
+	(void) gss_release_buffer(&min_stat, &out_buf);
+    }
+
+    (void) close(s);
+    return 0;
+}
+
+static void
+parse_oid(char *mechanism, gss_OID * oid)
+{
+    char   *mechstr = 0, *cp;
+    gss_buffer_desc tok;
+    OM_uint32 maj_stat, min_stat;
+
+    if (isdigit((int) mechanism[0])) {
+	mechstr = malloc(strlen(mechanism) + 5);
+	if (!mechstr) {
+	    fprintf(stderr, "Couldn't allocate mechanism scratch!\n");
+	    return;
+	}
+	sprintf(mechstr, "{ %s }", mechanism);
+	for (cp = mechstr; *cp; cp++)
+	    if (*cp == '.')
+		*cp = ' ';
+	tok.value = mechstr;
+    } else
+	tok.value = mechanism;
+    tok.length = strlen(tok.value);
+    maj_stat = gss_str_to_oid(&min_stat, &tok, oid);
+    if (maj_stat != GSS_S_COMPLETE) {
+	display_status("str_to_oid", maj_stat, min_stat);
+	return;
+    }
+    if (mechstr)
+	free(mechstr);
+}
+
+static int max_threads = 1;
+
+#ifdef _WIN32
+static  thread_count = 0;
+static HANDLE hMutex = NULL;
+static HANDLE hEvent = NULL;
+
+void
+InitHandles(void)
+{
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+void
+CleanupHandles(void)
+{
+    CloseHandle(hMutex);
+    CloseHandle(hEvent);
+}
+
+BOOL
+WaitAndIncrementThreadCounter(void)
+{
+    for (;;) {
+	if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
+	    if (thread_count < max_threads) {
+		thread_count++;
+		ReleaseMutex(hMutex);
+		return TRUE;
+	    } else {
+		ReleaseMutex(hMutex);
+
+		if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) {
+		    continue;
+		} else {
+		    return FALSE;
+		}
+	    }
+	} else {
+	    return FALSE;
+	}
+    }
+}
+
+BOOL
+DecrementAndSignalThreadCounter(void)
+{
+    if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
+	if (thread_count == max_threads)
+	    ResetEvent(hEvent);
+	thread_count--;
+	ReleaseMutex(hMutex);
+	return TRUE;
+    } else {
+	return FALSE;
+    }
+}
+#endif
+
+static char *service_name, *server_host, *msg;
+static char *mechanism = 0;
+static u_short port = 4444;
+static int use_file = 0;
+static OM_uint32 gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
+static OM_uint32 min_stat;
+static gss_OID oid = GSS_C_NULL_OID;
+static int mcount = 1, ccount = 1;
+static int auth_flag, wrap_flag, encrypt_flag, mic_flag, v1_format;
+
+void
+worker_bee(void *unused)
+{
+    if (call_server(server_host, port, oid, service_name,
+		    gss_flags, auth_flag, wrap_flag, encrypt_flag, mic_flag,
+		    v1_format, msg, use_file, mcount) < 0)
+	exit(1);
+
+#ifdef _WIN32
+    if (max_threads > 1)
+	DecrementAndSignalThreadCounter();
+#endif
+}
+
+int
+main(argc, argv)
+    int     argc;
+    char  **argv;
+{
+    int     i;
+
+    display_file = stdout;
+    auth_flag = wrap_flag = encrypt_flag = mic_flag = 1;
+    v1_format = 0;
+
+    /* Parse arguments. */
+    argc--;
+    argv++;
+    while (argc) {
+	if (strcmp(*argv, "-port") == 0) {
+	    argc--;
+	    argv++;
+	    if (!argc)
+		usage();
+	    port = atoi(*argv);
+	} else if (strcmp(*argv, "-mech") == 0) {
+	    argc--;
+	    argv++;
+	    if (!argc)
+		usage();
+	    mechanism = *argv;
+	}
+#ifdef _WIN32
+	else if (strcmp(*argv, "-threads") == 0) {
+	    argc--;
+	    argv++;
+	    if (!argc)
+		usage();
+	    max_threads = atoi(*argv);
+	}
+#endif
+	else if (strcmp(*argv, "-d") == 0) {
+	    gss_flags |= GSS_C_DELEG_FLAG;
+	} else if (strcmp(*argv, "-seq") == 0) {
+	    gss_flags |= GSS_C_SEQUENCE_FLAG;
+	} else if (strcmp(*argv, "-noreplay") == 0) {
+	    gss_flags &= ~GSS_C_REPLAY_FLAG;
+	} else if (strcmp(*argv, "-nomutual") == 0) {
+	    gss_flags &= ~GSS_C_MUTUAL_FLAG;
+	} else if (strcmp(*argv, "-f") == 0) {
+	    use_file = 1;
+	} else if (strcmp(*argv, "-q") == 0) {
+	    verbose = 0;
+	} else if (strcmp(*argv, "-ccount") == 0) {
+	    argc--;
+	    argv++;
+	    if (!argc)
+		usage();
+	    ccount = atoi(*argv);
+	    if (ccount <= 0)
+		usage();
+	} else if (strcmp(*argv, "-mcount") == 0) {
+	    argc--;
+	    argv++;
+	    if (!argc)
+		usage();
+	    mcount = atoi(*argv);
+	    if (mcount < 0)
+		usage();
+	} else if (strcmp(*argv, "-na") == 0) {
+	    auth_flag = wrap_flag = encrypt_flag = mic_flag = 0;
+	} else if (strcmp(*argv, "-nw") == 0) {
+	    wrap_flag = 0;
+	} else if (strcmp(*argv, "-nx") == 0) {
+	    encrypt_flag = 0;
+	} else if (strcmp(*argv, "-nm") == 0) {
+	    mic_flag = 0;
+	} else if (strcmp(*argv, "-v1") == 0) {
+	    v1_format = 1;
+	} else
+	    break;
+	argc--;
+	argv++;
+    }
+    if (argc != 3)
+	usage();
+
+#ifdef _WIN32
+    if (max_threads < 1) {
+	fprintf(stderr, "warning: there must be at least one thread\n");
+	max_threads = 1;
+    }
+#endif
+
+    server_host = *argv++;
+    service_name = *argv++;
+    msg = *argv++;
+
+    if (mechanism)
+	parse_oid(mechanism, &oid);
+
+    if (max_threads == 1) {
+	for (i = 0; i < ccount; i++) {
+	    worker_bee(0);
+	}
+    } else {
+#ifdef _WIN32
+	for (i = 0; i < ccount; i++) {
+	    if (WaitAndIncrementThreadCounter()) {
+		uintptr_t handle = _beginthread(worker_bee, 0, (void *) 0);
+		if (handle == (uintptr_t) - 1) {
+		    exit(1);
+		}
+	    } else {
+		exit(1);
+	    }
+	}
+#else
+	/* boom */
+	assert(max_threads == 1);
+#endif
+    }
+
+    if (oid != GSS_C_NULL_OID)
+	(void) gss_release_oid(&min_stat, &oid);
+
+#ifdef _WIN32
+    CleanupHandles();
+#endif
+
+    return 0;
+}
diff --git a/mechglue/src/appl/gss-sample/gss-misc.c b/mechglue/src/appl/gss-sample/gss-misc.c
new file mode 100644
index 000000000..fe578d1ab
--- /dev/null
+++ b/mechglue/src/appl/gss-sample/gss-misc.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 2003, 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock.h>
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+
+/* need struct timeval */
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#include <gssapi/gssapi_generic.h>
+#include "gss-misc.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc();
+#endif
+
+FILE   *display_file;
+
+gss_buffer_desc empty_token_buf = { 0, (void *) "" };
+gss_buffer_t empty_token = &empty_token_buf;
+
+static void display_status_1(char *m, OM_uint32 code, int type);
+
+static int
+write_all(int fildes, char *buf, unsigned int nbyte)
+{
+    int     ret;
+    char   *ptr;
+
+    for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
+	ret = send(fildes, ptr, nbyte, 0);
+	if (ret < 0) {
+	    if (errno == EINTR)
+		continue;
+	    return (ret);
+	} else if (ret == 0) {
+	    return (ptr - buf);
+	}
+    }
+
+    return (ptr - buf);
+}
+
+static int
+read_all(int fildes, char *buf, unsigned int nbyte)
+{
+    int     ret;
+    char   *ptr;
+    fd_set  rfds;
+    struct timeval tv;
+
+    FD_ZERO(&rfds);
+    FD_SET(fildes, &rfds);
+    tv.tv_sec = 10;
+    tv.tv_usec = 0;
+
+    for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
+	if (select(FD_SETSIZE, &rfds, NULL, NULL, &tv) <= 0
+	    || !FD_ISSET(fildes, &rfds))
+	    return (ptr - buf);
+	ret = recv(fildes, ptr, nbyte, 0);
+	if (ret < 0) {
+	    if (errno == EINTR)
+		continue;
+	    return (ret);
+	} else if (ret == 0) {
+	    return (ptr - buf);
+	}
+    }
+
+    return (ptr - buf);
+}
+
+/*
+ * Function: send_token
+ *
+ * Purpose: Writes a token to a file descriptor.
+ *
+ * Arguments:
+ *
+ * 	s		(r) an open file descriptor
+ *	flags		(r) the flags to write
+ * 	tok		(r) the token to write
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * If the flags are non-null, send_token writes the token flags (a
+ * single byte, even though they're passed in in an integer). Next,
+ * the token length (as a network long) and then the token data are
+ * written to the file descriptor s.  It returns 0 on success, and -1
+ * if an error occurs or if it could not write all the data.
+ */
+int
+send_token(s, flags, tok)
+    int     s;
+    int     flags;
+    gss_buffer_t tok;
+{
+    int     ret;
+    unsigned char char_flags = (unsigned char) flags;
+    unsigned char lenbuf[4];
+
+    if (char_flags) {
+	ret = write_all(s, (char *) &char_flags, 1);
+	if (ret != 1) {
+	    perror("sending token flags");
+	    return -1;
+	}
+    }
+    if (tok->length > 0xffffffffUL)
+	abort();
+    lenbuf[0] = (tok->length >> 24) & 0xff;
+    lenbuf[1] = (tok->length >> 16) & 0xff;
+    lenbuf[2] = (tok->length >> 8) & 0xff;
+    lenbuf[3] = tok->length & 0xff;
+
+    ret = write_all(s, lenbuf, 4);
+    if (ret < 0) {
+	perror("sending token length");
+	return -1;
+    } else if (ret != 4) {
+	if (display_file)
+	    fprintf(display_file,
+		    "sending token length: %d of %d bytes written\n", ret, 4);
+	return -1;
+    }
+
+    ret = write_all(s, tok->value, tok->length);
+    if (ret < 0) {
+	perror("sending token data");
+	return -1;
+    } else if (ret != tok->length) {
+	if (display_file)
+	    fprintf(display_file,
+		    "sending token data: %d of %d bytes written\n",
+		    ret, (int) tok->length);
+	return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Function: recv_token
+ *
+ * Purpose: Reads a token from a file descriptor.
+ *
+ * Arguments:
+ *
+ * 	s		(r) an open file descriptor
+ *	flags		(w) the read flags
+ * 	tok		(w) the read token
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * recv_token reads the token flags (a single byte, even though
+ * they're stored into an integer, then reads the token length (as a
+ * network long), allocates memory to hold the data, and then reads
+ * the token data from the file descriptor s.  It blocks to read the
+ * length and data, if necessary.  On a successful return, the token
+ * should be freed with gss_release_buffer.  It returns 0 on success,
+ * and -1 if an error occurs or if it could not read all the data.
+ */
+int
+recv_token(s, flags, tok)
+    int     s;
+    int    *flags;
+    gss_buffer_t tok;
+{
+    int     ret;
+    unsigned char char_flags;
+    unsigned char lenbuf[4];
+
+    ret = read_all(s, (char *) &char_flags, 1);
+    if (ret < 0) {
+	perror("reading token flags");
+	return -1;
+    } else if (!ret) {
+	if (display_file)
+	    fputs("reading token flags: 0 bytes read\n", display_file);
+	return -1;
+    } else {
+	*flags = (int) char_flags;
+    }
+
+    if (char_flags == 0) {
+	lenbuf[0] = 0;
+	ret = read_all(s, &lenbuf[1], 3);
+	if (ret < 0) {
+	    perror("reading token length");
+	    return -1;
+	} else if (ret != 3) {
+	    if (display_file)
+		fprintf(display_file,
+			"reading token length: %d of %d bytes read\n", ret, 3);
+	    return -1;
+	}
+    } else {
+	ret = read_all(s, lenbuf, 4);
+	if (ret < 0) {
+	    perror("reading token length");
+	    return -1;
+	} else if (ret != 4) {
+	    if (display_file)
+		fprintf(display_file,
+			"reading token length: %d of %d bytes read\n", ret, 4);
+	    return -1;
+	}
+    }
+
+    tok->length = ((lenbuf[0] << 24)
+		   | (lenbuf[1] << 16)
+		   | (lenbuf[2] << 8)
+		   | lenbuf[3]);
+    tok->value = (char *) malloc(tok->length ? tok->length : 1);
+    if (tok->length && tok->value == NULL) {
+	if (display_file)
+	    fprintf(display_file, "Out of memory allocating token data\n");
+	return -1;
+    }
+
+    ret = read_all(s, (char *) tok->value, tok->length);
+    if (ret < 0) {
+	perror("reading token data");
+	free(tok->value);
+	return -1;
+    } else if (ret != tok->length) {
+	fprintf(stderr, "sending token data: %d of %d bytes written\n",
+		ret, (int) tok->length);
+	free(tok->value);
+	return -1;
+    }
+
+    return 0;
+}
+
+static void
+display_status_1(m, code, type)
+    char   *m;
+    OM_uint32 code;
+    int     type;
+{
+    OM_uint32 maj_stat, min_stat;
+    gss_buffer_desc msg;
+    OM_uint32 msg_ctx;
+
+    msg_ctx = 0;
+    while (1) {
+	maj_stat = gss_display_status(&min_stat, code,
+				      type, GSS_C_NULL_OID, &msg_ctx, &msg);
+	if (display_file)
+	    fprintf(display_file, "GSS-API error %s: %s\n", m,
+		    (char *) msg.value);
+	(void) gss_release_buffer(&min_stat, &msg);
+
+	if (!msg_ctx)
+	    break;
+    }
+}
+
+/*
+ * Function: display_status
+ *
+ * Purpose: displays GSS-API messages
+ *
+ * Arguments:
+ *
+ * 	msg		a string to be displayed with the message
+ * 	maj_stat	the GSS-API major status code
+ * 	min_stat	the GSS-API minor status code
+ *
+ * Effects:
+ *
+ * The GSS-API messages associated with maj_stat and min_stat are
+ * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
+ * followed by a newline.
+ */
+void
+display_status(msg, maj_stat, min_stat)
+    char   *msg;
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+{
+    display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
+    display_status_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+/*
+ * Function: display_ctx_flags
+ *
+ * Purpose: displays the flags returned by context initation in
+ *	    a human-readable form
+ *
+ * Arguments:
+ *
+ * 	int		ret_flags
+ *
+ * Effects:
+ *
+ * Strings corresponding to the context flags are printed on
+ * stdout, preceded by "context flag: " and followed by a newline
+ */
+
+void
+display_ctx_flags(flags)
+    OM_uint32 flags;
+{
+    if (flags & GSS_C_DELEG_FLAG)
+	fprintf(display_file, "context flag: GSS_C_DELEG_FLAG\n");
+    if (flags & GSS_C_MUTUAL_FLAG)
+	fprintf(display_file, "context flag: GSS_C_MUTUAL_FLAG\n");
+    if (flags & GSS_C_REPLAY_FLAG)
+	fprintf(display_file, "context flag: GSS_C_REPLAY_FLAG\n");
+    if (flags & GSS_C_SEQUENCE_FLAG)
+	fprintf(display_file, "context flag: GSS_C_SEQUENCE_FLAG\n");
+    if (flags & GSS_C_CONF_FLAG)
+	fprintf(display_file, "context flag: GSS_C_CONF_FLAG \n");
+    if (flags & GSS_C_INTEG_FLAG)
+	fprintf(display_file, "context flag: GSS_C_INTEG_FLAG \n");
+}
+
+void
+print_token(tok)
+    gss_buffer_t tok;
+{
+    int     i;
+    unsigned char *p = tok->value;
+
+    if (!display_file)
+	return;
+    for (i = 0; i < tok->length; i++, p++) {
+	fprintf(display_file, "%02x ", *p);
+	if ((i % 16) == 15) {
+	    fprintf(display_file, "\n");
+	}
+    }
+    fprintf(display_file, "\n");
+    fflush(display_file);
+}
+
+#ifdef _WIN32
+#include <sys\timeb.h>
+#include <time.h>
+
+int
+gettimeofday(struct timeval *tv, void *ignore_tz)
+{
+    struct _timeb tb;
+    _tzset();
+    _ftime(&tb);
+    if (tv) {
+	tv->tv_sec = tb.time;
+	tv->tv_usec = tb.millitm * 1000;
+    }
+    return 0;
+}
+#endif /* _WIN32 */
diff --git a/mechglue/src/appl/gss-sample/gss-misc.h b/mechglue/src/appl/gss-sample/gss-misc.h
new file mode 100644
index 000000000..35b3b7390
--- /dev/null
+++ b/mechglue/src/appl/gss-sample/gss-misc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef _GSSMISC_H_
+#define _GSSMISC_H_
+
+#include <gssapi/gssapi_generic.h>
+#include <stdio.h>
+
+extern FILE *display_file;
+
+int send_token
+	(int s, int flags, gss_buffer_t tok);
+int recv_token
+	(int s, int *flags, gss_buffer_t tok);
+void display_status
+	(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat);
+void display_ctx_flags
+	(OM_uint32 flags);
+void print_token
+	(gss_buffer_t tok);
+
+/* Token types */
+#define TOKEN_NOOP		(1<<0)
+#define TOKEN_CONTEXT		(1<<1)
+#define TOKEN_DATA		(1<<2)
+#define TOKEN_MIC		(1<<3)
+
+/* Token flags */
+#define TOKEN_CONTEXT_NEXT	(1<<4)
+#define TOKEN_WRAPPED		(1<<5)
+#define TOKEN_ENCRYPTED		(1<<6)
+#define TOKEN_SEND_MIC		(1<<7)
+
+extern gss_buffer_t empty_token;
+
+#endif
diff --git a/mechglue/src/appl/gss-sample/gss-server.c b/mechglue/src/appl/gss-sample/gss-server.c
new file mode 100644
index 000000000..5377b689a
--- /dev/null
+++ b/mechglue/src/appl/gss-sample/gss-server.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 2004,2005 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock.h>
+#else
+#include "port-sockets.h"
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <gssapi/gssapi_generic.h>
+#include "gss-misc.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+static void
+usage()
+{
+    fprintf(stderr, "Usage: gss-server [-port port] [-verbose] [-once]");
+#ifdef _WIN32
+    fprintf(stderr, " [-threads num]");
+#endif
+    fprintf(stderr, "\n");
+    fprintf(stderr,
+	    "       [-inetd] [-export] [-logfile file] service_name\n");
+    exit(1);
+}
+
+static FILE *logfile;
+
+int     verbose = 0;
+
+/*
+ * Function: server_acquire_creds
+ *
+ * Purpose: imports a service name and acquires credentials for it
+ *
+ * Arguments:
+ *
+ * 	service_name	(r) the ASCII service name
+ * 	server_creds	(w) the GSS-API service credentials
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * The service name is imported with gss_import_name, and service
+ * credentials are acquired with gss_acquire_cred.  If either opertion
+ * fails, an error message is displayed and -1 is returned; otherwise,
+ * 0 is returned.
+ */
+static int
+server_acquire_creds(service_name, server_creds)
+    char   *service_name;
+    gss_cred_id_t *server_creds;
+{
+    gss_buffer_desc name_buf;
+    gss_name_t server_name;
+    OM_uint32 maj_stat, min_stat;
+
+    name_buf.value = service_name;
+    name_buf.length = strlen(name_buf.value) + 1;
+    maj_stat = gss_import_name(&min_stat, &name_buf,
+			       (gss_OID) gss_nt_service_name, &server_name);
+    if (maj_stat != GSS_S_COMPLETE) {
+	display_status("importing name", maj_stat, min_stat);
+	return -1;
+    }
+
+    maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
+				GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+				server_creds, NULL, NULL);
+    if (maj_stat != GSS_S_COMPLETE) {
+	display_status("acquiring credentials", maj_stat, min_stat);
+	return -1;
+    }
+
+    (void) gss_release_name(&min_stat, &server_name);
+
+    return 0;
+}
+
+/*
+ * Function: server_establish_context
+ *
+ * Purpose: establishses a GSS-API context as a specified service with
+ * an incoming client, and returns the context handle and associated
+ * client name
+ *
+ * Arguments:
+ *
+ * 	s		(r) an established TCP connection to the client
+ * 	service_creds	(r) server credentials, from gss_acquire_cred
+ * 	context		(w) the established GSS-API context
+ * 	client_name	(w) the client's ASCII name
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * Any valid client request is accepted.  If a context is established,
+ * its handle is returned in context and the client name is returned
+ * in client_name and 0 is returned.  If unsuccessful, an error
+ * message is displayed and -1 is returned.
+ */
+static int
+server_establish_context(s, server_creds, context, client_name, ret_flags)
+    int     s;
+    gss_cred_id_t server_creds;
+    gss_ctx_id_t *context;
+    gss_buffer_t client_name;
+    OM_uint32 *ret_flags;
+{
+    gss_buffer_desc send_tok, recv_tok;
+    gss_name_t client;
+    gss_OID doid;
+    OM_uint32 maj_stat, min_stat, acc_sec_min_stat;
+    gss_buffer_desc oid_name;
+    int     token_flags;
+
+    if (recv_token(s, &token_flags, &recv_tok) < 0)
+	return -1;
+
+    if (recv_tok.value) {
+	free(recv_tok.value);
+	recv_tok.value = NULL;
+    }
+
+    if (!(token_flags & TOKEN_NOOP)) {
+	if (logfile)
+	    fprintf(logfile, "Expected NOOP token, got %d token instead\n",
+		    token_flags);
+	return -1;
+    }
+
+    *context = GSS_C_NO_CONTEXT;
+
+    if (token_flags & TOKEN_CONTEXT_NEXT) {
+	do {
+	    if (recv_token(s, &token_flags, &recv_tok) < 0)
+		return -1;
+
+	    if (verbose && logfile) {
+		fprintf(logfile, "Received token (size=%d): \n",
+			(int) recv_tok.length);
+		print_token(&recv_tok);
+	    }
+
+	    maj_stat = gss_accept_sec_context(&acc_sec_min_stat, context, server_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &client, &doid, &send_tok, ret_flags, NULL,	/* ignore time_rec */
+					      NULL);	/* ignore del_cred_handle */
+
+	    if (recv_tok.value) {
+		free(recv_tok.value);
+		recv_tok.value = NULL;
+	    }
+
+	    if (send_tok.length != 0) {
+		if (verbose && logfile) {
+		    fprintf(logfile,
+			    "Sending accept_sec_context token (size=%d):\n",
+			    (int) send_tok.length);
+		    print_token(&send_tok);
+		}
+		if (send_token(s, TOKEN_CONTEXT, &send_tok) < 0) {
+		    if (logfile)
+			fprintf(logfile, "failure sending token\n");
+		    return -1;
+		}
+
+		(void) gss_release_buffer(&min_stat, &send_tok);
+	    }
+	    if (maj_stat != GSS_S_COMPLETE
+		&& maj_stat != GSS_S_CONTINUE_NEEDED) {
+		display_status("accepting context", maj_stat,
+			       acc_sec_min_stat);
+		if (*context != GSS_C_NO_CONTEXT)
+		    gss_delete_sec_context(&min_stat, context,
+					   GSS_C_NO_BUFFER);
+		return -1;
+	    }
+
+	    if (verbose && logfile) {
+		if (maj_stat == GSS_S_CONTINUE_NEEDED)
+		    fprintf(logfile, "continue needed...\n");
+		else
+		    fprintf(logfile, "\n");
+		fflush(logfile);
+	    }
+	} while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+	/* display the flags */
+	display_ctx_flags(*ret_flags);
+
+	if (verbose && logfile) {
+	    maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name);
+	    if (maj_stat != GSS_S_COMPLETE) {
+		display_status("converting oid->string", maj_stat, min_stat);
+		return -1;
+	    }
+	    fprintf(logfile, "Accepted connection using mechanism OID %.*s.\n",
+		    (int) oid_name.length, (char *) oid_name.value);
+	    (void) gss_release_buffer(&min_stat, &oid_name);
+	}
+
+	maj_stat = gss_display_name(&min_stat, client, client_name, &doid);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("displaying name", maj_stat, min_stat);
+	    return -1;
+	}
+	maj_stat = gss_release_name(&min_stat, &client);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("releasing name", maj_stat, min_stat);
+	    return -1;
+	}
+    } else {
+	client_name->length = *ret_flags = 0;
+
+	if (logfile)
+	    fprintf(logfile, "Accepted unauthenticated connection.\n");
+    }
+
+    return 0;
+}
+
+/*
+ * Function: create_socket
+ *
+ * Purpose: Opens a listening TCP socket.
+ *
+ * Arguments:
+ *
+ * 	port		(r) the port number on which to listen
+ *
+ * Returns: the listening socket file descriptor, or -1 on failure
+ *
+ * Effects:
+ *
+ * A listening socket on the specified port and created and returned.
+ * On error, an error message is displayed and -1 is returned.
+ */
+static int
+create_socket(port)
+    u_short port;
+{
+    struct sockaddr_in saddr;
+    int     s;
+    int     on = 1;
+
+    saddr.sin_family = AF_INET;
+    saddr.sin_port = htons(port);
+    saddr.sin_addr.s_addr = INADDR_ANY;
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	perror("creating socket");
+	return -1;
+    }
+    /* Let the socket be reused right away */
+    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
+    if (bind(s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
+	perror("binding socket");
+	(void) close(s);
+	return -1;
+    }
+    if (listen(s, 5) < 0) {
+	perror("listening on socket");
+	(void) close(s);
+	return -1;
+    }
+    return s;
+}
+
+static float
+timeval_subtract(tv1, tv2)
+    struct timeval *tv1, *tv2;
+{
+    return ((tv1->tv_sec - tv2->tv_sec) +
+	    ((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
+}
+
+/*
+ * Yes, yes, this isn't the best place for doing this test.
+ * DO NOT REMOVE THIS UNTIL A BETTER TEST HAS BEEN WRITTEN, THOUGH.
+ * 					-TYT
+ */
+static int
+test_import_export_context(context)
+    gss_ctx_id_t *context;
+{
+    OM_uint32 min_stat, maj_stat;
+    gss_buffer_desc context_token, copied_token;
+    struct timeval tm1, tm2;
+
+    /*
+     * Attempt to save and then restore the context.
+     */
+    gettimeofday(&tm1, (struct timezone *) 0);
+    maj_stat = gss_export_sec_context(&min_stat, context, &context_token);
+    if (maj_stat != GSS_S_COMPLETE) {
+	display_status("exporting context", maj_stat, min_stat);
+	return 1;
+    }
+    gettimeofday(&tm2, (struct timezone *) 0);
+    if (verbose && logfile)
+	fprintf(logfile, "Exported context: %d bytes, %7.4f seconds\n",
+		(int) context_token.length, timeval_subtract(&tm2, &tm1));
+    copied_token.length = context_token.length;
+    copied_token.value = malloc(context_token.length);
+    if (copied_token.value == 0) {
+	if (logfile)
+	    fprintf(logfile,
+		    "Couldn't allocate memory to copy context token.\n");
+	return 1;
+    }
+    memcpy(copied_token.value, context_token.value, copied_token.length);
+    maj_stat = gss_import_sec_context(&min_stat, &copied_token, context);
+    if (maj_stat != GSS_S_COMPLETE) {
+	display_status("importing context", maj_stat, min_stat);
+	return 1;
+    }
+    free(copied_token.value);
+    gettimeofday(&tm1, (struct timezone *) 0);
+    if (verbose && logfile)
+	fprintf(logfile, "Importing context: %7.4f seconds\n",
+		timeval_subtract(&tm1, &tm2));
+    (void) gss_release_buffer(&min_stat, &context_token);
+    return 0;
+}
+
+/*
+ * Function: sign_server
+ *
+ * Purpose: Performs the "sign" service.
+ *
+ * Arguments:
+ *
+ * 	s		(r) a TCP socket on which a connection has been
+ *			accept()ed
+ * 	service_name	(r) the ASCII name of the GSS-API service to
+ * 			establish a context as
+ *	export		(r) whether to test context exporting
+ * 
+ * Returns: -1 on error
+ *
+ * Effects:
+ *
+ * sign_server establishes a context, and performs a single sign request.
+ *
+ * A sign request is a single GSS-API sealed token.  The token is
+ * unsealed and a signature block, produced with gss_sign, is returned
+ * to the sender.  The context is the destroyed and the connection
+ * closed.
+ *
+ * If any error occurs, -1 is returned.
+ */
+static int
+sign_server(s, server_creds, export)
+    int     s;
+    gss_cred_id_t server_creds;
+    int     export;
+{
+    gss_buffer_desc client_name, xmit_buf, msg_buf;
+    gss_ctx_id_t context;
+    OM_uint32 maj_stat, min_stat;
+    int     i, conf_state, ret_flags;
+    char   *cp;
+    int     token_flags;
+
+    /* Establish a context with the client */
+    if (server_establish_context(s, server_creds, &context,
+				 &client_name, &ret_flags) < 0)
+	return (-1);
+
+    if (context == GSS_C_NO_CONTEXT) {
+	printf("Accepted unauthenticated connection.\n");
+    } else {
+	printf("Accepted connection: \"%.*s\"\n",
+	       (int) client_name.length, (char *) client_name.value);
+	(void) gss_release_buffer(&min_stat, &client_name);
+
+	if (export) {
+	    for (i = 0; i < 3; i++)
+		if (test_import_export_context(&context))
+		    return -1;
+	}
+    }
+
+    do {
+	/* Receive the message token */
+	if (recv_token(s, &token_flags, &xmit_buf) < 0)
+	    return (-1);
+
+	if (token_flags & TOKEN_NOOP) {
+	    if (logfile)
+		fprintf(logfile, "NOOP token\n");
+	    if (xmit_buf.value) {
+		free(xmit_buf.value);
+		xmit_buf.value = 0;
+	    }
+	    break;
+	}
+
+	if (verbose && logfile) {
+	    fprintf(logfile, "Message token (flags=%d):\n", token_flags);
+	    print_token(&xmit_buf);
+	}
+
+	if ((context == GSS_C_NO_CONTEXT) &&
+	    (token_flags & (TOKEN_WRAPPED | TOKEN_ENCRYPTED | TOKEN_SEND_MIC)))
+	{
+	    if (logfile)
+		fprintf(logfile,
+			"Unauthenticated client requested authenticated services!\n");
+	    if (xmit_buf.value) {
+		free(xmit_buf.value);
+		xmit_buf.value = 0;
+	    }
+	    return (-1);
+	}
+
+	if (token_flags & TOKEN_WRAPPED) {
+	    maj_stat = gss_unwrap(&min_stat, context, &xmit_buf, &msg_buf,
+				  &conf_state, (gss_qop_t *) NULL);
+	    if (maj_stat != GSS_S_COMPLETE) {
+		display_status("unsealing message", maj_stat, min_stat);
+		if (xmit_buf.value) {
+		    free(xmit_buf.value);
+		    xmit_buf.value = 0;
+		}
+		return (-1);
+	    } else if (!conf_state && (token_flags & TOKEN_ENCRYPTED)) {
+		fprintf(stderr, "Warning!  Message not encrypted.\n");
+	    }
+
+	    if (xmit_buf.value) {
+		free(xmit_buf.value);
+		xmit_buf.value = 0;
+	    }
+	} else {
+	    msg_buf = xmit_buf;
+	}
+
+	if (logfile) {
+	    fprintf(logfile, "Received message: ");
+	    cp = msg_buf.value;
+	    if ((isprint((int) cp[0]) || isspace((int) cp[0])) &&
+		(isprint((int) cp[1]) || isspace((int) cp[1]))) {
+		fprintf(logfile, "\"%.*s\"\n", (int) msg_buf.length,
+			(char *) msg_buf.value);
+	    } else {
+		fprintf(logfile, "\n");
+		print_token(&msg_buf);
+	    }
+	}
+
+	if (token_flags & TOKEN_SEND_MIC) {
+	    /* Produce a signature block for the message */
+	    maj_stat = gss_get_mic(&min_stat, context, GSS_C_QOP_DEFAULT,
+				   &msg_buf, &xmit_buf);
+	    if (maj_stat != GSS_S_COMPLETE) {
+		display_status("signing message", maj_stat, min_stat);
+		return (-1);
+	    }
+
+	    if (msg_buf.value) {
+		free(msg_buf.value);
+		msg_buf.value = 0;
+	    }
+
+	    /* Send the signature block to the client */
+	    if (send_token(s, TOKEN_MIC, &xmit_buf) < 0)
+		return (-1);
+
+	    if (xmit_buf.value) {
+		free(xmit_buf.value);
+		xmit_buf.value = 0;
+	    }
+	} else {
+	    if (msg_buf.value) {
+		free(msg_buf.value);
+		msg_buf.value = 0;
+	    }
+	    if (send_token(s, TOKEN_NOOP, empty_token) < 0)
+		return (-1);
+	}
+    } while (1 /* loop will break if NOOP received */ );
+
+    if (context != GSS_C_NO_CONTEXT) {
+	/* Delete context */
+	maj_stat = gss_delete_sec_context(&min_stat, &context, NULL);
+	if (maj_stat != GSS_S_COMPLETE) {
+	    display_status("deleting context", maj_stat, min_stat);
+	    return (-1);
+	}
+    }
+
+    if (logfile)
+	fflush(logfile);
+
+    return (0);
+}
+
+static int max_threads = 1;
+
+#ifdef _WIN32
+static  thread_count = 0;
+static HANDLE hMutex = NULL;
+static HANDLE hEvent = NULL;
+
+void
+InitHandles(void)
+{
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+void
+CleanupHandles(void)
+{
+    CloseHandle(hMutex);
+    CloseHandle(hEvent);
+}
+
+BOOL
+WaitAndIncrementThreadCounter(void)
+{
+    for (;;) {
+	if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
+	    if (thread_count < max_threads) {
+		thread_count++;
+		ReleaseMutex(hMutex);
+		return TRUE;
+	    } else {
+		ReleaseMutex(hMutex);
+
+		if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) {
+		    continue;
+		} else {
+		    return FALSE;
+		}
+	    }
+	} else {
+	    return FALSE;
+	}
+    }
+}
+
+BOOL
+DecrementAndSignalThreadCounter(void)
+{
+    if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
+	if (thread_count == max_threads)
+	    ResetEvent(hEvent);
+	thread_count--;
+	ReleaseMutex(hMutex);
+	return TRUE;
+    } else {
+	return FALSE;
+    }
+}
+#endif
+
+struct _work_plan
+{
+    int     s;
+    gss_cred_id_t server_creds;
+    int     export;
+};
+
+void
+worker_bee(void *param)
+{
+    struct _work_plan *work = (struct _work_plan *) param;
+
+    /* this return value is not checked, because there's
+     * not really anything to do if it fails 
+     */
+    sign_server(work->s, work->server_creds, work->export);
+    closesocket(work->s);
+    free(work);
+
+#ifdef _WIN32
+    if (max_threads > 1)
+	DecrementAndSignalThreadCounter();
+#endif
+}
+
+int
+main(argc, argv)
+    int     argc;
+    char  **argv;
+{
+    char   *service_name;
+    gss_cred_id_t server_creds;
+    OM_uint32 min_stat;
+    u_short port = 4444;
+    int     once = 0;
+    int     do_inetd = 0;
+    int     export = 0;
+
+    logfile = stdout;
+    display_file = stdout;
+    argc--;
+    argv++;
+    while (argc) {
+	if (strcmp(*argv, "-port") == 0) {
+	    argc--;
+	    argv++;
+	    if (!argc)
+		usage();
+	    port = atoi(*argv);
+	}
+#ifdef _WIN32
+	else if (strcmp(*argv, "-threads") == 0) {
+	    argc--;
+	    argv++;
+	    if (!argc)
+		usage();
+	    max_threads = atoi(*argv);
+	}
+#endif
+	else if (strcmp(*argv, "-verbose") == 0) {
+	    verbose = 1;
+	} else if (strcmp(*argv, "-once") == 0) {
+	    once = 1;
+	} else if (strcmp(*argv, "-inetd") == 0) {
+	    do_inetd = 1;
+	} else if (strcmp(*argv, "-export") == 0) {
+	    export = 1;
+	} else if (strcmp(*argv, "-logfile") == 0) {
+	    argc--;
+	    argv++;
+	    if (!argc)
+		usage();
+	    /* Gross hack, but it makes it unnecessary to add an
+	     * extra argument to disable logging, and makes the code
+	     * more efficient because it doesn't actually write data
+	     * to /dev/null. */
+	    if (!strcmp(*argv, "/dev/null")) {
+		logfile = display_file = NULL;
+	    } else {
+		logfile = fopen(*argv, "a");
+		display_file = logfile;
+		if (!logfile) {
+		    perror(*argv);
+		    exit(1);
+		}
+	    }
+	} else
+	    break;
+	argc--;
+	argv++;
+    }
+    if (argc != 1)
+	usage();
+
+    if ((*argv)[0] == '-')
+	usage();
+
+#ifdef _WIN32
+    if (max_threads < 1) {
+	fprintf(stderr, "warning: there must be at least one thread\n");
+	max_threads = 1;
+    }
+
+    if (max_threads > 1 && do_inetd)
+	fprintf(stderr,
+		"warning: one thread may be used in conjunction with inetd\n");
+
+    InitHandles();
+#endif
+
+    service_name = *argv;
+
+    if (server_acquire_creds(service_name, &server_creds) < 0)
+	return -1;
+
+    if (do_inetd) {
+	close(1);
+	close(2);
+
+	sign_server(0, server_creds, export);
+	close(0);
+    } else {
+	int     stmp;
+
+	if ((stmp = create_socket(port)) >= 0) {
+	    if (listen(stmp, max_threads == 1 ? 0 : max_threads) < 0)
+		perror("listening on socket");
+
+	    do {
+		struct _work_plan *work = malloc(sizeof(struct _work_plan));
+
+		if (work == NULL) {
+		    fprintf(stderr, "fatal error: out of memory");
+		    break;
+		}
+
+		/* Accept a TCP connection */
+		if ((work->s = accept(stmp, NULL, 0)) < 0) {
+		    perror("accepting connection");
+		    continue;
+		}
+
+		work->server_creds = server_creds;
+		work->export = export;
+
+		if (max_threads == 1) {
+		    worker_bee((void *) work);
+		}
+#ifdef _WIN32
+		else {
+		    if (WaitAndIncrementThreadCounter()) {
+			uintptr_t handle =
+			    _beginthread(worker_bee, 0, (void *) work);
+			if (handle == (uintptr_t) - 1) {
+			    closesocket(work->s);
+			    free(work);
+			}
+		    } else {
+			fprintf(stderr,
+				"fatal error incrementing thread counter");
+			closesocket(work->s);
+			free(work);
+			break;
+		    }
+		}
+#endif
+	    } while (!once);
+
+	    closesocket(stmp);
+	}
+    }
+
+    (void) gss_release_cred(&min_stat, &server_creds);
+
+#ifdef _WIN32
+    CleanupHandles();
+#endif
+
+    return 0;
+}
diff --git a/mechglue/src/appl/gssftp/.Sanitize b/mechglue/src/appl/gssftp/.Sanitize
new file mode 100644
index 000000000..0c2a9a0c1
--- /dev/null
+++ b/mechglue/src/appl/gssftp/.Sanitize
@@ -0,0 +1,40 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+README.gssftp
+arpa
+configure.in
+configure
+ftp
+ftpd
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/gssftp/ChangeLog b/mechglue/src/appl/gssftp/ChangeLog
new file mode 100644
index 000000000..002f457a5
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ChangeLog
@@ -0,0 +1,129 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2003-06-05  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: Don't check for vfork as we no longer use it
+
+2003-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't use libkrb524.a any more.
+	* ftpd.c: Don't include krb524.h.
+	(main): Don't call krb524_init_ets.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+2002-12-06  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Quote the argument to AC_CHECK_HEADER. Autoconf
+	2.57 was having problems.
+
+2002-11-26  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Set SETENVSRC correctly.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-07-24  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add check for getev() to avoid problems when
+	building setenv.c from appl/bsd.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in (SETENVOBJ): Define NEED_SETENV if compiling our own.
+
+2001-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for strerror.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_CHECK_FUNCS, AC_CHECK_HEADERS, AC_C_CONST
+	instead of the older names AC_HAVE_FUNCS, AC_HEADER_CHECK,
+	AC_CONST. Consolidate use of function testing macros.
+
+2000-03-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for alpha*-dec-osf* instead of
+	alpha-dec-osf*.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-04-13    <tytso@rsts-11.mit.edu>
+
+	* configure.in: Check to see if we need to pull in the util
+		library in order to find logwtmp().  (Needed for
+		Linux/glibc 2.1.)
+
+Wed Mar 24 17:14:06 1999  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Check for sys/sockio.h for systems that need it
+	for SIOCATMARK.
+
+Thu Feb 18 18:35:00 1999  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add check for setluid.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-05-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Add check for paths.h
+
+Fri Apr 10 22:52:41 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add CHECK_SETJMP and CHECK_SIGNALS.
+
+Wed Feb 18 15:28:07 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Sat Feb 14 10:34:26 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Remove USE_ANAME
+
+Fri Feb 13 15:31:26 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define LOCAL_SUBDIRS to recurse into the
+		ftp and ftpd subdirectories.
+
+	* configure.in: Create the makefiles for all of the subdirectories
+		and move all of the configure.in tests from the
+		subdirectories into this configure.in.
+	
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sun Jan 14 03:19:55 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* README.gssftp: new file, documents history of this implementation.
+
+Sat Sep 30 16:28:34 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in, Makefile.in: New files controlling the
+	construction of the GSSAPI implementation of ftp.
+
diff --git a/mechglue/src/appl/gssftp/Makefile.in b/mechglue/src/appl/gssftp/Makefile.in
new file mode 100644
index 000000000..4ea8995e8
--- /dev/null
+++ b/mechglue/src/appl/gssftp/Makefile.in
@@ -0,0 +1,6 @@
+thisconfigdir=.
+myfulldir=appl/gssftp
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCAL_SUBDIRS=ftp ftpd
+LDFLAGS = -g
diff --git a/mechglue/src/appl/gssftp/README.gssftp b/mechglue/src/appl/gssftp/README.gssftp
new file mode 100644
index 000000000..e0dff5200
--- /dev/null
+++ b/mechglue/src/appl/gssftp/README.gssftp
@@ -0,0 +1,45 @@
+Notes on "Secure FTP" Implementation
+===============================================
+Mark Eichin <eichin@cygnus.com>, Cygnus Support
+last modified: 1995 Jan 14
+===============================================
+
+This implementation is supplied by Cygnus Support for inclusion in the MIT
+Kerberos V5 Release. 
+
+Copyrights:
+The original BSD ftp implementation is:
+ * Copyright (c) 1980, 1983, 1985, 1988, 1989, 1990, 1991 Regents of the
+   University of California.
+
+History and Credits (as of 1995 Jan 14)
+================================================
+
+Steve Lunt at Bellcore developed the original V4 kerberized ftp. He
+also started writing the IETF ftpsec draft at the time. This was
+available to the public, and Cygnus eventually incorporated it into
+CNS V4.
+
+Steve Lunt left Bellcore, and dropped out of the computer security
+field altogether, after handing the draft off to Marc Horowitz at
+OpenVision, who was working on a commercial GSSAPI implementation.
+
+Marc Horowitz left OpenVision and is back at MIT currently; in the
+mean time, Cygnus took the V4 ftp and upgraded it to use GSSAPI and
+draft-08, as well as integrating it into the Kerberos V5 autoconf
+based configuration scheme.
+
+Bill Schoofs <wjs@cray.com> supplied corrections to the implementation
+to more correctly match draft 8, as well as correcting some of the
+remaining KERBEROS_V4 code.
+
+Karri Balk - Contractor <kbalk@cup.hp.com> supplied additional
+corrections based on interoperation testing with non-free
+implementations.
+
+Marc Horowitz has indicated that a draft 9 is forthcoming, with some
+clarifications based on experience with this implementation.
+
+No other free implementation of draft-8 is known at this time. 
+
+
diff --git a/mechglue/src/appl/gssftp/arpa/.Sanitize b/mechglue/src/appl/gssftp/arpa/.Sanitize
new file mode 100644
index 000000000..d804b41d7
--- /dev/null
+++ b/mechglue/src/appl/gssftp/arpa/.Sanitize
@@ -0,0 +1,34 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+ChangeLog
+ftp.h
+telnet.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/gssftp/arpa/ChangeLog b/mechglue/src/appl/gssftp/arpa/ChangeLog
new file mode 100644
index 000000000..41d73c0f1
--- /dev/null
+++ b/mechglue/src/appl/gssftp/arpa/ChangeLog
@@ -0,0 +1,5 @@
+Sun Jan 14 01:51:18 1996  Bill Schoofs <wjs@cray.com>
+
+	* arpa/ftp.h: define PROT_E and add Confidential to levelnames,
+	so as to return more precise errors.
+
diff --git a/mechglue/src/appl/gssftp/arpa/ftp.h b/mechglue/src/appl/gssftp/arpa/ftp.h
new file mode 100644
index 000000000..e20285c4c
--- /dev/null
+++ b/mechglue/src/appl/gssftp/arpa/ftp.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1983, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ftp.h	5.6 (Berkeley) 4/3/91
+ */
+
+#ifndef _FTP_H_
+#define	_FTP_H_
+
+/* Definitions for FTP; see RFC-765. */
+
+/*
+ * Reply codes.
+ */
+#define PRELIM		1	/* positive preliminary */
+#define COMPLETE	2	/* positive completion */
+#define CONTINUE	3	/* positive intermediate */
+#define TRANSIENT	4	/* transient negative completion */
+#define ERROR		5	/* permanent negative completion */
+
+/*
+ * Type codes
+ */
+#define	TYPE_A		1	/* ASCII */
+#define	TYPE_E		2	/* EBCDIC */
+#define	TYPE_I		3	/* image */
+#define	TYPE_L		4	/* local byte size */
+
+#ifdef FTP_NAMES
+char *typenames[] =  {"0", "ASCII", "EBCDIC", "Image", "Local" };
+#endif
+
+/*
+ * Form codes
+ */
+#define	FORM_N		1	/* non-print */
+#define	FORM_T		2	/* telnet format effectors */
+#define	FORM_C		3	/* carriage control (ASA) */
+#ifdef FTP_NAMES
+char *formnames[] =  {"0", "Nonprint", "Telnet", "Carriage-control" };
+#endif
+
+/*
+ * Structure codes
+ */
+#define	STRU_F		1	/* file (no record structure) */
+#define	STRU_R		2	/* record structure */
+#define	STRU_P		3	/* page structure */
+#ifdef FTP_NAMES
+char *strunames[] =  {"0", "File", "Record", "Page" };
+#endif
+
+/*
+ * Mode types
+ */
+#define	MODE_S		1	/* stream */
+#define	MODE_B		2	/* block */
+#define	MODE_C		3	/* compressed */
+#ifdef FTP_NAMES
+char *modenames[] =  {"0", "Stream", "Block", "Compressed" };
+#endif
+
+/*
+ * Protection levels
+ */
+#define	PROT_C		1	/* clear */
+#define	PROT_S		2	/* safe */
+#define	PROT_P		3	/* private */
+#define	PROT_E		4	/* confidential */
+
+#ifdef FTP_NAMES
+char *levelnames[] =  {"0", "Clear", "Safe", "Private", "Confidential" };
+#endif
+
+#if defined(KERBEROS) && defined(NOENCRYPTION)
+/* define away krb_rd_priv and krb_mk_priv.  Don't need them anyway. */
+/* This might not be the best place for this ... */
+#define krb_rd_priv(o,l,ses,s,h,c,m) krb_rd_safe(o,l,s,h,c,m)
+#define krb_mk_priv(i,o,l,ses,s,h,c) krb_mk_safe(i,o,l,s,h,c)
+#endif
+
+/*
+ * Record Tokens
+ */
+#define	REC_ESC		'\377'	/* Record-mode Escape */
+#define	REC_EOR		'\001'	/* Record-mode End-of-Record */
+#define REC_EOF		'\002'	/* Record-mode End-of-File */
+
+/*
+ * Block Header
+ */
+#define	BLK_EOR		0x80	/* Block is End-of-Record */
+#define	BLK_EOF		0x40	/* Block is End-of-File */
+#define BLK_ERRORS	0x20	/* Block is suspected of containing errors */
+#define	BLK_RESTART	0x10	/* Block is Restart Marker */
+
+#define	BLK_BYTECOUNT	2	/* Bytes in this block */
+
+#endif /* !_FTP_H_ */
diff --git a/mechglue/src/appl/gssftp/arpa/telnet.h b/mechglue/src/appl/gssftp/arpa/telnet.h
new file mode 100644
index 000000000..019bfeb60
--- /dev/null
+++ b/mechglue/src/appl/gssftp/arpa/telnet.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)telnet.h	5.14 (Berkeley) 4/3/91
+ */
+
+#ifndef _TELNET_H_
+#define	_TELNET_H_
+
+/*
+ * Definitions for the TELNET protocol.
+ */
+#define	IAC	255		/* interpret as command: */
+#define	DONT	254		/* you are not to use option */
+#define	DO	253		/* please, you use option */
+#define	WONT	252		/* I won't use option */
+#define	WILL	251		/* I will use option */
+#define	SB	250		/* interpret as subnegotiation */
+#define	GA	249		/* you may reverse the line */
+#define	EL	248		/* erase the current line */
+#define	EC	247		/* erase the current character */
+#define	AYT	246		/* are you there */
+#define	AO	245		/* abort output--but let prog finish */
+#define	IP	244		/* interrupt process--permanently */
+#define	BREAK	243		/* break */
+#define	DM	242		/* data mark--for connect. cleaning */
+#define	NOP	241		/* nop */
+#define	SE	240		/* end sub negotiation */
+#define EOR     239             /* end of record (transparent mode) */
+#define	ABORT	238		/* Abort process */
+#define	SUSP	237		/* Suspend process */
+#define	xEOF	236		/* End of file: EOF is already used... */
+
+#define SYNCH	242		/* for telfunc calls */
+
+#ifdef TELCMDS
+char *telcmds[] = {
+	"EOF", "SUSP", "ABORT", "EOR",
+	"SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC",
+	"EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0,
+};
+#else
+extern char *telcmds[];
+#endif
+
+#define	TELCMD_FIRST	xEOF
+#define	TELCMD_LAST	IAC
+#define	TELCMD_OK(x)	((x) <= TELCMD_LAST && (x) >= TELCMD_FIRST)
+#define	TELCMD(x)	telcmds[(x)-TELCMD_FIRST]
+
+/* telnet options */
+#define TELOPT_BINARY	0	/* 8-bit data path */
+#define TELOPT_ECHO	1	/* echo */
+#define	TELOPT_RCP	2	/* prepare to reconnect */
+#define	TELOPT_SGA	3	/* suppress go ahead */
+#define	TELOPT_NAMS	4	/* approximate message size */
+#define	TELOPT_STATUS	5	/* give status */
+#define	TELOPT_TM	6	/* timing mark */
+#define	TELOPT_RCTE	7	/* remote controlled transmission and echo */
+#define TELOPT_NAOL 	8	/* negotiate about output line width */
+#define TELOPT_NAOP 	9	/* negotiate about output page size */
+#define TELOPT_NAOCRD	10	/* negotiate about CR disposition */
+#define TELOPT_NAOHTS	11	/* negotiate about horizontal tabstops */
+#define TELOPT_NAOHTD	12	/* negotiate about horizontal tab disposition */
+#define TELOPT_NAOFFD	13	/* negotiate about formfeed disposition */
+#define TELOPT_NAOVTS	14	/* negotiate about vertical tab stops */
+#define TELOPT_NAOVTD	15	/* negotiate about vertical tab disposition */
+#define TELOPT_NAOLFD	16	/* negotiate about output LF disposition */
+#define TELOPT_XASCII	17	/* extended ascic character set */
+#define	TELOPT_LOGOUT	18	/* force logout */
+#define	TELOPT_BM	19	/* byte macro */
+#define	TELOPT_DET	20	/* data entry terminal */
+#define	TELOPT_SUPDUP	21	/* supdup protocol */
+#define	TELOPT_SUPDUPOUTPUT 22	/* supdup output */
+#define	TELOPT_SNDLOC	23	/* send location */
+#define	TELOPT_TTYPE	24	/* terminal type */
+#define	TELOPT_EOR	25	/* end or record */
+#define	TELOPT_TUID	26	/* TACACS user identification */
+#define	TELOPT_OUTMRK	27	/* output marking */
+#define	TELOPT_TTYLOC	28	/* terminal location number */
+#define	TELOPT_3270REGIME 29	/* 3270 regime */
+#define	TELOPT_X3PAD	30	/* X.3 PAD */
+#define	TELOPT_NAWS	31	/* window size */
+#define	TELOPT_TSPEED	32	/* terminal speed */
+#define	TELOPT_LFLOW	33	/* remote flow control */
+#define TELOPT_LINEMODE	34	/* Linemode option */
+#define TELOPT_XDISPLOC	35	/* X Display Location */
+#define TELOPT_ENVIRON	36	/* Environment variables */
+#define	TELOPT_AUTHENTICATION 37/* Authenticate */
+#define	TELOPT_ENCRYPT	38	/* Encryption option */
+#define	TELOPT_EXOPL	255	/* extended-options-list */
+
+
+#define	NTELOPTS	(1+TELOPT_ENCRYPT)
+#ifdef TELOPTS
+char *telopts[NTELOPTS+1] = {
+	"BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
+	"STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
+	"NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
+	"NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
+	"DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
+	"SEND LOCATION", "TERMINAL TYPE", "END OF RECORD",
+	"TACACS UID", "OUTPUT MARKING", "TTYLOC",
+	"3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW",
+	"LINEMODE", "XDISPLOC", "ENVIRON", "AUTHENTICATION",
+	"ENCRYPT",
+	0,
+};
+#define	TELOPT_FIRST	TELOPT_BINARY
+#define	TELOPT_LAST	TELOPT_ENCRYPT
+#define	TELOPT_OK(x)	((x) <= TELOPT_LAST && (x) >= TELOPT_FIRST)
+#define	TELOPT(x)	telopts[(x)-TELOPT_FIRST]
+#endif
+
+/* sub-option qualifiers */
+#define	TELQUAL_IS	0	/* option is... */
+#define	TELQUAL_SEND	1	/* send option */
+#define	TELQUAL_INFO	2	/* ENVIRON: informational version of IS */
+#define	TELQUAL_REPLY	2	/* AUTHENTICATION: client version of IS */
+#define	TELQUAL_NAME	3	/* AUTHENTICATION: client version of IS */
+
+/*
+ * LINEMODE suboptions
+ */
+
+#define	LM_MODE		1
+#define	LM_FORWARDMASK	2
+#define	LM_SLC		3
+
+#define	MODE_EDIT	0x01
+#define	MODE_TRAPSIG	0x02
+#define	MODE_ACK	0x04
+#define MODE_SOFT_TAB	0x08
+#define MODE_LIT_ECHO	0x10
+
+#define	MODE_MASK	0x1f
+
+/* Not part of protocol, but needed to simplify things... */
+#define MODE_FLOW		0x0100
+#define MODE_ECHO		0x0200
+#define MODE_INBIN		0x0400
+#define MODE_OUTBIN		0x0800
+#define MODE_FORCE		0x1000
+
+#define	SLC_SYNCH	1
+#define	SLC_BRK		2
+#define	SLC_IP		3
+#define	SLC_AO		4
+#define	SLC_AYT		5
+#define	SLC_EOR		6
+#define	SLC_ABORT	7
+#define	SLC_EOF		8
+#define	SLC_SUSP	9
+#define	SLC_EC		10
+#define	SLC_EL		11
+#define	SLC_EW		12
+#define	SLC_RP		13
+#define	SLC_LNEXT	14
+#define	SLC_XON		15
+#define	SLC_XOFF	16
+#define	SLC_FORW1	17
+#define	SLC_FORW2	18
+
+#define	NSLC		18
+
+/*
+ * For backwards compatability, we define SLC_NAMES to be the
+ * list of names if SLC_NAMES is not defined.
+ */
+#define	SLC_NAMELIST	"0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \
+			"ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \
+			"LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0,
+#ifdef	SLC_NAMES
+char *slc_names[] = {
+	SLC_NAMELIST
+};
+#else
+extern char *slc_names[];
+#define	SLC_NAMES SLC_NAMELIST
+#endif
+
+#define	SLC_NAME_OK(x)	((x) >= 0 && (x) < NSLC)
+#define SLC_NAME(x)	slc_names[x]
+
+#define	SLC_NOSUPPORT	0
+#define	SLC_CANTCHANGE	1
+#define	SLC_VARIABLE	2
+#define	SLC_DEFAULT	3
+#define	SLC_LEVELBITS	0x03
+
+#define	SLC_FUNC	0
+#define	SLC_FLAGS	1
+#define	SLC_VALUE	2
+
+#define	SLC_ACK		0x80
+#define	SLC_FLUSHIN	0x40
+#define	SLC_FLUSHOUT	0x20
+
+#define	ENV_VALUE	0
+#define	ENV_VAR		1
+#define	ENV_ESC		2
+
+/*
+ * AUTHENTICATION suboptions
+ */
+
+/*
+ * Who is authenticating who ...
+ */
+#define	AUTH_WHO_CLIENT		0	/* Client authenticating server */
+#define	AUTH_WHO_SERVER		1	/* Server authenticating client */
+#define	AUTH_WHO_MASK		1
+
+/*
+ * amount of authentication done
+ */
+#define	AUTH_HOW_ONE_WAY	0
+#define	AUTH_HOW_MUTUAL		2
+#define	AUTH_HOW_MASK		2
+
+#define	AUTHTYPE_NULL		0
+#define	AUTHTYPE_KERBEROS_V4	1
+#define	AUTHTYPE_KERBEROS_V5	2
+#define	AUTHTYPE_SPX		3
+#define	AUTHTYPE_MINK		4
+#define	AUTHTYPE_CNT		5
+
+#define	AUTHTYPE_TEST		99
+
+#ifdef	AUTH_NAMES
+char *authtype_names[] = {
+	"NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0,
+};
+#else
+extern char *authtype_names[];
+#endif
+
+#define	AUTHTYPE_NAME_OK(x)	((x) >= 0 && (x) < AUTHTYPE_CNT)
+#define	AUTHTYPE_NAME(x)	authtype_names[x]
+
+/*
+ * ENCRYPTion suboptions
+ */
+#define	ENCRYPT_IS		0	/* I pick encryption type ... */
+#define	ENCRYPT_SUPPORT		1	/* I support encryption types ... */
+#define	ENCRYPT_REPLY		2	/* Initial setup response */
+#define	ENCRYPT_START		3	/* Am starting to send encrypted */
+#define	ENCRYPT_END		4	/* Am ending encrypted */
+#define	ENCRYPT_REQSTART	5	/* Request you start encrypting */
+#define	ENCRYPT_REQEND		6	/* Request you send encrypting */
+#define	ENCRYPT_ENC_KEYID	7
+#define	ENCRYPT_DEC_KEYID	8
+#define	ENCRYPT_CNT		9
+
+#define	ENCTYPE_ANY		0
+#define	ENCTYPE_DES_CFB64	1
+#define	ENCTYPE_DES_OFB64	2
+#define	ENCTYPE_CNT		3
+
+#ifdef	ENCRYPT_NAMES
+char *encrypt_names[] = {
+	"IS", "SUPPORT", "REPLY", "START", "END",
+	"REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID",
+	0,
+};
+char *enctype_names[] = {
+	"ANY", "DES_CFB64",  "DES_OFB64",  0,
+};
+#else
+extern char *encrypt_names[];
+extern char *enctype_names[];
+#endif
+
+
+#define	ENCRYPT_NAME_OK(x)	((x) >= 0 && (x) < ENCRYPT_CNT)
+#define	ENCRYPT_NAME(x)		encrypt_names[x]
+
+#define	ENCTYPE_NAME_OK(x)	((x) >= 0 && (x) < ENCTYPE_CNT)
+#define	ENCTYPE_NAME(x)		enctype_names[x]
+
+#endif /* !_TELNET_H_ */
diff --git a/mechglue/src/appl/gssftp/configure.in b/mechglue/src/appl/gssftp/configure.in
new file mode 100644
index 000000000..6d86d77b8
--- /dev/null
+++ b/mechglue/src/appl/gssftp/configure.in
@@ -0,0 +1,71 @@
+K5_AC_INIT(README.gssftp)
+CONFIG_RULES
+AC_C_CONST
+AC_PROG_INSTALL
+AC_PROG_YACC
+KRB5_SIGTYPE
+CHECK_SIGNALS
+CHECK_SIGPROCMASK
+CHECK_SETJMP
+CHECK_WAIT_TYPE
+DECLARE_SYS_ERRLIST
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_HEADER_STDARG
+AC_CHECK_HEADER(termios.h,[AC_CHECK_FUNC(cfsetispeed,AC_DEFINE(POSIX_TERMIOS))])
+AC_CHECK_HEADERS(unistd.h stdlib.h string.h sys/select.h sys/sockio.h paths.h)
+CHECK_UTMP
+DECLARE_SYS_ERRLIST
+AC_REPLACE_FUNCS(getdtablesize)
+AC_CHECK_FUNCS(getcwd getdtablesize getusershell seteuid setreuid setresuid strerror getenv)
+AC_CHECK_LIB(crypt,crypt) dnl 
+KRB5_AC_LIBUTIL
+dnl 
+dnl copied from appl/bsd/configure.in
+dnl
+AC_MSG_CHECKING([setenv])
+AC_CACHE_VAL(krb5_cv_setenv,
+[AC_TRY_LINK(
+[],[setenv("PATH","/bin",0);],
+krb5_cv_setenv=yes,krb5_cv_setenv=no)])
+AC_MSG_RESULT($krb5_cv_setenv)
+if test $krb5_cv_setenv = no; then
+SETENVSRC='$(srcdir)/../../bsd/setenv.c'
+SETENVOBJ=setenv.o
+AC_SUBST([SETENVSRC])
+AC_SUBST([SETENVOBJ])
+AC_DEFINE([NEED_SETENV])
+fi
+dnl
+dnl
+dnl
+AC_MSG_CHECKING([shadow password support])
+AC_CACHE_VAL(krb5_cv_shadow_pwd,
+[AC_TRY_LINK(
+[#include <sys/types.h>
+#include <pwd.h>
+#include <shadow.h>],
+[struct spwd *sp = getspnam("root")],
+krb5_cv_shadow_pwd=yes, krb5_cv_shadow_pwd=no)])
+AC_MSG_RESULT($krb5_cv_shadow_pwd)
+if test $krb5_cv_shadow_pwd = yes; then
+AC_DEFINE(HAVE_SHADOW)
+fi
+case $krb5_cv_host in
+alpha*-dec-osf*)
+	AC_CHECK_LIB(security,setluid,
+		AC_DEFINE(HAVE_SETLUID)
+		FTPD_LIBS="$FTPD_LIBS -lsecurity"
+	)
+	;;
+esac
+dnl
+dnl
+dnl
+AC_SUBST(FTPD_LIBS)
+dnl
+dnl
+dnl
+KRB5_BUILD_PROGRAM
+V5_AC_OUTPUT_MAKEFILE(. ftp ftpd)
diff --git a/mechglue/src/appl/gssftp/ftp/.Sanitize b/mechglue/src/appl/gssftp/ftp/.Sanitize
new file mode 100644
index 000000000..1ffc3702e
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/.Sanitize
@@ -0,0 +1,51 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+cmds.c
+cmdtab.c
+configure.in
+configure
+domacro.c
+ftp.M
+ftp.c
+ftp_var.h
+getpass.c
+glob.c
+main.c
+pathnames.h
+pclose.c
+radix.c
+ruserpass.c
+secure.c
+secure.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/gssftp/ftp/ChangeLog b/mechglue/src/appl/gssftp/ftp/ChangeLog
new file mode 100644
index 000000000..1f17c0f45
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/ChangeLog
@@ -0,0 +1,740 @@
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftp.c (do_auth): Handle a return code of 335, where the
+	authentication exchange requires more messages.
+
+2003-06-25  Tom Yu  <tlyu@mit.edu>
+
+	* ftp.c (do_auth): Call gss_release_buffer() on send_tok
+	immediately after sending it.  Call gss_release_name() on
+	target_name at outer_loop instead of inside the loop.
+
+2003-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftp.c (recvrequest): Add new argument indicating whether "-" and
+	"|..." special treatment should be disabled.
+	* ftp_var.h (recvrequest): Update declaration.
+	* cmds.c (remglob, ls, mls): Pass 0 as the extra argument.
+	(mget): Pass 1.
+	(getit): Pass 1 iff only one filename was supplied.
+
+2003-06-05  Sam Hartman  <hartmans@mit.edu>
+
+	* pclose.c (mypopen): use fork not vfork
+
+2003-01-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftp.c (hookup, initconn, dataconn): Use socklen_t when passing
+	address to socket functions.
+
+2002-11-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* main.c (makeargv): Report an error if parsed arguments won't fit
+	in margv array.
+	* ftp_var.h (line, argbuf): Extend to 500 bytes.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(OUTPRE)ftp.exe): Use ws2_32.lib instead of
+	wsock32.lib.
+
+2002-04-11  Sam Hartman  <hartmans@mit.edu>
+
+	* radix.c : Initialize c and D to suppress warning; code was already correct
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* ftp.c: Include Winsock 2 instead of Winsock.
+	* ftp_var.h: Include Winsock 2 headers.
+	* secure.c: Include port-sockets.h on Win32.
+	* main.c: Include mswsock.h (MS Winsock extensions) so that we get
+	some socket options we need to convert sockets to "file
+	descriptors" used in posix-like routines.  We now need to pull
+	this in explictly now that we are using Winsock 2.
+
+2002-04-04  Sam Hartman  <hartmans@mit.edu>
+
+	* radix.c (decode;):  Patch from Mark Eichin for one char buffer overflow [635]
+	
+
+2002-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* cmds.c (unix): Define if BSD is defined.
+
+2001-11-30  Tom Yu  <tlyu@mit.edu>
+
+	* glob.c (execbrc): Fix some fencepost errors.  Don't copy
+	uninitialized memory past the end of the pattern string.  Don't
+	increment pointer beyond string end.
+
+2001-10-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* ftp.c: Conditionalize declarations of some "unused variables" to
+	eliminate warnings.  ANSI-fy definitions.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* cmds.c, ftp.c, ftp_var.h, glob.c, main.c, ruserpass.c, secure.c,
+	secure.h: Make prototypes unconditional.  Don't define PROTOTYPE
+	macro.
+
+2001-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* glob.c (amatch, case '*'): Treat multiple asterisks the same as
+	one.
+
+2001-07-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftp.c: Declare mech_type in struct gss_trials gss_OID to be
+	compatible with GSS_C_NO_OID type. (was gss_OID *).
+
+2001-07-27  Danilo Almeida  <dalmeida@mit.edu>
+
+	* ftp.c: Remove local Win32-specific definition of gss_mech_krb5.
+	Use GSS_C_NO_OID instead of gss_mech_krb5 for mech_type to use an
+	implementation specific default.
+
+2001-07-24  Tom Yu  <tlyu@mit.edu>
+
+	* getpass.c: Remove duplicate definitions of sig_t, my_sig_t;
+	they're already declared in ftp_var.h.
+
+	* ftp_var.h (FDOPEN_SOCKET): Fix second arg.
+
+2001-07-23  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in, cmds.c, ftp.c, ftp_var.h, getpass.c, glob.c,
+	main.c, ruserpass.c, secure.c, secure.h: Quick and dirty Win32
+	port.  Changes include using sockets more portably; changing the
+	method of getting username, home directory, and temporary
+	filenames; adding password reading code for Win32; directory
+	enumeration via FindNextFile() rather than readdir(); removing OUT
+	labels (which appear to cause problems with MSVC++ 6.0).  Since
+	ANSI C, assume we have stdarg.h.
+
+2001-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* secure.c: Instead of hard wiring the FUDGE_FACTOR, new variables
+	to keep track of the total buffer length desired and the actual
+	maximum that can be fitted. Add secure_determine_constants() to
+	determine the mechanism dependent overhead. This has a hard limit
+	for krb4 - for gssapi use gss_wrap_size_limit.
+
+2001-06-15  Ezra Peisach  <epeisach@mit.edu>
+
+	* cmds.c, domacro.c: Cast arguments to isspace() and isdigit()
+	from char to int.
+
+	* ftp.c: krb5_mk_priv(), krb5_mk_safe() expect C_Block *.
+
+2001-05-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* cmds.c (setpeer): Port number should be unsigned short.  (Patch
+	from Garry Zacheiss.)  Add upper-bound check in case short is not
+	exactly 16 bits.  Don't truncate the port number before checking.
+
+2001-04-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftp_var.h: Prototype for recvrequest() needs volatile
+ 	declaration to match code. Native Dec Alpha compiler errors on the
+ 	inconsistancy.
+
+	* secure.h (PROTOTYPE): Only define if not defined already.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftp_var.h (PROTOTYPE): Always define to use supplied prototype.
+	* secure.h (PROTOTYPE): Likewise.
+
+2001-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* cmds.c (strerror): Only define if not HAVE_STRERROR.
+	* ftp.c (strerror): Likewise.
+	* secure.c (secure_putbuf, secure_getbyte): Use strerror.
+
+2000-11-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* cmds.c (globulize): Use correct address of globbed results when
+	freeing storage.  Patch from Nalin Dahyabhai <nalin@redhat.com>.
+
+2000-10-23  Tom Yu  <tlyu@mit.edu>
+
+	* secure.h: Change SESSION to refer to &cred.session instead, so
+	as to have the correct pointer type when passed to
+	{mk,rd}_{safe,priv}() functions.
+
+Tue Oct 10 05:01:21 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftp.c (do_auth): Remove debugging printf which I inadvertantly
+ 	introduced.
+
+2000-08-29  Alexandra Ellwood  <lxs@mit.edu>
+
+        * cmds.c, cmdtab.c, ftp_var.h: renamed getmode() and setmode()
+	to get_mode() and set_mode() to avoid a collision with Mac OS X
+	file permission bits manipulation functions of the same name
+	which get included through unistd.h.
+
+Tue Aug 22 17:10:39 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* secure.h (myaddr): For secure data stream, pass the port number
+ 	of the data stream and not the control stream to krb_mk_priv.
+
+2000-08-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* domacro.c: Compiler warning cleanups and fix the overflow fix to
+	index the proper array.
+
+	* cmds.c, cmdtab.c, ftp.c, ftp_var.h, getpass.c, glob.c, main.c,
+	radix.c, ruserpass.c, secure.c, secure.h: Compiler warning
+	cleanups including providing prototypes, cleanup of assignments in
+	conditionals, including unistd.h and stdlib.h (if present),
+	declaring local functions as static.
+
+	* Makefile.in: Do not compile pclose.c - the code is not used. 
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* domacro.c (domacro): Don't overflow "line2"
+	* ftp.c (getreply, krb4 compat): Bail if message data too big for buffer
+	(getreply, gssapi): Ditto.
+	(pswitch): Don't overflow "ntin", "ntout", "mapin", "mapout".
+	(do_auth, krb4 compat): Don't overflow "realm".
+
+2000-04-27  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* cmds.c (remglob): Don't overflow buffer "temp".
+	(shell): Don't overflow buffer "shellnam".
+	(quote1): "buf"
+	* glob.c (ftpglob): Fix boundary in buffer "agpath".
+	(expand): Don't overflow buffer pointed to by "gpath".
+	(execbrc): Don't overflow buffer "restbuf".
+
+2000-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* cmds.c (mls): Declare some variables volatile to protect against
+	getting clobbered by setjmp/longjmp.
+	* ftp.c (sendrequest, recvrequest, proxtrans): Ditto.
+	* main.c (main): Ditto.
+	* pclose.c (mypopen): Ditto.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftp.c (getreply): Don't declare strpbrk or strstr functions if
+	they're defined as macros.
+
+1999-08-27  Tom Yu  <tlyu@mit.edu>
+
+	* ftp.c: Diable krb5-mech2 for now.
+
+Tue May 11 11:58:00 1999  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftp.c: Inclusion of gssapi_krb5.h requires gssapi_generic.h.
+
+Thu Feb 25 23:05:03 1999  Tom Yu  <tlyu@mit.edu>
+
+	* secure.c (secure_putbuf): Revert Sam's last change; if
+ 	FUDGE_FACTOR is wrong, then badness can happen.  Also, if
+ 	out_buf.length != nbytes+FUDGE_FACTOR, heap corruption could
+ 	happen.  We really should be using gss_wrap_size_limit() or
+ 	something like that, but doing so would require substantial
+ 	amounts of reworking. [krb5-appl/685]
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* ftp.c (login): *always* encrypt the password, regardless
+	of the default command mode.
+	(do_auth): Try the new krb5 mech, and if that fails, try the
+	old one.
+
+1998-10-26  Geoffrey King  <gjking@mit.edu>
+
+	* ftp.M: Add documentation for new ccc and cprotect commands.
+	Also, add previously omitted command line options -u and -t and
+	"passive" command to the man page.
+	
+	* main.c (main): Print out a usage message instead of just
+	"unknown option."
+
+Fri Oct  2 16:16:13 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* cmdtab.c: Update help message for passive mode so that it
+ 		indicates that the "passive" command toggles passive mode.
+
+	* main.c (main): Make passive mode off by default.
+
+Fri Aug 28 18:46:35 1998  Geoffrey King  <gjking@mit.edu>
+
+	* cmds.c (user): Replace "oldlevel" with the more descriptive
+	"oldclevel".  Also, replace all occurrences of "dlevel" in this
+	function with "clevel".
+
+	* ftp.c (login): Test whether or not the server actually requires
+	"PASS dummy" by first sending "PWD" and checking the return value.
+	
+Wed Aug 12 02:26:26 1998  Geoffrey King  <gjking@mit.edu>
+
+	* ftp.c, cmds.c, cmdtab.c, main.c, secure.c, ftp_var.h: Replace
+ 	global variable level with separate variables clevel and dlevel
+ 	for the control channel and data channel protection levels,
+ 	respectively, so that the user may specify separate protection
+ 	levels for each channel.  Similarly, functions such as getlevel
+ 	and setlevel are now getclevel/getdlevel, and setclevel/setdlevel.
+
+	* cmdtab.c: Add new FTP commands "cprotect" to allow the user to 
+	set the control channel protection level (similar to "protect"), 
+	and "ccc" (Clear Command Channel) which sets the control channel
+	protection level to clear (per the RFC).
+	
+Fri Aug  7 22:39:47 1998  Matthew D Hancher  <mdh@mit.edu>
+
+	* ftp.c (do_auth): Make verbosity not disappear if GSSAPI fails.
+	(getreply): Move 'S:' and 'P:' from verbose to debug.
+
+Fri Aug  7 11:45:17 1998  Tom Yu  <tlyu@mit.edu>
+
+	* ftp.c (getreply): Restore proper setting of safe.  This variable
+	was previously being set to the value of code rather than to the
+	boolean expression (code == 631), which it had been previously.
+	The bug resulted in all replies from the server being parsed as
+	krb_safe messages even when they were krb_priv messages.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* radix.c (argv): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Sat Apr 25 01:53:04 1998  Sam Hartman  <hartmans@luminous.mit.edu>
+
+	* cmds.c (setpeer): Fix so that autologin is respected again
+
+1998-04-21  Ken Raeburn  <raeburn@cygnus.com>
+
+	* glob.c (ftpglob): Always allocate new storage, even if no magic
+	glob characters were found, because the caller will always free
+	the storage.
+
+Tue Apr  7 16:53:58 1998  Dan Winship  <danw@mit.edu>
+
+	* secure.c (secure_putbyte): Set nout = 0 *before* calling
+ 	secure_putbuf: if the transfer is aborted, the SIGURG handler will
+ 	longjmp out, so the line after the secure_putbuf will never get
+ 	executed, so nout would never be reset and the next transfer
+ 	would overrun ucbuf.
+
+Wed Feb 18 15:29:35 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 15:31:46 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (thisconfigdir), configure.in: Point the
+ 		configuration directory at our parent, and remove our
+		local configure.in
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Jan 29 19:39:27 1998  Dan Winship  <danw@mit.edu>
+
+	* ftp.h:
+	* ftp.M:
+	* main.c (main): add options -f (forward credentials) and -x
+	(automatically negotiate encryption)
+
+	* ftp.c (do_auth): implement -f. Also, don't complain that
+	ftp/hostname doesn't exist if host/hostname does.
+
+	* cmds.c (setpeer): implement -x
+
+
+Thu Dec 11 23:26:58 1997  Tom Yu  <tlyu@mit.edu>
+
+	* ftp.c:
+	* main.c: Don't include netdb.h or sys/socket.h if krb.h is
+	included; this works around an Ultrix bug where those headers
+	aren't protected against multiple inclusion.
+
+Sat Dec  6 18:17:10 1997  Sam Hartman  <hartmans@luminous.mesas.com>
+
+	* main.c (main): Add -u for unauthenticated
+
+	* ftp_var.h: Add autoauth
+
+	* cmds.c (setpeer): Automatic authentication should not be
+ 	dependent on autologin; use -u instead.
+
+
+Thu Oct 16 01:20:30 1997  Tom Yu  <tlyu@mit.edu>
+
+	* main.c: Change KERBEROS to KRB5_KRB4_COMPAT where appropriate.
+
+	* secure.c: Use <secure.h> rather than "secure.h" so that the
+	correct secure.h gets included (the one in the $(srcdir) of the
+	directory we're compiling secure.c into).  From danw@mit.edu.
+
+	* ftp.c: Change KERBEROS to KRB5_KRB4_COMPAT where appropriate.
+	Re-order the clauses so that that GSSAPI gets tried before
+	KERBEROS_V4.
+
+	* Makefile.in: Update LOCALINCLUDE and the link line to DTRT with
+	krb4 compatibility.
+
+Sun Aug 17 14:23:39 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(srcdir) where needed.
+
+Wed Apr 30 14:59:03 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* cmds.c (getit): Fix Y2K bug in the parsing of the MDTM command.
+		[krb5-appl/399]
+
+Wed Feb  5 20:29:31 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Fri Nov 22 15:48:19 1996  unknown  <bjaspan@mit.edu>
+
+	* ftp.c (hookup): use sizeof instead of h_length to determine
+ 	number of bytes of addr to copy from DNS response [krb5-misc/211]
+
+Fri Sep 27 16:05:09 1996  Tom Yu  <tlyu@mit.edu>
+
+	* cmds.c (setpeer): Apply jik's fix so "-n" actually works as
+	intended.
+
+
+Tue Sep 10 14:07:15 1996  Tom Yu  <tlyu@mit.edu>
+
+	* ftp.M: remove ".so man1/header.doc"
+
+Fri Aug 16 20:04:03 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* secure.c (nbyte;): Fix for Kerberos IV version of the memory
+ 	allocation bug I fixed for Kerberos V; you want nbyte +
+ 	FUDGE_FACTOR, not out_buff.length.
+
+Tue Jul 30 19:45:45 1996  Samuel D Hartman  (hartmans@vorlon)
+
+	* ftp.c (empt resety): Use fd_set as a typedef not a struct.
+        Linux breaks.
+
+Mon Jul 29 22:37:23 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* secure.c: Do not assume sizeof(long) = 4 for sending lengths OTW
+
+	* configure.in: Determine sizeof short, int, long for secure.c
+
+Fri Jul 26 20:55:12 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* secure.c (secure_putbyte): Reset nout to zero on errorso we
+        don't overflow our buffer.
+
+	* ftp.c (sendrequest): If there is an error in secure_write, break
+        out of the loop.
+
+	* secure.c(FUDGE_FACTOR): Define for GSSAPI so writes don't fail.
+        i chose a value of 64, which is larger than the apparent 52 bytes
+        of additional data but I'm not sure 52 is constant.
+
+	(secure_putbuf): Set bufsize to the size we actually allocate
+	     Also, write foure bytes for net_len no matter how long it
+	     actually is.  I would rather declare it a 32-bit type but am not
+	     sure whether to use the GSSAPI, krb4, or krb5 32-bit int.
+
+Wed Jul 10 16:40:19 1996  Marc Horowitz  <marc@mit.edu>
+
+	* cmdtab.c (cmdtab[]), cmds.c (delete_file): rename delete() to
+ 	delete_file() to avoid conflict with the dbm delete() function
+
+Thu Mar 28 21:07:40 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* cmds.c (setpeer): Define unix for HP-UX.
+
+Thu Mar 28 19:26:53 1996  Marc Horowitz  <marc@mit.edu>
+
+	* secure.c (secure_putbuf): the size computation of the output
+ 	buffer was ok for krb4, but completely wrong for gssapi.  I moved
+ 	the code into the KERBEROS block, and wrote suitable code for
+ 	GSSAPI.  This affects the client and server, which were core
+ 	dumping on hpux.
+
+Mon Mar 18 12:12:44 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* secure.c, ftp.c, ftp_var.h: Define STDARG if HAVE_STDARG_H is
+ 		defined (in addition to the other tests)
+
+	* configure.in: Add AC_HEADER_STDARG
+
+Fri Feb 16 15:50:51 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* ftp.c (do_auth): return status handling fixes from kbalk@hp.com.
+
+Tue Jan 16 19:05:31 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* ftp.c (login): move do_auth ...
+	* cmds.c (setpeer): ... to just before login call.
+
+Mon Feb 5 09:06:16 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Check for stdlib.h
+
+	* secure.c, pclose.c, ruserpass.c, ftp.c: Include stdlib.h if
+		present for malloc declarations.
+
+Thu Jan 18 18:33:18 1996  Sam Hartman  <hartmans@zygorthian-space-raiders.MIT.EDU>
+
+	* cmds.c: Handle sys_errlist and remove declaration of errno.
+
+	* configure.in: Check to see if we need to declare sys_errlist.
+
+	* ftp.c secure.c: Only define sys_errlist if needed
+
+Thu Jan 18 11:55:50 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Check for sys/select.h
+
+	* ftp.c: Include sys/select.h if present.
+
+Sun Jan 14 01:54:35 1996  Bill Schoofs <wjs@cray.com>
+
+	* Makefile.in (DEFINES): define NOCONFIDENTIAL for future use.
+	* ftp.c (command): recognize 533, not 402, for 'server unwilling
+	to accept' 
+	(getreply): recognize 633 for confidential reply, and then don't
+	support it.
+	
+Tue Jan  2 19:17:47 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* pclose.c: test HAVE_GETDTABLESIZE instead of hpux.
+	* configure.in: set HAVE_GETDTABLESIZE.
+
+Fri Oct 20 11:59:32 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* ftp.c (do_auth): synthesize channel bindings from myctladdr and
+	hisctladdr, based on changes pending for draft 9.
+
+Thu Oct 19 04:47:36 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* configure.in: check for POSIX_TERMIOS just like appl/bsd does.
+
+Wed Oct  4 19:24:39 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* ftp, pclose, ruserpass.c, secure.c: don't ever declare malloc.
+
+Sun Oct  1 03:30:30 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* ftp.c (do_auth): accept ADAT 3yz response. Clean up loops, add
+	lots of debugging messages.
+
+Sun Oct  1 00:56:55 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in: use FTP_BUFSIZ everywhere and make it large for
+	now.
+	* ftp.c: only look at "host" for now. Report error parsing
+	name. Handle gssapi error reporting better.
+	
+
+Sat Sep 30 22:26:37 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* ftp.c, secure.c: correct gssapi includes. Fix some typos and
+	missing declarations.
+
+Sat Sep 30 21:31:09 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (depend, install): change to double colon rules.
+	* cmds.c: no conf.h, check HAVE_GETCWD, use krb5_sigtype.
+	* configure.in: check KRB5_SIGTYPE, CHECK_SIGPROCMASK,
+	CHECK_WAIT_TYPE, and getcwd.
+	* ftp.c: no conf.h, use krb5_sigtype.
+	(secure_command): use user_gss_error.
+	(do_auth): cycle through gss_services.
+	(user_gss_error): new function, decomposes GSSAPI errors and sends
+	them to standard error.
+	(secure_gss_error): hook for secure.c common functions to get the
+	correct error routine.
+	* getpass.c, main.c: no conf.h, use krb5_sigtype.
+	* pclose.c: no conf.h, use krb5_sigtype.
+	(mypclose): obey USE_SIGPROCMASK.
+	* secure.c (secure_getbyte): use generic secure_gss_error.
+	
+Sat Sep 30 16:43:28 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in, Makefile.in: new files for port to GSSAPI and
+	build within the Kerberos V5 build tree.
+	* ftp.c, secure.c: GSSAPI authentication changes based on the IETF
+	CAT working group ***DRAFT*** FTP Security specification, draft
+	number 8, appendix I.
+
+
+**** previous change logs from CNS V4 modifications of Steve Lunt's
+     draft-3 ftp client, which this is based on. ****
+	
+Wed Jul 26 21:01:42 1995  Ken Raeburn  <raeburn@cygnus.com>
+
+	* domacro.c: Include string.h.
+	* secure.c: Ditto.
+
+Mon Jul 10 14:54:41 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
+
+	* glob.c (matchdir): #if 0 code that uses a private member of the
+	DIR structure to check whether a filename passed to opendir is a
+	directory or not.
+
+Fri May 26 19:36:12 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* glob.c (matchdir): open "." explicitly if gpath is null.
+
+Fri May 19 16:11:07 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* ftp.c (ptransfer): be sure that printf(%g) gets a float, not an
+	implicit double, by doing the whole calculation in the variable.
+
+Thu Feb  2 13:40:04 1995  Ian Lance Taylor  <ian@cygnus.com>
+
+	* ftp.c: Don't try to use IP_TOS if the IP_TOS argument
+	(IPTOS_LOWDELAY, etc.) is not defined.
+
+Wed Jan 18 14:07:33 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* ftp.1: Include man1/tmac.doc.
+
+	* ftp.c (initconn): If the PASV command is rejected, turn off
+	passive mode and try again.
+
+Wed Jan  4 11:21:34 1995  Ian Lance Taylor  <ian@tweedledumb.cygnus.com>
+
+	* cmds.c, ftp.c: Use mygetpass instead of getpass.
+
+	* ruserpass.c: Don't include <utmp.h>.  Don't declare getlogin,
+	getpass, or getuttmp.
+
+Thu Dec 29 15:19:44 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* cmds.c (setpeer): add || defined(linux) to the NBBY == 8 check,
+	since this code is appropriate under linux.
+
+Thu Dec 29 14:11:37 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* cmds.c (siteidle): renamed idle() to avoid conflict with linux
+	idle(void).
+	* cmdtab.c: rename declaration and cmdtab entry.
+
+Tue Dec 27 13:29:08 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* ftp.c: If STDARG is defined, or if __STDC__ is defined and
+	VARARGS is not defined, include <stdarg.h>, instead of
+	<varargs.h>.
+	(command): Use <stdarg.h> routines if STDARG || (__STDC__ && !
+	VARARGS).
+	(secure_error): Likewise.
+	* ftp_var.h (command): Declare if STDARG || (__STDC__ && !
+	VARARGS).
+	* secure.c (secure_error): Likewise.
+
+	* secure.h (hisaddr): Define as hisdataaddr.
+	* ftp.c (hisdataaddr): New global variable.
+	(initconn): Set hisdataaddr to data_addr.
+	(dataconn): Use hisdataaddr instead of local variable from.
+
+Fri Dec 23 15:18:12 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* cmds.c (unix): Define if _AIX is defined (AIX compiler does not
+	predefine unix).
+
+	* ftp.c (login): When choosing the default login name, use the
+	values of the environment variables LOGNAME and then USER in
+	preference to calling getlogin.
+
+Thu Dec 22 14:59:34 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* cmds.c (gettype): Sometimes type will be zero, which requires
+	special handling.
+
+	* main.c: Include <krb.h>.
+	(main): Support new option: -k.
+	* ftp.c (realm): New global variable.
+	(do_auth): Remove local variable realm; use new global instead.
+	Don't call krb_realmofhost if realm is set.
+	* ftp.1: Document -k.
+
+Fri Dec 16 10:53:08 1994  Ian Lance Taylor  <ian@cygnus.com>
+
+	Fixes for Alpha OSF/1:
+	* cmds.c: Redefine sig_t to my_sig_t to avoid header file
+	conflict.
+	* ftp.c: Likewise.
+
+	Fixes for SCO:
+	* cmdtab.c: Include <stdio.h> before ftp_var.h.
+	* domacro.c: Move include of <stdio.h> before include of
+	ftp_var.h.  Don't include <sys/ttychars.h>.
+	* main.c: Move include of <stdio.h> before include of ftp_var.h.
+
+	Fixes for AIX:
+	* cmds.c (mput): Use 0 instead of NULL when an integer is
+	expected.
+	(getit, mget): Likewise.
+	* ftp_var.h (strncpy, strncat, strcat, strcpy): Don't declare.
+	* ruserpass.c (strcpy): Don't declare.
+	* secure.c: Include <netinet/in.h>.
+
+	Fixes for Irix 4:
+	* ftp_var.h: Unless DEFINITIONS is defined, declare variables
+	rather than defining them.
+	* ftp.c: Define DEFINITIONS before including ftp_var.h.
+	(recvrequest): If NOSTBLKSIZE is defined, use BUFSIZ instead of
+	st_blksize.
+	* getpass.c: Put note after #endif in /* */
+	* pclose.c: Likewise.
+	* ruserpass.c (token): Move before ruserpass.
+	(ruserpass): Don't declare token.
+
+	General fixes to make it compile on Solaris: Use sigtype for
+	signal handler return values, including conf.h where needed.  Add
+	a dummy argument to signal handler functions. Replace index,
+	rindex, bzero and bcopy with ANSI C functions.  Cast Kerberos
+	routine arguments to avoid warnings.  Also:
+	* cmds.c: Include <string.h>.  If POSIX is defined, include
+	unistd.h, otherwise define getcwd to call getwd.
+	(lcd): Call getcwd instead of getwd.
+	(shell): If WAIT_USES_INT, use int instead of union wait.
+	* ftp.c: Include <string.h>.
+	(L_SET, L_INCR): Define if not defined.
+
+	* ftp_var.h (index, rindex): Don't declare.
+	* main.c: Inclue <string.h>.
+	* pclose.c (getdtablesize): New function on hpux or __svr4__.
+	* radix.c (radix_encode): Cast strcmp arguments to avoid warnings.
+	* ruserpass.c: Include <string.h>.  If POSIX, include <stdlib.h>
+	and don't declare malloc.
+	(MAXHOSTNAMELEN): Define if not defined.
+	(index): Don't declare.
+
+Thu Dec 15 16:13:44 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* Initial checkin.  Based on Steve Lunt's ftp program, which was
+        based on BSD code.
diff --git a/mechglue/src/appl/gssftp/ftp/Makefile.in b/mechglue/src/appl/gssftp/ftp/Makefile.in
new file mode 100644
index 000000000..9e15dc6b5
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/Makefile.in
@@ -0,0 +1,101 @@
+thisconfigdir=./..
+myfulldir=appl/gssftp/ftp
+mydir=ftp
+BUILDTOP=$(REL)..$(S)..$(S)..
+#
+# appl/gssftp/ftp/Makefile.in
+#
+DEFINES = -DGSSAPI -DFTP_BUFSIZ=10240
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+SRCS	= $(srcdir)/cmds.c $(srcdir)/cmdtab.c $(srcdir)/domacro.c \
+	  $(srcdir)/ftp.c $(srcdir)/getpass.c $(srcdir)/glob.c \
+	  $(srcdir)/main.c $(srcdir)/radix.c \
+	  $(srcdir)/ruserpass.c $(srcdir)/secure.c 
+
+
+OBJS	= $(OUTPRE)cmds.$(OBJEXT) $(OUTPRE)cmdtab.$(OBJEXT) \
+	  $(OUTPRE)domacro.$(OBJEXT) $(OUTPRE)ftp.$(OBJEXT) \
+	  $(OUTPRE)getpass.$(OBJEXT) $(OUTPRE)glob.$(OBJEXT) \
+	  $(OUTPRE)main.$(OBJEXT) $(OUTPRE)radix.$(OBJEXT) \
+	  $(OUTPRE)ruserpass.$(OBJEXT) $(OUTPRE)secure.$(OBJEXT)
+
+LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir) @KRB4_INCLUDES@
+
+#
+# We cannot have @KRB4_INCLUDES@ under Windows, since we do not use
+# configure, so we redefine LOCALINCLUDES not to have that.
+#
+
+##WIN32##LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)
+
+all-unix::	ftp
+all-windows::	$(OUTPRE)ftp.exe
+
+ftp:	$(OBJS) $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o ftp $(OBJS) $(GSS_LIBS) $(KRB4COMPAT_LIBS)
+
+$(OUTPRE)ftp.exe: $(OBJS) $(GLIB) $(KLIB)
+	link $(EXE_LINKOPTS) -out:$@ $** ws2_32.lib advapi32.lib
+
+clean-unix::
+	$(RM) ftp
+
+depend::
+
+install-unix::
+	for f in ftp; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		$(DESTDIR)$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
+
+ftp.o cmds.o main.o:	$(srcdir)/../arpa/ftp.h
+ftp.o cmds.o cmdtab.o domacro.o main.o ruserpass.o: $(srcdir)/ftp_var.h 
+secure.o: secure.h
+
+cmds.o: $(srcdir)/cmds.c
+cmdtab.o: $(srcdir)/cmdtab.c
+ftp.o: $(srcdir)/ftp.c
+getpass.o: $(srcdir)/getpass.c
+glob.o: $(srcdir)/glob.c
+main.o: $(srcdir)/main.c
+pclose.o: $(srcdir)/pclose.c
+ruserpass.o: $(srcdir)/ruserpass.c
+domacro.o: $(srcdir)/domacro.c
+radix.o: $(srcdir)/radix.c
+secure.o: $(srcdir)/secure.c
+
+# NOPOSTFIX
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)cmds.$(OBJEXT): cmds.c $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(srcdir)/../arpa/ftp.h \
+  ftp_var.h pathnames.h
+$(OUTPRE)cmdtab.$(OBJEXT): cmdtab.c ftp_var.h
+$(OUTPRE)domacro.$(OBJEXT): domacro.c ftp_var.h
+$(OUTPRE)ftp.$(OBJEXT): ftp.c $(srcdir)/../arpa/ftp.h \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssapi/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+  $(BUILDTOP)/include/krb5.h ftp_var.h secure.h
+$(OUTPRE)getpass.$(OBJEXT): getpass.c ftp_var.h
+$(OUTPRE)glob.$(OBJEXT): glob.c ftp_var.h
+$(OUTPRE)main.$(OBJEXT): main.c ftp_var.h $(srcdir)/../arpa/ftp.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+$(OUTPRE)radix.$(OBJEXT): radix.c ftp_var.h
+$(OUTPRE)ruserpass.$(OBJEXT): ruserpass.c ftp_var.h
+$(OUTPRE)secure.$(OBJEXT): secure.c $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssapi/gssapi_generic.h secure.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(srcdir)/../arpa/ftp.h
diff --git a/mechglue/src/appl/gssftp/ftp/cmds.c b/mechglue/src/appl/gssftp/ftp/cmds.c
new file mode 100644
index 000000000..b9cb2a2a2
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/cmds.c
@@ -0,0 +1,2523 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmds.c	5.26 (Berkeley) 3/5/91";
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command Routines.
+ */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <port-sockets.h>
+
+#ifdef _WIN32
+#include <sys/stat.h>
+#include <direct.h>
+#include <mbstring.h>
+#undef ERROR
+#else
+#include <sys/wait.h>
+#include <sys/stat.h>
+#endif
+
+#include <arpa/ftp.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+
+#ifdef HAVE_GETCWD
+#define getwd(x) getcwd(x,MAXPATHLEN)
+#endif
+
+#include "ftp_var.h"
+#include "pathnames.h"
+
+extern	char *globerr;
+extern	char *home;
+extern	char *remglob();
+#ifndef HAVE_STRERROR
+#define strerror(error) (sys_errlist[error])
+#ifdef NEED_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+#endif
+
+extern off_t restart_point;
+extern char reply_string[];
+
+char *mname;
+jmp_buf jabort;
+
+extern	char *auth_type;
+extern int do_auth();
+
+static int globulize (char **);
+static int confirm (char *, char *);
+static int getit (int, char **, int, char *);
+static sigtype mabort (int);
+static void quote1 (char *, int, char **);
+static char *dotrans (char *);
+static char *domap (char *);
+
+/*
+ * `Another' gets another argument, and stores the new argc and argv.
+ * It reverts to the top level (via main.c's intr()) on EOF/error.
+ *
+ * Returns false if no new arguments have been added.
+ */
+int 
+another(pargc, pargv, prompt)
+	int *pargc;
+	char ***pargv;
+	char *prompt;
+{
+        int len = strlen(line), ret;
+	extern sig_t intr();
+
+	if (len >= sizeof(line) - 3) {
+		printf("sorry, arguments too long\n");
+		intr();
+	}
+	printf("(%s) ", prompt);
+	line[len++] = ' ';
+	if (fgets(&line[len], (signed) sizeof(line) - len, stdin) == NULL)
+		intr();
+	len += strlen(&line[len]);
+	if (len > 0 && line[len - 1] == '\n')
+		line[len - 1] = '\0';
+	makeargv();
+	ret = margc > *pargc;
+	*pargc = margc;
+	*pargv = margv;
+	return (ret);
+}
+
+/*
+ * Connect to peer server and
+ * auto-login, if possible.
+ */
+void setpeer(argc, argv)
+	int argc;
+	char *argv[];
+{
+	char *host, *hookup();
+	unsigned short port;
+
+	if (connected) {
+		printf("Already connected to %s, use close first.\n",
+			hostname);
+		code = -1;
+		return;
+	}
+	if (argc < 2)
+		(void) another(&argc, &argv, "to");
+	if (argc < 2 || argc > 3) {
+		printf("usage: %s host-name [port]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	port = sp->s_port;
+	if (argc > 2) {
+		int iport = atoi (argv[2]);
+		if (iport <= 0 || iport >= 65536) {
+			printf("%s: bad port number-- %s\n", argv[1], argv[2]);
+			printf ("usage: %s host-name [port]\n", argv[0]);
+			code = -1;
+			return;
+		}
+		port = htons(iport);
+	}
+	host = hookup(argv[1], port);
+	if (host) {
+		int overbose;
+
+		connected = 1;
+		/*
+		 * Set up defaults for FTP.
+		 */
+		clevel = dlevel = PROT_C;
+		type = TYPE_A;
+		curtype = TYPE_A;
+		form = FORM_N;
+		mode = MODE_S;
+		stru = STRU_F;
+		(void) strcpy(bytename, "8"), bytesize = 8;
+		if (autoauth) {
+			if (do_auth() && autoencrypt) {
+ 				clevel = PROT_P;
+				setpbsz(1<<20);
+				if (command("PROT P") == COMPLETE)
+					dlevel = PROT_P;
+				else
+					fprintf(stderr, "ftp: couldn't enable encryption\n");
+			}
+			if(auth_type && clevel == PROT_C)
+				clevel = PROT_S;
+			if(autologin)
+				(void) login(argv[1]);
+		}
+
+#ifndef unix
+/* sigh */
+#if defined(_AIX) || defined(__hpux) || defined(BSD)
+#define unix
+#endif
+#endif
+
+/* XXX - WIN32 - Is this really ok for Win32 (binary vs text mode)? */
+#if defined(unix) && (NBBY == 8 || defined(linux)) || defined(_WIN32)
+/*
+ * this ifdef is to keep someone form "porting" this to an incompatible
+ * system and not checking this out. This way they have to think about it.
+ */
+		overbose = verbose;
+		if (debug == 0)
+			verbose = -1;
+		if (command("SYST") == COMPLETE && overbose) {
+			register char *cp, c=0;
+			cp = strchr(reply_string+4, ' ');
+			if (cp == NULL)
+				cp = strchr(reply_string+4, '\r');
+			if (cp) {
+				if (cp[-1] == '.')
+					cp--;
+				c = *cp;
+				*cp = '\0';
+			}
+
+			printf("Remote system type is %s.\n",
+				reply_string+4);
+			if (cp)
+				*cp = c;
+		}
+		if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
+			if (proxy)
+				unix_proxy = 1;
+			else
+				unix_server = 1;
+			/*
+			 * Set type to 0 (not specified by user),
+			 * meaning binary by default, but don't bother
+			 * telling server.  We can use binary
+			 * for text files unless changed by the user.
+			 */
+			type = 0;
+			if (overbose)
+			    printf("Using %s mode to transfer files.\n",
+				"binary");
+		} else {
+			if (proxy)
+				unix_proxy = 0;
+			else
+				unix_server = 0;
+			if (overbose && 
+			    !strncmp(reply_string, "215 TOPS20", 10))
+				printf(
+"Remember to set tenex mode when transfering binary files from this machine.\n");
+		}
+		verbose = overbose;
+#endif /* unix */
+	}
+}
+
+struct	levels {
+	char	*p_name;
+	char	*p_mode;
+	int	p_level;
+} levels[] = {
+	{ "clear",	"C",	PROT_C },
+	{ "safe",	"S",	PROT_S },
+#ifndef NOENCRYPTION
+	{ "private",	"P",	PROT_P },
+#endif
+	{ 0,             0,     0}
+};
+
+static char *
+getclevel()
+{
+	register struct levels *p;
+
+	for (p = levels; p->p_level != clevel; p++);
+	return(p->p_name);
+}
+
+static char *
+getdlevel()
+{
+	register struct levels *p;
+
+	for (p = levels; p->p_level != dlevel; p++);
+	return(p->p_name);
+}
+
+char *plevel[] = {
+	"protect",
+	"",
+	0
+};
+
+/*
+ * Set control channel protection level.
+ */
+void setclevel(argc, argv)
+	char *argv[];
+{
+	register struct levels *p;
+	int comret;
+
+	if (argc > 2) {
+		char *sep;
+
+		printf("usage: %s [", argv[0]);
+		sep = " ";
+		for (p = levels; p->p_name; p++) {
+			printf("%s%s", sep, p->p_name);
+			if (*sep == ' ')
+				sep = " | ";
+		}
+		printf(" ]\n");
+		code = -1;
+		return;
+	}
+	if (argc < 2) {
+		printf("Using %s protection level for commands.\n",
+			getclevel());
+		code = 0;
+		return;
+	}
+	for (p = levels; p->p_name; p++)
+		if (strcmp(argv[1], p->p_name) == 0)
+			break;
+	if (p->p_name == 0) {
+		printf("%s: unknown protection level\n", argv[1]);
+		code = -1;
+		return;
+	}
+	if (!auth_type) {
+		if (strcmp(p->p_name, "clear"))
+			printf("Cannot set protection level to %s\n", argv[1]);
+		return;
+	}
+	if (!strcmp(p->p_name, "clear")) {
+		comret = command("CCC");
+		if (comret == COMPLETE)
+			clevel = PROT_C; 
+		return;
+	}
+	clevel = p->p_level;
+	printf("Control channel protection level set to %s.\n", p->p_name);
+}
+
+/*
+ * Set data channel protection level.
+ */
+void
+setdlevel(argc, argv)
+	char *argv[];
+{
+	register struct levels *p;
+	int comret;
+
+	if (argc > 2) {
+		char *sep;
+
+		printf("usage: %s [", argv[0]);
+		sep = " ";
+		for (p = levels; p->p_name; p++) {
+			printf("%s%s", sep, p->p_name);
+			if (*sep == ' ')
+				sep = " | ";
+		}
+		printf(" ]\n");
+		code = -1;
+		return;
+	}
+	if (argc < 2) {
+		printf("Using %s protection level to transfer files.\n",
+			getdlevel());
+		code = 0;
+		return;
+	}
+	for (p = levels; p->p_name; p++)
+		if (strcmp(argv[1], p->p_name) == 0)
+			break;
+	if (p->p_name == 0) {
+		printf("%s: unknown protection level\n", argv[1]);
+		code = -1;
+		return;
+	}
+	if (!auth_type) {
+		if (strcmp(p->p_name, "clear"))
+			printf("Cannot set protection level to %s\n", argv[1]);
+		return;
+	}
+	/* Start with a PBSZ of 1 meg */
+	if (p->p_level != PROT_C) setpbsz(1<<20);
+	comret = command("PROT %s", p->p_mode);
+	if (comret == COMPLETE)
+		dlevel = p->p_level;
+}
+
+
+/*
+ * Set clear command protection level.
+ */
+/*VARARGS*/
+void
+ccc()
+{
+	plevel[1] = "clear";
+	setclevel(2, plevel);
+}
+
+/*
+ * Set clear data protection level.
+ */
+/*VARARGS*/
+void
+setclear()
+{
+	plevel[1] = "clear";
+	setdlevel(2, plevel);
+}
+
+/*
+ * Set safe data protection level.
+ */
+/*VARARGS*/
+void
+setsafe()
+{
+	plevel[1] = "safe";
+	setdlevel(2, plevel);
+}
+
+#ifndef NOENCRYPTION
+/*
+ * Set private data protection level.
+ */
+/*VARARGS*/
+void
+setprivate()
+{
+	plevel[1] = "private";
+	setdlevel(2, plevel);
+}
+#endif
+
+struct	types {
+	char	*t_name;
+	char	*t_mode;
+	int	t_type;
+	char	*t_arg;
+} types[] = {
+	{ "ascii",	"A",	TYPE_A,	0 },
+	{ "binary",	"I",	TYPE_I,	0 },
+	{ "image",	"I",	TYPE_I,	0 },
+	{ "ebcdic",	"E",	TYPE_E,	0 },
+	{ "tenex",	"L",	TYPE_L,	bytename },
+	{  0,            0 ,    0,      0}
+};
+
+static char *
+gettype()
+{
+	register struct types *p;
+	int t;
+
+	t = type;
+	if (t == 0)
+		t = TYPE_I;
+	for (p = types; p->t_type != t; p++);
+	return(p->t_name);
+}
+
+/*
+ * Set transfer type.
+ */
+void
+settype(argc, argv)
+	int argc;
+	char *argv[];
+{
+	register struct types *p;
+	int comret;
+
+	if (argc > 2) {
+		char *sep;
+
+		printf("usage: %s [", argv[0]);
+		sep = " ";
+		for (p = types; p->t_name; p++) {
+			printf("%s%s", sep, p->t_name);
+			sep = " | ";
+		}
+		printf(" ]\n");
+		code = -1;
+		return;
+	}
+	if (argc < 2) {
+		printf("Using %s mode to transfer files.\n", gettype());
+		code = 0;
+		return;
+	}
+	for (p = types; p->t_name; p++)
+		if (strcmp(argv[1], p->t_name) == 0)
+			break;
+	if (p->t_name == 0) {
+		printf("%s: unknown mode\n", argv[1]);
+		code = -1;
+		return;
+	}
+	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
+		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
+	else
+		comret = command("TYPE %s", p->t_mode);
+	if (comret == COMPLETE)
+		curtype = type = p->t_type;
+}
+
+/*
+ * Internal form of settype; changes current type in use with server
+ * without changing our notion of the type for data transfers.
+ * Used to change to and from ascii for listings.
+ */
+void changetype(newtype, show)
+	int newtype, show;
+{
+	register struct types *p;
+	int comret, oldverbose = verbose;
+
+	if (newtype == 0)
+		newtype = TYPE_I;
+	if (newtype == curtype)
+		return;
+	if (debug == 0 && show == 0)
+		verbose = 0;
+	for (p = types; p->t_name; p++)
+		if (newtype == p->t_type)
+			break;
+	if (p->t_name == 0) {
+		printf("ftp: internal error: unknown type %d\n", newtype);
+		return;
+	}
+	if (newtype == TYPE_L && bytename[0] != '\0')
+		comret = command("TYPE %s %s", p->t_mode, bytename);
+	else
+		comret = command("TYPE %s", p->t_mode);
+	if (comret == COMPLETE)
+		curtype = newtype;
+	verbose = oldverbose;
+}
+
+char *stype[] = {
+	"type",
+	"",
+	0
+};
+
+/*
+ * Set binary transfer type.
+ */
+/*VARARGS*/
+void setbinary()
+{
+	stype[1] = "binary";
+	settype(2, stype);
+}
+
+/*
+ * Set ascii transfer type.
+ */
+/*VARARGS*/
+void setascii()
+{
+	stype[1] = "ascii";
+	settype(2, stype);
+}
+
+/*
+ * Set tenex transfer type.
+ */
+/*VARARGS*/
+void settenex()
+{
+	stype[1] = "tenex";
+	settype(2, stype);
+}
+
+static char *
+get_mode()
+{
+	return("stream");
+}
+
+/*
+ * Set file transfer mode.
+ */
+/*ARGSUSED*/
+void set_mode(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	printf("We only support %s mode, sorry.\n", get_mode());
+	code = -1;
+}
+
+static char *
+getform()
+{
+	return("non-print");
+}
+
+/*
+ * Set file transfer format.
+ */
+/*ARGSUSED*/
+void setform(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	printf("We only support %s format, sorry.\n", getform());
+	code = -1;
+}
+
+static char *
+getstruct()
+{
+	return("file");
+}
+
+/*
+ * Set file transfer structure.
+ */
+/*ARGSUSED*/
+void setstruct(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	printf("We only support %s structure, sorry.\n", getstruct());
+	code = -1;
+}
+
+/*
+ * Send a single file.
+ */
+void put(argc, argv)
+	int argc;
+	char *argv[];
+{
+	char *cmd;
+	int loc = 0;
+	char *oldargv1, *oldargv2;
+
+	if (argc == 2) {
+		argc++;
+		argv[2] = argv[1];
+		loc++;
+	}
+	if (argc < 2 && !another(&argc, &argv, "local-file"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "remote-file")) {
+usage:
+		printf("usage: %s local-file remote-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	oldargv1 = argv[1];
+	oldargv2 = argv[2];
+	if (!globulize(&argv[1])) {
+		code = -1;
+		return;
+	}
+	/*
+	 * If "globulize" modifies argv[1], and argv[2] is a copy of
+	 * the old argv[1], make it a copy of the new argv[1].
+	 */
+	if (argv[1] != oldargv1 && argv[2] == oldargv1) {
+		argv[2] = argv[1];
+	}
+	cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
+	if (loc && ntflag) {
+		argv[2] = dotrans(argv[2]);
+	}
+	if (loc && mapflag) {
+		argv[2] = domap(argv[2]);
+	}
+	sendrequest(cmd, argv[1], argv[2],
+	    argv[1] != oldargv1 || argv[2] != oldargv2);
+}
+
+/*
+ * Send multiple files.
+ */
+void mput(argc, argv)
+	int argc;
+	char **argv;
+{
+	register int i;
+	sig_t oldintr;
+	int ointer;
+	char *tp;
+
+	if (argc < 2 && !another(&argc, &argv, "local-files")) {
+		printf("usage: %s local-files\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mname = argv[0];
+	mflag = 1;
+	oldintr = signal(SIGINT, mabort);
+	(void) setjmp(jabort);
+	if (proxy) {
+		char *cp, *tp2, tmpbuf[MAXPATHLEN];
+
+		while ((cp = remglob(argv,0)) != NULL) {
+			if (*cp == 0) {
+				mflag = 0;
+				continue;
+			}
+			if (mflag && confirm(argv[0], cp)) {
+				tp = cp;
+				if (mcase) {
+					while (*tp && !islower((int) (*tp))) {
+						tp++;
+					}
+					if (!*tp) {
+						tp = cp;
+						tp2 = tmpbuf;
+						while ((*tp2 = *tp) != 0) {
+						     if (isupper((int) *tp2)) {
+						        *tp2 = 'a' + *tp2 - 'A';
+						     }
+						     tp++;
+						     tp2++;
+						}
+					}
+					tp = tmpbuf;
+				}
+				if (ntflag) {
+					tp = dotrans(tp);
+				}
+				if (mapflag) {
+					tp = domap(tp);
+				}
+				sendrequest((sunique) ? "STOU" : "STOR",
+				    cp, tp, cp != tp || !interactive);
+				if (!mflag && fromatty) {
+					ointer = interactive;
+					interactive = 1;
+					if (confirm("Continue with","mput")) {
+						mflag++;
+					}
+					interactive = ointer;
+				}
+			}
+		}
+		(void) signal(SIGINT, oldintr);
+		mflag = 0;
+		return;
+	}
+	for (i = 1; i < argc; i++) {
+		register char **cpp, **gargs;
+
+		if (!doglob) {
+			if (mflag && confirm(argv[0], argv[i])) {
+				tp = (ntflag) ? dotrans(argv[i]) : argv[i];
+				tp = (mapflag) ? domap(tp) : tp;
+				sendrequest((sunique) ? "STOU" : "STOR",
+				    argv[i], tp, tp != argv[i] || !interactive);
+				if (!mflag && fromatty) {
+					ointer = interactive;
+					interactive = 1;
+					if (confirm("Continue with","mput")) {
+						mflag++;
+					}
+					interactive = ointer;
+				}
+			}
+			continue;
+		}
+		gargs = ftpglob(argv[i]);
+		if (globerr != NULL) {
+			printf("%s\n", globerr);
+			if (gargs) {
+				blkfree(gargs);
+				free((char *)gargs);
+			}
+			continue;
+		}
+		for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
+			if (mflag && confirm(argv[0], *cpp)) {
+				tp = (ntflag) ? dotrans(*cpp) : *cpp;
+				tp = (mapflag) ? domap(tp) : tp;
+				sendrequest((sunique) ? "STOU" : "STOR",
+				    *cpp, tp, *cpp != tp || !interactive);
+				if (!mflag && fromatty) {
+					ointer = interactive;
+					interactive = 1;
+					if (confirm("Continue with","mput")) {
+						mflag++;
+					}
+					interactive = ointer;
+				}
+			}
+		}
+		if (gargs != NULL) {
+			blkfree(gargs);
+			free((char *)gargs);
+		}
+	}
+	(void) signal(SIGINT, oldintr);
+	mflag = 0;
+}
+
+void reget(argc, argv)
+	int argc;
+	char *argv[];
+{
+	(void) getit(argc, argv, 1, "r+w");
+}
+
+void get(argc, argv)
+	int argc;
+	char *argv[];
+{
+	(void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
+}
+
+/*
+ * Receive one file.
+ */
+static int getit(argc, argv, restartit, rmode)
+	int argc;
+	char *argv[];
+	char *rmode;
+{
+	int loc = 0;
+	char *oldargv1, *oldargv2;
+
+	if (argc == 2) {
+		argc++;
+		argv[2] = argv[1];
+		loc++;
+	}
+	if (argc < 2 && !another(&argc, &argv, "remote-file"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "local-file")) {
+usage:
+		printf("usage: %s remote-file [ local-file ]\n", argv[0]);
+		code = -1;
+		return (0);
+	}
+	oldargv1 = argv[1];
+	oldargv2 = argv[2];
+	if (!globulize(&argv[2])) {
+		code = -1;
+		return (0);
+	}
+	if (loc && mcase) {
+		char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
+
+		while (*tp && !islower((int) *tp)) {
+			tp++;
+		}
+		if (!*tp) {
+			tp = argv[2];
+			tp2 = tmpbuf;
+			while ((*tp2 = *tp) != 0) {
+				if (isupper((int) *tp2)) {
+					*tp2 = 'a' + *tp2 - 'A';
+				}
+				tp++;
+				tp2++;
+			}
+			argv[2] = tmpbuf;
+		}
+	}
+	if (loc && ntflag)
+		argv[2] = dotrans(argv[2]);
+	if (loc && mapflag)
+		argv[2] = domap(argv[2]);
+	if (restartit) {
+		struct stat stbuf;
+		int ret;
+
+		ret = stat(argv[2], &stbuf);
+		if (restartit == 1) {
+			if (ret < 0) {
+				fprintf(stderr, "local: %s: %s\n", argv[2],
+					strerror(errno));
+				return (0);
+			}
+			restart_point = stbuf.st_size;
+		} else {
+			if (ret == 0) {
+				int overbose;
+
+				overbose = verbose;
+				if (debug == 0)
+					verbose = -1;
+				if (command("MDTM %s", argv[1]) == COMPLETE) {
+					int yy, mo, day, hour, min, sec;
+					struct tm *tm;
+					verbose = overbose;
+					sscanf(reply_string,
+					    "%*s %04d%02d%02d%02d%02d%02d",
+					    &yy, &mo, &day, &hour, &min, &sec);
+					tm = gmtime(&stbuf.st_mtime);
+					tm->tm_mon++;
+					if (tm->tm_year > yy-1900)
+						return (1);
+					else if (tm->tm_year == yy-1900) {
+						if (tm->tm_mon > mo)
+							return (1);
+					} else if (tm->tm_mon == mo) {
+						if (tm->tm_mday > day)
+							return (1);
+					} else if (tm->tm_mday == day) {
+						if (tm->tm_hour > hour)
+							return (1);
+					} else if (tm->tm_hour == hour) {
+						if (tm->tm_min > min)
+							return (1);
+					} else if (tm->tm_min == min) {
+						if (tm->tm_sec > sec)
+							return (1);
+					}
+				} else {
+					printf("%s\n", reply_string);
+					verbose = overbose;
+					return (0);
+				}
+			}
+		}
+	}
+
+	recvrequest("RETR", argv[2], argv[1], rmode,
+	    argv[1] != oldargv1 || argv[2] != oldargv2, loc);
+	restart_point = 0;
+	return (0);
+}
+
+static sigtype
+mabort(sig)
+	int sig;
+{
+	int ointer;
+
+	printf("\n");
+	(void) fflush(stdout);
+	if (mflag && fromatty) {
+		ointer = interactive;
+		interactive = 1;
+		if (confirm("Continue with", mname)) {
+			interactive = ointer;
+			longjmp(jabort,0);
+		}
+		interactive = ointer;
+	}
+	mflag = 0;
+	longjmp(jabort,0);
+}
+
+/*
+ * Get multiple files.
+ */
+void mget(argc, argv)
+	int argc;
+	char **argv;
+{
+	sig_t oldintr;
+	int ointer;
+	char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
+
+	if (argc < 2 && !another(&argc, &argv, "remote-files")) {
+		printf("usage: %s remote-files\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mname = argv[0];
+	mflag = 1;
+	oldintr = signal(SIGINT,mabort);
+	(void) setjmp(jabort);
+	while ((cp = remglob(argv,proxy)) != NULL) {
+		if (*cp == '\0') {
+			mflag = 0;
+			continue;
+		}
+		if (mflag && confirm(argv[0], cp)) {
+			tp = cp;
+			if (mcase) {
+				while (*tp && !islower((int) *tp)) {
+					tp++;
+				}
+				if (!*tp) {
+					tp = cp;
+					tp2 = tmpbuf;
+					while ((*tp2 = *tp) != 0) {
+						if (isupper((int) *tp2)) {
+							*tp2 = 'a' + *tp2 - 'A';
+						}
+						tp++;
+						tp2++;
+					}
+				}
+				tp = tmpbuf;
+			}
+			if (ntflag) {
+				tp = dotrans(tp);
+			}
+			if (mapflag) {
+				tp = domap(tp);
+			}
+			recvrequest("RETR", tp, cp, "w",
+			    tp != cp || !interactive, 1);
+			if (!mflag && fromatty) {
+				ointer = interactive;
+				interactive = 1;
+				if (confirm("Continue with","mget")) {
+					mflag++;
+				}
+				interactive = ointer;
+			}
+		}
+	}
+	(void) signal(SIGINT,oldintr);
+	mflag = 0;
+}
+
+char *
+remglob(argv,doswitch)
+	char *argv[];
+	int doswitch;
+{
+#ifdef _WIN32
+	char *temp = NULL;
+#else
+	char temp[16];
+#endif
+	static char buf[MAXPATHLEN];
+	static FILE *ftemp = NULL;
+	static char **args;
+	int oldverbose, oldhash;
+	char *cp, *rmode;
+
+	if (!mflag) {
+		if (!doglob) {
+			args = NULL;
+		}
+		else {
+			if (ftemp) {
+				(void) fclose(ftemp);
+				ftemp = NULL;
+			}
+		}
+		return(NULL);
+	}
+	if (!doglob) {
+		if (args == NULL)
+			args = argv;
+		if ((cp = *++args) == NULL)
+			args = NULL;
+		return (cp);
+	}
+	if (ftemp == NULL) {
+#ifdef _WIN32
+		temp = _tempnam(_PATH_TMP, "ftpglob");
+		if (temp == NULL) {
+			printf("can't get temporary file name\n");
+			return (NULL);
+		}
+#else
+		(void) strncpy(temp, _PATH_TMP, sizeof(temp) - 1);
+		temp[sizeof(temp) - 1] = '\0';
+		(void) mktemp(temp);
+#endif /* !_WIN32 */
+		oldverbose = verbose, verbose = 0;
+		oldhash = hash, hash = 0;
+		if (doswitch) {
+			pswitch(!proxy);
+		}
+		for (rmode = "w"; *++argv != NULL; rmode = "a")
+			recvrequest ("NLST", temp, *argv, rmode, 0, 0);
+		if (doswitch) {
+			pswitch(!proxy);
+		}
+		verbose = oldverbose; hash = oldhash;
+		ftemp = fopen(temp, "r");
+		(void) unlink(temp);
+#ifdef _WIN32
+		free(temp);
+		temp = NULL;
+#endif /* _WIN32 */
+		if (ftemp == NULL) {
+			printf("can't find list of remote files, oops\n");
+			return (NULL);
+		}
+	}
+	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
+		(void) fclose(ftemp), ftemp = NULL;
+		return (NULL);
+	}
+	if ((cp = strchr(buf, '\n')) != NULL)
+		*cp = '\0';
+	return (buf);
+}
+
+static char *
+onoff(bool)
+	int bool;
+{
+
+	return (bool ? "on" : "off");
+}
+
+static void cstatus()
+{
+	if (!connected) {
+		printf(proxy ? "No proxy connection.\n" : "Not connected.\n");
+		return;
+	}
+	printf("Connected %sto %s.\n",
+		proxy ? "for proxy commands " : "", hostname);
+	if (auth_type) printf("Authentication type: %s\n", auth_type);
+	printf("Control Channel Protection Level: %s\n", getclevel());
+	printf("Data Channel Protection Level: %s\n", getdlevel());
+	printf("Passive mode %s\n", onoff(passivemode));
+	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
+		get_mode(), gettype(), getform(), getstruct());
+	printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
+		onoff(runique));
+	printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
+	if (ntflag) {
+		printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
+	}
+	else {
+		printf("Ntrans: off\n");
+	}
+	if (mapflag) {
+		printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
+	}
+	else {
+		printf("Nmap: off\n");
+	}
+}
+
+/*
+ * Show status.
+ */
+/*ARGSUSED*/
+void status(argc, argv)
+	char *argv[];
+{
+	int i;
+
+	cstatus();
+	if (!proxy) {
+		pswitch(1);
+		if (connected) putchar('\n');
+		cstatus(argc,argv);
+		if (connected) putchar('\n');
+		pswitch(0);
+	}
+	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
+		onoff(hash), onoff(sendport));
+	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
+		onoff(verbose), onoff(bell), onoff(interactive),
+		onoff(doglob));
+	if (macnum > 0) {
+		printf("Macros:\n");
+		for (i=0; i<macnum; i++) {
+			printf("\t%s\n",macros[i].mac_name);
+		}
+	}
+	code = 0;
+}
+
+/*
+ * Set beep on cmd completed mode.
+ */
+/*VARARGS*/
+void setbell()
+{
+
+	bell = !bell;
+	printf("Bell mode %s.\n", onoff(bell));
+	code = bell;
+}
+
+/*
+ * Turn on packet tracing.
+ */
+/*VARARGS*/
+void settrace()
+{
+
+	trace = !trace;
+	printf("Packet tracing %s.\n", onoff(trace));
+	code = trace;
+}
+
+/*
+ * Toggle hash mark printing during transfers.
+ */
+/*VARARGS*/
+void sethash()
+{
+
+	hash = !hash;
+	printf("Hash mark printing %s", onoff(hash));
+	code = hash;
+	if (hash)
+		printf(" (%d bytes/hash mark)", 1024);
+	printf(".\n");
+}
+
+/*
+ * Turn on printing of server echo's.
+ */
+/*VARARGS*/
+void setverbose()
+{
+
+	verbose = !verbose;
+	printf("Verbose mode %s.\n", onoff(verbose));
+	code = verbose;
+}
+
+/*
+ * Toggle PORT cmd use before each data connection.
+ */
+/*VARARGS*/
+void setport()
+{
+
+	sendport = !sendport;
+	printf("Use of PORT cmds %s.\n", onoff(sendport));
+	code = sendport;
+}
+
+/*
+ * Turn on interactive prompting
+ * during mget, mput, and mdelete.
+ */
+/*VARARGS*/
+void setprompt()
+{
+
+	interactive = !interactive;
+	printf("Interactive mode %s.\n", onoff(interactive));
+	code = interactive;
+}
+
+/*
+ * Toggle metacharacter interpretation
+ * on local file names.
+ */
+/*VARARGS*/
+void setglob()
+{
+	
+	doglob = !doglob;
+	printf("Globbing %s.\n", onoff(doglob));
+	code = doglob;
+}
+
+/*
+ * Set debugging mode on/off and/or
+ * set level of debugging.
+ */
+/*VARARGS*/
+void setdebug(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int val;
+
+	if (argc > 1) {
+		val = atoi(argv[1]);
+		if (val < 0) {
+			printf("%s: bad debugging value.\n", argv[1]);
+			code = -1;
+			return;
+		}
+	} else
+		val = !debug;
+	debug = val;
+	if (debug)
+		options |= SO_DEBUG;
+	else
+		options &= ~SO_DEBUG;
+	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
+	code = debug > 0;
+}
+
+/*
+ * Set current working directory
+ * on remote machine.
+ */
+void cd(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
+		printf("usage: %s remote-directory\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("CWD %s", argv[1]) == ERROR && code == 500) {
+		if (verbose)
+			printf("CWD command not recognized, trying XCWD\n");
+		(void) command("XCWD %s", argv[1]);
+	}
+}
+
+/*
+ * Set current working directory
+ * on local machine.
+ */
+void lcd(argc, argv)
+	int argc;
+	char *argv[];
+{
+	char buf[MAXPATHLEN];
+
+	if (argc < 2)
+		argc++, argv[1] = home;
+	if (argc != 2) {
+		printf("usage: %s local-directory\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (!globulize(&argv[1])) {
+		code = -1;
+		return;
+	}
+	if (chdir(argv[1]) < 0) {
+		fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno));
+		code = -1;
+		return;
+	}
+	printf("Local directory now %s\n", getcwd(buf, sizeof buf));
+	code = 0;
+}
+
+/*
+ * Delete a single file.
+ */
+void delete_file(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "remote-file")) {
+		printf("usage: %s remote-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	(void) command("DELE %s", argv[1]);
+}
+
+/*
+ * Delete multiple files.
+ */
+void mdelete(argc, argv)
+	int argc;
+	char **argv;
+{
+	sig_t oldintr;
+	int ointer;
+	char *cp;
+
+	if (argc < 2 && !another(&argc, &argv, "remote-files")) {
+		printf("usage: %s remote-files\n", argv[0]);
+		code = -1;
+		return;
+	}
+	mname = argv[0];
+	mflag = 1;
+	oldintr = signal(SIGINT, mabort);
+	(void) setjmp(jabort);
+	while ((cp = remglob(argv,0)) != NULL) {
+		if (*cp == '\0') {
+			mflag = 0;
+			continue;
+		}
+		if (mflag && confirm(argv[0], cp)) {
+			(void) command("DELE %s", cp);
+			if (!mflag && fromatty) {
+				ointer = interactive;
+				interactive = 1;
+				if (confirm("Continue with", "mdelete")) {
+					mflag++;
+				}
+				interactive = ointer;
+			}
+		}
+	}
+	(void) signal(SIGINT, oldintr);
+	mflag = 0;
+}
+
+/*
+ * Rename a remote file.
+ */
+void renamefile(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "from-name"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "to-name")) {
+usage:
+		printf("%s from-name to-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("RNFR %s", argv[1]) == CONTINUE)
+		(void) command("RNTO %s", argv[2]);
+}
+
+/*
+ * Get a directory listing
+ * of remote files.
+ */
+void ls(argc, argv)
+	int argc;
+	char *argv[];
+{
+	char *cmd;
+
+	if (argc < 2)
+		argc++, argv[1] = NULL;
+	if (argc < 3)
+		argc++, argv[2] = "-";
+	if (argc > 3) {
+		printf("usage: %s remote-directory local-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
+	if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
+		code = -1;
+		return;
+	}
+	if (strcmp(argv[2], "-") && *argv[2] != '|')
+		if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
+			code = -1;
+			return;
+	}
+	recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
+}
+
+/*
+ * Get a directory listing
+ * of multiple remote files.
+ */
+void mls(argc, argv)
+	int argc;
+	char **argv;
+{
+	sig_t oldintr;
+	int ointer, i;
+	char *volatile cmd, rmode[1], *dest;
+
+	if (argc < 2 && !another(&argc, &argv, "remote-files"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "local-file")) {
+usage:
+		printf("usage: %s remote-files local-file\n", argv[0]);
+		code = -1;
+		return;
+	}
+	dest = argv[argc - 1];
+	argv[argc - 1] = NULL;
+	if (strcmp(dest, "-") && *dest != '|')
+		if (!globulize(&dest) ||
+		    !confirm("output to local-file:", dest)) {
+			code = -1;
+			return;
+	}
+	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
+	mname = argv[0];
+	mflag = 1;
+	oldintr = signal(SIGINT, mabort);
+	(void) setjmp(jabort);
+	for (i = 1; mflag && i < argc-1; ++i) {
+		*rmode = (i == 1) ? 'w' : 'a';
+		recvrequest(cmd, dest, argv[i], rmode, 0, 0);
+		if (!mflag && fromatty) {
+			ointer = interactive;
+			interactive = 1;
+			if (confirm("Continue with", argv[0])) {
+				mflag ++;
+			}
+			interactive = ointer;
+		}
+	}
+	(void) signal(SIGINT, oldintr);
+	mflag = 0;
+}
+
+/*
+ * Do a shell escape
+ */
+/*ARGSUSED*/
+#ifdef _WIN32
+void shell(int argc, char **argv)
+{
+	char *AppName;
+	char ShellCmd[MAX_PATH];
+	char CmdLine[MAX_PATH];
+	int i;
+	PROCESS_INFORMATION ProcessInformation;
+	BOOL Result;
+	STARTUPINFO StartupInfo;
+	int NumBytes;
+
+#ifdef _DEBUG
+	if (trace)
+	{
+		fprintf(stderr, "entered shell\n");
+		fprintf(stderr, "arguments = \n");
+		fprintf(stderr, "   argc = %d\n", argc);
+		for (i = 0; i < argc; i++)
+		{
+			fprintf(stderr, "    argv %d = %s\n", i, argv[i]);
+		}
+	}
+#endif /* _DEBUG */
+
+	NumBytes = GetEnvironmentVariable("COMSPEC", ShellCmd, sizeof(ShellCmd));
+
+	if (NumBytes == 0)
+	{
+		code = -1;
+		return;
+	}
+
+	AppName = ShellCmd;
+	_mbscpy(CmdLine, ShellCmd);
+
+	if (argc > 1)
+	{
+		_mbsncat(CmdLine, " /C", sizeof(CmdLine));
+	}
+
+	for (i = 1; i < argc; i++)
+	{
+		_mbsncat(CmdLine, " ", sizeof(CmdLine));
+		_mbsncat(CmdLine, argv[i], sizeof(CmdLine));
+	}
+	CmdLine[sizeof(CmdLine)-1] = 0;
+
+	memset(&StartupInfo, 0, sizeof(StartupInfo));
+	StartupInfo.cb = sizeof(StartupInfo);
+	Result = CreateProcess(AppName,              /* command name */
+			       CmdLine,              /* command line w/args */
+			       NULL,                 /* sec attr (app) */
+			       NULL,                 /* sec attr (thread) */
+			       FALSE,                /* inherit flags */
+			       0,                    /* creation flags */
+			       NULL,                 /* environment */
+			       NULL,                 /* working directory */
+			       &StartupInfo,         /* startup info struct */
+			       &ProcessInformation); /* process info struct */
+
+	if (Result)
+	{
+		WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
+		CloseHandle(ProcessInformation.hProcess);
+		code = 0;
+	}
+	else {
+		code = -1;
+	}
+}
+#else
+void shell(argc, argv)
+	int argc;
+	char **argv;
+{
+	int pid;
+	sig_t old1, old2;
+	char shellnam[40], *shellprog, *namep; 
+#ifdef WAIT_USES_INT
+	int w_status;
+#else
+	union wait w_status;
+#endif
+
+	old1 = signal (SIGINT, SIG_IGN);
+	old2 = signal (SIGQUIT, SIG_IGN);
+	if ((pid = fork()) == 0) {
+		for (pid = 3; pid < 20; pid++)
+			(void) close(pid);
+		(void) signal(SIGINT, SIG_DFL);
+		(void) signal(SIGQUIT, SIG_DFL);
+		shellprog = getenv("SHELL");
+		if (shellprog == NULL)
+			shellprog = "/bin/sh";
+		namep = strrchr(shellprog,'/');
+		if (namep == NULL)
+			namep = shellprog;
+		(void) strcpy(shellnam,"-");
+		(void) strncat(shellnam, ++namep, sizeof(shellnam) - 1 - strlen(shellnam));
+		shellnam[sizeof(shellnam) - 1] = '\0';
+		if (strcmp(namep, "sh") != 0)
+			shellnam[0] = '+';
+		if (debug) {
+			printf ("%s\n", shellprog);
+			(void) fflush (stdout);
+		}
+		if (argc > 1) {
+			execl(shellprog,shellnam,"-c",altarg,(char *)0);
+		}
+		else {
+			execl(shellprog,shellnam,(char *)0);
+		}
+		perror(shellprog);
+		code = -1;
+		exit(1);
+		}
+	if (pid > 0)
+		while (wait(&w_status) != pid)
+			;
+	(void) signal(SIGINT, old1);
+	(void) signal(SIGQUIT, old2);
+	if (pid == -1) {
+		perror("Try again later");
+		code = -1;
+	}
+	else {
+		code = 0;
+	}
+	return;
+}
+#endif
+
+/*
+ * Send new user information (re-login)
+ */
+void user(argc, argv)
+	int argc;
+	char **argv;
+{
+	char macct[80];
+	int n, aflag = 0;
+
+	if (argc < 2)
+		(void) another(&argc, &argv, "username");
+	if (argc < 2 || argc > 4) {
+		printf("usage: %s username [password] [account]\n", argv[0]);
+		code = -1;
+		return;
+	}
+	n = command("USER %s", argv[1]);
+	if (n == COMPLETE)
+		n = command("PASS dummy");
+	else if (n == CONTINUE) {
+#ifndef NOENCRYPTION
+		int oldclevel;
+#endif
+		if (argc < 3)
+			argv[2] = mygetpass("Password: "), argc++;
+#ifndef NOENCRYPTION
+		if ((oldclevel = clevel) == PROT_S) clevel = PROT_P;
+#endif
+		n = command("PASS %s", argv[2]);
+#ifndef NOENCRYPTION
+		/* level may have changed */
+		if (clevel == PROT_P) clevel = oldclevel;
+#endif
+	}
+	if (n == CONTINUE) {
+		if (argc < 4) {
+			printf("Account: "); (void) fflush(stdout);
+			(void) fgets(macct, sizeof(macct) - 1, stdin);
+			macct[strlen(macct) - 1] = '\0';
+			argv[3] = macct; argc++;
+		}
+		n = command("ACCT %s", argv[3]);
+		aflag++;
+	}
+	if (n != COMPLETE) {
+		fprintf(stdout, "Login failed.\n");
+		/* code = -1;*/
+		return;
+	}
+	if (!aflag && argc == 4) {
+		(void) command("ACCT %s", argv[3]);
+	}
+	return;
+}
+
+/*
+ * Print working directory.
+ */
+/*VARARGS*/
+void pwd()
+{
+	int oldverbose = verbose;
+
+	/*
+	 * If we aren't verbose, this doesn't do anything!
+	 */
+	verbose = 1;
+	if (command("PWD") == ERROR && code == 500) {
+		printf("PWD command not recognized, trying XPWD\n");
+		(void) command("XPWD");
+	}
+	verbose = oldverbose;
+}
+
+/*
+ * Make a directory.
+ */
+void makedir(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "directory-name")) {
+		printf("usage: %s directory-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("MKD %s", argv[1]) == ERROR && code == 500) {
+		if (verbose)
+			printf("MKD command not recognized, trying XMKD\n");
+		(void) command("XMKD %s", argv[1]);
+	}
+}
+
+/*
+ * Remove a directory.
+ */
+void removedir(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "directory-name")) {
+		printf("usage: %s directory-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	if (command("RMD %s", argv[1]) == ERROR && code == 500) {
+		if (verbose)
+			printf("RMD command not recognized, trying XRMD\n");
+		(void) command("XRMD %s", argv[1]);
+	}
+}
+
+/*
+ * Send a line, verbatim, to the remote machine.
+ */
+void quote(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "command line to send")) {
+		printf("usage: %s line-to-send\n", argv[0]);
+		code = -1;
+		return;
+	}
+	quote1("", argc, argv);
+}
+
+/*
+ * Send a SITE command to the remote machine.  The line
+ * is sent verbatim to the remote machine, except that the
+ * word "SITE" is added at the front.
+ */
+void site(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
+		printf("usage: %s line-to-send\n", argv[0]);
+		code = -1;
+		return;
+	}
+	quote1("SITE ", argc, argv);
+}
+
+/*
+ * Turn argv[1..argc) into a space-separated string, then prepend initial text.
+ * Send the result as a one-line command and get response.
+ */
+static void quote1(initial, argc, argv)
+	char *initial;
+	int argc;
+	char **argv;
+{
+	register int i, len;
+	char buf[FTP_BUFSIZ];		/* must be >= sizeof(line) */
+
+	(void) strncpy(buf, initial, sizeof(buf) - 1);
+	buf[sizeof(buf) - 1] = '\0';
+	if (argc > 1) {
+		len = strlen(buf);
+		len += strlen(strncpy(&buf[len], argv[1], sizeof(buf) - 1 - len));
+		for (i = 2; i < argc; i++) {
+			buf[len++] = ' ';
+			len += strlen(strncpy(&buf[len], argv[i], sizeof(buf) - 1 - len));
+		}
+	}
+	if (command(buf) == PRELIM) {
+		while (getreply(0) == PRELIM);
+	}
+}
+
+void do_chmod(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "mode"))
+		goto usage;
+	if (argc < 3 && !another(&argc, &argv, "file-name")) {
+usage:
+		printf("usage: %s mode file-name\n", argv[0]);
+		code = -1;
+		return;
+	}
+	(void) command("SITE CHMOD %s %s", argv[1], argv[2]);
+}
+
+void do_umask(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int oldverbose = verbose;
+
+	verbose = 1;
+	(void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
+	verbose = oldverbose;
+}
+
+void siteidle(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int oldverbose = verbose;
+
+	verbose = 1;
+	(void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
+	verbose = oldverbose;
+}
+
+/*
+ * Ask the other side for help.
+ */
+void rmthelp(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int oldverbose = verbose;
+
+	verbose = 1;
+	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
+	verbose = oldverbose;
+}
+
+/*
+ * Terminate session and exit.
+ */
+/*VARARGS*/
+void quit()
+{
+
+	if (connected)
+		disconnect();
+	pswitch(1);
+	if (connected) {
+		disconnect();
+	}
+	exit(0);
+}
+
+/*
+ * Terminate session, but don't exit.
+ */
+void disconnect()
+{
+	extern FILE *cout;
+	extern SOCKET data;
+
+	if (!connected)
+		return;
+	(void) command("QUIT");
+	if (cout) {
+		(void) FCLOSE_SOCKET(cout);	
+		cout = NULL;
+	}
+	connected = 0;
+	data = INVALID_SOCKET;
+	if (!proxy) {
+		macnum = 0;
+	}
+	auth_type = NULL;
+	dlevel = PROT_C;
+}
+
+static int confirm(cmd, file)
+	char *cmd, *file;
+{
+	char mline[FTP_BUFSIZ];
+
+	if (!interactive)
+		return (1);
+	printf("%s %s? ", cmd, file);
+	(void) fflush(stdout);
+	if (fgets(mline, sizeof mline, stdin) == NULL)
+		return (0);
+	return (*mline != 'n' && *mline != 'N');
+}
+
+void fatal(msg)
+	char *msg;
+{
+
+	fprintf(stderr, "ftp: %s\n", msg);
+	exit(1);
+}
+
+/*
+ * Glob a local file name specification with
+ * the expectation of a single return value.
+ * Can't control multiple values being expanded
+ * from the expression, we return only the first.
+ */
+static int globulize(cpp)
+	char **cpp;
+{
+	char **globbed;
+	char **globbed1;
+
+	if (!doglob)
+		return (1);
+	globbed = ftpglob(*cpp);
+	if (globerr != NULL) {
+		printf("%s: %s\n", *cpp, globerr);
+		if (globbed) {
+			blkfree(globbed);
+			free((char *)globbed);
+		}
+		return (0);
+	}
+	if (globbed) {
+		globbed1 = globbed;
+		*cpp = *globbed1++;
+		/* don't waste too much memory */
+		if (*globbed) {
+			blkfree(globbed1);
+			free((char *)globbed);
+		}
+	}
+	return (1);
+}
+
+void account(argc,argv)
+	int argc;
+	char **argv;
+{
+	char macct[50], *ap;
+
+	if (argc > 1) {
+		++argv;
+		--argc;
+		(void) strncpy(macct,*argv,49);
+		macct[49] = '\0';
+		while (argc > 1) {
+			--argc;
+			++argv;
+			(void) strncat(macct,*argv, 49-strlen(macct));
+		}
+		ap = macct;
+	}
+	else {
+		ap = mygetpass("Account:");
+	}
+	(void) command("ACCT %s", ap);
+}
+
+jmp_buf abortprox;
+
+static sigtype
+proxabort(int sig)
+{
+	extern int proxy;
+
+	if (!proxy) {
+		pswitch(1);
+	}
+	if (connected) {
+		proxflag = 1;
+	}
+	else {
+		proxflag = 0;
+	}
+	pswitch(0);
+	longjmp(abortprox,1);
+}
+
+void doproxy(argc,argv)
+	int argc;
+	char *argv[];
+{
+	register struct cmd *c;
+	struct cmd *getcmd();
+	sig_t oldintr;
+
+	if (argc < 2 && !another(&argc, &argv, "command")) {
+		printf("usage: %s command\n", argv[0]);
+		code = -1;
+		return;
+	}
+	c = getcmd(argv[1]);
+	if (c == (struct cmd *) -1) {
+		printf("?Ambiguous command\n");
+		(void) fflush(stdout);
+		code = -1;
+		return;
+	}
+	if (c == 0) {
+		printf("?Invalid command\n");
+		(void) fflush(stdout);
+		code = -1;
+		return;
+	}
+	if (!c->c_proxy) {
+		printf("?Invalid proxy command\n");
+		(void) fflush(stdout);
+		code = -1;
+		return;
+	}
+	if (setjmp(abortprox)) {
+		code = -1;
+		return;
+	}
+	oldintr = signal(SIGINT, proxabort);
+	pswitch(1);
+	if (c->c_conn && !connected) {
+		printf("Not connected\n");
+		(void) fflush(stdout);
+		pswitch(0);
+		(void) signal(SIGINT, oldintr);
+		code = -1;
+		return;
+	}
+	(*c->c_handler)(argc-1, argv+1);
+	if (connected) {
+		proxflag = 1;
+	}
+	else {
+		proxflag = 0;
+	}
+	pswitch(0);
+	(void) signal(SIGINT, oldintr);
+}
+
+void setcase()
+{
+	mcase = !mcase;
+	printf("Case mapping %s.\n", onoff(mcase));
+	code = mcase;
+}
+
+void setcr()
+{
+	crflag = !crflag;
+	printf("Carriage Return stripping %s.\n", onoff(crflag));
+	code = crflag;
+}
+
+void setntrans(argc,argv)
+	int argc;
+	char *argv[];
+{
+	if (argc == 1) {
+		ntflag = 0;
+		printf("Ntrans off.\n");
+		code = ntflag;
+		return;
+	}
+	ntflag++;
+	code = ntflag;
+	(void) strncpy(ntin, argv[1], 16);
+	ntin[16] = '\0';
+	if (argc == 2) {
+		ntout[0] = '\0';
+		return;
+	}
+	(void) strncpy(ntout, argv[2], 16);
+	ntout[16] = '\0';
+}
+
+static char *
+dotrans(name)
+	char *name;
+{
+	static char new[MAXPATHLEN];
+	char *cp1, *cp2 = new;
+	register int i, ostop, found;
+
+	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++);
+	for (cp1 = name; *cp1; cp1++) {
+		found = 0;
+		for (i = 0; *(ntin + i) && i < 16; i++) {
+			if (*cp1 == *(ntin + i)) {
+				found++;
+				if (i < ostop) {
+					*cp2++ = *(ntout + i);
+				}
+				break;
+			}
+		}
+		if (!found) {
+			*cp2++ = *cp1;
+		}
+	}
+	*cp2 = '\0';
+	return(new);
+}
+
+void setnmap(argc, argv)
+	int argc;
+	char *argv[];
+{
+	char *cp;
+
+	if (argc == 1) {
+		mapflag = 0;
+		printf("Nmap off.\n");
+		code = mapflag;
+		return;
+	}
+	if (argc < 3 && !another(&argc, &argv, "mapout")) {
+		printf("Usage: %s [mapin mapout]\n",argv[0]);
+		code = -1;
+		return;
+	}
+	mapflag = 1;
+	code = 1;
+	cp = strchr(altarg, ' ');
+	if (proxy) {
+		while(*++cp == ' ');
+		altarg = cp;
+		cp = strchr(altarg, ' ');
+	}
+	*cp = '\0';
+	(void) strncpy(mapin, altarg, MAXPATHLEN - 1);
+	while (*++cp == ' ');
+	(void) strncpy(mapout, cp, MAXPATHLEN - 1);
+}
+
+static char *
+domap(name)
+	char *name;
+{
+	static char new[MAXPATHLEN];
+	register char *cp1 = name, *cp2 = mapin;
+	char *tp[9], *te[9];
+	int i, toks[9], toknum = 0, match = 1;
+
+	for (i=0; i < 9; ++i) {
+		toks[i] = 0;
+	}
+	while (match && *cp1 && *cp2) {
+		switch (*cp2) {
+			case '\\':
+				if (*++cp2 != *cp1) {
+					match = 0;
+				}
+				break;
+			case '$':
+				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
+					if (*cp1 != *(++cp2+1)) {
+						toks[toknum = *cp2 - '1']++;
+						tp[toknum] = cp1;
+						while (*++cp1 && *(cp2+1)
+							!= *cp1);
+						te[toknum] = cp1;
+					}
+					cp2++;
+					break;
+				}
+				/* FALLTHROUGH */
+			default:
+				if (*cp2 != *cp1) {
+					match = 0;
+				}
+				break;
+		}
+		if (match && *cp1) {
+			cp1++;
+		}
+		if (match && *cp2) {
+			cp2++;
+		}
+	}
+	if (!match && *cp1) /* last token mismatch */
+	{
+		toks[toknum] = 0;
+	}
+	cp1 = new;
+	*cp1 = '\0';
+	cp2 = mapout;
+	while (*cp2) {
+		match = 0;
+		switch (*cp2) {
+			case '\\':
+				if (*(cp2 + 1)) {
+					*cp1++ = *++cp2;
+				}
+				break;
+			case '[':
+LOOP:
+				if (*++cp2 == '$' && isdigit((int) *(cp2+1))) { 
+					if (*++cp2 == '0') {
+						char *cp3 = name;
+
+						while (*cp3) {
+							*cp1++ = *cp3++;
+						}
+						match = 1;
+					}
+					else if (toks[toknum = *cp2 - '1']) {
+						char *cp3 = tp[toknum];
+
+						while (cp3 != te[toknum]) {
+							*cp1++ = *cp3++;
+						}
+						match = 1;
+					}
+				}
+				else {
+					while (*cp2 && *cp2 != ',' && 
+					    *cp2 != ']') {
+						if (*cp2 == '\\') {
+							cp2++;
+						}
+						else if (*cp2 == '$' &&
+   						        isdigit((int) *(cp2+1))) {
+							if (*++cp2 == '0') {
+							   char *cp3 = name;
+
+							   while (*cp3) {
+								*cp1++ = *cp3++;
+							   }
+							}
+							else if (toks[toknum =
+							    *cp2 - '1']) {
+							   char *cp3=tp[toknum];
+
+							   while (cp3 !=
+								  te[toknum]) {
+								*cp1++ = *cp3++;
+							   }
+							}
+						}
+						else if (*cp2) {
+							*cp1++ = *cp2++;
+						}
+					}
+					if (!*cp2) {
+						printf("nmap: unbalanced brackets\n");
+						return(name);
+					}
+					match = 1;
+					cp2--;
+				}
+				if (match) {
+					while (*++cp2 && *cp2 != ']') {
+					      if (*cp2 == '\\' && *(cp2 + 1)) {
+							cp2++;
+					      }
+					}
+					if (!*cp2) {
+						printf("nmap: unbalanced brackets\n");
+						return(name);
+					}
+					break;
+				}
+				switch (*++cp2) {
+					case ',':
+						goto LOOP;
+					case ']':
+						break;
+					default:
+						cp2--;
+						goto LOOP;
+				}
+				break;
+			case '$':
+				if (isdigit((int) *(cp2 + 1))) {
+					if (*++cp2 == '0') {
+						char *cp3 = name;
+
+						while (*cp3) {
+							*cp1++ = *cp3++;
+						}
+					}
+					else if (toks[toknum = *cp2 - '1']) {
+						char *cp3 = tp[toknum];
+
+						while (cp3 != te[toknum]) {
+							*cp1++ = *cp3++;
+						}
+					}
+					break;
+				}
+				/* intentional drop through */
+			default:
+				*cp1++ = *cp2;
+				break;
+		}
+		cp2++;
+	}
+	*cp1 = '\0';
+	if (!*new) {
+		return(name);
+	}
+	return(new);
+}
+
+void setsunique()
+{
+	sunique = !sunique;
+	printf("Store unique %s.\n", onoff(sunique));
+	code = sunique;
+}
+
+void setrunique()
+{
+	runique = !runique;
+	printf("Receive unique %s.\n", onoff(runique));
+	code = runique;
+}
+
+/* change directory to perent directory */
+void cdup()
+{
+	if (command("CDUP") == ERROR && code == 500) {
+		if (verbose)
+			printf("CDUP command not recognized, trying XCUP\n");
+		(void) command("XCUP");
+	}
+}
+
+/* restart transfer at specific point */
+void restart(argc, argv)
+	int argc;
+	char *argv[];
+{
+	extern long atol();
+	if (argc != 2)
+		printf("restart: offset not specified\n");
+	else {
+		restart_point = atol(argv[1]);
+		printf("restarting at %ld. %s\n", (long) restart_point,
+		    "execute get, put or append to initiate transfer");
+	}
+}
+
+/* show remote system type */
+void syst()
+{
+	(void) command("SYST");
+}
+
+void macdef(argc, argv)
+	int argc;
+	char *argv[];
+{
+	char *tmp;
+	int c;
+
+	if (macnum == 16) {
+		printf("Limit of 16 macros have already been defined\n");
+		code = -1;
+		return;
+	}
+	if (argc < 2 && !another(&argc, &argv, "macro name")) {
+		printf("Usage: %s macro_name\n",argv[0]);
+		code = -1;
+		return;
+	}
+	if (interactive) {
+		printf("Enter macro line by line, terminating it with a null line\n");
+	}
+	(void) strncpy(macros[macnum].mac_name, argv[1], 8);
+	if (macnum == 0) {
+		macros[macnum].mac_start = macbuf;
+	}
+	else {
+		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
+	}
+	tmp = macros[macnum].mac_start;
+	while (tmp != macbuf+4096) {
+		if ((c = getchar()) == EOF) {
+			printf("macdef:end of file encountered\n");
+			code = -1;
+			return;
+		}
+		if ((*tmp = c) == '\n') {
+			if (tmp == macros[macnum].mac_start) {
+				macros[macnum++].mac_end = tmp;
+				code = 0;
+				return;
+			}
+			if (*(tmp-1) == '\0') {
+				macros[macnum++].mac_end = tmp - 1;
+				code = 0;
+				return;
+			}
+			*tmp = '\0';
+		}
+		tmp++;
+	}
+	while (1) {
+		while ((c = getchar()) != '\n' && c != EOF)
+			/* LOOP */;
+		if (c == EOF || getchar() == '\n') {
+			printf("Macro not defined - 4k buffer exceeded\n");
+			code = -1;
+			return;
+		}
+	}
+}
+
+/*
+ * get size of file on remote machine
+ */
+void sizecmd(argc, argv)
+	int argc;
+	char *argv[];
+{
+
+	if (argc < 2 && !another(&argc, &argv, "filename")) {
+		printf("usage: %s filename\n", argv[0]);
+		code = -1;
+		return;
+	}
+	(void) command("SIZE %s", argv[1]);
+}
+
+/*
+ * get last modification time of file on remote machine
+ */
+void modtime(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int overbose;
+
+	if (argc < 2 && !another(&argc, &argv, "filename")) {
+		printf("usage: %s filename\n", argv[0]);
+		code = -1;
+		return;
+	}
+	overbose = verbose;
+	if (debug == 0)
+		verbose = -1;
+	if (command("MDTM %s", argv[1]) == COMPLETE) {
+		int yy, mo, day, hour, min, sec;
+		sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
+			&day, &hour, &min, &sec);
+		/* might want to print this in local time */
+		printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
+			mo, day, yy, hour, min, sec);
+	} else
+		printf("%s\n", reply_string);
+	verbose = overbose;
+}
+
+/*
+ * show status on remote machine
+ */
+void rmtstatus(argc, argv)
+	int argc;
+	char *argv[];
+{
+	(void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
+}
+
+/*
+ * get file if modtime is more recent than current file
+ */
+void newer(argc, argv)
+	int argc;
+	char *argv[];
+{
+	if (getit(argc, argv, -1, "w"))
+		printf("Local file \"%s\" is newer than remote file \"%s\"\n",
+			argv[1], argv[2]);
+}
+
+#ifndef NO_PASSIVE_MODE
+/*
+ * Start up passive mode interaction
+ */
+
+/*VARARGS*/
+void setpassive()
+{
+
+	passivemode = !passivemode;
+	printf("Passive mode %s.\n", onoff(passivemode));
+	code = passivemode;
+}
+#endif
diff --git a/mechglue/src/appl/gssftp/ftp/cmdtab.c b/mechglue/src/appl/gssftp/ftp/cmdtab.c
new file mode 100644
index 000000000..cfa11e371
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/cmdtab.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmdtab.c	5.10 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <stdio.h>
+#include "ftp_var.h"
+
+/*
+ * User FTP -- Command Tables.
+ */
+
+char	accounthelp[] =	"send account command to remote server";
+char	appendhelp[] =	"append to a file";
+char	asciihelp[] =	"set ascii transfer type";
+char	beephelp[] =	"beep when command completed";
+char	binaryhelp[] =	"set binary transfer type";
+char	casehelp[] =	"toggle mget upper/lower case id mapping";
+char	ccchelp[] =	"set clear protection level for commands";
+char	cdhelp[] =	"change remote working directory";
+char	cduphelp[] = 	"change remote working directory to parent directory";
+char	chmodhelp[] =	"change file permissions of remote file";
+char	clearhelp[] =	"set clear protection level for file transfer";
+char	connecthelp[] =	"connect to remote ftp";
+char	crhelp[] =	"toggle carriage return stripping on ascii gets";
+char	deletehelp[] =	"delete remote file";
+char	debughelp[] =	"toggle/set debugging mode";
+char	dirhelp[] =	"list contents of remote directory";
+char	disconhelp[] =	"terminate ftp session";
+char	domachelp[] = 	"execute macro";
+char	formhelp[] =	"set file transfer format";
+char	globhelp[] =	"toggle metacharacter expansion of local file names";
+char	hashhelp[] =	"toggle printing `#' for each buffer transferred";
+char	helphelp[] =	"print local help information";
+char	idlehelp[] =	"get (set) idle timer on remote side";
+char	lcdhelp[] =	"change local working directory";
+char	levelhelp[] =	"set protection level for file transfer";
+char	clevelhelp[] =	"set protection level for commands";
+char	lshelp[] =	"list contents of remote directory";
+char	macdefhelp[] =  "define a macro";
+char	mdeletehelp[] =	"delete multiple files";
+char	mdirhelp[] =	"list contents of multiple remote directories";
+char	mgethelp[] =	"get multiple files";
+char	mkdirhelp[] =	"make directory on the remote machine";
+char	mlshelp[] =	"list contents of multiple remote directories";
+char	modtimehelp[] = "show last modification time of remote file";
+char	modehelp[] =	"set file transfer mode";
+char	mputhelp[] =	"send multiple files";
+char	newerhelp[] =	"get file if remote file is newer than local file ";
+char	nlisthelp[] =	"nlist contents of remote directory";
+char	nmaphelp[] =	"set templates for default file name mapping";
+char	ntranshelp[] =	"set translation table for default file name mapping";
+char	porthelp[] =	"toggle use of PORT cmd for each data connection";
+#ifndef NOENCRYPTION
+char	privatehelp[] =	"set private protection level for file transfer";
+#endif
+char	prompthelp[] =	"force interactive prompting on multiple commands";
+char	proxyhelp[] =	"issue command on alternate connection";
+char	pwdhelp[] =	"print working directory on remote machine";
+char	quithelp[] =	"terminate ftp session and exit";
+char	quotehelp[] =	"send arbitrary ftp command";
+char	receivehelp[] =	"receive file";
+char	regethelp[] =	"get file restarting at end of local file";
+char	remotehelp[] =	"get help from remote server";
+char	renamehelp[] =	"rename file";
+char	restarthelp[]=	"restart file transfer at bytecount";
+char	rmdirhelp[] =	"remove directory on the remote machine";
+char	rmtstatushelp[]="show status of remote machine";
+char	runiquehelp[] = "toggle store unique for local files";
+char	resethelp[] =	"clear queued command replies";
+char	safehelp[] =	"set safe protection level for file transfer";
+char	sendhelp[] =	"send one file";
+char	sitehelp[] =	"send site specific command to remote server\n\t\tTry \"rhelp site\" or \"site help\" for more information";
+char	shellhelp[] =	"escape to the shell";
+char	sizecmdhelp[] = "show size of remote file";
+char	statushelp[] =	"show current status";
+char	structhelp[] =	"set file transfer structure";
+char	suniquehelp[] = "toggle store unique on remote machine";
+char	systemhelp[] =  "show remote system type";
+char	tenexhelp[] =	"set tenex file transfer type";
+char	tracehelp[] =	"toggle packet tracing";
+char	typehelp[] =	"set file transfer type";
+char	umaskhelp[] =	"get (set) umask on remote side";
+char	userhelp[] =	"send new user information";
+char	verbosehelp[] =	"toggle verbose mode";
+#ifndef NO_PASSIVE_MODE
+char	setpassivehelp[] = "toggle passive transfer mode";
+#endif
+
+struct cmd cmdtab[] = {
+	{ "!",		shellhelp,	0,	0,	0,	shell },
+	{ "$",		domachelp,	1,	0,	0,	domacro },
+	{ "account",	accounthelp,	0,	1,	1,	account},
+	{ "append",	appendhelp,	1,	1,	1,	put },
+	{ "ascii",	asciihelp,	0,	1,	1,	setascii },
+	{ "bell",	beephelp,	0,	0,	0,	setbell },
+	{ "binary",	binaryhelp,	0,	1,	1,	setbinary },
+	{ "bye",	quithelp,	0,	0,	0,	quit },
+	{ "case",	casehelp,	0,	0,	1,	setcase },
+	{ "ccc",	ccchelp,	0,	1,	1,	ccc },
+	{ "cd",		cdhelp,		0,	1,	1,	cd },
+	{ "cdup",	cduphelp,	0,	1,	1,	cdup },
+	{ "chmod",	chmodhelp,	0,	1,	1,	do_chmod },
+	{ "clear",	clearhelp,	0,	1,	1,	setclear },
+	{ "close",	disconhelp,	0,	1,	1,	disconnect },
+	{ "cprotect",	clevelhelp,	0,	1,	1,	setclevel },
+	{ "cr",		crhelp,		0,	0,	0,	setcr },
+	{ "delete",	deletehelp,	0,	1,	1,	delete_file },
+	{ "debug",	debughelp,	0,	0,	0,	setdebug },
+	{ "dir",	dirhelp,	1,	1,	1,	ls },
+	{ "disconnect",	disconhelp,	0,	1,	1,	disconnect },
+	{ "form",	formhelp,	0,	1,	1,	setform },
+	{ "get",	receivehelp,	1,	1,	1,	get },
+	{ "glob",	globhelp,	0,	0,	0,	setglob },
+	{ "hash",	hashhelp,	0,	0,	0,	sethash },
+	{ "help",	helphelp,	0,	0,	1,	help },
+	{ "idle",	idlehelp,	0,	1,	1,	siteidle },
+	{ "image",	binaryhelp,	0,	1,	1,	setbinary },
+	{ "lcd",	lcdhelp,	0,	0,	0,	lcd },
+	{ "ls",		lshelp,		1,	1,	1,	ls },
+	{ "macdef",	macdefhelp,	0,	0,	0,	macdef },
+	{ "mdelete",	mdeletehelp,	1,	1,	1,	mdelete },
+	{ "mdir",	mdirhelp,	1,	1,	1,	mls },
+	{ "mget",	mgethelp,	1,	1,	1,	mget },
+	{ "mkdir",	mkdirhelp,	0,	1,	1,	makedir },
+	{ "mls",	mlshelp,	1,	1,	1,	mls },
+	{ "mode",	modehelp,	0,	1,	1,	set_mode },
+	{ "modtime",	modtimehelp,	0,	1,	1,	modtime },
+	{ "mput",	mputhelp,	1,	1,	1,	mput },
+	{ "newer",	newerhelp,	1,	1,	1,	newer },
+	{ "nmap",	nmaphelp,	0,	0,	1,	setnmap },
+	{ "nlist",	nlisthelp,	1,	1,	1,	ls },
+	{ "ntrans",	ntranshelp,	0,	0,	1,	setntrans },
+	{ "open",	connecthelp,	0,	0,	1,	setpeer },
+#ifndef NO_PASSIVE_MODE
+	{ "passive",	setpassivehelp,	0,	0,	0,	setpassive },
+#endif
+#ifndef NOENCRYPTION
+	{ "private",	privatehelp,	0,	1,	1,	setprivate },
+#endif
+	{ "prompt",	prompthelp,	0,	0,	0,	setprompt },
+	{ "protect",	levelhelp,	0,	1,	1,	setdlevel },
+	{ "proxy",	proxyhelp,	0,	0,	1,	doproxy },
+	{ "sendport",	porthelp,	0,	0,	0,	setport },
+	{ "put",	sendhelp,	1,	1,	1,	put },
+	{ "pwd",	pwdhelp,	0,	1,	1,	pwd },
+	{ "quit",	quithelp,	0,	0,	0,	quit },
+	{ "quote",	quotehelp,	1,	1,	1,	quote },
+	{ "recv",	receivehelp,	1,	1,	1,	get },
+	{ "reget",	regethelp,	1,	1,	1,	reget },
+	{ "rstatus",	rmtstatushelp,	0,	1,	1,	rmtstatus },
+	{ "rhelp",	remotehelp,	0,	1,	1,	rmthelp },
+	{ "rename",	renamehelp,	0,	1,	1,	renamefile },
+	{ "reset",	resethelp,	0,	1,	1,	reset },
+	{ "restart",	restarthelp,	1,	1,	1,	restart },
+	{ "rmdir",	rmdirhelp,	0,	1,	1,	removedir },
+	{ "runique",	runiquehelp,	0,	0,	1,	setrunique },
+	{ "safe",	safehelp,	0,	1,	1,	setsafe },
+	{ "send",	sendhelp,	1,	1,	1,	put },
+	{ "site",	sitehelp,	0,	1,	1,	site },
+	{ "size",	sizecmdhelp,	1,	1,	1,	sizecmd },
+	{ "status",	statushelp,	0,	0,	1,	status },
+	{ "struct",	structhelp,	0,	1,	1,	setstruct },
+	{ "system",	systemhelp,	0,	1,	1,	syst },
+	{ "sunique",	suniquehelp,	0,	0,	1,	setsunique },
+	{ "tenex",	tenexhelp,	0,	1,	1,	settenex },
+	{ "trace",	tracehelp,	0,	0,	0,	settrace },
+	{ "type",	typehelp,	0,	1,	1,	settype },
+	{ "user",	userhelp,	0,	1,	1,	user },
+	{ "umask",	umaskhelp,	0,	1,	1,	do_umask },
+	{ "verbose",	verbosehelp,	0,	0,	0,	setverbose },
+	{ "?",		helphelp,	0,	0,	1,	help },
+	{ 0 },
+};
+
+int	NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1;
+
diff --git a/mechglue/src/appl/gssftp/ftp/domacro.c b/mechglue/src/appl/gssftp/ftp/domacro.c
new file mode 100644
index 000000000..50684a72b
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/domacro.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)domacro.c	1.8 (Berkeley) 9/28/90";
+#endif /* not lint */
+
+#include <stdio.h>
+
+#include "ftp_var.h"
+
+#include <signal.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+
+void domacro(argc, argv)
+	int argc;
+	char *argv[];
+{
+	register int i, j;
+	register char *cp1, *cp2;
+	int count = 2, loopflg = 0;
+	char line2[200];
+	extern char **glob();
+	struct cmd *getcmd(), *c;
+
+	if (argc < 2 && !another(&argc, &argv, "macro name")) {
+		printf("Usage: %s macro_name.\n", argv[0]);
+		code = -1;
+		return;
+	}
+	for (i = 0; i < macnum; ++i) {
+		if (!strncmp(argv[1], macros[i].mac_name, 9)) {
+			break;
+		}
+	}
+	if (i == macnum) {
+		printf("'%s' macro not found.\n", argv[1]);
+		code = -1;
+		return;
+	}
+	(void) strncpy(line2, line, sizeof(line2) - 1);
+	line2[sizeof(line2) - 1] = '\0';
+TOP:
+	cp1 = macros[i].mac_start;
+	while (cp1 != macros[i].mac_end) {
+		while (isspace((int) *cp1)) {
+			cp1++;
+		}
+		cp2 = line;
+		while (*cp1 != '\0') {
+		      switch(*cp1) {
+		   	    case '\\':
+				 *cp2++ = *++cp1;
+				 break;
+			    case '$':
+				 if (isdigit((int) *(cp1+1))) {
+				    j = 0;
+				    while (isdigit((int) (*++cp1))) {
+					  j = 10*j +  *cp1 - '0';
+				    }
+				    cp1--;
+				    if (argc - 2 >= j) {
+                                        if(cp2 + strlen(argv[j+1]) - line < sizeof(line))
+					(void) strncpy(cp2, argv[j+1],
+						       sizeof(line) - 1 -
+						       (cp2 - line));
+					line[sizeof(line) - 1] = '\0';
+					cp2 += strlen(argv[j+1]);
+				    }
+				    break;
+				 }
+				 if (*(cp1+1) == 'i') {
+					loopflg = 1;
+					cp1++;
+					if (count < argc) {
+                                           if(cp2 + strlen(argv[count]) - line < sizeof(line))
+					   (void) strncpy(cp2, argv[count],
+							  sizeof(line) - 1 -
+							  (cp2 - line));
+					   line[sizeof(line) - 1] = '\0';
+					   cp2 += strlen(argv[count]);
+					}
+					break;
+				}
+				/* intentional drop through */
+			    default:
+				*cp2++ = *cp1;
+				break;
+		      }
+		      if (*cp1 != '\0') {
+			 cp1++;
+		      }
+		}
+		*cp2 = '\0';
+		makeargv();
+		c = getcmd(margv[0]);
+		if (c == (struct cmd *)-1) {
+			printf("?Ambiguous command\n");
+			code = -1;
+		}
+		else if (c == 0) {
+			printf("?Invalid command\n");
+			code = -1;
+		}
+		else if (c->c_conn && !connected) {
+			printf("Not connected.\n");
+			code = -1;
+		}
+		else {
+			if (verbose) {
+				printf("%s\n",line);
+			}
+			(*c->c_handler)(margc, margv);
+			if (bell && c->c_bell) {
+				(void) putchar('\007');
+			}
+			(void) strncpy(line, line2, sizeof(line) - 1);
+			line[sizeof(line) - 1] = '\0';
+			makeargv();
+			argc = margc;
+			argv = margv;
+		}
+		if (cp1 != macros[i].mac_end) {
+			cp1++;
+		}
+	}
+	if (loopflg && ++count < argc) {
+		goto TOP;
+	}
+}
diff --git a/mechglue/src/appl/gssftp/ftp/ftp.M b/mechglue/src/appl/gssftp/ftp/ftp.M
new file mode 100644
index 000000000..9c890cfb1
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/ftp.M
@@ -0,0 +1,1131 @@
+.\" Copyright (c) 1985, 1989, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)ftp.1	6.18 (Berkeley) 7/30/91
+.\" "
+.TH FTP 1
+.SH NAME
+ftp \- ARPANET file transfer program
+.SH SYNOPSIS
+.B ftp
+[\fB\-v\fP] [\fB\-d\fP] [\fB\-i\fP] [\fB\-n\fP] [\fB\-g\fP] [\fB\-k\fP
+\fIrealm\fP] [\fB\-f\fP] [\fB\-x\fP] [\fB\-u\fP] [\fB\-t\fP] [\fIhost\fP]
+.SH DESCRIPTION
+.B FTP
+is the user interface to the
+.SM ARPANET
+standard File Transfer Protocol.  The program allows a user to transfer
+files to and from a remote network site.
+.SH OPTIONS
+Options may be specified at the command line, or to the command
+interpreter.
+.TP
+.B \-v
+Verbose option forces
+.B ftp
+to show all responses from the remote server, as well as report on data
+transfer statistics.
+.TP
+.B \-n
+Restrains
+.B ftp
+from attempting ``auto-login'' upon initial connection.  If auto-login
+is enabled,
+.B ftp
+will check the
+.I .netrc
+(see below) file in the user's home directory for an entry describing an
+account on the remote machine.  If no entry exists,
+.B ftp
+will prompt for the remote machine login name (default is the user
+identity on the local machine), and, if necessary, prompt for a password
+and an account with which to login.
+.TP
+.B \-u
+Restrains
+.B ftp
+from attempting ``auto-authentication'' upon initial connection.  If
+auto-authentication is enabled,
+.B ftp
+attempts to authenticate to the
+.SM FTP
+server by sending the
+.SM AUTH
+command, using whichever authentication types are locally supported.
+Once an authentication type is accepted, an authentication protocol
+will proceed by issuing
+.SM ADAT
+commands.  This option also disables auto-login.
+.TP
+.B \-i
+Turns off interactive prompting during multiple file transfers.
+.TP
+.B \-d
+Enables debugging.
+.TP
+.B \-g
+Disables file name globbing.
+.TP
+\fB\-k\fP \fIrealm\fP
+When using Kerberos v4 authentication, gets tickets in
+.IR realm .
+.TP
+.B \-f
+Causes credentials to be forwarded to the remote host.
+.TP
+.B \-x
+Causes the client to attempt to negotiate encryption (data and command
+protection levels ``private'') immediately after successfully
+authenticating.
+.TP
+.B \-t
+Enables packet tracing.
+.SH COMMANDS
+The client host with which
+.B ftp
+is to communicate may be specified on the command line.  If this is
+done,
+.B ftp
+will immediately attempt to establish a connection to an
+.SM FTP
+server on that host; otherwise,
+.B ftp
+will enter its command interpreter and await instructions from the user.
+When
+.B ftp
+is awaiting commands from the user the prompt
+``ftp>''
+is provided to the user.  The following commands are recognized by
+.BR ftp :
+.TP
+\fB\&!\fP [\fIcommand\fP] [\fIargs\fP]]
+Invoke an interactive shell on the local machine.  If there are
+arguments, the first is taken to be a command to execute directly, with
+the rest of the arguments as its arguments.
+.TP
+\fB\&$\fP \fImacro-name\fP [\fIargs\fP]
+Execute the macro
+.I macro-name
+that was defined with the
+.B macdef
+command.  Arguments are passed to the macro unglobbed.
+.TP
+\fBaccount\fP [\fIpasswd\fP]
+Supply a supplemental password required by a remote system for access to
+resources once a login has been successfully completed.  If no argument
+is included, the user will be prompted for an account password in a
+non-echoing input mode.
+.TP
+\fBappend\fP \fIlocal-file\fP [\fIremote-file\fP]
+Append a local file to a file on the remote machine.  If
+.I remote-file
+is left unspecified, the local file name is used in naming the remote
+file after being altered by any
+.B ntrans
+or
+.B nmap
+setting.  File transfer uses the current settings for
+.BR type ,
+.BR format ,
+.BR mode ,
+and
+.BR structure .
+.TP
+.B ascii
+Set the file transfer
+.B type
+to network
+.SM ASCII .
+This is the default type.
+.TP
+.B bell
+Arrange that a bell be sounded after each file transfer command is
+completed.
+.TP
+.B binary
+Set the file transfer
+.B type
+to support binary file transfer.
+.TP
+.B bye
+Terminate the
+.SM FTP
+session with the remote server and exit
+.BR ftp .
+An end of file will also terminate the session and exit.
+.TP
+.B case
+Toggle remote computer file name case mapping during
+.B mget
+commands.  When
+.B case
+is on (default is off), remote computer file names with all letters in
+upper case are written in the local directory with the letters mapped to
+lower case.
+.TP
+.B ccc
+Turn off integrity protection on the command channel.  This command
+must be sent integrity protected, and must be proceeded by a successful
+.SM ADAT
+command.  Since turning off integrity protection potentially
+allows an attacker to insert commands onto the command channel, some
+.SM FTP
+servers may refuse to honor this command.
+.TP
+\fBcd\fP \fIremote-directory\fP
+Change the working directory on the remote machine to
+.IR remote-directory .
+.TP
+.B cdup
+Change the remote machine working directory to the parent of the current
+remote machine working directory.
+.TP
+\fBchmod\fP \fImode\fP \fIfile-name\fP
+Change the permission modes of the file
+.I file-name
+on the remote system to
+.IR mode .
+.TP
+.B clear
+Set the protection level on data transfers to ``clear''.  If no
+.SM ADAT
+command succeeded, then this is the default protection level.
+.TP
+.B close
+Terminate the
+.SM FTP
+session with the remote server, and return to the command interpreter.
+Any defined macros are erased.
+.TP
+\fBcprotect\fP [\fIprotection-level\fP]
+Set the protection level on commands to
+.IR protection-level .
+The valid protection levels are ``clear'' for unprotected commands,
+``safe'' for commands integrity protected by
+cryptographic checksum, and ``private'' for commands
+confidentiality and integrity protected by encryption.  If an
+.SM ADAT
+command succeeded, then the default command protection level is
+``safe'', otherwise the only possible level is ``clear''.  If no
+level is specified, the current level is printed.
+.B cprotect clear
+is equivalent to the
+.B ccc
+command.
+.TP
+.B cr
+Toggle carriage return stripping during ascii type file retrieval.
+Records are denoted by a carriage return/linefeed sequence during ascii
+type file transfer.  When
+.B cr
+is on (the default), carriage returns are stripped from this sequence to
+conform with the
+.SM UNIX
+single linefeed record delimiter.  Records on non-UNIX remote systems
+may contain single linefeeds; when an ascii type transfer is made, these
+linefeeds may be distinguished from a record delimiter only when
+.B cr
+is off.
+.TP
+\fBdelete\fP \fIremote-file\fP
+Delete the file
+.I remote-file
+on the remote machine.
+.TP
+\fBdebug\fP [\fIdebug-value\fP]
+Toggle debugging mode.  If an optional
+.I debug-value
+is specified it is used to set the debugging level.  When debugging is
+on,
+.B ftp
+prints each command sent to the remote machine, preceded by the string
+`\-\->'
+.TP
+\fBdir\fP [\fIremote-directory\fP] [\fIlocal-file\fP]
+Print a listing of the directory contents in the directory,
+.IR remote-directory ,
+and, optionally, placing the output in
+.IR local-file .
+If interactive prompting is on,
+.B ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.B dir
+output.  If no directory is specified, the current working directory on
+the remote machine is used.  If no local file is specified, or
+.I local-file
+is
+`\fB\-\fP',
+output comes to the terminal.
+.TP
+.B disconnect
+A synonym for
+.IR close .
+.TP
+\fBform\fP \fIformat\fP
+Set the file transfer
+.B form
+to
+.IR format .
+The default format is ``file''.
+.TP
+\fBget\fP \fIremote-file\fP [\fIlocal-file\fP]
+Retrieve the file
+.I remote-file
+and store it on the local machine.  If the local file name is not
+specified, it is given the same name it has on the remote machine,
+subject to alteration by the current
+.BR case ,
+.BR ntrans ,
+and
+.B nmap
+settings.  The current settings for
+.BR type ,
+.BR form ,
+.BR mode ,
+and
+.B structure
+are used while transferring the file.
+.TP
+.B glob
+Toggle filename expansion for
+.BR mdelete ,
+.BR mget ,
+and
+.BR mput .
+If globbing is turned off with
+.BR glob ,
+the file name arguments are taken literally and not expanded.  Globbing
+for
+.B mput
+is done as in
+.IR csh (1).
+For
+.B mdelete
+and
+.BR mget ,
+each remote file name is expanded separately on the remote machine and
+the lists are not merged.  Expansion of a directory name is likely to be
+different from expansion of the name of an ordinary file: the exact
+result depends on the foreign operating system and ftp server, and can
+be previewed by doing
+`mls remote-files \-'
+Note:
+.B mget
+and
+.B mput
+are not meant to transfer entire directory subtrees of files.  That can
+be done by transferring a
+.IR tar (1)
+archive of the subtree (in binary mode).
+.TP
+.B hash
+Toggle hash-sign (``#'') printing for each data block transferred.  The
+size of a data block is 1024 bytes.
+.TP
+\fBhelp\fP [\fIcommand\fP]
+Print an informative message about the meaning of
+.IR command .
+If no argument is given,
+.B ftp
+prints a list of the known commands.
+.TP
+\fBidle\fP [\fIseconds\fP]
+Set the inactivity timer on the remote server to
+.I seconds
+seconds.  If
+.I seconds
+is omitted, the current inactivity timer is printed.
+.TP
+\fBlcd\fP [\fIdirectory\fP]
+Change the working directory on the local machine.  If no
+.I directory
+is specified, the user's home directory is used.
+.TP
+\fBls\fP [\fIremote-directory\fP] [\fIlocal-file\fP]
+Print a listing of the contents of a directory on the remote machine.
+The listing includes any system-dependent information that the server
+chooses to include; for example, most
+.SM UNIX
+systems will produce output from the command `ls \-l'.  (See also
+.BR nlist .)
+If
+.I remote-directory
+is left unspecified, the current working directory is used.  If
+interactive prompting is on,
+.B ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.B ls
+output.  If no local file is specified, or if
+.I local-file
+is
+`\fB\-\fP',
+the output is sent to the terminal.
+.TP
+\fBmacdef\fP\fImacro-name\fP
+Define a macro.  Subsequent lines are stored as the macro
+.IR macro-name ;
+a null line (consecutive newline characters in a file or carriage
+returns from the terminal) terminates macro input mode.  There is a
+limit of 16 macros and 4096 total characters in all defined macros.
+Macros remain defined until a
+.B close
+command is executed.  The macro processor interprets `$' and `\e' as
+special characters.  A `$' followed by a number (or numbers) is replaced
+by the corresponding argument on the macro invocation command line.  A
+`$' followed by an `i' signals that macro processor that the executing
+macro is to be looped.  On the first pass `$i' is replaced by the first
+argument on the macro invocation command line, on the second pass it is
+replaced by the second argument, and so on.  A `\e' followed by any
+character is replaced by that character.  Use the `\e' to prevent
+special treatment of the `$'.
+.TP
+\fBmdelete\fP [\fIremote-files\fP]
+Delete
+.I remote-files
+on the remote machine.
+.TP
+\fBmdir\fP \fIremote-files\fP \fIlocal-file\fP
+Like
+.BR dir ,
+except multiple remote files may be specified.  If interactive prompting
+is on,
+.B ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.B mdir
+output.
+.TP
+\fBmget\fP \fIremote-files\fP
+Expand the
+.I remote-files
+on the remote machine and do a
+.B get
+for each file name thus produced.  See
+.B glob
+for details on the filename expansion.  Resulting file names will then
+be processed according to
+.BR case ,
+.BR ntrans ,
+and
+.B nmap
+settings.  Files are transferred into the local working directory, which
+can be changed with `lcd directory'; new local directories can be
+created with
+`\&! mkdir directory'.
+.TP
+\fBmkdir\fP \fIdirectory-name\fP
+Make a directory on the remote machine.
+.TP
+\fBmls\fP \fIremote-files\fP \fIlocal-file\fP
+Like
+.BR nlist ,
+except multiple remote files may be specified, and the
+.I local-file
+must be specified.  If interactive prompting is on,
+.B ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.B mls
+output.
+.TP
+\fBmode\fP [\fImode-name\fP]
+Set the file transfer
+.B mode
+to
+.IR mode-name .
+The default mode is ``stream'' mode.
+.TP
+\fBmodtime\fP \fIfile-name\fP
+Show the last modification time of the file on the remote machine.
+.TP
+\fBmput\fP \fIlocal-files\fP
+Expand wild cards in the list of local files given as arguments and do a
+.B put
+for each file in the resulting list.  See
+.B glob
+for details of filename expansion.  Resulting file names will then be
+processed according to
+.B ntrans
+and
+.B nmap
+settings.
+.TP
+\fBnewer\fP \fIfile-name\fP
+Get the file only if the modification time of the remote file is more
+recent that the file on the current system.  If the file does not exist
+on the current system, the remote file is considered
+.BR newer .
+Otherwise, this command is identical to
+.BR get .
+.TP
+\fBnlist\fP [\fIremote-directory\fP] [\fIlocal-file\fP]
+Print a list of the files in a directory on the remote machine.  If
+.I remote-directory
+is left unspecified, the current working directory is used.  If
+interactive prompting is on,
+.B ftp
+will prompt the user to verify that the last argument is indeed the
+target local file for receiving
+.B nlist
+output.  If no local file is specified, or if
+.I local-file
+is `\fB\-\fP', the output is sent to the terminal.
+.TP
+\fBnmap\fP [\fIinpattern\fP \fIoutpattern\fP]
+Set or unset the filename mapping mechanism.  If no arguments are
+specified, the filename mapping mechanism is unset.  If arguments are
+specified, remote filenames are mapped during
+.B mput
+commands and
+.B put
+commands issued without a specified remote target filename.
+If arguments are specified, local filenames are mapped during
+.B mget
+commands and
+.B get
+commands issued without a specified local target filename.  This command
+is useful when connecting to non\-UNIX remote computer with different
+file naming conventions or practices.  The mapping follows the pattern
+set by
+.I inpattern
+and
+.IR outpattern .
+[\fIInpattern\fP] is a template for incoming filenames (which may have
+already been processed according to the
+.B ntrans
+and
+.B case
+settings).  Variable templating is accomplished by including the
+sequences `$1', `$2', ..., `$9' in
+.IR inpattern .
+Use `\e' to prevent this special treatment of the `$' character.  All
+other characters are treated literally, and are used to determine the
+.B nmap
+[\fIinpattern\fP] variable values.  For example, given
+.I inpattern
+$1.$2 and the remote file name "mydata.data", $1 would have the value
+"mydata", and $2 would have the value "data".  The
+.I outpattern
+determines the resulting mapped filename.  The sequences `$1', `$2',
+...., `$9' are replaced by any value resulting from the
+.I inpattern
+template.  The sequence `$0' is replace by the original filename.
+Additionally, the sequence `[\fIseq1\fP, \fIseq2\fP]' is replaced by
+[\fIseq1\fP] if
+.I seq1
+is not a null string; otherwise it is replaced by
+.IR seq2 .
+For example, the command
+.sp
+.nf
+	nmap $1.$2.$3 [$1,$2].[$2,file]
+.fi
+.sp
+would yield the output filename "myfile.data" for input filenames
+"myfile.data" and "myfile.data.old", "myfile.file" for the input
+filename "myfile", and "myfile.myfile" for the input filename ".myfile".
+Spaces may be included in
+.IR outpattern ,
+as in the example: `nmap $1 sed "s/ *$//" > $1'.  Use the `\e' character
+to prevent special treatment of the `$','[',']', and `,' characters.
+.TP
+\fBntrans\fP [\fIinchars\fP [\fIoutchars\fP]]
+Set or unset the filename character translation mechanism.  If no
+arguments are specified, the filename character translation mechanism is
+unset.  If arguments are specified, characters in remote filenames are
+translated during
+.B mput
+commands and
+.B put
+commands issued without a specified remote target filename.  If
+arguments are specified, characters in local filenames are translated
+during
+.B mget
+commands and
+.B get
+commands issued without a specified local target filename.  This command
+is useful when connecting to a non-UNIX remote computer with different
+file naming conventions or practices.  Characters in a filename matching
+a character in
+.I inchars
+are replaced with the corresponding character in
+.IR outchars .
+If the character's position in
+.I inchars
+is longer than the length of
+.IR outchars ,
+the character is deleted from the file name.
+.TP
+\fBopen\fP \fIhost\fP [\fIport\fP] [\fB\-forward\fP]
+Establish a connection to the specified
+.I host
+.SM FTP
+server.  An optional port number may be supplied, in which case,
+.B ftp
+will attempt to contact an
+.SM FTP
+server at that port.  If the
+.B auto-authenticate
+option is on (default),
+.B ftp
+will attempt to authenticate to the
+.SM FTP
+server by sending the
+.SM AUTH
+command, using whichever authentication types which are locally
+supported.  Once an authentication type is accepted, an authentication
+protocol will proceed by issuing
+.SM ADAT
+commands.  If the
+.B auto-login
+option is on (default),
+.B ftp
+will also attempt to automatically log the user in to the
+.SM FTP
+server (see below).  If the
+.B \-forward
+option is specified,
+.B ftp
+will forward a copy of the user's Kerberos tickets to the remote host.
+.TP
+.B passive
+Toggle passive data transfer mode.  In passive mode, the client initiates
+the data connection by listening on the data port.  Passive mode may
+be necessary for operation from behind firewalls which do not permit
+incoming connections.
+.TP
+.B private
+Set the protection level on data transfers to ``private''.  Data
+transmissions are confidentiality and integrity protected by encryption.
+If no
+.SM ADAT
+command succeeded, then the only possible level is ``clear''.
+.TP
+.B prompt
+Toggle interactive prompting.  Interactive prompting occurs during
+multiple file transfers to allow the user to selectively retrieve or
+store files.  If prompting is turned off (default is on), any
+.B mget
+or
+.B mput
+will transfer all files, and any
+.B mdelete
+will delete all files.
+.TP
+\fBprotect\fP [\fIprotection-level\fP]
+Set the protection level on data transfers to
+.IR protection-level .
+The valid protection levels are ``clear'' for unprotected data
+transmissions, ``safe'' for data transmissions integrity protected by
+cryptographic checksum, and ``private'' for data transmissions
+confidentiality and integrity protected by encryption.  If no
+.SM ADAT
+command succeeded, then the only possible level is ``clear''.  If no
+level is specified, the current level is printed.  The default
+protection level is ``clear''.
+.TP
+\fBproxy\fP \fIftp-command\fP
+Execute an ftp command on a secondary control connection.  This command
+allows simultaneous connection to two remote ftp servers for
+transferring files between the two servers.  The first
+.B proxy
+command should be an
+.B open  ,
+to establish the secondary control connection.  Enter the command 
+"proxy ?" to see other ftp commands executable on the secondary connection.
+The following commands behave differently when prefaced by
+.BR proxy :
+.B open
+will not define new macros during the auto-login process,
+.B close
+will not erase existing macro definitions,
+.B get
+and
+.B mget
+transfer files from the host on the primary control connection to the
+host on the secondary control connection, and
+.BR put ,
+.BR mput ,
+and
+.B append
+transfer files from the host on the secondary control connection to the
+host on the primary control connection.  Third party file transfers
+depend upon support of the ftp protocol
+.SM PASV
+command by the server on the secondary control connection.
+.TP
+\fBput\fP \fIlocal-file\fP [\fIremote-file\fP]
+Store a local file on the remote machine.  If
+.I remote-file
+is left unspecified, the local file name is used after processing
+according to any
+.B ntrans
+or
+.B nmap
+settings in naming the remote file.  File transfer uses the current
+settings for
+.BR type ,
+.BR format ,
+.BR mode ,
+and
+.BR structure .
+.TP
+.B pwd
+Print the name of the current working directory on the remote machine.
+.TP
+.B quit
+A synonym for
+.BR bye .
+.TP
+\fBquote\fP \fIarg1\fP [\fIarg2\fP] [\fI...\fP]
+The arguments specified are sent, verbatim, to the remote
+.SM FTP
+server.
+.TP
+\fBrecv\fP \fIremote-file\fP [\fIlocal-file\fP]
+A synonym for get.
+.TP
+\fBreget\fP \fIremote-file\fP [\fIlocal-file\fP]
+Reget acts like get, except that if
+.I local-file
+exists and is smaller than
+.IR remote-file ,
+.I local-file
+is presumed to be a partially transferred copy of
+.I remote-file
+and the transfer is continued from the apparent point of failure.  This
+command is useful when transferring very large files over networks that
+are prone to dropping connections.
+.TP
+\fBremotehelp\fP [\fIcommand-name\fP]
+Request help from the remote
+.SM FTP
+server.  If a
+.I command-name
+is specified it is supplied to the server as well.
+.TP
+\fBremotestatus\fP [\fIfile-name\fP]
+With no arguments, show status of remote machine.  If
+.I file-name
+is specified, show status of
+.I file-name
+on remote machine.
+.TP
+\fBrename\fP [\fIfrom\fP] [\fIto\fP]
+Rename the file
+.I from
+on the remote machine, to the file
+.IR to .
+.TP
+.B reset
+Clear reply queue.  This command re-synchronizes command/reply
+sequencing with the remote ftp server.  Resynchronization may be
+necessary following a violation of the ftp protocol by the remote
+server.
+.TP
+\fBrestart\fP \fImarker\fP
+Restart the immediately following
+.B get
+or
+.B put
+at the indicated
+.IR marker .
+On UNIX systems, marker is usually a byte offset into the file.
+.TP
+\fBrmdir\fP \fIdirectory-name\fP
+Delete a directory on the remote machine.
+.TP
+.B runique
+Toggle storing of files on the local system with unique filenames.  If a
+file already exists with a name equal to the target local filename for a
+.B get
+or
+.B mget
+command, a ".1" is appended to the name.  If the resulting name matches
+another existing file, a ".2" is appended to the original name.  If this
+process continues up to ".99", an error message is printed, and the
+transfer does not take place.  The generated unique filename will be
+reported.  Note that
+.B runique
+will not affect local files generated from a shell command (see below).
+The default value is off.
+.TP
+.B safe
+Set the protection level on data transfers to ``safe''.  Data
+transmissions are integrity-protected by cryptographic checksum.  If no
+.SM ADAT
+command succeeded, then the only possible level is ``clear''.
+.TP
+\fBsend\fP \fIlocal-file\fP [\fIremote-file\fP]
+A synonym for put.
+.TP
+.B sendport
+Toggle the use of
+.SM PORT
+commands.  By default,
+.B ftp
+will attempt to use a
+.SM PORT
+command when establishing a connection for each data transfer.  The use
+of
+.SM PORT
+commands can prevent delays when performing multiple file transfers.  If
+the
+.SM PORT
+command fails,
+.B ftp
+will use the default data port.  When the use of
+.SM PORT
+commands is disabled, no attempt will be made to use
+.SM PORT
+commands for each data transfer.  This is useful for certain
+.SM FTP
+implementations which do ignore
+.SM PORT
+commands but, incorrectly, indicate they've been accepted.
+.TP
+\fBsite\fP \fIarg1\fP [\fIarg2\fP] [\fI...\fP]
+The arguments specified are sent, verbatim, to the remote
+.SM FTP
+server as a
+.SM SITE
+command.
+.TP
+\fBsize\fP \fIfile-name\fP
+Return size of
+.I file-name
+on remote machine.
+.TP
+.B status
+Show the current status of
+.BR ftp .
+.TP
+\fBstruct\fP \fIstruct-name\fP
+Set the file transfer
+.I structure
+to
+.IR struct-name .
+By default ``stream'' structure is used.
+.TP
+.B sunique
+Toggle storing of files on remote machine under unique file names.
+Remote ftp server must support ftp protocol
+.SM STOU
+command for successful completion.  The remote server will report unique
+name.  Default value is off.
+.TP
+.B system
+Show the type of operating system running on the remote machine.
+.TP
+.B tenex
+Set the file transfer type to that needed to talk to
+.SM TENEX
+machines.
+.TP
+.B trace
+Toggle packet tracing.
+.TP
+\fBtype\fP [\fItype-name\fP]
+Set the file transfer
+.B type
+to
+.IR type-name .
+If no type is specified, the current type is printed.  The default type
+is network
+.SM ASCII.
+.TP
+\fBumask\fP [\fInewmask\fP]
+Set the default umask on the remote server to
+.IR newmask .
+If
+.I newmask
+is omitted, the current umask is printed.
+.TP
+\fBuser\fP \fIuser-name\fP [\fIpassword\fP] [\fIaccount\fP]
+Identify yourself to the remote
+.SM FTP
+server.  If the
+.I password
+is not specified and the server requires it,
+.B ftp
+will prompt the user for it (after disabling local echo).  If an
+.I account
+field is not specified, and the
+.SM FTP
+server requires it, the user will be prompted for it.  If an
+.I account
+field is specified, an account command will be relayed to the remote
+server after the login sequence is completed if the remote server did
+not require it for logging in.  Unless
+.B ftp
+is invoked with ``auto-login'' disabled, this process is done
+automatically on initial connection to the
+.SM FTP
+server.
+.TP
+.B verbose
+Toggle verbose mode.  In verbose mode, all responses from the
+.SM FTP
+server are displayed to the user.  In addition, if verbose is on, when a
+file transfer completes, statistics regarding the efficiency of the
+transfer are reported.  By default, verbose is on.
+.TP
+\fB \&? [\fIcommand\fP]
+A synonym for help.
+.PP
+Command arguments which have embedded spaces may be quoted with quote
+`"' marks.
+.SH ABORTING A FILE TRANSFER
+To abort a file transfer, use the terminal interrupt key (usually
+Ctrl-C).  Sending transfers will be immediately halted.  Receiving
+transfers will be halted by sending a 
+.SM FTP
+protocol
+.SM ABOR
+command to the remote server, and discarding any further data received.
+The speed at which this is accomplished depends upon the remote server's
+support for
+.SM ABOR
+processing.  If the remote server does not support the
+.SM ABOR
+command, an `ftp>' prompt will not appear until the remote server has
+completed sending the requested file.
+.PP
+The terminal interrupt key sequence will be ignored when
+.B ftp
+has completed any local processing and is awaiting a reply from the
+remote server.  A long delay in this mode may result from the
+.SM ABOR
+processing described above, or from unexpected behavior by the remote
+server, including violations of the ftp protocol.  If the delay results
+from unexpected remote server behavior, the local
+.B ftp
+program must be killed by hand.
+.SH FILE NAMING CONVENTIONS
+Files specified as arguments to
+.B ftp
+commands are processed according to the following rules.
+.TP
+1.
+If the file name `\fB-\fP' is specified,
+.I stdin
+(for reading) or
+.I stdout
+(for writing) is used.
+.TP
+2.
+If the first character of the file name is `\&|', the remainder of the
+argument is interpreted as a shell command.
+.B Ftp
+then forks a shell, using
+.IR popen (3)
+with the argument supplied, and reads from (writes to) stdout (stdin).
+If the shell command includes spaces, the argument must be quoted; e.g.
+``" ls -lt"''.  A particularly useful example of this mechanism is:
+``dir more''.
+.TP
+3.
+Failing the above checks, if ``globbing'' is enabled, local file names
+are expanded according to the rules used in
+.IR csh (1);
+c.f. the
+.B glob
+command.  If the
+.B ftp
+command expects a single local file (.e.g.
+.BR put ),
+only the first filename generated by the ``globbing'' operation is used.
+.TP
+4.
+For
+.B mget
+commands and
+.B get
+commands with unspecified local file names, the local filename is the
+remote filename, which may be altered by a
+.BR case ,
+.BR ntrans ,
+or
+.B nmap
+setting.  The resulting filename may then be altered if
+.B runique
+is on.
+.TP
+5.
+For
+.B mput
+commands and
+.B put
+commands with unspecified remote file names, the remote filename is the
+local filename, which may be altered by a
+.B ntrans
+or
+.B nmap
+setting.  The resulting filename may then be altered by the remote
+server if
+.B sunique
+is on.
+.SH FILE TRANSFER PARAMETERS
+The FTP specification specifies many parameters which may affect a file
+transfer.  The
+.B type
+may be one of ``ascii'', ``image'' (binary), ``ebcdic'', and ``local
+byte size'' (mostly for PDP-10's and PDP-20's).
+.B Ftp
+supports the ascii and image types of file transfer, plus local byte
+size 8 for
+.B tenex
+mode transfers.
+.PP
+.B Ftp
+supports only the default values for the remaining file transfer
+parameters:
+.BR mode ,
+.BR form ,
+and
+.BR struct .
+.SH THE .netrc FILE
+The
+.I .netrc
+file contains login and initialization information used by the
+auto-login process.  It resides in the user's home directory.  The
+following tokens are recognized; they may be separated by spaces, tabs,
+or new-lines:
+.TP
+\fBmachine\fP \fIname\fP
+Identify a remote machine
+.IR name .
+The auto-login process searches the
+.I .netrc
+file for a
+.B machine
+token that matches the remote machine specified on the
+.B ftp
+command line or as an
+.B open
+command argument.  Once a match is made, the subsequent
+.I .netrc
+tokens are processed, stopping when the end of file is reached or
+another
+.B machine
+or a
+.B default
+token is encountered.
+.TP
+.B default
+This is the same as
+.B machine
+.I name
+except that
+.B default
+matches any name.  There can be only one
+.B default
+token, and it must be after all
+.B machine
+tokens.  This is normally used as:
+.sp
+     default login anonymous password user@site
+.sp
+thereby giving the user
+.I automatic
+anonymous ftp login to machines not specified in
+.IR .netrc .
+This can be overridden by using the
+.B \-n
+flag to disable auto-login.
+.TP
+\fBlogin\fP \fIname\fP
+Identify a user on the remote machine.  If this token is present, the
+auto-login process will initiate a login using the specified
+.IR name .
+.TP
+\fBpassword\fP \fIstring\fP
+Supply a password.  If this token is present, the auto-login process
+will supply the specified string if the remote server requires a
+password as part of the login process.  Note that if this token is
+present in the
+.I .netrc
+file for any user other than
+.IR anonymous ,
+.B ftp
+will abort the auto-login process if the
+.I .netrc
+is readable by anyone besides the user.
+.TP
+\fBaccount\fP \fIstring\fP
+Supply an additional account password.  If this token is present, the
+auto-login process will supply the specified string if the remote server
+requires an additional account password, or the auto-login process will
+initiate an
+.SM ACCT
+command if it does not.
+.TP
+\fBmacdef\fP \fIname\fP
+Define a macro.  This token functions like the
+.B ftp
+.B macdef
+command functions.  A macro is defined with the specified name; its
+contents begin with the next
+.I .netrc
+line and continue until a null line (consecutive new-line characters) is
+encountered.  If a macro named
+.B init
+is defined, it is automatically executed as the last step in the
+auto-login process.
+.SH ENVIRONMENT
+.B Ftp
+utilizes the following environment variables.
+.TP
+.SM HOME
+For default location of a
+.I .netrc
+file, if one exists.
+.TP
+.SM SHELL
+For default shell.
+.SH SEE ALSO
+.IR ftpd (8)
+.PP
+Lunt, S. J., FTP Security Extensions, Internet Draft, November 1993.
+.SH HISTORY
+The
+.B ftp
+command appeared in 4.2BSD.
+.SH BUGS
+Correct execution of many commands depends upon proper behavior by the
+remote server.
+.PP
+An error in the treatment of carriage returns in the 4.2BSD ascii-mode
+transfer code has been corrected.  This correction may result in
+incorrect transfers of binary files to and from 4.2BSD servers using the
+ascii type.  Avoid this problem by using the binary image type.
diff --git a/mechglue/src/appl/gssftp/ftp/ftp.c b/mechglue/src/appl/gssftp/ftp/ftp.c
new file mode 100644
index 000000000..6ef4e886e
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/ftp.c
@@ -0,0 +1,2365 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ftp.c	5.38 (Berkeley) 4/22/91";
+#endif /* not lint */
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock2.h>
+#include <sys/timeb.h>
+#include <time.h>
+#include <crtdbg.h>
+#undef ERROR
+#define NOSTBLKSIZE
+
+#define popen _popen
+#define pclose _pclose
+#define sleep(secs) Sleep(secs * 1000)
+int gettimeofday(struct timeval *tv, void *tz);
+
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef _WIN32
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#ifndef KRB5_KRB4_COMPAT
+/* krb.h gets this, and Ultrix doesn't protect vs multiple inclusion */
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+#include <sys/time.h>
+#include <sys/file.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <pwd.h>
+#endif
+
+#include <arpa/ftp.h>
+#include <arpa/telnet.h>
+
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include <port-sockets.h>
+
+#ifndef L_SET
+#define L_SET 0
+#endif
+#ifndef L_INCR
+#define L_INCR 1
+#endif
+
+#ifdef KRB5_KRB4_COMPAT
+#include <krb.h>
+
+KTEXT_ST ticket;
+CREDENTIALS cred;
+Key_schedule schedule;
+MSG_DAT msg_data;
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+#include <gssapi/gssapi.h>
+/* need to include the krb5 file, because we're doing manual fallback
+   from the v2 mech to the v2 mech.  Once there's real negotiation,
+   we can be generic again. */
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+gss_ctx_id_t gcontext;
+#endif /* GSSAPI */
+
+static int kerror;	/* XXX needed for all auth types */
+
+char	*auth_type;	/* Authentication succeeded?  If so, what type? */
+
+unsigned int maxbuf, actualbuf;
+unsigned char *ucbuf;
+ 
+#define DEFINITIONS
+#include "ftp_var.h"
+#include "secure.h"
+
+#ifdef GSSAPI
+void user_gss_error (OM_uint32, OM_uint32, char *);
+#endif
+
+static void proxtrans (char *, char *, char *);
+static int initconn (void);
+static void ptransfer (char *, long, struct timeval *, struct timeval *);
+static void abort_remote (FILE *);
+static void tvsub (struct timeval *, struct timeval *, struct timeval *);
+static char *gunique (char *);
+
+struct	sockaddr_in hisctladdr;
+struct	sockaddr_in hisdataaddr;
+struct	sockaddr_in data_addr;
+SOCKET	data = -1;
+int	abrtflag = 0;
+int	ptflag = 0;
+struct	sockaddr_in myctladdr;
+#ifndef _WIN32
+uid_t	getuid();
+#endif
+sig_t	lostpeer();
+off_t	restart_point = 0;
+jmp_buf ptabort;
+
+#ifndef HAVE_STRERROR
+#define strerror(error) (sys_errlist[error])
+#ifdef NEED_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+#endif
+
+extern int connected;
+
+#define herror()	printf("unknown host\n")
+
+FILE	*cin, *cout;
+FILE	*dataconn (char *);
+
+char *
+hookup(char* host, int port)
+{
+	register struct hostent *hp = 0;
+	int s;
+	socklen_t len;
+#ifdef IP_TOS
+#ifdef IPTOS_LOWDELAY
+	int tos;
+#endif
+#endif
+	static char hostnamebuf[80];
+
+	memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
+	hisctladdr.sin_addr.s_addr = inet_addr(host);
+	if (hisctladdr.sin_addr.s_addr != -1) {
+		hisctladdr.sin_family = AF_INET;
+		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
+	} else {
+		hp = gethostbyname(host);
+		if (hp == NULL) {
+			fprintf(stderr, "ftp: %s: ", host);
+			herror();
+			code = -1;
+			return((char *) 0);
+		}
+		hisctladdr.sin_family = hp->h_addrtype;
+		memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0],
+		       sizeof(hisctladdr.sin_addr));
+		(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
+	}
+	hostname = hostnamebuf;
+	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+	if (s == INVALID_SOCKET) {
+		PERROR_SOCKET("ftp: socket");
+		code = -1;
+		return (0);
+	}
+	hisctladdr.sin_port = port;
+	while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) == SOCKET_ERROR) {
+		if (hp && hp->h_addr_list[1]) {
+			int oerrno = SOCKET_ERRNO;
+#ifndef _WIN32
+			extern char *inet_ntoa();
+#endif
+			fprintf(stderr, "ftp: connect to address %s: ",
+				inet_ntoa(hisctladdr.sin_addr));
+			SOCKET_SET_ERRNO(oerrno);
+			PERROR_SOCKET((char *) 0);
+			hp->h_addr_list++;
+			memcpy(&hisctladdr.sin_addr,
+			       hp->h_addr_list[0], 
+			       sizeof(hisctladdr.sin_addr));
+			fprintf(stdout, "Trying %s...\n",
+				inet_ntoa(hisctladdr.sin_addr));
+			(void) closesocket(s);
+			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
+			if (s == INVALID_SOCKET) {
+				PERROR_SOCKET("ftp: socket");
+				code = -1;
+				return (0);
+			}
+			continue;
+		}
+		PERROR_SOCKET("ftp: connect");
+		code = -1;
+		goto bad;
+	}
+	len = sizeof (myctladdr);
+	if (getsockname(s, (struct sockaddr *)&myctladdr, &len) == SOCKET_ERROR) {
+		PERROR_SOCKET("ftp: getsockname");
+		code = -1;
+		goto bad;
+	}
+#ifdef IP_TOS
+#ifdef IPTOS_LOWDELAY
+	tos = IPTOS_LOWDELAY;
+	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) == SOCKET_ERROR) {
+		PERROR_SOCKET("ftp: setsockopt TOS (ignored)");
+	}
+#endif
+#endif
+	cin = FDOPEN_SOCKET(s, "r");
+	cout = FDOPEN_SOCKET(s, "w");
+	if (cin == NULL || cout == NULL) {
+		fprintf(stderr, "ftp: fdopen failed.\n");
+		if (cin) {
+			(void) FCLOSE_SOCKET(cin);
+			cin = NULL;
+		}
+		if (cout) {
+			(void) FCLOSE_SOCKET(cout);
+			cout = NULL;
+		}
+		code = -1;
+		goto bad;
+	}
+	if (verbose)
+		printf("Connected to %s.\n", hostname);
+	if (getreply(0) > 2) { 	/* read startup message from server */
+		if (cin) {
+			(void) FCLOSE_SOCKET(cin);
+			cin = NULL;
+		}
+		if (cout) {
+			(void) FCLOSE_SOCKET(cout);
+			cout = NULL;
+		}
+		code = -1;
+		goto bad;
+	}
+#ifdef SO_OOBINLINE
+	{
+	int on = 1;
+
+	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
+		== SOCKET_ERROR && debug) {
+			PERROR_SOCKET("ftp: setsockopt");
+		}
+	}
+#endif /* SO_OOBINLINE */
+
+	return (hostname);
+bad:
+	(void) closesocket(s);
+	return ((char *)0);
+}
+
+int login(char *host)
+{
+	char tmp[80];
+	char *l_user, *pass, *l_acct, *getenv(), *getlogin();
+	int n, aflag = 0;
+
+	l_user = pass = l_acct = 0;
+	if (ruserpass(host, &l_user, &pass, &l_acct) < 0) {
+		code = -1;
+		return(0);
+	}
+	while (l_user == NULL) {
+		char *myname;
+
+		myname = getenv("LOGNAME");
+		if (myname == NULL)
+			myname = getenv("USER");
+#ifndef _WIN32
+		if (myname == NULL)
+			myname = getlogin();
+		if (myname == NULL) {
+			struct passwd *pp = getpwuid(getuid());
+
+			if (pp != NULL)
+				myname = pp->pw_name;
+		}
+#else
+		if (myname == NULL) {
+			static char buffer[200];
+			int len = sizeof(buffer);
+			if (GetUserName(buffer, &len))
+				myname = buffer;
+			else
+				myname = "<Unknown>";
+		}
+#endif
+		if (myname)
+			printf("Name (%s:%s): ", host, myname);
+		else
+			printf("Name (%s): ", host);
+		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
+		tmp[strlen(tmp) - 1] = '\0';
+		if (*tmp == '\0')
+			l_user = myname;
+		else
+			l_user = tmp;
+	}
+	n = command("USER %s", l_user);
+	if (n == COMPLETE) {
+	        /* determine if we need to send a dummy password */
+		int oldverbose = verbose;
+
+		verbose = 0;
+		if (command("PWD") != COMPLETE) {
+			verbose = oldverbose;
+			command("PASS dummy");
+		} else {
+			verbose = oldverbose;
+		}
+	}
+	else if (n == CONTINUE) {
+#ifndef NOENCRYPTION
+		int oldclevel;
+#endif
+		if (pass == NULL)
+			pass = mygetpass("Password:");
+#ifndef NOENCRYPTION
+		oldclevel = clevel;
+		clevel = PROT_P;
+#endif
+		n = command("PASS %s", pass);
+#ifndef NOENCRYPTION
+		/* level may have changed */
+		if (clevel == PROT_P) clevel = oldclevel;
+#endif
+	}
+	if (n == CONTINUE) {
+		aflag++;
+		l_acct = mygetpass("Account:");
+		n = command("ACCT %s", l_acct);
+	}
+	if (n != COMPLETE) {
+		fprintf(stderr, "Login failed.\n");
+		return (0);
+	}
+	if (!aflag && l_acct != NULL)
+		(void) command("ACCT %s", l_acct);
+	if (proxy)
+		return(1);
+	for (n = 0; n < macnum; ++n) {
+		if (!strcmp("init", macros[n].mac_name)) {
+			(void) strcpy(line, "$init");
+			makeargv();
+			domacro(margc, margv);
+			break;
+		}
+	}
+	return (1);
+}
+
+static sigtype
+cmdabort(int sig)
+{
+	printf("\n");
+	(void) fflush(stdout);
+	abrtflag++;
+	if (ptflag)
+		longjmp(ptabort,1);
+}
+
+static int secure_command(char* cmd)
+{
+	unsigned char in[FTP_BUFSIZ], out[FTP_BUFSIZ];
+	int length;
+
+	if (auth_type && clevel != PROT_C) {
+#ifdef KRB5_KRB4_COMPAT
+		if (strcmp(auth_type, "KERBEROS_V4") == 0)
+		    if ((length = clevel == PROT_P ?
+			krb_mk_priv((unsigned char *)cmd, (unsigned char *)out,
+				strlen(cmd), schedule,
+				&cred.session, &myctladdr, &hisctladdr)
+		      : krb_mk_safe((unsigned char *)cmd, (unsigned char *)out,
+				strlen(cmd), &cred.session,
+				&myctladdr, &hisctladdr)) == -1) {
+			fprintf(stderr, "krb_mk_%s failed for KERBEROS_V4\n",
+					clevel == PROT_P ? "priv" : "safe");
+			return(0);
+		    }
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+		/* secure_command (based on level) */
+		if (strcmp(auth_type, "GSSAPI") == 0) {
+			gss_buffer_desc in_buf, out_buf;
+			OM_uint32 maj_stat, min_stat;
+			int conf_state;
+/* clevel = PROT_P; */
+			in_buf.value = cmd;
+			in_buf.length = strlen(cmd) + 1;
+			maj_stat = gss_seal(&min_stat, gcontext,
+					    (clevel==PROT_P), /* private */
+					    GSS_C_QOP_DEFAULT,
+					    &in_buf, &conf_state,
+					    &out_buf);
+			if (maj_stat != GSS_S_COMPLETE) {
+				/* generally need to deal */
+				user_gss_error(maj_stat, min_stat,
+					       (clevel==PROT_P)?
+						 "gss_seal ENC didn't complete":
+						 "gss_seal MIC didn't complete");
+			} else if ((clevel == PROT_P) && !conf_state) {
+				fprintf(stderr, 
+					"GSSAPI didn't encrypt message");
+			} else {
+				if (debug)
+				  fprintf(stderr, "sealed (%s) %d bytes\n",
+					  clevel==PROT_P?"ENC":"MIC", 
+					  out_buf.length);
+				length=out_buf.length;
+				memcpy(out, out_buf.value, out_buf.length);
+				gss_release_buffer(&min_stat, &out_buf);
+			}
+		}
+#endif /* GSSAPI */
+		/* Other auth types go here ... */
+		kerror = radix_encode(out, in, &length, 0);
+		if (kerror) {
+			fprintf(stderr,"Couldn't base 64 encode command (%s)\n",
+					radix_error(kerror));
+			return(0);
+		}
+		fprintf(cout, "%s %s", clevel == PROT_P ? "ENC" : "MIC", in);
+		if(debug) 
+		  fprintf(stderr, "secure_command(%s)\nencoding %d bytes %s %s\n",
+			  cmd, length, clevel==PROT_P ? "ENC" : "MIC", in);
+	} else	fputs(cmd, cout);
+	fprintf(cout, "\r\n");
+	(void) fflush(cout);
+	return(1);
+}
+
+int command(char *fmt, ...)
+{
+	char in[FTP_BUFSIZ];
+	va_list ap;
+	int r;
+	sig_t oldintr;
+
+	abrtflag = 0;
+	if (debug) {
+		if (proxflag) printf("%s ", hostname);
+		printf("---> ");
+		va_start(ap, fmt);
+		if (strncmp("PASS ", fmt, 5) == 0)
+			printf("PASS XXXX");
+		else 
+			vfprintf(stdout, fmt, ap);
+		va_end(ap);
+		printf("\n");
+		(void) fflush(stdout);
+	}
+	if (cout == NULL) {
+		perror ("No control connection for command");
+		code = -1;
+		return (0);
+	}
+	oldintr = signal(SIGINT, cmdabort);
+	va_start(ap, fmt);
+	vsprintf(in, fmt, ap);
+	va_end(ap);
+again:	if (secure_command(in) == 0)
+		return(0);
+	cpend = 1;
+	r = getreply(!strcmp(fmt, "QUIT"));
+#ifndef NOENCRYPTION
+	if (r == 533 && clevel == PROT_P) {
+		fprintf(stderr,
+			"ENC command not supported at server; retrying under MIC...\n");
+		clevel = PROT_S;
+		goto again;
+	}
+#endif
+	if (abrtflag && oldintr && oldintr != SIG_IGN)
+		(*oldintr)(SIGINT);
+	(void) signal(SIGINT, oldintr);
+	return(r);
+}
+
+char reply_string[FTP_BUFSIZ];		/* last line of previous reply */
+
+/* for parsing replies to the ADAT command */
+char *reply_parse, reply_buf[FTP_BUFSIZ], *reply_ptr;
+
+#include <ctype.h>
+
+int getreply(int expecteof)
+{
+	register int i, c, n;
+	register int dig;
+	register char *cp;
+	int originalcode = 0, continuation = 0;
+	sig_t oldintr;
+	int pflag = 0;
+	char *pt = pasv;
+	char ibuf[FTP_BUFSIZ], obuf[FTP_BUFSIZ];
+	int safe = 0;
+#ifndef strpbrk
+	extern char *strpbrk();
+#endif
+#ifndef strstr
+	extern char *strstr();
+#endif
+
+	ibuf[0] = '\0';
+	if (reply_parse) reply_ptr = reply_buf;
+	oldintr = signal(SIGINT, cmdabort);
+	for (;;) {
+		obuf[0] = '\0';
+		dig = n = code = i = 0;
+		cp = reply_string;
+		while ((c = ibuf[0] ? ibuf[i++] : getc(cin)) != '\n') {
+			if (c == IAC) {     /* handle telnet commands */
+				switch (c = getc(cin)) {
+				case WILL:
+				case WONT:
+					c = getc(cin);
+					fprintf(cout, "%c%c%c", IAC, DONT, c);
+					(void) fflush(cout);
+					break;
+				case DO:
+				case DONT:
+					c = getc(cin);
+					fprintf(cout, "%c%c%c", IAC, WONT, c);
+					(void) fflush(cout);
+					break;
+				default:
+					break;
+				}
+				continue;
+			}
+			dig++;
+			if (c == EOF) {
+				if (expecteof) {
+					(void) signal(SIGINT,oldintr);
+					code = 221;
+					return (0);
+				}
+				lostpeer();
+				if (verbose) {
+					printf("421 Service not available, remote server has closed connection\n");
+					(void) fflush(stdout);
+				}
+				code = 421;
+				return(4);
+			}
+			if (n == 0)
+				n = c;
+			if (auth_type && !ibuf[0] &&
+				(n == '6' || continuation)) {
+			    if (c != '\r' && dig > 4)
+				obuf[i++] = c;
+			} else {
+			    if (auth_type && !ibuf[0] && dig == 1 && verbose)
+			printf("Unauthenticated reply received from server:\n");
+			    if (reply_parse) *reply_ptr++ = c;
+			    if (c != '\r' && (verbose > 0 ||
+				(verbose > -1 && n == '5' && dig > 4))) {
+				    if (proxflag &&
+					(dig == 1 || (dig == 5 && verbose == 0)))
+						printf("%s:",hostname);
+				    (void) putchar(c);
+			    }
+			}
+			if (auth_type && !ibuf[0] && n != '6') continue;
+			if (dig < 4 && isdigit(c))
+				code = code * 10 + (c - '0');
+			if (!pflag && code == 227)
+				pflag = 1;
+			if (dig > 4 && pflag == 1 && isdigit(c))
+				pflag = 2;
+			if (pflag == 2) {
+				if (c != '\r' && c != ')')
+					*pt++ = c;
+				else {
+					*pt = '\0';
+					pflag = 3;
+				}
+			}
+			if (dig == 4 && c == '-' && n != '6') {
+				if (continuation)
+					code = 0;
+				continuation++;
+			}
+			if (cp < &reply_string[sizeof(reply_string) - 1])
+				*cp++ = c;
+		}
+		if (auth_type && !ibuf[0] && n != '6')
+			return(getreply(expecteof));
+		ibuf[0] = obuf[i] = '\0';
+		if (code && n == '6') {
+		    if (code != 631 && code != 632 && code != 633) {
+			printf("Unknown reply: %d %s\n", code, obuf);
+			n = '5';
+		    } else safe = (code == 631);
+		}
+		if (obuf[0])	/* if there is a string to decode */
+		    if (!auth_type) {
+			printf("Cannot decode reply:\n%d %s\n", code, obuf);
+			n = '5';
+		    }
+#ifdef NOENCRYPTION
+		    else if (code == 632) {
+			printf("Cannot decrypt %d reply: %s\n", code, obuf);
+			n = '5';
+		    }
+#endif
+#ifdef NOCONFIDENTIAL
+		    else if (code == 633) {
+			printf("Cannot decrypt %d reply: %s\n", code, obuf);
+			n = '5';
+		    }
+#endif
+		    else {
+			int len;
+			kerror = radix_encode((unsigned char *)obuf,
+					      (unsigned char *)ibuf, 
+					      &len, 1);
+			if (kerror) {
+			    printf("Can't base 64 decode reply %d (%s)\n\"%s\"\n",
+					code, radix_error(kerror), obuf);
+			    n = '5';
+			}
+#ifdef KRB5_KRB4_COMPAT
+			else if (strcmp(auth_type, "KERBEROS_V4") == 0)
+				if ((kerror = safe ?
+				  krb_rd_safe((unsigned char *)ibuf, 
+					      (unsigned int) len,
+					      &cred.session,
+					      &hisctladdr, 
+					      &myctladdr, &msg_data)
+				: krb_rd_priv((unsigned char *)ibuf, 
+					      (unsigned int) len,
+					      schedule, &cred.session,
+					      &hisctladdr, &myctladdr,
+					      &msg_data))
+				!= KSUCCESS) {
+				  printf("%d reply %s! (krb_rd_%s: %s)\n", code,
+					safe ? "modified" : "garbled",
+					safe ? "safe" : "priv",
+					krb_get_err_text(kerror));
+				  n = '5';
+				} else {
+				  if (debug) printf("%c:", safe ? 'S' : 'P');
+				  if(msg_data.app_length < sizeof(ibuf) - 2) {
+				    memcpy(ibuf, msg_data.app_data,
+					   msg_data.app_length);
+				    strcpy(&ibuf[msg_data.app_length], "\r\n");
+				  } else {
+			            printf("Message too long!");
+				  }
+				  continue;
+				}
+#endif
+#ifdef GSSAPI
+			else if (strcmp(auth_type, "GSSAPI") == 0) {
+				gss_buffer_desc xmit_buf, msg_buf;
+				OM_uint32 maj_stat, min_stat;
+				int conf_state;
+				xmit_buf.value = ibuf;
+				xmit_buf.length = len;
+				/* decrypt/verify the message */
+				conf_state = safe;
+				maj_stat = gss_unseal(&min_stat, gcontext, 
+						      &xmit_buf, &msg_buf, 
+						      &conf_state, NULL);
+				if (maj_stat != GSS_S_COMPLETE) {
+				  user_gss_error(maj_stat, min_stat, 
+						 "failed unsealing reply");
+				  n = '5';
+				} else {
+				  if(msg_buf.length < sizeof(ibuf) - 2 - 1) {
+				    memcpy(ibuf, msg_buf.value, 
+					   msg_buf.length);
+				    strcpy(&ibuf[msg_buf.length], "\r\n");
+				  } else {
+				    user_gss_error(maj_stat, min_stat, 
+						   "reply was too long");
+				  }
+				  gss_release_buffer(&min_stat,&msg_buf);
+				  continue;
+				}
+			}
+#endif
+			/* Other auth types go here... */
+		    }
+		else
+		if (verbose > 0 || (verbose > -1 && n == '5')) {
+			(void) putchar(c);
+			(void) fflush (stdout);
+		}
+		if (continuation && code != originalcode) {
+			if (originalcode == 0)
+				originalcode = code;
+			continue;
+		}
+		*cp = '\0';
+		if (n != '1')
+			cpend = 0;
+		(void) signal(SIGINT,oldintr);
+		if (code == 421 || originalcode == 421)
+			lostpeer();
+		if (abrtflag && oldintr && oldintr != cmdabort && oldintr != SIG_IGN)
+			(*oldintr)(SIGINT);
+		if (reply_parse) {
+			*reply_ptr = '\0';
+			reply_ptr = strstr(reply_buf, reply_parse);
+			if (reply_ptr) {
+				reply_parse = reply_ptr + strlen(reply_parse);
+				reply_ptr = strpbrk(reply_parse, " \r");
+				if (reply_ptr)
+					*reply_ptr = '\0';
+			} else reply_parse = reply_ptr;
+		}
+		return (n - '0');
+	}
+}
+
+static int empty(fd_set *mask, int sec)
+{
+	struct timeval t;
+
+	t.tv_sec = (long) sec;
+	t.tv_usec = 0;
+	return(select(32, mask, (fd_set *) 0, (fd_set *) 0, &t));
+}
+
+jmp_buf	sendabort;
+
+static sigtype
+abortsend(int sig)
+{
+
+	mflag = 0;
+	abrtflag = 0;
+	printf("\nsend aborted\nwaiting for remote to finish abort\n");
+	(void) fflush(stdout);
+	longjmp(sendabort, 1);
+}
+
+void secure_error(char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	putc('\n', stderr);
+}
+
+#define HASHBYTES 1024
+
+void sendrequest(char *cmd, char *local, char *remote, int printnames)
+{
+	struct stat st;
+	struct timeval start, stop;
+	register int c, d;
+	FILE *volatile fin, *volatile dout = 0;
+	int (*volatile closefunc)();
+	volatile sig_t oldintr, oldintp;
+	volatile long bytes = 0, hashbytes = HASHBYTES;
+	char *volatile lmode;
+	unsigned char buf[FTP_BUFSIZ], *bufp;
+
+	if (verbose && printnames) {
+		if (local && *local != '-')
+			printf("local: %s ", local);
+		if (remote)
+			printf("remote: %s\n", remote);
+	}
+	if (proxy) {
+		proxtrans(cmd, local, remote);
+		return;
+	}
+	if (curtype != type)
+		changetype(type, 0);
+	closefunc = NULL;
+	oldintr = NULL;
+	oldintp = NULL;
+	lmode = "w";
+	if (setjmp(sendabort)) {
+		while (cpend) {
+			(void) getreply(0);
+		}
+		if (data != INVALID_SOCKET) {
+			(void) closesocket(data);
+			data = INVALID_SOCKET;
+		}
+		if (oldintr)
+			(void) signal(SIGINT,oldintr);
+#ifdef SIGPIPE
+		if (oldintp)
+			(void) signal(SIGPIPE,oldintp);
+#endif
+		code = -1;
+		return;
+	}
+	oldintr = signal(SIGINT, abortsend);
+	if (strcmp(local, "-") == 0)
+		fin = stdin;
+	else if (*local == '|') {
+#ifdef SIGPIPE
+		oldintp = signal(SIGPIPE,SIG_IGN);
+#endif
+		fin = popen(local + 1, "r");
+		if (fin == NULL) {
+			perror(local + 1);
+			(void) signal(SIGINT, oldintr);
+#ifdef SIGPIPE
+			(void) signal(SIGPIPE, oldintp);
+#endif
+			code = -1;
+			return;
+		}
+		closefunc = pclose;
+	} else {
+#ifdef _WIN32
+		if ((curtype == TYPE_I) || (curtype == TYPE_L))
+			fin = fopen(local, "rb");
+		else
+			fin = fopen(local, "rt");
+#else /* !_WIN32 */
+		fin = fopen(local, "r");
+#endif /* !_WIN32 */			
+		if (fin == NULL) {
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			(void) signal(SIGINT, oldintr);
+			code = -1;
+			return;
+		}
+		closefunc = fclose;
+		if (fstat(fileno(fin), &st) < 0 ||
+		    (st.st_mode&S_IFMT) != S_IFREG) {
+			fprintf(stdout, "%s: not a plain file.\n", local);
+			(void) signal(SIGINT, oldintr);
+			fclose(fin);
+			code = -1;
+			return;
+		}
+	}
+	if (initconn()) {
+		(void) signal(SIGINT, oldintr);
+#ifdef SIGPIPE
+		if (oldintp)
+			(void) signal(SIGPIPE, oldintp);
+#endif
+		code = -1;
+		if (closefunc != NULL)
+			(*closefunc)(fin);
+		return;
+	}
+	if (setjmp(sendabort))
+		goto die;
+
+	if (restart_point &&
+	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
+		if (fseek(fin, (long) restart_point, 0) < 0) {
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			restart_point = 0;
+			if (closefunc != NULL)
+				(*closefunc)(fin);
+			return;
+		}
+		if (command("REST %ld", (long) restart_point)
+			!= CONTINUE) {
+			restart_point = 0;
+			if (closefunc != NULL)
+				(*closefunc)(fin);
+			return;
+		}
+		restart_point = 0;
+		lmode = "r+w";
+	}
+	if (remote) {
+		if (command("%s %s", cmd, remote) != PRELIM) {
+			(void) signal(SIGINT, oldintr);
+#ifdef SIGPIPE
+			if (oldintp)
+				(void) signal(SIGPIPE, oldintp);
+#endif
+			if (closefunc != NULL)
+				(*closefunc)(fin);
+			return;
+		}
+	} else
+		if (command("%s", cmd) != PRELIM) {
+			(void) signal(SIGINT, oldintr);
+#ifdef SIGPIPE
+			if (oldintp)
+				(void) signal(SIGPIPE, oldintp);
+#endif
+			if (closefunc != NULL)
+				(*closefunc)(fin);
+			return;
+		}
+	dout = dataconn(lmode);
+	if (dout == NULL)
+		goto die;
+	(void) gettimeofday(&start, (struct timezone *)0);
+#ifdef SIGPIPE
+	oldintp = signal(SIGPIPE, SIG_IGN);
+#endif
+	switch (curtype) {
+
+	case TYPE_I:
+	case TYPE_L:
+		errno = d = 0;
+		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
+			bytes += c;
+			for (bufp = buf; c > 0; c -= d, bufp += d)
+				if ((d = secure_write(fileno(dout), bufp, 
+						      (unsigned int) c)) <= 0)
+					break;
+			if (hash) {
+				while (bytes >= hashbytes) {
+					(void) putchar('#');
+					hashbytes += HASHBYTES;
+				}
+				(void) fflush(stdout);
+			}
+			if (d <= 0 ) 
+  break;
+		}
+		if (hash && bytes > 0) {
+			if (bytes < HASHBYTES)
+				(void) putchar('#');
+			(void) putchar('\n');
+			(void) fflush(stdout);
+		}
+		if (c < 0)
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+		if (d < 0 || (d = secure_flush(fileno(dout))) < 0) {
+			if (d == -1 && errno != EPIPE) 
+				perror("netout");
+			bytes = -1;
+		}
+		break;
+
+	case TYPE_A:
+		while ((c = getc(fin)) != EOF) {
+			if (c == '\n') {
+				while (hash && (bytes >= hashbytes)) {
+					(void) putchar('#');
+					(void) fflush(stdout);
+					hashbytes += HASHBYTES;
+				}
+				if (ferror(dout) ||
+				    secure_putc('\r', dout) < 0)
+					break;
+				bytes++;
+			}
+			if (secure_putc(c, dout) < 0)
+				break;
+			bytes++;
+	/*		if (c == '\r') {			  	*/
+	/*		(void)	putc('\0', dout);   this violates rfc */
+	/*			bytes++;				*/
+	/*		}                          			*/	
+		}
+		if (hash) {
+			if (bytes < hashbytes)
+				(void) putchar('#');
+			(void) putchar('\n');
+			(void) fflush(stdout);
+		}
+		if (ferror(fin))
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+		d = 0;
+		if (ferror(dout) || (d = secure_flush(fileno(dout))) < 0) {
+			if ((ferror(dout) || d == -1) && errno != EPIPE)
+				perror("netout");
+			bytes = -1;
+		}
+		break;
+	}
+	(void) gettimeofday(&stop, (struct timezone *)0);
+	if (closefunc != NULL)
+		(*closefunc)(fin);
+	(void) FCLOSE_SOCKET(dout);
+	dout = NULL;
+	(void) getreply(0);
+	(void) signal(SIGINT, oldintr);
+#ifdef SIGPIPE
+	if (oldintp)
+		(void) signal(SIGPIPE, oldintp);
+#endif
+	if (bytes > 0)
+		ptransfer("sent", bytes, &start, &stop);
+	return;
+die:
+	(void) gettimeofday(&stop, (struct timezone *)0);
+	(void) signal(SIGINT, oldintr);
+#ifdef SIGPIPE
+	if (oldintp)
+		(void) signal(SIGPIPE, oldintp);
+#endif
+	if (!cpend) {
+		code = -1;
+		return;
+	}
+	if (data != INVALID_SOCKET) {
+		(void) closesocket(data);
+		data = INVALID_SOCKET;
+	}
+	if (dout) {
+		(void) FCLOSE_SOCKET(dout);
+		dout = NULL;
+	}
+	(void) getreply(0);
+	code = -1;
+	if (closefunc != NULL && fin != NULL)
+		(*closefunc)(fin);
+	if (bytes > 0)
+		ptransfer("sent", bytes, &start, &stop);
+}
+
+jmp_buf	recvabort;
+
+static sigtype
+abortrecv(int sig)
+{
+
+	mflag = 0;
+	abrtflag = 0;
+	printf("\nreceive aborted\nwaiting for remote to finish abort\n");
+	(void) fflush(stdout);
+	longjmp(recvabort, 1);
+}
+
+void recvrequest(char *cmd, char *volatile local, char *remote, char *lmode,
+		 int printnames, int fnameonly)
+{
+	FILE *volatile fout, *volatile din = 0, *popen();
+	int (*volatile closefunc)(), pclose(), fclose();
+	volatile sig_t oldintr, oldintp;
+	volatile int is_retr, tcrflag, bare_lfs = 0;
+	static unsigned int bufsize;
+	static char *buf;
+	unsigned int blksize;
+	volatile long bytes = 0, hashbytes = HASHBYTES;
+	register int c, d;
+	struct timeval start, stop;
+#ifndef NOSTBLKSIZE
+	struct stat st;
+#endif
+	off_t lseek();
+
+	is_retr = strcmp(cmd, "RETR") == 0;
+	if (is_retr && verbose && printnames) {
+		if (local && *local != '-')
+			printf("local: %s ", local);
+		if (remote)
+			printf("remote: %s\n", remote);
+	}
+	if (proxy && is_retr) {
+		proxtrans(cmd, local, remote);
+		return;
+	}
+	closefunc = NULL;
+	oldintr = NULL;
+	oldintp = NULL;
+	tcrflag = !crflag && is_retr;
+	if (setjmp(recvabort)) {
+		while (cpend) {
+			(void) getreply(0);
+		}
+		if (data != INVALID_SOCKET) {
+			(void) closesocket(data);
+			data = INVALID_SOCKET;
+		}
+		if (oldintr)
+			(void) signal(SIGINT, oldintr);
+		code = -1;
+		return;
+	}
+	oldintr = signal(SIGINT, abortrecv);
+	if (fnameonly || (strcmp(local, "-") && *local != '|')) {
+		if (access(local, 2) < 0) {
+			char *dir = strrchr(local, '/');
+
+			if (errno != ENOENT && errno != EACCES) {
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+				(void) signal(SIGINT, oldintr);
+				code = -1;
+				return;
+			}
+			if (dir != NULL)
+				*dir = 0;
+			d = access(dir ? local : ".", 2);
+			if (dir != NULL)
+				*dir = '/';
+			if (d < 0) {
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+				(void) signal(SIGINT, oldintr);
+				code = -1;
+				return;
+			}
+			if (!runique && errno == EACCES &&
+			    chmod(local, 0600) < 0) {
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+				(void) signal(SIGINT, oldintr);
+				(void) signal(SIGINT, oldintr);
+				code = -1;
+				return;
+			}
+			if (runique && errno == EACCES &&
+			   (local = gunique(local)) == NULL) {
+				(void) signal(SIGINT, oldintr);
+				code = -1;
+				return;
+			}
+		}
+		else if (runique && (local = gunique(local)) == NULL) {
+			(void) signal(SIGINT, oldintr);
+			code = -1;
+			return;
+		}
+	}
+	if (!is_retr) {
+		if (curtype != TYPE_A)
+			changetype(TYPE_A, 0);
+	} else if (curtype != type)
+		changetype(type, 0);
+	if (initconn()) {
+		(void) signal(SIGINT, oldintr);
+		code = -1;
+		return;
+	}
+	if (setjmp(recvabort))
+		goto die;
+	if (is_retr && restart_point &&
+	    command("REST %ld", (long) restart_point) != CONTINUE)
+		return;
+	if (remote) {
+		if (command("%s %s", cmd, remote) != PRELIM) {
+			(void) signal(SIGINT, oldintr);
+			return;
+		}
+	} else {
+		if (command("%s", cmd) != PRELIM) {
+			(void) signal(SIGINT, oldintr);
+			return;
+		}
+	}
+	din = dataconn("r");
+	if (din == NULL)
+		goto die;
+	if (strcmp(local, "-") == 0 && !fnameonly)
+		fout = stdout;
+	else if (*local == '|' && !fnameonly) {
+#ifdef SIGPIPE
+		oldintp = signal(SIGPIPE, SIG_IGN);
+#endif
+		fout = popen(local + 1, "w");
+		if (fout == NULL) {
+			perror(local+1);
+			goto die;
+		}
+		closefunc = pclose;
+	} else {
+#ifdef _WIN32
+		int old_fmode = _fmode;
+
+		if ((curtype == TYPE_I) || (curtype == TYPE_L))
+			_fmode = _O_BINARY;
+#endif /* _WIN32 */
+		fout = fopen(local, lmode);
+#ifdef _WIN32
+		_fmode = old_fmode;
+#endif
+		if (fout == NULL) {
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			goto die;
+		}
+		closefunc = fclose;
+	}
+	blksize = FTP_BUFSIZ;
+#ifndef NOSTBLKSIZE
+	if (fstat(fileno(fout), &st) == 0 && st.st_blksize != 0)
+		blksize = st.st_blksize;
+#endif
+	if (blksize > bufsize) {
+		if (buf)
+			(void) free(buf);
+		buf = (char *)malloc((unsigned)blksize);
+		if (buf == NULL) {
+			perror("malloc");
+			bufsize = 0;
+			goto die;
+		}
+		bufsize = blksize;
+	}
+	(void) gettimeofday(&start, (struct timezone *)0);
+	switch (curtype) {
+
+	case TYPE_I:
+	case TYPE_L:
+		if (restart_point &&
+		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			if (closefunc != NULL)
+				(*closefunc)(fout);
+			return;
+		}
+		errno = d = 0;
+		while ((c = secure_read(fileno(din), buf, bufsize)) > 0) {
+		        d = write(fileno(fout), buf,(unsigned int) c);
+			if (d != c)
+				break;
+			bytes += c;
+			if (hash) {
+				while (bytes >= hashbytes) {
+					(void) putchar('#');
+					hashbytes += HASHBYTES;
+				}
+				(void) fflush(stdout);
+			}
+		}
+		if (hash && bytes > 0) {
+			if (bytes < HASHBYTES)
+				(void) putchar('#');
+			(void) putchar('\n');
+			(void) fflush(stdout);
+		}
+		if (c < 0) {
+			if (c == -1 && errno != EPIPE)
+				perror("netin");
+			bytes = -1;
+		}
+		if (d < c) {
+			if (d < 0)
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+			else
+				fprintf(stderr, "%s: short write\n", local);
+		}
+		break;
+
+	case TYPE_A:
+		if (restart_point) {
+			register int i, n, ch;
+
+			if (fseek(fout, 0L, L_SET) < 0)
+				goto done;
+			n = restart_point;
+			for (i = 0; i++ < n;) {
+				if ((ch = getc(fout)) == EOF)
+					goto done;
+				if (ch == '\n')
+					i++;
+			}
+			if (fseek(fout, 0L, L_INCR) < 0) {
+done:
+				fprintf(stderr, "local: %s: %s\n", local,
+					strerror(errno));
+				if (closefunc != NULL)
+					(*closefunc)(fout);
+				return;
+			}
+		}
+		while ((c = secure_getc(din)) >= 0) {
+			if (c == '\n')
+				bare_lfs++;
+			while (c == '\r') {
+				while (hash && (bytes >= hashbytes)) {
+					(void) putchar('#');
+					(void) fflush(stdout);
+					hashbytes += HASHBYTES;
+				}
+				bytes++;
+				if ((c = secure_getc(din)) != '\n' || tcrflag) {
+					if (ferror(fout))
+						goto break2;
+					(void) putc('\r', fout);
+					if (c == '\0') {
+						bytes++;
+						goto contin2;
+					}
+				}
+			}
+			if (c < 0) break;
+			(void) putc(c, fout);
+			bytes++;
+	contin2:	;
+		}
+break2:
+		if (bare_lfs) {
+			printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
+			printf("File may not have transferred correctly.\n");
+		}
+		if (hash) {
+			if (bytes < hashbytes)
+				(void) putchar('#');
+			(void) putchar('\n');
+			(void) fflush(stdout);
+		}
+		if (ferror(din)) {
+			if (errno != EPIPE)
+				perror("netin");
+			bytes = -1;
+		}
+		if (ferror(fout) || c == -2) {
+		    if (c != -2)
+			fprintf(stderr, "local: %s: %s\n", local,
+				strerror(errno));
+			bytes = -1;
+		}
+		break;
+	}
+	if (closefunc != NULL)
+		(*closefunc)(fout);
+	(void) signal(SIGINT, oldintr);
+#ifdef SIGPIPE
+	if (oldintp)
+		(void) signal(SIGPIPE, oldintp);
+#endif
+	(void) gettimeofday(&stop, (struct timezone *)0);
+	(void) FCLOSE_SOCKET(din);
+	din = NULL;
+	(void) getreply(0);
+	if (bytes > 0 && is_retr)
+		ptransfer("received", bytes, &start, &stop);
+	return;
+die:
+
+/* abort using RFC959 recommended IP,SYNC sequence  */
+
+	(void) gettimeofday(&stop, (struct timezone *)0);
+#ifdef SIGPIPE
+	if (oldintp)
+		(void) signal(SIGPIPE, oldintr);
+#endif
+	(void) signal(SIGINT, SIG_IGN);
+	if (!cpend) {
+		code = -1;
+		(void) signal(SIGINT, oldintr);
+		return;
+	}
+
+	abort_remote(din);
+	code = -1;
+	if (data != INVALID_SOCKET) {
+		(void) closesocket(data);
+		data = INVALID_SOCKET;
+	}
+	if (closefunc != NULL && fout != NULL)
+		(*closefunc)(fout);
+	if (din) {
+		(void) FCLOSE_SOCKET(din);
+		din = NULL;
+	}
+	if (bytes > 0)
+		ptransfer("received", bytes, &start, &stop);
+	(void) signal(SIGINT, oldintr);
+}
+
+/*
+ * Need to start a listen on the data channel before we send the command,
+ * otherwise the server's connect may fail.
+ */
+static int initconn()
+{
+	register char *p, *a;
+	int result, tmpno = 0;
+	socklen_t len;
+	int on = 1;
+#ifndef NO_PASSIVE_MODE
+	int a1,a2,a3,a4,p1,p2;
+
+	if (passivemode) {
+		data = socket(AF_INET, SOCK_STREAM, 0);
+		if (data == INVALID_SOCKET) {
+			PERROR_SOCKET("ftp: socket");
+			return(1);
+		}
+		if (options & SO_DEBUG &&
+		    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) == SOCKET_ERROR)
+			PERROR_SOCKET("ftp: setsockopt (ignored)");
+		if (command("PASV") != COMPLETE) {
+			printf("Passive mode refused.  Turning off passive mode.\n");
+			passivemode = 0;
+			return initconn();
+		}
+
+/*
+ * What we've got at this point is a string of comma separated
+ * one-byte unsigned integer values, separated by commas.
+ * The first four are the an IP address. The fifth is the MSB
+ * of the port number, the sixth is the LSB. From that we'll
+ * prepare a sockaddr_in.
+ */
+
+		if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2) != 6) {
+			printf("Passive mode address scan failure. Shouldn't happen!\n");
+			return(1);
+		};
+
+		data_addr.sin_family = AF_INET;
+		data_addr.sin_addr.s_addr = htonl((a1<<24)|(a2<<16)|(a3<<8)|a4);
+		data_addr.sin_port = htons((p1<<8)|p2);
+
+		if (connect(data, (struct sockaddr *) &data_addr, sizeof(data_addr)) == SOCKET_ERROR) {
+			PERROR_SOCKET("ftp: connect");
+			return(1);
+		}
+#ifdef IP_TOS
+#ifdef IPTOS_THROUGHPUT
+	on = IPTOS_THROUGHPUT;
+	if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) == SOCKET_ERROR)
+		PERROR_SOCKET("ftp: setsockopt TOS (ignored)");
+#endif
+#endif
+		hisdataaddr = data_addr;
+		return(0);
+	}
+#endif
+
+noport:
+	data_addr = myctladdr;
+	if (sendport)
+		data_addr.sin_port = 0;	/* let system pick one */ 
+	if (data != INVALID_SOCKET)
+		(void) closesocket(data);
+	data = socket(AF_INET, SOCK_STREAM, 0);
+	if (data == INVALID_SOCKET) {
+		PERROR_SOCKET("ftp: socket");
+		if (tmpno)
+			sendport = 1;
+		return (1);
+	}
+	if (!sendport)
+		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) == SOCKET_ERROR) {
+			PERROR_SOCKET("ftp: setsockopt (reuse address)");
+			goto bad;
+		}
+	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) == SOCKET_ERROR) {
+		PERROR_SOCKET("ftp: bind");
+		goto bad;
+	}
+	if (options & SO_DEBUG &&
+	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) == SOCKET_ERROR)
+		PERROR_SOCKET("ftp: setsockopt (ignored)");
+	len = sizeof (data_addr);
+	if (getsockname(data, (struct sockaddr *)&data_addr, &len) == SOCKET_ERROR) {
+		PERROR_SOCKET("ftp: getsockname");
+		goto bad;
+	}
+	if (listen(data, 1) == SOCKET_ERROR)
+		PERROR_SOCKET("ftp: listen");
+	if (sendport) {
+		a = (char *)&data_addr.sin_addr;
+		p = (char *)&data_addr.sin_port;
+#define	UC(b)	(((int)b)&0xff)
+		result =
+		    command("PORT %d,%d,%d,%d,%d,%d",
+		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+		      UC(p[0]), UC(p[1]));
+		if (result == ERROR && sendport == -1) {
+			sendport = 0;
+			tmpno = 1;
+			goto noport;
+		}
+		return (result != COMPLETE);
+	}
+	if (tmpno)
+		sendport = 1;
+#ifdef IP_TOS
+#ifdef IPTOS_THROUGHPUT
+	on = IPTOS_THROUGHPUT;
+	if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) == SOCKET_ERROR)
+		PERROR_SOCKET("ftp: setsockopt TOS (ignored)");
+#endif
+#endif
+	return (0);
+bad:
+	(void) closesocket(data), data = INVALID_SOCKET;
+	if (tmpno)
+		sendport = 1;
+	return (1);
+}
+
+FILE *
+dataconn(char *lmode)
+{
+	int s;
+	socklen_t fromlen = sizeof (hisdataaddr);
+#ifdef IP_TOS
+#ifdef IPTOS_LOWDELAY
+        int tos;
+#endif
+#endif
+
+#ifndef NO_PASSIVE_MODE
+	if (passivemode)
+		return (FDOPEN_SOCKET(data, lmode));
+#endif
+	s = accept(data, (struct sockaddr *) &hisdataaddr, &fromlen);
+	if (s == INVALID_SOCKET) {
+		PERROR_SOCKET("ftp: accept");
+		(void) closesocket(data), data = INVALID_SOCKET;
+		return (NULL);
+	}
+	(void) closesocket(data);
+	data = s;
+#ifdef IP_TOS
+#ifdef IPTOS_THROUGHPUT
+	tos = IPTOS_THROUGHPUT;
+	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) == SOCKET_ERROR)
+		PERROR_SOCKET("ftp: setsockopt TOS (ignored)");
+#endif
+#endif
+	return (FDOPEN_SOCKET(data, lmode));
+}
+
+static void ptransfer(char *direction, long bytes,
+		      struct timeval *t0, struct timeval *t1)
+{
+	struct timeval td;
+	float s, kbs;
+
+	if (verbose) {
+		tvsub(&td, t1, t0);
+		s = td.tv_sec + (td.tv_usec / 1000000.);
+#define	nz(x)	((x) == 0 ? 1 : (x))
+		kbs = (bytes / nz(s))/1024.0;
+		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
+		    bytes, direction, s, kbs);
+	}
+}
+
+/*tvadd(tsum, t0)
+	struct timeval *tsum, *t0;
+{
+
+	tsum->tv_sec += t0->tv_sec;
+	tsum->tv_usec += t0->tv_usec;
+	if (tsum->tv_usec > 1000000)
+		tsum->tv_sec++, tsum->tv_usec -= 1000000;
+} */
+
+static void tvsub(struct timeval *tdiff, struct timeval *t1,
+		  struct timeval *t0)
+{
+
+	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
+	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
+	if (tdiff->tv_usec < 0)
+		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
+}
+
+static sigtype
+psabort(int sig)
+{
+	abrtflag++;
+}
+
+void pswitch(int flag)
+{
+	sig_t oldintr;
+	static struct comvars {
+		int connect;
+		char name[MAXHOSTNAMELEN];
+		struct sockaddr_in mctl;
+		struct sockaddr_in hctl;
+		FILE *in;
+		FILE *out;
+		int tpe;
+		int curtpe;
+		int cpnd;
+		int sunqe;
+		int runqe;
+		int mcse;
+		int ntflg;
+		char nti[17];
+		char nto[17];
+		int mapflg;
+		char mi[MAXPATHLEN];
+		char mo[MAXPATHLEN];
+		char *authtype;
+		int clvl;
+	        int dlvl;
+#ifdef KRB5_KRB4_COMPAT
+		C_Block session;
+		Key_schedule schedule;
+#endif /* KRB5_KRB4_COMPAT */
+	} proxstruct, tmpstruct;
+	struct comvars *ip, *op;
+
+	abrtflag = 0;
+	oldintr = signal(SIGINT, psabort);
+	if (flag) {
+		if (proxy)
+			return;
+		ip = &tmpstruct;
+		op = &proxstruct;
+		proxy++;
+	} else {
+		if (!proxy)
+			return;
+		ip = &proxstruct;
+		op = &tmpstruct;
+		proxy = 0;
+	}
+	ip->connect = connected;
+	connected = op->connect;
+	if (hostname) {
+		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
+		ip->name[strlen(ip->name)] = '\0';
+	} else
+		ip->name[0] = 0;
+	hostname = op->name;
+	ip->hctl = hisctladdr;
+	hisctladdr = op->hctl;
+	ip->mctl = myctladdr;
+	myctladdr = op->mctl;
+	ip->in = cin;
+	cin = op->in;
+	ip->out = cout;
+	cout = op->out;
+	ip->tpe = type;
+	type = op->tpe;
+	ip->curtpe = curtype;
+	curtype = op->curtpe;
+	ip->cpnd = cpend;
+	cpend = op->cpnd;
+	ip->sunqe = sunique;
+	sunique = op->sunqe;
+	ip->runqe = runique;
+	runique = op->runqe;
+	ip->mcse = mcase;
+	mcase = op->mcse;
+	ip->ntflg = ntflag;
+	ntflag = op->ntflg;
+	(void) strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
+	(ip->nti)[strlen(ip->nti)] = '\0';
+	(void) strncpy(ntin, op->nti, sizeof(ntin) - 1);
+	ntin[sizeof(ntin) - 1] = '\0';
+	(void) strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
+	(ip->nto)[strlen(ip->nto)] = '\0';
+	(void) strncpy(ntout, op->nto, sizeof(ntout) - 1);
+	ntout[sizeof(ntout) - 1] = '\0';
+	ip->mapflg = mapflag;
+	mapflag = op->mapflg;
+	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
+	(ip->mi)[strlen(ip->mi)] = '\0';
+	(void) strncpy(mapin, op->mi, sizeof(mapin) - 1);
+	mapin[sizeof(mapin) - 1] = '\0';
+	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
+	(ip->mo)[strlen(ip->mo)] = '\0';
+	(void) strncpy(mapout, op->mo, sizeof(mapout) - 1);
+	mapout[sizeof(mapout) - 1] = '\0';
+	ip->authtype = auth_type;
+	auth_type = op->authtype;
+	ip->clvl = clevel;
+	clevel = op->clvl;
+	ip->dlvl = dlevel;
+	dlevel = op->dlvl;
+	if (!clevel)
+	     clevel = PROT_C;
+	if (!dlevel)
+	     dlevel = PROT_C;
+#ifdef KRB5_KRB4_COMPAT
+	memcpy(ip->session, cred.session, sizeof(cred.session));
+	memcpy(cred.session, op->session, sizeof(cred.session));
+	memcpy(ip->schedule, schedule, sizeof(schedule));
+	memcpy(schedule, op->schedule, sizeof(schedule));
+#endif /* KRB5_KRB4_COMPAT */
+	(void) signal(SIGINT, oldintr);
+	if (abrtflag) {
+		abrtflag = 0;
+		if (oldintr)
+			(*oldintr)(SIGINT);
+	}
+}
+
+int ptabflg;
+
+static sigtype
+abortpt(int sig)
+{
+	printf("\n");
+	(void) fflush(stdout);
+	ptabflg++;
+	mflag = 0;
+	abrtflag = 0;
+	longjmp(ptabort, 1);
+}
+
+static void
+proxtrans(char *cmd, char *local, char *remote)
+{
+	volatile sig_t oldintr;
+	volatile int secndflag = 0;
+	int prox_type, nfnd;
+	char *volatile cmd2;
+	 fd_set mask;
+
+	if (strcmp(cmd, "RETR"))
+		cmd2 = "RETR";
+	else
+		cmd2 = runique ? "STOU" : "STOR";
+	if ((prox_type = type) == 0) {
+		if (unix_server && unix_proxy)
+			prox_type = TYPE_I;
+		else
+			prox_type = TYPE_A;
+	}
+	if (curtype != prox_type)
+		changetype(prox_type, 1);
+	if (command("PASV") != COMPLETE) {
+		printf("proxy server does not support third party transfers.\n");
+		return;
+	}
+	pswitch(0);
+	if (!connected) {
+		printf("No primary connection\n");
+		pswitch(1);
+		code = -1;
+		return;
+	}
+	if (curtype != prox_type)
+		changetype(prox_type, 1);
+	if (command("PORT %s", pasv) != COMPLETE) {
+		pswitch(1);
+		return;
+	}
+	if (setjmp(ptabort))
+		goto die;
+	oldintr = signal(SIGINT, abortpt);
+	if (command("%s %s", cmd, remote) != PRELIM) {
+		(void) signal(SIGINT, oldintr);
+		pswitch(1);
+		return;
+	}
+	sleep(2);
+	pswitch(1);
+	secndflag++;
+	if (command("%s %s", cmd2, local) != PRELIM)
+		goto die;
+	ptflag++;
+	(void) getreply(0);
+	pswitch(0);
+	(void) getreply(0);
+	(void) signal(SIGINT, oldintr);
+	pswitch(1);
+	ptflag = 0;
+	printf("local: %s remote: %s\n", local, remote);
+	return;
+die:
+	(void) signal(SIGINT, SIG_IGN);
+	ptflag = 0;
+	if (strcmp(cmd, "RETR") && !proxy)
+		pswitch(1);
+	else if (!strcmp(cmd, "RETR") && proxy)
+		pswitch(0);
+	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
+		if (command("%s %s", cmd2, local) != PRELIM) {
+			pswitch(0);
+			if (cpend)
+				abort_remote((FILE *) NULL);
+		}
+		pswitch(1);
+		if (ptabflg)
+			code = -1;
+		(void) signal(SIGINT, oldintr);
+		return;
+	}
+	if (cpend)
+		abort_remote((FILE *) NULL);
+	pswitch(!proxy);
+	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
+		if (command("%s %s", cmd2, local) != PRELIM) {
+			pswitch(0);
+			if (cpend)
+				abort_remote((FILE *) NULL);
+			pswitch(1);
+			if (ptabflg)
+				code = -1;
+			(void) signal(SIGINT, oldintr);
+			return;
+		}
+	}
+	if (cpend)
+		abort_remote((FILE *) NULL);
+	pswitch(!proxy);
+	if (cpend) {
+		FD_ZERO(&mask);
+		FD_SET(SOCKETNO(fileno(cin)), &mask);
+		if ((nfnd = empty(&mask, 10)) <= 0) {
+			if (nfnd < 0) {
+				perror("abort");
+			}
+			if (ptabflg)
+				code = -1;
+			lostpeer();
+		}
+		(void) getreply(0);
+		(void) getreply(0);
+	}
+	if (proxy)
+		pswitch(0);
+	pswitch(1);
+	if (ptabflg)
+		code = -1;
+	(void) signal(SIGINT, oldintr);
+}
+
+void reset()
+{
+   fd_set mask;
+	int nfnd = 1;
+
+	FD_ZERO(&mask);
+	while (nfnd > 0) {
+		FD_SET(SOCKETNO(fileno(cin)), &mask);
+		if ((nfnd = empty(&mask,0)) < 0) {
+			perror("reset");
+			code = -1;
+			lostpeer();
+		}
+		else if (nfnd) {
+			(void) getreply(0);
+		}
+	}
+}
+
+static char *
+gunique(char *local)
+{
+	static char new[MAXPATHLEN];
+	char *cp = strrchr(local, '/');
+	int d, count=0;
+	char ext = '1';
+
+	if (cp)
+		*cp = '\0';
+	d = access(cp ? local : ".", 2);
+	if (cp)
+		*cp = '/';
+	if (d < 0) {
+		fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
+		return((char *) 0);
+	}
+	(void) strncpy(new, local, sizeof(new) - 3);
+	new[sizeof(new) - 1] = '\0';
+	cp = new + strlen(new);
+	*cp++ = '.';
+	while (!d) {
+		if (++count == 100) {
+			printf("runique: can't find unique file name.\n");
+			return((char *) 0);
+		}
+		*cp++ = ext;
+		*cp = '\0';
+		if (ext == '9')
+			ext = '0';
+		else
+			ext++;
+		if ((d = access(new, 0)) < 0)
+			break;
+		if (ext != '0')
+			cp--;
+		else if (*(cp - 2) == '.')
+			*(cp - 1) = '1';
+		else {
+			*(cp - 2) = *(cp - 2) + 1;
+			cp--;
+		}
+	}
+	return(new);
+}
+
+#ifdef KRB5_KRB4_COMPAT
+char realm[REALM_SZ + 1];
+#endif /* KRB5_KRB4_COMPAT */
+
+#ifdef GSSAPI
+struct {
+    gss_OID mech_type;
+    char *service_name;
+} gss_trials[] = {
+    { GSS_C_NO_OID, "ftp" },
+    { GSS_C_NO_OID, "host" },
+};
+int n_gss_trials = sizeof(gss_trials)/sizeof(gss_trials[0]);
+#endif /* GSSAPI */
+
+int do_auth()
+{
+	int oldverbose = verbose;
+#ifdef KRB5_KRB4_COMPAT
+	char *service, inst[INST_SZ];
+	KRB4_32 cksum, checksum = getpid();
+#endif /* KRB5_KRB4_COMPAT */
+#if defined(KRB5_KRB4_COMPAT) || defined(GSSAPI)
+	u_char out_buf[FTP_BUFSIZ];
+	int i;
+#endif /* KRB5_KRB4_COMPAT */
+
+	if (auth_type) return(1);	/* auth already succeeded */
+
+	/* Other auth types go here ... */
+
+#ifdef GSSAPI
+	if (command("AUTH %s", "GSSAPI") == CONTINUE) {
+	  OM_uint32 maj_stat, min_stat, dummy_stat;
+	  gss_name_t target_name;
+	  gss_buffer_desc send_tok, recv_tok, *token_ptr;
+	  char stbuf[FTP_BUFSIZ];
+	  int comcode, trial;
+	  struct gss_channel_bindings_struct chan;
+	  chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32  */ 
+	  chan.initiator_address.length = 4;
+	  chan.initiator_address.value = &myctladdr.sin_addr.s_addr;
+	  chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
+	  chan.acceptor_address.length = 4;
+	  chan.acceptor_address.value = &hisctladdr.sin_addr.s_addr;
+	  chan.application_data.length = 0;
+	  chan.application_data.value = 0;
+
+	  if (verbose)
+	    printf("GSSAPI accepted as authentication type\n");
+	  
+	  /* blob from gss-client */
+	  
+	  for (trial = 0; trial < n_gss_trials; trial++) {
+	    /* ftp@hostname first, the host@hostname */
+	    /* the V5 GSSAPI binding canonicalizes this for us... */
+	    sprintf(stbuf, "%s@%s", gss_trials[trial].service_name, hostname);
+	    if (debug)
+	      fprintf(stderr, "Trying to authenticate to <%s>\n", stbuf);
+
+	    send_tok.value = stbuf;
+	    send_tok.length = strlen(stbuf) + 1;
+	    maj_stat = gss_import_name(&min_stat, &send_tok,
+				       gss_nt_service_name, &target_name);
+	    
+	    if (maj_stat != GSS_S_COMPLETE) {
+		    user_gss_error(maj_stat, min_stat, "parsing name");
+		    secure_error("name parsed <%s>\n", stbuf);
+		    continue;
+	    }
+
+	    token_ptr = GSS_C_NO_BUFFER;
+	    gcontext = GSS_C_NO_CONTEXT; /* structure copy */
+	    
+	    do {
+	      if (debug)
+		fprintf(stderr, "calling gss_init_sec_context\n");
+	      maj_stat =
+		gss_init_sec_context(&min_stat,
+				     GSS_C_NO_CREDENTIAL,
+				     &gcontext,
+				     target_name,
+				     (gss_OID_desc *)gss_trials[trial].mech_type,
+				     GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+				       (forward ? GSS_C_DELEG_FLAG : 
+					(unsigned) 0),
+				     0,
+				     &chan,	/* channel bindings */
+				     token_ptr,
+				     NULL,	/* ignore mech type */
+				     &send_tok,
+				     NULL,	/* ignore ret_flags */
+				     NULL);	/* ignore time_rec */
+	      
+
+	      if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED){
+		if (trial == n_gss_trials-1)
+		  user_gss_error(maj_stat, min_stat, "initializing context");
+		/* could just be that we missed on the service name */
+		goto outer_loop;
+	      }
+	    
+	      if (send_tok.length != 0) {
+		int len = send_tok.length;
+		reply_parse = "ADAT="; /* for command() later */
+		oldverbose = verbose;
+		verbose = (trial == n_gss_trials-1)?0:-1;
+		kerror = radix_encode(send_tok.value, out_buf, &len, 0);
+		gss_release_buffer(&dummy_stat, &send_tok);
+		if (kerror)  {
+		  fprintf(stderr, "Base 64 encoding failed: %s\n",
+			  radix_error(kerror));
+		} else if ((comcode = command("ADAT %s", out_buf))!=COMPLETE
+			   && comcode != 3 /* (335) */) {
+		    if (trial == n_gss_trials-1) {
+			fprintf(stderr, "GSSAPI ADAT failed\n");
+			/* force out of loop */
+			maj_stat = GSS_S_FAILURE;
+		    }
+		    /* backoff to the v1 gssapi is still possible.  Send
+		       a new AUTH command.  If that fails, terminate the
+		       loop */
+		    if (command("AUTH %s", "GSSAPI") != CONTINUE) {
+			fprintf(stderr,
+				"GSSAPI ADAT failed, AUTH restart failed\n");
+			/* force out of loop */
+			maj_stat = GSS_S_FAILURE;
+		    }
+		    goto outer_loop;
+		} else if (!reply_parse) {
+		  fprintf(stderr,
+			  "No authentication data received from server\n");
+		  if (maj_stat == GSS_S_COMPLETE) {
+		    fprintf(stderr, "...but no more was needed\n");
+		    goto gss_complete_loop;
+		  } else {
+		    user_gss_error(maj_stat, min_stat, "no reply, huh?");
+		    goto gss_complete_loop;
+		  }
+		} else if ((kerror = radix_encode((unsigned char *)reply_parse,
+						  out_buf,&i,1))) {
+		  fprintf(stderr, "Base 64 decoding failed: %s\n",
+			  radix_error(kerror));
+		} else {
+		  /* everything worked */
+		  token_ptr = &recv_tok;
+		  recv_tok.value = out_buf;
+		  recv_tok.length = i;
+		  continue;
+		}
+
+		/* get out of loop clean */
+	      gss_complete_loop:
+		trial = n_gss_trials-1;
+		goto outer_loop;
+	      }
+	    } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+    outer_loop:
+	    gss_release_name(&dummy_stat, &target_name);
+	    if (maj_stat == GSS_S_COMPLETE)
+	        break;
+	  }
+	  verbose = oldverbose;
+	  if (maj_stat == GSS_S_COMPLETE) {
+	    printf("GSSAPI authentication succeeded\n");
+	    reply_parse = NULL;
+	    auth_type = "GSSAPI";
+	    return(1);
+	  } else {
+	    fprintf(stderr, "GSSAPI authentication failed\n");
+	    verbose = oldverbose;
+	    reply_parse = NULL;
+	  }
+	}
+#endif /* GSSAPI */
+#ifdef KRB5_KRB4_COMPAT
+	if (command("AUTH %s", "KERBEROS_V4") == CONTINUE) {
+	    if (verbose)
+		printf("%s accepted as authentication type\n", "KERBEROS_V4");
+
+	    strncpy(inst, (char *) krb_get_phost(hostname), sizeof(inst) - 1);
+	    inst[sizeof(inst) - 1] = '\0';
+	    if (realm[0] == '\0')
+	    	strncpy(realm, (char *) krb_realmofhost(hostname), sizeof(realm) - 1);
+	    realm[sizeof(realm) - 1] = '\0';
+	    if ((kerror = krb_mk_req(&ticket, service = "ftp",
+					inst, realm, checksum))
+		&& (kerror != KDC_PR_UNKNOWN ||
+	        (kerror = krb_mk_req(&ticket, service = "rcmd",
+					inst, realm, checksum))))
+			fprintf(stderr, "Kerberos V4 krb_mk_req failed: %s\n",
+					krb_get_err_text(kerror));
+	    else if ((kerror = krb_get_cred(service, inst, realm, &cred)))
+			fprintf(stderr, "Kerberos V4 krb_get_cred failed: %s\n",
+					krb_get_err_text(kerror));
+	    else {
+		key_sched(cred.session, schedule);
+		reply_parse = "ADAT=";
+		oldverbose = verbose;
+		verbose = 0;
+		i = ticket.length;
+		if ((kerror = radix_encode(ticket.dat, out_buf, &i, 0)))
+			fprintf(stderr, "Base 64 encoding failed: %s\n",
+					radix_error(kerror));
+		else if (command("ADAT %s", out_buf) != COMPLETE)
+			fprintf(stderr, "Kerberos V4 authentication failed\n");
+		else if (!reply_parse)
+			fprintf(stderr,
+			       "No authentication data received from server\n");
+		else if ((kerror = radix_encode((unsigned char *)reply_parse, out_buf, &i, 1)))
+			fprintf(stderr, "Base 64 decoding failed: %s\n",
+					radix_error(kerror));
+		else if ((kerror = krb_rd_safe(out_buf, (unsigned )i,
+					       &cred.session,
+					       &hisctladdr, &myctladdr, 
+					       &msg_data)))
+			fprintf(stderr, "Kerberos V4 krb_rd_safe failed: %s\n",
+					krb_get_err_text(kerror));
+		else {
+		    /* fetch the (modified) checksum */
+		    (void) memcpy(&cksum, msg_data.app_data, sizeof(cksum));
+		    if (ntohl(cksum) == checksum + 1) {
+			verbose = oldverbose;
+			if (verbose)
+			   printf("Kerberos V4 authentication succeeded\n");
+			reply_parse = NULL;
+			auth_type = "KERBEROS_V4";
+			return(1);
+		    } else fprintf(stderr,
+				"Kerberos V4 mutual authentication failed\n");
+		}
+		verbose = oldverbose;
+		reply_parse = NULL;
+	    }
+	} else	fprintf(stderr, "%s rejected as an authentication type\n",
+				"KERBEROS_V4");
+#endif /* KRB5_KRB4_COMPAT */
+
+	/* Other auth types go here ... */
+
+	return(0);
+}
+
+void
+setpbsz(unsigned int size)
+{
+	int oldverbose;
+
+	if (ucbuf) (void) free(ucbuf);
+	actualbuf = size;
+	while ((ucbuf = (unsigned char *)malloc(actualbuf)) == NULL)
+		if (actualbuf)
+			actualbuf >>= 2;
+		else {
+			perror("Error while trying to malloc PROT buffer:");
+			exit(1);
+		}
+	oldverbose = verbose;
+	verbose = 0;
+	reply_parse = "PBSZ=";
+	if (command("PBSZ %u", actualbuf) != COMPLETE)
+		fatal("Cannot set PROT buffer size");
+	if (reply_parse) {
+		if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf)
+			maxbuf = actualbuf;
+	} else	maxbuf = actualbuf;
+	reply_parse = NULL;
+	verbose = oldverbose;
+}
+
+static void abort_remote(FILE *din)
+{
+	char buf[FTP_BUFSIZ];
+	int nfnd;
+	fd_set mask;
+
+	/*
+	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
+	 * after urgent byte rather than before as is protocol now
+	 */
+	sprintf(buf, "%c%c%c", IAC, IP, IAC);
+	if (send(SOCKETNO(fileno(cout)), buf, 3, MSG_OOB) != 3)
+		PERROR_SOCKET("abort");
+	putc(DM, cout);
+	(void) secure_command("ABOR");
+	FD_ZERO(&mask);
+	FD_SET(SOCKETNO(fileno(cin)), &mask);
+	if (din) { 
+		FD_SET(SOCKETNO(fileno(din)), &mask);
+	}
+	if ((nfnd = empty(&mask, 10)) <= 0) {
+		if (nfnd < 0) {
+			perror("abort");
+		}
+		if (ptabflg)
+			code = -1;
+		lostpeer();
+	}
+	if (din && FD_ISSET(SOCKETNO(fileno(din)), &mask)) {
+		/* Security: No threat associated with this read. */
+		while (read(fileno(din), buf, FTP_BUFSIZ) > 0)
+			/* LOOP */;
+	}
+	if (getreply(0) == ERROR && code == 552) {
+		/* 552 needed for nic style abort */
+		(void) getreply(0);
+	}
+	(void) getreply(0);
+}
+
+#ifdef GSSAPI
+void user_gss_error(OM_uint32 maj_stat, OM_uint32 min_stat, char *s)
+{
+	/* a lot of work just to report the error */
+	OM_uint32 gmaj_stat, gmin_stat, msg_ctx;
+	gss_buffer_desc msg;
+	msg_ctx = 0;
+	while (!msg_ctx) {
+		gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
+					       GSS_C_GSS_CODE,
+					       GSS_C_NULL_OID,
+					       &msg_ctx, &msg);
+		if ((gmaj_stat == GSS_S_COMPLETE)||
+		    (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
+			fprintf(stderr, "GSSAPI error major: %s\n",
+				(char*)msg.value);
+			(void) gss_release_buffer(&gmin_stat, &msg);
+		}
+		if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
+			break;
+	}
+	msg_ctx = 0;
+	while (!msg_ctx) {
+		gmaj_stat = gss_display_status(&gmin_stat, min_stat,
+					       GSS_C_MECH_CODE,
+					       GSS_C_NULL_OID,
+					       &msg_ctx, &msg);
+		if ((gmaj_stat == GSS_S_COMPLETE)||
+		    (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
+			fprintf(stderr, "GSSAPI error minor: %s\n",
+				(char*)msg.value);
+			(void) gss_release_buffer(&gmin_stat, &msg);
+		}
+		if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
+			break;
+	}
+	fprintf(stderr, "GSSAPI error: %s\n", s);
+}
+
+void secure_gss_error(OM_uint32 maj_stat, OM_uint32 min_stat, char *s)
+{
+  user_gss_error(maj_stat, min_stat, s);
+  return;
+}
+#endif /* GSSAPI */
+
+#ifdef _WIN32
+
+int gettimeofday(struct timeval *tv, void *tz)
+{
+	struct _timeb tb;
+	_tzset();
+	_ftime(&tb);
+	if (tv) {
+		tv->tv_sec = tb.time;
+		tv->tv_usec = tb.millitm * 1000;
+	}
+#if 0
+	if (tz) {
+		tz->tz_minuteswest = tb.timezone;
+		tz->tz_dsttime = tb.dstflag;
+	}
+#else
+	_ASSERTE(!tz);
+#endif
+	return 0;
+}
+
+int fclose_socket(FILE* f)
+{
+	int rc = 0;
+	SOCKET _s = _get_osfhandle(_fileno(f));
+
+	rc = fclose(f);
+	if (rc)
+		return rc;
+	if (closesocket(_s) == SOCKET_ERROR)
+		return SOCKET_ERRNO;
+	return 0;
+}
+
+FILE* fdopen_socket(SOCKET s, char* mode)
+{
+	int o_mode = 0;
+	int old_fmode = _fmode;
+	FILE* f = 0;
+
+	if (strstr(mode, "a+")) o_mode |= _O_RDWR | _O_APPEND;
+	if (strstr(mode, "r+")) o_mode |= _O_RDWR;
+	if (strstr(mode, "w+")) o_mode |= _O_RDWR;
+	if (strchr(mode, 'a')) o_mode |= _O_WRONLY | _O_APPEND;
+	if (strchr(mode, 'r')) o_mode |= _O_RDONLY;
+	if (strchr(mode, 'w')) o_mode |= _O_WRONLY;
+
+	/* In theory, _open_osfhandle only takes: _O_APPEND, _O_RDONLY, _O_TEXT */
+
+	_fmode = _O_BINARY;
+	f = fdopen(_open_osfhandle(s, o_mode), mode);
+	_fmode = old_fmode;
+
+	return f;
+}
+#endif /* _WIN32 */
diff --git a/mechglue/src/appl/gssftp/ftp/ftp_var.h b/mechglue/src/appl/gssftp/ftp/ftp_var.h
new file mode 100644
index 000000000..9baa04730
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/ftp_var.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ftp_var.h	5.9 (Berkeley) 6/1/90
+ */
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#ifdef _WIN32
+int fclose_socket(FILE* f);
+FILE* fdopen_socket(SOCKET s, char* mode);
+#define FCLOSE_SOCKET(f) fclose_socket(f)
+#define FDOPEN_SOCKET(s, mode) fdopen_socket(s, mode)
+#define SOCKETNO(fd) _get_osfhandle(fd)
+#define PERROR_SOCKET(str) do { errno = SOCKET_ERRNO; perror(str); } while(0)
+#else
+#define FCLOSE_SOCKET(f) fclose(f)
+#define FDOPEN_SOCKET(s, mode) fdopen(s, mode)
+#define SOCKETNO(fd) (fd)
+#define PERROR_SOCKET(str) perror(str)
+#endif
+
+#ifdef _WIN32
+typedef void (*sig_t)(int);
+typedef void sigtype;
+#else
+#define sig_t my_sig_t
+#define sigtype krb5_sigtype
+typedef sigtype (*sig_t)();
+#endif
+
+/*
+ * FTP global variables.
+ */
+
+#ifdef DEFINITIONS
+#define extern
+#endif
+
+/*
+ * Options and other state info.
+ */
+extern int	trace;		/* trace packets exchanged */
+extern int	hash;		/* print # for each buffer transferred */
+extern int	sendport;	/* use PORT cmd for each data connection */
+extern int	verbose;	/* print messages coming back from server */
+extern int	connected;	/* connected to server */
+extern int	fromatty;	/* input is from a terminal */
+extern int	interactive;	/* interactively prompt on m* cmds */
+extern int	debug;		/* debugging level */
+extern int	bell;		/* ring bell on cmd completion */
+extern int	doglob;		/* glob local file names */
+extern int autoauth;		/* Do authentication on connect */
+extern int	autologin;	/* establish user account on connection */
+extern int	autoencrypt;	/* negotiate encryption on connection */
+extern int	forward;	/* forward credentials */
+extern int	proxy;		/* proxy server connection active */
+extern int	proxflag;	/* proxy connection exists */
+extern int	sunique;	/* store files on server with unique name */
+extern int	runique;	/* store local files with unique name */
+extern int	mcase;		/* map upper to lower case for mget names */
+extern int	ntflag;		/* use ntin ntout tables for name translation */
+extern int	mapflag;	/* use mapin mapout templates on file names */
+extern int	code;		/* return/reply code for ftp command */
+extern int	crflag;		/* if 1, strip car. rets. on ascii gets */
+extern char	pasv[64];	/* passive port for proxy data connection */
+#ifndef NO_PASSIVE_MODE
+extern int	passivemode;	/* passive mode enabled */
+#endif
+extern char	*altarg;	/* argv[1] with no shell-like preprocessing  */
+extern char	ntin[17];	/* input translation table */
+extern char	ntout[17];	/* output translation table */
+#ifdef _WIN32
+#ifndef MAXPATHLEN
+#define MAXPATHLEN MAX_PATH
+#endif
+#else
+#include <sys/param.h>
+#endif
+extern char	mapin[MAXPATHLEN];	/* input map template */
+extern char	mapout[MAXPATHLEN];	/* output map template */
+extern int	clevel;		/* command channel protection level */
+extern int	dlevel;		/* data channel protection level */
+extern int	type;		/* requested file transfer type */
+extern int	curtype;	/* current file transfer type */
+extern int	stru;		/* file transfer structure */
+extern int	form;		/* file transfer format */
+extern int	mode;		/* file transfer mode */
+extern char	bytename[32];	/* local byte size in ascii */
+extern int	bytesize;	/* local byte size in binary */
+
+extern char	*hostname;	/* name of host connected to */
+extern int	unix_server;	/* server is unix, can use binary for ascii */
+extern int	unix_proxy;	/* proxy is unix, can use binary for ascii */
+
+extern struct	servent *sp;	/* service spec for tcp/ftp */
+
+#include <setjmp.h>
+extern jmp_buf	toplevel;	/* non-local goto stuff for cmd scanner */
+
+extern char	line[500];	/* input line buffer */
+extern char	*stringbase;	/* current scan point in line buffer */
+extern char	argbuf[500];	/* argument storage buffer */
+extern char	*argbase;	/* current storage point in arg buffer */
+extern int	margc;		/* count of arguments on input line */
+extern char	*margv[20];	/* args parsed from input line */
+extern int     cpend;           /* flag: if != 0, then pending server reply */
+extern int	mflag;		/* flag: if != 0, then active multi command */
+
+extern int	options;	/* used during socket creation */
+
+/*
+ * Format of command table.
+ */
+struct cmd {
+	char	*c_name;	/* name of command */
+	char	*c_help;	/* help string */
+	char	c_bell;		/* give bell when command completes */
+	char	c_conn;		/* must be connected to use command */
+	char	c_proxy;	/* proxy server may execute */
+	void	(*c_handler)();	/* function to call */
+};
+
+struct macel {
+	char mac_name[9];	/* macro name */
+	char *mac_start;	/* start of macro in macbuf */
+	char *mac_end;		/* end of macro in macbuf */
+};
+
+extern int macnum;		/* number of defined macros */
+extern struct macel macros[16];
+extern char macbuf[4096];
+
+#ifdef DEFINITIONS
+#undef extern
+#endif
+
+extern	char *tail();
+#ifndef _WIN32
+extern	char *mktemp();
+#endif
+
+extern int command(char *, ...);
+
+char *remglob (char **, int);
+int another (int *, char ***, char *);
+void makeargv (void);
+void setpeer (int, char **);
+void setclevel (int, char **);
+void setdlevel (int, char **);
+void ccc (void);
+void setclear (void);
+void setsafe (void);
+void setprivate (void);
+void settype (int, char **);
+void changetype (int, int);
+void setbinary (void);
+void setascii (void);
+void settenex (void);
+void set_mode  (int, char **);
+void setform  (int, char **);
+void setstruct  (int, char **);
+void siteidle  (int, char **);
+void put  (int, char **);
+void mput  (int, char **);
+void reget  (int, char **);
+void get  (int, char **);
+void mget  (int, char **);
+void status  (int, char **);
+void setbell (void);
+void settrace (void);
+void sethash (void);
+void setverbose (void);
+void setport (void);
+void setprompt (void);
+void setglob (void);
+void setdebug (int, char **);
+void cd (int, char **);
+void lcd (int, char **);
+void delete_file (int, char **);
+void mdelete (int, char **);
+void renamefile (int, char **);
+void ls (int, char **);
+void mls (int, char **);
+void shell (int, char **);
+void user (int, char **);
+void pwd (void);
+void makedir (int, char **);
+void removedir (int, char **);
+void quote (int, char **);
+void site (int, char **);
+void do_chmod (int, char **);
+void do_umask (int, char **);
+void setidle (int, char **);
+void rmthelp (int, char **);
+void quit (void);
+void disconnect (void);
+void fatal (char *);
+void account (int, char **);
+void doproxy (int, char **);
+void setcase (void);
+void setcr (void);
+void setntrans (int, char **);
+void setnmap (int, char **);
+void setsunique (void);
+void setrunique (void);
+void cdup (void);
+void restart (int, char **);
+void syst (void);
+void macdef (int, char **);
+void sizecmd (int, char **);
+void modtime (int, char **);
+void rmtstatus (int, char **);
+void newer (int, char **);
+void setpassive (void);
+
+/* ftp.c */
+void sendrequest (char *, char *, char *, int);
+void recvrequest (char *, char *volatile, char *, char *, int, int);
+int login (char *);
+void setpbsz (unsigned int);
+void pswitch (int);
+int getreply (int);
+void reset (void);
+char *hookup (char *, int);
+int do_auth (void);
+
+/* glob.c */
+void blkfree (char **);
+
+/* domacro.c */
+void domacro (int, char **);
+
+
+/* main.c */
+void help (int, char **);
+struct cmd *getcmd (char *);
+
+
+/* ruserpass.c */
+int ruserpass (char *, char **, char **, char **);
+
+/* radix.h */
+int radix_encode (unsigned char *, unsigned char *, int *, int);
+char *radix_error (int);
+
+/* getpass.c */
+char *mygetpass (char *);
+
+/* glob.c */
+char **ftpglob (char *);
diff --git a/mechglue/src/appl/gssftp/ftp/getpass.c b/mechglue/src/appl/gssftp/ftp/getpass.c
new file mode 100644
index 000000000..cd27cdce5
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/getpass.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+static	char sccsid[] = "@(#)getpass.c 1.1 90/04/28 SMI"; /* from UCB 5.4 3/7/86 */
+#endif /* not lint */
+
+#ifdef _WIN32
+#include <io.h>
+#include <windows.h>
+#include <stdio.h>
+
+static DWORD old_mode;
+static HANDLE cons_handle;
+
+BOOL WINAPI
+GetPassConsoleControlHandler(DWORD dwCtrlType)
+{
+	switch(dwCtrlType){
+	case CTRL_BREAK_EVENT:
+	case CTRL_C_EVENT:
+		printf("Interrupt\n");
+		fflush(stdout);
+		(void) SetConsoleMode(cons_handle, old_mode);
+		ExitProcess(-1);
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+char *
+mygetpass(char *prompt)
+{
+	DWORD new_mode;
+	char *ptr;
+	int scratchchar;
+	static char password[50+1];
+	int pwsize = sizeof(password);
+
+	cons_handle = GetStdHandle(STD_INPUT_HANDLE);
+	if (cons_handle == INVALID_HANDLE_VALUE)
+		return NULL;
+	if (!GetConsoleMode(cons_handle, &old_mode))
+		return NULL;
+
+	new_mode = old_mode;
+	new_mode |=  ( ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT );
+	new_mode &= ~( ENABLE_ECHO_INPUT );
+
+	if (!SetConsoleMode(cons_handle, new_mode))
+		return NULL;
+
+	SetConsoleCtrlHandler(&GetPassConsoleControlHandler, TRUE);
+
+	(void) fputs(prompt, stdout);
+	(void) fflush(stdout);
+	(void) memset(password, 0, pwsize);
+
+	if (fgets(password, pwsize, stdin) == NULL) {
+		if (ferror(stdin))
+			goto out;
+		(void) putchar('\n');
+	}
+	else {
+		(void) putchar('\n');
+
+		if ((ptr = strchr(password, '\n')))
+			*ptr = '\0';
+		else /* need to flush */
+			do {
+				scratchchar = getchar();
+			} while (scratchchar != EOF && scratchchar != '\n');
+	}
+
+out:
+	(void) SetConsoleMode(cons_handle, old_mode);
+	SetConsoleCtrlHandler(&GetPassConsoleControlHandler, FALSE);
+
+	return password;
+}
+
+#else /* !_WIN32 */
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <signal.h>
+
+#if defined (POSIX) || defined (POSIX_TERMIOS)
+#include <termios.h>
+static	struct termios ttyo, ttyb;
+#define stty(f, t) tcsetattr(f, TCSANOW, t)
+#define gtty(f, t) tcgetattr(f, t)
+#else
+#include <sgtty.h>
+static	struct sgttyb ttyo, ttyb;
+#endif
+
+#include "ftp_var.h"
+
+static	FILE *fi;
+
+static sigtype
+intfix(sig)
+	int sig;
+{
+	if (fi != NULL)
+		(void) stty(fileno(fi), &ttyo);
+	exit(SIGINT);
+}
+
+char *
+mygetpass(prompt)
+char *prompt;
+{
+	register char *p;
+	register int c;
+	static char pbuf[50+1];
+	sigtype (*sig)();
+
+	if ((fi = fopen("/dev/tty", "r")) == NULL)
+		fi = stdin;
+	else
+		setbuf(fi, (char *)NULL);
+	sig = signal(SIGINT, intfix);
+	(void) gtty(fileno(fi), &ttyb);
+	ttyo = ttyb;
+#if defined (POSIX) || defined (POSIX_TERMIOS)
+	ttyb.c_lflag &= ~ECHO;
+#else
+	ttyb.sg_flags &= ~ECHO;
+#endif
+	(void) stty(fileno(fi), &ttyb);
+	fprintf(stderr, "%s", prompt); (void) fflush(stderr);
+	for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
+		if (p < &pbuf[sizeof(pbuf)-1])
+			*p++ = c;
+	}
+	*p = '\0';
+	fprintf(stderr, "\n"); (void) fflush(stderr);
+	(void) stty(fileno(fi), &ttyo);
+	(void) signal(SIGINT, sig);
+	if (fi != stdin)
+		(void) fclose(fi);
+	return(pbuf);
+}
+
+#endif /* !_WIN32 */
diff --git a/mechglue/src/appl/gssftp/ftp/glob.c b/mechglue/src/appl/gssftp/ftp/glob.c
new file mode 100644
index 000000000..272e50305
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/glob.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)glob.c	5.9 (Berkeley) 2/25/91";
+#endif /* not lint */
+
+/*
+ * C-shell glob for random programs.
+ */
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifndef _WIN32
+#include <sys/param.h>
+#include <dirent.h>
+#include <pwd.h>
+#endif
+
+#ifdef POSIX
+#include <limits.h>
+#endif
+
+#include "ftp_var.h"
+
+#ifdef ARG_MAX
+#undef NCARGS
+#define NCARGS ARG_MAX
+#endif
+
+#ifndef NCARGS
+#define NCARGS 4096
+#endif
+
+#define	QUOTE 0200
+#define	TRIM 0177
+#define	eq(a,b)		(strcmp(a, b)==0)
+#define	GAVSIZ		(NCARGS/6)
+#define	isdir(d)	((d.st_mode & S_IFMT) == S_IFDIR)
+
+static	char **gargv;		/* Pointer to the (stack) arglist */
+static	int gargc;		/* Number args in gargv */
+static	int gnleft;
+static	short gflag;
+char	**ftpglob();
+char	*globerr;
+char	*home;
+static	char *strspl (char *, char *), *strend (char *);
+char	**copyblk (char **);
+
+static void acollect (char *), addpath (int), 
+  collect (char *), expand (char *), 
+  Gcat (char *, char *);
+static void ginit (char **), matchdir (char *),
+  rscan (char **, int (*f)()), sort (void);
+static int amatch (char *, char *), 
+  execbrc (char *, char *), match (char *, char *);
+static int digit (int), letter (int),
+  any (int, char *);
+#ifndef _WIN32
+static int gethdir (char *);
+#endif
+static int tglob (int );
+
+static	int globcnt;
+
+char	*globchars = "`{[*?";
+
+static	char *gpath, *gpathp, *lastgpathp;
+static	int globbed;
+static	char *entp;
+static	char **sortbas;
+
+char **
+ftpglob(v)
+	register char *v;
+{
+	char agpath[FTP_BUFSIZ];
+	char *agargv[GAVSIZ];
+	char *vv[2];
+	vv[0] = v;
+	vv[1] = 0;
+	gflag = 0;
+	rscan(vv, tglob);
+	if (gflag == 0) {
+	  /* Caller will always free the contents, so make a copy.  */
+	  size_t len = strlen (v) + 1;
+	  vv[0] = malloc (len);
+	  if (vv[0] == 0) {
+	    globerr = "Can't allocate memory";
+	    return 0;
+	  }
+	  memcpy (vv[0], v, len);
+	  return (copyblk(vv));
+	}
+
+	globerr = 0;
+	gpath = agpath; gpathp = gpath; *gpathp = 0;
+	lastgpathp = &gpath[sizeof(agpath) - 1];
+	ginit(agargv); globcnt = 0;
+	collect(v);
+	if (globcnt == 0 && (gflag&1)) {
+		blkfree(gargv), gargv = 0;
+		return (0);
+	} else
+		return (gargv = copyblk(gargv));
+}
+
+static void
+ginit(agargv)
+	char **agargv;
+{
+
+	agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
+	gnleft = NCARGS - 4;
+}
+
+static void
+collect(as)
+	register char *as;
+{
+	if (eq(as, "{") || eq(as, "{}")) {
+		Gcat(as, "");
+		sort();
+	} else
+		acollect(as);
+}
+
+static void
+acollect(as)
+	register char *as;
+{
+	register int ogargc = gargc;
+
+	gpathp = gpath; *gpathp = 0; globbed = 0;
+	expand(as);
+	if (gargc != ogargc)
+		sort();
+}
+
+static void
+sort()
+{
+	register char **p1, **p2, *c;
+	char **Gvp = &gargv[gargc];
+
+	p1 = sortbas;
+	while (p1 < Gvp-1) {
+		p2 = p1;
+		while (++p2 < Gvp)
+			if (strcmp(*p1, *p2) > 0)
+				c = *p1, *p1 = *p2, *p2 = c;
+		p1++;
+	}
+	sortbas = Gvp;
+}
+
+static void
+expand(as)
+	char *as;
+{
+	register char *cs;
+	register char *sgpathp, *oldcs;
+	struct stat stb;
+
+	sgpathp = gpathp;
+	cs = as;
+#ifndef _WIN32
+	if (*cs == '~' && gpathp == gpath) {
+		addpath('~');
+		for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
+			addpath(*cs++);
+		if (!*cs || *cs == '/') {
+			if (gpathp != gpath + 1) {
+				*gpathp = 0;
+				if (gethdir(gpath + 1))
+					globerr = "Unknown user name after ~";
+				(void) strcpy(gpath, gpath + 1);
+			} else
+				(void) strncpy(gpath, home, FTP_BUFSIZ - 1);
+			gpath[FTP_BUFSIZ - 1] = '\0';
+			gpathp = strend(gpath);
+		}
+	}
+#endif
+	while (!any(*cs, globchars)) {
+		if (*cs == 0) {
+			if (!globbed)
+				Gcat(gpath, "");
+			else if (stat(gpath, &stb) >= 0) {
+				Gcat(gpath, "");
+				globcnt++;
+			}
+			goto endit;
+		}
+		addpath(*cs++);
+	}
+	oldcs = cs;
+	while (cs > as && *cs != '/')
+		cs--, gpathp--;
+	if (*cs == '/')
+		cs++, gpathp++;
+	*gpathp = 0;
+	if (*oldcs == '{') {
+		(void) execbrc(cs, ((char *)0));
+		return;
+	}
+	matchdir(cs);
+endit:
+	gpathp = sgpathp;
+	*gpathp = 0;
+}
+
+#ifdef _WIN32
+
+static void
+matchdir(pattern)
+	char *pattern;
+{
+	HANDLE hFile = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATA file_data;
+	char *base = *gpath ? gpath : ".";
+	char *buffer = 0;
+
+	buffer = malloc(strlen(base) + strlen("\\*") + 1);
+	if (!buffer) return;
+	strcpy(buffer, base);
+	strcat(buffer, "\\*");
+	hFile = FindFirstFile(buffer, &file_data);
+	if (hFile == INVALID_HANDLE_VALUE) {
+		if (!globbed)
+			globerr = "Bad directory components";
+		return;
+	}
+	do {
+		if (match(file_data.cFileName, pattern)) {
+			Gcat(gpath, file_data.cFileName);
+			globcnt++;
+		}
+	} while (FindNextFile(hFile, &file_data));
+	FindClose(hFile);
+}
+
+#else /* !_WIN32 */
+
+static void
+matchdir(pattern)
+	char *pattern;
+{
+#if 0
+	struct stat stb;
+#endif
+	register struct dirent *dp;
+	DIR *dirp;
+
+	dirp = opendir(*gpath?gpath:".");
+	if (dirp == NULL) {
+		if (globbed)
+			return;
+		goto patherr2;
+	}
+	/* This fails on systems where you can't inspect the contents of
+	   the DIR structure.  If there are systems whose opendir does
+	   not check for a directory, then use stat, not fstat. */
+#if 0
+	if (fstat(dirp->dd_fd, &stb) < 0)
+		goto patherr1;
+	if (!isdir(stb)) {
+		errno = ENOTDIR;
+		goto patherr1;
+	}
+#endif
+	while ((dp = readdir(dirp)) != NULL) {
+		if (dp->d_ino == 0)
+			continue;
+		if (match(dp->d_name, pattern)) {
+			Gcat(gpath, dp->d_name);
+			globcnt++;
+		}
+	}
+	closedir(dirp);
+	return;
+
+#if 0
+patherr1:
+#endif
+	closedir(dirp);
+patherr2:
+	globerr = "Bad directory components";
+}
+
+#endif /* !_WIN32 */
+
+static int
+execbrc(p, s)
+	char *p, *s;
+{
+	char restbuf[FTP_BUFSIZ + 2];
+	register char *pe, *pm, *pl;
+	int brclev = 0;
+	char *lm, savec, *sgpathp;
+
+	for (lm = restbuf; *p != '{'; *lm++ = *p++)
+		continue;
+	/* pe starts pointing to one past the first '{'. */
+	for (pe = ++p; *pe; pe++)
+	switch (*pe) {
+
+	case '{':
+		brclev++;
+		continue;
+
+	case '}':
+		if (brclev == 0)
+			goto pend;
+		brclev--;
+		continue;
+
+	case '[':
+		for (pe++; *pe && *pe != ']'; pe++)
+			continue;
+		if (!*pe)
+			pe--;
+		continue;
+	}
+pend:
+	brclev = 0;
+	for (pl = pm = p; pm <= pe; pm++)
+	switch (*pm & (QUOTE|TRIM)) {
+
+	case '{':
+		brclev++;
+		continue;
+
+	case '}':
+		if (brclev) {	/* brclev = 0 is outermost brace set */
+			brclev--;
+			continue;
+		}
+		goto doit;
+
+	case ','|QUOTE:
+	case ',':
+		if (brclev)
+			continue;
+doit:
+		savec = *pm;
+		*pm = 0;
+		(void) strncpy(lm, pl, sizeof(restbuf) - 1 - (lm - restbuf));
+		restbuf[sizeof(restbuf) - 1] = '\0';
+		if (*pe) {
+			(void) strncat(restbuf, pe + 1,
+				       sizeof(restbuf) - 1 - strlen(restbuf));
+		}
+		*pm = savec;
+		if (s == 0) {
+			sgpathp = gpathp;
+			expand(restbuf);
+			gpathp = sgpathp;
+			*gpathp = 0;
+		} else if (amatch(s, restbuf))
+			return (1);
+		sort();
+		pl = pm + 1;
+		if (brclev)
+			return (0);
+		continue;
+
+	case '[':
+		for (pm++; *pm && *pm != ']'; pm++)
+			continue;
+		if (!*pm)
+			pm--;
+		continue;
+	}
+	if (brclev)
+		goto doit;
+	return (0);
+}
+
+static int
+match(s, p)
+	char *s, *p;
+{
+	register int c;
+	register char *sentp;
+	char sglobbed = globbed;
+
+	if (*s == '.' && *p != '.')
+		return (0);
+	sentp = entp;
+	entp = s;
+	c = amatch(s, p);
+	entp = sentp;
+	globbed = sglobbed;
+	return (c);
+}
+
+static int
+amatch(s, p)
+	register char *s, *p;
+{
+	register int scc;
+	int ok, lc;
+	char *sgpathp;
+	struct stat stb;
+	int c, cc;
+
+	globbed = 1;
+	for (;;) {
+		scc = *s++ & TRIM;
+		switch (c = *p++) {
+
+		case '{':
+			return (execbrc(p - 1, s - 1));
+
+		case '[':
+			ok = 0;
+			lc = 077777;
+			while ((cc = *p++)) {
+				if (cc == ']') {
+					if (ok)
+						break;
+					return (0);
+				}
+				if (cc == '-') {
+					if (lc <= scc && scc <= *p++)
+						ok++;
+				} else
+					if (scc == (lc = cc))
+						ok++;
+			}
+			if (cc == 0) {
+				if (ok)
+					p--;
+				else
+					return 0;
+			}
+			continue;
+
+		case '*':
+			/* Multiple stars are equivalent to one.
+			   Don't chew up cpu time with O(n**2)
+			   recursion if a long string of them is
+			   given.  */
+			while (*p == '*')
+				p++;
+			if (!*p)
+				return (1);
+			if (*p == '/') {
+				p++;
+				goto slash;
+			}
+			s--;
+			do {
+				if (amatch(s, p))
+					return (1);
+			} while (*s++);
+			return (0);
+
+		case 0:
+			return (scc == 0);
+
+		default:
+			if (c != scc)
+				return (0);
+			continue;
+
+		case '?':
+			if (scc == 0)
+				return (0);
+			continue;
+
+		case '/':
+			if (scc)
+				return (0);
+slash:
+			s = entp;
+			sgpathp = gpathp;
+			while (*s)
+				addpath(*s++);
+			addpath('/');
+			if (stat(gpath, &stb) == 0 && isdir(stb)) {
+				if (*p == 0) {
+					Gcat(gpath, "");
+					globcnt++;
+				} else
+					expand(p);
+			}
+			gpathp = sgpathp;
+			*gpathp = 0;
+			return (0);
+		}
+	}
+}
+
+static int
+Gmatch(s, p)
+	register char *s, *p;
+{
+	register int scc;
+	int ok, lc;
+	int c, cc;
+
+	for (;;) {
+		scc = *s++ & TRIM;
+		switch (c = *p++) {
+
+		case '[':
+			ok = 0;
+			lc = 077777;
+			while ((cc = *p++)) {
+				if (cc == ']') {
+					if (ok)
+						break;
+					return (0);
+				}
+				if (cc == '-') {
+					if (lc <= scc && scc <= *p++)
+						ok++;
+				} else
+					if (scc == (lc = cc))
+						ok++;
+			}
+			if (cc == 0) {
+				if (ok)
+					p--;
+				else
+					return 0;
+			}
+			continue;
+
+		case '*':
+			if (!*p)
+				return (1);
+			for (s--; *s; s++)
+				if (Gmatch(s, p))
+					return (1);
+			return (0);
+
+		case 0:
+			return (scc == 0);
+
+		default:
+			if ((c & TRIM) != scc)
+				return (0);
+			continue;
+
+		case '?':
+			if (scc == 0)
+				return (0);
+			continue;
+
+		}
+	}
+}
+
+static void
+Gcat(s1, s2)
+	register char *s1, *s2;
+{
+	register int len = strlen(s1) + strlen(s2) + 1;
+
+	if (len >= gnleft || gargc >= GAVSIZ - 1)
+		globerr = "Arguments too long";
+	else {
+		gargc++;
+		gnleft -= len;
+		gargv[gargc] = 0;
+		gargv[gargc - 1] = strspl(s1, s2);
+	}
+}
+
+static void
+addpath(c)
+	int c;
+{
+
+	if (gpathp >= lastgpathp)
+		globerr = "Pathname too long";
+	else {
+		*gpathp++ = c & 0xff;
+		*gpathp = 0;
+	}
+}
+
+static void
+rscan(t, f)
+	register char **t;
+	int (*f)();
+{
+	register char *p, c;
+
+	while ((p = *t++)) {
+		if (f == tglob) {
+			if (*p == '~')
+				gflag |= 2;
+			else if (eq(p, "{") || eq(p, "{}"))
+				continue;
+		}
+		while ((c = *p++))
+			(*f)(c);
+	}
+}
+/*
+static
+scan(t, f)
+	register char **t;
+	int (*f)();
+{
+	register char *p, c;
+
+	while (p = *t++)
+		while (c = *p)
+			*p++ = (*f)(c);
+} */
+
+static int
+tglob(c)
+	register int c;
+{
+
+	if (any(c, globchars))
+		gflag |= c == '{' ? 2 : 1;
+	return (c);
+}
+/*
+static
+trim(c)
+	char c;
+{
+
+	return (c & TRIM);
+} */
+
+
+static int
+letter(c)
+	register int c;
+{
+
+	return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
+}
+
+static int
+digit(c)
+	register int c;
+{
+
+	return (c >= '0' && c <= '9');
+}
+
+static int any(c, s)
+	register int c;
+	register char *s;
+{
+
+	while (*s)
+		if (*s++ == c)
+			return(1);
+	return(0);
+}
+static int blklen(av)
+	register char **av;
+{
+	register int i = 0;
+
+	while (*av++)
+		i++;
+	return (i);
+}
+
+static char **
+blkcpy(oav, bv)
+	char **oav;
+	register char **bv;
+{
+	register char **av = oav;
+
+	while ((*av++ = *bv++))
+		continue;
+	return (oav);
+}
+
+void blkfree(av0)
+	char **av0;
+{
+	register char **av = av0;
+
+	while (*av)
+		free(*av++);
+}
+
+static
+char *
+strspl(cp, dp)
+	register char *cp, *dp;
+{
+	register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
+
+	if (ep == (char *)0)
+		fatal("Out of memory");
+	(void) strcpy(ep, cp);
+	(void) strcat(ep, dp);
+	return (ep);
+}
+
+char **
+copyblk(v)
+	register char **v;
+{
+	register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
+						sizeof(char **)));
+	if (nv == (char **)0)
+		fatal("Out of memory");
+
+	return (blkcpy(nv, v));
+}
+
+static
+char *
+strend(cp)
+	register char *cp;
+{
+
+	while (*cp)
+		cp++;
+	return (cp);
+}
+
+#ifndef _WIN32
+/*
+ * Extract a home directory from the password file
+ * The argument points to a buffer where the name of the
+ * user whose home directory is sought is currently.
+ * We write the home directory of the user back there.
+ */
+static int gethdir(mhome)
+	char *mhome;
+{
+	register struct passwd *pp = getpwnam(mhome);
+
+	if (!pp || ((mhome + strlen(pp->pw_dir)) >= lastgpathp))
+		return (1);
+	(void) strcpy(mhome, pp->pw_dir);
+	return (0);
+}
+#endif
diff --git a/mechglue/src/appl/gssftp/ftp/main.c b/mechglue/src/appl/gssftp/ftp/main.c
new file mode 100644
index 000000000..8e4cfe5ef
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/main.c
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c	5.18 (Berkeley) 3/1/91";
+#endif /* not lint */
+
+/*
+ * FTP User Program -- Command Interface.
+ */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "ftp_var.h"
+#ifndef _WIN32
+#ifndef KRB5_KRB4_COMPAT
+/* krb.h gets this, and Ultrix doesn't protect vs multiple inclusion */
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <pwd.h>
+#endif /* !_WIN32 */
+
+#ifdef _WIN32
+#include <io.h>
+#undef ERROR
+#endif
+
+#include <arpa/ftp.h>
+
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <port-sockets.h>
+
+#ifdef _WIN32
+/* For SO_SYNCHRONOUS_NONALERT and SO_OPENTYPE: */
+#include <mswsock.h>
+#endif
+
+#ifndef _WIN32
+uid_t	getuid();
+#endif
+
+sigtype	intr (int), lostpeer (int);
+extern	char *home;
+char	*getlogin();
+#ifdef KRB5_KRB4_COMPAT
+#include <krb.h>
+struct servent staticsp;
+extern char realm[];
+#endif /* KRB5_KRB4_COMPAT */
+
+static void cmdscanner (int);
+static char *slurpstring (void);
+
+
+int 
+main(argc, argv)
+	volatile int argc;
+	char **volatile argv;
+{
+	register char *cp;
+	int top;
+#ifndef _WIN32
+	struct passwd *pw = NULL;
+#endif
+	char homedir[MAXPATHLEN];
+	char *progname = argv[0];
+
+#ifdef _WIN32
+	DWORD optionValue = SO_SYNCHRONOUS_NONALERT;
+	if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)) == SOCKET_ERROR) {
+		fprintf(stderr, "ftp: cannot enable synchronous sockets\n");
+		exit(1);
+	}
+#endif
+
+	sp = getservbyname("ftp", "tcp");
+	if (sp == 0) {
+		fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
+		exit(1);
+	}
+#ifdef KRB5_KRB4_COMPAT
+/* GDM need to static sp so that the information is not lost
+   when kerberos calls getservbyname */
+	memcpy(&staticsp,sp,sizeof(struct servent));
+	sp = &staticsp;
+#endif /* KRB5_KRB4_COMPAT */
+	doglob = 1;
+	interactive = 1;
+	autoauth = 1;
+	autologin = 1;
+	forward = 0;
+	autoencrypt = 0;
+	argc--, argv++;
+	while (argc > 0 && **argv == '-') {
+		for (cp = *argv + 1; *cp; cp++)
+			switch (*cp) {
+
+			case 'd':
+				options |= SO_DEBUG;
+				debug++;
+				break;
+
+#ifdef KRB5_KRB4_COMPAT
+			case 'k':
+				if (*++cp != '\0')
+					strncpy(realm, ++cp, REALM_SZ);
+				else if (argc > 1) {
+					argc--, argv++;
+					strncpy(realm, *argv, REALM_SZ);
+				}
+				else
+					fprintf(stderr, "ftp: -k expects arguments\n");
+				goto nextopt;
+#endif
+
+			case 'v':
+				verbose++;
+				break;
+
+			case 't':
+				trace++;
+				break;
+
+			case 'i':
+				interactive = 0;
+				break;
+
+			case 'n':
+				autologin = 0;
+				break;
+
+			case 'g':
+				doglob = 0;
+				break;
+
+			case 'u':
+				autoauth = 0;
+				break;
+
+			case 'f':
+				forward = 1;
+				break;
+
+			case 'x':
+				autoencrypt = 1;
+				break;
+
+			default:
+			  fprintf(stderr,
+				  "ftp: %c: unknown option\n", *cp);
+			  fprintf(stderr, "Usage: %s [-v] [-d] [-i] [-n] [-g] "
+				  "[-k realm] [-f] [-x] [-u] [-t] [host]\n",
+				  progname);
+			  exit(1);
+			}
+	nextopt:
+		argc--, argv++;
+	}
+	fromatty = isatty(fileno(stdin));
+	if (fromatty)
+		verbose++;
+	cpend = 0;	/* no pending replies */
+	proxy = 0;	/* proxy not active */
+#ifndef NO_PASSIVE_MODE
+	passivemode = 0; /* passive mode not active */
+#endif
+	crflag = 1;	/* strip c.r. on ascii gets */
+	sendport = -1;	/* not using ports */
+	/*
+	 * Set up the home directory in case we're globbing.
+	 */
+#ifdef _WIN32
+	cp = getenv("HOME");
+	if (cp != NULL) {
+		home = homedir;
+		(void) strncpy(home, cp, sizeof(homedir) - 1);
+		homedir[sizeof(homedir) - 1] = '\0';
+	}
+#else /* !_WIN32 */
+	cp = getlogin();
+	if (cp != NULL) {
+		pw = getpwnam(cp);
+	}
+	if (pw == NULL)
+		pw = getpwuid(getuid());
+	if (pw != NULL) {
+		home = homedir;
+		(void) strncpy(home, pw->pw_dir, sizeof(homedir) - 1);
+		homedir[sizeof(homedir) - 1] = '\0';
+	}
+#endif /* !_WIN32 */
+	if (argc > 0) {
+		if (setjmp(toplevel))
+			exit(0);
+		(void) signal(SIGINT, intr);
+#ifdef SIGPIPE
+		(void) signal(SIGPIPE, lostpeer);
+#endif
+		setpeer(argc + 1, argv - 1);
+	}
+	top = setjmp(toplevel) == 0;
+	if (top) {
+		(void) signal(SIGINT, intr);
+#ifdef SIGPIPE
+		(void) signal(SIGPIPE, lostpeer);
+#endif
+	}
+	for (;;) {
+		cmdscanner(top);
+		top = 1;
+	}
+}
+
+sigtype
+intr(sig)
+	int sig;
+{
+
+	longjmp(toplevel, 1);
+}
+
+sigtype
+lostpeer(sig)
+	int sig;
+{
+	extern FILE *cout;
+	extern SOCKET data;
+	extern char *auth_type;
+	extern int clevel;
+	extern int dlevel;
+
+	if (connected) {
+		if (cout != NULL) {
+			(void) shutdown(SOCKETNO(fileno(cout)), 1+1);
+			(void) FCLOSE_SOCKET(cout);
+			cout = NULL;
+		}
+		if (data != INVALID_SOCKET) {
+			(void) shutdown(data, 1+1);
+			(void) closesocket(data);
+			data = INVALID_SOCKET;
+		}
+		connected = 0;
+		auth_type = NULL;
+		clevel = dlevel = PROT_C;
+	}
+	pswitch(1);
+	if (connected) {
+		if (cout != NULL) {
+			(void) shutdown(SOCKETNO(fileno(cout)), 1+1);
+			(void) FCLOSE_SOCKET(cout);
+			cout = NULL;
+		}
+		connected = 0;
+		auth_type = NULL;
+		clevel = dlevel = PROT_C;
+	}
+	proxflag = 0;
+	pswitch(0);
+}
+
+/*char *
+tail(filename)
+	char *filename;
+{
+	register char *s;
+	
+	while (*filename) {
+		s = strrchr(filename, '/');
+		if (s == NULL)
+			break;
+		if (s[1])
+			return (s + 1);
+		*s = '\0';
+	}
+	return (filename);
+}
+*/
+/*
+ * Command parser.
+ */
+static void
+cmdscanner(top)
+	int top;
+{
+	register struct cmd *c;
+	register int l;
+
+	if (!top)
+		(void) putchar('\n');
+	for (;;) {
+		if (fromatty) {
+			printf("ftp> ");
+			(void) fflush(stdout);
+		}
+		if (fgets(line, sizeof line, stdin) == NULL)
+			quit();
+		l = strlen(line);
+		if (l == 0)
+			break;
+		if (line[--l] == '\n') {
+			if (l == 0)
+				break;
+			line[l] = '\0';
+		} else if (l == sizeof(line) - 2) {
+			printf("sorry, input line too long\n");
+			while ((l = getchar()) != '\n' && l != EOF)
+				/* void */;
+			break;
+		} /* else it was a line without a newline */
+		makeargv();
+		if (margc == 0) {
+			continue;
+		}
+		c = getcmd(margv[0]);
+		if (c == (struct cmd *)-1) {
+			printf("?Ambiguous command\n");
+			continue;
+		}
+		if (c == 0) {
+			printf("?Invalid command\n");
+			continue;
+		}
+		if (c->c_conn && !connected) {
+			printf("Not connected.\n");
+			continue;
+		}
+		(*c->c_handler)(margc, margv);
+		if (bell && c->c_bell)
+			(void) putchar('\007');
+		if (c->c_handler != help)
+			break;
+	}
+	(void) signal(SIGINT, intr);
+#ifdef SIGPIPE
+	(void) signal(SIGPIPE, lostpeer);
+#endif
+}
+
+struct cmd *
+getcmd(name)
+	register char *name;
+{
+	extern struct cmd cmdtab[];
+	register char *p, *q;
+	register struct cmd *c, *found;
+	register int nmatches, longest;
+
+	longest = 0;
+	nmatches = 0;
+	found = 0;
+	for (c = cmdtab; (p = c->c_name) != NULL; c++) {
+		for (q = name; *q == *p++; q++)
+			if (*q == 0)		/* exact match? */
+				return (c);
+		if (!*q) {			/* the name was a prefix */
+			if (q - name > longest) {
+				longest = q - name;
+				nmatches = 1;
+				found = c;
+			} else if (q - name == longest)
+				nmatches++;
+		}
+	}
+	if (nmatches > 1)
+		return ((struct cmd *)-1);
+	return (found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+
+int slrflag;
+
+void makeargv()
+{
+	char **argp;
+
+	margc = 0;
+	argp = margv;
+	stringbase = line;		/* scan from first of buffer */
+	argbase = argbuf;		/* store from first of buffer */
+	slrflag = 0;
+	while ((*argp++ = slurpstring())) {
+		margc++;
+		if (margc == sizeof(margv)/sizeof(margv[0])) {
+			printf("sorry, too many arguments in input line\n");
+			margc = 0;
+			margv[0] = 0;
+			return;
+		}
+	}
+}
+
+/*
+ * Parse string into argbuf;
+ * implemented with FSM to
+ * handle quoting and strings
+ */
+static char *
+slurpstring()
+{
+	int got_one = 0;
+	register char *sb = stringbase;
+	register char *ap = argbase;
+	char *tmp = argbase;		/* will return this if token found */
+
+	if (*sb == '!' || *sb == '$') {	/* recognize ! as a token for shell */
+		switch (slrflag) {	/* and $ as token for macro invoke */
+			case 0:
+				slrflag++;
+				stringbase++;
+				return ((*sb == '!') ? "!" : "$");
+				/* NOTREACHED */
+			case 1:
+				slrflag++;
+				altarg = stringbase;
+				break;
+			default:
+				break;
+		}
+	}
+
+S0:
+	switch (*sb) {
+
+	case '\0':
+		goto EXIT;
+
+	case ' ':
+	case '\t':
+		sb++; goto S0;
+
+	default:
+		switch (slrflag) {
+			case 0:
+				slrflag++;
+				break;
+			case 1:
+				slrflag++;
+				altarg = sb;
+				break;
+			default:
+				break;
+		}
+		goto S1;
+	}
+
+S1:
+	switch (*sb) {
+
+	case ' ':
+	case '\t':
+	case '\0':
+		goto EXIT;	/* end of token */
+
+	case '\\':
+		sb++; goto S2;	/* slurp next character */
+
+	case '"':
+		sb++; goto S3;	/* slurp quoted string */
+
+	default:
+		*ap++ = *sb++;	/* add character to token */
+		got_one = 1;
+		goto S1;
+	}
+
+S2:
+	switch (*sb) {
+
+	case '\0':
+		goto EXIT;
+
+	default:
+		*ap++ = *sb++;
+		got_one = 1;
+		goto S1;
+	}
+
+S3:
+	switch (*sb) {
+
+	case '\0':
+		goto EXIT;
+
+	case '"':
+		sb++; goto S1;
+
+	default:
+		*ap++ = *sb++;
+		got_one = 1;
+		goto S3;
+	}
+
+EXIT:
+	if (got_one)
+		*ap++ = '\0';
+	argbase = ap;			/* update storage pointer */
+	stringbase = sb;		/* update scan pointer */
+	if (got_one) {
+		return(tmp);
+	}
+	switch (slrflag) {
+		case 0:
+			slrflag++;
+			break;
+		case 1:
+			slrflag++;
+			altarg = (char *) 0;
+			break;
+		default:
+			break;
+	}
+	return((char *)0);
+}
+
+#define	HELPINDENT ((int) sizeof("disconnect"))
+
+/*
+ * Help command.
+ * Call each command handler with argc == 0 and argv[0] == name.
+ */
+void help(argc, argv)
+	int argc;
+	char *argv[];
+{
+	extern struct cmd cmdtab[];
+	register struct cmd *c;
+
+	if (argc == 1) {
+		register int i, j, w, k;
+		int columns, width = 0, lines;
+		extern int NCMDS;
+
+		printf("Commands may be abbreviated.  Commands are:\n\n");
+		for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
+			int len = strlen(c->c_name);
+
+			if (len > width)
+				width = len;
+		}
+		width = (width + 8) &~ 7;
+		columns = 80 / width;
+		if (columns == 0)
+			columns = 1;
+		lines = (NCMDS + columns - 1) / columns;
+		for (i = 0; i < lines; i++) {
+			for (j = 0; j < columns; j++) {
+				c = cmdtab + j * lines + i;
+				if (c->c_name && (!proxy || c->c_proxy)) {
+					printf("%s", c->c_name);
+				}
+				else if (c->c_name) {
+					for (k=0; k < strlen(c->c_name); k++) {
+						(void) putchar(' ');
+					}
+				}
+				if (c + lines >= &cmdtab[NCMDS]) {
+					printf("\n");
+					break;
+				}
+				w = strlen(c->c_name);
+				while (w < width) {
+					w = (w + 8) &~ 7;
+					(void) putchar('\t');
+				}
+			}
+		}
+		return;
+	}
+	while (--argc > 0) {
+		register char *arg;
+		arg = *++argv;
+		c = getcmd(arg);
+		if (c == (struct cmd *)-1)
+			printf("?Ambiguous help command %s\n", arg);
+		else if (c == (struct cmd *)0)
+			printf("?Invalid help command %s\n", arg);
+		else
+			printf("%-*s\t%s\n", HELPINDENT,
+				c->c_name, c->c_help);
+	}
+}
diff --git a/mechglue/src/appl/gssftp/ftp/pathnames.h b/mechglue/src/appl/gssftp/ftp/pathnames.h
new file mode 100644
index 000000000..7c0de5b0e
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/pathnames.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pathnames.h	5.2 (Berkeley) 6/1/90
+ */
+
+#undef _PATH_TMP
+#define	_PATH_TMP	"/tmp/ftpXXXXXX"
diff --git a/mechglue/src/appl/gssftp/ftp/pclose.c b/mechglue/src/appl/gssftp/ftp/pclose.c
new file mode 100644
index 000000000..5d6a5aa57
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/pclose.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+static	char sccsid[] = "@(#)pclose.c 1.1 90/04/28 SMI"; /* from UCB 1.2 3/7/86 */
+#endif /* not lint */
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#define sig_t my_sig_t
+#define sigtype krb5_sigtype
+typedef sigtype (*sig_t)();
+
+#define	tst(a,b)	(*mode == 'r'? (b) : (a))
+#define	RDR	0
+#define	WTR	1
+
+static	int *popen_pid;
+static	int nfiles;
+
+#ifndef HAVE_GETDTABLESIZE
+#include <sys/resource.h>
+int getdtablesize() {
+  struct rlimit rl;
+  getrlimit(RLIMIT_NOFILE, &rl);
+  return rl.rlim_cur;
+}
+#endif
+
+FILE *
+mypopen(cmd,mode)
+	char *cmd;
+	char *mode;
+{
+	int p[2];
+	volatile int myside, hisside;
+	int pid;
+
+	if (nfiles <= 0)
+		nfiles = getdtablesize();
+	if (popen_pid == NULL) {
+		popen_pid = (int *)malloc((unsigned) nfiles * sizeof *popen_pid);
+		if (popen_pid == NULL)
+			return (NULL);
+		for (pid = 0; pid < nfiles; pid++)
+			popen_pid[pid] = -1;
+	}
+	if (pipe(p) < 0)
+		return (NULL);
+	myside = tst(p[WTR], p[RDR]);
+	hisside = tst(p[RDR], p[WTR]);
+	if ((pid = fork()) == 0) {
+		/* myside and hisside reverse roles in child */
+		(void) close(myside);
+		if (hisside != tst(0, 1)) {
+			(void) dup2(hisside, tst(0, 1));
+			(void) close(hisside);
+		}
+		execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
+		_exit(127);
+	}
+	if (pid == -1) {
+		(void) close(myside);
+		(void) close(hisside);
+		return (NULL);
+	}
+	popen_pid[myside] = pid;
+	(void) close(hisside);
+	return (fdopen(myside, mode));
+}
+
+sigtype
+pabort(sig)
+	int sig;
+{
+	extern int mflag;
+
+	mflag = 0;
+}
+
+mypclose(ptr)
+	FILE *ptr;
+{
+	int child, pid;
+#ifdef USE_SIGPROCMASK
+	sigset_t old, new;
+#else
+	int omask;
+#endif
+	sigtype pabort(), (*istat)();
+#ifdef WAIT_USES_INT
+	int status;
+#else
+	union wait status;
+#endif
+
+	child = popen_pid[fileno(ptr)];
+	popen_pid[fileno(ptr)] = -1;
+	(void) fclose(ptr);
+	if (child == -1)
+		return (-1);
+	istat = signal(SIGINT, pabort);
+#ifdef USE_SIGPROCMASK
+	sigemptyset(&old);
+	sigemptyset(&new);
+	sigaddset(&new,SIGQUIT);
+	sigaddset(&new,SIGHUP);
+	sigprocmask(SIG_BLOCK, &new, &old);
+	while ((pid = wait(&status)) != child && pid != -1)
+		;
+	sigprocmask(SIG_SETMASK, &old, NULL);
+#else
+	omask = sigblock(sigmask(SIGQUIT)|sigmask(SIGHUP));
+	while ((pid = wait(&status)) != child && pid != -1)
+		;
+	sigsetmask(omask);
+#endif
+	(void) signal(SIGINT, istat);
+	return (pid == -1 ? -1 : 0);
+}
diff --git a/mechglue/src/appl/gssftp/ftp/radix.c b/mechglue/src/appl/gssftp/ftp/radix.c
new file mode 100644
index 000000000..2d6dfd18d
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/radix.c
@@ -0,0 +1,166 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ftp_var.h"
+
+static char *radixN =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static char pad = '=';
+
+int radix_encode(inbuf, outbuf, len, decode)
+unsigned char inbuf[], outbuf[];
+int *len, decode;
+{
+	int i,j,D = 0;
+	char *p;
+	unsigned char c = 0;
+
+	if (decode) {
+		for (i=0,j=0; inbuf[i] && inbuf[i] != pad; i++) {
+		    if ((p = strchr(radixN, inbuf[i])) == NULL) return(1);
+		    D = p - radixN;
+		    switch (i&3) {
+			case 0:
+			    c = D<<2;
+			    break;
+			case 1:
+			    outbuf[j++] = c | D>>4;
+			    c = (D&15)<<4;
+			    break;
+			case 2:
+			    outbuf[j++] = c | D>>2;
+			    c = (D&3)<<6;
+			    break;
+			case 3:
+			    outbuf[j++] = c | D;
+		    }
+		}
+		switch (i&3) {
+			case 1: return(3);
+			case 2: if (D&15) return(3);
+				if (strcmp((char *)&inbuf[i], "==")) return(2);
+				break;
+			case 3: if (D&3) return(3);
+				if (strcmp((char *)&inbuf[i], "="))  return(2);
+		}
+		*len = j;
+	} else {
+		for (i=0,j=0; i < *len; i++)
+		    switch (i%3) {
+			case 0:
+			    outbuf[j++] = radixN[inbuf[i]>>2];
+			    c = (inbuf[i]&3)<<4;
+			    break;
+			case 1:
+			    outbuf[j++] = radixN[c|inbuf[i]>>4];
+			    c = (inbuf[i]&15)<<2;
+			    break;
+			case 2:
+			    outbuf[j++] = radixN[c|inbuf[i]>>6];
+			    outbuf[j++] = radixN[inbuf[i]&63];
+			    c = 0;
+		    }
+		if (i%3) outbuf[j++] = radixN[c];
+		switch (i%3) {
+			case 1: outbuf[j++] = pad;
+			case 2: outbuf[j++] = pad;
+		}
+		outbuf[*len = j] = '\0';
+	}
+	return(0);
+}
+
+char *
+radix_error(e)
+int e;
+{
+	switch (e) {
+	    case 0:  return("Success");
+	    case 1:  return("Bad character in encoding");
+	    case 2:  return("Encoding not properly padded");
+	    case 3:  return("Decoded # of bits not a multiple of 8");
+	    default: return("Unknown error");
+	}
+}
+
+#ifdef STANDALONE
+usage(s)
+char *s;
+{
+	fprintf(stderr, "Usage: %s [ -d ] [ string ]\n", s);
+	exit(2);
+}
+
+static int n;
+
+putbuf(inbuf, outbuf, len, decode)
+unsigned char inbuf[], outbuf[];
+int len, decode;
+{
+	int c;
+
+	if (c = radix_encode(inbuf, outbuf, &len, decode)) {
+		fprintf(stderr, "Couldn't %scode input: %s\n",
+				decode ? "de" : "en", radix_error(c));
+		exit(1);
+	}
+	if (decode)
+		write(1, outbuf, len);
+	else
+		for (c = 0; c < len;) {
+			putchar(outbuf[c++]);
+			if (++n%76 == 0) putchar('\n');
+		}
+}
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+	unsigned char *inbuf, *outbuf;
+	int c, len = 0, decode = 0;
+	extern int optind;
+
+	while ((c = getopt(argc, argv, "d")) != -1)
+		switch(c) {
+			default:
+				usage(argv[0]);
+			case 'd':
+				decode++;
+		}
+
+	switch (argc - optind) {
+		case 0:
+			inbuf  = (unsigned char *) malloc(5);
+			outbuf = (unsigned char *) malloc(5);
+			while ((c = getchar()) != EOF)
+			    if (c != '\n') {
+				inbuf[len++] = c;
+				if (len == (decode ? 4 : 3)) {
+					inbuf[len] = '\0';
+					putbuf(inbuf, outbuf, len, decode);
+					len=0;
+				}
+			    }
+			if (len) {
+				inbuf[len] = '\0';
+				putbuf(inbuf, outbuf, len, decode);
+			}
+			break;
+		case 1:
+			inbuf = (unsigned char *)argv[optind];
+			len = strlen(inbuf);
+			outbuf = (unsigned char *)
+				malloc((len * (decode?3:4)) / (decode?4:3) + 1);
+			putbuf(inbuf, outbuf, len, decode);
+			break;
+		default:
+			fprintf(stderr, "Only one argument allowed\n");
+			usage(argv[0]);
+	}
+	if (n%76) putchar('\n');
+	exit(0);
+}
+#endif /* STANDALONE */
diff --git a/mechglue/src/appl/gssftp/ftp/ruserpass.c b/mechglue/src/appl/gssftp/ftp/ruserpass.c
new file mode 100644
index 000000000..acfabfa2d
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/ruserpass.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ruserpass.c	5.3 (Berkeley) 3/1/91";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <ctype.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "ftp_var.h"
+
+#ifdef _WIN32
+#include <win-mac.h>
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+static int token (void);
+static	FILE *cfile;
+
+#define	DEFAULT	1
+#define	LOGIN	2
+#define	PASSWD	3
+#define	ACCOUNT 4
+#define MACDEF  5
+#define	ID	10
+#define	MACH	11
+
+static char tokval[100];
+
+static struct toktab {
+	char *tokstr;
+	int tval;
+} toktab[]= {
+	{ "default",	DEFAULT },
+	{ "login",	LOGIN },
+	{ "password",	PASSWD },
+	{ "passwd",	PASSWD },
+	{ "account",	ACCOUNT },
+	{ "machine",	MACH },
+	{ "macdef",	MACDEF },
+	{ NULL,		0 }
+};
+
+
+static int
+token()
+{
+	char *cp;
+	int c;
+	struct toktab *t;
+
+	if (feof(cfile))
+		return (0);
+	while ((c = getc(cfile)) != EOF &&
+	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
+		continue;
+	if (c == EOF)
+		return (0);
+	cp = tokval;
+	if (c == '"') {
+		while ((c = getc(cfile)) != EOF && c != '"') {
+			if (c == '\\')
+				c = getc(cfile);
+			*cp++ = c;
+		}
+	} else {
+		*cp++ = c;
+		while ((c = getc(cfile)) != EOF
+		    && c != '\n' && c != '\t' && c != ' ' && c != ',') {
+			if (c == '\\')
+				c = getc(cfile);
+			*cp++ = c;
+		}
+	}
+	*cp = 0;
+	if (tokval[0] == 0)
+		return (0);
+	for (t = toktab; t->tokstr; t++)
+		if (!strcmp(t->tokstr, tokval))
+			return (t->tval);
+	return (ID);
+}
+
+int 
+ruserpass(host, aname, apass, aacct)
+	char *host, **aname, **apass, **aacct;
+{
+	char *hdir, buf[FTP_BUFSIZ], *tmp;
+	char myname[MAXHOSTNAMELEN + 1], *mydomain;
+	int t, i, c, usedefault = 0;
+	struct stat stb;
+
+	hdir = getenv("HOME");
+	if (hdir == NULL)
+		hdir = ".";
+	(void) sprintf(buf, "%s/.netrc", hdir);
+	cfile = fopen(buf, "r");
+	if (cfile == NULL) {
+		if (errno != ENOENT)
+			perror(buf);
+		return(0);
+	}
+	if (gethostname(myname, sizeof(myname)) < 0)
+		myname[0] = '\0';
+	if ((mydomain = strchr(myname, '.')) == NULL)
+		mydomain = "";
+next:
+	while ((t = token())) switch(t) {
+
+	case DEFAULT:
+		usedefault = 1;
+		/* FALL THROUGH */
+
+	case MACH:
+		if (!usedefault) {
+			if (token() != ID)
+				continue;
+			/*
+			 * Allow match either for user's input host name
+			 * or official hostname.  Also allow match of 
+			 * incompletely-specified host in local domain.
+			 */
+			if (strcasecmp(host, tokval) == 0)
+				goto match;
+			if (strcasecmp(hostname, tokval) == 0)
+				goto match;
+			if ((tmp = strchr(hostname, '.')) != NULL &&
+			    strcasecmp(tmp, mydomain) == 0 &&
+			    strncasecmp(hostname, tokval,
+					(unsigned) (tmp-hostname)) == 0 &&
+			    tokval[tmp - hostname] == '\0')
+				goto match;
+			if ((tmp = strchr(host, '.')) != NULL &&
+			    strcasecmp(tmp, mydomain) == 0 &&
+			    strncasecmp(host, tokval,
+					(unsigned ) (tmp - host)) == 0 &&
+			    tokval[tmp - host] == '\0')
+				goto match;
+			continue;
+		}
+	match:
+		while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
+
+		case LOGIN:
+			if (token()) {
+				if (*aname == 0) { 
+					*aname = malloc((unsigned) strlen(tokval) + 1);
+					(void) strcpy(*aname, tokval);
+				} else {
+					if (strcmp(*aname, tokval))
+						goto next;
+				}
+			}
+			break;
+		case PASSWD:
+			if (strcmp(*aname, "anonymous") &&
+			    fstat(fileno(cfile), &stb) >= 0 &&
+			    (stb.st_mode & 077) != 0) {
+	fprintf(stderr, "Error - .netrc file not correct mode.\n");
+	fprintf(stderr, "Remove password or correct mode.\n");
+				goto bad;
+			}
+			if (token() && *apass == 0) {
+				*apass = malloc((unsigned) strlen(tokval) + 1);
+				(void) strcpy(*apass, tokval);
+			}
+			break;
+		case ACCOUNT:
+			if (fstat(fileno(cfile), &stb) >= 0
+			    && (stb.st_mode & 077) != 0) {
+	fprintf(stderr, "Error - .netrc file not correct mode.\n");
+	fprintf(stderr, "Remove account or correct mode.\n");
+				goto bad;
+			}
+			if (token() && *aacct == 0) {
+				*aacct = malloc((unsigned) strlen(tokval) + 1);
+				(void) strcpy(*aacct, tokval);
+			}
+			break;
+		case MACDEF:
+			if (proxy) {
+				(void) fclose(cfile);
+				return(0);
+			}
+			while ((c = getc(cfile)) != EOF)
+				if (c != ' ' && c != '\t')
+					break;
+			if (c == EOF || c == '\n') {
+				printf("Missing macdef name argument.\n");
+				goto bad;
+			}
+			if (macnum == 16) {
+				printf("Limit of 16 macros have already been defined\n");
+				goto bad;
+			}
+			tmp = macros[macnum].mac_name;
+			*tmp++ = c;
+			for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
+			    !isspace(c); ++i) {
+				*tmp++ = c;
+			}
+			if (c == EOF) {
+				printf("Macro definition missing null line terminator.\n");
+				goto bad;
+			}
+			*tmp = '\0';
+			if (c != '\n') {
+				while ((c=getc(cfile)) != EOF && c != '\n');
+			}
+			if (c == EOF) {
+				printf("Macro definition missing null line terminator.\n");
+				goto bad;
+			}
+			if (macnum == 0) {
+				macros[macnum].mac_start = macbuf;
+			}
+			else {
+				macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
+			}
+			tmp = macros[macnum].mac_start;
+			while (tmp != macbuf + 4096) {
+				if ((c=getc(cfile)) == EOF) {
+				printf("Macro definition missing null line terminator.\n");
+					goto bad;
+				}
+				*tmp = c;
+				if (*tmp == '\n') {
+					if (*(tmp-1) == '\0') {
+					   macros[macnum++].mac_end = tmp - 1;
+					   break;
+					}
+					*tmp = '\0';
+				}
+				tmp++;
+			}
+			if (tmp == macbuf + 4096) {
+				printf("4K macro buffer exceeded\n");
+				goto bad;
+			}
+			break;
+		default:
+	fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
+			break;
+		}
+		goto done;
+	}
+done:
+	(void) fclose(cfile);
+	return(0);
+bad:
+	(void) fclose(cfile);
+	return(-1);
+}
diff --git a/mechglue/src/appl/gssftp/ftp/secure.c b/mechglue/src/appl/gssftp/ftp/secure.c
new file mode 100644
index 000000000..999641b77
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/secure.c
@@ -0,0 +1,481 @@
+/*
+ * Shared routines for client and server for
+ * secure read(), write(), getc(), and putc().
+ * Only one security context, thus only work on one fd at a time!
+ */
+#ifdef GSSAPI
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+extern gss_ctx_id_t gcontext;
+#endif /* GSSAPI */
+
+#include <secure.h>	/* stuff which is specific to client or server */
+
+#ifdef KRB5_KRB4_COMPAT
+#include <krb.h>
+
+CRED_DECL
+extern KTEXT_ST ticket;
+extern MSG_DAT msg_data;
+extern Key_schedule schedule;
+#endif /* KRB5_KRB4_COMPAT */
+
+#ifdef _WIN32
+#undef ERROR
+#endif
+
+#include <arpa/ftp.h>
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#ifdef _WIN32
+#include <port-sockets.h>
+#else
+#include <netinet/in.h>
+#endif
+#include <errno.h>
+
+#ifndef HAVE_STRERROR
+#define strerror(error) (sys_errlist[error])
+#ifdef NEED_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+#endif
+
+#if (SIZEOF_SHORT == 4)
+typedef unsigned short ftp_uint32;
+typedef short ftp_int32;
+#elif (SIZEOF_INT == 4)
+typedef unsigned int ftp_uint32;
+typedef int ftp_int32;
+#elif (SIZEOF_LONG == 4)
+typedef unsigned long ftp_uint32;
+typedef long ftp_int32;
+#endif
+
+static int secure_putbuf (int, unsigned char *, unsigned int);
+
+extern struct	sockaddr_in hisaddr;
+extern struct	sockaddr_in myaddr;
+extern int	dlevel;
+extern char	*auth_type;
+
+/* Some libc's (GNU libc, at least) define MAX as a macro. Forget that. */
+#ifdef MAX
+#undef MAX
+#endif
+
+#define MAX maxbuf
+extern unsigned int maxbuf; 	/* maximum output buffer size */
+extern unsigned char *ucbuf;	/* cleartext buffer */
+static unsigned int nout;	/* number of chars in ucbuf,
+				 * pointer into ucbuf */
+static unsigned int smaxbuf;    /* Internal saved value of maxbuf 
+				   in case changes on us */
+static unsigned int smaxqueue;  /* Maximum allowed to queue before 
+				   flush buffer. < smaxbuf by fudgefactor */
+
+#ifdef KRB5_KRB4_COMPAT
+#define KRB4_FUDGE_FACTOR 32	/* Amount of growth
+				 * from cleartext to ciphertext.
+				 * krb_mk_priv adds this # bytes.
+				 * Must be defined for each auth type.
+				 */
+#endif /* KRB5_KRB4_COMPAT */
+
+#ifdef KRB5_KRB4_COMPAT
+/* XXX - The following must be redefined if KERBEROS_V4 is not used
+ * but some other auth type is.  They must have the same properties. */
+#define looping_write krb_net_write
+#define looping_read krb_net_read
+#endif
+
+/* perhaps use these in general, certainly use them for GSSAPI */
+
+#ifndef looping_write
+static int
+looping_write(fd, buf, len)
+    int fd;
+    register const char *buf;
+    int len;
+{
+    int cc;
+    register int wrlen = len;
+    do {
+	cc = write(fd, buf, wrlen);
+	if (cc < 0) {
+	    if (errno == EINTR)
+		continue;
+	    return(cc);
+	}
+	else {
+	    buf += cc;
+	    wrlen -= cc;
+	}
+    } while (wrlen > 0);
+    return(len);
+}
+#endif
+#ifndef looping_read
+static int
+looping_read(fd, buf, len)
+    int fd;
+    register char *buf;
+    register int len;
+{
+    int cc, len2 = 0;
+
+    do {
+	cc = read(fd, buf, len);
+	if (cc < 0) {
+	    if (errno == EINTR)
+		continue;
+	    return(cc);		 /* errno is already set */
+	}		
+	else if (cc == 0) {
+	    return(len2);
+	} else {
+	    buf += cc;
+	    len2 += cc;
+	    len -= cc;
+	}
+    } while (len > 0);
+    return(len2);
+}
+#endif
+
+
+
+#define ERR	-2
+
+/* 
+ * Given maxbuf as a buffer size, determine how much can we
+ * really transfer given the overhead of different algorithms 
+ *
+ * Sets smaxbuf and smaxqueue
+ */
+
+static int secure_determine_constants()
+{
+    smaxbuf = maxbuf;
+    smaxqueue = maxbuf;
+
+#ifdef KRB5_KRB4_COMPAT
+    /* For KRB4 - we know the fudge factor to be 32 */
+    if (strcmp(auth_type, "KERBEROS_V4") == 0) {
+	smaxqueue = smaxbuf - KRB4_FUDGE_FACTOR;
+    }
+#endif
+#ifdef GSSAPI
+    if (strcmp(auth_type, "GSSAPI") == 0) {
+	OM_uint32 maj_stat, min_stat, mlen;
+	OM_uint32 msize = maxbuf;
+	maj_stat = gss_wrap_size_limit(&min_stat, gcontext, 
+				       (dlevel == PROT_P),
+				       GSS_C_QOP_DEFAULT,
+				       msize, &mlen);
+	if (maj_stat != GSS_S_COMPLETE) {
+			secure_gss_error(maj_stat, min_stat, 
+					 "GSSAPI fudge determination");
+			/* Return error how? */
+			return ERR;
+	}
+	smaxqueue = mlen;
+    }
+#endif
+    
+	return 0;
+}
+
+static int
+secure_putbyte(fd, c)
+int fd;
+unsigned char c;
+{
+	int ret;
+
+	if ((smaxbuf == 0) || (smaxqueue == 0) || (smaxbuf != maxbuf)) {
+	    ret = secure_determine_constants();
+	    if (ret) return ret;
+	}
+	ucbuf[nout++] = c;
+	if (nout == smaxqueue) {
+	  nout = 0;
+	  ret = secure_putbuf(fd, ucbuf, smaxqueue);
+	  return(ret?ret:c);
+	}
+	return (c);
+}
+
+/* returns:
+ *	 0  on success
+ *	-1  on error (errno set)
+ *	-2  on security error
+ */
+int secure_flush(fd)
+int fd;
+{
+	int ret;
+
+	if (dlevel == PROT_C)
+		return(0);
+	if (nout) {
+ 	        ret = secure_putbuf(fd, ucbuf, nout);
+		if (ret)
+			return(ret);
+	}
+	return(secure_putbuf(fd, (unsigned char *) "", nout = 0));
+}
+
+/* returns:
+ *	c>=0  on success
+ *	-1    on error
+ *	-2    on security error
+ */
+int secure_putc(c, stream)
+int c;
+FILE *stream;
+{
+	if (dlevel == PROT_C)
+		return(putc(c,stream));
+	return(secure_putbyte(fileno(stream), (unsigned char) c));
+}
+
+/* returns:
+ *	nbyte on success
+ *	-1  on error (errno set)
+ *	-2  on security error
+ */
+int 
+secure_write(fd, buf, nbyte)
+int fd;
+unsigned char *buf;
+unsigned int nbyte;
+{
+	unsigned int i;
+	int c;
+
+	if (dlevel == PROT_C)
+		return(write(fd,buf,nbyte));
+	for (i=0; nbyte>0; nbyte--)
+		if ((c = secure_putbyte(fd, buf[i++])) < 0)
+			return(c);
+	return(i);
+}
+
+/* returns:
+ *	 0  on success
+ *	-1  on error (errno set)
+ *	-2  on security error
+ */
+static int
+secure_putbuf(fd, buf, nbyte)
+  int fd;
+unsigned char *buf;
+unsigned int nbyte;
+{
+	static char *outbuf;		/* output ciphertext */
+	static unsigned int bufsize;	/* size of outbuf */
+	ftp_int32 length;
+	ftp_uint32 net_len;
+	unsigned int fudge = smaxbuf - smaxqueue; /* Difference in length
+						     buffer lengths required */
+
+	/* Other auth types go here ... */
+#ifdef KRB5_KRB4_COMPAT
+	if (bufsize < nbyte + fudge) {
+		if (outbuf?
+		    (outbuf = realloc(outbuf, (unsigned) (nbyte + fudge))):
+		    (outbuf = malloc((unsigned) (nbyte + fudge)))) {
+		    bufsize = nbyte + fudge;
+		} else {
+			bufsize = 0;
+			secure_error("%s (in malloc of PROT buffer)",
+				     strerror(errno));
+			return(ERR);
+		}
+	}
+
+	if (strcmp(auth_type, "KERBEROS_V4") == 0)
+	  if ((length = dlevel == PROT_P ?
+	    krb_mk_priv(buf, (unsigned char *) outbuf, nbyte, schedule,
+			SESSION, &myaddr, &hisaddr)
+	  : krb_mk_safe(buf, (unsigned char *) outbuf, nbyte, SESSION,
+			&myaddr, &hisaddr)) == -1) {
+		secure_error("krb_mk_%s failed for KERBEROS_V4",
+				dlevel == PROT_P ? "priv" : "safe");
+		return(ERR);
+	  }
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+	if (strcmp(auth_type, "GSSAPI") == 0) {
+		gss_buffer_desc in_buf, out_buf;
+		OM_uint32 maj_stat, min_stat;
+		int conf_state;
+		
+		in_buf.value = buf;
+		in_buf.length = nbyte;
+		maj_stat = gss_seal(&min_stat, gcontext,
+				    (dlevel == PROT_P), /* confidential */
+				    GSS_C_QOP_DEFAULT,
+				    &in_buf, &conf_state,
+				    &out_buf);
+		if (maj_stat != GSS_S_COMPLETE) {
+			/* generally need to deal */
+			/* ie. should loop, but for now just fail */
+			secure_gss_error(maj_stat, min_stat,
+					 dlevel == PROT_P?
+					 "GSSAPI seal failed":
+					 "GSSAPI sign failed");
+			return(ERR);
+		}
+
+		if (bufsize < out_buf.length) {
+			if (outbuf?
+			    (outbuf = realloc(outbuf, (unsigned) out_buf.length)):
+			    (outbuf = malloc((unsigned) out_buf.length))) {
+				bufsize = out_buf.length;
+			} else {
+				bufsize = 0;
+				secure_error("%s (in malloc of PROT buffer)",
+					     strerror(errno));
+				return(ERR);
+			}
+		}
+
+		length=out_buf.length;
+		memcpy(outbuf, out_buf.value, out_buf.length);
+		gss_release_buffer(&min_stat, &out_buf);
+	}
+#endif /* GSSAPI */
+	net_len = htonl((u_long) length);
+	if (looping_write(fd, (char *) &net_len, 4) == -1) return(-1);
+	if (looping_write(fd, outbuf, length) != length) return(-1);
+	return(0);
+}
+
+static int
+secure_getbyte(fd)
+int fd;
+{
+	/* number of chars in ucbuf, pointer into ucbuf */
+	static unsigned int nin, bufp;
+	int kerror;
+	ftp_uint32 length;
+
+	if (nin == 0) {
+		if ((kerror = looping_read(fd, (char *) &length,
+				sizeof(length)))
+				!= sizeof(length)) {
+			secure_error("Couldn't read PROT buffer length: %d/%s",
+				     kerror,
+				     kerror == -1 ? strerror(errno)
+				     : "premature EOF");
+			return(ERR);
+		}
+		if ((length = (u_long) ntohl(length)) > MAX) {
+			secure_error("Length (%d) of PROT buffer > PBSZ=%u", 
+				     length, MAX);
+			return(ERR);
+		}
+		if ((kerror = looping_read(fd, (char *) ucbuf, (int) length)) != length) {
+			secure_error("Couldn't read %u byte PROT buffer: %s",
+					length, kerror == -1 ?
+					strerror(errno) : "premature EOF");
+			return(ERR);
+		}
+		/* Other auth types go here ... */
+#ifdef KRB5_KRB4_COMPAT
+		if (strcmp(auth_type, "KERBEROS_V4") == 0) {
+		  if ((kerror = dlevel == PROT_P ?
+		    krb_rd_priv(ucbuf, length, schedule, SESSION,
+				&hisaddr, &myaddr, &msg_data)
+		  : krb_rd_safe(ucbuf, length, SESSION,
+				&hisaddr, &myaddr, &msg_data))) {
+			secure_error("krb_rd_%s failed for KERBEROS_V4 (%s)",
+					dlevel == PROT_P ? "priv" : "safe",
+					krb_get_err_text(kerror));
+			return(ERR);
+		  }
+		  memcpy(ucbuf, msg_data.app_data, msg_data.app_length);
+		  nin = bufp = msg_data.app_length;
+		}
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+		if (strcmp(auth_type, "GSSAPI") == 0) {
+		  gss_buffer_desc xmit_buf, msg_buf;
+		  OM_uint32 maj_stat, min_stat;
+		  int conf_state;
+
+		  xmit_buf.value = ucbuf;
+		  xmit_buf.length = length;
+		  conf_state = (dlevel == PROT_P);
+		  /* decrypt/verify the message */
+		  maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
+					&msg_buf, &conf_state, NULL);
+		  if (maj_stat != GSS_S_COMPLETE) {
+		    secure_gss_error(maj_stat, min_stat, 
+				     (dlevel == PROT_P)?
+				     "failed unsealing ENC message":
+				     "failed unsealing MIC message");
+		    return ERR;
+		  }
+
+		  memcpy(ucbuf, msg_buf.value, nin = bufp = msg_buf.length);
+		  gss_release_buffer(&min_stat, &msg_buf);
+	      }
+#endif /* GSSAPI */
+		/* Other auth types go here ... */
+	}
+	if (nin == 0)
+		return(EOF);
+	else	return(ucbuf[bufp - nin--]);
+}
+
+/* returns:
+ *	c>=0 on success
+ *	-1   on EOF
+ *	-2   on security error
+ */
+int secure_getc(stream)
+FILE *stream;
+{
+	if (dlevel == PROT_C)
+		return(getc(stream));
+	return(secure_getbyte(fileno(stream)));
+}
+
+/* returns:
+ *	n>0 on success (n == # of bytes read)
+ *	0   on EOF
+ *	-1  on error (errno set), only for PROT_C
+ *	-2  on security error
+ */
+int secure_read(fd, buf, nbyte)
+int fd;
+char *buf;
+unsigned int nbyte;
+{
+	static int c;
+	int i;
+
+	if (dlevel == PROT_C)
+		return(read(fd,buf,nbyte));
+	if (c == EOF)
+		return(c = 0);
+	for (i=0; nbyte>0; nbyte--)
+		switch (c = secure_getbyte(fd)) {
+			case ERR: return(c);
+			case EOF: if (!i) c = 0;
+				  return(i);
+			default:  buf[i++] = c;
+		}
+	return(i);
+}
diff --git a/mechglue/src/appl/gssftp/ftp/secure.h b/mechglue/src/appl/gssftp/ftp/secure.h
new file mode 100644
index 000000000..5d1bd0bdb
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftp/secure.h
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+#define CRED_DECL	extern CREDENTIALS cred;
+#define SESSION		&cred.session
+#define myaddr		data_addr
+#define hisaddr		hisdataaddr
+
+int secure_flush (int);
+int secure_putc (int, FILE *);
+int secure_getc (FILE *);
+int secure_write (int, unsigned char *, unsigned int);
+int secure_read (int, char *, unsigned int);
+void secure_gss_error (OM_uint32 maj_stat, OM_uint32 min_stat, char *s);
+
+void secure_error(char *, ...);
diff --git a/mechglue/src/appl/gssftp/ftpd/.Sanitize b/mechglue/src/appl/gssftp/ftpd/.Sanitize
new file mode 100644
index 000000000..63e80a0df
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/.Sanitize
@@ -0,0 +1,45 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+CHANGES
+ChangeLog
+Makefile.in
+configure.in
+configure
+ftpcmd.y
+ftpd.M
+ftpd.c
+logwtmp.c
+pathnames.h
+popen.c
+secure.h
+vers.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/gssftp/ftpd/CHANGES b/mechglue/src/appl/gssftp/ftpd/CHANGES
new file mode 100644
index 000000000..39c7ebda0
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/CHANGES
@@ -0,0 +1,31 @@
+This version of ftpd has been fixed to conform to RFC959.
+
+Unfortunately, this conformance introduces a user visible change.  While
+technically, this is the fault of the client (ftp) instead of the server
+(ftpd), the change will be seen whenever an old ftp client calls a new ftpd
+server.
+
+The problem is that the old ftpd implemented the NLST command by execing
+/bin/ls.  This produced non-conformant output in some cases.  The new
+ftpd no longer executes /bin/ls for the NLST command as it has it's own
+built-in code.
+
+The user visible change in the ftp behavior is caused by the ftp client
+"knowing" that the daemon will exec /bin/ls.  This assumption should not
+have been made.
+
+When the old ftp client is used, one of the options is the "ls" command
+which sends the command NLST to the ftpd server.  The client should really
+be sending the LIST command.  The new ftp client has been corrected to do
+this.
+
+NLST should not normally be used directly by humans.  It is intended to
+interface with commands like mget or mput.
+
+Users who are not able to upgrade their ftp client may obtain the previous
+behavior, by using the command "dir" instead of "ls".
+
+These changes only apply to those sites using code derived from the Berkeley
+software releases (which means almost every UNIX based implementation will
+see this problem).
+
diff --git a/mechglue/src/appl/gssftp/ftpd/ChangeLog b/mechglue/src/appl/gssftp/ftpd/ChangeLog
new file mode 100644
index 000000000..281776833
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/ChangeLog
@@ -0,0 +1,920 @@
+2005-01-13  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpd.c: GCC 4.0 fixes... Move static declaration of gunique out
+	of function.
+
+2004-11-26  Sam Hartman  <hartmans@mit.edu>
+
+	* ftpcmd.y: nbby should be 8 for anything platform we care about.
+	The previous test broke on Debian BSD, so the test has been
+	removed. 
+
+2004-11-03  Tom Yu  <tlyu@mit.edu>
+
+	* ftpcmd.y (getline): Merge Athena change to reject MICed
+	password.
+
+	* ftpd.M: Document '-E'.
+
+	* ftpd.c (main): Merge Athena's '-E' changes to prohibit
+	unencrypted passwords.
+
+2004-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (ftpd): Use UTIL_LIB.
+
+2004-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c (ftpd_gss_convert_creds): Terminate argument list to
+	krb5_build_principal_ext with 0, not NULL.  Patch from Nalin
+	Dahyabhai.
+
+2004-08-27  Sam Hartman  <hartmans@mit.edu>
+
+	* ftpd.c (passwd;): Patch from Garry Zacheiss to use
+	krb5_get_init_creds_password instead of krb5_get_in_tkt since
+	get_in_tkt is obselete 
+
+2004-08-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c (main): Use socklen_t for the size of the address from
+	accept.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpcmd.y (getline): Allow "AUTH" as an unprotected command.
+	* ftpd.c (login): Fix checks for accept_sec_context status.  Only
+	send back one message in the CONTINUE_NEEDED case.
+	(with_gss_error_text): New function, split out from
+	reply_gss_error.
+	(reply_gss_error): Call it.
+	(reply_gss_error_1): New function.
+	(log_gss_error, log_gss_error_1): New functions.
+	(login): Call log_gss_error instead of syslog on error from
+	gss_display_name.
+
+2003-06-05  Sam Hartman  <hartmans@mit.edu>
+
+	* popen.c (ftpd_popen): Use fork not vfork
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c: Don't declare errno.
+
+2003-01-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c (auth_data): Kerberos v4 checksum must be a 32-bit
+	value.
+
+2002-10-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* ftpcmd.y: Bison 1.75 cleanup. Essentially remove `=' before
+	statements to be executed. (ticket 1218).
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* ftpd.c (auth_data, reply_gss_code): Use OM_uint32 instead of int
+	to match arguments to gssapi functions.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c: Include port-sockets.h.
+
+2002-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (ftpd): Don't use krb5util library.
+
+2002-04-11  Sam Hartman  <hartmans@mit.edu>
+
+	* ftpd.c (adata;): Don't use channel bindings in call to gss_accept
+
+2002-03-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Remove dependency on krb524.h and krb524_err.h as
+	they may not be present if compiling --without-krb4.
+
+2002-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpcmd.y (unix): Define if BSD is defined.
+
+2002-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c (login): New argument LOGINCODE, optional result code to
+	override local use of success code 230 when homedir is not
+	accessible but root directory is.
+	(user): Pass result code 232 to login.
+	(pass): Pass result code 0 to login.
+
+2001-11-30  Tom Yu  <tlyu@mit.edu>
+
+	* ftpcmd.y (pathname): Handle returns from ftpglob() better so
+	that errors get sent via reply(), while causing some match
+	failures to match to simply return $1, so the higher level can
+	deal.  Previously, some failures would cause synch problems since
+	NULL would be returned and no reply was sent.
+
+2001-10-11  Mitchell Berger  <mitchb@mit.edu>
+
+	* ftpd.M: Remove improper formatting from the .SH NAME section, as it
+	was reported to cause windex generation problems and was inconsistent
+	with all the other man pages.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd_var.h, secure.h: Make prototypes unconditional.
+
+2001-08-03  Mitchell Berger  <mitchb@mit.edu>
+
+	* ftpd.M: Update the usage line and option descriptions to be in sync
+	with what the code actually does and be in a consistent order.
+
+2001-08-03  Mitchell Berger  <mitchb@mit.edu>
+
+	* ftpd.c (main): Convert to do option parsing with getopt() rather
+	than the whitespace-sensitive voodoo we've used in the past.  This
+	fixes a bug where use of -u to set a default umask silently failed and
+	granted more permission on files than desired if the -u and the mode
+	were separated by a space, and likely many other such bugs.
+
+2001-07-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpd.c: Provide prototypes for myoob and lostconn. 
+
+2001-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpd.c (sgetpwnam): Remove local declaration of sgetsave.
+
+2001-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* popen.c: Include ftpd_var.h.
+
+	* ftpd.c: Declare secure_fprintf, gunique, sgetsave, sgetpwnam,
+	path_expand static.
+
+	* ftpd_var.h: Add prototypes for getline, renamefrom, ftpd_popen,
+	ftpd_pclose.
+
+	* ftpcmd.y: Declare lookup, copy and urgsafe_getc static.
+
+2001-06-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpcmd.y (help): Change local variable type to ftype.
+
+	* ftpd.c (main): Local variable name changes to prevent shadowing
+	of cp, sin, optarg.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpd.c: If NEED_SETENV defined, prototype for setenv.
+	(auth_data): radix_encode expects a int * and not a size_t *. Use
+	temporary variable to pass data in and out.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpd.c: Include gssapi/gssapi_krb5.h for gss_krb5_copy_ccache
+	prototype. Provide prototype for yyparse.
+
+2001-06-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpcmd.y: Cleanup potential ambiguity between comparsion and
+	pre-increment for a variable.
+
+2001-06-15  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpcmd.y, ftpd.c: Cast argument to isspace()/isdigit() to int.
+
+	* secure.h (SESSION): Pass pointer to C_Block as expected by
+	krb5_mk_priv().
+
+2001-06-08  Mitchell Berger  <mitchb@mit.edu>
+
+	* pathnames.h: _PATH_FTPUSERS renamed to _PATH_FTPUSERS_DEFAULT.
+
+	* ftpd.c: Added '-U filename' option to allow specification of
+	an ftpusers file other than the default.
+
+	* ftpd.M: Documented the new -U option.
+
+2001-06-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpcmd.y: Include "ftpd_var.h" and remove prototype for reply()
+	and lreply(). Add prototypes and declare as returning void
+	sizecmd(), help() and yylex(). Cleanup assignments in
+	conditionals.
+
+	* ftpd.c: Include <grp.h> for initgroups() prototype. Move
+	reply(), lreply() prototypes to ftpd_var.h (and include
+	same). Include "krb524.h" for krb524_convert_creds_kdc()
+	prototype. Include secure.h. Provide static prototypes for
+	ftpd_gss_convert_creds(), ftpd_gss_userok(), dolog(),
+	receive_data(), login(), end_login(), disallowed_user(),
+	restricted_user(), checkuser(). Declare main(), checkuser(),
+	disallowed_user(), restricted_user(), end_login(), kpass(),
+	retreive_data(), auth_data(), secure_printf(), ftpd_gss_userok(),
+	as returning int. Declare setdlevel(), user(), pass(), login(),
+	retreive(), store_file(), secure_error(), statfilecmd(),
+	stat_cmd(), fatal(), reply(), lreply(), ack(), nack(), yyerror(),
+	delete_file(), cwd(), makedir(), removedir(), pwd(), renamecmd(),
+	dolog(), dologout(), passive(), perror_reply(), auth(),
+	send_file_list(), reply_gss_error(), secure_gss_error(),
+	ftpd_gss_convert_creds(), as returning void. Cleanup printf
+	argument mismatches.
+
+	* ftpd_var.h: New header file with many prototypes from ftpd.c.
+
+	* popen.c (ftpd_popen): Add parenthesis in conditional to
+	distinguish || vs &&. Add prototype for blkfree(). 
+	(ftpd_pclose): Declare as returning int.
+
+2001-04-25  Tom Yu  <tlyu@mit.edu>
+
+	* ftpcmd.y: Don't dereference a NULL pointer returned from
+	ftpglob().
+
+	* ftpd.c: Be more paranoid about return values from ftpglob().
+	Police uses of sprintf().  Account for expansion in
+	radix_encode().
+
+2001-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c (strerror): Only define if not HAVE_STRERROR.
+
+2000-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c (dolog): Cast first argument to pty_make_sane_hostname to
+	sockaddr pointer.
+
+2000-10-16  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpd.c (reply): For gssapi connection, do not include NULL in
+	sealed reply string.
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* ftpd.c (login): Return of krb5_cc_get_name is now const char *.
+
+2000-08-25  Tom Yu  <tlyu@mit.edu>
+
+	* ftpcmd.y: Fix up grammar so that single character token names
+	are no longer used; this was breaking the build using bison on
+	HP/UX because some system headers declare structures with members
+	having all-uppercase field names and bison puts the token name
+	#define statements in front of the C declarations section in the
+	output, causing them to be in force while those headers get
+	#included.  There doesn't seem to be much purpose in not just
+	using character constants, anyway.
+
+Tue Aug 22 11:37:35 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* secure.h (myaddr): For secure data stream, pass the port number
+ 	of the data stream and not the control stream to krb_mk_priv.
+
+	* ftpd.c (auth_data): Iterate over all krb4 services instead of
+ 	trying to examine the srvtab file for a particular key (which
+ 	failes when falling back on the v5 keytab for des3 services).
+
+2000-06-14  Tom Yu  <tlyu@mit.edu>
+
+	* ftpcmd.y (nonguest): Return $1, not 1, if (!guest).
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* ftpd.c (gunique): Make sure that path stored in "new" isn't too long.
+
+2000-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c (reply, lreply): Declare with format attribute under
+	gcc.
+	(send_data, receive_data, send_file_list): Declare some variables
+	volatile to protect against getting clobbered by setjmp/longjmp.
+	* popen.c (ftpd_popen): Declare IOP volatile.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* ftpd.c (checkuser): Only call fclose on file handle if it's not
+	NULL.
+	(send_file_list): Don't declare strpbrk function if it's defined
+	as a macro.
+
+Thu Mar 25 23:13:56 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c (login): Check that the luid is not the uid we want to
+	change to prior to calling setluid() so that we can run as
+	non-root.
+
+Wed Mar 24 17:11:32 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ftpcmd.y (urgsafe_getc): New function; like getc() except it
+	retries once if SIOCATMARK returns TRUE.
+	(getline): Use urgsafe_getc() rather than getc() to avoid problems
+	with certain Mac clients that cause the urgent pointer to end up
+	in a location that results in EOF from getc().
+
+Fri Mar 12 07:35:01 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c (user): Remove extra "%s" in call to sprintf() to avoid
+	dereferencing stack garbage.
+
+Mon Mar  8 23:47:51 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.M: Resync with reality.
+
+	* Makefile.in (ftpd): Add libpty to link line.  Remove mention of
+	logwtmp files.
+
+	* ftpd.c: Fix up hostname logging to use
+	pty_make_sane_hostname().
+
+Thu Feb 25 23:31:37 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c (reply): Don't call secure_gss_error() or secure_error()
+	from within reply() to avoid setting up an infinite
+	loop. [krb5-appl/684]
+
+Thu Feb 18 18:34:23 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c (login): Add call to setluid() if necessary.
+
+Fri Feb 12 21:11:18 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c: strcat -> strncat
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Mon Oct 26 13:46:47 1998  Dan Winship  <danw@mit.edu>
+
+	* ftpd.c (main): Add -A (require authentication, but not
+	necessarily authorization) and -C (user wants local credentials).
+
+	(user): Implement -A. Reorganize code a bit. If want_creds (-C) is
+	set, require a password even if authorization succeeds.
+
+	(kpass): Add krb5 ticket-getting code too. If want_creds is set,
+ 	don't destroy the tickets after verifying the Kerberos password.
+
+	(pass): Check krb password before local password, so we can
+	get credentials if we need them. Ignore local password if
+	want_creds is set. In case of "too many failed login attempts",
+	exit via dologout() instead of exit() so on-disk credentials are
+	destroyed.
+
+	(auth_data): If user forwards GSSAPI creds and want_creds is set,
+	write them out to a krb5 ccache. If doing krb4 compat, convert
+	them to krb4 tickets as well. (If want_creds is not set, smile and
+	nod at the user and then destroy the creds.)
+
+	(end_login): If the user has creds on disk, destroy them.
+	(dologout): If the user has creds on disk, destroy them.
+
+	* ftpd.M: Add -A and -C.
+	
+Fri Oct 23 18:18:52 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ftpd.c (pass): Wait 5 seconds before returning "password
+		incorrect", and only allow three bad passwords.  Then
+		return an 421 reply code before closing the connection and
+		going away.
+
+	* ftpcmd.y (cmd): Don't allow the PORT command to accept a port
+		number lower than 1024; this prevents some nasty ftp
+		"bounce attacks" to SMTP ports, etc.
+
+Tue Oct 20 16:29:46 1998  Dan Winship  <danw@mit.edu>
+
+	* ftpd.M: Reality check. Add -a to synopsis, document -c and -u
+	and CCC.
+
+1998-10-08  Geoffrey King  <gjking@mit.edu>
+
+	* ftpd.c: Add support for restricted users, as requested in
+	[krb5-appl/481].  Users that appear in /etc/ftpusers, followed
+	by the keyword "restrict" will be granted access, but a chroot()
+	will be done to their home directory.
+
+Tue Sep 29 19:25:09 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ftpd.c (auth_data): Don't use h_errno, it's not fully portable,
+		and it's not worth it.
+
+1998-08-28  Geoffrey King  <gjking@mit.edu>
+
+	* ftpd.c (login): New function.  Essentially, the old pass
+	function has been split into its two logical components, pass and
+	login.  Don't reply 230 "User logged in" if the user didn't
+	send a PASS command; this causes the client to get a bit confused.
+	(pass): If auth_ok is true, reply with code 202 to tell the
+	user that a PASS command is not necessary. 
+	(auth_ok): New function that returns true if either gss_ok or
+	kerb_ok is true (all the #ifdefs were beginning to clutter things,
+	and it's a good abstraction in case other auth types are ever
+	added in the future).
+	(user): If GSSAPI or Kerberos v4 authentication succeeds, call
+	login immediately, instead of waiting for the client to send "PASS
+	dummy."  Also, use #ifdef PARANOID instead of "some paranoid sites
+	may wish to uncomment this"
+
+Wed Aug 19 06:47:46 1998  Geoffrey King  <gjking@mit.edu>
+
+	* ftpd.c: Add a new command line option, -c, which tells the
+	server to accept the CCC command.
+
+	* ftpcmd.y: If the -c option was given, check to make sure the CCC
+	command itself was integrity protected, and then set ccc_ok to
+	allow future commands to be transmitted as cleartext.
+	(getline): Now that CCC is potentially allowed, we must check to
+	see if we are parsing an unprotected command even if a security
+	context is established (i.e. auth_type is set).
+
+Wed Aug 12 02:57:07 1998  Geoffrey King  <gjking@mit.edu>
+
+	* ftpcmd.y, ftpd.c: Replace global variable level with clevel and
+ 	dlevel to allow independence of command and data channel
+ 	protection levels.
+
+Tue Aug 11 04:30:59 1998  Matthew D Hancher  <mdh@mit.edu>
+
+	* ftpd.c: Add support for extended logging as per PR#481. Using 
+	the 'l' command line option twice now logs the major file commands, 
+	and using it thrice logs bytecounts for RETR and STOR as well.
+
+Fri Aug  7 00:56:30 1998  Matthew D Hancher  <mdh@mit.edu>
+
+	* ftpcmd.y: Replace old KERBEROS #ifdef's with KRB5_KRB4_COMPAT
+	so that K4 compatibility support actually gets compiled in.
+	
+	* ftpd.c: (pass): Make daemon not lose for homedirs on 
+	root-squashing filesystems.
+	(auth_data): Fix that godawful "error: No error" message 
+	when gss_acquire_cred() fails.
+	(user): Fix getusershell() code so it works more than once.
+
+1998-07-11    <hartmans@fundsxpress.com>
+
+	* ftpd.c (data;): do not declare h_errno; breaks on AIX and
+	possibly with other multithreaded systems.
+
+1998-05-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* logwtmp.c: Include paths.h if present, and use _PATH_WTMP to
+		determine WTMPFILE.
+
+Fri May  8 18:06:52 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ftpcmd.y (cmd): Fix Y2K problem in the MDTM command.
+
+Fri Apr 10 20:06:31 1998  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c (receive_data):
+	(send_data): Add support for sigsetjmp().
+	(main): Use sigaction() if we can to avoid SysV lossage.
+	(send_file_list): Oops missed a sigsetjmp() call.
+	(send_data): Add call to secure_flush() to send a zero length
+	buffer when aborting.
+	(send_file_list): Add call to secure_flush() to send a zero length
+	buffer when aborting.
+
+	* ftpcmd.y (PBSZ): Remove restriction on shrinking buffer size.
+
+Thu Mar  5 13:59:47 1998  Dan Winship  <danw@mit.edu>
+
+	* ftpcmd.y (getline): Don't syslog passwords! (or newlines)
+
+Tue Feb 24 21:34:34 1998  Tom Yu  <tlyu@mit.edu>
+
+	* ftpcmd.y: Add production "nonguest" to catch things that
+	anonymous users aren't supposed to do.  Replace "check_login" with
+	"nonguest" in a few places to prevent w4r3z d00dz from being
+	lame with world-writable incoming directories.
+
+Sun Feb 22 19:37:07 1998  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c: Use krb5_seteuid() and krb5_setegid(). [krb5-libs/505]
+
+	* Makefile.in (ftpd): Fix up KRB4COMPAT_LIBS (was KRB5_BASE_LIBS),
+	and add UTIL_LIB.
+
+Wed Feb 18 15:30:10 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 22:23:34 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ftpd.c: Applied lxs's changes to make ftpd safe for systems
+		where sizeof(off_t) > sizeof(int).
+
+Fri Feb 13 15:31:46 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (thisconfigdir), configure.in: Point the
+ 		configuration directory at our parent, and remove our
+		local configure.in
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Feb  6 13:25:28 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* popen.c (ftpd_popen): Make sure you can't overrun the argv[] and
+		gargv[] arrays.  (Patch submitted by dima@best.net).
+
+Thu Jan 29 19:51:02 1998  Dan Winship  <danw@mit.edu>
+
+	* ftpd.c (auth_data): Accept forwarded credentials and dispose of
+	them properly. (And fix some indentation bugs.)
+
+Sun Dec 21 18:17:53 1997  Tom Yu  <tlyu@mit.edu>
+
+	* logwtmp.c (ftp_logwtmp): Rename logwtmp to ftp_logwtmp to avoid
+	collision with native logwtmp.  Also, return void rather than
+	int.
+
+	* ftpd.c: Rename logwtmp to ftp_logwtmp to avoid collision with
+	native logwtmp.
+
+Thu Dec 11 23:28:07 1997  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c: Don't include netdb.h or sys/socket.h if krb.h is
+	included; this works around an Ultrix bug where those headers
+	aren't protected against multiple inclusion.
+
+Thu Oct 16 01:23:41 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Change LOCALINCLUDE and the link line to allow for
+	krb4 compatibility.
+
+	* ftpd.c: Change KERBEROS to KRB5_KRB4_COMPAT where appropriate.
+	(reply): Fix up braces around the check for auth_type ==
+	"KERBEROS_V4" so that the nesting of if statements is correct.
+	Various and sundry fixes from danw@mit.edu to make it work.
+
+Thu Aug 28 23:48:27 1997  Sam Hartman  <hartmans@luminous.mesas.com>
+
+	* ftpd.c (send_file_list): Flush the data before closing it.
+
+Sun Aug 17 14:24:09 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(srcdir) where needed.
+
+Wed Jul 16 19:03:18 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ftpd.M: Fix name of srvtab file to be krb5.keytab.
+
+Wed Feb  5 20:34:38 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Tue Nov 12 00:04:00 1996  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.c (ftpd_userok): Don't undconditionally return -1.
+
+Thu Nov  7 15:38:51 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ftpd.c (ftpd_userok): Check return value of krb5_init_context()
+
+Thu Oct 17 23:55:32 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c (auth_data): actually exit the for loop if the ftp key
+	was ok.
+
+Mon Oct 14 07:54:17 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ftpd.c (secure_fprintf): Use STDARG routines if
+		present. [krb5-appl/108]
+
+Tue Sep 10 14:07:36 1996  Tom Yu  <tlyu@mit.edu>
+
+	* ftpd.M: remove ".so man1/header.doc"
+
+Mon Jul 29 22:37:05 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Determine sizeof short, int, long for secure.c
+
+Tue Jul 23 23:13:07 1996  Marc Horowitz  <marc@mit.edu>
+
+	* ftpd.c (auth_data): the logic which dealt with multiple acceptor
+ 	names and fallback was just broken.
+
+Wed Jul 10 16:38:01 1996  Marc Horowitz  <marc@mit.edu>
+
+	* ftpd.c (store), ftpcmd.y (STOR, APPE, STOU): rename store() to
+ 	store_file() to avoid conflict with dbm store() function
+	* ftpd.c (delete), ftpcmd.y (DELE): rename delete() to
+ 	delete_file() to avoid conflict with the dbm delete() function
+
+Thu Jun 13 18:35:19 1996  Kevin L Mitchell  <klmitch@mit.edu>
+
+	* ftpd.c (authdata): misplaced braces caused server to not be able to
+		use ftp principle if it was present.  Client looks for ftp
+		first, then tries host; ftpd was looking only for host.
+
+Mon Jun  3 16:12:59 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in, configure.in: back out previous changes and use
+		Ezra's patches instead.
+
+Sun Jun  2 22:08:17 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in, Makefile.in: only link getdtablesize.o if needed
+
+Thu Mar 28 21:07:20 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* ftpcmd.y: Define unix for HP-UX.
+
+Mon Mar 18 12:12:20 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add AC_HEADER_STDARG
+
+	* ftpcmd.y, ftpd.c: Declard STDARG if HAVE_STDARG_H is
+		declared. 
+
+Fri Mar 15 14:16:41 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ftpd.c (auth_data): Do not fail if last gss_service is not
+		present in keytab. If no services present, return a useful
+		minor error status.
+
+Fri Mar 15 01:24:39 1996  Richard Basch  <basch@lehman.com>
+
+        * configure.in, ftpd.c: Added shadow password support.
+
+Wed Mar 13 20:05:52 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c (auth_data): use gethostbyname to canonicalize local host
+	name, just like krb5_sname_to_principal does.
+
+Fri Feb 16 15:51:59 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpcmd.y (yylex): error handling changes from kbalk@hp.com.
+
+Tue Jan 16 18:44:42 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c (user): 331 is more appropriate for kuserok failure.
+
+Wed Feb  7 13:33:41 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean): Remove ftpd
+
+Thu Jan 18 18:39:06 1996  Sam Hartman  <hartmans@zygorthian-space-raiders.MIT.EDU>
+
+	* configure.in: Check for crypt in -lcrypt
+
+	* ftpd.c: Conditionalize sys_errlist
+
+	* configure.in: Check to declare sys_errlist.
+
+Thu Jan 18 14:55:42 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* ftpd.c : Only return an unable to acquire credentials error if all possible services fail.
+
+Sun Jan 14 02:58:42 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c (auth_data): call gss_release_cred on the server_creds we
+	acquired, before they leave scope.
+
+Sun Jan 14 02:47:19 1996  Karri Balk - Contractor <kbalk@cup.hp.com>
+
+	* ftpd.c (gss_services): list of gssapi service names to try.
+	(auth_data): loop over gss_services.
+
+Sun Jan 14 01:54:35 1996  Bill Schoofs <wjs@cray.com>
+
+	* Makefile.in (DEFINES): define NOCONFIDENTIAL for future use.
+	* ftpcmd.y (CCC): ditch broken CCC code, return proper 534 code.
+	(PBSZ): return proper code 501 for bad PBSZ argument
+	(PROT): recognize PROT E.
+	(cmdtab): add CCC so as to cleanly reject it.
+	(getline): reject CONF as unsupported (but put in code to
+	potentially recognize it in the future.) Reject protected commands
+	of auth_type isn't yet set.
+	* ftpd.c (setlevel): use 536, not 504, for invalid level, and
+	use levelnames to find the proper name.
+	(user): if kuserok succeeds, respond 232, not 231; if it fails,
+	respond 336 (though 331 might be more appropriate.)
+	(auth): fix spelling error.
+	
+Tue Jan  2 19:19:16 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c: use HAVE_SETEUID and HAVE_SETRESUID to figure out how
+	to emulate seteuid instead of assuming hpux.
+	* configure.in: test for seteuid, setreuid and setresuid.
+
+Fri Oct 20 17:17:19 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c (auth_data): supply correct channel bindings to accept,
+	matching the client changes.
+
+Thu Oct 19 12:22:28 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* configure.in: check WITH_DBM_LNAME since we use an_to_ln.
+
+Wed Oct  4 19:26:50 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c (user): use HAVE_GETUSERSHELL.
+	* configure.in: check for getusershell.
+
+Mon Oct  2 16:43:54 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* popen.c (ftpd_popen): malloc all strings, not just globbed ones.
+
+Sun Oct  1 03:31:24 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c (auth_data): acquire credentials (currently fixed for
+	service "host".) Fix loop reply logic. Add debugging syslogs. Set
+	auth_type *after* 235 success reply, so it doesn't get encrypted.
+
+Sun Oct  1 00:58:39 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in: use FTP_BUFSIZ everywhere and make it large for
+	now.
+	* configure.in: check for headers need to build getdtablesize.
+	* ftpd.c (secure_reply): add GSSAPI hooks.
+	(reply_gss_error): better gssapi error reporting.
+	
+
+Sat Sep 30 22:26:25 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c: correct gssapi includes. Fix type of client_name. Use
+	gss_ok instead of kerb_ok for GSSAPI case (to simplify future
+	combined code.) Fix some declarations. Fix arguments to
+	gss_accept_sec_context for type.
+	* ftpcmd.y: correct gssapi includes.
+	
+Sat Sep 30 21:40:30 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in: hook setenv.c and getdtablesize.c from appl/bsd.
+	Use double-colon rules for clean, depend, install.
+	configure.in: check for yacc, SIGTYPE, UTMP, SIGPROCMASK,
+	WAIT_TYPE, getdtablesize, getcwd, setenv (using the test from
+	appl/bsd.)
+	* ftpcmd.y: no conf.h. declare level. Use krb5_sigtype directly.
+	* ftpd.c: use getcwd directly, make -s srvtab KERBEROS specific.
+	(user): return 331 as per draft-8, but suggest 53z.
+	(auth_data): return 535 and 335 and quote draft-8 as to why.
+	(secure_gss_error): generic interface for secure.c functions to
+	call reply_gss_error instead.
+	* logwtmp.c: no conf.h, check NO_UT_HOST.
+	* popen.c: no conf.h, no getdtablesize.
+	(ftpd_pclose): Obey USE_SIGPROCMASK.
+
+Sat Sep 30 16:43:28 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in, Makefile.in: new files for port to GSSAPI and
+	build within the Kerberos V5 build tree.
+	* ftpcmd.y, ftpd.c, secure.c: GSSAPI authentication changes based
+	on the IETF CAT working group ***DRAFT*** FTP Security
+	specification, draft number 8, appendix I.
+
+
+**** previous change logs from CNS V4 modifications of Steve Lunt's
+     draft-3 ftp daemon, which this is based on. ****
+
+Wed Jul 26 21:03:13 1995  Ken Raeburn  <raeburn@cygnus.com>
+
+	* secure.c: Include string.h.
+
+	* ftpd.c (main): Cast signal() return value to long instead of
+	int; it's more likely to fit.
+
+Thu Feb  2 13:41:24 1995  Ian Lance Taylor  <ian@cygnus.com>
+
+	* ftpcmd.y (NBBY): Explicitly define if __pyrsoft and MIPSEB.
+	(cmd_list): In handling of SYST, undefine BSD if __svr4__ is
+	defined.
+
+	* ftpd.c: Don't try to use IP_TOS if the IP_TOS argument
+	(IPTOS_LOWDELAY, etc.) is not defined.
+
+Wed Jan 18 17:12:22 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* ftpd.8: Include man1/tmac.doc.
+
+Wed Jan 11 15:29:10 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* ftpd.c (authenticate): New variable.
+	(main): Handle -a (require authentication) option.
+	(user): If authenticate is set, reply with an error if kuserok
+	fails or if no Kerberos authentication was used.
+	* ftpcmd.y: Use check_login when parsing the PASV command.
+	* ftpd.8: Document new -a option.
+
+Tue Jan  3 01:25:57 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (clean): explicitly delete ftpcmd.c on clean.
+
+Thu Dec 29 15:17:12 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpcmd.y (rcmd): don't declare atol, since it isn't used here
+	anyhow, and it's a macro under linux.
+	(top level): #define NBBY 8 for linux.
+
+Thu Dec 29 14:51:41 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* ftpd.c (statcmd): don't use NBBY check -- linux doesn't have it,
+	it is in no spec, and if it isn't 8, it won't work anyway. (Use
+	strcat instead of sprintf, while we're at it...)
+
+Tue Dec 27 16:29:24 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* ftpcmd.y (reply, lreply): Declare if STDARG || (__STDC__ && !
+	VARARGS).
+	* ftpd.c:  If STDARG is defined, or if __STDC__ is defined and
+	VARARGS is not defined, include <stdarg.h>.
+	(secure_error): Use <stdarg.h> routines if STDARG || (__STDC__ &&
+	! VARARGS).
+	(reply, lreply): Likewise.
+	(setproctitle): Just use one argument.
+	* secure.c (secure_error): Declare if STDARG || (__STDC__ && !
+	VARARGS).
+
+Fri Dec 23 16:25:44 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* ftpcmd.y (unix): Define if _AIX is defined (AIX compiler does
+	not predefine unix).
+
+Thu Dec 22 15:05:14 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* ftpd.c (keyfile): New global variable.
+	(main): Move option processing before check of remote socket.  Add
+	new options -p, -r, and -s.  Handle -p by accepting a remote
+	connection.
+	(kpass): Use keyfile variable rather than KEYFILE.  Pass keyfile
+	explicitly to krb_rd_req.
+	(auth_data): Likewise.
+	* ftpd.8: Document new -p, -r, and -s options.
+
+Fri Dec 16 11:06:16 1994  Ian Lance Taylor  <ian@cygnus.com>
+
+	Fixes for HP/UX:
+	* ftpd.c: On HP/UX, define seteuid and setegid as macros which
+	call setresuid and setresgid.
+
+	Fixes for UnixWare:
+	* ftpd.c (main): Use a temporary variable rather than calling
+	htons(ntohs(X)).
+	* ftpcmd.y: Include conf.h.
+	(getline): Cast arguments to Kerberos routines to avoid warnings.
+	(toolong): Declare as type sigtype, and add dummy argument.
+
+	Fixes for SCO:
+	* cmdtab.y: Include <sys/types.h>.
+	* ftpd.c (initgroups): Define on SCO.
+	(main): Don't handle SIGURG if it is not defined.
+	(pass): Don't try to use crypt on SCO; instead, require Kerberos
+	password or anonymous login.
+
+	Fixes for AIX:
+	* ftpcmd.y (index): Don't define.
+	(strpbrk, strcpy): Don't declare.
+	* ftpd.c (index, rindex): Don't define.
+	* logwtmp.c (strncpy): Don't declare.
+	* secure.c: Include <netinet/in.h>.
+
+	Fixes for Ultrix:
+	* ftpd.c (main): Define LOG_NDELAY and LOG_DAEMON as zero if they
+	are not already defined by <syslog.h>.
+
+	Fixes for Irix 4:
+	* ftpd.c (retrieve): Don't refer to st_blksize if NOSTBLKSIZE is
+	defined.
+
+	* ftpcmd.y: Fix yacc code to use %union and %type.
+	(yylex): Assign to fields of yylval, rather than to yylval
+	directly.
+
+	General fixes to make it compile on Solaris: Use sigtype for
+	signal handler return values, including conf.h where needed.  Add
+	a dummy argument to signal handler functions. Replace index,
+	rindex, bzero and bcopy with ANSI C functions.  Cast Kerberos
+	routine arguments to avoid warnings.  Also:
+	* ftpd.c: Don't include <varargs.h>.  If POSIX is defined, include
+	unistd.h, otherwise define getcwd to call getwd.
+	(L_SET, L_INCR): Define if not defined.
+	(pwd): Use getcwd instead of getwd.  If POSIX, change the error
+	handling accordingly.
+	* popen.c (getdtablesize): New function on hpux or __svr4__.
+	(ftpd_pclose): If WAIT_USES_INT, use int instead of union wait.
+
+Thu Dec 15 16:13:44 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* Initial checkin.  Based on Steve Lunt's ftp program, which was
+        based on BSD code.
diff --git a/mechglue/src/appl/gssftp/ftpd/Makefile.in b/mechglue/src/appl/gssftp/ftpd/Makefile.in
new file mode 100644
index 000000000..46bbf5ca1
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/Makefile.in
@@ -0,0 +1,107 @@
+thisconfigdir=./..
+myfulldir=appl/gssftp/ftpd
+mydir=ftpd
+BUILDTOP=$(REL)..$(S)..$(S)..
+#
+# appl/gssftp/ftpd/Makefile.in
+#
+DEFINES = -DGSSAPI -DFTP_BUFSIZ=10240 #-DNOCONFIDENTIAL
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+SETENVSRC=@SETENVSRC@
+SETENVOBJ=@SETENVOBJ@
+LIBOBJS=@LIBOBJS@
+COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
+FTPD_LIBS=@FTPD_LIBS@
+
+SRCS	= $(srcdir)/ftpd.c ftpcmd.c $(srcdir)/popen.c \
+	  $(srcdir)/vers.c \
+	  $(srcdir)/../ftp/glob.c \
+	  $(srcdir)/../ftp/radix.c \
+	  $(srcdir)/../ftp/secure.c \
+	  $(srcdir)/../../bsd/getdtablesize.c $(SETENVSRC)
+
+OBJS	= ftpd.o ftpcmd.o glob.o popen.o vers.o radix.o \
+	  secure.o $(LIBOBJS) $(SETENVOBJ)
+
+LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir) @KRB4_INCLUDES@
+
+all::	ftpd
+
+ftpd:	$(OBJS) $(PTY_DEPLIB) $(GSS_DEPLIBS) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o $@ $(OBJS) $(FTPD_LIBS) $(PTY_LIB) $(UTIL_LIB) $(GSS_LIBS) $(KRB4COMPAT_LIBS)
+
+clean::
+	$(RM) ftpd ftpcmd.c
+
+depend::
+
+install::
+	for f in ftpd; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(SERVER_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		${DESTDIR}$(SERVER_MANDIR)/`echo $$f|sed '$(transform)'`.8; \
+	done
+
+
+ftpcmd.c: $(srcdir)/ftpcmd.y
+	$(RM) ftpcmd.c y.tab.c
+	$(YACC) $(srcdir)/ftpcmd.y
+	$(MV) y.tab.c ftpcmd.c
+
+glob.o: $(srcdir)/../ftp/glob.c
+	$(CC) -c $(ALL_CFLAGS) $(srcdir)/../ftp/glob.c
+radix.o: $(srcdir)/../ftp/radix.c
+	$(CC) -c $(ALL_CFLAGS) $(srcdir)/../ftp/radix.c
+secure.o: $(srcdir)/../ftp/secure.c
+	$(CC) -c $(ALL_CFLAGS) $(srcdir)/../ftp/secure.c
+
+getdtablesize.o: $(srcdir)/../../bsd/getdtablesize.c
+	$(CC) -c $(ALL_CFLAGS) $(srcdir)/../../bsd/getdtablesize.c
+
+setenv.o: $(srcdir)/../../bsd/setenv.c
+	$(CC) -c $(ALL_CFLAGS) $(srcdir)/../../bsd/setenv.c
+
+
+ftpd.o: $(srcdir)/pathnames.h
+secure.o: $(srcdir)/secure.h
+
+ftpd.o: $(srcdir)/ftpd.c
+ftpcmd.o: ftpcmd.c
+popen.o: $(srcdir)/popen.c
+vers.o: $(srcdir)/vers.c
+
+# NOPOSTFIX
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)ftpd.$(OBJEXT): ftpd.c $(srcdir)/../arpa/ftp.h \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/syslog.h \
+  pathnames.h $(BUILDTOP)/include/libpty.h $(SRCTOP)/include/k5-util.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssapi/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+  ftpd_var.h secure.h
+$(OUTPRE)ftpcmd.$(OBJEXT): ftpcmd.c $(srcdir)/../arpa/ftp.h \
+  $(SRCTOP)/include/syslog.h ftpd_var.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssapi/gssapi_generic.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(srcdir)/../arpa/telnet.h
+$(OUTPRE)popen.$(OBJEXT): popen.c ftpd_var.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssapi/gssapi_generic.h
+$(OUTPRE)vers.$(OBJEXT): vers.c
+$(OUTPRE)glob.$(OBJEXT): $(srcdir)/../ftp/glob.c $(srcdir)/../ftp/ftp_var.h
+$(OUTPRE)radix.$(OBJEXT): $(srcdir)/../ftp/radix.c \
+  $(srcdir)/../ftp/ftp_var.h
+$(OUTPRE)secure.$(OBJEXT): $(srcdir)/../ftp/secure.c \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  secure.h $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(srcdir)/../arpa/ftp.h
+$(OUTPRE)getdtablesize.$(OBJEXT): $(srcdir)/../../bsd/getdtablesize.c
diff --git a/mechglue/src/appl/gssftp/ftpd/ftpcmd.y b/mechglue/src/appl/gssftp/ftpd/ftpcmd.y
new file mode 100644
index 000000000..096014bd2
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/ftpcmd.y
@@ -0,0 +1,1557 @@
+/* -*- fundamental -*-
+ * Copyright (c) 1985, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ftpcmd.y	5.24 (Berkeley) 2/25/91
+ */
+
+/*
+ * Grammar for FTP commands.
+ * See RFC 959.
+ * See Also draft-ietf-cat-ftpsec-08.txt.
+ */
+
+%{
+
+#ifndef lint
+static char sccsid[] = "@(#)ftpcmd.y	5.24 (Berkeley) 2/25/91";
+#endif /* not lint */
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/ftp.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <syslog.h>
+#include <time.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ftpd_var.h"
+
+extern	char *auth_type;
+
+unsigned int maxbuf, actualbuf;
+unsigned char *ucbuf;
+
+static int kerror;	/* XXX needed for all auth types */
+#ifdef KRB5_KRB4_COMPAT
+extern	struct sockaddr_in his_addr, ctrl_addr;
+#include <krb.h>
+extern AUTH_DAT kdata;
+extern Key_schedule schedule;
+extern MSG_DAT msg_data;
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+extern gss_ctx_id_t gcontext;
+#endif
+
+#ifndef unix
+/* sigh */
+#if defined(_AIX) || defined(__hpux) || defined(BSD)
+#define unix
+#endif
+#endif
+
+#ifndef NBBY
+#define NBBY 8
+#endif
+
+static struct sockaddr_in host_port;
+
+extern	struct sockaddr_in data_dest;
+extern	int logged_in;
+extern	struct passwd *pw;
+extern	int guest;
+extern	int logging;
+extern	int type;
+extern	int form;
+extern	int clevel;
+extern	int debug;
+
+
+extern	int allow_ccc;
+extern	int ccc_ok;
+extern	int timeout;
+extern	int maxtimeout;
+extern  int pdata;
+extern	int authlevel;
+extern	char hostname[], remotehost[];
+extern	char proctitle[];
+extern	char *globerr;
+extern	int usedefault;
+extern  int transflag;
+extern  char tmpline[];
+
+char	**ftpglob();
+
+off_t	restart_point;
+
+static	int cmd_type;
+static	int cmd_form;
+static	int cmd_bytesz;
+char	cbuf[FTP_BUFSIZ]; /* was 512 */
+char	*fromname;
+
+/* bison needs these decls up front */
+extern jmp_buf errcatch;
+
+#define	CMD	0	/* beginning of command */
+#define	ARGS	1	/* expect miscellaneous arguments */
+#define	STR1	2	/* expect SP followed by STRING */
+#define	STR2	3	/* expect STRING */
+#define	OSTR	4	/* optional SP then STRING */
+#define	ZSTR1	5	/* SP then optional STRING */
+#define	ZSTR2	6	/* optional STRING after SP */
+#define	SITECMD	7	/* SITE command */
+#define	NSTR	8	/* Number followed by a string */
+
+struct tab {
+	char	*name;
+	short	token;
+	short	state;
+	short	implemented;	/* 1 if command is implemented */
+	char	*help;
+};
+struct tab cmdtab[];
+struct tab sitetab[];
+
+void sizecmd(char *);
+void help(struct tab *, char *);
+static int yylex(void);
+static char *copy(char *);
+%}
+
+%union { int num; char *str; }
+
+%token
+	SP	CRLF	COMMA	STRING	NUMBER
+
+	USER	PASS	ACCT	REIN	QUIT	PORT
+	PASV	TYPE	STRU	MODE	RETR	STOR
+	APPE	MLFL	MAIL	MSND	MSOM	MSAM
+	MRSQ	MRCP	ALLO	REST	RNFR	RNTO
+	ABOR	DELE	CWD	LIST	NLST	SITE
+	STAT	HELP	NOOP	MKD	RMD	PWD
+	CDUP	STOU	SMNT	SYST	SIZE	MDTM
+	AUTH	ADAT	PROT    PBSZ
+	CCC
+
+	UMASK	IDLE	CHMOD
+
+	LEXERR
+
+%type <num> NUMBER
+%type <num> form_code prot_code struct_code mode_code octal_number
+%type <num> check_login byte_size nonguest
+
+%type <str> STRING
+%type <str> password pathname username pathstring
+
+%start	cmd_list
+
+%%
+
+cmd_list:	/* empty */
+	|	cmd_list cmd
+		{
+			fromname = (char *) 0;
+			restart_point = (off_t) 0;
+		}
+	|	cmd_list rcmd
+	;
+
+cmd:		USER SP username CRLF
+		{
+			user((char *) $3);
+			free((char *) $3);
+		}
+	|	PASS SP password CRLF
+		{
+			pass((char *) $3);
+			free((char *) $3);
+		}
+	|	PORT SP host_port CRLF
+		{
+			/*
+			 * Don't allow a port < 1024 if we're not
+			 * connecting back to the original source address
+			 * This prevents nastier forms of the bounce attack.
+			 */
+			if (ntohs(host_port.sin_port) < 1024)
+				reply(504, "Port number too low");
+			else {
+				data_dest = host_port;
+				usedefault = 0;
+				if (pdata >= 0) {
+					(void) close(pdata);
+					pdata = -1;
+				}
+				reply(200, "PORT command successful.");
+			}
+		}
+	|	PASV check_login CRLF
+		{
+			if ($2)
+				passive();
+		}
+	|	PROT SP prot_code CRLF
+		{
+		    if (maxbuf)
+			setdlevel ($3);
+		    else
+			reply(503, "Must first set PBSZ");
+		}
+	|	CCC CRLF
+		{
+			if (!allow_ccc) {
+			    reply(534, "CCC not supported");
+			}
+			else {
+			    if(clevel == PROT_C && !ccc_ok) {
+			        reply(533, "CCC command must be integrity protected");
+			    } else {
+			        reply(200, "CCC command successful.");
+				ccc_ok = 1;
+			    }
+			}
+		}
+	|	PBSZ SP STRING CRLF
+		{
+			/* Others may want to do something more fancy here */
+			if (!auth_type)
+			    reply(503, "Must first perform authentication");
+			else if (strlen($3) > 10 ||
+				 (strlen($3) == 10 && 
+				  strcmp($3,"4294967296") >= 0))
+			    reply(501, "Bad value for PBSZ: %s", $3);
+			else {
+			    if (ucbuf) (void) free(ucbuf);
+			    actualbuf = (unsigned int) atol($3);
+			    /* I attempt what is asked for first, and if that
+			       fails, I try dividing by 4 */
+			    while ((ucbuf = (unsigned char *)malloc(actualbuf)) == NULL)
+				if (actualbuf)
+				    lreply(200, "Trying %u", actualbuf >>= 2);
+				else {
+				    perror_reply(421,
+					"Local resource failure: malloc");
+				    dologout(1);
+				}
+			    reply(200, "PBSZ=%u", maxbuf = actualbuf);
+			}
+		}
+	|	TYPE SP type_code CRLF
+		{
+			switch (cmd_type) {
+
+			case TYPE_A:
+				if (cmd_form == FORM_N) {
+					reply(200, "Type set to A.");
+					type = cmd_type;
+					form = cmd_form;
+				} else
+					reply(504, "Form must be N.");
+				break;
+
+			case TYPE_E:
+				reply(504, "Type E not implemented.");
+				break;
+
+			case TYPE_I:
+				reply(200, "Type set to I.");
+				type = cmd_type;
+				break;
+
+			case TYPE_L:
+#if NBBY == 8
+				if (cmd_bytesz == 8) {
+					reply(200,
+					    "Type set to L (byte size 8).");
+					type = cmd_type;
+				} else
+					reply(504, "Byte size must be 8.");
+#else /* NBBY == 8 */
+				UNIMPLEMENTED for NBBY != 8
+#endif /* NBBY == 8 */
+			}
+		}
+	|	STRU SP struct_code CRLF
+		{
+			switch ($3) {
+
+			case STRU_F:
+				reply(200, "STRU F ok.");
+				break;
+
+			default:
+				reply(504, "Unimplemented STRU type.");
+			}
+		}
+	|	MODE SP mode_code CRLF
+		{
+			switch ($3) {
+
+			case MODE_S:
+				reply(200, "MODE S ok.");
+				break;
+
+			default:
+				reply(502, "Unimplemented MODE type.");
+			}
+		}
+	|	ALLO SP NUMBER CRLF
+		{
+			reply(202, "ALLO command ignored.");
+		}
+	|	ALLO SP NUMBER SP 'R' SP NUMBER CRLF
+		{
+			reply(202, "ALLO command ignored.");
+		}
+	|	RETR check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				retrieve((char *) 0, (char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	STOR check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				store_file((char *) $4, "w", 0);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	APPE check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				store_file((char *) $4, "a", 0);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	NLST check_login CRLF
+		{
+			if ($2)
+				send_file_list(".");
+		}
+	|	NLST check_login SP STRING CRLF
+		{
+			if ($2 && $4 != NULL) 
+				send_file_list((char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	LIST check_login CRLF
+		{
+			if ($2)
+				retrieve("/bin/ls -lgA", "");
+		}
+	|	LIST check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				retrieve("/bin/ls -lgA %s", (char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	STAT check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				statfilecmd((char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	STAT CRLF
+		{
+			statcmd();
+		}
+	|	DELE check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				delete_file((char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	RNTO SP pathname CRLF
+		{
+			if (fromname) {
+				renamecmd(fromname, (char *) $3);
+				free(fromname);
+				fromname = (char *) 0;
+			} else {
+				reply(503, "Bad sequence of commands.");
+			}
+			free((char *) $3);
+		}
+	|	ABOR CRLF
+		{
+			reply(225, "ABOR command successful.");
+		}
+	|	CWD check_login CRLF
+		{
+			if ($2)
+				cwd(pw->pw_dir);
+		}
+	|	CWD check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				cwd((char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	HELP CRLF
+		{
+			help(cmdtab, (char *) 0);
+		}
+	|	HELP SP STRING CRLF
+		{
+			register char *cp = (char *)$3;
+
+			if (strncasecmp(cp, "SITE", 4) == 0) {
+				cp = (char *)$3 + 4;
+				if (*cp == ' ')
+					cp++;
+				if (*cp)
+					help(sitetab, cp);
+				else
+					help(sitetab, (char *) 0);
+			} else
+				help(cmdtab, (char *) $3);
+		}
+	|	NOOP CRLF
+		{
+			reply(200, "NOOP command successful.");
+		}
+	|	MKD nonguest SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				makedir((char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	RMD nonguest SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				removedir((char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	PWD check_login CRLF
+		{
+			if ($2)
+				pwd();
+		}
+	|	CDUP check_login CRLF
+		{
+			if ($2)
+				cwd("..");
+		}
+	|	SITE SP HELP CRLF
+		{
+			help(sitetab, (char *) 0);
+		}
+	|	SITE SP HELP SP STRING CRLF
+		{
+			help(sitetab, (char *) $5);
+		}
+	|	SITE SP UMASK check_login CRLF
+		{
+			int oldmask;
+
+			if ($4) {
+				oldmask = umask(0);
+				(void) umask(oldmask);
+				reply(200, "Current UMASK is %03o", oldmask);
+			}
+		}
+	|	SITE SP UMASK nonguest SP octal_number CRLF
+		{
+			int oldmask;
+
+			if ($4) {
+				if (($6 == -1) || ($6 > 0777)) {
+					reply(501, "Bad UMASK value");
+				} else {
+					oldmask = umask($6);
+					reply(200,
+					    "UMASK set to %03o (was %03o)",
+					    $6, oldmask);
+				}
+			}
+		}
+	|	SITE SP CHMOD nonguest SP octal_number SP pathname CRLF
+		{
+			if ($4 && ($8 != NULL)) {
+				if ($6 > 0777)
+					reply(501,
+				"CHMOD: Mode value must be between 0 and 0777");
+				else if (chmod((char *) $8, $6) < 0)
+					perror_reply(550, (char *) $8);
+				else
+					reply(200, "CHMOD command successful.");
+			}
+			if ($8 != NULL)
+				free((char *) $8);
+		}
+	|	SITE SP IDLE CRLF
+		{
+			reply(200,
+			    "Current IDLE time limit is %d seconds; max %d",
+				timeout, maxtimeout);
+		}
+	|	SITE SP IDLE SP NUMBER CRLF
+		{
+			if ($5 < 30 || $5 > maxtimeout) {
+				reply(501,
+			"Maximum IDLE time must be between 30 and %d seconds",
+				    maxtimeout);
+			} else {
+				timeout = $5;
+				(void) alarm((unsigned) timeout);
+				reply(200,
+				    "Maximum IDLE time set to %d seconds",
+				    timeout);
+			}
+		}
+	|	STOU check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				store_file((char *) $4, "w", 1);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	SYST CRLF
+		{
+#ifdef unix
+#ifdef __svr4__
+#undef BSD
+#endif
+#ifdef BSD
+			reply(215, "UNIX Type: L%d Version: BSD-%d",
+				NBBY, BSD);
+#else /* BSD */
+			reply(215, "UNIX Type: L%d", NBBY);
+#endif /* BSD */
+#else /* unix */
+			reply(215, "UNKNOWN Type: L%d", NBBY);
+#endif /* unix */
+		}
+
+		/*
+		 * SIZE is not in RFC959, but Postel has blessed it and
+		 * it will be in the updated RFC.
+		 *
+		 * Return size of file in a format suitable for
+		 * using with RESTART (we just count bytes).
+		 */
+	|	SIZE check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL)
+				sizecmd((char *) $4);
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+
+		/*
+		 * MDTM is not in RFC959, but Postel has blessed it and
+		 * it will be in the updated RFC.
+		 *
+		 * Return modification time of file as an ISO 3307
+		 * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
+		 * where xxx is the fractional second (of any precision,
+		 * not necessarily 3 digits)
+		 */
+	|	MDTM check_login SP pathname CRLF
+		{
+			if ($2 && $4 != NULL) {
+				struct stat stbuf;
+				if (stat($4, &stbuf) < 0)
+					perror_reply(550, $4);
+				else if ((stbuf.st_mode&S_IFMT) != S_IFREG) {
+					reply(550, "%s: not a plain file.",
+						(char *) $4);
+				} else {
+					register struct tm *t;
+					struct tm *gmtime();
+					t = gmtime(&stbuf.st_mtime);
+					reply(213,
+					    "%4d%02d%02d%02d%02d%02d",
+					    1900+t->tm_year, t->tm_mon+1, 
+					    t->tm_mday, t->tm_hour, 
+					    t->tm_min, t->tm_sec);
+				}
+			}
+			if ($4 != NULL)
+				free((char *) $4);
+		}
+	|	AUTH SP STRING CRLF
+		{
+			auth((char *) $3);
+		}
+	|	ADAT SP STRING CRLF
+		{
+			auth_data((char *) $3);
+			free((char *) $3);
+		}
+	|	QUIT CRLF
+		{
+			reply(221, "Goodbye.");
+			dologout(0);
+		}
+	|	error CRLF
+		{
+			yyerrok;
+		}
+	;
+rcmd:		RNFR check_login SP pathname CRLF
+		{
+			restart_point = (off_t) 0;
+			if ($2 && $4) {
+				fromname = renamefrom((char *) $4);
+				if (fromname == (char *) 0 && $4) {
+					free((char *) $4);
+				}
+			}
+		}
+	|	REST SP byte_size CRLF
+		{
+			fromname = (char *) 0;
+			restart_point = $3;
+			reply(350, "Restarting at %ld. %s", 
+			      (long) restart_point,
+			      "Send STORE or RETRIEVE to initiate transfer.");
+		}
+	;
+		
+username:	STRING
+	;
+
+password:	/* empty */
+		{
+			*(char **)&($$) = (char *)calloc(1, sizeof(char));
+		}
+	|	STRING
+	;
+
+byte_size:	NUMBER
+	;
+
+host_port:	NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 
+		NUMBER COMMA NUMBER
+		{
+			register char *a, *p;
+
+			a = (char *)&host_port.sin_addr;
+			a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7;
+			p = (char *)&host_port.sin_port;
+			p[0] = $9; p[1] = $11;
+			host_port.sin_family = AF_INET;
+		}
+	;
+
+form_code:	'N'
+	{
+		$$ = FORM_N;
+	}
+	|	'T'
+	{
+		$$ = FORM_T;
+	}
+	|	'C'
+	{
+		$$ = FORM_C;
+	}
+	;
+
+prot_code:	'C'
+	{
+		$$ = PROT_C;
+	}
+	|	'S'
+	{
+		$$ = PROT_S;
+	}
+	|	'P'
+	{
+		$$ = PROT_P;
+	}
+	|	'E'
+	{
+		$$ = PROT_E;
+	}
+	;
+
+type_code:	'A'
+	{
+		cmd_type = TYPE_A;
+		cmd_form = FORM_N;
+	}
+	|	'A' SP form_code
+	{
+		cmd_type = TYPE_A;
+		cmd_form = $3;
+	}
+	|	'E'
+	{
+		cmd_type = TYPE_E;
+		cmd_form = FORM_N;
+	}
+	|	'E' SP form_code
+	{
+		cmd_type = TYPE_E;
+		cmd_form = $3;
+	}
+	|	'I'
+	{
+		cmd_type = TYPE_I;
+	}
+	|	'L'
+	{
+		cmd_type = TYPE_L;
+		cmd_bytesz = NBBY;
+	}
+	|	'L' SP byte_size
+	{
+		cmd_type = TYPE_L;
+		cmd_bytesz = $3;
+	}
+	/* this is for a bug in the BBN ftp */
+	|	'L' byte_size
+	{
+		cmd_type = TYPE_L;
+		cmd_bytesz = $2;
+	}
+	;
+
+struct_code:	'F'
+	{
+		$$ = STRU_F;
+	}
+	|	'R'
+	{
+		$$ = STRU_R;
+	}
+	|	'P'
+	{
+		$$ = STRU_P;
+	}
+	;
+
+mode_code:	'S'
+	{
+		$$ = MODE_S;
+	}
+	|	'B'
+	{
+		$$ = MODE_B;
+	}
+	|	'C'
+	{
+		$$ = MODE_C;
+	}
+	;
+
+pathname:	pathstring
+	{
+		/*
+		 * Problem: this production is used for all pathname
+		 * processing, but only gives a 550 error reply.
+		 * This is a valid reply in some cases but not in others.
+		 */
+		if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) {
+			char **vv;
+
+			vv = ftpglob((char *) $1);
+			$$ = (vv != NULL) ? *vv : NULL;
+			if ($$ == NULL) {
+				if (globerr == NULL)
+					$$ = $1;
+				else {
+					reply(550, "%s", globerr);
+					free((char *) $1);
+				}
+			} else
+				free((char *) $1);
+		} else
+			$$ = $1;
+	}
+	;
+
+pathstring:	STRING
+	;
+
+octal_number:	NUMBER
+	{
+		register int ret, dec, multby, digit;
+
+		/*
+		 * Convert a number that was read as decimal number
+		 * to what it would be if it had been read as octal.
+		 */
+		dec = $1;
+		multby = 1;
+		ret = 0;
+		while (dec) {
+			digit = dec%10;
+			if (digit > 7) {
+				ret = -1;
+				break;
+			}
+			ret += digit * multby;
+			multby *= 8;
+			dec /= 10;
+		}
+		$$ = ret;
+	}
+	;
+
+check_login:	/* empty */
+	{
+		if (logged_in)
+			$$ = 1;
+		else {
+			reply(530, "Please login with USER and PASS.");
+			$$ = 0;
+		}
+	}
+	;
+
+nonguest: check_login
+	{
+		if (guest) {
+			reply(550, "Operation prohibited for anonymous users.");
+			$$ = 0;
+		}
+		else
+			$$ = $1;
+	}
+	;
+%%
+
+struct tab cmdtab[] = {		/* In order defined in RFC 765 */
+	{ "USER", USER, STR1, 1,	"<sp> username" },
+	{ "PASS", PASS, ZSTR1, 1,	"<sp> password" },
+	{ "ACCT", ACCT, STR1, 0,	"(specify account)" },
+	{ "SMNT", SMNT, ARGS, 0,	"(structure mount)" },
+	{ "REIN", REIN, ARGS, 0,	"(reinitialize server state)" },
+	{ "QUIT", QUIT, ARGS, 1,	"(terminate service)", },
+	{ "PORT", PORT, ARGS, 1,	"<sp> b0, b1, b2, b3, b4" },
+	{ "PASV", PASV, ARGS, 1,	"(set server in passive mode)" },
+	{ "TYPE", TYPE, ARGS, 1,	"<sp> [ A | E | I | L ]" },
+	{ "STRU", STRU, ARGS, 1,	"(specify file structure)" },
+	{ "MODE", MODE, ARGS, 1,	"(specify transfer mode)" },
+	{ "RETR", RETR, STR1, 1,	"<sp> file-name" },
+	{ "STOR", STOR, STR1, 1,	"<sp> file-name" },
+	{ "APPE", APPE, STR1, 1,	"<sp> file-name" },
+	{ "MLFL", MLFL, OSTR, 0,	"(mail file)" },
+	{ "MAIL", MAIL, OSTR, 0,	"(mail to user)" },
+	{ "MSND", MSND, OSTR, 0,	"(mail send to terminal)" },
+	{ "MSOM", MSOM, OSTR, 0,	"(mail send to terminal or mailbox)" },
+	{ "MSAM", MSAM, OSTR, 0,	"(mail send to terminal and mailbox)" },
+	{ "MRSQ", MRSQ, OSTR, 0,	"(mail recipient scheme question)" },
+	{ "MRCP", MRCP, STR1, 0,	"(mail recipient)" },
+	{ "ALLO", ALLO, ARGS, 1,	"allocate storage (vacuously)" },
+	{ "REST", REST, ARGS, 1,	"(restart command)" },
+	{ "RNFR", RNFR, STR1, 1,	"<sp> file-name" },
+	{ "RNTO", RNTO, STR1, 1,	"<sp> file-name" },
+	{ "ABOR", ABOR, ARGS, 1,	"(abort operation)" },
+	{ "DELE", DELE, STR1, 1,	"<sp> file-name" },
+	{ "CWD",  CWD,  OSTR, 1,	"[ <sp> directory-name ]" },
+	{ "XCWD", CWD,	OSTR, 1,	"[ <sp> directory-name ]" },
+	{ "LIST", LIST, OSTR, 1,	"[ <sp> path-name ]" },
+	{ "NLST", NLST, OSTR, 1,	"[ <sp> path-name ]" },
+	{ "SITE", SITE, SITECMD, 1,	"site-cmd [ <sp> arguments ]" },
+	{ "SYST", SYST, ARGS, 1,	"(get type of operating system)" },
+	{ "STAT", STAT, OSTR, 1,	"[ <sp> path-name ]" },
+	{ "HELP", HELP, OSTR, 1,	"[ <sp> <string> ]" },
+	{ "NOOP", NOOP, ARGS, 1,	"" },
+	{ "MKD",  MKD,  STR1, 1,	"<sp> path-name" },
+	{ "XMKD", MKD,  STR1, 1,	"<sp> path-name" },
+	{ "RMD",  RMD,  STR1, 1,	"<sp> path-name" },
+	{ "XRMD", RMD,  STR1, 1,	"<sp> path-name" },
+	{ "PWD",  PWD,  ARGS, 1,	"(return current directory)" },
+	{ "XPWD", PWD,  ARGS, 1,	"(return current directory)" },
+	{ "CDUP", CDUP, ARGS, 1,	"(change to parent directory)" },
+	{ "XCUP", CDUP, ARGS, 1,	"(change to parent directory)" },
+	{ "STOU", STOU, STR1, 1,	"<sp> file-name" },
+	{ "AUTH", AUTH, STR1, 1,	"<sp> auth-type" },
+	{ "ADAT", ADAT, STR1, 1,	"<sp> auth-data" },
+	{ "PROT", PROT, ARGS, 1,	"<sp> protection-level" },
+	{ "PBSZ", PBSZ, STR1, 1,	"<sp> buffer-size" },
+	{ "CCC",  CCC,  ARGS, 1,	"(clear command channel)" },
+	{ "SIZE", SIZE, OSTR, 1,	"<sp> path-name" },
+	{ "MDTM", MDTM, OSTR, 1,	"<sp> path-name" },
+	{ NULL,   0,    0,    0,	0 }
+};
+
+struct tab sitetab[] = {
+	{ "UMASK", UMASK, ARGS, 1,	"[ <sp> umask ]" },
+	{ "IDLE", IDLE, ARGS, 1,	"[ <sp> maximum-idle-time ]" },
+	{ "CHMOD", CHMOD, NSTR, 1,	"<sp> mode <sp> file-name" },
+	{ "HELP", HELP, OSTR, 1,	"[ <sp> <string> ]" },
+	{ NULL,   0,    0,    0,	0 }
+};
+
+static struct tab *
+lookup(p, cmd)
+	register struct tab *p;
+	char *cmd;
+{
+
+	for (; p->name != NULL; p++)
+		if (strcmp(cmd, p->name) == 0)
+			return (p);
+	return (0);
+}
+
+/*
+ * urgsafe_getc - hacked up getc to ignore EOF if SIOCATMARK returns TRUE
+ */
+static int
+urgsafe_getc(f)
+	FILE *f;
+{
+	register int c;
+	int atmark;
+
+	c = getc(f);
+	if (c == EOF) {
+		if (ioctl(fileno(f), SIOCATMARK, &atmark) != -1) {
+			c = getc(f);
+			syslog(LOG_DEBUG, "atmark: c=%d", c);
+		}
+	}
+	return c;
+}
+
+#include <arpa/telnet.h>
+
+/*
+ * getline - a hacked up version of fgets to ignore TELNET escape codes.
+ */
+char *
+getline(s, n, iop)
+	char *s;
+	int n;
+	register FILE *iop;
+{
+	register int c;
+	register char *cs;
+
+	cs = s;
+/* tmpline may contain saved command from urgent mode interruption */
+	for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) {
+		*cs++ = tmpline[c];
+		if (tmpline[c] == '\n') {
+			*cs++ = '\0';
+			if (debug)
+				syslog(LOG_DEBUG, "command: %s", s);
+			tmpline[0] = '\0';
+			return(s);
+		}
+		if (c == 0)
+			tmpline[0] = '\0';
+	}
+	while ((c = urgsafe_getc(iop)) != EOF) {
+		c &= 0377;
+		if (c == IAC) {
+			if (debug) syslog(LOG_DEBUG, "got IAC");
+		    if ((c = urgsafe_getc(iop)) != EOF) {
+			c &= 0377;
+			if (debug) syslog(LOG_DEBUG, "got IAC %d", c);
+			switch (c) {
+			case WILL:
+			case WONT:
+				c = urgsafe_getc(iop);
+				printf("%c%c%c", IAC, DONT, 0377&c);
+				(void) fflush(stdout);
+				continue;
+			case DO:
+			case DONT:
+				c = urgsafe_getc(iop);
+				printf("%c%c%c", IAC, WONT, 0377&c);
+				(void) fflush(stdout);
+				continue;
+			case IAC:
+				break;
+			default:
+				continue;	/* ignore command */
+			}
+		    }
+		}
+		*cs++ = c;
+		if (--n <= 0 || c == '\n')
+			break;
+	}
+	if (c == EOF && cs == s)
+		return (NULL);
+	*cs++ = '\0';
+	if (auth_type) {
+	    char out[sizeof(cbuf)], *cp;
+	    int len, mic;
+
+
+	    /* Check to see if we have a protected command. */
+	    if (!((mic = strncmp(s, "ENC", 3)) && strncmp(s, "MIC", 3)
+		&& strncmp(s, "AUTH", 4)
+#ifndef NOCONFIDENTIAL
+	        && strncmp(s, "CONF", 4)
+#endif
+	        ) && (cs = strpbrk(s, " \r\n"))) {
+	    	    *cs++ = '\0'; /* If so, split it into s and cs. */
+	    } else { /* If not, check if unprotected commands are allowed. */
+		if(ccc_ok) {
+		    clevel = PROT_C;
+		    upper(s);
+		    return(s);
+		} else {
+		    reply(533, "All commands must be protected.");
+		    syslog(LOG_ERR, "Unprotected command received");
+		    *s = '\0';
+		    return(s);
+		}
+	    }
+	    upper(s);
+	    if (debug)
+	        syslog(LOG_INFO, "command %s received (mic=%d)", s, mic);
+#ifdef NOCONFIDENTIAL
+	    if (!strcmp(s, "CONF")) {
+		reply(537, "CONF protected commands not supported.");
+		*s = '\0';
+		return(s);
+	    }
+#endif
+/* Some paranoid sites may want to require that commands be encrypted. */
+#ifdef PARANOID
+	    if (mic) {
+		reply(533, "All commands must be ENC protected.  Retry command under ENC.");
+		*s = '\0';
+		return(s);
+	    }
+#endif /* PARANOID */
+#ifdef NOENCRYPTION
+	    if (!mic) {
+		reply(533, "ENC protection not supported.  Retry command under MIC.");
+		*s = '\0';
+		return(s);
+	    }
+#endif /* NOENCRYPTION */
+	    if ((cp = strpbrk(cs, " \r\n")))
+		*cp = '\0';
+	    kerror = radix_encode(cs, out, &len, 1);
+	    if (kerror) {
+		reply(501, "Can't base 64 decode argument to %s command (%s)",
+		      mic ? "MIC" : "ENC", radix_error(kerror));
+		*s = '\0';
+		return(s);
+	    }
+	    if (debug) syslog(LOG_DEBUG, "getline got %d from %s <%s>\n", 
+			      len, cs, mic?"MIC":"ENC");
+	    clevel = mic ? PROT_S : PROT_P;
+#ifdef KRB5_KRB4_COMPAT
+	    if (strcmp(auth_type, "KERBEROS_V4") == 0) {
+		if ((kerror = mic ?
+		    krb_rd_safe((unsigned char *)out, len, &kdata.session,
+			    &his_addr, &ctrl_addr, &msg_data)
+		  : krb_rd_priv((unsigned char *)out, len, schedule,
+			    &kdata.session, &his_addr, &ctrl_addr, &msg_data))
+			!= KSUCCESS) {
+		    reply(535, "%s! (%s)",
+			   mic ? "MIC command modified" : "ENC command garbled",
+			   krb_get_err_text(kerror));
+		    syslog(LOG_ERR,"%s failed: %s",
+			   mic ? "MIC krb_rd_safe" : "ENC krb_rd_priv",
+			   krb_get_err_text(kerror));
+		    *s = '\0';
+		    return(s);
+		}
+		(void) memcpy(s, msg_data.app_data, msg_data.app_length);
+		(void) strcpy(s+msg_data.app_length, "\r\n");
+	    }
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+/* we know this is a MIC or ENC already, and out/len already has the bits */
+	    if (strcmp(auth_type, "GSSAPI") == 0) {
+		gss_buffer_desc xmit_buf, msg_buf;
+		OM_uint32 maj_stat, min_stat;
+		int conf_state;
+
+		xmit_buf.value = out;
+		xmit_buf.length = len;
+		/* decrypt the message */
+		conf_state = !mic;
+		maj_stat = gss_unseal(&min_stat, gcontext, &xmit_buf,
+				      &msg_buf, &conf_state, NULL);
+		if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+			if (debug) syslog(LOG_DEBUG, "%s-unseal continued", 
+					  mic?"MIC":"ENC");
+			reply(535, "%s-unseal continued, oops",
+			      mic?"MIC":"ENC");
+			*s = 0; return s;
+		}
+		if (maj_stat != GSS_S_COMPLETE) {
+			reply_gss_error(535, maj_stat, min_stat, 
+					mic? "failed unsealing MIC message":
+					"failed unsealing ENC message");
+			*s = 0;
+			return s;
+		}
+
+		memcpy(s, msg_buf.value, msg_buf.length);
+		strcpy(s+msg_buf.length-(s[msg_buf.length-1]?0:1), "\r\n");
+		gss_release_buffer(&min_stat, &msg_buf);
+	    }
+#endif /* GSSAPI */
+	    /* Other auth types go here ... */
+
+	    /* A password should never be MICed, but the CNS ftp
+	     * client and the pre-6/98 Krb5 client did this if you
+	     * authenticated but didn't encrypt.
+	     */
+	    if (authlevel && mic && !strncmp(s, "PASS", 4)) {
+	    	lreply(530, "There is a problem with your ftp client. Password refused.");
+		reply(530, "Enable encryption before logging in, or update your ftp program.");
+		*s = 0;
+		return s;
+	    }
+
+	}
+#if defined KRB5_KRB4_COMPAT || defined GSSAPI	/* or other auth types */
+	else {	/* !auth_type */
+	    if ( (!(strncmp(s, "ENC", 3))) || (!(strncmp(s, "MIC", 3)))
+#ifndef NOCONFIDENTIAL
+                || (!(strncmp(s, "CONF", 4)))
+#endif
+                                        ) {
+                reply(503, "Must perform authentication before sending protected commands");
+                *s = '\0';
+                return(s);
+	    }
+	}
+#endif /* KRB5_KRB4_COMPAT || GSSAPI */
+
+	if (debug) {
+		if (!strncmp(s, "PASS ", 5) && !guest)
+			syslog(LOG_DEBUG, "command: <PASS XXX>");
+		else
+			syslog(LOG_DEBUG, "command: <%.*s>(%d)",
+			       strlen(s) - 2, s, strlen(s));
+	}
+	return (s);
+}
+
+static krb5_sigtype
+toolong(sig)
+	int sig;
+{
+	time_t now;
+
+	reply(421,
+	  "Timeout (%d seconds): closing control connection.", timeout);
+	(void) time(&now);
+	if (logging) {
+		syslog(LOG_INFO,
+			"User %s timed out after %d seconds at %s",
+			(pw ? pw -> pw_name : "unknown"), timeout, ctime(&now));
+	}
+	dologout(1);
+}
+
+static int
+yylex()
+{
+	static int cpos, state;
+	register char *cp, *cp2;
+	register struct tab *p;
+	int n;
+	char c;
+
+	for (;;) {
+		switch (state) {
+
+		case CMD:
+			(void) signal(SIGALRM, toolong);
+			(void) alarm((unsigned) timeout);
+			if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
+				reply(221, "You could at least say goodbye.");
+				dologout(0);
+			}
+			(void) alarm(0);
+
+			/* If getline() finds an error, the string is null */
+			if (*cbuf == '\0')
+				continue;
+
+#ifdef SETPROCTITLE
+			if (strncasecmp(cbuf, "PASS", 4) != NULL)
+				setproctitle("%s: %s", proctitle, cbuf);
+#endif /* SETPROCTITLE */
+			if ((cp = strchr(cbuf, '\r'))) {
+				*cp++ = '\n';
+				*cp = '\0';
+			}
+			if ((cp = strpbrk(cbuf, " \n")))
+				cpos = cp - cbuf;
+			if (cpos == 0)
+				cpos = 4;
+			c = cbuf[cpos];
+			cbuf[cpos] = '\0';
+			upper(cbuf);
+			p = lookup(cmdtab, cbuf);
+			cbuf[cpos] = c;
+			if (p != 0) {
+				if (p->implemented == 0) {
+					nack(p->name);
+					longjmp(errcatch,0);
+					/* NOTREACHED */
+				}
+				state = p->state;
+				yylval.str = p->name;
+				return (p->token);
+			}
+			break;
+
+		case SITECMD:
+			if (cbuf[cpos] == ' ') {
+				cpos++;
+				return (SP);
+			}
+			cp = &cbuf[cpos];
+			if ((cp2 = strpbrk(cp, " \n")))
+				cpos = cp2 - cbuf;
+			c = cbuf[cpos];
+			cbuf[cpos] = '\0';
+			upper(cp);
+			p = lookup(sitetab, cp);
+			cbuf[cpos] = c;
+			if (p != 0) {
+				if (p->implemented == 0) {
+					state = CMD;
+					nack(p->name);
+					longjmp(errcatch,0);
+					/* NOTREACHED */
+				}
+				state = p->state;
+				yylval.str = p->name;
+				return (p->token);
+			}
+			state = CMD;
+			break;
+
+		case OSTR:
+			if (cbuf[cpos] == '\n') {
+				state = CMD;
+				return (CRLF);
+			}
+			/* FALLTHROUGH */
+
+		case STR1:
+		case ZSTR1:
+		dostr1:
+			if (cbuf[cpos] == ' ') {
+				cpos++;
+				state = state == OSTR ? STR2 : state+1;
+				return (SP);
+			}
+			break;
+
+		case ZSTR2:
+			if (cbuf[cpos] == '\n') {
+				state = CMD;
+				return (CRLF);
+			}
+			/* FALLTHROUGH */
+
+		case STR2:
+			cp = &cbuf[cpos];
+			n = strlen(cp);
+			cpos += n - 1;
+			/*
+			 * Make sure the string is nonempty and \n terminated.
+			 */
+			if (n > 1 && cbuf[cpos] == '\n') {
+				cbuf[cpos] = '\0';
+				yylval.str = copy(cp);
+				cbuf[cpos] = '\n';
+				state = ARGS;
+				return (STRING);
+			}
+			break;
+
+		case NSTR:
+			if (cbuf[cpos] == ' ') {
+				cpos++;
+				return (SP);
+			}
+			if (isdigit((int) cbuf[cpos])) {
+				cp = &cbuf[cpos];
+				while (isdigit((int) cbuf[++cpos]))
+					;
+				c = cbuf[cpos];
+				cbuf[cpos] = '\0';
+				yylval.num = atoi(cp);
+				cbuf[cpos] = c;
+				state = STR1;
+				return (NUMBER);
+			}
+			state = STR1;
+			goto dostr1;
+
+		case ARGS:
+			if (isdigit((int) cbuf[cpos])) {
+				cp = &cbuf[cpos];
+				while (isdigit((int) cbuf[++cpos]))
+					;
+				c = cbuf[cpos];
+				cbuf[cpos] = '\0';
+				yylval.num = atoi(cp);
+				cbuf[cpos] = c;
+				return (NUMBER);
+			}
+			switch (cbuf[cpos++]) {
+
+			case '\n':
+				state = CMD;
+				return (CRLF);
+
+			case ' ':
+				return (SP);
+
+			case ',':
+				return (COMMA);
+
+			case 'A':
+			case 'a':
+				return ('A');
+
+			case 'B':
+			case 'b':
+				return ('B');
+
+			case 'C':
+			case 'c':
+				return ('C');
+
+			case 'E':
+			case 'e':
+				return ('E');
+
+			case 'F':
+			case 'f':
+				return ('F');
+
+			case 'I':
+			case 'i':
+				return ('I');
+
+			case 'L':
+			case 'l':
+				return ('L');
+
+			case 'N':
+			case 'n':
+				return ('N');
+
+			case 'P':
+			case 'p':
+				return ('P');
+
+			case 'R':
+			case 'r':
+				return ('R');
+
+			case 'S':
+			case 's':
+				return ('S');
+
+			case 'T':
+			case 't':
+				return ('T');
+
+			}
+			break;
+
+		default:
+			fatal("Unknown state in scanner.");
+		}
+		yyerror((char *) 0);
+		state = CMD;
+		longjmp(errcatch,0);
+	}
+}
+
+void
+upper(s)
+	register char *s;
+{
+	while (*s != '\0') {
+		if (islower((int) (*s)))
+			*s = toupper((int) (*s));
+		s++;
+	}
+}
+
+static char *
+copy(s)
+	char *s;
+{
+	char *p;
+
+	p = malloc((unsigned) strlen(s) + 1);
+	if (p == NULL)
+		fatal("Ran out of memory.");
+	(void) strcpy(p, s);
+	return (p);
+}
+
+void
+help(ctab, s)
+	struct tab *ctab;
+	char *s;
+{
+	register struct tab *c;
+	register int width, NCMDS;
+	char str[80];
+	char *ftype;
+
+	if (ctab == sitetab)
+		ftype = "SITE ";
+	else
+		ftype = "";
+	width = 0, NCMDS = 0;
+	for (c = ctab; c->name != NULL; c++) {
+		int len = strlen(c->name);
+
+		if (len > width)
+			width = len;
+		NCMDS++;
+	}
+	width = (width + 8) &~ 7;
+	if (s == 0) {
+		register int i, j, w;
+		int columns, lines;
+
+		lreply(214, "The following %scommands are recognized %s.",
+		    ftype, "(* =>'s unimplemented)");
+		columns = 76 / width;
+		if (columns == 0)
+			columns = 1;
+		lines = (NCMDS + columns - 1) / columns;
+		for (i = 0; i < lines; i++) {
+			strcpy(str, "   ");
+			for (j = 0; j < columns; j++) {
+				c = ctab + j * lines + i;
+				sprintf(&str[strlen(str)], "%s%c", c->name,
+					c->implemented ? ' ' : '*');
+				if (c + lines >= &ctab[NCMDS])
+					break;
+				w = strlen(c->name) + 1;
+				while (w < width) {
+					strcat(str, " ");
+					w++;
+				}
+			}
+			reply(0, "%s", str);
+		}
+		reply(214, "Direct comments to ftp-bugs@%s.", hostname);
+		return;
+	}
+	upper(s);
+	c = lookup(ctab, s);
+	if (c == (struct tab *)0) {
+		reply(502, "Unknown command %s.", s);
+		return;
+	}
+	if (c->implemented)
+		reply(214, "Syntax: %s%s %s", ftype, c->name, c->help);
+	else
+		reply(214, "%s%-*s\t%s; unimplemented.", ftype, width,
+		    c->name, c->help);
+}
+
+void
+sizecmd(filename)
+char *filename;
+{
+	switch (type) {
+	case TYPE_L:
+	case TYPE_I: {
+		struct stat stbuf;
+		if (stat(filename, &stbuf) < 0 ||
+		    (stbuf.st_mode&S_IFMT) != S_IFREG)
+			reply(550, "%s: not a plain file.", filename);
+		else
+			reply(213, "%lu", (long) stbuf.st_size);
+		break;}
+	case TYPE_A: {
+		FILE *fin;
+		register int c;
+		register long count;
+		struct stat stbuf;
+		fin = fopen(filename, "r");
+		if (fin == NULL) {
+			perror_reply(550, filename);
+			return;
+		}
+		if (fstat(fileno(fin), &stbuf) < 0 ||
+		    (stbuf.st_mode&S_IFMT) != S_IFREG) {
+			reply(550, "%s: not a plain file.", filename);
+			(void) fclose(fin);
+			return;
+		}
+
+		count = 0;
+		while((c=getc(fin)) != EOF) {
+			if (c == '\n')	/* will get expanded to \r\n */
+				count++;
+			count++;
+		}
+		(void) fclose(fin);
+
+		reply(213, "%ld", count);
+		break;}
+	default:
+		reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
+	}
+}
diff --git a/mechglue/src/appl/gssftp/ftpd/ftpd.M b/mechglue/src/appl/gssftp/ftpd/ftpd.M
new file mode 100644
index 000000000..b26a4bd94
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/ftpd.M
@@ -0,0 +1,513 @@
+.\" Copyright (c) 1985, 1988, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)ftpd.8	6.9 (Berkeley) 3/16/91
+.\" "
+.TH FTPD 8
+.SH NAME
+ftpd \- DARPA Internet File Transfer Protocol server
+.SH SYNOPSIS
+.B ftpd
+[\fB\-A \fP|\fB -a\fP] [\fB\-C\fP] [\fB\-c\fP] [\fB\-d\fP] [\fB-E\fP]
+[\fB\-l\fP] [\fB\-v\fP] [\fB\-T\fP \fImaxtimeout\fP] [\fB\-t\fP \fItimeout\fP]
+[\fB\-p\fP \fIport\fP] [\fB\-U\fP \fIftpusers-file\fP] [\fB\-u\fP \fIumask\fP]
+[\fB\-r\fP \fIrealm-file\fP] [\fB\-s\fP \fIsrvtab\fP]
+[\fB\-w\fP{\fBip\fP|\fImaxhostlen\fP[\fB,\fP{\fBstriplocal\fP|\fBnostriplocal\fP}]}]
+.SH DESCRIPTION
+.B Ftpd
+is the
+.SM DARPA
+Internet File Transfer Protocol server process.  The server uses the
+.SM TCP
+protocol and listens at the port specified in the ``ftp'' service
+specification; see
+.IR services (5).
+.PP
+Available options:
+.TP
+.B \-A
+Connections are only allowed for users who can authenticate via the
+ftp AUTH mechanism. (Anonymous ftp may also be allowed if it is 
+configured.) Ftpd will ask the user for a password if one is
+required.
+.TP
+.B \-a
+Connections are only allowed for users who can authenticate (via the
+ftp AUTH mechanism) and who are authorized to connect to the named 
+account without a password. (Anonymous ftp may also be allowed if it is 
+configured.)
+.TP
+.B \-C
+Non-anonymous users need local credentials (for example, to authenticate
+to remote fileservers), and so they should be prompted for a password
+unless they forwarded credentials as part of authentication.
+.TP
+.B \-c
+Allow the CCC (Clear Command Channel) command to be used. This allows
+less secure connections, and should probably only be used when debugging.
+.TP
+.B \-d
+Debugging information is written to the syslog.  (Identical to -v)
+.TP
+.B \-E
+Don't allow passwords to be typed across unencrypted connections.
+.TP
+.B \-l
+Each
+.IR ftp (1)
+session is logged in the syslog.  If this flag appears twice, additional
+information about operations performed (such as files retrieved, directories
+created, etc.) will be logged via syslog.  If it appears three times, some
+other statistics such as the number of bytes transferred will be logged via
+syslog as well.
+.TP
+.B \-v
+Debugging information is written to the syslog.  (Identical to -d)
+.TP
+\fB\-T\fP \fImaxtimeout\fP
+A client may request a maximum timeout period allowed set to
+.I timeout
+seconds with the
+.B \-T
+option.  The default limit is 2 hours.  This is different from the normal
+inactivity timeout specified by the
+.B \-t
+option (see below).
+.TP
+\fB\-t\fP \fItimeout\fP
+The inactivity timeout period is set to
+.I timeout
+seconds (the default is 15 minutes).
+.TP
+\fB\-p\fP \fIport\fP
+Run as a server and accept a connection on
+.IR port .
+Normally the ftp server is invoked by
+.IR inetd (8).
+.TP
+\fB\-U\fP \fIftpusers-file\fP
+Sets the full path and name of the
+.I ftpusers
+file to use.  The default value is normally
+.IR /etc/ftpusers .
+.TP
+\fB\-u\fP \fIumask\fP
+Sets the umask for the ftpd process.  The default value is normally 027.
+.TP
+\fB\-r\fP \fIrealm-file\fP
+Sets the name of the
+.I krb.conf
+file to use.  The default value is normally set by
+.IR /etc/krb5.conf .
+.TP
+\fB\-s\fP \fIsrvtab\fP
+Sets the name of the
+.I srvtab
+file to use for Kerberos V4 authentication.  The default value is normally
+.IR /etc/srvtab .
+.TP
+\fB\-w \fP{\fBip\fP|\fImaxhostlen\fP[\fB,\fP{\fBstriplocal\fP|\fBnostriplocal\fP}]}
+Controls the form of the remote hostname passed to login(1).
+Specifying \fBip\fP results in the numeric IP address always being
+passed to login(1).  Specifying a number, \fImaxhostlen\fP, sets the
+maximum length of the hostname passed to login(1) before it will be
+passed as a numeric IP address.  If \fImaxhostlen\fP is 0, then the
+system default, as determined by the utmp or utmpx structures, is
+used.  The \fBnostriplocal\fP and \fBstriplocal\fP options, which must
+be preceded by a comma, control whether or not the local host domain
+is stripped from the remote hostname.  By default, the equivalent of
+\fBstriplocal\fP is in effect.
+.PP
+The ftp server currently supports the following ftp requests; case is
+not distinguished.
+.TP "\w'Request\ \ 'u"
+.B Request
+.B Description
+.sp -1
+.TP
+ABOR
+abort previous command
+.sp -1
+.TP
+ACCT
+specify account (ignored)
+.sp -1
+.TP
+ADAT
+send an authentication protocol message
+.sp -1
+.TP
+ALLO
+allocate storage (vacuously)
+.sp -1
+.TP
+APPE
+append to a file
+.sp -1
+.TP
+AUTH
+specify an authentication protocol to be performed
+.sp -1
+.TP
+CCC
+set the command channel protection mode to "Clear" (no protection).
+Only available if the \fB-c\fP command-line option was given.
+.sp -1
+.TP
+CDUP
+change to parent of current working directory
+.sp -1
+.TP
+CWD
+change working directory
+.sp -1
+.TP
+DELE
+delete a file
+.sp -1
+.TP
+ENC
+send a privacy and integrity protected command (given in argument)
+.sp -1
+.TP
+HELP
+give help information
+.sp -1
+.TP
+LIST
+give list files in a directory (``ls -lgA'')
+.sp -1
+.TP
+MIC
+send an integrity protected command (given in argument)
+.sp -1
+.TP
+MKD
+make a directory
+.sp -1
+.TP
+MDTM
+show last modification time of file
+.sp -1
+.TP
+MODE
+specify data transfer
+.I mode
+.sp -1
+.TP
+NLST
+give name list of files in directory
+.sp -1
+.TP
+NOOP
+do nothing
+.sp -1
+.TP
+PASS
+specify password
+.sp -1
+.TP
+PASV
+prepare for server-to-server transfer
+.sp -1
+.TP
+PBSZ
+specify a protection buffer size
+.sp -1
+.TP
+PORT
+specify data connection port
+.sp -1
+.TP
+PROT
+specify a protection level under which to protect data transfers
+.sp -1
+.TP
+PWD
+print the current working directory
+.sp -1
+.TP
+QUIT
+terminate session
+.sp -1
+.TP
+REST
+restart incomplete transfer
+.sp -1
+.TP
+RETR
+retrieve a file
+.sp -1
+.TP
+RMD
+remove a directory
+.sp -1
+.TP
+RNFR
+specify rename-from file name
+.sp -1
+.TP
+RNTO
+specify rename-to file name
+.sp -1
+.TP
+SITE
+non-standard commands (see next section)
+.sp -1
+.TP
+SIZE
+return size of file
+.sp -1
+.TP
+STAT
+return status of server
+.sp -1
+.TP
+STOR
+store a file
+.sp -1
+.TP
+STOU
+store a file with a unique name
+.sp -1
+.TP
+STRU
+specify data transfer
+.I structure
+.sp -1
+.TP
+SYST
+show operating system type of server system
+.sp -1
+.TP
+TYPE
+specify data transfer
+.I type
+.sp -1
+.TP
+USER
+specify user name
+.sp -1
+.TP
+XCUP
+change to parent of current working directory (deprecated)
+.sp -1
+.TP
+XCWD
+change working directory (deprecated)
+.sp -1
+.TP
+XMKD
+make a directory (deprecated)
+.sp -1
+.TP
+XPWD
+print the current working directory (deprecated)
+.sp -1
+.TP
+XRMD
+remove a directory (deprecated)
+.PP
+The following non-standard or
+.SM UNIX
+specific commands are supported by the SITE request.
+.TP "\w'Request\ \ 'u"
+.B Request
+.B Description
+.sp -1
+.TP
+UMASK
+change umask. 
+.IR E.g. ,
+SITE UMASK 002
+.sp -1
+.TP
+IDLE
+set idle-timer. 
+.IR E.g. ,
+SITE IDLE 60
+.sp -1
+.TP
+CHMOD
+change mode of a file. 
+.IR E.g. ,
+SITE CHMOD 755 filename
+.sp -1
+.TP
+HELP
+give help information.
+.IR E.g. ,
+SITE HELP
+.PP
+The remaining ftp requests specified in Internet
+.I RFC 959
+are recognized, but not implemented.  MDTM and SIZE are not specified in
+.I RFC
+.IR 959 ,
+but will appear in the next updated FTP RFC.
+.PP
+The ftp server will abort an active file transfer only when the ABOR
+command is preceded by a Telnet "Interrupt Process" (IP) signal and a
+Telnet "Synch" signal in the command Telnet stream, as described in
+Internet
+.I RFC
+.IR 959 .
+If a STAT command is received during a data transfer, preceded by a
+Telnet IP and Synch, transfer status will be returned.
+.PP
+.B Ftpd
+interprets file names according to the
+``globbing''
+conventions used by
+.IR csh (1).
+This allows users to utilize the metacharacters ``\&*?[]{}~''.
+.PP
+.B Ftpd
+authenticates users according to the following rules:
+.sp
+.TP
+  1.
+The user name must be in the password data base,
+.IR /etc/passwd .
+.TP
+  2.
+An
+.SM AUTH
+command must be accepted, the ensuing authentication protocol (conducted
+via
+.SM ADAT
+commands and replies) must successfully complete, and the authenticated
+user must permitted access.  Otherwise, a valid password which is not
+null must be provided by the client.
+.TP
+  3.
+The user name must not appear in the file
+.IR /etc/ftpusers .
+.TP
+  4.
+The user must have a standard shell returned by 
+.IR getusershell (3).
+.TP
+  5.
+If the user name is ``anonymous'' or ``ftp'', an anonymous ftp account
+must be present in the password file (user ``ftp'').  In this case the
+user is allowed to log in by specifying any password (by convention this
+is given as the client host's name).
+.PP
+In the last case,
+.B ftpd
+takes special measures to restrict the client's access privileges.  The
+server performs a
+.IR chroot (2)
+command to the home directory of the ``ftp'' user.  In order that system
+security is not breached, it is recommended that the ``ftp'' subtree be
+constructed with care; the following rules are recommended.
+.TP
+.I ~ftp
+Make the home directory owned by ``ftp'' and unwritable by anyone.
+.TP
+.I ~ftp/bin
+Make this directory owned by the super-user and unwritable by anyone.
+The program
+.IR ls (1)
+must be present to support the list command.  This program should have
+mode 111.
+.TP
+.I ~ftp/etc
+Make this directory owned by the super-user and unwritable by anyone.
+The files
+.IR passwd (5)
+and
+.IR group (5)
+must be present for the
+.I ls
+command to be able to produce owner names rather than numbers.  The
+password field in
+.I passwd
+is not used, and should not contain real encrypted passwords.  These
+files should be mode 444.
+.TP
+.I ~ftp/pub
+Make this directory mode 777 and owned by ``ftp''.  Users should then
+place files which are to be accessible via the anonymous account in this
+directory.
+.PP
+If an
+.SM ADAT
+command succeeds, the control channel must be either integrity or
+privacy protected.  In this case, the
+.SM MIC
+and
+.SM ENC
+commands are the only commands allowed over the control channel.  The
+argument to the
+.SM MIC
+command is a base 64 encoded string which, when decoded, is an ftp
+command integrity protected with a cryptographic checksum.  The argument
+to the
+.SM ENC
+command is a base 64 encoded string which, when decoded, is an ftp
+command privacy and integrity protected with encryption.
+.PP
+If an
+.SM ADAT
+command succeeds, ftp replies will also be either integrity or privacy
+protected.
+.PP
+If an
+.SM ADAT
+command succeeds, the data channel can also be integrity or privacy
+protected.  The
+.SM PROT
+command accepts S for integrity and P for privacy protection.  Unless an
+.SM ADAT
+command succeeds, the only protection level accepted by the
+.SM PROT
+command is C (clear).
+.SH SEE ALSO
+.IR ftp (1),
+.IR getusershell (3),
+.IR syslogd (8)
+.PP
+Lunt, S. J., FTP Security Extensions, Internet Draft, November 1993.
+.SH BUGS
+The anonymous account is inherently dangerous and should avoided when
+possible.
+.PP
+The server must run as the super-user to create sockets with privileged
+port numbers.  It maintains an effective user id of the logged in user,
+reverting to the super-user only when binding addresses to sockets.  The
+possible security holes have been extensively scrutinized, but are
+possibly incomplete.
+.SH HISTORY
+The
+.B ftpd
+command appeared in 4.2BSD.
diff --git a/mechglue/src/appl/gssftp/ftpd/ftpd.c b/mechglue/src/appl/gssftp/ftpd/ftpd.c
new file mode 100644
index 000000000..6655e0d62
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/ftpd.c
@@ -0,0 +1,3000 @@
+/*
+ * Copyright (c) 1985, 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)ftpd.c	5.40 (Berkeley) 7/2/91";
+#endif /* not lint */
+
+/*
+ * FTP server.
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#ifndef KRB5_KRB4_COMPAT
+/* krb.h gets this, and Ultrix doesn't protect vs multiple inclusion */
+#include <sys/socket.h>
+#endif
+#include <sys/wait.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#define	FTP_NAMES
+#include <arpa/ftp.h>
+#include <arpa/inet.h>
+#include <arpa/telnet.h>
+
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <time.h>
+#include <pwd.h>
+#ifdef HAVE_SHADOW
+#include <shadow.h>
+#endif
+#include <grp.h> 
+#include <setjmp.h>
+#ifndef POSIX_SETJMP
+#undef sigjmp_buf
+#undef sigsetjmp
+#undef siglongjmp
+#define sigjmp_buf	jmp_buf
+#define sigsetjmp(j,s)	setjmp(j)
+#define siglongjmp	longjmp
+#endif
+#ifndef KRB5_KRB4_COMPAT
+/* krb.h gets this, and Ultrix doesn't protect vs multiple inclusion */
+#include <netdb.h>
+#endif
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef STDARG
+#if (defined(__STDC__) && ! defined(VARARGS)) || defined(HAVE_STDARG_H)
+#define STDARG
+#endif
+#endif
+#ifdef STDARG
+#include <stdarg.h>
+#endif
+#include "pathnames.h"
+#include <libpty.h>
+
+#ifdef NEED_SETENV
+extern int setenv(char *, char *, int);
+#endif
+
+#ifndef L_SET
+#define L_SET 0
+#endif
+#ifndef L_INCR
+#define L_INCR 1
+#endif
+
+#ifndef HAVE_STRERROR
+#define strerror(error)	(sys_errlist[error])
+#ifdef NEED_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+#endif
+
+extern char *mktemp ();
+char *ftpusers;
+extern int yyparse(void);
+
+#include <k5-util.h>
+#include "port-sockets.h"
+
+#ifdef KRB5_KRB4_COMPAT
+#include <krb5.h>
+#include <krb.h>
+
+AUTH_DAT kdata;
+KTEXT_ST ticket;
+MSG_DAT msg_data;
+Key_schedule schedule;
+char *keyfile;
+static char *krb4_services[] = { "ftp", "rcmd", NULL };
+#endif /* KRB5_KRB4_COMPAT */
+
+#ifdef GSSAPI
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+gss_ctx_id_t gcontext;
+gss_buffer_desc client_name;
+static char *gss_services[] = { "ftp", "host", NULL };
+
+#include <krb5.h>
+krb5_context kcontext;
+krb5_ccache ccache;
+
+static void ftpd_gss_convert_creds(char *name, gss_cred_id_t);
+static int ftpd_gss_userok(gss_buffer_t, char *name);
+
+static void log_gss_error(int, OM_uint32, OM_uint32, const char *);
+
+#endif /* GSSAPI */
+
+char *auth_type;	/* Authentication succeeded?  If so, what type? */
+static char *temp_auth_type;
+int authorized;		/* Auth succeeded and was accepted by krb4 or gssapi */
+int have_creds;		/* User has credentials on disk */
+
+/*
+ * File containing login names
+ * NOT to be used on this machine.
+ * Commonly used to disallow uucp.
+ */
+#include "ftpd_var.h"
+#include "secure.h"
+
+extern	char *crypt();
+extern	char version[];
+extern	char *home;		/* pointer to home directory for glob */
+extern	FILE *ftpd_popen(), *fopen(), *freopen();
+extern	int  ftpd_pclose(), fclose();
+extern	char *getline();
+extern	char cbuf[];
+extern	off_t restart_point;
+
+struct	sockaddr_in ctrl_addr;
+struct	sockaddr_in data_source;
+struct	sockaddr_in data_dest;
+struct	sockaddr_in his_addr;
+struct	sockaddr_in pasv_addr;
+
+int	data;
+jmp_buf	errcatch;
+sigjmp_buf urgcatch;
+int	logged_in;
+struct	passwd *pw;
+int	debug;
+int	allow_ccc = 0;    /* whether or not the CCC command is allowed */
+int	ccc_ok = 0;       /* whether or not to accept cleartext commands */
+int	timeout = 900;    /* timeout after 15 minutes of inactivity */
+int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
+int	logging;
+int	authlevel;
+int	want_creds;
+int	guest;
+int	restricted;
+int	type;
+int	clevel;			/* control protection level */
+int	dlevel;			/* data protection level */
+int	form;
+int	stru;			/* avoid C keyword */
+int	mode;
+int	usedefault = 1;		/* for data transfers */
+int	pdata = -1;		/* for passive mode */
+int	transflag;
+off_t	file_size;
+off_t	byte_count;
+#if !defined(CMASK) || CMASK == 0
+#undef CMASK
+#define CMASK 027
+#endif
+int	defumask = CMASK;		/* default umask value */
+char	tmpline[FTP_BUFSIZ];
+char    pathbuf[MAXPATHLEN + 1];
+char	hostname[MAXHOSTNAMELEN];
+char	remotehost[MAXHOSTNAMELEN];
+char	rhost_addra[16];
+char	*rhost_sane;
+
+/* Defines for authlevel */
+#define AUTHLEVEL_NONE		0
+#define AUTHLEVEL_AUTHENTICATE	1
+#define AUTHLEVEL_AUTHORIZE	2
+
+/*
+ * Timeout intervals for retrying connections
+ * to hosts that don't accept PORT cmds.  This
+ * is a kludge, but given the problems with TCP...
+ */
+#define	SWAITMAX	90	/* wait at most 90 seconds */
+#define	SWAITINT	5	/* interval between retries */
+
+int	swaitmax = SWAITMAX;
+int	swaitint = SWAITINT;
+
+void	lostconn(int), myoob(int);
+FILE	*getdatasock(char *); 
+#if defined(__STDC__)
+/* 
+ * The following prototypes must be ANSI for systems for which
+ * sizeof(off_t) > sizeof(int) to prevent stack overflow problems 
+ */
+FILE	*dataconn(char *name, off_t size, char *mymode);
+void	send_data(FILE *instr, FILE *outstr, off_t blksize);
+#else
+void	send_data();
+FILE	*dataconn();
+#endif
+static void dolog(struct sockaddr_in *);
+static int receive_data(FILE *, FILE *);
+static void login(char *passwd, int logincode);
+static void end_login(void);
+static int disallowed_user(char *);
+static int restricted_user(char *);
+static int checkuser(char *);
+static char *gunique(char *);
+
+#ifdef SETPROCTITLE
+char	**Argv = NULL;		/* pointer to argument vector */
+char	*LastArgv = NULL;	/* end of argv */
+char	proctitle[FTP_BUFSIZ];	/* initial part of title */
+#endif /* SETPROCTITLE */
+
+#ifdef __SCO__
+/* sco has getgroups and setgroups but no initgroups */
+int initgroups(char* name, gid_t basegid) {
+  gid_t others[NGROUPS_MAX+1];
+  int ngrps;
+
+  others[0] = basegid;
+  ngrps = getgroups(NGROUPS_MAX, others+1);
+  return setgroups(ngrps+1, others);
+}
+#endif
+
+int stripdomain = 1;
+int maxhostlen = 0;
+int always_ip = 0;
+
+int
+main(argc, argv, envp)
+	int argc;
+	char *argv[];
+	char **envp;
+{
+	int addrlen, c, on = 1, tos, port = -1;
+	extern char *optarg;
+	extern int optopt;
+#ifdef KRB5_KRB4_COMPAT
+	char *option_string = "AaCcdElp:r:s:T:t:U:u:vw:";
+#else /* !KRB5_KRB4_COMPAT */
+	char *option_string = "AaCcdElp:r:T:t:U:u:vw:";
+#endif /* KRB5_KRB4_COMPAT */
+	ftpusers = _PATH_FTPUSERS_DEFAULT;
+
+#ifdef KRB5_KRB4_COMPAT
+	keyfile = KEYFILE;
+#endif /* KRB5_KRB4_COMPAT */
+	debug = 0;
+#ifdef SETPROCTITLE
+	/*
+	 *  Save start and extent of argv for setproctitle.
+	 */
+	Argv = argv;
+	while (*envp)
+		envp++;
+	LastArgv = envp[-1] + strlen(envp[-1]);
+#endif /* SETPROCTITLE */
+
+#ifdef GSSAPI
+	krb5_init_context(&kcontext);
+#endif
+
+	while ((c = getopt(argc, argv, option_string)) != -1) {
+		switch (c) {
+
+		case 'v':
+			debug = 1;
+			break;
+
+		case 'd':
+			debug = 1;
+			break;
+
+		case 'E':
+			if (!authlevel)
+				authlevel = AUTHLEVEL_AUTHENTICATE;
+			break;
+
+		case 'l':
+			logging ++;
+			break;
+
+		case 'a':
+			authlevel = AUTHLEVEL_AUTHORIZE;
+			break;
+
+		case 'A':
+			authlevel = AUTHLEVEL_AUTHENTICATE;
+			break;
+
+		case 'C':
+			want_creds = 1;
+			break;
+
+		case 'c':
+			allow_ccc = 1;
+			break;
+
+		case 'p':
+			port = atoi(optarg);
+			break;
+
+		case 'r':
+			setenv("KRB_CONF", optarg, 1);
+			break;
+
+#ifdef KRB5_KRB4_COMPAT
+		case 's':
+			keyfile = optarg;
+			break;
+#endif /* KRB5_KRB4_COMPAT */
+
+		case 't':
+			timeout = atoi(optarg);
+			if (maxtimeout < timeout)
+				maxtimeout = timeout;
+			break;
+
+		case 'T':
+			maxtimeout = atoi(optarg);
+			if (timeout > maxtimeout)
+				timeout = maxtimeout;
+			break;
+
+		case 'u':
+			{
+			    int val = 0;
+			    char *umask_val = optarg;
+
+			    while (*umask_val >= '0' && *umask_val <= '9') {
+				    val = val*8 + *umask_val - '0';
+				    umask_val++;
+			    }
+			    if (*umask_val != ' ' && *umask_val != '\0')
+				    fprintf(stderr, "ftpd: Bad value for -u\n");
+			    else
+				    defumask = val;
+			    break;
+			}
+
+		case 'U':
+			ftpusers = optarg;
+			break;
+
+		case 'w':
+		{
+			char *foptarg;
+			foptarg = optarg;
+
+			if (!strcmp(foptarg, "ip"))
+				always_ip = 1;
+			else {
+				char *cp2;
+				cp2 = strchr(foptarg, ',');
+				if (cp2 == NULL)
+					maxhostlen = atoi(foptarg);
+				else if (*(++cp2)) {
+					if (!strcmp(cp2, "striplocal"))
+						stripdomain = 1;
+					else if (!strcmp(cp2, "nostriplocal"))
+						stripdomain = 0;
+					else {
+						fprintf(stderr,
+							"ftpd: bad arg to -w\n");
+						exit(1);
+					}
+					*(--cp2) = '\0';
+					maxhostlen = atoi(foptarg);
+				}
+			}
+			break;
+		}
+		default:
+			fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
+			     (char)optopt);
+			break;
+		}
+	}
+
+	if (port != -1) {
+		struct sockaddr_in sin4;
+		int s, ns;
+		socklen_t sz;
+
+		/* Accept an incoming connection on port.  */
+		sin4.sin_family = AF_INET;
+		sin4.sin_addr.s_addr = INADDR_ANY;
+		sin4.sin_port = htons(port);
+		s = socket(AF_INET, SOCK_STREAM, 0);
+		if (s < 0) {
+			perror("socket");
+			exit(1);
+		}
+		(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+				  (char *)&on, sizeof(on));
+		if (bind(s, (struct sockaddr *)&sin4, sizeof sin4) < 0) {
+			perror("bind");
+			exit(1);
+		}
+		if (listen(s, 1) < 0) {
+			perror("listen");
+			exit(1);
+		}
+		sz = sizeof sin4;
+		ns = accept(s, (struct sockaddr *)&sin4, &sz);
+		if (ns < 0) {
+			perror("accept");
+			exit(1);
+		}
+		(void) close(s);
+		(void) dup2(ns, 0);
+		(void) dup2(ns, 1);
+		(void) dup2(ns, 2);
+		if (ns > 2)
+		  (void) close(ns);
+	}
+
+	/*
+	 * LOG_NDELAY sets up the logging connection immediately,
+	 * necessary for anonymous ftp's that chroot and can't do it later.
+	 */
+#ifndef LOG_NDELAY
+/* Ultrix syslog does not support NDELAY.  */
+#define LOG_NDELAY 0
+#endif
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
+
+	addrlen = sizeof (his_addr);
+	if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
+		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
+		exit(1);
+	}
+	addrlen = sizeof (ctrl_addr);
+	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
+		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
+		exit(1);
+	}
+#ifdef IP_TOS
+#ifdef IPTOS_LOWDELAY
+	tos = IPTOS_LOWDELAY;
+	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+#endif
+#endif
+	port = ntohs(ctrl_addr.sin_port);
+	data_source.sin_port = htons(port - 1);
+
+	(void) freopen("/dev/null", "w", stderr);
+	(void) signal(SIGPIPE, lostconn);
+	(void) signal(SIGCHLD, SIG_IGN);
+#ifdef SIGURG
+#ifdef POSIX_SIGNALS
+	{
+		struct sigaction sa;
+
+		sigemptyset(&sa.sa_mask);
+		sa.sa_flags = 0;
+		sa.sa_handler = myoob;
+		if (sigaction(SIGURG, &sa, NULL) < 0)
+			syslog(LOG_ERR, "signal: %m");
+	}
+#else
+	if ((long)signal(SIGURG, myoob) < 0)
+		syslog(LOG_ERR, "signal: %m");
+#endif /* POSIX_SIGNALS */
+#endif /* SIGURG */
+
+	/* Try to handle urgent data inline */
+#ifdef SO_OOBINLINE
+	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
+		syslog(LOG_ERR, "setsockopt: %m");
+#endif
+
+#ifdef	F_SETOWN
+	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
+		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
+#endif
+	dolog(&his_addr);
+	/*
+	 * Set up default state
+	 */
+	data = -1;
+	clevel = dlevel = PROT_C;
+	type = TYPE_A;
+	form = FORM_N;
+	stru = STRU_F;
+	mode = MODE_S;
+	tmpline[0] = '\0';
+	(void) gethostname(hostname, sizeof (hostname));
+	reply(220, "%s FTP server (%s) ready.", hostname, version);
+	(void) setjmp(errcatch);
+	for (;;)
+		(void) yyparse();
+	/* NOTREACHED */
+}
+
+void
+lostconn(sig)
+int sig;
+{
+	if (debug)
+		syslog(LOG_DEBUG, "lost connection");
+	dologout(-1);
+}
+
+static char ttyline[20];
+
+/*
+ * Helper function for sgetpwnam().
+ */
+static char *
+sgetsave(s)
+	char *s;
+{
+	char *new = malloc((unsigned) strlen(s) + 1);
+
+	if (new == NULL) {
+		perror_reply(421, "Local resource failure: malloc");
+		dologout(1);
+		/* NOTREACHED */
+	}
+	(void) strcpy(new, s);
+	return (new);
+}
+
+/*
+ * Save the result of a getpwnam.  Used for USER command, since
+ * the data returned must not be clobbered by any other command
+ * (e.g., globbing).
+ */
+static struct passwd *
+sgetpwnam(name)
+	char *name;
+{
+	static struct passwd save;
+	register struct passwd *p;
+#ifdef HAVE_SHADOW
+	register struct spwd *sp;
+#endif
+	if ((p = getpwnam(name)) == NULL)
+		return (p);
+	if (save.pw_name) {
+		free(save.pw_name);
+		free(save.pw_passwd);
+		free(save.pw_gecos);
+		free(save.pw_dir);
+		free(save.pw_shell);
+	}
+	save = *p;
+	save.pw_name = sgetsave(p->pw_name);
+#ifdef HAVE_SHADOW
+	if ((sp = getspnam(name)) == NULL)
+	    save.pw_passwd = sgetsave(p->pw_passwd);
+	else
+	    save.pw_passwd = sgetsave(sp->sp_pwdp);
+#else
+	save.pw_passwd = sgetsave(p->pw_passwd);
+#endif
+	save.pw_gecos = sgetsave(p->pw_gecos);
+	save.pw_dir = sgetsave(p->pw_dir);
+	save.pw_shell = sgetsave(p->pw_shell);
+	return (&save);
+}
+
+/*
+ * Expand the given pathname relative to the current working directory.
+ */
+static char *
+path_expand(path)
+       char *path;
+{
+	pathbuf[0] = '\x0';
+	if (!path) return pathbuf;
+	/* Don't bother with getcwd() if the path is absolute */
+	if (path[0] != '/') {
+	        if (!getcwd(pathbuf, sizeof pathbuf)) {
+		        pathbuf[0] = '\x0';
+			syslog(LOG_ERR, "getcwd() failed");
+		}
+		else {
+		        int len = strlen(pathbuf);
+			if (pathbuf[len-1] != '/') {
+			        pathbuf[len++] = '/';
+				pathbuf[len] = '\x0';
+			}
+		}
+	}
+	return strncat(pathbuf, path,
+		       sizeof (pathbuf) - strlen(pathbuf) - 1);
+}
+
+/*
+ * Set data channel protection level
+ */
+void
+setdlevel(prot_level)
+int prot_level;
+{
+	switch (prot_level) {
+		case PROT_S:
+#ifndef NOENCRYPTION
+		case PROT_P:
+#endif
+			if (auth_type)
+		case PROT_C:
+				reply(200, "Data channel protection level set to %s.",
+					(dlevel = prot_level) == PROT_S ?
+						"safe" : dlevel == PROT_P ?
+						"private" : "clear");
+			else
+		default:	reply(536, "%s protection level not supported.",
+					levelnames[prot_level]);
+	}
+}
+
+int login_attempts;		/* number of failed login attempts */
+int askpasswd;			/* had user command, ask for passwd */
+
+/*
+ * USER command.
+ * Sets global passwd pointer pw if named account exists and is acceptable;
+ * sets askpasswd if a PASS command is expected.  If logged in previously,
+ * need to reset state.  If name is "ftp" or "anonymous", the name is not in
+ * ftpusers, and ftp account exists, set guest and pw, then just return.
+ * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
+ * requesting login privileges.  Disallow anyone who does not have a standard
+ * shell as returned by getusershell().  Disallow anyone mentioned in the file
+ * ftpusers to allow people such as root and uucp to be avoided, except
+ * for users whose names are followed by whitespace and then the keyword
+ * "restrict."  Restricted users are allowed to login, but a chroot() is
+ * done to their home directory.
+ */
+void
+user(name)
+	char *name;
+{
+	register char *cp;
+	char *shell;
+	char buf[FTP_BUFSIZ];
+#ifdef HAVE_GETUSERSHELL
+	char *getusershell();
+#endif
+
+	if (logged_in) {
+		if (guest) {
+			reply(530, "Can't change user from guest login.");
+			return;
+		}
+		end_login();
+	}
+
+	authorized = guest = 0;
+	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
+		if (disallowed_user("ftp") || disallowed_user("anonymous"))
+			reply(530, "User %s access denied.", name);
+		else if ((pw = sgetpwnam("ftp")) != NULL) {
+			guest = 1;
+			askpasswd = 1;
+			reply(331, "Guest login ok, send ident as password.");
+		} else
+			reply(530, "User %s unknown.", name);
+		return;
+	}
+
+	/*
+	 * If authentication is required, check that before anything
+	 * else to avoid leaking information.
+	 */
+	if (authlevel && !auth_type) {
+		reply(530,
+		      "Must perform authentication before identifying USER.");
+		return;
+	}
+
+	pw = sgetpwnam(name);
+	if (pw) {
+		if ((shell = pw->pw_shell) == NULL || *shell == 0)
+			shell = "/bin/sh";
+#ifdef HAVE_GETUSERSHELL
+		setusershell();
+		while ((cp = getusershell()) != NULL)
+			if (strcmp(cp, shell) == 0)
+				break;
+		endusershell();
+#else
+		cp = shell;
+#endif
+		if (cp == NULL || disallowed_user(name)) {
+			reply(530, "User %s access denied.", name);
+			if (logging)
+				syslog(LOG_NOTICE,
+				    "FTP LOGIN REFUSED FROM %s, %s (%s)",
+				    rhost_addra, remotehost, name);
+			pw = (struct passwd *) NULL;
+			return;
+		}
+		restricted = restricted_user(name);
+	}
+
+	if (auth_type) {
+		int result;
+#ifdef GSSAPI
+		if (auth_type && strcmp(auth_type, "GSSAPI") == 0) {
+			int len;
+
+			authorized = ftpd_gss_userok(&client_name, name) == 0;
+			len = sizeof("GSSAPI user  is not authorized as "
+				     "; Password required.")
+				+ strlen(client_name.value)
+				+ strlen(name);
+			if (len >= sizeof(buf)) {
+				syslog(LOG_ERR, "user: username too long");
+				name = "[username too long]";
+			}
+			sprintf(buf, "GSSAPI user %s is%s authorized as %s",
+				(char *) client_name.value, 
+				authorized ? "" : " not",
+				name);
+		}
+#ifdef KRB5_KRB4_COMPAT
+		else
+#endif /* KRB5_KRB4_COMPAT */
+#endif /* GSSAPI */
+#ifdef KRB5_KRB4_COMPAT
+		if (auth_type && strcmp(auth_type, "KERBEROS_V4") == 0) {
+			int len;
+
+			authorized = kuserok(&kdata,name) == 0;
+			len = sizeof("Kerberos user .@ is not authorized as "
+				     "; Password required.")
+				+ strlen(kdata.pname)
+				+ strlen(kdata.pinst)
+				+ strlen(kdata.prealm)
+				+ strlen(name);
+			if (len >= sizeof(buf)) {
+				syslog(LOG_ERR, "user: username too long");
+				name = "[username too long]";
+			}
+			sprintf(buf, "Kerberos user %s%s%s@%s is%s authorized as %s",
+				kdata.pname, *kdata.pinst ? "." : "",
+				kdata.pinst, kdata.prealm,
+				authorized ? "" : " not", name);
+		}
+#endif /* KRB5_KRB4_COMPAT */
+
+		if (!authorized && authlevel == AUTHLEVEL_AUTHORIZE) {
+			strncat(buf, "; Access denied.",
+				sizeof(buf) - strlen(buf) - 1);
+			result = 530;
+			pw = NULL;
+		} else if (!authorized || (want_creds && !have_creds)) {
+			strncat(buf, "; Password required.",
+				sizeof(buf) - strlen(buf) - 1);
+			askpasswd = 1;
+			result = 331;
+		} else
+			result = 232;
+		reply(result, "%s", buf);
+		syslog(authorized ? LOG_INFO : LOG_ERR, "%s", buf);
+
+		if (result == 232)
+			login(NULL, result);
+		return;
+	}
+
+	/* User didn't authenticate and authentication wasn't required. */
+	reply(331, "Password required for %s.", name);
+	askpasswd = 1;
+
+	/*
+	 * Delay before reading passwd after first failed
+	 * attempt to slow down passwd-guessing programs.
+	 */
+	if (login_attempts)
+		sleep((unsigned) login_attempts);
+}
+
+/*
+ * Check if a user is in the file ftpusers.
+ * Return 1 if they are (a disallowed user), -1 if their username
+ * is followed by "restrict." (a restricted user).  Otherwise return 0.
+ */
+static int
+checkuser(name)
+	char *name;
+{
+	register FILE *fd;
+	register char *p;
+	char line[FTP_BUFSIZ];
+
+	if ((fd = fopen(ftpusers, "r")) != NULL) {
+	     while (fgets(line, sizeof(line), fd) != NULL) {
+	          if ((p = strchr(line, '\n')) != NULL) {
+			*p = '\0';
+			if (line[0] == '#')
+			     continue;
+			if (strcmp(line, name) == 0)
+			     return (1);
+			if (strncmp(line, name, strlen(name)) == 0) {
+			     int i = strlen(name) + 1;
+			     
+			     /* Make sure foo doesn't match foobar */
+			     if (line[i] == '\0' || !isspace((int) line[i]))
+			          continue;
+			     /* Ignore whitespace */
+			     while (isspace((int) line[++i]));
+
+			     if (strcmp(&line[i], "restrict") == 0)
+			          return (-1);
+			     else
+			          return (1);
+			}
+		  }
+	     }
+	     (void) fclose(fd);
+	}
+
+	return (0);
+}
+
+static int
+disallowed_user(name)
+        char *name;
+{
+        return(checkuser(name) == 1);
+}
+
+static int
+restricted_user(name)
+        char *name;
+{
+        return(checkuser(name) == -1);
+}
+
+/*
+ * Terminate login as previous user, if any, resetting state;
+ * used when USER command is given or login fails.
+ */
+static void 
+end_login()
+{
+
+	(void) krb5_seteuid((uid_t)0);
+	if (logged_in)
+		pty_logwtmp(ttyline, "", "");
+	if (have_creds) {
+#ifdef GSSAPI
+		krb5_cc_destroy(kcontext, ccache);
+#endif
+#ifdef KRB5_KRB4_COMPAT
+		dest_tkt();
+#endif
+		have_creds = 0;
+	}
+	pw = NULL;
+	logged_in = 0;
+	guest = 0;
+}
+
+static int
+kpass(name, passwd)
+char *name, *passwd;
+{
+#ifdef GSSAPI
+	krb5_principal server, me;
+	krb5_creds my_creds;
+	krb5_timestamp now;
+#endif /* GSSAPI */
+#ifdef KRB5_KRB4_COMPAT
+	char realm[REALM_SZ];
+#ifndef GSSAPI
+	char **service;
+	KTEXT_ST ticket;
+	AUTH_DAT authdata;
+	des_cblock key;
+	char instance[INST_SZ];
+	unsigned long faddr;
+	struct hostent *hp;
+#endif /* GSSAPI */
+#endif /* KRB5_KRB4_COMPAT */
+	char ccname[MAXPATHLEN];
+
+#ifdef GSSAPI
+	memset((char *)&my_creds, 0, sizeof(my_creds));
+	if (krb5_parse_name(kcontext, name, &me))
+		return 0;
+	my_creds.client = me;
+
+	sprintf(ccname, "FILE:/tmp/krb5cc_ftpd%ld", (long) getpid());
+	if (krb5_cc_resolve(kcontext, ccname, &ccache))
+		return(0);
+	if (krb5_cc_initialize(kcontext, ccache, me))
+		return(0);
+	if (krb5_build_principal_ext(kcontext, &server,
+				     krb5_princ_realm(kcontext, me)->length,
+				     krb5_princ_realm(kcontext, me)->data,
+				     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
+				     krb5_princ_realm(kcontext, me)->length,
+				     krb5_princ_realm(kcontext, me)->data,
+				     0))
+		goto nuke_ccache;
+
+	my_creds.server = server;
+	if (krb5_timeofday(kcontext, &now))
+		goto nuke_ccache;
+	my_creds.times.starttime = 0; /* start timer when 
+					 request gets to KDC */
+	my_creds.times.endtime = now + 60 * 60 * 10;
+	my_creds.times.renew_till = 0;
+
+	if (krb5_get_init_creds_password(kcontext, &my_creds, me,
+					 passwd, NULL, NULL, 0, NULL, NULL))
+	  goto nuke_ccache;
+
+	if (krb5_cc_store_cred(kcontext, ccache, &my_creds))
+	  goto nuke_ccache;
+
+	if (!want_creds) {
+		krb5_cc_destroy(kcontext, ccache);
+		return(1);
+	}
+#endif /* GSSAPI */
+
+#ifdef KRB5_KRB4_COMPAT
+	if (krb_get_lrealm(realm, 1) != KSUCCESS)
+		goto nuke_ccache;
+
+	sprintf(ccname, "%s_ftpd%ld", TKT_ROOT, (long) getpid());
+	krb_set_tkt_string(ccname);
+
+	if (krb_get_pw_in_tkt(name, "", realm, "krbtgt", realm, 1, passwd))
+		goto nuke_ccache;
+
+#ifndef GSSAPI
+	/* Verify the ticket since we didn't verify the krb5 one. */
+	strncpy(instance, krb_get_phost(hostname), sizeof(instance));
+
+	if ((hp = gethostbyname(instance)) == NULL)
+		goto nuke_ccache;
+	memcpy((char *) &faddr, (char *)hp->h_addr, sizeof(faddr));
+
+	for (service = krb4_services; *service; service++) {
+		if (!read_service_key(*service, instance,
+				      realm, 0, keyfile, key)) {
+			(void) memset(key, 0, sizeof(key));
+			if (krb_mk_req(&ticket, *service,
+				       instance, realm, 33) ||
+			    krb_rd_req(&ticket, *service, instance,
+				       faddr, &authdata,keyfile) ||
+			    kuserok(&authdata, name)) {
+				dest_tkt();
+				goto nuke_ccache;
+			} else
+				break;
+		}
+	}
+
+	if (!*service) {
+		dest_tkt();
+		goto nuke_ccache;
+	}
+
+	if (!want_creds) {
+		dest_tkt();
+		return(1);
+	}
+#endif /* GSSAPI */
+#endif /* KRB5_KRB4_COMPAT */
+
+#if defined(GSSAPI) || defined(KRB5_KRB4_COMPAT)
+	have_creds = 1;
+	return(1);
+#endif /* GSSAPI || KRB5_KRB4_COMPAT */
+
+nuke_ccache:
+#ifdef GSSAPI
+	krb5_cc_destroy(kcontext, ccache);
+#endif /* GSSAPI */
+	return(0);
+}
+
+void
+pass(passwd)
+	char *passwd;
+{
+	char *xpasswd, *salt;
+
+	if (authorized && !want_creds) {
+		reply(202, "PASS command superfluous.");
+		return;
+	}
+
+	if (logged_in || askpasswd == 0) {
+	  	reply(503, "Login with USER first.");
+		return;
+	} 
+
+	if (!guest) {
+	    	/* "ftp" is only account allowed no password */
+		if (pw == NULL)
+			salt = "xx";
+		else
+			salt = pw->pw_passwd;
+#ifdef __SCO__
+		/* SCO does not provide crypt.  */
+		xpasswd = "";
+#else
+		xpasswd = crypt(passwd, salt);
+#endif
+		/* Fail if:
+		 *   pw is NULL
+		 *   kpass fails and we want_creds
+		 *   kpass fails and the user has no local password
+		 *   kpass fails and the provided password doesn't match pw
+		 */
+		if (pw == NULL || (!kpass(pw->pw_name, passwd) &&
+				   (want_creds || !*pw->pw_passwd ||
+				    strcmp(xpasswd, pw->pw_passwd)))) {
+			pw = NULL;
+			sleep(5);
+			if (++login_attempts >= 3) {
+				reply(421,
+				      "Login incorrect, closing connection.");
+				syslog(LOG_NOTICE,
+				       "repeated login failures from %s (%s)",
+				       rhost_addra, remotehost);
+				dologout(0);
+			}
+			reply(530, "Login incorrect.");
+			return;
+	        }
+	}
+	login_attempts = 0;		/* this time successful */
+
+	login(passwd, 0);
+	return;
+}
+
+static void
+login(passwd, logincode)
+	char *passwd;
+	int logincode;
+{
+	if (have_creds) {
+#ifdef GSSAPI
+		const char *ccname = krb5_cc_get_name(kcontext, ccache);
+		chown(ccname, pw->pw_uid, pw->pw_gid);
+#endif
+#ifdef KRB5_KRB4_COMPAT
+		chown(tkt_string(), pw->pw_uid, pw->pw_gid);
+#endif
+	}
+
+	(void) krb5_setegid((gid_t)pw->pw_gid);
+	(void) initgroups(pw->pw_name, pw->pw_gid);
+
+	/* open wtmp before chroot */
+	(void) sprintf(ttyline, "ftp%ld", (long) getpid());
+	pty_logwtmp(ttyline, pw->pw_name, rhost_sane);
+	logged_in = 1;
+
+	if (guest || restricted) {
+		if (chroot(pw->pw_dir) < 0) {
+			reply(550, "Can't set privileges.");
+			goto bad;
+		}
+	}
+#ifdef HAVE_SETLUID
+  	/*
+  	 * If we're on a system which keeps track of login uids, then
+ 	 * set the login uid. If this fails this opens up a problem on DEC OSF
+ 	 * with C2 enabled.
+	 */
+	if (((uid_t)getluid() != pw->pw_uid)
+	    && setluid((uid_t)pw->pw_uid) < 0) {
+	        reply(550, "Can't set luid.");
+		goto bad;
+	}
+#endif
+	if (krb5_seteuid((uid_t)pw->pw_uid) < 0) {
+	        reply(550, "Can't set uid.");
+		goto bad;
+	}
+	if (guest) {
+		/*
+		 * We MUST do a chdir() after the chroot. Otherwise
+		 * the old current directory will be accessible as "."
+		 * outside the new root!
+		 */
+		if (chdir("/") < 0) {
+			reply(550, "Can't set guest privileges.");
+			goto bad;
+		}
+	} else {
+	        if (chdir(restricted ? "/" : pw->pw_dir) < 0) {
+		        if (chdir("/") < 0) {
+			        reply(530, "User %s: can't change directory to %s.",
+				      pw->pw_name, pw->pw_dir);
+				goto bad;
+			} else {
+				if (!logincode)
+					logincode = 230;
+			        lreply(logincode, "No directory! Logging in with home=/");
+			}
+		}
+	}
+	if (guest) {
+		reply(230, "Guest login ok, access restrictions apply.");
+#ifdef SETPROCTITLE
+		sprintf(proctitle, "%s: anonymous/%.*s", rhost_sane,
+		    sizeof(proctitle) - strlen(rhost_sane) -
+		    sizeof(": anonymous/"), passwd);
+		setproctitle(proctitle);
+#endif /* SETPROCTITLE */
+		if (logging)
+			syslog(LOG_INFO,
+			       "ANONYMOUS FTP LOGIN FROM %s, %s (%s)",
+			       rhost_addra, remotehost, passwd);
+	} else {
+		if (askpasswd) {
+			askpasswd = 0;
+			reply(230, "User %s logged in.", pw->pw_name);
+		}
+#ifdef SETPROCTITLE
+		sprintf(proctitle, "%s: %s", rhost_sane, pw->pw_name);
+		setproctitle(proctitle);
+#endif /* SETPROCTITLE */
+		if (logging)
+			syslog(LOG_INFO, "FTP LOGIN FROM %s, %s (%s)",
+			    rhost_addra, remotehost, pw->pw_name);
+	}
+	home = pw->pw_dir;		/* home dir for globbing */
+	(void) umask(defumask);
+	return;
+bad:
+	/* Forget all about it... */
+	end_login();
+}
+
+void
+retrieve(cmd, name)
+	char *cmd, *name;
+{
+	FILE *fin, *dout;
+	struct stat st;
+	int (*closefunc)();
+
+	if (logging > 1 && !cmd)
+	        syslog(LOG_NOTICE, "get %s", path_expand(name));
+	if (cmd == 0) {
+		fin = fopen(name, "r"), closefunc = fclose;
+		st.st_size = 0;
+	} else {
+		char line[FTP_BUFSIZ];
+
+		if (strlen(cmd) + strlen(name) + 1 >= sizeof(line)) {
+			syslog(LOG_ERR, "retrieve: filename too long");
+			reply(501, "filename too long");
+			return;
+		}
+		(void) sprintf(line, cmd, name), name = line;
+		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
+		st.st_size = -1;
+#ifndef NOSTBLKSIZE
+		st.st_blksize = FTP_BUFSIZ;
+#endif
+	}
+	if (fin == NULL) {
+		if (errno != 0)
+			perror_reply(550, name);
+		return;
+	}
+	if (cmd == 0 &&
+	    (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
+		reply(550, "%s: not a plain file.", name);
+		goto done;
+	}
+	if (restart_point) {
+		if (type == TYPE_A) {
+			register int i, n, c;
+
+			n = restart_point;
+			i = 0;
+			while (i++ < n) {
+				if ((c=getc(fin)) == EOF) {
+					perror_reply(550, name);
+					goto done;
+				}
+				if (c == '\n')
+					i++;
+			}	
+		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
+			perror_reply(550, name);
+			goto done;
+		}
+	}
+	dout = dataconn(name, st.st_size, "w");
+	if (dout == NULL)
+		goto done;
+#ifndef NOSTBLKSIZE
+	send_data(fin, dout, st.st_blksize);
+#else
+	send_data(fin, dout, FTP_BUFSIZ);
+#endif
+	(void) fclose(dout);
+	data = -1;
+	pdata = -1;
+done:
+	(*closefunc)(fin);
+	if (logging > 2 && !cmd)
+	        syslog(LOG_NOTICE, "get: %i bytes transferred", byte_count);
+}
+
+void
+store_file(name, fmode, unique)
+	char *name, *fmode;
+	int unique;
+{
+	FILE *fout, *din;
+	struct stat st;
+	int (*closefunc)();
+
+	if (logging > 1) syslog(LOG_NOTICE, "put %s", path_expand(name));
+
+	if (unique && stat(name, &st) == 0 &&
+	    (name = gunique(name)) == NULL)
+		return;
+
+	if (restart_point)
+		fmode = "r+w";
+	fout = fopen(name, fmode);
+	closefunc = fclose;
+	if (fout == NULL) {
+		perror_reply(553, name);
+		return;
+	}
+	if (restart_point) {
+		if (type == TYPE_A) {
+			register int i, n, c;
+
+			n = restart_point;
+			i = 0;
+			while (i++ < n) {
+				if ((c=getc(fout)) == EOF) {
+					perror_reply(550, name);
+					goto done;
+				}
+				if (c == '\n')
+					i++;
+			}	
+			/*
+			 * We must do this seek to "current" position
+			 * because we are changing from reading to
+			 * writing.
+			 */
+			if (fseek(fout, 0L, L_INCR) < 0) {
+				perror_reply(550, name);
+				goto done;
+			}
+		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
+			perror_reply(550, name);
+			goto done;
+		}
+	}
+	din = dataconn(name, (off_t)-1, "r");
+	if (din == NULL)
+		goto done;
+	if (receive_data(din, fout) == 0) {
+		if (unique)
+			reply(226, "Transfer complete (unique file name:%s).",
+			    name);
+		else
+			reply(226, "Transfer complete.");
+	}
+	(void) fclose(din);
+	data = -1;
+	pdata = -1;
+done:
+	(*closefunc)(fout);
+	if (logging > 2)
+	        syslog(LOG_NOTICE, "put: %i bytes transferred", byte_count);
+}
+
+FILE *
+getdatasock(fmode)
+	char *fmode;
+{
+	int s, on = 1, tries;
+
+	if (data >= 0)
+		return (fdopen(data, fmode));
+	(void) krb5_seteuid((uid_t)0);
+	s = socket(AF_INET, SOCK_STREAM, 0);
+	if (s < 0)
+		goto bad;
+	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+	    (char *) &on, sizeof (on)) < 0)
+		goto bad;
+	/* anchor socket to avoid multi-homing problems */
+	data_source.sin_family = AF_INET;
+	data_source.sin_addr = ctrl_addr.sin_addr;
+	for (tries = 1; ; tries++) {
+		if (bind(s, (struct sockaddr *)&data_source,
+		    sizeof (data_source)) >= 0)
+			break;
+		if (errno != EADDRINUSE || tries > 10)
+			goto bad;
+		sleep(tries);
+	}
+	(void) krb5_seteuid((uid_t)pw->pw_uid);
+#ifdef IP_TOS
+#ifdef IPTOS_THROUGHPUT
+	on = IPTOS_THROUGHPUT;
+	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
+		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+#endif
+#endif
+	return (fdopen(s, fmode));
+bad:
+	(void) krb5_seteuid((uid_t)pw->pw_uid);
+	(void) close(s);
+	return (NULL);
+}
+
+FILE *
+dataconn(name, size, fmode)
+	char *name;
+	off_t size;
+	char *fmode;
+{
+	char sizebuf[32];
+	FILE *file;
+	int retry = 0, tos;
+
+	file_size = size;
+	byte_count = 0;
+	if (size != (off_t) -1)
+		/* cast size to long in case sizeof(off_t) > sizeof(long) */
+		(void) sprintf (sizebuf, " (%ld bytes)", (long)size);
+	else
+		(void) strcpy(sizebuf, "");
+	if (pdata >= 0) {
+		int s, fromlen = sizeof(data_dest);
+
+		s = accept(pdata, (struct sockaddr *)&data_dest, &fromlen);
+		if (s < 0) {
+			reply(425, "Can't open data connection.");
+			(void) close(pdata);
+			pdata = -1;
+			return(NULL);
+		}
+		(void) close(pdata);
+		pdata = s;
+#ifdef IP_TOS
+#ifdef IPTOS_LOWDELAY
+		tos = IPTOS_LOWDELAY;
+		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
+		    sizeof(int));
+#endif
+#endif
+		reply(150, "Opening %s mode data connection for %s%s.",
+		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+		return(fdopen(pdata, fmode));
+	}
+	if (data >= 0) {
+		reply(125, "Using existing data connection for %s%s.",
+		    name, sizebuf);
+		usedefault = 1;
+		return (fdopen(data, fmode));
+	}
+	if (usedefault)
+		data_dest = his_addr;
+	usedefault = 1;
+	file = getdatasock(fmode);
+	if (file == NULL) {
+		reply(425, "Can't create data socket (%s,%d): %s.",
+		    inet_ntoa(data_source.sin_addr),
+		    ntohs(data_source.sin_port), strerror(errno));
+		return (NULL);
+	}
+	data = fileno(file);
+	while (connect(data, (struct sockaddr *)&data_dest,
+	    sizeof (data_dest)) < 0) {
+		if (errno == EADDRINUSE && retry < swaitmax) {
+			sleep((unsigned) swaitint);
+			retry += swaitint;
+			continue;
+		}
+		perror_reply(425, "Can't build data connection");
+		(void) fclose(file);
+		data = -1;
+		return (NULL);
+	}
+	reply(150, "Opening %s mode data connection for %s%s.",
+	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+	return (file);
+}
+
+/*
+ * XXX callers need to limit total length of output string to
+ * FTP_BUFSIZ
+ */
+#ifdef STDARG
+void
+secure_error(char *fmt, ...)
+#else
+/* VARARGS1 */
+void
+secure_error(fmt, p1, p2, p3, p4, p5)
+	char *fmt;
+#endif
+{
+	char buf[FTP_BUFSIZ];
+#ifdef STDARG
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsprintf(buf, fmt, ap);
+	va_end(ap);
+#else
+	sprintf(buf, fmt, p1, p2, p3, p4, p5);
+#endif
+	reply(535, "%s", buf);
+	syslog(LOG_ERR, "%s", buf);
+}
+
+/*
+ * Tranfer the contents of "instr" to
+ * "outstr" peer using the appropriate
+ * encapsulation of the data subject
+ * to Mode, Structure, and Type.
+ *
+ * NB: Form isn't handled.
+ */
+void send_data(instr, outstr, blksize)
+	FILE *instr, *outstr;
+	off_t blksize;
+{
+	register int c, cnt;
+	register char *buf;
+	int netfd, filefd;
+	volatile int ret = 0;
+
+	transflag++;
+	if (sigsetjmp(urgcatch, 1)) {
+		transflag = 0;
+		(void)secure_flush(fileno(outstr));
+		return;
+	}
+	switch (type) {
+
+	case TYPE_A:
+		while ((c = getc(instr)) != EOF) {
+			byte_count++;
+			if (c == '\n') {
+				if (ferror(outstr) ||
+				    (ret = secure_putc('\r', outstr)) < 0)
+					goto data_err;
+			}
+			if ((ret = secure_putc(c, outstr)) < 0)
+				goto data_err;
+		}
+		transflag = 0;
+		if (ferror(instr))
+			goto file_err;
+		if (ferror(outstr) ||
+		    (ret = secure_flush(fileno(outstr))) < 0)
+			goto data_err;
+		reply(226, "Transfer complete.");
+		return;
+
+	case TYPE_I:
+	case TYPE_L:
+		if ((buf = malloc((u_int)blksize)) == NULL) {
+			transflag = 0;
+			perror_reply(451, "Local resource failure: malloc");
+			return;
+		}
+		netfd = fileno(outstr);
+		filefd = fileno(instr);
+		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
+		    (ret = secure_write(netfd, buf, cnt)) == cnt)
+			byte_count += cnt;
+		transflag = 0;
+		(void)free(buf);
+		if (cnt != 0) {
+			if (cnt < 0)
+				goto file_err;
+			goto data_err;
+		}
+		if ((ret = secure_flush(netfd)) < 0)
+			goto data_err;
+		reply(226, "Transfer complete.");
+		return;
+	default:
+		transflag = 0;
+		reply(550, "Unimplemented TYPE %d in send_data", type);
+		return;
+	}
+
+data_err:
+	transflag = 0;
+	if (ret != -2) perror_reply(426, "Data connection");
+	return;
+
+file_err:
+	transflag = 0;
+	perror_reply(551, "Error on input file");
+}
+
+/*
+ * Transfer data from peer to
+ * "outstr" using the appropriate
+ * encapulation of the data subject
+ * to Mode, Structure, and Type.
+ *
+ * N.B.: Form isn't handled.
+ */
+static int
+receive_data(instr, outstr)
+	FILE *instr, *outstr;
+{
+	register int c;
+	volatile int cnt, bare_lfs = 0;
+	char buf[FTP_BUFSIZ];
+	int ret = 0;
+
+	transflag++;
+	if (sigsetjmp(urgcatch, 1)) {
+		transflag = 0;
+		return (-1);
+	}
+	switch (type) {
+
+	case TYPE_I:
+	case TYPE_L:
+		while ((cnt = secure_read(fileno(instr), buf, sizeof buf)) > 0) {
+			if (write(fileno(outstr), buf, cnt) != cnt)
+				goto file_err;
+			byte_count += cnt;
+		}
+		transflag = 0;
+		ret = cnt;
+		if (cnt < 0)
+			goto data_err;
+		return (0);
+
+	case TYPE_E:
+		reply(553, "TYPE E not implemented.");
+		transflag = 0;
+		return (-1);
+
+	case TYPE_A:
+		while ((c = secure_getc(instr)) >= 0) {
+			byte_count++;
+			if (c == '\n')
+				bare_lfs++;
+			while (c == '\r') {
+				if (ferror(outstr))
+					goto data_err;
+				if ((c = secure_getc(instr)) != '\n') {
+					(void) putc ('\r', outstr);
+					if (c == '\0')
+						goto contin2;
+				}
+			}
+			if (c < 0) break;
+			(void) putc(c, outstr);
+	contin2:	;
+		}
+		fflush(outstr);
+		ret = c;
+		if (c == -2 || ferror(instr))
+			goto data_err;
+		if (ferror(outstr))
+			goto file_err;
+		transflag = 0;
+		if (bare_lfs) {
+			lreply(226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
+			reply(0, "   File may not have transferred correctly.");
+		}
+		return (0);
+	default:
+		reply(550, "Unimplemented TYPE %d in receive_data", type);
+		transflag = 0;
+		return (-1);
+	}
+
+data_err:
+	transflag = 0;
+	if (ret != -2) perror_reply(426, "Data Connection");
+	return (-1);
+
+file_err:
+	transflag = 0;
+	perror_reply(452, "Error writing file");
+	return (-1);
+}
+
+void
+statfilecmd(filename)
+	char *filename;
+{
+	char line[FTP_BUFSIZ];
+	FILE *fin;
+	int c, n;
+	char str[FTP_BUFSIZ], *p;
+
+	if (strlen(filename) + sizeof("/bin/ls -lgA ")
+	    >= sizeof(line)) {
+		reply(501, "filename too long");
+		return;
+	}
+	(void) sprintf(line, "/bin/ls -lgA %s", filename);
+	fin = ftpd_popen(line, "r");
+	lreply(211, "status of %s:", filename);
+	p = str;
+	n = 0;
+	while ((c = getc(fin)) != EOF) {
+		if (c == '\n') {
+			if (ferror(stdout)){
+				perror_reply(421, "control connection");
+				(void) ftpd_pclose(fin);
+				dologout(1);
+				/* NOTREACHED */
+			}
+			if (ferror(fin)) {
+				perror_reply(551, filename);
+				(void) ftpd_pclose(fin);
+				return;
+			}
+			*p = '\0';
+			reply(0, "%s", str);
+			p = str;
+			n = 0;
+		} else {
+			*p++ = c;
+			n++;
+			if (n >= sizeof(str)) {
+				reply(551, "output line too long");
+				(void) ftpd_pclose(fin);
+				return;
+			}
+		}
+	}
+	if (p != str) {
+		*p = '\0';
+		reply(0, "%s", str);
+	}
+	(void) ftpd_pclose(fin);
+	reply(211, "End of Status");
+}
+
+void
+statcmd()
+{
+	struct sockaddr_in *sin4;
+	u_char *a, *p;
+	char str[FTP_BUFSIZ];
+
+	lreply(211, "%s FTP server status:", hostname);
+	reply(0, "     %s", version);
+	sprintf(str, "     Connected to %s", remotehost[0] ? remotehost : "");
+	sprintf(&str[strlen(str)], " (%s)", rhost_addra);
+	reply(0, "%s", str);
+	if (auth_type) reply(0, "     Authentication type: %s", auth_type);
+	if (logged_in) {
+		if (guest)
+			reply(0, "     Logged in anonymously");
+		else
+			reply(0, "     Logged in as %s", pw->pw_name);
+	} else if (askpasswd)
+		reply(0, "     Waiting for password");
+	else if (temp_auth_type)
+		reply(0, "     Waiting for authentication data");
+	else
+		reply(0, "     Waiting for user name");
+	reply(0, "     Protection level: %s", levelnames[dlevel]);
+	sprintf(str, "     TYPE: %s", typenames[type]);
+	if (type == TYPE_A || type == TYPE_E)
+		sprintf(&str[strlen(str)], ", FORM: %s", formnames[form]);
+	if (type == TYPE_L)
+#if 1
+		strncat(str, " 8", sizeof (str) - strlen(str) - 1);
+#else
+/* this is silly. -- eichin@cygnus.com */
+#if NBBY == 8
+		sprintf(&str[strlen(str)], " %d", NBBY);
+#else
+		sprintf(&str[strlen(str)], " %d", bytesize);	/* need definition! */
+#endif
+#endif
+	sprintf(&str[strlen(str)], "; STRUcture: %s; transfer MODE: %s",
+	    strunames[stru], modenames[mode]);
+	reply(0, "%s", str);
+	if (data != -1)
+		strcpy(str, "     Data connection open");
+	else if (pdata != -1) {
+		strcpy(str, "     in Passive mode");
+		sin4 = &pasv_addr;
+		goto printaddr;
+	} else if (usedefault == 0) {
+		strcpy(str, "     PORT");
+		sin4 = &data_dest;
+printaddr:
+		a = (u_char *) &sin4->sin_addr;
+		p = (u_char *) &sin4->sin_port;
+#define UC(b) (((int) b) & 0xff)
+		sprintf(&str[strlen(str)], " (%d,%d,%d,%d,%d,%d)", UC(a[0]),
+			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
+#undef UC
+	} else
+		strcpy(str, "     No data connection");
+	reply(0, "%s", str);
+	reply(211, "End of status");
+}
+
+void
+fatal(s)
+	char *s;
+{
+	reply(451, "Error in server: %s", s);
+	reply(221, "Closing connection due to server error.");
+	dologout(0);
+	/* NOTREACHED */
+}
+
+char cont_char = ' ';
+
+/*
+ * XXX callers need to limit total length of output string to
+ * FTP_BUFSIZ bytes for now.
+ */
+#ifdef STDARG
+void
+reply(int n, char *fmt, ...)
+#else
+/* VARARGS2 */
+void
+reply(n, fmt, p0, p1, p2, p3, p4, p5)
+	int n;
+	char *fmt;
+#endif
+{
+	char buf[FTP_BUFSIZ];
+#ifdef STDARG
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsprintf(buf, fmt, ap);
+	va_end(ap);
+#else
+	sprintf(buf, fmt, p0, p1, p2, p3, p4, p5);
+#endif
+
+	if (auth_type) {
+		/*
+		 * Deal with expansion in mk_{safe,priv},
+		 * radix_encode, gss_seal, plus slop.
+		 */
+		char in[FTP_BUFSIZ*3/2], out[FTP_BUFSIZ*3/2];
+		int length, kerror;
+		if (n) sprintf(in, "%d%c", n, cont_char);
+		else in[0] = '\0';
+		strncat(in, buf, sizeof (in) - strlen(in) - 1);
+#ifdef KRB5_KRB4_COMPAT
+		if (strcmp(auth_type, "KERBEROS_V4") == 0) {
+			if (clevel == PROT_P)
+				length = krb_mk_priv((unsigned char *)in,
+						     (unsigned char *)out,
+						     strlen(in),
+						     schedule, &kdata.session,
+						     &ctrl_addr,
+						     &his_addr);
+			else
+				length = krb_mk_safe((unsigned char *)in,
+						     (unsigned char *)out,
+						     strlen(in),
+						     &kdata.session,
+						     &ctrl_addr,
+						     &his_addr);
+			if (length == -1) {
+				syslog(LOG_ERR,
+				       "krb_mk_%s failed for KERBEROS_V4",
+				       clevel == PROT_P ? "priv" : "safe");
+				fputs(in,stdout);
+			}
+		} else
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+		/* reply (based on level) */
+		if (strcmp(auth_type, "GSSAPI") == 0) {
+			gss_buffer_desc in_buf, out_buf;
+			OM_uint32 maj_stat, min_stat;
+			int conf_state;
+		
+			in_buf.value = in;
+			in_buf.length = strlen(in);
+			maj_stat = gss_seal(&min_stat, gcontext,
+					    clevel == PROT_P, /* private */
+					    GSS_C_QOP_DEFAULT,
+					    &in_buf, &conf_state,
+					    &out_buf);
+			if (maj_stat != GSS_S_COMPLETE) {
+#if 0
+/* Don't setup an infinite loop */
+				/* generally need to deal */
+				secure_gss_error(maj_stat, min_stat,
+					       (clevel==PROT_P)?
+						 "gss_seal ENC didn't complete":
+						 "gss_seal MIC didn't complete");
+#endif /* 0 */
+			} else if ((clevel == PROT_P) && !conf_state) {
+#if 0
+/* Don't setup an infinite loop */
+				secure_error("GSSAPI didn't encrypt message");
+#endif /* 0 */
+			} else {
+				memcpy(out, out_buf.value, 
+				       length=out_buf.length);
+				gss_release_buffer(&min_stat, &out_buf);
+			}
+		}
+#endif /* GSSAPI */
+		/* Other auth types go here ... */
+		if (length >= sizeof(in) / 4 * 3) {
+			syslog(LOG_ERR, "input to radix_encode too long");
+			fputs(in, stdout);
+		} else if ((kerror = radix_encode(out, in, &length, 0))) {
+			syslog(LOG_ERR, "Couldn't encode reply (%s)",
+					radix_error(kerror));
+			fputs(in,stdout);
+		} else
+			printf("%s%c%s", clevel == PROT_P ? "632" : "631",
+			       n ? cont_char : '-', in);
+	} else {
+		if (n) printf("%d%c", n, cont_char);
+		fputs(buf, stdout);
+	}
+	printf("\r\n");
+	(void)fflush(stdout);
+	if (debug) {
+		if (n) syslog(LOG_DEBUG, "<--- %d%c", n, cont_char);
+		syslog(LOG_DEBUG, "%s", buf);
+	}
+}
+
+/*
+ * XXX callers need to limit total length of output string to
+ * FTP_BUFSIZ
+ */
+#ifdef STDARG
+void
+lreply(int n, char *fmt, ...)
+#else
+/* VARARGS2 */
+void
+lreply(n, fmt, p0, p1, p2, p3, p4, p5)
+	int n;
+	char *fmt;
+#endif
+{
+	char buf[FTP_BUFSIZ];
+#ifdef STDARG
+	va_list ap;
+
+	va_start(ap, fmt);
+	vsprintf(buf, fmt, ap);
+	va_end(ap);
+#else
+	sprintf(buf, fmt, p0, p1, p2, p3, p4, p5);
+#endif
+	cont_char = '-';
+	reply(n, "%s", buf);
+	cont_char = ' ';
+}
+
+void
+ack(s)
+	char *s;
+{
+	reply(250, "%s command successful.", s);
+}
+
+void
+nack(s)
+	char *s;
+{
+	reply(502, "%s command not implemented.", s);
+}
+
+/* ARGSUSED */
+void
+yyerror(s)
+	char *s;
+{
+	char *cp;
+
+	cp = strchr(cbuf,'\n');
+	if (cp)
+		*cp = '\0';
+	reply(500, "'%.*s': command not understood.",
+	      (int) (FTP_BUFSIZ - sizeof("'': command not understood.")),
+	      cbuf);
+}
+
+void
+delete_file(name)
+	char *name;
+{
+	struct stat st;
+
+	if (logging > 1) syslog(LOG_NOTICE, "del %s", path_expand(name));
+
+	if (stat(name, &st) < 0) {
+		perror_reply(550, name);
+		return;
+	}
+	if ((st.st_mode&S_IFMT) == S_IFDIR) {
+		if (rmdir(name) < 0) {
+			perror_reply(550, name);
+			return;
+		}
+		goto done;
+	}
+	if (unlink(name) < 0) {
+		perror_reply(550, name);
+		return;
+	}
+done:
+	ack("DELE");
+}
+
+void
+cwd(path)
+	char *path;
+{
+	if (chdir(path) < 0)
+		perror_reply(550, path);
+	else
+		ack("CWD");
+}
+
+void
+makedir(name)
+	char *name;
+{
+        if (logging > 1) syslog(LOG_NOTICE, "mkdir %s", path_expand(name));
+
+	if (mkdir(name, 0777) < 0)
+		perror_reply(550, name);
+	else
+		reply(257, "MKD command successful.");
+}
+
+void
+removedir(name)
+	char *name;
+{
+        if (logging > 1) syslog(LOG_NOTICE, "rmdir %s", path_expand(name));
+
+	if (rmdir(name) < 0)
+		perror_reply(550, name);
+	else
+		ack("RMD");
+}
+
+void
+pwd()
+{
+	if (getcwd(pathbuf, sizeof pathbuf) == (char *)NULL)
+#ifdef POSIX
+		perror_reply(550, pathbuf);
+#else
+		reply(550, "%s.", pathbuf);
+#endif
+	else
+		reply(257, "\"%s\" is current directory.", pathbuf);
+}
+
+char *
+renamefrom(name)
+	char *name;
+{
+	struct stat st;
+
+	if (stat(name, &st) < 0) {
+		perror_reply(550, name);
+		return ((char *)0);
+	}
+	reply(350, "File exists, ready for destination name");
+	return (name);
+}
+
+void
+renamecmd(from, to)
+	char *from, *to;
+{
+        if(logging > 1)
+                syslog(LOG_NOTICE, "rename %s %s", path_expand(from), to);
+
+	if (rename(from, to) < 0)
+		perror_reply(550, "rename");
+	else
+		ack("RNTO");
+}
+
+static void
+dolog(sin4)
+	struct sockaddr_in *sin4;
+{
+	struct hostent *hp = gethostbyaddr((char *)&sin4->sin_addr,
+		sizeof (struct in_addr), AF_INET);
+	time_t t, time();
+	extern char *ctime();
+	krb5_error_code retval;
+
+	if (hp != NULL) {
+		(void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
+		remotehost[sizeof (remotehost) - 1] = '\0';
+	} else
+		remotehost[0] = '\0';
+	strncpy(rhost_addra, inet_ntoa(sin4->sin_addr), sizeof (rhost_addra));
+	rhost_addra[sizeof (rhost_addra) - 1] = '\0';
+	retval = pty_make_sane_hostname((struct sockaddr *) sin4, maxhostlen,
+					stripdomain, always_ip, &rhost_sane);
+	if (retval) {
+		fprintf(stderr, "make_sane_hostname: %s\n",
+			error_message(retval));
+		exit(1);
+	}
+#ifdef SETPROCTITLE
+	sprintf(proctitle, "%s: connected", rhost_sane);
+	setproctitle(proctitle);
+#endif /* SETPROCTITLE */
+
+	if (logging) {
+		t = time((time_t *) 0);
+		syslog(LOG_INFO, "connection from %s (%s) at %s",
+		    rhost_addra, remotehost, ctime(&t));
+	}
+}
+
+/*
+ * Record logout in wtmp file
+ * and exit with supplied status.
+ */
+void
+dologout(status)
+	int status;
+{
+	if (logged_in) {
+		(void) krb5_seteuid((uid_t)0);
+		pty_logwtmp(ttyline, "", "");
+	}
+	if (have_creds) {
+#ifdef GSSAPI
+		krb5_cc_destroy(kcontext, ccache);
+#endif
+#ifdef KRB5_KRB4_COMPAT
+		dest_tkt();
+#endif
+	}
+	/* beware of flushing buffers after a SIGPIPE */
+	_exit(status);
+}
+
+void
+myoob(sig)
+    int sig;
+{
+	char *cp, *cs;
+#ifndef strpbrk
+	extern char *strpbrk();
+#endif
+
+	/* only process if transfer occurring */
+	if (!transflag)
+		return;
+	cp = tmpline;
+	if (getline(cp, sizeof(tmpline), stdin) == NULL) {
+		reply(221, "You could at least say goodbye.");
+		dologout(0);
+	}
+	upper(cp);
+	if ((cs = strpbrk(cp, "\r\n")))
+		*cs++ = '\0';
+	if (strcmp(cp, "ABOR") == 0) {
+		tmpline[0] = '\0';
+		reply(426, "Transfer aborted. Data connection closed.");
+		reply(226, "Abort successful");
+		siglongjmp(urgcatch, 1);
+	}
+	if (strcmp(cp, "STAT") == 0) {
+		if (file_size != (off_t) -1)
+			reply(213, "Status: %lu of %lu bytes transferred",
+			      (unsigned long) byte_count, 
+			      (unsigned long) file_size);
+		else
+			reply(213, "Status: %lu bytes transferred", 
+			      (unsigned long) byte_count);
+	}
+}
+
+/*
+ * Note: a response of 425 is not mentioned as a possible response to
+ * 	the PASV command in RFC959. However, it has been blessed as
+ * 	a legitimate response by Jon Postel in a telephone conversation
+ *	with Rick Adams on 25 Jan 89.
+ */
+void
+passive()
+{
+	int len;
+	register char *p, *a;
+
+	pdata = socket(AF_INET, SOCK_STREAM, 0);
+	if (pdata < 0) {
+		perror_reply(425, "Can't open passive connection");
+		return;
+	}
+	pasv_addr = ctrl_addr;
+	pasv_addr.sin_port = 0;
+	(void) krb5_seteuid((uid_t)0);
+	if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
+		(void) krb5_seteuid((uid_t)pw->pw_uid);
+		goto pasv_error;
+	}
+	(void) krb5_seteuid((uid_t)pw->pw_uid);
+	len = sizeof(pasv_addr);
+	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
+		goto pasv_error;
+	if (listen(pdata, 1) < 0)
+		goto pasv_error;
+	a = (char *) &pasv_addr.sin_addr;
+	p = (char *) &pasv_addr.sin_port;
+
+#define UC(b) (((int) b) & 0xff)
+
+	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
+		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
+	return;
+
+pasv_error:
+	(void) close(pdata);
+	pdata = -1;
+	perror_reply(425, "Can't open passive connection");
+	return;
+}
+
+/*
+ * Generate unique name for file with basename "local".
+ * The file named "local" is already known to exist.
+ * Generates failure reply on error.
+ */
+static char *
+gunique(local)
+	char *local;
+{
+	static char new[MAXPATHLEN];
+	struct stat st;
+	char *cp = strrchr(local, '/');
+	int count = 0;
+
+	if (cp)
+		*cp = '\0';
+	if (stat(cp ? local : ".", &st) < 0) {
+		perror_reply(553, cp ? local : ".");
+		return((char *) 0);
+	}
+	if (cp)
+		*cp = '/';
+	(void) strncpy(new, local, sizeof(new) - 1);
+	new[sizeof(new) - 1] = '\0';
+	cp = new + strlen(new);
+	*cp++ = '.';
+	for (count = 1; count < 100; count++) {
+		(void) sprintf(cp, "%d", count);
+		if (stat(new, &st) < 0)
+			return(new);
+	}
+	reply(452, "Unique file name cannot be created.");
+	return((char *) 0);
+}
+
+/*
+ * Format and send reply containing system error number.
+ */
+void
+perror_reply(code, string)
+	int code;
+	char *string;
+{
+	char *err_string;
+	size_t extra_len;
+
+	err_string = strerror(errno);
+	if (err_string == NULL)
+		err_string = "(unknown error)";
+	extra_len = strlen(err_string) + sizeof("(truncated): .");
+
+	/*
+	 * XXX knows about FTP_BUFSIZ in reply()
+	 */
+	if (strlen(string) + extra_len > FTP_BUFSIZ) {
+		reply(code, "(truncated)%.*s: %s.",
+		      (int) (FTP_BUFSIZ - extra_len), string, err_string);
+	} else {
+		reply(code, "%s: %s.", string, err_string);
+	}
+}
+
+void
+auth(atype)
+char *atype;
+{
+	if (auth_type)
+		reply(534, "Authentication type already set to %s", auth_type);
+	else
+#ifdef KRB5_KRB4_COMPAT
+	if (strcmp(atype, "KERBEROS_V4") == 0)
+		reply(334, "Using authentication type %s; ADAT must follow",
+				temp_auth_type = atype);
+	else
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+	if (strcmp(atype, "GSSAPI") == 0)
+		reply(334, "Using authentication type %s; ADAT must follow",
+				temp_auth_type = atype);
+	else
+#endif /* GSSAPI */
+	/* Other auth types go here ... */
+		reply(504, "Unknown authentication type: %s", atype);
+}
+
+int
+auth_data(adata)
+char *adata;
+{
+	int kerror, length;
+#ifdef KRB5_KRB4_COMPAT
+	static char **service=NULL;
+	char instance[INST_SZ];
+	KRB4_32 cksum;
+	char buf[FTP_BUFSIZ];
+	u_char out_buf[sizeof(buf)];
+#endif /* KRB5_KRB4_COMPAT */
+
+	if (auth_type) {
+		reply(503, "Authentication already established");
+		return(0);
+	}
+	if (!temp_auth_type) {
+		reply(503, "Must identify AUTH type before ADAT");
+		return(0);
+	}
+#ifdef KRB5_KRB4_COMPAT
+	if (strcmp(temp_auth_type, "KERBEROS_V4") == 0) {
+	        kerror = radix_encode(adata, out_buf, &length, 1);
+		if (kerror) {
+			reply(501, "Couldn't decode ADAT (%s)",
+			      radix_error(kerror));
+			syslog(LOG_ERR, "Couldn't decode ADAT (%s)",
+			       radix_error(kerror));
+			return(0);
+		}
+		(void) memcpy((char *)ticket.dat, (char *)out_buf, ticket.length = length);
+		strcpy(instance, "*");
+
+		kerror = 255;
+		for (service = krb4_services; *service; service++) {
+		  kerror = krb_rd_req(&ticket, *service, instance,
+				      his_addr.sin_addr.s_addr, 
+				      &kdata, keyfile);
+		  /* Success */
+		  if(!kerror) break;
+		} 
+		/* rd_req failed.... */
+		if(kerror) {
+		  secure_error("ADAT: Kerberos V4 krb_rd_req: %s",
+			       krb_get_err_text(kerror));
+		  return(0);
+		}
+
+		/* add one to the (formerly) sealed checksum, and re-seal it */
+		cksum = kdata.checksum + 1;
+		cksum = htonl(cksum);
+		key_sched(kdata.session,schedule);
+		if ((length = krb_mk_safe((u_char *)&cksum, out_buf, sizeof(cksum),
+					  &kdata.session,&ctrl_addr, &his_addr)) == -1) {
+			secure_error("ADAT: krb_mk_safe failed");
+			return(0);
+		}
+		if (length >= (FTP_BUFSIZ - sizeof("ADAT=")) / 4 * 3) {
+			secure_error("ADAT: reply too long");
+			return(0);
+		}
+
+		kerror = radix_encode(out_buf, buf, &length, 0);
+		if (kerror) {
+			secure_error("Couldn't encode ADAT reply (%s)",
+				     radix_error(kerror));
+			return(0);
+		}
+		reply(235, "ADAT=%s", buf);
+		/* Kerberos V4 authentication succeeded */
+		auth_type = temp_auth_type;
+		temp_auth_type = NULL;
+		return(1);
+	}
+#endif /* KRB5_KRB4_COMPAT */
+#ifdef GSSAPI
+	if (strcmp(temp_auth_type, "GSSAPI") == 0) {
+		int replied = 0;
+		int found = 0;
+		gss_cred_id_t server_creds, deleg_creds;
+		gss_name_t client;
+		OM_uint32 ret_flags;
+		int rad_len;
+		gss_buffer_desc name_buf;
+		gss_name_t server_name;
+		OM_uint32 acquire_maj, acquire_min, accept_maj, accept_min,
+				stat_maj, stat_min;
+		gss_OID mechid;
+		gss_buffer_desc tok, out_tok;
+		char gbuf[FTP_BUFSIZ];
+		u_char gout_buf[FTP_BUFSIZ];
+		char localname[MAXHOSTNAMELEN];
+		char service_name[MAXHOSTNAMELEN+10];
+		char **gservice;
+		struct hostent *hp;
+
+
+		kerror = radix_encode(adata, gout_buf, &length, 1);
+		if (kerror) {
+			reply(501, "Couldn't decode ADAT (%s)",
+			      radix_error(kerror));
+			syslog(LOG_ERR, "Couldn't decode ADAT (%s)",
+			       radix_error(kerror));
+			return(0);
+		}
+		tok.value = gout_buf;
+		tok.length = length;
+
+		if (gethostname(localname, MAXHOSTNAMELEN)) {
+			reply(501, "couldn't get local hostname (%d)\n", errno);
+			syslog(LOG_ERR, "Couldn't get local hostname (%d)", errno);
+			return 0;
+		}
+		if (!(hp = gethostbyname(localname))) {
+			reply(501, "couldn't canonicalize local hostname\n");
+			syslog(LOG_ERR, "Couldn't canonicalize local hostname");
+			return 0;
+		}
+		strncpy(localname, hp->h_name, sizeof(localname) - 1);
+		localname[sizeof(localname) - 1] = '\0';
+
+		for (gservice = gss_services; *gservice; gservice++) {
+			sprintf(service_name, "%s@%s", *gservice, localname);
+			name_buf.value = service_name;
+			name_buf.length = strlen(name_buf.value) + 1;
+			if (debug)
+				syslog(LOG_INFO, "importing <%s>", service_name);
+			stat_maj = gss_import_name(&stat_min, &name_buf, 
+						   gss_nt_service_name,
+						   &server_name);
+			if (stat_maj != GSS_S_COMPLETE) {
+				reply_gss_error(501, stat_maj, stat_min,
+						"importing name");
+				syslog(LOG_ERR, "gssapi error importing name");
+				return 0;
+			}
+			
+			acquire_maj = gss_acquire_cred(&acquire_min, server_name, 0,
+						       GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+						       &server_creds, NULL, NULL);
+			(void) gss_release_name(&stat_min, &server_name);
+
+			if (acquire_maj != GSS_S_COMPLETE)
+				continue;
+
+			found++;
+
+			gcontext = GSS_C_NO_CONTEXT;
+
+			accept_maj = gss_accept_sec_context(&accept_min,
+							    &gcontext, /* context_handle */
+							    server_creds, /* verifier_cred_handle */
+							    &tok, /* input_token */
+							    GSS_C_NO_CHANNEL_BINDINGS, /* channel bindings */
+							    &client, /* src_name */
+							    &mechid, /* mech_type */
+							    &out_tok, /* output_token */
+							    &ret_flags,
+							    NULL, 	/* ignore time_rec */
+							    &deleg_creds  /* forwarded credentials */
+							    );
+			if (accept_maj==GSS_S_COMPLETE||accept_maj==GSS_S_CONTINUE_NEEDED)
+				break;
+		}
+
+		if (found) {
+			if (accept_maj!=GSS_S_COMPLETE && accept_maj!=GSS_S_CONTINUE_NEEDED) {
+				reply_gss_error(535, accept_maj, accept_min,
+						"accepting context");
+				syslog(LOG_ERR, "failed accepting context");
+				(void) gss_release_cred(&stat_min, &server_creds);
+				if (ret_flags & GSS_C_DELEG_FLAG)
+					(void) gss_release_cred(&stat_min,
+								&deleg_creds);
+				return 0;
+			}
+		} else {
+			/* Kludge to make sure the right error gets reported, so we don't *
+			 * get those nasty "error: no error" messages.			  */
+			if(stat_maj != GSS_S_COMPLETE)
+			        reply_gss_error(501, stat_maj, stat_min,
+						"acquiring credentials");
+			else
+			        reply_gss_error(501, acquire_maj, acquire_min,
+						"acquiring credentials");
+			syslog(LOG_ERR, "gssapi error acquiring credentials");
+			return 0;
+		}
+
+		if (out_tok.length) {
+			if (out_tok.length >= ((FTP_BUFSIZ - sizeof("ADAT="))
+					       / 4 * 3)) {
+				secure_error("ADAT: reply too long");
+				syslog(LOG_ERR, "ADAT: reply too long");
+				(void) gss_release_cred(&stat_min, &server_creds);
+				if (ret_flags & GSS_C_DELEG_FLAG)
+					(void) gss_release_cred(&stat_min,
+								&deleg_creds);
+				return(0);
+			}
+
+			rad_len = out_tok.length;
+			kerror = radix_encode(out_tok.value, gbuf, 
+					      &rad_len, 0);
+			out_tok.length = rad_len;
+			if (kerror) {
+				secure_error("Couldn't encode ADAT reply (%s)",
+					     radix_error(kerror));
+				syslog(LOG_ERR, "couldn't encode ADAT reply");
+				(void) gss_release_cred(&stat_min, &server_creds);
+				if (ret_flags & GSS_C_DELEG_FLAG)
+					(void) gss_release_cred(&stat_min,
+								&deleg_creds);
+				return(0);
+			}
+			if (accept_maj == GSS_S_COMPLETE) {
+				reply(235, "ADAT=%s", gbuf);
+			} else {
+				/* If the server accepts the security data, and
+				   requires additional data, it should respond
+				   with reply code 335. */
+				reply(335, "ADAT=%s", gbuf);
+			}
+			replied = 1;
+			(void) gss_release_buffer(&stat_min, &out_tok);
+		}
+		if (accept_maj == GSS_S_COMPLETE) {
+			/* GSSAPI authentication succeeded */
+			stat_maj = gss_display_name(&stat_min, client,
+						    &client_name, &mechid);
+			if (stat_maj != GSS_S_COMPLETE) {
+				/* "If the server rejects the security data (if
+				   a checksum fails, for instance), it should 
+				   respond with reply code 535." */
+				reply_gss_error(535, stat_maj, stat_min,
+						"extracting GSSAPI identity name");
+				log_gss_error(LOG_ERR, stat_maj, stat_min,
+					      "gssapi error extracting identity");
+				(void) gss_release_cred(&stat_min, &server_creds);
+				if (ret_flags & GSS_C_DELEG_FLAG)
+					(void) gss_release_cred(&stat_min,
+								&deleg_creds);
+				return 0;
+			}
+			auth_type = temp_auth_type;
+			temp_auth_type = NULL;
+
+			(void) gss_release_cred(&stat_min, &server_creds);
+			if (ret_flags & GSS_C_DELEG_FLAG) {
+			  if (want_creds)
+			    ftpd_gss_convert_creds(client_name.value,
+						   deleg_creds);
+			  (void) gss_release_cred(&stat_min, &deleg_creds);
+			}
+
+			/* If the server accepts the security data, but does
+			   not require any additional data (i.e., the security
+			   data exchange has completed successfully), it must
+			   respond with reply code 235. */
+			if (!replied)
+			  {
+			    if (ret_flags & GSS_C_DELEG_FLAG && !have_creds)
+			      reply(235, "GSSAPI Authentication succeeded, but could not accept forwarded credentials");
+			    else
+			      reply(235, "GSSAPI Authentication succeeded");
+			  }
+				
+			return(1);
+		} else if (accept_maj == GSS_S_CONTINUE_NEEDED) {
+			/* If the server accepts the security data, and
+			   requires additional data, it should respond with
+			   reply code 335. */
+			if (!replied)
+			    reply(335, "more data needed");
+			(void) gss_release_cred(&stat_min, &server_creds);
+			if (ret_flags & GSS_C_DELEG_FLAG)
+			  (void) gss_release_cred(&stat_min, &deleg_creds);
+			return(0);
+		} else {
+			/* "If the server rejects the security data (if 
+			   a checksum fails, for instance), it should 
+			   respond with reply code 535." */
+			reply_gss_error(535, stat_maj, stat_min, 
+					"GSSAPI failed processing ADAT");
+			syslog(LOG_ERR, "GSSAPI failed processing ADAT");
+			(void) gss_release_cred(&stat_min, &server_creds);
+			if (ret_flags & GSS_C_DELEG_FLAG)
+			  (void) gss_release_cred(&stat_min, &deleg_creds);
+			return(0);
+		}
+	}
+#endif /* GSSAPI */
+	/* Other auth types go here ... */
+	/* Also need to check authorization, but that is done in user() */
+	return(0);
+}
+
+static char *onefile[] = {
+	"",
+	0
+};
+
+/* returns:
+ *	n>=0 on success
+ *	-1 on error
+ *	-2 on security error
+ *
+ * XXX callers need to limit total length of output string to
+ * FTP_BUFSIZ
+ */
+#ifdef STDARG
+static int
+secure_fprintf(FILE *stream, char *fmt, ...)
+#else
+static int
+secure_fprintf(stream, fmt, p1, p2, p3, p4, p5)
+FILE *stream;
+char *fmt;
+#endif
+{
+        char s[FTP_BUFSIZ];
+        int rval;
+#ifdef STDARG
+        va_list ap;
+
+        va_start(ap, fmt);
+        if (dlevel == PROT_C) rval = vfprintf(stream, fmt, ap);
+        else {
+                vsprintf(s, fmt, ap);
+                rval = secure_write(fileno(stream), s, strlen(s));
+        }
+        va_end(ap);
+
+        return(rval);
+#else
+        if (dlevel == PROT_C)
+                return(fprintf(stream, fmt, p1, p2, p3, p4, p5));
+        sprintf(s, fmt, p1, p2, p3, p4, p5);
+        return(secure_write(fileno(stream), s, strlen(s)));
+#endif
+}
+
+void
+send_file_list(whichfiles)
+	char *whichfiles;
+{
+	struct stat st;
+	DIR *dirp = NULL;
+	struct dirent *dir;
+	FILE *volatile dout = NULL;
+	register char **volatile dirlist, *dirname;
+	volatile int simple = 0;
+#ifndef strpbrk
+	char *strpbrk();
+#endif
+	volatile int ret = 0;
+
+	if (strpbrk(whichfiles, "~{[*?") != NULL) {
+		extern char **ftpglob(), *globerr;
+
+		globerr = NULL;
+		dirlist = ftpglob(whichfiles);
+		if (globerr != NULL) {
+			reply(550, globerr);
+			return;
+		} else if (dirlist == NULL) {
+			errno = ENOENT;
+			perror_reply(550, whichfiles);
+			return;
+		}
+	} else {
+		onefile[0] = whichfiles;
+		dirlist = onefile;
+		simple = 1;
+	}
+
+	if (sigsetjmp(urgcatch, 1)) {
+		transflag = 0;
+		(void)secure_flush(fileno(dout));
+		return;
+	}
+	while ((dirname = *dirlist++)) {
+		if (stat(dirname, &st) < 0) {
+			/*
+			 * If user typed "ls -l", etc, and the client
+			 * used NLST, do what the user meant.
+			 */
+			if (dirname[0] == '-' && *dirlist == NULL &&
+			    transflag == 0) {
+				retrieve("/bin/ls %s", dirname);
+				return;
+			}
+			perror_reply(550, whichfiles);
+			if (dout != NULL) {
+				(void) fclose(dout);
+				transflag = 0;
+				data = -1;
+				pdata = -1;
+			}
+			return;
+		}
+
+		if ((st.st_mode&S_IFMT) == S_IFREG) {
+			if (dout == NULL) {
+				dout = dataconn("file list", (off_t)-1, "w");
+				if (dout == NULL)
+					return;
+				transflag++;
+			}
+			if ((ret = secure_fprintf(dout, "%s%s\n", dirname,
+				type == TYPE_A ? "\r" : "")) < 0)
+					goto data_err;
+			byte_count += strlen(dirname) + 1;
+			continue;
+		} else if ((st.st_mode&S_IFMT) != S_IFDIR)
+			continue;
+
+		if ((dirp = opendir(dirname)) == NULL)
+			continue;
+
+		while ((dir = readdir(dirp)) != NULL) {
+			char nbuf[MAXPATHLEN];
+
+			if (dir->d_name[0] == '.' && dir->d_name[1] == '\0')
+				continue;
+			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
+			    dir->d_name[2] == '\0')
+				continue;
+
+			if (strlen(dirname) + strlen(dir->d_name)
+			    + 1 /* slash */
+			    + 2	/* CRLF */
+			    + 1 > sizeof(nbuf)) {
+				syslog(LOG_ERR,
+				       "send_file_list: pathname too long");
+				ret = -2; /* XXX */
+				goto data_err;
+			}
+			sprintf(nbuf, "%s/%s", dirname, dir->d_name);
+
+			/*
+			 * We have to do a stat to insure it's
+			 * not a directory or special file.
+			 */
+			if (simple || (stat(nbuf, &st) == 0 &&
+			    (st.st_mode&S_IFMT) == S_IFREG)) {
+				if (dout == NULL) {
+					dout = dataconn("file list", (off_t)-1,
+						"w");
+					if (dout == NULL)
+						return;
+					transflag++;
+				}
+				if (nbuf[0] == '.' && nbuf[1] == '/')
+				{
+					if ((ret = secure_fprintf(dout, "%s%s\n", &nbuf[2],
+						type == TYPE_A ? "\r" : "")) < 0)
+							goto data_err;
+				}
+				else
+					if ((ret = secure_fprintf(dout, "%s%s\n", nbuf,
+						type == TYPE_A ? "\r" : "")) < 0)
+							goto data_err;
+				byte_count += strlen(nbuf) + 1;
+			}
+		}
+		(void) closedir(dirp);
+	}
+	if (dout != NULL ) {
+	  ret = secure_write(fileno(dout), "", 0);
+	  if (ret >= 0)
+	    ret = secure_flush(fileno(dout));
+	}
+data_err:
+	if (dout == NULL)
+		reply(550, "No files found.");
+	else if (ferror(dout) != 0 || ret == EOF)
+		perror_reply(550, "Data connection");
+	else if (ret != -2)
+		reply(226, "Transfer complete.");
+
+	transflag = 0;
+	if (dout != NULL)
+	  (void) fclose(dout);
+	data = -1;
+	pdata = -1;
+}
+
+#ifdef SETPROCTITLE
+/*
+ * clobber argv so ps will show what we're doing.
+ * (stolen from sendmail)
+ * warning, since this is usually started from inetd.conf, it
+ * often doesn't have much of an environment or arglist to overwrite.
+ */
+
+setproctitle(buf)
+char *buf;
+{
+	register char *p, *bp, ch;
+	register int i;
+
+	/* make ps print our process name */
+	p = Argv[0];
+	*p++ = '-';
+
+	i = strlen(buf);
+	if (i > LastArgv - p - 2) {
+		i = LastArgv - p - 2;
+		buf[i] = '\0';
+	}
+	bp = buf;
+	while (ch = *bp++)
+		if (ch != '\n' && ch != '\r')
+			*p++ = ch;
+	while (p < LastArgv)
+		*p++ = ' ';
+}
+#endif /* SETPROCTITLE */
+
+#ifdef GSSAPI
+/* A more general callback would probably use a void*, but currently I
+   only need an int in both cases.  */
+static void with_gss_error_text(void (*cb)(const char *, int, int),
+				OM_uint32 maj_stat, OM_uint32 min_stat,
+				int misc);
+
+static void
+log_gss_error_1(const char *msg, int severity, int is_major)
+{
+    syslog(severity, "... GSSAPI error %s: %s",
+	   is_major ? "major" : "minor", msg);
+}
+
+static void
+log_gss_error(int severity, OM_uint32 maj_stat, OM_uint32 min_stat,
+	      const char *s)
+{
+    syslog(severity, s);
+    with_gss_error_text(log_gss_error_1, maj_stat, min_stat, severity);
+}
+
+static void
+reply_gss_error_1(const char *msg, int code, int is_major)
+{
+    lreply(code, "GSSAPI error %s: %s",
+	   is_major ? "major" : "minor", msg);
+}
+
+void
+reply_gss_error(int code, OM_uint32 maj_stat, OM_uint32 min_stat, char *s)
+{
+    with_gss_error_text(reply_gss_error_1, maj_stat, min_stat, code);
+    reply(code, "GSSAPI error: %s", s);
+}
+
+static void with_gss_error_text(void (*cb)(const char *, int, int),
+				OM_uint32 maj_stat, OM_uint32 min_stat,
+				int misc)
+{
+	/* a lot of work just to report the error */
+	OM_uint32 gmaj_stat, gmin_stat;
+	gss_buffer_desc msg;
+	OM_uint32 msg_ctx;
+	msg_ctx = 0;
+	while (!msg_ctx) {
+		gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
+					       GSS_C_GSS_CODE,
+					       GSS_C_NULL_OID,
+					       &msg_ctx, &msg);
+		if ((gmaj_stat == GSS_S_COMPLETE)||
+		    (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
+			(*cb)((char*)msg.value, misc, 1);
+			(void) gss_release_buffer(&gmin_stat, &msg);
+		}
+		if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
+			break;
+	}
+	msg_ctx = 0;
+	while (!msg_ctx) {
+		gmaj_stat = gss_display_status(&gmin_stat, min_stat,
+					       GSS_C_MECH_CODE,
+					       GSS_C_NULL_OID,
+					       &msg_ctx, &msg);
+		if ((gmaj_stat == GSS_S_COMPLETE)||
+		    (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
+			(*cb)((char*)msg.value, misc, 0);
+			(void) gss_release_buffer(&gmin_stat, &msg);
+		}
+		if (gmaj_stat != GSS_S_CONTINUE_NEEDED)
+			break;
+	}
+}
+
+void
+secure_gss_error(maj_stat, min_stat, s)
+OM_uint32 maj_stat, min_stat;
+char *s;
+{
+  reply_gss_error(535, maj_stat, min_stat, s);
+  return;
+}
+
+
+/* ftpd_gss_userok -- hide details of getting the name and verifying it */
+/* returns 0 for OK */
+static int
+ftpd_gss_userok(gclient_name, name)
+	gss_buffer_t gclient_name;
+	char *name;
+{
+	int retval = -1;
+	krb5_principal p;
+	
+	if (krb5_parse_name(kcontext, gclient_name->value, &p) != 0)
+		return -1;
+	if (krb5_kuserok(kcontext, p, name))
+		retval = 0;
+	else 
+		retval = 1;
+	krb5_free_principal(kcontext, p);
+	return retval;
+}
+
+/* ftpd_gss_convert_creds -- write out forwarded creds */
+/* (code lifted from login.krb5) */
+static void
+ftpd_gss_convert_creds(name, creds)
+	char *name;
+	gss_cred_id_t creds;
+{
+	OM_uint32 major_status, minor_status;
+	krb5_principal me;
+	char ccname[MAXPATHLEN];
+#ifdef KRB5_KRB4_COMPAT
+	krb5_principal kpcserver;
+	krb5_creds increds, *v5creds;
+	CREDENTIALS v4creds;
+#endif
+
+	/* Set up ccache */
+	if (krb5_parse_name(kcontext, name, &me))
+		return;
+
+	sprintf(ccname, "FILE:/tmp/krb5cc_ftpd%ld", (long) getpid());
+	if (krb5_cc_resolve(kcontext, ccname, &ccache))
+		return;
+	if (krb5_cc_initialize(kcontext, ccache, me))
+		return;
+
+	/* Copy GSS creds into ccache */
+	major_status = gss_krb5_copy_ccache(&minor_status, creds, ccache);
+	if (major_status != GSS_S_COMPLETE)
+		goto cleanup;
+
+#ifdef KRB5_KRB4_COMPAT
+	/* Convert krb5 creds to krb4 */
+
+	if (krb5_build_principal_ext(kcontext, &kpcserver, 
+				     krb5_princ_realm(kcontext, me)->length,
+				     krb5_princ_realm(kcontext, me)->data,
+				     6, "krbtgt",
+				     krb5_princ_realm(kcontext, me)->length,
+				     krb5_princ_realm(kcontext, me)->data,
+				     0))
+		goto cleanup;
+
+	memset((char *) &increds, 0, sizeof(increds));
+	increds.client = me;
+	increds.server = kpcserver;
+	increds.times.endtime = 0;
+	increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+	if (krb5_get_credentials(kcontext, 0, ccache, &increds, &v5creds))
+		goto cleanup;
+	if (krb524_convert_creds_kdc(kcontext, v5creds, &v4creds))
+		goto cleanup;
+
+	sprintf(ccname, "%s_ftpd%ld", TKT_ROOT, (long) getpid());
+	krb_set_tkt_string(ccname);
+
+	if (in_tkt(v4creds.pname, v4creds.pinst) != KSUCCESS)
+		goto cleanup;
+
+	if (krb_save_credentials(v4creds.service, v4creds.instance,
+				 v4creds.realm, v4creds.session,
+				 v4creds.lifetime, v4creds.kvno,
+				 &(v4creds.ticket_st), v4creds.issue_date))
+		goto cleanup_v4;
+#endif /* KRB5_KRB4_COMPAT */
+	have_creds = 1;
+	return;
+
+#ifdef KRB5_KRB4_COMPAT
+cleanup_v4:
+	dest_tkt();
+#endif
+cleanup:
+	krb5_cc_destroy(kcontext, ccache);
+}
+
+
+#endif /* GSSAPI */
+
diff --git a/mechglue/src/appl/gssftp/ftpd/ftpd_var.h b/mechglue/src/appl/gssftp/ftpd/ftpd_var.h
new file mode 100644
index 000000000..07fb14a63
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/ftpd_var.h
@@ -0,0 +1,97 @@
+/*
+ * appl/gssftp/ftpd/ftp_var.h
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Prototypes for various functions in the ftpd sources.
+ */
+
+#ifndef FTPD_VAR_H__
+#define FTPD_VAR_H__
+
+/* Prototypes */
+
+#ifdef GSSAPI
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#endif
+
+/* radix.c */
+char *radix_error (int);
+int radix_encode (unsigned char *, unsigned char *, int *, int);
+
+/* ftpd.c */
+void ack(char *);
+int auth_data(char *);
+void auth(char *);
+void cwd(char *);
+void delete_file(char *);
+void dologout(int);
+void fatal(char *);
+void makedir(char *);
+void nack(char *);
+void pass(char *);
+void passive(void);
+void perror_reply(int, char *);
+void pwd(void);
+void removedir(char *);
+void renamecmd(char *, char *);
+char *renamefrom(char *);
+void retrieve(char *, char *);
+void send_file_list(char *);
+void setdlevel(int);
+void statcmd(void);
+void statfilecmd(char *);
+void store_file(char *, char *, int);
+void user(char *);
+void yyerror(char *);
+
+#ifdef GSSAPI
+void
+reply_gss_error(int, OM_uint32, OM_uint32, char *);
+#endif
+
+
+#if defined(STDARG) || (defined(__STDC__) && ! defined(VARARGS)) || defined(HAVE_STDARG_H)
+extern void reply(int, char *, ...)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+     __attribute__ ((__format__ (__printf__, 2, 3)))
+#endif
+     ;
+extern void lreply(int, char *, ...)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+     __attribute__ ((__format__ (__printf__, 2, 3)))
+#endif
+     ;
+#endif
+
+
+/* ftpcmd.y */
+void upper(char *);
+char *getline(char *, int, FILE *);
+#endif /* FTPD_VAR_H__ */
+
+/* popen.c */
+FILE * ftpd_popen(char *, char *);
+int ftpd_pclose(FILE *);
diff --git a/mechglue/src/appl/gssftp/ftpd/logwtmp.c b/mechglue/src/appl/gssftp/ftpd/logwtmp.c
new file mode 100644
index 000000000..06b97b986
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/logwtmp.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)logwtmp.c	5.7 (Berkeley) 2/25/91";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifdef WTMP_FILE
+#define WTMPFILE WTMP_FILE
+#else
+#ifdef _PATH_WTMP
+#define WTMPFILE _PATH_WTMP
+#endif 	/* _PATH_WTMP  */
+#endif	/* WTMP_FILE */
+
+#ifndef WTMPFILE
+#define	WTMPFILE	"/usr/adm/wtmp"
+#endif
+
+static int fd = -1;
+
+/*
+ * Modified version of logwtmp that holds wtmp file open
+ * after first call, for use with ftp (which may chroot
+ * after login, but before logout).
+ */
+void ftp_logwtmp(line, name, host)
+	char *line, *name, *host;
+{
+	struct utmp ut;
+	struct stat buf;
+	time_t time();
+
+	if (fd < 0 && (fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
+		return;
+	if (fstat(fd, &buf) == 0) {
+		(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+		(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+#ifndef NO_UT_HOST
+		(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+#endif
+		(void)time(&ut.ut_time);
+		if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+		    sizeof(struct utmp))
+			(void)ftruncate(fd, buf.st_size);
+	}
+}
diff --git a/mechglue/src/appl/gssftp/ftpd/pathnames.h b/mechglue/src/appl/gssftp/ftpd/pathnames.h
new file mode 100644
index 000000000..41398bc5f
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/pathnames.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pathnames.h	5.2 (Berkeley) 6/1/90
+ */
+
+#define	_PATH_FTPUSERS_DEFAULT	"/etc/ftpusers"
diff --git a/mechglue/src/appl/gssftp/ftpd/popen.c b/mechglue/src/appl/gssftp/ftpd/popen.c
new file mode 100644
index 000000000..e9e589594
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/popen.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)popen.c	5.9 (Berkeley) 2/25/91";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ftpd_var.h"
+
+/*
+ * Special version of popen which avoids call to shell.  This insures noone
+ * may create a pipe to a hidden program as a side effect of a list or dir
+ * command.
+ */
+static int *pids;
+static int fds;
+
+#define MAX_ARGV	100
+#define MAX_GARGV	1000
+
+FILE *
+ftpd_popen(program, type)
+	char *program, *type;
+{
+	register char *cp;
+	FILE *volatile iop;
+	int argc, gargc, pdes[2], pid;
+	char **pop, *argv[MAX_ARGV], *gargv[MAX_GARGV], *vv[2];
+	extern char **ftpglob(), **copyblk();
+	extern void blkfree(char **);
+
+	if ((*type != 'r' && *type != 'w') || type[1])
+		return(NULL);
+
+	if (!pids) {
+		if ((fds = getdtablesize()) <= 0)
+			return(NULL);
+		if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
+			return(NULL);
+		memset((char *)pids, 0, fds * sizeof(int));
+	}
+	if (pipe(pdes) < 0)
+		return(NULL);
+
+	/* break up string into pieces */
+	for (argc = 0, cp = program; argc < MAX_ARGV - 1; cp = NULL)
+		if (!(argv[argc++] = strtok(cp, " \t\n")))
+			break;
+	argv[MAX_ARGV-1] = NULL;
+	for (argc = 0; argv[argc]; argc++)
+		argv[argc] = strdup(argv[argc]);
+
+	/* glob each piece */
+	gargv[0] = argv[0];
+	for (gargc = argc = 1; argv[argc]; argc++) {
+		if (!(pop = ftpglob(argv[argc]))) {	/* globbing failed */
+			vv[0] = argv[argc];
+			vv[1] = NULL;
+			pop = copyblk(vv);
+		}
+		argv[argc] = (char *)pop;		/* save to free later */
+		while (*pop && gargc < MAX_GARGV)
+			gargv[gargc++] = *pop++;
+	}
+	gargv[gargc] = NULL;
+
+	iop = NULL;
+	switch(pid = fork()) {
+	case -1:			/* error */
+		(void)close(pdes[0]);
+		(void)close(pdes[1]);
+		goto pfree;
+		/* NOTREACHED */
+	case 0:				/* child */
+		if (*type == 'r') {
+			if (pdes[1] != 1) {
+				dup2(pdes[1], 1);
+				dup2(pdes[1], 2);	/* stderr, too! */
+				(void)close(pdes[1]);
+			}
+			(void)close(pdes[0]);
+		} else {
+			if (pdes[0] != 0) {
+				dup2(pdes[0], 0);
+				(void)close(pdes[0]);
+			}
+			(void)close(pdes[1]);
+		}
+		execv(gargv[0], gargv);
+		_exit(1);
+	}
+	/* parent; assume fdopen can't fail...  */
+	if (*type == 'r') {
+		iop = fdopen(pdes[0], type);
+		(void)close(pdes[1]);
+	} else {
+		iop = fdopen(pdes[1], type);
+		(void)close(pdes[0]);
+	}
+	pids[fileno(iop)] = pid;
+
+pfree:	for (argc = 1; argv[argc] != NULL; argc++) {
+		blkfree((char **)argv[argc]);
+		free((char *)argv[argc]);
+	}
+	return(iop);
+}
+
+int
+ftpd_pclose(iop)
+	FILE *iop;
+{
+	register int fdes;
+#ifdef USE_SIGPROCMASK
+	sigset_t old, new;
+#else
+	int omask;
+#endif
+#ifdef WAIT_USES_INT
+	int stat_loc;
+#else
+	union wait stat_loc;
+#endif
+	int pid;
+
+	/*
+	 * pclose returns -1 if stream is not associated with a
+	 * `popened' command, or, if already `pclosed'.
+	 */
+	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
+		return(-1);
+	(void)fclose(iop);
+#ifdef USE_SIGPROCMASK
+	sigemptyset(&old);
+	sigemptyset(&new);
+	sigaddset(&new,SIGINT);
+	sigaddset(&new,SIGQUIT);
+	sigaddset(&new,SIGHUP);
+	sigprocmask(SIG_BLOCK, &new, &old);
+	while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1);
+	sigprocmask(SIG_SETMASK, &old, NULL);
+#else
+	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
+	while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1);
+	sigsetmask(omask);
+#endif
+	pids[fdes] = 0;
+#ifdef WAIT_USES_INT
+	return(pid == -1 ? -1 : stat_loc);
+#else
+	return(pid == -1 ? -1 : stat_loc.w_status);
+#endif
+}
diff --git a/mechglue/src/appl/gssftp/ftpd/secure.h b/mechglue/src/appl/gssftp/ftpd/secure.h
new file mode 100644
index 000000000..97fd0c752
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/secure.h
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+#define CRED_DECL	extern AUTH_DAT kdata;
+#define SESSION		&kdata.session
+#define myaddr		data_source
+#define hisaddr		data_dest
+
+int secure_flush (int);
+int secure_putc (int, FILE *);
+int secure_getc (FILE *);
+int secure_write (int, unsigned char *, unsigned int);
+int secure_read (int, char *, unsigned int);
+void secure_gss_error (OM_uint32 maj_stat, OM_uint32 min_stat, char *s);
+
+#if defined(STDARG) || (defined(__STDC__) && ! defined(VARARGS)) || defined(HAVE_STDARG_H)
+void secure_error(char *, ...);
+#else
+void secure_error();
+#endif
diff --git a/mechglue/src/appl/gssftp/ftpd/vers.c b/mechglue/src/appl/gssftp/ftpd/vers.c
new file mode 100644
index 000000000..76846bda7
--- /dev/null
+++ b/mechglue/src/appl/gssftp/ftpd/vers.c
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)vers.c	5.1 (Berkeley) 6/24/90";
+#endif /* not lint */
+
+char version[] = "Version 5.60";
diff --git a/mechglue/src/appl/sample/.Sanitize b/mechglue/src/appl/sample/.Sanitize
new file mode 100644
index 000000000..335f5ed3f
--- /dev/null
+++ b/mechglue/src/appl/sample/.Sanitize
@@ -0,0 +1,39 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+sample.h
+sclient
+sserver
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/sample/ChangeLog b/mechglue/src/appl/sample/ChangeLog
new file mode 100644
index 000000000..404dce130
--- /dev/null
+++ b/mechglue/src/appl/sample/ChangeLog
@@ -0,0 +1,60 @@
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCAL_SUBDIRS): Renamed from MY_SUBDIRS.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Removed and tests moved up to appl/configure.in
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS definition to control the directories
+		which are recursively descended by the Makefile.
+
+Wed Feb 18 15:31:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Thu Feb 12 16:14:53 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented out AC_OUTPUT to force autoreconf to
+	rebuild the configure script.
+
+Mon Feb  2 16:47:05 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* configure.in: Create the makefiles for all of the subdirectories
+		and move all of the configure.in tests from the
+		subdirectories into this configure.in.
+	
+Fri Jul 7 15:45:38 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* Makefile.in - Remove LDFLAGS.
+
+Fri Jun  9 18:27:34 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Tue Feb 28 01:58:05 1995  John Gilmore  (gnu at toad.com)
+
+	* sample.h:  Avoid <krb5/...> includes.
+
diff --git a/mechglue/src/appl/sample/Makefile.in b/mechglue/src/appl/sample/Makefile.in
new file mode 100644
index 000000000..a580359e4
--- /dev/null
+++ b/mechglue/src/appl/sample/Makefile.in
@@ -0,0 +1,5 @@
+thisconfigdir=./..
+myfulldir=appl/sample
+mydir=sample
+LOCAL_SUBDIRS = sclient sserver
+BUILDTOP=$(REL)..$(S)..
diff --git a/mechglue/src/appl/sample/sample.h b/mechglue/src/appl/sample/sample.h
new file mode 100644
index 000000000..6c81d9351
--- /dev/null
+++ b/mechglue/src/appl/sample/sample.h
@@ -0,0 +1,36 @@
+/*
+ * appl/sample/sample.h
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Common definitions for the sample client/server.
+ */
+
+#ifndef KRB5_SAMPLE__
+#define KRB5_SAMPLE__
+
+#define SAMPLE_SERVICE "sample"
+#define SAMPLE_PORT "sample"
+#define SAMPLE_VERSION "KRB5_sample_protocol_v1.0"
+
+#endif /* KRB5_SAMPLE__ */
diff --git a/mechglue/src/appl/sample/sclient/.Sanitize b/mechglue/src/appl/sample/sclient/.Sanitize
new file mode 100644
index 000000000..d34f936e0
--- /dev/null
+++ b/mechglue/src/appl/sample/sclient/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+sclient.M
+sclient.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/sample/sclient/ChangeLog b/mechglue/src/appl/sample/sclient/ChangeLog
new file mode 100644
index 000000000..51a10942b
--- /dev/null
+++ b/mechglue/src/appl/sample/sclient/ChangeLog
@@ -0,0 +1,160 @@
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* sclient.c: Include fake-addrinfo.h.  Include stdlib.h
+	unconditionally.
+	(net_read): New function, borrowed from krb5_net_read.
+	(main): Use krb5_c_valid_cksumtype, net_read, getaddrinfo,
+	getnameinfo.  Try contacting each address for the host.
+
+2002-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* sclient.c: Include errno.h.
+
+2001-11-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* sclient.c (main): Use GETSOCKNAME_ARG3_TYPE instead of int.
+
+2001-01-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* sclient.c (main): Do not free auth_context unless
+	set. (krb5-appl/895 from tim.mann@compaq.com)
+
+2000-07-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* sclient.c:  Include unistd.h if present (for close prototype). 
+	Change variable named sin (shadows math library).
+
+2000-02-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* sclient.c (main): Return type of main should by int, not void.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS macro set to '.' to indicate that there
+		are no subdirectories to be processed by the Makefile.
+
+Wed Feb 18 15:32:24 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Dec 16 09:43:15 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* sclient.c (main): Free client principal and krb5_ap_rep_enc_part
+	    returned from krb5_sendauth when done using.
+
+Tue Feb  4 20:44:24 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Nov  7 15:25:03 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sclient.c (argv): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Tue Sep 10 14:09:01 1996  Tom Yu  <tlyu@mit.edu>
+
+	* sclient.M: remove ".so man1/header.doc"
+
+Mon Sep 18 05:05:48 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* sclient.c (main): Set the default service name to SAMPLE_SERVICE.
+
+Sat Sep 16 03:40:41 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sclient.c (main): Add an optional third argument which allows
+		the user to set the Kerberos service name to be used.
+
+Fri Jul 7 15:46:11 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling and LDFLAGS.
+	* configure.in - Add KRB5_LIBRARIES.
+
+Tue Jun 20 13:16:10 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: added missing check for stdlib.h
+
+Thu Jun 15 17:38:55 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Sat Jun 10 22:58:15 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* sclient.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:27:44 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed May 10 15:13:09 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* sclient.c: Include <stdlib.h> if present on system. Else define
+		malloc. 
+
+Fri Mar 24 23:49:22 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sclient.c (main): Initialize auth_context to NULL before calling
+	        sendauth().
+
+Fri Mar 10 11:09:34 1995  Chris Provenzano (proven@mit.edu)
+
+        * sclient.c Use new calling convention for krb5_sendauth().
+
+Thu Mar  2 12:27:22 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 11:56:51 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:58:39 1995  John Gilmore  (gnu at toad.com)
+
+	* sclient.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Tue Feb 14 15:30:55 1995 Chris Provenzano  (proven@mit.edu)
+
+        * kadmin.c Call krb5_sendauth() with new calling convention.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Mon Oct  3 19:16:02 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
+Wed Sep 28 23:09:00 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executable when library chages.
+
+
diff --git a/mechglue/src/appl/sample/sclient/Makefile.in b/mechglue/src/appl/sample/sclient/Makefile.in
new file mode 100644
index 000000000..868f678eb
--- /dev/null
+++ b/mechglue/src/appl/sample/sclient/Makefile.in
@@ -0,0 +1,19 @@
+thisconfigdir=./../..
+myfulldir=appl/sample/sclient
+mydir=sample/sclient
+
+BUILDTOP=$(REL)..$(S)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all:: sclient
+
+sclient: sclient.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o sclient sclient.o $(KRB5_BASE_LIBS)
+
+clean::
+	$(RM) sclient.o sclient
+
+install::
+	$(INSTALL_PROGRAM) sclient ${DESTDIR}$(CLIENT_BINDIR)/sclient
+	$(INSTALL_DATA) $(srcdir)/sclient.M ${DESTDIR}$(CLIENT_MANDIR)/sclient.1
diff --git a/mechglue/src/appl/sample/sclient/sclient.M b/mechglue/src/appl/sample/sclient/sclient.M
new file mode 100644
index 000000000..1b5a8d6b7
--- /dev/null
+++ b/mechglue/src/appl/sample/sclient/sclient.M
@@ -0,0 +1,38 @@
+.\" appl/sample/sclient/sclient.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" 
+.\"
+.TH SCLIENT 1
+.SH NAME
+sclient \- sample Kerberos version 5 client
+.SH SYNOPSIS
+.B sclient
+.I remotehost
+.br
+.SH DESCRIPTION
+.I sclient
+will contact a sample server (\fIsserver\fR(8)) and authenticate to it
+using Kerberos version 5 tickets, then display the server's response.
+.SH SEE ALSO
+kinit(1), sserver(8)
+.SH BUGS
diff --git a/mechglue/src/appl/sample/sclient/sclient.c b/mechglue/src/appl/sample/sclient/sclient.c
new file mode 100644
index 000000000..46877211b
--- /dev/null
+++ b/mechglue/src/appl/sample/sclient/sclient.c
@@ -0,0 +1,253 @@
+/*
+ * appl/sample/sclient/sclient.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Sample Kerberos v5 client.
+ *
+ * Usage: sample_client hostname
+ */
+
+#include "krb5.h"
+#include "com_err.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "fake-addrinfo.h" /* not everyone implements getaddrinfo yet */
+
+#include <signal.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+
+#include "../sample.h"
+
+#ifndef GETSOCKNAME_ARG3_TYPE
+#define GETSOCKNAME_ARG3_TYPE int
+#endif
+
+static int
+net_read(fd, buf, len)
+    int fd;
+    char *buf;
+    int len;
+{
+    int cc, len2 = 0;
+
+    do {
+	cc = SOCKET_READ((SOCKET)fd, buf, len);
+	if (cc < 0) {
+	    if (SOCKET_ERRNO == SOCKET_EINTR)
+		continue;
+		
+		/* XXX this interface sucks! */
+        errno = SOCKET_ERRNO;    
+               
+	    return(cc);		 /* errno is already set */
+	}		
+	else if (cc == 0) {
+	    return(len2);
+	} else {
+	    buf += cc;
+	    len2 += cc;
+	    len -= cc;
+	}
+    } while (len > 0);
+    return(len2);
+}
+
+int
+main(int argc, char *argv[])
+{
+    struct addrinfo *ap, aihints;
+    int aierr;
+    int sock;
+    krb5_context context;
+    krb5_data recv_data;
+    krb5_data cksum_data;
+    krb5_error_code retval;
+    krb5_ccache ccdef;
+    krb5_principal client, server;
+    krb5_error *err_ret;
+    krb5_ap_rep_enc_part *rep_ret;
+    krb5_auth_context auth_context = 0;
+    short xmitlen;
+    char *portstr;
+    char *service = SAMPLE_SERVICE;
+
+    if (argc != 2 && argc != 3 && argc != 4) {
+	fprintf(stderr, "usage: %s <hostname> [port] [service]\n",argv[0]);
+	exit(1);
+    }
+
+    retval = krb5_init_context(&context);
+    if (retval) {
+	    com_err(argv[0], retval, "while initializing krb5");
+	    exit(1);
+    }
+
+    (void) signal(SIGPIPE, SIG_IGN);
+
+    if (argc > 2)
+	portstr = argv[2];
+    else
+	portstr = SAMPLE_PORT;
+
+    memset(&aihints, 0, sizeof(aihints));
+    aihints.ai_socktype = SOCK_STREAM;
+    aierr = getaddrinfo(argv[1], portstr, &aihints, &ap);
+    if (aierr) {
+	fprintf(stderr, "%s: error looking up host '%s' port '%s'/tcp: %s\n",
+		argv[0], argv[1], portstr, gai_strerror(aierr));
+	exit(1);
+    }
+    if (ap == 0) {
+	/* Should never happen.  */
+	fprintf(stderr, "%s: error looking up host '%s' port '%s'/tcp: no addresses returned?\n",
+		argv[0], argv[1], portstr);
+	exit(1);
+    }
+
+    if (argc > 3) {
+	service = argv[3];
+    }
+
+    retval = krb5_sname_to_principal(context, argv[1], service,
+				     KRB5_NT_SRV_HST, &server);
+    if (retval) {
+	com_err(argv[0], retval, "while creating server name for host %s service %s",
+		argv[1], service);
+	exit(1);
+    }
+
+    /* set up the address of the foreign socket for connect() */
+    for (sock = -1; ap && sock == -1; ap = ap->ai_next) {
+	char abuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+	char mbuf[NI_MAXHOST + NI_MAXSERV + 64];
+	if (getnameinfo(ap->ai_addr, ap->ai_addrlen, abuf, sizeof(abuf),
+			pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
+	    memset(abuf, 0, sizeof(abuf));
+	    strncpy(abuf, "[error, cannot print address?]",
+		    sizeof(abuf)-1);
+	    strcpy(pbuf, "[?]");
+	}
+	sprintf(mbuf, "error contacting %s port %s", abuf, pbuf);
+	sock = socket(ap->ai_family, SOCK_STREAM, 0);
+	if (sock < 0) {
+	    fprintf(stderr, "%s: socket: %s\n", mbuf, strerror(errno));
+	    continue;
+	}
+	if (connect(sock, ap->ai_addr, ap->ai_addrlen) < 0) {
+	    fprintf(stderr, "%s: connect: %s\n", mbuf, strerror(errno));
+	    close(sock);
+	    sock = -1;
+	    continue;
+	}
+	/* connected, yay! */
+    }
+    if (sock == -1)
+	/* Already printed error message above.  */
+	exit(1);
+    printf("connected\n");
+
+    cksum_data.data = argv[1];
+    cksum_data.length = strlen(argv[1]);
+
+    retval = krb5_cc_default(context, &ccdef);
+    if (retval) {
+	com_err(argv[0], retval, "while getting default ccache");
+	exit(1);
+    }
+
+    retval = krb5_cc_get_principal(context, ccdef, &client);
+    if (retval) {
+	com_err(argv[0], retval, "while getting client principal name");
+	exit(1);
+    }
+    retval = krb5_sendauth(context, &auth_context, (krb5_pointer) &sock,
+			   SAMPLE_VERSION, client, server,
+			   AP_OPTS_MUTUAL_REQUIRED,
+			   &cksum_data,
+			   0,		/* no creds, use ccache instead */
+			   ccdef, &err_ret, &rep_ret, NULL);
+
+    krb5_free_principal(context, server);	/* finished using it */
+    krb5_free_principal(context, client);      
+    krb5_cc_close(context, ccdef);
+    if (auth_context) krb5_auth_con_free(context, auth_context);
+
+    if (retval && retval != KRB5_SENDAUTH_REJECTED) {
+	com_err(argv[0], retval, "while using sendauth");
+	exit(1);
+    }
+    if (retval == KRB5_SENDAUTH_REJECTED) {
+	/* got an error */
+	printf("sendauth rejected, error reply is:\n\t\"%*s\"\n",
+	       err_ret->text.length, err_ret->text.data);
+    } else if (rep_ret) {
+	/* got a reply */
+	krb5_free_ap_rep_enc_part(context, rep_ret);
+
+	printf("sendauth succeeded, reply is:\n");
+	if ((retval = net_read(sock, (char *)&xmitlen,
+			       sizeof(xmitlen))) <= 0) {
+	    if (retval == 0)
+		errno = ECONNABORTED;
+	    com_err(argv[0], errno, "while reading data from server");
+	    exit(1);
+	}
+	recv_data.length = ntohs(xmitlen);
+	if (!(recv_data.data = (char *)malloc((size_t) recv_data.length + 1))) {
+	    com_err(argv[0], ENOMEM,
+		    "while allocating buffer to read from server");
+	    exit(1);
+	}
+	if ((retval = net_read(sock, (char *)recv_data.data,
+			       recv_data.length)) <= 0) {
+	    if (retval == 0)
+		errno = ECONNABORTED;
+	    com_err(argv[0], errno, "while reading data from server");
+	    exit(1);
+	}
+	recv_data.data[recv_data.length] = '\0';
+	printf("reply len %d, contents:\n%s\n",
+	       recv_data.length,recv_data.data);
+	free(recv_data.data);
+    } else {
+	com_err(argv[0], 0, "no error or reply from sendauth!");
+	exit(1);
+    }
+    krb5_free_context(context);
+    exit(0);
+}
diff --git a/mechglue/src/appl/sample/sserver/.Sanitize b/mechglue/src/appl/sample/sserver/.Sanitize
new file mode 100644
index 000000000..da0dcd050
--- /dev/null
+++ b/mechglue/src/appl/sample/sserver/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+sserver.M
+sserver.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/sample/sserver/ChangeLog b/mechglue/src/appl/sample/sserver/ChangeLog
new file mode 100644
index 000000000..902f203e3
--- /dev/null
+++ b/mechglue/src/appl/sample/sserver/ChangeLog
@@ -0,0 +1,152 @@
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-11-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* sserver.c (main): Use GETPEERNAME_ARG3_TYPE instead of int.
+
+2000-07-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* sserver.c (main): Include unistd.h if present (for close
+	prototype).  Change variable named sin (shadows maht
+	library). Compiler warning cleanups.
+
+
+2000-02-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* sserver.c (main): Return type should be int, not void. Clenup
+	unused variables.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS macro set to '.' to indicate that there
+		are no subdirectories to be processed by the Makefile.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sserver.c (main): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Wed Feb 18 15:33:15 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Feb  4 20:47:55 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Dec  5 19:44:05 1996  Tom Yu  <tlyu@mit.edu>
+
+	* sserver.M: remove ref's to "/krb5" [PR 279]
+
+	* sserver.M: v5srvtab -> krb5.keytab; also kdb5_edit -> kadmin [PR
+	279]
+
+Thu Nov  7 15:24:43 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sserver.c (main): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Tue Sep 10 14:09:19 1996  Tom Yu  <tlyu@mit.edu>
+
+	* sserver.M: remove ".so man1/header.doc"
+
+Sat Sep 16 00:21:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sserver.c (main): Allow the user to specify the service instance
+		using the -s option.  Use SO_REUSEEADDR so that the port
+		can be immediately reused.  Free the context and
+		auth_context before exiting.
+
+Sat Jul 29 04:39:02 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* configure.in: Don't link with -lkadm.
+
+Fri Jul 7 15:47:04 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling and LDFLAGS.
+	* configure.in - Add KRB5_LIBRARIES and USE_KADM_LIBRARY.
+
+
+Thu Jun 15 17:39:17 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Sat Jun 10 22:58:40 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* sserver.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:28:33 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Sat Jun  3 17:20:28 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* sserver.c (main): If using inetd, set file descriptor to 0.
+
+Wed May 10 15:18:19 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* sserver.M: Document options.
+
+	* sserver.c: (main): Add options -p port, -S keytab for use by
+		dejagnu. Cleaned up warnings in compile.
+
+Wed May 03 03:30:51 1995  Chris Provenzano (proven@mit.edu)
+
+        * sserver.c: (krb5_recvauth()): No longer needs the rc_type arg.
+
+Tue Apr 25 21:41:46 1995 Chris Provenzano (proven@mit.edu)
+
+	* sserver.c: Initialize auth_context to NULL before using.
+
+Mon Mar 27 07:56:26 1995 Chris Provenzano (proven@mit.edu)
+
+        * sserver.c: Use new calling convention for krb5_recvauth().
+
+Thu Mar  2 12:27:36 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 11:57:12 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:59:17 1995  John Gilmore  (gnu at toad.com)
+
+	* sserver.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Mon Oct  3 19:16:14 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
+Wed Sep 28 23:49:10 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executable when library changes.
+
diff --git a/mechglue/src/appl/sample/sserver/Makefile.in b/mechglue/src/appl/sample/sserver/Makefile.in
new file mode 100644
index 000000000..32e8864ef
--- /dev/null
+++ b/mechglue/src/appl/sample/sserver/Makefile.in
@@ -0,0 +1,19 @@
+thisconfigdir=./../..
+myfulldir=appl/sample/sserver
+mydir=sample/sserver
+
+BUILDTOP=$(REL)..$(S)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all:: sserver
+
+sserver: sserver.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o sserver sserver.o $(KRB5_BASE_LIBS)
+
+clean::
+	$(RM) sserver.o sserver
+
+install::
+	$(INSTALL_PROGRAM) sserver ${DESTDIR}$(SERVER_BINDIR)/sserver
+	$(INSTALL_DATA) $(srcdir)/sserver.M ${DESTDIR}$(SERVER_MANDIR)/sserver.8
diff --git a/mechglue/src/appl/sample/sserver/sserver.M b/mechglue/src/appl/sample/sserver/sserver.M
new file mode 100644
index 000000000..4323fd11b
--- /dev/null
+++ b/mechglue/src/appl/sample/sserver/sserver.M
@@ -0,0 +1,130 @@
+.\" appl/sample/sserver/sserver.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH SSERVER 8
+.SH NAME
+sserver \- sample Kerberos version 5 server
+.SH SYNOPSIS
+.B sserver
+[
+.I \-p
+port ] [
+.I \-S
+keytab ] [
+.I server_port
+]
+.br
+.SH DESCRIPTION
+
+\fIsserver\fP and \fIsclient\fP are a simple demonstration
+client/server application.  When \fIsclient\fP connects to
+\fIsserver\fP, it performs a Kerberos authentication, and then
+\fIsserver\fP returns to \fIsclient\fP the Kerberos
+principal which was used for the Kerberos authentication.  It makes a
+good test that Kerberos has been successfully installed on a machine.
+.PP
+The service name used by \fIsserver\fP and \fIsclient\fP is
+\fBsample\fP.  Hence, \fIsserver\fP will require that there be a keytab
+entry for the service "sample/hostname.domain.name@REALM.NAME".  This
+keytab is generated using the
+.IR kadmin(8)
+program.  The keytab file is usually installed as "/etc/krb5.keytab".
+.PP
+The 
+.B \-S
+option allows for a different keytab than the default.
+.PP
+\fIsserver\fP is normally invoked out of 
+.IR inetd(8), 
+using a line in
+/etc/inetd.conf that looks like this:
+.PP
+sample  stream  tcp     nowait  root /usr/local/sbin/sserver	sserver
+.PP
+Since \fBsample\fP is normally not a port defined in /etc/services, you will
+usually have to add a line to /etc/services which looks like this:
+.PP
+sample          13135/tcp
+.PP
+When using \fIsclient,\fP you will first have to have an entry in the Kerberos
+database, by using 
+.IR kadmin(8),
+and then you have to get Kerberos
+tickets, by using 
+.IR kinit(8).  
+Also, if you are running the \fIsclient\fP
+program on a different host than the \fIsserver\fP it will be
+connecting to, be
+sure that both hosts have an entry in /etc/services for the \fBsample\fP tcp
+port, and that the same port number is in both files.
+.PP
+When you run sclient you should see something like this:
+.PP
+sendauth succeeded, reply is:
+.br
+reply len 32, contents:
+.br
+You are nlgilman@JIMI.MIT.EDU
+.br
+.SH COMMON ERROR MESSAGES
+
+1)  \fIkinit\fP returns the error:
+.PP
+kinit: Client not found in Kerberos database while getting initial credentials
+.PP
+This means that you didn't create an entry for your username in the
+Kerberos database.
+.PP
+2)  \fIsclient\fP returns the error:
+.PP
+unknown service sample/tcp; check /etc/services
+.PP
+This means that you don't have an entry in /etc/services for the
+\fBsample\fP tcp port.
+.PP
+3)  \fIsclient\fP returns the error:
+.PP
+connect: Connection refused
+.PP
+This probably means you didn't edit /etc/inetd.conf correctly, or you
+didn't restart \fIinetd\fP after editing inetd.conf.
+.PP
+4)  \fIsclient\fP returns the error:
+.PP
+sclient: Server not found in Kerberos database while using sendauth
+.PP
+This means that the "sample/hostname@LOCAL.REALM" service was not
+defined in the Kerberos database; it should be created using \fIkadmin,\fP
+and a keytab file needs to be generated to make the key for that service
+principal available for \fIssclient\fP.
+.PP
+5)  \fIsclient\fP returns the error:
+.PP
+sendauth rejected, error reply is:
+        " No such file or directory"
+.PP
+This probably means \fIsserver\fP couldn't find the keytab file.  It was
+probably not installed in the proper directory.
+.br
+.SH SEE ALSO
+sclient(1), services(5), inetd(8)
diff --git a/mechglue/src/appl/sample/sserver/sserver.c b/mechglue/src/appl/sample/sserver/sserver.c
new file mode 100644
index 000000000..979b0ffd4
--- /dev/null
+++ b/mechglue/src/appl/sample/sserver/sserver.c
@@ -0,0 +1,237 @@
+/*
+ * appl/sample/sserver/sserver.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Sample Kerberos v5 server.
+ *
+ * sample_server:
+ * A sample Kerberos server, which reads an AP_REQ from a TCP socket,
+ * decodes it, and writes back the results (in ASCII) to the client.
+ *
+ * Usage:
+ * sample_server servername
+ *
+ * file descriptor 0 (zero) should be a socket connected to the requesting
+ * client (this will be correct if this server is started by inetd).
+ */
+
+#include "krb5.h"
+#include "com_err.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <syslog.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "../sample.h"
+
+extern krb5_deltat krb5_clockskew;
+
+#ifndef GETPEERNAME_ARG3_TYPE
+#define GETPEERNAME_ARG3_TYPE int
+#endif
+
+#define DEBUG
+
+static void
+usage(name)
+    char *name;
+{
+	fprintf(stderr, "usage: %s [-p port] [-s service] [-S keytab]\n",
+		name);
+}	
+
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_context context;
+    krb5_auth_context auth_context = NULL;
+    krb5_ticket * ticket;
+    struct sockaddr_in peername;
+    GETPEERNAME_ARG3_TYPE  namelen = sizeof(peername);
+    int sock = -1;			/* incoming connection fd */
+    krb5_data recv_data;
+    short xmitlen;
+    krb5_error_code retval;
+    krb5_principal server;
+    char repbuf[BUFSIZ];
+    char *cname;
+    char *service = SAMPLE_SERVICE;
+    short port = 0;		/* If user specifies port */
+    extern int opterr, optind;
+    extern char * optarg;
+    int ch;
+    krb5_keytab keytab = NULL;	/* Allow specification on command line */
+    char *progname;
+    int on = 1;
+
+    progname = *argv;
+
+    retval = krb5_init_context(&context);
+    if (retval) {
+	    com_err(argv[0], retval, "while initializing krb5");
+	    exit(1);
+    }
+
+    /* open a log connection */
+    openlog("sserver", 0, LOG_DAEMON);
+
+    /*
+     * Parse command line arguments
+     *  
+     */
+    opterr = 0;
+    while ((ch = getopt(argc, argv, "p:S:s:")) != -1)
+    switch (ch) {
+    case 'p':
+	port = atoi(optarg);
+	break;
+    case 's':
+	service = optarg;
+	break;
+    case 'S':
+	if ((retval = krb5_kt_resolve(context, optarg, &keytab))) {
+	    com_err(progname, retval,
+		    "while resolving keytab file %s", optarg);
+	    exit(2);
+	}
+	break;
+
+      case '?':
+    default:
+	usage(progname);
+	exit(1);
+	break;
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    /* Backwards compatibility, allow port to be specified at end */
+    if (argc > 1) {
+	    port = atoi(argv[1]);
+    }
+
+    retval = krb5_sname_to_principal(context, NULL, service, 
+				     KRB5_NT_SRV_HST, &server);
+    if (retval) {
+	syslog(LOG_ERR, "while generating service name (%s): %s",
+	       service, error_message(retval));
+	exit(1);
+    }
+    
+    /*
+     * If user specified a port, then listen on that port; otherwise,
+     * assume we've been started out of inetd. 
+     */
+
+    if (port) {
+	int acc;
+	struct sockaddr_in sockin;
+
+	if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+	    syslog(LOG_ERR, "socket: %m");
+	    exit(3);
+	}
+	/* Let the socket be reused right away */
+	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+			  sizeof(on));
+
+	sockin.sin_family = AF_INET;
+	sockin.sin_addr.s_addr = 0;
+	sockin.sin_port = htons(port);
+	if (bind(sock, (struct sockaddr *) &sockin, sizeof(sockin))) {
+	    syslog(LOG_ERR, "bind: %m");
+	    exit(3);
+	}
+	if (listen(sock, 1) == -1) {
+	    syslog(LOG_ERR, "listen: %m");
+	    exit(3);
+	}
+	if ((acc = accept(sock, (struct sockaddr *)&peername, &namelen)) == -1){
+	    syslog(LOG_ERR, "accept: %m");
+	    exit(3);
+	}
+	dup2(acc, 0);
+	close(sock);
+	sock = 0;
+    } else {
+	/*
+	 * To verify authenticity, we need to know the address of the
+	 * client.
+	 */
+	if (getpeername(0, (struct sockaddr *)&peername, &namelen) < 0) {
+	    syslog(LOG_ERR, "getpeername: %m");
+	    exit(1);
+	}
+	sock = 0;
+    }
+
+    retval = krb5_recvauth(context, &auth_context, (krb5_pointer)&sock,
+			   SAMPLE_VERSION, server, 
+			   0,	/* no flags */
+			   keytab,	/* default keytab is NULL */
+			   &ticket);
+    if (retval) {
+	syslog(LOG_ERR, "recvauth failed--%s", error_message(retval));
+	exit(1);
+    }
+
+    /* Get client name */
+    retval = krb5_unparse_name(context, ticket->enc_part2->client, &cname);
+    if (retval){
+	syslog(LOG_ERR, "unparse failed: %s", error_message(retval));
+        sprintf(repbuf, "You are <unparse error>\n");
+    } else {
+        sprintf(repbuf, "You are %s\n", cname);
+	free(cname);
+    }
+    xmitlen = htons(strlen(repbuf));
+    recv_data.length = strlen(repbuf);
+    recv_data.data = repbuf;
+    if ((retval = krb5_net_write(context, 0, (char *)&xmitlen,
+				 sizeof(xmitlen))) < 0) {
+	syslog(LOG_ERR, "%m: while writing len to client");
+	exit(1);
+    }
+    if ((retval = krb5_net_write(context, 0, (char *)recv_data.data,
+				 recv_data.length)) < 0) {
+	syslog(LOG_ERR, "%m: while writing data to client");
+	exit(1);
+    }
+    krb5_auth_con_free(context, auth_context);
+    krb5_free_context(context);
+    exit(0);
+}
diff --git a/mechglue/src/appl/simple/.Sanitize b/mechglue/src/appl/simple/.Sanitize
new file mode 100644
index 000000000..1f061c528
--- /dev/null
+++ b/mechglue/src/appl/simple/.Sanitize
@@ -0,0 +1,39 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+client
+configure
+configure.in
+server
+simple.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/simple/ChangeLog b/mechglue/src/appl/simple/ChangeLog
new file mode 100644
index 000000000..9c9da9569
--- /dev/null
+++ b/mechglue/src/appl/simple/ChangeLog
@@ -0,0 +1,64 @@
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCAL_SUBDIRS): Renamed from MY_SUBDIRS.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Removed and tests moved up to appl/configure.in
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS definition to control the directories
+		which are recursively descended by the Makefile.
+
+Wed Feb 18 15:33:49 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Thu Feb 12 16:15:30 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented AC_OUTPUT to force autoreconf to
+	rebuild configure script.
+
+Mon Feb  2 16:47:05 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* configure.in: Create the makefiles for all of the subdirectories
+		and move all of the configure.in tests from the
+		subdirectories into this configure.in.
+	
+Fri Sep 15 14:24:37 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* simple.h (SIMPLE_SERVICE, SIMPLE_PORT): Use separate definitions
+		for the Kerberos instance name and the UDP port name.
+
+Thu Aug 24 19:25:48 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Fri Jul 7 15:47:50 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS.
+
+Fri Jun  9 18:28:55 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
diff --git a/mechglue/src/appl/simple/Makefile.in b/mechglue/src/appl/simple/Makefile.in
new file mode 100644
index 000000000..9e6f16da2
--- /dev/null
+++ b/mechglue/src/appl/simple/Makefile.in
@@ -0,0 +1,5 @@
+thisconfigdir=./..
+myfulldir=appl/simple
+mydir=simple
+LOCAL_SUBDIRS = client server
+BUILDTOP=$(REL)..$(S)..
diff --git a/mechglue/src/appl/simple/client/.Sanitize b/mechglue/src/appl/simple/client/.Sanitize
new file mode 100644
index 000000000..67a3f6130
--- /dev/null
+++ b/mechglue/src/appl/simple/client/.Sanitize
@@ -0,0 +1,37 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+sim_client.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/simple/client/ChangeLog b/mechglue/src/appl/simple/client/ChangeLog
new file mode 100644
index 000000000..29b95a64f
--- /dev/null
+++ b/mechglue/src/appl/simple/client/ChangeLog
@@ -0,0 +1,175 @@
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* sim_client.c: Always include stdlib.h.
+	(main): Don't call valid_cksumtype.
+
+2002-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* sim_client.c: Include errno.h.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* sim_client.c: Make prototypes unconditional.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* sim_client.c (main): Cast argument to isupper()/tolower() to int.
+
+Tue Sep 26 18:15:47 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* sim_client.c: Warnings cleanups unsigned vs signed.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS macro set to '.' to indicate that there
+		are no subdirectories to be processed by the Makefile.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sim_client.c (main): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Wed Feb 18 15:34:52 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Feb 18 18:11:03 1997  Richard Basch  <basch@lehman.com>
+
+	* sim_client.c: Replace krb5_xfree with krb5_free_data_contents
+
+Tue Feb  4 20:38:44 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Fri Nov 22 15:48:30 1996  unknown  <bjaspan@mit.edu>
+
+	* sim_client.c (main): use sizeof instead of h_length to determine
+ 	number of bytes of addr to copy from DNS response [krb5-misc/211]
+
+Thu Nov  7 15:26:10 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sim_client.c (main): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Thu Nov  9 09:33:38 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* sim_client.c (main): Use krb5_get_server_rcache instead of
+		duplicating code. Remove use of krb5_clockskew variable.
+
+Sun Oct 15 10:49:35 1995    <tytso@rsts-11.mit.edu>
+
+	* sim_client.c (main): Fixed location where usage() wasn't being
+		called with an argument.
+
+Sat Sep 16 03:45:59 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sim_client.c (main): Fix optional host parsing so that host is
+		recognized as an argument without the -h option.  
+		Free the context and auth_context structures before exiting.
+
+Fri Sep 15 04:59:30 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sim_client.c (main): Added better options parsing for more
+		flexibility in calling this program.  Worked around
+		breakage in the Solaris Streams Sockets emulation where
+		getsockname() can not be used to find out the address of
+		a network interface.
+
+	* configure.in: If we are including both -lsocket and -lnsl,
+		#define BROKEN_STREAMS_SOCKETS.
+	
+
+Fri Jul 7 15:48:14 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling and LDFLAGS.
+	* configure.in - Add KRB5_LIBRARIES.
+
+Wed Jun 28 13:27:17 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* sim_client.c: Include stdlib.h or declare malloc.
+		Include string.h for strlen and memcpy defintions.
+
+	* configure.in: Check for stdlib.h.
+
+Thu Jun 15 17:39:54 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Sat Jun 10 22:58:57 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* sim_client.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:29:09 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Mon May 01 15:56:32 1995  Chris Provenzano  (proven@mit.edu)
+
+        * sim_client.c (main()): Changes to auth_context to better
+                support full addresses, for mk_safe() and friends.
+
+Mon Mar 27 09:25:21 1995  Chris Provenzano (proven@mit.edu)
+
+	* sim_client.c: Don't set cksumtype because CKSUMTYPE_RSA_MD4_DES
+		is now the default type.
+
+Fri Mar 10 11:09:34 1995  Chris Provenzano (proven@mit.edu)
+
+        * sim_client.c: Use new calling convention for krb5_mk_req(),
+		krb5_mk_priv(), and krb5_mk_safe().
+
+Thu Mar  2 12:26:47 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:24:21 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 02:01:29 1995  John Gilmore  (gnu at toad.com)
+
+	* sim_client.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Tue Feb 14 15:30:55 1995 Chris Provenzano  (proven@mit.edu)
+
+        * sim_client.c Call krb5_sendauth() with new calling convention.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Thu Sep 29 22:45:52 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executable if library changes
+
+
diff --git a/mechglue/src/appl/simple/client/Makefile.in b/mechglue/src/appl/simple/client/Makefile.in
new file mode 100644
index 000000000..c7023ca1d
--- /dev/null
+++ b/mechglue/src/appl/simple/client/Makefile.in
@@ -0,0 +1,19 @@
+thisconfigdir=./../..
+myfulldir=appl/simple/client
+mydir=simple/client
+BUILDTOP=$(REL)..$(S)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all:: sim_client
+
+LOCALINCLUDES= -I.. -I$(srcdir)/..
+
+sim_client: sim_client.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o sim_client sim_client.o $(KRB5_BASE_LIBS)
+
+install::
+	$(INSTALL_PROGRAM) sim_client $(DESTDIR)$(CLIENT_BINDIR)/sim_client
+
+clean::
+	$(RM) sim_client.o sim_client
diff --git a/mechglue/src/appl/simple/client/sim_client.c b/mechglue/src/appl/simple/client/sim_client.c
new file mode 100644
index 000000000..d9a40dc82
--- /dev/null
+++ b/mechglue/src/appl/simple/client/sim_client.c
@@ -0,0 +1,332 @@
+/*
+ * appl/simple/client/sim_client.c
+ *
+ * Copyright 1989,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Simple UDP-based sample client program.  For demonstration.
+ * This program performs no useful function.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <krb5.h>
+#include "com_err.h"
+
+#include "simple.h"
+
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* for old Unixes and friends ... */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define MSG "hi there!"			/* message text */
+
+void usage (char *);
+
+void
+usage(name)
+    char *name;
+{
+	fprintf(stderr, "usage: %s [-p port] [-h host] [-m message] [-s service] [host]\n", name);
+}	
+
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    int sock, i;
+    unsigned int len;
+    int flags = 0;			/* flags for sendto() */
+    struct servent *serv;
+    struct hostent *host;
+    char *cp;
+    char full_hname[MAXHOSTNAMELEN];
+#ifdef BROKEN_STREAMS_SOCKETS
+    char my_hostname[MAXHOSTNAMELEN];
+#endif
+    struct sockaddr_in s_sock;		/* server address */
+    struct sockaddr_in c_sock;		/* client address */
+    extern int opterr, optind;
+    extern char * optarg;
+    int	ch;
+    
+    short port = 0;
+    char *message = MSG;
+    char *hostname = 0;
+    char *service = SIMPLE_SERVICE;
+    char *progname = 0;
+
+    krb5_error_code retval;
+    krb5_data packet, inbuf;
+    krb5_ccache ccdef;
+    krb5_address addr, *portlocal_addr;
+    krb5_rcache rcache;
+    krb5_data	rcache_name;
+
+    krb5_context 	  context;
+    krb5_auth_context 	  auth_context = NULL;
+
+    retval = krb5_init_context(&context);
+    if (retval) {
+	    com_err(argv[0], retval, "while initializing krb5");
+	    exit(1);
+    }
+
+    progname = argv[0];
+
+    /*
+     * Parse command line arguments
+     *  
+     */
+    opterr = 0;
+    while ((ch = getopt(argc, argv, "p:m:h:s:")) != -1)
+    switch (ch) {
+    case 'p':
+	port = atoi(optarg);
+	break;
+    case 'm':
+	message = optarg;
+	break;
+    case 'h':
+	hostname = optarg;
+	break;
+    case 's':
+	service = optarg;
+	break;
+    case '?':
+    default:
+	usage(progname);
+	exit(1);
+	break;
+    }
+    argc -= optind;
+    argv += optind;
+    if (argc > 0) {
+	if (hostname)
+	    usage(progname);
+	hostname = argv[0];
+    }
+
+    if (hostname == 0) {
+	fprintf(stderr, "You must specify a hostname to contact.\n\n");
+	usage(progname);
+	exit(1);
+    }
+
+    /* Look up server host */
+    if ((host = gethostbyname(hostname)) == (struct hostent *) 0) {
+	fprintf(stderr, "%s: unknown host\n", hostname);
+	exit(1);
+    }
+    strncpy(full_hname, host->h_name, sizeof(full_hname)-1);
+    full_hname[sizeof(full_hname)-1] = '\0';
+
+    /* lower-case to get name for "instance" part of service name */
+    for (cp = full_hname; *cp; cp++)
+        if (isupper((int) *cp))
+            *cp = tolower((int) *cp);
+
+    /* Set server's address */
+    (void) memset((char *)&s_sock, 0, sizeof(s_sock));
+
+    memcpy((char *)&s_sock.sin_addr, host->h_addr, sizeof(s_sock.sin_addr));
+#ifdef DEBUG
+    printf("s_sock.sin_addr is %s\n", inet_ntoa(s_sock.sin_addr));
+#endif
+    s_sock.sin_family = AF_INET;
+
+    if (port == 0) {
+	/* Look up service */
+	if ((serv = getservbyname(SIMPLE_PORT, "udp")) == NULL) {
+	    fprintf(stderr, "service unknown: %s/udp\n", SIMPLE_PORT);
+	    exit(1);
+	}
+	s_sock.sin_port = serv->s_port;
+    } else {
+	s_sock.sin_port = htons(port);
+    }
+
+    /* Open a socket */
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	com_err(progname, errno, "opening datagram socket");
+	exit(1);
+    }
+
+    memset((char *)&c_sock, 0, sizeof(c_sock));
+    c_sock.sin_family = AF_INET;
+#ifdef BROKEN_STREAMS_SOCKETS
+    if (gethostname(my_hostname, sizeof(my_hostname)) < 0) {
+	perror("gethostname");
+	exit(1);
+    }
+
+    if ((host = gethostbyname(my_hostname)) == (struct hostent *)0) {
+	fprintf(stderr, "%s: unknown host\n", hostname);
+	exit(1);
+    }
+    memcpy((char *)&c_sock.sin_addr, host->h_addr, sizeof(c_sock.sin_addr));
+#endif
+    
+
+    /* Bind it to set the address; kernel will fill in port # */
+    if (bind(sock, (struct sockaddr *)&c_sock, sizeof(c_sock)) < 0) {
+	com_err(progname, errno, "while binding datagram socket");
+	exit(1);
+    }
+	
+    /* PREPARE KRB_AP_REQ MESSAGE */
+
+    inbuf.data = hostname;
+    inbuf.length = strlen(hostname);
+
+    /* Get credentials for server */
+    if ((retval = krb5_cc_default(context, &ccdef))) {
+	com_err(progname, retval, "while getting default ccache");
+	exit(1);
+    }
+
+    if ((retval = krb5_mk_req(context, &auth_context, 0, service, full_hname,
+			      &inbuf, ccdef, &packet))) {
+	com_err(progname, retval, "while preparing AP_REQ");
+	exit(1);
+    }
+    printf("Got credentials for %s.\n", service);
+
+    /* "connect" the datagram socket; this is necessary to get a local address
+       properly bound for getsockname() below. */
+
+    if (connect(sock, (struct sockaddr *)&s_sock, sizeof(s_sock)) == -1) {
+	com_err(progname, errno, "while connecting to server");
+	exit(1);
+    }
+    /* Send authentication info to server */
+    if ((i = send(sock, (char *)packet.data, (unsigned) packet.length, 
+		  flags)) < 0) 
+	com_err(progname, errno, "while sending KRB_AP_REQ message");
+    printf("Sent authentication data: %d bytes\n", i);
+    krb5_free_data_contents(context, &packet);
+
+    /* PREPARE KRB_SAFE MESSAGE */
+
+    /* Get my address */
+    memset((char *) &c_sock, 0, sizeof(c_sock));
+    len = sizeof(c_sock);
+    if (getsockname(sock, (struct sockaddr *)&c_sock, &len) < 0) {
+	com_err(progname, errno, "while getting socket name");
+	exit(1);
+    }
+
+    addr.addrtype = ADDRTYPE_IPPORT;
+    addr.length = sizeof(c_sock.sin_port);
+    addr.contents = (krb5_octet *)&c_sock.sin_port;
+    if ((retval = krb5_auth_con_setports(context, auth_context,
+					 &addr, NULL))) {
+	com_err(progname, retval, "while setting local port\n");
+	exit(1);
+    }
+
+    addr.addrtype = ADDRTYPE_INET;
+    addr.length = sizeof(c_sock.sin_addr);
+    addr.contents = (krb5_octet *)&c_sock.sin_addr;
+    if ((retval = krb5_auth_con_setaddrs(context, auth_context,
+					 &addr, NULL))) {
+	com_err(progname, retval, "while setting local addr\n");
+	exit(1);
+    }
+
+    /* THIS IS UGLY */
+    if ((retval = krb5_gen_portaddr(context, &addr,
+				    (krb5_pointer) &c_sock.sin_port,
+				    &portlocal_addr))) {
+	com_err(progname, retval, "while generating port address");
+	exit(1);
+    }
+    
+    if ((retval = krb5_gen_replay_name(context,portlocal_addr,
+				       "_sim_clt",&cp))) {
+	com_err(progname, retval, "while generating replay cache name");
+	exit(1);
+    }
+
+    rcache_name.length = strlen(cp);
+    rcache_name.data = cp;
+
+    if ((retval = krb5_get_server_rcache(context, &rcache_name, &rcache))) {
+	com_err(progname, retval, "while getting server rcache");
+	exit(1);
+    }
+
+    /* set auth_context rcache */
+    krb5_auth_con_setrcache(context, auth_context, rcache);
+
+    /* Make the safe message */
+    inbuf.data = message;
+    inbuf.length = strlen(message);
+
+    if ((retval = krb5_mk_safe(context, auth_context, &inbuf, &packet, NULL))){
+	com_err(progname, retval, "while making KRB_SAFE message");
+	exit(1);
+    }
+
+    /* Send it */
+    if ((i = send(sock, (char *)packet.data, (unsigned) packet.length, 
+		  flags)) < 0)
+	com_err(progname, errno, "while sending SAFE message");
+    printf("Sent checksummed message: %d bytes\n", i);
+    krb5_free_data_contents(context, &packet);
+
+    /* PREPARE KRB_PRIV MESSAGE */
+
+    /* Make the encrypted message */
+    if ((retval = krb5_mk_priv(context, auth_context, &inbuf,
+			       &packet, NULL))) {
+	com_err(progname, retval, "while making KRB_PRIV message");
+	exit(1);
+    }
+
+    /* Send it */
+    if ((i = send(sock, (char *)packet.data, (unsigned) packet.length, 
+		  flags)) < 0)
+	com_err(progname, errno, "while sending PRIV message");
+    printf("Sent encrypted message: %d bytes\n", i);
+    krb5_free_data_contents(context, &packet);
+
+    krb5_auth_con_free(context, auth_context);
+    krb5_free_context(context);
+    
+    exit(0);
+}
diff --git a/mechglue/src/appl/simple/server/.Sanitize b/mechglue/src/appl/simple/server/.Sanitize
new file mode 100644
index 000000000..fa837442a
--- /dev/null
+++ b/mechglue/src/appl/simple/server/.Sanitize
@@ -0,0 +1,37 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+sim_server.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/simple/server/ChangeLog b/mechglue/src/appl/simple/server/ChangeLog
new file mode 100644
index 000000000..67d2769e4
--- /dev/null
+++ b/mechglue/src/appl/simple/server/ChangeLog
@@ -0,0 +1,141 @@
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2000-10-16  Ezra Peisach  <epeisach@mit.edu>
+
+	* sim_server.c: Cast to int strings width arguments in printf.
+
+Tue Sep 26 18:16:33 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* sim_server.c: Warnigs cleanup of signed vs. unsigned arguments
+ 	to functions.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS macro set to '.' to indicate that there
+		are no subdirectories to be processed by the Makefile.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sim_server.c (argv): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Wed Feb 18 15:35:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Feb 18 18:12:16 1997  Richard Basch  <basch@lehman.com>
+
+	* sim_server.c: Use krb5_free_data_contents instead of krb5_xfree
+
+Tue Feb  4 20:41:49 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Fri Nov 22 15:48:42 1996  unknown  <bjaspan@mit.edu>
+
+	* sim_server.c (argv): use sizeof instead of h_length to determine
+ 	number of bytes of addr to copy from DNS response [krb5-misc/211]
+
+Thu Nov  7 15:26:44 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sim_server.c (argv): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Sat Sep 16 03:41:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sim_server.c (main): Free the context and auth_context before
+	        exiting.
+
+Fri Sep 15 14:31:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sim_server.c: Improved (and changed) input argument handling, to
+		make sim_server more flexible.  This should make it
+		possible to run sim_server from a DejaGnu test suite.
+		Fixed -Wall nits.
+
+Sat Jul 29 04:39:39 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* configure.in: don't link with -lkadm.
+
+Fri Jul 7 15:48:58 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling and LDFLAGS.
+	* configure.in - Add KRB5_LIBRARIES and USE_KADM_LIBRARY.
+
+Wed Jun 28 13:13:34 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* sim_server.c: Include <string.h> for memcpy definitions.
+
+Thu Jun 15 17:40:51 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Sat Jun 10 22:59:20 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* sim_server.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:23:58 1995    <tytso@rsx-11.mit.edu>
+
+	* sim_server.c: #include krb5.h first, to reduce size of debugging
+	        executable.
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Mon May 01 15:56:32 1995  Chris Provenzano (proven@mit.edu)
+
+        * sim_server.c (main()): Changes to auth_context to better
+                support full addresses, for mk_safe() and friends.
+
+Mon Mar 27 07:56:26 1995 Chris Provenzano (proven@mit.edu)
+
+        * sim_server.c: Use new calling convention for krb5_rd_req(),
+		krb5_rd_safe(), and krb5_rd_priv().
+
+Thu Mar  2 12:27:03 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:24:58 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 02:01:53 1995  John Gilmore  (gnu at toad.com)
+
+	* sim_server.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    	* Added krb5_context to all krb5_routines
+
+Thu Sep 29 22:46:51 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: relink executable when libraries change
+
diff --git a/mechglue/src/appl/simple/server/Makefile.in b/mechglue/src/appl/simple/server/Makefile.in
new file mode 100644
index 000000000..d670edaa7
--- /dev/null
+++ b/mechglue/src/appl/simple/server/Makefile.in
@@ -0,0 +1,20 @@
+thisconfigdir=./../..
+myfulldir=appl/simple/server
+mydir=simple/server
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+LOCALINCLUDES= -I.. -I$(srcdir)/..
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all:: sim_server
+
+sim_server: sim_server.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o sim_server sim_server.o $(KRB5_BASE_LIBS)
+
+install::
+	$(INSTALL_PROGRAM) sim_server $(DESTDIR)$(SERVER_BINDIR)/sim_server
+
+clean::
+	$(RM) sim_server.o sim_server
diff --git a/mechglue/src/appl/simple/server/sim_server.c b/mechglue/src/appl/simple/server/sim_server.c
new file mode 100644
index 000000000..137cc49f0
--- /dev/null
+++ b/mechglue/src/appl/simple/server/sim_server.c
@@ -0,0 +1,279 @@
+/*
+ * appl/simple/server/sim_server.c
+ *
+ * Copyright 1989,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Usage:
+ * sample_server servername
+ *
+ * Simple UDP-based server application.  For demonstration.
+ * This program performs no useful function.
+ */
+
+#include "krb5.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "com_err.h"
+
+#include "simple.h"
+
+/* for old Unixes and friends ... */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define PROGNAME argv[0]
+
+static void
+usage(name)
+    char *name;
+{
+	fprintf(stderr, "usage: %s [-p port] [-s service] [-S keytab]\n", name);
+}	
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+    int sock, i;
+    unsigned int len;
+    int flags = 0;			/* for recvfrom() */
+    int on = 1;
+    struct servent *serv;
+    struct hostent *host;
+    struct sockaddr_in s_sock;		/* server's address */
+    struct sockaddr_in c_sock;		/* client's address */
+    char full_hname[MAXHOSTNAMELEN];
+    char *cp;
+    extern int opterr, optind;
+    extern char * optarg;
+    int	ch;
+
+    short port = 0;		/* If user specifies port */
+    krb5_keytab keytab = NULL;	/* Allow specification on command line */
+    char *service = SIMPLE_SERVICE;
+
+    krb5_error_code retval;
+    krb5_data packet, message;
+    unsigned char pktbuf[BUFSIZ];
+    krb5_principal sprinc;
+    krb5_context context;
+    krb5_auth_context auth_context = NULL;
+    krb5_address addr;
+    krb5_ticket *ticket = NULL;
+
+    retval = krb5_init_context(&context);
+    if (retval) {
+	    com_err(argv[0], retval, "while initializing krb5");
+	    exit(1);
+    }
+
+    /*
+     * Parse command line arguments
+     *  
+     */
+    opterr = 0;
+    while ((ch = getopt(argc, argv, "p:s:S:")) != -1)
+    switch (ch) {
+    case 'p':
+	port = atoi(optarg);
+	break;
+    case 's':
+	service = optarg;
+	break;
+    case 'S':
+	if ((retval = krb5_kt_resolve(context, optarg, &keytab))) {
+	    com_err(PROGNAME, retval,
+		    "while resolving keytab file %s", optarg);
+	    exit(2);
+	}
+	break;
+
+    case '?':
+    default:
+	usage(PROGNAME);
+	exit(1);
+	break;
+    }
+
+    if ((retval = krb5_sname_to_principal(context, NULL, service, 
+					  KRB5_NT_SRV_HST, &sprinc))) {
+	com_err(PROGNAME, retval, "while generating service name %s", service);
+	exit(1);
+    }
+
+    /* Set up server address */
+    memset((char *)&s_sock, 0, sizeof(s_sock));
+    s_sock.sin_family = AF_INET;
+
+    if (port == 0) {
+	/* Look up service */
+	if ((serv = getservbyname(SIMPLE_PORT, "udp")) == NULL) {
+	    fprintf(stderr, "service unknown: %s/udp\n", SIMPLE_PORT);
+	    exit(1);
+	}
+	s_sock.sin_port = serv->s_port;
+    } else {
+	s_sock.sin_port = htons(port);
+    }
+    
+    if (gethostname(full_hname, sizeof(full_hname)) < 0) {
+	perror("gethostname");
+	exit(1);
+    }
+
+    if ((host = gethostbyname(full_hname)) == (struct hostent *)0) {
+	fprintf(stderr, "%s: host unknown\n", full_hname);
+	exit(1);
+    }
+    memcpy((char *)&s_sock.sin_addr, host->h_addr, sizeof(s_sock.sin_addr));
+
+    /* Open socket */
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	perror("opening datagram socket");
+	exit(1);
+    }
+
+     /* Let the socket be reused right away */
+     (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+		       sizeof(on));
+
+    /* Bind the socket */
+    if (bind(sock, (struct sockaddr *)&s_sock, sizeof(s_sock))) {
+	perror("binding datagram socket");
+	exit(1);
+    }
+
+#ifdef DEBUG
+    printf("socket has port # %d\n", ntohs(s_sock.sin_port));
+#endif
+
+    /* GET KRB_AP_REQ MESSAGE */
+
+    /* use "recvfrom" so we know client's address */
+    len = sizeof(struct sockaddr_in);
+    if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags,
+		 (struct sockaddr *)&c_sock, &len)) < 0) {
+	perror("receiving datagram");
+	exit(1);
+    }
+
+    printf("Received %d bytes\n", i);
+    packet.length = i;
+    packet.data = (krb5_pointer) pktbuf;
+
+    /* Check authentication info */
+    if ((retval = krb5_rd_req(context, &auth_context, &packet, 
+			      sprinc, keytab, NULL, &ticket))) {
+	com_err(PROGNAME, retval, "while reading request");
+	exit(1);
+    }
+    if ((retval = krb5_unparse_name(context, ticket->enc_part2->client,
+				    &cp))) {
+	com_err(PROGNAME, retval, "while unparsing client name");
+	exit(1);
+    }
+    printf("Got authentication info from %s\n", cp);
+    free(cp);
+
+    /* Set foreign_addr for rd_safe() and rd_priv() */
+    addr.addrtype = ADDRTYPE_INET;
+    addr.length = sizeof(c_sock.sin_addr);
+    addr.contents = (krb5_octet *)&c_sock.sin_addr;
+    if ((retval = krb5_auth_con_setaddrs(context, auth_context,
+					 NULL, &addr))) {
+	com_err(PROGNAME, retval, "while setting foreign addr");
+        exit(1);
+    }
+
+    addr.addrtype = ADDRTYPE_IPPORT;
+    addr.length = sizeof(c_sock.sin_port);
+    addr.contents = (krb5_octet *)&c_sock.sin_port;
+    if ((retval = krb5_auth_con_setports(context, auth_context,
+					 NULL, &addr))) {
+	com_err(PROGNAME, retval, "while setting foreign port");
+        exit(1);
+    }
+
+    /* GET KRB_MK_SAFE MESSAGE */
+
+    /* use "recvfrom" so we know client's address */
+    len = sizeof(struct sockaddr_in);
+    if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags,
+		 (struct sockaddr *)&c_sock, &len)) < 0) {
+	perror("receiving datagram");
+	exit(1);
+    }
+#ifdef DEBUG
+    printf("&c_sock.sin_addr is %s\n", inet_ntoa(c_sock.sin_addr));
+#endif
+    printf("Received %d bytes\n", i);
+
+    packet.length = i;
+    packet.data = (krb5_pointer) pktbuf;
+
+    if ((retval = krb5_rd_safe(context, auth_context, &packet,
+			       &message, NULL))) {
+	com_err(PROGNAME, retval, "while verifying SAFE message");
+	exit(1);
+    }
+    printf("Safe message is: '%.*s'\n", (int) message.length, message.data);
+
+    krb5_free_data_contents(context, &message);
+
+    /* NOW GET ENCRYPTED MESSAGE */
+
+    /* use "recvfrom" so we know client's address */
+    len = sizeof(struct sockaddr_in);
+    if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags,
+		      (struct sockaddr *)&c_sock, &len)) < 0) {
+	perror("receiving datagram");
+	exit(1);
+    }
+    printf("Received %d bytes\n", i);
+
+    packet.length = i;
+    packet.data = (krb5_pointer) pktbuf;
+    
+    if ((retval = krb5_rd_priv(context, auth_context, &packet,
+			       &message, NULL))) {
+	com_err(PROGNAME, retval, "while verifying PRIV message");
+	exit(1);
+    }
+    printf("Decrypted message is: '%.*s'\n", (int) message.length, 
+	   message.data);
+
+    krb5_auth_con_free(context, auth_context);
+    krb5_free_context(context);
+
+    exit(0);
+}
diff --git a/mechglue/src/appl/simple/simple.h b/mechglue/src/appl/simple/simple.h
new file mode 100644
index 000000000..f230592e6
--- /dev/null
+++ b/mechglue/src/appl/simple/simple.h
@@ -0,0 +1,32 @@
+/*
+ * appl/simple/simple.h
+ *
+ * Copyright 1988,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Common definitions for the simple UDP-based Kerberos-mediated
+ * server & client applications.
+ */
+
+#define SIMPLE_SERVICE	"sample"
+#define SIMPLE_PORT	"sample"
diff --git a/mechglue/src/appl/telnet/.Sanitize b/mechglue/src/appl/telnet/.Sanitize
new file mode 100644
index 000000000..72a66203f
--- /dev/null
+++ b/mechglue/src/appl/telnet/.Sanitize
@@ -0,0 +1,47 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+Config.generic
+Makefile.in
+Makefile.orig
+README
+arpa
+configure
+configure.in
+kern.diff
+libtelnet
+stty.diff
+telnet
+telnet.state
+telnetd
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/telnet/.rconf b/mechglue/src/appl/telnet/.rconf
new file mode 100644
index 000000000..e98c0164f
--- /dev/null
+++ b/mechglue/src/appl/telnet/.rconf
@@ -0,0 +1 @@
+ignore */*.0
diff --git a/mechglue/src/appl/telnet/ChangeLog b/mechglue/src/appl/telnet/ChangeLog
new file mode 100644
index 000000000..5fc18685f
--- /dev/null
+++ b/mechglue/src/appl/telnet/ChangeLog
@@ -0,0 +1,73 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-01-13  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: When looking for setupterm() - look in
+	libcurses/libncurses even if termcap library found.
+
+2004-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Use KRB5_AC_LIBUTIL.
+
+2004-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Move test for setupterm back down below addition
+	of termcap/curses libraries.
+
+2004-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Merged in code from subdir configure.in files.
+	Create the subdir Makefiles here.  Substitute TELNET_LIBS and
+	TELNETD_LIBS with the appropriate sets of libraries.
+	* Makefile.in (LOCAL_SUBDIRS): Set to list the subdirs.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.orig: Deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Wed Feb 18 15:36:25 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+ 	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jun  9 18:29:38 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Fri Mar 31 16:53:03 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Remove CFLAGS=@CCOPTS@ line, which is in pre.in
+
+Fri Nov 18 00:14:56 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: add WITH_CCOPTS so that subdirs work.
+
+Sat Jul 23 08:18:18 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in:
+	* configure.in: first cut at making telnet completely autoconf
+
diff --git a/mechglue/src/appl/telnet/Config.generic b/mechglue/src/appl/telnet/Config.generic
new file mode 100644
index 000000000..c6f88a52b
--- /dev/null
+++ b/mechglue/src/appl/telnet/Config.generic
@@ -0,0 +1,830 @@
+#
+# Copyright (c) 1991 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted provided
+# that: (1) source distributions retain this entire copyright notice and
+# comment, and (2) distributions including binaries display the following
+# acknowledgement:  ``This product includes software developed by the
+# University of California, Berkeley and its contributors'' in the
+# documentation or other materials provided with the distribution and in
+# all advertising materials mentioning features or use of this software.
+# Neither the name of the University nor the names of its contributors may
+# be used to endorse or promote products derived from this software without
+# specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#	@(#)Config.generic	5.5 (Berkeley) 3/1/91
+#
+
+# This is the configuration file for building all of
+# telnet/telnetd/libtelnet.  If you want to add your
+# own local configuration for a specific machine that
+# is already listed here, it is best to create a new
+# file called "Config.local", and put the definitions
+# there.  If you are adding definitions for a new system
+# type, you can add them here.  In this case, please send
+# the new definition, and any changes you have to make to
+# the code, back to "dab@cray.com" so that your changes
+# can be put into the next release.
+#
+# Each definition must have the form:
+#
+#	<target>:
+#		make -f Makefile.generic ${WHAT} \
+#			<definitions>
+
+# DEFINES=
+#
+#    Variables to be defined when actually compiling the source.  Defined
+#    as: DEFINES="-D<var> -D<var2> ... -D<varn>"
+#
+#    TELNET/TELNETD CONFIGURATION
+#
+# 	LINEMODE	Turns on support in telnetd for the linemode option.
+#			(Linemode is always on in the client).
+#
+#	KLUDGELINEMODE	Define this to get the kludged up version of linemode
+#			that was in 4.3BSD.  This is a good thing to have
+#			around for talking to older systems.  This has no
+#			effect on telnetd if LINEMODE has not been defined.
+#
+#	DIAGNOSTICS	Turns on diagnostic code in telnetd; adds extra
+#			logic and checks, and debuging output if started
+#			with the -D option.
+#
+#	NO_URGENT	Define this if you don't want telnetd to send
+#			IAC DM in urgent mode when the pty output queue
+#			is flushed.
+#
+#	GENERATE_GA	Turns on code to allow the generation of Go Ahead(GA)
+#			if the server is WONT SGA.  This code is imprecise,
+#			it generates the GA when two seconds have elapsed
+#			and no input or output has occurred.
+#
+#	AUTHENTICATION	Enable the AUTHENTICATION option.
+#
+#	ENCRYPTION	Enable the ENCRYPT option.
+#
+#	KRB4		Enable Kerberos Version 4 Authentication code
+#			in libtelnet/libtelnet.a
+#
+#	KRB5		Enable Kerberos Version 5 Authentication code
+#			in libtelnet/libtelnet.a
+#
+#	SPX		Enable SPX authentication code in.
+#			libtelnet/libtelnet.a
+#
+#	RSA_ENCPWD
+#
+#	KRB4_ENCPWD
+#
+#
+#	DES_ENCRYPTION	Enable DES encryption/decryption, requires
+#			getting a the initial key from Kerberos.  This
+#			works with both Kerberos Version 4 and 5.
+#
+#	ENV_HACK	Turn on code to recognize and allow
+#			interoperability with systems that have their
+#			definitions for ENV_VALUE and ENV_VAR reversed.
+#
+#    LOCAL SYSYTEM PARAMATERS
+#
+#	TERMCAP		Define this if your system is termcap based,
+#			otherwise a terminfo based system is assumed.
+#
+#	SYSV_TERMIO	Use the System V termio structure. (implies USE_TERMIO)
+#
+#	NO_CC_T		Define this if your termio.h file does not have
+#			a typedef for cc_t.
+#
+#	USE_TERMIO	Define this if you have the POSIX termios structures.
+#			This code works under the BSD 4.4 terminal driver.
+#
+#	HAS_GETTOS	Define this if you have the setsockopt() option for
+#			setting the IP Type Of Service bits, (IP_TOS) and
+#			you have the gettosbyname() function.
+#
+#	NEWINIT		Turns on the new init code for UNICOS systems.
+#
+#	STREAMS		This system needs <sys/stream.h> for <sys/tty.h>
+#			(Sun 4.0.3)
+#
+#	FILIO_H		This system should use <sys/fileo.h> instead
+#			of <sys/ioctl.h> (Sun 4.0.3)
+#
+#	HAVE_fd_set	This system has a typedef for fd_set, but does
+#			not have FDSET() defined.
+#
+#	NO_STRING_H	If you don't have <string.h>, but have <strings.h>
+#
+#	LOGIN_PROGRAM=	Specifies the login program to use.  By default,
+#			it is /bin/login, or whatever is specified by 
+#			_PATH_LOGIN in <paths.h>
+#
+#	NO_LOGIN_P	If /bin/login doesn't understand the "-p"
+#			(preserve environment) option.
+#
+#	LOGIN_ARGS	if /bin/login understands environment variables
+#			after the login name.  Only used if NO_LOGIN_P
+#			is defined.
+#
+#	NO_LOGIN_F	If /bin/login doesn't understand the "-f" option.
+#			Only used if AUTHENTICATION is defined.
+#
+#	LOGIN_CAP_F	If /bin/login understands the "-F" option (which
+#			works like "-f", but root logins are allowed).
+#			Only used if NO_LOGIN_F is not defined.
+#
+#	LOGIN_R		This says that /bin/login understands the "-r host"
+#			option.  Only used if NO_LOGIN_F is defined (and
+#			the system supports the TIOCSTI ioctl).
+#
+#	LOGIN_HOST	Only applies if LOGIN_R is defined.  This
+#			specifies the hostname to be passed to "login -r"
+#			for successfully authenticated logins.  This
+#			defaults to "localhost" (don't forget to include
+#			the quotes, e.g. -DLOGIN_HOST=\"localhost\").
+#
+#			It can also be set to host (-DLOGIN_HOST=host)
+#			to have the real hostname passed to "/bin/login -r".
+#			  NOTE: If you do this, then anyone that wants to
+#				allow authenticated login access will have
+#				to add those remote hosts to their .rhosts,
+#				which sort of defeats the whole purpose of
+#				authenticated login... 
+#
+#	NO_BSD_SETJMP	For UNICOS releases prior to 7.0.  Turns off
+#			the inclusion of <bsdsetjmp.h>.
+#
+#	STREAMS		If the system has streams; causes <sys/stream.h>
+#			to be included instead of <sys/tty.h>
+#
+#	MUST_ALIGN	If !KRB & !HAVE_KRB4_DES_LIB and your words
+#			must be word aligned.
+#
+#	STREAMSPTY	Use /dev/ptmx to get a clean pty.  Uses
+#			streams packet mode rather than Berkeley.
+#			Appropriate for SVr4 derivatives.
+#
+#	UTMPX		System has /etc/utmpx as well as /etc/utmp.
+#			Use makeutx and modutx to update utmp/x and wtmp/x.
+#			Appropriate for SVr4 derivatives.
+#
+#	HAS_CGETENT	If your system has the cgetent() and cgetstr()
+#			routines.  This is a 4.4BSD feature, that
+#			eliminates grabbing the getty gettytab.c source.
+#			You need to include getent.o on the LIB_OBJ
+#			line if this is defined.
+#
+#	OLD_ENVIRON	Support for the old environment option.
+
+# LIB_OBJ=
+#    This is a list of object files that are needed but are not in
+#    the standard C library.
+#
+# 	    strcasecmp.o	If you don't have strncasecmp(3)
+#	    strdup.o		If you don't have strdup(3)
+#	    setenv.o		If you don't have setenv(3) and unsetenv(3)
+#	    setsid.o		If you don't have the POSIX setsid() call
+#	    strerror.o		If you don't have strerror(3)
+#	    strftime.o		If you don't have strftime(3)
+#	    getopt.o		If you don't have getopt(3)
+#	    herror.o		If you don't have herror(3)
+#	    gettytab.o		If you can get gettytab.c from getty source.
+#	    getent.o		If you can't get gettytab.c (or have
+#				HAS_CGETENT defined...)
+#	    mem.o		If you don't have mem*(3) routines.
+
+# LIB_SRC=
+#    This is a list of source modules for specificed in LIB_OBJ.
+#    This information is used by make for checking dependencies.
+
+
+# LIBS=
+#    This is a list of libraries to be included.  This will always
+#    include the telnet library, and will also include either -lcurses
+#    or -ltermcap, -lutil for 4.4bsd, and -lnet for UNICOS5.0 and earlier.
+#    Also -lkrb & -ldes if Kerberos.
+
+# LIBPATH=
+#    This is a list of the paths to all the libraries listed in LIBS.
+#    This information is used by make for checking dependencies.
+#    Don't forget libc.a
+
+# VPATH=
+#    Directory where gettytab.c can be found, if you have it.
+
+# LIBEXEC=
+#    Directory where the telnetd executable should be installed.
+
+# LCCFLAGS=
+#    Local flags for ${CC} (like -O)
+
+# AR=
+#    Name of "ar" program, usually just "ar".
+
+# ARFLAGS
+#    Flags to pass to ${AR}
+
+# RANLIB
+#    Name of "ranlib" program, set it to "NONE" if you don't
+#    have a "ranlib".
+
+all:
+	@echo "You must specify what type of system you are on,"
+	@echo "or setup a Config.local file for your system."
+	@echo "Known system types are:"
+	@echo
+	@echo " 4.4bsd 4.3reno 4.4bsd.auth 4.3reno.auth 4.3tahoe 4.3bsd"
+	@echo " bsdi1.0 bsdi1.0.auth"
+	@echo " unicos8.1 unicos8.0 unicos7.C unicos7.0"
+	@echo " unicos8.1.auth unicos8.0.auth unicos7.0.auth"
+	@echo " unicos7.C.auth unicos7.0.des.auth"
+	@echo " unicos6.1 unicos6.0 unicos5.1 unicos5.0"
+	@echo " sun3.5 sun4.0.3c sun4.0 sun4.1 sun4.1.auth"
+	@echo " solaris2.2 solaris2.2.auth"
+	@echo " dynix3.0.12 dynix3.0.17"
+	@echo " ultrix3.1 ultrix4.0 ultrix4.1 ultrix4.3 ultrix4.3.auth"
+	@echo " irix4.0.1"
+	@echo " hpux8.0"
+	@echo " next1.0"
+	@echo " convex"
+
+4.4bsd:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lutil -ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/usr/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/bin \
+		DEFINES=${ODEFS}"-DLINEMODE -DTERMCAP -DKLUDGELINEMODE \
+		    -DDEFAULT_IM='\"\r\n4.4 BSD UNIX (%h) (%t)\r\n\r\r\n\r\"' \
+			-DUSE_TERMIO -DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON \
+			-DHAS_CGETENT" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o" \
+		LIB_SRC="getent.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/libexec \
+		CC="${CC}" LCCFLAGS="-O"
+
+4.3reno:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lutil -ltermcap ../libtelnet/libtelnet.a ${AUTH_LIB}" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a ${AUTH_LIBPATH}" \
+		DEST=${DESTDIR}/usr/bin \
+		DEFINES=${ODEFS}"-DLINEMODE -DTERMCAP -DKLUDGELINEMODE \
+	-DDEFAULT_IM='\"\r\n4.3BSD-Reno UNIX (%h) (%t)\r\n\r\r\n\r\"' \
+			-DUSE_TERMIO -DDIAGNOSTICS -DENV_HACK \
+			-DOLD_ENVIRON ${AUTH_DEF}" \
+		INCLUDES="-I.. ${AUTH_INC}" \
+		LIB_OBJ="gettytab.o" \
+		LIB_SRC="gettytab.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		VPATH=/usr/src/libexec/getty \
+		LIBEXEC=${DESTDIR}/usr/libexec \
+		CC="${CC}" LCCFLAGS="-O"
+
+
+4.4bsd.auth 4.3reno.auth:
+	make -f ../Config.generic `basename $@ .auth` WHAT=${WHAT} \
+		AUTH_LIB="-lkrb -ldes" \
+		AUTH_LIBPATH="/usr/lib/libkrb.a /usr/lib/libdes.a" \
+		AUTH_DEF="-DAUTHENTICATION -DENCRYPTION -DKRB4 -DDES_ENCRYPTION"
+
+4.3tahoe:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/bin \
+		DEFINES=${ODEFS}"-DTERMCAP -DKLUDGELINEMODE \
+		 -DDEFAULT_IM='\"\r\n4.3BSD-Tahoe UNIX (%h) (%t)\r\n\r\r\n\r\"'\
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		INCLUDES="-I.." \
+		LIB_OBJ="strdup.o setsid.o strftime.o gettytab.o" \
+		LIB_SRC="strdup.c setsid.c strftime.c gettytab.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		VPATH=/usr/src/etc/getty \
+		LIBEXEC=${DESTDIR}/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+4.3bsd:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/bin \
+		DEFINES=${ODEFS}"-DTERMCAP -DKLUDGELINEMODE \
+		    -DDEFAULT_IM='\"\r\n4.3BSD UNIX (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		INCLUDES="-I.." \
+		LIB_OBJ="strdup.o setsid.o strftime.o \
+			gettytab.o getopt.o herror.o" \
+		LIB_SRC="strdup.c setsid.c strftime.c \
+			gettytab.c getopt.c herror.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		VPATH=/usr/src/etc/getty \
+		LIBEXEC=${DESTDIR}/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+bsdi1.0:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lutil -ltermcap ../libtelnet/libtelnet.a ${AUTH_LIB}" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+			../libtelnet/libtelnet.a ${AUTH_LIBPATH}" \
+		DEST=${DESTDIR}/usr/bin \
+		DEFINES=${ODEFS}"-DLINEMODE -DTERMCAP -DKLUDGELINEMODE \
+	-DDEFAULT_IM='\"\r\nBSDI BSD/386 1.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DUSE_TERMIO -DDIAGNOSTICS -DENV_HACK \
+			-DOLD_ENVIRON ${AUTH_DEF}" \
+		INCLUDES="-I.. ${AUTH_INC}" \
+		LIB_OBJ="gettytab.o" \
+		LIB_SRC="gettytab.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		VPATH=/usr/src/libexec/getty \
+		LIBEXEC=${DESTDIR}/usr/libexec \
+		CC="${CC}" LCCFLAGS="-O"
+
+bsdi1.0.auth:
+	make -f ../Config.generic `basename $@ .auth` WHAT=${WHAT} \
+		AUTH_LIB="-lkrb -ldes" \
+		AUTH_LIBPATH="/usr/lib/libkrb.a /usr/lib/libdes.a" \
+		AUTH_DEF="-DAUTHENTICATION -DENCRYPTION -DKRB4 -DDES_ENCRYPTION"
+		AUTH_INC=-I/usr/include/kerberosIV
+
+unicos8.1:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lcurses -L../libtelnet -ltelnet ${AUTH_LIB}" \
+		LIBPATH="/lib/libc.a /usr/lib/libcurses.a \
+				../libtelnet/libtelnet.a ${AUTH_LIBPATH}" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-Dvfork=fork -Dsignal=bsdsignal \
+			-DLINEMODE -DKLUDGELINEMODE \
+			-DSYSV_TERMIO -DHAS_GETTOS ${AUTH_DEF} \
+		  -DDEFAULT_IM='\"\r\nCray UNICOS 8.1 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		AR=bld ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		INCLUDES="-I.. ${AUTH_INC}" \
+		LIB_OBJ="getent.o" \
+		LIB_SRC="getent.c" \
+
+unicos8.0:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lcurses -L../libtelnet -ltelnet ${AUTH_LIB}" \
+		LIBPATH="/lib/libc.a /usr/lib/libcurses.a \
+				../libtelnet/libtelnet.a ${AUTH_LIBPATH}" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-Dvfork=fork -Dsignal=bsdsignal \
+			-DLINEMODE -DKLUDGELINEMODE \
+			-DSYSV_TERMIO -DHAS_GETTOS ${AUTH_DEF} \
+		  -DDEFAULT_IM='\"\r\nCray UNICOS 8.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		AR=bld ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		INCLUDES="-I.. ${AUTH_INC}" \
+		LIB_OBJ="getent.o" \
+		LIB_SRC="getent.c" \
+		CC="${CC}" LCCFLAGS="-O"
+
+unicos7.C:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lcurses -L../libtelnet -ltelnet ${AUTH_LIB}" \
+		LIBPATH="/lib/libc.a /usr/lib/libcurses.a \
+				../libtelnet/libtelnet.a ${AUTH_LIBPATH}"\
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-Dvfork=fork -Dsignal=bsdsignal \
+			-DLINEMODE -DKLUDGELINEMODE \
+			-DSYSV_TERMIO -DHAS_GETTOS ${AUTH_DEF} \
+		  -DDEFAULT_IM='\"\r\nCray UNICOS 7.C (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		AR=bld ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		INCLUDES="-I.. ${AUTH_INC}" \
+		LIB_OBJ="getent.o" \
+		LIB_SRC="getent.c" \
+		CC="${CC}" LCCFLAGS="-O"
+
+
+unicos7.0:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lcurses -L../libtelnet -ltelnet -lkrb" \
+		LIBPATH="/lib/libc.a /usr/lib/libcurses.a \
+				../libtelnet/libtelnet.a /usr/lib/libkrb.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-Dvfork=fork -Dsignal=bsdsignal \
+			-DLINEMODE -DKLUDGELINEMODE \
+			-DSYSV_TERMIO -DHAS_GETTOS \
+		  -DDEFAULT_IM='\"\r\nCray UNICOS 7.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		AR=bld ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o" \
+		LIB_SRC="getent.c" \
+		CC="${CC}" LCCFLAGS="-O"
+
+# As of UNICOS 7.0.5.2, there is no longer a /usr/lib/libdes.a
+# If you still have a /usr/lib/libdes.a, use the "unicos7.0.des.auth"
+# target instead of "unicos7.0.auth".
+
+unicos8.1.auth unicos8.0.auth unicos7.0.auth:
+	make -f ../Config.generic `basename $@ .auth` WHAT=${WHAT} \
+		AUTH_LIB=-lkrb AUTH_LIBPATH=/usr/lib/libkrb.a \
+		AUTH_INC=-I/usr/include/krb \
+		AUTH_DEF="-DAUTHENTICATION -DENCRYPTION -DKRB4 -DDES_ENCRYPTION"
+
+unicos7.C.auth unicos7.0.des.auth:
+	make -f ../Config.generic `basename $@ .des.auth` WHAT=${WHAT} \
+		AUTH_LIB="-lkrb -ldes" \
+		AUTH_LIBPATH="/usr/lib/libkrb.a /usr/lib/libdes.a" \
+		AUTH_INC=-I/usr/include/krb \
+		AUTH_DEF="-DAUTHENTICATION -DENCRYPTION -DKRB4 -DDES_ENCRYPTION"
+
+unicos6.1:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lcurses -L../libtelnet -ltelnet" \
+		LIBPATH="/lib/libc.a /usr/lib/libcurses.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-Dvfork=fork -Dsignal=bsdsignal \
+			-DKLUDGELINEMODE -DUSE_TERMIO -DHAS_GETTOS \
+			-DLINEMODE -DSYSV_TERMIO -DNEWINIT \
+			-DNO_LOGIN_F -DNO_LOGIN_P -DNO_BSD_SETJMP \
+			-DLOGIN_ARGS \
+		  -DDEFAULT_IM='\"\r\nCray UNICOS 6.1 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		AR=bld ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o parsetos.o" \
+		LIB_SRC="getent.c parsetos.c" \
+		CC="${CC}" LCCFLAGS="-O"
+
+unicos6.0:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lcurses -L../libtelnet -ltelnet" \
+		LIBPATH="/lib/libc.a /usr/lib/libcurses.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-Dvfork=fork -Dsignal=bsdsignal \
+			-DKLUDGELINEMODE -DUSE_TERMIO -DHAS_GETTOS \
+			-DLINEMODE -DSYSV_TERMIO -DNEWINIT \
+			-DNO_LOGIN_F -DNO_LOGIN_P -DNO_BSD_SETJMP \
+			-DLOGIN_ARGS \
+		  -DDEFAULT_IM='\"\r\nCray UNICOS 6.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		AR=bld ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o parsetos.o" \
+		LIB_SRC="getent.c parsetos.c" \
+		CC="${CC}" LCCFLAGS="-O"
+
+unicos5.1:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lnet -lcurses -L../libtelnet -ltelnet" \
+		LIBPATH="/lib/libc.a /usr/lib/libcurses.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-Dvfork=fork -Dsignal=sigset \
+			-DKLUDGELINEMODE -DSYSV_TERMIO -DNO_CC_T \
+			-DUNICOS5 -DLINEMODE -DSYSV_TERMIO \
+			-DNEWINIT -DNO_LOGIN_F -DNO_LOGIN_P -DNO_BSD_SETJMP \
+			-DLOGIN_ARGS \
+		  -DDEFAULT_IM='\"\r\nCray UNICOS 5.1 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strerror.o setsid.o strftime.o" \
+		LIB_SRC="getent.c strerror.c setsid.c strftime.c" \
+		AR=bld ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+unicos5.0:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-lnet -lcurses -L../libtelnet -ltelnet" \
+		LIBPATH="/lib/libc.a /usr/lib/libcurses.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-Dvfork=fork -Dsignal=sigset \
+			-DKLUDGELINEMODE -DSYSV_TERMIO -DNO_CC_T \
+			-DUNICOS5 -DUNICOS50 -DLINEMODE -DSYSV_TERMIO \
+			-DNEWINIT -DNO_LOGIN_F -DNO_LOGIN_P -DNO_BSD_SETJMP \
+			-DLOGIN_ARGS \
+		  -DDEFAULT_IM='\"\r\nCray UNICOS 5.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strerror.o setsid.o strftime.o" \
+		LIB_SRC="getent.c strerror.c setsid.c strftime.c" \
+		AR=bld ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+sun3.5:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DTERMCAP -DKLUDGELINEMODE \
+			-DHAVE_fd_set \
+			-DDIAGNOSTICS  -DENV_HACK -DOLD_ENVIRON \
+		   -DDEFAULT_IM='\"\r\nSunOS UNIX 3.5 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DNO_LOGIN_P" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strdup.o strerror.o setsid.o \
+			setenv.o strftime.o strcasecmp.o herror.o" \
+		LIB_SRC="getent.c strdup.c strerror.c setsid.c \
+			setenv.c strftime.c strcasecmp.c herror.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc/in.telnetd \
+		CC="${CC}" LCCFLAGS="-O"
+
+sun4.0.3c sun4.0:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DFILIO_H -DTERMCAP -DUSE_TERMIO -DNO_CC_T \
+			-DKLUDGELINEMODE \
+		   -DDEFAULT_IM='\"\r\nSunOS UNIX 4.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DSTREAMS -DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON \
+			" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strerror.o setsid.o setenv.o \
+				strcasecmp.o strftime.o herror.o" \
+		LIB_SRC="getent.c strerror.c setsid.c setenv.c \
+				strcasecmp.c strftime.c herror.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc/in.telnetd \
+		CC="${CC}" LCCFLAGS="-O"
+
+sun4.1:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a ${AUTH_LIB}" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+			../libtelnet/libtelnet.a ${AUTH_LIBPATH}" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DFILIO_H -DTERMCAP -DUSE_TERMIO \
+			-DKLUDGELINEMODE -DSTREAMS \
+		   -DDEFAULT_IM='\"\r\nSunOS UNIX 4.1 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON ${AUTH_DEF}" \
+		INCLUDES="-I.. ${AUTH_INC}" \
+		LIB_OBJ="getent.o strerror.o setenv.o herror.o" \
+		LIB_SRC="getent.c strerror.c setenv.c herror.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc/in.telnetd \
+		CC="${CC}" LCCFLAGS="-O"
+
+sun4.1.auth:
+	make -f ../Config.generic `basename $@ .auth` WHAT=${WHAT} \
+		AUTH_LIB="-lkrb -ldes" \
+		AUTH_LIBPATH="/usr/lib/libkrb.a /usr/lib/libdes.a" \
+		AUTH_DEF="-DAUTHENTICATION -DENCRYPTION -DKRB4 -DDES_ENCRYPTION"
+
+sol2.2 solaris2.2:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermlib ../libtelnet/libtelnet.a" \
+		LIBPATH="/usr/ccs/lib/libtermlib.a ../libtelnet/libtelnet.a \
+			/usr/lib/libc.a /usr/ucblib/libucb.a \
+			/usr/lib/libsocket.a /usr/lib/libnsl.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES="-DFILIO_H -DUSE_TERMIO -DKLUDGELINEMODE \
+			-DSTREAMS -DSTREAMSPTY -DDIAGNOSTICS -DSOLARIS \
+			-DENV_HACK -DOLD_ENVIRON -DNO_LOGIN_P -DUTMPX \
+	-DDEFAULT_IM='\"\r\n\r\nUNIX(r) System V Release 4.0 (%h)\r\n\r\n\"' \
+			-DLOGIN_ARGS" \
+		INCLUDES="-I.. -I/usr/ucbinclude" \
+		LIB_OBJ="getent.o strerror.o setenv.o herror.o" \
+		LIB_SRC="getent.c strerror.c setenv.c herror.c" \
+		AR=ar ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/usr/etc/in.telnetd \
+		CC="${CC}" LCCFLAGS="-O"
+
+sol2.2.auth solaris2.2.auth:
+	make -f ../Config.generic `basename $@ .auth` WHAT=${WHAT} \
+		AUTH_LIB="-lkrb" AUTH_LIBPATH="/usr/lib/libkrb.a" \
+		AUTH_INC=-I/usr/include/kerberos \
+		AUTH_DEF="-DAUTHENTICATION -DKRB4"
+
+dynix3.0.12:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DTERMCAP -DKLUDGELINEMODE \
+		 -DDEFAULT_IM='\"\r\nDYNIX(R) V3.0.12 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON -DNO_STRING_H " \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strchr.o strrchr.o strdup.o strerror.o \
+			setsid.o setenv.o strcasecmp.o strftime.o getopt.o \
+			mem.o" \
+		LIB_SRC="getent.c strchr.c strrchr.c strdup.c strerror.c \
+			setsid.c setenv.c strcasecmp.c strftime.c getopt.c \
+			mem.o" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+dynix3.0.17:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a -lseq" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+			../libtelnet/libtelnet.a /usr/lib/libseq.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DTERMCAP -DKLUDGELINEMODE \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON -DNO_STRING_H \
+		 -DDEFAULT_IM='\"\r\nDYNIX(R) V3.0.17 (%h) (%t)\r\n\r\r\n\r\"' \
+			" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strchr.o strrchr.o strdup.o strerror.o \
+			setsid.o strftime.o mem.o" \
+		LIB_SRC="getent.c strchr.c strrchr.c strdup.c strerror.c \
+			setsid.c strftime.c mem.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+ultrix3.1:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DTERMCAP -DKLUDGELINEMODE \
+			-DNO_LOGIN_F -DNO_LOGIN_P -DNO_LOGIN_H \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON -DUSE_TERMIO \
+		    -DDEFAULT_IM='\"\r\nULTRIX V3.1 (%h) (%t)\r\n\r\r\n\r\"' \
+			-YPOSIX" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strdup.o strerror.o setenv.o \
+			strftime.o herror.o" \
+		LIB_SRC="getent.c strdup.c strerror.c setenv.c \
+			strftime.c herror.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+ultrix4.0:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DUSE_TERMIO -DTERMCAP \
+		    -DDEFAULT_IM='\"\r\nULTRIX V4.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DKLUDGELINEMODE -DDIAGNOSTICS \
+			-DNO_LOGIN_F -DNO_LOGIN_P -DNO_LOGIN_H \
+			-DENV_HACK -DOLD_ENVIRON" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strdup.o strerror.o setsid.o \
+			setenv.o strftime.o" \
+		LIB_SRC="getent.c strdup.c strerror.c setsid.c \
+			setenv.c strftime.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+ultrix4.1:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DUSE_TERMIO -DTERMCAP \
+		    -DDEFAULT_IM='\"\r\nULTRIX V4.1 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DKLUDGELINEMODE -DDIAGNOSTICS \
+			-DNO_LOGIN_F -DNO_LOGIN_P -DNO_LOGIN_H \
+			-DENV_HACK -DOLD_ENVIRON" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o strdup.o" \
+		LIB_SRC="getent.c strdup.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+ultrix4.3:
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a ${AUTH_LIB}" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a ${AUTH_LIBPATH}" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-DUSE_TERMIO -DTERMCAP \
+		    -DDEFAULT_IM='\"\r\nULTRIX V4.3 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DKLUDGELINEMODE -DDIAGNOSTICS \
+			-DNO_LOGIN_F -DNO_LOGIN_P -DNO_LOGIN_H \
+			-DENV_HACK -DOLD_ENVIRON ${AUTH_DEF}" \
+		INCLUDES="-I.. ${AUTH_INC}" \
+		LIB_OBJ="getent.o strdup.o" \
+		LIB_SRC="getent.c strdup.c" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc \
+		CC="${CC}" LCCFLAGS="-g"
+
+ultrix4.3.auth:
+	make -f ../Config.generic `basename $@ .auth` WHAT=${WHAT} \
+		AUTH_LIB="-lkrb -ldes" \
+		AUTH_LIBPATH="/usr/lib/libkrb.a /usr/lib/libdes.a" \
+		AUTH_DEF="-DAUTHENTICATION -DKRB4"
+
+irix4.0.1:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermlib ../libtelnet/libtelnet.a" \
+		LIBPATH="/usr/lib/libc.a /usr/lib/libtermlib.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/bin \
+		DEFINES=${ODEFS}"-Dvfork=fork -DUSE_TERMIO \
+		    -DDEFAULT_IM='\"\r\n\r\nIRIX System V.3 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DNO_LOGIN_F -DNO_LOGIN_P \
+			-DDIAGNOSTICS " \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o setenv.o" \
+		LIB_SRC="getent.c setenv.c" \
+		AR=ar ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+hpux8.0:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="/lib/libc.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a" \
+		DEST=${DESTDIR}/usr/bin \
+		DEFINES=${ODEFS}"-Dvfork=fork -DUSE_TERMIO \
+		    -DDEFAULT_IM='\"\r\n\r\nHP-UX 8.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DNO_LOGIN_F -DNO_LOGIN_P -DNO_LOGIN_H \
+			-DDIAGNOSTICS -DLOGIN_ARGS" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o setenv.o" \
+		LIB_SRC="getent.c setenv.c" \
+		AR=ar ARFLAGS=cq RANLIB=NONE \
+		LIBEXEC=${DESTDIR}/etc \
+		CC="${CC}" LCCFLAGS="-O"
+
+next1.0:
+	@echo $@ is untested... it may or may not work..."
+	make -f Makefile.generic ${WHAT} \
+		LIBS="../libtelnet/libtelnet.a -ltermcap -lsys_s ${AUTH_LIB}" \
+		LIBPATH="/lib/libc.a /lib/libsys_s.a /usr/lib/libtermcap.a \
+				../libtelnet/libtelnet.a ${AUTH_LIBPATH}" \
+		DEST=${DESTDIR}/usr/ucb \
+		DEFINES=${ODEFS}"-bsd -DTERMCAP -DKLUDGELINEMODE \
+			-DDEFAULT_IM='\"\r\nNeXT 1.0 (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON \
+			-DNO_STRING_H -Dgetenv=getenv_ ${AUTH_DEF}" \
+		INCLUDES="-I.. ${AUTH_INC}" \
+		LIB_OBJ="strdup.o setenv.o setsid.o strftime.o \
+			strcasecmp.o gettytab.o" \
+		LIB_SRC=s"trdup.c setenv.c setsid.c strftime.c \
+			strcasecmp.c gettytab.c" \
+		CC="${CC}" LCCFLAGS="-O" \
+		VPATH=../../getty \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc
+
+#
+# For the convex, make symbolic links to the tc[sg]getattr.c routines,
+# because we are using posix stuff, but not the posix library...
+# Pass the stuff to Makefile.generic by passing the object/source names
+# in through LIB_OBJ and LIB_SRC
+#
+convex:
+	@echo $@ is untested... it may or may not work..."
+	ln -s ../../rel_usr/src/lib/libc/posix/tcsetattr.c tcsetattr.c
+	ln -s ../../rel_usr/src/lib/libc/posix/tcgetattr.c tcgetattr.c
+	make -f Makefile.generic ${WHAT} \
+		LIBS="-ltermcap ../libtelnet/libtelnet.a" \
+		LIBPATH="../libtelnet/libtelnet.a" \
+		AR=ar ARFLAGS=cq RANLIB=ranlib \
+		LIBEXEC=${DESTDIR}/usr/etc/in.telnetd \
+		CC="${CC}" LCCFLAGS="-g ${OPTLEV} -Dconvex" \
+		DEFINES=${ODEFS}"-DUSE_TERMIO -DLINEMODE \
+			-DDEFAULT_IM='\"\r\nConvex (%h) (%t)\r\n\r\r\n\r\"' \
+			-DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON" \
+		INCLUDES="-I.." \
+		LIB_OBJ="getent.o setsid.o strftime.o \
+			tcsetattr.o tcgetattr.o" \
+		LIB_SRC="getent.c setsid.c strftime.c \
+			tcsetattr.c tcgetattr.c"
+
+clean cleandir:
+	make -f Makefile.generic $@
diff --git a/mechglue/src/appl/telnet/Makefile.in b/mechglue/src/appl/telnet/Makefile.in
new file mode 100644
index 000000000..32e41551f
--- /dev/null
+++ b/mechglue/src/appl/telnet/Makefile.in
@@ -0,0 +1,5 @@
+thisconfigdir=.
+myfulldir=appl/telnet
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCAL_SUBDIRS=libtelnet telnet telnetd
diff --git a/mechglue/src/appl/telnet/README b/mechglue/src/appl/telnet/README
new file mode 100644
index 000000000..29d51a392
--- /dev/null
+++ b/mechglue/src/appl/telnet/README
@@ -0,0 +1,679 @@
+
+This is a distribution of both client and server telnet.  These programs
+have been compiled on:
+			telnet	telnetd
+	BSD 4.4		  x	  x
+	BSD 4.3 Reno	  X	  X
+	UNICOS 8.0	  X	  X
+	UNICOS 7.C	  X	  X
+	UNICOS 7.0	  X	  X
+	UNICOS 6.1	  X	  X
+	BSDI 1.0	  X	  X
+	Solaris 2.2       x       x (no linemode in server)
+	Solaris 2.3       x       x (no linemode in server)
+	SunOs 4.1.3	  X	  X (no linemode in server)
+	Ultrix 4.3	  X	  X (no linemode in server)
+	DYNIX V3.0.17.9	  X	  X (no linemode in server)
+	HP-UX 8.0	  x       x (no linemode in server)
+
+In addition, previous versions have been compiled on the following
+machines, but were not available for testing this version.
+			telnet	telnetd
+	Next1.0		  X	  X
+	UNICOS 6.0	  X	  X
+	UNICOS 5.1	  X	  X
+	UNICOS 5.0	  X	  X
+	SunOs 4.0.3c	  X	  X (no linemode in server)
+	BSD 4.3		  X  	  X (no linemode in server)
+	DYNIX V3.0.12	  X	  X (no linemode in server)
+	Ultrix 3.1	  X	  X (no linemode in server)
+	Ultrix 4.0	  X	  X (no linemode in server)
+	SunOs 3.5	  X	  X (no linemode in server)
+
+This code should work, but there are no guarantees.
+
+January 19, 1994
+
+This is a list of some of the changes since the last tar release
+of telnet/telnetd.  There are probably other changes that aren't
+listed here, but this should hit a lot of the main ones.
+
+   General:
+	Changed #define for AUTHENTICATE to AUTHENTICATION
+	Changed #define for ENCRYPT to ENCRYPTION
+	Changed #define for DES_ENCRYPT to DES_ENCRYPTION
+
+	Added support for SPX authentication: -DSPX
+
+	Added support for Kerberos Version 5 authentication: -DKRB5
+
+	Added support for ANSI C function prototypes
+
+	Added support for the NEW-ENVIRON option (RFC-1572)
+	including support for USERVAR.
+
+	Made support for the old Environment Option (RFC-1408)
+	conditional on -DOLD_ENVIRON
+
+	Added #define ENV_HACK - support for RFC 1571
+
+	The encryption code is removed from the public distributions.
+	Domestic 4.4 BSD distributions contain the encryption code.
+
+	ENV_HACK: Code to deal with systems that only implement
+		the old ENVIRON option, and have reversed definitions
+		of ENV_VAR and ENV_VAL.  Also fixes ENV processing in
+		client to handle things besides just the default set...
+
+	NO_BSD_SETJMP: UNICOS configuration for
+		UNICOS 6.1/6.0/5.1/5.0 systems.
+
+	STREAMSPTY: Use /dev/ptmx to get a clean pty.  This
+		is for SVr4 derivatives (Like Solaris)
+
+	UTMPX: For systems that have /etc/utmpx. This is for
+		SVr4 derivatives (Like Solaris)
+
+	Definitions for BSDI 1.0
+
+	Definitions for 4.3 Reno and 4.4 BSD.
+
+	Definitions for UNICOS 8.0 and UNICOS 7.C
+
+	Definitions for Solaris 2.0
+
+	Definitions for HP-UX 8.0
+
+	Latest Copyright notices from Berkeley.
+
+	FLOW-CONTROL: support for RFC-XXXx
+
+
+   Client Specific:
+
+	Fix the "send" command to not send garbage...
+
+	Fix status message for "skiprc"
+
+	Make sure to send NAWS after telnet has been suspended
+	or an external command has been run, if the window size
+	has changed.
+
+	sysV88 support.
+
+   Server Specific:
+
+	Support flowcontrol option in non-linemode servers.
+
+	-k Server supports Kludge Linemode, but will default to
+	   either single character mode or real Linemode support.
+	   The user will have to explicitly ask to switch into
+	   kludge linemode. ("stty extproc", or escape back to
+	   to telnet and say "mode line".)
+
+	-u Specify the length of the hostname field in the utmp
+	   file.  Hostname longer than this length will be put
+	   into the utmp file in dotted decimal notation, rather
+	   than putting in a truncated hostname.
+	
+	-U Registered hosts only.  If a reverse hostname lookup
+	   fails, the connection will be refused.
+
+	-f/-F
+	   Allows forwarding of credentials for KRB5.
+
+Februrary 22, 1991:
+
+    Features:
+
+	This version of telnet/telnetd has support for both
+	the AUTHENTICATION and ENCRYPTION options.  The
+	AUTHENTICATION option is fairly well defined, and
+	an option number has been assigned to it.  The
+	ENCRYPTION option is still in a state of flux; an
+	option number has been assigned to, but it is still
+	subject to change.  The code is provided in this release
+	for experimental and testing purposes.
+
+	The telnet "send" command can now be used to send
+	do/dont/will/wont commands, with any telnet option
+	name.  The rules for when do/dont/will/wont are sent
+	are still followed, so just because the user requests
+	that one of these be sent doesn't mean that it will
+	be sent...
+
+	The telnet "getstatus" command no longer requires
+	that option printing be enabled to see the response
+	to the "DO STATUS" command.
+
+	A -n flag has been added to telnetd to disable
+	keepalives.
+
+	A new telnet command, "auth" has been added (if
+	AUTHENTICATE is defined).  It has four sub-commands,
+	"status", "disable", "enable" and "help".
+
+	A new telnet command, "encrypt" has been added (if
+	ENCRYPT is defined).  It has many sub-commands:
+	"enable", "type", "start", "stop", "input",
+	"-input", "output", "-output", "status", and "help".
+
+	The LOGOUT option is now supported by both telnet
+	and telnetd, a new command, "logout", was added
+	to support this.
+
+	Several new toggle options were added:
+	    "autoencrypt", "autodecrypt", "autologin", "authdebug",
+	    "encdebug", "skiprc", "verbose_encrypt"
+
+	An "rlogin" interface has been added.  If the program
+	is named "rlogin", or the "-r" flag is given, then
+	an rlogin type of interface will be used.
+		~.	Terminates the session
+		~<susp> Suspend the session
+		~^]	Escape to telnet command mode
+		~~	Pass through the ~.
+	    BUG: If you type the rlogin escape character
+		 in the middle of a line while in rlogin
+		 mode, you cannot erase it or any characters
+		 before it.  Hopefully this can be fixed
+		 in a future release...
+
+    General changes:
+
+	A "libtelnet.a" has now been created.  This libraray
+	contains code that is common to both telnet and
+	telnetd.  This is also where library routines that
+	are needed, but are not in the standard C library,
+	are placed.
+
+	The makefiles have been re-done.  All of the site
+	specific configuration information has now been put
+	into a single "Config.generic" file, in the top level
+	directory.  Changing this one file will take care of
+	all three subdirectories.  Also, to add a new/local
+	definition, a "Config.local" file may be created
+	at the top level; if that file exists, the subdirectories
+	will use that file instead of "Config.generic".
+
+	Many 1-2 line functions in commands.c have been
+	removed, and just inserted in-line, or replaced
+	with a macro.
+
+    Bug Fixes:
+
+	The non-termio code in both telnet and telnetd was
+	setting/clearing CTLECH in the sg_flags word.  This
+	was incorrect, and has been changed to set/clear the
+	LCTLECH bit in the local mode word.
+
+	The SRCRT #define has been removed.  If IP_OPTIONS
+	and IPPROTO_IP are defined on the system, then the
+	source route code is automatically enabled.
+
+	The NO_GETTYTAB #define has been removed; there
+	is a compatability routine that can be built into
+	libtelnet to achive the same results.
+
+	The server, telnetd, has been switched to use getopt()
+	for parsing the argument list.
+
+	The code for getting the input/output speeds via
+	cfgetispeed()/cfgetospeed() was still not quite
+	right in telnet.  Posix says if the ispeed is 0,
+	then it is really equal to the ospeed.
+
+	The suboption processing code in telnet now has
+	explicit checks to make sure that we received
+	the entire suboption (telnetd was already doing this).
+
+	The telnet code for processing the terminal type
+	could cause a core dump if an existing connection
+	was closed, and a new connection opened without
+	exiting telnet.
+
+	Telnetd was doing a TCSADRAIN when setting the new
+	terminal settings;  This is not good, because it means
+	that the tcsetattr() will hang waiting for output to
+	drain, and telnetd is the only one that will drain
+	the output...  The fix is to use TCSANOW which does
+	not wait.
+
+	Telnetd was improperly setting/clearing the ISTRIP
+	flag in the c_lflag field, it should be using the
+	c_iflag field. 
+
+	When the child process of telnetd was opening the
+	slave side of the pty, it was re-setting the EXTPROC
+	bit too early, and some of the other initialization
+	code was wiping it out.  This would cause telnetd
+	to go out of linemode and into single character mode.
+
+	One instance of leaving linemode in telnetd forgot
+	to send a WILL ECHO to the client, the net result
+	would be that the user would see double character
+	echo.
+
+	If the MODE was being changed several times very
+	quickly, telnetd could get out of sync with the
+	state changes and the returning acks; and wind up
+	being left in the wrong state.
+
+September 14, 1990:
+
+	Switch the client to use getopt() for parsing the
+	argument list.  The 4.3Reno getopt.c is included for
+	systems that don't have getopt().
+
+	Use the posix _POSIX_VDISABLE value for what value
+	to use when disabling special characters.  If this
+	is undefined, it defaults to 0x3ff.
+
+	For non-termio systems, TIOCSETP was being used to
+	change the state of the terminal.  This causes the
+	input queue to be flushed, which we don't want.  This
+	is now changed to TIOCSETN.
+
+	Take out the "#ifdef notdef" around the code in the
+	server that generates a "sync" when the pty oputput
+	is flushed.  The potential problem is that some older
+	telnet clients may go into an infinate loop when they
+	receive a "sync", if so, the server can be compiled
+	with "NO_URGENT" defined.
+
+	Fix the client where it was setting/clearing the OPOST
+	bit in the c_lflag field, not the c_oflag field.
+
+	Fix the client where it was setting/clearing the ISTRIP
+	bit in the c_lflag field, not the c_iflag field.  (On
+	4.3Reno, this is the ECHOPRT bit in the c_lflag field.)
+	The client also had its interpretation of WILL BINARY
+	and DO BINARY reversed.
+
+	Fix a bug in client that would cause a core dump when
+	attempting to remove the last environment variable.
+
+	In the client, there were a few places were switch()
+	was being passed a character, and if it was a negative
+	value, it could get sign extended, and not match
+	the 8 bit case statements.  The fix is to and the
+	switch value with 0xff.
+
+	Add a couple more printoption() calls in the client, I
+	don't think there are any more places were a telnet
+	command can be received and not printed out when
+	"options" is on.
+
+	A new flag has been added to the client, "-a".  Currently,
+	this just causes the USER name to be sent across, in
+	the future this may be used to signify that automatic
+	authentication is requested.
+
+	The USER variable is now only sent by the client if
+	the "-a" or "-l user" options are explicity used, or
+	if the user explicitly asks for the "USER" environment
+	variable to be exported.  In the server, if it receives
+	the "USER" environment variable, it won't print out the
+	banner message, so that only "Password:" will be printed.
+	This makes the symantics more like rlogin, and should be
+	more familiar to the user.  (People are not used to
+	getting a banner message, and then getting just a
+	"Password:" prompt.)
+
+	Re-vamp the code for starting up the child login
+	process.  The code was getting ugly, and it was
+	hard to tell what was really going on.  What we
+	do now is after the fork(), in the child:
+		1) make sure we have no controlling tty
+		2) open and initialize the tty
+		3) do a setsid()/setpgrp()
+		4) makes the tty our controlling tty.
+	On some systems, #2 makes the tty our controlling
+	tty, and #4 is a no-op.  The parent process does
+	a gets rid of any controlling tty after the child
+	is fork()ed.
+
+	Use the strdup() library routine in telnet, instead
+	of the local savestr() routine.  If you don't have
+	strdup(), you need to define NO_STRDUP.
+
+	Add support for ^T (SIGINFO/VSTATUS), found in the
+	4.3Reno distribution.  This maps to the AYT character.
+	You need a 4-line bugfix in the kernel to get this
+	to work properly:
+
+	> *** tty_pty.c.ORG	Tue Sep 11 09:41:53 1990
+	> --- tty_pty.c	Tue Sep 11 17:48:03 1990
+	> ***************
+	> *** 609,613 ****
+	> 			if ((tp->t_lflag&NOFLSH) == 0)
+	> 				ttyflush(tp, FREAD|FWRITE);
+	> ! 			pgsignal(tp->t_pgrp, *(unsigned int *)data);
+	> 			return(0);
+	> 		}
+	> --- 609,616 ----
+	> 			if ((tp->t_lflag&NOFLSH) == 0)
+	> 				ttyflush(tp, FREAD|FWRITE);
+	> ! 			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
+	> ! 			if ((*(unsigned int *)data == SIGINFO) &&
+	> ! 			    ((tp->t_lflag&NOKERNINFO) == 0))
+	> ! 				ttyinfo(tp);
+	> 			return(0);
+	> 		}
+
+	The client is now smarter when setting the telnet escape
+	character; it only sets it to one of VEOL and VEOL2 if
+	one of them is undefined, and the other one is not already
+	defined to the telnet escape character.
+
+	Handle TERMIOS systems that have seperate input and output
+	line speed settings imbedded in the flags.
+
+	Many other minor bug fixes.
+
+June 20, 1990:
+	Re-organize makefiles and source tree.  The telnet/Source
+	directory is now gone, and all the source that was in
+	telnet/Source is now just in the telnet directory.
+
+	Seperate makefile for each system are now gone.  There
+	are two makefiles, Makefile and Makefile.generic.
+	The "Makefile" has the definitions for the various
+	system, and "Makefile.generic" does all the work.
+	There is a variable called "WHAT" that is used to
+	specify what to make.  For example, in the telnet
+	directory, you might say:
+		make 4.4bsd WHAT=clean
+	to clean out the directory.
+
+	Add support for the ENVIRON and XDISPLOC options.
+	In order for the server to work, login has to have
+	the "-p" option to preserve environment variables.
+
+	Add the SOFT_TAB and LIT_ECHO modes in the LINEMODE support.
+
+	Add the "-l user" option to command line and open command
+	(This is passed through the ENVIRON option).
+
+	Add the "-e" command line option, for setting the escape
+	character.
+
+	Add the "-D", diagnostic, option to the server.  This allows
+	the server to print out debug information, which is very
+	useful when trying to debug a telnet that doesn't have any
+	debugging ability.
+
+	Turn off the literal next character when not in LINEMODE.
+
+	Don't recognize ^Y locally, just pass it through.
+
+	Make minor modifications for Sun4.0 and Sun4.1
+
+	Add support for both FORW1 and FORW2 characters.  The
+	telnet escpape character is set to whichever of the
+	two is not being used.  If both are in use, the escape
+	character is not set, so when in linemode the user will
+	have to follow the escape character with a <CR> or <EOF)
+	to get it passed through.
+
+	Commands can now be put in single and double quotes, and
+	a backslash is now an escape character.  This is needed
+	for allowing arbitrary strings to be assigned to environment
+	variables.
+
+	Switch telnetd to use macros like telnet for keeping
+	track of the state of all the options.
+
+	Fix telnetd's processing of options so that we always do
+	the right processing of the LINEMODE option, regardless
+	of who initiates the request to turn it on.  Also, make
+	sure that if the other side went "WILL ECHO" in response
+	to our "DO ECHO", that we send a "DONT ECHO" to get the
+	option turned back off!
+
+	Fix the TERMIOS setting of the terminal speed to handle both
+	BSD's seperate fields, and the SYSV method of CBAUD bits.
+
+	Change how we deal with the other side refusing to enable
+	an option.  The sequence used to be: send DO option; receive
+	WONT option; send DONT option.  Now, the sequence is: send
+	DO option; receive WONT option.  Both should be valid
+	according to the spec, but there has been at least one
+	client implementation of telnet identified that can get
+	really confused by this.  (The exact sequence, from a trace
+	on the server side, is (numbers are number of responses that
+	we expect to get after that line...):
+
+		send WILL ECHO	1 (initial request)
+		send WONT ECHO	2 (server is changing state)
+		recv DO ECHO	1 (first reply, ok.  expect DONT ECHO next)
+		send WILL ECHO	2 (server changes state again)
+		recv DONT ECHO	1 (second reply, ok.  expect DO ECHO next)
+		recv DONT ECHO	0 (third reply, wrong answer. got DONT!!!)
+	***	send WONT ECHO	  (send WONT to acknowledge the DONT)
+		send WILL ECHO	1 (ask again to enable option)
+		recv DO ECHO	0
+
+		recv DONT ECHO	0
+		send WONT ECHO	1
+		recv DONT ECHO	0
+		recv DO ECHO	1
+		send WILL ECHO	0
+		(and the last 5 lines loop forever)
+
+	The line with the "***" is last of the WILL/DONT/WONT sequence.
+	The change to the server to not generate that makes this same
+	example become:
+
+		send will ECHO	1
+		send wont ECHO	2
+		recv do ECHO	1
+		send will ECHO	2
+		recv dont ECHO	1
+		recv dont ECHO	0
+		recv do ECHO	1
+		send will ECHO	0
+
+	There is other option negotiation going on, and not sending
+	the third part changes some of the timings, but this specific
+	example no longer gets stuck in a loop.  The "telnet.state"
+	file has been modified to reflect this change to the algorithm.
+
+	A bunch of miscellaneous bug fixes and changes to make
+	lint happier.
+
+	This version of telnet also has some KERBEROS stuff in
+	it. This has not been tested, it uses an un-authorized
+	telnet option number, and uses an out-of-date version
+	of the (still being defined) AUTHENTICATION option.
+	There is no support for this code, do not enable it.
+
+
+March 1, 1990:
+CHANGES/BUGFIXES SINCE LAST RELEASE:
+	Some support for IP TOS has been added.  Requires that the
+	kernel support the IP_TOS socket option (currently this
+	is only in UNICOS 6.0).
+
+	Both telnet and telnetd now use the cc_t typedef.  typedefs are
+	included for systems that don't have it (in termios.h).
+
+	SLC_SUSP was not supported properly before.  It is now.
+
+	IAC EOF was not translated  properly in telnetd for SYSV_TERMIO
+	when not in linemode.  It now saves a copy of the VEOF character,
+	so that when ICANON is turned off and we can't trust it anymore
+	(because it is now the VMIN character) we use the saved value.
+
+	There were two missing "break" commands in the linemode
+	processing code in telnetd.
+
+	Telnetd wasn't setting the kernel window size information
+	properly.  It was using the rows for both rows and columns...
+
+Questions/comments go to
+		David Borman
+		Cray Research, Inc.
+		655F Lone Oak Drive
+		Eagan, MN 55123
+		dab@cray.com.
+
+README:	You are reading it.
+
+Config.generic:
+	This file contains all the OS specific definitions.  It
+	has pre-definitions for many common system types, and is
+	in standard makefile fromat.  See the comments at the top
+	of the file for more information.
+
+Config.local:
+	This is not part of the distribution, but if this file exists,
+	it is used instead of "Config.generic".  This allows site
+	specific configuration without having to modify the distributed
+	"Config.generic" file.
+
+kern.diff:
+	This file contains the diffs for the changes needed for the
+	kernel to support LINEMODE is the server.  These changes are
+	for a 4.3BSD system.  You may need to make some changes for
+	your particular system.
+
+	There is a new bit in the terminal state word, TS_EXTPROC.
+	When this bit is set, several aspects of the terminal driver
+	are disabled.  Input line editing, character echo, and
+	mapping of signals are all disabled.  This allows the telnetd
+	to turn of these functions when in linemode, but still keep
+	track of what state the user wants the terminal to be in.
+
+	New ioctl()s:
+
+		TIOCEXT		Turn on/off the TS_EXTPROC bit
+		TIOCGSTATE	Get t_state of tty to look at TS_EXTPROC bit
+		TIOCSIG		Generate a signal to processes in the
+				current process group of the pty.
+
+	There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
+	When packet mode is turned on in the pty, and the TS_EXTPROC
+	bit is set, then whenever the state of the pty is changed, the
+	next read on the master side of the pty will have the TIOCPKT_IOCTL
+	bit set, and the data will contain the following:
+		struct xx {
+			struct sgttyb a;
+			struct tchars b;
+			struct ltchars c;
+			int t_state;
+			int t_flags;
+		}
+	This allows the process on the server side of the pty to know
+	when the state of the terminal has changed, and what the new
+	state is.
+
+	However, if you define USE_TERMIO or SYSV_TERMIO, the code will
+	expect that the structure returned in the TIOCPKT_IOCTL is
+	the termio/termios structure.
+
+stty.diff:
+	This file contains the changes needed for the stty(1) program
+	to report on the current status of the TS_EXTPROC bit.  It also
+	allows the user to turn on/off the TS_EXTPROC bit.  This is useful
+	because it allows the user to say "stty -extproc", and the
+	LINEMODE option will be automatically disabled, and saying "stty
+	extproc" will re-enable the LINEMODE option.
+
+telnet.state:
+	Both the client and server have code in them to deal
+	with option negotiation loops.  The algorithm that is
+	used is described in this file.
+
+telnet:
+	This directory contains the client code.  No kernel changes are
+	needed to use this code.
+
+telnetd:
+	This directory contains the server code.  If LINEMODE or KLUDGELINEMODE
+	are defined, then the kernel modifications listed above are needed.
+
+libtelnet:
+	This directory contains code that is common to both the client
+	and the server.
+
+arpa:
+	This directory has a new <arpa/telnet.h>
+
+libtelnet/Makefile.4.4:
+telnet/Makefile.4.4:
+telnetd/Makefile.4.4:
+	These are the makefiles that can be used on a 4.3Reno
+	system when this software is installed in /usr/src/lib/libtelnet,
+	/usr/src/libexec/telnetd, and /usr/src/usr.bin/telnet.
+
+
+The following TELNET options are supported:
+	
+	LINEMODE:
+		The LINEMODE option is supported as per RFC1116.  The
+		FORWARDMASK option is not currently supported.
+
+	BINARY: The client has the ability to turn on/off the BINARY
+		option in each direction.  Turning on BINARY from
+		server to client causes the LITOUT bit to get set in
+		the terminal driver on both ends,  turning on BINARY
+		from the client to the server causes the PASS8 bit
+		to get set in the terminal driver on both ends.
+
+	TERMINAL-TYPE:
+		This is supported as per RFC1091.  On the server side,
+		when a terminal type is received, termcap/terminfo
+		is consulted to determine if it is a known terminal
+		type.  It keeps requesting terminal types until it
+		gets one that it recongnizes, or hits the end of the
+		list.  The server side looks up the entry in the
+		termcap/terminfo data base, and generates a list of
+		names which it then passes one at a time to each
+		request for a terminal type, duplicating the last
+		entry in the list before cycling back to the beginning.
+
+	NAWS:	The Negotiate about Window Size, as per RFC 1073.
+
+	TERMINAL-SPEED:
+		Implemented as per RFC 1079
+
+	TOGGLE-FLOW-CONTROL:
+		Implemented as per RFC 1080
+
+	TIMING-MARK:
+		As per RFC 860
+
+	SGA:	As per RFC 858
+
+	ECHO:	As per RFC 857
+
+	LOGOUT: As per RFC 727
+
+	STATUS:
+		The server will send its current status upon
+		request.  It does not ask for the clients status.
+		The client will request the servers current status
+		from the "send getstatus" command.
+
+	ENVIRON:
+		This option is currently being defined by the IETF
+		Telnet Working Group, and an RFC has not yet been
+		issued, but should be in the near future...
+
+	X-DISPLAY-LOCATION:
+		This functionality can be done through the ENVIRON
+		option, it is added here for completeness.
+
+	AUTHENTICATION:
+		This option is currently being defined by the IETF
+		Telnet Working Group, and an RFC has not yet been
+		issued.  The basic framework is pretty much decided,
+		but the definitions for the specific authentication
+		schemes is still in a state of flux.
+
+	ENCRYPTION:
+		This option is currently being defined by the IETF
+		Telnet Working Group, and an RFC has not yet been
+		issued.  The draft RFC is still in a state of flux,
+		so this code may change in the future.
diff --git a/mechglue/src/appl/telnet/arpa/.Sanitize b/mechglue/src/appl/telnet/arpa/.Sanitize
new file mode 100644
index 000000000..e5eeb8f68
--- /dev/null
+++ b/mechglue/src/appl/telnet/arpa/.Sanitize
@@ -0,0 +1,32 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+telnet.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/telnet/arpa/telnet.h b/mechglue/src/appl/telnet/arpa/telnet.h
new file mode 100644
index 000000000..f6d0eb566
--- /dev/null
+++ b/mechglue/src/appl/telnet/arpa/telnet.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)telnet.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _TELNET_H_
+#define	_TELNET_H_
+
+/*
+ * Definitions for the TELNET protocol.
+ */
+#define	IAC	255		/* interpret as command: */
+#define	DONT	254		/* you are not to use option */
+#define	DO	253		/* please, you use option */
+#define	WONT	252		/* I won't use option */
+#define	WILL	251		/* I will use option */
+#define	SB	250		/* interpret as subnegotiation */
+#define	GA	249		/* you may reverse the line */
+#define	EL	248		/* erase the current line */
+#define	EC	247		/* erase the current character */
+#define	AYT	246		/* are you there */
+#define	AO	245		/* abort output--but let prog finish */
+#define	IP	244		/* interrupt process--permanently */
+#define	BREAK	243		/* break */
+#define	DM	242		/* data mark--for connect. cleaning */
+#define	NOP	241		/* nop */
+#define	SE	240		/* end sub negotiation */
+#define EOR     239             /* end of record (transparent mode) */
+#define	ABORT	238		/* Abort process */
+#define	SUSP	237		/* Suspend process */
+#define	xEOF	236		/* End of file: EOF is already used... */
+
+#define SYNCH	242		/* for telfunc calls */
+
+#ifdef TELCMDS
+char *telcmds[] = {
+	"EOF", "SUSP", "ABORT", "EOR",
+	"SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC",
+	"EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0,
+};
+#else
+extern char *telcmds[];
+#endif
+
+#define	TELCMD_FIRST	xEOF
+#define	TELCMD_LAST	IAC
+#define	TELCMD_OK(x)	((unsigned int)(x) <= TELCMD_LAST && \
+			 (unsigned int)(x) >= TELCMD_FIRST)
+#define	TELCMD(x)	telcmds[(x)-TELCMD_FIRST]
+
+/* telnet options */
+#define TELOPT_BINARY	0	/* 8-bit data path */
+#define TELOPT_ECHO	1	/* echo */
+#define	TELOPT_RCP	2	/* prepare to reconnect */
+#define	TELOPT_SGA	3	/* suppress go ahead */
+#define	TELOPT_NAMS	4	/* approximate message size */
+#define	TELOPT_STATUS	5	/* give status */
+#define	TELOPT_TM	6	/* timing mark */
+#define	TELOPT_RCTE	7	/* remote controlled transmission and echo */
+#define TELOPT_NAOL 	8	/* negotiate about output line width */
+#define TELOPT_NAOP 	9	/* negotiate about output page size */
+#define TELOPT_NAOCRD	10	/* negotiate about CR disposition */
+#define TELOPT_NAOHTS	11	/* negotiate about horizontal tabstops */
+#define TELOPT_NAOHTD	12	/* negotiate about horizontal tab disposition */
+#define TELOPT_NAOFFD	13	/* negotiate about formfeed disposition */
+#define TELOPT_NAOVTS	14	/* negotiate about vertical tab stops */
+#define TELOPT_NAOVTD	15	/* negotiate about vertical tab disposition */
+#define TELOPT_NAOLFD	16	/* negotiate about output LF disposition */
+#define TELOPT_XASCII	17	/* extended ascic character set */
+#define	TELOPT_LOGOUT	18	/* force logout */
+#define	TELOPT_BM	19	/* byte macro */
+#define	TELOPT_DET	20	/* data entry terminal */
+#define	TELOPT_SUPDUP	21	/* supdup protocol */
+#define	TELOPT_SUPDUPOUTPUT 22	/* supdup output */
+#define	TELOPT_SNDLOC	23	/* send location */
+#define	TELOPT_TTYPE	24	/* terminal type */
+#define	TELOPT_EOR	25	/* end or record */
+#define	TELOPT_TUID	26	/* TACACS user identification */
+#define	TELOPT_OUTMRK	27	/* output marking */
+#define	TELOPT_TTYLOC	28	/* terminal location number */
+#define	TELOPT_3270REGIME 29	/* 3270 regime */
+#define	TELOPT_X3PAD	30	/* X.3 PAD */
+#define	TELOPT_NAWS	31	/* window size */
+#define	TELOPT_TSPEED	32	/* terminal speed */
+#define	TELOPT_LFLOW	33	/* remote flow control */
+#define TELOPT_LINEMODE	34	/* Linemode option */
+#define TELOPT_XDISPLOC	35	/* X Display Location */
+#define TELOPT_OLD_ENVIRON 36	/* Old - Environment variables */
+#define	TELOPT_AUTHENTICATION 37/* Authenticate */
+#define	TELOPT_ENCRYPT	38	/* Encryption option */
+#define TELOPT_NEW_ENVIRON 39	/* New - Environment variables */
+#define	TELOPT_EXOPL	255	/* extended-options-list */
+
+
+#define	NTELOPTS	(1+TELOPT_NEW_ENVIRON)
+#ifdef TELOPTS
+char *telopts[NTELOPTS+1] = {
+	"BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME",
+	"STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP",
+	"NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS",
+	"NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
+	"DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT",
+	"SEND LOCATION", "TERMINAL TYPE", "END OF RECORD",
+	"TACACS UID", "OUTPUT MARKING", "TTYLOC",
+	"3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW",
+	"LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION",
+	"ENCRYPT", "NEW-ENVIRON",
+	0,
+};
+#define	TELOPT_FIRST	TELOPT_BINARY
+#define	TELOPT_LAST	TELOPT_NEW_ENVIRON
+#define	TELOPT_OK(x)	((unsigned int)(x) <= TELOPT_LAST)
+#define	TELOPT(x)	telopts[(x)-TELOPT_FIRST]
+#endif
+
+/* sub-option qualifiers */
+#define	TELQUAL_IS	0	/* option is... */
+#define	TELQUAL_SEND	1	/* send option */
+#define	TELQUAL_INFO	2	/* ENVIRON: informational version of IS */
+#define	TELQUAL_REPLY	2	/* AUTHENTICATION: client version of IS */
+#define	TELQUAL_NAME	3	/* AUTHENTICATION: client version of IS */
+
+#define	LFLOW_OFF		0	/* Disable remote flow control */
+#define	LFLOW_ON		1	/* Enable remote flow control */
+#define	LFLOW_RESTART_ANY	2	/* Restart output on any char */
+#define	LFLOW_RESTART_XON	3	/* Restart output only on XON */
+
+/*
+ * LINEMODE suboptions
+ */
+
+#define	LM_MODE		1
+#define	LM_FORWARDMASK	2
+#define	LM_SLC		3
+
+#define	MODE_EDIT	0x01
+#define	MODE_TRAPSIG	0x02
+#define	MODE_ACK	0x04
+#define MODE_SOFT_TAB	0x08
+#define MODE_LIT_ECHO	0x10
+
+#define	MODE_MASK	0x1f
+
+/* Not part of protocol, but needed to simplify things... */
+#define MODE_FLOW		0x0100
+#define MODE_ECHO		0x0200
+#define MODE_INBIN		0x0400
+#define MODE_OUTBIN		0x0800
+#define MODE_FORCE		0x1000
+
+#define	SLC_SYNCH	1
+#define	SLC_BRK		2
+#define	SLC_IP		3
+#define	SLC_AO		4
+#define	SLC_AYT		5
+#define	SLC_EOR		6
+#define	SLC_ABORT	7
+#define	SLC_EOF		8
+#define	SLC_SUSP	9
+#define	SLC_EC		10
+#define	SLC_EL		11
+#define	SLC_EW		12
+#define	SLC_RP		13
+#define	SLC_LNEXT	14
+#define	SLC_XON		15
+#define	SLC_XOFF	16
+#define	SLC_FORW1	17
+#define	SLC_FORW2	18
+
+#define	NSLC		18
+
+/*
+ * For backwards compatability, we define SLC_NAMES to be the
+ * list of names if SLC_NAMES is not defined.
+ */
+#define	SLC_NAMELIST	"0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \
+			"ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \
+			"LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0,
+#ifdef	SLC_NAMES
+char *slc_names[] = {
+	SLC_NAMELIST
+};
+#else
+extern char *slc_names[];
+#define	SLC_NAMES SLC_NAMELIST
+#endif
+
+#define	SLC_NAME_OK(x)	((unsigned int)(x) <= NSLC)
+#define SLC_NAME(x)	slc_names[x]
+
+#define	SLC_NOSUPPORT	0
+#define	SLC_CANTCHANGE	1
+#define	SLC_VARIABLE	2
+#define	SLC_DEFAULT	3
+#define	SLC_LEVELBITS	0x03
+
+#define	SLC_FUNC	0
+#define	SLC_FLAGS	1
+#define	SLC_VALUE	2
+
+#define	SLC_ACK		0x80
+#define	SLC_FLUSHIN	0x40
+#define	SLC_FLUSHOUT	0x20
+
+#define	OLD_ENV_VAR	1
+#define	OLD_ENV_VALUE	0
+#define	NEW_ENV_VAR	0
+#define	NEW_ENV_VALUE	1
+#define	ENV_ESC		2
+#define ENV_USERVAR	3
+
+/*
+ * AUTHENTICATION suboptions
+ */
+
+/*
+ * Who is authenticating who ...
+ */
+#define	AUTH_WHO_CLIENT		0	/* Client authenticating server */
+#define	AUTH_WHO_SERVER		1	/* Server authenticating client */
+#define	AUTH_WHO_MASK		1
+
+/*
+ * amount of authentication done
+ */
+#define	AUTH_HOW_ONE_WAY	0
+#define	AUTH_HOW_MUTUAL		2
+#define	AUTH_HOW_MASK		2
+
+/*
+ * should we be encrypting? (not yet formally standardized)
+ */
+#define AUTH_ENCRYPT_OFF	0
+#define AUTH_ENCRYPT_ON		4
+#define AUTH_ENCRYPT_MASK	4
+
+#define	AUTHTYPE_NULL		0
+#define	AUTHTYPE_KERBEROS_V4	1
+#define	AUTHTYPE_KERBEROS_V5	2
+#define	AUTHTYPE_SPX		3
+#define	AUTHTYPE_MINK		4
+#define	AUTHTYPE_CNT		5
+
+#define	AUTHTYPE_TEST		99
+
+#ifdef	AUTH_NAMES
+char *authtype_names[] = {
+	"NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0,
+};
+#else
+extern char *authtype_names[];
+#endif
+
+#define	AUTHTYPE_NAME_OK(x)	((unsigned int)(x) < AUTHTYPE_CNT)
+#define	AUTHTYPE_NAME(x)	authtype_names[x]
+
+/*
+ * ENCRYPTion suboptions
+ */
+#define	ENCRYPT_IS		0	/* I pick encryption type ... */
+#define	ENCRYPT_SUPPORT		1	/* I support encryption types ... */
+#define	ENCRYPT_REPLY		2	/* Initial setup response */
+#define	ENCRYPT_START		3	/* Am starting to send encrypted */
+#define	ENCRYPT_END		4	/* Am ending encrypted */
+#define	ENCRYPT_REQSTART	5	/* Request you start encrypting */
+#define	ENCRYPT_REQEND		6	/* Request you send encrypting */
+#define	ENCRYPT_ENC_KEYID	7
+#define	ENCRYPT_DEC_KEYID	8
+#define	ENCRYPT_CNT		9
+
+#define	ENCTYPE_ANY		0
+#define	ENCTYPE_DES_CFB64	1
+#define	ENCTYPE_DES_OFB64	2
+#define	ENCTYPE_CNT		3
+
+#ifdef	ENCRYPT_NAMES
+char *encrypt_names[] = {
+	"IS", "SUPPORT", "REPLY", "START", "END",
+	"REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID",
+	0,
+};
+char *enctype_names[] = {
+	"ANY", "DES_CFB64",  "DES_OFB64",  0,
+};
+#else
+extern char *encrypt_names[];
+extern char *enctype_names[];
+#endif
+
+
+#define	ENCRYPT_NAME_OK(x)	((unsigned int)(x) < ENCRYPT_CNT)
+#define	ENCRYPT_NAME(x)		encrypt_names[x]
+
+#define	ENCTYPE_NAME_OK(x)	((unsigned int)(x) < ENCTYPE_CNT)
+#define	ENCTYPE_NAME(x)		enctype_names[x]
+
+#endif /* !_TELNET_H_ */
diff --git a/mechglue/src/appl/telnet/configure.in b/mechglue/src/appl/telnet/configure.in
new file mode 100644
index 000000000..da8b31623
--- /dev/null
+++ b/mechglue/src/appl/telnet/configure.in
@@ -0,0 +1,175 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+dnl AC_CONFIG_SUBDIRS(libtelnet telnet telnetd)
+dnl
+dnl from old libtelnet/configure.in, plus additional header & func checks
+dnl
+AC_REPLACE_FUNCS([strcasecmp strdup setsid strerror strftime getopt herror parsetos])
+AC_CHECK_FUNCS(setenv unsetenv getenv gettosbyname cgetent gettosbyname vsnprintf)
+AC_CHECK_HEADERS(stdlib.h string.h unistd.h arpa/nameser.h sys/select.h arpa/inet.h sys/filio.h curses.h utmp.h sys/time.h sys/tty.h sac.h sys/ptyvar.h sys/stream.h sys/utsname.h memory.h)
+if test $ac_cv_func_setenv = no || test $ac_cv_func_unsetenv = no \
+  || test $ac_cv_func_getenv = no; then
+  SETENVSRC=setenv.c
+  SETENVOBJ=setenv.o
+  AC_SUBST([SETENVSRC])
+  AC_SUBST([SETENVOBJ])
+  AC_DEFINE([NEED_SETENV])
+fi
+dnl
+KRB5_NEED_PROTO([#include <stdlib.h>],setenv)
+AC_C_CONST
+if test "$KRB4_LIB" = ''; then
+	AC_MSG_RESULT(No Kerberos 4 authentication)
+else
+	AC_MSG_RESULT(Kerberos 4 authentication enabled)
+	AC_DEFINE(KRB4)
+fi
+KRB5_BUILD_LIBRARY_STATIC
+KRB5_BUILD_LIBOBJS
+dnl
+old_LIBS="$LIBS"
+dnl
+dnl from old telnet/configure.in
+dnl
+AC_PROG_INSTALL
+AC_FUNC_VFORK
+AC_HEADER_STDARG
+case $krb5_cv_host in
+*-*-solaris*)
+	if test "$krb5_cv_prog_gcc" = yes; then
+		# Solaris 8 at least has curses.h that is noisy under gcc
+		ac_cv_header_curses_h=yes
+	fi
+	;;
+esac
+dnl
+dnl On some systems, term.h requires curses.h inclusion
+AC_CHECK_HEADERS(term.h,,,dnl
+[#ifdef HAVE_CURSES_H
+#include <curses.h>
+#endif
+])
+dnl
+AC_CHECK_LIB(termcap,main,AC_DEFINE(TERMCAP)
+LIBS="$LIBS -ltermcap")
+AC_CHECK_LIB(curses,setupterm,LIBS="$LIBS -lcurses",
+  AC_CHECK_LIB(ncurses,setupterm,LIBS="$LIBS -lncurses")
+)
+KRB5_AC_INET6
+AC_CHECK_FUNCS(setupterm)
+AC_CHECK_HEADER(termios.h,AC_DEFINE(USE_TERMIO) ac_termio=1)
+if test -z "$ac_termio"; then
+AC_CHECK_HEADER(termio.h,AC_DEFINE(SYSV_TERMIO),ac_sysv_termio=1)
+if test -z "$ac_sysv_termio"; then
+  AC_MSG_CHECKING([for cc_t in termio.h])
+  AC_CACHE_VAL(krb_cv_type_cc_t,
+  [AC_TRY_LINK([cc_t],[#include <termio.h>],
+  [cc_t foo;],krb_cv_type_cc_t=yes,krb_cv_type_cc_t=no)])
+  AC_MSG_RESULT($krb_cv_type_cc_t)
+  if test $krb_cv_type_cc_t = no; then
+    AC_DEFINE(NO_CC_T)
+  fi
+fi
+fi
+KRB5_NEED_PROTO([#include <unistd.h>
+#include <stdlib.h>],parsetos,1)
+dnl
+KRB5_NEED_PROTO([#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>],herror,1)
+dnl
+CHECK_SIGNALS
+if test "$KRB4_LIB" = ''; then
+	AC_MSG_RESULT(No Kerberos 4 authentication)
+else
+	AC_MSG_RESULT(Kerberos 4 authentication enabled)
+	AC_DEFINE(KRB4)
+fi
+dnl
+KRB5_BUILD_PROGRAM
+dnl
+TELNET_LIBS="$LIBS"
+AC_SUBST(TELNET_LIBS)
+LIBS="$old_LIBS"
+dnl
+dnl from old telnetd/configure.in
+dnl
+dnl AC_PROG_INSTALL
+AC_CHECK_LIB(termcap,main,AC_DEFINE(TERMCAP)
+LIBS="$LIBS -ltermcap",
+  AC_CHECK_LIB(curses,setupterm,LIBS="$LIBS -lcurses",
+  AC_CHECK_LIB(ncurses,setupterm,LIBS="$LIBS -lncurses")
+))
+dnl ... whole termios.h/termio.h/NO_CC_T thing again ...
+AC_HEADER_TIME
+dnl KRB5_AC_INET6
+dnl
+dnl Test if speed_t needs to be defined
+AC_CACHE_CHECK([if speed_t is defined], krb5_cv_type_speed_t,
+[AC_TRY_COMPILE(dnl
+[#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#ifndef	USE_TERMIO
+#include <sgtty.h>
+#else
+# ifdef	SYSV_TERMIO
+# include <termio.h>
+# else
+# include <termios.h>
+# endif
+#endif
+],[speed_t termspeed],krb5_cv_type_speed_t=yes, krb5_cv_type_speed_t=no)])
+if test $krb5_cv_type_speed_t = no; then
+   AC_DEFINE(speed_t, int)
+fi;
+dnl
+dnl
+dnl Make our operating system-specific security checks and definitions for
+dnl login.
+dnl
+case $krb5_cv_host in
+*-*-hpux*)
+     broken_streams=yes
+     ;;
+*-*-linux*)
+     # Someday Linux may have a Streams user-level interface, so checking
+     # for sys/stream.h may not always work.  But I'm reasonably
+     # sure Linux will never require pushing magic streams modules onto 
+     # pty's! :-)   --- TYT
+     broken_streams=yes
+     ;;
+*-*-irix*)
+     # Irix doesn't have a working granpt, and more over
+     # you can't push anything onto a pty, so telnetd really
+     # Really wants to treat it as if it doesn't have streams
+     broken_streams=yes
+     ;;
+esac
+if test -z "$broken_streams" -a "$ac_cv_header_sys_stream_h" = yes; then
+    AC_CHECK_FUNC(grantpt,AC_DEFINE(STREAMSPTY))
+fi
+AC_MSG_CHECKING([if setpgrp takes two arguments])
+dnl
+AC_CACHE_VAL(krb5_cv_sys_setpgrp_two,
+[AC_TRY_LINK( 
+[#include <unistd.h>],[setpgrp(0,0)],
+krb5_cv_sys_setpgrp_two=yes,krb5_cv_sys_setpgrp_two=no)])
+AC_MSG_RESULT($krb5_cv_sys_setpgrp_two)
+if test $krb5_cv_sys_setpgrp_two = yes; then
+  AC_DEFINE(SETPGRP_TWOARG)
+fi
+dnl
+KRB5_NEED_PROTO([#include <stdlib.h>],unsetenv,1)
+dnl KRB5_NEED_PROTO([#include <stdlib.h>],setenv,1)
+dnl KRB5_BUILD_PROGRAM
+dnl
+TELNETD_LIBS="$LIBS"
+AC_SUBST(TELNETD_LIBS)
+LIBS="$old_LIBS"
+dnl
+KRB5_AC_LIBUTIL
+V5_AC_OUTPUT_MAKEFILE(. libtelnet telnet telnetd)
diff --git a/mechglue/src/appl/telnet/kern.diff b/mechglue/src/appl/telnet/kern.diff
new file mode 100644
index 000000000..3c1153bab
--- /dev/null
+++ b/mechglue/src/appl/telnet/kern.diff
@@ -0,0 +1,308 @@
+*** h/ioctl.h.old	Tue May 23 14:50:42 1989
+--- h/ioctl.h	Tue Aug 29 18:24:49 1989
+***************
+*** 214,219 ****
+--- 214,220 ----
+  #define		TIOCPKT_START		0x08	/* start output */
+  #define		TIOCPKT_NOSTOP		0x10	/* no more ^S, ^Q */
+  #define		TIOCPKT_DOSTOP		0x20	/* now do ^S ^Q */
++ #define		TIOCPKT_IOCTL		0x40	/* state change of pty driver */
+  #define	TIOCSTOP	_IO('t', 111)		/* stop output, like ^S */
+  #define	TIOCSTART	_IO('t', 110)		/* start output, like ^Q */
+  #define	TIOCMSET	_IOW('t', 109, int)	/* set all modem bits */
+***************
+*** 226,231 ****
+--- 227,235 ----
+  #define	TIOCUCNTL	_IOW('t', 102, int)	/* pty: set/clr usr cntl mode */
+  #define		UIOCCMD(n)	_IO('u', n)		/* usr cntl op "n" */
+  #define	TIOCCONS	_IO('t', 98)		/* become virtual console */
++ #define	TIOCEXT		_IOW('t', 97, int)	/* pty: external processing */
++ #define	TIOCGSTATE	_IOR('t', 96, int)	/* pty: get internal state */
++ #define	TIOCSIG		_IO('t', 95)		/* pty: generate signal */
+  
+  #define	OTTYDISC	0		/* old, v7 std tty driver */
+  #define	NETLDISC	1		/* line discip for berk net */
+*** h/tty.h.old	Tue May 23 14:51:01 1989
+--- h/tty.h	Wed Aug 23 11:30:40 1989
+***************
+*** 70,75 ****
+--- 70,76 ----
+  	struct	ttychars t_chars;	/* tty */
+  	struct	winsize t_winsize;	/* window size */
+  /* be careful of tchars & co. */
++ #ifndef	NO_T_CHARS_DEFINES
+  #define	t_erase		t_chars.tc_erase
+  #define	t_kill		t_chars.tc_kill
+  #define	t_intrc		t_chars.tc_intrc
+***************
+*** 84,89 ****
+--- 85,91 ----
+  #define	t_flushc	t_chars.tc_flushc
+  #define	t_werasc	t_chars.tc_werasc
+  #define	t_lnextc	t_chars.tc_lnextc
++ #endif
+  };
+  
+  #define	TTIPRI	28
+***************
+*** 124,129 ****
+--- 126,132 ----
+  #define	TS_LNCH		0x080000	/* next character is literal */
+  #define	TS_TYPEN	0x100000	/* retyping suspended input (PENDIN) */
+  #define	TS_CNTTB	0x200000	/* counting tab width; leave FLUSHO alone */
++ #define	TS_EXTPROC	0x400000	/* external processing of data */
+  
+  #define	TS_LOCAL	(TS_BKSL|TS_QUOT|TS_ERASE|TS_LNCH|TS_TYPEN|TS_CNTTB)
+  
+*** sys/tty.c.old	Tue May 23 14:52:28 1989
+--- sys/tty.c	Thu Aug 24 09:31:49 1989
+***************
+*** 275,280 ****
+--- 275,285 ----
+  	 */
+  	switch (com) {
+  
++ 	/* get internal state - needed for TS_EXTPROC bit */
++ 	case TIOCGSTATE:
++ 		*(int *)data = tp->t_state;
++ 		break;
++ 
+  	/* get discipline number */
+  	case TIOCGETD:
+  		*(int *)data = tp->t_line;
+***************
+*** 752,757 ****
+--- 757,763 ----
+  	 */
+  	if ((tp->t_state&TS_TYPEN) == 0 && (t_flags&PASS8) == 0)
+  		c &= 0177;
++     if ((tp->t_state&TS_EXTPROC) == 0) {
+  	/*
+  	 * Check for literal nexting very first
+  	 */
+***************
+*** 834,839 ****
+--- 840,846 ----
+  		else if (c == '\\')
+  			tp->t_state |= TS_BKSL;
+  	}
++     }
+  
+  	/*
+  	 * Cbreak mode, don't process line editing
+***************
+*** 851,856 ****
+--- 858,864 ----
+  		goto endcase;
+  	}
+  
++     if ((tp->t_state&TS_EXTPROC) == 0) {
+  	/*
+  	 * From here on down cooked mode character
+  	 * processing takes place.
+***************
+*** 911,916 ****
+--- 919,925 ----
+  			goto endcase;
+  		}
+  	}
++     }
+  
+  	/*
+  	 * Check for input buffer overflow
+***************
+*** 933,938 ****
+--- 942,948 ----
+  		} else if (tp->t_rocount++ == 0)
+  			tp->t_rocol = tp->t_col;
+  		tp->t_state &= ~TS_QUOT;
++ 	    if ((tp->t_state&TS_EXTPROC) == 0) {
+  		if (c == '\\')
+  			tp->t_state |= TS_QUOT;
+  		if (tp->t_state&TS_ERASE) {
+***************
+*** 948,953 ****
+--- 958,964 ----
+  				i--;
+  			}
+  		}
++ 	    }
+  	}
+  endcase:
+  	/*
+***************
+*** 998,1005 ****
+  		return (-1);
+  	/*
+  	 * Turn tabs to spaces as required
+  	 */
+! 	if (c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
+  		register int s;
+  
+  		c = 8 - (tp->t_col&7);
+--- 1009,1022 ----
+  		return (-1);
+  	/*
+  	 * Turn tabs to spaces as required
++ 	 *
++ 	 * Special case if we have external processing, we don't
++ 	 * do the tab expansion because we'll probably get it
++ 	 * wrong.  If tab expansion needs to be done, let it
++ 	 * happen externally.
+  	 */
+! 	if ((tp->t_state&TS_EXTPROC) == 0 &&
+! 	    c == '\t' && (tp->t_flags&TBDELAY) == XTABS) {
+  		register int s;
+  
+  		c = 8 - (tp->t_col&7);
+***************
+*** 1497,1503 ****
+  	int s;
+  	char *nextc();
+  
+! 	if ((tp->t_flags&ECHO) == 0)
+  		return;
+  	tp->t_flags &= ~FLUSHO;
+  	c &= 0377;
+--- 1514,1520 ----
+  	int s;
+  	char *nextc();
+  
+! 	if ((tp->t_flags&ECHO) == 0 || (tp->t_state&TS_EXTPROC))
+  		return;
+  	tp->t_flags &= ~FLUSHO;
+  	c &= 0377;
+***************
+*** 1618,1624 ****
+  
+  	if ((tp->t_state&TS_CNTTB) == 0)
+  		tp->t_flags &= ~FLUSHO;
+! 	if ((tp->t_flags&ECHO) == 0)
+  		return;
+  	c &= 0377;
+  	if (tp->t_flags&RAW) {
+--- 1635,1641 ----
+  
+  	if ((tp->t_state&TS_CNTTB) == 0)
+  		tp->t_flags &= ~FLUSHO;
+! 	if ((tp->t_flags&ECHO) == 0 || (tp->t_state&TS_EXTPROC))
+  		return;
+  	c &= 0377;
+  	if (tp->t_flags&RAW) {
+*** sys/tty_pty.c.old	Tue May 23 14:52:43 1989
+--- sys/tty_pty.c	Tue Aug 29 18:48:36 1989
+***************
+*** 208,213 ****
+--- 208,214 ----
+  		return (EIO);
+  	tp->t_oproc = ptsstart;
+  	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
++ 	tp->t_state &= ~TS_EXTPROC;
+  	pti = &pt_ioctl[minor(dev)];
+  	pti->pt_flags = 0;
+  	pti->pt_send = 0;
+***************
+*** 247,252 ****
+--- 248,275 ----
+  				error = ureadc((int)pti->pt_send, uio);
+  				if (error)
+  					return (error);
++ 				if (pti->pt_send & TIOCPKT_IOCTL) {
++ 					struct xx {
++ 						struct sgttyb a;
++ 						struct tchars b;
++ 						struct ltchars c;
++ 						int d;
++ 						int e;
++ 					} cb;
++ 					cb.a.sg_ispeed = tp->t_ispeed;
++ 					cb.a.sg_ospeed = tp->t_ospeed;
++ 					cb.a.sg_erase = tp->t_erase;
++ 					cb.a.sg_kill = tp->t_kill;
++ 					cb.a.sg_flags = tp->t_flags;
++ 					bcopy((caddr_t)&tp->t_intrc,
++ 					      (caddr_t)&cb.b, sizeof(cb.b));
++ 					bcopy((caddr_t)&tp->t_suspc,
++ 					      (caddr_t)&cb.c, sizeof(cb.c));
++ 					cb.d = tp->t_state;
++ 					cb.e = ((unsigned)tp->t_flags)>>16;
++ 					cc = MIN(uio->uio_resid, sizeof(cb));
++ 					uiomove(&cb, cc, UIO_READ, uio);
++ 				}
+  				pti->pt_send = 0;
+  				return (0);
+  			}
+***************
+*** 483,488 ****
+--- 506,533 ----
+  	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
+  	 * ttywflush(tp) will hang if there are characters in the outq.
+  	 */
++ 	if (cmd == TIOCEXT) {
++ 		/*
++ 		 * When the TS_EXTPROC bit is being toggled, we need
++ 		 * to send an TIOCPKT_IOCTL if the packet driver
++ 		 * is turned on.
++ 		 */
++ 		if (*(int *)data) {
++ 			if (pti->pt_flags & PF_PKT) {
++ 				pti->pt_send |= TIOCPKT_IOCTL;
++ 				ptcwakeup(tp);
++ 			}
++ 			tp->t_state |= TS_EXTPROC;
++ 		} else {
++ 			if ((tp->t_state & TS_EXTPROC) &&
++ 			    (pti->pt_flags & PF_PKT)) {
++ 				pti->pt_send |= TIOCPKT_IOCTL;
++ 				ptcwakeup(tp);
++ 			}
++ 			tp->t_state &= ~TS_EXTPROC;
++ 		}
++ 		return (0);
++ 	} else
+  	if (cdevsw[major(dev)].d_open == ptcopen)
+  		switch (cmd) {
+  
+***************
+*** 525,530 ****
+--- 570,583 ----
+  			while (getc(&tp->t_outq) >= 0)
+  				;
+  			break;
++ 
++ 		case TIOCSIG:
++ 			if (*(unsigned int *)data >= NSIG)
++ 				return(EINVAL);
++ 			if ((tp->t_flags&NOFLSH) == 0)
++ 				ttyflush(tp, FREAD|FWRITE);
++ 			gsignal(tp->t_pgrp, *(unsigned int *)data);
++ 			return(0);
+  		}
+  	error = ttioctl(tp, cmd, data, flag);
+  	/*
+***************
+*** 549,554 ****
+--- 602,624 ----
+  			return (0);
+  		}
+  		error = ENOTTY;
++ 	}
++ 	/*
++ 	 * If external processing and packet mode send ioctl packet.
++ 	 */
++ 	if ((tp->t_state & TS_EXTPROC) && (pti->pt_flags & PF_PKT)) {
++ 		switch(cmd) {
++ 		case TIOCSETP:
++ 		case TIOCSETN:
++ 		case TIOCSETC:
++ 		case TIOCSLTC:
++ 		case TIOCLBIS:
++ 		case TIOCLBIC:
++ 		case TIOCLSET:
++ 			pti->pt_send |= TIOCPKT_IOCTL;
++ 		default:
++ 			break;
++ 		}
+  	}
+  	stop = (tp->t_flags & RAW) == 0 &&
+  	    tp->t_stopc == CTRL('s') && tp->t_startc == CTRL('q');
diff --git a/mechglue/src/appl/telnet/libtelnet/.Sanitize b/mechglue/src/appl/telnet/libtelnet/.Sanitize
new file mode 100644
index 000000000..a5a5333d8
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/.Sanitize
@@ -0,0 +1,70 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.4.4
+Makefile.generic
+Makefile.in
+Makefile.orig
+auth-proto.h
+auth.c
+auth.h
+configure
+configure.in
+enc-proto.h
+enc_des.c
+encrypt.c
+encrypt.h
+forward.c
+genget.c
+getent.c
+getopt.c
+gettytab.c
+gettytab.h
+herror.c
+kerberos.c
+kerberos5.c
+key-proto.h
+mem.c
+misc-proto.h
+misc.c
+misc.h
+parsetos.c
+setenv.c
+setsid.c
+spx.c
+strcasecmp.c
+strchr.c
+strdup.c
+strerror.c
+strftime.c
+strrchr.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/telnet/libtelnet/ChangeLog b/mechglue/src/appl/telnet/libtelnet/ChangeLog
new file mode 100644
index 000000000..a02cd8d31
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/ChangeLog
@@ -0,0 +1,756 @@
+2004-12-20  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos.c (kerberos4_status): Null-terminate the correct
+	string.  Reported by Marcin Garski.
+
+2004-11-15  Tom Yu  <tlyu@mit.edu>
+
+	* auth-proto.h, auth.c: Merge Athena changes for requiring
+	encrypted connections.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Deleted; configure this dir from parent now.
+	* Makefile.in (thisconfigdir, mydir): Updated.
+
+2003-05-09  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos5.c (kerberos5_send): Rename getlocalsubkey ->
+	getsendsubkey.
+	(kerberos5_is): Rename getremotesubkey -> getrecvsubkey.
+
+2003-04-10  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Use library build framework.
+
+	* configure.in: Add support for library build framework.  Remove
+	old explicit checks for ranlib, etc.
+
+2003-04-09  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos.c (kerberos4_status): Always copy in username if
+	present.  Patch from Nathan Neulinger to make "-a user" work.
+
+	* kerberos5.c (kerberos5_status): Always copy in username if
+	present.  Patch from Nathan Neulinger to make "-a user" work.
+
+2003-04-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kerberos5.c (kerberos5_is): Check principal name length before
+	examining components.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.orig: Deleted.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos.c (kerberos4_send, kerberos4_is): Use
+	krb_get_err_text() instead of krb_err_txt array.
+
+	* strcasecmp.c: Include sys/types.h rather than sys/cdefs.h.
+
+2002-11-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* enc-proto.h, enc_des.c, encrypt.c: Unsigned/signed cleanups.
+
+	* forward.c: Include unistd.h if present on machine.
+
+	* misc-proto.h misc.c (auth_encrypt_user): Declare argument as
+	const.
+
+	* auth.c: Cast argument auth_encrypt_user. auth_gen_printsub() and
+	auth_printsub() take unsigned int as buffer length.
+
+	* auth.h, auth-proto.h, kerberos.c, kerberos5.c, spx.c:
+	auth_gen_printsub(), auth_printsub(), kerberos4_printsub(),
+	kerberos5_printsub(), spx_printsub() take unsigned int as length
+	argument.
+
+	* configure.in: Check for unistd.h
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-04-12  Sam Hartman  <hartmans@mit.edu>
+
+	* kerberos5.c forward.c: Build without k5-int.h
+
+2002-03-29  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos.c, kerberos5.c (Data): Reindent to 8 columns. (yes,
+	this is original BSD style)
+
+2002-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* kerberos.c: Include errno.h.
+
+2002-03-26  Sam Hartman  <hartmans@mit.edu>
+
+	* kerberos.c kerberos5.c (Data): Fix indentation; fix termination condition
+
+2002-03-14  Sam Hartman  <hartmans@mit.edu>
+
+	* kerberos5.c kerberos.c  (Data): Don't overflow
+	buffer. [telnet/1073] 
+
+2002-03-13  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Do not explicitly add getent.o and setenv.o to
+	LIBOBJS. Autoconf 2.53 labels this as an error. Move to
+	Makefile.in.
+
+	* Makefile.in (OBJS): Add getent.o and setenv.o explicity. 
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* auth-proto.h, auth.h, enc-proto.h, enc_des.c, encrypt.c,
+	encrypt.h, kerberos.c, key-proto.h, misc-proto.h, misc.h,
+	setenv.c: Make prototypes unconditional.  Don't define P().
+
+2001-07-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* enc_des.c (fb64_start): Remove variable set but never used.
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* kerberos.c (Data): Third argument now const.
+
+	* misc.c (printd): First argument now const.
+
+	* misc-proto.h: Modify printd prototype to take const first
+	argument. 
+
+	* auth.c: Cast argument to memcpy to unsigned. 
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Check for need to provide setenv prototype if
+	setenv is in the C library.
+
+	* forward.c: Provide setenv prototype if needed.
+
+	* auth.c (auth_name): Cast result of sizeof() to int to match
+	printf format specification.
+
+2001-07-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* encrypt.c (encrypt_reply): Cast arguments to printf to match
+	format in debugging statments.
+
+2001-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5forw.h: File with prototype for rd_and_store_for_creds().
+
+	* kerberos5.c: Include krb5forw.h for rd_and_store_for_creds()
+	prototype which is removed from this file.
+
+	* forward.c: Include krb5forw.h for prototype.
+
+	* setenv.c: Include misc-proto.h for setenv/unsetenv prototypes.
+
+	* parsetos.c: Include misc-proto.h for parsetos prototype.
+
+	* misc-proto.h: Add prototype for parsetos(), setenv(), unsetenv()
+	as needed.
+
+	* kerberos5.c: Declare kerberos5_forward() static and flush out
+	prototype.
+
+	* gettytab.h: Flush out prototypes for getent() and getstr().
+
+	* getent.c: Include gettytab.h for prototypes.
+
+	* genget.c: Include misc.h for prototypes.
+
+	* enc_des.c: Add prototype for fb64_printsub.
+
+	* enc-proto.h: Add prototypes for encrypt_debug(),
+	finddecryption(), EncryptAuthEnc(), EncryptAutoDec(),
+	EncryptDebug(), EncryptVerbose().
+
+	* encrypt.c: Declare encrypt_list_types() and encrypt_keyid() static.
+
+2001-06-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* enc_des.c: Change local variable index to idx to not shadown
+	global function.
+
+	* kerberos5.c (kerberos5_is): Change errbuf to kerrbuf to not
+	shadow previous local.
+
+	* kerberos.c (kerberos4_send): Change random_key to rand_key to
+	prevent redefine by des.h. Change auth to kauth to not shadow global.
+	(kerberos4_status): Change name to kname for same reason.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* forward.c: If NEED_SETENV defined, provide prototype for setenv.
+
+	* configure.in: If compiling setenv.c, define NEED_SETENV.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* kerberos5.c: Add prototype for rd_and_store_for_creds().
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* encrypt.c (encrypt_is): Cast arguments to printf to match format. 
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* genget.c (LOWER): Cast argument to isupper()/tolower() to int.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* auth-proto.h: Add prototype for kerberos5_cleanup().
+
+	* enc-proto.h: Add prototypes for encrypt_printsub(),
+	encrypt_request_sart(), encrypt_request_end(),
+	encrypt_enc_keyid()m encrypt_dec_keyid(), encrypt_support(),
+	encrypt_start(), encrypt_end().
+
+2001-06-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* auth-proto.h: Add prototypes for getauthmask(), auth_enable,
+	auth_disable(), auth_onoff(), auth_togdebug(), auth_status(),
+	auth_name(), auth_sendname(), auth_debug(), and auth_printsub().
+
+	* auth.c: Include unistd.h and cleanup some assignments in
+	conditionals.
+
+	* auth.h: Explicitly declare auth_debug mode as an int.
+
+	* enc-proto.h: Add prototypes for EncryptDisable(), EncryptType(),
+	EncryptStart(), EncryptStartInput(), EncryptStartOutput(),
+	EncryptStop(), EncryptStopInput(), EncryptStopOutput(),
+	EncryptStatus(), encrypt_gen_printsub(), printsub().
+
+	* enc_des.c: Declare encrypt_debug_mode as int. Cleanup unused
+	variables and assignments in conditionals. 
+
+	* encrypt.c: Include stdio.h for sprintf prototype. Cleanup
+	assignments in conditionals.
+
+	* getent.c: Conditionalize definition of some variables.
+
+	* kerberos5.c: Explicitly declare auth_debug_mode an int.
+
+	* misc-proto.h: Add prototype for auth_encrypt_user().
+
+	* misc.c: Include auth.h and encrypt.h for prototypes.
+
+	* misc.h: Add prototypes for isprfix(), genget(), Ambiguous().
+
+	* parsetos.c: Include stdlib.h for strtol() prototype.
+
+	* forward.c, kerberos.c, setenv.c: Assignment in conditional cleanup.
+
+2001-04-03  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Check for setenv, unsetenv, and getenv.  Compile
+	setenv.c if at least of these is undefined. [pullup from
+	krb5-1-2-2-branch]
+
+	* setenv.c: Add conditionals for compilation of setenv, unsetenv,
+	and getenv such that they only get compiled if they don't already
+	exist. [pullup from krb5-1-2-2-branch]
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+        * configure.in: Use AC_C_CONST instead of AC_CONST.
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* gettytab.c (nchktc): Don't overflow tcname if tty type name is too
+	long
+	* kerberos.c (kerberos4_status): Make sure "UserNameRequested" is
+	always properly terminated.
+	* kerberos5.c (kerberos5_is): If bad principal name is too long to fit
+	in "errbuf", don't print it.
+	(kerberos5_status): Make sure "UserNameRequested" is always properly
+	terminated.
+	* spx.c (spx_status): Ditto.
+
+2000-04-28  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kerberos5.c (kerberos5_is): Don't overflow buffer "errbuf".
+	* spx.c (spx_init, spx_send, spx_is): Don't overflow buffer
+	"targ_printable".
+	(spx_status): Don't overflow buffer "acl_file".
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-31 17:28   Jeffrey Altman <jaltman@columbia.edu>
+
+        * kerberos5.c: Ensure that only "host" service tickets are accepted.
+
+Wed Feb  3 22:59:27 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kerberos5.c: Increase size of str_data so that we can accept
+		mongo-gram tickets from Microsoft.  [telnet/686]
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* enc_des.c, kerberos.c: the ECB des functions don't exist
+	anymore, but telnet always encrypted/decrypted one block.  Convert
+	to calls to the new crypto api, with des-cbc-raw, using a single
+	block.
+
+Tue Mar  3 14:43:30 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Change test for cgetent to use HAVE_ instead
+		of HAS_, and add a test for gettosbyname().
+
+	* getent.c: Use HAVE_CGETENT instead of HAS_CGETENT
+
+	* parsetos.c: Use HAVE_GETTOSBYNAME instead of HAS_GETTOS
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* getopt.c (getopt): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Wed Feb 18 15:37:20 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Thu Feb 12 10:23:28 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Remove obsolete USE_KRB4_LIBRARY macro
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Nov 20 17:13:42 1997  Tom Yu  <tlyu@mit.edu>
+
+	* forward.c (rd_and_store_for_creds): Fix up to no longer do the
+	chown [krb5-appl/502]
+
+	* kerberos5.c (kerberos5_is): Fix up call to
+	rd_and_store_for_creds. [krb5-appl/502]
+
+Tue Oct 21 10:54:22 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* enc_des.c: Include string.h/strings.h for memcpy prototype
+
+Thu Jul 31 14:57:05 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Fix typo s/scrdir/srcdir/
+
+Thu Feb  6 00:14:50 1997  Richard Basch  <basch@lehman.com>
+
+	* kerberos5.c (kerberos5_is): First argument to
+		krb5_verify_checksum is a krb5_context!!!
+
+Thu Nov  7 15:29:09 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kerberos5.c (kerberos5_init): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Fri Nov  1 20:32:12 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* parsetos.c (proto;): Add parsetos support on all platforms which
+ 	support TOS[57]
+
+Thu Oct 31 18:29:08 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* auth.h: Move constants for ticket forwarding here.
+
+	* kerberos5.c : Clarify what errors come from what programs
+ 	(telnetd|telnet); patch by John Hawkinson <jhawk@bbnplanet.com>
+ 	[77]
+
+Mon Oct 14 00:21:08 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (OBJS): Remove rsaencpwd aned krb4encpwd stuff as
+ 	well as associated read_password [50]
+
+	* auth.c krb4encpwd.c Makefile.in: Remove krb4encpwd [50]
+	While we're at it, remove rsaencpwd as well.
+
+Tue Jul  9 14:59:19 1996  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): use @KRB4_INCLUDES@ instead of an
+ 	explicit path to the in-tree krb4 headers
+
+Mon Jul  8 01:33:30 1996  Marc Horowitz  <marc@mit.edu>
+
+	* enc-proto.h (des_new_random_key, des_set_random_generator_seed,
+ 	des_key_sched, des_ecb_encrypt, des_string_to_key): removed these
+ 	declarations.  these are kerberos/des symbols, and should not be
+ 	declared here.  Two of these symbols (des_key_sched and
+ 	des_ecb_encrypt) conflict with CNS.
+	
+Fri Jun 14 19:09:48 1996  Sam Hartman  <hartmans@mit.edu>
+*	configure.in * Makefile.in (LOCALINCLUDES): Don't include KerberosIV; use
+ 	whatever is appropriate for the withval
+
+Thu May  9 00:06:41 1996  Richard Basch  <basch@lehman.com>
+
+	* kerberos5.c: use the default server principal name to generate
+	the rcache filename
+
+Sat Apr 27 16:09:54 1996  Richard Basch  <basch@lehman.com>
+
+	* kerberos5.c: a host may have multiple names and multiple keys,
+	so do not try to resolve the "server" principal before the rd_req
+
+Fri Apr 12 23:36:01 1996  Richard Basch  <basch@lehman.com>
+
+	* forward.c (rd_and_store_for_creds): Consistency with the
+ 	krlogind forwarded credentials cache naming scheme - krb5cc_p<pid>
+
+Thu Apr 11 21:45:21 1996  Richard Basch  <basch@lehman.com>
+
+	* forward.c (rd_and_store_for_creds): If we are going to use a
+	ttyname based credentials file, at least compute it in a saner
+	fashion (strip the /dev/ and translate remaining /'s into _, so
+	the cache name looks like krb5cc_pts_4 instead of krb5cc_4).
+
+	* kerberos5.c (kerberos5_cleanup): Cleanup the credentials cache
+	that we may have created and destroy the context.
+
+Mon Mar 18 20:56:37 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kerberos5.c (kerberos5_send): Send in as input the
+		authentication type pair (ap->type, ap->way) to be
+		checksumed in the authenticator.
+		(kerberos5_is): If the checksum is present in the
+		authenticator, then validate the authentication type pair
+		against the checksum.
+		(kerberos5_reply): If we didn't do mutual authentication,
+		and we receive a KRB_ACCEPT, then stash away the session
+		key anyway.  This way we have a chance of doing encryption
+		even if mutual authentication wasn't done.
+
+	* encrypt.c (EncryptStartInput, EncryptStartOutput): Added
+		conditional around printf so that these two functions can
+		be called by the server.
+		(encrypt_is_encrypting): New function which returns true
+		only if both sides of the telnet stream is encrypted.
+
+Fri Mar 15 18:19:44 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* auth.c: Added new authentication scheme for Krb5 mutual
+		authentication with mandatory encryption.
+		(auth_send, auth_send_retry): Split auth_send() so that
+		the functionality done by auth_send_retry() is separate.
+		This avoids a really dodgy pointer comparison which was
+		caused by auth_send() being used for two purposes.  
+		If the client has not requested encryption, then don't
+		use the authentication systems which require encryption.
+		(auth_must_encrypt):  New function which returns whether 
+		or not encryption must be negotiated.
+
+	* auth-proto.h: Added prototype for new option
+		auth_must_encrypt().
+
+	* Makefile.in (ENCRYPTION, DES_ENCRYPTION): Added defines to turn
+	        on encryption and des encryption.
+
+Fri Jan 26 01:05:46 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* kerberos5.c (kerberos5_send): Get DES_CBC-CRC credentials.
+
+Tue Jan  9 22:53:58 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* forward.c (get_for_creds): Removed no longer used function.
+
+	* kerberos5.c (kerberos5_forward): Convert from using
+		get_for_creds() from forward.c to using the official
+		library routine, krb5_fwd_tgt_creds().  Misc. lint
+		cleanups. 
+
+Sun Nov 12 04:48:41 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* forward.c: set KRB5_DEFAULT_LIFE to 10 hours, not 8.
+	* forward.c (rd_and_store_for_creds): construct correct cache name
+	for forwarded tickets (based on tty name if available) and drop it
+	into the environment so login notices it.
+
+Mon Oct  9 23:03:48 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* kerberos5.c: make session_key a pointer, and use
+        krb5_copy_keyblock not krb5_copy_keyblock_contents; there was no
+        reason to violate this abstraction.
+
+Sun Sep 24 12:33:03 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* kerberos5.c: Initialize session key from the subsession key we get from krb5_mk_req_extended, using ticket key as a fallback.
+	(kerberos5_send): Use appropriate enctypes when encryption defined.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * encrypt.h, kerberos5.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * kerberos5.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate.
+
+Thu Aug 3 11:36:15 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kerberos.c - Give the compiler something to compile when K4 disabled.
+
+
+Tue Jun 27 16:16:18 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* enc_des.c, encrypt.c, krb4encpwd.c, read_password.c, rsaencpwd.c,
+		spx.c - Give the compiler something to compile when these
+		modules are essentially disabled.  Some compilers choke when
+		there's nothing to compile.
+	* setenv.c - Change prototype for __findenv to be static since it's
+		really static.
+
+Tue Jun 20 13:59:43 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: fix typo
+
+	* strrchr.c: NO_STRING_H -> HAVE_STRING_H
+
+	* strftime.c: NO_STRING_H -> HAVE_STRING_H
+
+	* strerror.c: NO_STRING_H -> HAVE_STRING_H
+
+	* strdup.c: NO_STRING_H -> HAVE_STRING_H
+
+	* strchr.c: NO_STRING_H -> HAVE_STRING_H
+
+	* strcasecmp.c: NO_STRING_H -> HAVE_STRING_H
+
+	* spx.c: NO_STRING_H -> HAVE_STRING_H
+
+	* rsaencpwd: NO_STRING_H -> HAVE_STRING_H
+
+	* read_password.c: NO_STRING_H -> HAVE_STRING_H
+
+	* mem.c: NO_STRING_H -> HAVE_STRING_H
+
+	* krb4encpwd.c: NO_STRING_H -> HAVE_STRING_H
+
+	* kerberos5.c: NO_STRING_H -> HAVE_STRING_H
+
+	* kerberos.c: NO_STRING_H -> HAVE_STRING_H
+
+	* encrypt.c: NO_STRING_H -> HAVE_STRING_H
+
+	* auth.c: NO_STRING_H -> HAVE_STRING_H for consistency
+
+	* configure.in: added missing tests for string.h, stdlib.h
+
+Sat Jun 10 22:59:42 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* forward.c, kerberos5.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:30:02 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed May 24 10:29:54 1995  Ezra Peisach  <epeisach@mit.edu>
+
+	* kerberos5.c: Include string.h/strings.h. Include stdlib.h or
+		declare malloc. 
+
+Sun May  7 18:45:09 1995  Ezra Peisach  <epeisach@mit.edu>
+
+	* kerberos5.c (kerberos5_send): Fix improperly closed comment
+			krb5_get_credentials second argument is not 
+				kdc_options....
+
+	* configure.in (LIBOBJS): Removed duplicate WITH_KRB4
+
+Fri Apr 28 11:17:16 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: switch to WITH_KRB4 since it suffices in this case.
+
+Thu Apr 27 17:08:16 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: use AC_CONST since we need it for v4.
+
+Thu Apr 27 15:52:19 1995  Chris Provenzano  (proven@mit.edu)
+
+	* kerberos5.c (kerberos_is()) : Initialize keytabid to NULL.
+
+Thu Apr 27 14:48:38 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (LOCALINCLUDES): find kerberosIV headers.
+
+Wed Apr 26 19:52:52 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* kerberos5.c (kerberos5_is): use kt_resolve to get keytab, to
+	correspond to current interface to rd_req.
+
+Tue Apr 25 21:23:28 1995  Chris Provenzano  (proven@mit.edu)
+
+        * forward.c (rd_and_store_for_creds()) : Rewritten to use
+                auth_context and the new krb5_rd_creds().
+        * forward.c (get_for_creds()) : New function replacing
+                krb5_get_for_creds() and uses auth_context and new
+                krb5_mk_creds() routine.
+        * kerberos5.c (kerberos5_send()): Set initial flags on auth_context
+		to KRB5_AUTH_CONTEXT_RET_TIME, and use new
+        	rd_and_store_for_creds() routine.
+	* kerberos5.c (kerberos5_forward()): Use the new get_for_creds().
+
+Sat Apr 22 00:50:14 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kerberos5.c (kerberos5_init): Only call krb5_init_context if 
+		the telnet context hasn't been initialized yet.
+
+Thu Apr 20 20:12:32 1995  Mark Eichin  <eichin@cygnus.com>
+
+	Changes for testsuite from Ian Taylor <ian@cygnus.com>
+	* kerberos5.c (telnet_srvtab): New global variable.
+	(telnet_krb5_realm): New global variable.
+	(kerberos5_send): If telnet_krb5_realm is set, copy it into
+	creds.server.  Pass new_creds to krb5_mk_req_extended, not &creds.
+	Pass &new_creds->keyblock to krb5_copy_keyblock_contents, not
+	new_creds.
+	(kerberos5_is): pass telnet_srvtab in to krb_rd_req.
+	(kerberos5_forward): If telnet_krb5_realm is set, copy it into
+	local_creds->server.
+
+Wed Mar 29 15:08:43 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kerberos5.c: No need to have the session_key established for
+		mutual authentication to work.  (That's only done if
+		ENCRYPTION is defined.)
+
+	* auth.c (authenticators): Allow mutual authentication even if the
+		ENCRYPTION option is not turned on.
+
+Mon Mar 27 07:56:26 1995 Chris Provenzano (proven@mit.edu)
+
+        * kerberos5.c (kerberos5_is()): Use new calling convention for 
+		krb5_rd_req(), and krb5_mk_rep().
+
+Fri Mar 24 23:51:18 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kerberos5.c (kerberos5_send): Initialize auth_context to zero
+		before calling mk_req.
+
+Fri Mar 10 11:09:34 1995  Chris Provenzano (proven@mit.edu)
+
+        * kerberos5.c: Use new calling convention for krb5_mk_req_extended().
+
+Tue Mar  7 19:52:00 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: take out ISODE_DEFS, ISODE_INCLUDE.
+
+Tue Feb 28 01:48:32 1995  John Gilmore  (gnu at toad.com)
+
+	* forward.c, kerberos5.c:  Avoid <krb5/...> includes.
+
+Tue Feb 14 15:30:55 1995 Chris Provenzano  (proven@mit.edu)
+
+        * kerberos5.c (kerberos5_send(), kerberos5_forward()) 
+		Call krb5_get_credentials() and krb5_mk_req_extended() 
+		with new calling convention.
+
+Thu Feb  2 02:56:50 1995  John Gilmore  <gnu@cygnus.com>
+
+	* forward.c:  Remove unused #include <krb5/crc-32.h>.
+	* kerberos5.c (kerberos5_send):  Remove code for sending a checksum
+	of a zero-byte string; we can just send no checksum at all.  This
+	eliminates dependency on <krb5/crc-32.h>.
+	(kerberos5_forward):  Remove extra parameter to krb5_get_for_creds,
+	probably accidentally inserted during context changes -- which don't
+	seem to be here in the ChangeLog.
+	* kerberos.c:  Remove prototypes for krb4 functions, since
+	some of them are wrong with CNS (u_long vs. KRB_INT32 conflicts).
+
+Fri Nov 18 15:19:26 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kerberos5.c (kerberos5_init): Initialize magic variable and
+		encryption type.  
+
+Fri Nov 18 00:37:13 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: use WITH_KRB4. (from epeisach)
+
+Mon Nov 14 16:27:29 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kerberos.c (kerberos4_is): Initialize random number generator on
+		the server side so that the encryption routines later on
+		can use it. 
+
+	* kerberos.c (kerberos4_send): Fix bug in how we pick the
+		challenge for the challenge/response mutual
+		authentication.
+
+Fri Nov 11 00:55:36 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* forward.c (mk_cred, rd_cred): Move these routines to libkrb.a.
+
+Tue Nov  8 01:39:50 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kerberos.c (kerberos4_is): Fix bug in logic of incrementing the
+		received challenge.  A ++/-- mixup means there's a 1 in
+		256 chance the server will get it wrong.
+
+	* kerberos.c: Use des_init_random_number_genator(), since that
+		will result in different subsession keys on successive
+		runs of telnet.
+
+Mon Nov  7 22:36:20 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* auth.c (auth_status): Only print each possible authentication
+		type once in the status report.
+
+	* auth.c (auth_onoff): Remove excess call to getauthmask() which
+		stomped the mask field.  Only print each possible
+		authentication type once in the help message.
+
+	* auth.c (getauthmask): Fix reversed sense of strcasecmp
+		comparison.
+
+	* auth.c (auth_enable, auth_disable): Change the input type to be
+		a char *, which is what auth_onoff wants anyway.
+
+Mon Aug  8 22:16:54 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* kerberos5.c (kerberos5_send): Whoops, mispelled
+	krb5_copy_keyblock_contents().  (It was inside #ifdef
+	ENCRYPTION)
+
+Thu Aug  4 03:36:29 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: add blank target for install
+
+Tue Jul 26 18:21:29 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: whoops left out some $(srcdir) stuff
+
+Mon Jul 25 01:05:31 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: remove reference to lorder (linux doesn't have
+	lorder, it seems)
+
+Fri Jul 15 23:36:50 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* kerberos5.c (kerberos5_is): Avoid coredump caused by freeing of
+	an unitialized variable.  Also make sure we don't try to free name
+	if it is NULL.
+
diff --git a/mechglue/src/appl/telnet/libtelnet/Makefile.4.4 b/mechglue/src/appl/telnet/libtelnet/Makefile.4.4
new file mode 100644
index 000000000..495dd73c5
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/Makefile.4.4
@@ -0,0 +1,33 @@
+#	@(#)Makefile	8.2 (Berkeley) 12/15/93
+
+LIB=	telnet
+SRCS=	auth.c encrypt.c genget.c getent.c misc.c
+SRCS+=	kerberos.c enc_des.c
+#SRCS+=	kerberos5.c
+CFLAGS+= -DENCRYPTION -DAUTHENTICATION -DHAS_CGETENT
+CFLAGS+= -DKRB4 -DDES_ENCRYPTION -I/usr/include/kerberosIV
+
+# These are the sources that have encryption stuff in them.
+CRYPT_SRC= auth.c enc-proto.h enc_des.c encrypt.c
+CRYPT_SRC+= encrypt.h kerberos.c kerberos5.c krb4encpwd.c
+CRYPT_SRC+= misc.c spx.c Makefile
+NOCRYPT_DIR=${.CURDIR}/Nocrypt
+
+.include <bsd.lib.mk>
+
+nocrypt:
+#ifdef	ENCRYPTION
+	@for i in ${CRYPT_SRC}; do \
+	    if [ ! -d ${NOCRYPT_DIR} ]; then \
+		echo Creating subdirectory ${NOCRYPT_DIR}; \
+		mkdir ${NOCRYPT_DIR}; \
+	    fi; \
+	    echo ${NOCRYPT_DIR}/$$i; \
+	    unifdef -UENCRYPTION ${.CURDIR}/$$i | \
+		sed "s/ || defined(ENCRYPTION)//" > ${NOCRYPT_DIR}/$$i; \
+	done
+
+placeholder:
+#else	/* ENCRYPTION */
+	@echo "Encryption code already removed."
+#endif	/* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/libtelnet/Makefile.generic b/mechglue/src/appl/telnet/libtelnet/Makefile.generic
new file mode 100644
index 000000000..760417f17
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/Makefile.generic
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 1991 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted provided
+# that: (1) source distributions retain this entire copyright notice and
+# comment, and (2) distributions including binaries display the following
+# acknowledgement:  ``This product includes software developed by the
+# University of California, Berkeley and its contributors'' in the
+# documentation or other materials provided with the distribution and in
+# all advertising materials mentioning features or use of this software.
+# Neither the name of the University nor the names of its contributors may
+# be used to endorse or promote products derived from this software without
+# specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#	@(#)Makefile.generic	5.5 (Berkeley) 3/1/91
+#
+
+LIB=    libtelnet.a
+SRCS=   auth.c encrypt.c genget.c \
+	misc.c kerberos.c kerberos5.c forward.c spx.c enc_des.c \
+	rsaencpwd.c krb4encpwd.c read_password.c \
+	setenv.c getent.c strdup.c strcasecmp.c \
+	strchr.c strrchr.c strftime.c strerror.c \
+	${LIB_SRC}
+
+OBJS=   auth.o encrypt.o genget.o \
+	misc.o kerberos.o kerberos5.o forward.o spx.o enc_des.o \
+	rsaencpwd.o krb4encpwd.o read_password.o \
+	${LIB_OBJ}
+
+TELNET_H= ../arpa/telnet.h
+
+CFLAGS= ${LCCFLAGS} ${DEFINES} ${INCLUDES}
+
+${LIB}: ${OBJS}
+	rm -f ${LIB}
+	${AR} ${ARFLAGS} ${LIB} `lorder ${OBJS} | tsort`
+	@if [ ${RANLIB} != NONE ]; \
+		then echo ${RANLIB} ${LIB}; ${RANLIB} ${LIB}; fi
+
+clean cleandir:
+	rm -f *.o ${LIB} core a.out
+
+auth.o: ${TELNET_H}
+auth.o: encrypt.h
+auth.o: auth.h
+auth.o: misc-proto.h
+encrypt.o: ${TELNET_H}
+encrypt.o: encrypt.h
+encrypt.o: misc.h
+kerberos.o: ${TELNET_H}
+kerberos.o: encrypt.h
+kerberos.o: auth.h
+kerberos.o: misc.h
+kerberos5.o: ${TELNET_H}
+kerberos5.o: encrypt.h
+kerberos5.o: auth.h
+kerberos5.o: misc.h
+misc.o: misc.h
+enc_des.o: ${TELNET_H}
+enc_des.o: encrypt.h
+enc_des.o: key-proto.h
+enc_des.o: misc-proto.h
diff --git a/mechglue/src/appl/telnet/libtelnet/Makefile.in b/mechglue/src/appl/telnet/libtelnet/Makefile.in
new file mode 100644
index 000000000..b31c98730
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/Makefile.in
@@ -0,0 +1,140 @@
+thisconfigdir=..
+myfulldir=appl/telnet/libtelnet
+mydir=libtelnet
+BUILDTOP=$(REL)..$(S)..$(S)..
+# derived from the original Makefile.generic
+#
+# Copyright (c) 1991 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted provided
+# that: (1) source distributions retain this entire copyright notice and
+# comment, and (2) distributions including binaries display the following
+# acknowledgement:  ``This product includes software developed by the
+# University of California, Berkeley and its contributors'' in the
+# documentation or other materials provided with the distribution and in
+# all advertising materials mentioning features or use of this software.
+# Neither the name of the University nor the names of its contributors may
+# be used to endorse or promote products derived from this software without
+# specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#	@(#)Makefile.generic	5.5 (Berkeley) 3/1/91
+#
+AUTH_DEF=-DAUTHENTICATION -DENCRYPTION -DDES_ENCRYPTION -DKRB5 -DFORWARD \
+	-UNO_LOGIN_F -DLOGIN_CAP_F -DLOGIN_PROGRAM=KRB5_PATH_LOGIN
+LOCALINCLUDES=-I.. -I$(srcdir)/.. @KRB4_INCLUDES@
+DEFINES = $(AUTH_DEF)
+LIBOBJS=@LIBOBJS@
+
+SETENVSRC=@SETENVSRC@
+SETENVOBJ=@SETENVOBJ@
+
+LIBBASE=telnet
+LIBMAJOR=0
+LIBMINOR=0
+RELDIR=../../../appl/telnet/libtelnet
+STOBJLISTS=OBJS.ST
+
+SRCS=   $(srcdir)/auth.c \
+	$(srcdir)/encrypt.c \
+	$(srcdir)/genget.c \
+	$(srcdir)/misc.c \
+	$(srcdir)/kerberos.c \
+	$(srcdir)/kerberos5.c \
+	$(srcdir)/forward.c \
+	$(srcdir)/spx.c \
+	$(srcdir)/enc_des.c \
+	$(srcdir)/setenv.c \
+	$(srcdir)/getent.c \
+	$(srcdir)/parsetos.c \
+	$(srcdir)/strdup.c \
+	$(srcdir)/strcasecmp.c \
+	$(srcdir)/strchr.c \
+	$(srcdir)/strrchr.c \
+	$(srcdir)/strftime.c \
+	$(srcdir)/strerror.c
+
+STLIBOBJS=   auth.o encrypt.o genget.o \
+	misc.o kerberos.o kerberos5.o forward.o spx.o enc_des.o \
+	$(LIBOBJS) getent.o $(SETENVOBJ)
+
+TELNET_H= $(srcdir)/../arpa/telnet.h
+
+all:: all-libs
+
+clean:: clean-libs clean-libobjs
+
+auth.o: $(TELNET_H)
+auth.o: encrypt.h
+auth.o: auth.h
+auth.o: misc-proto.h
+encrypt.o: $(TELNET_H)
+encrypt.o: encrypt.h
+encrypt.o: misc.h
+kerberos.o: $(TELNET_H)
+kerberos.o: encrypt.h
+kerberos.o: auth.h
+kerberos.o: misc.h
+kerberos5.o: $(TELNET_H)
+kerberos5.o: encrypt.h
+kerberos5.o: auth.h
+kerberos5.o: misc.h
+misc.o: misc.h
+enc_des.o: $(TELNET_H)
+enc_des.o: encrypt.h
+enc_des.o: key-proto.h
+enc_des.o: misc-proto.h
+install::
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+auth.so auth.po $(OUTPRE)auth.$(OBJEXT): auth.c $(srcdir)/../arpa/telnet.h \
+  encrypt.h enc-proto.h auth.h auth-proto.h misc-proto.h
+encrypt.so encrypt.po $(OUTPRE)encrypt.$(OBJEXT): encrypt.c \
+  $(srcdir)/../arpa/telnet.h encrypt.h enc-proto.h misc.h \
+  misc-proto.h
+genget.so genget.po $(OUTPRE)genget.$(OBJEXT): genget.c \
+  misc.h misc-proto.h
+misc.so misc.po $(OUTPRE)misc.$(OBJEXT): misc.c misc.h \
+  misc-proto.h auth.h auth-proto.h encrypt.h enc-proto.h
+kerberos.so kerberos.po $(OUTPRE)kerberos.$(OBJEXT): \
+  kerberos.c $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h encrypt.h enc-proto.h \
+  auth.h auth-proto.h misc.h misc-proto.h
+kerberos5.so kerberos5.po $(OUTPRE)kerberos5.$(OBJEXT): \
+  kerberos5.c $(srcdir)/../arpa/telnet.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/syslog.h encrypt.h \
+  enc-proto.h auth.h auth-proto.h misc.h misc-proto.h \
+  krb5forw.h
+forward.so forward.po $(OUTPRE)forward.$(OBJEXT): forward.c \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) krb5forw.h
+spx.so spx.po $(OUTPRE)spx.$(OBJEXT): spx.c misc-proto.h
+enc_des.so enc_des.po $(OUTPRE)enc_des.$(OBJEXT): enc_des.c \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(srcdir)/../arpa/telnet.h \
+  encrypt.h enc-proto.h key-proto.h misc-proto.h
+setenv.so setenv.po $(OUTPRE)setenv.$(OBJEXT): setenv.c \
+  misc-proto.h
+getent.so getent.po $(OUTPRE)getent.$(OBJEXT): getent.c \
+  gettytab.h
+parsetos.so parsetos.po $(OUTPRE)parsetos.$(OBJEXT): \
+  parsetos.c misc-proto.h
+strdup.so strdup.po $(OUTPRE)strdup.$(OBJEXT): strdup.c
+strcasecmp.so strcasecmp.po $(OUTPRE)strcasecmp.$(OBJEXT): \
+  strcasecmp.c
+strchr.so strchr.po $(OUTPRE)strchr.$(OBJEXT): strchr.c
+strrchr.so strrchr.po $(OUTPRE)strrchr.$(OBJEXT): strrchr.c
+strftime.so strftime.po $(OUTPRE)strftime.$(OBJEXT): \
+  strftime.c
+strerror.so strerror.po $(OUTPRE)strerror.$(OBJEXT): \
+  strerror.c
diff --git a/mechglue/src/appl/telnet/libtelnet/auth-proto.h b/mechglue/src/appl/telnet/libtelnet/auth-proto.h
new file mode 100644
index 000000000..6b4957032
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/auth-proto.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)auth-proto.h	8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#if	defined(AUTHENTICATION)
+Authenticator *findauthenticator (int, int);
+
+void auth_init (char *, int);
+int auth_cmd (int, char **);
+void auth_request (void);
+void auth_send (unsigned char *, int);
+void auth_send_retry (void);
+void auth_is (unsigned char *, int);
+void auth_reply (unsigned char *, int);
+void auth_finished (Authenticator *, int);
+void auth_wait (char *);
+int auth_check (char *);
+int auth_must_encrypt (void);
+void auth_disable_name (char *);
+void auth_gen_printsub (unsigned char *, int, unsigned char *, unsigned int);
+
+
+int getauthmask (char *, int *);
+int auth_enable (char *);
+int auth_disable (char *);
+int auth_onoff (char *, int);
+int auth_togdebug (int);
+int auth_status (void);
+void auth_name (unsigned char *, int);
+int auth_sendname (unsigned char *, int);
+void auth_debug (int);
+void auth_printsub (unsigned char *, int, unsigned char *, unsigned int);
+
+
+#ifdef	KRB4
+int kerberos4_init (Authenticator *, int);
+int kerberos4_send (Authenticator *);
+void kerberos4_is (Authenticator *, unsigned char *, int);
+void kerberos4_reply (Authenticator *, unsigned char *, int);
+int kerberos4_status (Authenticator *, char *, int);
+void kerberos4_printsub (unsigned char *, int, unsigned char *, unsigned int);
+#endif
+
+#ifdef	KRB5
+int kerberos5_init (Authenticator *, int);
+int kerberos5_send (Authenticator *);
+void kerberos5_is (Authenticator *, unsigned char *, int);
+void kerberos5_reply (Authenticator *, unsigned char *, int);
+int kerberos5_status (Authenticator *, char *, int);
+void kerberos5_printsub (unsigned char *, int, unsigned char *, unsigned int);
+void kerberos5_cleanup (void);
+#endif
+#endif
diff --git a/mechglue/src/appl/telnet/libtelnet/auth.c b/mechglue/src/appl/telnet/libtelnet/auth.c
new file mode 100644
index 000000000..28b8ae8d1
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/auth.c
@@ -0,0 +1,669 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)auth.c	8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may 
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#if	defined(AUTHENTICATION)
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#define	AUTH_NAMES
+#include <arpa/telnet.h>
+#ifdef	__STDC__
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include "encrypt.h"
+#include "auth.h"
+#include "misc-proto.h"
+#include "auth-proto.h"
+
+#define	typemask(x)		(1<<((x)-1))
+
+
+
+int auth_debug_mode = 0;
+int auth_has_failed = 0;
+int auth_enable_encrypt = 0;
+int auth_client_non_unix = 0;
+static 	char	*Name = "Noname";
+static	int	Server = 0;
+static	Authenticator	*authenticated = 0;
+static	int	authenticating = 0;
+static	int	validuser = 0;
+static	unsigned char	_auth_send_data[256];
+static	unsigned char	*auth_send_data;
+static	int	auth_send_cnt = 0;
+
+/*
+ * Authentication types supported.  Plese note that these are stored
+ * in priority order, i.e. try the first one first.
+ */
+Authenticator authenticators[] = {
+#ifdef	SPX
+	{ AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
+				spx_init,
+				spx_send,
+				spx_is,
+				spx_reply,
+				spx_status,
+				spx_printsub },
+	{ AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
+				spx_init,
+				spx_send,
+				spx_is,
+				spx_reply,
+				spx_status,
+				spx_printsub },
+#endif
+#ifdef	KRB5
+#ifdef ENCRYPTION
+	{ AUTHTYPE_KERBEROS_V5,
+		  AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL|AUTH_ENCRYPT_ON,
+				kerberos5_init,
+				kerberos5_send,
+				kerberos5_is,
+				kerberos5_reply,
+				kerberos5_status,
+				kerberos5_printsub },
+#endif	
+	{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
+				kerberos5_init,
+				kerberos5_send,
+				kerberos5_is,
+				kerberos5_reply,
+				kerberos5_status,
+				kerberos5_printsub },
+	{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
+				kerberos5_init,
+				kerberos5_send,
+				kerberos5_is,
+				kerberos5_reply,
+				kerberos5_status,
+				kerberos5_printsub },
+#endif
+#ifdef	KRB4
+# ifdef ENCRYPTION
+	{ AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
+				kerberos4_init,
+				kerberos4_send,
+				kerberos4_is,
+				kerberos4_reply,
+				kerberos4_status,
+				kerberos4_printsub },
+# endif	/* ENCRYPTION */
+	{ AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
+				kerberos4_init,
+				kerberos4_send,
+				kerberos4_is,
+				kerberos4_reply,
+				kerberos4_status,
+				kerberos4_printsub },
+#endif
+	{ 0, },
+};
+
+static Authenticator NoAuth = { 0 };
+
+static int	i_support = 0;
+static int	i_wont_support = 0;
+
+	Authenticator *
+findauthenticator(type, way)
+	int type;
+	int way;
+{
+	Authenticator *ap = authenticators;
+
+	while (ap->type && (ap->type != type || ap->way != way))
+		++ap;
+	return(ap->type ? ap : 0);
+}
+
+	void
+auth_init(name, server)
+	char *name;
+	int server;
+{
+	Authenticator *ap = authenticators;
+
+	Server = server;
+	Name = name;
+
+	i_support = 0;
+	authenticated = 0;
+	authenticating = 0;
+	while (ap->type) {
+		if (!ap->init || (*ap->init)(ap, server)) {
+			i_support |= typemask(ap->type);
+			if (auth_debug_mode)
+				printf(">>>%s: I support auth type %d %d\r\n",
+					Name,
+					ap->type, ap->way);
+		}
+		++ap;
+	}
+}
+
+	void
+auth_disable_name(name)
+	char *name;
+{
+	int x;
+	for (x = 0; x < AUTHTYPE_CNT; ++x) {
+		if (!strcasecmp(name, AUTHTYPE_NAME(x))) {
+			i_wont_support |= typemask(x);
+			break;
+		}
+	}
+}
+
+	int
+getauthmask(type, maskp)
+	char *type;
+	int *maskp;
+{
+	register int x;
+
+	if (!strcasecmp(type, AUTHTYPE_NAME(0))) {
+		*maskp = -1;
+		return(1);
+	}
+
+	for (x = 1; x < AUTHTYPE_CNT; ++x) {
+		if (!strcasecmp(type, AUTHTYPE_NAME(x))) {
+			*maskp = typemask(x);
+			return(1);
+		}
+	}
+	return(0);
+}
+
+	int
+auth_enable(type)
+	char * type;
+{
+	return(auth_onoff(type, 1));
+}
+
+	int
+auth_disable(type)
+	char * type;
+{
+	return(auth_onoff(type, 0));
+}
+
+	int
+auth_onoff(type, on)
+	char *type;
+	int on;
+{
+	int i, mask = -1;
+	Authenticator *ap;
+
+	if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
+                printf("auth %s 'type'\n", on ? "enable" : "disable");
+		printf("Where 'type' is one of:\n");
+		printf("\t%s\n", AUTHTYPE_NAME(0));
+		mask = 0;
+		for (ap = authenticators; ap->type; ap++) {
+			if ((mask & (i = typemask(ap->type))) != 0)
+				continue;
+			mask |= i;
+			printf("\t%s\n", AUTHTYPE_NAME(ap->type));
+		}
+		return(0);
+	}
+
+	if (!getauthmask(type, &mask)) {
+		printf("%s: invalid authentication type\n", type);
+		return(0);
+	}
+	if (on)
+		i_wont_support &= ~mask;
+	else
+		i_wont_support |= mask;
+	return(1);
+}
+
+	int
+auth_togdebug(on)
+	int on;
+{
+	if (on < 0)
+		auth_debug_mode ^= 1;
+	else
+		auth_debug_mode = on;
+	printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
+	return(1);
+}
+
+	int
+auth_status()
+{
+	Authenticator *ap;
+	int i, mask;
+
+	if (i_wont_support == -1)
+		printf("Authentication disabled\n");
+	else
+		printf("Authentication enabled\n");
+
+	mask = 0;
+	for (ap = authenticators; ap->type; ap++) {
+		if ((mask & (i = typemask(ap->type))) != 0)
+			continue;
+		mask |= i;
+		printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
+			(i_wont_support & typemask(ap->type)) ?
+					"disabled" : "enabled");
+	}
+	return(1);
+}
+
+/*
+ * This routine is called by the server to start authentication
+ * negotiation.
+ */
+	void
+auth_request()
+{
+	static unsigned char str_request[64] = { IAC, SB,
+						 TELOPT_AUTHENTICATION,
+						 TELQUAL_SEND, };
+	Authenticator *ap = authenticators;
+	unsigned char *e = str_request + 4;
+
+	if (!authenticating) {
+		authenticating = 1;
+		while (ap->type) {
+			if (i_support & ~i_wont_support & typemask(ap->type)) {
+				if (ap->type == AUTHTYPE_KERBEROS_V4 ||
+				    !auth_client_non_unix) {
+					if (auth_debug_mode) {
+						printf(">>>%s: Sending type %d %d\r\n",
+						       Name, ap->type, ap->way);
+					}
+					*e++ = ap->type;
+					*e++ = ap->way;
+				}
+			}
+			++ap;
+		}
+		if (auth_client_non_unix) {
+			ap = authenticators;
+			while (ap->type) {
+				if (i_support & ~i_wont_support & typemask(ap->type)) {
+					*e++ = ap->type;
+					*e++ = ap->way;
+				}
+				++ap;
+			}
+		}
+		*e++ = IAC;
+		*e++ = SE;
+		net_write(str_request, e - str_request);
+		printsub('>', &str_request[2], e - str_request - 2);
+	}
+}
+
+/*
+ * This is called when an AUTH SEND is received.
+ * It should never arrive on the server side (as only the server can
+ * send an AUTH SEND).
+ * You should probably respond to it if you can...
+ *
+ * If you want to respond to the types out of order (i.e. even
+ * if he sends  LOGIN KERBEROS and you support both, you respond
+ * with KERBEROS instead of LOGIN (which is against what the
+ * protocol says)) you will have to hack this code...
+ */
+	void
+auth_send(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	if (Server) {
+		if (auth_debug_mode) {
+			printf(">>>%s: auth_send called!\r\n", Name);
+		}
+		return;
+	}
+
+	if (auth_debug_mode) {
+		printf(">>>%s: auth_send got:", Name);
+		printd(data, cnt); printf("\r\n");
+	}
+
+	/*
+	 * Save the list of authentication mechanisms
+	 */
+	auth_send_cnt = cnt;
+	if (auth_send_cnt > sizeof(_auth_send_data))
+	    auth_send_cnt = sizeof(_auth_send_data);
+	memcpy((void *)_auth_send_data, (void *)data, 
+	       (unsigned) auth_send_cnt);
+	auth_send_data = _auth_send_data;
+
+	auth_send_retry();
+}
+
+/*
+ * Try the next authentication mechanism on the list, and see if it
+ * works.
+ */
+void auth_send_retry()
+{
+	Authenticator *ap;
+	static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
+					    TELQUAL_IS, AUTHTYPE_NULL, 0,
+					    IAC, SE };
+	
+	if (Server) {
+		if (auth_debug_mode) {
+			printf(">>>%s: auth_send_retry called!\r\n", Name);
+		}
+		return;
+	}
+
+	for (;(auth_send_cnt -= 2) >= 0; auth_send_data += 2) {
+	    if (auth_debug_mode)
+		printf(">>>%s: He supports %d\r\n", Name, *auth_send_data);
+	    if (!(i_support & typemask(*auth_send_data)))
+		continue;
+	    if (i_wont_support & typemask(*auth_send_data))
+		continue;
+	    ap = findauthenticator(auth_send_data[0], auth_send_data[1]);
+	    if (!ap || !ap->send)
+		continue;
+	    if ((ap->way & AUTH_ENCRYPT_MASK) && !auth_enable_encrypt)
+		continue;
+
+	    if (auth_debug_mode)
+		printf(">>>%s: Trying %d %d\r\n", Name, auth_send_data[0],
+		       auth_send_data[1]);
+	    if ((*ap->send)(ap)) {
+		/*
+		 * Okay, we found one we like and did it.  we can go
+		 * home now.
+		 */
+		if (auth_debug_mode)
+		    printf(">>>%s: Using type %d\r\n", Name, *auth_send_data);
+		auth_send_data += 2;
+		return;
+	    }
+	}
+	net_write(str_none, sizeof(str_none));
+	printsub('>', &str_none[2], sizeof(str_none) - 2);
+	if (auth_debug_mode)
+		printf(">>>%s: Sent failure message\r\n", Name);
+	auth_finished(0, AUTH_REJECT);
+	auth_has_failed = 1;
+#ifdef KANNAN
+	/*
+	 *  We requested strong authentication, however no mechanisms worked.
+	 *  Therefore, exit on client end.
+	 */
+	printf("Unable to securely authenticate user ... exit\n"); 
+	exit(0);
+#endif /* KANNAN */
+}
+
+	void
+auth_is(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	Authenticator *ap;
+
+	if (cnt < 2)
+		return;
+
+	if (data[0] == AUTHTYPE_NULL) {
+		auth_finished(0, AUTH_REJECT);
+		return;
+	}
+
+	if ((ap = findauthenticator(data[0], data[1]))) {
+		if (ap->is)
+			(*ap->is)(ap, data+2, cnt-2);
+	} else if (auth_debug_mode)
+		printf(">>>%s: Invalid authentication in IS: %d\r\n",
+			Name, *data);
+}
+
+	void
+auth_reply(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	Authenticator *ap;
+
+	if (cnt < 2)
+		return;
+
+	if ((ap = findauthenticator(data[0], data[1]))) {
+		if (ap->reply)
+			(*ap->reply)(ap, data+2, cnt-2);
+	} else if (auth_debug_mode)
+		printf(">>>%s: Invalid authentication in SEND: %d\r\n",
+			Name, *data);
+}
+
+	void
+auth_name(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	unsigned char savename[256];
+
+	if (cnt < 1) {
+		if (auth_debug_mode)
+			printf(">>>%s: Empty name in NAME\r\n", Name);
+		return;
+	}
+	if (cnt > sizeof(savename) - 1) {
+		if (auth_debug_mode)
+			printf(">>>%s: Name in NAME (%d) exceeds %d length\r\n",
+					Name, cnt, (int) sizeof(savename)-1);
+		return;
+	}
+	memcpy((void *)savename, (void *)data, (unsigned) cnt);
+	savename[cnt] = '\0';	/* Null terminate */
+	if (auth_debug_mode)
+		printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
+	auth_encrypt_user((const char *)savename);
+}
+
+	int
+auth_sendname(cp, len)
+	unsigned char *cp;
+	int len;
+{
+	static unsigned char str_request[256+6]
+			= { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
+	register unsigned char *e = str_request + 4;
+	register unsigned char *ee = &str_request[sizeof(str_request)-2];
+
+	while (--len >= 0) {
+		if ((*e++ = *cp++) == IAC)
+			*e++ = IAC;
+		if (e >= ee)
+			return(0);
+	}
+	*e++ = IAC;
+	*e++ = SE;
+	net_write(str_request, e - str_request);
+	printsub('>', &str_request[2], e - &str_request[2]);
+	return(1);
+}
+
+	void
+auth_finished(ap, result)
+	Authenticator *ap;
+	int result;
+{
+	if (!(authenticated = ap))
+		authenticated = &NoAuth;
+	validuser = result;
+}
+
+	/* ARGSUSED */
+	static void
+auth_intr(sig)
+	int sig;
+{
+	auth_finished(0, AUTH_REJECT);
+}
+
+	void
+auth_wait(name)
+	char *name;
+{
+	if (auth_debug_mode)
+		printf(">>>%s: in auth_wait.\r\n", Name);
+
+	if (Server && !authenticating)
+		return;
+
+	(void) signal(SIGALRM, auth_intr);
+	alarm(30);
+	while (!authenticated)
+		if (telnet_spin())
+			break;
+	alarm(0);
+	(void) signal(SIGALRM, SIG_DFL);
+}
+
+	int
+auth_check(name)
+	char *name;
+{
+	/*
+	 * Now check to see if the user is valid or not
+	 */
+	if (!authenticated || authenticated == &NoAuth)
+		return(AUTH_REJECT);
+
+	if (validuser == AUTH_VALID)
+		validuser = AUTH_USER;
+
+	if (authenticated->status)
+		validuser = (*authenticated->status)(authenticated,
+						     name, validuser);
+	return(validuser);
+}
+
+int auth_must_encrypt()
+{
+    if (authenticated &&
+	((authenticated->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON))
+	return 1;
+    return 0;
+}
+
+	void
+auth_debug(mode)
+	int mode;
+{
+	auth_debug_mode = mode;
+}
+
+	void
+auth_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt;
+	unsigned int buflen;
+{
+	Authenticator *ap;
+
+	if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
+		(*ap->printsub)(data, cnt, buf, buflen);
+	else
+		auth_gen_printsub(data, cnt, buf, buflen);
+}
+
+	void
+auth_gen_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt;
+	unsigned int buflen;
+{
+	register unsigned char *cp;
+	unsigned char tbuf[16];
+
+	cnt -= 3;
+	data += 3;
+	buf[buflen-1] = '\0';
+	buf[buflen-2] = '*';
+	buflen -= 2;
+	for (; cnt > 0; cnt--, data++) {
+		sprintf((char *)tbuf, " %d", *data);
+		for (cp = tbuf; *cp && buflen > 0; --buflen)
+			*buf++ = *cp++;
+		if (buflen <= 0)
+			return;
+	}
+	*buf = '\0';
+}
+#endif
diff --git a/mechglue/src/appl/telnet/libtelnet/auth.h b/mechglue/src/appl/telnet/libtelnet/auth.h
new file mode 100644
index 000000000..f9f31d8e7
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/auth.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)auth.h	8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef	__AUTH__
+#define	__AUTH__
+
+#define	AUTH_REJECT	0	/* Rejected */
+#define	AUTH_UNKNOWN	1	/* We don't know who he is, but he's okay */
+#define	AUTH_OTHER	2	/* We know him, but not his name */
+#define	AUTH_USER	3	/* We know he name */
+#define	AUTH_VALID	4	/* We know him, and he needs no password */
+
+typedef struct XauthP {
+	int	type;
+	int	way;
+	int	(*init) (struct XauthP *, int);
+	int	(*send) (struct XauthP *);
+	void	(*is) (struct XauthP *, unsigned char *, int);
+	void	(*reply) (struct XauthP *, unsigned char *, int);
+	int	(*status) (struct XauthP *, char *, int);
+	void	(*printsub) (unsigned char *, int, unsigned char *, unsigned int);
+} Authenticator;
+
+#include "auth-proto.h"
+
+#define OPTS_FORWARD_CREDS           0x00000002
+#define OPTS_FORWARDABLE_CREDS       0x00000001
+
+extern int auth_debug_mode;
+#endif
diff --git a/mechglue/src/appl/telnet/libtelnet/enc-proto.h b/mechglue/src/appl/telnet/libtelnet/enc-proto.h
new file mode 100644
index 000000000..eed7db66b
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/enc-proto.h
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)enc-proto.h	8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+#ifdef	ENCRYPTION
+void encrypt_init (char *, int);
+Encryptions *findencryption (int);
+Encryptions *finddecryption (int);
+void encrypt_send_supprt (void);
+void encrypt_auto (int);
+void decrypt_auto (int);
+void encrypt_debug (int);
+void encrypt_is (unsigned char *, int);
+void encrypt_reply (unsigned char *, int);
+void encrypt_start_input (int);
+void encrypt_session_key (Session_Key *, int);
+void encrypt_end_input (void);
+void encrypt_start_output (int);
+void encrypt_end_output (void);
+void encrypt_send_request_start (void);
+void encrypt_send_request_end (void);
+void encrypt_send_end (void);
+void encrypt_wait (void);
+int encrypt_is_encrypting (void);
+int EncryptAutoEnc (int);
+int EncryptAutoDec (int);
+int EncryptEnable (char *, char *);
+int EncryptDisable (char *, char *);
+int EncryptDebug (int);
+int EncryptType (char *, char *);
+int EncryptStart (char *);
+int EncryptStartInput (void);
+int EncryptStartOutput (void);
+int EncryptStop (char *);
+int EncryptStopInput (void);
+int EncryptStopOutput (void);
+int EncryptStatus (void);
+int EncryptVerbose (int);
+void encrypt_send_support (void);
+void encrypt_send_keyid (int, unsigned char *, unsigned int, int);
+int net_write (unsigned char *, int);
+void encrypt_gen_printsub (unsigned char *, int, unsigned char *, int);
+void encrypt_printsub (unsigned char *, int, unsigned char *, int);
+
+
+void encrypt_request_start (unsigned char *, int);
+void encrypt_request_end (void);
+void encrypt_enc_keyid (unsigned char *, int);
+void encrypt_dec_keyid (unsigned char *, int);
+void encrypt_support (unsigned char *, int);
+void encrypt_start (unsigned char *, int);
+void encrypt_end (void);
+
+
+#ifdef	TELENTD
+void encrypt_wait (void);
+#else
+void printsub (int, unsigned char *, int);
+int encrypt_cmd (int, char **);
+void encrypt_display (void);
+#endif
+
+void krbdes_encrypt (unsigned char *, int);
+int krbdes_decrypt (int);
+int krbdes_is (unsigned char *, int);
+int krbdes_reply (unsigned char *, int);
+void krbdes_init (int);
+int krbdes_start (int, int);
+void krbdes_session (Session_Key *, int);
+void krbdes_printsub (unsigned char *, int, unsigned char *, int);
+
+void cfb64_encrypt (unsigned char *, int);
+int cfb64_decrypt (int);
+void cfb64_init (int);
+int cfb64_start (int, int);
+int cfb64_is (unsigned char *, int);
+int cfb64_reply (unsigned char *, int);
+void cfb64_session (Session_Key *, int);
+int cfb64_keyid (int, unsigned char *, int *);
+void cfb64_printsub (unsigned char *, int, unsigned char *, int);
+
+void ofb64_encrypt (unsigned char *, int);
+int ofb64_decrypt (int);
+void ofb64_init (int);
+int ofb64_start (int, int);
+int ofb64_is (unsigned char *, int);
+int ofb64_reply (unsigned char *, int);
+void ofb64_session (Session_Key *, int);
+int ofb64_keyid (int, unsigned char *, int *);
+void ofb64_printsub (unsigned char *, int, unsigned char *, int);
+#endif	/* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/libtelnet/enc_des.c b/mechglue/src/appl/telnet/libtelnet/enc_des.c
new file mode 100644
index 000000000..c399d22c7
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/enc_des.c
@@ -0,0 +1,780 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)enc_des.c	8.1 (Berkeley) 6/4/93 */
+
+#ifdef	ENCRYPTION
+# ifdef	AUTHENTICATION
+#  ifdef DES_ENCRYPTION
+#include <krb5.h>
+#include <arpa/telnet.h>
+#include <stdio.h>
+#ifdef	__STDC__
+#include <stdlib.h>
+#endif
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include "encrypt.h"
+#include "key-proto.h"
+#include "misc-proto.h"
+
+extern int encrypt_debug_mode;
+
+extern krb5_context telnet_context;
+
+#define	CFB	0
+#define	OFB	1
+
+#define	NO_SEND_IV	1
+#define	NO_RECV_IV	2
+#define	NO_KEYID	4
+#define	IN_PROGRESS	(NO_SEND_IV|NO_RECV_IV|NO_KEYID)
+#define	SUCCESS		0
+#define	FAILED		-1
+
+
+struct fb {
+	Block temp_feed;
+	unsigned char fb_feed[64];
+	int need_start;
+	int state[2];
+	int keyid[2];
+	int once;
+	int validkey;
+	struct stinfo {
+		Block		str_output;
+		Block		str_feed;
+		Block		str_iv;
+		unsigned char	str_keybytes[8]; /* yuck */
+		krb5_keyblock	str_key;
+		int		str_index;
+		int		str_flagshift;
+	} streams[2];
+};
+
+static struct fb fb[2];
+
+struct keyidlist {
+	char	*keyid;
+	int	keyidlen;
+	char	*key;
+	int	keylen;
+	int	flags;
+} keyidlist [] = {
+	{ "\0", 1, 0, 0, 0 },		/* default key of zero */
+	{ 0, 0, 0, 0, 0 }
+};
+
+#define	KEYFLAG_MASK	03
+
+#define	KEYFLAG_NOINIT	00
+#define	KEYFLAG_INIT	01
+#define	KEYFLAG_OK	02
+#define	KEYFLAG_BAD	03
+
+#define	KEYFLAG_SHIFT	2
+
+#define	SHIFT_VAL(a,b)	(KEYFLAG_SHIFT*((a)+((b)*2)))
+
+#define	FB64_IV		1
+#define	FB64_IV_OK	2
+#define	FB64_IV_BAD	3
+
+
+void fb64_stream_iv (Block, struct stinfo *);
+void fb64_init (struct fb *);
+static int fb64_start (struct fb *, int, int);
+int fb64_is (unsigned char *, int, struct fb *);
+int fb64_reply (unsigned char *, int, struct fb *);
+static void fb64_session (Session_Key *, int, struct fb *);
+void fb64_stream_key (Block, struct stinfo *);
+int fb64_keyid (int, unsigned char *, int *, struct fb *);
+void fb64_printsub (unsigned char *, int, unsigned char *, int, 
+		     unsigned char *);
+
+static void ecb_encrypt(stp, in, out)
+     struct stinfo *stp;
+     Block in;
+     Block out;
+{
+	krb5_error_code code;
+	krb5_data din;
+	krb5_enc_data dout;
+	
+	din.length = 8;
+	din.data = in;
+
+	dout.ciphertext.length = 8;
+	dout.ciphertext.data = out;
+	dout.enctype = ENCTYPE_UNKNOWN;
+
+	code = krb5_c_encrypt(telnet_context, &stp->str_key, 0, 0,
+			      &din, &dout);
+	/* XXX I'm not sure what to do if this fails */
+	if (code)
+		com_err("libtelnet", code, "encrypting stream data");
+}
+
+	void
+cfb64_init(server)
+	int server;
+{
+	fb64_init(&fb[CFB]);
+	fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
+	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
+	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
+}
+
+	void
+ofb64_init(server)
+	int server;
+{
+	fb64_init(&fb[OFB]);
+	fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
+	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
+	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
+}
+
+	void
+fb64_init(fbp)
+	register struct fb *fbp;
+{
+	memset((void *)fbp, 0, sizeof(*fbp));
+	fbp->state[0] = fbp->state[1] = FAILED;
+	fbp->fb_feed[0] = IAC;
+	fbp->fb_feed[1] = SB;
+	fbp->fb_feed[2] = TELOPT_ENCRYPT;
+	fbp->fb_feed[3] = ENCRYPT_IS;
+}
+
+/*
+ * Returns:
+ *	-1: some error.  Negotiation is done, encryption not ready.
+ *	 0: Successful, initial negotiation all done.
+ *	 1: successful, negotiation not done yet.
+ *	 2: Not yet.  Other things (like getting the key from
+ *	    Kerberos) have to happen before we can continue.
+ */
+	int
+cfb64_start(dir, server)
+	int dir;
+	int server;
+{
+	return(fb64_start(&fb[CFB], dir, server));
+}
+	int
+ofb64_start(dir, server)
+	int dir;
+	int server;
+{
+	return(fb64_start(&fb[OFB], dir, server));
+}
+
+	static int
+fb64_start(fbp, dir, server)
+	struct fb *fbp;
+	int dir;
+	int server;
+{
+	int x;
+	unsigned char *p;
+	register int state;
+
+	switch (dir) {
+	case DIR_DECRYPT:
+		/*
+		 * This is simply a request to have the other side
+		 * start output (our input).  He will negotiate an
+		 * IV so we need not look for it.
+		 */
+		state = fbp->state[dir-1];
+		if (state == FAILED)
+			state = IN_PROGRESS;
+		break;
+
+	case DIR_ENCRYPT:
+		state = fbp->state[dir-1];
+		if (state == FAILED)
+			state = IN_PROGRESS;
+		else if ((state & NO_SEND_IV) == 0)
+			break;
+
+		if (!fbp->validkey) {
+			fbp->need_start = 1;
+			break;
+		}
+		state &= ~NO_SEND_IV;
+		state |= NO_RECV_IV;
+		if (encrypt_debug_mode)
+			printf("Creating new feed\r\n");
+		/*
+		 * Create a random feed and send it over.
+		 */
+		{
+			krb5_data d;
+
+			d.data = fbp->temp_feed;
+			d.length = sizeof(fbp->temp_feed);
+
+			if (krb5_c_random_make_octets(telnet_context, &d))
+				return(FAILED);
+		}
+
+		p = fbp->fb_feed + 3;
+		*p++ = ENCRYPT_IS;
+		p++;
+		*p++ = FB64_IV;
+		for (x = 0; x < sizeof(Block); ++x) {
+			if ((*p++ = fbp->temp_feed[x]) == IAC)
+				*p++ = IAC;
+		}
+		*p++ = IAC;
+		*p++ = SE;
+		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+		net_write(fbp->fb_feed, p - fbp->fb_feed);
+		break;
+	default:
+		return(FAILED);
+	}
+	return(fbp->state[dir-1] = state);
+}
+
+/*
+ * Returns:
+ *	-1: some error.  Negotiation is done, encryption not ready.
+ *	 0: Successful, initial negotiation all done.
+ *	 1: successful, negotiation not done yet.
+ */
+	int
+cfb64_is(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	return(fb64_is(data, cnt, &fb[CFB]));
+}
+	int
+ofb64_is(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	return(fb64_is(data, cnt, &fb[OFB]));
+}
+
+	int
+fb64_is(data, cnt, fbp)
+	unsigned char *data;
+	int cnt;
+	struct fb *fbp;
+{
+	unsigned char *p;
+	register int state = fbp->state[DIR_DECRYPT-1];
+
+	if (cnt-- < 1)
+		goto failure;
+
+	switch (*data++) {
+	case FB64_IV:
+		if (cnt != sizeof(Block)) {
+			if (encrypt_debug_mode)
+				printf("CFB64: initial vector failed on size\r\n");
+			state = FAILED;
+			goto failure;
+		}
+
+		if (encrypt_debug_mode)
+			printf("CFB64: initial vector received\r\n");
+
+		if (encrypt_debug_mode)
+			printf("Initializing Decrypt stream\r\n");
+
+		fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
+
+		p = fbp->fb_feed + 3;
+		*p++ = ENCRYPT_REPLY;
+		p++;
+		*p++ = FB64_IV_OK;
+		*p++ = IAC;
+		*p++ = SE;
+		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+		net_write(fbp->fb_feed, p - fbp->fb_feed);
+
+		state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
+		break;
+
+	default:
+		if (encrypt_debug_mode) {
+			printf("Unknown option type: %d\r\n", *(data-1));
+			printd(data, cnt);
+			printf("\r\n");
+		}
+		/* FALL THROUGH */
+	failure:
+		/*
+		 * We failed.  Send an FB64_IV_BAD option
+		 * to the other side so it will know that
+		 * things failed.
+		 */
+		p = fbp->fb_feed + 3;
+		*p++ = ENCRYPT_REPLY;
+		p++;
+		*p++ = FB64_IV_BAD;
+		*p++ = IAC;
+		*p++ = SE;
+		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+		net_write(fbp->fb_feed, p - fbp->fb_feed);
+
+		break;
+	}
+	return(fbp->state[DIR_DECRYPT-1] = state);
+}
+
+/*
+ * Returns:
+ *	-1: some error.  Negotiation is done, encryption not ready.
+ *	 0: Successful, initial negotiation all done.
+ *	 1: successful, negotiation not done yet.
+ */
+	int
+cfb64_reply(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	return(fb64_reply(data, cnt, &fb[CFB]));
+}
+	int
+ofb64_reply(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	return(fb64_reply(data, cnt, &fb[OFB]));
+}
+
+
+	int
+fb64_reply(data, cnt, fbp)
+	unsigned char *data;
+	int cnt;
+	struct fb *fbp;
+{
+	register int state = fbp->state[DIR_ENCRYPT-1];
+
+	if (cnt-- < 1)
+		goto failure;
+
+	switch (*data++) {
+	case FB64_IV_OK:
+		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+		if (state == FAILED)
+			state = IN_PROGRESS;
+		state &= ~NO_RECV_IV;
+		encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
+		break;
+
+	case FB64_IV_BAD:
+		memset(fbp->temp_feed, 0, sizeof(Block));
+		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+		state = FAILED;
+		break;
+
+	default:
+		if (encrypt_debug_mode) {
+			printf("Unknown option type: %d\r\n", data[-1]);
+			printd(data, cnt);
+			printf("\r\n");
+		}
+		/* FALL THROUGH */
+	failure:
+		state = FAILED;
+		break;
+	}
+	return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+	void
+cfb64_session(key, server)
+	Session_Key *key;
+	int server;
+{
+	fb64_session(key, server, &fb[CFB]);
+}
+
+	void
+ofb64_session(key, server)
+	Session_Key *key;
+	int server;
+{
+	fb64_session(key, server, &fb[OFB]);
+}
+
+	static void
+fb64_session(key, server, fbp)
+	Session_Key *key;
+	int server;
+	struct fb *fbp;
+{
+	if (!key || key->type != SK_DES) {
+		if (encrypt_debug_mode)
+			printf("Can't set krbdes's session key (%d != %d)\r\n",
+				key ? key->type : -1, SK_DES);
+		return;
+	}
+
+	fbp->validkey = 1;
+
+	fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1]);
+	fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1]);
+
+	/*
+	 * Now look to see if krbdes_start() was was waiting for
+	 * the key to show up.  If so, go ahead an call it now
+	 * that we have the key.
+	 */
+	if (fbp->need_start) {
+		fbp->need_start = 0;
+		fb64_start(fbp, DIR_ENCRYPT, server);
+	}
+}
+
+/*
+ * We only accept a keyid of 0.  If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+	int
+cfb64_keyid(dir, kp, lenp)
+	int dir, *lenp;
+	unsigned char *kp;
+{
+	return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
+}
+
+	int
+ofb64_keyid(dir, kp, lenp)
+	int dir, *lenp;
+	unsigned char *kp;
+{
+	return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
+}
+
+	int
+fb64_keyid(dir, kp, lenp, fbp)
+	int dir, *lenp;
+	unsigned char *kp;
+	struct fb *fbp;
+{
+	register int state = fbp->state[dir-1];
+
+	if (*lenp != 1 || (*kp != '\0')) {
+		*lenp = 0;
+		return(state);
+	}
+
+	if (state == FAILED)
+		state = IN_PROGRESS;
+
+	state &= ~NO_KEYID;
+
+	return(fbp->state[dir-1] = state);
+}
+
+	void
+fb64_printsub(data, cnt, buf, buflen, type)
+	unsigned char *data, *buf, *type;
+	int cnt, buflen;
+{
+	char lbuf[32];
+	register int i;
+	char *cp;
+
+	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
+	buflen -= 1;
+
+	switch(data[2]) {
+	case FB64_IV:
+		sprintf(lbuf, "%s_IV", type);
+		cp = lbuf;
+		goto common;
+
+	case FB64_IV_OK:
+		sprintf(lbuf, "%s_IV_OK", type);
+		cp = lbuf;
+		goto common;
+
+	case FB64_IV_BAD:
+		sprintf(lbuf, "%s_IV_BAD", type);
+		cp = lbuf;
+		goto common;
+
+	default:
+		sprintf(lbuf, " %d (unknown)", data[2]);
+		cp = lbuf;
+	common:
+		for (; (buflen > 0) && (*buf = *cp++); buf++)
+			buflen--;
+		for (i = 3; i < cnt; i++) {
+			sprintf(lbuf, " %d", data[i]);
+			for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
+				buflen--;
+		}
+		break;
+	}
+}
+
+	void
+cfb64_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt, buflen;
+{
+	fb64_printsub(data, cnt, buf, buflen, (unsigned char *) "CFB64");
+}
+
+	void
+ofb64_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt, buflen;
+{
+	fb64_printsub(data, cnt, buf, buflen, (unsigned char *) "OFB64");
+}
+
+	void
+fb64_stream_iv(seed, stp)
+	Block seed;
+	register struct stinfo *stp;
+{
+	memcpy((void *)stp->str_iv,     (void *)seed, sizeof(Block));
+	memcpy((void *)stp->str_output, (void *)seed, sizeof(Block));
+
+	stp->str_index = sizeof(Block);
+}
+
+	void
+fb64_stream_key(key, stp)
+	Block key;
+	register struct stinfo *stp;
+{
+	memcpy((void *)stp->str_keybytes, (void *)key, sizeof(Block));
+	stp->str_key.length = 8;
+	stp->str_key.contents = stp->str_keybytes;
+	/* the original version of this code uses des ecb mode, but
+	   it only ever does one block at a time.  cbc with a zero iv
+	   is identical */
+	stp->str_key.enctype = ENCTYPE_DES_CBC_RAW;
+
+	memcpy((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
+
+	stp->str_index = sizeof(Block);
+}
+
+/*
+ * DES 64 bit Cipher Feedback
+ *
+ *     key --->+-----+
+ *          +->| DES |--+
+ *          |  +-----+  |
+ *	    |           v
+ *  INPUT --(--------->(+)+---> DATA
+ *          |             |
+ *	    +-------------+
+ *         
+ *
+ * Given:
+ *	iV: Initial vector, 64 bits (8 bytes) long.
+ *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ *	V0 = DES(iV, key)
+ *	On = Dn ^ Vn
+ *	V(n+1) = DES(On, key)
+ */
+
+	void
+cfb64_encrypt(s, c)
+	register unsigned char *s;
+	int c;
+{
+	register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
+	register int idx;
+
+	idx = stp->str_index;
+	while (c-- > 0) {
+		if (idx == sizeof(Block)) {
+			Block b;
+			ecb_encrypt(stp, stp->str_output, b);
+			memcpy((void *)stp->str_feed,(void *)b,sizeof(Block));
+			idx = 0;
+		}
+
+		/* On encryption, we store (feed ^ data) which is cypher */
+		*s = stp->str_output[idx] = (stp->str_feed[idx] ^ *s);
+		s++;
+		idx++;
+	}
+	stp->str_index = idx;
+}
+
+	int
+cfb64_decrypt(data)
+	int data;
+{
+	register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
+	int idx;
+
+	if (data == -1) {
+		/*
+		 * Back up one byte.  It is assumed that we will
+		 * never back up more than one byte.  If we do, this
+		 * may or may not work.
+		 */
+		if (stp->str_index)
+			--stp->str_index;
+		return(0);
+	}
+
+	idx = stp->str_index++;
+	if (idx == sizeof(Block)) {
+		Block b;
+		ecb_encrypt(stp, stp->str_output, b);
+		memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+		stp->str_index = 1;	/* Next time will be 1 */
+		idx = 0;		/* But now use 0 */ 
+	}
+
+	/* On decryption we store (data) which is cypher. */
+	stp->str_output[idx] = data;
+	return(data ^ stp->str_feed[idx]);
+}
+
+/*
+ * DES 64 bit Output Feedback
+ *
+ * key --->+-----+
+ *	+->| DES |--+
+ *	|  +-----+  |
+ *	+-----------+
+ *	            v
+ *  INPUT -------->(+) ----> DATA
+ *
+ * Given:
+ *	iV: Initial vector, 64 bits (8 bytes) long.
+ *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
+ *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
+ *
+ *	V0 = DES(iV, key)
+ *	V(n+1) = DES(Vn, key)
+ *	On = Dn ^ Vn
+ */
+	void
+ofb64_encrypt(s, c)
+	register unsigned char *s;
+	int c;
+{
+	register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
+	register int idx;
+
+	idx = stp->str_index;
+	while (c-- > 0) {
+		if (idx == sizeof(Block)) {
+			Block b;
+			ecb_encrypt(stp, stp->str_feed, b);
+			memcpy((void *)stp->str_feed,(void *)b,sizeof(Block));
+			idx = 0;
+		}
+		*s++ ^= stp->str_feed[idx];
+		idx++;
+	}
+	stp->str_index = idx;
+}
+
+	int
+ofb64_decrypt(data)
+	int data;
+{
+	register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
+	int idx;
+
+	if (data == -1) {
+		/*
+		 * Back up one byte.  It is assumed that we will
+		 * never back up more than one byte.  If we do, this
+		 * may or may not work.
+		 */
+		if (stp->str_index)
+			--stp->str_index;
+		return(0);
+	}
+
+	idx = stp->str_index++;
+	if (idx == sizeof(Block)) {
+		Block b;
+		ecb_encrypt(stp, stp->str_feed, b);
+		memcpy((void *)stp->str_feed, (void *)b, sizeof(Block));
+		stp->str_index = 1;	/* Next time will be 1 */
+		idx = 0;		/* But now use 0 */ 
+	}
+
+	return(data ^ stp->str_feed[idx]);
+}
+#  endif /* DES_ENCRYPTION */
+# endif	/* AUTHENTICATION */
+#else	/* ENCRYPTION */
+#include "misc-proto.h"
+#endif	/* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/libtelnet/encrypt.c b/mechglue/src/appl/telnet/libtelnet/encrypt.c
new file mode 100644
index 000000000..e99f346c4
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/encrypt.c
@@ -0,0 +1,1014 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)encrypt.c	8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef	ENCRYPTION
+
+#include <stdio.h>
+#define	ENCRYPT_NAMES
+#include <arpa/telnet.h>
+
+#include "encrypt.h"
+#include "misc.h"
+
+#ifdef	__STDC__
+#include <stdlib.h>
+#endif
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * These functions pointers point to the current routines
+ * for encrypting and decrypting data.
+ */
+void	(*encrypt_output) (unsigned char *, int);
+int	(*decrypt_input) (int);
+
+int encrypt_debug_mode = 0;
+static int decrypt_mode = 0;
+static int encrypt_mode = 0;
+static int encrypt_verbose = 0;
+static int autoencrypt = 0;
+static int autodecrypt = 0;
+static int havesessionkey = 0;
+static int Server = 0;
+static char *Name = "Noname";
+
+#define	typemask(x)	((x) > 0 ? 1 << ((x)-1) : 0)
+
+static long i_support_encrypt = typemask(ENCTYPE_DES_CFB64)
+				| typemask(ENCTYPE_DES_OFB64);
+static long i_support_decrypt = typemask(ENCTYPE_DES_CFB64)
+				| typemask(ENCTYPE_DES_OFB64);
+static long i_wont_support_encrypt = 0;
+static long i_wont_support_decrypt = 0;
+#define	I_SUPPORT_ENCRYPT	(i_support_encrypt & ~i_wont_support_encrypt)
+#define	I_SUPPORT_DECRYPT	(i_support_decrypt & ~i_wont_support_decrypt)
+
+static long remote_supports_encrypt = 0;
+static long remote_supports_decrypt = 0;
+
+static Encryptions encryptions[] = {
+#ifdef	DES_ENCRYPTION
+    { "DES_CFB64",	ENCTYPE_DES_CFB64,
+			cfb64_encrypt,	
+			cfb64_decrypt,
+			cfb64_init,
+			cfb64_start,
+			cfb64_is,
+			cfb64_reply,
+			cfb64_session,
+			cfb64_keyid,
+			cfb64_printsub },
+    { "DES_OFB64",	ENCTYPE_DES_OFB64,
+			ofb64_encrypt,	
+			ofb64_decrypt,
+			ofb64_init,
+			ofb64_start,
+			ofb64_is,
+			ofb64_reply,
+			ofb64_session,
+			ofb64_keyid,
+			ofb64_printsub },
+#endif	/* DES_ENCRYPTION */
+    { 0, },
+};
+
+static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPT,
+					 ENCRYPT_SUPPORT };
+static unsigned char str_suplen = 0;
+static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPT };
+static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPT, 0, IAC, SE };
+
+	Encryptions *
+findencryption(type)
+	int type;
+{
+	Encryptions *ep = encryptions;
+
+	if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type)))
+		return(0);
+	while (ep->type && ep->type != type)
+		++ep;
+	return(ep->type ? ep : 0);
+}
+
+	Encryptions *
+finddecryption(type)
+	int type;
+{
+	Encryptions *ep = encryptions;
+
+	if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type)))
+		return(0);
+	while (ep->type && ep->type != type)
+		++ep;
+	return(ep->type ? ep : 0);
+}
+
+#define	MAXKEYLEN 64
+
+static struct key_info {
+	unsigned char keyid[MAXKEYLEN];
+	int keylen;
+	int dir;
+	int *modep;
+	Encryptions *(*getcrypt)();
+} ki[2] = {
+	{ { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption },
+	{ { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption },
+};
+
+	void
+encrypt_init(name, server)
+	char *name;
+	int server;
+{
+	Encryptions *ep = encryptions;
+
+	Name = name;
+	Server = server;
+	i_support_encrypt = i_support_decrypt = 0;
+	remote_supports_encrypt = remote_supports_decrypt = 0;
+	encrypt_mode = 0;
+	decrypt_mode = 0;
+	encrypt_output = 0;
+	decrypt_input = 0;
+#ifdef notdef
+	encrypt_verbose = !server;
+#endif
+
+	str_suplen = 4;
+
+	while (ep->type) {
+		if (encrypt_debug_mode)
+			printf(">>>%s: I will support %s\r\n",
+				Name, ENCTYPE_NAME(ep->type));
+		i_support_encrypt |= typemask(ep->type);
+		i_support_decrypt |= typemask(ep->type);
+		if ((i_wont_support_decrypt & typemask(ep->type)) == 0)
+			if ((str_send[str_suplen++] = ep->type) == IAC)
+				str_send[str_suplen++] = IAC;
+		if (ep->init)
+			(*ep->init)(Server);
+		++ep;
+	}
+	str_send[str_suplen++] = IAC;
+	str_send[str_suplen++] = SE;
+}
+
+static	void
+encrypt_list_types()
+{
+	Encryptions *ep = encryptions;
+
+	printf("Valid encryption types:\n");
+	while (ep->type) {
+		printf("\t%s (%d)\r\n", ENCTYPE_NAME(ep->type), ep->type);
+		++ep;
+	}
+}
+
+	int
+EncryptEnable(type, mode)
+	char *type, *mode;
+{
+	if (isprefix(type, "help") || isprefix(type, "?")) {
+		printf("Usage: encrypt enable <type> [input|output]\n");
+		encrypt_list_types();
+		return(0);
+	}
+	if (EncryptType(type, mode))
+		return(EncryptStart(mode));
+	return(0);
+}
+
+	int
+EncryptDisable(type, mode)
+	char *type, *mode;
+{
+	register Encryptions *ep;
+	int ret = 0;
+
+	if (isprefix(type, "help") || isprefix(type, "?")) {
+		printf("Usage: encrypt disable <type> [input|output]\n");
+		encrypt_list_types();
+	} else if ((ep = (Encryptions *)genget(type, (char **) encryptions,
+						sizeof(Encryptions))) == 0) {
+		printf("%s: invalid encryption type\n", type);
+	} else if (Ambiguous(ep)) {
+		printf("Ambiguous type '%s'\n", type);
+	} else {
+		if ((mode == 0) || (isprefix(mode, "input") ? 1 : 0)) {
+			if (decrypt_mode == ep->type)
+				EncryptStopInput();
+			i_wont_support_decrypt |= typemask(ep->type);
+			ret = 1;
+		}
+		if ((mode == 0) || (isprefix(mode, "output"))) {
+			if (encrypt_mode == ep->type)
+				EncryptStopOutput();
+			i_wont_support_encrypt |= typemask(ep->type);
+			ret = 1;
+		}
+		if (ret == 0)
+			printf("%s: invalid encryption mode\n", mode);
+	}
+	return(ret);
+}
+
+	int
+EncryptType(type, mode)
+	char *type;
+	char *mode;
+{
+	register Encryptions *ep;
+	int ret = 0;
+
+	if (isprefix(type, "help") || isprefix(type, "?")) {
+		printf("Usage: encrypt type <type> [input|output]\n");
+		encrypt_list_types();
+	} else if ((ep = (Encryptions *)genget(type, (char **) encryptions,
+						sizeof(Encryptions))) == 0) {
+		printf("%s: invalid encryption type\n", type);
+	} else if (Ambiguous(ep)) {
+		printf("Ambiguous type '%s'\n", type);
+	} else {
+		if ((mode == 0) || isprefix(mode, "input")) {
+			decrypt_mode = ep->type;
+			i_wont_support_decrypt &= ~typemask(ep->type);
+			ret = 1;
+		}
+		if ((mode == 0) || isprefix(mode, "output")) {
+			encrypt_mode = ep->type;
+			i_wont_support_encrypt &= ~typemask(ep->type);
+			ret = 1;
+		}
+		if (ret == 0)
+			printf("%s: invalid encryption mode\n", mode);
+	}
+	return(ret);
+}
+
+	int
+EncryptStart(mode)
+	char *mode;
+{
+	register int ret = 0;
+	if (mode) {
+		if (isprefix(mode, "input"))
+			return(EncryptStartInput());
+		if (isprefix(mode, "output"))
+			return(EncryptStartOutput());
+		if (isprefix(mode, "help") || isprefix(mode, "?")) {
+			printf("Usage: encrypt start [input|output]\n");
+			return(0);
+		}
+		printf("%s: invalid encryption mode 'encrypt start ?' for help\n", mode);
+		return(0);
+	}
+	ret += EncryptStartInput();
+	ret += EncryptStartOutput();
+	return(ret);
+}
+
+	int
+EncryptStartInput()
+{
+	if (decrypt_mode) {
+		encrypt_send_request_start();
+		return(1);
+	}
+	if (!Server)
+	    printf("No previous decryption mode, decryption not enabled\r\n");
+	return(0);
+}
+
+	int
+EncryptStartOutput()
+{
+	if (encrypt_mode) {
+		encrypt_start_output(encrypt_mode);
+		return(1);
+	}
+	if (!Server)
+	    printf("No previous encryption mode, encryption not enabled\r\n");
+	return(0);
+}
+
+	int
+EncryptStop(mode)
+	char *mode;
+{
+	int ret = 0;
+	if (mode) {
+		if (isprefix(mode, "input"))
+			return(EncryptStopInput());
+		if (isprefix(mode, "output"))
+			return(EncryptStopOutput());
+		if (isprefix(mode, "help") || isprefix(mode, "?")) {
+			printf("Usage: encrypt stop [input|output]\n");
+			return(0);
+		}
+		printf("%s: invalid encryption mode 'encrypt stop ?' for help\n", mode);
+		return(0);
+	}
+	ret += EncryptStopInput();
+	ret += EncryptStopOutput();
+	return(ret);
+}
+
+	int
+EncryptStopInput()
+{
+	encrypt_send_request_end();
+	return(1);
+}
+
+	int
+EncryptStopOutput()
+{
+	encrypt_send_end();
+	return(1);
+}
+
+	void
+encrypt_display()
+{
+	if (encrypt_output)
+		printf("Currently encrypting output with %s\r\n",
+			ENCTYPE_NAME(encrypt_mode));
+	if (decrypt_input)
+		printf("Currently decrypting input with %s\r\n",
+			ENCTYPE_NAME(decrypt_mode));
+}
+
+	int
+EncryptStatus()
+{
+	if (encrypt_output)
+		printf("Currently encrypting output with %s\r\n",
+			ENCTYPE_NAME(encrypt_mode));
+	else if (encrypt_mode) {
+		printf("Currently output is clear text.\r\n");
+		printf("Last encryption mode was %s\r\n",
+			ENCTYPE_NAME(encrypt_mode));
+	}
+	if (decrypt_input) {
+		printf("Currently decrypting input with %s\r\n",
+			ENCTYPE_NAME(decrypt_mode));
+	} else if (decrypt_mode) {
+		printf("Currently input is clear text.\r\n");
+		printf("Last decryption mode was %s\r\n",
+			ENCTYPE_NAME(decrypt_mode));
+	}
+	return 1;
+}
+
+	void
+encrypt_send_support()
+{
+	if (str_suplen) {
+		/*
+		 * If the user has requested that decryption start
+		 * immediatly, then send a "REQUEST START" before
+		 * we negotiate the type.
+		 */
+		if (!Server && autodecrypt)
+			encrypt_send_request_start();
+		net_write(str_send, str_suplen);
+		printsub('>', &str_send[2], str_suplen - 2);
+		str_suplen = 0;
+	}
+}
+
+	int
+EncryptDebug(on)
+	int on;
+{
+	if (on < 0)
+		encrypt_debug_mode ^= 1;
+	else
+		encrypt_debug_mode = on;
+	printf("Encryption debugging %s\r\n",
+		encrypt_debug_mode ? "enabled" : "disabled");
+	return(1);
+}
+
+	int
+EncryptVerbose(on)
+	int on;
+{
+	if (on < 0)
+		encrypt_verbose ^= 1;
+	else
+		encrypt_verbose = on;
+	printf("Encryption %s verbose\r\n",
+		encrypt_verbose ? "is" : "is not");
+	return(1);
+}
+
+	int
+EncryptAutoEnc(on)
+	int on;
+{
+	encrypt_auto(on);
+	printf("Automatic encryption of output is %s\r\n",
+		autoencrypt ? "enabled" : "disabled");
+	return(1);
+}
+
+	int
+EncryptAutoDec(on)
+	int on;
+{
+	decrypt_auto(on);
+	printf("Automatic decryption of input is %s\r\n",
+		autodecrypt ? "enabled" : "disabled");
+	return(1);
+}
+
+/*
+ * Called when ENCRYPT SUPPORT is received.
+ */
+	void
+encrypt_support(typelist, cnt)
+	unsigned char *typelist;
+	int cnt;
+{
+	register int type, use_type = 0;
+	Encryptions *ep;
+
+	/*
+	 * Forget anything the other side has previously told us.
+	 */
+	remote_supports_decrypt = 0;
+
+	while (cnt-- > 0) {
+		type = *typelist++;
+		if (encrypt_debug_mode)
+			printf(">>>%s: He is supporting %s (%d)\r\n",
+				Name,
+				ENCTYPE_NAME(type), type);
+		if ((type < ENCTYPE_CNT) &&
+		    (I_SUPPORT_ENCRYPT & typemask(type))) {
+			remote_supports_decrypt |= typemask(type);
+			if (use_type == 0)
+				use_type = type;
+		}
+	}
+	if (use_type) {
+		ep = findencryption(use_type);
+		if (!ep)
+			return;
+		type = ep->start ? (*ep->start)(DIR_ENCRYPT, Server) : 0;
+		if (encrypt_debug_mode)
+			printf(">>>%s: (*ep->start)() returned %d\r\n",
+					Name, type);
+		if (type < 0)
+			return;
+		encrypt_mode = use_type;
+		if (type == 0)
+			encrypt_start_output(use_type);
+	}
+}
+
+	void
+encrypt_is(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	Encryptions *ep;
+	register int type, ret;
+
+	if (--cnt < 0)
+		return;
+	type = *data++;
+	if (type < ENCTYPE_CNT)
+		remote_supports_encrypt |= typemask(type);
+	if (!(ep = finddecryption(type))) {
+		if (encrypt_debug_mode)
+			printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n",
+				Name,
+				ENCTYPE_NAME_OK(type)
+					? ENCTYPE_NAME(type) : "(unknown)",
+				type);
+		return;
+	}
+	if (!ep->is) {
+		if (encrypt_debug_mode)
+			printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n",
+				Name,
+				ENCTYPE_NAME_OK(type)
+					? ENCTYPE_NAME(type) : "(unknown)",
+				type);
+		ret = 0;
+	} else {
+		ret = (*ep->is)(data, cnt);
+		if (encrypt_debug_mode)
+			printf("(*ep->is)(%lx, %d) returned %s(%d)\n", 
+			        (unsigned long) data, cnt,
+				(ret < 0) ? "FAIL " :
+				(ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret);
+	}
+	if (ret < 0) {
+		autodecrypt = 0;
+	} else {
+		decrypt_mode = type;
+		if (ret == 0 && autodecrypt)
+			encrypt_send_request_start();
+	}
+}
+
+	void
+encrypt_reply(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	Encryptions *ep;
+	register int ret, type;
+
+	if (--cnt < 0)
+		return;
+	type = *data++;
+	if (!(ep = findencryption(type))) {
+		if (encrypt_debug_mode)
+			printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n",
+				Name,
+				ENCTYPE_NAME_OK(type)
+					? ENCTYPE_NAME(type) : "(unknown)",
+				type);
+		return;
+	}
+	if (!ep->reply) {
+		if (encrypt_debug_mode)
+			printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n",
+				Name,
+				ENCTYPE_NAME_OK(type)
+					? ENCTYPE_NAME(type) : "(unknown)",
+				type);
+		ret = 0;
+	} else {
+		ret = (*ep->reply)(data, cnt);
+		if (encrypt_debug_mode)
+			printf("(*ep->reply)(%lx, %d) returned %s(%d)\n",
+				(unsigned long) data, cnt,
+				(ret < 0) ? "FAIL " :
+				(ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret);
+	}
+	if (encrypt_debug_mode)
+		printf(">>>%s: encrypt_reply returned %d\n", Name, ret);
+	if (ret < 0) {
+		autoencrypt = 0;
+	} else {
+		encrypt_mode = type;
+		if (ret == 0 && autoencrypt)
+			encrypt_start_output(type);
+	}
+}
+
+/*
+ * Called when a ENCRYPT START command is received.
+ */
+	void
+encrypt_start(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	Encryptions *ep;
+
+	if (!decrypt_mode) {
+		/*
+		 * Something is wrong.  We should not get a START
+		 * command without having already picked our
+		 * decryption scheme.  Send a REQUEST-END to
+		 * attempt to clear the channel...
+		 */
+		printf("%s: Warning, Cannot decrypt input stream!!!\r\n", Name);
+		encrypt_send_request_end();
+		return;
+	}
+
+	if ((ep = finddecryption(decrypt_mode))) {
+		decrypt_input = ep->input;
+		if (encrypt_verbose)
+			printf("[ Input is now decrypted with type %s ]\r\n",
+				ENCTYPE_NAME(decrypt_mode));
+		if (encrypt_debug_mode)
+			printf(">>>%s: Start to decrypt input with type %s\r\n",
+				Name, ENCTYPE_NAME(decrypt_mode));
+	} else {
+		printf("%s: Warning, Cannot decrypt type %s (%d)!!!\r\n",
+				Name,
+				ENCTYPE_NAME_OK(decrypt_mode)
+					? ENCTYPE_NAME(decrypt_mode)
+					: "(unknown)",
+				decrypt_mode);
+		encrypt_send_request_end();
+	}
+}
+
+	void
+encrypt_session_key(key, server)
+	Session_Key *key;
+	int server;
+{
+	Encryptions *ep = encryptions;
+
+	havesessionkey = 1;
+
+	while (ep->type) {
+		if (ep->session)
+			(*ep->session)(key, server);
+#ifdef notdef
+		if (!encrypt_output && autoencrypt && !server)
+			encrypt_start_output(ep->type);
+		if (!decrypt_input && autodecrypt && !server)
+			encrypt_send_request_start();
+#endif
+		++ep;
+	}
+}
+
+/*
+ * Called when ENCRYPT END is received.
+ */
+	void
+encrypt_end()
+{
+	decrypt_input = 0;
+	if (encrypt_debug_mode)
+		printf(">>>%s: Input is back to clear text\r\n", Name);
+	if (encrypt_verbose)
+		printf("[ Input is now clear text ]\r\n");
+}
+
+/*
+ * Called when ENCRYPT REQUEST-END is received.
+ */
+	void
+encrypt_request_end()
+{
+	encrypt_send_end();
+}
+
+/*
+ * Called when ENCRYPT REQUEST-START is received.  If we receive
+ * this before a type is picked, then that indicates that the
+ * other side wants us to start encrypting data as soon as we
+ * can. 
+ */
+	void
+encrypt_request_start(data, cnt)
+	unsigned char *data;
+	int cnt;
+{
+	if (encrypt_mode == 0)  {
+		if (Server)
+			autoencrypt = 1;
+		return;
+	}
+	encrypt_start_output(encrypt_mode);
+}
+
+static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT };
+
+static void encrypt_keyid (struct key_info *kp, unsigned char *, unsigned int);
+		
+void encrypt_enc_keyid(keyid, len)
+	unsigned char *keyid;
+	int len;
+{
+	encrypt_keyid(&ki[1], keyid, (unsigned) len);
+}
+
+void encrypt_dec_keyid(keyid, len)
+	unsigned char *keyid;
+	int len;
+{
+	encrypt_keyid(&ki[0], keyid, (unsigned) len);
+}
+
+static void encrypt_keyid(kp, keyid, len)
+	struct key_info *kp;
+	unsigned char *keyid;
+	unsigned int len;
+{
+	Encryptions *ep;
+	int dir = kp->dir;
+	register int ret = 0;
+
+	if (!(ep = (*kp->getcrypt)(*kp->modep))) {
+		if (len == 0)
+			return;
+		kp->keylen = 0;
+	} else if (len == 0) {
+		/*
+		 * Empty option, indicates a failure.
+		 */
+		if (kp->keylen == 0)
+			return;
+		kp->keylen = 0;
+		if (ep->keyid)
+			(void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
+
+	} else if ((len != kp->keylen) || 
+		   (memcmp(keyid, kp->keyid, len) != 0)) {
+		/*
+		 * Length or contents are different
+		 */
+		kp->keylen = len;
+		memcpy(kp->keyid, keyid, len);
+		if (ep->keyid)
+			(void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
+	} else {
+		if (ep->keyid)
+			ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen);
+		if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt)
+			encrypt_start_output(*kp->modep);
+		return;
+	}
+
+	encrypt_send_keyid(dir, kp->keyid, (unsigned) kp->keylen, 0);
+}
+
+	void
+encrypt_send_keyid(dir, keyid, keylen, saveit)
+	int dir;
+	unsigned char *keyid;
+	unsigned int keylen;
+	int saveit;
+{
+	unsigned char *strp;
+
+	str_keyid[3] = (dir == DIR_ENCRYPT)
+			? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID;
+	if (saveit) {
+		struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1];
+		memcpy(kp->keyid, keyid, keylen);
+		kp->keylen = keylen;
+	}
+
+	for (strp = &str_keyid[4]; keylen > 0; --keylen) {
+		if ((*strp++ = *keyid++) == IAC)
+			*strp++ = IAC;
+	}
+	*strp++ = IAC;
+	*strp++ = SE;
+	net_write(str_keyid, strp - str_keyid);
+	printsub('>', &str_keyid[2], strp - str_keyid - 2);
+}
+
+	void
+encrypt_auto(on)
+	int on;
+{
+	if (on < 0)
+		autoencrypt ^= 1;
+	else
+		autoencrypt = on ? 1 : 0;
+}
+
+	void
+decrypt_auto(on)
+	int on;
+{
+	if (on < 0)
+		autodecrypt ^= 1;
+	else
+		autodecrypt = on ? 1 : 0;
+}
+
+	void
+encrypt_start_output(type)
+	int type;
+{
+	Encryptions *ep;
+	register unsigned char *p;
+	register int i;
+
+	if (!(ep = findencryption(type))) {
+		if (encrypt_debug_mode) {
+			printf(">>>%s: Can't encrypt with type %s (%d)\r\n",
+				Name,
+				ENCTYPE_NAME_OK(type)
+					? ENCTYPE_NAME(type) : "(unknown)",
+				type);
+		}
+		return;
+	}
+	if (ep->start) {
+		i = (*ep->start)(DIR_ENCRYPT, Server);
+		if (encrypt_debug_mode) {
+			printf(">>>%s: Encrypt start: %s (%d) %s\r\n",
+				Name, 
+				(i < 0) ? "failed" :
+					"initial negotiation in progress",
+				i, ENCTYPE_NAME(type));
+		}
+		if (i)
+			return;
+	}
+	p = str_start + 3;
+	*p++ = ENCRYPT_START;
+	for (i = 0; i < ki[0].keylen; ++i) {
+		if ((*p++ = ki[0].keyid[i]) == IAC)
+			*p++ = IAC;
+	}
+	*p++ = IAC;
+	*p++ = SE;
+	net_write(str_start, p - str_start);
+	net_encrypt();
+	printsub('>', &str_start[2], p - &str_start[2]);
+	/*
+	 * If we are already encrypting in some mode, then
+	 * encrypt the ring (which includes our request) in
+	 * the old mode, mark it all as "clear text" and then
+	 * switch to the new mode.
+	 */
+	encrypt_output = ep->output;
+	encrypt_mode = type;
+	if (encrypt_debug_mode)
+		printf(">>>%s: Started to encrypt output with type %s\r\n",
+			Name, ENCTYPE_NAME(type));
+	if (encrypt_verbose)
+		printf("[ Output is now encrypted with type %s ]\r\n",
+			ENCTYPE_NAME(type));
+}
+
+	void
+encrypt_send_end()
+{
+	if (!encrypt_output)
+		return;
+
+	str_end[3] = ENCRYPT_END;
+	net_write(str_end, sizeof(str_end));
+	net_encrypt();
+	printsub('>', &str_end[2], sizeof(str_end) - 2);
+	/*
+	 * Encrypt the output buffer now because it will not be done by
+	 * netflush...
+	 */
+	encrypt_output = 0;
+	if (encrypt_debug_mode)
+		printf(">>>%s: Output is back to clear text\r\n", Name);
+	if (encrypt_verbose)
+		printf("[ Output is now clear text ]\r\n");
+}
+
+	void
+encrypt_send_request_start()
+{
+	register unsigned char *p;
+	register int i;
+
+	p = &str_start[3];
+	*p++ = ENCRYPT_REQSTART;
+	for (i = 0; i < ki[1].keylen; ++i) {
+		if ((*p++ = ki[1].keyid[i]) == IAC)
+			*p++ = IAC;
+	}
+	*p++ = IAC;
+	*p++ = SE;
+	net_write(str_start, p - str_start);
+	printsub('>', &str_start[2], p - &str_start[2]);
+	if (encrypt_debug_mode)
+		printf(">>>%s: Request input to be encrypted\r\n", Name);
+}
+
+	void
+encrypt_send_request_end()
+{
+	str_end[3] = ENCRYPT_REQEND;
+	net_write(str_end, sizeof(str_end));
+	printsub('>', &str_end[2], sizeof(str_end) - 2);
+
+	if (encrypt_debug_mode)
+		printf(">>>%s: Request input to be clear text\r\n", Name);
+}
+
+	void
+encrypt_wait()
+{
+	if (encrypt_debug_mode)
+		printf(">>>%s: in encrypt_wait\r\n", Name);
+	if (!havesessionkey || !(I_SUPPORT_ENCRYPT & remote_supports_decrypt))
+		return;
+	while (autoencrypt && !encrypt_output)
+		if (telnet_spin())
+			return;
+}
+
+int encrypt_is_encrypting()
+{
+    if (encrypt_output && decrypt_input)
+	return 1;
+    return 0;
+}
+
+	void
+encrypt_debug(mode)
+	int mode;
+{
+	encrypt_debug_mode = mode;
+}
+
+	void
+encrypt_gen_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt, buflen;
+{
+	char tbuf[16], *cp;
+
+	cnt -= 2;
+	data += 2;
+	buf[buflen-1] = '\0';
+	buf[buflen-2] = '*';
+	buflen -= 2;;
+	for (; cnt > 0; cnt--, data++) {
+		sprintf(tbuf, " %d", *data);
+		for (cp = tbuf; *cp && buflen > 0; --buflen)
+			*buf++ = *cp++;
+		if (buflen <= 0)
+			return;
+	}
+	*buf = '\0';
+}
+
+	void
+encrypt_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt, buflen;
+{
+	Encryptions *ep;
+	register int type = data[1];
+
+	for (ep = encryptions; ep->type && ep->type != type; ep++)
+		;
+
+	if (ep->printsub)
+		(*ep->printsub)(data, cnt, buf, buflen);
+	else
+		encrypt_gen_printsub(data, cnt, buf, buflen);
+}
+#else	/* ENCRYPTION */
+#include "misc-proto.h"
+#endif	/* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/libtelnet/encrypt.h b/mechglue/src/appl/telnet/libtelnet/encrypt.h
new file mode 100644
index 000000000..4efac570b
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/encrypt.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)encrypt.h	8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef	ENCRYPTION
+# ifndef __ENCRYPTION__
+# define __ENCRYPTION__
+
+#define	DIR_DECRYPT		1
+#define	DIR_ENCRYPT		2
+
+typedef	unsigned char Block[8];
+typedef unsigned char *BlockT;
+typedef struct { Block _; } Schedule[16];
+
+#define	VALIDKEY(key)	( key[0] | key[1] | key[2] | key[3] | \
+			  key[4] | key[5] | key[6] | key[7])
+
+#define	SAMEKEY(k1, k2)	(!memcmp((void *)k1, (void *)k2, sizeof(Block)))
+
+typedef	struct {
+	short		type;
+	int		length;
+	unsigned char	*data;
+} Session_Key;
+
+typedef struct {
+	char	*name;
+	int	type;
+	void	(*output) (unsigned char *, int);
+	int	(*input) (int);
+	void	(*init) (int);
+	int	(*start) (int, int);
+	int	(*is) (unsigned char *, int);
+	int	(*reply) (unsigned char *, int);
+	void	(*session) (Session_Key *, int);
+	int	(*keyid) (int, unsigned char *, int *);
+	void	(*printsub) (unsigned char *, int, unsigned char *, int);
+} Encryptions;
+
+#define	SK_DES		1	/* Matched Kerberos v5 ENCTYPE_DES */
+
+#include "enc-proto.h"
+
+extern int encrypt_debug_mode;
+extern int (*decrypt_input) (int);
+extern void (*encrypt_output) (unsigned char *, int);
+# endif /* __ENCRYPTION__ */
+#endif /* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/libtelnet/forward.c b/mechglue/src/appl/telnet/libtelnet/forward.c
new file mode 100644
index 000000000..09d558906
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/forward.c
@@ -0,0 +1,78 @@
+/*
+ * appl/telnet/libtelnet/forward.c
+ */
+
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/* General-purpose forwarding routines. These routines may be put into */
+/* libkrb5.a to allow widespread use */ 
+
+#if defined(KERBEROS) || defined(KRB5)
+#include <stdio.h>
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+ 
+#include "krb5.h"
+#include <errno.h>
+
+#include "krb5forw.h"
+ 
+#if defined(NEED_SETENV) || defined(NEED_SETENV_PROTO)
+extern int setenv(char *, char *, int);
+#endif
+
+extern char *line;		/* see sys_term.c */
+
+/* Decode, decrypt and store the forwarded creds in the local ccache. */
+krb5_error_code
+rd_and_store_for_creds(context, auth_context, inbuf, ticket)
+    krb5_context context;
+    krb5_auth_context auth_context;
+    krb5_data *inbuf;
+    krb5_ticket *ticket;
+{
+    krb5_creds **creds;
+    krb5_error_code retval;
+    char ccname[35];
+    krb5_ccache ccache = NULL;
+
+    if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)))
+	return(retval);
+
+    sprintf(ccname, "FILE:/tmp/krb5cc_p%ld", (long) getpid());
+    setenv("KRB5CCNAME", ccname, 1);
+
+    if ((retval = krb5_cc_resolve(context, ccname, &ccache)))
+	goto cleanup;
+
+    if ((retval = krb5_cc_initialize(context, ccache, 
+				     ticket->enc_part2->client)))
+	goto cleanup;
+
+    if ((retval = krb5_cc_store_cred(context, ccache, *creds))) 
+	goto cleanup;
+
+cleanup:
+    krb5_free_creds(context, *creds);
+    return retval;
+}
+
+#endif /* defined(KRB5) && defined(FORWARD) */
diff --git a/mechglue/src/appl/telnet/libtelnet/genget.c b/mechglue/src/appl/telnet/libtelnet/genget.c
new file mode 100644
index 000000000..bc307c81f
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/genget.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)genget.c	8.1 (Berkeley) 6/4/93 */
+
+#include <ctype.h>
+#include "misc.h"
+
+#define	LOWER(x) (isupper((int) x) ? tolower((int) x) : (x))
+/*
+ * The prefix function returns 0 if *s1 is not a prefix
+ * of *s2.  If *s1 exactly matches *s2, the negative of
+ * the length is returned.  If *s1 is a prefix of *s2,
+ * the length of *s1 is returned.
+ */
+	int
+isprefix(s1, s2)
+	register char *s1, *s2;
+{
+        char *os1;
+	register char c1, c2;
+
+        if (*s1 == '\0')
+                return(-1);
+        os1 = s1;
+	c1 = *s1;
+	c2 = *s2;
+        while (LOWER(c1) == LOWER(c2)) {
+		if (c1 == '\0')
+			break;
+                c1 = *++s1;
+                c2 = *++s2;
+        }
+        return(*s1 ? 0 : (*s2 ? (s1 - os1) : (os1 - s1)));
+}
+
+static char *ambiguous;		/* special return value for command routines */
+
+	char **
+genget(name, table, stlen)
+	char	*name;		/* name to match */
+	char	**table;	/* name entry in table */
+	int	stlen;
+{
+	register char **c, **found;
+	register int n;
+
+	if (name == 0)
+	    return 0;
+
+	found = 0;
+	for (c = table; *c != 0; c = (char **)((char *)c + stlen)) {
+		if ((n = isprefix(name, *c)) == 0)
+			continue;
+		if (n < 0)		/* exact match */
+			return(c);
+		if (found)
+			return(&ambiguous);
+		found = c;
+	}
+	return(found);
+}
+
+/*
+ * Function call version of Ambiguous()
+ */
+	int
+Ambiguous(s)
+	void *s;
+{
+	return((char **)s == &ambiguous);
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/getent.c b/mechglue/src/appl/telnet/libtelnet/getent.c
new file mode 100644
index 000000000..b80439e6e
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/getent.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)getent.c	8.1 (Berkeley) 6/4/93 */
+
+#include "gettytab.h"
+
+#ifdef	HAVE_CGETENT
+static char *area;
+#endif
+
+/*ARGSUSED*/
+int
+getent(cp, name)
+char *cp, *name;
+{
+#ifdef	HAVE_CGETENT
+	char *dba[2];
+
+	dba[0] = "/etc/gettytab";
+	dba[1] = 0;
+	return((cgetent(&area, dba, name) == 0) ? 1 : 0);
+#else
+	return(0);
+#endif
+}
+
+#ifndef	SOLARIS
+/*ARGSUSED*/
+char *
+getstr(id, cpp)
+char *id, **cpp;
+{
+#ifdef	HAVE_CGETENT
+	char *answer;
+	return((cgetstr(area, id, &answer) > 0) ? answer : 0);
+#else
+	return(0);
+#endif
+}
+#endif
diff --git a/mechglue/src/appl/telnet/libtelnet/getopt.c b/mechglue/src/appl/telnet/libtelnet/getopt.c
new file mode 100644
index 000000000..d61cc3c1f
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/getopt.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1987, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)getopt.c	8.1 (Berkeley) 6/4/93 */
+
+#ifndef __STDC__
+#define const
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * get option letter from argument vector
+ */
+int	opterr = 1,		/* if error message should be printed */
+	optind = 1,		/* index into parent argv vector */
+	optopt,			/* character checked for validity */
+	optreset;		/* reset getopt */
+char	*optarg;		/* argument associated with option */
+
+#define	BADCH	(int)'?'
+#define	BADARG	(int)':'
+#define	EMSG	""
+
+int
+getopt(nargc, nargv, ostr)
+	int nargc;
+	char * const *nargv;
+	const char *ostr;
+{
+	static char *place = EMSG;		/* option letter processing */
+	register char *oli;			/* option letter list index */
+	char *p;
+
+	if (optreset || !*place) {		/* update scanning pointer */
+		optreset = 0;
+		if (optind >= nargc || *(place = nargv[optind]) != '-') {
+			place = EMSG;
+			return(-1);
+		}
+		if (place[1] && *++place == '-') {	/* found "--" */
+			++optind;
+			place = EMSG;
+			return(-1);
+		}
+	}					/* option letter okay? */
+	if ((optopt = (int)*place++) == (int)':' ||
+	    !(oli = index(ostr, optopt))) {
+		/*
+		 * if the user didn't specify '-' as an option,
+		 * assume it means EOF.
+		 */
+		if (optopt == (int)'-')
+			return(-1);
+		if (!*place)
+			++optind;
+		if (opterr && *ostr != ':') {
+			if (!(p = rindex(*nargv, '/')))
+				p = *nargv;
+			else
+				++p;
+			(void)fprintf(stderr, "%s: illegal option -- %c\n",
+			    p, optopt);
+		}
+		return(BADCH);
+	}
+	if (*++oli != ':') {			/* don't need argument */
+		optarg = NULL;
+		if (!*place)
+			++optind;
+	}
+	else {					/* need an argument */
+		if (*place)			/* no white space */
+			optarg = place;
+		else if (nargc <= ++optind) {	/* no arg */
+			place = EMSG;
+			if (!(p = rindex(*nargv, '/')))
+				p = *nargv;
+			else
+				++p;
+			if (*ostr == ':')
+				return(BADARG);
+			if (opterr)
+				(void)fprintf(stderr,
+				    "%s: option requires an argument -- %c\n",
+				    p, optopt);
+			return(BADCH);
+		}
+	 	else				/* white space */
+			optarg = nargv[optind];
+		place = EMSG;
+		++optind;
+	}
+	return(optopt);				/* dump back option letter */
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/gettytab.c b/mechglue/src/appl/telnet/libtelnet/gettytab.c
new file mode 100644
index 000000000..aaad43aad
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/gettytab.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+/* based on @(#)gettytab.c	5.1 (Berkeley) 4/29/85 */
+
+#include <ctype.h>
+
+#define	TABBUFSIZ	512
+
+static	char *tbuf;
+int	hopcount;	/* detect infinite loops in termcap, init 0 */
+char	*skip();
+char	*getstr();
+char	*decode();
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file.  Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+getent(bp, name)
+	char *bp, *name;
+{
+	register char *cp;
+	register int c;
+	register int i = 0, cnt = 0;
+	char ibuf[TABBUFSIZ];
+	char *cp2;
+	int tf;
+
+	tbuf = bp;
+	tf = open("/etc/gettytab", 0);
+	if (tf < 0)
+		return (-1);
+	for (;;) {
+		cp = bp;
+		for (;;) {
+			if (i == cnt) {
+				cnt = read(tf, ibuf, TABBUFSIZ);
+				if (cnt <= 0) {
+					close(tf);
+					return (0);
+				}
+				i = 0;
+			}
+			c = ibuf[i++];
+			if (c == '\n') {
+				if (cp > bp && cp[-1] == '\\'){
+					cp--;
+					continue;
+				}
+				break;
+			}
+			if (cp >= bp+TABBUFSIZ) {
+				write(2,"Gettytab entry too long\n", 24);
+				break;
+			} else
+				*cp++ = c;
+		}
+		*cp = 0;
+
+		/*
+		 * The real work for the match.
+		 */
+		if (namatch(name)) {
+			close(tf);
+			return(nchktc());
+		}
+	}
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+#define	MAXHOP	32
+nchktc()
+{
+	register char *p, *q;
+	char tcname[16];	/* name of similar terminal */
+	char tcbuf[TABBUFSIZ];
+	char *holdtbuf = tbuf;
+	int l;
+
+	p = tbuf + strlen(tbuf) - 2;	/* before the last colon */
+	while (*--p != ':')
+		if (p<tbuf) {
+			write(2, "Bad gettytab entry\n", 19);
+			return (0);
+		}
+	p++;
+	/* p now points to beginning of last field */
+	if (p[0] != 't' || p[1] != 'c')
+		return(1);
+	strncpy(tcname, p + 3, sizeof(tcname) - 1);
+	tcname[sizeof(tcname) - 1] = '\0';
+	q = tcname;
+	while (*q && *q != ':')
+		q++;
+	*q = 0;
+	if (++hopcount > MAXHOP) {
+		write(2, "Getty: infinite tc= loop\n", 25);
+		return (0);
+	}
+	if (getent(tcbuf, tcname) != 1)
+		return(0);
+	for (q=tcbuf; *q != ':'; q++)
+		;
+	l = p - holdtbuf + strlen(q);
+	if (l > TABBUFSIZ) {
+		write(2, "Gettytab entry too long\n", 24);
+		q[TABBUFSIZ - (p-tbuf)] = 0;
+	}
+	strcpy(p, q+1);
+	tbuf = holdtbuf;
+	return(1);
+}
+
+/*
+ * Tnamatch deals with name matching.  The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name.  The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+namatch(np)
+	char *np;
+{
+	register char *Np, *Bp;
+
+	Bp = tbuf;
+	if (*Bp == '#')
+		return(0);
+	for (;;) {
+		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+			continue;
+		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+			return (1);
+		while (*Bp && *Bp != ':' && *Bp != '|')
+			Bp++;
+		if (*Bp == 0 || *Bp == ':')
+			return (0);
+		Bp++;
+	}
+}
+
+/*
+ * Skip to the next field.  Notice that this is very dumb, not
+ * knowing about \: escapes or any such.  If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+skip(bp)
+	register char *bp;
+{
+
+	while (*bp && *bp != ':')
+		bp++;
+	if (*bp == ':')
+		bp++;
+	return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ *	li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character.  If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+long
+getnum(id)
+	char *id;
+{
+	register long i, base;
+	register char *bp = tbuf;
+
+	for (;;) {
+		bp = skip(bp);
+		if (*bp == 0)
+			return (-1);
+		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+			continue;
+		if (*bp == '@')
+			return(-1);
+		if (*bp != '#')
+			continue;
+		bp++;
+		base = 10;
+		if (*bp == '0')
+			base = 8;
+		i = 0;
+		while (isdigit(*bp))
+			i *= base, i += *bp++ - '0';
+		return (i);
+	}
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer.  Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+getflag(id)
+	char *id;
+{
+	register char *bp = tbuf;
+
+	for (;;) {
+		bp = skip(bp);
+		if (!*bp)
+			return (-1);
+		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+			if (!*bp || *bp == ':')
+				return (1);
+			else if (*bp == '!')
+				return (0);
+			else if (*bp == '@')
+				return(-1);
+		}
+	}
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ *	cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+getstr(id, area)
+	char *id, **area;
+{
+	register char *bp = tbuf;
+
+	for (;;) {
+		bp = skip(bp);
+		if (!*bp)
+			return (0);
+		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+			continue;
+		if (*bp == '@')
+			return(0);
+		if (*bp != '=')
+			continue;
+		bp++;
+		return (decode(bp, area));
+	}
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+decode(str, area)
+	register char *str;
+	char **area;
+{
+	register char *cp;
+	register int c;
+	register char *dp;
+	int i;
+
+	cp = *area;
+	while ((c = *str++) && c != ':') {
+		switch (c) {
+
+		case '^':
+			c = *str++ & 037;
+			break;
+
+		case '\\':
+			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+			c = *str++;
+nextc:
+			if (*dp++ == c) {
+				c = *dp++;
+				break;
+			}
+			dp++;
+			if (*dp)
+				goto nextc;
+			if (isdigit(c)) {
+				c -= '0', i = 2;
+				do
+					c <<= 3, c |= *str++ - '0';
+				while (--i && isdigit(*str));
+			}
+			break;
+		}
+		*cp++ = c;
+	}
+	*cp++ = 0;
+	str = *area;
+	*area = cp;
+	return (str);
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/gettytab.h b/mechglue/src/appl/telnet/libtelnet/gettytab.h
new file mode 100644
index 000000000..02e5050a8
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/gettytab.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ *	@(#)gettytab.h	5.2 (Berkeley) 1/7/86
+ */
+
+/*
+ * Getty description definitions.
+ */
+struct	gettystrs {
+	char	*field;		/* name to lookup in gettytab */
+	char	*defalt;	/* value we find by looking in defaults */
+	char	*value;		/* value that we find there */
+};
+
+struct	gettynums {
+	char	*field;		/* name to lookup */
+	long	defalt;		/* number we find in defaults */
+	long	value;		/* number we find there */
+	int	set;		/* we actually got this one */
+};
+
+struct gettyflags {
+	char	*field;		/* name to lookup */
+	char	invrt;		/* name existing in gettytab --> false */
+	char	defalt;		/* true/false in defaults */
+	char	value;		/* true/false flag */
+	char	set;		/* we found it */
+};
+
+/*
+ * String values.
+ */
+#define	NX	gettystrs[0].value
+#define	CL	gettystrs[1].value
+#define IM	gettystrs[2].value
+#define	LM	gettystrs[3].value
+#define	ER	gettystrs[4].value
+#define	KL	gettystrs[5].value
+#define	ET	gettystrs[6].value
+#define	PC	gettystrs[7].value
+#define	TT	gettystrs[8].value
+#define	EV	gettystrs[9].value
+#define	LO	gettystrs[10].value
+#define HN	gettystrs[11].value
+#define HE	gettystrs[12].value
+#define IN	gettystrs[13].value
+#define QU	gettystrs[14].value
+#define XN	gettystrs[15].value
+#define XF	gettystrs[16].value
+#define BK	gettystrs[17].value
+#define SU	gettystrs[18].value
+#define DS	gettystrs[19].value
+#define RP	gettystrs[20].value
+#define FL	gettystrs[21].value
+#define WE	gettystrs[22].value
+#define LN	gettystrs[23].value
+
+/*
+ * Numeric definitions.
+ */
+#define	IS	gettynums[0].value
+#define	OS	gettynums[1].value
+#define	SP	gettynums[2].value
+#define	ND	gettynums[3].value
+#define	CD	gettynums[4].value
+#define	TD	gettynums[5].value
+#define	FD	gettynums[6].value
+#define	BD	gettynums[7].value
+#define	TO	gettynums[8].value
+#define	F0	gettynums[9].value
+#define	F0set	gettynums[9].set
+#define	F1	gettynums[10].value
+#define	F1set	gettynums[10].set
+#define	F2	gettynums[11].value
+#define	F2set	gettynums[11].set
+#define	PF	gettynums[12].value
+
+/*
+ * Boolean values.
+ */
+#define	HT	gettyflags[0].value
+#define	NL	gettyflags[1].value
+#define	EP	gettyflags[2].value
+#define	EPset	gettyflags[2].set
+#define	OP	gettyflags[3].value
+#define	OPset	gettyflags[2].set
+#define	AP	gettyflags[4].value
+#define	APset	gettyflags[2].set
+#define	EC	gettyflags[5].value
+#define	CO	gettyflags[6].value
+#define	CB	gettyflags[7].value
+#define	CK	gettyflags[8].value
+#define	CE	gettyflags[9].value
+#define	PE	gettyflags[10].value
+#define	RW	gettyflags[11].value
+#define	XC	gettyflags[12].value
+#define	LC	gettyflags[13].value
+#define	UC	gettyflags[14].value
+#define	IG	gettyflags[15].value
+#define	PS	gettyflags[16].value
+#define	HC	gettyflags[17].value
+#define UB	gettyflags[18].value
+#define AB	gettyflags[19].value
+#define DX	gettyflags[20].value
+#define RM	gettyflags[21].value
+
+int	getent (char *, char *);
+long	getnum();
+int	getflag();
+#ifndef SOLARIS
+char	*getstr(char *, char **);
+#endif
+
+extern	struct gettyflags gettyflags[];
+extern	struct gettynums gettynums[];
+extern	struct gettystrs gettystrs[];
+extern	int hopcount;
diff --git a/mechglue/src/appl/telnet/libtelnet/herror.c b/mechglue/src/appl/telnet/libtelnet/herror.c
new file mode 100644
index 000000000..3b20f807f
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/herror.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)herror.c	8.1 (Berkeley) 6/4/93 */
+
+#include <stdio.h>
+
+char	*h_errlist[] = {
+	"Error 0",
+	"Unknown host",				/* 1 HOST_NOT_FOUND */
+	"Host name lookup failure",		/* 2 TRY_AGAIN */
+	"Unknown server error",			/* 3 NO_RECOVERY */
+	"No address associated with name",	/* 4 NO_ADDRESS */
+};
+int	h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) };
+
+int h_errno;		/* In some version of SunOS this is necessary */
+
+/*
+ * herror --
+ *	print the error indicated by the h_errno value.
+ */
+herror(s)
+	char *s;
+{
+	if (s && *s) {
+		fprintf(stderr, "%s: ", s);
+	}
+	if ((h_errno < 0) || (h_errno >= h_nerr)) {
+		fprintf(stderr, "Unknown error\n");
+	} else if (h_errno == 0) {
+#if	defined(sun)
+		fprintf(stderr, "Host unknown\n");
+#endif	/* defined(sun) */
+	} else {
+		fprintf(stderr, "%s\n", h_errlist[h_errno]);
+	}
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/kerberos.c b/mechglue/src/appl/telnet/libtelnet/kerberos.c
new file mode 100644
index 000000000..7e0d7360c
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/kerberos.c
@@ -0,0 +1,744 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)kerberos.c	8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef	KRB4
+/* this code must be compiled in the krb5 tree.  disgustingly, there
+   is code in here which declares structures which happen to mirror
+   the krb4 des structures.  I didn't want to rototill this *completely*
+   so this is how it's going to work. --marc */
+#include <krb5.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <arpa/telnet.h>
+#include <stdio.h>
+#include <des.h>        /* BSD wont include this in krb.h, so we do it here */
+#include <krb.h>
+#ifdef	__STDC__
+#include <stdlib.h>
+#endif
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include "encrypt.h"
+#include "auth.h"
+#include "misc.h"
+
+extern int auth_debug_mode;
+extern krb5_context telnet_context;
+
+int kerberos4_cksum (unsigned char *, int);
+
+static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
+			  		AUTHTYPE_KERBEROS_V4, };
+#if 0
+static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
+					TELQUAL_NAME, };
+#endif
+
+#define	KRB_AUTH	0		/* Authentication data follows */
+#define	KRB_REJECT	1		/* Rejected (reason might follow) */
+#define	KRB_ACCEPT	2		/* Accepted */
+#define	KRB_CHALLENGE	3		/* Challenge for mutual auth. */
+#define	KRB_RESPONSE	4		/* Response for mutual auth. */
+
+#define KRB_SERVICE_NAME   "rcmd"
+
+static	KTEXT_ST auth;
+static	char name[ANAME_SZ];
+static	AUTH_DAT adat = { 0 };
+#ifdef	ENCRYPTION
+static Block	session_key	= { 0 };
+static krb5_keyblock krbkey;
+static Block	challenge	= { 0 };
+#endif	/* ENCRYPTION */
+
+	static int
+Data(ap, type, d, c)
+	Authenticator *ap;
+	int type;
+	const void *d;
+	int c;
+{
+        unsigned char *p = str_data + 4;
+	const unsigned char *cd = (const unsigned char *)d;
+	size_t spaceleft = sizeof(str_data) - 4;
+	if (c == -1)
+		c = strlen((const char *)cd);
+
+        if (auth_debug_mode) {
+                printf("%s:%d: [%d] (%d)",
+                        str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+                        str_data[3],
+                        type, c);
+                printd(d, c);
+                printf("\r\n");
+        }
+	*p++ = ap->type;
+	*p++ = ap->way;
+	*p++ = type;
+	spaceleft -= 3;
+        while (c-- > 0) {
+		if ((*p++ = *cd++) == IAC) {
+			*p++ = IAC;
+			spaceleft--;
+		}
+		if ((--spaceleft < 4) && c) {
+			errno = ENOMEM;
+			return -1;
+		}
+        }
+        *p++ = IAC;
+        *p++ = SE;
+	if (str_data[3] == TELQUAL_IS)
+		printsub('>', &str_data[2], p - (&str_data[2]));
+        return(net_write(str_data, p - str_data));
+}
+
+	int
+kerberos4_init(ap, server)
+	Authenticator *ap;
+	int server;
+{
+	FILE *fp;
+
+	if (server) {
+		str_data[3] = TELQUAL_REPLY;
+		if ((fp = fopen(KEYFILE, "r")) == NULL)
+			return(0);
+		fclose(fp);
+	} else {
+		str_data[3] = TELQUAL_IS;
+	}
+
+	kerberos5_init(NULL, server);
+
+	return(1);
+}
+
+char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
+unsigned int dst_realm_sz = REALM_SZ;
+
+	int
+kerberos4_send(ap)
+	Authenticator *ap;
+{
+	KTEXT_ST kauth;
+	char instance[INST_SZ];
+	char *realm;
+	char *krb_realmofhost();
+	char *krb_get_phost();
+	CREDENTIALS cred;
+	int r;
+#ifdef ENCRYPTION
+	krb5_data data;
+	krb5_enc_data encdata;
+	krb5_error_code code;
+	krb5_keyblock rand_key;
+#endif
+
+	printf("[ Trying KERBEROS4 ... ]\r\n");	
+	if (!UserNameRequested) {
+		if (auth_debug_mode) {
+			printf("Kerberos V4: no user name supplied\r\n");
+		}
+		return(0);
+	}
+
+	memset(instance, 0, sizeof(instance));
+
+	if ((realm = krb_get_phost(RemoteHostName)))
+		strncpy(instance, realm, sizeof(instance));
+
+	instance[sizeof(instance)-1] = '\0';
+
+	realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName);
+
+	if (!realm) {
+		printf("Kerberos V4: no realm for %s\r\n", RemoteHostName);
+		return(0);
+	}
+	if ((r = krb_mk_req(&kauth, KRB_SERVICE_NAME, instance, realm, 0))) {
+		printf("mk_req failed: %s\r\n", krb_get_err_text(r));
+		return(0);
+	}
+	if ((r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred))) {
+		printf("get_cred failed: %s\r\n", krb_get_err_text(r));
+		return(0);
+	}
+	if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
+		if (auth_debug_mode)
+			printf("Not enough room for user name\r\n");
+		return(0);
+	}
+	if (auth_debug_mode)
+		printf("Sent %d bytes of authentication data\r\n", kauth.length);
+	if (!Data(ap, KRB_AUTH, (void *)kauth.dat, kauth.length)) {
+		if (auth_debug_mode)
+			printf("Not enough room for authentication data\r\n");
+		return(0);
+	}
+#ifdef	ENCRYPTION
+	/*
+	 * If we are doing mutual authentication, get set up to send
+	 * the challenge, and verify it when the response comes back.
+	 */
+	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+		register int i;
+
+		data.data = cred.session;
+		data.length = 8; /* sizeof(cred.session) */;
+
+		if ((code = krb5_c_random_seed(telnet_context, &data))) {
+		    com_err("libtelnet", code,
+			    "while seeding random number generator");
+		    return(0);
+		}
+
+		if ((code = krb5_c_make_random_key(telnet_context,
+						   ENCTYPE_DES_CBC_RAW,
+						   &rand_key))) {
+		    com_err("libtelnet", code,
+			    "while creating random session key");
+		    return(0);
+		}
+
+		/* the krb4 code uses ecb mode, but on a single block
+		   with a zero ivec, ecb and cbc are the same */
+		krbkey.enctype = ENCTYPE_DES_CBC_RAW;
+		krbkey.length = 8;
+		krbkey.contents = cred.session;
+
+		encdata.ciphertext.data = rand_key.contents;
+		encdata.ciphertext.length = rand_key.length;
+		encdata.enctype = ENCTYPE_UNKNOWN;
+
+		data.data = session_key;
+		data.length = 8;
+
+		code = krb5_c_decrypt(telnet_context, &krbkey, 0, 0,
+				      &encdata, &data);
+
+		krb5_free_keyblock_contents(telnet_context, &rand_key);
+
+		if (code) {
+		    com_err("libtelnet", code, "while encrypting random key");
+		    return(0);
+		}
+
+		encdata.ciphertext.data = session_key;
+		encdata.ciphertext.length = 8;
+		encdata.enctype = ENCTYPE_UNKNOWN;
+
+		data.data = challenge;
+		data.length = 8;
+
+		code = krb5_c_decrypt(telnet_context, &krbkey, 0, 0,
+				      &encdata, &data);
+
+		/*
+		 * Increment the challenge by 1, and encrypt it for
+		 * later comparison.
+		 */
+		for (i = 7; i >= 0; --i) {
+			register int x;
+			x = (unsigned int)challenge[i] + 1;
+			challenge[i] = x;	/* ignore overflow */
+			if (x < 256)		/* if no overflow, all done */
+				break;
+		}
+
+		data.data = challenge;
+		data.length = 8;
+
+		encdata.ciphertext.data = challenge;
+		encdata.ciphertext.length = 8;
+		encdata.enctype = ENCTYPE_UNKNOWN;
+
+		if ((code = krb5_c_encrypt(telnet_context, &krbkey, 0, 0, 
+					   &data, &encdata))) {
+		    com_err("libtelnet", code, "while encrypting random key");
+		    return(0);
+		}
+	}
+#endif	/* ENCRYPTION */
+	
+	if (auth_debug_mode) {
+		printf("CK: %d:", kerberos4_cksum(kauth.dat, kauth.length));
+		printd(kauth.dat, kauth.length);
+		printf("\r\n");
+		printf("Sent Kerberos V4 credentials to server\r\n");
+	}
+	return(1);
+}
+
+	void
+kerberos4_is(ap, data, cnt)
+	Authenticator *ap;
+	unsigned char *data;
+	int cnt;
+{
+#ifdef	ENCRYPTION
+	Session_Key skey;
+	Block datablock, tmpkey;
+	krb5_data kdata;
+	krb5_enc_data encdata;
+	krb5_error_code code;
+#endif	/* ENCRYPTION */
+	char realm[REALM_SZ];
+	char instance[INST_SZ];
+	int r;
+
+	if (cnt-- < 1)
+		return;
+	switch (*data++) {
+	case KRB_AUTH:
+		if (krb_get_lrealm(realm, 1) != KSUCCESS) {
+			Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1);
+			auth_finished(ap, AUTH_REJECT);
+			if (auth_debug_mode)
+				printf("No local realm\r\n");
+			return;
+		}
+		memcpy((void *)auth.dat, (void *)data, auth.length = cnt);
+		if (auth_debug_mode) {
+			printf("Got %d bytes of authentication data\r\n", cnt);
+			printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
+			printd(auth.dat, auth.length);
+			printf("\r\n");
+		}
+		instance[0] = '*'; instance[1] = 0;
+		if ((r = krb_rd_req(&auth, KRB_SERVICE_NAME,
+				    instance, 0, &adat, ""))) {
+			if (auth_debug_mode)
+				printf("Kerberos failed him as %s\r\n", name);
+			Data(ap, KRB_REJECT, (const void *)krb_get_err_text(r), -1);
+			auth_finished(ap, AUTH_REJECT);
+			return;
+		}
+#ifdef	ENCRYPTION
+		memcpy((void *)session_key, (void *)adat.session, sizeof(Block));
+#endif	/* ENCRYPTION */
+		krb_kntoln(&adat, name);
+
+		if (UserNameRequested && !kuserok(&adat, UserNameRequested))
+			Data(ap, KRB_ACCEPT, (void *)0, 0);
+		else
+			Data(ap, KRB_REJECT,
+				(void *)"user is not authorized", -1);
+		auth_finished(ap, AUTH_USER);
+		break;
+
+	case KRB_CHALLENGE:
+#ifndef	ENCRYPTION
+		Data(ap, KRB_RESPONSE, (void *)0, 0);
+#else	/* ENCRYPTION */
+		if (!VALIDKEY(session_key)) {
+			/*
+			 * We don't have a valid session key, so just
+			 * send back a response with an empty session
+			 * key.
+			 */
+			Data(ap, KRB_RESPONSE, (void *)0, 0);
+			break;
+		}
+
+		/*
+		 * Initialize the random number generator since it's
+		 * used later on by the encryption routine.
+		 */
+
+		kdata.data = session_key;
+		kdata.length = 8;
+
+		if ((code = krb5_c_random_seed(telnet_context, &kdata))) {
+		    com_err("libtelnet", code,
+			    "while seeding random number generator");
+		    return;
+		}
+
+		memcpy((void *)datablock, (void *)data, sizeof(Block));
+		/*
+		 * Take the received encrypted challenge, and encrypt
+		 * it again to get a unique session_key for the
+		 * ENCRYPT option.
+		 */
+		krbkey.enctype = ENCTYPE_DES_CBC_RAW;
+		krbkey.length = 8;
+		krbkey.contents = session_key;
+
+		kdata.data = datablock;
+		kdata.length = 8;
+
+		encdata.ciphertext.data = tmpkey;
+		encdata.ciphertext.length = 8;
+		encdata.enctype = ENCTYPE_UNKNOWN;
+
+		if ((code = krb5_c_encrypt(telnet_context, &krbkey, 0, 0,
+					   &kdata, &encdata))) {
+		    com_err("libtelnet", code, "while encrypting random key");
+		    return;
+		}
+
+		skey.type = SK_DES;
+		skey.length = 8;
+		skey.data = tmpkey;
+		encrypt_session_key(&skey, 1);
+		/*
+		 * Now decrypt the received encrypted challenge,
+		 * increment by one, re-encrypt it and send it back.
+		 */
+		encdata.ciphertext.data = datablock;
+		encdata.ciphertext.length = 8;
+		encdata.enctype = ENCTYPE_UNKNOWN;
+
+		kdata.data = challenge;
+		kdata.length = 8;
+
+		if ((code = krb5_c_decrypt(telnet_context, &krbkey, 0, 0, 
+					   &encdata, &kdata))) {
+		    com_err("libtelnet", code, "while decrypting challenge");
+		    return;
+		}
+
+		for (r = 7; r >= 0; r--) {
+			register int t;
+			t = (unsigned int)challenge[r] + 1;
+			challenge[r] = t;	/* ignore overflow */
+			if (t < 256)		/* if no overflow, all done */
+				break;
+		}
+
+		kdata.data = challenge;
+		kdata.length = 8;
+
+		encdata.ciphertext.data = challenge;
+		encdata.ciphertext.length = 8;
+		encdata.enctype = ENCTYPE_UNKNOWN;
+
+		if ((code = krb5_c_encrypt(telnet_context, &krbkey, 0, 0,
+					   &kdata, &encdata))) {
+		    com_err("libtelnet", code, "while decrypting challenge");
+		    return;
+		}
+
+		Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge));
+#endif	/* ENCRYPTION */
+		break;
+
+	default:
+		if (auth_debug_mode)
+			printf("Unknown Kerberos option %d\r\n", data[-1]);
+		Data(ap, KRB_REJECT, 0, 0);
+		break;
+	}
+}
+
+	void
+kerberos4_reply(ap, data, cnt)
+	Authenticator *ap;
+	unsigned char *data;
+	int cnt;
+{
+#ifdef	ENCRYPTION
+	Session_Key skey;
+	krb5_data kdata;
+	krb5_enc_data encdata;
+	krb5_error_code code;
+
+#endif	/* ENCRYPTION */
+
+	if (cnt-- < 1)
+		return;
+	switch (*data++) {
+	case KRB_REJECT:
+		if (cnt > 0) {
+			printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n",
+				cnt, data);
+		} else
+			printf("[ Kerberos V4 refuses authentication ]\r\n");
+		auth_send_retry();
+		return;
+	case KRB_ACCEPT:
+		printf("[ Kerberos V4 accepts you ]\r\n");
+		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+			/*
+			 * Send over the encrypted challenge.
+		 	 */
+#ifndef	ENCRYPTION
+			Data(ap, KRB_CHALLENGE, (void *)0, 0);
+#else	/* ENCRYPTION */
+			Data(ap, KRB_CHALLENGE, (void *)session_key,
+						sizeof(session_key));
+
+			kdata.data = session_key;
+			kdata.length = 8;
+
+			encdata.ciphertext.data = session_key;
+			encdata.ciphertext.length = 8;
+			encdata.enctype = ENCTYPE_UNKNOWN;
+
+			if ((code = krb5_c_encrypt(telnet_context, &krbkey,
+						   0, 0, &kdata, &encdata))) {
+				com_err("libtelnet", code,
+					"while encrypting session_key");
+				return;
+			}
+
+			skey.type = SK_DES;
+			skey.length = 8;
+			skey.data = session_key;
+			encrypt_session_key(&skey, 0);
+#endif	/* ENCRYPTION */
+			return;
+		}
+		auth_finished(ap, AUTH_USER);
+		return;
+	case KRB_RESPONSE:
+#ifdef	ENCRYPTION
+		/*
+		 * Verify that the response to the challenge is correct.
+		 */
+		if ((cnt != sizeof(Block)) ||
+		    (0 != memcmp((void *)data, (void *)challenge,
+						sizeof(challenge))))
+		{
+#endif	/* ENCRYPTION */
+			printf("[ Kerberos V4 challenge failed!!! ]\r\n");
+			auth_send_retry();
+			return;
+#ifdef	ENCRYPTION
+		}
+		printf("[ Kerberos V4 challenge successful ]\r\n");
+		auth_finished(ap, AUTH_USER);
+#endif	/* ENCRYPTION */
+		break;
+	default:
+		if (auth_debug_mode)
+			printf("Unknown Kerberos option %d\r\n", data[-1]);
+		return;
+	}
+}
+
+	int
+kerberos4_status(ap, kname, level)
+	Authenticator *ap;
+	char *kname;
+	int level;
+{
+	if (level < AUTH_USER)
+		return(level);
+
+	/*
+	 * Always copy in UserNameRequested if the authentication
+	 * is valid, because the higher level routines need it.
+	 */
+	if (UserNameRequested) {
+		/* the name buffer comes from telnetd/telnetd{-ktd}.c */
+		strncpy(kname, UserNameRequested, 255);
+		kname[255] = '\0';
+	}
+
+	if (UserNameRequested && !kuserok(&adat, UserNameRequested)) {
+		return(AUTH_VALID);
+	} else
+		return(AUTH_USER);
+}
+
+#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
+#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+	void
+kerberos4_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt;
+	unsigned int buflen;
+{
+	char lbuf[32];
+	register int i;
+
+	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
+	buflen -= 1;
+
+	switch(data[3]) {
+	case KRB_REJECT:		/* Rejected (reason might follow) */
+		strncpy((char *)buf, " REJECT ", buflen);
+		goto common;
+
+	case KRB_ACCEPT:		/* Accepted (name might follow) */
+		strncpy((char *)buf, " ACCEPT ", buflen);
+	common:
+		BUMP(buf, buflen);
+		if (cnt <= 4)
+			break;
+		ADDC(buf, buflen, '"');
+		for (i = 4; i < cnt; i++)
+			ADDC(buf, buflen, data[i]);
+		ADDC(buf, buflen, '"');
+		ADDC(buf, buflen, '\0');
+		break;
+
+	case KRB_AUTH:			/* Authentication data follows */
+		strncpy((char *)buf, " AUTH", buflen);
+		goto common2;
+
+	case KRB_CHALLENGE:
+		strncpy((char *)buf, " CHALLENGE", buflen);
+		goto common2;
+
+	case KRB_RESPONSE:
+		strncpy((char *)buf, " RESPONSE", buflen);
+		goto common2;
+
+	default:
+		sprintf(lbuf, " %d (unknown)", data[3]);
+		strncpy((char *)buf, lbuf, buflen);
+	common2:
+		BUMP(buf, buflen);
+		for (i = 4; i < cnt; i++) {
+			sprintf(lbuf, " %d", data[i]);
+			strncpy((char *)buf, lbuf, buflen);
+			BUMP(buf, buflen);
+		}
+		break;
+	}
+}
+
+	int
+kerberos4_cksum(d, n)
+	unsigned char *d;
+	int n;
+{
+	int ck = 0;
+
+	/*
+	 * A comment is probably needed here for those not
+	 * well versed in the "C" language.  Yes, this is
+	 * supposed to be a "switch" with the body of the
+	 * "switch" being a "while" statement.  The whole
+	 * purpose of the switch is to allow us to jump into
+	 * the middle of the while() loop, and then not have
+	 * to do any more switch()s.
+	 *
+	 * Some compilers will spit out a warning message
+	 * about the loop not being entered at the top.
+	 */
+	switch (n&03)
+	while (n > 0) {
+	case 0:
+		ck ^= (int)*d++ << 24;
+		--n;
+	case 3:
+		ck ^= (int)*d++ << 16;
+		--n;
+	case 2:
+		ck ^= (int)*d++ << 8;
+		--n;
+	case 1:
+		ck ^= (int)*d++;
+		--n;
+	}
+	return(ck);
+}
+#else
+#include <krb5.h>
+#include <errno.h>
+
+#endif
+
+#ifdef notdef
+
+prkey(msg, key)
+	char *msg;
+	unsigned char *key;
+{
+	register int i;
+	printf("%s:", msg);
+	for (i = 0; i < 8; i++)
+		printf(" %3d", key[i]);
+	printf("\r\n");
+}
+#endif
diff --git a/mechglue/src/appl/telnet/libtelnet/kerberos5.c b/mechglue/src/appl/telnet/libtelnet/kerberos5.c
new file mode 100644
index 000000000..ad36aedda
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/kerberos5.c
@@ -0,0 +1,898 @@
+/*
+ *	appl/telnet/libtelnet/kerberos5.c
+ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)kerberos5.c	8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#ifdef	KRB5
+#include <arpa/telnet.h>
+#include <errno.h>
+#include <stdio.h>
+#include "krb5.h"
+
+#include "com_err.h"
+#include <netdb.h>
+#include <ctype.h>
+#include <syslog.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc();
+#endif
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+ 
+#include "encrypt.h"
+#include "auth.h"
+#include "misc.h"
+
+extern int auth_debug_mode;
+extern int net;
+
+#ifdef	FORWARD
+int forward_flags = 0;  /* Flags get set in telnet/main.c on -f and -F */
+
+static void kerberos5_forward(Authenticator *);
+
+#include "krb5forw.h"
+
+#endif	/* FORWARD */
+
+static unsigned char str_data[8192] = {IAC, SB, TELOPT_AUTHENTICATION, 0,
+			  		AUTHTYPE_KERBEROS_V5, };
+/*static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
+					TELQUAL_NAME, };*/
+
+#define	KRB_AUTH		0	/* Authentication data follows */
+#define	KRB_REJECT		1	/* Rejected (reason might follow) */
+#define	KRB_ACCEPT		2	/* Accepted */
+#define	KRB_RESPONSE		3	/* Response for mutual auth. */
+
+#ifdef	FORWARD
+#define KRB_FORWARD     	4       /* Forwarded credentials follow */
+#define KRB_FORWARD_ACCEPT     	5       /* Forwarded credentials accepted */
+#define KRB_FORWARD_REJECT     	6       /* Forwarded credentials rejected */
+#endif	/* FORWARD */
+
+krb5_auth_context auth_context = 0;
+
+static	krb5_data auth;
+	/* telnetd gets session key from here */
+static	krb5_ticket * ticket = NULL;
+/* telnet matches the AP_REQ and AP_REP with this */
+
+/* some compilers can't hack void *, so we use the Kerberos krb5_pointer,
+   which is either void * or char *, depending on the compiler. */
+
+#define Voidptr krb5_pointer
+
+krb5_keyblock	*session_key = 0;
+char *		telnet_srvtab = NULL;
+char *		telnet_krb5_realm = NULL;
+
+	static int
+Data(ap, type, d, c)
+	Authenticator *ap;
+	int type;
+	Voidptr d;
+	int c;
+{
+        unsigned char *p = str_data + 4;
+	unsigned char *cd = (unsigned char *)d;
+	size_t spaceleft = sizeof(str_data) - 4;
+
+	if (c == -1)
+		c = strlen((char *)cd);
+
+        if (auth_debug_mode) {
+                printf("%s:%d: [%d] (%d)",
+                        str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+                        str_data[3],
+                        type, c);
+                printd(d, c);
+                printf("\r\n");
+        }
+	*p++ = ap->type;
+	*p++ = ap->way;
+	*p++ = type;
+	spaceleft -= 3;
+        while (c-- > 0) {
+		if ((*p++ = *cd++) == IAC) {
+			*p++ = IAC;
+			spaceleft--;
+		}
+		if ((--spaceleft < 4) && c) {
+			errno = ENOMEM;
+			return -1;
+		}
+        }
+        *p++ = IAC;
+        *p++ = SE;
+	if (str_data[3] == TELQUAL_IS)
+		printsub('>', &str_data[2], p - &str_data[2]);
+        return(net_write(str_data, p - str_data));
+}
+
+krb5_context telnet_context = 0;
+int
+kerberos5_init(ap, server)
+	Authenticator *ap;
+	int server;
+{
+	krb5_error_code retval;
+	
+	if (server)
+		str_data[3] = TELQUAL_REPLY;
+	else
+		str_data[3] = TELQUAL_IS;
+	if (telnet_context == 0) {
+		retval = krb5_init_context(&telnet_context);
+		if (retval)
+			return 0;
+	}
+	return(1);
+}
+
+void
+kerberos5_cleanup()
+{
+    krb5_error_code retval;
+    krb5_ccache ccache;
+    char *ccname;
+    
+    if (telnet_context == 0)
+	return;
+
+    ccname = getenv("KRB5CCNAME");
+    if (ccname) {
+	retval = krb5_cc_resolve(telnet_context, ccname, &ccache);
+	if (!retval)
+	    retval = krb5_cc_destroy(telnet_context, ccache);
+    }
+
+    krb5_free_context(telnet_context);
+    telnet_context = 0;
+}
+
+
+	int
+kerberos5_send(ap)
+	Authenticator *ap;
+{
+	krb5_error_code r;
+	krb5_ccache ccache;
+	krb5_creds creds;		/* telnet gets session key from here */
+	krb5_creds * new_creds = 0;
+	int ap_opts;
+	char type_check[2];
+	krb5_data check_data;
+
+#ifdef	ENCRYPTION
+	krb5_keyblock *newkey = 0;
+#endif	/* ENCRYPTION */
+
+        if (!UserNameRequested) {
+                if (auth_debug_mode) {
+                        printf(
+			"telnet: Kerberos V5: no user name supplied\r\n");
+                }
+                return(0);
+        }
+
+	if ((r = krb5_cc_default(telnet_context, &ccache))) {
+		if (auth_debug_mode) {
+		    printf(
+		    "telnet: Kerberos V5: could not get default ccache\r\n");
+		}
+		return(0);
+	}
+
+	memset((char *)&creds, 0, sizeof(creds));
+	if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName,
+					 "host", KRB5_NT_SRV_HST,
+					 &creds.server))) {
+	    if (auth_debug_mode)
+		printf("telnet: Kerberos V5: error while constructing service name: %s\r\n", error_message(r));
+	    return(0);
+	}
+
+	if (telnet_krb5_realm != NULL) {
+	    krb5_data rdata;
+
+	    rdata.length = strlen(telnet_krb5_realm);
+	    rdata.data = (char *) malloc(rdata.length + 1);
+	    if (rdata.data == NULL) {
+	        fprintf(stderr, "malloc failed\n");
+		return(0);
+	    }
+	    strcpy(rdata.data, telnet_krb5_realm);
+	    krb5_princ_set_realm(telnet_context, creds.server, &rdata);
+	}
+
+	if ((r = krb5_cc_get_principal(telnet_context, ccache,
+				       &creds.client))) {
+		if (auth_debug_mode) {
+			printf(
+			"telnet: Kerberos V5: failure on principal (%s)\r\n",
+				error_message(r));
+		}
+		krb5_free_cred_contents(telnet_context, &creds);
+		return(0);
+	}
+
+	creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC;
+	if ((r = krb5_get_credentials(telnet_context, 0,
+				      ccache, &creds, &new_creds))) {
+		if (auth_debug_mode) {
+			printf(
+			"telnet: Kerberos V5: failure on credentials(%s)\r\n",
+			       error_message(r));
+		}
+		krb5_free_cred_contents(telnet_context, &creds);
+		return(0);
+	}
+
+	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+	    ap_opts = AP_OPTS_MUTUAL_REQUIRED;
+	else
+	    ap_opts = 0;
+
+#ifdef ENCRYPTION
+	ap_opts |= AP_OPTS_USE_SUBKEY;
+#endif	/* ENCRYPTION */
+	    
+	if (auth_context) {
+	    krb5_auth_con_free(telnet_context, auth_context);
+	    auth_context = 0;
+	}
+	if ((r = krb5_auth_con_init(telnet_context, &auth_context))) {
+	    if (auth_debug_mode) {
+		printf("Kerberos V5: failed to init auth_context (%s)\r\n",
+		       error_message(r));
+	    }
+	    return(0);
+	}
+	
+	krb5_auth_con_setflags(telnet_context, auth_context,
+			       KRB5_AUTH_CONTEXT_RET_TIME);
+	
+	type_check[0] = ap->type;
+	type_check[1] = ap->way;
+	check_data.magic = KV5M_DATA;
+	check_data.length = 2;
+	check_data.data = (char *) &type_check;
+
+	r = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts,
+				 &check_data, new_creds, &auth);
+
+#ifdef	ENCRYPTION
+	krb5_auth_con_getsendsubkey(telnet_context, auth_context, &newkey);
+	if (session_key) {
+		krb5_free_keyblock(telnet_context, session_key);
+		session_key = 0;
+	}
+
+	if (newkey) {
+	    /* keep the key in our private storage, but don't use it
+	       yet---see kerberos5_reply() below */
+	    if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) &&
+		(newkey-> enctype != ENCTYPE_DES_CBC_MD5)) {
+		if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) ||
+		    (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5))
+		    /* use the session key in credentials instead */
+		    krb5_copy_keyblock(telnet_context,&new_creds->keyblock,
+				       &session_key);
+		else
+		    /* XXX ? */;
+	    } else {
+		krb5_copy_keyblock(telnet_context, newkey, &session_key);
+	    }
+	    krb5_free_keyblock(telnet_context, newkey);
+	}
+#endif	/* ENCRYPTION */
+	krb5_free_cred_contents(telnet_context, &creds);
+	krb5_free_creds(telnet_context, new_creds);
+	if (r) {
+		if (auth_debug_mode) {
+			printf("telnet: Kerberos V5: mk_req failed (%s)\r\n",
+			       error_message(r));
+		}
+		return(0);
+	}
+
+        if (!auth_sendname((unsigned char *) UserNameRequested, 
+			   (int) strlen(UserNameRequested))) {
+                if (auth_debug_mode)
+                        printf("telnet: Not enough room for user name\r\n");
+                return(0);
+        }
+	if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
+		if (auth_debug_mode)
+		    printf(
+		    "telnet: Not enough room for authentication data\r\n");
+		return(0);
+	}
+	if (auth_debug_mode) {
+		printf("telnet: Sent Kerberos V5 credentials to server\r\n");
+	}
+	return(1);
+}
+
+	void
+kerberos5_is(ap, data, cnt)
+	Authenticator *ap;
+	unsigned char *data;
+	int cnt;
+{
+	int r = 0;
+	krb5_principal server;
+	krb5_keyblock *newkey = NULL;
+	krb5_keytab keytabid = 0;
+	krb5_data outbuf;
+#ifdef ENCRYPTION
+	Session_Key skey;
+#endif
+	char errbuf[320];
+	char *name;
+	char *getenv();
+	krb5_data inbuf;
+	krb5_authenticator *authenticator;
+
+	if (cnt-- < 1)
+		return;
+	switch (*data++) {
+	case KRB_AUTH:
+		auth.data = (char *)data;
+		auth.length = cnt;
+
+		if (!r && !auth_context)
+		    r = krb5_auth_con_init(telnet_context, &auth_context);
+		if (!r) {
+		    krb5_rcache rcache;
+		    
+		    r = krb5_auth_con_getrcache(telnet_context, auth_context,
+						&rcache);
+		    if (!r && !rcache) {
+			r = krb5_sname_to_principal(telnet_context, 0, 0,
+						    KRB5_NT_SRV_HST, &server);
+			if (!r) {
+			    r = krb5_get_server_rcache(telnet_context,
+					krb5_princ_component(telnet_context,
+							     server, 0),
+						       &rcache);
+			    krb5_free_principal(telnet_context, server);
+			}
+		    }
+		    if (!r)
+			r = krb5_auth_con_setrcache(telnet_context,
+						    auth_context, rcache);
+		}
+		if (!r && telnet_srvtab)
+		    r = krb5_kt_resolve(telnet_context, 
+					telnet_srvtab, &keytabid);
+		if (!r)
+		    r = krb5_rd_req(telnet_context, &auth_context, &auth,
+				    NULL, keytabid, NULL, &ticket);
+		if (r) {
+			(void) strcpy(errbuf, "krb5_rd_req failed: ");
+			errbuf[sizeof(errbuf) - 1] = '\0';
+			(void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+			goto errout;
+		}
+
+		/*
+		 * 256 bytes should be much larger than any reasonable
+		 * first component of a service name especially since
+		 * the default is of length 4.
+		 */
+		if (krb5_princ_size(telnet_context,ticket->server) < 1) {
+		    (void) strcpy(errbuf, "malformed service name");
+		    goto errout;
+		}
+		if (krb5_princ_component(telnet_context,ticket->server,0)->length < 256) {
+		    char princ[256];
+		    strncpy(princ,	
+			    krb5_princ_component(telnet_context, ticket->server,0)->data,
+			    krb5_princ_component(telnet_context, ticket->server,0)->length);
+		    princ[krb5_princ_component(telnet_context, 
+					       ticket->server,0)->length] = '\0';
+		    if (strcmp("host", princ)) {
+                        if(strlen(princ) < sizeof(errbuf) - 39) {
+                            (void) sprintf(errbuf, "incorrect service name: \"%s\" != \"host\"",
+                                           princ);
+                        } else {
+                            (void) sprintf(errbuf, "incorrect service name: principal != \"host\"");
+                        }
+			goto errout;
+		    }
+		} else {
+		    (void) strcpy(errbuf, "service name too long");
+		    goto errout;
+		}
+
+		r = krb5_auth_con_getauthenticator(telnet_context,
+						   auth_context,
+						   &authenticator);
+		if (r) {
+		    (void) strcpy(errbuf,
+				  "krb5_auth_con_getauthenticator failed: ");
+		    errbuf[sizeof(errbuf) - 1] = '\0';
+		    (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+		    goto errout;
+		}
+		if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON &&
+		    !authenticator->checksum) {
+			(void) strcpy(errbuf,
+				"authenticator is missing required checksum");
+			goto errout;
+		}
+		if (authenticator->checksum) {
+		    char type_check[2];
+		    krb5_checksum *cksum = authenticator->checksum;
+		    krb5_keyblock *key;
+
+		    type_check[0] = ap->type;
+		    type_check[1] = ap->way;
+
+		    r = krb5_auth_con_getkey(telnet_context, auth_context,
+					     &key);
+		    if (r) {
+			(void) strcpy(errbuf, "krb5_auth_con_getkey failed: ");
+			errbuf[sizeof(errbuf) - 1] = '\0';
+			(void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+			goto errout;
+		    }
+		    r = krb5_verify_checksum(telnet_context,
+					     cksum->checksum_type, cksum,
+					     &type_check, 2, key->contents,
+					     key->length);
+		/*
+		 * Note that krb5_verify_checksum() will fail if a pre-
+		 * MIT Kerberos Beta 5 client is attempting to connect
+		 * to this server (Beta 6 or later). There is not way to
+		 * fix this without compromising encryption. It would be
+		 * reasonable to add a -i option to telnetd to ignore
+		 * checksums (like in klogind). Such an option is not
+		 * present at this time.
+		 */
+		    if (r) {
+			(void) strcpy(errbuf,
+				      "checksum verification failed: ");
+		        errbuf[sizeof(errbuf) - 1] = '\0';
+			(void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+			goto errout;
+		    }
+		    krb5_free_keyblock(telnet_context, key);
+		}
+		krb5_free_authenticator(telnet_context, authenticator);
+		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+		    /* do ap_rep stuff here */
+		    if ((r = krb5_mk_rep(telnet_context, auth_context,
+					 &outbuf))) {
+			(void) strcpy(errbuf, "Make reply failed: ");
+		        errbuf[sizeof(errbuf) - 1] = '\0';
+			(void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf));
+			goto errout;
+		    }
+
+		    Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
+		} 
+		if (krb5_unparse_name(telnet_context, 
+				      ticket->enc_part2 ->client,
+				      &name))
+			name = 0;
+		Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
+		if (auth_debug_mode) {
+			printf(
+			"telnetd: Kerberos5 identifies him as ``%s''\r\n",
+							name ? name : "");
+		}
+                auth_finished(ap, AUTH_USER);
+		
+		if (name)
+		    free(name);
+		krb5_auth_con_getrecvsubkey(telnet_context, auth_context,
+					      &newkey);
+		if (session_key) {
+		    krb5_free_keyblock(telnet_context, session_key);
+		    session_key = 0;
+		}
+	    	if (newkey) {
+		    krb5_copy_keyblock(telnet_context, newkey, &session_key);
+		    krb5_free_keyblock(telnet_context, newkey);
+		} else {
+		    krb5_copy_keyblock(telnet_context,
+				       ticket->enc_part2->session,
+				       &session_key);
+		}
+		
+#ifdef ENCRYPTION
+		skey.type = SK_DES;
+		skey.length = 8;
+		skey.data = session_key->contents;
+		encrypt_session_key(&skey, 1);
+#endif
+		break;
+#ifdef	FORWARD
+	case KRB_FORWARD:
+		inbuf.length = cnt;
+		inbuf.data = (char *)data;
+		if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context, 
+			net, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) || 
+		    (r = rd_and_store_for_creds(telnet_context, auth_context,
+			   &inbuf, ticket))) {
+
+		    char kerrbuf[128];
+		    
+		    (void) strcpy(kerrbuf, "Read forwarded creds failed: ");
+		    kerrbuf[sizeof(kerrbuf) - 1] = '\0';
+		    (void) strncat(kerrbuf, error_message(r), 
+			sizeof(kerrbuf) - 1 - strlen(kerrbuf));
+		    Data(ap, KRB_FORWARD_REJECT, kerrbuf, -1);
+		    if (auth_debug_mode)
+		      printf(
+			"telnetd: Could not read forwarded credentials\r\n");
+		}
+		else 
+		  Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
+		  if (auth_debug_mode)
+		    printf("telnetd: Forwarded credentials obtained\r\n");
+		break;
+#endif	/* FORWARD */
+	default:
+		if (auth_debug_mode)
+			printf("telnetd: Unknown Kerberos option %d\r\n",
+			data[-1]);
+		Data(ap, KRB_REJECT, 0, 0);
+		break;
+	}
+	return;
+	
+    errout:
+	{
+	    char eerrbuf[329];
+
+	    strcpy(eerrbuf, "telnetd: ");
+	    eerrbuf[sizeof(eerrbuf) - 1] = '\0';
+	    strncat(eerrbuf, errbuf, sizeof(eerrbuf) - 1 - strlen(eerrbuf));
+	    Data(ap, KRB_REJECT, eerrbuf, -1);
+	}
+	if (auth_debug_mode)
+	    printf("telnetd: %s\r\n", errbuf);
+	syslog(LOG_ERR, "%s", errbuf);
+	if (auth_context) {
+	    krb5_auth_con_free(telnet_context, auth_context);
+	    auth_context = 0;
+	}
+	return;
+}
+
+	void
+kerberos5_reply(ap, data, cnt)
+	Authenticator *ap;
+	unsigned char *data;
+	int cnt;
+{
+#ifdef ENCRYPTION
+        Session_Key skey;
+#endif
+	static int mutual_complete = 0;
+
+	if (cnt-- < 1)
+		return;
+	switch (*data++) {
+	case KRB_REJECT:
+		if (cnt > 0) {
+			printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
+				cnt, data);
+		} else
+			printf("[ Kerberos V5 refuses authentication ]\r\n");
+		auth_send_retry();
+		return;
+	case KRB_ACCEPT:
+		if (!mutual_complete) {
+		    if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+			printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
+			auth_send_retry();
+			return;
+		    }
+#ifdef	ENCRYPTION
+		    if (session_key) {
+			skey.type = SK_DES;
+			skey.length = 8;
+			skey.data = session_key->contents;
+			encrypt_session_key(&skey, 0);
+		    }
+#endif	/* ENCRYPTION */
+		}
+		if (cnt)
+		    printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
+		else
+		    printf("[ Kerberos V5 accepts you ]\r\n");
+		auth_finished(ap, AUTH_USER);
+#ifdef	FORWARD
+		if (forward_flags & OPTS_FORWARD_CREDS)
+		  kerberos5_forward(ap);
+#endif	/* FORWARD */
+		break;
+	case KRB_RESPONSE:
+		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+		    /* the rest of the reply should contain a krb_ap_rep */
+		    krb5_ap_rep_enc_part *reply;
+		    krb5_data inbuf;
+		    krb5_error_code r;
+
+		    inbuf.length = cnt;
+		    inbuf.data = (char *)data;
+
+		    if ((r = krb5_rd_rep(telnet_context, auth_context, &inbuf,
+					 &reply))) {
+			printf("[ Mutual authentication failed: %s ]\r\n",
+			       error_message(r));
+			auth_send_retry();
+			return;
+		    }
+		    krb5_free_ap_rep_enc_part(telnet_context, reply);
+#ifdef	ENCRYPTION
+		    if (session_key) {
+			skey.type = SK_DES;
+			skey.length = 8;
+			skey.data = session_key->contents;
+			encrypt_session_key(&skey, 0);
+		      }
+#endif	/* ENCRYPTION */
+		    mutual_complete = 1;
+		}
+		return;
+#ifdef	FORWARD
+	case KRB_FORWARD_ACCEPT:
+		printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
+		return;
+	case KRB_FORWARD_REJECT:
+		printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
+				cnt, data);
+		return;
+#endif	/* FORWARD */
+	default:
+		if (auth_debug_mode)
+			printf("Unknown Kerberos option %d\r\n", data[-1]);
+		return;
+	}
+	return;
+}
+
+	int
+kerberos5_status(ap, name, level)
+	Authenticator *ap;
+	char *name;
+	int level;
+{
+	if (level < AUTH_USER)
+		return(level);
+
+	/*
+	 * Always copy in UserNameRequested if the authentication
+	 * is valid, because the higher level routines need it.
+	 * the name buffer comes from telnetd/telnetd{-ktd}.c
+	 */
+	if (UserNameRequested) {
+		strncpy(name, UserNameRequested, 255);
+		name[255] = '\0';
+	}
+
+	if (UserNameRequested &&
+	    krb5_kuserok(telnet_context, ticket->enc_part2->client, 
+			 UserNameRequested))
+	{
+		return(AUTH_VALID);
+	} else
+		return(AUTH_USER);
+}
+
+#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
+#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+	void
+kerberos5_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt;
+	unsigned int buflen;
+{
+	char lbuf[32];
+	register int i;
+
+	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
+	buflen -= 1;
+
+	switch(data[3]) {
+	case KRB_REJECT:		/* Rejected (reason might follow) */
+		strncpy((char *)buf, " REJECT ", buflen);
+		goto common;
+
+	case KRB_ACCEPT:		/* Accepted (name might follow) */
+		strncpy((char *)buf, " ACCEPT ", buflen);
+	common:
+		BUMP(buf, buflen);
+		if (cnt <= 4)
+			break;
+		ADDC(buf, buflen, '"');
+		for (i = 4; i < cnt; i++)
+			ADDC(buf, buflen, data[i]);
+		ADDC(buf, buflen, '"');
+		ADDC(buf, buflen, '\0');
+		break;
+
+
+	case KRB_AUTH:			/* Authentication data follows */
+		strncpy((char *)buf, " AUTH", buflen);
+		goto common2;
+
+	case KRB_RESPONSE:
+		strncpy((char *)buf, " RESPONSE", buflen);
+		goto common2;
+
+#ifdef	FORWARD
+	case KRB_FORWARD:               /* Forwarded credentials follow */
+		strncpy((char *)buf, " FORWARD", buflen);
+		goto common2;
+
+	case KRB_FORWARD_ACCEPT:               /* Forwarded credentials accepted */
+		strncpy((char *)buf, " FORWARD_ACCEPT", buflen);
+		goto common2;
+
+	case KRB_FORWARD_REJECT:               /* Forwarded credentials rejected */
+					       /* (reason might follow) */
+		strncpy((char *)buf, " FORWARD_REJECT", buflen);
+		goto common2;
+#endif	/* FORWARD */
+
+	default:
+		sprintf(lbuf, " %d (unknown)", data[3]);
+		strncpy((char *)buf, lbuf, buflen);
+	common2:
+		BUMP(buf, buflen);
+		for (i = 4; i < cnt; i++) {
+			sprintf(lbuf, " %d", data[i]);
+			strncpy((char *)buf, lbuf, buflen);
+			BUMP(buf, buflen);
+		}
+		break;
+	}
+}
+
+#ifdef	FORWARD
+
+static void
+kerberos5_forward(ap)
+     Authenticator *ap;
+{
+    krb5_error_code r;
+    krb5_ccache ccache;
+    krb5_principal client = 0;
+    krb5_principal server = 0;
+    krb5_data forw_creds;
+
+    forw_creds.data = 0;
+
+    if ((r = krb5_cc_default(telnet_context, &ccache))) {
+	if (auth_debug_mode) 
+	    printf("Kerberos V5: could not get default ccache - %s\r\n",
+		   error_message(r));
+	return;
+    }
+
+    if ((r = krb5_cc_get_principal(telnet_context, ccache, &client))) {
+	if (auth_debug_mode) 
+	    printf("Kerberos V5: could not get default principal - %s\r\n",
+		   error_message(r));
+	goto cleanup;
+    }
+
+    if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName, "host",
+				     KRB5_NT_SRV_HST, &server))) {
+	if (auth_debug_mode) 
+	    printf("Kerberos V5: could not make server principal - %s\r\n",
+		   error_message(r));
+	goto cleanup;
+    }
+
+    if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context, net,
+			    KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) {
+	if (auth_debug_mode)
+	    printf("Kerberos V5: could not gen local full address - %s\r\n",
+		    error_message(r));
+	goto cleanup;
+    }
+
+    if ((r = krb5_fwd_tgt_creds(telnet_context, auth_context, 0, client,
+				server, ccache,
+				forward_flags & OPTS_FORWARDABLE_CREDS,
+				&forw_creds))) {
+	if (auth_debug_mode) 
+	    printf("Kerberos V5: error getting forwarded creds - %s\r\n",
+	  	   error_message(r));
+	goto cleanup;
+    }
+    
+    /* Send forwarded credentials */
+    if (!Data(ap, KRB_FORWARD, forw_creds.data, forw_creds.length)) {
+	if (auth_debug_mode)
+	    printf("Not enough room for authentication data\r\n");
+    } else {
+	if (auth_debug_mode)
+	    printf("Forwarded local Kerberos V5 credentials to server\r\n");
+    }
+    
+cleanup:
+    if (client)
+	krb5_free_principal(telnet_context, client);
+    if (server)
+	krb5_free_principal(telnet_context, server);
+    if (forw_creds.data)
+	free(forw_creds.data);
+    krb5_cc_close(telnet_context, ccache);
+}
+#endif	/* FORWARD */
+
+#endif /* KRB5 */
diff --git a/mechglue/src/appl/telnet/libtelnet/key-proto.h b/mechglue/src/appl/telnet/libtelnet/key-proto.h
new file mode 100644
index 000000000..0a19c97bc
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/key-proto.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)key-proto.h	8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef	__KEY_PROTO__
+#define	__KEY_PROTO__
+
+int key_file_exists (void);
+void key_lookup (unsigned char *, Block);
+void key_stream_init (Block, Block, int);
+unsigned char key_stream (int, int);
+#endif
diff --git a/mechglue/src/appl/telnet/libtelnet/krb5forw.h b/mechglue/src/appl/telnet/libtelnet/krb5forw.h
new file mode 100644
index 000000000..1fb757ddf
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/krb5forw.h
@@ -0,0 +1,4 @@
+extern krb5_error_code 
+rd_and_store_for_creds(krb5_context, krb5_auth_context, krb5_data *, 
+		       krb5_ticket *);
+
diff --git a/mechglue/src/appl/telnet/libtelnet/mem.c b/mechglue/src/appl/telnet/libtelnet/mem.c
new file mode 100644
index 000000000..5a2ced8d5
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/mem.c
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on:
+   @(#)memcmp.c	8.1 (Berkeley) 6/4/93
+   @(#)memset.c	8.1 (Berkeley) 6/4/93
+   @(#)memcpy.c	8.1 (Berkeley) 6/4/93
+   @(#)memmove.c	8.1 (Berkeley) 6/4/93
+ */
+
+#ifndef	__STDC__
+#define	const
+#endif
+typedef int size_t;
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <limits.h>
+
+/*
+ * Compare memory regions.
+ */
+int
+memcmp(s1, s2, n)
+	const void *s1, *s2;
+	size_t n;
+{
+	if (n != 0) {
+		register const unsigned char *p1 = s1, *p2 = s2;
+
+		do {
+			if (*p1++ != *p2++)
+				return (*--p1 - *--p2);
+		} while (--n != 0);
+	}
+	return (0);
+}
+
+/*
+ * Copy a block of memory.
+ */
+void *
+memcpy(dst, src, n)
+	void *dst;
+	const void *src;
+	size_t n;
+{
+	bcopy((const char *)src, (char *)dst, n);
+	return(dst);
+}
+
+/*
+ * Copy a block of memory, handling overlap.
+ */
+void *
+memmove(dst, src, length)
+	void *dst;
+	const void *src;
+	register size_t length;
+{
+	bcopy((const char *)src, (char *)dst, length);
+	return(dst);
+}
+
+#define	wsize	sizeof(u_int)
+#define	wmask	(wsize - 1)
+
+#ifdef BZERO
+#define	RETURN	return
+#define	VAL	0
+#define	WIDEVAL	0
+
+void
+memset(dst0, 0, length)
+	void *dst0;
+	register size_t length;
+#else
+#define	RETURN	return (dst0)
+#define	VAL	c0
+#define	WIDEVAL	c
+
+void *
+memset(dst0, c0, length)
+	void *dst0;
+	register int c0;
+	register size_t length;
+#endif
+{
+	register size_t t;
+	register u_int c;
+	register u_char *dst;
+
+	dst = dst0;
+	/*
+	 * If not enough words, just fill bytes.  A length >= 2 words
+	 * guarantees that at least one of them is `complete' after
+	 * any necessary alignment.  For instance:
+	 *
+	 *	|-----------|-----------|-----------|
+	 *	|00|01|02|03|04|05|06|07|08|09|0A|00|
+	 *	          ^---------------------^
+	 *		 dst		 dst+length-1
+	 *
+	 * but we use a minimum of 3 here since the overhead of the code
+	 * to do word writes is substantial.
+	 */ 
+	if (length < 3 * wsize) {
+		while (length != 0) {
+			*dst++ = VAL;
+			--length;
+		}
+		RETURN;
+	}
+
+#ifndef BZERO
+	if ((c = (u_char)c0) != 0) {	/* Fill the word. */
+#ifndef UINT_MAX
+		UINT_MAX must be defined, try 0xFFFFFFFF;
+#endif
+		c = (c << 8) | c;	/* u_int is 16 bits. */
+#if UINT_MAX > 0xffff
+		c = (c << 16) | c;	/* u_int is 32 bits. */
+#endif
+#if UINT_MAX > 0xffffffff
+		c = (c << 32) | c;	/* u_int is 64 bits. */
+#endif
+	}
+#endif
+	/* Align destination by filling in bytes. */
+	if ((t = (int)dst & wmask) != 0) {
+		t = wsize - t;
+		length -= t;
+		do {
+			*dst++ = VAL;
+		} while (--t != 0);
+	}
+
+	/* Fill words.  Length was >= 2*words so we know t >= 1 here. */
+	t = length / wsize;
+	do {
+		*(u_int *)dst = WIDEVAL;
+		dst += wsize;
+	} while (--t != 0);
+
+	/* Mop up trailing bytes, if any. */
+	t = length & wmask;
+	if (t != 0)
+		do {
+			*dst++ = VAL;
+		} while (--t != 0);
+	RETURN;
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/misc-proto.h b/mechglue/src/appl/telnet/libtelnet/misc-proto.h
new file mode 100644
index 000000000..66e9dd7bf
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/misc-proto.h
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)misc-proto.h	8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef	__MISC_PROTO__
+#define	__MISC_PROTO__
+
+void auth_encrypt_init (char *, char *, char *, int);
+void auth_encrypt_user (const char *);
+void auth_encrypt_connect (int);
+void printd (const unsigned char *, int);
+
+/*
+ * These functions are imported from the application
+ */
+int net_write (unsigned char *, int);
+void net_encrypt (void);
+int telnet_spin (void);
+char *telnet_getenv (char *);
+char *telnet_gets (char *, char *, int, int);
+
+
+#ifdef NEED_PARSETOS
+int parsetos(char *, char *);
+#endif
+
+#ifdef NEED_SETENV
+int setenv(const char *, const char *, int);
+#ifndef HAVE_UNSETENV
+void unsetenv(const char *);
+#endif
+#endif
+
+#endif
diff --git a/mechglue/src/appl/telnet/libtelnet/misc.c b/mechglue/src/appl/telnet/libtelnet/misc.c
new file mode 100644
index 000000000..86e14cb1b
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/misc.c
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)misc.c	8.1 (Berkeley) 6/4/93 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "misc.h"
+#include "auth.h"
+#include "encrypt.h"
+
+char *RemoteHostName;
+char *LocalHostName;
+char *UserNameRequested = 0;
+int ConnectedCount = 0;
+
+	void
+auth_encrypt_init(local, remote, name, server)
+	char *local;
+	char *remote;
+	char *name;
+	int server;
+{
+	RemoteHostName = remote;
+	LocalHostName = local;
+#if	defined(AUTHENTICATION)
+	auth_init(name, server);
+#endif
+#ifdef	ENCRYPTION
+	encrypt_init(name, server);
+#endif	/* ENCRYPTION */
+	if (UserNameRequested) {
+		free(UserNameRequested);
+		UserNameRequested = 0;
+	}
+}
+
+	void
+auth_encrypt_user(name)
+	const char *name;
+{
+	extern char *strdup();
+
+	if (UserNameRequested)
+		free(UserNameRequested);
+	UserNameRequested = name ? strdup(name) : 0;
+}
+
+	void
+auth_encrypt_connect(cnt)
+	int cnt;
+{
+}
+
+	void
+printd(data, cnt)
+	const unsigned char *data;
+	int cnt;
+{
+	if (cnt > 16)
+		cnt = 16;
+	while (cnt-- > 0) {
+		printf(" %02x", *data);
+		++data;
+	}
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/misc.h b/mechglue/src/appl/telnet/libtelnet/misc.h
new file mode 100644
index 000000000..8ae603836
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/misc.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)misc.h	8.1 (Berkeley) 6/4/93
+ */
+
+extern char *UserNameRequested;
+extern char *LocalHostName;
+extern char *RemoteHostName;
+extern int ConnectedCount;
+extern int ReservedPort;
+
+int isprefix (char *, char *);
+char **genget (char *, char **, int);
+int Ambiguous (void *);
+
+#include "misc-proto.h"
diff --git a/mechglue/src/appl/telnet/libtelnet/parsetos.c b/mechglue/src/appl/telnet/libtelnet/parsetos.c
new file mode 100644
index 000000000..303d7c3e5
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/parsetos.c
@@ -0,0 +1,42 @@
+
+/*
+ * The routine parsetos() for UNICOS 6.0/6.1, as well as more traditional
+ * Unix systems.  This is part of UNICOS 7.0 and later.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <errno.h>
+#define NEED_PARSETOS
+#include "misc-proto.h"
+
+#define	MIN_TOS	0
+#define	MAX_TOS	255
+
+int
+parsetos(name, proto)
+char	*name;
+char	*proto;
+{
+#if 0
+	register char	*c;
+#endif
+	int		tos;
+
+#ifdef HAVE_GETTOSBYNAME
+	struct tosent	*tosp;
+
+	tosp = gettosbyname(name, proto);
+	if (tosp)
+		tos = tosp->t_tos;
+	else
+#endif
+		tos = (int)strtol(name, (char **)NULL, 0);
+
+	if (tos < MIN_TOS || tos > MAX_TOS) {
+		return (-1);
+	}
+	return (tos);
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/setenv.c b/mechglue/src/appl/telnet/libtelnet/setenv.c
new file mode 100644
index 000000000..941b816ca
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/setenv.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1987, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)setenv.c	8.1 (Berkeley) 6/4/93 */
+/* based on @(#)getenv.c	8.1 (Berkeley) 6/4/93 */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "misc-proto.h"
+
+static char *__findenv (const char *, int *); 
+
+/*
+ * setenv --
+ *	Set the value of the environmental variable "name" to be
+ *	"value".  If rewrite is set, replace any current value.
+ */
+#ifndef HAVE_SETENV
+int
+setenv(name, value, rewrite)
+	register const char *name;
+	register const char *value;
+	int rewrite;
+{
+	extern char **environ;
+	static int alloced;			/* if allocated space before */
+	register char *c;
+	const char *c2;
+	int l_value, offset;
+
+	if (*value == '=')			/* no `=' in value */
+		++value;
+	l_value = strlen(value);
+	if ((c = __findenv(name, &offset))) {	/* find if already exists */
+		if (!rewrite)
+			return (0);
+		if (strlen(c) >= l_value) {	/* old larger; copy over */
+			while ((*c++ = *value++));
+			return (0);
+		}
+	} else {					/* create new slot */
+		register int cnt;
+		register char **p;
+
+		for (p = environ, cnt = 0; *p; ++p, ++cnt);
+		if (alloced) {			/* just increase size */
+			environ = (char **)realloc((char *)environ,
+			    (size_t)(sizeof(char *) * (cnt + 2)));
+			if (!environ)
+				return (-1);
+		}
+		else {				/* get new space */
+			alloced = 1;		/* copy old entries into it */
+			p = (char **)malloc((size_t)(sizeof(char *) * (cnt + 2)));
+			if (!p)
+				return (-1);
+			memcpy(p, environ, cnt * sizeof(char *));
+			environ = p;
+		}
+		environ[cnt + 1] = NULL;
+		offset = cnt;
+	}
+	for (c2 = name; *c2 && *c2 != '='; ++c2);	/* no `=' in name */
+	if (!(environ[offset] =			/* name + `=' + value */
+	    malloc((size_t)((int)(c2 - name) + l_value + 2))))
+		return (-1);
+	for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
+	for (*c++ = '='; (*c++ = *value++););
+	return (0);
+}
+#endif
+
+/*
+ * unsetenv(name) --
+ *	Delete environmental variable "name".
+ */
+#ifndef HAVE_UNSETENV
+void
+unsetenv(name)
+	const char *name;
+{
+	extern char **environ;
+	register char **p;
+	int offset;
+
+	while (__findenv(name, &offset))	/* if set multiple times */
+		for (p = &environ[offset];; ++p)
+			if (!(*p = *(p + 1)))
+				break;
+}
+#endif
+
+/*
+ * getenv --
+ *	Returns ptr to value associated with name, if any, else NULL.
+ */
+#ifndef HAVE_GETENV
+char *
+getenv(name)
+	const char *name;
+{
+	int offset;
+
+	return (__findenv(name, &offset));
+}
+#endif
+
+/*
+ * __findenv --
+ *	Returns pointer to value associated with name, if any, else NULL.
+ *	Sets offset to be the offset of the name/value combination in the
+ *	environmental array, for use by setenv(3) and unsetenv(3).
+ *	Explicitly removes '=' in argument name.
+ */
+static char *
+__findenv(name, offset)
+	register const char *name;
+	int *offset;
+{
+	extern char **environ;
+	register unsigned int len;
+	register const char *np;
+	register char **p, *c;
+
+	if (name == NULL || environ == NULL)
+		return (NULL);
+	for (np = name; *np && *np != '='; ++np)
+		continue;
+	len = np - name;
+	for (p = environ; (c = *p) != NULL; ++p)
+		if (strncmp(c, name, len) == 0 && c[len] == '=') {
+			*offset = p - environ;
+			return (c + len + 1);
+		}
+	return (NULL);
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/setsid.c b/mechglue/src/appl/telnet/libtelnet/setsid.c
new file mode 100644
index 000000000..48c861c8c
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/setsid.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)setsid.c	8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Emulate the functionality of setsid(), called when forking
+ * and execing the new process.
+ */
+
+extern char *line;
+setsid()
+{
+#ifndef	convex
+	if (setpgrp(0, 0) < 0)
+		return(-1);
+#endif
+	return(0);
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/spx.c b/mechglue/src/appl/telnet/libtelnet/spx.c
new file mode 100644
index 000000000..b3e0e9dfc
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/spx.c
@@ -0,0 +1,594 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)spx.c	8.1 (Berkeley) 6/4/93 */
+
+#ifdef	SPX
+/*
+ * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
+ * ALL RIGHTS RESERVED
+ *
+ * "Digital Equipment Corporation authorizes the reproduction,
+ * distribution and modification of this software subject to the following
+ * restrictions:
+ *
+ * 1.  Any partial or whole copy of this software, or any modification
+ * thereof, must include this copyright notice in its entirety.
+ *
+ * 2.  This software is supplied "as is" with no warranty of any kind,
+ * expressed or implied, for any purpose, including any warranty of fitness
+ * or merchantibility.  DIGITAL assumes no responsibility for the use or
+ * reliability of this software, nor promises to provide any form of
+ * support for it on any basis.
+ *
+ * 3.  Distribution of this software is authorized only if no profit or
+ * remuneration of any kind is received in exchange for such distribution.
+ *
+ * 4.  This software produces public key authentication certificates
+ * bearing an expiration date established by DIGITAL and RSA Data
+ * Security, Inc.  It may cease to generate certificates after the expiration
+ * date.  Any modification of this software that changes or defeats
+ * the expiration date or its effect is unauthorized.
+ *
+ * 5.  Software that will renew or extend the expiration date of
+ * authentication certificates produced by this software may be obtained
+ * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
+ * 94065, (415)595-8782, or from DIGITAL"
+ *
+ */
+
+#include <sys/types.h>
+#include <arpa/telnet.h>
+#include <stdio.h>
+#include "gssapi_defs.h"
+#ifdef	__STDC__
+#include <stdlib.h>
+#endif
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include <pwd.h>
+#include "encrypt.h"
+#include "auth.h"
+#include "misc.h"
+
+extern auth_debug_mode;
+
+static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
+			  		AUTHTYPE_SPX, };
+static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
+					TELQUAL_NAME, };
+
+#define	SPX_AUTH	0		/* Authentication data follows */
+#define	SPX_REJECT	1		/* Rejected (reason might follow) */
+#define SPX_ACCEPT	2		/* Accepted */
+
+#ifdef	ENCRYPTION
+static Block	session_key	= { 0 };
+#endif	/* ENCRYPTION */
+static Schedule sched;
+static Block	challenge	= { 0 };
+
+
+/*******************************************************************/
+
+gss_OID_set           actual_mechs;
+gss_OID               actual_mech_type, output_name_type;
+int                   major_status, status, msg_ctx = 0, new_status;
+int                   req_flags = 0, ret_flags, lifetime_rec;
+gss_cred_id_t         gss_cred_handle;
+gss_ctx_id_t          actual_ctxhandle, context_handle;
+gss_buffer_desc       output_token, input_token, input_name_buffer;
+gss_buffer_desc       status_string;
+gss_name_t            desired_targname, src_name;
+gss_channel_bindings  input_chan_bindings;
+char                  lhostname[GSS_C_MAX_PRINTABLE_NAME];
+char                  targ_printable[GSS_C_MAX_PRINTABLE_NAME];
+int                   to_addr=0, from_addr=0;
+char                  *address;
+gss_buffer_desc       fullname_buffer;
+gss_OID               fullname_type;
+gss_cred_id_t         gss_delegated_cred_handle;
+
+/*******************************************************************/
+
+
+
+	static int
+Data(ap, type, d, c)
+	Authenticator *ap;
+	int type;
+	void *d;
+	int c;
+{
+        unsigned char *p = str_data + 4;
+	unsigned char *cd = (unsigned char *)d;
+
+	if (c == -1)
+		c = strlen((char *)cd);
+
+        if (0) {
+                printf("%s:%d: [%d] (%d)",
+                        str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
+                        str_data[3],
+                        type, c);
+                printd(d, c);
+                printf("\r\n");
+        }
+	*p++ = ap->type;
+	*p++ = ap->way;
+	*p++ = type;
+        while (c-- > 0) {
+                if ((*p++ = *cd++) == IAC)
+                        *p++ = IAC;
+        }
+        *p++ = IAC;
+        *p++ = SE;
+	if (str_data[3] == TELQUAL_IS)
+		printsub('>', &str_data[2], p - (&str_data[2]));
+        return(net_write(str_data, p - str_data));
+}
+
+	int
+spx_init(ap, server)
+	Authenticator *ap;
+	int server;
+{
+        gss_cred_id_t    tmp_cred_handle;
+
+	if (server) {
+		str_data[3] = TELQUAL_REPLY;
+		gethostname(lhostname, sizeof(lhostname));
+		strcpy(targ_printable, "SERVICE:rcmd@");
+		strncat(targ_printable, lhostname, sizeof(targ_printable) - 1 - 13);
+		targ_printable[sizeof(targ_printable) - 1] = '\0';
+		input_name_buffer.length = strlen(targ_printable);
+		input_name_buffer.value = targ_printable;
+		major_status = gss_import_name(&status,
+                                       &input_name_buffer,
+                                       GSS_C_NULL_OID,
+                                       &desired_targname);
+		major_status = gss_acquire_cred(&status,
+                                        desired_targname,
+                                        0,
+                                        GSS_C_NULL_OID_SET,
+                                        GSS_C_ACCEPT,
+                                        &tmp_cred_handle,
+                                        &actual_mechs,
+                                        &lifetime_rec);
+		if (major_status != GSS_S_COMPLETE) return(0);
+	} else {
+		str_data[3] = TELQUAL_IS;
+	}
+	return(1);
+}
+
+	int
+spx_send(ap)
+	Authenticator *ap;
+{
+	Block enckey;
+	int r;
+
+	gss_OID  actual_mech_type, output_name_type;
+	int           msg_ctx = 0, new_status, status;
+	int           req_flags = 0, ret_flags, lifetime_rec, major_status;
+	gss_buffer_desc  output_token, input_token, input_name_buffer;
+	gss_buffer_desc  output_name_buffer, status_string;
+	gss_name_t    desired_targname;
+	gss_channel_bindings  input_chan_bindings;
+	char targ_printable[GSS_C_MAX_PRINTABLE_NAME];
+	int  from_addr=0, to_addr=0, myhostlen, j;
+	int  deleg_flag=1, mutual_flag=0, replay_flag=0, seq_flag=0;
+	char *address;
+
+	printf("[ Trying SPX ... ]\n");
+	strcpy(targ_printable, "SERVICE:rcmd@");
+	strncat(targ_printable, RemoteHostName, sizeof(targ_printable) - 1 - 13);
+	targ_printable[sizeof(targ_printable) - 1] = '\0';
+
+	input_name_buffer.length = strlen(targ_printable);
+	input_name_buffer.value = targ_printable;
+
+	if (!UserNameRequested) {
+		return(0);
+	}
+
+	major_status = gss_import_name(&status,
+				       &input_name_buffer,
+				       GSS_C_NULL_OID,
+				       &desired_targname);
+
+
+	major_status = gss_display_name(&status,
+					desired_targname,
+					&output_name_buffer,
+					&output_name_type);
+
+	printf("target is '%s'\n", output_name_buffer.value); fflush(stdout);
+
+	major_status = gss_release_buffer(&status, &output_name_buffer);
+
+	input_chan_bindings = (gss_channel_bindings)
+	  malloc(sizeof(gss_channel_bindings_desc));
+
+	input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
+	input_chan_bindings->initiator_address.length = 4;
+	address = (char *) malloc(4);
+	input_chan_bindings->initiator_address.value = (char *) address;
+	address[0] = ((from_addr & 0xff000000) >> 24);
+	address[1] = ((from_addr & 0xff0000) >> 16);
+	address[2] = ((from_addr & 0xff00) >> 8);
+	address[3] = (from_addr & 0xff);
+	input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
+	input_chan_bindings->acceptor_address.length = 4;
+	address = (char *) malloc(4);
+	input_chan_bindings->acceptor_address.value = (char *) address;
+	address[0] = ((to_addr & 0xff000000) >> 24);
+	address[1] = ((to_addr & 0xff0000) >> 16);
+	address[2] = ((to_addr & 0xff00) >> 8);
+	address[3] = (to_addr & 0xff);
+	input_chan_bindings->application_data.length = 0;
+
+        req_flags = 0;
+        if (deleg_flag)  req_flags = req_flags | 1;
+        if (mutual_flag) req_flags = req_flags | 2;
+        if (replay_flag) req_flags = req_flags | 4;
+        if (seq_flag)    req_flags = req_flags | 8;
+
+        major_status = gss_init_sec_context(&status,         /* minor status */
+					GSS_C_NO_CREDENTIAL, /* cred handle */
+                                        &actual_ctxhandle,   /* ctx handle */
+                                        desired_targname,    /* target name */
+                                        GSS_C_NULL_OID,      /* mech type */
+                                        req_flags,           /* req flags */
+                                        0,                   /* time req */
+                                        input_chan_bindings, /* chan binding */
+                                        GSS_C_NO_BUFFER,     /* input token */
+                                        &actual_mech_type,   /* actual mech */
+                                        &output_token,       /* output token */
+                                        &ret_flags,          /* ret flags */
+                                        &lifetime_rec);      /* time rec */
+
+	if ((major_status != GSS_S_COMPLETE) &&
+	    (major_status != GSS_S_CONTINUE_NEEDED)) {
+          gss_display_status(&new_status,
+                             status,
+                             GSS_C_MECH_CODE,
+                             GSS_C_NULL_OID,
+                             &msg_ctx,
+                             &status_string);
+          printf("%s\n", status_string.value);
+	  return(0);
+	}
+
+	if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
+		return(0);
+	}
+
+	if (!Data(ap, SPX_AUTH, (void *)output_token.value, output_token.length)) {
+		return(0);
+	}
+
+	return(1);
+}
+
+	void
+spx_is(ap, data, cnt)
+	Authenticator *ap;
+	unsigned char *data;
+	int cnt;
+{
+	Session_Key skey;
+	Block datablock;
+	int r;
+
+	if (cnt-- < 1)
+		return;
+	switch (*data++) {
+	case SPX_AUTH:
+	        input_token.length = cnt;
+		input_token.value = (char *) data;
+
+		gethostname(lhostname, sizeof(lhostname));
+
+		strcpy(targ_printable, "SERVICE:rcmd@");
+		strncat(targ_printable, lhostname, sizeof(targ_printable) - 1 - 13);
+		targ_printable[sizeof(targ_printable) - 1] = '\0';
+
+		input_name_buffer.length = strlen(targ_printable);
+		input_name_buffer.value = targ_printable;
+
+		major_status = gss_import_name(&status,
+                                       &input_name_buffer,
+                                       GSS_C_NULL_OID,
+                                       &desired_targname);
+
+		major_status = gss_acquire_cred(&status,
+                                        desired_targname,
+                                        0,
+                                        GSS_C_NULL_OID_SET,
+                                        GSS_C_ACCEPT,
+                                        &gss_cred_handle,
+                                        &actual_mechs,
+                                        &lifetime_rec);
+
+		major_status = gss_release_name(&status, desired_targname);
+
+		input_chan_bindings = (gss_channel_bindings)
+		  malloc(sizeof(gss_channel_bindings_desc));
+
+		input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
+		input_chan_bindings->initiator_address.length = 4;
+		address = (char *) malloc(4);
+		input_chan_bindings->initiator_address.value = (char *) address;
+		address[0] = ((from_addr & 0xff000000) >> 24);
+		address[1] = ((from_addr & 0xff0000) >> 16);
+		address[2] = ((from_addr & 0xff00) >> 8);
+		address[3] = (from_addr & 0xff);
+		input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
+		input_chan_bindings->acceptor_address.length = 4;
+		address = (char *) malloc(4);
+		input_chan_bindings->acceptor_address.value = (char *) address;
+		address[0] = ((to_addr & 0xff000000) >> 24);
+		address[1] = ((to_addr & 0xff0000) >> 16);
+		address[2] = ((to_addr & 0xff00) >> 8);
+		address[3] = (to_addr & 0xff);
+		input_chan_bindings->application_data.length = 0;
+
+		major_status = gss_accept_sec_context(&status,
+					      &context_handle,
+                                              gss_cred_handle,
+                                              &input_token,
+                                              input_chan_bindings,
+                                              &src_name,
+                                              &actual_mech_type,
+                                              &output_token,
+                                              &ret_flags,
+                                              &lifetime_rec,
+                                              &gss_delegated_cred_handle);
+
+
+		if (major_status != GSS_S_COMPLETE) {
+
+		  major_status = gss_display_name(&status,
+					  src_name,
+                                          &fullname_buffer,
+                                          &fullname_type);
+			Data(ap, SPX_REJECT, (void *)"auth failed", -1);
+			auth_finished(ap, AUTH_REJECT);
+			return;
+		}
+
+		major_status = gss_display_name(&status,
+                                          src_name,
+                                          &fullname_buffer,
+                                          &fullname_type);
+
+
+		Data(ap, SPX_ACCEPT, (void *)output_token.value, output_token.length);
+		auth_finished(ap, AUTH_USER);
+		break;
+
+	default:
+		Data(ap, SPX_REJECT, 0, 0);
+		break;
+	}
+}
+
+
+	void
+spx_reply(ap, data, cnt)
+	Authenticator *ap;
+	unsigned char *data;
+	int cnt;
+{
+	Session_Key skey;
+
+	if (cnt-- < 1)
+		return;
+	switch (*data++) {
+	case SPX_REJECT:
+		if (cnt > 0) {
+			printf("[ SPX refuses authentication because %.*s ]\r\n",
+				cnt, data);
+		} else
+			printf("[ SPX refuses authentication ]\r\n");
+		auth_send_retry();
+		return;
+	case SPX_ACCEPT:
+		printf("[ SPX accepts you ]\n");
+		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+			/*
+			 * Send over the encrypted challenge.
+		 	 */
+		  input_token.value = (char *) data;
+		  input_token.length = cnt;
+
+		  major_status = gss_init_sec_context(&status, /* minor stat */
+                                        GSS_C_NO_CREDENTIAL, /* cred handle */
+                                        &actual_ctxhandle,   /* ctx handle */
+                                        desired_targname,    /* target name */
+                                        GSS_C_NULL_OID,      /* mech type */
+                                        req_flags,           /* req flags */
+                                        0,                   /* time req */
+                                        input_chan_bindings, /* chan binding */
+                                        &input_token,        /* input token */
+                                        &actual_mech_type,   /* actual mech */
+                                        &output_token,       /* output token */
+                                        &ret_flags,          /* ret flags */
+                                        &lifetime_rec);      /* time rec */
+
+		  if (major_status != GSS_S_COMPLETE) {
+		    gss_display_status(&new_status,
+				       status,
+				       GSS_C_MECH_CODE,
+				       GSS_C_NULL_OID,
+				       &msg_ctx,
+				       &status_string);
+		    printf("[ SPX mutual response fails ... '%s' ]\r\n",
+			 status_string.value);
+		    auth_send_retry();
+		    return;
+		  }
+		}
+		auth_finished(ap, AUTH_USER);
+		return;
+
+	default:
+		return;
+	}
+}
+
+	int
+spx_status(ap, name, level)
+	Authenticator *ap;
+	char *name;
+	int level;
+{
+
+	gss_buffer_desc  fullname_buffer, acl_file_buffer;
+	gss_OID          fullname_type;
+        char acl_file[MAXPATHLEN], fullname[160];
+        int major_status, status = 0;
+	struct passwd  *pwd;
+
+        /*
+         * hard code fullname to
+         *   "SPX:/C=US/O=Digital/OU=LKG/OU=Sphinx/OU=Users/CN=Kannan Alagappan"
+         * and acl_file to "~kannan/.sphinx"
+         */
+
+	pwd = getpwnam(UserNameRequested);
+	if (pwd == NULL) {
+          return(AUTH_USER);   /*  not authenticated  */
+        }
+
+	acl_file[sizeof(acl_file) - 1] = '\0';
+	strncpy(acl_file, pwd->pw_dir, sizeof(acl_file) - 1);
+	strncat(acl_file, "/.sphinx", sizeof(acl_file) - 1 - strlen(acl_file));
+        acl_file_buffer.value = acl_file;
+        acl_file_buffer.length = strlen(acl_file);
+
+	major_status = gss_display_name(&status,
+					src_name,
+					&fullname_buffer,
+					&fullname_type);
+
+	if (level < AUTH_USER)
+		return(level);
+
+        major_status = gss__check_acl(&status, &fullname_buffer,
+                                      &acl_file_buffer);
+
+        if (major_status == GSS_S_COMPLETE) {
+          /* the name buffer comes from telnetd/telnetd{-ktd}.c */
+	  strncpy(name, UserNameRequested, 255);
+	  name[255] = '\0';
+	  return(AUTH_VALID);
+        } else {
+           return(AUTH_USER);
+        }
+
+}
+
+#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
+#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
+
+	void
+spx_printsub(data, cnt, buf, buflen)
+	unsigned char *data, *buf;
+	int cnt;
+	unsigned int buflen;
+{
+	char lbuf[32];
+	register int i;
+
+	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
+	buflen -= 1;
+
+	switch(data[3]) {
+	case SPX_REJECT:		/* Rejected (reason might follow) */
+		strncpy((char *)buf, " REJECT ", buflen);
+		goto common;
+
+	case SPX_ACCEPT:		/* Accepted (name might follow) */
+		strncpy((char *)buf, " ACCEPT ", buflen);
+	common:
+		BUMP(buf, buflen);
+		if (cnt <= 4)
+			break;
+		ADDC(buf, buflen, '"');
+		for (i = 4; i < cnt; i++)
+			ADDC(buf, buflen, data[i]);
+		ADDC(buf, buflen, '"');
+		ADDC(buf, buflen, '\0');
+		break;
+
+	case SPX_AUTH:			/* Authentication data follows */
+		strncpy((char *)buf, " AUTH", buflen);
+		goto common2;
+
+	default:
+		sprintf(lbuf, " %d (unknown)", data[3]);
+		strncpy((char *)buf, lbuf, buflen);
+	common2:
+		BUMP(buf, buflen);
+		for (i = 4; i < cnt; i++) {
+			sprintf(lbuf, " %d", data[i]);
+			strncpy((char *)buf, lbuf, buflen);
+			BUMP(buf, buflen);
+		}
+		break;
+	}
+}
+#else
+#include "misc-proto.h"
+#endif
+
+#ifdef notdef
+
+prkey(msg, key)
+	char *msg;
+	unsigned char *key;
+{
+	register int i;
+	printf("%s:", msg);
+	for (i = 0; i < 8; i++)
+		printf(" %3d", key[i]);
+	printf("\r\n");
+}
+#endif
diff --git a/mechglue/src/appl/telnet/libtelnet/strcasecmp.c b/mechglue/src/appl/telnet/libtelnet/strcasecmp.c
new file mode 100644
index 000000000..edd9f1415
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/strcasecmp.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 1987, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* based on @(#)strcasecmp.c	8.1 (Berkeley) 6/4/93 */
+
+typedef unsigned char u_char;
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static const u_char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+	'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+	'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+	'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(s1, s2)
+	const char *s1, *s2;
+{
+	register const u_char *cm = charmap,
+			*us1 = (const u_char *)s1,
+			*us2 = (const u_char *)s2;
+
+	while (cm[*us1] == cm[*us2++])
+		if (*us1++ == '\0')
+			return (0);
+	return (cm[*us1] - cm[*--us2]);
+}
+
+int
+strncasecmp(s1, s2, n)
+	const char *s1, *s2;
+	register size_t n;
+{
+	if (n != 0) {
+		register const u_char *cm = charmap,
+				*us1 = (const u_char *)s1,
+				*us2 = (const u_char *)s2;
+
+		do {
+			if (cm[*us1] != cm[*us2++])
+				return (cm[*us1] - cm[*--us2]);
+			if (*us1++ == '\0')
+				break;
+		} while (--n != 0);
+	}
+	return (0);
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/strchr.c b/mechglue/src/appl/telnet/libtelnet/strchr.c
new file mode 100644
index 000000000..91f5612fa
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/strchr.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)strchr.c	8.1 (Berkeley) 6/4/93 */
+
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+char *
+strchr(p, ch)
+	char *p, ch;
+{
+	return(index(p, ch));
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/strdup.c b/mechglue/src/appl/telnet/libtelnet/strdup.c
new file mode 100644
index 000000000..d501ed992
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/strdup.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)strdup.c	8.1 (Berkeley) 6/4/93 */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+char *
+strdup(str)
+	const char *str;
+{
+	size_t len;
+	char *copy;
+
+	len = strlen(str) + 1;
+	if (!(copy = malloc((u_int)len)))
+		return (NULL);
+	memcpy(copy, str, len);
+	return (copy);
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/strerror.c b/mechglue/src/appl/telnet/libtelnet/strerror.c
new file mode 100644
index 000000000..8bed9c670
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/strerror.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)strerror.c	8.1 (Berkeley) 6/4/93 */
+
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+char *
+strerror(num)
+	int num;
+{
+	extern int sys_nerr;
+	extern char *sys_errlist[];
+#define	UPREFIX	"Unknown error: "
+	static char ebuf[40] = UPREFIX;		/* 64-bit number + slop */
+	register unsigned int errnum;
+	register char *p, *t;
+	char tmp[40];
+
+	errnum = num;				/* convert to unsigned */
+	if (errnum < sys_nerr)
+		return(sys_errlist[errnum]);
+
+	/* Do this by hand, so we don't include stdio(3). */
+	t = tmp;
+	do {
+		*t++ = "0123456789"[errnum % 10];
+	} while (errnum /= 10);
+	for (p = ebuf + sizeof(UPREFIX) - 1;;) {
+		*p++ = *--t;
+		if (t <= tmp)
+			break;
+	}
+	return(ebuf);
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/strftime.c b/mechglue/src/appl/telnet/libtelnet/strftime.c
new file mode 100644
index 000000000..f2bcc676c
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/strftime.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)strftime.c	8.1 (Berkeley) 6/4/93 */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#ifdef notdef
+#include <tzfile.h>
+#else
+#define TM_YEAR_BASE	1900	/* from <tzfile.h> */
+#endif
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+static char *afmt[] = {
+	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+};
+static char *Afmt[] = {
+	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
+	"Saturday",
+};
+static char *bfmt[] = {
+	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+	"Oct", "Nov", "Dec",
+};
+static char *Bfmt[] = {
+	"January", "February", "March", "April", "May", "June", "July",
+	"August", "September", "October", "November", "December",
+};
+
+static size_t gsize;
+static char *pt;
+#ifndef	__P
+#define	__P(x)	()
+#endif
+static int _add __P((char *));
+static int _conv __P((int, int, int));
+static int _secs __P((const struct tm *));
+static size_t _fmt __P((const char *, const struct tm *));
+
+size_t
+strftime(s, maxsize, format, t)
+	char *s;
+	size_t maxsize;
+	const char *format;
+	const struct tm *t;
+{
+
+	pt = s;
+	if ((gsize = maxsize) < 1)
+		return(0);
+	if (_fmt(format, t)) {
+		*pt = '\0';
+		return(maxsize - gsize);
+	}
+	return(0);
+}
+
+static size_t
+_fmt(format, t)
+	register const char *format;
+	const struct tm *t;
+{
+	for (; *format; ++format) {
+		if (*format == '%')
+			switch(*++format) {
+			case '\0':
+				--format;
+				break;
+			case 'A':
+				if (t->tm_wday < 0 || t->tm_wday > 6)
+					return(0);
+				if (!_add(Afmt[t->tm_wday]))
+					return(0);
+				continue;
+			case 'a':
+				if (t->tm_wday < 0 || t->tm_wday > 6)
+					return(0);
+				if (!_add(afmt[t->tm_wday]))
+					return(0);
+				continue;
+			case 'B':
+				if (t->tm_mon < 0 || t->tm_mon > 11)
+					return(0);
+				if (!_add(Bfmt[t->tm_mon]))
+					return(0);
+				continue;
+			case 'b':
+			case 'h':
+				if (t->tm_mon < 0 || t->tm_mon > 11)
+					return(0);
+				if (!_add(bfmt[t->tm_mon]))
+					return(0);
+				continue;
+			case 'C':
+				if (!_fmt("%a %b %e %H:%M:%S %Y", t))
+					return(0);
+				continue;
+			case 'c':
+				if (!_fmt("%m/%d/%y %H:%M:%S", t))
+					return(0);
+				continue;
+			case 'D':
+				if (!_fmt("%m/%d/%y", t))
+					return(0);
+				continue;
+			case 'd':
+				if (!_conv(t->tm_mday, 2, '0'))
+					return(0);
+				continue;
+			case 'e':
+				if (!_conv(t->tm_mday, 2, ' '))
+					return(0);
+				continue;
+			case 'H':
+				if (!_conv(t->tm_hour, 2, '0'))
+					return(0);
+				continue;
+			case 'I':
+				if (!_conv(t->tm_hour % 12 ?
+				    t->tm_hour % 12 : 12, 2, '0'))
+					return(0);
+				continue;
+			case 'j':
+				if (!_conv(t->tm_yday + 1, 3, '0'))
+					return(0);
+				continue;
+			case 'k':
+				if (!_conv(t->tm_hour, 2, ' '))
+					return(0);
+				continue;
+			case 'l':
+				if (!_conv(t->tm_hour % 12 ?
+				    t->tm_hour % 12 : 12, 2, ' '))
+					return(0);
+				continue;
+			case 'M':
+				if (!_conv(t->tm_min, 2, '0'))
+					return(0);
+				continue;
+			case 'm':
+				if (!_conv(t->tm_mon + 1, 2, '0'))
+					return(0);
+				continue;
+			case 'n':
+				if (!_add("\n"))
+					return(0);
+				continue;
+			case 'p':
+				if (!_add(t->tm_hour >= 12 ? "PM" : "AM"))
+					return(0);
+				continue;
+			case 'R':
+				if (!_fmt("%H:%M", t))
+					return(0);
+				continue;
+			case 'r':
+				if (!_fmt("%I:%M:%S %p", t))
+					return(0);
+				continue;
+			case 'S':
+				if (!_conv(t->tm_sec, 2, '0'))
+					return(0);
+				continue;
+			case 's':
+				if (!_secs(t))
+					return(0);
+				continue;
+			case 'T':
+			case 'X':
+				if (!_fmt("%H:%M:%S", t))
+					return(0);
+				continue;
+			case 't':
+				if (!_add("\t"))
+					return(0);
+				continue;
+			case 'U':
+				if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
+				    2, '0'))
+					return(0);
+				continue;
+			case 'W':
+				if (!_conv((t->tm_yday + 7 -
+				    (t->tm_wday ? (t->tm_wday - 1) : 6))
+				    / 7, 2, '0'))
+					return(0);
+				continue;
+			case 'w':
+				if (!_conv(t->tm_wday, 1, '0'))
+					return(0);
+				continue;
+			case 'x':
+				if (!_fmt("%m/%d/%y", t))
+					return(0);
+				continue;
+			case 'y':
+				if (!_conv((t->tm_year + TM_YEAR_BASE)
+				    % 100, 2, '0'))
+					return(0);
+				continue;
+			case 'Y':
+				if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0'))
+					return(0);
+				continue;
+#ifdef notdef
+			case 'Z':
+				if (!t->tm_zone || !_add(t->tm_zone))
+					return(0);
+				continue;
+#endif
+			case '%':
+			/*
+			 * X311J/88-090 (4.12.3.5): if conversion char is
+			 * undefined, behavior is undefined.  Print out the
+			 * character itself as printf(3) does.
+			 */
+			default:
+				break;
+		}
+		if (!gsize--)
+			return(0);
+		*pt++ = *format;
+	}
+	return(gsize);
+}
+
+static int
+_secs(t)
+	const struct tm *t;
+{
+	static char buf[15];
+	register time_t s;
+	register char *p;
+	struct tm tmp;
+
+	/* Make a copy, mktime(3) modifies the tm struct. */
+	tmp = *t;
+	s = mktime(&tmp);
+	for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10)
+		*p-- = s % 10 + '0';
+	return(_add(++p));
+}
+
+static int
+_conv(n, digits, pad)
+	int n, digits, pad;
+{
+	static char buf[10];
+	register char *p;
+
+	for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
+		*p-- = n % 10 + '0';
+	while (p > buf && digits-- > 0)
+		*p-- = pad;
+	return(_add(++p));
+}
+
+static int
+_add(str)
+	register char *str;
+{
+	for (;; ++pt, --gsize) {
+		if (!gsize)
+			return(0);
+		if (!(*pt = *str++))
+			return(1);
+	}
+}
diff --git a/mechglue/src/appl/telnet/libtelnet/strrchr.c b/mechglue/src/appl/telnet/libtelnet/strrchr.c
new file mode 100644
index 000000000..f65a7e805
--- /dev/null
+++ b/mechglue/src/appl/telnet/libtelnet/strrchr.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)strrchr.c	8.1 (Berkeley) 6/4/93 */
+
+#ifdef	HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+char *
+strrchr(p, ch)
+	char *p, ch;
+{
+	return(rindex(p, ch));
+}
diff --git a/mechglue/src/appl/telnet/stty.diff b/mechglue/src/appl/telnet/stty.diff
new file mode 100644
index 000000000..3c1b02acc
--- /dev/null
+++ b/mechglue/src/appl/telnet/stty.diff
@@ -0,0 +1,72 @@
+*** stty.c.old	Tue May 23 13:54:29 1989
+--- stty.c	Wed Aug 23 13:42:32 1989
+***************
+*** 20,25 ****
+--- 20,28 ----
+  
+  #include <stdio.h>
+  #include <sys/ioctl.h>
++ #include <sys/types.h>
++ #define	NO_T_CHARS_DEFINES
++ #include <sys/tty.h>
+  
+  struct
+  {
+***************
+*** 145,150 ****
+--- 148,156 ----
+  struct winsize win;
+  int	lmode;
+  int	oldisc, ldisc;
++ #ifdef	TIOCGSTATE
++ int	extproc;
++ #endif
+  
+  struct	special {
+  	char	*name;
+***************
+*** 188,193 ****
+--- 194,203 ----
+  	ioctl(1, TIOCLGET, &lmode);
+  	ioctl(1, TIOCGLTC, <c);
+  	ioctl(1, TIOCGWINSZ, &win);
++ #ifdef	TIOCGSTATE
++ 	ioctl(1, TIOCGSTATE, &extproc);
++ 	extproc &= TS_EXTPROC;
++ #endif
+  	if(argc == 1) {
+  		prmodes(0);
+  		exit(0);
+***************
+*** 292,297 ****
+--- 302,316 ----
+  			printf("%d %d\n", win.ws_row, win.ws_col);
+  			exit(0);
+  		}
++ #if	defined(TIOCEXT)
++ 		if (eq("extproc") || eq("-extproc")) {
++ 			if (**argv == '-')
++ 				extproc = 0;
++ 			else
++ 				extproc = 1;
++ 			ioctl(1, TIOCEXT, &extproc);
++ 		}
++ #endif
+  		for(i=0; speeds[i].string; i++)
+  			if(eq(speeds[i].string)) {
+  				mode.sg_ispeed = mode.sg_ospeed = speeds[i].speed;
+***************
+*** 438,443 ****
+--- 457,468 ----
+  		lpit(LPENDIN, "-pendin ");
+  		lpit(LDECCTQ, "-decctlq ");
+  		lpit(LNOFLSH, "-noflsh ");
++ #ifdef	TIOCGSTATE
++ 		if (all==2||extproc) {
++ 			fprintf(stderr,"-extproc"+(extproc!=0));
++ 			any++;
++ 		}
++ #endif
+  		if (any || nothing)
+  			fprintf(stderr,"\n");
+  	} else if (!all)
diff --git a/mechglue/src/appl/telnet/telnet.state b/mechglue/src/appl/telnet/telnet.state
new file mode 100644
index 000000000..1927a2b4b
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet.state
@@ -0,0 +1,80 @@
+
+   Three pieces of state need to be kept for each side of each option.
+   (You need the localside, sending WILL/WONT & receiving DO/DONT, and
+   the remoteside, sending DO/DONT and receiving WILL/WONT)
+
+	MY_STATE:	What state am I in?
+	WANT_STATE:	What state do I want?
+	WANT_RESP:	How many requests have I initiated?
+
+   Default values:
+	MY_STATE = WANT_STATE = DONT
+	WANT_RESP = 0
+
+   The local setup will change based on the state of the Telnet
+   variables.  When we are the originator, we can either make the
+   local setup changes at option request time (in which case if
+   the option is denied we need to change things back) or when
+   the option is acknowledged.
+
+   To initiate a switch to NEW_STATE:
+
+	if ((WANT_RESP == 0 && NEW_STATE == MY_STATE) ||
+			WANT_STATE == NEW_STATE) {
+	    do nothing;
+	} else {
+	    /*
+	     * This is where the logic goes to change the local setup
+	     * if we are doing so at request initiation
+	     */
+	    WANT_STATE = NEW_STATE;
+	    send NEW_STATE;
+	    WANT_RESP += 1;
+	}
+
+   When receiving NEW_STATE:
+
+	if (WANT_RESP) {
+	    --WANT_RESP;
+	    if (WANT_RESP && (NEW_STATE == MY_STATE))
+		--WANT_RESP;
+	}
+	if (WANT_RESP == 0) {
+	    if (NEW_STATE != WANT_STATE) {
+		/*
+		 * This is where the logic goes to decide if it is ok
+		 * to switch to NEW_STATE, and if so, do any necessary
+		 * local setup changes.
+		 */
+		if (ok_to_switch_to NEW_STATE)
+		    WANT_STATE = NEW_STATE;
+		else
+		    WANT_RESP++;
+*		if (MY_STATE != WANT_STATE)
+		    reply with WANT_STATE;
+	    } else {
+		/*
+		 * This is where the logic goes to change the local setup
+		 * if we are doing so at request acknowledgment
+		 */
+	    }
+	}
+	MY_STATE = NEW_STATE;
+
+* This if() line is not needed, it should be ok to always do the
+  "reply with WANT_STATE".  With the if() line, asking to turn on
+  an option that the other side doesn't understand is:
+		Send DO option
+		Recv WONT option
+  Without the if() line, it is:
+		Send DO option
+		Recv WONT option
+		Send DONT option
+  If the other side does not expect to receive the latter case,
+  but generates the latter case, then there is a potential for
+  option negotiation loops.  An implementation that does not expect
+  to get the second case should not generate it, an implementation
+  that does expect to get it may or may not generate it, and things
+  will still work.  Being conservative in what we send, we have the
+  if() statement in, but we expect the other side to generate the
+  last response.
diff --git a/mechglue/src/appl/telnet/telnet/.Sanitize b/mechglue/src/appl/telnet/telnet/.Sanitize
new file mode 100644
index 000000000..d9ba4ac97
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/.Sanitize
@@ -0,0 +1,59 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.4.4
+Makefile.generic
+Makefile.in
+Makefile.orig
+authenc.c
+commands.c
+configure
+configure.in
+defines.h
+externs.h
+fdset.h
+general.h
+main.c
+network.c
+ring.c
+ring.h
+sys_bsd.c
+telnet.0.ps
+telnet.0.txt
+telnet.1
+telnet.c
+terminal.c
+tmac.doc
+tn3270.c
+types.h
+utilities.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/telnet/telnet/ChangeLog b/mechglue/src/appl/telnet/telnet/ChangeLog
new file mode 100644
index 000000000..3e090ca6e
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/ChangeLog
@@ -0,0 +1,614 @@
+2005-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* commands.c (shell): Change 0 to (char*)NULL in execl calls.
+	Patch provided by Michael Calmer.
+
+2005-03-28  Tom Yu  <tlyu@mit.edu>
+
+	* telnet.c (slc_add_reply, slc_end_reply): Fix buffer overflow
+	vulnerability by checking lengths.
+	(env_opt_add): Ensure buffer allocation is sufficiently large,
+	accounting for expansion during IAC quoting.
+
+2004-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Deleted; configure this dir from parent now.
+	* Makefile.in (thisconfigdir, mydir): Updated.
+	(LIBS): Define from @TELNET_LIBS@.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* externs.h: Don't declare errno.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.orig: Deleted.
+
+2002-11-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* sys_bsd.c: Moved declaration for susp() to type of file and
+	provide prototype.
+
+	* commands.c, externs.h, telnet.c, network.c: Add prototype
+	declaration for command handler table dispatch functions. Make
+	functions called consistant with prototype. Misc unsigned/signed
+	cleanups.
+
+	* authenc.c, main.c, utilities.c: Signed vs. unsigned cleanup.
+
+2002-10-22  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Autoconf 2.55 will not simply use cpp to test for
+	header file existance - the header file must be compilable. This
+	will mean that if one header depends on another, it must be
+	included. Test for term.h using the optional fourth argument to
+	AC_CHECK_HEADERS to specify include files to test.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-04-12  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Sepcial-case solaris+gcc to always find curses.h,
+	since it fails to find it otherwise due to some macro redefinition
+	warnings.
+
+2002-03-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* commands.c: Include fake-addrinfo.h, not fake-addrinfo.c.
+	(FAI_PREFIX): Delete.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* commands.c, externs.h, ring.h, telnet.c: Make prototypes
+	unconditional.
+
+2001-09-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* commands.c (tn): Don't crash printing null hostname in case
+	where supplied destination is a numeric address that doesn't map
+	to a hostname.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Use $(srcdir).
+
+2001-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* commands.c: Include netdb.h and fake-addrinfo.c.
+	(FAI_PREFIX): Define.
+	(hostaddr): Deleted.
+	(hostaddrstring): New static variable.
+	(status): Use hostaddrstring instead of hostaddr.
+	(tn): Use get{addr,name}info instead of gethostby{name,addr}, and
+	attempt to connect to both IPv6 and IPv4 sockets.  Add workarounds
+	for GNU libc bugs.  Fill in hostaddrstring with printable form of
+	each net address.  Source routing is still IPv4-only.
+
+	* configure.in: Run KRB5_AC_INET6.
+
+2001-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* telnet.c (setupterm): Now static.
+	(suboption): Rename local variable "ospeed" to "o_speed" to avoid
+	conflict with global.
+	(env_opt_add): Cast opt_welldefined argument to char * to silence
+	warning.
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add AC_HEADER_STDARG.
+
+	* commands.c (call): Rewrite to use varargs/stdarg interface.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Check if prototype needed for herror().
+
+	* commands.c (ayt_status): Add explict return type (void or int)
+	depending on signal handler definition. Add prototype for herror
+	if system does not provide one.
+
+2001-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* commands.c: Remove prototypes for EncryptAutoEnc(),
+	EncryptAuthDec(), EcnryptDebug(), EncryptVerbose() as they exists
+	in enc-proto.h in libtelnet.
+
+
+2001-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* commands.c: Declare sourceroute() static.
+
+2001-07-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* commands.c: Declare local functions static.
+
+	* main.c: Declare usage() static.
+
+	* ring.h: Provide full prototypes for ring_mark() and
+	ring_clear_mark(). 
+
+	* sys_bsd.c: Declare signal handler and NetNonblockingIO static.
+
+	* telnet.c: Declear gettermname() and mklist() static. Change
+	local variable timeout to tmie_out to avoid shadowing curses
+	header file. 
+
+2001-06-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* commands.c (tn): Change sin to sin4 to not shadow global.
+
+	* authenc.c (telnet_gets): Change local variable prompt to tprompt
+	to not shadow global variable.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Test for parsetos() prototype and presence of
+	curses.h and term.h header files.
+
+	* telnet.c: Include term.h and curses.h if present for setupterm()
+	prototype.
+
+	* main.c: Declare prototype for parsetos() if needed.
+
+2001-06-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* telnet.c (telrcv): Ensure variable set before use.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* commands.c: Cast argument to isspace() to int.
+
+	* telnet.c (mklist): Cast argument to islower()/toupper() to int.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* main.c: Include unistd.h (if present) for getopt() prototype.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* authenc.c (telnet_gets): Cleanup assignment in conditional.
+
+	* commands.c: Include sys/wait.h, libtelent/auth.h,
+	libtelnet/encrypt.h for prototypes. Explicity declare functions as
+	returning int. Assignments in conditionals cleanup.
+
+	* externs.h: Add numerous prototypes.
+
+	* ring.c (ring_init): Explicitly declare as returning int.
+
+	* ring.h: Add prototype for ring_at_mark().
+
+	* telnet.c: Include unistd.h, libtelnet/auth.h,
+	libtelnet/encrypt.h for prototypes. Delcare is_unique()
+	static. Fix up format string for sprintf() to expect
+	longs. Assignments in conditionals cleaned up.
+
+	* main.c, terminal.c: Include libtelnet/encrypt.h for prototype. 
+
+	* utilities.c: Include sys/socket.h, libtelent/auth.h,
+	libtelnet/encrypt.h for prototypes.
+
+2001-05-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* telnet.c (telnet): Fix grammar in some error messages.  Based on
+	a patch from Garry Zacheiss.
+
+2000-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* commands.c (tn): Local var "user" should be volatile.
+	* main.c (main): Local var "argp" should be volatile.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_CHECK_HEADER and AC_FUNC_VFORK instead of
+	AC_HEADER_CHECK and AC_VFORK.
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* commands.c (makeargv): Don't overflow buffer "saveline".
+	(tn): Don't overflow buffer "_hostname".
+	(cmdrc): Don't overflow buffer "m1save".
+	* externs.h: Include the size of "tline", so that we can check for
+	overflows elsewhere.
+	* main.c(main, tn370): Don't overflow buffer "tline".
+	* utilities.c (SetNetTrace): Don't overflow buffer "NetTraceFile".
+
+2000-04-28  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* commands.c (cmdrc): Don't overflow buffer "rcbuf".
+	* tn3270.c (settranscom): Don't overflow buffer "transcom".
+
+2000-02-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Remove dependency on libdes425 when krb4 support
+		is not compiled in.
+
+2000-02-16  Ezra Peisach  <epeisach@mit.edu>
+
+	* commands.c: Move include of libtelnet/auth.h earlier to provide
+	prototype for auth_cmd.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-07-26  Tom Yu  <tlyu@mit.edu>
+
+	* telnet.c (telnet): Fix typo in error message, via
+	schwim@whatmore.Stanford.EDU
+
+1999-04-13    <tytso@rsts-11.mit.edu>
+
+	* configure.in: Check for setupterm() in libncurses in addition to
+		libcurses.  (Will be needed for Linux/Redhat 6.0)
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* commands.c: remove calls to setuid(getuid()).  This looks like
+	it was once an attempt to make it safe to run setuid, but it's not
+	safe for a number of other reasons, so there's no reason to
+	pretend.
+
+Sat Oct 10 06:24:55 1998  Geoffrey King  <gjking@mit.edu>
+
+	* telnet.c (telnet): Cosmetic change: Put a newline after "Waiting
+ 	for encryption to be negotiated..." so that the response
+	"[ Kerberos V5 accepts you as ``gjking@ATHENA.MIT.EDU'' ]" doesn't
+ 	run off the end of the line.
+
+Mon Aug 17 04:32:08 1998  Geoffrey King  <gjking@mit.edu>
+
+	* main.c (main): Declare dst_realm_sz as extern int instead of
+ 	extern char, to agree with its definition in libtelnet/kerberos.c.
+	This was causing dst_realm_sz to be zero unexpectedly, and so
+	strncpy was not copying the -k realm argument into dest_realm.
+	[krb5-appl/616]
+	
+Tue May 26 15:27:55 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Re-order check for setupterm to avoid lossage if
+	setupterm is defined in libtermcap or libcurses.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* main.c (main): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+	* configure.in: Use standard autoconf test names. Change tests
+		to define standard autoconf CPP macro names, not the
+		non-standard HAS_GETTOS, etc.
+
+	* main.c, commands.c: Use HAVE_GETTOSBYNAME instead of HAS_GETTOS
+
+	* ring.c, externs.h: Use HAVE_SYS_FILIO_H instead of FILIO_H
+
+Wed Feb 18 15:38:05 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Feb 12 15:23:36 1997  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: Fix DES425_LIB... missed this in libhack_branch;
+	prevents --without-krb4 from working for some odd reason, though
+	comments says "fix post beta-6".
+
+Wed Feb  5 22:03:35 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Tue Nov 26 20:41:31 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: Check for apra/inet.h
+
+	* commands.c: Remove explicit declaration of inet_addr, and
+	declare INADDR_NONE to be 0xffffffff again, but mask off the lower
+	32 bits while doing the compare.
+
+Sat Nov 23 00:33:58 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* commands.c (tn): Patch from mycroft@mit.edu for Alpha NetBSD.
+  	Comparing to -1 is not 64-bit clean.
+ 	[233]
+	(INADDR_NONE): Mycroft suggests using -1 not 0xffffffff if I have
+ 	to define it ourselves. [233]
+
+	Fri Nov 22 15:48:57 1996  unknown  <bjaspan@mit.edu>
+
+	* commands.c (sourceroute): use sizeof instead of h_length to
+ 	determine number of bytes of addr to copy from DNS response
+ 	[krb5-misc/211]
+
+Thu Nov 14 14:25:51 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sys_bsd.c(intr): Added checks to intr_waiting and intr_happened
+		to handle ^C while waiting for encryption negotiation.
+
+	* telnet.c (telnet): Allow ^C to work while waiting for encryption
+		negotiation to finish. [telnet/64]
+
+Sun Nov 10 17:34:40 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* commands.c (tn): Reverse resolve address to deal with dialup
+ 	pools [krb5-libs/170]
+	(tn): Store IP and print in status; patch from jhawk. [113]
+
+Fri Nov  1 00:49:21 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* main.c: Implement Type Of Service patch from jhawk. [57]
+
+Thu Oct 31 18:12:15 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* main.c commands.c: Don't define OPTS_FORWARD* here; include
+ 	libtelnet/auth.h to get them.
+
+	* commands.c (forw_status): Integrate forward command from
+ 	jik@cam.ov.com [45]
+
+Mon Oct 14 02:22:16 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* commands.c (env_cmd): Print only' at correct times.  Patch from
+ 	jhawk. [
+75]
+Sat Sep 21 03:47:46 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* telnet.c (telnet): Only support XDISPLOC if DISPLAY is
+ 	supported, thanks to jik.
+
+	* commands.c (tn): Save away arguments before memory used by other
+ 	functions.  Patch thanks to jik.
+	(env_init): Cannonify DISPLAY; patch thanks to jik.
+
+	* sys_bsd.c: Use POSIX_SIGNALS when available.  This patch is
+ 	contribued by jik.  It could be cleaned up a bit to be more
+ 	consistent with Kerberos style, but is functionally correct.
+
+Tue Sep 10 14:09:49 1996  Tom Yu  <tlyu@mit.edu>
+
+	* telnet.1: remove ".so man1/header.doc"
+	* telnet.1: Update -x flag usage to reflect our behavior of
+		dropping connection if encryption cannot be negotiated.
+
+Sat Jul 27 21:34:22 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* telnet.c(setupterm): Only compile if setupterm not present in
+        library; for Debian Linux and others, you get an endless loop
+        because tcgetent is defined in terms of setupterm, and setupterm
+        in telnet calls tcgetent.
+
+	* configure.in : Check for setupterm
+
+Mon Jun  3 21:31:37 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Ezra's patches to allow compilation w/o krb4
+		support
+
+Mon Mar 18 20:31:44 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Added flags to turn on the encryption option.
+
+	* authenc.c (telnet_spin): Implemented the telnet spin function,
+		which works by calling the Scheduler with the tty_lockout
+		flag set.
+
+	* main.c (main): If the -x option is given, set the autologin,
+		wantencryption, and auth_enable_encrypt flag.  They enable
+		authentication, enforcement of the encryption option, and
+		a flag to the auth layer to negotiate authentication with
+		mandatory encryption option.
+
+	* telnet.c (telnet): If the wantencryption flag is set (because
+		the user has given the -x option, then we enforce that
+		encryption must be turned on.  The user will not be able
+		to type to the network stream until encryption is enabled,
+		and if encryption is refused, the client will print an
+		error message.
+		(Scheduler): If the tty_lockout flag is set, then don't
+		process keyboard read events.  This prevents the user from
+		typing over the network until encryption is enabled.
+
+	* utilities.c (printsub): Added print support for the
+		authentication must-encrypt option.
+
+Sun Feb 25 20:32:57 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Check for arpa/nameser.h
+
+	* commands.c : use MAXDNAME as maximum length of a domain.
+
+Sun Nov 12 04:53:17 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* main.c: initialize line (to avoid splitting up forward.c.)
+
+Mon Aug  7 19:39:36 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS): Add authenc.c to the SRCS list; authenc.o is
+		in the OBJS list, after all.
+
+Fri Jul 7 15:49:55 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling.
+	* configure.in - Add USE_KRB4_LIBRARY and KRB5_LIBRARIES.
+
+Sun Jul  2 04:19:48 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* commands.c: rename setmode() and clearmode() to tel_setmode()
+		and tel_clearmode() to avoid conflicts with setmode()
+		defined in NetBSD unistd.h
+
+Tue Jun 20 14:10:26 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* externs.h: NO_STRING_H -> HAVE_STRING_H
+
+	* configure.in: add test for string.h
+
+Fri Jun 16 09:18:42 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: "install::" to shut up gmake
+
+
+Thu Jun 15 17:41:31 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+		Also, remove DBMLIB, it was not used.
+	* configure.in - Remove dbm library checks, these are no longer needed
+		with the Berkeley database code.  Also, add shared library
+		usage check.
+
+Fri Jun  9 18:29:49 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed May 24 10:00:38 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ring.c: Include string.h or strings.h
+
+	* configure.in: Check for stdlib.h
+
+	* externs.h: Include sys/param.h before redefining BSD
+	            Include stdlib.h or define malloc, realloc, calloc
+
+Fri Apr 28 18:07:03 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (KLIB): put KRB4_LIB inside KLIB.
+
+Thu Apr 27 13:56:12 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (telnet): use KRB4_LIB directly.
+	* configure.in: use WITH_KRB4 as-is.
+
+Fri Apr 21 12:45:40 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* main.c (main): Handle -k if KRB5 is defined. (from ian@cygnus.com)
+
+Wed Mar 29 15:39:02 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Add dependency for libtelnet.a
+
+Tue Mar  7 19:59:07 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: take out ISODE_INCLUDE.
+
+Thu Mar  2 12:30:14 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:25:34 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE and ISODE_DEFS, replace check
+		for -lsocket and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 13:28:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (install): Add $(srcdir) to install line so that
+		installs work correctly when the build tree != the source
+		tree. 
+
+Wed Jan 25 18:33:41 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* telnet.1: refer to man1/tmac.doc.
+	* tmac.doc: actually works with telnet.
+	* Makefile.in (install): install tmac.doc. CLIENT_MANDIR had
+	better be man1.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Thu Dec  1 13:09:34 1994    <tytso@rsx-11.mit.edu>
+
+	* externs.h: If USE_TERMIO is  defined and SYSV_TERMIO isn't,
+		then always #define termio to termios.
+
+	* configure: Set K4LIBS correctly.
+
+Fri Nov 18 01:21:54 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (install): install telnet man page.
+	(from Ted Lemon <mellon@ipd.wellsfargo.com>).
+
+Fri Nov 18 00:38:18 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in (LIBS): use WITH_KRB4, CHECK_SIGNALS, and cache
+	cc_t in termio.h check. (from epeisach)
+	* Makefile.in (K4LIB): set to @K4LIB@ instead of explicit setting.
+	(telnet): link with $(K4LIB). (from epeisach).
+
+Tue Nov  8 01:42:13 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* commands.c (EncryptList): Fix spelling typo.
+
+Mon Nov  7 22:40:17 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* commands.c (auth_cmd, encrypt_cmd): Print an error message if
+		there are no arguments to "auth" or "encrypt", instead of
+		core dumping.
+
+	* commands.c (auth_enable, auth_disable): Change prototypes of
+		these routines to be a char *.
+
+Mon Oct  3 13:28:04 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* externs.h: The proper place to look for termios.h is
+		<termios.h>, not <sys/termios.h>. 
+
+Thu Sep 29 22:51:39 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executables if libraries change
+
+Tue Aug 16 18:07:54 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* externs.h: don't hide termdata under defined(unix).
+	* commands.c: ditto.
+
+Tue Aug 16 18:00:48 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in: use AC_VFORK (runtime test -- consider just using
+	fork instead.)
+	* commands.c: check HAVE_VFORK_H.
+
+Tue Aug  9 04:02:28 1994  Mark Eichin  (eichin@tess-turbo)
+
+	* configure.in: test for -lsocket, -lnsl, POSIX_SIGNALS
+	* sys_bsd.c: use POSIX_SIGNALS.
+	* commands.c: don't use Berzerkely-style string functions.
+
+Sat Aug  6 18:05:42 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* commands.c: in_systm.h is *not* broken on linux with 4.5 libc.
+
+Thu Aug  4 03:36:59 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in:
+	* configure.in: make install fixes
+
+Wed Jul 27 22:49:18 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: add check for dbm libs
+
+	* commands.c: linux in_system.h (note "e") is broken
+
+Tue Jul 26 18:22:00 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: forgot some $(srcdir) stuff
+
diff --git a/mechglue/src/appl/telnet/telnet/Makefile.4.4 b/mechglue/src/appl/telnet/telnet/Makefile.4.4
new file mode 100644
index 000000000..2e38a2880
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/Makefile.4.4
@@ -0,0 +1,73 @@
+#
+# Copyright (c) 1990 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#	This product includes software developed by the University of
+#	California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#	@(#)Makefile	8.1 (Berkeley) 6/6/93
+#
+
+PROG=	telnet
+
+CFLAGS+=-DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DAUTHENTICATION -DENCRYPTION
+CFLAGS+=-DENV_HACK
+CFLAGS+=-I${.CURDIR}/../../lib
+
+CFLAGS+= -DKRB4
+
+LDADD=	-ltermcap -ltelnet
+LDADD+=	-lkrb -ldes
+DPADD=	${LIBTERMCAP}
+
+SRCS=	authenc.c commands.c main.c network.c ring.c sys_bsd.c telnet.c \
+	terminal.c tn3270.c utilities.c
+
+# These are the sources that have encryption stuff in them.
+CRYPT_SRC= authenc.c commands.c externs.h main.c network.c
+CRYPT_SRC+= ring.c ring.h telnet.c terminal.c utilities.c Makefile
+NOCRYPT_DIR=${.CURDIR}/Nocrypt
+
+.include <bsd.prog.mk>
+
+nocrypt:
+#ifdef	ENCRYPTION
+	@for i in ${CRYPT_SRC}; do \
+	    if [ ! -d ${NOCRYPT_DIR} ]; then \
+		echo Creating subdirectory ${NOCRYPT_DIR}; \
+		mkdir ${NOCRYPT_DIR}; \
+	    fi; \
+	    echo ${NOCRYPT_DIR}/$$i; \
+	    unifdef -UENCRYPTION ${.CURDIR}/$$i | \
+		sed "s/ || defined(ENCRYPTION)//" > ${NOCRYPT_DIR}/$$i; \
+	done
+
+placeholder:
+#else	/* ENCRYPTION */
+	@echo "Encryption code already removed."
+#endif	/* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/telnet/Makefile.generic b/mechglue/src/appl/telnet/telnet/Makefile.generic
new file mode 100644
index 000000000..5b6ea2651
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/Makefile.generic
@@ -0,0 +1,89 @@
+#
+# Copyright (c) 1991 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted provided
+# that: (1) source distributions retain this entire copyright notice and
+# comment, and (2) distributions including binaries display the following
+# acknowledgement:  ``This product includes software developed by the
+# University of California, Berkeley and its contributors'' in the
+# documentation or other materials provided with the distribution and in
+# all advertising materials mentioning features or use of this software.
+# Neither the name of the University nor the names of its contributors may
+# be used to endorse or promote products derived from this software without
+# specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#	@(#)Makefile.generic	5.5 (Berkeley) 3/1/91
+#
+
+INCLUDES= -I..
+ARPA_TELNET= ../arpa/telnet.h
+
+SRCS=	commands.c main.c network.c ring.c \
+	sys_bsd.c telnet.c terminal.c \
+	utilities.c ${GETOPT_SRC}
+
+CFLAGS=	${LCCFLAGS} ${INCLUDES} ${DEFINES}
+
+ALLHC=	${SRCS} \
+	defines.h externs.h fdset.h general.h \
+	ring.h types.h
+
+OBJS=	authenc.o commands.o main.o network.o ring.o sys_bsd.o \
+	telnet.o terminal.o utilities.o ${GETOPT_OBJ}
+MAN=	telnet.0
+
+#
+# These next three lines are not needed in 4.4BSD
+#
+.SUFFIXES: .0 .1
+.1.0:
+	nroff -man -h $< > $@
+
+all: telnet
+
+telnet:	${OBJS} ${LIBPATH}
+	${CC} -o $@ ${CFLAGS} ${OBJS} ${LIBS}
+
+clean: FRC
+	rm -f ${OBJS} core errs l.errs telnet
+
+cleandir: clean
+	rm -f ${MAN} tags .depend
+
+clist:	FRC ${SRCS}
+	@for i in ${SRCS} ; \
+		do (echo ${DIRPATH}$$i); done
+
+hclist:	FRC ${ALLHC}
+	@for i in ${ALLHC} ; \
+		do (echo ${DIRPATH}$$i); done
+
+depend: FRC ${SRCS}
+	mkdep ${CFLAGS} `make clist`
+
+install: ${MAN} FRC
+	install -s -o bin -g bin -m 755 telnet ${DEST}
+	install -c -o bin -g bin -m 444 telnet.0 ${DESTDIR}/usr/man/cat1
+
+lint: FRC ${SRCS}
+	lint ${CFLAGS} `make clist`
+
+tags: FRC ${SRCS}
+	ctags `make hclist`
+
+FRC:
+
+authenc.o: defines.h externs.h general.h ring.h types.h ${ARPA_TELNET}
+commands.o: defines.h externs.h general.h ring.h types.h ${ARPA_TELNET}
+main.o: defines.h externs.h ring.h
+network.o: defines.h externs.h fdset.h ring.h ${ARPA_TELNET}
+ring.o: general.h ring.h
+sys_bsd.o: defines.h externs.h fdset.h ring.h types.h ${ARPA_TELNET}
+telnet.o: defines.h externs.h general.h ring.h types.h ${ARPA_TELNET}
+terminal.o: externs.h ring.h types.h ${ARPA_TELNET}
+tn3270.o: defines.h externs.h fdset.h general.h ring.h ${ARPA_TELNET}
+utilities.o: defines.h externs.h fdset.h general.h ring.h ${ARPA_TELNET}
diff --git a/mechglue/src/appl/telnet/telnet/Makefile.in b/mechglue/src/appl/telnet/telnet/Makefile.in
new file mode 100644
index 000000000..7c3d81e50
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/Makefile.in
@@ -0,0 +1,110 @@
+thisconfigdir=..
+myfulldir=appl/telnet/telnet
+mydir=telnet
+BUILDTOP=$(REL)..$(S)..$(S)..
+# derived from the original Makefile.generic
+#
+# Copyright (c) 1991 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted provided
+# that: (1) source distributions retain this entire copyright notice and
+# comment, and (2) distributions including binaries display the following
+# acknowledgement:  ``This product includes software developed by the
+# University of California, Berkeley and its contributors'' in the
+# documentation or other materials provided with the distribution and in
+# all advertising materials mentioning features or use of this software.
+# Neither the name of the University nor the names of its contributors may
+# be used to endorse or promote products derived from this software without
+# specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#	@(#)Makefile.generic	5.5 (Berkeley) 3/1/91
+#
+
+AUTH_DEF=-DAUTHENTICATION -DENCRYPTION -DKRB5 -DFORWARD -UNO_LOGIN_F -DLOGIN_CAP_F -DLOGIN_PROGRAM=KRB5_PATH_LOGIN
+OTHERDEFS=-DLINEMODE -DKLUDGELINEMODE -DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON
+LOCALINCLUDES=-I.. -I$(srcdir)/..
+DEFINES = $(AUTH_DEF) $(OTHERDEFS)
+ARPA_TELNET= $(srcdir)/../arpa/telnet.h
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+LIBS=	@TELNET_LIBS@
+
+SRCS=	$(srcdir)/authenc.c $(srcdir)/commands.c $(srcdir)/main.c $(srcdir)/network.c $(srcdir)/ring.c \
+	$(srcdir)/sys_bsd.c $(srcdir)/telnet.c $(srcdir)/terminal.c \
+	$(srcdir)/utilities.c $(GETOPT_SRC)
+ALLHC=	$(SRCS) \
+	defines.h externs.h fdset.h general.h \
+	ring.h types.h
+
+OBJS=	authenc.o commands.o main.o network.o ring.o sys_bsd.o \
+	telnet.o terminal.o utilities.o $(GETOPT_OBJ)
+
+all:: telnet
+
+telnet:	$(OBJS) $(KRB4COMPAT_DEPLIBS) ../libtelnet/libtelnet.a
+	$(CC_LINK) -o $@ $(OBJS) ../libtelnet/libtelnet.a $(KRB4COMPAT_LIBS)
+
+clean::
+	$(RM) telnet
+
+install::
+	for f in telnet; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.1 \
+		${DESTDIR}$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
+	$(INSTALL_DATA) $(srcdir)/tmac.doc ${DESTDIR}$(CLIENT_MANDIR)/tmac.doc
+
+authenc.o: defines.h externs.h general.h ring.h types.h $(ARPA_TELNET)
+commands.o: defines.h externs.h general.h ring.h types.h $(ARPA_TELNET)
+main.o: defines.h externs.h ring.h
+network.o: defines.h externs.h fdset.h ring.h $(ARPA_TELNET)
+ring.o: general.h ring.h
+sys_bsd.o: defines.h externs.h fdset.h ring.h types.h $(ARPA_TELNET)
+telnet.o: defines.h externs.h general.h ring.h types.h $(ARPA_TELNET)
+terminal.o: externs.h ring.h types.h $(ARPA_TELNET)
+tn3270.o: defines.h externs.h fdset.h general.h ring.h $(ARPA_TELNET)
+utilities.o: defines.h externs.h fdset.h general.h ring.h $(ARPA_TELNET)
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)authenc.$(OBJEXT): authenc.c $(srcdir)/../arpa/telnet.h \
+  $(srcdir)/../libtelnet/encrypt.h $(srcdir)/../libtelnet/enc-proto.h \
+  $(srcdir)/../libtelnet/misc.h $(srcdir)/../libtelnet/misc-proto.h \
+  general.h ring.h externs.h defines.h types.h
+$(OUTPRE)commands.$(OBJEXT): commands.c $(srcdir)/../arpa/telnet.h \
+  general.h ring.h externs.h defines.h types.h $(srcdir)/../libtelnet/auth.h \
+  $(srcdir)/../libtelnet/auth-proto.h $(srcdir)/../libtelnet/encrypt.h \
+  $(srcdir)/../libtelnet/enc-proto.h $(srcdir)/../libtelnet/misc-proto.h \
+  $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h
+$(OUTPRE)main.$(OBJEXT): main.c $(srcdir)/../libtelnet/auth.h \
+  $(srcdir)/../libtelnet/auth-proto.h $(srcdir)/../libtelnet/encrypt.h \
+  $(srcdir)/../libtelnet/enc-proto.h ring.h externs.h \
+  defines.h
+$(OUTPRE)network.$(OBJEXT): network.c $(srcdir)/../arpa/telnet.h \
+  ring.h defines.h externs.h fdset.h
+$(OUTPRE)ring.$(OBJEXT): ring.c ring.h general.h
+$(OUTPRE)sys_bsd.$(OBJEXT): sys_bsd.c $(srcdir)/../arpa/telnet.h \
+  ring.h fdset.h defines.h externs.h types.h
+$(OUTPRE)telnet.$(OBJEXT): telnet.c $(srcdir)/../arpa/telnet.h \
+  ring.h defines.h externs.h types.h general.h $(srcdir)/../libtelnet/auth.h \
+  $(srcdir)/../libtelnet/auth-proto.h $(srcdir)/../libtelnet/encrypt.h \
+  $(srcdir)/../libtelnet/enc-proto.h $(srcdir)/../libtelnet/misc-proto.h
+$(OUTPRE)terminal.$(OBJEXT): terminal.c $(srcdir)/../arpa/telnet.h \
+  ring.h externs.h types.h $(srcdir)/../libtelnet/encrypt.h \
+  $(srcdir)/../libtelnet/enc-proto.h
+$(OUTPRE)utilities.$(OBJEXT): utilities.c $(srcdir)/../arpa/telnet.h \
+  general.h fdset.h ring.h defines.h externs.h $(srcdir)/../libtelnet/auth.h \
+  $(srcdir)/../libtelnet/auth-proto.h $(srcdir)/../libtelnet/encrypt.h \
+  $(srcdir)/../libtelnet/enc-proto.h
diff --git a/mechglue/src/appl/telnet/telnet/authenc.c b/mechglue/src/appl/telnet/telnet/authenc.c
new file mode 100644
index 000000000..aa4459f27
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/authenc.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)authenc.c	8.1 (Berkeley) 6/6/93 */
+
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
+#include <sys/types.h>
+#include <arpa/telnet.h>
+#include <libtelnet/encrypt.h>
+#include <libtelnet/misc.h>
+
+#include "general.h"
+#include "ring.h"
+#include "externs.h"
+#include "defines.h"
+#include "types.h"
+
+	int
+net_write(str, len)
+	unsigned char *str;
+	int len;
+{
+	if (NETROOM() > len) {
+		ring_supply_data(&netoring, str, len);
+		if (str[0] == IAC && str[1] == SE)
+			printsub('>', &str[2], len-2);
+		return(len);
+	}
+	return(0);
+}
+
+	void
+net_encrypt()
+{
+#ifdef	ENCRYPTION
+	if (encrypt_output)
+		ring_encrypt(&netoring, encrypt_output);
+	else
+		ring_clearto(&netoring);
+#endif	/* ENCRYPTION */
+}
+
+	int
+telnet_spin()
+{
+    extern int scheduler_lockout_tty;
+
+    scheduler_lockout_tty = 1;
+    Scheduler(0);
+    scheduler_lockout_tty = 0;
+    
+    return 0;
+}
+
+	char *
+telnet_getenv(val)
+	char *val;
+{
+	return((char *)env_getvalue((unsigned char *)val));
+}
+
+	char *
+telnet_gets(tprompt, result, length, echo)
+	char *tprompt;
+	char *result;
+	int length;
+	int echo;
+{
+	extern char *getpass();
+	extern int globalmode;
+	int om = globalmode;
+	char *res;
+
+	TerminalNewMode(-1);
+	if (echo) {
+		printf("%s", tprompt);
+		res = fgets(result, length, stdin);
+	} else if ((res = getpass(tprompt))) {
+		strncpy(result, res, (unsigned) length);
+		res = result;
+	}
+	TerminalNewMode(om);
+	return(res);
+}
+#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
diff --git a/mechglue/src/appl/telnet/telnet/commands.c b/mechglue/src/appl/telnet/telnet/commands.c
new file mode 100644
index 000000000..cb3390d38
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/commands.c
@@ -0,0 +1,3191 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)commands.c	8.1 (Berkeley) 6/6/93 */
+
+#if	defined(unix)
+#include <sys/param.h>
+#if	defined(CRAY) || defined(sysV88)
+#include <sys/types.h>
+#endif
+#include <sys/file.h>
+#else
+#include <sys/types.h>
+#endif	/* defined(unix) */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif /* HAVE_ARPA_INET_H */
+#ifdef	CRAY
+#include <fcntl.h>
+#endif	/* CRAY */
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <pwd.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+
+#include <arpa/telnet.h>
+
+#include "general.h"
+
+#include "ring.h"
+
+#include "externs.h"
+#include "defines.h"
+#include "types.h"
+
+#if defined(AUTHENTICATION) || defined(FORWARD)
+#include <libtelnet/auth.h>
+#endif
+
+#ifdef	ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
+#include <libtelnet/misc-proto.h>
+#endif
+
+#if !defined(CRAY) && !defined(sysV88)
+#include <netinet/in_systm.h>
+# if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
+# include <machine/endian.h>
+# endif /* vax */
+#endif /* !defined(CRAY) && !defined(sysV88) */
+#include <netinet/ip.h>
+
+
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#include <netdb.h>
+
+#ifndef MAXDNAME
+#define MAXDNAME 256 /*per the rfc*/
+#endif
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+#if	defined(IPPROTO_IP) && defined(IP_TOS)
+int tos = -1;
+static	unsigned long sourceroute(char *, char **, int *);
+#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
+
+#include "fake-addrinfo.h"
+
+char	*hostname;
+static char _hostname[MAXDNAME];
+static char hostaddrstring[NI_MAXHOST];
+
+extern char *getenv();
+
+extern int isprefix();
+extern char **genget();
+extern int Ambiguous();
+
+typedef int (*intrtn_t)();
+static int call (intrtn_t, ...);
+void cmdrc (char *, char *);
+static    int
+send_tncmd (void (*func)(), char *, char *);
+static int help(int, char **);
+
+#ifdef NEED_HERROR_PROTO
+extern void herror(const char *);
+#endif
+
+typedef struct {
+	char	*name;		/* command name */
+	char	*help;		/* help string (NULL for no help) */
+	int	(*handler)	/* routine which executes command */
+                        (int, char *[]);
+	int	needconnect;	/* Do we need to be connected to execute? */
+} Command;
+
+static char line[256];
+static char saveline[256];
+static int margc;
+static char *margv[20];
+
+    static void
+makeargv()
+{
+    register char *cp, *cp2, c;
+    register char **argp = margv;
+
+    margc = 0;
+    cp = line;
+    if (*cp == '!') {		/* Special case shell escape */
+	strncpy(saveline, line, sizeof(saveline) - 1);
+				/* save for shell command */
+	saveline[sizeof(saveline)  - 1] = '\0';
+	*argp++ = "!";		/* No room in string to get this */
+	margc++;
+	cp++;
+    }
+    while ((c = *cp)) {
+	register int inquote = 0;
+	while (isspace((int) c))
+	    c = *++cp;
+	if (c == '\0')
+	    break;
+	*argp++ = cp;
+	margc += 1;
+	for (cp2 = cp; c != '\0'; c = *++cp) {
+	    if (inquote) {
+		if (c == inquote) {
+		    inquote = 0;
+		    continue;
+		}
+	    } else {
+		if (c == '\\') {
+		    if ((c = *++cp) == '\0')
+			break;
+		} else if (c == '"') {
+		    inquote = '"';
+		    continue;
+		} else if (c == '\'') {
+		    inquote = '\'';
+		    continue;
+		} else if (isspace((int) c))
+		    break;
+	    }
+	    *cp2++ = c;
+	}
+	*cp2 = '\0';
+	if (c == '\0')
+	    break;
+	cp++;
+    }
+    *argp++ = 0;
+}
+
+/*
+ * Make a character string into a number.
+ *
+ * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
+ */
+
+	static int
+special(s)
+	register char *s;
+{
+	register char c;
+	char b;
+
+	switch (*s) {
+	case '^':
+		b = *++s;
+		if (b == '?') {
+		    c = b | 0x40;		/* DEL */
+		} else {
+		    c = b & 0x1f;
+		}
+		break;
+	default:
+		c = *s;
+		break;
+	}
+	return c;
+}
+
+/*
+ * Construct a control character sequence
+ * for a special character.
+ */
+	static char *
+control(c)
+	register cc_t c;
+{
+	static char buf[5];
+	/*
+	 * The only way I could get the Sun 3.5 compiler
+	 * to shut up about
+	 *	if ((unsigned int)c >= 0x80)
+	 * was to assign "c" to an unsigned int variable...
+	 * Arggg....
+	 */
+	register unsigned int uic = (unsigned int)c;
+
+	if (uic == 0x7f)
+		return ("^?");
+	if (c == (cc_t)_POSIX_VDISABLE) {
+		return "off";
+	}
+	if (uic >= 0x80) {
+		buf[0] = '\\';
+		buf[1] = ((c>>6)&07) + '0';
+		buf[2] = ((c>>3)&07) + '0';
+		buf[3] = (c&07) + '0';
+		buf[4] = 0;
+	} else if (uic >= 0x20) {
+		buf[0] = c;
+		buf[1] = 0;
+	} else {
+		buf[0] = '^';
+		buf[1] = '@'+c;
+		buf[2] = 0;
+	}
+	return (buf);
+}
+
+
+
+/*
+ *	The following are data structures and routines for
+ *	the "send" command.
+ *
+ */
+ 
+struct sendlist {
+    char	*name;		/* How user refers to it (case independent) */
+    char	*help;		/* Help information (0 ==> no help) */
+    int		needconnect;	/* Need to be connected */
+    int		narg;		/* Number of arguments */
+    int		(*handler)	/* Routine to perform (for special ops) */
+			(char *);
+    int		nbyte;		/* Number of bytes to send this command */
+    int		what;		/* Character to be sent (<0 ==> special) */
+};
+
+
+static int
+	send_esc (char *),
+	send_help (char *),
+	send_docmd (char *),
+	send_dontcmd (char *),
+	send_willcmd (char *),
+	send_wontcmd (char *);
+
+static struct sendlist Sendlist[] = {
+    { "ao",	"Send Telnet Abort output",		1, 0, 0, 2, AO },
+    { "ayt",	"Send Telnet 'Are You There'",		1, 0, 0, 2, AYT },
+    { "brk",	"Send Telnet Break",			1, 0, 0, 2, BREAK },
+    { "break",	0,					1, 0, 0, 2, BREAK },
+    { "ec",	"Send Telnet Erase Character",		1, 0, 0, 2, EC },
+    { "el",	"Send Telnet Erase Line",		1, 0, 0, 2, EL },
+    { "escape",	"Send current escape character",	1, 0, send_esc, 1, 0 },
+    { "ga",	"Send Telnet 'Go Ahead' sequence",	1, 0, 0, 2, GA },
+    { "ip",	"Send Telnet Interrupt Process",	1, 0, 0, 2, IP },
+    { "intp",	0,					1, 0, 0, 2, IP },
+    { "interrupt", 0,					1, 0, 0, 2, IP },
+    { "intr",	0,					1, 0, 0, 2, IP },
+    { "nop",	"Send Telnet 'No operation'",		1, 0, 0, 2, NOP },
+    { "eor",	"Send Telnet 'End of Record'",		1, 0, 0, 2, EOR },
+    { "abort",	"Send Telnet 'Abort Process'",		1, 0, 0, 2, ABORT },
+    { "susp",	"Send Telnet 'Suspend Process'",	1, 0, 0, 2, SUSP },
+    { "eof",	"Send Telnet End of File Character",	1, 0, 0, 2, xEOF },
+    { "synch",	"Perform Telnet 'Synch operation'",	1, 0, dosynch, 2, 0 },
+    { "getstatus", "Send request for STATUS",		1, 0, get_status, 6, 0 },
+    { "?",	"Display send options",			0, 0, send_help, 0, 0 },
+    { "help",	0,					0, 0, send_help, 0, 0 },
+    { "do",	0,					0, 1, send_docmd, 3, 0 },
+    { "dont",	0,					0, 1, send_dontcmd, 3, 0 },
+    { "will",	0,					0, 1, send_willcmd, 3, 0 },
+    { "wont",	0,					0, 1, send_wontcmd, 3, 0 },
+    { 0 }
+};
+
+#define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
+				sizeof(struct sendlist)))
+
+    static int
+sendcmd(argc, argv)
+    int  argc;
+    char **argv;
+{
+    int count;		/* how many bytes we are going to need to send */
+    int i;
+    struct sendlist *s;	/* pointer to current command */
+    int success = 0;
+    int needconnect = 0;
+
+    if (argc < 2) {
+	printf("need at least one argument for 'send' command\r\n");
+	printf("'send ?' for help\n");
+	return 0;
+    }
+    /*
+     * First, validate all the send arguments.
+     * In addition, we see how much space we are going to need, and
+     * whether or not we will be doing a "SYNCH" operation (which
+     * flushes the network queue).
+     */
+    count = 0;
+    for (i = 1; i < argc; i++) {
+	s = GETSEND(argv[i]);
+	if (s == 0) {
+	    printf("Unknown send argument '%s'\n'send ?' for help.\r\n",
+			argv[i]);
+	    return 0;
+	} else if (Ambiguous(s)) {
+	    printf("Ambiguous send argument '%s'\n'send ?' for help.\r\n",
+			argv[i]);
+	    return 0;
+	}
+	if (i + s->narg >= argc) {
+	    fprintf(stderr,
+	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
+		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
+	    return 0;
+	}
+	count += s->nbyte;
+	if (s->handler == send_help) {
+	    send_help(NULL);
+	    return 0;
+	}
+
+	i += s->narg;
+	needconnect += s->needconnect;
+    }
+    if (!connected && needconnect) {
+	printf("?Need to be connected first.\r\n");
+	printf("'send ?' for help\r\n");
+	return 0;
+    }
+    /* Now, do we have enough room? */
+    if (NETROOM() < count) {
+	printf("There is not enough room in the buffer TO the network\r\n");
+	printf("to process your request.  Nothing will be done.\r\n");
+	printf("('send synch' will throw away most data in the network\r\n");
+	printf("buffer, if this might help.)\r\n");
+	return 0;
+    }
+    /* OK, they are all OK, now go through again and actually send */
+    count = 0;
+    for (i = 1; i < argc; i++) {
+	if ((s = GETSEND(argv[i])) == 0) {
+	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
+	    (void) quit(0, NULL);
+	    /*NOTREACHED*/
+	}
+	if (s->handler) {
+	    count++;
+	    success += (*s->handler)(argv[i+1]);
+	    i += s->narg;
+	} else {
+	    NET2ADD(IAC, s->what);
+	    printoption("SENT", IAC, s->what);
+	}
+    }
+    return (count == success);
+}
+
+    static int
+send_esc(s)
+    char *s;
+{
+    NETADD(escape);
+    return 1;
+}
+
+    static int
+send_docmd(name)
+    char *name;
+{
+    return(send_tncmd(send_do, "do", name));
+}
+
+    static int
+send_dontcmd(name)
+    char *name;
+{
+    return(send_tncmd(send_dont, "dont", name));
+}
+    static int
+send_willcmd(name)
+    char *name;
+{
+    return(send_tncmd(send_will, "will", name));
+}
+    static int
+send_wontcmd(name)
+    char *name;
+{
+    return(send_tncmd(send_wont, "wont", name));
+}
+
+static    int
+send_tncmd(func, cmd, name)
+    void	(*func)();
+    char	*cmd, *name;
+{
+    char **cpp;
+    extern char *telopts[];
+    register int val = 0;
+
+    if (isprefix(name, "help") || isprefix(name, "?")) {
+	register int col, len;
+
+	printf("Usage: send %s <value|option>\r\n", cmd);
+	printf("\"value\" must be from 0 to 255\r\n");
+	printf("Valid options are:\r\n\t");
+
+	col = 8;
+	for (cpp = telopts; *cpp; cpp++) {
+	    len = strlen(*cpp) + 3;
+	    if (col + len > 65) {
+		printf("\r\n\t");
+		col = 8;
+	    }
+	    printf(" \"%s\"", *cpp);
+	    col += len;
+	}
+	printf("\r\n");
+	return 0;
+    }
+    cpp = (char **)genget(name, telopts, sizeof(char *));
+    if (Ambiguous(cpp)) {
+	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
+					name, cmd);
+	return 0;
+    }
+    if (cpp) {
+	val = cpp - telopts;
+    } else {
+	register char *cp = name;
+
+	while (*cp >= '0' && *cp <= '9') {
+	    val *= 10;
+	    val += *cp - '0';
+	    cp++;
+	}
+	if (*cp != 0) {
+	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
+					name, cmd);
+	    return 0;
+	} else if (val < 0 || val > 255) {
+	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
+					name, cmd);
+	    return 0;
+	}
+    }
+    if (!connected) {
+	printf("?Need to be connected first.\r\n");
+	return 0;
+    }
+    (*func)(val, 1);
+    return 1;
+}
+
+    static int
+send_help(n)
+     char *n;
+{
+    struct sendlist *s;	/* pointer to current command */
+    for (s = Sendlist; s->name; s++) {
+	if (s->help)
+	    printf("%-15s %s\r\n", s->name, s->help);
+    }
+    return(0);
+}
+
+/*
+ * The following are the routines and data structures referred
+ * to by the arguments to the "toggle" command.
+ */
+
+    static int
+lclchars(s)
+     int s;
+{
+    donelclchars = 1;
+    return 1;
+}
+
+    static int
+togdebug(s)
+     int s;
+{
+#ifndef	NOT43
+    if (net > 0 &&
+	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
+	    perror("setsockopt (SO_DEBUG)");
+    }
+#else	/* NOT43 */
+    if (debug) {
+	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
+	    perror("setsockopt (SO_DEBUG)");
+    } else
+	printf("Cannot turn off socket debugging\r\n");
+#endif	/* NOT43 */
+    return 1;
+}
+
+
+    static int
+togcrlf(s)
+     int s;
+{
+    if (crlf) {
+	printf("Will send carriage returns as telnet <CR><LF>.\r\n");
+    } else {
+	printf("Will send carriage returns as telnet <CR><NUL>.\r\n");
+    }
+    return 1;
+}
+
+int binmode;
+
+    static int
+togbinary(val)
+    int val;
+{
+    donebinarytoggle = 1;
+
+    if (val >= 0) {
+	binmode = val;
+    } else {
+	if (my_want_state_is_will(TELOPT_BINARY) &&
+				my_want_state_is_do(TELOPT_BINARY)) {
+	    binmode = 1;
+	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
+				my_want_state_is_dont(TELOPT_BINARY)) {
+	    binmode = 0;
+	}
+	val = binmode ? 0 : 1;
+    }
+
+    if (val == 1) {
+	if (my_want_state_is_will(TELOPT_BINARY) &&
+					my_want_state_is_do(TELOPT_BINARY)) {
+	    printf("Already operating in binary mode with remote host.\r\n");
+	} else {
+	    printf("Negotiating binary mode with remote host.\r\n");
+	    tel_enter_binary(3);
+	}
+    } else {
+	if (my_want_state_is_wont(TELOPT_BINARY) &&
+					my_want_state_is_dont(TELOPT_BINARY)) {
+	    printf("Already in network ascii mode with remote host.\r\n");
+	} else {
+	    printf("Negotiating network ascii mode with remote host.\r\n");
+	    tel_leave_binary(3);
+	}
+    }
+    return 1;
+}
+
+    static int
+togrbinary(val)
+    int val;
+{
+    donebinarytoggle = 1;
+
+    if (val == -1)
+	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
+
+    if (val == 1) {
+	if (my_want_state_is_do(TELOPT_BINARY)) {
+	    printf("Already receiving in binary mode.\r\n");
+	} else {
+	    printf("Negotiating binary mode on input.\r\n");
+	    tel_enter_binary(1);
+	}
+    } else {
+	if (my_want_state_is_dont(TELOPT_BINARY)) {
+	    printf("Already receiving in network ascii mode.\r\n");
+	} else {
+	    printf("Negotiating network ascii mode on input.\r\n");
+	    tel_leave_binary(1);
+	}
+    }
+    return 1;
+}
+
+    static int
+togxbinary(val)
+    int val;
+{
+    donebinarytoggle = 1;
+
+    if (val == -1)
+	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
+
+    if (val == 1) {
+	if (my_want_state_is_will(TELOPT_BINARY)) {
+	    printf("Already transmitting in binary mode.\r\n");
+	} else {
+	    printf("Negotiating binary mode on output.\r\n");
+	    tel_enter_binary(2);
+	}
+    } else {
+	if (my_want_state_is_wont(TELOPT_BINARY)) {
+	    printf("Already transmitting in network ascii mode.\r\n");
+	} else {
+	    printf("Negotiating network ascii mode on output.\r\n");
+	    tel_leave_binary(2);
+	}
+    }
+    return 1;
+}
+
+
+static int togglehelp (int);
+#if	defined(AUTHENTICATION)
+extern int auth_togdebug (int);
+#endif
+
+struct togglelist {
+    char	*name;		/* name of toggle */
+    char	*help;		/* help message */
+    int		(*handler)	/* routine to do actual setting */
+			(int);
+    int		*variable;
+    char	*actionexplanation;
+};
+
+static struct togglelist Togglelist[] = {
+    { "autoflush",
+	"flushing of output when sending interrupt characters",
+	    0,
+		&autoflush,
+		    "flush output when sending interrupt characters" },
+    { "autosynch",
+	"automatic sending of interrupt characters in urgent mode",
+	    0,
+		&autosynch,
+		    "send interrupt characters in urgent mode" },
+#if	defined(AUTHENTICATION)
+    { "autologin",
+	"automatic sending of login and/or authentication info",
+	    0,
+		&autologin,
+		    "send login name and/or authentication information" },
+    { "authdebug",
+	"Toggle authentication debugging",
+	    auth_togdebug,
+		0,
+		     "print authentication debugging information" },
+#endif
+#ifdef	ENCRYPTION
+    { "autoencrypt",
+	"automatic encryption of data stream",
+	    EncryptAutoEnc,
+		0,
+		    "automatically encrypt output" },
+    { "autodecrypt",
+	"automatic decryption of data stream",
+	    EncryptAutoDec,
+		0,
+		    "automatically decrypt input" },
+    { "verbose_encrypt",
+	"Toggle verbose encryption output",
+	    EncryptVerbose,
+		0,
+		    "print verbose encryption output" },
+    { "encdebug",
+	"Toggle encryption debugging",
+	    EncryptDebug,
+		0,
+		    "print encryption debugging information" },
+#endif	/* ENCRYPTION */
+    { "skiprc",
+	"don't read ~/.telnetrc file",
+	    0,
+		&skiprc,
+		    "skip reading of ~/.telnetrc file" },
+    { "binary",
+	"sending and receiving of binary data",
+	    togbinary,
+		0,
+		    0 },
+    { "inbinary",
+	"receiving of binary data",
+	    togrbinary,
+		0,
+		    0 },
+    { "outbinary",
+	"sending of binary data",
+	    togxbinary,
+		0,
+		    0 },
+    { "crlf",
+	"sending carriage returns as telnet <CR><LF>",
+	    togcrlf,
+		&crlf,
+		    0 },
+    { "crmod",
+	"mapping of received carriage returns",
+	    0,
+		&crmod,
+		    "map carriage return on output" },
+    { "localchars",
+	"local recognition of certain control characters",
+	    lclchars,
+		&localchars,
+		    "recognize certain control characters" },
+    { " ", "", 0 },		/* empty line */
+#if	defined(unix) && defined(TN3270)
+    { "apitrace",
+	"(debugging) toggle tracing of API transactions",
+	    0,
+		&apitrace,
+		    "trace API transactions" },
+    { "cursesdata",
+	"(debugging) toggle printing of hexadecimal curses data",
+	    0,
+		&cursesdata,
+		    "print hexadecimal representation of curses data" },
+#endif	/* defined(unix) && defined(TN3270) */
+    { "debug",
+	"debugging",
+	    togdebug,
+		&debug,
+		    "turn on socket level debugging" },
+    { "netdata",
+	"printing of hexadecimal network data (debugging)",
+	    0,
+		&netdata,
+		    "print hexadecimal representation of network traffic" },
+    { "prettydump",
+	"output of \"netdata\" to user readable format (debugging)",
+	    0,
+		&prettydump,
+		    "print user readable output for \"netdata\"" },
+    { "options",
+	"viewing of options processing (debugging)",
+	    0,
+		&showoptions,
+		    "show option processing" },
+    { "termdata",
+	"(debugging) toggle printing of hexadecimal terminal data",
+	    0,
+		&termdata,
+		    "print hexadecimal representation of terminal traffic" },
+    { "?",
+	0,
+	    togglehelp },
+    { "help",
+	0,
+	    togglehelp },
+    { 0 }
+};
+
+    static int
+togglehelp(n)
+    int n;
+{
+    struct togglelist *c;
+
+    for (c = Togglelist; c->name; c++) {
+	if (c->help) {
+	    if (*c->help)
+		printf("%-15s toggle %s\r\n", c->name, c->help);
+	    else
+		printf("\r\n");
+	}
+    }
+    printf("\r\n");
+    printf("%-15s %s\r\n", "?", "display help information");
+    return 0;
+}
+
+    static void
+settogglehelp(set)
+    int set;
+{
+    struct togglelist *c;
+
+    for (c = Togglelist; c->name; c++) {
+	if (c->help) {
+	    if (*c->help)
+		printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable",
+						c->help);
+	    else
+		printf("\r\n");
+	}
+    }
+}
+
+#define	GETTOGGLE(name) (struct togglelist *) \
+		genget(name, (char **) Togglelist, sizeof(struct togglelist))
+
+    static int
+toggle(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    int retval = 1;
+    char *name;
+    struct togglelist *c;
+
+    if (argc < 2) {
+	fprintf(stderr,
+	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
+	return 0;
+    }
+    argc--;
+    argv++;
+    while (argc--) {
+	name = *argv++;
+	c = GETTOGGLE(name);
+	if (Ambiguous(c)) {
+	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
+					name);
+	    return 0;
+	} else if (c == 0) {
+	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
+					name);
+	    return 0;
+	} else {
+	    if (c->variable) {
+		*c->variable = !*c->variable;		/* invert it */
+		if (c->actionexplanation) {
+		    printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
+							c->actionexplanation);
+		}
+	    }
+	    if (c->handler) {
+		retval &= (*c->handler)(-1);
+	    }
+	}
+    }
+    return retval;
+}
+
+/*
+ * The following perform the "set" command.
+ */
+
+#ifdef	USE_TERMIO
+struct termio new_tc = { 0 };
+#endif
+
+struct setlist {
+    char *name;				/* name */
+    char *help;				/* help information */
+    void (*handler)();
+    cc_t *charp;			/* where it is located at */
+};
+
+static struct setlist Setlist[] = {
+#ifdef	KLUDGELINEMODE
+    { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
+#endif
+    { "escape",	"character to escape back to telnet command mode", 0, &escape },
+    { "rlogin", "rlogin escape character", 0, &rlogin },
+    { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
+    { " ", "" },
+    { " ", "The following need 'localchars' to be toggled true", 0, 0 },
+    { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
+    { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
+    { "quit",	"character to cause an Abort process", 0, termQuitCharp },
+    { "eof",	"character to cause an EOF ", 0, termEofCharp },
+    { " ", "" },
+    { " ", "The following are for local editing in linemode", 0, 0 },
+    { "erase",	"character to use to erase a character", 0, termEraseCharp },
+    { "kill",	"character to use to erase a line", 0, termKillCharp },
+    { "lnext",	"character to use for literal next", 0, termLiteralNextCharp },
+    { "susp",	"character to cause a Suspend Process", 0, termSuspCharp },
+    { "reprint", "character to use for line reprint", 0, termRprntCharp },
+    { "worderase", "character to use to erase a word", 0, termWerasCharp },
+    { "start",	"character to use for XON", 0, termStartCharp },
+    { "stop",	"character to use for XOFF", 0, termStopCharp },
+    { "forw1",	"alternate end of line character", 0, termForw1Charp },
+    { "forw2",	"alternate end of line character", 0, termForw2Charp },
+    { "ayt",	"alternate AYT character", 0, termAytCharp },
+    { 0 }
+};
+
+#if	defined(CRAY) && !defined(__STDC__)
+/* Work around compiler bug in pcc 4.1.5 */
+    void
+_setlist_init()
+{
+#ifndef	KLUDGELINEMODE
+#define	N 5
+#else
+#define	N 6
+#endif
+	Setlist[N+0].charp = &termFlushChar;
+	Setlist[N+1].charp = &termIntChar;
+	Setlist[N+2].charp = &termQuitChar;
+	Setlist[N+3].charp = &termEofChar;
+	Setlist[N+6].charp = &termEraseChar;
+	Setlist[N+7].charp = &termKillChar;
+	Setlist[N+8].charp = &termLiteralNextChar;
+	Setlist[N+9].charp = &termSuspChar;
+	Setlist[N+10].charp = &termRprntChar;
+	Setlist[N+11].charp = &termWerasChar;
+	Setlist[N+12].charp = &termStartChar;
+	Setlist[N+13].charp = &termStopChar;
+	Setlist[N+14].charp = &termForw1Char;
+	Setlist[N+15].charp = &termForw2Char;
+	Setlist[N+16].charp = &termAytChar;
+#undef	N
+}
+#endif	/* defined(CRAY) && !defined(__STDC__) */
+
+    static struct setlist *
+getset(name)
+    char *name;
+{
+    return (struct setlist *)
+		genget(name, (char **) Setlist, sizeof(struct setlist));
+}
+
+    void
+set_escape_char(s)
+    char *s;
+{
+	if (rlogin != _POSIX_VDISABLE) {
+		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
+		printf("Telnet rlogin escape character is '%s'.\r\n",
+					control(rlogin));
+	} else {
+		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
+		printf("Telnet escape character is '%s'.\r\n", control(escape));
+	}
+}
+
+    static int
+setcmd(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    int value;
+    struct setlist *ct;
+    struct togglelist *c;
+
+    if (argc < 2 || argc > 3) {
+	printf("Format is 'set Name Value'\n'set ?' for help.\r\n");
+	return 0;
+    }
+    if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
+	for (ct = Setlist; ct->name; ct++)
+	    printf("%-15s %s\r\n", ct->name, ct->help);
+	printf("\r\n");
+	settogglehelp(1);
+	printf("%-15s %s\r\n", "?", "display help information");
+	return 0;
+    }
+
+    ct = getset(argv[1]);
+    if (ct == 0) {
+	c = GETTOGGLE(argv[1]);
+	if (c == 0) {
+	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
+			argv[1]);
+	    return 0;
+	} else if (Ambiguous(c)) {
+	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
+			argv[1]);
+	    return 0;
+	}
+	if (c->variable) {
+	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
+		*c->variable = 1;
+	    else if (strcmp("off", argv[2]) == 0)
+		*c->variable = 0;
+	    else {
+		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\r\n");
+		return 0;
+	    }
+	    if (c->actionexplanation) {
+		printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
+							c->actionexplanation);
+	    }
+	}
+	if (c->handler)
+	    (*c->handler)(1);
+    } else if (argc != 3) {
+	printf("Format is 'set Name Value'\n'set ?' for help.\r\n");
+	return 0;
+    } else if (Ambiguous(ct)) {
+	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
+			argv[1]);
+	return 0;
+    } else if (ct->handler) {
+	(*ct->handler)(argv[2]);
+	printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp);
+    } else {
+	if (strcmp("off", argv[2])) {
+	    value = special(argv[2]);
+	} else {
+	    value = _POSIX_VDISABLE;
+	}
+	*(ct->charp) = (cc_t)value;
+	printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
+    }
+    slc_check();
+    return 1;
+}
+
+    static int
+unsetcmd(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    struct setlist *ct;
+    struct togglelist *c;
+    register char *name;
+
+    if (argc < 2) {
+	fprintf(stderr,
+	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
+	return 0;
+    }
+    if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
+	for (ct = Setlist; ct->name; ct++)
+	    printf("%-15s %s\r\n", ct->name, ct->help);
+	printf("\r\n");
+	settogglehelp(0);
+	printf("%-15s %s\r\n", "?", "display help information");
+	return 0;
+    }
+
+    argc--;
+    argv++;
+    while (argc--) {
+	name = *argv++;
+	ct = getset(name);
+	if (ct == 0) {
+	    c = GETTOGGLE(name);
+	    if (c == 0) {
+		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
+			name);
+		return 0;
+	    } else if (Ambiguous(c)) {
+		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
+			name);
+		return 0;
+	    }
+	    if (c->variable) {
+		*c->variable = 0;
+		if (c->actionexplanation) {
+		    printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
+							c->actionexplanation);
+		}
+	    }
+	    if (c->handler)
+		(*c->handler)(0);
+	} else if (Ambiguous(ct)) {
+	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
+			name);
+	    return 0;
+	} else if (ct->handler) {
+	    (*ct->handler)(0);
+	    printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp);
+	} else {
+	    *(ct->charp) = _POSIX_VDISABLE;
+	    printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
+	}
+    }
+    return 1;
+}
+
+/*
+ * The following are the data structures and routines for the
+ * 'mode' command.
+ */
+#ifdef	KLUDGELINEMODE
+extern int kludgelinemode;
+
+    static int
+dokludgemode()
+{
+    kludgelinemode = 1;
+    send_wont(TELOPT_LINEMODE, 1);
+    send_dont(TELOPT_SGA, 1);
+    send_dont(TELOPT_ECHO, 1);
+    return 1;			/* I'm guessing here -- eichin -- XXX */
+}
+#endif
+
+    static int
+dolinemode()
+{
+#ifdef	KLUDGELINEMODE
+    if (kludgelinemode)
+	send_dont(TELOPT_SGA, 1);
+#endif
+    send_will(TELOPT_LINEMODE, 1);
+    send_dont(TELOPT_ECHO, 1);
+    return 1;
+}
+
+    static int
+docharmode()
+{
+#ifdef	KLUDGELINEMODE
+    if (kludgelinemode)
+	send_do(TELOPT_SGA, 1);
+    else
+#endif
+    send_wont(TELOPT_LINEMODE, 1);
+    send_do(TELOPT_ECHO, 1);
+    return 1;
+}
+
+    static int
+dolmmode(bit, on)
+    int bit, on;
+{
+    unsigned char c;
+    extern int linemode;
+
+    if (my_want_state_is_wont(TELOPT_LINEMODE)) {
+	printf("?Need to have LINEMODE option enabled first.\r\n");
+	printf("'mode ?' for help.\r\n");
+	return 0;
+    }
+
+    if (on)
+	c = (linemode | bit);
+    else
+	c = (linemode & ~bit);
+    lm_mode(&c, 1, 1);
+    return 1;
+}
+
+static int
+tel_setmode(bit)
+    int bit;
+{
+    return dolmmode(bit, 1);
+}
+
+static int
+tel_clearmode(bit)
+    int bit;
+{
+    return dolmmode(bit, 0);
+}
+
+struct modelist {
+	char	*name;		/* command name */
+	char	*help;		/* help string */
+	int	(*handler)();	/* routine which executes command */
+	int	needconnect;	/* Do we need to be connected to execute? */
+	int	arg1;
+};
+
+static int modehelp(void);
+
+static struct modelist ModeList[] = {
+    { "character", "Disable LINEMODE option",	docharmode, 1 },
+#ifdef	KLUDGELINEMODE
+    { "",	"(or disable obsolete line-by-line mode)", 0 },
+#endif
+    { "line",	"Enable LINEMODE option",	dolinemode, 1 },
+#ifdef	KLUDGELINEMODE
+    { "",	"(or enable obsolete line-by-line mode)", 0 },
+#endif
+    { "", "", 0 },
+    { "",	"These require the LINEMODE option to be enabled", 0 },
+    { "isig",	"Enable signal trapping",	tel_setmode, 1, MODE_TRAPSIG },
+    { "+isig",	0,				tel_setmode, 1, MODE_TRAPSIG },
+    { "-isig",	"Disable signal trapping",	tel_clearmode, 1, MODE_TRAPSIG },
+    { "edit",	"Enable character editing",	tel_setmode, 1, MODE_EDIT },
+    { "+edit",	0,				tel_setmode, 1, MODE_EDIT },
+    { "-edit",	"Disable character editing",	tel_clearmode, 1, MODE_EDIT },
+    { "softtabs", "Enable tab expansion",	tel_setmode, 1, MODE_SOFT_TAB },
+    { "+softtabs", 0,				tel_setmode, 1, MODE_SOFT_TAB },
+    { "-softtabs", "Disable character editing",	tel_clearmode, 1, MODE_SOFT_TAB },
+    { "litecho", "Enable literal character echo", tel_setmode, 1, MODE_LIT_ECHO },
+    { "+litecho", 0,				tel_setmode, 1, MODE_LIT_ECHO },
+    { "-litecho", "Disable literal character echo", tel_clearmode, 1, MODE_LIT_ECHO },
+    { "help",	0,				modehelp, 0 },
+#ifdef	KLUDGELINEMODE
+    { "kludgeline", 0,				dokludgemode, 1 },
+#endif
+    { "", "", 0 },
+    { "?",	"Print help information",	modehelp, 0 },
+    { 0 },
+};
+
+
+static int
+modehelp()
+{
+    struct modelist *mt;
+
+    printf("format is:  'mode Mode', where 'Mode' is one of:\r\n\r\n");
+    for (mt = ModeList; mt->name; mt++) {
+	if (mt->help) {
+	    if (*mt->help)
+		printf("%-15s %s\r\n", mt->name, mt->help);
+	    else
+		printf("\r\n");
+	}
+    }
+    return 0;
+}
+
+#define	GETMODECMD(name) (struct modelist *) \
+		genget(name, (char **) ModeList, sizeof(struct modelist))
+
+    static int
+modecmd(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    struct modelist *mt;
+
+    if (argc != 2) {
+	printf("'mode' command requires an argument\r\n");
+	printf("'mode ?' for help.\r\n");
+    } else if ((mt = GETMODECMD(argv[1])) == 0) {
+	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
+    } else if (Ambiguous(mt)) {
+	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
+    } else if (mt->needconnect && !connected) {
+	printf("?Need to be connected first.\r\n");
+	printf("'mode ?' for help.\r\n");
+    } else if (mt->handler) {
+	return (*mt->handler)(mt->arg1);
+    }
+    return 0;
+}
+
+/*
+ * The following data structures and routines implement the
+ * "display" command.
+ */
+
+    static int
+display(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    struct togglelist *tl;
+    struct setlist *sl;
+
+#define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
+			    if (*tl->variable) { \
+				printf("will"); \
+			    } else { \
+				printf("won't"); \
+			    } \
+			    printf(" %s.\r\n", tl->actionexplanation); \
+			}
+
+#define	doset(sl)   if (sl->name && *sl->name != ' ') { \
+			if (sl->handler == 0) \
+			    printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \
+			else \
+			    printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \
+		    }
+
+    if (argc == 1) {
+	for (tl = Togglelist; tl->name; tl++) {
+	    dotog(tl);
+	}
+	printf("\r\n");
+	for (sl = Setlist; sl->name; sl++) {
+	    doset(sl);
+	}
+    } else {
+	int i;
+
+	for (i = 1; i < argc; i++) {
+	    sl = getset(argv[i]);
+	    tl = GETTOGGLE(argv[i]);
+	    if (Ambiguous(sl) || Ambiguous(tl)) {
+		printf("?Ambiguous argument '%s'.\r\n", argv[i]);
+		return 0;
+	    } else if (!sl && !tl) {
+		printf("?Unknown argument '%s'.\r\n", argv[i]);
+		return 0;
+	    } else {
+		if (tl) {
+		    dotog(tl);
+		}
+		if (sl) {
+		    doset(sl);
+		}
+	    }
+	}
+    }
+    /*@*/optionstatus();
+#ifdef	ENCRYPTION
+    EncryptStatus();
+#endif	/* ENCRYPTION */
+    return 1;
+#undef	doset
+#undef	dotog
+}
+
+/*
+ * The following are the data structures, and many of the routines,
+ * relating to command processing.
+ */
+
+/*
+ * Set the escape character.
+ */
+	static int
+setescape(argc, argv)
+	int argc;
+	char *argv[];
+{
+	register char *arg;
+	char buf[50];
+
+	printf(
+	    "Deprecated usage - please use 'set escape%s%s' in the future.\r\n",
+				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
+	if (argc > 2)
+		arg = argv[1];
+	else {
+		printf("new escape character: ");
+		(void) fgets(buf, sizeof(buf), stdin);
+		arg = buf;
+	}
+	if (arg[0] != '\0')
+		escape = arg[0];
+	if (!In3270) {
+		printf("Escape character is '%s'.\r\n", control(escape));
+	}
+	(void) fflush(stdout);
+	return 1;
+}
+
+    /*VARARGS*/
+    static int
+togcrmod(argc, argv)
+     int argc;
+     char **argv;
+{
+    crmod = !crmod;
+    printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n");
+    printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't");
+    (void) fflush(stdout);
+    return 1;
+}
+
+    /*VARARGS*/
+static int
+suspend(argc, argv)
+     int argc;
+     char **argv;
+{
+#ifdef	SIGTSTP
+    setcommandmode();
+    {
+	long oldrows, oldcols, newrows, newcols, err;
+
+	err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
+	(void) kill(0, SIGTSTP);
+	/*
+	 * If we didn't get the window size before the SUSPEND, but we
+	 * can get them now (???), then send the NAWS to make sure that
+	 * we are set up for the right window size.
+	 */
+	if (TerminalWindowSize(&newrows, &newcols) && connected &&
+	    (err || ((oldrows != newrows) || (oldcols != newcols)))) {
+		sendnaws();
+	}
+    }
+    /* reget parameters in case they were changed */
+    TerminalSaveState();
+    setconnmode(0);
+#else
+    printf("Suspend is not supported.  Try the '!' command instead\r\n");
+#endif
+    return 1;
+}
+
+#if	!defined(TN3270)
+    /*ARGSUSED*/
+static int
+shell(argc, argv)
+    int argc;
+    char *argv[];
+{
+    long oldrows, oldcols, newrows, newcols, err;
+
+    setcommandmode();
+
+    err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
+    switch(vfork()) {
+    case -1:
+	perror("Fork failed");
+	break;
+
+    case 0:
+	{
+	    /*
+	     * Fire up the shell in the child.
+	     */
+	    register char *shellp, *shellname;
+
+	    shellp = getenv("SHELL");
+	    if (shellp == NULL)
+		shellp = "/bin/sh";
+	    if ((shellname = strrchr(shellp, '/')) == 0)
+		shellname = shellp;
+	    else
+		shellname++;
+	    if (argc > 1)
+		execl(shellp, shellname, "-c", &saveline[1], (char *)NULL);
+	    else
+		execl(shellp, shellname, (char *)NULL);
+	    perror("Execl");
+	    _exit(1);
+	}
+    default:
+	    (void)wait((int *)0);	/* Wait for the shell to complete */
+
+	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
+		(err || ((oldrows != newrows) || (oldcols != newcols)))) {
+		    sendnaws();
+	    }
+	    break;
+    }
+    return 1;
+}
+#else	/* !defined(TN3270) */
+extern int shell();
+#endif	/* !defined(TN3270) */
+
+/*VARARGS*/
+static int
+bye(argc, argv)
+    int  argc;		/* Number of arguments */
+    char *argv[];	/* arguments */
+{
+    extern int resettermname;
+
+    if (connected) {
+	(void) shutdown(net, 2);
+	printf("Connection closed.\r\n");
+	(void) NetClose(net);
+	connected = 0;
+	resettermname = 1;
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
+	auth_encrypt_connect(connected);
+#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+	/* reset options */
+	tninit();
+#if	defined(TN3270)
+	SetIn3270();		/* Get out of 3270 mode */
+#endif	/* defined(TN3270) */
+    }
+    if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
+	longjmp(toplevel, 1);
+	/* NOTREACHED */
+    }
+    return 1;			/* Keep lint, etc., happy */
+}
+
+/*VARARGS*/
+int
+quit(argc, argv)
+	int argc;
+	char *argv[];
+{
+	(void) call(bye, "bye", "fromquit", 0);
+	Exit(0);
+	/*NOTREACHED*/
+	return 0;
+}
+
+/*VARARGS*/
+static int
+logout(argc, argv)
+     int argc;
+     char **argv;
+{
+	send_do(TELOPT_LOGOUT, 1);
+	(void) netflush();
+	return 1;
+}
+
+
+/*
+ * The SLC command.
+ */
+
+struct slclist {
+	char	*name;
+	char	*help;
+	void	(*handler)();
+	int	arg;
+};
+
+static void slc_help(void);
+
+struct slclist SlcList[] = {
+    { "export",	"Use local special character definitions",
+						slc_mode_export,	0 },
+    { "import",	"Use remote special character definitions",
+						slc_mode_import,	1 },
+    { "check",	"Verify remote special character definitions",
+						slc_mode_import,	0 },
+    { "help",	0,				slc_help,		0 },
+    { "?",	"Print help information",	slc_help,		0 },
+    { 0 },
+};
+
+    static void
+slc_help()
+{
+    struct slclist *c;
+
+    for (c = SlcList; c->name; c++) {
+	if (c->help) {
+	    if (*c->help)
+		printf("%-15s %s\r\n", c->name, c->help);
+	    else
+		printf("\r\n");
+	}
+    }
+}
+
+static struct slclist *
+getslc(name)
+    char *name;
+{
+    return (struct slclist *)
+		genget(name, (char **) SlcList, sizeof(struct slclist));
+}
+
+static int
+slccmd(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    struct slclist *c;
+
+    if (argc != 2) {
+	fprintf(stderr,
+	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
+	return 0;
+    }
+    c = getslc(argv[1]);
+    if (c == 0) {
+        fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    if (Ambiguous(c)) {
+        fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    (*c->handler)(c->arg);
+    slcstate();
+    return 1;
+}
+
+/*
+ * The ENVIRON command.
+ */
+
+struct envlist {
+	char	*name;
+	char	*help;
+	void	(*handler)();
+	int	narg;
+};
+
+extern struct env_lst *
+	env_define (unsigned char *, unsigned char *);
+extern void
+	env_undefine (unsigned char *),
+	env_export (unsigned char *),
+	env_unexport (unsigned char *),
+	env_send (unsigned char *),
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+	env_varval (unsigned char *),
+#endif
+	env_list (void);
+static void
+	env_help (void);
+
+struct envlist EnvList[] = {
+    { "define",	"Define an environment variable",
+						(void (*)())env_define,	2 },
+    { "undefine", "Undefine an environment variable",
+						env_undefine,	1 },
+    { "export",	"Mark an environment variable for automatic export",
+						env_export,	1 },
+    { "unexport", "Don't mark an environment variable for automatic export",
+						env_unexport,	1 },
+    { "send",	"Send an environment variable", env_send,	1 },
+    { "list",	"List the current environment variables",
+						env_list,	0 },
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+    { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
+						env_varval,    1 },
+#endif
+    { "help",	0,				env_help,		0 },
+    { "?",	"Print help information",	env_help,		0 },
+    { 0 },
+};
+
+    static void
+env_help()
+{
+    struct envlist *c;
+
+    for (c = EnvList; c->name; c++) {
+	if (c->help) {
+	    if (*c->help)
+		printf("%-15s %s\r\n", c->name, c->help);
+	    else
+		printf("\r\n");
+	}
+    }
+}
+
+    static struct envlist *
+getenvcmd(name)
+    char *name;
+{
+    return (struct envlist *)
+		genget(name, (char **) EnvList, sizeof(struct envlist));
+}
+
+static int
+env_cmd(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    struct envlist *c;
+
+    if (argc < 2) {
+	fprintf(stderr,
+	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
+	return 0;
+    }
+    c = getenvcmd(argv[1]);
+    if (c == 0) {
+        fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    if (Ambiguous(c)) {
+        fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    if (c->narg + 2 != argc) {
+	fprintf(stderr,
+	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
+		c->narg < argc - 2 ? "only " : "",
+		c->narg, c->narg == 1 ? "" : "s", c->name);
+	return 0;
+    }
+    (*c->handler)(argv[2], argv[3]);
+    return 1;
+}
+
+struct env_lst {
+	struct env_lst *next;	/* pointer to next structure */
+	struct env_lst *prev;	/* pointer to previous structure */
+	unsigned char *var;	/* pointer to variable name */
+	unsigned char *value;	/* pointer to variable value */
+	int export;		/* 1 -> export with default list of variables */
+	int welldefined;	/* A well defined variable */
+};
+
+struct env_lst envlisthead;
+
+static	struct env_lst *
+env_find(var)
+	unsigned char *var;
+{
+	register struct env_lst *ep;
+
+	for (ep = envlisthead.next; ep; ep = ep->next) {
+		if (strcmp((char *)ep->var, (char *)var) == 0)
+			return(ep);
+	}
+	return(NULL);
+}
+
+	void
+env_init()
+{
+	extern char **environ;
+	register char **epp, *cp;
+	register struct env_lst *ep;
+
+	for (epp = environ; *epp; epp++) {
+		if ((cp = strchr(*epp, '='))) {
+			*cp = '\0';
+			ep = env_define((unsigned char *)*epp,
+					(unsigned char *)cp+1);
+			ep->export = 0;
+			*cp = '=';
+		}
+	}
+	/*
+	 * Special case for DISPLAY variable.  If it is ":0.0" or
+	 * "unix:0.0", we have to get rid of "unix" and insert our
+	 * hostname.
+	 */
+	if ((ep = env_find("DISPLAY"))
+	    && ((*ep->value == ':')
+	        || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
+		char hbuf[256+1];
+		char *cp2 = strchr((char *)ep->value, ':');
+
+		gethostname(hbuf, 256);
+		hbuf[256] = '\0';
+		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
+		sprintf((char *)cp, "%s%s", hbuf, cp2);
+		free(ep->value);
+		ep->value = (unsigned char *)cp;
+	}
+	/*
+	 * If USER is not defined, but LOGNAME is, then add
+	 * USER with the value from LOGNAME.  By default, we
+	 * don't export the USER variable.
+	 */
+	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
+		env_define((unsigned char *)"USER", ep->value);
+		env_unexport((unsigned char *)"USER");
+	}
+	env_export((unsigned char *)"DISPLAY");
+	env_export((unsigned char *)"PRINTER");
+}
+
+	struct env_lst *
+env_define(var, value)
+	unsigned char *var, *value;
+{
+	register struct env_lst *ep;
+
+	if ((ep = env_find(var))) {
+		if (ep->var)
+			free(ep->var);
+		if (ep->value)
+			free(ep->value);
+	} else {
+		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
+		ep->next = envlisthead.next;
+		envlisthead.next = ep;
+		ep->prev = &envlisthead;
+		if (ep->next)
+			ep->next->prev = ep;
+	}
+	ep->welldefined = opt_welldefined((char *)var);
+	ep->export = 1;
+	ep->var = (unsigned char *)strdup((char *)var);
+	ep->value = (unsigned char *)strdup((char *)value);
+	return(ep);
+}
+
+	void
+env_undefine(var)
+	unsigned char *var;
+{
+	register struct env_lst *ep;
+
+	if ((ep = env_find(var))) {
+		ep->prev->next = ep->next;
+		if (ep->next)
+			ep->next->prev = ep->prev;
+		if (ep->var)
+			free(ep->var);
+		if (ep->value)
+			free(ep->value);
+		free(ep);
+	}
+}
+
+	void
+env_export(var)
+	unsigned char *var;
+{
+	register struct env_lst *ep;
+
+	if ((ep = env_find(var)))
+		ep->export = 1;
+}
+
+	void
+env_unexport(var)
+	unsigned char *var;
+{
+	register struct env_lst *ep;
+
+	if ((ep = env_find(var)))
+		ep->export = 0;
+}
+
+	void
+env_send(var)
+	unsigned char *var;
+{
+	register struct env_lst *ep;
+
+        if (my_state_is_wont(TELOPT_NEW_ENVIRON)
+#ifdef	OLD_ENVIRON
+	    && my_state_is_wont(TELOPT_OLD_ENVIRON)
+#endif
+		) {
+		fprintf(stderr,
+		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
+									var);
+		return;
+	}
+	ep = env_find(var);
+	if (ep == 0) {
+		fprintf(stderr, "Cannot send '%s': variable not defined\n",
+									var);
+		return;
+	}
+	env_opt_start_info();
+	env_opt_add(ep->var);
+	env_opt_end(0);
+}
+
+	void
+env_list()
+{
+	register struct env_lst *ep;
+
+	for (ep = envlisthead.next; ep; ep = ep->next) {
+		printf("%c %-20s %s\r\n", ep->export ? '*' : ' ',
+					ep->var, ep->value);
+	}
+}
+
+	unsigned char *
+env_default(init, welldefined)
+	int init;
+{
+	static struct env_lst *nep = NULL;
+
+	if (init) {
+		nep = &envlisthead;
+		return NULL;	/* guessing here too -- eichin -- XXX */
+	}
+	if (nep) {
+		while ((nep = nep->next)) {
+			if (nep->export && (nep->welldefined == welldefined))
+				return(nep->var);
+		}
+	}
+	return(NULL);
+}
+
+	unsigned char *
+env_getvalue(var)
+	unsigned char *var;
+{
+	register struct env_lst *ep;
+
+	if ((ep = env_find(var)))
+		return(ep->value);
+	return(NULL);
+}
+
+	int
+env_is_exported(var)
+	unsigned char *var;
+{
+	register struct env_lst *ep;
+
+	if ((ep = env_find(var)))
+		return ep->export;
+	return 0;
+}
+	    
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+	void
+env_varval(what)
+	unsigned char *what;
+{
+	extern int old_env_var, old_env_value, env_auto;
+	unsigned int len = strlen((char *)what);
+
+	if (len == 0)
+		goto unknown;
+
+	if (strncasecmp((char *)what, "status", len) == 0) {
+		if (env_auto)
+			printf("%s%s", "VAR and VALUE are/will be ",
+					"determined automatically\r\n");
+		if (old_env_var == OLD_ENV_VAR)
+			printf("VAR and VALUE set to correct definitions\r\n");
+		else
+			printf("VAR and VALUE definitions are reversed\r\n");
+	} else if (strncasecmp((char *)what, "auto", len) == 0) {
+		env_auto = 1;
+		old_env_var = OLD_ENV_VALUE;
+		old_env_value = OLD_ENV_VAR;
+	} else if (strncasecmp((char *)what, "right", len) == 0) {
+		env_auto = 0;
+		old_env_var = OLD_ENV_VAR;
+		old_env_value = OLD_ENV_VALUE;
+	} else if (strncasecmp((char *)what, "wrong", len) == 0) {
+		env_auto = 0;
+		old_env_var = OLD_ENV_VALUE;
+		old_env_value = OLD_ENV_VAR;
+	} else {
+unknown:
+		printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\r\n");
+	}
+}
+#endif
+
+#if	defined(AUTHENTICATION)
+/*
+ * The AUTHENTICATE command.
+ */
+
+struct authlist {
+	char	*name;
+	char	*help;
+	int	(*handler)();
+	int	narg;
+};
+
+extern int
+	auth_enable (char *),
+	auth_disable (char *),
+	auth_status (void);
+static int
+	auth_help (void);
+
+struct authlist AuthList[] = {
+    { "status",	"Display current status of authentication information",
+						auth_status,	0 },
+    { "disable", "Disable an authentication type ('auth disable ?' for more)",
+						auth_disable,	1 },
+    { "enable", "Enable an authentication type ('auth enable ?' for more)",
+						auth_enable,	1 },
+    { "help",	0,				auth_help,		0 },
+    { "?",	"Print help information",	auth_help,		0 },
+    { 0 },
+};
+
+    static int
+auth_help()
+{
+    struct authlist *c;
+
+    for (c = AuthList; c->name; c++) {
+	if (c->help) {
+	    if (*c->help)
+		printf("%-15s %s\r\n", c->name, c->help);
+	    else
+		printf("\r\n");
+	}
+    }
+    return 0;
+}
+
+int
+auth_cmd(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    struct authlist *c;
+
+    if (argc < 2) {
+      fprintf(stderr,
+          "Need an argument to 'auth' command.  'auth ?' for help.\n");
+      return 0;
+    }
+
+    c = (struct authlist *)
+		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
+    if (c == 0) {
+        fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    if (Ambiguous(c)) {
+        fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    if (c->narg + 2 != argc) {
+	fprintf(stderr,
+	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
+		c->narg < argc + 2 ? "only " : "",
+		c->narg, c->narg == 1 ? "" : "s", c->name);
+	return 0;
+    }
+    return((*c->handler)(argv[2], argv[3]));
+}
+#endif
+
+#ifdef	ENCRYPTION
+/*
+ * The ENCRYPT command.
+ */
+
+struct encryptlist {
+	char	*name;
+	char	*help;
+	int	(*handler)();
+	int	needconnect;
+	int	minarg;
+	int	maxarg;
+};
+
+extern int
+	EncryptEnable (char *, char *),
+	EncryptDisable (char *, char *),
+	EncryptType (char *, char *),
+	EncryptStart (char *),
+	EncryptStartInput (void),
+	EncryptStartOutput (void),
+	EncryptStop (char *),
+	EncryptStopInput (void),
+	EncryptStopOutput (void),
+	EncryptStatus (void);
+static int
+	EncryptHelp (void);
+
+struct encryptlist EncryptList[] = {
+    { "enable", "Enable encryption. ('encrypt enable ?' for more)",
+						EncryptEnable, 1, 1, 2 },
+    { "disable", "Disable encryption. ('encrypt enable ?' for more)",
+						EncryptDisable, 0, 1, 2 },
+    { "type", "Set encryption type. ('encrypt type ?' for more)",
+						EncryptType, 0, 1, 1 },
+    { "start", "Start encryption. ('encrypt start ?' for more)",
+						EncryptStart, 1, 0, 1 },
+    { "stop", "Stop encryption. ('encrypt stop ?' for more)",
+						EncryptStop, 1, 0, 1 },
+    { "input", "Start encrypting the input stream",
+						EncryptStartInput, 1, 0, 0 },
+    { "-input", "Stop encrypting the input stream",
+						EncryptStopInput, 1, 0, 0 },
+    { "output", "Start encrypting the output stream",
+						EncryptStartOutput, 1, 0, 0 },
+    { "-output", "Stop encrypting the output stream",
+						EncryptStopOutput, 1, 0, 0 },
+
+    { "status",	"Display current status of authentication information",
+						EncryptStatus,	0, 0, 0 },
+    { "help",	0,				EncryptHelp,	0, 0, 0 },
+    { "?",	"Print help information",	EncryptHelp,	0, 0, 0 },
+    { 0 },
+};
+
+    static int
+EncryptHelp()
+{
+    struct encryptlist *c;
+
+    for (c = EncryptList; c->name; c++) {
+	if (c->help) {
+	    if (*c->help)
+		printf("%-15s %s\r\n", c->name, c->help);
+	    else
+		printf("\r\n");
+	}
+    }
+    return 0;
+}
+
+int
+encrypt_cmd(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    struct encryptlist *c;
+
+    if (argc < 2) {
+	fprintf(stderr,
+	    "Need an argument to 'encrypt' command.  'encrypt ?' for help.\n");
+	return 0;
+    }
+
+    c = (struct encryptlist *)
+		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
+    if (c == 0) {
+        fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    if (Ambiguous(c)) {
+        fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    argc -= 2;
+    if (argc < c->minarg || argc > c->maxarg) {
+	if (c->minarg == c->maxarg) {
+	    fprintf(stderr, "Need %s%d argument%s ",
+		c->minarg < argc ? "only " : "", c->minarg,
+		c->minarg == 1 ? "" : "s");
+	} else {
+	    fprintf(stderr, "Need %s%d-%d arguments ",
+		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
+	}
+	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
+		c->name);
+	return 0;
+    }
+    if (c->needconnect && !connected) {
+	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
+	    printf("?Need to be connected first.\r\n");
+	    return 0;
+	}
+    }
+    return ((*c->handler)(argc > 0 ? argv[2] : 0,
+			argc > 1 ? argv[3] : 0,
+			argc > 2 ? argv[4] : 0));
+}
+#endif	/* ENCRYPTION */
+
+#if	defined(FORWARD)
+
+/*
+ * The FORWARD command.
+ */
+
+
+extern int forward_flags;
+
+struct forwlist {
+	char	*name;
+	char	*help;
+	int	(*handler)();
+	int	f_flags;
+};
+
+static int
+	forw_status (void),
+	forw_set (int),
+	forw_help (void);
+
+struct forwlist ForwList[] = {
+    { "status",	"Display current status of credential forwarding",
+						forw_status,	0 },
+    { "disable", "Disable credential forwarding",
+						forw_set,	0 },
+    { "enable", "Enable credential forwarding",
+						forw_set,
+						OPTS_FORWARD_CREDS },
+    { "forwardable", "Enable credential forwarding of forwardable credentials",
+						forw_set,
+						OPTS_FORWARD_CREDS |
+						OPTS_FORWARDABLE_CREDS },
+    { "help",	0,				forw_help,		0 },
+    { "?",	"Print help information",	forw_help,		0 },
+    { 0 },
+};
+
+    static int
+forw_status()
+{
+    if (forward_flags & OPTS_FORWARD_CREDS) {
+	if (forward_flags & OPTS_FORWARDABLE_CREDS) {
+	    printf("Credential forwarding of forwardable credentials enabled\n");
+	} else {
+	    printf("Credential forwarding enabled\n");
+	}
+    } else {
+	printf("Credential forwarding disabled\n");
+    }
+    return(0);
+}
+
+int
+forw_set(f_flags)
+     int f_flags;
+{
+    forward_flags = f_flags;
+    return(0);
+}
+
+static int
+forw_help()
+{
+    struct forwlist *c;
+
+    for (c = ForwList; c->name; c++) {
+	if (c->help) {
+	    if (*c->help)
+		printf("%-15s %s\n", c->name, c->help);
+	    else
+		printf("\n");
+	}
+    }
+    return 0;
+}
+
+static int
+forw_cmd(argc, argv)
+    int  argc;
+    char *argv[];
+{
+    struct forwlist *c;
+
+    if (argc < 2) {
+      fprintf(stderr,
+          "Need an argument to 'forward' command.  'forward ?' for help.\n");
+      return 0;
+    }
+
+    c = (struct forwlist *)
+		genget(argv[1], (char **) ForwList, sizeof(struct forwlist));
+    if (c == 0) {
+        fprintf(stderr, "'%s': unknown argument ('forw ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    if (Ambiguous(c)) {
+        fprintf(stderr, "'%s': ambiguous argument ('forw ?' for help).\n",
+    				argv[1]);
+        return 0;
+    }
+    if (argc != 2) {
+	fprintf(stderr,
+       "No arguments needed to 'forward %s' command.  'forward ?' for help.\n",
+		c->name);
+	return 0;
+    }
+    return((*c->handler)(c->f_flags));
+}
+#endif
+
+#if	defined(unix) && defined(TN3270)
+    static void
+filestuff(fd)
+    int fd;
+{
+    int res;
+
+#ifdef	F_GETOWN
+    setconnmode(0);
+    res = fcntl(fd, F_GETOWN, 0);
+    setcommandmode();
+
+    if (res == -1) {
+	perror("fcntl");
+	return;
+    }
+    printf("\tOwner is %d.\r\n", res);
+#endif
+
+    setconnmode(0);
+    res = fcntl(fd, F_GETFL, 0);
+    setcommandmode();
+
+    if (res == -1) {
+	perror("fcntl");
+	return;
+    }
+#ifdef notdef
+    printf("\tFlags are 0x%x: %s\r\n", res, decodeflags(res));
+#endif
+}
+#endif /* defined(unix) && defined(TN3270) */
+
+/*
+ * Print status about the connection.
+ */
+    /*ARGSUSED*/
+static int
+status(argc, argv)
+    int	 argc;
+    char *argv[];
+{
+    if (connected) {
+	printf("Connected to %s (%s).\r\n", hostname, hostaddrstring);
+	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
+	    int mode = getconnmode();
+
+	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
+		printf("Operating with LINEMODE option\r\n");
+		printf("%s line editing\r\n", (mode&MODE_EDIT) ? "Local" : "No");
+		printf("%s catching of signals\r\n",
+					(mode&MODE_TRAPSIG) ? "Local" : "No");
+		slcstate();
+#ifdef	KLUDGELINEMODE
+	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
+		printf("Operating in obsolete linemode\r\n");
+#endif
+	    } else {
+		printf("Operating in single character mode\r\n");
+		if (localchars)
+		    printf("Catching signals locally\r\n");
+	    }
+	    printf("%s character echo\r\n", (mode&MODE_ECHO) ? "Local" : "Remote");
+	    if (my_want_state_is_will(TELOPT_LFLOW))
+		printf("%s flow control\r\n", (mode&MODE_FLOW) ? "Local" : "No");
+#ifdef	ENCRYPTION
+	    encrypt_display();
+#endif	/* ENCRYPTION */
+	}
+    } else {
+	printf("No connection.\r\n");
+    }
+#   if !defined(TN3270)
+    printf("Escape character is '%s'.\r\n", control(escape));
+    (void) fflush(stdout);
+#   else /* !defined(TN3270) */
+    if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
+	printf("Escape character is '%s'.\r\n", control(escape));
+    }
+#   if defined(unix)
+    if ((argc >= 2) && !strcmp(argv[1], "everything")) {
+	printf("SIGIO received %d time%s.\r\n",
+				sigiocount, (sigiocount == 1)? "":"s");
+	if (In3270) {
+	    printf("Process ID %d, process group %d.\r\n",
+					    getpid(), getpgrp(getpid()));
+	    printf("Terminal input:\r\n");
+	    filestuff(tin);
+	    printf("Terminal output:\r\n");
+	    filestuff(tout);
+	    printf("Network socket:\r\n");
+	    filestuff(net);
+	}
+    }
+    if (In3270 && transcom) {
+       printf("Transparent mode command is '%s'.\r\n", transcom);
+    }
+#   endif /* defined(unix) */
+    (void) fflush(stdout);
+    if (In3270) {
+	return 0;
+    }
+#   endif /* defined(TN3270) */
+    return 1;
+}
+
+#ifdef	SIGINFO
+/*
+ * Function that gets called when SIGINFO is received.
+ */
+#if	defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO))
+void 
+ayt_status()
+{
+    (void) call(status, "status", "notmuch", 0);
+}
+#else
+int
+ayt_status()
+{
+    (void) call(status, "status", "notmuch", 0);
+    return 0;
+}
+#endif
+#endif
+
+    int
+tn(argc, argv)
+    int argc;
+    char *argv[];
+{
+#if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
+    char *srp = 0;
+    int srlen;
+#endif
+    char *cmd, *hostp = 0, *portp = 0, *volatile user = 0;
+    struct addrinfo *addrs = 0, *addrp;
+    struct addrinfo hints;
+    int error;
+
+    if (connected) {
+	printf("?Already connected to %s\r\n", hostname);
+	return 0;
+    }
+    if (argc < 2) {
+	(void) strcpy(line, "open ");
+	printf("(to) ");
+	(void) fgets(&line[strlen(line)], (int) (sizeof(line) - strlen(line)),
+		     stdin);
+	makeargv();
+	argc = margc;
+	argv = margv;
+    }
+    cmd = *argv;
+    --argc; ++argv;
+    while (argc) {
+	if (isprefix(*argv, "help") || isprefix(*argv, "?"))
+	    goto usage;
+	if (strcmp(*argv, "-l") == 0) {
+	    --argc; ++argv;
+	    if (argc == 0)
+		goto usage;
+	    user = *argv++;
+	    --argc;
+	    continue;
+	}
+	if (strcmp(*argv, "-a") == 0) {
+	    --argc; ++argv;
+	    autologin = 1;
+	    continue;
+	}
+	if (hostp == 0) {
+	    hostp = *argv++;
+	    --argc;
+	    continue;
+	}
+	if (portp == 0) {
+	    portp = *argv++;
+	    --argc;
+	    continue;
+	}
+    usage:
+	printf("usage: %s [-l user] [-a] host-name [port]\r\n", cmd);
+	return 0;
+    }
+    if (hostp == 0)
+	goto usage;
+
+    if (portp) {
+	if (*portp == '-') {
+	    portp++;
+	    telnetport = 1;
+	} else
+	    telnetport = 0;
+    } else {
+	portp = "telnet";
+	telnetport = 1;
+    }
+
+#if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
+    if (hostp[0] == '@' || hostp[0] == '!') {
+	static struct sockaddr_in sr_sin4;
+	static struct addrinfo sr_addr;
+	unsigned long temp;
+	if ((hostname = strrchr(hostp, ':')) == NULL)
+	    hostname = strrchr(hostp, '@');
+	hostname++;
+	srp = 0;
+	temp = sourceroute(hostp, &srp, &srlen);
+	if (temp == 0) {
+	    herror(srp);
+	    return 0;
+	} else if (temp == -1) {
+	    printf("Bad source route option: %s\r\n", hostp);
+	    return 0;
+	} else {
+	    sr_sin4.sin_addr.s_addr = temp;
+	    sr_sin4.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+	    sr_sin4.sin_len = sizeof (sr_sin4);
+#endif
+	    sr_addr.ai_family = AF_INET;
+	    sr_addr.ai_addrlen = sizeof (sr_sin4);
+	    sr_addr.ai_addr = (struct sockaddr *) &sr_sin4;
+	    sr_addr.ai_next = 0;
+	    sr_addr.ai_canonname = hostname;
+	    addrs = &sr_addr;
+	}
+    } else {
+#endif
+	memset (&hints, 0, sizeof (hints));
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_family = PF_UNSPEC;
+
+
+	/* The GNU Libc (Red Hat Linux 6.1, on x86, which MIT is using
+	   at this time) implementation seems to completely ignore
+	   AI_NUMERICHOST, and contacts DNS anyways.  But other
+	   versions will not, and we do want to treat the two cases a
+	   little differently.  */
+#ifdef AF_INET6
+#define IS_NUMERIC_ADDR(P) \
+	('\0' == (P)[strspn((P), (strchr((P),':') ? "abcdefABCDEF:0123456789." : "0123456789."))])
+#else
+#define IS_NUMERIC_ADDR(P) \
+	('\0' == (P)[strspn((P), "0123456789.")])
+#endif
+	if (! IS_NUMERIC_ADDR (hostp))
+	    goto not_numeric;
+
+
+	hints.ai_flags = AI_NUMERICHOST;
+	error = getaddrinfo (hostp, portp, &hints, &addrs);
+	if (error == 0) {
+	    if (getnameinfo (addrs->ai_addr, addrs->ai_addrlen,
+			     _hostname, sizeof(_hostname), 0, 0, NI_NAMEREQD) != 0)
+		strncpy(_hostname, hostp, sizeof (_hostname));
+	    hostname = _hostname;
+	} else {
+	not_numeric:
+	    hints.ai_flags = AI_CANONNAME;
+	    error = getaddrinfo (hostp, portp, &hints, &addrs);
+	    if (error == 0) {
+
+		/* Stupid glibc lossage again.  */
+		if (! IS_NUMERIC_ADDR (addrs->ai_canonname)) {
+		    strncpy(_hostname, addrs->ai_canonname, sizeof(_hostname));
+		} else {
+		    fprintf (stderr,
+			     "telnet: system library bug? getaddrinfo returns numeric address\n"
+			     "\tas canonical name of %s\n",
+			     hostp);
+		    strncpy(_hostname, hostp, sizeof (_hostname));
+		}
+
+	    } else {
+		strncpy(_hostname, hostp, sizeof (_hostname));
+	    }
+	    hostname = _hostname;
+	}
+	if (error) {
+	    fprintf (stderr, "%s/%s: %s\n", hostp, portp, gai_strerror (error));
+	    return 0;
+	}
+#if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
+    }
+#endif
+    for (addrp = addrs; addrp && !connected; addrp = addrp->ai_next) {
+	error = getnameinfo (addrp->ai_addr, addrp->ai_addrlen,
+			     hostaddrstring, sizeof (hostaddrstring),
+			     (char *) NULL, 0, NI_NUMERICHOST);
+	if (error) {
+	    fprintf (stderr, "getnameinfo() error printing address: %s\n",
+		     gai_strerror (error));
+	    strcpy (hostaddrstring, "[address unprintable]");
+	}
+	printf("Trying %s...\r\n", hostaddrstring);
+#if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
+	if (srp && addrp->ai_family != AF_INET) {
+	    printf ("source routing not supported (yet) for address family,"
+		    " trying another address\n");
+	    continue;
+	}
+#endif
+	net = socket(addrp->ai_family, SOCK_STREAM, 0);
+	if (net < 0) {
+	    perror("telnet: socket");
+	    continue;
+	}
+#if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
+	if (srp) {
+	    if (addrp->ai_family != AF_INET)
+		printf ("source routing not supported (yet)"
+			" for address family\n");
+	    else if (setsockopt(net, IPPROTO_IP, IP_OPTIONS,
+				(char *)srp, srlen) < 0)
+		perror("setsockopt (IP_OPTIONS)");
+	}
+#endif
+#if	defined(IPPROTO_IP) && defined(IP_TOS)
+	if (addrp->ai_family == AF_INET) {
+# if	defined(HAVE_GETTOSBYNAME)
+	    struct tosent *tp;
+	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+		tos = tp->t_tos;
+# endif
+	    if (tos < 0)
+		tos = 020;	/* Low Delay bit */
+	    if (tos
+		&& (setsockopt(net, IPPROTO_IP, IP_TOS,
+		    (char *)&tos, sizeof(int)) < 0)
+		&& (errno != ENOPROTOOPT))
+		    perror("telnet: setsockopt (IP_TOS) (ignored)");
+	}
+#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
+
+	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
+		perror("setsockopt (SO_DEBUG)");
+	}
+
+	if (connect(net, addrp->ai_addr, addrp->ai_addrlen) < 0) {
+	    if (hostaddrstring[0]) {
+		fprintf(stderr, "telnet: connect to address %s: %s\n",
+			hostaddrstring, strerror (errno));
+		(void) NetClose(net);
+		continue;
+	    }
+	}
+	connected++;
+
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
+	auth_encrypt_connect(connected);
+#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+    }
+    if (!connected) {
+	perror("telnet: Unable to connect to remote host");
+	return 0;
+    }
+    if (user)
+      user = strdup(user);
+    if (hostp)
+      hostp = strdup(hostp);
+    cmdrc(hostp, hostname);
+    if (hostp)
+      free(hostp);
+    if (autologin && user == NULL) {
+	struct passwd *pw;
+
+	user = getenv("USER");
+	if (user == NULL ||
+	    ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
+	        pw = getpwuid(getuid());
+		if (pw)
+			user = pw->pw_name;
+		else
+			user = NULL;
+	}
+	if (user)
+	  user = strdup(user);
+    }
+    if (user) {
+	env_define((unsigned char *)"USER", (unsigned char *)user);
+	env_export((unsigned char *)"USER");
+    }
+    (void) call(status, "status", "notmuch", 0);
+    if (setjmp(peerdied) == 0)
+	telnet(user);
+    if (user)
+      free(user);
+    (void) NetClose(net);
+    ExitString("Connection closed by foreign host.\r\n",1);
+    /*NOTREACHED*/
+    return 0;
+}
+
+#define HELPINDENT ((int) sizeof ("connect"))
+
+static char
+	openhelp[] =	"connect to a site",
+	closehelp[] =	"close current connection",
+	logouthelp[] =	"forcibly logout remote user and close the connection",
+	quithelp[] =	"exit telnet",
+	statushelp[] =	"print status information",
+	helphelp[] =	"print help information",
+	sendhelp[] =	"transmit special characters ('send ?' for more)",
+	sethelp[] = 	"set operating parameters ('set ?' for more)",
+	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
+	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
+	slchelp[] =	"change state of special charaters ('slc ?' for more)",
+	displayhelp[] =	"display operating parameters",
+#if	defined(TN3270) && defined(unix)
+	transcomhelp[] = "specify Unix command for transparent mode pipe",
+#endif	/* defined(TN3270) && defined(unix) */
+#if	defined(AUTHENTICATION)
+	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
+#endif
+#ifdef	ENCRYPTION
+	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
+#endif	/* ENCRYPTION */
+#ifdef  FORWARD
+	forwardhelp[] = "turn on (off) credential forwarding ('forward ?' for more)",
+#endif
+#if	defined(unix)
+	zhelp[] =	"suspend telnet",
+#endif	/* defined(unix) */
+	shellhelp[] =	"invoke a subshell",
+	envhelp[] =	"change environment variables ('environ ?' for more)",
+	modestring[] = "try to enter line or character mode ('mode ?' for more)";
+
+static int	help();
+
+static Command cmdtab[] = {
+	{ "close",	closehelp,	bye,		1 },
+	{ "logout",	logouthelp,	logout,		1 },
+	{ "display",	displayhelp,	display,	0 },
+	{ "mode",	modestring,	modecmd,	0 },
+	{ "open",	openhelp,	tn,		0 },
+	{ "quit",	quithelp,	quit,		0 },
+	{ "send",	sendhelp,	sendcmd,	0 },
+	{ "set",	sethelp,	setcmd,		0 },
+	{ "unset",	unsethelp,	unsetcmd,	0 },
+	{ "status",	statushelp,	status,		0 },
+	{ "toggle",	togglestring,	toggle,		0 },
+	{ "slc",	slchelp,	slccmd,		0 },
+#if	defined(TN3270) && defined(unix)
+	{ "transcom",	transcomhelp,	settranscom,	0 },
+#endif	/* defined(TN3270) && defined(unix) */
+#if	defined(AUTHENTICATION)
+	{ "auth",	authhelp,	auth_cmd,	0 },
+#endif
+#ifdef	ENCRYPTION
+	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
+#endif	/* ENCRYPTION */
+#ifdef  FORWARD
+	{ "forward",    forwardhelp,    forw_cmd,       0 },
+#endif
+#if	defined(unix)
+	{ "z",		zhelp,		suspend,	0 },
+#endif	/* defined(unix) */
+#if	defined(TN3270)
+	{ "!",		shellhelp,	shell,		1 },
+#else
+	{ "!",		shellhelp,	shell,		0 },
+#endif
+	{ "environ",	envhelp,	env_cmd,	0 },
+	{ "?",		helphelp,	help,		0 },
+	{  0,           0,              0,              0 }
+};
+
+static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
+static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
+
+static Command cmdtab2[] = {
+	{ "help",	0,		help,		0 },
+	{ "escape",	escapehelp,	setescape,	0 },
+	{ "crmod",	crmodhelp,	togcrmod,	0 },
+	{  0,           0,              0,              0 }
+};
+
+
+/*
+ * Call routine with argc, argv set from args (terminated by 0).
+ */
+
+    /*VARARGS1*/
+static int
+#ifdef HAVE_STDARG_H
+call(intrtn_t routine, ...)
+#else
+call(routine, va_alist)
+    intrtn_t routine;
+    va_dcl
+#endif
+{
+    va_list ap;
+    char *args[100];
+    int argno = 0;
+
+#ifdef HAVE_STDARG_H
+    va_start(ap, routine);
+#else
+    va_start(ap);
+#endif
+
+    while ((args[argno++] = va_arg(ap, char *)) != 0) {
+	;
+    }
+    va_end(ap);
+    return (*routine)(argno-1, args);
+}
+
+
+    static Command *
+getcmd(name)
+    char *name;
+{
+    Command *cm;
+
+    if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
+	return cm;
+    return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
+}
+
+    void
+command(top, tbuf, cnt)
+    int top;
+    char *tbuf;
+    int cnt;
+{
+    register Command *c;
+
+    setcommandmode();
+    if (!top) {
+	putchar('\n');
+#if	defined(unix)
+    } else {
+	(void) signal(SIGINT, SIG_DFL);
+	(void) signal(SIGQUIT, SIG_DFL);
+#endif	/* defined(unix) */
+    }
+    for (;;) {
+	if (rlogin == _POSIX_VDISABLE)
+		printf("%s> ", prompt);
+	if (tbuf) {
+	    register char *cp;
+	    cp = line;
+	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
+		cnt--;
+	    tbuf = 0;
+	    if (cp == line || *--cp != '\n' || cp == line)
+		goto getline;
+	    *cp = '\0';
+	    if (rlogin == _POSIX_VDISABLE)
+	        printf("%s\r\n", line);
+	} else {
+	getline:
+	    if (rlogin != _POSIX_VDISABLE)
+		printf("%s> ", prompt);
+	    if (fgets(line, sizeof(line), stdin) == NULL) {
+		if (feof(stdin) || ferror(stdin)) {
+		    (void) quit(0, NULL);
+		    /*NOTREACHED*/
+		}
+		break;
+	    }
+	}
+	if (line[0] == 0)
+	    break;
+	makeargv();
+	if (margv[0] == 0) {
+	    break;
+	}
+	c = getcmd(margv[0]);
+	if (Ambiguous(c)) {
+	    printf("?Ambiguous command\r\n");
+	    continue;
+	}
+	if (c == 0) {
+	    printf("?Invalid command\r\n");
+	    continue;
+	}
+	if (c->needconnect && !connected) {
+	    printf("?Need to be connected first.\r\n");
+	    continue;
+	}
+	if ((*c->handler)(margc, margv)) {
+	    break;
+	}
+    }
+    if (!top) {
+	if (!connected) {
+	    longjmp(toplevel, 1);
+	    /*NOTREACHED*/
+	}
+#if	defined(TN3270)
+	if (shell_active == 0) {
+	    setconnmode(0);
+	}
+#else	/* defined(TN3270) */
+	setconnmode(0);
+#endif	/* defined(TN3270) */
+    }
+}
+
+/*
+ * Help command.
+ */
+static int
+help(argc, argv)
+	int argc;
+	char *argv[];
+{
+	register Command *c;
+
+	if (argc == 1) {
+		printf("Commands may be abbreviated.  Commands are:\r\n\r\n");
+		for (c = cmdtab; c->name; c++)
+			if (c->help) {
+				printf("%-*s\t%s\r\n", HELPINDENT, c->name,
+								    c->help);
+			}
+		return 0;
+	}
+	while (--argc > 0) {
+		register char *arg;
+		arg = *++argv;
+		c = getcmd(arg);
+		if (Ambiguous(c))
+			printf("?Ambiguous help command %s\r\n", arg);
+		else if (c == (Command *)0)
+			printf("?Invalid help command %s\r\n", arg);
+		else
+			printf("%s\r\n", c->help);
+	}
+	return 0;
+}
+
+static char *rcname = 0;
+static char rcbuf[128];
+
+void
+cmdrc(m1, m2)
+	char *m1, *m2;
+{
+    register Command *c;
+    FILE *rcfile;
+    int gotmachine = 0;
+    unsigned int l1 = strlen(m1);
+    unsigned int l2 = strlen(m2);
+    char m1save[64];
+
+    if (skiprc)
+	return;
+
+    strncpy(m1save, m1, sizeof(m1save) - 1);
+    m1save[sizeof(m1save) - 1] = '\0';
+    m1 = m1save;
+
+    if (rcname == 0) {
+	rcname = getenv("HOME");
+	if (rcname)
+	    strncpy(rcbuf, rcname, sizeof(rcbuf) - 1);
+	else
+	    rcbuf[0] = '\0';
+	rcbuf[sizeof(rcbuf) - 1] = '\0';
+	strncat(rcbuf, "/.telnetrc", sizeof(rcbuf) - 1 - strlen(rcbuf));
+	rcname = rcbuf;
+    }
+
+    if ((rcfile = fopen(rcname, "r")) == 0) {
+	return;
+    }
+
+    for (;;) {
+	if (fgets(line, sizeof(line), rcfile) == NULL)
+	    break;
+	if (line[0] == 0)
+	    break;
+	if (line[0] == '#')
+	    continue;
+	if (gotmachine) {
+	    if (!isspace((int) line[0]))
+		gotmachine = 0;
+	}
+	if (gotmachine == 0) {
+	    if (isspace((int) line[0]))
+		continue;
+	    if (strncasecmp(line, m1, l1) == 0)
+		strncpy(line, &line[l1], sizeof(line) - l1);
+	    else if (strncasecmp(line, m2, l2) == 0)
+		strncpy(line, &line[l2], sizeof(line) - l2);
+	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
+		strncpy(line, &line[7], sizeof(line) - 7);
+	    else
+		continue;
+	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
+		continue;
+	    gotmachine = 1;
+	}
+	makeargv();
+	if (margv[0] == 0)
+	    continue;
+	c = getcmd(margv[0]);
+	if (Ambiguous(c)) {
+	    printf("?Ambiguous command: %s\r\n", margv[0]);
+	    continue;
+	}
+	if (c == 0) {
+	    printf("?Invalid command: %s\r\n", margv[0]);
+	    continue;
+	}
+	/*
+	 * This should never happen...
+	 */
+	if (c->needconnect && !connected) {
+	    printf("?Need to be connected first for %s.\r\n", margv[0]);
+	    continue;
+	}
+	(*c->handler)(margc, margv);
+    }
+    fclose(rcfile);
+}
+
+#if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
+
+/*
+ * Source route is handed in as
+ *	[!]@hop1@hop2...[@|:]dst
+ * If the leading ! is present, it is a
+ * strict source route, otherwise it is
+ * assmed to be a loose source route.
+ *
+ * We fill in the source route option as
+ *	hop1,hop2,hop3...dest
+ * and return a pointer to hop1, which will
+ * be the address to connect() to.
+ *
+ * Arguments:
+ *	arg:	pointer to route list to decipher
+ *
+ *	cpp: 	If *cpp is not equal to NULL, this is a
+ *		pointer to a pointer to a character array
+ *		that should be filled in with the option.
+ *
+ *	lenp:	pointer to an integer that contains the
+ *		length of *cpp if *cpp != NULL.
+ *
+ * Return values:
+ *
+ *	Returns the address of the host to connect to.  If the
+ *	return value is -1, there was a syntax error in the
+ *	option, either unknown characters, or too many hosts.
+ *	If the return value is 0, one of the hostnames in the
+ *	path is unknown, and *cpp is set to point to the bad
+ *	hostname.
+ *
+ *	*cpp:	If *cpp was equal to NULL, it will be filled
+ *		in with a pointer to our static area that has
+ *		the option filled in.  This will be 32bit aligned.
+ * 
+ *	*lenp:	This will be filled in with how long the option
+ *		pointed to by *cpp is.
+ *	
+ */
+static	unsigned long
+sourceroute(arg, cpp, lenp)
+	char	*arg;
+	char	**cpp;
+	int	*lenp;
+{
+	static char lsr[44];
+#ifdef	sysV88
+	static IOPTN ipopt;
+#endif
+	char *cp, *cp2, *lsrp, *lsrep;
+	register int tmp;
+	struct in_addr sin_addr;
+	register struct hostent *host = 0;
+	register char c;
+
+	/*
+	 * Verify the arguments, and make sure we have
+	 * at least 7 bytes for the option.
+	 */
+	if (cpp == NULL || lenp == NULL)
+		return((unsigned long)-1);
+	if (*cpp != NULL && *lenp < 7)
+		return((unsigned long)-1);
+	/*
+	 * Decide whether we have a buffer passed to us,
+	 * or if we need to use our own static buffer.
+	 */
+	if (*cpp) {
+		lsrp = *cpp;
+		lsrep = lsrp + *lenp;
+	} else {
+		*cpp = lsrp = lsr;
+		lsrep = lsrp + 44;
+	}
+
+	cp = arg;
+
+	/*
+	 * Next, decide whether we have a loose source
+	 * route or a strict source route, and fill in
+	 * the begining of the option.
+	 */
+#ifndef	sysV88
+	if (*cp == '!') {
+		cp++;
+		*lsrp++ = IPOPT_SSRR;
+	} else
+		*lsrp++ = IPOPT_LSRR;
+#else
+	if (*cp == '!') {
+		cp++;
+		ipopt.io_type = IPOPT_SSRR;
+	} else
+		ipopt.io_type = IPOPT_LSRR;
+#endif
+
+	if (*cp != '@')
+		return((unsigned long)-1);
+
+#ifndef	sysV88
+	lsrp++;		/* skip over length, we'll fill it in later */
+	*lsrp++ = 4;
+#endif
+
+	cp++;
+
+	sin_addr.s_addr = 0;
+
+	for (c = 0;;) {
+		if (c == ':')
+			cp2 = 0;
+		else for (cp2 = cp; (c = *cp2); cp2++) {
+			if (c == ',') {
+				*cp2++ = '\0';
+				if (*cp2 == '@')
+					cp2++;
+			} else if (c == '@') {
+				*cp2++ = '\0';
+			} else if (c == ':') {
+				*cp2++ = '\0';
+			} else
+				continue;
+			break;
+		}
+		if (!c)
+			cp2 = 0;
+
+		if ((tmp = inet_addr(cp)) != -1) {
+			sin_addr.s_addr = tmp;
+		} else if ((host = gethostbyname(cp))) {
+#if	defined(h_addr)
+			memcpy((caddr_t)&sin_addr,
+				host->h_addr_list[0], sizeof(sin_addr));
+#else
+			memcpy((caddr_t)&sin_addr, host->h_addr, 
+			       sizeof(sin_addr));
+#endif
+		} else {
+			*cpp = cp;
+			return(0);
+		}
+		memcpy(lsrp, (char *)&sin_addr, 4);
+		lsrp += 4;
+		if (cp2)
+			cp = cp2;
+		else
+			break;
+		/*
+		 * Check to make sure there is space for next address
+		 */
+		if (lsrp + 4 > lsrep)
+			return((unsigned long)-1);
+	}
+#ifndef	sysV88
+	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
+		*cpp = 0;
+		*lenp = 0;
+		return((unsigned long)-1);
+	}
+	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
+	*lenp = lsrp - *cpp;
+#else
+	ipopt.io_len = lsrp - *cpp;
+	if (ipopt.io_len <= 5) {		/* Is 3 better ? */
+		*cpp = 0;
+		*lenp = 0;
+		return((unsigned long)-1);
+	}
+	*lenp = sizeof(ipopt);
+	*cpp = (char *) &ipopt;
+#endif
+	return(sin_addr.s_addr);
+}
+#endif
diff --git a/mechglue/src/appl/telnet/telnet/defines.h b/mechglue/src/appl/telnet/telnet/defines.h
new file mode 100644
index 000000000..0978173ea
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/defines.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)defines.h	8.1 (Berkeley) 6/6/93
+ */
+
+#define	settimer(x)	clocks.x = clocks.system++
+
+#if	!defined(TN3270)
+
+#define	SetIn3270()
+
+#endif	/* !defined(TN3270) */
+
+#define	NETADD(c)	{ *netoring.supply = c; ring_supplied(&netoring, 1); }
+#define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
+#define	NETBYTES()	(ring_full_count(&netoring))
+#define	NETROOM()	(ring_empty_count(&netoring))
+
+#define	TTYADD(c)	if (!(SYNCHing||flushout)) { \
+				*ttyoring.supply = c; \
+				ring_supplied(&ttyoring, 1); \
+			}
+#define	TTYBYTES()	(ring_full_count(&ttyoring))
+#define	TTYROOM()	(ring_empty_count(&ttyoring))
+
+/*	Various modes */
+#define	MODE_LOCAL_CHARS(m)	((m)&(MODE_EDIT|MODE_TRAPSIG))
+#define	MODE_LOCAL_ECHO(m)	((m)&MODE_ECHO)
+#define	MODE_COMMAND_LINE(m)	((m)==-1)
+
+#define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
diff --git a/mechglue/src/appl/telnet/telnet/externs.h b/mechglue/src/appl/telnet/telnet/externs.h
new file mode 100644
index 000000000..dccb424f0
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/externs.h
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)externs.h	8.1 (Berkeley) 6/6/93
+ */
+
+#include <sys/param.h>
+
+#ifndef	BSD
+# define BSD 43
+#endif
+
+/*
+ * ucb stdio.h defines BSD as something wierd
+ */
+#if defined(sun) && defined(__svr4__)
+#define BSD 43
+#endif
+
+#ifndef	USE_TERMIO
+# if BSD > 43 || defined(SYSV_TERMIO)
+#  define USE_TERMIO
+# endif
+#endif
+
+#include <stdio.h>
+#include <setjmp.h>
+#if defined(CRAY) && !defined(NO_BSD_SETJMP)
+#include <bsdsetjmp.h>
+#endif
+#ifndef	HAVE_SYS_FILIO_H
+#include <sys/ioctl.h>
+#else
+#include <sys/filio.h>
+#endif
+#ifdef CRAY
+# include <errno.h>
+#endif /* CRAY */
+#ifdef	USE_TERMIO
+# ifndef	VINTR
+#  ifdef SYSV_TERMIO
+#   include <sys/termio.h>
+#  else
+#   include <termios.h>
+#  endif
+# endif
+#endif
+#if defined(USE_TERMIO) && !defined(SYSV_TERMIO)
+# define termio termios
+#endif
+#if defined(NO_CC_T) || !defined(USE_TERMIO)
+# if !defined(USE_TERMIO)
+typedef char cc_t;
+# else
+typedef unsigned char cc_t;
+# endif
+#endif
+
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc(), *calloc(), *realloc();
+#endif
+
+#ifndef	HAVE_STRING_H
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+
+#ifndef	_POSIX_VDISABLE
+# ifdef sun
+#  include <sys/param.h>	/* pick up VDISABLE definition, mayby */
+# endif
+# ifdef VDISABLE
+#  define _POSIX_VDISABLE VDISABLE
+# else
+#  define _POSIX_VDISABLE ((cc_t)'\377')
+# endif
+#endif
+
+#define	SUBBUFSIZE	256
+
+extern int
+    autologin,		/* Autologin enabled */
+    skiprc,		/* Don't process the ~/.telnetrc file */
+    eight,		/* use eight bit mode (binary in and/or out */
+    flushout,		/* flush output */
+    connected,		/* Are we connected to the other side? */
+    globalmode,		/* Mode tty should be in */
+    In3270,			/* Are we in 3270 mode? */
+    telnetport,		/* Are we connected to the telnet port? */
+    localflow,		/* Flow control handled locally */
+    restartany,		/* If flow control, restart output on any character */
+    localchars,		/* we recognize interrupt/quit */
+    donelclchars,		/* the user has set "localchars" */
+    showoptions,
+    wantencryption,	/* User has requested encryption */
+    net,		/* Network file descriptor */
+    tin,		/* Terminal input file descriptor */
+    tout,		/* Terminal output file descriptor */
+    crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
+    autoflush,		/* flush output when interrupting? */
+    autosynch,		/* send interrupt characters with SYNCH? */
+    SYNCHing,		/* Is the stream in telnet SYNCH mode? */
+    donebinarytoggle,	/* the user has put us in binary */
+    dontlecho,		/* do we suppress local echoing right now? */
+    crmod,
+    netdata,		/* Print out network data flow */
+    prettydump,		/* Print "netdata" output in user readable format */
+#if	defined(TN3270)
+    cursesdata,		/* Print out curses data flow */
+    apitrace,		/* Trace API transactions */
+#endif	/* defined(TN3270) */
+    termdata,		/* Print out terminal data flow */
+    debug;			/* Debug level */
+
+extern int intr_happened, intr_waiting;	/* for interrupt handling */
+
+extern cc_t escape;	/* Escape to command mode */
+extern cc_t rlogin;	/* Rlogin mode escape character */
+#ifdef	KLUDGELINEMODE
+extern cc_t echoc;	/* Toggle local echoing */
+#endif
+
+extern char
+    *prompt;		/* Prompt for command. */
+
+extern char
+    doopt[],
+    dont[],
+    will[],
+    wont[],
+    options[],		/* All the little options */
+    *hostname;		/* Who are we connected to? */
+#ifdef	ENCRYPTION
+extern void (*encrypt_output) (unsigned char *, int);
+extern int (*decrypt_input) (int);
+#endif	/* ENCRYPTION */
+
+/*
+ * We keep track of each side of the option negotiation.
+ */
+
+#define	MY_STATE_WILL		0x01
+#define	MY_WANT_STATE_WILL	0x02
+#define	MY_STATE_DO		0x04
+#define	MY_WANT_STATE_DO	0x08
+
+/*
+ * Macros to check the current state of things
+ */
+
+#define	my_state_is_do(opt)		(options[opt]&MY_STATE_DO)
+#define	my_state_is_will(opt)		(options[opt]&MY_STATE_WILL)
+#define my_want_state_is_do(opt)	(options[opt]&MY_WANT_STATE_DO)
+#define my_want_state_is_will(opt)	(options[opt]&MY_WANT_STATE_WILL)
+
+#define	my_state_is_dont(opt)		(!my_state_is_do(opt))
+#define	my_state_is_wont(opt)		(!my_state_is_will(opt))
+#define my_want_state_is_dont(opt)	(!my_want_state_is_do(opt))
+#define my_want_state_is_wont(opt)	(!my_want_state_is_will(opt))
+
+#define	set_my_state_do(opt)		{options[opt] |= MY_STATE_DO;}
+#define	set_my_state_will(opt)		{options[opt] |= MY_STATE_WILL;}
+#define	set_my_want_state_do(opt)	{options[opt] |= MY_WANT_STATE_DO;}
+#define	set_my_want_state_will(opt)	{options[opt] |= MY_WANT_STATE_WILL;}
+
+#define	set_my_state_dont(opt)		{options[opt] &= ~MY_STATE_DO;}
+#define	set_my_state_wont(opt)		{options[opt] &= ~MY_STATE_WILL;}
+#define	set_my_want_state_dont(opt)	{options[opt] &= ~MY_WANT_STATE_DO;}
+#define	set_my_want_state_wont(opt)	{options[opt] &= ~MY_WANT_STATE_WILL;}
+
+/*
+ * Make everything symetrical
+ */
+
+#define	HIS_STATE_WILL			MY_STATE_DO
+#define	HIS_WANT_STATE_WILL		MY_WANT_STATE_DO
+#define HIS_STATE_DO			MY_STATE_WILL
+#define HIS_WANT_STATE_DO		MY_WANT_STATE_WILL
+
+#define	his_state_is_do			my_state_is_will
+#define	his_state_is_will		my_state_is_do
+#define his_want_state_is_do		my_want_state_is_will
+#define his_want_state_is_will		my_want_state_is_do
+
+#define	his_state_is_dont		my_state_is_wont
+#define	his_state_is_wont		my_state_is_dont
+#define his_want_state_is_dont		my_want_state_is_wont
+#define his_want_state_is_wont		my_want_state_is_dont
+
+#define	set_his_state_do		set_my_state_will
+#define	set_his_state_will		set_my_state_do
+#define	set_his_want_state_do		set_my_want_state_will
+#define	set_his_want_state_will		set_my_want_state_do
+
+#define	set_his_state_dont		set_my_state_wont
+#define	set_his_state_wont		set_my_state_dont
+#define	set_his_want_state_dont		set_my_want_state_wont
+#define	set_his_want_state_wont		set_my_want_state_dont
+
+
+extern FILE
+    *NetTrace;		/* Where debugging output goes */
+extern unsigned char
+    NetTraceFile[];	/* Name of file where debugging output goes */
+extern void
+    SetNetTrace (char *);	/* Function to change where debugging goes */
+
+extern jmp_buf
+    peerdied,
+    toplevel;		/* For error conditions. */
+
+extern void
+    command (int, char *, int),
+    Dump (int, unsigned char *, int),
+    init_3270 (void),
+    init_terminal (void),
+    init_telnet (void),
+    init_network (void),
+    init_sys (void),
+    printoption (char *, int, int),
+    printsub (int, unsigned char *, int),
+    sendnaws (void),
+    sendabort (void),
+    sendeof (void),
+    sendayt (void),
+    sendsusp (void),
+    setconnmode (int),
+    setcommandmode (void),
+    setneturg (void),
+    set_escape_char (char *),
+    sys_telnet_init (void),
+    telnet (char *),
+    tel_enter_binary (int),
+    tel_leave_binary (int),
+    TerminalDefaultChars (void),
+    TerminalFlushOutput (void),
+    TerminalNewMode (int),
+    TerminalRestoreState (void),
+    TerminalSaveState (void),
+    TerminalSpeeds (long *, long *),
+    tninit (void),
+    upcase (char *),
+    willoption (int),
+    wontoption (int);
+
+extern void
+    send_do (int, int),
+    send_dont (int, int),
+    send_will (int, int),
+    send_wont (int, int);
+
+extern void
+    sendbrk (void),
+    intp (void),
+    xmitAO (void),
+    xmitEL (void),
+    xmitEC (void);
+
+extern void
+    lm_will (unsigned char *, int),
+    lm_wont (unsigned char *, int),
+    lm_do (unsigned char *, int),
+    lm_dont (unsigned char *, int),
+    lm_mode (unsigned char *, int, int);
+
+extern void
+    ExitString (char *, int), 
+    Exit (int),
+    SetForExit (void),
+    EmptyTerminal (void),
+    slc_init (void),
+    slcstate (void),
+    slc_mode_export (void),
+    slc_mode_import (int),
+    slc_import (int),
+    slc_export (void),
+    slc (unsigned char *, int),
+    slc_check (void),
+    slc_start_reply (void),
+    slc_add_reply (int, int, int),
+    slc_end_reply (void);
+
+extern int
+    quit (int, char *[]), 
+    ttyflush (int),
+    rlogin_susp (void),
+    tn (int, char **),
+    getconnmode (void),
+    netflush (void),
+    NetClose (int),
+    opt_welldefined (char *),
+    process_rings (int, int, int, int, int, int),
+    slc_update (void),
+    Scheduler (int),
+    SetSockOpt (int, int, int, int),
+    stilloob (void), 
+    telrcv (void),
+    telnet_spin (void),
+    TerminalWrite (unsigned char *, int),
+    TerminalRead (unsigned char *, int),
+    TerminalAutoFlush (void),
+    TerminalSpecialChars (int),
+    TerminalWindowSize (long *, long *);
+
+
+extern void
+    env_init (void),
+    env_opt (unsigned char *, int),
+    env_opt_start (void),
+    env_opt_start_info (void),
+    env_opt_add (unsigned char *),
+    env_opt_end (int),
+    optionstatus (void);
+
+extern unsigned char
+    *env_default (int, int),
+    *env_getvalue (unsigned char *);
+
+extern int
+    env_is_exported (unsigned char *);
+
+extern int
+    get_status (char *),
+    dosynch (char *);
+
+extern cc_t
+    *tcval (int);
+
+#ifndef	USE_TERMIO
+
+extern struct	tchars ntc;
+extern struct	ltchars nltc;
+extern struct	sgttyb nttyb;
+
+# define termEofChar		ntc.t_eofc
+# define termEraseChar		nttyb.sg_erase
+# define termFlushChar		nltc.t_flushc
+# define termIntChar		ntc.t_intrc
+# define termKillChar		nttyb.sg_kill
+# define termLiteralNextChar	nltc.t_lnextc
+# define termQuitChar		ntc.t_quitc
+# define termSuspChar		nltc.t_suspc
+# define termRprntChar		nltc.t_rprntc
+# define termWerasChar		nltc.t_werasc
+# define termStartChar		ntc.t_startc
+# define termStopChar		ntc.t_stopc
+# define termForw1Char		ntc.t_brkc
+extern cc_t termForw2Char;
+extern cc_t termAytChar;
+
+# define termEofCharp		(cc_t *)&ntc.t_eofc
+# define termEraseCharp		(cc_t *)&nttyb.sg_erase
+# define termFlushCharp		(cc_t *)&nltc.t_flushc
+# define termIntCharp		(cc_t *)&ntc.t_intrc
+# define termKillCharp		(cc_t *)&nttyb.sg_kill
+# define termLiteralNextCharp	(cc_t *)&nltc.t_lnextc
+# define termQuitCharp		(cc_t *)&ntc.t_quitc
+# define termSuspCharp		(cc_t *)&nltc.t_suspc
+# define termRprntCharp		(cc_t *)&nltc.t_rprntc
+# define termWerasCharp		(cc_t *)&nltc.t_werasc
+# define termStartCharp		(cc_t *)&ntc.t_startc
+# define termStopCharp		(cc_t *)&ntc.t_stopc
+# define termForw1Charp		(cc_t *)&ntc.t_brkc
+# define termForw2Charp		(cc_t *)&termForw2Char
+# define termAytCharp		(cc_t *)&termAytChar
+
+# else
+
+extern struct	termio new_tc;
+
+# define termEofChar		new_tc.c_cc[VEOF]
+# define termEraseChar		new_tc.c_cc[VERASE]
+# define termIntChar		new_tc.c_cc[VINTR]
+# define termKillChar		new_tc.c_cc[VKILL]
+# define termQuitChar		new_tc.c_cc[VQUIT]
+
+# ifndef	VSUSP
+extern cc_t termSuspChar;
+# else
+#  define termSuspChar		new_tc.c_cc[VSUSP]
+# endif
+# if	defined(VFLUSHO) && !defined(VDISCARD)
+#  define VDISCARD VFLUSHO
+# endif
+# ifndef	VDISCARD
+extern cc_t termFlushChar;
+# else
+#  define termFlushChar		new_tc.c_cc[VDISCARD]
+# endif
+# ifndef VWERASE
+extern cc_t termWerasChar;
+# else
+#  define termWerasChar		new_tc.c_cc[VWERASE]
+# endif
+# ifndef	VREPRINT
+extern cc_t termRprntChar;
+# else
+#  define termRprntChar		new_tc.c_cc[VREPRINT]
+# endif
+# ifndef	VLNEXT
+extern cc_t termLiteralNextChar;
+# else
+#  define termLiteralNextChar	new_tc.c_cc[VLNEXT]
+# endif
+# ifndef	VSTART
+extern cc_t termStartChar;
+# else
+#  define termStartChar		new_tc.c_cc[VSTART]
+# endif
+# ifndef	VSTOP
+extern cc_t termStopChar;
+# else
+#  define termStopChar		new_tc.c_cc[VSTOP]
+# endif
+# ifndef	VEOL
+extern cc_t termForw1Char;
+# else
+#  define termForw1Char		new_tc.c_cc[VEOL]
+# endif
+# ifndef	VEOL2
+extern cc_t termForw2Char;
+# else
+#  define termForw2Char		new_tc.c_cc[VEOL]
+# endif
+# ifndef	VSTATUS
+extern cc_t termAytChar;
+#else
+#  define termAytChar		new_tc.c_cc[VSTATUS]
+#endif
+
+# if !defined(CRAY) || defined(__STDC__)
+#  define termEofCharp		&termEofChar
+#  define termEraseCharp	&termEraseChar
+#  define termIntCharp		&termIntChar
+#  define termKillCharp		&termKillChar
+#  define termQuitCharp		&termQuitChar
+#  define termSuspCharp		&termSuspChar
+#  define termFlushCharp	&termFlushChar
+#  define termWerasCharp	&termWerasChar
+#  define termRprntCharp	&termRprntChar
+#  define termLiteralNextCharp	&termLiteralNextChar
+#  define termStartCharp	&termStartChar
+#  define termStopCharp		&termStopChar
+#  define termForw1Charp	&termForw1Char
+#  define termForw2Charp	&termForw2Char
+#  define termAytCharp		&termAytChar
+# else
+	/* Work around a compiler bug */
+#  define termEofCharp		0
+#  define termEraseCharp	0
+#  define termIntCharp		0
+#  define termKillCharp		0
+#  define termQuitCharp		0
+#  define termSuspCharp		0
+#  define termFlushCharp	0
+#  define termWerasCharp	0
+#  define termRprntCharp	0
+#  define termLiteralNextCharp	0
+#  define termStartCharp	0
+#  define termStopCharp		0
+#  define termForw1Charp	0
+#  define termForw2Charp	0
+#  define termAytCharp		0
+# endif
+#endif
+
+
+/* Ring buffer structures which are shared */
+
+extern Ring
+    netoring,
+    netiring,
+    ttyoring,
+    ttyiring;
+
+/* Tn3270 section */
+#if	defined(TN3270)
+
+extern int
+    HaveInput,		/* Whether an asynchronous I/O indication came in */
+    noasynchtty,	/* Don't do signals on I/O (SIGURG, SIGIO) */
+    noasynchnet,	/* Don't do signals on I/O (SIGURG, SIGIO) */
+    sigiocount,		/* Count of SIGIO receptions */
+    shell_active;	/* Subshell is active */
+
+extern char
+    *Ibackp,		/* Oldest byte of 3270 data */
+    Ibuf[],		/* 3270 buffer */
+    *Ifrontp,		/* Where next 3270 byte goes */
+    tline[200],
+    *transcom;		/* Transparent command */
+
+extern int
+    settranscom (int, char**);
+
+extern void
+    inputAvailable (int);
+#endif	/* defined(TN3270) */
diff --git a/mechglue/src/appl/telnet/telnet/fdset.h b/mechglue/src/appl/telnet/telnet/fdset.h
new file mode 100644
index 000000000..045bb7221
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/fdset.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)fdset.h	8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * The following is defined just in case someone should want to run
+ * this telnet on a 4.2 system.
+ *
+ */
+
+#ifndef	FD_SETSIZE
+
+#define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
+#define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
+#define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
+#define FD_ZERO(p)	((p)->fds_bits[0] = 0)
+
+#endif
diff --git a/mechglue/src/appl/telnet/telnet/general.h b/mechglue/src/appl/telnet/telnet/general.h
new file mode 100644
index 000000000..4efa95194
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/general.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)general.h	8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Some general definitions.
+ */
+
+
+#define	numberof(x)	(sizeof x/sizeof x[0])
+#define	highestof(x)	(numberof(x)-1)
+
+#define	ClearElement(x)		memset((char *)&x, 0, sizeof x)
+#define	ClearArray(x)		memset((char *)x, 0, sizeof x)
diff --git a/mechglue/src/appl/telnet/telnet/main.c b/mechglue/src/appl/telnet/telnet/main.c
new file mode 100644
index 000000000..77832f912
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/main.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 1988, 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1988, 1990 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)main.c	5.5 (Berkeley) 12/18/92 */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <libtelnet/auth.h>
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+# include <netinet/in.h>
+
+#include "ring.h"
+#include "externs.h"
+#include "defines.h"
+
+#ifdef NEED_PARSETOS_PROTO
+extern int parsetos(char *, char *);
+#endif
+
+#if 0
+#define FORWARD
+#endif
+
+/*
+ * Initialize variables.
+ */
+    void
+tninit()
+{
+    init_terminal();
+
+    init_network();
+    
+    init_telnet();
+
+    init_sys();
+
+#if defined(TN3270)
+    init_3270();
+#endif
+}
+
+static void
+usage()
+{
+	fprintf(stderr, "Usage: %s %s%s%s%s\n",
+	    prompt,
+#ifdef	AUTHENTICATION
+	    " [-8] [-E] [-K] [-L] [-X atype] [-a] [-d] [-e char] [-k realm]",
+	    "\n\t[-l user] [-f/-F] [-n tracefile] ",
+#else
+	    " [-8] [-E] [-L] [-a] [-d] [-e char] [-l user] [-n tracefile]",
+	    "\n\t",
+#endif
+#if defined(TN3270) && defined(unix)
+# ifdef AUTHENTICATION
+	    "[-noasynch] [-noasynctty] [-noasyncnet]\n\t[-r] [-t transcom] ",
+# else
+	    "[-noasynch] [-noasynctty] [-noasyncnet] [-r] [-t transcom]\n\t",
+# endif
+#else
+	    "[-r] ",
+#endif
+#ifdef	ENCRYPTION
+	    "[-x] [host-name [port]]"
+#else
+	    "[host-name [port]]"
+#endif
+	);
+	exit(1);
+}
+
+/*
+ * main.  Parse arguments, invoke the protocol or command parser.
+ */
+
+/* see forward.c -- indicate that we're in telnet, not telnetd. */
+char *line = 0;
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	extern char *optarg;
+	extern int optind;
+	int ch;
+	char *user;
+#ifdef	FORWARD
+	extern int forward_flags;
+#endif	/* FORWARD */
+#ifdef ENCRYPTION
+	extern int auth_enable_encrypt;
+#endif /* ENCRYPTION */
+
+	tninit();		/* Clear out things */
+#if	defined(CRAY) && !defined(__STDC__)
+	_setlist_init();	/* Work around compiler bug */
+#endif
+
+	TerminalSaveState();
+
+	if ((prompt = strrchr(argv[0], '/')))
+		++prompt;
+	else
+		prompt = argv[0];
+
+	user = NULL;
+
+	rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
+	autologin = -1;
+
+	while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != -1) {
+		switch(ch) {
+		case '8':
+			eight = 3;	/* binary output and input */
+			break;
+		case 'E':
+			rlogin = escape = _POSIX_VDISABLE;
+			break;
+		case 'K':
+#ifdef	AUTHENTICATION
+			autologin = 0;
+#endif
+			break;
+		case 'L':
+			eight |= 2;	/* binary output only */
+			break;
+		case 'S':
+		    {
+#if defined(HAVE_GETTOSBYNAME) || (defined(IPPROTO_IP) && defined(IP_TOS))
+			extern int tos;
+
+			if ((tos = parsetos(optarg, "tcp")) < 0)
+				fprintf(stderr, "%s%s%s%s\n",
+					prompt, ": Bad TOS argument '",
+					optarg,
+					"; will try to use default TOS");
+
+                      fprintf(stderr, "Setting TOS to 0x%x\n", tos);
+#else
+			fprintf(stderr,
+			   "%s: Warning: -S ignored, no parsetos() support.\n",
+								prompt);
+#endif
+		    }
+			break;
+		case 'X':
+#ifdef	AUTHENTICATION
+			auth_disable_name(optarg);
+#endif
+			break;
+		case 'a':
+			autologin = 1;
+			break;
+		case 'c':
+			skiprc = 1;
+			break;
+		case 'd':
+			debug = 1;
+			break;
+		case 'e':
+			set_escape_char(optarg);
+			break;
+		case 'f':
+#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
+			if (forward_flags & OPTS_FORWARD_CREDS) {
+			    fprintf(stderr, 
+				    "%s: Only one of -f and -F allowed.\n",
+				    prompt);
+			    usage();
+			}
+			forward_flags |= OPTS_FORWARD_CREDS;
+#else
+			fprintf(stderr,
+			 "%s: Warning: -f ignored, no Kerberos V5 support.\n", 
+				prompt);
+#endif
+			break;
+		case 'F':
+#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
+			if (forward_flags & OPTS_FORWARD_CREDS) {
+			    fprintf(stderr, 
+				    "%s: Only one of -f and -F allowed.\n",
+				    prompt);
+			    usage();
+			}
+			forward_flags |= OPTS_FORWARD_CREDS;
+			forward_flags |= OPTS_FORWARDABLE_CREDS;
+#else
+			fprintf(stderr,
+			 "%s: Warning: -F ignored, no Kerberos V5 support.\n", 
+				prompt);
+#endif
+			break;
+		case 'k':
+#if defined(AUTHENTICATION) && defined(KRB4)
+		    {
+			extern char *dest_realm, dst_realm_buf[];
+			extern unsigned int dst_realm_sz;
+			dest_realm = dst_realm_buf;
+			(void)strncpy(dest_realm, optarg, dst_realm_sz);
+		    }
+#endif
+#if defined(AUTHENTICATION) && defined(KRB5)
+		    {
+			extern char *telnet_krb5_realm;
+
+			telnet_krb5_realm = optarg;
+			break;
+		    }
+#endif
+#if !defined(AUTHENTICATION) || (!defined(KRB4) && !defined(KRB5))
+			fprintf(stderr,
+			   "%s: Warning: -k ignored, no Kerberos V4 support.\n",
+								prompt);
+#endif
+			break;
+		case 'l':
+			autologin = 1;
+			user = optarg;
+			break;
+		case 'n':
+#if defined(TN3270) && defined(unix)
+			/* distinguish between "-n oasynch" and "-noasynch" */
+			if (argv[optind - 1][0] == '-' && argv[optind - 1][1]
+			    == 'n' && argv[optind - 1][2] == 'o') {
+				if (!strcmp(optarg, "oasynch")) {
+					noasynchtty = 1;
+					noasynchnet = 1;
+				} else if (!strcmp(optarg, "oasynchtty"))
+					noasynchtty = 1;
+				else if (!strcmp(optarg, "oasynchnet"))
+					noasynchnet = 1;
+			} else
+#endif	/* defined(TN3270) && defined(unix) */
+				SetNetTrace(optarg);
+			break;
+		case 'r':
+			rlogin = '~';
+			break;
+		case 't':
+#if defined(TN3270) && defined(unix)
+			transcom = tline;
+			(void)strncpy(transcom, optarg, sizeof(tline) - 1);
+			tline[sizeof(tline) - 1] = '\0';
+#else
+			fprintf(stderr,
+			   "%s: Warning: -t ignored, no TN3270 support.\n",
+								prompt);
+#endif
+			break;
+		case 'x':
+#ifdef	ENCRYPTION
+			encrypt_auto(1);
+			decrypt_auto(1);
+			wantencryption = 1;
+			autologin = 1;
+			auth_enable_encrypt = 1;
+#else
+			fprintf(stderr,
+			    "%s: Warning: -x ignored, no ENCRYPT support.\n",
+								prompt);
+#endif
+			break;
+		case '?':
+		default:
+			usage();
+			/* NOTREACHED */
+		}
+	}
+	if (autologin == -1)
+		autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1;
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc) {
+		char *args[7], **volatile argp = args;
+
+		if (argc > 2)
+			usage();
+		*argp++ = prompt;
+		if (user) {
+			*argp++ = "-l";
+			*argp++ = user;
+		}
+		*argp++ = argv[0];		/* host */
+		if (argc > 1)
+			*argp++ = argv[1];	/* port */
+		*argp = 0;
+
+		if (setjmp(toplevel) != 0)
+			Exit(0);
+		if (tn(argp - args, args) == 1)
+			return (0);
+		else
+			return (1);
+	}
+	(void)setjmp(toplevel);
+	for (;;) {
+#ifdef TN3270
+		if (shell_active)
+			shell_continue();
+		else
+#endif
+			command(1, 0, 0);
+	}
+}
diff --git a/mechglue/src/appl/telnet/telnet/network.c b/mechglue/src/appl/telnet/telnet/network.c
new file mode 100644
index 000000000..1282bdb7e
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/network.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)network.c	8.1 (Berkeley) 6/6/93 */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <errno.h>
+
+#include <arpa/telnet.h>
+
+#include "ring.h"
+
+#include "defines.h"
+#include "externs.h"
+#include "fdset.h"
+
+Ring		netoring, netiring;
+unsigned char	netobuf[2*BUFSIZ], netibuf[BUFSIZ];
+
+/*
+ * Initialize internal network data structures.
+ */
+
+    void
+init_network()
+{
+    if (ring_init(&netoring, netobuf, sizeof netobuf) != 1) {
+	exit(1);
+    }
+    if (ring_init(&netiring, netibuf, sizeof netibuf) != 1) {
+	exit(1);
+    }
+    NetTrace = stdout;
+}
+
+
+/*
+ * Check to see if any out-of-band data exists on a socket (for
+ * Telnet "synch" processing).
+ */
+
+    int
+stilloob()
+{
+    static struct timeval timeout = { 0 };
+    fd_set	excepts;
+    int value;
+
+    do {
+	FD_ZERO(&excepts);
+	FD_SET(net, &excepts);
+	value = select(net+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
+    } while ((value == -1) && (errno == EINTR));
+
+    if (value < 0) {
+	perror("select");
+	(void) quit(0, NULL);
+	/* NOTREACHED */
+    }
+    if (FD_ISSET(net, &excepts)) {
+	return 1;
+    } else {
+	return 0;
+    }
+}
+
+
+/*
+ *  setneturg()
+ *
+ *	Sets "neturg" to the current location.
+ */
+
+    void
+setneturg()
+{
+    ring_mark(&netoring);
+}
+
+
+/*
+ *  netflush
+ *		Send as much data as possible to the network,
+ *	handling requests for urgent data.
+ *
+ *		The return value indicates whether we did any
+ *	useful work.
+ */
+
+
+    int
+netflush()
+{
+    register int n, n1;
+
+#ifdef	ENCRYPTION
+    if (encrypt_output)
+	ring_encrypt(&netoring, encrypt_output);
+#endif	/* ENCRYPTION */
+    if ((n1 = n = ring_full_consecutive(&netoring)) > 0) {
+	if (!ring_at_mark(&netoring)) {
+	    n = send(net, (char *)netoring.consume, n, 0); /* normal write */
+	} else {
+	    /*
+	     * In 4.2 (and 4.3) systems, there is some question about
+	     * what byte in a sendOOB operation is the "OOB" data.
+	     * To make ourselves compatible, we only send ONE byte
+	     * out of band, the one WE THINK should be OOB (though
+	     * we really have more the TCP philosophy of urgent data
+	     * rather than the Unix philosophy of OOB data).
+	     */
+	    n = send(net, (char *)netoring.consume, 1, MSG_OOB);/* URGENT data */
+	}
+    }
+    if (n < 0) {
+	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
+	    setcommandmode();
+	    perror(hostname);
+	    (void)NetClose(net);
+	    ring_clear_mark(&netoring);
+	    longjmp(peerdied, -1);
+	    /*NOTREACHED*/
+	}
+	n = 0;
+    }
+    if (netdata && n) {
+	Dump('>', netoring.consume, n);
+    }
+    if (n) {
+	ring_consumed(&netoring, n);
+	/*
+	 * If we sent all, and more to send, then recurse to pick
+	 * up the other half.
+	 */
+	if ((n1 == n) && ring_full_consecutive(&netoring)) {
+	    (void) netflush();
+	}
+	return 1;
+    } else {
+	return 0;
+    }
+}
diff --git a/mechglue/src/appl/telnet/telnet/ring.c b/mechglue/src/appl/telnet/telnet/ring.c
new file mode 100644
index 000000000..fdff682b5
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/ring.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)ring.c	8.1 (Berkeley) 6/6/93 */
+
+/*
+ * This defines a structure for a ring buffer.
+ *
+ * The circular buffer has two parts:
+ *(((
+ *	full:	[consume, supply)
+ *	empty:	[supply, consume)
+ *]]]
+ *
+ */
+
+#include	<stdio.h>
+#include	<errno.h>
+
+#ifdef	size_t
+#undef	size_t
+#endif
+
+#include	<sys/types.h>
+#ifndef	HAVE_SYS_FILIO_H
+#include	<sys/ioctl.h>
+#endif
+#include	<sys/socket.h>
+
+#include	"ring.h"
+#include	"general.h"
+
+#ifndef	NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* Internal macros */
+
+#if	!defined(MIN)
+#define	MIN(a,b)	(((a)<(b))? (a):(b))
+#endif	/* !defined(MIN) */
+
+#define	ring_subtract(d,a,b)	(((a)-(b) >= 0)? \
+					(a)-(b): (((a)-(b))+(d)->size))
+
+#define	ring_increment(d,a,c)	(((a)+(c) < (d)->top)? \
+					(a)+(c) : (((a)+(c))-(d)->size))
+
+#define	ring_decrement(d,a,c)	(((a)-(c) >= (d)->bottom)? \
+					(a)-(c) : (((a)-(c))-(d)->size))
+
+
+/*
+ * The following is a clock, used to determine full, empty, etc.
+ *
+ * There is some trickiness here.  Since the ring buffers are initialized
+ * to ZERO on allocation, we need to make sure, when interpreting the
+ * clock, that when the times are EQUAL, then the buffer is FULL.
+ */
+static u_long ring_clock = 0;
+
+
+#define	ring_empty(d) (((d)->consume == (d)->supply) && \
+				((d)->consumetime >= (d)->supplytime))
+#define	ring_full(d) (((d)->supply == (d)->consume) && \
+				((d)->supplytime > (d)->consumetime))
+
+
+
+
+
+/* Buffer state transition routines */
+
+int
+ring_init(ring, buffer, count)
+Ring *ring;
+    unsigned char *buffer;
+    int count;
+{
+    memset((char *)ring, 0, sizeof *ring);
+
+    ring->size = count;
+
+    ring->supply = ring->consume = ring->bottom = buffer;
+
+    ring->top = ring->bottom+ring->size;
+
+#ifdef	ENCRYPTION
+    ring->clearto = 0;
+#endif	/* ENCRYPTION */
+
+    return 1;
+}
+
+/* Mark routines */
+
+/*
+ * Mark the most recently supplied byte.
+ */
+
+    void
+ring_mark(ring)
+    Ring *ring;
+{
+    ring->mark = ring_decrement(ring, ring->supply, 1);
+}
+
+/*
+ * Is the ring pointing to the mark?
+ */
+
+    int
+ring_at_mark(ring)
+    Ring *ring;
+{
+    if (ring->mark == ring->consume) {
+	return 1;
+    } else {
+	return 0;
+    }
+}
+
+/*
+ * Clear any mark set on the ring.
+ */
+
+    void
+ring_clear_mark(ring)
+    Ring *ring;
+{
+    ring->mark = 0;
+}
+
+/*
+ * Add characters from current segment to ring buffer.
+ */
+    void
+ring_supplied(ring, count)
+    Ring *ring;
+    int count;
+{
+    ring->supply = ring_increment(ring, ring->supply, count);
+    ring->supplytime = ++ring_clock;
+}
+
+/*
+ * We have just consumed "c" bytes.
+ */
+    void
+ring_consumed(ring, count)
+    Ring *ring;
+    int count;
+{
+    if (count == 0)	/* don't update anything */
+	return;
+
+    if (ring->mark &&
+		(ring_subtract(ring, ring->mark, ring->consume) < count)) {
+	ring->mark = 0;
+    }
+#ifdef	ENCRYPTION
+    if (ring->consume < ring->clearto &&
+		ring->clearto <= ring->consume + count)
+	ring->clearto = 0;
+    else if (ring->consume + count > ring->top &&
+		ring->bottom <= ring->clearto &&
+		ring->bottom + ((ring->consume + count) - ring->top))
+	ring->clearto = 0;
+#endif	/* ENCRYPTION */
+    ring->consume = ring_increment(ring, ring->consume, count);
+    ring->consumetime = ++ring_clock;
+    /*
+     * Try to encourage "ring_empty_consecutive()" to be large.
+     */
+    if (ring_empty(ring)) {
+	ring->consume = ring->supply = ring->bottom;
+    }
+}
+
+
+
+/* Buffer state query routines */
+
+
+/* Number of bytes that may be supplied */
+    int
+ring_empty_count(ring)
+    Ring *ring;
+{
+    if (ring_empty(ring)) {	/* if empty */
+	    return ring->size;
+    } else {
+	return ring_subtract(ring, ring->consume, ring->supply);
+    }
+}
+
+/* number of CONSECUTIVE bytes that may be supplied */
+    int
+ring_empty_consecutive(ring)
+    Ring *ring;
+{
+    if ((ring->consume < ring->supply) || ring_empty(ring)) {
+			    /*
+			     * if consume is "below" supply, or empty, then
+			     * return distance to the top
+			     */
+	return ring_subtract(ring, ring->top, ring->supply);
+    } else {
+				    /*
+				     * else, return what we may.
+				     */
+	return ring_subtract(ring, ring->consume, ring->supply);
+    }
+}
+
+/* Return the number of bytes that are available for consuming
+ * (but don't give more than enough to get to cross over set mark)
+ */
+
+    int
+ring_full_count(ring)
+    Ring *ring;
+{
+    if ((ring->mark == 0) || (ring->mark == ring->consume)) {
+	if (ring_full(ring)) {
+	    return ring->size;	/* nothing consumed, but full */
+	} else {
+	    return ring_subtract(ring, ring->supply, ring->consume);
+	}
+    } else {
+	return ring_subtract(ring, ring->mark, ring->consume);
+    }
+}
+
+/*
+ * Return the number of CONSECUTIVE bytes available for consuming.
+ * However, don't return more than enough to cross over set mark.
+ */
+    int
+ring_full_consecutive(ring)
+    Ring *ring;
+{
+    if ((ring->mark == 0) || (ring->mark == ring->consume)) {
+	if ((ring->supply < ring->consume) || ring_full(ring)) {
+	    return ring_subtract(ring, ring->top, ring->consume);
+	} else {
+	    return ring_subtract(ring, ring->supply, ring->consume);
+	}
+    } else {
+	if (ring->mark < ring->consume) {
+	    return ring_subtract(ring, ring->top, ring->consume);
+	} else {	/* Else, distance to mark */
+	    return ring_subtract(ring, ring->mark, ring->consume);
+	}
+    }
+}
+
+/*
+ * Move data into the "supply" portion of of the ring buffer.
+ */
+    void
+ring_supply_data(ring, buffer, count)
+    Ring *ring;
+    unsigned char *buffer;
+    int count;
+{
+    int i;
+
+    while (count) {
+	i = MIN(count, ring_empty_consecutive(ring));
+	memcpy(ring->supply, buffer, i);
+	ring_supplied(ring, i);
+	count -= i;
+	buffer += i;
+    }
+}
+
+#ifdef notdef
+
+/*
+ * Move data from the "consume" portion of the ring buffer
+ */
+    void
+ring_consume_data(ring, buffer, count)
+    Ring *ring;
+    unsigned char *buffer;
+    int count;
+{
+    int i;
+
+    while (count) {
+	i = MIN(count, ring_full_consecutive(ring));
+	memcpy(buffer, ring->consume, i);
+	ring_consumed(ring, i);
+	count -= i;
+	buffer += i;
+    }
+}
+#endif
+
+#ifdef	ENCRYPTION
+    void
+ring_encrypt(ring, encryptor)
+    Ring *ring;
+    void (*encryptor)();
+{
+    unsigned char *s, *c;
+
+    if (ring_empty(ring) || ring->clearto == ring->supply)
+	return;
+
+    if (!(c = ring->clearto))
+	c = ring->consume;
+
+    s = ring->supply;
+
+    if (s <= c) {
+	(*encryptor)(c, ring->top - c);
+	(*encryptor)(ring->bottom, s - ring->bottom);
+    } else
+	(*encryptor)(c, s - c);
+
+    ring->clearto = ring->supply;
+}
+
+    void
+ring_clearto(ring)
+    Ring *ring;
+{
+    if (!ring_empty(ring))
+	ring->clearto = ring->supply;
+    else
+	ring->clearto = 0;
+}
+#endif	/* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/telnet/ring.h b/mechglue/src/appl/telnet/telnet/ring.h
new file mode 100644
index 000000000..87f0ab77a
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/ring.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ring.h	8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * This defines a structure for a ring buffer.
+ *
+ * The circular buffer has two parts:
+ *(((
+ *	full:	[consume, supply)
+ *	empty:	[supply, consume)
+ *]]]
+ *
+ */
+typedef struct {
+    unsigned char	*consume,	/* where data comes out of */
+			*supply,	/* where data comes in to */
+			*bottom,	/* lowest address in buffer */
+			*top,		/* highest address+1 in buffer */
+			*mark;		/* marker (user defined) */
+#ifdef	ENCRYPTION
+    unsigned char	*clearto;	/* Data to this point is clear text */
+    unsigned char	*encryyptedto;	/* Data is encrypted to here */
+#endif	/* ENCRYPTION */
+    int		size;		/* size in bytes of buffer */
+    u_long	consumetime,	/* help us keep straight full, empty, etc. */
+		supplytime;
+} Ring;
+
+/* Here are some functions and macros to deal with the ring buffer */
+
+/* Initialization routine */
+extern int
+	ring_init (Ring *ring, unsigned char *buffer, int count);
+
+/* Data movement routines */
+extern void
+	ring_supply_data (Ring *ring, unsigned char *buffer, int count);
+#ifdef notdef
+extern void
+	ring_consume_data (Ring *ring, unsigned char *buffer, int count);
+#endif
+
+/* Buffer state transition routines */
+extern void
+	ring_supplied (Ring *ring, int count),
+	ring_consumed (Ring *ring, int count);
+
+/* Buffer state query routines */
+extern int
+	ring_empty_count (Ring *ring),
+	ring_empty_consecutive (Ring *ring),
+	ring_full_count (Ring *ring),
+	ring_full_consecutive (Ring *ring);
+
+#ifdef	ENCRYPTION
+extern void
+	ring_encrypt (Ring *ring, void (*func)()),
+	ring_clearto (Ring *ring);
+#endif	/* ENCRYPTION */
+
+extern void
+    ring_clear_mark (Ring *ring),
+    ring_mark (Ring *ring);
+
+extern int
+    ring_at_mark (Ring *);
diff --git a/mechglue/src/appl/telnet/telnet/sys_bsd.c b/mechglue/src/appl/telnet/telnet/sys_bsd.c
new file mode 100644
index 000000000..89f9d4b5a
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/sys_bsd.c
@@ -0,0 +1,1208 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)sys_bsd.c	8.1 (Berkeley) 6/6/93 */
+
+/*
+ * The following routines try to encapsulate what is system dependent
+ * (at least between 4.x and dos) which is used in telnet.c.
+ */
+
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <signal.h>
+#ifdef POSIX_SIGNALS
+#include <unistd.h>
+#endif /* POSIX_SIGNALS */
+#include <errno.h>
+#include <arpa/telnet.h>
+
+#include "ring.h"
+
+#include "fdset.h"
+
+#include "defines.h"
+#include "externs.h"
+#include "types.h"
+
+#if	defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO))
+#define	SIG_FUNC_RET	void
+#else
+#define	SIG_FUNC_RET	int
+#endif
+
+#ifdef	SIGTSTP
+static SIG_FUNC_RET susp(int);
+#endif	/* SIGTSTP */
+#ifdef	SIGINFO
+SIG_FUNC_RET ayt(int);
+#endif
+#ifdef	SIGINFO
+extern SIG_FUNC_RET ayt_status();
+#endif
+
+#ifdef POSIX_SIGNALS
+static struct sigaction new_sa_rec, old_sa_rec;
+
+#ifdef SA_INTERRUPT
+#define SIGACTION_INTERRUPT SA_INTERRUPT
+#else
+#define SIGACTION_INTERRUPT 0
+#endif
+
+#ifdef SA_NOMASK
+#define SIGACTION_NOMASK SA_NOMASK
+#else
+#define SIGACTION_NOMASK 0
+#endif
+
+#define signal(sig, func) ((new_sa_rec.sa_handler = func), \
+			   sigemptyset(&new_sa_rec.sa_mask), \
+			   (new_sa_rec.sa_flags = SIGACTION_INTERRUPT | \
+			    SIGACTION_NOMASK), \
+			   sigaction(sig, &new_sa_rec, &old_sa_rec), \
+			   old_sa_rec.sa_handler)
+
+#endif /* POSIX_SIGNALS */
+
+int
+	tout,			/* Output file descriptor */
+	tin,			/* Input file descriptor */
+	net;
+
+#ifndef	USE_TERMIO
+struct	tchars otc = { 0 }, ntc = { 0 };
+struct	ltchars oltc = { 0 }, nltc = { 0 };
+struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
+int	olmode = 0;
+# define cfgetispeed(ptr)	(ptr)->sg_ispeed
+# define cfgetospeed(ptr)	(ptr)->sg_ospeed
+# define old_tc ottyb
+
+#else	/* USE_TERMIO */
+struct	termio old_tc = { 0 };
+extern struct termio new_tc;
+
+# ifndef	TCSANOW
+#  ifdef TCSETS
+#   define	TCSANOW		TCSETS
+#   define	TCSADRAIN	TCSETSW
+#   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
+#  else
+#   ifdef TCSETA
+#    define	TCSANOW		TCSETA
+#    define	TCSADRAIN	TCSETAW
+#    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
+#   else
+#    define	TCSANOW		TIOCSETA
+#    define	TCSADRAIN	TIOCSETAW
+#    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
+#   endif
+#  endif
+#  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
+#  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
+#  ifdef CIBAUD
+#   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
+#  else
+#   define	cfgetispeed(ptr)	cfgetospeed(ptr)
+#  endif
+# endif /* TCSANOW */
+# ifdef	sysV88
+# define TIOCFLUSH TC_PX_DRAIN
+# endif
+#endif	/* USE_TERMIO */
+
+static fd_set ibits, obits, xbits;
+
+
+    void
+init_sys()
+{
+    tout = fileno(stdout);
+    tin = fileno(stdin);
+    FD_ZERO(&ibits);
+    FD_ZERO(&obits);
+    FD_ZERO(&xbits);
+
+    errno = 0;
+}
+
+
+    int
+TerminalWrite(buf, n)
+    unsigned char *buf;
+    int  n;
+{
+    return write(tout, buf, n);
+}
+
+    int
+TerminalRead(buf, n)
+    unsigned char *buf;
+    int  n;
+{
+    return read(tin, buf, n);
+}
+
+/*
+ *
+ */
+
+    int
+TerminalAutoFlush()
+{
+#if	defined(LNOFLSH)
+    int flush;
+
+    ioctl(0, TIOCLGET, (char *)&flush);
+    return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
+#else	/* LNOFLSH */
+    return 1;
+#endif	/* LNOFLSH */
+}
+
+#ifdef	KLUDGELINEMODE
+extern int kludgelinemode;
+#endif
+/*
+ * TerminalSpecialChars()
+ *
+ * Look at an input character to see if it is a special character
+ * and decide what to do.
+ *
+ * Output:
+ *
+ *	0	Don't add this character.
+ *	1	Do add this character
+ */
+
+    int
+TerminalSpecialChars(c)
+    int	c;
+{
+    if (c == termIntChar) {
+	intp();
+	return 0;
+    } else if (c == termQuitChar) {
+#ifdef	KLUDGELINEMODE
+	if (kludgelinemode)
+	    sendbrk();
+	else
+#endif
+	    sendabort();
+	return 0;
+    } else if (c == termEofChar) {
+	if (my_want_state_is_will(TELOPT_LINEMODE)) {
+	    sendeof();
+	    return 0;
+	}
+	return 1;
+    } else if (c == termSuspChar) {
+	sendsusp();
+	return(0);
+    } else if (c == termFlushChar) {
+	xmitAO();		/* Transmit Abort Output */
+	return 0;
+    } else if (!MODE_LOCAL_CHARS(globalmode)) {
+	if (c == termKillChar) {
+	    xmitEL();
+	    return 0;
+	} else if (c == termEraseChar) {
+	    xmitEC();		/* Transmit Erase Character */
+	    return 0;
+	}
+    }
+    return 1;
+}
+
+
+/*
+ * Flush output to the terminal
+ */
+    void
+TerminalFlushOutput()
+{
+#ifdef	TIOCFLUSH
+    (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
+#else
+    (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
+#endif
+}
+
+    void
+TerminalSaveState()
+{
+#ifndef	USE_TERMIO
+    ioctl(0, TIOCGETP, (char *)&ottyb);
+    ioctl(0, TIOCGETC, (char *)&otc);
+    ioctl(0, TIOCGLTC, (char *)&oltc);
+    ioctl(0, TIOCLGET, (char *)&olmode);
+
+    ntc = otc;
+    nltc = oltc;
+    nttyb = ottyb;
+
+#else	/* USE_TERMIO */
+    tcgetattr(0, &old_tc);
+
+    new_tc = old_tc;
+
+#ifndef	VDISCARD
+    termFlushChar = CONTROL('O');
+#endif
+#ifndef	VWERASE
+    termWerasChar = CONTROL('W');
+#endif
+#ifndef	VREPRINT
+    termRprntChar = CONTROL('R');
+#endif
+#ifndef	VLNEXT
+    termLiteralNextChar = CONTROL('V');
+#endif
+#ifndef	VSTART
+    termStartChar = CONTROL('Q');
+#endif
+#ifndef	VSTOP
+    termStopChar = CONTROL('S');
+#endif
+#ifndef	VSTATUS
+    termAytChar = CONTROL('T');
+#endif
+#endif	/* USE_TERMIO */
+}
+
+    cc_t *
+tcval(func)
+    register int func;
+{
+    switch(func) {
+    case SLC_IP:	return(&termIntChar);
+    case SLC_ABORT:	return(&termQuitChar);
+    case SLC_EOF:	return(&termEofChar);
+    case SLC_EC:	return(&termEraseChar);
+    case SLC_EL:	return(&termKillChar);
+    case SLC_XON:	return(&termStartChar);
+    case SLC_XOFF:	return(&termStopChar);
+    case SLC_FORW1:	return(&termForw1Char);
+#ifdef	USE_TERMIO
+    case SLC_FORW2:	return(&termForw2Char);
+# ifdef	VDISCARD
+    case SLC_AO:	return(&termFlushChar);
+# endif
+# ifdef	VSUSP
+    case SLC_SUSP:	return(&termSuspChar);
+# endif
+# ifdef	VWERASE
+    case SLC_EW:	return(&termWerasChar);
+# endif
+# ifdef	VREPRINT
+    case SLC_RP:	return(&termRprntChar);
+# endif
+# ifdef	VLNEXT
+    case SLC_LNEXT:	return(&termLiteralNextChar);
+# endif
+# ifdef	VSTATUS
+    case SLC_AYT:	return(&termAytChar);
+# endif
+#endif
+
+    case SLC_SYNCH:
+    case SLC_BRK:
+    case SLC_EOR:
+    default:
+	return((cc_t *)0);
+    }
+}
+
+    void
+TerminalDefaultChars()
+{
+#ifndef	USE_TERMIO
+    ntc = otc;
+    nltc = oltc;
+    nttyb.sg_kill = ottyb.sg_kill;
+    nttyb.sg_erase = ottyb.sg_erase;
+#else	/* USE_TERMIO */
+    memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
+# ifndef	VDISCARD
+    termFlushChar = CONTROL('O');
+# endif
+# ifndef	VWERASE
+    termWerasChar = CONTROL('W');
+# endif
+# ifndef	VREPRINT
+    termRprntChar = CONTROL('R');
+# endif
+# ifndef	VLNEXT
+    termLiteralNextChar = CONTROL('V');
+# endif
+# ifndef	VSTART
+    termStartChar = CONTROL('Q');
+# endif
+# ifndef	VSTOP
+    termStopChar = CONTROL('S');
+# endif
+# ifndef	VSTATUS
+    termAytChar = CONTROL('T');
+# endif
+#endif	/* USE_TERMIO */
+}
+
+#ifdef notdef
+void
+TerminalRestoreState()
+{
+}
+#endif
+
+/*
+ * TerminalNewMode - set up terminal to a specific mode.
+ *	MODE_ECHO: do local terminal echo
+ *	MODE_FLOW: do local flow control
+ *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
+ *	MODE_EDIT: do local line editing
+ *
+ *	Command mode:
+ *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
+ *		local echo
+ *		local editing
+ *		local xon/xoff
+ *		local signal mapping
+ *
+ *	Linemode:
+ *		local/no editing
+ *	Both Linemode and Single Character mode:
+ *		local/remote echo
+ *		local/no xon/xoff
+ *		local/no signal mapping
+ */
+
+
+    void
+TerminalNewMode(f)
+    register int f;
+{
+    static int prevmode = 0;
+#ifndef	USE_TERMIO
+    struct tchars tc;
+    struct ltchars ltc;
+    struct sgttyb sb;
+    int lmode;
+#else	/* USE_TERMIO */
+    struct termio tmp_tc;
+#endif	/* USE_TERMIO */
+    int onoff;
+    int old;
+    cc_t esc;
+
+    globalmode = f&~MODE_FORCE;
+    if (prevmode == f)
+	return;
+
+    /*
+     * Write any outstanding data before switching modes
+     * ttyflush() returns 0 only when there is no more data
+     * left to write out, it returns -1 if it couldn't do
+     * anything at all, otherwise it returns 1 + the number
+     * of characters left to write.
+#ifndef	USE_TERMIO
+     * We would really like ask the kernel to wait for the output
+     * to drain, like we can do with the TCSADRAIN, but we don't have
+     * that option.  The only ioctl that waits for the output to
+     * drain, TIOCSETP, also flushes the input queue, which is NOT
+     * what we want (TIOCSETP is like TCSADFLUSH).
+#endif
+     */
+    old = ttyflush(SYNCHing|flushout);
+    if (old < 0 || old > 1) {
+#ifdef	USE_TERMIO
+	tcgetattr(tin, &tmp_tc);
+#endif	/* USE_TERMIO */
+	do {
+	    /*
+	     * Wait for data to drain, then flush again.
+	     */
+#ifdef	USE_TERMIO
+	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
+#endif	/* USE_TERMIO */
+	    old = ttyflush(SYNCHing|flushout);
+	} while (old < 0 || old > 1);
+    }
+
+    old = prevmode;
+    prevmode = f&~MODE_FORCE;
+#ifndef	USE_TERMIO
+    sb = nttyb;
+    tc = ntc;
+    ltc = nltc;
+    lmode = olmode;
+#else
+    tmp_tc = new_tc;
+#endif
+
+    if (f&MODE_ECHO) {
+#ifndef	USE_TERMIO
+	sb.sg_flags |= ECHO;
+#else
+	tmp_tc.c_lflag |= ECHO;
+	tmp_tc.c_oflag |= ONLCR;
+	if (crlf)
+		tmp_tc.c_iflag |= ICRNL;
+#endif
+    } else {
+#ifndef	USE_TERMIO
+	sb.sg_flags &= ~ECHO;
+#else
+	tmp_tc.c_lflag &= ~ECHO;
+	tmp_tc.c_oflag &= ~ONLCR;
+# ifdef notdef
+	if (crlf)
+		tmp_tc.c_iflag &= ~ICRNL;
+# endif
+#endif
+    }
+
+    if ((f&MODE_FLOW) == 0) {
+#ifndef	USE_TERMIO
+	tc.t_startc = _POSIX_VDISABLE;
+	tc.t_stopc = _POSIX_VDISABLE;
+#else
+	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
+    } else {
+	if (restartany < 0) {
+		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
+	} else if (restartany > 0) {
+		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
+	} else {
+		tmp_tc.c_iflag |= IXOFF|IXON;
+		tmp_tc.c_iflag &= ~IXANY;
+	}
+#endif
+    }
+
+    if ((f&MODE_TRAPSIG) == 0) {
+#ifndef	USE_TERMIO
+	tc.t_intrc = _POSIX_VDISABLE;
+	tc.t_quitc = _POSIX_VDISABLE;
+	tc.t_eofc = _POSIX_VDISABLE;
+	ltc.t_suspc = _POSIX_VDISABLE;
+	ltc.t_dsuspc = _POSIX_VDISABLE;
+#else
+	tmp_tc.c_lflag &= ~ISIG;
+#endif
+	localchars = 0;
+    } else {
+#ifdef	USE_TERMIO
+	tmp_tc.c_lflag |= ISIG;
+#endif
+	localchars = 1;
+    }
+
+    if (f&MODE_EDIT) {
+#ifndef	USE_TERMIO
+	sb.sg_flags &= ~CBREAK;
+	sb.sg_flags |= CRMOD;
+#else
+	tmp_tc.c_lflag |= ICANON;
+#endif
+    } else {
+#ifndef	USE_TERMIO
+	sb.sg_flags |= CBREAK;
+	if (f&MODE_ECHO)
+	    sb.sg_flags |= CRMOD;
+	else
+	    sb.sg_flags &= ~CRMOD;
+#else
+	tmp_tc.c_lflag &= ~ICANON;
+	tmp_tc.c_iflag &= ~ICRNL;
+	tmp_tc.c_cc[VMIN] = 1;
+	tmp_tc.c_cc[VTIME] = 0;
+#endif
+    }
+
+    if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
+#ifndef	USE_TERMIO
+	ltc.t_lnextc = _POSIX_VDISABLE;
+#else
+# ifdef VLNEXT
+	tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
+# endif
+#endif
+    }
+
+    if (f&MODE_SOFT_TAB) {
+#ifndef USE_TERMIO
+	sb.sg_flags |= XTABS;
+#else
+# ifdef	OXTABS
+	tmp_tc.c_oflag |= OXTABS;
+# endif
+# ifdef	TABDLY
+	tmp_tc.c_oflag &= ~TABDLY;
+	tmp_tc.c_oflag |= TAB3;
+# endif
+#endif
+    } else {
+#ifndef USE_TERMIO
+	sb.sg_flags &= ~XTABS;
+#else
+# ifdef	OXTABS
+	tmp_tc.c_oflag &= ~OXTABS;
+# endif
+# ifdef	TABDLY
+	tmp_tc.c_oflag &= ~TABDLY;
+# endif
+#endif
+    }
+
+    if (f&MODE_LIT_ECHO) {
+#ifndef USE_TERMIO
+	lmode &= ~LCTLECH;
+#else
+# ifdef	ECHOCTL
+	tmp_tc.c_lflag &= ~ECHOCTL;
+# endif
+#endif
+    } else {
+#ifndef USE_TERMIO
+	lmode |= LCTLECH;
+#else
+# ifdef	ECHOCTL
+	tmp_tc.c_lflag |= ECHOCTL;
+# endif
+#endif
+    }
+
+    if (f == -1) {
+	onoff = 0;
+    } else {
+#ifndef	USE_TERMIO
+	if (f & MODE_OUTBIN)
+		lmode |= LLITOUT;
+	else
+		lmode &= ~LLITOUT;
+
+	if (f & MODE_INBIN)
+		lmode |= LPASS8;
+	else
+		lmode &= ~LPASS8;
+#else
+	if (f & MODE_INBIN)
+		tmp_tc.c_iflag &= ~ISTRIP;
+	else
+		tmp_tc.c_iflag |= ISTRIP;
+	if (f & MODE_OUTBIN) {
+		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
+		tmp_tc.c_cflag |= CS8;
+		tmp_tc.c_oflag &= ~OPOST;
+	} else {
+		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
+		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
+		tmp_tc.c_oflag |= OPOST;
+	}
+#endif
+	onoff = 1;
+    }
+
+    if (f != -1) {
+
+#ifdef	SIGTSTP
+	(void) signal(SIGTSTP, susp);
+#endif	/* SIGTSTP */
+#ifdef	SIGINFO
+	(void) signal(SIGINFO, ayt);
+#endif
+#if	defined(USE_TERMIO) && defined(NOKERNINFO)
+	tmp_tc.c_lflag |= NOKERNINFO;
+#endif
+	/*
+	 * We don't want to process ^Y here.  It's just another
+	 * character that we'll pass on to the back end.  It has
+	 * to process it because it will be processed when the
+	 * user attempts to read it, not when we send it.
+	 */
+#ifndef	USE_TERMIO
+	ltc.t_dsuspc = _POSIX_VDISABLE;
+#else
+# ifdef	VDSUSP
+	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
+# endif
+#endif
+#ifdef	USE_TERMIO
+	/*
+	 * If the VEOL character is already set, then use VEOL2,
+	 * otherwise use VEOL.
+	 */
+	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
+	if ((tmp_tc.c_cc[VEOL] != esc)
+# ifdef	VEOL2
+	    && (tmp_tc.c_cc[VEOL2] != esc)
+# endif
+	    ) {
+		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
+		    tmp_tc.c_cc[VEOL] = esc;
+# ifdef	VEOL2
+		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
+		    tmp_tc.c_cc[VEOL2] = esc;
+# endif
+	}
+#else
+	if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
+		tc.t_brkc = esc;
+#endif
+    } else {
+#ifdef	SIGINFO
+	SIG_FUNC_RET ayt_status();
+
+	(void) signal(SIGINFO, ayt_status);
+#endif
+#ifdef	SIGTSTP
+	(void) signal(SIGTSTP, SIG_DFL);
+#ifdef POSIX_SIGNALS
+	{
+	  sigset_t tmask;
+	  sigemptyset(&tmask);
+	  sigaddset(&tmask, SIGTSTP);
+	  sigprocmask(SIG_UNBLOCK, &tmask, (sigset_t*)0);
+	}
+#else
+	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
+#endif
+#endif	/* SIGTSTP */
+#ifndef USE_TERMIO
+	ltc = oltc;
+	tc = otc;
+	sb = ottyb;
+	lmode = olmode;
+#else
+	tmp_tc = old_tc;
+#endif
+    }
+#ifndef USE_TERMIO
+    ioctl(tin, TIOCLSET, (char *)&lmode);
+    ioctl(tin, TIOCSLTC, (char *)<c);
+    ioctl(tin, TIOCSETC, (char *)&tc);
+    ioctl(tin, TIOCSETN, (char *)&sb);
+#else
+    if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
+	tcsetattr(tin, TCSANOW, &tmp_tc);
+#endif
+
+#if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
+# if	!defined(sysV88)
+    ioctl(tin, FIONBIO, (char *)&onoff);
+    ioctl(tout, FIONBIO, (char *)&onoff);
+# endif
+#endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
+#if	defined(TN3270)
+    if (noasynchtty == 0) {
+	ioctl(tin, FIOASYNC, (char *)&onoff);
+    }
+#endif	/* defined(TN3270) */
+
+}
+
+#ifndef	B19200
+# define B19200 B9600
+#endif
+
+#ifndef	B38400
+# define B38400 B19200
+#endif
+
+/*
+ * This code assumes that the values B0, B50, B75...
+ * are in ascending order.  They do not have to be
+ * contiguous.
+ */
+struct termspeeds {
+	long speed;
+	long value;
+} termspeeds[] = {
+	{ 0,     B0 },     { 50,    B50 },   { 75,    B75 },
+	{ 110,   B110 },   { 134,   B134 },  { 150,   B150 },
+	{ 200,   B200 },   { 300,   B300 },  { 600,   B600 },
+	{ 1200,  B1200 },  { 1800,  B1800 }, { 2400,  B2400 },
+	{ 4800,  B4800 },  { 9600,  B9600 }, { 19200, B19200 },
+	{ 38400, B38400 }, { -1,    B38400 }
+};
+
+    void
+TerminalSpeeds(ispeed, ospeed)
+    long *ispeed;
+    long *ospeed;
+{
+    register struct termspeeds *tp;
+    register long in, out;
+
+    out = cfgetospeed(&old_tc);
+    in = cfgetispeed(&old_tc);
+    if (in == 0)
+	in = out;
+
+    tp = termspeeds;
+    while ((tp->speed != -1) && (tp->value < in))
+	tp++;
+    *ispeed = tp->speed;
+
+    tp = termspeeds;
+    while ((tp->speed != -1) && (tp->value < out))
+	tp++;
+    *ospeed = tp->speed;
+}
+
+    int
+TerminalWindowSize(rows, cols)
+    long *rows, *cols;
+{
+#ifdef	TIOCGWINSZ
+    struct winsize ws;
+
+    if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
+	*rows = ws.ws_row;
+	*cols = ws.ws_col;
+	return 1;
+    }
+#endif	/* TIOCGWINSZ */
+    return 0;
+}
+
+    int
+NetClose(fd)
+    int	fd;
+{
+    return close(fd);
+}
+
+
+static void
+NetNonblockingIO(fd, onoff)
+    int fd;
+    int onoff;
+{
+    ioctl(fd, FIONBIO, (char *)&onoff);
+}
+
+#if	defined(TN3270)
+    void
+NetSigIO(fd, onoff)
+    int fd;
+    int onoff;
+{
+    ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
+}
+
+    void
+NetSetPgrp(fd)
+    int fd;
+{
+    int myPid;
+
+    myPid = getpid();
+    fcntl(fd, F_SETOWN, myPid);
+}
+#endif	/*defined(TN3270)*/
+
+/*
+ * Various signal handling routines.
+ */
+
+    /* ARGSUSED */
+static  SIG_FUNC_RET
+deadpeer(sig)
+    int sig;
+{
+	setcommandmode();
+	longjmp(peerdied, -1);
+}
+
+int intr_happened = 0;
+int intr_waiting = 0;
+
+    /* ARGSUSED */
+static SIG_FUNC_RET
+intr(sig)
+    int sig;
+{
+    if (intr_waiting) {
+	intr_happened = 1;
+	return;
+    }
+    if (localchars) {
+	intp();
+	return;
+    }
+    setcommandmode();
+    longjmp(toplevel, -1);
+}
+
+    /* ARGSUSED */
+static SIG_FUNC_RET
+intr2(sig)
+    int sig;
+{
+    if (localchars) {
+#ifdef	KLUDGELINEMODE
+	if (kludgelinemode)
+	    sendbrk();
+	else
+#endif
+	    sendabort();
+	return;
+    }
+}
+
+#ifdef	SIGTSTP
+    /* ARGSUSED */
+static SIG_FUNC_RET
+susp(sig)
+    int sig;
+{
+    if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
+	return;
+    if (localchars)
+	sendsusp();
+}
+#endif
+
+#ifdef	SIGWINCH
+    /* ARGSUSED */
+static  SIG_FUNC_RET
+sendwin(sig)
+    int sig;
+{
+    if (connected) {
+	sendnaws();
+    }
+}
+#endif
+
+#ifdef	SIGINFO
+    /* ARGSUSED */
+    SIG_FUNC_RET
+ayt(sig)
+    int sig;
+{
+    if (connected)
+	sendayt();
+    else
+	ayt_status();
+}
+#endif
+
+
+    void
+sys_telnet_init()
+{
+    (void) signal(SIGINT, intr);
+    (void) signal(SIGQUIT, intr2);
+    (void) signal(SIGPIPE, deadpeer);
+#ifdef	SIGWINCH
+    (void) signal(SIGWINCH, sendwin);
+#endif
+#ifdef	SIGTSTP
+    (void) signal(SIGTSTP, susp);
+#endif
+#ifdef	SIGINFO
+    (void) signal(SIGINFO, ayt);
+#endif
+
+    setconnmode(0);
+
+    NetNonblockingIO(net, 1);
+
+#if	defined(TN3270)
+    if (noasynchnet == 0) {			/* DBX can't handle! */
+	NetSigIO(net, 1);
+	NetSetPgrp(net);
+    }
+#endif	/* defined(TN3270) */
+
+#if	defined(SO_OOBINLINE)
+    if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
+	perror("SetSockOpt");
+    }
+#endif	/* defined(SO_OOBINLINE) */
+}
+
+/*
+ * Process rings -
+ *
+ *	This routine tries to fill up/empty our various rings.
+ *
+ *	The parameter specifies whether this is a poll operation,
+ *	or a block-until-something-happens operation.
+ *
+ *	The return value is 1 if something happened, 0 if not.
+ */
+
+    int
+process_rings(netin, netout, netex, ttyin, ttyout, poll)
+    int poll;		/* If 0, then block until something to do */
+{
+    register int c;
+		/* One wants to be a bit careful about setting returnValue
+		 * to one, since a one implies we did some useful work,
+		 * and therefore probably won't be called to block next
+		 * time (TN3270 mode only).
+		 */
+    int returnValue = 0;
+    static struct timeval TimeValue = { 0 };
+
+    if (netout) {
+	FD_SET(net, &obits);
+    } 
+    if (ttyout) {
+	FD_SET(tout, &obits);
+    }
+#if	defined(TN3270)
+    if (ttyin) {
+	FD_SET(tin, &ibits);
+    }
+#else	/* defined(TN3270) */
+    if (ttyin) {
+	FD_SET(tin, &ibits);
+    }
+#endif	/* defined(TN3270) */
+#if	defined(TN3270)
+    if (netin) {
+	FD_SET(net, &ibits);
+    }
+#   else /* !defined(TN3270) */
+    if (netin) {
+	FD_SET(net, &ibits);
+    }
+#   endif /* !defined(TN3270) */
+    if (netex) {
+	FD_SET(net, &xbits);
+    }
+    if ((c = select(16, &ibits, &obits, &xbits,
+			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
+	if (c == -1) {
+		    /*
+		     * we can get EINTR if we are in line mode,
+		     * and the user does an escape (TSTP), or
+		     * some other signal generator.
+		     */
+	    if (errno == EINTR) {
+		return 0;
+	    }
+#	    if defined(TN3270)
+		    /*
+		     * we can get EBADF if we were in transparent
+		     * mode, and the transcom process died.
+		    */
+	    if (errno == EBADF) {
+			/*
+			 * zero the bits (even though kernel does it)
+			 * to make sure we are selecting on the right
+			 * ones.
+			*/
+		FD_ZERO(&ibits);
+		FD_ZERO(&obits);
+		FD_ZERO(&xbits);
+		return 0;
+	    }
+#	    endif /* defined(TN3270) */
+		    /* I don't like this, does it ever happen? */
+	    printf("sleep(5) from telnet, after select\r\n");
+	    sleep(5);
+	}
+	return 0;
+    }
+
+    /*
+     * Any urgent data?
+     */
+    if (FD_ISSET(net, &xbits)) {
+	FD_CLR(net, &xbits);
+	SYNCHing = 1;
+	(void) ttyflush(1);	/* flush already enqueued data */
+    }
+
+    /*
+     * Something to read from the network...
+     */
+    if (FD_ISSET(net, &ibits)) {
+	int canread;
+
+	FD_CLR(net, &ibits);
+	canread = ring_empty_consecutive(&netiring);
+#if	!defined(SO_OOBINLINE)
+	    /*
+	     * In 4.2 (and some early 4.3) systems, the
+	     * OOB indication and data handling in the kernel
+	     * is such that if two separate TCP Urgent requests
+	     * come in, one byte of TCP data will be overlaid.
+	     * This is fatal for Telnet, but we try to live
+	     * with it.
+	     *
+	     * In addition, in 4.2 (and...), a special protocol
+	     * is needed to pick up the TCP Urgent data in
+	     * the correct sequence.
+	     *
+	     * What we do is:  if we think we are in urgent
+	     * mode, we look to see if we are "at the mark".
+	     * If we are, we do an OOB receive.  If we run
+	     * this twice, we will do the OOB receive twice,
+	     * but the second will fail, since the second
+	     * time we were "at the mark", but there wasn't
+	     * any data there (the kernel doesn't reset
+	     * "at the mark" until we do a normal read).
+	     * Once we've read the OOB data, we go ahead
+	     * and do normal reads.
+	     *
+	     * There is also another problem, which is that
+	     * since the OOB byte we read doesn't put us
+	     * out of OOB state, and since that byte is most
+	     * likely the TELNET DM (data mark), we would
+	     * stay in the TELNET SYNCH (SYNCHing) state.
+	     * So, clocks to the rescue.  If we've "just"
+	     * received a DM, then we test for the
+	     * presence of OOB data when the receive OOB
+	     * fails (and AFTER we did the normal mode read
+	     * to clear "at the mark").
+	     */
+	if (SYNCHing) {
+	    int atmark;
+	    static int bogus_oob = 0, first = 1;
+
+	    ioctl(net, SIOCATMARK, (char *)&atmark);
+	    if (atmark) {
+		c = recv(net, netiring.supply, canread, MSG_OOB);
+		if ((c == -1) && (errno == EINVAL)) {
+		    c = recv(net, netiring.supply, canread, 0);
+		    if (clocks.didnetreceive < clocks.gotDM) {
+			SYNCHing = stilloob(net);
+		    }
+		} else if (first && c > 0) {
+		    /*
+		     * Bogosity check.  Systems based on 4.2BSD
+		     * do not return an error if you do a second
+		     * recv(MSG_OOB).  So, we do one.  If it
+		     * succeeds and returns exactly the same
+		     * data, then assume that we are running
+		     * on a broken system and set the bogus_oob
+		     * flag.  (If the data was different, then
+		     * we probably got some valid new data, so
+		     * increment the count...)
+		     */
+		    int i;
+		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
+		    if (i == c &&
+			memcmp(netiring.supply, netiring.supply + c, i) == 0) {
+			bogus_oob = 1;
+			first = 0;
+		    } else if (i < 0) {
+			bogus_oob = 0;
+			first = 0;
+		    } else
+			c += i;
+		}
+		if (bogus_oob && c > 0) {
+		    int i;
+		    /*
+		     * Bogosity.  We have to do the read
+		     * to clear the atmark to get out of
+		     * an infinate loop.
+		     */
+		    i = read(net, netiring.supply + c, canread - c);
+		    if (i > 0)
+			c += i;
+		}
+	    } else {
+		c = recv(net, netiring.supply, canread, 0);
+	    }
+	} else {
+	    c = recv(net, netiring.supply, canread, 0);
+	}
+	settimer(didnetreceive);
+#else	/* !defined(SO_OOBINLINE) */
+	c = recv(net, (char *)netiring.supply, canread, 0);
+#endif	/* !defined(SO_OOBINLINE) */
+	if (c < 0 && errno == EWOULDBLOCK) {
+	    c = 0;
+	} else if (c <= 0) {
+	    return -1;
+	}
+	if (netdata) {
+	    Dump('<', netiring.supply, c);
+	}
+	if (c)
+	    ring_supplied(&netiring, c);
+	returnValue = 1;
+    }
+
+    /*
+     * Something to read from the tty...
+     */
+    if (FD_ISSET(tin, &ibits)) {
+	FD_CLR(tin, &ibits);
+	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
+	if (c < 0 && errno == EWOULDBLOCK) {
+	    c = 0;
+	} else {
+	    /* EOF detection for line mode!!!! */
+	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
+			/* must be an EOF... */
+		*ttyiring.supply = termEofChar;
+		c = 1;
+	    }
+	    if (c <= 0) {
+		return -1;
+	    }
+	    if (termdata) {
+		Dump('<', ttyiring.supply, c);
+	    }
+	    ring_supplied(&ttyiring, c);
+	}
+	returnValue = 1;		/* did something useful */
+    }
+
+    if (FD_ISSET(net, &obits)) {
+	FD_CLR(net, &obits);
+	returnValue |= netflush();
+    }
+    if (FD_ISSET(tout, &obits)) {
+	FD_CLR(tout, &obits);
+	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
+    }
+
+    return returnValue;
+}
diff --git a/mechglue/src/appl/telnet/telnet/telnet.0.ps b/mechglue/src/appl/telnet/telnet/telnet.0.ps
new file mode 100644
index 000000000..9edd0b321
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/telnet.0.ps
@@ -0,0 +1,1008 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Courier-Bold
+%%+ font Courier-Oblique
+%%+ font Courier
+%%+ font Symbol
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 10
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll 
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Courier-Bold
+%%IncludeResource: font Courier-Oblique
+%%IncludeResource: font Courier
+%%IncludeResource: font Symbol
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Courier@0 ENC0/Courier RE/Courier-Oblique@0 ENC0/Courier-Oblique RE
+/Courier-Bold@0 ENC0/Courier-Bold RE/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R/F1 10/Times-Bold@0 SF -.2(NA)72
+108 S(ME).2 E/F2 10/Courier-Bold@0 SF(telnet)102 120 Q F0 2.5<ad75>2.5 G
+(ser interf)153.64 120 Q(ace to the)-.1 E/F3 9/Times-Roman@0 SF(TELNET)2.5 E F0
+(protocol)2.5 E F1(SYNOPSIS)72 144 Q F2(telnet)102 156 Q F0([)3.333 E F2<ad38>
+2.499 E F0 3.333(][).833 G F2<ad45>-.834 E F0 3.333(][).833 G F2<ad46>-.834 E
+F0 3.333(][).833 G F2<ad4b>-.834 E F0 3.333(][).833 G F2<ad4c>-.834 E F0 3.333
+(][).833 G F2<ad53>-.834 E/F4 10/Courier-Oblique@0 SF(tos)6 E F0 3.333(][).833
+G F2<ad58>-.834 E F4(authtype)6 E F0 3.333(][).833 G F2<ad61>-.834 E F0 3.333
+(][).833 G F2<ad63>-.834 E F0 3.333(][).833 G F2<ad64>-.834 E F0 3.333(][).833
+G F2<ad65>-.834 E F4(escapechar)144 168 Q F0 3.333(][).833 G F2<ad66>-.834 E F0
+3.333(][).833 G F2<ad6b>-.834 E F4(realm)6 E F0 3.333(][).833 G F2<ad6c>-.834 E
+F4(user)6 E F0 3.333(][).833 G F2<ad6e>-.834 E F4(tracefile)6 E F0 3.333(][)
+.833 G F2<ad72>-.834 E F0 3.333(][).833 G F2<ad78>-.834 E F0 2.5(][).833 G F4
+(host)491.943 168 Q F0 .833([p)144.833 180 S -1.667(ort ]])-.833 F F1
+(DESCRIPTION)72 204 Q F0(The)102 216 Q F2(telnet)2.523 E F0 .023
+(command is used to communicate with another host using the)2.523 F F3(TELNET)
+2.523 E F0 2.523(protocol. If)2.523 F F2(telnet)2.523 E F0(is)2.522 E(in)102
+228 Q -.2(vo)-.4 G -.1(ke).2 G 2.693(dw).1 G .193(ithout the)143.433 228 R F4
+(host)2.693 E F0(ar)2.693 E .194
+(gument, it enters command mode, indicated by its prompt)-.18 F(\()4.36 E F2
+(telnet>)1.666 E F0 -3.138 1.666(\). I)1.666 H 2.694(nt)-1.666 G(his)528.33 228
+Q 1.07(mode, it accepts and e)102 240 R -.15(xe)-.15 G 1.07
+(cutes the commands listed belo).15 F 4.87 -.65(w. I)-.25 H 3.57(fi).65 G 3.57
+(ti)361.18 240 S 3.57(si)370.31 240 S -1.9 -.4(nv o)380.55 240 T -.1(ke).4 G
+3.57(dw).1 G 1.07(ith ar)420.08 240 R 1.07(guments, it performs an)-.18 F F2
+(open)102 252 Q F0(command with those ar)2.5 E(guments.)-.18 E(Options:)102 270
+Q F2<ad38>103.666 288 Q F0 .352(Speci\214es an 8-bit data path.)143 288 R .353
+(This causes an attempt to ne)5.352 F .353(gotiate the)-.15 F/F5 10/Courier@0
+SF .353(TELNET BINARY)2.853 F F0 .353(option on)2.853 F(both input and output.)
+143 300 Q F2<ad45>103.666 318 Q F0(Stops an)143 318 Q 2.5(yc)-.15 G
+(haracter from being recognized as an escape character)188.96 318 Q(.)-.55 E F2
+<ad46>103.666 336 Q F0 .691(If K)143 336 R .691
+(erberos V5 authentication is being used, the)-.25 F F2<ad46>4.856 E F0 .69
+(option allo)3.19 F .69(ws the local credentials to be for)-.25 F(-)-.2 E -.1
+(wa)143 348 S .615(rded to the remote system, including an).1 F 3.116(yc)-.15 G
+.616(redentials that ha)328.698 348 R .916 -.15(ve a)-.2 H .616
+(lready been forw).15 F .616(arded into the)-.1 F(local en)143 360 Q
+(vironment.)-.4 E F2<ad4b>103.666 378 Q F0
+(Speci\214es no automatic login to the remote system.)143 378 Q F2<ad4c>103.666
+396 Q F0 .147(Speci\214es an 8-bit data path on output.)143 396 R .146
+(This causes the BIN)5.146 F(AR)-.35 E 2.646(Yo)-.65 G .146(ption to be ne)
+409.42 396 R .146(gotiated on output.)-.15 F F2<ad53>103.666 414 Q F4(tos)6 E
+F0 .288(Sets the IP type-of-service \(T)143 426 R .288
+(OS\) option for the telnet connection to the v)-.18 F(alue)-.25 E F4(tos,)
+2.788 E F0 .289(which can be)2.788 F 3.12(an)143 438 S .62(umeric T)155.56 438
+R .62(OS v)-.18 F .62(alue or)-.25 F 3.12(,o)-.4 G 3.12(ns)251.36 438 S .619
+(ystems that support it, a symbolic T)263.37 438 R .619
+(OS name found in the /etc/iptos)-.18 F(\214le.)143 450 Q F2<ad58>103.666 468 Q
+F4(atype)6 E F0(Disables the)143 480 Q F4(atype)2.5 E F0
+(type of authentication.)2.5 E F2<ad61>103.666 498 Q F0 2.562
+(Attempt automatic login.)143 498 R(Currently)7.563 E 5.063(,t)-.65 G 2.563
+(his sends the user name via the)303.99 498 R F5(USER)5.063 E F0 -.25(va)5.063
+G 2.563(riable of the).25 F F5(ENVIRON)143 510 Q F0 .444
+(option if supported by the remote system.)2.945 F .444
+(The name used is that of the current user as)5.444 F .168(returned by)143 522
+R F5(getlogin)2.668 E F0 .168(\(2\) if it agrees with the current user ID, oth\
+erwise it is the name associated)B(with the user ID.)143 534 Q F2<ad63>103.666
+552 Q F0 .022(Disables the reading of the user')143 552 R(s)-.55 E F5
+(.telnetrc)2.522 E F0 2.522(\214le. \(See)2.522 F(the)2.522 E F2 .022
+(toggle skiprc)2.522 F F0 .022(command on this)2.522 F(man page.\))143 564 Q F2
+<ad64>103.666 582 Q F0(Sets the initial v)143 582 Q(alue of the)-.25 E F2
+(debug)2.5 E F0(toggle to)2.5 E F5(TRUE)2.5 E F2<ad65>103.666 600 Q F4
+(escape char)6 E F0 1.759(Sets the initial)143 612 R F2 -1.741(telnet telnet)
+4.259 F F0 1.759(escape character to)4.259 F F4 1.759(escape char.)4.259 F F0
+(If)4.259 E F4 1.76(escape char)4.26 F F0(is)4.26 E
+(omitted, then there will be no escape character)143 624 Q(.)-.55 E F2<ad66>
+103.666 642 Q F0 .691(If K)143 642 R .691
+(erberos V5 authentication is being used, the)-.25 F F2<ad66>4.856 E F0 .69
+(option allo)3.19 F .69(ws the local credentials to be for)-.25 F(-)-.2 E -.1
+(wa)143 654 S(rded to the remote system.).1 E F2<ad6b>103.666 672 Q F4(realm)6
+E F0 .008(If K)143 684 R .008(erberos authentication is being used, the)-.25 F
+F2<ad6b>4.174 E F0 .009(option requests that telnet obtain tick)2.508 F .009
+(ets for the re-)-.1 F 6.61
+(mote host in realm realm instead of the remote host')143 696 R 9.11(sr)-.55 G
+6.61(ealm, as determined by)427.41 696 R(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)
+-.15 G(istrib)132.57 750 Q 95.71(ution February)-.2 F(3, 1994)2.5 E(1)535 750 Q
+EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R/F1 10/Courier@0 SF
+(krb_realmofhost)143 96 Q F0(\(3\).)A/F2 10/Courier-Bold@0 SF<ad6c>103.666 114
+Q/F3 10/Courier-Oblique@0 SF(user)6 E F0 1.135
+(When connecting to the remote system, if the remote system understands the)143
+126 R F1(ENVIRON)3.636 E F0(option,)3.636 E(then)143 138 Q F3(user)2.974 E F0
+.474(will be sent to the remote system as the v)2.974 F .474(alue for the v)
+-.25 F .474(ariable USER.)-.25 F .473(This option im-)5.474 F(plies the)143 150
+Q F2<ad61>4.166 E F0 2.5(option. This)2.5 F(option may also be used with the)
+2.5 E F2(open)2.5 E F0(command.)2.5 E F2<ad6e>103.666 168 Q F3(tracefile)6 E F0
+(Opens)143 180 Q F3(tracefile)2.561 E F0 .062(for recording trace information.)
+2.561 F .062(See the)5.062 F F2 .062(set tracefile)2.562 F F0 .062
+(command belo)2.562 F -.65(w.)-.25 G F2<ad72>103.666 198 Q F0 .936
+(Speci\214es a user interf)143 198 R .936(ace similar to)-.1 F F1(rlogin)3.435
+E F0 4.37(\(1\). In)B .935(this mode, the escape character is set to the)3.435
+F(tilde \(~\) character)143 210 Q 2.5(,u)-.4 G
+(nless modi\214ed by the -e option.)222.01 210 Q F2<ad78>103.666 228 Q F0 -.45
+(Tu)143 228 S .123(rns on encryption of the data stream if possible.).45 F .124
+(This option is not a)5.124 F -.25(va)-.2 G .124(ilable outside of the Unit-)
+.25 F(ed States and Canada.)143 240 Q F3(host)102 258 Q F0(Indicates the of)143
+258 Q(\214cial name, an alias, or the Internet address of a remote host.)-.25 E
+F3(port)102 276 Q F0 1.96
+(Indicates a port number \(address of an application\).)143 276 R 1.96
+(If a number is not speci\214ed, the def)6.96 F(ault)-.1 E F2(telnet)143 288 Q
+F0(port is used.)2.5 E .237(When in rlogin mode, a line of the form ~.)102 306
+R .238(disconnects from the remote host; ~ is the telnet escape character)5.237
+F(.)-.55 E(Similarly)102 318 Q 2.5(,t)-.65 G
+(he line ~^Z suspends the telnet session.)146.36 318 Q
+(The line ~^] escapes to the normal telnet escape prompt.)5 E 1.008
+(Once a connection has been opened,)102 336 R F2(telnet)3.507 E F0 1.007
+(will attempt to enable the)3.507 F F1 1.007(TELNET LINEMODE)3.507 F F0 3.507
+(option. If)3.507 F .73(this f)102 348 R .73(ails, then)-.1 F F2(telnet)3.23 E
+F0 .73(will re)3.23 F -.15(ve)-.25 G .73(rt to one of tw).15 F 3.23(oi)-.1 G
+.731(nput modes: either `)308.3 348 R .731(`character at a time')-.74 F 3.231
+('o)-.74 G 3.231(r`)483.277 348 S .731(`old line by)492.428 348 R(line')102 360
+Q 2.5('d)-.74 G(epending on what the remote system supports.)130.42 360 Q(When)
+102 378 Q F1(LINEMODE)3.143 E F0 .642(is enabled, character processing is done\
+ on the local system, under the control of the re-)3.143 F .123(mote system.)
+102 390 R .123(When input editing or character echoing is to be disabled, the \
+remote system will relay that in-)5.123 F 3.397(formation. The)102 402 R .897
+(remote system will also relay changes to an)3.397 F 3.397(ys)-.15 G .897
+(pecial characters that happen on the remote)361.34 402 R(system, so that the)
+102 414 Q 2.5(yc)-.15 G(an tak)187.68 414 Q 2.5(ee)-.1 G -.25(ff)223.12 414 S
+(ect on the local system.).25 E(In `)102 432 Q(`character at a time')-.74 E 2.5
+('m)-.74 G(ode, most te)208.53 432 Q
+(xt typed is immediately sent to the remote host for processing.)-.15 E .323
+(In `)102 450 R .323(`old line by line')-.74 F 2.823('m)-.74 G .323
+(ode, all te)196.845 450 R .323(xt is echoed locally)-.15 F 2.823(,a)-.65 G
+.323(nd \(normally\) only completed lines are sent to the re-)324.073 450 R
+.757(mote host.)102 462 R .757(The `)5.757 F .757(`local echo character')-.74 F
+3.257('\()-.74 G .756(initially `)268.892 462 R(`^E')-.74 E .756
+('\) may be used to turn of)-.74 F 3.256(fa)-.25 G .756
+(nd on the local echo \(this)435.4 462 R -.1(wo)102 474 S
+(uld mostly be used to enter passw).1 E(ords without the passw)-.1 E
+(ord being echoed\).)-.1 E 1.076(If the)102 492 R F1(LINEMODE)3.576 E F0 1.076
+(option is enabled, or if the)3.576 F F2(localchars)3.577 E F0 1.077(toggle is)
+3.577 F F1(TRUE)3.577 E F0 1.077(\(the def)3.577 F 1.077(ault for `)-.1 F 1.077
+(`old line by)-.74 F(line`)102 504 Q .866(`; see belo)-.74 F .866
+(w\), the user')-.25 F(s)-.55 E F2(quit)3.366 E F0(,)A F2(intr)3.366 E F0 3.366
+(,a)C(nd)285.042 504 Q F2(flush)3.365 E F0 .865(characters are trapped locally)
+3.365 F 3.365(,a)-.65 G .865(nd sent as)461.472 504 R/F4 9/Times-Roman@0 SF
+(TELNET)3.365 E F0 .368(protocol sequences to the remote side.)102 516 R(If)
+5.368 E F1(LINEMODE)2.868 E F0 .368(has e)2.868 F -.15(ve)-.25 G 2.868(rb).15 G
+.368(een enabled, then the user')363.23 516 R(s)-.55 E F2(susp)2.869 E F0(and)
+2.869 E F2(eof)2.869 E F0 1.308(are also sent as)102 528 R F4(TELNET)3.808 E F0
+1.308(protocol sequences, and)3.808 F F2(quit)3.808 E F0 1.307(is sent as a)
+3.807 F F1 1.307(TELNET ABORT)3.807 F F0 1.307(instead of)3.807 F F1(BREAK)
+3.807 E F0 .474(There are options \(see)102 540 R F2 -3.026(toggle autoflush)
+2.974 F F0(and)2.974 E F2 -3.026(toggle autosynch)2.974 F F0(belo)2.974 E .475
+(w\) which cause this action to)-.25 F .194
+(\215ush subsequent output to the terminal \(until the remote host ackno)102
+552 R .194(wledges the)-.25 F F4(TELNET)2.694 E F0 .193(sequence\) and \215ush)
+2.693 F(pre)102 564 Q(vious terminal input \(in the case of)-.25 E F2(quit)2.5
+E F0(and)2.5 E F2(intr)2.5 E F0(\).)A .235(While connected to a remote host,)
+102 582 R F2(telnet)2.735 E F0 .235(command mode may be entered by typing the)
+2.735 F F2(telnet)2.735 E F0 -.74(``)2.735 G(escape).74 E(character')102 594 Q
+2.5('\()-.74 G(initially `)150.39 594 Q(`^]')-.74 E 2.5('\). When)-.74 F
+(in command mode, the normal terminal editing con)2.5 E -.15(ve)-.4 G
+(ntions are a).15 E -.25(va)-.2 G(ilable.).25 E .018(The follo)102 612 R(wing)
+-.25 E F2(telnet)2.518 E F0 .018(commands are a)2.518 F -.25(va)-.2 G 2.517
+(ilable. Only).25 F .017(enough of each command to uniquely identify it need)
+2.517 F 2.478(be typed \(this is also true for ar)102 624 R 2.478
+(guments to the)-.18 F F2(mode)4.978 E F0(,)A F2(set)4.978 E F0(,)A F2(toggle)
+4.978 E F0(,)A F2(unset)4.978 E F0(,)A F2(slc)4.978 E F0(,)A F2(environ)4.979 E
+F0 4.979(,a)C(nd)530 624 Q F2(display)102 636 Q F0(commands\).)2.5 E F2(auth)
+102 654 Q F3(argument ...)6 E F0 .308
+(The auth command manipulates the information sent through the)161 666 R F1
+.308(TELNET AUTHENTICATE)2.808 F F0 2.5(option. V)161 678 R(alid ar)-1.11 E
+(guments for the auth command are as follo)-.18 E(ws:)-.25 E(4.2 Berk)72 750 Q
+(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71(ution February)-.2 F
+(3, 1994)2.5 E(2)535 750 Q EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R/F1 10/Courier-Bold@0 SF(disable)
+161 96 Q/F2 10/Courier-Oblique@0 SF(type)6.76 E F0 .76
+(Disables the speci\214ed type of authentication.)5 F 2.36 -.8(To o)5.76 H .76
+(btain a list of a).8 F -.25(va)-.2 G(ilable).25 E(types, use the)238 108 Q F1
+(auth disable ?)2.5 E F0(command.)2.5 E F1(enable)161 126 Q F2(type)6.992 E F0
+.992(Enables the speci\214ed type of authentication.)238.992 126 R 2.592 -.8
+(To o)5.992 H .991(btain a list of a).8 F -.25(va)-.2 G(ilable).25 E
+(types, use the)238 138 Q F1(auth enable ?)2.5 E F0(command.)2.5 E F1(status)
+161 156 Q F0(Lists the current status of the v)238 156 Q
+(arious types of authentication.)-.25 E F1(close)102 174 Q F0(Close a)161 174 Q
+/F3 9/Times-Roman@0 SF(TELNET)2.5 E F0(session and return to command mode.)2.5
+E F1(display)102 192 Q F2(argument ...)6 E F0(Displays all, or some, of the)161
+204 Q F1(set)2.5 E F0(and)2.5 E F1(toggle)2.5 E F0 -.25(va)2.5 G
+(lues \(see belo).25 E(w\).)-.25 E F1(encrypt)102 222 Q F2(argument ...)6 E F0
+.407(The encrypt command manipulates the information sent through the)161 234 R
+/F4 10/Courier@0 SF .408(TELNET ENCRYPT)2.908 F F0(op-)2.908 E(tion.)161 246 Q
+2.856(Note: Because)161 264 R .356(of e)2.856 F .356(xport controls, the)-.15 F
+F4 .355(TELNET ENCRYPT)2.855 F F0 .355(option is not supported outside of)2.855
+F(the United States and Canada.)161 276 Q -1.11(Va)161 294 S(lid ar)1.11 E
+(guments for the encrypt command are as follo)-.18 E(ws:)-.25 E F1(disable)161
+312 Q F2(type)6 E F1([input|output])6 E F0 1.099
+(Disables the speci\214ed type of encryption.)226 324 R 1.099
+(If you omit the input and output,)6.099 F .357
+(both input and output are disabled.)226 336 R 1.957 -.8(To o)5.357 H .357
+(btain a list of a).8 F -.25(va)-.2 G .357(ilable types, use the).25 F F1
+(encrypt disable ?)226 348 Q F0(command.)2.5 E F1(enable)161 366 Q F2(type)6 E
+F1([input|output])6 E F0 .867(Enables the speci\214ed type of encryption.)226
+378 R .868(If you omit input and output, both)5.867 F 2.117
+(input and output are enabled.)226 390 R 3.716 -.8(To o)7.116 H 2.116
+(btain a list of a).8 F -.25(va)-.2 G 2.116(ilable types, use the).25 F F1
+(encrypt enable ?)226 402 Q F0(command.)2.5 E F1(input)161 420 Q F0
+(This is the same as the)226 420 Q F1(encrypt start input)2.5 E F0(command.)2.5
+E F1(-input)161 438 Q F0(This is the same as the)226 438 Q F1
+(encrypt stop input)2.5 E F0(command.)2.5 E F1(output)161 456 Q F0
+(This is the same as the)226 456 Q F1(encrypt start output)2.5 E F0(command.)
+2.5 E F1(-output)161 474 Q F0(This is the same as the)226 474 Q F1
+(encrypt stop output)2.5 E F0(command.)2.5 E F1(start [input|output])161 492 Q
+F0 1.116(Attempts to start encryption.)226 504 R 1.116(If you omit)6.116 F F1
+(input)3.616 E F0(and)3.617 E F1(output,)3.617 E F0 1.117(both input)3.617 F
+.467(and output are enabled.)226 516 R 2.067 -.8(To o)5.467 H .467
+(btain a list of a).8 F -.25(va)-.2 G .467(ilable types, use the).25 F F1
+(encrypt)2.966 E(enable ?)226 528 Q F0(command.)2.5 E F1(status)161 546 Q F0
+(Lists the current status of encryption.)226 546 Q F1(stop [input|output])161
+564 Q F0 1.096(Stops encryption.)226 576 R 1.097
+(If you omit input and output, encryption is on both input)6.096 F(and output.)
+226 588 Q F1(type)161 606 Q F2(type)6.121 E F0 .121(Sets the def)226.121 606 R
+.121(ault type of encryption to be used with later)-.1 F F1 .12(encrypt start)
+2.62 F F0(or)2.62 E F1(encrypt stop)226 618 Q F0(commands.)2.5 E F1(environ)102
+636 Q F2(arguments...)6 E F0(The)161 648 Q F1(environ)3.189 E F0 .689
+(command is used to manipulate the the v)3.189 F .69
+(ariables that my be sent through the)-.25 F F4 .552(TELNET ENVIRON)161 660 R
+F0 3.052(option. The)3.052 F .552(initial set of v)3.052 F .551
+(ariables is tak)-.25 F .551(en from the users en)-.1 F(vironment,)-.4 E .501
+(with only the)161 672 R F4(DISPLAY)3.001 E F0(and)3.001 E F4(PRINTER)3.001 E
+F0 -.25(va)3.001 G .502(riables being e).25 F .502(xported by def)-.15 F 3.002
+(ault. The)-.1 F F4(USER)3.002 E F0 -.25(va)3.002 G(ri-).25 E(able is also e)
+161 684 Q(xported if the)-.15 E F1<ad61>4.166 E F0(or)2.5 E F1<ad6c>4.166 E F0
+(options are used.)2.5 E(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)
+132.57 750 Q 95.71(ution February)-.2 F(3, 1994)2.5 E(3)535 750 Q EP
+%%Page: 4 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R -1.11(Va)161 96 S(lid ar)1.11 E
+(guments for the)-.18 E/F1 10/Courier-Bold@0 SF(environ)2.5 E F0(command are:)
+2.5 E F1(define)161 114 Q/F2 10/Courier-Oblique@0 SF(variable value)6 E F0
+1.082(De\214ne the v)216 126 R(ariable)-.25 E F2(variable)3.582 E F0 1.082
+(to ha)3.582 F 1.382 -.15(ve a v)-.2 H 1.082(alue of)-.1 F F2(value.)3.581 E F0
+(An)3.581 E 3.581(yv)-.15 G 1.081(ariables de-)492.549 126 R 1.922
+(\214ned by this command are automatically e)216 138 R 4.422(xported. The)-.15
+F F2(value)4.422 E F0 1.922(may be en-)4.422 F
+(closed in single or double quotes so that tabs and spaces may be included.)216
+150 Q F1(undefine)161 168 Q F2(variable)6 E F0(Remo)216 180 Q -.15(ve)-.15 G F2
+(variable)2.65 E F0(from the list of en)2.5 E(vironment v)-.4 E(ariables.)-.25
+E F1(export)161 198 Q F2(variable)6 E F0(Mark the v)216 210 Q(ariable)-.25 E F2
+(variable)2.5 E F0(to be e)2.5 E(xported to the remote side.)-.15 E F1
+(unexport)161 228 Q F2(variable)6 E F0 .697(Mark the v)216 240 R(ariable)-.25 E
+F2(variable)3.197 E F0 .697(to not be e)3.197 F .697(xported unless e)-.15 F
+.696(xplicitly ask)-.15 F .696(ed for by)-.1 F(the remote side.)216 252 Q F1
+(list)161 270 Q F0 1.416(List the current set of en)216 270 R 1.416
+(vironment v)-.4 F 3.916(ariables. Those)-.25 F(mark)3.916 E 1.416(ed with a)
+-.1 F/F3 10/Symbol SF(*)3.916 E F0 1.417(will be)3.917 F(sent automatically)216
+282 Q 2.5(,o)-.65 G(ther v)298.4 282 Q(ariables will only be sent if e)-.25 E
+(xplicitly requested.)-.15 E F1(?)161 300 Q F0
+(Prints out help information for the)216 300 Q F1(environ)2.5 E F0(command.)2.5
+E F1(logout)102 318 Q F0 .104(Sends the)161 318 R/F4 10/Courier@0 SF .104
+(TELNET LOGOUT)2.604 F F0 .104(option to the remote side.)2.604 F .104
+(This command is similar to a)5.104 F F1(close)2.604 E F0 .228(command; ho)161
+330 R(we)-.25 E -.15(ve)-.25 G 1.028 -.4(r, i).15 H 2.728(ft).4 G .228
+(he remote side does not support the)256.174 330 R F4(LOGOUT)2.729 E F0 .229
+(option, nothing happens.)2.729 F .233(If, ho)161 342 R(we)-.25 E -.15(ve)-.25
+G 1.033 -.4(r, t).15 H .233(he remote side does support the).4 F F4(LOGOUT)
+2.733 E F0 .233(option, this command should cause the)2.733 F .652
+(remote side to close the)161 354 R/F5 9/Times-Roman@0 SF(TELNET)3.152 E F0
+3.152(connection. If)3.152 F .653(the remote side also supports the concept of)
+3.152 F 1.904(suspending a user')161 366 R 4.404(ss)-.55 G 1.903
+(ession for later reattachment, the logout ar)250.872 366 R 1.903
+(gument indicates that you)-.18 F(should terminate the session immediately)161
+378 Q(.)-.65 E F1(mode)102 396 Q F2 -1(type Type)6.889 F F0 .889(is one of se)
+3.389 F -.15(ve)-.25 G .889(ral options, depending on the state of the).15 F F5
+(TELNET)3.389 E F0 3.39(session. The)3.39 F(remote)3.39 E .882(host is ask)161
+408 R .881(ed for permission to go into the requested mode.)-.1 F .881
+(If the remote host is capable of)5.881 F
+(entering that mode, the requested mode will be entered.)161 420 Q F1
+(character)161 438 Q F0 .715(Disable the)226 438 R F4 .716(TELNET LINEMODE)
+3.215 F F0 .716(option, or)3.216 F 3.216(,i)-.4 G 3.216(ft)416.834 438 S .716
+(he remote side does not un-)426.16 438 R(derstand the)226 450 Q F4(LINEMODE)
+2.5 E F0(option, then enter `)2.5 E(`character at a time`)-.74 E 2.5(`m)-.74 G
+(ode.)496.07 450 Q F1(line)161 468 Q F0 .948(Enable the)226 468 R F4 .948
+(TELNET LINEMODE)3.448 F F0 .948(option, or)3.448 F 3.448(,i)-.4 G 3.447(ft)
+415.448 468 S .947(he remote side does not un-)425.005 468 R 2.78(derstand the)
+226 480 R F4(LINEMODE)5.28 E F0 2.78(option, then attempt to enter `)5.28 F
+(`old-line-by-line`)-.74 E(`)-.74 E(mode.)226 492 Q F1(isig)161 510 Q F0(\()
+7.666 E F1(\255isig)1.666 E F0(\))1.666 E 1.43
+(Attempt to enable \(disable\) the)226 522 R F4(TRAPSIG)3.93 E F0 1.43
+(mode of the)3.93 F F4(LINEMODE)3.93 E F0(option.)3.93 E
+(This requires that the)226 534 Q F4(LINEMODE)2.5 E F0(option be enabled.)2.5 E
+F1(edit)161 552 Q F0(\()7.666 E F1(\255edit)1.666 E F0(\))1.666 E .865
+(Attempt to enable \(disable\) the)226 564 R F4(EDIT)3.365 E F0 .866
+(mode of the)3.365 F F4(LINEMODE)3.366 E F0 3.366(option. This)3.366 F
+(requires that the)226 576 Q F4(LINEMODE)2.5 E F0(option be enabled.)2.5 E F1
+(softtabs)161 594 Q F0(\()7.666 E F1(\255softtabs)1.666 E F0(\))1.666 E .83
+(Attempt to enable \(disable\) the)226 606 R F4(SOFT_TAB)3.33 E F0 .83
+(mode of the)3.33 F F4(LINEMODE)3.33 E F0(option.)3.33 E
+(This requires that the)226 618 Q F4(LINEMODE)2.5 E F0(option be enabled.)2.5 E
+F1(litecho)161 636 Q F0(\()7.666 E F1(\255litecho)1.666 E F0(\))1.666 E .83
+(Attempt to enable \(disable\) the)226 648 R F4(LIT_ECHO)3.33 E F0 .83
+(mode of the)3.33 F F4(LINEMODE)3.33 E F0(option.)3.33 E
+(This requires that the)226 660 Q F4(LINEMODE)2.5 E F0(option be enabled.)2.5 E
+F1(?)161 678 Q F0(Prints out help information for the)226 678 Q F1(mode)2.5 E
+F0(command.)2.5 E(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q
+95.71(ution February)-.2 F(3, 1994)2.5 E(4)535 750 Q EP
+%%Page: 5 5
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R/F1 10/Courier-Bold@0 SF(open)102
+102 Q/F2 10/Courier-Oblique@0 SF(host)6 E F0 .833([[)2.5 G F1<ad6c>1.666 E F0
+(]).833 E F2(user)6 E F0(][)A F1<ad>1.666 E F2(port)A F0(])A .207
+(Open a connection to the named host.)161 114 R .207
+(If no port number is speci\214ed,)5.207 F F1(telnet)2.707 E F0 .206
+(will attempt to)2.707 F .263(contact a)161 126 R/F3 9/Times-Roman@0 SF(TELNET)
+2.763 E F0(serv)2.763 E .263(er at the def)-.15 F .263(ault port.)-.1 F .264
+(The host speci\214cation may be either a host name)5.264 F(\(see)161 138 Q/F4
+10/Courier@0 SF(hosts)3.531 E F0 4.562(\(5\)\) or)B 1.031
+(an Internet address speci\214ed in the `)3.531 F 1.03(`dot notation')-.74 F
+3.53('\()-.74 G(see)459.6 138 Q F4(inet)3.53 E F0 4.56(\(3\)\). The)B([)161.833
+150 Q F1<ad6c>2.499 E F0 3.03(]o).833 G .531(ption may be used to specify the \
+user name to be passed to the remote system via the)191.855 150 R F4(ENVIRON)
+161 162 Q F0 3.971(option. When)3.971 F 1.471
+(connecting to a non-standard port,)3.971 F F1(telnet)3.971 E F0 1.471
+(omits an)3.971 F 3.97(ya)-.15 G(utomatic)505 162 Q .631(initiation of)161 174
+R F3(TELNET)3.131 E F0 3.131(options. When)3.131 F .631
+(the port number is preceded by a minus sign, the initial)3.131 F .441
+(option ne)161 186 R .441(gotiation is done.)-.15 F .441
+(After establishing a connection, the \214le)5.441 F F4(.telnetrc)2.941 E F0
+.44(in the users)2.94 F .928(home directory is opened.)161 198 R .928(Lines be)
+5.928 F .928(ginning with a # are comment lines.)-.15 F .928
+(Blank lines are ig-)5.928 F 3.255(nored. Lines)161 210 R .755(that be)3.255 F
+.755(gin without white space are the start of a machine entry)-.15 F 5.755(.T)
+-.65 G .755(he \214rst thing)487.93 210 R .022
+(on the line is the name of the machine that is being connected to.)161 222 R
+.023(The rest of the line, and suc-)5.023 F(cessi)161 234 Q .856 -.15(ve l)-.25
+H .556(ines that be).15 F .556(gin with white space are assumed to be)-.15 F F1
+(telnet)3.056 E F0 .556(commands and are pro-)3.056 F(cessed as if the)161 246
+Q 2.5(yh)-.15 G(ad been typed in manually to the)233.61 246 Q F1(telnet)2.5 E
+F0(command prompt.)2.5 E F1(quit)102 264 Q F0 .114(Close an)161 264 R 2.614(yo)
+-.15 G(pen)208.298 264 Q F3(TELNET)2.614 E F0 .115(session and e)2.615 F(xit)
+-.15 E F1(telnet)2.615 E F0 2.615(.A)C 2.615(ne)376.32 264 S .115
+(nd of \214le \(in command mode\) will al-)388.375 264 R
+(so close a session and e)161 276 Q(xit.)-.15 E F1(send)102 294 Q F2(arguments)
+6 E F0 .024(Sends one or more special character sequences to the remote host.)
+161 306 R .024(The follo)5.024 F .024(wing are the ar)-.25 F(gu-)-.18 E
+(ments which may be speci\214ed \(more than one ar)161 318 Q
+(gument may be speci\214ed at a time\):)-.18 E F1(abort)161 336 Q F0(Sends the)
+202 336 Q F4(TELNET ABORT)2.5 E F0(\(Abort processes\) sequence.)2.5 E F1(ao)
+161 354 Q F0 1.15(Sends the)202 354 R F4 1.151(TELNET AO)3.651 F F0 1.151
+(\(Abort Output\) sequence, which should cause the remote)3.651 F
+(system to \215ush all output)202 366 Q/F5 10/Times-Italic@0 SF(fr)2.5 E(om)
+-.45 E F0(the remote system)2.5 E F5(to)2.5 E F0(the user')2.5 E 2.5(st)-.55 G
+(erminal.)454.89 366 Q F1(ayt)161 384 Q F0 1.18(Sends the)202 384 R F4 1.18
+(TELNET AYT)3.68 F F0 1.18(\(Are Y)3.68 F 1.18
+(ou There\) sequence, to which the remote system)-1.1 F
+(may or may not choose to respond.)202 396 Q F1(brk)161 414 Q F0 .47(Sends the)
+202 414 R F4 .47(TELNET BRK)2.97 F F0 .47(\(Break\) sequence, which may ha)2.97
+F .77 -.15(ve s)-.2 H .47(igni\214cance to the re-).15 F(mote system.)202 426 Q
+F1(ec)161 444 Q F0 .245(Sends the)202 444 R F4 .245(TELNET EC)2.745 F F0 .244
+(\(Erase Character\) sequence, which should cause the remote)2.745 F
+(system to erase the last character entered.)202 456 Q F1(el)161 474 Q F0 .385
+(Sends the)202 474 R F4 .385(TELNET EL)2.885 F F0 .385
+(\(Erase Line\) sequence, which should cause the remote sys-)2.885 F
+(tem to erase the line currently being entered.)202 486 Q F1(eof)161 504 Q F0
+(Sends the)202 504 Q F4(TELNET EOF)2.5 E F0(\(End Of File\) sequence.)2.5 E F1
+(eor)161 522 Q F0(Sends the)202 522 Q F4(TELNET EOR)2.5 E F0
+(\(End of Record\) sequence.)2.5 E F1(escape)161 540 Q F0(Sends the current)5 E
+F1(telnet)2.5 E F0(escape character \(initially `)2.5 E(`^')-.74 E('\).)-.74 E
+F1(ga)161 558 Q F0 .855(Sends the)202 558 R F4 .855(TELNET GA)3.355 F F0 .855
+(\(Go Ahead\) sequence, which lik)3.355 F .855(ely has no signi\214cance to)-.1
+F(the remote system.)202 570 Q F1(getstatus)161 588 Q F0 1.713
+(If the remote side supports the)202 600 R F4 1.713(TELNET STATUS)4.213 F F0
+(command,)4.213 E F1(getstatus)4.213 E F0(will)4.213 E(send the subne)202 612 Q
+(gotiation to request that the serv)-.15 E(er send its current option status.)
+-.15 E F1(ip)161 630 Q F0 1.355(Sends the)202 630 R F4 1.355(TELNET IP)3.855 F
+F0 1.354(\(Interrupt Process\) sequence, which should cause the re-)3.855 F
+(mote system to abort the currently running process.)202 642 Q F1(nop)161 660 Q
+F0(Sends the)202 660 Q F4(TELNET NOP)2.5 E F0(\(No OPeration\) sequence.)2.5 E
+F1(susp)161 678 Q F0(Sends the)202 678 Q F4(TELNET SUSP)2.5 E F0
+(\(SUSPend process\) sequence.)2.5 E(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G
+(istrib)132.57 750 Q 95.71(ution February)-.2 F(3, 1994)2.5 E(5)535 750 Q EP
+%%Page: 6 6
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R/F1 10/Courier-Bold@0 SF(synch)
+161 96 Q F0 .65(Sends the)202 96 R/F2 10/Courier@0 SF .651(TELNET SYNCH)3.151 F
+F0 3.151(sequence. This)3.151 F .651(sequence causes the remote system to)3.151
+F .777(discard all pre)202 108 R .777(viously typed \(b)-.25 F .777
+(ut not yet read\) input.)-.2 F .776(This sequence is sent as)5.777 F/F3 9
+/Times-Roman@0 SF(TCP)3.276 E F0(ur)202 120 Q 1.665(gent data \(and may not w)
+-.18 F 1.665(ork if the remote system is a 4.2)-.1 F F3(BSD)A F0 1.666
+(system -- if it)4.166 F(doesn')202 132 Q 2.5(tw)-.18 G(ork, a lo)240.88 132 Q
+(wer case `)-.25 E(`r')-.74 E 2.5('m)-.74 G(ay be echoed on the terminal\).)
+336.33 132 Q F1(do)161 150 Q/F4 10/Courier-Oblique@0 SF(cmd)6 E F1(dont)161 168
+Q F4(cmd)6 E F1(will)161 186 Q F4(cmd)6 E F1(wont)161 204 Q F4(cmd)6 E F0 1.134
+(Sends the)202 216 R F2 1.133(TELNET DO)3.633 F F4(cmd)3.633 E F0(sequence.)
+3.633 E F4(Cmd)6.133 E F0 1.133(can be either a decimal number be-)3.633 F .865
+(tween 0 and 255, or a symbolic name for a speci\214c)202 228 R F2(TELNET)3.365
+E F0(command.)3.365 E F4(Cmd)5.865 E F0(can)3.365 E 1.181(also be either)202
+240 R F1(help)3.681 E F0(or)3.681 E F1(?)3.681 E F0 1.18
+(to print out help information, including a list of kno)3.681 F(wn)-.25 E
+(symbolic names.)202 252 Q F1(?)161 270 Q F0
+(Prints out help information for the)202 270 Q F1(send)2.5 E F0(command.)2.5 E
+F1(set)102 288 Q F4(argument value)6 E F1(unset)102 306 Q F4(argument value)6 E
+F0(The)161 318 Q F1(set)2.601 E F0 .101(command will set an)2.601 F 2.601(yo)
+-.15 G .101(ne of a number of)295.556 318 R F1(telnet)2.601 E F0 -.25(va)2.601
+G .101(riables to a speci\214c v).25 F .102(alue or to)-.25 F F2(TRUE)161 330 Q
+F0 2.722(.T)C .222(he special v)196.332 330 R(alue)-.25 E F1(off)2.722 E F0
+.222(turns of)2.722 F 2.722(ft)-.25 G .222(he function associated with the v)
+323.474 330 R .222(ariable, this is equi)-.25 F(v-)-.25 E .37
+(alent to using the)161 342 R F1(unset)2.87 E F0 2.871(command. The)2.87 F F1
+(unset)2.871 E F0 .371(command will disable or set to)2.871 F F2(FALSE)2.871 E
+F0(an)2.871 E(y)-.15 E 1.248(of the speci\214ed functions.)161 354 R 1.248
+(The v)6.248 F 1.248(alues of v)-.25 F 1.248(ariables may be interrog)-.25 F
+1.247(ated with the)-.05 F F1(display)3.747 E F0 2.886(command. The)161 366 R
+-.25(va)2.886 G .386(riables which may be set or unset, b).25 F .386
+(ut not toggled, are listed here.)-.2 F .387(In addi-)5.387 F .763(tion, an)161
+378 R 3.263(yo)-.15 G 3.263(ft)204.876 378 S .763(he v)214.249 378 R .763
+(ariables for the)-.25 F F1(toggle)3.263 E F0 .762(command may be e)3.263 F
+.762(xplicitly set or unset using the)-.15 F F1(set)161 390 Q F0(and)2.5 E F1
+(unset)2.5 E F0(commands.)2.5 E F1(ayt)161 408 Q F0(If)202 408 Q F3(TELNET)
+2.689 E F0 .189(is in localchars mode, or)2.689 F F2(LINEMODE)2.689 E F0 .189
+(is enabled, and the status character)2.689 F 1.056(is typed, a)202 420 R F2
+1.056(TELNET AYT)3.556 F F0 1.056(sequence \(see)3.556 F F1 1.056(send ayt)
+3.556 F F0 1.055(preceding\) is sent to the re-)3.556 F .327(mote host.)202 432
+R .328(The initial v)5.327 F .328(alue for the "Are Y)-.25 F .328
+(ou There" character is the terminal')-1.1 F 2.828(ss)-.55 G(ta-)529.45 432 Q
+(tus character)202 444 Q(.)-.55 E F1(echo)161 462 Q F0 .805(This is the v)202
+462 R .805(alue \(initially `)-.25 F(`^E')-.74 E .804('\) which, when in `)-.74
+F .804(`line by line')-.74 F 3.304('m)-.74 G .804(ode, toggles be-)474.792 462
+R .988(tween doing local echoing of entered characters \(for normal processing\
+\), and sup-)202 474 R
+(pressing echoing of entered characters \(for entering, say)202 486 Q 2.5(,ap)
+-.65 G(assw)442.66 486 Q(ord\).)-.1 E F1(eof)161 504 Q F0(If)202 504 Q F1
+(telnet)3.864 E F0 1.364(is operating in)3.864 F F2(LINEMODE)3.864 E F0 1.364
+(or `)3.864 F 1.364(`old line by line')-.74 F 3.864('m)-.74 G 1.363
+(ode, entering this)468.114 504 R .199(character as the \214rst character on a\
+ line will cause this character to be sent to the re-)202 516 R .12
+(mote system.)202 528 R .12(The initial v)5.12 F .119
+(alue of the eof character is tak)-.25 F .119(en to be the terminal')-.1 F(s)
+-.55 E F1(eof)2.619 E F0(character)202 540 Q(.)-.55 E F1(erase)161 558 Q F0(If)
+202 558 Q F1(telnet)3.12 E F0 .62(is in)3.12 F F1(localchars)3.12 E F0 .62
+(mode \(see)3.12 F F1 -2.88(toggle localchars)3.12 F F0(belo)3.12 E(w\),)-.25 E
+/F5 10/Times-Bold@0 SF(and)3.12 E F0(if)3.12 E F1(telnet)202 570 Q F0 1.385
+(is operating in `)3.885 F 1.385(`character at a time')-.74 F 3.885('m)-.74 G
+1.384(ode, then when this character is)407 570 R .417(typed, a)202 582 R F2
+.418(TELNET EC)2.917 F F0 .418(sequence \(see)2.918 F F1 -3.082(send ec)2.918 F
+F0(abo)2.918 E -.15(ve)-.15 G 2.918(\)i).15 G 2.918(ss)427.36 582 S .418
+(ent to the remote system.)438.058 582 R .325(The initial v)202 594 R .325
+(alue for the erase character is tak)-.25 F .325(en to be the terminal')-.1 F
+(s)-.55 E F1(erase)2.825 E F0(charac-)2.825 E(ter)202 606 Q(.)-.55 E F1(escape)
+161 624 Q F0 2.873(This is the)5 F F1(telnet)5.373 E F0 2.874
+(escape character \(initially `)5.373 F(`^[')-.74 E 2.874
+('\) which causes entry into)-.74 F F1(telnet)202 636 Q F0
+(command mode \(when connected to a remote system\).)2.5 E F1(flushoutput)161
+654 Q F0(If)202 666 Q F1(telnet)2.945 E F0 .445(is in)2.945 F F1(localchars)
+2.945 E F0 .445(mode \(see)2.945 F F1 -3.056(toggle localchars)2.944 F F0(belo)
+2.944 E .444(w\) and the)-.25 F F1(flushoutput)202 678 Q F0 .442
+(character is typed, a)2.942 F F2 .443(TELNET AO)2.943 F F0 .443
+(sequence \(see)2.943 F F1 -3.057(send ao)2.943 F F0(abo)2.943 E -.15(ve)-.15 G
+(\)).15 E .314(is sent to the remote host.)202 690 R .314(The initial v)5.314 F
+.314(alue for the \215ush character is tak)-.25 F .314(en to be the)-.1 F
+(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71
+(ution February)-.2 F(3, 1994)2.5 E(6)535 750 Q EP
+%%Page: 7 7
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R(terminal')202 96 Q(s)-.55 E/F1
+10/Courier-Bold@0 SF(flush)2.5 E F0(character)2.5 E(.)-.55 E F1(forw1)161 114 Q
+(forw2)161 132 Q F0(If)202 132 Q/F2 9/Times-Roman@0 SF(TELNET)3.769 E F0 1.269
+(is operating in)3.769 F/F3 10/Courier@0 SF(LINEMODE)3.77 E F0 3.77(,t)C 1.27
+(hese are the characters that, when typed,)370.77 132 R .958
+(cause partial lines to be forw)202 144 R .958(arded to the remote system.)-.1
+F .958(The initial v)5.958 F .957(alue for the)-.25 F(forw)202 156 Q
+(arding characters are tak)-.1 E(en from the terminal')-.1 E 2.5(se)-.55 G
+(ol and eol2 characters.)414.23 156 Q F1(interrupt)161 174 Q F0(If)202 186 Q F1
+(telnet)2.944 E F0 .444(is in)2.944 F F1(localchars)2.944 E F0 .445(mode \(see)
+2.944 F F1 -3.055(toggle localchars)2.945 F F0(belo)2.945 E .445(w\) and the)
+-.25 F F1(interrupt)202 198 Q F0 .642(character is typed, a)3.142 F F3 .642
+(TELNET IP)3.142 F F0 .642(sequence \(see)3.142 F F1 -2.859(send ip)3.141 F F0
+(abo)3.141 E -.15(ve)-.15 G 3.141(\)i).15 G(s)536.11 198 Q .949
+(sent to the remote host.)202 210 R .949(The initial v)5.949 F .949
+(alue for the interrupt character is tak)-.25 F .95(en to be)-.1 F
+(the terminal')202 222 Q(s)-.55 E F1(intr)2.5 E F0(character)2.5 E(.)-.55 E F1
+(kill)161 240 Q F0(If)202 240 Q F1(telnet)2.95 E F0 .449(is in)2.949 F F1
+(localchars)2.949 E F0 .449(mode \(see)2.949 F F1 -3.051(toggle localchars)
+2.949 F F0(belo)2.949 E(w\),)-.25 E F1(and)2.949 E F0(if)2.949 E F1(telnet)202
+252 Q F0 1.384(is operating in `)3.884 F 1.385(`character at a time')-.74 F
+3.885('m)-.74 G 1.385(ode, then when this character is)406.995 252 R .418
+(typed, a)202 264 R F3 .418(TELNET EL)2.918 F F0 .418(sequence \(see)2.918 F F1
+-3.082(send el)2.918 F F0(abo)2.918 E -.15(ve)-.15 G 2.918(\)i).15 G 2.918(ss)
+427.362 264 S .418(ent to the remote system.)438.06 264 R(The initial v)202 276
+Q(alue for the kill character is tak)-.25 E(en to be the terminal')-.1 E(s)-.55
+E F1(kill)2.5 E F0(character)2.5 E(.)-.55 E F1(lnext)161 294 Q F0(If)202 294 Q
+F1(telnet)2.597 E F0 .097(is operating in)2.597 F F3(LINEMODE)2.597 E F0 .097
+(or `)2.597 F .097(`old line by line`)-.74 F 2.597(`m)-.74 G .098
+(ode, then this charac-)454.177 294 R 1.405(ter is tak)202 306 R 1.405
+(en to be the terminal')-.1 F(s)-.55 E F1(lnext)3.904 E F0(character)3.904 E
+6.404(.T)-.55 G 1.404(he initial v)422.56 306 R 1.404(alue for the lne)-.25 F
+(xt)-.15 E(character is tak)202 318 Q(en to be the terminal')-.1 E(s)-.55 E F1
+(lnext)2.5 E F0(character)2.5 E(.)-.55 E F1(quit)161 336 Q F0(If)202 336 Q F1
+(telnet)2.944 E F0 .444(is in)2.944 F F1(localchars)2.944 E F0 .445(mode \(see)
+2.944 F F1 -3.055(toggle localchars)2.945 F F0(belo)2.945 E .445(w\) and the)
+-.25 F F1(quit)202 348 Q F0 .546(character is typed, a)3.046 F F3 .545
+(TELNET BRK)3.046 F F0 .545(sequence \(see)3.045 F F1 -2.955(send brk)3.045 F
+F0(abo)3.045 E -.15(ve)-.15 G 3.045(\)i).15 G 3.045(ss)516.955 348 S(ent)527.78
+348 Q .629(to the remote host.)202 360 R .629(The initial v)5.629 F .629
+(alue for the quit character is tak)-.25 F .63(en to be the termi-)-.1 F(nal')
+202 372 Q(s)-.55 E F1(quit)2.5 E F0(character)2.5 E(.)-.55 E F1(reprint)161 390
+Q F0(If)202 402 Q F1(telnet)2.598 E F0 .097(is operating in)2.598 F F3
+(LINEMODE)2.597 E F0 .097(or `)2.597 F .097(`old line by line`)-.74 F 2.597(`m)
+-.74 G .097(ode, then this charac-)454.179 402 R .06(ter is tak)202 414 R .06
+(en to be the terminal')-.1 F(s)-.55 E F1(reprint)2.561 E F0(character)2.561 E
+5.061(.T)-.55 G .061(he initial v)422.465 414 R .061(alue for the reprint)-.25
+F(character is tak)202 426 Q(en to be the terminal')-.1 E(s)-.55 E F1(reprint)
+2.5 E F0(character)2.5 E(.)-.55 E F1(rlogin)161 444 Q F0 .956
+(This is the rlogin escape character)5 F 5.956(.I)-.55 G 3.456(fs)354.366 444 S
+.956(et, the normal)365.042 444 R F2(TELNET)3.456 E F0 .956
+(escape character is)3.456 F .357
+(ignored unless it is preceded by this character at the be)202 456 R .358
+(ginning of a line.)-.15 F .358(This char)5.358 F(-)-.2 E(acter)202 468 Q 3.14
+(,a)-.4 G 3.14(tt)231.11 468 S .64(he be)239.81 468 R .64
+(ginning of a line follo)-.15 F .639(wed by a ".")-.25 F .639
+(closes the connection; when fol-)5.639 F(lo)202 480 Q 1.31
+(wed by a ^Z it suspends the telnet command.)-.25 F 1.311
+(The initial state is to disable the)6.311 F(rlogin escape character)202 492 Q
+(.)-.55 E F1(start)161 510 Q F0 2.232(If the)202 510 R F3 2.231
+(TELNET TOGGLE-FLOW-CONTROL)4.731 F F0 2.231
+(option has been enabled, then this)4.731 F .005(character is tak)202 522 R
+.005(en to be the terminal')-.1 F(s)-.55 E F1(start)2.506 E F0(character)2.506
+E 5.006(.T)-.55 G .006(he initial v)436.06 522 R .006(alue for the kill)-.25 F
+(character is tak)202 534 Q(en to be the terminal')-.1 E(s)-.55 E F1(start)2.5
+E F0(character)2.5 E(.)-.55 E F1(stop)161 552 Q F0 2.232(If the)202 552 R F3
+2.231(TELNET TOGGLE-FLOW-CONTROL)4.731 F F0 2.231
+(option has been enabled, then this)4.731 F .434(character is tak)202 564 R
+.434(en to be the terminal')-.1 F(s)-.55 E F1(stop)2.934 E F0(character)2.934 E
+5.434(.T)-.55 G .434(he initial v)433.916 564 R .435(alue for the kill)-.25 F
+(character is tak)202 576 Q(en to be the terminal')-.1 E(s)-.55 E F1(stop)2.5 E
+F0(character)2.5 E(.)-.55 E F1(susp)161 594 Q F0(If)202 594 Q F1(telnet)2.576 E
+F0 .076(is in)2.576 F F1(localchars)2.576 E F0 .076(mode, or)2.576 F F3
+(LINEMODE)2.576 E F0 .076(is enabled, and the)2.576 F F1(suspend)2.575 E F0 .87
+(character is typed, a)202 606 R F3 .87(TELNET SUSP)3.37 F F0 .87
+(sequence \(see)3.37 F F1 -2.63(send susp)3.37 F F0(abo)3.37 E -.15(ve)-.15 G
+3.37(\)i).15 G 3.37(ss)505.48 606 S .87(ent to)516.63 606 R .246
+(the remote host.)202 618 R .246(The initial v)5.246 F .246
+(alue for the suspend character is tak)-.25 F .246(en to be the termi-)-.1 F
+(nal')202 630 Q(s)-.55 E F1(suspend)2.5 E F0(character)2.5 E(.)-.55 E F1
+(tracefile)161 648 Q F0 .537(This is the \214le to which the output, caused by)
+202 660 R F1(netdata)3.037 E F0(or)3.037 E F1(option)3.037 E F0 .538
+(tracing being)3.038 F F3(TRUE)202 672 Q F0 3.079(,w)C .579(ill be written.)
+238.799 672 R .579(If it is set to `)5.579 F(`)-.74 E F1<ad>1.666 E F0 -.74('')
+1.666 G 3.078(,t).74 G .578(hen tracing information will be written)381.85 672
+R(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71
+(ution February)-.2 F(3, 1994)2.5 E(7)535 750 Q EP
+%%Page: 8 8
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R(to standard output \(the def)202
+96 Q(ault\).)-.1 E/F1 10/Courier-Bold@0 SF(worderase)161 114 Q F0(If)202 126 Q
+F1(telnet)2.597 E F0 .097(is operating in)2.597 F/F2 10/Courier@0 SF(LINEMODE)
+2.597 E F0 .097(or `)2.597 F .097(`old line by line`)-.74 F 2.597(`m)-.74 G
+.098(ode, then this charac-)454.177 126 R 1.386(ter is tak)202 138 R 1.386
+(en to be the terminal')-.1 F(s)-.55 E F1(worderase)3.885 E F0(character)3.885
+E 6.385(.T)-.55 G 1.385(he initial v)446.39 138 R 1.385(alue for the)-.25 F -.1
+(wo)202 150 S(rderase character is tak).1 E(en to be the terminal')-.1 E(s)-.55
+E F1(worderase)2.5 E F0(character)2.5 E(.)-.55 E F1(?)161 168 Q F0
+(Displays the le)202 168 Q -.05(ga)-.15 G(l).05 E F1(set)2.5 E F0(\()4.166 E F1
+(unset)1.666 E F0 4.166(\)c)1.666 G(ommands.)346.724 168 Q F1(slc)102 186 Q/F3
+10/Courier-Oblique@0 SF(state)6.383 E F0(The)5 E F1(slc)2.883 E F0 .384(comman\
+d \(Set Local Characters\) is used to set or change the state of the the speci\
+al)2.884 F 1.231(characters when the)161 198 R F2 1.231(TELNET LINEMODE)3.731 F
+F0 1.231(option has been enabled.)3.731 F 1.231(Special characters are)6.231 F
+.139(characters that get mapped to)161 210 R/F4 9/Times-Roman@0 SF(TELNET)2.639
+E F0 .139(commands sequences \(lik)2.639 F(e)-.1 E F1(ip)2.639 E F0(or)2.639 E
+F1(quit)2.639 E F0 2.639(\)o)C 2.639(rl)488.611 210 S .14(ine editing)497.36
+210 R(characters \(lik)161 222 Q(e)-.1 E F1(erase)2.5 E F0(and)2.5 E F1(kill)
+2.5 E F0(\). By def)A(ault, the local special characters are e)-.1 E(xported.)
+-.15 E F1(check)161 240 Q F0 -1.11(Ve)216 240 S .526
+(rify the current settings for the current special characters.)1.11 F .525
+(The remote side is)5.526 F .925(requested to send all the current special cha\
+racter settings, and if there are an)216 252 R(y)-.15 E
+(discrepancies with the local side, the local side will switch to the remote v)
+216 264 Q(alue.)-.25 E F1(export)161 282 Q F0 .497(Switch to the local def)216
+282 R .497(aults for the special characters.)-.1 F .496(The local def)5.496 F
+.496(ault charac-)-.1 F(ters are those of the local terminal at the time when)
+216 294 Q F1(telnet)2.5 E F0 -.1(wa)2.5 G 2.5(ss).1 G(tarted.)483.8 294 Q F1
+(import)161 312 Q F0 1.929(Switch to the remote def)216 312 R 1.929
+(aults for the special characters.)-.1 F 1.929(The remote def)6.929 F(ault)-.1
+E .37(characters are those of the remote system at the time when the)216 324 R
+F4(TELNET)2.869 E F0(connec-)2.869 E(tion w)216 336 Q(as established.)-.1 E F1
+(?)161 354 Q F0(Prints out help information for the)216 354 Q F1(slc)2.5 E F0
+(command.)2.5 E F1(status)102 372 Q F0(Sho)161 372 Q 2.808(wt)-.25 G .308
+(he current status of)189.118 372 R F1(telnet)2.809 E F0 2.809(.T)C .309
+(his includes the peer one is connected to, as well as the)316.641 372 R
+(current mode.)161 384 Q F1(toggle)102 402 Q F3(arguments ...)6 E F0 -.8(To)161
+414 S 2.112(ggle \(between).8 F F2(TRUE)4.612 E F0(and)4.612 E F2(FALSE)4.612 E
+F0 4.612(\)v)C 2.112(arious \215ags that control ho)324.76 414 R(w)-.25 E F1
+(telnet)4.611 E F0 2.111(responds to)4.611 F -2.15 -.25(ev e)161 426 T 2.73
+(nts. These).25 F .23(\215ags may be set e)2.73 F .231(xplicitly to)-.15 F F2
+(TRUE)2.731 E F0(or)2.731 E F2(FALSE)2.731 E F0 .231(using the)2.731 F F1(set)
+2.731 E F0(and)2.731 E F1(unset)2.731 E F0(com-)2.731 E .544(mands listed abo)
+161 438 R -.15(ve)-.15 G 5.544(.M).15 G .544(ore than one ar)255.382 438 R .543
+(gument may be speci\214ed.)-.18 F .543(The state of these \215ags may)5.543 F
+(be interrog)161 450 Q(ated with the)-.05 E F1(display)2.5 E F0 2.5(command. V)
+2.5 F(alid ar)-1.11 E(guments are:)-.18 E F1(authdebug)161 468 Q F0 -.45(Tu)226
+468 S(rns on deb).45 E(ugging information for the authentication code.)-.2 E F1
+(autoflush)161 486 Q F0(If)226 486 Q F1(autoflush)4.407 E F0(and)4.407 E F1
+(localchars)4.407 E F0 1.907(are both)4.407 F F2(TRUE)4.407 E F0 4.407(,t)C
+1.907(hen when the)451.219 486 R F1(ao)4.408 E F0 4.408(,o)C(r)536.67 486 Q F1
+(quit)226 498 Q F0 1.803(characters are recognized \(and transformed into)4.304
+F F4(TELNET)4.303 E F0(sequences;)4.303 E(see)226 510 Q F1(set)2.966 E F0(abo)
+2.966 E .766 -.15(ve f)-.15 H .466(or details\),).15 F F1(telnet)2.966 E F0
+.466(refuses to display an)2.966 F 2.966(yd)-.15 G .467(ata on the user')473.89
+510 R(s)-.55 E 2.241(terminal until the remote system ackno)226 522 R 2.241
+(wledges \(via a)-.25 F F2 2.241(TELNET TIMING)4.741 F(MARK)226 534 Q F0 .496
+(option\) that it has processed those)2.996 F F4(TELNET)2.996 E F0 2.996
+(sequences. The)2.996 F .497(initial v)2.996 F(al-)-.25 E .754
+(ue for this toggle is)226 546 R F2(TRUE)3.254 E F0 .753
+(if the terminal user had not done an "stty no\215sh",)3.253 F(otherwise)226
+558 Q F2(FALSE)2.5 E F0(\(see)2.5 E F2(stty)2.5 E F0(\(1\)\).)A F1(autodecrypt)
+161 576 Q F0 .556(When the)226 588 R F2 .556(TELNET ENCRYPT)3.056 F F0 .556
+(option is ne)3.056 F .556(gotiated, by def)-.15 F .557(ault the actual en-)-.1
+F .403(cryption \(decryption\) of the data stream does not start automatically)
+226 600 R 5.402(.T)-.65 G .402(he au-)514.888 600 R .789(toencrypt \(autodecry\
+pt\) command states that encryption of the output \(input\))226 612 R
+(stream should be enabled as soon as possible.)226 624 Q 2.87(Note: Because)226
+642 R .369(of e)2.869 F .369(xport controls, the)-.15 F F2 .369(TELNET ENCRYPT)
+2.869 F F0 .369(option is not sup-)2.869 F
+(ported outside the United States and Canada.)226 654 Q F1(autologin)161 672 Q
+F0 4.509(If the remote side supports the)226 672 R F2 4.509
+(TELNET AUTHENTICATION)7.009 F F0(option)7.009 E F4(TELNET)226 684 Q F0 3.448
+(attempts to use it to perform automatic authentication.)5.948 F 3.447(If the)
+8.447 F F2(AUTHENTICATION)226 696 Q F0 .197(option is not supported, the user')
+2.697 F 2.697(sl)-.55 G .197(ogin name are propa-)454.159 696 R -.05(ga)226 708
+S .41(ted through the).05 F F2 .41(TELNET ENVIRON)2.91 F F0 2.91(option. This)
+2.91 F .41(command is the same as)2.91 F(4.2 Berk)72 756 Q(ele)-.1 E 2.5(yD)
+-.15 G(istrib)132.57 756 Q 95.71(ution February)-.2 F(3, 1994)2.5 E(8)535 756 Q
+EP
+%%Page: 9 9
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R(specifying)226 96 Q/F1 10
+/Courier-Oblique@0 SF(a)2.5 E F0(option on the)2.5 E/F2 10/Courier-Bold@0 SF
+(open)2.5 E F0(command.)2.5 E F2(autosynch)161 114 Q F0(If)226 114 Q F2
+(autosynch)4.854 E F0(and)4.854 E F2(localchars)4.854 E F0 2.354(are both)4.854
+F/F3 10/Courier@0 SF(TRUE)4.854 E F0 4.854(,t)C 2.354(hen when either the)
+454.348 114 R F2(intr)226 126 Q F0(or)4.17 E F2(quit)4.17 E F0 1.669
+(characters is typed \(see)4.169 F F2(set)4.169 E F0(abo)4.169 E 1.969 -.15
+(ve f)-.15 H 1.669(or descriptions of the).15 F F2(intr)226 138 Q F0(and)2.925
+E F2(quit)2.925 E F0 .426(characters\), the resulting)2.925 F/F4 9
+/Times-Roman@0 SF(TELNET)2.926 E F0 .426(sequence sent is follo)2.926 F(wed)
+-.25 E 1.634(by the)226 150 R F3 1.634(TELNET SYNCH)4.134 F F0 4.134
+(sequence. This)4.134 F(procedure)4.134 E F2(should)4.134 E F0 1.634
+(cause the re-)4.134 F .871(mote system to be)226 162 R .871(gin thro)-.15 F
+.872(wing a)-.25 F -.1(wa)-.15 G 3.372(ya).1 G .872(ll pre)385.008 162 R .872
+(viously typed input until both of)-.25 F(the)226 174 Q F4(TELNET)3.622 E F0
+1.122(sequences ha)3.622 F 1.422 -.15(ve b)-.2 H 1.121
+(een read and acted upon.).15 F 1.121(The initial v)6.121 F 1.121(alue of)-.25
+F(this toggle is)226 186 Q F3(FALSE)2.5 E F0(.)A F2(binary)161 204 Q F0
+(Enable or disable the)226 204 Q F3(TELNET BINARY)2.5 E F0
+(option on both input and output.)2.5 E F2(inbinary)161 222 Q F0
+(Enable or disable the)226 222 Q F3(TELNET BINARY)2.5 E F0(option on input.)2.5
+E F2(outbinary)161 240 Q F0(Enable or disable the)226 240 Q F3(TELNET BINARY)
+2.5 E F0(option on output.)2.5 E F2(crlf)161 258 Q F0 1.415(If this is)226 258
+R F3(TRUE)3.915 E F0 3.915(,t)C 1.415(hen carriage returns will be sent as)
+298.72 258 R F3(<CR><LF>)3.915 E F0 3.915(.I)C 3.915(ft)507.72 258 S 1.415
+(his is)517.745 258 R F3(FALSE)226 270 Q F0 3.26(,t)C .759
+(hen carriage returns will be send as)264.54 270 R F3(<CR><NUL>)3.259 E F0
+3.259(.T)C .759(he initial v)479.292 270 R(alue)-.25 E(for this toggle is)226
+282 Q F3(FALSE)2.5 E F0(.)A F2(crmod)161 300 Q F0 -.8(To)226 300 S 1.1
+(ggle carriage return mode.).8 F 1.1
+(When this mode is enabled, most carriage re-)6.1 F .745(turn characters recei)
+226 312 R -.15(ve)-.25 G 3.244(df).15 G .744
+(rom the remote host will be mapped into a carriage)329.174 312 R 1.492
+(return follo)226 324 R 1.492(wed by a line feed.)-.25 F 1.493
+(This mode does not af)6.492 F 1.493(fect those characters)-.25 F .207
+(typed by the user)226 336 R 2.707(,o)-.4 G .207(nly those recei)305.028 336 R
+-.15(ve)-.25 G 2.706(df).15 G .206(rom the remote host.)383.838 336 R .206
+(This mode is not)5.206 F -.15(ve)226 348 S 1.026
+(ry useful unless the remote host only sends carriage return, b).15 F 1.026
+(ut ne)-.2 F -.15(ve)-.25 G 3.526(rl).15 G(ine)527.78 348 Q 2.5(feed. The)226
+360 R(initial v)2.5 E(alue for this toggle is)-.25 E F3(FALSE)2.5 E F0(.)A F2
+(debug)161 378 Q F0 -.8(To)226 378 S .073(ggles sock).8 F .073(et le)-.1 F -.15
+(ve)-.25 G 2.573(ld).15 G(eb)314.629 378 Q .073(ugging \(useful only to the)-.2
+F F2 .072(super user)2.573 F F0 .072(\). The initial)B -.25(va)226 390 S
+(lue for this toggle is).25 E F3(FALSE)2.5 E F0(.)A F2(encdebug)161 408 Q F0
+-.45(Tu)226 408 S(rns on deb).45 E(ugging information for the encryption code.)
+-.2 E F2(localchars)161 426 Q F0 1.485(If this is)5 F F3(TRUE)3.985 E F0 3.985
+(,t)C 1.485(hen the)299 426 R F2(flush)3.985 E F0(,)A F2(interrupt)3.986 E F0
+(,)A F2(quit)3.986 E F0(,)A F2(erase)3.986 E F0 3.986(,a)C(nd)502.014 426 Q F2
+(kill)3.986 E F0 2.944(characters \(see)226 438 R F2(set)5.444 E F0(abo)5.444 E
+-.15(ve)-.15 G 5.443(\)a).15 G 2.943(re recognized locally)353.755 438 R 5.443
+(,a)-.65 G 2.943(nd transformed into)455.234 438 R 3.265
+(\(hopefully\) appropriate)226 450 R F4(TELNET)5.765 E F0 3.265
+(control sequences \(respecti)5.765 F -.15(ve)-.25 G(ly).15 E F2(ao)5.766 E F0
+(,)A F2(ip)5.766 E F0(,)A F2(brk)226 462 Q F0(,)A F2(ec)2.788 E F0 2.788(,a)C
+(nd)271.016 462 Q F2(el)2.787 E F0 2.787(;s)C(ee)305.26 462 Q F2(send)2.787 E
+F0(abo)2.787 E -.15(ve)-.15 G 2.787(\). The).15 F .287(initial v)2.787 F .287
+(alue for this toggle is)-.25 F F3(TRUE)2.787 E F0 .045(in `)226 474 R .045
+(`old line by line')-.74 F 2.546('m)-.74 G .046(ode, and)318.906 474 R F3
+(FALSE)2.546 E F0 .046(in `)2.546 F .046(`character at a time')-.74 F 2.546('m)
+-.74 G 2.546(ode. When)494.134 474 R(the)226 486 Q F3(LINEMODE)2.894 E F0 .394
+(option is enabled, the v)2.894 F .394(alue of)-.25 F F2(localchars)2.893 E F0
+.393(is ignored, and)2.893 F 2.388(assumed to al)226 498 R -.1(wa)-.1 G 2.388
+(ys be).1 F F3(TRUE)4.888 E F0 4.888(.I)C(f)359.5 498 Q F3(LINEMODE)4.888 E F0
+2.388(has e)4.888 F -.15(ve)-.25 G 4.888(rb).15 G 2.389(een enabled, then)
+465.522 498 R F2(quit)226 510 Q F0 1.574(is sent as)4.074 F F2(abort)4.074 E F0
+4.074(,a)C(nd)338.42 510 Q F2 1.574(eof and)4.074 F F0 1.573(are sent as)4.074
+F F2 1.573(eof and)4.073 F(susp)4.073 E F0 4.073(,s)C(ee)531.12 510 Q F2(send)
+226 522 Q F0(abo)2.5 E -.15(ve)-.15 G(\).).15 E F2(netdata)161 540 Q F0 -.8(To)
+226 540 S .993(ggles the display of all netw).8 F .994(ork data \(in he)-.1 F
+.994(xadecimal format\).)-.15 F .994(The initial)5.994 F -.25(va)226 552 S
+(lue for this toggle is).25 E F3(FALSE)2.5 E F0(.)A F2(options)161 570 Q F0 -.8
+(To)226 570 S .625(ggles the display of some internal).8 F F2(telnet)3.125 E F0
+.625(protocol processing \(ha)3.125 F .625(ving to)-.2 F(do with)226 582 Q F4
+(TELNET)2.5 E F0 2.5(options\). The)2.5 F(initial v)2.5 E
+(alue for this toggle is)-.25 E F3(FALSE)2.5 E F0(.)A F2(prettydump)161 600 Q
+F0 .133(When the)5 F F2(netdata)2.633 E F0 .134(toggle is enabled, if)2.633 F
+F2(prettydump)2.634 E F0 .134(is enabled the output)2.634 F .745(from the)226
+612 R F2(netdata)3.245 E F0 .744
+(command will be formatted in a more user readable for)3.244 F(-)-.2 E 3.199
+(mat. Spaces)226 624 R .699
+(are put between each character in the output, and the be)3.199 F(ginning)-.15
+E(of an)226 636 Q(y)-.15 E F4(TELNET)2.5 E F0
+(escape sequence is preceded by a ')2.5 E/F5 10/Symbol SF(*)A F0 2.5('t)C 2.5
+(oa)442.553 636 S(id in locating them.)454.493 636 Q F2(skiprc)161 654 Q F0
+4.589(When the skiprc toggle is)226 654 R F3(TRUE)7.089 E F0(,)A F4(TELNET)
+7.089 E F0 4.589(skips the reading of the)7.089 F F3(.telnetrc)226 666 Q F0
+1.033(\214le in the users home directory when connections are opened.)3.533 F
+(The initial v)226 678 Q(alue for this toggle is)-.25 E F3(FALSE.)2.5 E F0
+(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71
+(ution February)-.2 F(3, 1994)2.5 E(9)535 750 Q EP
+%%Page: 10 10
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNET \( 1 \))72 48 R(BSD Reference Manual)
+258.235 48 Q -.834(TELNET \( 1 \))485.572 48 R/F1 10/Courier-Bold@0 SF
+(termdata)161 96 Q F0 -.8(To)226 96 S .934
+(ggles the display of all terminal data \(in he).8 F .933(xadecimal format\).)
+-.15 F .933(The initial)5.933 F -.25(va)226 108 S(lue for this toggle is).25 E
+/F2 10/Courier@0 SF(FALSE)2.5 E F0(.)A F1(verbose_encrypt)161 126 Q F0 1.129
+(When the)226 138 R F1(verbose_encrypt)3.629 E F0 1.13(toggle is)3.629 F F2
+(TRUE)3.63 E F0(,)A/F3 9/Times-Roman@0 SF(TELNET)3.63 E F0 1.13
+(prints out a mes-)3.63 F 1.377
+(sage each time encryption is enabled or disabled.)226 150 R 1.376
+(The initial v)6.377 F 1.376(alue for this)-.25 F 1.223(toggle is)226 162 R F2
+(FALSE.)3.723 E F0 3.723(Note: Because)3.723 F 1.224(of e)3.724 F 1.224
+(xport controls, data encryption is not)-.15 F
+(supported outside of the United States and Canada.)226 174 Q F1(?)161 192 Q F0
+(Displays the le)226 192 Q -.05(ga)-.15 G(l).05 E F1(toggle)2.5 E F0(commands.)
+2.5 E F1(z)102 210 Q F0(Suspend)161 210 Q F1(telnet)2.5 E F0 2.5(.T)C
+(his command only w)244.5 210 Q(orks when the user is using the)-.1 E F2(csh)
+2.5 E F0(\(1\).)A F1(!)102 228 Q F0([)6.833 E/F4 10/Courier-Oblique@0 SF
+(command).833 E F0(]).833 E(Ex)161 240 Q .293
+(ecute a single command in a subshell on the local system.)-.15 F(If)5.292 E F1
+(command)2.792 E F0 .292(is omitted, then an)2.792 F(interacti)161 252 Q .3
+-.15(ve s)-.25 H(ubshell is in).15 E -.2(vo)-.4 G -.1(ke).2 G(d.).1 E F1(?)102
+270 Q F0([)6.833 E F4(command).833 E F0(]).833 E 1.177(Get help.)161 282 R -.4
+(Wi)6.177 G 1.178(th no ar).4 F(guments,)-.18 E F1(telnet)3.678 E F0 1.178
+(prints a help summary)3.678 F 6.178(.I)-.65 G 3.678(fac)433.358 282 S 1.178
+(ommand is speci\214ed,)452.924 282 R F1(telnet)161 294 Q F0
+(will print the help information for just that command.)2.5 E/F5 10
+/Times-Bold@0 SF(ENVIR)72 318 Q(ONMENT)-.3 E F1(Telnet)102 330 Q F0 .666
+(uses at least the)3.166 F F2(HOME)3.166 E F0(,)A F2(SHELL)3.165 E F0(,)A F2
+(DISPLAY)3.165 E F0 3.165(,a)C(nd)326.255 330 Q F2(TERM)3.165 E F0(en)3.165 E
+.665(vironment v)-.4 F 3.165(ariables. Other)-.25 F(en)3.165 E(vironment)-.4 E
+-.25(va)102 342 S(riables may be propag).25 E(ated to the other side via the)
+-.05 E F2(TELNET ENVIRON)2.5 E F0(option.)2.5 E F5(FILES)72 366 Q F2
+(~/.telnetrc)102 378 Q F0(user customized telnet startup v)5 E(alues)-.25 E F5
+(HIST)72 402 Q(OR)-.18 E(Y)-.35 E F0(The)102 414 Q F1(Telnet)2.5 E F0
+(command appeared in 4.2)2.5 E F3(BSD)A F0(.)A F5(NO)72 438 Q(TES)-.4 E F0
+(On some remote systems, echo has to be turned of)102 450 Q 2.5(fm)-.25 G
+(anually when in `)316.44 450 Q(`old line by line')-.74 E 2.5('m)-.74 G(ode.)
+465.22 450 Q .691(In `)102 468 R .691(`old line by line')-.74 F 3.191('m)-.74 G
+.691(ode or)198.685 468 R F2(LINEMODE)3.191 E F0 .691(the terminal')3.191 F(s)
+-.55 E F1(eof)3.191 E F0 .691(character is only recognized \(and sent to the)
+3.191 F(remote system\) when it is the \214rst character on a line.)102 480 Q
+(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71
+(ution February)-.2 F(3, 1994)2.5 E(10)530 750 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/mechglue/src/appl/telnet/telnet/telnet.0.txt b/mechglue/src/appl/telnet/telnet/telnet.0.txt
new file mode 100644
index 000000000..41d410bab
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/telnet.0.txt
@@ -0,0 +1,718 @@
+TELNET(1)                    BSD Reference Manual                    TELNET(1)
+
+NNAAMMEE
+     tteellnneett - user interface to the TELNET protocol
+
+SSYYNNOOPPSSIISS
+     tteellnneett [--88] [--EE] [--FF] [--KK] [--LL] [--SS _t_o_s] [--XX _a_u_t_h_t_y_p_e] [--aa] [--cc] [--dd] [--ee
+            _e_s_c_a_p_e_c_h_a_r] [--ff] [--kk _r_e_a_l_m] [--ll _u_s_e_r] [--nn _t_r_a_c_e_f_i_l_e] [--rr] [--xx]
+            [_h_o_s_t [port]]
+
+DDEESSCCRRIIPPTTIIOONN
+     The tteellnneett command is used to communicate with another host using the
+     TELNET protocol.  If tteellnneett is invoked without the _h_o_s_t argument, it en-
+     ters command mode, indicated by its prompt (tteellnneett>>). In this mode, it
+     accepts and executes the commands listed below.  If it is invoked with
+     arguments, it performs an ooppeenn command with those arguments.
+
+     Options:
+
+     --88      Specifies an 8-bit data path.  This causes an attempt to negoti-
+             ate the TELNET BINARY option on both input and output.
+
+     --EE      Stops any character from being recognized as an escape character.
+
+     --FF      If Kerberos V5 authentication is being used, the --FF option allows
+             the local credentials to be forwarded to the remote system, in-
+             cluding any credentials that have already been forwarded into the
+             local environment.
+
+     --KK      Specifies no automatic login to the remote system.
+
+     --LL      Specifies an 8-bit data path on output.  This causes the BINARY
+             option to be negotiated on output.
+
+     --SS _t_o_s  Sets the IP type-of-service (TOS) option for the telnet connec-
+             tion to the value _t_o_s_, which can be a numeric TOS value or, on
+             systems that support it, a symbolic TOS name found in the
+             /etc/iptos file.
+
+     --XX _a_t_y_p_e
+             Disables the _a_t_y_p_e type of authentication.
+
+     --aa      Attempt automatic login.  Currently, this sends the user name via
+             the USER variable of the ENVIRON option if supported by the re-
+             mote system.  The name used is that of the current user as re-
+             turned by getlogin(2) if it agrees with the current user ID, oth-
+             erwise it is the name associated with the user ID.
+
+     --cc      Disables the reading of the user's _._t_e_l_n_e_t_r_c file.  (See the
+             ttooggggllee sskkiipprrcc command on this man page.)
+
+     --dd      Sets the initial value of the ddeebbuugg toggle to TRUE
+
+     --ee _e_s_c_a_p_e _c_h_a_r
+             Sets the initial tteellnneett tteellnneett escape character to _e_s_c_a_p_e _c_h_a_r_.
+             If _e_s_c_a_p_e _c_h_a_r is omitted, then there will be no escape charac-
+             ter.
+
+     --ff      If Kerberos V5 authentication is being used, the --ff option allows
+             the local credentials to be forwarded to the remote system.
+
+     --kk _r_e_a_l_m
+             If Kerberos authentication is being used, the --kk option requests
+             that telnet obtain tickets for the remote host in realm realm in-
+             stead of the remote host's realm, as determined by
+
+             krb_realmofhost(3).
+
+     --ll _u_s_e_r
+             When connecting to the remote system, if the remote system under-
+             stands the ENVIRON option, then _u_s_e_r will be sent to the remote
+             system as the value for the variable USER.  This option implies
+             the --aa option.  This option may also be used with the ooppeenn com-
+             mand.
+
+     --nn _t_r_a_c_e_f_i_l_e
+             Opens _t_r_a_c_e_f_i_l_e for recording trace information.  See the sseett
+             ttrraacceeffiillee command below.
+
+     --rr      Specifies a user interface similar to rlogin(1).  In this mode,
+             the escape character is set to the tilde (~) character, unless
+             modified by the -e option.
+
+     --xx      Turns on encryption of the data stream if possible.  This option
+             is not available outside of the United States and Canada.
+
+     _h_o_s_t    Indicates the official name, an alias, or the Internet address of
+             a remote host.
+
+     _p_o_r_t    Indicates a port number (address of an application).  If a number
+             is not specified, the default tteellnneett port is used.
+
+     When in rlogin mode, a line of the form ~.  disconnects from the remote
+     host; ~ is the telnet escape character.  Similarly, the line ~^Z suspends
+     the telnet session.  The line ~^] escapes to the normal telnet escape
+     prompt.
+
+     Once a connection has been opened, tteellnneett will attempt to enable the
+     TELNET LINEMODE option.  If this fails, then tteellnneett will revert to one of
+     two input modes: either ``character at a time'' or ``old line by line''
+     depending on what the remote system supports.
+
+     When LINEMODE is enabled, character processing is done on the local sys-
+     tem, under the control of the remote system.  When input editing or char-
+     acter echoing is to be disabled, the remote system will relay that infor-
+     mation.  The remote system will also relay changes to any special charac-
+     ters that happen on the remote system, so that they can take effect on
+     the local system.
+
+     In ``character at a time'' mode, most text typed is immediately sent to
+     the remote host for processing.
+
+     In ``old line by line'' mode, all text is echoed locally, and (normally)
+     only completed lines are sent to the remote host.  The ``local echo char-
+     acter'' (initially ``^E'') may be used to turn off and on the local echo
+     (this would mostly be used to enter passwords without the password being
+     echoed).
+
+     If the LINEMODE option is enabled, or if the llooccaallcchhaarrss toggle is TRUE
+     (the default for ``old line by line``; see below), the user's qquuiitt, iinnttrr,
+     and fflluusshh characters are trapped locally, and sent as TELNET protocol se-
+     quences to the remote side.  If LINEMODE has ever been enabled, then the
+     user's ssuusspp and eeooff are also sent as TELNET protocol sequences, and qquuiitt
+     is sent as a TELNET ABORT instead of BREAK There are options (see ttooggggllee
+     aauuttoofflluusshh and ttooggggllee aauuttoossyynncchh below) which cause this action to flush
+     subsequent output to the terminal (until the remote host acknowledges the
+     TELNET sequence) and flush previous terminal input (in the case of qquuiitt
+     and iinnttrr).
+
+     While connected to a remote host, tteellnneett command mode may be entered by
+     typing the tteellnneett ``escape character'' (initially ``^]'').  When in com-
+     mand mode, the normal terminal editing conventions are available.
+
+     The following tteellnneett commands are available.  Only enough of each command
+     to uniquely identify it need be typed (this is also true for arguments to
+     the mmooddee, sseett, ttooggggllee, uunnsseett, ssllcc, eennvviirroonn, and ddiissppllaayy commands).
+
+     aauutthh _a_r_g_u_m_e_n_t _._._.
+                The auth command manipulates the information sent through the
+                TELNET AUTHENTICATE option.  Valid arguments for the auth com-
+                mand are as follows:
+
+                ddiissaabbllee _t_y_p_e  Disables the specified type of authentication.
+                              To obtain a list of available types, use the
+                              aauutthh ddiissaabbllee ?? command.
+
+                eennaabbllee _t_y_p_e   Enables the specified type of authentication.
+                              To obtain a list of available types, use the
+                              aauutthh eennaabbllee ?? command.
+
+                ssttaattuuss        Lists the current status of the various types of
+                              authentication.
+
+     cclloossee      Close a TELNET session and return to command mode.
+
+     ddiissppllaayy _a_r_g_u_m_e_n_t _._._.
+                Displays all, or some, of the sseett and ttooggggllee values (see be-
+                low).
+
+     eennccrryypptt _a_r_g_u_m_e_n_t _._._.
+                The encrypt command manipulates the information sent through
+                the TELNET ENCRYPT option.
+
+                Note:  Because of export controls, the TELNET ENCRYPT option
+                is not supported outside of the United States and Canada.
+
+                Valid arguments for the encrypt command are as follows:
+
+                ddiissaabbllee _t_y_p_e [[iinnppuutt||oouuttppuutt]]
+                              Disables the specified type of encryption.  If
+                              you omit the input and output, both input and
+                              output are disabled.  To obtain a list of avail-
+                              able types, use the eennccrryypptt ddiissaabbllee ?? command.
+
+                eennaabbllee _t_y_p_e [[iinnppuutt||oouuttppuutt]]
+                              Enables the specified type of encryption.  If
+                              you omit input and output, both input and output
+                              are enabled.  To obtain a list of available
+                              types, use the eennccrryypptt eennaabbllee ?? command.
+
+                iinnppuutt         This is the same as the eennccrryypptt ssttaarrtt iinnppuutt com-
+                              mand.
+
+                --iinnppuutt        This is the same as the eennccrryypptt ssttoopp iinnppuutt com-
+                              mand.
+
+                oouuttppuutt        This is the same as the eennccrryypptt ssttaarrtt oouuttppuutt
+                              command.
+
+                --oouuttppuutt       This is the same as the eennccrryypptt ssttoopp oouuttppuutt com-
+                              mand.
+
+                ssttaarrtt [[iinnppuutt||oouuttppuutt]]
+                              Attempts to start encryption.  If you omit iinnppuutt
+                              and oouuttppuutt,, both input and output are enabled.
+                              To obtain a list of available types, use the
+
+                              eennccrryypptt eennaabbllee ?? command.
+
+                ssttaattuuss        Lists the current status of encryption.
+
+                ssttoopp [[iinnppuutt||oouuttppuutt]]
+                              Stops encryption.  If you omit input and output,
+                              encryption is on both input and output.
+
+                ttyyppee _t_y_p_e     Sets the default type of encryption to be used
+                              with later eennccrryypptt ssttaarrtt or eennccrryypptt ssttoopp com-
+                              mands.
+
+     eennvviirroonn _a_r_g_u_m_e_n_t_s_._._.
+                The eennvviirroonn command is used to manipulate the the variables
+                that my be sent through the TELNET ENVIRON option.  The ini-
+                tial set of variables is taken from the users environment,
+                with only the DISPLAY and PRINTER variables being exported by
+                default.  The USER variable is also exported if the --aa or --ll
+                options are used.
+                Valid arguments for the eennvviirroonn command are:
+
+                ddeeffiinnee _v_a_r_i_a_b_l_e _v_a_l_u_e
+                            Define the variable _v_a_r_i_a_b_l_e to have a value of
+                            _v_a_l_u_e_. Any variables defined by this command are
+                            automatically exported.  The _v_a_l_u_e may be enclosed
+                            in single or double quotes so that tabs and spaces
+                            may be included.
+
+                uunnddeeffiinnee _v_a_r_i_a_b_l_e
+                            Remove _v_a_r_i_a_b_l_e from the list of environment vari-
+                            ables.
+
+                eexxppoorrtt _v_a_r_i_a_b_l_e
+                            Mark the variable _v_a_r_i_a_b_l_e to be exported to the
+                            remote side.
+
+                uunneexxppoorrtt _v_a_r_i_a_b_l_e
+                            Mark the variable _v_a_r_i_a_b_l_e to not be exported un-
+                            less explicitly asked for by the remote side.
+
+                lliisstt        List the current set of environment variables.
+                            Those marked with a ** will be sent automatically,
+                            other variables will only be sent if explicitly
+                            requested.
+
+                ??           Prints out help information for the eennvviirroonn com-
+                            mand.
+
+     llooggoouutt     Sends the TELNET LOGOUT option to the remote side.  This com-
+                mand is similar to a cclloossee command; however, if the remote
+                side does not support the LOGOUT option, nothing happens.  If,
+                however, the remote side does support the LOGOUT option, this
+                command should cause the remote side to close the TELNET con-
+                nection.  If the remote side also supports the concept of sus-
+                pending a user's session for later reattachment, the logout
+                argument indicates that you should terminate the session imme-
+                diately.
+
+     mmooddee _t_y_p_e  _T_y_p_e is one of several options, depending on the state of the
+                TELNET session.  The remote host is asked for permission to go
+                into the requested mode.  If the remote host is capable of en-
+                tering that mode, the requested mode will be entered.
+
+                cchhaarraacctteerr     Disable the TELNET LINEMODE option, or, if the
+                              remote side does not understand the LINEMODE op-
+
+                              tion, then enter ``character at a time`` mode.
+
+                lliinnee          Enable the TELNET LINEMODE option, or, if the
+                              remote side does not understand the LINEMODE op-
+                              tion, then attempt to enter ``old-line-by-line``
+                              mode.
+
+                iissiigg (--iissiigg)  Attempt to enable (disable) the TRAPSIG mode of
+                              the LINEMODE option.  This requires that the
+                              LINEMODE option be enabled.
+
+                eeddiitt (--eeddiitt)  Attempt to enable (disable) the EDIT mode of the
+                              LINEMODE option.  This requires that the
+                              LINEMODE option be enabled.
+
+                ssooffttttaabbss (--ssooffttttaabbss)
+                              Attempt to enable (disable) the SOFT_TAB mode of
+                              the LINEMODE option.  This requires that the
+                              LINEMODE option be enabled.
+
+                lliitteecchhoo (--lliitteecchhoo)
+                              Attempt to enable (disable) the LIT_ECHO mode of
+                              the LINEMODE option.  This requires that the
+                              LINEMODE option be enabled.
+
+                ??             Prints out help information for the mmooddee com-
+                              mand.
+
+     ooppeenn _h_o_s_t [[--ll] _u_s_e_r][--_p_o_r_t]
+                Open a connection to the named host.  If no port number is
+                specified, tteellnneett will attempt to contact a TELNET server at
+                the default port.  The host specification may be either a host
+                name (see hosts(5))  or an Internet address specified in the
+                ``dot notation'' (see inet(3)).  The [--ll] option may be used
+                to specify the user name to be passed to the remote system via
+                the ENVIRON option.  When connecting to a non-standard port,
+                tteellnneett omits any automatic initiation of TELNET options.  When
+                the port number is preceded by a minus sign, the initial op-
+                tion negotiation is done.  After establishing a connection,
+                the file _._t_e_l_n_e_t_r_c in the users home directory is opened.
+                Lines beginning with a # are comment lines.  Blank lines are
+                ignored.  Lines that begin without white space are the start
+                of a machine entry.  The first thing on the line is the name
+                of the machine that is being connected to.  The rest of the
+                line, and successive lines that begin with white space are as-
+                sumed to be tteellnneett commands and are processed as if they had
+                been typed in manually to the tteellnneett command prompt.
+
+     qquuiitt       Close any open TELNET session and exit tteellnneett. An end of file
+                (in command mode) will also close a session and exit.
+
+     sseenndd _a_r_g_u_m_e_n_t_s
+                Sends one or more special character sequences to the remote
+                host.  The following are the arguments which may be specified
+                (more than one argument may be specified at a time):
+
+                aabboorrtt   Sends the TELNET ABORT (Abort processes) sequence.
+
+                aaoo      Sends the TELNET AO (Abort Output) sequence, which
+                        should cause the remote system to flush all output
+                        _f_r_o_m the remote system _t_o the user's terminal.
+
+                aayytt     Sends the TELNET AYT (Are You There) sequence, to
+                        which the remote system may or may not choose to re-
+
+
+                        spond.
+
+                bbrrkk     Sends the TELNET BRK (Break) sequence, which may have
+                        significance to the remote system.
+
+                eecc      Sends the TELNET EC (Erase Character) sequence, which
+                        should cause the remote system to erase the last char-
+                        acter entered.
+
+                eell      Sends the TELNET EL (Erase Line) sequence, which
+                        should cause the remote system to erase the line cur-
+                        rently being entered.
+
+                eeooff     Sends the TELNET EOF (End Of File) sequence.
+
+                eeoorr     Sends the TELNET EOR (End of Record) sequence.
+
+                eessccaappee  Sends the current tteellnneett escape character (initially
+                        ``^'').
+
+                ggaa      Sends the TELNET GA (Go Ahead) sequence, which likely
+                        has no significance to the remote system.
+
+                ggeettssttaattuuss
+                        If the remote side supports the TELNET STATUS command,
+                        ggeettssttaattuuss will send the subnegotiation to request that
+                        the server send its current option status.
+
+                iipp      Sends the TELNET IP (Interrupt Process) sequence,
+                        which should cause the remote system to abort the cur-
+                        rently running process.
+
+                nnoopp     Sends the TELNET NOP (No OPeration) sequence.
+
+                ssuusspp    Sends the TELNET SUSP (SUSPend process) sequence.
+
+                ssyynncchh   Sends the TELNET SYNCH sequence.  This sequence causes
+                        the remote system to discard all previously typed (but
+                        not yet read) input.  This sequence is sent as TCP ur-
+                        gent data (and may not work if the remote system is a
+                        4.2BSD system -- if it doesn't work, a lower case
+                        ``r'' may be echoed on the terminal).
+
+                ddoo _c_m_d
+
+                ddoonntt _c_m_d
+
+                wwiillll _c_m_d
+
+                wwoonntt _c_m_d
+                        Sends the TELNET DO _c_m_d sequence.  _C_m_d can be either a
+                        decimal number between 0 and 255, or a symbolic name
+                        for a specific TELNET command.  _C_m_d can also be either
+                        hheellpp or ?? to print out help information, including a
+                        list of known symbolic names.
+
+                ??       Prints out help information for the sseenndd command.
+
+     sseett _a_r_g_u_m_e_n_t _v_a_l_u_e
+
+     uunnsseett _a_r_g_u_m_e_n_t _v_a_l_u_e
+                The sseett command will set any one of a number of tteellnneett vari-
+                ables to a specific value or to TRUE. The special value ooffff
+                turns off the function associated with the variable, this is
+                equivalent to using the uunnsseett command.  The uunnsseett command will
+                disable or set to FALSE any of the specified functions.  The
+                values of variables may be interrogated with the ddiissppllaayy com-
+                mand.  The variables which may be set or unset, but not tog-
+                gled, are listed here.  In addition, any of the variables for
+                the ttooggggllee command may be explicitly set or unset using the
+                sseett and uunnsseett commands.
+
+                aayytt     If TELNET is in localchars mode, or LINEMODE is en-
+                        abled, and the status character is typed, a TELNET AYT
+                        sequence (see sseenndd aayytt preceding) is sent to the re-
+                        mote host.  The initial value for the "Are You There"
+                        character is the terminal's status character.
+
+                eecchhoo    This is the value (initially ``^E'') which, when in
+                        ``line by line'' mode, toggles between doing local
+                        echoing of entered characters (for normal processing),
+                        and suppressing echoing of entered characters (for en-
+                        tering, say, a password).
+
+                eeooff     If tteellnneett is operating in LINEMODE or ``old line by
+                        line'' mode, entering this character as the first
+                        character on a line will cause this character to be
+                        sent to the remote system.  The initial value of the
+                        eof character is taken to be the terminal's eeooff char-
+                        acter.
+
+                eerraassee   If tteellnneett is in llooccaallcchhaarrss mode (see ttooggggllee llooccaallcchhaarrss
+                        below), aanndd if tteellnneett is operating in ``character at a
+                        time'' mode, then when this character is typed, a
+                        TELNET EC sequence (see sseenndd eecc above) is sent to the
+                        remote system.  The initial value for the erase char-
+                        acter is taken to be the terminal's eerraassee character.
+
+                eessccaappee  This is the tteellnneett escape character (initially ``^['')
+                        which causes entry into tteellnneett command mode (when con-
+                        nected to a remote system).
+
+                fflluusshhoouuttppuutt
+                        If tteellnneett is in llooccaallcchhaarrss mode (see ttooggggllee llooccaallcchhaarrss
+                        below) and the fflluusshhoouuttppuutt character is typed, a
+                        TELNET AO sequence (see sseenndd aaoo above) is sent to the
+                        remote host.  The initial value for the flush charac-
+                        ter is taken to be the terminal's fflluusshh character.
+
+                ffoorrww11
+
+                ffoorrww22   If TELNET is operating in LINEMODE, these are the
+                        characters that, when typed, cause partial lines to be
+                        forwarded to the remote system.  The initial value for
+                        the forwarding characters are taken from the termi-
+                        nal's eol and eol2 characters.
+
+                iinntteerrrruupptt
+                        If tteellnneett is in llooccaallcchhaarrss mode (see ttooggggllee llooccaallcchhaarrss
+                        below) and the iinntteerrrruupptt character is typed, a TELNET
+                        IP sequence (see sseenndd iipp above) is sent to the remote
+                        host.  The initial value for the interrupt character
+                        is taken to be the terminal's iinnttrr character.
+
+                kkiillll    If tteellnneett is in llooccaallcchhaarrss mode (see ttooggggllee llooccaallcchhaarrss
+                        below), aanndd if tteellnneett is operating in ``character at a
+                        time'' mode, then when this character is typed, a
+                        TELNET EL sequence (see sseenndd eell above) is sent to the
+                        remote system.  The initial value for the kill charac-
+                        ter is taken to be the terminal's kkiillll character.
+
+                llnneexxtt   If tteellnneett is operating in LINEMODE or ``old line by
+                        line`` mode, then this character is taken to be the
+                        terminal's llnneexxtt character.  The initial value for the
+                        lnext character is taken to be the terminal's llnneexxtt
+                        character.
+
+                qquuiitt    If tteellnneett is in llooccaallcchhaarrss mode (see ttooggggllee llooccaallcchhaarrss
+                        below) and the qquuiitt character is typed, a TELNET BRK
+                        sequence (see sseenndd bbrrkk above) is sent to the remote
+                        host.  The initial value for the quit character is
+                        taken to be the terminal's qquuiitt character.
+
+                rreepprriinntt
+                        If tteellnneett is operating in LINEMODE or ``old line by
+                        line`` mode, then this character is taken to be the
+                        terminal's rreepprriinntt character.  The initial value for
+                        the reprint character is taken to be the terminal's
+                        rreepprriinntt character.
+
+                rrllooggiinn  This is the rlogin escape character.  If set, the nor-
+                        mal TELNET escape character is ignored unless it is
+                        preceded by this character at the beginning of a line.
+                        This character, at the beginning of a line followed by
+                        a "."  closes the connection; when followed by a ^Z it
+                        suspends the telnet command.  The initial state is to
+                        disable the rlogin escape character.
+
+                ssttaarrtt   If the TELNET TOGGLE-FLOW-CONTROL option has been en-
+                        abled, then this character is taken to be the termi-
+                        nal's ssttaarrtt character.  The initial value for the kill
+                        character is taken to be the terminal's ssttaarrtt charac-
+                        ter.
+
+                ssttoopp    If the TELNET TOGGLE-FLOW-CONTROL option has been en-
+                        abled, then this character is taken to be the termi-
+                        nal's ssttoopp character.  The initial value for the kill
+                        character is taken to be the terminal's ssttoopp charac-
+                        ter.
+
+                ssuusspp    If tteellnneett is in llooccaallcchhaarrss mode, or LINEMODE is en-
+                        abled, and the ssuussppeenndd character is typed, a TELNET
+                        SUSP sequence (see sseenndd ssuusspp above) is sent to the re-
+                        mote host.  The initial value for the suspend charac-
+                        ter is taken to be the terminal's ssuussppeenndd character.
+
+                ttrraacceeffiillee
+                        This is the file to which the output, caused by
+                        nneettddaattaa or ooppttiioonn tracing being TRUE, will be written.
+                        If it is set to ``--'', then tracing information will
+                        be written to standard output (the default).
+
+                wwoorrddeerraassee
+                        If tteellnneett is operating in LINEMODE or ``old line by
+                        line`` mode, then this character is taken to be the
+                        terminal's wwoorrddeerraassee character.  The initial value for
+                        the worderase character is taken to be the terminal's
+                        wwoorrddeerraassee character.
+
+                ??       Displays the legal sseett (uunnsseett) commands.
+
+     ssllcc _s_t_a_t_e  The ssllcc command (Set Local Characters) is used to set or
+                change the state of the the special characters when the TELNET
+                LINEMODE option has been enabled.  Special characters are
+                characters that get mapped to TELNET commands sequences (like
+                iipp or qquuiitt) or line editing characters (like eerraassee and kkiillll).
+
+
+                By default, the local special characters are exported.
+
+                cchheecckk       Verify the current settings for the current spe-
+                            cial characters.  The remote side is requested to
+                            send all the current special character settings,
+                            and if there are any discrepancies with the local
+                            side, the local side will switch to the remote
+                            value.
+
+                eexxppoorrtt      Switch to the local defaults for the special char-
+                            acters.  The local default characters are those of
+                            the local terminal at the time when tteellnneett was
+                            started.
+
+                iimmppoorrtt      Switch to the remote defaults for the special
+                            characters.  The remote default characters are
+                            those of the remote system at the time when the
+                            TELNET connection was established.
+
+                ??           Prints out help information for the ssllcc command.
+
+     ssttaattuuss     Show the current status of tteellnneett. This includes the peer one
+                is connected to, as well as the current mode.
+
+     ttooggggllee _a_r_g_u_m_e_n_t_s _._._.
+                Toggle (between TRUE and FALSE) various flags that control how
+                tteellnneett responds to events.  These flags may be set explicitly
+                to TRUE or FALSE using the sseett and uunnsseett commands listed
+                above.  More than one argument may be specified.  The state of
+                these flags may be interrogated with the ddiissppllaayy command.
+                Valid arguments are:
+
+                aauutthhddeebbuugg     Turns on debugging information for the authenti-
+                              cation code.
+
+                aauuttoofflluusshh     If aauuttoofflluusshh and llooccaallcchhaarrss are both TRUE, then
+                              when the aaoo, or qquuiitt characters are recognized
+                              (and transformed into TELNET sequences; see sseett
+                              above for details), tteellnneett refuses to display
+                              any data on the user's terminal until the remote
+                              system acknowledges (via a TELNET TIMING MARK
+                              option) that it has processed those TELNET se-
+                              quences.  The initial value for this toggle is
+                              TRUE if the terminal user had not done an "stty
+                              noflsh", otherwise FALSE (see stty(1)).
+
+                aauuttooddeeccrryypptt   When the TELNET ENCRYPT option is negotiated, by
+                              default the actual encryption (decryption) of
+                              the data stream does not start automatically.
+                              The autoencrypt (autodecrypt) command states
+                              that encryption of the output (input) stream
+                              should be enabled as soon as possible.
+
+                              Note:  Because of export controls, the TELNET
+                              ENCRYPT option is not supported outside the
+                              United States and Canada.
+
+                aauuttoollooggiinn     If the remote side supports the TELNET
+                              AUTHENTICATION option TELNET attempts to use it
+                              to perform automatic authentication.  If the
+                              AUTHENTICATION option is not supported, the us-
+                              er's login name are propagated through the
+                              TELNET ENVIRON option.  This command is the same
+                              as specifying _a option on the ooppeenn command.
+
+                aauuttoossyynncchh     If aauuttoossyynncchh and llooccaallcchhaarrss are both TRUE, then
+                              when either the iinnttrr or qquuiitt characters is typed
+                              (see sseett above for descriptions of the iinnttrr and
+                              qquuiitt characters), the resulting TELNET sequence
+                              sent is followed by the TELNET SYNCH sequence.
+                              This procedure sshhoouulldd cause the remote system to
+                              begin throwing away all previously typed input
+                              until both of the TELNET sequences have been
+                              read and acted upon.  The initial value of this
+                              toggle is FALSE.
+
+                bbiinnaarryy        Enable or disable the TELNET BINARY option on
+                              both input and output.
+
+                iinnbbiinnaarryy      Enable or disable the TELNET BINARY option on
+                              input.
+
+                oouuttbbiinnaarryy     Enable or disable the TELNET BINARY option on
+                              output.
+
+                ccrrllff          If this is TRUE, then carriage returns will be
+                              sent as <CR><LF>. If this is FALSE, then car-
+                              riage returns will be send as <CR><NUL>. The
+                              initial value for this toggle is FALSE.
+
+                ccrrmmoodd         Toggle carriage return mode.  When this mode is
+                              enabled, most carriage return characters re-
+                              ceived from the remote host will be mapped into
+                              a carriage return followed by a line feed.  This
+                              mode does not affect those characters typed by
+                              the user, only those received from the remote
+                              host.  This mode is not very useful unless the
+                              remote host only sends carriage return, but nev-
+                              er line feed.  The initial value for this toggle
+                              is FALSE.
+
+                ddeebbuugg         Toggles socket level debugging (useful only to
+                              the ssuuppeerr uusseerr). The initial value for this tog-
+                              gle is FALSE.
+
+                eennccddeebbuugg      Turns on debugging information for the encryp-
+                              tion code.
+
+                llooccaallcchhaarrss    If this is TRUE, then the fflluusshh, iinntteerrrruupptt,
+                              qquuiitt, eerraassee, and kkiillll characters (see sseett above)
+                              are recognized locally, and transformed into
+                              (hopefully) appropriate TELNET control sequences
+                              (respectively aaoo, iipp, bbrrkk, eecc, and eell; see sseenndd
+                              above).  The initial value for this toggle is
+                              TRUE in ``old line by line'' mode, and FALSE in
+                              ``character at a time'' mode.  When the LINEMODE
+                              option is enabled, the value of llooccaallcchhaarrss is
+                              ignored, and assumed to always be TRUE. If
+                              LINEMODE has ever been enabled, then qquuiitt is
+                              sent as aabboorrtt, and eeooff aanndd are sent as eeooff aanndd
+                              ssuusspp, see sseenndd above).
+
+                nneettddaattaa       Toggles the display of all network data (in hex-
+                              adecimal format).  The initial value for this
+                              toggle is FALSE.
+
+                ooppttiioonnss       Toggles the display of some internal tteellnneett pro-
+                              tocol processing (having to do with TELNET op-
+                              tions).  The initial value for this toggle is
+                              FALSE.
+
+                pprreettttyydduummpp    When the nneettddaattaa toggle is enabled, if
+                              pprreettttyydduummpp is enabled the output from the
+                              nneettddaattaa command will be formatted in a more user
+                              readable format.  Spaces are put between each
+                              character in the output, and the beginning of
+                              any TELNET escape sequence is preceded by a '*'
+                              to aid in locating them.
+
+                sskkiipprrcc        When the skiprc toggle is TRUE, TELNET skips the
+                              reading of the _._t_e_l_n_e_t_r_c file in the users home
+                              directory when connections are opened.  The ini-
+                              tial value for this toggle is FALSE.
+
+                tteerrmmddaattaa      Toggles the display of all terminal data (in
+                              hexadecimal format).  The initial value for this
+                              toggle is FALSE.
+
+                vveerrbboossee__eennccrryypptt
+                              When the vveerrbboossee__eennccrryypptt toggle is TRUE, TELNET
+                              prints out a message each time encryption is en-
+                              abled or disabled.  The initial value for this
+                              toggle is FALSE. Note:  Because of export con-
+                              trols, data encryption is not supported outside
+                              of the United States and Canada.
+
+                ??             Displays the legal ttooggggllee commands.
+
+     zz          Suspend tteellnneett. This command only works when the user is using
+                the csh(1).
+
+     !! [_c_o_m_m_a_n_d]
+                Execute a single command in a subshell on the local system.
+                If ccoommmmaanndd is omitted, then an interactive subshell is in-
+                voked.
+
+     ?? [_c_o_m_m_a_n_d]
+                Get help.  With no arguments, tteellnneett prints a help summary.
+                If a command is specified, tteellnneett will print the help informa-
+                tion for just that command.
+
+EENNVVIIRROONNMMEENNTT
+     TTeellnneett uses at least the HOME, SHELL, DISPLAY, and TERM environment vari-
+     ables.  Other environment variables may be propagated to the other side
+     via the TELNET ENVIRON option.
+
+FFIILLEESS
+     ~/.telnetrc  user customized telnet startup values
+
+HHIISSTTOORRYY
+     The TTeellnneett command appeared in 4.2BSD.
+
+NNOOTTEESS
+     On some remote systems, echo has to be turned off manually when in ``old
+     line by line'' mode.
+
+     In ``old line by line'' mode or LINEMODE the terminal's eeooff character is
+     only recognized (and sent to the remote system) when it is the first
+     character on a line.
+
+4.2 Berkeley Distribution      February 3, 1994                             11
diff --git a/mechglue/src/appl/telnet/telnet/telnet.1 b/mechglue/src/appl/telnet/telnet/telnet.1
new file mode 100644
index 000000000..e354c2a12
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/telnet.1
@@ -0,0 +1,1339 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)telnet.1	8.4 (Berkeley) 2/3/94
+.\" "
+.TH TELNET 1
+.SH NAME
+telnet \- user interface to the TELNET protocol
+.SH SYNOPSIS
+.B telnet
+[\fB\-8\fP] [\fB\-E\fP] [\fB\-F\fP] [\fB\-K\fP] [\fB\-L\fP] [\fB\-S\fP
+\fItos\fP] [\fB\-X\fP \fIauthtype\fP] [\fB\-a\fP] [\fB\-c\fP]
+[\fB\-d\fP] [\fB\-e\fP \fIescapechar\fP] [\fB\-f\fP] [\fB\-k\fP
+\fIrealm\fP] [\fB\-l\fP \fIuser\fP] [\fB\-n\fP \fItracefile\fP]
+[\fB\-r\fP] [\fB\-x\fP] [\fIhost\fP [\fIport\fP]]
+.SH DESCRIPTION
+The 
+.B telnet
+command is used to communicate with another host using the
+.SM TELNET
+protocol.  If
+.B telnet
+is invoked without the
+.I host
+argument, it enters command mode, indicated by its prompt (
+.BR telnet\&> ).
+In this mode, it accepts and executes the commands listed below.  If it
+is invoked with arguments, it performs an
+.B open
+command with those arguments.
+.SH OPTIONS
+.TP
+.B \-8
+Specify an 8-bit data path.  This causes an attempt to negotiate the
+.SM TELNET BINARY
+option on both input and output.
+.TP
+.B \-E
+Stop any character from being recognized as an escape character.
+.TP
+\fB\-F\fP
+forward a
+.I forwardable
+copy of the local credentials to the remote system.
+.TP
+\fB\-K\fP
+Specify no automatic login to the remote system.
+.TP
+.B \-L
+Specify an 8-bit data path on output.  This causes the BINARY option to
+be negotiated on output.
+.TP
+\fB\-S\fP \fItos\fP
+Set the IP type-of-service (TOS) option for the telnet connection to the
+value
+.I tos,
+which can be a numeric TOS value (in decimal, or a hex value preceded
+by 0x, or an octal value preceded by a leading 0) or, on systems that support it, a
+symbolic TOS name found in the /etc/iptos file.
+.TP
+\fB\-X\fP \fIatype\fP
+Disable the
+.I atype
+type of authentication.
+.TP
+\fB\-a\fP
+Attempt automatic login.  This sends the user name via the
+.SM USER
+variable of the
+.SM ENVIRON
+option, if supported by the remote system.  The name used is that of the
+current user as returned by
+.IR getlogin (2)
+if it agrees with the current user ID; otherwise it is the name
+associated with the user ID.
+.TP
+.B \-c
+Disable the reading of the user's
+.B \&.telnetrc
+file.  (See the
+.B toggle skiprc
+command on this man page.)
+.TP
+.B \-d
+Set the initial value of the
+.B debug
+flag to TRUE
+.TP
+\fB\-e\fP \fIescape char\fP
+Set the initial
+.B telnet
+escape character to
+.I escape char.
+If
+.I escape char
+is omitted, then there will be no escape character.
+.TP
+\fB\-f\fP
+forward a copy of the local credentials to the remote system.
+.TP
+\fB\-k\fP \fIrealm\fP
+If Kerberos authentication is being used, request that telnet obtain
+tickets for the remote host in realm
+.I realm
+instead of the remote host's realm, as determined by
+.IR krb_realmofhost (3).
+.TP
+\fB\-l\fP \fIuser\fP
+If the remote system understands the
+.SM ENVIRON
+option, then
+.I user
+will be sent to the remote system as the value for the variable 
+.SM USER.
+This option implies the
+.B \-a
+option.  This option may also be used with the
+.B open
+command.
+.TP
+\fB\-n\fP \fItracefile\fP
+Open
+.I tracefile
+for recording trace information.  See the
+.B set tracefile
+command below.
+.TP
+.B \-r
+Specify a user interface similar to
+.IR rlogin (1).
+In this mode, the escape character is set to the tilde (~) character,
+unless modified by the
+.B \-e
+option.
+.TP
+\fB\-x\fP
+Turn on encryption of the data stream.  When this option is turned on,
+.B telnet
+will exit with an error if authentication cannot be negotiated or if
+encryption cannot be turned on.
+.TP
+.I host
+Indicates the name, alias, or Internet address of the remote host.
+.TP
+.I port
+Indicates a port number (address of an application).  If the port is not
+specified, the default
+.B telnet
+port (23) is used.
+.PP
+When in rlogin mode, ~ is the telnet escape character; a line of the
+form ~. disconnects from the remote host.  Similarly, the line ~^Z
+suspends the telnet session.  The line ~^] escapes to the normal telnet
+escape prompt.
+.PP
+Once a connection has been opened,
+.B telnet
+will attempt to enable the
+.SM TELNET LINEMODE
+option.  If this fails, then
+.B telnet
+will revert to one of two input modes: either ``character at a time'' or
+``old line by line,'' depending on what the remote system supports.
+.PP
+When
+.SM LINEMODE
+is enabled, character processing is done on the local system, under the
+control of the remote system.  When input editing or character echoing
+is to be disabled, the remote system will relay that information.  The
+remote system will also relay changes to any special characters that
+happen on the remote system, so that they can take effect on the local
+system.
+.PP
+In ``character at a time'' mode, most text typed is immediately sent to
+the remote host for processing.
+.PP
+In ``old line by line'' mode, all text is echoed locally, and (normally)
+only completed lines are sent to the remote host.  The ``local echo
+character'' (initially ``^E'') may be used to turn off and on the local
+echo.  (This would mostly be used to enter passwords without the
+password being echoed).
+.PP
+If the LINEMODE option is enabled, or if the
+.B localchars
+flag is TRUE (the default for ``old line by line''; see below), the
+user's
+.BR quit  ,
+.BR intr ,
+and
+.BR flush
+characters are trapped locally, and sent as
+.SM TELNET
+protocol sequences to the remote side.  If
+.SM LINEMODE
+has ever been enabled, then the user's
+.B susp
+and
+.B eof
+are also sent as
+.SM TELNET
+protocol sequences, and
+.B quit
+is sent as a
+.SM TELNET ABORT
+instead of
+.SM BREAK.
+There are options (see
+.B toggle autoflush
+and
+.B toggle autosynch
+below) which cause this action to flush subsequent output to the
+terminal (until the remote host acknowledges the 
+.SM TELNET
+sequence) and flush previous terminal input (in the case of
+.B quit
+and
+.BR intr  ).
+.PP
+While connected to a remote host,
+.B telnet
+command mode may be entered by typing the
+.B telnet
+``escape character'' (initially ``^]'').  When in command mode, the
+normal terminal editing conventions are available.
+.PP
+The following
+.B telnet
+commands are available.  Only enough of each command to uniquely
+identify it need be typed (this is also true for arguments to the
+.BR mode ,
+.BR set ,
+.BR toggle ,
+.BR unset ,
+.BR slc ,
+.BR environ ,
+and
+.B display
+commands).
+.PP
+.TP
+\fBauth\fP \fIargument ...\fP
+The auth command manipulates the information sent through the
+.SM TELNET AUTHENTICATE
+option.  Valid arguments for the auth command are as
+follows:
+.RS
+.TP
+\fBdisable\fP \fItype\fP 
+Disables the specified type of authentication.  To obtain a list of
+available types, use the
+.B auth disable \&?
+command.
+.TP
+\fBenable\fP \fItype\fP
+Enables the specified type of authentication.  To obtain a list of
+available types, use the
+.B auth enable \&?
+command.
+.TP
+.B status
+Lists the current status of the various types of authentication.
+.RE
+.TP
+.B close
+Close a
+.SM TELNET
+session and return to command mode.
+.TP
+\fBdisplay\fP \fIargument ...\fP
+Displays some or all of the
+.B set
+and
+.B toggle
+values (see below).
+.TP
+\fBencrypt\fP \fIargument ...\fP
+The encrypt command manipulates the information sent through the
+.SM TELNET ENCRYPT
+option.
+.PP
+Note:  Because of export controls, the
+.SM TELNET ENCRYPT
+option is not supported outside of the United States and Canada.
+.PP
+Valid arguments for the encrypt command are as follows:
+.RS
+.TP
+\fBdisable\fP \fItype\fP [\fBinput\fP|\fBoutput\fP]
+Disables the specified type of encryption.  If you omit the input and
+output, both input and output are disabled.  To obtain a list of
+available types, use the
+.B encrypt disable \&?
+command.
+.TP
+\fBenable\fP \fItype]fP [\fBinput\fP|\fBoutput\fP]
+Enables the specified type of encryption.  If you omit input and output,
+both input and output are enabled.  To obtain a list of available types,
+use the
+.B encrypt enable \&?
+command.
+.TP
+.B input
+This is the same as the
+.B encrypt start input
+command.
+.TP
+.B \-input
+This is the same as the
+.B encrypt stop input
+command.
+.TP
+.B output
+This is the same as the
+.B encrypt start output
+command.
+.TP
+.B \-output
+This is the same as the
+.B encrypt stop output
+command.
+.TP
+\fBstart\fP [\fBinput\fP|\fBoutput\fP]
+Attempts to start encryption.  If you omit
+.B input
+and
+.BR output ,
+both input and output are enabled.  To obtain a list of available types,
+use the
+.B encrypt enable \&?
+command.
+.TP
+.B status
+Lists the current status of encryption.
+.TP
+\fBstop\fP [\fBinput\fP|\fBoutput\fP]
+Stops encryption.  If you omit input and output, encryption is on both
+input and output.
+.TP
+\fBtype\fP \fItype\fP
+Sets the default type of encryption to be used with later
+.B encrypt start
+or
+.B encrypt stop
+commands.
+.RE
+.TP
+\fBenviron\fP \fIarguments ...\fP
+The
+.B environ
+command is used to manipulate the the variables that my be sent through
+the
+.SM TELNET ENVIRON
+option.  The initial set of variables is taken from the users
+environment, with only the
+.SM DISPLAY
+and
+.SM PRINTER
+variables being exported by default.  The
+.SM USER
+variable is also exported if the
+.B \-a
+or
+.B \-l
+options are used.
+.PP
+Valid arguments for the
+.B environ
+command are:
+.RS
+.TP
+\fBdefine\fP \fIvariable value\fP
+Define the variable
+.I variable
+to have a value of
+.IR value .
+Any variables defined by this command are automatically exported.  The
+.I value
+may be enclosed in single or double quotes so that tabs and spaces may
+be included.
+.TP
+\fBundefine\fP \fIvariable\fP
+Remove
+.I variable
+from the list of environment variables.
+.TP
+\fBexport\fP \fIvariable\fP
+Mark the variable
+.I variable
+to be exported to the remote side.
+.TP
+\fBunexport\fP \fIvariable\fP
+Mark the variable
+.I variable
+to not be exported unless explicitly asked for by the remote side.
+.TP
+.B list
+List the current set of environment variables.  Those marked with a \&*
+will be sent automatically; other variables will only be sent if
+explicitly requested.
+.TP
+.B \&?
+Prints out help information for the
+.B environ
+command.
+.RE
+.TP
+.B logout
+Sends the
+.SM TELNET LOGOUT
+option to the remote side.  This command is similar to a
+.B close
+command; however, if the remote side does not support the
+.SM LOGOUT
+option, nothing happens.  If, however, the remote side does support the
+.SM LOGOUT
+option, this command should cause the remote side to close the
+.SM TELNET
+connection.  If the remote side also supports the concept of suspending
+a user's session for later reattachment, the logout argument indicates
+that you should terminate the session immediately.
+.TP
+\fBmode\fP \fItype\fP
+.I Type
+is one of several options, depending on the state of the
+.SM TELNET
+session.  The remote host is asked for permission to go into the
+requested mode.  If the remote host is capable of entering that mode,
+the requested mode will be entered.
+.RS
+.TP
+.B character
+Disable the
+.SM TELNET LINEMODE
+option, or, if the remote side does not understand the
+.SM LINEMODE
+option, then enter ``character at a time'' mode.
+.TP
+.B line
+Enable the
+.SM TELNET LINEMODE
+option, or, if the remote side does not understand the
+.SM LINEMODE
+option, then attempt to enter ``old-line-by-line'' mode.
+.TP
+\fBisig\fP (\fI\-isig\fP)
+Attempt to enable (disable) the 
+.SM TRAPSIG
+mode of the 
+.SM LINEMODE
+option.  This requires that the
+.SM LINEMODE
+option be enabled.
+.TP
+\fBedit\fP (\fB\-edit\fP)
+Attempt to enable (disable) the
+.SM EDIT
+mode of the 
+.SM LINEMODE
+option.  This requires that the
+.SM LINEMODE
+option be enabled.
+.TP
+\fBsofttabs\fP (\fB\-softtabs\fP)
+Attempt to enable (disable) the
+.SM SOFT_TAB
+mode of the 
+.SM LINEMODE
+option.  This requires that the
+.SM LINEMODE
+option be enabled.
+.TP
+\fBlitecho\fP (\fB\-litecho\fP)
+Attempt to enable (disable) the 
+.SM LIT_ECHO
+mode of the 
+.SM LINEMODE
+option.  This requires that the
+.SM LINEMODE
+option be enabled.
+.TP
+.B \&?
+Prints out help information for the
+.B mode
+command.
+.RE
+.TP
+\fBopen\fP \fIhost\fP [\fB-a\fP] [[\fB\-l\fP] \fIuser\fP] [\fB\-\fP\fIport\fP]
+Open a connection to the named host.  If no port number is specified,
+.B telnet
+will attempt to contact a
+.SM TELNET
+server at the default port.  The host specification may be either a host
+name (see
+.IR hosts (5)
+or an Internet address specified in the ``dot notation'' (see
+.IR inet (3).
+After establishing a connection, the file
+.B \&.telnetrc
+in the user's home directory is opened.  Lines beginning with a # are
+comment lines.  Blank lines are ignored.  Lines that begin without white
+space are the start of a machine entry.  The first thing on the line is
+the name of the machine that is being connected to.  The rest of the
+line, and successive lines that begin with white space are assumed to be
+.B telnet
+commands and are processed as if they had been typed in manually to the
+.B telnet
+command prompt.
+.RS
+.TP
+.B \-a
+Attempt automatic login.  This sends the user name via the
+.SM USER
+variable of the
+.SM ENVIRON
+option, if supported by the remote system.  The name used is that of the
+current user as returned by
+.IR getlogin (2)
+if it agrees with the current user ID; otherwise it is the name
+associated with the user ID.  
+.TP
+[\fB\-l\fP] \fIuser\fP
+may be used to specify the user name to be passed to the remote system
+via the
+.SM ENVIRON
+option.
+.TP
+\fB\-\fP\fIport\fP
+When connecting to a non-standard port,
+.B telnet
+omits any automatic initiation of
+.SM TELNET
+options.  When the port number is preceded by a minus sign, the initial
+option negotiation is done.
+.RE
+.TP
+.B quit
+Close any open
+.SM TELNET
+session and exit
+.BR telnet .
+An end of file (in command mode) will also close a session and exit.
+.TP
+\fBsend\fP \fIarguments\fP
+Sends one or more special character sequences to the remote host.  The
+following are the arguments which may be specified (more than one
+argument may be specified at a time):
+.PP
+.RS
+.TP
+.B abort
+Sends the
+.SM TELNET ABORT
+(Abort processes) sequence.
+.TP
+.B ao
+Sends the
+.SM TELNET AO
+(Abort Output) sequence, which should cause the remote system to flush
+all output
+.I from
+the remote system
+.I to
+the user's terminal.
+.TP
+.B ayt
+Sends the
+.SM TELNET AYT
+(Are You There) sequence, to which the remote system may or may not
+choose to respond.
+.TP
+.B brk
+Sends the
+.SM TELNET BRK
+(Break) sequence, which may have significance to the remote system.
+.TP
+.B ec
+Sends the
+.SM TELNET EC
+(Erase Character) sequence, which should cause the remote system to
+erase the last character entered.
+.TP
+.B el
+Sends the
+.SM TELNET EL
+(Erase Line) sequence, which should cause the remote system to erase the
+line currently being entered.
+.TP
+.B eof
+Sends the
+.SM TELNET EOF
+(End Of File) sequence.
+.TP
+.B eor
+Sends the
+.SM TELNET EOR
+(End of Record) sequence.
+.TP
+.B escape
+Sends the current
+.b telnet
+escape character (initially ``^''.
+.TP
+.B ga
+Sends the
+.SM TELNET GA
+(Go Ahead) sequence, which likely has no significance to the remote
+system.
+.TP
+.B getstatus
+If the remote side supports the
+.SM TELNET STATUS
+command,
+.B getstatus
+will send the subnegotiation to request that the server send its current
+option status.
+.TP
+.B ip
+Sends the
+.SM TELNET IP
+(Interrupt Process) sequence, which should cause the remote system to
+abort the currently running process.
+.TP
+.B nop
+Sends the
+.SM TELNET NOP
+(No OPeration) sequence.
+.TP
+.B susp
+Sends the
+.SM TELNET SUSP
+(SUSPend process) sequence.
+.TP
+.B synch
+Sends the
+.SM TELNET SYNCH
+sequence.  This sequence causes the remote system to discard all
+previously typed (but not yet read) input.  This sequence is sent as
+.SM TCP
+urgent data (and may not work if the remote system is a 4.2BSD system --
+if it doesn't work, a lower case ``r'' may be echoed on the terminal).
+.TP
+\fBdo\fP \fIcmd\fP
+.TP
+\fBdont\fP \fIcmd\fP
+.TP
+\fBwill\fP \fIcmd\fP
+.TP
+\fBwont\fP \fIcmd\fP
+Sends the
+.SM TELNET DO
+.I cmd
+sequence.
+.I Cmd
+can be either a decimal number between 0 and 255, or a symbolic name for
+a specific
+.SM TELNET
+command.
+.I Cmd
+can also be either
+.B help
+or
+.B \&?
+to print out help information, including a list of known symbolic names.
+.TP
+.B \&?
+Prints out help information for the
+.B send
+command.
+.RE
+.TP
+\fBset\fP \fIargument value\fP 
+.TP
+\fBunset\fP \fIargument value\fP
+The
+.B set
+command will set any one of a number of
+.B telnet
+variables to a specific value or to
+.SM TRUE.
+The special value
+.B off
+turns off the function associated with the variable; this is equivalent
+to using the
+.B unset
+command.  The
+.B unset
+command will disable or set to
+.SM FALSE
+any of the specified functions.  The values of variables may be
+interrogated with the
+.B display
+command.  The variables which may be set or unset, but not toggled, are
+listed here.  In addition, any of the variables for the
+.B toggle
+command may be explicitly set or unset using the
+.B set
+and
+.B unset
+commands.
+.RS
+.TP
+.B ayt
+If
+.B telnet
+is in localchars mode, or
+.SM LINEMODE
+is enabled, and the status character is typed, a
+.SM TELNET AYT
+sequence (see
+.B send ayt
+preceding) is sent to the remote host.  The initial value for the "Are
+You There" character is the terminal's status character.
+.TP
+.B echo
+This is the value (initially ``^E'') which, when in ``line by line''
+mode, toggles between doing local echoing of entered characters (for
+normal processing), and suppressing echoing of entered characters (for
+entering, say, a password).
+.TP
+.B eof
+If
+.B telnet
+is operating in
+.SM LINEMODE
+or ``old line by line'' mode, entering this character as the first
+character on a line will cause this character to be sent to the remote
+system.  The initial value of the eof character is taken to be the
+terminal's
+.B eof
+character.
+.TP
+.B erase
+If
+.B telnet
+is in
+.b localchars
+mode (see
+.B toggle localchars
+below),
+.I and
+if
+.B telnet
+is operating in ``character at a time'' mode, then when this character
+is typed, a
+.SM TELNET EC
+sequence (see
+.B send ec
+above) is sent to the remote system.  The initial value for the erase
+character is taken to be the terminal's
+.B erase
+character.
+.TP
+.B escape
+This is the
+.B telnet
+escape character (initially ``^['') which causes entry into
+.B telnet
+command mode (when connected to a remote system).
+.TP
+.B flushoutput
+If
+.B telnet
+is in
+.B localchars
+mode (see
+.B toggle localchars
+below) and the
+.B flushoutput
+character is typed, a
+.SM TELNET AO
+sequence (see
+.B send ao
+above) is sent to the remote host.  The initial value for the flush
+character is taken to be the terminal's
+.B flush
+character.
+.TP
+.B forw1
+.TP
+.B forw2
+If
+.B telnet
+is operating in
+.SM LINEMODE,
+these are the characters that, when typed, cause partial lines to be
+forwarded to the remote system.  The initial value for the forwarding
+characters are taken from the terminal's eol and eol2 characters.
+.TP
+.B interrupt
+If
+.B telnet
+is in
+.B localchars
+mode (see
+.B toggle localchars
+below) and the
+.B interrupt
+character is typed, a
+.SM TELNET IP
+sequence (see
+.B send ip
+above) is sent to the remote host.  The initial value for the interrupt
+character is taken to be the terminal's
+.B intr
+character.
+.TP
+.B kill
+If
+.B telnet
+is in
+.B localchars
+mode (see
+.B toggle localchars
+below),
+.I and
+if
+.B telnet
+is operating in ``character at a time'' mode, then when this character
+is typed, a
+.SM TELNET EL
+sequence (see
+.B send el
+above) is sent to the remote system.  The initial value for the kill
+character is taken to be the terminal's
+.B kill
+character.
+.TP
+.B lnext
+If
+.B telnet
+is operating in
+.SM LINEMODE
+or ``old line by line'' mode, then this character is taken to be the
+terminal's
+.B lnext
+character.  The initial value for the lnext character is taken to be the
+terminal's
+.B lnext
+character.
+.TP
+.B quit
+If
+.B telnet
+is in
+.B localchars
+mode (see
+.B toggle localchars
+below) and the
+.B quit
+character is typed, a
+.SM TELNET BRK
+sequence (see
+.B send brk
+above) is sent to the remote host.  The initial value for the quit
+character is taken to be the terminal's
+.B quit
+character.
+.TP
+.B reprint
+If
+.B telnet
+is operating in
+.SM LINEMODE
+or ``old line by line'' mode, then this character is taken to be the
+terminal's
+.B reprint
+character.  The initial value for the reprint character is taken to be
+the terminal's
+.B reprint
+character.
+.TP
+.B rlogin
+This is the rlogin escape character.  If set, the normal
+.B TELNET
+escape character is ignored unless it is preceded by this character at
+the beginning of a line.  This character, at the beginning of a line
+followed by a "."  closes the connection; when followed by a ^Z it
+suspends the telnet command.  The initial state is to disable the rlogin
+escape character.
+.TP
+.B start
+If the
+.SM TELNET TOGGLE-FLOW-CONTROL
+option has been enabled, then this character is taken to be the
+terminal's
+.B start
+character.  The initial value for the kill character is taken to be the
+terminal's
+.B start
+character.
+.TP
+.B stop
+If the
+.SM TELNET TOGGLE-FLOW-CONTROL
+option has been enabled, then this character is taken to be the
+terminal's
+.B stop
+character.  The initial value for the kill character is taken to be the
+terminal's
+.B stop
+character.
+.TP
+.B susp
+If
+.B telnet
+is in
+.B localchars
+mode, or
+.SM LINEMODE
+is enabled, and the
+.B suspend
+character is typed, a
+.SM TELNET SUSP
+sequence (see
+.B send susp
+above) is sent to the remote host.  The initial value for the suspend
+character is taken to be the terminal's
+.B suspend
+character.
+.TP
+.B tracefile
+This is the file to which the output, caused by
+.B netdata
+or
+.B option
+tracing being
+.SM TRUE,
+will be written.  If it is set to ``\fB\-\fP'', then tracing information
+will be written to standard output (the default).
+.TP
+.B worderase
+If
+.B telnet
+is operating in
+.SM LINEMODE
+or ``old line by line'' mode, then this character is taken to be the
+terminal's
+.B worderase
+character.  The initial value for the worderase character is taken to be
+the terminal's
+.B worderase
+character.
+.TP
+.B \&?
+Displays the legal \fBset\fP (\fBunset\fP) commands.
+.RE
+.TP
+\fBslc\fP \fIstate\fP
+The
+.B slc
+command (Set Local Characters) is used to set or change the state of the
+the special characters when the
+.SM TELNET LINEMODE
+option has been enabled.  Special characters are characters that get
+mapped to
+.B telnet
+commands sequences (like
+.B ip
+or
+.B quit  )
+or line editing characters (like
+.B erase
+and
+.BR kill ).
+By default, the local special characters are exported.
+.RS
+.TP
+.B check
+Verify the current settings for the current special characters.  The
+remote side is requested to send all the current special character
+settings, and if there are any discrepancies with the local side, the
+local side will switch to the remote value.
+.TP
+.B export
+Switch to the local defaults for the special characters.  The local
+default characters are those of the local terminal at the time when
+.B telnet
+was started.
+.TP
+.B import
+Switch to the remote defaults for the special characters.  The remote
+default characters are those of the remote system at the time when the
+.SM TELNET
+connection was established.
+.TP
+.B \&?
+Prints out help information for the
+.B slc
+command.
+.RE
+.TP
+.B status
+Show the current status of
+.BR telnet  .
+This includes the peer one is connected to, as well as the current mode.
+.TP
+\fBtoggle\fP \fIarguments ...\fP
+Toggle (between
+.SM TRUE
+and
+.SM FALSE)
+various flags that control how
+.B telnet
+responds to events.  These flags may be set explicitly to
+.SM TRUE
+or
+.SM FALSE
+using the
+.B set
+and
+.B unset
+commands listed above.  More than one argument may be specified.  The
+state of these flags may be interrogated with the
+.B display
+command.  Valid arguments are:
+.RS
+.TP
+.B authdebug
+Turns on debugging information for the authentication code.
+.TP
+.B autoflush
+If
+.B autoflush
+and
+.B localchars
+are both
+.SM TRUE ,
+then when the
+.BR ao  ,
+or
+.B quit
+characters are recognized (and transformed into
+.SM TELNET
+sequences; see
+.B set
+above for details),
+.B telnet
+refuses to display any data on the user's terminal until the remote
+system acknowledges (via a
+.SM TELNET TIMING MARK
+option) that it has processed those
+.SM TELNET
+sequences.  The initial value for this toggle is
+.SM TRUE
+if the terminal user had not done an "stty noflsh", otherwise
+.SM FALSE
+(see
+.BR stty  (1).
+.TP
+.B autodecrypt
+When the
+.SM TELNET ENCRYPT
+option is negotiated, by default the actual encryption (decryption) of
+the data stream does not start automatically.  The autoencrypt
+(autodecrypt) command states that encryption of the output (input)
+stream should be enabled as soon as possible.
+.PP
+Note:  Because of export controls, the
+.SM TELNET ENCRYPT
+option is not supported outside the United States and Canada.
+.TP
+.B autologin
+If the remote side supports the
+.SM TELNET AUTHENTICATION
+option
+.B telnet
+attempts to use it to perform automatic authentication.  If the
+.SM AUTHENTICATION
+option is not supported, the user's login name are propagated through
+the
+.SM TELNET ENVIRON
+option.  This command is the same as specifying the
+.B \-a
+option on the
+.B open
+command.
+.TP
+.B autosynch
+If
+.B autosynch
+and
+.B localchars
+are both
+.SM TRUE,
+then when either the
+.B intr
+or
+.B quit
+characters is typed (see
+.B set
+above for descriptions of the
+.B intr
+and
+.B quit
+characters), the resulting
+.SM TELNET
+sequence sent is followed by the
+.SM TELNET SYNCH
+sequence.  This procedure
+.I should
+cause the remote system to begin throwing away all previously typed
+input until both of the
+.SM TELNET
+sequences have been read and acted upon.  The initial value of this
+toggle is
+.SM FALSE.
+.TP
+.B binary
+Enable or disable the
+.SM TELNET BINARY
+option on both input and output.
+.TP
+.B inbinary
+Enable or disable the
+.SM TELNET BINARY
+option on input.
+.TP
+.B outbinary
+Enable or disable the
+.SM TELNET BINARY
+option on output.
+.TP
+.B crlf
+If this is
+.SM TRUE,
+then carriage returns will be sent as <CR><LF>.  If this is
+.SM FALSE,
+then carriage returns will be send as <CR><NUL>.  The initial value for
+this toggle is
+.SM FALSE.
+.TP
+.B crmod
+Toggle carriage return mode.  When this mode is enabled, most carriage
+return characters received from the remote host will be mapped into a
+carriage return followed by a line feed.  This mode does not affect
+those characters typed by the user, only those received from the remote
+host.  This mode is not very useful unless the remote host only sends
+carriage return, but never line feed.  The initial value for this toggle
+is
+.SM FALSE .
+.TP
+.B debug
+Toggles socket level debugging (useful only to the \fBsuper user\fP).
+The initial value for this toggle is
+.SM FALSE .
+.TP
+.B encdebug
+Turns on debugging information for the encryption code.
+.TP
+.B localchars
+If this is
+.SM TRUE ,
+then the
+.BR flush ,
+.BR interrupt ,
+.BR quit ,
+.BR erase ,
+and
+.B kill
+characters (see
+.B set
+above) are recognized locally, and transformed into (hopefully)
+appropriate
+.SM TELNET
+control sequences (respectively
+.BR ao ,
+.BR ip ,
+.BR brk ,
+.BR ec ,
+and
+.BR el ;
+see
+.B send
+above).  The initial value for this toggle is
+.SM TRUE
+in ``old line by line'' mode, and
+.SM FALSE
+in ``character at a time'' mode.  When the
+.SM LINEMODE
+option is enabled, the value of
+.B localchars
+is ignored, and assumed to always be
+.SM TRUE.
+If
+.SM LINEMODE
+has ever been enabled, then
+.B quit
+is sent as
+.BR abort ,
+and
+.B eof
+and
+.B suspend
+are sent as
+.B eof
+and
+.BR susp ,
+see
+.B send
+above).
+.TP
+.B netdata
+Toggles the display of all network data (in hexadecimal format).  The
+initial value for this toggle is
+.SM FALSE.
+.TP
+.B options
+Toggles the display of some internal
+.B telnet
+protocol processing (having to do with
+.SM TELNET
+options).  The initial value for this flag is
+.SM FALSE .
+.TP
+.B prettydump
+When the
+.B netdata
+flag is enabled, if
+.B prettydump
+is enabled the output from the
+.B netdata
+command will be formatted in a more user-readable format.  Spaces are
+put between each character in the output, and the beginning of any
+.SM TELNET
+escape sequence is preceded by a '*' to aid in locating them.
+.TP
+.B skiprc
+When the skiprc flag is
+.SM TRUE,
+.SM TELNET
+skips the reading of the \&.telnetrc file in the user's home directory
+when connections are opened.  The initial value for this flag is
+.SM FALSE.
+.TP
+.B termdata
+Toggles the display of all terminal data (in hexadecimal format).  The
+initial value for this flag is
+.SM FALSE.
+.TP
+.B verbose_encrypt
+When the
+.B verbose_encrypt
+flag is
+.SM TRUE,
+.SM TELNET
+prints out a message each time encryption is enabled or disabled.  The
+initial value for this toggle is
+.SM FALSE.
+Note:  Because of export controls, data encryption is not supported
+outside of the United States and Canada.
+.TP
+.B \&?
+Displays the legal
+.B toggle
+commands.
+.RE
+.TP
+.B z
+Suspend
+.BR telnet .
+This command only works when the user's shell is
+.IR csh (1).
+.TP
+\fB\&!\fP [\fIcommand\fP]
+Execute a single command in a subshell on the local system.  If
+.B command
+is omitted, then an interactive subshell is invoked.
+.TP
+\fB\&?\fP \fIcommand\fP
+Get help.  With no arguments,
+.b telnet
+prints a help summary.  If a command is specified,
+.b telnet
+will print the help information for just that command.
+.SH ENVIRONMENT
+.B Telnet
+uses at least the
+.SM HOME,
+.SM SHELL,
+.SM DISPLAY,
+and
+.SM TERM
+environment variables.  Other environment variables may be propagated to
+the other side via the
+.SM TELNET ENVIRON
+option.
+.SH FILES
+.TP "\w'~/.telnetrc\ \ 'u"
+.TP
+~/.telnetrc
+user-customized telnet startup values
+.sp -1v
+.TP
+~/.k5login
+(on remote host) - file containing Kerberos principals that are allowed
+access.
+.SH HISTORY
+The
+.B Telnet
+command appeared in 4.2BSD.
+.SH NOTES
+.PP
+On some remote systems, echo has to be turned off manually when in ``old
+line by line'' mode.
+.PP
+In ``old line by line'' mode or
+.SM LINEMODE
+the terminal's
+.B eof
+character is only recognized (and sent to the remote system) when it is
+the first character on a line.
diff --git a/mechglue/src/appl/telnet/telnet/telnet.c b/mechglue/src/appl/telnet/telnet/telnet.c
new file mode 100644
index 000000000..6215fc1e9
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/telnet.c
@@ -0,0 +1,2756 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)telnet.c	8.1 (Berkeley) 6/6/93 */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <time.h>
+
+#if	defined(unix)
+#include <signal.h>
+/* By the way, we need to include curses.h before telnet.h since,
+ * among other things, telnet.h #defines 'DO', which is a variable
+ * declared in curses.h.
+ */
+#endif	/* defined(unix) */
+
+#ifdef HAVE_CURSES_H
+#include <curses.h>
+#endif
+
+#ifdef HAVE_TERM_H
+#include <term.h>
+#endif
+
+#include <arpa/telnet.h>
+
+#include <ctype.h>
+
+#include "ring.h"
+
+#include "defines.h"
+#include "externs.h"
+#include "types.h"
+#include "general.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION) 
+#include <libtelnet/misc-proto.h>
+#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
+
+static int is_unique (char *, char **, char **);
+
+
+#define	strip(x)	((x)&0x7f)
+
+static unsigned char	subbuffer[SUBBUFSIZE],
+			*subpointer, *subend;	 /* buffer for sub-options */
+#define	SB_CLEAR()	subpointer = subbuffer;
+#define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
+#define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
+				*subpointer++ = (c); \
+			}
+
+#define	SB_GET()	((*subpointer++)&0xff)
+#define	SB_PEEK()	((*subpointer)&0xff)
+#define	SB_EOF()	(subpointer >= subend)
+#define	SB_LEN()	(subend - subpointer)
+
+char	options[256];		/* The combined options */
+char	do_dont_resp[256];
+char	will_wont_resp[256];
+
+int
+	eight = 0,
+	autologin = 0,	/* Autologin anyone? */
+	skiprc = 0,
+	connected,
+	showoptions,
+	In3270,		/* Are we in 3270 mode? */
+	ISend,		/* trying to send network data in */
+	debug = 0,
+	crmod,
+	netdata,	/* Print out network data flow */
+	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
+#if	defined(TN3270)
+	noasynchtty = 0,/* User specified "-noasynch" on command line */
+	noasynchnet = 0,/* User specified "-noasynch" on command line */
+	askedSGA = 0,	/* We have talked about suppress go ahead */
+#endif	/* defined(TN3270) */
+	telnetport,
+        wantencryption = 0,
+	SYNCHing,	/* we are in TELNET SYNCH mode */
+	flushout,	/* flush output */
+	autoflush = 0,	/* flush output when interrupting? */
+	autosynch,	/* send interrupt characters with SYNCH? */
+	localflow,	/* we handle flow control locally */
+	restartany,	/* if flow control enabled, restart on any character */
+	localchars,	/* we recognize interrupt/quit */
+	donelclchars,	/* the user has set "localchars" */
+	donebinarytoggle,	/* the user has put us in binary */
+	dontlecho,	/* do we suppress local echoing right now? */
+	globalmode;
+
+char *prompt = 0;
+
+int scheduler_lockout_tty = 0;
+
+cc_t escape;
+cc_t rlogin;
+#ifdef	KLUDGELINEMODE
+cc_t echoc;
+#endif
+
+/*
+ * Telnet receiver states for fsm
+ */
+#define	TS_DATA		0
+#define	TS_IAC		1
+#define	TS_WILL		2
+#define	TS_WONT		3
+#define	TS_DO		4
+#define	TS_DONT		5
+#define	TS_CR		6
+#define	TS_SB		7		/* sub-option collection */
+#define	TS_SE		8		/* looking for sub-option end */
+
+static int	telrcv_state;
+#ifdef	OLD_ENVIRON
+unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
+#else
+# define telopt_environ TELOPT_NEW_ENVIRON
+#endif
+
+jmp_buf	toplevel = { 0 };
+jmp_buf	peerdied;
+
+int	flushline;
+int	linemode;
+
+#ifdef	KLUDGELINEMODE
+int	kludgelinemode = 1;
+#endif
+
+/*
+ * The following are some clocks used to decide how to interpret
+ * the relationship between various variables.
+ */
+
+Clocks clocks;
+
+#ifdef	notdef
+Modelist modelist[] = {
+	{ "telnet command mode", COMMAND_LINE },
+	{ "character-at-a-time mode", 0 },
+	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
+	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
+	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
+	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
+	{ "3270 mode", 0 },
+};
+#endif
+
+
+/*
+ * Initialize telnet environment.
+ */
+
+    void
+init_telnet()
+{
+    env_init();
+
+    SB_CLEAR();
+    ClearArray(options);
+
+    connected = In3270 = ISend = localflow = donebinarytoggle = 0;
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION) 
+    auth_encrypt_connect(connected);
+#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
+    restartany = -1;
+
+    SYNCHing = 0;
+
+    /* Don't change NetTrace */
+
+    escape = CONTROL(']');
+    rlogin = _POSIX_VDISABLE;
+#ifdef	KLUDGELINEMODE
+    echoc = CONTROL('E');
+#endif
+
+    flushline = 1;
+    telrcv_state = TS_DATA;
+}
+
+
+#ifdef	notdef
+#include <varargs.h>
+
+    /*VARARGS*/
+    static void
+printring(va_alist)
+    va_dcl
+{
+    va_list ap;
+    char buffer[100];		/* where things go */
+    char *ptr;
+    char *format;
+    char *string;
+    Ring *ring;
+    int i;
+
+    va_start(ap);
+
+    ring = va_arg(ap, Ring *);
+    format = va_arg(ap, char *);
+    ptr = buffer;
+
+    while ((i = *format++) != 0) {
+	if (i == '%') {
+	    i = *format++;
+	    switch (i) {
+	    case 'c':
+		*ptr++ = va_arg(ap, int);
+		break;
+	    case 's':
+		string = va_arg(ap, char *);
+		ring_supply_data(ring, buffer, ptr-buffer);
+		ring_supply_data(ring, string, strlen(string));
+		ptr = buffer;
+		break;
+	    case 0:
+		ExitString("printring: trailing %%.\n", 1);
+		/*NOTREACHED*/
+	    default:
+		ExitString("printring: unknown format character.\n", 1);
+		/*NOTREACHED*/
+	    }
+	} else {
+	    *ptr++ = i;
+	}
+    }
+    ring_supply_data(ring, buffer, ptr-buffer);
+}
+#endif
+
+/*
+ * These routines are in charge of sending option negotiations
+ * to the other side.
+ *
+ * The basic idea is that we send the negotiation if either side
+ * is in disagreement as to what the current state should be.
+ */
+
+    void
+send_do(c, init)
+    register int c, init;
+{
+    if (init) {
+	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
+				my_want_state_is_do(c))
+	    return;
+	set_my_want_state_do(c);
+	do_dont_resp[c]++;
+    }
+    NET2ADD(IAC, DO);
+    NETADD(c);
+    printoption("SENT", DO, c);
+}
+
+    void
+send_dont(c, init)
+    register int c, init;
+{
+    if (init) {
+	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
+				my_want_state_is_dont(c))
+	    return;
+	set_my_want_state_dont(c);
+	do_dont_resp[c]++;
+    }
+    NET2ADD(IAC, DONT);
+    NETADD(c);
+    printoption("SENT", DONT, c);
+}
+
+    void
+send_will(c, init)
+    register int c, init;
+{
+    if (init) {
+	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
+				my_want_state_is_will(c))
+	    return;
+	set_my_want_state_will(c);
+	will_wont_resp[c]++;
+    }
+    NET2ADD(IAC, WILL);
+    NETADD(c);
+    printoption("SENT", WILL, c);
+}
+
+    void
+send_wont(c, init)
+    register int c, init;
+{
+    if (init) {
+	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
+				my_want_state_is_wont(c))
+	    return;
+	set_my_want_state_wont(c);
+	will_wont_resp[c]++;
+    }
+    NET2ADD(IAC, WONT);
+    NETADD(c);
+    printoption("SENT", WONT, c);
+}
+
+
+	void
+willoption(option)
+	int option;
+{
+	int new_state_ok = 0;
+
+	if (do_dont_resp[option]) {
+	    --do_dont_resp[option];
+	    if (do_dont_resp[option] && my_state_is_do(option))
+		--do_dont_resp[option];
+	}
+
+	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
+
+	    switch (option) {
+
+	    case TELOPT_ECHO:
+#	    if defined(TN3270)
+		/*
+		 * The following is a pain in the rear-end.
+		 * Various IBM servers (some versions of Wiscnet,
+		 * possibly Fibronics/Spartacus, and who knows who
+		 * else) will NOT allow us to send "DO SGA" too early
+		 * in the setup proceedings.  On the other hand,
+		 * 4.2 servers (telnetd) won't set SGA correctly.
+		 * So, we are stuck.  Empirically (but, based on
+		 * a VERY small sample), the IBM servers don't send
+		 * out anything about ECHO, so we postpone our sending
+		 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
+		 * DO send).
+		  */
+		{
+		    if (askedSGA == 0) {
+			askedSGA = 1;
+			if (my_want_state_is_dont(TELOPT_SGA))
+			    send_do(TELOPT_SGA, 1);
+		    }
+		}
+		    /* Fall through */
+	    case TELOPT_EOR:
+#endif	    /* defined(TN3270) */
+	    case TELOPT_BINARY:
+	    case TELOPT_SGA:
+		settimer(modenegotiated);
+		/* FALL THROUGH */
+	    case TELOPT_STATUS:
+#if	defined(AUTHENTICATION)
+	    case TELOPT_AUTHENTICATION:
+#endif
+#ifdef	ENCRYPTION
+	    case TELOPT_ENCRYPT:
+#endif /* ENCRYPTION */
+		new_state_ok = 1;
+		break;
+
+	    case TELOPT_TM:
+		if (flushout)
+		    flushout = 0;
+		/*
+		 * Special case for TM.  If we get back a WILL,
+		 * pretend we got back a WONT.
+		 */
+		set_my_want_state_dont(option);
+		set_my_state_dont(option);
+		return;			/* Never reply to TM will's/wont's */
+
+	    case TELOPT_LINEMODE:
+	    default:
+		break;
+	    }
+
+	    if (new_state_ok) {
+		set_my_want_state_do(option);
+		send_do(option, 0);
+		setconnmode(0);		/* possibly set new tty mode */
+	    } else {
+		do_dont_resp[option]++;
+		send_dont(option, 0);
+	    }
+	}
+	set_my_state_do(option);
+#ifdef	ENCRYPTION
+	if (option == TELOPT_ENCRYPT)
+		encrypt_send_support();
+#endif	/* ENCRYPTION */
+}
+
+	void
+wontoption(option)
+	int option;
+{
+	if (do_dont_resp[option]) {
+	    --do_dont_resp[option];
+	    if (do_dont_resp[option] && my_state_is_dont(option))
+		--do_dont_resp[option];
+	}
+
+	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
+
+	    switch (option) {
+
+#ifdef	KLUDGELINEMODE
+	    case TELOPT_SGA:
+		if (!kludgelinemode)
+		    break;
+		/* FALL THROUGH */
+#endif
+	    case TELOPT_ECHO:
+		settimer(modenegotiated);
+		break;
+
+	    case TELOPT_TM:
+		if (flushout)
+		    flushout = 0;
+		set_my_want_state_dont(option);
+		set_my_state_dont(option);
+		return;		/* Never reply to TM will's/wont's */
+
+	    default:
+		break;
+	    }
+	    set_my_want_state_dont(option);
+	    if (my_state_is_do(option))
+		send_dont(option, 0);
+	    setconnmode(0);			/* Set new tty mode */
+	} else if (option == TELOPT_TM) {
+	    /*
+	     * Special case for TM.
+	     */
+	    if (flushout)
+		flushout = 0;
+	    set_my_want_state_dont(option);
+	}
+	set_my_state_dont(option);
+}
+
+	static void
+dooption(option)
+	int option;
+{
+	int new_state_ok = 0;
+
+	if (will_wont_resp[option]) {
+	    --will_wont_resp[option];
+	    if (will_wont_resp[option] && my_state_is_will(option))
+		--will_wont_resp[option];
+	}
+
+	if (will_wont_resp[option] == 0) {
+	  if (my_want_state_is_wont(option)) {
+
+	    switch (option) {
+
+	    case TELOPT_TM:
+		/*
+		 * Special case for TM.  We send a WILL, but pretend
+		 * we sent WONT.
+		 */
+		send_will(option, 0);
+		set_my_want_state_wont(TELOPT_TM);
+		set_my_state_wont(TELOPT_TM);
+		return;
+
+#	if defined(TN3270)
+	    case TELOPT_EOR:		/* end of record */
+#	endif	/* defined(TN3270) */
+	    case TELOPT_BINARY:		/* binary mode */
+	    case TELOPT_NAWS:		/* window size */
+	    case TELOPT_TSPEED:		/* terminal speed */
+	    case TELOPT_LFLOW:		/* local flow control */
+	    case TELOPT_TTYPE:		/* terminal type option */
+	    case TELOPT_SGA:		/* no big deal */
+#ifdef	ENCRYPTION
+	    case TELOPT_ENCRYPT:	/* encryption variable option */
+#endif	/* ENCRYPTION */
+		new_state_ok = 1;
+		break;
+
+	    case TELOPT_NEW_ENVIRON:	/* New environment variable option */
+#ifdef	OLD_ENVIRON
+		if (my_state_is_will(TELOPT_OLD_ENVIRON))
+			send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
+		goto env_common;
+	    case TELOPT_OLD_ENVIRON:	/* Old environment variable option */
+		if (my_state_is_will(TELOPT_NEW_ENVIRON))
+			break;		/* Don't enable if new one is in use! */
+	    env_common:
+		telopt_environ = option;
+#endif
+		new_state_ok = 1;
+		break;
+
+#if	defined(AUTHENTICATION)
+	    case TELOPT_AUTHENTICATION:
+		if (autologin)
+			new_state_ok = 1;
+		break;
+#endif
+
+	    case TELOPT_XDISPLOC:	/* X Display location */
+		if (env_getvalue((unsigned char *)"DISPLAY") &&
+		    env_is_exported((unsigned char *)"DISPLAY"))
+		    new_state_ok = 1;
+		break;
+
+	    case TELOPT_LINEMODE:
+#ifdef	KLUDGELINEMODE
+		kludgelinemode = 0;
+		send_do(TELOPT_SGA, 1);
+#endif
+		set_my_want_state_will(TELOPT_LINEMODE);
+		send_will(option, 0);
+		set_my_state_will(TELOPT_LINEMODE);
+		slc_init();
+		return;
+
+	    case TELOPT_ECHO:		/* We're never going to echo... */
+	    default:
+		break;
+	    }
+
+	    if (new_state_ok) {
+		set_my_want_state_will(option);
+		send_will(option, 0);
+		setconnmode(0);			/* Set new tty mode */
+	    } else {
+		will_wont_resp[option]++;
+		send_wont(option, 0);
+	    }
+	  } else {
+	    /*
+	     * Handle options that need more things done after the
+	     * other side has acknowledged the option.
+	     */
+	    switch (option) {
+	    case TELOPT_LINEMODE:
+#ifdef	KLUDGELINEMODE
+		kludgelinemode = 0;
+		send_do(TELOPT_SGA, 1);
+#endif
+		set_my_state_will(option);
+		slc_init();
+		send_do(TELOPT_SGA, 0);
+		return;
+	    }
+	  }
+	}
+	set_my_state_will(option);
+}
+
+	static void
+dontoption(option)
+	int option;
+{
+
+	if (will_wont_resp[option]) {
+	    --will_wont_resp[option];
+	    if (will_wont_resp[option] && my_state_is_wont(option))
+		--will_wont_resp[option];
+	}
+
+	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
+	    switch (option) {
+	    case TELOPT_LINEMODE:
+		linemode = 0;	/* put us back to the default state */
+		break;
+#ifdef	OLD_ENVIRON
+	    case TELOPT_NEW_ENVIRON:
+		/*
+		 * The new environ option wasn't recognized, try
+		 * the old one.
+		 */
+		send_will(TELOPT_OLD_ENVIRON, 1);
+		telopt_environ = TELOPT_OLD_ENVIRON;
+		break;
+#endif
+	    }
+	    /* we always accept a DONT */
+	    set_my_want_state_wont(option);
+	    if (my_state_is_will(option))
+		send_wont(option, 0);
+	    setconnmode(0);			/* Set new tty mode */
+	}
+	set_my_state_wont(option);
+}
+
+/*
+ * Given a buffer returned by tgetent(), this routine will turn
+ * the pipe seperated list of names in the buffer into an array
+ * of pointers to null terminated names.  We toss out any bad,
+ * duplicate, or verbose names (names with spaces).
+ */
+
+static char *name_unknown = "UNKNOWN";
+static char *unknown[] = { 0, 0 };
+
+static	char **
+mklist(buf, name)
+	char *buf, *name;
+{
+	register int n;
+	register char c, *cp, **argvp, *cp2, **argv, **avt;
+
+	if (name) {
+		if (strlen(name) > 40) {
+			name = 0;
+			unknown[0] = name_unknown;
+		} else {
+			unknown[0] = name;
+			upcase(name);
+		}
+	} else
+		unknown[0] = name_unknown;
+	/*
+	 * Count up the number of names.
+	 */
+	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
+		if (*cp == '|')
+			n++;
+	}
+	/*
+	 * Allocate an array to put the name pointers into
+	 */
+	argv = (char **)malloc((n+3)*sizeof(char *));
+	if (argv == 0)
+		return(unknown);
+
+	/*
+	 * Fill up the array of pointers to names.
+	 */
+	*argv = 0;
+	argvp = argv+1;
+	n = 0;
+	for (cp = cp2 = buf; (c = *cp);  cp++) {
+		if (c == '|' || c == ':') {
+			*cp++ = '\0';
+			/*
+			 * Skip entries that have spaces or are over 40
+			 * characters long.  If this is our environment
+			 * name, then put it up front.  Otherwise, as
+			 * long as this is not a duplicate name (case
+			 * insensitive) add it to the list.
+			 */
+			if (n || (cp - cp2 > 41))
+				;
+			else if (name && (strncasecmp(name, cp2, 
+						      (unsigned) (cp-cp2)) 
+					  == 0))
+				*argv = cp2;
+			else if (is_unique(cp2, argv+1, argvp))
+				*argvp++ = cp2;
+			if (c == ':')
+				break;
+			/*
+			 * Skip multiple delimiters. Reset cp2 to
+			 * the beginning of the next name. Reset n,
+			 * the flag for names with spaces.
+			 */
+			while ((c = *cp) == '|')
+				cp++;
+			cp2 = cp;
+			n = 0;
+		}
+		/*
+		 * Skip entries with spaces or non-ascii values.
+		 * Convert lower case letters to upper case.
+		 */
+		if ((c == ' ') || !isascii(c))
+			n = 1;
+		else if (islower((int) c))
+			*cp = toupper((int) c);
+	}
+	
+	/*
+	 * Check for an old V6 2 character name.  If the second
+	 * name points to the beginning of the buffer, and is
+	 * only 2 characters long, move it to the end of the array.
+	 */
+	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
+		--argvp;
+		for (avt = &argv[1]; avt < argvp; avt++)
+			*avt = *(avt+1);
+		*argvp++ = buf;
+	}
+
+	/*
+	 * Duplicate last name, for TTYPE option, and null
+	 * terminate the array.  If we didn't find a match on
+	 * our terminal name, put that name at the beginning.
+	 */
+	cp = *(argvp-1);
+	*argvp++ = cp;
+	*argvp = 0;
+
+	if (*argv == 0) {
+		if (name)
+			*argv = name;
+		else {
+			--argvp;
+			for (avt = argv; avt < argvp; avt++)
+				*avt = *(avt+1);
+		}
+	}
+	if (*argv)
+		return(argv);
+	else
+		return(unknown);
+}
+
+static int
+is_unique(name, as, ae)
+	register char *name, **as, **ae;
+{
+	register char **ap;
+	register unsigned int n;
+
+	n = strlen(name) + 1;
+	for (ap = as; ap < ae; ap++)
+		if (strncasecmp(*ap, name, n) == 0)
+			return(0);
+	return (1);
+}
+
+#ifndef	HAVE_SETUPTERM
+char termbuf[1024];
+
+	/*ARGSUSED*/
+static int
+setupterm(tname, fd, errp)
+	char *tname;
+	int fd, *errp;
+{
+	if (tgetent(termbuf, tname) == 1) {
+		termbuf[1023] = '\0';
+		if (errp)
+			*errp = 1;
+		return(0);
+	}
+	if (errp)
+		*errp = 0;
+	return(-1);
+}
+#else
+#define	termbuf	ttytype
+extern char ttytype[];
+#endif
+
+int resettermname = 1;
+
+static	char *
+gettermname()
+{
+	char *tname;
+	static char **tnamep = 0;
+	static char **next;
+	int err;
+
+	if (resettermname) {
+		resettermname = 0;
+		if (tnamep && tnamep != unknown)
+			free(tnamep);
+		if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
+				(setupterm(tname, 1, &err) == 0)) {
+			tnamep = mklist(termbuf, tname);
+		} else {
+			if (tname && (strlen(tname) <= 40)) {
+				unknown[0] = tname;
+				upcase(tname);
+			} else
+				unknown[0] = name_unknown;
+			tnamep = unknown;
+		}
+		next = tnamep;
+	}
+	if (*next == 0)
+		next = tnamep;
+	return(*next++);
+}
+/*
+ * suboption()
+ *
+ *	Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ *
+ *	Currently we recognize:
+ *
+ *		Terminal type, send request.
+ *		Terminal speed (send request).
+ *		Local flow control (is request).
+ *		Linemode
+ */
+
+    static void
+suboption()
+{
+    unsigned char subchar;
+
+    printsub('<', subbuffer, SB_LEN()+2);
+    switch (subchar = SB_GET()) {
+    case TELOPT_TTYPE:
+	if (my_want_state_is_wont(TELOPT_TTYPE))
+	    return;
+	if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
+	    return;
+	} else {
+	    char *name;
+	    unsigned char temp[50];
+	    int len;
+
+#if	defined(TN3270)
+	    if (tn3270_ttype()) {
+		return;
+	    }
+#endif	/* defined(TN3270) */
+	    name = gettermname();
+	    len = strlen(name) + 4 + 2;
+	    if (len < NETROOM()) {
+		sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+				TELQUAL_IS, name, IAC, SE);
+		ring_supply_data(&netoring, temp, len);
+		printsub('>', &temp[2], len-2);
+	    } else {
+		ExitString("No room in buffer for terminal type.\n", 1);
+		/*NOTREACHED*/
+	    }
+	}
+	break;
+    case TELOPT_TSPEED:
+	if (my_want_state_is_wont(TELOPT_TSPEED))
+	    return;
+	if (SB_EOF())
+	    return;
+	if (SB_GET() == TELQUAL_SEND) {
+	    long o_speed, ispeed;
+	    unsigned char temp[50];
+	    int len;
+
+	    TerminalSpeeds(&ispeed, &o_speed);
+
+	    sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
+		    TELQUAL_IS, o_speed, ispeed, IAC, SE);
+	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
+
+	    if (len < NETROOM()) {
+		ring_supply_data(&netoring, temp, len);
+		printsub('>', temp+2, len - 2);
+	    }
+/*@*/	    else printf("lm_will: not enough room in buffer\n");
+	}
+	break;
+    case TELOPT_LFLOW:
+	if (my_want_state_is_wont(TELOPT_LFLOW))
+	    return;
+	if (SB_EOF())
+	    return;
+	switch(SB_GET()) {
+	case LFLOW_RESTART_ANY:
+	    restartany = 1;
+	    break;
+	case LFLOW_RESTART_XON:
+	    restartany = 0;
+	    break;
+	case LFLOW_ON:
+	    localflow = 1;
+	    break;
+	case LFLOW_OFF:
+	    localflow = 0;
+	    break;
+	default:
+	    return;
+	}
+	setcommandmode();
+	setconnmode(0);
+	break;
+
+    case TELOPT_LINEMODE:
+	if (my_want_state_is_wont(TELOPT_LINEMODE))
+	    return;
+	if (SB_EOF())
+	    return;
+	switch (SB_GET()) {
+	case WILL:
+	    lm_will(subpointer, SB_LEN());
+	    break;
+	case WONT:
+	    lm_wont(subpointer, SB_LEN());
+	    break;
+	case DO:
+	    lm_do(subpointer, SB_LEN());
+	    break;
+	case DONT:
+	    lm_dont(subpointer, SB_LEN());
+	    break;
+	case LM_SLC:
+	    slc(subpointer, SB_LEN());
+	    break;
+	case LM_MODE:
+	    lm_mode(subpointer, SB_LEN(), 0);
+	    break;
+	default:
+	    break;
+	}
+	break;
+
+#ifdef	OLD_ENVIRON
+    case TELOPT_OLD_ENVIRON:
+#endif
+    case TELOPT_NEW_ENVIRON:
+	if (SB_EOF())
+	    return;
+	switch(SB_PEEK()) {
+	case TELQUAL_IS:
+	case TELQUAL_INFO:
+	    if (my_want_state_is_dont(subchar))
+		return;
+	    break;
+	case TELQUAL_SEND:
+	    if (my_want_state_is_wont(subchar)) {
+		return;
+	    }
+	    break;
+	default:
+	    return;
+	}
+	env_opt(subpointer, SB_LEN());
+	break;
+
+    case TELOPT_XDISPLOC:
+	if (my_want_state_is_wont(TELOPT_XDISPLOC))
+	    return;
+	if (SB_EOF())
+	    return;
+	if (SB_GET() == TELQUAL_SEND) {
+	    unsigned char temp[50], *dp;
+	    int len;
+
+	    if (((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) ||
+		(! env_is_exported((unsigned char *)"DISPLAY"))) {
+		/*
+		 * Something happened, we no longer have a DISPLAY
+		 * variable.  So, turn off the option.
+		 */
+		send_wont(TELOPT_XDISPLOC, 1);
+		break;
+	    }
+	    sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
+		    TELQUAL_IS, dp, IAC, SE);
+	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
+
+	    if (len < NETROOM()) {
+		ring_supply_data(&netoring, temp, len);
+		printsub('>', temp+2, len - 2);
+	    }
+/*@*/	    else printf("lm_will: not enough room in buffer\n");
+	}
+	break;
+
+#if	defined(AUTHENTICATION)
+	case TELOPT_AUTHENTICATION: {
+		if (!autologin)
+			break;
+		if (SB_EOF())
+			return;
+		switch(SB_GET()) {
+		case TELQUAL_IS:
+			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
+				return;
+			auth_is(subpointer, SB_LEN());
+			break;
+		case TELQUAL_SEND:
+			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+				return;
+			auth_send(subpointer, SB_LEN());
+			break;
+		case TELQUAL_REPLY:
+			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+				return;
+			auth_reply(subpointer, SB_LEN());
+			break;
+		case TELQUAL_NAME:
+			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
+				return;
+			auth_name(subpointer, SB_LEN());
+			break;
+		}
+	}
+	break;
+#endif
+#ifdef	ENCRYPTION
+	case TELOPT_ENCRYPT:
+		if (SB_EOF())
+			return;
+		switch(SB_GET()) {
+		case ENCRYPT_START:
+			if (my_want_state_is_dont(TELOPT_ENCRYPT))
+				return;
+			encrypt_start(subpointer, SB_LEN());
+			break;
+		case ENCRYPT_END:
+			if (my_want_state_is_dont(TELOPT_ENCRYPT))
+				return;
+			encrypt_end();
+			break;
+		case ENCRYPT_SUPPORT:
+			if (my_want_state_is_wont(TELOPT_ENCRYPT))
+				return;
+			encrypt_support(subpointer, SB_LEN());
+			break;
+		case ENCRYPT_REQSTART:
+			if (my_want_state_is_wont(TELOPT_ENCRYPT))
+				return;
+			encrypt_request_start(subpointer, SB_LEN());
+			break;
+		case ENCRYPT_REQEND:
+			if (my_want_state_is_wont(TELOPT_ENCRYPT))
+				return;
+			/*
+			 * We can always send an REQEND so that we cannot
+			 * get stuck encrypting.  We should only get this
+			 * if we have been able to get in the correct mode
+			 * anyhow.
+			 */
+			encrypt_request_end();
+			break;
+		case ENCRYPT_IS:
+			if (my_want_state_is_dont(TELOPT_ENCRYPT))
+				return;
+			encrypt_is(subpointer, SB_LEN());
+			break;
+		case ENCRYPT_REPLY:
+			if (my_want_state_is_wont(TELOPT_ENCRYPT))
+				return;
+			encrypt_reply(subpointer, SB_LEN());
+			break;
+		case ENCRYPT_ENC_KEYID:
+			if (my_want_state_is_dont(TELOPT_ENCRYPT))
+				return;
+			encrypt_enc_keyid(subpointer, SB_LEN());
+			break;
+		case ENCRYPT_DEC_KEYID:
+			if (my_want_state_is_wont(TELOPT_ENCRYPT))
+				return;
+			encrypt_dec_keyid(subpointer, SB_LEN());
+			break;
+		default:
+			break;
+		}
+		break;
+#endif	/* ENCRYPTION */
+    default:
+	break;
+    }
+}
+
+static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
+
+    void
+lm_will(cmd, len)
+    unsigned char *cmd;
+    int len;
+{
+    if (len < 1) {
+/*@*/	printf("lm_will: no command!!!\n");	/* Should not happen... */
+	return;
+    }
+    switch(cmd[0]) {
+    case LM_FORWARDMASK:	/* We shouldn't ever get this... */
+    default:
+	str_lm[3] = DONT;
+	str_lm[4] = cmd[0];
+	if (NETROOM() > sizeof(str_lm)) {
+	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
+	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
+	}
+/*@*/	else printf("lm_will: not enough room in buffer\n");
+	break;
+    }
+}
+
+    void
+lm_wont(cmd, len)
+    unsigned char *cmd;
+    int len;
+{
+    if (len < 1) {
+/*@*/	printf("lm_wont: no command!!!\n");	/* Should not happen... */
+	return;
+    }
+    switch(cmd[0]) {
+    case LM_FORWARDMASK:	/* We shouldn't ever get this... */
+    default:
+	/* We are always DONT, so don't respond */
+	return;
+    }
+}
+
+    void
+lm_do(cmd, len)
+    unsigned char *cmd;
+    int len;
+{
+    if (len < 1) {
+/*@*/	printf("lm_do: no command!!!\n");	/* Should not happen... */
+	return;
+    }
+    switch(cmd[0]) {
+    case LM_FORWARDMASK:
+    default:
+	str_lm[3] = WONT;
+	str_lm[4] = cmd[0];
+	if (NETROOM() > sizeof(str_lm)) {
+	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
+	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
+	}
+/*@*/	else printf("lm_do: not enough room in buffer\n");
+	break;
+    }
+}
+
+    void
+lm_dont(cmd, len)
+    unsigned char *cmd;
+    int len;
+{
+    if (len < 1) {
+/*@*/	printf("lm_dont: no command!!!\n");	/* Should not happen... */
+	return;
+    }
+    switch(cmd[0]) {
+    case LM_FORWARDMASK:
+    default:
+	/* we are always WONT, so don't respond */
+	break;
+    }
+}
+
+static unsigned char str_lm_mode[] = {
+	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
+};
+
+	void
+lm_mode(cmd, len, init)
+	unsigned char *cmd;
+	int len, init;
+{
+	if (len != 1)
+		return;
+	if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
+		return;
+	if (*cmd&MODE_ACK)
+		return;
+	linemode = *cmd&(MODE_MASK&~MODE_ACK);
+	str_lm_mode[4] = linemode;
+	if (!init)
+	    str_lm_mode[4] |= MODE_ACK;
+	if (NETROOM() > sizeof(str_lm_mode)) {
+	    ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
+	    printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
+	}
+/*@*/	else printf("lm_mode: not enough room in buffer\n");
+	setconnmode(0);	/* set changed mode */
+}
+
+
+
+/*
+ * slc()
+ * Handle special character suboption of LINEMODE.
+ */
+
+struct spc {
+	cc_t val;
+	cc_t *valp;
+	char flags;	/* Current flags & level */
+	char mylevel;	/* Maximum level & flags */
+} spc_data[NSLC+1];
+
+#define SLC_IMPORT	0
+#define	SLC_EXPORT	1
+#define SLC_RVALUE	2
+static int slc_mode = SLC_EXPORT;
+
+	void
+slc_init()
+{
+	register struct spc *spcp;
+
+	localchars = 1;
+	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
+		spcp->val = 0;
+		spcp->valp = 0;
+		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
+	}
+
+#define	initfunc(func, flags) { \
+					spcp = &spc_data[func]; \
+					if ((spcp->valp = tcval(func)) != NULL) { \
+					    spcp->val = *spcp->valp; \
+					    spcp->mylevel = SLC_VARIABLE|flags; \
+					} else { \
+					    spcp->val = 0; \
+					    spcp->mylevel = SLC_DEFAULT; \
+					} \
+				    }
+
+	initfunc(SLC_SYNCH, 0);
+	/* No BRK */
+	initfunc(SLC_AO, 0);
+	initfunc(SLC_AYT, 0);
+	/* No EOR */
+	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
+	initfunc(SLC_EOF, 0);
+#ifndef	SYSV_TERMIO
+	initfunc(SLC_SUSP, SLC_FLUSHIN);
+#endif
+	initfunc(SLC_EC, 0);
+	initfunc(SLC_EL, 0);
+#ifndef	SYSV_TERMIO
+	initfunc(SLC_EW, 0);
+	initfunc(SLC_RP, 0);
+	initfunc(SLC_LNEXT, 0);
+#endif
+	initfunc(SLC_XON, 0);
+	initfunc(SLC_XOFF, 0);
+#ifdef	SYSV_TERMIO
+	spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
+	spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
+#endif
+	initfunc(SLC_FORW1, 0);
+#ifdef	USE_TERMIO
+	initfunc(SLC_FORW2, 0);
+	/* No FORW2 */
+#endif
+
+	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
+#undef	initfunc
+
+	if (slc_mode == SLC_EXPORT)
+		slc_export();
+	else
+		slc_import(1);
+
+}
+
+    void
+slcstate()
+{
+    printf("Special characters are %s values\n",
+		slc_mode == SLC_IMPORT ? "remote default" :
+		slc_mode == SLC_EXPORT ? "local" :
+					 "remote");
+}
+
+    void
+slc_mode_export()
+{
+    slc_mode = SLC_EXPORT;
+    if (my_state_is_will(TELOPT_LINEMODE))
+	slc_export();
+}
+
+    void
+slc_mode_import(def)
+    int def;
+{
+    slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
+    if (my_state_is_will(TELOPT_LINEMODE))
+	slc_import(def);
+}
+
+unsigned char slc_import_val[] = {
+	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
+};
+unsigned char slc_import_def[] = {
+	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
+};
+
+    void
+slc_import(def)
+    int def;
+{
+    if (NETROOM() > sizeof(slc_import_val)) {
+	if (def) {
+	    ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
+	    printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
+	} else {
+	    ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
+	    printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
+	}
+    }
+/*@*/ else printf("slc_import: not enough room\n");
+}
+
+    void
+slc_export()
+{
+    register struct spc *spcp;
+
+    TerminalDefaultChars();
+
+    slc_start_reply();
+    for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+	if (spcp->mylevel != SLC_NOSUPPORT) {
+	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
+		spcp->flags = SLC_NOSUPPORT;
+	    else
+		spcp->flags = spcp->mylevel;
+	    if (spcp->valp)
+		spcp->val = *spcp->valp;
+	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
+	}
+    }
+    slc_end_reply();
+    (void)slc_update();
+    setconnmode(1);	/* Make sure the character values are set */
+}
+
+	void
+slc(cp, len)
+	register unsigned char *cp;
+	int len;
+{
+	register struct spc *spcp;
+	register int func,level;
+
+	slc_start_reply();
+
+	for (; len >= 3; len -=3, cp +=3) {
+
+		func = cp[SLC_FUNC];
+
+		if (func == 0) {
+			/*
+			 * Client side: always ignore 0 function.
+			 */
+			continue;
+		}
+		if (func > NSLC) {
+			if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
+				slc_add_reply(func, SLC_NOSUPPORT, 0);
+			continue;
+		}
+
+		spcp = &spc_data[func];
+
+		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
+
+		if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
+		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
+			continue;
+		}
+
+		if (level == (SLC_DEFAULT|SLC_ACK)) {
+			/*
+			 * This is an error condition, the SLC_ACK
+			 * bit should never be set for the SLC_DEFAULT
+			 * level.  Our best guess to recover is to
+			 * ignore the SLC_ACK bit.
+			 */
+			cp[SLC_FLAGS] &= ~SLC_ACK;
+		}
+
+		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
+			spcp->val = (cc_t)cp[SLC_VALUE];
+			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
+			continue;
+		}
+
+		level &= ~SLC_ACK;
+
+		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
+			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
+			spcp->val = (cc_t)cp[SLC_VALUE];
+		}
+		if (level == SLC_DEFAULT) {
+			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
+				spcp->flags = spcp->mylevel;
+			else
+				spcp->flags = SLC_NOSUPPORT;
+		}
+		slc_add_reply(func, spcp->flags, spcp->val);
+	}
+	slc_end_reply();
+	if (slc_update())
+		setconnmode(1);	/* set the  new character values */
+}
+
+    void
+slc_check()
+{
+    register struct spc *spcp;
+
+    slc_start_reply();
+    for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+	if (spcp->valp && spcp->val != *spcp->valp) {
+	    spcp->val = *spcp->valp;
+	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
+		spcp->flags = SLC_NOSUPPORT;
+	    else
+		spcp->flags = spcp->mylevel;
+	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
+	}
+    }
+    slc_end_reply();
+    setconnmode(1);
+}
+
+
+unsigned char slc_reply[128];
+unsigned char *slc_replyp;
+
+	void
+slc_start_reply()
+{
+	slc_replyp = slc_reply;
+	*slc_replyp++ = IAC;
+	*slc_replyp++ = SB;
+	*slc_replyp++ = TELOPT_LINEMODE;
+	*slc_replyp++ = LM_SLC;
+}
+
+	void
+slc_add_reply(func, flags, value)
+	unsigned char func;
+	unsigned char flags;
+	cc_t value;
+{
+	if ((slc_replyp - slc_reply) + 6 > sizeof(slc_reply))
+		return;
+	if ((*slc_replyp++ = func) == IAC)
+		*slc_replyp++ = IAC;
+	if ((*slc_replyp++ = flags) == IAC)
+		*slc_replyp++ = IAC;
+	if ((*slc_replyp++ = (unsigned char)value) == IAC)
+		*slc_replyp++ = IAC;
+}
+
+    void
+slc_end_reply()
+{
+    register int len;
+
+    len = slc_replyp - slc_reply;
+    if (len <= 4 || (len + 2 > sizeof(slc_reply)))
+	return;
+    *slc_replyp++ = IAC;
+    *slc_replyp++ = SE;
+    len += 2;
+    if (NETROOM() > len) {
+	ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
+	printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
+    }
+/*@*/else printf("slc_end_reply: not enough room\n");
+}
+
+	int
+slc_update()
+{
+	register struct spc *spcp;
+	int need_update = 0;
+
+	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+		if (!(spcp->flags&SLC_ACK))
+			continue;
+		spcp->flags &= ~SLC_ACK;
+		if (spcp->valp && (*spcp->valp != spcp->val)) {
+			*spcp->valp = spcp->val;
+			need_update = 1;
+		}
+	}
+	return(need_update);
+}
+
+#ifdef	OLD_ENVIRON
+# ifdef	ENV_HACK
+/*
+ * Earlier version of telnet/telnetd from the BSD code had
+ * the definitions of VALUE and VAR reversed.  To ensure
+ * maximum interoperability, we assume that the server is
+ * an older BSD server, until proven otherwise.  The newer
+ * BSD servers should be able to handle either definition,
+ * so it is better to use the wrong values if we don't
+ * know what type of server it is.
+ */
+int env_auto = 1;
+int old_env_var = OLD_ENV_VAR;
+int old_env_value = OLD_ENV_VALUE;
+# else
+#  define old_env_var OLD_ENV_VAR
+#  define old_env_value OLD_ENV_VALUE
+# endif
+#endif
+
+	void
+env_opt(buf, len)
+	register unsigned char *buf;
+	register int len;
+{
+	register unsigned char *ep = 0, *epc = 0;
+	register int i;
+
+	switch(buf[0]&0xff) {
+	case TELQUAL_SEND:
+		env_opt_start();
+		if (len == 1) {
+			env_opt_add(NULL);
+		} else for (i = 1; i < len; i++) {
+			switch (buf[i]&0xff) {
+#ifdef	OLD_ENVIRON
+			case OLD_ENV_VAR:
+# ifdef	ENV_HACK
+				if (telopt_environ == TELOPT_OLD_ENVIRON
+				    && env_auto) {
+					/* Server has the same definitions */
+					old_env_var = OLD_ENV_VAR;
+					old_env_value = OLD_ENV_VALUE;
+				}
+				/* FALL THROUGH */
+# endif
+			case OLD_ENV_VALUE:
+				/*
+				 * Although OLD_ENV_VALUE is not legal, we will
+				 * still recognize it, just in case it is an
+				 * old server that has VAR & VALUE mixed up...
+				 */
+				/* FALL THROUGH */
+#else
+			case NEW_ENV_VAR:
+#endif
+			case ENV_USERVAR:
+				if (ep) {
+					*epc = 0;
+					env_opt_add(ep);
+				}
+				ep = epc = &buf[i+1];
+				break;
+			case ENV_ESC:
+				i++;
+				/*FALL THROUGH*/
+			default:
+				if (epc)
+					*epc++ = buf[i];
+				break;
+			}
+		}
+		if (ep) {
+			*epc = 0;
+			env_opt_add(ep);
+		}
+		env_opt_end(1);
+		break;
+
+	case TELQUAL_IS:
+	case TELQUAL_INFO:
+		/* Ignore for now.  We shouldn't get it anyway. */
+		break;
+
+	default:
+		break;
+	}
+}
+
+#define	OPT_REPLY_SIZE	256
+unsigned char *opt_reply;
+unsigned char *opt_replyp;
+unsigned char *opt_replyend;
+
+	void
+env_opt_start()
+{
+	if (opt_reply)
+		opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
+	else
+		opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
+	if (opt_reply == NULL) {
+/*@*/		printf("env_opt_start: malloc()/realloc() failed!!!\n");
+		opt_reply = opt_replyp = opt_replyend = NULL;
+		return;
+	}
+	opt_replyp = opt_reply;
+	opt_replyend = opt_reply + OPT_REPLY_SIZE;
+	*opt_replyp++ = IAC;
+	*opt_replyp++ = SB;
+	*opt_replyp++ = telopt_environ;
+	*opt_replyp++ = TELQUAL_IS;
+}
+
+	void
+env_opt_start_info()
+{
+	env_opt_start();
+	if (opt_replyp)
+	    opt_replyp[-1] = TELQUAL_INFO;
+}
+
+	void
+env_opt_add(ep)
+	register unsigned char *ep;
+{
+	register unsigned char *vp, c;
+	unsigned int len, olen, elen;
+
+	if (opt_reply == NULL)		/*XXX*/
+		return;			/*XXX*/
+
+	if (ep == NULL || *ep == '\0') {
+		/* Send user defined variables first. */
+		env_default(1, 0);
+		while ((ep = env_default(0, 0)) != NULL)
+			env_opt_add(ep);
+
+		/* Now add the list of well know variables.  */
+		env_default(1, 1);
+		while ((ep = env_default(0, 1)) != NULL)
+			env_opt_add(ep);
+		return;
+	}
+	vp = env_getvalue(ep);
+	elen = 2 * (vp ? strlen((char *)vp) : 0) +
+		2 * strlen((char *)ep) + 6;
+	if ((opt_replyend - opt_replyp) < elen)
+	{
+		len = opt_replyend - opt_reply + elen;
+		olen = opt_replyp - opt_reply;
+		opt_reply = (unsigned char *)realloc(opt_reply, len);
+		if (opt_reply == NULL) {
+/*@*/			printf("env_opt_add: realloc() failed!!!\n");
+			opt_reply = opt_replyp = opt_replyend = NULL;
+			return;
+		}
+		opt_replyp = opt_reply + olen;
+		opt_replyend = opt_reply + len;
+	}
+	if (opt_welldefined((char *) ep))
+#ifdef	OLD_ENVIRON
+		if (telopt_environ == TELOPT_OLD_ENVIRON)
+			*opt_replyp++ = old_env_var;
+		else
+#endif
+			*opt_replyp++ = NEW_ENV_VAR;
+	else
+		*opt_replyp++ = ENV_USERVAR;
+	for (;;) {
+		while ((c = *ep++)) {
+			switch(c&0xff) {
+			case IAC:
+				*opt_replyp++ = IAC;
+				break;
+			case NEW_ENV_VAR:
+			case NEW_ENV_VALUE:
+			case ENV_ESC:
+			case ENV_USERVAR:
+				*opt_replyp++ = ENV_ESC;
+				break;
+			}
+			*opt_replyp++ = c;
+		}
+		if ((ep = vp) != NULL) {
+#ifdef	OLD_ENVIRON
+			if (telopt_environ == TELOPT_OLD_ENVIRON)
+				*opt_replyp++ = old_env_value;
+			else
+#endif
+				*opt_replyp++ = NEW_ENV_VALUE;
+			vp = NULL;
+		} else
+			break;
+	}
+}
+
+	int
+opt_welldefined(ep)
+	char *ep;
+{
+	if ((strcmp(ep, "USER") == 0) ||
+	    (strcmp(ep, "DISPLAY") == 0) ||
+	    (strcmp(ep, "PRINTER") == 0) ||
+	    (strcmp(ep, "SYSTEMTYPE") == 0) ||
+	    (strcmp(ep, "JOB") == 0) ||
+	    (strcmp(ep, "ACCT") == 0))
+		return(1);
+	return(0);
+}
+	void
+env_opt_end(emptyok)
+	register int emptyok;
+{
+	register int len;
+
+	len = opt_replyp - opt_reply + 2;
+	if (emptyok || len > 6) {
+		*opt_replyp++ = IAC;
+		*opt_replyp++ = SE;
+		if (NETROOM() > len) {
+			ring_supply_data(&netoring, opt_reply, len);
+			printsub('>', &opt_reply[2], len - 2);
+		}
+/*@*/		else printf("slc_end_reply: not enough room\n");
+	}
+	if (opt_reply) {
+		free(opt_reply);
+		opt_reply = opt_replyp = opt_replyend = NULL;
+	}
+}
+
+
+
+    int
+telrcv()
+{
+    register int c;
+    register int scc;
+    register unsigned char *sbp = NULL;
+    int count;
+    int returnValue = 0;
+
+    scc = 0;
+    count = 0;
+    while (TTYROOM() > 2) {
+	if (scc == 0) {
+	    if (count) {
+		ring_consumed(&netiring, count);
+		returnValue = 1;
+		count = 0;
+	    }
+	    sbp = netiring.consume;
+	    scc = ring_full_consecutive(&netiring);
+	    if (scc == 0) {
+		/* No more data coming in */
+		break;
+	    }
+	}
+
+	c = *sbp++ & 0xff, scc--; count++;
+#ifdef	ENCRYPTION
+	if (decrypt_input)
+		c = (*decrypt_input)(c);
+#endif	/* ENCRYPTION */
+
+	switch (telrcv_state) {
+
+	case TS_CR:
+	    telrcv_state = TS_DATA;
+	    if (c == '\0') {
+		break;	/* Ignore \0 after CR */
+	    }
+	    else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
+		TTYADD(c);
+		break;
+	    }
+	    /* Else, fall through */
+
+	case TS_DATA:
+	    if (c == IAC) {
+		telrcv_state = TS_IAC;
+		break;
+	    }
+#	    if defined(TN3270)
+	    if (In3270) {
+		*Ifrontp++ = c;
+		while (scc > 0) {
+		    c = *sbp++ & 0377, scc--; count++;
+#ifdef	ENCRYPTION
+		    if (decrypt_input)
+			c = (*decrypt_input)(c);
+#endif	/* ENCRYPTION */
+		    if (c == IAC) {
+			telrcv_state = TS_IAC;
+			break;
+		    }
+		    *Ifrontp++ = c;
+		}
+	    } else
+#	    endif /* defined(TN3270) */
+		    /*
+		     * The 'crmod' hack (see following) is needed
+		     * since we can't * set CRMOD on output only.
+		     * Machines like MULTICS like to send \r without
+		     * \n; since we must turn off CRMOD to get proper
+		     * input, the mapping is done here (sigh).
+		     */
+	    if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
+		if (scc > 0) {
+		    c = *sbp&0xff;
+#ifdef	ENCRYPTION
+		    if (decrypt_input)
+			c = (*decrypt_input)(c);
+#endif	/* ENCRYPTION */
+		    if (c == 0) {
+			sbp++, scc--; count++;
+			/* a "true" CR */
+			TTYADD('\r');
+		    } else if (my_want_state_is_dont(TELOPT_ECHO) &&
+					(c == '\n')) {
+			sbp++, scc--; count++;
+			TTYADD('\n');
+		    } else {
+#ifdef	ENCRYPTION
+		        if (decrypt_input)
+			    (*decrypt_input)(-1);
+#endif	/* ENCRYPTION */
+
+			TTYADD('\r');
+			if (crmod) {
+				TTYADD('\n');
+			}
+		    }
+		} else {
+		    telrcv_state = TS_CR;
+		    TTYADD('\r');
+		    if (crmod) {
+			    TTYADD('\n');
+		    }
+		}
+	    } else {
+		TTYADD(c);
+	    }
+	    continue;
+
+	case TS_IAC:
+process_iac:
+	    switch (c) {
+	    
+	    case WILL:
+		telrcv_state = TS_WILL;
+		continue;
+
+	    case WONT:
+		telrcv_state = TS_WONT;
+		continue;
+
+	    case DO:
+		telrcv_state = TS_DO;
+		continue;
+
+	    case DONT:
+		telrcv_state = TS_DONT;
+		continue;
+
+	    case DM:
+		    /*
+		     * We may have missed an urgent notification,
+		     * so make sure we flush whatever is in the
+		     * buffer currently.
+		     */
+		printoption("RCVD", IAC, DM);
+		SYNCHing = 1;
+		(void) ttyflush(1);
+		SYNCHing = stilloob();
+		settimer(gotDM);
+		break;
+
+	    case SB:
+		SB_CLEAR();
+		telrcv_state = TS_SB;
+		continue;
+
+#	    if defined(TN3270)
+	    case EOR:
+		if (In3270) {
+		    if (Ibackp == Ifrontp) {
+			Ibackp = Ifrontp = Ibuf;
+			ISend = 0;	/* should have been! */
+		    } else {
+			Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
+			ISend = 1;
+		    }
+		}
+		printoption("RCVD", IAC, EOR);
+		break;
+#	    endif /* defined(TN3270) */
+
+	    case IAC:
+#	    if !defined(TN3270)
+		TTYADD(IAC);
+#	    else /* !defined(TN3270) */
+		if (In3270) {
+		    *Ifrontp++ = IAC;
+		} else {
+		    TTYADD(IAC);
+		}
+#	    endif /* !defined(TN3270) */
+		break;
+
+	    case NOP:
+	    case GA:
+	    default:
+		printoption("RCVD", IAC, c);
+		break;
+	    }
+	    telrcv_state = TS_DATA;
+	    continue;
+
+	case TS_WILL:
+	    printoption("RCVD", WILL, c);
+	    willoption(c);
+	    SetIn3270();
+	    telrcv_state = TS_DATA;
+	    continue;
+
+	case TS_WONT:
+	    printoption("RCVD", WONT, c);
+	    wontoption(c);
+	    SetIn3270();
+	    telrcv_state = TS_DATA;
+	    continue;
+
+	case TS_DO:
+	    printoption("RCVD", DO, c);
+	    dooption(c);
+	    SetIn3270();
+	    if (c == TELOPT_NAWS) {
+		sendnaws();
+	    } else if (c == TELOPT_LFLOW) {
+		localflow = 1;
+		setcommandmode();
+		setconnmode(0);
+	    }
+	    telrcv_state = TS_DATA;
+	    continue;
+
+	case TS_DONT:
+	    printoption("RCVD", DONT, c);
+	    dontoption(c);
+	    flushline = 1;
+	    setconnmode(0);	/* set new tty mode (maybe) */
+	    SetIn3270();
+	    telrcv_state = TS_DATA;
+	    continue;
+
+	case TS_SB:
+	    if (c == IAC) {
+		telrcv_state = TS_SE;
+	    } else {
+		SB_ACCUM(c);
+	    }
+	    continue;
+
+	case TS_SE:
+	    if (c != SE) {
+		if (c != IAC) {
+		    /*
+		     * This is an error.  We only expect to get
+		     * "IAC IAC" or "IAC SE".  Several things may
+		     * have happend.  An IAC was not doubled, the
+		     * IAC SE was left off, or another option got
+		     * inserted into the suboption are all possibilities.
+		     * If we assume that the IAC was not doubled,
+		     * and really the IAC SE was left off, we could
+		     * get into an infinate loop here.  So, instead,
+		     * we terminate the suboption, and process the
+		     * partial suboption if we can.
+		     */
+		    SB_ACCUM(IAC);
+		    SB_ACCUM(c);
+		    subpointer -= 2;
+		    SB_TERM();
+
+		    printoption("In SUBOPTION processing, RCVD", IAC, c);
+		    suboption();	/* handle sub-option */
+		    SetIn3270();
+		    telrcv_state = TS_IAC;
+		    goto process_iac;
+		}
+		SB_ACCUM(c);
+		telrcv_state = TS_SB;
+	    } else {
+		SB_ACCUM(IAC);
+		SB_ACCUM(SE);
+		subpointer -= 2;
+		SB_TERM();
+		suboption();	/* handle sub-option */
+		SetIn3270();
+		telrcv_state = TS_DATA;
+	    }
+	}
+    }
+    if (count)
+	ring_consumed(&netiring, count);
+    return returnValue||count;
+}
+
+static int bol = 1, local = 0;
+
+    int
+rlogin_susp()
+{
+    if (local) {
+	local = 0;
+	bol = 1;
+	command(0, "z\n", 2);
+	return(1);
+    }
+    return(0);
+}
+
+    static int
+telsnd()
+{
+    int tcc;
+    int count;
+    int returnValue = 0;
+    unsigned char *tbp;
+
+    tcc = 0;
+    count = 0;
+    while (NETROOM() > 2) {
+	register int sc;
+	register int c;
+
+	if (tcc == 0) {
+	    if (count) {
+		ring_consumed(&ttyiring, count);
+		returnValue = 1;
+		count = 0;
+	    }
+	    tbp = ttyiring.consume;
+	    tcc = ring_full_consecutive(&ttyiring);
+	    if (tcc == 0) {
+		break;
+	    }
+	}
+	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
+	if (rlogin != _POSIX_VDISABLE) {
+		if (bol) {
+			bol = 0;
+			if (sc == rlogin) {
+				local = 1;
+				continue;
+			}
+		} else if (local) {
+			local = 0;
+			if (sc == '.' || c == termEofChar) {
+				bol = 1;
+				command(0, "close\n", 6);
+				continue;
+			}
+			if (sc == termSuspChar) {
+				bol = 1;
+				command(0, "z\n", 2);
+				continue;
+			}
+			if (sc == escape) {
+				command(0, (char *)tbp, tcc);
+				bol = 1;
+				count += tcc;
+				tcc = 0;
+				flushline = 1;
+				break;
+			}
+			if (sc != rlogin) {
+				++tcc;
+				--tbp;
+				--count;
+				c = sc = rlogin;
+			}
+		}
+		if ((sc == '\n') || (sc == '\r'))
+			bol = 1;
+	} else if (sc == escape) {
+	    /*
+	     * Double escape is a pass through of a single escape character.
+	     */
+	    if (tcc && strip(*tbp) == escape) {
+		tbp++;
+		tcc--;
+		count++;
+		bol = 0;
+	    } else {
+		command(0, (char *)tbp, tcc);
+		bol = 1;
+		count += tcc;
+		tcc = 0;
+		flushline = 1;
+		break;
+	    }
+	} else
+	    bol = 0;
+#ifdef	KLUDGELINEMODE
+	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
+	    if (tcc > 0 && strip(*tbp) == echoc) {
+		tcc--; tbp++; count++;
+	    } else {
+		dontlecho = !dontlecho;
+		settimer(echotoggle);
+		setconnmode(0);
+		flushline = 1;
+		break;
+	    }
+	}
+#endif
+	if (MODE_LOCAL_CHARS(globalmode)) {
+	    if (TerminalSpecialChars(sc) == 0) {
+		bol = 1;
+		break;
+	    }
+	}
+	if (my_want_state_is_wont(TELOPT_BINARY)) {
+	    switch (c) {
+	    case '\n':
+		    /*
+		     * If we are in CRMOD mode (\r ==> \n)
+		     * on our local machine, then probably
+		     * a newline (unix) is CRLF (TELNET).
+		     */
+		if (MODE_LOCAL_CHARS(globalmode)) {
+		    NETADD('\r');
+		}
+		NETADD('\n');
+		bol = flushline = 1;
+		break;
+	    case '\r':
+		if (!crlf) {
+		    NET2ADD('\r', '\0');
+		} else {
+		    NET2ADD('\r', '\n');
+		}
+		bol = flushline = 1;
+		break;
+	    case IAC:
+		NET2ADD(IAC, IAC);
+		break;
+	    default:
+		NETADD(c);
+		break;
+	    }
+	} else if (c == IAC) {
+	    NET2ADD(IAC, IAC);
+	} else {
+	    NETADD(c);
+	}
+    }
+    if (count)
+	ring_consumed(&ttyiring, count);
+    return returnValue||count;		/* Non-zero if we did anything */
+}
+
+/*
+ * Scheduler()
+ *
+ * Try to do something.
+ *
+ * If we do something useful, return 1; else return 0.
+ *
+ */
+
+
+    int
+Scheduler(block)
+    int	block;			/* should we block in the select ? */
+{
+		/* One wants to be a bit careful about setting returnValue
+		 * to one, since a one implies we did some useful work,
+		 * and therefore probably won't be called to block next
+		 * time (TN3270 mode only).
+		 */
+    int returnValue;
+    int netin, netout, netex, ttyin, ttyout;
+
+    /* Decide which rings should be processed */
+
+    netout = ring_full_count(&netoring) &&
+	    (flushline ||
+		(my_want_state_is_wont(TELOPT_LINEMODE)
+#ifdef	KLUDGELINEMODE
+			&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
+#endif
+		) ||
+			my_want_state_is_will(TELOPT_BINARY));
+    ttyout = ring_full_count(&ttyoring);
+
+#if	defined(TN3270)
+    ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
+#else	/* defined(TN3270) */
+    ttyin = ring_empty_count(&ttyiring);
+#endif	/* defined(TN3270) */
+
+#if	defined(TN3270)
+    netin = ring_empty_count(&netiring);
+#   else /* !defined(TN3270) */
+    netin = !ISend && ring_empty_count(&netiring);
+#   endif /* !defined(TN3270) */
+
+    netex = !SYNCHing;
+
+    /* If we have seen a signal recently, reset things */
+#   if defined(TN3270) && defined(unix)
+    if (HaveInput) {
+	HaveInput = 0;
+	(void) signal(SIGIO, inputAvailable);
+    }
+#endif	/* defined(TN3270) && defined(unix) */
+
+    if (scheduler_lockout_tty) {
+	ttyin = ttyout = 0;
+    }
+
+    /* Call to system code to process rings */
+
+    returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
+
+    /* Now, look at the input rings, looking for work to do. */
+
+    if (ring_full_count(&ttyiring)) {
+#   if defined(TN3270)
+	if (In3270) {
+	    int c;
+
+	    c = DataFromTerminal(ttyiring.consume,
+					ring_full_consecutive(&ttyiring));
+	    if (c) {
+		returnValue = 1;
+	        ring_consumed(&ttyiring, c);
+	    }
+	} else {
+#   endif /* defined(TN3270) */
+	    returnValue |= telsnd();
+#   if defined(TN3270)
+	}
+#   endif /* defined(TN3270) */
+    }
+
+    if (ring_full_count(&netiring)) {
+#	if !defined(TN3270)
+	returnValue |= telrcv();
+#	else /* !defined(TN3270) */
+	returnValue = Push3270();
+#	endif /* !defined(TN3270) */
+    }
+    return returnValue;
+}
+
+/*
+ * Select from tty and network...
+ */
+    void
+telnet(user)
+    char *user;
+{
+    int printed_encrypt = 0;
+    
+    sys_telnet_init();
+
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION) 
+    {
+	static char local_host[256] = { 0 };
+
+	if (!local_host[0]) {
+		gethostname(local_host, sizeof(local_host));
+		local_host[sizeof(local_host)-1] = 0;
+	}
+	auth_encrypt_init(local_host, hostname, "TELNET", 0);
+	auth_encrypt_user(user);
+    }
+#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
+#   if !defined(TN3270)
+#if	defined(AUTHENTICATION)
+    if (autologin)
+	send_will(TELOPT_AUTHENTICATION, 1);
+#endif
+#ifdef	ENCRYPTION
+    if (telnetport || wantencryption) {
+	send_do(TELOPT_ENCRYPT, 1);
+	send_will(TELOPT_ENCRYPT, 1);
+    }
+#endif	/* ENCRYPTION */
+    if (telnetport) {
+	send_do(TELOPT_SGA, 1);
+	send_will(TELOPT_TTYPE, 1);
+	send_will(TELOPT_NAWS, 1);
+	send_will(TELOPT_TSPEED, 1);
+	send_will(TELOPT_LFLOW, 1);
+	send_will(TELOPT_LINEMODE, 1);
+	send_will(TELOPT_NEW_ENVIRON, 1);
+	send_do(TELOPT_STATUS, 1);
+	if (env_getvalue((unsigned char *)"DISPLAY") &&
+	    env_is_exported((unsigned char *)"DISPLAY"))
+	    send_will(TELOPT_XDISPLOC, 1);
+	if (eight)
+	    tel_enter_binary(eight);
+    }
+#   endif /* !defined(TN3270) */
+
+#ifdef ENCRYPTION
+    /*
+     * Note: we assume a tie to the authentication option here.  This
+     * is necessary so that authentication fails, we don't spin
+     * forever. 
+     */
+    if (wantencryption) {
+	extern int auth_has_failed;
+	time_t time_out = time(0) + 60;
+
+	send_do(TELOPT_ENCRYPT, 1);
+	send_will(TELOPT_ENCRYPT, 1);
+	while (1) {
+	    if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
+		printf("\nServer refused to negotiate authentication, which is required\n");
+		printf("for encryption.  Good-bye.\n\r");
+		Exit(1);
+	    }
+	    if (auth_has_failed) {
+		printf("\nNegotiation of authentication, which is required for encryption,\n");
+		printf("has failed.  Good-bye.\n\r");
+		Exit(1);
+	    }
+	    if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
+		my_want_state_is_wont(TELOPT_ENCRYPT)) {
+		printf("\nServer refused to negotiate encryption.  Good-bye.\n\r");
+		Exit(1);
+	    }
+	    if (encrypt_is_encrypting())
+		break;
+	    if (time(0) > time_out) {
+		printf("\nEncryption could not be enabled.  Good-bye.\n\r");
+		Exit(1);
+	    }
+	    if (printed_encrypt == 0) {
+		    printed_encrypt = 1;
+		    printf("Waiting for encryption to be negotiated...\n");
+		    /*
+		     * Turn on MODE_TRAPSIG and then turn off localchars 
+		     * so that ^C will cause telnet to exit.
+		     */
+		    TerminalNewMode(getconnmode()|MODE_TRAPSIG);
+		    intr_waiting = 1;
+	    }
+	    if (intr_happened) {
+		    printf("\nUser requested an interrupt.  Good-bye.\n\r");
+		    Exit(1);
+	    }
+	    telnet_spin();
+	}
+	if (printed_encrypt) {
+		printf("done.\n");
+		intr_waiting = 0;
+		setconnmode(0);
+	}
+    }
+#endif
+
+
+#   if !defined(TN3270)
+    for (;;) {
+	int schedValue;
+
+	while ((schedValue = Scheduler(0)) != 0) {
+	    if (schedValue == -1) {
+		setcommandmode();
+		return;
+	    }
+	}
+
+	if (Scheduler(1) == -1) {
+	    setcommandmode();
+	    return;
+	}
+    }
+#   else /* !defined(TN3270) */
+    for (;;) {
+	int schedValue;
+
+	while (!In3270 && !shell_active) {
+	    if (Scheduler(1) == -1) {
+		setcommandmode();
+		return;
+	    }
+	}
+
+	while ((schedValue = Scheduler(0)) != 0) {
+	    if (schedValue == -1) {
+		setcommandmode();
+		return;
+	    }
+	}
+		/* If there is data waiting to go out to terminal, don't
+		 * schedule any more data for the terminal.
+		 */
+	if (ring_full_count(&ttyoring)) {
+	    schedValue = 1;
+	} else {
+	    if (shell_active) {
+		if (shell_continue() == 0) {
+		    ConnectScreen();
+		}
+	    } else if (In3270) {
+		schedValue = DoTerminalOutput();
+	    }
+	}
+	if (schedValue && (shell_active == 0)) {
+	    if (Scheduler(1) == -1) {
+		setcommandmode();
+		return;
+	    }
+	}
+    }
+#   endif /* !defined(TN3270) */
+}
+
+#if	0	/* XXX - this not being in is a bug */
+/*
+ * nextitem()
+ *
+ *	Return the address of the next "item" in the TELNET data
+ * stream.  This will be the address of the next character if
+ * the current address is a user data character, or it will
+ * be the address of the character following the TELNET command
+ * if the current address is a TELNET IAC ("I Am a Command")
+ * character.
+ */
+
+    static char *
+nextitem(current)
+    char *current;
+{
+    if ((*current&0xff) != IAC) {
+	return current+1;
+    }
+    switch (*(current+1)&0xff) {
+    case DO:
+    case DONT:
+    case WILL:
+    case WONT:
+	return current+3;
+    case SB:		/* loop forever looking for the SE */
+	{
+	    register char *look = current+2;
+
+	    for (;;) {
+		if ((*look++&0xff) == IAC) {
+		    if ((*look++&0xff) == SE) {
+			return look;
+		    }
+		}
+	    }
+	}
+    default:
+	return current+2;
+    }
+}
+#endif	/* 0 */
+
+/*
+ * netclear()
+ *
+ *	We are about to do a TELNET SYNCH operation.  Clear
+ * the path to the network.
+ *
+ *	Things are a bit tricky since we may have sent the first
+ * byte or so of a previous TELNET command into the network.
+ * So, we have to scan the network buffer from the beginning
+ * until we are up to where we want to be.
+ *
+ *	A side effect of what we do, just to keep things
+ * simple, is to clear the urgent data pointer.  The principal
+ * caller should be setting the urgent data pointer AFTER calling
+ * us in any case.
+ */
+
+    static void
+netclear()
+{
+#if	0	/* XXX */
+    register char *thisitem, *next;
+    char *good;
+#define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
+				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
+
+    thisitem = netobuf;
+
+    while ((next = nextitem(thisitem)) <= netobuf.send) {
+	thisitem = next;
+    }
+
+    /* Now, thisitem is first before/at boundary. */
+
+    good = netobuf;	/* where the good bytes go */
+
+    while (netoring.add > thisitem) {
+	if (wewant(thisitem)) {
+	    int length;
+
+	    next = thisitem;
+	    do {
+		next = nextitem(next);
+	    } while (wewant(next) && (nfrontp > next));
+	    length = next-thisitem;
+	    memcpy(good, thisitem, length);
+	    good += length;
+	    thisitem = next;
+	} else {
+	    thisitem = nextitem(thisitem);
+	}
+    }
+
+#endif	/* 0 */
+}
+
+/*
+ * These routines add various telnet commands to the data stream.
+ */
+
+    static void
+doflush()
+{
+    NET2ADD(IAC, DO);
+    NETADD(TELOPT_TM);
+    flushline = 1;
+    flushout = 1;
+    (void) ttyflush(1);			/* Flush/drop output */
+    /* do printoption AFTER flush, otherwise the output gets tossed... */
+    printoption("SENT", DO, TELOPT_TM);
+}
+
+    void
+xmitAO()
+{
+    NET2ADD(IAC, AO);
+    printoption("SENT", IAC, AO);
+    if (autoflush) {
+	doflush();
+    }
+}
+
+
+    void
+xmitEL()
+{
+    NET2ADD(IAC, EL);
+    printoption("SENT", IAC, EL);
+}
+
+    void
+xmitEC()
+{
+    NET2ADD(IAC, EC);
+    printoption("SENT", IAC, EC);
+}
+
+
+    int
+dosynch(s)
+     char *s;
+{
+    netclear();			/* clear the path to the network */
+    NETADD(IAC);
+    setneturg();
+    NETADD(DM);
+    printoption("SENT", IAC, DM);
+    return 1;
+}
+
+int want_status_response = 0;
+
+    int
+get_status(s)
+    char *s;
+{
+    unsigned char tmp[16];
+    register unsigned char *cp;
+
+    if (my_want_state_is_dont(TELOPT_STATUS)) {
+	printf("Remote side does not support STATUS option\n");
+	return 0;
+    }
+    cp = tmp;
+
+    *cp++ = IAC;
+    *cp++ = SB;
+    *cp++ = TELOPT_STATUS;
+    *cp++ = TELQUAL_SEND;
+    *cp++ = IAC;
+    *cp++ = SE;
+    if (NETROOM() >= cp - tmp) {
+	ring_supply_data(&netoring, tmp, cp-tmp);
+	printsub('>', tmp+2, cp - tmp - 2);
+    }
+    ++want_status_response;
+    return 1;
+}
+
+    void
+intp()
+{
+    NET2ADD(IAC, IP);
+    printoption("SENT", IAC, IP);
+    flushline = 1;
+    if (autoflush) {
+	doflush();
+    }
+    if (autosynch) {
+	dosynch(NULL);
+    }
+}
+
+    void
+sendbrk()
+{
+    NET2ADD(IAC, BREAK);
+    printoption("SENT", IAC, BREAK);
+    flushline = 1;
+    if (autoflush) {
+	doflush();
+    }
+    if (autosynch) {
+	dosynch(NULL);
+    }
+}
+
+    void
+sendabort()
+{
+    NET2ADD(IAC, ABORT);
+    printoption("SENT", IAC, ABORT);
+    flushline = 1;
+    if (autoflush) {
+	doflush();
+    }
+    if (autosynch) {
+	dosynch(NULL);
+    }
+}
+
+    void
+sendsusp()
+{
+    NET2ADD(IAC, SUSP);
+    printoption("SENT", IAC, SUSP);
+    flushline = 1;
+    if (autoflush) {
+	doflush();
+    }
+    if (autosynch) {
+	dosynch(NULL);
+    }
+}
+
+    void
+sendeof()
+{
+    NET2ADD(IAC, xEOF);
+    printoption("SENT", IAC, xEOF);
+}
+
+    void
+sendayt()
+{
+    NET2ADD(IAC, AYT);
+    printoption("SENT", IAC, AYT);
+}
+
+/*
+ * Send a window size update to the remote system.
+ */
+
+    void
+sendnaws()
+{
+    long rows, cols;
+    unsigned char tmp[16];
+    register unsigned char *cp;
+
+    if (my_state_is_wont(TELOPT_NAWS))
+	return;
+
+#define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
+			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
+
+    if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
+	return;
+    }
+
+    cp = tmp;
+
+    *cp++ = IAC;
+    *cp++ = SB;
+    *cp++ = TELOPT_NAWS;
+    PUTSHORT(cp, cols);
+    PUTSHORT(cp, rows);
+    *cp++ = IAC;
+    *cp++ = SE;
+    if (NETROOM() >= cp - tmp) {
+	ring_supply_data(&netoring, tmp, cp-tmp);
+	printsub('>', tmp+2, cp - tmp - 2);
+    }
+}
+
+    void
+tel_enter_binary(rw)
+    int rw;
+{
+    if (rw&1)
+	send_do(TELOPT_BINARY, 1);
+    if (rw&2)
+	send_will(TELOPT_BINARY, 1);
+}
+
+    void
+tel_leave_binary(rw)
+    int rw;
+{
+    if (rw&1)
+	send_dont(TELOPT_BINARY, 1);
+    if (rw&2)
+	send_wont(TELOPT_BINARY, 1);
+}
diff --git a/mechglue/src/appl/telnet/telnet/terminal.c b/mechglue/src/appl/telnet/telnet/terminal.c
new file mode 100644
index 000000000..611270373
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/terminal.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)terminal.c	8.1 (Berkeley) 6/6/93 */
+
+#include <arpa/telnet.h>
+#include <sys/types.h>
+
+#include "ring.h"
+
+#include "externs.h"
+#include "types.h"
+
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+Ring		ttyoring, ttyiring;
+unsigned char	ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ];
+
+int termdata;			/* Debugging flag */
+
+#ifdef	USE_TERMIO
+# ifndef VDISCARD
+cc_t termFlushChar;
+# endif
+# ifndef VLNEXT
+cc_t termLiteralNextChar;
+# endif
+# ifndef VSUSP
+cc_t termSuspChar;
+# endif
+# ifndef VWERASE
+cc_t termWerasChar;
+# endif
+# ifndef VREPRINT
+cc_t termRprntChar;
+# endif
+# ifndef VSTART
+cc_t termStartChar;
+# endif
+# ifndef VSTOP
+cc_t termStopChar;
+# endif
+# ifndef VEOL
+cc_t termForw1Char;
+# endif
+# ifndef VEOL2
+cc_t termForw2Char;
+# endif
+# ifndef VSTATUS
+cc_t termAytChar;
+# endif
+#else
+cc_t termForw2Char;
+cc_t termAytChar;
+#endif
+
+/*
+ * initialize the terminal data structures.
+ */
+
+    void
+init_terminal()
+{
+    if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) {
+	exit(1);
+    }
+    if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) {
+	exit(1);
+    }
+    autoflush = TerminalAutoFlush();
+}
+
+
+/*
+ *		Send as much data as possible to the terminal.
+ *
+ *		Return value:
+ *			-1: No useful work done, data waiting to go out.
+ *			 0: No data was waiting, so nothing was done.
+ *			 1: All waiting data was written out.
+ *			 n: All data - n was written out.
+ */
+
+
+    int
+ttyflush(drop)
+    int drop;
+{
+    register int n, n0, n1;
+
+    n0 = ring_full_count(&ttyoring);
+    if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) {
+	if (drop) {
+	    TerminalFlushOutput();
+	    /* we leave 'n' alone! */
+	} else {
+	    n = TerminalWrite(ttyoring.consume, n);
+	}
+    }
+    if (n > 0) {
+	if (termdata && n) {
+	    Dump('>', ttyoring.consume, n);
+	}
+	/*
+	 * If we wrote everything, and the full count is
+	 * larger than what we wrote, then write the
+	 * rest of the buffer.
+	 */
+	if (n1 == n && n0 > n) {
+		n1 = n0 - n;
+		if (!drop)
+			n1 = TerminalWrite(ttyoring.bottom, n1);
+		n += n1;
+	}
+	ring_consumed(&ttyoring, n);
+    }
+    if (n < 0)
+	return -1;
+    if (n == n0) {
+	if (n0)
+	    return -1;
+	return 0;
+    }
+    return n0 - n + 1;
+}
+
+
+/*
+ * These routines decides on what the mode should be (based on the values
+ * of various global variables).
+ */
+
+
+    int
+getconnmode()
+{
+    extern int linemode;
+    int mode = 0;
+#ifdef	KLUDGELINEMODE
+    extern int kludgelinemode;
+#endif
+
+    if (In3270)
+	return(MODE_FLOW);
+
+    if (my_want_state_is_dont(TELOPT_ECHO))
+	mode |= MODE_ECHO;
+
+    if (localflow)
+	mode |= MODE_FLOW;
+
+    if (my_want_state_is_will(TELOPT_BINARY))
+	mode |= MODE_INBIN;
+
+    if (his_want_state_is_will(TELOPT_BINARY))
+	mode |= MODE_OUTBIN;
+
+#ifdef	KLUDGELINEMODE
+    if (kludgelinemode) {
+	if (my_want_state_is_dont(TELOPT_SGA)) {
+	    mode |= (MODE_TRAPSIG|MODE_EDIT);
+	    if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
+		mode &= ~MODE_ECHO;
+	    }
+	}
+	return(mode);
+    }
+#endif
+    if (my_want_state_is_will(TELOPT_LINEMODE))
+	mode |= linemode;
+    return(mode);
+}
+
+    void
+setconnmode(force)
+    int force;
+{
+#ifdef	ENCRYPTION
+    static int enc_passwd = 0;
+#endif	/* ENCRYPTION */
+    register int newmode;
+
+    newmode = getconnmode()|(force?MODE_FORCE:0);
+
+    TerminalNewMode(newmode);
+
+#ifdef  ENCRYPTION
+    if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) {
+	if (my_want_state_is_will(TELOPT_ENCRYPT)
+				&& (enc_passwd == 0) && !encrypt_output) {
+	    encrypt_request_start(0, 0);
+	    enc_passwd = 1;
+	}
+    } else {
+	if (enc_passwd) {
+	    encrypt_request_end();
+	    enc_passwd = 0;
+	}
+    }
+#endif	/* ENCRYPTION */
+
+}
+
+
+    void
+setcommandmode()
+{
+    TerminalNewMode(-1);
+}
diff --git a/mechglue/src/appl/telnet/telnet/tmac.doc b/mechglue/src/appl/telnet/telnet/tmac.doc
new file mode 100644
index 000000000..464023fea
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/tmac.doc
@@ -0,0 +1,4102 @@
+.\" Copyright (c) 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)doc	5.8 (Berkeley) 8/5/91
+.\"
+.\" .mdoc-parse - attempt to parse troff request arguments
+.\" This version has had comments stripped; an unstripped version is available.
+.if \n(.g \{\
+.cp 0
+.ftr C CR
+.\}
+.if t \{\
+.\" tmac.mdoc-ditroff
+.ds aD \fI\s10
+.ds aR \f(CO\s10
+.ds cM \f(CB\s10
+.ds dF \fR\s10
+.ds eM \fI\s10
+.ds eR \fC\s10
+.ds eV \fC\s10
+.ds fA \f(CO\s10
+.ds fD \f(CB\s10
+.ds fL \f(CB\s10
+.ds fN \f(CB\s10
+.ds fP \fP\s0
+.ds fS \s0
+.ds fT \f(CO\s10
+.ds Hs \fR\s10
+.ds iC \f(CB\s10
+.ds lI \fC
+.ds lP \fR\|(\|\fP\s10
+.ds lp \fR(\fP\s10
+.ds rP \fR\|)\|\fP\s10
+.ds rp \fR)\fP\s10
+.ds lB \fR\^[\^\fP\s10
+.ds rB \fR\^]\fP\s10
+.ds mL \fB\s10
+.ds nM \f(CB\s10
+.ds nO \fR\s10
+.ds nT \s0
+.ds pA \fC\s10
+.ds Pu \fR{\ .\ ,\ :\ ;\ (\ )\ [\ ]\ \fR}
+.ds rA \fR\s10
+.ds rT \f(CO\s10
+.ds sH \fB\s10
+.ds sP \s0
+.ds sY \fB\s10
+.ds sX \fR\s10
+.ds tF \fR
+.ds tN \s9
+.ds vA \fI\s10
+.ds Vs \fR\s10
+.ds vT \f(CB\s10
+.ds xR \fC\s10
+.tr *\(**
+.nr sI \w\fC,u*5
+.nr Ti \n(sIu
+.nr Pp .5v
+.ds lS \0
+.nr lS \w'\0'u
+.nr dI 6n
+.de pL
+.nr Hm .5i
+.nr Fm .5i
+.nr ll 6.5i
+.ll 6.5i
+.nr lt 6.5i
+.lt 6.5i
+.nr po 1i
+.po 1.i
+.nr dV .5v
+..
+.ds <= \(<=
+.ds >= \(>=
+.ds Lq \&``
+.ds Rq \&''
+.ds ua \(ua
+.ds aa \(aa
+.ds ga \(ga
+.ds sR \&'
+.ds sL \&`
+.ds q \&"
+.ds Pi \(*p
+.ds Ne \(!=
+.ds Le \(<=
+.ds Ge \(>=
+.ds Lt <
+.ds Gt >
+.ds Pm \(+-
+.ds If \(if
+.ds Na \fINaN\fP
+.ds Ba \fR\&|\fP
+.nr gX 0
+.de hK
+.ds hT \\*(dT
+.if !"\\*(cH"Null" \{\
+.       ie !"\\*(gP"Null" .as hT \|(\|\\*(cH\\*(gP\|)
+.       el .as hT \\|(\\|\\*(cH\\|)
+.\}
+.if "\\*(cH"Null" \{\
+.	if !"\\*(gP"Null" .as hT \&\|(\|\\*(gP\|)
+.\}
+.wh 0 hM
+.wh -1.25i fM
+.ie \\n(gX==1 \{\
+.	rm n1
+.	if \\n(.g .br
+.	if !\\n(.g .bp
+.\}
+.el \{\
+.	if \\n(.g .br
+.	if !\\n(.g 'bp
+.\}
+.nr % 1
+.nr gX 0
+.em lM
+..
+.nr fW \w\fC0
+.de sW
+.nr sW \w\fC\\$1
+.ie \\n(sW>=\\n(fW \{\
+.       ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+.       el .nr sW \\n(sW/\\n(fW
+.\}
+.el \{\
+.	ie \\n(sW>0 .nr sW 1
+.	el .nr sW 0
+.\}
+..
+.de aW
+.nr sW \w\fC\\*(A\\$1
+.ie \\n(sW>=\\n(fW \{\
+.       ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+.       el .nr sW \\n(sW/\\n(fW
+.\}
+.el \{\
+.	ie \\n(sW>0 .nr sW 1
+.	el .nr sW 0
+.\}
+..
+.de Ql
+.if \\n(aC==0  \{\
+.	ds mN Ql
+.       ds A1 \\$1
+.       ds A2 \\$2
+.       ds A3 \\$3
+.       ds A4 \\$4
+.       ds A5 \\$5
+.       ds A6 \\$6
+.       ds A7 \\$7
+.       ds A8 \\$8
+. 	nr fV \\n(.$
+. 	fV
+.\}
+.nr aP \\n(aP+1
+.aW \\n(aP
+.nr aP \\n(aP-1
+.if \\n(sW>2 .Li
+.if \\n(sW<=2 \{\
+.	if (\\n(aP>0) \{\
+.		ds A\\n(aP Li
+.		nr aP \\n(aP -1
+.	\}		
+.	if (\\n(aP==0) \{\
+.		rm C0 C1 C2 C3 C4 C5 C6 C7 C8 C9
+.		rm S1 S2 S3 S4 S5 S6 S7 S8 S9
+.		rn A8 A9
+.		rn A7 A8
+.		rn A6 A7
+.		rn A5 A6
+.		rn A4 A5
+.		rn A3 A4
+.		rn A2 A3
+.		rn A1 A2
+.		ds A1 Li
+.	 	nr fV \\n(aC+1
+.		nr aC 0
+.		fV
+.	\}
+.	ds qL \&\\*(sL
+.	ds qR \&\\*(sR
+.	En
+.\}
+..
+.de Sh
+.nr nS 0
+.nr sE 0
+.nr iS 0
+'ad
+.ie "\\$1"NAME" \{\
+.       hK
+'       in 0
+.\}
+.el \{\
+.       nr nS 0
+.       nr nA 0
+.       nr nF 0
+.       nr nT 0
+.       nr nY 0
+.       nr oT 0
+.       if "\\$1"SYNOPSIS" \{\
+.		na
+.		nr nS 1
+.	\}
+.       if "\\$1"DESCRIPTION" \{\
+.		nr fY 0
+.		nr fZ 0
+.		nr fB 0
+.		nr Fb 0
+.		ds Fb
+.	\}
+.       if "\\$1"SEE" \{\
+.               nr nA 1
+.               na
+.       \}
+.       if "\\$1"FILES" .nr nF 1
+.       if "\\$1"STANDARDS" .nr nT 1
+.       if "\\$1"AUTHORS" .nr nY 1
+.	if "\\$1"SEE" .nr sE 1
+.       in 0
+.       nr aN 0
+.\}
+.pL
+'sp
+.ns
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.if !\\n(cR .ne 3
+'fi
+\&\\*(sH\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 \|\\$7 \|\\$8 \|\\$9
+\&\fP\s0\&
+.in \\n(.iu+\\n(Tiu
+.ns
+..
+.\}
+.if n \{\
+.\" tmac.mdoc-nroff
+.ds aD \fI
+.ds aR \fI
+.ds cM \fB
+.ds dF \fR
+.ds eM \fI
+.ds eR \fR
+.ds eV \fR
+.ds fA \fI
+.ds fD \fB
+.ds fL \fB
+.ds fN \fB
+.ds fP \fP
+.ds fS
+.ds fT \fI
+.ds Hs \fR
+.ds iC \fB
+.ds lI \fR
+.ds lP \fR\|(\fP
+.ds rP \fR\|)\fP
+.ds lp \fR\|(\fP
+.ds rp \fR\|)\fP
+.ds lB \fR\|[\|\fP
+.ds rB \fR\|]\fP
+.ds mL \fB
+.ds nM \fB
+.ds nO \fR
+.ds pA \fI
+.ds Pu {\ .\ ,\ ;\ :\ (\ )\ [\ ]}
+.ds rA \fR
+.ds rT \fI
+.ds sH \fB
+.ds sP
+.ds sY \fB
+.ds sX \fI
+.ds tF \fR
+.ds tN
+.ds vA \fI
+.ds Vs \fR
+.ds vT \fB
+.ds xR \fR
+.nr sI .5i
+.nr Ti .5i
+.nr cR 1
+.nr Pp 1v
+.ds lS \0\0
+.nr lS \w'\0\0'u
+.nr dI 6n
+.de pL
+.ie \\n(cR .nr Hm 0
+.el .nr Hm .5i
+.nr Fm .5i
+.nr ll 78n
+.ll 78n
+.nr lt 78n
+.lt 78n
+.nr po 0i
+.po 0i
+.nr dV 1v
+.ad l
+.na
+..
+.ds <= \&<\&=
+.ds >= \&>\&=
+.ds Rq ''
+.ds Lq ``
+.ds ua ^
+.ds aa \'
+.ds ga \`
+.ds sL `
+.ds sR '
+.ds q \&"
+.ds Pi pi
+.ds Ne !=
+.ds Le <=
+.ds Ge >=
+.ds Lt <
+.ds Gt >
+.ds Pm +-
+.ds If infinity
+.ds Na \fINaN\fP
+.ds Ba \fR\&|\fP
+.de hK
+.nr % 1
+.ds hT \\*(dT
+.if !"\\*(cH"Null" \{\
+.	ie !"\\*(gP"Null" .as hT \|(\|\\*(cH\\*(gP\|)
+.	el .as hT \\|(\\|\\*(cH\\|)
+.\}
+.if "\\*(cH"Null" .if !"\\*(gP"Null" .as hT \&\|(\|\\*(gP\|)
+.ie \\n(cR \{\
+.	hM
+.	wh -1v fM
+.\}
+.el \{\
+.	wh 0 hM
+.	wh -1.167i fM
+.\}
+.if \\n(nl==0:\\n(nl==-1 'bp
+.em lM
+..
+.nr fW \w'0'
+.de sW
+.nr sW \w\\$1
+.ie \\n(sW>=\\n(fW \{\
+.       ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+.       el .nr sW \\n(sW/\\n(fW
+.\}
+.el .nr sW 0
+..
+.de aW
+.nr sW \w\\*(A\\$1
+.ie \\n(sW>=\\n(fW \{\
+.       ie \\n(sW%\\n(fW .nr sW (\\n(sW/\\n(fW)+1
+.       el .nr sW \\n(sW/\\n(fW
+.\}
+.el .nr sW 0
+..
+.de Ql
+.if \\n(aC==0  \{\
+.	ds mN Ql
+.	ds A1 \\$1
+.	ds A2 \\$2
+.	ds A3 \\$3
+.	ds A4 \\$4
+.	ds A5 \\$5
+.	ds A6 \\$6
+.	ds A7 \\$7
+.	ds A8 \\$8
+.	ds A9 \\$9
+.	nr fV \\n(.$
+. 	fV
+.\}
+.ds qL \&\\*(sL
+.ds qR \&\\*(sR
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Sh
+.nr nS 0
+.nr sE 0
+.nr iS 0
+.ie "\\$1"NAME" \{\
+.       hK
+'       in 0
+.\}
+.el \{\
+.       nr nS 0
+.       nr nA 0
+.       nr nF 0
+.       nr nT 0
+.       nr nY 0
+.       nr aN 0
+.       nr oT 0
+.       if "\\$1"SEE" .nr nA 1
+.       if "\\$1"FILES" .nr nF 1
+.       if "\\$1"STANDARDS" .nr nT 1
+.       if "\\$1"SYNOPSIS" .nr nS 1
+.       if "\\$1"DESCRIPTION" \{\
+.               rr fB
+.               rr Fb
+.               ds Fb
+.               nr fY 0
+.               nr fZ 0
+.       \}
+.	if "\\$1"AUTHORS" .nr nY 1
+.       in 0
+.\}
+.pL
+'sp
+.ns
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.if !\\n(cR .ne 3
+'fi
+\&\\*(sH\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 \|\\$7 \|\\$8 \|\\$9
+\&\fP\s0\&
+.in \\n(.iu+\\n(Tiu
+.if "\\$1"SEE" .nr sE 1
+.ns
+..
+.\}
+.\"     @(#)doc-common	5.7 (Berkeley) 8/5/91
+.nr %A 1
+.nr %J 1
+.nr %N 1
+.nr %O 1
+.nr %R 1
+.nr %T 1
+.nr %V 1
+.nr Ad 12n
+.nr Ac 3
+.nr Ao 12n
+.nr Ap 2
+.nr An 12n
+.nr Aq 12n
+.nr Ar 12n
+.nr Bc 3
+.nr Bl 1
+.nr Bo 12n
+.nr Bq 12n
+.nr Bx 12n
+.nr Cd 12n
+.nr Cm 10n
+.nr Co 15n
+.nr Cx 20n
+.nr Dc 3
+.nr Do 10n
+.nr Dq 12n
+.nr Ds 6n
+.nr Dq 12n
+.nr Dv 12n
+.nr tI \n(Dsu
+.nr Ec 3
+.nr El 1
+.nr Eo 12n
+.nr Eq 12n
+.nr Em 10n
+.nr Er 12n
+.nr Ev 15n
+.nr Ex 10n
+.nr Fa 12n
+.nr Fl 10n
+.nr Fc 3
+.nr Fo 16n
+.nr Fn 16n
+.nr Hl 1
+.nr I1 6n
+.nr I2 12n
+.nr I3 18n
+.nr Ic 10n
+.nr Li 16n
+.nr Ms 6n
+.nr Nm 10n
+.nr No 12n
+.nr Ns 2
+.nr Oo 10n
+.nr Oc 3
+.nr Op 14n
+.nr Pa 32n
+.nr Pf 12n
+.nr Pc 3
+.nr Po 12n
+.nr Pq 12n
+.nr Ql 16n
+.nr Qc 3
+.nr Qo 12n
+.nr Qq 12n
+.nr Sc 3
+.nr So 12n
+.nr Sq 12n
+.nr Sy 6n
+.nr Sx 16n
+.nr Ra 1
+.nr Rj 1
+.nr Rn 1
+.nr Ro 1
+.nr Rr 1
+.nr Rt 1
+.nr Rv 1
+.nr Tn 10n
+.nr Ta 1
+.nr Tv 1
+.nr Tx 22n
+.nr Ux 10n
+.nr Va 12n
+.nr Xc 3
+.nr Xo 1
+.nr Xr 10n
+.ds sV \& \&
+.ds hV \&\ \&
+.ds iV \& \&
+.ds tV \&\\t\&
+.nr z. 3
+.nr z, 3
+.nr z: 3
+.nr z; 3
+.nr z( 4
+.nr z) 3
+.nr z[ 4
+.nr z] 3
+.ds z( z)
+.ds z[ z]
+.ds z< z>
+.nr z0 0
+.nr z1 0
+.nr z2 0
+.nr z3 0
+.nr z4 0
+.nr z5 0
+.nr z6 0
+.nr z7 0
+.nr z8 0
+.nr z9 0
+.nr z# 0
+.de Dt
+.ds dT UNTITLED
+.ds vT LOCAL
+.ds cH Null
+.if !"\\$1"" .ds dT \\$1
+.if !"\\$2"" \{\
+.	ds cH \\$2
+.		if \\$2>=1 .if \\$2<=8 \{\
+.			ds vT NetBSD Reference Manual
+.			if \\$2>1 .if \\$2<6 .ds vT NetBSD Programmer's Manual
+.			if "\\$2"8" .ds vT NetBSD System Manager's Manual
+.			nr sN \\$2
+.		\}
+.		if "\\$2"unass"  .ds vT DRAFT
+.		if "\\$2"draft"  .ds vT DRAFT
+.		if "\\$2"paper"  .ds vT UNTITLED
+.\}
+.if !"\\$3"" \{\
+.	if "\\$3"USD"   .ds vT NetBSD User's Supplementary Documents
+.	if "\\$3"PS1"   .ds vT NetBSD Programmers's Supplementary Documents
+.	if "\\$3"AMD"   .ds vT NetBSD Ancestral Manual Documents
+.	if "\\$3"SMM"   .ds vT NetBSD System Manager's Manual
+.	if "\\$3"URM"   .ds vT NetBSD Reference Manual
+.	if "\\$3"PRM"   .ds vT NetBSD Programmers's Manual
+.	if "\\$3"IND"   .ds vT NetBSD Manual Master Index
+.	if "\\$3"LOCAL" .ds vT NetBSD Local Manual
+.	if "\\$3"tahoe" .as vT \ (Tahoe Architecture)
+.	if "\\$3"vax" .as vT \ (VAX Architecture)
+.	if "\\$3"hp300" .as vT \ (HP300 Architecture)
+.	if "\\*(vT"LOCAL" .ds vT \\$3
+.\}
+..
+.de Os
+.ds oS Null
+.if "\\$1"" \{\
+.	ds oS BSD Experimental
+.\}
+.if "\\$2"" \{\
+.	ds aa Non-Null
+.\}
+.if "\\$1"ATT"   \{\
+.	ds oS AT&T
+.	if "\\$2""    .as oS \0UNIX
+.	if "\\$2"7th" .as oS \07th Edition
+.	if "\\$2"7"   .as oS \07th Edition
+.	if "\\$2"III" .as oS \0System III
+.	if "\\$2"3"   .as oS \0System III
+.	if "\\$2"V"   .as oS \0System V
+.	if "\\$2"V.2" .as oS \0System V Release 2
+.	if "\\$2"V.3" .as oS \0System V Release 3
+.	if "\\$2"V.4" .as oS \0System V Release 4
+.\}
+.if "\\$1"BSD" \{\
+.	if "\\$2"3"    .ds oS 3rd Berkeley Distribution
+.	if "\\$2"4"    .ds oS 4th Berkeley Distribution
+.	if "\\$2"4.1"  .ds oS 4.1 Berkeley Distribution
+.	if "\\$2"4.2"  .ds oS 4.2 Berkeley Distribution
+.	if "\\$2"4.3"  .ds oS 4.3 Berkeley Distribution
+.	if "\\$2"4.3T" .ds oS 4.3-Tahoe Berkeley Distribution
+.	if "\\$2"4.3R" .ds oS 4.3-Reno Berkeley Distribution
+.	if "\\$2"4.3t" .ds oS 4.3-Tahoe Berkeley Distribution
+.	if "\\$2"4.3r" .ds oS 4.3-Reno Berkeley Distribution
+.	if "\\$2"4.4"  .ds oS BSD Experimental
+.\}
+.if "\\$1"NetBSD" \{\
+.	ds oS NetBSD
+.	if "\\$2"0.8"  .as oS \00.8
+.	if "\\$2"0.8a" .as oS \00.8a
+.	if "\\$2"0.9"  .as oS \00.9
+.	if "\\$2"0.9a" .as oS \00.9a Experimental
+.	if "\\$2"1.0"  .as oS \01.0 Experimental
+.\}
+.if "\\*(oS"Null" .ds oS \0\\$1
+.if "\\*(aa"Non-Null" .as oS \0\\$2
+.rm aa
+..
+.de Dd
+.if !"\\*(dD"" .nr gX 1
+.ie \\n(.$>0 \{\
+.	ie \\n(.$==3 \{\
+.		ds dD \\$1 \\$2 \\$3
+.	\}
+.	el \{\
+.		if "\\n(mo"1"  .ds dD January
+.		if "\\n(mo"2"  .ds dD February
+.		if "\\n(mo"3"  .ds dD March
+.		if "\\n(mo"4"  .ds dD April
+.		if "\\n(mo"5"  .ds dD May
+.		if "\\n(mo"6"  .ds dD June
+.		if "\\n(mo"7"  .ds dD July
+.		if "\\n(mo"8"  .ds dD August
+.		if "\\n(mo"9"  .ds dD September
+.		if "\\n(mo"10" .ds dD October
+.		if "\\n(mo"11" .ds dD November
+.		if "\\n(mo"12" .ds dD December
+.		as dD \&\ \\n(dy, 19\\n(yr
+.	\}
+.\}
+.el \{\
+.	ds dD Epoch
+.\}
+..
+.de hM
+.ev 1
+.pL
+.if !\\n(cR 'sp \\n(Hmu
+.tl @\\*(Hs\\*(hT\fP@\\*(Vs\\*(vT\fP@\\*(Hs\\*(hT\fP@
+'sp \\n(Hmu
+.ev
+..
+.de fM
+.ie \\n(cR 'br
+.el \{\
+.	ev 1
+.	pL
+.	if !\\n(cR \{\
+'		sp \\n(Fmu
+.		tl @\\*(Hs\\*(oS\fP@\\*(Vs\\*(dD\fP@%@
+'		bp
+.	\}
+.	ev
+.\}
+..
+.de lM
+.fl
+.if \\n(cR \{\
+'	sp
+.	tl @\\*(Hs\\*(oS\fP@\\*(Vs\\*(dD\fP@%@
+.       pl \\n(nlu
+.\}
+..
+.de Pp
+.sp \\n(Ppu
+.ne 2
+.ns
+..
+.de Lp
+.Pp
+..
+.de LP
+.tm Not a \-mdoc command: .LP
+..
+.de PP
+.tm Not a \-mdoc command: .PP
+..
+.de pp
+.tm Not a \-mdoc command: .pp
+..
+.de Nd
+\&\-\& \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Ss
+.sp
+.ne 2
+.ti -.25i
+\&\\*(sH\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 \|\\$7 \|\\$8 \|\\$9
+\&\fP\s0
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.if !\\n(cR .ne 2
+.br
+..
+.de Rd
+.tm MDOC REGISTER DUMP
+.tm Db==\\n(Db register DEBUG MODE
+.tm L[0-9] registers - stack of list types
+.tm L0==\\n(L0
+.tm L1==\\n(L1
+.tm L2==\\n(L2
+.tm L3==\\n(L3
+.tm L4==\\n(L4
+.tm L5==\\n(L5
+.tm L6==\\n(L6
+.tm L7==\\n(L7
+.tm L8==\\n(L8
+.tm L9==\\n(L9
+.tm O[0-9] registers - stack of indent
+.tm O0==\\n(O0
+.tm O1==\\n(O1
+.tm O2==\\n(O2
+.tm O3==\\n(O3
+.tm O4==\\n(O4
+.tm O5==\\n(O5
+.tm O6==\\n(O6
+.tm O7==\\n(O7
+.tm O8==\\n(O8
+.tm O9==\\n(O9
+.tm aC==\\n(aC register argument counter (aV/fV)
+.tm aJ==\\n(aJ register (for vR)
+.tm aN==\\n(aN register
+.tm aP==\\n(aP register argument pointer (aV)
+.tm aT==\\n(aT register argument type
+.tm aa==\\n(aa local register
+.tm bK==\\n(bK register - Book Name flag
+.tm cF==\\n(cF register save current font
+.tm cI==\\n(cI register - column indent width
+.tm cZ==\\n(cZ register save current font size
+.tm dK==\\n(dK register - Date flag
+.tm d[0-9] registers - display-type stack
+.tm d0==\\n(d0
+.tm d1==\\n(d1
+.tm d2==\\n(d2
+.tm d3==\\n(d3
+.tm d4==\\n(d4
+.tm d5==\\n(d5
+.tm d6==\\n(d6
+.tm d7==\\n(d7
+.tm d8==\\n(d8
+.tm d9==\\n(d9
+.tm dZ==\\n(dZ register diversion count
+.tm fD==\\n(fD register subroutine test (in synopsis only)
+.tm fV==\\n(fV register argument counter (must set to \\n(.$ prior to
+.tm fY==\\n(fY register - dick with old style function declarations (fortran)
+.tm fZ==\\n(fZ register also subroutine count (in synopsis only)
+.tm h[0-9] register horizontal tag stack (continuous if 1, break if
+.tm h0==\\n(h0
+.tm h1==\\n(h1
+.tm h2==\\n(h2
+.tm h3==\\n(h3
+.tm h4==\\n(h4
+.tm h5==\\n(h5
+.tm h6==\\n(h6
+.tm h7==\\n(h7
+.tm h8==\\n(h8
+.tm h9==\\n(h9
+.tm iD==\\n(iD local register
+.tm iI==\\n(iI local register (indent for inline debug mode)
+.tm iN==\\n(iN register DEBUG MODE (inline if 1, to stderr if
+.tm iS==\\n(iS register - indent second command line in a synopsis
+.tm jK==\\n(jK register - [reference] Journal Name flag
+.tm jM==\\n(jM local register
+.tm jN==\\n(jN local register
+.tm lC==\\n(lC register - list type stack counter
+.tm lK==\\n(lK register count of lines read from input file
+.tm nK==\\n(nK register - [reference] issue number flag
+.tm nU==\\n(nU register count
+.tm oK==\\n(oK register - [reference] optional information flag
+.tm oM==\\n(oM register (extension possible)
+.tm o[0-9] register offset stack (nested tags)
+.tm o0==\\n(o0
+.tm o1==\\n(o1
+.tm o2==\\n(o2
+.tm o3==\\n(o3
+.tm o4==\\n(o4
+.tm o5==\\n(o5
+.tm o6==\\n(o6
+.tm o7==\\n(o7
+.tm o8==\\n(o8
+.tm o9==\\n(o9
+.tm oM==\\n(oM register open ended line flag
+.tm pK==\\n(pK register - [reference] page number flag
+.tm qK==\\n(qK register - Corporate or Foreign Author flag
+.tm rK==\\n(rK register - [reference] report flag
+.tm rS==\\n(rS register - Reference Start flag
+.tm sM==\\n(sM register - default is one (space mode on)
+.tm tK==\\n(tK register - reference title flag
+.tm tP==\\n(tP register tag flag (for diversions)
+.tm tX==\\n(tX register (initial class)
+.tm tY==\\n(tY register (next possible lC value)
+.tm t[0-9] register tag string stack (nested tags)
+.tm t0==\\n(t0
+.tm t1==\\n(t1
+.tm t2==\\n(t2
+.tm t3==\\n(t3
+.tm t4==\\n(t4
+.tm t5==\\n(t5
+.tm t6==\\n(t6
+.tm t7==\\n(t7
+.tm t8==\\n(t8
+.tm t9==\\n(t9
+.tm uK==\\n(uK register - reference author(s) counter
+.tm vK==\\n(vK register - reference volume flag
+.tm v[0-9] register vertical tag break stack
+.tm v0==\\n(v0
+.tm v1==\\n(v1
+.tm v2==\\n(v2
+.tm v3==\\n(v3
+.tm v4==\\n(v4
+.tm v5==\\n(v5
+.tm v6==\\n(v6
+.tm v7==\\n(v7
+.tm v8==\\n(v8
+.tm v9==\\n(v9
+.tm w[0-9] register tag stack (nested tags)
+.tm w0==\\n(w0
+.tm w1==\\n(w1
+.tm w2==\\n(w2
+.tm w3==\\n(w3
+.tm w4==\\n(w4
+.tm w5==\\n(w5
+.tm w6==\\n(w6
+.tm w7==\\n(w7
+.tm w8==\\n(w8
+.tm w9==\\n(w9
+.tm xX==\\n(xX local register
+.tm END OF REGISTER DUMP
+..
+.\"     @(#)doc-syms	5.6 (Berkeley) 8/5/91
+.de Ux
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ds aa \&\f\\n(cF\s\\n(cZ
+.as b1 \&\\*(tNUNIX\\*(aa
+.rm aa
+.if \\n(aC==0 \{\
+.       if \\n(.$>0 .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.ie \\n(aC>\\n(aP \{\
+.       nr aP \\n(aP+1
+.       ie \\n(C\\n(aP==1 \{\
+.               \\*(A\\n(aP
+.       \}
+.       el .nR
+.\}
+.el .aZ
+..
+.de Bx
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ds aa \&\f\\n(cF\s\\n(cZ
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 \&\\*(tNBSD\\*(aa \\*(tNUNIX\\*(aa
+.       el .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.if "\\$1"-alpha" \{\
+\¤tly in alpha test.
+.	aY
+.\}
+.if "\\$1"-beta" \{\
+\¤tly in beta test.
+.	aY
+.\}
+.if "\\$1"-devel" \{\
+\¤tly under development.
+.	aY
+.\}
+.if \\n(aC>\\n(aP \{\
+.       nr aP \\n(aP+1
+.	ie \\n(C\\n(aP==2 \{\
+.		as b1 \&\\*(A\\n(aP\&\\*(tNBSD\\*(aa
+.		ie \\n(aC>\\n(aP \{\
+.			nr jj \\n(aP+1
+.			ie \\n(C\\n(jj==2 \{\
+.				if "\\*(A\\n(jj"Reno" \{\
+.					nr aP \\n(aP+1
+.					as b1 \&\-\\*(A\\n(jj
+.				\}
+.				if "\\*(A\\n(jj"reno" \{\
+.					nr aP \\n(aP+1
+.					as b1 \&\-Reno
+.				\}
+.				if "\\*(A\\n(jj"Tahoe" \{\
+.					nr aP \\n(aP+1
+.					as b1 \&\-\\*(A\\n(jj
+.				\}
+.				if "\\*(A\\n(jj"tahoe" \{\
+.					nr aP \\n(aP+1
+.					as b1 \&\-Tahoe
+.				\}
+.				ie \\n(aC>\\n(aP \{\
+.					nr aP \\n(aP+1
+.					nR
+.				\}
+.				el .aZ
+.			\}
+.			el \{\
+.				nr aP \\n(aP+1
+.				nR
+.			\}
+.			rr jj
+.		\}
+.		el .aZ
+.	\}
+.	el \{\
+.	       as b1 \&\\*(tNBSD\\*(aa U\\*(tNNIX\\*(aa
+.	       nR
+.	\}
+.\}
+..
+.de Ud
+\¤tly under development.
+..
+.de Nx
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ds aa \&\f\\n(cF\s\\n(cZ
+.if \\n(.$==2 \{\
+.	if "\\$1"0.8"  \&\\*(tNNetBSD\\*(aa 0.8\\*(aa\\$2
+.	if "\\$1"0.8a"  \&\\*(tNNetBSD\\*(aa 0.8a\\*(aa\\$2
+.	if "\\$1"0.9"  \&\\*(tNNetBSD\\*(aa 0.9\\*(aa\\$2
+.	if "\\$1"0.9a"  \&\\*(tNNetBSD\\*(aa 0.9a\\*(aa\\$2
+.	if "\\$1"1.0"  \&\\*(tNNetBSD\\*(aa 1.0\\*(aa\\$2
+.	if "\\$1"1.0a"  \&\\*(tNNetBSD\\*(aa 1.0a\\*(aa\\$2
+.\}
+.if \\n(.$==1 \{\
+.	if "\\$1"0.8"  \&\\*(tNNetBSD\\*(aa 0.8\\*(aa
+.	if "\\$1"0.8a"  \&\\*(tNNetBSD\\*(aa 0.8a\\*(aa
+.	if "\\$1"0.9"  \&\\*(tNNetBSD\\*(aa 0.9\\*(aa
+.	if "\\$1"0.9a"  \&\\*(tNNetBSD\\*(aa 0.9a\\*(aa
+.	if "\\$1"1.0"  \&\\*(tNNetBSD\\*(aa 1.0\\*(aa
+.	if "\\$1"1.0a"  \&\\*(tNNetBSD\\*(aa 1.0a\\*(aa
+.\}
+..
+.de At
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ds aa \&\f\\n(cF\s\\n(cZ
+.if \\n(.$==2 \{\
+.	if "\\$1"32v" \&Version 32V \\*(tNAT&T UNIX\\*(aa\\$2
+.	if "\\$1"v6"  \&Version 6 \\*(tNAT&T UNIX\\*(aa\\$2
+.	if "\\$1"v7"  \&Version 7 \\*(tNAT&T UNIX\\*(aa\\$2
+.	if "\\$1"V"  \&\\*(tNAT&T\\*(aa System V \\*(tNUNIX\\*(aa\\$2
+.	if "\\$1"V.1"  \&\\*(tNAT&T\\*(aa System V.1 \\*(tNUNIX\\*(aa\\$2
+.	if "\\$1"V.2"  \&\\*(tNAT&T\\*(aa System V.2 \\*(tNUNIX\\*(aa\\$2
+.	if "\\$1"V.4"  \&\\*(tNAT&T\\*(aa System V.4 \\*(tNUNIX\\*(aa\\$2
+.\}
+.if \\n(.$==1 \{\
+.	if "\\$1"32v" \&Version 32V \\*(tNAT&T UNIX\\*(aa
+.	if "\\$1"v6"  \&Version 6 \\*(tNAT&T UNIX\\*(aa
+.	if "\\$1"v7"  \&Version 7 \\*(tNAT&T UNIX\\*(aa
+.	if "\\$1"V"  \&\\*(tNAT&T\\*(aa System V \\*(tNUNIX\\*(aa
+.	if "\\$1"V.1"  \&\\*(tNAT&T\\*(aa System V.1 \\*(tNUNIX\\*(aa
+.	if "\\$1"V.2"  \&\\*(tNAT&T\\*(aa System V.2 \\*(tNUNIX\\*(aa
+.	if "\\$1"V.4"  \&\\*(tNAT&T\\*(aa System V.4 \\*(tNUNIX\\*(aa
+.\}
+..
+.de Bt
+\&is currently in beta test.
+..
+.ds Px \\*(tNPOSIX
+.ds Ai \\*(tNANSI
+.de St
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 \{\
+.tm Usage: .St [-p1003.1-90 | -p1003.2 | -ansiC-89 | -iso ] \\*(Pu ... (#\\n(.c)
+.	\}
+.	el \{\
+.		ds mN St
+.		nr aP 0
+.		ds A1 \\$1
+.		ds A2 \\$2
+.		ds A3 \\$3
+.		ds A4 \\$4
+.		ds A5 \\$5
+.		ds A6 \\$6
+.		ds A7 \\$7
+.		ds A8 \\$8
+.		ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr cF \\n(.f
+.	nr cZ \\n(.s
+.	ds aa \&\f\\n(cF\s\\n(cZ
+.	nr aP \\n(aP+1
+.       if "\\*(A\\n(aP"-p1003.1-90" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.1-1990\\*(sV
+.			as b1 (``\\*(tN\\*(Px\\*(aa'')
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.1-1990\\*(sV
+.			as b1 (``\\*(tN\\*(Px\\*(aa'')
+.		\}
+.       \}
+.       if "\\*(A\\n(aP"-p1003.1-88" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.1-1988\\*(sV
+.			as b1 (``\\*(tN\\*(Px\\*(aa'')
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.1-1988\\*(sV
+.			as b1 (``\\*(tN\\*(Px\\*(aa'')
+.		\}
+.       \}
+.       if "\\*(A\\n(aP"-p1003.1" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.1\\*(sV
+.			as b1 (``\\*(tN\\*(Px\\*(aa'')
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.1\\*(sV
+.			as b1 (``\\*(tN\\*(Px\\*(aa'')
+.		\}
+.       \}
+.       if "\\*(A\\n(aP"-p1003.2-92" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.2-1992\\*(sV
+.			as b1 (``\\*(tN\\*(Px.2\\*(aa'')
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.2-1992\\*(sV
+.			as b1 (``\\*(tN\\*(Px.2\\*(aa'')
+.		\}
+.       \}
+.       if "\\*(A\\n(aP"-p1003.2" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.2\\*(sV
+.			as b1 (``\\*(tN\\*(Px.2\\*(aa'')
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa1003.2\\*(sV
+.			as b1 (``\\*(tN\\*(Px.2\\*(aa'')
+.		\}
+.       \}
+.       if "\\*(A\\n(aP"-ansiC" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNANSI \\*(aaX3.159-1989\\*(sV
+.			as b1 (``\\*(tNANSI C\\*(aa'')
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNANSI \\*(aaX3.159-1989\\*(sV
+.			as b1 (``\\*(tNANSI C\\*(aa'')
+.		\}
+.       \}
+.       if "\\*(A\\n(aP"-ansiC-89" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNANSI \\*(aaX3.159-1989\\*(sV
+.			as b1 (``\\*(tNANSI C\\*(aa'')
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNANSI \\*(aaX3.159-1989\\*(sV
+.			as b1 (``\\*(tNANSI C\\*(aa'')
+.		\}
+.       \}
+.       if "\\*(A\\n(aP"-ieee754" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa754-1985
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNIEEE Std\\*(aa754-1985
+.		\}
+.       \}
+.       if "\\*(A\\n(aP"-iso8802-3" \{\
+.		ie \\n(sT==1 \{\
+.			ds b1 \&\\*(tNISO \\*(aa8802-3: 1989\\*(sV
+.		\}
+.		el \{\
+.			ds b1 \&\\*(tNISO \\*(aa8802-3: 1989\\*(sV
+.		\}
+.       \}
+.	ie \\n(aC>\\n(aP \{\
+.		nr aP \\n(aP+1
+.		nR
+.	\}
+.	el .aZ
+.\}
+..
+.nr Db 0
+.de Db
+.ie \\n(.$==0 \{\
+.	ie \\n(Db==0 \{\
+.tm DEBUGGING ON
+.		nr Db 1
+.	\}
+.	el \{\
+.tm DEBUGGING OFF
+.		nr Db 0
+.	\}
+.\}
+.el \{\
+.	if "\\$1"on" \{\
+.tm DEBUGGING ON
+.		nr Db 1
+.	\}
+.	if "\\$1"off" \{\
+.tm DEBUGGING OFF
+.		nr Db 0
+.	\}
+.\}
+..
+.de aV
+.nr aC \\n(aC+1
+.ie "\\$1"|" \{\
+.	if "\\*(mN"Op" .ds A\\n(aC \fR\\$1\fP
+.	if "\\*(mN"Ar" .ds A\\n(aC \fR\\$1\fP
+.	if "\\*(mN"Fl" .ds A\\n(aC \fR\\$1\fP
+.	if "\\*(mN"Cm" .ds A\\n(aC \fR\\$1\fP
+.	if "\\*(mN"It" .ds A\\n(aC \fR\\$1\fP
+.\}
+.el .ds A\\n(aC \\$1
+.aU \\n(aC
+.nr C\\n(aC \\n(aT
+.s\\n(aT
+.if \\n(Db \{\
+.	if \\n(aT==1 .ds yU Executable
+.	if \\n(aT==2 .ds yU String
+.	if \\n(aT==3 .ds yU Closing Punctuation or suffix
+.	if \\n(aT==4 .ds yU Opening Punctuation or prefix
+.	if \\n(iN==1 \{\
+.		br
+.		nr iI \\n(.iu
+.		in -\\n(iIu
+.		if \\n(aC==1 \{\
+\&\fBDEBUG(argv) MACRO:\fP `.\\*(mN'  \fBLine #:\fP \\n(.c
+.		\}
+\&\t\fBArgc:\fP \\n(aC  \fBArgv:\fP `\\*(A\\n(aC'  \fBLength:\fP \\n(sW
+\&\t\fBSpace:\fP `\\*(S\\n(aC'  \fBClass:\fP \\*(yU
+.	\}
+.	if \\n(iN==0 \{\
+.		if \\n(aC==1 \{\
+.			tm DEBUG(argv) MACRO: `.\\*(mN'  Line #: \\n(.c
+.		\}
+.		tm \tArgc: \\n(aC  Argv: `\\*(A\\n(aC'  Length: \\n(sW
+.		tm \tSpace: `\\*(S\\n(aC'  Class: \\*(yU
+.	\}
+.\}
+.ie \\n(.$==1 \{\
+.	nr aP 0
+.	ie \\n(dZ==1 \{\
+.		if \\n(oM>1 .as b1 \\*(S0
+.	\}
+.	el \{\
+.		if \\n(oM>0 \{\
+.			if \\n(fC==0 .as b1 \\*(S0
+.		\}
+.	\}
+.	ds S0 \\*(S\\n(aC
+.	if \\n(Db \{\
+.		if \\n(iN==1 \{\
+\&MACRO REQUEST: \t.\\*(mN \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+.			br
+.			in \\n(iIu
+.		\}
+.		if \\n(iN==0 \{\
+.tm \tMACRO REQUEST: .\\*(mN \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+.		\}
+.	\}
+.\}
+.el .aV \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de fV
+.nr aC \\n(aC+1
+.if "\\*(A\\n(aC"|" \{\
+.	if "\\*(mN"Op" .ds A\\n(aC \fR\\*(A\\n(aC\fP
+.	if "\\*(mN"Ar" .ds A\\n(aC \fR\\*(A\\n(aC\fP
+.	if "\\*(mN"Fl" .ds A\\n(aC \fR\&\\*(A\\n(aC\fP
+.	if "\\*(mN"Cm" .ds A\\n(aC \fR\\*(A\\n(aC\fP
+.	if "\\*(mN"It" .ds A\\n(aC \fR\\*(A\\n(aC\fP
+.\}
+.aU \\n(aC
+.nr C\\n(aC \\n(aT
+.s\\n(aT
+.if \\n(Db \{\
+.	if \\n(aT==1 .ds yU Executable
+.	if \\n(aT==2 .ds yU String
+.	if \\n(aT==3 .ds yU Closing Punctuation or suffix
+.	if \\n(aT==4 .ds yU Opening Punctuation or prefix
+.	if \\n(iN==1 \{\
+.		br
+.		nr iI \\n(.iu
+.		in -\\n(iIu
+.		if \\n(aC==1 \{\
+\&\fBDEBUG(fargv) MACRO:\fP `.\\*(mN'  \fBLine #:\fP \\n(.c
+.		\}
+\&\t\fBArgc:\fP \\n(aC  \fBArgv:\fP `\\*(A\\n(aC'  \fBLength:\fP \\n(sW
+\&\t\fBSpace:\fP `\\*(S\\n(aC'  \fBClass:\fP \\*(yU
+.	\}
+.	if \\n(iN==0 \{\
+.		if \\n(aC==1 \{\
+.			tm DEBUG(fargv) MACRO: `.\\*(mN'  Line #: \\n(.c
+.		\}
+.		tm \tArgc: \\n(aC  Argv: `\\*(A\\n(aC'  Length: \\n(sW
+.		tm \tSpace: `\\*(S\\n(aC'  Class: \\*(yU
+.	\}
+.\}
+.ie \\n(fV==1 \{\
+.	nr aP 0
+.	ie \\n(dZ==1 \{\
+.		if \\n(oM>1 .as b1 \\*(S0
+.	\}
+.	el \{\
+.		if \\n(oM>0 \{\
+.			if \\n(fC==0 .as b1 \\*(S0
+.		\}
+.	\}
+.	ds S0 \\*(S\\n(aC
+.	nr fV 0
+.	if \\n(Db \{\
+.		ie \\n(iN \{\
+\&\tMACRO REQUEST: .\\*(mN \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+.			br
+.			in \\n(iIu
+.		\}
+.		el \{\
+.tm \tMACRO REQUEST: .\\*(mN \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+.		\}
+.	\}
+.\}
+.el \{\
+.	nr fV \\n(fV-1
+.	fV
+.\}
+..
+.de aX
+.nr aP \\n(aP+1
+.as b1 \&\\*(A\\n(aP
+.ie \\n(fV==1 \{\
+.	nr aP 0
+.	nr fV 0
+.\}
+.el \{\
+.	as b1 \&\\*(sV
+.	nr fV \\n(fV-1
+.	aX
+.\}
+..
+.de aI
+.ie \\n(aC<9 \{\
+.	nr aC \\n(aC+1
+.	ds A\\n(aC \\$1
+.	nr C\\n(aC \\$2
+.	s\\$2
+.	ds xV S\\n(aC
+.\}
+.el \{\
+.	tm Usage: Too many arguments (maximum of 8 accepted) (#\\n(.c)
+.	tm \\*(A1 \\*(A2 \\*(A3 \\*(A4 \\*(A5 \\*(A6 \\*(A7 \\*(A8 \\*(A9
+.\}
+..
+.de aZ
+.pB
+.aY
+..
+.de aY
+.rm C0 C1 C2 C3 C4 C5 C6 C7 C8 C9
+.rm A0 A1 A2 A3 A4 A5 A6 A7 A8 A9
+.rm S1 S2 S3 S4 S5 S6 S7 S8 S9
+.nr aC 0
+.nr aP 0
+..
+.de pB
+.ie \\n(dZ==1 \{\
+.	if \\n(oM==1 \{\&\\*(b1
+.		rm S0
+.		ds b1
+.	\}
+.	if \\n(oM==0 \{\
+.		x2
+.	\}
+.\}
+.el \{\
+.	ie \\n(oM==0 \{\&\\*(b1
+.		rm S0
+.		ds b1
+.	\}
+.	el \{\
+.		if ((\\n(sM==1)&(\\n(tP==0)) \{\
+.			x1
+.		\}
+.	\}
+.\}
+.hy
+..
+.de x1
+.nr dZ \\n(dZ+1
+.ds b2 \\*(b1
+.ds b1
+.nr lK \\n(.c
+.ev 2
+.fi
+.di eB
+..
+.de x2
+.br
+.di
+.ev
+.ie (\\n(.c-\\n(lK>1) \{\
+.	ds b0 \&\\*(eB\\
+.	ds b1 \\*(b2\\*(b0\\*(b1
+.\}
+.el .ds b1 \\*(b2\\*(b1
+\&\\*(b1
+.rm eB b2 b0 b1
+.nr dZ \\n(dZ-1
+..
+.de Fl
+.as b1 \&\\*(fL
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 \{\
+.		as b1 \&\|\-\|\fP\s0
+.		pB
+.	\}
+.	el \{\
+.		ds mN Fl
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>0 \{\
+.	ie (\\n(aC-\\n(aP)==0 \{\
+.		as b1 \&\|\-\fP\s0
+.		aZ
+.	\}
+.	el \{\
+.		nr aP \\n(aP+1
+.		ie \\n(C\\n(aP==1 \{\
+.			as b1 \&\|\-\fP\s0
+.			\\*(A\\n(aP
+.		\}
+.		el \{\
+.			nr cF \\n(.f
+.			nr cZ \\n(.s
+.			if \\n(C\\n(aP==3 \{\
+.				as b1 \&\|\-\|
+.			\}
+.			fR
+.		\}
+.	\}
+.\}
+..
+.de fR
+.hy 0
+.nr jM \\n(C\\n(aP
+.ie \\n(jM==1 \{\
+.	as b1 \&\fP\s0
+.	\\*(A\\n(aP
+.\}
+.el \{\
+.	nr jN \\n(aP
+.	ie \\n(jM==2 \{\
+.		ie !"\\*(A\\n(aP"\\*(Ba" \{\
+.			ie !"\\*(A\\n(aP"\fR|\fP" \{\
+.		               ie "\\*(A\\n(aP"-" .as b1 \&\|\-\^\-\|
+.		               el .as b1 \&\|\-\\*(A\\n(aP
+.			\}
+.			el .as b1 \&\\*(A\\n(aP
+.		\}
+.		el .as b1 \&\\*(A\\n(aP
+.	\}
+.	el .as b1 \&\f\\n(cF\s\\n(cZ\\*(A\\n(aP\fP\s0
+.	ie \\n(aC==\\n(aP \{\
+.		if \\n(jM==4 .as b1 \&\|\-
+.		as b1 \&\fP\s0
+.		aZ
+.	\}
+.	el \{\
+.		nr aP \\n(aP+1
+.		ie ((\\n(C\\n(aP==3)&(\\n(C\\n(jN==4)) .as b1 \&\|\-
+.		el .as b1 \&\\*(S\\n(jN
+.		fR \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.rr jM jN
+..
+.de nR
+.hy 0
+.nr jM \\n(C\\n(aP
+.ie \\n(jM==1 \{\
+.	as b1 \&\f\\n(cF\s\\n(cZ
+.	\\*(A\\n(aP
+.\}
+.el \{\
+.	nr jN \\n(aP
+.	ie \\n(jM==2 .as b1 \&\\*(A\\n(aP
+.	el .as b1 \&\f\\n(cF\s\\n(cZ\\*(A\\n(aP\fP\s0
+.	ie \\n(aC==\\n(aP \{\
+.		as b1 \&\f\\n(cF\s\\n(cZ
+.		aZ
+.	\}
+.	el \{\
+.		nr aP \\n(aP+1
+.		as b1 \&\\*(S\\n(jN
+.		nR
+.	\}
+.\}
+.rr jM jN
+..
+.de Ar
+.as b1 \\*(aR
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 \{\
+.		as b1 file\ ...\fP\s0
+.		pB
+.	\}
+.	el \{\
+.		ds mN Ar
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>0 \{\
+.	ie (\\n(aC-\\n(aP)==0 \{\
+.		as b1 \&file\ ...\fP\s0
+.		aZ
+.	\}
+.	el \{\
+.		nr aP \\n(aP+1
+.		ie \\n(C\\n(aP==1 \{\
+.			as b1 \&file\ ...\fP\s0
+.			\\*(A\\n(aP
+.               \}
+.               el \{\
+.                       nr cF \\n(.f
+.			nr cZ \\n(.s
+.			if \\n(C\\n(aP==3 \{\
+.				as b1 \&file\ ...
+.			\}
+.                       nR
+.		\}
+.       \}
+.\}
+..
+.de Ad
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Ad address ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Ad
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(aD
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Cd
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Cd Configuration file declaration (#\\n(.c)
+. 	el \{\
+.		ds mN Cd
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+. 		nr fV \\n(.$
+. 		fV
+.	\}
+.\}
+.br
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(nM
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.	ie \\n(nS \{\
+.		if "\\*(mN"Cd" \{\
+.			rs
+.			ie \\n(nS>1 .br
+.			el \{\
+.				if \\n(iS==0 .nr iS \\n(Dsu
+.			\}
+.			in +\\n(iSu
+.			ti -\\n(iSu
+.			nr nS \\n(nS+1
+.		\}
+.	nR
+.	in -\\n(iSu
+.	\}
+.	el .nR
+.\}
+..
+.de Cm
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Cm Interactive command modifier ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Cm
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(cM
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Dv
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Dv define_variable ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Dv
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(eR
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Em
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 \{\
+.		tm Usage: .Em text ... \\*(Pu (#\\n(.c)
+.	\}
+.	el \{\
+.		ds mN Em
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(eM
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Er
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Er ERRNOTYPE ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Er
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(eR
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Ev
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Ev ENVIRONMENT_VARIABLE ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Ev
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(eV
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Fd
+.ds mN Fd
+.if \\n(nS>0 \{\
+.	if \\n(fX>0 \{\
+.		Pp
+.		nr fX 0
+.	\}
+.	if \\n(fZ>0 \{\
+.		ie \\n(fD==0 \{\
+.			Pp
+.			rs
+.		\}
+.		el .br
+.	\}
+.	nr fD \\n(fD+1
+.\}
+.nr cF \\n(.f
+.nr cZ \\n(.s
+\&\\*(fD\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.br
+.ft \\n(cF
+.fs \\n(cZ
+..
+.de Fr
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Fr Function_return_value... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Fr
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(aR
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Ic
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Ic Interactive command ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Ic
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(iC
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Li
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage .Li argument ... \\*(Pu (#\\n(.c)
+.       el \{\
+.		ds mN Li
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.               nr fV \\n(.$
+.               fV
+.       \}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(lI
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Or
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Or ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Or
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(iC
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Ms
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Ms Math symbol ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Ms
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(sY
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Nm
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 \{\
+.		ie "\\*(n1"" .tm Usage: .Nm Name(s) ... \\*(Pu (#\\n(.c)
+.		el \&\\*(nM\\*(n1\fP\s0
+.	\}
+.	el \{\
+.		ds mN Nm
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.               nr fV \\n(.$
+.               fV
+.       \}
+.\}
+.if \\n(aC>0 \{\
+.	ie \\n(aC==\\n(aP \{\
+.		as b1 \&\\*(nM\\*(n1\fP\s0
+.		aZ
+.	\}
+.	el \{\
+.		as b1 \\*(nM
+.		nr aP \\n(aP+1
+.		ie \\n(C\\n(aP==1 \{\
+.			as b1 \&\\*(n1\fP\s0
+.			\\*(A\\n(aP
+.		\}
+.		el \{\
+.			nr cF \\n(.f
+.			nr cZ \\n(.s
+.			if \\n(nS \{\
+.				if "\\*(mN"Nm" \{\
+.					rs
+.					in -\\n(iSu
+.					ie \\n(nS>1 .br
+.					el \{\
+.						if \\n(iS==0 \{\
+.							sw \\$1
+.					nr iS ((\\n(sWu+1)*\\n(fW)u
+.						\}
+.					\}
+.					in +\\n(iSu
+.					ti -\\n(iSu
+.					nr nS \\n(nS+1
+.				\}
+.			\}
+.			if "\\*(n1"" .ds n1 \\*(A\\n(aP
+.			nR
+.		\}
+.	\}
+.\}
+..
+.de Pa
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 \&\\*(pA~\fP\s0
+.	el \{\
+.		ds mN Pa
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(pA
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Sy
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Sy symbolic_text ... \\*(Pu (#\\n(.c)
+. 	el \{\
+.		ds mN Sy
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+. 		nr fV \\n(.$
+. 		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(sY
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Tn
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Tn Trade_name(s) ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Tn
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(tN\\*(tF
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de nN
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Tn Trade_name(s) ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Tn
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(tN
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de Va
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Va variable_name(s) ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Va
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	as b1 \\*(vA
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de No
+.as b1 \\*(nO
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 .tm Usage: .No must be called with arguments (#\\n(.c)
+.	el \{\
+.		ds mN No
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       ie \\n(C\\n(aP==1 \{\
+.		\\*(A\\n(aP
+.       \}
+.       el \{\
+.		nr cF \\n(.f
+.		nr cZ \\n(.s
+.		nR
+.       \}
+.\}
+..
+.de Op
+.if \\n(aC==0 \{\
+.	ds mN Op
+.\}
+.ds qL \&\\*(lB
+.ds qR \&\\*(rB
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+..
+.de Aq
+.if \\n(aC==0 .ds mN Aq
+.ds qL \&<
+.ds qR \&>
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Bq
+.if \\n(aC==0 .ds mN Bq
+.ds qL \&\\*(lB
+.ds qR \&\\*(rB
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Dq
+.if \\n(aC==0 .ds mN Dq
+.ds qL \&\\*(Lq
+.ds qR \&\\*(Rq
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Eq
+.if \\n(aC==0 .ds mN Eq
+.ds qL \\$1
+.ds qR \\$2
+.En \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Pq
+.if \\n(aC==0 .ds mN Pq
+.ds qL \&\\*(lP
+.ds qR \&\\*(rP
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Qq
+.if \\n(aC==0 .ds mN Qq
+.ds qL \&\\*q
+.ds qR \&\\*q
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Sq
+.if \\n(aC==0 .ds mN Sq
+.ds qL \&\\*(sL
+.ds qR \&\\*(sR
+.En \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Es
+.if \\n(aC==0 \{\
+.	ie \\n(.$>2 .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	el \{\
+.		ds qL \\$1
+.		ds qR \\$2
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.	ds qL \\*(A\\n(aP
+.	nr aP \\n(aP+1
+.	ds qR \\*(A\\n(aP
+.	ie \\n(aC>\\n(aP .c\\n(C\\n(aP
+.	el .aZ
+.\}
+..
+.de En
+.ie \\n(aC==0 \{\
+.	ie \\n(.$==0 \{\
+.		as b1 \&\\*(qL\\*(qR
+.		pB
+.	\}
+.	el \{\
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.		as b1 \&\\*(qL
+.	\}
+.\}
+.el \{\
+.	as b1 \&\\*(qL
+.\}
+.if \\n(aC>0 \{\
+.	ie (\\n(aC-\\n(aP)==0 \{\
+.		as b1 \&\\*(qR
+.		aZ
+.	\}
+.	el \{\
+.		ie \\n(C\\n(aC==3 \{\
+.			nr aJ \\n(aC-1
+.			vR
+.			nr aJ \\n(aJ+1
+.			ds A\\n(aJ \&\\*(qR\\*(A\\n(aJ
+.			nr aJ 0
+.		\}
+.		el .aI \&\\*(qR 3
+.		nr aP \\n(aP+1
+.		if \\n(C\\n(aP==1 .\\*(A\\n(aP
+.		if \\n(C\\n(aP>1 \{\
+.			nr aP \\n(aP-1
+.			No
+.		\}
+.	\}
+.\}
+..
+.de vR
+.if \\n(C\\n(aJ==3 \{\
+.	nr aJ \\n(aJ-1
+.	vR
+.\}
+..
+.de Ao
+.if \\n(aC==0 .ds mN Ao
+.ds qL \&<
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Ac
+.if \\n(aC==0 .ds mN Ac
+.ds qR \&>
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Bo
+.if \\n(aC==0 .ds mN Bo
+.ds qL \&[
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Bc
+.if \\n(aC==0 .ds mN Bc
+.ds qR \&]
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Do
+.if \\n(aC==0 .ds mN Do
+.ds qL \&\\*(Lq
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Dc
+.if \\n(aC==0 .ds mN Dc
+.ds qR \&\\*(Rq
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Eo
+.if \\n(aC==0 .ds mN Eo
+.ds qL \\$1
+.eO \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Ec
+.if \\n(aC==0 .ds mN Ec
+.ds qR \\$1
+.eC \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Oo
+.if \\n(aC==0 .ds mN Oo
+.ds qL \&[
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Oc
+.if \\n(aC==0 .ds mN Oc
+.ds qR \&]
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Po
+.if \\n(aC==0 .ds mN Po
+.ds qL \&(
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Pc
+.if \\n(aC==0 .ds mN Pc
+.ds qR \&)
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Qo
+.if \\n(aC==0 .ds mN Qo
+.ds qL \&\\*q
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Qc
+.if \\n(aC==0 .ds mN Qc
+.ds qR \&\\*q
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de So
+.if \\n(aC==0 .ds mN So
+.ds qL \&\\*(sL
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Sc
+.if \\n(aC==0 .ds mN Sc
+.ds qR \&\\*(sR
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Xo
+.if \\n(aC==0 .ds mN Xo
+.ds qL
+.eO \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Xc
+.if \\n(aC==0 .ds mN Xc
+.ds qR
+.eC \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de eO
+.nr oM \\n(oM+1
+.ie \\n(aC==0 \{\
+.       ie \\n(.$>0 \{\
+.               aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.		as b1 \\*(qL
+.       \}
+.	el \{\
+.		as b1 \\*(qL
+.		if (\\n(dZ==0)&(\\n(sM==1) \{\
+.			nr dZ \\n(dZ+1
+.			ds b2 \\*(b1
+.			ds b1
+.			nr lK \\n(.c
+.			ev 2
+.			fi
+.			di eB
+.		\}
+.	\}
+.\}
+.el \{\
+.	as b1 \\*(qL
+.\}
+.ie \\n(aC>0 \{\
+.	if \\n(aC>\\n(aP \{\
+.		nr aP \\n(aP+1
+.		ie \\n(C\\n(aP==1 .\\*(A\\n(aP
+.		el  \{\
+.			nr aP \\n(aP-1
+.			No
+.		\}
+.	\}
+.	if \\n(aC==\\n(aP \{\
+.		if \\n(tP==1 \{\
+.			nr Xt 1
+.		\}
+.		aY
+.	\}
+.\}
+.el \{\
+.	if \\n(oM>1 .as b1 \\*(sV
+.\}
+..
+.de eC
+.nr oM \\n(oM-1
+.as b1 \\*(qR
+.if \\n(aC==0 \{\
+.       ie \\n(.$>0 \{\
+.               aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.       \}
+.	el \{\
+.		ie "\\*(xB"" \{\
+.			pB
+.		\}
+.		el \{\
+.			pB
+.\\*(L\\n(lC
+.			nr Xt 0
+.			ds xB
+.		\}
+.	\}
+.\}
+.if \\n(aC>0 \{\
+.	ie \\n(aC==\\n(aP \{\
+.		ie \\n(oM==0 \{\
+.			aZ
+.		\}
+.		el .aY
+.	\}
+.	el \{\
+.		nr aa \\n(aP+1
+.		if \\n(C\\n(aa==2 .as b1 \\*(S\\n(aC
+.		rr aa
+.		if \\n(tP>0 \{\
+.			if \\n(Xt>0 .nr Xt \\n(Xt-1
+.		\}
+.		No
+.	\}
+.\}
+..
+.de Pf
+.if \\n(aC==0 .ds mN Pf
+.ds qL \&\\$1
+.pF \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de pF
+.ie \\n(aC==0 \{\
+.	as b1 \&\\*(qL
+.	ie \\n(.$<2 \{\
+.		tm Warning: Missing arguments - prefix .Pf)
+.		pB
+.	\}
+.	el .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+.el \{\
+.	ie (\\n(aC-\\n(aP)>1 \{\
+.		nr aP \\n(aP+1
+.		as b1 \&\\*(A\\n(aP
+.	\}
+.	el .tm Warning: .Pf: trailing prefix (#\\n(.c)
+.\}
+.if \\n(aC>0 \{\
+.	ie (\\n(aC-\\n(aP)==0 .aZ
+.	el \{\
+.		nr aP \\n(aP+1
+.		c\\n(C\\n(aP
+.	\}
+.\}
+..
+.de Ns
+.if \\n(aC==0 \{\
+.	ds mN Ns
+.	ie \\n(.$>0 .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	el .tm Usage: .Ns must be called with arguments (#\\n(.c)
+.\}
+.No
+..
+.de Ap
+.if \\n(aC==0 \{\
+.	ds mN Ap
+.	tm Usage: Ap "cannot be first request on a line (no .Ap)" (#\\n(.c)
+.\}
+.as b1 \&'
+.No
+..
+.de Hv
+.ds iV \\*(sV
+.ds sV \\*(hV
+..
+.de Sv
+.ds sV \\*(iV
+..
+.de Tv
+.ds sV \\*(tV
+..
+.nr sM 1
+.de Sm
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 .tm "Usage: .Sm [off | on]" (#\\n(.c)
+.	el \{\
+.		ds mN Sm
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>0 \{\
+.	nr aP \\n(aP+1
+.	if "\\*(A\\n(aP"on" \{\
+.		ds sV \\*(iV
+.		nr sM 1
+.	\}
+.	if "\\*(A\\n(aP"off" \{\
+.		ds sV
+.		rm S0 S1 S2 S3 S4 S5 S6 S7 S8 S9
+.		nr sM 0
+.	\}
+.	ie \\n(aC>\\n(aP \{\
+.		No
+.	\}
+.	el .aY
+.\}
+..
+.if \n(.g \{\
+.de aT
+.nr aT 0
+.ie \\n(sW>2:(\A'\\$1'==0) \{\
+.	nr aT 2
+.\}
+.el \{\
+.	if \\n(sW==1 \{\
+.		ie \\n(z\\$1>2 \{\
+.			nr aT \\n(z\\$1
+.		\}
+.		el .nr aT 2
+.	\}
+.	if \\n(sW==2 \{\
+.		ie \\n(\\$1 \{\
+.			nr aT 1
+.		\}
+.		el .nr aT 2
+.	\}
+.\}
+..
+.de aU
+.nr aT 0
+.aW \\$1
+.ie \\n(sW>2:(\A'\\*(A\\$1'==0) .nr aT 2
+.el \{\
+.	if \\n(sW==1 \{\
+.		ie \\n(z\\*(A\\$1>2 \{\
+.			nr aT \\n(z\\*(A\\$1
+.		\}
+.		el .nr aT 2
+.	\}
+.	if \\n(sW==2 \{\
+.		ie (\\n(\\*(A\\$1) \{\
+.			nr aT 1
+.		\}
+.		el .nr aT 2
+.	\}
+.\}
+..
+.\}
+.if !\n(.g \{\
+.de aT
+.nr aT 0
+.ie \\n(sW>2 \{\
+.	nr aT 2
+.\}
+.el \{\
+.	if \\n(sW==1 \{\
+.		ie \\n(z\\$1>2 \{\
+.			nr aT \\n(z\\$1
+.		\}
+.		el .nr aT 2
+.	\}
+.	if \\n(sW==2 \{\
+.		ie \\n(\\$1 \{\
+.			nr aT 1
+.		\}
+.		el .nr aT 2
+.	\}
+.\}
+..
+.de aU
+.nr aT 0
+.aW \\$1
+.ie \\n(sW>2 .nr aT 2
+.el \{\
+.	if \\n(sW==1 \{\
+.		ie \\n(z\\*(A\\$1>2 \{\
+.			nr aT \\n(z\\*(A\\$1
+.		\}
+.		el .nr aT 2
+.	\}
+.	if \\n(sW==2 \{\
+.		ie (\\n(\\*(A\\$1) \{\
+.			nr aT 1
+.		\}
+.		el .nr aT 2
+.	\}
+.\}
+..
+.\}
+.de s0
+.tm MDOC-ERROR: bogus type 0 (can't set space '\\*(A\\n(aC') (#\\n(.c)
+..
+.de s1
+.if \\n(\\*(A\\n(aC==3 \{\
+.	nr xX \\n(aC-1
+.	rm S\\n(xX
+.	ds S\\n(aC \\*(sV
+.\}
+.if \\n(\\*(A\\n(aC==2 \{\
+.	nr xX \\n(aC-1
+.	ie "\\*(A\\n(aC"Nb" .ds S\\n(xX \\*(hV
+.	el .rm S\\n(xX
+.\}
+..
+.de s2
+.ds S\\n(aC \\*(sV
+..
+.de s3
+.if \\n(aC>1 \{\
+.	nr xX \\n(aC-1
+.	rm S\\n(xX
+.\}
+.ds S\\n(aC \\*(sV
+..
+.de s4
+.nr aa 0
+..
+.de c0
+.tm MDOC-ERROR: bogus class 0 (can't determine '\\*(A\\n(aC') (#\\n(.c)
+..
+.de c1
+.\\*(A\\n(aP
+..
+.de c2
+.nr aP \\n(aP-1
+.No
+..
+.de c3
+.nr aP \\n(aP-1
+.No
+..
+.de c4
+.nr aP \\n(aP-1
+.No
+..
+.de y1
+.nr aa 1
+..
+.de y2
+.nr aa 1
+..
+.de y3
+.as b1 \\*(A\\n(aP
+.nr aP \\n(aP+1
+.n\\C\\n(aP
+..
+.de y4
+.as b1 \\*(A\\n(aP
+.nr aP \\n(aP+1
+.n\\C\\n(aP
+..
+.de Bf
+.ds mN Bf
+.ie \\n(.$>0 \{\
+.	nr bF \\n(.f
+.	nr bZ \\n(.s
+.	if "\\$1"Em" \&\\*(eM\c
+.	if "\\$1"Li" \&\\*(lI\c
+.	if "\\$1"Sy" \&\\*(sY\c
+.	if "\\$1"-emphasis" \&\\*(eM\c
+.	if "\\$1"-literal" \&\\*(lI\c
+.	if "\\$1"-symbolic" \&\\*(sY\c
+.\}
+.el .tm Usage .Bf [Em | emphasis | Li | literal | Sy | symbolic] (#\\n(.c)
+..
+.de Ef
+.ds mN Ef
+.ie \\n(.$>0 .tm Usage .Ef (does not take arguments) (#\\n(.c)
+.el \&\f\\n(bF\s\\n(bZ
+..
+.de Bk
+.ds mN Bk
+.ie \\n(.$==0 \{\
+.tm Usage: .Bk [-lines | -words] (#\\n(.c)
+.\}
+.el \{\
+.	if !"\\*(kS"" .tm .Bk: nesting keeps not implemented yet. (#\\n(.c)
+.	if "\\$1"-lines" .tm .Bd -lines: Not implemented yet. (#\\n(.c)
+.	if "\\$1"-words" .Hv
+.	ds kS \\$1
+.\}
+..
+.de Ek
+.ds mN Ek
+.ie \\n(.$>0 .tm Usage .Ek (does not take arguments) (#\\n(.c)
+.el \{\
+.	if "\\*(kS"-lines" .tm .Bd -lines: Not implemented yet. (#\\n(.c)
+.	if "\\*(kS"-words" .Sv
+.	rm kS
+.\}
+..
+.de Bd
+.ds mN Bd
+.ie \\n(.$==0 \{\
+.tm Usage: .Bd [-literal | -filled | -ragged | -unfilled] [-offset [string]] [-compact] (#\\n(.c)
+.\}
+.el \{\
+.	ds aa
+.	nr bV 0
+.       nr iD 0
+.	nr dP \\n(dP+1
+.       if "\\$1"-literal" \{\
+.		nr iD \\n(iD+1
+.               ds d\\n(dP dL
+.		nr cF \\n(.f
+.		nr cZ \\n(.s
+.		ie t \{\&\\*(lI
+'			ta 9n 18n 27n 36n 45n 54n 63n 72n
+.		\}
+.		el \{\
+'			ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
+.		\}
+.		nf
+.       \}
+.       if "\\$1"-filled" \{\
+.		nr iD \\n(iD+1
+.               ds d\\n(dP dF
+.		br
+.       \}
+.       if "\\$1"-ragged" \{\
+.		nr iD \\n(iD+1
+.               ds d\\n(dP dR
+.		na
+.       \}
+.       if "\\$1"-unfilled" \{\
+.		nr iD \\n(iD+1
+.               ds d\\n(dP dU
+.		nf
+.       \}
+.       if ((\\n(iD>=1)&(\\n(.$>\\n(iD)) \{\
+.		bV \\$2 \\$3 \\$4
+.	\}
+.	if \\n(O\\n(dP>0 'in \\n(.iu+\\n(O\\n(dPu
+.	if (\\n(bV==0) \{\
+.		if (\\n(nS==0) \{\
+.			ie "\\*(d\\n(dP"dR" .sp \\n(dVu
+.			el 'sp \\n(dVu
+.		\}
+.	\}
+.	if \\n(cR==0 .ne 2v
+.	nr bV 0
+.	nr iD 0
+.\}
+..
+.de bV
+.nr iD 1
+.ds bY
+.if "\\$1"-offset" \{\
+.	ds bY \\$2
+.	if "\\*(bY"left" \{\
+.		nr iD \\n(iD+1
+.		nr O\\n(dP 0
+.	\}
+.	if "\\*(bY"right" \{\
+.		nr iD \\n(iD+1
+.		nr O\\n(dP (\\n(.l/3)u
+.	\}
+.	if "\\*(bY"center" \{\
+.		nr iD \\n(iD+1
+.		nr O\\n(dP (\\n(.l-\\n(.i)/4u
+.	\}
+.	if "\\*(bY"indent" \{\
+.		nr iD \\n(iD+1
+.		nr O\\n(dP \\n(dIu
+.	\}
+.	if "\\*(bY"indent-two" \{\
+.		nr iD \\n(iD+1
+.		nr O\\n(dP \\n(dIu+\\n(dIu
+.	\}
+.	if \\n(iD==1 \{\
+.		nr iD \\n(iD+1
+.		sW "\\*(bY"
+.		ie \\n(sW>2 \{\
+.			ie ((\\*(bY>9n)&(\\*(bY<100n)) \{\
+.				nr O\\n(dP \\*(bY
+.			\}
+.			el .nr O\\n(dP (\\n(sW)*\\n(fWu
+.		\}
+.		el \{\
+.			if \\n(sW==2 .aT \\*(bY
+.			ie \\n(aT==1 \{\
+.				nr O\\n(dP \\n(\\*(bY
+.			\}
+.			el .nr O\\n(dP \\*(bY
+.		\}
+.	\}
+.\}
+.if "\\$1"-compact" \{\
+.	nr bV 1
+.\}
+.if \\n(iD<\\n(.$ \{\
+.	ie "\\*(bY"" \{\
+.		bV \\$2 \\$3
+.	\}
+.	el \{\
+.		bV \\$3
+.	\}
+.\}
+..
+.de Ed
+.ds mN Ed
+.br
+.if \\n(dP==0 .tm mdoc: Extraneous .Ed
+.if "\\*(d\\n(dP"dL" \{\
+.	ft \\n(cF
+.	fz \\n(cZ
+.\}
+.in \\n(.iu-\\n(O\\n(dPu
+.rr O\\n(dP
+.rm d\\n(dP
+.nr dP \\n(dP-1
+.fi
+.if t .ad
+..
+.de Bl
+.ie \\n(.$==0 \{\
+.tm Usage: .Bl [[-hang | -tag] [-width]] [ -item | -enum | -bullet | -diag] (#\\n(.c)
+.\}
+.el \{\
+.	ds mN Bl
+.	nr aP 0
+.	nr lC \\n(lC+1
+.	ds A1 \\$2
+.	ds A2 \\$3
+.	ds A3 \\$4
+.	ds A4 \\$5
+.	ds A5 \\$6
+.	ds A6 \\$7
+.	ds A7 \\$8
+.	ds A8 \\$9
+.	nr fV \\n(.$-1
+.	if "\\$1"-hang" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC hL
+.		nr w\\n(lC 6n
+.		nr tC  1
+.	\}
+.	if "\\$1"-tag" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC tL
+.		nr tC  1
+.	\}
+.	if "\\$1"-item" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC iT
+.		nr tC  1
+.	\}
+.	if "\\$1"-enum" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC nU
+.		nr w\\n(lC 3n
+.		nr tC  1
+.	\}
+.	if "\\$1"-bullet" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC bU
+.		nr w\\n(lC 2n
+.		nr tC  1
+.	\}
+.	if "\\$1"-dash" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC hU
+.		nr w\\n(lC 2n
+.		nr tC  1
+.	\}
+.	if "\\$1"-hyphen" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC hU
+.		nr w\\n(lC 2n
+.		nr tC  1
+.	\}
+.	if "\\$1"-inset" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC lL
+.		nr tC  1
+.	\}
+.	if "\\$1"-diag" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC mL
+.		nr mL 1
+.	\}
+.	if "\\$1"-ohang" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC oL
+.		nr tC 1
+.	\}
+.	if "\\$1"-column" \{\
+.		nr aP \\n(aP+1
+.		ds L\\n(lC cL
+.	\}
+.	ie \\n(aP==0 \{\
+.	tm \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	tm Usage: .Bl [[-inset|-tag] -width] [-item|-enum|-bullet|-diag] (#\\n(.c)
+.	\}
+.	el \{\
+.		tY
+.		if (\\n(aP==1)&(\\n(aP<\\n(.$) \{\
+.			nr aP 0
+.			lV
+.			if "\\*(L\\n(lC"cL" \{\
+.				W\\n(wV
+.				nr w\\n(lC 0
+'				in -\\n(eWu
+.				ie \\n(v\\n(lC==1 \{\
+.				       nr aa 0
+.				\}
+.				el \{\
+.					sp \\n(dVu
+.				\}
+.				nf
+.				nr wV 0
+.			\}
+.		\}
+.	\}
+.	nr aP 0
+.	aY
+.\}
+..
+.if \n(.g \{\
+.	nr i 10
+.	while \ni<100 \{\
+.	     nr num!\nin 1
+.	     nr i +1
+.	\}
+.\}
+.de lV
+.nr aP \\n(aP+1
+.if \\n(fV>=\\n(aP \{\
+.	nr iD 0
+.	if "\\*(A\\n(aP"-compact" \{\
+.		nr iD 1
+.		nr v\\n(lC 1
+.	\}
+.	if "\\*(A\\n(aP"-width" \{\
+.		nr iD 1
+.		nr aP \\n(aP+1
+.		nr tW 1
+.		ds t\\n(lC TagwidtH
+.		ds tS \\*(A\\n(aP
+.		aW \\n(aP
+.		ie \\n(sW>2 \{\
+.			nr w\\n(lC (\\n(sW)*\\n(fWu
+.			if \\n(sW==3 \{\
+.				ie \\n(.g \{\
+.					if \A'\\*(tS' .if r num!\\*(tS \{\
+.						nr w\\n(lC \\*(tS
+.					\}
+.				\}
+.				el \{\
+.					if (\\*(tS>9n)&(\\*(tS<99n) \{\
+.						nr w\\n(lC \\*(tSu
+.					\}
+.				\}
+.			\}
+.		\}
+.		el \{\
+.			aT \\*(tS
+.			ie \\n(aT==1 \{\
+.				nr w\\n(lC \\n(\\*(tS
+.			\}
+.			el \{\
+.				nr w\\n(lC \\*(tSu
+.			\}
+.		\}
+.	\}
+.	if "\\*(A\\n(aP"-offset" \{\
+.		nr iD 1
+.		nr aP \\n(aP+1
+.		ie "\\*(A\\n(aP"indent" \{\
+.			nr o\\n(lC \\n(Dsu
+.		\}
+.		el \{\
+.			ds tS \\*(A\\n(aP
+.			aW \\n(aP
+.			ie \\n(sW>2 \{\
+.				nr o\\n(lC (\\n(sW)*\\n(fWu
+.				ie \\n(.g \{\
+.					if \A'\\*(tS' .if r num!\\*(tS \{\
+.						nr o\\n(lC \\*(tS
+.					\}
+.				\}
+.				el \{\
+.					if (\\*(tS>9n)&(\\*(tS<100n) \{\
+.						nr o\\n(lC \\*(tS
+.					\}
+.				\}
+.			\}
+.			el \{\
+.				ie \\n(C\\n(aP==1 .nr o\\n(lC \\n(\\*(tS
+.				el .nr o\\n(lC \\*(tS
+.			\}
+.		\}
+.	\}
+.	if \\n(iD==0 \{\
+.		if "\\*(L\\n(lC"cL" \{\
+.			nr wV \\n(wV+1
+.			ds A\\n(wV \\*(A\\n(aP
+.		\}
+.	\}
+.	if \\n(fV>\\n(aP .lV
+.\}
+..
+.de El
+.ie \\n(.$>0 \{\
+.	tm Usage: .El (#\\n(.c)
+.\}
+.el \{\
+.	ds mN El
+.	nr iD 0
+.	if "\\*(L\\n(lC"cL" \{\
+.		nr iD 1
+.		cC
+.	\}
+.	if "\\*(L\\n(lC"nU" \{\
+.		nr nU 0
+.	\}
+.	if \\n(mL>0 \{\
+.		nr iD 1
+.		nr mL 0
+.		tZ
+.		nr lC \\n(lC-1
+.		tY
+.	\}
+.	if "\\*(L\\n(lC"iT" \{\
+'		in \\n(.iu-\\n(o\\n(lCu
+.		tZ
+.		nr lC \\n(lC-1
+.		tY
+.		nr iD 1
+.	\}
+.	if "\\*(L\\n(lC"oL" \{\
+'		in \\n(.iu-\\n(o\\n(lCu
+.		tZ
+.		nr lC \\n(lC-1
+.		tY
+.		nr iD 1
+.	\}
+.	if "\\*(L\\n(lC"lL" \{\
+'		in \\n(.iu-\\n(o\\n(lCu
+.		tZ
+.		nr lC \\n(lC-1
+.		tY
+.		nr iD 1
+.	\}
+.	if \\n(iD==0 \{\
+.		lE
+.	\}
+.	br
+.	nr iD 0
+.\}
+..
+.de It
+.if "\\*(L\\n(lC"" \{\
+.	tm Usage .Bl -list-type [-width [string] | -compact | -offset [string]] (#\\n(.c)
+.	tm .It \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+.\}
+.ne 3v
+.ie \\n(.$>0 \{\
+.	ds mN It
+.	ds b1
+.	nr iD 0
+.	ds A1 \\$1
+.	ds A2 \\$2
+.	ds A3 \\$3
+.	ds A4 \\$4
+.	ds A5 \\$5
+.	ds A6 \\$6
+.	ds A7 \\$7
+.	ds A8 \\$8
+.	ds A9 \\$9
+.	nr fV \\n(.$
+.	if "\\*(L\\n(lC"mL" \{\
+.		nr iD 1
+.		nr aP 0
+.		aX
+.		\\*(L\\n(lC
+.	\}
+.	if "\\*(L\\n(lC"cL" \{\
+.		ds b1
+.		nr aP 0
+.		nr iD 1
+.		\\*(L\\n(lC
+.	\}
+.	if "\\*(L\\n(lC"iT" \{\
+.		nr aP 0
+.		nr iD 1
+.		\\*(L\\n(lC
+.	\}
+.	if \\n(iD==0 \{\
+.		fV
+.		nr oM \\n(oM+1
+.		nr tP 1
+.		nr aP \\n(aP+1
+.		nr tX \\n(C\\n(aP
+.		ds tX \\*(A\\n(aP
+.		if \\n(nF==1 \{\
+.			ds aA \\*(pA
+.			if n .ds pA \\*(nO
+.		\}
+.		ie \\n(C\\n(aP==1 \{\
+.			\\*(A\\n(aP
+.		\}
+.		el \{\
+.			nr aP \\n(aP-1
+.			No
+.		\}
+.		ie \\n(Xt==1 .ds xB \&\\*(L\\n(lC
+.		el .\\*(L\\n(lC
+.	\}
+.	nr iD 0
+.\}
+.el .\\*(L\\n(lC
+..
+.de lL
+.lY
+.br
+\&\\*(b1
+.nr oM \\n(oM-1
+.nr tP 0
+.ds b1
+.aY
+'fi
+..
+.de hL
+.lX
+.nr bb \\n(w\\n(lCu+\\n(lSu
+.ti -\\n(bbu
+.ie \w\\*(b1u>=(\\n(w\\n(lCu) \&\\*(b1
+.el \&\\*(b1\h'|\\n(bbu'\c
+.nr oM \\n(oM-1
+.ds b1
+.nr tP 0
+.aY
+'fi
+..
+.de oL
+.lY
+\&\\*(b1
+.br
+.nr oM \\n(oM-1
+.ds b1
+.nr tP 0
+.aY
+'fi
+..
+.de iT
+.lY
+.br
+.aY
+'fi
+..
+.de nU
+.nr oM \\n(oM+1
+.nr nU \\n(nU+1
+.ds b1 \&\\n(nU.
+.uL
+..
+.de bU
+.nr oM \\n(oM+1
+.nr bU \\n(bU+1
+.ds b1 \&\\*(sY\&\(bu\fP
+.uL
+..
+.de hU
+.nr oM \\n(oM+1
+.nr bU \\n(bU+1
+.ds b1 \&\\*(sY\&\-\fP
+.uL
+..
+.de uL
+.lX
+.nr bb \\n(w\\n(lCu+\\n(lSu
+.ti -\\n(bbu
+.ie \w\\*(b1u>=(\\n(w\\n(lCu) \&\\*(b1
+.el \&\\*(b1\h'|\\n(bbu'\c
+.nr oM \\n(oM-1
+.ds b1
+.nr tP 0
+.aY
+'fi
+..
+.de mL
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ie \\n(mL==1 \{\
+.	nr zB \\n(.c
+.	ie (\\n(zB-\\n(zA)>1 .Pp
+.	el .br
+.	nr zA \\n(zB
+.	nr zB 0
+.\}
+.el \{\
+.	nr zA \\n(.c
+.	br
+.\}
+\&\\*(sY\\*(b1\f\\n(cF\s\\n(cZ\\*(lS\c
+.aY
+.ds b1
+'fi
+..
+.de tL
+.if \\n(tW==0 .lW
+.lX
+.nr bb \\n(w\\n(lCu+\\n(lSu
+.ti -\\n(bbu
+.ie (\w\\*(b1u)>(\\n(w\\n(lCu) \{\&\\*(b1
+.       br
+.\}
+.el \&\\*(b1\h'|\\n(bbu'\c
+.if \\n(nF==1 \{\
+.	if n .ds pA \\*(aA
+.\}
+.nr oM \\n(oM-1
+.nr tP 0
+.ds b1
+.aY
+'fi
+..
+.de lW
+.if !"TagwidtH"\\*(t\\n(lC" \{\
+.       ie \\n(tX==1 \{\
+.               ds t\\n(lN \\*(tX
+.               nr w\\n(lN \\n(\\*(tX
+.       \}
+.       el \{\
+.               ds t\\n(lN No
+.               nr w\\n(lN \\n(No
+.       \}
+.       if !"\\*(t\\n(lC"\\*(t\\n(lN" .nr tC 1
+.\}
+..
+.de lX
+.ie \\n(tC \{\
+.       nr tC 0
+.       nr tW 0
+.       if \\n(v\\n(lC==0 .sp \\n(dVu
+.       in \\n(.iu+\\n(w\\n(lCu+\\n(o\\n(lCu+\\n(lSu
+.\}
+.el \{\
+.	ie \\n(v\\n(lC==1 \{\
+.	       nr aa 0
+.	\}
+.	el \{\
+.		sp \\n(dVu
+.	\}
+.\}
+.if !\\n(cR .ne 2v
+..
+.de lY
+.ie \\n(tC \{\
+.       nr tC 0
+.       nr tW 0
+.       if \\n(v\\n(lC==0 .sp \\n(dVu
+.       in \\n(.iu+\\n(o\\n(lCu
+.\}
+.el \{\
+.	ie \\n(v\\n(lC==1 \{\
+.	       nr aa 0
+.	\}
+.	el \{\
+.		sp \\n(dVu
+.	\}
+.\}
+.if !\\n(cR .ne 2v
+..
+.nr lC 0
+.nr wV 0
+.nr w1 0
+.nr o1 0
+.nr v1 0
+.nr h1 0
+.ds t\n(lC
+.de lE
+.ie \\n(o\\n(lC>0 \{\
+'	in \\n(.iu-(\\n(w\\n(lCu)-(\\n(o\\n(lCu)-\\n(lSu
+.	rr o\\n(lC
+.\}
+.el 'in \\n(.iu-\\n(w\\n(lCu-\\n(lSu
+.if \\n(lC<=0 .tm Extraneous .El call (#\\n(.c)
+.tZ
+.nr lC \\n(lC-1
+.tY
+..
+.de tY
+.nr tY (\\n(lC+1)
+.nr w\\n(tY 0
+.nr h\\n(tY 0
+.nr o\\n(tY 0
+.ds t\\n(tY \\*(t\\n(lC
+.ds L\\n(tY
+.nr v\\n(tY 0
+..
+.de tZ
+.rm L\\n(tY
+.rr w\\n(tY
+.rr h\\n(tY
+.rr o\\n(tY
+.rm t\\n(tY
+.rr v\\n(tY
+.nr tY \\n(tY-1
+..
+.nr w1 0
+.nr o1 0
+.nr h1 0
+.ds t1
+.nr v1 0
+.nr tY 1
+.de Xr
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 .tm Usage: .Xr manpage_name [section#] \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Xr
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.	ie \\n(C\\n(aP==1 .tm Usage: .Xr manpage_name [section#] \\*(Pu (#\\n(.c)
+.	el \{\
+.		ie \\n(C\\n(aP>2 .y\\n(C\\n(aP
+.		el \{\
+.			as b1 \&\\*(xR\\*(A\\n(aP\fP\s0
+.			if \\n(aC>\\n(aP \{\
+.				nr aP \\n(aP+1
+.				if \\n(C\\n(aP==2 \{\
+.					as b1 \&(\\*(A\\n(aP)
+.					nr aP \\n(aP+1
+.				\}
+.				if \\n(aC>=\\n(aP \{\
+.					c\\n(C\\n(aP
+.				\}
+.			\}
+.		\}
+.		aZ
+.       \}
+.\}
+..
+.de Sx
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 .tm Sx Usage: .Sx Section Header \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Sx
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.	as b1 \\*(sX
+.	nr cF \\n(.f
+.	nr cZ \\n(.s
+.	nR
+.\}
+..
+.de cC
+'in \\n(.iu-\\n(o\\n(lCu-\\n(w\\n(lCu
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.fi
+.tZ
+.nr lC \\n(lC-1
+.tY
+..
+.de W1
+.ta \w\\*(A1    u
+.nr eW \w\\*(A1    u
+'in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W2
+.ta \w\\*(A1    u +\w\\*(A2    u
+.nr eW \w\\*(A1    u+\w\\*(A2    u
+'in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W3
+.ta \w\\*(A1    u +\w\\*(A2    u +\w\\*(A3    u
+.nr eW \w\\*(A1    u+\w\\*(A2    u+\w\\*(A3    u
+'in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W4
+.ta \w\\*(A1    u +\w\\*(A2    u +\w\\*(A3    u +\w\\*(A4    u
+.nr eW \w\\*(A1    u+\w\\*(A2    u +\w\\*(A3    u +\w\\*(A4    u
+'in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W5
+.ta \w\\*(A1   u +\w\\*(A2   u +\w\\*(A3   u +\w\\*(A4   u +\w\\*(A5   u
+.nr eW \w\\*(A1   u +\w\\*(A2   u +\w\\*(A3   u +\w\\*(A4   u +\w\\*(A5   u
+'	in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de W6
+.ta \w\\*(A1 u +\w\\*(A2 u +\w\\*(A3 u +\w\\*(A4 u +\w\\*(A5 u +\w\\*(A6
+.nr eW \w\\*(A1 u +\w\\*(A2 u +\w\\*(A3 u +\w\\*(A4 u +\w\\*(A5 u +\w\\*(A6
+'	in \\n(.iu+\\n(eWu+\\n(o\\n(lCu
+..
+.de cL
+.if \\n(w\\n(lC==0 .nr w\\n(lC \\n(eWu
+.if \\n(.u==0 \{\
+.	fi
+'	in \\n(.iu+\\n(eWu
+.\}
+.ti -\\n(eWu
+.fV
+.nr aP \\n(aP+1
+.ie \\n(aC>=\\n(aP  \{\
+.	if "\\*(A\\n(aP"Ta" \{\
+.		nr jJ \\n(aP-1
+.		rm S\\n(jJ
+.		rr jJ
+.	\}
+.	c\\n(C\\n(aP
+.\}
+.el .tm Usage: .It column_string [Ta [column_string ...] ] (#\\n(.c)
+..
+.de Ta
+.ie \\n(aC>0 \{\
+.	nr aP \\n(aP+1
+.	ie \\n(aC>=\\n(aP \{\
+.		if "\\*(A\\n(aP"Ta" \{\
+.			nr jJ \\n(aP-1
+.			rm S\\n(jJ
+.			rr jJ
+.		\}
+.		as b1 \\t
+.		c\\n(C\\n(aP
+.	\}
+.	el \{\
+.		as b1 \\t\\c
+.		rm S\\n(aP
+.		pB
+.		aY
+.	\}
+.\}
+.el \{\
+.	tm Usage: Ta must follow column entry: e.g. (#\\n(.c)
+.	tm .It column_string [Ta [column_string ...] ]
+.\}
+..
+.de Dl
+'ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.in \\n(.iu+\\n(Dsu
+.ie \\n(aC==0 \{\
+.	ie \\n(.$==0 \{\
+.		tm Usage: .Dl argument ... (#\\n(.c)
+.	\}
+.	el \{\
+.		ds mN Dl
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.		Li
+.	\}
+.\}
+.el \{\
+.	tm Usage: .Dl not callable by other macros (#\\n(.c)
+.\}
+.in \\n(.iu-\\n(Dsu
+..
+.de D1
+'ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6i 6.5i
+.in \\n(.iu+\\n(Dsu
+.ie \\n(aC==0 \{\
+.	ie \\n(.$==0 \{\
+.		tm Usage: .D1 argument ... (#\\n(.c)
+.	\}
+.	el \{\
+.		ds mN D1
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.		nr aP \\n(aP+1
+.		ie \\n(C\\n(aP==1 .\\*(A\\n(aP
+.		el .No
+.	\}
+.\}
+.el \{\
+.	tm Usage: .D1 not callable by other macros (#\\n(.c)
+.\}
+.in \\n(.iu-\\n(Dsu
+..
+.de Ex
+.tm Ex defunct, Use .D1: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Ex
+.tm Ex defunct, Use .D1: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+..
+.de Vt
+.if \\n(fD>0 \{\
+.	Pp
+.	nr fD 0
+.\}
+.if \\n(fZ>0 \{\
+.	ie \\n(fX==0 \{\
+.		Pp
+.		rs
+.	\}
+.	el .br
+.\}
+.nr fX \\n(fX+1
+.nr cF \\n(.f
+.nr cZ \\n(.s
+\\*(fT\&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.ie \\n(oT==0 .br
+.el \&\ \&
+.ft \\n(cF
+.fs \\n(cZ
+..
+.nr fZ 0
+.de Ft
+.if \\n(nS>0 \{\
+.	if \\n(fZ>0 \{\
+.		Pp
+.		nr fD 0
+.		nr fX 0
+.	\}
+.	if \\n(fD>0 \{\
+.		Pp
+.		nr fD 0
+.		nr fX 0
+.	\}
+.	if \\n(fX>0 \{\
+.		Pp
+.		nr fX 0
+.	\}
+.	nr fY 1
+.\}
+.nr cF \\n(.f
+.nr cZ \\n(.s
+\&\\*(fT\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.ft \\n(cF
+.fs \\n(cZ
+..
+.nr oT 0
+.de Ot
+.nr oT 1
+.if \\n(nS>0 \{\
+.	if \\n(fZ>0 \{\
+.		Pp
+.		nr fD 0
+.		nr fX 0
+.	\}
+.	if \\n(fD>0 \{\
+.		Pp
+.		nr fD 0
+.		nr fX 0
+.	\}
+.	if \\n(fX>0 \{\
+.		Pp
+.		nr fX 0
+.	\}
+.	nr fY 1
+.\}
+.if \\n(.$==4 .as b1 \&\\*(fT\&\\$1 \\$2 \\$3 \\$4
+.if \\n(.$==3 .as b1 \&\\*(fT\&\\$1 \\$2 \\$3
+.if \\n(.$==2 .as b1 \&\\*(fT\&\\$1 \\$2
+.if \\n(.$==1 .as b1 \&\\*(fT\&\\$1
+.as b1 \&\ \fP
+..
+.de Fa
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .Fa Function Arguments ... \\*(Pu (#\\n(.c)
+.       el \{\
+.		ds mN Fa
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.ie \\n(fC>0 \{\
+.	fC
+.\}
+.el \{\
+.	if \\n(aC>\\n(aP \{\
+.		as b1 \\*(fA
+.		nr aP \\n(aP+1
+.		nr cF \\n(.f
+.		nr cZ \\n(.s
+.		nR
+.		if \\n(nS>0 \{\
+.			if \\n(fZ>0 .br
+.		\}
+.	\}
+.\}
+..
+.de fC
+.ie \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.		ds Fb
+.		nr fB 0
+.		nr Fb 0
+.		fB \\*(A\\n(aP
+.		if \\n(fB>1 \{\
+.			rm A\\n(aP
+.			rn Fb A\\n(aP
+.		\}
+.	if \\n(fC>1 \{\
+.		as b1 \&\f\\n(cF\s\\n(cZ,\\*(S\\n(aP\\*(fA\\*(A\\n(aP\fP\s0
+.	\}
+.	if \\n(fC==1 \{\
+.		as b1 \&\|\\*(fA\\*(A\\n(aP\fP\s0
+.	\}
+.	nr fC \\n(fC+1
+.	fC
+.\}
+.el  \{\
+.	aY
+.\}
+..
+.de Fn
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 .tm Usage: .Fn function_name function_arg(s) ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN Fn
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(nS>0 \{\
+.	if \\n(fY==0 \{\
+.		if \\n(fZ>0 \{\
+.			Pp
+.			nr fX 0
+.			nr fD 0
+.		\}
+.	\}
+.	if \\n(fY==1 \{\
+.		br
+.		nr fX 0
+.		nr fD 0
+.		nr fY 0
+.	\}
+.	if \\n(fD>0 \{\
+.		Pp
+.		nr fX 0
+.	\}
+.	if \\n(fX>0 \{\
+.		Pp
+.		nr fD 0
+.	\}
+.	nr fZ \\n(fZ+1
+.	nr fY 0
+.	rs
+.	ie \\n(nS>1 .br
+.	el \{\
+.		if \\n(iS==0 \{\
+.			nr iS ((8)*\\n(fW)u
+.		\}
+.	\}
+.	in +\\n(iSu
+.	ti -\\n(iSu
+.	nr nS \\n(nS+1
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.	nr cF \\n(.f
+.	nr cZ \\n(.s
+.	as b1 \\*(fN\\*(A\\n(aP\fP\s0\\*(lp
+.	ie \\n(aC>\\n(aP \{\
+.		as b1 \\*(fA
+.		nr aP \\n(aP+1
+.		f\\n(C\\n(aP
+.	\}
+.	el \{\
+.		as b1 \|\\*(rp
+.		aZ
+.	\}
+.	if \\n(nS>0 \{\
+. 		in -\\n(iSu
+.	\}
+.\}
+..
+.de f1
+.as b1 \\*(rp\f\\n(cF\s\\n(cZ
+.\\*(A\\n(aP
+..
+.de f2
+.if \\n(nS>0 \{\
+.	ds Fb
+.	nr fB 0
+.	nr Fb 0
+.	fB \\*(A\\n(aP
+.	if \\n(fB>1 \{\
+.		rm A\\n(aP
+.		rn Fb A\\n(aP
+.	\}
+.\}
+.as b1 \\*(A\\n(aP
+.ie \\n(aC>\\n(aP \{\
+.	nr aa \\n(aP
+.	nr aP \\n(aP+1
+.	if \\n(C\\n(aP==2 \{\
+.		as b1 \&\|\f\\n(cF\s\\n(cZ,\\*(S\\n(aa\fP\s0\|
+.	\}
+.	f\\n(C\\n(aP
+.\}
+.el  \{\
+.	as b1 \\*(rp\f\\n(cF\s\\n(cZ
+.	aZ
+.\}
+..
+.de f3
+.as b1 \\*(rp\f\\n(cF\s\\n(cZ\\*(A\\n(aP
+.ie \\n(aC>\\n(aP \{\
+.	No
+.\}
+.el .aZ
+..
+.de f4
+.as b1 \\*(rp\f\\n(cF\s\\n(cZ\\*(S\\n(aP\\*(A\\n(aP
+.ie \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.	No
+.\}
+.el .aZ
+..
+.de Fo
+.hy 0
+.if \\n(aC==0 \{\
+.	ie \\n(.$==0 .tm Usage: .Fo function_name
+.	el \{\
+.		ds mN Fo
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(nS>0 \{\
+.	if \\n(fY==0 \{\
+.		if \\n(fZ>0 \{\
+.			Pp
+.			nr fX 0
+.			nr fD 0
+.		\}
+.	\}
+.	if \\n(fY==1 \{\
+.		br
+.		nr fX 0
+.		nr fD 0
+.		nr fY 0
+.	\}
+.	if \\n(fD>0 \{\
+.		Pp
+.		nr fX 0
+.	\}
+.	if \\n(fX>0 \{\
+.		Pp
+.		nr fD 0
+.	\}
+.	nr fZ \\n(fZ+1
+.	nr fY 0
+.	rs
+.	ie \\n(nS>1 .br
+.	el \{\
+.		if \\n(iS==0 \{\
+.			nr iS ((8)*\\n(fW)u
+.		\}
+.	\}
+.	in +\\n(iSu
+.	ti -\\n(iSu
+.	nr nS \\n(nS+1
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr oM \\n(oM+1
+.	nr fC 1
+.	nr aP \\n(aP+1
+.	nr cF \\n(.f
+.	nr cZ \\n(.s
+.	as b1 \\*(fN\\*(A\\n(aP\fP\s0\\*(lp
+.	aY
+.\}
+..
+.de Fc
+.if \\n(aC==0 \{\
+.	if \\n(.$>0 \{\
+.		ds mN Fo
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.nr fC 0
+.nr oM \\n(oM-1
+.as b1 \|\\*(rp
+.ie \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.	\\*(A\\n(aP
+.\}
+.el \{\
+.	aZ
+.\}
+.if \\n(nS>0 \{\
+.	in -\\n(iSu
+.\}
+.hy
+..
+.de fB
+.if \\n(fB==0 \{\
+.	nr fB \\n(.$
+.	nr Fb 0
+.	ds Fb
+.\}
+.nr Fb \\n(Fb+1
+.as Fb \&\\$1
+.if \\n(Fb<\\n(fB \{\
+.	as Fb \&\\*(hV
+.	fB \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.\}
+..
+.de Rs
+.nr rS 1
+.rC
+.if \\n(nA==1 .Pp
+.nr Kl 0
+..
+.de Re
+.rZ
+.rC
+.nr rS 0
+..
+.de rC
+.nr uK 0
+.nr jK 0
+.nr nK 0
+.nr oK 0
+.nr qK 0
+.nr rK 0
+.nr tK 0
+.nr vK 0
+.nr dK 0
+.nr pK 0
+.nr bK 0
+.ds rS
+.rm U1 U2 U3 U4 U5 U6 U7 U8
+.rm uK jK nK oK rK qK tK vK dK pK bK
+..
+.de rZ
+.if \\n(uK \{\&\\*(U1,
+.	nr aK 1
+.	if (\\n(uK>1 \{\
+.		aK
+.	\}
+.	nr Kl -\\n(uK
+.\}
+.if \\n(tK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \{\
+.		ie (\\n(jK==1):(\\n(bK==1) \{\&\\*q\\*(tK\\*q.
+.		\}
+.		el \{\&\\*(eM\\*(tK\\*(nO.
+.		\}
+.	\}
+.	if \\n(Kl>0 \{\
+.		ie (\\n(jK==1):(\\n(bK==1) \{\&\\*q\\*(tK\\*q,
+.		\}
+.		el \{\&\\*(eM\\*(tK\\*(nO,
+.		\}
+.	\}
+.\}
+.if \\n(bK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(eM\\*(bK\\*(nO.
+.	if \\n(Kl>0 \&\\*(eM\\*(bK\\*(nO,
+.\}
+.if \\n(jK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(eM\\*(jK\\*(nO.
+.	if \\n(Kl>0 \&\\*(eM\\*(jK\\*(nO,
+.\}
+.if \\n(rK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(rK.
+.	if \\n(Kl>0 \&\\*(rK,
+.\}
+.if \\n(nK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(nK.
+.	if \\n(Kl>0 \&\\*(nK,
+.\}
+.if \\n(vK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(vK.
+.	if \\n(Kl>0 \&\\*(vK,
+.\}
+.if \\n(pK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(pK.
+.	if \\n(Kl>0 \&\\*(pK,
+.\}
+.if \\n(qK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(qK.
+.	if \\n(Kl>0 \&\\*(qK,
+.\}
+.if \\n(dK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(dK.
+.	if \\n(Kl>0 \&\\*(dK,
+.\}
+.if \\n(oK \{\
+.	nr Kl \\n(Kl-1
+.	if \\n(Kl==0 \&\\*(oK.
+.	if \\n(Kl>0 \&\\*(oK,
+.\}
+.if \\n(Kl>0 .tm unresolved reference problem
+..
+.de aK
+.nr aK \\n(aK+1
+.ie (\\n(uK-\\n(aK)==0 \{\&and \\*(U\\n(aK,
+.\}
+.el \{\&\\*(U\\n(aK,
+.	aK
+.\}
+..
+.de %A
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%A Author_name (#\\n(.c)
+.	el \{\
+.		nr uK \\n(uK+1
+.		nr Kl \\n(Kl+1
+.		ds rS U\\n(uK
+.		ds mN %A
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de %B
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%B Book Name (#\\n(.c)
+.       el \{\
+.		ds mN %B
+.		if \\n(rS>0 \{\
+.			nr bK \\n(bK+1
+.			nr Kl \\n(Kl+1
+.			ds rS bK
+.		\}
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.	ie \\n(rS==0 \{\
+.		as b1 \&\\*(eM
+.		nR
+.	\}
+.	el .rR
+.\}
+..
+.de %D
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%D Date (#\\n(.c)
+.       el \{\
+.		ds mN %D
+.		nr dK \\n(dK+1
+.		nr Kl \\n(Kl+1
+.		ds rS dK
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de %J
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%J Journal Name (#\\n(.c)
+.       el \{\
+.		ds mN %J
+.		nr jK \\n(jK+1
+.		ds rS jK
+.		nr Kl \\n(Kl+1
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de %N
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%N issue number (#\\n(.c)
+.	el \{\
+.		nr nK \\n(nK+1
+.		nr Kl \\n(Kl+1
+.		ds rS nK
+.		ds mN %N
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de %O
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%O optional information ... \\*(Pu (#\\n(.c)
+.       el \{\
+.		ds mN %O
+.		nr oK \\n(oK+1
+.		nr Kl \\n(Kl+1
+.		ds rS oK
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de %P
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%P page numbers ... \\*(Pu (#\\n(.c)
+.       el \{\
+.		ds mN %P
+.		nr pK \\n(pK+1
+.		nr Kl \\n(Kl+1
+.		ds rS pK
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de %Q
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%Q Corporate or Foreign Author (#\\n(.c)
+.       el \{\
+.		ds mN %Q
+.		nr qK \\n(qK+1
+.		nr Kl \\n(Kl+1
+.		ds rS qK
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de %R
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%R reference report (#\\n(.c)
+.       el \{\
+.		ds mN %R
+.		nr rK \\n(rK+1
+.		nr Kl \\n(Kl+1
+.		ds rS rK
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de %T
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%T (#\\n(.c)
+.       el \{\
+.		ds mN %T
+.		if \\n(rS>0 \{\
+.			nr tK \\n(tK+1
+.			nr Kl \\n(Kl+1
+.			ds rS tK
+.		\}
+.               ds A1 \\$1
+.               ds A2 \\$2
+.               ds A3 \\$3
+.               ds A4 \\$4
+.               ds A5 \\$5
+.               ds A6 \\$6
+.               ds A7 \\$7
+.               ds A8 \\$8
+.               ds A9 \\$9
+.		nr fV \\n(.$
+.		fV
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.		nr aP \\n(aP+1
+.		nr cF \\n(.f
+.		nr cZ \\n(.s
+.		ie \\n(rS==0 \{\
+.			as b1 \&\\*(eM
+.			nR
+.		\}
+.		el .rR
+.\}
+..
+.de %V
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .%V Volume , ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN %V
+.		nr vK \\n(vK+1
+.		nr Kl \\n(Kl+1
+.		ds rS vK
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       rR
+.\}
+..
+.de rR
+.hy 0
+.nr jM \\n(C\\n(aP
+.ie \\n(jM==1 \{\
+.	ie "\\*(A\\n(aP"Tn" \{\
+.		nN
+.	\}
+.	el \{\
+.		if \\n(aC>8 .tm Usage: \\*(mN - maximum 8 arguments (#\\n(.c)
+.		aI rR 1
+.		\\*(A\\n(aP
+.	\}
+.\}
+.el \{\
+.	nr jN \\n(aP
+.	ie \\n(jM==2 .as b1 \&\\*(A\\n(aP
+.	el .as b1 \&\\*(A\\n(aP
+.	ie \\n(aC==\\n(aP \{\
+.		rD
+.	\}
+.	el \{\
+.		nr aP \\n(aP+1
+.		as b1 \&\\*(S\\n(jN
+.		rR
+.	\}
+.\}
+.rr jM jN
+..
+.de rD
+.as \\*(rS \\*(b1
+.ds b1
+.ds rS
+.aY
+..
+.de Hf
+.Pp
+File:
+.Pa \\$1
+.Pp
+.nr cF \\n(.f
+.nr cZ \\n(.s
+.ie t \{\
+\&\\*(lI
+.br
+.ta +9n 18n 27n 36n 45n 54n 63n 72n
+.\}
+.el \{\
+.ta +8n 16n 24n 32n 40n 48n 56n 64n 72n
+.\}
+.nf
+.so  \\$1
+.fi
+.ft \\n(cF
+.fz \\n(cZ
+.Pp
+..
+.nr aN 0
+.de An
+.if \\n(nY==1 \{\
+.	ie \\n(aN==1 \{\
+.		br
+.	\}
+.	el \{\
+.		nr aN 1
+.	\}
+.\}
+.if \\n(aC==0 \{\
+.       ie \\n(.$==0 .tm Usage: .An author_name ... \\*(Pu (#\\n(.c)
+.	el \{\
+.		ds mN An
+.		aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.	\}
+.\}
+.if \\n(aC>\\n(aP \{\
+.	nr aP \\n(aP+1
+.       nr cF \\n(.f
+.	nr cZ \\n(.s
+.       nR
+.\}
+..
+.de Sf
+.tm .Sf defunct, use prefix or Ns
+..
+.ds rV "function returns the value 0 if successful; otherwise the value -1 is returned and the global variable \\*(vAerrno\fP is set to indicate the error.
+.de Rv
+.ie \\n(.$==0 \{\
+.tm Usage: .Rv [-std] (#\\n(.c)
+.\}
+.el \{\
+.	ds mN Rv
+.	if "\\$1"-std" \{\
+.	nr cH \\*(cH
+.	if (\\n(cH<2):(\\n(cH>3) .tm Usage: .Rv -std sections 2 and 3 only
+.		br
+\&The
+.Fn \\$2
+\&\\*(rV
+.	\}
+.\}
+..
diff --git a/mechglue/src/appl/telnet/telnet/tn3270.c b/mechglue/src/appl/telnet/telnet/tn3270.c
new file mode 100644
index 000000000..c46ae7eb8
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/tn3270.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)tn3270.c	8.1 (Berkeley) 6/6/93 */
+
+#include <sys/types.h>
+#include <arpa/telnet.h>
+
+#include "general.h"
+
+#include "defines.h"
+#include "ring.h"
+#include "externs.h"
+#include "fdset.h"
+
+#if	defined(TN3270)
+
+#include "../ctlr/screen.h"
+#include "../general/globals.h"
+
+#include "../sys_curses/telextrn.h"
+#include "../ctlr/externs.h"
+
+#if	defined(unix)
+int
+	HaveInput,		/* There is input available to scan */
+	cursesdata,		/* Do we dump curses data? */
+	sigiocount;		/* Number of times we got a SIGIO */
+
+char	tline[200];
+char	*transcom = 0;	/* transparent mode command (default: none) */
+#endif	/* defined(unix) */
+
+char	Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
+
+static char	sb_terminal[] = { IAC, SB,
+			TELOPT_TTYPE, TELQUAL_IS,
+			'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
+			IAC, SE };
+#define	SBTERMMODEL	13
+
+static int
+	Sent3270TerminalType;	/* Have we said we are a 3270? */
+
+#endif	/* defined(TN3270) */
+
+
+    void
+init_3270()
+{
+#if	defined(TN3270)
+#if	defined(unix)
+    HaveInput = 0;
+    sigiocount = 0;
+#endif	/* defined(unix) */
+    Sent3270TerminalType = 0;
+    Ifrontp = Ibackp = Ibuf;
+    init_ctlr();		/* Initialize some things */
+    init_keyboard();
+    init_screen();
+    init_system();
+#endif	/* defined(TN3270) */
+}
+
+
+#if	defined(TN3270)
+
+/*
+ * DataToNetwork - queue up some data to go to network.  If "done" is set,
+ * then when last byte is queued, we add on an IAC EOR sequence (so,
+ * don't call us with "done" until you want that done...)
+ *
+ * We actually do send all the data to the network buffer, since our
+ * only client needs for us to do that.
+ */
+
+    int
+DataToNetwork(buffer, count, done)
+    register char *buffer;	/* where the data is */
+    register int  count;	/* how much to send */
+    int		  done;		/* is this the last of a logical block */
+{
+    register int loop, c;
+    int origCount;
+
+    origCount = count;
+
+    while (count) {
+	/* If not enough room for EORs, IACs, etc., wait */
+	if (NETROOM() < 6) {
+	    fd_set o;
+
+	    FD_ZERO(&o);
+	    netflush();
+	    while (NETROOM() < 6) {
+		FD_SET(net, &o);
+		(void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
+						(struct timeval *) 0);
+		netflush();
+	    }
+	}
+	c = ring_empty_count(&netoring);
+	if (c > count) {
+	    c = count;
+	}
+	loop = c;
+	while (loop) {
+	    if (((unsigned char)*buffer) == IAC) {
+		break;
+	    }
+	    buffer++;
+	    loop--;
+	}
+	if ((c = c-loop)) {
+	    ring_supply_data(&netoring, buffer-c, c);
+	    count -= c;
+	}
+	if (loop) {
+	    NET2ADD(IAC, IAC);
+	    count--;
+	    buffer++;
+	}
+    }
+
+    if (done) {
+	NET2ADD(IAC, EOR);
+	netflush();		/* try to move along as quickly as ... */
+    }
+    return(origCount - count);
+}
+
+
+#if	defined(unix)
+    void
+inputAvailable(signo)
+	int signo;
+{
+    HaveInput = 1;
+    sigiocount++;
+}
+#endif	/* defined(unix) */
+
+    void
+outputPurge()
+{
+    (void) ttyflush(1);
+}
+
+
+/*
+ * The following routines are places where the various tn3270
+ * routines make calls into telnet.c.
+ */
+
+/*
+ * DataToTerminal - queue up some data to go to terminal.
+ *
+ * Note: there are people who call us and depend on our processing
+ * *all* the data at one time (thus the select).
+ */
+
+    int
+DataToTerminal(buffer, count)
+    register char	*buffer;		/* where the data is */
+    register int	count;			/* how much to send */
+{
+    register int c;
+    int origCount;
+
+    origCount = count;
+
+    while (count) {
+	if (TTYROOM() == 0) {
+#if	defined(unix)
+	    fd_set o;
+
+	    FD_ZERO(&o);
+#endif	/* defined(unix) */
+	    (void) ttyflush(0);
+	    while (TTYROOM() == 0) {
+#if	defined(unix)
+		FD_SET(tout, &o);
+		(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+						(struct timeval *) 0);
+#endif	/* defined(unix) */
+		(void) ttyflush(0);
+	    }
+	}
+	c = TTYROOM();
+	if (c > count) {
+	    c = count;
+	}
+	ring_supply_data(&ttyoring, buffer, c);
+	count -= c;
+	buffer += c;
+    }
+    return(origCount);
+}
+
+
+/*
+ * Push3270 - Try to send data along the 3270 output (to screen) direction.
+ */
+
+    int
+Push3270()
+{
+    int save = ring_full_count(&netiring);
+
+    if (save) {
+	if (Ifrontp+save > Ibuf+sizeof Ibuf) {
+	    if (Ibackp != Ibuf) {
+		memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
+		Ifrontp -= (Ibackp-Ibuf);
+		Ibackp = Ibuf;
+	    }
+	}
+	if (Ifrontp+save < Ibuf+sizeof Ibuf) {
+	    (void)telrcv();
+	}
+    }
+    return save != ring_full_count(&netiring);
+}
+
+
+/*
+ * Finish3270 - get the last dregs of 3270 data out to the terminal
+ *		before quitting.
+ */
+
+    void
+Finish3270()
+{
+    while (Push3270() || !DoTerminalOutput()) {
+#if	defined(unix)
+	HaveInput = 0;
+#endif	/* defined(unix) */
+	;
+    }
+}
+
+
+/* StringToTerminal - output a null terminated string to the terminal */
+
+    void
+StringToTerminal(s)
+    char *s;
+{
+    int count;
+
+    count = strlen(s);
+    if (count) {
+	(void) DataToTerminal(s, count);	/* we know it always goes... */
+    }
+}
+
+
+#if	((!defined(NOT43)) || defined(PUTCHAR))
+/* _putchar - output a single character to the terminal.  This name is so that
+ *	curses(3x) can call us to send out data.
+ */
+
+    void
+_putchar(c)
+    char c;
+{
+#if	defined(sun)		/* SunOS 4.0 bug */
+    c &= 0x7f;
+#endif	/* defined(sun) */
+    if (cursesdata) {
+	Dump('>', &c, 1);
+    }
+    if (!TTYROOM()) {
+	(void) DataToTerminal(&c, 1);
+    } else {
+	TTYADD(c);
+    }
+}
+#endif	/* ((!defined(NOT43)) || defined(PUTCHAR)) */
+
+    void
+SetIn3270()
+{
+    if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY)
+		&& my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) {
+	if (!In3270) {
+	    In3270 = 1;
+	    Init3270();		/* Initialize 3270 functions */
+	    /* initialize terminal key mapping */
+	    InitTerminal();	/* Start terminal going */
+	    setconnmode(0);
+	}
+    } else {
+	if (In3270) {
+	    StopScreen(1);
+	    In3270 = 0;
+	    Stop3270();		/* Tell 3270 we aren't here anymore */
+	    setconnmode(0);
+	}
+    }
+}
+
+/*
+ * tn3270_ttype()
+ *
+ *	Send a response to a terminal type negotiation.
+ *
+ *	Return '0' if no more responses to send; '1' if a response sent.
+ */
+
+    int
+tn3270_ttype()
+{
+    /*
+     * Try to send a 3270 type terminal name.  Decide which one based
+     * on the format of our screen, and (in the future) color
+     * capaiblities.
+     */
+    InitTerminal();		/* Sets MaxNumberColumns, MaxNumberLines */
+    if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
+	Sent3270TerminalType = 1;
+	if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
+	    MaxNumberLines = 27;
+	    MaxNumberColumns = 132;
+	    sb_terminal[SBTERMMODEL] = '5';
+	} else if (MaxNumberLines >= 43) {
+	    MaxNumberLines = 43;
+	    MaxNumberColumns = 80;
+	    sb_terminal[SBTERMMODEL] = '4';
+	} else if (MaxNumberLines >= 32) {
+	    MaxNumberLines = 32;
+	    MaxNumberColumns = 80;
+	    sb_terminal[SBTERMMODEL] = '3';
+	} else {
+	    MaxNumberLines = 24;
+	    MaxNumberColumns = 80;
+	    sb_terminal[SBTERMMODEL] = '2';
+	}
+	NumberLines = 24;		/* before we start out... */
+	NumberColumns = 80;
+	ScreenSize = NumberLines*NumberColumns;
+	if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
+	    ExitString("Programming error:  MAXSCREENSIZE too small.\n",
+								1);
+	    /*NOTREACHED*/
+	}
+	printsub('>', sb_terminal+2, sizeof sb_terminal-2);
+	ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
+	return 1;
+    } else {
+	return 0;
+    }
+}
+
+#if	defined(unix)
+	int
+settranscom(argc, argv)
+	int argc;
+	char *argv[];
+{
+	int i;
+
+	if (argc == 1 && transcom) {
+	   transcom = 0;
+	}
+	if (argc == 1) {
+	   return 1;
+	}
+	transcom = tline;
+	(void) strncpy(transcom, argv[1], sizeof(tline) - 1);
+	tline[sizeof(tline) - 1] = '\0';
+	for (i = 2; i < argc; ++i) {
+	    (void) strncat(transcom, " ", sizeof(tline) - 1 - (transcom - tline));
+	    (void) strncat(transcom, argv[i], sizeof(tline) - 1 - (transcom - tline));
+	}
+	return 1;
+}
+#endif	/* defined(unix) */
+
+#endif	/* defined(TN3270) */
diff --git a/mechglue/src/appl/telnet/telnet/types.h b/mechglue/src/appl/telnet/telnet/types.h
new file mode 100644
index 000000000..191d311fd
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/types.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)types.h	8.1 (Berkeley) 6/6/93
+ */
+
+typedef struct {
+    char *modedescriptions;
+    char modetype;
+} Modelist;
+
+extern Modelist modelist[];
+
+typedef struct {
+    int
+	system,			/* what the current time is */
+	echotoggle,		/* last time user entered echo character */
+	modenegotiated,		/* last time operating mode negotiated */
+	didnetreceive,		/* last time we read data from network */
+	gotDM;			/* when did we last see a data mark */
+} Clocks;
+
+extern Clocks clocks;
diff --git a/mechglue/src/appl/telnet/telnet/utilities.c b/mechglue/src/appl/telnet/telnet/utilities.c
new file mode 100644
index 000000000..4b198dabf
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnet/utilities.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)utilities.c	8.1 (Berkeley) 6/6/93 */
+
+#define	TELOPTS
+#define	TELCMDS
+#define	SLC_NAMES
+#include <arpa/telnet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+
+#include "general.h"
+
+#include "fdset.h"
+
+#include "ring.h"
+
+#include "defines.h"
+
+#include "externs.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
+int	prettydump;
+
+/*
+ * upcase()
+ *
+ *	Upcase (in place) the argument.
+ */
+
+    void
+upcase(argument)
+    register char *argument;
+{
+    register int c;
+
+    while ((c = *argument) != 0) {
+	if (islower(c)) {
+	    *argument = toupper(c);
+	}
+	argument++;
+    }
+}
+
+/*
+ * SetSockOpt()
+ *
+ * Compensate for differences in 4.2 and 4.3 systems.
+ */
+
+    int
+SetSockOpt(fd, level, option, yesno)
+    int fd, level, option, yesno;
+{
+#ifndef	NOT43
+    return setsockopt(fd, level, option,
+				(char *)&yesno, sizeof yesno);
+#else	/* NOT43 */
+    if (yesno == 0) {		/* Can't do that in 4.2! */
+	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
+				option);
+	return -1;
+    }
+    return setsockopt(fd, level, option, 0, 0);
+#endif	/* NOT43 */
+}
+
+/*
+ * The following are routines used to print out debugging information.
+ */
+
+unsigned char NetTraceFile[256] = "(standard output)";
+
+    void
+SetNetTrace(file)
+    register char *file;
+{
+    if (NetTrace && NetTrace != stdout)
+	fclose(NetTrace);
+    if (file  && (strcmp(file, "-") != 0)) {
+	NetTrace = fopen(file, "w");
+	if (NetTrace) {
+	    strncpy((char *)NetTraceFile, file, sizeof(NetTraceFile) - 1);
+	    NetTraceFile[sizeof(NetTraceFile) - 1] = '\0';
+	    return;
+	}
+	fprintf(stderr, "Cannot open %s.\n", file);
+    }
+    NetTrace = stdout;
+    strncpy((char *)NetTraceFile, "(standard output)", sizeof(NetTraceFile) - 1);
+    NetTraceFile[sizeof(NetTraceFile) - 1] = '\0';
+}
+
+    void
+Dump(direction, buffer, length)
+    char direction;
+    unsigned char *buffer;
+    int length;
+{
+#   define BYTES_PER_LINE	32
+#   define min(x,y)	((x<y)? x:y)
+    unsigned char *pThis;
+    int offset;
+
+    offset = 0;
+
+    while (length) {
+	/* print one line */
+	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
+	pThis = buffer;
+	if (prettydump) {
+	    buffer = buffer + min(length, BYTES_PER_LINE/2);
+	    while (pThis < buffer) {
+		fprintf(NetTrace, "%c%.2x",
+		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
+		    (*pThis)&0xff);
+		pThis++;
+	    }
+	    length -= BYTES_PER_LINE/2;
+	    offset += BYTES_PER_LINE/2;
+	} else {
+	    buffer = buffer + min(length, BYTES_PER_LINE);
+	    while (pThis < buffer) {
+		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
+		pThis++;
+	    }
+	    length -= BYTES_PER_LINE;
+	    offset += BYTES_PER_LINE;
+	}
+	if (NetTrace == stdout) {
+	    fprintf(NetTrace, "\r\n");
+	} else {
+	    fprintf(NetTrace, "\n");
+	}
+	if (length < 0) {
+	    fflush(NetTrace);
+	    return;
+	}
+	/* find next unique line */
+    }
+    fflush(NetTrace);
+}
+
+
+	void
+printoption(direction, cmd, option)
+	char *direction;
+	int cmd, option;
+{
+	if (!showoptions)
+		return;
+	if (cmd == IAC) {
+		if (TELCMD_OK(option))
+		    fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
+		else
+		    fprintf(NetTrace, "%s IAC %d", direction, option);
+	} else {
+		register char *fmt;
+		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
+			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
+		if (fmt) {
+		    fprintf(NetTrace, "%s %s ", direction, fmt);
+		    if (TELOPT_OK(option))
+			fprintf(NetTrace, "%s", TELOPT(option));
+		    else if (option == TELOPT_EXOPL)
+			fprintf(NetTrace, "EXOPL");
+		    else
+			fprintf(NetTrace, "%d", option);
+		} else
+		    fprintf(NetTrace, "%s %d %d", direction, cmd, option);
+	}
+	if (NetTrace == stdout) {
+	    fprintf(NetTrace, "\r\n");
+	    fflush(NetTrace);
+	} else {
+	    fprintf(NetTrace, "\n");
+	}
+	return;
+}
+
+    void
+optionstatus()
+{
+    register int i;
+    extern char will_wont_resp[], do_dont_resp[];
+
+    for (i = 0; i < 256; i++) {
+	if (do_dont_resp[i]) {
+	    if (TELOPT_OK(i))
+		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
+	    else if (TELCMD_OK(i))
+		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
+	    else
+		printf("resp DO_DONT %d: %d\n", i,
+				do_dont_resp[i]);
+	    if (my_want_state_is_do(i)) {
+		if (TELOPT_OK(i))
+		    printf("want DO   %s\n", TELOPT(i));
+		else if (TELCMD_OK(i))
+		    printf("want DO   %s\n", TELCMD(i));
+		else
+		    printf("want DO   %d\n", i);
+	    } else {
+		if (TELOPT_OK(i))
+		    printf("want DONT %s\n", TELOPT(i));
+		else if (TELCMD_OK(i))
+		    printf("want DONT %s\n", TELCMD(i));
+		else
+		    printf("want DONT %d\n", i);
+	    }
+	} else {
+	    if (my_state_is_do(i)) {
+		if (TELOPT_OK(i))
+		    printf("     DO   %s\n", TELOPT(i));
+		else if (TELCMD_OK(i))
+		    printf("     DO   %s\n", TELCMD(i));
+		else
+		    printf("     DO   %d\n", i);
+	    }
+	}
+	if (will_wont_resp[i]) {
+	    if (TELOPT_OK(i))
+		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
+	    else if (TELCMD_OK(i))
+		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
+	    else
+		printf("resp WILL_WONT %d: %d\n",
+				i, will_wont_resp[i]);
+	    if (my_want_state_is_will(i)) {
+		if (TELOPT_OK(i))
+		    printf("want WILL %s\n", TELOPT(i));
+		else if (TELCMD_OK(i))
+		    printf("want WILL %s\n", TELCMD(i));
+		else
+		    printf("want WILL %d\n", i);
+	    } else {
+		if (TELOPT_OK(i))
+		    printf("want WONT %s\n", TELOPT(i));
+		else if (TELCMD_OK(i))
+		    printf("want WONT %s\n", TELCMD(i));
+		else
+		    printf("want WONT %d\n", i);
+	    }
+	} else {
+	    if (my_state_is_will(i)) {
+		if (TELOPT_OK(i))
+		    printf("     WILL %s\n", TELOPT(i));
+		else if (TELCMD_OK(i))
+		    printf("     WILL %s\n", TELCMD(i));
+		else
+		    printf("     WILL %d\n", i);
+	    }
+	}
+    }
+
+}
+
+    void
+printsub(direction, pointer, length)
+    char direction;	/* '<' or '>' */
+    unsigned char *pointer;	/* where suboption data sits */
+    int		  length;	/* length of suboption data */
+{
+    register int i;
+    unsigned char buf[512];
+    extern int want_status_response;
+
+    if (showoptions || direction == 0 ||
+	(want_status_response && (pointer[0] == TELOPT_STATUS))) {
+	if (direction) {
+	    fprintf(NetTrace, "%s IAC SB ",
+				(direction == '<')? "RCVD":"SENT");
+	    if (length >= 3) {
+		register int j;
+
+		i = pointer[length-2];
+		j = pointer[length-1];
+
+		if (i != IAC || j != SE) {
+		    fprintf(NetTrace, "(terminated by ");
+		    if (TELOPT_OK(i))
+			fprintf(NetTrace, "%s ", TELOPT(i));
+		    else if (TELCMD_OK(i))
+			fprintf(NetTrace, "%s ", TELCMD(i));
+		    else
+			fprintf(NetTrace, "%d ", i);
+		    if (TELOPT_OK(j))
+			fprintf(NetTrace, "%s", TELOPT(j));
+		    else if (TELCMD_OK(j))
+			fprintf(NetTrace, "%s", TELCMD(j));
+		    else
+			fprintf(NetTrace, "%d", j);
+		    fprintf(NetTrace, ", not IAC SE!) ");
+		}
+	    }
+	    length -= 2;
+	}
+	if (length < 1) {
+	    fprintf(NetTrace, "(Empty suboption??\?)");
+	    if (NetTrace == stdout)
+		fflush(NetTrace);
+	    return;
+	}
+	switch (pointer[0]) {
+	case TELOPT_TTYPE:
+	    fprintf(NetTrace, "TERMINAL-TYPE ");
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
+		break;
+	    case TELQUAL_SEND:
+		fprintf(NetTrace, "SEND");
+		break;
+	    default:
+		fprintf(NetTrace,
+				"- unknown qualifier %d (0x%x).",
+				pointer[1], pointer[1]);
+	    }
+	    break;
+	case TELOPT_TSPEED:
+	    fprintf(NetTrace, "TERMINAL-SPEED");
+	    if (length < 2) {
+		fprintf(NetTrace, " (empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		fprintf(NetTrace, " IS ");
+		fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
+		break;
+	    default:
+		if (pointer[1] == 1)
+		    fprintf(NetTrace, " SEND");
+		else
+		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
+		for (i = 2; i < length; i++)
+		    fprintf(NetTrace, " ?%d?", pointer[i]);
+		break;
+	    }
+	    break;
+
+	case TELOPT_LFLOW:
+	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
+	    if (length < 2) {
+		fprintf(NetTrace, " (empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case LFLOW_OFF:
+		fprintf(NetTrace, " OFF"); break;
+	    case LFLOW_ON:
+		fprintf(NetTrace, " ON"); break;
+	    case LFLOW_RESTART_ANY:
+		fprintf(NetTrace, " RESTART-ANY"); break;
+	    case LFLOW_RESTART_XON:
+		fprintf(NetTrace, " RESTART-XON"); break;
+	    default:
+		fprintf(NetTrace, " %d (unknown)", pointer[1]);
+	    }
+	    for (i = 2; i < length; i++)
+		fprintf(NetTrace, " ?%d?", pointer[i]);
+	    break;
+
+	case TELOPT_NAWS:
+	    fprintf(NetTrace, "NAWS");
+	    if (length < 2) {
+		fprintf(NetTrace, " (empty suboption??\?)");
+		break;
+	    }
+	    if (length == 2) {
+		fprintf(NetTrace, " ?%d?", pointer[1]);
+		break;
+	    }
+	    fprintf(NetTrace, " %d %d (%d)",
+		pointer[1], pointer[2],
+		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
+	    if (length == 4) {
+		fprintf(NetTrace, " ?%d?", pointer[3]);
+		break;
+	    }
+	    fprintf(NetTrace, " %d %d (%d)",
+		pointer[3], pointer[4],
+		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
+	    for (i = 5; i < length; i++)
+		fprintf(NetTrace, " ?%d?", pointer[i]);
+	    break;
+
+#if	defined(AUTHENTICATION)
+	case TELOPT_AUTHENTICATION:
+	    fprintf(NetTrace, "AUTHENTICATION");
+	    if (length < 2) {
+		fprintf(NetTrace, " (empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case TELQUAL_REPLY:
+	    case TELQUAL_IS:
+		fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
+							"IS" : "REPLY");
+		if (AUTHTYPE_NAME_OK(pointer[2]))
+		    fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
+		else
+		    fprintf(NetTrace, "%d ", pointer[2]);
+		if (length < 3) {
+		    fprintf(NetTrace, "(partial suboption??\?)");
+		    break;
+		}
+		fprintf(NetTrace, "%s|%s%s",
+			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+			"CLIENT" : "SERVER",
+			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+			"MUTUAL" : "ONE-WAY",
+			((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON) ?
+			"|ENCRYPT" : "");
+		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
+		fprintf(NetTrace, "%s", buf);
+		break;
+
+	    case TELQUAL_SEND:
+		i = 2;
+		fprintf(NetTrace, " SEND ");
+		while (i < length) {
+		    if (AUTHTYPE_NAME_OK(pointer[i]))
+			fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
+		    else
+			fprintf(NetTrace, "%d ", pointer[i]);
+		    if (++i >= length) {
+			fprintf(NetTrace, "(partial suboption??\?)");
+			break;
+		    }
+		    fprintf(NetTrace, "%s|%s%s ",
+			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+							"CLIENT" : "SERVER",
+			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+							"MUTUAL" : "ONE-WAY",
+			((pointer[i] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON) ?
+							"|ENCRYPT" : "");
+		    ++i;
+		}
+		break;
+
+	    case TELQUAL_NAME:
+		i = 2;
+		fprintf(NetTrace, " NAME \"");
+		while (i < length)
+		    putc(pointer[i++], NetTrace);
+		putc('"', NetTrace);
+		break;
+
+	    default:
+		    for (i = 2; i < length; i++)
+			fprintf(NetTrace, " ?%d?", pointer[i]);
+		    break;
+	    }
+	    break;
+#endif
+
+#ifdef	ENCRYPTION
+	case TELOPT_ENCRYPT:
+	    fprintf(NetTrace, "ENCRYPT");
+	    if (length < 2) {
+		fprintf(NetTrace, " (empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case ENCRYPT_START:
+		fprintf(NetTrace, " START");
+		break;
+
+	    case ENCRYPT_END:
+		fprintf(NetTrace, " END");
+		break;
+
+	    case ENCRYPT_REQSTART:
+		fprintf(NetTrace, " REQUEST-START");
+		break;
+
+	    case ENCRYPT_REQEND:
+		fprintf(NetTrace, " REQUEST-END");
+		break;
+
+	    case ENCRYPT_IS:
+	    case ENCRYPT_REPLY:
+		fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
+							"IS" : "REPLY");
+		if (length < 3) {
+		    fprintf(NetTrace, " (partial suboption??\?)");
+		    break;
+		}
+		if (ENCTYPE_NAME_OK(pointer[2]))
+		    fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
+		else
+		    fprintf(NetTrace, " %d (unknown)", pointer[2]);
+
+		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
+		fprintf(NetTrace, "%s", buf);
+		break;
+
+	    case ENCRYPT_SUPPORT:
+		i = 2;
+		fprintf(NetTrace, " SUPPORT ");
+		while (i < length) {
+		    if (ENCTYPE_NAME_OK(pointer[i]))
+			fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
+		    else
+			fprintf(NetTrace, "%d ", pointer[i]);
+		    i++;
+		}
+		break;
+
+	    case ENCRYPT_ENC_KEYID:
+		fprintf(NetTrace, " ENC_KEYID ");
+		goto encommon;
+
+	    case ENCRYPT_DEC_KEYID:
+		fprintf(NetTrace, " DEC_KEYID ");
+		goto encommon;
+
+	    default:
+		fprintf(NetTrace, " %d (unknown)", pointer[1]);
+	    encommon:
+		for (i = 2; i < length; i++)
+		    fprintf(NetTrace, " %d", pointer[i]);
+		break;
+	    }
+	    break;
+#endif	/* ENCRYPTION */
+
+	case TELOPT_LINEMODE:
+	    fprintf(NetTrace, "LINEMODE ");
+	    if (length < 2) {
+		fprintf(NetTrace, " (empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case WILL:
+		fprintf(NetTrace, "WILL ");
+		goto common;
+	    case WONT:
+		fprintf(NetTrace, "WONT ");
+		goto common;
+	    case DO:
+		fprintf(NetTrace, "DO ");
+		goto common;
+	    case DONT:
+		fprintf(NetTrace, "DONT ");
+	    common:
+		if (length < 3) {
+		    fprintf(NetTrace, "(no option??\?)");
+		    break;
+		}
+		switch (pointer[2]) {
+		case LM_FORWARDMASK:
+		    fprintf(NetTrace, "Forward Mask");
+		    for (i = 3; i < length; i++)
+			fprintf(NetTrace, " %x", pointer[i]);
+		    break;
+		default:
+		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
+		    for (i = 3; i < length; i++)
+			fprintf(NetTrace, " %d", pointer[i]);
+		    break;
+		}
+		break;
+		
+	    case LM_SLC:
+		fprintf(NetTrace, "SLC");
+		for (i = 2; i < length - 2; i += 3) {
+		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
+			fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
+		    else
+			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
+		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
+		    case SLC_NOSUPPORT:
+			fprintf(NetTrace, " NOSUPPORT"); break;
+		    case SLC_CANTCHANGE:
+			fprintf(NetTrace, " CANTCHANGE"); break;
+		    case SLC_VARIABLE:
+			fprintf(NetTrace, " VARIABLE"); break;
+		    case SLC_DEFAULT:
+			fprintf(NetTrace, " DEFAULT"); break;
+		    }
+		    fprintf(NetTrace, "%s%s%s",
+			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
+			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
+			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
+		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
+						SLC_FLUSHOUT| SLC_LEVELBITS))
+			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
+		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
+		    if ((pointer[i+SLC_VALUE] == IAC) &&
+			(pointer[i+SLC_VALUE+1] == IAC))
+				i++;
+		}
+		for (; i < length; i++)
+		    fprintf(NetTrace, " ?%d?", pointer[i]);
+		break;
+
+	    case LM_MODE:
+		fprintf(NetTrace, "MODE ");
+		if (length < 3) {
+		    fprintf(NetTrace, "(no mode??\?)");
+		    break;
+		}
+		{
+		    char tbuf[64];
+		    sprintf(tbuf, "%s%s%s%s%s",
+			pointer[2]&MODE_EDIT ? "|EDIT" : "",
+			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
+			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
+			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
+			pointer[2]&MODE_ACK ? "|ACK" : "");
+		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
+		}
+		if (pointer[2]&~(MODE_MASK))
+		    fprintf(NetTrace, " (0x%x)", pointer[2]);
+		for (i = 3; i < length; i++)
+		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
+		break;
+	    default:
+		fprintf(NetTrace, "%d (unknown)", pointer[1]);
+		for (i = 2; i < length; i++)
+		    fprintf(NetTrace, " %d", pointer[i]);
+	    }
+	    break;
+
+	case TELOPT_STATUS: {
+	    register char *cp;
+	    register int j, k;
+
+	    fprintf(NetTrace, "STATUS");
+
+	    switch (pointer[1]) {
+	    default:
+		if (pointer[1] == TELQUAL_SEND)
+		    fprintf(NetTrace, " SEND");
+		else
+		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
+		for (i = 2; i < length; i++)
+		    fprintf(NetTrace, " ?%d?", pointer[i]);
+		break;
+	    case TELQUAL_IS:
+		if (--want_status_response < 0)
+		    want_status_response = 0;
+		if (NetTrace == stdout)
+		    fprintf(NetTrace, " IS\r\n");
+		else
+		    fprintf(NetTrace, " IS\n");
+
+		for (i = 2; i < length; i++) {
+		    switch(pointer[i]) {
+		    case DO:	cp = "DO"; goto common2;
+		    case DONT:	cp = "DONT"; goto common2;
+		    case WILL:	cp = "WILL"; goto common2;
+		    case WONT:	cp = "WONT"; goto common2;
+		    common2:
+			i++;
+			if (TELOPT_OK((int)pointer[i]))
+			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
+			else
+			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
+
+			if (NetTrace == stdout)
+			    fprintf(NetTrace, "\r\n");
+			else
+			    fprintf(NetTrace, "\n");
+			break;
+
+		    case SB:
+			fprintf(NetTrace, " SB ");
+			i++;
+			j = k = i;
+			while (j < length) {
+			    if (pointer[j] == SE) {
+				if (j+1 == length)
+				    break;
+				if (pointer[j+1] == SE)
+				    j++;
+				else
+				    break;
+			    }
+			    pointer[k++] = pointer[j++];
+			}
+			printsub(0, &pointer[i], k - i);
+			if (i < length) {
+			    fprintf(NetTrace, " SE");
+			    i = j;
+			} else
+			    i = j - 1;
+
+			if (NetTrace == stdout)
+			    fprintf(NetTrace, "\r\n");
+			else
+			    fprintf(NetTrace, "\n");
+
+			break;
+				
+		    default:
+			fprintf(NetTrace, " %d", pointer[i]);
+			break;
+		    }
+		}
+		break;
+	    }
+	    break;
+	  }
+
+	case TELOPT_XDISPLOC:
+	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
+		break;
+	    case TELQUAL_SEND:
+		fprintf(NetTrace, "SEND");
+		break;
+	    default:
+		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
+				pointer[1], pointer[1]);
+	    }
+	    break;
+
+	case TELOPT_NEW_ENVIRON:
+	    fprintf(NetTrace, "NEW-ENVIRON ");
+#ifdef	OLD_ENVIRON
+	    goto env_common1;
+	case TELOPT_OLD_ENVIRON:
+	    fprintf(NetTrace, "OLD-ENVIRON");
+	env_common1:
+#endif
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		fprintf(NetTrace, "IS ");
+		goto env_common;
+	    case TELQUAL_SEND:
+		fprintf(NetTrace, "SEND ");
+		goto env_common;
+	    case TELQUAL_INFO:
+		fprintf(NetTrace, "INFO ");
+	    env_common:
+		{
+		    register int noquote = 2;
+#if defined(ENV_HACK) && defined(OLD_ENVIRON)
+		    extern int old_env_var, old_env_value;
+#endif
+		    for (i = 2; i < length; i++ ) {
+			switch (pointer[i]) {
+			case NEW_ENV_VALUE:
+#ifdef OLD_ENVIRON
+		     /*	case NEW_ENV_OVAR: */
+			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
+# ifdef	ENV_HACK
+				if (old_env_var == OLD_ENV_VALUE)
+				    fprintf(NetTrace, "\" (VALUE) " + noquote);
+				else
+# endif
+				    fprintf(NetTrace, "\" VAR " + noquote);
+			    } else
+#endif /* OLD_ENVIRON */
+				fprintf(NetTrace, "\" VALUE " + noquote);
+			    noquote = 2;
+			    break;
+
+			case NEW_ENV_VAR:
+#ifdef OLD_ENVIRON
+		     /* case OLD_ENV_VALUE: */
+			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
+# ifdef	ENV_HACK
+				if (old_env_value == OLD_ENV_VAR)
+				    fprintf(NetTrace, "\" (VAR) " + noquote);
+				else
+# endif
+				    fprintf(NetTrace, "\" VALUE " + noquote);
+			    } else
+#endif /* OLD_ENVIRON */
+				fprintf(NetTrace, "\" VAR " + noquote);
+			    noquote = 2;
+			    break;
+
+			case ENV_ESC:
+			    fprintf(NetTrace, "\" ESC " + noquote);
+			    noquote = 2;
+			    break;
+
+			case ENV_USERVAR:
+			    fprintf(NetTrace, "\" USERVAR " + noquote);
+			    noquote = 2;
+			    break;
+
+			default:
+			    if (isprint(pointer[i]) && pointer[i] != '"') {
+				if (noquote) {
+				    putc('"', NetTrace);
+				    noquote = 0;
+				}
+				putc(pointer[i], NetTrace);
+			    } else {
+				fprintf(NetTrace, "\" %03o " + noquote,
+							pointer[i]);
+				noquote = 2;
+			    }
+			    break;
+			}
+		    }
+		    if (!noquote)
+			putc('"', NetTrace);
+		    break;
+		}
+	    }
+	    break;
+
+	default:
+	    if (TELOPT_OK(pointer[0]))
+		fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
+	    else
+		fprintf(NetTrace, "%d (unknown)", pointer[0]);
+	    for (i = 1; i < length; i++)
+		fprintf(NetTrace, " %d", pointer[i]);
+	    break;
+	}
+	if (direction) {
+	    if (NetTrace == stdout)
+		fprintf(NetTrace, "\r\n");
+	    else
+		fprintf(NetTrace, "\n");
+	}
+	if (NetTrace == stdout)
+	    fflush(NetTrace);
+    }
+}
+
+/* EmptyTerminal - called to make sure that the terminal buffer is empty.
+ *			Note that we consider the buffer to run all the
+ *			way to the kernel (thus the select).
+ */
+
+    void
+EmptyTerminal()
+{
+#if	defined(unix)
+    fd_set	o;
+
+    FD_ZERO(&o);
+#endif	/* defined(unix) */
+
+    if (TTYBYTES() == 0) {
+#if	defined(unix)
+	FD_SET(tout, &o);
+	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+			(struct timeval *) 0);	/* wait for TTLOWAT */
+#endif	/* defined(unix) */
+    } else {
+	while (TTYBYTES()) {
+	    (void) ttyflush(0);
+#if	defined(unix)
+	    FD_SET(tout, &o);
+	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+				(struct timeval *) 0);	/* wait for TTLOWAT */
+#endif	/* defined(unix) */
+	}
+    }
+}
+
+    void
+SetForExit()
+{
+    setconnmode(0);
+#if	defined(TN3270)
+    if (In3270) {
+	Finish3270();
+    }
+#else	/* defined(TN3270) */
+    do {
+	(void)telrcv();			/* Process any incoming data */
+	EmptyTerminal();
+    } while (ring_full_count(&netiring));	/* While there is any */
+#endif	/* defined(TN3270) */
+    setcommandmode();
+    fflush(stdout);
+    fflush(stderr);
+#if	defined(TN3270)
+    if (In3270) {
+	StopScreen(1);
+    }
+#endif	/* defined(TN3270) */
+    setconnmode(0);
+    EmptyTerminal();			/* Flush the path to the tty */
+    setcommandmode();
+}
+
+    void
+Exit(returnCode)
+    int returnCode;
+{
+    SetForExit();
+    exit(returnCode);
+}
+
+    void
+ExitString(string, returnCode)
+    char *string;
+    int returnCode;
+{
+    SetForExit();
+    fwrite(string, 1, strlen(string), stderr);
+    exit(returnCode);
+}
diff --git a/mechglue/src/appl/telnet/telnetd/.Sanitize b/mechglue/src/appl/telnet/telnetd/.Sanitize
new file mode 100644
index 000000000..87df12999
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/.Sanitize
@@ -0,0 +1,57 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.4.4
+Makefile.generic
+Makefile.in
+Makefile.orig
+authenc.c
+configure
+configure.in
+defs.h
+ext.h
+global.c
+pathnames.h
+slc.c
+state.c
+sys_term.c
+telnetd-ktd.c
+telnetd.0.ps
+telnetd.0.txt
+telnetd.8
+telnetd.c
+telnetd.h
+termstat.c
+termio-tn.c
+termios-tn.c
+utility.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/telnet/telnetd/ChangeLog b/mechglue/src/appl/telnet/telnetd/ChangeLog
new file mode 100644
index 000000000..760cbb23f
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/ChangeLog
@@ -0,0 +1,815 @@
+2004-11-15  Tom Yu  <tlyu@mit.edu>
+
+	* ext.h: New variable "must_encrypt".
+
+	* telnetd.8: Update for changed command-line options.
+
+	* telnetd.c (getterminaltype): Merge Athena changes to require
+	encrypted connections.
+
+	* utility.c (ttsuck): Merge Athena changes to work around some
+	client timing bugs.
+
+2004-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (telnetd): Use UTIL_LIB.
+
+2004-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Deleted; configure this dir from parent now.
+	* Makefile.in (thisconfigdir, mydir): Updated.
+	(LIBS): Define from @TELNETD_LIBS@.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* telnetd.h: Don't declare errno.
+
+2003-01-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* telnetd.c (main): Use socklen_t when passing address to socket
+	functions.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.orig: Deleted.
+
+2002-11-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Test for speed_t being present.
+
+	* sys_term.c (addarg): When reallocing memory, ensure in size of
+	pointer. Use speed_t instead of int for termspeeds.
+
+	* authenc.c, ext.h, state.c, utility.c: Unsigned/signed cleanup.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-08  Jen Selby  <jenselby@mit.edu>
+
+	* telnetd.c: Switched the valid and user descriptions under the -a
+	flag
+
+2002-03-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* telnetd.c: Include fake-addrinfo.h, not fake-addrinfo.c.
+	(FAI_PREFIX): Delete.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* defs.h, state.c, sys_term.c, telnetd-ktd.c, telnetd.c: Make
+	prototypes unconditional.
+
+Sat Sep  8 08:24:51 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* telnetd.c: Move include of fake-addrinfo.c to after stdlib.h so
+ 	that malloc prototype povided.
+
+2001-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for ipv6 support.
+
+	* ext.h: Always use prototype declarations.
+	(P): Definitions deleted.
+
+	* defs.h: Don't include socket-utils.h until after netinet/in.h.
+
+2001-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* defs.h: Include socket-utils.h.
+	* telnetd.c: Include fake-addrinfo.c.
+	(FAI_PREFIX): Define.
+	(doit): Now static, and takes sockaddr pointer rather than
+	sockaddr_in pointer.  Use getnameinfo instead of gethostbyaddr to
+	verify that host name was available.
+	(main): Use sockaddr_storage for remote address buffer; clear
+	before using.  Only do IP_TOS processing for IPv4.
+
+	* termio-tn.c, termios-tn.c: Define dummy variables if STREAMSPTY
+	isn't defined, to silence compiler complaints about empty files.
+
+2001-08-02  Tom Yu  <tlyu@mit.edu>
+
+	* authenc.c (net_write): Rewrite in terms of netwrite().
+
+	* configure.in: Check for vsnprintf().
+
+	* ext.h: New prototypes for netprintf, netprintf_urg,
+	netprintf_noflush, netwrite, netputs.
+
+	* slc.c: Fix to use new NETOBUF-handling functions.
+
+	* state.c: Fix to use new NETOBUF-handling functions.
+
+	* telnetd.c: Fix to use new NETOBUF-handling functions.
+
+	* termstat.c: Fix to use new NETOBUF-handling functions.
+
+	* utility.c: General rework to be more paranoid about
+	bounds-checking of NETOBUF and NFRONTP.  Abstract away
+	interactions with NETOBUF to eliminate explicit references to
+	NFRONTP in many places.
+	(netwrite): New function; copies a buffer to the
+	NETOBUF "ring buffer", checking bounds and calling netflush() if
+	needed.
+	(netputs): New function; calls netwrite() with a nul-terminated
+	string.
+	(netprintf, netprintf_ext): New function; wrap sprintf() with
+	bounds checking for use with NETOBUF.
+	(netprintf_urg): New function; like netprintf() except sets neturg
+	to point at last char written.
+	(netprintf_noflush): New function; like netprintf() except
+	silently fails if NETOBUF is full.
+	(ttloop, printoption, printsub, printdata): Fix to use new
+	NETOBUF-handling functions.
+
+2001-07-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* sys_term.c (startslave): Get rid of extra argument in call to
+	getptyslave().
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* sys_term.c (addarg): Cast char to long in indexing array.
+
+2001-07-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* state.c: Declate doclientstat() static and conditionalize
+	inclusion if LINEMODE defined. 
+
+	* sys_term.c: Declare getptyslave() and addard() static.
+
+	* telnetd.c: Declare _gettermname() and getterminaltype() static.
+
+	* utility.c: Declare putstr() and nextitem() static.
+
+2001-06-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* telnetd.c (main): Change variable sin to sin4.
+	(encrypt_failure): Change to not shadow global error_message.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* telnetd.c: Add prototypes for getent() and tgetent(). 
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Test if prototypes needed for setenv and unsetenv. 
+
+	* ext.h: Provide prototypes for unsetenv and setenv if needed.
+
+2001-06-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* utility.c (printsub): Ensure variable set before use.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* utility.c (printdata): Cast argument to isprint() to int.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* ext.h: Remove unused prototype for start_slave() and replace
+	with one for startslave().
+
+	* state.c: Add libtlnet/encrypt.h for missing prototypes.
+
+	* sys_term.c: Add prototype for dup_tty(). Change getptyslave()
+	from int to void. Cleanup an assignment in conditional warning. 
+
+	* telnetd.c: Include libtelnet/misc-proto.h. Declare return from
+	terminaltypeok() and main() as int.
+
+	* utility.c: Include libtelnet/auth.h and libtelnet/encrypt.h for
+	prototypes.
+
+2001-04-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* telnetd.c (valid_opts): Note that 'w' takes a parameter.
+	Reported by Nico Williams, <Nicolas.Williams@ubsw.com>.
+	(main): Delete options 'N', 'u', 'i' that were removed from
+	valid_opts in 1999.
+	(usage): Don't show -u option.  Align output columns better.
+
+2001-01-25  Tom Yu  <tlyu@mit.edu>
+
+	* state.c (envvarok): Disallow LC_* and NLSPATH.
+
+2000-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* telnetd.c (doit): Cast pty_make_sane_hostname first argument to
+	sockaddr pointer.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+        * configure.in: Use AC_CHECK_HEADER and AC_CHECK_FUNC instead of
+	AC_HEADER_CHECK and AC_FUNC_CHECK.
+
+2000-06-29  Tom Yu  <tlyu@mit.edu>
+
+	* telnetd.c (doit): Change test for "no authentication" as per
+	Jeffrey Altman's patch.
+
+2000-06-29  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* sys_term.c (start_login, Solaris): forcefully terminate "termbuf"
+	in case the "TERM" environment variable isn't.
+	* telnet-ktd.c (getterminaltype): Don't overflow buffers "first" and
+	"netobuf".
+	(recv_ayt): Forcibly terminate buffer "netobuf".
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* configure.in, defs.h: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-03-20  Ken Raeburn  <raeburn@mit.edu>
+	    Jeffrey Altman  <jaltman@watsun.cc.columbia.edu>
+
+	* state.c (telrcv): Fix off-by-one error dealing with full
+	buffer.
+
+2000-02-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Remove dependency on libdes425 when krb4 support
+		is not compiled in.
+
+2000-02-21  Bear Giles  <bgiles@coyotesong.com>
+	    Ken Raeburn  <raeburn@mit.edu>
+
+	* telnetd.c (doit): Provide a more useful error message than
+	"authentication failed" if no authentication was even attempted.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Thu Apr 15 17:02:49 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* configure.in: Fix typo in test below; fixed name of the autoconf
+		cache variable which indicates if sys/streams.h exists.
+
+1999-04-13    <tytso@rsts-11.mit.edu>
+
+	* configure.in: Check for setupterm() in libncurses in addition to
+		libcurses.  Only set STREAMSPTY if both grantpt and
+		sys/streams.h exists.  (Will be needed for Linux/Redhat 6.0)
+
+Wed Mar 31 00:05:58 1999  Tom Yu  <tlyu@mit.edu>
+
+	* sys_term.c (getptyslave): Under AIX, ignore I_PUSH pckt
+	failure.
+
+Tue Mar 30 23:59:15 1999  Tom Yu  <tlyu@mit.edu>
+
+	* termios-tn.c: Include termio.h under AIX due to brokenness.
+
+Wed Feb 24 20:12:10 1999  Tom Yu  <tlyu@mit.edu>
+
+	* telnetd.8: Resync manpage.
+
+	* telnetd.c: Rework flags controlling hostname logging.
+
+Mon Feb 22 18:27:38 1999  Tom Yu  <tlyu@mit.edu>
+
+	* telnetd.8: Document hostname logging changes.
+
+	* telnetd.c: Add options to control logging of remote hostname to
+	login(1).
+
+Wed Feb  3 22:57:52 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* state.c: Increase size of subbufer so that we don't truncate
+		mongo-gram tickets from Microsoft.  [telnet/688]
+
+1998-11-14  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Add check for <sys/utsname.h>.
+
+	* utility.c (putf): Add support for %s, %m, %r, %v using
+		information from the uname() system call.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Wed Aug 12 00:17:09 1998  Matthew D Hancher  <mdh@mit.edu>
+
+	* Makefile.in (AUTH_DEF): Undefine LOGIN_CAP_F so that telnetd
+	runs login with -f rather than -F for preauthenticated login, 
+	following the changes in appl/bsd/.
+
+1998-05-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sys_term.c: #include utmp.h if present, and use _PATH_WTMP and
+		_PATH_UTMP if defined to determine location of the wtmp
+		and utmp files.
+
+	* configure.in: Add check for utmp.h
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* telnetd.c (main): 
+	* telnetd-ktd.c (main): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Tue Mar  3 14:26:04 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Rename HAS_* to HAVE_* for the following tests:
+ 		sac.h, sys/ptyvar.h, sys/filio.h, sys/stream.h,
+ 		gettosbyname(), and make appropriate adjustments in the
+ 		rest of the .c files.  Remove tests which aren't being
+ 		used anymore: vhangup, utmpx.h, utmp.h, etc.
+
+	* defs.h: Use HAVE_SYS_FILIO_H instead of FILIO_H
+
+	* sys_term.c: Use HAVE_SAC_H and HAVE_SYS_STREAM_H instead of
+		HAS_SAC and STREAMS.
+
+	* telnetd.c, telnetd-ktd.c: Use HAVE_GETTOSBYNAME instead of
+		HAS_GETTOS
+
+	* telnetd.c: Use HAVE_SYS_PTYVAR_H instead of HAS_PTYVAR.
+
+Mon Feb 23 22:58:22 1998  Tom Yu  <tlyu@mit.edu>
+
+	* utility.c (ptyflush, netflush): Explicitly reset SIGCHLD handler
+ 	before calling cleanup(). [telnet/546]
+
+	* telnetd.c (telnet):  Explicitly reset SIGCHLD handler before
+	calling cleanup(). [telnet/546]
+
+	* state.c (dooption): Explicitly reset SIGCHLD handler before
+	calling cleanup(). [telnet/546]
+
+Wed Feb 18 15:38:31 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Sat Feb 14 10:35:36 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Remove USE_ANAME.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 28 17:21:08 1998  Dan Winship  <danw@mit.edu>
+
+	* telnetd.c (doit): additional fix for previous terminaltype change
+
+Tue Jan 27 18:27:16 1998  Dan Winship  <danw@mit.edu>
+
+	* telnetd.c (getterminaltype): Null-terminate strings and avoid a
+	buffer overrun.
+
+	* ext.h: make terminaltype a char[] instead of a char * for
+	telnetd.c change
+
+	* state.c (suboption): redo handling of terminaltype
+
+Fri Jan 23 22:13:02 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* telnetd.c (telnet, get_default_IM): Instead of using a hardcoded
+		IM variable, use one which is dynamically generated from
+		the uname() system call.
+
+	* ext.h: Remove definition of DEFAULT_IM, since it's no longer used.
+
+Thu Dec  4 21:32:37 1997  Tom Yu  <tlyu@mit.edu>
+
+	* telnetd.c (doit): Fix up slave buffer length.
+
+Thu Oct 23 13:59:32 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* state.c (envvarok): Prohibit the passing of TERMCAP, TERMPATH,
+		TERMINFO, and HOME, since they can be used to exploit a
+		security hole in tgetent.
+
+Wed Apr  9 23:46:40 1997  Tom Yu  <tlyu@mit.edu>
+
+	* sys_term.c (start_login): Bounds check the constructed "speed"
+	passed in to login.
+
+Wed Feb 12 15:22:53 1997  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: Fix DES425_DEPLIB
+
+Wed Feb  5 22:08:58 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Nov  7 15:32:06 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* telnetd.c (main): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Mon Oct 14 01:55:41 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* utility.c (printsub): Patch from jhawk@bbnplannet.com to deal
+ 	with bug printing out authentication name. [71]
+Sat Sep 21 03:38:31 1996  Sam Hartman  <hartmans@mit.edu>
+(printsub): Fix encrypt promise bit option parsing [74]
+
+	* utility.c (ttloop): Continue on eintr.
+
+Tue Sep 10 14:10:41 1996  Tom Yu  <tlyu@mit.edu>
+
+	* telnetd.8: remove ".so man1/header.doc"
+
+Mon Aug 19 23:22:55 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* state.c (envvarok): Don't allow the environment variable
+	 	RESOLV_HOST_CONF to be set for Linux's sake.
+
+Thu Jun 13 17:05:17 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* telnetd.8: Remove documentation of  desupported -u options.
+
+	* sys_term.c: Remove last fragments of PARENT_DOES_UTMP, and
+ 	remove dependence on utmp.h and utmpx.h
+
+	* telnetd.c: Remove support for -u option as that type of utmp
+ 	mucking is below the libpty abstraction and I do not see it as
+ 	useful enough to export outside libpty.
+
+Tue Jun  4 00:27:09 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Ezra's changes to allow compiling w/o krb4
+
+Wed May  1 21:14:45 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Fix typo in Apr 16 HP-UX change.
+
+	Thu Apr 18 16:17:55 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* state.c (envvarok): nuke all KRB5* environment variables, not
+	just the previously selected ones.
+
+	Fri Mar 29 01:21:29 1996  Marc Horowitz  <marc@mit.edu>
+
+	* telnetd.c (telnet -> doit): moved SIGTTOU handler before the
+ 	first thing which would cause the terminal driver to get upset.
+
+	Mon Mar 25 01:05:50 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* sys_term.c (line): Remove initialization silliness.  The
+	non-GNUC method was Just Wrong, do it the other way always.
+	(Xline): Specify length, not contents.
+
+	Wed Feb 28 22:27:46 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* termio-tn.c (readstream_termio): new file, provides isolated
+	version of M_IOCTL handling for systems where termio and termios
+	can't be compiled together.
+	* termios-tn.c (readstream_termios): new file, provides isolated
+	version of M_IOCTL handling for systems where termio and termios
+	can't be compiled together.
+	* telnetd.c (readstream): use readstream_termios and
+	readstream_termio to handle getmsg with M_IOCTL.
+
+Thu Apr 18 16:33:42 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* state.c (suboption): Don't accept authentication suboptions
+	after authentication negotiation complete.
+	(envvarok):  exclude KRB5_KTNAME and KRB5CCNAME
+
+Tue Apr 16 12:23:02 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in : Treat HPUX as if it doesn't have streams.
+
+	* state.c (suboption): For certain options like environment and X
+ 	display, require authentication and encryption to be established
+ 	or not established before processing the option.
+	(sb_auth_complete): Fail and kill telnetd if authentication
+ 	negotiation is not complete.
+
+	* ext.h: Define new global variable indicating whether encryption
+ 	wait has happened.
+
+Thu Apr 11 21:44:39 1996  Richard Basch  <basch@lehman.com>
+
+	* sys_term.c (cleanup): Call the Kerberos 5 cleanup routine, also.
+
+Wed Mar 27 00:27:32 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* telnetd.c: remove inclusion of netdb.h; it's already in defs.h,
+		and #$%&* ultrix doesn't protect it from multiple
+		inclusions.
+
+Sat Mar 23 01:33:09 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* sys_term.c: Remove utmpx stuff so libpty can do it.
+	(start_login): Remove utmpx handling here as well.
+	(rmut): expunged; libpty should deal.
+
+	* configure.in : Do not use streamspty on SGIs; it really doesn't
+ 	work, even though all the interfaces are prsent.
+
+	* telnetd.c: Move prototype for doit to be global instead of
+        streams-specific.
+
+	Tue Mar 19 18:43:46 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+        For environments not supporting common storage:
+        * defs.h (P): Add definition here.
+        (line, encrypt_output, decrypt_input): Declare here.
+        * ext.h (line, encrypt_output, decrypt_input): Not here.
+        (terminaltype): Declare explicitly "extern".
+        * telnetd.c (auth_level, require_SecurID): Don't initialize here.
+
+Mon Mar 18 20:29:05 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Added flags which turn on the encryption option.
+
+	* telnetd.c (getterminaltype): If the authentication option which
+		was negotiated requires that encryption be turned on, then
+		enforce this here.
+
+Sun Mar  3 14:43:04 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* configure.in: if we don't have termcap, check for curses lib.
+
+Wed Feb 28 21:07:42 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* telnetd.c (telnet): rename HE to HEstr to avoid conflict with
+	HP/UX 10.01 "Fields within IO_STATUS register" values in cpu.h.
+
+Mon Feb 26 03:33:48 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Call USE_ANAME
+
+Sun Feb 25 20:26:00 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* telnetd.c: Use MAXDNAME not MAXHOSTNAMELEN; MAXHOSTNAMELEN is
+        only for gethostname() and sethostname() and has nothing to do
+        with domains.
+
+	* configure.in : Check for arpa/nameser.h for MAXDNAME
+
+Tue Feb 13 16:23:23 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ext.h, utility.c (fatalperror, fatal): Add const to argument.
+
+Mon Jan 15 17:35:25 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* sys_term.c: Call pty_update_utmp with PTY_TTYSLOT_USABLE flag.
+
+Mon Nov 27 15:55:50 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* state.c: use P properly so it won't break non-ansi compilers.
+
+Sun Nov 12 04:56:15 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* telnetd.8: source tmac.doc for correct parsing.
+
+Sat Oct 21 15:37:55 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* state.c (envvarok): Also check for variables involving =.
+
+Thu Oct 19 01:28:23 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* state.c (envvarok): New function, checks environment variables
+	for exceptions that should not be passed to login.
+	(suboption): don't do anything to propagated environment variables
+	if they fail the exception test above.
+
+Mon Oct  9 23:01:36 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* telnetd.c (getterminaltype): If ENCRYPTION defined, send do
+        encryption, *not* just will encrypt. if you don't do this, then you won't encrypt the input to the server; your password prompt is encrypted, but your password isn't.
+
+Tue Aug  8 11:26:54 1995  Sam Hartman  <hartmans@pao.mit.edu>
+
+	* sys_term.c: Fail if the slave side dies.
+	(dup_tty): Renamed from login_tty because OSF already has that function and it isn't compatible.
+
+	(getptyslave): Fix argument to fatalperror by including com_err.h instead of casting.
+
+Tue Aug 8 17:25:22 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* sys_term.c - Cast argument to fatalperror().
+
+
+
+
+	* sys_term.c: Use new interface to pty_update_utmp.
+	(getptyslave): Handle error return from pty_open_slave
+	Close syncpipe[1] before we read from it.
+
+Mon Aug 7 14:44:21 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in, sys_term.c - Use utmpx.h if present, then check for
+		utmp.h.  Add logic to handle ut_tv from utmpx.h.
+
+
+Mon Aug 7 13:08:39 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add check for utmp.h.  Make check for utmpx.h define
+		additional symbol to work with libpty.h.
+	* sys_term.c - Fix syntax error and reinstate #ifdef LINEMODE deleted
+		by last checkin.
+
+Fri Aug  4 20:22:28 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* sys_term.c (getptyslave): Select terminal settings more likely
+        to work.
+	(cleanup): Pass pid to cleanup so it can killpg if necessary.
+
+Tue Aug  1 11:28:55 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* telnetd.c (doit): Use pty_getpty.
+
+	* Makefile.in (LOCAL_LIBRARIES): Add -lpty
+
+	* sys_term.c (startslave): Use pty_update_utmp.  Export slave's
+        pid so it's global for pty_cleanup.  Use pipe to synchronize so
+        that slave is opened before parent writes.
+	(cleanopen): removed in favor of pty_open_slave
+	(login_tty): Don't set controlling terminal; libpty does this.  Just dup2 the terminals.
+	(getpty): removed.
+
+	(getptyslave): Use libpty.
+
+	* telnetd-ktd.c: Use libpty.
+
+Tue Jul 11 11:32:56 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+Sat Jul 29 04:40:04 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+
+	* telnetd-ktd.c (doit): Remove special casing of Convex PTY
+        handling here.  There isn't enough code here for me to understand
+        what to do on a Convex system, so if it breaks, it should be
+        special cased in a more-appropriate manner.
+
+
+	* configure.in: Don't link with -lkadm.
+
+Fri Jul 7 15:51:03 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling.
+	* configure.in - Add USE_{KRB4,KADM}_LIBRARY and KRB5_LIBRARIES.
+
+Tue Jun 20 14:25:01 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* defs.h: NO_STRING_H -> HAVE_STRING_H
+
+	* configure.in: add test for string.h
+
+Thu Jun 15 17:43:21 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+		Also, remove DBMLIB, it was not used. Also, for K4, use
+		KRB4_LIB and KRB4_CRYPTO_LIB, these were
+                split out.
+	* configure.in - Remove dbm library checks, these are no longer needed
+		with the Berkeley database code.  Also, add shared library
+		usage check.
+
+
+Thu Jun 15 16:18:39 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* sys_term.c (getpty): On AIX, open /dev/ptc for master and use
+        ttyname() to get slave side; much simpler and doesn't get used
+        ptys.
+
+	(cleanopen): Revoke on AIX as well.  This may cause problems on early 3.2 versions, but not revoking causes disconnected sessions to be partially connected to new telnets.  The complete fix will be to make sure telnetd cleans up when it dies.
+
+
+
+
+Fri Jun  9 18:29:56 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed May  3 16:50:05 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* telnetd.c: respect HAVE_SYS_TTY_H.
+
+Mon May  1 11:33:28 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* defs.h: Temporary hack for the alpha. Undefine STREAMSPTY if
+		defined. This will be removed in a later release.
+
+Fri Apr 28 18:07:34 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (KLIB): put KRB4_LIB inside KLIB.
+
+Thu Apr 27 13:57:03 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (telnetd): use KRB4_LIB directly.
+	* configure.in: use WITH_KRB4 as-is.
+
+Wed Apr 25 22:53:20 1995  Chris Provenzano  (proven@mit.edu)
+
+        * configure.in, sys_term.c, telnetd.c : Have configure check for
+                sys/ptyvar.h and sac.h before .c files include it.
+
+Sat Apr 22 00:52:01 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* telnetd.c (main): Don't use krb5_override_default_realm, as it
+		is obsolete (non-existent).  Use krb5_set_default_realm
+		instead. 
+
+Fri Apr 21 12:47:57 1995  Mark Eichin  <eichin@cygnus.com>
+
+	From Ian Taylor <ian@cygnus.com>.
+	* telnetd.c (valid_opts): Add 'L'.  If KRB5, add -R and -t.
+	(main): Handle -L.  If KRB5, handle -R and -t.
+	* sys_term.c (login_program): New global variable.
+	(start_login): Use login_program instead of LOGIN_PROGRAM.
+
+Wed Mar 29 15:39:39 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Add dependency on libtelnet.a
+
+Tue Mar  7 19:59:30 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: take out ISODE_INCLUDE.
+
+Thu Mar  2 12:30:32 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:25:58 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE and ISODE_DEFS, replace check
+		for -lsocket and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:50:22 1995  John Gilmore  (gnu at toad.com)
+
+	* sys_term.c:  Avoid <krb5/...> includes.
+
+Wed Jan 11 15:23:07 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in (K4LIB): fix quoting so $(KRB4) actually survives
+	to the Makefile.
+
+Fri Nov 18 01:23:13 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (install): install telnetd manpage
+	(from Ted Lemon <mellon@ipd.wellsfargo.com>).
+
+Fri Nov 18 00:44:05 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: use WITH_KRB4, cache cc_t in termio check, cache
+	SETPGRP_TWOARG check.
+	* Makefile.in (K4LIB): use @K4LIB@.
+	(telnetd): use $(K4LIB). (from epeisach)
+
+Mon Nov  7 22:16:51 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: 
+	  sys_term.c: Only include <sys/tty.h> if HAVE_SYS_TTY_H is
+	  	  defined by configure.
+
+        * configure.in: Check for sys/time.h and time.h.
+
+	* defs.h: Pull in <sys/time.h> and <time.h> as necessary.
+
+	* sys_term.c (startslave): Don't define time() manually.
+
+	* configure.in: Add check for util library (needed for the Alpha)
+
+Thu Sep 29 22:51:52 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executables if libraries change
+
+Tue Aug 16 18:04:58 1994  Mark Eichin  (eichin@tweedledumber.cygnus.com)
+
+	* configure.in: check for vhangup.
+	sys_term.c (cleanup): check for HAVE_VHANGUP.
+	(cleanopen): ditto.
+
+Mon Aug  8 01:15:27 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* utility.c (putf): don't misdeclare index/rindex, strings.h
+	already got included. Don't even use them -- use str*chr instead.
+
+Thu Aug  4 03:37:26 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: pick up dbm libs
+
+	* sys_term.h: fix linux lossage, i.e. <linux/tty.h>
+	* configure.in: check for STREAMSPTY (hopefully)
+
+	* Makefile.in:
+	* configure.in: make install changes
+
+Tue Jul 26 18:23:01 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: fix missing $(srcdir)
+
+Mon Jul 25 02:35:16 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: check for utmpx
+
diff --git a/mechglue/src/appl/telnet/telnetd/ISSUES b/mechglue/src/appl/telnet/telnetd/ISSUES
new file mode 100644
index 000000000..5b61997bb
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/ISSUES
@@ -0,0 +1,7 @@
+Issues to be dealt with in telnetd:
+
+Debug mode won't do ipv6.
+
+FIX: Rewrite listener setup code in main after argument parsing.
+
+Needs auditing.
diff --git a/mechglue/src/appl/telnet/telnetd/Makefile.4.4 b/mechglue/src/appl/telnet/telnetd/Makefile.4.4
new file mode 100644
index 000000000..4b1d5302e
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/Makefile.4.4
@@ -0,0 +1,36 @@
+#	@(#)Makefile	8.2 (Berkeley) 12/15/93
+
+PROG=	telnetd
+CFLAGS+=-DLINEMODE -DKLUDGELINEMODE -DUSE_TERMIO -DDIAGNOSTICS
+CFLAGS+=-DOLD_ENVIRON -DENV_HACK
+CFLAGS+=-DAUTHENTICATION -DENCRYPTION -I${.CURDIR}/../../lib
+SRCS=	authenc.c global.c slc.c state.c sys_term.c telnetd.c \
+	termstat.c utility.c
+DPADD=	${LIBUTIL} ${LIBTERM}
+LDADD=	-lutil -ltermcap -ltelnet
+LDADD+=	-lkrb -ldes
+MAN8=	telnetd.0
+
+# These are the sources that have encryption stuff in them.
+CRYPT_SRC= authenc.c ext.h state.c telnetd.c termstat.c
+CRYPT_SRC+= utility.c Makefile
+NOCRYPT_DIR=${.CURDIR}/Nocrypt
+
+.include <bsd.prog.mk>
+
+nocrypt:
+#ifdef	ENCRYPTION
+	@for i in ${CRYPT_SRC}; do \
+	    if [ ! -d ${NOCRYPT_DIR} ]; then \
+		echo Creating subdirectory ${NOCRYPT_DIR}; \
+		mkdir ${NOCRYPT_DIR}; \
+	    fi; \
+	    echo ${NOCRYPT_DIR}/$$i; \
+	    unifdef -UENCRYPTION ${.CURDIR}/$$i | \
+		sed "s/ || defined(ENCRYPTION)//" > ${NOCRYPT_DIR}/$$i; \
+	done
+
+placeholder:
+#else	/* ENCRYPTION */
+	@echo "Encryption code already removed."
+#endif	/* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/telnetd/Makefile.generic b/mechglue/src/appl/telnet/telnetd/Makefile.generic
new file mode 100644
index 000000000..892042973
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/Makefile.generic
@@ -0,0 +1,71 @@
+#
+# Copyright (c) 1991 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted provided
+# that: (1) source distributions retain this entire copyright notice and
+# comment, and (2) distributions including binaries display the following
+# acknowledgement:  ``This product includes software developed by the
+# University of California, Berkeley and its contributors'' in the
+# documentation or other materials provided with the distribution and in
+# all advertising materials mentioning features or use of this software.
+# Neither the name of the University nor the names of its contributors may
+# be used to endorse or promote products derived from this software without
+# specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#	@(#)Makefile.generic	5.5 (Berkeley) 3/1/91
+#
+
+SRC1=	telnetd.c state.c termstat.c slc.c sys_term.c utility.c global.c authenc.c
+OBJ1=	telnetd.o state.o termstat.o slc.o sys_term.o utility.o global.o authenc.o
+
+OBJS=	${OBJ1} ${GETTYOBJ}
+SRCS=	${SRC1} ${GETTYSRC}
+
+MAN=	telnetd.0
+CFLAGS=	${LCCFLAGS} ${INCLUDES} ${DEFINES}
+ARPA_TELNET = ../arpa/telnet.h
+
+#
+# These next three lines are not needed in 4.4BSD
+#
+.SUFFIXES: .0 .8
+.8.0:
+	nroff -man -h $< > $@
+
+
+all: telnetd
+
+telnetd: ${OBJS} ${LIBPATH}
+	${CC} -o $@ ${CFLAGS} ${OBJS} ${LIBS}
+
+clean:
+	rm -f ${OBJS} core telnetd
+
+cleandir: clean
+	rm -f ${MAN} tags .depend
+
+depend: ${SRCS}
+	mkdep ${CFLAGS} ${SRCS}
+
+install: ${MAN}
+	install -s -o bin -g bin -m 755 telnetd ${LIBEXEC}
+	install -c -o bin -g bin -m 444 ${MAN} ${DESTDIR}/usr/man/cat8
+
+lint: ${SRCS}
+	lint ${CFLAGS} ${SRCS}
+
+tags: ${SRCS}
+	ctags ${SRCS}
+
+authenc.o: telnetd.h
+global.o: defs.h ext.h ${ARPA_TELNET}
+slc.o: telnetd.h defs.h ext.h ${ARPA_TELNET}
+state.o: telnetd.h defs.h ext.h ${ARPA_TELNET}
+sys_term.o: telnetd.h pathnames.h defs.h ext.h ${ARPA_TELNET}
+telnetd.o: telnetd.h defs.h ext.h ${ARPA_TELNET}
+termstat.o: telnetd.h defs.h ext.h ${ARPA_TELNET}
+utility.o: telnetd.h defs.h ext.h ${ARPA_TELNET}
diff --git a/mechglue/src/appl/telnet/telnetd/Makefile.in b/mechglue/src/appl/telnet/telnetd/Makefile.in
new file mode 100644
index 000000000..37b26ceb1
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/Makefile.in
@@ -0,0 +1,144 @@
+thisconfigdir=..
+myfulldir=appl/telnet/telnetd
+mydir=telnetd
+BUILDTOP=$(REL)..$(S)..$(S)..
+# derived from the original Makefile.generic
+#
+# Copyright (c) 1991 The Regents of the University of California.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms are permitted provided
+# that: (1) source distributions retain this entire copyright notice and
+# comment, and (2) distributions including binaries display the following
+# acknowledgement:  ``This product includes software developed by the
+# University of California, Berkeley and its contributors'' in the
+# documentation or other materials provided with the distribution and in
+# all advertising materials mentioning features or use of this software.
+# Neither the name of the University nor the names of its contributors may
+# be used to endorse or promote products derived from this software without
+# specific prior written permission.
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#	@(#)Makefile.generic	5.5 (Berkeley) 3/1/91
+#
+
+AUTH_DEF=-DAUTHENTICATION -DENCRYPTION -DKRB5 -DFORWARD -UNO_LOGIN_F -ULOGIN_CAP_F -DLOGIN_PROGRAM=KRB5_PATH_LOGIN
+OTHERDEFS=-DKLUDGELINEMODE -DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON
+LOCALINCLUDES=-I.. -I$(srcdir)/..
+DEFINES = $(AUTH_DEF) $(OTHERDEFS)
+ARPA_TELNET= $(srcdir)/../arpa/telnet.h
+
+PROG_LIBPATH=-L$(TOPLIBD) $(KRB4_LIBPATH)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+LIBS=	@TELNETD_LIBS@
+
+SRCS=	$(srcdir)/telnetd.c \
+	$(srcdir)/termio-tn.c \
+	$(srcdir)/termios-tn.c \
+	$(srcdir)/state.c \
+	$(srcdir)/termstat.c \
+	$(srcdir)/slc.c \
+	$(srcdir)/sys_term.c \
+	$(srcdir)/utility.c \
+	$(srcdir)/global.c \
+	$(srcdir)/authenc.c \
+	$(GETTYSRC)
+OBJS=	telnetd.o \
+	termio-tn.o \
+	termios-tn.o \
+	state.o \
+	termstat.o \
+	slc.o \
+	sys_term.o \
+	utility.o \
+	global.o \
+	authenc.o \
+	$(GETTYOBJ)
+
+all:: telnetd
+
+telnetd: $(OBJS) $(PTY_DEPLIB) $(KRB4COMPAT_DEPLIBS) ../libtelnet/libtelnet.a
+	$(CC_LINK) -o $@ $(OBJS) ../libtelnet/libtelnet.a $(PTY_LIB) $(UTIL_LIB) $(KRB4COMPAT_LIBS)
+
+clean::
+	$(RM) telnetd
+
+install::
+	for f in telnetd; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(SERVER_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.8 \
+		${DESTDIR}$(SERVER_MANDIR)/`echo $$f|sed '$(transform)'`.8; \
+	done
+
+authenc.o: telnetd.h
+global.o: defs.h ext.h $(ARPA_TELNET)
+slc.o: telnetd.h defs.h ext.h $(ARPA_TELNET)
+state.o: telnetd.h defs.h ext.h $(ARPA_TELNET)
+sys_term.o: telnetd.h pathnames.h defs.h ext.h $(ARPA_TELNET)
+telnetd.o: telnetd.h defs.h ext.h $(ARPA_TELNET)
+termstat.o: telnetd.h defs.h ext.h $(ARPA_TELNET)
+utility.o: telnetd.h defs.h ext.h $(ARPA_TELNET)
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)telnetd.$(OBJEXT): telnetd.c telnetd.h defs.h \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/socket-utils.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/syslog.h ext.h pathnames.h $(BUILDTOP)/include/libpty.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/fake-addrinfo.h $(BUILDTOP)/include/krb5.h \
+  $(srcdir)/../libtelnet/auth.h $(srcdir)/../libtelnet/auth-proto.h \
+  $(srcdir)/../libtelnet/encrypt.h $(srcdir)/../libtelnet/enc-proto.h \
+  $(srcdir)/../libtelnet/misc-proto.h
+$(OUTPRE)termio-tn.$(OBJEXT): termio-tn.c
+$(OUTPRE)termios-tn.$(OBJEXT): termios-tn.c
+$(OUTPRE)state.$(OBJEXT): state.c telnetd.h defs.h \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/socket-utils.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/syslog.h ext.h $(srcdir)/../libtelnet/auth.h \
+  $(srcdir)/../libtelnet/auth-proto.h $(srcdir)/../libtelnet/encrypt.h \
+  $(srcdir)/../libtelnet/enc-proto.h
+$(OUTPRE)termstat.$(OBJEXT): termstat.c telnetd.h defs.h \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/socket-utils.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/syslog.h ext.h
+$(OUTPRE)slc.$(OBJEXT): slc.c telnetd.h defs.h $(srcdir)/../arpa/telnet.h \
+  $(SRCTOP)/include/socket-utils.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/syslog.h \
+  ext.h
+$(OUTPRE)sys_term.$(OBJEXT): sys_term.c telnetd.h defs.h \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/socket-utils.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/syslog.h ext.h pathnames.h $(COM_ERR_DEPS) \
+  $(BUILDTOP)/include/libpty.h $(srcdir)/../libtelnet/auth.h \
+  $(srcdir)/../libtelnet/auth-proto.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5.h \
+  $(BUILDTOP)/include/profile.h $(SRCTOP)/include/krb5/kdb.h
+$(OUTPRE)utility.$(OBJEXT): utility.c telnetd.h defs.h \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/socket-utils.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/syslog.h ext.h $(srcdir)/../libtelnet/auth.h \
+  $(srcdir)/../libtelnet/auth-proto.h $(srcdir)/../libtelnet/encrypt.h \
+  $(srcdir)/../libtelnet/enc-proto.h
+$(OUTPRE)global.$(OBJEXT): global.c defs.h $(srcdir)/../arpa/telnet.h \
+  $(SRCTOP)/include/socket-utils.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/syslog.h \
+  ext.h
+$(OUTPRE)authenc.$(OBJEXT): authenc.c telnetd.h defs.h \
+  $(srcdir)/../arpa/telnet.h $(SRCTOP)/include/socket-utils.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/syslog.h ext.h $(srcdir)/../libtelnet/misc.h \
+  $(srcdir)/../libtelnet/misc-proto.h
diff --git a/mechglue/src/appl/telnet/telnetd/authenc.c b/mechglue/src/appl/telnet/telnetd/authenc.c
new file mode 100644
index 000000000..6d8b04ced
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/authenc.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)authenc.c	8.1 (Berkeley) 6/4/93 */
+
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
+#include "telnetd.h"
+#include <libtelnet/misc.h>
+
+int
+net_write(str, len)
+	unsigned char *str;
+	int len;
+{
+	if (len < 0)
+		return 0;
+	return netwrite(str, (size_t) len);
+}
+
+void
+net_encrypt()
+{
+#ifdef	ENCRYPTION
+	char *s = (nclearto > nbackp) ? nclearto : nbackp;
+	if (s < nfrontp && encrypt_output) {
+		(*encrypt_output)((unsigned char *)s, nfrontp - s);
+	}
+	nclearto = nfrontp;
+#endif /* ENCRYPTION */
+}
+
+	int
+telnet_spin()
+{
+	ttloop();
+	return(0);
+}
+
+	char *
+telnet_getenv(val)
+	char *val;
+{
+	extern char *getenv();
+	return(getenv(val));
+}
+
+	char *
+telnet_gets(prompt, result, length, echo)
+	char *prompt;
+	char *result;
+	int length;
+	int echo;
+{
+	return((char *)0);
+}
+#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
diff --git a/mechglue/src/appl/telnet/telnetd/defs.h b/mechglue/src/appl/telnet/telnetd/defs.h
new file mode 100644
index 000000000..3ceb8653d
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/defs.h
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)defs.h	8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Telnet server defines
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifndef	BSD
+# define	BSD 43
+#endif
+
+#if	defined(CRAY) && !defined(LINEMODE)
+# define SYSV_TERMIO
+# define LINEMODE
+# define KLUDGELINEMODE
+# define DIAGNOSTICS
+# if defined(UNICOS50) && !defined(UNICOS5)
+#  define UNICOS5
+# endif
+# if !defined(UNICOS5)
+#  define BFTPDAEMON
+#  define HAS_IP_TOS
+# endif
+#endif /* CRAY */
+#if defined(UNICOS5) && !defined(NO_SETSID)
+# define NO_SETSID
+#endif
+
+#if defined(PRINTOPTIONS) && defined(DIAGNOSTICS)
+#define TELOPTS
+#define TELCMDS
+#define	SLC_NAMES
+#endif
+
+#if	defined(SYSV_TERMIO) && !defined(USE_TERMIO)
+# define	USE_TERMIO
+#endif
+
+#include <sys/socket.h>
+#ifndef	CRAY
+#include <sys/wait.h>
+#endif	/* CRAY */
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#ifndef	HAVE_SYS_FILIO_H
+#include <sys/ioctl.h>
+#else
+#include <sys/filio.h>
+#endif
+
+#include <netinet/in.h>
+
+#include <arpa/telnet.h>
+
+/* for socklen() */
+#include "socket-utils.h"
+
+#include <stdio.h>
+#ifdef	__STDC__
+#include <stdlib.h>
+#endif
+#include <signal.h>
+#include <errno.h>
+#include <netdb.h>
+#include <syslog.h>
+#ifndef	LOG_DAEMON
+#define	LOG_DAEMON	0
+#endif
+#ifndef	LOG_ODELAY
+#define	LOG_ODELAY	0
+#endif
+#include <ctype.h>
+#ifndef HAVE_STRING_H
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+
+#ifndef	USE_TERMIO
+#include <sgtty.h>
+#else
+# ifdef	SYSV_TERMIO
+# include <termio.h>
+# else
+# include <termios.h>
+# endif
+#endif
+#if !defined(USE_TERMIO) || defined(NO_CC_T)
+typedef unsigned char cc_t;
+#endif
+
+#ifdef	__STDC__
+#include <unistd.h>
+#endif
+
+#ifndef _POSIX_VDISABLE
+# ifdef VDISABLE
+#  define _POSIX_VDISABLE VDISABLE
+# else
+#  define _POSIX_VDISABLE ((unsigned char)'\377')
+# endif
+#endif
+
+
+#ifdef	CRAY
+# ifdef	CRAY1
+# include <sys/pty.h>
+#  ifndef FD_ZERO
+# include <sys/select.h>
+#  endif /* FD_ZERO */
+# endif	/* CRAY1 */
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#endif	/* CRAY */
+
+#ifdef __hpux
+#include <sys/ptyio.h>
+#endif
+
+#if defined(__alpha) && defined(STREAMSPTY)
+#undef STREAMSPTY
+#endif
+
+#if	!defined(TIOCSCTTY) && defined(TCSETCTTY)
+# define	TIOCSCTTY TCSETCTTY
+#endif
+
+#ifndef	FD_SET
+#ifndef	HAVE_fd_set
+typedef struct fd_set { int fds_bits[1]; } fd_set;
+#endif
+
+#define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
+#define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
+#define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
+#define FD_ZERO(p)	((p)->fds_bits[0] = 0)
+#endif	/* FD_SET */
+
+/*
+ * I/O data buffers defines
+ */
+#define	NETSLOP	64
+#ifdef CRAY
+#undef BUFSIZ
+#define BUFSIZ  2048
+#endif
+
+#define	NIACCUM(c)	{   *netip++ = c; \
+			    ncc++; \
+			}
+
+/* clock manipulations */
+#define	settimer(x)	(clocks.x = ++clocks.system)
+#define	sequenceIs(x,y)	(clocks.x < clocks.y)
+
+/*
+ * Linemode support states, in decreasing order of importance
+ */
+#define REAL_LINEMODE	0x04
+#define KLUDGE_OK	0x03
+#define	NO_AUTOKLUDGE	0x02
+#define KLUDGE_LINEMODE	0x01
+#define NO_LINEMODE	0x00
+
+/*
+ * Structures of information for each special character function.
+ */
+typedef struct {
+	unsigned char	flag;		/* the flags for this function */
+	cc_t		val;		/* the value of the special character */
+} slcent, *Slcent;
+
+typedef struct {
+	slcent		defset;		/* the default settings */
+	slcent		current;	/* the current settings */
+	cc_t		*sptr;		/* a pointer to the char in */
+					/* system data structures */
+} slcfun, *Slcfun;
+
+#ifdef DIAGNOSTICS
+/*
+ * Diagnostics capabilities
+ */
+#define	TD_REPORT	0x01	/* Report operations to client */
+#define TD_EXERCISE	0x02	/* Exercise client's implementation */
+#define TD_NETDATA	0x04	/* Display received data stream */
+#define TD_PTYDATA	0x08	/* Display data passed to pty */
+#define	TD_OPTIONS	0x10	/* Report just telnet options */
+#endif /* DIAGNOSTICS */
+
+/*
+ * We keep track of each side of the option negotiation.
+ */
+
+#define	MY_STATE_WILL		0x01
+#define	MY_WANT_STATE_WILL	0x02
+#define	MY_STATE_DO		0x04
+#define	MY_WANT_STATE_DO	0x08
+
+/*
+ * Macros to check the current state of things
+ */
+
+#define	my_state_is_do(opt)		(options[opt]&MY_STATE_DO)
+#define	my_state_is_will(opt)		(options[opt]&MY_STATE_WILL)
+#define my_want_state_is_do(opt)	(options[opt]&MY_WANT_STATE_DO)
+#define my_want_state_is_will(opt)	(options[opt]&MY_WANT_STATE_WILL)
+
+#define	my_state_is_dont(opt)		(!my_state_is_do(opt))
+#define	my_state_is_wont(opt)		(!my_state_is_will(opt))
+#define my_want_state_is_dont(opt)	(!my_want_state_is_do(opt))
+#define my_want_state_is_wont(opt)	(!my_want_state_is_will(opt))
+
+#define	set_my_state_do(opt)		(options[opt] |= MY_STATE_DO)
+#define	set_my_state_will(opt)		(options[opt] |= MY_STATE_WILL)
+#define	set_my_want_state_do(opt)	(options[opt] |= MY_WANT_STATE_DO)
+#define	set_my_want_state_will(opt)	(options[opt] |= MY_WANT_STATE_WILL)
+
+#define	set_my_state_dont(opt)		(options[opt] &= ~MY_STATE_DO)
+#define	set_my_state_wont(opt)		(options[opt] &= ~MY_STATE_WILL)
+#define	set_my_want_state_dont(opt)	(options[opt] &= ~MY_WANT_STATE_DO)
+#define	set_my_want_state_wont(opt)	(options[opt] &= ~MY_WANT_STATE_WILL)
+
+/*
+ * Tricky code here.  What we want to know is if the MY_STATE_WILL
+ * and MY_WANT_STATE_WILL bits have the same value.  Since the two
+ * bits are adjacent, a little arithmatic will show that by adding
+ * in the lower bit, the upper bit will be set if the two bits were
+ * different, and clear if they were the same.
+ */
+#define my_will_wont_is_changing(opt) \
+			((options[opt]+MY_STATE_WILL) & MY_WANT_STATE_WILL)
+
+#define my_do_dont_is_changing(opt) \
+			((options[opt]+MY_STATE_DO) & MY_WANT_STATE_DO)
+
+/*
+ * Make everything symetrical
+ */
+
+#define	HIS_STATE_WILL			MY_STATE_DO
+#define	HIS_WANT_STATE_WILL		MY_WANT_STATE_DO
+#define HIS_STATE_DO			MY_STATE_WILL
+#define HIS_WANT_STATE_DO		MY_WANT_STATE_WILL
+
+#define	his_state_is_do			my_state_is_will
+#define	his_state_is_will		my_state_is_do
+#define his_want_state_is_do		my_want_state_is_will
+#define his_want_state_is_will		my_want_state_is_do
+
+#define	his_state_is_dont		my_state_is_wont
+#define	his_state_is_wont		my_state_is_dont
+#define his_want_state_is_dont		my_want_state_is_wont
+#define his_want_state_is_wont		my_want_state_is_dont
+
+#define	set_his_state_do		set_my_state_will
+#define	set_his_state_will		set_my_state_do
+#define	set_his_want_state_do		set_my_want_state_will
+#define	set_his_want_state_will		set_my_want_state_do
+
+#define	set_his_state_dont		set_my_state_wont
+#define	set_his_state_wont		set_my_state_dont
+#define	set_his_want_state_dont		set_my_want_state_wont
+#define	set_his_want_state_wont		set_my_want_state_dont
+
+#define his_will_wont_is_changing	my_do_dont_is_changing
+#define his_do_dont_is_changing		my_will_wont_is_changing
+
+extern char	*line;
+
+#ifdef	ENCRYPTION
+extern void	(*encrypt_output) (unsigned char *, int);
+extern int	(*decrypt_input) (int);
+#endif	/* ENCRYPTION */
diff --git a/mechglue/src/appl/telnet/telnetd/ext.h b/mechglue/src/appl/telnet/telnetd/ext.h
new file mode 100644
index 000000000..7b77a44b0
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/ext.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ext.h	8.1 (Berkeley) 6/4/93
+ */
+
+/*
+ * Telnet server variable declarations
+ */
+extern char	options[256];
+extern char	do_dont_resp[256];
+extern char	will_wont_resp[256];
+extern int	linemode;	/* linemode on/off */
+#ifdef	LINEMODE
+extern int	uselinemode;	/* what linemode to use (on/off) */
+extern int	editmode;	/* edit modes in use */
+extern int	useeditmode;	/* edit modes to use */
+extern int	alwayslinemode;	/* command line option */
+# ifdef	KLUDGELINEMODE
+extern int	lmodetype;	/* Client support for linemode */
+# endif	/* KLUDGELINEMODE */
+#endif	/* LINEMODE */
+extern int	flowmode;	/* current flow control state */
+extern int	restartany;	/* restart output on any character state */
+#ifdef DIAGNOSTICS
+extern int	diagnostic;	/* telnet diagnostic capabilities */
+#endif /* DIAGNOSTICS */
+#ifdef BFTPDAEMON
+extern int	bftpd;		/* behave as bftp daemon */
+#endif /* BFTPDAEMON */
+#if	defined(SecurID)
+extern int	require_SecurID;
+#endif
+#if	defined(AUTHENTICATION)
+extern int	auth_level;
+#endif
+extern int auth_negotiated; /* Have we finished all authentication negotiation we plan to finish?*/
+extern slcfun	slctab[NSLC + 1];	/* slc mapping table */
+
+extern char	terminaltype[41];
+
+/*
+ * I/O data buffers, pointers, and counters.
+ */
+extern char	ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;
+
+extern char	netibuf[BUFSIZ], *netip;
+
+extern char	netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp;
+extern char	*neturg;		/* one past last bye of urgent data */
+
+extern int	pcc, ncc;
+
+#if defined(CRAY2) && defined(UNICOS5)
+extern int unpcc;  /* characters left unprocessed by CRAY-2 terminal routine */
+extern char *unptyip;  /* pointer to remaining characters in buffer */
+#endif
+
+extern int	pty, net;
+extern int	SYNCHing;		/* we are in TELNET SYNCH mode */
+
+#ifdef ENCRYPTION
+extern int	must_encrypt;
+#endif
+
+extern void
+	_termstat (void),
+	add_slc (int, int, int),
+	check_slc (void),
+	change_slc (int, int, int),
+	cleanup (int),
+	clientstat (int, int, int),
+	copy_termbuf (char *, int),
+	deferslc (void),
+	defer_terminit (void),
+	do_opt_slc (unsigned char *, int),
+	doeof (void),
+	dooption (int),
+	dontoption (int),
+	edithost (char *, char *),
+	fatal (int, const char *),
+	fatalperror (int, const char *),
+	get_slc_defaults (void),
+	init_env (void),
+	init_termbuf (void),
+	interrupt (void),
+	localstat (void),
+	flowstat (void),
+	netclear (void),
+	netflush (void),
+#ifdef DIAGNOSTICS
+	printoption (char *, int),
+	printdata (char *, char *, int),
+	printsub (int, unsigned char *, int),
+#endif
+	ptyflush (void),
+	putchr (int),
+	putf (char *, char *),
+	recv_ayt (void),
+	send_do (int, int),
+	send_dont (int, int),
+	send_slc (void),
+	send_status (void),
+	send_will (int, int),
+	send_wont (int, int),
+	sendbrk (void),
+	sendsusp (void),
+	set_termbuf (void),
+	start_login (char *, int, char *),
+	start_slc (int),
+	startslave (char *, int, char *),
+	suboption (void),
+	telrcv (void),
+	ttloop (void),
+	tty_binaryin (int),
+	tty_binaryout (int);
+
+extern int
+	end_slc (unsigned char **),
+	getnpty (void),
+#ifndef convex
+	getpty (int *),
+#endif
+	login_tty (int),
+	spcset (int, cc_t *, cc_t **),
+	stilloob (int),
+	terminit (void),
+	termstat (void),
+	tty_flowmode (void),
+	tty_restartany (void),
+	tty_isbinaryin (void),
+	tty_isbinaryout (void),
+	tty_iscrnl (void),
+	tty_isecho (void),
+	tty_isediting (void),
+	tty_islitecho (void),
+	tty_isnewmap (void),
+	tty_israw (void),
+	tty_issofttab (void),
+	tty_istrapsig (void),
+	tty_linemode (void);
+
+extern void
+	tty_rspeed (int),
+	tty_setecho (int),
+	tty_setedit (int),
+	tty_setlinemode (int),
+	tty_setlitecho (int),
+	tty_setsig (int),
+	tty_setsofttab (int),
+	tty_tspeed (int),
+	willoption (int),
+	wontoption (int);
+
+extern void netprintf (const char *, ...);
+extern void netprintf_urg (const char *fmt, ...);
+extern void netprintf_noflush (const char *fmt, ...);
+extern int netwrite (const unsigned char *, size_t);
+extern void netputs (const char *);
+
+#ifdef	ENCRYPTION
+extern char	*nclearto;
+#endif	/* ENCRYPTION */
+
+
+/*
+ * The following are some clocks used to decide how to interpret
+ * the relationship between various variables.
+ */
+
+extern struct {
+    int
+	system,			/* what the current time is */
+	echotoggle,		/* last time user entered echo character */
+	modenegotiated,		/* last time operating mode negotiated */
+	didnetreceive,		/* last time we read data from network */
+	ttypesubopt,		/* ttype subopt is received */
+	tspeedsubopt,		/* tspeed subopt is received */
+	environsubopt,		/* environ subopt is received */
+	oenvironsubopt,		/* old environ subopt is received */
+	xdisplocsubopt,		/* xdisploc subopt is received */
+	baseline,		/* time started to do timed action */
+	gotDM;			/* when did we last see a data mark */
+} clocks;
+
+
+#if	defined(CRAY2) && defined(UNICOS5)
+extern int	needtermstat;
+#endif
+
+#ifdef NEED_UNSETENV_PROTO
+extern void unsetenv(const char *);
+#endif
+#ifdef NEED_SETENV_PROTO
+extern void setenv(const char *, const char *, int);
+#endif
diff --git a/mechglue/src/appl/telnet/telnetd/global.c b/mechglue/src/appl/telnet/telnetd/global.c
new file mode 100644
index 000000000..c1412834e
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/global.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)global.c	8.1 (Berkeley) 6/4/93 */
+
+/*
+ * Allocate global variables.  We do this
+ * by including the header file that defines
+ * them all as externs, but first we define
+ * the keyword "extern" to be nothing, so that
+ * we will actually allocate the space.
+ */
+
+#include "defs.h"
+#define extern
+#include "ext.h"
diff --git a/mechglue/src/appl/telnet/telnetd/pathnames.h b/mechglue/src/appl/telnet/telnetd/pathnames.h
new file mode 100644
index 000000000..c8b0806e7
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/pathnames.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pathnames.h	8.1 (Berkeley) 6/4/93
+ */
+
+#if BSD > 43
+
+# include <paths.h>
+
+# ifndef _PATH_LOGIN
+#  define	_PATH_LOGIN	"/usr/bin/login"
+# endif
+
+#else
+ 
+# define	_PATH_TTY	"/dev/tty"
+# ifndef _PATH_LOGIN
+#  define	_PATH_LOGIN	"/bin/login"
+# endif
+
+#endif
+
+#ifdef BFTPDAEMON
+#define		BFTPPATH	"/usr/ucb/bftp"
+#endif  /* BFTPDAEMON */
diff --git a/mechglue/src/appl/telnet/telnetd/slc.c b/mechglue/src/appl/telnet/telnetd/slc.c
new file mode 100644
index 000000000..613674b01
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/slc.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)slc.c	8.1 (Berkeley) 6/4/93 */
+
+#include "telnetd.h"
+
+#ifdef	LINEMODE
+/*
+ * local varibles
+ */
+static unsigned char	*def_slcbuf = (unsigned char *)0;
+static int		def_slclen = 0;
+static int		slcchange;	/* change to slc is requested */
+static unsigned char	*slcptr;	/* pointer into slc buffer */
+static unsigned char	slcbuf[NSLC*6];	/* buffer for slc negotiation */
+
+/*
+ * send_slc
+ *
+ * Write out the current special characters to the client.
+ */
+	void
+send_slc()
+{
+	register int i;
+
+	/*
+	 * Send out list of triplets of special characters
+	 * to client.  We only send info on the characters
+	 * that are currently supported.
+	 */
+	for (i = 1; i <= NSLC; i++) {
+		if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT)
+			continue;
+		add_slc((unsigned char)i, slctab[i].current.flag,
+							slctab[i].current.val);
+	}
+
+}  /* end of send_slc */
+
+/*
+ * default_slc
+ *
+ * Set pty special characters to all the defaults.
+ */
+	void
+default_slc()
+{
+	register int i;
+
+	for (i = 1; i <= NSLC; i++) {
+		slctab[i].current.val = slctab[i].defset.val;
+		if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE))
+			slctab[i].current.flag = SLC_NOSUPPORT;
+		else
+			slctab[i].current.flag = slctab[i].defset.flag;
+		if (slctab[i].sptr) {
+			*(slctab[i].sptr) = slctab[i].defset.val;
+		}
+	}
+	slcchange = 1;
+
+}  /* end of default_slc */
+#endif	/* LINEMODE */
+
+/*
+ * get_slc_defaults
+ *
+ * Initialize the slc mapping table.
+ */
+	void
+get_slc_defaults()
+{
+	register int i;
+
+	init_termbuf();
+
+	for (i = 1; i <= NSLC; i++) {
+		slctab[i].defset.flag = 
+			spcset(i, &slctab[i].defset.val, &slctab[i].sptr);
+		slctab[i].current.flag = SLC_NOSUPPORT; 
+		slctab[i].current.val = 0; 
+	}
+
+}  /* end of get_slc_defaults */
+
+#ifdef	LINEMODE
+/*
+ * add_slc
+ *
+ * Add an slc triplet to the slc buffer.
+ */
+	void
+add_slc(func, flag, val)
+	register char func, flag;
+	register cc_t val;
+{
+
+	if ((*slcptr++ = (unsigned char)func) == 0xff)
+		*slcptr++ = 0xff;
+
+	if ((*slcptr++ = (unsigned char)flag) == 0xff)
+		*slcptr++ = 0xff;
+
+	if ((*slcptr++ = (unsigned char)val) == 0xff)
+		*slcptr++ = 0xff;
+
+}  /* end of add_slc */
+
+/*
+ * start_slc
+ *
+ * Get ready to process incoming slc's and respond to them.
+ *
+ * The parameter getit is non-zero if it is necessary to grab a copy
+ * of the terminal control structures.
+ */
+	void
+start_slc(getit)
+	register int getit;
+{
+
+	slcchange = 0;
+	if (getit)
+		init_termbuf();
+	(void) sprintf((char *)slcbuf, "%c%c%c%c",
+					IAC, SB, TELOPT_LINEMODE, LM_SLC);
+	slcptr = slcbuf + 4;
+
+}  /* end of start_slc */
+
+/*
+ * end_slc
+ *
+ * Finish up the slc negotiation.  If something to send, then send it.
+ */
+	int
+end_slc(bufp)
+	register unsigned char **bufp;
+{
+	register int len;
+	void netflush();
+
+	/*
+	 * If a change has occured, store the new terminal control
+	 * structures back to the terminal driver.
+	 */
+	if (slcchange) {
+		set_termbuf();
+	}
+
+	/*
+	 * If the pty state has not yet been fully processed and there is a
+	 * deferred slc request from the client, then do not send any
+	 * sort of slc negotiation now.  We will respond to the client's
+	 * request very soon.
+	 */
+	if (def_slcbuf && (terminit() == 0)) {
+		return(0);
+	}
+
+	if (slcptr > (slcbuf + 4)) {
+		if (bufp) {
+			*bufp = &slcbuf[4];
+			return(slcptr - slcbuf - 4);
+		} else {
+			(void) sprintf((char *)slcptr, "%c%c", IAC, SE);
+			slcptr += 2;
+			len = slcptr - slcbuf;
+			netwrite(slcbuf, len);
+			netflush();  /* force it out immediately */
+			DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2););
+		}
+	}
+	return (0);
+
+}  /* end of end_slc */
+
+/*
+ * process_slc
+ *
+ * Figure out what to do about the client's slc
+ */
+	void
+process_slc(func, flag, val)
+	register unsigned char func, flag;
+	register cc_t val;
+{
+	register int hislevel, mylevel, ack;
+
+	/*
+	 * Ensure that we know something about this function
+	 */
+	if (func > NSLC) {
+		add_slc(func, SLC_NOSUPPORT, 0);
+		return;
+	}
+
+	/*
+	 * Process the special case requests of 0 SLC_DEFAULT 0
+	 * and 0 SLC_VARIABLE 0.  Be a little forgiving here, don't
+	 * worry about whether the value is actually 0 or not.
+	 */
+	if (func == 0) {
+		if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) {
+			default_slc();
+			send_slc();
+		} else if (flag == SLC_VARIABLE) {
+			send_slc();
+		}
+		return;
+	}
+
+	/*
+	 * Appears to be a function that we know something about.  So
+	 * get on with it and see what we know.
+	 */
+
+	hislevel = flag & SLC_LEVELBITS;
+	mylevel = slctab[func].current.flag & SLC_LEVELBITS;
+	ack = flag & SLC_ACK;
+	/*
+	 * ignore the command if:
+	 * the function value and level are the same as what we already have;
+	 * or the level is the same and the ack bit is set
+	 */
+	if (hislevel == mylevel && (val == slctab[func].current.val || ack)) {
+		return;
+	} else if (ack) {
+		/*
+		 * If we get here, we got an ack, but the levels don't match.
+		 * This shouldn't happen.  If it does, it is probably because
+		 * we have sent two requests to set a variable without getting
+		 * a response between them, and this is the first response.
+		 * So, ignore it, and wait for the next response.
+		 */
+		return;
+	} else {
+		change_slc(func, flag, val);
+	}
+
+}  /* end of process_slc */
+
+/*
+ * change_slc
+ *
+ * Process a request to change one of our special characters.
+ * Compare client's request with what we are capable of supporting.
+ */
+	void
+change_slc(func, flag, val)
+	register char func, flag;
+	register cc_t val;
+{
+	register int hislevel, mylevel;
+	
+	hislevel = flag & SLC_LEVELBITS;
+	mylevel = slctab[func].defset.flag & SLC_LEVELBITS;
+	/*
+	 * If client is setting a function to NOSUPPORT
+	 * or DEFAULT, then we can easily and directly
+	 * accomodate the request.
+	 */
+	if (hislevel == SLC_NOSUPPORT) {
+		slctab[func].current.flag = flag;
+		slctab[func].current.val = (cc_t)_POSIX_VDISABLE;
+		flag |= SLC_ACK;
+		add_slc(func, flag, val);
+		return;
+	}
+	if (hislevel == SLC_DEFAULT) {
+		/*
+		 * Special case here.  If client tells us to use
+		 * the default on a function we don't support, then
+		 * return NOSUPPORT instead of what we may have as a
+		 * default level of DEFAULT.
+		 */
+		if (mylevel == SLC_DEFAULT) {
+			slctab[func].current.flag = SLC_NOSUPPORT;
+		} else {
+			slctab[func].current.flag = slctab[func].defset.flag;
+		}
+		slctab[func].current.val = slctab[func].defset.val;
+		add_slc(func, slctab[func].current.flag,
+						slctab[func].current.val);
+		return;
+	}
+
+	/*
+	 * Client wants us to change to a new value or he
+	 * is telling us that he can't change to our value.
+	 * Some of the slc's we support and can change,
+	 * some we do support but can't change,
+	 * and others we don't support at all.
+	 * If we can change it then we have a pointer to
+	 * the place to put the new value, so change it,
+	 * otherwise, continue the negotiation.
+	 */
+	if (slctab[func].sptr) {
+		/*
+		 * We can change this one.
+		 */
+		slctab[func].current.val = val;
+		*(slctab[func].sptr) = val;
+		slctab[func].current.flag = flag;
+		flag |= SLC_ACK;
+		slcchange = 1;
+		add_slc(func, flag, val);
+	} else {
+		/*
+		* It is not possible for us to support this
+		* request as he asks.
+		*
+		* If our level is DEFAULT, then just ack whatever was
+		* sent. 
+		*
+		* If he can't change and we can't change,
+		* then degenerate to NOSUPPORT.
+		*
+		* Otherwise we send our level back to him, (CANTCHANGE
+		* or NOSUPPORT) and if CANTCHANGE, send
+		* our value as well.
+		*/
+		if (mylevel == SLC_DEFAULT) {
+			slctab[func].current.flag = flag;
+			slctab[func].current.val = val;
+			flag |= SLC_ACK;
+		} else if (hislevel == SLC_CANTCHANGE &&
+				    mylevel == SLC_CANTCHANGE) {
+			flag &= ~SLC_LEVELBITS;
+			flag |= SLC_NOSUPPORT;
+			slctab[func].current.flag = flag;
+		} else {
+			flag &= ~SLC_LEVELBITS;
+			flag |= mylevel;
+			slctab[func].current.flag = flag;
+			if (mylevel == SLC_CANTCHANGE) {
+				slctab[func].current.val =
+					slctab[func].defset.val;
+				val = slctab[func].current.val;
+			}
+			
+		}
+		add_slc(func, flag, val);
+	}
+
+}  /* end of change_slc */
+
+#if	defined(USE_TERMIO) && (VEOF == VMIN)
+cc_t oldeofc = '\004';
+#endif
+
+/*
+ * check_slc
+ *
+ * Check the special characters in use and notify the client if any have
+ * changed.  Only those characters that are capable of being changed are
+ * likely to have changed.  If a local change occurs, kick the support level
+ * and flags up to the defaults.
+ */
+	void
+check_slc()
+{
+	register int i;
+
+	for (i = 1; i <= NSLC; i++) {
+#if	defined(USE_TERMIO) && (VEOF == VMIN)
+		/*
+		 * In a perfect world this would be a neat little
+		 * function.  But in this world, we should not notify
+		 * client of changes to the VEOF char when
+		 * ICANON is off, because it is not representing
+		 * a special character.
+		 */
+		if (i == SLC_EOF) {
+			if (!tty_isediting())
+				continue;
+			else if (slctab[i].sptr)
+				oldeofc = *(slctab[i].sptr);
+		}
+#endif	/* defined(USE_TERMIO) && defined(SYSV_TERMIO) */
+		if (slctab[i].sptr &&
+				(*(slctab[i].sptr) != slctab[i].current.val)) {
+			slctab[i].current.val = *(slctab[i].sptr);
+			if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE)
+				slctab[i].current.flag = SLC_NOSUPPORT;
+			else
+				slctab[i].current.flag = slctab[i].defset.flag;
+			add_slc((unsigned char)i, slctab[i].current.flag,
+						slctab[i].current.val);
+		}
+	}
+			
+}  /* check_slc */
+
+/*
+ * do_opt_slc
+ *
+ * Process an slc option buffer.  Defer processing of incoming slc's
+ * until after the terminal state has been processed.  Save the first slc
+ * request that comes along, but discard all others.
+ *
+ * ptr points to the beginning of the buffer, len is the length.
+ */
+	void
+do_opt_slc(ptr, len)
+	register unsigned char *ptr;
+	register int len;
+{
+	register unsigned char func, flag;
+	cc_t val;
+	register unsigned char *end = ptr + len;
+
+	if (terminit()) {  /* go ahead */
+		while (ptr < end) {
+			func = *ptr++;
+			if (ptr >= end) break;
+			flag = *ptr++;
+			if (ptr >= end) break;
+			val = (cc_t)*ptr++;
+
+			process_slc(func, flag, val);
+
+		}
+	} else {
+		/*
+		 * save this slc buffer if it is the first, otherwise dump
+		 * it.
+		 */
+		if (def_slcbuf == (unsigned char *)0) {
+			def_slclen = len;
+			def_slcbuf = (unsigned char *)malloc((unsigned)len);
+			if (def_slcbuf == (unsigned char *)0)
+				return;  /* too bad */
+			memcpy(def_slcbuf, ptr, len);
+		}
+	}
+
+}  /* end of do_opt_slc */
+
+/*
+ * deferslc
+ *
+ * Do slc stuff that was deferred.
+ */
+	void
+deferslc()
+{
+	if (def_slcbuf) {
+		start_slc(1);
+		do_opt_slc(def_slcbuf, def_slclen);
+		(void) end_slc(0);
+		free(def_slcbuf);
+		def_slcbuf = (unsigned char *)0;
+		def_slclen = 0;
+	}
+
+}  /* end of deferslc */
+
+#endif	/* LINEMODE */
diff --git a/mechglue/src/appl/telnet/telnetd/state.c b/mechglue/src/appl/telnet/telnetd/state.c
new file mode 100644
index 000000000..b01842f00
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/state.c
@@ -0,0 +1,1675 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)state.c	8.1 (Berkeley) 6/4/93 */
+
+#include "telnetd.h"
+#if	defined(AUTHENTICATION)
+#include <libtelnet/auth.h>
+#endif
+#if defined(ENCRYPTION)
+#include <libtelnet/encrypt.h>
+#endif
+
+unsigned char	doopt[] = { IAC, DO, '%', 'c', 0 };
+unsigned char	dont[] = { IAC, DONT, '%', 'c', 0 };
+unsigned char	will[] = { IAC, WILL, '%', 'c', 0 };
+unsigned char	wont[] = { IAC, WONT, '%', 'c', 0 };
+int	not42 = 1;
+
+static int envvarok (char *);
+
+/*
+ * Buffer for sub-options, and macros
+ * for suboptions buffer manipulations
+ */
+unsigned char subbuffer[4096], *subpointer= subbuffer, *subend= subbuffer;
+
+#define	SB_CLEAR()	subpointer = subbuffer
+#define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
+#define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
+				*subpointer++ = (c); \
+			}
+#define	SB_GET()	((*subpointer++)&0xff)
+#define	SB_EOF()	(subpointer >= subend)
+#define	SB_LEN()	(subend - subpointer)
+
+#ifdef	ENV_HACK
+unsigned char *subsave;
+#define SB_SAVE()	subsave = subpointer;
+#define	SB_RESTORE()	subpointer = subsave;
+#endif
+
+
+/*
+ * State for recv fsm
+ */
+#define	TS_DATA		0	/* base state */
+#define	TS_IAC		1	/* look for double IAC's */
+#define	TS_CR		2	/* CR-LF ->'s CR */
+#define	TS_SB		3	/* throw away begin's... */
+#define	TS_SE		4	/* ...end's (suboption negotiation) */
+#define	TS_WILL		5	/* will option negotiation */
+#define	TS_WONT		6	/* wont " */
+#define	TS_DO		7	/* do " */
+#define	TS_DONT		8	/* dont " */
+
+static void sb_auth_complete()
+{
+  if (!auth_negotiated) {
+    static char *error =
+      "An environment option was sent before authentication negotiation completed.\r\nThis may create a security hazard. Connection dropped.\r\n";
+    netputs(error);
+    netflush();
+    exit(1);
+  }
+}
+
+	void
+telrcv()
+{
+	register int c;
+	static int state = TS_DATA;
+#if	defined(CRAY2) && defined(UNICOS5)
+	char *opfrontp = pfrontp;
+#endif
+
+	while (ncc > 0) {
+		if ((&ptyobuf[BUFSIZ] - pfrontp) < 1)
+			break;
+		c = *netip++ & 0377, ncc--;
+#ifdef	ENCRYPTION
+		if (decrypt_input)
+			c = (*decrypt_input)(c);
+#endif	/* ENCRYPTION */
+		switch (state) {
+
+		case TS_CR:
+			state = TS_DATA;
+			/* Strip off \n or \0 after a \r */
+			if ((c == 0) || (c == '\n')) {
+				break;
+			}
+			/* FALL THROUGH */
+
+		case TS_DATA:
+			if (c == IAC) {
+				state = TS_IAC;
+				break;
+			}
+			/*
+			 * We now map \r\n ==> \r for pragmatic reasons.
+			 * Many client implementations send \r\n when
+			 * the user hits the CarriageReturn key.
+			 *
+			 * We USED to map \r\n ==> \n, since \r\n says
+			 * that we want to be in column 1 of the next
+			 * printable line, and \n is the standard
+			 * unix way of saying that (\r is only good
+			 * if CRMOD is set, which it normally is).
+			 */
+			if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
+				int nc = *netip;
+#ifdef	ENCRYPTION
+				if (decrypt_input)
+					nc = (*decrypt_input)(nc & 0xff);
+#endif	/* ENCRYPTION */
+#ifdef	LINEMODE
+				/*
+				 * If we are operating in linemode,
+				 * convert to local end-of-line.
+				 */
+				if (linemode && (ncc > 0) && (('\n' == nc) ||
+					 ((0 == nc) && tty_iscrnl())) ) {
+					netip++; ncc--;
+					c = '\n';
+				} else
+#endif
+				{
+#ifdef	ENCRYPTION
+					if (decrypt_input)
+						(void)(*decrypt_input)(-1);
+#endif	/* ENCRYPTION */
+					state = TS_CR;
+				}
+			}
+			*pfrontp++ = c;
+			break;
+
+		case TS_IAC:
+gotiac:			switch (c) {
+
+			/*
+			 * Send the process on the pty side an
+			 * interrupt.  Do this with a NULL or
+			 * interrupt char; depending on the tty mode.
+			 */
+			case IP:
+				DIAG(TD_OPTIONS,
+					printoption("td: recv IAC", c));
+				interrupt();
+				break;
+
+			case BREAK:
+				DIAG(TD_OPTIONS,
+					printoption("td: recv IAC", c));
+				sendbrk();
+				break;
+
+			/*
+			 * Are You There?
+			 */
+			case AYT:
+				DIAG(TD_OPTIONS,
+					printoption("td: recv IAC", c));
+				recv_ayt();
+				break;
+
+			/*
+			 * Abort Output
+			 */
+			case AO:
+			    {
+				DIAG(TD_OPTIONS,
+					printoption("td: recv IAC", c));
+				ptyflush();	/* half-hearted */
+				init_termbuf();
+
+				if (slctab[SLC_AO].sptr &&
+				    *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
+				    *pfrontp++ =
+					(unsigned char)*slctab[SLC_AO].sptr;
+				}
+
+				netclear();	/* clear buffer back */
+				netprintf_urg("%c%c", IAC, DM);
+				DIAG(TD_OPTIONS,
+					printoption("td: send IAC", DM));
+				break;
+			    }
+
+			/*
+			 * Erase Character and
+			 * Erase Line
+			 */
+			case EC:
+			case EL:
+			    {
+				cc_t ch;
+
+				DIAG(TD_OPTIONS,
+					printoption("td: recv IAC", c));
+				ptyflush();	/* half-hearted */
+				init_termbuf();
+				if (c == EC)
+					ch = *slctab[SLC_EC].sptr;
+				else
+					ch = *slctab[SLC_EL].sptr;
+				if (ch != (cc_t)(_POSIX_VDISABLE))
+					*pfrontp++ = (unsigned char)ch;
+				break;
+			    }
+
+			/*
+			 * Check for urgent data...
+			 */
+			case DM:
+				DIAG(TD_OPTIONS,
+					printoption("td: recv IAC", c));
+				SYNCHing = stilloob(net);
+				settimer(gotDM);
+				break;
+
+
+			/*
+			 * Begin option subnegotiation...
+			 */
+			case SB:
+				state = TS_SB;
+				SB_CLEAR();
+				continue;
+
+			case WILL:
+				state = TS_WILL;
+				continue;
+
+			case WONT:
+				state = TS_WONT;
+				continue;
+
+			case DO:
+				state = TS_DO;
+				continue;
+
+			case DONT:
+				state = TS_DONT;
+				continue;
+			case EOR:
+				if (his_state_is_will(TELOPT_EOR))
+					doeof();
+				break;
+
+			/*
+			 * Handle RFC 10xx Telnet linemode option additions
+			 * to command stream (EOF, SUSP, ABORT).
+			 */
+			case xEOF:
+				doeof();
+				break;
+
+			case SUSP:
+				sendsusp();
+				break;
+
+			case ABORT:
+				sendbrk();
+				break;
+
+			case IAC:
+				*pfrontp++ = c;
+				break;
+			}
+			state = TS_DATA;
+			break;
+
+		case TS_SB:
+			if (c == IAC) {
+				state = TS_SE;
+			} else {
+				SB_ACCUM(c);
+			}
+			break;
+
+		case TS_SE:
+			if (c != SE) {
+				if (c != IAC) {
+					/*
+					 * bad form of suboption negotiation.
+					 * handle it in such a way as to avoid
+					 * damage to local state.  Parse
+					 * suboption buffer found so far,
+					 * then treat remaining stream as
+					 * another command sequence.
+					 */
+
+					/* for DIAGNOSTICS */
+					SB_ACCUM(IAC);
+					SB_ACCUM(c);
+					subpointer -= 2;
+
+					SB_TERM();
+					suboption();
+					state = TS_IAC;
+					goto gotiac;
+				}
+				SB_ACCUM(c);
+				state = TS_SB;
+			} else {
+				/* for DIAGNOSTICS */
+				SB_ACCUM(IAC);
+				SB_ACCUM(SE);
+				subpointer -= 2;
+
+				SB_TERM();
+				suboption();	/* handle sub-option */
+				state = TS_DATA;
+			}
+			break;
+
+		case TS_WILL:
+			willoption(c);
+			state = TS_DATA;
+			continue;
+
+		case TS_WONT:
+			wontoption(c);
+			state = TS_DATA;
+			continue;
+
+		case TS_DO:
+			dooption(c);
+			state = TS_DATA;
+			continue;
+
+		case TS_DONT:
+			dontoption(c);
+			state = TS_DATA;
+			continue;
+
+		default:
+			syslog(LOG_ERR, "telnetd: panic state=%d", state);
+			printf("telnetd: panic state=%d\n", state);
+			exit(1);
+		}
+	}
+#if	defined(CRAY2) && defined(UNICOS5)
+	if (!linemode) {
+		char	xptyobuf[BUFSIZ+NETSLOP];
+		char	xbuf2[BUFSIZ];
+		register char *cp;
+		int n = pfrontp - opfrontp, oc;
+		memcpy(xptyobuf, opfrontp, n);
+		pfrontp = opfrontp;
+		pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
+					xbuf2, &oc, BUFSIZ);
+		for (cp = xbuf2; oc > 0; --oc) {
+			if (*cp == IAC)
+				netprintf("%c%c", *cp++, IAC);
+			else
+				netprintf("%c", *cp++);
+		}
+	}
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+}  /* end of telrcv */
+
+/*
+ * The will/wont/do/dont state machines are based on Dave Borman's
+ * Telnet option processing state machine.
+ *
+ * These correspond to the following states:
+ *	my_state = the last negotiated state
+ *	want_state = what I want the state to go to
+ *	want_resp = how many requests I have sent
+ * All state defaults are negative, and resp defaults to 0.
+ *
+ * When initiating a request to change state to new_state:
+ * 
+ * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
+ *	do nothing;
+ * } else {
+ *	want_state = new_state;
+ *	send new_state;
+ *	want_resp++;
+ * }
+ *
+ * When receiving new_state:
+ *
+ * if (want_resp) {
+ *	want_resp--;
+ *	if (want_resp && (new_state == my_state))
+ *		want_resp--;
+ * }
+ * if ((want_resp == 0) && (new_state != want_state)) {
+ *	if (ok_to_switch_to new_state)
+ *		want_state = new_state;
+ *	else
+ *		want_resp++;
+ *	send want_state;
+ * }
+ * my_state = new_state;
+ *
+ * Note that new_state is implied in these functions by the function itself.
+ * will and do imply positive new_state, wont and dont imply negative.
+ *
+ * Finally, there is one catch.  If we send a negative response to a
+ * positive request, my_state will be the positive while want_state will
+ * remain negative.  my_state will revert to negative when the negative
+ * acknowlegment arrives from the peer.  Thus, my_state generally tells
+ * us not only the last negotiated state, but also tells us what the peer
+ * wants to be doing as well.  It is important to understand this difference
+ * as we may wish to be processing data streams based on our desired state
+ * (want_state) or based on what the peer thinks the state is (my_state).
+ *
+ * This all works fine because if the peer sends a positive request, the data
+ * that we receive prior to negative acknowlegment will probably be affected
+ * by the positive state, and we can process it as such (if we can; if we
+ * can't then it really doesn't matter).  If it is that important, then the
+ * peer probably should be buffering until this option state negotiation
+ * is complete.
+ *
+ */
+	void
+send_do(option, init)
+	int option, init;
+{
+	if (init) {
+		if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
+		    his_want_state_is_will(option))
+			return;
+		/*
+		 * Special case for TELOPT_TM:  We send a DO, but pretend
+		 * that we sent a DONT, so that we can send more DOs if
+		 * we want to.
+		 */
+		if (option == TELOPT_TM)
+			set_his_want_state_wont(option);
+		else
+			set_his_want_state_will(option);
+		do_dont_resp[option]++;
+	}
+	netprintf((char *)doopt, option);
+
+	DIAG(TD_OPTIONS, printoption("td: send do", option));
+}
+
+#ifdef	AUTHENTICATION
+extern void auth_request();
+#endif
+#ifdef	LINEMODE
+static void doclientstat(void);
+#endif
+#ifdef	ENCRYPTION
+extern void encrypt_send_support();
+#endif	/* ENCRYPTION */
+
+	void
+willoption(option)
+	int option;
+{
+	int changeok = 0;
+	void (*func)() = 0;
+
+	/*
+	 * process input from peer.
+	 */
+
+	DIAG(TD_OPTIONS, printoption("td: recv will", option));
+
+	if (do_dont_resp[option]) {
+		do_dont_resp[option]--;
+		if (do_dont_resp[option] && his_state_is_will(option))
+			do_dont_resp[option]--;
+	}
+	if (do_dont_resp[option] == 0) {
+	    if (his_want_state_is_wont(option)) {
+		switch (option) {
+
+		case TELOPT_BINARY:
+			init_termbuf();
+			tty_binaryin(1);
+			set_termbuf();
+			changeok++;
+			break;
+
+		case TELOPT_ECHO:
+			/*
+			 * See comments below for more info.
+			 */
+			not42 = 0;	/* looks like a 4.2 system */
+			break;
+
+		case TELOPT_TM:
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+			/*
+			 * This telnetd implementation does not really
+			 * support timing marks, it just uses them to
+			 * support the kludge linemode stuff.  If we
+			 * receive a will or wont TM in response to our
+			 * do TM request that may have been sent to
+			 * determine kludge linemode support, process
+			 * it, otherwise TM should get a negative
+			 * response back.
+			 */
+			/*
+			 * Handle the linemode kludge stuff.
+			 * If we are not currently supporting any
+			 * linemode at all, then we assume that this
+			 * is the client telling us to use kludge
+			 * linemode in response to our query.  Set the
+			 * linemode type that is to be supported, note
+			 * that the client wishes to use linemode, and
+			 * eat the will TM as though it never arrived.
+			 */
+			if (lmodetype < KLUDGE_LINEMODE) {
+				lmodetype = KLUDGE_LINEMODE;
+				clientstat(TELOPT_LINEMODE, WILL, 0);
+				send_wont(TELOPT_SGA, 1);
+			} else if (lmodetype == NO_AUTOKLUDGE) {
+				lmodetype = KLUDGE_OK;
+			}
+#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+			/*
+			 * We never respond to a WILL TM, and
+			 * we leave the state WONT.
+			 */
+			return;
+
+		case TELOPT_LFLOW:
+			/*
+			 * If we are going to support flow control
+			 * option, then don't worry peer that we can't
+			 * change the flow control characters.
+			 */
+			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
+			slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
+			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
+			slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
+		case TELOPT_TTYPE:
+		case TELOPT_SGA:
+		case TELOPT_NAWS:
+		case TELOPT_TSPEED:
+		case TELOPT_XDISPLOC:
+		case TELOPT_NEW_ENVIRON:
+		case TELOPT_OLD_ENVIRON:
+			changeok++;
+			break;
+
+#ifdef	LINEMODE
+		case TELOPT_LINEMODE:
+# ifdef	KLUDGELINEMODE
+			/*
+			 * Note client's desire to use linemode.
+			 */
+			lmodetype = REAL_LINEMODE;
+# endif	/* KLUDGELINEMODE */
+			func = doclientstat;
+			changeok++;
+			break;
+#endif	/* LINEMODE */
+
+#ifdef	AUTHENTICATION
+		case TELOPT_AUTHENTICATION:
+			func = auth_request;
+			changeok++;
+			break;
+#endif
+
+#ifdef	ENCRYPTION
+		case TELOPT_ENCRYPT:
+			func = encrypt_send_support;
+			changeok++;
+			break;
+#endif	/* ENCRYPTION */
+
+		default:
+			break;
+		}
+		if (changeok) {
+			set_his_want_state_will(option);
+			send_do(option, 0);
+		} else {
+			do_dont_resp[option]++;
+			send_dont(option, 0);
+		}
+	    } else {
+		/*
+		 * Option processing that should happen when
+		 * we receive conformation of a change in
+		 * state that we had requested.
+		 */
+		switch (option) {
+		case TELOPT_ECHO:
+			not42 = 0;	/* looks like a 4.2 system */
+			/*
+			 * Egads, he responded "WILL ECHO".  Turn
+			 * it off right now!
+			 */
+			send_dont(option, 1);
+			/*
+			 * "WILL ECHO".  Kludge upon kludge!
+			 * A 4.2 client is now echoing user input at
+			 * the tty.  This is probably undesireable and
+			 * it should be stopped.  The client will
+			 * respond WONT TM to the DO TM that we send to
+			 * check for kludge linemode.  When the WONT TM
+			 * arrives, linemode will be turned off and a
+			 * change propogated to the pty.  This change
+			 * will cause us to process the new pty state
+			 * in localstat(), which will notice that
+			 * linemode is off and send a WILL ECHO
+			 * so that we are properly in character mode and
+			 * all is well.
+			 */
+			break;
+#ifdef	LINEMODE
+		case TELOPT_LINEMODE:
+# ifdef	KLUDGELINEMODE
+			/*
+			 * Note client's desire to use linemode.
+			 */
+			lmodetype = REAL_LINEMODE;
+# endif	/* KLUDGELINEMODE */
+			func = doclientstat;
+			break;
+#endif	/* LINEMODE */
+
+#ifdef	AUTHENTICATION
+		case TELOPT_AUTHENTICATION:
+			func = auth_request;
+			break;
+#endif
+
+#ifdef	ENCRYPTION
+		case TELOPT_ENCRYPT:
+			func = encrypt_send_support;
+			break;
+#endif	/* ENCRYPTION */
+		case TELOPT_LFLOW:
+			func = flowstat;
+			break;
+		}
+	    }
+	}
+	set_his_state_will(option);
+	if (func)
+		(*func)();
+}  /* end of willoption */
+
+	void
+send_dont(option, init)
+	int option, init;
+{
+	if (init) {
+		if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
+		    his_want_state_is_wont(option))
+			return;
+		set_his_want_state_wont(option);
+		do_dont_resp[option]++;
+	}
+	netprintf((char *)dont, option);
+
+	DIAG(TD_OPTIONS, printoption("td: send dont", option));
+}
+
+	void
+wontoption(option)
+	int option;
+{
+	/*
+	 * Process client input.
+	 */
+
+	DIAG(TD_OPTIONS, printoption("td: recv wont", option));
+
+	if (do_dont_resp[option]) {
+		do_dont_resp[option]--;
+		if (do_dont_resp[option] && his_state_is_wont(option))
+			do_dont_resp[option]--;
+	}
+	if (do_dont_resp[option] == 0) {
+	    if (his_want_state_is_will(option)) {
+		/* it is always ok to change to negative state */
+		switch (option) {
+		case TELOPT_ECHO:
+			not42 = 1; /* doesn't seem to be a 4.2 system */
+			break;
+
+		case TELOPT_BINARY:
+			init_termbuf();
+			tty_binaryin(0);
+			set_termbuf();
+			break;
+
+#ifdef	LINEMODE
+		case TELOPT_LINEMODE:
+# ifdef	KLUDGELINEMODE
+			/*
+			 * If real linemode is supported, then client is
+			 * asking to turn linemode off.
+			 */
+			if (lmodetype != REAL_LINEMODE)
+				break;
+			lmodetype = KLUDGE_LINEMODE;
+# endif	/* KLUDGELINEMODE */
+			clientstat(TELOPT_LINEMODE, WONT, 0);
+			break;
+#endif	/* LINEMODE */
+
+		case TELOPT_TM:
+			/*
+			 * If we get a WONT TM, and had sent a DO TM,
+			 * don't respond with a DONT TM, just leave it
+			 * as is.  Short circut the state machine to
+			 * achive this.
+			 */
+			set_his_want_state_wont(TELOPT_TM);
+			return;
+
+		case TELOPT_LFLOW:
+			/*
+			 * If we are not going to support flow control
+			 * option, then let peer know that we can't
+			 * change the flow control characters.
+			 */
+			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
+			slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
+			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
+			slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
+			break;
+
+#if	defined(AUTHENTICATION)
+		case TELOPT_AUTHENTICATION:
+			auth_finished(0, AUTH_REJECT);
+			break;
+#endif
+
+		/*
+		 * For options that we might spin waiting for
+		 * sub-negotiation, if the client turns off the
+		 * option rather than responding to the request,
+		 * we have to treat it here as if we got a response
+		 * to the sub-negotiation, (by updating the timers)
+		 * so that we'll break out of the loop.
+		 */
+		case TELOPT_TTYPE:
+			settimer(ttypesubopt);
+			break;
+
+		case TELOPT_TSPEED:
+			settimer(tspeedsubopt);
+			break;
+
+		case TELOPT_XDISPLOC:
+			settimer(xdisplocsubopt);
+			break;
+
+		case TELOPT_OLD_ENVIRON:
+			settimer(oenvironsubopt);
+			break;
+
+		case TELOPT_NEW_ENVIRON:
+			settimer(environsubopt);
+			break;
+
+		default:
+			break;
+		}
+		set_his_want_state_wont(option);
+		if (his_state_is_will(option))
+			send_dont(option, 0);
+	    } else {
+		switch (option) {
+		case TELOPT_TM:
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+			if (lmodetype < NO_AUTOKLUDGE) {
+				lmodetype = NO_LINEMODE;
+				clientstat(TELOPT_LINEMODE, WONT, 0);
+				send_will(TELOPT_SGA, 1);
+				send_will(TELOPT_ECHO, 1);
+			}
+#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+			break;
+
+#if	defined(AUTHENTICATION)
+		case TELOPT_AUTHENTICATION:
+			auth_finished(0, AUTH_REJECT);
+			break;
+#endif
+		default:
+			break;
+		}
+	    }
+	}
+	set_his_state_wont(option);
+
+}  /* end of wontoption */
+
+	void
+send_will(option, init)
+	int option, init;
+{
+	if (init) {
+		if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
+		    my_want_state_is_will(option))
+			return;
+		set_my_want_state_will(option);
+		will_wont_resp[option]++;
+	}
+	netprintf((char *)will, option);
+
+	DIAG(TD_OPTIONS, printoption("td: send will", option));
+}
+
+#if	!defined(LINEMODE) || !defined(KLUDGELINEMODE)
+/*
+ * When we get a DONT SGA, we will try once to turn it
+ * back on.  If the other side responds DONT SGA, we
+ * leave it at that.  This is so that when we talk to
+ * clients that understand KLUDGELINEMODE but not LINEMODE,
+ * we'll keep them in char-at-a-time mode.
+ */
+int turn_on_sga = 0;
+#endif
+
+	void
+dooption(option)
+	int option;
+{
+	int changeok = 0;
+
+	/*
+	 * Process client input.
+	 */
+
+	DIAG(TD_OPTIONS, printoption("td: recv do", option));
+
+	if (will_wont_resp[option]) {
+		will_wont_resp[option]--;
+		if (will_wont_resp[option] && my_state_is_will(option))
+			will_wont_resp[option]--;
+	}
+	if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
+		switch (option) {
+		case TELOPT_ECHO:
+#ifdef	LINEMODE
+# ifdef	KLUDGELINEMODE
+			if (lmodetype == NO_LINEMODE)
+# else
+			if (his_state_is_wont(TELOPT_LINEMODE))
+# endif
+#endif
+			{
+				init_termbuf();
+				tty_setecho(1);
+				set_termbuf();
+			}
+			changeok++;
+			break;
+
+		case TELOPT_BINARY:
+			init_termbuf();
+			tty_binaryout(1);
+			set_termbuf();
+			changeok++;
+			break;
+
+		case TELOPT_SGA:
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+			/*
+			 * If kludge linemode is in use, then we must
+			 * process an incoming do SGA for linemode
+			 * purposes.
+			 */
+			if (lmodetype == KLUDGE_LINEMODE) {
+				/*
+				 * Receipt of "do SGA" in kludge
+				 * linemode is the peer asking us to
+				 * turn off linemode.  Make note of
+				 * the request.
+				 */
+				clientstat(TELOPT_LINEMODE, WONT, 0);
+				/*
+				 * If linemode did not get turned off
+				 * then don't tell peer that we did.
+				 * Breaking here forces a wont SGA to
+				 * be returned.
+				 */
+				if (linemode)
+					break;
+			}
+#else
+			turn_on_sga = 0;
+#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+			changeok++;
+			break;
+
+		case TELOPT_STATUS:
+			changeok++;
+			break;
+
+		case TELOPT_TM:
+			/*
+			 * Special case for TM.  We send a WILL, but
+			 * pretend we sent a WONT.
+			 */
+			send_will(option, 0);
+			set_my_want_state_wont(option);
+			set_my_state_wont(option);
+			return;
+
+		case TELOPT_LOGOUT:
+			/*
+			 * When we get a LOGOUT option, respond
+			 * with a WILL LOGOUT, make sure that
+			 * it gets written out to the network,
+			 * and then just go away...
+			 */
+			set_my_want_state_will(TELOPT_LOGOUT);
+			send_will(TELOPT_LOGOUT, 0);
+			set_my_state_will(TELOPT_LOGOUT);
+			(void)netflush();
+			(void)signal(SIGCHLD, SIG_DFL);
+			cleanup(0);
+			/* NOT REACHED */
+			break;
+
+#ifdef	ENCRYPTION
+		case TELOPT_ENCRYPT:
+			changeok++;
+			break;
+#endif	/* ENCRYPTION */
+		case TELOPT_LINEMODE:
+		case TELOPT_TTYPE:
+		case TELOPT_NAWS:
+		case TELOPT_TSPEED:
+		case TELOPT_LFLOW:
+		case TELOPT_XDISPLOC:
+#ifdef	TELOPT_ENVIRON
+		case TELOPT_NEW_ENVIRON:
+#endif
+		case TELOPT_OLD_ENVIRON:
+		default:
+			break;
+		}
+		if (changeok) {
+			set_my_want_state_will(option);
+			send_will(option, 0);
+		} else {
+			will_wont_resp[option]++;
+			send_wont(option, 0);
+		}
+	}
+	set_my_state_will(option);
+
+}  /* end of dooption */
+
+	void
+send_wont(option, init)
+	int option, init;
+{
+	if (init) {
+		if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
+		    my_want_state_is_wont(option))
+			return;
+		set_my_want_state_wont(option);
+		will_wont_resp[option]++;
+	}
+	netprintf((char *)wont, option);
+
+	DIAG(TD_OPTIONS, printoption("td: send wont", option));
+}
+
+	void
+dontoption(option)
+	int option;
+{
+	/*
+	 * Process client input.
+	 */
+
+
+	DIAG(TD_OPTIONS, printoption("td: recv dont", option));
+
+	if (will_wont_resp[option]) {
+		will_wont_resp[option]--;
+		if (will_wont_resp[option] && my_state_is_wont(option))
+			will_wont_resp[option]--;
+	}
+	if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
+		switch (option) {
+		case TELOPT_BINARY:
+			init_termbuf();
+			tty_binaryout(0);
+			set_termbuf();
+			break;
+
+		case TELOPT_ECHO:	/* we should stop echoing */
+#ifdef	LINEMODE
+# ifdef	KLUDGELINEMODE
+			if ((lmodetype != REAL_LINEMODE) &&
+			    (lmodetype != KLUDGE_LINEMODE))
+# else
+			if (his_state_is_wont(TELOPT_LINEMODE))
+# endif
+#endif
+			{
+				init_termbuf();
+				tty_setecho(0);
+				set_termbuf();
+			}
+			break;
+
+		case TELOPT_SGA:
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+			/*
+			 * If kludge linemode is in use, then we
+			 * must process an incoming do SGA for
+			 * linemode purposes.
+			 */
+			if ((lmodetype == KLUDGE_LINEMODE) ||
+			    (lmodetype == KLUDGE_OK)) {
+				/*
+				 * The client is asking us to turn
+				 * linemode on.
+				 */
+				lmodetype = KLUDGE_LINEMODE;
+				clientstat(TELOPT_LINEMODE, WILL, 0);
+				/*
+				 * If we did not turn line mode on,
+				 * then what do we say?  Will SGA?
+				 * This violates design of telnet.
+				 * Gross.  Very Gross.
+				 */
+			}
+			break;
+#else
+			set_my_want_state_wont(option);
+			if (my_state_is_will(option))
+				send_wont(option, 0);
+			set_my_state_wont(option);
+			if (turn_on_sga ^= 1)
+				send_will(option, 1);
+			return;
+#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+
+		default:
+			break;
+		}
+
+		set_my_want_state_wont(option);
+		if (my_state_is_will(option))
+			send_wont(option, 0);
+	}
+	set_my_state_wont(option);
+
+}  /* end of dontoption */
+
+#ifdef	ENV_HACK
+int env_ovar = -1;
+int env_ovalue = -1;
+#else	/* ENV_HACK */
+# define env_ovar OLD_ENV_VAR
+# define env_ovalue OLD_ENV_VALUE
+#endif	/* ENV_HACK */
+
+/*
+ * suboption()
+ *
+ *	Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ *
+ *	Currently we recognize:
+ *
+ *	Terminal type is
+ *	Linemode
+ *	Window size
+ *	Terminal speed
+ */
+	void
+suboption()
+{
+    register int subchar;
+
+    DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
+
+    subchar = SB_GET();
+    switch (subchar) {
+    case TELOPT_TSPEED: {
+	register int xspeed, rspeed;
+
+	if (his_state_is_wont(TELOPT_TSPEED))	/* Ignore if option disabled */
+		break;
+
+	sb_auth_complete();
+	
+	settimer(tspeedsubopt);
+
+	if (SB_EOF() || SB_GET() != TELQUAL_IS)
+		return;
+
+	xspeed = atoi((char *)subpointer);
+
+	while (SB_GET() != ',' && !SB_EOF());
+	if (SB_EOF())
+		return;
+
+	rspeed = atoi((char *)subpointer);
+	clientstat(TELOPT_TSPEED, xspeed, rspeed);
+
+	break;
+
+    }  /* end of case TELOPT_TSPEED */
+
+    case TELOPT_TTYPE: {		/* Yaaaay! */
+	char *tt;
+
+	if (his_state_is_wont(TELOPT_TTYPE))	/* Ignore if option disabled */
+		break;
+	sb_auth_complete();
+	settimer(ttypesubopt);
+
+	if (SB_EOF() || SB_GET() != TELQUAL_IS) {
+	    return;		/* ??? XXX but, this is the most robust */
+	}
+
+	tt = terminaltype;
+
+	while ((tt < (terminaltype + sizeof(terminaltype) - 1)) && !SB_EOF()) {
+	    register int c;
+
+	    c = SB_GET();
+	    if (isupper(c)) {
+		c = tolower(c);
+	    }
+	    *tt++ = c;    /* accumulate name */
+	}
+	*tt = 0;
+	break;
+    }  /* end of case TELOPT_TTYPE */
+
+    case TELOPT_NAWS: {
+	register int xwinsize, ywinsize;
+
+	if (his_state_is_wont(TELOPT_NAWS))	/* Ignore if option disabled */
+		break;
+
+	if (SB_EOF())
+		return;
+	xwinsize = SB_GET() << 8;
+	if (SB_EOF())
+		return;
+	xwinsize |= SB_GET();
+	if (SB_EOF())
+		return;
+	ywinsize = SB_GET() << 8;
+	if (SB_EOF())
+		return;
+	ywinsize |= SB_GET();
+	clientstat(TELOPT_NAWS, xwinsize, ywinsize);
+
+	break;
+
+    }  /* end of case TELOPT_NAWS */
+
+#ifdef	LINEMODE
+    case TELOPT_LINEMODE: {
+	register int request;
+
+	if (his_state_is_wont(TELOPT_LINEMODE))	/* Ignore if option disabled */
+		break;
+	/*
+	 * Process linemode suboptions.
+	 */
+	if (SB_EOF())
+	    break;		/* garbage was sent */
+	request = SB_GET();	/* get will/wont */
+
+	if (SB_EOF())
+	    break;		/* another garbage check */
+
+	if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
+		/*
+		 * Process suboption buffer of slc's
+		 */
+		start_slc(1);
+		do_opt_slc(subpointer, subend - subpointer);
+		(void) end_slc(0);
+		break;
+	} else if (request == LM_MODE) {
+		if (SB_EOF())
+		    return;
+		useeditmode = SB_GET();  /* get mode flag */
+		clientstat(LM_MODE, 0, 0);
+		break;
+	}
+
+	if (SB_EOF())
+	    break;
+	switch (SB_GET()) {  /* what suboption? */
+	case LM_FORWARDMASK:
+		/*
+		 * According to spec, only server can send request for
+		 * forwardmask, and client can only return a positive response.
+		 * So don't worry about it.
+		 */
+
+	default:
+		break;
+	}
+	break;
+    }  /* end of case TELOPT_LINEMODE */
+#endif
+    case TELOPT_STATUS: {
+	int mode;
+
+	if (SB_EOF())
+	    break;
+	mode = SB_GET();
+	switch (mode) {
+	case TELQUAL_SEND:
+	    if (my_state_is_will(TELOPT_STATUS))
+		send_status();
+	    break;
+
+	case TELQUAL_IS:
+	    break;
+
+	default:
+	    break;
+	}
+	break;
+    }  /* end of case TELOPT_STATUS */
+
+    case TELOPT_XDISPLOC: {
+	if (SB_EOF() || SB_GET() != TELQUAL_IS)
+		return;
+	sb_auth_complete();
+	settimer(xdisplocsubopt);
+	subpointer[SB_LEN()] = '\0';
+	(void)setenv("DISPLAY", (char *)subpointer, 1);
+	break;
+    }  /* end of case TELOPT_XDISPLOC */
+
+#ifdef	TELOPT_NEW_ENVIRON
+    case TELOPT_NEW_ENVIRON:
+#endif
+    case TELOPT_OLD_ENVIRON: {
+	register int c;
+	register char *cp, *varp, *valp;
+
+	if (SB_EOF())
+		return;
+	sb_auth_complete();
+	c = SB_GET();
+	if (c == TELQUAL_IS) {
+		if (subchar == TELOPT_OLD_ENVIRON)
+			settimer(oenvironsubopt);
+		else
+			settimer(environsubopt);
+	} else if (c != TELQUAL_INFO) {
+		return;
+	}
+
+#ifdef	TELOPT_NEW_ENVIRON
+	if (subchar == TELOPT_NEW_ENVIRON) {
+	    while (!SB_EOF()) {
+		c = SB_GET();
+		if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
+			break;
+	    }
+	} else
+#endif
+	{
+#ifdef	ENV_HACK
+	    /*
+	     * We only want to do this if we haven't already decided
+	     * whether or not the other side has its VALUE and VAR
+	     * reversed.
+	     */
+	    if (env_ovar < 0) {
+		register int last = -1;		/* invalid value */
+		int empty = 0;
+		int got_var = 0, got_value = 0, got_uservar = 0;
+
+		/*
+		 * The other side might have its VALUE and VAR values
+		 * reversed.  To be interoperable, we need to determine
+		 * which way it is.  If the first recognized character
+		 * is a VAR or VALUE, then that will tell us what
+		 * type of client it is.  If the fist recognized
+		 * character is a USERVAR, then we continue scanning
+		 * the suboption looking for two consecutive
+		 * VAR or VALUE fields.  We should not get two
+		 * consecutive VALUE fields, so finding two
+		 * consecutive VALUE or VAR fields will tell us
+		 * what the client is.
+		 */
+		SB_SAVE();
+		while (!SB_EOF()) {
+			c = SB_GET();
+			switch(c) {
+			case OLD_ENV_VAR:
+				if (last < 0 || last == OLD_ENV_VAR
+				    || (empty && (last == OLD_ENV_VALUE)))
+					goto env_ovar_ok;
+				got_var++;
+				last = OLD_ENV_VAR;
+				break;
+			case OLD_ENV_VALUE:
+				if (last < 0 || last == OLD_ENV_VALUE
+				    || (empty && (last == OLD_ENV_VAR)))
+					goto env_ovar_wrong;
+				got_value++;
+				last = OLD_ENV_VALUE;
+				break;
+			case ENV_USERVAR:
+				/* count strings of USERVAR as one */
+				if (last != ENV_USERVAR)
+					got_uservar++;
+				if (empty) {
+					if (last == OLD_ENV_VALUE)
+						goto env_ovar_ok;
+					if (last == OLD_ENV_VAR)
+						goto env_ovar_wrong;
+				}
+				last = ENV_USERVAR;
+				break;
+			case ENV_ESC:
+				if (!SB_EOF())
+					c = SB_GET();
+				/* FALL THROUGH */
+			default:
+				empty = 0;
+				continue;
+			}
+			empty = 1;
+		}
+		if (empty) {
+			if (last == OLD_ENV_VALUE)
+				goto env_ovar_ok;
+			if (last == OLD_ENV_VAR)
+				goto env_ovar_wrong;
+		}
+		/*
+		 * Ok, the first thing was a USERVAR, and there
+		 * are not two consecutive VAR or VALUE commands,
+		 * and none of the VAR or VALUE commands are empty.
+		 * If the client has sent us a well-formed option,
+		 * then the number of VALUEs received should always
+		 * be less than or equal to the number of VARs and
+		 * USERVARs received.
+		 *
+		 * If we got exactly as many VALUEs as VARs and
+		 * USERVARs, the client has the same definitions.
+		 *
+		 * If we got exactly as many VARs as VALUEs and
+		 * USERVARS, the client has reversed definitions.
+		 */
+		if (got_uservar + got_var == got_value) {
+	    env_ovar_ok:
+			env_ovar = OLD_ENV_VAR;
+			env_ovalue = OLD_ENV_VALUE;
+		} else if (got_uservar + got_value == got_var) {
+	    env_ovar_wrong:
+			env_ovar = OLD_ENV_VALUE;
+			env_ovalue = OLD_ENV_VAR;
+			DIAG(TD_OPTIONS,
+			     netputs("ENVIRON VALUE and VAR are reversed!\r\n"));
+		}
+	    }
+	    SB_RESTORE();
+#endif
+
+	    while (!SB_EOF()) {
+		c = SB_GET();
+		if ((c == env_ovar) || (c == ENV_USERVAR))
+			break;
+	    }
+	}
+
+	if (SB_EOF())
+		return;
+
+	cp = varp = (char *)subpointer;
+	valp = 0;
+
+	while (!SB_EOF()) {
+		c = SB_GET();
+		if (subchar == TELOPT_OLD_ENVIRON) {
+			if (c == env_ovar)
+				c = NEW_ENV_VAR;
+			else if (c == env_ovalue)
+				c = NEW_ENV_VALUE;
+		}
+		switch (c) {
+
+		case NEW_ENV_VALUE:
+			*cp = '\0';
+			cp = valp = (char *)subpointer;
+			break;
+
+		case NEW_ENV_VAR:
+		case ENV_USERVAR:
+			*cp = '\0';
+			if (envvarok(varp)) {
+				if (valp)
+					(void)setenv(varp, valp, 1);
+				else
+					unsetenv(varp);
+			}
+			cp = varp = (char *)subpointer;
+			valp = 0;
+			break;
+
+		case ENV_ESC:
+			if (SB_EOF())
+				break;
+			c = SB_GET();
+			/* FALL THROUGH */
+		default:
+			*cp++ = c;
+			break;
+		}
+	}
+	*cp = '\0';
+	if (envvarok(varp)) {
+		if (valp)
+			(void)setenv(varp, valp, 1);
+		else
+			unsetenv(varp);
+	}
+	break;
+    }  /* end of case TELOPT_NEW_ENVIRON */
+#if	defined(AUTHENTICATION)
+    case TELOPT_AUTHENTICATION:
+	if (SB_EOF())
+		break;
+	switch(SB_GET()) {
+	case TELQUAL_SEND:
+	case TELQUAL_REPLY:
+		/*
+		 * These are sent by us and cannot be sent by
+		 * the client.
+		 */
+		break;
+	case TELQUAL_IS:
+		if (!auth_negotiated)
+			auth_is(subpointer, SB_LEN());
+		break;
+	case TELQUAL_NAME:
+		if (!auth_negotiated)
+			auth_name(subpointer, SB_LEN());
+		break;
+	}
+	break;
+#endif
+#ifdef	ENCRYPTION
+    case TELOPT_ENCRYPT:
+	if (SB_EOF())
+		break;
+	switch(SB_GET()) {
+	case ENCRYPT_SUPPORT:
+		encrypt_support(subpointer, SB_LEN());
+		break;
+	case ENCRYPT_IS:
+		encrypt_is(subpointer, SB_LEN());
+		break;
+	case ENCRYPT_REPLY:
+		encrypt_reply(subpointer, SB_LEN());
+		break;
+	case ENCRYPT_START:
+		encrypt_start(subpointer, SB_LEN());
+		break;
+	case ENCRYPT_END:
+		encrypt_end();
+		break;
+	case ENCRYPT_REQSTART:
+		encrypt_request_start(subpointer, SB_LEN());
+		break;
+	case ENCRYPT_REQEND:
+		/*
+		 * We can always send an REQEND so that we cannot
+		 * get stuck encrypting.  We should only get this
+		 * if we have been able to get in the correct mode
+		 * anyhow.
+		 */
+		encrypt_request_end();
+		break;
+	case ENCRYPT_ENC_KEYID:
+		encrypt_enc_keyid(subpointer, SB_LEN());
+		break;
+	case ENCRYPT_DEC_KEYID:
+		encrypt_dec_keyid(subpointer, SB_LEN());
+		break;
+	default:
+		break;
+	}
+	break;
+#endif	/* ENCRYPTION */
+
+    default:
+	break;
+    }  /* end of switch */
+
+}  /* end of suboption */
+
+#ifdef	LINEMODE
+static	void
+doclientstat()
+{
+	clientstat(TELOPT_LINEMODE, WILL, 0);
+}
+#endif
+
+#define	ADD(c)	 *ncp++ = c;
+#define	ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
+	void
+send_status()
+{
+	unsigned char statusbuf[256];
+	register unsigned char *ncp;
+	register unsigned char i;
+
+	ncp = statusbuf;
+
+	netflush();	/* get rid of anything waiting to go out */
+
+	ADD(IAC);
+	ADD(SB);
+	ADD(TELOPT_STATUS);
+	ADD(TELQUAL_IS);
+
+	/*
+	 * We check the want_state rather than the current state,
+	 * because if we received a DO/WILL for an option that we
+	 * don't support, and the other side didn't send a DONT/WONT
+	 * in response to our WONT/DONT, then the "state" will be
+	 * WILL/DO, and the "want_state" will be WONT/DONT.  We
+	 * need to go by the latter.
+	 */
+	for (i = 0; i < (unsigned char)NTELOPTS; i++) {
+		if (my_want_state_is_will(i)) {
+			ADD(WILL);
+			ADD_DATA(i);
+			if (i == IAC)
+				ADD(IAC);
+		}
+		if (his_want_state_is_will(i)) {
+			ADD(DO);
+			ADD_DATA(i);
+			if (i == IAC)
+				ADD(IAC);
+		}
+	}
+
+	if (his_want_state_is_will(TELOPT_LFLOW)) {
+		ADD(SB);
+		ADD(TELOPT_LFLOW);
+		if (flowmode) {
+			ADD(LFLOW_ON);
+		} else {
+			ADD(LFLOW_OFF);
+		}
+		ADD(SE);
+
+		if (restartany >= 0) {
+			ADD(SB)
+			ADD(TELOPT_LFLOW);
+			if (restartany) {
+				ADD(LFLOW_RESTART_ANY);
+			} else {
+				ADD(LFLOW_RESTART_XON);
+			}
+			ADD(SE)
+			ADD(SB);
+		}
+	}
+
+#ifdef	LINEMODE
+	if (his_want_state_is_will(TELOPT_LINEMODE)) {
+		unsigned char *cp, *cpe;
+		int len;
+
+		ADD(SB);
+		ADD(TELOPT_LINEMODE);
+		ADD(LM_MODE);
+		ADD_DATA(editmode);
+		if (editmode == IAC)
+			ADD(IAC);
+		ADD(SE);
+
+		ADD(SB);
+		ADD(TELOPT_LINEMODE);
+		ADD(LM_SLC);
+		start_slc(0);
+		send_slc();
+		len = end_slc(&cp);
+		for (cpe = cp + len; cp < cpe; cp++)
+			ADD_DATA(*cp);
+		ADD(SE);
+	}
+#endif	/* LINEMODE */
+
+	ADD(IAC);
+	ADD(SE);
+
+	netwrite(statusbuf, (unsigned) (ncp - statusbuf));
+	netflush();	/* Send it on its way */
+
+	DIAG(TD_OPTIONS,
+		{printsub('>', statusbuf, ncp - statusbuf); netflush();});
+}
+
+static int envvarok(varp)
+	char *varp;
+{
+	if (!strchr(varp, '=') &&
+	    strcmp(varp, "TERMCAP") && /* to prevent a security hole  */
+	    strcmp(varp, "TERMINFO") &&	/* with tgetent */
+	    strcmp(varp, "TERMPATH") &&
+	    strcmp(varp, "HOME") && /* to prevent the tegetent bug  */
+	    strncmp(varp, "LD_", strlen("LD_")) && /* most systems */
+	    strncmp(varp, "_RLD_", strlen("_RLD_")) && /* irix */
+	    strncmp(varp, "KRB5", strlen("KRB5")) && /* v5 */
+	    /* The above is a catch-all for now.  Here are some of the
+	       specific ones we must avoid passing, at least until we
+	       can prove it can be done safely.  Keep this list around
+	       in case someone wants to remove the catch-all.  */
+	    strcmp(varp, "KRB5_CONFIG") && /* v5 */
+	    strcmp(varp, "KRB5CCNAME") &&  /* v5 */
+	    strcmp(varp, "KRB5_KTNAME") && /* v5 */
+	    strcmp(varp, "KRBTKFILE") &&   /* v4 */
+	    strcmp(varp, "KRB_CONF") &&	   /* cns v4 */
+	    strcmp(varp, "KRB_REALMS") &&  /* cns v4 */
+	    strcmp(varp, "LIBPATH") &&     /* AIX */
+	    strcmp(varp, "RESOLV_HOST_CONF") && /* linux */
+	    strcmp(varp, "NLSPATH") && /* locale stuff */
+	    strncmp(varp, "LC_", strlen("LC_")) && /* locale stuff */
+	    strcmp(varp, "IFS")) {
+		return 1;
+	} else {
+		syslog(LOG_INFO, "Rejected the attempt to modify the environment variable \"%s\"", varp);
+		return 0;
+	}
+
+}
diff --git a/mechglue/src/appl/telnet/telnetd/sys_term.c b/mechglue/src/appl/telnet/telnetd/sys_term.c
new file mode 100644
index 000000000..bfd1f81af
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/sys_term.c
@@ -0,0 +1,1475 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* baesd on @(#)sys_term.c	8.1 (Berkeley) 6/4/93 */
+
+#include "telnetd.h"
+#include "pathnames.h"
+#include <com_err.h>
+
+#ifndef LOGIN_PROGRAM
+#define LOGIN_PROGRAM _PATH_LOGIN
+#endif
+
+#include <libpty.h>
+#if	defined(AUTHENTICATION)
+#include <libtelnet/auth.h>
+#endif
+
+#if	defined(KRB5)
+#include "k5-int.h"
+#endif
+
+char *login_program = LOGIN_PROGRAM;
+
+#ifdef	NEWINIT
+#include <initreq.h>
+int	utmp_len = MAXHOSTNAMELEN;	/* sizeof(init_request.host) */
+#else	/* NEWINIT*/
+
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif
+
+#ifdef _PATH_WTMP
+char	wtmpf[] = _PATH_WTMP;
+#else
+char	wtmpf[]	= "/usr/adm/wtmp";
+#endif
+
+#ifdef _PATH_UTMP
+char 	utmpf[] = _PATH_UTMP;
+#else
+char	utmpf[] = "/etc/utmp";
+#endif
+  
+# ifdef CRAY
+#include <tmpdir.h>
+#include <sys/wait.h>
+#  if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
+   /*
+    * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
+    * use it to tell us to turn off all the socket security code,
+    * since that is only used in UNICOS 7.0 and later.
+    */
+#   undef _SC_CRAY_SECURE_SYS
+#  endif
+
+#  if defined(_SC_CRAY_SECURE_SYS)
+#include <sys/sysv.h>
+#include <sys/secstat.h>
+extern int secflag;
+extern struct sysv sysv;
+#  endif /* _SC_CRAY_SECURE_SYS */
+# endif	/* CRAY */
+#endif	/* NEWINIT */
+
+#ifdef	STREAMSPTY
+#ifdef HAVE_SAC_H
+#include <sac.h> 
+#endif
+#include <sys/stropts.h>
+#endif
+
+#define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
+#define SCMPN(a, b)	strncmp(a, b, sizeof(a))
+
+#ifdef	HAVE_SYS_STREAM_H
+#include <sys/stream.h>
+#endif
+#ifdef __hpux
+#include <sys/resource.h>
+#include <sys/proc.h>
+#endif
+	/* For what platforms do we really need sys/tty.h? */
+#ifdef HAVE_SYS_TTY_H
+#include <sys/tty.h>
+#endif
+	
+#ifdef	t_erase
+#undef	t_erase
+#undef	t_kill
+#undef	t_intrc
+#undef	t_quitc
+#undef	t_startc
+#undef	t_stopc
+#undef	t_eofc
+#undef	t_brkc
+#undef	t_suspc
+#undef	t_dsuspc
+#undef	t_rprntc
+#undef	t_flushc
+#undef	t_werasc
+#undef	t_lnextc
+#endif
+
+#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC)
+# define EXTPROC 0400
+#endif
+
+#ifndef	USE_TERMIO
+struct termbuf {
+	struct sgttyb sg;
+	struct tchars tc;
+	struct ltchars ltc;
+	int state;
+	int lflags;
+} termbuf, termbuf2;
+# define	cfsetospeed(tp, val)	(tp)->sg.sg_ospeed = (val)
+# define	cfsetispeed(tp, val)	(tp)->sg.sg_ispeed = (val)
+# define	cfgetospeed(tp)		(tp)->sg.sg_ospeed
+# define	cfgetispeed(tp)		(tp)->sg.sg_ispeed
+#else	/* USE_TERMIO */
+# ifdef	SYSV_TERMIO
+#	define termios termio
+# endif
+# ifndef	TCSANOW
+#  ifdef TCSETS
+#   define	TCSANOW		TCSETS
+#   define	TCSADRAIN	TCSETSW
+#   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
+#  else
+#   ifdef TCSETA
+#    define	TCSANOW		TCSETA
+#    define	TCSADRAIN	TCSETAW
+#    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
+#   else
+#    define	TCSANOW		TIOCSETA
+#    define	TCSADRAIN	TIOCSETAW
+#    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
+#   endif
+#  endif
+#  define	tcsetattr(f, a, t)	ioctl(f, a, t)
+#  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
+					(tp)->c_cflag |= (val)
+#  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
+#  ifdef CIBAUD
+#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
+					(tp)->c_cflag |= ((val)<<IBSHIFT)
+#   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
+#  else
+#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
+					(tp)->c_cflag |= (val)
+#   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
+#  endif
+# endif /* TCSANOW */
+struct termios termbuf, termbuf2;	/* pty control structure */
+# ifdef  STREAMSPTY
+int ttyfd = -1;
+# endif
+#endif	/* USE_TERMIO */
+
+#ifndef SETPGRP_TWOARG
+#define setpgrp(a,b) setpgrp()
+#endif
+
+int dup_tty(int);
+static char **addarg(char **, char *);
+
+/*
+ * init_termbuf()
+ * copy_termbuf(cp)
+ * set_termbuf()
+ *
+ * These three routines are used to get and set the "termbuf" structure
+ * to and from the kernel.  init_termbuf() gets the current settings.
+ * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
+ * set_termbuf() writes the structure into the kernel.
+ */
+
+	void
+init_termbuf()
+{
+#ifndef	USE_TERMIO
+	(void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
+	(void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
+	(void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
+# ifdef	TIOCGSTATE
+	(void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
+# endif
+#else
+# ifdef  STREAMSPTY
+	(void) tcgetattr(ttyfd, &termbuf);
+# else
+	(void) tcgetattr(pty, &termbuf);
+# endif
+#endif
+	termbuf2 = termbuf;
+}
+
+#if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
+	void
+copy_termbuf(cp, len)
+	char *cp;
+	int len;
+{
+	if (len > sizeof(termbuf))
+		len = sizeof(termbuf);
+	memcpy((char *)&termbuf, cp, len);
+	termbuf2 = termbuf;
+}
+#endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
+
+	void
+set_termbuf()
+{
+	/*
+	 * Only make the necessary changes.
+	 */
+#ifndef	USE_TERMIO
+	if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
+		(void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
+	if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
+		(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
+	if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
+							sizeof(termbuf.ltc)))
+		(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
+	if (termbuf.lflags != termbuf2.lflags)
+		(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
+#else	/* USE_TERMIO */
+	if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
+# ifdef  STREAMSPTY
+		(void) tcsetattr(ttyfd, TCSANOW, &termbuf);
+# else
+		(void) tcsetattr(pty, TCSANOW, &termbuf);
+# endif
+# if	defined(CRAY2) && defined(UNICOS5)
+	needtermstat = 1;
+# endif
+#endif	/* USE_TERMIO */
+}
+
+
+/*
+ * spcset(func, valp, valpp)
+ *
+ * This function takes various special characters (func), and
+ * sets *valp to the current value of that character, and
+ * *valpp to point to where in the "termbuf" structure that
+ * value is kept.
+ *
+ * It returns the SLC_ level of support for this function.
+ */
+
+#ifndef	USE_TERMIO
+	int
+spcset(func, valp, valpp)
+	int func;
+	cc_t *valp;
+	cc_t **valpp;
+{
+	switch(func) {
+	case SLC_EOF:
+		*valp = termbuf.tc.t_eofc;
+		*valpp = (cc_t *)&termbuf.tc.t_eofc;
+		return(SLC_VARIABLE);
+	case SLC_EC:
+		*valp = termbuf.sg.sg_erase;
+		*valpp = (cc_t *)&termbuf.sg.sg_erase;
+		return(SLC_VARIABLE);
+	case SLC_EL:
+		*valp = termbuf.sg.sg_kill;
+		*valpp = (cc_t *)&termbuf.sg.sg_kill;
+		return(SLC_VARIABLE);
+	case SLC_IP:
+		*valp = termbuf.tc.t_intrc;
+		*valpp = (cc_t *)&termbuf.tc.t_intrc;
+		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+	case SLC_ABORT:
+		*valp = termbuf.tc.t_quitc;
+		*valpp = (cc_t *)&termbuf.tc.t_quitc;
+		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+	case SLC_XON:
+		*valp = termbuf.tc.t_startc;
+		*valpp = (cc_t *)&termbuf.tc.t_startc;
+		return(SLC_VARIABLE);
+	case SLC_XOFF:
+		*valp = termbuf.tc.t_stopc;
+		*valpp = (cc_t *)&termbuf.tc.t_stopc;
+		return(SLC_VARIABLE);
+	case SLC_AO:
+		*valp = termbuf.ltc.t_flushc;
+		*valpp = (cc_t *)&termbuf.ltc.t_flushc;
+		return(SLC_VARIABLE);
+	case SLC_SUSP:
+		*valp = termbuf.ltc.t_suspc;
+		*valpp = (cc_t *)&termbuf.ltc.t_suspc;
+		return(SLC_VARIABLE);
+	case SLC_EW:
+		*valp = termbuf.ltc.t_werasc;
+		*valpp = (cc_t *)&termbuf.ltc.t_werasc;
+		return(SLC_VARIABLE);
+	case SLC_RP:
+		*valp = termbuf.ltc.t_rprntc;
+		*valpp = (cc_t *)&termbuf.ltc.t_rprntc;
+		return(SLC_VARIABLE);
+	case SLC_LNEXT:
+		*valp = termbuf.ltc.t_lnextc;
+		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
+		return(SLC_VARIABLE);
+	case SLC_FORW1:
+		*valp = termbuf.tc.t_brkc;
+		*valpp = (cc_t *)&termbuf.ltc.t_lnextc;
+		return(SLC_VARIABLE);
+	case SLC_BRK:
+	case SLC_SYNCH:
+	case SLC_AYT:
+	case SLC_EOR:
+		*valp = (cc_t)0;
+		*valpp = (cc_t *)0;
+		return(SLC_DEFAULT);
+	default:
+		*valp = (cc_t)0;
+		*valpp = (cc_t *)0;
+		return(SLC_NOSUPPORT);
+	}
+}
+
+#else	/* USE_TERMIO */
+
+	int
+spcset(func, valp, valpp)
+	int func;
+	cc_t *valp;
+	cc_t **valpp;
+{
+
+#define	setval(a, b)	*valp = termbuf.c_cc[a]; \
+			*valpp = &termbuf.c_cc[a]; \
+			return(b);
+#define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
+
+	switch(func) {
+	case SLC_EOF:
+		setval(VEOF, SLC_VARIABLE);
+	case SLC_EC:
+		setval(VERASE, SLC_VARIABLE);
+	case SLC_EL:
+		setval(VKILL, SLC_VARIABLE);
+	case SLC_IP:
+		setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+	case SLC_ABORT:
+		setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+	case SLC_XON:
+#ifdef	VSTART
+		setval(VSTART, SLC_VARIABLE);
+#else
+		defval(0x13);
+#endif
+	case SLC_XOFF:
+#ifdef	VSTOP
+		setval(VSTOP, SLC_VARIABLE);
+#else
+		defval(0x11);
+#endif
+	case SLC_EW:
+#ifdef	VWERASE
+		setval(VWERASE, SLC_VARIABLE);
+#else
+		defval(0);
+#endif
+	case SLC_RP:
+#ifdef	VREPRINT
+		setval(VREPRINT, SLC_VARIABLE);
+#else
+		defval(0);
+#endif
+	case SLC_LNEXT:
+#ifdef	VLNEXT
+		setval(VLNEXT, SLC_VARIABLE);
+#else
+		defval(0);
+#endif
+	case SLC_AO:
+#if	!defined(VDISCARD) && defined(VFLUSHO)
+# define VDISCARD VFLUSHO
+#endif
+#ifdef	VDISCARD
+		setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
+#else
+		defval(0);
+#endif
+	case SLC_SUSP:
+#ifdef	VSUSP
+		setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
+#else
+		defval(0);
+#endif
+#ifdef	VEOL
+	case SLC_FORW1:
+		setval(VEOL, SLC_VARIABLE);
+#endif
+#ifdef	VEOL2
+	case SLC_FORW2:
+		setval(VEOL2, SLC_VARIABLE);
+#endif
+	case SLC_AYT:
+#ifdef	VSTATUS
+		setval(VSTATUS, SLC_VARIABLE);
+#else
+		defval(0);
+#endif
+
+	case SLC_BRK:
+	case SLC_SYNCH:
+	case SLC_EOR:
+		defval(0);
+
+	default:
+		*valp = 0;
+		*valpp = 0;
+		return(SLC_NOSUPPORT);
+	}
+}
+#endif	/* USE_TERMIO */
+
+#ifdef CRAY
+/*
+ * getnpty()
+ *
+ * Return the number of pty's configured into the system.
+ */
+	int
+getnpty()
+{
+#ifdef _SC_CRAY_NPTY
+	int numptys;
+
+	if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
+		return numptys;
+	else
+#endif /* _SC_CRAY_NPTY */
+		return 128;
+}
+#endif /* CRAY */
+
+#ifndef	convex
+/*
+ * getpty()
+ *
+ * Allocate a pty.  As a side effect, the external character
+ * array "line" contains the name of the slave side.
+ *
+ * Returns the file descriptor of the opened pty.
+ */
+static char Xline[17];
+char *line = Xline;
+
+#ifdef	CRAY
+char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+#endif	/* CRAY */
+
+
+#endif	/* convex */
+
+static pid_t slavepid = 0;
+
+#ifdef	LINEMODE
+/*
+ * tty_flowmode()	Find out if flow control is enabled or disabled.
+ * tty_linemode()	Find out if linemode (external processing) is enabled.
+ * tty_setlinemod(on)	Turn on/off linemode.
+ * tty_isecho()		Find out if echoing is turned on.
+ * tty_setecho(on)	Enable/disable character echoing.
+ * tty_israw()		Find out if terminal is in RAW mode.
+ * tty_binaryin(on)	Turn on/off BINARY on input.
+ * tty_binaryout(on)	Turn on/off BINARY on output.
+ * tty_isediting()	Find out if line editing is enabled.
+ * tty_istrapsig()	Find out if signal trapping is enabled.
+ * tty_setedit(on)	Turn on/off line editing.
+ * tty_setsig(on)	Turn on/off signal trapping.
+ * tty_issofttab()	Find out if tab expansion is enabled.
+ * tty_setsofttab(on)	Turn on/off soft tab expansion.
+ * tty_islitecho()	Find out if typed control chars are echoed literally
+ * tty_setlitecho()	Turn on/off literal echo of control chars
+ * tty_tspeed(val)	Set transmit speed to val.
+ * tty_rspeed(val)	Set receive speed to val.
+ */
+
+#ifdef convex
+static int linestate;
+#endif
+
+	int
+tty_linemode()
+{
+#ifndef convex
+#ifndef	USE_TERMIO
+	return(termbuf.state & TS_EXTPROC);
+#else
+	return(termbuf.c_lflag & EXTPROC);
+#endif
+#else
+	return(linestate);
+#endif
+}
+
+	void
+tty_setlinemode(on)
+	int on;
+{
+#ifdef	TIOCEXT
+# ifndef convex
+	set_termbuf();
+# else
+	linestate = on;
+# endif
+	(void) ioctl(pty, TIOCEXT, (char *)&on);
+# ifndef convex
+	init_termbuf();
+# endif
+#else	/* !TIOCEXT */
+# ifdef	EXTPROC
+	if (on)
+		termbuf.c_lflag |= EXTPROC;
+	else
+		termbuf.c_lflag &= ~EXTPROC;
+# endif
+#endif	/* TIOCEXT */
+}
+#endif	/* LINEMODE */
+
+	int
+tty_isecho()
+{
+#ifndef USE_TERMIO
+	return (termbuf.sg.sg_flags & ECHO);
+#else
+	return (termbuf.c_lflag & ECHO);
+#endif
+}
+
+	int
+tty_flowmode()
+{
+#ifndef USE_TERMIO
+	return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
+#else
+	return((termbuf.c_iflag & IXON) ? 1 : 0);
+#endif
+}
+
+	int
+tty_restartany()
+{
+#ifndef USE_TERMIO
+# ifdef	DECCTQ
+	return((termbuf.lflags & DECCTQ) ? 0 : 1);
+# else
+	return(-1);
+# endif
+#else
+	return((termbuf.c_iflag & IXANY) ? 1 : 0);
+#endif
+}
+
+	void
+tty_setecho(on)
+	int on;
+{
+#ifndef	USE_TERMIO
+	if (on)
+		termbuf.sg.sg_flags |= ECHO|CRMOD;
+	else
+		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
+#else
+	if (on)
+		termbuf.c_lflag |= ECHO;
+	else
+		termbuf.c_lflag &= ~ECHO;
+#endif
+}
+
+	int
+tty_israw()
+{
+#ifndef USE_TERMIO
+	return(termbuf.sg.sg_flags & RAW);
+#else
+	return(!(termbuf.c_lflag & ICANON));
+#endif
+}
+
+#if	defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
+	int
+tty_setraw(on)
+{
+#  ifndef USE_TERMIO
+	if (on)
+		termbuf.sg.sg_flags |= RAW;
+	else
+		termbuf.sg.sg_flags &= ~RAW;
+#  else
+	if (on)
+		termbuf.c_lflag &= ~ICANON;
+	else
+		termbuf.c_lflag |= ICANON;
+#  endif
+}
+#endif
+
+	void
+tty_binaryin(on)
+	int on;
+{
+#ifndef	USE_TERMIO
+	if (on)
+		termbuf.lflags |= LPASS8;
+	else
+		termbuf.lflags &= ~LPASS8;
+#else
+	if (on) {
+		termbuf.c_iflag &= ~ISTRIP;
+	} else {
+		termbuf.c_iflag |= ISTRIP;
+	}
+#endif
+}
+
+	void
+tty_binaryout(on)
+	int on;
+{
+#ifndef	USE_TERMIO
+	if (on)
+		termbuf.lflags |= LLITOUT;
+	else
+		termbuf.lflags &= ~LLITOUT;
+#else
+	if (on) {
+		termbuf.c_cflag &= ~(CSIZE|PARENB);
+		termbuf.c_cflag |= CS8;
+		termbuf.c_oflag &= ~OPOST;
+	} else {
+		termbuf.c_cflag &= ~CSIZE;
+		termbuf.c_cflag |= CS7|PARENB;
+		termbuf.c_oflag |= OPOST;
+	}
+#endif
+}
+
+	int
+tty_isbinaryin()
+{
+#ifndef	USE_TERMIO
+	return(termbuf.lflags & LPASS8);
+#else
+	return(!(termbuf.c_iflag & ISTRIP));
+#endif
+}
+
+	int
+tty_isbinaryout()
+{
+#ifndef	USE_TERMIO
+	return(termbuf.lflags & LLITOUT);
+#else
+	return(!(termbuf.c_oflag&OPOST));
+#endif
+}
+
+#ifdef	LINEMODE
+	int
+tty_isediting()
+{
+#ifndef USE_TERMIO
+	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
+#else
+	return(termbuf.c_lflag & ICANON);
+#endif
+}
+
+	int
+tty_istrapsig()
+{
+#ifndef USE_TERMIO
+	return(!(termbuf.sg.sg_flags&RAW));
+#else
+	return(termbuf.c_lflag & ISIG);
+#endif
+}
+
+	void
+tty_setedit(on)
+	int on;
+{
+#ifndef USE_TERMIO
+	if (on)
+		termbuf.sg.sg_flags &= ~CBREAK;
+	else
+		termbuf.sg.sg_flags |= CBREAK;
+#else
+	if (on)
+		termbuf.c_lflag |= ICANON;
+	else
+		termbuf.c_lflag &= ~ICANON;
+#endif
+}
+
+	void
+tty_setsig(on)
+	int on;
+{
+#ifndef	USE_TERMIO
+	if (on)
+		;
+#else
+	if (on)
+		termbuf.c_lflag |= ISIG;
+	else
+		termbuf.c_lflag &= ~ISIG;
+#endif
+}
+#endif	/* LINEMODE */
+
+	int
+tty_issofttab()
+{
+#ifndef	USE_TERMIO
+	return (termbuf.sg.sg_flags & XTABS);
+#else
+# ifdef	OXTABS
+	return (termbuf.c_oflag & OXTABS);
+# endif
+# ifdef	TABDLY
+	return ((termbuf.c_oflag & TABDLY) == TAB3);
+# endif
+#endif
+}
+
+	void
+tty_setsofttab(on)
+	int on;
+{
+#ifndef	USE_TERMIO
+	if (on)
+		termbuf.sg.sg_flags |= XTABS;
+	else
+		termbuf.sg.sg_flags &= ~XTABS;
+#else
+	if (on) {
+# ifdef	OXTABS
+		termbuf.c_oflag |= OXTABS;
+# endif
+# ifdef	TABDLY
+		termbuf.c_oflag &= ~TABDLY;
+		termbuf.c_oflag |= TAB3;
+# endif
+	} else {
+# ifdef	OXTABS
+		termbuf.c_oflag &= ~OXTABS;
+# endif
+# ifdef	TABDLY
+		termbuf.c_oflag &= ~TABDLY;
+		termbuf.c_oflag |= TAB0;
+# endif
+	}
+#endif
+}
+
+	int
+tty_islitecho()
+{
+#ifndef	USE_TERMIO
+	return (!(termbuf.lflags & LCTLECH));
+#else
+# ifdef	ECHOCTL
+	return (!(termbuf.c_lflag & ECHOCTL));
+# endif
+# ifdef	TCTLECH
+	return (!(termbuf.c_lflag & TCTLECH));
+# endif
+# if	!defined(ECHOCTL) && !defined(TCTLECH)
+	return (0);	/* assumes ctl chars are echoed '^x' */
+# endif
+#endif
+}
+
+	void
+tty_setlitecho(on)
+	int on;
+{
+#ifndef	USE_TERMIO
+	if (on)
+		termbuf.lflags &= ~LCTLECH;
+	else
+		termbuf.lflags |= LCTLECH;
+#else
+# ifdef	ECHOCTL
+	if (on)
+		termbuf.c_lflag &= ~ECHOCTL;
+	else
+		termbuf.c_lflag |= ECHOCTL;
+# endif
+# ifdef	TCTLECH
+	if (on)
+		termbuf.c_lflag &= ~TCTLECH;
+	else
+		termbuf.c_lflag |= TCTLECH;
+# endif
+#endif
+}
+
+	int
+tty_iscrnl()
+{
+#ifndef	USE_TERMIO
+	return (termbuf.sg.sg_flags & CRMOD);
+#else
+	return (termbuf.c_iflag & ICRNL);
+#endif
+}
+
+/*
+ * A table of available terminal speeds
+ */
+struct termspeeds {
+	int	speed;
+	speed_t	value;
+} termspeeds[] = {
+	{ 0,     B0 },    { 50,    B50 },   { 75,    B75 },
+	{ 110,   B110 },  { 134,   B134 },  { 150,   B150 },
+	{ 200,   B200 },  { 300,   B300 },  { 600,   B600 },
+	{ 1200,  B1200 }, { 1800,  B1800 }, { 2400,  B2400 },
+	{ 4800,  B4800 }, { 9600,  B9600 }, { 19200, B9600 },
+	{ 38400, B9600 }, { -1,    B9600 }
+};
+
+	void
+tty_tspeed(val)
+	int val;
+{
+	register struct termspeeds *tp;
+
+	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
+		;
+	cfsetospeed(&termbuf, tp->value);
+}
+
+	void
+tty_rspeed(val)
+	int val;
+{
+	register struct termspeeds *tp;
+
+	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
+		;
+	cfsetispeed(&termbuf, tp->value);
+}
+
+#if	defined(CRAY2) && defined(UNICOS5)
+	int
+tty_isnewmap()
+{
+	return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
+			!(termbuf.c_oflag & ONLRET));
+}
+#endif
+
+
+#ifndef	NEWINIT
+#endif
+
+/*
+ * getptyslave()
+ *
+ * Open the slave side of the pty, and do any initialization
+ * that is necessary.  The return value is a file descriptor
+ * for the slave side.
+ */
+static void
+getptyslave()
+{
+     int t = -1;
+     long retval;
+
+#if	!defined(CRAY) || !defined(NEWINIT)
+# ifdef	LINEMODE
+	int waslm;
+# endif
+# ifdef	TIOCGWINSZ
+	struct winsize ws;
+	extern int def_row, def_col;
+# endif
+	extern int def_tspeed, def_rspeed;
+	/*
+	 * Opening the slave side may cause initilization of the
+	 * kernel tty structure.  We need remember the state of
+	 * 	if linemode was turned on
+	 *	terminal window size
+	 *	terminal speed
+	 * so that we can re-set them if we need to.
+	 */
+# ifdef	LINEMODE
+	waslm = tty_linemode();
+# endif
+
+	if ( (retval = pty_open_slave (line, &t)) != 0 )
+	    {
+		fatalperror(net,  error_message(retval));
+	    }
+
+#ifdef  STREAMSPTY
+#ifdef	USE_TERMIO
+	ttyfd = t;
+#endif
+	if (ioctl(pty, I_PUSH, "pckt") < 0) {
+#ifndef _AIX
+		fatal(net, "I_PUSH pckt");
+#endif
+	}
+#endif
+
+	/*
+	 * set up the tty modes as we like them to be.
+	 */
+	init_termbuf();
+# ifdef	TIOCGWINSZ
+	if (def_row || def_col) {
+		memset((char *)&ws, 0, sizeof(ws));
+		ws.ws_col = def_col;
+		ws.ws_row = def_row;
+		(void)ioctl(t, TIOCSWINSZ, (char *)&ws);
+	}
+# endif
+
+	/*
+	 * Settings for sgtty based systems
+	 */
+# ifndef	USE_TERMIO
+	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
+# endif	/* USE_TERMIO */
+
+	/*
+	 * Settings for UNICOS (and HPUX)
+	 */
+# if defined(CRAY) || defined(__hpux)
+	termbuf.c_oflag = OPOST|ONLCR|TAB3;
+	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
+	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
+	termbuf.c_cflag = EXTB|HUPCL|CS8;
+# endif
+
+	/*
+	 * Settings for all other termios/termio based
+	 * systems, other than 4.4BSD.  In 4.4BSD the
+	 * kernel does the initial terminal setup.
+	 */
+# if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
+#  ifndef	OXTABS
+#   define OXTABS	0
+#  endif
+	termbuf.c_lflag |= ECHO|ICANON|IEXTEN|ISIG;
+	termbuf.c_oflag |= ONLCR|OXTABS|OPOST;
+	termbuf.c_iflag |= ICRNL|IGNPAR;
+termbuf.c_cflag |= HUPCL;
+	termbuf.c_iflag &= ~IXOFF;
+# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
+	tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
+	tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
+# ifdef	LINEMODE
+	if (waslm)
+		tty_setlinemode(1);
+# endif	/* LINEMODE */
+
+	/*
+	 * Set the tty modes, and make this our controlling tty.
+	 */
+	set_termbuf();
+	if (dup_tty(t) == -1)
+		fatalperror(net, "dup_tty");
+#endif	/* !defined(CRAY) || !defined(NEWINIT) */
+	if (net > 2)
+		(void) close(net);
+#if	defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
+	/*
+	 * Leave the pty open so that we can write out the rlogin
+	 * protocol for /bin/login, if the authentication works.
+	 */
+#else
+	if (pty > 2) {
+		(void) close(pty);
+		pty = -1;
+	}
+#endif
+}
+
+#if	!defined(CRAY) || !defined(NEWINIT)
+#ifndef	O_NOCTTY
+#define	O_NOCTTY	0
+#endif
+#endif	/* !defined(CRAY) || !defined(NEWINIT) */
+
+
+
+	int
+dup_tty(t)
+	int t;
+{
+	if (t != 0)
+		(void) dup2(t, 0);
+	if (t != 1)
+		(void) dup2(t, 1);
+	if (t != 2)
+		(void) dup2(t, 2);
+	if (t > 2)
+		close(t);
+	return(0);
+}
+
+
+#ifdef	NEWINIT
+char *gen_id = "fe";
+#endif
+
+/*
+ * startslave(host)
+ *
+ * Given a hostname, do whatever
+ * is necessary to startup the login process on the slave side of the pty.
+ */
+
+
+/* ARGSUSED */
+	void
+startslave(host, autologin, autoname)
+	char *host;
+	int autologin;
+	char *autoname;
+{
+	int syncpipe[2];
+	register int i;
+#ifdef	NEWINIT
+	extern char *ptyip;
+	struct init_request request;
+	void nologinproc();
+	register int n;
+#endif	/* NEWINIT */
+
+	if ( pipe(syncpipe) < 0 ) 
+		fatal(net, "failed getting synchronization pipe");
+    
+#if	defined(AUTHENTICATION)
+	if (!autoname || !autoname[0])
+		autologin = 0;
+
+	if (autologin < auth_level) {
+		fatal(net, "Authorization failed");
+		exit(1);
+	}
+#endif
+
+#ifndef	NEWINIT
+
+	if ((i = fork()) < 0)
+		fatalperror(net, "fork");
+	if (i) {
+		char c;
+
+		void sigjob (int);
+		slavepid = i; /* So we can clean it up later */
+#ifdef	CRAY
+		(void) signal(WJSIGNAL, sigjob);
+#endif
+
+		/* Wait for child before writing to parent side of pty.*/
+		(void) close(syncpipe[1]);
+		if ( read(syncpipe[0], &c, 1) == 0 ) {
+			/* Slave side died */
+			fatal ( net, "Slave failed to initialize");
+		}
+
+		close(syncpipe[0]);
+		
+	} else {
+		
+		pty_update_utmp (PTY_LOGIN_PROCESS, getpid(), "LOGIN", line,
+				 host, PTY_TTYSLOT_USABLE);
+		getptyslave();
+
+		/* Notify our parent we're ready to continue.*/
+		write(syncpipe[1],"y",1);
+		close(syncpipe[0]);
+		close(syncpipe[1]);
+		
+		start_login(host, autologin, autoname);
+		/*NOTREACHED*/
+	}
+#else	/* NEWINIT */
+
+	/*
+	 * Init will start up login process if we ask nicely.  We only wait
+	 * for it to start up and begin normal telnet operation.
+	 */
+	if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
+		char tbuf[128];
+		(void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
+		fatalperror(net, tbuf);
+	}
+	memset((char *)&request, 0, sizeof(request));
+	request.magic = INIT_MAGIC;
+	SCPYN(request.gen_id, gen_id);
+	SCPYN(request.tty_id, &line[8]);
+	SCPYN(request.host, host);
+	SCPYN(request.term_type, *terminaltype ? terminaltype : "network");
+#if	!defined(UNICOS5)
+	request.signal = SIGCLD;
+	request.pid = getpid();
+#endif
+#ifdef BFTPDAEMON
+	/*
+	 * Are we working as the bftp daemon?
+	 */
+	if (bftpd) {
+		SCPYN(request.exec_name, BFTPPATH);
+	}
+#endif /* BFTPDAEMON */
+	if (write(i, (char *)&request, sizeof(request)) < 0) {
+		char tbuf[128];
+		(void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
+		fatalperror(net, tbuf);
+	}
+	(void) close(i);
+	(void) signal(SIGALRM, nologinproc);
+	for (i = 0; ; i++) {
+		char tbuf[128];
+		alarm(15);
+		n = read(pty, ptyip, BUFSIZ);
+		if (i == 3 || n >= 0 || !gotalarm)
+			break;
+		gotalarm = 0;
+		sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line);
+		(void) write(net, tbuf, strlen(tbuf));
+	}
+	if (n < 0 && gotalarm)
+		fatal(net, "/etc/init didn't start login process");
+	pcc += n;
+	alarm(0);
+	(void) signal(SIGALRM, SIG_DFL);
+
+	return;
+#endif	/* NEWINIT */
+}
+
+char	*envinit[3];
+extern char **environ;
+
+	void
+init_env()
+{
+	extern char *getenv();
+	char **envp;
+
+	envp = envinit;
+	if ((*envp = getenv("TZ")))
+		*envp++ -= 3;
+#if	defined(CRAY) || defined(__hpux)
+	else
+		*envp++ = "TZ=GMT0";
+#endif
+	*envp = 0;
+	environ = envinit;
+}
+
+#ifndef	NEWINIT
+
+/*
+ * start_login(host)
+ *
+ * Assuming that we are now running as a child processes, this
+ * function will turn us into the login process.
+ */
+
+	void
+start_login(host, autologin, name)
+	char *host;
+	int autologin;
+	char *name;
+{
+	register char **argv;
+	extern char *getenv();
+
+#ifdef SOLARIS
+	char *term;
+	char termbuf[64];
+#endif
+
+
+	/*
+	 * -h : pass on name of host.
+	 *		WARNING:  -h is accepted by login if and only if
+	 *			getuid() == 0.
+	 * -p : don't clobber the environment (so terminal type stays set).
+	 *
+	 * -f : force this login, he has already been authenticated
+	 */
+	argv = addarg(0, "login");
+
+#if	!defined(NO_LOGIN_H)
+
+# if	defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
+	/*
+	 * Don't add the "-h host" option if we are going
+	 * to be adding the "-r host" option down below...
+	 */
+	if ((auth_level < 0) || (autologin != AUTH_VALID))
+# endif
+	{
+		argv = addarg(argv, "-h");
+		argv = addarg(argv, host);
+#ifdef	SOLARIS
+		/*
+		 * SVR4 version of -h takes TERM= as second arg, or -
+		 */
+		term = getenv("TERM");
+		if (term == NULL || term[0] == 0) {
+			term = "-";
+		} else {
+			strcpy(termbuf, "TERM=");
+			strncat(termbuf, term, sizeof(termbuf) - 6);
+			termbuf[sizeof(termbuf) - 1] = '\0';
+			term = termbuf;
+		}
+		argv = addarg(argv, term);
+#endif
+	}
+#endif
+#if	!defined(NO_LOGIN_P)
+	argv = addarg(argv, "-p");
+#endif
+#ifdef	BFTPDAEMON
+	/*
+	 * Are we working as the bftp daemon?  If so, then ask login
+	 * to start bftp instead of shell.
+	 */
+	if (bftpd) {
+		argv = addarg(argv, "-e");
+		argv = addarg(argv, BFTPPATH);
+	} else 
+#endif
+#if	defined (SecurID)
+	/*
+	 * don't worry about the -f that might get sent.
+	 * A -s is supposed to override it anyhow.
+	 */
+	if (require_SecurID)
+		argv = addarg(argv, "-s");
+#endif
+#if	defined (AUTHENTICATION)
+	if (auth_level >= 0 && autologin == AUTH_VALID) {
+# if	!defined(NO_LOGIN_F)
+#if	defined(LOGIN_CAP_F)
+		argv = addarg(argv, "-F");
+#else
+		argv = addarg(argv, "-f");
+#endif
+		argv = addarg(argv, name);
+# else
+#  if defined(LOGIN_R)
+		/*
+		 * We don't have support for "login -f", but we
+		 * can fool /bin/login into thinking that we are
+		 * rlogind, and allow us to log in without a
+		 * password.  The rlogin protocol expects
+		 *	local-user\0remote-user\0term/speed\0
+		 */
+
+		if (pty > 2) {
+			register char *cp;
+			char speed[1024];
+			int isecho, israw, xpty, len;
+			extern int def_rspeed;
+#  ifndef LOGIN_HOST
+			/*
+			 * Tell login that we are coming from "localhost".
+			 * If we passed in the real host name, then the
+			 * user would have to allow .rhost access from
+			 * every machine that they want authenticated
+			 * access to work from, which sort of defeats
+			 * the purpose of an authenticated login...
+			 * So, we tell login that the session is coming
+			 * from "localhost", and the user will only have
+			 * to have "localhost" in their .rhost file.
+			 */
+#			define LOGIN_HOST "localhost"
+#  endif
+			argv = addarg(argv, "-r");
+			argv = addarg(argv, LOGIN_HOST);
+
+			xpty = pty;
+# ifndef  STREAMSPTY
+			pty = 0;
+# else
+			ttyfd = 0;
+# endif
+			init_termbuf();
+			isecho = tty_isecho();
+			israw = tty_israw();
+			if (isecho || !israw) {
+				tty_setecho(0);		/* Turn off echo */
+				tty_setraw(1);		/* Turn on raw */
+				set_termbuf();
+			}
+			len = strlen(name)+1;
+			write(xpty, name, len);
+			write(xpty, name, len);
+			memset(speed, 0, sizeof(speed));
+			strncpy(speed,
+				(cp = getenv("TERM")) ? cp : "",
+				sizeof(speed)-1-(10*sizeof(def_rspeed)/4)-1);
+			/* 1 for /, () for the number, 1 for trailing 0. */
+			sprintf(speed + strlen(speed),
+				"/%d",
+				(def_rspeed > 0) ? def_rspeed : 9600);
+			len = strlen(speed)+1;
+			write(xpty, speed, len);
+
+			if (isecho || !israw) {
+				init_termbuf();
+				tty_setecho(isecho);
+				tty_setraw(israw);
+				set_termbuf();
+				if (!israw) {
+					/*
+					 * Write a newline to ensure
+					 * that login will be able to
+					 * read the line...
+					 */
+					write(xpty, "\n", 1);
+				}
+			}
+			pty = xpty;
+		}
+#  else
+		argv = addarg(argv, name);
+#  endif
+# endif
+	} else
+#endif
+	if (getenv("USER")) {
+		argv = addarg(argv, getenv("USER"));
+#if	defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
+		{
+			register char **cpp;
+			for (cpp = environ; *cpp; cpp++)
+				argv = addarg(argv, *cpp);
+		}
+#endif
+		/*
+		 * Assume that login will set the USER variable
+		 * correctly.  For SysV systems, this means that
+		 * USER will no longer be set, just LOGNAME by
+		 * login.  (The problem is that if the auto-login
+		 * fails, and the user then specifies a different
+		 * account name, he can get logged in with both
+		 * LOGNAME and USER in his environment, but the
+		 * USER value will be wrong.
+		 */
+		unsetenv("USER");
+	}
+#if	defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
+	if (pty > 2)
+		close(pty);
+#endif
+	closelog();
+	execv(login_program, argv);
+
+	syslog(LOG_ERR, "%s: %m", login_program);
+	fatalperror(net, login_program);
+	/*NOTREACHED*/
+}
+
+/*
+ * This code returns a pointer to the first element of the array and
+ * expects the same to be called with.
+ * Therefore the -1 reference is legal. 
+ */
+
+static char **
+addarg(argv, val)
+	register char **argv;
+	register char *val;
+{
+	register char **cpp;
+
+	if (argv == NULL) {
+		/*
+		 * 10 entries, a leading length, and a null
+		 */
+		argv = (char **)malloc(sizeof(*argv) * 12);
+		if (argv == NULL)
+			return(NULL);
+		*argv++ = (char *)10;
+		*argv = (char *)0;
+	}
+	for (cpp = argv; *cpp; cpp++)
+		;
+	if (cpp == &argv[(long)argv[-1]]) {
+		--argv;
+		*argv = (char *)((long)(*argv) + 10);
+		argv = (char **)realloc(argv, sizeof(*argv) * ((long)(*argv) + 2));
+		if (argv == NULL)
+			return(NULL);
+		argv++;
+		cpp = &argv[(long)argv[-1] - 10];
+	}
+	*cpp++ = val;
+	*cpp = 0;
+	return(argv);
+}
+#endif	/* NEWINIT */
+
+/*
+ * cleanup()
+ *
+ * This is the routine to call when we are all through, to
+ * clean up anything that needs to be cleaned up.
+ */
+	/* ARGSUSED */
+	void
+cleanup(sig)
+	int sig;
+{
+	pty_cleanup(line,slavepid,1);
+#ifdef KRB5
+	kerberos5_cleanup();
+#endif
+    
+	(void) shutdown(net, 2);
+	exit(1);
+}
+
+
+
+
+
diff --git a/mechglue/src/appl/telnet/telnetd/telnetd-ktd.c b/mechglue/src/appl/telnet/telnetd/telnetd-ktd.c
new file mode 100644
index 000000000..295f19580
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/telnetd-ktd.c
@@ -0,0 +1,1462 @@
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)telnetd.c	5.51 (Berkeley) 1/21/93 */
+
+#include "telnetd.h"
+#include "pathnames.h"
+
+#if	defined(_SC_CRAY_SECURE_SYS)
+#include <sys/sysv.h>
+#include <libpty.h>
+#include <sys/secdev.h>
+int	secflag;
+char	tty_dev[16];
+struct	secdev dv;
+struct	sysv sysv;
+struct	socket_security ss;
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+#if	defined(AUTHENTICATION)
+#include <libtelnet/auth.h>
+int	auth_level = 0;
+#endif
+#if	defined(SecurID)
+int	require_SecurID = 0;
+#endif
+
+extern	int utmp_len;
+int	registerd_host_only = 0;
+
+#ifdef	STREAMSPTY
+# include <stropts.h>
+# include <termio.h>
+/* make sure we don't get the bsd version */
+# include "/usr/include/sys/tty.h"
+# include <sys/ptyvar.h>
+
+/*
+ * Because of the way ptyibuf is used with streams messages, we need
+ * ptyibuf+1 to be on a full-word boundary.  The following wierdness
+ * is simply to make that happen.
+ */
+char	ptyibufbuf[BUFSIZ+4];
+char	*ptyibuf = ptyibufbuf+3;
+char	*ptyip = ptyibufbuf+3;
+char	ptyibuf2[BUFSIZ];
+unsigned char ctlbuf[BUFSIZ];
+struct	strbuf strbufc, strbufd;
+
+int readstream();
+
+#else	/* ! STREAMPTY */
+
+/*
+ * I/O data buffers,
+ * pointers, and counters.
+ */
+char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
+char	ptyibuf2[BUFSIZ];
+
+#endif /* ! STREAMPTY */
+
+int	hostinfo = 1;			/* do we print login banner? */
+
+#ifdef	CRAY
+extern int      newmap; /* nonzero if \n maps to ^M^J */
+int	lowpty = 0, highpty;	/* low, high pty numbers */
+#endif /* CRAY */
+
+int debug = 0;
+int keepalive = 1;
+char *progname;
+
+extern void usage (void);
+
+main(argc, argv)
+	char *argv[];
+{
+	struct sockaddr_in from;
+	int on = 1, fromlen;
+	register int ch;
+	extern char *optarg;
+	extern int optind;
+#if	defined(IPPROTO_IP) && defined(IP_TOS)
+	int tos = -1;
+#endif
+
+	pfrontp = pbackp = ptyobuf;
+	netip = netibuf;
+	nfrontp = nbackp = netobuf;
+#if	defined(ENCRYPTION)
+	nclearto = 0;
+#endif
+
+	progname = *argv;
+
+#ifdef CRAY
+	/*
+	 * Get number of pty's before trying to process options,
+	 * which may include changing pty range.
+	 */
+	highpty = getnpty();
+#endif /* CRAY */
+
+	while ((ch = getopt(argc, argv, "d:a:e:klhnr:u:UI:D:B:sS:a:X:")) != -1) {
+		switch(ch) {
+
+#ifdef	AUTHENTICATION
+		case 'a':
+			/*
+			 * Check for required authentication level
+			 */
+			if (strcmp(optarg, "debug") == 0) {
+				extern int auth_debug_mode;
+				auth_debug_mode = 1;
+			} else if (strcasecmp(optarg, "none") == 0) {
+				auth_level = 0;
+			} else if (strcasecmp(optarg, "other") == 0) {
+				auth_level = AUTH_OTHER;
+			} else if (strcasecmp(optarg, "user") == 0) {
+				auth_level = AUTH_USER;
+			} else if (strcasecmp(optarg, "valid") == 0) {
+				auth_level = AUTH_VALID;
+			} else if (strcasecmp(optarg, "off") == 0) {
+				/*
+				 * This hack turns off authentication
+				 */
+				auth_level = -1;
+			} else {
+				fprintf(stderr,
+			    "telnetd: unknown authorization level for -a\n");
+			}
+			break;
+#endif	/* AUTHENTICATION */
+
+#ifdef BFTPDAEMON
+		case 'B':
+			bftpd++;
+			break;
+#endif /* BFTPDAEMON */
+
+		case 'd':
+			if (strcmp(optarg, "ebug") == 0) {
+				debug++;
+				break;
+			}
+			usage();
+			/* NOTREACHED */
+			break;
+
+#ifdef DIAGNOSTICS
+		case 'D':
+			/*
+			 * Check for desired diagnostics capabilities.
+			 */
+			if (!strcmp(optarg, "report")) {
+				diagnostic |= TD_REPORT|TD_OPTIONS;
+			} else if (!strcmp(optarg, "exercise")) {
+				diagnostic |= TD_EXERCISE;
+			} else if (!strcmp(optarg, "netdata")) {
+				diagnostic |= TD_NETDATA;
+			} else if (!strcmp(optarg, "ptydata")) {
+				diagnostic |= TD_PTYDATA;
+			} else if (!strcmp(optarg, "options")) {
+				diagnostic |= TD_OPTIONS;
+			} else {
+				usage();
+				/* NOT REACHED */
+			}
+			break;
+#endif /* DIAGNOSTICS */
+
+#ifdef	ENCRYPTION
+		case 'e':
+			if (strcmp(optarg, "debug") == 0) {
+				extern int encrypt_debug_mode;
+				encrypt_debug_mode = 1;
+				break;
+			}
+			usage();
+			/* NOTREACHED */
+			break;
+#endif	/* ENCRYPTION */
+
+		case 'h':
+			hostinfo = 0;
+			break;
+
+#if	defined(CRAY) && defined(NEWINIT)
+		case 'I':
+		    {
+			extern char *gen_id;
+			gen_id = optarg;
+			break;
+		    }
+#endif	/* defined(CRAY) && defined(NEWINIT) */
+
+#ifdef	LINEMODE
+		case 'l':
+			alwayslinemode = 1;
+			break;
+#endif	/* LINEMODE */
+
+		case 'k':
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+			lmodetype = NO_AUTOKLUDGE;
+#else
+			/* ignore -k option if built without kludge linemode */
+#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+			break;
+
+		case 'n':
+			keepalive = 0;
+			break;
+
+#ifdef CRAY
+		case 'r':
+		    {
+			char *strchr();
+			char *c;
+
+			/*
+			 * Allow the specification of alterations
+			 * to the pty search range.  It is legal to
+			 * specify only one, and not change the
+			 * other from its default.
+			 */
+			c = strchr(optarg, '-');
+			if (c) {
+				*c++ = '\0';
+				highpty = atoi(c);
+			}
+			if (*optarg != '\0')
+				lowpty = atoi(optarg);
+			if ((lowpty > highpty) || (lowpty < 0) ||
+							(highpty > 32767)) {
+				usage();
+				/* NOT REACHED */
+			}
+			break;
+		    }
+#endif	/* CRAY */
+
+#ifdef	SecurID
+		case 's':
+			/* SecurID required */
+			require_SecurID = 1;
+			break;
+#endif	/* SecurID */
+		case 'S':
+#ifdef	HAVE_GETTOSBYNAME
+			if ((tos = parsetos(optarg, "tcp")) < 0)
+				fprintf(stderr, "%s%s%s\n",
+					"telnetd: Bad TOS argument '", optarg,
+					"'; will try to use default TOS");
+#else
+			fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
+						"-S flag not supported\n");
+#endif
+			break;
+
+		case 'u':
+			utmp_len = atoi(optarg);
+			break;
+
+		case 'U':
+			registerd_host_only = 1;
+			break;
+
+#ifdef	AUTHENTICATION
+		case 'X':
+			/*
+			 * Check for invalid authentication types
+			 */
+			auth_disable_name(optarg);
+			break;
+#endif	/* AUTHENTICATION */
+
+		default:
+			fprintf(stderr, "telnetd: %s: unknown option\n", ch);
+			/* FALLTHROUGH */
+		case '?':
+			usage();
+			/* NOTREACHED */
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (debug) {
+	    int s, ns, foo;
+	    struct servent *sp;
+	    static struct sockaddr_in sin = { AF_INET };
+
+	    if (argc > 1) {
+		usage();
+		/* NOT REACHED */
+	    } else if (argc == 1) {
+		    if (sp = getservbyname(*argv, "tcp")) {
+			sin.sin_port = sp->s_port;
+		    } else {
+			sin.sin_port = atoi(*argv);
+			if ((int)sin.sin_port <= 0) {
+			    fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
+			    usage();
+			    /* NOT REACHED */
+			}
+			sin.sin_port = htons((u_short)sin.sin_port);
+		   }
+	    } else {
+		sp = getservbyname("ktelnet", "tcp");
+		if (sp == 0) {
+		    fprintf(stderr, "telnetd: tcp/ktelnet: unknown service\n");
+		    exit(1);
+		}
+		sin.sin_port = sp->s_port;
+	    }
+
+	    s = socket(AF_INET, SOCK_STREAM, 0);
+	    if (s < 0) {
+		    perror("telnetd: socket");;
+		    exit(1);
+	    }
+	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+				(char *)&on, sizeof(on));
+	    if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+		perror("bind");
+		exit(1);
+	    }
+	    if (listen(s, 1) < 0) {
+		perror("listen");
+		exit(1);
+	    }
+	    foo = sizeof(sin);
+	    ns = accept(s, (struct sockaddr *)&sin, &foo);
+	    if (ns < 0) {
+		perror("accept");
+		exit(1);
+	    }
+	    (void) dup2(ns, 0);
+	    (void) close(ns);
+	    (void) close(s);
+#ifdef convex
+	} else if (argc == 1) {
+		; /* VOID*/		/* Just ignore the host/port name */
+#endif
+	} else if (argc > 0) {
+		usage();
+		/* NOT REACHED */
+	}
+
+#if	defined(_SC_CRAY_SECURE_SYS)
+	secflag = sysconf(_SC_CRAY_SECURE_SYS);
+
+	/*
+	 *      Get socket's security label 
+	 */
+	if (secflag)  {
+		int sz = sizeof(ss);
+
+		memset((char *)&dv, 0, sizeof(dv));
+
+		if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
+			perror("getsysv");
+			exit(1);
+		}
+
+		/*
+		 *      Get socket security label and set device values
+		 *         {security label to be set on ttyp device}
+		 */
+		if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
+				(char *)&ss, &sz) >= 0) {
+
+			dv.dv_actlvl = ss.ss_slevel;
+			dv.dv_actcmp = ss.ss_compart;
+			dv.dv_minlvl = ss.ss_minlvl;
+			dv.dv_maxlvl = ss.ss_maxlvl;
+			dv.dv_valcmp = ss.ss_maxcmp;
+		}
+	}
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+	fromlen = sizeof (from);
+	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+		fprintf(stderr, "%s: ", progname);
+		perror("getpeername");
+		_exit(1);
+	}
+	if (keepalive &&
+	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+			(char *)&on, sizeof (on)) < 0) {
+		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+	}
+
+#if	defined(IPPROTO_IP) && defined(IP_TOS)
+	{
+# if	defined(HAVE_GETTOSBYNAME)
+		struct tosent *tp;
+		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+			tos = tp->t_tos;
+# endif
+		if (tos < 0)
+			tos = 020;	/* Low Delay bit */
+		if (tos
+		   && (setsockopt(0, IPPROTO_IP, IP_TOS,
+				  (char *)&tos, sizeof(tos)) < 0)
+		   && (errno != ENOPROTOOPT) )
+			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+	}
+#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
+	net = 0;
+	doit(&from);
+	/* NOTREACHED */
+}  /* end of main */
+
+	void
+usage()
+{
+	fprintf(stderr, "Usage: telnetd");
+#ifdef	AUTHENTICATION
+	fprintf(stderr, " [-a (debug|other|user|valid|off)]\n\t");
+#endif
+#ifdef BFTPDAEMON
+	fprintf(stderr, " [-B]");
+#endif
+	fprintf(stderr, " [-debug]");
+#ifdef DIAGNOSTICS
+	fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
+#endif
+#ifdef	AUTHENTICATION
+	fprintf(stderr, " [-edebug]");
+#endif
+	fprintf(stderr, " [-h]");
+#if	defined(CRAY) && defined(NEWINIT)
+	fprintf(stderr, " [-Iinitid]");
+#endif
+#ifdef LINEMODE
+	fprintf(stderr, " [-l]");
+#endif
+	fprintf(stderr, " [-n]");
+#ifdef	CRAY
+	fprintf(stderr, " [-r[lowpty]-[highpty]]");
+#endif
+#ifdef	SecurID
+	fprintf(stderr, " [-s]");
+#endif
+#ifdef	AUTHENTICATION
+	fprintf(stderr, " [-X auth-type]");
+#endif
+	fprintf(stderr, " [-u utmp_hostname_length] [-U]");
+	fprintf(stderr, " [port]\n");
+	exit(1);
+}
+
+/*
+ * getterminaltype
+ *
+ *	Ask the other end to send along its terminal type and speed.
+ * Output is the variable terminaltype filled in.
+ */
+static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
+
+    int
+getterminaltype(name)
+    char *name;
+{
+    int retval = -1;
+    void _gettermname();
+
+    settimer(baseline);
+#if	defined(AUTHENTICATION)
+    /*
+     * Handle the Authentication option before we do anything else.
+     */
+    send_do(TELOPT_AUTHENTICATION, 1);
+    while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
+	ttloop();
+    if (his_state_is_will(TELOPT_AUTHENTICATION)) {
+	retval = auth_wait(name);
+    }
+#endif
+
+#if	defined(ENCRYPTION)
+    send_will(TELOPT_ENCRYPT, 1);
+#endif
+    send_do(TELOPT_TTYPE, 1);
+    send_do(TELOPT_TSPEED, 1);
+    send_do(TELOPT_XDISPLOC, 1);
+    send_do(TELOPT_ENVIRON, 1);
+    while (
+#if	defined(ENCRYPTION)
+	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
+#endif
+	   his_will_wont_is_changing(TELOPT_TTYPE) ||
+	   his_will_wont_is_changing(TELOPT_TSPEED) ||
+	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
+	   his_will_wont_is_changing(TELOPT_ENVIRON)) {
+	ttloop();
+    }
+#if	defined(ENCRYPTION)
+    /*
+     * Wait for the negotiation of what type of encryption we can
+     * send with.  If autoencrypt is not set, this will just return.
+     */
+    if (his_state_is_will(TELOPT_ENCRYPT)) {
+	encrypt_wait();
+    }
+#endif
+    if (his_state_is_will(TELOPT_TSPEED)) {
+	static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
+
+	if(nfrontp - netobuf + sizeof(sbbuf) < sizeof(netobuf)) {
+		memcpy(nfrontp, sbbuf, sizeof(sbbuf));
+		nfrontp += sizeof(sbbuf);
+	}
+    }
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+	static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
+
+	if(nfrontp - netobuf + sizeof(sbbuf) < sizeof(netobuf)) {
+		memcpy(nfrontp, sbbuf, sizeof(sbbuf));
+		nfrontp += sizeof(sbbuf);
+	}
+    }
+    if (his_state_is_will(TELOPT_ENVIRON)) {
+	static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+	if(nfrontp - netobuf + sizeof(sbbuf) < sizeof(netobuf)) {
+		memcpy(nfrontp, sbbuf, sizeof(sbbuf));
+		nfrontp += sizeof(sbbuf);
+	}
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
+
+	if(nfrontp - netobuf + sizeof(ttytype_sbbuf) < sizeof(netobuf)) {
+		memcpy(nfrontp, ttytype_sbbuf, sizeof(ttytype_sbbuf));
+		nfrontp += sizeof(ttytype_sbbuf);
+	}
+    }
+    if (his_state_is_will(TELOPT_TSPEED)) {
+	while (sequenceIs(tspeedsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+	while (sequenceIs(xdisplocsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_ENVIRON)) {
+	while (sequenceIs(environsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
+	char first[256], last[256];
+
+	while (sequenceIs(ttypesubopt, baseline))
+	    ttloop();
+
+	/*
+	 * If the other side has already disabled the option, then
+	 * we have to just go with what we (might) have already gotten.
+	 */
+	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
+	    (void) strncpy(first, terminaltype, sizeof(first) - 1);
+	    first[sizeof(first) - 1] = '\0';
+	    for(;;) {
+		/*
+		 * Save the unknown name, and request the next name.
+		 */
+		(void) strncpy(last, terminaltype, sizeof(last) - 1);
+	    	last[sizeof(last) - 1] = '\0';
+		_gettermname();
+		if (terminaltypeok(terminaltype))
+		    break;
+		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
+		    his_state_is_wont(TELOPT_TTYPE)) {
+		    /*
+		     * We've hit the end.  If this is the same as
+		     * the first name, just go with it.
+		     */
+		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
+			break;
+		    /*
+		     * Get the terminal name one more time, so that
+		     * RFC1091 compliant telnets will cycle back to
+		     * the start of the list.
+		     */
+		     _gettermname();
+		    if (strncmp(first, terminaltype, sizeof(first)) != 0)
+			(void) strncpy(terminaltype, first, sizeof(terminaltype) - 1);
+		    terminaltype[sizeof(terminaltype) - 1] = '\0';
+		    break;
+		}
+	    }
+	}
+    }
+    return(retval);
+}  /* end of getterminaltype */
+
+    void
+_gettermname()
+{
+    /*
+     * If the client turned off the option,
+     * we can't send another request, so we
+     * just return.
+     */
+    if (his_state_is_wont(TELOPT_TTYPE))
+	return;
+    settimer(baseline);
+    memcpy(nfrontp, ttytype_sbbuf, sizeof(ttytype_sbbuf));
+    nfrontp += sizeof(ttytype_sbbuf);
+    while (sequenceIs(ttypesubopt, baseline))
+	ttloop();
+}
+
+    int
+terminaltypeok(s)
+    char *s;
+{
+    char buf[1024];
+
+    if (terminaltype == NULL)
+	return(1);
+
+    /*
+     * tgetent() will return 1 if the type is known, and
+     * 0 if it is not known.  If it returns -1, it couldn't
+     * open the database.  But if we can't open the database,
+     * it won't help to say we failed, because we won't be
+     * able to verify anything else.  So, we treat -1 like 1.
+     */
+    if (tgetent(buf, s) == 0)
+	return(0);
+    return(1);
+}
+
+#ifndef	MAXHOSTNAMELEN
+#define	MAXHOSTNAMELEN 64
+#endif	/* MAXHOSTNAMELEN */
+
+char *hostname;
+char host_name[MAXHOSTNAMELEN];
+char remote_host_name[MAXHOSTNAMELEN];
+
+#ifndef	convex
+extern void telnet (int, int);
+#else
+extern void telnet (int, int, char *);
+#endif
+
+/*
+ * Get a pty, scan input lines.
+ */
+doit(who)
+	struct sockaddr_in *who;
+{
+	char *host, *inet_ntoa();
+	int t;
+	struct hostent *hp;
+	int level;
+	char user_name[256];
+
+	/*
+	 * Find an available pty to use.
+	 */
+	if ( (retval = pty_getpty(&pty, line, sizeof(line)) < 0 ) {
+	    com_err(retval, "telnetd", "");
+	    
+	if (pty < 0)
+		fatal(net, "All network ports in use");
+
+#if	defined(_SC_CRAY_SECURE_SYS)
+	/*
+	 *	set ttyp line security label 
+	 */
+	if (secflag) {
+		extern char *myline;
+		if (setdevs(myline, &dv) < 0)
+			fatal(net, "cannot set pty security");
+	}
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+	/* get name of connected client */
+	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
+		who->sin_family);
+
+	if (hp == NULL && registerd_host_only) {
+		fatal(net, "Couldn't resolve your address into a host name.\r\n\
+         Please contact your net administrator");
+	} else if (hp &&
+	    (strlen(hp->h_name) <= ((utmp_len < 0) ? -utmp_len : utmp_len))) {
+		host = hp->h_name;
+	} else {
+		host = inet_ntoa(who->sin_addr);
+	}
+	/*
+	 * We must make a copy because Kerberos is probably going
+	 * to also do a gethost* and overwrite the static data...
+	 */
+	strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
+	remote_host_name[sizeof(remote_host_name)-1] = 0;
+	host = remote_host_name;
+
+	(void) gethostname(host_name, sizeof (host_name));
+	hostname = host_name;
+
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
+	auth_encrypt_init(hostname, host, "TELNETD", 1);
+#endif
+
+	init_env();
+	/*
+	 * get terminal type.
+	 */
+	*user_name = 0;
+	level = getterminaltype(user_name);
+	setenv("TERM", terminaltype ? terminaltype : "network", 1);
+
+	/*
+	 * Start up the login process on the slave side of the terminal
+	 */
+
+	startslave(host, level, user_name);
+	telnet(net, pty);  /* begin server processing */
+	/*NOTREACHED*/
+}  /* end of doit */
+
+#if	defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
+	int
+Xterm_output(ibufp, obuf, icountp, ocount)
+	char **ibufp, *obuf;
+	int *icountp, ocount;
+{
+	int ret;
+	ret = term_output(*ibufp, obuf, *icountp, ocount);
+	*ibufp += *icountp;
+	*icountp = 0;
+	return(ret);
+}
+#define	term_output	Xterm_output
+#endif	/* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
+
+/*
+ * Main loop.  Select from pty and network, and
+ * hand data to telnet receiver finite state machine.
+ */
+	void
+#ifndef	convex
+telnet(f, p)
+#else
+telnet(f, p, host)
+#endif
+	int f, p;
+#ifdef convex
+	char *host;
+#endif
+{
+	int on = 1;
+#define	TABBUFSIZ	512
+	char	defent[TABBUFSIZ];
+	char	defstrs[TABBUFSIZ];
+#undef	TABBUFSIZ
+	char *HE;
+	char *HN;
+	char *IM;
+	void netflush();
+
+	/*
+	 * Initialize the slc mapping table.
+	 */
+	get_slc_defaults();
+
+	/*
+	 * Do some tests where it is desireable to wait for a response.
+	 * Rather than doing them slowly, one at a time, do them all
+	 * at once.
+	 */
+	if (my_state_is_wont(TELOPT_SGA))
+		send_will(TELOPT_SGA, 1);
+	/*
+	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
+	 * because 4.2 clients are unable to deal with TCP urgent data.
+	 *
+	 * To find out, we send out a "DO ECHO".  If the remote system
+	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
+	 * that fact ("WILL ECHO" ==> that the client will echo what
+	 * WE, the server, sends it; it does NOT mean that the client will
+	 * echo the terminal input).
+	 */
+	send_do(TELOPT_ECHO, 1);
+
+#ifdef	LINEMODE
+	if (his_state_is_wont(TELOPT_LINEMODE)) {
+		/* Query the peer for linemode support by trying to negotiate
+		 * the linemode option.
+		 */
+		linemode = 0;
+		editmode = 0;
+		send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
+	}
+#endif	/* LINEMODE */
+
+	/*
+	 * Send along a couple of other options that we wish to negotiate.
+	 */
+	send_do(TELOPT_NAWS, 1);
+	send_will(TELOPT_STATUS, 1);
+	flowmode = 1;		/* default flow control state */
+	restartany = -1;	/* uninitialized... */
+	send_do(TELOPT_LFLOW, 1);
+
+	/*
+	 * Spin, waiting for a response from the DO ECHO.  However,
+	 * some REALLY DUMB telnets out there might not respond
+	 * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
+	 * telnets so far seem to respond with WONT for a DO that
+	 * they don't understand...) because by the time we get the
+	 * response, it will already have processed the DO ECHO.
+	 * Kludge upon kludge.
+	 */
+	while (his_will_wont_is_changing(TELOPT_NAWS))
+		ttloop();
+
+	/*
+	 * But...
+	 * The client might have sent a WILL NAWS as part of its
+	 * startup code; if so, we'll be here before we get the
+	 * response to the DO ECHO.  We'll make the assumption
+	 * that any implementation that understands about NAWS
+	 * is a modern enough implementation that it will respond
+	 * to our DO ECHO request; hence we'll do another spin
+	 * waiting for the ECHO option to settle down, which is
+	 * what we wanted to do in the first place...
+	 */
+	if (his_want_state_is_will(TELOPT_ECHO) &&
+	    his_state_is_will(TELOPT_NAWS)) {
+		while (his_will_wont_is_changing(TELOPT_ECHO))
+			ttloop();
+	}
+	/*
+	 * On the off chance that the telnet client is broken and does not
+	 * respond to the DO ECHO we sent, (after all, we did send the
+	 * DO NAWS negotiation after the DO ECHO, and we won't get here
+	 * until a response to the DO NAWS comes back) simulate the
+	 * receipt of a will echo.  This will also send a WONT ECHO
+	 * to the client, since we assume that the client failed to
+	 * respond because it believes that it is already in DO ECHO
+	 * mode, which we do not want.
+	 */
+	if (his_want_state_is_will(TELOPT_ECHO)) {
+		DIAG(TD_OPTIONS,
+			{sprintf(nfrontp, "td: simulating recv\r\n");
+			 nfrontp += strlen(nfrontp);});
+		willoption(TELOPT_ECHO);
+	}
+
+	/*
+	 * Finally, to clean things up, we turn on our echo.  This
+	 * will break stupid 4.2 telnets out of local terminal echo.
+	 */
+
+	if (my_state_is_wont(TELOPT_ECHO))
+		send_will(TELOPT_ECHO, 1);
+
+#ifndef	STREAMSPTY
+	/*
+	 * Turn on packet mode
+	 */
+	(void) ioctl(p, TIOCPKT, (char *)&on);
+#endif
+
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+	/*
+	 * Continuing line mode support.  If client does not support
+	 * real linemode, attempt to negotiate kludge linemode by sending
+	 * the do timing mark sequence.
+	 */
+	if (lmodetype < REAL_LINEMODE)
+		send_do(TELOPT_TM, 1);
+#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+
+	/*
+	 * Call telrcv() once to pick up anything received during
+	 * terminal type negotiation, 4.2/4.3 determination, and
+	 * linemode negotiation.
+	 */
+	telrcv();
+
+	(void) ioctl(f, FIONBIO, (char *)&on);
+	(void) ioctl(p, FIONBIO, (char *)&on);
+#if	defined(CRAY2) && defined(UNICOS5)
+	init_termdriver(f, p, interrupt, sendbrk);
+#endif
+
+#if	defined(SO_OOBINLINE)
+	(void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
+				(char *)&on, sizeof(on));
+#endif	/* defined(SO_OOBINLINE) */
+
+#ifdef	SIGTSTP
+	(void) signal(SIGTSTP, SIG_IGN);
+#endif
+#ifdef	SIGTTOU
+	/*
+	 * Ignoring SIGTTOU keeps the kernel from blocking us
+	 * in ttioct() in /sys/tty.c.
+	 */
+	(void) signal(SIGTTOU, SIG_IGN);
+#endif
+
+	(void) signal(SIGCHLD, cleanup);
+
+#if	defined(CRAY2) && defined(UNICOS5)
+	/*
+	 * Cray-2 will send a signal when pty modes are changed by slave
+	 * side.  Set up signal handler now.
+	 */
+	if ((int)signal(SIGUSR1, termstat) < 0)
+		perror("signal");
+	else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
+		perror("ioctl:TCSIGME");
+	/*
+	 * Make processing loop check terminal characteristics early on.
+	 */
+	termstat();
+#endif
+
+#ifdef  TIOCNOTTY
+	{
+		register int t;
+		t = open(_PATH_TTY, O_RDWR);
+		if (t >= 0) {
+			(void) ioctl(t, TIOCNOTTY, (char *)0);
+			(void) close(t);
+		}
+	}
+#endif
+
+#if	defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
+	(void) setsid();
+	ioctl(p, TIOCSCTTY, 0);
+#endif
+
+	/*
+	 * Show banner that getty never gave.
+	 *
+	 * We put the banner in the pty input buffer.  This way, it
+	 * gets carriage return null processing, etc., just like all
+	 * other pty --> client data.
+	 */
+
+#if	!defined(CRAY) || !defined(NEWINIT)
+	if (getenv("USER"))
+		hostinfo = 0;
+#endif
+
+	if (getent(defent, "default") == 1) {
+		char *getstr();
+		char *cp=defstrs;
+
+		HE = getstr("he", &cp);
+		HN = getstr("hn", &cp);
+		IM = getstr("im", &cp);
+		if (HN && *HN) {
+			(void) strncpy(host_name, HN, sizeof(host_name) - 1);
+			host_name[sizeof(host_name) - 1] = '\0';
+		}
+		if (IM == 0)
+			IM = "";
+	} else {
+		IM = DEFAULT_IM;
+		HE = 0;
+	}
+	edithost(HE, host_name);
+	if (hostinfo && *IM)
+		putf(IM, ptyibuf2);
+
+	if (pcc)
+		(void) strncat(ptyibuf2, ptyip, pcc+1);
+	ptyip = ptyibuf2;
+	pcc = strlen(ptyip);
+#ifdef	LINEMODE
+	/*
+	 * Last check to make sure all our states are correct.
+	 */
+	init_termbuf();
+	localstat();
+#endif	/* LINEMODE */
+
+	DIAG(TD_REPORT,
+		{sprintf(nfrontp, "td: Entering processing loop\r\n");
+		 nfrontp += strlen(nfrontp);});
+
+#ifdef	convex
+	startslave(host);
+#endif
+
+	for (;;) {
+		fd_set ibits, obits, xbits;
+		register int c;
+
+		if (ncc < 0 && pcc < 0)
+			break;
+
+#if	defined(CRAY2) && defined(UNICOS5)
+		if (needtermstat)
+			_termstat();
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+		FD_ZERO(&ibits);
+		FD_ZERO(&obits);
+		FD_ZERO(&xbits);
+		/*
+		 * Never look for input if there's still
+		 * stuff in the corresponding output buffer
+		 */
+		if (nfrontp - nbackp || pcc > 0) {
+			FD_SET(f, &obits);
+		} else {
+			FD_SET(p, &ibits);
+		}
+		if (pfrontp - pbackp || ncc > 0) {
+			FD_SET(p, &obits);
+		} else {
+			FD_SET(f, &ibits);
+		}
+		if (!SYNCHing) {
+			FD_SET(f, &xbits);
+		}
+		if ((c = select(16, &ibits, &obits, &xbits,
+						(struct timeval *)0)) < 1) {
+			if (c == -1) {
+				if (errno == EINTR) {
+					continue;
+				}
+			}
+			sleep(5);
+			continue;
+		}
+
+		/*
+		 * Any urgent data?
+		 */
+		if (FD_ISSET(net, &xbits)) {
+		    SYNCHing = 1;
+		}
+
+		/*
+		 * Something to read from the network...
+		 */
+		if (FD_ISSET(net, &ibits)) {
+#if	!defined(SO_OOBINLINE)
+			/*
+			 * In 4.2 (and 4.3 beta) systems, the
+			 * OOB indication and data handling in the kernel
+			 * is such that if two separate TCP Urgent requests
+			 * come in, one byte of TCP data will be overlaid.
+			 * This is fatal for Telnet, but we try to live
+			 * with it.
+			 *
+			 * In addition, in 4.2 (and...), a special protocol
+			 * is needed to pick up the TCP Urgent data in
+			 * the correct sequence.
+			 *
+			 * What we do is:  if we think we are in urgent
+			 * mode, we look to see if we are "at the mark".
+			 * If we are, we do an OOB receive.  If we run
+			 * this twice, we will do the OOB receive twice,
+			 * but the second will fail, since the second
+			 * time we were "at the mark", but there wasn't
+			 * any data there (the kernel doesn't reset
+			 * "at the mark" until we do a normal read).
+			 * Once we've read the OOB data, we go ahead
+			 * and do normal reads.
+			 *
+			 * There is also another problem, which is that
+			 * since the OOB byte we read doesn't put us
+			 * out of OOB state, and since that byte is most
+			 * likely the TELNET DM (data mark), we would
+			 * stay in the TELNET SYNCH (SYNCHing) state.
+			 * So, clocks to the rescue.  If we've "just"
+			 * received a DM, then we test for the
+			 * presence of OOB data when the receive OOB
+			 * fails (and AFTER we did the normal mode read
+			 * to clear "at the mark").
+			 */
+		    if (SYNCHing) {
+			int atmark;
+
+			(void) ioctl(net, SIOCATMARK, (char *)&atmark);
+			if (atmark) {
+			    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
+			    if ((ncc == -1) && (errno == EINVAL)) {
+				ncc = read(net, netibuf, sizeof (netibuf));
+				if (sequenceIs(didnetreceive, gotDM)) {
+				    SYNCHing = stilloob(net);
+				}
+			    }
+			} else {
+			    ncc = read(net, netibuf, sizeof (netibuf));
+			}
+		    } else {
+			ncc = read(net, netibuf, sizeof (netibuf));
+		    }
+		    settimer(didnetreceive);
+#else	/* !defined(SO_OOBINLINE)) */
+		    ncc = read(net, netibuf, sizeof (netibuf));
+#endif	/* !defined(SO_OOBINLINE)) */
+		    if (ncc < 0 && errno == EWOULDBLOCK)
+			ncc = 0;
+		    else {
+			if (ncc <= 0) {
+			    break;
+			}
+			netip = netibuf;
+		    }
+		    DIAG((TD_REPORT | TD_NETDATA),
+			    {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
+			     nfrontp += strlen(nfrontp);});
+		    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
+		}
+
+		/*
+		 * Something to read from the pty...
+		 */
+		if (FD_ISSET(p, &ibits)) {
+#ifndef	STREAMSPTY
+			pcc = read(p, ptyibuf, BUFSIZ);
+#else
+			pcc = readstream(p, ptyibuf, BUFSIZ);
+#endif
+			/*
+			 * On some systems, if we try to read something
+			 * off the master side before the slave side is
+			 * opened, we get EIO.
+			 */
+			if (pcc < 0 && (errno == EWOULDBLOCK ||
+#ifdef	EAGAIN
+					errno == EAGAIN ||
+#endif
+					errno == EIO)) {
+				pcc = 0;
+			} else {
+				if (pcc <= 0)
+					break;
+#if	!defined(CRAY2) || !defined(UNICOS5)
+#ifdef	LINEMODE
+				/*
+				 * If ioctl from pty, pass it through net
+				 */
+				if (ptyibuf[0] & TIOCPKT_IOCTL) {
+					copy_termbuf(ptyibuf+1, pcc-1);
+					localstat();
+					pcc = 1;
+				}
+#endif	/* LINEMODE */
+				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
+					netclear();	/* clear buffer back */
+#ifndef	NO_URGENT
+					/*
+					 * There are client telnets on some
+					 * operating systems get screwed up
+					 * royally if we send them urgent
+					 * mode data.
+					 */
+					*nfrontp++ = IAC;
+					*nfrontp++ = DM;
+					neturg = nfrontp-1; /* off by one XXX */
+#endif
+				}
+				if (his_state_is_will(TELOPT_LFLOW) &&
+				    (ptyibuf[0] &
+				     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
+					int newflow =
+					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
+					if (newflow != flowmode) {
+						flowmode = newflow;
+						(void) sprintf(nfrontp,
+							"%c%c%c%c%c%c",
+							IAC, SB, TELOPT_LFLOW,
+							flowmode ? LFLOW_ON
+								 : LFLOW_OFF,
+							IAC, SE);
+						nfrontp += 6;
+					}
+				}
+				pcc--;
+				ptyip = ptyibuf+1;
+#else	/* defined(CRAY2) && defined(UNICOS5) */
+				if (!uselinemode) {
+					unpcc = pcc;
+					unptyip = ptyibuf;
+					pcc = term_output(&unptyip, ptyibuf2,
+								&unpcc, BUFSIZ);
+					ptyip = ptyibuf2;
+				} else
+					ptyip = ptyibuf;
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+			}
+		}
+
+		while (pcc > 0) {
+			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
+				break;
+			c = *ptyip++ & 0377, pcc--;
+			if (c == IAC)
+				*nfrontp++ = c;
+#if	defined(CRAY2) && defined(UNICOS5)
+			else if (c == '\n' &&
+				     my_state_is_wont(TELOPT_BINARY) && newmap)
+				*nfrontp++ = '\r';
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+			*nfrontp++ = c;
+			if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
+				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
+					*nfrontp++ = *ptyip++ & 0377;
+					pcc--;
+				} else
+					*nfrontp++ = '\0';
+			}
+		}
+#if	defined(CRAY2) && defined(UNICOS5)
+		/*
+		 * If chars were left over from the terminal driver,
+		 * note their existence.
+		 */
+		if (!uselinemode && unpcc) {
+			pcc = unpcc;
+			unpcc = 0;
+			ptyip = unptyip;
+		}
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+
+		if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
+			netflush();
+		if (ncc > 0)
+			telrcv();
+		if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
+			ptyflush();
+	}
+	cleanup(0);
+}  /* end of telnet */
+	
+#ifndef	TCSIG
+# ifdef	TIOCSIG
+#  define TCSIG TIOCSIG
+# endif
+#endif
+
+#ifdef	STREAMSPTY
+
+int flowison = -1;  /* current state of flow: -1 is unknown */
+
+int readstream(p, ibuf, bufsize)
+	int p;
+	char *ibuf;
+	int bufsize;
+{
+	int flags = 0;
+	int ret = 0;
+	struct termios *tsp;
+	struct termio *tp;
+	struct iocblk *ip;
+	char vstop, vstart;
+	int ixon;
+	int newflow;
+
+	strbufc.maxlen = BUFSIZ;
+	strbufc.buf = ctlbuf;
+	strbufd.maxlen = bufsize-1;
+	strbufd.len = 0;
+	strbufd.buf = ibuf+1;
+	ibuf[0] = 0;
+
+	ret = getmsg(p, &strbufc, &strbufd, &flags);
+	if (ret < 0)  /* error of some sort -- probably EAGAIN */
+		return(-1);
+
+	if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
+		/* data message */
+		if (strbufd.len > 0) {			/* real data */
+			return(strbufd.len + 1);	/* count header char */
+		} else {
+			/* nothing there */
+			errno = EAGAIN;
+			return(-1);
+		}
+	}
+
+	/*
+	 * It's a control message.  Return 1, to look at the flag we set
+	 */
+
+	switch (ctlbuf[0]) {
+	case M_FLUSH:
+		if (ibuf[1] & FLUSHW)
+			ibuf[0] = TIOCPKT_FLUSHWRITE;
+		return(1);
+
+	case M_IOCTL:
+		ip = (struct iocblk *) (ibuf+1);
+
+		switch (ip->ioc_cmd) {
+		case TCSETS:
+		case TCSETSW:
+		case TCSETSF:
+			tsp = (struct termios *)
+					(ibuf+1 + sizeof(struct iocblk));
+			vstop = tsp->c_cc[VSTOP];
+			vstart = tsp->c_cc[VSTART];
+			ixon = tsp->c_iflag & IXON;
+			break;
+		case TCSETA:
+		case TCSETAW:
+		case TCSETAF:
+			tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
+			vstop = tp->c_cc[VSTOP];
+			vstart = tp->c_cc[VSTART];
+			ixon = tp->c_iflag & IXON;      
+			break;
+		default:
+			errno = EAGAIN;
+			return(-1);
+		}
+
+		newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
+		if (newflow != flowison) {  /* it's a change */
+			flowison = newflow;
+			ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
+			return(1);
+		}
+	}
+
+	/* nothing worth doing anything about */
+	errno = EAGAIN;
+	return(-1);
+}
+#endif /* STREAMSPTY */
+
+/*
+ * Send interrupt to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write intr char.
+ */
+	void
+interrupt()
+{
+	ptyflush();	/* half-hearted */
+
+#ifdef	TCSIG
+	(void) ioctl(pty, TCSIG, (char *)SIGINT);
+#else	/* TCSIG */
+	init_termbuf();
+	*pfrontp++ = slctab[SLC_IP].sptr ?
+			(unsigned char)*slctab[SLC_IP].sptr : '\177';
+#endif	/* TCSIG */
+}
+
+/*
+ * Send quit to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write quit char.
+ */
+	void
+sendbrk()
+{
+	ptyflush();	/* half-hearted */
+#ifdef	TCSIG
+	(void) ioctl(pty, TCSIG, (char *)SIGQUIT);
+#else	/* TCSIG */
+	init_termbuf();
+	*pfrontp++ = slctab[SLC_ABORT].sptr ?
+			(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
+#endif	/* TCSIG */
+}
+
+	void
+sendsusp()
+{
+#ifdef	SIGTSTP
+	ptyflush();	/* half-hearted */
+# ifdef	TCSIG
+	(void) ioctl(pty, TCSIG, (char *)SIGTSTP);
+# else	/* TCSIG */
+	*pfrontp++ = slctab[SLC_SUSP].sptr ?
+			(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
+# endif	/* TCSIG */
+#endif	/* SIGTSTP */
+}
+
+/*
+ * When we get an AYT, if ^T is enabled, use that.  Otherwise,
+ * just send back "[Yes]".
+ */
+	void
+recv_ayt()
+{
+#if	defined(SIGINFO) && defined(TCSIG)
+	if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
+		(void) ioctl(pty, TCSIG, (char *)SIGINFO);
+		return;
+	}
+#endif
+	(void) strncpy(nfrontp, "\r\n[Yes]\r\n",
+		       sizeof(netobuf) - 1 - (nfrontp - netobuf));
+	nfrontp += 9;
+	*nfrontp = '\0';
+}
+
+	void
+doeof()
+{
+	init_termbuf();
+
+#if	defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
+	if (!tty_isediting()) {
+		extern char oldeofc;
+		*pfrontp++ = oldeofc;
+		return;
+	}
+#endif
+	*pfrontp++ = slctab[SLC_EOF].sptr ?
+			(unsigned char)*slctab[SLC_EOF].sptr : '\004';
+}
diff --git a/mechglue/src/appl/telnet/telnetd/telnetd.0.ps b/mechglue/src/appl/telnet/telnetd/telnetd.0.ps
new file mode 100644
index 000000000..bbbdbd002
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/telnetd.0.ps
@@ -0,0 +1,555 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Courier-Bold
+%%+ font Courier-Oblique
+%%+ font Courier
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 5
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll 
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Courier-Bold
+%%IncludeResource: font Courier-Oblique
+%%IncludeResource: font Courier
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Courier@0 ENC0/Courier RE
+/Courier-Oblique@0 ENC0/Courier-Oblique RE/Courier-Bold@0 ENC0/Courier-Bold RE
+/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNETD \( 8 \))72 48 R(BSD System Manager')
+241.42 48 Q 2.5(sM)-.55 G 105.272(anual TELNETD)348.92 48 R 1.666(\(8\))1.666 G
+/F1 10/Times-Bold@0 SF -.2(NA)72 108 S(ME).2 E/F2 10/Courier-Bold@0 SF(telnetd)
+102 120 Q F0 2.5<ad44>2.5 G(ARP)161.46 120 Q(A)-.92 E/F3 9/Times-Roman@0 SF
+(TELNET)2.5 E F0(protocol serv)2.5 E(er)-.15 E F1(SYNOPSIS)72 144 Q F2
+(/usr/libexec/telnetd)102 156 Q F0([)3.333 E F2<ad61>2.499 E/F4 10
+/Courier-Oblique@0 SF(authmode)6 E F0 3.333(][).833 G F2<ad42>-.834 E F0 3.333
+(][).833 G F2<ad44>-.834 E F4(debugmode)6 E F0 3.333(][).833 G F2(\255edebug)
+-.834 E F0 3.333(][).833 G F2<ad68>-.834 E F0(]).833 E([)228.833 168 Q F2<ad49>
+2.499 E F4(initid)A F0 3.333(][).833 G F2<ad6c>-.834 E F0 3.333(][).833 G F2
+<ad6b>-.834 E F0 3.333(][).833 G F2<ad6e>-.834 E F0 3.333(][).833 G F2<ad72>
+-.834 E F4(lowpty-highpty)A F0 3.333(][).833 G F2<ad73>-.834 E F0 3.333(][).833
+G F2<ad53>-.834 E F4(tos)228 180 Q F0 3.333(][).833 G F2<ad75>-.834 E F4(len)6
+E F0 3.333(][).833 G F2<ad55>-.834 E F0 3.333(][).833 G F2<ad58>-.834 E F4
+(authtype)6 E F0 3.333(][).833 G F2(\255debug)-.834 E F0([)6.833 E F4(port).833
+E F0 .833(]]).833 G F1(DESCRIPTION)72 204 Q F0(The)102 216 Q F2(telnetd)3.044 E
+F0 .544(command is a serv)3.044 F .544(er which supports the)-.15 F F3 -.36(DA)
+3.044 G(RP).36 E(A)-.828 E F0(standard)3.044 E F3(TELNET)3.044 E F0 .543
+(virtual terminal protocol.)3.044 F F2(Telnetd)102 228 Q F0 .221
+(is normally in)2.721 F -.2(vo)-.4 G -.1(ke).2 G 2.721(db).1 G 2.721(yt)234.184
+228 S .221(he internet serv)244.685 228 R .221(er \(see)-.15 F/F5 10/Courier@0
+SF(inetd)2.721 E F0 2.942(\(8\)\) for)B .221(requests to connect to the)2.721 F
+F3(TELNET)2.721 E F0 .673(port as indicated by the)102 240 R F5(/etc/services)
+3.173 E F0 .673(\214le \(see)3.173 F F5(services)3.173 E F0 3.846(\(5\)\). The)
+B F2(\255debug)4.839 E F0 .672(option may be used to)3.173 F .145(start up)102
+252 R F2(telnetd)2.645 E F0(manually)2.645 E 2.645(,i)-.65 G .145
+(nstead of through)223.65 252 R F5(inetd)2.645 E F0 2.79(\(8\). If)B .145
+(started up this w)2.645 F(ay)-.1 E(,)-.65 E F4(port)2.645 E F0 .145
+(may be speci\214ed to)2.645 F(run)102 264 Q F2(telnetd)2.5 E F0
+(on an alternate)2.5 E F3(TCP)2.5 E F0(port number)2.5 E(.)-.55 E(The)102 282 Q
+F2(telnetd)2.5 E F0(command accepts the follo)2.5 E(wing options:)-.25 E F2
+<ad61>103.666 300 Q F4(authmode)6 E F0 .106(This option may be used for specif\
+ying what mode should be used for authentication.)173 312 R(Note)5.106 E 2.778
+(that this option is only useful if)173 324 R F2(telnetd)5.279 E F0 2.779
+(has been compiled with support for the)5.279 F F5(AUTHENTICATION)173 336 Q F0
+2.5(option. There)2.5 F(are se)2.5 E -.15(ve)-.25 G(ral v).15 E(alid v)-.25 E
+(alues for)-.25 E F4(authmode:)2.5 E F0(deb)173 354 Q 8.26(ug T)-.2 F
+(urns on authentication deb)-.45 E(ugging code.)-.2 E 15.84(user Only)173 372 R
+(allo)2.923 E 2.923(wc)-.25 G .423(onnections when the remote user can pro)
+260.256 372 R .422(vide v)-.15 F .422(alid authentication in-)-.25 F 1.277
+(formation to identify the remote user)208 384 R 3.777(,a)-.4 G 1.277
+(nd is allo)372.181 384 R 1.277(wed access to the speci\214ed ac-)-.25 F
+(count without pro)208 396 Q(viding a passw)-.15 E(ord.)-.1 E -.25(va)173 414 S
+12.75(lid Only).25 F(allo)2.923 E 2.923(wc)-.25 G .423
+(onnections when the remote user can pro)260.256 414 R .422(vide v)-.15 F .422
+(alid authentication in-)-.25 F .742(formation to identify the remote user)208
+426 R 5.743(.T)-.55 G(he)372.995 426 Q F5(login)3.243 E F0 .743
+(\(1\) command will pro)B .743(vide an)-.15 F(y)-.15 E .53(additional user v)
+208 438 R .529(eri\214cation needed if the remote user is not allo)-.15 F .529
+(wed automatic ac-)-.25 F(cess to the speci\214ed account.)208 450 Q 11.95
+(other Only)173 468 R(allo)3.028 E 3.029(wc)-.25 G .529
+(onnections that supply some authentication information.)260.467 468 R .529
+(This option)5.529 F .079(is currently not supported by an)208 480 R 2.578(yo)
+-.15 G 2.578(ft)347.752 480 S .078(he e)356.44 480 R .078
+(xisting authentication mechanisms, and is)-.15 F(thus the same as specifying)
+208 492 Q F2 -3.5(\255a valid)4.166 F F0(.)A 13.06(none This)173 510 R .869
+(is the def)3.369 F .869(ault state.)-.1 F .869
+(Authentication information is not required.)5.869 F .87(If no or in-)5.869 F
+(suf)208 522 Q .394(\214cient authentication information is pro)-.25 F .393
+(vided, then the)-.15 F F5(login)2.893 E F0 .393(\(1\) program will)B(pro)208
+534 Q(vide the necessary user v)-.15 E(eri\214cation.)-.15 E(of)173 552 Q 23.59
+(fT)-.25 G 1.385(his disables the authentication code.)214.11 552 R 1.385
+(All user v)6.385 F 1.385(eri\214cation will happen through)-.15 F(the)208 564
+Q F5(login)2.5 E F0(\(1\) program.)A F2<ad42>103.666 582 Q F0 .82
+(Speci\214es bftp serv)173 582 R .82(er mode.)-.15 F .819(In this mode,)5.82 F
+F2(telnetd)3.319 E F0 .819(causes login to start a)3.319 F F5(bftp)3.319 E F0
+.819(\(1\) ses-)B .747(sion rather than the user')173 594 R 3.247(sn)-.55 G
+.747(ormal shell.)286.995 594 R .748
+(In bftp daemon mode normal logins are not sup-)5.747 F
+(ported, and it must be used on a port other than the normal)173 606 Q F3
+(TELNET)2.5 E F0(port.)2.5 E F2<ad44>103.666 624 Q F4(debugmode)6 E F0 .827
+(This option may be used for deb)173 636 R .827(ugging purposes.)-.2 F .827
+(This allo)5.827 F(ws)-.25 E F2(telnetd)3.327 E F0 .827(to print out de-)3.327
+F -.2(bu)173 648 S .827(gging information to the connection, allo).2 F .827
+(wing the user to see what)-.25 F F2(telnetd)3.327 E F0 .827(is doing.)3.327 F
+(There are se)173 660 Q -.15(ve)-.25 G(ral possible v).15 E(alues for)-.25 E F4
+(debugmode:)2.5 E F2(options)173 678 Q F0(Prints information about the ne)226
+678 Q(gotiation of)-.15 E F3(TELNET)2.5 E F0(options.)2.5 E(4.2 Berk)72 750 Q
+(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71(ution February)-.2 F
+(3, 1994)2.5 E(1)535 750 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNETD \( 8 \))72 48 R(BSD System Manager')
+241.42 48 Q 2.5(sM)-.55 G 105.272(anual TELNETD)348.92 48 R 1.666(\(8\))1.666 G
+/F1 10/Courier-Bold@0 SF(report)173 96 Q F0 2.438(Prints the)226 96 R F1
+(options)4.938 E F0 2.437(information, plus some additional information about)
+4.938 F(what processing is going on.)226 108 Q F1(netdata)173 126 Q F0
+(Displays the data stream recei)226 126 Q -.15(ve)-.25 G 2.5(db).15 G(y)367.51
+126 Q F1(telnetd.)2.5 E(ptydata)173 144 Q F0(Displays data written to the pty)
+226 144 Q(.)-.65 E F1(exercise)173 162 Q F0(Has not been implemented yet.)5 E
+F1(\255debug)103.666 180 Q F0(Enables deb)173 180 Q(ugging on each sock)-.2 E
+(et created by)-.1 E F1(telnetd)2.5 E F0(\(see)2.5 E/F2 10/Courier@0 SF
+(SO_DEBUG)2.5 E F0(in)2.5 E F2(socket)2.5 E F0(\(2\)\).)A F1(\255edebug)103.666
+198 Q F0(If)173 198 Q F1(telnetd)3.161 E F0 .662
+(has been compiled with support for data encryption, then the)3.161 F F1
+(\255edebug)4.828 E F0(op-)3.162 E(tion may be used to enable encryption deb)
+173 210 Q(ugging code.)-.2 E F1<ad68>103.666 228 Q F0(Disables the printing of\
+ host-speci\214c information before login has been completed.)173 228 Q F1
+<ad49>103.666 246 Q/F3 10/Courier-Oblique@0 SF(initid)7.171 E F0 1.171
+(This option is only applicable to)174.171 246 R/F4 9/Times-Roman@0 SF(UNICOS)
+3.671 E F0 1.171(systems prior to 7.0.)3.671 F 1.17(It speci\214es the)6.171 F
+F2(ID)3.67 E F0(from)3.67 E F2(/etc/inittab)173 258 Q F0
+(to use when init starts login sessions.)2.5 E(The def)5 E(ault)-.1 E F2(ID)2.5
+E F0(is)2.5 E F2(fe.)2.5 E F1<ad6b>103.666 276 Q F0 .556
+(This option is only useful if)173 276 R F1(telnetd)3.056 E F0 .557
+(has been compiled with both linemode and kludge)3.056 F .521
+(linemode support.)173 288 R .521(If the)5.521 F F1<ad6b>4.687 E F0 .52
+(option is speci\214ed, then if the remote client does not support)3.02 F(the)
+173 300 Q F2(LINEMODE)3.697 E F0 1.197(option, then)3.697 F F1(telnetd)3.697 E
+F0 1.197(will operate in character at a time mode.)3.697 F 1.198(It will)6.198
+F .148(still support kludge linemode, b)173 312 R .147
+(ut will only go into kludge linemode if the remote client re-)-.2 F 2.06
+(quests it.)173 324 R 2.061(\(This is done by by the client sending)7.06 F F2
+2.061(DONT SUPPRESS-GO-AHEAD)4.561 F F0(and)4.561 E F2 .1(DONT ECHO)173 336 R
+F0 .1(.\) The)B F1<ad6b>4.266 E F0 .1
+(option is most useful when there are remote clients that do not sup-)2.6 F .67
+(port kludge linemode, b)173 348 R .67(ut pass the heuristic \(if the)-.2 F
+3.17(yr)-.15 G .67(espond with)390.88 348 R F2 .67(WILL TIMING-MARK)3.17 F F0
+(in response to a)173 360 Q F2(DO TIMING-MARK\))2.5 E F0
+(for kludge linemode support.)2.5 E F1<ad6c>103.666 378 Q F0 .672
+(Speci\214es line mode.)173 378 R -.35(Tr)5.672 G .671
+(ies to force clients to use line- at-a-time mode.).35 F .671(If the)5.671 F F2
+(LINEMODE)3.171 E F0(option is not supported, it will go into kludge linemode.)
+173 390 Q F1<ad6e>103.666 408 Q F0(Disable)173 408 Q F2(TCP)3.488 E F0 -.1(ke)
+3.488 G(ep-ali).1 E -.15(ve)-.25 G 3.488(s. Normally).15 F F1(telnetd)3.488 E
+F0 .988(enables the)3.488 F F4(TCP)3.489 E F0 -.1(ke)3.489 G(ep-ali).1 E 1.289
+-.15(ve m)-.25 H .989(echanism to).15 F .602(probe connections that ha)173 420
+R .902 -.15(ve b)-.2 H .602
+(een idle for some period of time to determine if the client is).15 F 1.124
+(still there, so that idle connections from machines that ha)173 432 R 1.424
+-.15(ve c)-.2 H 1.124(rashed or can no longer be).15 F
+(reached may be cleaned up.)173 444 Q F1<ad72>103.666 462 Q F3(lowpty-highpty)6
+E F0 .772(This option is only enabled when)173 474 R F1(telnetd)3.272 E F0 .771
+(is compiled for)3.271 F F2(UNICOS.)3.271 E F0 .771(It speci\214es an in-)3.271
+F(clusi)173 486 Q 3.232 -.15(ve r)-.25 H 2.932(ange of pseudo-terminal de).15 F
+2.932(vices to use.)-.25 F 2.933(If the system has sysconf v)7.933 F(ariable)
+-.25 E F2(_SC_CRAY_NPTY)173 498 Q F0 1.486(con\214gured, the def)3.986 F 1.486
+(ault pty search range is 0 to)-.1 F F2(_SC_CRAY_NPTY;)3.986 E F0 .72
+(otherwise, the def)173 510 R .72(ault range is 0 to 128.)-.1 F(Either)5.72 E
+F3(lowpty)3.22 E F0(or)3.22 E F3(highpty)3.22 E F0 .72(may be omitted to)3.22 F
+(allo)173 522 Q 2.6(wc)-.25 G .1(hanging either end of the search range.)202.01
+522 R(If)5.1 E F3(lowpty)2.6 E F0 .1(is omitted, the - character is still)2.6 F
+(required so that)173 534 Q F1(telnetd)2.5 E F0(can dif)2.5 E(ferentiate)-.25 E
+F3(highpty)2.5 E F0(from)2.5 E F3(lowpty)2.5 E F0(.)A F1<ad73>103.666 552 Q F0
+1.391(This option is only enabled if)173 552 R F1(telnetd)3.891 E F0 1.391
+(is compiled with support for)3.891 F F4(SecurID)3.891 E F0 3.891(cards. It)
+3.891 F .787(causes the)173 564 R F1<ad73>4.953 E F0 .786
+(option to be passed on to)3.286 F F2(login)3.286 E F0 4.072(\(1\), and)B .786
+(thus is only useful if)3.286 F F2(login)3.286 E F0(\(1\))A .48(supports the)
+173 576 R F1<ad73>4.646 E F0 .48(\215ag to indicate that only)2.98 F F4
+(SecurID)2.98 E F0 -.25(va)2.98 G .481(lidated logins are allo).25 F .481
+(wed, and is usu-)-.25 F
+(ally useful for controlling remote logins from outside of a \214re)173 588 Q
+-.1(wa)-.25 G(ll.).1 E F1<ad53>103.666 606 Q F3(tos)6 E F1<ad75>103.666 624 Q
+F3(len)6.628 E F0 .628
+(This option is used to specify the size of the \214eld in the)173.628 624 R F2
+(utmp)3.127 E F0 .627(structure that holds the re-)3.127 F 1(mote host name.)
+173 636 R 1(If the resolv)6 F 1(ed host name is longer than)-.15 F F3(len)3.5 E
+F0 3.5(,t)C 1(he dotted decimal v)441.99 636 R(alue)-.25 E .046
+(will be used instead.)173 648 R .046(This allo)5.046 F .046(ws hosts with v)
+-.25 F .045(ery long host names that o)-.15 F -.15(ve)-.15 G(r\215o).15 E 2.545
+(wt)-.25 G .045(his \214eld to)497.68 648 R .996
+(still be uniquely identi\214ed.)173 660 R(Specifying)5.997 E F1(\255u0)5.163 E
+F0 .997(indicates that only dotted decimal addresses)3.497 F
+(should be put into the)173 672 Q F2(utmp)2.5 E F0(\214le.)2.5 E F1<ad55>
+103.666 690 Q F0 .422(This option causes)173 690 R F1(telnetd)2.922 E F0 .422
+(to refuse connections from addresses that cannot be mapped)2.922 F(4.2 Berk)72
+750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71(ution February)-.2 F
+(3, 1994)2.5 E(2)535 750 Q EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNETD \( 8 \))72 48 R(BSD System Manager')
+241.42 48 Q 2.5(sM)-.55 G 105.272(anual TELNETD)348.92 48 R 1.666(\(8\))1.666 G
+(back into a symbolic name via the)173 96 Q/F1 10/Courier@0 SF(gethostbyaddr)
+2.5 E F0(\(3\) routine.)A/F2 10/Courier-Bold@0 SF<ad58>103.666 114 Q/F3 10
+/Courier-Oblique@0 SF(authtype)6 E F0 .123(This option is only v)173 126 R .123
+(alid if)-.25 F F2(telnetd)2.623 E F0 .123(has been b)2.623 F .124
+(uilt with support for the authentication op-)-.2 F 2.968(tion. It)173 138 R
+.467(disables the use of)2.968 F F3(authtype)2.967 E F0 .467
+(authentication, and can be used to temporarily dis-)2.967 F
+(able a speci\214c authentication type without ha)173 150 Q(ving to recompile)
+-.2 E F2(telnetd)2.5 E F0(.)A F2(Telnetd)102 168 Q F0 .851
+(operates by allocating a pseudo-terminal de)3.351 F .851(vice \(see)-.25 F F1
+(pty)3.351 E F0 4.202(\(4\)\) for)B 3.351(ac)3.351 G .852
+(lient, then creating a login)431.882 168 R .757(process which has the sla)102
+180 R 1.057 -.15(ve s)-.2 H .757(ide of the pseudo-terminal as).15 F F1(stdin)
+3.257 E F0(,)A F1(stdout)3.256 E F0(and)3.256 E F1(stderr)3.256 E F0(.)A F2
+(Telnetd)3.256 E F0(ma-)3.256 E .483
+(nipulates the master side of the pseudo-terminal, implementing the)102 192 R
+/F4 9/Times-Roman@0 SF(TELNET)2.984 E F0 .484(protocol and passing characters)
+2.984 F(between the remote client and the login process.)102 204 Q .538(When a)
+102 222 R F4(TELNET)3.038 E F0 .538(session is started up,)3.038 F F2(telnetd)
+3.038 E F0(sends)3.038 E F4(TELNET)3.038 E F0 .538
+(options to the client side indicating a will-)3.038 F(ingness to do the follo)
+102 234 Q(wing)-.25 E F4(TELNET)2.5 E F0
+(options, which are described in more detail belo)2.5 E(w:)-.25 E F1
+(DO AUTHENTICATION)132 252 Q(WILL ENCRYPT)132 264 Q(DO TERMINAL TYPE)132 276 Q
+(DO TSPEED)132 288 Q(DO XDISPLOC)132 300 Q(DO NEW-ENVIRON)132 312 Q(DO ENVIRON)
+132 324 Q(WILL SUPPRESS GO AHEAD)132 336 Q(DO ECHO)132 348 Q(DO LINEMODE)132
+360 Q(DO NAWS)132 372 Q(WILL STATUS)132 384 Q(DO LFLOW)132 396 Q
+(DO TIMING-MARK)132 408 Q F0 .468(The pseudo-terminal allocated to the client \
+is con\214gured to operate in cook)102 426 R .468(ed mode, and with)-.1 F F1
+.469(XTABS and)2.969 F(CRMOD)102 438 Q F0(enabled \(see)2.5 E F1(tty)2.5 E F0
+(\(4\)\).)A F2(Telnetd)102 456 Q F0(has support for enabling locally the follo)
+2.5 E(wing)-.25 E F4(TELNET)2.5 E F0(options:)2.5 E .558(WILL ECHO)102 474 R
+.558(When the)209.558 474 R F1(LINEMODE)3.057 E F0 .557(option is enabled, a)
+3.057 F F1 .557(WILL ECHO)3.057 F F0(or)3.057 E F1 .557(WONT ECHO)3.057 F F0
+.557(will be)3.057 F .487
+(sent to the client to indicate the current state of terminal echoing.)209 486
+R .487(When terminal)5.487 F .409(echo is not desired, a)209 498 R F1 .408
+(WILL ECHO)2.908 F F0 .408(is sent to indicate that)2.908 F F4(telnetd)2.908 E
+F0 .408(will tak)2.908 F 2.908(ec)-.1 G .408(are of)516.552 498 R 1.811
+(echoing an)209 510 R 4.311(yd)-.15 G 1.811
+(ata that needs to be echoed to the terminal, and then nothing is)268.572 510 R
+3.876(echoed. When)209 522 R 1.376(terminal echo is desired, a)3.876 F F1 1.375
+(WONT ECHO)3.875 F F0 1.375(is sent to indicate that)3.875 F F4(telnetd)209 534
+Q F0 .11(will not be doing an)2.61 F 2.61(yt)-.15 G .11
+(erminal echoing, so the client should do an)326.788 534 R 2.611(yt)-.15 G
+(erminal)509.45 534 Q(echoing that is needed.)209 546 Q .243(WILL BIN)102 564 R
+(AR)-.35 E 42.18(YI)-.65 G .243(ndicates that the client is willing to send a \
+8 bits of data, rather than the normal 7)212.573 564 R(bits of the Netw)209 576
+Q(ork V)-.1 E(irtual T)-.6 E(erminal.)-.7 E(WILL SGA)102 594 Q
+(Indicates that it will not be sending)209 594 Q F1(IAC GA,)2.5 E F0
+(go ahead, commands.)2.5 E .366(WILL ST)102 612 R -1.11(AT)-.93 G 41.27
+(US Indicates)1.11 F 2.866(aw)2.866 G .366
+(illingness to send the client, upon request, of the current status of all)
+262.858 612 R F4(TELNET)209 624 Q F0(options.)2.5 E .51(WILL TIMING-MARK)102
+642 R(Whene)209.51 642 Q -.15(ve)-.25 G 3.01(ra).15 G F1 .509(DO TIMING-MARK)
+-.001 F F0 .509(command is recei)3.009 F -.15(ve)-.25 G .509(d, it is al).15 F
+-.1(wa)-.1 G .509(ys responded to).1 F(with a)209 654 Q F1(WILL TIMING-MARK)2.5
+E F0 .726(WILL LOGOUT)102 672 R .726(When a)209.726 672 R F1 .726(DO LOGOUT)
+3.226 F F0 .726(is recei)3.226 F -.15(ve)-.25 G .726(d, a).15 F F1 .726
+(WILL LOGOUT)3.226 F F0 .726(is sent in response, and the)3.226 F(4.2 Berk)72
+750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71(ution February)-.2 F
+(3, 1994)2.5 E(3)535 750 Q EP
+%%Page: 4 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNETD \( 8 \))72 48 R(BSD System Manager')
+241.42 48 Q 2.5(sM)-.55 G 105.272(anual TELNETD)348.92 48 R 1.666(\(8\))1.666 G
+/F1 9/Times-Roman@0 SF(TELNET)209 96 Q F0(session is shut do)2.5 E(wn.)-.25 E
+.118(WILL ENCR)102 114 R 32.1(YPT Only)-.65 F .118(sent if)2.618 F/F2 10
+/Courier-Bold@0 SF(telnetd)2.618 E F0 .118
+(is compiled with support for data encryption, and indicates)2.618 F 2.5(aw)209
+126 S(illingness to decrypt the data stream.)223.16 126 Q F2(Telnetd)102 144 Q
+F0(has support for enabling remotely the follo)2.5 E(wing)-.25 E F1(TELNET)2.5
+E F0(options:)2.5 E(DO BIN)102 162 Q(AR)-.35 E 52.73(YS)-.65 G
+(ent to indicate that)214.56 162 Q F1(telnetd)2.5 E F0(is willing to recei)2.5
+E .3 -.15(ve a)-.25 H 2.5(n8b).15 G(it data stream.)423.918 162 Q(DO LFLO)102
+180 Q 55.97(WR)-.35 G(equests that the client handle \215o)215.67 180 Q 2.5(wc)
+-.25 G(ontrol characters remotely)358.18 180 Q(.)-.65 E .967(DO ECHO)102 198 R
+.967(This is not really supported, b)209.967 198 R .967
+(ut is sent to identify a 4.2BSD)-.2 F/F3 10/Courier@0 SF(telnet)3.468 E F0
+.968(\(1\) client,)B .365(which will improperly respond with)209 210 R F3 .365
+(WILL ECHO.)2.865 F F0 .365(If a)2.865 F F3 .365(WILL ECHO)2.865 F F0 .365
+(is recei)2.865 F -.15(ve)-.25 G(d,).15 E(a)209 222 Q F3(DONT ECHO)2.5 E F0
+(will be sent in response.)2.5 E .445(DO TERMIN)102 240 R 7.92
+(AL-TYPE Indicates)-.35 F 2.945(ad)2.945 G .445
+(esire to be able to request the name of the type of terminal that is at-)
+260.875 240 R(tached to the client side of the connection.)209 252 Q(DO SGA)102
+270 Q(Indicates that it does not need to recei)209 270 Q -.15(ve)-.25 G F3
+(IAC GA,)2.65 E F0(the go ahead command.)2.5 E .006(DO N)102 288 R -.9(AW)-.35
+G 61.87(SR).9 G .006(equests that the client inform the serv)215.676 288 R .005
+(er when the windo)-.15 F 2.505(w\()-.25 G .005(display\) size changes.)452.51
+288 R(DO TERMIN)102 306 Q(AL-SPEED)-.35 E 1.029(Indicates a desire to be able \
+to request information about the speed of the serial)209 318 R
+(line to which the client is attached.)209 330 Q .469(DO XDISPLOC)102 348 R
+.469(Indicates a desire to be able to request the name of the X windo)209.469
+348 R .468(ws display that is)-.25 F(associated with the telnet client.)209 360
+Q 1.008(DO NEW)102 378 R(-ENVIR)-.65 E 17.52(ON Indicates)-.4 F 3.508(ad)3.508
+G 1.008(esire to be able to request en)262.564 378 R 1.009(vironment v)-.4 F
+1.009(ariable information, as de-)-.25 F(scribed in RFC 1572.)209 390 Q 1.009
+(DO ENVIR)102 408 R 42.97(ON Indicates)-.4 F 3.509(ad)3.509 G 1.009
+(esire to be able to request en)262.567 408 R 1.008(vironment v)-.4 F 1.008
+(ariable information, as de-)-.25 F(scribed in RFC 1408.)209 420 Q .886
+(DO LINEMODE)102 438 R .886(Only sent if)209.886 438 R F2(telnetd)3.386 E F0
+.886(is compiled with support for linemode, and requests that)3.386 F
+(the client do line by line processing.)209 450 Q 1.292(DO TIMING-MARK)102 468
+R 1.292(Only sent if)210.292 468 R F2(telnetd)3.792 E F0 1.291
+(is compiled with support for both linemode and kludge)3.792 F 2.029
+(linemode, and the client responded with)209 480 R F3 2.029(WONT LINEMODE.)
+4.529 F F0 2.029(If the client re-)4.529 F 3.375(sponds with)209 492 R F3 3.375
+(WILL TM,)5.875 F F0 3.375(the it is assumed that the client supports kludge)
+5.875 F 2.5(linemode. Note)209 504 R(that the)2.5 E([)3.333 E F2<ad6b>2.499 E
+F0 2.5(]o).833 G(ption can be used to disable this.)338.205 504 Q(DO A)102 522
+Q(UTHENTICA)-.55 E(TION)-1.11 E .618(Only sent if)209 534 R F2(telnetd)3.118 E
+F0 .618(is compiled with support for authentication, and indicates)3.118 F 2.5
+(aw)209 546 S(illingness to recei)223.16 546 Q .3 -.15(ve a)-.25 H
+(uthentication information for automatic login.).15 E .118(DO ENCR)102 564 R
+42.65(YPT Only)-.65 F .118(sent if)2.618 F F2(telnetd)2.618 E F0 .118
+(is compiled with support for data encryption, and indicates)2.618 F 2.5(aw)209
+576 S(illingness to decrypt the data stream.)223.16 576 Q/F4 10/Times-Bold@0 SF
+(ENVIR)72 600 Q(ONMENT)-.3 E(FILES)72 612 Q F3(/etc/services)102 624 Q
+(/etc/inittab)102 636 Q F0(\(UNICOS systems only\))2.5 E F3(/etc/iptos)102 648
+Q F0(\(if supported\))2.5 E F3(/usr/ucb/bftp)102 660 Q F0(\(if supported\))2.5
+E(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71
+(ution February)-.2 F(3, 1994)2.5 E(4)535 750 Q EP
+%%Page: 5 5
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF -.834(TELNETD \( 8 \))72 48 R(BSD System Manager')
+241.42 48 Q 2.5(sM)-.55 G 105.272(anual TELNETD)348.92 48 R 1.666(\(8\))1.666 G
+/F1 10/Times-Bold@0 SF(SEE ALSO)72 96 Q/F2 10/Courier@0 SF(telnet)102 108 Q F0
+(\(1\),)A F2(login)5 E F0(\(1\),)A F2(bftp)5 E F0(\(1\) \(if supported\))A F1
+(ST)72 132 Q(AND)-.9 E(ARDS)-.35 E/F3 10/Courier-Bold@0 SF(RFC-854)102 144 Q/F4
+9/Times-Roman@0 SF(TELNET)155 144 Q F0(PR)2.5 E -1.88 -.4(OT O)-.4 H
+(COL SPECIFICA).4 E(TION)-1.11 E F3(RFC-855)102 156 Q F0
+(TELNET OPTION SPECIFICA)155 156 Q(TIONS)-1.11 E F3(RFC-856)102 168 Q F0
+(TELNET BIN)155 168 Q(AR)-.35 E 2.5(YT)-.65 G(RANSMISSION)241.21 168 Q F3
+(RFC-857)102 180 Q F0(TELNET ECHO OPTION)155 180 Q F3(RFC-858)102 192 Q F0
+(TELNET SUPPRESS GO AHEAD OPTION)155 192 Q F3(RFC-859)102 204 Q F0(TELNET ST)
+155 204 Q -1.11(AT)-.93 G(US OPTION)1.11 E F3(RFC-860)102 216 Q F0
+(TELNET TIMING MARK OPTION)155 216 Q F3(RFC-861)102 228 Q F0
+(TELNET EXTENDED OPTIONS - LIST OPTION)155 228 Q F3(RFC-885)102 240 Q F0
+(TELNET END OF RECORD OPTION)155 240 Q F3(RFC-1073)102 252 Q F0 -.7(Te)5 G
+(lnet W).7 E(indo)-.4 E 2.5(wS)-.25 G(ize Option)224.2 252 Q F3(RFC-1079)102
+264 Q F0 -.7(Te)5 G(lnet T).7 E(erminal Speed Option)-.7 E F3(RFC-1091)102 276
+Q F0 -.7(Te)5 G(lnet T).7 E(erminal-T)-.7 E(ype Option)-.8 E F3(RFC-1096)102
+288 Q F0 -.7(Te)5 G(lnet X Display Location Option).7 E F3(RFC-1123)102 300 Q
+F0(Requirements for Internet Hosts -- Application and Support)5 E F3(RFC-1184)
+102 312 Q F0 -.7(Te)5 G(lnet Linemode Option).7 E F3(RFC-1372)102 324 Q F0 -.7
+(Te)5 G(lnet Remote Flo).7 E 2.5(wC)-.25 G(ontrol Option)245.44 324 Q F3
+(RFC-1416)102 336 Q F0 -.7(Te)5 G(lnet Authentication Option).7 E F3(RFC-1411)
+102 348 Q F0 -.7(Te)5 G(lnet Authentication: K).7 E(erberos V)-.25 E(ersion 4)
+-1.11 E F3(RFC-1412)102 360 Q F0 -.7(Te)5 G(lnet Authentication: SPX).7 E F3
+(RFC-1571)102 372 Q F0 -.7(Te)5 G(lnet En).7 E
+(vironment Option Interoperability Issues)-.4 E F3(RFC-1572)102 384 Q F0 -.7
+(Te)5 G(lnet En).7 E(vironment Option)-.4 E F1 -.1(BU)72 408 S(GS).1 E F0(Some)
+102 420 Q F4(TELNET)2.5 E F0(commands are only partially implemented.)2.5 E
+.082(Because of b)102 438 R .082(ugs in the original 4.2 BSD)-.2 F F2(telnet)
+2.582 E F0(\(1\),)A F3(telnetd)5.164 E F0 .082
+(performs some dubious protocol e)2.582 F(xchanges)-.15 E(to try to disco)102
+450 Q -.15(ve)-.15 G 2.5(ri).15 G 2.5(ft)175.03 450 S
+(he remote client is, in f)183.64 450 Q(act, a 4.2 BSD)-.1 E F2(telnet)2.5 E F0
+(\(1\).)A(Binary mode has no common interpretation e)102 468 Q
+(xcept between similar operating systems \(Unix in this case\).)-.15 E
+(The terminal type name recei)102 486 Q -.15(ve)-.25 G 2.5(df).15 G
+(rom the remote client is con)239.06 486 Q -.15(ve)-.4 G(rted to lo).15 E
+(wer case.)-.25 E F3(Telnetd)102 504 Q F0(ne)2.5 E -.15(ve)-.25 G 2.5(rs).15 G
+(ends)174.7 504 Q F4(TELNET)2.5 E F2(IAC GA)2.5 E F0(\(go ahead\) commands.)2.5
+E(4.2 Berk)72 750 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 750 Q 95.71
+(ution February)-.2 F(3, 1994)2.5 E(5)535 750 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/mechglue/src/appl/telnet/telnetd/telnetd.0.txt b/mechglue/src/appl/telnet/telnetd/telnetd.0.txt
new file mode 100644
index 000000000..f13b6994c
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/telnetd.0.txt
@@ -0,0 +1,322 @@
+TELNETD(8)                BSD System Manager's Manual               TELNETD(8)
+
+NNAAMMEE
+     tteellnneettdd - DARPA TELNET protocol server
+
+SSYYNNOOPPSSIISS
+     //uussrr//lliibbeexxeecc//tteellnneettdd [--aa _a_u_t_h_m_o_d_e] [--BB] [--DD _d_e_b_u_g_m_o_d_e] [--eeddeebbuugg] [--hh]
+                          [--II_i_n_i_t_i_d] [--ll] [--kk] [--nn] [--rr_l_o_w_p_t_y_-_h_i_g_h_p_t_y] [--ss]
+                          [--SS _t_o_s] [--uu _l_e_n] [--UU] [--XX _a_u_t_h_t_y_p_e] [--ddeebbuugg [_p_o_r_t]]
+
+DDEESSCCRRIIPPTTIIOONN
+     The tteellnneettdd command is a server which supports the DARPA standard TELNET
+     virtual terminal protocol.  TTeellnneettdd is normally invoked by the internet
+     server (see inetd(8))  for requests to connect to the TELNET port as in-
+     dicated by the _/_e_t_c_/_s_e_r_v_i_c_e_s file (see services(5)).  The --ddeebbuugg option
+     may be used to start up tteellnneettdd manually, instead of through inetd(8).
+     If started up this way, _p_o_r_t may be specified to run tteellnneettdd on an alter-
+     nate TCP port number.
+
+     The tteellnneettdd command accepts the following options:
+
+     --aa _a_u_t_h_m_o_d_e  This option may be used for specifying what mode should be
+                  used for authentication.  Note that this option is only use-
+                  ful if tteellnneettdd has been compiled with support for the
+                  AUTHENTICATION option.  There are several valid values for
+                  _a_u_t_h_m_o_d_e_:
+
+                  debug  Turns on authentication debugging code.
+
+                  user   Only allow connections when the remote user can pro-
+                         vide valid authentication information to identify the
+                         remote user, and is allowed access to the specified
+                         account without providing a password.
+
+                  valid  Only allow connections when the remote user can pro-
+                         vide valid authentication information to identify the
+                         remote user.  The login(1) command will provide any
+                         additional user verification needed if the remote us-
+                         er is not allowed automatic access to the specified
+                         account.
+
+                  other  Only allow connections that supply some authentica-
+                         tion information.  This option is currently not sup-
+                         ported by any of the existing authentication mecha-
+                         nisms, and is thus the same as specifying --aa vvaalliidd.
+
+                  none   This is the default state.  Authentication informa-
+                         tion is not required.  If no or insufficient authen-
+                         tication information is provided, then the login(1)
+                         program will provide the necessary user verification.
+
+                  off    This disables the authentication code.  All user ver-
+                         ification will happen through the login(1) program.
+
+     --BB           Specifies bftp server mode.  In this mode, tteellnneettdd causes
+                  login to start a bftp(1) session rather than the user's nor-
+                  mal shell.  In bftp daemon mode normal logins are not sup-
+                  ported, and it must be used on a port other than the normal
+                  TELNET port.
+
+     --DD _d_e_b_u_g_m_o_d_e
+                  This option may be used for debugging purposes.  This allows
+                  tteellnneettdd to print out debugging information to the connec-
+                  tion, allowing the user to see what tteellnneettdd is doing.  There
+
+                  are several possible values for _d_e_b_u_g_m_o_d_e_:
+
+                  ooppttiioonnss   Prints information about the negotiation of TELNET
+                            options.
+
+                  rreeppoorrtt    Prints the ooppttiioonnss information, plus some addi-
+                            tional information about what processing is going
+                            on.
+
+                  nneettddaattaa   Displays the data stream received by tteellnneettdd..
+
+                  ppttyyddaattaa   Displays data written to the pty.
+
+                  eexxeerrcciissee  Has not been implemented yet.
+
+     --ddeebbuugg       Enables debugging on each socket created by tteellnneettdd (see
+                  SO_DEBUG in socket(2)).
+
+     --eeddeebbuugg      If tteellnneettdd has been compiled with support for data encryp-
+                  tion, then the --eeddeebbuugg option may be used to enable encryp-
+                  tion debugging code.
+
+     --hh           Disables the printing of host-specific information before
+                  login has been completed.
+
+     --II _i_n_i_t_i_d    This option is only applicable to UNICOS systems prior to
+                  7.0.  It specifies the ID from _/_e_t_c_/_i_n_i_t_t_a_b to use when init
+                  starts login sessions.  The default ID is fe.
+
+     --kk           This option is only useful if tteellnneettdd has been compiled with
+                  both linemode and kludge linemode support.  If the --kk option
+                  is specified, then if the remote client does not support the
+                  LINEMODE option, then tteellnneettdd will operate in character at a
+                  time mode.  It will still support kludge linemode, but will
+                  only go into kludge linemode if the remote client requests
+                  it.  (This is done by by the client sending DONT SUPPRESS-
+                  GO-AHEAD and DONT ECHO.) The --kk option is most useful when
+                  there are remote clients that do not support kludge
+                  linemode, but pass the heuristic (if they respond with WILL
+                  TIMING-MARK in response to a DO TIMING-MARK) for kludge
+                  linemode support.
+
+     --ll           Specifies line mode.  Tries to force clients to use line-
+                  at-a-time mode.  If the LINEMODE option is not supported, it
+                  will go into kludge linemode.
+
+     --nn           Disable TCP keep-alives.  Normally tteellnneettdd enables the TCP
+                  keep-alive mechanism to probe connections that have been
+                  idle for some period of time to determine if the client is
+                  still there, so that idle connections from machines that
+                  have crashed or can no longer be reached may be cleaned up.
+
+     --rr _l_o_w_p_t_y_-_h_i_g_h_p_t_y
+                  This option is only enabled when tteellnneettdd is compiled for
+                  UNICOS. It specifies an inclusive range of pseudo-terminal
+                  devices to use.  If the system has sysconf variable
+                  _SC_CRAY_NPTY configured, the default pty search range is 0
+                  to _SC_CRAY_NPTY; otherwise, the default range is 0 to 128.
+                  Either _l_o_w_p_t_y or _h_i_g_h_p_t_y may be omitted to allow changing
+                  either end of the search range.  If _l_o_w_p_t_y is omitted, the -
+                  character is still required so that tteellnneettdd can differenti-
+                  ate _h_i_g_h_p_t_y from _l_o_w_p_t_y.
+
+     --ss           This option is only enabled if tteellnneettdd is compiled with sup-
+                  port for SecurID cards.  It causes the --ss option to be
+                  passed on to login(1),  and thus is only useful if login(1)
+                  supports the --ss flag to indicate that only SecurID validated
+                  logins are allowed, and is usually useful for controlling
+                  remote logins from outside of a firewall.
+
+     --SS _t_o_s
+
+     --uu _l_e_n       This option is used to specify the size of the field in the
+                  utmp structure that holds the remote host name.  If the re-
+                  solved host name is longer than _l_e_n, the dotted decimal val-
+                  ue will be used instead.  This allows hosts with very long
+                  host names that overflow this field to still be uniquely
+                  identified.  Specifying --uu00 indicates that only dotted deci-
+                  mal addresses should be put into the _u_t_m_p file.
+
+     --UU           This option causes tteellnneettdd to refuse connections from ad-
+                  dresses that cannot be mapped back into a symbolic name via
+                  the gethostbyaddr(3) routine.
+
+     --XX _a_u_t_h_t_y_p_e  This option is only valid if tteellnneettdd has been built with
+                  support for the authentication option.  It disables the use
+                  of _a_u_t_h_t_y_p_e authentication, and can be used to temporarily
+                  disable a specific authentication type without having to re-
+                  compile tteellnneettdd.
+
+     TTeellnneettdd operates by allocating a pseudo-terminal device (see pty(4))  for
+     a client, then creating a login process which has the slave side of the
+     pseudo-terminal as stdin, stdout and stderr. TTeellnneettdd manipulates the mas-
+     ter side of the pseudo-terminal, implementing the TELNET protocol and
+     passing characters between the remote client and the login process.
+
+     When a TELNET session is started up, tteellnneettdd sends TELNET options to the
+     client side indicating a willingness to do the following TELNET options,
+     which are described in more detail below:
+
+           DO AUTHENTICATION
+           WILL ENCRYPT
+           DO TERMINAL TYPE
+           DO TSPEED
+           DO XDISPLOC
+           DO NEW-ENVIRON
+           DO ENVIRON
+           WILL SUPPRESS GO AHEAD
+           DO ECHO
+           DO LINEMODE
+           DO NAWS
+           WILL STATUS
+           DO LFLOW
+           DO TIMING-MARK
+
+     The pseudo-terminal allocated to the client is configured to operate in
+     cooked mode, and with XTABS and CRMOD enabled (see tty(4)).
+
+     TTeellnneettdd has support for enabling locally the following TELNET options:
+
+     WILL ECHO          When the LINEMODE option is enabled, a WILL ECHO or
+                        WONT ECHO will be sent to the client to indicate the
+                        current state of terminal echoing.  When terminal echo
+                        is not desired, a WILL ECHO is sent to indicate that
+                        telnetd will take care of echoing any data that needs
+                        to be echoed to the terminal, and then nothing is
+                        echoed.  When terminal echo is desired, a WONT ECHO is
+                        sent to indicate that telnetd will not be doing any
+                        terminal echoing, so the client should do any terminal
+                        echoing that is needed.
+
+     WILL BINARY        Indicates that the client is willing to send a 8 bits
+                        of data, rather than the normal 7 bits of the Network
+                        Virtual Terminal.
+
+     WILL SGA           Indicates that it will not be sending IAC GA, go
+                        ahead, commands.
+
+     WILL STATUS        Indicates a willingness to send the client, upon re-
+                        quest, of the current status of all TELNET options.
+
+     WILL TIMING-MARK   Whenever a DO TIMING-MARK command is received, it is
+                        always responded to with a WILL TIMING-MARK
+
+     WILL LOGOUT        When a DO LOGOUT is received, a WILL LOGOUT is sent in
+                        response, and the TELNET session is shut down.
+
+     WILL ENCRYPT       Only sent if tteellnneettdd is compiled with support for data
+                        encryption, and indicates a willingness to decrypt the
+                        data stream.
+
+     TTeellnneettdd has support for enabling remotely the following TELNET options:
+
+     DO BINARY          Sent to indicate that telnetd is willing to receive an
+                        8 bit data stream.
+
+     DO LFLOW           Requests that the client handle flow control charac-
+                        ters remotely.
+
+     DO ECHO            This is not really supported, but is sent to identify
+                        a 4.2BSD telnet(1) client, which will improperly re-
+                        spond with WILL ECHO. If a WILL ECHO is received, a
+                        DONT ECHO will be sent in response.
+
+     DO TERMINAL-TYPE   Indicates a desire to be able to request the name of
+                        the type of terminal that is attached to the client
+                        side of the connection.
+
+     DO SGA             Indicates that it does not need to receive IAC GA, the
+                        go ahead command.
+
+     DO NAWS            Requests that the client inform the server when the
+                        window (display) size changes.
+
+     DO TERMINAL-SPEED  Indicates a desire to be able to request information
+                        about the speed of the serial line to which the client
+                        is attached.
+
+     DO XDISPLOC        Indicates a desire to be able to request the name of
+                        the X windows display that is associated with the tel-
+                        net client.
+
+     DO NEW-ENVIRON     Indicates a desire to be able to request environment
+                        variable information, as described in RFC 1572.
+
+     DO ENVIRON         Indicates a desire to be able to request environment
+                        variable information, as described in RFC 1408.
+
+     DO LINEMODE        Only sent if tteellnneettdd is compiled with support for
+                        linemode, and requests that the client do line by line
+                        processing.
+
+     DO TIMING-MARK     Only sent if tteellnneettdd is compiled with support for both
+                        linemode and kludge linemode, and the client responded
+                        with WONT LINEMODE. If the client responds with WILL
+                        TM, the it is assumed that the client supports kludge
+                        linemode.  Note that the [--kk] option can be used to
+
+                        disable this.
+
+     DO AUTHENTICATION  Only sent if tteellnneettdd is compiled with support for au-
+                        thentication, and indicates a willingness to receive
+                        authentication information for automatic login.
+
+     DO ENCRYPT         Only sent if tteellnneettdd is compiled with support for data
+                        encryption, and indicates a willingness to decrypt the
+                        data stream.
+
+EENNVVIIRROONNMMEENNTT
+FFIILLEESS
+     _/_e_t_c_/_s_e_r_v_i_c_e_s
+     _/_e_t_c_/_i_n_i_t_t_a_b (UNICOS systems only)
+     _/_e_t_c_/_i_p_t_o_s (if supported)
+     _/_u_s_r_/_u_c_b_/_b_f_t_p (if supported)
+
+SSEEEE AALLSSOO
+     telnet(1),  login(1),  bftp(1) (if supported)
+
+SSTTAANNDDAARRDDSS
+     RRFFCC--885544   TELNET PROTOCOL SPECIFICATION
+     RRFFCC--885555   TELNET OPTION SPECIFICATIONS
+     RRFFCC--885566   TELNET BINARY TRANSMISSION
+     RRFFCC--885577   TELNET ECHO OPTION
+     RRFFCC--885588   TELNET SUPPRESS GO AHEAD OPTION
+     RRFFCC--885599   TELNET STATUS OPTION
+     RRFFCC--886600   TELNET TIMING MARK OPTION
+     RRFFCC--886611   TELNET EXTENDED OPTIONS - LIST OPTION
+     RRFFCC--888855   TELNET END OF RECORD OPTION
+     RRFFCC--11007733  Telnet Window Size Option
+     RRFFCC--11007799  Telnet Terminal Speed Option
+     RRFFCC--11009911  Telnet Terminal-Type Option
+     RRFFCC--11009966  Telnet X Display Location Option
+     RRFFCC--11112233  Requirements for Internet Hosts -- Application and Support
+     RRFFCC--11118844  Telnet Linemode Option
+     RRFFCC--11337722  Telnet Remote Flow Control Option
+     RRFFCC--11441166  Telnet Authentication Option
+     RRFFCC--11441111  Telnet Authentication: Kerberos Version 4
+     RRFFCC--11441122  Telnet Authentication: SPX
+     RRFFCC--11557711  Telnet Environment Option Interoperability Issues
+     RRFFCC--11557722  Telnet Environment Option
+
+BBUUGGSS
+     Some TELNET commands are only partially implemented.
+
+     Because of bugs in the original 4.2 BSD telnet(1),  tteellnneettdd performs some
+     dubious protocol exchanges to try to discover if the remote client is, in
+     fact, a 4.2 BSD telnet(1).
+
+     Binary mode has no common interpretation except between similar operating
+     systems (Unix in this case).
+
+     The terminal type name received from the remote client is converted to
+     lower case.
+
+     TTeellnneettdd never sends TELNET IAC GA (go ahead) commands.
+
+4.2 Berkeley Distribution      February 3, 1994                              5
diff --git a/mechglue/src/appl/telnet/telnetd/telnetd.8 b/mechglue/src/appl/telnet/telnetd/telnetd.8
new file mode 100644
index 000000000..78700cbed
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/telnetd.8
@@ -0,0 +1,631 @@
+.\" Copyright (c) 1983, 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)telnetd.8	8.2 (Berkeley) 2/3/94
+.\" "
+.TH TELNETD 8
+.SH NAME
+telnetd \-
+.SM DARPA TELNET
+protocol server
+.SH SYNOPSIS
+.B /usr/libexec/telnetd
+[\fB\-a\fP \fIauthmode\fP] [\fB\-B\fP] [\fB\-D\fP] [\fIdebugmode\fP]
+[\fB\-e\fP] [\fB\-h\fP] [\fB\-I\fP\fIinitid\fP] [\fB\-l\fP]
+[\fB\-k\fP] [\fB\-n\fP] [\fB\-r\fP\fIlowpty-highpty\fP] [\fB\-s\fP]
+[\fB\-S\fP \fItos\fP] [\fB\-U\fP] [\fB\-X\fP \fIauthtype\fP]
+[\fB\-w\fP [\fBip\fP|\fImaxhostlen\fP[\fB,\fP[\fBno\fP]\fBstriplocal\fP]]]
+[\fB\-debug\fP [\fIport\fP]]
+.SH DESCRIPTION
+The
+.B telnetd
+command is a server which supports the
+.SM DARPA
+standard
+.SM TELNET
+virtual terminal protocol.
+.B Telnetd
+is normally invoked by the internet server (see
+.BR inetd (8)
+for requests to connect to the
+.SM TELNET
+port as indicated by the
+.I /etc/services
+file (see
+.BR services (5)).
+The
+.B \-debug
+option may be used to start up
+.B telnetd
+manually, instead of through
+.IR inetd (8).
+If started up this way, 
+.I port
+may be specified to run
+.B telnetd
+on an alternate
+.SM TCP
+port number.
+.PP
+The
+.B telnetd
+command accepts the following options:
+.TP
+\fB\-a\fP \fIauthmode\fP
+This option may be used for specifying what mode should be used for
+authentication.  Note that this option is only useful if
+.B telnetd
+has been compiled with support for the
+.SM AUTHENTICATION
+option.  There are several valid values for
+.IR authmode :
+.RS
+.TP
+.B debug
+Turns on authentication debugging code.
+.TP
+.B valid
+Only allow connections when the remote user can provide valid
+authentication information to identify the remote user, and is allowed
+access to the specified account without providing a password.
+.TP
+.B user
+Only allow connections when the remote user can provide valid
+authentication information to identify the remote user.  The
+.IR login (1)
+command will provide any additional user verification needed if the
+remote user is not allowed automatic access to the specified account.
+.TP
+.B other
+Only allow connections that supply some authentication information.
+This option is currently not supported by any of the existing
+authentication mechanisms, and is thus the same as specifying
+.B \-a
+.BR valid .
+.TP
+.B none
+This is the default state.  Authentication information is not required.
+If no or insufficient authentication information is provided, then the
+.IR login (1)
+program will provide the necessary user verification.
+.TP
+.B off
+This disables the authentication code.  All user verification will
+happen through the
+.IR login (1)
+program.
+.RE
+.TP
+.B \-B
+Specifies bftp server mode.  In this mode,
+.B telnetd
+causes login to start a
+.IR bftp (1)
+session rather than the user's normal shell.  In bftp daemon mode,
+normal logins are not supported, and it must be used on a port other
+than the normal
+.SM TELNET
+port.
+.TP
+\fB\-D\fP \fIdebugmode\fP
+This option may be used for debugging purposes.  This allows
+.B telnetd
+to print out debugging information to the connection, allowing the user
+to see what
+.B telnetd
+is doing.  There are several possible values for
+.IR debugmode :
+.RS
+.TP
+.B options
+Prints information about the negotiation of
+.SM TELNET
+options.
+.TP
+.B report
+Prints the
+.B options
+information, plus some additional information about what processing is
+going on.
+.TP
+.B netdata
+Displays the data stream received by
+.B telnetd.
+.TP
+.B ptydata
+Displays data written to the pty.
+.TP
+.B encrypt
+Enables	encryption debugging code.
+.TP
+.B exercise
+Has not been implemented yet.
+.RE
+.TP
+.B \-debug
+Enables debugging on each socket created by
+.B telnetd
+(see
+.SM SO_DEBUG
+in
+.IR socket (2)).
+.TP
+.B \-e
+This option causes
+.B telnetd
+to refuse unencrypted connections.
+.TP
+.B \-h
+Disables the printing of host-specific information before login has been
+completed.
+.TP
+\fB\-I\fP \fIinitid\fP
+This option is only applicable to
+.SM UNICOS
+systems prior to 7.0.  It specifies the
+.SM ID
+from
+.I /etc/inittab
+to use when init starts login sessions.  The default
+.SM ID
+is fe.
+.TP
+.B \-k
+This option is only useful if
+.B telnetd
+has been compiled with both linemode and kludge linemode support.  If
+the
+.B \-k
+option is specified, then if the remote client does not support the
+.SM LINEMODE
+option, then
+.B telnetd
+will operate in character at a time mode.  It will still support kludge
+linemode, but will only go into kludge linemode if the remote client
+requests it.  (This is done by by the client sending
+.SM DONT SUPPRESS-GO-AHEAD
+and
+.SM DONT ECHO.)
+The
+.B \-k
+option is most useful when there are remote clients that do not support
+kludge linemode, but pass the heuristic (if they respond with
+.SM WILL TIMING-MARK
+in response to a
+.SM DO TIMING-MARK)
+for kludge linemode support.
+.TP
+.B \-l
+Specifies line mode.  Tries to force clients to use line-at-a-time
+mode.  If the
+.SM LINEMODE
+option is not supported, it will go into kludge linemode.
+.TP
+.B \-n
+Disable
+.SM TCP
+keep-alives.  Normally
+.B telnetd
+enables the
+.SM TCP
+keep-alive mechanism to probe connections that have been idle for some
+period of time to determine if the client is still there, so that idle
+connections from machines that have crashed or can no longer be reached
+may be cleaned up.
+.TP
+\fB\-r\fP \fIlowpty-highpty\fP
+This option is only enabled when
+.B telnetd
+is compiled for
+.SM UNICOS.
+It specifies an inclusive range of pseudo-terminal devices to use.  If
+the system has sysconf variable
+.SM _SC_CRAY_NPTY
+configured, the default pty search range is 0 to
+.SM _SC_CRAY_NPTY;
+otherwise, the default range is 0 to 128.  Either
+.I lowpty
+or
+.I highpty
+may be omitted to allow changing either end of the search range.  If
+.I lowpty
+is omitted, the - character is still required so that
+.B telnetd
+can differentiate
+.I highpty
+from
+.IR lowpty .
+.TP
+.B \-s
+This option is only enabled if
+.B telnetd
+is compiled with support for SecurID cards.  It causes the
+.B \-s
+option to be passed on to
+.IR login (1),
+and thus is only useful if
+.IR login (1)
+supports the
+.B \-s
+flag to indicate that only SecurID validated logins are allowed, and is
+usually useful for controlling remote logins from outside of a firewall.
+.TP
+\fB\-S\fP \fItos\fP
+.TP
+.B \-U
+This option causes
+.B telnetd
+to refuse connections from addresses that cannot be mapped back into a
+symbolic name via the
+.IR gethostbyaddr (3)
+routine.
+.TP
+.B \-w \fP[\fBip\fP|\fImaxhostlen\fP[\fB,\fP[\fBno\fP]\fBstriplocal\fP]]
+Controls the form of the remote hostname passed to login(1).
+Specifying \fBip\fP results in the numeric IP address always being
+passed to login(1).  Specifying a number, \fImaxhostlen\fP, sets the
+maximum length of the hostname passed to login(1) before it will be
+passed as a numeric IP address.  If \fImaxhostlen\fP is 0, then the
+system default, as determined by the utmp or utmpx structures, is
+used.  The \fBnostriplocal\fP and \fBstriplocal\fP options, which must
+be preceded by a comma, control whether or not the local host domain
+is stripped from the remote hostname.  By default, the equivalent of
+\fBstriplocal\fP is in effect.
+.TP
+\fB\-X\fP \fIauthtype\fP
+This option is only valid if
+.B telnetd
+has been built with support for the authentication option.  It disables
+the use of
+.I authtype
+authentication, and can be used to temporarily disable a specific
+authentication type without having to recompile
+.BR telnetd .
+.PP
+.B Telnetd
+operates by allocating a pseudo-terminal device (see
+.IR pty (4))
+for a client, then creating a login process which has the slave side of
+the pseudo-terminal as
+.IR stdin ,
+.I stdout
+and
+.IR stderr .
+.B Telnetd
+manipulates the master side of the pseudo-terminal, implementing the
+.SM TELNET
+protocol and passing characters between the remote client and the login
+process.
+.PP
+When a
+.SM TELNET
+session is started up, 
+.B telnetd
+sends
+.SM TELNET
+options to the client side indicating a willingness to do the following
+.SM TELNET
+options, which are described in more detail below:
+.sp
+.nf
+.in +0.5i
+DO AUTHENTICATION
+WILL ENCRYPT
+DO TERMINAL TYPE
+DO TSPEED
+DO XDISPLOC
+DO NEW-ENVIRON
+DO ENVIRON
+WILL SUPPRESS GO AHEAD
+DO ECHO
+DO LINEMODE
+DO NAWS
+WILL STATUS
+DO LFLOW
+DO TIMING-MARK
+.in 
+.fi
+.PP
+The pseudo-terminal allocated to the client is configured
+to operate in \*(lqcooked\*(rq mode, and with
+.SM XTABS
+and
+.SM CRMOD
+enabled (see
+.IR tty (4)).
+.PP
+.B Telnetd
+has support for enabling locally the following
+.SM TELNET
+options:
+.TP "\w'.SM WILL TIMING-MARK\ 'u"
+.SM WILL ECHO
+When the
+.SM LINEMODE
+option is enabled, a
+.SM WILL ECHO
+or
+.SM WONT ECHO
+will be sent to the client to indicate the current state of terminal
+echoing.  When terminal echo is not desired, a
+.SM WILL ECHO
+is sent to indicate that
+.B telnetd
+will take care of echoing any data that needs to be echoed to the
+terminal, and then nothing is echoed.  When terminal echo is desired, a
+.SM WONT ECHO
+is sent to indicate that
+.B telnetd
+will not be doing any terminal echoing, so the
+client should do any terminal echoing that is needed.
+.TP
+.SM WILL BINARY
+Indicates that the client is willing to send a 8 bits of data, rather
+than the normal 7 bits of the Network Virtual Terminal.
+.TP
+.SM WILL SGA
+Indicates that it will not be sending
+.SM IAC GA,
+go ahead, commands.
+.TP
+.SM WILL STATUS 
+Indicates a willingness to send the client, upon request, of the current
+status of all
+.SM TELNET
+options.
+.TP
+.SM WILL TIMING-MARK
+Whenever a
+.SM DO TIMING-MARK
+command is received, it is always responded to with a
+.SM WILL TIMING-MARK
+.TP
+.SM WILL LOGOUT
+When a
+.SM DO LOGOUT
+is received, a
+.SM WILL LOGOUT
+is sent in response, and the
+.SM TELNET
+session is shut down.
+.TP
+.SM WILL ENCRYPT
+Only sent if
+.B telnetd
+is compiled with support for data encryption, and indicates a
+willingness to decrypt the data stream.
+.PP
+.B Telnetd
+has support for enabling remotely the following
+.SM TELNET
+options:
+.TP "\w'.SM DO TERMINAL-SPEED\ 'u"
+.SM DO BINARY
+Sent to indicate that
+.B telnetd
+is willing to receive an 8 bit data stream.
+.TP
+.SM DO LFLOW
+Requests that the client handle flow control characters remotely.
+.TP
+.SM DO ECHO
+This is not really supported, but is sent to identify a 4.2BSD
+.IR telnet (1)
+client, which will improperly respond with
+.SM WILL ECHO.
+If a
+.SM WILL ECHO
+is received, a
+.SM DONT ECHO
+will be sent in response.
+.TP
+.SM DO TERMINAL-TYPE
+Indicates a desire to be able to request the name of the type of
+terminal that is attached to the client side of the connection.
+.TP
+.SM DO SGA
+Indicates that it does not need to receive
+.SM IAC GA,
+the go ahead command.
+.TP
+.SM DO NAWS
+Requests that the client inform the server when the window (display)
+size changes.
+.TP
+.SM DO TERMINAL-SPEED
+Indicates a desire to be able to request information about the speed of
+the serial line to which the client is attached.
+.TP
+.SM DO XDISPLOC
+Indicates a desire to be able to request the name of the X windows
+display that is associated with the telnet client.
+.TP
+.SM DO NEW-ENVIRON
+Indicates a desire to be able to request environment variable
+information, as described in RFC 1572.
+.TP
+.SM DO ENVIRON
+Indicates a desire to be able to request environment variable
+information, as described in RFC 1408.
+.TP
+.SM DO LINEMODE
+Only sent if
+.B telnetd
+is compiled with support for linemode, and requests that the client do
+line by line processing.
+.TP
+.SM DO TIMING-MARK
+Only sent if
+.B telnetd
+is compiled with support for both linemode and kludge linemode, and the
+client responded with
+.SM WONT LINEMODE.
+If the client responds with
+.SM WILL TM,
+the it is assumed that the client supports kludge linemode.  Note that
+the
+.B \-k
+option can be used to disable this.
+.TP
+.SM DO AUTHENTICATION
+Only sent if
+.B telnetd
+is compiled with support for authentication, and indicates a willingness
+to receive authentication information for automatic login.
+.TP
+.SM DO ENCRYPT
+Only sent if
+.B telnetd
+is compiled with support for data encryption, and indicates a
+willingness to decrypt the data stream.
+.SH FILES
+.I /etc/services
+.br
+.I /etc/inittab
+(UNICOS systems only)
+.br
+.I /etc/iptos
+(if supported)
+.br
+.I /usr/ucb/bftp
+(if supported)
+.SH "SEE ALSO"
+.IR telnet (1),
+.IR login (1),
+.IR bftp (1)
+(if supported)
+.SH STANDARDS
+.TP "\w'.B RFC-2000\ 'u"
+.B RFC-854
+TELNET PROTOCOL SPECIFICATION
+.sp -1
+.TP
+.B RFC-855
+TELNET OPTION SPECIFICATIONS
+.sp -1
+.TP
+.B RFC-856
+TELNET BINARY TRANSMISSION
+.sp -1
+.TP
+.B RFC-857
+TELNET ECHO OPTION
+.sp -1
+.TP
+.B RFC-858
+TELNET SUPPRESS GO AHEAD OPTION
+.sp -1
+.TP
+.B RFC-859
+TELNET STATUS OPTION
+.sp -1
+.TP
+.B RFC-860
+TELNET TIMING MARK OPTION
+.sp -1
+.TP
+.B RFC-861
+TELNET EXTENDED OPTIONS - LIST OPTION
+.sp -1
+.TP
+.B RFC-885
+TELNET END OF RECORD OPTION
+.sp -1
+.TP
+.B RFC-1073
+Telnet Window Size Option
+.sp -1
+.TP
+.B RFC-1079
+Telnet Terminal Speed Option
+.sp -1
+.TP
+.B RFC-1091
+Telnet Terminal-Type Option
+.sp -1
+.TP
+.B RFC-1096
+Telnet X Display Location Option
+.sp -1
+.TP
+.B RFC-1123
+Requirements for Internet Hosts -- Application and Support
+.sp -1
+.TP
+.B RFC-1184
+Telnet Linemode Option
+.sp -1
+.TP
+.B RFC-1372
+Telnet Remote Flow Control Option
+.sp -1
+.TP
+.B RFC-1416
+Telnet Authentication Option
+.sp -1
+.TP
+.B RFC-1411
+Telnet Authentication: Kerberos Version 4
+.sp -1
+.TP
+.B RFC-1412
+Telnet Authentication: SPX
+.sp -1
+.TP
+.B RFC-1571
+Telnet Environment Option Interoperability Issues
+.sp -1
+.TP
+.B RFC-1572
+Telnet Environment Option
+.SH BUGS
+Some
+.SM TELNET
+commands are only partially implemented.
+.PP
+Because of bugs in the original 4.2 BSD
+.IR telnet (1),
+.B telnetd
+performs some dubious protocol exchanges to try to discover if the
+remote client is, in fact, a 4.2 BSD
+.IR telnet (1).
+.PP
+Binary mode has no common interpretation except between similar
+operating systems (Unix in this case).
+.PP
+The terminal type name received from the remote client is converted to
+lower case.
+.PP
+.B Telnetd
+never sends
+.SM TELNET
+.SM IAC GA
+(go ahead) commands.
diff --git a/mechglue/src/appl/telnet/telnetd/telnetd.c b/mechglue/src/appl/telnet/telnetd/telnetd.c
new file mode 100644
index 000000000..a90fa5c5c
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/telnetd.c
@@ -0,0 +1,1714 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+/* based on @(#)telnetd.c	8.1 (Berkeley) 6/4/93 */
+
+#include "telnetd.h"
+#include "pathnames.h"
+
+extern int getent(char *, char *);
+extern int tgetent(char *, char *);
+
+#if	defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
+/*
+ * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
+ * use it to tell us to turn off all the socket security code,
+ * since that is only used in UNICOS 7.0 and later.
+ */
+# undef _SC_CRAY_SECURE_SYS
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libpty.h>
+#include <com_err.h>
+#if	defined(_SC_CRAY_SECURE_SYS)
+#include <sys/sysv.h>
+#include <sys/secdev.h>
+# ifdef SO_SEC_MULTI		/* 8.0 code */
+#include <sys/secparm.h>
+#include <sys/usrv.h>
+# endif /* SO_SEC_MULTI */
+int	secflag;
+char	tty_dev[16];
+struct	secdev dv;
+struct	sysv sysv;
+# ifdef SO_SEC_MULTI		/* 8.0 code */
+struct	socksec ss;
+# else /* SO_SEC_MULTI */	/* 7.0 code */
+struct	socket_security ss;
+# endif /* SO_SEC_MULTI */
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+#include "fake-addrinfo.h"
+
+#ifdef KRB5
+#include "krb5.h"
+#endif
+
+#if	defined(AUTHENTICATION)
+#include <libtelnet/auth.h>
+#include <libtelnet/auth-proto.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#include <libtelnet/enc-proto.h>
+#endif
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
+#include <libtelnet/misc-proto.h>
+#endif
+
+int	registerd_host_only = 0;
+
+#ifdef	STREAMSPTY
+#include <sys/stream.h>
+# include <stropts.h>
+# include <termio.h>
+/* make sure we don't get the bsd version */
+#ifdef HAVE_SYS_TTY_H
+# include "/usr/include/sys/tty.h"
+#endif
+#ifdef  HAVE_SYS_PTYVAR_H
+# include <sys/ptyvar.h>
+#endif
+
+/*
+ * Because of the way ptyibuf is used with streams messages, we need
+ * ptyibuf+1 to be on a full-word boundary.  The following wierdness
+ * is simply to make that happen.
+ */
+long	ptyibufbuf[BUFSIZ/sizeof(long)+1];
+char	*ptyibuf = ((char *)&ptyibufbuf[1])-1;
+char	*ptyip = ((char *)&ptyibufbuf[1])-1;
+char	ptyibuf2[BUFSIZ];
+unsigned char ctlbuf[BUFSIZ];
+struct	strbuf strbufc, strbufd;
+
+int readstream();
+
+#else	/* ! STREAMPTY */
+
+/*
+ * I/O data buffers,
+ * pointers, and counters.
+ */
+char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
+char	ptyibuf2[BUFSIZ];
+
+#endif /* ! STREAMPTY */
+
+static void doit (struct sockaddr *);
+int terminaltypeok (char *);
+static void _gettermname(void);
+
+int	hostinfo = 1;			/* do we print login banner? */
+
+#ifdef	CRAY
+extern int      newmap; /* nonzero if \n maps to ^M^J */
+int	lowpty = 0, highpty;	/* low, high pty numbers */
+#endif /* CRAY */
+
+int debug = 0;
+int keepalive = 1;
+char *progname;
+
+int maxhostlen = 0;
+int always_ip = 0;
+int stripdomain = 1;
+
+extern void usage (void);
+
+/*
+ * The string to pass to getopt().  We do it this way so
+ * that only the actual options that we support will be
+ * passed off to getopt().
+ */
+char valid_opts[] = {
+	'd', ':', 'h', 'k', 'L', ':', 'n', 'S', ':', 'U',
+	'w', ':',
+#ifdef	AUTHENTICATION
+	'a', ':', 'X', ':',
+#endif
+#ifdef BFTPDAEMON
+	'B',
+#endif
+#ifdef DIAGNOSTICS
+	'D', ':',
+#endif
+#ifdef	ENCRYPTION
+	'e',
+#endif
+#if	defined(CRAY) && defined(NEWINIT)
+	'I', ':',
+#endif
+#ifdef	LINEMODE
+	'l',
+#endif
+#ifdef CRAY
+	'r', ':',
+#endif
+#ifdef	SecurID
+	's',
+#endif
+#ifdef KRB5
+	'R', ':', 't', ':',
+#endif
+	'\0'
+};
+
+#include <sys/utsname.h>
+static char *
+get_default_IM()
+{
+	struct utsname name;
+	static char banner[1024];
+	
+	if (uname(&name) < 0)
+		sprintf(banner, "\r\nError getting hostname: %s\r\n",
+		    strerror(errno));
+        else {
+#if defined(_AIX)
+		sprintf(banner, "\r\n    %%h (%s release %s.%s) (%%t)\r\n\r\n",
+		    name.sysname, name.version, name.release);
+#else
+		sprintf(banner, "\r\n    %%h (%s release %s %s) (%%t)\r\n\r\n",
+		    name.sysname, name.release, name.version);
+#endif
+	}
+	return banner;
+}
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	struct sockaddr_storage from;
+	int on = 1;
+	socklen_t fromlen;
+	register int ch;
+	extern char *optarg;
+	extern int optind;
+#if	defined(IPPROTO_IP) && defined(IP_TOS)
+	int tos = -1;
+#endif
+
+	pfrontp = pbackp = ptyobuf;
+	netip = netibuf;
+	nfrontp = nbackp = netobuf;
+#ifdef	ENCRYPTION
+	nclearto = 0;
+#endif	/* ENCRYPTION */
+
+	progname = *argv;
+
+#ifdef CRAY
+	/*
+	 * Get number of pty's before trying to process options,
+	 * which may include changing pty range.
+	 */
+	highpty = getnpty();
+#endif /* CRAY */
+
+	while ((ch = getopt(argc, argv, valid_opts)) != -1) {
+		switch(ch) {
+
+#ifdef	AUTHENTICATION
+		case 'a':
+			/*
+			 * Check for required authentication level
+			 */
+			if (strcmp(optarg, "debug") == 0) {
+				extern int auth_debug_mode;
+				auth_debug_mode = 1;
+			} else if (strcasecmp(optarg, "none") == 0) {
+				auth_level = 0;
+			} else if (strcasecmp(optarg, "other") == 0) {
+				auth_level = AUTH_OTHER;
+			} else if (strcasecmp(optarg, "user") == 0) {
+				auth_level = AUTH_USER;
+			} else if (strcasecmp(optarg, "valid") == 0) {
+				auth_level = AUTH_VALID;
+			} else if (strcasecmp(optarg, "off") == 0) {
+				/*
+				 * This hack turns off authentication
+				 */
+				auth_level = -1;
+			} else {
+				fprintf(stderr,
+			    "telnetd: unknown authorization level for -a\n");
+			}
+			break;
+#endif	/* AUTHENTICATION */
+
+#ifdef BFTPDAEMON
+		case 'B':
+			bftpd++;
+			break;
+#endif /* BFTPDAEMON */
+
+		case 'd':
+			if (strcmp(optarg, "ebug") == 0) {
+				debug++;
+				break;
+			}
+			usage();
+			/* NOTREACHED */
+			break;
+
+#ifdef DIAGNOSTICS
+		case 'D':
+			/*
+			 * Check for desired diagnostics capabilities.
+			 */
+			if (!strcmp(optarg, "report")) {
+				diagnostic |= TD_REPORT|TD_OPTIONS;
+			} else if (!strcmp(optarg, "exercise")) {
+				diagnostic |= TD_EXERCISE;
+			} else if (!strcmp(optarg, "netdata")) {
+				diagnostic |= TD_NETDATA;
+			} else if (!strcmp(optarg, "ptydata")) {
+				diagnostic |= TD_PTYDATA;
+			} else if (!strcmp(optarg, "options")) {
+				diagnostic |= TD_OPTIONS;
+			} else if (!strcmp(optarg, "encrypt")) {
+				extern int encrypt_debug_mode;
+				encrypt_debug_mode = 1;
+			} else {
+				usage();
+				/* NOT REACHED */
+			}
+			break;
+#endif /* DIAGNOSTICS */
+
+#ifdef	ENCRYPTION
+		case 'e':
+			must_encrypt = 1;
+			break;
+#endif	/* ENCRYPTION */
+
+		case 'h':
+			hostinfo = 0;
+			break;
+
+#if	defined(CRAY) && defined(NEWINIT)
+		case 'I':
+		    {
+			extern char *gen_id;
+			gen_id = optarg;
+			break;
+		    }
+#endif	/* defined(CRAY) && defined(NEWINIT) */
+
+#ifdef	LINEMODE
+		case 'l':
+			alwayslinemode = 1;
+			break;
+#endif	/* LINEMODE */
+
+		case 'k':
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+			lmodetype = NO_AUTOKLUDGE;
+#else
+			/* ignore -k option if built without kludge linemode */
+#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+			break;
+
+		case 'L':
+		    {
+		        extern char *login_program;
+
+			login_program = optarg;
+			break;
+		    }
+
+		case 'n':
+			keepalive = 0;
+			break;
+
+#ifdef CRAY
+		case 'r':
+		    {
+			char *strchr();
+			char *c;
+
+			/*
+			 * Allow the specification of alterations
+			 * to the pty search range.  It is legal to
+			 * specify only one, and not change the
+			 * other from its default.
+			 */
+			c = strchr(optarg, '-');
+			if (c) {
+				*c++ = '\0';
+				highpty = atoi(c);
+			}
+			if (*optarg != '\0')
+				lowpty = atoi(optarg);
+			if ((lowpty > highpty) || (lowpty < 0) ||
+							(highpty > 32767)) {
+				usage();
+				/* NOT REACHED */
+			}
+			break;
+		    }
+#endif	/* CRAY */
+
+#ifdef KRB5
+		case 'R':
+		    {
+			extern krb5_context telnet_context;
+			krb5_error_code retval;
+			
+			if (telnet_context == 0) {
+				retval = krb5_init_context(&telnet_context);
+				if (retval) {
+					com_err("telnetd", retval,
+						"while initializing krb5");
+					exit(1);
+				}
+			}
+			krb5_set_default_realm(telnet_context, optarg);
+			break;
+		    }
+#endif	/* KRB5 */
+
+#ifdef	SecurID
+		case 's':
+			/* SecurID required */
+			require_SecurID = 1;
+			break;
+#endif	/* SecurID */
+		case 'S':
+#ifdef	HAVE_GETTOSBYNAME
+			if ((tos = parsetos(optarg, "tcp")) < 0)
+				fprintf(stderr, "%s%s%s\n",
+					"telnetd: Bad TOS argument '", optarg,
+					"'; will try to use default TOS");
+#else
+			fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
+						"-S flag not supported\n");
+#endif
+			break;
+
+#ifdef KRB5
+		case 't':
+		    {
+			extern char *telnet_srvtab;
+
+			telnet_srvtab = optarg;
+			break;
+		    }
+#endif	/* KRB5 */
+
+
+		case 'U':
+			registerd_host_only = 1;
+			break;
+
+#ifdef	AUTHENTICATION
+		case 'X':
+			/*
+			 * Check for invalid authentication types
+			 */
+			auth_disable_name(optarg);
+			break;
+#endif	/* AUTHENTICATION */
+		case 'w':
+			if (!strcmp(optarg, "ip"))
+				always_ip = 1;
+			else {
+				char *cp;
+				cp = strchr(optarg, ',');
+				if (cp == NULL)
+					maxhostlen = atoi(optarg);
+				else if (*(++cp)) {
+					if (!strcmp(cp, "striplocal"))
+						stripdomain = 1;
+					else if (!strcmp(cp, "nostriplocal"))
+						stripdomain = 0;
+					else {
+						usage();
+					}
+					*(--cp) = '\0';
+					maxhostlen = atoi(optarg);
+				}
+			}
+			break;
+		default:
+			fprintf(stderr, "telnetd: %c: unknown option\n", ch);
+			/* FALLTHROUGH */
+		case '?':
+			usage();
+			/* NOTREACHED */
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	/* XXX Convert this to support getaddrinfo, ipv6, etc.  */
+	if (debug) {
+	    int s, ns;
+	    socklen_t foo;
+	    struct servent *sp;
+	    static struct sockaddr_in sin4 = { AF_INET };
+
+	    if (argc > 1) {
+		usage();
+		/* NOT REACHED */
+	    } else if (argc == 1) {
+		    if ((sp = getservbyname(*argv, "tcp"))) {
+			sin4.sin_port = sp->s_port;
+		    } else {
+			sin4.sin_port = atoi(*argv);
+			if ((int)sin4.sin_port <= 0) {
+			    fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
+			    usage();
+			    /* NOT REACHED */
+			}
+			sin4.sin_port = htons((u_short)sin4.sin_port);
+		   }
+	    } else {
+		sp = getservbyname("telnet", "tcp");
+		if (sp == 0) {
+		    fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
+		    exit(1);
+		}
+		sin4.sin_port = sp->s_port;
+	    }
+
+	    s = socket(AF_INET, SOCK_STREAM, 0);
+	    if (s < 0) {
+		    perror("telnetd: socket");;
+		    exit(1);
+	    }
+	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+				(char *)&on, sizeof(on));
+	    if (bind(s, (struct sockaddr *)&sin4, sizeof(sin4)) < 0) {
+		perror("bind");
+		exit(1);
+	    }
+	    if (listen(s, 1) < 0) {
+		perror("listen");
+		exit(1);
+	    }
+	    foo = sizeof(sin4);
+	    ns = accept(s, (struct sockaddr *)&sin4, &foo);
+	    if (ns < 0) {
+		perror("accept");
+		exit(1);
+	    }
+	    (void) dup2(ns, 0);
+	    (void) close(ns);
+	    (void) close(s);
+#ifdef convex
+	} else if (argc == 1) {
+		; /* VOID*/		/* Just ignore the host/port name */
+#endif
+	} else if (argc > 0) {
+		usage();
+		/* NOT REACHED */
+	}
+
+#if	defined(_SC_CRAY_SECURE_SYS)
+	secflag = sysconf(_SC_CRAY_SECURE_SYS);
+
+	/*
+	 *	Get socket's security label
+	 */
+	if (secflag)  {
+		int szss = sizeof(ss);
+#ifdef SO_SEC_MULTI			/* 8.0 code */
+		int sock_multi;
+		int szi = sizeof(int);
+#endif /* SO_SEC_MULTI */
+
+		memset((char *)&dv, 0, sizeof(dv));
+
+		if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
+			perror("getsysv");
+			exit(1);
+		}
+
+		/*
+		 *	Get socket security label and set device values
+		 *	   {security label to be set on ttyp device}
+		 */
+#ifdef SO_SEC_MULTI			/* 8.0 code */
+		if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
+			       (char *)&ss, &szss) < 0) ||
+		    (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
+				(char *)&sock_multi, &szi) < 0)) {
+			perror("getsockopt");
+			exit(1);
+		} else {
+			dv.dv_actlvl = ss.ss_actlabel.lt_level;
+			dv.dv_actcmp = ss.ss_actlabel.lt_compart;
+			if (!sock_multi) {
+				dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
+				dv.dv_valcmp = dv.dv_actcmp;
+			} else {
+				dv.dv_minlvl = ss.ss_minlabel.lt_level;
+				dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
+				dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
+			}
+			dv.dv_devflg = 0;
+		}
+#else /* SO_SEC_MULTI */		/* 7.0 code */
+		if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
+				(char *)&ss, &szss) >= 0) {
+			dv.dv_actlvl = ss.ss_slevel;
+			dv.dv_actcmp = ss.ss_compart;
+			dv.dv_minlvl = ss.ss_minlvl;
+			dv.dv_maxlvl = ss.ss_maxlvl;
+			dv.dv_valcmp = ss.ss_maxcmp;
+		}
+#endif /* SO_SEC_MULTI */
+	}
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+	fromlen = sizeof (from);
+	memset(&from, 0, sizeof(from));
+	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+		fprintf(stderr, "%s: ", progname);
+		perror("getpeername");
+		_exit(1);
+	}
+	if (keepalive &&
+	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+			(char *)&on, sizeof (on)) < 0) {
+		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+	}
+
+#if	defined(IPPROTO_IP) && defined(IP_TOS)
+	if (fromlen == sizeof (struct in_addr)) {
+# if	defined(HAVE_GETTOSBYNAME)
+		struct tosent *tp;
+		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+			tos = tp->t_tos;
+# endif
+		if (tos < 0)
+			tos = 020;	/* Low Delay bit */
+		if (tos
+		   && (setsockopt(0, IPPROTO_IP, IP_TOS,
+				  (char *)&tos, sizeof(tos)) < 0)
+		   && (errno != ENOPROTOOPT) )
+			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+	}
+#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
+	net = 0;
+	doit((struct sockaddr *)&from);
+	
+	/* NOTREACHED */
+	return 0;
+}  /* end of main */
+
+	void
+usage()
+{
+	fprintf(stderr, "Usage: telnetd");
+#ifdef	AUTHENTICATION
+	fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t");
+#endif
+#ifdef BFTPDAEMON
+	fprintf(stderr, " [-B]");
+#endif
+	fprintf(stderr, " [-debug]");
+#ifdef DIAGNOSTICS
+	fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
+#endif
+#ifdef	AUTHENTICATION
+	fprintf(stderr, " [-edebug]");
+#endif
+	fprintf(stderr, " [-h]");
+#if	defined(CRAY) && defined(NEWINIT)
+	fprintf(stderr, " [-Iinitid]");
+#endif
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+	fprintf(stderr, " [-k]");
+#endif
+#ifdef LINEMODE
+	fprintf(stderr, " [-l]");
+#endif
+	fprintf(stderr, " [-n]");
+#ifdef	CRAY
+	fprintf(stderr, " [-r[lowpty]-[highpty]]");
+#endif
+	fprintf(stderr, "\n\t");
+#ifdef	SecurID
+	fprintf(stderr, " [-s]");
+#endif
+#ifdef	HAVE_GETTOSBYNAME
+	fprintf(stderr, " [-S tos]");
+#endif
+#ifdef	AUTHENTICATION
+	fprintf(stderr, " [-X auth-type]");
+#endif
+	fprintf(stderr, " [-U]\n\t");
+	fprintf(stderr, " [-w [ip|maxhostlen[,[no]striplocal]]]\n\t");
+	fprintf(stderr, " [port]\n");
+	exit(1);
+}
+
+static void encrypt_failure()
+{
+    char *lerror_message;
+
+    if (auth_must_encrypt())
+	lerror_message = "Encryption was not successfully negotiated.  Goodbye.\r\n\r\n";
+    else
+	lerror_message = "Unencrypted connection refused. Goodbye.\r\n\r\n";
+
+    netputs(lerror_message);
+    netflush();
+    exit(1);
+}
+
+/*
+ * getterminaltype
+ *
+ *	Ask the other end to send along its terminal type and speed.
+ * Output is the variable terminaltype filled in.
+ */
+static unsigned char ttytype_sbbuf[] = {
+	IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
+};
+
+static int
+getterminaltype(name)
+    char *name;
+{
+    int retval = -1;
+
+    settimer(baseline);
+#if	defined(AUTHENTICATION)
+    ttsuck();
+    /*
+     * Handle the Authentication option before we do anything else.
+     */
+    send_do(TELOPT_AUTHENTICATION, 1);
+    while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
+	ttloop();
+    if (his_state_is_will(TELOPT_AUTHENTICATION)) {
+	auth_wait(name);
+    }
+#endif
+
+#ifdef	ENCRYPTION
+    send_will(TELOPT_ENCRYPT, 1);
+    send_do(TELOPT_ENCRYPT, 1);
+#endif	/* ENCRYPTION */
+    send_do(TELOPT_TTYPE, 1);
+    send_do(TELOPT_TSPEED, 1);
+    send_do(TELOPT_XDISPLOC, 1);
+    send_do(TELOPT_NEW_ENVIRON, 1);
+    send_do(TELOPT_OLD_ENVIRON, 1);
+    while (
+#ifdef	ENCRYPTION
+	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
+	   his_will_wont_is_changing(TELOPT_ENCRYPT) ||
+#endif	/* ENCRYPTION */
+	   his_will_wont_is_changing(TELOPT_TTYPE) ||
+	   his_will_wont_is_changing(TELOPT_TSPEED) ||
+	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
+	   his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
+	   his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
+	ttloop();
+    }
+#ifdef	ENCRYPTION
+    /*
+     * Wait for the negotiation of what type of encryption we can
+     * send with.  If autoencrypt is not set, this will just return.
+     */
+    if (his_state_is_will(TELOPT_ENCRYPT)) {
+	encrypt_wait();
+    }
+    if (must_encrypt || auth_must_encrypt()) {
+	time_t timeout = time(0) + 60;
+	
+	if (my_state_is_dont(TELOPT_ENCRYPT) ||
+	    my_state_is_wont(TELOPT_ENCRYPT) ||
+	    his_state_is_wont(TELOPT_AUTHENTICATION))
+	    encrypt_failure();
+
+	while (!EncryptStartInput()) {
+	    if (time (0) > timeout)
+		encrypt_failure();
+	    ttloop();
+	}
+
+	while (!EncryptStartOutput()) {
+	    if (time (0) > timeout)
+		encrypt_failure();
+	    ttloop();
+	}
+
+	while (!encrypt_is_encrypting()) {
+	    if (time(0) > timeout)
+		encrypt_failure();
+	    ttloop();
+	}
+    }
+#endif	/* ENCRYPTION */
+    /* Options like environment require authentication and encryption
+       negotiation to be completed.*/
+    auth_negotiated = 1;
+    if (his_state_is_will(TELOPT_TSPEED)) {
+	static unsigned char sb[] =
+			{ IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
+	netwrite(sb, sizeof(sb));
+    }
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+	static unsigned char sb[] =
+			{ IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
+	netwrite(sb, sizeof(sb));
+    }
+    if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
+	static unsigned char sb[] =
+			{ IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
+	netwrite(sb, sizeof(sb));
+    }
+    else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
+	static unsigned char sb[] =
+			{ IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
+	netwrite(sb, sizeof(sb));
+    }
+    if (his_state_is_will(TELOPT_TTYPE))
+	netwrite(ttytype_sbbuf, sizeof(ttytype_sbbuf));
+
+    if (his_state_is_will(TELOPT_TSPEED)) {
+	while (sequenceIs(tspeedsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+	while (sequenceIs(xdisplocsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
+	while (sequenceIs(environsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
+	while (sequenceIs(oenvironsubopt, baseline))
+	    ttloop();
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
+	char first[256], last[256];
+
+	while (sequenceIs(ttypesubopt, baseline))
+	    ttloop();
+
+	/*
+	 * If the other side has already disabled the option, then
+	 * we have to just go with what we (might) have already gotten.
+	 */
+	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
+	    (void) strncpy(first, terminaltype, sizeof(first) - 1);
+	    first[sizeof(first) - 1] = '\0';
+	    for(;;) {
+		/*
+		 * Save the unknown name, and request the next name.
+		 */
+		(void) strncpy(last, terminaltype, sizeof(last) - 1);
+		last[sizeof(last) - 1] = '\0';
+		_gettermname();
+		if (terminaltypeok(terminaltype))
+		    break;
+		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
+		    his_state_is_wont(TELOPT_TTYPE)) {
+		    /*
+		     * We've hit the end.  If this is the same as
+		     * the first name, just go with it.
+		     */
+		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
+			break;
+		    /*
+		     * Get the terminal name one more time, so that
+		     * RFC1091 compliant telnets will cycle back to
+		     * the start of the list.
+		     */
+		    _gettermname();
+		    if (strncmp(first, terminaltype, sizeof(first)) != 0) {
+			(void) strncpy(terminaltype, first,
+				       sizeof(terminaltype) - 1);
+			terminaltype[sizeof(terminaltype) - 1] = '\0';
+		    }
+		    break;
+		}
+	    }
+	}
+    }
+#ifdef AUTHENTICATION
+    return(auth_check(name));
+#else
+    return(-1);
+#endif
+}  /* end of getterminaltype */
+
+static void
+_gettermname()
+{
+    /*
+     * If the client turned off the option,
+     * we can't send another request, so we
+     * just return.
+     */
+    if (his_state_is_wont(TELOPT_TTYPE))
+	return;
+    settimer(baseline);
+    netwrite(ttytype_sbbuf, sizeof(ttytype_sbbuf));
+    while (sequenceIs(ttypesubopt, baseline))
+	ttloop();
+}
+
+    int
+terminaltypeok(s)
+    char *s;
+{
+    char buf[1024];
+
+    if (!*s)
+	return(1);
+
+    /*
+     * tgetent() will return 1 if the type is known, and
+     * 0 if it is not known.  If it returns -1, it couldn't
+     * open the database.  But if we can't open the database,
+     * it won't help to say we failed, because we won't be
+     * able to verify anything else.  So, we treat -1 like 1.
+     */
+    if (tgetent(buf, s) == 0)
+	return(0);
+    return(1);
+}
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+
+#ifndef MAXDNAME
+#define MAXDNAME 256 /*per the rfc*/
+#endif
+
+char *hostname;
+char host_name[MAXDNAME];
+char remote_host_name[MAXDNAME];
+char *rhost_sane;
+
+#ifndef	convex
+extern void telnet (int, int);
+#else
+extern void telnet (int, int, char *);
+#endif
+
+/*
+ * Get a pty, scan input lines.
+ */
+static void doit(who)
+	struct sockaddr *who;
+{
+	int level;
+#if	defined(_SC_CRAY_SECURE_SYS)
+	int ptynum;
+#endif
+	char user_name[256];
+	long retval;
+	/*
+	 * Find an available pty to use.
+	 */
+	pty_init();
+	
+
+	if ((retval = pty_getpty(&pty, line, 17)) != 0) {
+		fatal(net, error_message(retval));
+	}
+
+#if	defined(_SC_CRAY_SECURE_SYS)
+	/*
+	 *	set ttyp line security label 
+	 */
+	if (secflag) {
+		char slave_dev[16];
+/*xxx This code needs to be fixed to work without ptynum; I don't understand why they don't currently use line, so I don't really know how to fix.*/
+		sprintf(tty_dev, "/dev/pty/%03d", ptynum);
+		if (setdevs(tty_dev, &dv) < 0)
+		 	fatal(net, "cannot set pty security");
+		sprintf(slave_dev, "/dev/ttyp%03d", ptynum);
+		if (setdevs(slave_dev, &dv) < 0)
+		 	fatal(net, "cannot set tty security");
+	}
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+	retval = pty_make_sane_hostname((struct sockaddr *) who, maxhostlen,
+					stripdomain, always_ip,
+					&rhost_sane);
+	if (retval) {
+		fatal(net, error_message(retval));
+	}
+	if (registerd_host_only) {
+	    /* Get name of connected client -- but we don't actually
+	       use it.  Just confirm that we can get it.  */
+	    int aierror;
+	    char hostnamebuf[NI_MAXHOST];
+	    aierror = getnameinfo (who, socklen (who),
+				   hostnamebuf, sizeof (hostnamebuf), 0, 0,
+				   NI_NAMEREQD);
+	    if (aierror != 0) {
+		fatal(net,
+		      "Couldn't resolve your address into a host name.\r\n"
+		      "Please contact your net administrator");
+	    }
+	}
+
+	(void) gethostname(host_name, sizeof (host_name));
+	hostname = host_name;
+
+#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
+	auth_encrypt_init(hostname, rhost_sane, "TELNETD", 1);
+#endif
+
+	init_env();
+
+#ifdef	SIGTTOU
+	/*
+	 * Ignoring SIGTTOU keeps the kernel from blocking us.
+	 * we tweak the tty with an ioctl()
+	 * (in ttioct() in /sys/tty.c in a BSD kernel)
+	 */
+	(void) signal(SIGTTOU, SIG_IGN);
+#endif
+	/*
+	 * get terminal type.
+	 */
+	*user_name = 0;
+	level = getterminaltype(user_name);
+	setenv("TERM", *terminaltype ? terminaltype : "network", 1);
+
+#if defined (AUTHENTICATION)
+	if (level < 0 && auth_level > 0) {
+		fatal (net, "No authentication provided");
+		exit (-1);
+	}
+#endif
+	/*
+	 * Start up the login process on the slave side of the terminal
+	 */
+#ifndef	convex
+	startslave(rhost_sane, level, user_name);
+
+#if	defined(_SC_CRAY_SECURE_SYS)
+	if (secflag) {
+		if (setulvl(dv.dv_actlvl) < 0)
+			fatal(net,"cannot setulvl()");
+		if (setucmp(dv.dv_actcmp) < 0)
+			fatal(net, "cannot setucmp()");
+	}
+#endif	/* _SC_CRAY_SECURE_SYS */
+
+	telnet(net, pty);  /* begin server processing */
+#else
+	telnet(net, pty, rhost_sane);
+#endif
+	/*NOTREACHED*/
+}  /* end of doit */
+
+#if	defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
+	int
+Xterm_output(ibufp, obuf, icountp, ocount)
+	char **ibufp, *obuf;
+	int *icountp, ocount;
+{
+	int ret;
+	ret = term_output(*ibufp, obuf, *icountp, ocount);
+	*ibufp += *icountp;
+	*icountp = 0;
+	return(ret);
+}
+#define	term_output	Xterm_output
+#endif	/* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
+
+/*
+ * Main loop.  Select from pty and network, and
+ * hand data to telnet receiver finite state machine.
+ */
+	void
+#ifndef	convex
+telnet(f, p)
+#else
+telnet(f, p, host)
+#endif
+	int f, p;
+#ifdef convex
+	char *host;
+#endif
+{
+	int on = 1;
+#define	TABBUFSIZ	512
+	char	defent[TABBUFSIZ];
+	char	defstrs[TABBUFSIZ];
+#undef	TABBUFSIZ
+	char *HEstr;
+	char *HN;
+	char *IM;
+	void netflush();
+
+	/*
+	 * Initialize the slc mapping table.
+	 */
+	get_slc_defaults();
+
+	/*
+	 * Do some tests where it is desireable to wait for a response.
+	 * Rather than doing them slowly, one at a time, do them all
+	 * at once.
+	 */
+	if (my_state_is_wont(TELOPT_SGA))
+		send_will(TELOPT_SGA, 1);
+	/*
+	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
+	 * because 4.2 clients are unable to deal with TCP urgent data.
+	 *
+	 * To find out, we send out a "DO ECHO".  If the remote system
+	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
+	 * that fact ("WILL ECHO" ==> that the client will echo what
+	 * WE, the server, sends it; it does NOT mean that the client will
+	 * echo the terminal input).
+	 */
+	send_do(TELOPT_ECHO, 1);
+
+#ifdef	LINEMODE
+	if (his_state_is_wont(TELOPT_LINEMODE)) {
+		/* Query the peer for linemode support by trying to negotiate
+		 * the linemode option.
+		 */
+		linemode = 0;
+		editmode = 0;
+		send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
+	}
+#endif	/* LINEMODE */
+
+	/*
+	 * Send along a couple of other options that we wish to negotiate.
+	 */
+	send_do(TELOPT_NAWS, 1);
+	send_will(TELOPT_STATUS, 1);
+	flowmode = 1;		/* default flow control state */
+	restartany = -1;	/* uninitialized... */
+	send_do(TELOPT_LFLOW, 1);
+
+	/*
+	 * Spin, waiting for a response from the DO ECHO.  However,
+	 * some REALLY DUMB telnets out there might not respond
+	 * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
+	 * telnets so far seem to respond with WONT for a DO that
+	 * they don't understand...) because by the time we get the
+	 * response, it will already have processed the DO ECHO.
+	 * Kludge upon kludge.
+	 */
+	while (his_will_wont_is_changing(TELOPT_NAWS))
+		ttloop();
+
+	/*
+	 * But...
+	 * The client might have sent a WILL NAWS as part of its
+	 * startup code; if so, we'll be here before we get the
+	 * response to the DO ECHO.  We'll make the assumption
+	 * that any implementation that understands about NAWS
+	 * is a modern enough implementation that it will respond
+	 * to our DO ECHO request; hence we'll do another spin
+	 * waiting for the ECHO option to settle down, which is
+	 * what we wanted to do in the first place...
+	 */
+	if (his_want_state_is_will(TELOPT_ECHO) &&
+	    his_state_is_will(TELOPT_NAWS)) {
+		while (his_will_wont_is_changing(TELOPT_ECHO))
+			ttloop();
+	}
+	/*
+	 * On the off chance that the telnet client is broken and does not
+	 * respond to the DO ECHO we sent, (after all, we did send the
+	 * DO NAWS negotiation after the DO ECHO, and we won't get here
+	 * until a response to the DO NAWS comes back) simulate the
+	 * receipt of a will echo.  This will also send a WONT ECHO
+	 * to the client, since we assume that the client failed to
+	 * respond because it believes that it is already in DO ECHO
+	 * mode, which we do not want.
+	 */
+	if (his_want_state_is_will(TELOPT_ECHO)) {
+		DIAG(TD_OPTIONS, netputs("td: simulating recv\r\n"));
+		willoption(TELOPT_ECHO);
+	}
+
+	/*
+	 * Finally, to clean things up, we turn on our echo.  This
+	 * will break stupid 4.2 telnets out of local terminal echo.
+	 */
+
+	if (my_state_is_wont(TELOPT_ECHO))
+		send_will(TELOPT_ECHO, 1);
+
+#ifndef	STREAMSPTY
+	/*
+	 * Turn on packet mode
+	 */
+	(void) ioctl(p, TIOCPKT, (char *)&on);
+#endif
+
+#if	defined(LINEMODE) && defined(KLUDGELINEMODE)
+	/*
+	 * Continuing line mode support.  If client does not support
+	 * real linemode, attempt to negotiate kludge linemode by sending
+	 * the do timing mark sequence.
+	 */
+	if (lmodetype < REAL_LINEMODE)
+		send_do(TELOPT_TM, 1);
+#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+
+	/*
+	 * Call telrcv() once to pick up anything received during
+	 * terminal type negotiation, 4.2/4.3 determination, and
+	 * linemode negotiation.
+	 */
+	telrcv();
+
+	(void) ioctl(f, FIONBIO, (char *)&on);
+	(void) ioctl(p, FIONBIO, (char *)&on);
+#if	defined(CRAY2) && defined(UNICOS5)
+	init_termdriver(f, p, interrupt, sendbrk);
+#endif
+
+#if	defined(SO_OOBINLINE)
+	(void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
+				(char *)&on, sizeof(on));
+#endif	/* defined(SO_OOBINLINE) */
+
+#ifdef	SIGTSTP
+	(void) signal(SIGTSTP, SIG_IGN);
+#endif
+
+	(void) signal(SIGCHLD, cleanup);
+
+#if	defined(CRAY2) && defined(UNICOS5)
+	/*
+	 * Cray-2 will send a signal when pty modes are changed by slave
+	 * side.  Set up signal handler now.
+	 */
+	if ((int)signal(SIGUSR1, termstat) < 0)
+		perror("signal");
+	else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
+		perror("ioctl:TCSIGME");
+	/*
+	 * Make processing loop check terminal characteristics early on.
+	 */
+	termstat();
+#endif
+
+#ifdef  TIOCNOTTY
+	{
+		register int t;
+		t = open(_PATH_TTY, O_RDWR);
+		if (t >= 0) {
+			(void) ioctl(t, TIOCNOTTY, (char *)0);
+			(void) close(t);
+		}
+	}
+#endif
+
+#if	defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
+	(void) setsid();
+	ioctl(p, TIOCSCTTY, 0);
+#endif
+
+	/*
+	 * Show banner that getty never gave.
+	 *
+	 * We put the banner in the pty input buffer.  This way, it
+	 * gets carriage return null processing, etc., just like all
+	 * other pty --> client data.
+	 */
+
+#if	!defined(CRAY) || !defined(NEWINIT)
+	if (getenv("USER"))
+		hostinfo = 0;
+#endif
+
+	if (getent(defent, "default") == 1) {
+		char *getstr();
+		char *cp=defstrs;
+
+		HEstr = getstr("he", &cp);
+		HN = getstr("hn", &cp);
+		IM = getstr("im", &cp);
+		if (HN && *HN)
+			(void) strncpy(host_name, HN, sizeof(host_name) - 1);
+		host_name[sizeof(host_name) - 1] = '\0';
+		if (IM == 0)
+			IM = "";
+	} else {
+		IM = get_default_IM();
+		HEstr = 0;
+	}
+	edithost(HEstr, host_name);
+	if (hostinfo && *IM)
+		putf(IM, ptyibuf2);
+
+	if (pcc)
+		(void) strncat(ptyibuf2, ptyip, pcc+1);
+	ptyip = ptyibuf2;
+	pcc = strlen(ptyip);
+#ifdef	LINEMODE
+	/*
+	 * Last check to make sure all our states are correct.
+	 */
+	init_termbuf();
+	localstat();
+#endif	/* LINEMODE */
+
+	DIAG(TD_REPORT, netputs("td: Entering processing loop\r\n"));
+
+#ifdef	convex
+	startslave(host);
+#endif
+
+	for (;;) {
+		fd_set ibits, obits, xbits;
+		register int c;
+
+		if (ncc < 0 && pcc < 0)
+			break;
+
+#if	defined(CRAY2) && defined(UNICOS5)
+		if (needtermstat)
+			_termstat();
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+		FD_ZERO(&ibits);
+		FD_ZERO(&obits);
+		FD_ZERO(&xbits);
+		/*
+		 * Never look for input if there's still
+		 * stuff in the corresponding output buffer
+		 */
+		if (nfrontp - nbackp || pcc > 0) {
+			FD_SET(f, &obits);
+		} else {
+			FD_SET(p, &ibits);
+		}
+		if (pfrontp - pbackp || ncc > 0) {
+			FD_SET(p, &obits);
+		} else {
+			FD_SET(f, &ibits);
+		}
+		if (!SYNCHing) {
+			FD_SET(f, &xbits);
+		}
+		if ((c = select(16, &ibits, &obits, &xbits,
+						(struct timeval *)0)) < 1) {
+			if (c == -1) {
+				if (errno == EINTR) {
+					continue;
+				}
+			}
+			sleep(5);
+			continue;
+		}
+
+		/*
+		 * Any urgent data?
+		 */
+		if (FD_ISSET(net, &xbits)) {
+		    SYNCHing = 1;
+		}
+
+		/*
+		 * Something to read from the network...
+		 */
+		if (FD_ISSET(net, &ibits)) {
+#if	!defined(SO_OOBINLINE)
+			/*
+			 * In 4.2 (and 4.3 beta) systems, the
+			 * OOB indication and data handling in the kernel
+			 * is such that if two separate TCP Urgent requests
+			 * come in, one byte of TCP data will be overlaid.
+			 * This is fatal for Telnet, but we try to live
+			 * with it.
+			 *
+			 * In addition, in 4.2 (and...), a special protocol
+			 * is needed to pick up the TCP Urgent data in
+			 * the correct sequence.
+			 *
+			 * What we do is:  if we think we are in urgent
+			 * mode, we look to see if we are "at the mark".
+			 * If we are, we do an OOB receive.  If we run
+			 * this twice, we will do the OOB receive twice,
+			 * but the second will fail, since the second
+			 * time we were "at the mark", but there wasn't
+			 * any data there (the kernel doesn't reset
+			 * "at the mark" until we do a normal read).
+			 * Once we've read the OOB data, we go ahead
+			 * and do normal reads.
+			 *
+			 * There is also another problem, which is that
+			 * since the OOB byte we read doesn't put us
+			 * out of OOB state, and since that byte is most
+			 * likely the TELNET DM (data mark), we would
+			 * stay in the TELNET SYNCH (SYNCHing) state.
+			 * So, clocks to the rescue.  If we've "just"
+			 * received a DM, then we test for the
+			 * presence of OOB data when the receive OOB
+			 * fails (and AFTER we did the normal mode read
+			 * to clear "at the mark").
+			 */
+		    if (SYNCHing) {
+			int atmark;
+
+			(void) ioctl(net, SIOCATMARK, (char *)&atmark);
+			if (atmark) {
+			    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
+			    if ((ncc == -1) && (errno == EINVAL)) {
+				ncc = read(net, netibuf, sizeof (netibuf));
+				if (sequenceIs(didnetreceive, gotDM)) {
+				    SYNCHing = stilloob(net);
+				}
+			    }
+			} else {
+			    ncc = read(net, netibuf, sizeof (netibuf));
+			}
+		    } else {
+			ncc = read(net, netibuf, sizeof (netibuf));
+		    }
+		    settimer(didnetreceive);
+#else	/* !defined(SO_OOBINLINE)) */
+		    ncc = read(net, netibuf, sizeof (netibuf));
+#endif	/* !defined(SO_OOBINLINE)) */
+		    if (ncc < 0 && errno == EWOULDBLOCK)
+			ncc = 0;
+		    else {
+			if (ncc <= 0) {
+			    break;
+			}
+			netip = netibuf;
+		    }
+		    DIAG((TD_REPORT | TD_NETDATA),
+			 netprintf("td: netread %d chars\r\n", ncc));
+		    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
+		}
+
+		/*
+		 * Something to read from the pty...
+		 */
+		if (FD_ISSET(p, &ibits)) {
+#ifndef	STREAMSPTY
+			pcc = read(p, ptyibuf, BUFSIZ);
+#else
+			pcc = readstream(p, ptyibuf, BUFSIZ);
+#endif
+			/*
+			 * On some systems, if we try to read something
+			 * off the master side before the slave side is
+			 * opened, we get EIO.
+			 */
+			if (pcc < 0 && (errno == EWOULDBLOCK ||
+#ifdef	EAGAIN
+					errno == EAGAIN ||
+#endif
+					errno == EIO)) {
+				pcc = 0;
+			} else {
+				if (pcc <= 0)
+					break;
+#if	!defined(CRAY2) || !defined(UNICOS5)
+#ifdef	LINEMODE
+				/*
+				 * If ioctl from pty, pass it through net
+				 */
+				if (ptyibuf[0] & TIOCPKT_IOCTL) {
+					copy_termbuf(ptyibuf+1, pcc-1);
+					localstat();
+					pcc = 1;
+				}
+#endif	/* LINEMODE */
+				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
+					netclear();	/* clear buffer back */
+#ifndef	NO_URGENT
+					/*
+					 * There are client telnets on some
+					 * operating systems get screwed up
+					 * royally if we send them urgent
+					 * mode data.
+					 */
+					netprintf_urg("%c%c", IAC, DM);
+#endif
+				}
+				if (his_state_is_will(TELOPT_LFLOW) &&
+				    (ptyibuf[0] &
+				     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
+					int newflow =
+					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
+					if (newflow != flowmode) {
+						flowmode = newflow;
+						netprintf("%c%c%c%c%c%c",
+							IAC, SB, TELOPT_LFLOW,
+							flowmode ? LFLOW_ON
+								 : LFLOW_OFF,
+							IAC, SE);
+					}
+				}
+				pcc--;
+				ptyip = ptyibuf+1;
+#else	/* defined(CRAY2) && defined(UNICOS5) */
+				if (!uselinemode) {
+					unpcc = pcc;
+					unptyip = ptyibuf;
+					pcc = term_output(&unptyip, ptyibuf2,
+								&unpcc, BUFSIZ);
+					ptyip = ptyibuf2;
+				} else
+					ptyip = ptyibuf;
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+			}
+		}
+
+		while (pcc > 0) {
+			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
+				break;
+			c = *ptyip++ & 0377, pcc--;
+			if (c == IAC)
+				netprintf("%c", c);
+#if	defined(CRAY2) && defined(UNICOS5)
+			else if (c == '\n' &&
+				     my_state_is_wont(TELOPT_BINARY) && newmap)
+				netputs("\r");
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+			netprintf("%c", c);
+			if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
+				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
+					netprintf("%c", *ptyip++ & 0377);
+					pcc--;
+				} else
+					netprintf("%c", '\0');
+			}
+		}
+#if	defined(CRAY2) && defined(UNICOS5)
+		/*
+		 * If chars were left over from the terminal driver,
+		 * note their existence.
+		 */
+		if (!uselinemode && unpcc) {
+			pcc = unpcc;
+			unpcc = 0;
+			ptyip = unptyip;
+		}
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+
+		if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
+			netflush();
+		if (ncc > 0)
+			telrcv();
+		if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
+			ptyflush();
+	}
+	(void) signal(SIGCHLD, SIG_DFL);
+	cleanup(0);
+}  /* end of telnet */
+	
+#ifndef	TCSIG
+# ifdef	TIOCSIG
+#  define TCSIG TIOCSIG
+# endif
+#endif
+
+#ifdef	STREAMSPTY
+
+int flowison = -1;  /* current state of flow: -1 is unknown */
+
+int readstream(p, ibuf, bufsize)
+	int p;
+	char *ibuf;
+	int bufsize;
+{
+	int flags = 0;
+	int ret = 0;
+	struct termios *tsp;
+	struct termio *tp;
+	struct iocblk *ip;
+	char vstop, vstart;
+	int ixon;
+	int newflow;
+
+	strbufc.maxlen = BUFSIZ;
+	strbufc.buf = (char *)ctlbuf;
+	strbufd.maxlen = bufsize-1;
+	strbufd.len = 0;
+	strbufd.buf = ibuf+1;
+	ibuf[0] = 0;
+
+	ret = getmsg(p, &strbufc, &strbufd, &flags);
+	if (ret < 0)  /* error of some sort -- probably EAGAIN */
+		return(-1);
+
+	if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
+		/* data message */
+		if (strbufd.len > 0) {			/* real data */
+			return(strbufd.len + 1);	/* count header char */
+		} else {
+			/* nothing there */
+			errno = EAGAIN;
+			return(-1);
+		}
+	}
+
+	/*
+	 * It's a control message.  Return 1, to look at the flag we set
+	 */
+
+	switch (ctlbuf[0]) {
+	case M_FLUSH:
+		if (ibuf[1] & FLUSHW)
+			ibuf[0] = TIOCPKT_FLUSHWRITE;
+		return(1);
+
+	case M_IOCTL:
+		ip = (struct iocblk *) (ibuf+1);
+		if (readstream_termio(ip->ioc_cmd, ibuf, 
+				      &vstop, &vstart, &ixon)) {
+		  if (readstream_termios(ip->ioc_cmd, ibuf, 
+					 &vstop, &vstart, &ixon)) {
+		    errno = EAGAIN;
+		    return(-1);
+		  }
+		}
+
+		newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
+		if (newflow != flowison) {  /* it's a change */
+			flowison = newflow;
+			ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
+			return(1);
+		}
+	}
+
+	/* nothing worth doing anything about */
+	errno = EAGAIN;
+	return(-1);
+}
+#endif /* STREAMSPTY */
+
+/*
+ * Send interrupt to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write intr char.
+ */
+	void
+interrupt()
+{
+	ptyflush();	/* half-hearted */
+
+#ifdef	TCSIG
+	(void) ioctl(pty, TCSIG, (char *)SIGINT);
+#else	/* TCSIG */
+	init_termbuf();
+	*pfrontp++ = slctab[SLC_IP].sptr ?
+			(unsigned char)*slctab[SLC_IP].sptr : '\177';
+#endif	/* TCSIG */
+}
+
+/*
+ * Send quit to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write quit char.
+ */
+	void
+sendbrk()
+{
+	ptyflush();	/* half-hearted */
+#ifdef	TCSIG
+	(void) ioctl(pty, TCSIG, (char *)SIGQUIT);
+#else	/* TCSIG */
+	init_termbuf();
+	*pfrontp++ = slctab[SLC_ABORT].sptr ?
+			(unsigned char)*slctab[SLC_ABORT].sptr : '\034';
+#endif	/* TCSIG */
+}
+
+	void
+sendsusp()
+{
+#ifdef	SIGTSTP
+	ptyflush();	/* half-hearted */
+# ifdef	TCSIG
+	(void) ioctl(pty, TCSIG, (char *)SIGTSTP);
+# else	/* TCSIG */
+	*pfrontp++ = slctab[SLC_SUSP].sptr ?
+			(unsigned char)*slctab[SLC_SUSP].sptr : '\032';
+# endif	/* TCSIG */
+#endif	/* SIGTSTP */
+}
+
+/*
+ * When we get an AYT, if ^T is enabled, use that.  Otherwise,
+ * just send back "[Yes]".
+ */
+void
+recv_ayt()
+{
+#if	defined(SIGINFO) && defined(TCSIG)
+	if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
+		(void) ioctl(pty, TCSIG, (char *)SIGINFO);
+		return;
+	}
+#endif
+	netputs("\r\n[Yes]\r\n");
+}
+
+	void
+doeof()
+{
+	init_termbuf();
+
+#if	defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
+	if (!tty_isediting()) {
+		extern char oldeofc;
+		*pfrontp++ = oldeofc;
+		return;
+	}
+#endif
+	*pfrontp++ = slctab[SLC_EOF].sptr ?
+			(unsigned char)*slctab[SLC_EOF].sptr : '\004';
+}
diff --git a/mechglue/src/appl/telnet/telnetd/telnetd.h b/mechglue/src/appl/telnet/telnetd/telnetd.h
new file mode 100644
index 000000000..f21f617e5
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/telnetd.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)telnetd.h	8.1 (Berkeley) 6/4/93
+ */
+
+
+#include "defs.h"
+#include "ext.h"
+
+#ifdef	DIAGNOSTICS
+#define	DIAG(a,b)	if (diagnostic & (a)) b
+#else
+#define	DIAG(a,b)
+#endif
+
+/* other external variables */
+extern	char **environ;
+
diff --git a/mechglue/src/appl/telnet/telnetd/termio-tn.c b/mechglue/src/appl/telnet/telnetd/termio-tn.c
new file mode 100644
index 000000000..c34f5eb16
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/termio-tn.c
@@ -0,0 +1,33 @@
+/* handle having mutually exclusive termio vs. termios */
+/* return 0 if handled */
+#ifdef	STREAMSPTY
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/ioctl.h>
+#include <termio.h>
+
+int readstream_termio(cmd, ibuf, vstop, vstart, ixon)
+     int cmd;
+     char *ibuf;
+     char *vstop, *vstart;
+     int *ixon;
+{
+  struct termio *tp;
+  switch (cmd) {
+  case TCSETA:
+  case TCSETAW:
+  case TCSETAF:
+    tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
+#if 0				/* VSTOP/VSTART only in termios!? */
+    *vstop = tp->c_cc[VSTOP];
+    *vstart = tp->c_cc[VSTART];
+#endif
+    *ixon = tp->c_iflag & IXON;      
+    return 0;
+  }
+  return -1;
+}
+
+#else
+int silence_warnings_about_empty_source_file_termio = 42;
+#endif /* STREAMSPTY */
diff --git a/mechglue/src/appl/telnet/telnetd/termios-tn.c b/mechglue/src/appl/telnet/telnetd/termios-tn.c
new file mode 100644
index 000000000..3e5488371
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/termios-tn.c
@@ -0,0 +1,35 @@
+/* handle having mutually exclusive termio vs. termios */
+/* return 0 if handled */
+#ifdef	STREAMSPTY
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#if !defined(TCSETS) && defined(_AIX) /* kludge for AIX */
+#include <termio.h>
+#endif
+
+int readstream_termios(cmd, ibuf, vstop, vstart, ixon)
+     int cmd;
+     char *ibuf;
+     char *vstop, *vstart;
+     int *ixon;
+{
+  struct termios *tsp;
+  switch (cmd) {
+  case TCSETS:
+  case TCSETSW:
+  case TCSETSF:
+    tsp = (struct termios *)
+      (ibuf+1 + sizeof(struct iocblk));
+    *vstop = tsp->c_cc[VSTOP];
+    *vstart = tsp->c_cc[VSTART];
+    *ixon = tsp->c_iflag & IXON;
+    return 0;
+  }
+  return -1;
+}
+
+#else
+int silence_warnings_about_empty_source_file_termios = 42;
+#endif /* STREAMSPTY */
diff --git a/mechglue/src/appl/telnet/telnetd/termstat.c b/mechglue/src/appl/telnet/telnetd/termstat.c
new file mode 100644
index 000000000..531e16783
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/termstat.c
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)termstat.c	8.1 (Berkeley) 6/4/93 */
+
+#include "telnetd.h"
+
+/*
+ * local variables
+ */
+int def_tspeed = -1, def_rspeed = -1;
+#ifdef	TIOCSWINSZ
+int def_row = 0, def_col = 0;
+#endif
+#ifdef	LINEMODE
+static int _terminit = 0;
+#endif	/* LINEMODE */
+
+#if	defined(CRAY2) && defined(UNICOS5)
+int	newmap = 1;	/* nonzero if \n maps to ^M^J */
+#endif
+
+#ifdef	LINEMODE
+/*
+ * localstat
+ *
+ * This function handles all management of linemode.
+ *
+ * Linemode allows the client to do the local editing of data
+ * and send only complete lines to the server.  Linemode state is
+ * based on the state of the pty driver.  If the pty is set for
+ * external processing, then we can use linemode.  Further, if we
+ * can use real linemode, then we can look at the edit control bits
+ * in the pty to determine what editing the client should do.
+ *
+ * Linemode support uses the following state flags to keep track of
+ * current and desired linemode state.
+ *	alwayslinemode : true if -l was specified on the telnetd
+ * 	command line.  It means to have linemode on as much as
+ *	possible.
+ *
+ * 	lmodetype: signifies whether the client can
+ *	handle real linemode, or if use of kludgeomatic linemode
+ *	is preferred.  It will be set to one of the following:
+ *		REAL_LINEMODE : use linemode option
+ *		NO_KLUDGE : don't initiate kludge linemode.
+ *		KLUDGE_LINEMODE : use kludge linemode
+ *		NO_LINEMODE : client is ignorant of linemode
+ *
+ *	linemode, uselinemode : linemode is true if linemode
+ *	is currently on, uselinemode is the state that we wish
+ *	to be in.  If another function wishes to turn linemode
+ *	on or off, it sets or clears uselinemode.
+ *
+ *	editmode, useeditmode : like linemode/uselinemode, but
+ *	these contain the edit mode states (edit and trapsig).
+ *
+ * The state variables correspond to some of the state information
+ * in the pty.
+ *	linemode:
+ *		In real linemode, this corresponds to whether the pty
+ *		expects external processing of incoming data.
+ *		In kludge linemode, this more closely corresponds to the
+ *		whether normal processing is on or not.  (ICANON in
+ *		system V, or COOKED mode in BSD.)
+ *		If the -l option was specified (alwayslinemode), then
+ *		an attempt is made to force external processing on at
+ *		all times.
+ *
+ * The following heuristics are applied to determine linemode
+ * handling within the server.
+ *	1) Early on in starting up the server, an attempt is made
+ *	   to negotiate the linemode option.  If this succeeds
+ *	   then lmodetype is set to REAL_LINEMODE and all linemode
+ *	   processing occurs in the context of the linemode option.
+ *	2) If the attempt to negotiate the linemode option failed,
+ *	   and the "-k" (don't initiate kludge linemode) isn't set,
+ *	   then we try to use kludge linemode.  We test for this
+ *	   capability by sending "do Timing Mark".  If a positive
+ *	   response comes back, then we assume that the client
+ *	   understands kludge linemode (ech!) and the
+ *	   lmodetype flag is set to KLUDGE_LINEMODE.
+ *	3) Otherwise, linemode is not supported at all and
+ *	   lmodetype remains set to NO_LINEMODE (which happens
+ *	   to be 0 for convenience).
+ *	4) At any time a command arrives that implies a higher
+ *	   state of linemode support in the client, we move to that
+ *	   linemode support.
+ *
+ * A short explanation of kludge linemode is in order here.
+ *	1) The heuristic to determine support for kludge linemode
+ *	   is to send a do timing mark.  We assume that a client
+ *	   that supports timing marks also supports kludge linemode.
+ *	   A risky proposition at best.
+ *	2) Further negotiation of linemode is done by changing the
+ *	   the server's state regarding SGA.  If server will SGA,
+ *	   then linemode is off, if server won't SGA, then linemode
+ *	   is on.
+ */
+	void
+localstat()
+{
+	void netflush();
+	int need_will_echo = 0;
+
+#if	defined(CRAY2) && defined(UNICOS5)
+	/*
+	 * Keep track of that ol' CR/NL mapping while we're in the
+	 * neighborhood.
+	 */
+	newmap = tty_isnewmap();
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+
+	/*
+	 * Check for state of BINARY options.
+	 */
+	if (tty_isbinaryin()) {
+		if (his_want_state_is_wont(TELOPT_BINARY))
+			send_do(TELOPT_BINARY, 1);
+	} else {
+		if (his_want_state_is_will(TELOPT_BINARY))
+			send_dont(TELOPT_BINARY, 1);
+	}
+
+	if (tty_isbinaryout()) {
+		if (my_want_state_is_wont(TELOPT_BINARY))
+			send_will(TELOPT_BINARY, 1);
+	} else {
+		if (my_want_state_is_will(TELOPT_BINARY))
+			send_wont(TELOPT_BINARY, 1);
+	}
+
+	/*
+	 * Check for changes to flow control if client supports it.
+	 */
+	flowstat();
+
+	/*
+	 * Check linemode on/off state
+	 */
+	uselinemode = tty_linemode();
+
+	/*
+	 * If alwayslinemode is on, and pty is changing to turn it off, then
+	 * force linemode back on.
+	 */
+	if (alwayslinemode && linemode && !uselinemode) {
+		uselinemode = 1;
+		tty_setlinemode(uselinemode);
+	}
+
+#ifdef	ENCRYPTION
+	/*
+	 * If the terminal is not echoing, but editing is enabled,
+	 * something like password input is going to happen, so
+	 * if we the other side is not currently sending encrypted
+	 * data, ask the other side to start encrypting.
+	 */
+	if (his_state_is_will(TELOPT_ENCRYPT)) {
+		static int enc_passwd = 0;
+		if (uselinemode && !tty_isecho() && tty_isediting()
+		    && (enc_passwd == 0) && !decrypt_input) {
+			encrypt_send_request_start();
+			enc_passwd = 1;
+		} else if (enc_passwd) {
+			encrypt_send_request_end();
+			enc_passwd = 0;
+		}
+	}
+#endif	/* ENCRYPTION */
+
+	/*
+	 * Do echo mode handling as soon as we know what the
+	 * linemode is going to be.
+	 * If the pty has echo turned off, then tell the client that
+	 * the server will echo.  If echo is on, then the server
+	 * will echo if in character mode, but in linemode the
+	 * client should do local echoing.  The state machine will
+	 * not send anything if it is unnecessary, so don't worry
+	 * about that here.
+	 *
+	 * If we need to send the WILL ECHO (because echo is off),
+	 * then delay that until after we have changed the MODE.
+	 * This way, when the user is turning off both editing
+	 * and echo, the client will get editing turned off first.
+	 * This keeps the client from going into encryption mode
+	 * and then right back out if it is doing auto-encryption
+	 * when passwords are being typed.
+	 */
+	if (uselinemode) {
+		if (tty_isecho())
+			send_wont(TELOPT_ECHO, 1);
+		else
+			need_will_echo = 1;
+#ifdef	KLUDGELINEMODE
+		if (lmodetype == KLUDGE_OK)
+			lmodetype = KLUDGE_LINEMODE;
+#endif
+	}
+
+	/*
+	 * If linemode is being turned off, send appropriate
+	 * command and then we're all done.
+	 */
+	 if (!uselinemode && linemode) {
+# ifdef	KLUDGELINEMODE
+		if (lmodetype == REAL_LINEMODE) {
+# endif	/* KLUDGELINEMODE */
+			send_dont(TELOPT_LINEMODE, 1);
+# ifdef	KLUDGELINEMODE
+		} else if (lmodetype == KLUDGE_LINEMODE)
+			send_will(TELOPT_SGA, 1);
+# endif	/* KLUDGELINEMODE */
+		send_will(TELOPT_ECHO, 1);
+		linemode = uselinemode;
+		goto done;
+	}
+
+# ifdef	KLUDGELINEMODE
+	/*
+	 * If using real linemode check edit modes for possible later use.
+	 * If we are in kludge linemode, do the SGA negotiation.
+	 */
+	if (lmodetype == REAL_LINEMODE) {
+# endif	/* KLUDGELINEMODE */
+		useeditmode = 0;
+		if (tty_isediting())
+			useeditmode |= MODE_EDIT;
+		if (tty_istrapsig())
+			useeditmode |= MODE_TRAPSIG;
+		if (tty_issofttab())
+			useeditmode |= MODE_SOFT_TAB;
+		if (tty_islitecho())
+			useeditmode |= MODE_LIT_ECHO;
+# ifdef	KLUDGELINEMODE
+	} else if (lmodetype == KLUDGE_LINEMODE) {
+		if (tty_isediting() && uselinemode)
+			send_wont(TELOPT_SGA, 1);
+		else
+			send_will(TELOPT_SGA, 1);
+	}
+# endif	/* KLUDGELINEMODE */
+
+	/*
+	 * Negotiate linemode on if pty state has changed to turn it on.
+	 * Send appropriate command and send along edit mode, then all done.
+	 */
+	if (uselinemode && !linemode) {
+# ifdef	KLUDGELINEMODE
+		if (lmodetype == KLUDGE_LINEMODE) {
+			send_wont(TELOPT_SGA, 1);
+		} else if (lmodetype == REAL_LINEMODE) {
+# endif	/* KLUDGELINEMODE */
+			send_do(TELOPT_LINEMODE, 1);
+			/* send along edit modes */
+			netprintf("%c%c%c%c%c%c%c", IAC, SB,
+				TELOPT_LINEMODE, LM_MODE, useeditmode,
+				IAC, SE);
+			editmode = useeditmode;
+# ifdef	KLUDGELINEMODE
+		}
+# endif	/* KLUDGELINEMODE */
+		linemode = uselinemode;
+		goto done;
+	}
+
+# ifdef	KLUDGELINEMODE
+	/*
+	 * None of what follows is of any value if not using
+	 * real linemode.
+	 */
+	if (lmodetype < REAL_LINEMODE)
+		goto done;
+# endif	/* KLUDGELINEMODE */
+
+	if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
+		/*
+		 * If edit mode changed, send edit mode.
+		 */
+		 if (useeditmode != editmode) {
+			/*
+			 * Send along appropriate edit mode mask.
+			 */
+			(void) netprintf("%c%c%c%c%c%c%c", IAC, SB,
+				TELOPT_LINEMODE, LM_MODE, useeditmode,
+				IAC, SE);
+			editmode = useeditmode;
+		}
+							
+
+		/*
+		 * Check for changes to special characters in use.
+		 */
+		start_slc(0);
+		check_slc();
+		(void) end_slc(0);
+	}
+
+done:
+	if (need_will_echo)
+		send_will(TELOPT_ECHO, 1);
+	/*
+	 * Some things should be deferred until after the pty state has
+	 * been set by the local process.  Do those things that have been
+	 * deferred now.  This only happens once.
+	 */
+	if (_terminit == 0) {
+		_terminit = 1;
+		defer_terminit();
+	}
+
+	netflush();
+	set_termbuf();
+	return;
+
+}  /* end of localstat */
+#endif	/* LINEMODE */
+
+/*
+ * flowstat
+ *
+ * Check for changes to flow control
+ */
+	void
+flowstat()
+{
+	if (his_state_is_will(TELOPT_LFLOW)) {
+		if (tty_flowmode() != flowmode) {
+			flowmode = tty_flowmode();
+			netprintf("%c%c%c%c%c%c",
+					IAC, SB, TELOPT_LFLOW,
+					flowmode ? LFLOW_ON : LFLOW_OFF,
+					IAC, SE);
+		}
+		if (tty_restartany() != restartany) {
+			restartany = tty_restartany();
+			netprintf("%c%c%c%c%c%c",
+					IAC, SB, TELOPT_LFLOW,
+					restartany ? LFLOW_RESTART_ANY
+						   : LFLOW_RESTART_XON,
+					IAC, SE);
+		}
+	}
+}
+
+/*
+ * clientstat
+ *
+ * Process linemode related requests from the client.
+ * Client can request a change to only one of linemode, editmode or slc's
+ * at a time, and if using kludge linemode, then only linemode may be
+ * affected.
+ */
+	void
+clientstat(code, parm1, parm2)
+	register int code, parm1, parm2;
+{
+	void netflush();
+
+	/*
+	 * Get a copy of terminal characteristics.
+	 */
+	init_termbuf();
+
+	/*
+	 * Process request from client. code tells what it is.
+	 */
+	switch (code) {
+#ifdef	LINEMODE
+	case TELOPT_LINEMODE:
+		/*
+		 * Don't do anything unless client is asking us to change
+		 * modes.
+		 */
+		uselinemode = (parm1 == WILL);
+		if (uselinemode != linemode) {
+# ifdef	KLUDGELINEMODE
+			/*
+			 * If using kludge linemode, make sure that
+			 * we can do what the client asks.
+			 * We can not turn off linemode if alwayslinemode
+			 * and the ICANON bit is set.
+			 */
+			if (lmodetype == KLUDGE_LINEMODE) {
+				if (alwayslinemode && tty_isediting()) {
+					uselinemode = 1;
+				}
+			}
+		
+			/*
+			 * Quit now if we can't do it.
+			 */
+			if (uselinemode == linemode)
+				return;
+
+			/*
+			 * If using real linemode and linemode is being
+			 * turned on, send along the edit mode mask.
+			 */
+			if (lmodetype == REAL_LINEMODE && uselinemode)
+# else	/* KLUDGELINEMODE */
+			if (uselinemode)
+# endif	/* KLUDGELINEMODE */
+			{
+				useeditmode = 0;
+				if (tty_isediting())
+					useeditmode |= MODE_EDIT;
+				if (tty_istrapsig)
+					useeditmode |= MODE_TRAPSIG;
+				if (tty_issofttab())
+					useeditmode |= MODE_SOFT_TAB;
+				if (tty_islitecho())
+					useeditmode |= MODE_LIT_ECHO;
+				netprintf("%c%c%c%c%c%c%c", IAC,
+					SB, TELOPT_LINEMODE, LM_MODE,
+					useeditmode, IAC, SE);
+				editmode = useeditmode;
+			}
+
+
+			tty_setlinemode(uselinemode);
+
+			linemode = uselinemode;
+
+			if (!linemode)
+				send_will(TELOPT_ECHO, 1);
+		}
+		break;
+	
+	case LM_MODE:
+	    {
+		register int ack, changed;
+
+		/*
+		 * Client has sent along a mode mask.  If it agrees with
+		 * what we are currently doing, ignore it; if not, it could
+		 * be viewed as a request to change.  Note that the server
+		 * will change to the modes in an ack if it is different from
+		 * what we currently have, but we will not ack the ack.
+		 */
+		 useeditmode &= MODE_MASK;
+		 ack = (useeditmode & MODE_ACK);
+		 useeditmode &= ~MODE_ACK;
+
+		 if (changed = (useeditmode ^ editmode)) {
+			/*
+			 * This check is for a timing problem.  If the
+			 * state of the tty has changed (due to the user
+			 * application) we need to process that info
+			 * before we write in the state contained in the
+			 * ack!!!  This gets out the new MODE request,
+			 * and when the ack to that command comes back
+			 * we'll set it and be in the right mode.
+			 */
+			if (ack)
+				localstat();
+			if (changed & MODE_EDIT)
+				tty_setedit(useeditmode & MODE_EDIT);
+
+			if (changed & MODE_TRAPSIG)
+				tty_setsig(useeditmode & MODE_TRAPSIG);
+
+			if (changed & MODE_SOFT_TAB)
+				tty_setsofttab(useeditmode & MODE_SOFT_TAB);
+
+			if (changed & MODE_LIT_ECHO)
+				tty_setlitecho(useeditmode & MODE_LIT_ECHO);
+
+			set_termbuf();
+
+ 			if (!ack) {
+ 				netprintf("%c%c%c%c%c%c%c", IAC,
+					SB, TELOPT_LINEMODE, LM_MODE,
+ 					useeditmode|MODE_ACK,
+ 					IAC, SE);
+ 			}
+ 		
+			editmode = useeditmode;
+		}
+
+		break;
+
+	    }  /* end of case LM_MODE */
+#endif	/* LINEMODE */
+
+	case TELOPT_NAWS:
+#ifdef	TIOCSWINSZ
+	    {
+		struct winsize ws;
+
+		def_col = parm1;
+		def_row = parm2;
+#ifdef	LINEMODE
+		/*
+		 * Defer changing window size until after terminal is
+		 * initialized.
+		 */
+		if (terminit() == 0)
+			return;
+#endif	/* LINEMODE */
+
+		/*
+		 * Change window size as requested by client.
+		 */
+
+		ws.ws_col = parm1;
+		ws.ws_row = parm2;
+		(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
+	    }
+#endif	/* TIOCSWINSZ */
+		
+		break;
+	
+	case TELOPT_TSPEED:
+	    {
+		def_tspeed = parm1;
+		def_rspeed = parm2;
+#ifdef	LINEMODE
+		/*
+		 * Defer changing the terminal speed.
+		 */
+		if (terminit() == 0)
+			return;
+#endif	/* LINEMODE */
+		/*
+		 * Change terminal speed as requested by client.
+		 * We set the receive speed first, so that if we can't
+		 * store seperate receive and transmit speeds, the transmit
+		 * speed will take precedence.
+		 */
+		tty_rspeed(parm2);
+		tty_tspeed(parm1);
+		set_termbuf();
+
+		break;
+
+	    }  /* end of case TELOPT_TSPEED */
+
+	default:
+		/* What? */
+		break;
+	}  /* end of switch */
+
+#if	defined(CRAY2) && defined(UNICOS5)
+	/*
+	 * Just in case of the likely event that we changed the pty state.
+	 */
+	rcv_ioctl();
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+
+	netflush();
+
+}  /* end of clientstat */
+
+#if	defined(CRAY2) && defined(UNICOS5)
+	void
+termstat()
+{
+	needtermstat = 1;
+}
+
+	void
+_termstat()
+{
+	needtermstat = 0;
+	init_termbuf();
+	localstat();
+	rcv_ioctl();
+}
+#endif	/* defined(CRAY2) && defined(UNICOS5) */
+
+#ifdef	LINEMODE
+/*
+ * defer_terminit
+ *
+ * Some things should not be done until after the login process has started
+ * and all the pty modes are set to what they are supposed to be.  This
+ * function is called when the pty state has been processed for the first time. 
+ * It calls other functions that do things that were deferred in each module.
+ */
+	void
+defer_terminit()
+{
+
+	/*
+	 * local stuff that got deferred.
+	 */
+	if (def_tspeed != -1) {
+		clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
+		def_tspeed = def_rspeed = 0;
+	}
+
+#ifdef	TIOCSWINSZ
+	if (def_col || def_row) {
+		struct winsize ws;
+
+		memset((char *)&ws, 0, sizeof(ws));
+		ws.ws_col = def_col;
+		ws.ws_row = def_row;
+		(void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
+	}
+#endif
+
+	/*
+	 * The only other module that currently defers anything.
+	 */
+	deferslc();
+
+}  /* end of defer_terminit */
+
+/*
+ * terminit
+ *
+ * Returns true if the pty state has been processed yet.
+ */
+	int
+terminit()
+{
+	return(_terminit);
+
+}  /* end of terminit */
+#endif	/* LINEMODE */
diff --git a/mechglue/src/appl/telnet/telnetd/utility.c b/mechglue/src/appl/telnet/telnetd/utility.c
new file mode 100644
index 000000000..f4568ec28
--- /dev/null
+++ b/mechglue/src/appl/telnet/telnetd/utility.c
@@ -0,0 +1,1300 @@
+/*
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)utility.c	8.1 (Berkeley) 6/4/93 */
+
+#include <stdarg.h>
+#define PRINTOPTIONS
+#include "telnetd.h"
+
+#ifdef HAVE_SYS_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+
+#if	defined(AUTHENTICATION)
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+/*
+ * utility functions performing io related tasks
+ */
+
+/*
+ * ttloop
+ *
+ *	A small subroutine to flush the network output buffer, get some data
+ * from the network, and pass it through the telnet state machine.  We
+ * also flush the pty input buffer (by dropping its data) if it becomes
+ * too full.
+ */
+
+    void
+ttloop()
+{
+    void netflush();
+
+    DIAG(TD_REPORT, netputs("td: ttloop\r\n"));
+    if (nfrontp-nbackp) {
+	netflush();
+    }
+read_again:
+    ncc = read(net, netibuf, sizeof netibuf);
+    if (ncc < 0) {
+	if (errno == EINTR)
+	    goto read_again;
+	syslog(LOG_INFO, "ttloop:  read: %m");
+	exit(1);
+    } else if (ncc == 0) {
+	syslog(LOG_INFO, "ttloop:  peer died: %m");
+	exit(1);
+    }
+    DIAG(TD_REPORT, netprintf("td: ttloop read %d chars\r\n", ncc));
+    netip = netibuf;
+    telrcv();			/* state machine */
+    if (ncc > 0) {
+	pfrontp = pbackp = ptyobuf;
+	telrcv();
+    }
+}  /* end of ttloop */
+
+/* 
+ * ttsuck - This is a horrible kludge to deal with a bug in
+ * HostExplorer. HostExplorer thinks it knows how to do krb5 auth, but
+ * it doesn't really. So if you offer it krb5 as an auth choice before
+ * krb4, it will sabotage the connection. So we peek ahead into the
+ * input stream to see if the client is a UNIX client, and then
+ * (later) offer krb5 first only if it is. Since no Mac/PC telnet
+ * clients do auto switching between krb4 and krb5 like the UNIX
+ * client does, it doesn't matter what order they see the choices in
+ * (except for HostExplorer).
+ *
+ * It is actually not possible to do this without looking ahead into
+ * the input stream: the client and server both try to begin
+ * auth/encryption negotiation as soon as possible, so if we let the
+ * server process things normally, it will already have sent the list
+ * of supported auth types before seeing the NEW-ENVIRON option. If
+ * you change the code to hold off sending the list of supported auth
+ * types until after it knows whether or not the remote side supports
+ * NEW-ENVIRON, then the auth negotiation and encryption negotiation
+ * race conditions won't interact properly, and encryption negotiation
+ * will reliably fail.
+ */
+
+    void
+ttsuck()
+{
+    extern int auth_client_non_unix;
+    int nread;
+    struct timeval tv;
+    fd_set fds;
+    char *p, match[] = {IAC, WILL, TELOPT_NEW_ENVIRON};
+
+    if (nfrontp-nbackp) {
+	netflush();
+    }
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+    FD_SET(net, &fds);
+
+    while (select(net + 1, &fds, NULL, NULL, &tv) == 1)
+      {
+	nread = read(net, netibuf + ncc, sizeof(netibuf) - ncc);
+	if (nread <= 0)
+	  break;
+	ncc += nread;
+      }
+
+    auth_client_non_unix = 1;
+    for (p = netibuf; p < netibuf + ncc; p++)
+      {
+	if (!memcmp(p, match, sizeof(match)))
+	  {
+	    auth_client_non_unix = 0;
+	    break;
+	  }
+      }
+
+    if (ncc > 0)
+      telrcv();
+}
+
+/*
+ * Check a descriptor to see if out of band data exists on it.
+ */
+    int
+stilloob(s)
+    int	s;		/* socket number */
+{
+    static struct timeval timeout = { 0 };
+    fd_set	excepts;
+    int value;
+
+    do {
+	FD_ZERO(&excepts);
+	FD_SET(s, &excepts);
+	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
+    } while ((value == -1) && (errno == EINTR));
+
+    if (value < 0) {
+	fatalperror(pty, "select");
+    }
+    if (FD_ISSET(s, &excepts)) {
+	return 1;
+    } else {
+	return 0;
+    }
+}
+
+	void
+ptyflush()
+{
+	int n;
+
+	if ((n = pfrontp - pbackp) > 0) {
+		DIAG((TD_REPORT | TD_PTYDATA),
+		     netprintf("td: ptyflush %d chars\r\n", n));
+		DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
+		n = write(pty, pbackp, (unsigned) n);
+	}
+	if (n < 0) {
+		if (errno == EWOULDBLOCK || errno == EINTR)
+			return;
+		(void)signal(SIGCHLD, SIG_DFL);
+		cleanup(0);
+	}
+	pbackp += n;
+	if (pbackp == pfrontp)
+		pbackp = pfrontp = ptyobuf;
+}
+
+/*
+ * nextitem()
+ *
+ *	Return the address of the next "item" in the TELNET data
+ * stream.  This will be the address of the next character if
+ * the current address is a user data character, or it will
+ * be the address of the character following the TELNET command
+ * if the current address is a TELNET IAC ("I Am a Command")
+ * character.
+ */
+static char *
+nextitem(current)
+    char	*current;
+{
+    if ((*current&0xff) != IAC) {
+	return current+1;
+    }
+    switch (*(current+1)&0xff) {
+    case DO:
+    case DONT:
+    case WILL:
+    case WONT:
+	return current+3;
+    case SB:		/* loop forever looking for the SE */
+	{
+	    register char *look = current+2;
+
+	    for (;;) {
+		if ((*look++&0xff) == IAC) {
+		    if ((*look++&0xff) == SE) {
+			return look;
+		    }
+		}
+	    }
+	}
+    default:
+	return current+2;
+    }
+}  /* end of nextitem */
+
+
+/*
+ * netclear()
+ *
+ *	We are about to do a TELNET SYNCH operation.  Clear
+ * the path to the network.
+ *
+ *	Things are a bit tricky since we may have sent the first
+ * byte or so of a previous TELNET command into the network.
+ * So, we have to scan the network buffer from the beginning
+ * until we are up to where we want to be.
+ *
+ *	A side effect of what we do, just to keep things
+ * simple, is to clear the urgent data pointer.  The principal
+ * caller should be setting the urgent data pointer AFTER calling
+ * us in any case.
+ */
+    void
+netclear()
+{
+    register char *thisitem, *next;
+    char *good;
+#define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
+				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
+
+#ifdef	ENCRYPTION
+    thisitem = nclearto > netobuf ? nclearto : netobuf;
+#else	/* ENCRYPTION */
+    thisitem = netobuf;
+#endif	/* ENCRYPTION */
+
+    while ((next = nextitem(thisitem)) <= nbackp) {
+	thisitem = next;
+    }
+
+    /* Now, thisitem is first before/at boundary. */
+
+#ifdef	ENCRYPTION
+    good = nclearto > netobuf ? nclearto : netobuf;
+#else	/* ENCRYPTION */
+    good = netobuf;	/* where the good bytes go */
+#endif	/* ENCRYPTION */
+
+    while (nfrontp > thisitem) {
+	if (wewant(thisitem)) {
+	    unsigned int length;
+
+	    next = thisitem;
+	    do {
+		next = nextitem(next);
+	    } while (wewant(next) && (nfrontp > next));
+	    length = next-thisitem;
+	    memcpy(good, thisitem, length);
+	    good += length;
+	    thisitem = next;
+	} else {
+	    thisitem = nextitem(thisitem);
+	}
+    }
+
+    nbackp = netobuf;
+    nfrontp = good;		/* next byte to be sent */
+    neturg = 0;
+}  /* end of netclear */
+
+/*
+ *  netflush
+ *		Send as much data as possible to the network,
+ *	handling requests for urgent data.
+ */
+void
+netflush()
+{
+    int n;
+    extern int not42;
+
+    if ((n = nfrontp - nbackp) > 0) {
+	DIAG(TD_REPORT, {netprintf_noflush("td: netflush %d chars\r\n", n);
+			 n = nfrontp - nbackp;});
+#ifdef	ENCRYPTION
+	if (encrypt_output) {
+		char *s = nclearto ? nclearto : nbackp;
+		if (nfrontp - s > 0) {
+			(*encrypt_output)((unsigned char *)s, nfrontp-s);
+			nclearto = nfrontp;
+		}
+	}
+#endif	/* ENCRYPTION */
+	/*
+	 * if no urgent data, or if the other side appears to be an
+	 * old 4.2 client (and thus unable to survive TCP urgent data),
+	 * write the entire buffer in non-OOB mode.
+	 */
+	if ((neturg == 0) || (not42 == 0)) {
+	    n = write(net, nbackp, (unsigned) n);	/* normal write */
+	} else {
+	    n = neturg - nbackp;
+	    /*
+	     * In 4.2 (and 4.3) systems, there is some question about
+	     * what byte in a sendOOB operation is the "OOB" data.
+	     * To make ourselves compatible, we only send ONE byte
+	     * out of band, the one WE THINK should be OOB (though
+	     * we really have more the TCP philosophy of urgent data
+	     * rather than the Unix philosophy of OOB data).
+	     */
+	    if (n > 1) {
+		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
+	    } else {
+		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
+	    }
+	}
+    }
+    if (n < 0) {
+	if (errno == EWOULDBLOCK || errno == EINTR)
+		return;
+	(void)signal(SIGCHLD, SIG_DFL);
+	cleanup(0);
+    }
+    nbackp += n;
+#ifdef	ENCRYPTION
+    if (nbackp > nclearto)
+	nclearto = 0;
+#endif	/* ENCRYPTION */
+    if (nbackp >= neturg) {
+	neturg = 0;
+    }
+    if (nbackp == nfrontp) {
+	nbackp = nfrontp = netobuf;
+#ifdef	ENCRYPTION
+	nclearto = 0;
+#endif	/* ENCRYPTION */
+    }
+    return;
+}  /* end of netflush */
+
+/*
+ * L8_256(x) = log8(256**x), rounded up, including sign (for decimal
+ * strings too).  log8(256) = 8/3, but we use integer math to round
+ * up.
+ */
+#define L8_256(x) (((x * 8 + 2) / 3) + 1)
+
+/*
+ * netprintf
+ *
+ * Do the equivalent of printf() to the NETOBUF "ring buffer",
+ * possibly calling netflush() if needed.
+ *
+ * Thou shalt not call this with a "%s" format; use netputs instead.
+ * We also don't deal with floating point widths in here.
+ */
+static void
+netprintf_ext(int noflush, int seturg, const char *fmt, va_list args)
+{
+	size_t remain;
+	size_t maxoutlen;
+	char buf[BUFSIZ];
+	const char *cp;
+	int len;
+
+	buf[0] = '\0';		/* nul-terminate */
+	remain = sizeof(netobuf) - (nfrontp - netobuf);
+	for (maxoutlen = 0, cp = fmt; *cp; cp++) {
+		if (*cp == '%')
+			/* Ok so this is slightly overkill... */
+			maxoutlen += L8_256(sizeof(long));
+		else
+			maxoutlen++;
+	}
+	if (maxoutlen >= sizeof(buf))
+		return;		/* highly unlikely */
+
+#ifdef HAVE_VSNPRINTF
+	len = vsnprintf(buf, sizeof(buf), fmt, args);
+#else
+	len = vsprintf(buf, fmt, args);	/* XXX need to fix for SunOS? */
+#endif
+
+	/*
+	 * The return value from sprintf()-like functions may be the
+	 * number of characters that *would* have been output, not the
+	 * number actually output.
+	 */
+	if (len <= 0 || len > sizeof(buf))
+		return;
+	if (remain < len && !noflush) {
+		netflush();
+		remain = sizeof(netobuf) - (nfrontp - netobuf);
+	}
+	if (remain < len)
+		return;		/* still not enough space? */
+	memcpy(nfrontp, buf, (size_t)len);
+	nfrontp += len;
+	if (seturg)
+		neturg = nfrontp - 1;
+}
+
+void
+netprintf(const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	netprintf_ext(0, 0, fmt, args);
+	va_end(args);
+}
+
+void
+netprintf_urg(const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	netprintf_ext(0, 1, fmt, args);
+	va_end(args);
+}
+
+void
+netprintf_noflush(const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	netprintf_ext(1, 0, fmt, args);
+	va_end(args);
+}
+
+/*
+ * netwrite
+ *
+ * Copy BUF into the NETOBUF "ring buffer", possibly calling
+ * netflush() if needed.
+ */
+int
+netwrite(const unsigned char *buf, size_t len)
+{
+	size_t remain;
+
+	remain = sizeof(netobuf) - (nfrontp - netobuf);
+	if (remain < len) {
+		netflush();
+		remain = sizeof(netobuf) - (nfrontp - netobuf);
+	}
+	if (remain < len)
+		return 0;
+	memcpy(nfrontp, buf, len);
+	nfrontp += len;
+	return len;
+}
+
+/*
+ * netputs
+ *
+ * Write S to the NETOBUF "ring buffer".  Does not write a '\n'.
+ */
+void
+netputs(const char *s)
+{
+	netwrite((const unsigned char *) s, strlen(s));
+}
+
+/*
+ * miscellaneous functions doing a variety of little jobs follow ...
+ */
+
+
+	void
+fatal(f, msg)
+	int f;
+	const char *msg;
+{
+	char buf[BUFSIZ];
+
+	(void) sprintf(buf, "telnetd: %s.\r\n", msg);
+#ifdef	ENCRYPTION
+	if (encrypt_output) {
+		/*
+		 * Better turn off encryption first....
+		 * Hope it flushes...
+		 */
+		encrypt_send_end();
+		netflush();
+	}
+#endif	/* ENCRYPTION */
+	(void) write(f, buf, strlen(buf));
+	sleep(1);	/*XXX*/
+	exit(1);
+}
+
+	void
+fatalperror(f, msg)
+	int f;
+	const char *msg;
+{
+	char buf[BUFSIZ], *strerror();
+
+	(void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
+	fatal(f, buf);
+}
+
+char editedhost[32];
+
+	void
+edithost(pat, host)
+	register char *pat;
+	register char *host;
+{
+	register char *res = editedhost;
+
+	if (!pat)
+		pat = "";
+	while (*pat) {
+		switch (*pat) {
+
+		case '#':
+			if (*host)
+				host++;
+			break;
+
+		case '@':
+			if (*host)
+				*res++ = *host++;
+			break;
+
+		default:
+			*res++ = *pat;
+			break;
+		}
+		if (res == &editedhost[sizeof editedhost - 1]) {
+			*res = '\0';
+			return;
+		}
+		pat++;
+	}
+	if (*host)
+		(void) strncpy(res, host,
+				sizeof editedhost - (res - editedhost) -1);
+	else
+		*res = '\0';
+	editedhost[sizeof editedhost - 1] = '\0';
+}
+
+static char *putlocation;
+
+static	void
+putstr(s)
+	register char *s;
+{
+
+	while (*s)
+		putchr(*s++);
+}
+
+	void
+putchr(cc)
+	int cc;
+{
+	*putlocation++ = cc;
+}
+
+/*
+ * This is split on two lines so that SCCS will not see the M
+ * between two % signs and expand it...
+ */
+static char fmtstr[] = { "%l:%M\
+%P on %A, %d %B %Y" };
+
+	void
+putf(cp, where)
+	register char *cp;
+	char *where;
+{
+	char *slash;
+	time_t t;
+	char db[100];
+#ifdef HAVE_SYS_UTSNAME_H
+	struct utsname utsinfo;
+
+	(void) uname(&utsinfo);
+#endif
+
+	putlocation = where;
+
+	while (*cp) {
+		if (*cp != '%') {
+			putchr(*cp++);
+			continue;
+		}
+		switch (*++cp) {
+
+		case 't':
+#ifdef	STREAMSPTY
+			/* names are like /dev/pts/2 -- we want pts/2 */
+			slash = strchr(line+1, '/');
+#else
+			slash = strrchr(line, '/');
+#endif
+			if (slash == (char *) 0)
+				putstr(line);
+			else
+				putstr(&slash[1]);
+			break;
+
+		case 'h':
+			putstr(editedhost);
+			break;
+
+		case 'd':
+			(void)time(&t);
+			(void)strftime(db, sizeof(db), fmtstr, localtime(&t));
+			putstr(db);
+			break;
+
+#ifdef HAVE_SYS_UTSNAME_H
+		case 's':
+			putstr(utsinfo.sysname);
+			break;
+
+		case 'm':
+			putstr(utsinfo.machine);
+			break;
+
+		case 'r':
+			putstr(utsinfo.release);
+			break;
+
+		case 'v':
+			putstr(utsinfo.version);
+			break;
+#endif
+
+		case '%':
+			putchr('%');
+			break;
+		}
+		cp++;
+	}
+}
+
+#ifdef DIAGNOSTICS
+/*
+ * Print telnet options and commands in plain text, if possible.
+ */
+void
+printoption(fmt, option)
+	register char *fmt;
+	register int option;
+{
+	netputs(fmt);
+	netputs(" ");
+	if (TELOPT_OK(option)) {
+		netputs(TELOPT(option));
+		netputs("\r\n");
+	} else if (TELCMD_OK(option)) {
+		netputs(TELCMD(option));
+		netputs("\r\n");
+	} else {
+		netprintf("%d\r\n", option);
+	}
+	return;
+}
+
+void
+printsub(direction, pointer, length)
+    char		direction;	/* '<' or '>' */
+    unsigned char	*pointer;	/* where suboption data sits */
+    int			length;		/* length of suboption data */
+{
+    register int i = 0;
+    char buf[512];
+
+        if (!(diagnostic & TD_OPTIONS))
+		return;
+
+	if (direction) {
+	    netputs("td: ");
+	    netputs(direction == '<' ? "recv" : "send");
+	    netputs(" suboption ");
+	    if (length >= 3) {
+		register int j;
+
+		i = pointer[length-2];
+		j = pointer[length-1];
+
+		if (i != IAC || j != SE) {
+		    netputs("(terminated by ");
+		    if (TELOPT_OK(i))
+			netputs(TELOPT(i));
+		    else if (TELCMD_OK(i))
+			netputs(TELCMD(i));
+		    else
+			netprintf("%d", i);
+		    netputs(" ");
+		    if (TELOPT_OK(j))
+			netputs(TELOPT(j));
+		    else if (TELCMD_OK(j))
+			netputs(TELCMD(j));
+		    else
+			netprintf("%d", j);
+		    netputs(", not IAC SE!) ");
+		}
+	    }
+	    length -= 2;
+	}
+	if (length < 1) {
+	    netputs("(Empty suboption??\?)");
+	    return;
+	}
+	switch (pointer[0]) {
+	case TELOPT_TTYPE:
+	    netputs("TERMINAL-TYPE ");
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		netputs("IS \"");
+		netwrite(pointer + 2, (size_t)(length - 2));
+		netputs("\"");
+		break;
+	    case TELQUAL_SEND:
+		netputs("SEND");
+		break;
+	    default:
+		netprintf("- unknown qualifier %d (0x%x).",
+			  pointer[1], pointer[1]);
+	    }
+	    break;
+	case TELOPT_TSPEED:
+	    netputs("TERMINAL-SPEED ");
+	    if (length < 2) {
+		netputs("(empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		netputs("IS ");
+		netwrite(pointer + 2, (size_t)(length - 2));
+		break;
+	    default:
+		if (pointer[1] == 1)
+		    netputs("SEND");
+		else
+		    netprintf("%d (unknown)", pointer[1]);
+		for (i = 2; i < length; i++)
+		    netprintf(" ?%d?", pointer[i]);
+		break;
+	    }
+	    break;
+
+	case TELOPT_LFLOW:
+	    netputs("TOGGLE-FLOW-CONTROL ");
+	    if (length < 2) {
+		netputs("(empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case LFLOW_OFF:
+		netputs("OFF"); break;
+	    case LFLOW_ON:
+		netputs("ON"); break;
+	    case LFLOW_RESTART_ANY:
+		netputs("RESTART-ANY"); break;
+	    case LFLOW_RESTART_XON:
+		netputs("RESTART-XON"); break;
+	    default:
+		netprintf("%d (unknown)", pointer[1]);
+	    }
+	    for (i = 2; i < length; i++)
+		netprintf(" ?%d?", pointer[i]);
+	    break;
+
+	case TELOPT_NAWS:
+	    netputs("NAWS");
+	    if (length < 2) {
+		netputs(" (empty suboption??\?)");
+		break;
+	    }
+	    if (length == 2) {
+		netprintf(" ?%d?", pointer[1]);
+		break;
+	    }
+	    netprintf(" %d %d (%d)",
+		pointer[1], pointer[2],
+		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
+	    if (length == 4) {
+		netprintf(" ?%d?", pointer[3]);
+		break;
+	    }
+	    netprintf(" %d %d (%d)",
+		pointer[3], pointer[4],
+		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
+	    for (i = 5; i < length; i++)
+		netprintf(" ?%d?", pointer[i]);
+	    break;
+
+	case TELOPT_LINEMODE:
+	    netputs("LINEMODE ");
+	    if (length < 2) {
+		netputs("(empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case WILL:
+		netputs("WILL ");
+		goto common;
+	    case WONT:
+		netputs("WONT ");
+		goto common;
+	    case DO:
+		netputs("DO ");
+		goto common;
+	    case DONT:
+		netputs("DONT ");
+	    common:
+		if (length < 3) {
+		    netputs("(no option??\?)");
+		    break;
+		}
+		switch (pointer[2]) {
+		case LM_FORWARDMASK:
+		    netputs("Forward Mask");
+		    for (i = 3; i < length; i++)
+			netprintf(" %x", pointer[i]);
+		    break;
+		default:
+		    netprintf("%d (unknown)", pointer[2]);
+		    for (i = 3; i < length; i++)
+			netprintf(" %d", pointer[i]);
+		    break;
+		}
+		break;
+		
+	    case LM_SLC:
+		netputs("SLC");
+		for (i = 2; i < length - 2; i += 3) {
+		    if (SLC_NAME_OK(pointer[i+SLC_FUNC])) {
+			netputs(" ");
+			netputs(SLC_NAME(pointer[i+SLC_FUNC]));
+		    } else
+			netprintf(" %d", pointer[i+SLC_FUNC]);
+		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
+		    case SLC_NOSUPPORT:
+			netputs(" NOSUPPORT"); break;
+		    case SLC_CANTCHANGE:
+			netputs(" CANTCHANGE"); break;
+		    case SLC_VARIABLE:
+			netputs(" VARIABLE"); break;
+		    case SLC_DEFAULT:
+			netputs(" DEFAULT"); break;
+		    }
+		    netputs(pointer[i+SLC_FLAGS]&SLC_ACK
+			    ? "|ACK" : "");
+		    netputs(pointer[i+SLC_FLAGS]&SLC_FLUSHIN
+			    ? "|FLUSHIN" : "");
+		    netputs(pointer[i+SLC_FLAGS]&SLC_FLUSHOUT
+			    ? "|FLUSHOUT" : "");
+		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
+						SLC_FLUSHOUT| SLC_LEVELBITS)) {
+			netprintf("(0x%x)", pointer[i+SLC_FLAGS]);
+		    }
+		    netprintf(" %d;", pointer[i+SLC_VALUE]);
+		    if ((pointer[i+SLC_VALUE] == IAC) &&
+			(pointer[i+SLC_VALUE+1] == IAC))
+				i++;
+		}
+		for (; i < length; i++)
+		    netprintf(" ?%d?", pointer[i]);
+		break;
+
+	    case LM_MODE:
+		netputs("MODE ");
+		if (length < 3) {
+		    netputs("(no mode??\?)");
+		    break;
+		}
+		{
+		    int wrotemode = 0;
+
+#define NETPUTS_MODE(x)				\
+do {						\
+	if (pointer[2] & (MODE_##x)) {		\
+		if (wrotemode) netputs("|");	\
+		netputs(#x);			\
+		wrotemode++;			\
+	}					\
+} while (0)
+		    NETPUTS_MODE(EDIT);
+		    NETPUTS_MODE(TRAPSIG);
+		    NETPUTS_MODE(SOFT_TAB);
+		    NETPUTS_MODE(LIT_ECHO);
+		    NETPUTS_MODE(ACK);
+#undef NETPUTS_MODE
+		    if (!wrotemode)
+			netputs("0");
+		}
+		if (pointer[2] & ~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
+		    netprintf(" (0x%x)", pointer[2]);
+		for (i = 3; i < length; i++)
+		    netprintf(" ?0x%x?", pointer[i]);
+		break;
+	    default:
+		netprintf("%d (unknown)", pointer[1]);
+		for (i = 2; i < length; i++)
+		    netprintf(" %d", pointer[i]);
+	    }
+	    break;
+
+	case TELOPT_STATUS: {
+	    register char *cp;
+	    register int j, k;
+
+	    netputs("STATUS");
+
+	    switch (pointer[1]) {
+	    default:
+		if (pointer[1] == TELQUAL_SEND)
+		    netputs(" SEND");
+		else
+		    netprintf(" %d (unknown)", pointer[1]);
+		for (i = 2; i < length; i++)
+		    netprintf(" ?%d?", pointer[i]);
+		break;
+	    case TELQUAL_IS:
+		netputs(" IS\r\n");
+
+		for (i = 2; i < length; i++) {
+		    switch(pointer[i]) {
+		    case DO:	cp = "DO"; goto common2;
+		    case DONT:	cp = "DONT"; goto common2;
+		    case WILL:	cp = "WILL"; goto common2;
+		    case WONT:	cp = "WONT"; goto common2;
+		    common2:
+			i++;
+			netputs(" ");
+			netputs(cp);
+			netputs(" ");
+			if (TELOPT_OK(pointer[i]))
+			    netputs(TELOPT(pointer[i]));
+			else
+			    netprintf("%d", pointer[i]);
+
+			netputs("\r\n");
+			break;
+
+		    case SB:
+			netputs(" SB ");
+			i++;
+			j = k = i;
+			while (j < length) {
+			    if (pointer[j] == SE) {
+				if (j+1 == length)
+				    break;
+				if (pointer[j+1] == SE)
+				    j++;
+				else
+				    break;
+			    }
+			    pointer[k++] = pointer[j++];
+			}
+			printsub(0, &pointer[i], k - i);
+			if (i < length) {
+			    netputs(" SE");
+			    i = j;
+			} else
+			    i = j - 1;
+
+			netputs("\r\n");
+
+			break;
+				
+		    default:
+			netprintf(" %d", pointer[i]);
+			break;
+		    }
+		}
+		break;
+	    }
+	    break;
+	  }
+
+	case TELOPT_XDISPLOC:
+	    netputs("X-DISPLAY-LOCATION ");
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		netputs("IS \"");
+		netwrite(pointer + 2, (size_t)(length - 2));
+		netputs("\"");
+		break;
+	    case TELQUAL_SEND:
+		netputs("SEND");
+		break;
+	    default:
+		netprintf("- unknown qualifier %d (0x%x).",
+			  pointer[1], pointer[1]);
+	    }
+	    break;
+
+	case TELOPT_NEW_ENVIRON:
+	    netputs("NEW-ENVIRON ");
+	    goto env_common1;
+	case TELOPT_OLD_ENVIRON:
+	    netputs("OLD-ENVIRON ");
+	env_common1:
+	    switch (pointer[1]) {
+	    case TELQUAL_IS:
+		netputs("IS ");
+		goto env_common;
+	    case TELQUAL_SEND:
+		netputs("SEND ");
+		goto env_common;
+	    case TELQUAL_INFO:
+		netputs("INFO ");
+	    env_common:
+		{
+		    register int noquote = 2;
+		    for (i = 2; i < length; i++ ) {
+			switch (pointer[i]) {
+			case NEW_ENV_VAR:
+			    netputs("\" VAR " + noquote);
+			    noquote = 2;
+			    break;
+
+			case NEW_ENV_VALUE:
+			    netputs("\" VALUE " + noquote);
+			    noquote = 2;
+			    break;
+
+			case ENV_ESC:
+			    netputs("\" ESC " + noquote);
+			    noquote = 2;
+			    break;
+
+			case ENV_USERVAR:
+			    netputs("\" USERVAR " + noquote);
+			    noquote = 2;
+			    break;
+
+			default:
+			    if (isprint(pointer[i]) && pointer[i] != '"') {
+				if (noquote) {
+				    netputs("\"");
+				    noquote = 0;
+				}
+				netprintf("%c", pointer[i]);
+			    } else {
+				netprintf("\" %03o " + noquote,
+					  pointer[i]);
+				noquote = 2;
+			    }
+			    break;
+			}
+		    }
+		    if (!noquote)
+			netputs("\"");
+		    break;
+		}
+	    }
+	    break;
+
+#if	defined(AUTHENTICATION)
+	case TELOPT_AUTHENTICATION:
+	    netputs("AUTHENTICATION");
+	
+	    if (length < 2) {
+		netputs(" (empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case TELQUAL_REPLY:
+	    case TELQUAL_IS:
+		netputs((pointer[1] == TELQUAL_IS) ? " IS " : " REPLY ");
+		if (AUTHTYPE_NAME_OK(pointer[2]))
+		    netputs(AUTHTYPE_NAME(pointer[2]));
+		else
+		    netprintf(" %d ", pointer[2]);
+		if (length < 3) {
+		    netputs("(partial suboption??\?)");
+		    break;
+		}
+		netputs(((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT)
+			? "CLIENT|" : "SERVER|");
+		netputs(((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+			? "MUTUAL" : "ONE-WAY");
+		netputs(((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON)
+			? "|ENCRYPT" : "");
+
+		auth_printsub(&pointer[1], length - 1, (unsigned char *)buf, 
+			      sizeof(buf));
+		netputs(buf);
+		break;
+
+	    case TELQUAL_SEND:
+		i = 2;
+		netputs(" SEND ");
+		while (i < length) {
+		    if (AUTHTYPE_NAME_OK(pointer[i]))
+			netputs(AUTHTYPE_NAME(pointer[i]));
+		    else
+			netprintf("%d", pointer[i]);
+		    netputs(" ");
+		    if (++i >= length) {
+			netputs("(partial suboption??\?)");
+			break;
+		    }
+		    netputs(((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT)
+			    ? "CLIENT|" : "SERVER|");
+		    netputs(((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+			    ? "MUTUAL" : "ONE-WAY");
+		    if ((pointer[3] & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON)
+			netputs("|ENCRYPT");
+		    ++i;
+		}
+		break;
+
+	    case TELQUAL_NAME:
+		i = 2;
+		netputs(" NAME \"");
+		while (i < length) {
+		    if (isprint(pointer[i]))
+			netprintf("%c", pointer[i++]);
+		    else {
+			netprintf("\\%03o", pointer[i++]);
+		    }
+		}
+		netputs("\"");
+		break;
+
+	    default:
+		    for (i = 2; i < length; i++)
+			netprintf(" ?%d?", pointer[i]);
+		    break;
+	    }
+	    break;
+#endif
+
+#ifdef	ENCRYPTION
+	case TELOPT_ENCRYPT:
+	    netputs("ENCRYPT");
+	    if (length < 2) {
+		netputs(" (empty suboption??\?)");
+		break;
+	    }
+	    switch (pointer[1]) {
+	    case ENCRYPT_START:
+		netputs(" START");
+		break;
+
+	    case ENCRYPT_END:
+		netputs(" END");
+		break;
+
+	    case ENCRYPT_REQSTART:
+		netputs(" REQUEST-START");
+		break;
+
+	    case ENCRYPT_REQEND:
+		netputs(" REQUEST-END");
+		break;
+
+	    case ENCRYPT_IS:
+	    case ENCRYPT_REPLY:
+		netputs((pointer[1] == ENCRYPT_IS)
+			? " IS " : " REPLY ");
+		if (length < 3) {
+		    netputs(" (partial suboption??\?)");
+		    nfrontp += strlen(nfrontp);
+		    break;
+		}
+		if (ENCTYPE_NAME_OK(pointer[2]))
+		    netputs(ENCTYPE_NAME(pointer[2]));
+		else
+		    netprintf("%d (unknown)", pointer[2]);
+		netputs(" ");
+
+		encrypt_printsub(&pointer[1], length - 1, 
+				 (unsigned char *) buf, sizeof(buf));
+		netputs(buf);
+		break;
+
+	    case ENCRYPT_SUPPORT:
+		i = 2;
+		netputs(" SUPPORT ");
+		nfrontp += strlen(nfrontp);
+		while (i < length) {
+		    if (ENCTYPE_NAME_OK(pointer[i]))
+			netputs(ENCTYPE_NAME(pointer[i]));
+		    else
+			netprintf("%d", pointer[i]);
+		    netputs(" ");
+		    i++;
+		}
+		break;
+
+	    case ENCRYPT_ENC_KEYID:
+		netputs(" ENC_KEYID");
+		goto encommon;
+
+	    case ENCRYPT_DEC_KEYID:
+		netputs(" DEC_KEYID");
+		goto encommon;
+
+	    default:
+		netprintf(" %d (unknown)", pointer[1]);
+	    encommon:
+		for (i = 2; i < length; i++)
+		    netprintf(" %d", pointer[i]);
+		break;
+	    }
+	    break;
+#endif	/* ENCRYPTION */
+
+	default:
+	    if (TELOPT_OK(pointer[0]))
+	        netputs(TELOPT(pointer[0]));
+	    else
+	        netprintf("%d", pointer[0]);
+	    netputs(" (unknown)");
+	    for (i = 1; i < length; i++)
+		netprintf(" %d", pointer[i]);
+	    break;
+	}
+	netputs("\r\n");
+}
+
+/*
+ * Dump a data buffer in hex and ascii to the output data stream.
+ */
+	void
+printdata(tag, ptr, cnt)
+	register char *tag;
+	register char *ptr;
+	register int cnt;
+{
+	register int i;
+	char xbuf[30];
+
+	while (cnt) {
+		/* add a line of output */
+		netputs(tag);
+		netputs(": ");
+		for (i = 0; i < 20 && cnt; i++) {
+			netprintf(nfrontp, "%02x", *ptr);
+			nfrontp += strlen(nfrontp); 
+			if (isprint((int) *ptr)) {
+				xbuf[i] = *ptr;
+			} else {
+				xbuf[i] = '.';
+			}
+			if (i % 2)
+				netputs(" ");
+			cnt--;
+			ptr++;
+		}
+		xbuf[i] = '\0';
+		netputs(" ");
+		netputs(xbuf);
+		netputs("\r\n");
+	} 
+}
+#endif /* DIAGNOSTICS */
diff --git a/mechglue/src/appl/user_user/.Sanitize b/mechglue/src/appl/user_user/.Sanitize
new file mode 100644
index 000000000..f5bedf431
--- /dev/null
+++ b/mechglue/src/appl/user_user/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+client.c
+configure
+configure.in
+server.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/appl/user_user/ChangeLog b/mechglue/src/appl/user_user/ChangeLog
new file mode 100644
index 000000000..c3bf3dbbf
--- /dev/null
+++ b/mechglue/src/appl/user_user/ChangeLog
@@ -0,0 +1,174 @@
+2004-04-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* server.c: Include string.h.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* server.c: Include port-sockets.h.
+
+2003-01-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* server.c (main): Use socklen_t when passing address to socket
+	functions.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* client.c, server.c: Include errno.h.
+
+2001-06-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* client.c, server.c: Cleanup assignments in conditionals.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Removed and tests moved up to appl/configure.in
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS macro set to '.' to indicate that there
+		are no subdirectories to be processed by the Makefile.
+
+Tue Sep 29 18:58:46 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* client.c (main): Don't use h_errno at all; it doesn't work on
+ 		all platforms (for example HPUX), and it's just not worth
+ 		the effort to disambiguate between the different reasons
+		why gethostbyname() might have failed.
+
+1998-07-05    <hartmans@fundsxpress.com>
+
+	* client.c (main): do not declare h_errno
+
+Wed Feb 18 15:39:14 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Feb  4 20:35:45 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Fri Nov 22 15:49:09 1996  unknown  <bjaspan@mit.edu>
+
+	* client.c (argv): use sizeof instead of h_length to determine
+ 	number of bytes of addr to copy from DNS response [krb5-misc/211]
+
+Thu Nov  7 15:36:15 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* client.c (argv): 
+	* server.c (argv): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Fri Mar 15 21:39:25 1996  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* server.c: Remove declaration of krb5_kdc_default_options.
+
+Fri Jul 7 15:51:45 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling and LDFLAGS.
+	* configure.in - Add KRB5_LIBRARIES.
+
+
+Thu Jun 15 17:44:23 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Sat Jun 10 23:00:05 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* client.c, server.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:30:36 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed May 03 03:30:51 1995  Chris Provenzano (proven@mit.edu)
+
+        * client.c: (krb5_recvauth()): No longer needs the rc_type arg.
+
+Mon May 01 15:56:32 1995  Chris Provenzano (proven@mit.edu)
+
+        * client.c (main()): Changes to auth_context to better
+                support full addresses, for mk_safe() and friends.
+
+Wed Apr 26 22:12:26 1995  Chris Provenzano (proven@mit.edu)
+
+	* server.c, client.c : Use krb5_auth_con_genaddrs() instead of
+		krb5_auth_con_setaddrs().
+
+Mon Mar 27 07:56:26 11995 Chris Provenzano (proven@mit.edu)
+
+        * server.c: Use new calling conventions for krb5_sendauth(),
+		krb5_mk_req_extended(), and krb5_mk_safe().
+
+        * server.c: Use new calling conventions for krb5_recvauth(),
+		krb5_rd_req(), and krb5_rd_safe().
+
+Thu Mar  2 12:28:58 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:26:20 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:51:29 1995  John Gilmore  (gnu at toad.com)
+
+	* client.c, server.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Tue Feb 14 15:30:55 1995 Chris Provenzano  (proven@mit.edu)
+
+        * client.c Call krb5_get_credentials() with new calling convention.
+
+        * server.c Call krb5_mk_req_extended() with new calling convention.
+
+Fri Feb  3 11:58:18 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* client.c: (tgt_keyproc): Add keytype argument to rd_req_proc.
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+        * Removed all narrow types and references to wide.h and narrow.h
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Tue Oct  4 17:12:52 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* client.c (tgt_keyproc): Add widen.h and narrow.h around
+		declaration so that argument types are widened.
+
+Thu Sep 29 22:48:20 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executable when libraries change
+
+Wed Sep 14 21:47:00 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Fixed stupid typo (uusrever) in the install target.
diff --git a/mechglue/src/appl/user_user/Makefile.in b/mechglue/src/appl/user_user/Makefile.in
new file mode 100644
index 000000000..e55eda8a2
--- /dev/null
+++ b/mechglue/src/appl/user_user/Makefile.in
@@ -0,0 +1,25 @@
+thisconfigdir=./..
+myfulldir=appl/user_user
+mydir=user_user
+BUILDTOP=$(REL)..$(S)..
+DEFINES = -DDEBUG
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all:: uuclient uuserver
+
+uuclient: client.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o uuclient client.o $(KRB5_BASE_LIBS)
+
+clean::
+	$(RM) client.o uuclient
+
+uuserver: server.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o uuserver server.o $(KRB5_BASE_LIBS)
+
+install::
+	$(INSTALL_PROGRAM) uuclient $(DESTDIR)$(CLIENT_BINDIR)/uuclient
+	$(INSTALL_PROGRAM) uuserver $(DESTDIR)$(SERVER_BINDIR)/uuserver
+
+clean::
+	$(RM) server.o uuserver
diff --git a/mechglue/src/appl/user_user/client.c b/mechglue/src/appl/user_user/client.c
new file mode 100644
index 000000000..3bcb84b95
--- /dev/null
+++ b/mechglue/src/appl/user_user/client.c
@@ -0,0 +1,278 @@
+/*
+ * appl/user_user/client.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Other end of user-user client/server pair.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "krb5.h"
+#include "com_err.h"
+
+int main (argc, argv)
+int argc;
+char *argv[];
+{
+  int s;
+  register int retval, i;
+  char *hname;		/* full name of server */
+  char **srealms;	/* realm(s) of server */
+  char *princ;		/* principal in credentials cache */
+  struct servent *serv;
+  struct hostent *host;
+  struct sockaddr_in serv_net_addr, cli_net_addr;
+  krb5_ccache cc;
+  krb5_creds creds, *new_creds;
+  krb5_data reply, msg, princ_data;
+  krb5_auth_context auth_context = NULL;
+  krb5_ticket * ticket = NULL;
+  krb5_context context;
+  unsigned short port;
+
+  if (argc < 2 || argc > 4) {
+      fputs ("usage: uu-client <hostname> [message [port]]\n", stderr);
+      return 1;
+  }
+
+  retval = krb5_init_context(&context);
+  if (retval) {
+      com_err(argv[0], retval, "while initializing krb5");
+      exit(1);
+  }
+
+  if (argc == 4) {
+      port = htons(atoi(argv[3]));
+  }
+  else if ((serv = getservbyname ("uu-sample", "tcp")) == NULL)
+  {
+      fputs ("uu-client: unknown service \"uu-sample/tcp\"\n", stderr);
+      return 2;
+  } else {
+      port = serv->s_port;
+  }
+
+  if ((host = gethostbyname (argv[1])) == NULL) {
+      fprintf (stderr, "uu-client: can't get address of host \"%s\".\n", 
+	       argv[1]);
+      return 3;
+  }
+  
+  if (host->h_addrtype != AF_INET) {
+      fprintf (stderr, "uu-client: bad address type %d for \"%s\".\n",
+	       host->h_addrtype, argv[1]);
+      return 3;
+  }
+
+  hname = strdup (host->h_name);
+
+#ifndef USE_STDOUT
+  if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+      com_err ("uu-client", errno, "creating socket");
+      return 4;
+  } else {
+      cli_net_addr.sin_family = AF_INET;
+      cli_net_addr.sin_port = 0;
+      cli_net_addr.sin_addr.s_addr = 0;
+      if (bind (s, (struct sockaddr *)&cli_net_addr, 
+		sizeof (cli_net_addr)) < 0) {
+	  com_err ("uu-client", errno, "binding socket");
+	  return 4;
+      }
+  }
+  
+  serv_net_addr.sin_family = AF_INET;
+  serv_net_addr.sin_port = port;
+
+  i = 0;
+  while (1) {
+      if (host->h_addr_list[i] == 0) {
+	  fprintf (stderr, "uu-client: unable to connect to \"%s\"\n", hname);
+	  return 5;
+      }
+
+      memcpy ((char *)&serv_net_addr.sin_addr, host->h_addr_list[i++], 
+	      sizeof(serv_net_addr.sin_addr));
+
+      if (connect(s, (struct sockaddr *)&serv_net_addr, 
+		  sizeof (serv_net_addr)) == 0)
+	  break;
+      com_err ("uu-client", errno, "connecting to \"%s\" (%s).",
+	       hname, inet_ntoa(serv_net_addr.sin_addr));
+  }
+#else
+  s = 1;
+#endif
+
+  retval = krb5_cc_default(context, &cc);
+  if (retval) {
+      com_err("uu-client", retval, "getting credentials cache");
+      return 6;
+  }
+
+  memset ((char*)&creds, 0, sizeof(creds));
+
+  retval = krb5_cc_get_principal(context, cc, &creds.client);
+  if (retval) {
+      com_err("uu-client", retval, "getting principal name");
+      return 6;
+  }
+  
+  retval = krb5_unparse_name(context, creds.client, &princ);
+  if (retval) {
+      com_err("uu-client", retval, "printing principal name");
+      return 7;
+  } 
+  else
+      fprintf(stderr, "uu-client: client principal is \"%s\".\n", princ);
+
+  retval = krb5_get_host_realm(context, hname, &srealms);
+  if (retval) {
+      com_err("uu-client", retval, "getting realms for \"%s\"", hname);
+      return 7;
+  }
+
+  retval = 
+      krb5_build_principal_ext(context, &creds.server,
+			       krb5_princ_realm(context, creds.client)->length,
+			       krb5_princ_realm(context, creds.client)->data,
+			       6, "krbtgt",
+			       krb5_princ_realm(context, creds.client)->length,
+			       krb5_princ_realm(context, creds.client)->data,
+			       0);
+  if (retval) {
+      com_err("uu-client", retval, "setting up tgt server name");
+      return 7;
+  }
+  
+  /* Get TGT from credentials cache */
+  retval = krb5_get_credentials(context, KRB5_GC_CACHED, cc, 
+				&creds, &new_creds);
+  if (retval) {
+      com_err("uu-client", retval, "getting TGT");
+      return 6;
+  }
+
+  i = strlen(princ) + 1;
+
+  fprintf(stderr, "uu-client: sending %d bytes\n",new_creds->ticket.length + i);
+  princ_data.data = princ;
+  princ_data.length = i;		/* include null terminator for
+					   server's convenience */
+  retval = krb5_write_message(context, (krb5_pointer) &s, &princ_data);
+  if (retval) {
+      com_err("uu-client", retval, "sending principal name to server");
+      return 8;
+  }
+  
+  free(princ);
+  
+  retval = krb5_write_message(context, (krb5_pointer) &s, &new_creds->ticket);
+  if (retval) {
+      com_err("uu-client", retval, "sending ticket to server");
+      return 8;
+  }
+
+  retval = krb5_read_message(context, (krb5_pointer) &s, &reply);
+  if (retval) {
+      com_err("uu-client", retval, "reading reply from server");
+      return 9;
+  }
+
+  retval = krb5_auth_con_init(context, &auth_context);
+  if (retval) {
+      com_err("uu-client", retval, "initializing the auth_context");
+      return 9;
+  }
+  
+  retval = 
+      krb5_auth_con_genaddrs(context, auth_context, s,
+			     KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR |
+			     KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
+  if (retval) {
+      com_err("uu-client", retval, "generating addrs for auth_context");
+      	return 9;
+    }
+
+  retval = krb5_auth_con_setflags(context, auth_context,
+				  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+  if (retval) {
+      com_err("uu-client", retval, "initializing the auth_context flags");
+      return 9;
+  }
+  
+  retval = krb5_auth_con_setuseruserkey(context, auth_context, 
+					&new_creds->keyblock);
+  if (retval) {
+      com_err("uu-client", retval, "setting useruserkey for authcontext");
+      return 9;
+  }
+  
+#if 1
+  /* read the ap_req to get the session key */
+  retval = krb5_rd_req(context, &auth_context, &reply,
+		       NULL, NULL, NULL, &ticket);
+  free(reply.data);
+#else
+  retval = krb5_recvauth(context, &auth_context, (krb5_pointer)&s, "???",
+			 0, /* server */, 0, NULL, &ticket);
+#endif
+  
+  if (retval) {
+      com_err("uu-client", retval, "reading AP_REQ from server");
+      return 9;
+  }
+
+  retval = krb5_unparse_name(context, ticket->enc_part2->client, &princ);
+  if (retval)
+      com_err("uu-client", retval, "while unparsing client name");
+  else {
+      printf("server is named \"%s\"\n", princ);
+      free(princ);
+  }
+
+  retval = krb5_read_message(context, (krb5_pointer) &s, &reply);
+  if (retval) {
+      com_err("uu-client", retval, "reading reply from server");
+      return 9;
+  }
+  
+  retval = krb5_rd_safe(context, auth_context, &reply, &msg, NULL);
+  if (retval) {
+      com_err("uu-client", retval, "decoding reply from server");
+      return 10;
+  }
+
+  printf ("uu-client: server says \"%s\".\n", msg.data);
+  return 0;
+}
+
diff --git a/mechglue/src/appl/user_user/server.c b/mechglue/src/appl/user_user/server.c
new file mode 100644
index 000000000..292bacf6d
--- /dev/null
+++ b/mechglue/src/appl/user_user/server.c
@@ -0,0 +1,231 @@
+/*
+ * appl/user_user/server.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * One end of the user-user client-server pair.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "port-sockets.h"
+#include "krb5.h"
+#include "com_err.h"
+
+/* fd 0 is a tcp socket used to talk to the client */
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+  krb5_data pname_data, tkt_data;
+  int sock = 0;
+  socklen_t l;
+  int retval;
+  struct sockaddr_in l_inaddr, f_inaddr;	/* local, foreign address */
+  krb5_creds creds, *new_creds;
+  krb5_ccache cc;
+  krb5_data msgtext, msg;
+  krb5_context context;
+    krb5_auth_context auth_context = NULL;
+
+#ifndef DEBUG
+  freopen("/tmp/uu-server.log", "w", stderr);
+#endif
+
+  retval = krb5_init_context(&context);
+  if (retval) {
+	  com_err(argv[0], retval, "while initializing krb5");
+	  exit(1);
+  }
+
+#ifdef DEBUG
+  {
+      int one = 1;
+      int acc;
+      struct servent *sp;
+      socklen_t namelen = sizeof(f_inaddr);
+      
+      if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+	  com_err("uu-server", errno, "creating socket");
+	  exit(3);
+      }
+      
+      l_inaddr.sin_family = AF_INET;
+      l_inaddr.sin_addr.s_addr = 0;
+      if (!(sp = getservbyname("uu-sample", "tcp"))) {
+	  com_err("uu-server", 0, "can't find uu-sample/tcp service");
+	  exit(3);
+      }
+      (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (one));
+      l_inaddr.sin_port = sp->s_port;
+      if (bind(sock, (struct sockaddr *)&l_inaddr, sizeof(l_inaddr))) {
+	  com_err("uu-server", errno, "binding socket");
+	  exit(3);
+      }
+      if (listen(sock, 1) == -1) {
+	  com_err("uu-server", errno, "listening");
+	  exit(3);
+      }
+      if ((acc = accept(sock, (struct sockaddr *)&f_inaddr, &namelen)) == -1) {
+	  com_err("uu-server", errno, "accepting");
+	  exit(3);
+      }
+      dup2(acc, 0);
+      close(sock);
+      sock = 0;
+  }
+#endif
+
+  retval = krb5_read_message(context, (krb5_pointer) &sock, &pname_data);
+  if (retval) {
+      com_err ("uu-server", retval, "reading pname");
+      return 2;
+  }
+
+  retval = krb5_read_message(context, (krb5_pointer) &sock, &tkt_data);
+  if (retval) {
+      com_err ("uu-server", retval, "reading ticket data");
+      return 2;
+  }
+
+  retval = krb5_cc_default(context, &cc);
+  if (retval) {
+      com_err("uu-server", retval, "getting credentials cache");
+      return 4;
+  }
+
+  memset ((char*)&creds, 0, sizeof(creds));
+  retval = krb5_cc_get_principal(context, cc, &creds.client);
+  if (retval) {
+      com_err("uu-client", retval, "getting principal name");
+      return 6;
+  }
+
+  /* client sends it already null-terminated. */
+  printf ("uu-server: client principal is \"%s\".\n", pname_data.data);
+
+  retval = krb5_parse_name(context, pname_data.data, &creds.server);
+  if (retval) {
+      com_err("uu-server", retval, "parsing client name");
+      return 3;
+  }
+
+  creds.second_ticket = tkt_data;
+  printf ("uu-server: client ticket is %d bytes.\n",
+	  creds.second_ticket.length);
+
+  retval = krb5_get_credentials(context, KRB5_GC_USER_USER, cc, 
+				&creds, &new_creds);
+  if (retval) {
+      com_err("uu-server", retval, "getting user-user ticket");
+      return 5;
+  }
+
+#ifndef DEBUG
+  l = sizeof(f_inaddr);
+  if (getpeername(0, (struct sockaddr *)&f_inaddr, &l) == -1)
+    {
+      com_err("uu-server", errno, "getting client address");
+      return 6;
+    }
+#endif
+  l = sizeof(l_inaddr);
+  if (getsockname(0, (struct sockaddr *)&l_inaddr, &l) == -1)
+    {
+      com_err("uu-server", errno, "getting local address");
+      return 6;
+    }
+
+  /* send a ticket/authenticator to the other side, so it can get the key
+     we're using for the krb_safe below. */
+
+  retval = krb5_auth_con_init(context, &auth_context);
+  if (retval) {
+      com_err("uu-server", retval, "making auth_context");
+      return 8;
+  }
+
+  retval = krb5_auth_con_setflags(context, auth_context,
+				  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+  if (retval) {
+      com_err("uu-server", retval, "initializing the auth_context flags");
+      return 8;
+  }
+  
+  retval = 
+      krb5_auth_con_genaddrs(context, auth_context, sock,
+			     KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR |
+			     KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
+  if (retval) {
+      com_err("uu-server", retval, "generating addrs for auth_context");
+      return 9;
+  }
+  
+#if 1
+  retval = krb5_mk_req_extended(context, &auth_context, 
+				AP_OPTS_USE_SESSION_KEY, 
+				NULL, new_creds, &msg);
+  if (retval) {
+      com_err("uu-server", retval, "making AP_REQ");
+      return 8;
+  }
+  retval = krb5_write_message(context, (krb5_pointer) &sock, &msg);
+#else
+  retval = krb5_sendauth(context, &auth_context, (krb5_pointer)&sock,"???", 0,
+			 0, AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SESSION_KEY,
+			 NULL, &creds, cc, NULL, NULL, NULL);
+#endif
+  if (retval)
+      goto cl_short_wrt;
+  
+  free(msg.data);
+  
+  msgtext.length = 32;
+  msgtext.data = "Hello, other end of connection.";
+  
+  retval = krb5_mk_safe(context, auth_context, &msgtext, &msg, NULL);
+  if (retval) {
+      com_err("uu-server", retval, "encoding message to client");
+      return 6;
+  }
+
+  retval = krb5_write_message(context, (krb5_pointer) &sock, &msg);
+  if (retval) {
+  cl_short_wrt:
+      com_err("uu-server", retval, "writing message to client");
+      return 7;
+  }
+
+  return 0;
+}
diff --git a/mechglue/src/clients/.Sanitize b/mechglue/src/clients/.Sanitize
new file mode 100644
index 000000000..5caddf1af
--- /dev/null
+++ b/mechglue/src/clients/.Sanitize
@@ -0,0 +1,40 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+kdestroy
+kinit
+klist
+ksu
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/clients/ChangeLog b/mechglue/src/clients/ChangeLog
new file mode 100644
index 000000000..4167a5773
--- /dev/null
+++ b/mechglue/src/clients/ChangeLog
@@ -0,0 +1,128 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2004-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * Makefile.in: output status info for kcpytkt, kdeltkt
+
+2004-08-20  Jeffrey Altman <jaltman@mit.edu>
+
+        * Add kcpytkt and kdeltkt directories
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't look for getipnodebyaddr.
+
+2001-04-03  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add checks for unsetenv and getenv.  Compile
+	setenv.o if any of setenv, unsetenv, or getenv are
+	missing. [pullup from krb5-1-2-2-branch]
+
+2000-03-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for alpha*-dec-osf* instead of
+	alpha-dec-osf*.
+
+2000-02-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Test for <arpa/inet.h> include file for inet_ntop
+	prototype.
+
+2000-02-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for inet_ntop and getipnodebyaddr, both used
+	in klist.
+
+1999-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for setenv.  Set SETENVOBJ to setenv.o if
+	it's not available, empty otherwise.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add kvno to Windows build.
+	* Makefile.in: Clean kpasswd in Windows build.
+
+1999-08-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Build kpasswd under windows.
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+Mon May 17 12:24:55 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add NO_OUTPRE flag to prevent creation of output
+		directory under win32.  Add clean-windows target.
+
+Thu Feb 18 22:31:56 1999  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add check for setluid().
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: add kvno
+
+Sat Jul 25 15:00:26 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* Makefile.in (LOCAL_SUBDIRS): add kvno
+
+Wed Feb 18 15:40:02 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.
+
+Thu Feb 12 16:15:54 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented AC_OUTPUT to force autoreconf to
+	rebuild configure script.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Jan 29 00:12:07 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use this configure.in for all subdirectories.
+
+Fri Jan 30 16:08:25 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add new directory for kpasswd.
+
+Sun Feb 23 01:26:27 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Define BUILDTOP for Win16/Win32
+
+Sat Feb  8 15:27:31 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Added win32 rules (kinit,kdestroy,klist console apps)
+
+Fri Jul 7 15:52:28 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS
+
+Fri Jun  9 18:36:37 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Wed Jul 20 23:36:04 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in: add ksu
+
diff --git a/mechglue/src/clients/Makefile.in b/mechglue/src/clients/Makefile.in
new file mode 100644
index 000000000..f1c8be6e2
--- /dev/null
+++ b/mechglue/src/clients/Makefile.in
@@ -0,0 +1,55 @@
+thisconfigdir=.
+myfulldir=clients
+mydir=.
+BUILDTOP=$(REL)..
+
+LOCAL_SUBDIRS= klist kinit kdestroy kpasswd ksu kvno kcpytkt kdeltkt
+
+NO_OUTPRE=1
+all-windows::
+	@echo Making all in clients\klist
+	cd klist
+	$(MAKE) -$(MFLAGS)
+	@echo Making all in clients\kdestroy
+	cd ..\kdestroy
+	$(MAKE) -$(MFLAGS)
+	@echo Making all in clients\kinit
+	cd ..\kinit
+	$(MAKE) -$(MFLAGS)
+	@echo Making all in clients\kpasswd
+	cd ..\kpasswd
+	$(MAKE) -$(MFLAGS)
+	@echo Making all in clients\kvno
+	cd ..\kvno
+	$(MAKE) -$(MFLAGS)
+	@echo Making all in clients\kcpytkt
+	cd ..\kcpytkt
+	$(MAKE) -$(MFLAGS)
+	@echo Making all in clients\kdeltkt
+	cd ..\kdeltkt
+	$(MAKE) -$(MFLAGS)
+	cd ..
+
+clean-windows::
+	@echo Making clean in clients\klist
+	cd klist
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in clients\kdestroy
+	cd ..\kdestroy
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in clients\kinit
+	cd ..\kinit
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in clients\kpasswd
+	cd ..\kpasswd
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in clients\kvno
+	cd ..\kvno
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in clients\kcpytkt
+	cd ..\kcpytkt
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in clients\kdeltkt
+	cd ..\kdeltkt
+	$(MAKE) -$(MFLAGS) clean
+	cd ..
diff --git a/mechglue/src/clients/configure.in b/mechglue/src/clients/configure.in
new file mode 100644
index 000000000..39d0f795b
--- /dev/null
+++ b/mechglue/src/clients/configure.in
@@ -0,0 +1,24 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+AC_PROG_INSTALL
+KRB5_BUILD_PROGRAM
+AC_HEADER_STDARG
+AC_CHECK_FUNCS(getusershell lstat setenv unsetenv getenv inet_ntop)
+if test $ac_cv_func_setenv = no || test $ac_cv_func_unsetenv = no \
+  || test $ac_cv_func_getenv = no; then
+  SETENVOBJ=setenv.o
+else
+  SETENVOBJ=
+fi
+AC_SUBST(SETENVOBJ)
+AC_CHECK_HEADERS(unistd.h pwd.h arpa/inet.h)
+case $krb5_cv_host in
+alpha*-dec-osf*)
+	AC_CHECK_LIB(security,setluid,
+		AC_DEFINE(HAVE_SETLUID)
+		KSU_LIBS="$KSU_LIBS -lsecurity"
+	)
+	;;
+esac
+AC_SUBST(KSU_LIBS)
+V5_AC_OUTPUT_MAKEFILE(. klist kinit kvno kdestroy kpasswd ksu)
diff --git a/mechglue/src/clients/kcpytkt/ChangeLog b/mechglue/src/clients/kcpytkt/ChangeLog
new file mode 100644
index 000000000..ace7be592
--- /dev/null
+++ b/mechglue/src/clients/kcpytkt/ChangeLog
@@ -0,0 +1,4 @@
+2004-08-20  Jeffrey Altman  <jaltman@mit.edu>
+
+	* kcpytkt.c, kcpytkt.M: Create a new application.
+
diff --git a/mechglue/src/clients/kcpytkt/Makefile.in b/mechglue/src/clients/kcpytkt/Makefile.in
new file mode 100644
index 000000000..d7089841c
--- /dev/null
+++ b/mechglue/src/clients/kcpytkt/Makefile.in
@@ -0,0 +1,28 @@
+thisconfigdir=./..
+myfulldir=clients/kcpytkt
+mydir=kcpytkt
+BUILDTOP=$(REL)..$(S)..
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all-unix:: kcpytkt
+all-windows:: $(OUTPRE)kcpytkt.exe
+all-mac::
+
+kcpytkt: kcpytkt.o $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o $@ kcpytkt.o $(KRB4COMPAT_LIBS)
+
+$(OUTPRE)kcpytkt.exe: $(OUTPRE)kcpytkt.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.obj $(KLIB) $(CLIB)
+	link $(EXE_LINKOPTS) /out:$@ $**
+
+clean-unix::
+	$(RM) kcpytkt.o kcpytkt
+
+install-unix::
+	for f in kcpytkt; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		$(DESTDIR)$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
diff --git a/mechglue/src/clients/kcpytkt/kcpytkt.M b/mechglue/src/clients/kcpytkt/kcpytkt.M
new file mode 100644
index 000000000..11ed93929
--- /dev/null
+++ b/mechglue/src/clients/kcpytkt/kcpytkt.M
@@ -0,0 +1,37 @@
+.\"
+.\" clients/kvnol/kcpytkt.M
+.\" "
+.TH KCPYTKT 1
+.SH NAME
+kcpytkt \- copies one or more service tickets between credentials caches
+.SH SYNOPSIS
+\fBkcpytkt\fP [\fB\-h\fP] [\fB\-c source_ccache\fP] [\fB\-e etype\fP] [\fB\-f flags\fP] 
+\fBdest_ccache\fP \fBservice1\fP \fBservice2\fP \fB...\fP
+.br
+.SH DESCRIPTION
+.I kcpytkt
+copies the specified service tickets to the destination credentials cache
+.SH OPTIONS
+.TP
+.B \-c
+specifies the source credentials cache from which service tickets will be.
+copied.  if no ccache is specified, the default ccache is used.
+.TP
+.B \-e
+specifies the session key enctype of the service tickets you wish to delete.
+.TP
+.B \-h
+prints a usage statement and exits
+.SH ENVIRONMENT
+.B kcpytkt
+uses the following environment variable:
+.TP "\w'.SM KRB5CCNAME\ \ 'u"
+.SM KRB5CCNAME
+Location of the credentials (ticket) cache.
+.SH FILES
+.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
+/tmp/krb5cc_[uid]
+default location of the credentials cache ([uid] is the decimal UID of
+the user).
+.SH SEE ALSO
+kinit(1), kdestroy(1), krb5(3)
diff --git a/mechglue/src/clients/kcpytkt/kcpytkt.c b/mechglue/src/clients/kcpytkt/kcpytkt.c
new file mode 100644
index 000000000..8efddb413
--- /dev/null
+++ b/mechglue/src/clients/kcpytkt/kcpytkt.c
@@ -0,0 +1,182 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <krb5.h>
+
+extern int optind;
+extern char *optarg;
+
+static char *prog;
+
+static void xusage()
+{
+    fprintf(stderr, "xusage: %s [-c from_ccache] [-e etype] [-f flags] dest_ccache service1 service2 ...\n", prog);
+    exit(1);
+}
+
+int quiet = 0;
+
+static void do_kcpytkt (int argc, char *argv[], char *fromccachestr, char *etypestr, int flags);
+
+int main(int argc, char *argv[])
+{
+    int option;
+    char *etypestr = 0;
+    char *fromccachestr = 0;
+    int flags = 0;
+
+    prog = strrchr(argv[0], '/');
+    prog = prog ? (prog + 1) : argv[0];
+
+    while ((option = getopt(argc, argv, "c:e:f:hq")) != -1) {
+	switch (option) {
+        case 'c':
+            fromccachestr = optarg;
+            break;
+	case 'e':
+	    etypestr = optarg;
+	    break;
+        case 'f':
+            flags = atoi(optarg);
+            break;
+	case 'q':
+	    quiet = 1;
+	    break;
+	case 'h':
+	default:
+	    xusage();
+	    break;
+	}
+    }
+
+    if ((argc - optind) < 2)
+	xusage();
+
+    do_kcpytkt(argc - optind, argv + optind, fromccachestr, etypestr, flags);
+    return 0;
+}
+
+static void do_kcpytkt (int count, char *names[], 
+                        char *fromccachestr, char *etypestr, int flags)
+{
+    krb5_context context;
+    krb5_error_code ret;
+    int i, errors;
+    krb5_enctype etype;
+    krb5_ccache fromccache;
+    krb5_ccache destccache;
+    krb5_principal me;
+    krb5_creds in_creds, out_creds;
+    int retflags;
+    char *princ;
+
+    ret = krb5_init_context(&context);
+    if (ret) {
+	com_err(prog, ret, "while initializing krb5 library");
+	exit(1);
+    }
+
+    if (etypestr) {
+        ret = krb5_string_to_enctype(etypestr, &etype);
+	if (ret) {
+	    com_err(prog, ret, "while converting etype");
+	    exit(1);
+	}
+        retflags = KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES;
+    } else {
+	etype = 0;
+        retflags = KRB5_TC_MATCH_SRV_NAMEONLY;
+    }
+
+    if (fromccachestr)
+        ret = krb5_cc_resolve(context, fromccachestr, &fromccache);
+    else
+        ret = krb5_cc_default(context, &fromccache);
+    if (ret) {
+	com_err(prog, ret, "while opening source ccache");
+	exit(1);
+    }
+
+    ret = krb5_cc_get_principal(context, fromccache, &me);
+    if (ret) {
+	com_err(prog, ret, "while getting client principal name");
+	exit(1);
+    }
+
+    ret = krb5_cc_resolve(context, names[0], &destccache);
+    if (ret) {
+	com_err(prog, ret, "while opening destination cache");
+	exit(1);
+    }
+
+    errors = 0;
+
+    for (i = 1; i < count; i++) {
+	memset(&in_creds, 0, sizeof(in_creds));
+
+	in_creds.client = me;
+
+	ret = krb5_parse_name(context, names[i], &in_creds.server);
+	if (ret) {
+	    if (!quiet)
+		fprintf(stderr, "%s: %s while parsing principal name\n",
+			names[i], error_message(ret));
+	    errors++;
+	    continue;
+	}
+
+	ret = krb5_unparse_name(context, in_creds.server, &princ);
+	if (ret) {
+	    fprintf(stderr, "%s: %s while printing principal name\n",
+		    names[i], error_message(ret));
+	    errors++;
+	    continue;
+	}
+
+	in_creds.keyblock.enctype = etype;
+
+        ret = krb5_cc_retrieve_cred(context, fromccache, retflags,
+                                    &in_creds, &out_creds);  
+	if (ret) {
+	    fprintf(stderr, "%s: %s while retrieving credentials\n",
+		    princ, error_message(ret));
+
+	    krb5_free_unparsed_name(context, princ);
+
+	    errors++;
+	    continue;
+	}
+
+	ret = krb5_cc_store_cred(context, destccache, &out_creds);
+
+	krb5_free_principal(context, in_creds.server);
+
+	if (ret) {
+	    fprintf(stderr, "%s: %s while removing credentials\n",
+		    princ, error_message(ret));
+
+            krb5_free_cred_contents(context, &out_creds);
+	    krb5_free_unparsed_name(context, princ);
+
+	    errors++;
+	    continue;
+	}
+
+	krb5_free_unparsed_name(context, princ);
+        krb5_free_cred_contents(context, &out_creds);
+    }
+
+    krb5_free_principal(context, me);
+    krb5_cc_close(context, fromccache);
+    krb5_cc_close(context, destccache);
+    krb5_free_context(context);
+
+    if (errors)
+	exit(1);
+
+    exit(0);
+}
diff --git a/mechglue/src/clients/kdeltkt/ChangeLog b/mechglue/src/clients/kdeltkt/ChangeLog
new file mode 100644
index 000000000..35a25951f
--- /dev/null
+++ b/mechglue/src/clients/kdeltkt/ChangeLog
@@ -0,0 +1,8 @@
+2004-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * Makefile.in: correct the makefile to build kdeltkt, not kvno
+
+2004-08-19  Jeffrey Altman <jaltman@mit.edu>
+
+	* kdeltkt.c, kdeltkt.M: Create a new application.
+
diff --git a/mechglue/src/clients/kdeltkt/Makefile.in b/mechglue/src/clients/kdeltkt/Makefile.in
new file mode 100644
index 000000000..d7d371a79
--- /dev/null
+++ b/mechglue/src/clients/kdeltkt/Makefile.in
@@ -0,0 +1,28 @@
+thisconfigdir=./..
+myfulldir=clients/kdeltkt
+mydir=kvno
+BUILDTOP=$(REL)..$(S)..
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all-unix:: kdeltkt
+all-windows:: $(OUTPRE)kdeltkt.exe
+all-mac::
+
+kdeltkt: kdeltkt.o $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o $@ kdeltkt.o $(KRB4COMPAT_LIBS)
+
+$(OUTPRE)kdeltkt.exe: $(OUTPRE)kdeltkt.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.obj $(KLIB) $(CLIB)
+	link $(EXE_LINKOPTS) /out:$@ $**
+
+clean-unix::
+	$(RM) kdeltkt.o kdeltkt
+
+install-unix::
+	for f in kdeltkt; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		$(DESTDIR)$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
diff --git a/mechglue/src/clients/kdeltkt/kdeltkt.M b/mechglue/src/clients/kdeltkt/kdeltkt.M
new file mode 100644
index 000000000..a9f369418
--- /dev/null
+++ b/mechglue/src/clients/kdeltkt/kdeltkt.M
@@ -0,0 +1,37 @@
+.\"
+.\" clients/kvnol/kdeltkt.M
+.\" "
+.TH KDELTKT 1
+.SH NAME
+kdeltkt \- delete one or more service tickets from the credentials cache
+.SH SYNOPSIS
+\fBkdeltkt\fP [\fB\-h\fP] [\fB\-c ccache\fP] [\fB\-e etype\fP] [\fB\-f flags\fP] 
+\fBservice1\fP \fBservice2\fP \fB...\fP
+.br
+.SH DESCRIPTION
+.I kdeltkt
+deletes the specified service tickets from the credentials cache
+.SH OPTIONS
+.TP
+.B \-c
+specifies the credentials cache from which service tickets will be deleted.
+if no cache is specified, the default cache is used.
+.TP
+.B \-e
+specifies the session key enctype of the service tickets you wish to delete.
+.TP
+.B \-h
+prints a usage statement and exits
+.SH ENVIRONMENT
+.B kdeltkt
+uses the following environment variable:
+.TP "\w'.SM KRB5CCNAME\ \ 'u"
+.SM KRB5CCNAME
+Location of the credentials (ticket) cache.
+.SH FILES
+.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
+/tmp/krb5cc_[uid]
+default location of the credentials cache ([uid] is the decimal UID of
+the user).
+.SH SEE ALSO
+kinit(1), kdestroy(1), krb5(3)
diff --git a/mechglue/src/clients/kdeltkt/kdeltkt.c b/mechglue/src/clients/kdeltkt/kdeltkt.c
new file mode 100644
index 000000000..832a07075
--- /dev/null
+++ b/mechglue/src/clients/kdeltkt/kdeltkt.c
@@ -0,0 +1,174 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <krb5.h>
+
+extern int optind;
+extern char *optarg;
+
+static char *prog;
+
+static void xusage()
+{
+    fprintf(stderr, "xusage: %s [-c ccache] [-e etype] [-f flags] service1 service2 ...\n", prog);
+    exit(1);
+}
+
+int quiet = 0;
+
+static void do_kdeltkt (int argc, char *argv[], char *ccachestr, char *etypestr, int flags);
+
+int main(int argc, char *argv[])
+{
+    int option;
+    char *etypestr = 0;
+    char *ccachestr = 0;
+    int flags = 0;
+
+    prog = strrchr(argv[0], '/');
+    prog = prog ? (prog + 1) : argv[0];
+
+    while ((option = getopt(argc, argv, "c:e:f:hq")) != -1) {
+	switch (option) {
+        case 'c':
+            ccachestr = optarg;
+            break;
+	case 'e':
+	    etypestr = optarg;
+	    break;
+        case 'f':
+            flags = atoi(optarg);
+            break;
+	case 'q':
+	    quiet = 1;
+	    break;
+	case 'h':
+	default:
+	    xusage();
+	    break;
+	}
+    }
+
+    if ((argc - optind) < 1)
+	xusage();
+
+    do_kdeltkt(argc - optind, argv + optind, ccachestr, etypestr, flags);
+    return 0;
+}
+
+static void do_kdeltkt (int count, char *names[], 
+                        char *ccachestr, char *etypestr, int flags)
+{
+    krb5_context context;
+    krb5_error_code ret;
+    int i, errors;
+    krb5_enctype etype;
+    krb5_ccache ccache;
+    krb5_principal me;
+    krb5_creds in_creds, out_creds;
+    int retflags;
+    char *princ;
+
+    ret = krb5_init_context(&context);
+    if (ret) {
+	com_err(prog, ret, "while initializing krb5 library");
+	exit(1);
+    }
+
+    if (etypestr) {
+        ret = krb5_string_to_enctype(etypestr, &etype);
+	if (ret) {
+	    com_err(prog, ret, "while converting etype");
+	    exit(1);
+	}
+        retflags = KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES;
+    } else {
+	etype = 0;
+        retflags = KRB5_TC_MATCH_SRV_NAMEONLY;
+    }
+
+    if (ccachestr)
+        ret = krb5_cc_resolve(context, ccachestr, &ccache);
+    else
+        ret = krb5_cc_default(context, &ccache);
+    if (ret) {
+	com_err(prog, ret, "while opening ccache");
+	exit(1);
+    }
+
+    ret = krb5_cc_get_principal(context, ccache, &me);
+    if (ret) {
+	com_err(prog, ret, "while getting client principal name");
+	exit(1);
+    }
+
+    errors = 0;
+
+    for (i = 0; i < count; i++) {
+	memset(&in_creds, 0, sizeof(in_creds));
+
+	in_creds.client = me;
+
+	ret = krb5_parse_name(context, names[i], &in_creds.server);
+	if (ret) {
+	    if (!quiet)
+		fprintf(stderr, "%s: %s while parsing principal name\n",
+			names[i], error_message(ret));
+	    errors++;
+	    continue;
+	}
+
+	ret = krb5_unparse_name(context, in_creds.server, &princ);
+	if (ret) {
+	    fprintf(stderr, "%s: %s while printing principal name\n",
+		    names[i], error_message(ret));
+	    errors++;
+	    continue;
+	}
+
+	in_creds.keyblock.enctype = etype;
+
+        ret = krb5_cc_retrieve_cred(context, ccache, retflags,
+                                    &in_creds, &out_creds);  
+	if (ret) {
+	    fprintf(stderr, "%s: %s while retrieving credentials\n",
+		    princ, error_message(ret));
+
+	    krb5_free_unparsed_name(context, princ);
+
+	    errors++;
+	    continue;
+	}
+
+	ret = krb5_cc_remove_cred(context, ccache, flags, &out_creds);
+
+	krb5_free_principal(context, in_creds.server);
+
+	if (ret) {
+	    fprintf(stderr, "%s: %s while removing credentials\n",
+		    princ, error_message(ret));
+
+            krb5_free_cred_contents(context, &out_creds);
+	    krb5_free_unparsed_name(context, princ);
+
+	    errors++;
+	    continue;
+	}
+
+	krb5_free_unparsed_name(context, princ);
+    krb5_free_cred_contents(context, &out_creds);
+    }
+
+    krb5_free_principal(context, me);
+    krb5_cc_close(context, ccache);
+    krb5_free_context(context);
+
+    if (errors)
+	exit(1);
+
+    exit(0);
+}
diff --git a/mechglue/src/clients/kdestroy/.Sanitize b/mechglue/src/clients/kdestroy/.Sanitize
new file mode 100644
index 000000000..951b5e67d
--- /dev/null
+++ b/mechglue/src/clients/kdestroy/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+kdestroy.M
+kdestroy.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/clients/kdestroy/ChangeLog b/mechglue/src/clients/kdestroy/ChangeLog
new file mode 100644
index 000000000..17a82afb7
--- /dev/null
+++ b/mechglue/src/clients/kdestroy/ChangeLog
@@ -0,0 +1,172 @@
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac): Target deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdestroy.c: Include unistd.h (if present) for getopt() prototype. 
+
+2000-08-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdestroy.c (main): Clean up compiler warnings.
+
+2000-03-16  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdestroy.c: Do not define variables if v4 compatilibilty is not
+	defined.
+
+2000-03-07  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kdestroy.M: Make up-to-date.
+
+	* kdestroy.c: Add support for combining -5 and -4.  Add ability to
+	easily change defaults in terms of whether to use 5, 4 or both.
+	Expand usage info.
+
+2000-02-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kdestroy.c: Fix GET_PROGNAME macro to properly return program
+	name under Win32.  Re-indent, turning spaces that should be tabs
+	into tabs.
+
+2000-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (kdestroy): Fix to build under Unix again.
+
+2000-02-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kdestroy.c: Major revamp to support Kerberos 4 compatibility.  Code
+	restructured to allow changes to support Kerberos 4 or Kerberos 5
+	only operation depending on whether dynamic libraries are
+	avialable.  Explicit documentation and support files to make it
+	easy to do this will be forthcoming.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Windows fix for 10/26/99 cleanup.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Use standard windows exe link flags.
+
+Mon May 10 15:09:31 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdestroy.c (main): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Wed Feb 18 15:40:31 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.  Fix up extraneous whitespace.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 21 15:12:30 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdestroy.c (main): returns int, not void. ANSI X3.159-1989
+	2.1.2.2.1 says so, and gcc now warns about it.
+
+Sat Feb 15 12:25:00 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Link in ComErr library $(CLIB)
+
+Mon Feb 10 14:59:54 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in:
+		Build kdestroy.exe (win32 console app)
+
+Mon Jan 27 16:38:44 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Wed Nov  6 12:02:20 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdestroy.c (main): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Tue Sep 10 14:13:33 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kdestroy.M: remove ".so man1/header.doc"
+
+Fri Jul 7 15:52:51 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling and LDFLAGS..
+	* configure.in - Add KRB5_LIBRARIES.
+
+
+Thu Jun 15 17:45:03 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Fri Jun  9 18:37:19 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu May 04 04:31:53 1995  Chris Provenzano  (proven@mit.edu)
+
+	* kdestroy.c : Added #include <string.h>
+
+Thu Mar  2 12:32:49 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:26:51 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Replace check for -lsocket and -lnsl with
+		WITH_NETLIB check.
+
+Tue Feb 28 02:10:17 1995  John Gilmore  (gnu at toad.com)
+
+	* kdestroy.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Fri Feb 10 18:46:17 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove ISODE cruft.  Use $(LIBS) so that
+		libsocket can be pulled in if necessary.
+
+	* kdestroy.c (main): Call krb5_init_context to initialize the
+		context. 
+
+	* configure.in: Add check for libsocket and libnsl (sigh).
+		krb5_init_ctx drags in cryptoconf.c, which drags in enough
+		of the crypto library that socket() gets called.  We should
+		to fix this eventually to make klist smaller, but the fix
+		will be subtle.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Mon Oct  3 19:14:48 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
diff --git a/mechglue/src/clients/kdestroy/Makefile.in b/mechglue/src/clients/kdestroy/Makefile.in
new file mode 100644
index 000000000..353535822
--- /dev/null
+++ b/mechglue/src/clients/kdestroy/Makefile.in
@@ -0,0 +1,27 @@
+thisconfigdir=./..
+myfulldir=clients/kdestroy
+mydir=kdestroy
+BUILDTOP=$(REL)..$(S)..
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all-unix:: kdestroy
+all-windows:: $(OUTPRE)kdestroy.exe
+
+kdestroy: kdestroy.o $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o $@ kdestroy.o $(KRB4COMPAT_LIBS)
+
+$(OUTPRE)kdestroy.exe: $(OUTPRE)kdestroy.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.obj $(KLIB) $(CLIB)
+	link $(EXE_LINKOPTS) -out:$@ $**
+
+clean-unix::
+	$(RM) kdestroy.o kdestroy
+
+install-unix::
+	for f in kdestroy; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		$(DESTDIR)$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
diff --git a/mechglue/src/clients/kdestroy/kdestroy.M b/mechglue/src/clients/kdestroy/kdestroy.M
new file mode 100644
index 000000000..c7d0135b7
--- /dev/null
+++ b/mechglue/src/clients/kdestroy/kdestroy.M
@@ -0,0 +1,104 @@
+.\" clients/kdestroy/kdestroy.M
+.\"
+.\" Copyright 1992 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH KDESTROY 1
+.SH NAME
+kdestroy \- destroy Kerberos tickets
+.SH SYNOPSIS
+.B kdestroy
+[\fB\-5\fP] [\fB\-4\fP] [\fB\-q\fP] [\fB\-c\fP \fIcache_name]
+.br
+.SH DESCRIPTION
+The
+.I kdestroy
+utility destroys the user's active Kerberos authorization tickets by
+writing zeros to the specified credentials cache that contains them.  If
+the credentials cache is not specified, the default credentials cache is
+destroyed.
+If kdestroy was built with Kerberos 4 support, the default behavior is to
+destroy both Kerberos 5 and Kerberos 4 credentials.  Otherwise, kdestroy 
+will default to destroying only Kerberos 5 credentials.
+.SH OPTIONS
+.TP
+.B \-5
+destroy Kerberos 5 credentials.  This overrides whatever the default built-in
+behavior may be.  This option may be used with
+.B \-4
+.
+.TP
+.B \-4
+destroy Kerberos 4 credentials.  This overrides whatever the default built-in
+behavior may be.  This option is only available if kinit was built
+with Kerberos 4 compatibility.  This option may be used with 
+.B \-5
+.
+.TP
+.B \-q
+Run quietly.  Normally
+.B kdestroy
+beeps if it fails to destroy the user's tickets.  The
+.B \-q
+flag suppresses this behavior.
+.TP
+\fB\-c\fP \fIcache_name\fP
+use
+.I cache_name
+as the credentials (ticket) cache name and location; if this option is
+not used, the default cache name and location are used.
+.sp
+The default credentials cache may vary between systems.  If the
+.SM KRB5CCNAME
+environment variable is set, its value is used to name the default
+ticket cache.
+.PP
+Most installations recommend that you place the
+.I kdestroy
+command in your
+.I .logout
+file, so that your tickets are destroyed automatically when you log out.
+.SH ENVIRONMENT
+.B Kdestroy
+uses the following environment variables:
+.TP "\w'.SM KRB5CCNAME\ \ 'u"
+.SM KRB5CCNAME
+Location of the Kerberos 5 credentials (ticket) cache.
+.TP "\w'.SM KRBTKFILE\ \ 'u"
+.SM KRBTKFILE
+Filename of the Kerberos 4 credentials (ticket) cache.
+.SH FILES
+.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
+/tmp/krb5cc_[uid]
+default location of Kerberos 5 credentials cache 
+([uid] is the decimal UID of the user).
+.TP "\w'/tmp/tkt[uid]\ \ 'u"
+/tmp/tkt[uid]
+default location of Kerberos 4 credentials cache 
+([uid] is the decimal UID of the user).
+.SH SEE ALSO
+kinit(1), klist(1), krb5(3)
+.SH BUGS
+.PP
+Only the tickets in the specified credentials cache are destroyed.
+Separate ticket caches are used to hold root instance and password
+changing tickets.  These should probably be destroyed too, or all of a
+user's tickets kept in a single credentials cache.
diff --git a/mechglue/src/clients/kdestroy/kdestroy.c b/mechglue/src/clients/kdestroy/kdestroy.c
new file mode 100644
index 000000000..a9072ed54
--- /dev/null
+++ b/mechglue/src/clients/kdestroy/kdestroy.c
@@ -0,0 +1,227 @@
+/*
+ * clients/kdestroy/kdestroy.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Destroy the contents of your credential cache.
+ */
+
+#include <krb5.h>
+#include <com_err.h>
+#include <string.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+
+#ifdef __STDC__
+#define BELL_CHAR '\a'
+#else
+#define BELL_CHAR '\007'
+#endif
+
+extern int optind;
+extern char *optarg;
+
+#ifndef _WIN32
+#define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x))
+#else
+#define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
+#endif
+
+char *progname;
+
+int got_k5 = 0;
+int got_k4 = 0;
+
+int default_k5 = 1;
+#ifdef KRB5_KRB4_COMPAT
+int default_k4 = 1;
+#else
+int default_k4 = 0;
+#endif
+
+
+static void usage()
+{
+#define KRB_AVAIL_STRING(x) ((x)?"available":"not available")
+
+    fprintf(stderr, "Usage: %s [-5] [-4] [-q] [-c cache_name]\n", progname);
+    fprintf(stderr, "\t-5 Kerberos 5 (%s)\n", KRB_AVAIL_STRING(got_k5));
+    fprintf(stderr, "\t-4 Kerberos 4 (%s)\n", KRB_AVAIL_STRING(got_k4));
+    fprintf(stderr, "\t   (Default is %s%s%s%s)\n",
+	    default_k5?"Kerberos 5":"",
+	    (default_k5 && default_k4)?" and ":"",
+	    default_k4?"Kerberos 4":"",
+	    (!default_k5 && !default_k4)?"neither":"");
+    fprintf(stderr, "\t-q quiet mode\n");
+    fprintf(stderr, "\t-c specify name of credentials cache\n");
+    exit(2);
+}
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    krb5_context kcontext;
+    krb5_error_code retval;
+    int c;
+    krb5_ccache cache = NULL;
+    char *cache_name = NULL;
+    int code = 0;
+#ifdef KRB5_KRB4_COMPAT
+    int v4code = 0;
+    int v4 = 1;
+#endif
+    int errflg = 0;
+    int quiet = 0;
+
+    int use_k5 = 0;
+    int use_k4 = 0;
+
+    progname = GET_PROGNAME(argv[0]);
+
+    got_k5 = 1;
+#ifdef KRB5_KRB4_COMPAT
+    got_k4 = 1;
+#endif
+
+    while ((c = getopt(argc, argv, "54qc:")) != -1) {
+	switch (c) {
+	case 'q':
+	    quiet = 1;
+	    break;	
+	case 'c':
+	    if (cache_name) {
+		fprintf(stderr, "Only one -c option allowed\n");
+		errflg++;
+	    } else {
+		cache_name = optarg;
+	    }
+	    break;
+	case '4':
+	    if (!got_k4)
+	    {
+#ifdef KRB5_KRB4_COMPAT
+		fprintf(stderr, "Kerberos 4 support could not be loaded\n");
+#else
+		fprintf(stderr, "This was not built with Kerberos 4 support\n");
+#endif
+		exit(3);
+	    }
+	    use_k4 = 1;
+	    break;
+	case '5':
+	    if (!got_k5)
+	    {
+		fprintf(stderr, "Kerberos 5 support could not be loaded\n");
+		exit(3);
+	    }
+	    use_k5 = 1;
+	    break;
+	case '?':
+	default:
+	    errflg++;
+	    break;
+	}
+    }
+
+    if (optind != argc)
+	errflg++;
+    
+    if (errflg) {
+	usage();
+    }
+
+    if (!use_k5 && !use_k4)
+    {
+	use_k5 = default_k5;
+	use_k4 = default_k4;
+    }
+
+    if (!use_k5)
+	got_k5 = 0;
+    if (!use_k4)
+	got_k4 = 0;
+
+    if (got_k5) {
+	retval = krb5_init_context(&kcontext);
+	if (retval) {
+	    com_err(progname, retval, "while initializing krb5");
+	    exit(1);
+	}
+
+	if (cache_name) {
+#ifdef KRB5_KRB4_COMPAT
+	    v4 = 0;	/* Don't do v4 if doing v5 and cache name given. */
+#endif
+	    code = krb5_cc_resolve (kcontext, cache_name, &cache);
+	    if (code != 0) {
+		com_err (progname, code, "while resolving %s", cache_name);
+		exit(1);
+	    }
+	} else {
+	    code = krb5_cc_default(kcontext, &cache);
+	    if (code) {
+		com_err(progname, code, "while getting default ccache");
+		exit(1);
+	    }
+	}
+
+	code = krb5_cc_destroy (kcontext, cache);
+	if (code != 0) {
+	    com_err (progname, code, "while destroying cache");
+	    if (code != KRB5_FCC_NOFILE) {
+		if (quiet)
+		    fprintf(stderr, "Ticket cache NOT destroyed!\n");
+		else {
+		    fprintf(stderr, "Ticket cache %cNOT%c destroyed!\n", 
+			    BELL_CHAR, BELL_CHAR);
+		}
+		errflg = 1;
+	    }
+	}
+    }
+#ifdef KRB5_KRB4_COMPAT
+    if (got_k4 && v4) {
+	v4code = dest_tkt();
+	if (v4code == KSUCCESS && code != 0)
+	    fprintf(stderr, "Kerberos 4 ticket cache destroyed.\n");
+	if (v4code != KSUCCESS && v4code != RET_TKFIL) {
+	    if (quiet)
+		fprintf(stderr, "Kerberos 4 ticket cache NOT destroyed!\n");
+	    else
+		fprintf(stderr, "Kerberos 4 ticket cache %cNOT%c destroyed!\n",
+			BELL_CHAR, BELL_CHAR);
+	    errflg = 1;
+	}
+    }
+#endif
+    return errflg;
+}
diff --git a/mechglue/src/clients/kinit/.Sanitize b/mechglue/src/clients/kinit/.Sanitize
new file mode 100644
index 000000000..9b66652c6
--- /dev/null
+++ b/mechglue/src/clients/kinit/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+kinit.M
+kinit.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/clients/kinit/ChangeLog b/mechglue/src/clients/kinit/ChangeLog
new file mode 100644
index 000000000..63d53ffa9
--- /dev/null
+++ b/mechglue/src/clients/kinit/ChangeLog
@@ -0,0 +1,394 @@
+2004-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* kinit.c (k5_kinit): Don't free addresses after calling
+	krb5_get_init_creds_opt_set_address_list; it doesn't make a copy.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac): Target deleted.
+
+2003-08-01  Tom Yu  <tlyu@mit.edu>
+
+	* kinit.c (main): Apply patch from Stephen Grau to correctly
+	return non-zero for certain error conditions.
+
+2003-05-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* kinit.c (KRB4_BACKUP_DEFAULT_LIFE_SECS): Update to one day.
+
+2003-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (kinit): Don't use krb524 library.
+	* kinit.c: Don't include krb524.h.
+	(try_convert524): Don't call krb524_init_ets.
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* kinit.c (k4_kinit): Remove trailing colon, as new implementation
+	of krb5_read_password() appends it.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-30  Ezra Peisach  <epeisach@bu.edu>
+
+	* kinit.c (ULINE): Invoke fprintf with correct number of arguments
+	depending on if V4 support is compiled in or not.
+
+2002-07-17  Jen Selby <jenselby@mit.edu>
+
+	* kinit.M: added documentation of the "-a" option
+
+2001-12-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kinit.c (main): Fix typo in #ifdef KRB5_KRB4_COMPAT.  Thanks to
+	rbasch@mit.edu
+
+2001-09-24  Mitchell Berger  <mitchb@mit.edu>
+
+	* kinit.M: Correct some typos.  Thanks to Dennis Davis
+	<D.H.Davis@bath.ac.uk>
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* kinit.c (k4_begin): Cleanup assignment in conditional warning.
+
+2001-04-05  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kinit.c (k4_kinit): Use ANSI C-style string continuation.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* kinit.c (k4_kinit): Argument to krb5_read_password takes as
+	unsigned int as argument.
+
+2000-10-09  Tom Yu  <tlyu@mit.edu>
+
+	* kinit.c (k4_kinit): Call time_to_life().
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* kinit.c: Include krb524.h if suport desired. Clean up
+	addignements in conditionals and do not shadow global variables. 
+
+2000-03-16  Ezra Peisach  <epeisach@mit.edu>
+
+	* kinit.c (k4_kinit): Fix the code that was broken with
+	krb5_get_prompt_types code changes. Also - cleanup unused
+	variables when krb4 not compiled in.
+
+2000-03-15  Danilo Almeida  <dalmeida@mit.edu  >
+
+	* kinit.c: Add support for krb5_get_prompt_types.
+
+2000-03-07  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kinit.c: Add support for using both -4 and -5.  Default to krb5
+	only.  Add KINIT_DEFAULT_BOTH support.  Tweak usage info.
+
+	* kinit.M: Fix a couple of typos.  Document new default
+	behavior.   Document that -4 and -5 may be combined.
+
+2000-02-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kinit.M: Document that -s is not applicable to Kerberos 4.
+
+	* kinit.c: Nicer usage message.  Better checking for illegal
+	options.  Do not output error when doing Kerberos 4 if we will be
+	trying 524 afterwards.  Add hooks for future support for
+	specifying the Kerberos 4 cache name.  Fix GET_PROGNAME macro to
+	properly return program name under Win32.  Re-indent, turning
+	spaces that should be tabs into tabs.
+
+	* kinit.M: Document new Kerberos 4 kinit behavior.
+
+2000-02-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* kinit.c (try_convert524): Avoid duplicate free calls.
+
+2000-02-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kinit.c: Only free stuff if it's not NULL.
+
+2000-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (kinit): Fix to build on Unix again.
+
+2000-02-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kinit.c: Major revamp to support Kerberos 4 compatibility.  Code
+	restructured to allow changes to support Kerberos 4 or Kerberos 5
+	only operation depending on whether dynamic libraries are
+	avialable.  Explicit documentation and support files to make it
+	easy to do this will be forthcoming.
+
+	* Makefile.in: On Windows, use getopt.lib instead of getopt.obj, 
+	and add support for getopt_long.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Windows fix for 10/26/99 cleanup.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* kinit.c (optind, optarg) [sun]: Declare on SunOS 4.  Maybe
+	declare unconditionally, in the future.
+
+1999-08-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* kinit.c (main): Initialize cache_name to null, in case it's not
+	set.
+
+1999-08-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Use standard windows exe link flags.
+
+Mon May 10 15:13:37 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Mon Feb  8 22:10:36 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kinit.c: If unistd.h is not available, use manual definitions
+		for getopt, optarg, and optind.  (For Windows).
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* kinit.c: convert to new init_creds api
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kinit.c (main): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Wed Feb 18 15:42:14 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.  Remove extraneous whitespace.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 21 15:10:37 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kinit.c (main): returns int, not void. ANSI X3.159-1989
+	2.1.2.2.1 says so, and gcc now warns about it. (eichin@cygnus.com)
+
+Thu May 29 19:39:08 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kinit.c (main): Fix bug where kinit would core dump if given a
+		really long principal name.
+
+Tue Feb 25 00:29:46 1997  Richard Basch  <basch@lehman.com>
+
+	* kinit.c: Moved krb5_read_password back into the library (win32)
+
+Sat Feb 15 12:24:32 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Link in ComErr library $(CLIB)
+	* kinit.c: Winsock initialization/teardown is now done by krb5 lib
+
+Thu Feb 13 14:27:41 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in:
+		Link wsock32 library (win32)
+
+	* kinit.c:
+		Added krb5_read_password implementation for win32 console.
+		Initialize Winsock library (win32)
+
+Sat Feb  8 15:37:39 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in:
+		Build kinit.exe (win32 console app)
+
+	* kinit.c:
+		Removed unused local variables
+		Created prototypes for internal functions (win32)
+
+Mon Jan 27 16:44:20 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Dec  5 21:59:08 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kinit.M: v5srvtab -> krb5.keytab [279]
+
+Wed Nov  6 09:31:35 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kinit.c (main): Check the return code from krb5_init_context,
+		and print an error message if appropriate.  No longer call
+		krb5_init_ets(), as it's no longer necessary.
+
+Tue Sep 10 14:13:52 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kinit.M: remove ".so man1/header.doc"
+
+Sun Jul  7 15:21:58 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kinit.M: Document -R option.
+
+	* kinit.c (krb5_tgt_gen): Code from krb5_validate_tgt() modified
+	to handle both renewal and validation of postdated tickets. 
+	(krb5_renew_tgt): Takes a credential cache with a tgt with the
+	"renewable flag" set and asks ths kdc to renew it. Cache is wiped
+	and only new tgt is stored.
+	(main): New option -R to renew tickets.
+
+Thu Jun 20 20:19:44 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kinit.M, kinit.c (main): Add a -s option to kinit which specifies
+ 	the service name to be used in the TGS_REQ.
+
+Fri May  3 00:28:10 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kinit.c (krb5_validate_tgt): new function, takes a credential
+	cache with an tgt with the "invalid flag" set, and asks the kdc to
+	validate it. Wipes cache and stores only the newly validated
+	credential. (After all, there won't be any others, because the
+	invalid krbtgt couldn't have gotten them.) Most of the code is
+	taken from krb5_mk_req, since it did the right thing.
+	(main): add -v option, validates the ticket already in the
+	selected cache.
+
+Wed May  1 02:37:17 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kinit.c (main): add -s starttime option. Have it accept a delta
+	time (if the value doesn't parse as a valid timestamp.) Set the
+	postdated option as well. get time of day early enough in main so
+	the options code can use it. Make the end time relative to the
+	start time, if given.
+	* kinit.M: document -s option.
+
+Thu Feb 15 12:31:03 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kinit.c (main): Do not free memory until all done using it.
+
+Tue Sep 26 22:19:32 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* kinit.c (KRB5_DEFAULT_LIFE): default life should be 10 hours,
+	not eight, for practical/social reasons.
+
+Mon Aug 21 16:49:06 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kinit.c - Use string_to_deltat to parse lifetime arguments so that
+		we use common code.  Remove convtime().  Fix gcc -Wall.
+	* configure.in - Add -lkadm.
+	* kinit.M - Remove restriction on lifetimes.
+
+
+Fri Jul 7 15:53:29 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling.
+	* configure.in - Add KRB5_LIBRARIES.
+
+
+Thu Jun 15 17:45:47 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Fri Jun  9 18:37:27 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Fri Apr 28 15:49:39 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (kinit): Use $(LD) instead of $(CC) when trying to
+	        link.  (So purify works).  Note: to get things to work on
+		the mac, just put LD=$(CC) in the Makefile.
+
+Fri Apr 21 15:24:57 1995  Chris Provenzano (proven@mit.edu)
+
+	* configure.in : Make configure look for pwd.h and define
+		HAVE_PWD_H if found.
+
+Tue Mar 28 17:55:37 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Remove, conflicts with pre.in.
+	(kinit):  Link with $(CC) $(LDFLAGS), to work on the Mac.
+	* kinit.c (HAVE_PWD_H):  Use.
+	(NO_KEYTAB):  Skip keytab support if defined.
+	FIXME:  NO_KEYTAB needs to be set by configure.
+
+Fri Mar 24 14:45:00 1995    <tytso@rsx-11.mit.edu>
+
+	* kinit.c (main): Remove the call to krb5_os_localaddr() since
+		get_in_tkt_XXXX will default appropriately.
+
+	* kinit.c (main): Kinit will print an error when there are two
+		many arguments.
+
+Thu Mar  2 12:31:49 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:27:21 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 02:10:44 1995  John Gilmore  (gnu at toad.com)
+
+	* kinit.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Mon Feb 13 23:50:52 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(LD) instead of $(CC) when linking.
+
+Thu Feb 02 22:43:38 1995  Chris Provenzano (proven@mit.edu)
+
+	* kinit.c (main()) Removed krb5_keytype, changed krb5_enctype to
+                krb5_enctype *, changed krb5_preauthtype to krb5_preauthtype *
+                for krb5_get_in_tkt_with_password() rotuine.
+
+	* kinit.c (main()) use new API for krb5_get_in_tkt(), and replace 
+		krb5_get_in_tkt_with_skey() with krb5_get_in_tkt_with_keytab()
+		and remove all unnecessary cruft.
+
+	* kinit.c Do a krb5_init_context() before using a krb5_context.
+
+Sat Jan 28 14:45:55 1995  Chris Provenzano (proven@mit.edu)
+
+        * kinit.c (main()) use new API for krb5_kt_get_entry().
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Mon Oct  3 19:14:30 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
+Fri Sep 30 22:14:12 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kinit.c: Add magic number placeholder to statically defined 
+	        structures.
+
+Mon Aug  8 22:26:11 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* kinit.c: Change name of preauthentication
+	KRB5_PADATA_ENC_TIMESTAMP to KRB5_PADATA_ENC_UNIX_TIME
+
+Sat Jul 16 03:01:49 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* kinit.c: frob error codes
+
diff --git a/mechglue/src/clients/kinit/Makefile.in b/mechglue/src/clients/kinit/Makefile.in
new file mode 100644
index 000000000..dbdf2714c
--- /dev/null
+++ b/mechglue/src/clients/kinit/Makefile.in
@@ -0,0 +1,30 @@
+thisconfigdir=./..
+myfulldir=clients/kinit
+mydir=kinit
+BUILDTOP=$(REL)..$(S)..
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+##WIN32##LOCALINCLUDES=-I$(BUILDTOP)\util\windows
+##WIN32##DEFINES=-DGETOPT_LONG
+
+all-unix:: kinit
+all-windows:: $(OUTPRE)kinit.exe
+
+kinit: kinit.o $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o $@ kinit.o $(KRB4COMPAT_LIBS)
+
+$(OUTPRE)kinit.exe: $(OUTPRE)kinit.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.lib $(KLIB) $(CLIB)
+	link $(EXE_LINKOPTS) -out:$@ $** advapi32.lib
+
+clean-unix::
+	$(RM) kinit.o kinit
+
+install-unix::
+	for f in kinit; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		$(DESTDIR)$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
diff --git a/mechglue/src/clients/kinit/kinit.M b/mechglue/src/clients/kinit/kinit.M
new file mode 100644
index 000000000..52ad59de6
--- /dev/null
+++ b/mechglue/src/clients/kinit/kinit.M
@@ -0,0 +1,200 @@
+.\" clients/kinit/kinit.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH KINIT 1
+.SH NAME
+kinit \- obtain and cache Kerberos ticket-granting ticket
+.SH SYNOPSIS
+.TP
+.B kinit
+.ad l
+[\fB\-5\fP]
+[\fB\-4\fP]
+[\fB\-V\fP]
+[\fB\-l\fP \fIlifetime\fP] [\fB\-s\fP \fIstart_time\fP]
+[\fB\-r\fP \fIrenewable_life\fP]
+[\fB\-p\fP | \fB\-P\fP]
+[\fB\-f\fP | \fB\-F\fP]
+[\fB\-a\fP]
+[\fB\-A\fP]
+[\fB\-v\fP] [\fB\-R\fP]
+[\fB\-k\fP [\fB\-t\fP \fIkeytab_file\fP]] [\fB\-c\fP \fIcache_name\fP]
+[\fB\-S\fP \fIservice_name\fP] [\fIprincipal\fP]
+.ad b
+.br
+.SH DESCRIPTION
+.I kinit
+obtains and caches an initial ticket-granting ticket for
+.IR principal .  The typical default behavior is to acquire only
+Kerberos 5 tickets.  However, if kinit was built with both 
+Kerberos 4 support and with the default behavior of acquiring both
+types of tickets, it will try to acquire both Kerberos 5 and Kerberos 4
+by default.
+Any documentation particular to Kerberos 4 does not apply if Kerberos 4
+support was not built into kinit.
+.SH OPTIONS
+.TP
+.B \-5
+get Kerberos 5 tickets.  This overrides whatever the default built-in
+behavior may be.  This option may be used with
+.B \-4
+.
+.TP
+.B \-4
+get Kerberos 4 tickets.  This overrides whatever the default built-in
+behavior may be.  This option is only available if kinit was built
+with Kerberos 4 compatibility.  This option may be used with 
+.B \-5
+.
+.TP
+.B \-V
+display verbose output.
+.TP
+\fB\-l\fP \fIlifetime\fP
+requests a ticket with the lifetime
+.IR lifetime .
+The value for
+.I lifetime
+must be followed immediately by one of the following delimiters:
+.sp
+.nf
+.in +.3i
+\fBs\fP  seconds
+\fBm\fP  minutes
+\fBh\fP  hours
+\fBd\fP  days
+.in -.3i
+.fi
+.sp
+as in "kinit -l 90m".  You cannot mix units; a value of `3h30m' will
+result in an error.
+.sp
+If the
+.B \-l
+option is not specified, the default ticket lifetime (configured by each
+site) is used.  Specifying a ticket lifetime longer than the maximum
+ticket lifetime (configured by each site) results in a ticket with the
+maximum lifetime.
+.TP
+\fB\-s\fP \fIstart_time\fP
+requests a postdated ticket, valid starting at
+.IR start_time .
+Postdated tickets are issued with the
+.I invalid
+flag set, and need to be fed back to the kdc before use.
+(Not applicable to Kerberos 4.)
+.TP
+\fB\-r\fP \fIrenewable_life\fP
+requests renewable tickets, with a total lifetime of
+.IR renewable_life .
+The duration is in the same format as the
+.B \-l
+option, with the same delimiters.  (Not applicable to Kerberos 4.)
+.TP
+.B \-f
+request forwardable tickets.  (Not applicable to Kerberos 4.)
+.TP
+.B \-F
+do not request forwardable tickets.  (Not applicable to Kerberos 4.)
+.TP
+.B \-p
+request proxiable tickets.  (Not applicable to Kerberos 4.)
+.TP
+.B \-P
+do not request proxiable tickets.  (Not applicable to Kerberos 4.)
+.TP
+.B \-a
+request tickets with the local address[es].  (Not applicable to Kerberos 4.)
+.TP
+.B \-A
+request address-less tickets.  (Not applicable to Kerberos 4.)
+.TP
+.B \-v
+requests that the ticket granting ticket in the cache (with the 
+.I invalid
+flag set) be passed to the kdc for validation.  If the ticket is within
+its requested time range, the cache is replaced with the validated
+ticket.  (Not applicable to Kerberos 4.)
+.TP
+.B \-R
+requests renewal of the ticket-granting ticket.  Note that an expired
+ticket cannot be renewed, even if the ticket is still within its
+renewable life.  When using this option with Kerberos 4, the kdc must
+support Kerberos 5 to Kerberos 4 ticket conversion.
+.TP
+\fB\-k\fP [\fB\-t\fP \fIkeytab_file\fP]
+requests a host ticket, obtained from a key in the local host's
+.I keytab
+file.  The name and location of the keytab file may be specified with
+the
+.B \-t
+.I keytab_file
+option; otherwise the default name and location will be used.  When using
+this option with Kerberos 4, the kdc must support Kerberos 5 to Kerberos 4
+ticket conversion.
+.TP
+\fB\-c\fP \fIcache_name\fP
+use
+.I cache_name
+as the Kerberos 5 credentials (ticket) cache name and location; if this 
+option is not used, the default cache name and location are used.
+.sp
+The default credentials cache may vary between systems.  If the
+.B KRB5CCNAME
+environment variable is set, its value is used to name the default
+ticket cache.  Any existing contents of the cache are destroyed by
+.IR kinit .
+(Note: The default name for Kerberos 4 comes from the
+.B KRBTKFILE
+environment variable.  This option does not apply to Kerberos 4.)
+.TP
+\fB\-S\fP \fIservice_name\fP
+specify an alternate service name to use when
+getting initial tickets.  (Applicable to Kerberos 5 or if using both
+Kerberos 5 and Kerberos 4 with a kdc that supports Kerberos 5 to Kerberos 4
+ticket conversion.)
+.SH ENVIRONMENT
+.B Kinit
+uses the following environment variables:
+.TP "\w'.SM KRB5CCNAME\ \ 'u"
+.SM KRB5CCNAME
+Location of the Kerberos 5 credentials (ticket) cache.
+.TP "\w'.SM KRBTKFILE\ \ 'u"
+.SM KRBTKFILE
+Filename of the Kerberos 4 credentials (ticket) cache.
+.SH FILES
+.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
+/tmp/krb5cc_[uid]
+default location of Kerberos 5 credentials cache 
+([uid] is the decimal UID of the user).
+.TP "\w'/tmp/tkt[uid]\ \ 'u"
+/tmp/tkt[uid]
+default location of Kerberos 4 credentials cache 
+([uid] is the decimal UID of the user).
+.TP
+/etc/krb5.keytab
+default location for the local host's
+.B keytab
+file.
+.SH SEE ALSO
+klist(1), kdestroy(1), krb5(3)
diff --git a/mechglue/src/clients/kinit/kinit.c b/mechglue/src/clients/kinit/kinit.c
new file mode 100644
index 000000000..6ffebadd4
--- /dev/null
+++ b/mechglue/src/clients/kinit/kinit.c
@@ -0,0 +1,1129 @@
+/*
+ * clients/kinit/kinit.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Initialize a credentials cache.
+ */
+
+#include <krb5.h>
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#define HAVE_KRB524
+#else
+#undef HAVE_KRB524
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+#ifdef GETOPT_LONG
+#include <getopt.h>
+#else
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#ifdef sun
+/* SunOS4 unistd didn't declare these; okay to make unconditional?  */
+extern int optind;
+extern char *optarg;
+#endif /* sun */
+#else
+extern int optind;
+extern char *optarg;
+extern int getopt();
+#endif /* HAVE_UNISTD_H */
+#endif /* GETOPT_LONG */
+
+#ifndef _WIN32
+#define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x))
+#else
+#define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+static 
+char * get_name_from_os()
+{
+    struct passwd *pw;
+    if ((pw = getpwuid((int) getuid())))
+	return pw->pw_name;
+    return 0;
+}
+#else /* HAVE_PWD_H */
+#ifdef _WIN32
+static
+char * get_name_from_os()
+{
+    static char name[1024];
+    DWORD name_size = sizeof(name);
+    if (GetUserName(name, &name_size)) {
+	name[sizeof(name)-1] = 0; /* Just to be extra safe */
+	return name;
+    } else {
+	return 0;
+    }
+}
+#else /* _WIN32 */
+static
+char * get_name_from_os()
+{
+    return 0;
+}
+#endif /* _WIN32 */
+#endif /* HAVE_PWD_H */
+
+static char* progname_v5 = 0;
+#ifdef KRB5_KRB4_COMPAT
+static char* progname_v4 = 0;
+static char* progname_v524 = 0;
+#endif
+
+static int got_k5 = 0;
+static int got_k4 = 0;
+
+static int default_k5 = 1;
+#if defined(KRB5_KRB4_COMPAT) && defined(KINIT_DEFAULT_BOTH)
+static int default_k4 = 1;
+#else
+static int default_k4 = 0;
+#endif
+
+static int authed_k5 = 0;
+static int authed_k4 = 0;
+
+#define KRB4_BACKUP_DEFAULT_LIFE_SECS 24*60*60 /* 1 day */
+
+typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
+
+struct k_opts
+{
+    /* in seconds */
+    krb5_deltat starttime;
+    krb5_deltat lifetime;
+    krb5_deltat rlife;
+
+    int forwardable;
+    int proxiable;
+    int addresses;
+
+    int not_forwardable;
+    int not_proxiable;
+    int no_addresses;
+
+    int verbose;
+
+    char* principal_name;
+    char* service_name;
+    char* keytab_name;
+    char* k5_cache_name;
+    char* k4_cache_name;
+
+    action_type action;
+};
+
+struct k5_data
+{
+    krb5_context ctx;
+    krb5_ccache cc;
+    krb5_principal me;
+    char* name;
+};
+
+struct k4_data
+{
+    krb5_deltat lifetime;
+#ifdef KRB5_KRB4_COMPAT
+    char aname[ANAME_SZ + 1];
+    char inst[INST_SZ + 1];
+    char realm[REALM_SZ + 1];
+    char name[ANAME_SZ + 1 + INST_SZ + 1 + REALM_SZ + 1];
+#endif
+};
+
+#ifdef GETOPT_LONG
+/* if struct[2] == NULL, then long_getopt acts as if the short flag
+   struct[3] was specified.  If struct[2] != NULL, then struct[3] is
+   stored in *(struct[2]), the array index which was specified is
+   stored in *index, and long_getopt() returns 0. */
+
+struct option long_options[] = {
+    { "noforwardable", 0, NULL, 'F' },
+    { "noproxiable", 0, NULL, 'P' },
+    { "addresses", 0, NULL, 'a'},
+    { "forwardable", 0, NULL, 'f' },
+    { "proxiable", 0, NULL, 'p' },
+    { "noaddresses", 0, NULL, 'A' },
+    { NULL, 0, NULL, 0 }
+};
+
+#define GETOPT(argc, argv, str) getopt_long(argc, argv, str, long_options, 0)
+#else
+#define GETOPT(argc, argv, str) getopt(argc, argv, str)
+#endif
+
+static void
+usage(progname)
+     char *progname;
+{
+#define USAGE_BREAK "\n\t"
+
+#ifdef GETOPT_LONG
+#define USAGE_LONG_FORWARDABLE " | --forwardable | --noforwardable"
+#define USAGE_LONG_PROXIABLE   " | --proxiable | --noproxiable"
+#define USAGE_LONG_ADDRESSES   " | --addresses | --noaddresses"
+#define USAGE_BREAK_LONG       USAGE_BREAK
+#else
+#define USAGE_LONG_FORWARDABLE ""
+#define USAGE_LONG_PROXIABLE   ""
+#define USAGE_LONG_ADDRESSES   ""
+#define USAGE_BREAK_LONG       ""
+#endif
+
+    fprintf(stderr, "Usage: %s [-5] [-4] [-V] "
+	    "[-l lifetime] [-s start_time] "
+	    USAGE_BREAK
+	    "[-r renewable_life] "
+	    "[-f | -F" USAGE_LONG_FORWARDABLE "] "
+	    USAGE_BREAK_LONG
+	    "[-p | -P" USAGE_LONG_PROXIABLE "] "
+	    USAGE_BREAK_LONG
+	    "[-A" USAGE_LONG_ADDRESSES "] "
+	    USAGE_BREAK
+	    "[-v] [-R] "
+	    "[-k [-t keytab_file]] "
+	    USAGE_BREAK
+	    "[-c cachename] "
+	    "[-S service_name] [principal]"
+	    "\n\n", 
+	    progname);
+
+#define KRB_AVAIL_STRING(x) ((x)?"available":"not available")
+
+#define OPTTYPE_KRB5   "5"
+#define OPTTYPE_KRB4   "4"
+#define OPTTYPE_EITHER "Either 4 or 5"
+#ifdef HAVE_KRB524
+#define OPTTYPE_BOTH "5, or both 5 and 4"
+#else
+#define OPTTYPE_BOTH "5"
+#endif
+
+#ifdef KRB5_KRB4_COMPAT
+#define USAGE_OPT_FMT "%s%-50s%s\n"
+#define ULINE(indent, col1, col2) \
+fprintf(stderr, USAGE_OPT_FMT, indent, col1, col2)
+#else
+#define USAGE_OPT_FMT "%s%s\n"
+#define ULINE(indent, col1, col2) \
+fprintf(stderr, USAGE_OPT_FMT, indent, col1)
+#endif
+
+    ULINE("    ", "options:", "valid with Kerberos:");
+    fprintf(stderr, "\t-5 Kerberos 5 (%s)\n", KRB_AVAIL_STRING(got_k5));
+    fprintf(stderr, "\t-4 Kerberos 4 (%s)\n", KRB_AVAIL_STRING(got_k4));
+    fprintf(stderr, "\t   (Default behavior is to try %s%s%s%s)\n",
+	    default_k5?"Kerberos 5":"",
+	    (default_k5 && default_k4)?" and ":"",
+	    default_k4?"Kerberos 4":"",
+	    (!default_k5 && !default_k4)?"neither":"");
+    ULINE("\t", "-V verbose",                   OPTTYPE_EITHER);
+    ULINE("\t", "-l lifetime",                  OPTTYPE_EITHER);
+    ULINE("\t", "-s start time",                OPTTYPE_KRB5);
+    ULINE("\t", "-r renewable lifetime",        OPTTYPE_KRB5);
+    ULINE("\t", "-f forwardable",               OPTTYPE_KRB5);
+    ULINE("\t", "-F not forwardable",           OPTTYPE_KRB5);
+    ULINE("\t", "-p proxiable",                 OPTTYPE_KRB5);
+    ULINE("\t", "-P not proxiable",             OPTTYPE_KRB5);
+    ULINE("\t", "-A do not include addresses",  OPTTYPE_KRB5);
+    ULINE("\t", "-v validate",                  OPTTYPE_KRB5);
+    ULINE("\t", "-R renew",                     OPTTYPE_BOTH);
+    ULINE("\t", "-k use keytab",                OPTTYPE_BOTH);
+    ULINE("\t", "-t filename of keytab to use", OPTTYPE_BOTH);
+    ULINE("\t", "-c Kerberos 5 cache name",     OPTTYPE_KRB5);
+    /* This options is not yet available: */
+    /* ULINE("\t", "-C Kerberos 4 cache name",     OPTTYPE_KRB4); */
+    ULINE("\t", "-S service",                   OPTTYPE_BOTH);
+    exit(2);
+}
+
+static char *
+parse_options(argc, argv, opts, progname)
+    int argc;
+    char **argv;
+    struct k_opts* opts;
+    char *progname;
+{
+    krb5_error_code code;
+    int errflg = 0;
+    int use_k4 = 0;
+    int use_k5 = 0;
+    int i;
+
+    while ((i = GETOPT(argc, argv, "r:fpFP54AVl:s:c:kt:RS:v"))
+	   != -1) {
+	switch (i) {
+	case 'V':
+	    opts->verbose = 1;
+	    break;
+	case 'l':
+	    /* Lifetime */
+	    code = krb5_string_to_deltat(optarg, &opts->lifetime);
+	    if (code != 0 || opts->lifetime == 0) {
+		fprintf(stderr, "Bad lifetime value %s\n", optarg);
+		errflg++;
+	    }
+	    break;
+	case 'r':
+	    /* Renewable Time */
+	    code = krb5_string_to_deltat(optarg, &opts->rlife);
+	    if (code != 0 || opts->rlife == 0) {
+		fprintf(stderr, "Bad lifetime value %s\n", optarg);
+		errflg++;
+	    }
+	    break;
+	case 'f':
+	    opts->forwardable = 1;
+	    break;
+	case 'F':
+	    opts->not_forwardable = 1;
+	    break;
+	case 'p':
+	    opts->proxiable = 1;
+	    break;
+	case 'P':
+	    opts->not_proxiable = 1;
+	    break;
+	case 'a':
+	    /* Note: This is supported only with GETOPT_LONG */
+	    opts->addresses = 1;
+	    break;
+	case 'A':
+	    opts->no_addresses = 1;
+	    break;
+       	case 's':
+	    code = krb5_string_to_deltat(optarg, &opts->starttime);
+	    if (code != 0 || opts->starttime == 0) {
+		krb5_timestamp abs_starttime;
+
+		code = krb5_string_to_timestamp(optarg, &abs_starttime);
+		if (code != 0 || abs_starttime == 0) {
+		    fprintf(stderr, "Bad start time value %s\n", optarg);
+		    errflg++;
+		} else {
+		    opts->starttime = abs_starttime - time(0);
+		}
+	    }
+	    break;
+	case 'S':
+	    opts->service_name = optarg;
+	    break;
+	case 'k':
+	    opts->action = INIT_KT;
+	    break;
+	case 't':
+	    if (opts->keytab_name)
+	    {
+		fprintf(stderr, "Only one -t option allowed.\n");
+		errflg++;
+	    } else {
+		opts->keytab_name = optarg;
+	    }
+	    break;
+	case 'R':
+	    opts->action = RENEW;
+	    break;
+	case 'v':
+	    opts->action = VALIDATE;
+	    break;
+       	case 'c':
+	    if (opts->k5_cache_name)
+	    {
+		fprintf(stderr, "Only one -c option allowed\n");
+		errflg++;
+	    } else {
+		opts->k5_cache_name = optarg;
+	    }
+	    break;
+#if 0
+	    /*
+	      A little more work is needed before we can enable this
+	      option.
+	    */
+	case 'C':
+	    if (opts->k4_cache_name)
+	    {
+		fprintf(stderr, "Only one -C option allowed\n");
+		errflg++;
+	    } else {
+		opts->k4_cache_name = optarg;
+	    }
+	    break;
+#endif
+	case '4':
+	    if (!got_k4)
+	    {
+#ifdef KRB5_KRB4_COMPAT
+		fprintf(stderr, "Kerberos 4 support could not be loaded\n");
+#else
+		fprintf(stderr, "This was not built with Kerberos 4 support\n");
+#endif
+		exit(3);
+	    }
+	    use_k4 = 1;
+	    break;
+	case '5':
+	    if (!got_k5)
+	    {
+		fprintf(stderr, "Kerberos 5 support could not be loaded\n");
+		exit(3);
+	    }
+	    use_k5 = 1;
+	    break;
+	default:
+	    errflg++;
+	    break;
+	}
+    }
+
+    if (opts->forwardable && opts->not_forwardable)
+    {
+	fprintf(stderr, "Only one of -f and -F allowed\n");
+	errflg++;
+    }
+    if (opts->proxiable && opts->not_proxiable)
+    {
+	fprintf(stderr, "Only one of -p and -P allowed\n");
+	errflg++;
+    }
+    if (opts->addresses && opts->no_addresses)
+    {
+	fprintf(stderr, "Only one of -a and -A allowed\n");
+	errflg++;
+    }
+
+    if (argc - optind > 1) {
+	fprintf(stderr, "Extra arguments (starting with \"%s\").\n",
+		argv[optind+1]);
+	errflg++;
+    }
+
+    /* At this point, if errorless, we know we only have one option
+       selection */
+    if (!use_k5 && !use_k4) {
+	use_k5 = default_k5;
+	use_k4 = default_k4;
+    }
+
+    /* Now, we encode the OPTTYPE stuff here... */
+    if (!use_k5 &&
+	(opts->starttime || opts->rlife || opts->forwardable || 
+	 opts->proxiable || opts->addresses || opts->not_forwardable || 
+	 opts->not_proxiable || opts->no_addresses || 
+	 (opts->action == VALIDATE) || opts->k5_cache_name))
+    {
+	fprintf(stderr, "Specified option that requires Kerberos 5\n");
+	errflg++;
+    }
+    if (!use_k4 &&
+	opts->k4_cache_name)
+    {
+	fprintf(stderr, "Specified option that require Kerberos 4\n");
+	errflg++;
+    }
+    if (
+#ifdef HAVE_KRB524
+	!use_k5
+#else
+	use_k4
+#endif
+	&& (opts->service_name || opts->keytab_name || 
+	    (opts->action == INIT_KT) || (opts->action == RENEW))
+	)
+    {
+	fprintf(stderr, "Specified option that requires Kerberos 5\n");
+	errflg++;
+    }
+
+    if (errflg) {
+	usage(progname);
+    }
+
+    got_k5 = got_k5 && use_k5;
+    got_k4 = got_k4 && use_k4;
+
+    opts->principal_name = (optind == argc-1) ? argv[optind] : 0;
+    return opts->principal_name;
+}
+
+static int
+k5_begin(opts, k5, k4)
+    struct k_opts* opts;
+struct k5_data* k5;
+struct k4_data* k4;
+{
+    char* progname = progname_v5;
+    krb5_error_code code = 0;
+
+    if (!got_k5)
+	return 0;
+
+    code = krb5_init_context(&k5->ctx);
+    if (code) {
+	com_err(progname, code, "while initializing Kerberos 5 library");
+	return 0;
+    }
+    if (opts->k5_cache_name)
+    {
+	code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc);
+	if (code != 0) {
+	    com_err(progname, code, "resolving ccache %s",
+		    opts->k5_cache_name);
+	    return 0;
+	}
+    } 
+    else
+    {
+	if ((code = krb5_cc_default(k5->ctx, &k5->cc))) {
+	    com_err(progname, code, "while getting default ccache");
+	    return 0;
+	}
+    }
+
+    if (opts->principal_name)
+    {
+	/* Use specified name */
+	if ((code = krb5_parse_name(k5->ctx, opts->principal_name, 
+				    &k5->me))) {
+	    com_err(progname, code, "when parsing name %s", 
+		    opts->principal_name);
+	    return 0;
+	}
+    }
+    else
+    {
+	/* No principal name specified */
+	if (opts->action == INIT_KT) {
+	    /* Use the default host/service name */
+	  code = krb5_sname_to_principal(k5->ctx, NULL, NULL,
+					 KRB5_NT_SRV_HST, &k5->me);
+	  if (code) {
+	    com_err(progname, code,
+		    "when creating default server principal name");
+	    return 0;
+	  }
+	} else {
+	  /* Get default principal from cache if one exists */
+	  code = krb5_cc_get_principal(k5->ctx, k5->cc, 
+				       &k5->me);
+	  if (code)
+	    {
+	      char *name = get_name_from_os();
+	      if (!name)
+		{
+		  fprintf(stderr, "Unable to identify user\n");
+		  return 0;
+		}
+	      if ((code = krb5_parse_name(k5->ctx, name, 
+					  &k5->me)))
+		{
+		  com_err(progname, code, "when parsing name %s", 
+			  name);
+		  return 0;
+		}
+	    }
+	}
+    }
+
+    code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
+    if (code) {
+	com_err(progname, code, "when unparsing name");
+	return 0;
+    }
+    opts->principal_name = k5->name;
+
+#ifdef KRB5_KRB4_COMPAT
+    if (got_k4)
+    {
+	/* Translate to a Kerberos 4 principal */
+	code = krb5_524_conv_principal(k5->ctx, k5->me,
+				       k4->aname, k4->inst, k4->realm);
+	if (code) {
+	    k4->aname[0] = 0;
+	    k4->inst[0] = 0;
+	    k4->realm[0] = 0;
+	}
+    }
+#endif
+    return 1;
+}
+
+static void
+k5_end(k5)
+    struct k5_data* k5;
+{
+    if (k5->name)
+	krb5_free_unparsed_name(k5->ctx, k5->name);
+    if (k5->me)
+	krb5_free_principal(k5->ctx, k5->me);
+    if (k5->cc)
+	krb5_cc_close(k5->ctx, k5->cc);
+    if (k5->ctx)
+	krb5_free_context(k5->ctx);
+    memset(k5, 0, sizeof(*k5));
+}
+
+static int
+k4_begin(opts, k4)
+    struct k_opts* opts;
+    struct k4_data* k4;
+{
+#ifdef KRB5_KRB4_COMPAT
+    char* progname = progname_v4;
+    int k_errno = 0;
+#endif
+
+    if (!got_k4)
+	return 0;
+
+#ifdef KRB5_KRB4_COMPAT
+    if (k4->aname[0])
+	goto skip;
+
+    if (opts->principal_name)
+    {
+	/* Use specified name */
+        k_errno = kname_parse(k4->aname, k4->inst, k4->realm, 
+			      opts->principal_name);
+	if (k_errno)
+	{
+	    fprintf(stderr, "%s: %s\n", progname, 
+		    krb_get_err_text(k_errno));
+	    return 0;
+	}
+    } else {
+	/* No principal name specified */
+	if (opts->action == INIT_KT) {
+	    /* Use the default host/service name */
+	    /* XXX - need to add this functionality */
+	    fprintf(stderr, "%s: Kerberos 4 srvtab support is not "
+		    "implemented\n", progname);
+	    return 0;
+	} else {
+	    /* Get default principal from cache if one exists */
+	    k_errno = krb_get_tf_fullname(tkt_string(), k4->aname, 
+					  k4->inst, k4->realm);
+	    if (k_errno)
+	    {
+		char *name = get_name_from_os();
+		if (!name)
+		{
+		    fprintf(stderr, "Unable to identify user\n");
+		    return 0;
+		}
+		k_errno = kname_parse(k4->aname, k4->inst, k4->realm,
+				      name);
+		if (k_errno)
+		{
+		    fprintf(stderr, "%s: %s\n", progname, 
+			    krb_get_err_text(k_errno));
+		    return 0;
+		}
+	    }
+	}
+    }
+
+    if (!k4->realm[0])
+	krb_get_lrealm(k4->realm, 1);
+
+    if (k4->inst[0])
+	sprintf(k4->name, "%s.%s@%s", k4->aname, k4->inst, k4->realm);
+    else
+	sprintf(k4->name, "%s@%s", k4->aname, k4->realm);
+    opts->principal_name = k4->name;
+
+ skip:
+    if (k4->aname[0] && !k_isname(k4->aname))
+    {
+	fprintf(stderr, "%s: bad Kerberos 4 name format\n", progname);
+	return 0;
+    }
+
+    if (k4->inst[0] && !k_isinst(k4->inst))
+    {
+	fprintf(stderr, "%s: bad Kerberos 4 instance format\n", progname);
+	return 0;
+    }
+
+    if (k4->realm[0] && !k_isrealm(k4->realm))
+    {
+	fprintf(stderr, "%s: bad Kerberos 4 realm format\n", progname);
+	return 0;
+    }
+#endif /* KRB5_KRB4_COMPAT */
+    return 1;
+}
+
+static void
+k4_end(k4)
+    struct k4_data* k4;
+{
+    memset(k4, 0, sizeof(*k4));
+}
+
+#ifdef KRB5_KRB4_COMPAT
+static char stash_password[1024];
+static int got_password = 0;
+#endif /* KRB5_KRB4_COMPAT */
+
+static krb5_error_code
+KRB5_CALLCONV
+kinit_prompter(
+    krb5_context ctx,
+    void *data,
+    const char *name,
+    const char *banner,
+    int num_prompts,
+    krb5_prompt prompts[]
+    )
+{
+    int i;
+    krb5_prompt_type *types;
+    krb5_error_code rc =
+	krb5_prompter_posix(ctx, data, name, banner, num_prompts, prompts);
+    if (!rc && (types = krb5_get_prompt_types(ctx)))
+	for (i = 0; i < num_prompts; i++)
+	    if ((types[i] == KRB5_PROMPT_TYPE_PASSWORD) ||
+		(types[i] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN))
+	    {
+#ifdef KRB5_KRB4_COMPAT
+		strncpy(stash_password, prompts[i].reply->data,
+			sizeof(stash_password));
+		got_password = 1;
+#endif
+	    }
+    return rc;
+}
+
+static int
+k5_kinit(opts, k5)
+    struct k_opts* opts;
+    struct k5_data* k5;
+{
+    char* progname = progname_v5;
+    int notix = 1;
+    krb5_keytab keytab = 0;
+    krb5_creds my_creds;
+    krb5_error_code code = 0;
+    krb5_get_init_creds_opt options;
+
+    if (!got_k5)
+	return 0;
+
+    krb5_get_init_creds_opt_init(&options);
+    memset(&my_creds, 0, sizeof(my_creds));
+
+    /*
+      From this point on, we can goto cleanup because my_creds is
+      initialized.
+    */
+
+    if (opts->lifetime)
+	krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime);
+    if (opts->rlife)
+	krb5_get_init_creds_opt_set_renew_life(&options, opts->rlife);
+    if (opts->forwardable)
+	krb5_get_init_creds_opt_set_forwardable(&options, 1);
+    if (opts->not_forwardable)
+	krb5_get_init_creds_opt_set_forwardable(&options, 0);
+    if (opts->proxiable)
+	krb5_get_init_creds_opt_set_proxiable(&options, 1);
+    if (opts->not_proxiable)
+	krb5_get_init_creds_opt_set_proxiable(&options, 0);
+    if (opts->addresses)
+    {
+	krb5_address **addresses = NULL;
+	code = krb5_os_localaddr(k5->ctx, &addresses);
+	if (code != 0) {
+	    com_err(progname, code, "getting local addresses");
+	    goto cleanup;
+	}
+	krb5_get_init_creds_opt_set_address_list(&options, addresses);
+    }
+    if (opts->no_addresses)
+	krb5_get_init_creds_opt_set_address_list(&options, NULL);
+
+    if ((opts->action == INIT_KT) && opts->keytab_name)
+    {
+	code = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab);
+	if (code != 0) {
+	    com_err(progname, code, "resolving keytab %s", 
+		    opts->keytab_name);
+	    goto cleanup;
+	}
+    }
+
+    switch (opts->action) {
+    case INIT_PW:
+	code = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me,
+					    0, kinit_prompter, 0,
+					    opts->starttime, 
+					    opts->service_name,
+					    &options);
+	break;
+    case INIT_KT:
+	code = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me,
+					  keytab,
+					  opts->starttime, 
+					  opts->service_name,
+					  &options);
+	break;
+    case VALIDATE:
+	code = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->cc,
+					opts->service_name);
+	break;
+    case RENEW:
+	code = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->cc,
+				      opts->service_name);
+	break;
+    }
+
+    if (code) {
+	char *doing = 0;
+	switch (opts->action) {
+	case INIT_PW:
+	case INIT_KT:
+	    doing = "getting initial credentials";
+	    break;
+	case VALIDATE:
+	    doing = "validating credentials";
+	    break;
+	case RENEW:
+	    doing = "renewing credentials";
+	    break;
+	}
+
+	/* If got code == KRB5_AP_ERR_V4_REPLY && got_k4, we should
+	   let the user know that maybe he/she wants -4. */
+	if (code == KRB5KRB_AP_ERR_V4_REPLY && got_k4)
+	    com_err(progname, code, "while %s\n"
+		    "The KDC doesn't support v5.  "
+		    "You may want the -4 option in the future",
+		    doing);
+	else if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+	    fprintf(stderr, "%s: Password incorrect while %s\n", progname,
+		    doing);
+	else
+	    com_err(progname, code, "while %s", doing);
+	goto cleanup;
+    }
+
+    if (!opts->lifetime) {
+	/* We need to figure out what lifetime to use for Kerberos 4. */
+	opts->lifetime = my_creds.times.endtime - my_creds.times.authtime;
+    }
+
+    code = krb5_cc_initialize(k5->ctx, k5->cc, k5->me);
+    if (code) {
+	com_err(progname, code, "when initializing cache %s",
+		opts->k5_cache_name?opts->k5_cache_name:"");
+	goto cleanup;
+    }
+
+    code = krb5_cc_store_cred(k5->ctx, k5->cc, &my_creds);
+    if (code) {
+	com_err(progname, code, "while storing credentials");
+	goto cleanup;
+    }
+
+    notix = 0;
+
+ cleanup:
+    if (my_creds.client == k5->me) {
+	my_creds.client = 0;
+    }
+    krb5_free_cred_contents(k5->ctx, &my_creds);
+    if (keytab)
+	krb5_kt_close(k5->ctx, keytab);
+    return notix?0:1;
+}
+
+static int
+k4_kinit(opts, k4, ctx)
+    struct k_opts* opts;
+    struct k4_data* k4;
+    krb5_context ctx;
+{
+#ifdef KRB5_KRB4_COMPAT
+    char* progname = progname_v4;
+    int k_errno = 0;
+#endif
+
+    if (!got_k4)
+	return 0;
+
+    if (opts->starttime)
+	return 0;
+
+#ifdef KRB5_KRB4_COMPAT
+    if (!k4->lifetime)
+	k4->lifetime = opts->lifetime;
+    if (!k4->lifetime)
+	k4->lifetime = KRB4_BACKUP_DEFAULT_LIFE_SECS;
+
+    k4->lifetime = krb_time_to_life(0, k4->lifetime);
+
+    switch (opts->action)
+    {
+    case INIT_PW:
+	if (!got_password) {
+	    unsigned int pwsize = sizeof(stash_password);
+	    krb5_error_code code;
+	    char prompt[1024];
+
+	    sprintf(prompt, "Password for %s", opts->principal_name);
+	    stash_password[0] = 0;
+	    /*
+	      Note: krb5_read_password does not actually look at the
+	      context, so we're ok even if we don't have a context.  If
+	      we cannot dynamically load krb5, we can substitute any
+	      decent read password function instead of the krb5 one.
+	    */
+	    code = krb5_read_password(ctx, prompt, 0, stash_password, &pwsize);
+	    if (code || pwsize == 0)
+	    {
+		fprintf(stderr, "Error while reading password for '%s'\n",
+			opts->principal_name);
+		memset(stash_password, 0, sizeof(stash_password));
+		return 0;
+	    }
+	    got_password = 1;
+	}
+	k_errno = krb_get_pw_in_tkt(k4->aname, k4->inst, k4->realm, "krbtgt", 
+				    k4->realm, k4->lifetime, stash_password);
+
+	if (k_errno) {
+	    fprintf(stderr, "%s: %s\n", progname, 
+		    krb_get_err_text(k_errno));
+	    if (authed_k5)
+	        fprintf(stderr, "Maybe your KDC does not support v4.  "
+			"Try the -5 option next time.\n");
+	    return 0;
+	}
+	return 1;
+#ifndef HAVE_KRB524
+    case INIT_KT:
+	fprintf(stderr, "%s: srvtabs are not supported\n", progname);
+	return 0;
+    case RENEW:
+	fprintf(stderr, "%s: renewal of krb4 tickets is not supported\n",
+		progname);
+	return 0;
+#else
+    /* These cases are handled by the 524 code - this prevents the compiler 
+       warnings of not using all the enumerated types.
+    */ 
+    case INIT_KT:
+    case RENEW:
+    case VALIDATE:
+        return 0;
+#endif
+    }
+#endif
+    return 0;
+}
+
+static char*
+getvprogname(v, progname)
+    char *v, *progname;
+{
+    unsigned int len = strlen(progname) + 2 + strlen(v) + 2;
+    char *ret = malloc(len);
+    if (ret)
+	sprintf(ret, "%s(v%s)", progname, v);
+    else
+	ret = progname;
+    return ret;
+}
+
+#ifdef HAVE_KRB524
+/* Convert krb5 tickets to krb4. */
+static int try_convert524(k5)
+    struct k5_data* k5;
+{
+    char * progname = progname_v524;
+    krb5_error_code code = 0;
+    int icode = 0;
+    krb5_principal kpcserver = 0;
+    krb5_creds *v5creds = 0;
+    krb5_creds increds;
+    CREDENTIALS v4creds;
+
+    if (!got_k4 || !got_k5)
+	return 0;
+
+    memset((char *) &increds, 0, sizeof(increds));
+    /*
+      From this point on, we can goto cleanup because increds is
+      initialized.
+    */
+
+    if ((code = krb5_build_principal(k5->ctx,
+				     &kpcserver, 
+				     krb5_princ_realm(k5->ctx, k5->me)->length,
+				     krb5_princ_realm(k5->ctx, k5->me)->data,
+				     "krbtgt",
+				     krb5_princ_realm(k5->ctx, k5->me)->data,
+				     NULL))) {
+	com_err(progname, code,
+		"while creating service principal name");
+	goto cleanup;
+    }
+
+    increds.client = k5->me;
+    increds.server = kpcserver;
+    /* Prevent duplicate free calls.  */
+    kpcserver = 0;
+
+    increds.times.endtime = 0;
+    increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+    if ((code = krb5_get_credentials(k5->ctx, 0, 
+				     k5->cc,
+				     &increds, 
+				     &v5creds))) {
+	com_err(progname, code,
+		"getting V5 credentials");
+	goto cleanup;
+    }
+    if ((icode = krb524_convert_creds_kdc(k5->ctx,
+					  v5creds,
+					  &v4creds))) {
+	com_err(progname, icode, 
+		"converting to V4 credentials");
+	goto cleanup;
+    }
+    /* this is stolen from the v4 kinit */
+    /* initialize ticket cache */
+    if ((icode = in_tkt(v4creds.pname, v4creds.pinst)
+	 != KSUCCESS)) {
+	com_err(progname, icode,
+		"trying to create the V4 ticket file");
+	goto cleanup;
+    }
+    /* stash ticket, session key, etc. for future use */
+    if ((icode = krb_save_credentials(v4creds.service,
+				      v4creds.instance,
+				      v4creds.realm, 
+				      v4creds.session,
+				      v4creds.lifetime,
+				      v4creds.kvno,
+				      &(v4creds.ticket_st), 
+				      v4creds.issue_date))) {
+	com_err(progname, icode,
+		"trying to save the V4 ticket");
+	goto cleanup;
+    }
+
+ cleanup:
+    memset(&v4creds, 0, sizeof(v4creds));
+    if (v5creds)
+	krb5_free_creds(k5->ctx, v5creds);
+    increds.client = 0;
+    krb5_free_cred_contents(k5->ctx, &increds);
+    if (kpcserver)
+	krb5_free_principal(k5->ctx, kpcserver);
+    return !(code || icode);
+}
+#endif /* HAVE_KRB524 */
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    struct k_opts opts;
+    struct k5_data k5;
+    struct k4_data k4;
+    char *progname;
+
+
+    progname = GET_PROGNAME(argv[0]);
+    progname_v5 = getvprogname("5", progname);
+#ifdef KRB5_KRB4_COMPAT
+    progname_v4 = getvprogname("4", progname);
+    progname_v524 = getvprogname("524", progname);
+#endif
+
+    /* Ensure we can be driven from a pipe */
+    if(!isatty(fileno(stdin)))
+	setvbuf(stdin, 0, _IONBF, 0);
+    if(!isatty(fileno(stdout)))
+	setvbuf(stdout, 0, _IONBF, 0);
+    if(!isatty(fileno(stderr)))
+	setvbuf(stderr, 0, _IONBF, 0);
+
+    /*
+      This is where we would put in code to dynamically load Kerberos
+      libraries.  Currenlty, we just get them implicitly.
+    */
+    got_k5 = 1;
+#ifdef KRB5_KRB4_COMPAT
+    got_k4 = 1;
+#endif
+
+    memset(&opts, 0, sizeof(opts));
+    opts.action = INIT_PW;
+
+    memset(&k5, 0, sizeof(k5));
+    memset(&k4, 0, sizeof(k4));
+
+    parse_options(argc, argv, &opts, progname);
+
+    got_k5 = k5_begin(&opts, &k5, &k4);
+    got_k4 = k4_begin(&opts, &k4);
+
+    authed_k5 = k5_kinit(&opts, &k5);
+#ifdef HAVE_KRB524
+    if (authed_k5)
+	authed_k4 = try_convert524(&k5);
+#endif
+    if (!authed_k4)
+	authed_k4 = k4_kinit(&opts, &k4, k5.ctx);
+#ifdef KRB5_KRB4_COMPAT
+    memset(stash_password, 0, sizeof(stash_password));
+#endif
+
+    if (authed_k5 && opts.verbose)
+	fprintf(stderr, "Authenticated to Kerberos v5\n");
+    if (authed_k4 && opts.verbose)
+	fprintf(stderr, "Authenticated to Kerberos v4\n");
+
+    k5_end(&k5);
+    k4_end(&k4);
+
+    if ((got_k5 && !authed_k5) || (got_k4 && !authed_k4) ||
+	(!got_k5 && !got_k4))
+	exit(1);
+    return 0;
+}
diff --git a/mechglue/src/clients/klist/.Sanitize b/mechglue/src/clients/klist/.Sanitize
new file mode 100644
index 000000000..585d1da17
--- /dev/null
+++ b/mechglue/src/clients/klist/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+klist.M
+klist.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/clients/klist/ChangeLog b/mechglue/src/clients/klist/ChangeLog
new file mode 100644
index 000000000..70aa52e12
--- /dev/null
+++ b/mechglue/src/clients/klist/ChangeLog
@@ -0,0 +1,376 @@
+2005-01-04  Jeffrey Altman <jaltman@mit.edu>
+   
+        * Makefile.in: add support library to klist dependencies
+
+2004-11-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Define.
+
+2004-08-31  Tom Yu  <tlyu@mit.edu>
+
+	* klist.c: Fix double-free vulnerabilities.
+
+2004-07-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c: Include autoconf.h before network headers.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac): Target deleted.
+
+2003-07-27  Sam Hartman  <hartmans@mit.edu>
+
+	* klist.M : Note that -s can return non-zero if credentials are
+	expired 
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(OUTPRE)klist.exe): Use ws2_32.lib instead of
+	wsock32.lib.
+
+2002-06-13  Jen Selby <jenselby@mit.edu>
+
+	* klist.M: updated the manpage to show new ticket flags
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* klist.c: Do not pull in winsock.h since we already pull in
+	port-sockets.h.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c (one_addr): Make 0 unsigned (!) in conditional
+	expression in getnameinfo call to avoid silly compiler warning.
+
+2002-03-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c: Include fake-addrinfo.h, not fake-addrinfo.c.
+	(FAI_PREFIX): Delete.
+
+2002-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c: Include port-sockets.h and socket-utils.h instead of
+	k5-int.h.
+	(NEED_SOCKETS): Don't define.
+
+2001-11-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c (flags_string): Display transit-policy-checked,
+	ok-as-delegate, and anonymous ticket flags.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c: Make prototypes unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c: Delete _MSDOS support.
+
+2001-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c: Include fake-addrinfo.c instead of .h file.
+	(FAI_IMPLEMENTATION): Don't define.
+
+2001-08-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c: Include k5-int.h and fake-addrinfo.h.
+	(NEED_SOCKETS, FAI_PREFIX, FAI_IMPLEMENTATION): Define macros.
+	(one_addr): Use getnameinfo always.
+
+2001-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c (one_addr): Pass UNIX address family, not Kerberos
+	address type, to inet_ntop.  Print different messages for unknown
+	address types and known address types we don't know how to print
+	(e.g., AF_INET6 without inet_ntop).
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* klist.c: Include unistd.h (if present) for getopt() prototype. 
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* klist.c (one_addr): Drop getipnodebyaddr support.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* klist.c (one_addr): gethostbyaddr takes an int as second argument.
+
+2000-10-09  Tom Yu  <tlyu@mit.edu>
+
+	* klist.c (do_v4_ccache): Call life_to_time().
+
+2000-08-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* klist.c: Compiler warning cleanups by declaring functions as
+	static, using existing global variables instead of trying to
+	shadow them, and removing assignments from conditionals.
+
+2000-04-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Link in getopt library on Windows.
+
+	* klist.c: Use getopt so that we can parse combined options (e.g.,
+	-an or -45).
+
+2000-03-07  Danilo Almeida  <dalmeida@mit.edu>
+
+	* klist.M: Get man page up-to-date.
+
+	* klist.c: Add support for combining -4 and -5.  Tweak usage info.
+
+2000-02-24  Ezra Peisach  <epeisach@engrailed.mit.edu>
+
+	* klist.c: Include <arpa/inet.h> if present for inet_ntop
+	prototype. Use const for the variable receiving the result of
+	inet_ntop.
+
+2000-02-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* klist.c: Fix GET_PROGNAME macro to properly return program name
+	under Win32.  Re-indent, turning spaces that should be tabs into
+	tabs.
+
+2000-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (klist): Fix to build under Unix again.
+
+2000-02-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* klist.c: Major revamp to support Kerberos 4 compatibility.  Code
+	restructured to allow changes to support Kerberos 4 or Kerberos 5
+	only operation depending on whether dynamic libraries are
+	avialable.  Explicit documentation and support files to make it
+	easy to do this will be forthcoming.
+
+1999-11-02  Ken Raeburn  <raeburn@raeburn.org>
+
+	* klist.c (one_addr): Always use indicated address family and
+	length in gethostbyaddr or getipnodebyaddr calls.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Windows fix for 10/26/99 cleanup.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-10-17  Ken Raeburn  <raeburn@raeburn.org>
+
+	* klist.c (one_addr): Use getipnodebyaddr and inet_ntop if
+	available.  Display ADDRTYPE_INET6 addresses if AF_INET6 is
+	defined.
+
+1999-09-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* klist.c (do_ccache, show_credential): Use krb5_free_unparsed_name
+	instead of free.
+
+1999-08-26  Danilo Almeida  <dalmeida@mit.edu>
+
+	* klist.c (show_credential): Index addresses array with i
+	in a loop instead of 1.  (Thanks to jaltman@columbia.edu)
+
+1999-08-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Use standard windows exe link flags.
+
+Mon May 10 15:13:58 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Mon Feb  8 22:11:50 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* klist.c: Under Windows, #include winsock.h instead of
+		sys/socket.h and netdb.h
+
+	* Makefile.in: Under Windows, link against wsock32.lib to get
+	 	gethostbyaddr().
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* klist.c: add -a flag to print the ticket address, and -n flag to
+	do so without attempting resolution.  Make klist use the new api
+	for stringifying enctypes.
+
+Tue Aug 11 23:38:53 1998  Matthew D Hancher  <mdh@mit.edu>
+
+	* klist.c (do_ccache): Properly check the return value of
+	krb5_cc_set_flags() so the right thing happens if there is no CC.
+	
+Mon Mar 30 17:08:07 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* klist.c (main): Exit with a 0 exit status if everything okay
+
+Wed Feb 18 15:42:57 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.  Remove extraneous whitespace.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 21 15:11:22 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* klist.c (main): returns int, not void. ANSI X3.159-1989
+	2.1.2.2.1 says so, and gcc now warns about it.
+
+Sat Feb 15 12:25:14 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Link in ComErr library $(CLIB)
+
+Mon Feb 10 14:59:33 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in:
+		Build klist.exe (win32 console app)
+
+Mon Jan 27 16:51:50 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Dec  5 21:59:34 1996  Tom Yu  <tlyu@mit.edu>
+
+	* klist.M: v5srvtab -> krb5.keytab [279]
+
+Wed Nov  6 12:02:59 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* klist.c (main): Check the error return from krb5_init_context(),
+ 		and print an error message if neceesary.
+
+Tue Sep 10 14:14:21 1996  Tom Yu  <tlyu@mit.edu>
+
+	* klist.M: remove ".so man1/header.doc"
+
+Fri May 10 02:50:58 1996  Richard Basch  <basch@lehman.com>
+
+	* klist.c (etype_string): changed des3-md5 to des3-sha
+
+Fri Jan 26 16:14:38 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* klist.c : Implement -e option for keytabs as well.
+
+Fri Sep 15 16:22:45 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* klist.M: Updated the man page to include all of the supported
+	        options.
+
+	* klist.c (main, show_credential): Reimplement the -e option, and
+		display the encryption used by the session key and of the
+		ticket.
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * klist.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate.
+
+Mon Aug 21 16:50:54 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* klist.c - Add logic to figure out width of time string and then use
+		this width to format the timestamp output.  Remove English-
+		specific months and let timestamp_to_sfstring() handle it.
+		Replace etype string array with enctype_to_string().
+	* configure.in - Add -lkadm.
+
+
+Fri Jul 7 15:54:35 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling and LDFLAGS.
+	* configure.in - Add KRB5_LIBRARIES.
+
+Wed Jun 21 10:37:01 1995    <tytso@rsx-11.mit.edu>
+
+	* klist.c: Change PROTOTYPE -> KRB5_PROTOTYPE
+
+Thu Jun 15 17:47:11 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Fri Jun  9 18:37:35 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Jun  8 17:46:51 1995    <tytso@rsx-11.mit.edu>
+
+	* klist.c: Integrated patch from OpenVision which allows klist to
+		list keytabs as well as ccache's.
+
+Thu May 11 07:31:42 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* klist.c (main): Update usage message to include -e and -f.
+
+	* klist.M: -e flag documented.
+
+Thu May 04 04:24:38 1995  Chris Provenzano (proven@mit.edu)
+
+	* klist.c : Changed progname to argv[0] for consistancy with 
+		kdestroy, and to cleanup the code some.
+
+Wed May 03 20:20:48 1995  Chris Provenzano (proven@mit.edu)
+
+	* klist.c : #include <string.h>, a must for prototypes of various 
+		string routines on systems where int != void *.
+
+Thu Mar  2 12:31:29 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:28:00 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Replace check for -lsocket and -lnsl with
+		WITH_NETLIB check.
+
+Tue Feb 28 02:11:02 1995  John Gilmore  (gnu at toad.com)
+
+	* klist.c:  Avoid <krb5/...> and <com_err.h> includes.
+
+Fri Feb 10 18:44:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove ISODE cruft.  Use $(LIBS) so that
+		libsocket can be pulled in if necessary.
+
+	* configure.in: Add check for libsocket and libnsl (sigh).
+		krb5_init_ctx drags in cryptoconf.c, which drags in enough
+		of the crypto library that socket() gets called.  We should
+		to fix this eventually to make klist smaller, but the fix
+		will be subtle.
+
+Thu Feb 09 17:43:47 1995  Chris Provenzano (proven@mit.edu)
+
+	* klist.c Added -e option to print out encryption types.
+
+Fri Feb 03 22:14:26 1995  Chris Provenzano (proven@mit.edu)
+
+	* klist.c Do a krb5_init_context() before using a krb5_context.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Mon Oct  3 19:14:09 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
+Thu Sep 22 22:41:42 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* klist.c (main): Fix memory leak in klist --- the returned
+		credentials should be freed before you fetch the next set.
+
diff --git a/mechglue/src/clients/klist/Makefile.in b/mechglue/src/clients/klist/Makefile.in
new file mode 100644
index 000000000..45d76fad0
--- /dev/null
+++ b/mechglue/src/clients/klist/Makefile.in
@@ -0,0 +1,42 @@
+thisconfigdir=./..
+myfulldir=clients/klist
+mydir=klist
+BUILDTOP=$(REL)..$(S)..
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+SRCS = klist.c
+
+all-unix:: klist
+all-windows:: $(OUTPRE)klist.exe
+
+klist: klist.o $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o $@ klist.o $(KRB4COMPAT_LIBS)
+
+$(OUTPRE)klist.exe: $(OUTPRE)klist.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.lib $(SLIB) $(KLIB) $(CLIB)
+	link $(EXE_LINKOPTS) -out:$@ $** ws2_32.lib
+
+clean-unix::
+	$(RM) klist.o klist
+
+install-unix::
+	for f in klist; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		$(DESTDIR)$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)klist.$(OBJEXT): klist.c $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/fake-addrinfo.h
diff --git a/mechglue/src/clients/klist/klist.M b/mechglue/src/clients/klist/klist.M
new file mode 100644
index 000000000..c5f66d525
--- /dev/null
+++ b/mechglue/src/clients/klist/klist.M
@@ -0,0 +1,154 @@
+.\" clients/klist/klist.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH KLIST 1
+.SH NAME
+klist \- list cached Kerberos tickets
+.SH SYNOPSIS
+\fBklist\fP [\fB\-5\fP] [\fB\-4\fP] [\fB\-e\fP] [[\fB\-c\fP] [\fB\-f\fP] 
+[\fB\-s\fP] [\fB\-a\fP  [\fB\-n\fP]]]
+[\fB\-k\fP [\fB\-t\fP] [\fB\-K\fP]]
+[\fIcache_name\fP | \fIkeytab_name\fP]
+.br
+.SH DESCRIPTION
+.I Klist
+lists the Kerberos principal and Kerberos tickets held in a credentials
+cache, or the keys held in a
+.B keytab
+file.
+If klist was built with Kerberos 4 support, the default behavior is to list
+both Kerberos 5 and Kerberos 4 credentials.  Otherwise, klist will default
+to listing only Kerberos 5 credentials.
+.SH OPTIONS
+.TP
+.B \-5
+list Kerberos 5 credentials.  This overrides whatever the default built-in
+behavior may be.  This option may be used with
+.B \-4
+.
+.TP
+.B \-4
+list Kerberos 4 credentials.  This overrides whatever the default built-in
+behavior may be.  This option is only available if kinit was built
+with Kerberos 4 compatibility.  This option may be used with 
+.B \-5
+.
+.TP
+.B \-e
+displays the encryption types of the session key and the ticket for each
+credential in the credential cache, or each key in the keytab file.
+.TP
+.B \-c
+List tickets held in a credentials cache.  This is the default if
+neither
+.B \-c
+nor
+.B \-k
+is specified.
+.TP
+.B \-f
+shows the flags present in the credentials, using the following
+abbreviations:
+.sp
+.nf
+.in +.5i
+F	\fBF\fPorwardable
+f	\fBf\fPorwarded
+P	\fBP\fProxiable
+p	\fBp\fProxy
+D	post\fBD\fPateable
+d	post\fBd\fPated
+R	\fBR\fPenewable
+I	\fBI\fPnitial
+i	\fBi\fPnvalid
+H	\fBH\fPardware authenticated
+A	pre\fBA\fPuthenticated
+T	\fBT\fPransit policy checked
+O	\fBO\fPkay as delegate
+a	\fBa\fPnonymous
+.in -.5i
+.fi
+.TP
+.B \-s
+causes
+.B klist
+to run silently (produce no output), but to still set the exit status
+according to whether it finds the credentials cache.  The exit status is
+`0' if
+.B klist
+finds a credentials cache, and `1' if it does not or if the tickets are
+ expired.
+.TP
+.B \-a
+display list of addresses in credentials.
+.TP
+.B \-n
+show numeric addresses instead of reverse-resolving addresses.
+.TP
+\fB\-k\fP
+List keys held in a
+.B keytab
+file.  
+.TP
+.B \-t
+display the time entry timestamps for each keytab entry in the keytab
+file.
+.TP
+.B \-K
+display the value of the encryption key in each keytab entry in the
+keytab file.
+.PP
+If
+.I cache_name
+or
+.I keytab_name
+is not specified, klist will display the credentials in the default
+credentials cache or keytab file as appropriate.  If the
+.B KRB5CCNAME
+environment variable is set, its value is used to name the default
+ticket cache.
+.SH ENVIRONMENT
+.B Klist
+uses the following environment variables:
+.TP "\w'.SM KRB5CCNAME\ \ 'u"
+.SM KRB5CCNAME
+Location of the Kerberos 5 credentials (ticket) cache.
+.TP "\w'.SM KRBTKFILE\ \ 'u"
+.SM KRBTKFILE
+Filename of the Kerberos 4 credentials (ticket) cache.
+.SH FILES
+.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
+/tmp/krb5cc_[uid]
+default location of Kerberos 5 credentials cache 
+([uid] is the decimal UID of the user).
+.TP "\w'/tmp/tkt[uid]\ \ 'u"
+/tmp/tkt[uid]
+default location of Kerberos 4 credentials cache 
+([uid] is the decimal UID of the user).
+.TP
+/etc/krb5.keytab
+default location for the local host's
+.B keytab
+file.
+.SH SEE ALSO
+kinit(1), kdestroy(1), krb5(3)
diff --git a/mechglue/src/clients/klist/klist.c b/mechglue/src/clients/klist/klist.c
new file mode 100644
index 000000000..8a70e0685
--- /dev/null
+++ b/mechglue/src/clients/klist/klist.c
@@ -0,0 +1,837 @@
+/*
+ * clients/klist/klist.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * List out the contents of your credential cache or keytab.
+ */
+
+#include <krb5.h>
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+#include <com_err.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+/* Need definition of INET6 before network headers, for IRIX.  */
+#include "autoconf.h"
+#if defined(HAVE_ARPA_INET_H)
+#include <arpa/inet.h>
+#endif
+
+#ifndef _WIN32
+#define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x))
+#else
+#define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
+#endif
+
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+extern int optind;
+
+int show_flags = 0, show_time = 0, status_only = 0, show_keys = 0;
+int show_etype = 0, show_addresses = 0, no_resolve = 0;
+char *defname;
+char *progname;
+krb5_int32 now;
+unsigned int timestamp_width;
+
+krb5_context kcontext;
+
+char * etype_string (krb5_enctype );
+void show_credential (krb5_creds *);
+	
+void do_ccache (char *);
+void do_keytab (char *);
+void printtime (time_t);
+void one_addr (krb5_address *);
+void fillit (FILE *, unsigned int, int);
+
+#ifdef KRB5_KRB4_COMPAT
+void do_v4_ccache (char *);
+#endif /* KRB5_KRB4_COMPAT */
+
+#define DEFAULT 0
+#define CCACHE 1
+#define KEYTAB 2
+
+/*
+ * The reason we start out with got_k4 and got_k5 as zero (false) is
+ * so that we can easily add dynamic loading support for determining
+ * whether Kerberos 4 and Keberos 5 libraries are available
+ */
+
+static int got_k5 = 0; 
+static int got_k4 = 0;
+
+static int default_k5 = 1;
+#ifdef KRB5_KRB4_COMPAT
+static int default_k4 = 1;
+#else
+static int default_k4 = 0;
+#endif
+
+static void usage()
+{
+#define KRB_AVAIL_STRING(x) ((x)?"available":"not available")
+
+    fprintf(stderr, "Usage: %s [-5] [-4] [-e] [[-c] [-f] [-s] [-a [-n]]] %s",
+	     progname, "[-k [-t] [-K]] [name]\n"); 
+    fprintf(stderr, "\t-5 Kerberos 5 (%s)\n", KRB_AVAIL_STRING(got_k5));
+    fprintf(stderr, "\t-4 Kerberos 4 (%s)\n", KRB_AVAIL_STRING(got_k4));
+    fprintf(stderr, "\t   (Default is %s%s%s%s)\n",
+	    default_k5?"Kerberos 5":"",
+	    (default_k5 && default_k4)?" and ":"",
+	    default_k4?"Kerberos 4":"",
+	    (!default_k5 && !default_k4)?"neither":"");
+    fprintf(stderr, "\t-c specifies credentials cache\n");
+    fprintf(stderr, "\t-k specifies keytab\n");
+    fprintf(stderr, "\t   (Default is credentials cache)\n");
+    fprintf(stderr, "\t-e shows the encryption type\n");
+    fprintf(stderr, "\toptions for credential caches:\n");
+    fprintf(stderr, "\t\t-f shows credentials flags\n");
+    fprintf(stderr, "\t\t-s sets exit status based on valid tgt existence\n");
+    fprintf(stderr, "\t\t-a displays the address list\n");
+    fprintf(stderr, "\t\t\t-n do not reverse-resolve\n");
+    fprintf(stderr, "\toptions for keytabs:\n");
+    fprintf(stderr, "\t\t-t shows keytab entry timestamps\n");
+    fprintf(stderr, "\t\t-K shows keytab entry DES keys\n");
+    exit(1);
+}
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    int c;
+    char *name;
+    int mode;
+    int use_k5 = 0, use_k4 = 0;
+
+    got_k5 = 1;
+#ifdef KRB5_KRB4_COMPAT
+    got_k4 = 1;
+#endif
+
+    progname = GET_PROGNAME(argv[0]);
+
+    name = NULL;
+    mode = DEFAULT;
+    while ((c = getopt(argc, argv, "fetKsnack45")) != -1) {
+	switch (c) {
+	case 'f':
+	    show_flags = 1;
+	    break;
+	case 'e':
+	    show_etype = 1;
+	    break;
+	case 't':
+	    show_time = 1;
+	    break;
+	case 'K':
+	    show_keys = 1;
+	    break;
+	case 's':
+	    status_only = 1;
+	    break;
+	case 'n':
+	    no_resolve = 1;
+	    break;
+	case 'a':
+	    show_addresses = 1;
+	    break;
+	case 'c':
+	    if (mode != DEFAULT) usage();
+	    mode = CCACHE;
+	    break;
+	case 'k':
+	    if (mode != DEFAULT) usage();
+	    mode = KEYTAB;
+	    break;
+	case '4':
+	    if (!got_k4)
+	    {
+#ifdef KRB5_KRB4_COMPAT
+		fprintf(stderr, "Kerberos 4 support could not be loaded\n");
+#else
+		fprintf(stderr, "This was not built with Kerberos 4 support\n");
+#endif
+		exit(3);
+	    }
+	    use_k4 = 1;
+	    break;
+	case '5':
+	    if (!got_k5)
+	    {
+		fprintf(stderr, "Kerberos 5 support could not be loaded\n");
+		exit(3);
+	    }
+	    use_k5 = 1;
+	    break;
+	default:
+	    usage();
+	    break;
+	}
+    }
+
+    if (no_resolve && !show_addresses) {
+	usage();
+    }
+
+    if (mode == DEFAULT || mode == CCACHE) {
+	if (show_time || show_keys)
+	    usage();
+    } else {
+	if (show_flags || status_only || show_addresses)
+	    usage();
+    }
+
+    if (argc - optind > 1) {
+	fprintf(stderr, "Extra arguments (starting with \"%s\").\n",
+		argv[optind+1]);
+	usage();
+    }
+
+    name = (optind == argc-1) ? argv[optind] : 0;
+
+    if (!use_k5 && !use_k4)
+    {
+	use_k5 = default_k5;
+	use_k4 = default_k4;
+    }
+
+    if (!use_k5)
+	got_k5 = 0;
+    if (!use_k4)
+	got_k4 = 0;
+
+    now = time(0);
+    {
+	char tmp[BUFSIZ];
+
+	if (!krb5_timestamp_to_sfstring(now, tmp, 20, (char *) NULL) ||
+	    !krb5_timestamp_to_sfstring(now, tmp, sizeof(tmp), 
+					(char *) NULL))
+	    timestamp_width = (int) strlen(tmp);
+	else
+	    timestamp_width = 15;
+    }
+
+    if (got_k5)
+    {
+	krb5_error_code retval;
+	retval = krb5_init_context(&kcontext);
+	if (retval) {
+	    com_err(progname, retval, "while initializing krb5");
+	    exit(1);
+	}
+
+	if (mode == DEFAULT || mode == CCACHE)
+	    do_ccache(name);
+	else
+	    do_keytab(name);
+    } else {
+#ifdef KRB5_KRB4_COMPAT
+	if (mode == DEFAULT || mode == CCACHE)
+	    do_v4_ccache(name);
+	else {
+	    /* We may want to add v4 srvtab support */
+	    fprintf(stderr, 
+		    "%s: srvtab option not supported for Kerberos 4\n", 
+		    progname);
+	    exit(1);
+	}
+#endif /* KRB4_KRB5_COMPAT */
+    }
+
+    return 0;
+}    
+
+void do_keytab(name)
+   char *name;
+{
+     krb5_keytab kt;
+     krb5_keytab_entry entry;
+     krb5_kt_cursor cursor;
+     char buf[BUFSIZ]; /* hopefully large enough for any type */
+     char *pname;
+     int code;
+     
+     if (name == NULL) {
+	  if ((code = krb5_kt_default(kcontext, &kt))) {
+	       com_err(progname, code, "while getting default keytab");
+	       exit(1);
+	  }
+     } else {
+	  if ((code = krb5_kt_resolve(kcontext, name, &kt))) {
+	       com_err(progname, code, "while resolving keytab %s",
+		       name);
+	       exit(1);
+	  }
+     }
+
+     if ((code = krb5_kt_get_name(kcontext, kt, buf, BUFSIZ))) {
+	  com_err(progname, code, "while getting keytab name");
+	  exit(1);
+     }
+
+     printf("Keytab name: %s\n", buf);
+     
+     if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) {
+	  com_err(progname, code, "while starting keytab scan");
+	  exit(1);
+     }
+
+     if (show_time) {
+	  printf("KVNO Timestamp");
+	  fillit(stdout, timestamp_width - sizeof("Timestamp") + 2, (int) ' ');
+	  printf("Principal\n");
+	  printf("---- ");
+	  fillit(stdout, timestamp_width, (int) '-');
+	  printf(" ");
+	  fillit(stdout, 78 - timestamp_width - sizeof("KVNO"), (int) '-');
+	  printf("\n");
+     } else {
+	  printf("KVNO Principal\n");
+	  printf("---- --------------------------------------------------------------------------\n");
+     }
+     
+     while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) {
+	  if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) {
+	       com_err(progname, code, "while unparsing principal name");
+	       exit(1);
+	  }
+	  printf("%4d ", entry.vno);
+	  if (show_time) {
+	       printtime(entry.timestamp);
+	       printf(" ");
+	  }
+	  printf("%s", pname);
+	  if (show_etype)
+	      printf(" (%s) " , etype_string(entry.key.enctype));
+	  if (show_keys) {
+	       printf(" (0x");
+	       {
+		    int i;
+		    for (i = 0; i < entry.key.length; i++)
+			 printf("%02x", entry.key.contents[i]);
+	       }
+	       printf(")");
+	  }
+	  printf("\n");
+	  krb5_free_unparsed_name(kcontext, pname);
+     }
+     if (code && code != KRB5_KT_END) {
+	  com_err(progname, code, "while scanning keytab");
+	  exit(1);
+     }
+     if ((code = krb5_kt_end_seq_get(kcontext, kt, &cursor))) {
+	  com_err(progname, code, "while ending keytab scan");
+	  exit(1);
+     }
+     exit(0);
+}
+void do_ccache(name)
+   char *name;
+{
+    krb5_ccache cache = NULL;
+    krb5_cc_cursor cur;
+    krb5_creds creds;
+    krb5_principal princ;
+    krb5_flags flags;
+    krb5_error_code code;
+    int	exit_status = 0;
+	    
+    if (status_only)
+	/* exit_status is set back to 0 if a valid tgt is found */
+	exit_status = 1;
+
+    if (name == NULL) {
+	if ((code = krb5_cc_default(kcontext, &cache))) {
+	    if (!status_only)
+		com_err(progname, code, "while getting default ccache");
+	    exit(1);
+	    }
+    } else {
+	if ((code = krb5_cc_resolve(kcontext, name, &cache))) {
+	    if (!status_only)
+		com_err(progname, code, "while resolving ccache %s",
+			name);
+	    exit(1);
+	}
+    }
+ 
+    flags = 0;				/* turns off OPENCLOSE mode */
+    if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+	if (code == KRB5_FCC_NOFILE) {
+	    if (!status_only) {
+		com_err(progname, code, "(ticket cache %s:%s)",
+			krb5_cc_get_type(kcontext, cache),
+			krb5_cc_get_name(kcontext, cache));
+#ifdef KRB5_KRB4_COMPAT
+		if (name == NULL)
+		    do_v4_ccache(0);
+#endif
+	    }
+	} else {
+	    if (!status_only)
+		com_err(progname, code,
+			"while setting cache flags (ticket cache %s:%s)",
+			krb5_cc_get_type(kcontext, cache),
+			krb5_cc_get_name(kcontext, cache));
+	}
+	exit(1);
+    }
+    if ((code = krb5_cc_get_principal(kcontext, cache, &princ))) {
+	if (!status_only)
+	    com_err(progname, code, "while retrieving principal name");
+	exit(1);
+    }
+    if ((code = krb5_unparse_name(kcontext, princ, &defname))) {
+	if (!status_only)
+	    com_err(progname, code, "while unparsing principal name");
+	exit(1);
+    }
+    if (!status_only) {
+	printf("Ticket cache: %s:%s\nDefault principal: %s\n\n",
+	       krb5_cc_get_type(kcontext, cache),
+	       krb5_cc_get_name(kcontext, cache), defname);
+	fputs("Valid starting", stdout);
+	fillit(stdout, timestamp_width - sizeof("Valid starting") + 3,
+	       (int) ' ');
+	fputs("Expires", stdout);
+	fillit(stdout, timestamp_width - sizeof("Expires") + 3,
+	       (int) ' ');
+	fputs("Service principal\n", stdout);
+    }
+    if ((code = krb5_cc_start_seq_get(kcontext, cache, &cur))) {
+	if (!status_only)
+	    com_err(progname, code, "while starting to retrieve tickets");
+	exit(1);
+    }
+    while (!(code = krb5_cc_next_cred(kcontext, cache, &cur, &creds))) {
+	if (status_only) {
+	    if (exit_status && creds.server->length == 2 &&
+		strcmp(creds.server->realm.data, princ->realm.data) == 0 &&
+		strcmp((char *)creds.server->data[0].data, "krbtgt") == 0 &&
+		strcmp((char *)creds.server->data[1].data,
+		       princ->realm.data) == 0 && 
+		creds.times.endtime > now)
+		exit_status = 0;
+	} else {
+	    show_credential(&creds);
+	}
+	krb5_free_cred_contents(kcontext, &creds);
+    }
+    if (code == KRB5_CC_END) {
+	if ((code = krb5_cc_end_seq_get(kcontext, cache, &cur))) {
+	    if (!status_only)
+		com_err(progname, code, "while finishing ticket retrieval");
+	    exit(1);
+	}
+	flags = KRB5_TC_OPENCLOSE;	/* turns on OPENCLOSE mode */
+	if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
+	    if (!status_only)
+		com_err(progname, code, "while closing ccache");
+	    exit(1);
+	}
+#ifdef KRB5_KRB4_COMPAT
+	if (name == NULL && !status_only)
+	    do_v4_ccache(0);
+#endif
+	exit(exit_status);
+    } else {
+	if (!status_only)
+	    com_err(progname, code, "while retrieving a ticket");
+	exit(1);
+    }	
+}
+
+char *
+etype_string(enctype)
+    krb5_enctype enctype;
+{
+    static char buf[100];
+    krb5_error_code retval;
+    
+    if ((retval = krb5_enctype_to_string(enctype, buf, sizeof(buf)))) {
+	/* XXX if there's an error != EINVAL, I should probably report it */
+	sprintf(buf, "etype %d", enctype);
+    }
+
+    return buf;
+}
+
+static char *
+flags_string(cred)
+    register krb5_creds *cred;
+{
+    static char buf[32];
+    int i = 0;
+	
+    if (cred->ticket_flags & TKT_FLG_FORWARDABLE)
+	buf[i++] = 'F';
+    if (cred->ticket_flags & TKT_FLG_FORWARDED)
+	buf[i++] = 'f';
+    if (cred->ticket_flags & TKT_FLG_PROXIABLE)
+	buf[i++] = 'P';
+    if (cred->ticket_flags & TKT_FLG_PROXY)
+	buf[i++] = 'p';
+    if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)
+	buf[i++] = 'D';
+    if (cred->ticket_flags & TKT_FLG_POSTDATED)
+	buf[i++] = 'd';
+    if (cred->ticket_flags & TKT_FLG_INVALID)
+	buf[i++] = 'i';
+    if (cred->ticket_flags & TKT_FLG_RENEWABLE)
+	buf[i++] = 'R';
+    if (cred->ticket_flags & TKT_FLG_INITIAL)
+	buf[i++] = 'I';
+    if (cred->ticket_flags & TKT_FLG_HW_AUTH)
+	buf[i++] = 'H';
+    if (cred->ticket_flags & TKT_FLG_PRE_AUTH)
+	buf[i++] = 'A';
+    if (cred->ticket_flags & TKT_FLG_TRANSIT_POLICY_CHECKED)
+	buf[i++] = 'T';
+    if (cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE)
+	buf[i++] = 'O';		/* D/d are taken.  Use short strings?  */
+    if (cred->ticket_flags & TKT_FLG_ANONYMOUS)
+	buf[i++] = 'a';
+    buf[i] = '\0';
+    return(buf);
+}
+
+void 
+printtime(tv)
+    time_t tv;
+{
+    char timestring[BUFSIZ];
+    char fill;
+
+    fill = ' ';
+    if (!krb5_timestamp_to_sfstring((krb5_timestamp) tv,
+				    timestring,
+				    timestamp_width+1,
+				    &fill)) {
+	printf(timestring);
+    }
+}
+
+void
+show_credential(cred)
+    register krb5_creds * cred;
+{
+    krb5_error_code retval;
+    krb5_ticket *tkt;
+    char *name, *sname, *flags;
+    int	extra_field = 0;
+
+    retval = krb5_unparse_name(kcontext, cred->client, &name);
+    if (retval) {
+	com_err(progname, retval, "while unparsing client name");
+	return;
+    }
+    retval = krb5_unparse_name(kcontext, cred->server, &sname);
+    if (retval) {
+	com_err(progname, retval, "while unparsing server name");
+	krb5_free_unparsed_name(kcontext, name);
+	return;
+    }
+    if (!cred->times.starttime)
+	cred->times.starttime = cred->times.authtime;
+
+    printtime(cred->times.starttime);
+    putchar(' '); putchar(' ');
+    printtime(cred->times.endtime);
+    putchar(' '); putchar(' ');
+
+    printf("%s\n", sname);
+
+    if (strcmp(name, defname)) {
+	    printf("\tfor client %s", name);
+	    extra_field++;
+    }
+    
+    if (cred->times.renew_till) {
+	if (!extra_field)
+		fputs("\t",stdout);
+	else
+		fputs(", ",stdout);
+	fputs("renew until ", stdout);
+	printtime(cred->times.renew_till);
+	extra_field += 2;
+    }
+
+    if (extra_field > 3) {
+	fputs("\n", stdout);
+	extra_field = 0;
+    }
+
+    if (show_flags) {
+	flags = flags_string(cred);
+	if (flags && *flags) {
+	    if (!extra_field)
+		fputs("\t",stdout);
+	    else
+		fputs(", ",stdout);
+	    printf("Flags: %s", flags);
+	    extra_field++;
+	}
+    }
+
+    if (extra_field > 2) {
+	fputs("\n", stdout);
+	extra_field = 0;
+    }
+
+    if (show_etype) {
+	retval = krb5_decode_ticket(&cred->ticket, &tkt);
+	if (retval)
+	    goto err_tkt;
+
+	if (!extra_field)
+	    fputs("\t",stdout);
+	else
+	    fputs(", ",stdout);
+	printf("Etype (skey, tkt): %s, ",
+	       etype_string(cred->keyblock.enctype));
+	printf("%s ",
+	       etype_string(tkt->enc_part.enctype));
+	extra_field++;
+
+    err_tkt:
+	if (tkt != NULL)
+	    krb5_free_ticket(kcontext, tkt);
+    }
+
+    /* if any additional info was printed, extra_field is non-zero */
+    if (extra_field)
+	putchar('\n');
+
+
+    if (show_addresses) {
+	if (!cred->addresses || !cred->addresses[0]) {
+	    printf("\tAddresses: (none)\n");
+	} else {
+	    int i;
+
+	    printf("\tAddresses: ");
+	    one_addr(cred->addresses[0]);
+
+	    for (i=1; cred->addresses[i]; i++) {
+		printf(", ");
+		one_addr(cred->addresses[i]);
+	    }
+
+	    printf("\n");
+	}
+    }
+
+    krb5_free_unparsed_name(kcontext, name);
+    krb5_free_unparsed_name(kcontext, sname);
+}
+
+#include "port-sockets.h"
+#include "socket-utils.h" /* for ss2sin etc */
+#include "fake-addrinfo.h"
+
+void one_addr(a)
+    krb5_address *a;
+{
+    struct sockaddr_storage ss;
+    int err;
+    char namebuf[NI_MAXHOST];
+
+    memset (&ss, 0, sizeof (ss));
+
+    switch (a->addrtype) {
+    case ADDRTYPE_INET:
+	if (a->length != 4) {
+	broken:
+	    printf ("broken address (type %d length %d)",
+		    a->addrtype, a->length);
+	    return;
+	}
+	{
+	    struct sockaddr_in *sinp = ss2sin (&ss);
+	    sinp->sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+	    sinp->sin_len = sizeof (struct sockaddr_in);
+#endif
+	    memcpy (&sinp->sin_addr, a->contents, 4);
+	}
+	break;
+#ifdef KRB5_USE_INET6
+    case ADDRTYPE_INET6:
+	if (a->length != 16)
+	    goto broken;
+	{
+	    struct sockaddr_in6 *sin6p = ss2sin6 (&ss);
+	    sin6p->sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+	    sin6p->sin6_len = sizeof (struct sockaddr_in6);
+#endif
+	    memcpy (&sin6p->sin6_addr, a->contents, 16);
+	}
+	break;
+#endif
+    default:
+	printf ("unknown addrtype %d", a->addrtype);
+	return;
+    }
+
+    namebuf[0] = 0;
+    err = getnameinfo (ss2sa (&ss), socklen (ss2sa (&ss)),
+		       namebuf, sizeof (namebuf), 0, 0,
+		       no_resolve ? NI_NUMERICHOST : 0U);
+    if (err) {
+	printf ("unprintable address (type %d, error %d %s)", a->addrtype, err,
+		gai_strerror (err));
+	return;
+    }
+    printf ("%s", namebuf);
+}
+
+void
+fillit(f, num, c)
+    FILE		*f;
+    unsigned int	num;
+    int			c;
+{
+    int i;
+
+    for (i=0; i<num; i++)
+	fputc(c, f);
+}
+
+#ifdef KRB5_KRB4_COMPAT
+void
+do_v4_ccache(name)
+    char * name;
+{
+    char    pname[ANAME_SZ];
+    char    pinst[INST_SZ];
+    char    prealm[REALM_SZ];
+    char    *file;
+    int     k_errno;
+    CREDENTIALS c;
+    int     header = 1;
+
+    if (!got_k4)
+	return;
+
+    file = name?name:tkt_string();
+
+    if (status_only) {
+	fprintf(stderr, 
+		"%s: exit status option not supported for Kerberos 4\n",
+		progname);
+	exit(1);
+    }
+
+    if (got_k5)
+	printf("\n\n");
+
+    printf("Kerberos 4 ticket cache: %s\n", file);
+
+    /* 
+     * Since krb_get_tf_realm will return a ticket_file error, 
+     * we will call tf_init and tf_close first to filter out
+     * things like no ticket file.  Otherwise, the error that 
+     * the user would see would be 
+     * klist: can't find realm of ticket file: No ticket file (tf_util)
+     * instead of
+     * klist: No ticket file (tf_util)
+     */
+
+    /* Open ticket file */
+    k_errno = tf_init(file, R_TKT_FIL);
+    if (k_errno) {
+	fprintf(stderr, "%s: %s\n", progname, krb_get_err_text (k_errno));
+	exit(1);
+    }
+    /* Close ticket file */
+    (void) tf_close();
+
+    /* 
+     * We must find the realm of the ticket file here before calling
+     * tf_init because since the realm of the ticket file is not
+     * really stored in the principal section of the file, the
+     * routine we use must itself call tf_init and tf_close.
+     */
+    if ((k_errno = krb_get_tf_realm(file, prealm)) != KSUCCESS) {
+	fprintf(stderr, "%s: can't find realm of ticket file: %s\n",
+		progname, krb_get_err_text (k_errno));
+	exit(1);
+    }
+
+    /* Open ticket file */
+    if ((k_errno = tf_init(file, R_TKT_FIL))) {
+	fprintf(stderr, "%s: %s\n", progname, krb_get_err_text (k_errno));
+	exit(1);
+    }
+    /* Get principal name and instance */
+    if ((k_errno = tf_get_pname(pname)) ||
+	(k_errno = tf_get_pinst(pinst))) {
+	fprintf(stderr, "%s: %s\n", progname, krb_get_err_text (k_errno));
+	exit(1);
+    }
+
+    /* 
+     * You may think that this is the obvious place to get the
+     * realm of the ticket file, but it can't be done here as the
+     * routine to do this must open the ticket file.  This is why 
+     * it was done before tf_init.
+     */
+       
+    printf("Principal: %s%s%s%s%s\n\n", pname,
+	   (pinst[0] ? "." : ""), pinst,
+	   (prealm[0] ? "@" : ""), prealm);
+    while ((k_errno = tf_get_cred(&c)) == KSUCCESS) {
+	if (header) {
+	    printf("%-18s  %-18s  %s\n",
+		   "  Issued", "  Expires", "  Principal");
+	    header = 0;
+	}
+	printtime(c.issue_date);
+	fputs("  ", stdout);
+	printtime(krb_life_to_time(c.issue_date, c.lifetime));
+	printf("  %s%s%s%s%s\n",
+	       c.service, (c.instance[0] ? "." : ""), c.instance,
+	       (c.realm[0] ? "@" : ""), c.realm);
+    }
+    if (header && k_errno == EOF) {
+	printf("No tickets in file.\n");
+    }
+}
+#endif /* KRB4_KRB5_COMPAT */
diff --git a/mechglue/src/clients/kpasswd/ChangeLog b/mechglue/src/clients/kpasswd/ChangeLog
new file mode 100644
index 000000000..367cacccd
--- /dev/null
+++ b/mechglue/src/clients/kpasswd/ChangeLog
@@ -0,0 +1,121 @@
+2004-06-24  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.c (P1, P2): Cosmetic fix for prompts to avoid
+	double colons.
+
+2004-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* kpasswd.c (get_name_from_passwd_file): Do not cast return from
+	getuid() to int as argument to getpwuid.
+
+	* ksetpwd.c: Include time.h for time() prototype.
+	(main): Return 0 on success.
+
+2004-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* ksetpwd.c (verify_creds, get_init_creds_opt_init,
+	userinitcontext, init_creds): Now static.
+	(main): Remove one of two variables named "ccache".
+
+2003-04-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* ksetpwd.c (init_creds): Let's use C comments for C code, shall
+	we?
+
+2003-04-25  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in :   Add rule to build ksetpw, a set/change password
+	client for the Microsoft protocol.  We do not install this program
+	by default because it is not of release quality yet.
+
+2003-02-25  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.c (main): Don't pass a NULL pointer to printf().
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-18  Jen Selby <jenselby@mit.edu>
+
+	* kpasswd.M: commented out the inclusion of man1/header.doc
+
+2001-10-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* kpasswd.c (main): Do not free potentially NULL pointers.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* kpasswd.c (main): Argument to krb5_read_password takes an
+	unsigned int as argument.
+
+2000-07-29  Ezra Peisach  <epeisach@mit.edu>
+
+	* kpasswd.c (main): Warnings cleanup.
+
+2000-03-16  Ezra Peisach  <epeisach@mit.edu>
+
+	* kpasswd.c (main): Remove unused variables.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Windows fix for 10/26/99 cleanup.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kpasswd.c: 
+	* Makefile.in: Build kpasswd under windows.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Wed Feb 18 15:43:41 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing whitespace from thisconfigdir.  Fix
+	up BUILDTOP for new conventions.
+
+Thu Feb 12 08:37:00 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jan 30 16:06:13 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.c:
+	* kpasswd.M:
+	* Makefile.in:
+	* configure.in: New: Cygnus kpasswd client.
+
+Mon Mar 31 23:49:34 1997  Marc Horowitz  <marc@cygnus.com>
+
+	* Makefile.in (install-all install-kdc install-server install-client install-unix): install the new man page
+
+Sat Mar 29 14:31:51 1997  Mark Eichin  <eichin@cygnus.com>
+
+	* kpasswd.c (main): use fprintf correctly in usage.
+
+Tue Mar  4 21:47:48 1997  Marc Horowitz  <marc@cygnus.com>
+
+	* kpasswd.c (main): retool for new init_creds interface
+
+Wed Feb 19 21:00:12 1997  Marc Horowitz  <marc@cygnus.com>
+
+	* kpasswd.c: use the string version of the chpw result_code in the
+ 	error message.
+
+Mon Feb  3 17:50:30 1997  Marc Horowitz  <marc@cygnus.com>
+
+	* kpasswd.c: new password change client
+	* Makefile.in: new directory
diff --git a/mechglue/src/clients/kpasswd/Makefile.in b/mechglue/src/clients/kpasswd/Makefile.in
new file mode 100644
index 000000000..3f6394342
--- /dev/null
+++ b/mechglue/src/clients/kpasswd/Makefile.in
@@ -0,0 +1,29 @@
+thisconfigdir=./..
+myfulldir=clients/kpasswd
+mydir=kpasswd
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+kpasswd: kpasswd.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o kpasswd kpasswd.o $(KRB5_BASE_LIBS)
+
+ksetpwd: ksetpwd.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o ksetpwd ksetpwd.o $(KRB5_BASE_LIBS)
+
+kpasswd.o:	$(srcdir)/kpasswd.c
+ksetpwd.o:	$(srcdir)/ksetpwd.c
+
+all-unix:: kpasswd ksetpwd
+
+clean-unix::
+	$(RM) kpasswd.o kpasswd ksetpwd.o ksetpwd
+
+install-all install-kdc install-server install-client install-unix::
+	$(INSTALL_PROGRAM) kpasswd $(DESTDIR)$(CLIENT_BINDIR)/`echo kpasswd|sed '$(transform)'`
+	$(INSTALL_DATA) $(srcdir)/kpasswd.M $(DESTDIR)$(CLIENT_MANDIR)/`echo kpasswd|sed '$(transform)'`.1;
+
+all-windows:: $(OUTPRE)kpasswd.exe
+
+$(OUTPRE)kpasswd.exe: $(OUTPRE)kpasswd.obj $(KLIB) $(CLIB)
+	link $(EXE_LINKOPTS) -out:$@ $**
diff --git a/mechglue/src/clients/kpasswd/kpasswd.M b/mechglue/src/clients/kpasswd/kpasswd.M
new file mode 100644
index 000000000..d3cacbbaa
--- /dev/null
+++ b/mechglue/src/clients/kpasswd/kpasswd.M
@@ -0,0 +1,75 @@
+.\" clients/kpasswd/kpasswd.M
+.\" 
+.\" Copyright 1995 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.\.so man1/header.doc
+.TH KPASSWD 1 \*h
+.SH NAME
+kpasswd \- change a user's Kerberos password
+.SH SYNOPSIS
+.B kpasswd
+[\fIprincipal\fP]
+.SH DESCRIPTION
+.PP
+The
+.I kpasswd
+command is used to change a Kerberos principal's password.
+.I Kpasswd
+prompts for the current Kerberos password, which is used to obtain a 
+.B changepw
+ticket from the
+.SM KDC
+for the user's Kerberos realm.  If
+.B kpasswd
+successfully obtains the
+.B changepw
+ticket, the user is prompted twice for the new password, and the
+password is changed.
+.PP
+If the principal is governed by a policy that specifies the length and/or
+number of character classes required in the new password, the new
+password must conform to the policy.  (The five character classes are
+lower case, upper case, numbers, punctuation, and all other characters.)
+.SH OPTIONS
+.TP
+.I principal
+change the password for the Kerberos principal
+.IR principal .
+Otherwise, 
+.I kpasswd
+uses the principal name from an existing ccache if there is one; if
+not, the principal is derived from the identity of the user
+invoking the
+.I kpasswd
+command.
+.SH PORTS
+.B kpasswd 
+looks first for kpasswd_server = host:port in the [realms] section of
+the krb5.conf file under the current realm.  If that is missing,
+.B kpasswd
+looks for the admin_server entry, but substitutes 464 for the port.
+.SH SEE ALSO
+kadmin(8), kadmind(8)
+.SH BUGS
+.PP
+.B kpasswd
+may not work with multi-homed hosts running on the Solaris platform.
diff --git a/mechglue/src/clients/kpasswd/kpasswd.c b/mechglue/src/clients/kpasswd/kpasswd.c
new file mode 100644
index 000000000..b597853cf
--- /dev/null
+++ b/mechglue/src/clients/kpasswd/kpasswd.c
@@ -0,0 +1,150 @@
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include <krb5.h>
+
+#define P1 "Enter new password"
+#define P2 "Enter it again"
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+
+static
+void get_name_from_passwd_file(program_name, kcontext, me)
+    char * program_name;
+    krb5_context kcontext;
+    krb5_principal * me;
+{
+    struct passwd *pw;
+    krb5_error_code code;
+    if ((pw = getpwuid(getuid()))) {
+	if ((code = krb5_parse_name(kcontext, pw->pw_name, me))) {
+	    com_err (program_name, code, "when parsing name %s", pw->pw_name);
+	    exit(1);
+	}
+    } else {
+	fprintf(stderr, "Unable to identify user from password file\n");
+	exit(1);
+    }
+}
+#else /* HAVE_PWD_H */
+void get_name_from_passwd_file(kcontext, me)
+    krb5_context kcontext;
+    krb5_principal * me;
+{
+    fprintf(stderr, "Unable to identify user\n");
+    exit(1);
+}
+#endif /* HAVE_PWD_H */
+
+int main(int argc, char *argv[])
+{
+   krb5_error_code ret;
+   krb5_context context;
+   krb5_principal princ;
+   char *pname;
+   krb5_ccache ccache;
+   krb5_get_init_creds_opt opts;
+   krb5_creds creds;
+
+   char pw[1024];
+   unsigned int pwlen;
+   int result_code;
+   krb5_data result_code_string, result_string;
+
+   if (argc > 2) {
+      fprintf(stderr, "usage: %s [principal]\n", argv[0]);
+      exit(1);
+   }
+
+   pname = argv[1];
+
+   ret = krb5_init_context(&context);
+   if (ret) {
+      com_err(argv[0], ret, "initializing kerberos library");
+      exit(1);
+   }
+
+   /* in order, use the first of:
+      - a name specified on the command line
+      - the principal name from an existing ccache
+      - the name corresponding to the ruid of the process
+
+      otherwise, it's an error.
+      */
+
+   if (pname) {
+      if ((ret = krb5_parse_name(context, pname, &princ))) {
+	 com_err(argv[0], ret, "parsing client name");
+	 exit(1);
+      }
+   } else if ((ret = krb5_cc_default(context, &ccache)) != KRB5_CC_NOTFOUND) {
+      if (ret) {
+	 com_err(argv[0], ret, "opening default ccache");
+	 exit(1);
+      }
+
+      if ((ret = krb5_cc_get_principal(context, ccache, &princ))) {
+	 com_err(argv[0], ret, "getting principal from ccache");
+	 exit(1);
+      }
+
+      if ((ret = krb5_cc_close(context, ccache))) {
+	 com_err(argv[0], ret, "closing ccache");
+	 exit(1);
+      }
+   } else {
+       get_name_from_passwd_file(argv[0], context, &princ);
+   }
+
+   krb5_get_init_creds_opt_init(&opts);
+   krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
+   krb5_get_init_creds_opt_set_renew_life(&opts, 0);
+   krb5_get_init_creds_opt_set_forwardable(&opts, 0);
+   krb5_get_init_creds_opt_set_proxiable(&opts, 0);
+
+   if ((ret = krb5_get_init_creds_password(context, &creds, princ, NULL,
+					   krb5_prompter_posix, NULL, 
+					   0, "kadmin/changepw", &opts))) {
+      if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+	 com_err(argv[0], 0,
+		 "Password incorrect while getting initial ticket");
+      else
+	 com_err(argv[0], ret, "getting initial ticket");
+      exit(1);
+   }
+
+   pwlen = sizeof(pw);
+   if ((ret = krb5_read_password(context, P1, P2, pw, &pwlen))) {
+      com_err(argv[0], ret, "while reading password");
+      exit(1);
+   }
+
+   if ((ret = krb5_change_password(context, &creds, pw,
+				   &result_code, &result_code_string,
+				   &result_string))) {
+      com_err(argv[0], ret, "changing password");
+      exit(1);
+   }
+
+   if (result_code) {
+      printf("%.*s%s%.*s\n",
+	     (int) result_code_string.length, result_code_string.data,
+	     result_string.length?": ":"",
+	     (int) result_string.length,
+	     result_string.data ? result_string.data : "");
+      exit(2);
+   }
+
+   if (result_string.data != NULL) 
+       free(result_string.data);
+   if (result_code_string.data != NULL)
+       free(result_code_string.data);
+
+   printf("Password changed.\n");
+   exit(0);
+}
diff --git a/mechglue/src/clients/kpasswd/ksetpwd.c b/mechglue/src/clients/kpasswd/ksetpwd.c
new file mode 100644
index 000000000..148e68651
--- /dev/null
+++ b/mechglue/src/clients/kpasswd/ksetpwd.c
@@ -0,0 +1,313 @@
+#include <krb5.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+
+#define TKTTIMELEFT     60*10   /* ten minutes */
+
+static int verify_creds()
+{
+	krb5_context	kcontext;
+	krb5_ccache		ccache;
+	krb5_error_code	kres;
+
+	kres = krb5_init_context(&kcontext);
+	if( kres == 0 )
+	{
+		kres = krb5_cc_default( kcontext, &ccache );
+		if( kres == 0 )
+		{
+			krb5_principal	user_princ;
+
+			kres = krb5_cc_get_principal( kcontext, ccache, &user_princ );
+			if( kres == 0 )
+				krb5_free_principal( kcontext, user_princ );
+			krb5_cc_close( kcontext, ccache );
+		}
+		krb5_free_context(kcontext);
+	}
+	return kres;
+}
+
+static void get_init_creds_opt_init( krb5_get_init_creds_opt *outOptions )
+{
+    krb5_preauthtype    preauth[] = { KRB5_PADATA_ENC_TIMESTAMP };
+    krb5_enctype        etypes[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_CRC};
+    memset( outOptions, 0, sizeof(*outOptions) );
+    krb5_get_init_creds_opt_init(outOptions);
+    krb5_get_init_creds_opt_set_address_list(outOptions, NULL);
+    krb5_get_init_creds_opt_set_etype_list( outOptions, etypes, sizeof(etypes)/sizeof(krb5_enctype) );
+    krb5_get_init_creds_opt_set_preauth_list(outOptions, preauth, sizeof(preauth)/sizeof(krb5_preauthtype) );
+}
+
+typedef void * kbrccache_t;
+#define CCACHE_PREFIX_DEFAULT "MEMORY:C_"
+
+static kbrccache_t userinitcontext(
+	const char * user, const char * domain, const char * passwd, const char * cachename, int initialize,
+	int * outError )
+{
+	krb5_context	kcontext = 0;
+	krb5_ccache		kcache = 0;
+	krb5_creds		kcreds;
+	krb5_principal	kme = 0;
+	krb5_error_code	kres;
+	char *			pPass = strdup( passwd );
+	char *			pName = NULL;
+	char *			pCacheName = NULL;
+	int				numCreds = 0;
+
+	memset( &kcreds, 0, sizeof(kcreds) );
+	kres = krb5_init_context( &kcontext );
+	if( kres )
+		goto return_error;
+	if( domain )
+		kres = krb5_build_principal( kcontext, &kme, strlen(domain), domain, user, 0 );
+	else
+		kres = krb5_parse_name( kcontext, user, &kme );
+	if( kres )
+		goto fail;
+	krb5_unparse_name( kcontext, kme, &pName );
+	if( cachename )
+	{
+		pCacheName = malloc( strlen( pName ) + strlen( cachename ) + 1 );
+		if( pCacheName == NULL )
+		{
+			kres = KRB5_CC_NOMEM;
+			goto fail;
+		}
+		strcpy( pCacheName, cachename );
+		strcat( pCacheName, pName );
+		kres = krb5_cc_resolve( kcontext, pCacheName, &kcache );
+		if( kres )
+		{
+			kres = krb5_cc_resolve( kcontext, CCACHE_PREFIX_DEFAULT, &kcache );
+			if( kres == 0 )
+				pCacheName = strdup(CCACHE_PREFIX_DEFAULT);
+		}
+	}
+	else
+	{
+		kres = krb5_cc_default( kcontext, &kcache );
+		pCacheName = strdup( krb5_cc_get_name( kcontext, kcache ) );
+	}
+	if( kres )
+	{
+		krb5_free_context(kcontext);
+		goto return_error;
+	}
+	if( initialize )
+		krb5_cc_initialize( kcontext, kcache, kme );
+	if( kres == 0 && user && passwd )
+	{
+		long timeneeded = time(0L) +TKTTIMELEFT;
+		int have_credentials = 0;
+		krb5_cc_cursor cc_curs = NULL;
+		numCreds = 0;
+		if( (kres=krb5_cc_start_seq_get(kcontext, kcache, &cc_curs)) >= 0 )
+		{
+			while( (kres=krb5_cc_next_cred(kcontext, kcache, &cc_curs, &kcreds))== 0)
+			{
+				numCreds++;
+				if( krb5_principal_compare( kcontext, kme, kcreds.client ) )
+				{
+					if( kcreds.ticket_flags & TKT_FLG_INITIAL && kcreds.times.endtime>timeneeded )
+						have_credentials = 1;
+				}
+				krb5_free_cred_contents( kcontext, &kcreds );
+				if( have_credentials )
+					break;
+			}
+			krb5_cc_end_seq_get( kcontext, kcache, &cc_curs );
+		}
+		else
+		{
+			const char * errmsg = error_message(kres);
+			fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg );
+		}
+		if( kres != 0 || have_credentials == 0 )
+		{
+			krb5_get_init_creds_opt options;
+			get_init_creds_opt_init(&options);
+/*
+** no valid credentials - get new ones
+*/
+			kres = krb5_get_init_creds_password( kcontext, &kcreds, kme, pPass,
+					NULL /*prompter*/, 
+					NULL /*data*/,
+					0 /*starttime*/,
+					0 /*in_tkt_service*/,
+					&options /*options*/ );
+			if( kres == 0 )
+			{
+				if( numCreds <= 0 )
+					kres = krb5_cc_initialize( kcontext, kcache, kme );
+				if( kres == 0 )
+					kres = krb5_cc_store_cred( kcontext, kcache, &kcreds );
+				if( kres == 0 )
+					have_credentials = 1;
+			}
+		}
+#ifdef NOTUSED
+		if( have_credentials )
+		{
+			int mstat;
+			kres = gss_krb5_ccache_name( &mstat, pCacheName, NULL );
+			if( getenv( ENV_DEBUG_LDAPKERB ) )
+				fprintf( stderr, "gss credentials cache set to %s(%d)\n", pCacheName, kres );
+		}
+#endif
+		krb5_cc_close( kcontext, kcache );
+	}
+fail:
+	if( kres )
+	{
+			const char * errmsg = error_message(kres);
+			fprintf( stderr, "%s user init(%s): %s\n", "setpass", pName, errmsg );
+	}
+	krb5_free_principal( kcontext, kme );
+	krb5_free_cred_contents( kcontext, &kcreds );
+	if( pName )
+		free( pName );
+	free(pPass);
+	krb5_free_context(kcontext);
+
+return_error:
+	if( kres )
+	{
+		if( pCacheName )
+		{
+			free(pCacheName);
+			pCacheName = NULL;
+		}
+	}
+	if( outError )
+		*outError = kres;
+	return pCacheName;
+}
+
+static int init_creds()
+{
+	char user[512];
+	char * password = NULL;
+	int result;
+
+	user[0] = 0;
+	result = -1;
+
+	for(;;)
+	{
+		while( user[0] == 0 )
+		{
+			int userlen;
+			printf( "Username: ");
+			fflush(stdout);
+			if( fgets( user, sizeof(user), stdin ) == NULL )
+				return -1;
+			userlen = strlen( user);
+			if( userlen < 2 )
+				continue;
+			user[userlen-1] = 0;	/* get rid of the newline */
+			break;
+		}
+		{
+			kbrccache_t usercontext;
+			password = getpass( "Password: ");
+			if( ! password )
+				return -1;
+			result = 0;
+			usercontext = userinitcontext( user, NULL, password, NULL, 1, &result );
+			if( usercontext )
+				break;
+		}
+	}
+	return result;
+}
+
+int main( int argc, char ** argv )
+{
+	char * new_password = NULL;
+	char * new_password2;
+	krb5_context	kcontext;
+	krb5_error_code	kerr;
+	krb5_principal	target_principal;
+
+
+	if( argc < 2 )
+	{
+		fprintf( stderr, "Usage: setpass user@REALM\n");
+		exit(1);
+	}
+
+/*
+** verify credentials -
+*/
+	if( verify_creds() )
+		init_creds();
+	if( verify_creds() )
+	{
+		fprintf( stderr, "No user credentials available\n");
+		exit(1);
+	}
+/*
+** check the principal name -
+*/
+	krb5_init_context(&kcontext);
+	kerr = krb5_parse_name( kcontext, argv[1], &target_principal );
+
+	{
+		char * pname = NULL;
+		kerr = krb5_unparse_name( kcontext, target_principal, &pname );
+		printf( "Changing password for %s:\n", pname);
+		fflush( stdout );
+		free( pname );
+	}
+/*
+** get the new password -
+*/
+	while( !new_password )
+	{
+		new_password = getpass("Enter new password: ");
+		new_password2 = getpass("Verify new password: ");
+		if( strcmp( new_password, new_password2 ) )
+		{
+			printf("Passwords do not match\n");
+			free( new_password );
+			free( new_password2 );
+			continue;
+		}
+	}
+/*
+** change the password -
+*/
+	fprintf( stderr, "the password is %s\n", new_password );
+
+	{
+		int pw_result;
+		krb5_ccache ccache;
+		krb5_data	pw_res_string, res_string;
+
+		kerr = krb5_cc_default( kcontext, &ccache );
+		if( kerr == 0 )
+		{
+			kerr = krb5_set_password_using_ccache(kcontext, ccache, new_password, target_principal,
+						&pw_result, &pw_res_string, &res_string );
+			if( kerr )
+				fprintf( stderr, "Failed: %s\n", error_message(kerr) );
+			else
+			{
+				if( pw_result )
+				{
+					fprintf( stderr, "Failed(%d)", pw_result );
+					if( pw_res_string.length > 0 )
+						fprintf( stderr, ": %s", pw_res_string.data);
+					if( res_string.length > 0 )
+						fprintf( stderr, " %s", res_string.data);
+					fprintf( stderr, "\n");
+				}
+			}
+		}
+	}
+	return(0);
+}
diff --git a/mechglue/src/clients/ksu/.Sanitize b/mechglue/src/clients/ksu/.Sanitize
new file mode 100644
index 000000000..037d5b20f
--- /dev/null
+++ b/mechglue/src/clients/ksu/.Sanitize
@@ -0,0 +1,43 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+authorization.c
+ccache.c
+configure
+configure.in
+heuristic.c
+krb_auth_su.c
+ksu.M
+ksu.h
+main.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/clients/ksu/ChangeLog b/mechglue/src/clients/ksu/ChangeLog
new file mode 100644
index 000000000..17a1dffe8
--- /dev/null
+++ b/mechglue/src/clients/ksu/ChangeLog
@@ -0,0 +1,557 @@
+2003-04-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* heuristic.c (get_closest_principal): Don't try to examine
+	principal name components after the last.
+	* krb_auth_su.c (get_best_principal): Check principal name length
+	before examining components.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* authorization.c, heuristic.c, ksu.h: Use uid_t instead of int in
+	arguments to fowner() and get_best_princ_for_target(). Signed
+	vs. unsigned int cleanup.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-14  Jen Selby  <jenselby@mit.edu>
+
+	* main.c:  updated the usage function
+
+2002-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (ksu): Don't use krb5util library.
+
+2002-06-21  Ezra Peisach  <epeisach@bu.edu>
+
+	* ccache.c (printtime): Do not assume that krb5_timestamp and
+	time_t are the same size as an argument to localtime.
+
+	* heuristic.c (get_authorized_princ_names): If .k5login file
+	exists but is not owned by the user, do not attempt to fclose an
+	uninitialized FILE *.
+
+2001-10-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* main.c (main): Do not pass LOG_AUTH facility into openlog() as a
+	logopt.
+
+2001-10-18  Ken Raeburn  <raeburn@mit.edu>
+
+	Don't crash if .k[5]login file ownership is wrong.  Patch from
+	Emily Ratliff, ratliff@austin.ibm.com.
+	* authorization.c (fowner): Don't close the file even on error.
+	(krb5_authorization): Close the file if fowner returns FALSE.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* authorization.c, heuristic.c, krb_auth_su.c, ksu.h, main.c: Make
+	prototypes unconditional.
+
+2001-10-07  Mitchell Berger  <mitchb@mit.edu>
+
+	* krb_auth_su.c: Fix a call to plain_dump_principal() that had the
+	wrong number of arguments but was only compiled if GET_TGT_VIA_PASSWD
+	wasn't defined.
+
+2001-09-16  Mitchell Berger  <mitchb@mit.edu>
+
+	* ksu.M: Correct a few typos.
+
+2001-07-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* setenv.c: Include stdlib.h, provide prototypes for setenv and
+	unsetenv before declaration.
+
+2001-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* authorization.c (find_first_cmd_that_exists): Change xmalloc()
+	to xcalloc() where was intented in code (two arguments to xmalloc).
+
+	* ksu.h: Provide full prototypes for xmalloc(), xrealloc(),
+	xcalloc(), and xstrdup().
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* main.c (get_params): Change optind to optindex to prevent
+	shadowing. 
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* main.c (main): Cast arguments to print_status to be consitant
+	with format string.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* setenv.c: Add prototype for _findenv to avoid inconsistancy of
+	static vs. extern.
+
+	* heuristic.c (find_either_ticket): Change krb5_tgtname() to
+	ksu_tgtname().
+
+	* ccache.c: Include <sys/types.h> and <sys/stat.h> for start()
+	prototype.
+
+	* krb_auth_su.c: Reindent for readability. Remove defunct
+	code. Change use of krb5_tgtname to ksu_tgtname().
+
+	* ksu.h: Include k5-util.h for krb5_seteuid() prototype. Add
+	prototype for ksu_tgtname. Add prototype for unsetenv() if not
+	defined.
+
+	* main.c: Include grp.h for initgroups() prototype. Cleanup
+	assignment in conditional warning. Reindent for
+	readability. Arguments to print_status made consistant with regard
+	to long vs. int. Change krb5_tgtname to ksu_tgtname. (do not use
+	an internal krb5 function that is not advertised).
+
+2001-06-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* authorization.c, heuristic.c, krb_auth_su.c, main.c, setenv.c:
+	Cleanup assignments in conditionals.
+
+2001-04-03  Tom Yu  <tlyu@mit.edu>
+
+	* setenv.c: Add conditionals for compilation of setenv, unsetenv,
+	and getenv such that they only get compiled if they don't already
+	exist. [pullup from krb5-1-2-2-branch]
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb_auth_su.c (krb5_get_tkt_via_passwd): Argument to
+	krb5_read_password now takes an unsigned int.
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* ccache.c, heuristic.c, main.c: Return of krb5_cc_get_name() is
+	const char *.
+
+2000-05-22  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (OBJS): Put @SETENVOBJ@ on same line as xmalloc.o to
+	avoid trailing backslash on the end of the variable.
+
+2000-05-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* ccache.c (krb5_ccache_copy): Modify conditionalized code block
+	slightly to make automatic indentation work better.
+
+	* main.c (main): Complain and quit if prog_name is longer than 50
+	characters.
+
+2000-04-26  Ken Raeburn  <raeburn@mit.edu>
+	    Nalin Dahyabhai  <nalin@redhat.com>
+
+	* main.c (DEBUG): Don't define.
+	(usage): Remove -C option from description.
+	(sweep_up): Deleted second argument; all callers changed.
+	(main): Support -D option only if DEBUG is defined.  Initialize
+	ruid on entry.  Set effective uid to ruid before processing
+	argument list.  Removed -C option from -z/-Z conflict messages.
+	Report errors trying to stat source ccache using com_err.  Verify
+	that getpwuid's returned data for source user has correct uid.
+	Eliminate use_source_cache variable.
+
+	* ksu.M: Updates for removal of -C option.
+
+2000-01-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* main.c (print_status): Now static.  Add format attribute if
+	using GNU C.
+
+1999-12-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb_auth_su.c (krb5_get_tkt_via_passwd): Check length of
+	principal name before copying to fixed-size buffer.
+
+	* ccache.c (krb5_ccache_filter): Fix speling error.
+	(krb5_get_login_princ): Check length of home directory pathname.
+
+	* setenv.c: New file, copied from appl/bsd.
+	* Makefile.in (OBJS): Add @SETENVOBJ@.
+	(SRCS): Add setenv.c.
+
+	* xmalloc.c: New file, providing versions of malloc, calloc,
+	realloc, and strdup that print messages and exit if memory
+	allocation fails.
+	* ksu.h (xmalloc, xrealloc, xcalloc, xstrdup): Declare.
+	* Makefile.in (SRCS, OBJS): Use it.
+	* authorization.c, ccache.c, heuristic.c, main.c: Change all calls
+	to malloc, calloc, realloc, and strdup to call x* versions if the
+	return value is not checked before use.
+
+	* authorization.c (auth_cleanup): Ditch int arguments, check for
+	null pointers instead.
+	(krb5_authorization): Update calls.  Initialize file pointers to
+	null.
+	(init_auth_names): Check for buffer overflow.
+	(fcmd_resolve): Ensure enough buffer space is allocated.
+	(find_first_cmd_that_exists): Likewise.  Use strcat instead of
+	sprintf'ing a buffer into itself.
+
+	* krb_auth_su.c (dump_principal, plain_dump_principal): Reformat
+	slightly.
+
+	* main.c (cc_source_tag, cc_source_tag_tmp): Now point to const.
+	(main): Unset environment variable KRB5_CONFIG.  Delete -C
+	option.  Force an error if lifetime strings are over 14
+	characters.  Fix error message string if setluid fails.  Cast pid
+	to long for printing.  Call krb5_init_secure_context instead of
+	krb5_init_context and krb5_secure_config_files.
+	(main): Fix speling error.
+	(ontty): Check string size.
+	(get_dir_of_file): Argument now points to const.
+	* ksu.h (get_dir_of_file): Update declaration.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* heuristic.c (find_ticket): Use flag KRB5_TC_SUPPORTED_KTYPES
+	when calling krb5_cc_retrieve_cred.
+	* krb_auth_su.c (krb5_auth_check, krb5_fast_auth): Ditto.
+
+Fri Mar 12 18:52:18 1999  Tom Yu  <tlyu@mit.edu>
+
+	* main.c (main): Fix cleanup code for setluid() failure.
+
+Thu Mar  4 18:46:55 1999  Tom Yu  <tlyu@mit.edu>
+
+	* heuristic.c (get_authorized_princ_names): Fix to not call
+	list_union() if cmd is NULL, otherwise freed memory gets
+	referenced. [krb5-clients/698]
+
+Thu Feb 18 22:26:30 1999  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (ksu): Add $(KSU_LIBS) in case we need -lsecurity.
+
+	* main.c (main): Add call to setluid() on systems that have it.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* main.c (main): POSIX states that getopt returns -1 when it
+		is done parsing options, not EOF.
+
+Wed Feb 18 15:44:15 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+ 	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Feb  4 20:46:49 1998  Tom Yu  <tlyu@mit.edu>
+
+	* krb_auth_su.c (krb5_verify_tkt_def): If using a pre-existing
+	credential cache, ensure that the host ticket has not yet
+	expired.  Patch from vwelch@ncsa.uiuc.edu [krb5-clients/545].
+
+Mon Jan 27 16:56:07 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Sun Nov 10 20:10:53 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* krb_auth_su.c (path_passwd;): If you don't have a srvtab, always
+ 	fail.
+
+Thu Nov  7 15:41:19 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* main.c (main): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Wed Sep 18 15:54:41 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb_auth_su.c (krb5_get_tkt_via_passwd): Remove call to
+		krb5_os_localaddr(), since get_in_tkt will default correctly.
+
+Tue Sep 10 14:15:02 1996  Tom Yu  <tlyu@mit.edu>
+
+	* ksu.M: remove ".so man1/header.doc"
+
+Thu Aug  8 12:31:30 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* main.c (main): Close source cache before executing command.
+
+Sat May 25 16:11:55 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: Use aname db libs.
+
+Tue May 21 19:14:27 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (install): Ignore error return from installation of
+ 	ksu; if we can't set the setuid bit (AFS or non-root), we should
+ 	still continue.
+
+Mon May 20 00:07:16 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* main.c (main):  Do not force source cache open if we are going to use it as the target.
+
+Sun May 19 13:41:21 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* main.c: Force source ccache to stay open between transactions.
+
+Sun May 19 03:24:26 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krb_auth_su.c: Use target uid while creating ccache
+
+	* ccache.c: Set uid to target before creating target cache.
+
+	* ksu.h: Add target_uid to copy_ccache and copy_ccache_restricted
+
+Sat May 18 16:39:15 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Use libkrb5util to get krb5_seteuid
+
+	* heuristic.c (get_best_princ_for_target): Remove seteuid around stat call and insert call to krb5_seteuid before accessing .k5login or .k5users.
+
+	* main.c (main): Insert appropriate calls to krb5_seteuid so that
+        files are accessed as appropriate.  Also, remove code to copy
+        tickets obtained while running ksu overthe source cache; this is
+        not appropriate because it changes the ownership of the source
+        cache.
+
+Mon May 13 06:50:12 1996  Richard Basch  <basch@lehman.com>
+
+	* authorization.c: users in the .k5login were not permitted to use
+	the '-e command' flag; the man page does not indicate this should fail.
+	All users in .k5login, and those in .k5users (for the specified cmd)
+	are now allowed to execute commands.
+	Also, a lot of indentation cleanup was done.
+
+	* configure.in heuristic.c:
+	Before getting the best principal from the ccache, reset the euid;
+	we don't want to use someone else's ccache.
+	Also, a lot of indentation cleanup was done.
+
+Wed Apr 10 20:24:49 1996  Richard Basch  <basch@lehman.com>
+
+	* main.c, krb_auth_su.c: Mostly cosmetic cleanup of output
+	statements.  Also, rather than computing the default host key,
+	let the library routine do it.
+
+Sun Mar 31 16:48:29 1996  Chris Provenzano  <proven@cygnus.com>
+
+	* main.c (main): Handle suspend/fg properly.
+
+Fri Mar 29 23:35:53 1996  Chris Provenzano  <proven@cygnus.com>
+
+	* ccache.c main.c: Remove krb5_ccache_refresh(). All this functionality
+	is is done in the krb5_ccache_copy(), and the way refresh() was
+	implemented it was generating a new ccache owner by root (ksu is suid)
+	over the old ccache, thereby making it possible that programs 
+	accessing the ccache during this time would fail.
+
+Wed Mar 13 17:45:11 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Use AC_HEADER_STDARG.
+
+Wed Nov  8 17:54:11 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* ccache.c (krb5_check_exp): Change use of krb5_clockskew to be
+	        context->clockskew.
+
+Mon Oct  9 23:14:33 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* main.c (main): Handle case when ticket cache name does not
+		include ':'
+
+Thu Oct  5 11:23:21 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ksu.M: Document authorization changes.
+
+	* ksu.1: Remove as was out of date.
+
+	* Makefile.in (DEFINES): Remove LOCAL_REALM definition.
+
+	* ksu.h: Remove local_realm from krb5_authorization.
+
+	* authorization.c (krb5_authorization): Remove old copied code
+		that is in krb5 library and is out of date. Use the
+		configurable aname to localname methods.
+
+	* main.c (main): Add krb5_secure_config_files so that users cannot
+		override system config files.
+	
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * krb_auth_su.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * krb_auth_su.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate.
+
+Mon Aug 21 16:53:40 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* ksu.h - Change lifetime types to krb5_deltat.
+	* main.c - Use string_to_deltat() to parse lifetimes.  Fix gcc -Wall.
+	* krb_auth_su.c - Fix gcc -Wall.  Remove krb5_parse_lifetime() and
+		convtime().  No longer needed.
+	* ccache.c - Remove English-specific months and let timestamp_to_
+		sfstring() handle it.  Fix gcc -Wall.
+	* configure.in - Add -lkadm.
+
+Sat Jul 29 04:41:07 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* configure.in: Don't link with -lkadm.
+
+Tue Jul 11 11:10:13 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* main.c (main): Remove extraneous argument to call to
+		krb5_parse_lifetime. Add context argument to call to
+		plain_dump_principal. 
+
+	* authorization.c, heuristic.c, krb_auth_su.c: Add prototypes
+		for static functions. Add missing arguments to
+		_dbm_an_to_ln call. 
+
+	* ccache.c: Remove prototype declaration of function now defined
+		in ksu.h
+
+	* ksu.h: Add full prototypes for all functions in program.
+
+Fri Jul 7 15:55:14 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling and LDFLAGS.
+	* configure.in - Add USE_KADM_LIBRARY and KRB5_LIBRARIES.
+
+Thu Jul  6 17:30:49 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* krb_auth_su.c (krb5_get_tkt_via_passwd): Pass context to
+		os_localaddr.
+
+Tue Jun 20 14:32:46 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* main.c: HAS_GETUSERSHELL -> HAVE_GETUSERSHELL
+
+	* configure.in: add test for getusershell()
+
+Thu Jun 15 17:46:22 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Fri Jun  9 18:37:43 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Tue May  9 15:52:15 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb_auth_su.c (krb5_auth_check): Add missing context
+		(wolfgang@wsrcc.com) 
+
+	* ccache.c (krb5_get_nonexp_tkts): Add missing context
+		(wolfgang@wsrcc.com) 
+
+	* heuristic.c (get_best_princ_for_target): Missing context cuased
+		coredump. 
+		(get_best_princ_for_target): Missing contexts in call to
+		 		find_either_ticket. 
+		(find_either_ticket): Missing context in call of find_ticket
+		(get_best_princ_for_target): Add missing context
+
+Thu Mar 16 20:50:32 1995  John Gilmore  (gnu at toad.com)
+
+	* configure.in:  Replace CHECK_STDARG with AC_CHECK_HEADERS.
+	* main.c (print_status):  Use HAVE_STDARG_H to control whether to
+	declare with ", ..."; not STDARG_PROTOTYPES.
+	* ksu.h:  Don't include <stdarg.h> or <varargs.h>, since they
+	are already included by "com_err.h".
+
+Thu Mar  2 12:32:17 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:28:36 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 02:11:21 1995  John Gilmore  (gnu at toad.com)
+
+	* ksu.h:  Avoid <krb5/...> and <com_err.h> includes.
+
+Fri Feb 17 18:10:04 1995 Chris Provenzano  (proven@mit.edu)
+
+	* krb_auth_su.c krb5_auth_check()) Call krb5_get_cred_from_kdc()
+		with new calling convention.
+
+Mon Feb 06 17:19:04 1995 Chris Provenzano  (proven@mit.edu)
+
+        * krb_auth_su.c Removed krb5_keytype, changed krb5_enctype to
+                krb5_enctype *, changed krb5_preauthtype to krb5_preauthtype *
+                for krb5_get_in_tkt_with_password() rotuine.
+
+Sat Jan 28 14:45:55 1995  Chris Provenzano (proven@mit.edu)
+
+        * krb_auth_su.c (krb5_verify_tkt_def()) use new API for 
+		krb5_kt_get_entry.
+
+Wed Jan 18 12:21:30 1995    <tytso@rsx-11.mit.edu>
+
+	* main.c (main): If gethostbyname returns an error, exit after
+		printing an error message.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Mon Oct  3 19:15:28 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
+Fri Sep 30 22:14:41 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb_auth_su.c: Add magic number placeholder to structures.
+
+Tue Aug  9 20:29:47 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* *.c: "upgrade" to C Classic :-)
+
+Tue Aug  9 00:11:07 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* main.c: define MAXHOSTNAMELEN if it isn't there already
+	(print_status): use varargs form as well
+	* configure.in: check for stdarg.h
+
+Thu Aug  4 03:38:03 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: make install fixes
+
+Mon Jul 25 01:23:36 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: check for ndbm/dbm
+
+Thu Jul 21 01:01:20 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in:
+	* configure.in: attempt to autoconf
+
+Sat Jul 16 03:02:17 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* ksu.c: frob error codes
+
+Fri Jul 15 23:45:34 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* ksu.c (get_dir_of_file): Change to use POSIX getcwd() function.
+
+
diff --git a/mechglue/src/clients/ksu/Makefile.in b/mechglue/src/clients/ksu/Makefile.in
new file mode 100644
index 000000000..6004932f2
--- /dev/null
+++ b/mechglue/src/clients/ksu/Makefile.in
@@ -0,0 +1,90 @@
+thisconfigdir=./..
+myfulldir=clients/ksu
+mydir=ksu
+BUILDTOP=$(REL)..$(S)..
+DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /local/bin"'
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+KSU_LIBS=@KSU_LIBS@
+
+SRCS = \
+	$(srcdir)/krb_auth_su.c \
+	$(srcdir)/ccache.c \
+	$(srcdir)/authorization.c \
+	$(srcdir)/main.c \
+	$(srcdir)/heuristic.c \
+	$(srcdir)/xmalloc.c \
+	$(srcdir)/setenv.c
+OBJS = \
+	krb_auth_su.o \
+	ccache.o \
+	authorization.o \
+	main.o \
+	heuristic.o \
+	xmalloc.o @SETENVOBJ@
+
+all:: ksu
+
+ksu: $(OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS)
+
+clean::
+	$(RM) ksu
+
+install::
+	-for f in ksu; do \
+	  $(INSTALL_SETUID) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		${DESTDIR}$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)krb_auth_su.$(OBJEXT): krb_auth_su.c ksu.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/k5-util.h $(SRCTOP)/include/syslog.h
+$(OUTPRE)ccache.$(OBJEXT): ccache.c ksu.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/k5-util.h \
+  $(SRCTOP)/include/syslog.h $(SRCTOP)/include/krb5/adm_proto.h
+$(OUTPRE)authorization.$(OBJEXT): authorization.c ksu.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/k5-util.h $(SRCTOP)/include/syslog.h
+$(OUTPRE)main.$(OBJEXT): main.c ksu.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/k5-util.h \
+  $(SRCTOP)/include/syslog.h $(SRCTOP)/include/krb5/adm_proto.h
+$(OUTPRE)heuristic.$(OBJEXT): heuristic.c ksu.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/k5-util.h \
+  $(SRCTOP)/include/syslog.h
+$(OUTPRE)xmalloc.$(OBJEXT): xmalloc.c ksu.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/k5-util.h \
+  $(SRCTOP)/include/syslog.h
+$(OUTPRE)setenv.$(OBJEXT): setenv.c
diff --git a/mechglue/src/clients/ksu/authorization.c b/mechglue/src/clients/ksu/authorization.c
new file mode 100644
index 000000000..09a67b976
--- /dev/null
+++ b/mechglue/src/clients/ksu/authorization.c
@@ -0,0 +1,730 @@
+/*
+ * Copyright (c) 1994 by the University of Southern California
+ *
+ * EXPORT OF THIS SOFTWARE from the United States of America may
+ *     require a specific license from the United States Government.
+ *     It is the responsibility of any person or organization contemplating
+ *     export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
+ *     this software and its documentation in source and binary forms is
+ *     hereby granted, provided that any documentation or other materials
+ *     related to such distribution or use acknowledge that the software
+ *     was developed by the University of Southern California.
+ *
+ * DISCLAIMER OF WARRANTY.  THIS SOFTWARE IS PROVIDED "AS IS".  The
+ *     University of Southern California MAKES NO REPRESENTATIONS OR
+ *     WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
+ *     limitation, the University of Southern California MAKES NO
+ *     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+ *     PARTICULAR PURPOSE. The University of Southern
+ *     California shall not be held liable for any liability nor for any
+ *     direct, indirect, or consequential damages with respect to any
+ *     claim by the user or distributor of the ksu software.
+ *
+ * KSU was writen by:  Ari Medvinsky, ari@isi.edu
+ */
+
+#include "ksu.h"
+
+static void auth_cleanup (FILE *, FILE *, char *);
+
+krb5_boolean fowner(fp, uid)
+    FILE *fp;
+    uid_t uid;
+{
+    struct stat sbuf;
+
+    /*
+     * For security reasons, file must be owned either by
+     * the user himself, or by root.  Otherwise, don't grant access.
+     */
+    if (fstat(fileno(fp), &sbuf)) {
+	return(FALSE);
+    }
+
+    if ((sbuf.st_uid != uid) && sbuf.st_uid) {
+	return(FALSE);
+    }
+
+    return(TRUE);
+}
+
+/*
+ * Given a Kerberos principal "principal", and a local username "luser",
+ * determine whether user is authorized to login according to the
+ * authorization files ~luser/.k5login" and ~luser/.k5users.  Returns TRUE
+ * if authorized, FALSE if not authorized.
+ *
+ */
+
+krb5_error_code krb5_authorization(context, principal, luser,
+				   cmd, ok, out_fcmd)
+    /* IN */
+    krb5_context context;
+    krb5_principal principal;
+    const char *luser;
+    char *cmd;
+    /* OUT */
+    krb5_boolean *ok;
+    char **out_fcmd;
+{
+    struct passwd *pwd;
+    char *princname;
+    int k5login_flag =0;
+    int k5users_flag =0;
+    krb5_boolean retbool =FALSE;
+    FILE * login_fp = 0, * users_fp = 0;
+    krb5_error_code retval = 0;
+    struct stat st_temp;
+
+    *ok =FALSE;
+
+    /* no account => no access */
+    if ((pwd = getpwnam(luser)) == NULL)
+	return 0;
+
+    retval = krb5_unparse_name(context, principal, &princname);
+    if (retval)
+	return retval;
+
+#ifdef DEBUG
+    printf("principal to be authorized %s\n", princname);
+    printf("login file: %s\n", k5login_path);
+    printf("users file: %s\n", k5users_path);
+#endif
+
+    k5login_flag = stat(k5login_path, &st_temp);
+    k5users_flag = stat(k5users_path, &st_temp);
+
+    /* k5login and k5users must be owned by target user or root */
+    if (!k5login_flag){
+    	if ((login_fp = fopen(k5login_path, "r")) == NULL)
+	    return 0;
+	if ( fowner(login_fp, pwd->pw_uid) == FALSE) {
+	    fclose(login_fp);
+	    return 0;
+	}
+    }
+
+    if (!k5users_flag){
+    	if ((users_fp = fopen(k5users_path, "r")) == NULL) {
+	    return 0;
+    	}
+	if ( fowner(users_fp, pwd->pw_uid) == FALSE){
+	    fclose(users_fp);
+	    return 0;
+    	}
+    }
+
+    if (auth_debug){
+	fprintf(stderr,
+		"In krb5_authorization: if auth files exist -> can access\n");
+    }
+
+#if 0
+    if (cmd){
+	if(k5users_flag){
+	    return 0; /* if  kusers does not exist -> done */
+	}else{
+	    if(retval = k5users_lookup(users_fp,princname,
+				       cmd,&retbool,out_fcmd)){
+		auth_cleanup(users_fp, login_fp, princname);
+		return retval;
+	    }else{
+		*ok =retbool;
+		return retval;
+	    }
+	}
+    }
+#endif
+
+    /* if either file exists,
+       first see if the principal is in the login in file,
+       if it's not there check the k5users file */
+
+    if (!k5login_flag){
+	if (auth_debug)
+	    fprintf(stderr,
+		    "In krb5_authorization: principal to be authorized %s\n",
+		    princname);
+
+	retval = k5login_lookup(login_fp,  princname, &retbool);
+	if (retval) {
+	    auth_cleanup(users_fp, login_fp, princname);
+	    return retval;
+	}
+	if (retbool) {
+	    if (cmd)
+		*out_fcmd = xstrdup(cmd);
+	}
+    }
+
+    if ((!k5users_flag) && (retbool == FALSE) ){
+	retval = k5users_lookup (users_fp, princname,
+				 cmd, &retbool, out_fcmd);
+	if(retval) {
+	    auth_cleanup(users_fp, login_fp, princname);
+	    return retval;
+	}
+    }
+
+    if (k5login_flag && k5users_flag){
+
+	char * kuser =  (char *) xcalloc (strlen(princname), sizeof(char));
+	if (!(krb5_aname_to_localname(context, principal,
+				      strlen(princname), kuser))
+	    && (strcmp(kuser, luser) == 0)) {
+	    retbool = TRUE;
+	}
+
+	free(kuser);
+    }
+
+    *ok =retbool;
+    auth_cleanup(users_fp, login_fp, princname);
+    return 0;
+}
+
+/***********************************************************
+k5login_lookup looks for princname in file fp. Spaces
+before the princaname (in the file ) are not ignored
+spaces after the princname are ignored. If there are
+any tokens after the principal name  FALSE is returned.
+
+***********************************************************/
+
+krb5_error_code k5login_lookup (fp, princname, found)
+    FILE *fp;
+    char *princname;
+    krb5_boolean *found;
+{
+
+    krb5_error_code retval;
+    char * line;
+    char * fprinc;
+    char * lp;
+    krb5_boolean loc_found = FALSE;
+
+    retval = get_line(fp, &line);
+    if (retval)
+	return retval;
+
+    while (line){
+	fprinc = get_first_token (line, &lp);
+
+	if (fprinc && (!strcmp(princname, fprinc))){
+	    if( get_next_token (&lp) ){
+		free (line);
+		break;  /* nothing should follow princname*/
+	    }
+	    else{
+		loc_found = TRUE;
+		free (line);
+		break;
+	    }
+	}
+
+	free (line);
+
+	retval = get_line(fp, &line);
+	if (retval)
+	    return retval;
+    }
+
+
+    *found = loc_found;
+    return 0;
+
+}
+
+/***********************************************************
+k5users_lookup looks for princname in file fp. Spaces
+before the princaname (in the file ) are not ignored
+spaces after the princname are ignored.
+
+authorization alg:
+
+if princname is not found return false.
+
+if princname is found{
+	 if cmd == NULL then the file entry after principal
+			name must be nothing or *
+
+	 if cmd !=NULL  then entry must be matched (* is ok)
+}
+
+
+***********************************************************/
+krb5_error_code k5users_lookup (fp, princname, cmd, found, out_fcmd)
+    FILE *fp;
+    char *princname;
+    char *cmd;
+    krb5_boolean *found;
+    char **out_fcmd;
+{
+    krb5_error_code retval;
+    char * line;
+    char * fprinc, *fcmd;
+    char * lp;
+    char * loc_fcmd = NULL;
+    krb5_boolean loc_found = FALSE;
+
+    retval = get_line(fp, &line);
+    if (retval)
+	return retval;
+
+    while (line){
+	fprinc = get_first_token (line, &lp);
+
+	if (fprinc && (!strcmp(princname, fprinc))){
+	    fcmd = get_next_token (&lp);
+
+	    if ((fcmd) && (!strcmp(fcmd, PERMIT_ALL_COMMANDS))){
+		if (get_next_token(&lp) == NULL){
+		    loc_fcmd =cmd ? xstrdup(cmd): NULL;
+		    loc_found = TRUE;
+		}
+		free (line);
+		break;
+	    }
+
+	    if (cmd == NULL){
+		if (fcmd == NULL)
+		    loc_found = TRUE;
+		free (line);
+		break;
+
+	    }else{
+		if (fcmd != NULL) {
+		    char * temp_rfcmd, *err;
+		    krb5_boolean match;
+		    do {
+			if(match_commands(fcmd,cmd,&match,
+					  &temp_rfcmd, &err)){
+			    if (auth_debug){
+				fprintf(stderr,"%s",err);
+			    }
+			    loc_fcmd = err;
+			    break;
+			}else{
+			    if (match == TRUE){
+				loc_fcmd = temp_rfcmd;
+				loc_found = TRUE;
+				break;
+			    }
+			}
+
+		    }while ((fcmd = get_next_token( &lp)));
+		}
+		free (line);
+		break;
+	    }
+	}
+
+	free (line);
+
+	retval = get_line(fp, &line);
+	if (retval) { 
+	    return retval;
+	}
+    }
+
+    *out_fcmd = loc_fcmd;
+    *found = loc_found;
+    return 0;
+
+}
+
+
+/***********************************************
+fcmd_resolve -
+takes a command specified .k5users file and
+resolves it into a full path name.
+
+************************************************/
+
+krb5_boolean fcmd_resolve(fcmd, out_fcmd, out_err)
+    char *fcmd;
+    char ***out_fcmd;
+    char **out_err;
+{
+    char * out_path;
+    char * err;
+    char ** tmp_fcmd;
+    char * path_ptr, *path;
+    char * lp, * tc;
+    int i=0;
+
+    tmp_fcmd = (char **) xcalloc (MAX_CMD, sizeof(char *));
+
+    if (*fcmd == '/'){  /* must be full path */
+	tmp_fcmd[0] = xstrdup(fcmd);
+	tmp_fcmd[1] = NULL;
+	*out_fcmd = tmp_fcmd;
+	return TRUE;
+    }else{
+	/* must be either full path or just the cmd name */
+	if (strchr(fcmd, '/')){
+	    err = (char *) xcalloc((strlen(fcmd) +200) ,sizeof(char));
+	    sprintf(err,"Error: bad entry - %s in %s file, must be either full path or just the cmd name\n", fcmd, KRB5_USERS_NAME);
+	    *out_err = err;
+	    return FALSE;
+	}
+
+#ifndef CMD_PATH
+	err = (char *) xcalloc(2*(strlen(fcmd) +200) ,sizeof(char));
+	sprintf(err,"Error: bad entry - %s in %s file, since %s is just the cmd name, CMD_PATH must be defined \n", fcmd, KRB5_USERS_NAME, fcmd);
+	*out_err = err;
+	return FALSE;
+#else
+
+	path = xstrdup (CMD_PATH);
+	path_ptr = path;
+
+	while ((*path_ptr == ' ') || (*path_ptr == '\t')) path_ptr ++;
+
+	tc = get_first_token (path_ptr, &lp);
+
+	if (! tc){
+	    err = (char *) xcalloc((strlen(fcmd) +200) ,sizeof(char));
+	    sprintf(err,"Error: bad entry - %s in %s file, CMD_PATH contains no paths \n",  fcmd, KRB5_USERS_NAME);
+	    *out_err = err;
+	    return FALSE;
+	}
+
+	i=0;
+	do{
+	    if (*tc != '/'){  /* must be full path */
+		err = (char *) xcalloc((strlen(tc) +200) ,sizeof(char));
+		sprintf(err,"Error: bad path %s in CMD_PATH for %s must start with '/' \n",tc, KRB5_USERS_NAME );
+		*out_err = err;
+		return FALSE;
+	    }
+
+	    out_path = (char *) xmalloc(strlen(tc) + strlen(fcmd) + 2);
+	    sprintf(out_path,"%s/%s",tc, fcmd );
+
+	    tmp_fcmd[i] = out_path;
+
+	    i++;
+
+	} while((tc = get_next_token (&lp)));
+
+	tmp_fcmd[i] = NULL;
+	*out_fcmd = tmp_fcmd;
+	return TRUE;
+
+#endif /* CMD_PATH */
+    }
+}
+
+/********************************************
+cmd_single - checks if cmd consists of a path
+	     or a single token
+
+********************************************/
+
+krb5_boolean cmd_single(cmd)
+    char * cmd;
+{
+
+    if ( ( strrchr( cmd, '/')) ==  NULL){
+	return TRUE;
+    }else{
+	return FALSE;
+    }
+}
+
+/********************************************
+cmd_arr_cmp_postfix - compares a command with the postfix
+         of fcmd
+********************************************/
+
+int cmd_arr_cmp_postfix(fcmd_arr, cmd)
+    char **fcmd_arr;
+    char *cmd;
+{
+    char  * temp_fcmd;
+    char *ptr;
+    int result =1;
+    int i = 0;
+
+    while(fcmd_arr[i]){
+	if ( (ptr = strrchr( fcmd_arr[i], '/')) ==  NULL){
+	    temp_fcmd = fcmd_arr[i];
+	}else {
+	    temp_fcmd = ptr + 1;
+	}
+
+	result = strcmp (temp_fcmd, cmd);
+	if (result == 0){
+	    break;
+	}
+	i++;
+    }
+
+    return result;
+
+
+}
+
+/**********************************************
+cmd_arr_cmp - checks if cmd matches any
+              of the fcmd entries.
+
+**********************************************/
+
+int cmd_arr_cmp (fcmd_arr, cmd)
+    char **fcmd_arr;
+    char *cmd;
+{
+    int result =1;
+    int i = 0;
+
+    while(fcmd_arr[i]){
+	result = strcmp (fcmd_arr[i], cmd);
+	if (result == 0){
+	    break;
+	}
+	i++;
+    }
+    return result;
+}
+
+
+krb5_boolean find_first_cmd_that_exists(fcmd_arr, cmd_out, err_out)
+    char **fcmd_arr;
+    char **cmd_out;
+    char **err_out;
+{
+    struct stat st_temp;
+    int i = 0;
+    krb5_boolean retbool= FALSE;
+    int j =0;
+    char * err;
+    unsigned int max_ln=0;
+    unsigned int tln=0;
+
+    while(fcmd_arr[i]){
+	tln = strlen(fcmd_arr[i]);
+	if ( tln > max_ln) max_ln = tln;
+	if (!stat (fcmd_arr[i], &st_temp )){
+	    *cmd_out = xstrdup(fcmd_arr[i]);
+	    retbool = TRUE;
+	    break;
+	}
+	i++;
+    }
+
+    if (retbool == FALSE ){
+	err = (char *) xcalloc((80 + (max_ln+2)*i) ,sizeof(char));
+	strcpy(err,"Error: not found -> ");
+	for(j= 0; j < i; j ++){
+	    strcat(err, " ");
+	    strcat(err, fcmd_arr[j]);
+	    strcat(err, " ");
+	}
+	strcat(err, "\n");
+	*err_out = err;
+    }
+
+
+    return retbool;
+}
+
+/***************************************************************
+returns 1 if there is an error, 0 if no error.
+
+***************************************************************/
+
+int match_commands (fcmd, cmd, match, cmd_out, err_out)
+    char *fcmd;
+    char *cmd;
+    krb5_boolean *match;
+    char **cmd_out;
+    char **err_out;
+{
+    char ** fcmd_arr;
+    char * err;
+    char * cmd_temp;
+
+    if(fcmd_resolve(fcmd, &fcmd_arr, &err )== FALSE ){
+	*err_out = err;
+	return 1;
+    }
+
+    if (cmd_single( cmd ) == TRUE){
+	if (!cmd_arr_cmp_postfix(fcmd_arr, cmd)){ /* found */
+
+	    if(find_first_cmd_that_exists( fcmd_arr,&cmd_temp,&err)== TRUE){
+		*match = TRUE;
+		*cmd_out = cmd_temp;
+		return 0;
+	    }else{
+		*err_out = err;
+		return 1;
+	    }
+	}else{
+	    *match = FALSE;
+	    return 0;
+	}
+    }else{
+	if (!cmd_arr_cmp(fcmd_arr, cmd)){  /* found */
+	    *match = TRUE;
+	    *cmd_out = xstrdup(cmd);
+	    return 0;
+	} else{
+	    *match = FALSE;
+	    return 0;
+	}
+    }
+
+}
+
+/*********************************************************
+   get_line - returns a line of any length.  out_line
+	      is set to null if eof.
+*********************************************************/
+
+krb5_error_code get_line (fp, out_line)
+    /* IN */
+    FILE *fp;
+    /* OUT */
+    char **out_line;
+{
+    char * line, *r, *newline , *line_ptr;
+    int chunk_count = 1;
+
+    line = (char *) xcalloc (BUFSIZ, sizeof (char ));
+    line_ptr = line;
+    line[0] = '\0';
+
+    while (( r = fgets(line_ptr, BUFSIZ , fp)) != NULL){
+	newline = strchr(line_ptr, '\n');
+	if (newline) {
+	    *newline = '\0';
+	    break;
+	}
+	else {
+	    chunk_count ++;
+	    if(!( line = (char *) realloc( line,
+					   chunk_count * sizeof(char) * BUFSIZ))){
+		return  ENOMEM;
+	    }
+
+	    line_ptr = line + (BUFSIZ -1) *( chunk_count -1) ;
+	}
+    }
+
+    if ((r == NULL) && (strlen(line) == 0)) {
+	*out_line = NULL;
+    }
+    else{
+	*out_line = line;
+    }
+
+    return 0;
+}
+
+/*******************************************************
+get_first_token -
+Expects a '\0' terminated input line .
+If there are any spaces before the first token, they
+will be returned as part of the first token.
+
+Note: this routine reuses the space pointed to by line
+******************************************************/
+
+char *  get_first_token (line, lnext)
+    char *line;
+    char **lnext;
+{
+
+    char * lptr, * out_ptr;
+
+
+    out_ptr = line;
+    lptr = line;
+    
+    while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;
+    
+    if (strlen(lptr) == 0) return NULL;
+    
+    while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;
+    
+    if (*lptr == '\0'){
+	*lnext = lptr;
+    } else{
+	*lptr = '\0';
+	*lnext = lptr + 1;
+    }
+    
+    return out_ptr;
+}
+/**********************************************************
+get_next_token -
+returns the next token pointed to by *lnext.
+returns NULL if there is no more tokens.
+Note: that this function modifies the stream
+      pointed to by *lnext and does not allocate
+      space for the returned tocken. It also advances
+      lnext to the next tocken.
+**********************************************************/
+
+char *  get_next_token (lnext)
+    char **lnext;
+{
+    char * lptr, * out_ptr;
+
+
+    lptr = *lnext;
+
+    while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;
+
+    if (strlen(lptr) == 0) return NULL;
+
+    out_ptr = lptr;
+
+    while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;
+
+    if (*lptr == '\0'){
+	*lnext = lptr;
+    } else{
+	*lptr = '\0';
+	*lnext = lptr + 1;
+    }
+
+    return out_ptr;
+}
+
+static void auth_cleanup(users_fp, login_fp, princname)
+    FILE *users_fp;
+    FILE *login_fp;
+    char *princname;
+{
+
+    free (princname);
+    if (users_fp)
+	fclose(users_fp);
+    if (login_fp)
+	fclose(login_fp);
+}
+
+void init_auth_names(pw_dir)
+    char *pw_dir;
+{
+    if (strlen (k5login_path) + 2 + strlen (KRB5_LOGIN_NAME) >= MAXPATHLEN) {
+	fprintf (stderr,
+		 "home directory name `%s' too long, can't search for .k5login\n",
+		 pw_dir);
+	exit (1);
+    }
+    if ((strlen(pw_dir) == 1) && (*pw_dir == '/')){
+	sprintf(k5login_path,"%s%s", pw_dir, KRB5_LOGIN_NAME);
+	sprintf(k5users_path,"%s%s", pw_dir, KRB5_USERS_NAME);
+    } else {
+	sprintf(k5login_path,"%s/%s", pw_dir, KRB5_LOGIN_NAME);
+	sprintf(k5users_path,"%s/%s", pw_dir, KRB5_USERS_NAME);
+    }
+}
diff --git a/mechglue/src/clients/ksu/ccache.c b/mechglue/src/clients/ksu/ccache.c
new file mode 100644
index 000000000..5e9c5ec51
--- /dev/null
+++ b/mechglue/src/clients/ksu/ccache.c
@@ -0,0 +1,819 @@
+/* 
+ * Copyright (c) 1994 by the University of Southern California
+ *
+ * EXPORT OF THIS SOFTWARE from the United States of America may
+ *     require a specific license from the United States Government.
+ *     It is the responsibility of any person or organization contemplating
+ *     export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
+ *     this software and its documentation in source and binary forms is
+ *     hereby granted, provided that any documentation or other materials
+ *     related to such distribution or use acknowledge that the software
+ *     was developed by the University of Southern California. 
+ *
+ * DISCLAIMER OF WARRANTY.  THIS SOFTWARE IS PROVIDED "AS IS".  The
+ *     University of Southern California MAKES NO REPRESENTATIONS OR
+ *     WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
+ *     limitation, the University of Southern California MAKES NO
+ *     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+ *     PARTICULAR PURPOSE. The University of Southern
+ *     California shall not be held liable for any liability nor for any
+ *     direct, indirect, or consequential damages with respect to any
+ *     claim by the user or distributor of the ksu software.
+ *
+ * KSU was writen by:  Ari Medvinsky, ari@isi.edu
+ */
+
+#include "ksu.h" 
+#include "adm_proto.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/******************************************************************
+krb5_cache_copy
+
+gets rid of any expired tickets in the secondary cache,
+copies the default cache into the secondary cache, 
+
+************************************************************************/
+
+void show_credential();
+
+/* modifies only the cc_other, the algorithm may look a bit funny,
+   but I had to do it this way, since remove function did not come 
+   with k5 beta 3 release.                                          
+*/
+
+krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag, 
+				  primary_principal, cc_out, stored, target_uid)
+    /* IN */
+    krb5_context context;
+    krb5_ccache cc_def;
+    char *cc_other_tag;
+    krb5_principal primary_principal;
+uid_t target_uid;
+    /* OUT */
+    krb5_ccache *cc_out;
+    krb5_boolean *stored;
+{
+int i=0; 
+krb5_ccache  * cc_other;
+const char * cc_def_name;
+const char * cc_other_name; 
+krb5_error_code retval=0;
+krb5_creds ** cc_def_creds_arr = NULL;
+krb5_creds ** cc_other_creds_arr = NULL;
+struct stat st_temp;
+
+    cc_other = (krb5_ccache *)  xcalloc(1, sizeof (krb5_ccache));  	
+
+    if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){
+               com_err (prog_name, retval, "resolving ccache %s",
+                        cc_other_tag);
+		return retval;
+    }
+
+    cc_def_name = krb5_cc_get_name(context, cc_def);    
+    cc_other_name = krb5_cc_get_name(context, *cc_other);    
+
+    if ( ! stat(cc_def_name, &st_temp)){
+	if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){
+		return retval;
+	}
+    }
+
+    *stored = krb5_find_princ_in_cred_list(context, cc_def_creds_arr,
+					   primary_principal);
+
+#ifdef HAVE_LSTAT
+    if (!lstat( cc_other_name, &st_temp))
+#else /*HAVE_LSTAT*/
+    if (!stat( cc_other_name, &st_temp))
+#endif
+      return EINVAL;
+    
+      if (krb5_seteuid(0)||krb5_seteuid(target_uid)) {
+	return errno;
+      }
+      
+      
+    if ((retval = krb5_cc_initialize(context, *cc_other, primary_principal))){
+	return retval; 
+    }
+
+    retval = krb5_store_all_creds(context, * cc_other, cc_def_creds_arr, 
+				  cc_other_creds_arr); 
+
+    if (cc_def_creds_arr){ 	
+ 	   while (cc_def_creds_arr[i]){
+    		krb5_free_creds(context, cc_def_creds_arr[i]);	
+		i++;
+    	   }
+    }	
+
+    i=0;
+
+    if(cc_other_creds_arr){	
+    	while (cc_other_creds_arr[i]){
+    		krb5_free_creds(context, cc_other_creds_arr[i]);	
+		i++;
+	}
+    }
+
+    *cc_out = *cc_other; 	
+    return retval;	
+}
+
+
+krb5_error_code krb5_store_all_creds(context, cc, creds_def, creds_other)
+    krb5_context context;
+    krb5_ccache cc;
+    krb5_creds **creds_def;
+    krb5_creds **creds_other;
+{
+
+int i = 0; 
+krb5_error_code retval = 0;  
+krb5_creds ** temp_creds= NULL;   
+
+	
+	if ((creds_def == NULL) && (creds_other == NULL)) 
+		return 0;	
+
+	if ((creds_def == NULL) && (creds_other != NULL)) 
+		temp_creds = creds_other; 		
+
+	if ((creds_def != NULL) && (creds_other == NULL)) 
+		temp_creds = creds_def; 		
+
+
+	if (temp_creds){	
+		while(temp_creds[i]){ 
+			if ((retval= krb5_cc_store_cred(context, cc, 
+							temp_creds[i]))){
+				return retval; 
+			}
+			i++;	
+		}
+	}	
+	else { /* both arrays have elements in them */       
+
+		return  KRB5KRB_ERR_GENERIC;
+
+/************	while(creds_other[i]){ 
+			cmp = FALSE;	
+			j = 0;			
+			while(creds_def[j]){ 
+			   cmp = compare_creds(creds_other[i],creds_def[j]);
+
+			   if( cmp == TRUE) break;    		
+
+			   j++; 	
+			}
+			if (cmp == FALSE){
+				if (retval= krb5_cc_store_cred(context, cc,
+							 creds_other[i])){
+						return retval; 
+				}
+			}
+			i ++;
+		}
+
+		i=0;	
+		while(creds_def[i]){ 
+			if (retval= krb5_cc_store_cred(context, cc, 
+						       creds_def[i])){
+				return retval; 
+			}
+			i++;	
+		}
+
+**************/
+	}
+	return 0;
+}
+
+krb5_boolean compare_creds(context, cred1, cred2)
+    krb5_context context;
+    krb5_creds *cred1;
+    krb5_creds *cred2;
+{
+krb5_boolean retval; 
+
+	retval = krb5_principal_compare (context, cred1->client, cred2->client);
+
+	if (retval == TRUE) 
+		retval = krb5_principal_compare (context, cred1->server, 							 cred2->server);
+
+	return retval;
+}
+
+
+
+ 
+krb5_error_code krb5_get_nonexp_tkts(context, cc, creds_array)
+    krb5_context context;
+    krb5_ccache cc;
+    krb5_creds ***creds_array;
+{
+
+krb5_creds creds, temp_tktq, temp_tkt;
+krb5_creds **temp_creds; 
+krb5_error_code retval=0;
+krb5_cc_cursor cur; 
+int count = 0;
+int chunk_count = 1; 
+	
+  if ( ! ( temp_creds = (krb5_creds **) malloc( CHUNK * sizeof(krb5_creds *)))){
+                return errno;
+        }
+
+
+   memset((char *) &temp_tktq, 0, sizeof(temp_tktq));
+   memset((char *) &temp_tkt, 0, sizeof(temp_tkt));
+   memset((char *) &creds, 0, sizeof(creds));
+
+	/* initialize the cursor */    	
+    if ((retval = krb5_cc_start_seq_get(context, cc, &cur))) {
+	return retval; 
+    }
+
+    while (!(retval = krb5_cc_next_cred(context, cc, &cur, &creds))){
+
+	if ((retval = krb5_check_exp(context, creds.times))){
+		if (retval != KRB5KRB_AP_ERR_TKT_EXPIRED){ 
+			return retval;
+		} 
+		if (auth_debug){ 
+			fprintf(stderr,"krb5_ccache_copy: CREDS EXPIRED:\n");  
+			fputs("  Valid starting		Expires		Service principal\n",stdout);
+			show_credential(context, &creds, cc); 
+			fprintf(stderr,"\n");  
+		}
+	}
+	else {   /* these credentials didn't expire */      
+	
+			if ((retval = krb5_copy_creds(context, &creds, 
+						      &temp_creds[count]))){
+			return retval;				
+		}
+		count ++;
+
+	 	if (count == (chunk_count * CHUNK -1)){
+               		  chunk_count ++;
+                	 if (!(temp_creds = (krb5_creds **) realloc(temp_creds,
+                       	       chunk_count * CHUNK * sizeof(krb5_creds *)))){
+                       	       return errno;
+                 	}
+         	}
+	}
+		
+    }
+
+    temp_creds[count] = NULL;	
+    *creds_array   = temp_creds; 	
+
+    if (retval == KRB5_CC_END) {
+		retval = krb5_cc_end_seq_get(context, cc, &cur);
+    }	
+
+    return retval;	
+
+}
+
+
+krb5_error_code krb5_check_exp(context, tkt_time)
+    krb5_context context;
+    krb5_ticket_times tkt_time;
+{
+krb5_error_code retval =0;
+krb5_timestamp currenttime;
+
+	if ((retval = krb5_timeofday (context, ¤ttime))){ 
+		return retval;		
+	}	
+	if (auth_debug){
+		fprintf(stderr,"krb5_check_exp: the krb5_clockskew is %d \n",
+			context->clockskew);
+
+		fprintf(stderr,"krb5_check_exp: currenttime - endtime %d \n",
+	(currenttime - tkt_time.endtime )); 
+		
+	}
+
+	if (currenttime - tkt_time.endtime > context->clockskew){ 
+		retval = KRB5KRB_AP_ERR_TKT_EXPIRED ;
+		return retval;
+	}
+
+	return 0;
+}
+
+
+char *flags_string(cred)
+    krb5_creds *cred;
+{
+    static char buf[32];
+    int i = 0;
+	
+    if (cred->ticket_flags & TKT_FLG_FORWARDABLE)
+        buf[i++] = 'F';
+    if (cred->ticket_flags & TKT_FLG_FORWARDED)
+        buf[i++] = 'f';
+    if (cred->ticket_flags & TKT_FLG_PROXIABLE)
+        buf[i++] = 'P';
+    if (cred->ticket_flags & TKT_FLG_PROXY)
+        buf[i++] = 'p';
+    if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)
+        buf[i++] = 'D';
+    if (cred->ticket_flags & TKT_FLG_POSTDATED)
+        buf[i++] = 'd';
+    if (cred->ticket_flags & TKT_FLG_INVALID)
+        buf[i++] = 'i';
+    if (cred->ticket_flags & TKT_FLG_RENEWABLE)
+        buf[i++] = 'R';
+    if (cred->ticket_flags & TKT_FLG_INITIAL)
+        buf[i++] = 'I';
+    if (cred->ticket_flags & TKT_FLG_HW_AUTH)
+        buf[i++] = 'H';
+    if (cred->ticket_flags & TKT_FLG_PRE_AUTH)
+        buf[i++] = 'A';
+    buf[i] = '\0';
+    return(buf);
+}
+
+void printtime(tv)
+    time_t tv;
+{
+    char fmtbuf[18];
+    char fill;
+    krb5_timestamp tstamp;
+
+    /* XXXX ASSUMES sizeof(krb5_timestamp) >= sizeof(time_t) */
+    (void) localtime((time_t *)&tv);
+    tstamp = tv;
+    fill = ' ';
+    if (!krb5_timestamp_to_sfstring(tstamp,
+				    fmtbuf,
+				    sizeof(fmtbuf),
+				    &fill))
+	printf(fmtbuf);
+}
+
+
+krb5_error_code
+krb5_get_login_princ(luser, princ_list)
+    const char *luser;
+    char ***princ_list;
+{
+    struct stat sbuf;
+    struct passwd *pwd;
+    char pbuf[MAXPATHLEN];
+    FILE *fp;
+    char * linebuf;
+    char *newline;
+    int gobble;
+    char ** buf_out;
+    struct stat st_temp;
+    int count = 0, chunk_count = 1; 
+
+    /* no account => no access */
+
+    if ((pwd = getpwnam(luser)) == NULL) {
+	return 0;
+    }
+    if (strlen(pwd->pw_dir) + sizeof("/.k5login") > MAXPATHLEN) {
+	fprintf (stderr, "home directory path for %s too long\n", luser);
+	exit (1);
+    }
+    (void) strcpy(pbuf, pwd->pw_dir);
+    (void) strcat(pbuf, "/.k5login");
+
+    if (stat(pbuf, &st_temp)) {	 /* not accessible */
+	return 0;
+    }
+
+
+    /* open ~/.k5login */
+    if ((fp = fopen(pbuf, "r")) == NULL) {
+	return 0;
+    }
+    /*
+     * For security reasons, the .k5login file must be owned either by
+     * the user himself, or by root.  Otherwise, don't grant access.
+     */
+    if (fstat(fileno(fp), &sbuf)) {
+	fclose(fp);
+	return 0;
+    }
+    if ((sbuf.st_uid != pwd->pw_uid) && sbuf.st_uid) {
+	fclose(fp);
+	return 0;
+    }
+
+    /* check each line */
+
+
+    if( !(linebuf = (char *) calloc (BUFSIZ, sizeof(char)))) return errno; 
+
+    if (!(buf_out = (char **) malloc( CHUNK * sizeof(char *)))) return errno;
+
+    while ( fgets(linebuf, BUFSIZ, fp) != NULL) {
+	/* null-terminate the input string */
+	linebuf[BUFSIZ-1] = '\0';
+	newline = NULL;
+	/* nuke the newline if it exists */
+	if ((newline = strchr(linebuf, '\n')))
+	    *newline = '\0';
+
+	buf_out[count] = linebuf;
+        count ++;
+
+        if (count == (chunk_count * CHUNK -1)){
+            chunk_count ++;
+            if (!(buf_out = (char **) realloc(buf_out,
+                            chunk_count * CHUNK * sizeof(char *)))){
+                            return errno;
+            }
+        }
+
+	/* clean up the rest of the line if necessary */
+	if (!newline)
+	    while (((gobble = getc(fp)) != EOF) && gobble != '\n');
+
+    	if( !(linebuf = (char *) calloc (BUFSIZ, sizeof(char)))) return errno; 
+    }
+
+    buf_out[count] = NULL;
+    *princ_list = buf_out; 	
+    fclose(fp);
+    return 0;
+}
+
+
+
+void
+show_credential(context, cred, cc)
+    krb5_context context;
+    krb5_creds *cred;
+    krb5_ccache cc;
+{
+    krb5_error_code retval;
+    char *name, *sname, *flags;
+    int	first = 1;
+    krb5_principal princ;
+    char * defname;	
+    int show_flags =1;
+
+    retval = krb5_unparse_name(context, cred->client, &name);
+    if (retval) {
+	com_err(prog_name, retval, "while unparsing client name");
+	return;
+    }
+    retval = krb5_unparse_name(context, cred->server, &sname);
+    if (retval) {
+	com_err(prog_name, retval, "while unparsing server name");
+	free(name);
+	return;
+    }
+
+    if ((retval = krb5_cc_get_principal(context, cc, &princ))) {
+        com_err(prog_name, retval, "while retrieving principal name");
+	return;
+    }
+    if ((retval = krb5_unparse_name(context, princ, &defname))) {
+        com_err(prog_name, retval, "while unparsing principal name");
+	return;
+    }	
+
+    if (!cred->times.starttime)
+	cred->times.starttime = cred->times.authtime;
+
+    printtime(cred->times.starttime);
+    putchar(' '); putchar(' ');
+    printtime(cred->times.endtime);
+    putchar(' '); putchar(' ');
+
+    printf("%s\n", sname);
+
+    if (strcmp(name, defname)) {
+	    printf("\tfor client %s", name);
+	    first = 0;
+    }
+    
+    if (cred->times.renew_till) {
+	if (first)
+		fputs("\t",stdout);
+	else
+		fputs(", ",stdout);
+	fputs("renew until ", stdout);
+        printtime(cred->times.renew_till);
+    }
+    if (show_flags) {
+	flags = flags_string(cred);
+	if (flags && *flags) {
+	    if (first)
+		fputs("\t",stdout);
+	    else
+		fputs(", ",stdout);
+	    printf("Flags: %s", flags);
+	    first = 0;
+        }
+    }
+    putchar('\n');
+    free(name);
+    free(sname);
+}
+
+int gen_sym(){
+	static int i = 0; 
+	i ++;
+	return i;
+}
+
+krb5_error_code krb5_ccache_overwrite(context, ccs, cct, primary_principal)
+    krb5_context context;
+    krb5_ccache ccs;
+    krb5_ccache cct;
+    krb5_principal primary_principal;
+{
+const char * cct_name;
+const char * ccs_name; 
+krb5_error_code retval=0;
+krb5_principal temp_principal;
+krb5_creds ** ccs_creds_arr = NULL;
+int i=0; 
+struct stat st_temp;
+
+    ccs_name = krb5_cc_get_name(context, ccs);    
+    cct_name = krb5_cc_get_name(context, cct);    
+
+    if ( ! stat(ccs_name, &st_temp)){
+	if ((retval = krb5_get_nonexp_tkts(context,  ccs, &ccs_creds_arr))){
+		return retval;
+	}
+    }	
+
+    if ( ! stat(cct_name, &st_temp)){
+	if ((retval = krb5_cc_get_principal(context, cct, &temp_principal))){ 
+		return retval;
+	}
+    }else{
+	temp_principal = primary_principal; 
+    }
+
+    if ((retval = krb5_cc_initialize(context, cct, temp_principal))){
+	return retval; 
+    }
+
+    retval = krb5_store_all_creds(context, cct, ccs_creds_arr, NULL); 
+
+    if (ccs_creds_arr){ 	
+ 	   while (ccs_creds_arr[i]){
+    		krb5_free_creds(context, ccs_creds_arr[i]);	
+		i++;
+    	   }
+    }	
+
+    return retval;	
+}
+
+krb5_error_code krb5_store_some_creds(context, cc, creds_def, creds_other, prst,
+				      stored)
+    krb5_context context;
+    krb5_ccache cc;
+    krb5_creds **creds_def;
+    krb5_creds **creds_other;
+    krb5_principal prst;
+    krb5_boolean *stored;
+{
+
+int i = 0; 
+krb5_error_code retval = 0;  
+krb5_creds ** temp_creds= NULL;   
+krb5_boolean temp_stored = FALSE; 
+
+	
+	if ((creds_def == NULL) && (creds_other == NULL)) 
+		return 0;	
+
+	if ((creds_def == NULL) && (creds_other != NULL)) 
+		temp_creds = creds_other; 		
+
+	if ((creds_def != NULL) && (creds_other == NULL)) 
+		temp_creds = creds_def; 		
+
+
+	if (temp_creds){	
+		while(temp_creds[i]){ 
+			if (krb5_principal_compare(context, 
+						   temp_creds[i]->client,
+						   prst)== TRUE) {
+
+				if ((retval = krb5_cc_store_cred(context, 
+							cc,temp_creds[i]))){
+					return retval; 
+				}
+				temp_stored = TRUE;
+			}
+
+			i++;	
+		}
+	}	
+	else { /* both arrays have elements in them */       
+		return KRB5KRB_ERR_GENERIC;
+	}
+
+*stored = temp_stored;
+return 0;
+}
+/******************************************************************
+krb5_cache_copy_restricted
+
+gets rid of any expired tickets in the secondary cache,
+copies the default cache into the secondary cache,  
+only credentials that are for prst are copied.            
+
+the algorithm may look a bit funny,
+but I had to do it this way, since cc_remove function did not come 
+with k5 beta 3 release.                                          
+************************************************************************/
+
+krb5_error_code krb5_ccache_copy_restricted (context, cc_def, cc_other_tag, 
+					     prst, cc_out, stored, target_uid)
+    krb5_context context;
+    krb5_ccache cc_def;
+    char *cc_other_tag;
+    krb5_principal prst;
+uid_t target_uid;
+    /* OUT */
+    krb5_ccache *cc_out;
+    krb5_boolean *stored;
+{
+
+int i=0; 
+krb5_ccache  * cc_other;
+const char * cc_def_name;
+const char * cc_other_name; 
+krb5_error_code retval=0;
+krb5_creds ** cc_def_creds_arr = NULL;
+krb5_creds ** cc_other_creds_arr = NULL;
+struct stat st_temp;
+
+    cc_other = (krb5_ccache *)  xcalloc(1, sizeof (krb5_ccache));  	
+
+    if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){
+               com_err (prog_name, retval, "resolving ccache %s",
+                        cc_other_tag);
+		return retval;
+    }
+
+    cc_def_name = krb5_cc_get_name(context, cc_def);    
+    cc_other_name = krb5_cc_get_name(context, *cc_other);    
+
+    if ( ! stat(cc_def_name, &st_temp)){
+	if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){
+		return retval;
+	}
+
+    }
+
+#ifdef HAVE_LSTAT
+    if (!lstat( cc_other_name, &st_temp)) {
+#else /*HAVE_LSTAT*/
+    if (!stat( cc_other_name, &st_temp)) {
+#endif
+      return EINVAL;
+    }
+    
+      if (krb5_seteuid(0)||krb5_seteuid(target_uid)) {
+	return errno;
+      }
+      
+    
+    if ((retval = krb5_cc_initialize(context, *cc_other, prst))){
+	return retval; 
+    }
+
+    retval = krb5_store_some_creds(context, * cc_other, 
+			cc_def_creds_arr, cc_other_creds_arr, prst, stored); 
+
+
+
+    if (cc_def_creds_arr){ 	
+ 	   while (cc_def_creds_arr[i]){
+    		krb5_free_creds(context, cc_def_creds_arr[i]);	
+		i++;
+    	   }
+    }	
+
+    i=0;
+
+    if(cc_other_creds_arr){	
+    	while (cc_other_creds_arr[i]){
+    		krb5_free_creds(context, cc_other_creds_arr[i]);	
+		i++;
+	}
+    }
+
+    *cc_out = *cc_other; 	
+    return retval;	
+}
+
+krb5_error_code krb5_ccache_filter (context, cc, prst)
+    krb5_context context;
+    krb5_ccache cc;
+    krb5_principal prst;
+{
+
+int i=0; 
+krb5_error_code retval=0;
+krb5_principal temp_principal;
+krb5_creds ** cc_creds_arr = NULL;
+const char * cc_name;
+krb5_boolean stored;
+struct stat st_temp;
+
+    cc_name = krb5_cc_get_name(context, cc);    
+
+    if ( ! stat(cc_name, &st_temp)){
+
+	if (auth_debug) {  
+	      fprintf(stderr,"putting cache %s through a filter for -z option\n", 		      cc_name);
+	}
+
+	if ((retval = krb5_get_nonexp_tkts(context, cc, &cc_creds_arr))){
+		return retval;
+	}
+
+	if ((retval = krb5_cc_get_principal(context, cc, &temp_principal))){ 
+		return retval;
+	}
+
+    	if ((retval = krb5_cc_initialize(context, cc, temp_principal))){
+		return retval; 
+    	}
+
+	if ((retval = krb5_store_some_creds(context, cc, cc_creds_arr,
+					    NULL, prst, &stored))){ 
+		return retval; 
+    	}
+
+   	if (cc_creds_arr){ 	
+ 	  	 while (cc_creds_arr[i]){
+    			krb5_free_creds(context, cc_creds_arr[i]);	
+			i++;
+    	   	}
+    	}	
+    }
+    return 0;	
+}
+
+krb5_boolean  krb5_find_princ_in_cred_list (context, creds_list, princ)
+    krb5_context context;
+    krb5_creds **creds_list;
+    krb5_principal princ;
+{
+
+int i = 0; 
+krb5_boolean temp_stored = FALSE; 
+
+	if (creds_list){	
+		while(creds_list[i]){ 
+			if (krb5_principal_compare(context, 
+						   creds_list[i]->client,
+						   princ)== TRUE){
+				temp_stored = TRUE;
+				break;
+			}
+
+			i++;	
+		}
+	}	
+
+return temp_stored;
+}
+
+krb5_error_code  krb5_find_princ_in_cache (context, cc, princ, found)
+    krb5_context context;
+    krb5_ccache cc;
+    krb5_principal princ;
+    krb5_boolean *found;
+{
+krb5_error_code retval;
+krb5_creds ** creds_list = NULL;
+const char * cc_name;
+struct stat st_temp;
+
+    cc_name = krb5_cc_get_name(context, cc);    
+
+    if ( ! stat(cc_name, &st_temp)){
+	if ((retval = krb5_get_nonexp_tkts(context, cc, &creds_list))){
+		return retval;
+	}
+    }
+
+    *found = krb5_find_princ_in_cred_list(context, creds_list, princ); 
+return 0;
+}
diff --git a/mechglue/src/clients/ksu/heuristic.c b/mechglue/src/clients/ksu/heuristic.c
new file mode 100644
index 000000000..85b94b5e2
--- /dev/null
+++ b/mechglue/src/clients/ksu/heuristic.c
@@ -0,0 +1,769 @@
+/*
+ * Copyright (c) 1994 by the University of Southern California
+ *
+ * EXPORT OF THIS SOFTWARE from the United States of America may
+ *     require a specific license from the United States Government.
+ *     It is the responsibility of any person or organization contemplating
+ *     export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
+ *     this software and its documentation in source and binary forms is
+ *     hereby granted, provided that any documentation or other materials
+ *     related to such distribution or use acknowledge that the software
+ *     was developed by the University of Southern California.
+ *
+ * DISCLAIMER OF WARRANTY.  THIS SOFTWARE IS PROVIDED "AS IS".  The
+ *     University of Southern California MAKES NO REPRESENTATIONS OR
+ *     WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
+ *     limitation, the University of Southern California MAKES NO
+ *     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+ *     PARTICULAR PURPOSE. The University of Southern
+ *     California shall not be held liable for any liability nor for any
+ *     direct, indirect, or consequential damages with respect to any
+ *     claim by the user or distributor of the ksu software.
+ *
+ * KSU was writen by:  Ari Medvinsky, ari@isi.edu
+ */
+
+#include "ksu.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+/*******************************************************************
+get_all_princ_from_file - retrieves all principal names
+			from file pointed to by fp.
+
+*******************************************************************/
+static void close_time (int, FILE *, int, FILE *);
+static krb5_boolean find_str_in_list (char **, char *);
+
+krb5_error_code get_all_princ_from_file (fp, plist)
+    FILE *fp;
+    char ***plist;
+{
+
+    krb5_error_code retval;
+    char * line, * fprinc, * lp, ** temp_list = NULL;
+    int count = 0, chunk_count = 1;
+
+    if (!(temp_list = (char **) malloc( CHUNK * sizeof(char *))))
+	return errno;
+
+    retval = get_line(fp, &line);
+    if (retval)
+	return retval;	
+
+    while (line){
+	fprinc = get_first_token (line, &lp);
+		
+	if (fprinc ){
+	    temp_list[count] = xstrdup(fprinc);
+	    count ++;
+	}
+
+	if(count == (chunk_count * CHUNK -1)){
+	    chunk_count ++;
+	    if (!(temp_list = (char **) realloc(temp_list,
+						chunk_count * CHUNK * sizeof(char *)))){
+		return errno;
+	    }
+	}
+
+
+	free (line);
+	retval = get_line(fp, &line);
+	if (retval)
+	    return retval;
+    }
+
+    temp_list[count] = NULL;
+
+    *plist = temp_list;
+    return 0;
+}
+
+/*************************************************************
+list_union - combines list1 and list2 into combined_list.
+	     the  space for list1 and list2 is either freed
+	     or used by combined_list.
+**************************************************************/
+
+krb5_error_code list_union(list1, list2, combined_list)
+    char **list1;
+    char **list2;
+    char ***combined_list;
+{
+
+    unsigned int c1 =0, c2 = 0, i=0, j=0;
+    char ** tlist;
+
+    if (! list1){   	
+	*combined_list = list2;   	
+	return 0;
+    }
+
+    if (! list2){   	
+	*combined_list = list1;   	
+	return 0;
+    }
+
+    while (list1[c1]) c1++;
+    while (list2[c2]) c2++;
+	
+    if (!(tlist = (char **) calloc( c1 + c2 + 1, sizeof ( char *))))
+	return errno;
+
+    i = 0;
+    while(list1[i]) {
+	tlist[i] = list1[i];
+	i++;
+    }
+    j = 0;
+    while(list2[j]){
+	if(find_str_in_list(list1, list2[j])==FALSE){   	
+	    tlist[i] = list2[j];
+	    i++;
+	}
+	j++;
+    }
+
+    free (list1); 	
+    free (list2); 	
+	
+    tlist[i]= NULL;
+
+    *combined_list = tlist;
+    return 0;
+}
+
+krb5_error_code
+filter(fp, cmd, k5users_list, k5users_filt_list)
+    FILE *fp;
+    char *cmd;
+    char **k5users_list;
+    char ***k5users_filt_list;
+{
+
+    krb5_error_code retval =0;
+    krb5_boolean found = FALSE;
+    char * out_cmd = NULL;
+    unsigned int i=0, j=0, found_count = 0, k=0;	
+    char ** temp_filt_list;
+
+    *k5users_filt_list = NULL;
+
+    if (! k5users_list){		
+	return 0;
+    }
+
+    while(k5users_list[i]){	
+
+	retval= k5users_lookup(fp, k5users_list[i], cmd, &found, &out_cmd);
+	if (retval)
+	    return retval;
+
+	if (found == FALSE){ 		
+	    free (k5users_list[i]);
+	    k5users_list[i] = NULL;
+	    if (out_cmd) gb_err = out_cmd;
+	} else
+	    found_count ++;	
+
+	i++;
+    }
+
+    if (! (temp_filt_list = (char **) calloc(found_count +1, sizeof (char*))))
+	return errno;
+
+    for(j= 0, k=0; j < i; j++ ) {	
+	if (k5users_list[j]){
+	    temp_filt_list[k] = k5users_list[j]; 		
+	    k++;
+	}
+    }
+
+    temp_filt_list[k] = NULL;
+
+    free (k5users_list);	
+
+    *k5users_filt_list = temp_filt_list;
+    return 0;
+}
+
+krb5_error_code
+get_authorized_princ_names(luser, cmd, princ_list)
+    const char *luser;
+    char *cmd;
+    char ***princ_list;
+{
+
+    struct passwd *pwd;
+    int k5login_flag =0;
+    int k5users_flag =0;
+    FILE * login_fp = NULL , * users_fp = NULL;
+    char **  k5login_list = NULL, ** k5users_list = NULL;
+    char ** k5users_filt_list = NULL;
+    char ** combined_list = NULL;
+    struct stat tb;
+    krb5_error_code retval;	
+
+    *princ_list = NULL; 	
+
+    /* no account => no access */
+
+    if ((pwd = getpwnam(luser)) == NULL)
+	return 0;
+
+    k5login_flag = stat(k5login_path, &tb);
+    k5users_flag = stat(k5users_path, &tb);
+
+    if (!k5login_flag){
+        if ((login_fp = fopen(k5login_path, "r")) == NULL)
+	    return 0;
+        if ( fowner(login_fp, pwd->pw_uid) == FALSE){
+	    close_time(1 /*k5users_flag*/, (FILE *) 0 /*users_fp*/, 
+		       k5login_flag,login_fp);
+	    return 0;
+        }
+    }
+    if (!k5users_flag){
+        if ((users_fp = fopen(k5users_path, "r")) == NULL)
+	    return 0;
+
+        if ( fowner(users_fp, pwd->pw_uid) == FALSE){
+	    close_time(k5users_flag,users_fp, k5login_flag,login_fp);
+	    return 0;
+        }
+
+	retval = get_all_princ_from_file (users_fp, &k5users_list);
+   	if(retval) {
+	    close_time(k5users_flag,users_fp, k5login_flag,login_fp);
+	    return retval;
+   	}
+
+	rewind(users_fp);	
+	
+	retval = filter(users_fp,cmd, k5users_list, &k5users_filt_list);
+	if(retval) {
+	    close_time(k5users_flag,users_fp, k5login_flag, login_fp);
+	    return retval;
+	}
+    }
+ 	
+    if (!k5login_flag){
+	retval = get_all_princ_from_file (login_fp, &k5login_list);
+   	if(retval) {
+	    close_time(k5users_flag,users_fp, k5login_flag,login_fp);
+	    return retval;
+   	}
+    }	
+
+    close_time(k5users_flag,users_fp, k5login_flag, login_fp);
+
+    if (cmd) {
+      retval = list_union(k5login_list, k5users_filt_list, &combined_list);
+      if (retval){
+	  close_time(k5users_flag,users_fp, k5login_flag,login_fp);
+	  return retval;
+      }
+      *princ_list = combined_list;
+      return 0;
+    } else {
+	if (k5users_filt_list != NULL)
+	    free(k5users_filt_list);
+	*princ_list = k5login_list;
+	return 0;
+    }
+}
+
+static void close_time(k5users_flag, users_fp, k5login_flag, login_fp)
+    int k5users_flag;
+    FILE *users_fp;
+    int k5login_flag;
+    FILE *login_fp;
+{
+
+    if (!k5users_flag) fclose(users_fp);
+    if (!k5login_flag) fclose(login_fp);
+
+}
+
+static krb5_boolean find_str_in_list(list , elm)
+    char **list;
+    char *elm;
+{
+
+    int i=0;
+    krb5_boolean found = FALSE;
+
+    if (!list) return found;
+
+    while (list[i] ){
+        if (!strcmp(list[i], elm)){
+	    found = TRUE;
+	    break;
+        }
+        i++;
+    }
+
+    return found;
+}
+
+/**********************************************************************
+returns the principal that is closes to client (can be the the client
+himself). plist contains
+a principal list obtained from .k5login and .k5users file.
+A principal is picked that has the best chance of getting in.
+
+**********************************************************************/
+
+
+krb5_error_code get_closest_principal(context, plist, client, found)
+    krb5_context context;
+    char **plist;
+    krb5_principal *client;
+    krb5_boolean *found;
+{
+    krb5_error_code retval =0;
+    krb5_principal temp_client, best_client = NULL;
+    int i = 0, j=0, cnelem, pnelem;
+    krb5_boolean got_one;
+	
+    *found = FALSE;
+
+    if (! plist ) return 0;
+
+    cnelem = krb5_princ_size(context, *client);
+
+    while(plist[i]){
+
+	retval = krb5_parse_name(context, plist[i], &temp_client);
+	if (retval)
+	    return retval;
+	
+	pnelem = krb5_princ_size(context, temp_client);
+	
+	if ( cnelem > pnelem){	
+	    i++;
+	    continue;
+	}
+	
+	if (krb5_princ_realm(context, *client)->length ==
+	    krb5_princ_realm(context, temp_client)->length
+	    && (!memcmp (krb5_princ_realm(context, *client)->data,
+			 krb5_princ_realm(context, temp_client)->data,
+			 krb5_princ_realm(context, temp_client)->length))){
+	    
+	    got_one = TRUE;
+	    for(j =0; j < cnelem; j ++){
+		krb5_data *p1 =
+		    krb5_princ_component(context, *client, j);
+		krb5_data *p2 =
+		    krb5_princ_component(context, temp_client, j);
+		
+		if (!p1 || !p2 || (p1->length != p2->length) ||
+		    memcmp(p1->data,p2->data,p1->length)){
+		    got_one = FALSE;
+		    break;
+		}
+	    }
+	    if (got_one == TRUE){		
+		if(best_client){
+		    if(krb5_princ_size(context, best_client) >
+		       krb5_princ_size(context, temp_client)){
+			best_client = temp_client;
+		    }
+		}else
+		    best_client = temp_client;
+	    }
+	}
+	i++;
+    }
+    
+    if (best_client) {
+	*found = TRUE;
+	*client = best_client;
+    }
+
+    return 0;
+}
+
+/****************************************************************
+find_either_ticket checks to see whether there is a ticket for the
+   end server or tgt, if neither is there the return FALSE,
+*****************************************************************/
+
+krb5_error_code find_either_ticket (context, cc, client, end_server, found)
+    krb5_context context;
+    krb5_ccache cc;
+    krb5_principal client;
+    krb5_principal end_server;
+    krb5_boolean *found;
+{
+
+    krb5_principal kdc_server;
+    krb5_error_code retval;
+    krb5_boolean temp_found = FALSE;
+    const char * cc_source_name;
+    struct stat st_temp;
+
+    cc_source_name = krb5_cc_get_name(context, cc);
+
+    if ( ! stat(cc_source_name, &st_temp)){
+
+	retval = find_ticket(context, cc, client, end_server, &temp_found);
+	if (retval)
+	    return retval;
+ 	
+	if (temp_found == FALSE){
+	    retval = ksu_tgtname(context,
+				  krb5_princ_realm(context, client),
+				  krb5_princ_realm(context, client),
+				  &kdc_server);
+	    if (retval)
+		return retval;
+
+	    retval = find_ticket(context, cc,client, kdc_server, &temp_found);
+	    if(retval)
+		return retval;
+	}
+	else if (auth_debug)
+	    printf("find_either_ticket: found end server ticket\n");
+    }
+
+    *found = temp_found;
+
+    return 0;
+}
+
+
+krb5_error_code find_ticket (context, cc, client, server, found)
+    krb5_context context;
+    krb5_ccache cc;
+    krb5_principal client;
+    krb5_principal server;
+    krb5_boolean *found;
+{
+
+    krb5_creds tgt, tgtq;
+    krb5_error_code retval;
+	
+    *found = FALSE;
+
+    memset((char *) &tgtq, 0, sizeof(tgtq));
+    memset((char *) &tgt, 0, sizeof(tgt));
+
+    retval= krb5_copy_principal(context,  client, &tgtq.client);
+    if (retval)
+	return retval; 	
+
+    retval= krb5_copy_principal(context,  server, &tgtq.server);
+    if (retval)
+	return retval ; 	
+
+    retval = krb5_cc_retrieve_cred(context, cc, KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
+				   &tgtq, &tgt);
+
+    if (! retval) retval = krb5_check_exp(context, tgt.times);
+
+    if (retval){
+	if ((retval != KRB5_CC_NOTFOUND) &&
+	    (retval != KRB5KRB_AP_ERR_TKT_EXPIRED)){
+	    return retval ;
+	}
+    } else{
+	*found = TRUE;
+	return 0;	
+    }
+
+    free(tgtq.server);
+    free(tgtq.client);
+
+    return 0;
+}
+
+
+
+krb5_error_code find_princ_in_list (context, princ, plist, found)
+    krb5_context context;
+    krb5_principal princ;
+    char **plist;
+    krb5_boolean *found;
+{
+
+    int i=0;
+    char * princname;
+    krb5_error_code retval;
+
+    *found = FALSE;
+
+    if (!plist) return 0;
+
+    retval = krb5_unparse_name(context, princ, &princname);
+    if (retval)
+	return retval;
+
+    while (plist[i] ){
+	if (!strcmp(plist[i], princname)){
+	    *found = TRUE;
+	    break;
+	}
+	i++;
+    }
+
+    return 0;
+
+}
+
+typedef struct princ_info {
+	krb5_principal p;
+	krb5_boolean found;
+}princ_info;
+
+/**********************************************************************
+get_best_princ_for_target -
+
+sets the client name, path_out gets set, if authorization is not possible
+path_out gets set to ...
+
+***********************************************************************/
+
+krb5_error_code get_best_princ_for_target(context, source_uid, target_uid,
+					  source_user, target_user,
+					  cc_source, options, cmd,
+					  hostname, client, path_out)
+    krb5_context context;
+    uid_t source_uid;
+    uid_t target_uid;
+    char *source_user;
+    char *target_user;
+    krb5_ccache cc_source;
+    opt_info *options;
+    char *cmd;
+    char *hostname;
+    krb5_principal *client;
+    int *path_out;
+{
+
+    princ_info princ_trials[10];
+    const char * cc_source_name;
+    krb5_principal cc_def_princ = NULL;
+    krb5_principal temp_client;
+    krb5_principal target_client;
+    krb5_principal source_client;
+    krb5_principal end_server;
+    krb5_error_code retval;
+    char ** aplist =NULL;
+    krb5_boolean found = FALSE;
+    struct stat tb;
+    int count =0;
+    int i;
+    struct stat st_temp;
+
+    *path_out = 0;
+
+    /* -n option was specified client is set we are done */
+    if (options->princ)
+	return 0;
+
+    cc_source_name = krb5_cc_get_name(context, cc_source);
+
+	
+    if (! stat(cc_source_name, &st_temp)) {
+	retval = krb5_cc_get_principal(context, cc_source, &cc_def_princ);
+	if (retval)
+	    return retval;
+    }
+
+    retval=krb5_parse_name(context, target_user, &target_client);
+    if (retval)
+	return retval;
+
+    retval=krb5_parse_name(context, source_user, &source_client);
+    if (retval)
+	return retval;
+
+    if (source_uid == 0){
+	if (target_uid != 0)
+	    *client = target_client; /* this will be used to restrict
+					the cache copty */   	
+	else {
+	    if(cc_def_princ)
+		*client = cc_def_princ;
+	    else
+		*client = target_client;
+	}
+
+	if (auth_debug)
+	    printf(" GET_best_princ_for_target: via source_uid == 0\n");
+
+	return 0;
+    }
+
+    /* from here on, the code is for source_uid !=  0 */
+
+    if (source_uid && (source_uid == target_uid)){
+	if(cc_def_princ)
+	    *client = cc_def_princ;
+	else
+	    *client = target_client;
+	if (auth_debug)
+	    printf("GET_best_princ_for_target: via source_uid == target_uid\n");
+	return 0;
+    }
+
+    /* Become root, then target for looking at .k5login.*/
+    if (krb5_seteuid(0) || krb5_seteuid(target_uid) ) {
+      return errno;
+    }
+    
+    /* if .k5users and .k5login do not exist */  	
+    if (stat(k5login_path, &tb) && stat(k5users_path, &tb) ){
+	*client = target_client;
+
+	if (cmd)
+	    *path_out = NOT_AUTHORIZED;
+
+	if (auth_debug)
+	    printf(" GET_best_princ_for_target: via no auth files path\n");
+
+	return 0;	
+    }else{
+	retval = get_authorized_princ_names(target_user, cmd, &aplist);
+	if (retval)
+	    return retval;
+
+	/* .k5users or .k5login exist, but no authorization */
+	if ((!aplist) || (!aplist[0])) {
+	    *path_out = NOT_AUTHORIZED;
+	    if (auth_debug)
+		printf("GET_best_princ_for_target: via empty auth files path\n");
+	    return 0;	
+	}
+    }
+
+    retval = krb5_sname_to_principal(context, hostname, NULL,
+				     KRB5_NT_SRV_HST, &end_server);
+    if (retval)
+	return retval;
+
+
+    /* first see if default principal of the source cache
+     * can get us in, then the target_user@realm, then the
+     * source_user@realm. If all of them fail, try any
+     * other ticket in the cache. */
+
+    if (cc_def_princ)
+	princ_trials[count ++].p = cc_def_princ;
+    else
+	princ_trials[count ++].p = NULL;
+
+    princ_trials[count ++].p = target_client;
+    princ_trials[count ++].p = source_client;
+
+    for (i= 0; i < count; i ++)
+	princ_trials[i].found = FALSE;
+
+    for (i= 0; i < count; i ++){
+	if(princ_trials[i].p) {	
+	    retval= find_princ_in_list(context, princ_trials[i].p, aplist, 
+				       &found);
+	    if (retval)
+		return retval;	
+	
+	    if (found == TRUE){
+		princ_trials[i].found = TRUE;
+
+		retval = find_either_ticket (context, cc_source, 
+					     princ_trials[i].p,
+					     end_server, &found);
+ 		if (retval)
+		    return retval;
+		if (found == TRUE){
+		    *client = princ_trials[i].p;
+		    if (auth_debug)
+			printf("GET_best_princ_for_target: via ticket file, choice #%d\n", i);
+		    return 0;	
+		}
+	    }	
+	}
+    }
+
+    /* out of preferred principals, see if there is any ticket that will
+       get us in */
+
+    i=0;
+    while (aplist[i]){
+	retval = krb5_parse_name(context, aplist[i], &temp_client);
+ 	if (retval)
+	    return retval;
+
+	retval = find_either_ticket (context, cc_source, temp_client,
+				     end_server, &found);
+	if (retval)
+	    return retval;
+
+	if (found == TRUE){
+	    if (auth_debug)
+		printf("GET_best_princ_for_target: via ticket file, choice: any ok ticket \n" );
+	    *client = temp_client;
+	    return 0;	
+	}
+
+	krb5_free_principal(context, temp_client);
+
+	i++;
+    }
+
+    /* no tickets qualified, select a principal, that may be used
+       for password promting */
+
+
+    for (i=0; i < count; i ++){
+	if (princ_trials[i].found == TRUE){
+	    *client = princ_trials[i].p;
+
+	    if (auth_debug)
+		printf("GET_best_princ_for_target: via prompt passwd list choice #%d \n",i);
+	    return  0;	
+	}
+    }
+
+#ifdef PRINC_LOOK_AHEAD
+    for (i=0; i < count; i ++){
+	if (princ_trials[i].p){
+	    retval=krb5_copy_principal(context, princ_trials[i].p,
+				       &temp_client);
+	    if(retval)
+		return retval; 	
+
+	    /* get the client name that is the closest
+	       to the three princ in trials */
+
+	    retval=get_closest_principal(context, aplist, &temp_client, 
+					 &found);
+	    if(retval)
+		return retval; 	
+
+	    if (found == TRUE){
+		*client = temp_client; 	
+		if (auth_debug)
+		    printf("GET_best_princ_for_target: via prompt passwd list choice: approximation of princ in trials # %d \n",i);
+		return 0;
+	    }
+	    krb5_free_principal(context, temp_client);
+	}
+    }
+
+#endif /* PRINC_LOOK_AHEAD */
+
+
+    if(auth_debug)
+	printf( "GET_best_princ_for_target: out of luck, can't get appropriate default principal\n");
+
+    *path_out = NOT_AUTHORIZED;
+    return 0;
+}
diff --git a/mechglue/src/clients/ksu/krb_auth_su.c b/mechglue/src/clients/ksu/krb_auth_su.c
new file mode 100644
index 000000000..8e1834240
--- /dev/null
+++ b/mechglue/src/clients/ksu/krb_auth_su.c
@@ -0,0 +1,584 @@
+/* 
+ * Copyright (c) 1994 by the University of Southern California
+ *
+ * EXPORT OF THIS SOFTWARE from the United States of America may
+ *     require a specific license from the United States Government.
+ *     It is the responsibility of any person or organization contemplating
+ *     export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
+ *     this software and its documentation in source and binary forms is
+ *     hereby granted, provided that any documentation or other materials
+ *     related to such distribution or use acknowledge that the software
+ *     was developed by the University of Southern California. 
+ *
+ * DISCLAIMER OF WARRANTY.  THIS SOFTWARE IS PROVIDED "AS IS".  The
+ *     University of Southern California MAKES NO REPRESENTATIONS OR
+ *     WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
+ *     limitation, the University of Southern California MAKES NO
+ *     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+ *     PARTICULAR PURPOSE. The University of Southern
+ *     California shall not be held liable for any liability nor for any
+ *     direct, indirect, or consequential damages with respect to any
+ *     claim by the user or distributor of the ksu software.
+ *
+ * KSU was writen by:  Ari Medvinsky, ari@isi.edu
+ */
+
+#include "ksu.h"
+    
+static krb5_error_code krb5_verify_tkt_def
+		  (krb5_context,
+    		   krb5_principal,
+    		   krb5_principal,
+    		   krb5_keyblock *,
+    		   krb5_data *,
+    		   krb5_ticket **);
+
+void plain_dump_principal ();
+
+/*
+ * Try no preauthentication first; then try the encrypted timestamp
+ */
+krb5_preauthtype * preauth_ptr = NULL;
+
+
+
+krb5_boolean krb5_auth_check(context, client_pname, hostname, options,
+			     target_user, cc, path_passwd, target_uid)
+    krb5_context context;
+    krb5_principal client_pname;
+    char *hostname;
+    opt_info *options;
+    char *target_user;
+    uid_t target_uid;
+    krb5_ccache cc;
+    int *path_passwd;
+{
+    krb5_principal client, server;
+    krb5_creds tgt, tgtq, in_creds, * out_creds;
+    krb5_creds **tgts = NULL; /* list of ticket granting tickets */       
+    
+    krb5_ticket * target_tkt; /* decrypted ticket for server */                
+    krb5_error_code retval =0;
+    int got_it = 0; 
+    krb5_boolean zero_password;
+    
+    *path_passwd = 0;
+    memset((char *) &tgtq, 0, sizeof(tgtq)); 
+    memset((char *) &tgt, 0, sizeof(tgt)); 
+    memset((char *) &in_creds, 0, sizeof(krb5_creds)); 
+    
+	
+    if ((retval= krb5_copy_principal(context,  client_pname, &client))){
+	com_err(prog_name, retval,"while copying client principal");   
+	return (FALSE) ; 	
+    }
+    
+    if (auth_debug) {
+	dump_principal(context, "krb5_auth_check: Client principal name", 
+		       client); 
+    }
+    
+    if ((retval = krb5_sname_to_principal(context, hostname, NULL,
+					  KRB5_NT_SRV_HST, &server))){
+	com_err(prog_name, retval, 
+		"while creating server %s principal name", hostname);  
+	krb5_free_principal(context, client);
+	return (FALSE) ; 	
+    }
+    
+    if (auth_debug) {
+	dump_principal(context, "krb5_auth_check: Server principal name", 
+		       server); 
+    }
+    
+    
+    
+    /* check if ticket is already in the cache, if it is
+       then use it.    
+       */
+    if( krb5_fast_auth(context, client, server, target_user, cc) == TRUE){
+	if (auth_debug ){ 	
+	    fprintf (stderr,"Authenticated via fast_auth \n");
+	}
+	return TRUE;
+    }
+    
+    /* check to see if the local tgt is in the cache */         
+    
+    if ((retval= krb5_copy_principal(context,  client, &tgtq.client))){
+	com_err(prog_name, retval,"while copying client principal");   
+	return (FALSE) ; 	
+    }
+    
+    if ((retval = ksu_tgtname(context,  krb5_princ_realm(context, client),
+			       krb5_princ_realm(context, client),
+			       &tgtq.server))){ 		
+	com_err(prog_name, retval, "while creating tgt for local realm");  
+	krb5_free_principal(context, client);
+	krb5_free_principal(context, server);
+	return (FALSE) ; 	
+    }	
+
+    if (auth_debug){ dump_principal(context, "local tgt principal name", tgtq.server ); } 	
+    retval = krb5_cc_retrieve_cred(context, cc,
+				   KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
+				   &tgtq, &tgt); 
+    
+    if (! retval) retval = krb5_check_exp(context, tgt.times);
+    
+    if (retval){	
+	if ((retval != KRB5_CC_NOTFOUND) &&  
+	    (retval != KRB5KRB_AP_ERR_TKT_EXPIRED)){
+	    com_err(prog_name, retval, 
+		    "while retrieving creds from cache");
+	    return (FALSE) ; 	
+	}
+    } else{
+	got_it = 1;	
+    }
+    
+    if (! got_it){
+	
+#ifdef GET_TGT_VIA_PASSWD
+	if (krb5_seteuid(0)||krb5_seteuid(target_uid)) {
+	    com_err("ksu", errno, "while switching to target uid");
+	    return FALSE;
+	}
+	
+
+	fprintf(stderr,"WARNING: Your password may be exposed if you enter it here and are logged \n");
+	fprintf(stderr,"         in remotely using an unsecure (non-encrypted) channel. \n");
+	
+	/*get the ticket granting ticket, via passwd(promt for passwd)*/
+	if (krb5_get_tkt_via_passwd (context, &cc, client, tgtq.server,
+				     options, & zero_password) == FALSE){ 
+	    krb5_seteuid(0);
+	    
+	    return FALSE;
+	}
+	*path_passwd = 1;
+	if (krb5_seteuid(0)) {
+	    com_err("ksu", errno, "while reclaiming root uid");
+	    return FALSE;
+	}
+	
+#else
+	plain_dump_principal (context, client);
+	fprintf(stderr,"does not have any appropriate tickets in the cache.\n");
+	return FALSE;
+	
+#endif /* GET_TGT_VIA_PASSWD */ 
+
+    }
+    
+    if ((retval= krb5_copy_principal(context, client, &in_creds.client))){
+	com_err(prog_name, retval,"while copying client principal");   
+	return (FALSE) ; 	
+    }
+    
+    if ((retval= krb5_copy_principal(context, server, &in_creds.server))){
+	com_err(prog_name, retval,"while copying client principal");   
+	return (FALSE) ; 	
+    }
+    
+    if ((retval = krb5_get_cred_from_kdc(context, cc, &in_creds, 
+					 &out_creds, &tgts))){
+	com_err(prog_name, retval, "while geting credentials from kdc");  
+	return (FALSE);
+    }
+    
+
+    if (auth_debug){ 
+	fprintf(stderr,"krb5_auth_check: got ticket for end server \n"); 
+	dump_principal(context, "out_creds->server", out_creds->server ); 
+    } 	
+    
+    
+    if (tgts){   
+	register int i =0;
+	
+	if (auth_debug){	
+	    fprintf(stderr, "krb5_auth_check: went via multiple realms");
+	}
+	while (tgts[i]){
+	    if ((retval=krb5_cc_store_cred(context,cc,tgts[i]))) {
+		com_err(prog_name, retval,
+			"while storing credentials from cross-realm walk");
+		return (FALSE);
+	    }
+	    i++;
+	}
+	krb5_free_tgt_creds(context, tgts);
+    }
+    
+    retval = krb5_verify_tkt_def(context, client, server, 
+				 &out_creds->keyblock, &out_creds->ticket,
+				 &target_tkt);
+    if (retval) {
+	com_err(prog_name, retval, "while verifying ticket for server");
+	return (FALSE);
+    }
+    
+    if ((retval = krb5_cc_store_cred(context,  cc, out_creds))){
+	com_err(prog_name, retval,
+		"While storing credentials");
+	return (FALSE);
+    }
+
+    return (TRUE);
+}
+
+/* krb5_fast_auth checks if ticket for the end server is already in
+   the cache, if it is, we don't need a tgt */     
+
+krb5_boolean krb5_fast_auth(context, client, server, target_user, cc)
+    krb5_context context;
+    krb5_principal client;
+    krb5_principal server;
+    char *target_user;
+    krb5_ccache cc;
+{
+				 
+    krb5_creds tgt, tgtq;
+    krb5_ticket * target_tkt;                 
+    krb5_error_code retval;
+    
+    memset((char *) &tgtq, 0, sizeof(tgtq)); 
+    memset((char *) &tgt, 0, sizeof(tgt)); 
+    
+    if ((retval= krb5_copy_principal(context, client, &tgtq.client))){
+	com_err(prog_name, retval,"while copying client principal");   
+	return (FALSE) ; 	
+    }
+    
+    if ((retval= krb5_copy_principal(context, server, &tgtq.server))){
+	com_err(prog_name, retval,"while copying client principal");   
+	return (FALSE) ; 	
+    }
+    
+    if ((retval = krb5_cc_retrieve_cred(context, cc,
+					KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
+					&tgtq, &tgt))){ 
+	if (auth_debug)
+	    com_err(prog_name, retval,"While Retrieving credentials"); 
+	return (FALSE) ; 	
+	
+    }
+    
+    if ((retval = krb5_verify_tkt_def(context, client, server, &tgt.keyblock, 
+				      &tgt.ticket, &target_tkt))){
+	com_err(prog_name, retval, "while verifing ticket for server"); 
+	return (FALSE);
+    }
+    
+    return TRUE;
+}
+
+static krb5_error_code 
+krb5_verify_tkt_def(context, client, server, cred_ses_key, 
+		    scr_ticket, clear_ticket)
+    /* IN */
+    krb5_context context;
+    krb5_principal client;
+    krb5_principal server;
+    krb5_keyblock *cred_ses_key;
+    krb5_data *scr_ticket;
+    /* OUT */
+    krb5_ticket **clear_ticket;
+{
+    krb5_keytab keytabid;
+    krb5_enctype enctype;
+    krb5_keytab_entry ktentry;
+    krb5_keyblock *tkt_key = NULL;
+    krb5_ticket * tkt = NULL;
+    krb5_error_code retval =0;
+    krb5_keyblock *	tkt_ses_key;
+    
+    if ((retval = decode_krb5_ticket(scr_ticket, &tkt))){
+	return retval;
+    }
+    
+    if (server && !krb5_principal_compare(context, server, tkt->server)){
+	return KRB5KRB_AP_WRONG_PRINC;
+    }
+    
+    if (auth_debug){ 
+	fprintf(stderr,"krb5_verify_tkt_def: verified target server\n");
+	dump_principal(context, "server", server); 
+	dump_principal(context, "tkt->server", tkt->server); 
+    } 	
+    
+    /* get the default keytab */
+    if ((retval = krb5_kt_default(context, &keytabid))){
+	krb5_free_ticket(context, tkt);	
+	return retval;
+    }
+
+    enctype = tkt->enc_part.enctype;
+    
+    if ((retval = krb5_kt_get_entry(context, keytabid, server,
+				    tkt->enc_part.kvno, enctype, &ktentry))){
+	krb5_free_ticket(context, tkt);	
+	return retval;
+    }
+    
+    krb5_kt_close(context, keytabid);
+    
+    if ((retval = krb5_copy_keyblock(context, &ktentry.key, &tkt_key))){
+	krb5_free_ticket(context, tkt);	
+	krb5_kt_free_entry(context, &ktentry);
+	return retval;
+    }
+    
+    /* decrypt the ticket */  
+    if ((retval = krb5_decrypt_tkt_part(context, tkt_key, tkt))) {
+	krb5_free_ticket(context, tkt);	
+	krb5_kt_free_entry(context, &ktentry);
+	krb5_free_keyblock(context, tkt_key);
+	return(retval);
+    }
+
+    /* Check to make sure ticket hasn't expired */
+    retval = krb5_check_exp(context, tkt->enc_part2->times);
+    if (retval) {
+	if (auth_debug && (retval == KRB5KRB_AP_ERR_TKT_EXPIRED)) {
+	    fprintf(stderr,
+		    "krb5_verify_tkt_def: ticket has expired");
+	}
+	krb5_free_ticket(context, tkt);	
+	krb5_kt_free_entry(context, &ktentry);
+	krb5_free_keyblock(context, tkt_key);
+	return KRB5KRB_AP_ERR_TKT_EXPIRED;
+    }
+    
+    if (!krb5_principal_compare(context, client, tkt->enc_part2->client)) {
+	krb5_free_ticket(context, tkt);	
+	krb5_kt_free_entry(context, &ktentry);
+	krb5_free_keyblock(context, tkt_key);
+	return KRB5KRB_AP_ERR_BADMATCH;
+    }
+    
+    if (auth_debug){ 
+	fprintf(stderr,
+		"krb5_verify_tkt_def: verified client's identity\n");
+	dump_principal(context, "client", client);
+	dump_principal(context, "tkt->enc_part2->client",tkt->enc_part2->client);
+    } 	
+    
+    tkt_ses_key = tkt->enc_part2->session;	
+    
+    if (cred_ses_key->enctype != tkt_ses_key->enctype ||
+	cred_ses_key->length != tkt_ses_key->length ||
+	memcmp((char *)cred_ses_key->contents,
+	       (char *)tkt_ses_key->contents, cred_ses_key->length)) {
+	
+	krb5_free_ticket(context, tkt);	
+	krb5_kt_free_entry(context, &ktentry);
+	krb5_free_keyblock(context, tkt_key);
+	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
+    }
+    
+    if (auth_debug){ 
+	fprintf(stderr,
+		"krb5_verify_tkt_def: session keys match \n");
+    } 	
+    
+    *clear_ticket = tkt; 
+    krb5_kt_free_entry(context, &ktentry);
+    krb5_free_keyblock(context, tkt_key);
+    return 0; 	
+    
+}
+
+
+krb5_boolean krb5_get_tkt_via_passwd (context, ccache, client, server,
+				      options, zero_password)
+    krb5_context context;
+    krb5_ccache *ccache;
+    krb5_principal client;
+    krb5_principal server;
+    opt_info *options;
+    krb5_boolean *zero_password;
+{
+    krb5_error_code code;
+    krb5_creds my_creds;
+    krb5_timestamp now;
+    unsigned int pwsize;
+    char password[255], *client_name, prompt[255];
+
+
+    *zero_password = FALSE;	
+    
+    if ((code = krb5_unparse_name(context, client, &client_name))) {
+        com_err (prog_name, code, "when unparsing name");
+        return (FALSE);
+    }
+
+    memset((char *)&my_creds, 0, sizeof(my_creds));
+    
+    if ((code = krb5_copy_principal(context, client, &my_creds.client))){ 
+        com_err (prog_name, code, "while copying principal");
+	return (FALSE);	
+    }	
+
+    if ((code = krb5_copy_principal(context, server, &my_creds.server))){ 
+        com_err (prog_name, code, "while copying principal");
+	return (FALSE);	
+    }	
+
+    if ((code = krb5_timeofday(context, &now))) {
+	com_err(prog_name, code, "while getting time of day");
+	return (FALSE);	
+    }
+
+    my_creds.times.starttime = 0;	/* start timer when request
+					   gets to KDC */
+    
+    my_creds.times.endtime = now + options->lifetime;
+    if (options->opt & KDC_OPT_RENEWABLE) {
+	my_creds.times.renew_till = now + options->rlife;
+    } else
+	my_creds.times.renew_till = 0;
+
+    if (strlen (client_name) + 80 > sizeof (prompt)) {
+	fprintf (stderr,
+		 "principal name %s too long for internal buffer space\n",
+		 client_name);
+	return FALSE;
+    }
+    (void) sprintf(prompt,"Kerberos password for %s: ", client_name);
+    
+    pwsize = sizeof(password);
+    
+    code = krb5_read_password(context, prompt, 0, password, &pwsize);
+    if (code ) {
+	com_err(prog_name, code, "while reading password for '%s'\n",
+		client_name);
+	memset(password, 0, sizeof(password));
+	return (FALSE); 
+    }
+    
+    if ( pwsize == 0) {
+	fprintf(stderr, "No password given\n");
+	*zero_password = TRUE;
+	memset(password, 0, sizeof(password));
+	return (FALSE); 
+    }
+    
+    code = krb5_get_in_tkt_with_password(context, options->opt, 
+					 0, NULL, preauth_ptr,
+					 password, *ccache, &my_creds, 0);
+    memset(password, 0, sizeof(password));
+    
+    
+    if (code) {
+	if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+	    fprintf (stderr, "%s: Password incorrect\n", prog_name);
+	else
+	    com_err (prog_name, code, "while getting initial credentials");
+	return (FALSE);
+    }
+    return (TRUE);
+}
+
+
+void dump_principal (context, str, p)
+    krb5_context context;
+    char *str;
+    krb5_principal p;
+{
+    char * stname;
+    krb5_error_code retval; 
+
+    if ((retval = krb5_unparse_name(context, p, &stname))) {
+	fprintf(stderr, " %s while unparsing name\n", error_message(retval));
+    }
+    fprintf(stderr, " %s: %s\n", str, stname);
+}
+
+void plain_dump_principal (context, p)
+    krb5_context context;
+    krb5_principal p;
+{    
+    char * stname;
+    krb5_error_code retval; 
+
+    if ((retval = krb5_unparse_name(context, p, &stname)))
+	fprintf(stderr, " %s while unparsing name\n", error_message(retval));
+    fprintf(stderr, "%s ", stname);
+}
+
+
+/**********************************************************************
+returns the principal that is closest to client. plist contains
+a principal list obtained from .k5login and parhaps .k5users file.   
+This routine gets called before getting the password for a tgt.             
+A principal is picked that has the best chance of getting in.          
+
+**********************************************************************/
+
+
+krb5_error_code get_best_principal(context, plist, client)
+    krb5_context context;
+    char **plist;
+    krb5_principal *client;
+{
+    krb5_error_code retval =0; 
+    krb5_principal temp_client, best_client = NULL;
+    
+    int i = 0, nelem;
+    
+    if (! plist ) return 0;
+    
+    nelem = krb5_princ_size(context, *client);
+    
+    while(plist[i]){
+	
+	if ((retval = krb5_parse_name(context, plist[i], &temp_client))){
+	    return retval;
+	}
+	
+	if (krb5_princ_realm(context, *client)->length ==
+	    krb5_princ_realm(context, temp_client)->length  
+	    && (!memcmp (krb5_princ_realm(context, *client)->data,
+			 krb5_princ_realm(context, temp_client)->data,
+			 krb5_princ_realm(context, temp_client)->length))){
+	    
+	    
+	    if (nelem &&
+		krb5_princ_size(context, *client) > 0 &&
+		krb5_princ_size(context, temp_client) > 0) {
+		krb5_data *p1 =
+		    krb5_princ_component(context, *client, 0);
+		krb5_data *p2 = 
+		    krb5_princ_component(context, temp_client, 0);
+		
+		if ((p1->length == p2->length) &&
+		    (!memcmp(p1->data,p2->data,p1->length))){
+		    
+		    if (auth_debug){
+			fprintf(stderr,
+				"get_best_principal: compare with %s\n",
+				plist[i]);
+		    }
+		    
+		    if(best_client){
+			if(krb5_princ_size(context, best_client) >
+			   krb5_princ_size(context, temp_client)){
+			    best_client = temp_client;
+			}
+		    }else{
+			best_client = temp_client;
+		    }
+		}
+	    }
+	    
+	}
+	i++;
+    }
+    
+    if (best_client) *client = best_client;
+    return 0;
+}
diff --git a/mechglue/src/clients/ksu/ksu.M b/mechglue/src/clients/ksu/ksu.M
new file mode 100644
index 000000000..aeceaad30
--- /dev/null
+++ b/mechglue/src/clients/ksu/ksu.M
@@ -0,0 +1,481 @@
+.\" Copyright (c) 1994 by the University of Southern California
+.\"
+.\" EXPORT OF THIS SOFTWARE from the United States of America may
+.\"     require a specific license from the United States Government.
+.\"     It is the responsibility of any person or organization contemplating
+.\"     export to obtain such a license before exporting.
+.\"
+.\" WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
+.\"     this software and its documentation in source and binary forms is
+.\"     hereby granted, provided that any documentation or other materials
+.\"     related to such distribution or use acknowledge that the software
+.\"     was developed by the University of Southern California. 
+.\"
+.\" DISCLAIMER OF WARRANTY.  THIS SOFTWARE IS PROVIDED "AS IS".  The
+.\"     University of Southern California MAKES NO REPRESENTATIONS OR
+.\"     WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
+.\"     limitation, the University of Southern California MAKES NO
+.\"     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+.\"     PARTICULAR PURPOSE. The University of Southern
+.\"     California shall not be held liable for any liability nor for any
+.\"     direct, indirect, or consequential damages with respect to any
+.\"     claim by the user or distributor of the ksu software.
+.\"
+.\" KSU was writen by:  Ari Medvinsky, ari@isi.edu
+.\" "
+.TH KSU 1
+.SH NAME
+ksu \- Kerberized super-user    	
+.SH SYNOPSIS
+.B ksu 
+[
+.I target_user
+] [
+.B \-n
+.I target_principal_name 
+] [
+.B \-c
+.I source_cache_name
+] [
+.B \-k
+] [
+.B \-D
+] [
+.B \-r
+.I time
+] [
+.B \-pf
+] [
+.B \-l 
+.I lifetime
+] [
+.B \-zZ
+] [
+.B \-q
+] [
+.B \-e
+.I command
+[
+.I args ...
+] ] [
+.B \-a 
+[
+.I args ...
+] ] 
+.br
+.SH REQUIREMENTS
+Must have Kerberos version 5 installed to compile ksu.
+Must have a Kerberos version 5 server running to use ksu.
+.br
+.SH DESCRIPTION
+.I ksu
+is a Kerberized version of the su program that has two missions:
+one is to securely change the real and effective user ID to that
+of the target user, and the other is to create a new security context.
+For the sake of clarity, all references to and attributes of
+the user invoking the program will start with 'source' (e.g.
+source user, source cache, etc.).  Likewise, all references
+to and attributes of the target account will start with 'target'.
+.br
+.SH AUTHENTICATION
+To fulfill the first mission, ksu operates in two phases: authentication
+and authorization.  Resolving the target principal name is the
+first step in authentication.  The user
+can either specify his principal name with the
+.B \-n
+option
+(e.g.
+.B \-n
+jqpublic@USC.EDU) or a default principal name will be assigned
+using a heuristic described in the OPTIONS section (see
+.B \-n
+option).
+The target user name must be the first argument to ksu; if not specified
+root is the default.  If '.' is specified then the target user will be
+the source user (e.g. ksu .). 
+If the source user is root or the target user is the source user, no 
+authentication or authorization takes place.  Otherwise, ksu looks
+for an appropriate Kerberos ticket in the source cache.
+.PP
+The ticket can either be for
+the end-server
+or a ticket granting ticket (TGT) for the target principal's realm.  If the
+ticket for the end-server is already in the cache, it's decrypted and
+verified.  If it's not in the cache but the TGT is, the TGT is used to
+obtain the ticket for the end-server.   The end-server ticket is then
+verified.  If neither ticket is in the cache, but ksu is compiled
+with the GET_TGT_VIA_PASSWD define, the user will be prompted
+for a Kerberos password which will then be used to get a TGT.
+If the user is logged in remotely and
+does not have a secure channel, the password may be exposed.
+If neither ticket is in the cache and GET_TGT_VIA_PASSWD is not defined,
+authentication fails.
+.br
+.SH AUTHORIZATION
+This section describes authorization of the source user when ksu
+is invoked without the
+.B \-e
+option.
+For a description of the
+.B \-e
+option, see the OPTIONS section.
+.PP
+Upon successful authentication, ksu checks whether the target principal
+is authorized to access the target account.
+In the target user's home directory, ksu attempts to access
+two authorization files: .k5login and .k5users.  In the .k5login  
+file each line contains the name of a
+principal that is authorized to access the account.
+.TP 12
+For example:
+jqpublic@USC.EDU
+.br
+jqpublic/secure@USC.EDU
+.br
+jqpublic/admin@USC.EDU
+.PP
+The format of .k5users is the same, except the
+principal name may be followed by a list of commands that
+the principal is authorized to execute. (see the
+.B \-e
+option in the OPTIONS section for details).
+.PP
+Thus if the target principal
+name is found in the .k5login file the source user is authorized to access
+the target account. Otherwise ksu looks in the .k5users file.
+If the target principal name is found without any trailing commands
+or followed only by '*' then the source user is authorized.  
+If either .k5login or .k5users exist but an appropriate entry for the target
+principal does not exist then access is denied. If neither
+file exists then the principal will be granted access 
+to the account according to the aname\->lname mapping rules (see
+.IR krb5_anadd(8) 
+for more details).
+Otherwise, authorization fails.
+.br
+.SH EXECUTION OF THE TARGET SHELL
+Upon successful authentication and authorization, ksu
+proceeds in a similar fashion to su.  The environment
+is unmodified with the exception of USER, HOME and SHELL variables.
+If the target user is not root, USER gets set to the target user
+name. Otherwise USER remains unchanged. Both HOME and SHELL are
+set to the target login's default values.
+In addition, the environment variable KRB5CCNAME gets set to the
+name of the target cache.
+The real and effective user ID are changed to that of the
+target user.  The target user's shell is then invoked
+(the shell name is specified in the password file).
+Upon termination of the shell, ksu deletes the target cache (unless
+ksu is invoked with the
+.B \-k option).
+This is implemented by first doing a fork and then an exec, instead
+of just exec, as done by su.
+.br
+.SH CREATING A NEW SECURITY CONTEXT
+.PP
+Ksu can be used to create a new security context for the
+target program (either the target
+shell, or command specified via the -e option).
+The target program inherits a set
+of credentials from the source user.
+By default, this set includes all of the credentials
+in the source cache plus any
+additional credentials obtained during authentication.
+The source user is able to limit the credentials in this set
+by using -z or -Z option.
+-z restricts the copy of tickets from the source cache
+to the target cache to only the tickets where client ==
+the target principal name.  The -Z option
+provides the target user with a fresh target cache
+(no creds in the cache). Note that for security reasons,
+when the source user is root and target user is non-root,
+-z option is the default mode of operation. 
+
+While no authentication takes place if the source user
+is root or is the same as the target user, additional
+tickets can still be obtained for the target cache.
+If -n is specified and no credentials can be copied to the target
+cache,  the  source user is prompted for a Kerberos password
+(unless -Z specified or GET_TGT_VIA_PASSWD is undefined). If
+successful,  a  TGT is obtained from the Kerberos server and
+stored in the target cache.  Otherwise,
+if a password is not provided (user hit return)
+ksu continues  in  a
+normal  mode  of  operation (the target cache will
+not contain the desired TGT).
+If the wrong password is typed in, ksu fails.
+.PP
+\fISide Note:\fP during authentication, only the tickets that could be
+obtained without providing a password are cached in
+in the source cache.
+.SH OPTIONS
+.TP 10
+\fB\-n \fItarget_principal_name
+Specify a Kerberos target principal name.
+Used in authentication and authorization
+phases of ksu.
+
+If ksu is invoked without
+.B \-n,
+a default principal name is
+assigned via the following heuristic:
+
+\fICase 1:\fP source user is non-root.
+.br
+If the target user is the source user the default principal name
+is set to the default principal of the source cache. If the
+cache does not exist then the default principal name is set to
+target_user@local_realm.
+If the source and target users are different and
+neither ~target_user/.k5users
+nor ~target_user/.k5login exist then
+the default principal name is
+target_user_login_name@local_realm. Otherwise,
+starting with the first principal listed below,
+ksu checks if the principal is authorized
+to  access the target account and whether
+there is a legitimate ticket for that principal
+in the source cache. If both conditions are met
+that principal becomes the default target principal,
+otherwise go to the next principal.
+
+a) default principal of the source cache
+.br
+b) target_user@local_realm
+.br
+c) source_user@local_realm
+
+If a-c fails try any principal for which there is
+a ticket in the source cache and that is
+authorized to access the target account.
+If that fails select the first principal that
+is authorized to access the target account from
+the above list.
+If none are authorized and ksu is configured with PRINC_LOOK_AHEAD
+turned on, select the default principal as follows:
+
+For each candidate in the above list,
+select an authorized principal that has
+the same realm name and first part
+of the principal name equal to the prefix of the candidate.
+For example if candidate a) is jqpublic@ISI.EDU and jqpublic/secure@ISI.EDU
+is authorized to access the target account then the default principal
+is set to jqpublic/secure@ISI.EDU.
+
+\fICase 2:\fP source user is root.
+.br
+If the target user is non-root then the
+default principal name is target_user@local_realm.
+Else, if the source cache exists the default
+principal name is set to the default principal
+of the source cache. If the source cache does not
+exist, default principal name is set to
+root@local_realm.
+.TP 10
+\fB\-c \fIsource_cache_name
+Specify source cache name (e.g.
+.B \-c
+FILE:/tmp/my_cache).
+If
+.B \-c
+option is not used then the
+name is obtained from KRB5CCNAME environment variable.
+If KRB5CCNAME is not defined the source cache name
+is set to krb5cc_<source uid>.
+The target cache name is automatically
+set to krb5cc_<target uid>.(gen_sym()),
+where gen_sym generates a new number such that
+the resulting cache does not already exist.
+.br
+For example: krb5cc_1984.2
+.TP 10
+\fB\-k
+Do not delete the target cache upon termination of the
+target shell or a command (
+.B \-e
+command).
+Without
+.B \-k,
+ksu deletes the target cache.
+.TP 10
+\fB\-D
+turn on debug mode.
+.TP 10
+\fITicket granting ticket options: -l lifetime -r time -pf\fP
+The ticket granting ticket options only apply to the
+case where there are no appropriate tickets in
+the cache to authenticate the source user. In this case
+if ksu is configured to prompt users for a
+Kerberos password (GET_TGT_VIA_PASSWD is defined),
+the ticket granting
+ticket options that are specified will be used
+when getting a ticket granting ticket from the Kerberos
+server.
+.TP 10
+\fB\-l \fIlifetime
+option specifies the lifetime to be
+requested for the ticket; if this option is not
+specified, the  default ticket lifetime
+(configured by each site) is used instead.
+.TP 10
+\fB\-r \fItime
+option  specifies  that  the  RENEWABLE  option
+should be requested for the ticket, and specifies
+the desired total lifetime of the ticket.
+.TP 10
+\fB\-p
+option specifies that the PROXIABLE option should  be
+requested for the ticket.
+.TP 10
+\fB\-f
+option specifies that the FORWARDABLE  option  should
+be requested for the ticket.
+.TP 10
+\fB\-z
+restrict the copy of tickets from the source cache
+to the target cache to only the tickets where client ==
+the target principal name. Use the
+.B \-n
+option
+if you want the tickets for other then the default
+principal. Note that the
+.B \-z 
+option is mutually
+exclusive with the -Z option.
+.TP 10
+\fB\-Z
+Don't copy any tickets from the source cache to the
+target cache. Just create a fresh target cache,
+where the default principal name of the cache is
+initialized to the target principal name.  Note that
+.B \-Z
+option is mutually
+exclusive with the -z option.
+.TP 10
+\fB\-q
+suppress the printing of status messages.
+.TP 10
+\fB\-e \fIcommand [args ...]
+ksu proceeds exactly the same as if it was invoked without the
+.B \-e
+option,
+except instead of executing the target shell, ksu executes the
+specified command (Example of usage: ksu bob
+.B \-e
+ls
+.B \-lag).
+
+\fIThe authorization algorithm for -e is as follows:\fP
+
+If the source user is root or source user == target user,
+no authorization takes place and             
+the command is executed.  If source user id != 0, and ~target_user/.k5users
+file does not exist, authorization fails.
+Otherwise, ~target_user/.k5users file must have an
+appropriate entry for target principal
+to get authorized.
+
+\fIThe .k5users file format:\fP
+
+A single principal entry on each line
+that may be followed by a list of commands that
+the principal is authorized to execute.
+A principal name followed by a '*' means
+that the user is authorized to execute
+any command. Thus, in the following example:
+
+jqpublic@USC.EDU ls mail /local/kerberos/klist
+.br
+jqpublic/secure@USC.EDU *
+.br
+jqpublic/admin@USC.EDU
+
+jqpublic@USC.EDU is only authorized to execute ls, mail
+and klist commands. jqpublic/secure@USC.EDU is authorized
+to execute any command. jqpublic/admin@USC.EDU is not
+authorized to execute any command.  Note, that
+jqpublic/admin@USC.EDU is authorized to execute
+the target shell (regular ksu, without the
+.B \-e
+option) but jqpublic@USC.EDU is not.
+
+The commands listed after the principal name must
+be either a full path names or just the program name.
+In the second case, CMD_PATH specifying the location
+of authorized programs must be defined at the
+compilation time of ksu.               
+
+\fIWhich command gets executed ?\fP
+
+If the source user is root or
+the target user is the source user or 
+the user
+is authorized to execute any command ('*' entry)
+then command can be either a full or a relative
+path leading to the target program.
+Otherwise, the user must specify either a full
+path or just the program name.
+.TP 10
+\fB\-a \fIargs
+specify arguments to be passed to the target shell.
+Note: that all flags and parameters following -a
+will be passed to the shell, thus all options
+intended for ksu must precede
+.B \-a.
+The
+.B \-a
+option can be used to simulate the
+.B \-e
+option if used as follows:
+.B \-a
+.B \-c
+[command [arguments]].
+.B \-c
+is interpreted by the c-shell to execute the command.
+.PP
+.SH INSTALLATION INSTRUCTIONS
+ksu can be compiled with the following 4 flags (see the Imakefile):
+.TP 10
+\fIGET_TGT_VIA_PASSWD\fP 
+in case no appropriate tickets are found in the source
+cache, the user will be prompted for a Kerberos
+password.  The password is then used to get a
+ticket granting ticket from the Kerberos server.
+The danger of configuring ksu with this macro is
+if the source user is loged in remotely and does not
+have a secure channel, the password may get exposed.
+.TP 10
+\fIPRINC_LOOK_AHEAD\fP
+during the resolution of the default principal name,
+PRINC_LOOK_AHEAD enables ksu to find principal names          
+in the .k5users file as described in the OPTIONS section
+(see -n option).      
+.TP 10
+\fICMD_PATH\fP
+specifies a list of directories containing programs
+that users are authorized to execute (via .k5users file). 
+.TP 10
+\fIHAS_GETUSERSHELL\fP
+If the source user is non-root, ksu insists that
+the target user's shell to be invoked
+is a "legal shell". getusershell(3) is called to obtain
+the names of "legal shells".  Note that the target user's    
+shell is obtained from the passwd file.
+.TP 10
+SAMPLE CONFIGURATION:
+KSU_OPTS = -DGET_TGT_VIA_PASSWD 
+-DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /usr/ucb /local/bin"
+.TP 10
+PERMISSIONS FOR KSU
+ksu should be owned by root and have the set user id  bit turned on.   
+.TP 10
+END-SERVER ENTRY     
+
+ksu attempts to get a ticket for the end server just as Kerberized
+telnet and rlogin.  Thus, there must be an entry for the server in the
+Kerberos database (e.g. host/nii.isi.edu@ISI.EDU).  The keytab file must
+be in an appropriate location.
+
+.SH SIDE EFFECTS
+ksu deletes all expired tickets from the source cache. 
+.SH AUTHOR OF KSU:	GENNADY (ARI) MEDVINSKY
diff --git a/mechglue/src/clients/ksu/ksu.h b/mechglue/src/clients/ksu/ksu.h
new file mode 100644
index 000000000..7b6bbebbe
--- /dev/null
+++ b/mechglue/src/clients/ksu/ksu.h
@@ -0,0 +1,254 @@
+/* 
+ * Copyright (c) 1994 by the University of Southern California
+ *
+ * EXPORT OF THIS SOFTWARE from the United States of America may
+ *     require a specific license from the United States Government.
+ *     It is the responsibility of any person or organization contemplating
+ *     export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
+ *     this software and its documentation in source and binary forms is
+ *     hereby granted, provided that any documentation or other materials
+ *     related to such distribution or use acknowledge that the software
+ *     was developed by the University of Southern California. 
+ *
+ * DISCLAIMER OF WARRANTY.  THIS SOFTWARE IS PROVIDED "AS IS".  The
+ *     University of Southern California MAKES NO REPRESENTATIONS OR
+ *     WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
+ *     limitation, the University of Southern California MAKES NO
+ *     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+ *     PARTICULAR PURPOSE. The University of Southern
+ *     California shall not be held liable for any liability nor for any
+ *     direct, indirect, or consequential damages with respect to any
+ *     claim by the user or distributor of the ksu software.
+ *
+ * KSU was writen by:  Ari Medvinsky, ari@isi.edu
+ */
+
+#include "k5-int.h"
+#include "k5-util.h"
+#include <stdio.h>
+#include "com_err.h"
+#include <sys/types.h> 
+#include <sys/param.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+/* <stdarg.h> or <varargs.h> is already included by com_err.h.  */
+
+#define NO_TARGET_FILE '.'
+#define SOURCE_USER_LOGIN "."
+
+#define KRB5_DEFAULT_OPTIONS 0
+#define KRB5_DEFAULT_TKT_LIFE 60*60*12 /* 12 hours */
+
+#define KRB5_SECONDARY_CACHE "FILE:/tmp/krb5cc_"
+
+#define KRB5_LOGIN_NAME ".k5login"
+#define KRB5_USERS_NAME ".k5users"
+#define USE_DEFAULT_REALM_NAME "."
+#define PERMIT_ALL_COMMANDS "*" 
+#define KRB5_SEC_BUFFSIZE 80
+#define NOT_AUTHORIZED 1
+
+#define CHUNK 3
+#define CACHE_MODE 0600
+#define MAX_CMD 2048 /* this is temp, should use realloc instead,          
+			as done in most of the code */       
+		      
+
+extern int optind;
+extern char * optarg;
+
+/* globals */
+extern char * prog_name;
+extern int auth_debug;
+extern int quiet;
+extern char k5login_path[MAXPATHLEN];
+extern char k5users_path[MAXPATHLEN];
+extern char * gb_err;
+/***********/
+
+typedef struct opt_info{
+	int opt;
+	krb5_deltat lifetime;
+	krb5_deltat rlife;
+	int princ;
+}opt_info;
+
+/* krb_auth_su.c */
+extern krb5_boolean krb5_auth_check
+        (krb5_context, krb5_principal, char *, opt_info *,
+		   char *, krb5_ccache, int *, uid_t);
+
+extern krb5_boolean krb5_fast_auth
+        (krb5_context, krb5_principal, krb5_principal, char *,
+		   krb5_ccache);
+
+extern krb5_boolean krb5_get_tkt_via_passwd 
+	(krb5_context, krb5_ccache *, krb5_principal,
+		   krb5_principal, opt_info *, krb5_boolean *);
+
+extern void dump_principal 
+	(krb5_context, char *, krb5_principal);
+
+extern void plain_dump_principal 
+	(krb5_context, krb5_principal);
+
+
+extern krb5_error_code krb5_parse_lifetime
+	(char *, long *);
+
+extern krb5_error_code get_best_principal
+	(krb5_context, char **, krb5_principal *);
+
+/* ccache.c */
+extern krb5_error_code krb5_ccache_copy
+	(krb5_context, krb5_ccache, char *, krb5_principal, 
+		   krb5_ccache *, krb5_boolean *, uid_t);
+
+extern krb5_error_code krb5_store_all_creds
+	(krb5_context, krb5_ccache, krb5_creds **, krb5_creds **);
+
+extern krb5_error_code krb5_store_all_creds
+	(krb5_context, krb5_ccache, krb5_creds **, krb5_creds **);
+
+extern krb5_boolean compare_creds
+	(krb5_context, krb5_creds *, krb5_creds *);
+
+extern krb5_error_code krb5_get_nonexp_tkts
+	(krb5_context, krb5_ccache, krb5_creds ***);
+
+extern krb5_error_code krb5_check_exp
+	(krb5_context, krb5_ticket_times);
+
+extern char *flags_string (krb5_creds *);
+
+extern krb5_error_code krb5_get_login_princ
+	(const char *, char ***);
+
+extern void show_credential
+	(krb5_context, krb5_creds *, krb5_ccache);
+
+extern int gen_sym (void);
+
+extern krb5_error_code krb5_ccache_overwrite
+	(krb5_context, krb5_ccache, krb5_ccache, krb5_principal);
+
+extern krb5_error_code krb5_store_some_creds
+	(krb5_context, krb5_ccache, krb5_creds **, krb5_creds **,
+		   krb5_principal, krb5_boolean *);
+
+extern krb5_error_code krb5_ccache_copy_restricted
+	(krb5_context, krb5_ccache, char *, krb5_principal, 
+		   krb5_ccache *, krb5_boolean *, uid_t);
+
+extern krb5_error_code krb5_ccache_refresh
+	(krb5_context, krb5_ccache);
+
+extern krb5_error_code krb5_ccache_filter
+	(krb5_context, krb5_ccache, krb5_principal);
+
+extern krb5_boolean krb5_find_princ_in_cred_list
+	(krb5_context, krb5_creds **, krb5_principal);
+
+extern krb5_error_code krb5_find_princ_in_cache
+	(krb5_context, krb5_ccache, krb5_principal, krb5_boolean *);
+
+extern void printtime (time_t);
+
+/* authorization.c */
+extern krb5_boolean fowner (FILE *, uid_t);
+
+extern krb5_error_code krb5_authorization
+	(krb5_context, krb5_principal, const char *, char *, 
+		   krb5_boolean *, char **);
+
+extern krb5_error_code k5login_lookup (FILE *, char *,
+						 krb5_boolean *);
+
+extern krb5_error_code k5users_lookup 
+	(FILE *, char *, char *, krb5_boolean *, char **);
+
+extern krb5_boolean fcmd_resolve
+	(char *, char ***, char **);
+
+extern krb5_boolean cmd_single (char *);
+
+extern int cmd_arr_cmp_postfix (char **, char *);
+
+extern int cmd_arr_cmp (char **, char *);
+
+extern krb5_boolean find_first_cmd_that_exists 
+	(char **, char **, char **);
+
+extern int match_commands 
+	(char *, char *, krb5_boolean *, char **, char **);
+
+extern krb5_error_code get_line (FILE *, char **);
+
+extern char *  get_first_token (char *, char **);
+
+extern char *  get_next_token (char **);
+
+extern void init_auth_names (char *);
+
+/* main.c */
+extern void usage (void);
+
+extern int standard_shell (char *);
+
+extern krb5_error_code get_params (int *, int, char **, char ***);
+
+extern char *get_dir_of_file (const char *);
+
+/* heuristic.c */
+extern krb5_error_code get_all_princ_from_file (FILE *, char ***);
+
+extern krb5_error_code list_union (char **, char **, char ***);
+
+extern krb5_error_code filter (FILE *, char *, char **, char ***);
+
+extern krb5_error_code get_authorized_princ_names
+	(const char *, char *, char ***);
+
+extern krb5_error_code get_closest_principal 
+	(krb5_context, char **, krb5_principal *, krb5_boolean *);
+
+extern krb5_error_code find_either_ticket 
+	(krb5_context, krb5_ccache, krb5_principal,
+		krb5_principal, krb5_boolean *);
+
+extern krb5_error_code find_ticket 
+	(krb5_context, krb5_ccache, krb5_principal,
+		krb5_principal, krb5_boolean *);
+
+
+extern krb5_error_code find_princ_in_list
+	(krb5_context, krb5_principal, char **, krb5_boolean *);
+
+extern krb5_error_code get_best_princ_for_target
+	(krb5_context, uid_t, uid_t, char *, char *, krb5_ccache, 
+		opt_info *, char *, char *, krb5_principal *, int *);
+
+extern krb5_error_code ksu_tgtname (krb5_context, const krb5_data *,
+					      const krb5_data *, 
+					      krb5_principal *tgtprinc);
+
+#ifndef min
+#define min(a,b) ((a) > (b) ? (b) : (a))
+#endif /* min */
+
+
+extern char *krb5_lname_file;  /* Note: print this out just be sure
+				  that it gets set */   	    
+
+extern void *xmalloc (size_t), 
+    *xrealloc (void *, size_t), 
+    *xcalloc (size_t, size_t);
+extern char *xstrdup (const char *);
+
+#ifndef HAVE_UNSETENV
+void unsetenv (char *);
+#endif
diff --git a/mechglue/src/clients/ksu/main.c b/mechglue/src/clients/ksu/main.c
new file mode 100644
index 000000000..d6b001b79
--- /dev/null
+++ b/mechglue/src/clients/ksu/main.c
@@ -0,0 +1,997 @@
+/* 
+ * Copyright (c) 1994 by the University of Southern California
+ *
+ * EXPORT OF THIS SOFTWARE from the United States of America may
+ *     require a specific license from the United States Government.
+ *     It is the responsibility of any person or organization contemplating
+ *     export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
+ *     this software and its documentation in source and binary forms is
+ *     hereby granted, provided that any documentation or other materials
+ *     related to such distribution or use acknowledge that the software
+ *     was developed by the University of Southern California. 
+ *
+ * DISCLAIMER OF WARRANTY.  THIS SOFTWARE IS PROVIDED "AS IS".  The
+ *     University of Southern California MAKES NO REPRESENTATIONS OR
+ *     WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
+ *     limitation, the University of Southern California MAKES NO
+ *     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+ *     PARTICULAR PURPOSE. The University of Southern
+ *     California shall not be held liable for any liability nor for any
+ *     direct, indirect, or consequential damages with respect to any
+ *     claim by the user or distributor of the ksu software.
+ *
+ * KSU was writen by:  Ari Medvinsky, ari@isi.edu
+ */
+
+#include "ksu.h"
+#include "adm_proto.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <grp.h>
+
+/* globals */
+char * prog_name;
+int auth_debug =0;     
+char k5login_path[MAXPATHLEN];
+char k5users_path[MAXPATHLEN];
+char * gb_err = NULL;
+int quiet = 0;
+/***********/
+
+#define _DEF_CSH "/bin/csh" 
+static int set_env_var (char *, char *);
+static void sweep_up (krb5_context, krb5_ccache);
+static char * ontty (void);
+#ifdef HAVE_STDARG_H
+static void print_status( const char *fmt, ...)
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+     __attribute__ ((__format__ (__printf__, 1, 2)))
+#endif
+     ;
+#else
+static void print_status();
+#endif
+char * get_dir_of_file();     
+
+/* Note -e and -a options are mutually exclusive */
+/* insure the proper specification of target user as well as catching         
+   ill specified arguments to commands */        
+
+void usage (){
+    fprintf(stderr, "Usage: %s [target user] [-n principal] [-c source cachename] [-k] [-D] [-r time] [-pf] [-l lifetime] [-zZ] [-q] [-e command [args... ] ] [-a [args... ] ]\n", prog_name);
+}
+
+/* for Ultrix and friends ... */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+/* These are file static so sweep_up can get to them*/
+static uid_t source_uid, target_uid;
+
+int
+main (argc, argv)
+    int argc;
+    char ** argv;
+{ 
+    int hp =0;
+    int some_rest_copy = 0;	
+    int all_rest_copy = 0;	
+    char *localhostname = NULL;
+    opt_info options;
+    int option=0;
+    int statusp=0;
+    krb5_error_code retval = 0; 
+    krb5_principal client = NULL;
+    krb5_ccache cc_target = NULL;
+    krb5_context ksu_context;
+    char * cc_target_tag = NULL; 
+    char * target_user = NULL;
+    char * source_user;
+    
+    krb5_ccache cc_source = NULL;
+    const char * cc_source_tag = NULL; 
+    uid_t source_gid, target_gid;
+    const char * cc_source_tag_tmp = NULL;
+    char * cc_target_tag_tmp=NULL; 
+    char * cmd = NULL, * exec_cmd = NULL;
+    int errflg = 0;
+    krb5_boolean auth_val; 
+    krb5_boolean authorization_val = FALSE; 
+    int path_passwd = 0;
+    int done =0,i,j;
+    uid_t ruid = getuid ();
+    struct passwd *pwd=NULL,  *target_pwd ;
+    char * shell;
+    char ** params;
+    int keep_target_cache = 0;
+    int child_pid, child_pgrp, ret_pid;
+    extern char * getpass(), *crypt();
+    int pargc;
+    char ** pargv;
+    struct stat  st_temp;
+    krb5_boolean stored = FALSE;
+    krb5_principal  kdc_server;
+    krb5_boolean zero_password;
+    char * dir_of_cc_target;     
+    
+    options.opt = KRB5_DEFAULT_OPTIONS;
+    options.lifetime = KRB5_DEFAULT_TKT_LIFE;
+    options.rlife =0; 
+    options.princ =0;	
+
+    params = (char **) xcalloc (2, sizeof (char *));
+    params[1] = NULL;
+
+
+    unsetenv ("KRB5_CONFIG");
+
+    retval = krb5_init_secure_context(&ksu_context);
+    if (retval) {
+        com_err(argv[0], retval, "while initializing krb5");
+	exit(1);
+    }
+
+    if (strrchr(argv[0], '/'))
+	argv[0] = strrchr(argv[0], '/')+1;
+    prog_name = argv[0];
+    if (strlen (prog_name) > 50) {
+	/* this many chars *after* last / ?? */
+	com_err(prog_name, 0, "program name too long - quitting to avoid triggering system logging bugs");
+	exit (1);
+    }
+
+
+#ifndef LOG_NDELAY
+#define LOG_NDELAY 0
+#endif
+    
+#ifndef LOG_AUTH /* 4.2 syslog */
+    openlog(prog_name, LOG_PID|LOG_NDELAY);
+#else
+    openlog(prog_name, LOG_PID | LOG_NDELAY, LOG_AUTH);
+#endif /* 4.2 syslog */
+    
+      
+    if (( argc == 1) || (argv[1][0] == '-')){
+	target_user = xstrdup("root");
+	pargc = argc;
+	pargv = argv;
+    } else {
+	target_user = xstrdup(argv[1]);
+	pargc = argc -1;
+	
+	if ((pargv =(char **) calloc(pargc +1,sizeof(char *)))==NULL){
+	    com_err(prog_name, errno, "while allocating memory");
+	    exit(1);
+	}
+	
+	pargv[pargc] = NULL;
+	pargv[0] = argv[0];
+	
+	for(i =1; i< pargc; i ++){
+	    pargv[i] = argv[i + 1];
+	}
+    }
+    
+    if (krb5_seteuid (ruid)) {
+	com_err (prog_name, errno, "while setting euid to source user");
+	exit (1);
+    }
+    while(!done && ((option = getopt(pargc, pargv,"n:c:r:a:zZDfpkql:e:")) != -1)){
+	switch (option) {
+	case 'r':
+	    options.opt |= KDC_OPT_RENEWABLE;
+	    if (strlen (optarg) >= 14)
+		optarg = "bad-time";
+	    retval = krb5_string_to_deltat(optarg, &options.rlife);
+	    if (retval != 0 || options.rlife == 0) {
+		fprintf(stderr, "Bad lifetime value (%s hours?)\n", optarg);
+		errflg++;
+	    }
+	    break;
+	case 'a':
+            /* when integrating this remember to pass in pargc, pargv and
+               take care of params argument */
+	    optind --;	
+	    if (auth_debug){printf("Before get_params optind=%d\n", optind);}
+	    
+            if ((retval = get_params( & optind, pargc, pargv, ¶ms))){
+                com_err(prog_name, retval, "when gathering parameters");
+                errflg++;
+            }
+            if(auth_debug){ printf("After get_params optind=%d\n", optind);}
+	    done = 1;
+            break;
+	case 'p':
+	    options.opt |= KDC_OPT_PROXIABLE;
+	    break;
+	case 'f':
+	    options.opt |= KDC_OPT_FORWARDABLE;
+	    break;
+	case 'k':
+	    keep_target_cache =1;
+	    break;
+	case 'q':
+	    quiet =1;
+	    break;
+        case 'l':
+	    if (strlen (optarg) >= 14)
+		optarg = "bad-time";
+	    retval = krb5_string_to_deltat(optarg, &options.lifetime);
+	    if (retval != 0 || options.lifetime == 0) {
+		fprintf(stderr, "Bad lifetime value (%s hours?)\n", optarg);
+		errflg++;
+	    }
+	    break;
+	case 'n': 
+	    if ((retval = krb5_parse_name(ksu_context, optarg, &client))){
+		com_err(prog_name, retval, "when parsing name %s", optarg); 
+		errflg++;
+	    }	
+	    
+    	    options.princ = 1;
+	    
+	    break;
+#ifdef DEBUG
+	case 'D':
+	    auth_debug = 1;	
+	    break;
+#endif
+	case 'z':
+	    some_rest_copy = 1;	
+	    if(all_rest_copy) {  	
+		fprintf(stderr, 
+			"-z option is mutually exclusive with -Z.\n"); 
+		errflg++;
+	    }	
+	    break;	
+	case 'Z':
+	    all_rest_copy = 1;	
+	    if(some_rest_copy) {  	
+		fprintf(stderr, 
+			"-Z option is mutually exclusive with -z.\n"); 
+		errflg++;
+	    } 	
+	    break;	
+	case 'c':
+	    if (cc_source_tag == NULL) {
+		cc_source_tag = xstrdup(optarg);
+		if ( strchr(cc_source_tag, ':')){
+		    cc_source_tag_tmp = strchr(cc_source_tag, ':') + 1;
+		    
+		    if( stat( cc_source_tag_tmp, &st_temp)){
+			com_err (prog_name, errno,
+				 "while looking for credentials file %s",
+				 cc_source_tag_tmp);
+			exit (1);
+		    }
+		}
+		else { 
+		    fprintf(stderr,"malformed credential cache name %s\n",
+			    cc_source_tag); 
+		    errflg++;
+		}
+		
+	    } else {
+		fprintf(stderr, "Only one -c option allowed\n");
+		errflg++;
+	    }
+	    break;
+	case 'e': 
+	    cmd = xstrdup(optarg);
+            if(auth_debug){printf("Before get_params optind=%d\n", optind);}
+            if ((retval = get_params( & optind, pargc, pargv, ¶ms))){
+                com_err(prog_name, retval, "when gathering parameters");
+                errflg++;
+            }
+            if(auth_debug){printf("After get_params optind=%d\n", optind);}
+            done = 1;
+
+            if (auth_debug){
+                fprintf(stderr,"Command to be executed: %s\n", cmd);
+            }
+            break;
+	case '?':
+	default:
+	    errflg++;
+	    break;
+	}
+    }
+
+    if (errflg) {
+	usage();
+	exit(2);
+    }
+
+    if (optind != pargc ){
+        usage();
+        exit(2);
+    }
+
+    if (auth_debug){	
+	for(j=1; params[j] != NULL; j++){
+	    fprintf (stderr,"params[%d]= %s\n", j,params[j]);
+	}
+    }	
+
+    /***********************************/
+    source_user = getlogin(); /*checks for the the login name in /etc/utmp*/
+    
+    /* verify that that the user exists and get his passwd structure */
+    
+    if (source_user == NULL ||(pwd = getpwnam(source_user)) == NULL ||
+	pwd->pw_uid != ruid){
+	pwd = getpwuid(ruid);
+    }
+    
+    if (pwd == NULL) {
+	fprintf(stderr, "ksu: who are you?\n");
+	exit(1);
+    }
+    if (pwd->pw_uid != ruid) {
+	fprintf (stderr, "Your uid doesn't match your passwd entry?!\n");
+	exit (1);
+    }
+    /* Okay, now we have *some* passwd entry that matches the
+       current real uid.  */
+    
+    /* allocate space and copy the usernamane there */        
+    source_user = xstrdup(pwd->pw_name);
+    source_uid = pwd->pw_uid;
+    source_gid = pwd->pw_gid;
+    
+    
+    if (!strcmp(SOURCE_USER_LOGIN, target_user)){
+	target_user = xstrdup (source_user);			
+    }
+    
+    if ((target_pwd = getpwnam(target_user)) == NULL){ 
+	fprintf(stderr, "ksu: unknown login %s\n", target_user); 
+	exit(1);
+    }
+    target_uid = target_pwd->pw_uid;
+    target_gid = target_pwd->pw_gid;
+    
+    init_auth_names(target_pwd->pw_dir);
+    
+    /***********************************/
+    
+    if (cc_source_tag == NULL){
+	cc_source_tag = krb5_cc_default_name(ksu_context);
+	cc_source_tag_tmp = strchr(cc_source_tag, ':');
+	if (cc_source_tag_tmp == 0)
+	    cc_source_tag_tmp = cc_source_tag;
+	else
+	    cc_source_tag_tmp++;
+    }
+    
+    /* get a handle for the cache */      
+    if ((retval = krb5_cc_resolve(ksu_context, cc_source_tag, &cc_source))){
+	com_err(prog_name, retval,"while getting source cache");    
+	exit(1);
+    }
+    
+    if (((retval = krb5_cc_set_flags(ksu_context,  cc_source, 0x0)) != 0)
+	&& (retval != KRB5_FCC_NOFILE)) {
+	    com_err(prog_name, retval, "while opening ccache");
+	    exit(1);
+    }
+    if ((retval = get_best_princ_for_target(ksu_context, source_uid,
+					    target_uid, source_user, 
+					    target_user, cc_source, 
+					    &options, cmd, localhostname, 
+					    &client, &hp))){
+	com_err(prog_name,retval, "while selecting the best principal"); 
+	exit(1);
+    }
+    
+    /* We may be running as either source or target, depending on
+       what happened; become source.*/
+    if ( geteuid() != source_uid) {
+	if (krb5_seteuid(0) || krb5_seteuid(source_uid) ) {
+	    com_err(prog_name, errno, "while returning to source uid after finding best principal");
+	    exit(1);
+	}
+    }
+    
+    if (auth_debug){
+	if (hp){	
+	    fprintf(stderr,
+		    "GET_best_princ_for_target result: NOT AUTHORIZED\n");
+	}else{
+	    fprintf(stderr,
+		    "GET_best_princ_for_target result-best principal ");
+	    plain_dump_principal (ksu_context, client);
+	    fprintf(stderr,"\n");
+	}
+    }
+    
+    if (hp){	
+	if (gb_err) fprintf(stderr, "%s", gb_err);
+	fprintf(stderr,"account %s: authorization failed\n",target_user);
+	exit(1);
+    }
+    
+    if (cc_target_tag == NULL) {
+	
+	cc_target_tag = (char *)xcalloc(KRB5_SEC_BUFFSIZE ,sizeof(char));
+	/* make sure that the new ticket file does not already exist
+	   This is run as source_uid because it is reasonable to
+	   require the source user to have write to where the target
+	   cache will be created.*/
+	
+	do {
+	    sprintf(cc_target_tag, "%s%ld.%d",
+		    KRB5_SECONDARY_CACHE,
+		    (long) target_uid, gen_sym());
+	    cc_target_tag_tmp = strchr(cc_target_tag, ':') + 1;
+	    
+	}while ( !stat ( cc_target_tag_tmp, &st_temp)); 
+    }
+    
+    
+    dir_of_cc_target = get_dir_of_file(cc_target_tag_tmp);
+    
+    if (access(dir_of_cc_target, R_OK | W_OK )){
+	fprintf(stderr,
+		"%s does not have correct permissions for %s\n", 
+		source_user, cc_target_tag); 
+	exit(1); 	
+    }
+    
+    if (auth_debug){	
+	fprintf(stderr, " source cache =  %s\n", cc_source_tag); 
+	fprintf(stderr, " target cache =  %s\n", cc_target_tag); 
+    }
+    
+    /* 
+       Only when proper authentication and authorization
+       takes place, the target user becomes the owner of the cache.         
+       */           
+    
+    /* we continue to run as source uid until
+       the middle of the copy, when becomewe become the target user
+       The cache is owned by the target user.*/
+    
+	
+    /* if root ksu's to a regular user, then      
+       then only the credentials for that particular user 
+       should be copied */            
+    
+    if ((source_uid == 0) && (target_uid != 0)) {
+	
+	if ((retval = krb5_ccache_copy_restricted(ksu_context,  cc_source,
+						  cc_target_tag, client, 
+						  &cc_target, &stored, 
+						  target_uid))){
+	    com_err (prog_name, retval, 
+		     "while copying cache %s to %s",
+		     krb5_cc_get_name(ksu_context, cc_source),cc_target_tag);
+	    exit(1);
+	}
+	
+    } else {
+	if ((retval = krb5_ccache_copy(ksu_context, cc_source, cc_target_tag,
+				       client,&cc_target, &stored, target_uid))) {
+	    com_err (prog_name, retval, 
+		     "while copying cache %s to %s",
+		     krb5_cc_get_name(ksu_context, cc_source),
+		     cc_target_tag);
+	    exit(1);
+	}
+	
+    }
+    
+    /* Become root for authentication*/
+    
+    if (krb5_seteuid(0)) {
+	com_err(prog_name, errno, "while reclaiming root uid");
+	exit(1);
+    }
+    
+    if ((source_uid == 0) || (target_uid == source_uid)){
+#ifdef GET_TGT_VIA_PASSWD
+	if ((!all_rest_copy) && options.princ && (stored == FALSE)){
+	    if ((retval = ksu_tgtname(ksu_context, 
+				       krb5_princ_realm (ksu_context, client),
+				       krb5_princ_realm(ksu_context, client),
+				       &kdc_server))){
+		com_err(prog_name, retval,
+			"while creating tgt for local realm");
+		sweep_up(ksu_context, cc_target);
+		exit(1);
+	    }
+	    
+	    fprintf(stderr,"WARNING: Your password may be exposed if you enter it here and are logged\n");
+	    fprintf(stderr,"         in remotely using an unsecure (non-encrypted) channel.\n");
+	    if (krb5_get_tkt_via_passwd (ksu_context, &cc_target, client,
+					 kdc_server, &options, 
+					 &zero_password) == FALSE){
+		
+		if (zero_password == FALSE){  
+		    fprintf(stderr,"Goodbye\n");
+		    sweep_up(ksu_context, cc_target);
+		    exit(1);
+		}
+		
+		fprintf(stderr,
+			"Could not get a tgt for ");    
+		plain_dump_principal (ksu_context, client);
+		fprintf(stderr, "\n");    
+		
+	    }
+	}
+#endif /* GET_TGT_VIA_PASSWD */
+    }
+    
+    /* if the user is root or same uid then authentication is not neccesary,
+       root gets in automatically */   	
+    
+    if (source_uid && (source_uid != target_uid)) {
+	char * client_name;
+	
+	auth_val = krb5_auth_check(ksu_context, client, localhostname, &options,
+				   target_user,cc_target, &path_passwd, target_uid); 
+	
+	/* if Kerberos authentication failed then exit */     
+	if (auth_val ==FALSE){
+	    fprintf(stderr, "Authentication failed.\n");
+	    syslog(LOG_WARNING,
+		   "'%s %s' authentication failed for %s%s",
+		   prog_name,target_user,source_user,ontty());
+	    sweep_up(ksu_context, cc_target);
+	    exit(1);
+	}
+	
+#if 0
+	/* At best, this avoids a single kdc request
+	   It is hard to implement dealing with file permissions and
+	   is unnecessary.  It is important
+	   to properly handle races in chown if this code is ever re-enabled.
+	   */
+	/* cache the tickets if possible in the source cache */ 
+	if (!path_passwd){ 	
+	    
+	    if ((retval = krb5_ccache_overwrite(ksu_context, cc_target, cc_source,
+						client))){
+		com_err (prog_name, retval,
+			 "while copying cache %s to %s",
+			 krb5_cc_get_name(ksu_context, cc_target),
+			 krb5_cc_get_name(ksu_context, cc_source));
+		sweep_up(ksu_context, cc_target);
+		exit(1);
+	    }
+	    if (chown(cc_source_tag_tmp, source_uid, source_gid)){  
+		com_err(prog_name, errno, 
+			"while changing owner for %s",
+			cc_source_tag_tmp);   
+		exit(1);
+	    }
+	}
+#endif /*0*/
+
+	if ((retval = krb5_unparse_name(ksu_context, client, &client_name))) {
+	    com_err (prog_name, retval, "When unparsing name");
+	    sweep_up(ksu_context, cc_target);
+	    exit(1);
+	}     
+	
+	print_status("Authenticated %s\n", client_name);
+	syslog(LOG_NOTICE,"'%s %s' authenticated %s for %s%s",
+	       prog_name,target_user,client_name,
+	       source_user,ontty());
+	
+	/* Run authorization as target.*/
+	if (krb5_seteuid(target_uid)) {
+	    com_err(prog_name, errno, "while switching to target for authorization check");
+	    sweep_up(ksu_context, cc_target);
+	    exit(1);
+	}
+	
+	if ((retval = krb5_authorization(ksu_context, client,target_user,
+					 cmd, &authorization_val, &exec_cmd))){
+	    com_err(prog_name,retval,"while checking authorization");
+	    krb5_seteuid(0); /*So we have some chance of sweeping up*/
+	    sweep_up(ksu_context, cc_target);
+	    exit(1);
+	}
+	
+	if (krb5_seteuid(0)) {
+	    com_err(prog_name, errno, "while switching back from  target after authorization check");
+	    sweep_up(ksu_context, cc_target);
+	    exit(1);
+	}
+	if (authorization_val == TRUE){
+
+	    if (cmd) {	
+		print_status(
+		    "Account %s: authorization for %s for execution of\n",
+		    target_user, client_name);
+		print_status("               %s successful\n",exec_cmd);
+		syslog(LOG_NOTICE,
+		       "Account %s: authorization for %s for execution of %s successful",
+		       target_user, client_name, exec_cmd);
+		
+	    }else{
+		print_status(
+		    "Account %s: authorization for %s successful\n",
+			  	target_user, client_name);
+		syslog(LOG_NOTICE,
+		       "Account %s: authorization for %s successful",
+		       target_user, client_name);
+	    }
+	}else {
+	    if (cmd){ 	
+		if (exec_cmd){ /* was used to pass back the error msg */
+		    fprintf(stderr, "%s", exec_cmd );
+		    syslog(LOG_WARNING, "%s",exec_cmd);
+		}
+		fprintf(stderr,
+			"Account %s: authorization for %s for execution of %s failed\n",
+			target_user, client_name, cmd );
+		syslog(LOG_WARNING,
+		       "Account %s: authorization for %s for execution of %s failed",
+		       target_user, client_name, cmd );
+		
+	    }else{
+		fprintf(stderr,
+			"Account %s: authorization of %s failed\n",
+			target_user, client_name);
+		syslog(LOG_WARNING,
+		       "Account %s: authorization of %s failed",
+		       target_user, client_name);
+		
+	    }
+	    
+	    sweep_up(ksu_context, cc_target);
+	    exit(1);
+	}
+    }
+    
+    if( some_rest_copy){ 
+	if ((retval = krb5_ccache_filter(ksu_context, cc_target, client))){ 	
+	    com_err(prog_name,retval,"while calling cc_filter");
+	    sweep_up(ksu_context, cc_target);
+	    exit(1);
+	}
+    }
+    
+    if (all_rest_copy){
+	if ((retval = krb5_cc_initialize(ksu_context, cc_target, client))){  
+	    com_err(prog_name, retval,
+		    "while erasing target cache");    
+	    exit(1);
+	}
+	
+    }
+    
+    /* get the shell of the user, this will be the shell used by su */      
+    target_pwd = getpwnam(target_user);
+    
+    if (target_pwd->pw_shell)
+	shell = xstrdup(target_pwd->pw_shell);
+    else {
+	shell = _DEF_CSH;  /* default is cshell */   
+    }
+    
+#ifdef HAVE_GETUSERSHELL
+    
+    /* insist that the target login uses a standard shell (root is omited) */ 
+    
+    if (!standard_shell(target_pwd->pw_shell) && source_uid) {
+	fprintf(stderr, "ksu: permission denied (shell).\n");
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    }
+#endif /* HAVE_GETUSERSHELL */
+    
+    if (target_pwd->pw_uid){
+	
+	if(set_env_var("USER", target_pwd->pw_name)){
+	    fprintf(stderr,"ksu: couldn't set environment variable USER\n");
+	    sweep_up(ksu_context, cc_target);
+	    exit(1);
+	} 			
+    }	
+    
+    if(set_env_var( "HOME", target_pwd->pw_dir)){
+	fprintf(stderr,"ksu: couldn't set environment variable USER\n");
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    } 			
+    
+    if(set_env_var( "SHELL", shell)){
+	fprintf(stderr,"ksu: couldn't set environment variable USER\n");
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    } 			
+    
+    /* set the cc env name to target */         	
+    
+    if(set_env_var( KRB5_ENV_CCNAME, cc_target_tag)){
+	fprintf(stderr,"ksu: couldn't set environment variable %s\n",
+		KRB5_ENV_CCNAME);
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    } 			
+    
+    /* set permissions */
+    if (setgid(target_pwd->pw_gid) < 0) {
+	perror("ksu: setgid");
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    }
+    
+    
+    if (initgroups(target_user, target_pwd->pw_gid)) {
+	fprintf(stderr, "ksu: initgroups failed.\n");
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    }
+    
+    if ( ! strcmp(target_user, source_user)){ 			
+	print_status("Leaving uid as %s (%ld)\n",
+		     target_user, (long) target_pwd->pw_uid); 
+    }else{
+	print_status("Changing uid to %s (%ld)\n", 
+		     target_user, (long) target_pwd->pw_uid); 
+    }
+    
+#ifdef	HAVE_SETLUID
+    /*
+     * If we're on a system which keeps track of login uids, then
+     * set the login uid. If this fails this opens up a problem on DEC OSF
+     * with C2 enabled.
+     */
+    if (setluid((uid_t) pwd->pw_uid) < 0) {
+	perror("setluid");
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    }
+#endif	/* HAVE_SETLUID */
+    
+    if (setuid(target_pwd->pw_uid) < 0) {
+	perror("ksu: setuid");
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    }   
+    
+    if (access( cc_target_tag_tmp, R_OK | W_OK )){
+	com_err(prog_name, errno,
+		"%s does not have correct permissions for %s, %s aborted",
+		target_user, cc_target_tag_tmp, prog_name);
+	exit(1);
+    }
+    
+    if ( cc_source)
+	krb5_cc_close(ksu_context, cc_source);
+    
+    if (cmd){
+	if ((source_uid == 0) || (source_uid == target_uid )){
+	    exec_cmd = cmd;
+	}
+	
+	if( !exec_cmd){ 
+	    fprintf(stderr,
+		    "Internal error: command %s did not get resolved\n",cmd);
+	    exit(1);	
+	}
+	
+	params[0] = exec_cmd;
+    }
+    else{
+	params[0] = shell;
+    }
+    
+    if (auth_debug){		
+	fprintf(stderr, "program to be execed %s\n",params[0]);
+    }
+    
+    if( keep_target_cache ) {
+	execv(params[0], params);
+	com_err(prog_name, errno, "while trying to execv %s",
+		params[0]);
+	sweep_up(ksu_context, cc_target);
+	exit(1);
+    }else{
+	statusp = 1;
+	switch ((child_pid = fork())) {
+	default:
+	    if (auth_debug){
+	 	printf(" The child pid is %ld\n", (long) child_pid);
+        	printf(" The parent pid is %ld\n", (long) getpid());
+	    }
+            while ((ret_pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) {
+		if (WIFSTOPPED(statusp)) {
+		    child_pgrp = tcgetpgrp(1);
+		    kill(getpid(), SIGSTOP);
+		    tcsetpgrp(1, child_pgrp);
+		    kill(child_pid, SIGCONT); 
+		    statusp = 1;
+		    continue;
+		}
+		break;
+            }
+	    if (auth_debug){
+		printf("The exit status of the child is %d\n", statusp); 
+	    }
+	    if (ret_pid == -1) {
+	    	com_err(prog_name, errno, "while calling waitpid");
+	    }
+	    sweep_up(ksu_context, cc_target);
+	    exit (statusp);
+	case -1:
+	    com_err(prog_name, errno, "while trying to fork.");
+	    sweep_up(ksu_context, cc_target);
+	    exit (1);
+	case 0:
+	    execv(params[0], params);
+	    com_err(prog_name, errno, "while trying to execv %s", params[0]);
+	    exit (1);
+	}
+    }
+}
+
+#ifdef HAVE_GETUSERSHELL
+
+int standard_shell(sh)
+char *sh;
+{
+    register char *cp;
+    char *getusershell();
+    
+    while ((cp = getusershell()) != NULL)
+	if (!strcmp(cp, sh))
+	    return (1);
+    return (0);    
+}
+						  
+#endif /* HAVE_GETUSERSHELL */
+
+static char * ontty()
+{
+    char *p, *ttyname();
+    static char buf[MAXPATHLEN + 4];
+    
+    buf[0] = 0;
+    if ((p = ttyname(STDERR_FILENO))) {
+	if (strlen (p) > MAXPATHLEN) {
+	    fprintf (stderr, "terminal name %s too long\n", p);
+	    exit (1);
+	}
+	sprintf(buf, " on %s", p);
+    }
+    return (buf);
+}
+
+
+static int set_env_var(name, value)
+    char *name;
+    char *value;
+{
+    char * env_var_buf;
+    
+    /* allocate extra two spaces, one for the = and one for the \0 */  
+    env_var_buf = (char *) xcalloc(2 + strlen(name) + strlen(value),
+				   sizeof(char)); 
+    
+    sprintf(env_var_buf,"%s=%s",name, value);  
+    return putenv(env_var_buf);
+    
+}
+
+static void sweep_up(context, cc)
+    krb5_context context;
+    krb5_ccache cc;
+{
+    krb5_error_code retval; 
+    const char * cc_name;
+    struct stat  st_temp;
+
+    krb5_seteuid(0);
+    krb5_seteuid(target_uid);
+    
+    cc_name = krb5_cc_get_name(context, cc);
+    if ( ! stat(cc_name, &st_temp)){
+	if ((retval = krb5_cc_destroy(context, cc))){
+	    com_err(prog_name, retval, 
+		    "while destroying cache");   
+	}
+    }
+}
+
+/*****************************************************************
+get_params is to be called for the -a option or -e option to
+           collect all params passed in for the shell or for
+           cmd.  An aray is returned containing all params.
+           optindex is incremented accordingly and the first
+           element in the returned array is reserved for the
+           name of the command to be executed or the name of the
+           shell.
+*****************************************************************/
+
+krb5_error_code
+get_params(optindex, pargc, pargv, params)
+    int *optindex;
+    int pargc;
+    char **pargv;
+    char ***params;
+{
+
+    int i,j;
+    char ** ret_params;
+    int size = pargc - *optindex + 2;
+    
+    if ((ret_params = (char **) calloc(size, sizeof (char *)))== NULL ){
+	return errno;
+    }
+    
+    for (i = *optindex, j=1; i < pargc; i++,j++){
+	ret_params[j] = pargv[i];
+	*optindex = *optindex + 1;
+    }
+    
+    ret_params[size-1] = NULL;
+    *params = ret_params;
+    return 0;
+}
+
+static
+#ifdef HAVE_STDARG_H
+void print_status( const char *fmt, ...)
+#else
+void print_status (va_alist)
+     va_dcl
+#endif
+{
+    va_list ap;
+#ifndef HAVE_STDARG_H
+    char *fmt;
+    va_start (ap);
+    fmt = va_arg (ap, char*);
+    if (!quiet) vfprintf(stderr, fmt, ap);
+    va_end(ap);
+#else
+    if (! quiet){
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+    }
+#endif
+}
+
+
+char *get_dir_of_file(path)
+    const char *path;
+{
+    char * temp_path;      
+    char * ptr;
+
+    temp_path =  xstrdup(path);
+    
+    if ((ptr = strrchr( temp_path, '/'))) {
+	*ptr = '\0';  
+    } else {
+	free (temp_path);
+	temp_path = xmalloc(MAXPATHLEN);
+	if (temp_path)
+	    getcwd(temp_path, MAXPATHLEN);
+    }
+    return temp_path;  
+}
+
+krb5_error_code
+ksu_tgtname(context, server, client, tgtprinc)
+    krb5_context context;
+    const krb5_data *server, *client;
+    krb5_principal *tgtprinc;
+{
+    return krb5_build_principal_ext(context, tgtprinc, client->length, client->data,
+				    KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, 
+				    server->length, server->data,
+				    0);
+}
diff --git a/mechglue/src/clients/ksu/setenv.c b/mechglue/src/clients/ksu/setenv.c
new file mode 100644
index 000000000..286721446
--- /dev/null
+++ b/mechglue/src/clients/ksu/setenv.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)setenv.c	5.2 (Berkeley) 6/27/88 */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static char *_findenv(char *, int *);
+
+#ifndef HAVE_SETENV
+extern int setenv(char *, char *, int);
+#endif
+#ifndef HAVE_UNSETENV
+extern void unsetenv(char *);
+#endif
+
+/*
+ * setenv --
+ *	Set the value of the environmental variable "name" to be
+ *	"value".  If rewrite is set, replace any current value.
+ */
+#ifndef HAVE_SETENV
+int
+setenv(name, value, rewrite)
+	register char *name, *value;
+	int rewrite;
+{
+	extern char **environ;
+	static int alloced;			/* if allocated space before */
+	register char *C;
+	int l_value, offset;
+
+	if (*value == '=')			/* no `=' in value */
+		++value;
+	l_value = strlen(value);
+	if ((C = _findenv(name, &offset))) {	/* find if already exists */
+		if (!rewrite)
+			return(0);
+		if (strlen(C) >= l_value) {	/* old larger; copy over */
+			while ((*C++ = *value++));
+			return(0);
+		}
+	}
+	else {					/* create new slot */
+		register int	cnt;
+		register char	**P;
+
+		for (P = environ, cnt = 0; *P; ++P, ++cnt);
+		if (alloced) {			/* just increase size */
+			environ = (char **)realloc((char *)environ,
+			    (u_int)(sizeof(char *) * (cnt + 2)));
+			if (!environ)
+				return(-1);
+		}
+		else {				/* get new space */
+			alloced = 1;		/* copy old entries into it */
+			P = (char **)malloc((u_int)(sizeof(char *) *
+			    (cnt + 2)));
+			if (!P)
+				return(-1);
+			memcpy(P, environ, cnt * sizeof(char *));
+			environ = P;
+		}
+		environ[cnt + 1] = NULL;
+		offset = cnt;
+	}
+	for (C = name; *C && *C != '='; ++C);	/* no `=' in name */
+	if (!(environ[offset] =			/* name + `=' + value */
+	    malloc((u_int)((int)(C - name) + l_value + 2))))
+		return(-1);
+	for (C = environ[offset]; (*C = *name++) &&( *C != '='); ++C);
+	for (*C++ = '='; (*C++ = *value++) != NULL;);
+	return(0);
+}
+#endif
+
+/*
+ * unsetenv(name) --
+ *	Delete environmental variable "name".
+ */
+#ifndef HAVE_UNSETENV
+void
+unsetenv(name)
+	char	*name;
+{
+	extern	char	**environ;
+	register char	**P;
+	int	offset;
+
+	while (_findenv(name, &offset))		/* if set multiple times */
+		for (P = &environ[offset];; ++P)
+			if (!(*P = *(P + 1)))
+				break;
+}
+#endif
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)getenv.c	5.5 (Berkeley) 6/27/88 */
+
+/*
+ * getenv --
+ *	Returns ptr to value associated with name, if any, else NULL.
+ */
+#ifndef HAVE_GETENV
+char *
+getenv(name)
+	char *name;
+{
+	int offset;
+
+	return(_findenv(name, &offset));
+}
+#endif
+
+/*
+ * _findenv --
+ *	Returns pointer to value associated with name, if any, else NULL.
+ *	Sets offset to be the offset of the name/value combination in the
+ *	environmental array, for use by setenv(3) and unsetenv(3).
+ *	Explicitly removes '=' in argument name.
+ *
+ */
+static char *
+_findenv(name, offset)
+	register char *name;
+	int *offset;
+{
+	extern char **environ;
+	register int len;
+	register char **P, *C;
+
+	for (C = name, len = 0; *C && *C != '='; ++C, ++len);
+	for (P = environ; *P; ++P)
+		if (!strncmp(*P, name, len))
+			if (*(C = *P + len) == '=') {
+				*offset = P - environ;
+				return(++C);
+			}
+	return(NULL);
+}
diff --git a/mechglue/src/clients/ksu/xmalloc.c b/mechglue/src/clients/ksu/xmalloc.c
new file mode 100644
index 000000000..425b44f0e
--- /dev/null
+++ b/mechglue/src/clients/ksu/xmalloc.c
@@ -0,0 +1,68 @@
+/*
+ * clients/ksu/xmalloc.c
+ *
+ * Copyright 1999 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Perform simple allocation/copy operations, exiting on failure.
+ */
+
+#include "ksu.h"
+
+void *xmalloc (size_t sz)
+{
+    void *ret = malloc (sz);
+    if (ret == 0 && sz != 0) {
+	perror (prog_name);
+	exit (1);
+    }
+    return ret;
+}
+
+void *xrealloc (void *old, size_t newsz)
+{
+    void *ret = realloc (old, newsz);
+    if (ret == 0 && newsz != 0) {
+	perror (prog_name);
+	exit (1);
+    }
+    return ret;
+}
+
+void *xcalloc (size_t nelts, size_t eltsz)
+{
+    void *ret = calloc (nelts, eltsz);
+    if (ret == 0 && nelts != 0 && eltsz != 0) {
+	perror (prog_name);
+	exit (1);
+    }
+    return ret;
+}
+
+char *xstrdup (const char *src)
+{
+    size_t len = strlen (src) + 1;
+    char *dst = xmalloc (len);
+    memcpy (dst, src, len);
+    return dst;
+}
diff --git a/mechglue/src/clients/kvno/ChangeLog b/mechglue/src/clients/kvno/ChangeLog
new file mode 100644
index 000000000..0a81427ff
--- /dev/null
+++ b/mechglue/src/clients/kvno/ChangeLog
@@ -0,0 +1,89 @@
+2004-08-31  Tom Yu  <tlyu@mit.edu>
+
+	* kvno.M: Update usage.
+
+	* kvno.c (xusage): Update usage message.
+
+2004-08-20  Jeffrey Altman <jaltman@mit.edu>
+
+        * kvno.c: Add -c ccache command line option
+                  use krb5_free_unparsed_name() instead of free()
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac): Target deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-15  Tom Yu  <tlyu@mit.edu>
+
+	* kvno.c (do_v4_kvno): Initialize name, inst, realm to empty
+	strings.
+
+2002-07-30  Ezra Peisach  <epeisach@bu.edu>
+
+	* kvno.c (do_v4_kvno): If not compiling with v4 support, xusage
+	does not take any arguments.
+
+2002-07-29  Jen Selby   <jenselby@mit.edu>
+
+	* kvno.M: added documentation of the "-q" and "-h" options.
+
+2002-07-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* kvno.c: Include stdlib.h.
+	(xusage): Renamed from usage; all callers changed.
+
+2002-07-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* kvno.c (do_v5_kvno): New function, split out from main.
+	(do_v4_kvno): New function.
+	(prog, quiet): New global variables.
+	(main): Parse new option '-4' and call do_v5_kvno or do_v4_kvno.
+	(usage): List new option.
+	* kvno.M: Document v4 aspects.
+	* Makefile.in (kvno): Use krb4 compat libraries.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* kvno.c: Include unistd.h (if present) for getopt() prototype. 
+
+2000-08-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* kvno.c (main): Compiler warning fixes - declare usage as static, and 
+	break out assignments within conditionals.
+
+2000-02-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kvno.c (main): Use krb5_decode_ticket() instead of
+	decode_krb5_ticket(), which is not part of API.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kvno.c (main): Use krb5_free_unparsed_name() isntead of free().
+	Free krb5 context when done.
+
+	* Makefile.in: Build kvno under Windows.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* kvno.c, kvno.M: Create a new application.
+
diff --git a/mechglue/src/clients/kvno/Makefile.in b/mechglue/src/clients/kvno/Makefile.in
new file mode 100644
index 000000000..69c92bd2a
--- /dev/null
+++ b/mechglue/src/clients/kvno/Makefile.in
@@ -0,0 +1,27 @@
+thisconfigdir=./..
+myfulldir=clients/kvno
+mydir=kvno
+BUILDTOP=$(REL)..$(S)..
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all-unix:: kvno
+all-windows:: $(OUTPRE)kvno.exe
+
+kvno: kvno.o $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o $@ kvno.o $(KRB4COMPAT_LIBS)
+
+$(OUTPRE)kvno.exe: $(OUTPRE)kvno.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.obj $(KLIB) $(CLIB)
+	link $(EXE_LINKOPTS) /out:$@ $**
+
+clean-unix::
+	$(RM) kvno.o kvno
+
+install-unix::
+	for f in kvno; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(CLIENT_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		$(DESTDIR)$(CLIENT_MANDIR)/`echo $$f|sed '$(transform)'`.1; \
+	done
diff --git a/mechglue/src/clients/kvno/kvno.M b/mechglue/src/clients/kvno/kvno.M
new file mode 100644
index 000000000..864f75ec2
--- /dev/null
+++ b/mechglue/src/clients/kvno/kvno.M
@@ -0,0 +1,76 @@
+.\" Copyright (C) 1998 by the FundsXpress, INC.
+.\" 
+.\" All rights reserved.
+.\" 
+.\" Export of this software from the United States of America may require
+.\" a specific license from the United States Government.  It is the
+.\" responsibility of any person or organization contemplating export to
+.\" obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of FundsXpress. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  FundsXpress makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" clients/kvnol/kvno.M
+.\" "
+.TH KVNO 1
+.SH NAME
+kvno \- print key version numbers of Kerberos principals
+.SH SYNOPSIS
+\fBkvno\fP [\fB\-q\fP] [\fB\-h\fP] [\fB\-4\fP\ |\ [\fB-c ccache\fP]\ [\fB\-e etype\fP]]
+\fBservice1\fP \fBservice2\fP \fB...\fP
+.br
+.SH DESCRIPTION
+.I Kvno
+acquires a service ticket for the specified Kerberos principals and
+prints out the key version numbers of each.  
+.SH OPTIONS
+.TP
+.B \-c ccache
+specifies the name of a credentials cache to use (if not the default)
+.TP
+.B \-e etype
+specifies the enctype which will be requested for the session key of
+all the services named on the command line.  This is useful in certain
+backward compatibility situations.
+.TP
+.B \-q
+suppress printing
+.TP
+.B \-h
+prints a usage statement and exits
+.TP
+.B \-4
+specifies that Kerberos version 4 tickets should be acquired and
+described.  This option is only available if Kerberos 4 support was
+enabled at compilation time.
+.SH ENVIRONMENT
+.B Kvno
+uses the following environment variable:
+.TP "\w'.SM KRB5CCNAME\ \ 'u"
+.SM KRB5CCNAME
+Location of the credentials (ticket) cache.
+.TP
+.SM KRBTKFILE
+Location of the v4 ticket file.
+.SH FILES
+.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
+/tmp/krb5cc_[uid]
+default location of the credentials cache ([uid] is the decimal UID of
+the user).
+.TP
+/tmp/tkt[uid]
+default location of the v4 ticket file.
+.SH SEE ALSO
+kinit(1), kdestroy(1), krb5(3)
diff --git a/mechglue/src/clients/kvno/kvno.c b/mechglue/src/clients/kvno/kvno.c
new file mode 100644
index 000000000..c860eb7d4
--- /dev/null
+++ b/mechglue/src/clients/kvno/kvno.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+
+extern int optind;
+extern char *optarg;
+
+static char *prog;
+
+static void xusage()
+{
+#ifdef KRB5_KRB4_COMPAT
+    fprintf(stderr, 
+            "usage: %s [-4 | [-c ccache] [-e etype]] service1 service2 ...\n", 
+            prog);
+#else
+    fprintf(stderr, "usage: %s [-c ccache] [-e etype] service1 service2 ...\n",
+            prog);
+#endif
+    exit(1);
+}
+
+int quiet = 0;
+
+static void do_v4_kvno (int argc, char *argv[]);
+static void do_v5_kvno (int argc, char *argv[], 
+                        char *ccachestr, char *etypestr);
+
+int main(int argc, char *argv[])
+{
+    int option;
+    char *etypestr = 0, *ccachestr = 0;
+    int v4 = 0;
+
+    prog = strrchr(argv[0], '/');
+    prog = prog ? (prog + 1) : argv[0];
+
+    while ((option = getopt(argc, argv, "c:e:hq4")) != -1) {
+	switch (option) {
+	case 'c':
+	    ccachestr = optarg;
+	    break;
+	case 'e':
+	    etypestr = optarg;
+	    break;
+	case 'h':
+	    xusage();
+	    break;
+	case 'q':
+	    quiet = 1;
+	    break;
+	case '4':
+	    v4 = 1;
+	    break;
+	default:
+	    xusage();
+	    break;
+	}
+    }
+
+    if ((argc - optind) < 1)
+	xusage();
+
+    if ((ccachestr != 0 || etypestr != 0) && v4)
+	xusage();
+
+    if (v4)
+	do_v4_kvno(argc - optind, argv + optind);
+    else
+	do_v5_kvno(argc - optind, argv + optind, ccachestr, etypestr);
+    return 0;
+}
+
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
+static void do_v4_kvno (int count, char *names[])
+{
+#ifdef KRB5_KRB4_COMPAT
+    int i;
+
+    for (i = 0; i < count; i++) {
+	int err;
+	char name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
+	KTEXT_ST req;
+	CREDENTIALS creds;
+	*name = *inst = *realm = '\0';
+	err = kname_parse (name, inst, realm, names[i]);
+	if (err) {
+	    fprintf(stderr, "%s: error parsing name '%s': %s\n",
+		    prog, names[i], krb_get_err_text(err));
+	    exit(1);
+	}
+	if (realm[0] == 0) {
+	    err = krb_get_lrealm(realm, 1);
+	    if (err) {
+		fprintf(stderr, "%s: error looking up local realm: %s\n",
+			prog, krb_get_err_text(err));
+		exit(1);
+	    }
+	}
+	err = krb_mk_req(&req, name, inst, realm, 0);
+	if (err) {
+	    fprintf(stderr, "%s: krb_mk_req error: %s\n", prog,
+		    krb_get_err_text(err));
+	    exit(1);
+	}
+	err = krb_get_cred(name, inst, realm, &creds);
+	if (err) {
+	    fprintf(stderr, "%s: krb_get_cred error: %s\n", prog,
+		    krb_get_err_text(err));
+	    exit(1);
+	}
+	if (!quiet)
+	    printf("%s: kvno = %d\n", names[i], creds.kvno);
+    }
+#else
+    xusage();
+#endif
+}
+
+#include <krb5.h>
+static void do_v5_kvno (int count, char *names[], 
+                        char * ccachestr, char *etypestr)
+{
+    krb5_context context;
+    krb5_error_code ret;
+    int i, errors;
+    krb5_enctype etype;
+    krb5_ccache ccache;
+    krb5_principal me;
+    krb5_creds in_creds, *out_creds;
+    krb5_ticket *ticket;
+    char *princ;
+
+    ret = krb5_init_context(&context);
+    if (ret) {
+	com_err(prog, ret, "while initializing krb5 library");
+	exit(1);
+    }
+
+    if (etypestr) {
+        ret = krb5_string_to_enctype(etypestr, &etype);
+	if (ret) {
+	    com_err(prog, ret, "while converting etype");
+	    exit(1);
+	}
+    } else {
+	etype = 0;
+    }
+
+    if (ccachestr)
+        ret = krb5_cc_resolve(context, ccachestr, &ccache);
+    else
+        ret = krb5_cc_default(context, &ccache);
+    if (ret) {
+	com_err(prog, ret, "while opening ccache");
+	exit(1);
+    }
+
+    ret = krb5_cc_get_principal(context, ccache, &me);
+    if (ret) {
+	com_err(prog, ret, "while getting client principal name");
+	exit(1);
+    }
+
+    errors = 0;
+
+    for (i = 0; i < count; i++) {
+	memset(&in_creds, 0, sizeof(in_creds));
+
+	in_creds.client = me;
+
+	ret = krb5_parse_name(context, names[i], &in_creds.server);
+	if (ret) {
+	    if (!quiet)
+		fprintf(stderr, "%s: %s while parsing principal name\n",
+			names[i], error_message(ret));
+	    errors++;
+	    continue;
+	}
+
+	ret = krb5_unparse_name(context, in_creds.server, &princ);
+	if (ret) {
+	    fprintf(stderr, "%s: %s while printing principal name\n",
+		    names[i], error_message(ret));
+	    errors++;
+	    continue;
+	}
+
+	in_creds.keyblock.enctype = etype;
+
+	ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
+
+	krb5_free_principal(context, in_creds.server);
+
+	if (ret) {
+	    fprintf(stderr, "%s: %s while getting credentials\n",
+		    princ, error_message(ret));
+
+	    krb5_free_unparsed_name(context, princ);
+
+	    errors++;
+	    continue;
+	}
+
+	/* we need a native ticket */
+	ret = krb5_decode_ticket(&out_creds->ticket, &ticket);
+	if (ret) {
+	    fprintf(stderr, "%s: %s while decoding ticket\n",
+		    princ, error_message(ret));
+
+	    krb5_free_creds(context, out_creds);
+	    krb5_free_unparsed_name(context, princ);
+
+	    errors++;
+	    continue;
+	}
+	    
+	if (!quiet)
+	    printf("%s: kvno = %d\n", princ, ticket->enc_part.kvno);
+
+	krb5_free_ticket(context, ticket);
+	krb5_free_creds(context, out_creds);
+	krb5_free_unparsed_name(context, princ);
+    }
+
+    krb5_free_principal(context, me);
+    krb5_cc_close(context, ccache);
+    krb5_free_context(context);
+
+    if (errors)
+	exit(1);
+
+    exit(0);
+}
diff --git a/mechglue/src/config-files/.Sanitize b/mechglue/src/config-files/.Sanitize
new file mode 100644
index 000000000..2bd71ffcd
--- /dev/null
+++ b/mechglue/src/config-files/.Sanitize
@@ -0,0 +1,43 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+convert-config-files
+kdc.conf
+kdc.conf.M
+krb5.conf
+krb5.conf.M
+services.append
+krb5.conf
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/config-files/ChangeLog b/mechglue/src/config-files/ChangeLog
new file mode 100644
index 000000000..42ddabcb2
--- /dev/null
+++ b/mechglue/src/config-files/ChangeLog
@@ -0,0 +1,227 @@
+2004-10-06  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install): Install example config files.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2003-06-27  Jen Selby <jenselby@mit.edu>
+
+	* kdc.conf.M: replaced the @LOCALSTATEDIR typos with
+	/usr/local/var
+
+2003-06-20  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.conf.M: Sync with doc/krb5conf.texinfo.
+
+2003-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc.conf: Delete supported and master key type specs.
+
+	* krb5.conf: Delete Athena KDC specifications.  Delete Cygnus
+	realm info.  Replace CLUB.CC.CMU.EDU info with ANDREW.CMU.EDU,
+	which has SRV records and thus doesn't need KDC specs.  Provide a
+	commented-out example of a [logging] spec.  Delete commented-out
+	enctype specs.
+
+	* krb5.conf.M: Remove "kdc =" lines from "realms" section example,
+	and recommend not using it unless DNS info isn't available.
+
+2003-05-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc.conf.M (FILES): Refer to correct location for kdc.conf in
+	the default installation path.
+
+2002-09-24  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.conf: Update enctypes and add club.cc.cmu.edu
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-22  Jen Selby <jenselby@mit.edu>
+	
+	* kdc.conf.M: added descriptions of some tags
+	* krb5.conf.M: added a description of the [login] section and some
+	tags.
+
+2001-04-04  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.conf.M: Update description of safe_checksum_type for recent
+	changes. [pullup from krb5-1-2-2-branch]
+	
+2000-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.conf.M: Added description of v4_realm from Booker
+	C. Bense.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.conf: Put primary KDC for Cygnus first.  Add GNU.ORG
+	realm.
+
+1999-01-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, configure.in: Move the responsibility for
+		generating the Makefile in this directory to the top-level
+		configure script.  The local configure.in script has been
+		deleted.
+
+Wed Feb 18 15:45:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 28 09:02:31 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc.conf.M: Document the v4_mode option. [krb5-kdc/464]
+
+Tue Nov 26 19:24:34 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kdc.conf: Fixed paths to use the GNU standard conventions.  
+		[PR#246]
+
+Thu Nov 14 23:08:37 1996  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.conf.M: Note change in default_keytab_name.
+
+Wed Nov 13 15:15:07 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdc.conf: remove profile, admin database_name, and admin
+ 	lockfile relations [PR 124]
+
+Wed Oct 16 15:39:59 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdc.conf: remove the (wrong) kadmind_port relation
+	[krb5-admin/61]
+
+Tue Sep 10 14:35:53 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kdc.conf.M, krb5.conf.M: remove extra args from .TH
+
+Fri Jul 26 14:05:42 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kdc.conf: added acl_file to prototype
+
+Mon Jul 22 18:40:31 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kdc.conf (admin_*): add the fields for the new admin system to
+ 	the prototype config.file
+
+Mon May 20 17:25:09 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.conf.M: Document kdc_req_checksumtype,
+		as_req_checksum_type, and safe_checksum_type.
+
+	* krb5.conf: Remove the tkt_lifetime parameter altogether.  We may
+ 		end up doing it slightly differently post-Beta 6...
+
+Mon May 13 20:39:33 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.conf: Change the default ticket lifetime to something
+		reasonable (10 hours, instead of 10 minutes).  Also change
+		the label of this parameter to be tkt_lifetime.
+
+Tue Apr  2 22:31:48 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5.conf.M, krb5.conf: add default_tkt_enctypes.
+
+Wed Mar 27 22:44:36 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5.conf, kdc.conf: specify des-cbc-crc as the only valid
+	enctype (but permit normal, v4, norealm, onlyrealm, and afs3
+	salttypes.)
+	
+Tue Oct  3 17:57:32 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5.conf[libdefaults]: add krb4_config, krb4_realms.
+
+Wed Jan 10 22:13:04 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.conf.M: Added documentation for the DCE compat options,
+		plus the capaths section.
+
+Sun Nov 12 05:16:28 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* krb5.conf[libdefaults]: add krb4_config, krb4_realms.
+
+Sat Oct 21 09:07:59 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+    
+	* kdc.conf.M: Fixed typo
+
+	* configure.in, Makefile.in: Install manual pages.
+
+	* .Sanitize: Update file list
+
+	* .cvsignore: Ignore configure
+
+Thu Oct  5 22:38:24 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdc.conf.M: Documented kdc_ports, and removed references to
+		primary_port and secondary_port, which are no longer used.
+
+Wed Sep 13 18:40:24 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdc.conf.M (profile): Remove definition of the profile field,
+		which is being desupported.
+
+Fri Sep  1 23:26:46 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.conf.M: Add documentation for the clockskew and
+		kdc_timesync relations in the libdefaults section.
+
+Thu Aug 24 19:24:26 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Mon Aug 21 16:59:00 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdc.conf.M - Change types of master_key_type and encryption_type to
+		be "key type string" and "encryption type string".  Add
+		default_principal_expiration, default_principal_flags and
+		supported_keytypes.
+
+
+Wed Jul 12 12:06:10 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdc.conf[.M] - Change syntax.  KDC now has per-realm information in
+		[realms] section and has [kdcdefaults] to contain global data.
+		Add profile and secondary_port per-realm data.
+
+Fri Jun 23 10:36:48 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdc.conf[.M] - Add description of new KDC configuration file.
+
+
+Thu Jun 8 15:00:39 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krb5.conf.M - Add description of logging profile entries.
+
+Fri May  5 00:58:55 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5.conf: Add example of the new [realms]/<realm>/
+		v4_instance_convert/<instance> form used by
+		krb5_425_convert_principal.
+
+	* krb5.conf.M: Document new v4_instance_convert subsection.
+
+Tue Apr 25 22:04:54 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.conf.M: New file added to document the new krb5.conf
+		format.
+
+	* krb5.conf: New file added as a demo version of the new krb5.conf
+		format. 
+
+	* convert-config-files: New file to convert old-style krb.conf and
+		krb.realms file to use the new krb5.conf format.
+
+	* krb.conf, krb.realms, krb.conf.M, krb.realms.M: Removed.
+
+Thu Apr 20 22:20:37 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* services.append: Fix name of port for kpropd from krb_prop to
+		krb5_prop. 
+
+
diff --git a/mechglue/src/config-files/Makefile.in b/mechglue/src/config-files/Makefile.in
new file mode 100644
index 000000000..ad2b999d9
--- /dev/null
+++ b/mechglue/src/config-files/Makefile.in
@@ -0,0 +1,12 @@
+thisconfigdir=./..
+myfulldir=config-files
+mydir=config-files
+BUILDTOP=$(REL)..
+all::
+
+install::
+	$(INSTALL_DATA) $(srcdir)/kdc.conf.M ${DESTDIR}$(FILE_MANDIR)/kdc.conf.5
+	$(INSTALL_DATA) $(srcdir)/krb5.conf.M ${DESTDIR}$(FILE_MANDIR)/krb5.conf.5
+	$(INSTALL_DATA) $(srcdir)/kdc.conf ${DESTDIR}$(EXAMPLEDIR)/kdc.conf
+	$(INSTALL_DATA) $(srcdir)/krb5.conf ${DESTDIR}$(EXAMPLEDIR)/krb5.conf
+	$(INSTALL_DATA) $(srcdir)/services.append ${DESTDIR}$(EXAMPLEDIR)/services.append
diff --git a/mechglue/src/config-files/convert-config-files b/mechglue/src/config-files/convert-config-files
new file mode 100644
index 000000000..53ddefff1
--- /dev/null
+++ b/mechglue/src/config-files/convert-config-files
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+#
+# This program converts the old-style krb.conf and krb.realms files into the
+# new-format krb5.conf file.  It takes two arguments; the first is the krb.conf
+# file, and the second is the krb.realms file.  The krb5.conf file is output
+# to stdout.
+#
+# Written by Theodore Ts'o, 4/25/95
+#
+
+if ($#ARGV >= 0) {
+	$krb_conf_file = $ARGV[0];
+} else {
+	$krb_conf_file = "/etc/krb.conf";
+}
+
+if ($#ARGV >= 1) {
+	$krb_realms_file = $ARGV[1];
+} else {
+	$krb_realms_file = "/etc/krb.realms";
+}
+
+open(FILE, "<$krb_conf_file") || die "Couldn't open the krb.conf file\n";
+
+$_ = <FILE>;
+strip;
+$default_realm = $_;
+
+while(<FILE>) {
+	strip;
+	($realm, $host, $admin) = split;
+	if (!defined($realmpt{$realm})) {
+		$realmpt{$realm} = 1;
+	}
+	$realmkdc{$realm . "##" . $realmpt{$realm}} = $host;
+	$realmpt{$realm}++;
+	if ($admin eq "admin") {	
+		$realmadmin{$realm} = $host;
+	}
+}
+
+close(FILE);
+
+open(FILE, "<$krb_realms_file") || die "Couldn't open krb.realms file";
+
+while (<FILE>) {
+	strip;
+	($domain, $realm) = split;
+	$domain =~ s/\.$//;
+	$domain =~ tr/[A-Z]/[a-z]/;
+	$dom_realm{$domain} = $realm;
+	if ($domain =~ /^\./) {
+		$domain =~ s/^\.//;
+		$def_realm{$realm} = $domain;
+	}
+}
+
+print "[libdefaults]\n\tdefault_realm = $default_realm\n";
+
+print "[realms]\n";
+
+foreach $realm (sort(keys(%realmpt))) {
+	print "\t$realm = {\n";
+	for ($i = 1; $i < $realmpt{$realm}; $i++) {
+		printf("\t\tkdc = %s\n", $realmkdc{$realm . "##" . $i});
+		
+	}
+	if (defined($realmadmin{$realm})) {
+		print "\t\tadmin_server = $realmadmin{$realm}\n";
+	}
+	if (defined($def_realm{$realm})) {
+		print "\t\tdefault_domain = $def_realm{$realm}\n";
+	}
+	print "\t}\n";
+}
+
+print "\n[domain_realm]\n";
+
+foreach $domain (keys(%dom_realm)) {
+	print "\t$domain = $dom_realm{$domain}\n";
+}
+
+
+
diff --git a/mechglue/src/config-files/kdc.conf b/mechglue/src/config-files/kdc.conf
new file mode 100644
index 000000000..3355699ff
--- /dev/null
+++ b/mechglue/src/config-files/kdc.conf
@@ -0,0 +1,13 @@
+[kdcdefaults]
+	kdc_ports = 750,88
+
+[realms]
+	ATHENA.MIT.EDU = {
+		database_name = /usr/local/var/krb5kdc/principal
+		admin_keytab = FILE:/usr/local/var/krb5kdc/kadm5.keytab
+		acl_file = /usr/local/var/krb5kdc/kadm5.acl
+		key_stash_file = /usr/local/var/krb5kdc/.k5.ATHENA.MIT.EDU
+		kdc_ports = 750,88
+		max_life = 10h 0m 0s
+		max_renewable_life = 7d 0h 0m 0s
+	}
diff --git a/mechglue/src/config-files/kdc.conf.M b/mechglue/src/config-files/kdc.conf.M
new file mode 100644
index 000000000..0c1735f3c
--- /dev/null
+++ b/mechglue/src/config-files/kdc.conf.M
@@ -0,0 +1,241 @@
+.\" Copyright 1995 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\"
+.TH KDC.CONF 5
+.SH NAME
+kdc.conf \- Kerberos V5 KDC configuration file
+.SH DESCRIPTION
+.I kdc.conf
+specifies per-realm configuration data to be used by the Kerberos V5
+Authentication Service and Key Distribution Center (AS/KDC).  This
+includes database, key and per-realm defaults.
+.PP
+The 
+.I kdc.conf
+file uses the same format as the
+.I krb5.conf
+file.  For a basic description of the syntax, please refer to the
+.I krb5.conf
+description.
+.PP
+The following sections are currently used in the
+.I kdc.conf
+file:
+.IP [kdcdefaults]
+Contains parameters which control the overall behaviour of the KDC.
+.IP [realms]
+Contains subsections keyed by Kerberos realm names which describe per-realm
+KDC parameters.
+.SH KDCDEFAULTS SECTION
+The following relations are defined in the
+.I [kdcdefaults]
+section:
+.IP kdc_ports
+This relation lists the ports which the Kerberos server should listen
+on, by default.  This list is a comma separated list of integers.  If
+this relation is not specified, the compiled-in default is usually
+port 88 and port 750.
+
+.IP v4_mode
+This 
+.B string
+specifies how the KDC should respond to Kerberos IV packets. If this
+relation is not specified, the compiled-in default of
+.I nopreauth 
+is used.
+
+.SH REALMS SECTION
+Each tag in the
+.I [realms]
+section of the file names a Kerberos realm.  The value of the tag is a
+subsection where the relations in that subsection define KDC parameters for
+that particular realm.
+.PP
+For each realm, the following tags may be specified in the
+.I [realms]
+subsection:
+
+.IP acl_file
+This
+.B string
+specifies the location of the access control list (acl) file that
+kadmin uses to determine which principals are allowed which permissions
+on the database. The default value is /usr/local/var/krb5kdc/kadm5.acl.
+
+.IP admin_keytab
+This
+.B string
+Specifies the location of the keytab file that kadmin uses to
+authenticate to the database.  The default value is
+/usr/local/var/krb5kdc/kadm5.keytab.
+
+.IP database_name
+This
+.B string
+specifies the location of the Kerberos database for this realm.
+
+.IP default_principal_expiration
+This
+.B absolute time string
+specifies the default expiration date of principals created in this realm.
+
+.IP default_principal_flags
+This
+.B flag string
+specifies the default attributes of principals created in this realm.
+The format for the string is a comma-separated list of flags, with '+'
+before each flag to be enabled and '-' before each flag to be
+disabled.  The default is for postdateable, forwardable, tgt-based,
+renewable, proxiable, dup-skey, allow-tickets, and service to be
+enabled, and all others to be disabled.
+
+There are a number of possible flags: 
+.RS
+.TP
+.B postdateable
+Enabling this flag allows the principal to obtain postdateable tickets.
+.TP
+.B forwardable
+Enabling this flag allows the principal to obtain forwardable tickets.
+.TP
+.B tgt-based
+Enabling this flag allows a principal to obtain tickets based on a
+ticket-granting-ticket, rather than repeating the authentication
+process that was used to obtain the TGT.
+.TP
+.B renewable
+Enabling this flag allows the principal to obtain renewable tickets.
+.TP
+.B proxiable
+Enabling this flag allows the principal to obtain proxy tickets.
+.TP
+.B dup-skey
+Enabling this flag allows the principal to obtain a session key for
+another user, permitting user-to-user authentication for this principal.
+.TP
+.B allow-tickets
+Enabling this flag means that the KDC will issue tickets for this
+principal.  Disabling this flag essentially deactivates the principal
+within this realm.
+.TP
+.B preauth
+If this flag is enabled on a client principal, then that principal is
+required to preauthenticate to the KDC before receiving any tickets.
+On a service principal, enabling this flag means that service tickets
+for this principal will only be issued to clients with a TGT that has
+the preauthenticated ticket set.
+.TP
+.B hwauth
+If this flag is enabled, then the principal is required to
+preauthenticate using a hardware device before receiving any tickets.
+.TP
+.B pwchange
+Enabling this flag forces a password change for this principal.
+.TP
+.B service
+Enabling this flag allows the the KDC to issue service tickets for this
+principal.
+.TP
+.B pwservice
+If this flag is enabled, it marks this principal as a password change
+service.  This should only be used in special cases, for example, if a
+user's password has expired, the user has to get tickets for that
+principal to be able to change it without going through the normal
+password authentication.
+.RE
+
+.IP dict_file
+This
+.B string
+location of the dictionary file containing strings that are not allowed
+as passwords.  If this tag is not set or if there is no policy assigned
+to the principal, then no check will be done.
+
+.IP kadmind_port
+This
+.B port number
+specifies the port on which the kadmind daemon is to listen for this
+realm.
+
+.IP kpasswd_port
+This
+.B port number
+specifies the port on which the kadmind daemon is to listen for this
+realm.
+
+.IP key_stash_file
+This
+.B string
+specifies the location where the master key has been stored with
+.I kdb5_stash.
+
+.IP kdc_ports
+This
+.B string
+specifies the list of ports that the KDC is to listen to for this realm.  
+By default, the value of 
+.I kdc_ports
+as specified in the 
+.I [kdcdefaults] 
+section is used.
+
+.IP master_key_name
+This
+.B string
+specifies the name of the principal associated with the master key.
+The default value is K/M.
+
+.IP master_key_type
+This
+.B key type string
+represents the master key's key type.
+
+.IP max_life
+This
+.B delta time string
+specifes the maximum time period that a ticket may be valid for in
+this realm.  
+
+.IP max_renewable_life
+This
+.B delta time string
+specifies the maximum time period that a ticket may be renewed for in
+this realm. 
+
+.IP supported_enctypes
+list of key:salt strings that specifies the default key/salt
+combinations of principals for this realm
+
+.IP kdc_supported_enctypes
+specifies the permitted key-salt combinations of principals for this realm
+
+.IP reject_bad_transit
+this
+.B boolean
+specifies whether or not the list of transited realms for cross-realm
+tickets should be checked against the transit path computed from the
+realm names and the [capaths] section of its krb5.conf file
+
+.SH FILES 
+/usr/local/var/krb5kdc/kdc.conf
+
+.SH SEE ALSO
+krb5.conf(5), krb5kdc(8)
diff --git a/mechglue/src/config-files/krb5.conf b/mechglue/src/config-files/krb5.conf
new file mode 100644
index 000000000..efc19e45d
--- /dev/null
+++ b/mechglue/src/config-files/krb5.conf
@@ -0,0 +1,33 @@
+[libdefaults]
+	default_realm = ATHENA.MIT.EDU
+	krb4_config = /usr/kerberos/lib/krb.conf
+	krb4_realms = /usr/kerberos/lib/krb.realms
+
+[realms]
+	ATHENA.MIT.EDU = {
+		admin_server = KERBEROS.MIT.EDU
+		default_domain = MIT.EDU
+		v4_instance_convert = {
+			mit = mit.edu
+			lithium = lithium.lcs.mit.edu
+		}
+	}
+	ANDREW.CMU.EDU = {
+		admin_server = vice28.fs.andrew.cmu.edu
+	}
+# use "kdc =" if realm admins haven't put SRV records into DNS
+        GNU.ORG = {
+                kdc = kerberos.gnu.org
+                kdc = kerberos-2.gnu.org
+                admin_server = kerberos.gnu.org
+        }
+
+[domain_realm]
+	.mit.edu = ATHENA.MIT.EDU
+	mit.edu = ATHENA.MIT.EDU
+	.media.mit.edu = MEDIA-LAB.MIT.EDU
+	media.mit.edu = MEDIA-LAB.MIT.EDU
+	.ucsc.edu = CATS.UCSC.EDU
+
+[logging]
+#	kdc = CONSOLE
diff --git a/mechglue/src/config-files/krb5.conf.M b/mechglue/src/config-files/krb5.conf.M
new file mode 100644
index 000000000..87582c0b4
--- /dev/null
+++ b/mechglue/src/config-files/krb5.conf.M
@@ -0,0 +1,555 @@
+.\" Copyright 1995 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH KRB5.CONF 5
+.SH NAME
+krb5.conf \- Kerberos configuration file
+.SH DESCRIPTION
+.I krb5.conf
+contains configuration information needed by the Kerberos V5 library.
+This includes information describing the default Kerberos realm, and the
+location of the Kerberos key distribution centers for known realms.
+.PP
+The 
+.I krb5.conf
+file uses an INI-style format.  Sections are delimited by square braces;
+within each section, there are relations where tags can be assigned to
+have specific values.  Tags can also contain a subsection, which
+contains further relations or subsections.  A tag can be assigned to
+multiple values.  Here is an example of the INI-style format used by
+.IR krb5.conf :
+
+.sp
+.nf
+.in +1i
+[section1]
+	tag1 = value_a
+	tag1 = value_b
+	tag2 = value_c
+
+[section 2]
+	tag3 = {
+		subtag1 = subtag_value_a
+		subtag1 = subtag_value_b
+		subtag2 = subtag_value_c
+	}
+	tag4 = {
+		subtag1 = subtag_value_d
+		subtag2 = subtag_value_e
+	}
+.in -1i
+.fi
+.sp
+
+.PP
+The following sections are currently used in the 
+.I krb5.conf
+file:
+.IP [libdefaults]
+Contains various default values used by the Kerberos V5 library.
+
+.IP [login]
+Contains default values used by the Kerberos V5 login program,
+.IR login.krb5 (8).
+
+.IP [appdefaults]
+Contains default values that can be used by Kerberos V5 applications.
+
+.IP [realms]
+Contains subsections keyed by Kerberos realm names which describe where
+to find the Kerberos servers for a particular realm, and other
+realm-specific information.
+
+.IP [domain_realm]
+Contains relations which map subdomains and domain names to Kerberos
+realm names.  This is used by programs to determine what realm a host
+should be in, given its fully qualified domain name.
+
+.IP [logging]
+Contains relations which determine how Kerberos entities are to perform
+their logging.
+
+.IP [capaths]
+Contains the authentication paths used with non-hierarchical
+cross-realm. Entries in the section are used by the client to determine
+the intermediate realms which may be used in cross-realm
+authentication. It is also used by the end-service when checking the
+transited field for trusted intermediate realms.
+.PP 
+Each of these sections will be covered in more details in the following
+sections.
+.SH LIBDEFAULTS SECTION
+The following relations are defined in the [libdefaults] section:
+
+.IP default_keytab_name
+This relation specifies the default keytab name to be used by
+application severs such as telnetd and rlogind.  The default is
+"/etc/krb5.keytab".  This formerly defaulted to "/etc/v5srvtab", but
+was changed to the current value.
+
+.IP default_realm
+This relation identifies the default realm to be used in a client host's
+Kerberos activity.
+
+.IP default_tgs_enctypes
+This relation identifies the supported list of session key encryption
+types that should be returned by the KDC. The list may be delimited with
+commas or whitespace.
+
+.IP default_tkt_enctypes
+This relation identifies the supported list of session key encryption
+types that should be requested by the client, in the same format.
+
+.IP permitted_enctypes
+This relation identifies the permitted list of session key encryption
+types.
+
+.IP clockskew 
+This relation sets the maximum allowable amount of clockskew in seconds
+that the library will tolerate before assuming that a Kerberos message
+is invalid.  The default value is 300 seconds, or five minutes.
+
+.IP kdc_timesync 
+If the value of this relation is non-zero (the default), the library
+will compute the difference between the system clock and the time
+returned by the KDC and in order to correct for an inaccurate system
+clock.  This corrective factor is only used by the Kerberos library.
+
+.IP kdc_req_checksum_type
+For compatability with DCE security servers which do not support the
+default CKSUMTYPE_RSA_MD5 used by this version of Kerberos. Use a value
+of 2 to use the CKSUMTYPE_RSA_MD4 instead. This applies to DCE 1.1 and
+earlier.
+
+.IP ap_req_checksum_type 
+This allows you to set the checksum type used in the authenticator of
+KRB_AP_REQ messages.  The default value for this type is
+CKSUMTYPE_RSA_MD5.  For compatibility with applications linked against
+DCE version 1.1 or earlier Kerberos libraries, use a value of 2 to use
+the CKSUMTYPE_RSA_MD4
+instead.
+
+.IP safe_checksum_type 
+This allows you to set the preferred keyed-checksum type for use in KRB_SAFE
+messages.  The default value for this type is CKSUMTYPE_RSA_MD5_DES.
+For compatibility with applications linked against DCE version 1.1 or
+earlier Kerberos
+libraries, use a value of 3 to use the CKSUMTYPE_RSA_MD4_DES
+instead.  This field is ignored when its value is incompatible with
+the session key type.
+
+.IP ccache_type
+User this parameter on systems which are DCE clients, to specify the
+type of cache to be created by kinit, or when forwarded tickets are
+received. DCE and Kerberos can share the cache, but some versions of DCE
+do not support the default cache as created by this version of
+Kerberos. Use a value of 1 on DCE 1.0.3a systems, and a value of 2 on
+DCE 1.1 systems.
+
+.IP krb4_srvtab 
+Specifies the location of the Kerberos V4 srvtab file.  Default is
+"/etc/srvtab".
+
+.IP krb4_config
+Specifies the location of hte Kerberos V4 configuration file.  Default
+is "/etc/krb.conf".
+
+.IP krb4_realms
+Specifies the location of the Kerberos V4 domain/realm translation
+file.  Default is "/etc/krb.realms".
+
+.IP dns_lookup_kdc
+Indicate whether DNS SRV records shoud be used to locate the KDCs and 
+other servers for a realm, if they are not listed in the information 
+for the realm.  The default is to use these records.
+
+.IP dns_lookup_realm
+Indicate whether DNS TXT records should be used to determine the Kerberos
+realm of a host.  The default is not to use these records.
+
+.IP dns_fallback
+General flag controlling the use of DNS for Kerberos information.  If both
+of the preceding options are specified, this option has no effect.
+
+.IP extra_addresses
+This allows a computer to use multiple local addresses, in order to
+allow Kerberos to work in a network that uses NATs.  The addresses should
+be in a comma-separated list.
+
+.IP udp_preference_limit
+When sending a message to the KDC, the library will try using TCP
+before UDP if the size of the message is above "udp_preference_list".
+If the message is smaller than "udp_preference_list", then UDP will be
+tried before TCP.  Regardless of the size, both protocols will be
+tried if the first attempt fails.
+
+.IP verify_ap_req_nofail
+If this flag is set, then an attempt to get initial credentials will
+fail if the client machine does not have a keytab.  The default for the
+flag is false.
+
+.IP renew_lifetime
+The value of this tag is the default renewable lifetime for initial
+tickets.  The default value for the tag is 0.
+
+.IP noaddresses
+Setting this flag causes the initial Kerberos ticket to be addressless.
+The default for the flag is true.
+
+.IP forwardable
+If this flag is set, initial tickets by default will be forwardable.
+The default value for this flag is false.
+
+.IP proxiable
+If this flag is set, initial tickets by default will be proxiable.
+The default value for this flag is false.
+
+.SH APPDEFAULTS SECTION
+
+Each tag in the [appdefaults] section names a Kerberos V5 application
+or an option that is used by some Kerberos V5 application[s].  The
+four ways that you can set values for options are as follows, in
+decreasing order of precedence:
+
+.sp
+.nf
+.in +1i
+#1) 	
+	application = {
+		realm1 = {
+			option = value
+		}
+		realm2 = {
+			option = value
+		}
+	}
+#2) 	
+	application = {
+		option1 = value
+		option2 = value
+	}
+#3)	
+	realm = {
+		option = value
+	}
+#4)	
+	option = value
+.in -1in
+.fi
+.sp
+
+.SH LOGIN SECTION
+The [login] section is used to configure the behavior of the Kerberos V5
+login program,
+.IR login.krb5 (8).
+Refer to the manual entry for
+.I login.krb5
+for a description of the relations allowed in this section.
+.SH REALMS SECTION
+Each tag in the [realms] section of the file names a Kerberos realm.
+The value of the tag is a subsection where the relations in that
+subsection define the properties of that particular realm.  For example:
+
+.sp
+.nf
+.in +1i
+[realms]
+	ATHENA.MIT.EDU = {
+		admin_server = KERBEROS.MIT.EDU
+		default_domain = MIT.EDU
+		v4_instance_convert = {
+			mit = mit.edu
+			lithium = lithium.lcs.mit.edu
+		}
+		v4_realm = LCS.MIT.EDU
+	}
+.in -1i
+.fi
+.sp
+
+For each realm, the following tags may be specified in the realm's
+subsection:
+
+.IP kdc
+The value of this relation is the name of a host running a KDC for that
+realm.  An optional port number (preceded by a colon) may be appended to
+the hostname.  This tag should generally be used only if the realm
+administrator has not made the information available through DNS.
+
+.IP admin_server
+This relation identifies the host where the administration server is
+running.  Typically this is the Master Kerberos server.
+
+.IP default_domain
+This relation identifies the default domain for which hosts in this
+realm are assumed to be in.  This is needed for translating V4 principal
+names (which do not contain a domain name) to V5 principal names (which
+do).
+
+.IP v4_instance_convert
+This subsection allows the administrator to configure exceptions to the
+default_domain mapping rule.  It contains V4 instances (the tag name)
+which should be translated to some specific hostname (the tag value) as
+the second component in a Kerberos V5 principal name.
+
+.IP v4_realm
+This relation is used by the krb524 library routines when converting 
+a V5 principal name to a V4 principal name. It is used when V4 realm
+name and the V5 realm are not the same, but still share the same 
+principal names and passwords. The tag value is the Kerberos V4 realm 
+name. 
+
+.IP auth_to_local_names
+This subsection allows you to set explicit mappings from principal
+names to local user names.  The tag is the mapping name, and the value
+is the corresponding local user name.
+
+.IP auth_to_local
+This tag allows you to set a general rule for mapping principal names
+to local user names.  It will be used if there is not an explicit
+mapping for the principal name that is being translated.  The possible
+values are:
+
+.in +.5i
+DB:<filename>
+.in +.5i
+The principal will be looked up in the database <filename>.
+Support for this is not currently compiled in by default.
+.in -.5in
+RULE:<exp>
+.in +.5i
+The local name will be formulated from <exp>.
+.in -.5i
+DEFAULT
+.in +.5i
+The principal name will be used as the local name.  If the
+principal has more than one component or is not in the default
+realm, this rule is not applicable and the conversion will fail.
+.in -1i
+
+.SH DOMAIN_REALM SECTION
+
+The [domain_realm] section provides a translation from a hostname to the
+Kerberos realm name for the services provided by that host.
+.PP
+The tag name can be a hostname, or a domain name, where domain names are
+indicated by a prefix of a period ('.') character.  The value of the
+relation is the Kerberos realm name for that particular host or domain.
+Host names and domain names should be in lower case.
+.PP
+If no translation entry applies, the host's realm is considered to be
+the hostname's domain portion converted to upper case.  For example, the
+following [domain_realm] section:
+
+.sp
+.nf
+.in +1i
+[domain_realm]
+	.mit.edu = ATHENA.MIT.EDU
+	mit.edu = ATHENA.MIT.EDU 
+	dodo.mit.edu = SMS_TEST.MIT.EDU
+	.ucsc.edu = CATS.UCSC.EDU
+.in -1i
+.fi
+.sp
+maps dodo.mit.edu into the SMS_TEST.MIT.EDU realm, all other hosts in
+the MIT.EDU domain to the ATHENA.MIT.EDU realm, and all hosts in the
+UCSC.EDU domain into the CATS.UCSC.EDU realm.  ucbvax.berkeley.edu would
+be mapped by the default rules to the BERKELEY.EDU realm, while
+sage.lcs.mit.edu would be mapped to the LCS.MIT.EDU realm.
+
+.SH LOGGING SECTION
+
+The [logging] section indicates how a particular entity is to perform
+its logging.  The relations specified in this section assign one or more
+values to the entity name.
+.PP
+Currently, the following entities are used:
+.IP kdc
+These entries specify how the KDC is to perform its logging.
+.IP admin_server
+These entries specify how the administrative server is to perform its logging.
+.IP default
+These entries specify how to perform logging in the absence of explicit
+specifications otherwise.
+.PP
+Values are of the following forms:
+.IP FILE=<filename>
+.IP FILE:<filename>
+This value causes the entity's logging messages to go to the specified
+file.  If the
+.B =
+form is used, then the file is overwritten.  Otherwise, the file is
+appended to.
+.IP STDERR
+This value causes the entity's logging messages to go to its standard
+error stream.
+.IP CONSOLE
+This value causes the entity's logging messages to go to the console, if
+the system supports it.
+.IP DEVICE=<devicename>
+This causes the entity's logging messages to go to the specified device.
+.IP SYSLOG[:<severity>[:<facility>]]
+This causes the entity's logging messages to go to the system log.
+
+The
+.B severity
+argument specifies the default severity of system log messages.  This
+may be any of the following severities supported by the
+.I syslog(3)
+call minus the LOG_ prefix: LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
+LOG_WARNING, LOG_NOTICE, LOG_INFO, and LOG_DEBUG.  For example, to
+specify LOG_CRIT severity, one would use CRIT for
+.B severity.
+
+The
+.B facility
+argument specifies the facility under which the messages are logged.
+This may be any of the following facilities supported by the
+.I syslog(3)
+call minus the LOG_ prefix: LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON,
+LOG_AUTH, LOG_LPR, LOG_NEWS, LOG_UUCP, LOG_CRON, and LOG_LOCAL0 through
+LOG_LOCAL7.
+
+If no
+.B severity
+is specified, the default is ERR, and if no
+.B facility
+is specified, the default is AUTH.
+.PP
+In the following example, the logging messages from the KDC will go to
+the console and to the system log under the facility LOG_DAEMON with
+default severity of LOG_INFO; and the logging messages from the
+administrative server will be appended to the file /var/adm/kadmin.log
+and sent to the device /dev/tty04.
+.sp
+.nf
+.in +1i
+[logging]
+	kdc = CONSOLE
+	kdc = SYSLOG:INFO:DAEMON
+	admin_server = FILE:/var/adm/kadmin.log
+	admin_server = DEVICE=/dev/tty04
+.in -1i
+.fi
+.sp
+
+.SH CAPATHS SECTION
+
+Cross-realm authentication is typically organized hierarchically.  This
+hierarchy is based on the name of the realm, which thus imposes
+restrictions on the choice of realm names, and on who may participate in
+a cross-realm authentication. A non hierarchical orgization may be used,
+but requires a database to construct the authentication paths between
+the realms. This section defines that database.
+.PP
+A client will use this section to find the authentication path between
+its realm and the realm of the server. The server will use this section
+to verify the authentication path used be the client, by checking the
+transited field of the received ticket.
+.PP
+There is a tag name for each participating realm, and each tag has
+subtags for each of the realms. The value of the subtags is an
+intermediate realm which may participate in the cross-realm
+authentication. The subtags may be repeated if there is more then one
+intermediate realm. A value of "." means that the two realms share keys
+directly, and no intermediate realms should be allowed to participate.
+.PP
+There are n**2 possible entries in this table, but only those entries
+which will be needed on the client or the server need to be present. The
+client needs a tag for its local realm, with subtags for all the realms
+of servers it will need to authenticate with.  A server needs a tag for
+each realm of the clients it will serve.
+.PP
+For example, ANL.GOV, PNL.GOV, and NERSC.GOV all wish to use the ES.NET
+realm as an intermediate realm. ANL has a sub realm of TEST.ANL.GOV
+which will authenticate with NERSC.GOV but not PNL.GOV.  The [capath]
+section for ANL.GOV systems would look like this:
+.sp
+.nf
+.in +1i
+[capaths]
+	ANL.GOV = {
+		TEST.ANL.GOV = .
+		PNL.GOV = ES.NET
+		NERSC.GOV = ES.NET
+		ES.NET = .
+	}
+	TEST.ANL.GOV = {
+		ANL.GOV = .
+	}
+	PNL.GOV = {
+		ANL.GOV = ES.NET
+	}
+	NERSC.GOV = {
+		ANL.GOV = ES.NET
+	}
+	ES.NET = {
+		ANL.GOV = .
+	}
+.in -1i
+.fi
+.sp
+The [capath] section of the configuration file used on NERSC.GOV systems
+would look like this:
+.sp
+.nf
+.in +1i
+[capaths]
+	NERSC.GOV = {
+		ANL.GOV = ES.NET
+		TEST.ANL.GOV = ES.NET
+		TEST.ANL.GOV = ANL.GOV
+		PNL.GOV = ES.NET
+		ES.NET = .
+	}
+	ANL.GOV = {
+		NERSC.GOV = ES.NET
+	}
+	PNL.GOV = {
+		NERSC.GOV = ES.NET
+	}
+	ES.NET = {
+		NERSC.GOV = .
+	}
+	TEST.ANL.GOV = {
+		NERSC.GOV = ANL.GOV
+		NERSC.GOV = ES.NET
+	}
+.in -1i
+.fi
+.sp
+In the above examples, the ordering is not important, except when the
+same subtag name is used more then once. The client will use this to
+determing the path. (It is not important to the server, since the
+transited field is not sorted.)
+.PP
+If this section is not present, or if the client or server cannot find a
+client/server path, then normal hierarchical orginization is assumed.
+.PP
+This feature is not currently supported by DCE. DCE security servers can
+be used with Kerberized clients and servers, but versions prior to DCE
+1.1 did not fill in the transited field, and should be used with
+caution.
+.SH FILES 
+/etc/krb5.conf
+.SH SEE ALSO
+syslog(3)
diff --git a/mechglue/src/config-files/services.append b/mechglue/src/config-files/services.append
new file mode 100644
index 000000000..bd1010f5c
--- /dev/null
+++ b/mechglue/src/config-files/services.append
@@ -0,0 +1,32 @@
+#
+# Note --- if you are using Kerberos V4 clients and you either (a)
+# haven't converted all your KDC's over to use V5, or (b) are worried
+# about inter-realm interoperability with other KDC's that are still
+# using V4, then you will have to switch the definition of kerberos and
+# kerberos-sec.
+#
+# The issue is that the official port assignement for the "kerberos"
+# port is port 88, yet the unofficial port that has been used for
+# Kerberos V4 is port 750.  The V5 KDC will respond to requests made on
+# either port, and if V4 compatibility is turned on, it will respond to
+# V4 requests on either port as well.
+#
+#
+# Hence, it is safe to switch the definitions of kerberos and
+# kerberos-sec; both should be defined, though, and one should be port
+# 88 and one should be port 750.
+#
+kerberos	88/udp 		kdc		# Kerberos authentication--udp
+kerberos	88/tcp 		kdc		# Kerberos authentication--tcp
+kerberos-sec	750/udp 			# Kerberos authentication--udp
+kerberos-sec	750/tcp 			# Kerberos authentication--tcp
+kerberos_master	751/udp 			# Kerberos authentication
+kerberos_master	751/tcp 			# Kerberos authentication
+kerberos-adm	749/tcp				# Kerberos 5 admin/changepw
+kerberos-adm	749/udp				# Kerberos 5 admin/changepw
+kpop		1109/tcp			# Pop with Kerberos
+kshell		544/tcp		cmd		# and remote shell
+klogin		543/tcp				# Kerberos authenticated rlogin
+eklogin		2105/tcp			# Kerberos encrypted rlogin
+krb5_prop	754/tcp				# Kerberos slave propagation
+krb524		4444/tcp			# Kerberos 5 to 4 ticket xlator
diff --git a/mechglue/src/config/.Sanitize b/mechglue/src/config/.Sanitize
new file mode 100644
index 000000000..3371ae91f
--- /dev/null
+++ b/mechglue/src/config/.Sanitize
@@ -0,0 +1,49 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+ChangeLog
+config.guess
+config.sub
+doc
+install-sh
+mac-config.README
+mac-config.cache
+mac-mf.sed
+mac-post.in
+mac-pre.in
+post.in
+pre.in
+ren2long
+ren2long.awk
+rm.bat
+windows.in
+win-post.in
+winexclude.sed
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/config/ChangeLog b/mechglue/src/config/ChangeLog
new file mode 100644
index 000000000..6dd123327
--- /dev/null
+++ b/mechglue/src/config/ChangeLog
@@ -0,0 +1,1489 @@
+2005-11-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (*-*-solaris*): Include $(CFLAGS) in LDCOMBINE.
+	Don't use compiler command-line options for initializers for
+	Solaris 7 and earlier native compilers.
+
+2005-10-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* libnover.in (LIBLIST): Use DYNOBJEXT instead of SHLIBEXT.
+	* shlib.conf (*-*-darwin*): Include SHLIB_DIRS, and
+	DYNOBJ_EXPLIBS_WITH_LOADER instead of
+	DYNOBJ_EXPFLAGS_WITH_LOADER.
+
+	* post.in (.depend): Don't run sed, just use perl.  Use new name
+	of perl script.
+
+	* shlib.conf: Set DYNOBJ_EXPDEPS and DYNOBJ_EXPFLAGS.
+	(*-*-darwin*): Change MAKE_DYNOBJ_COMMAND definition to use
+	DYNOBJ_EXPFLAGS and DYNOBJ_LOADER_PROG instead of SHLIB_EXPFLAGS
+	and a hardcoded pathname to the KDC binary, respectively.
+	* pre.in (DYNOBJ_EXPDEPS, DYNOBJ_EXPFLAGS): New variables.
+	* libnover.in ($(LIBBASE)$(DYNOBJEXT)): Use DYNOBJ_EXPDEPS instead
+	of SHLIB_EXPDEPS in dependencies.
+
+2005-10-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* libnover.in (PARSE_OBJLISTS): Die on warnings (including input
+	file not found).
+	* lib.in (PARSE_OBJLISTS): Likewise.
+
+	* shlib.conf: Change aix5.3 section to aix5.*.  Change aix*
+	section to aix4.*, and set DYNOBJEXT and MAKE_DYNOBJ_COMMAND.
+
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in ($(BUILDTOP)/.depend-verify-db, depend-verify-db-k5,
+	depend-verify-db-sys): Targets deleted.
+	(DEP_CFG_VERIFY): Don't depend on $(BUILDTOP)/.depend-verify-db.
+
+	* libnover.in (darwin.exports): New target.
+	($(LIBBASE)$(DYNOBJEXT)): New target, instead of
+	$(LIBBASE)$(SHLIBVEXT).
+	(all-libs): Build $(LIBBASE)$(DYNOBJEXT).
+	(install-shared): Use DYNOBJEXT.
+
+	* pre.in (DYNOBJEXT, MAKE_DYNOBJ_COMMAND): New variables.
+	* shlib.conf: Set DYNOBJEXT, MAKE_DYNOBJ_COMMAND to the SHLIB
+	versions.  For Darwin, set them to create a .so bundle, and set
+	SHLIB_EXPORT_FILE_DEP to darwin.exports.
+
+	* pre.in (DB_DEPLIB, DB_DEPLIB-k5, DB_DEPLIB-sys, DB_VERSION,
+	DB_DEPS, DB_DEPS-sys, DB_DEPS-k5, DB_DEPS-redirect, DB_LIB,
+	KDB5_DB_LIB): Variables deleted.
+	(KDB5_LIBS): Set to just $(KDB5_LIB).
+
+2005-09-01  Marc Aurele La France  <tsi@ualberta.ca>
+
+	* shlib.conf (case *-*-aix5.3*):  Generate proper shared libraries
+	acceptable to dlopen(3) (as in mechglue, for example).  Allows for
+	building both shared and static libraries in one run.  Only done for
+	AIX 5.3, but probably should be done for earlier versions.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (configure): Depend on patchlevel.h.
+
+2005-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in (LIBPREFIX): New variable.
+	* libnover.in (LIBPREFIX): New variable.
+	(LIBLIST, $(LIBBASE)$(SHLIBVEXT),
+	$(TOPLIBD)/$(LIBBASE)$(SHLIBEXT), clean-libs, install-shared):
+	Drop "lib" from generated shared object name.
+	* pre.in (SHLIB_EXPORT_FILE): Use $(LIBPREFIX).
+	* shlib.conf: Use $(LIBPREFIX) in LDCOMBINE.
+
+2005-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (KRB5_DB_MODULE_DIR): New variable.
+
+	* libnover.in: New file.
+	(Makefile): Depend on correct makefile fragment.
+	(SHLIBVEXT): Fix definition.
+	(LIBLIST, LIBINSTLIST): Override configured definitions.
+	(all-liblinks, clean-liblinks): Targets deleted.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (PTHREAD_LIBS, DL_LIB, THREAD_LINKOPTS): New variables.
+
+2005-04-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (depend-dependencies): Use (and depend on) depfix2.pl
+	instead of .depfix2.sed.
+	(.depfix2.sed): Target deleted.
+	(DEPTARGETS): Delete .depfix2.sed and .depfix2.tmp.
+
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in (hpux10.exports): New target, constructed similar to
+	osf1.exports but with HP-UX 10.x linker options, no initializers,
+	and "errno" explicitly added to the export list.
+	* shlib.conf (*-*-hpux*): Combine PICFLAGS setting with
+	SHLIB_EXPFLAGS and LDCOMBINE setting.  Add linker option "-c
+	hpux10.exports" to LDCOMBINE.  Set SHLIB_EXPORT_FILE_DEP to
+	hpux10.exports.  Set use_linker_fini_option.
+
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in (config.status): Change target to be in $thisconfigdir
+	rather than local.
+	(osf1.exports): Create a temporary file then rename into place.
+	Add options for library init/fini symbols, handling multiple
+	values.
+
+	* shlib.conf (case alpha*-dec-osf*): Don't handle init/fini
+	symbols here.
+	(case mips-sgi-irix*): Handle multiple init/fini symbols.  Always
+	set $initfini before it gets used.
+	(case *-*-solaris*, not gcc): Handle multiple init/fini symbols.
+	(case *-*-aix*): Handle multiple fini symbols.
+
+2005-01-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (Makefile): Nuke autom4te.cache before and after
+	autoconf runs.
+
+2004-12-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (.depend): Delete blank lines in generated file.  Don't
+	do target name munging here.
+	(DEP_CFG_VERIFY, DEP_VERIFY, depend-verify-*, .depend-verify-*,
+	.depfix2.sed): Move all the flag files to $(BUILDTOP) so there'll
+	be only one of each.
+	(.depfix2.sed): Pass extra value $(STLIBOBJS).
+
+2004-12-17  Jeffrey Altman <jaltman@mit.edu>
+
+        * win-pre.in: add -debug switch to LOPTS if DEBUG_SYMBOLS 
+
+2004-12-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (*-*-netbsd*): Use -fPIC instead of -fpic, which
+	won't work on sparc64 at least.
+
+2004-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * win-pre.in; optionally build debug symbols for release builds
+                      and rename krb5support_32.dll to k5sprt32.dll
+
+2004-11-19  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (KRB5_INCSUBDIRS): Add KRB5_INCDIR/gssrpc.
+
+2004-10-06  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (datadir, EXAMPLEDIR): Add directory for examples.
+
+2004-09-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in (binutils.versions, osf1.exports): New file targets.
+	(clean-libs): Delete them.
+	* pre.in (SHLIB_EXPORT_FILE_DEP): Use @SHLIB_EXPORT_FILE_DEP@.
+	* shlib.conf: Set it to $(SHLIB_EXPORT_FILE) by default.
+	(alpha*-dec-osf*): Use osf1.exports instead of adding commands to
+	generate a temporary file.
+	(*-*-linux*, *-*-gnu*, *-*-k*bsd*-gnu): Use binutils.versions.
+
+2004-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (UTIL_LIB): Set if we need libutil.
+
+	* shlib.conf (alpha*-dec-osf*): Only use -Wl,-oldstyle_liblookup
+	if using native linker, with check for native linker if gcc is
+	being used.
+
+2004-09-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (*-*-linux*, *-*-gnu*, *-*-k*bsd*-gnu): Don't use the
+	linker option --retain-symbols-file, it doesn't work for shared
+	libraries.
+
+2004-09-17  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (INSTALL_SCRIPT): New variable; use to install scripts,
+	as we don't want to strip scripts.
+
+2004-08-19  Sam Hartman  <hartmans@mit.edu>
+
+	* shlib.conf: Add support for gnu hurd and for BSD kernels with
+	glibc; use the Linux shared library procedure 
+
+2004-07-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (alpha*-dec-osf*): Use $(PTHREAD_CFLAGS) in
+	CC_LINK_SHARED and CC_LINK_STATIC.
+
+2004-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (alpha*-dec-osf*): Use $(PTHREAD_CFLAGS) in
+	LDCOMBINE.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (*-*-darwin*, *-*-rhapsody*): Don't set PICFLAGS or
+	LDFLAGS.  Force static libraries only always, instead of just as
+	the default.
+	(*-*-aix*): The initfini argument should be "-binitfini".  Use
+	-bernotok, not -berok.  Do use the INIT_FINI_PREP command in
+	constructing MAKE_SHLIB_COMMAND.
+
+	* pre.in (PTHREAD_CFLAGS): New variable.
+	(ALL_CFLAGS): Include it.
+
+	* win-pre.in (SLIB): New variable.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* mac-config.README, mac-config.cache, mac-mf.sed, mac-post.in,
+	mac-pre.in: Files deleted.
+
+2004-06-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (AUTOCONF, AUTOHEADER): Always set to autoconf and
+	autoheader respectively.
+	(AUTOCONFFLAGS, AUTOHEADERFLAGS): Always set to empty.
+	* post.in (Makefile): Always run autoconf with --include, don't
+	bother with --localdir any more.  Don't delete autom4te.cache
+	here.
+	(clean-unix): Delete autom4te.cache.
+
+	* shlib.conf (*-*-darwin*, *-*-rhapsody*): Add
+	-Wl,-search_paths_first to linker flags.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in (lib*, clean-*, install-*): Use $(LIBBASE) instead of
+	$(LIB).
+	* pre.in (SHLIB_EXPORT_FILE): Likewise.
+	* shlib.conf: Likewise.
+
+2004-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (*-*-aix*): Use linker options for library
+	finalization.
+
+2004-05-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* win-pre.in (CP): Copy nul: plus the file, to avoid carrying over
+	the original modification time, since some of our makefiles depend
+	on $(CP) updating the timestamp.  Use binary mode for the copy,
+	because default/ASCII seems to cause a ^Z to be added to the
+	file.
+
+2004-05-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (*-*-linux*): Use GNU linker's --retain-symbols-file
+	option to implement export list.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* libobj.in (OBJS.ST, OBJS.SH, OBJS.PF): Depend on Makefile.
+
+	* pre.in (SUPPORT_LIBNAME, SUPPORT_DEPLIB, SUPPORT_LIB): New
+	variables.
+	(KRB5_BASE_LIBS): Add $(SUPPORT_LIB).
+
+2004-05-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (alpha*-dec-osf*): Do remember to set
+	use_linker_init_option and use_linker_fini_option.
+	(mips-sgi-irix*): Set LDCOMBINE_TAIL only if not using gcc.
+
+2004-04-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (alpha*-dec-osf*): Add support for export list, using
+	a temporary file, and init/fini functions.
+	(mips-sgi-irix*): Previous support should not be used with gcc.
+
+	* pre.in (EXTRA_FILES): New variable.
+	* post.in (clean-unix): Delete extra files.
+
+	* shlib.conf: Initialize use_linker_init_option and
+	use_linker_fini_option to no.
+	(mips-sgi-irix*): Add link-time support for library
+	initialization and finalization.
+	(*-*-solaris*): Likewise, for native compiler.  Change "pic" mode
+	to "PIC", libkrb5 seems to need it now.
+
+2004-04-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* libobj.in (.c.so): Add -DSHARED to compile options.
+
+2004-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in (PARSE_OBJLISTS): New variable.
+	(lib$(LIB)$(STLIBEXT), lib$(LIB)$(SHLIBVEXT)): Use it.
+	(lib$(LIB)$(PFLIBEXT)): Use it.
+
+	* shlib.conf (INIT_FINI_PREP): New variable.  Default to a no-op,
+	but let each platform set setup routines to process
+	initialization and finalization options for the default
+	MAKE_SHLIB_COMMAND value.
+	(case mips-sgi-irix*): Define LDCOMBINE_TAIL to use the library's
+	export list.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (PERL): New variable.
+	* lib.in (lib$(LIB)$(SHLIBVEXT)): Use one perl invocation rather
+	than n+1 sed invocations.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (DO_MAKE_SHLIB, SHLIB_STATIC_TARGET, LDCOMBINE,
+	LDCOMBINE_TAIL): Delete unused variables.
+	(SHLIB_EXPORT_FILE, SHLIB_EXPORT_FILE_DEP, MAKE_SHLIB_COMMAND):
+	New variables.
+	* lib.in (lib$(LIB)$(SHLIBVEXT)): Depend on
+	SHLIB_EXPORT_FILE_DEP.  Set objlist to the list of object files
+	before invoking MAKE_SHLIB_COMMAND, instead of wrapping the list
+	with LDCOMBINE and LDCOMBINE_TAIL.
+	* shlib.conf: Set MAKE_SHLIB_COMMAND, using LDCOMBINE and
+	LDCOMBINE_TAIL in the common case.
+	(case *-*-aix*): Specify new commands, taken from makeshlib.sh,
+	but assume the export list is provided externally.
+
+2004-03-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (default_static, default_shared): New variables to
+	set.
+
+2004-03-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* ac-archive: New directory.
+	* ac-archive/README: New file.
+	* ac-archive/acx_pthread.m4: New file, data taken from autoconf
+	macro archive at sourceforge.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (SUBDIRS): Use autoconf substitution trick to make
+	SUBDIRS contain @subdirs@ only for the directory containing the
+	configure script, and only LOCAL_SUBDIRS elsewhere.
+	(top_srcdir): Define, set by configure.
+
+	* post.in (RECURSE_TARGETS): Drop MY_SUBDIRS support.
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (APPUTILS_DEPLIB, APPUTILS_LIB): New vars.
+	* post.in (daemon.c): Delete rule for copying source file.
+
+2004-02-18  Tom Yu  <tlyu@mit.edu>
+
+	* shlib.conf (alpha-*-dec-osf*, mips-sgi-irix*): Use $(CC) instead
+	of ld for building shared libraries.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* shlib.conf (*-*-solaris-*): Remove exitsleep.
+
+	* pre.in (FAKEDEST, FAKEPREFIX, FAKELIBDIR): Support variables for
+	the _RLD_ROOT hack.
+
+	* shlib.conf: For alpha/Tru64 and Irix, construct _RLD_ROOT values
+	pointing to a fake destdir, as well as to the real root directory.
+	Previously, pointing _RLD_ROOT at a non-existent directory and
+	putting everything in LD_LIBRARY_PATH caused other installed
+	utilities with RPATHs which were run by the test suite to fail to
+	run.
+
+2004-02-09  Tom Yu  <tlyu@mit.edu>
+
+	* config.guess: Update from autoconf-2.59.
+
+	* config.sub: Update from autoconf-2.59.
+
+	* install-sh: Update from autoconf-2.59.
+
+2003-11-26  Jeffrey Altman <jaltman@mit.edu>
+
+    * win-pre.in (KFWFLAGS): conditionally define USE_LEASH=1
+      to enable access to Leash apis for kinit dialogs within 
+      gssapi32.dll
+
+2003-12-05  Tom Yu  <tlyu@mit.edu>
+
+	* shlib.conf: Add Solaris support for LD_PRELOAD.
+
+2003-09-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (configure): Make configure depend on configure.in and
+	aclocal.m4 only if maintainer mode is enabled.
+
+2003-09-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf (*-*-linux*): Use $(CC) for linking shared libraries,
+	and -Wl to pass linker flags in, so it can supply the necessary
+	support libraries.
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (daemon.c): New rule for copying daemon.c locally from
+	master copy in lib/krb5/posix.
+
+2003-05-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* win-pre.in (CPPFLAGS): Define KRB5_DEPRECATED=1.
+
+2003-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (KRB524_H_DEP, KRB524_ERR_H_DEP, KRB524_LIB,
+	KRB524_DEPLIB): Deleted.
+
+2003-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (configure): Try running autoconf with --include, and if
+	that doesn't work, try --localdir.  Don't use AUTOCONFINCFLAGS.
+
+2003-04-01  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (KDB5_DEPLIBS): Don't depend on $(DB_DEPLIB) anymore.
+	(KDB5_DB_LIB): New variable; is empty if not building with system
+	libdb.
+	(KDB5_LIBS): Use $(KDB5_DB_LIB) instead of $(DB_LIB).
+
+2003-03-03  Tom Yu  <tlyu@mit.edu>
+
+	* libobj.in: Change .c.so and .c.po rules to use ALL_CFLAGS.
+
+	* pre.in (ALL_CFLAGS): Add KRB_INCLUDES.
+	(KRB_INCLUDES): Move from aclocal.m4, where it had been added to
+	CPPFLAGS.  This move allows CPPFLAGS to be used by the builder.
+
+	* shlib.conf: Add CFLAGS to many places where only LDFLAGS had
+	been previously.
+
+2003-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* post.in (.dtmp): Use -DDEPEND to allow source files to exclude
+	inclusions from dependencies.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in (LN_S, AR, LIBLIST, LIBLINKS, LIBINSTLIST, STLIBEXT,
+	SHLIBVEXT, SHLIBSEXT, SHLIBEXT, PFLIBEXT, LDCOMBINE,
+	LDCOMBINE_TAIL, SHLIB_EXPFLAGS): Move these autoconf-substituted
+	variables...
+	* libobj.in (OBJLISTS, SHLIBOBJS, PFLIBOBJS, LDCOMBINE, SONAME,
+	PICFLAGS, PROFFLAGS): ...and these...
+	* pre.in: ...to here.
+
+2002-12-23  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add variables for krb524 and krb4 generated headers for
+	dependencies.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* post.in: Fix depend rules to keep state about whether
+	verification of various things succeeded.  Change some double
+	colons to single colons.  Add a new depend-dependencies target to
+	allow Makefile.in to specify things that must be built for depend
+	to work.
+
+	* pre.in: Fix recursion rules to use fewer double colons.
+
+2002-12-09  Tom Yu  <tlyu@mit.edu>
+
+	* post.in: depfix2.sed -> .depfix2.sed to avoid a little clutter.
+
+2002-11-27  Tom Yu  <tlyu@mit.edu>
+
+	* post.in (clean-unix): Clean depfix2.sed as well.
+
+2002-11-13  Ezra Peisach  <epeisach@bu.edu>
+
+	* pre.in (AUTOCONFINCFLAGS): Define by configure.
+
+	* post.in (Makefile): Invoke autoconf with AUTOCONFINCFLAGS
+	instead of hardcoding --localdir.
+
+2002-11-12  Tom Yu  <tlyu@mit.edu>
+
+	* shlib.conf: Fix AIX to explicitly include system libraries in
+	"-blibpath:" by adding a variable RPATH_TAIL.  Fix typo in non-gcc
+	case.
+
+2002-11-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (.et.h, .et.c): Drop "set -x".
+
+2002-11-04  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: New variables RPATH_FLAG (set regardless of whether
+	we're building shared), TCL_MAYBE_RPATH (empty unless we're
+	building static and are capable of shared libs, in case there's a
+	shared tcl lib).
+
+	* shlib.conf: New variable RPATH_FLAG. 
+
+2002-10-07  Sam Hartman  <hartmans@mit.edu>
+
+	* pre.in post.in (RECURSE_TARGETS): Add install-headers-recurse
+
+2002-09-24  Ezra Peisach  <epeisach@bu.edu>
+
+	* post.in (Makefile): Run config.status to generate only the
+	specific makefile that changed.
+
+2002-09-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (.et.c, .et.h): Change rules to only update the desired
+	target file, by using temporary files; this makes them safe for
+	use in parallel builds.
+
+2002-09-19  Ezra Peisach  <epeisach@bu.edu>
+
+	* post.in (Makefile): Revert change until aclocal.m4 fixed.
+
+2002-09-19  Ezra Peisach  <epeisach@bu.edu>
+
+	* post.in (Makefile): Run config.status to generate only the
+	specific makefile that changed.
+
+2002-09-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in ($(srcdir)/$(thisconfigdir)/configure): Delete
+	autom4te.cache directory.
+
+2002-09-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (KRB5_LIB_libopt, KRB5_LIB_frameworkopt,
+	K5CRYPTO_LIB_libopt, K5CRYPTO_LIB_frameworkopt,
+	GSS_KRB5_LIB_libopt, GSS_KRB5_LIB_frameworkopt): Variables
+	deleted.
+	(KRB5_LIB, K5CRYPTO_LIB, GSS_KRB5_LIB): Use old _libopt values.
+	* lib.in (EXTRA_CLEAN_TARGETS, EXTRA_CLEAN_LINKS): Variables
+	deleted.
+	(clean-libs, clean-liblinks): Don't depend on them.
+	(all-framework, link-framework, clean-framework,
+	clean-framework-link, install-framework): Placeholder targets
+	deleted.
+	* shlib.conf: Don't define LIB_LINK_OPT, EXTRA_LIB_TARGETS,
+	EXTRA_LIBLINK_TARGETS, EXTRA_LIBINST_TARGETS, EXTRA_CLEAN_TARGETS,
+	EXTRA_CLEAN_LINKS.
+
+	* post.in (depend-verify-et-sys, depend-verify-et-k5,
+	depend-verify-ss-sys, depend-verify-ss-k5, depend-verify-db-sys,
+	depend-verify-db-k5): New targets.  Report errors in the -sys
+	versions.
+	(depend-verify-et, depend-verify-ss, depend-verify-db): New
+	targets.  Depend on the above based on the _VERSION macro
+	corresponding.
+	(depend-verify-srcdir): New target, split out from .d rules.
+	(.d): Depend on depend-verify-{et,ss,db,srcdir}.
+	(depend-verify-gcc, depend-verify-gcc-yes, depend-verify-gcc-no):
+	Report an error if not using gcc.
+	(depfix2.sed): Depend on depend-verify-gcc.  Supply libgcc file
+	name as fifth input field to depgen.sed.
+
+	* pre.in (DB_DEPLIB-k5, DB_DEPLIB-sys, DB_DEPS-sys, DB_DEPS-k5,
+	DB_DEPS-redirect): New variables.
+	(DB_DEPLIB, DB_DEPS): Select from them.
+	(DB_LIB): Substitute from configure script.
+	(COM_ERR_VERSION, SS_VERSION, DB_VERSION): New variables.
+
+2002-09-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (depfix2.sed): Pass srcdir and BUILDTOP as additional
+	inputs to depgen.sed.  Don't emit any other text.
+
+2002-09-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* libobj.in (.c.so, .c.po): Put LOCALINCLUDES before CPPFLAGS.
+
+	* pre.in (ALL_CFLAGS): Put LOCALINCLUDES before CPPFLAGS.
+	(SS_LIB-sys): Use @SS_LIB@ substitution.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (COM_ERR_DEPLIB-sys, COM_ERR_DEPLIB-k5, SS_DEPLIB-k5,
+	SS_DEPLIB-sys, COM_ERR_DEPS-sys, COM_ERR_DEPS-k5, SS_DEPS-sys,
+	SS_DEPS-k5, SS_LIB-sys, SS_LIB-k5, COMPILE_ET-sys, COMPILE_ET-k5,
+	MAKE_COMMANDS-sys, MAKE_COMMANDS-k5): New variables.
+	(COM_ERR_DEPLIB, SS_DEPLIB, COM_ERR_DEPS, SS_DEPS, SS_LIB,
+	COMPILE_ET, MAKE_COMMANDS): Use them, selecting using new
+	configure substitutions.
+	(COM_ERR_LIB): Always define as -lcom_err.
+	(CFLAGS): Define using @CFLAGS@, not @CCOPTS@.
+
+	* win-pre.in (COM_ERR_DEPS): New variable.
+
+	* shlib.conf: Use $(LDFLAGS) in CC_LINK_SHARED and CC_LINK_STATIC,
+	after other options.
+
+	* pre.in (S): Variable restored.
+	(ABS): Variable deleted.
+	(SS_DEPS): New variable.
+
+2002-08-26  Ezra Peisach  <epeisach@bu.edu>
+
+	* pre.in: Set host to @krb5_cv_host@ instead of @host@. The way
+	aclocal.m4 is setup, AC_CANONICAL_HOST may only be evaluated as a
+	cached variable and autoconf 2.52 will only allow one inclusion of
+	the code.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (S, U): Variables deleted.
+
+2002-08-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in ($(SUBDIROBJLISTS) and .SH/.PF variants): Depend on
+	recursion.  Use extra dummy target in case the variable is
+	empty.
+	* post.in (ALL_DEP_SRCS): New variable, includes SRCS and
+	EXTRADEPSRCS.
+	(.d): Depend on and use $(ALL_DEP_SRCS).
+	* pre.in (all-unix, all-recurse, all-postrecurse): Make each stage
+	depend on the previous, rather than having all-unix depend on
+	each.
+
+2002-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (DYN_DEPLIB): Removed.
+	(GSSRPC_DEPLIBS, GSSRPC_LIBS): Drop libdyn references.
+
+2002-07-13  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (PTY_DEPLIB): Fix to reflect always being built static.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (KRB5_INCSUBDIRS): Don't create the asn.1 subdirectory.
+
+2002-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (UTIL_DEPLIB, UTIL_LIB): Variables deleted.
+
+2002-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (COM_ERR_DEPS): New variable.
+
+	* post.in (clean-unix): Delete .d and .depend files along with
+	$(OBJS) in one command, to avoid needing to test whether the
+	latter is empty.
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-pre.in: Define KRB5_PRIVATE=1 so that private definitions
+	are used.  Define WIN32_LEAN_AND_MEAN so there are no Winsock
+	vs. Winsock 2 header file issues.  (Winsock 2 is needed for IPv6
+	support.)
+
+2002-04-02  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add support for doing optional stripping of programs.
+
+2002-03-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* move-if-changed: New script.
+	* post.in (depend-postrecurse): Use it.
+
+2002-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf: For Linux, always add "-lc" at the end of the link
+	command.
+
+	* libobj.in (config.status): Depend on shlib.conf.
+
+2001-12-18  Tom Yu  <tlyu@mit.edu>
+
+	* shlib.conf: Fix hpux to deal with building shared libs with gcc.
+	Patch from Doug Engert; fixes krb5-build/1021.
+
+2001-10-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (DEPLIBOBJNAMEFIX): New variable.
+	(.depend): If $(STLIBOBJS) is non-empty, filter dependency info
+	through $(DEPLIBOBJNAMEFIX).
+
+2001-10-11  Tom Yu  <tlyu@mit.edu>
+
+	* post.in: Minor tidying.  Make the target of the mondo recursion
+	rule commands be the variable $(RECURSE_TARGETS).
+
+2001-09-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (depfix2.sed): New target, generates a sed script
+	that'll do a better job of identifying possible $(SRCTOP) uses.
+	Collapse multiple slashes to one.  Uses new depgen.sed script.
+	(.depend): Use it.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* post.in (.d): Run compiler as a separate target from sed
+	processing.  Refuse to do anything if srcdir is ".".
+	(.depend): Find a shortcut name for SRCTOP to eliminate "foo/.."
+	subsequences, in case the compiler does the same.  Run depfix.sed
+	after the directory-specific substitutions, not before.
+	(depend-postrecurse): Renamed from old "depend" target.
+	(depend, depend-prerecurse, depend-recurse): Make "depend"
+	processing recursive.
+
+2001-08-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* post.in (all-recurse clean-recurse distclean-recurse
+	install-recurse check-recurse Makefiles-recurse): Do not pass down
+	CC and CCOPTS to subdirs. This causes automatic reconfiguration to
+	fail with autoconf 2.52 where config.status is invoked with
+	different environment variables.
+
+2001-07024  Jeffrey Altman <jaltman@columbia.edu>
+
+        * win-pre.in:  the proper #define is KRB5_DNS_LOOKUP_REALM
+          and not KRB5_DNS_LOOKUP_REALMS
+
+2001-07-23  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-pre.in, win-post.in: Move rule-printing code to win-post.in
+	so we get the correct build options displayed (i.e., the options
+	as they stand after parsing Makefile.in).
+
+2001-06-22  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-pre.in: Minimize printing of compiler command line during
+	build of a directory.
+
+2001-06-21  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-pre.in, win-post.in: Improve output directory creation and
+	cleanup.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* pre.in (KADM_COMM_DEPLIBS): Depend on GSSRPC_DEPLIBS and not
+	UTIL_DEPLIB. (KADMSRC_DEPLIBS) add dependency on KDB5_DEPLIB.
+
+2001-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (AUTOHEADER, AUTOHEADERFLAGS): New variables.
+
+2001-05-10  Tom Yu  <tlyu@mit.edu>
+
+	* shlib.conf: Fix RUN_ENV for Irix. [pulled up from 1.2.2]
+
+2001-01-28  Tom Yu  <tlyu@mit.edu>
+
+	* shlib.conf: We don't need aix.bincmds anymore for AIX.  Use the
+	-blibpath flag instead.
+
+2001-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (COMPILE_ET): New variable.
+	(COMPILE_ET_H, COMPILE_ET_C): Deleted.
+	(.et.h, .et.c): Use $(COMPILE_ET) instead of invoking awk
+	explicitly.
+
+2000-10-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* post.in (Makefile): When running autoconf, use AUTOCONFFLAGS
+	instead of always specificying the trees macrodir.
+
+	* pre.in (AUTOCONFFLAGS): Add as flags to pass to autoconf.
+
+2000-08-30  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Fix some inconsistent spelling in the previous changes
+	for MacOS X lib framework support, especially in the *_LIB and
+	*_LIB_*opt variables.
+
+2000-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib.in (EXTRA_CLEAN_TARGETS, EXTRA_CLEAN_LINKS): New variables.
+	(clean-libs, clean-liblinks): Depend on targets specified in those
+	variables.
+	(config.status): Depend on shlib.conf.
+	(all-framework, link-framework, clean-framework,
+	clean-framework-link, install-framework): New targets, details to
+	be filled in later.
+
+	* pre.in (KRB5_LIB_libopt): Renamed from KDB5_LIB.
+	(KRB5_LIB_frameworkopt): Tentative framework version for Mac OS X,
+	details to be tuned later.
+	(KRB5_LIB): Select between them using @LIB_LINK_OPT@.
+	(KRB5CRYPTO_LIB*, COM_ERR_LIB*, GSS_KRB5_LIB*): Similarly.
+	(KRB5_BASE_LIBS, GSS_LIBS): Use them.
+	(KRB4COMPAT_LIBS): Use KRB5_BASE_LIBS.
+
+	* shlib.conf: Set LIB_LINK_OPT.  Set new EXTRA_* variables for
+	darwin target.
+
+2000-08-29  Tom Yu  <tlyu@mit.edu>
+
+	* post.in: Test for existing Makefile in directory before
+	recursing into it.
+
+2000-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* libobj.in (clean-libobjs): Combine "rm" commands into one.
+
+2000-07-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-pre.in: Add KRB4_INCLUDES definition.
+
+2000-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* shlib.conf: New file, taken from KRB5_LIB_PARAMS in
+	../aclocal.m4.
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* pre.in: Remove the kdb5 and db libraries from the
+	common application list but list them for server applications.
+
+2000-07-01  Tom Yu  <tlyu@mit.edu>
+
+	* lib.in: Fix up lib build rules to deal properly (hopefuly) with
+	empty objlist files.
+
+2000-06-30  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-pre.in: Fix up DNS build flags to correspond to new DNS
+	build flags.  Add support for not using wshelper.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Twiddle things around to support building libdb under
+	krb5 build system.
+
+2000-06-08  Tom Yu  <tlyu@mit.edu>
+
+	* config.guess: Update to 2000-05-30 from FSF.
+
+	* config.sub: Update to 2000-05-30 from FSF.
+
+2000-05-03  Tom Yu  <tlyu@mit.edu>
+
+	* libobj.in, pre.in: Put $(LOCALINCLUDES) after $(CPPFLAGS) since
+	$(CPPFLAGS) should have its includes show up first.
+
+2000-03-01  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (INSTALL_SHLIB): New variable.
+
+	* lib.in (install-shared): Use $(INSTALL_SHLIB)
+
+2000-02-15  Tom Yu  <tlyu@mit.edu>
+
+	* libobj.in: Fix up .c.so and .c.po rules to include $(CFLAGS),
+	which were previously missing.
+
+2000-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add KRB524_DEPLIB and KRB524_LIB
+
+2000-01-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* pre.in (KADM_COMM_LIBS): Drop krb5util library.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-pre.in: Pull changes from krb5-1-1 branch: a) Make is so
+	that all C flags are the same and so that the only difference
+	between EXE and DLL builds are the DLL_LINKOPTS and EXE_LINKOPTS
+	linker options.  b) Fix DNS error messages to wshelper instead of
+	version server.  c) Fix DNS flags it does not try to depend on mit
+	dir.  Define NULL so we can do directory existence checks via the
+	shell under both NT and 9x.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* config.guess: Recognize Rhapsody OS.
+	* config.sub: Recognize OS name "rhapsody*".
+
+	* post.in (*-recurse): If an error occurs when using -k, report an
+	error after finishing all the subdirectories.
+
+1999-08-13  Brad Thompson  <yak@mit.edu>
+
+	* config.sub: Now recognizes MacOS 10 as a valid OS.
+
+1999-07-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* config.guess: Add MacOS 10 support.  (Submitted to autoconf
+	maintainers.)
+
+1999-07-22  Tom Yu  <tlyu@mit.edu>
+
+	* mkinstalldirs: New file; from autoconf-2.13.
+
+	* config.guess, config.sub, install-sh: Update from autoconf-2.13.
+
+Tue May 18 20:06:01 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-pre.in, win-pre.in: Remove trailing backslash from output
+		dir target in rule so rule is not always invoked if it
+		already exists.  Add MIGNORE option if we really want make
+		to ignore errors from recursive invocations of make.  Move
+		definition of WCONFIG and WCONFIG_EXE into win-pre.in.
+		Add NO_OUTDIR as synonym for NO_OUTPRE.
+
+Mon May 17 20:45:05 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-post.in, win-pre.in, windows.in: Rename windows.in to
+		win-pre.in.
+
+Mon May 17 12:26:12 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* windows.in, win-post.in: Remove win16 stuff.  Add
+		Win9x-compatible output directory creation.  Add more
+		thorough cleanup of output files and directories.  Use
+		latest and greatest (MSVC 6.0) debug flag.
+
+Mon May 10 15:03:28 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* windows.in, win-post.in: Build win32 binaries in 
+		obj/$(CPU)/{dbg,rel}.
+
+1999-03-31  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* post.in (Makefile): Don't try to run autoconf with $(SHELL),
+		since this doesn't work if $(AUTOCONF) isn't a path to the
+		built-in autoconf, but just an unqualified pathname to the
+		system autoconf.  [krb5-build/707]
+
+1999-02-19  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* windows.in (DLL_FILE_DEF): Add makefile controls to set either
+		KRB5_DLL_FILE or GSS_DLL_FILE, with the default being
+		KRB5_DLL_FILE.
+
+Mon Feb  8 22:13:23 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* winexclude.sed: Add .dll and .lib files to the list of functions
+ 		which shouldn't get included in the non-binary list of
+ 		files to be added to kerbsrc.zip for the Windows build.
+		(If .dll or .lib files need to be included in the zip
+ 		file, they must be added to the WINBINARYFILES macro in
+ 		the top-level Makefile.in)
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* post.in (*-recurse): If $(MY_SUBDIRS) is non-NULL use it instead
+		of $(SUBDIRS) to control which directories are iterated
+		over.  (This is needed so we can fold a directory's
+		configure.in scripts into the parent's configure.in
+		without having to move all of its siblings as well into
+		the parent directory's configure.in.  This is because if
+		the parent's configure.in file as a AC_CONFIG_DIRS macro,
+		it gets included into all the $(SUBDIRS) macro of *all*
+		of its generated makefiles, and this is wrong for all
+		but the Makefile.in of the parent directory.  For example,
+		if the configure.in in src/appl contains
+		AC_CONFIG_DIRS(bsd telnet gssftp), and that configure
+		script also generates the Makefile.in for src/appl/sample,
+		then SUBDIRS will contain "bsd telnet gssftp" plus
+		whatever LOCAL_SUBDIRS is defined to contain.  This
+		doesn't work.  So instead of defining LOCAL_SUBDIRS,
+		the Makefile.in in src/appl/sample defines MY_SUBDIRS,
+		which completely overrides the SUBDIRS macro.
+		Eventually, we should replace all of the LOCAL_SUBDIRS
+		definitions in the Makefile.in's with MY_SUBDIRS, and
+		add MY_SUBDIRS definitions into all Makefile.in's that
+		don't currently have then, and depend on
+		AC_CONFIG_SUBDIRS to insert the right magic value into
+		SUBDIRS.  At that point, we can get rid of the SUBDIR
+		definition in pre.in, and remove this test from
+		post.in which tests of MY_SUBDIRS and uses it in
+		preference to SUBDIRS, and simply always use MY_SUBDIRS.)
+
+1998-05-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* windows.in: Remove -DLEHMAN, which doesn't do anything.  (A grep
+		through the whole source tree shows no instances of #ifdef
+		LEHMAN)
+
+Sun May 24 21:39:49 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* windows.in (ABS,S,C): Use double backslashes for the path
+		separators to workaround Microsoft NMAKE brain damaging.
+		Sometimes backslashes are treated as a quoting characters,
+		and sometimes not, with no rhyme or reason that I can
+		determine.  Fortunatelly double backslashes in pathanmes
+		don't seem to hurt (for the times when the backslash isn't
+		treated as a quoating character).  Whoever decided Windows
+		should use backslash as a path separator should be shot.
+
+Wed Apr 15 18:01:39 1998  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (CRYPTO_DEPLIB):
+	(KRB5_BASE_LIBS):
+	(KRB4COMPAT_LIBS): Rename; libcrypto -> libk5crypto.
+
+Sun Mar  1 22:25:34 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* pre.in: Define AUTOCONF and CONFIG_RELTOPDIR from the autoconf
+ 		substitution macros.
+
+	* post.in: Fix the call to autoconf to use $(AUTOCONF) and
+	 	$(CONFIG_RELTOPDIR), so that configure regeneration rule
+	 	works even in a subdirectory below the configure script.
+
+Wed Feb 18 17:31:52 1998  Tom Yu  <tlyu@mit.edu>
+
+	* windows.in: Rewrite some of the directory syntax.
+
+	* pre.in: Rewrite some of the directory syntax.
+
+	* mac-pre.in: Rewrite some of the directory syntax.
+
+Fri Feb 13 22:16:51 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* config.guess, config.sub: Applied lxs's changes to add support
+ 		for Rhapsody DR1.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* pre.in: SUBDIRS now also includes LOCAL_SUBDIRS, which is
+		defined in the Makefile.in to control the recursive
+		descent through the subdirectories.  This is used so
+		that the subdirectories can be defined in Makefile.in,
+		instead of in the individual configure.in files.
+
+Tue Nov 18 19:20:59 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Clean up up .ct.c rule.
+
+	* lib.in (clean-libs): Remove lib$(LIB)$(SHLIBSEXT) as well.
+
+Mon Oct 20 14:27:19 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* pre.in (INSTALL_SETUID): Explicitly set the owner of the files
+		which are installed setuid root.
+
+Wed Aug  6 20:23:32 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add $(HESIOD_LIBS) to KADMSRV_LIBS.
+
+Sun Mar  9 22:28:34 1997  Tom Yu  <tlyu@mit.edu>
+
+	* lib.in: Add provisions for making shared libraries of the same
+	major version number compatible.
+
+Sun Mar  2 19:54:26 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* pre.in (KRB4COMPAT_DEPLIBS): Depends on KRB5_BASE_DEPLIBS (not
+	        KRB5_BASE_DEPLBS)
+
+Sat Mar  1 14:33:21 1997  Tom Yu  <tlyu@mit.edu>
+
+	* libobj.in: Change .c.so and .c.po rules to work better with
+	compilers that insist that $(CC) -fpic -c foo.c -o foo.so is
+	wrong; basically, cheat and do -o foo.so.o, etc.
+
+Thu Feb 27 17:40:51 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add recursion hooks for distclean.
+
+	* post.in: Change recursion rules to skip recursion if NORECURSE
+	is non-null; add distclean support; don't remove config.log,
+	etc. if not doing distclean.
+
+Sat Feb 22 18:42:32 1997  Richard Basch  <basch@lehman.com>
+
+	* win-post.in: Move library list file rule from various
+		Makefile.in files to win-post.in
+
+Mon Feb 17 19:29:27 1997  Richard Basch  <basch@lehman.com>
+
+	* windows.in: Define K4LIB as the krb4 library
+
+Fri Feb 14 22:02:33 1997  Richard Basch  <basch@lehman.com>
+
+	* windows.in: Define CLIB as the ComErr library (now separate lib)
+
+Mon Feb 10 08:39:10 1997  Tom Yu  <tlyu@mit.edu>
+
+	* post.in: Fix recursion rules to deal with Ultrix sh lossage.
+
+	* libobj.in: Remove instances of STAMP.*, since they aren't
+		actually necessary.
+
+Sun Feb  9 13:43:42 1997  Tom Yu  <tlyu@mit.edu>
+
+	* libobj.in (OBJS.*): Work around a gmake optimization where the
+		timestamps of OBJS.* would not get checked after STAMP.* get
+		updated, even though OBJS.* get updated as a side effect.
+
+Sat Feb  8 12:17:17 1997  Richard Basch  <basch@lehman.com>
+
+	* windows.in: Define WLIB (winsock library) for Win16.
+
+Fri Feb  7 08:44:32 1997  Richard Basch  <basch@lehman.com>
+
+	* windows.in: Compile win16 non-DLL objects with /GA to add the
+		appropriate Windows prolog code for protected-mode
+
+Tue Feb  4 15:56:41 1997  Richard Basch  <basch@lehman.com>
+
+	* windows.in: Do not bother to define INTERFACE or INTERFACE_C
+
+Sun Feb  2 23:30:17 1997  Richard Basch  <basch@lehman.com>
+
+	* windows.in:
+		Compile with /Ld to link dynamic libraries (win16)
+		Compile DLL objects with /DKRB5_DLL_FILE (win16)
+
+Thu Jan 30 22:08:42 1997  Richard Basch  <basch@lehman.com>
+
+	* windows.in:
+		Compile with /MD to link against the runtime library (win32)
+
+Thu Feb  6 15:32:46 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add definitions for KDB5_DEPLIBS, KDB5_LIBS for
+	convenience.
+
+Wed Feb  5 23:20:53 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Fix up TCL_* variables to work with changes to
+	aclocal.m4
+
+Tue Feb  4 20:23:31 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Fix typo in KADMCLNT_DEPLIBS.
+
+	* pre.in: Add more --with-krb4 support (KRB4_LIBPATH and
+	KRB4_INCLUDES).
+
+Mon Feb  3 23:29:02 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add GEN_LIB support (-lgen); also fix --with-krb4 stuff
+	(such as KRB4_LIB).
+
+Fri Jan 31 20:41:34 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Fix up GEN_LIB to DTRT
+
+	* pre.in: Add KDB5_LIB, and also fix typo (-lutil -> -lkrb5util)
+
+Mon Jan 27 17:13:15 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add variable to support new program building procedure.
+
+Thu Jan 16 18:58:16 1997  Tom Yu  <tlyu@mit.edu>
+
+	* post.in (Makefiles-prerecurse): Change to use double-colon
+	rule.
+
+	* pre.in (recursion rules): Change *-prerecurse and *-postrecurse
+	targets to be double-colon rules, to allow for multiple targets to
+	be evaluated in sequence.
+
+Fri Jan  3 23:16:31 1997  Tom Yu  <tlyu@mit.edu>
+
+	* lib.in: Change semantics of SHLIB_EXPFLAGS somewhat to sync with
+	new aclocal.m4 changes.
+
+Thu Jan  2 18:19:20 1997  Tom Yu  <tlyu@mit.edu>
+
+	* lib.in: Add facilities for explicit dependencies in libraries.
+
+Mon Dec 30 12:54:23 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* lib.in: Remove object of symlink before creating.
+
+Sun Dec 29 22:40:14 1996  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Add missing Makefiles rules.
+
+Sun Dec 29 21:24:01 1996  Tom Yu  <tlyu@mit.edu>
+
+	* lib.in: fix typo in profiled lib build
+
+	* libobj.in: random bugfixes
+
+Sat Dec 28 21:46:33 1996  Tom Yu  <tlyu@mit.edu>
+
+	* libobj.in: Cause Makefile to depend on config/libobj.in
+	* lib.in: Cause Makefile to depend on config/lib.in
+
+Fri Dec 27 17:06:41 1996  Tom Yu  <tlyu@mit.edu>
+
+	* lib.in: Fix up loops to deal with an OBJS.ST that is in the
+	current directory; add a comment documenting possible make
+	incompatibility if OBJS.ST is specified as ./OBJS.ST.
+
+	* pre.in:
+	* post.in: Fix up recursion to be somewhat saner.
+	* lib.in:
+	* libobj.in: Add these frags for new library build system.
+
+Tue Dec 24 16:43:45 1996  Tom Yu  <tlyu@mit.edu>
+
+	* config.guess:
+	* config.sub: Update from autoconf-2.12.
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+	* rm.bat: Do the work first; the comments are at the end so as
+		to improve the speed of the script significantly (20%)
+	* windows.in: corrected typo (all-windows) and added win32 support
+	* win-post.in: win16/win32 support
+
+Mon Nov 11 20:53:01 1996  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in (DEJAFLAGS): Change gmake-dependent $(shell uname foo) to
+	use $(host), which will get set by AC_CANONICAL_HOST in
+	configure.in.
+
+Thu Oct 31 17:45:21 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* pre.in (FILE_MANDIR): Create $prefix/include/kerberosIV [36]
+
+Mon Oct 21 21:21:43 1996  Tom Yu  <tlyu@mit.edu>
+
+	* pre.in: Substitute for *_RECURSE variables.
+
+	* post.in: Add *-recurse targets for new recursion method.
+
+Fri Oct 18 11:03:24 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* pre.in (DEJAFLAGS): s/:=/=/ [PR #117]
+
+Tue Oct 15 16:26:19 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* pre.in: add TEST_PATH argument to START_SERVERS and STOP_SERVERS
+
+Thu Oct  3 13:08:40 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* pre.in: Separate KADM5 unit test files to source dir and build
+		dir based on how generated.
+
+Mon Sep 23 15:40:04 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* pre.in (DEJAFLAGS): set --srcdir $(srcdir) so unit test files
+ 	don't have to be symlinked to build tree
+
+Fri Oct 18 01:13:19 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* pre.in :  Adjust directories to comply with autoconf standards [37]
+
+Fri Sep 20 16:58:08 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* pre.in: added support for KADM5 unit test system; could
+	stand some cleaning
+
+Tue Jul  9 15:02:00 1996  Marc Horowitz  <marc@mit.edu>
+
+	* pre.in (SRVLIBS, SRVDEPLIBS, CLNTLIBS, CLNTDEPLIBS): added for
+ 	support of new aclocal.m4 KRB5_LIBRARIES macro
+
+Thu Jun 13 23:02:23 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* post.in,pre.in: break some things out from aclocal.m4 and put
+		them here
+
+Wed Jun 12 20:19:49 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* windows.in (PAGESIZE): New variable which is used to control the
+		/pagesize parameter for Windows 16.  (Obviously we're
+		suffering from library size bloat if we need to set this.)
+
+Wed Jun 12 15:31:19 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* config.guess: Updated to a more recent version (from autoconf 1.10).
+
+Mon Jun 10 17:18:34 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* windows.in (CCOPTS): Windows-32 CCOPTS
+	
+	* win-post.in: Use a Windows-32 specific LIB command line syntax
+
+Thu Jun  6 15:54:57 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* windows.in (LIBCMD): Add the option /PAGESIZE:128 to the library
+		command, since the krb5 library has gotten so big.
+
+Tue Mar 12 19:40:59 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* pre.in (SRCTOP, BUILDTOP): Don't define.
+
+Mon Oct 16 15:19:42 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* pre.in: KRB5_LIBDIR, ADMIN_BINDIR, KRB5_SHLIBDIR, KRB5_INCDIR
+		are all based on exec_prefix.
+
+Wed Oct 11 18:13:30 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* pre.in (DO_MAKE_SHLIB):  substitute VEXT, for the version extension for shared libs
+
+Tue Oct 10 21:42:14 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* win-post.in: New file
+
+	* windows.in: Moved .c -> .obj rule to win-post.in, since we need
+		it after the LIBNAME makefile variable is defined in the
+		main body of the Makefile.
+
+Wed Sep 27 00:51:51 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* winexclude.sed: New file, used for generating DOS zip files.
+
+Mon Sep 25 13:09:17 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* windows.in:
+	* mac-pre.in:
+	* pre.in: Added lines of the form "all:: all-$(WHAT)" for all,
+		clean, install, and check.
+
+Wed Sep 13 10:20:02 1995 Keith Vetter (keithv@fusion.com)
+
+	* windows.in: added windows value for SRCTOP.
+
+Thu Aug 24 19:25:10 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Fri Jul 7 15:56:09 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* pre.in - Add DEPLIBS and LDFLAGS to be provided with each Makefile.
+
+Fri Jun 23 14:24:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* pre.in (SRCTOP): Change SRCTOP so that it's defined in configure
+		script, instead of being hardcoded as $(srcdir)/$(BUILDTOP).
+
+Thu Jun 22 13:27:00 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* pre.in (STEXT): Add definitions for STEXT and STATIC_TARGET
+
+Thu Jun 15 17:47:49 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* pre.in - Add definitions for building and using shared libraries.
+		Add KRB5_SHLIBDIR which is the destination directory for
+		shared libraries.
+
+Wed Jun 14 19:34:12 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* pre.in: DO_SUBDIRS causes make {install,clean,check,etc.} to get
+		run in subdirectories where they haven't been before.
+		Added some blank dependencies to keep things from breaking
+		too badly.
+
+Fri Jun  9 18:39:55 1995    <tytso@rsx-11.mit.edu>
+
+	* pre.in: Remove KRB5ROOT
+
+Thu Jun  8 17:44:12 1995    <tytso@rsx-11.mit.edu>
+
+	* pre.in: Define ${prefix} since exec_prefix is sometimes to that.
+		Don't create the directories include/krb5 and
+		include/kerberosIV when installing.  (They're not needed).
+
+Wed Jun  7 16:08:35 1995    <tytso@rsx-11.mit.edu>
+
+	* pre.in: Use the GNU/configure standard method of prefix and
+		exec_prefix to determine where programs get installed.
+		The use of KRB5ROOT is obsolete.
+
+Thu May 25 21:36:40 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* pre.in(HOST_TYPE, SHEXT, DO_MAKE_SHLIB): Added variables filled
+		in by configure 
+
+Wed May 24 15:42:02 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* config.guess, config.sub: Added for shared library support.
+
+Mon May 22 09:45:40 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* pre.in	- Add gssapi to list of subdirectories.
+
+Thu Apr 27 13:50:59 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* pre.in (KRB4): remove, unused.
+
+Wed Apr 26 14:27:03 1995 Keith Vetter (keithv@fusion.com)
+
+	* post.in: added target check-windows.
+	* ren2long, ren2long.awk: scripts to rename DOS 8.3 names back
+	   to their proper longer names.
+
+Thu Apr 20 20:00:42 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* post.in: The .depend production rule now does even more
+		cannonicalization of the generated dependencies.
+
+	* post.in: cc should be $(CC)
+
+Tue Apr 18 09:36:00 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* post.in (.depend, depend): Add production for creating the
+		.depend file, and updating the Makefile.in with the
+		new dependencies.
+
+Thu Apr 13 16:20:28 1995 Keith Vetter (keithv@fusion.com)
+
+	* windows.in: compile with stdc extensions enabled versus
+           strict stdc adherence.
+
+Tue Mar 28 17:58:55 1995  John Gilmore  (gnu at toad.com)
+
+	* mac-config.cache:  Correct some entries.
+	* mac-mf.sed:  Improve conversion of pathnames, $(srcdir),
+	support linking MPW tools (for make check, kinit).
+	* mac-pre.in (.c.o):  Add -sym on for debugging.
+	(LDFLAGS):  Remove ToolLibs.o.
+	(RANLIB, ARCHIVE):  Make these work.
+	(MAKE):  Make recursive makes work, with BuildProgram.
+
+Thu Mar 16 20:55:18 1995  John Gilmore  (gnu at toad.com)
+
+	First cut at Macintosh configuration support.
+
+	* mac-config.cache:  New file, a hand-built autoconf `config.cache'
+	file with the right values for building under MPW.
+	* mac-config.README:  Documentation for mac-config.cache.
+	* mac-pre.in, mac-post.in:  Versions of pre.in and post.in for 
+	configuring on MPW.
+	* mac-mf.sed:  A `sed' script which will turn carefully constructed
+	Unix Makefiles into carefully constructed Macintosh MPW Makefiles.
+
+Wed Mar 3 16:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* windows.in: changed included directories to reflect MAC changes
+
+Mon Feb 20 15:48:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* windows.in: changed API to INTERFACE        
+
+Mon Feb 13 23:40:11 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* pre.in: Add line for $(LD)
+
+Mon Feb 6 19:33:57 1995 Keith Vetter (keithv@fusion.com)
+
+	* pre.in: Added macros for directory syntax, filename extensions 
+	  and what system we're building on (defaults to Unix).
+	* post.in: split clean into unix and windows branches
+	* windows.in: new file--makefile macros and rules for windows
+	* rm.bat: new file--DOS batch file to mimic Unix's rm command
+
+Wed Nov  2 21:04:18 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* pre.in: Don't actually add the $(CPPOPTS) flags to CPPFLAGS;
+		CPPFLAGS has them defined already.  In fact, don't define
+		the CPPOPTS makefile variable at all; we don't need it.
+
+	* pre.in: Add support for a new --with-cppopts" value where you
+		can put -DXXXXX such that they are found by autoconf tests
+		that use run the preprocessor over header files.
+
+Tue Nov  1 14:11:57 1994    (tytso@rsx-11)
+
+	* post.in (clean): Also clean up config.log, pre.out, post.out and
+		Makefile.out 
+
+Thu Oct  6 19:41:52 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* post.in: add default "check" rule for Makefiles that don't do
+		anything else.
+
+	* pre.in: add default all:: rule at the end of pre.in
+
+Thu Aug  4 03:52:23 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* pre.in: strip installed programs by default
+
+Sun Jul  3 04:41:54 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* post.in: whoops, now making sure errors don't get returned if
+	something is empty
+
+	* post.in: fixing missing semicolon in make rules
+	* pre.in: MV=mv -f
+
+Sat Jul  2 00:03:24 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* pre.in: added KRB4 to the template to keep things like v4server
+	from losing
+
diff --git a/mechglue/src/config/ac-archive/README b/mechglue/src/config/ac-archive/README
new file mode 100644
index 000000000..7bc626eb5
--- /dev/null
+++ b/mechglue/src/config/ac-archive/README
@@ -0,0 +1,51 @@
+-*- text -*-
+
+These macros are taken from the autoconf archive at
+ac-archive.sourceforge.net.  Unless otherwise noted, they are under
+this modified version of the GNU General Public License version 2
+(also copied from ac-archive.sourceforge.net):
+
+    Every Autoconf macro presented on this web site is free software;
+    you can redistribute it and/or modify it under the terms of the
+    GNU General Public License as published by the Free Software
+    Foundation; either version 2, or (at your option) any later
+    version.
+
+    They are distributed in the hope that they will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+    General Public License for more details. (You should have received
+    a copy of the GNU General Public License along with this program;
+    if not, write to the Free Software Foundation, Inc., 59 Temple
+    Place -- Suite 330, Boston, MA 02111-1307, USA.)
+
+    As a special exception, the Free Software Foundation gives
+    unlimited permission to copy, distribute and modify the configure
+    scripts that are the output of Autoconf. You need not follow the
+    terms of the GNU General Public License when using or distributing
+    such scripts, even though portions of the text of Autoconf appear
+    in them. The GNU General Public License (GPL) does govern all
+    other use of the material that constitutes the Autoconf program.
+
+    Certain portions of the Autoconf source text are designed to be
+    copied (in certain cases, depending on the input) into the output
+    of Autoconf. We call these the "data" portions. The rest of the
+    Autoconf source text consists of comments plus executable code
+    that decides which of the data portions to output in any given
+    case. We call these comments and executable code the "non-data"
+    portions. Autoconf never copies any of the non-data portions into
+    its output.
+
+    This special exception to the GPL applies to versions of Autoconf
+    released by the Free Software Foundation. When you make and
+    distribute a modified version of Autoconf, you may extend this
+    special exception to the GPL to apply to your modified version as
+    well, *unless* your modified version has the potential to copy
+    into its output some of the text that was the non-data portion of
+    the version that you started with. (In other words, unless your
+    change moves or copies text from the non-data portions to the data
+    portions.) If your modification has such potential, you must
+    delete any notice of this special exception to the GPL from your
+    modified version.
+
+acx_pthread.m4 version 1.5 2004/03/01
diff --git a/mechglue/src/config/ac-archive/acx_pthread.m4 b/mechglue/src/config/ac-archive/acx_pthread.m4
new file mode 100644
index 000000000..6a1537d47
--- /dev/null
+++ b/mechglue/src/config/ac-archive/acx_pthread.m4
@@ -0,0 +1,239 @@
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl This macro figures out how to build C programs using POSIX
+dnl threads.  It sets the PTHREAD_LIBS output variable to the threads
+dnl library and linker flags, and the PTHREAD_CFLAGS output variable
+dnl to any special C compiler flags that are needed.  (The user can also
+dnl force certain compiler flags/libs to be tested by setting these
+dnl environment variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well.  e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to
+dnl use these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl        LIBS="$PTHREAD_LIBS $LIBS"
+dnl        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl        CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE
+dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands
+dnl to run it if it is not found.  If ACTION-IF-FOUND is not specified,
+dnl the default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform,
+dnl or if you have any other suggestions or comments.  This macro was
+dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org)
+dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread
+dnl macros posted by AFC to the autoconf macro repository.  We are also
+dnl grateful for the helpful feedback of numerous users.
+dnl
+dnl @version $Id: acx_pthread.m4,v 1.5 2004/03/01 19:28:29 guidod Exp $
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Alejandro Forero Cuervo <bachue@bachue.com>
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test x"$acx_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+        *solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthread or
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
+        ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+		pthread-config)
+		AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+		if test x"$acx_pthread_config" = xno; then continue; fi
+		PTHREAD_CFLAGS="`pthread-config --cflags`"
+		PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+		;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_TRY_LINK([#include <pthread.h>],
+                    [pthread_t th; pthread_join(th, 0);
+                     pthread_attr_init(0); pthread_cleanup_push(0, 0);
+                     pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+                    [acx_pthread_ok=yes])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test "x$acx_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: threads are created detached by default
+        # and the JOINABLE attribute has a nonstandard name (UNDETACHED).
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        AC_TRY_LINK([#include <pthread.h>],
+                    [int attr=PTHREAD_CREATE_JOINABLE;],
+                    ok=PTHREAD_CREATE_JOINABLE, ok=unknown)
+        if test x"$ok" = xunknown; then
+                AC_TRY_LINK([#include <pthread.h>],
+                            [int attr=PTHREAD_CREATE_UNDETACHED;],
+                            ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)
+        fi
+        if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then
+                AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok,
+                          [Define to the necessary symbol if this constant
+                           uses a non-standard name on your system.])
+        fi
+        AC_MSG_RESULT(${ok})
+        if test x"$ok" = xunknown; then
+                AC_MSG_WARN([we do not know how to create joinable pthreads])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case "${host_cpu}-${host_os}" in
+                *-aix* | *-freebsd*)     flag="-D_THREAD_SAFE";;
+                *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+                PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with cc_r
+        AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+        :
+else
+        acx_pthread_ok=no
+        $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff --git a/mechglue/src/config/config.guess b/mechglue/src/config/config.guess
new file mode 100755
index 000000000..500ee74b0
--- /dev/null
+++ b/mechglue/src/config/config.guess
@@ -0,0 +1,1410 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-10-03'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit 0 ;;
+    amiga:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    arc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    hp300:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mac68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    macppc:OpenBSD:*:*)
+	echo powerpc-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+	echo m88k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvmeppc:OpenBSD:*:*)
+	echo powerpc-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    pmax:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sgi:OpenBSD:*:*)
+	echo mipseb-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sun3:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    *:OpenBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	if test $UNAME_RELEASE = "V4.0"; then
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+	fi
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit 0 ;;
+    Alpha*:OpenVMS:*:*)
+	echo alpha-hp-vms
+	exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit 0 ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit 0;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit 0 ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit 0 ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit 0 ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit 0 ;;
+    DRS?6000:UNIX_SV:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7 && exit 0 ;;
+	esac ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    i86pc:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit 0 ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c \
+	  && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+	  && exit 0
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit 0 ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit 0 ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+	exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		$CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:[45])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    # avoid double evaluation of $set_cc_for_build
+	    test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit 0 ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    *:UNICOS/mp:*:*)
+	echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
+	# Determine whether the default compiler uses glibc.
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#if __GLIBC__ >= 2
+	LIBC=gnu
+	#else
+	LIBC=
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+	# GNU/FreeBSD systems have a "k" prefix to indicate we are using
+	# FreeBSD's kernel, but not the complete OS.
+	case ${LIBC} in gnu) kernel_only='k' ;; esac
+	echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+	exit 0 ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit 0 ;;
+    i*:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit 0 ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit 0 ;;
+    x86:Interix*:[34]*)
+	echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+	exit 0 ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit 0 ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit 0 ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit 0 ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit 0 ;;
+    arm*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit 0 ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+	test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+	test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+	;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit 0 ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit 0 ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit 0 ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit 0 ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit 0 ;;
+	  coff-i386)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit 0 ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit 0 ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#ifdef __INTEL_COMPILER
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+	test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+	test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit 0 ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit 0 ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit 0 ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit 0 ;;
+    i*86:*:5:[78]*)
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit 0 ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit 0 ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+	echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit 0 ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit 0 ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit 0 ;;
+    M68*:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit 0 ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit 0 ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit 0 ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit 0 ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit 0 ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit 0 ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Darwin:*:*)
+	case `uname -p` in
+	    *86) UNAME_PROCESSOR=i686 ;;
+	    powerpc) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit 0 ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit 0 ;;
+    NSR-[DGKLNPTVWY]:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit 0 ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit 0 ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit 0 ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit 0 ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit 0 ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit 0 ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit 0 ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit 0 ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/mechglue/src/config/config.sub b/mechglue/src/config/config.sub
new file mode 100755
index 000000000..1f31816b9
--- /dev/null
+++ b/mechglue/src/config/config.sub
@@ -0,0 +1,1510 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-08-18'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| m32r | m68000 | m68k | m88k | mcore \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| msp430 \
+	| ns16k | ns32k \
+	| openrisc | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+	| strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xscale | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* \
+	| bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| m32r-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| msp430-* \
+	| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+	| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+	| xtensa-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	mmix*)
+		basic_machine=mmix-knuth
+		os=-mmixware
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nv1)
+		basic_machine=nv1-cray
+		os=-unicosmp
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	or32 | or32-*)
+		basic_machine=or32-unknown
+		os=-coff
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparc | sparcv9 | sparcv9b)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+    c4x-* | tic4x-*)
+        os=-coff
+        ;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/mechglue/src/config/install-sh b/mechglue/src/config/install-sh
new file mode 100755
index 000000000..f5061e7e2
--- /dev/null
+++ b/mechglue/src/config/install-sh
@@ -0,0 +1,295 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2003-09-24.23
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=
+transform_arg=
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+
+usage="Usage: $0 [OPTION]... SRCFILE DSTFILE
+   or: $0 -d DIR1 DIR2...
+
+In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default.
+In the second, create the directory path DIR.
+
+Options:
+-b=TRANSFORMBASENAME
+-c         copy source (using $cpprog) instead of moving (using $mvprog).
+-d         create directories instead of installing files.
+-g GROUP   $chgrp installed files to GROUP.
+-m MODE    $chmod installed files to MODE.
+-o USER    $chown installed files to USER.
+-s         strip installed files (using $stripprog).
+-t=TRANSFORM
+--help     display this help and exit.
+--version  display version info and exit.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+  case $1 in
+    -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+        shift
+        continue;;
+
+    -c) instcmd=$cpprog
+        shift
+        continue;;
+
+    -d) dir_arg=true
+        shift
+        continue;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+        shift
+        shift
+        continue;;
+
+    --help) echo "$usage"; exit 0;;
+
+    -m) chmodcmd="$chmodprog $2"
+        shift
+        shift
+        continue;;
+
+    -o) chowncmd="$chownprog $2"
+        shift
+        shift
+        continue;;
+
+    -s) stripcmd=$stripprog
+        shift
+        continue;;
+
+    -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+        shift
+        continue;;
+
+    --version) echo "$0 $scriptversion"; exit 0;;
+
+    *)  if test -z "$src"; then
+          src=$1
+        else
+          # this colon is to work around a 386BSD /bin/sh bug
+          :
+          dst=$1
+        fi
+        shift
+        continue;;
+  esac
+done
+
+if test -z "$src"; then
+  echo "$0: no input file specified." >&2
+  exit 1
+fi
+
+# Protect names starting with `-'.
+case $src in
+  -*) src=./$src ;;
+esac
+
+if test -n "$dir_arg"; then
+  dst=$src
+  src=
+
+  if test -d "$dst"; then
+    instcmd=:
+    chmodcmd=
+  else
+    instcmd=$mkdirprog
+  fi
+else
+  # Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+  # might cause directories to be created, which would be especially bad
+  # if $src (and thus $dsttmp) contains '*'.
+  if test ! -f "$src" && test ! -d "$src"; then
+    echo "$0: $src does not exist." >&2
+    exit 1
+  fi
+
+  if test -z "$dst"; then
+    echo "$0: no destination specified." >&2
+    exit 1
+  fi
+
+  # Protect names starting with `-'.
+  case $dst in
+    -*) dst=./$dst ;;
+  esac
+
+  # If destination is a directory, append the input filename; won't work
+  # if double slashes aren't ignored.
+  if test -d "$dst"; then
+    dst=$dst/`basename "$src"`
+  fi
+fi
+
+# This sed command emulates the dirname command.
+dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+
+# Skip lots of stat calls in the usual case.
+if test ! -d "$dstdir"; then
+  defaultIFS='
+	'
+  IFS="${IFS-$defaultIFS}"
+
+  oIFS=$IFS
+  # Some sh's can't handle IFS=/ for some reason.
+  IFS='%'
+  set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+  IFS=$oIFS
+
+  pathcomp=
+
+  while test $# -ne 0 ; do
+    pathcomp=$pathcomp$1
+    shift
+    test -d "$pathcomp" || $mkdirprog "$pathcomp"
+    pathcomp=$pathcomp/
+  done
+fi
+
+if test -n "$dir_arg"; then
+  $doit $instcmd "$dst" \
+    && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+    && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+    && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+    && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+else
+  # If we're going to rename the final executable, determine the name now.
+  if test -z "$transformarg"; then
+    dstfile=`basename "$dst"`
+  else
+    dstfile=`basename "$dst" $transformbasename \
+             | sed $transformarg`$transformbasename
+  fi
+
+  # don't allow the sed command to completely eliminate the filename.
+  test -z "$dstfile" && dstfile=`basename "$dst"`
+
+  # Make a couple of temp file names in the proper directory.
+  dsttmp=$dstdir/_inst.$$_
+  rmtmp=$dstdir/_rm.$$_
+
+  # Trap to clean up those temp files at exit.
+  trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+  trap '(exit $?); exit' 1 2 13 15
+
+  # Move or copy the file name to the temp name
+  $doit $instcmd "$src" "$dsttmp" &&
+
+  # and set any options; do chmod last to preserve setuid bits.
+  #
+  # If any of these fail, we abort the whole thing.  If we want to
+  # ignore errors from any of these, just make sure not to ignore
+  # errors from the above "$doit $instcmd $src $dsttmp" command.
+  #
+  { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+    && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+    && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+    && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+
+  # Now remove or move aside any old file at destination location.  We
+  # try this two ways since rm can't unlink itself on some systems and
+  # the destination file might be busy for other reasons.  In this case,
+  # the final cleanup might fail but the new file should still install
+  # successfully.
+  {
+    if test -f "$dstdir/$dstfile"; then
+      $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+      || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+      || {
+	  echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+	  (exit 1); exit
+      }
+    else
+      :
+    fi
+  } &&
+
+  # Now rename the file to the real destination.
+  $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+fi &&
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+{
+  (exit 0); exit
+}
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/mechglue/src/config/lib.in b/mechglue/src/config/lib.in
new file mode 100644
index 000000000..760294d28
--- /dev/null
+++ b/mechglue/src/config/lib.in
@@ -0,0 +1,164 @@
+### config/lib.in
+# *** keep this in sync with libnover.in
+#
+# Makefile fragment that creates static, shared, and profiled libraries.
+#
+# The following variables must be set in the Makefile.in:
+#
+# LIBBASE	library name without "lib" or extension
+# LIBMAJOR	library major version
+# LIBMINOR	library minor version
+# STOBJLISTS	list of files, each of which is an OBJS.ST created by
+#			libobj.in; *DO NOT* use ./OBJS.ST for the current
+#			directory as that will cause some makes to lose.
+# SHLIB_EXPDEPS	list of libraries that this one has explicit
+#			dependencies on, pref. in the form libfoo$(SHLIBEXT)
+# SHLIB_EXPLIBS	list of libraries that this one has explicit
+#			dependencies on, in "-lfoo" form.
+# SHLIB_DIRS	list of directories where $(SHLIB_EXPLIBS) can be
+#			found, in the form -Ldir1 -Ldir2 ...
+#			since there are very few systems where -L is the
+#			wrong thing (notable exception of SunOS but we
+#			deal with it...)
+# SHLIB_RDIRS	rpath directories to search; given in the
+#			form dir1:dir2 ...
+# RELDIR	path to this directory relative to $(TOPLIBD)
+
+LIBPREFIX=lib
+
+# STOBJLISTS=dir1/OBJS.ST dir2/OBJS.ST etc...
+SHOBJLISTS=$(STOBJLISTS:.ST=.SH)
+PFOBJLISTS=$(STOBJLISTS:.ST=.PF)
+
+dummy-target-1 $(SUBDIROBJLISTS) $(SUBDIROBJLISTS:.ST=.SH) $(SUBDIROBJLISTS:.ST=.PF): all-recurse
+
+# Gets invoked as $(PARSE_OBJLISTS) list-of-OBJS.*-files
+PARSE_OBJLISTS= set -x && $(PERL) -p -e 'BEGIN { $$SIG{__WARN__} = sub {die @_} }; $$e=$$ARGV; $$e =~ s/OBJS\...$$//; s/^/ /; s/ $$//; s/ / $$e/g;'
+
+lib$(LIBBASE)$(STLIBEXT): $(STOBJLISTS)
+	$(RM) $@
+	@echo "building static $(LIBBASE) library"
+	set -x; objlist=`$(PARSE_OBJLISTS) $(STOBJLISTS)` && $(AR) cq $@ $$objlist
+	$(RANLIB) $@
+
+lib$(LIBBASE)$(SHLIBVEXT): $(SHOBJLISTS) $(SHLIB_EXPDEPS) $(SHLIB_EXPORT_FILE_DEP)
+	$(RM) $@
+	@echo "building shared $(LIBBASE) library ($(LIBMAJOR).$(LIBMINOR))"
+	set -x; objlist=`$(PARSE_OBJLISTS) $(SHOBJLISTS)` && $(MAKE_SHLIB_COMMAND)
+
+lib$(LIBBASE)$(SHLIBSEXT): lib$(LIBBASE)$(SHLIBVEXT)
+	$(RM) $@
+	$(LN_S) lib$(LIBBASE)$(SHLIBVEXT) $@
+lib$(LIBBASE)$(SHLIBEXT): lib$(LIBBASE)$(SHLIBVEXT)
+	$(RM) $@
+	$(LN_S) lib$(LIBBASE)$(SHLIBVEXT) $@
+
+binutils.versions: $(SHLIB_EXPORT_FILE) Makefile
+	echo >  binutils.versions "HIDDEN { local: __*; _rest*; _save*; *; };"
+	echo >> binutils.versions "$(LIBBASE)_$(LIBMAJOR)_MIT {"
+	sed  >> binutils.versions < $(SHLIB_EXPORT_FILE) "s/$$/;/"
+	echo >> binutils.versions "};"
+
+osf1.exports: $(SHLIB_EXPORT_FILE) Makefile
+	$(RM) osf1.tmp osf1.exports
+	sed "s/^/-exported_symbol /" < $(SHLIB_EXPORT_FILE) > osf1.tmp
+	for f in . $(LIBINITFUNC); do \
+	  if test "$$f" != "." ; then \
+	    echo " -init $$f"__auxinit >> osf1.tmp; \
+	  else :; fi; \
+	done
+	a=""; \
+	for f in . $(LIBFINIFUNC); do \
+	  if test "$$f" != "." ; then \
+	    a="-fini $$f $$a"; \
+	  else :; fi; \
+	done; echo " $$a" >> osf1.tmp; \
+	mv -f osf1.tmp osf1.exports
+
+hpux10.exports: $(SHLIB_EXPORT_FILE) Makefile
+	$(RM) hpux10.tmp hpux10.exports
+	sed "s/^/+e /" < $(SHLIB_EXPORT_FILE) > hpux10.tmp
+	a=""; \
+	for f in . $(LIBFINIFUNC); do \
+	  if test "$$f" != .; then \
+	    a="+I $${f}__auxfini $$a"; \
+	  else :; fi; \
+	done; echo "$$a" >> hpux10.tmp
+	echo "+e errno" >> hpux10.tmp
+	mv -f hpux10.tmp hpux10.exports
+
+lib$(LIBBASE)$(PFLIBEXT): $(PFOBJLISTS)
+	$(RM) $@
+	@echo "building profiled $(LIBBASE) library"
+	set -x; objlist=`$(PARSE_OBJLISTS) $(PFOBJLISTS)` && $(AR) cq $@ $$objlist
+	$(RANLIB) $@
+
+$(TOPLIBD)/lib$(LIBBASE)$(STLIBEXT): lib$(LIBBASE)$(STLIBEXT)
+	$(RM) $@
+	(cd $(TOPLIBD) && $(LN_S) $(RELDIR)/lib$(LIBBASE)$(STLIBEXT) .)
+$(TOPLIBD)/lib$(LIBBASE)$(SHLIBEXT): lib$(LIBBASE)$(SHLIBEXT)
+	$(RM) $@
+	(cd $(TOPLIBD) && $(LN_S) $(RELDIR)/lib$(LIBBASE)$(SHLIBEXT) .)
+$(TOPLIBD)/lib$(LIBBASE)$(SHLIBSEXT): lib$(LIBBASE)$(SHLIBSEXT)
+	$(RM) $@
+	(cd $(TOPLIBD) && $(LN_S) $(RELDIR)/lib$(LIBBASE)$(SHLIBSEXT) .)
+$(TOPLIBD)/lib$(LIBBASE)$(SHLIBVEXT): lib$(LIBBASE)$(SHLIBVEXT)
+	$(RM) $@
+	(cd $(TOPLIBD) && $(LN_S) $(RELDIR)/lib$(LIBBASE)$(SHLIBVEXT) .)
+$(TOPLIBD)/lib$(LIBBASE)$(PFLIBEXT): lib$(LIBBASE)$(PFLIBEXT)
+	$(RM) $@
+	(cd $(TOPLIBD) && $(LN_S) $(RELDIR)/lib$(LIBBASE)$(PFLIBEXT) .)
+
+all-libs: $(LIBLIST)
+all-liblinks: $(LIBLINKS)
+
+clean-libs:
+	$(RM) lib$(LIBBASE)$(STLIBEXT)
+	$(RM) lib$(LIBBASE)$(SHLIBVEXT)
+	$(RM) lib$(LIBBASE)$(SHLIBSEXT)
+	$(RM) lib$(LIBBASE)$(SHLIBEXT)
+	$(RM) lib$(LIBBASE)$(PFLIBEXT)
+	$(RM) binutils.versions osf1.exports
+
+clean-liblinks:
+	$(RM) $(TOPLIBD)/lib$(LIBBASE)$(STLIBEXT)
+	$(RM) $(TOPLIBD)/lib$(LIBBASE)$(SHLIBVEXT)
+	$(RM) $(TOPLIBD)/lib$(LIBBASE)$(SHLIBSEXT)
+	$(RM) $(TOPLIBD)/lib$(LIBBASE)$(SHLIBEXT)
+	$(RM) $(TOPLIBD)/lib$(LIBBASE)$(PFLIBEXT)
+
+install-libs: $(LIBINSTLIST)
+install-static:
+	$(RM) $(DESTDIR)$(KRB5_LIBDIR)/lib$(LIBBASE)$(STLIBEXT)
+	$(INSTALL_DATA) lib$(LIBBASE)$(STLIBEXT) $(DESTDIR)$(KRB5_LIBDIR)
+	$(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/lib$(LIBBASE)$(STLIBEXT)
+install-shared:
+	$(RM) $(DESTDIR)$(KRB5_LIBDIR)/lib$(LIBBASE)$(SHLIBVEXT)
+	$(RM) $(DESTDIR)$(KRB5_LIBDIR)/lib$(LIBBASE)$(SHLIBEXT)
+	$(INSTALL_SHLIB) lib$(LIBBASE)$(SHLIBVEXT) $(DESTDIR)$(KRB5_LIBDIR)
+	(cd $(DESTDIR)$(KRB5_LIBDIR) && $(LN_S) lib$(LIBBASE)$(SHLIBVEXT) \
+		lib$(LIBBASE)$(SHLIBEXT))
+install-shlib-soname: install-shared
+	$(RM) $(DESTDIR)$(KRB5_LIBDIR)/lib$(LIBBASE)$(SHLIBSEXT)
+	(cd $(DESTDIR)$(KRB5_LIBDIR) && $(LN_S) lib$(LIBBASE)$(SHLIBVEXT) \
+		lib$(LIBBASE)$(SHLIBSEXT))
+install-profiled:
+	$(RM) $(DESTDIR)$(KRB5_LIBDIR)/lib$(LIBBASE)$(PFLIBEXT)
+	$(INSTALL_DATA) lib$(LIBBASE)$(PFLIBEXT) $(DESTDIR)$(KRB5_LIBDIR)
+	$(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/lib$(LIBBASE)$(PFLIBEXT)
+
+Makefile: $(SRCTOP)/config/lib.in
+$(thisconfigdir)/config.status: $(SRCTOP)/config/shlib.conf
+
+# Use the following if links need to be made to $(TOPLIBD):
+# all-unix:: all-liblinks
+# install-unix:: install-libs
+# clean-unix:: clean-liblinks clean-libs
+
+# Use the following if links need not be made:
+# all-unix:: all-libs
+# install-unix:: install-libs
+# clean-unix:: clean-libs
+
+###
+### end config/lib.in
diff --git a/mechglue/src/config/libnover.in b/mechglue/src/config/libnover.in
new file mode 100644
index 000000000..3896e8462
--- /dev/null
+++ b/mechglue/src/config/libnover.in
@@ -0,0 +1,112 @@
+### config/libnover.in
+# *** keep this in sync with lib.in
+#
+# Makefile fragment that creates shared libraries sans version
+# info (plugin modules).
+#
+# The following variables must be set in the Makefile.in:
+#
+# LIBBASE	library name without "lib" or extension
+# STOBJLISTS	list of files, each of which is an OBJS.ST created by
+#			libobj.in; *DO NOT* use ./OBJS.ST for the current
+#			directory as that will cause some makes to lose.
+# SHLIB_EXPDEPS	list of libraries that this one has explicit
+#			dependencies on, pref. in the form libfoo$(SHLIBEXT)
+# SHLIB_EXPLIBS	list of libraries that this one has explicit
+#			dependencies on, in "-lfoo" form.
+# SHLIB_DIRS	list of directories where $(SHLIB_EXPLIBS) can be
+#			found, in the form -Ldir1 -Ldir2 ...
+#			since there are very few systems where -L is the
+#			wrong thing (notable exception of SunOS but we
+#			deal with it...)
+# SHLIB_RDIRS	rpath directories to search; given in the
+#			form dir1:dir2 ...
+# RELDIR	path to this directory relative to $(TOPLIBD)
+
+LIBPREFIX=
+
+# STOBJLISTS=dir1/OBJS.ST dir2/OBJS.ST etc...
+SHOBJLISTS=$(STOBJLISTS:.ST=.SH)
+
+dummy-target-1 $(SUBDIROBJLISTS) $(SUBDIROBJLISTS:.ST=.SH) $(SUBDIROBJLISTS:.ST=.PF): all-recurse
+
+# Gets invoked as $(PARSE_OBJLISTS) list-of-OBJS.*-files
+PARSE_OBJLISTS= set -x && $(PERL) -p -e 'BEGIN { $$SIG{__WARN__} = sub {die @_} }; $$e=$$ARGV; $$e =~ s/OBJS\...$$//; s/^/ /; s/ $$//; s/ / $$e/g;'
+
+SHLIBVEXT=$(SHLIBEXT)
+LIBLIST=$(LIBBASE)$(DYNOBJEXT)
+LIBINSTLIST=install-shared
+
+$(LIBBASE)$(DYNOBJEXT): $(SHOBJLISTS) $(DYNOBJ_EXPDEPS) $(SHLIB_EXPORT_FILE_DEP)
+	$(RM) $@
+	@echo "building dynamic $(LIBBASE) object"
+	set -x; objlist=`$(PARSE_OBJLISTS) $(SHOBJLISTS)` && $(MAKE_DYNOBJ_COMMAND)
+
+binutils.versions: $(SHLIB_EXPORT_FILE) Makefile
+	echo >  binutils.versions "HIDDEN { local: __*; _rest*; _save*; *; };"
+	echo >> binutils.versions "$(LIBBASE)_$(LIBMAJOR)_MIT {"
+	sed  >> binutils.versions < $(SHLIB_EXPORT_FILE) "s/$$/;/"
+	echo >> binutils.versions "};"
+
+osf1.exports: $(SHLIB_EXPORT_FILE) Makefile
+	$(RM) osf1.tmp osf1.exports
+	sed "s/^/-exported_symbol /" < $(SHLIB_EXPORT_FILE) > osf1.tmp
+	for f in . $(LIBINITFUNC); do \
+	  if test "$$f" != "." ; then \
+	    echo " -init $$f"__auxinit >> osf1.tmp; \
+	  else :; fi; \
+	done
+	a=""; \
+	for f in . $(LIBFINIFUNC); do \
+	  if test "$$f" != "." ; then \
+	    a="-fini $$f $$a"; \
+	  else :; fi; \
+	done; echo " $$a" >> osf1.tmp; \
+	mv -f osf1.tmp osf1.exports
+
+hpux10.exports: $(SHLIB_EXPORT_FILE) Makefile
+	$(RM) hpux10.tmp hpux10.exports
+	sed "s/^/+e /" < $(SHLIB_EXPORT_FILE) > hpux10.tmp
+	a=""; \
+	for f in . $(LIBFINIFUNC); do \
+	  if test "$$f" != .; then \
+	    a="+I $${f}__auxfini $$a"; \
+	  else :; fi; \
+	done; echo "$$a" >> hpux10.tmp
+	echo "+e errno" >> hpux10.tmp
+	mv -f hpux10.tmp hpux10.exports
+
+darwin.exports: $(SHLIB_EXPORT_FILE) Makefile
+	$(RM) darwin.exports
+	sed "s/^/_/" < $(SHLIB_EXPORT_FILE) > darwin.exports
+
+$(TOPLIBD)/$(LIBBASE)$(SHLIBEXT): $(LIBBASE)$(SHLIBEXT)
+	$(RM) $@
+	(cd $(TOPLIBD) && $(LN_S) $(RELDIR)/$(LIBBASE)$(SHLIBEXT) .)
+
+all-libs: $(LIBBASE)$(DYNOBJEXT) # $(LIBLIST)
+
+clean-libs:
+	$(RM) $(LIBBASE)$(SHLIBEXT)
+	$(RM) binutils.versions osf1.exports
+
+install-libs: $(LIBINSTLIST)
+install-shared:
+	$(RM) $(DESTDIR)$(KRB5_DB_MODULE_DIR)/$(LIBBASE)$(DYNOBJEXT)
+	$(INSTALL_SHLIB) $(LIBBASE)$(DYNOBJEXT) $(DESTDIR)$(KRB5_DB_MODULE_DIR)
+
+Makefile: $(SRCTOP)/config/libnover.in
+$(thisconfigdir)/config.status: $(SRCTOP)/config/shlib.conf
+
+# Use the following if links need to be made to $(TOPLIBD):
+# all-unix:: all-liblinks
+# install-unix:: install-libs
+# clean-unix:: clean-liblinks clean-libs
+
+# Use the following if links need not be made:
+# all-unix:: all-libs
+# install-unix:: install-libs
+# clean-unix:: clean-libs
+
+###
+### end config/libnovers.in
diff --git a/mechglue/src/config/libobj.in b/mechglue/src/config/libobj.in
new file mode 100644
index 000000000..19cf2546e
--- /dev/null
+++ b/mechglue/src/config/libobj.in
@@ -0,0 +1,39 @@
+### config/libobj.in
+#
+# Makefile fragment that builds object files for libraries.
+#
+# The following variables must be set in Makefile.in:
+#
+# STLIBOBJS	list of .o objects; this must not contain variable
+#		references.
+
+.SUFFIXES: .c .so .po
+.c.so:
+	$(CC) $(PICFLAGS) -DSHARED $(ALL_CFLAGS) -c $< -o $*.so.o && $(MV) $*.so.o $*.so
+.c.po:
+	$(CC) $(PROFFLAGS) $(ALL_CFLAGS) -c $< -o $*.po.o && $(MV) $*.po.o $*.po
+
+# rules to generate object file lists
+
+OBJS.ST: $(STLIBOBJS) Makefile
+	@echo $(STLIBOBJS) > $@
+
+OBJS.SH: $(SHLIBOBJS) Makefile
+	@echo $(SHLIBOBJS) > $@
+
+OBJS.PF: $(PFLIBOBJS) Makefile
+	@echo $(PFLIBOBJS) > $@
+
+all-libobjs: $(OBJLISTS)
+
+clean-libobjs:
+	$(RM) OBJS.ST OBJS.SH OBJS.PF $(STLIBOBJS) $(SHLIBOBJS) $(PFLIBOBJS)
+
+Makefile: $(SRCTOP)/config/libobj.in
+config.status: $(SRCTOP)/config/shlib.conf
+
+# clean-unix:: clean-libobjs
+# all-unix:: all-libobjs
+
+###
+### end config/libobj.in
diff --git a/mechglue/src/config/mkinstalldirs b/mechglue/src/config/mkinstalldirs
new file mode 100755
index 000000000..6b3b5fc5d
--- /dev/null
+++ b/mechglue/src/config/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/mechglue/src/config/move-if-changed b/mechglue/src/config/move-if-changed
new file mode 100755
index 000000000..21403e129
--- /dev/null
+++ b/mechglue/src/config/move-if-changed
@@ -0,0 +1,17 @@
+#!/bin/sh
+# Move file 1 to file 2 if they don't already match.
+# Good for "make depend" for example, where it'd be nice to keep the
+# old datestamp.
+if [ $# != 2 ]; then
+  echo 2>&1 usage: $0 newfile oldfilename
+  exit 1
+fi
+#
+if [ ! -r "$2" ]; then
+  exec mv -f "$1" "$2"
+fi
+if cmp "$1" "$2" >/dev/null; then
+  echo "$2 is unchanged"
+  exec rm -f "$1"
+fi
+exec mv -f "$1" "$2"
diff --git a/mechglue/src/config/post.in b/mechglue/src/config/post.in
new file mode 100644
index 000000000..35cc91a76
--- /dev/null
+++ b/mechglue/src/config/post.in
@@ -0,0 +1,183 @@
+############################################################
+## config/post.in
+##
+
+# in case there is no default target (very unlikely)
+all::
+
+check-windows::
+
+##############################
+# dependency generation
+#
+
+depend:: depend-postrecurse
+depend-postrecurse: depend-recurse
+depend-recurse: depend-prerecurse
+
+depend-prerecurse:
+depend-postrecurse:
+
+depend-postrecurse: depend-update-makefile
+
+ALL_DEP_SRCS= $(SRCS) $(EXTRADEPSRCS)
+
+# be sure to check ALL_DEP_SRCS against *what it would be if SRCS and
+# EXTRADEPSRCS are both empty*
+$(BUILDTOP)/.depend-verify-srcdir:
+	@if test "$(srcdir)" = "." ; then \
+		echo 1>&2 error: cannot build dependencies with srcdir=. ; \
+		echo 1>&2 "(can't distinguish generated files from source files)" ; \
+		exit 1 ; \
+	else \
+		if test -r $(BUILDTOP)/.depend-verify-srcdir; then :; \
+			else (set -x; touch $(BUILDTOP)/.depend-verify-srcdir); fi \
+	fi
+$(BUILDTOP)/.depend-verify-et: depend-verify-et-$(COM_ERR_VERSION)
+depend-verify-et-k5:
+	@if test -r $(BUILDTOP)/.depend-verify-et; then :; \
+		else (set -x; touch $(BUILDTOP)/.depend-verify-et); fi
+depend-verify-et-sys:
+	@echo 1>&2 error: cannot build dependencies using system et package
+	@exit 1
+$(BUILDTOP)/.depend-verify-ss: depend-verify-ss-$(SS_VERSION)
+depend-verify-ss-k5:
+	@if test -r $(BUILDTOP)/.depend-verify-ss; then :; \
+		else (set -x; touch $(BUILDTOP)/.depend-verify-ss); fi
+depend-verify-ss-sys:
+	@echo 1>&2 error: cannot build dependencies using system ss package
+	@exit 1
+$(BUILDTOP)/.depend-verify-gcc: depend-verify-gcc-@HAVE_GCC@
+depend-verify-gcc-yes:
+	@if test -r $(BUILDTOP)/.depend-verify-gcc; then :; \
+		else (set -x; touch $(BUILDTOP)/.depend-verify-gcc); fi
+depend-verify-gcc-no:
+	@echo 1>&2 error: The '"depend"' rules are written for gcc.
+	@echo 1>&2 Please use gcc, or update the rules to handle your compiler.
+	@exit 1
+
+DEP_CFG_VERIFY = $(BUILDTOP)/.depend-verify-srcdir \
+	$(BUILDTOP)/.depend-verify-et $(BUILDTOP)/.depend-verify-ss
+DEP_VERIFY = $(DEP_CFG_VERIFY) $(BUILDTOP)/.depend-verify-gcc
+
+.d: $(ALL_DEP_SRCS) $(DEP_CFG_VERIFY) depend-dependencies
+	if test "$(ALL_DEP_SRCS)" != " " ; then \
+		$(RM) .dtmp && $(MAKE) .dtmp && mv -f .dtmp .d ; \
+	else \
+		touch .d ; \
+	fi
+
+# These are dependencies of the depend target that do not get fed to
+# the compiler.  Examples include generated header files.
+depend-dependencies:
+
+# .dtmp must *always* be out of date so that $? can be used to perform
+# VPATH searches on the sources.
+#
+# NOTE: This will fail when using Make programs whose VPATH support is
+# broken.
+.dtmp: $(ALL_DEP_SRCS)
+	$(CC) -M -DDEPEND $(ALL_CFLAGS) $? > .dtmp
+
+# NOTE: This will also generate spurious $(OUTPRE) and $(OBJEXT)
+# references in rules for non-library objects in a directory where
+# library objects happen to be built.  It's mostly harmless.
+.depend: .d $(SRCTOP)/util/depfix.pl
+	x=`$(CC) -print-libgcc-file-name` ; \
+	perl $(SRCTOP)/util/depfix.pl \
+		'$(SRCTOP)' '$(myfulldir)' '$(srcdir)' '$(BUILDTOP)' "$$x" '$(STLIBOBJS)' \
+		< .d > .depend
+
+depend-update-makefile: .depend depend-recurse
+	if test -n "$(SRCS)" ; then \
+		sed -e '/^# +++ Dependency line eater +++/,$$d' \
+			< $(srcdir)/Makefile.in | cat - .depend \
+			> $(srcdir)/Makefile.in.new; \
+	$(SRCTOP)/config/move-if-changed $(srcdir)/Makefile.in.new $(srcdir)/Makefile.in ; \
+	else :; fi
+
+DEPTARGETS = .depend .d .dtmp $(DEP_VERIFY)
+
+#
+# end dependency generation
+##############################
+
+clean:: clean-$(WHAT)
+
+clean-unix::
+	$(RM) $(OBJS) $(DEPTARGETS) $(EXTRA_FILES)
+	-$(RM) -r $(srcdir)/$(thisconfigdir)/autom4te.cache
+
+clean-windows::
+	$(RM) *.$(OBJEXT)
+	$(RM) msvc.pdb *.err
+
+distclean:: distclean-$(WHAT)
+
+distclean-normal-clean:
+	$(MAKE) NORECURSE=true clean
+distclean-prerecurse: distclean-normal-clean
+distclean-nuke-configure-state:
+	$(RM) config.log config.cache config.status Makefile
+distclean-postrecurse: distclean-nuke-configure-state
+
+Makefiles-prerecurse: Makefile
+
+# thisconfigdir = relative path from this Makefile to config.status
+# mydir = relative path from config.status to this Makefile
+Makefile: $(srcdir)/Makefile.in $(thisconfigdir)/config.status \
+		$(SRCTOP)/config/pre.in $(SRCTOP)/config/post.in
+	cd $(thisconfigdir) && $(SHELL) config.status $(mydir)/Makefile
+$(thisconfigdir)/config.status: $(srcdir)/$(thisconfigdir)/configure
+	cd $(thisconfigdir) && $(SHELL) config.status --recheck
+# autom4te.cache supposedly improves performance with multiple runs, but
+# it breaks across versions, and around MIT we've got plenty of version
+# mixing.  So nuke it.
+$(srcdir)/$(thisconfigdir)/configure: @MAINT@ \
+		$(srcdir)/$(thisconfigdir)/configure.in \
+		$(SRCTOP)/patchlevel.h \
+		$(SRCTOP)/aclocal.m4
+	-$(RM) -r $(srcdir)/$(thisconfigdir)/autom4te.cache
+	cd $(srcdir)/$(thisconfigdir) && \
+		$(AUTOCONF) --include=$(CONFIG_RELTOPDIR) $(AUTOCONFFLAGS)
+	-$(RM) -r $(srcdir)/$(thisconfigdir)/autom4te.cache
+
+RECURSE_TARGETS=all-recurse clean-recurse distclean-recurse install-recurse \
+	check-recurse depend-recurse Makefiles-recurse install-headers-recurse
+
+# MY_SUBDIRS overrides any setting of SUBDIRS generated by the
+# configure script that generated this Makefile.  This is needed when
+# the configure script that produced this Makefile creates multiple
+# Makefiles in different directories; the setting of SUBDIRS will be
+# the same in each.
+#
+# LOCAL_SUBDIRS seems to account for the case where the configure
+# script doesn't call any other subsidiary configure scripts, but
+# generates multiple Makefiles.
+$(RECURSE_TARGETS):
+	@case "`echo 'x$(MFLAGS)'|sed -e 's/^x//' -e 's/ --.*$$//'`" \
+		in *[ik]*) e="status=1" ;; *) e="exit 1";; esac; \
+	do_subdirs="$(SUBDIRS)" ; \
+	status=0; \
+	if test -n "$$do_subdirs" && test -z "$(NORECURSE)"; then \
+	for i in $$do_subdirs ; do \
+		if test -d $$i && test -r $$i/Makefile ; then \
+		case $$i in .);; *) \
+			target=`echo $@|sed s/-recurse//`; \
+			echo "making $$target in $(CURRENT_DIR)$$i..."; \
+			if (cd $$i ; $(MAKE) \
+			    CURRENT_DIR=$(CURRENT_DIR)$$i/ $$target) then :; \
+			else eval $$e; fi; \
+			;; \
+		esac; \
+		else \
+			echo "Skipping missing directory $(CURRENT_DIR)$$i" ; \
+		fi; \
+	done; \
+	else :; \
+	fi;\
+	exit $$status
+
+##
+## end of post.in
+############################################################
diff --git a/mechglue/src/config/pre.in b/mechglue/src/config/pre.in
new file mode 100644
index 000000000..2dcba6c2c
--- /dev/null
+++ b/mechglue/src/config/pre.in
@@ -0,0 +1,546 @@
+############################################################
+## config/pre.in
+## common prefix for all Makefile.in in the Kerberos V5 tree.
+##
+
+# These are set per-directory by autoconf 2.52 and 2.53:
+#  srcdir=@srcdir@
+#  top_srcdir=@top_srcdir@
+# but these are only set by autoconf 2.53, and thus not useful to us on
+# Mac OS X yet (as of 10.2):
+#  abs_srcdir=@abs_srcdir@
+#  abs_top_srcdir=@abs_top_srcdir@
+#  builddir=@builddir@
+#  abs_builddir=@abs_builddir@
+#  top_builddir=@top_builddir@
+#  abs_top_builddir=@abs_top_builddir@
+# The "top" variables refer to the directory with the configure (or
+# config.status) script.
+
+WHAT = unix
+SHELL=/bin/sh
+
+all:: all-$(WHAT)
+
+clean:: clean-$(WHAT)
+
+distclean:: distclean-$(WHAT)
+
+install:: install-$(WHAT)
+
+check:: check-$(WHAT)
+
+install-headers:: install-headers-$(WHAT)
+
+##############################
+# Recursion rule support
+#
+
+# The commands for the recursion targets live in config/post.in.
+#
+# General form of recursion rules:
+#
+# Each recursive target foo-unix has related targets: foo-prerecurse,
+# foo-recurse, and foo-postrecurse
+#
+# The foo-recurse rule is in post.in.  It is what actually recursively
+# calls make.
+#
+# foo-recurse depends on foo-prerecurse, so any targets that must be
+# built before descending into subdirectories must be dependencies of
+# foo-prerecurse.
+#
+# foo-postrecurse depends on foo-recurse, but targets that must be
+# built after descending into subdirectories should be have
+# foo-recurse as dependencies in addition to being listed under
+# foo-postrecurse, to avoid ordering issues.
+#
+# The foo-prerecurse, foo-recurse, and foo-postrecurse rules are all
+# single-colon rules, to avoid nasty ordering problems with
+# double-colon rules.
+#
+# e.g.
+# all:: includes foo
+# foo:
+#	echo foo
+# includes::
+#	echo bar
+# includes::
+#	echo baz
+#
+# will result in "bar", "foo", "baz" on AIX, and possibly others.
+all-unix:: all-postrecurse
+all-postrecurse: all-recurse
+all-recurse: all-prerecurse
+
+all-prerecurse:
+all-postrecurse:
+
+clean-unix:: clean-postrecurse
+clean-postrecurse: clean-recurse
+clean-recurse: clean-prerecurse
+
+clean-prerecurse:
+clean-postrecurse:
+
+distclean-unix: distclean-postrecurse
+distclean-postrecurse: distclean-recurse
+distclean-recurse: distclean-prerecurse
+
+distclean-prerecurse:
+distclean-postrecurse:
+
+install-unix:: install-postrecurse
+install-postrecurse: install-recurse
+install-recurse: install-prerecurse
+
+install-prerecurse:
+install-postrecurse:
+
+install-headers-unix:: install-headers-postrecurse
+install-headers-postrecurse: install-headers-recurse
+install-headers-recurse: install-headers-prerecurse
+
+install-headers-prerecurse:
+install-headers-postrecurse:
+
+check-unix:: check-postrecurse
+check-postrecurse: check-recurse
+check-recurse: check-prerecurse
+
+check-prerecurse:
+check-postrecurse:
+
+Makefiles: Makefiles-postrecurse
+Makefiles-postrecurse: Makefiles-recurse
+Makefiles-recurse: Makefiles-prerecurse
+
+Makefiles-prerecurse:
+Makefiles-postrecurse:
+
+#
+# end recursion rule support
+##############################
+
+# Directory syntax:
+#
+# begin relative path
+REL=
+# this is magic... should only be used for preceding a program invocation
+C=./
+# "/" for UNIX, "\" for Windows; *sigh*
+S=/
+
+#SUBDIRS = @subdirs@ $(LOCAL_SUBDIRS)
+SUBDIRS_@top_srcdir@ = @subdirs@
+SUBDIRS = $(SUBDIRS_@srcdir@) $(LOCAL_SUBDIRS)
+#
+srcdir = @srcdir@
+SRCTOP = @srcdir@/$(BUILDTOP)
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+CONFIG_RELTOPDIR = @CONFIG_RELTOPDIR@
+
+FAKEDEST=$(BUILDTOP)/util/fakedest
+FAKEPREFIX=$(FAKEDEST)/$(prefix)
+FAKELIBDIR=$(FAKEPREFIX)/lib
+
+# DEFS		set by configure
+# DEFINES	set by local Makefile.in
+# LOCALINCLUDES	set by local Makefile.in
+# CPPFLAGS	user override
+# CFLAGS	user override but starts off set by configure
+# PTHREAD_CFLAGS set by configure, not included in CFLAGS so that we
+#		don't pull the pthreads library into shared libraries
+ALL_CFLAGS = $(DEFS) $(DEFINES) $(KRB_INCLUDES) $(LOCALINCLUDES) \
+	$(CPPFLAGS) $(CFLAGS) $(PTHREAD_CFLAGS)
+
+CFLAGS = @CFLAGS@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+THREAD_LINKOPTS = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+CC = @CC@
+LD = $(PURE) @LD@
+DEPLIBS = @DEPLIBS@
+KRB_INCLUDES = -I$(BUILDTOP)/include -I$(SRCTOP)/include \
+	-I$(BUILDTOP)/include/krb5 -I$(SRCTOP)/include/krb5
+LDFLAGS = @LDFLAGS@
+LD_UNRESOLVED_PREFIX = @LD_UNRESOLVED_PREFIX@
+LD_SHLIBDIR_PREFIX = @LD_SHLIBDIR_PREFIX@
+LDARGS = @LDARGS@
+LIBS = @LIBS@
+SRVLIBS = @SRVLIBS@
+SRVDEPLIBS = @SRVDEPLIBS@
+CLNTLIBS = @CLNTLIBS@
+CLNTDEPLIBS = @CLNTDEPLIBS@
+
+INSTALL=@INSTALL@
+INSTALL_STRIP=
+INSTALL_PROGRAM=@INSTALL_PROGRAM@ $(INSTALL_STRIP)
+INSTALL_SCRIPT=@INSTALL_PROGRAM@
+INSTALL_DATA=@INSTALL_DATA@
+INSTALL_SHLIB=@INSTALL_SHLIB@
+INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755 -o root
+## This is needed because autoconf will sometimes define @exec_prefix@ to be
+## ${prefix}.
+prefix=@prefix@
+INSTALL_PREFIX=$(prefix)
+INSTALL_EXEC_PREFIX=@exec_prefix@
+exec_prefix=@exec_prefix@
+SHLIB_TAIL_COMP=@SHLIB_TAIL_COMP@
+
+datadir = @datadir@
+EXAMPLEDIR = $(datadir)/examples/krb5
+
+KRB5MANROOT = @mandir@
+ADMIN_BINDIR = @sbindir@
+SERVER_BINDIR = @sbindir@
+CLIENT_BINDIR =@bindir@
+ADMIN_MANDIR = $(KRB5MANROOT)/man8
+SERVER_MANDIR = $(KRB5MANROOT)/man8
+CLIENT_MANDIR = $(KRB5MANROOT)/man1
+FILE_MANDIR = $(KRB5MANROOT)/man5
+KRB5_LIBDIR = @libdir@
+KRB5_SHLIBDIR = @libdir@$(SHLIB_TAIL_COMP)
+KRB5_INCDIR = @includedir@
+KRB5_DB_MODULE_DIR = @libdir@/db-modules
+KRB5_INCSUBDIRS = \
+	$(KRB5_INCDIR)/gssapi \
+	$(KRB5_INCDIR)/kerberosIV \
+	$(KRB5_INCDIR)/gssrpc
+
+#
+# Macros used by the KADM5 (OV-based) unit test system.
+# XXX check which of these are actually used!
+#
+TESTDIR		= $(BUILDTOP)/kadmin/testing
+STESTDIR	= $(SRCTOP)/kadmin/testing
+COMPARE_DUMP	= $(TESTDIR)/scripts/compare_dump.pl
+FIX_CONF_FILES	= $(TESTDIR)/scripts/fixup-conf-files.pl
+INITDB		= $(STESTDIR)/scripts/init_db
+MAKE_KEYTAB	= $(TESTDIR)/scripts/make-host-keytab.pl
+LOCAL_MAKE_KEYTAB= $(TESTDIR)/scripts/make-host-keytab.pl
+RESTORE_FILES	= $(STESTDIR)/scripts/restore_files.sh
+SAVE_FILES	= $(STESTDIR)/scripts/save_files.sh
+ENV_SETUP	= $(TESTDIR)/scripts/env-setup.sh
+CLNTTCL		= $(TESTDIR)/util/ovsec_kadm_clnt_tcl
+SRVTCL		= $(TESTDIR)/util/ovsec_kadm_srv_tcl
+# Dejagnu variables.
+# We have to set the host with --host so that setup_xfail will work.
+# If we don't set it, then the host type used is "native", which
+# doesn't match "*-*-*".
+host=@krb5_cv_host@
+DEJAFLAGS	= $(DEJALFLAGS) $(CLFLAGS) --debug --srcdir $(srcdir) --host \
+		   $(host)
+RUNTEST		= runtest $(DEJAFLAGS)
+
+START_SERVERS	= $(STESTDIR)/scripts/start_servers $(TEST_SERVER) $(TEST_PATH)
+START_SERVERS_LOCAL = $(STESTDIR)/scripts/start_servers_local
+
+STOP_SERVERS	= $(STESTDIR)/scripts/stop_servers $(TEST_SERVER) $(TEST_PATH)
+STOP_SERVERS_LOCAL = $(STESTDIR)/scripts/stop_servers_local
+#
+# End of macros for the KADM5 unit test system.
+#
+
+transform = @program_transform_name@
+
+RM = rm -f
+CP  = cp
+MV = mv -f
+CHMOD=chmod
+RANLIB = @RANLIB@
+ARCHIVE = @ARCHIVE@
+ARADD = @ARADD@
+LN = @LN_S@
+AWK = @AWK@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+YACC = @YACC@
+PERL = @PERL@
+AUTOCONF = autoconf
+AUTOCONFFLAGS =
+AUTOHEADER = autoheader
+AUTOHEADERFLAGS =
+
+HOST_TYPE = @HOST_TYPE@
+SHEXT = @SHEXT@
+STEXT=@STEXT@
+VEXT=@VEXT@
+
+TOPLIBD = $(BUILDTOP)/lib
+
+OBJEXT = o
+LIBEXT = a
+EXEEXT =
+
+#
+# variables for libraries, for use in linking programs
+# -- this may want to get broken out into a separate frag later
+#
+#
+# Note: the following variables must be set in any Makefile.in that
+# uses KRB5_BUILD_PROGRAM
+#
+# PROG_LIBPATH	list of dirs, in -Ldir form, to search for libraries at link
+# PROG_RPATH	list of dirs, in dir1:dir2 form, for rpath purposes
+#
+# invocation is like:
+# prog: foo.o bar.o $(KRB5_BASE_DEPLIBS)
+# 	$(CC_LINK) -o $@ foo.o bar.o $(KRB5_BASE_LIBS)
+
+
+CC_LINK=@CC_LINK@
+
+# prefix (with no spaces after) for rpath flag to cc
+RPATH_FLAG=@RPATH_FLAG@
+
+# this gets set by configure to either $(STLIBEXT) or $(SHLIBEXT),
+# depending on whether we're building with shared libraries.
+DEPLIBEXT=@DEPLIBEXT@
+
+KADMCLNT_DEPLIB	= $(TOPLIBD)/libkadm5clnt$(DEPLIBEXT)
+KADMSRV_DEPLIB	= $(TOPLIBD)/libkadm5srv$(DEPLIBEXT)
+KDB5_DEPLIB	= $(TOPLIBD)/libkdb5$(DEPLIBEXT)
+GSSRPC_DEPLIB	= $(TOPLIBD)/libgssrpc$(DEPLIBEXT)
+GSS_DEPLIB	= $(TOPLIBD)/libgssapi_krb5$(DEPLIBEXT)
+KRB4_DEPLIB	= @KRB4_DEPLIB@		# $(TOPLIBD)/libkrb4$(DEPLIBEXT)
+DES425_DEPLIB	= @DES425_DEPLIB@	# $(TOPLIBD)/libdes425$(DEPLIBEXT)
+KRB5_DEPLIB	= $(TOPLIBD)/libkrb5$(DEPLIBEXT)
+CRYPTO_DEPLIB	= $(TOPLIBD)/libk5crypto$(DEPLIBEXT)
+COM_ERR_DEPLIB	= $(COM_ERR_DEPLIB-@COM_ERR_VERSION@)
+COM_ERR_DEPLIB-sys = # empty
+COM_ERR_DEPLIB-k5 = $(TOPLIBD)/libcom_err$(DEPLIBEXT)
+SUPPORT_LIBNAME=krb5support
+SUPPORT_DEPLIB	= $(TOPLIBD)/lib$(SUPPORT_LIBNAME)$(DEPLIBEXT)
+
+# These are forced to use ".a" as an extension because they're never
+# built shared.
+SS_DEPLIB	= $(SS_DEPLIB-@SS_VERSION@)
+SS_DEPLIB-k5	= $(TOPLIBD)/libss.a
+SS_DEPLIB-sys	=
+PTY_DEPLIB	= $(TOPLIBD)/libpty.a
+APPUTILS_DEPLIB	= $(TOPLIBD)/libapputils.a
+
+KRB5_BASE_DEPLIBS	= $(KRB5_DEPLIB) $(CRYPTO_DEPLIB) $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
+KRB4COMPAT_DEPLIBS	= $(KRB4_DEPLIB) $(DES425_DEPLIB) $(KRB5_BASE_DEPLIBS)
+KDB5_DEPLIBS		= $(KDB5_DEPLIB)
+GSS_DEPLIBS		= $(GSS_DEPLIB)
+GSSRPC_DEPLIBS		= $(GSSRPC_DEPLIB) $(GSS_DEPLIBS)
+KADM_COMM_DEPLIBS	= $(GSSRPC_DEPLIBS) $(KDB5_DEPLIBS) $(GSSRPC_DEPLIBS)
+KADMSRV_DEPLIBS		= $(KADMSRV_DEPLIB) $(KDB5_DEPLIBS) $(KADM_COMM_DEPLIBS)
+KADMCLNT_DEPLIBS	= $(KADMCLNT_DEPLIB) $(KADM_COMM_DEPLIBS)
+
+# Header file dependencies we might override.
+# See util/depfix.sed.
+# Also see depend-verify-* in post.in, which wants to confirm that we're using
+# the in-tree versions.
+COM_ERR_VERSION = @COM_ERR_VERSION@
+COM_ERR_DEPS	= $(COM_ERR_DEPS-@COM_ERR_VERSION@)
+COM_ERR_DEPS-sys =
+COM_ERR_DEPS-k5	= $(BUILDTOP)/include/com_err.h
+SS_VERSION	= @SS_VERSION@
+SS_DEPS		= $(SS_DEPS-@SS_VERSION@)
+SS_DEPS-sys	=
+SS_DEPS-k5	= $(BUILDTOP)/include/ss/ss.h $(BUILDTOP)/include/ss/ss_err.h
+
+# Header file dependencies that might depend on whether krb4 support
+# is compiled.
+
+KRB_ERR_H_DEP	= @KRB_ERR_H_DEP@
+
+# LIBS gets substituted in... e.g. -lnsl -lsocket
+
+# GEN_LIB is -lgen if needed for regexp
+GEN_LIB		= @GEN_LIB@
+
+SS_LIB		= $(SS_LIB-@SS_VERSION@)
+SS_LIB-sys	= @SS_LIB@
+SS_LIB-k5	= $(TOPLIBD)/libss.a
+KDB5_LIB	= -lkdb5
+
+DL_LIB		= @DL_LIB@
+
+KRB5_LIB			= -lkrb5
+K5CRYPTO_LIB			= -lk5crypto
+COM_ERR_LIB			= -lcom_err
+GSS_KRB5_LIB			= -lgssapi_krb5
+SUPPORT_LIB			= -l$(SUPPORT_LIBNAME)
+
+# KRB4_LIB is -lkrb4 if building --with-krb4
+# needs fixing if ever used on Mac OS X!
+KRB4_LIB	= @KRB4_LIB@
+
+# DES425_LIB is -ldes425 if building --with-krb4
+# needs fixing if ever used on Mac OS X!
+DES425_LIB	= @DES425_LIB@
+
+# HESIOD_LIBS is -lhesiod...
+HESIOD_LIBS	= @HESIOD_LIBS@
+
+KRB5_BASE_LIBS	= $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_LIB) $(LIBS)
+KRB4COMPAT_LIBS	= $(KRB4_LIB) $(DES425_LIB) $(KRB5_BASE_LIBS)
+KDB5_LIBS	= $(KDB5_LIB)
+GSS_LIBS	= $(GSS_KRB5_LIB)
+# needs fixing if ever used on Mac OS X!
+GSSRPC_LIBS	= -lgssrpc $(GSS_LIBS)
+KADM_COMM_LIBS	= $(GSSRPC_LIBS)
+# need fixing if ever used on Mac OS X!
+KADMSRV_LIBS	= -lkadm5srv $(HESIOD_LIBS) $(KDB5_LIBS) $(KADM_COMM_LIBS)
+KADMCLNT_LIBS	= -lkadm5clnt $(KADM_COMM_LIBS)
+
+# need fixing if ever used on Mac OS X!
+PTY_LIB		= -lpty
+
+# libutil for NetBSD, et al. for openpty(), etc.
+UTIL_LIB	= @UTIL_LIB@
+
+# Misc stuff for linking server programs (and maybe some others,
+# eventually) but which we don't want to install.
+APPUTILS_LIB	= -lapputils
+
+#
+# some more stuff for --with-krb4
+KRB4_LIBPATH	= @KRB4_LIBPATH@
+KRB4_INCLUDES	= @KRB4_INCLUDES@
+
+#
+# variables for --with-tcl=
+TCL_LIBS	= @TCL_LIBS@
+TCL_LIBPATH	= @TCL_LIBPATH@
+TCL_RPATH	= @TCL_RPATH@
+TCL_MAYBE_RPATH = @TCL_MAYBE_RPATH@
+TCL_INCLUDES	= @TCL_INCLUDES@
+
+# error table rules
+#
+### /* these are invoked as $(...) foo.et, which works, but could be better */
+COMPILE_ET= $(COMPILE_ET-@COM_ERR_VERSION@)
+COMPILE_ET-sys= compile_et
+COMPILE_ET-k5= $(BUILDTOP)/util/et/compile_et -d $(SRCTOP)/util/et
+
+.SUFFIXES:  .h .c .et .ct
+
+# These versions cause both .c and .h files to be generated at once.
+# But GNU make doesn't understand this, and parallel builds can trigger
+# both of them at once, causing them to stomp on each other.  The versions
+# below only update one of the files, so compile_et has to get run twice,
+# but it won't break parallel builds.
+#.et.h: ; $(COMPILE_ET) $<
+#.et.c: ; $(COMPILE_ET) $<
+
+.et.h:
+	d=ettmp$$$$ ; (cp $< $$d.et && $(COMPILE_ET) $$d.et && mv $$d.h $*.h) ; \
+		e=$$? ; rm -f $$d.* ; exit $$e
+
+.et.c:
+	d=ettmp$$$$ ; (cp $< $$d.et && $(COMPILE_ET) $$d.et && mv $$d.c $*.c) ; \
+		e=$$? ; rm -f $$d.* ; exit $$e
+
+# rule to make object files
+#
+.SUFFIXES: .c .o
+.c.o:
+	$(CC) $(ALL_CFLAGS) -c $<
+
+# ss command table rules
+#
+MAKE_COMMANDS= $(MAKE_COMMANDS-@SS_VERSION@)
+MAKE_COMMANDS-sys= mk_cmds
+MAKE_COMMANDS-k5= $(BUILDTOP)/util/ss/mk_cmds
+
+.ct.c:
+	$(MAKE_COMMANDS) $<
+
+## Parameters to be set by configure for use in lib.in:
+##
+
+LN_S=@LN_S@
+AR=@AR@
+
+# Set to "lib$(LIBBASE)$(STEXT) lib$(LIBBASE)$(SHEXT) lib$(LIBBASE)$(PFEXT)" or
+# some subset thereof by configure; determines which types of libs get
+# built.
+LIBLIST=@LIBLIST@
+
+# Set by configure; list of library symlinks to make to $(TOPLIBD)
+LIBLINKS=@LIBLINKS@
+
+# Set by configure; list of install targets
+LIBINSTLIST=@LIBINSTLIST@
+
+# Some of these should really move to pre.in, since programs will need
+# it too. (e.g. stuff that has dependencies on the libraries)
+
+# usually .a
+STLIBEXT=@STLIBEXT@
+
+# usually .so.$(LIBMAJOR).$(LIBMINOR)
+SHLIBVEXT=@SHLIBVEXT@
+
+# usually .so.$(LIBMAJOR) (to allow for major-version compat)
+SHLIBSEXT=@SHLIBSEXT@
+
+# usually .so
+SHLIBEXT=@SHLIBEXT@
+
+# usually _p.a
+PFLIBEXT=@PFLIBEXT@
+
+#
+DYNOBJEXT=@DYNOBJEXT@
+MAKE_DYNOBJ_COMMAND=@MAKE_DYNOBJ_COMMAND@
+DYNOBJ_EXPDEPS=@DYNOBJ_EXPDEPS@
+DYNOBJ_EXPFLAGS=@DYNOBJ_EXPFLAGS@
+
+# File with symbol names to be exported, both functions and data,
+# currently not distinguished.
+SHLIB_EXPORT_FILE=$(srcdir)/$(LIBPREFIX)$(LIBBASE).exports
+
+# File that needs to be current for building the shared library,
+# usually SHLIB_EXPORT_FILE, but not always, if we have to convert
+# it to another, intermediate form for the linker.
+SHLIB_EXPORT_FILE_DEP=@SHLIB_EXPORT_FILE_DEP@
+
+# Command to run to build a shared library.
+# In systems that require multiple commands, like AIX, it may need
+# to change to rearrange where the various parameters fit in.
+MAKE_SHLIB_COMMAND=@MAKE_SHLIB_COMMAND@
+
+# flags for explicit libraries depending on this one,
+# e.g. "-R$(SHLIB_RPATH) $(SHLIB_SHLIB_DIRFLAGS) $(SHLIB_EXPLIBS)"
+SHLIB_EXPFLAGS=@SHLIB_EXPFLAGS@
+
+## Parameters to be set by configure for use in libobj.in:
+
+# Set to "OBJS.ST OBJS.SH OBJS.PF" or some subset thereof by
+# configure; determines which types of object files get built.
+OBJLISTS=@OBJLISTS@
+
+# Note that $(LIBSRCS) *cannot* contain any variable references, or
+# the suffix substitution will break on some platforms!
+SHLIBOBJS=$(STLIBOBJS:.o=@SHOBJEXT@)
+PFLIBOBJS=$(STLIBOBJS:.o=@PFOBJEXT@)
+
+# "$(CC) -G", "$(LD) -Bshareable", etc.
+LDCOMBINE=@LDCOMBINE@
+
+# "-h $@", "-h lib$(LIBNAME).$(LIBMAJOR)", etc.
+SONAME=@SONAME@
+
+#
+# rules to make various types of object files
+#
+PICFLAGS=@PICFLAGS@
+PROFFLAGS=@PROFFLAGS@
+
+# platform-dependent temporary files that should get cleaned up
+EXTRA_FILES=@EXTRA_FILES@
+
+
+
+##
+## end of pre.in
+############################################################
diff --git a/mechglue/src/config/ren2long b/mechglue/src/config/ren2long
new file mode 100755
index 000000000..e44dc8d5f
--- /dev/null
+++ b/mechglue/src/config/ren2long
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# Shell script that changes names that have been truncated to 8.3 format
+# back to their original longer name. The awk script produces a script with
+# lines of the following format:
+#     if [ -f <short> ]; then echo ::mv <short> <long> ; mv <short> <long> ; fi
+# These lines then get executed in bin/sh.
+#
+find . -type f -print | gawk -f $0.awk | sh -x 2> /dev/null
diff --git a/mechglue/src/config/ren2long.awk b/mechglue/src/config/ren2long.awk
new file mode 100644
index 000000000..fcf0177ea
--- /dev/null
+++ b/mechglue/src/config/ren2long.awk
@@ -0,0 +1,75 @@
+#
+# Awk script to convert filenames shortened down to 8.3 
+# back to their larger size. 
+#
+# Works by looking at every filename and seeing if it's shortened
+# 8.3 version exists, and if so then mv the short name to the long
+# name.
+#
+# Usage: find . -type f -print | gawk -f ren2long.awk | sh -x [ 2> /dev/null ]
+#
+
+
+# Parse_path
+#
+# Takes the whole path and converts the basename part to 8.3. If it
+# changed in the process we emit a sh command to mv it if the shortened
+# name exists.
+# 
+function parse_path(p,P2,N,NEW) {
+
+     P2 = tolower(p)
+
+     NEW = ""
+     while(1) {
+	  N = index(P2,"/")			# Go until all / are parsed
+	  if (N == 0) break
+
+	  NEW = NEW name83(substr(P2,1,N-1)) "/"; # More of the path
+	  P2 = substr(P2,N+1)
+     }
+
+     if (bad[P2] == 1) {
+	  print "echo skipping " p
+	  return
+     }
+     NEW = NEW name83(P2)			# Append path and 8.3 name
+
+     if (bad[P2] == 2) {
+	  print "if [ -f " NEW " ]; then echo ::rm " NEW " ; rm " NEW " ; fi"
+	  return
+     }
+     if (NEW != p) 
+	  print "if [ -f " NEW " ]; then echo ::mv " NEW " " p " ; mv " NEW " " p " ; fi"
+}
+#
+# Name83
+# 
+# Converts the a single component part of a file name into 8.3 format
+#
+function name83(fname,P,B,E) {
+     P = index(fname,".");			# Find the extension
+
+     if (P == 0) {				# No extension
+	  B = substr(fname,1,8);		# Just truncate at 8 chars
+	  return B;
+    }
+
+    B = substr(fname, 1, P <= 8 ? P-1 : 8);	# At most 8 chars in name
+    E = substr(fname, P+1, 3)			# And 3 in extension
+    P = index(E, ".")				# 2 dot problem
+    if (P)
+	 E = substr(E, 1, P-1)
+
+     B = B "." E				# Put name together
+     return B
+}
+BEGIN {
+     bad["krb5-types-aux.h"] = 1
+     bad["autoconf.h.in"] = 1
+     bad["conv_tkt_skey.c"] = 1
+     ##bad["makefile"] = 2 -- windows have legitimate files with this name
+}
+{
+     parse_path($1)				# Do it
+}
diff --git a/mechglue/src/config/rm.bat b/mechglue/src/config/rm.bat
new file mode 100644
index 000000000..4cb1c8822
--- /dev/null
+++ b/mechglue/src/config/rm.bat
@@ -0,0 +1,32 @@
+@echo off
+:loop
+if exist %1 del %1
+shift
+if not %1.==. goto loop
+exit
+
+Rem
+Rem rm.bat
+Rem
+Rem Copyright 1995 by the Massachusetts Institute of Technology.
+Rem All Rights Reserved.
+Rem
+Rem Export of this software from the United States of America may
+Rem   require a specific license from the United States Government.
+Rem   It is the responsibility of any person or organization contemplating
+Rem   export to obtain such a license before exporting.
+Rem 
+Rem WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+Rem distribute this software and its documentation for any purpose and
+Rem without fee is hereby granted, provided that the above copyright
+Rem notice appear in all copies and that both that copyright notice and
+Rem this permission notice appear in supporting documentation, and that
+Rem the name of M.I.T. not be used in advertising or publicity pertaining
+Rem to distribution of the software without specific, written prior
+Rem permission.  M.I.T. makes no representations about the suitability of
+Rem this software for any purpose.  It is provided "as is" without express
+Rem or implied warranty.
+Rem 
+Rem
+Rem Batch file to mimic the functionality of the Unix rm command
+Rem
diff --git a/mechglue/src/config/shlib.conf b/mechglue/src/config/shlib.conf
new file mode 100644
index 000000000..9d9a2066b
--- /dev/null
+++ b/mechglue/src/config/shlib.conf
@@ -0,0 +1,448 @@
+#
+# Set up some defaults.
+#
+STLIBEXT=.a
+# Default to being unable to build shared libraries.
+SHLIBEXT=.so-nobuild
+SHLIBVEXT=.so.v-nobuild
+SHLIBSEXT=.so.s-nobuild
+# Most systems support profiled libraries.
+PFLIBEXT=_p.a
+# Most systems install shared libs as mode 644, etc. while hpux wants 755
+INSTALL_SHLIB='$(INSTALL_DATA)'
+# Most systems use the same objects for shared libraries and dynamically
+# loadable objects.
+DYNOBJEXT='$(SHLIBEXT)'
+MAKE_DYNOBJ_COMMAND='$(MAKE_SHLIB_COMMAND)'
+DYNOBJ_EXPDEPS='$(SHLIB_EXPDEPS)'
+DYNOBJ_EXPFLAGS='$(SHLIB_EXPFLAGS)'
+#
+use_linker_init_option=no
+use_linker_fini_option=no
+
+STOBJEXT=.o
+SHOBJEXT=.so
+PFOBJEXT=.po
+# Default for systems w/o shared libraries
+CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+#
+SHLIB_EXPORT_FILE_DEP='$(SHLIB_EXPORT_FILE)'
+# This will do for most platforms, and we'll substitute for
+# LDCOMBINE, SHLIB_EXPFLAGS, and LDCOMBINE_TAIL below.
+MAKE_SHLIB_COMMAND=x
+INIT_FINI_PREP=:
+
+# Default to static or shared libraries?
+default_static=no
+default_shared=yes
+
+# Set up architecture-specific variables.
+case $krb5_cv_host in
+alpha*-dec-osf*)
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBSEXT='.so.$(LIBMAJOR)'
+	SHLIBEXT=.so
+	# Alpha OSF/1 doesn't need separate PIC objects
+	SHOBJEXT=.o
+	INIT_FINI_PREP=initfini=
+	LDCOMBINE='$(CC) $(PTHREAD_CFLAGS) -shared -Wl,-expect_unresolved -Wl,\* -Wl,-update_registry -Wl,$(BUILDTOP)/so_locations -Wl,-soname -Wl,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) -Wl,-hidden -Wl,-input,osf1.exports $$initfini'
+	SHLIB_EXPORT_FILE_DEP=osf1.exports
+	use_linker_init_option=yes
+	use_linker_fini_option=yes
+	EXTRA_FILES="$EXTRA_FILES export"
+	SHLIB_EXPFLAGS='-rpath $(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	PROFFLAGS=-pg
+	RPATH_FLAG='-Wl,-rpath -Wl,'
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(PTHREAD_CFLAGS) $(LDFLAGS)'
+	if test "$krb5_cv_prog_gcc" = yes \
+		&& test "$krb5_cv_gnu_ld" = yes; then
+		# Really should check for gnu ld vs system ld, too.
+		CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(PTHREAD_CFLAGS) $(LDFLAGS)'
+	else
+		# Need -oldstyle_liblookup to avoid picking up shared libs from
+		# other builds.  OSF/1 / Tru64 ld programs look through the entire
+		# library path for shared libs prior to looking through the
+		# entire library path for static libs.
+		CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) -Wl,-oldstyle_liblookup $(CFLAGS) $(PTHREAD_CFLAGS) $(LDFLAGS)'
+	fi
+	# _RLD_ROOT hack needed to repoint "root" directory for purposes
+	# of searching for shared libs, since RPATHs take precedence over
+	# LD_LIBRARY_PATH.
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`$${LD_LIBRARY_PATH+:$$LD_LIBRARY_PATH}; export LD_LIBRARY_PATH; _RLD_ROOT=$(FAKEDEST):$${_RLD_ROOT+$$_RLD_ROOT}$${_RLD_ROOT-/}; export _RLD_ROOT;'
+	;;
+
+# HPUX *seems* to work under 10.20.
+# 
+# Note: "-Wl,+s" when building executables enables the use of the
+# SHLIB_PATH environment variable for finding shared libraries 
+# in non-standard directories.  If a non-standard search-path for
+#  shared libraries is compiled into the executable (using 
+# -Wl,+b,$KRB5_SHLIBDIR), then the order of "-Wl,+b,..." and "-Wl,+s" 
+# on the commandline of the linker will determine which path
+# (compiled-in or SHLIB_PATH) will be searched first.
+#
+# +I initproc routine gets called at load and unload time for
+#    shl_load calls, but appears to never be called for link-time
+#    specified libraries.
+# +e sym exports symbol and supposedly prevents other symbols
+#    from being exported, according to the man page, but the
+#    latter bit doesn't actually seem to work
+# -O +dpv should display any routines eliminated as unused, but -b
+#	  apparently turns that off
+*-*-hpux*)
+	INSTALL_SHLIB='$(INSTALL)'
+	SHLIBEXT=.sl
+	SHLIBVEXT='.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBSEXT='.$(LIBMAJOR)'
+	RPATH_FLAG='-Wl,+b,'
+	if test "$krb5_cv_prog_gcc" = yes; then
+		PICFLAGS=-fPIC
+		SHLIB_EXPFLAGS='-Wl,+s -Wl,+b,$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+		LDCOMBINE='gcc -fPIC -shared -Wl,+h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) -Wl,-c,hpux10.exports'
+	else
+		PICFLAGS=+z
+		SHLIB_EXPFLAGS='+s +b $(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+		LDCOMBINE='ld -b +h $(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) -c hpux10.exports'
+	fi
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) -Wl,+s $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='SHLIB_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export SHLIB_PATH;'
+	SHLIB_EXPORT_FILE_DEP=hpux10.exports
+	# Do *not* set use_linker_init_option=yes here, because in the
+	# case where the library is specified at program link time, the
+	# initialization function appears not to get called, only for
+	# shl_load.  But for finalization functions, the shl_load case
+	# is the one we care about.
+	#
+	# Not setting use_linker_init_option here should cause compilation
+	# failures if the user tries to disable delayed initialization.
+	use_linker_fini_option=yes
+	;;
+
+mips-sgi-irix6.3)	# This is a Kludge; see below
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBSEXT='.so.$(LIBMAJOR)'
+	SHLIBEXT=.so
+	SHOBJEXT=.o
+	# Kludge follows: (gcc makes n32 object files but ld expects o32, so we reeducate ld)
+	if test "$krb5_cv_prog_gcc" = yes; then
+		LDCOMBINE='ld -n32 -shared -ignore_unresolved -update_registry $(BUILDTOP)/so_locations -soname $(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT)'
+	else
+		LDCOMBINE='ld -shared -ignore_unresolved -update_registry $(BUILDTOP)/so_locations -soname $(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT)'
+	fi
+	SHLIB_EXPFLAGS='-rpath $(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	# no gprof for Irix...
+	PROFFLAGS=-p
+	RPATH_FLAG='-Wl,-rpath -Wl,'
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	# This grossness is necessary due to the presence of *three*
+	# supported ABIs on Irix, and the precedence of the rpath over
+	# LD_LIBRARY*_PATH.  Like OSF/1, _RLD*_ROOT needs to be set to
+	# work around this lossage.
+	#
+	# Set the N32 and 64 variables first because the unqualified
+	# variables affect all three and can cause the sed command to fail.
+	#
+	# This loop is to reduce the clutter a slight bit.
+	add='`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`'
+	RUN_ENV=
+	for i in N32 64 ''; do
+		RUN_ENV="${RUN_ENV+ $RUN_ENV}LD_LIBRARY${i}_PATH=$add\$\${LD_LIBRARY${i}_PATH+:\$\$LD_LIBRARY${i}_PATH}; export LD_LIBRARY${i}_PATH;"
+		RUN_ENV="${RUN_ENV} _RLD${i}_ROOT=\$(FAKEDEST):\$\${_RLD${i}_ROOT+\$\${_RLD${i}_ROOT}}\$\${_RLD${i}_ROOT-/}; export _RLD${i}_ROOT;"
+	done
+	;;
+
+mips-sgi-irix*)
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBSEXT='.so.$(LIBMAJOR)'
+	SHLIBEXT=.so
+	SHOBJEXT=.o
+	if test "$krb5_cv_prog_gcc" = yes; then
+		LDCOMBINE_TAIL=""
+		INIT_FINI_PREP="initfini="
+	else
+		use_linker_init_option=yes
+		use_linker_fini_option=yes
+		INIT_FINI_PREP='initfini=; for f in . $(LIBINITFUNC); do if test $$f = .; then :; else initfini="$$initfini -Wl,-init,$${f}__auxinit"; fi; done; for f in . $(LIBFINIFUNC); do if test $$f = .; then :; else initfini="$$initfini -Wl,-fini,$${f}"; fi; done'
+		LDCOMBINE_TAIL='-Wl,-exports_file -Wl,$(SHLIB_EXPORT_FILE)'
+	fi
+	LDCOMBINE='$(CC) -shared -Wl,-ignore_unresolved -Wl,-update_registry -Wl,$(BUILDTOP)/so_locations -Wl,-soname -Wl,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $$initfini'
+	SHLIB_EXPFLAGS='-rpath $(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	# no gprof for Irix...
+	PROFFLAGS=-p
+	RPATH_FLAG='-Wl,-rpath -Wl,'
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	# This grossness is necessary due to the presence of *three*
+	# supported ABIs on Irix, and the precedence of the rpath over
+	# LD_LIBRARY*_PATH.  Like OSF/1, _RLD*_ROOT needs to be set to
+	# work around this lossage.
+	#
+	# Set the N32 and 64 variables first because the unqualified
+	# variables affect all three and can cause the sed command to fail.
+	#
+	# This loop is to reduce the clutter a slight bit.
+	add='`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`'
+	RUN_ENV=
+	for i in N32 64 ''; do
+		RUN_ENV="${RUN_ENV+ $RUN_ENV}LD_LIBRARY${i}_PATH=$add\$\${LD_LIBRARY${i}_PATH+:\$\$LD_LIBRARY${i}_PATH}; export LD_LIBRARY${i}_PATH;"
+		RUN_ENV="${RUN_ENV} _RLD${i}_ROOT=\$(FAKEDEST):\$\${_RLD${i}_ROOT+\$\${_RLD${i}_ROOT}}\$\${_RLD${i}_ROOT-/}; export _RLD${i}_ROOT;"
+	done
+	;;
+
+# untested...
+mips-sni-sysv4)
+	if test "$krb5_cv_prog_gcc" = yes; then
+		PICFLAGS=-fpic
+		LDCOMBINE='$(CC) -G -Wl,-h -Wl,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT)'
+	else
+		PICFLAGS=-Kpic
+		LDCOMBINE='$(CC) -G -h $(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT)'
+	fi
+	SHLIB_EXPFLAGS='-R$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	SHLIBEXT=.so
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBSEXT='.so.$(LIBMAJOR)'
+	RPATH_FLAG=-R
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export LD_LIBRARY_PATH;'
+	PROFFLAGS=-pg
+	;;
+
+mips-*-netbsd*)
+	PICFLAGS=-fPIC
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBSEXT='.so.$(LIBMAJOR)'
+	SHLIBEXT=.so
+	LDCOMBINE='ld -shared -soname $(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT)'
+	SHLIB_EXPFLAGS='-R$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	RPATH_FLAG='-Wl,-rpath -Wl,'
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export LD_LIBRARY_PATH;'
+	PROFFLAGS=-pg
+	;;
+
+*-*-netbsd*)
+	PICFLAGS=-fPIC
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBEXT=.so
+	LDCOMBINE='ld -Bshareable'
+	SHLIB_EXPFLAGS='-R$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	RPATH_FLAG=-R
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export LD_LIBRARY_PATH;'
+	PROFFLAGS=-pg
+	;;
+
+*-*-freebsd*)
+	if test -x /usr/bin/objformat ; then
+		objformat=`/usr/bin/objformat`
+	else
+		objformat="aout"
+	fi
+	PICFLAGS=-fpic
+	if test "x$objformat" = "xelf" ; then
+		SHLIBVEXT='.so.$(LIBMAJOR)'
+		RPATH_FLAG='-Wl,-rpath -Wl,'
+	else
+		RPATH_FLAG=-R
+		SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	fi
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	SHLIBEXT=.so
+	LDCOMBINE='ld -Bshareable'
+	SHLIB_EXPFLAGS='-R$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export LD_LIBRARY_PATH;'
+	PROFFLAGS=-pg
+	;;
+
+*-*-openbsd*)
+	PICFLAGS=-fpic
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBEXT=.so
+	LDCOMBINE='ld -Bshareable'
+	SHLIB_EXPFLAGS='-R$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	RPATH_FLAG=-R
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export LD_LIBRARY_PATH;'
+	PROFFLAGS=-pg
+	;;
+
+*-*-darwin* | *-*-rhapsody*)
+	SHLIBVEXT='.$(LIBMAJOR).$(LIBMINOR).dylib'
+	SHLIBSEXT='.$(LIBMAJOR).dylib'
+	SHLIB_EXPFLAGS='$(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	SHLIBEXT=.dylib
+	DYNOBJEXT=.so
+	SHLIB_EXPORT_FILE_DEP=darwin.exports
+	DYNOBJ_EXPDEPS='$(DYNOBJ_EXPDEPS_WITH_LOADER)'
+	DYNOBJ_EXPFLAGS='$(SHLIB_DIRS) $(DYNOBJ_EXPLIBS_WITH_LOADER)'
+	MAKE_DYNOBJ_COMMAND='$(CC) -bundle $(CFLAGS) -bundle_loader $(DYNOBJ_LOADER_PROG) $(LDFLAGS) -o $@ $$objlist $(DYNOBJ_EXPFLAGS) -exported_symbols_list darwin.exports'
+	LDCOMBINE='$(CC) -undefined warning -dynamiclib -compatibility_version $(LIBMAJOR) -current_version $(LIBMAJOR).$(LIBMINOR) -install_name "$(KRB5_LIBDIR)/$(LIBPREFIX)$(LIBBASE)$(SHLIBVEXT)" $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) -dynamic $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='DYLD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export DYLD_LIBRARY_PATH;'
+	# We need some changes for *all* library builds on Darwin, too.
+	# (Well, the KfM builds which generate .dylib files, at least.
+	# They might not be needed for "dumb" UNIX builds with static
+	# libraries, that just happen to be done on Darwin.)
+	enable_static=yes
+	enable_shared=no
+	;;
+
+*-*-solaris*)
+	if test "$krb5_cv_prog_gcc" = yes; then
+		PICFLAGS=-fPIC
+		LDCOMBINE='$(CC) $(CFLAGS) -shared -h $(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT)'
+	else
+		PICFLAGS=-KPIC
+		# Solaris cc doesn't default to stuffing the SONAME field...
+		LDCOMBINE='$(CC) $(CFLAGS) -dy -G -z text -h $(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $$initfini'
+		#
+		case $krb5_cv_host in
+		*-*-solaris2.[1-7] | *-*-solaris2.[1-7].*)
+		    # Did Solaris 7 and earlier have a linker option for this?
+		    ;;
+		*)
+		    INIT_FINI_PREP='initfini=; for f in . $(LIBINITFUNC); do if test $$f = .; then :; else initfini="$$initfini -Wl,-z,initarray=$${f}__auxinit"; fi; done; for f in . $(LIBFINIFUNC); do if test $$f = .; then :; else initfini="$$initfini -Wl,-z,finiarray=$$f"; fi; done'
+		    use_linker_init_option=yes
+		    use_linker_fini_option=yes
+		    ;;
+		esac
+	fi
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBSEXT='.so.$(LIBMAJOR)'
+	SHLIBEXT=.so
+	SHLIB_EXPFLAGS='-R$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	PROFFLAGS=-pg
+	RPATH_FLAG=-R
+	CC_LINK_SHARED='$(PURE) $(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(PURE) $(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export LD_LIBRARY_PATH;'
+	;;
+
+*-*-sunos*)
+	PICFLAGS=-fpic
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBEXT=.so
+	# The following grossness is to prevent relative paths from
+	# creeping into the RPATH of an executable or library built
+	# under SunOS; the explicit setting of LD_LIBRARY_PATH does
+	# does not make it into the output file, while directories
+	# passed by "-Ldirname" do.
+	LDCOMBINE='LD_LIBRARY_PATH=`echo $(SHLIB_DIRS) | sed -e "s/-L//g" -e "s/ /:/g"` ld -dp -assert pure-text'
+	SHLIB_EXPFLAGS='-L$(SHLIB_RDIRS) $(SHLIB_EXPLIBS)'
+	PROFFLAGS=-pg
+	# ick.
+	RPATH_FLAG=-L
+	CC_LINK_SHARED='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"` $(PURE) $(CC) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g` $(PURE) $(CC) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export LD_LIBRARY_PATH;'
+	;;
+*-*-linux* | *-*-gnu* | *-*-k*bsd*-gnu)
+	PICFLAGS=-fPIC
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBSEXT='.so.$(LIBMAJOR)'
+	SHLIBEXT=.so
+	# Linux ld doesn't default to stuffing the SONAME field...
+	# Use objdump -x to examine the fields of the library
+	LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT)'
+	# 
+	LDCOMBINE_TAIL='-Wl,--version-script binutils.versions'
+	SHLIB_EXPORT_FILE_DEP=binutils.versions
+	# For cases where we do have dependencies on other libraries
+	# built in this tree...
+	SHLIB_EXPFLAGS='-Wl,-R$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	PROFFLAGS=-pg
+	RPATH_FLAG='-Wl,-rpath -Wl,'
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	RUN_ENV='LD_LIBRARY_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export LD_LIBRARY_PATH;'
+
+	## old version:
+	# Linux libc does weird stuff at shlib link time, must be
+	# explicitly listed here.  This also makes it get used even
+	# for the libraries marked as not having any dependencies; while
+	# that's not strictly correct, the resulting behavior -- not adding
+	# extra -R directories -- is still what we want.
+	#LDCOMBINE='ld -shared -h $(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT)'
+	#LDCOMBINE_TAIL="-lc"
+	#SHLIB_EXPFLAGS='-R$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+
+	;;
+
+*-*-aix5*)
+	SHLIBVEXT='.so.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBEXT=.so
+	# AIX doesn't need separate PIC objects
+	SHOBJEXT=.o
+	SHLIB_EXPFLAGS='  $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	PROFFLAGS=-pg
+	if test "$krb5_cv_prog_gcc" = "yes" ; then
+	  wl_prefix=-Wl,
+	  RPATH_FLAG='-Wl,-blibpath:'
+	  LDCOMBINE='$(CC) -shared -v -o $@ $$objlist -nostartfiles -Xlinker -bgcbypass:1 -Xlinker -bfilelist -Xlinker -bM:SRE -Xlinker -bE:$(SHLIB_EXPORT_FILE) -Xlinker -bernotok -Xlinker -brtl $(SHLIB_EXPFLAGS) -lc $$initfini'
+	else
+	  wl_prefix=
+	  RPATH_FLAG=-blibpath:
+	  LDCOMBINE='/bin/ld -o $@ $$objlist -H512 -T512 -bnoentry -bgcbypass:1 -bnodelcsect -bfilelist -bM:SRE -bE:$(SHLIB_EXPORT_FILE) -bernotok -brtl $(SHLIB_EXPFLAGS) -lc $$initfini'
+	fi
+	# Assume initialization always delayed.
+	INIT_FINI_PREP="wl=${wl_prefix}; "'i=1; initfini=; for f in . $(LIBFINIFUNC); do if test $$f != .; then initfini="$$initfini $${wl}-binitfini::$$f:$$i"; else :; fi; i=`expr $$i + 1`; done'
+	use_linker_fini_option=yes
+	MAKE_SHLIB_COMMAND="${INIT_FINI_PREP} && ${LDCOMBINE}"
+	RPATH_TAIL=:/usr/lib:/lib
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH):'"$RPATH_TAIL"' $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	# $(PROG_RPATH) is here to handle things like a shared tcl library
+	RUN_ENV='LIBPATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`:$(PROG_RPATH):/usr/lib:/usr/local/lib; export LIBPATH; '
+	;;
+
+*-*-aix4.*)
+	SHLIBVEXT='.a.$(LIBMAJOR).$(LIBMINOR)'
+	SHLIBEXT=.a
+	# AIX doesn't need separate PIC objects
+	SHOBJEXT=.o
+	SHLIB_EXPFLAGS='  $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+	PROFFLAGS=-pg
+	# Dynamically loaded object can have whatever suffix, but don't
+	# make archives like for shared libraries.
+	DYNOBJEXT=.so
+	#
+	if test "$krb5_cv_prog_gcc" = "yes" ; then
+	  wl_prefix=-Wl,
+	  RPATH_FLAG='-Wl,-blibpath:'
+	  LDCOMBINE='$(CC) -shared -v -o shr.o.$(LIBMAJOR).$(LIBMINOR) $$objlist -nostartfiles -Xlinker -bgcbypass:1 -Xlinker -bfilelist -Xlinker -bM:SRE -Xlinker -bE:$(SHLIB_EXPORT_FILE) -Xlinker -bernotok $(SHLIB_EXPFLAGS) -lc $$initfini'
+	  LDCOMBINE_DYN='$(CC) -shared -v -o $@ $$objlist -nostartfiles -Xlinker -bgcbypass:1 -Xlinker -bfilelist -Xlinker -bM:SRE -Xlinker -bE:$(SHLIB_EXPORT_FILE) -Xlinker -bernotok $(SHLIB_EXPFLAGS) -lc $$initfini'
+	else
+	  wl_prefix=
+	  RPATH_FLAG=-blibpath:
+	  LDCOMBINE='/bin/ld -o shr.o.$(LIBMAJOR).$(LIBMINOR) $$objlist -H512 -T512 -bnoentry -bgcbypass:1 -bnodelcsect -bfilelist -bM:SRE -bE:$(SHLIB_EXPORT_FILE) -bernotok $(SHLIB_EXPFLAGS) -lc $$initfini'
+	  LDCOMBINE_DYN='/bin/ld -o $@ $$objlist -H512 -T512 -bnoentry -bgcbypass:1 -bnodelcsect -bfilelist -bM:SRE -bE:$(SHLIB_EXPORT_FILE) -bernotok $(SHLIB_EXPFLAGS) -lc $$initfini'
+	fi
+	# Assume initialization always delayed.
+	INIT_FINI_PREP="wl=${wl_prefix}; "'i=1; initfini=; for f in . $(LIBFINIFUNC); do if test $$f != .; then initfini="$$initfini $${wl}-binitfini::$$f:$$i"; else :; fi; i=`expr $$i + 1`; done'
+	use_linker_fini_option=yes
+	MAKE_SHLIB_COMMAND="${INIT_FINI_PREP} && ${LDCOMBINE}"' && ar cq $@ shr.o.$(LIBMAJOR).$(LIBMINOR) && chmod +x $@ && rm -f shr.o.$(LIBMAJOR).$(LIBMINOR)'
+	MAKE_DYNOBJ_COMMAND="${INIT_FINI_PREP} && ${LDCOMBINE_DYN}"
+	RPATH_TAIL=:/usr/lib:/lib
+	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(RPATH_FLAG)$(PROG_RPATH):'"$RPATH_TAIL"' $(CFLAGS) $(LDFLAGS)'
+	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+	# $(PROG_RPATH) is here to handle things like a shared tcl library
+	RUN_ENV='LIBPATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`:$(PROG_RPATH):/usr/lib:/usr/local/lib; export LIBPATH; '
+	;;
+esac
+
+if test "${MAKE_SHLIB_COMMAND}" = "x" ; then
+  if test "${INIT_FINI_PREP}" != ":"; then
+    MAKE_SHLIB_COMMAND="${INIT_FINI_PREP} && ${LDCOMBINE} -o \$@ \$\$objlist \$(SHLIB_EXPFLAGS) ${LDCOMBINE_TAIL}"
+  else
+    MAKE_SHLIB_COMMAND="${LDCOMBINE} -o \$@ \$\$objlist \$(SHLIB_EXPFLAGS) ${LDCOMBINE_TAIL}"
+  fi
+fi
diff --git a/mechglue/src/config/win-post.in b/mechglue/src/config/win-post.in
new file mode 100644
index 000000000..74241750a
--- /dev/null
+++ b/mechglue/src/config/win-post.in
@@ -0,0 +1,102 @@
+#
+# Start of Win32 post-config lines (config/win-post.in)
+#
+
+setup-msg::
+	@set C_RULE_PRINT=	$(C_RULE_PRINT)
+	@set DO_C_RULE_PRINT=1
+
+!if defined(NO_OUTPRE) || defined(NO_OUTDIR)
+outpre-dir::
+!else
+outpre-dir:: $(OUTPRE3)$(DIRNUL)
+!endif
+
+#
+# put all:: first just in case no other rules occur here
+#
+all::
+
+#
+# Set the #define to indicate that we are compiling a DLL.  We default to 
+# compiling the Kerberos library
+#
+!if defined(DLL_EXP_TYPE)
+DLL_FILE_DEF=/D$(DLL_EXP_TYPE)_DLL_FILE
+!else
+DLL_FILE_DEF=/DKRB5_DLL_FILE
+!endif
+
+# Build the Makefile unless we are in the top-level
+#(where there is already an explicit rule).
+!if !defined(ZIP) && !defined(WINFILES)
+Makefile: Makefile.in $(BUILDTOP)\config\win-pre.in $(BUILDTOP)\config\win-post.in
+	$(WCONFIG) $(BUILDTOP)\config < Makefile.in > Makefile
+!endif
+
+
+!if defined(LIBNAME)
+
+!if !defined(OBJFILELIST)
+OBJFILELIST=@$(OBJFILE)
+!endif
+!if !defined(OBJFILEDEP)
+OBJFILEDEP=$(OBJFILE)
+!endif
+
+all-windows:: $(LIBNAME)
+$(LIBNAME): $(OBJFILEDEP)
+	$(LIBCMD) /out:$(LIBNAME) /nologo $(OBJFILELIST)
+
+!endif # LIBNAME
+
+
+!if defined(OBJFILE)
+all-windows:: $(OBJFILE)
+!if defined(LIBOBJS)
+$(OBJFILE): $(LIBOBJS)
+	if exist $(OBJFILE) del $(OBJFILE)
+!if defined(PREFIXDIR)
+	$(LIBECHO) -p $(PREFIXDIR)\ $** > $(OBJFILE)
+!else
+	$(LIBECHO) $** > $(OBJFILE)
+!endif # !PREFIXDIR
+!endif # LIBOBJS
+!endif # OBJFILE
+
+
+check::
+check-windows::
+
+!if defined(LIBNAME)
+clean-windows::
+# NO LONGER NEEDED BECAUSE WE CLEAN OUT THE DIR...
+#	if exist $(LIBNAME) del $(LIBNAME)
+!endif
+!if defined(OBJFILE)
+clean-windows::
+# NO LONGER NEEDED BECAUSE WE CLEAN OUT THE DIR...
+#	if exist $(OBJFILE) del $(OBJFILE)
+!endif
+
+clean-windows:: clean-windows-files clean-windows-dir
+
+
+# This needs to be in the post because we need RM to be defined in terms
+# of BUILDTOP
+clean-windows-files::
+!if "$(OUTPRE3)" == ""
+!error ASSERTION FAILURE: OUTPRE3 must be defined!!!
+!endif
+!if "$(OS)" == "Windows_NT"
+	@if exist $(OUTPRE3)$(DIRNUL) rd /s/q $(OUTPRE3)
+!else
+	@if exist $(OUTPRE3)$(DIRNUL) deltree /y $(OUTPRE3)
+!endif
+!if 0
+	$(RM) .\$(OUTPRE)*.obj .\$(OUTPRE)*.res
+	$(RM) .\$(OUTPRE)*.exe .\$(OUTPRE)*.dll
+	$(RM) .\$(OUTPRE)*.lib .\$(OUTPRE)*.pdb
+	$(RM) .\$(OUTPRE)*.exp .\$(OUTPRE)*.map
+	$(RM) .\$(OUTPRE)*.idb .\$(OUTPRE)*.ilk
+!endif
diff --git a/mechglue/src/config/win-pre.in b/mechglue/src/config/win-pre.in
new file mode 100644
index 000000000..73e7bea6a
--- /dev/null
+++ b/mechglue/src/config/win-pre.in
@@ -0,0 +1,226 @@
+WHAT=windows
+
+all:: setup-msg outpre-dir
+
+all:: all-$(WHAT)
+clean:: clean-$(WHAT)
+install:: install-$(WHAT)
+check:: check-$(WHAT)
+
+all-windows::
+clean-windows::
+install-windows::
+check-windows::
+
+all-windows:: Makefile
+clean-windows:: Makefile
+
+#
+# Figure out the CPU
+#
+!if !defined(CPU) || "$(CPU)" == ""
+CPU=$(PROCESSOR_ARCHITECTURE)
+!endif # CPU
+
+!if "$(CPU)" == ""
+CPU=i386
+!endif
+
+# Change x86 or X86 to i386
+!if ( "$(CPU)" == "X86" ) || ( "$(CPU)" == "x86" )
+CPU=i386
+!endif # CPU == X86
+
+!if ( "$(CPU)" != "i386" ) && ( "$(CPU)" != "ALPHA" )
+!error Must specify CPU environment variable ( CPU=i386, CPU=ALPHA)
+!endif
+#
+# End of figuring out CPU
+#
+
+!if "$(OS)" == "Windows_NT"
+DIRNUL=
+!else 
+DIRNUL=\nul
+!endif
+
+# NOTE: ^ is an escape char for NMAKE.
+!ifdef NODEBUG
+OUTPRE_DBG=rel
+!else
+OUTPRE_DBG=dbg
+!endif
+OUTPRE1=obj
+OUTPRE2=$(OUTPRE1)\$(CPU)
+OUTPRE3=$(OUTPRE2)\$(OUTPRE_DBG)
+OUTPRE=$(OUTPRE3)^\
+
+$(OUTPRE3)$(DIRNUL):
+	-@if not exist $(OUTPRE1)$(DIRNUL) mkdir $(OUTPRE1)
+	-@if not exist $(OUTPRE2)$(DIRNUL) mkdir $(OUTPRE2)
+	-@if not exist $(OUTPRE3)$(DIRNUL) mkdir $(OUTPRE3)
+	@if exist $(OUTPRE3)$(DIRNUL) echo Output going into $(OUTPRE3)
+	@if not exist $(OUTPRE1)$(DIRNUL) echo The directory $(OUTPRE1) could not be created.
+	@if exist $(OUTPRE1)$(DIRNUL) if not exist $(OUTPRE2)$(DIRNUL) echo The directory $(OUTPRE2) could not be created.
+	@if exist $(OUTPRE2)$(DIRNUL) if not exist $(OUTPRE3)$(DIRNUL) echo The directory $(OUTPRE3) could not be created.
+
+
+clean-windows-dir::
+	-@if exist $(OUTPRE3)$(DIRNUL) rmdir $(OUTPRE3)
+	-@if exist $(OUTPRE2)$(DIRNUL) rmdir $(OUTPRE2)
+	-@if exist $(OUTPRE1)$(DIRNUL) rmdir $(OUTPRE1)
+	@if exist $(OUTPRE2)$(DIRNUL) echo The directory $(OUTPRE2) is not empty.
+	@if not exist $(OUTPRE2)$(DIRNUL) if exist $(OUTPRE1)$(DIRNUL) echo The directory $(OUTPRE1) is not empty.
+
+# Directory syntax:
+#
+# begin absolute path
+ABS=^\
+# begin relative path
+REL=
+# up-directory
+U=..
+# path separator
+S=^\
+# this is magic... should only be used for preceding a program invocation
+C=.^\
+
+srcdir = .
+SRCTOP = $(srcdir)\$(BUILDTOP)
+
+!if defined(KRB5_USE_DNS) || defined(KRB5_USE_DNS_KDC) || defined(KRB5_USE_DNS_REALMS)
+!if defined(KRB5_NO_WSHELPER)
+DNSMSG=resolver
+!else
+DNSMSG=wshelper
+DNSFLAGS=-DWSHELPER=1
+!endif
+!if !defined(DNS_INC)
+!message Must define DNS_INC to point to $(DNSMSG) includes dir!
+!error
+!endif
+!if !defined(DNS_LIB)
+!message Must define DNS_LIB to point to $(DNSMSG) library!
+!error
+!endif
+DNSLIBS=$(DNS_LIB)
+DNSFLAGS=-I$(DNS_INC) $(DNSFLAGS) -DKRB5_DNS_LOOKUP=1
+!if defined(KRB5_USE_DNS_KDC)
+DNSFLAGS=$(DNSFLAGS) -DKRB5_DNS_LOOKUP_KDC=1
+!endif
+!if defined(KRB5_USE_DNS_REALMS)
+DNSFLAGS=$(DNSFLAGS) -DKRB5_DNS_LOOKUP_REALM=1
+!endif
+!else
+DNSLIBS=
+DNSFLAGS=
+!endif
+
+!if defined(KRB5_KFW_COMPILE)
+KFWFLAGS=-DUSE_LEASH=1
+!endif
+
+#
+# The name of the C compiler for the target
+#
+CC=cl
+
+PDB_OPTS=-Fd$(OUTPRE)\ -FD
+CPPFLAGS=-I$(SRCTOP)\include -I$(SRCTOP)\include\krb5 $(DNSFLAGS) -DKRB5_PRIVATE=1 -DWIN32_LEAN_AND_MEAN -DKRB5_DEPRECATED=1 $(KFWFLAGS)
+CCOPTS=-nologo /W3 $(PDB_OPTS) $(DLL_FILE_DEF)
+LOPTS=-nologo -incremental:no
+
+# /ZI gives better debug info in each object file (MSVC 6.0 or higher).
+# /Zi gives debug info in each object file.
+# /Gs Avoid stack probes (they don't seem to work anyway)
+# /Os optimize for space.  FIXME:  Do not use /Ox; it miscompiles the DES lib!
+# /Od disable optimization (for debugging)
+# /MD (Win32) thread safe, ML would be single threaded, don't build with ML
+
+#
+# CCOPTS  was for DLL compiles
+# CCOPTS2 was for non-DLL compiles (EXEs, for example)
+#
+!ifdef NODEBUG
+!ifdef DEBUG_SYMBOL
+CCOPTS=/ZI $(CCOPTS)
+LOPTS=$(LOPTS) -debug
+!endif
+CCOPTS=/Os /MD $(CCOPTS)
+LOPTS=$(LOPTS)
+!else
+CCOPTS=/Od /ZI /MDd $(CCOPTS)
+LOPTS=$(LOPTS) -debug
+!endif
+
+# XXX - NOTE: We should probably use DllMainCRTStartup
+DLL_LINKOPTS=$(LOPTS) -dll -entry:DllMain
+EXE_LINKOPTS=$(LOPTS)
+
+RM=$(BUILDTOP)\config\rm.bat
+LIBECHO=$(BUILDTOP)\util\windows\$(OUTPRE)libecho
+CP=copy/b nul:+
+MV=ren
+LN=copy
+LIBCMD=lib
+AWK=rem
+RC = rc
+CVTRES = cvtres
+
+WCONFIG_EXE=$(BUILDTOP)\$(OUTPRE)wconfig.exe
+WCONFIG=$(WCONFIG_EXE:.exe=) $(WCONFIG_FLAGS)
+
+CLIB=$(BUILDTOP)\lib\$(OUTPRE)comerr32.lib
+PLIB=$(BUILDTOP)\lib\$(OUTPRE)xpprof32.lib
+KLIB=$(BUILDTOP)\lib\$(OUTPRE)krb5_32.lib
+K4LIB=$(BUILDTOP)\lib\$(OUTPRE)krb4_32.lib
+SLIB=$(BUILDTOP)\lib\$(OUTPRE)k5sprt32.lib
+GLIB=$(BUILDTOP)\lib\$(OUTPRE)gssapi32.lib
+WLIB=
+
+KRB4_INCLUDES=-I$(BUILDTOP)/include/kerberosIV
+
+COM_ERR_DEPS	= $(BUILDTOP)/include/com_err.h
+
+ARADD=rem
+RANLIB=rem
+ARCHIVE=rem
+
+LIBEXT=lib
+OBJEXT=obj
+EXEEXT=.exe
+
+MFLAGS=$(MAKEFLAGS)
+!ifdef MIGNORE
+MAKE=-$(MAKE)
+!endif
+
+CFLAGS = $(CCOPTS)
+ALL_CFLAGS = $(DEFS) $(DEFINES) $(LOCALINCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+C_RULE_STUFF=$(CC) $(ALL_CFLAGS) -Fo$(OUTPRE)\ -c
+C_RULE_PRINT=$(C_RULE_STUFF)
+C_RULE=$(C_RULE_STUFF) $<
+
+{}.rc{$(OUTPRE)}.res:
+	$(RC) $(RCFLAGS) -fo $@ -r $<
+
+{}.c{$(OUTPRE)}.obj:
+	@if "%DO_C_RULE_PRINT%"=="1" echo %C_RULE_PRINT% ...
+	@set DO_C_RULE_PRINT=
+	@$(C_RULE)
+
+{}.cxx{$(OUTPRE)}.obj:
+	@if "%DO_C_RULE_PRINT%"=="1" echo %C_RULE_PRINT% ...
+	@set DO_C_RULE_PRINT=
+	@$(C_RULE)
+
+{}.cpp{$(OUTPRE)}.obj:
+	@if "%DO_C_RULE_PRINT%"=="1" echo %C_RULE_PRINT% ...
+	@set DO_C_RULE_PRINT=
+	@$(C_RULE)
+
+#
+# End of Win32 pre-config lines (config/win-pre.in)
+#
+
diff --git a/mechglue/src/config/winexclude.sed b/mechglue/src/config/winexclude.sed
new file mode 100644
index 000000000..fd76486ac
--- /dev/null
+++ b/mechglue/src/config/winexclude.sed
@@ -0,0 +1,20 @@
+/krb5\.saber/d
+/autoconf.h$/d
+/t_mddriver$/d
+/test_parse$/d
+/test_profile$/d
+/\.orig$/d
+/\.rej/d
+/\.ico$/d
+/\.doc$/d
+/\.hlp$/d
+/\.hpj$/d
+/\.o$/d
+/\.a$/d
+/\.zip$/d
+/\.tar$/d
+/\.lib$/d
+/\.dll$/d
+/~$/d
+/winfile.list$/d
+/macfile.list$/d
diff --git a/mechglue/src/configure.in b/mechglue/src/configure.in
new file mode 100644
index 000000000..74985522d
--- /dev/null
+++ b/mechglue/src/configure.in
@@ -0,0 +1,550 @@
+K5_AC_INIT([aclocal.m4])
+dnl
+dnl autoconf 2.49 defaults to a /dev/null cache file, which is what we
+dnl do not want for performance reasons. 
+if test "x$cache_file" = "x/dev/null"; then
+  cache_file=./config.cache
+  AC_CACHE_LOAD
+fi
+dnl
+CONFIG_RULES
+KRB5_VERSION=K5_VERSION
+AC_SUBST(KRB5_VERSION)
+dnl
+dnl
+AC_REQUIRE_CPP
+dnl
+dnl The following lines are so that configure --help gives some global 
+dnl configuration options.
+dnl
+KRB5_LIB_AUX
+AC_KRB5_TCL
+AC_ARG_ENABLE([athena],
+[  --enable-athena         build with MIT Project Athena configuration],,)
+dnl
+if test -z "$KRB4_LIB"; then
+kadminv4=""
+krb524=""
+libkrb4=""
+KRB4=""
+else
+kadminv4=kadmin.v4
+krb524=krb524
+libkrb4=lib/krb4
+KRB4=krb4
+fi
+AC_SUBST(KRB4)
+AC_SUBST(krb524)
+dnl
+dnl Begin autoconf tests for the Makefiles generated out of the top-level
+dnl configure.in...
+dnl
+AC_CHECK_FUNCS(memmove)
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+KRB5_BUILD_PROGRAM
+dnl for slave
+AC_TYPE_MODE_T
+AC_PROG_INSTALL
+KRB5_AC_NEED_DAEMON
+KRB5_GETSOCKNAME_ARGS
+KRB5_GETPEERNAME_ARGS
+LIBUTIL=
+AC_CHECK_LIB(util,main,[AC_DEFINE(HAVE_LIBUTIL,1,[Define if the util library is available])
+LIBUTIL=-lutil
+])
+AC_SUBST(LIBUTIL)
+dnl for kdc
+AC_CHECK_HEADERS(syslog.h stdarg.h sys/select.h sys/sockio.h ifaddrs.h unistd.h)
+AC_CHECK_FUNCS(openlog syslog closelog strftime vsprintf)
+KRB5_NEED_PROTO([#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+/* Solaris 8 declares swab in stdlib.h.  */
+#include <stdlib.h>
+],swab,1)
+dnl
+AC_PROG_AWK
+KRB5_AC_INET6
+KRB5_SOCKADDR_SA_LEN
+CHECK_SIGNALS
+dnl
+dnl --with-vague-errors disables useful error messages.
+dnl
+AC_ARG_WITH([vague-errors],
+AC_HELP_STRING([--with-vague-errors],[Do not @<:@do@:>@ send helpful errors to client]), , withval=no)dnl
+if test "$withval" = yes; then
+	AC_MSG_RESULT(Supplying vague error messages to KDC clients)
+	AC_DEFINE(KRBCONF_VAGUE_ERRORS,1,[Define if the KDC should return only vague error codes to clients])
+fi
+dnl
+dnl --with-kdc-kdb-update makes the KDC update the database with last request
+dnl information and failure information.
+dnl
+AC_ARG_WITH([kdc-kdb-update],
+AC_HELP_STRING([--with-kdc-kdb-update],[Update the database @<:@don't update@:>@]), , withval=no)dnl
+if test "$withval" = yes; then
+	AC_MSG_RESULT(Updating KDC database with each request)
+	AC_DEFINE(KRBCONF_KDC_MODIFIES_KDB,1,[Define if KDC should update database with each request])
+fi
+dnl
+dnl Needed for hw-preauth replay detection on KDC.
+dnl
+dnl USE_RCACHE enables the replay cache
+dnl NOCACHE disables the lookaside cache
+dnl
+dnl The lookaside cache is checked first; if *exactly* the same message
+dnl comes in twice, e.g., because the (legitimate) client resent it,
+dnl the previous response will be resent.  Otherwise, the replay cache
+dnl is used to check for attempts to fake out the KDC.  Some hardware
+dnl preauth methods are weak enough that we *really* want to have this
+dnl checking turned on.
+dnl
+AC_ARG_ENABLE([kdc-replay-cache],
+AC_HELP_STRING([--enable-kdc-replay-cache],[check for replayed/retransmitted KDC requests (recommended when hardware preauthentication is in use) @<:@disabled@:>@]), , enableval=yes)dnl
+if test "$enableval" = yes ; then
+	AC_DEFINE(USE_RCACHE,1,[Define if the KDC should use a replay cache])
+else
+	AC_DEFINE(NOCACHE,1,[Define if the KDC should use no replay cache])
+fi
+AC_ARG_ENABLE([fakeka],
+AC_HELP_STRING([--enable-fakeka],[build the Fake KA server (emulates an AFS kaserver) @<:@default: don't build@:>@]), , enableval=no)dnl
+if test "$enableval" = yes; then
+	FAKEKA=fakeka
+else
+	FAKEKA=
+fi
+AC_SUBST(FAKEKA)
+KRB5_RUN_FLAGS
+dnl
+dnl for krb524
+AC_TYPE_SIGNAL
+dnl
+dnl from old include/configure.in
+AH_TEMPLATE([HAVE_STRUCT_SOCKADDR_STORAGE], 
+[Define if "struct sockaddr_storage" is available.])
+dnl
+AC_CONFIG_HEADER(include/krb5/autoconf.h)
+AC_PROG_INSTALL
+AC_PROG_AWK
+AC_PROG_LEX
+AC_C_CONST
+AC_CHECK_FUNCS(strdup setvbuf inet_ntoa inet_aton seteuid setresuid setreuid setegid setresgid setregid setsid flock fchmod chmod strftime strptime geteuid setenv unsetenv getenv gethostbyname2 getifaddrs gmtime_r localtime_r pthread_mutex_lock sched_yield dlopen bswap16 bswap64 mkstemp)
+AC_HEADER_STDARG
+AC_CHECK_HEADERS(unistd.h paths.h regex.h regexp.h regexpr.h fcntl.h memory.h ifaddrs.h sys/filio.h sched.h byteswap.h machine/endian.h machine/byte_order.h sys/bswap.h endian.h)
+dnl bswap_16 is a macro in byteswap.h under GNU libc
+AC_MSG_CHECKING(for bswap_16)
+AC_CACHE_VAL(krb5_cv_bswap_16,[
+AC_TRY_LINK([#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif],[bswap_16(37);],krb5_cv_bswap_16=yes,krb5_cv_bswap_16=no)])
+AC_MSG_RESULT($krb5_cv_bswap_16)
+if test "$krb5_cv_bswap_16" = yes; then
+  AC_DEFINE(HAVE_BSWAP_16,1,[Define to 1 if bswap_16 is available via byteswap.h])
+fi
+AC_MSG_CHECKING(for bswap_64)
+AC_CACHE_VAL(krb5_cv_bswap_64,[
+AC_TRY_LINK([#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif],[bswap_64(37);],krb5_cv_bswap_64=yes,krb5_cv_bswap_64=no)])
+AC_MSG_RESULT($krb5_cv_bswap_64)
+if test "$krb5_cv_bswap_64" = yes; then
+  AC_DEFINE(HAVE_BSWAP_64,1,[Define to 1 if bswap_64 is available via byteswap.h])
+fi
+dnl
+dnl Check what the return types for gethostbyname_r and getservbyname_r are.
+dnl
+AC_CHECK_FUNC(gethostbyname_r,[
+ac_cv_func_gethostbyname_r=yes
+if test "$ac_cv_func_gethostbyname_r" = yes; then
+  AC_MSG_CHECKING([if gethostbyname_r returns an int])
+  AC_CACHE_VAL(krb5_cv_gethostbyname_r_returns_int,
+  [AC_TRY_COMPILE([#include <netdb.h>
+  extern int gethostbyname_r ();], [1;],
+  krb5_cv_gethostbyname_r_returns_int=yes,
+  krb5_cv_gethostbyname_r_returns_int=no)])
+  AC_MSG_RESULT($krb5_cv_gethostbyname_r_returns_int)
+
+  AC_MSG_CHECKING([if gethostbyname_r returns a pointer])
+  AC_CACHE_VAL(krb5_cv_gethostbyname_r_returns_ptr,
+  [AC_TRY_COMPILE([#include <netdb.h>
+  extern struct hostent *gethostbyname_r ();], [1;],
+  krb5_cv_gethostbyname_r_returns_ptr=yes,
+  krb5_cv_gethostbyname_r_returns_ptr=no)])
+  AC_MSG_RESULT($krb5_cv_gethostbyname_r_returns_ptr)
+
+  if test "$krb5_cv_gethostbyname_r_returns_int" = "$krb5_cv_gethostbyname_r_returns_ptr"; then
+    AC_MSG_WARN(cannot determine return type of gethostbyname_r -- disabling)
+    ac_cv_func_gethostbyname_r=no
+  fi
+  if test "$krb5_cv_gethostbyname_r_returns_int" = yes; then
+    AC_DEFINE(GETHOSTBYNAME_R_RETURNS_INT, 1, [Define if gethostbyname_r returns int rather than struct hostent * ])
+  fi
+fi
+if test "$ac_cv_func_gethostbyname_r" = yes; then
+  AC_DEFINE(HAVE_GETHOSTBYNAME_R, 1, [Define if gethostbyname_r exists and its return type is known])
+  AC_CHECK_FUNC(gethostbyaddr_r)
+fi
+])
+dnl
+
+AC_CHECK_FUNC(getpwnam_r,ac_cv_func_getpwnam_r=yes,ac_cv_func_getpwnam_r=no)
+AC_CHECK_FUNC(getpwuid_r,ac_cv_func_getpwuid_r=yes,ac_cv_func_getpwuid_r=no)
+if test "$ac_cv_func_getpwnam_r" = yes; then
+  AC_MSG_CHECKING([return type of getpwnam_r])
+  AC_CACHE_VAL(krb5_cv_getpwnam_r_return_type,
+  [AC_TRY_COMPILE([#include <pwd.h>
+   extern int getpwnam_r();], [1;],
+   getpwnam_r_returns_int=yes,getpwnam_r_returns_int=no)
+   AC_TRY_COMPILE([#include <pwd.h>
+   extern struct passwd *getpwnam_r();], [1;],
+   getpwnam_r_returns_ptr=yes,getpwnam_r_returns_ptr=no)
+   case "$getpwnam_r_returns_int/$getpwnam_r_returns_ptr" in
+     yes/no) krb5_cv_getpwnam_r_return_type=int ;;
+     no/yes) krb5_cv_getpwnam_r_return_type=ptr ;;
+     *) krb5_cv_getpwnam_r_return_type=unknown ;;
+   esac])
+  AC_MSG_RESULT($krb5_cv_getpwnam_r_return_type)
+  if test $krb5_cv_getpwnam_r_return_type = int; then
+    AC_DEFINE(GETPWNAM_R_RETURNS_INT, 1, [Define if getpwnam_r returns an int])
+  elif test $krb5_cv_getpwnam_r_return_type = unknown; then
+    AC_MSG_WARN([Cannot determine getpwnam_r return type, disabling getpwnam_r])
+    ac_cv_func_getpwnam_r=no
+  fi
+fi
+if test "$ac_cv_func_getpwnam_r" = yes; then
+  AC_MSG_CHECKING([number of arguments to getpwnam_r])
+  AC_CACHE_VAL(krb5_cv_getpwnam_r_args,
+  [AC_TRY_COMPILE([#include <pwd.h>
+   struct passwd pwx; char buf[1024];],
+   [getpwnam_r("", &pwx, buf, sizeof(buf));], args4=yes, args4=no)
+   AC_TRY_COMPILE([#include <pwd.h>
+   struct passwd pwx, *p; char buf[1024];],
+   [getpwnam_r("", &pwx, buf, sizeof(buf), &p);], args5=yes, args5=no)
+   case $args4/$args5 in
+     yes/no) krb5_cv_getpwnam_r_args=4 ;;
+     no/yes) krb5_cv_getpwnam_r_args=5 ;;
+     *) krb5_cv_getpwnam_r_args=unknown ;;
+   esac])
+  AC_MSG_RESULT($krb5_cv_getpwnam_r_args)
+  if test "$krb5_cv_getpwnam_r_args" = unknown; then
+    AC_MSG_WARN([Cannot determine number of arguments to getpwnam_r, disabling its use.])
+    ac_cv_func_getpwnam_r=no
+  else
+    AC_DEFINE(HAVE_GETPWNAM_R,1,[Define if getpwnam_r is available and useful.])
+    if test "$krb5_cv_getpwnam_r_args" = 4; then
+      AC_DEFINE(GETPWNAM_R_4_ARGS,1,[Define if getpwnam_r exists but takes only 4 arguments (e.g., POSIX draft 6 implementations like some Solaris releases).])
+    fi
+  fi
+fi
+
+if test "$ac_cv_func_getpwnam_r" = no && test "$ac_cv_func_getpwuid_r" = yes; then
+  # Actually, we could do this check, and the corresponding checks
+  # for return type and number of arguments, but I doubt we'll run
+  # into a system where we'd get to use getpwuid_r but not getpwnam_r.
+  AC_MSG_NOTICE([getpwnam_r not useful, so disabling getpwuid_r too])
+  ac_cv_func_getpwuid_r=no
+fi
+if test "$ac_cv_func_getpwuid_r" = yes; then
+  AC_DEFINE(HAVE_GETPWUID_R,1,[Define if getpwuid_r is available and useful.])
+  # Hack: Assume getpwuid_r is the shorter form if getpwnam_r is.
+  if test "$krb5_cv_getpwnam_r_args" = 4; then
+    AC_DEFINE(GETPWUID_R_4_ARGS,1,[Define if getpwuid_r exists but takes only 4 arguments (e.g., POSIX draft 6 implementations like some Solaris releases).])
+  fi
+fi
+
+if test "$ac_cv_func_gmtime_r" = yes; then
+  AC_MSG_CHECKING([whether gmtime_r returns int])
+  AC_CACHE_VAL(krb5_cv_gmtime_r_returns_int,
+  [AC_TRY_COMPILE([#include <time.h>
+   extern int gmtime_r ();], [1;], return_int=yes, return_int=no)
+   AC_TRY_COMPILE([#include <time.h>
+   extern struct tm *gmtime_r ();], [1;], return_ptr=yes, return_ptr=no)
+   case $return_int/$return_ptr in
+     yes/no) krb5_cv_gmtime_r_returns_int=yes ;;
+     no/yes) krb5_cv_gmtime_r_returns_int=no ;;
+     *)      # Can't figure it out, punt the function.
+             ac_cv_func_gmtime_r=no ;;
+   esac])
+  if test "$ac_cv_func_gmtime_r" = no; then
+    AC_MSG_RESULT(unknown -- ignoring gmtime_r)
+  else
+    AC_MSG_RESULT($krb5_cv_gmtime_r_returns_int)
+    if test "$krb5_cv_gmtime_r_returns_int" = yes; then
+      AC_DEFINE(GMTIME_R_RETURNS_INT,1,[Define if gmtime_r returns int instead of struct tm pointer, as on old HP-UX systems.])
+    fi
+  fi
+fi
+
+AC_CHECK_FUNC(getservbyname_r,[
+ac_cv_func_getservbyname_r=yes
+if test "$ac_cv_func_getservbyname_r" = yes; then
+  AC_MSG_CHECKING([if getservbyname_r returns an int])
+  AC_CACHE_VAL(krb5_cv_getservbyname_r_returns_int,
+  [AC_TRY_COMPILE([#include <netdb.h>
+  extern int getservbyname_r ();], [1;],
+  krb5_cv_getservbyname_r_returns_int=yes,
+  krb5_cv_getservbyname_r_returns_int=no)])
+  AC_MSG_RESULT($krb5_cv_getservbyname_r_returns_int)
+
+  AC_MSG_CHECKING([if getservbyname_r returns a pointer])
+  AC_CACHE_VAL(krb5_cv_getservbyname_r_returns_ptr,
+  [AC_TRY_COMPILE([#include <netdb.h>
+  extern struct servent *getservbyname_r ();], [1;],
+  krb5_cv_getservbyname_r_returns_ptr=yes,
+  krb5_cv_getservbyname_r_returns_ptr=no)])
+  AC_MSG_RESULT($krb5_cv_getservbyname_r_returns_ptr)
+
+  if test "$krb5_cv_getservbyname_r_returns_int" = "$krb5_cv_getservbyname_r_returns_ptr"; then
+    AC_MSG_WARN(cannot determine return type of getservbyname_r -- disabling)
+    ac_cv_func_getservbyname_r=no
+  fi
+  if test "$krb5_cv_getservbyname_r_returns_int" = yes; then
+    AC_DEFINE(GETSERVBYNAME_R_RETURNS_INT, 1, [Define if getservbyname_r returns int rather than struct servent * ])
+  fi
+fi
+if test "$ac_cv_func_getservbyname_r" = yes; then
+  AC_DEFINE(HAVE_GETSERVBYNAME_R, 1, [Define if getservbyname_r exists and its return type is known])
+  AC_CHECK_FUNC(getservbyport_r)
+fi
+])
+dnl
+HAVE_YYLINENO
+CHECK_DIRENT
+AC_TYPE_UID_T
+AC_TYPE_MODE_T
+dnl
+AC_CHECK_HEADER(termios.h,dnl
+[AC_CHECK_FUNC([tcsetattr],dnl
+  AC_DEFINE(POSIX_TERMIOS,1,[Define if termios.h exists and tcsetattr exists]))])
+dnl
+KRB5_SIGTYPE
+AC_CHECK_HEADERS(stdlib.h string.h stddef.h unistd.h sys/types.h sys/file.h sys/param.h sys/stat.h sys/time.h netinet/in.h sys/uio.h sys/filio.h sys/select.h time.h paths.h)
+AC_HEADER_STDARG
+KRB5_AC_INET6
+dnl
+dnl If compiling with IPv6 support, test if in6addr_any functions.
+dnl Irix 6.5.16 defines it, but lacks support in the C library.
+if test $krb5_cv_inet6 = yes || test "$krb5_cv_inet6_with_dinet6" = yes ; then
+AC_CACHE_CHECK([for in6addr_any definition in library], 
+  krb5_cv_var_in6addr_any,
+[AC_TRY_LINK([
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+],[
+  struct sockaddr_in6 in;
+  in.sin6_addr = in6addr_any;
+  printf("%x", &in);
+],krb5_cv_var_in6addr_any=yes, krb5_cv_var_in6addr_any=no)])
+  if test $krb5_cv_var_in6addr_any = no; then
+    AC_DEFINE(NEED_INSIXADDR_ANY,1,[Define if in6addr_any is not defined in libc])
+  fi
+fi
+
+dnl
+dnl
+dnl check for ANSI stdio, esp "b" option to fopen().  This (unfortunately)
+dnl requires a run check...
+dnl
+AC_MSG_CHECKING([for ANSI stdio])
+AC_CACHE_VAL(krb5_cv_has_ansi_stdio,
+[AC_TRY_RUN(
+[#include <stdio.h>
+int main()
+{
+  FILE *conftest;
+  if ((conftest = fopen("conftest.dat", "w")) == NULL) exit(1);
+  if (fclose(conftest)) exit(1);
+  if ((conftest = fopen("conftest.dat", "rb+")) == NULL) exit(1);
+  if (fputs("testing ANSI for stdio\n", conftest) == EOF) exit(1);
+  exit(0);
+}],
+krb5_cv_has_ansi_stdio=yes, krb5_cv_has_ansi_stdio=no,
+krb5_cv_has_ansi_stdio=yes)])dnl assume ANSI in cross environment
+AC_MSG_RESULT($krb5_cv_has_ansi_stdio)
+if test $krb5_cv_has_ansi_stdio = yes; then
+AC_DEFINE(ANSI_STDIO,1,[Define if ANSI stdio is present (in particular "b" option to fopen)])
+fi
+dnl
+dnl Word sizes...
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+dnl
+dnl then from osconf.h, we have
+dnl
+AC_HEADER_TIME
+AC_CHECK_TYPE(time_t, long)
+dnl
+dnl Determine where to put the replay cache.
+dnl
+AC_MSG_CHECKING([for replay cache directory])
+AC_CACHE_VAL(krb5_cv_sys_rcdir,
+[
+for t_dir in /var/tmp /usr/tmp /var/usr/tmp /tmp ; do
+	test -d $t_dir || continue
+	krb5_cv_sys_rcdir=$t_dir
+	break
+done])dnl
+AC_MSG_RESULT($krb5_cv_sys_rcdir)
+KRB5_RCTMPDIR=$krb5_cv_sys_rcdir
+AC_SUBST(KRB5_RCTMPDIR)
+dnl
+dnl
+AC_MSG_CHECKING(for socklen_t)
+AC_CACHE_VAL(krb5_cv_has_type_socklen_t,
+[AC_TRY_COMPILE(
+[#include <sys/types.h>
+#include <sys/socket.h>
+],[sizeof (socklen_t);],
+krb5_cv_has_type_socklen_t=yes,krb5_cv_has_type_socklen_t=no)])
+AC_MSG_RESULT($krb5_cv_has_type_socklen_t)
+if test $krb5_cv_has_type_socklen_t = yes; then
+    AC_DEFINE(HAVE_SOCKLEN_T,1,[Define if there is a socklen_t type. If not, probably use size_t])
+fi
+dnl
+AC_MSG_CHECKING(for struct lifconf)
+AC_CACHE_VAL(krb5_cv_has_struct_lifconf,
+[AC_TRY_COMPILE(
+[#include <sys/socket.h>
+#include <net/if.h>
+],[sizeof (struct lifconf);],
+krb5_cv_has_struct_lifconf=yes,krb5_cv_has_struct_lifconf=no)])
+AC_MSG_RESULT($krb5_cv_has_struct_lifconf)
+if test $krb5_cv_has_struct_lifconf = yes; then
+    AC_DEFINE(HAVE_STRUCT_LIFCONF,1,[Define if there is a struct lifconf.])
+fi
+dnl HP-UX 11 uses stuct if_laddrconf
+AC_MSG_CHECKING(for struct if_laddrconf)
+AC_CACHE_VAL(krb5_cv_has_struct_if_laddrconf,
+[AC_TRY_COMPILE(
+[#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if6.h>
+],[sizeof (struct if_laddrconf);],
+krb5_cv_has_struct_if_laddrconf=yes,krb5_cv_has_struct_if_laddrconf=no)])
+AC_MSG_RESULT($krb5_cv_has_struct_if_laddrconf)
+if test $krb5_cv_has_struct_if_laddrconf = yes; then
+    AC_DEFINE(HAVE_STRUCT_IF_LADDRCONF,1,[Define if there is a struct if_laddrconf.])
+fi
+dnl
+dnl
+AC_MSG_CHECKING([for h_errno in netdb.h])
+AC_CACHE_VAL(krb5_cv_header_netdb_h_h_errno,
+[AC_TRY_COMPILE(
+	[#include <netdb.h>],
+	[int x = h_errno;], krb5_cv_header_netdb_h_h_errno=yes,
+	krb5_cv_header_netdb_h_h_errno=no)])
+AC_MSG_RESULT($krb5_cv_header_netdb_h_h_errno)
+if test $krb5_cv_header_netdb_h_h_errno = yes; then
+    AC_DEFINE([HAVE_NETDB_H_H_ERRNO], 1,
+	[Define if netdb.h declares h_errno])
+fi
+dnl
+dnl
+AC_ARG_ENABLE([athena],
+[  --enable-athena         build with MIT Project Athena configuration],
+AC_DEFINE(KRB5_ATHENA_COMPAT,1,[Define if MIT Project Athena default configuration should be used]),)
+
+if test "$KRB4_LIB" = ''; then
+	AC_MSG_NOTICE(No Kerberos 4 compatibility)
+	maybe_kerberosIV=
+else
+	AC_MSG_NOTICE(Kerberos 4 compatibility enabled)
+	maybe_kerberosIV=kerberosIV
+	AC_DEFINE(KRB5_KRB4_COMPAT,1,[Define if Kerberos V4 backwards compatibility should be supported])
+fi
+AC_SUBST(maybe_kerberosIV)
+dnl
+AC_C_INLINE
+AH_TOP([
+#ifndef KRB5_AUTOCONF_H
+/* Leading comment stops autoconf/config.status from turning these
+   into #define statements.  But the preprocessor will still pay
+   attention to them.  (Comment removal is in translation phase 3;
+   processing of #undef is phase 4.)  */
+/*x*/#undef PACKAGE_NAME
+/*x*/#undef PACKAGE_VERSION
+/*x*/#undef PACKAGE_BUGREPORT
+/*x*/#undef PACKAGE_STRING
+/*x*/#undef PACKAGE_TARNAME
+])
+AH_BOTTOM([
+#if defined(__GNUC__) && !defined(inline)
+/* Silence gcc pedantic warnings about ANSI C.  */
+# define inline __inline__
+#endif
+
+#define KRB5_AUTOCONF_H
+#endif
+])
+dnl
+dnl Not used yet, but let's find out what we've got on the platforms
+dnl we're working with....
+AC_CHECK_HEADERS(inttypes.h stdint.h)
+AC_CHECK_TYPES([uint32_t, int32_t, uint64_t, int64_t, uint_least32_t, uintptr_t, uintmax_t, long long], , , [
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#endif
+])
+dnl
+dnl
+dnl Check for thread safety issues.
+dnl (Is there a better place for this?)
+dnl tsfuncs="getpwnam_r getpwuid_r gethostbyname_r getservbyname_r gmtime_r localtime_r"
+dnl Removed getpwnam_r and getpwuid_r because include/configure.in has some
+dnl more careful checks, and may decide to pretend that they're not found if
+dnl the function signatures can't be figured out.
+tsfuncs="gethostbyname_r getservbyname_r gmtime_r localtime_r"
+AC_CHECK_FUNCS($tsfuncs)
+if test "$enable_thread_support" = yes; then
+  tsmissing=""
+  for ts in $tsfuncs; do
+    if eval "test \"\${ac_cv_func_$ts}\" != yes"; then
+      tsmissing="$tsmissing $ts"
+    fi
+  done
+  if test "$ac_cv_func_res_nsearch/$ac_cv_lib_resolv_res_nsearch" = "no/no"; then
+    tsmissing="$tsmissing res_nsearch"
+  fi
+  if test "$tsmissing" != ""; then
+    AC_MSG_WARN([Some functions that are needed for library thread])
+    AC_MSG_WARN([safety appear to be missing.])
+    for ts in $tsmissing; do
+      AC_MSG_WARN([  missing thread-safe function: $ts])
+    done
+    AC_MSG_WARN([Without these functions, the installed libraries])
+    AC_MSG_WARN([may not be thread-safe.])
+  fi # tsmissing not empty
+fi # enable_thread_support
+dnl
+HOST_TYPE=$krb5_cv_host
+AC_SUBST(HOST_TYPE)
+dnl
+dnl
+if test "$COM_ERR_VERSION" = k5 ; then
+  AC_CONFIG_SUBDIRS(util/et)
+fi
+if test "$SS_VERSION" = k5 ; then
+  AC_CONFIG_SUBDIRS(util/ss)
+fi
+AC_CONFIG_SUBDIRS(util/profile util/pty)
+AC_CONFIG_SUBDIRS(lib/crypto lib/krb5 lib/des425 lib/apputils)
+if test -n "$KRB4_LIB"; then
+  AC_CONFIG_SUBDIRS(lib/krb4)
+fi
+AC_CONFIG_SUBDIRS(lib/kdb lib/gssapi lib/rpc lib/kadm5)
+dnl if test -n "$KRB4_LIB"; then
+dnl   AC_CONFIG_SUBDIRS(krb524)
+dnl fi
+
+AC_CONFIG_SUBDIRS(kadmin clients plugins/kdb/db2 appl tests)
+AC_CONFIG_FILES(krb5-config, [chmod +x krb5-config])
+V5_AC_OUTPUT_MAKEFILE(. util util/support util/send-pr lib kdc slave krb524 config-files gen-manpages include include/krb5 include/kerberosIV)
diff --git a/mechglue/src/gen-manpages/ChangeLog b/mechglue/src/gen-manpages/ChangeLog
new file mode 100644
index 000000000..7c7cb1a1c
--- /dev/null
+++ b/mechglue/src/gen-manpages/ChangeLog
@@ -0,0 +1,43 @@
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-24  Jen Selby <jenselby@mit.edu>
+
+	* kerberos.M: updated the output line from kinit
+
+1999-01-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, configure.in: Move the responsibility for
+		generating the Makefile in this directory to the top-level
+		configure script.  The local configure.in script has been
+		deleted.
+
+Wed Feb 18 15:46:07 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (thisconfigdir): Remove trialing slash.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Sep 10 14:22:14 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install): don't install header.doc
+
+	* k5login.M, kerberos.M: remove ".so man1/header.doc"
+
+Tue Aug 27 16:38:29 1996  Jeff Bigler  <jcb@viola.cygnus.com>
+
+	* Makefile.in (install): Added line to install .k5login man page.
+
+	* k5login.M: new file
+
+Sat Aug  3 15:35:19 1996  Michael Graff  <explorer@lenin.cygnus.com>
+
+	* configure.in:  add CONFIG_RULES and AC_PROG_INSTALL checks
+
diff --git a/mechglue/src/gen-manpages/Makefile.in b/mechglue/src/gen-manpages/Makefile.in
new file mode 100644
index 000000000..a005278b5
--- /dev/null
+++ b/mechglue/src/gen-manpages/Makefile.in
@@ -0,0 +1,9 @@
+thisconfigdir=./..
+myfulldir=gen-manpages
+mydir=gen-manpages
+BUILDTOP=$(REL)..
+all::
+
+install::
+	$(INSTALL_DATA) $(srcdir)/kerberos.M ${DESTDIR}$(CLIENT_MANDIR)/kerberos.1
+	$(INSTALL_DATA) $(srcdir)/k5login.M ${DESTDIR}$(FILE_MANDIR)/.k5login.5
diff --git a/mechglue/src/gen-manpages/header.doc b/mechglue/src/gen-manpages/header.doc
new file mode 100644
index 000000000..d11228786
--- /dev/null
+++ b/mechglue/src/gen-manpages/header.doc
@@ -0,0 +1 @@
+.ds h ""Kerberos V5 release Beta 7" "MIT Project Athena"
diff --git a/mechglue/src/gen-manpages/k5login.M b/mechglue/src/gen-manpages/k5login.M
new file mode 100644
index 000000000..d6b30ae57
--- /dev/null
+++ b/mechglue/src/gen-manpages/k5login.M
@@ -0,0 +1,55 @@
+.TH .K5LOGIN 5
+.SH NAME
+.k5login \- Kerberos V5 acl file for host access.
+.SH DESCRIPTION
+The
+.B .k5login
+file, which resides in a user's home directory, contains a list of the
+Kerberos principals.  Anyone with valid tickets for a principal in the
+file is allowed host access with the UID of the user in whose home
+directory the file resides.  One common use is to place a
+.B .k5login
+file in root's home directory, thereby granting system administrators
+remote root access to the host via Kerberos.
+.SH EXAMPLES
+Suppose the user "janedoe" had a 
+.B .k5login
+file in her home directory containing the following line:
+.sp
+.nf
+.in +1i
+johndoe@FUBAR.ORG
+.in -1i
+.fi
+.sp
+This would allow her husband "johndoe" to use any of the Kerberos
+network applications, such as
+.IR telnet (1),
+.IR rlogin (1),
+.IR rsh (1),
+and
+.IR rcp (1),
+to access her account, using his own Kerberos tickets.
+.PP
+Let us further suppose that "janedoe" is a system administrator.  She
+and the other system administrators would have their principals in
+root's
+.B .k5login
+file on each host:
+.sp
+.nf
+.in +1i
+janedoe@BLEEP.COM
+joeadmin/root@BLEEP.COM
+.in -1i
+.fi
+.sp
+This would allow either system administrator to log in to these hosts
+using their Kerberos tickets instead of having to type the root
+password.  Note that because "janedoe"'s husband retains the Kerberos
+tickets for his own principal, "johndoe@FUBAR.ORG", he would not have
+any of the privileges that require his wife's tickets, such as root
+access to any of her site's hosts, or the ability to change her
+password.
+.SH SEE ALSO
+telnet(1), rlogin(1), rsh(1), rcp(1), ksu(1), telnetd(8), klogind(8)
diff --git a/mechglue/src/gen-manpages/kerberos.M b/mechglue/src/gen-manpages/kerberos.M
new file mode 100644
index 000000000..b412be570
--- /dev/null
+++ b/mechglue/src/gen-manpages/kerberos.M
@@ -0,0 +1,143 @@
+.\" Copyright 1989 by the Massachusetts Institute of Technology.
+.\"
+.\" For copying and distribution information,
+.\" please see the file <mit-copyright.h>.
+.\" "
+.TH KERBEROS 1
+.SH NAME
+kerberos \- introduction to the Kerberos system
+.SH DESCRIPTION
+The Kerberos system authenticates individual users in a network
+environment.  After authenticating yourself to Kerberos, you can use
+network utilities such as
+.IR rlogin ,
+.IR rcp ,
+and
+.IR rsh
+without having to present passwords to remote hosts and without having
+to bother with
+.I \.rhosts
+files.  Note that these utilities will work without passwords only if
+the remote machines you deal with support the Kerberos system.
+.PP
+If you enter your username and
+.I kinit
+responds with this message:
+.PP
+kinit(v5): Client not found in Kerberos database while getting initial
+credentials
+.PP
+you haven't been registered as a Kerberos user.  See your system
+administrator.
+.PP
+A Kerberos name usually contains three parts.  The first is the
+.IR primary ,
+which is usually a user's or service's name.  The second is the
+.IR instance ,
+which in the case of a user is usually null.  Some users may have
+privileged instances, however, such as ``root'' or ``admin''.  In the
+case of a service, the instance is the fully qualified name of the
+machine on which it runs; i.e. there can be an
+.I rlogin
+service running on the machine ABC, which is different from the rlogin
+service running on the machine XYZ.  The third part of a Kerberos name
+is the
+.IR realm .
+The realm corresponds to the Kerberos service providing authentication
+for the principal.
+.PP
+When writing a Kerberos name, the principal name is separated from the
+instance (if not null) by a slash, and the realm (if not the local
+realm) follows, preceded by an ``@'' sign.  The following are examples
+of valid Kerberos names:
+.sp
+.nf
+.in +8
+david
+jennifer/admin
+joeuser@BLEEP.COM
+cbrown/root@FUBAR.ORG
+.in -8
+.fi
+.PP
+When you authenticate yourself with Kerberos you get an initial Kerberos
+.IR ticket .
+(A Kerberos ticket is an encrypted protocol message that provides
+authentication.)  Kerberos uses this ticket for network utilities such
+as
+.I rlogin
+and
+.IR rcp .
+The ticket transactions are done transparently, so you don't have to
+worry about their management.
+.PP
+Note, however, that tickets expire.  Privileged tickets, such as those
+with the instance ``root'', expire in a few minutes, while tickets that
+carry more ordinary privileges may be good for several hours or a day,
+depending on the installation's policy.  If your login session extends
+beyond the time limit, you will have to re-authenticate yourself to
+Kerberos to get new tickets.  Use the
+.IR kinit
+command to re-authenticate yourself.
+.PP
+If you use the
+.I kinit
+command to get your tickets, make sure you use the
+.I kdestroy
+command to destroy your tickets before you end your login session.  You
+should put the
+.I kdestroy
+command in your
+.I \.logout
+file so that your tickets will be destroyed automatically when you
+logout.  For more information about the
+.I kinit
+and
+.I kdestroy
+commands, see the
+.IR kinit (1)
+and
+.IR kdestroy (1)
+manual pages.
+.PP
+Kerberos tickets can be forwarded.  In order to forward tickets, you
+must request
+.I forwardable
+tickets when you
+.IR kinit .
+Once you have forwardable tickets, most Kerberos programs have a command
+line option to forward them to the remote host.
+.PP
+Currently, Kerberos support is available for the following network
+services:
+.IR rlogin ,
+.IR rsh ,
+.IR rcp ,
+.IR telnet ,
+.IR ftp ,
+.I krdist
+(a Kerberized version of
+.IR rdist ),
+.I ksu
+(a Kerberized version of
+.IR su ),
+.IR login ,
+and
+.IR Xdm .
+.SH "SEE ALSO"
+kdestroy(1), kinit(1), klist(1), kpasswd(1), rsh (1), rcp(1), rlogin(1),
+telnet(1), ftp(1), krdist(1), ksu(1), sclient(1), xdm(1), des_crypt(3),
+hash(3), krb5strings(3), krb5.conf(5), kdc.conf(5), kadmin(8),
+kadmind(8), kdb5_util(8), telnetd(8), ftpd(8), rdistd(8), sserver(8),
+klogind(8c), kshd(8c), login(8c)
+.SH BUGS
+.SH AUTHORS
+Steve Miller, MIT Project Athena/Digital Equipment Corporation
+.br
+Clifford Neuman, MIT Project Athena
+.SH HISTORY
+Kerberos was developed at MIT.  OpenVision rewrote and donated the
+administration server, which is used in the current version of Kerberos
+5.
+.SH RESTRICTIONS
+Copyright 1985,1986,1989-1996,2002 Massachusetts Institute of Technology
diff --git a/mechglue/src/include/.Sanitize b/mechglue/src/include/.Sanitize
new file mode 100644
index 000000000..75b559ff8
--- /dev/null
+++ b/mechglue/src/include/.Sanitize
@@ -0,0 +1,46 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+Makefile.in
+bsdlib.h
+bstring.h
+configure
+configure.in
+fake-stdlib.h
+k5-int.h
+kerberosIV
+krb5
+krb5.hin
+sys
+syslog.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/include/.rconf b/mechglue/src/include/.rconf
new file mode 100644
index 000000000..283d25c23
--- /dev/null
+++ b/mechglue/src/include/.rconf
@@ -0,0 +1 @@
+copy syslog.h
diff --git a/mechglue/src/include/ChangeLog b/mechglue/src/include/ChangeLog
new file mode 100644
index 000000000..e5c7530e8
--- /dev/null
+++ b/mechglue/src/include/ChangeLog
@@ -0,0 +1,3236 @@
+2005-12-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (USE_PTHREAD_LOCK_ONLY_IF_LOADED): Define any time
+	HAVE_PRAGMA_WEAK_REF is defined.
+
+2005-12-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (k5_mutex_lock_update_stats) [__GNUC__]: Use an
+	inline function, to avoid "statement with no effect" warnings.
+
+2005-10-20  Jeffrey Altman <jaltman@mit.edu>
+
+	* win-mac.h: 
+          - Add definitions for int64_t and uint64_t
+	  - Force the use of 32-bit time_t on 32-bit Windows
+          - Correct the definition of MAX_SIZE to use the value
+            of SIZE_MAX which is defined in limits.h
+          - Add check to ensure that 32-bit time_t is forced
+            only when k5-int.h has been loaded.
+        * k5-int.h:
+          - Add check to ensure that k5-int.h is loaded before
+            krb5.h
+        * krb5.hin:
+          - Modify prototypes of functions that take krb5_int32
+            when they are really passing krb5_timestamp values
+            krb5_us_timeofday, krb5_timeofday, krb5_set_real_time,
+            krb5_set_debugging_time, krb5_get_time_offsets,
+            krb5_set_time_offsets
+
+2005-10-20  Jeffrey Altman <jaltman@mit.edu>
+
+	* win-mac.h: Add definitions for int32_t and uint32_t
+
+2005-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (k5_key_t): Add K5_KEY_KDB_ERR_HANDLER and
+	K5_KEY_KADM_CLNT_ERR_HANDLER.
+
+2005-06-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h: Include endian.h if it's available, or
+	machine/endian.h if it's available.  Include byteswap.h if
+	available.
+	(K5_LE, K5_BE): Define based on endianness macros from header
+	files, if available.  Only do the architecture tests if this
+	fails.
+	(SWAP16, SWAP32, SWAP64): Define if byteswap.h and bswap_16 are
+	available.
+	({load,store}_{16,32,64}_le): Disable building of little-endian
+	versions, which aren't currently used.
+
+2005-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (load_*): Change argument type to point to const.
+	(K5_BE, K5_LE): New macros, defined based on architecture macros
+	for certain big-endian and little-endian platforms, respectively.
+	(PUT, GET) [__GNUC__]: New macros.  Use GCC's packed-structure
+	support to do unaligned loads and stores.
+	(PUTSWAPPED, GETSWAPPED) [__GNUC__]: Similar, but invoke a
+	SWAP<size> macro (not defined yet) to swap the bytes of the
+	value.
+	(store_*, load_*): Use these macros when using GCC, depending on
+	endianness and availability of the SWAP<size> macros.
+
+2005-06-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (MAYBE_DEFINE_CALLINIT_FUNCTION)
+	[DELAY_INITIALIZER]: New macro.  If not __GNUC__, define
+	k5_call_init_function in the expansion; otherwise, do nothing.
+	(MAKE_INIT_FUNCTION) [DELAY_INITIALIZER]: Use it.
+	(k5_call_init_function): Don't define function form at top level.
+
+2005-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (krb5int_pthread_loaded) [HAVE_PRAGMA_WEAK_REF]:
+	Declare.
+	(K5_PTHREADS_LOADED) [HAVE_PRAGMA_WEAK_REF]: Use it.
+
+2005-05-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (encode_krb5_sam_challenge, encode_krb5_sam_key,
+	encode_krb5_enc_sam_response_enc, encode_krb5_sam_response,
+	decode_krb5_sam_challenge, decode_krb5_enc_sam_response_enc,
+	decode_krb5_sam_response, decode_krb5_predicted_sam_response,
+	krb5_validate_times): Delete duplicate declarations.
+
+2005-05-19  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h (krb5int_c_ free_keyblock init_keyblock free_keyblock_contents):  new
+
+2005-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Deleted, content merged into ../configure.in.
+	* Makefile.in (thisconfigdir, mydir): Updated for configure
+	change.
+	($(srcdir)/krb5/autoconf.stmp): Use $(thisconfigdir) when
+	locating configure.in and autom4te.cache.
+
+2005-05-06  Sam Hartman  <hartmans@mit.edu>
+
+	
+	* krb5.hin: Add krb5_c_prf_length
+
+
+2005-04-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h: Include fcntl.h only if HAVE_FCNTL_H is defined.
+	(krb5int_zap_data): For PalmOS without gcc, call memset but
+	without the volatile cast.
+
+	* port-sockets.h: On PalmOS, include autoconf.h and netdb.h, and
+	define socklen_t.
+	* socket-utils.h: Include k5-platform.h.
+	(sa2sin, sa2sin6, ss2sa, ss2sin, ss2sin6): Always use inline
+	function form, and use "inline" instead of "__inline__".
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h: Remove disabled code that used to be part of the
+	non-NEED_SOCKETS case.
+
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't check for getpwnam_r and getpwuid_r with
+	AC_CHECK_FUNCS; use AC_CHECK_FUNC, and only set shell variables.
+	Run stricter tests on return types and numbers of arguments, and
+	only define the C macros if these parameters can actually be
+	determined.
+	* k5-platform.h (k5_getpwnam_r, k5_getpwuid_r): New macros.
+
+	* Makefile.in ($(srcdir)/krb5/autoconf.stmp): Nuke autom4te.cache
+	directory.
+
+	* k5-platform.h: Expand on init/fini comments some more.
+	(MAKE_FINI_FUNCTION): Add an HP-UX specific variant that defines
+	an auxiliary function fitting the signature of HP-UX 10 library
+	combined initializer/finalizer functions.
+
+2005-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check return type of gmtime_r, and define
+	GMTIME_R_RETURNS_INT if it returns int.  If the return type can't
+	be determined, pretend the function isn't there.
+
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (PROGRAM_EXITING) [__GNUC__ && !_WIN32 &&
+	CONSTRUCTOR_ATTR_WORKS]: Define as zero.
+
+2005-02-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Put #ifndef/#define/#endif wrapper into
+	autoconf.h to protect against multiple inclusions.  Don't look for
+	xom.h.  Check for dlopen.
+
+2005-01-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-thread.h (k5_os_mutex_lock): Under Irix, invoke
+	k5_pthread_mutex_lock() with the k5_os_mutex, not the
+	pthread_mutex_t.
+	(k5_pthread_assert_locked,unlocked): If DEBUG_THREADS not use, provide
+	correct prototype. Add missing close paren.
+
+2005-01-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h [HAVE_PTHREAD && HAVE_PRAGMA_WEAK_REF]: Mark
+	pthread_self and pthread_equal as weak references.
+
+2005-01-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (k5_os_mutex) [pthread case]: Add new field "owner"
+	if DEBUG_THREADS.
+	(k5_pthread_mutex_lock, k5_pthread_mutex_unlock,
+	k5_pthread_assert_locked): New macros/functions; if DEBUG_THREADS,
+	and thread support loaded, set or check the owner field.
+	(K5_OS_MUTEX_PARTIAL_INITIALIZER) [pthread case && DEBUG_THREADS]:
+	Set the owner field.  If PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+	is defined, use it.
+	(k5_os_mutex_lock, k5_os_mutex_unlock, k5_os_mutex_assert_locked)
+	[pthread case]: Use k5_pthread_ versions.
+	(k5_mutex_destroy): Update the location data with the mutex
+	locked, before destroying it.
+	(k5_mutex_unlock): Update the location data while the mutex is
+	still locked, and check the assertion that the mutex really is
+	locked.  Convert inline function to macro.
+
+	* k5-thread.h (krb5int_mutex_lock_update_stats,
+	krb5int_mutex_unlock_update_stats, krb5int_mutex_report_stats)
+	[!DEBUG_THREADS_STATS]: Declare KRB5_CALLCONV.
+
+2005-01-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (krb5int_zap_data): Fix preprocessor test for Windows.
+
+2005-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (KRB5_CALLCONV, KRB5_CALLCONV_C): Define if not
+	defined.
+	(krb5int_mutx_lock_update_stats,
+	krb5int_mutex_unlock_update_stats, krb5int_mutex_report_stats)
+	[!DEBUG_THREADS_STATS]: Declare, with KRB5_CALLCONV.
+	(k5_debug_make_loc): Change "lineno" to type int.
+	(k5_debug_make_loc): Likewise for argument "line".
+
+
+2005-01-04  Jeffrey Altman <jaltman@mit.edu>
+
+        * krb5.hin: add prototype for krb5_is_thread_safe
+
+2005-01-04  Jeffrey Altman <jaltman@mit.edu>
+
+        * win-mac.h: define NEED_INSIXADDR_ANY for ipv6 symbol
+
+2005-01-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for uint32_t and int32_t in system headers.
+
+	* Makefile.in (krb5.h): Don't pull in autoconf SIZEOF macros.
+
+2004-12-21  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Flag krb5_principal2salt as KRB5_CALLCONV_WRONG.
+
+
+2004-12-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (KRB5INT_ACCESS_STRUCT_VERSION): Bump to 9.
+	(struct _krb5int_access): Add function pointer field use_dns_kdc.
+
+2004-12-07  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: Add prf_length to the keytype function
+
+	* krb5.hin: Add krb5_c_prf
+
+2004-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h [DEBUG_THREADS_STATS]: Include string.h and
+	inttypes.h.
+	(get_current_time) [DEBUG_THREADS_STATS]: Define as inline.
+	(k5_mutex_init_stats) [DEBUG_THREADS_STATS]: Save away current
+	time as creation time.
+	(k5_mutex_stats_tmp): New typedef, k5_debug_time_t if recording
+	stats, dummy int otherwise.
+	(k5_mutex_stats_start): New macro, get current time if recording,
+	zero otherwise.
+	(krb5int_mutex_lock_update_stats,
+	krb5int_mutex_unlock_update_stats, krb5int_mutex_report_stats)
+	[DEBUG_THREADS_STATS]: Declare.
+	(krb5int_mutex_report_stats) [! DEBUG_THREADS_STATS]: New macro,
+	does nothing.
+	(k5_mutex_lock_update_stats, k5_mutex_unlock_update_stats): New
+	macros, map to krb5int_ functions if recording, dummy statements
+	otherwise.
+	(k5_mutex_destroy): Call krb5int_mutex_report_stats.
+	(k5_mutex_lock, k5_mutex_lock_1): Call k5_mutex_stats_start and
+	k5_mutex_lock_update_stats.
+	(k5_mutex_unlock_1): Call k5_mutex_unlock_update_stats.
+
+2004-11-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* win-mac.h (HAVE_GETADDRINFO, HAVE_GETNAMEINFO): Define.
+
+2004-11-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct _krb5_cc_ops): Add new function pointer field
+	get_flags.
+
+	* krb5.hin (krb5_cc_get_flags): Declare.
+
+2004-11-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h: Move most of code content into
+	util/support/fake-addrinfo.c.
+	(krb5int_getaddrinfo, krb5int_freeaddrinfo, krb5int_getnameinfo,
+	krb5int_gai_strerror): Declare.
+	(getaddrinfo, freeaddrinfo, getnameinfo, gai_strerror): Define as
+	macros mapping to the krb5int_ function names.
+
+2004-10-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h: Include errno.h earlier.
+
+2004-10-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (return_after_yield, k5_mutex_lock) [__GNUC__]: Add
+	macro versions so debugging line numbers will be useful.
+	(DEBUG_THREADS_SLOW): Don't define.
+
+2004-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (AI_ADDRCONFIG, AI_V4MAPPED, AI_ALL): If not
+	defined, or when completely faking getaddrinfo, define them as
+	zero.
+
+2004-10-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for struct if_laddrconf, as for struct
+	lifconf.
+
+2004-09-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use AC_MSG_NOTICE for krb4 messages instead of
+	AC_MSG_RESULT, because there's no corresponding AC_MSG_CHECKING.
+
+2004-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Remove KRB5_AC_NEED_BIND_8_COMPAT.
+
+2004-09-15  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Check for h_errno declaration in netdb.h.
+
+	* port-sockets.h: Explicitly declare h_errno if it's missing.
+
+2004-09-10  Tom Yu  <tlyu@mit.edu>
+
+	* port-sockets.h: Remove _XOPEN_SOURCE_EXTENDED hack for netdb.h,
+	as it can cause inconsistencies between headers.  It significantly
+	broke HP-UX 10.20 anyway.
+
+2004-09-01  Jeffrey Altman <jaltman@mit.edu>
+
+        * krb5.hin: define KRB5_TC_NOTICKET for use with krb5_cc_set_flags
+
+2004-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (fai_add_hosts_by_name): Handle case where
+	returned ai_canonname is null.
+
+2004-08-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (k5_os_nothread_mutex_assert_locked,
+	k5_os_nothread_mutex_assert_unlocked, k5_os_mutex_assert_locked,
+	k5_os_mutex_assert_unlocked): Assertion macros should always have
+	type void.
+
+2004-08-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (k5_os_nothread_mutex_finish_init,
+	k5_os_nothread_mutex_init, k5_os_nothread_mutex_destroy,
+	k5_os_nothread_mutex_lock, k5_os_nothread_mutex_unlock)
+	[!DEBUG_THREADS]: Replace macros with inline functions, to gain
+	type checking and eliminate gratuitous compiler warnings.
+	(k5_pthread_assert_unlocked, k5_pthread_assert_locked): Likewise.
+	(k5_os_mutex_finish_init) [HAVE_PTHREAD &&
+	!USE_PTHREAD_LOCK_ONLY_IF_LOADED]: Likewise.
+	(return_after_yield): New inline function.
+	(k5_os_mutex_lock) [HAVE_PTHREAD]: Change back to a macro,
+	calling return_after_yield.
+
+2004-08-09  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Solaris getpwnam_r returns struct passwd*, not
+	struct pwd*.
+
+2004-08-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: If getpwnam_r is available, determine its return
+	type.
+
+2004-08-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Look for sched.h and sched_yield.
+	* k5-thread.h: Only include sched.h if it's available.
+	(MAYBE_SCHED_YIELD): Only use sched_yield if sched.h and
+	sched_yield are available; if weak references are supported and
+	sched_yield isn't available by default, check for it at run time.
+
+2004-08-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h [HAVE_PTHREAD]: Include sched.h if
+	DEBUG_THREADS_SLOW is defined.
+	(MAYBE_SCHED_YIELD) [HAVE_PTHREAD]: Define, to call sched_yield or
+	not, depending on DEBUG_THREADS_SLOW.
+	(k5_os_mutex_lock, k5_os_mutex_unlock) [HAVE_PTHREAD]: Use
+	MAYBE_SCHED_YIELD.
+	(DEBUG_THREADS_SLOW): Define.
+
+2004-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Actually check for pthread_mutex_lock.
+
+	* k5-int.h (krb5_rc_recover_or_initialize): Declare.
+
+2004-07-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h [HAVE_PRAGMA_WEAK_REF]: Declare the pthread mutex
+	functions as weak.
+	(USE_PTHREAD_LOCK_ONLY_IF_LOADED): Define if pthread_mutex_lock
+	isn't available by default.
+
+2004-07-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h: Include k5-thread.h.
+	(struct fac): Add a mutex.
+	(plant_face, find_face): Check that mutex is already locked.
+	(krb5int_lock_fac, krb5int_unlock_fac): Declare.
+	(fai_add_hosts_by_name): Use them to lock and unlock the mutex.
+
+2004-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Look for "struct lifconf" and maybe define
+	HAVE_STRUCT_LIFCONF.
+
+2004-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (struct face, struct fac): Always declare.
+	(krb5int_fac): Renamed from fac, and made extern.  Always
+	declare.
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in, port-sockets.h: Don't check for macsock.h.
+
+	* fake-addrinfo.h: Don't include netdb.h, since port-sockets.h
+	already does.
+	* port-sockets.h: Define _XOPEN_SOURCE_EXTENDED around inclusion
+	of netdb.h if it's not defined and not Windows, as fake-addrinfo.h
+	used to do; otherwise just include it normally.
+
+	* port-sockets.h (inet_ntop): Cast NULL to desired return pointer
+	type.
+
+2004-07-15  Alexandra Ellwood  <lxs@mit.edu>
+
+	* k5-int.h (krb5_os_context) 
+        Removed default_ccprincipal field from krb5_context
+
+2004-07-14  Jeffrey Altman <jaltman@mit.edu>
+
+    * k5-int.h: define for WIN32 the macro krb5int_zap_data to 
+      utilize the Win32 API SecureZeroMemory which is guaranteed
+      by Microsoft not to be optimized out by the compiler.
+      Both memset and ZeroMemory will be optimized out by the 
+      compiler when possible.
+
+2004-07-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (k5_call_init_function) [DELAY_INITIALIZER]
+	[__GNUC__]: Use a statement expression so any line number info
+	printed by assertion failures is useful.
+
+	* k5-thread.h (k5_os_mutex_init, k5_os_mutex_destroy): If
+	USE_PTHREAD_LOCK_ONLY_IF_LOADED is defined, use pthread_mutex_init
+	and _destroy only if pthread support is loaded.
+	(k5_key_t): Add a couple new values for GSSAPI ccache name
+	manipulation.
+
+2004-07-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (k5_os_mutex_lock, k5_os_mutex_unlock,
+	k5_os_mutex_assert_locked, k5_os_mutex_assert_unlocked)
+	[USE_PTHREAD_LOCK_ONLY_IF_LOADED]: Fix typo in accessing
+	non-pthread versions.
+
+	* configure.in: Check krb5_cv_inet6_with_dinet6 as well as
+	krb5_cv_inet6 when deciding whether to test for in6addr_any.  If
+	gcc is in use, suppress pedantic warnings about "inline".
+
+	* fake-addrinfo.h (in6addr_any): If we need to define a static
+	copy, rename it with a macro first.
+
+2004-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h: Test HAVE_PTHREAD instead of HAVE_PTHREAD_H.
+
+	* win-mac.h (KRB5_USE_INET6, ENABLE_THREADS): Define.
+
+2004-07-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h [! HAVE_PTHREAD_H]: Don't explicitly disable thread
+	support when pthread.h is missing.
+	(k5_os_mutex, K5_OS_MUTEX_PARTIAL_INITIALIZER,
+	k5_os_mutex_finish_init, k5_os_mutex_init, k5_os_mutex_destroy,
+	k5_os_mutex_lock, k5_os_mutex_unlock, k5_os_mutex_assert_unlocked,
+	k5_os_mutex_assert_locked) [_WIN32]: Define Windows versions;
+	still not enabled by default.
+
+2004-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h: Use K5_THREAD_H for multiple inclusion protection.
+	(k5_debug_mutex_stats, k5_mutex_init_stats,
+	k5_mutex_finish_init_stats, K5_MUTEX_STATS_INIT): Add some dummy
+	support for recording statistics on how long mutexes are held,
+	etc.  Incomplete implementation started, but code not enabled.
+	(k5_mutex_t): Add statistics field.
+	(K5_MUTEX_PARTIAL_INITIALIZER, k5_mutex_init_1, k5_mutex_init):
+	Initialize it.
+
+	* configure.in: Check for getpwuid_r.
+
+2004-07-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h: Restructured mutex code.
+	(k5_debug_loc): New type, may contain file/line info if
+	DEBUG_THREADS_LOC is defined.
+	(k5_os_nothread_*): Dummy implementation of mutex lock for a
+	single-threded process.  Uses a flag and assert() if DEBUG_THREADS
+	is defined, does nothing interesting otherwise.
+	(k5_os_mutex*, k5_once*): General implementations, with dummy or
+	POSIX or POSIX-if-loaded-otherwise-dummy variants.
+	(k5_mutex_*): Combine OS-specific mutex implementation with
+	optional file/line tracking, and provide a place to instrument for
+	other debugging or performance data.
+
+2004-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Test for 'inline' support.
+	* k5-platform.h (inline): Don't define here.
+	* win-mac.h (inline): Define as __inline.
+
+2004-06-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (k5_debug_assert_locked, k5_debug_assert_unlocked):
+	New macros.
+	(k5_assert_locked, k5_assert_unlocked): New macros, may or may not
+	call the debug macros.
+	(K5_MUTEX_DEBUG_INITIALIZER): Use current file and line.
+	(k5_mutex_debug_finish_init, k5_mutex_debug_init,
+	k5_mutex_debug_destroy): Save current file and line.
+	(k5_mutex_debug_lock): Verify that the lock was unlocked before,
+	and set the state to locked.
+	(k5_mutex_debug_unlock): Verify that the mutex was locked before,
+	and set the state to unlocked.
+	(k5_debug_assert_locked, k5_debug_assert_unlocked): Use
+	k5_mutex_debug_check_init instead of checking initialized==1.
+
+2004-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (JOIN4, JOIN4_2, JOIN3, JOIN3_2): Unused macros
+	deleted.
+	(JOIN__2, JOIN__2_2): Renamed from JOIN2 and JOIN2_2.  Insert
+	two underscores between the tokens supplied.  All uses changed to
+	use new macros, and not use identifiers with leading underscores.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h: Don't test macintosh, __MWERKS__, applec, or THINK_C.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (MAKE_INIT_FUNCTION, CALL_INIT_FUNCTION,
+	INITIALIZER_RAN): Use the linker-driven version for Windows.  The
+	auxinit function definition needs an argument list.
+	(MAKE_FINI_FUNCTION): Likewise.
+
+	* win-mac.h (HAVE_STRERROR, SYS_ERRLIST_DECLARED): Define.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac, clean-mac): Targets deleted.
+
+2004-06-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(srcdir)/krb5/autoconf.stmp): Always use
+	--include, don't try --localdir.
+	(all-recurse): Depend on krb5/autoconf.h.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check number of arguments to getpwnam_r and
+	getpwuid_r and define some new macros if they're the
+	four-argument draft POSIX versions.
+
+2004-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for getpwnam_r, gmtime_r, and localtime_r.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h: Error out at compile time if thread support is
+	enabled but the thread system isn't pthreads.  (This is after the
+	code disabling thread support for non-pthreads systems, so it's a
+	placeholder for now that should never get invoked.)
+
+	* k5-int.h (struct krb5_rc_st, struct _krb5_rc_ops, krb5_rc_ops):
+	Move type definitions to rc-int.h.
+	(krb5_rc_register_type, krb5_rc_dfl_ops): Move declarations to
+	rc-int.h.
+
+2004-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (krb5int_crypto_init, krb5int_prng_init): Declare.
+
+2004-05-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h: On IRIX, with threads enabled, reject gcc older
+	than v3.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* foreachaddr.c: Implementation moved to lib/krb5/os/localaddr.c.
+	* foreachaddr.h: New file.
+	(krb5int_foreach_localaddr): Declare.
+	(foreach_localaddr): New macro.
+
+2004-04-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-thread.h (k5_mutex_debug_check_init,
+	k5_mutex_debug_update_loc): New macros.
+	(k5_mutex_debug_lock, k5_mutex_debug_unlock): Use them.
+	(k5_mutex_lock, k5_mutex_unlock) [ENABLE_THREADS &&
+	DEBUG_THREADS]: Use them instead of k5_mutex_debug_lock and
+	k5_mutex_debug_unlock.
+	(enum k5_mutex_debug_states): New enum.
+	(K5_MUTEX_DEBUG_LOCKED, K5_MUTEX_DEBUG_UNLOCKED): Change to
+	enumerator values.
+	(k5_mutex_debug_info): Use the enum type.  Reorder fields.
+	(K5_MUTEX_DEBUG_INITIALIZER): Update for new field order.
+
+	* k5-int.h: Include k5-thread.h.
+	(struct krb5_rc_st): Add a mutex.
+
+2004-04-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (DELAY_INITIALIZER): Don't define.
+	(CONSTRUCTOR_ATTR_WORKS, DESTRUCTOR_ATTR_WORKS): Don't define.
+	(USE_LINKER_FINI_OPTION): Don't define.
+	(MAYBE_DUMMY_INIT): New macro, to optionally produce a dummy
+	initializer for the linker to reference in the case where other
+	options indicate we don't want to use it.
+	(MAKE_INIT_FUNCTION): Use it in some versions.  Set the exported
+	function name to have a __auxinit suffix.
+	(MAKE_FINI_FUNCTION) [!SHARED]: Declare the function static, and
+	do nothing to try to cause it to get invoked.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (DELAY_INITIALIZER): New macro, defined always.
+	(CONSTRUCTOR_ATTR_WORKS, DESTRUCTOR_ATTR_WORKS): New macro,
+	defined for Linux and NetBSD, and Solaris with gcc.
+	(USE_LINKER_FINI_OPTION): New macro, defined on IRIX, and on
+	Solaris with native compiler.
+	(JOIN2, JOIN2_2, JOIN3, JOIN3_2, JOIN4, JOIN4_2): New utility
+	macros.
+	(k5_init_t): New typedef, for some platforms.
+	(MAKE_INIT_FUNCTION, MAKE_FINI_FUNCTION, CALL_INIT_FUNCTION,
+	INITIALIZER_RAN, PROGRAM_EXITING): New macros for library
+	initialization and finalization support.
+
+	* k5-thread.h: Use k5_mutex_init instead of K5_MUTEX_INITIALIZER
+	for multiple-inclusion protection.
+	(K5_MUTEX_DEBUG_INITIALIZER): Change initial initialized flag to
+	2.
+	(k5_mutex_debug_finish_init): New macro, verifies value 2 and
+	changes it to 1.
+	(k5_mutex_debug_lock): Test various values of initialized and
+	locked flags separately, so assertion failure message is more
+	immediately informative.
+	(K5_MUTEX_PARTIAL_INITIALIZER): Rename from K5_MUTEX_INITIALIZER.
+	(k5_mutex_finish_init): New macro.
+	(pthread_once, pthread_mutexattr_setrobust_np): Consider
+	declaring weak based on availability.
+	(K5_PTHREADS_LOADED): New macro, tests to see if pthread
+	functions are available, if weak references are supported.
+	(k5_mutex_lock, k5_mutex_unlock): On IRIX, redefine to bypass
+	pthread code if pthread library isn't loaded.
+	(k5_once_t): New typedef.
+	(K5_ONCE_INIT, k5_once): New macros.
+
+	* Makefile.in (autoconf.stmp): Depend on aclocal.m4.
+
+	* k5-platform.h: Include limits.h before testing for SIZE_MAX.
+
+	* k5-thread.h (k5_key_t): New enumerator typedef.
+	(k5_key_register, k5_getspecific, k5_setspecific): New macros.
+	(krb5int_key_register, krb5int_getspecific, krb5int_setspecific,
+	krb5int_key_delete): Declare.
+
+2004-04-16  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: krb5int_populate_gic_opt now takes credentials  so it
+	can get lifetime related options out of them 
+
+2004-04-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (krb5int_prng_cleanup): Declare.
+
+2004-03-25  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: Check for mkstemp
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCAL_SUBDIRS): Renamed from MY_SUBDIRS.
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_kt_register): Ops table is now const.
+
+	* k5-thread.h: New file.
+
+2004-02-26  Jeffrey Altman <jaltman@mit.edu>
+
+    * k5-int.h: change prototype declarations necessary to support
+      the use of krb5_get_init_creds_password's use_master as an
+      in/out parameter
+
+2004-02-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* win-mac.h (GETSOCKNAME_ARG2_TYPE, GETSOCKNAME_ARG3_TYPE): Set
+	proper values for Windows here.
+	(GETPEERNAME_ARG2_TYPE, GETPEERNAME_ARG3_TYPE): Map to the
+	getsockname versions.
+
+2004-02-24  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* krb5.hin: Remove des3 with 32-bit length
+
+2004-01-04 Jeffrey Altman <jaltman@mit.edu>
+
+    * win-mac.h: conditionally define strcasecmp/strncasecmp macros 
+      only if they do not already exist.
+
+2003-12-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for flock, fchmod, chmod, strftime,
+	strptime, geteuid, setenv, unsetenv, getenv, gethostbyname2,
+	getifaddrs, stdarg.h, unistd.h, paths.h, regex.h, regexp.h,
+	regexpr.h, fcntl.h, memory.h, ifaddrs.h, and sys/filio.h, as was
+	previously done in the krb5 library configure script.
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h: Include stdio.h.
+
+2003-12-18  Jeffrey Altman <jaltman@mit.edu>
+
+    * k5-int.h: add new functions to krb5int_access for use by gssapi
+
+2003-12-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-platform.h (SIZE_MAX): Provide default definition if stdint.h
+	doesn't define it.
+
+2003-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+  * win-mac.h: source code written to the C99 standard assumes there
+    are standard definitions for the MAX sizes of C types including
+    size_t.  The MAX preprocessor variables are declared in limits.h
+    but limits.h is not included by any of the other header files.
+    We will therefore include it via win-mac.h.  We must also add a
+    declaration of SIZE_MAX (for size_t) because Microsoft does not
+    provide one.  
+
+2003-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+  * k5-platform.h: apply casts (unsigned char) to the assignments from
+    64-bit ints to unsigned char fields to avoid warnings 
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (KRB5_AUTH_CONTEXT_USE_SUBKEY): New macro.
+
+	* k5-int.h (struct krb5_keytypes): Added field required_ctype.
+	(krb5int_c_mandatory_cksumtype): New declaration.
+	(krb5int_generate_and_set_subkey): Declare.
+	(memset) [__GNUC__ && __GLIBC__]: Undef, to reduce compilation
+	warnings in zap() macro with volatile pointer.
+
+	* k5-platform.h: New header file.  Manages inline-function and
+	64-bit support, in platform-specific ways.
+	* fake-addrinfo.h: Include k5-platform.h.
+	(inline): Don't define here.
+	* k5-int.h: Include k5-platform.h.
+	(krb5_ui_8, krb5_int64): New typedefs.
+	(krb5_ser_pack_int64, krb5_ser_unpack_int64): New function decls.
+
+2003-10-08  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h: Add prototypes for decode_krb5_safe_with_body and
+	encode_krb5_safe_with_body.
+
+2003-09-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(srcdir)/krb5/autoconf.h.in): Depend on
+	autoconf.stmp only if maintainer mode is enabled.
+
+2003-09-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for setsid() and <paths.h>.
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (WRAP_GETADDRINFO, COPY_FIRST_CANONNAME): Don't
+	define on Linux unless HAVE_GETADDRINFO is defined, for libc5
+	compatibility.
+
+2003-08-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (struct _krb5_donot_replay, krb5_rc_default)
+	(krb5_rc_resolve_type, krb5_rc_resolve_full, krb5_rc_get_type)
+	(krb5_rc_default_type, krb5_rc_default_name, krb5_auth_to_rep):
+	Private declarations moved...
+	* k5-int.h: ...to here.
+
+	* configure.in: Don't test for labs, memmove or bcopy.
+	* k5-int.h (labs, HAVE_LABS): Never define.
+	* win-mac.h (HAVE_LABS): Don't define.
+
+	* configure.in: Check for some C99 headers and types.
+
+	* fake-addrinfo.h (inline): Supported by Sun Forte Developer 7
+	compiler.
+
+	* foreachaddr.c (foreach_localaddr) [HAVE_IFADDRS_H]: Skip over
+	any returned data structure with a NULL ifa_addr field.
+
+2003-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (getnameinfo): Define to my_fake_getnameinfo
+	only if HAVE_GETADDRINFO is defined.
+
+2003-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (inline): Move definitions further up, before
+	first use.  Do use __inline__ for gcc without c99 support.
+	(GET_SERV_BY_NAME) [!GETSERVBYNAME_R_RETURNS_INT]: Fix invocation
+	for IRIX definition.
+	* socket-utils.h: Include port-sockets.h to get a definition for
+	struct sockaddr_storage.
+
+	First cut at adding local caching to the getaddrinfo support.
+	Still needs work.
+	* fake-addrinfo.h: Delete the unused WRAP_GETNAMEINFO support.
+	(HAVE_GETADDRINFO) [__APPLE__ && __MACH__]: Don't undefine.
+	(FAI_CACHE) [__APPLE__ && __MACH__]: Define.
+	(system_getaddrinfo, system_freeaddrinfo, system_getnameinfo):
+	New functions.
+	(gaiptr, faiptr, gniptr): Variables deleted.  Change references
+	to use the system_* functions above.
+	(getaddrinfo, freeaddrinfo) [FAI_CACHE]: Define as macros to the
+	my_fake_* versions.
+	(protoname, socktypename, familyname): Use caller-supplied
+	buffers instead of local static buffers.
+	(debug_dump_getaddrinfo_args): Provide a buffer.
+	(NEED_FAKE_GETNAMEINFO): Define if HAVE_GETADDRINFO is not
+	defined.
+	(inline): Rework macros to test for C99 and IRIX.
+	(NEED_FAKE_GETADDRINFO): Define if FAI_CACHE is defined.
+	(fai_add_entry) [KRB5_USE_INET6]: Support IPv6.
+	(CACHE_ENTRY_LIFETIME): New macro.
+	(struct face, struct fac): New types.
+	(fac): New static variable.
+	(plant_face, find_face): New functions.
+	(fai_add_hosts_by_name) [FAI_CACHE]: Check the cache before
+	looking up the hostname.  Add the looked-up host info to the
+	cache.
+	(fake_getaddrinfo): Call GET_SERV_BY_NAME instead of
+	conditionally calling getservbyname or getservbyname_r.  Don't
+	pass AF_INET to fai_add_hosts_by_name.
+	(fake_getnameinfo): Define only if NEED_FAKE_GETNAMEINFO is
+	defined.
+	(gai_strerror): Define if either HAVE_FAKE_GETADDRINFO or
+	NEED_FAKE_GETNAMEINFO is defined.
+	(getaddrinfo): Do define function if FAI_CACHE is defined.
+	(getnameinfo): Define only if NEED_FAKE_GETNAMEINFO is defined.
+
+2003-08-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for mode_t.
+
+2003-07-31  Jeffrey Altman  <jaltman@mit.edu>
+
+	* krb5.hin: krb5_get_host_realm and krb5_free_host_realm should
+	not be labeled as KRB5_PRIVATE.  They are required for many
+	applications including OpenAFS and UMich's Kx509.  1.2.8 had them
+	public but the change was never reflected on the trunk.
+
+2003-07-22  Alexandra Ellwood  <lxs@mit.edu>
+
+        * fake-addrinfo.h: Don't use broken getaddrinfo on Mac OS X
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (krb5int_zap_data, zap): New macros; call memset with
+	volatile cast for now.
+	(struct krb5_enc_provider, struct krb5_hash_provider, struct
+	krb5_keyhash_provider): Use numeric values for block size,
+	key size, hash size, etc, instead of function pointers.
+
+2003-07-21  Alexandra Ellwood  <lxs@mit.edu>
+
+        * krb5.hin: Export krb5_principal2salt.
+
+2003-07-09  Alexandra Ellwood  <lxs@mit.edu>
+
+        * krb5.hin: Export krb5_get_permitted_enctypes and 
+        krb5_set_real_time for Samba.
+
+2003-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct krb5_cksumtypes): Add new field trunc_size.
+
+2003-06-12  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: krb524_init_ets() takes one argument.
+
+2003-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct srv_dns_entry): Declare.
+	(krb5int_make_srv_query_realm, krb5int_free_srv_dns_data):
+	Declare.
+	(struct _krb5int_access): Add make_srv_query_realm and
+	free_srv_dns_data fields.
+
+2003-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct _krb5int_access): Add locate_server back in.
+
+2003-05-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (KRB524_SERVICE, KRB524_PORT): Moved here...
+	* krb5.h: ...from here.
+	(krb5_524_convert_creds): Renamed from krb524_convert_creds_kdc,
+	fixed calling convention spec.
+	(krb524_convert_creds_kdc, krb524_init_ets) [KRB5_DEPRECATED]: New
+	macros.
+
+	* Makefile.in (clean-windows): Remove new "timestamp" file when
+	cleaning up.
+
+2003-05-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: Sequence number of krb5_replay_data should be unsigned.
+
+2003-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (krb5.h): Include krb524_err.h.
+	(krb524_err.h): Depend on rebuild-error-tables like krb5_err.h and
+	friends.  Add a null command to cause make to recheck the
+	timestamp on the files possibly updated.
+	(clean-unix): Get rid of it.
+	* k5-int.h (KRb5INT_ACCESS_STRUCT_VERSION): Update to 7.
+	(struct ktext) [!defined(ANAME_SZ)]: Declare forward.
+	(krb5int_access): Delete krb5_locate_kdc, krb5_locate_server,
+	krb5_max_dgram_size and timeout fields.  Add krb_life_to_time,
+	krb_time_to_life, and krb524_encode_v4tkt function pointer
+	fields.  Reorder fields, and add comments.
+	(krb5int_krb_life_to_time, krb5int_krb_time_to_life,
+	krb5int_encode_v4tkt, krb5int_524_sendto_kdc): Declare.
+	* krb5.hin (KRB524_SERVICE, KRB524_PORT): New macros.
+	(struct credentials): Declare forward.
+	(krb524_convert_creds_kdc): Declare.
+
+2003-05-22  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h: Add prototype for krb5int_auth_con_chkseqnum.
+
+	* krb5.hin: Default KRB5_DEPRECATED to 0.  Default KRB5_PRIVATE to
+	0 on all platforms.
+
+2003-05-22  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: krb5int_populate_gic_opt returns void
+
+2003-05-19  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: Prototype krb5int_populate_gic_opt
+
+2003-05-18  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h: Sequence numbers are now unsigned.
+
+	* krb5.hin: Sequence numbers are now unsigned.
+
+2003-05-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (KRB5_KPASSWD_ACCESSDENIED): New macro.
+	(KRB5_KPASSWD_BAD_VERSION, KRB5_KPASSWD_INITIAL_FLAG_NEEDED): New
+	macros.
+
+2003-05-13  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: Add krb5int_copy_data_contents
+
+2003-05-08  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin: Add prototype for krb5_c_string_to_key_with_params
+
+	* k5-int.h: Add s2kparams to krb5_gic_get_as_key_fct
+
+2003-05-07  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin: Add KRB5_PADATA_ETYPE_INFO2
+
+2003-05-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct _krb5_context): New fields conf_tgs_ktypes,
+	conf_tgs_ktypes_count, use_conf_ktypes.
+
+2003-05-09  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Add krb5_auth_con_getsendsubkey,
+	krb5_auth_con_getrecvsubkey, krb5_auth_con_setsendsubkey,
+	krb5_auth_con_setrecvsubkey.  Mark krb5_auth_con_getlocalsubkey
+	and krb5_auth_con_getremotesubkey as deprecated.
+
+2003-05-06  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: Add s2kparams to 
+	krb5_etype_info_entry
+	Add encode_etype_info2 and decode_etype_info2
+
+2003-05-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* port-sockets.h (inet_ntop) [!_WIN32 && !HAVE_MACSOCK_H]: Define
+	as a macro if not provided by the OS.
+
+2003-04-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct _krb5_context): Change os_context to be an
+	array of one _krb5_os_context instead of a void pointer.
+
+2003-04-17  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: Add encode_krb5_setpw_req
+
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin: Add krb5_set_password
+	Move krb5*_chpw internals to k5int.h
+
+	* k5-int.h: Add prototypes for set-password helper functions
+
+2003-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(srcdir)/krb5/autoconf.stmp): Try running
+	autoheader with --include, and if that doesn't work, try
+	--localdir.
+
+2003-04-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (getaddrinfo) [NUMERIC_SERVICE_BROKEN]:
+	Overwrite the port number only if a numeric service port was
+	supplied.
+
+2003-04-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (COPY_FIRST_CANONNAME) [_AIX]: Define.
+	(GET_HOST_BY_NAME) [_AIX]: New version for AIX version of
+	gethostbyname_r.
+	(getaddrinfo) [NUMERIC_SERVICE_BROKEN]: Use "discard" as a dummy
+	service name instead of none at all.  Don't check for unsigned
+	value less than zero.
+	(getaddrinfo) [COPY_FIRST_CANONNAME]: Set any ai_canonname fields
+	other than the first one to null.
+
+2003-03-18  Alexandra Ellwood  <lxs@mit.edu>
+
+    * configure.in: Use KRB5_AC_NEED_BIND_8_COMPAT to check for bind 9
+    and higher.  When bind 9 is present, BIND_8_COMPAT needs to be 
+    defined to get bind 8 types.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+    
+    * krb5.h: Removed enumsalwaysint because there are no typed
+    enums in this header.
+    
+    * k5-int.h: Removed Mac OS header goober. Added prototype for 
+    os_get_default_config_files which will be used by KfM's 
+    preference APIs (KFM needs to get the secure default files as 
+    well as the normal ones). Moved profile.h inclusion higher so 
+    it gets included before this function and thus its types are 
+    defined (the reason I put it where I did was there is another 
+    config file function next to it).
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.h (ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+	ENCTYPE_AES256_CTS_HMAC_SHA1_96, CKSUMTYPE_HMAC_SHA1_96_AES128,
+	CKSUMTYPE_HMAC_SHA1_96_AES256): New macros.
+	* k5-int.h (krb5_str2key_func): Added params argument.
+	(krb5int_pbkdf2_hmac_sha1): Declare.
+	(krb5_cryptosystem_entry, krb5_cs_table_entry, SUM_FUNC,
+	SUM_VERF_FUNC, krb5_checksum_entry): Delete unused declarations.
+
+2003-02-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Set and substitute maybe_kerberosIV.
+	* Makefile.in (MY_SUBDIRS): Use it.
+
+2003-02-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_princ_component): Return NULL if going off the
+	end of the array.
+
+	* configure.in: Check for sys/select.h and time.h.
+
+2003-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-unix): Remove kerberosIV/krb_err.h, as it was
+	causing spurious rebuilds of lots of stuff because it was
+	depending on all-recurse, which is always out of date.
+	(install-headers-unix): Also, no need to depend on
+	kerberosIV/krb_err.h here, since the kerberosIV subdirectory takes
+	care of it.
+
+2003-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_mk_req_checksum_func): Fix Windows calling
+	convention syntax.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* socket-utils.h (socklen_t, krb5int_sockaddr_storage): Move
+	definitions...
+	* port-sockets.h (socklen_t, krb5int_sockaddr_storage): ...to
+	here.
+	(socket) [!_WIN32 && S_SPLINT_S]: Declare with Splint
+	annotations.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+2003-01-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (getaddrinfo) [_AIX]: Always overwrite sa_family
+	and sa_len fields, since sa_family at least may be non-zero *and*
+	wrong.
+	(protoname, socktypename, familyname, debug_dump_getaddrinfo_args,
+	debug_dump_error, debug_dump_error, debug_dump_addrinfos)
+	[DEBUG_ADDRINFO]: New debugging functions.
+	(fake_getaddrinfo, getaddrinfo) [DEBUG_ADDRINFO]: Use them.
+
+2003-01-08  Ezra Peisach  <epeisach@bu.edu>
+
+	* fake-addrinfo.h (freeaddrinfo): Back out 1/3/03 change. ANSI
+	does not require it.
+
+2003-01-08  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin :  Move KRB5_CALLCONV specifier for
+	krb5_mk_req_checksum_func to right place 
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (krb5_cc_dfl_ops): Declare as pointer to const.
+	(struct krb5_rc_st): Field ops now points to const.
+	(krb5_rc_register_type): Ops argument now points to const.
+	(krb5_rc_dfl_ops): Now const.
+	(struct _krb5_ccache): Field ops now points to const.
+
+2003-01-06  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin: Add support for setting a callback to generate the
+	data  checksummed by mk_req
+
+2003-01-03  Ezra Peisach  <epeisach@bu.edu>
+
+	* fake-addrinfo.h (freeaddrinfo): Do not free a NULL pointer.
+
+2002-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_encrypt, krb5_decrypt, krb5_use_enctype,
+	krb5_calculate_checksum, krb5_verify_checksum,
+	krb5_get_credentials, krb5_get_credentials_validate,
+	krb5_get_credentials_renew, krb5_get_cred_via_tkt, krb5_mk_req,
+	krb5_mk_req_extended, krb5_524_conv_principal, krb5_send_tgs,
+	krb5_get_in_tkt, krb5_get_in_tkt_with_password,
+	krb5_get_in_tkt_with_skey, krb5_get_in_tkt_with_keytab,
+	krb5_aname_to_localname): Clean up use of "const" in API, where it
+	was applied to the value passed and not something pointed to.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Update comment on krb5_kt_free_entry prototype to
+	point at the correct recommended function.
+
+2002-12-06  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h: Update prototype of krb5int_locate_server() to take
+	protocol family argument.  Update krb5int_access to current call
+	signatures of locate_kdc() and locate_server(), as well as to add
+	add_host_to_list() for use by krb4 library.
+
+2002-11-26  Tom Yu  <tlyu@mit.edu>
+
+	* port-sockets.h: Add SOCKET_CONNECT, SOCKET_GETSOCKNAME, and
+	SOCKET_CLOSE to allow for porting of some KfM things.
+
+2002-11-14  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove references to adm_err.h from here too.
+
+2002-11-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h [NEED_FAKE_GETADDRINFO]: Include errno.h.
+	(fake_getnameinfo): Check that socklen_t size arguments are
+	positive and fit in size_t; return EAI_SYSTEM/EINVAL if not.  Use
+	the size_t variants when calling string functions.
+	[_AIX]: Define NUMERIC_SERVICE_BROKEN.
+	[NUMERIC_SERVICE_BROKEN]: Include ctype.h and stdlib.h.
+	(getaddrinfo) [NUMERIC_SERVICE_BROKEN]: If the service name is a
+	numeric string, save its value and the socket type, pass a null
+	pointer to the real getaddrinfo, and patch the returned results.
+
+2002-10-23  Sam Hartman  <hartmans@mit.edu>
+
+	* spnego-asn1.h: New file.
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h (DEFAULT_PWD_STRING1, DEFAULT_PWD_STRING2): Remove
+	trailing colon, as new implementation of krb5_read_password()
+	appends it.
+
+2002-10-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (krb5_ser_handle): Now points to const.
+	(krb5_kt_dfl_ops): Now const.
+	(struct _krb5_kt_ops): Field serializer now points to const
+	krb5_ser_entry instead of void.
+	* krb5.hin (struct _krb5_kt): Field ops now points to const.
+
+2002-10-30  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* krb5.hin: Change definitions of new SAM preauth types to
+	match kerberos-clarifications.
+
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* k5-int.h, krb5.hin: Add new protocols, definitions, and
+	data structures for new hardware preauthentication protocol.
+
+2002-10-23  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* krb5.hin: Add new LRQ type for password expiration
+	(from krb-clarifications)
+
+2002-10-07  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in : Add install-headers support
+
+2002-09-26  Tom Yu  <tlyu@mit.edu>
+
+	* socket-utils.h (sa2sin, sa2sin6): Add redundant cast to (void *)
+	to get GCC to shut up about alignment increasing.
+
+2002-09-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* port-sockets.h: Include sys/filio.h if available.
+
+2002-09-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for sys/filio.h.
+
+	* cm.h: New file.
+
+2002-09-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (maybe-make-db.h-sys, maybe-make-db.h-k5): New
+	targets, doing nothing.
+	(maybe-make-db.h-redirect): New target, creates db.h using
+	@DB_HEADER@.
+	(all-unix): Depend on maybe-make-db.h-@DB_HEADER_VERSION@.
+
+2002-09-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (gaiptr, faiptr, gniptr): Delete duplicate
+	declarations.
+
+	* foreachaddr.c: Include errno.h instead of declaring errno.
+
+2002-09-03  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Use AH_TEMPLATE to put undefined definition of
+	HAVE_STRUCT_SOCKADDR_STORAGE in krb5/autoconf.h - allowing for
+	acconfig.h to be removed.
+
+	* Makefile.in (autoconf.stmp): No longer depend on
+	$(SRCTOP)/acconfig.h.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* port-sockets.h (SG_BUF): New macro.
+
+	* k5-int.h (krb5int_sendto_udp, krb5int_sendto_tcp): Declarations
+	deleted.
+	(krb5int_sendto, krb5int_grow_addrlist): New decls.
+
+2002-08-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct _krb5_context): Add new member udp_pref_limit.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (install): Don't install port-sockets.h.
+
+2002-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin: Put # for cpp directives in first column.
+
+2002-07-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h: Always include socket support headers; don't check
+	NEED_SOCKETS.
+	(krb5int_sendto_udp): Update prototype.
+	(struct _krb5int_access): Update sendto_udp field declaracion to
+	match krb5int_sendto_udp.
+
+2002-07-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* port-sockets.h (SOCKET_WRITEV) [!_WIN32]: Use TMP after setting
+	it, to silence compiler warnings.
+
+	* configure.in: Rewrite gethostbyname_r and getservbyname_r tests
+	to properly disable the use of these functions if the argument
+	types cannot be determined.
+
+	* fake-addrinfo.h [NEED_FAKE_GETADDRINFO]: Include string.h.
+	(fake_getnameinfo): Cast GET_HOST_BY_ADDR address pointer argument
+	to char * as required by gethostbyaddr prototype.
+	(HAVE_GETADDRINFO, HAVE_GETNAMEINFO): If defining, define them to
+	1.
+
+2002-06-26  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Modify test for in6addr_any definition in C
+	library. Original test was stripped out by optimizing gcc
+	compiler.
+
+2002-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (GET_SERV_BY_PORT) [HAVE_GETSERVBYNAME_R &&
+	!GETSERVBYNAME_R_RETURNS_INT]: Fix getservbyport_r calling
+	sequence, based on IRIX man pages.
+	(getaddrinfo) [WRAP_GETADDRINFO]: Handle case where gethostbyname
+	fails because host has no IPv4 addresses.  Don't return a success
+	indication without replacing the old ai_canonname value if it
+	wasn't null.
+
+	* socket-utils.h (ss2sin6): Enable compilation of inline function
+	version.
+
+	* configure.in: Check for seteuid, setresuid, setreuid, setegid,
+	setresgid and setregid.
+	* k5-util.h: Include sys/types.h, unistd.h, and stdlib.h if
+	available; include krb5/autoconf.h and errno.h always.
+	(krb5_seteuid, krb5_setegid): Replace function declarations with
+	macro definitions.
+	(krb5_setedid): Delete declaration of non-existent function.
+	(krb5_compat_recvauth, krb5_compat_recvauth_version): Declarations
+	deleted.
+
+2002-06-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* port-sockets.h (win_socket_initialize): Delete declaration,
+	since it's not mentioned elsewhere in the tree.
+
+2002-06-21  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Fix up yet more CALLCONV botches from last merge.
+
+2002-06-21  Ezra Peisach  <epeisach@bu.edu>
+
+	* fake-addrinfo.h: If IPv6 support is compiled in, but the OS does
+	not provide in6addr_any in libc, provide a static copy.
+
+	* configure.in: If IPv6 support is compiled in, test for existence
+	of in6addr_any in libc.
+
+2002-06-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* port-sockets.h [!_WIN32 && !HAVE_MACSOCK_H]: Include
+	krb5/autoconf.h, to get HAVE_SYS_UIO_H.
+
+2002-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for sys/uio.h.
+	* port-sockets.h [!_WIN32 && !HAVE_MACSOCK_H]: Include sys/uio.h
+	if available, to get struct iovec.
+
+2002-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* port-sockets.h (sg_buf): New typedef name for OS-specific
+	scatter-gather buffer handle type.
+	(SG_ADVANCE, SG_LEN, SG_SET): New macros to manipulate sg_buf.
+	(SOCKET_WRITEV, SOCKET_WRITEV_TEMP): New macros for sending on
+	socket with gathered input.
+	(SHUTDOWN_READ, SHUTDOWN_WRITE, SHUTDOWN_BOTH): New macros, to be
+	passed to shutdown() to indicate direction.
+	(EINPROGRESS, EWOULDBLOCK, ECONNRESET, ECONNABORTED,
+	ECONNREFUSED, EHOSTUNREACH, ETIMEDOUT) [_WIN32]: Define as WSA
+	equivalents if not already defined.
+
+2002-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin: Delete inclusion of profile.h again.
+
+2002-06-15  Alexandra Ellwood <lxs@mit.edu>
+
+	* krb5.hin: Conditionalize KRB5_CALLCONV_WRONG separately
+	because gssapi.h defines KRB5_CALLCONV but doesn't need
+	KRB5_CALLCONV_WRONG
+	[pullup from 1-2-2-branch]
+
+2002-06-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5.hin: Rename krb5_kt_free_entry_contents as
+	krb5_free_keytab_entry_contents to make it consistent with rest of
+	API.  Add KRB5_CALLCONV_WRONG.  Fix up various calling
+	conventions.  For Win32, add KT an CC accessors and default to not
+	PRIVATE.
+
+	* krb5.hin: Make krb5_build_principal_va() KRB5_CALLCONV.
+
+	[pullups from 1-2-2-branch]
+
+2002-06-15  Alexandra Ellwood <lxs@mit.edu>
+
+	* krb5.hin: Conditionalized pragmas for Metrowerks
+
+	* krb5.hin: Updated Mac OS X headers to new framework layout
+
+	[pullups from 1-2-2-branch]
+
+2002-06-15  Miro Jurisic  <meeroh@mit.edu>
+
+	* krb5.hin: Updated Mac OS #defines
+	and #includes for new header layout and Mac OS X frameworks
+
+	[pullups from 1-2-2-branch]
+
+2002-06-14  Alexandra Ellwood <lxs@mit.edu>
+
+	* k5-int.h: Added krb5_kt_dfl_ops for KRB5_KEYTAB_ACCESSOR_FUNCTIONS
+
+	* k5-int.h: Removed conditionals now defined in prefix files
+	and updated header paths
+
+	[pullups from 1-2-2-branch]
+
+2002-06-14  Miro Jurisic  <meeroh@mit.edu>
+
+	* k5-int.h: Rearranged the #ifdef macintosh section to
+	work on Mac OS 9 and X
+
+	* k5-int.h: Updated Mac OS #defines
+	and #includes for new header layout and Mac OS X frameworks
+
+	[pullups from 1-2-2-branch]
+
+2002-06-14  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Fix BEGIN_DECLS conditional.
+
+2002-06-14  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-mac.h: Since this file is now only Win32, remove non-Win32
+	stuff to make it easier to read.  Never used __declspec(dllexport)
+	so that we do not accidentally export symbols.
+
+	* win-mac.h: Add KRB5_CALLCONV_WRONG.
+
+	[pullups from 1-2-2-branch]
+
+2002-06-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* bsdlib.h, bstring.h, fake-stdlib.h: Deleted.
+
+	* sys/syslog.h: Deleted.
+
+2002-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (KRB_AP_PATH_NOT_ACCEPTED, KRB_ERR_RESPONSE_TOO_BIG):
+	New error number macros.
+	(krb5int_sendto_kdc): Update for new argument.
+	(krb5int_sendto_tcp): Declare.
+
+2002-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (krb5int_sendto_udp): Declare.
+	(krb5_sendto_kdc): Update declaration.
+	(KRB5INT_ACCESS_STRUCT_VERSION): Bump.
+	(struct _krb5int_access): Update locate_kdc interface; add
+	sendto_udp.
+
+	* fake-addrinfo.h [COPY_FIRST_CANONNAME]: Include string.h.
+
+	* k5-int.h (struct addrlist): Field "addrs" now points to
+	addrinfo instead of sockaddr.
+
+2002-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* socket-utils.h (socklen) [! HAVE_SA_LEN]: Return a socklen_t
+	instead of size_t.
+
+	* configure.in: Check return type for getservbyname_r just as for
+	gethostbyname_r.
+	* fake-addrinfo.h (GET_HOST_BY_NAME): Use plain gethostbyname if
+	THREADSAFE_GETHOSTBYNAME is defined, even if _r versions are
+	available.
+	(GET_HOST_BY_ADDR) [GETHOSTBYNAME_R_RETURNS_INT]: Add missing
+	variable declaration.
+	(GET_SERV_BY_NAME, GET_SERV_BY_PORT): New macros, in three
+	flavors, parallel to GET_HOST macros; not used yet.
+	(getaddrinfo, getnameinfo, gai_strerror, freeaddrinfo)
+	[S_SPLINT_S]: Add Splint annotations.
+	(getaddrinfo, getnameinfo): Buffer sizes are supposed to be
+	socklen_t, not size_t.
+	(freeaddrinfo) [COPY_FIRST_CANONNAME]: Handle null pointer
+	argument.
+	(getaddrinfo) [COPY_FIRST_CANONNAME]: Always do the copying if the
+	ai_canonname is non-null, regardless of the supplied flags.
+
+2002-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	Reduce build-time per-system dependencies and krb5.h namespace
+	intrusions:
+	* krb5.hin: Don't include profile.h.  Do include limits.h.
+	(krb5_int16, krb5_ui_2, krb5_int32, krb5_ui_4): Conditionalize on
+	the values of INT_MAX, LONG_MAX and SHRT_MAX.
+	(VALID_INT_BITS, VALID_UINT_BITS, SALT_TYPE_AFS_LENGTH,
+	SALT_TYPE_NO_LENGTH): Define in terms of INT_MAX and UINT_MAX.
+	(struct _profile_t): Declare forward.
+	(krb5_get_profile): Use struct _profile_t instead of profile_t in
+	declaration.
+	(krb5_ui_1): Delete.
+	* Makefile.in (krb5.h): Don't put SIZEOF macros into output.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* sys/syslog.h (syslog, vsyslog, openlog, closelog, setlogmask):
+	Always use prototype versions of declarations; delete
+	non-prototype declarations.
+
+2002-04-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (GET_HOST_BY_NAME, GET_HOST_BY_ADDR)
+	[GETHOSTBYNAME_R_RETURNS_INT]: Fix backwards test of return
+	value.
+
+2002-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: If the return type for gethostbyname_r can't be
+	determined, just pretend it's not avaliable.
+
+	* fake-addrinfo.h (getaddrinfo) [_AIX]: Declare and initialize
+	variable "ai".
+
+2002-04-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for gethostbyname_r, gethostbyaddr_r,
+	getservbyname_r and getservbyport_r.  Figure out the return type
+	of gethostbyname_r.
+	* fake-addrinfo.h (GET_HOST_BY_NAME, GET_HOST_BY_ADDR): New
+	macros.
+	(fai_add_hosts_by_name, fake_getnameinfo, getaddrinfo): Use them.
+	(fake_getaddrinfo): Use getservbyname_r if available.
+	(fake_getnameinfo): Never call inet_ntoa; in open-coded form,
+	initialize local pointer variable after label.  Use
+	getservbyport_r if available.
+	(gaiptr, faiptr, gniptr): Pointer variables are now const.
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* port-sockets.h: Use Winsock 2 headers for Win32.
+	* fake-addrinfo.h: Define HAVE_GETADDRINFO for Win32.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_c_valid_enctype, krb5_c_valid_cksumtype,
+	krb5_c_is_coll_proof_cksum, krb5_c_is_keyed_cksum): Declare.
+
+2002-04-02  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Default to KRB5_DEPRECATED=1, allowing compiler
+	command line to override.  Hide some struct definitions.  Use
+	KRB5INT_BEGIN_DECLS and KRB5INT_END_DECLS to deal with C++
+	function declarations.
+
+2002-04-01  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Move a whole bunch of stuff under KRB5_DEPRECATED or
+	KRB5_PRIVATE as a first pass for cleaning up the API.
+
+2002-03-28  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin: krb5_init_keyblock new function.
+
+2002-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h: Include errno.h.
+	* krb5.hin: Don't include errno.h.
+
+	* fake-addrinfo.h (getaddrinfo) [__linux__]: Don't crash if hint
+	is a null pointer.
+
+2002-03-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h [NEED_FAKE_GETADDRINFO]: Include errno.h.
+	(fake_getnameinfo) [__GNUC__ && __mips__]: Use const when
+	referencing bytes of supplied address.
+
+	* krb5.hin: Don't include <sys/types.h> any more.
+	* Makefile.in (krb5.h): Don't put HAVE_STDARG_H or HAVE_SYS_TYPE_H
+	symbols into output.
+
+2002-03-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h: Incorporate all of fake-addrinfo.c.  Make all
+	defined functions static, and inline if gcc is used.  Drop
+	FAI_PREFIX renaming hacks.  Fix some bugs in the separation of
+	getnameinfo from getaddrinfo/freeaddrinfo for wrapping purposes.
+	(fake_getnameinfo) [__GNUC__ && __mips__]: Don't call inet_ntoa,
+	struct passing doesn't work.  Format the output string locally.
+	* fake-addrinfo.c: Delete.
+
+2002-03-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.c (fixup_addrinfo): Deleted.
+	(fake_getaddrinfo, fake_getnameinfo, fake_freeaddrinfo): Renamed
+	from non-"fake_" versions, and made static.  Compile if
+	NEED_FAKE_GETADDRINFO is defined.
+	(fake_getnameinfo): Truncate results if provided buffers are too
+	small.
+	(getaddrinfo, getnameinfo, freeaddrinfo) [HAVE_FAKE_GETADDRINFO]:
+	New functions, simple wrappers around the "fake_" versions.
+	(getaddrinfo, freeaddrinfo) [WRAP_GETADDRINFO]: New functions
+	which call the system versions via function pointers and then fix
+	up some known problems in the returned data.
+	(getnameinfo) [WRAP_GETNAMEINFO]: Likewise.
+	(gaiptr, faiptr, gniptr) [WRAP_GETADDRINFO || WRAP_GETNAMEINFO]:
+	New static variables, initialized with addresses of system
+	versions of getaddrinfo, etc.
+	* fake-addrinfo.h (fixup_addrinfo): Declaration deleted.
+	(WRAP_GETADDRINFO): New macro, defined on Linux and AIX.
+	(getaddrinfo, getnameinfo, freeaddrinfo): Define as macros, and
+	declare functions, if WRAP_GETADDRINFO is defined or
+	HAVE_GETADDRINFO is not defined; drop BROKEN_GETADDRINFO check.
+	(gai_strerror, addrinfo, EAI_*): Define macros and declare
+	functions only if HAVE_GETADDRINFO isn't defined.
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_const): Restore macro definition, but include a
+	warning that it'll go away soon.
+
+2002-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* foreachaddr.c (SLOP): New macro.
+	(foreach_localaddr): Use it as the amount of extra space we look
+	for past the ifreq structures actually filled in.  Add SLOP to the
+	size of the buffer allocated to hold the ifreq structures.  Place
+	an upper bound on the buffer size.  Don't crash if the returned
+	ifc_len is larger than the supplied buffer size.
+
+2002-02-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin, k5-int.h: Use const instead of krb5_const.
+	* krb5.hin (krb5_const): Deleted definition.
+
+2002-02-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* foreachaddr.c: New file, contents taken from code shared between
+	kdc/network.c and lib/krb5/os/localaddr.c.  Split out multiple
+	branches within foreach_localaddr into separate functions.  Fixed
+	a couple minor compiler warnings on Linux.
+
+2002-02-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.c (_XOPEN_SOURCE_EXTENDED): Define if not defined,
+	and if not Mac or Windows, for duration of inclusion of netdb.h.
+	This gets us the h_errno declaration on HP-UX.
+	(getnameinfo): Cast gethostbyaddr pointer arg to char *, not
+	sockaddr *.
+
+2002-02-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h: Always check for FAI_PREFIX, not just when fake
+	getaddrinfo support is needed.
+	(fixup_addrinfo): Declare.
+	* fake-addrinfo.c (fixup_addrinfo): New function, fixes up
+	breakage in AIX and GNU implementations (so far) of getaddrinfo.
+
+2002-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* socket-utils.h (ss2sin6) [__GNUC__]: Define inline function only
+	if IPv6 support is turned on.
+
+2001-12-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-int.h (krb5int_des_init_state): Change variable name in
+	prototype away from usage.
+
+2001-11-18  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin: Add krb5_set_default_tgs_enctypes
+
+2001-11-15  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin:  Add krb5_c_random_add_entropy and
+	krb5_c_random_os_entropy 
+
+2001-11-14  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin: Added definitions of random sources 
+
+2001-11-06  Sam Hartman  <hartmans@tir-na-nogth.mit.edu>
+
+	* k5-int.h: Add krb5int_des_init_state and krb5int_default_free_state
+
+2001-11-06  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: Add init_state and free_state to enc_provider struct
+
+2001-11-05  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin:  Add krb5_c_init_state and krb5_c_free_state
+
+2001-10-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* fake-addrinfo.c (freeaddrinfo): Do not free NULL pointers.
+
+2001-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-int.h: Do not use "usage" in argument names in
+	krb5_keyhash_provider functions.
+
+2001-10-24  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: Add  declaration for  arcfour enc_provider and  md5
+	hash_provider  so we can get to these indirectly from libgssapi.
+	Ick.  This is an evil hack but somewhat less evil than  having raw
+	enctypes. 
+	Add above to krb5int_access along with krb5_hmac function
+
+2001-10-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use of AC_DEFINE modified to include third
+	argument - the comment for the generated header file so that
+	acconfig.h can be cleaned up.
+
+2001-10-23  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5.hin: Add rc4-hmac, rc4-hmac-exp enctypes,  hmac-md5-rc4
+	cksumtype 
+
+2001-10-22  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: keyhash_provider gains usage argument to hash function
+
+2001-10-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5.hin (krb5_kt_get_type): KRB5_CALLCONV.
+
+2001-10-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct _krb5_kt_ops, krb5_kt_ops, krb5_kt_dfl_ops):
+	Definitions and declarations moved here...
+	* krb5.hin: ...from here.
+	(krb5_kt_get_type, krb5_kt_get_name, krb5_kt_close,
+	krb5_kt_get_entry, krb5_kt_start_seq_get, krb5_kt_next_entry,
+	krb5_kt_end_seq_get): Replaced macro definitions with declarations
+	for functions now in lib/krb5/keytab/ktfns.c.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-stdlib.h: Make prototypes unconditional.
+	(P): Don't define.
+	* krb5.hin (KRB5_PROTOTYPE): Don't define.
+	* krb54proto.h: Make prototypes unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (KRB5_EXPORTVAR): Don't define.
+	* krb5.hin (KRB5_EXPORTVAR): Don't define.
+	* win-mac.h (KRB5_EXPORTVAR): Don't define.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h, krb5.hin, win-mac.h: Don't use or define KRB5_DLLIMP,
+	GSS_DLLIMP.  Drop MSDOS, NEAR, FAR support.
+	* krb54proto.h: Don't explicitly declare pointers FAR any more.
+	* port-sockets.h: Delete _MSDOS support.
+
+2001-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-unix): Depend directly on kerberosIV/krb_err.h
+	instead of on krb_err.h.
+	(krb_err.h): Target and rule deleted.
+	(clean-unix): Don't delete krb_err.h.
+
+2001-09-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (TKT_FLG_TRANSIT_POLICY_CHECKED,
+	TKT_FLG_OK_AS_DELEGATE, TKT_FLG_ANONYMOUS): New macros.
+	(KDC_OPT_REQUEST_ANONYMOUS, KDC_OPT_DISABLE_TRANSITED_CHECK):
+	Likewise.
+	(krb5_check_transited_list): Pointed-to krb5_data structures are
+	now all const.
+
+2001-09-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h: Include socket-utils.h.
+
+2001-08-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.c: Test only HAVE_FAKE_GETADDRINFO.
+	* fake-addrinfo.h: Define it, when remapping symbols.
+
+	* socket-utils.h (struct krb5int_sockaddr_storage,
+	sockaddr_storage): Conditionalize on HAVE_STRUCT_SOCKADDR_STORAGE
+	instead of KRB5_USE_INET6.
+
+2001-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* socket-utils.h (struct krb5int_sockaddr_storage): Add some extra
+	space.
+
+	* Makefile.in ($(srcdir)/krb5/autoconf.stmp): Since autoheader
+	doesn't change the target file if the contents wouldn't be
+	altered, touch an auxiliary timestamp file to avoid re-running
+	autoheader all the time.
+	(rebuild-error-tables): New intermediate target, avoids running
+	make in error_tables directory once for each generated header file
+	we care about.
+
+	* fake-addrinfo.c (getnameinfo): Cast address argument to
+	gethostbyaddr.
+
+	* fake-addrinfo.h (AI_V4MAPPED, AI_ADDRCONFIG, AI_ALL,
+	AI_DEFAULT): Define as bogus values, since they're part of
+	getipnodeby* API, not getaddrinfo API.
+
+2001-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* socket-utils.h: New file.
+	* k5-int.h: Include it.
+	(socklen_t, struct krb5int_sockaddr_storage, sa2sin, sa2sin6,
+	ss2sa, ss2sin, ss2sin6, socklen): Definitions moved to
+	socket-utils.h.
+	(krb5int_get_fq_local_hostname, krb5int_translate_gai_error): New
+	decls.
+
+	* fake-addrinfo.c: New file, split off from fake-addrinfo.h.
+	* fake-addrinfo.h: Don't define implementation functions.
+	(FAI_DEFINED): New macro, used to protect against multiple
+	inclusions.
+
+2001-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (ss2sin6): New gcc-specific function and alternative
+	macro.
+	(krb5_crypt_func, krb5_encrypt_helper): Don't use "usage" in
+	argument names.
+
+2001-08-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (AI_NUMERICHOST): Define as zero if not already
+	defined.
+
+2001-07-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_check_transited_list): Pointer args now point to
+	const.
+
+2001-07-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h: Include port-sockets.h instead of system header
+	files; should fix Windows build.
+
+2001-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.h (translate_h_errno): Supply a default value in
+	case some unrecognized code is returned.
+	(HAVE_GETNAMEINFO): Undefine before defining, just in case.
+
+	* krb5.hin (krb5_os_hostaddr): Declaration moved...
+	* k5-int.h (krb5_os_hostaddr): ...to here.
+
+	* fake-addrinfo.h: New file.
+
+2001-06-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: Do not use "random_key" as argument name. When krb.h
+	included, it gets redefined. Do not use "options" either.
+
+	* k5-int.h (krb5_get_init_creds): Do not use "options" as argument
+	name.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: Move prototypes for krb5_net_read() and
+	krb5_net_write() here.
+	* k5-int.h: From here.
+
+2001-06-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (struct addrlist): New type.
+	(ADDRLIST_INIT): New macro.
+	(krb5int_free_addrlist): Declare.
+	(krb5int_locate_server): Update declaration.
+	(KRB5INT_ACCESS_STRUCT_VERSION): Update to 3.
+	(struct _krb5int_access): Change locale_server prototype.  Add
+	free_addrlist function pointer field.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-util.h: Add prototypes for krb5_compat_recvauth_version() and
+	krb5_compat_recvauth().
+
+	* krb5.hin: Move krb5_read_message() and krb5_write_message()
+	prototypes here.
+	k5-int.h: From here.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: Get rid of extraneous krb5_const before integer
+	arguments in prototypes for valid_enctype(), valid_cksumtype(),
+	is_coll_proof_cksum(), is_keyed_cksum(), krb5_encrypt_size(),
+	krb5_checksum_size(), krb5_verify_checksum() so they match the
+	existing code.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-int.h: Remove AS_REP_105_SAM_COMPAT definition. Not used in
+	tree.  Remove SYSV redefinition of random() to rand() and
+	srandom() to srand(). Two locations in tree that might matter
+	already handled in configure. Unicos redefinition of utimes() to
+	utime() removed - appl/bsd has its own implementation.
+
+2001-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(srcdir)/krb5/autoconf.h.in): New target; rebuild
+	using autoheader.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (krb5int_locate_server): New prototype.
+	(krb5_locate_srv_conf, krb5_locate_srv_dns): Deleted.
+	(KRB5INT_ACCESS_STRUCT_VERSION): Update to 2.
+	(struct _krb5int_access): Update signature for locate_kdc, add
+	pointer for locate_server.
+	(struct krb5int_sockaddr_storage) [!KRB5_USE_INET6]: Declare dummy
+	type with space and alignment for an IPv4 address.
+	(sockaddr_storage) [!KRB5_USE_INET6]: Define to
+	krb5int_sockaddr_storage, so "struct sockaddr_storage" will do
+	something reasonable even without IPv6 support.
+	(sa2sin, sa2sin6, ss2sa, ss2sin): Define as macros or inline
+	functions, for safety in type conversion.
+
+	* win-mac.h (HAS_ANSI_VOLATILE, KRB5_PROVIDE_PROTOTYPES): Don't
+	define.
+
+	* configure.in: Don't use KRB5_CHECK_PROTOS.  Don't check for use
+	of prototypes inside structures.
+
+	* syslog.h (syslog, vsyslog, openlog, closelog, setlogmask):
+	Always use prototype versions of declarations; delete
+	non-prototype declarations.
+
+2001-04-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h (socklen_t) [NEED_SOCKETS] [!HAVE_SOCKLEN_T]: Define as
+	typedef for size_t.
+	(socklen) [NEED_SOCKETS]: Define macro if not already defined.
+	* configure.in: Don't check for support for type "void".  Move
+	socklen_t test here from krb5 library.
+
+2001-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (adm_err.h, asn1_err.h, krb5_err.h, kv5m_err.h):
+	Depend on corresponding error tables.  Run "make includes" in krb5
+	library code to rebuild instead of invoking awk here.
+	(all-unix): Depend on krb_err.h.
+	(krb_err.h): Depend on kerberosIV/krb_err.h; copy that file.
+	(kerberosIV/krb_err.h): Depend on all-recurse.
+	(clean-unix): Delete krb_err.h.
+
+	* k5-int.h: Always include stdlib.h and string.h; don't bother
+	testing the HAVE_ macros.
+
+2001-03-08 Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: Add prototypes for krb5_auth_con_setpermetypes() and
+ 	krb5_auth_con_getpermetypes().
+
+2001-01-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (KRB5_NPROTOTYPE): Delete.
+
+	* k5-int.h, krb5.hin: Use prototypes unconditionally.
+
+	* krb5.hin (krb5_const, krb5_pointer, krb5_const_pointer): Always
+	define as ANSI versions.
+
+	* krb5.hin (struct _krb5_safe, struct _krb5_priv, struct
+	_krb5_priv_enc_part, krb5_free_safe, krb5_free_priv,
+	krb5_free_priv_enc_part, struct krb5_rc_st, struct _krb5_rc_ops,
+	krb5_rc_register_type, krb5_rc_dfl_ops): Move from here...
+	* k5-int.h: ...to here.
+
+	* krb5.hin (krb5_rc_initialize, krb5_rc_recover, krb5_rc_destroy,
+	krb5_rc_close, krb5_rc_close, krb5_rc_store, krb5_rc_expunge,
+	krb5_rc_get_lifespan, krb5_rc_get_name, krb5_rc_resolve): Replace
+	macros with function decls.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_C_CONST instead of AC_CONST and
+	AC_CHECK_HEADER instead of AC_HEADER_CHECK.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-int.h: krb5_alt_method, krb5_etype_info_entry length fields
+	changed to unsigned int. KRB5_ETYPE_NO_LENGTH defined.  Change
+	prototype decode_krb5_sam_key to decode_krb5_enc_sam_key which is
+	what the code says.
+	krb5int_access - change timeouts, shifts, etc to unsigned ints. 
+
+	* krb5.hin: krb5_data, krb5_address, krb5_keyblock, krb5_checksum,
+	krb5_authdata, and krb5_pa_data length fields changed to unsigned
+	int. krb5_kt_get_name(), krb5_unparse_name_ext(),
+	krb5_build_principal(), krb5_build_principal_ext(),
+	krb5_build_principal_va() and krb5_read_password() all take or
+	return unsigned int lengths.
+
+	* port-sockets.h (SOCKET): Under unix, a socket is of type int.
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin, k5-int.h: krb5_cc_get_name now returns const char *.
+
+Tue Sep 26 18:10:22 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: Move prototype for krb5_gen_replay_name()
+
+	* k5-int.h: from here.
+
+2000-09-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-util.h (krb5_setedid): Add prototype.
+
+2000-08-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: lr_type element of krb5_last_req_entry needs to be a
+	signed int instead of an unsigned char.
+
+2000-07-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5.hin: Fix calling convention for krb5_cc_get_type.
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* k5-int.h: Add krb5int_accessor() and related definitions.
+	krb5int_accessor should be used by any code that is trying to use
+	krb5 internal functions (such as krb524 and GSSAPI).  The goal is
+	to eventually make this function do nothing.  That will only be
+	accomplished when we fix our apps/libraries not to call internal
+	functions.
+
+2000-07-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-int.h: Move prototypes for krb5 only internal functions
+	krb5_libdefault_boolean, _krb5_use_dns_realm, _krb5_use_dns_kdc,
+	_krb5_conf_boolean to the header files in the lib/krb5/{os,krb}
+	directories.
+
+2000-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_cc_*): Replace macro definitions with function
+	declarations.
+	(struct _krb5_ccache, struct _krb5_cc_ops): Declare
+	only; move structure definitions...
+	* k5-int.h: To here.
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5-int.h: Add prototypes for krb5_libdefault_boolean,
+	_krb5_use_dns_realm, _krb5_use_dns_kdc, _krb5_conf_boolean.
+
+2000-06-23  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5.hin (krb5_get_tgs_ktypes, krb5_free_ktypes): Fix linkage to
+	be KRB5_CALLCONV.
+
+	* k5-int.h (krb5int_cc_default): Fix linkage to be consistent with
+	code.  (Note: We should dump KRB5_DLLIMP.)
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_recvauth_version, krb5_free_ktypes): Declare.
+
+2000-06-05      Jeffrey Altman          <jaltman@columbia.edu>
+
+        * krb5-int.h: Fix the prototype for krb5int_cc_default so that it builds
+          on Windows.
+
+2000-5-19	Alexandra Ellwood <lxs@mit.edu>
+
+	* krb5-int.h: Added krb5int_cc_default.  This function supports the 
+	Kerberos Login Library and pops up a dialog if the cache does not
+	contain valid tickets.  This is used to automatically get a tgt before
+	obtaining service tickets.  Note that this should be an internal function
+	because callers don't expect krb5_cc_default to pop up a dialog!
+	(We found this out the hard way :-)
+
+2000-05-15      Jeffrey Altman          <jaltman@columbia.edu>
+
+        * krb5.hin
+          Added prototypes for new public functions
+
+               krb5_appdefault_string
+               krb5_appdefault_boolean
+
+2000-4-13	Alexandra Ellwood <lxs@mit.edu>
+
+	* krb5-int.h: Added support to store a krb5_principal in the os_context 
+	along with the default ccache name (if known, this principal is the same 
+	as the last time we looked at the ccache.
+	* win-mac.h: Set up the macintosh build to use KerberosLogin.
+
+2000-03-25  Miro Jurisic  <meeroh@mit.edu>
+
+	* k5-int.h: Fixed protos for krb5_locate_srv_* (naddrs is int*)
+
+2000-03-20  Miro Jurisic  <meeroh@mit.edu>
+
+	* krb5.hin: Add krb5_free_default_realm
+
+2000-03-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5.hin: Add krb5_get_prompt_types() and related defs..
+	* k5-int.h: Add krb5int_set_prompt_types().
+
+2000-03-13  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h: Update prototype to sync with changes in preauth2.c.
+
+2000-02-06  Ken Raeburn  <raeburn@mit.edu>
+
+	Patches from Frank Cusack for hw preauth.
+	* k5-int.h (krb5_predicted_sam_response): Add timestamp, client
+	principal, flags, and per-mechanism data fields.
+	(krb5_enc_sam_response_enc): Change "passcode" field to "sad".
+
+2000-02-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5.hin (krb5_decode_ticket): Declare.
+
+2000-01-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-int.h [!NEED_SOCKETS]: Declare (but do not define) struct
+	sockaddr if SOCK_DGRAM hasn't been defined yet.
+	(krb5_locate_srv_conf, krb5_locate_srv_dns): Declare.
+	(struct krb5_keytypes, struct krb5_cksumtypes): enc, hash, and
+	keyhash provider structures pointed to are now const.
+
+1999-11-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (krb5_secure_config_files): Delete declaration.
+	(krb5_init_secure_context): Declare.
+
+1999-11-02  Ken Raeburn  <raeburn@raeburn.org>
+
+	* configure.in: Invoke KRB5_AC_INET6.  Delete most of the 10-17
+	changes except for inet_ntoa/aton, since they're in KRB5_AC_INET6
+	now.
+
+1999-10-17  Ken Raeburn  <raeburn@raeburn.org>
+
+	* configure.in: Check for inet_{ntop,pton,ntoa,aton},
+	getipnodeby{name,addr}, get{name,addr}info.
+
+	* krb5.hin (ADDRTYPE_INET6): Define.
+
+1999-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install): Install port-sockets.h, needed by
+	kerberosIV/krb.h.
+
+1999-09-13  Miro Jurisic <meeroh@mit.edu>
+
+    * win-mac.h:  Remove #define HAVE_STRING_H for MacOS builds (it's already
+    in autoconf.h and I am a moron)
+
+1999-09-13  Miro Jurisic <meeroh@mit.edu>
+
+    * win0mac.h:  Add #define HAVE_STRING_H for MacOS builds.
+
+1999-08-31  Jeffrey Altman <jaltman@columbia.edu>
+
+    * k5-int.h:  Add #define ANSI_STDIO for Windows builds so that 
+                 stdio opens files in binary mode instead of text
+                 mode.  This is necessary for Ctrl-Z transparency.
+
+1999-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for memmove and bcopy.
+
+	* Makefile.in (install): Install profile.h since krb5.h will use
+	it.
+
+1999-08-26  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5.hin (krb5_kuserok): Fix calling convention to make it
+	consistent with rest of krb5 exports before we start exporting 
+	this from the Windows DLL.
+
+1999-08-25  Danilo Almeida  <dalmeida@mit.edu>
+
+	* k5-int.h (krb5_cc_retrieve_cred_default): Fix calling convention
+	to make it consistent with actual calling convention.
+
+1999-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin (KRB5_TC_SUPPORTED_KTYPES): New flag.
+	* k5-int.h (krb5_cc_retrieve_cred_default): Declare.
+
+1999-08-18  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Re-align des3-cbc-sha1 and hmac-sha1-des3 to agree
+	with new number assignments; also rename symbols a little bit.
+
+1999-08-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win-mac.h: Define MAXPATHLEN only if not already defined.  This
+	avoids warnings under Windows.
+
+1999-08-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* k5-int.h: Keep invariant that profile_in_memory member of context
+	is only sensible if KRB5_DNS_LOOKUP is defined.
+
+1999-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.hin: Wrap all declarations in `extern "C"' for C++, not
+	just some.  Move header file inclusions up above extern-C block.
+
+1997-07-26 Miro Jurisic <meeroh@mit.edu>
+	* win-mac.h (size_t): Fixed size_t redefinition on MacOS
+	
+1997-07-26 Miro Jurisic <meeroh@mit.edu>
+
+        * k5-int.h (krb5_get_profile): added krb5_get_profile. It returns
+        a profile handle you can use with the profile layer. It is guaranteed
+        to be initialized with the same config files as the profile of the context
+        passed in. 
+
+1997-07-22 Jeffrey Altman <jaltman@columbia.edu>
+
+        * k5-int.h struct _krb5_context
+                Added profile_in_memory boolean to be used to store
+                whether or not krb5 intentionally requested a profile
+                to be allocated by the profile library without a real
+                file (or list of files) behind it.
+
+1999-07-21  Miro Jurisic  <meeroh@.mit.edu>
+
+	* krb5.hin: #ifdefed out krb5_set_config_files, 
+		krb5_get_default_config_files, and krb5_free_confilg_files
+		on the Mac
+
+1999-06-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5.hin (krb5_get_default_config_files, krb5_free_config_files): 
+		Add function to get default config files with corresponding 
+		free function.
+
+1999-05-26  Miro Jurisic  <meeroh@.mit.edu>
+
+	* k5-int.h: Remove #define ENOMEM under #ifdef macintosh
+
+Wed May 19 11:33:15 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove copying of header files for Win32.  These
+		will be copied only if needed by the components that are
+		responsible for the header files (gssapi, et, and
+		profile).
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+Mon May 17 12:30:58 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add NO_OUTPRE flag to prevent creation of output
+		directory under win32.
+
+Tue May 11 15:19:12 1999  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: Remove unused priv_size from krb5_encrypt_block
+
+1999-04-09  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* k5-int.h: Add new prototypes and #define's provided by Frank
+		Cusack's preauth patch (PR# [krb5-kdc/662])
+
+1999-04-01  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5.hin (krb5_prompter_fct, krb5_prompter_posix): Update
+		function prototypes to reflect new prompter prototype
+		which takes an extra argument for the window titlebar
+		name.  (From Frank Cusack) [krb5-kdc/662]
+
+Mon Mar 15 15:57:41 1999  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h: Fix GSS_DLLIMP.
+
+1999-03-14  Miro Jurisic  <meeroh@mit.edu>
+
+	* win-mac.h: Fixed GSS_DLLIMP for the Mac
+
+1999-03-11  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* win-mac.h: Define GSS_DLLIMP to be __declspec(dllimport) or
+		__declspec(dllexport)  depending on whether GSS_DLL_FILE
+		is defined.
+
+1999-02-19  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* win-mac.h: Add definition for GSS_DLLIMP which is set ala
+		KRB5_DLLIMP, but controlled by the #define GSS_DLL_FILE.
+
+Mon Feb  8 21:51:10 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.hin (krb5_get_realm_domain): Add appropriate modifiers so
+		that this function can get exported in a Windows DLL.
+
+1999-02-01  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* k5-int.h: Add an entry to the os_context to store the default
+		ccache name.
+
+	* krb5.hin (krb5_cc_set_default_name): Add function prototype
+		which sets the defulat ccache name.
+	
+Thu Jan 21 15:23:28 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.hin: Fix realm iterator prototypes so that they use
+		KRB5_PROTOTYPE, and surround them with extern "C" so
+		things work under C++.
+
+Sun Dec  6 19:45:54 1998  Tom Yu  <tlyu@mit.edu>
+
+	* krb54proto.h: Fix decomp_tkt_krb5 to use KRB4_32, instead of a
+	nonexistent type.
+
+Sat Dec  5 01:08:57 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.hin: Add KRB5_DLLIMP and KRB5_CALLCONV to the prototypes of
+		valid_enctype, valid_cksumtype, is_coll_proof_cksum, and
+		is_keyed_cksum, which had previously been #defines, but
+		since they are now functions, they needed to be exported
+		by the DLL interface.
+
+1998-12-05  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5.hin: Move krb4 function prototypes to krb54proto.h
+
+1998-12-04  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5.hin: Add function prototypes for the new realm iterator
+		functions.  Also add some krb4 function prototypes to make
+		catching prototype errors easier.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS definition to control the directories
+		which are recursively descended by the Makefile.
+
+	* configure.in: Folded tests from krb5 and kerberosIV directories
+		into this configure.in file.
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* krb5.hin: add new interfaces for new crypto API and key
+	derivation/key usage.  Add new (krb5_get_permitted_enctypes,
+	krb5_is_permitted_enctype) api for querying permitted etypes from
+	krb5.conf, and new auth_context flag
+	(KRB5_AUTH_CONTEXT_PERMIT_ALL) to override this.  Fix bug in
+	krb5_kt_get_type.
+	
+	* k5-int.h: make changes related to new crypto API and key
+	derivation/key usage
+
+Tue Sep  1 19:32:33 1998  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Add ENCTYPE_LOCAL_DES3_HMAC_SHA1, in order to deal
+	with marc's current des3 cryptosystem until we figure out what
+	we're actually going to use for a standardized cryptosystem.
+
+Wed Jul  1 19:14:25 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* win-mac.h: Make size_t to be an unsigned long instead of
+		unsigned int.
+
+1998-05-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5.hin: Declare krb5_auth_con_setrcache and
+		krb5_get_server_rcache to be exported by the DLL.
+
+Sun Feb 22 19:20:31 1998  Tom Yu  <tlyu@mit.edu>
+
+	* k5-util.h: New file.  Add krb5_seteuid in order to allow
+ 	applications to use it without including k5-int.h.
+
+	* k5-int.h: Remove krb5_seteuid, as it is moving to k5-util.h.
+
+Wed Feb 18 15:50:40 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.  Fix up use of $(C) for new
+	conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Jan 29 20:15:30 1998  Dan Winship  <danw@mit.edu>
+
+	* krb5.hin: fix #define of krb5_cc_gen_new (takes a krb5_ccache *,
+	not a krb5_ccache)
+
+Sat Dec  6 02:20:11 1997  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Add constants and prototypes for the Cygnus password
+	changing API.  Add krb5_cc_copy_creds.  Add support for Cygnus
+	initial credentials API.
+
+	* k5-int.h: Add additional preauth types.  Add additional
+	parameter to krb5_sendto_kdc for designating whether to use the
+	master.  Add functions to support Cygnus initial credentials API.
+	Add prototypes for sam functions.
+
+Tue Sep 30 18:56:05 1997  Tom Yu  <tlyu@mit.edu>
+
+	* win-mac.h: Replace HAS_STDLIB_H with something more sane.
+
+	* k5-int.h: Replace HAS_STDLIB_H, NO_STDLIB_H with something more
+ 	sane.
+
+Thu Sep 25 21:10:37 1997  Tom Yu  <tlyu@mit.edu>
+
+	* win-mac.h: Replace KRB5_USE_INET with something more sane.
+
+	* k5-int.h: Replace HAS_UNISTD_H with something more sane.
+
+Thu Sep 18 17:52:59 1997  Tom Yu  <tlyu@mit.edu>
+
+	* win-mac.h: Replace USE_STRING_H with something more sane.
+
+	* k5-int.h: Replace USE_STRING_H, HAS_STRDUP, HAS_LABS with
+ 	something more sane.
+
+Mon Sep 15 14:54:55 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.hin: Add const to prototypes for krb5_cc_resolve,
+	        krb5_cc_default_name, credential cache resolve and keytab
+	        get functions.
+
+Tue Jul 29 23:14:27 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.hin: For Windows and Macintosh, always include stdlib.h
+
+Fri Jul 25 15:21:26 1997  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h: Don't include anything related to dbm.
+
+Tue Jul 15 12:35:41 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* win-mac.h: Remove (probably unneeded) size_t definition.
+
+Tue Mar 18 13:47:26 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5.hin: Add 'extern "C"' for C++ compatibility; also check for
+		__cplusplus since some C++ compilers don't set __STDC__
+
+Tue Feb 25 00:33:52 1997  Richard Basch  <basch@lehman.com>
+
+	* krb5.hin: Export krb5_read_password
+	* win-mac.h: Declare get_lib_instance (win_glue.c)
+
+Fri Feb 21 17:13:19 1997  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+	* port-sockets.h: Include sys/types.h before netinet/in.h for NetBSD
+	Protect against multiple inclusion
+
+Thu Feb 20 23:28:31 1997  Richard Basch  <basch@lehman.com>
+
+	* port-sockets.h: Define SOCKET_INITIALIZE and SOCKET_CLEANUP
+		as no-ops under Windows, since this is now handled by
+		the DLL entry/exit code.
+
+Wed Feb 19 14:25:32 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.hin: Added function prototype for krb5_set_principal_realm().
+
+Tue Feb 18 17:43:55 1997  Richard Basch  <basch@lehman.com>
+
+	* krb5.hin:
+		Added prototypes for krb5_free_data, krb5_free_data_contents
+		Moved krb5_xfree definition to k5-int.h
+	* k5-int.h:
+		krb5_xfree is an internal macro
+
+Mon Feb 17 13:58:45 1997  Richard Basch  <basch@lehman.com>
+
+	* win-mac.h: Added KRB4 Windows INI related definitions.
+
+Sat Feb  8 15:01:33 1997  Richard Basch  <basch@lehman.com>
+
+	* krb5.hin: Export krb5_get_credentials_{renew,validate} (win32)
+
+Tue Feb  4 15:57:18 1997  Richard Basch  <basch@lehman.com>
+
+	* k5-int.h: Make sure KRB5_EXPORTVAR is defined
+	* krb5.hin: Do not bother to define INTERFACE or INTERFACE_C
+
+Sun Feb  2 20:58:40 1997  Richard Basch  <basch@lehman.com>
+
+	* k5-int.h: All pointers to KRB5_DLLIMP functions must be declared FAR
+
+Fri Jan 31 23:10:09 1997  Richard Basch  <basch@lehman.com>
+
+	* krb5.hin:
+		Fixed improper declaration of krb5_eblock_enctype;
+		it returns a krb5_enctype, not a krb5_error_code.
+
+Thu Jan 30 21:22:28 1997  Richard Basch  <basch@lehman.com>
+
+	* krb5.hin
+		Functionalized remaining cryptosystem entrypoints
+		Made the cryptosystem structures private
+	* k5-int.h
+		Made the cryptosystem structures private
+	* win-mac.h
+		Win32 - compile with /MD to link with the runtime C library
+	* Makefile.in
+		Remove profile.h in clean-windows
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+	* krb5.hin: Moved windows/mac stuff to win-mac.h
+		Really, we should have krb5_os.h and utilize that file
+		  even when we don't include krb5.h, such as with the building
+		  of the crypto or util libs.
+		Declared various functions as DLL exports (win16/win32)
+		Major whitespace adjustment for consistency...
+	* k5-int.h: Re-structured accordingly to accomodate win-mac.h
+	* win-mac.h: New file containing the Windows/Mac definitions
+
+Wed Nov 13 14:28:08 1996  Tom Yu  <tlyu@mit.edu>
+
+	* k5-int.h, krb5.hin: Revert kt_default_name changes.
+
+Tue Nov 12 22:04:41 1996  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.hin: Add definition for krb5_kt_set_default_name().
+
+	* k5-int.h (struct _krb5_context): Add kt_default_name to
+	context.
+
+Mon Nov  4 14:50:42 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* k5-int.h: Removed unusued prototype for krb5_verify_padata();
+		this is old code that has since been removed. [PR#21]
+
+Thu Aug 15 16:31:20 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* k5-int.h: Since we are only supporting the db in the util/db2
+		directory, just use db-ndbm.h, instead of hoping that the
+		system ndbm.h will be appropriate.
+
+Fri Aug  2 14:15:26 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5.hin: Add prototype for krb5_free_keyblock_contents
+
+Wed Jul 24 00:38:40 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* k5-int.h: Prototype krb5_setenv and krb5_unsetenv
+
+Sun Jul  7 12:27:39 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5.hin: Add prototypes for krb5_get_credentials_renew() and
+		krb5_get_cred_from_kdc_renew() 
+
+Wed Jun 12 01:32:33 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* syslog.h: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS
+
+	* sys/syslog.h: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS
+
+Mon Jun 10 16:52:35 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5.hin		
+	* k5-int.h: For Win-32: always #include windows.h.  
+
+		Change INTERFACE to be KRB5_CALLCONV, which is where
+		the calling convention is defined.  Add KRB5_DLLIMP
+		which is where the DLL import/export should be put for
+		Win32.  (Win16 is just different.)  The correct way to
+		declare a function which will be used in a DLL is now:
+		KRB5_DLLIMP func_return_t KRB5_CALLCONV func(long)
+
+		Change function delcarations to use the new
+		convention.  Actually, it doesn't hurt to use the old
+		convention as long as func_return_t doesn't contain a
+		'*'.  But in the long run we should be exterminating
+		all uses of INTERFACE in favor of KRB5_CALLCONV and
+		KRB5_DLLIMP.
+
+Fri Jun  7 18:13:33 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.hin: 
+	* k5-int.h: Beginnings of Win-32 support.
+
+Thu Jun  6 14:14:28 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5.hin (krb5_cc_get_type): Remove extraneous '*' from definition.
+
+Mon May 20 02:51:06 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* k5-int.h: Ultrix CC wants krb5_seteuid to take uid_t so that the
+ 	type can be promoted from a short.
+
+Sat May 18 16:53:06 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* k5-int.h: Add krb5_seteuid
+
+Tue May 14 20:29:09 1996  Richard Basch  <basch@lehman.com>
+
+	* krb5.hin: replaced CKSUMTYPE_SHA_DES3 with CKSUMTYPE_HMAC_SHA
+
+Thu May  9 19:28:48 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* k5-int.h: Added new field values for ap_req_sumtype and
+	 	safe_sumtype.  Added new convenience function for
+		verifying magic numbers: KRB5_VERIFY_MAGIC.
+
+	* krb5.hin (krb5_auth_con_set_req_cksumtype,
+	 	krb5_auth_con_set_safe_cksumtype): Added prototypes of
+		new functions, to replace old krb5_auth_con_setcksumtype.
+
+Fri May 10 01:26:24 1996  Richard Basch  <basch@lehman.com>
+
+	* k5-int.h krb5.hin: Replaced 3des-md5 with 3des-sha.
+
+Tue May  7 17:19:17 1996  Richard Basch  <basch@lehman.com>
+
+	* k5-int.h: We are providing 3DES routines in libcrypto, too...
+
+Thu May  2 18:41:00 1996  Richard Basch  <basch@lehman.com>
+
+	* krb5.hin: krb5_init_random_key & krb5_finish_random_key now
+		pass the eblock to the underlying crypto routine.
+
+Fri May  3 00:26:47 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5.hin
+	(krb5_get_credentials_validate): declaration for new function.
+	(krb5_get_cred_from_kdc_validate): ditto.
+
+Thu May  2 22:52:14 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5.hin (krb5_rd_req_decoded_anyflag): declaration for new
+	function, see rd_req_dec.c for details.
+
+Tue Apr 30 14:51:55 1996    <tytso@rsts-11.mit.edu>
+
+	* k5-int.h: Fix Windows definition of PROVIDE_DES_CBC_RAW so that
+		the raw DES cryptosystem is properly included.  Removed
+		Macintosh definitions of PROVIDE_* since that is done in
+		mac/libaries/KerberosHeaders.h.
+
+Wed Apr 17 20:56:51 1996  Marc Horowitz  <marc@mit.edu>
+
+	* k5-int.h, port-sockets.h: moved socket stuff into a separate
+	file so that gssapi doesn't have to include k5-int.h
+
+Thu Apr 11 23:50:24 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.hin (krb5_x, krb5_xc): Fix wrapper macros so they don't
+		try to dereference a function pointer as a data value.
+		This doesn't work if you're using hpux cc, since functions
+		are aligned on 2-byte boundaries, but data has to be
+		accessed on 4-byte boundaries.  Accessing a function as a
+		data value isn't ANSI C portable anyway.  :-)  Wrapper
+		macros now take a function pointer, and check to see if
+		the function pointer is non-NULL, instead of taking a
+		(*funptr), and seeing if the function when treated as data
+		object is non-NULL. 
+
+Wed Apr 10 10:37:21 1996  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5.hin (krb5_validate_times): Add prototype of new function.
+
+Tue Apr  9 22:40:49 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* k5-int.h: add prototypes for sam preauth functions.
+
+Thu Mar 28 19:55:04 1996  Richard Basch  <basch@lehman.com>
+
+	* krb5.hin: Added ENCTYPE_DES3_CBC_RAW
+
+Wed Mar 20 22:55:50 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.hin (krb5_pa_data): Change type of pa_type field in
+		krb5_pa_data to be krb5_preauthtype, for consistency's
+		sake.  Added prototype for krb5_copy_addr().  Change type
+		of etype in krb5_etype_info_entry to be krb5_enctype, for
+		consistency's sake.
+
+Sat Feb 24 21:46:13 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (all-windows): hpux make doesn't grok $@, so I'm
+	        told.  Use explicit target names for building errortable
+	        include files.
+
+Fri Feb 23 18:59:18 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5.hin (krb5_x, krb5_xc): wrapper macros to test all function
+	pointers before calling through them (abort if null.) Simplifies
+	debugging on many platforms. Currently #if 1, but could be
+	conditionalized once we're in "production".
+
+Wed Feb 21 23:33:18 1996  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Do not install k5-int.h
+
+Wed Jan 10 22:46:51 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5-int.h: Add fields for fcc_default_format and
+	        scc_default_format in krb5_context structure.
+
+Tue Jan  9 22:23:31 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.hin (krb5_fwd_tgt_creds, krb5_os_hostaddr): Added new
+		function prototypes.
+
+Thu Jan  4 22:49:13 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.hin: Added support for KRB5_INT16_MAX, which tells us the
+		limitations of using 16 bit ints.
+
+Sun Nov 26 19:23:35 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* k5-int.h: Ultrix is broken.  Hacked around by redefining the
+		typedefs of preauth_obtain_data_proc and
+		preauth_process_proc to be pointers to the functions
+		rather than the functions themselves.  Also made some
+		things KRB5_NPROTOTYPE.
+
+Fri Nov 17 22:29:13 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.hin, k5-int.h: Moved prototype for encode_kdc_rep to
+		k5-int.h, and remove the eblock argument.
+
+Mon Nov 13 11:49:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5-int.h: Added typedef for krb5_preauth_proces_proc, and
+		changed the prototype of krb5_process_padata() to take
+		additional arguments for returning the decryption key to
+		use for decrypting the as_reply, as well as passing in the
+		decrypt_proc procedure in case some preauth types want to
+		call decrypt_proc themselves.
+
+	* krb5.hin: Add prototypes for krb5_encrypt_data(),
+		krb5_decrypt_data(). 
+
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * krb5.hin : Remove krb5_enctype from krb5_string_to_key() args.
+
+Thu Nov  9 00:04:52 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5-int.h: Remove etype_info from the argument list of
+	        krb5_obtain_padata.
+
+Wed Nov  8 02:53:48 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.hin: Add preauthentication type KRB5_PADATA_ETYPE_INFO.
+
+	* k5-int.h: Add declaration for krb5_free_etype_info.
+
+	* krb5.hin: Removed internal functions krb5_encrypt_tkt_part,
+		krb5_verify_padta, and krb5_obtain_padata from the public
+		header file.
+
+	* k5-int.h: Removed old preauthentication declarations and added
+		new ones.  Changed function prototype of
+		krb5_encrypt_tkt_part.
+
+Tue Nov 7 12:00:00 1995  John Rivlin <jrivlin@fusion.com>
+
+	* k5-int.h: Place stat declation inside #ifndef __MWERKS__ so
+		as not to conflict with the definition in the 
+		MetroWerks compiler.
+
+Tue Oct 24 17:31:36 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5-int.h: Manually defined PROVIDE_* for Macintosh and MS-DOS so
+		that libcrypto knows which encryption systems to include.
+		Otherwise, we would be building an exportable (and
+		useless) krb5 library for the Mac and PC.
+
+Fri Oct  6 21:59:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Thu Oct  5 21:31:10 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.hin: Change types of krb5_max_enctype and
+		krb5_max_cksumtype to be krb5_enctype and krb5_cksumtype,
+		to fix some gcc -Wall flames.
+
+Thu Oct  5 07:34:51 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* k5-int.h: Add profile_secure to context.
+
+	* krb5.hin: Add krb5_secure_config_profile prototype.
+
+Fri Sep 29 15:17:30 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: If krb5/autoconf.h doesn't exist, cd to krb5 and
+		make it.
+
+		Don't make krb5-pro.h; this confuses things under Windows,
+		since Windows attempts to build krb5-pro.h and then
+		rebuildes krb5.h, when it shouldn't do that.  Fold in the
+		krb5-pro.h rules as part of the rules for krb5.h.  This
+		way, they don't get executed under DOS, since krb5.h
+		already exists under DOS.
+
+Fri Sep 29 13:35:08 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean-unix): Remove krb5-pro.h
+	              (krb5-pro.h): Add HAVE_SYS_TYPES_H file so that
+		      sys/types.h may be included definition of size_t for
+		      krb5.h  
+
+Fri Sep 29 01:35:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5-int.h: #include "osconf.h" all the time, at the beginning of
+		the file.
+
+Tue Sep 26 15:18:26 1995    <tytso@rsts-11.mit.edu>
+
+	* k5-int.h: Don't predefine symbols to stop kdb.h and kdb_dbm.h
+		for _MSDOS.
+
+	* krb5.hin, k5-int.h: Move some src/lib/krb5/os prototypes to
+		krb5.hin.
+
+Mon Sep 25 16:39:21 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Sat Sep 23 01:37:19 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5.hin: Added preauth numbers for KRB5_CYBERSAFE_SECUREID and
+	        KRB5_PADATA_AFS3_SALT.
+
+Fri Sep 22 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* k5-int.h: removed define for OLD_CONFIG_FILES for 
+		change password
+
+Fri Sep 22 19:42:47 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5-int.h: Change length field in krb5_alt_method and
+		krb5_etype_info_entry to be an int, instead of an int32.
+		This allows the ASN.1 length parsing routines to work
+		properly. 
+
+	* k5-int.h: (from Keith Vetter's windows changes); define
+		THREEPARAMOPEN and prototype for sscanf.  Also add #define
+		for strncasecmp() to the microsoft's strnicmp() function.
+
+Tue Sep 12 12:00:00 1995  John Rivlin <jrivlin@fusion.com>
+
+	* k5-int.h: Removed KRB5_REALM_CANT RESOLVE,
+		PROF_NO_SECTION and PROF_NO_RELATION defines
+		as they are also defined in KerberosIV/krb_err.h
+		and util/profile/prof_err.et and create conflicts
+		on the Mac.
+
+Sun Sep 10 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* krb5.hin:  Conditionalized inclusion of <sts/types.h> for _MACINTOSH
+
+Wed Sep  6 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* k5-int.h:  Added requisite defines, fake struct definitions for compilation
+		on MACINTOSH.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * k5-int.h krb5.hin : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * k5-int.h, krb5.hin : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate.
+
+Fri Sep  1 00:44:59 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5-int.h: Added clockskew, kdc_req_sumtype, and
+		kdc_default_options to the krb5_context structure.
+
+	* krb5.hin: Added expected nonce and request_time fields to the
+	        krb5_response structure.  The fields are used to pass
+		information from krb5_send_tgs() to
+		krb5_get_cred_via_tkt() so that it can do sanity checking.
+
+	* k5-int.h: Add time offset field to the os_context structure.
+		This offset is added to the system clock time to produce
+		the "true" time.  
+
+		Added prototypes for the functions which manipulate the
+		time offset structures: krb5_set_real_time(),
+		krb5_set_debugging_time(), krb5_use_natural_time(),
+		krb5_get_time_offsets(), and krb5_set_time_offsets().
+
+Tue Aug 29 13:26:22 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* k5-int.h - Add ser_ctx[_count] to krb5_context.  This keeps track
+		of registered serializers.  Add serializer definitions and
+		prototypes.
+	* krb5.hin - Add priv_size to krb5_encrypt_block.  This indicates the
+		size of the private data.  Add pointer to keytab ops for
+		serializer handle.
+
+Mon Aug 28 15:58:14 1995    <tytso@rsts-11.mit.edu>
+
+	* k5-int.h: Added two new data structures: krb5_alt_method and
+	        krb5_etype_info (and krb5_etype_info_entry).  
+
+Fri Aug 25 17:12:37 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5-int.h: Added prototypes for encode_krb5_padata_sequence and
+	        decode_krb5_padata_sequence.
+
+	* krb5.hin: Removed unused (and misleading) macros
+		KEYTYPE_IS_LOCAL, ETYPE_IS_LOCAL, CKSUMTYPE_IS_LOCAL
+
+Thu Aug 24 19:23:10 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Wed Aug 16 02:45:19 1995  Chris Provenzano <proven@mit.edu>
+
+	*  k5-int.h (krb5_lock_file(), krb5_unlock_file()):
+		Use fds instead of FILE *s and don't pass the filename.
+
+Fri Aug  4 23:04:06 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* k5-int.h: Add prototypes for krb5_crypto_os_localaddr and
+		krb5_crypto_us_timeofday
+
+Thu Jul 27 15:04:37 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* k5-int.h - Inline or delete header files included here.  These were:
+		{asn1, dbm, ext-proto, k5-config, k5-errors, k5-sockets,
+		 libos, los-proto, mit-des, preauth, rsa-md5 and sysincl}.h
+		Also remove #defines which controlled the KDC, move these
+		definitions to kdc/configure.in.
+
+Thu Jul 27 04:27:45 1995  Chris Provenzano <proven@mit.edu)
+
+	* krb5.hin : Added #define KEYTYPE_UNKNOWN
+
+Tue Jul 11 13:12:14 1995    <tytso@rsx-11.mit.edu>
+
+	* krb5.hin (krb5_cc_get_type, krb5_kt_get_type): Add the new
+		functions to get the type of the credentials cache and key
+		table.
+	
+Sun Jul  9 21:37:50 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5.hin: Add krb5_rd_cred prototype.
+
+Fri Jul 7 15:56:49 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krb5.hin - Add checksum verifier dispatch in the checksum entry.
+		This is now the supported method for verifying checksums.  Also
+		add krb5_verify_checksum which uses this dispatch.
+
+Thu Jul  6 17:19:26 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* krb5.hin: Change definition of krb5_os_localaddr to include
+		context argument.
+
+Wed July  5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* k5-int.h disable inclusion of profile.h for macintosh build
+	* krb5.h   enable inclusion of sys/types.h on HAS_SYS_TYPES
+
+Thu Jun 29 22:54:30 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* krb5.hin: special-case ultrix brokenness (again!) for
+		KRB5_CONST; krb5.h breaks when typedef'ing while
+		installed.  Yuck.
+
+Tue Jun 27 16:14:38 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krb5.hin - Reinstate KRB5_PROVIDE_PROTOTYPES.  This is needed for
+		compilers which recognize prototypes but don't set __STDC__
+		or _WINDOWS.
+
+Thu Jun 22 16:03:07 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* syslog.h: reverse sense of KRB5_PROVIDE_PROTOTYPES
+	* krb5.hin: special-case ultrix brokenness, reverse sense of
+		KRB5_PROVIDE_PROTOTYPES (becomes KRB5_NO_PROTOTYPES);
+		also, NO_NESTED_PROTOTYPES -> KRB5_NO_NESTED_PROTOTYPES
+	* Makefile.in: don't install NO_NESTED_PROTOTYPES, HAS_VOID_TYPE,
+		and KRB5_PROVIDE_PROTOTYPES symbols into krb5.h
+	* sys/syslog.h: reverse sense of KRB5_PROVIDE_PROTOTYPES
+
+Thu Jun 22 11:51:10 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* k5-int.h - Add pointer in krb5_context for database context.
+
+Wed Jun 21 10:54:58 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in, krb5.hin: Don't include autoconf.h anymore; have
+		the Makefile include the few configure symbols which
+		krb5.h needs.
+
+	* krb5.hin: Change PROTOTYPE -> KRB5_PROTOTYPE and 
+		NPROTOTYPE -> KRB5_NPROTOTYPE.
+
+Fri Jun 16 11:39:36 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Fix install logic for krb5.h and k5-int.h.
+
+Sun Jun 11 09:20:29 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5.hin: Add missing declaration of krb5_auth_con_initivector.
+
+Sat Jun 10 22:10:46 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* krb5.hin: declare krb5_auth_context as
+		struct _krb5_auth_context FAR *
+
+Fri Jun  9 18:43:20 1995    <tytso@rsx-11.mit.edu>
+
+	* krb5.hin: Remove definition of the krb5_fulladdr structure, and
+		the prototype for the unused function krb5_fulladdr_order.
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Fri Jun 9 12:02:02 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in(all-unix) : Add adm_err.h build target since it's not 
+		built in lib/krb5/error_tables any more.  kadmin.old needs it.
+
+Tue Jun  6 12:25:38 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5.hin: Add prototype for krb5_524_conv_principal()
+
+Tue May 30 10:59:13 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean-unix): Remove built header files krb5.h
+		krb5_err.h kdb5_err.h kv5m_err.h asn1_err.h 
+
+Wed May 24 10:54:34 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in	- Change $< to explicit target names when generating
+			  error table header files.  OSF/1 and Ultrix-native
+			  make only expand $< on suffix rules.
+
+Tue May 23 22:07:02 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5.hin: Remove krb5_encode_ticket as it does not exist in
+		library. 
+
+Tue May 23 15:08:54 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in, configure.in, krb5.hin: Move krb5.h to krb5.hin,
+		and build krb5.h from krb5.hin and the error table
+		include files, which are now built in this directory.
+		This way, krb5.h is the only include file that we need to
+		install.
+
+	* k5-int.h: Move the sockets specific setup out of k5-config.h to
+		  k5-sockets.h, and modify k5-int to include k5-sockets.h
+		  (if it is requested by NEED_SOCKETS) after including
+		  krb5.h.  This keeps the gdb type numbers the same across
+		  .o files, so that recent binuntils can compress the
+		  debugging information in executables linked with a
+		  debugging library.
+
+Mon May 22 10:24:49 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in	- (install) Always perform install actions using
+			  $(INSTALL_DATA).
+	* configure.in	- locate install program.
+
+Wed May  3 10:32:18 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5.h: (krb5_auth_con_setports): Added missing prototype.
+	          (krb5_auth_con_getkey): Added as well.
+
+Wed May 03 03:30:51 1995  Chris Provenzano (proven@mit.edu)
+
+	* krb5.h: (krb5_recvauth()): No longer needs the rc_type arg.
+
+Mon May  1 17:06:51 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5.h: (krb5_set_config_files): Added const to prototype
+
+Sat Apr 29 07:10:02 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* krb5.h (krb5_set_config_files): Added new function prototype.
+
+Fri Apr 28 01:44:51 1995  Chris Provenzano  (proven@mit.edu)
+
+	* krb5.h (krb5_send_tgs()) : Removed krb5_cksumtype argument.
+
+Thu Apr 27 21:36:01 1995  Chris Provenzano  (proven@mit.edu)
+
+        * krb5.h : Added mask AP_OPTS_WIRE_MASK.
+
+Thu Apr 27 18:27:36 1995 Keith Vetter (keithv@fusion.com)
+	
+	* Makefile.in: duplicate copying the profile.h file for the PC.
+
+Thu Apr 27 17:57:36 1995 Keith Vetter (keithv@fusion.com)
+
+	* krb5.h: krb5_mk_req somehow got INTERFACE added to it--removed it.
+
+Tue Apr 25 21:58:23 1995  Chris Provenzano  (proven@mit.edu)
+
+	* krb5.h (krb5_fulladdr) : Change port to be of type krb5_address.
+	* krb5.h (krb5_auth_con_genaddrs()) : Added flags for new routine.
+	* krb5.h (krb5_get_for_creds()) : Removed prototype.
+	* krb5.h (krb5_get_cred_via_tkt()) : Added prototype.
+	* krb5.h (krb5_mk_ncred(), krb5_mk_1cred(), krb5_rd_cred()):
+		Updated prototype to include auth_context.
+
+Fri Apr 21 08:58:50 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* krb5.h: krb5_princ_aref() doesn't work, and isn't used anywhere.
+		Removed.  (So all of macros.h is gone.)
+
+	* krb5.h, k5-int.h: Moved struct _krb5_context to k5-int.h
+
+Thu Apr 20 12:15:54 1995 Keith Vetter (keithv@fusion.com)
+
+	* krb5.h: Needs SIZEOF_INT, SIZEOF_LONG defined for the PC.
+
+Wed Apr 29 10:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: duplicated the file copying stuff from 
+           ..\gssapi\generic so that all the copying stuff can be
+           found in one place.
+
+Thu Apr 20 11:32:09 1995    <tytso@rsx-11.mit.edu>
+
+	* krb5.h, k5-int.h: Inlined the following include files, to
+		simplify the header files which actually need to be
+		installed: wordsize.h, base-defs.h, hostaddr.h,
+		fieldbits.h, proto.h, macros.h, error_def.h, safepriv.h,
+		ccache.h, rcache.h, keytab.h, func-proto.h, k5-free.h.
+		Also moved the #include of k5-config.h and k5-errors.h to
+		k5-int.h.
+
+Wed Apr 19 13:23:39 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5.h: Added default_realm pointer to krb5_context
+
+Thu Apr 13 16:05:08 1995 Keith Vetter (keithv@fusion.com)
+
+	* bsdlib.h, bstring.h, fake-std.h, syslog.h:  __STDC__ conditionals
+           also check for the _WINDOWS define.
+        * krb5.h: added FAR to pointers visible to the world.
+	* sys/syslog.h:  __STDC__ conditionals also check for the _WINDOWS
+	   define.
+
+Tue Mar 28 18:12:32 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (KRB5_HEADERS, install):  `Make install' now works.
+	* configure.in (WITH_KRB5ROOT):  For `make install'.
+	* krb5.h:  Include "k5-errors.h" rather than "errors.h".
+
+Fri Mar 17 19:10:41 1995  John Gilmore  (gnu at toad.com)
+
+	* krb5.h:  Move <sys/types> and u_long (etc) code to krb5/k5-config.h.
+	It is needed there when NEED_SOCKETS is defined.
+	* Makefile.in (all-mac, clean-mac):  Add.
+
+Wed Mar 15 20:27:57 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: added recursion into krb5 for the PC.
+
+Fri Mar 10 10:18:50 1995  Chris Provenzano (proven@mit.edu)
+
+	* krb5.h Added empty structure declaration of krb5_auth_context.
+
+	* k5-int.h Moved #include "adm_defs.h" to krb5.h
+
+Thu Mar  2 23:24:00 1995  John Gilmore  (gnu at toad.com)
+
+	Make include files begin to work on the Macintosh.
+
+	* k5-int.h:  Remove krb5/ from #includes.  Rearrange #includes
+	so that time_t is defined before kdb.h is included.
+	* krb5.h:  Include k5-config.h first, so its #define's can
+	control the rest of the file.  If <sys/types.h> is not present,
+	define u_long, etc, manually.
+
+Wed Feb 22 18:31:12 1995  John Gilmore  (gnu at toad.com)
+
+	* k5-int.h:  Remove commented-out <widen.h> and <narrow.h>.
+	* krb5.h: Same as old krb5/krb5.h, as a start.  Gradually things
+	that don't need to be exported will be moved from krb5.h into
+	k5-int.h (and vice verse for e.g. function prototypes).
+
+Wed Jan 25 19:19:38 1995  John Gilmore  (gnu at toad.com)
+
+	Make it possible to #include "..." without using slashes,
+	for Macintosh support.
+
+	* krb5.h:  New file, the externally visible interface to
+	Kerberos V5.  Currently the whole kitchen sink, to bootstrap.
+	* k5-int.h:  New file, the internally visible declarations
+	needed by source files that are part of the Kerberos V5 library
+	itself.  Currently the same whole kitchen sink, to bootstrap.
+
+Fri Nov 18 00:16:31 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: use WITH_CCOPTS.
+
diff --git a/mechglue/src/include/Makefile.in b/mechglue/src/include/Makefile.in
new file mode 100644
index 000000000..dcd86a26f
--- /dev/null
+++ b/mechglue/src/include/Makefile.in
@@ -0,0 +1,76 @@
+thisconfigdir=..
+myfulldir=include
+mydir=include
+LOCAL_SUBDIRS=krb5 @maybe_kerberosIV@
+BUILDTOP=$(REL)..
+##DOSBUILDTOP = ..
+NO_OUTPRE=1
+
+all-unix:: krb5.h
+
+all-windows::
+	@echo Making in include\krb5
+	cd krb5
+	$(MAKE) -$(MFLAGS)
+	cd ..
+
+all-unix:: maybe-make-db.h-@DB_HEADER_VERSION@
+
+maybe-make-db.h-k5:
+	: db.h will be installed by util/db2
+maybe-make-db.h-sys:
+	: fall back to system db.h 
+maybe-make-db.h-redirect:
+	test -r db.h || echo '#include <@DB_HEADER@>' > db.h
+
+all-recurse: krb5/autoconf.h
+krb5/autoconf.h: $(srcdir)/krb5/autoconf.h.in
+	(cd krb5; $(MAKE) autoconf.h)
+$(srcdir)/krb5/autoconf.h.in: @MAINT@ $(srcdir)/krb5/autoconf.stmp
+$(srcdir)/krb5/autoconf.stmp: $(srcdir)/$(thisconfigdir)/configure.in $(SRCTOP)/aclocal.m4
+	$(RM) -r $(srcdir)/$(thisconfigdir)/autom4te.cache
+	cd $(srcdir)/$(thisconfigdir) && $(AUTOHEADER) --include=$(CONFIG_RELTOPDIR) $(AUTOHEADERFLAGS)
+	touch $(srcdir)/krb5/autoconf.stmp
+	$(RM) -r $(srcdir)/$(thisconfigdir)/autom4te.cache
+
+krb5.h: krb5/autoconf.h $(srcdir)/krb5.hin krb5_err.h kdb5_err.h kv5m_err.h krb524_err.h \
+		asn1_err.h
+	echo "/* This file is generated, please don't edit it directly.  */" > krb5.h
+	cat $(srcdir)/krb5.hin krb5_err.h kdb5_err.h kv5m_err.h krb524_err.h \
+		asn1_err.h >> krb5.h
+
+#
+# Build the error table include files:
+# asn1_err.h kdb5_err.h krb5_err.h kv5m_err.h krb524_err.h
+
+asn1_err.h kdb5_err.h krb5_err.h kv5m_err.h krb524_err.h: rebuild-error-tables
+	: $@
+rebuild-error-tables:
+	(cd ../lib/krb5/error_tables && $(MAKE) includes)
+
+.PHONY: force rebuild-error-tables
+force:
+
+asn1_err.h: $(SRCTOP)/lib/krb5/error_tables/asn1_err.et
+kdb5_err.h: $(SRCTOP)/lib/krb5/error_tables/kdb5_err.et
+krb5_err.h: $(SRCTOP)/lib/krb5/error_tables/krb5_err.et	
+kv5m_err.h: $(SRCTOP)/lib/krb5/error_tables/kv5m_err.et
+krb524_err.h: $(SRCTOP)/lib/krb5/error_tables/krb524_err.et
+
+clean-unix::
+	$(RM) krb5.h krb5_err.h kdb5_err.h kv5m_err.h krb524_err.h \
+		asn1_err.h
+
+clean-windows::
+	$(RM) com_err.h profile.h
+	$(RM) gssapi\gssapi.h gssapi\gssapi_generic.h gssapi\gssapi_krb5.h gssapi\timestamp
+	if exist gssapi\nul rmdir gssapi
+	cd krb5
+	@echo Making clean in include\krb5
+	$(MAKE) -$(MFLAGS) clean
+	cd ..
+	@echo Making clean in include
+
+install-headers-unix install:: krb5.h profile.h
+	$(INSTALL_DATA) krb5.h $(DESTDIR)$(KRB5_INCDIR)$(S)krb5.h
+	$(INSTALL_DATA) profile.h $(DESTDIR)$(KRB5_INCDIR)$(S)profile.h
diff --git a/mechglue/src/include/cm.h b/mechglue/src/include/cm.h
new file mode 100644
index 000000000..428e61e58
--- /dev/null
+++ b/mechglue/src/include/cm.h
@@ -0,0 +1,41 @@
+/*
+ * include/cm.h
+ *
+ * Copyright 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/* Since fd_set is large on some platforms (8K on AIX 5.2), this
+   probably shouldn't be allocated in automatic storage.  */
+struct select_state {
+    int max, nfds;
+    fd_set rfds, wfds, xfds;
+    struct timeval end_time;	/* magic: tv_sec==0 => never time out */
+};
+
+/* Select state flags.  */
+#define SSF_READ	0x01
+#define SSF_WRITE	0x02
+#define SSF_EXCEPTION	0x04
+
+krb5_error_code krb5int_cm_call_select (const struct select_state *,
+					struct select_state *, int *);
diff --git a/mechglue/src/include/fake-addrinfo.h b/mechglue/src/include/fake-addrinfo.h
new file mode 100644
index 000000000..952b43f0b
--- /dev/null
+++ b/mechglue/src/include/fake-addrinfo.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2001,2002,2003,2004 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
+
+/* Approach overview:
+
+   If a system version is available but buggy, save handles to it (via
+   inline functions in a support library), redefine the names to refer
+   to library functions, and in those functions, call the system
+   versions and fix up the returned data.  Use the native data
+   structures and flag values.
+
+   If no system version exists, use gethostby* and fake it.  Define
+   the data structures and flag values locally.
+
+
+   On Mac OS X, getaddrinfo results aren't cached (though
+   gethostbyname results are), so we need to build a cache here.  Now
+   things are getting really messy.  Because the cache is in use, we
+   use getservbyname, and throw away thread safety.  (Not that the
+   cache is thread safe, but when we get locking support, that'll be
+   dealt with.)  This code needs tearing down and rebuilding, soon.
+
+
+   Note that recent Windows developers' code has an interesting hack:
+   When you include the right header files, with the right set of
+   macros indicating system versions, you'll get an inline function
+   that looks for getaddrinfo (or whatever) in the system library, and
+   calls it if it's there.  If it's not there, it fakes it with
+   gethostby* calls.
+
+   We're taking a simpler approach: A system provides these routines or
+   it does not.
+
+   Someday, we may want to take into account different versions (say,
+   different revs of GNU libc) where some are broken in one way, and
+   some work or are broken in another way.  Cross that bridge when we
+   come to it.  */
+
+/* To do, maybe:
+
+   + For AIX 4.3.3, using the RFC 2133 definition: Implement
+     AI_NUMERICHOST.  It's not defined in the header file.
+
+     For certain (old?) versions of GNU libc, AI_NUMERICHOST is
+     defined but not implemented.
+
+   + Use gethostbyname2, inet_aton and other IPv6 or thread-safe
+     functions if available.  But, see
+     http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=135182 for one
+     gethostbyname2 problem on Linux.  And besides, if a platform is
+     supporting IPv6 at all, they really should be doing getaddrinfo
+     by now.
+
+   + inet_ntop, inet_pton
+
+   + Conditionally export/import the function definitions, so a
+     library can have a single copy instead of multiple.
+
+   + Upgrade host requirements to include working implementations of
+     these functions, and throw all this away.  Pleeease?  :-)  */
+
+#ifndef FAI_DEFINED
+#define FAI_DEFINED
+#include "port-sockets.h"
+#include "socket-utils.h"
+
+#if !defined (HAVE_GETADDRINFO)
+
+#undef  addrinfo
+#define addrinfo	my_fake_addrinfo
+
+struct addrinfo {
+    int ai_family;		/* PF_foo */
+    int ai_socktype;		/* SOCK_foo */
+    int ai_protocol;		/* 0, IPPROTO_foo */
+    int ai_flags;		/* AI_PASSIVE etc */
+    size_t ai_addrlen;		/* real length of socket address */
+    char *ai_canonname;		/* canonical name of host */
+    struct sockaddr *ai_addr;	/* pointer to variable-size address */
+    struct addrinfo *ai_next;	/* next in linked list */
+};
+
+#undef	AI_PASSIVE
+#define	AI_PASSIVE	0x01
+#undef	AI_CANONNAME
+#define	AI_CANONNAME	0x02
+#undef	AI_NUMERICHOST
+#define	AI_NUMERICHOST	0x04
+/* RFC 2553 says these are part of the interface for getipnodebyname,
+   not for getaddrinfo.  RFC 3493 says they're part of the interface
+   for getaddrinfo, and getipnodeby* are deprecated.  Our fake
+   getaddrinfo implementation here does IPv4 only anyways.  */
+#undef	AI_V4MAPPED
+#define	AI_V4MAPPED	0
+#undef	AI_ADDRCONFIG
+#define	AI_ADDRCONFIG	0
+#undef	AI_ALL
+#define	AI_ALL		0
+#undef	AI_DEFAULT
+#define	AI_DEFAULT	(AI_V4MAPPED|AI_ADDRCONFIG)
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 32
+#endif
+
+#undef	NI_NUMERICHOST
+#define NI_NUMERICHOST	0x01
+#undef	NI_NUMERICSERV
+#define NI_NUMERICSERV	0x02
+#undef	NI_NAMEREQD
+#define NI_NAMEREQD	0x04
+#undef	NI_DGRAM
+#define NI_DGRAM	0x08
+#undef	NI_NOFQDN
+#define NI_NOFQDN	0x10
+
+
+#undef  EAI_ADDRFAMILY
+#define EAI_ADDRFAMILY	1
+#undef  EAI_AGAIN
+#define EAI_AGAIN	2
+#undef  EAI_BADFLAGS
+#define EAI_BADFLAGS	3
+#undef  EAI_FAIL
+#define EAI_FAIL	4
+#undef  EAI_FAMILY
+#define EAI_FAMILY	5
+#undef  EAI_MEMORY
+#define EAI_MEMORY	6
+#undef  EAI_NODATA
+#define EAI_NODATA	7
+#undef  EAI_NONAME
+#define EAI_NONAME	8
+#undef  EAI_SERVICE
+#define EAI_SERVICE	9
+#undef  EAI_SOCKTYPE
+#define EAI_SOCKTYPE	10
+#undef  EAI_SYSTEM
+#define EAI_SYSTEM	11
+
+#endif /* ! HAVE_GETADDRINFO */
+
+/* Fudge things on older gai implementations.  */
+/* AIX 4.3.3 is based on RFC 2133; no AI_NUMERICHOST.  */
+#ifndef AI_NUMERICHOST
+# define AI_NUMERICHOST 0
+#endif
+/* Partial RFC 2553 implementations may not have AI_ADDRCONFIG and
+   friends, which RFC 3493 says are now part of the getaddrinfo
+   interface, and we'll want to use.  */
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+#ifndef AI_V4MAPPED
+# define AI_V4MAPPED 0
+#endif
+#ifndef AI_ALL
+# define AI_ALL 0
+#endif
+#ifndef AI_DEFAULT
+# define AI_DEFAULT (AI_ADDRCONFIG|AI_V4MAPPED)
+#endif
+
+#if defined(KRB5_USE_INET6) && defined(NEED_INSIXADDR_ANY) 
+/* If compiling with IPv6 support and C library does not define in6addr_any */
+extern const struct in6_addr krb5int_in6addr_any;
+#undef in6addr_any
+#define in6addr_any krb5int_in6addr_any
+#endif
+
+/* Call out to stuff defined in libkrb5support.  */
+extern int krb5int_getaddrinfo (const char *node, const char *service,
+				const struct addrinfo *hints,
+				struct addrinfo **aip);
+extern void krb5int_freeaddrinfo (struct addrinfo *ai);
+extern const char *krb5int_gai_strerror(int err);
+extern int krb5int_getnameinfo (const struct sockaddr *sa, socklen_t salen,
+				char *hbuf, size_t hbuflen,
+				char *sbuf, size_t sbuflen,
+				int flags);
+#ifndef IMPLEMENT_FAKE_GETADDRINFO
+#undef	getaddrinfo
+#define getaddrinfo krb5int_getaddrinfo
+#undef  freeaddrinfo
+#define freeaddrinfo krb5int_freeaddrinfo
+#undef  gai_strerror
+#define gai_strerror krb5int_gai_strerror
+#undef  getnameinfo
+#define getnameinfo krb5int_getnameinfo
+#endif
+
+#endif /* FAI_DEFINED */
diff --git a/mechglue/src/include/foreachaddr.h b/mechglue/src/include/foreachaddr.h
new file mode 100644
index 000000000..57591f596
--- /dev/null
+++ b/mechglue/src/include/foreachaddr.h
@@ -0,0 +1,64 @@
+/*
+ * include/foreachaddr.c
+ *
+ * Copyright 1990,1991,2000,2001,2002,2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Iterate over the protocol addresses supported by this host, invoking
+ * a callback function or three supplied by the caller.
+ *
+ * XNS support is untested, but "should just work".  (Hah!)
+ */
+
+/* This function iterates over all the addresses it can find for the
+   local system, in one or two passes.  In each pass, and between the
+   two, it can invoke callback functions supplied by the caller.  The
+   two passes should operate on the same information, though not
+   necessarily in the same order each time.  Duplicate and local
+   addresses should be eliminated.  Storage passed to callback
+   functions should not be assumed to be valid after foreach_localaddr
+   returns.
+
+   The int return value is an errno value (XXX or krb5_error_code
+   returned for a socket error) if something internal to
+   foreach_localaddr fails.  If one of the callback functions wants to
+   indicate an error, it should store something via the 'data' handle.
+   If any callback function returns a non-zero value,
+   foreach_localaddr will clean up and return immediately.
+
+   Multiple definitions are provided below, dependent on various
+   system facilities for extracting the necessary information.  */
+
+extern int
+krb5int_foreach_localaddr (/*@null@*/ void *data,
+			   int (*pass1fn) (/*@null@*/ void *,
+					   struct sockaddr *) /*@*/,
+			   /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
+			   /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
+						      struct sockaddr *) /*@*/)
+#if defined(DEBUG) || defined(TEST)
+     /*@modifies fileSystem@*/
+#endif
+    ;
+
+#define foreach_localaddr krb5int_foreach_localaddr
diff --git a/mechglue/src/include/k5-int.h b/mechglue/src/include/k5-int.h
new file mode 100644
index 000000000..3f8c60da7
--- /dev/null
+++ b/mechglue/src/include/k5-int.h
@@ -0,0 +1,1895 @@
+/*
+ * Copyright (C) 1989,1990,1991,1992,1993,1994,1995,2000,2001, 2003 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * This prototype for k5-int.h (Krb5 internals include file)
+ * includes the user-visible definitions from krb5.h and then
+ * includes other definitions that are not user-visible but are
+ * required for compiling Kerberos internal routines.
+ *
+ * John Gilmore, Cygnus Support, Sat Jan 21 22:45:52 PST 1995
+ */
+
+#ifndef _KRB5_INT_H
+#define _KRB5_INT_H
+
+#ifdef KRB5_GENERAL__
+#error krb5.h included before k5-int.h
+#endif /* KRB5_GENERAL__ */
+
+#include "osconf.h"
+
+/*
+ * Begin "k5-config.h"
+ */
+#ifndef KRB5_CONFIG__
+#define KRB5_CONFIG__
+
+/* 
+ * Machine-type definitions: PC Clone 386 running Microloss Windows
+ */
+
+#if defined(_MSDOS) || defined(_WIN32)
+#include "win-mac.h"
+
+/* Kerberos Windows initialization file */
+#define KERBEROS_INI	"kerberos.ini"
+#define INI_FILES	"Files"
+#define INI_KRB_CCACHE	"krb5cc"	/* Location of the ccache */
+#define INI_KRB5_CONF	"krb5.ini"	/* Location of krb5.conf file */
+#define ANSI_STDIO
+#endif
+
+#ifndef KRB5_AUTOCONF__
+#define KRB5_AUTOCONF__
+#include "autoconf.h"
+#endif
+
+#ifndef KRB5_SYSTYPES__
+#define KRB5_SYSTYPES__
+
+#ifdef HAVE_SYS_TYPES_H		/* From autoconf.h */
+#include <sys/types.h>
+#else /* HAVE_SYS_TYPES_H */
+typedef unsigned long 	u_long;
+typedef unsigned int	u_int;
+typedef unsigned short	u_short;
+typedef unsigned char	u_char;
+#endif /* HAVE_SYS_TYPES_H */
+#endif /* KRB5_SYSTYPES__ */
+
+
+#include "k5-platform.h"
+/* not used in krb5.h (yet) */
+typedef UINT64_TYPE krb5_ui_8;
+typedef INT64_TYPE krb5_int64;
+
+
+#define DEFAULT_PWD_STRING1 "Enter password"
+#define DEFAULT_PWD_STRING2 "Re-enter password for verification"
+
+#define	KRB5_KDB_MAX_LIFE	(60*60*24) /* one day */
+#define	KRB5_KDB_MAX_RLIFE	(60*60*24*7) /* one week */
+#define	KRB5_KDB_EXPIRATION	2145830400 /* Thu Jan  1 00:00:00 2038 UTC */
+
+/* 
+ * Windows requires a different api interface to each function. Here
+ * just define it as NULL.
+ */
+#ifndef KRB5_CALLCONV
+#define KRB5_CALLCONV
+#define KRB5_CALLCONV_C
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* #define KRB5_OLD_CRYPTO is done in krb5.h */
+
+#endif /* KRB5_CONFIG__ */
+
+/*
+ * End "k5-config.h"
+ */
+
+/*
+ * After loading the configuration definitions, load the Kerberos definitions.
+ */
+#include <errno.h>
+#include "krb5.h"
+#include "profile.h"
+
+#include "port-sockets.h"
+#include "socket-utils.h"
+
+/* Get mutex support; currently used only for the replay cache.  */
+#include "k5-thread.h"
+
+/* krb5/krb5.h includes many other .h files in the krb5 subdirectory.
+   The ones that it doesn't include, we include below.  */
+
+/*
+ * Begin "k5-errors.h"
+ */
+#ifndef KRB5_ERRORS__
+#define KRB5_ERRORS__
+
+
+/* Error codes used in KRB_ERROR protocol messages.
+   Return values of library routines are based on a different error table
+   (which allows non-ambiguous error codes between subsystems) */
+
+/* KDC errors */
+#define	KDC_ERR_NONE			0 /* No error */
+#define	KDC_ERR_NAME_EXP		1 /* Client's entry in DB expired */
+#define	KDC_ERR_SERVICE_EXP		2 /* Server's entry in DB expired */
+#define	KDC_ERR_BAD_PVNO		3 /* Requested pvno not supported */
+#define	KDC_ERR_C_OLD_MAST_KVNO		4 /* C's key encrypted in old master */
+#define	KDC_ERR_S_OLD_MAST_KVNO		5 /* S's key encrypted in old master */
+#define	KDC_ERR_C_PRINCIPAL_UNKNOWN	6 /* Client not found in Kerberos DB */
+#define	KDC_ERR_S_PRINCIPAL_UNKNOWN	7 /* Server not found in Kerberos DB */
+#define	KDC_ERR_PRINCIPAL_NOT_UNIQUE	8 /* Multiple entries in Kerberos DB */
+#define	KDC_ERR_NULL_KEY		9 /* The C or S has a null key */
+#define	KDC_ERR_CANNOT_POSTDATE		10 /* Tkt ineligible for postdating */
+#define	KDC_ERR_NEVER_VALID		11 /* Requested starttime > endtime */
+#define	KDC_ERR_POLICY			12 /* KDC policy rejects request */
+#define	KDC_ERR_BADOPTION		13 /* KDC can't do requested opt. */
+#define	KDC_ERR_ENCTYPE_NOSUPP		14 /* No support for encryption type */
+#define KDC_ERR_SUMTYPE_NOSUPP		15 /* No support for checksum type */
+#define KDC_ERR_PADATA_TYPE_NOSUPP	16 /* No support for padata type */
+#define KDC_ERR_TRTYPE_NOSUPP		17 /* No support for transited type */
+#define KDC_ERR_CLIENT_REVOKED		18 /* C's creds have been revoked */
+#define KDC_ERR_SERVICE_REVOKED		19 /* S's creds have been revoked */
+#define KDC_ERR_TGT_REVOKED		20 /* TGT has been revoked */
+#define KDC_ERR_CLIENT_NOTYET		21 /* C not yet valid */
+#define KDC_ERR_SERVICE_NOTYET		22 /* S not yet valid */
+#define KDC_ERR_KEY_EXP			23 /* Password has expired */
+#define KDC_ERR_PREAUTH_FAILED		24 /* Preauthentication failed */
+#define KDC_ERR_PREAUTH_REQUIRED	25 /* Additional preauthentication */
+					   /* required */
+#define KDC_ERR_SERVER_NOMATCH		26 /* Requested server and */
+					   /* ticket don't match*/
+/* Application errors */
+#define	KRB_AP_ERR_BAD_INTEGRITY 31	/* Decrypt integrity check failed */
+#define	KRB_AP_ERR_TKT_EXPIRED	32	/* Ticket expired */
+#define	KRB_AP_ERR_TKT_NYV	33	/* Ticket not yet valid */
+#define	KRB_AP_ERR_REPEAT	34	/* Request is a replay */
+#define	KRB_AP_ERR_NOT_US	35	/* The ticket isn't for us */
+#define	KRB_AP_ERR_BADMATCH	36	/* Ticket/authenticator don't match */
+#define	KRB_AP_ERR_SKEW		37	/* Clock skew too great */
+#define	KRB_AP_ERR_BADADDR	38	/* Incorrect net address */
+#define	KRB_AP_ERR_BADVERSION	39	/* Protocol version mismatch */
+#define	KRB_AP_ERR_MSG_TYPE	40	/* Invalid message type */
+#define	KRB_AP_ERR_MODIFIED	41	/* Message stream modified */
+#define	KRB_AP_ERR_BADORDER	42	/* Message out of order */
+#define	KRB_AP_ERR_BADKEYVER	44	/* Key version is not available */
+#define	KRB_AP_ERR_NOKEY	45	/* Service key not available */
+#define	KRB_AP_ERR_MUT_FAIL	46	/* Mutual authentication failed */
+#define KRB_AP_ERR_BADDIRECTION	47 	/* Incorrect message direction */
+#define KRB_AP_ERR_METHOD	48 	/* Alternative authentication */
+					/* method required */
+#define KRB_AP_ERR_BADSEQ	49 	/* Incorrect sequence numnber */
+					/* in message */
+#define KRB_AP_ERR_INAPP_CKSUM	50	/* Inappropriate type of */
+					/* checksum in message */
+#define KRB_AP_PATH_NOT_ACCEPTED 51	/* Policy rejects transited path */
+#define KRB_ERR_RESPONSE_TOO_BIG 52	/* Response too big for UDP, */
+					/*   retry with TCP */
+
+/* other errors */
+#define KRB_ERR_GENERIC		60 	/* Generic error (description */
+					/* in e-text) */
+#define	KRB_ERR_FIELD_TOOLONG	61	/* Field is too long for impl. */
+
+#endif /* KRB5_ERRORS__ */
+/*
+ * End "k5-errors.h"
+ */
+
+/*
+ * This structure is returned in the e-data field of the KRB-ERROR
+ * message when the error calling for an alternative form of
+ * authentication is returned, KRB_AP_METHOD.
+ */
+typedef struct _krb5_alt_method {
+	krb5_magic	magic;
+	krb5_int32	method;
+	unsigned int	length;
+	krb5_octet	*data;
+} krb5_alt_method;
+
+/*
+ * A null-terminated array of this structure is returned by the KDC as
+ * the data part of the ETYPE_INFO preauth type.  It informs the
+ * client which encryption types are supported.
+ * The  same data structure is used by both etype-info and etype-info2
+ * but s2kparams must be null when encoding etype-info.
+ */
+typedef struct _krb5_etype_info_entry {
+	krb5_magic	magic;
+	krb5_enctype	etype;
+	unsigned int	length;
+	krb5_octet	*salt;
+    krb5_data s2kparams;
+} krb5_etype_info_entry;
+
+/* 
+ *  This is essentially -1 without sign extension which can screw up
+ *  comparisons on 64 bit machines. If the length is this value, then
+ *  the salt data is not present. This is to distinguish between not
+ *  being set and being of 0 length. 
+ */
+#define KRB5_ETYPE_NO_SALT VALID_UINT_BITS
+
+typedef krb5_etype_info_entry ** krb5_etype_info;
+
+/*
+ * a sam_challenge is returned for alternate preauth 
+ */
+/*
+          SAMFlags ::= BIT STRING {
+              use-sad-as-key[0],
+              send-encrypted-sad[1],
+              must-pk-encrypt-sad[2]
+          }
+ */
+/*
+          PA-SAM-CHALLENGE ::= SEQUENCE {
+              sam-type[0]                 INTEGER,
+              sam-flags[1]                SAMFlags,
+              sam-type-name[2]            GeneralString OPTIONAL,
+              sam-track-id[3]             GeneralString OPTIONAL,
+              sam-challenge-label[4]      GeneralString OPTIONAL,
+              sam-challenge[5]            GeneralString OPTIONAL,
+              sam-response-prompt[6]      GeneralString OPTIONAL,
+              sam-pk-for-sad[7]           EncryptionKey OPTIONAL,
+              sam-nonce[8]                INTEGER OPTIONAL,
+              sam-cksum[9]                Checksum OPTIONAL
+          }
+*/
+/* sam_type values -- informational only */
+#define PA_SAM_TYPE_ENIGMA     1   /*  Enigma Logic */
+#define PA_SAM_TYPE_DIGI_PATH  2   /*  Digital Pathways */
+#define PA_SAM_TYPE_SKEY_K0    3   /*  S/key where  KDC has key 0 */
+#define PA_SAM_TYPE_SKEY       4   /*  Traditional S/Key */
+#define PA_SAM_TYPE_SECURID    5   /*  Security Dynamics */
+#define PA_SAM_TYPE_CRYPTOCARD 6   /*  CRYPTOCard */
+#if 1 /* XXX need to figure out who has which numbers assigned */
+#define PA_SAM_TYPE_ACTIVCARD_DEC  6   /*  ActivCard decimal mode */
+#define PA_SAM_TYPE_ACTIVCARD_HEX  7   /*  ActivCard hex mode */
+#define PA_SAM_TYPE_DIGI_PATH_HEX  8   /*  Digital Pathways hex mode */
+#endif
+#define PA_SAM_TYPE_EXP_BASE    128 /* experimental */
+#define PA_SAM_TYPE_GRAIL		(PA_SAM_TYPE_EXP_BASE+0) /* testing */
+#define PA_SAM_TYPE_SECURID_PREDICT	(PA_SAM_TYPE_EXP_BASE+1) /* special */
+
+typedef struct _krb5_predicted_sam_response {
+	krb5_magic	magic;
+	krb5_keyblock	sam_key;
+	krb5_flags	sam_flags; /* Makes key munging easier */
+	krb5_timestamp  stime;	/* time on server, for replay detection */
+	krb5_int32      susec;
+	krb5_principal  client;
+	krb5_data       msd;	/* mechanism specific data */
+} krb5_predicted_sam_response;
+
+typedef struct _krb5_sam_challenge {
+	krb5_magic	magic;
+	krb5_int32	sam_type; /* information */
+	krb5_flags	sam_flags; /* KRB5_SAM_* values */
+	krb5_data	sam_type_name;
+	krb5_data	sam_track_id;
+	krb5_data	sam_challenge_label;
+	krb5_data	sam_challenge;
+	krb5_data	sam_response_prompt;
+	krb5_data	sam_pk_for_sad;
+	krb5_int32	sam_nonce;
+	krb5_checksum	sam_cksum;
+} krb5_sam_challenge;
+
+typedef struct _krb5_sam_key {	/* reserved for future use */
+	krb5_magic	magic;
+	krb5_keyblock	sam_key;
+} krb5_sam_key;
+
+typedef struct _krb5_enc_sam_response_enc {
+	krb5_magic	magic;
+	krb5_int32	sam_nonce;
+	krb5_timestamp	sam_timestamp;
+	krb5_int32	sam_usec;
+	krb5_data	sam_sad;
+} krb5_enc_sam_response_enc;
+
+typedef struct _krb5_sam_response {
+	krb5_magic	magic;
+	krb5_int32	sam_type; /* informational */
+	krb5_flags	sam_flags; /* KRB5_SAM_* values */
+	krb5_data	sam_track_id; /* copied */
+	krb5_enc_data	sam_enc_key; /* krb5_sam_key - future use */
+	krb5_enc_data	sam_enc_nonce_or_ts; /* krb5_enc_sam_response_enc */
+	krb5_int32	sam_nonce;
+	krb5_timestamp	sam_patimestamp;
+} krb5_sam_response;
+
+typedef struct _krb5_sam_challenge_2 {
+	krb5_data	sam_challenge_2_body;
+	krb5_checksum	**sam_cksum;		/* Array of checksums */
+} krb5_sam_challenge_2;
+
+typedef struct _krb5_sam_challenge_2_body {
+	krb5_magic	magic;
+	krb5_int32	sam_type; /* information */
+	krb5_flags	sam_flags; /* KRB5_SAM_* values */
+	krb5_data	sam_type_name;
+	krb5_data	sam_track_id;
+	krb5_data	sam_challenge_label;
+	krb5_data	sam_challenge;
+	krb5_data	sam_response_prompt;
+	krb5_data	sam_pk_for_sad;
+	krb5_int32	sam_nonce;
+	krb5_enctype	sam_etype;
+} krb5_sam_challenge_2_body;
+
+typedef struct _krb5_sam_response_2 {
+	krb5_magic	magic;
+	krb5_int32	sam_type; /* informational */
+	krb5_flags	sam_flags; /* KRB5_SAM_* values */
+	krb5_data	sam_track_id; /* copied */
+	krb5_enc_data	sam_enc_nonce_or_sad; /* krb5_enc_sam_response_enc */
+	krb5_int32	sam_nonce;
+} krb5_sam_response_2;
+
+typedef struct _krb5_enc_sam_response_enc_2 {
+	krb5_magic	magic;
+	krb5_int32	sam_nonce;
+	krb5_data	sam_sad;
+} krb5_enc_sam_response_enc_2;
+
+/*
+ * Begin "ext-proto.h"
+ */
+#ifndef KRB5_EXT_PROTO__
+#define KRB5_EXT_PROTO__
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef HAVE_STRDUP
+extern char *strdup (const char *);
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#endif /* KRB5_EXT_PROTO__ */
+/*
+ * End "ext-proto.h"
+ */
+
+/*
+ * Begin "sysincl.h"
+ */
+#ifndef KRB5_SYSINCL__
+#define KRB5_SYSINCL__
+
+#ifndef KRB5_SYSTYPES__
+#define KRB5_SYSTYPES__
+/* needed for much of the rest -- but already handled in krb5.h? */
+/* #include <sys/types.h> */
+#endif /* KRB5_SYSTYPES__ */
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#include <time.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>			/* struct stat, stat() */
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>			/* MAXPATHLEN */
+#endif
+
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>			/* prototypes for file-related
+					   syscalls; flags for open &
+					   friends */
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#endif /* KRB5_SYSINCL__ */
+/*
+ * End "sysincl.h"
+ */
+
+/*
+ * Begin "los-proto.h"
+ */
+#ifndef KRB5_LIBOS_PROTO__
+#define KRB5_LIBOS_PROTO__
+
+#include <stdio.h>
+
+struct addrlist;
+
+/* libos.spec */
+krb5_error_code krb5_lock_file (krb5_context, int, int);
+krb5_error_code krb5_unlock_file (krb5_context, int);
+krb5_error_code krb5_sendto_kdc (krb5_context, const krb5_data *,
+				 const krb5_data *, krb5_data *, int *, int);
+krb5_error_code krb5int_sendto (krb5_context, const krb5_data *,
+				const struct addrlist *, krb5_data *,
+				struct sockaddr *, socklen_t *, int *);
+krb5_error_code krb5_get_krbhst (krb5_context, const krb5_data *, char *** );
+krb5_error_code krb5_free_krbhst (krb5_context, char * const * );
+krb5_error_code krb5_create_secure_file (krb5_context, const char * pathname);
+krb5_error_code krb5_sync_disk_file (krb5_context, FILE *fp);
+
+krb5_error_code krb5int_get_fq_local_hostname (char *, size_t);
+
+krb5_error_code krb5_os_init_context (krb5_context);
+
+void krb5_os_free_context (krb5_context);
+
+/* This function is needed by KfM's KerberosPreferences API 
+ * because it needs to be able to specify "secure" */
+krb5_error_code os_get_default_config_files 
+    (profile_filespec_t **pfiles, krb5_boolean secure);
+
+krb5_error_code krb5_find_config_files (void);
+
+krb5_error_code krb5_os_hostaddr
+	(krb5_context, const char *, krb5_address ***);
+
+/* N.B.: You need to include fake-addrinfo.h *before* k5-int.h if you're
+   going to use this structure.  */
+struct addrlist {
+    struct addrinfo **addrs;
+    int naddrs;
+    int space;
+};
+#define ADDRLIST_INIT { 0, 0, 0 }
+extern void krb5int_free_addrlist (struct addrlist *);
+extern int krb5int_grow_addrlist (struct addrlist *, int);
+extern int krb5int_add_host_to_list (struct addrlist *, const char *,
+				     int, int, int, int);
+
+krb5_error_code
+krb5int_locate_server (krb5_context,
+		       const krb5_data *realm,
+		       struct addrlist *,
+		       /* Only meaningful for kdc, really...  */
+		       int want_masters,
+		       /* look up [realms]->$realm->$name in krb5.conf */
+		       const char *profilename,
+		       /* SRV record lookup */
+		       const char *dnsname,
+		       int is_stream_service,
+		       /* Port numbers, in network order!  For profile
+			  version only, DNS code gets port numbers
+			  itself.  Use 0 for dflport2 if there's no
+			  secondary port (most common, except kdc
+			  case).  */
+		       int dflport1, int dflport2,
+		       int family);
+
+#endif /* KRB5_LIBOS_PROTO__ */
+
+/* new encryption provider api */
+
+struct krb5_enc_provider {
+    /* keybytes is the input size to make_key; 
+       keylength is the output size */
+    size_t block_size, keybytes, keylength;
+
+    /* cipher-state == 0 fresh state thrown away at end */
+    krb5_error_code (*encrypt) (const krb5_keyblock *key,
+				const krb5_data *cipher_state,
+				const krb5_data *input,
+				krb5_data *output);
+
+    krb5_error_code (*decrypt) (const krb5_keyblock *key,
+				const krb5_data *ivec,
+				const krb5_data *input,
+				krb5_data *output);
+
+    krb5_error_code (*make_key) (const krb5_data *randombits,
+				 krb5_keyblock *key);
+
+  krb5_error_code (*init_state) (const krb5_keyblock *key,
+				 krb5_keyusage keyusage, krb5_data *out_state);
+  krb5_error_code (*free_state) (krb5_data *state);
+  
+};
+
+struct krb5_hash_provider {
+    size_t hashsize, blocksize;
+
+    /* this takes multiple inputs to avoid lots of copying. */
+    krb5_error_code (*hash) (unsigned int icount, const krb5_data *input,
+			     krb5_data *output);
+};
+
+struct krb5_keyhash_provider {
+    size_t hashsize;
+
+    krb5_error_code (*hash) (const krb5_keyblock *key,
+			     krb5_keyusage keyusage,
+			     const krb5_data *ivec,
+			     const krb5_data *input,
+			     krb5_data *output);
+
+    krb5_error_code (*verify) (const krb5_keyblock *key,
+			       krb5_keyusage keyusage,
+			       const krb5_data *ivec,
+			       const krb5_data *input,
+			       const krb5_data *hash,
+			       krb5_boolean *valid);
+};
+
+typedef void (*krb5_encrypt_length_func) (const struct krb5_enc_provider *enc,
+  const struct krb5_hash_provider *hash,
+  size_t inputlen, size_t *length);
+
+typedef krb5_error_code (*krb5_crypt_func) (const struct krb5_enc_provider *enc,
+  const struct krb5_hash_provider *hash,
+  const krb5_keyblock *key, krb5_keyusage keyusage,
+  const krb5_data *ivec, 
+  const krb5_data *input, krb5_data *output);
+
+typedef krb5_error_code (*krb5_str2key_func) (const struct krb5_enc_provider *enc, const krb5_data *string,
+  const krb5_data *salt, const krb5_data *parm, krb5_keyblock *key);
+
+typedef krb5_error_code (*krb5_prf_func)(
+					 const struct krb5_enc_provider *enc, const struct krb5_hash_provider *hash,
+					 const krb5_keyblock *key,
+					 krb5_data *in, krb5_data *out);
+
+struct krb5_keytypes {
+    krb5_enctype etype;
+    char *in_string;
+    char *out_string;
+    const struct krb5_enc_provider *enc;
+    const struct krb5_hash_provider *hash;
+  size_t prf_length;
+    krb5_encrypt_length_func encrypt_len;
+    krb5_crypt_func encrypt;
+    krb5_crypt_func decrypt;
+    krb5_str2key_func str2key;
+  krb5_prf_func prf;
+    krb5_cksumtype required_ctype;
+};
+
+struct krb5_cksumtypes {
+    krb5_cksumtype ctype;
+    unsigned int flags;
+    char *in_string;
+    char *out_string;
+    /* if the hash is keyed, this is the etype it is keyed with.
+       Actually, it can be keyed by any etype which has the same
+       enc_provider as the specified etype.  DERIVE checksums can
+       be keyed with any valid etype. */
+    krb5_enctype keyed_etype;
+    /* I can't statically initialize a union, so I'm just going to use
+       two pointers here.  The keyhash is used if non-NULL.  If NULL,
+       then HMAC/hash with derived keys is used if the relevant flag
+       is set.  Otherwise, a non-keyed hash is computed.  This is all
+       kind of messy, but so is the krb5 api. */
+    const struct krb5_keyhash_provider *keyhash;
+    const struct krb5_hash_provider *hash;
+    /* This just gets uglier and uglier.  In the key derivation case,
+       we produce an hmac.  To make the hmac code work, we can't hack
+       the output size indicated by the hash provider, but we may want
+       a truncated hmac.  If we want truncation, this is the number of
+       bytes we truncate to; it should be 0 otherwise.  */
+    unsigned int trunc_size;
+};
+
+#define KRB5_CKSUMFLAG_DERIVE		0x0001
+#define KRB5_CKSUMFLAG_NOT_COLL_PROOF	0x0002
+
+/*
+ * in here to deal with stuff from lib/crypto
+ */
+
+void krb5_nfold
+(unsigned int inbits, const unsigned char *in,
+		unsigned int outbits, unsigned char *out);
+
+krb5_error_code krb5_hmac
+(const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, unsigned int icount,
+		const krb5_data *input, krb5_data *output);
+
+krb5_error_code krb5int_pbkdf2_hmac_sha1 (const krb5_data *, unsigned long,
+					  const krb5_data *,
+					  const krb5_data *);
+
+/* Make this a function eventually?  */
+#ifdef _WIN32
+# define krb5int_zap_data(ptr, len) SecureZeroMemory(ptr, len)
+#elif defined(__palmos__) && !defined(__GNUC__)
+/* CodeWarrior 8.3 complains about passing a pointer to volatile in to
+   memset.  On the other hand, we probably want it for gcc.  */
+# define krb5int_zap_data(ptr, len) memset(ptr, 0, len)
+#else
+# define krb5int_zap_data(ptr, len) memset((volatile void *)ptr, 0, len)
+# if defined(__GNUC__) && defined(__GLIBC__)
+/* GNU libc generates multiple bogus initialization warnings if we
+   pass memset a volatile pointer.  The compiler should do well enough
+   with memset even without GNU libc's attempt at optimization.  */
+# undef memset
+# endif
+#endif /* WIN32 */
+#define zap(p,l) krb5int_zap_data(p,l)
+
+/* A definition of init_state for DES based encryption systems.
+ * sets up an 8-byte IV of all zeros
+ */
+
+krb5_error_code krb5int_des_init_state
+(const krb5_keyblock *key, krb5_keyusage keyusage, krb5_data *new_state);
+
+/* 
+ * normally to free a cipher_state you can just memset the length to zero and
+ * free it.
+ */
+krb5_error_code krb5int_default_free_state
+(krb5_data *state);
+
+
+/*
+ * Combine two keys (normally used by the hardware preauth mechanism)
+ */
+krb5_error_code krb5int_c_combine_keys
+(krb5_context context, krb5_keyblock *key1, krb5_keyblock *key2,
+		krb5_keyblock *outkey);
+
+void  krb5int_c_free_keyblock
+(krb5_context, krb5_keyblock *key);
+void  krb5int_c_free_keyblock_contents
+	(krb5_context, krb5_keyblock *);
+krb5_error_code   krb5int_c_init_keyblock
+		(krb5_context, krb5_enctype enctype,
+		size_t length, krb5_keyblock **out); 
+
+/*
+ * Internal - for cleanup.
+ */
+extern void krb5int_prng_cleanup (void);
+
+
+/* 
+ * These declarations are here, so both krb5 and k5crypto
+ * can get to them.
+ * krb5 needs to get to them so it can  make them available to libgssapi.
+ */
+extern const struct krb5_enc_provider krb5int_enc_arcfour;
+extern const struct krb5_hash_provider krb5int_hash_md5;
+
+
+#ifdef KRB5_OLD_CRYPTO
+/* old provider api */
+
+krb5_error_code krb5_crypto_os_localaddr
+	(krb5_address ***);
+
+krb5_error_code krb5_crypto_us_timeofday
+	(krb5_int32 *,
+		krb5_int32 *);
+
+time_t gmt_mktime (struct tm *);
+
+#endif /* KRB5_OLD_CRYPTO */
+
+/* this helper fct is in libkrb5, but it makes sense declared here. */
+
+krb5_error_code krb5_encrypt_helper
+(krb5_context context, const krb5_keyblock *key,
+		krb5_keyusage keyusage, const krb5_data *plain,
+		krb5_enc_data *cipher);
+
+/*
+ * End "los-proto.h"
+ */
+
+/*
+ * Include the KDB definitions.
+ */
+#include "kdb.h"
+
+/*
+ * Begin "libos.h"
+ */
+#ifndef KRB5_LIBOS__
+#define KRB5_LIBOS__
+
+typedef struct _krb5_os_context {
+	krb5_magic		magic;
+	krb5_int32		time_offset;
+	krb5_int32		usec_offset;
+	krb5_int32		os_flags;
+	char *			default_ccname;
+} *krb5_os_context;
+
+/*
+ * Flags for the os_flags field
+ *
+ * KRB5_OS_TOFFSET_VALID means that the time offset fields are valid.
+ * The intention is that this facility to correct the system clocks so
+ * that they reflect the "real" time, for systems where for some
+ * reason we can't set the system clock.  Instead we calculate the
+ * offset between the system time and real time, and store the offset
+ * in the os context so that we can correct the system clock as necessary.
+ *
+ * KRB5_OS_TOFFSET_TIME means that the time offset fields should be
+ * returned as the time by the krb5 time routines.  This should only
+ * be used for testing purposes (obviously!)
+ */
+#define KRB5_OS_TOFFSET_VALID	1
+#define KRB5_OS_TOFFSET_TIME	2
+
+/* lock mode flags */
+#define	KRB5_LOCKMODE_SHARED	0x0001
+#define	KRB5_LOCKMODE_EXCLUSIVE	0x0002
+#define	KRB5_LOCKMODE_DONTBLOCK	0x0004
+#define	KRB5_LOCKMODE_UNLOCK	0x0008
+
+#endif /* KRB5_LIBOS__ */
+/*
+ * End "libos.h"
+ */
+
+/*
+ * Define our view of the size of a DES key.
+ */
+#define	KRB5_MIT_DES_KEYSIZE		8
+/*
+ * Check if des_int.h has been included before us.  If so, then check to see
+ * that our view of the DES key size is the same as des_int.h's.
+ */
+#ifdef	MIT_DES_KEYSIZE
+#if	MIT_DES_KEYSIZE != KRB5_MIT_DES_KEYSIZE
+error(MIT_DES_KEYSIZE does not equal KRB5_MIT_DES_KEYSIZE)
+#endif	/* MIT_DES_KEYSIZE != KRB5_MIT_DES_KEYSIZE */
+#endif	/* MIT_DES_KEYSIZE */
+
+/*
+ * Begin "preauth.h"
+ *
+ * (Originally written by Glen Machin at Sandia Labs.)
+ */
+/*
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ */
+#ifndef KRB5_PREAUTH__
+#define KRB5_PREAUTH__
+
+typedef struct _krb5_pa_enc_ts {
+    krb5_timestamp	patimestamp;
+    krb5_int32		pausec;
+} krb5_pa_enc_ts;
+
+typedef krb5_error_code (*krb5_preauth_obtain_proc)
+    (krb5_context,
+		    krb5_pa_data *,
+		    krb5_etype_info,
+		    krb5_keyblock *, 
+		    krb5_error_code ( * )(krb5_context,
+					  const krb5_enctype,
+					  krb5_data *,
+					  krb5_const_pointer,
+					  krb5_keyblock **),
+		    krb5_const_pointer,
+		    krb5_creds *,
+		    krb5_kdc_req *,
+		    krb5_pa_data **);
+
+typedef krb5_error_code (*krb5_preauth_process_proc)
+    (krb5_context,
+		    krb5_pa_data *,
+		    krb5_kdc_req *,
+		    krb5_kdc_rep *,
+		    krb5_error_code ( * )(krb5_context,
+					  const krb5_enctype,
+					  krb5_data *,
+					  krb5_const_pointer,
+					  krb5_keyblock **),
+		    krb5_const_pointer,
+		    krb5_error_code ( * )(krb5_context,
+					  const krb5_keyblock *,
+					  krb5_const_pointer,
+					  krb5_kdc_rep * ),
+		    krb5_keyblock **,
+		    krb5_creds *, 
+		    krb5_int32 *,
+		    krb5_int32 *);
+
+typedef struct _krb5_preauth_ops {
+    krb5_magic magic;
+    int     type;
+    int	flags;
+    krb5_preauth_obtain_proc	obtain;
+    krb5_preauth_process_proc	process;
+} krb5_preauth_ops;
+
+krb5_error_code krb5_obtain_padata
+    	(krb5_context,
+		krb5_pa_data **,
+		krb5_error_code ( * )(krb5_context,
+						      const krb5_enctype,
+						      krb5_data *,
+						      krb5_const_pointer,
+						      krb5_keyblock **),
+		krb5_const_pointer, 
+		krb5_creds *,
+		krb5_kdc_req *);
+
+krb5_error_code krb5_process_padata
+	(krb5_context,
+		krb5_kdc_req *,
+		krb5_kdc_rep *,
+		krb5_error_code ( * )(krb5_context,
+						      const krb5_enctype,
+						      krb5_data *,
+						      krb5_const_pointer,
+						      krb5_keyblock **),
+		krb5_const_pointer,
+		krb5_error_code ( * )(krb5_context,
+						      const krb5_keyblock *,
+						      krb5_const_pointer,
+						      krb5_kdc_rep * ),
+		krb5_keyblock **, 	
+		krb5_creds *, 
+		krb5_int32 *);		
+
+void krb5_free_etype_info
+    (krb5_context, krb5_etype_info);
+
+/*
+ * Preauthentication property flags
+ */
+#define KRB5_PREAUTH_FLAGS_ENCRYPT	0x00000001
+#define KRB5_PREAUTH_FLAGS_HARDWARE	0x00000002
+
+#endif /* KRB5_PREAUTH__ */
+/*
+ * End "preauth.h"
+ */
+krb5_error_code
+krb5int_copy_data_contents (krb5_context, const krb5_data *, krb5_data *);
+
+typedef krb5_error_code (*krb5_gic_get_as_key_fct)
+    (krb5_context,
+		     krb5_principal,
+		     krb5_enctype,
+		     krb5_prompter_fct,
+		     void *prompter_data,
+		     krb5_data *salt,
+     krb5_data *s2kparams,
+		     krb5_keyblock *as_key,
+		     void *gak_data);
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds
+(krb5_context context,
+		krb5_creds *creds,
+		krb5_principal client,
+		krb5_prompter_fct prompter,
+		void *prompter_data,
+		krb5_deltat start_time,
+		char *in_tkt_service,
+		krb5_get_init_creds_opt *gic_options,
+		krb5_gic_get_as_key_fct gak,
+		void *gak_data,
+		int *master,
+		krb5_kdc_rep **as_reply);
+
+void krb5int_populate_gic_opt (
+    krb5_context, krb5_get_init_creds_opt *,
+    krb5_flags options, krb5_address * const *addrs, krb5_enctype *ktypes,
+    krb5_preauthtype *pre_auth_types, krb5_creds *creds);
+
+
+krb5_error_code krb5_do_preauth
+(krb5_context, krb5_kdc_req *,
+		krb5_pa_data **, krb5_pa_data ***,
+		krb5_data *salt, krb5_data *s2kparams,
+ krb5_enctype *,
+		krb5_keyblock *,
+		krb5_prompter_fct, void *,
+		krb5_gic_get_as_key_fct, void *);
+
+void KRB5_CALLCONV krb5_free_sam_challenge
+	(krb5_context, krb5_sam_challenge * );
+void KRB5_CALLCONV krb5_free_sam_challenge_2
+	(krb5_context, krb5_sam_challenge_2 * );
+void KRB5_CALLCONV krb5_free_sam_challenge_2_body
+	(krb5_context, krb5_sam_challenge_2_body *);
+void KRB5_CALLCONV krb5_free_sam_response
+	(krb5_context, krb5_sam_response * );
+void KRB5_CALLCONV krb5_free_sam_response_2
+	(krb5_context, krb5_sam_response_2 * );
+void KRB5_CALLCONV krb5_free_predicted_sam_response
+	(krb5_context, krb5_predicted_sam_response * );
+void KRB5_CALLCONV krb5_free_enc_sam_response_enc
+	(krb5_context, krb5_enc_sam_response_enc * );
+void KRB5_CALLCONV krb5_free_enc_sam_response_enc_2
+	(krb5_context, krb5_enc_sam_response_enc_2 * );
+void KRB5_CALLCONV krb5_free_sam_challenge_contents
+	(krb5_context, krb5_sam_challenge * );
+void KRB5_CALLCONV krb5_free_sam_challenge_2_contents
+	(krb5_context, krb5_sam_challenge_2 * );
+void KRB5_CALLCONV krb5_free_sam_challenge_2_body_contents
+	(krb5_context, krb5_sam_challenge_2_body * );
+void KRB5_CALLCONV krb5_free_sam_response_contents
+	(krb5_context, krb5_sam_response * );
+void KRB5_CALLCONV krb5_free_sam_response_2_contents
+	(krb5_context, krb5_sam_response_2 *);
+void KRB5_CALLCONV krb5_free_predicted_sam_response_contents
+	(krb5_context, krb5_predicted_sam_response * );
+void KRB5_CALLCONV krb5_free_enc_sam_response_enc_contents
+	(krb5_context, krb5_enc_sam_response_enc * );
+void KRB5_CALLCONV krb5_free_enc_sam_response_enc_2_contents
+	(krb5_context, krb5_enc_sam_response_enc_2 * );
+ 
+void KRB5_CALLCONV krb5_free_pa_enc_ts
+	(krb5_context, krb5_pa_enc_ts *);
+
+/* #include "krb5/wordsize.h" -- comes in through base-defs.h. */
+#include "com_err.h"
+
+struct _krb5_context {
+	krb5_magic	magic;
+	krb5_enctype	*in_tkt_ktypes;
+	int		in_tkt_ktype_count;
+	krb5_enctype	*tgs_ktypes;
+	int		tgs_ktype_count;
+	/* This used to be a void*, but since we always allocate them
+	   together (though in different source files), and the types
+	   are declared in the same header, might as well just combine
+	   them.
+
+	   The array[1] is so the existing code treating the field as
+	   a pointer will still work.  For cleanliness, it should
+	   eventually get changed to a single element instead of an
+	   array.  */
+	struct _krb5_os_context	os_context[1];
+	char		*default_realm;
+	profile_t	profile;
+	void		*db_context;
+	int		ser_ctx_count;
+	void		*ser_ctx;
+	/* allowable clock skew */
+	krb5_deltat 	clockskew;
+	krb5_cksumtype	kdc_req_sumtype;
+	krb5_cksumtype	default_ap_req_sumtype;
+	krb5_cksumtype	default_safe_sumtype;
+	krb5_flags 	kdc_default_options;
+	krb5_flags	library_options;
+	krb5_boolean	profile_secure;
+	int		fcc_default_format;
+	int		scc_default_format;
+	krb5_prompt_type *prompt_types;
+	/* Message size above which we'll try TCP first in send-to-kdc
+	   type code.  Aside from the 2**16 size limit, we put no
+	   absolute limit on the UDP packet size.  */
+	int		udp_pref_limit;
+
+	/* This is the tgs_ktypes list as read from the profile, or
+	   set to compiled-in defaults.  The application code cannot
+	   override it.  This is used for session keys for
+	   intermediate ticket-granting tickets used to acquire the
+	   requested ticket (the session key of which may be
+	   constrained by tgs_ktypes above).  */
+	krb5_enctype	*conf_tgs_ktypes;
+	int		conf_tgs_ktypes_count;
+	/* Use the _configured version?  */
+	krb5_boolean	use_conf_ktypes;
+
+#ifdef KRB5_DNS_LOOKUP
+        krb5_boolean    profile_in_memory;
+#endif /* KRB5_DNS_LOOKUP */
+};
+
+/* could be used in a table to find an etype and initialize a block */
+
+
+#define KRB5_LIBOPT_SYNC_KDCTIME	0x0001
+
+/* internal message representations */
+
+typedef struct _krb5_safe {
+    krb5_magic magic;
+    krb5_data user_data;		/* user data */
+    krb5_timestamp timestamp;		/* client time, optional */
+    krb5_int32 usec;			/* microsecond portion of time,
+					   optional */
+    krb5_ui_4 seq_number;		/* sequence #, optional */
+    krb5_address *s_address;	/* sender address */
+    krb5_address *r_address;	/* recipient address, optional */
+    krb5_checksum *checksum;	/* data integrity checksum */
+} krb5_safe;
+
+typedef struct _krb5_priv {
+    krb5_magic magic;
+    krb5_enc_data enc_part;		/* encrypted part */
+} krb5_priv;
+
+typedef struct _krb5_priv_enc_part {
+    krb5_magic magic;
+    krb5_data user_data;		/* user data */
+    krb5_timestamp timestamp;		/* client time, optional */
+    krb5_int32 usec;			/* microsecond portion of time, opt. */
+    krb5_ui_4 seq_number;		/* sequence #, optional */
+    krb5_address *s_address;	/* sender address */
+    krb5_address *r_address;	/* recipient address, optional */
+} krb5_priv_enc_part;
+
+void KRB5_CALLCONV krb5_free_safe
+	(krb5_context, krb5_safe * );
+void KRB5_CALLCONV krb5_free_priv
+	(krb5_context, krb5_priv * );
+void KRB5_CALLCONV krb5_free_priv_enc_part
+	(krb5_context, krb5_priv_enc_part * );
+
+/*
+ * Begin "asn1.h"
+ */
+#ifndef KRB5_ASN1__
+#define KRB5_ASN1__
+
+/* ASN.1 encoding knowledge; KEEP IN SYNC WITH ASN.1 defs! */
+/* here we use some knowledge of ASN.1 encodings */
+/* 
+  Ticket is APPLICATION 1.
+  Authenticator is APPLICATION 2.
+  AS_REQ is APPLICATION 10.
+  AS_REP is APPLICATION 11.
+  TGS_REQ is APPLICATION 12.
+  TGS_REP is APPLICATION 13.
+  AP_REQ is APPLICATION 14.
+  AP_REP is APPLICATION 15.
+  KRB_SAFE is APPLICATION 20.
+  KRB_PRIV is APPLICATION 21.
+  KRB_CRED is APPLICATION 22.
+  EncASRepPart is APPLICATION 25.
+  EncTGSRepPart is APPLICATION 26.
+  EncAPRepPart is APPLICATION 27.
+  EncKrbPrivPart is APPLICATION 28.
+  EncKrbCredPart is APPLICATION 29.
+  KRB_ERROR is APPLICATION 30.
+ */
+/* allow either constructed or primitive encoding, so check for bit 6
+   set or reset */
+#define krb5_is_krb_ticket(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x61 ||\
+				    (dat)->data[0] == 0x41))
+#define krb5_is_krb_authenticator(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x62 ||\
+				    (dat)->data[0] == 0x42))
+#define krb5_is_as_req(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x6a ||\
+				    (dat)->data[0] == 0x4a))
+#define krb5_is_as_rep(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x6b ||\
+				    (dat)->data[0] == 0x4b))
+#define krb5_is_tgs_req(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x6c ||\
+				    (dat)->data[0] == 0x4c))
+#define krb5_is_tgs_rep(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x6d ||\
+				    (dat)->data[0] == 0x4d))
+#define krb5_is_ap_req(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x6e ||\
+				    (dat)->data[0] == 0x4e))
+#define krb5_is_ap_rep(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x6f ||\
+				    (dat)->data[0] == 0x4f))
+#define krb5_is_krb_safe(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x74 ||\
+				    (dat)->data[0] == 0x54))
+#define krb5_is_krb_priv(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x75 ||\
+				    (dat)->data[0] == 0x55))
+#define krb5_is_krb_cred(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x76 ||\
+				    (dat)->data[0] == 0x56))
+#define krb5_is_krb_enc_as_rep_part(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x79 ||\
+				    (dat)->data[0] == 0x59))
+#define krb5_is_krb_enc_tgs_rep_part(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x7a ||\
+				    (dat)->data[0] == 0x5a))
+#define krb5_is_krb_enc_ap_rep_part(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x7b ||\
+				    (dat)->data[0] == 0x5b))
+#define krb5_is_krb_enc_krb_priv_part(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x7c ||\
+				    (dat)->data[0] == 0x5c))
+#define krb5_is_krb_enc_krb_cred_part(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x7d ||\
+				    (dat)->data[0] == 0x5d))
+#define krb5_is_krb_error(dat)\
+	((dat) && (dat)->length && ((dat)->data[0] == 0x7e ||\
+				    (dat)->data[0] == 0x5e))
+
+/*************************************************************************
+ * Prototypes for krb5_encode.c
+ *************************************************************************/
+
+/*
+   krb5_error_code encode_krb5_structure(const krb5_structure *rep,
+					 krb5_data **code);
+   modifies  *code
+   effects   Returns the ASN.1 encoding of *rep in **code.
+             Returns ASN1_MISSING_FIELD if a required field is emtpy in *rep.
+             Returns ENOMEM if memory runs out.
+*/
+
+krb5_error_code encode_krb5_authenticator
+	(const krb5_authenticator *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_ticket
+	(const krb5_ticket *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_encryption_key
+	(const krb5_keyblock *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_enc_tkt_part
+	(const krb5_enc_tkt_part *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_enc_kdc_rep_part
+	(const krb5_enc_kdc_rep_part *rep, krb5_data **code);
+
+/* yes, the translation is identical to that used for KDC__REP */ 
+krb5_error_code encode_krb5_as_rep
+	(const krb5_kdc_rep *rep, krb5_data **code);
+
+/* yes, the translation is identical to that used for KDC__REP */ 
+krb5_error_code encode_krb5_tgs_rep
+	(const krb5_kdc_rep *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_ap_req
+	(const krb5_ap_req *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_ap_rep
+	(const krb5_ap_rep *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_ap_rep_enc_part
+	(const krb5_ap_rep_enc_part *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_as_req
+	(const krb5_kdc_req *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_tgs_req
+	(const krb5_kdc_req *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_kdc_req_body
+	(const krb5_kdc_req *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_safe
+	(const krb5_safe *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_safe_with_body
+	(const krb5_safe *rep, const krb5_data *body, krb5_data **code);
+
+krb5_error_code encode_krb5_priv
+	(const krb5_priv *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_enc_priv_part
+	(const krb5_priv_enc_part *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_cred
+	(const krb5_cred *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_enc_cred_part
+	(const krb5_cred_enc_part *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_error
+	(const krb5_error *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_authdata
+	(const krb5_authdata **rep, krb5_data **code);
+
+krb5_error_code encode_krb5_pwd_sequence
+	(const passwd_phrase_element *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_pwd_data
+	(const krb5_pwd_data *rep, krb5_data **code);
+
+krb5_error_code encode_krb5_padata_sequence
+	(const krb5_pa_data ** rep, krb5_data **code);
+
+krb5_error_code encode_krb5_alt_method
+	(const krb5_alt_method *, krb5_data **code);
+
+krb5_error_code encode_krb5_etype_info
+	(const krb5_etype_info_entry **, krb5_data **code);
+krb5_error_code encode_krb5_etype_info2
+	(const krb5_etype_info_entry **, krb5_data **code);
+
+krb5_error_code encode_krb5_enc_data
+    	(const krb5_enc_data *, krb5_data **);
+
+krb5_error_code encode_krb5_pa_enc_ts
+    	(const krb5_pa_enc_ts *, krb5_data **);
+
+krb5_error_code encode_krb5_sam_challenge
+	(const krb5_sam_challenge * , krb5_data **);
+
+krb5_error_code encode_krb5_sam_key
+	(const krb5_sam_key * , krb5_data **);
+
+krb5_error_code encode_krb5_enc_sam_response_enc
+	(const krb5_enc_sam_response_enc * , krb5_data **);
+
+krb5_error_code encode_krb5_sam_response
+	(const krb5_sam_response * , krb5_data **);
+
+krb5_error_code encode_krb5_sam_challenge_2
+	(const krb5_sam_challenge_2 * , krb5_data **);
+
+krb5_error_code encode_krb5_sam_challenge_2_body
+	(const krb5_sam_challenge_2_body * , krb5_data **);
+
+krb5_error_code encode_krb5_enc_sam_response_enc_2
+	(const krb5_enc_sam_response_enc_2 * , krb5_data **);
+
+krb5_error_code encode_krb5_sam_response_2
+	(const krb5_sam_response_2 * , krb5_data **);
+
+krb5_error_code encode_krb5_predicted_sam_response
+	(const krb5_predicted_sam_response * , krb5_data **);
+
+krb5_error_code encode_krb5_setpw_req
+(const krb5_principal target, char *password, krb5_data **code);
+
+/*************************************************************************
+ * End of prototypes for krb5_encode.c
+ *************************************************************************/
+
+krb5_error_code decode_krb5_sam_challenge
+       (const krb5_data *, krb5_sam_challenge **);
+
+krb5_error_code decode_krb5_enc_sam_key
+       (const krb5_data *, krb5_sam_key **);
+
+krb5_error_code decode_krb5_enc_sam_response_enc
+       (const krb5_data *, krb5_enc_sam_response_enc **);
+
+krb5_error_code decode_krb5_sam_response
+       (const krb5_data *, krb5_sam_response **);
+
+krb5_error_code decode_krb5_predicted_sam_response
+       (const krb5_data *, krb5_predicted_sam_response **);
+
+krb5_error_code decode_krb5_sam_challenge_2
+	(const krb5_data *, krb5_sam_challenge_2 **);
+
+krb5_error_code decode_krb5_sam_challenge_2_body
+	(const krb5_data *, krb5_sam_challenge_2_body **);
+
+krb5_error_code decode_krb5_enc_sam_response_enc_2
+	(const krb5_data *, krb5_enc_sam_response_enc_2 **);
+
+krb5_error_code decode_krb5_sam_response_2
+	(const krb5_data *, krb5_sam_response_2 **);
+
+
+/*************************************************************************
+ * Prototypes for krb5_decode.c
+ *************************************************************************/
+
+krb5_error_code krb5_validate_times
+       (krb5_context, 
+		       krb5_ticket_times *);
+
+/*
+   krb5_error_code decode_krb5_structure(const krb5_data *code,
+                                         krb5_structure **rep);
+                                         
+   requires  Expects **rep to not have been allocated;
+              a new *rep is allocated regardless of the old value.
+   effects   Decodes *code into **rep.
+	     Returns ENOMEM if memory is exhausted.
+             Returns asn1 and krb5 errors.
+*/
+
+krb5_error_code decode_krb5_authenticator
+	(const krb5_data *code, krb5_authenticator **rep);
+
+krb5_error_code decode_krb5_ticket
+	(const krb5_data *code, krb5_ticket **rep);
+
+krb5_error_code decode_krb5_encryption_key
+	(const krb5_data *output, krb5_keyblock **rep);
+
+krb5_error_code decode_krb5_enc_tkt_part
+	(const krb5_data *output, krb5_enc_tkt_part **rep);
+
+krb5_error_code decode_krb5_enc_kdc_rep_part
+	(const krb5_data *output, krb5_enc_kdc_rep_part **rep);
+
+krb5_error_code decode_krb5_as_rep
+	(const krb5_data *output, krb5_kdc_rep **rep);
+
+krb5_error_code decode_krb5_tgs_rep
+	(const krb5_data *output, krb5_kdc_rep **rep);
+
+krb5_error_code decode_krb5_ap_req
+	(const krb5_data *output, krb5_ap_req **rep);
+
+krb5_error_code decode_krb5_ap_rep
+	(const krb5_data *output, krb5_ap_rep **rep);
+
+krb5_error_code decode_krb5_ap_rep_enc_part
+	(const krb5_data *output, krb5_ap_rep_enc_part **rep);
+
+krb5_error_code decode_krb5_as_req
+	(const krb5_data *output, krb5_kdc_req **rep);
+
+krb5_error_code decode_krb5_tgs_req
+	(const krb5_data *output, krb5_kdc_req **rep);
+
+krb5_error_code decode_krb5_kdc_req_body
+	(const krb5_data *output, krb5_kdc_req **rep);
+
+krb5_error_code decode_krb5_safe
+	(const krb5_data *output, krb5_safe **rep);
+
+krb5_error_code decode_krb5_safe_with_body
+	(const krb5_data *output, krb5_safe **rep, krb5_data *body);
+
+krb5_error_code decode_krb5_priv
+	(const krb5_data *output, krb5_priv **rep);
+
+krb5_error_code decode_krb5_enc_priv_part
+	(const krb5_data *output, krb5_priv_enc_part **rep);
+
+krb5_error_code decode_krb5_cred
+	(const krb5_data *output, krb5_cred **rep);
+
+krb5_error_code decode_krb5_enc_cred_part
+	(const krb5_data *output, krb5_cred_enc_part **rep);
+
+krb5_error_code decode_krb5_error
+	(const krb5_data *output, krb5_error **rep);
+
+krb5_error_code decode_krb5_authdata
+	(const krb5_data *output, krb5_authdata ***rep);
+
+krb5_error_code decode_krb5_pwd_sequence
+	(const krb5_data *output, passwd_phrase_element **rep);
+
+krb5_error_code decode_krb5_pwd_data
+	(const krb5_data *output, krb5_pwd_data **rep);
+
+krb5_error_code decode_krb5_padata_sequence
+	(const krb5_data *output, krb5_pa_data ***rep);
+
+krb5_error_code decode_krb5_alt_method
+	(const krb5_data *output, krb5_alt_method **rep);
+
+krb5_error_code decode_krb5_etype_info
+	(const krb5_data *output, krb5_etype_info_entry ***rep);
+
+krb5_error_code decode_krb5_etype_info2
+	(const krb5_data *output, krb5_etype_info_entry ***rep);
+
+krb5_error_code decode_krb5_enc_data
+	(const krb5_data *output, krb5_enc_data **rep);
+
+krb5_error_code decode_krb5_pa_enc_ts
+	(const krb5_data *output, krb5_pa_enc_ts **rep);
+
+krb5_error_code decode_krb5_sam_key
+	(const krb5_data *, krb5_sam_key **);
+
+/*************************************************************************
+ * End of prototypes for krb5_decode.c
+ *************************************************************************/
+
+#endif /* KRB5_ASN1__ */
+/*
+ * End "asn1.h"
+ */
+
+
+/*
+ * Internal krb5 library routines
+ */
+krb5_error_code krb5_encrypt_tkt_part
+	(krb5_context,
+		const krb5_keyblock *,
+		krb5_ticket * );
+
+
+krb5_error_code krb5_encode_kdc_rep
+	(krb5_context,
+		const krb5_msgtype,
+		const krb5_enc_kdc_rep_part *,
+		int using_subkey,
+		const krb5_keyblock *,
+		krb5_kdc_rep *,
+		krb5_data ** );
+
+krb5_boolean krb5int_auth_con_chkseqnum
+	(krb5_context ctx, krb5_auth_context ac, krb5_ui_4 in_seq);
+/*
+ * [De]Serialization Handle and operations.
+ */
+struct __krb5_serializer {
+    krb5_magic		odtype;
+    krb5_error_code	(*sizer) (krb5_context,
+						  krb5_pointer,
+						  size_t *);
+    krb5_error_code	(*externalizer) (krb5_context,
+							 krb5_pointer,
+							 krb5_octet **,
+							 size_t *);
+    krb5_error_code	(*internalizer) (krb5_context,
+							 krb5_pointer *,
+							 krb5_octet **,
+							 size_t *);
+};
+typedef const struct __krb5_serializer * krb5_ser_handle;
+typedef struct __krb5_serializer krb5_ser_entry;
+
+krb5_ser_handle krb5_find_serializer
+	(krb5_context,
+		krb5_magic);
+krb5_error_code krb5_register_serializer
+	(krb5_context,
+			const krb5_ser_entry *);
+
+/* Determine the external size of a particular opaque structure */
+krb5_error_code KRB5_CALLCONV krb5_size_opaque
+	(krb5_context,
+		krb5_magic,
+		krb5_pointer,
+		size_t *);
+
+/* Serialize the structure into a buffer */
+krb5_error_code KRB5_CALLCONV krb5_externalize_opaque
+	(krb5_context,
+		krb5_magic,
+		krb5_pointer,
+		krb5_octet **,
+		size_t *);
+
+/* Deserialize the structure from a buffer */
+krb5_error_code KRB5_CALLCONV krb5_internalize_opaque
+	(krb5_context,
+		krb5_magic,
+		krb5_pointer *,
+		krb5_octet **,
+		size_t *);
+
+/* Serialize data into a buffer */
+krb5_error_code krb5_externalize_data
+	(krb5_context,
+		krb5_pointer,
+		krb5_octet **,
+		size_t *);
+/*
+ * Initialization routines.
+ */
+
+/* Initialize serialization for krb5_[os_]context */
+krb5_error_code KRB5_CALLCONV krb5_ser_context_init
+	(krb5_context);
+
+/* Initialize serialization for krb5_auth_context */
+krb5_error_code KRB5_CALLCONV krb5_ser_auth_context_init
+	(krb5_context);
+
+/* Initialize serialization for krb5_keytab */
+krb5_error_code KRB5_CALLCONV krb5_ser_keytab_init
+	(krb5_context);
+
+/* Initialize serialization for krb5_ccache */
+krb5_error_code KRB5_CALLCONV krb5_ser_ccache_init
+	(krb5_context);
+
+/* Initialize serialization for krb5_rcache */
+krb5_error_code KRB5_CALLCONV krb5_ser_rcache_init
+	(krb5_context);
+
+/* [De]serialize 4-byte integer */
+krb5_error_code KRB5_CALLCONV krb5_ser_pack_int32
+	(krb5_int32,
+		krb5_octet **,
+		size_t *);
+krb5_error_code KRB5_CALLCONV krb5_ser_unpack_int32
+	(krb5_int32 *,
+		krb5_octet **,
+		size_t *);
+/* [De]serialize 8-byte integer */
+krb5_error_code KRB5_CALLCONV krb5_ser_pack_int64
+	(krb5_int64, krb5_octet **, size_t *);
+krb5_error_code KRB5_CALLCONV krb5_ser_unpack_int64
+	(krb5_int64 *, krb5_octet **, size_t *);
+/* [De]serialize byte string */
+krb5_error_code KRB5_CALLCONV krb5_ser_pack_bytes
+	(krb5_octet *,
+		size_t,
+		krb5_octet **,
+		size_t *);
+krb5_error_code KRB5_CALLCONV krb5_ser_unpack_bytes
+	(krb5_octet *,
+		size_t,
+		krb5_octet **,
+		size_t *);
+
+krb5_error_code KRB5_CALLCONV krb5int_cc_default
+	(krb5_context, krb5_ccache *);
+
+krb5_error_code KRB5_CALLCONV krb5_cc_retrieve_cred_default
+	(krb5_context, krb5_ccache, krb5_flags,
+			krb5_creds *, krb5_creds *);
+
+void krb5int_set_prompt_types
+	(krb5_context, krb5_prompt_type *);
+
+krb5_error_code
+krb5int_generate_and_save_subkey (krb5_context, krb5_auth_context,
+				  krb5_keyblock * /* Old keyblock, not new!  */);
+
+/* set and change password helpers */
+
+krb5_error_code krb5int_mk_chpw_req
+	(krb5_context context, krb5_auth_context auth_context,
+ 			krb5_data *ap_req, char *passwd, krb5_data *packet);
+krb5_error_code krb5int_rd_chpw_rep
+	(krb5_context context, krb5_auth_context auth_context,
+		       krb5_data *packet, int *result_code,
+		       krb5_data *result_data);
+krb5_error_code KRB5_CALLCONV krb5_chpw_result_code_string
+	(krb5_context context, int result_code,
+			char **result_codestr);
+krb5_error_code  krb5int_mk_setpw_req
+	(krb5_context context, krb5_auth_context auth_context,
+ 			krb5_data *ap_req, krb5_principal targetprinc, char *passwd, krb5_data *packet);
+krb5_error_code krb5int_rd_setpw_rep
+	(krb5_context context, krb5_auth_context auth_context,
+		       krb5_data *packet, int *result_code,
+		       krb5_data *result_data);
+krb5_error_code krb5int_setpw_result_code_string
+	(krb5_context context, int result_code,
+			const char **result_codestr);
+
+struct srv_dns_entry {
+    struct srv_dns_entry *next;
+    int priority;
+    int weight;
+    unsigned short port;
+    char *host;
+};
+krb5_error_code
+krb5int_make_srv_query_realm(const krb5_data *realm,
+			     const char *service,
+			     const char *protocol,
+			     struct srv_dns_entry **answers);
+void krb5int_free_srv_dns_data(struct srv_dns_entry *);
+
+/*
+ * Convenience function for structure magic number
+ */
+#define KRB5_VERIFY_MAGIC(structure,magic_number) \
+    if ((structure)->magic != (magic_number)) return (magic_number);
+
+/* to keep lint happy */
+#define krb5_xfree(val) free((char *)(val))
+
+/* To keep happy libraries which are (for now) accessing internal stuff */
+
+/* Make sure to increment by one when changing the struct */
+#define KRB5INT_ACCESS_STRUCT_VERSION 9
+
+#ifndef ANAME_SZ
+struct ktext;			/* from krb.h, for krb524 support */
+#endif
+typedef struct _krb5int_access {
+    /* crypto stuff */
+    const struct krb5_hash_provider *md5_hash_provider;
+    const struct krb5_enc_provider *arcfour_enc_provider;
+    krb5_error_code (* krb5_hmac) (const struct krb5_hash_provider *hash,
+				   const krb5_keyblock *key,
+				   unsigned int icount, const krb5_data *input,
+				   krb5_data *output);
+    /* service location and communication */
+    krb5_error_code (*locate_server) (krb5_context, const krb5_data *,
+				      struct addrlist *, int,
+				      const char *, const char *,
+				      int, int, int, int);
+    krb5_error_code (*sendto_udp) (krb5_context, const krb5_data *msg,
+				   const struct addrlist *, krb5_data *reply,
+				   struct sockaddr *, socklen_t *, int *);
+    krb5_error_code (*add_host_to_list)(struct addrlist *lp,
+					const char *hostname,
+					int port, int secport,
+					int socktype, int family);
+    void (*free_addrlist) (struct addrlist *);
+
+    krb5_error_code (*make_srv_query_realm)(const krb5_data *realm,
+					    const char *service,
+					    const char *protocol,
+					    struct srv_dns_entry **answers);
+    void (*free_srv_dns_data)(struct srv_dns_entry *);
+    int (*use_dns_kdc)(krb5_context);
+
+    /* krb4 compatibility stuff -- may be null if not enabled */
+    krb5_int32 (*krb_life_to_time)(krb5_int32, int);
+    int (*krb_time_to_life)(krb5_int32, krb5_int32);
+    int (*krb524_encode_v4tkt)(struct ktext *, char *, unsigned int *);
+    krb5_error_code (*krb5int_c_mandatory_cksumtype)
+        (krb5_context, krb5_enctype, krb5_cksumtype *);
+    krb5_error_code (KRB5_CALLCONV *krb5_ser_pack_int64)
+        (krb5_int64, krb5_octet **, size_t *);
+    krb5_error_code (KRB5_CALLCONV *krb5_ser_unpack_int64)
+        (krb5_int64 *, krb5_octet **, size_t *);
+} krb5int_access;
+
+#define KRB5INT_ACCESS_VERSION \
+    (((krb5_int32)((sizeof(krb5int_access) & 0xFFFF) | \
+		   (KRB5INT_ACCESS_STRUCT_VERSION << 16))) & 0xFFFFFFFF)
+
+krb5_error_code KRB5_CALLCONV krb5int_accessor
+	(krb5int_access*, krb5_int32);
+
+/* Ick -- some krb524 and krb4 support placed in the krb5 library,
+   because AFS (and potentially other applications?) use the krb4
+   object as an opaque token, which (in some implementations) is not
+   in fact a krb4 ticket, so we don't want to drag in the krb4 support
+   just to enable this.  */
+
+#define KRB524_SERVICE "krb524"
+#define KRB524_PORT 4444
+
+/* v4lifetime.c */
+extern krb5_int32 krb5int_krb_life_to_time(krb5_int32, int);
+extern int krb5int_krb_time_to_life(krb5_int32, krb5_int32);
+
+/* conv_creds.c */
+int krb5int_encode_v4tkt
+	(struct ktext *v4tkt, char *buf, unsigned int *encoded_len);
+
+/* send524.c */
+int krb5int_524_sendto_kdc
+        (krb5_context context, const krb5_data * message, 
+	 const krb5_data * realm, krb5_data * reply,
+	 struct sockaddr *, socklen_t *);
+
+/* temporary -- this should be under lib/krb5/ccache somewhere */
+
+struct _krb5_ccache {
+    krb5_magic magic;
+    const struct _krb5_cc_ops *ops;
+    krb5_pointer data;
+};
+
+struct _krb5_cc_ops {
+    krb5_magic magic;
+    char *prefix;
+    const char * (KRB5_CALLCONV *get_name) (krb5_context, krb5_ccache);
+    krb5_error_code (KRB5_CALLCONV *resolve) (krb5_context, krb5_ccache *,
+					    const char *);
+    krb5_error_code (KRB5_CALLCONV *gen_new) (krb5_context, krb5_ccache *);
+    krb5_error_code (KRB5_CALLCONV *init) (krb5_context, krb5_ccache,
+					    krb5_principal);
+    krb5_error_code (KRB5_CALLCONV *destroy) (krb5_context, krb5_ccache);
+    krb5_error_code (KRB5_CALLCONV *close) (krb5_context, krb5_ccache);
+    krb5_error_code (KRB5_CALLCONV *store) (krb5_context, krb5_ccache,
+					    krb5_creds *);
+    krb5_error_code (KRB5_CALLCONV *retrieve) (krb5_context, krb5_ccache,
+					    krb5_flags, krb5_creds *,
+					    krb5_creds *);
+    krb5_error_code (KRB5_CALLCONV *get_princ) (krb5_context, krb5_ccache,
+					    krb5_principal *);
+    krb5_error_code (KRB5_CALLCONV *get_first) (krb5_context, krb5_ccache,
+					    krb5_cc_cursor *);
+    krb5_error_code (KRB5_CALLCONV *get_next) (krb5_context, krb5_ccache,
+					    krb5_cc_cursor *, krb5_creds *);
+    krb5_error_code (KRB5_CALLCONV *end_get) (krb5_context, krb5_ccache,
+					    krb5_cc_cursor *);
+    krb5_error_code (KRB5_CALLCONV *remove_cred) (krb5_context, krb5_ccache,
+					    krb5_flags, krb5_creds *);
+    krb5_error_code (KRB5_CALLCONV *set_flags) (krb5_context, krb5_ccache,
+					    krb5_flags);
+    krb5_error_code (KRB5_CALLCONV *get_flags) (krb5_context, krb5_ccache,
+						krb5_flags *);
+};
+
+extern const krb5_cc_ops *krb5_cc_dfl_ops;
+
+typedef struct _krb5_donot_replay {
+    krb5_magic magic;
+    krb5_ui_4 hash;
+    char *server;			/* null-terminated */
+    char *client;			/* null-terminated */
+    krb5_int32 cusec;
+    krb5_timestamp ctime;
+} krb5_donot_replay;
+
+krb5_error_code krb5_rc_default 
+	(krb5_context,
+		krb5_rcache *);
+krb5_error_code krb5_rc_resolve_type 
+	(krb5_context,
+		krb5_rcache *,char *);
+krb5_error_code krb5_rc_resolve_full 
+	(krb5_context,
+		krb5_rcache *,char *);
+char * krb5_rc_get_type 
+	(krb5_context,
+		krb5_rcache);
+char * krb5_rc_default_type 
+	(krb5_context);
+char * krb5_rc_default_name 
+	(krb5_context);
+krb5_error_code krb5_auth_to_rep 
+	(krb5_context,
+		krb5_tkt_authent *,
+		krb5_donot_replay *);
+
+
+krb5_error_code KRB5_CALLCONV krb5_rc_initialize
+	(krb5_context, krb5_rcache,krb5_deltat);
+krb5_error_code KRB5_CALLCONV krb5_rc_recover_or_initialize
+	(krb5_context, krb5_rcache,krb5_deltat);
+krb5_error_code KRB5_CALLCONV krb5_rc_recover
+	(krb5_context, krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_destroy
+	(krb5_context, krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_close
+	(krb5_context, krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_store
+	(krb5_context, krb5_rcache,krb5_donot_replay *);
+krb5_error_code KRB5_CALLCONV krb5_rc_expunge
+	(krb5_context, krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_get_lifespan
+	(krb5_context, krb5_rcache,krb5_deltat *);
+char *KRB5_CALLCONV krb5_rc_get_name
+	(krb5_context, krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_resolve
+	(krb5_context, krb5_rcache, char *);
+
+typedef struct _krb5_kt_ops {
+    krb5_magic magic;
+    char *prefix;
+    /* routines always present */
+    krb5_error_code (KRB5_CALLCONV *resolve) 
+	(krb5_context,
+		 const char *,
+		 krb5_keytab *);
+    krb5_error_code (KRB5_CALLCONV *get_name) 
+	(krb5_context,
+		 krb5_keytab,
+		 char *,
+		 unsigned int);
+    krb5_error_code (KRB5_CALLCONV *close) 
+	(krb5_context,
+		 krb5_keytab);
+    krb5_error_code (KRB5_CALLCONV *get) 
+	(krb5_context,
+		 krb5_keytab,
+		 krb5_const_principal,
+		 krb5_kvno,
+		 krb5_enctype,
+		 krb5_keytab_entry *);
+    krb5_error_code (KRB5_CALLCONV *start_seq_get) 
+	(krb5_context,
+		 krb5_keytab,
+		 krb5_kt_cursor *);	
+    krb5_error_code (KRB5_CALLCONV *get_next) 
+	(krb5_context,
+		 krb5_keytab,
+		 krb5_keytab_entry *,
+		 krb5_kt_cursor *);
+    krb5_error_code (KRB5_CALLCONV *end_get) 
+	(krb5_context,
+		 krb5_keytab,
+		 krb5_kt_cursor *);
+    /* routines to be included on extended version (write routines) */
+    krb5_error_code (KRB5_CALLCONV *add) 
+	(krb5_context,
+		 krb5_keytab,
+		 krb5_keytab_entry *);
+    krb5_error_code (KRB5_CALLCONV *remove) 
+	(krb5_context,
+		 krb5_keytab,
+		  krb5_keytab_entry *);
+
+    /* Handle for serializer */
+    const krb5_ser_entry *serializer;
+} krb5_kt_ops;
+
+extern const krb5_kt_ops krb5_kt_dfl_ops;
+
+extern krb5_error_code krb5int_translate_gai_error (int);
+
+/* Not sure it's ready for exposure just yet.  */
+extern krb5_error_code
+krb5int_c_mandatory_cksumtype (krb5_context, krb5_enctype, krb5_cksumtype *);
+
+extern int krb5int_crypto_init (void);
+extern int krb5int_prng_init(void);
+
+#endif /* _KRB5_INT_H */
diff --git a/mechglue/src/include/k5-platform.h b/mechglue/src/include/k5-platform.h
new file mode 100644
index 000000000..7f7f3087b
--- /dev/null
+++ b/mechglue/src/include/k5-platform.h
@@ -0,0 +1,715 @@
+/*
+ * k5-platform.h
+ *
+ * Copyright 2003, 2004, 2005 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.	Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Some platform-dependent definitions to sync up the C support level.
+ * Some to a C99-ish level, some related utility code.
+ *
+ * Currently:
+ * + make "static inline" work
+ * + 64-bit types and load/store code
+ * + SIZE_MAX
+ * + shared library init/fini hooks
+ * + consistent getpwnam/getpwuid interfaces
+ */
+
+#ifndef K5_PLATFORM_H
+#define K5_PLATFORM_H
+
+#include "autoconf.h"
+
+/* Initialization and finalization function support for libraries.
+
+   At top level, before the functions are defined or even declared:
+   MAKE_INIT_FUNCTION(init_fn);
+   MAKE_FINI_FUNCTION(fini_fn);
+   Then:
+   int init_fn(void) { ... }
+   void fini_fn(void) { if (INITIALIZER_RAN(init_fn)) ... }
+   In code, in the same file:
+   err = CALL_INIT_FUNCTION(init_fn);
+
+   To trigger or verify the initializer invocation from another file,
+   a helper function must be created.
+
+   This model handles both the load-time execution (Windows) and
+   delayed execution (pthread_once) approaches, and should be able to
+   guarantee in both cases that the init function is run once, in one
+   thread, before other stuff in the library is done; furthermore, the
+   finalization code should only run if the initialization code did.
+   (Maybe I could've made the "if INITIALIZER_RAN" test implicit, via
+   another function hidden in macros, but this is hairy enough
+   already.)
+
+   The init_fn and fini_fn names should be chosen such that any
+   exported names staring with those names, and optionally followed by
+   additional characters, fits in with any namespace constraints on
+   the library in question.
+
+
+   There's also PROGRAM_EXITING() currently always defined as zero.
+   If there's some trivial way to find out if the fini function is
+   being called because the program that the library is linked into is
+   exiting, we can just skip all the work because the resources are
+   about to be freed up anyways.  Generally this is likely to be the
+   same as distinguishing whether the library was loaded dynamically
+   while the program was running, or loaded as part of program
+   startup.  On most platforms, I don't think we can distinguish these
+   cases easily, and it's probably not worth expending any significant
+   effort.  (Note in particular that atexit() won't do, because if the
+   library is explicitly loaded and unloaded, it would have to be able
+   to deregister the atexit callback function.  Also, the system limit
+   on atexit callbacks may be small.)
+
+
+   Implementation outline:
+
+   Windows: MAKE_FINI_FUNCTION creates a symbol with a magic name that
+   is sought at library build time, and code is added to invoke the
+   function when the library is unloaded.  MAKE_INIT_FUNCTION does
+   likewise, but the function is invoked when the library is loaded,
+   and an extra variable is declared to hold an error code and a "yes
+   the initializer ran" flag.  CALL_INIT_FUNCTION blows up if the flag
+   isn't set, otherwise returns the error code.
+
+   UNIX: MAKE_INIT_FUNCTION creates and initializes a variable with a
+   name derived from the function name, containing a k5_once_t
+   (pthread_once_t or int), an error code, and a pointer to the
+   function.  The function itself is declared static, but the
+   associated variable has external linkage.  CALL_INIT_FUNCTION
+   ensures thath the function is called exactly once (pthread_once or
+   just check the flag) and returns the stored error code (or the
+   pthread_once error).
+
+   (That's the basic idea.  With some debugging assert() calls and
+   such, it's a bit more complicated.  And we also need to handle
+   doing the pthread test at run time on systems where that works, so
+   we use the k5_once_t stuff instead.)
+
+   UNIX, with compiler support: MAKE_FINI_FUNCTION declares the
+   function as a destructor, and the run time linker support or
+   whatever will cause it to be invoked when the library is unloaded,
+   the program ends, etc.
+
+   UNIX, with linker support: MAKE_FINI_FUNCTION creates a symbol with
+   a magic name that is sought at library build time, and linker
+   options are used to mark it as a finalization function for the
+   library.  The symbol must be exported.
+
+   UNIX, no library finalization support: The finalization function
+   never runs, and we leak memory.  Tough.
+
+   DELAY_INITIALIZER will be defined by the configure script if we
+   want to use k5_once instead of load-time initialization.  That'll
+   be the preferred method on most systems except Windows, where we
+   have to initialize some mutexes.
+
+
+
+
+   For maximum flexibility in defining the macros, the function name
+   parameter should be a simple name, not even a macro defined as
+   another name.  The function should have a unique name, and should
+   conform to whatever namespace is used by the library in question.
+   (We do have export lists, but (1) they're not used for all
+   platforms, and (2) they're not used for static libraries.)
+
+   If the macro expansion needs the function to have been declared, it
+   must include a declaration.  If it is not necessary for the symbol
+   name to be exported from the object file, the macro should declare
+   it as "static".  Hence the signature must exactly match "void
+   foo(void)".  (ANSI C allows a static declaration followed by a
+   non-static one; the result is internal linkage.)  The macro
+   expansion has to come before the function, because gcc apparently
+   won't act on "__attribute__((constructor))" if it comes after the
+   function definition.
+
+   This is going to be compiler- and environment-specific, and may
+   require some support at library build time, and/or "asm"
+   statements.  But through macro expansion and auxiliary functions,
+   we should be able to handle most things except #pragma.
+
+   It's okay for this code to require that the library be built
+   with the same compiler and compiler options throughout, but
+   we shouldn't require that the library and application use the
+   same compiler.
+
+   For static libraries, we don't really care about cleanup too much,
+   since it's all memory handling and mutex allocation which will all
+   be cleaned up when the program exits.  Thus, it's okay if gcc-built
+   static libraries don't play nicely with cc-built executables when
+   it comes to static constructors, just as long as it doesn't cause
+   linking to fail.
+
+   For dynamic libraries on UNIX, we'll use pthread_once-type support
+   to do delayed initialization, so if finalization can't be made to
+   work, we'll only have memory leaks in a load/use/unload cycle.  If
+   anyone (like, say, the OS vendor) complains about this, they can
+   tell us how to get a shared library finalization function invoked
+   automatically.
+
+   Currently there's --disable-delayed-initialization for preventing
+   the initialization from being delayed on UNIX, but that's mainly
+   just for testing the linker options for initialization, and will
+   probably be removed at some point.  */
+
+/* Helper macros.  */
+
+# define JOIN__2_2(A,B) A ## _ ## _ ## B
+# define JOIN__2(A,B) JOIN__2_2(A,B)
+
+/* XXX Should test USE_LINKER_INIT_OPTION early, and if it's set,
+   always provide a function by the expected name, even if we're
+   delaying initialization.  */
+
+#if defined(DELAY_INITIALIZER)
+
+/* Run the initialization code during program execution, at the latest
+   possible moment.  This means multiple threads may be active.  */
+# include "k5-thread.h"
+typedef struct { k5_once_t once; int error, did_run; void (*fn)(void); } k5_init_t;
+# ifdef USE_LINKER_INIT_OPTION
+#  define MAYBE_DUMMY_INIT(NAME)		\
+	void JOIN__2(NAME, auxinit) () { }
+# else
+#  define MAYBE_DUMMY_INIT(NAME)
+# endif
+# ifdef __GNUC__
+/* Do it in macro form so we get the file/line of the invocation if
+   the assertion fails.  */
+#  define k5_call_init_function(I)					\
+	(__extension__ ({						\
+		k5_init_t *k5int_i = (I);				\
+		int k5int_err = k5_once(&k5int_i->once, k5int_i->fn);	\
+		(k5int_err						\
+		 ? k5int_err						\
+		 : (assert(k5int_i->did_run != 0), k5int_i->error));	\
+	    }))
+#  define MAYBE_DEFINE_CALLINIT_FUNCTION
+# else
+#  define MAYBE_DEFINE_CALLINIT_FUNCTION			\
+	static inline int k5_call_init_function(k5_init_t *i)	\
+	{							\
+	    int err;						\
+	    err = k5_once(&i->once, i->fn);			\
+	    if (err)						\
+		return err;					\
+	    assert (i->did_run != 0);				\
+	    return i->error;					\
+	}
+# endif
+# define MAKE_INIT_FUNCTION(NAME)				\
+	static int NAME(void);					\
+	MAYBE_DUMMY_INIT(NAME)					\
+	/* forward declaration for use in initializer */	\
+	static void JOIN__2(NAME, aux) (void);			\
+	static k5_init_t JOIN__2(NAME, once) =			\
+		{ K5_ONCE_INIT, 0, 0, JOIN__2(NAME, aux) };	\
+	MAYBE_DEFINE_CALLINIT_FUNCTION				\
+	static void JOIN__2(NAME, aux) (void)			\
+	{							\
+	    JOIN__2(NAME, once).did_run = 1;			\
+	    JOIN__2(NAME, once).error = NAME();			\
+	}							\
+	/* so ';' following macro use won't get error */	\
+	static int NAME(void)
+# define CALL_INIT_FUNCTION(NAME)	\
+	k5_call_init_function(& JOIN__2(NAME, once))
+/* This should be called in finalization only, so we shouldn't have
+   multiple active threads mucking around in our library at this
+   point.  So ignore the once_t object and just look at the flag.
+
+   XXX Could we have problems with memory coherence between processors
+   if we don't invoke mutex/once routines?  Probably not, the
+   application code should already be coordinating things such that
+   the library code is not in use by this point, and memory
+   synchronization will be needed there.  */
+# define INITIALIZER_RAN(NAME)	\
+	(JOIN__2(NAME, once).did_run && JOIN__2(NAME, once).error == 0)
+
+# define PROGRAM_EXITING()		(0)
+
+#elif defined(__GNUC__) && !defined(_WIN32) && defined(CONSTRUCTOR_ATTR_WORKS)
+
+/* Run initializer at load time, via GCC/C++ hook magic.  */
+
+# ifdef USE_LINKER_INIT_OPTION
+     /* Both gcc and linker option??  Favor gcc.  */
+#  define MAYBE_DUMMY_INIT(NAME)		\
+	void JOIN__2(NAME, auxinit) () { }
+# else
+#  define MAYBE_DUMMY_INIT(NAME)
+# endif
+
+typedef struct { int error; unsigned char did_run; } k5_init_t;
+# define MAKE_INIT_FUNCTION(NAME)		\
+	MAYBE_DUMMY_INIT(NAME)			\
+	static k5_init_t JOIN__2(NAME, ran)	\
+		= { 0, 2 };			\
+	static void JOIN__2(NAME, aux)(void)	\
+	    __attribute__((constructor));	\
+	static int NAME(void);			\
+	static void JOIN__2(NAME, aux)(void)	\
+	{					\
+	    JOIN__2(NAME, ran).error = NAME();	\
+	    JOIN__2(NAME, ran).did_run = 3;	\
+	}					\
+	static int NAME(void)
+# define CALL_INIT_FUNCTION(NAME)		\
+	(JOIN__2(NAME, ran).did_run == 3	\
+	 ? JOIN__2(NAME, ran).error		\
+	 : (abort(),0))
+# define INITIALIZER_RAN(NAME)	(JOIN__2(NAME,ran).did_run == 3 && JOIN__2(NAME, ran).error == 0)
+
+# define PROGRAM_EXITING()		(0)
+
+#elif defined(USE_LINKER_INIT_OPTION) || defined(_WIN32)
+
+/* Run initializer at load time, via linker magic, or in the
+   case of WIN32, win_glue.c hard-coded knowledge.  */
+typedef struct { int error; unsigned char did_run; } k5_init_t;
+# define MAKE_INIT_FUNCTION(NAME)		\
+	static k5_init_t JOIN__2(NAME, ran)	\
+		= { 0, 2 };			\
+	static int NAME(void);			\
+	void JOIN__2(NAME, auxinit)()		\
+	{					\
+	    JOIN__2(NAME, ran).error = NAME();	\
+	    JOIN__2(NAME, ran).did_run = 3;	\
+	}					\
+	static int NAME(void)
+# define CALL_INIT_FUNCTION(NAME)		\
+	(JOIN__2(NAME, ran).did_run == 3	\
+	 ? JOIN__2(NAME, ran).error		\
+	 : (abort(),0))
+# define INITIALIZER_RAN(NAME)	\
+	(JOIN__2(NAME, ran).error == 0)
+
+# define PROGRAM_EXITING()		(0)
+
+#else
+
+# error "Don't know how to do load-time initializers for this configuration."
+
+# define PROGRAM_EXITING()		(0)
+
+#endif
+
+
+
+#if defined(USE_LINKER_FINI_OPTION) || defined(_WIN32)
+/* If we're told the linker option will be used, it doesn't really
+   matter what compiler we're using.  Do it the same way
+   regardless.  */
+
+# ifdef __hpux
+
+     /* On HP-UX, we need this auxiliary function.  At dynamic load or
+	unload time (but *not* program startup and termination for
+	link-time specified libraries), the linker-indicated function
+	is called with a handle on the library and a flag indicating
+	whether it's being loaded or unloaded.
+
+	The "real" fini function doesn't need to be exported, so
+	declare it static.
+
+	As usual, the final declaration is just for syntactic
+	convenience, so the top-level invocation of this macro can be
+	followed by a semicolon.  */
+
+#  include <dl.h>
+#  define MAKE_FINI_FUNCTION(NAME)					    \
+	static void NAME(void);						    \
+	void JOIN__2(NAME, auxfini)(shl_t, int); /* silence gcc warnings */ \
+	void JOIN__2(NAME, auxfini)(shl_t h, int l) { if (!l) NAME(); }	    \
+	static void NAME(void)
+
+# else /* not hpux */
+
+#  define MAKE_FINI_FUNCTION(NAME)	\
+	void NAME(void)
+
+# endif
+
+#elif defined(__GNUC__) && defined(DESTRUCTOR_ATTR_WORKS)
+/* If we're using gcc, if the C++ support works, the compiler should
+   build executables and shared libraries that support the use of
+   static constructors and destructors.  The C compiler supports a
+   function attribute that makes use of the same facility as C++.
+
+   XXX How do we know if the C++ support actually works?  */
+# define MAKE_FINI_FUNCTION(NAME)	\
+	static void NAME(void) __attribute__((destructor))
+
+#elif !defined(SHARED)
+
+/* In this case, we just don't care about finalization.
+
+   The code will still define the function, but we won't do anything
+   with it.  Annoying: This may generate unused-function warnings.  */
+
+# define MAKE_FINI_FUNCTION(NAME)	\
+	static void NAME(void)
+
+#else
+
+# error "Don't know how to do unload-time finalization for this configuration."
+
+#endif
+
+
+/* 64-bit support: krb5_ui_8 and krb5_int64.
+
+   This should move to krb5.h eventually, but without the namespace
+   pollution from the autoconf macros.  */
+#if defined(HAVE_STDINT_H) || defined(HAVE_INTTYPES_H)
+# ifdef HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+# ifdef HAVE_INTTYPES_H
+#  include <inttypes.h>
+# endif
+# define INT64_TYPE int64_t
+# define UINT64_TYPE uint64_t
+#elif defined(_WIN32)
+# define INT64_TYPE signed __int64
+# define UINT64_TYPE unsigned __int64
+#else /* not Windows, and neither stdint.h nor inttypes.h */
+# define INT64_TYPE signed long long
+# define UINT64_TYPE unsigned long long
+#endif
+
+#include <limits.h>
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t)((size_t)0 - 1))
+#endif
+
+/* Read and write integer values as (unaligned) octet strings in
+   specific byte orders.  Add per-platform optimizations as
+   needed.  */
+
+#if HAVE_ENDIAN_H
+# include <endian.h>
+#elif HAVE_MACHINE_ENDIAN_H
+# include <machine/endian.h>
+#endif
+/* Check for BIG/LITTLE_ENDIAN macros.  If exactly one is defined, use
+   it.  If both are defined, then BYTE_ORDER should be defined and
+   match one of them.  Try those symbols, then try again with an
+   underscore prefix.  */
+#if defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN)
+# if BYTE_ORDER == BIG_ENDIAN
+#  define K5_BE
+# endif
+# if BYTE_ORDER == LITTLE_ENDIAN
+#  define K5_LE
+# endif
+#elif defined(BIG_ENDIAN)
+# define K5_BE
+#elif defined(LITTLE_ENDIAN)
+# define K5_LE
+#elif defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
+# if _BYTE_ORDER == _BIG_ENDIAN
+#  define K5_BE
+# endif
+# if _BYTE_ORDER == _LITTLE_ENDIAN
+#  define K5_LE
+# endif
+#elif defined(_BIG_ENDIAN)
+# define K5_BE
+#elif defined(_LITTLE_ENDIAN)
+# define K5_LE
+#endif
+#if !defined(K5_BE) && !defined(K5_LE)
+/* Look for some architectures we know about.
+
+   MIPS can use either byte order, but the preprocessor tells us which
+   mode we're compiling for.  The GCC config files indicate that
+   variants of Alpha and IA64 might be out there with both byte
+   orders, but until we encounter the "wrong" ones in the real world,
+   just go with the default (unless there are cpp predefines to help
+   us there too).
+
+   As far as I know, only PDP11 and ARM (which we don't handle here)
+   have strange byte orders where an 8-byte value isn't laid out as
+   either 12345678 or 87654321.  */
+# if defined(__i386__) || defined(_MIPSEL) || defined(__alpha__) || defined(__ia64__)
+#  define K5_LE
+# endif
+# if defined(__hppa__) || defined(__rs6000__) || defined(__sparc__) || defined(_MIPSEB) || defined(__m68k__) || defined(__sparc64__) || defined(__ppc__) || defined(__ppc64__)
+#  define K5_BE
+# endif
+#endif
+#if defined(K5_BE) && defined(K5_LE)
+# error "oops, check the byte order macros"
+#endif
+
+/* Optimize for GCC on platforms with known byte orders.
+
+   GCC's packed structures can be written to with any alignment; the
+   compiler will use byte operations, unaligned-word operations, or
+   normal memory ops as appropriate for the architecture.
+
+   This assumes the availability of uint##_t types, which should work
+   on most of our platforms except Windows, where we're not using
+   GCC.  */
+#ifdef __GNUC__
+# define PUT(SIZE,PTR,VAL)	(((struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i = (VAL))
+# define GET(SIZE,PTR)		(((const struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i)
+# define PUTSWAPPED(SIZE,PTR,VAL)	PUT(SIZE,PTR,SWAP##SIZE(VAL))
+# define GETSWAPPED(SIZE,PTR)		SWAP##SIZE(GET(SIZE,PTR))
+#endif
+/* To do: Define SWAP16, SWAP32, SWAP64 macros to byte-swap values
+   with the indicated numbers of bits.
+
+   Linux: byteswap.h, bswap_16 etc.
+   Solaris 10: none
+   Mac OS X: machine/endian.h or byte_order.h, NXSwap{Short,Int,LongLong}
+   NetBSD: sys/bswap.h, bswap16 etc.  */
+
+#if defined(HAVE_BYTESWAP_H) && defined(HAVE_BSWAP_16)
+# include <byteswap.h>
+# define SWAP16			bswap_16
+# define SWAP32			bswap_32
+# ifdef HAVE_BSWAP_64
+#  define SWAP64		bswap_64
+# endif
+#endif
+
+static inline void
+store_16_be (unsigned int val, unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_BE)
+    PUT(16,p,val);
+#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16)
+    PUTSWAPPED(16,p,val);
+#else
+    p[0] = (val >>  8) & 0xff;
+    p[1] = (val      ) & 0xff;
+#endif
+}
+static inline void
+store_32_be (unsigned int val, unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_BE)
+    PUT(32,p,val);
+#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32)
+    PUTSWAPPED(32,p,val);
+#else
+    p[0] = (val >> 24) & 0xff;
+    p[1] = (val >> 16) & 0xff;
+    p[2] = (val >>  8) & 0xff;
+    p[3] = (val      ) & 0xff;
+#endif
+}
+static inline void
+store_64_be (UINT64_TYPE val, unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_BE)
+    PUT(64,p,val);
+#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64)
+    PUTSWAPPED(64,p,val);
+#else
+    p[0] = (unsigned char)((val >> 56) & 0xff);
+    p[1] = (unsigned char)((val >> 48) & 0xff);
+    p[2] = (unsigned char)((val >> 40) & 0xff);
+    p[3] = (unsigned char)((val >> 32) & 0xff);
+    p[4] = (unsigned char)((val >> 24) & 0xff);
+    p[5] = (unsigned char)((val >> 16) & 0xff);
+    p[6] = (unsigned char)((val >>  8) & 0xff);
+    p[7] = (unsigned char)((val      ) & 0xff);
+#endif
+}
+static inline unsigned short
+load_16_be (const unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_BE)
+    return GET(16,p);
+#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16)
+    return GETSWAPPED(16,p);
+#else
+    return (p[1] | (p[0] << 8));
+#endif
+}
+static inline unsigned int
+load_32_be (const unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_BE)
+    return GET(32,p);
+#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32)
+    return GETSWAPPED(32,p);
+#else
+    return (p[3] | (p[2] << 8)
+	    | ((uint32_t) p[1] << 16)
+	    | ((uint32_t) p[0] << 24));
+#endif
+}
+static inline UINT64_TYPE
+load_64_be (const unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_BE)
+    return GET(64,p);
+#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64)
+    return GETSWAPPED(64,p);
+#else
+    return ((UINT64_TYPE)load_32_be(p) << 32) | load_32_be(p+4);
+#endif
+}
+#if 0 /* don't need little-endian so far */
+static inline void
+store_16_le (unsigned int val, unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_LE)
+    PUT(16,p,val);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
+    PUTSWAPPED(16,p,val);
+#else
+    p[1] = (val >>  8) & 0xff;
+    p[0] = (val      ) & 0xff;
+#endif
+}
+static inline void
+store_32_le (unsigned int val, unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_LE)
+    PUT(32,p,val);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
+    PUTSWAPPED(32,p,val);
+#else
+    p[3] = (val >> 24) & 0xff;
+    p[2] = (val >> 16) & 0xff;
+    p[1] = (val >>  8) & 0xff;
+    p[0] = (val      ) & 0xff;
+#endif
+}
+static inline void
+store_64_le (UINT64_TYPE val, unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_LE)
+    PUT(64,p,val);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
+    PUTSWAPPED(64,p,val);
+#else
+    p[7] = (unsigned char)((val >> 56) & 0xff);
+    p[6] = (unsigned char)((val >> 48) & 0xff);
+    p[5] = (unsigned char)((val >> 40) & 0xff);
+    p[4] = (unsigned char)((val >> 32) & 0xff);
+    p[3] = (unsigned char)((val >> 24) & 0xff);
+    p[2] = (unsigned char)((val >> 16) & 0xff);
+    p[1] = (unsigned char)((val >>  8) & 0xff);
+    p[0] = (unsigned char)((val      ) & 0xff);
+#endif
+}
+static inline unsigned short
+load_16_le (const unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_LE)
+    return GET(16,p);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
+    return GETSWAPPED(16,p);
+#else
+    return (p[0] | (p[1] << 8));
+#endif
+}
+static inline unsigned int
+load_32_le (const unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_LE)
+    return GET(32,p);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
+    return GETSWAPPED(32,p);
+#else
+    return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
+#endif
+}
+static inline UINT64_TYPE
+load_64_le (const unsigned char *p)
+{
+#if defined(__GNUC__) && defined(K5_LE)
+    return GET(64,p);
+#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
+    return GETSWAPPED(64,p);
+#else
+    return ((UINT64_TYPE)load_32_le(p+4) << 32) | load_32_le(p);
+#endif
+}
+#endif
+
+/* Make the interfaces to getpwnam and getpwuid consistent.
+   Model the wrappers on the POSIX thread-safe versions, but
+   use the unsafe system versions if the safe ones don't exist
+   or we can't figure out their interfaces.  */
+
+/* int k5_getpwnam_r(const char *, blah blah) */
+#ifdef HAVE_GETPWNAM_R
+# ifndef GETPWNAM_R_4_ARGS
+/* POSIX */
+#  define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
+	getpwnam_r(NAME,REC,BUF,BUFSIZE,OUT)
+# else
+/* POSIX drafts? */
+#  ifdef GETPWNAM_R_RETURNS_INT
+#   define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT)	\
+	(getpwnam_r(NAME,REC,BUF,BUFSIZE) == 0		\
+	 ? (*(OUT) = REC, 0)				\
+	 : (*(OUT) = NULL, -1))
+#  else
+#   define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT)  \
+	(*(OUT) = getpwnam_r(NAME,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
+#  endif
+# endif
+#else /* no getpwnam_r, or can't figure out #args or return type */
+/* Will get warnings about unused variables.  */
+# define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
+	(*(OUT) = getpwnam(NAME), *(OUT) == NULL ? -1 : 0)
+#endif
+
+/* int k5_getpwuid_r(uid_t, blah blah) */
+#ifdef HAVE_GETPWUID_R
+# ifndef GETPWUID_R_4_ARGS
+/* POSIX */
+#  define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
+	getpwuid_r(UID,REC,BUF,BUFSIZE,OUT)
+# else
+/* POSIX drafts?  Yes, I mean to test GETPWNAM... here.  Less junk to
+   do at configure time.  */
+#  ifdef GETPWNAM_R_RETURNS_INT
+#   define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)	\
+	(getpwuid_r(UID,REC,BUF,BUFSIZE) == 0		\
+	 ? (*(OUT) = REC, 0)				\
+	 : (*(OUT) = NULL, -1))
+#  else
+#   define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)  \
+	(*(OUT) = getpwuid_r(UID,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
+#  endif
+# endif
+#else /* no getpwuid_r, or can't figure out #args or return type */
+/* Will get warnings about unused variables.  */
+# define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
+	(*(OUT) = getpwuid(UID), *(OUT) == NULL ? -1 : 0)
+#endif
+
+
+#endif /* K5_PLATFORM_H */
diff --git a/mechglue/src/include/k5-thread.h b/mechglue/src/include/k5-thread.h
new file mode 100644
index 000000000..7dbcfac6b
--- /dev/null
+++ b/mechglue/src/include/k5-thread.h
@@ -0,0 +1,777 @@
+/*
+ * include/k5-thread.h
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Preliminary thread support.
+ */
+
+#ifndef K5_THREAD_H
+#define K5_THREAD_H
+
+#include "autoconf.h"
+#ifndef KRB5_CALLCONV
+# define KRB5_CALLCONV
+#endif
+#ifndef KRB5_CALLCONV_C
+# define KRB5_CALLCONV_C
+#endif
+
+/* Interface (tentative):
+
+   Mutex support:
+
+   // Between these two, we should be able to do pure compile-time
+   // and pure run-time initialization.
+   //   POSIX:   partial initializer is PTHREAD_MUTEX_INITIALIZER,
+   //            finish does nothing
+   //   Windows: partial initializer is an invalid handle,
+   //            finish does the real initialization work
+   //   debug:   partial initializer sets one magic value,
+   //            finish verifies and sets a new magic value for
+   //              lock/unlock to check
+   k5_mutex_t foo_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+   int k5_mutex_finish_init(k5_mutex_t *);
+   // for dynamic allocation
+   int k5_mutex_init(k5_mutex_t *);
+   // Must work for both kinds of alloc, even if it means adding flags.
+   int k5_mutex_destroy(k5_mutex_t *);
+
+   // As before.
+   int k5_mutex_lock(k5_mutex_t *);
+   int k5_mutex_unlock(k5_mutex_t *);
+
+   In each library, one new function to finish the static mutex init,
+   and any other library-wide initialization that might be desired.
+   On POSIX, this function would be called via the second support
+   function (see below).  On Windows, it would be called at library
+   load time.  These functions, or functions they calls, should be the
+   only places that k5_mutex_finish_init gets called.
+
+   A second function or macro called at various possible "first" entry
+   points which either calls pthread_once on the first function
+   (POSIX), or checks some flag set by the first function (Windows,
+   debug support), and possibly returns an error.  (In the
+   non-threaded case, a simple flag can be used to avoid multiple
+   invocations, and the mutexes don't need run-time initialization
+   anyways.)
+
+   A third function for library termination calls mutex_destroy on
+   each mutex for the library.  This function would be called
+   automatically at library unload time.  If it turns out to be needed
+   at exit time for libraries that don't get unloaded, perhaps we
+   should also use atexit().  Any static mutexes should be cleaned up
+   with k5_mutex_destroy here.
+
+   How does that second support function invoke the first support
+   function only once?  Through something modelled on pthread_once
+   that I haven't written up yet.  Probably:
+
+   k5_once_t foo_once = K5_ONCE_INIT;
+   k5_once(k5_once_t *, void (*)(void));
+
+   For POSIX: Map onto pthread_once facility.
+   For non-threaded case: A simple flag.
+   For Windows: Not needed; library init code takes care of it.
+
+   XXX: A general k5_once mechanism isn't possible for Windows,
+   without faking it through named mutexes or mutexes initialized at
+   startup.  I was only using it in one place outside these headers,
+   so I'm dropping the general scheme.  Eventually the existing uses
+   in k5-thread.h and k5-platform.h will be converted to pthread_once
+   or static variables.
+
+
+   Thread-specific data:
+
+   // TSD keys are limited in number in gssapi/krb5/com_err; enumerate
+   // them all.  This allows support code init to allocate the
+   // necessary storage for pointers all at once, and avoids any
+   // possible error in key creation.
+   enum { ... } k5_key_t;
+   // Register destructor function.  Called in library init code.
+   int k5_key_register(k5_key_t, void (*destructor)(void *));
+   // Returns NULL or data.
+   void *k5_getspecific(k5_key_t);
+   // Returns error if key out of bounds, or the pointer table can't
+   // be allocated.  A call to k5_key_register must have happened first.
+   // This may trigger the calling of pthread_setspecific on POSIX.
+   int k5_setspecific(k5_key_t, void *);
+   // Called in library termination code.
+   // Trashes data in all threads, calling the registered destructor
+   // (but calling it from the current thread).
+   int k5_key_delete(k5_key_t);
+
+   For the non-threaded version, the support code will have a static
+   array indexed by k5_key_t values, and get/setspecific simply access
+   the array elements.
+
+   The TSD destructor table is global state, protected by a mutex if
+   threads are enabled.
+
+   Debug support: Not much.  Might check if k5_key_register has been
+   called and abort if not.
+
+
+   Any actual external symbols will use the krb5int_ prefix.  The k5_
+   names will be simple macros or inline functions to rename the
+   external symbols, or slightly more complex ones to expand the
+   implementation inline (e.g., map to POSIX versions and/or debug
+   code using __FILE__ and the like).
+
+
+   More to be added, perhaps.  */
+
+#define DEBUG_THREADS
+#define DEBUG_THREADS_LOC
+#undef DEBUG_THREADS_SLOW /* debugging stuff that'll slow things down? */
+#undef DEBUG_THREADS_STATS
+
+#include <assert.h>
+
+/* For tracking locations, of (e.g.) last lock or unlock of mutex.  */
+#ifdef DEBUG_THREADS_LOC
+typedef struct {
+    const char *filename;
+    int lineno;
+} k5_debug_loc;
+#define K5_DEBUG_LOC_INIT	{ __FILE__, __LINE__ }
+#if __GNUC__ >= 2
+#define K5_DEBUG_LOC		(__extension__ (k5_debug_loc)K5_DEBUG_LOC_INIT)
+#else
+static inline k5_debug_loc k5_debug_make_loc(const char *file, int line)
+{
+    k5_debug_loc l;
+    l.filename = file;
+    l.lineno = line;
+    return l;
+}
+#define K5_DEBUG_LOC		(k5_debug_make_loc(__FILE__,__LINE__))
+#endif
+#else /* ! DEBUG_THREADS_LOC */
+typedef char k5_debug_loc;
+#define K5_DEBUG_LOC_INIT	0
+#define K5_DEBUG_LOC		0
+#endif
+
+#define k5_debug_update_loc(L)	((L) = K5_DEBUG_LOC)
+
+
+
+/* Statistics gathering:
+
+   Currently incomplete, don't try enabling it.
+
+   Eventually: Report number of times locked, total and standard
+   deviation of the time the lock was held, total and std dev time
+   spent waiting for the lock.  "Report" will probably mean "write a
+   line to a file if a magic environment variable is set."  */
+
+#ifdef DEBUG_THREADS_STATS
+
+#if HAVE_TIME_H && (!defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME))
+# include <time.h>
+#endif
+#if HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+/* for memset */
+#include <string.h>
+/* for uint64_t */
+#include <inttypes.h>
+typedef uint64_t k5_debug_timediff_t; /* or long double */
+typedef struct timeval k5_debug_time_t;
+static inline k5_debug_timediff_t
+timediff(k5_debug_time_t t2, k5_debug_time_t t1)
+{
+    return (t2.tv_sec - t1.tv_sec) * 1000000 + (t2.tv_usec - t1.tv_usec);
+}
+static inline k5_debug_time_t get_current_time(void)
+{
+    struct timeval tv;
+    if (gettimeofday(&tv,0) < 0) { tv.tv_sec = tv.tv_usec = 0; }
+    return tv;
+}
+struct k5_timediff_stats {
+    k5_debug_timediff_t valmin, valmax, valsum, valsqsum;
+};
+typedef struct {
+    int count;
+    k5_debug_time_t time_acquired, time_created;
+    struct k5_timediff_stats lockwait, lockheld;
+} k5_debug_mutex_stats;
+#define k5_mutex_init_stats(S)					\
+	(memset((S), 0, sizeof(k5_debug_mutex_stats)),	\
+	 (S)->time_created = get_current_time(),		\
+	 0)
+#define k5_mutex_finish_init_stats(S) 	(0)
+#define K5_MUTEX_STATS_INIT	{ 0, {0}, {0}, {0}, {0} }
+typedef k5_debug_time_t k5_mutex_stats_tmp;
+#define k5_mutex_stats_start()	get_current_time()
+void KRB5_CALLCONV krb5int_mutex_lock_update_stats(k5_debug_mutex_stats *m,
+						   k5_mutex_stats_tmp start);
+void KRB5_CALLCONV krb5int_mutex_unlock_update_stats(k5_debug_mutex_stats *m);
+#define k5_mutex_lock_update_stats	krb5int_mutex_lock_update_stats
+#define k5_mutex_unlock_update_stats	krb5int_mutex_unlock_update_stats
+void KRB5_CALLCONV krb5int_mutex_report_stats(/* k5_mutex_t *m */);
+
+#else
+
+typedef char k5_debug_mutex_stats;
+#define k5_mutex_init_stats(S)		(*(S) = 's', 0)
+#define k5_mutex_finish_init_stats(S)	(0)
+#define K5_MUTEX_STATS_INIT		's'
+typedef int k5_mutex_stats_tmp;
+#define k5_mutex_stats_start()		(0)
+#ifdef __GNUC__
+static inline void
+k5_mutex_lock_update_stats(k5_debug_mutex_stats *m, k5_mutex_stats_tmp t)
+{
+}
+#else
+# define k5_mutex_lock_update_stats(M,S)	(S)
+#endif
+#define k5_mutex_unlock_update_stats(M)	(*(M) = 's')
+
+/* If statistics tracking isn't enabled, these functions don't actually
+   do anything.  Declare anyways so we can do type checking etc.  */
+void KRB5_CALLCONV krb5int_mutex_lock_update_stats(k5_debug_mutex_stats *m,
+						   k5_mutex_stats_tmp start);
+void KRB5_CALLCONV krb5int_mutex_unlock_update_stats(k5_debug_mutex_stats *m);
+void KRB5_CALLCONV krb5int_mutex_report_stats(/* k5_mutex_t *m */);
+
+#define krb5int_mutex_report_stats(M)	((M)->stats = 'd')
+
+#endif
+
+
+
+/* Define the OS mutex bit.  */
+
+/* First, if we're not actually doing multiple threads, do we
+   want the debug support or not?  */
+
+#ifdef DEBUG_THREADS
+
+enum k5_mutex_init_states {
+    K5_MUTEX_DEBUG_PARTLY_INITIALIZED = 0x12,
+    K5_MUTEX_DEBUG_INITIALIZED,
+    K5_MUTEX_DEBUG_DESTROYED
+};
+enum k5_mutex_flag_states {
+    K5_MUTEX_DEBUG_UNLOCKED = 0x23,
+    K5_MUTEX_DEBUG_LOCKED
+};
+
+typedef struct {
+    enum k5_mutex_init_states initialized;
+    enum k5_mutex_flag_states locked;
+} k5_os_nothread_mutex;
+
+# define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER \
+	{ K5_MUTEX_DEBUG_PARTLY_INITIALIZED, K5_MUTEX_DEBUG_UNLOCKED }
+
+# define k5_os_nothread_mutex_finish_init(M)				\
+	(assert((M)->initialized != K5_MUTEX_DEBUG_INITIALIZED),	\
+	 assert((M)->initialized == K5_MUTEX_DEBUG_PARTLY_INITIALIZED),	\
+	 assert((M)->locked == K5_MUTEX_DEBUG_UNLOCKED),		\
+	 (M)->initialized = K5_MUTEX_DEBUG_INITIALIZED, 0)
+# define k5_os_nothread_mutex_init(M)			\
+	((M)->initialized = K5_MUTEX_DEBUG_INITIALIZED,	\
+	 (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, 0)
+# define k5_os_nothread_mutex_destroy(M)				\
+	(assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),	\
+	 (M)->initialized = K5_MUTEX_DEBUG_DESTROYED, 0)
+
+# define k5_os_nothread_mutex_lock(M)			\
+	(k5_os_nothread_mutex_assert_unlocked(M),	\
+	 (M)->locked = K5_MUTEX_DEBUG_LOCKED, 0)
+# define k5_os_nothread_mutex_unlock(M)			\
+	(k5_os_nothread_mutex_assert_locked(M),		\
+	 (M)->locked = K5_MUTEX_DEBUG_UNLOCKED, 0)
+
+# define k5_os_nothread_mutex_assert_locked(M)				\
+	(assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),	\
+	 assert((M)->locked != K5_MUTEX_DEBUG_UNLOCKED),		\
+	 assert((M)->locked == K5_MUTEX_DEBUG_LOCKED))
+# define k5_os_nothread_mutex_assert_unlocked(M)			\
+	(assert((M)->initialized == K5_MUTEX_DEBUG_INITIALIZED),	\
+	 assert((M)->locked != K5_MUTEX_DEBUG_LOCKED),			\
+	 assert((M)->locked == K5_MUTEX_DEBUG_UNLOCKED))
+
+#else /* threads disabled and not debugging */
+
+typedef char k5_os_nothread_mutex;
+# define K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER	0
+/* Empty inline functions avoid the "statement with no effect"
+   warnings, and do better type-checking than functions that don't use
+   their arguments.  */
+static inline int k5_os_nothread_mutex_finish_init(k5_os_nothread_mutex *m) {
+    return 0;
+}
+static inline int k5_os_nothread_mutex_init(k5_os_nothread_mutex *m) {
+    return 0;
+}
+static inline int k5_os_nothread_mutex_destroy(k5_os_nothread_mutex *m) {
+    return 0;
+}
+static inline int k5_os_nothread_mutex_lock(k5_os_nothread_mutex *m) {
+    return 0;
+}
+static inline int k5_os_nothread_mutex_unlock(k5_os_nothread_mutex *m) {
+    return 0;
+}
+# define k5_os_nothread_mutex_assert_locked(M)		((void)0)
+# define k5_os_nothread_mutex_assert_unlocked(M)	((void)0)
+
+#endif
+
+/* Values:
+   2 - function has not been run
+   3 - function has been run
+   4 - function is being run -- deadlock detected */
+typedef unsigned char k5_os_nothread_once_t;
+# define K5_OS_NOTHREAD_ONCE_INIT	2
+# define k5_os_nothread_once(O,F)					\
+	(*(O) == 3 ? 0							\
+	 : *(O) == 2 ? (*(O) = 4, (F)(), *(O) = 3, 0)			\
+	 : (assert(*(O) != 4), assert(*(O) == 2 || *(O) == 3), 0))
+
+
+
+#ifndef ENABLE_THREADS
+
+typedef k5_os_nothread_mutex k5_os_mutex;
+# define K5_OS_MUTEX_PARTIAL_INITIALIZER	\
+		K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER
+# define k5_os_mutex_finish_init	k5_os_nothread_mutex_finish_init
+# define k5_os_mutex_init		k5_os_nothread_mutex_init
+# define k5_os_mutex_destroy		k5_os_nothread_mutex_destroy
+# define k5_os_mutex_lock		k5_os_nothread_mutex_lock
+# define k5_os_mutex_unlock		k5_os_nothread_mutex_unlock
+# define k5_os_mutex_assert_locked	k5_os_nothread_mutex_assert_locked
+# define k5_os_mutex_assert_unlocked	k5_os_nothread_mutex_assert_unlocked
+
+# define k5_once_t			k5_os_nothread_once_t
+# define K5_ONCE_INIT			K5_OS_NOTHREAD_ONCE_INIT
+# define k5_once			k5_os_nothread_once
+
+#elif HAVE_PTHREAD
+
+# include <pthread.h>
+
+/* Weak reference support, etc.
+
+   Linux: Stub mutex routines exist, but pthread_once does not.
+
+   Solaris: In libc there's a pthread_once that doesn't seem
+   to do anything.  Bleah.  But pthread_mutexattr_setrobust_np
+   is defined only in libpthread.
+
+   IRIX 6.5 stub pthread support in libc is really annoying.  The
+   pthread_mutex_lock function returns ENOSYS for a program not linked
+   against -lpthread.  No link-time failure, no weak symbols, etc.
+   The C library doesn't provide pthread_once; we can use weak
+   reference support for that.
+
+   If weak references are not available, then for now, we assume that
+   the pthread support routines will always be available -- either the
+   real thing, or functional stubs that merely prohibit creating
+   threads.
+
+   If we find a platform with non-functional stubs and no weak
+   references, we may have to resort to some hack like dlsym on the
+   symbol tables of the current process.  */
+#ifdef HAVE_PRAGMA_WEAK_REF
+# pragma weak pthread_once
+# pragma weak pthread_mutex_lock
+# pragma weak pthread_mutex_unlock
+# pragma weak pthread_mutex_destroy
+# pragma weak pthread_mutex_init
+# pragma weak pthread_self
+# pragma weak pthread_equal
+# ifdef HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB
+#  pragma weak pthread_mutexattr_setrobust_np
+# endif
+extern int krb5int_pthread_loaded(void);
+# define K5_PTHREADS_LOADED	(krb5int_pthread_loaded())
+#else
+/* no pragma weak support */
+# define K5_PTHREADS_LOADED	(1)
+#endif
+
+#if defined(__mips) && defined(__sgi) && (defined(_SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__))
+/* IRIX 6.5 stub pthread support in libc is really annoying.  The
+   pthread_mutex_lock function returns ENOSYS for a program not linked
+   against -lpthread.  No link-time failure, no weak reference tests,
+   etc.
+
+   The C library doesn't provide pthread_once; we can use weak
+   reference support for that.  */
+# ifndef HAVE_PRAGMA_WEAK_REF
+#  if defined(__GNUC__) && __GNUC__ < 3
+#   error "Please update to a newer gcc with weak symbol support, or switch to native cc, reconfigure and recompile."
+#  else
+#   error "Weak reference support is required"
+#  endif
+# endif
+#endif
+
+#ifdef HAVE_PRAGMA_WEAK_REF
+# define USE_PTHREAD_LOCK_ONLY_IF_LOADED
+#endif
+
+#ifdef HAVE_PRAGMA_WEAK_REF
+/* Can't rely on useful stubs -- see above regarding Solaris.  */
+typedef struct {
+    pthread_once_t o;
+    k5_os_nothread_once_t n;
+} k5_once_t;
+# define K5_ONCE_INIT	{ PTHREAD_ONCE_INIT, K5_OS_NOTHREAD_ONCE_INIT }
+# define k5_once(O,F)	(K5_PTHREADS_LOADED			\
+			 ? pthread_once(&(O)->o,F)		\
+			 : k5_os_nothread_once(&(O)->n,F))
+#else
+typedef pthread_once_t k5_once_t;
+# define K5_ONCE_INIT	PTHREAD_ONCE_INIT
+# define k5_once	pthread_once
+#endif
+
+typedef struct {
+    pthread_mutex_t p;
+#ifdef DEBUG_THREADS
+    pthread_t owner;
+#endif
+#ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED
+    k5_os_nothread_mutex n;
+#endif
+} k5_os_mutex;
+
+#ifdef DEBUG_THREADS
+# ifdef __GNUC__
+#  define k5_pthread_mutex_lock(M)			\
+	({						\
+	    k5_os_mutex *_m2 = (M);			\
+	    int _r2 = pthread_mutex_lock(&_m2->p);	\
+	    if (_r2 == 0) _m2->owner = pthread_self();	\
+	    _r2;					\
+	})
+# else
+static inline int
+k5_pthread_mutex_lock(k5_os_mutex *m)
+{
+    int r = pthread_mutex_lock(&m->p);
+    if (r)
+	return r;
+    m->owner = pthread_self();
+    return 0;
+}
+# endif
+# define k5_pthread_assert_locked(M)				\
+	(K5_PTHREADS_LOADED					\
+	 ? assert(pthread_equal((M)->owner, pthread_self()))	\
+	 : (void)0)
+# define k5_pthread_mutex_unlock(M)	\
+	(k5_pthread_assert_locked(M),	\
+	 (M)->owner = (pthread_t) 0,	\
+	 pthread_mutex_unlock(&(M)->p))
+#else
+# define k5_pthread_mutex_lock(M) pthread_mutex_lock(&(M)->p)
+static inline void k5_pthread_assert_locked(k5_os_mutex *m) { }
+# define k5_pthread_mutex_unlock(M) pthread_mutex_unlock(&(M)->p)
+#endif
+
+/* Define as functions to:
+   (1) eliminate "statement with no effect" warnings for "0"
+   (2) encourage type-checking in calling code  */
+
+static inline void k5_pthread_assert_unlocked(pthread_mutex_t *m) { }
+
+#if defined(DEBUG_THREADS_SLOW) && HAVE_SCHED_H && (HAVE_SCHED_YIELD || HAVE_PRAGMA_WEAK_REF)
+# include <sched.h>
+# if !HAVE_SCHED_YIELD
+#  pragma weak sched_yield
+#  define MAYBE_SCHED_YIELD()	((void)((&sched_yield != NULL) ? sched_yield() : 0))
+# else
+#  define MAYBE_SCHED_YIELD()	((void)sched_yield())
+# endif
+#else
+# define MAYBE_SCHED_YIELD()	((void)0)
+#endif
+
+/* It may not be obvious why this function is desirable.
+
+   I want to call pthread_mutex_lock, then sched_yield, then look at
+   the return code from pthread_mutex_lock.  That can't be implemented
+   in a macro without a temporary variable, or GNU C extensions.
+
+   There used to be an inline function which did it, with both
+   functions called from the inline function.  But that messes with
+   the debug information on a lot of configurations, and you can't
+   tell where the inline function was called from.  (Typically, gdb
+   gives you the name of the function from which the inline function
+   was called, and a line number within the inline function itself.)
+
+   With this auxiliary function, pthread_mutex_lock can be called at
+   the invoking site via a macro; once it returns, the inline function
+   is called (with messed-up line-number info for gdb hopefully
+   localized to just that call).  */
+#ifdef __GNUC__
+#define return_after_yield(R)			\
+	__extension__ ({			\
+	    int _r = (R);			\
+	    MAYBE_SCHED_YIELD();		\
+	    _r;					\
+	})
+#else
+static inline int return_after_yield(int r)
+{
+    MAYBE_SCHED_YIELD();
+    return r;
+}
+#endif
+
+#ifdef USE_PTHREAD_LOCK_ONLY_IF_LOADED
+
+# if defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) && defined(DEBUG_THREADS)
+#  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
+	{ PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, (pthread_t) 0, \
+	  K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
+# elif defined(DEBUG_THREADS)
+#  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
+	{ PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, \
+	  K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
+# else
+#  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
+	{ PTHREAD_MUTEX_INITIALIZER, K5_OS_NOTHREAD_MUTEX_PARTIAL_INITIALIZER }
+# endif
+
+# define k5_os_mutex_finish_init(M)		\
+	k5_os_nothread_mutex_finish_init(&(M)->n)
+# define k5_os_mutex_init(M)			\
+	(k5_os_nothread_mutex_init(&(M)->n),	\
+	 (K5_PTHREADS_LOADED			\
+	  ? pthread_mutex_init(&(M)->p, 0)	\
+	  : 0))
+# define k5_os_mutex_destroy(M)			\
+	(k5_os_nothread_mutex_destroy(&(M)->n),	\
+	 (K5_PTHREADS_LOADED			\
+	  ? pthread_mutex_destroy(&(M)->p)	\
+	  : 0))
+
+# define k5_os_mutex_lock(M)						\
+	return_after_yield(K5_PTHREADS_LOADED				\
+			   ? k5_pthread_mutex_lock(M)			\
+			   : k5_os_nothread_mutex_lock(&(M)->n))
+# define k5_os_mutex_unlock(M)				\
+	(MAYBE_SCHED_YIELD(),				\
+	 (K5_PTHREADS_LOADED				\
+	  ? k5_pthread_mutex_unlock(M)			\
+	  : k5_os_nothread_mutex_unlock(&(M)->n)))
+
+# define k5_os_mutex_assert_unlocked(M)			\
+	(K5_PTHREADS_LOADED				\
+	 ? k5_pthread_assert_unlocked(&(M)->p)		\
+	 : k5_os_nothread_mutex_assert_unlocked(&(M)->n))
+# define k5_os_mutex_assert_locked(M)			\
+	(K5_PTHREADS_LOADED				\
+	 ? k5_pthread_assert_locked(M)			\
+	 : k5_os_nothread_mutex_assert_locked(&(M)->n))
+
+#else
+
+# ifdef DEBUG_THREADS
+#  ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+#   define K5_OS_MUTEX_PARTIAL_INITIALIZER \
+	{ PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, (pthread_t) 0 }
+#  else
+#   define K5_OS_MUTEX_PARTIAL_INITIALIZER \
+	{ PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0 }
+#  endif
+# else
+#  define K5_OS_MUTEX_PARTIAL_INITIALIZER \
+	{ PTHREAD_MUTEX_INITIALIZER }
+# endif
+
+static inline int k5_os_mutex_finish_init(k5_os_mutex *m) { return 0; }
+# define k5_os_mutex_init(M)		pthread_mutex_init(&(M)->p, 0)
+# define k5_os_mutex_destroy(M)		pthread_mutex_destroy(&(M)->p)
+# define k5_os_mutex_lock(M)	return_after_yield(k5_pthread_mutex_lock(M))
+# define k5_os_mutex_unlock(M)		(MAYBE_SCHED_YIELD(),k5_pthread_mutex_unlock(M))
+
+# define k5_os_mutex_assert_unlocked(M)	k5_pthread_assert_unlocked(&(M)->p)
+# define k5_os_mutex_assert_locked(M)	k5_pthread_assert_locked(M)
+
+#endif /* is pthreads always available? */
+
+#elif defined _WIN32
+
+typedef struct {
+    HANDLE h;
+    int is_locked;
+} k5_os_mutex;
+
+# define K5_OS_MUTEX_PARTIAL_INITIALIZER { INVALID_HANDLE_VALUE, 0 }
+
+# define k5_os_mutex_finish_init(M)					 \
+	(assert((M)->h == INVALID_HANDLE_VALUE),			 \
+	 ((M)->h = CreateMutex(NULL, FALSE, NULL)) ? 0 : GetLastError())
+# define k5_os_mutex_init(M)						 \
+	((M)->is_locked = 0,						 \
+	 ((M)->h = CreateMutex(NULL, FALSE, NULL)) ? 0 : GetLastError())
+# define k5_os_mutex_destroy(M)		\
+	(CloseHandle((M)->h) ? ((M)->h = 0, 0) : GetLastError())
+
+static inline int k5_os_mutex_lock(k5_os_mutex *m)
+{
+    DWORD res;
+    res = WaitForSingleObject(m->h, INFINITE);
+    if (res == WAIT_FAILED)
+	return GetLastError();
+    /* Eventually these should be turned into some reasonable error
+       code.  */
+    assert(res != WAIT_TIMEOUT);
+    assert(res != WAIT_ABANDONED);
+    assert(res == WAIT_OBJECT_0);
+    /* Avoid locking twice.  */
+    assert(m->is_locked == 0);
+    m->is_locked = 1;
+    return 0;
+}
+
+# define k5_os_mutex_unlock(M)				\
+	(assert((M)->is_locked == 1),			\
+	 (M)->is_locked = 0,				\
+	 ReleaseMutex((M)->h) ? 0 : GetLastError())
+
+# define k5_os_mutex_assert_unlocked(M)	((void)0)
+# define k5_os_mutex_assert_locked(M)	((void)0)
+
+#else
+
+# error "Thread support enabled, but thread system unknown"
+
+#endif
+
+
+
+
+typedef struct {
+    k5_debug_loc loc_last, loc_created;
+    k5_os_mutex os;
+    k5_debug_mutex_stats stats;
+} k5_mutex_t;
+#define K5_MUTEX_PARTIAL_INITIALIZER		\
+	{ K5_DEBUG_LOC_INIT, K5_DEBUG_LOC_INIT,	\
+	  K5_OS_MUTEX_PARTIAL_INITIALIZER, K5_MUTEX_STATS_INIT }
+static inline int k5_mutex_init_1(k5_mutex_t *m, k5_debug_loc l)
+{
+    int err = k5_os_mutex_init(&m->os);
+    if (err) return err;
+    m->loc_created = m->loc_last = l;
+    err = k5_mutex_init_stats(&m->stats);
+    assert(err == 0);
+    return 0;
+}
+#define k5_mutex_init(M)	k5_mutex_init_1((M), K5_DEBUG_LOC)
+static inline int k5_mutex_finish_init_1(k5_mutex_t *m, k5_debug_loc l)
+{
+    int err = k5_os_mutex_finish_init(&m->os);
+    if (err) return err;
+    m->loc_created = m->loc_last = l;
+    err = k5_mutex_finish_init_stats(&m->stats);
+    assert(err == 0);
+    return 0;
+}
+#define k5_mutex_finish_init(M)	k5_mutex_finish_init_1((M), K5_DEBUG_LOC)
+#define k5_mutex_destroy(M)			\
+	(k5_os_mutex_assert_unlocked(&(M)->os),	\
+	 krb5int_mutex_report_stats(M),		\
+	 k5_mutex_lock(M), (M)->loc_last = K5_DEBUG_LOC, k5_mutex_unlock(M), \
+	 k5_os_mutex_destroy(&(M)->os))
+#ifdef __GNUC__
+#define k5_mutex_lock(M)						 \
+	__extension__ ({						 \
+	    int _err = 0;						 \
+	    k5_mutex_stats_tmp _stats = k5_mutex_stats_start();		 \
+	    k5_mutex_t *_m = (M);					 \
+	    _err = k5_os_mutex_lock(&_m->os);				 \
+	    if (_err == 0) _m->loc_last = K5_DEBUG_LOC;			 \
+	    if (_err == 0) k5_mutex_lock_update_stats(&_m->stats, _stats); \
+	    _err;							 \
+	})
+#else
+static inline int k5_mutex_lock_1(k5_mutex_t *m, k5_debug_loc l)
+{
+    int err = 0;
+    k5_mutex_stats_tmp stats = k5_mutex_stats_start();
+    err = k5_os_mutex_lock(&m->os);
+    if (err)
+	return err;
+    m->loc_last = l;
+    k5_mutex_lock_update_stats(&m->stats, stats);
+    return err;
+}
+#define k5_mutex_lock(M)	k5_mutex_lock_1(M, K5_DEBUG_LOC)
+#endif
+#define k5_mutex_unlock(M)				\
+	(k5_mutex_assert_locked(M),			\
+	 k5_mutex_unlock_update_stats(&(M)->stats),	\
+	 (M)->loc_last = K5_DEBUG_LOC,			\
+	 k5_os_mutex_unlock(&(M)->os))
+
+#define k5_mutex_assert_locked(M)	k5_os_mutex_assert_locked(&(M)->os)
+#define k5_mutex_assert_unlocked(M)	k5_os_mutex_assert_unlocked(&(M)->os)
+
+#define k5_assert_locked	k5_mutex_assert_locked
+#define k5_assert_unlocked	k5_mutex_assert_unlocked
+
+
+/* Thread-specific data; implemented in a support file, because we'll
+   need to keep track of some global data for cleanup purposes.
+
+   Note that the callback function type is such that the C library
+   routine free() is a valid callback.  */
+typedef enum {
+    K5_KEY_COM_ERR,
+    K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME,
+    K5_KEY_GSS_KRB5_CCACHE_NAME,
+    K5_KEY_KDB_ERR_HANDLER,
+    K5_KEY_KADM_CLNT_ERR_HANDLER,
+    K5_KEY_MAX
+} k5_key_t;
+/* rename shorthand symbols for export */
+#define k5_key_register	krb5int_key_register
+#define k5_getspecific	krb5int_getspecific
+#define k5_setspecific	krb5int_setspecific
+#define k5_key_delete	krb5int_key_delete
+extern int k5_key_register(k5_key_t, void (*)(void *));
+extern void *k5_getspecific(k5_key_t);
+extern int k5_setspecific(k5_key_t, void *);
+extern int k5_key_delete(k5_key_t);
+
+#endif /* multiple inclusion? */
diff --git a/mechglue/src/include/k5-util.h b/mechglue/src/include/k5-util.h
new file mode 100644
index 000000000..4255c8f65
--- /dev/null
+++ b/mechglue/src/include/k5-util.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 1989-1998,2002 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
+
+/*
+ * "internal" utility functions used by various applications.
+ * They live in libkrb5util.
+ */
+
+#include "krb5/autoconf.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <errno.h>
+
+#ifndef krb5_seteuid
+
+#if defined(HAVE_SETEUID)
+#  define krb5_seteuid(EUID)	(seteuid((uid_t)(EUID)))
+#elif defined(HAVE_SETRESUID)
+#  define krb5_seteuid(EUID)	setresuid(getuid(), (uid_t)(EUID), geteuid())
+#elif defined(HAVE_SETREUID)
+#  define krb5_seteuid(EUID)	setreuid(geteuid(), (uid_t)(EUID))
+#else
+   /* You need to add a case to deal with this operating system.*/
+#  define krb5_seteuid(EUID)	(errno = EPERM, -1)
+#endif
+
+#ifdef HAVE_SETEGID
+#  define krb5_setegid(EGID)	(setegid((gid_t)(EGID)))
+#elif defined(HAVE_SETRESGID)
+#  define krb5_setegid(EGID)	(setresgid(getgid(), (gid_t)(EGID), getegid()))
+#elif defined(HAVE_SETREGID)
+#  define krb5_setegid(EGID)	(setregid(getegid(), (gid_t)(EGID)))
+#else
+   /* You need to add a case to deal with this operating system.*/
+#  define krb5_setegid(EGID)	(errno = EPERM, -1)
+#endif
+
+#endif
diff --git a/mechglue/src/include/kerberosIV/.Sanitize b/mechglue/src/include/kerberosIV/.Sanitize
new file mode 100644
index 000000000..6933b4031
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/.Sanitize
@@ -0,0 +1,56 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+addr_comp.h
+admin_server.h
+configure
+configure.in
+des.h
+des_conf.h
+highc.h
+kadm.h
+kdc.h
+klog.h
+kparse.h
+krb.h
+krb4-proto.h
+krbports.h
+krb_conf.h
+krb_db.h
+krb_err.h
+lsb_addr_cmp.h
+mit-copyright.h
+passwd_server.h
+principal.h
+prot.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/include/kerberosIV/ChangeLog b/mechglue/src/include/kerberosIV/ChangeLog
new file mode 100644
index 000000000..9a0cd7764
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/ChangeLog
@@ -0,0 +1,567 @@
+2005-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (thisconfigdir, mydir): Updated for configure
+	change.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.h, krb.h: Don't test for macintosh or __MWERKS__.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2003-09-23  Jeffrey Altman  <jaltman@mit.edu>
+
+	* krb.h: Modify the declaration of the CREDENTIALS structure to
+	support the additional address field used on Windows.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+    * des.h, krb.h: Removed deprecated KfM functions.  They will be 
+    exported but not in the headers to discourage new callers. Removed 
+    enumsalwaysint because there are no typed enums in this header.
+    
+    * des.h: Made afs_string_to_key public on all platforms. (OpenAFS 
+    folk think this is okay.)
+    
+    * krb.h, prot.h: Made KRB_TICKET_GRANTING_TICKET public and 
+    removed non-public TICKET_GRANTING_TICKET because this macro is 
+    used in lots of places by KfM, including some clients. Made 
+    krb__get_srvtabname non-private because it is used by KEYFILE.
+    
+    * kadm.h: moved definition of MAXHOSTNAMELEN below the inclusion
+    of other headers so that if it gets defined by those other 
+    headers or headers they include, we don't get a redefinition
+    error (this happens on Mac OS X). 
+
+2003-02-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (krb_err.h, kadm_err.h): Rebuild by going to
+	lib/krb4 and building "includes".
+	(clean-unix): Don't need to delete copies of .et files any more.
+
+2003-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* krb.h: Add KRB_PRIVATE conditionals around lots of stuff that
+	doesn't belong in krb.h, and historically hasn't been in krb.h on
+	KfM.  For now, everything except MacOS will define KRB_PRIVATE to
+	1.
+
+2003-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* krb.h: Declare krb_err_txt differently on Mac.
+
+2003-01-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-unix, install): Build and install kadm_err.h.
+	(install-headers-unix): Install both generated header files.
+
+2003-01-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (krb_err.et, kadm_err.et): New intermediate targets;
+	copy files from lib/krb4.
+	(krb_err.h, kadm_err.h): Delete actions, use patterns in pre.in.
+	(clean-unix): Delete these generated files.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* krb.h: Change _WINDOWS->_WIN32.  Add symbols for
+	RealmsConfig-glue.c.  Remove explicit errno declaration.  Fix some
+	prototypes of functions in RealmsConfig-glue.c to take const char*
+	for realm.  Update prorotypes of functions that may take a ticket
+	file name to take const char*.  Collect prototypes of FSp-glue.c
+	functions together.
+
+2002-12-04  Tom Yu  <tlyu@mit.edu>
+
+	* des.h: Move explicit definition of _WINDOWS to precede
+	conditionalized inclusion of win-mac.h.
+
+	* kadm.h: Include port-sockets.h, not netinet/in.h, for Windows
+	portability.
+
+2002-12-02  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (kadm_err.h): Build here.
+
+2002-11-26  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (KRB4_HEADERS): Don't install kadm.h anymore.
+
+	* des.h: Put "#" characters in first column.  Do the
+	KRBINT_BEGIN_DECLS hack to make emacs happy.  Shuffle limits.h
+	inclusion to be outside C++ and Mac alignment magic.
+
+	* kadm.h: Remove some spurious prototypes.  Rename a bunch of
+	internal kadm_stream stuff to avoid stomping on namespace.  Add
+	prototypes for some client-side kadm stuff.
+
+	* krb.h: Do Mac CFM magic.  Do C++ mangling protection.  Do Mac
+	alignment magic.  Move inclusions outside of C++ mangling
+	protection and Mac magic.  Add KRB5_CALLCONV to a few functions
+	that KfM's krb.h exports.  Merge the *_in_tkt_*_creds,
+	mk_req_creds, and rd_req_int functions from KfM.  Add prototypes
+	for some KfM-specific things yet to be merged.
+
+	* prot.h: Don't include krb_conf.h anymore.  Twiddle the int
+	encoding/decoding macros a little.
+
+	* des_conf.h:
+	* highc.h:
+	* krb_conf.h:
+	* passwd_server.h:
+	* principal.h: Remove, since they're obsolete.
+
+2002-10-07  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in: Support install-headers
+
+2002-09-26  Tom Yu  <tlyu@mit.edu>
+
+	* des.h: Some initial work for KfM integration.  Clean up
+	DES_INT32 selection.  Set up for inclusion by
+	lib/crypto/des/des_int.h, which will define a special macro to
+	prevent the krb4-specific stuff from being declared.
+
+	* krb.h: Initial work for KfM integration.  Fix up KRB4_32, and
+	add KRB_INT32, KRB_UINT32.  Change all error code macros to be
+	offsets from krb_err.et symbols.
+
+2002-09-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb.h: Add extern "C" markers in case a C++ compiler is used.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb.h: Don't include port-sockets.h.  Don't check for
+	NEED_TIME_H, just don't include time.h and sys/time.h on
+	non-Windows platforms.
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb.h: Do not include winsock.h for Win32, since we already use
+	port-sockets.h.  This avoids winsock.h vs winsock2.h issues.
+
+2002-03-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* lsb_addr_cmp.h (krb4int_address_less): Declare.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.h (KRB5_EXPORTVAR): Don't define.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.h, krb.h: Don't use or define KRB5_DLLIMP, GSS_DLLIMP.  Drop
+	NEAR, FAR support.
+
+2001-06-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* klog.h: Flush out prototype for klog().
+
+2001-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* prot.h: Flush out prototypes for create_auth_reply(), pkt_cipher().
+
+2001-06-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb.h: Don't use "options" and "user" as argument names.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb.h: Add prototype for krb__get_srvtabname() which is invoked
+	in place of KEYFILE.
+	Add prototypes for krb_kntoln(), k_isinst(), k_isname(), k_isrealm().
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb.h: Add prototype for krb_sendauth().
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb.h: Add "internal" prototypes cr_err_reply(), create_ciph(),
+	krb_create_ticket(), krb5_cr_tkt_krb5(), krb_set_key_krb5().
+
+2001-05-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* des.h: Do not use "encrypt" as an argument.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb.h: Make struct sockaddr_in declaration unconditional.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.h (des_pcbc_encrypt, des_quad_cksum, des_cbc_cksum,
+	des_cbc_encrypt, des_ecb_encrypt): Use const for some input args.
+
+	* krb.h (krb_get_admhst, krb_get_krbhst, krb_get_lrealm): Don't
+	use "index" as argument name.
+
+	* kparse.h: Don't use PROTOTYPE macro.
+
+	* des.h (des_cblock, des_key_schedule): Separate definitions into
+	a block with a comment indicating lib/crypto/des/des_int.h needs
+	to be kept in sync.  Use macro KRB5INT_DES_TYPES_DEFINED to avoid
+	duplication.
+
+2001-04-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.h: Include stdio.h.
+	(PROTOTYPE): Delete macro.  Make all function prototypes
+	unconditional.
+	(des_ecb_encrypt, des_fixup_key_parity, des_check_key_parity,
+	des_new_random_key, des_init_random_number_generator,
+	des_random_key, des_is_weak_key, des_cblock_print_file): Add
+	prototypes.
+	(des_cbc_cksum, des_cbc_encrypt, des_read_password)
+	[KRB5_GENERAL__]: Add prototypes.
+
+	* krb.h: Make all function prototypes unconditional, don't use
+	PROTOTYPE macro.
+
+2001-01-29  Tom Yu  <tlyu@mit.edu>
+
+	* krb.h: Remove KRB_NEVERDATE.
+
+2001-01-25  Tom Yu  <tlyu@mit.edu>
+
+	* prot.h: Add new prototypes for prot_client.c stuff.  Also, add
+	new prototype for decode_header().
+
+2001-01-24  Tom Yu  <tlyu@mit.edu>
+
+	* prot.h: Add prototype for decode_kdc_request() and some rough
+	starting points for KRB4PROT_* error codes.
+
+2001-01-23  Tom Yu  <tlyu@mit.edu>
+
+	* krb.h: Remove internal prototypes and macros.
+
+	* prot.h: Put internal prototypes and macros here.  Make
+	KRB4_PUT{16,32} into little-endian and big-endian versions
+	thereof, with the original names getting an extra arg to determine
+	endianness of encoding.
+
+2000-11-08  Tom Yu  <tlyu@mit.edu>
+
+	* des.h: Change to make KRB4_32 an int if it's at least 32 bits
+	wide, else a long.  This is a change from previously where it was
+	a long except on the alpha.  We may want to rethink this if there
+	are binary compat issues that result.  Also, define DES_INT32 as
+	KRB4_INT32.
+
+	* krb.h: Add new macros KRB4_PUT32, KRB4_PUT16 which
+	unconditionally encode integers by bytes as big-endian.  Add new
+	macros KRB4_GET32BE, KRB4_GET32LE, KRB4_GET32, KRB4_GET16BE,
+	KRB4_GET16LE, KRB4_GET16 to retrieve integers by bytes.  Add
+	prototype for krb_strnlen.
+
+2000-10-23  Tom Yu  <tlyu@mit.edu>
+
+	* krb.h: Modify krb_{mk,rd}_{priv,safe} prototypes to align with
+	CNS, mostly by making them take C_Block * arguments.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* kparse.h: Add prototypes for fGetChar(), fGetParameterSet(),
+	ParmCompare(), FreeParameterSet(), fGetKeywordValue(),
+	fGetToken(), fGetLiteral(), fUngetChar().
+
+2000-08-31  Tom Yu  <tlyu@mit.edu>
+
+	* krb.h: Add prototypes for krb_life_to_time() and
+	krb_time_to_life(), as well as the KRB_NEVERDATE constant.
+
+2000-08-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb.h: Add prototypes for tf_init(), tf_get_pname(),
+	tf_get_pinst(), tf_get_cred() and tf_close() which are all used by
+	clients.
+
+2000-07-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb.h: For get_pw_tkt() and unix_time_gmt_unixsec() add required
+	KRB5_DLLIMP and KRB4_CALLCONV declarations.
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb.h: Add krb_in_tkt() prototype.
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb.h: Add prototypes for get_pw_tkt() and unix_time_gmt_unixsec().
+
+2000-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb.h (krb4_swab16): Mask upper byte of input after shifting, in
+	case the input value is a signed short.
+
+2000-05-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb.h (krb4_swab32): Mask high byte of input value after
+	shifting, to avoid "time out of bounds" error when byte orders are
+	different and low byte of timestamp has its high bit set and the
+	timestamp is stored as a signed value.
+
+	* krb.h (krb_get_err_text): Don't use "errno" as an argument
+	name.
+
+Mon Mar 15 15:58:34 1999  Tom Yu  <tlyu@mit.edu>
+
+	* des.h: Fix GSS_DLLIMP.
+
+1998-12-05  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb.h: Add prototypes for krb_set_key() and decomp_ticket().
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS macro set to '.' to indicate that there
+		are no subdirectories to be processed by the Makefile.
+
+	* configure.in: Removed and tests moved to parent directory.
+
+	* krb.h: Add a declaration for the global variable
+		krb5__krb4_context, which is used by the krb4 routines
+		that need to call krb5 library routines.
+
+Thu Sep 17 18:23:26 1998  Tom Yu  <tlyu@mit.edu>
+
+	* krb_db.h: ifdef out the declarations for kerb_get_* and
+	kerb_db_* to avoid problems with krb4 compat code in the kdc,
+	which declares some of these static.
+
+Wed Feb 18 15:51:41 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.  Fix up usage of $(C) for new
+	conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Nov 18 23:37:54 1997  Tom Yu  <tlyu@mit.edu>
+
+	* des.h: Clean up prototypes so they're sane and look a little
+ 	nicer.  The ivec parameter to pcbc_encrypt is now a C_Block FAR *,
+	while the paremeters to quad_cksum have been re-ordered to match
+	reality.
+
+Mon Oct 27 01:04:24 1997  Tom Yu  <tlyu@mit.edu>
+
+	* des.h: Replace KRB_INT32 with DES_INT32 to avoid temptation to
+	misuse.
+
+Mon Oct 20 14:09:45 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb.h: If we are using prototypes, add a forward declaration for
+		struct sockaddr_in.
+
+Tue Oct 14 15:39:28 1997  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* des.h: Define KRB_INT32 for the purposes of dealing with the key
+ 	schedule.  Also, define the key schedule more sanely.  See related
+ 	comments in lib/crypto/des.
+
+Sat Feb 22 00:49:37 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krb.h: Do not depend on unix being defined on Unix systems;
+        treat as the default case except when _WINDOWS defined
+
+Thu Feb 20 17:38:23 1997  Richard Basch  <basch@lehman.com>
+
+	* configure.in: awk is required by the Makefile
+	* Makefile.in: Re-arranged build/install rules because
+		krb_err.h is a generated file.
+
+Mon Feb 17 13:59:41 1997  Richard Basch  <basch@lehman.com>
+
+	* des.h: Added various function prototypes
+	* krb.h: Moved various macros from krb.h to des.h so
+		prototypes could be added to des.h
+
+Sun Feb 16 18:43:24 1997  Richard Basch  <basch@lehman.com>
+
+	* krb.h:
+		Removed INTERFACE declaration
+		Added prototypes for exported V4 functions
+
+Thu Feb  6 00:22:22 1997  Richard Basch  <basch@lehman.com>
+
+	* krb.h: Make sure KRB5_EXPORTVAR is defined
+
+Fri Nov 22 11:34:46 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in:  Install krb_err.h [218]
+
+Thu Oct 31 17:27:08 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (install): Start installing headers again [36]
+
+Sun Jul  7 18:18:45 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb4-proto.h: Change prototype for decomp_ticket to match source
+		(addr is not unsigned long *)
+
+Tue Dec 19 17:10:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kparse.h (LineNbr): Remove declaration of LineNbr; no longer
+		exported by kparse.c
+
+Sun Nov 12 05:18:05 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* krb.h (KEYFILE): change to call krb__get_srvtabname with a
+	default of the old hardcoded value "/etc/srvtab".
+
+Wed Jun 28 00:01:52 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb4-proto.h: correct signature for krb_rd_req.
+
+Tue Jun 27 23:53:22 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb.h (swap_u_long): use KRB4_32 in swap() macros.
+
+Thu Jun 22 16:06:26 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* krb4-proto.h, krb.h: reverse sense of KRB5_PROVIDE_PROTOTYPES
+		(-> KRB5_NO_PROTOTYPES)
+
+Fri Jun  9 18:40:51 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Fri Jun  9 15:51:45 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* kdc.h: Don't define the macros for max and min; they're already
+		defined in kdc_util.h.
+
+Thu Jun  8 11:22:23 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* Makefile.in (install): Don't install the install/kerberosIV
+		header files.
+
+Tue Jun  6 21:16:39 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb4-proto.h: decomp_ticket change the time field to unsigned
+		KRB4_32 to match the Cygnus krb4 library.
+
+Tue Jun  6 12:30:41 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb4-proto.h: Rename save_credentials to krb_save_credentials,
+		to match the Cygnus krb4 library.
+
+Tue May 23 22:08:05 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb4-proto.h: klog prototype did not match source.
+
+Sun May  7 08:26:21 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kparse.h: Remove ErrorMsg definition. It is declared static in
+		source file.
+
+	* krb4-proto.h: krb_rd_priv prototype did not match source
+
+Fri Apr 28 16:39:47 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* kparse.h (strutol, strsave): are only static in this module.
+
+Fri Apr 28 15:05:23 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb4-proto.h: #if 0, not #ifdef 0.
+
+Fri Apr 28 14:56:39 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* lsb_addr_cmp.h: Don't try to include osconf.h
+
+Fri Apr 28 08:24:23 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* conf.h, conf-*.h: Removed.  We don't need them anymore,
+		we're using autoconf!  (And things like MSBFIRST AND
+		LSBFIRST aren't needed anyway, since the CNS V4
+		library figures this all out dynamically anyway.)
+
+	* krb4-proto.h: Don't define the functions found in getenv.o or
+		setenv.o.  Declare krb_stime() instead of stime().
+
+Thu Apr 27 17:12:30 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb.h: add _fmemcpy, _fstrncpy, and far_fputs from cc-unix.h also.
+
+Thu Apr 27 14:22:10 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb.h (DECRYPT_TKT_TYPE_DEFINED, KEY_PROC_TYPE_DEFINED): needed
+	to keep secondary (readability) defines in g_in_tkt.c out.
+
+Thu Apr 27 13:32:22 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* conf-osf1alpha.h: New file
+
+	* osconf.h: Add inclusion of conf-osf1alpha.h
+
+	* krb.h: Add const to krb_err_txt to agree with library definition
+
+Thu Apr 27 10:55:00 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb.h: make INTERFACE, FAR go away for now.
+	Drag in the unix time conversion functions for unix only.
+	Locally define PROTOTYPE().
+	Drag in unix versions of SOCKET macros.
+	Recognize DEFINE_SOCKADDR and NEED_TIME_H the way cc-unix.h does.
+	Declare krb_ignore_ip_address.
+	Define DEB() to support non-printf debugging.
+	Declare errno.
+	Define key_proc_type and decrypt_tkt_type.
+	* prot.h: add KERB_ERR_PREAUTH_SHORT and _MISMATCH from Cygnus
+	extensions.
+	* krbports.h: new file, has default ports for V4 services for
+	hard-coded fallback.
+	* lsb_addr_cmp.h: from V4, handles the mutant comparison
+	functions needed for the V4 "direction" comparison. (Rename
+	of lsb_addr_comp.h due to filename length.)
+
+Tue Mar 14 16:53:37 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in: Delete definitions defined in pre/config.in.
+
+Wed Mar  1 17:59:19 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kadm.h: Remove declaration of malloc() and realloc().
+
+Fri Feb  3 06:50:46 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb.h: Add changes to make this work on Alpha's.  (From Ezra).
+
+Wed Jan 25 19:25:02 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* kadm.h: add DEL_ENT and DEL_ACL for CNS V4 delete support.
+
+Fri Nov 18 01:24:58 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (install): use $(INSTALL_DATA) instead of cp. Elide
+	dependency in install rule so $(srcdir) works.
+	* configure.in: use AC_PROG_INSTALL.
+
+Fri Nov 18 00:17:03 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: add WITH_CCOPTS.
+
+Mon Oct  3 18:50:25 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR)
+
+	* Makefile.in: Fix "make install" to use $(srcdir) when copying in
+		header files.
+
diff --git a/mechglue/src/include/kerberosIV/Makefile.in b/mechglue/src/include/kerberosIV/Makefile.in
new file mode 100644
index 000000000..dc410e885
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/Makefile.in
@@ -0,0 +1,22 @@
+thisconfigdir=./../..
+myfulldir=include/kerberosIV
+mydir=include/kerberosIV
+BUILDTOP=$(REL)..$(S)..
+KRB4_HEADERS=krb.h des.h mit-copyright.h
+
+all-unix:: krb_err.h kadm_err.h
+
+krb_err.h: $(SRCTOP)/lib/krb4/krb_err.et
+kadm_err.h: $(SRCTOP)/lib/krb4/kadm_err.et
+krb_err.h kadm_err.h:
+	(cd $(BUILDTOP)/lib/krb4 && $(MAKE) includes)
+
+clean-unix::
+	$(RM) krb_err.h kadm_err.h
+
+install-headers-unix install:: krb_err.h kadm_err.h
+	@set -x; for f in $(KRB4_HEADERS) ; \
+	do $(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(KRB5_INCDIR)/kerberosIV/$$f ; \
+	done
+	$(INSTALL_DATA) krb_err.h $(DESTDIR)$(KRB5_INCDIR)$(S)kerberosIV$(S)krb_err.h
+	$(INSTALL_DATA) kadm_err.h $(DESTDIR)$(KRB5_INCDIR)$(S)kerberosIV$(S)kadm_err.h
diff --git a/mechglue/src/include/kerberosIV/addr_comp.h b/mechglue/src/include/kerberosIV/addr_comp.h
new file mode 100644
index 000000000..ccf3a8d05
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/addr_comp.h
@@ -0,0 +1,52 @@
+/*
+ * include/kerberosIV/addr_comp.h
+ *
+ * Copyright 1987-1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Include file for address comparison macros.
+ */
+
+#ifndef ADDR_COMP_DEFS
+#define ADDR_COMP_DEFS
+
+/*
+** Look boys and girls, a big kludge
+** We need to compare the two internet addresses in network byte order, not
+**   local byte order.  This is a *really really slow way of doing that*
+** But.....
+**         .....it works
+** so we run with it
+**
+** long_less_than gets fed two (u_char *)'s....
+*/
+
+#define u_char_comp(x,y) \
+        (((x)>(y))?(1):(((x)==(y))?(0):(-1)))
+
+#define long_less_than(x,y) \
+        (u_char_comp((x)[0],(y)[0])?u_char_comp((x)[0],(y)[0]): \
+	 (u_char_comp((x)[1],(y)[1])?u_char_comp((x)[1],(y)[1]): \
+	  (u_char_comp((x)[2],(y)[2])?u_char_comp((x)[2],(y)[2]): \
+	   (u_char_comp((x)[3],(y)[3])))))
+
+#endif /* ADDR_COMP_DEFS */
diff --git a/mechglue/src/include/kerberosIV/admin_server.h b/mechglue/src/include/kerberosIV/admin_server.h
new file mode 100644
index 000000000..3da415518
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/admin_server.h
@@ -0,0 +1,58 @@
+/*
+ * include/kerberosIV/admin_server.h
+ *
+ * Copyright 1987-1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#ifndef ADMIN_SERVER_DEFS
+#define ADMIN_SERVER_DEFS
+
+#define PW_SRV_VERSION		 2	/* version number */
+
+#define INSTALL_NEW_PW		(1<<0)	/*
+					 * ver, cmd, name, password,
+					 * old_pass, crypt_pass, uid
+					 */
+
+#define ADMIN_NEW_PW		(2<<1)	/*
+					 * ver, cmd, name, passwd,
+					 * old_pass
+					 * (grot), crypt_pass (grot)
+					 */
+
+#define ADMIN_SET_KDC_PASSWORD	(3<<1)	/* ditto */
+#define ADMIN_ADD_NEW_KEY	(4<<1)	/* ditto */
+#define ADMIN_ADD_NEW_KEY_ATTR	(5<<1)  /*
+					 * ver, cmd, name, passwd,
+					 * inst, attr (grot)
+					 */
+#define INSTALL_REPLY		(1<<1)	/* ver, cmd, name, password */
+#define	RETRY_LIMIT		 1
+#define	TIME_OUT		30
+#define USER_TIMEOUT		90
+#define MAX_KPW_LEN		40
+
+#define KADM	"changepw"		/* service name */
+
+#endif /* ADMIN_SERVER_DEFS */
diff --git a/mechglue/src/include/kerberosIV/des.h b/mechglue/src/include/kerberosIV/des.h
new file mode 100644
index 000000000..3814aa88c
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/des.h
@@ -0,0 +1,195 @@
+/*
+ * include/kerberosIV/des.h
+ *
+ * Copyright 1987, 1988, 1994, 2002 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Include file for the Data Encryption Standard library.
+ */
+
+#if defined(__MACH__) && defined(__APPLE__)
+#	include <TargetConditionals.h>
+#	if TARGET_RT_MAC_CFM
+#		error "Use KfM 4.0 SDK headers for CFM compilation."
+#	endif
+#endif
+
+#ifdef __cplusplus
+#ifndef KRBINT_BEGIN_DECLS
+#define KRBINT_BEGIN_DECLS	extern "C" {
+#define KRBINT_END_DECLS	}
+#endif
+#else
+#define KRBINT_BEGIN_DECLS
+#define KRBINT_END_DECLS
+#endif
+
+#ifndef KRB5INT_DES_TYPES_DEFINED
+#define KRB5INT_DES_TYPES_DEFINED
+
+#include <limits.h>
+
+KRBINT_BEGIN_DECLS
+
+#if TARGET_OS_MAC
+#	pragma options align=mac68k
+#endif
+
+#if UINT_MAX >= 0xFFFFFFFFUL
+#define DES_INT32 int
+#define DES_UINT32 unsigned int
+#else
+#define DES_INT32 long
+#define DES_UINT32 unsigned long
+#endif
+
+typedef unsigned char des_cblock[8];	/* crypto-block size */
+/*
+ * Key schedule.
+ *
+ * This used to be
+ *
+ * typedef struct des_ks_struct {
+ *     union { DES_INT32 pad; des_cblock _;} __;
+ * } des_key_schedule[16];
+ *
+ * but it would cause trouble if DES_INT32 were ever more than 4
+ * bytes.  The reason is that all the encryption functions cast it to
+ * (DES_INT32 *), and treat it as if it were DES_INT32[32].  If
+ * 2*sizeof(DES_INT32) is ever more than sizeof(des_cblock), the
+ * caller-allocated des_key_schedule will be overflowed by the key
+ * scheduling functions.  We can't assume that every platform will
+ * have an exact 32-bit int, and nothing should be looking inside a
+ * des_key_schedule anyway.
+ */
+typedef struct des_ks_struct {  DES_INT32 _[2]; } des_key_schedule[16];
+
+#if TARGET_OS_MAC
+#	pragma options align=reset
+#endif
+
+KRBINT_END_DECLS
+
+#endif /* KRB5INT_DES_TYPES_DEFINED */
+
+/* only do the whole thing once	 */
+#ifndef DES_DEFS
+/*
+ * lib/crypto/des/des_int.h defines KRB5INT_CRYPTO_DES_INT temporarily
+ * to avoid including the defintions and declarations below.  The
+ * reason that the crypto library needs to include this file is that
+ * it needs to have its types aligned with krb4's types.
+ */
+#ifndef KRB5INT_CRYPTO_DES_INT
+#define DES_DEFS
+
+#if defined(_WIN32)
+#ifndef KRB4
+#define KRB4 1
+#endif
+#include <win-mac.h>
+#endif
+#include <stdio.h> /* need FILE for des_cblock_print_file */
+
+KRBINT_BEGIN_DECLS
+
+#if TARGET_OS_MAC
+#	pragma options align=mac68k
+#endif
+
+/* Windows declarations */
+#ifndef KRB5_CALLCONV
+#define KRB5_CALLCONV
+#define KRB5_CALLCONV_C
+#endif
+
+#define DES_KEY_SZ 	(sizeof(des_cblock))
+#define DES_ENCRYPT	1
+#define DES_DECRYPT	0
+
+#ifndef NCOMPAT
+#define C_Block des_cblock
+#define Key_schedule des_key_schedule
+#define ENCRYPT DES_ENCRYPT
+#define DECRYPT DES_DECRYPT
+#define KEY_SZ DES_KEY_SZ
+#define string_to_key des_string_to_key
+#define read_pw_string des_read_pw_string
+#define random_key des_random_key
+#define pcbc_encrypt des_pcbc_encrypt
+#define key_sched des_key_sched
+#define cbc_encrypt des_cbc_encrypt
+#define cbc_cksum des_cbc_cksum
+#define C_Block_print des_cblock_print
+#define quad_cksum des_quad_cksum
+typedef struct des_ks_struct bit_64;
+#endif
+
+#define des_cblock_print(x) des_cblock_print_file(x, stdout)
+
+/*
+ * Function Prototypes
+ */
+
+int KRB5_CALLCONV des_key_sched (C_Block, Key_schedule);
+
+int KRB5_CALLCONV
+des_pcbc_encrypt (C_Block *in, C_Block *out, long length,
+		  const des_key_schedule schedule, C_Block *ivec,
+		  int enc);
+
+unsigned long KRB5_CALLCONV
+des_quad_cksum (const unsigned char *in, unsigned DES_INT32 *out,
+		long length, int out_count, C_Block *seed);
+/*
+ * XXX ABI change: used to return void; also, cns/kfm have signed long
+ * instead of unsigned long length.
+ */
+unsigned long KRB5_CALLCONV
+des_cbc_cksum(const des_cblock *, des_cblock *, unsigned long,
+	      const des_key_schedule, const des_cblock *);
+int KRB5_CALLCONV des_string_to_key (const char *, C_Block);
+void afs_string_to_key(char *, char *, des_cblock);
+
+/* XXX ABI change: used to return krb5_error_code */
+int KRB5_CALLCONV des_read_password(des_cblock *, char *, int);
+int KRB5_CALLCONV des_ecb_encrypt(des_cblock *, des_cblock *,
+				  const des_key_schedule, int);
+/* XXX kfm/cns have signed long length */
+int des_cbc_encrypt(des_cblock *, des_cblock *, unsigned long,
+		    const des_key_schedule, const des_cblock *, int);
+void des_fixup_key_parity(des_cblock);
+int des_check_key_parity(des_cblock);
+int KRB5_CALLCONV des_new_random_key(des_cblock);
+void des_init_random_number_generator(des_cblock);
+int des_random_key(des_cblock *);
+int des_is_weak_key(des_cblock);
+void des_cblock_print_file(des_cblock *, FILE *fp);
+
+#if TARGET_OS_MAC
+#	pragma options align=reset
+#endif
+
+KRBINT_END_DECLS
+
+#endif /* KRB5INT_CRYPTO_DES_INT */
+#endif	/* DES_DEFS */
diff --git a/mechglue/src/include/kerberosIV/kadm.h b/mechglue/src/include/kerberosIV/kadm.h
new file mode 100644
index 000000000..21bc60e5a
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/kadm.h
@@ -0,0 +1,194 @@
+/*
+ * include/kerberosIV/kadm.h
+ *
+ * Copyright 1988, 1994, 2002 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Definitions for Kerberos administration server & client.  These
+ * should be considered private; among other reasons, it leaks all
+ * over the namespace.
+ */
+
+#ifndef KADM_DEFS
+#define KADM_DEFS
+
+/*
+ * kadm.h
+ * Header file for the fourth attempt at an admin server
+ * Doug Church, December 28, 1989, MIT Project Athena
+ */
+
+#include <sys/types.h>
+#include "port-sockets.h"
+#include <kerberosIV/krb.h>
+#include <kerberosIV/des.h>
+
+/* for those broken Unixes without this defined... should be in sys/param.h */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+/* The global structures for the client and server */
+typedef struct {
+    struct sockaddr_in admin_addr;
+    struct sockaddr_in my_addr;
+    int my_addr_len;
+    int admin_fd;		/* file descriptor for link to admin server */
+    char sname[ANAME_SZ];	/* the service name */
+    char sinst[INST_SZ];	/* the services instance */
+    char krbrlm[REALM_SZ];
+    /* KfM additions... */
+    int  default_port;
+    CREDENTIALS creds; /* The client's credentials (from krb_get_pw_in_tkt_creds)*/
+} Kadm_Client;
+
+typedef struct {		/* status of the server, i.e the parameters */
+    int inter;			/* Space for command line flags */
+    char *sysfile;		/* filename of server */
+} admin_params;			/* Well... it's the admin's parameters */
+
+/* Largest password length to be supported */
+#define MAX_KPW_LEN	128
+
+/* Largest packet the admin server will ever allow itself to return */
+#define KADM_RET_MAX 2048
+
+/* That's right, versions are 8 byte strings */
+#define KADM_VERSTR	"KADM0.0A"
+#define KADM_ULOSE	"KYOULOSE"	/* sent back when server can't
+					   decrypt client's msg */
+#define KADM_VERSIZE strlen(KADM_VERSTR)
+
+/* the lookups for the server instances */
+#define PWSERV_NAME  "changepw"
+#define KADM_SNAME   "kerberos_master"
+#define KADM_SINST   "kerberos"
+
+/* Attributes fields constants and macros */
+#define ALLOC        2
+#define RESERVED     3
+#define DEALLOC      4
+#define DEACTIVATED  5
+#define ACTIVE       6
+
+/* Kadm_vals structure for passing db fields into the server routines */
+#define FLDSZ        4
+
+typedef struct {
+    u_char         fields[FLDSZ];     /* The active fields in this struct */
+    char           name[ANAME_SZ];
+    char           instance[INST_SZ];
+    KRB_UINT32     key_low;
+    KRB_UINT32     key_high;
+    KRB_UINT32     exp_date;
+    unsigned short attributes;
+    unsigned char  max_life;
+} Kadm_vals;                    /* The basic values structure in Kadm */
+
+/* Kadm_vals structure for passing db fields into the server routines */
+#define FLDSZ        4
+
+/* Need to define fields types here */
+#define KADM_NAME       31
+#define KADM_INST       30
+#define KADM_EXPDATE    29
+#define KADM_ATTR       28
+#define KADM_MAXLIFE    27
+#define KADM_DESKEY     26
+
+/* To set a field entry f in a fields structure d */
+#define SET_FIELD(f,d)  (d[3-(f/8)]|=(1<<(f%8)))
+
+/* To set a field entry f in a fields structure d */
+#define CLEAR_FIELD(f,d)  (d[3-(f/8)]&=(~(1<<(f%8))))
+
+/* Is field f in fields structure d */
+#define IS_FIELD(f,d)   (d[3-(f/8)]&(1<<(f%8)))
+
+/* Various return codes */
+#define KADM_SUCCESS    0
+
+#define WILDCARD_STR "*"
+
+enum acl_types {
+ADDACL,
+GETACL,
+MODACL,
+STABACL,
+DELACL
+};
+
+/* Various opcodes for the admin server's functions */
+#define CHANGE_PW    2
+#define ADD_ENT      3
+#define MOD_ENT      4
+#define GET_ENT      5
+#define CHECK_PW     6
+#define CHG_STAB     7
+/* Cygnus principal-deletion support */
+#define KADM_CYGNUS_EXT_BASE 64
+#define DEL_ENT              (KADM_CYGNUS_EXT_BASE+1)
+
+#ifdef POSIX
+typedef void sigtype;
+#else
+typedef int sigtype;
+#endif
+
+/* Avoid stomping on namespace... */
+
+#define vals_to_stream		kadm_vals_to_stream
+#define build_field_header	kadm_build_field_header
+#define vts_string		kadm_vts_string
+#define vts_short		kadm_vts_short
+#define vts_long		kadm_vts_long
+#define vts_char		kadm_vts_char
+
+#define stream_to_vals		kadm_stream_to_vals
+#define check_field_header	kadm_check_field_header
+#define stv_string		kadm_stv_string
+#define stv_short		kadm_stv_short
+#define stv_long		kadm_stv_long
+#define stv_char		kadm_stv_char
+
+int vals_to_stream(Kadm_vals *, u_char **);
+int build_field_header(u_char *, u_char **);
+int vts_string(char *, u_char **, int);
+int vts_short(KRB_UINT32, u_char **, int);
+int vts_long(KRB_UINT32, u_char **, int);
+int vts_char(KRB_UINT32, u_char **, int);
+
+int stream_to_vals(u_char *, Kadm_vals *, int);
+int check_field_header(u_char *, u_char *, int);
+int stv_string(u_char *, char *, int, int, int);
+int stv_short(u_char *, u_short *, int, int);
+int stv_long(u_char *, KRB_UINT32 *, int, int);
+int stv_char(u_char *, u_char *, int, int);
+
+int kadm_init_link(char *, char *, char *, Kadm_Client *, int);
+int kadm_cli_send(Kadm_Client *, u_char *, size_t, u_char **, size_t *);
+int kadm_cli_conn(Kadm_Client *);
+void kadm_cli_disconn(Kadm_Client *);
+int kadm_cli_out(Kadm_Client *, u_char *, int, u_char **, size_t *);
+int kadm_cli_keyd(Kadm_Client *, des_cblock, des_key_schedule);
+
+#endif /* KADM_DEFS */
diff --git a/mechglue/src/include/kerberosIV/kdc.h b/mechglue/src/include/kerberosIV/kdc.h
new file mode 100644
index 000000000..095420c28
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/kdc.h
@@ -0,0 +1,55 @@
+/*
+ * include/kerberosIV/kdc.h
+ *
+ * Copyright 1987, 1988, 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Include file for the Kerberos Key Distribution Center. 
+ */
+
+#ifndef KDC_DEFS
+#define KDC_DEFS
+
+#define S_AD_SZ		sizeof(struct sockaddr_in)
+
+#ifdef notdef
+#define max(a,b)	(a>b ? a : b)
+#define min(a,b)	(a<b ? a : b)
+#endif
+
+#define TRUE		1
+#define FALSE		0
+
+#define MKEYFILE	"/.k"
+#define K_LOGFIL	"/kerberos/kpropd.log"
+#define KS_LOGFIL	"/kerberos/kerberos_slave.log"
+#define KRB_ACL		"/kerberos/kerberos.acl"
+#define KRB_PROG	"./kerberos"
+
+#define ONE_MINUTE	60
+#define FIVE_MINUTES	(5 * ONE_MINUTE)
+#define ONE_HOUR	(60 * ONE_MINUTE)
+#define ONE_DAY		(24 * ONE_HOUR)
+#define THREE_DAYS	(3 * ONE_DAY)
+
+#endif /* KDC_DEFS */
+
diff --git a/mechglue/src/include/kerberosIV/klog.h b/mechglue/src/include/kerberosIV/klog.h
new file mode 100644
index 000000000..360fcfbee
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/klog.h
@@ -0,0 +1,57 @@
+/*
+ * include/kerberosIV/klog.h
+ *
+ * Copyright 1988, 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * This file defines the types of log messages logged by klog.  Each
+ * type of message may be selectively turned on or off. 
+ */
+
+#ifndef KLOG_DEFS
+#define KLOG_DEFS
+
+#define KRBLOG 		"/kerberos/kerberos.log"  /* master server  */
+#define KRBSLAVELOG	"/kerberos/kerberos_slave.log"  /* master server  */
+#define	NLOGTYPE	100	/* Maximum number of log msg types  */
+
+#define L_NET_ERR	  1	/* Error in network code	    */
+#define L_NET_INFO	  2	/* Info on network activity	    */
+#define L_KRB_PERR	  3	/* Kerberos protocol errors	    */
+#define L_KRB_PINFO	  4	/* Kerberos protocol info	    */
+#define L_INI_REQ	  5	/* Request for initial ticket	    */
+#define L_NTGT_INTK       6	/* Initial request not for TGT	    */
+#define L_DEATH_REQ       7	/* Request for server death	    */
+#define L_TKT_REQ	  8	/* All ticket requests using a tgt  */
+#define L_ERR_SEXP	  9	/* Service expired		    */
+#define L_ERR_MKV	 10	/* Master key version incorrect     */
+#define L_ERR_NKY	 11	/* User's key is null		    */
+#define L_ERR_NUN	 12	/* Principal not unique		    */
+#define L_ERR_UNK	 13	/* Principal Unknown		    */
+#define L_ALL_REQ	 14	/* All requests			    */
+#define L_APPL_REQ	 15	/* Application requests (using tgt) */
+#define L_KRB_PWARN      16	/* Protocol warning messages	    */
+
+char   *klog(int, char *, char *, char *, char *, char *, char *, char *, 
+	     char *, char *, char *, char *);
+
+#endif /* KLOG_DEFS */
diff --git a/mechglue/src/include/kerberosIV/kparse.h b/mechglue/src/include/kerberosIV/kparse.h
new file mode 100644
index 000000000..6cc890f65
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/kparse.h
@@ -0,0 +1,106 @@
+/*
+ * include/kerberosIV/kparse.h
+ *
+ * Copyright 1988, 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Include file for kparse routines.
+ */
+
+#ifndef KPARSE_DEFS
+#define KPARSE_DEFS
+
+/*
+ * values returned by fGetParameterSet() 
+ */
+
+#define PS_BAD_KEYWORD	  -2	/* unknown or duplicate keyword */
+#define PS_SYNTAX	  -1	/* syntax error */
+#define PS_OKAY		   0	/* got a complete parameter set */
+#define PS_EOF		   1	/* nothing more in the file */
+
+/*
+ * values returned by fGetKeywordValue() 
+ */
+
+#define KV_SYNTAX	 -2	/* syntax error */
+#define KV_EOF		 -1	/* nothing more in the file */
+#define KV_OKAY		  0	/* got a keyword/value pair */
+#define KV_EOL		  1	/* nothing more on this line */
+
+/*
+ * values returned by fGetToken() 
+ */
+
+#define GTOK_BAD_QSTRING -1	/* newline found in quoted string */
+#define GTOK_EOF	  0	/* end of file encountered */
+#define GTOK_QSTRING	  1	/* quoted string */
+#define GTOK_STRING	  2	/* unquoted string */
+#define GTOK_NUMBER	  3	/* one or more digits */
+#define GTOK_PUNK	  4	/* punks are punctuation, newline,
+				 * etc. */
+#define GTOK_WHITE	  5	/* one or more whitespace chars */
+
+/*
+ * extended character classification macros 
+ */
+
+#define ISOCTAL(CH) 	( (CH>='0')  && (CH<='7') )
+#define ISQUOTE(CH) 	( (CH=='\"') || (CH=='\'') || (CH=='`') )
+#define ISWHITESPACE(C) ( (C==' ')   || (C=='\t') )
+#define ISLINEFEED(C) 	( (C=='\n')  || (C=='\r')  || (C=='\f') )
+
+/*
+ * tokens consist of any printable charcacter except comma, equal, or
+ * whitespace 
+ */
+
+#define ISTOKENCHAR(C) ((C>040) && (C<0177) && (C != ',') && (C != '='))
+
+/*
+ * the parameter table defines the keywords that will be recognized by
+ * fGetParameterSet, and their default values if not specified. 
+ */
+
+typedef struct {
+    char *keyword;
+    char *defvalue;
+    char *value;
+}       parmtable;
+
+#define PARMCOUNT(P) (sizeof(P)/sizeof(P[0]))
+
+int fGetChar (FILE *fp);
+int fGetParameterSet (FILE *fp, parmtable parm[], int parmcount);
+int ParmCompare (parmtable parm[], int parmcount, char *keyword, char *value);
+
+void FreeParameterSet (parmtable parm[], int parmcount);
+
+int fGetKeywordValue (FILE *fp, char *keyword, int klen, char *value, int vlen);
+
+int fGetToken (FILE *fp, char *dest, int maxlen);
+
+int fGetLiteral (FILE *fp);
+
+int fUngetChar (int ch, FILE *fp);
+
+#endif /* KPARSE_DEFS */
diff --git a/mechglue/src/include/kerberosIV/krb.h b/mechglue/src/include/kerberosIV/krb.h
new file mode 100644
index 000000000..6bc7149d7
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/krb.h
@@ -0,0 +1,787 @@
+/*
+ * include/kerberosIV/krb.h
+ *
+ * Copyright 1987, 1988, 1994, 2001, 2002 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Include file for the Kerberos V4 library. 
+ */
+
+/* Only one time, please */
+#ifndef	KRB_DEFS
+#define KRB_DEFS
+
+/*
+ * For MacOS, don't expose prototypes of various private functions.
+ * Unfortuantely, they've leaked out everywhere else.
+ */
+#if defined(__MACH__) && defined(__APPLE__)
+#	include <TargetConditionals.h>
+#	if TARGET_RT_MAC_CFM
+#		error "Use KfM 4.0 SDK headers for CFM compilation."
+#	endif
+#	ifndef KRB_PRIVATE
+#		define KRB_PRIVATE 0
+#	endif
+#else
+#	ifndef KRB_PRIVATE
+#		define KRB_PRIVATE 1
+#	endif
+#endif
+
+/* Define u_char, u_short, u_int, and u_long. */
+/* XXX these typdef names are not standardized! */
+#include <sys/types.h>
+
+/* Need some defs from des.h	 */
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb_err.h>
+#include <profile.h>
+
+#ifdef _WIN32
+#include <time.h>
+#endif /* _WIN32 */
+
+#ifdef __cplusplus
+#ifndef KRBINT_BEGIN_DECLS
+#define KRBINT_BEGIN_DECLS	extern "C" {
+#define KRBINT_END_DECLS	}
+#endif
+#else
+#define KRBINT_BEGIN_DECLS
+#define KRBINT_END_DECLS
+#endif
+KRBINT_BEGIN_DECLS
+
+#if TARGET_OS_MAC
+#	pragma options align=mac68k
+#endif
+
+#define KRB4_32		DES_INT32
+#define KRB_INT32	DES_INT32
+#define KRB_UINT32	DES_UINT32
+
+#define		MAX_KRB_ERRORS	256
+
+#if TARGET_OS_MAC
+/* ABI divergence on Mac for backwards compatibility. */
+extern const char * const * const krb_err_txt;
+#else
+extern const char * const krb_err_txt[MAX_KRB_ERRORS];
+#endif
+
+/* General definitions */
+#define		KSUCCESS	0
+#define		KFAILURE	255
+
+/*
+ * Kerberos specific definitions 
+ *
+ * KRBLOG is the log file for the kerberos master server. KRB_CONF is
+ * the configuration file where different host machines running master
+ * and slave servers can be found. KRB_MASTER is the name of the
+ * machine with the master database.  The admin_server runs on this
+ * machine, and all changes to the db (as opposed to read-only
+ * requests, which can go to slaves) must go to it. KRB_HOST is the
+ * default machine * when looking for a kerberos slave server.  Other
+ * possibilities are * in the KRB_CONF file. KRB_REALM is the name of
+ * the realm. 
+ */
+
+#define		KRB_CONF	"/etc/krb.conf"
+#define		KRB_RLM_TRANS	"/etc/krb.realms"
+#define		KRB_MASTER	"kerberos"
+#define		KRB_HOST	 KRB_MASTER
+#define		KRB_REALM	"ATHENA.MIT.EDU"
+
+/* The maximum sizes for aname, realm, sname, and instance +1 */
+#define 	ANAME_SZ	40
+#define		REALM_SZ	40
+#define		SNAME_SZ	40
+#define		INST_SZ		40
+#define     ADDR_SZ     40
+/*
+ * NB: This overcounts due to NULs.
+ */
+/* include space for '.' and '@' */
+#define		MAX_K_NAME_SZ	(ANAME_SZ + INST_SZ + REALM_SZ + 2)
+#define		KKEY_SZ		100
+#define		VERSION_SZ	1
+#define		MSG_TYPE_SZ	1
+#define		DATE_SZ		26	/* RTI date output */
+
+#define		MAX_HSTNM	100
+
+#ifndef DEFAULT_TKT_LIFE		/* allow compile-time override */
+#define DEFAULT_TKT_LIFE	120	/* default lifetime for krb_mk_req */
+#endif
+
+#define		KRB_TICKET_GRANTING_TICKET	"krbtgt"
+
+/* Definition of text structure used to pass text around */
+#define		MAX_KTXT_LEN	1250
+
+struct ktext {
+    int     length;		/* Length of the text */
+    unsigned char dat[MAX_KTXT_LEN];	/* The data itself */
+    unsigned long mbz;		/* zero to catch runaway strings */
+};
+
+typedef struct ktext *KTEXT;
+typedef struct ktext KTEXT_ST;
+
+
+/* Definitions for send_to_kdc */
+#define	CLIENT_KRB_TIMEOUT	4	/* time between retries */
+#define CLIENT_KRB_RETRY	5	/* retry this many times */
+#define	CLIENT_KRB_BUFLEN	512	/* max unfragmented packet */
+
+/* Definitions for ticket file utilities */
+#define	R_TKT_FIL	0
+#define	W_TKT_FIL	1
+
+/* Definitions for cl_get_tgt */
+#ifdef PC
+#define CL_GTGT_INIT_FILE		"\\kerberos\\k_in_tkts"
+#else
+#define CL_GTGT_INIT_FILE		"/etc/k_in_tkts"
+#endif /* PC */
+
+/* Parameters for rd_ap_req */
+/* Maximum allowable clock skew in seconds */
+#define 	CLOCK_SKEW	5*60
+/* Filename for readservkey */
+#define		KEYFILE		((char*)krb__get_srvtabname("/etc/srvtab"))
+
+/* Structure definition for rd_ap_req */
+
+struct auth_dat {
+    unsigned char k_flags;	/* Flags from ticket */
+    char    pname[ANAME_SZ];	/* Principal's name */
+    char    pinst[INST_SZ];	/* His Instance */
+    char    prealm[REALM_SZ];	/* His Realm */
+    unsigned KRB4_32 checksum;	/* Data checksum (opt) */
+    C_Block session;		/* Session Key */
+    int     life;		/* Life of ticket */
+    unsigned KRB4_32 time_sec;	/* Time ticket issued */
+    unsigned KRB4_32 address;	/* Address in ticket */
+    KTEXT_ST reply;		/* Auth reply (opt) */
+};
+
+typedef struct auth_dat AUTH_DAT;
+
+/* Structure definition for credentials returned by get_cred */
+
+struct credentials {
+    char    service[ANAME_SZ];	/* Service name */
+    char    instance[INST_SZ];	/* Instance */
+    char    realm[REALM_SZ];	/* Auth domain */
+    C_Block session;		/* Session key */
+    int     lifetime;		/* Lifetime */
+    int     kvno;		/* Key version number */
+    KTEXT_ST ticket_st;		/* The ticket itself */
+    KRB4_32 issue_date;		/* The issue time */
+    char    pname[ANAME_SZ];	/* Principal's name */
+    char    pinst[INST_SZ];	/* Principal's instance */
+#if TARGET_OS_MAC
+    KRB_UINT32 address;			/* Address in ticket */
+    KRB_UINT32 stk_type;		/* string_to_key function needed */
+#endif
+#ifdef _WIN32
+    char    address[ADDR_SZ];   /* Address in ticket */
+#endif
+};
+
+typedef struct credentials CREDENTIALS;
+
+/* Structure definition for rd_private_msg and rd_safe_msg */
+
+struct msg_dat {
+    unsigned char *app_data;	/* pointer to appl data */
+    unsigned KRB4_32 app_length;	/* length of appl data */
+    unsigned KRB4_32 hash;		/* hash to lookup replay */
+    int     swap;			/* swap bytes? */
+    KRB4_32  time_sec;			/* msg timestamp seconds */
+    unsigned char time_5ms;		/* msg timestamp 5ms units */
+};
+
+typedef struct msg_dat MSG_DAT;
+
+
+/* Location of ticket file for save_cred and get_cred */
+#ifdef _WIN32
+#define TKT_FILE        "\\kerberos\\ticket.ses"
+#else
+#define TKT_FILE        tkt_string()
+#define TKT_ROOT        "/tmp/tkt"
+#endif /* _WIN32 */
+
+/*
+ * Error codes are now defined as offsets from com_err (krb_err.et)
+ * values.
+ */
+#define KRB_ET(x)	((KRBET_ ## x) - ERROR_TABLE_BASE_krb)
+
+/* Error codes returned from the KDC */
+#define	KDC_OK		KRB_ET(KSUCCESS)	/*  0 - Request OK */
+#define	KDC_NAME_EXP	KRB_ET(KDC_NAME_EXP)	/*  1 - Principal expired */
+#define	KDC_SERVICE_EXP	KRB_ET(KDC_SERVICE_EXP)	/*  2 - Service expired */
+#define	KDC_AUTH_EXP	KRB_ET(KDC_AUTH_EXP)	/*  3 - Auth expired */
+#define	KDC_PKT_VER	KRB_ET(KDC_PKT_VER)	/*  4 - Prot version unknown */
+#define	KDC_P_MKEY_VER	KRB_ET(KDC_P_MKEY_VER)	/*  5 - Wrong mkey version */
+#define	KDC_S_MKEY_VER 	KRB_ET(KDC_S_MKEY_VER)	/*  6 - Wrong mkey version */
+#define	KDC_BYTE_ORDER	KRB_ET(KDC_BYTE_ORDER)	/*  7 - Byte order unknown */
+#define	KDC_PR_UNKNOWN	KRB_ET(KDC_PR_UNKNOWN)	/*  8 - Princ unknown */
+#define	KDC_PR_N_UNIQUE KRB_ET(KDC_PR_N_UNIQUE)	/*  9 - Princ not unique */
+#define	KDC_NULL_KEY	KRB_ET(KDC_NULL_KEY)	/* 10 - Princ has null key */
+#define	KDC_GEN_ERR	KRB_ET(KDC_GEN_ERR)	/* 20 - Generic err frm KDC */
+
+/* Values returned by get_credentials */
+#define	GC_OK		KRB_ET(KSUCCESS)	/*  0 - Retrieve OK */
+#define	RET_OK		KRB_ET(KSUCCESS)	/*  0 - Retrieve OK */
+#define	GC_TKFIL	KRB_ET(GC_TKFIL)	/* 21 - Can't rd tkt file */
+#define	RET_TKFIL	KRB_ET(GC_TKFIL)	/* 21 - Can't rd tkt file */
+#define	GC_NOTKT	KRB_ET(GC_NOTKT)	/* 22 - Can't find tkt|TGT */
+#define	RET_NOTKT	KRB_ET(GC_NOTKT)	/* 22 - Can't find tkt|TGT */
+
+/* Values returned by mk_ap_req	 */
+#define	MK_AP_OK	KRB_ET(KSUCCESS)	/*  0 - Success */
+#define	MK_AP_TGTEXP	KRB_ET(MK_AP_TGTEXP)	/* 26 - TGT Expired */
+
+/* Values returned by rd_ap_req */
+#define	RD_AP_OK	KRB_ET(KSUCCESS)	/*  0 - Request authentic */
+#define	RD_AP_UNDEC	KRB_ET(RD_AP_UNDEC)	/* 31 - Can't decode authent */
+#define	RD_AP_EXP	KRB_ET(RD_AP_EXP)	/* 32 - Ticket expired */
+#define	RD_AP_NYV	KRB_ET(RD_AP_NYV)	/* 33 - Ticket not yet valid */
+#define	RD_AP_REPEAT	KRB_ET(RD_AP_REPEAT)	/* 34 - Repeated request */
+#define	RD_AP_NOT_US	KRB_ET(RD_AP_NOT_US)	/* 35 - Ticket isn't for us */
+#define	RD_AP_INCON	KRB_ET(RD_AP_INCON)	/* 36 - Request inconsistent */
+#define	RD_AP_TIME	KRB_ET(RD_AP_TIME)	/* 37 - delta_t too big */
+#define	RD_AP_BADD	KRB_ET(RD_AP_BADD)	/* 38 - Incorrect net addr */
+#define	RD_AP_VERSION	KRB_ET(RD_AP_VERSION)	/* 39 - prot vers mismatch */
+#define	RD_AP_MSG_TYPE	KRB_ET(RD_AP_MSG_TYPE)	/* 40 - invalid msg type */
+#define	RD_AP_MODIFIED	KRB_ET(RD_AP_MODIFIED)	/* 41 - msg stream modified */
+#define	RD_AP_ORDER	KRB_ET(RD_AP_ORDER)	/* 42 - message out of order */
+#define	RD_AP_UNAUTHOR	KRB_ET(RD_AP_UNAUTHOR)	/* 43 - unauthorized request */
+
+/* Values returned by get_pw_tkt */
+#define	GT_PW_OK	KRB_ET(KSUCCESS)	/*  0 - Got passwd chg tkt */
+#define	GT_PW_NULL	KRB_ET(GT_PW_NULL)	/* 51 - Current PW is null */
+#define	GT_PW_BADPW	KRB_ET(GT_PW_BADPW)	/* 52 - Wrong passwd */
+#define	GT_PW_PROT	KRB_ET(GT_PW_PROT)	/* 53 - Protocol Error */
+#define	GT_PW_KDCERR	KRB_ET(GT_PW_KDCERR)	/* 54 - Error ret by KDC */
+#define	GT_PW_NULLTKT	KRB_ET(GT_PW_NULLTKT)	/* 55 - Null tkt ret by KDC */
+
+/* Values returned by send_to_kdc */
+#define	SKDC_OK		KRB_ET(KSUCCESS)	/*  0 - Response received */
+#define	SKDC_RETRY	KRB_ET(SKDC_RETRY)	/* 56 - Retry count exceeded */
+#define	SKDC_CANT	KRB_ET(SKDC_CANT)	/* 57 - Can't send request */
+
+/*
+ * Values returned by get_intkt
+ * (can also return SKDC_* and KDC errors)
+ */
+
+#define	INTK_OK		KRB_ET(KSUCCESS)	/*  0 - Ticket obtained */
+#define	INTK_PW_NULL	KRB_ET(GT_PW_NULL)	/* 51 - Current PW is null */
+#define	INTK_W_NOTALL	KRB_ET(INTK_W_NOTALL)	/* 61 - Not ALL tkts retd */
+#define	INTK_BADPW	KRB_ET(INTK_BADPW)	/* 62 - Incorrect password */
+#define	INTK_PROT	KRB_ET(INTK_PROT)	/* 63 - Protocol Error */
+#define	INTK_ERR	KRB_ET(INTK_ERR)	/* 70 - Other error */
+
+/* Values returned by get_adtkt */
+#define AD_OK		KRB_ET(KSUCCESS)	/*  0 - Ticket Obtained */
+#define AD_NOTGT	KRB_ET(AD_NOTGT)	/* 71 - Don't have tgt */
+
+/* Error codes returned by ticket file utilities */
+#define	NO_TKT_FIL	KRB_ET(NO_TKT_FIL)	/* 76 - No ticket file found */
+#define	TKT_FIL_ACC	KRB_ET(TKT_FIL_ACC)	/* 77 - Can't acc tktfile */
+#define	TKT_FIL_LCK	KRB_ET(TKT_FIL_LCK)	/* 78 - Can't lck tkt file */
+#define	TKT_FIL_FMT	KRB_ET(TKT_FIL_FMT)	/* 79 - Bad tkt file format */
+#define	TKT_FIL_INI	KRB_ET(TKT_FIL_INI)	/* 80 - tf_init not called */
+
+/* Error code returned by kparse_name */
+#define	KNAME_FMT	KRB_ET(KNAME_FMT)	/* 81 - Bad krb name fmt */
+
+/* Error code returned by krb_mk_safe */
+#define	SAFE_PRIV_ERROR	(-1)			/* syscall error */
+
+/* Kerberos ticket flag field bit definitions */
+#define K_FLAG_ORDER    0       /* bit 0 --> lsb */
+#define K_FLAG_1                /* reserved */
+#define K_FLAG_2                /* reserved */
+#define K_FLAG_3                /* reserved */
+#define K_FLAG_4                /* reserved */
+#define K_FLAG_5                /* reserved */
+#define K_FLAG_6                /* reserved */
+#define K_FLAG_7                /* reserved, bit 7 --> msb */
+
+/* Are these needed anymore? */
+#ifdef	OLDNAMES
+#define krb_mk_req	mk_ap_req
+#define krb_rd_req	rd_ap_req
+#define krb_kntoln	an_to_ln
+#define krb_set_key	set_serv_key
+#define krb_get_cred	get_credentials
+#define krb_mk_priv	mk_private_msg
+#define krb_rd_priv	rd_private_msg
+#define krb_mk_safe	mk_safe_msg
+#define krb_rd_safe	rd_safe_msg
+#define krb_mk_err	mk_appl_err_msg
+#define krb_rd_err	rd_appl_err_msg
+#define krb_ck_repl	check_replay
+#define	krb_get_pw_in_tkt	get_in_tkt
+#define krb_get_svc_in_tkt	get_svc_in_tkt
+#define krb_get_pw_tkt		get_pw_tkt
+#define krb_realmofhost		krb_getrealm
+#define krb_get_phost		get_phost
+#define krb_get_krbhst		get_krbhst
+#define krb_get_lrealm		get_krbrlm
+#endif	/* OLDNAMES */
+
+/* Defines for krb_sendauth and krb_recvauth */
+
+#define	KOPT_DONT_MK_REQ 0x00000001 /* don't call krb_mk_req */
+#define	KOPT_DO_MUTUAL   0x00000002 /* do mutual auth */
+#define	KOPT_DONT_CANON  0x00000004 /* don't canonicalize inst as a host */
+
+#define	KRB_SENDAUTH_VLEN 8	    /* length for version strings */
+
+#ifdef ATHENA_COMPAT
+#define	KOPT_DO_OLDSTYLE 0x00000008 /* use the old-style protocol */
+#endif /* ATHENA_COMPAT */
+
+
+#ifdef _WIN32
+#define	TIME_GMT_UNIXSEC	win_time_gmt_unixsec((unsigned KRB4_32 *)0)
+#define	TIME_GMT_UNIXSEC_US(us)	win_time_gmt_unixsec((us))
+#define	CONVERT_TIME_EPOCH	win_time_get_epoch()
+#else
+/* until we do V4 compat under DOS, just turn this off */
+#define	_fmemcpy	memcpy
+#define	_fstrncpy	strncpy
+#define	far_fputs	fputs
+/* and likewise, just drag in the unix time interface */
+#define	TIME_GMT_UNIXSEC	unix_time_gmt_unixsec((unsigned KRB4_32 *)0)
+#define	TIME_GMT_UNIXSEC_US(us)	unix_time_gmt_unixsec((us))
+#define	CONVERT_TIME_EPOCH	((long)0)	/* Unix epoch is Krb epoch */
+#endif /* _WIN32 */
+
+/* Constants for KerberosProfileLib */
+#define	REALMS_V4_PROF_REALMS_SECTION		"v4 realms"
+#define	REALMS_V4_PROF_KDC			"kdc"
+#define	REALMS_V4_PROF_ADMIN_KDC		"admin_server"
+#define	REALMS_V4_PROF_KPASSWD_KDC		"kpasswd_server"
+#define	REALMS_V4_PROF_DOMAIN_SECTION		"v4 domain_realm"
+#define	REALMS_V4_PROF_LIBDEFAULTS_SECTION	"libdefaults"
+#define	REALMS_V4_PROF_LOCAL_REALM		"default_realm"
+#define	REALMS_V4_PROF_STK			"string_to_key_type"
+#define	REALMS_V4_MIT_STK			"mit_string_to_key"
+#define	REALMS_V4_AFS_STK			"afs_string_to_key"
+#define	REALMS_V4_COLUMBIA_STK			"columbia_string_to_key"
+#define	REALMS_V4_DEFAULT_REALM			"default_realm"
+#define	REALMS_V4_NO_ADDRESSES			"noaddresses"
+
+/* ask to disable IP address checking in the library */
+extern int krb_ignore_ip_address;
+
+/* Debugging printfs shouldn't even be compiled on many systems that don't
+   support printf!  Use it like  DEB (("Oops - %s\n", string));  */
+
+#ifdef DEBUG
+#define	DEB(x)	if (krb_debug) printf x
+extern int krb_debug;
+#else
+#define	DEB(x)	/* nothing */
+#endif
+
+/* Define a couple of function types including parameters.  These
+   are needed on MS-Windows to convert arguments of the function pointers
+   to the proper types during calls.  */
+
+typedef int (KRB5_CALLCONV *key_proc_type)
+	(char *, char *, char *,
+		    char *, C_Block);
+#define KEY_PROC_TYPE_DEFINED
+
+typedef int (KRB5_CALLCONV *decrypt_tkt_type)
+	(char *, char *, char *,
+		    char *, key_proc_type, KTEXT *);
+#define DECRYPT_TKT_TYPE_DEFINED
+
+extern struct _krb5_context * krb5__krb4_context;
+
+/*
+ * Function Prototypes for Kerberos V4.
+ */
+
+struct sockaddr_in;
+
+/* dest_tkt.c */
+int KRB5_CALLCONV dest_tkt
+	(void);
+/* err_txt.c */
+const char * KRB5_CALLCONV krb_get_err_text
+	(int errnum);
+/* g_ad_tkt.c */
+/* Previously not KRB5_CALLCONV */
+int KRB5_CALLCONV get_ad_tkt
+	(char *service, char *sinst, char *realm, int lifetime);
+/* g_admhst.c */
+int KRB5_CALLCONV krb_get_admhst
+	(char *host, char *realm, int idx);
+/* g_cred.c */
+int KRB5_CALLCONV krb_get_cred
+	(char *service, char *instance, char *realm,
+		   CREDENTIALS *c);
+/* g_in_tkt.c */
+/* Previously not KRB5_CALLCONV */
+int KRB5_CALLCONV krb_get_in_tkt
+	(char *k_user, char *instance, char *realm,
+		   char *service, char *sinst, int life,
+		   key_proc_type, decrypt_tkt_type, char *arg);
+#if KRB_PRIVATE
+/* Previously not KRB5_CALLCONV */
+int KRB5_CALLCONV krb_get_in_tkt_preauth
+	(char *k_user, char *instance, char *realm,
+		   char *service, char *sinst, int life,
+		   key_proc_type, decrypt_tkt_type, char *arg,
+		   char *preauth_p, int preauth_len);
+#endif
+/* From KfM */
+int KRB5_CALLCONV krb_get_in_tkt_creds(char *, char *, char *, char *, char *,
+    int, key_proc_type, decrypt_tkt_type, char *, CREDENTIALS *);
+
+/* g_krbhst.c */
+int KRB5_CALLCONV krb_get_krbhst
+	(char *host, const char *realm, int idx);
+/* g_krbrlm.c */
+int KRB5_CALLCONV krb_get_lrealm
+	(char *realm, int idx);
+/* g_phost.c */
+char * KRB5_CALLCONV krb_get_phost
+	(char * alias);
+/* get_pw_tkt */
+int KRB5_CALLCONV get_pw_tkt 
+        (char *, char *, char *, char *);
+/* g_pw_in_tkt.c */
+int KRB5_CALLCONV krb_get_pw_in_tkt
+	(char *k_user, char *instance, char *realm,
+		   char *service, char *sinstance,
+		   int life, char *password);
+#if KRB_PRIVATE
+int KRB5_CALLCONV krb_get_pw_in_tkt_preauth
+	(char *k_user, char *instance, char *realm,
+		   char *service, char *sinstance,
+		   int life, char *password);
+#endif
+int KRB5_CALLCONV
+krb_get_pw_in_tkt_creds(char *, char *, char *,
+	char *, char *, int, char *, CREDENTIALS *);
+
+/* g_svc_in_tkt.c */
+int KRB5_CALLCONV krb_get_svc_in_tkt
+	(char *k_user, char *instance, char *realm,
+		   char *service, char *sinstance,
+		   int life, char *srvtab);
+
+/* g_tf_fname.c */
+int KRB5_CALLCONV krb_get_tf_fullname
+	(const char *ticket_file, char *name, char *inst, char *realm);
+/* g_tf_realm.c */
+int KRB5_CALLCONV krb_get_tf_realm
+	(const char *ticket_file, char *realm);
+/* g_tkt_svc.c */
+int KRB5_CALLCONV krb_get_ticket_for_service
+	(char *serviceName,
+		   char *buf, unsigned KRB4_32 *buflen,
+		   int checksum, des_cblock, Key_schedule,
+		   char *version, int includeVersion);
+#if KRB_PRIVATE
+/* in_tkt.c */
+int KRB5_CALLCONV in_tkt
+	(char *name, char *inst);
+int KRB5_CALLCONV krb_in_tkt
+        (char *pname, char *pinst, char *realm);
+#endif
+
+/* kname_parse.c */
+int KRB5_CALLCONV kname_parse
+	(char *name, char *inst, char *realm,
+		   char *fullname);
+/* Merged from KfM */
+int KRB5_CALLCONV kname_unparse
+	(char *, const char *, const char *, const char *);
+
+int KRB5_CALLCONV k_isname
+        (char *);
+int KRB5_CALLCONV k_isinst
+        (char *);
+int KRB5_CALLCONV k_isrealm
+        (char *);
+
+
+/* kuserok.c */
+int KRB5_CALLCONV kuserok
+	(AUTH_DAT *kdata, char *luser);
+
+/* lifetime.c */
+KRB4_32 KRB5_CALLCONV krb_life_to_time
+	(KRB4_32 start, int life);
+int KRB5_CALLCONV krb_time_to_life
+	(KRB4_32 start, KRB4_32 end);
+
+/* mk_auth.c */
+int KRB5_CALLCONV krb_check_auth
+	(KTEXT, unsigned KRB4_32 cksum, MSG_DAT *,
+		   C_Block, Key_schedule,
+		   struct sockaddr_in * local_addr,
+		   struct sockaddr_in * foreign_addr);
+int KRB5_CALLCONV krb_mk_auth
+	(long k4_options, KTEXT ticket,
+		   char *service, char *inst, char *realm,
+		   unsigned KRB4_32 checksum, char *version, KTEXT buf);
+/* mk_err.c */
+long KRB5_CALLCONV krb_mk_err
+	(u_char *out, KRB4_32 k4_code, char *text);
+#if KRB_PRIVATE
+/* mk_preauth.c */
+int krb_mk_preauth
+	(char **preauth_p, int *preauth_len, key_proc_type,
+		   char *name, char *inst, char *realm, char *password,
+		   C_Block);
+void krb_free_preauth
+	(char * preauth_p, int len);
+#endif
+/* mk_priv.c */
+long KRB5_CALLCONV krb_mk_priv
+	(u_char *in, u_char *out,
+		   unsigned KRB4_32 length,
+		   Key_schedule, C_Block *,
+		   struct sockaddr_in * sender,
+		   struct sockaddr_in * receiver);
+/* mk_req.c */
+int KRB5_CALLCONV krb_mk_req
+	(KTEXT authent,
+		   char *service, char *instance, char *realm,
+		   KRB4_32 checksum);
+/* Merged from KfM */
+int KRB5_CALLCONV krb_mk_req_creds(KTEXT, CREDENTIALS *, KRB_INT32);
+
+/* Added CALLCONV (KfM exports w/o INTERFACE, but KfW doesn't export?) */
+int KRB5_CALLCONV krb_set_lifetime(int newval);
+
+/* mk_safe.c */
+long KRB5_CALLCONV krb_mk_safe
+	(u_char *in, u_char *out, unsigned KRB4_32 length,
+		   C_Block *,
+		   struct sockaddr_in *sender,
+		   struct sockaddr_in *receiver);
+#if KRB_PRIVATE
+/* netread.c */
+int krb_net_read
+	(int fd, char *buf, int len);
+/* netwrite.c */
+int krb_net_write
+	(int fd, char *buf, int len);
+/* pkt_clen.c */
+int pkt_clen
+	(KTEXT);
+#endif
+
+/* put_svc_key.c */
+int KRB5_CALLCONV put_svc_key
+	(char *sfile,
+		   char *name, char *inst, char *realm,
+		   int newvno, char *key);
+
+/* rd_err.c */
+int KRB5_CALLCONV krb_rd_err
+	(u_char *in, u_long in_length,
+		   long *k4_code, MSG_DAT *m_data);
+/* rd_priv.c */
+long KRB5_CALLCONV krb_rd_priv
+	(u_char *in,unsigned KRB4_32 in_length,
+		   Key_schedule, C_Block *,
+		   struct sockaddr_in *sender,
+		   struct sockaddr_in *receiver,
+		   MSG_DAT *m_data);
+/* rd_req.c */
+int KRB5_CALLCONV krb_rd_req
+	(KTEXT, char *service, char *inst,
+		   unsigned KRB4_32 from_addr, AUTH_DAT *,
+		   char *srvtab);
+/* Merged from KfM */
+int KRB5_CALLCONV
+krb_rd_req_int(KTEXT, char *, char *, KRB_UINT32, AUTH_DAT *, C_Block);
+
+/* rd_safe.c */
+long KRB5_CALLCONV krb_rd_safe
+	(u_char *in, unsigned KRB4_32 in_length,
+		   C_Block *,
+		   struct sockaddr_in *sender,
+		   struct sockaddr_in *receiver,
+		   MSG_DAT *m_data);
+/* rd_svc_key.c */
+int KRB5_CALLCONV read_service_key
+	(char *service, char *instance, char *realm,
+		   int kvno, char *file, char *key);
+int KRB5_CALLCONV get_service_key
+	(char *service, char *instance, char *realm,
+		   int *kvno, char *file, char *key);
+
+/* realmofhost.c */
+char * KRB5_CALLCONV krb_realmofhost
+	(char *host);
+/* recvauth.c */
+int KRB5_CALLCONV krb_recvauth
+	(long k4_options, int fd, KTEXT ticket,
+		   char *service, char *instance,
+		   struct sockaddr_in *foreign_addr,
+		   struct sockaddr_in *local_addr,
+		   AUTH_DAT *kdata, char *srvtab,
+		   Key_schedule schedule, char *version);
+/* sendauth.c */
+int KRB5_CALLCONV krb_sendauth
+        (long k4_options, int fd, KTEXT ticket,
+	 char *service, char *inst, char *realm,
+	 unsigned KRB4_32 checksum, MSG_DAT *msg_data,
+	 CREDENTIALS *cred, Key_schedule schedule, 
+	 struct sockaddr_in *laddr, struct sockaddr_in *faddr, 
+	 char *version);
+
+#if KRB_PRIVATE
+/* save_creds.c */
+int KRB5_CALLCONV krb_save_credentials
+	(char *service, char *instance, char *realm,
+		   C_Block session, int lifetime, int kvno,
+		   KTEXT ticket, long issue_date);
+/* send_to_kdc.c */
+/* XXX PRIVATE? KfM doesn't export. */
+int send_to_kdc
+	(KTEXT pkt, KTEXT rpkt, char *realm);
+#endif
+
+/* tkt_string.c */
+/* Used to return pointer to non-const char */
+const char * KRB5_CALLCONV tkt_string
+	(void);
+/* Previously not KRB5_CALLCONV, and previously took pointer to non-const. */
+void KRB5_CALLCONV krb_set_tkt_string
+	(const char *);
+
+#if KRB_PRIVATE
+/* tf_util.c */
+int KRB5_CALLCONV tf_init (const char *tf_name, int rw);
+
+int KRB5_CALLCONV tf_get_pname (char *p);
+
+int KRB5_CALLCONV tf_get_pinst (char *p);
+
+int KRB5_CALLCONV tf_get_cred (CREDENTIALS *c);
+
+void KRB5_CALLCONV tf_close (void);
+#endif
+
+#if KRB_PRIVATE
+/* unix_time.c */
+unsigned KRB4_32 KRB5_CALLCONV unix_time_gmt_unixsec 
+        (unsigned KRB4_32 *);
+
+/*
+ * Internal prototypes
+ */
+extern int krb_set_key
+	(char *key, int cvt);
+
+/* This is exported by KfM.  It was previously not KRB5_CALLCONV. */
+extern int KRB5_CALLCONV decomp_ticket
+	(KTEXT tkt, unsigned char *flags, char *pname,
+		   char *pinstance, char *prealm, unsigned KRB4_32 *paddress,
+		   C_Block session, int *life, unsigned KRB4_32 *time_sec,
+		   char *sname, char *sinstance, C_Block,
+		   Key_schedule key_s);
+
+
+extern void cr_err_reply(KTEXT pkt, char *pname, char *pinst, char *prealm,
+			 u_long time_ws, u_long e, char *e_string);
+
+extern int create_ciph(KTEXT c, C_Block session, char *service, 
+		       char *instance, char *realm, unsigned long life,
+		       int kvno, KTEXT tkt, unsigned long kdc_time, 
+		       C_Block key);
+
+
+extern int krb_create_ticket(KTEXT tkt, unsigned int flags, char *pname,
+			     char *pinstance, char *prealm, long paddress,
+			     char *session, int life, long time_sec, 
+			     char *sname, char *sinstance, C_Block key);
+
+#endif /* KRB_PRIVATE */
+
+/* This function is used by KEYFILE above.  Do not call it directly */
+extern char * krb__get_srvtabname(const char *);
+
+#if KRB_PRIVATE
+
+extern int krb_kntoln(AUTH_DAT *, char *);
+
+#ifdef KRB5_GENERAL__
+extern int krb_cr_tkt_krb5(KTEXT tkt, unsigned int flags, char *pname,
+			   char *pinstance, char *prealm, long paddress,
+			   char *session, int life, long time_sec, 
+			   char *sname, char *sinstance,  
+			   krb5_keyblock *k5key);
+
+extern int krb_set_key_krb5(krb5_context ctx, krb5_keyblock *key);
+
+#endif
+
+#endif /* KRB_PRIVATE */
+
+/*
+ * krb_change_password -- merged from KfM
+ */
+/* change_password.c */
+int KRB5_CALLCONV krb_change_password(char *, char *, char *, char *, char *);
+
+/*
+ * RealmsConfig-glue.c -- merged from KfM
+ */
+int KRB5_CALLCONV krb_get_profile(profile_t *);
+
+#ifdef _WIN32
+HINSTANCE get_lib_instance(void);
+unsigned int krb_get_notification_message(void);
+char * KRB5_CALLCONV krb_get_default_user(void);
+int KRB5_CALLCONV krb_set_default_user(char *);
+unsigned KRB4_32 win_time_gmt_unixsec(unsigned KRB4_32 *);
+long win_time_get_epoch(void);
+#endif
+
+#if TARGET_OS_MAC
+#	pragma options align=reset
+#endif
+
+KRBINT_END_DECLS
+
+#endif	/* KRB_DEFS */
diff --git a/mechglue/src/include/kerberosIV/krb_db.h b/mechglue/src/include/kerberosIV/krb_db.h
new file mode 100644
index 000000000..3e3b1dda6
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/krb_db.h
@@ -0,0 +1,119 @@
+/*
+ * include/kerberosIV/krb_db.h
+ *
+ * Copyright 1987, 1988, 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * spm		Project Athena  8/85 
+ *
+ * This file defines data structures for the kerberos
+ * authentication/authorization database. 
+ *
+ * They MUST correspond to those defined in *.rel 
+ */
+
+#ifndef KRB_DB_DEFS
+#define KRB_DB_DEFS
+
+#define KERB_M_NAME		"K"	/* Kerberos */
+#define KERB_M_INST		"M"	/* Master */
+#define KERB_DEFAULT_NAME	"default"
+#define KERB_DEFAULT_INST	""
+#define	DBM_FILE		"/kerberos/principal"
+
+/* this also defines the number of queue headers */
+#define KERB_DB_HASH_MODULO 64
+
+
+/* Arguments to kerb_dbl_lock() */
+
+#define KERB_DBL_EXCLUSIVE 1
+#define KERB_DBL_SHARED 0
+
+/* arguments to kerb_db_set_lockmode() */
+
+#define KERB_DBL_BLOCKING 0
+#define KERB_DBL_NONBLOCKING 1
+
+/* Principal defines the structure of a principal's name */
+
+typedef struct {
+    char    name[ANAME_SZ];
+    char    instance[INST_SZ];
+
+    unsigned long key_low;
+    unsigned long key_high;
+    unsigned long exp_date;
+    char    exp_date_txt[DATE_SZ];
+    unsigned long mod_date;
+    char    mod_date_txt[DATE_SZ];
+    unsigned short attributes;
+    unsigned char max_life;
+    unsigned char kdc_key_ver;
+    unsigned char key_version;
+
+    char    mod_name[ANAME_SZ];
+    char    mod_instance[INST_SZ];
+    char   *old;		/* cast to (Principal *); not in db,
+				 * ptr to old vals */
+}
+        Principal;
+
+typedef struct {
+    long    cpu;
+    long    elapsed;
+    long    dio;
+    long    pfault;
+    long    t_stamp;
+    long    n_retrieve;
+    long    n_replace;
+    long    n_append;
+    long    n_get_stat;
+    long    n_put_stat;
+}
+        DB_stat;
+
+/* Dba defines the structure of a database administrator */
+
+typedef struct {
+    char    name[ANAME_SZ];
+    char    instance[INST_SZ];
+    unsigned short attributes;
+    unsigned long exp_date;
+    char    exp_date_txt[DATE_SZ];
+    char   *old;	/*
+			 * cast to (Dba *); not in db, ptr to
+			 * old vals
+			 */
+}
+        Dba;
+
+#if 0
+extern int kerb_get_principal();
+extern int kerb_put_principal();
+extern int kerb_db_get_stat();
+extern int kerb_db_put_stat();
+extern int kerb_get_dba();
+extern int kerb_db_get_dba();
+#endif
+
+#endif /* KRB_DB_DEFS */
diff --git a/mechglue/src/include/kerberosIV/krbports.h b/mechglue/src/include/kerberosIV/krbports.h
new file mode 100644
index 000000000..5b4dc5641
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/krbports.h
@@ -0,0 +1,27 @@
+/* krbports.h -- fallback port numbers in case /etc/services isn't changed */
+/* used by: appl/bsd/rcp.c, rlogin.c, rsh.c, knetd.c
+            kadmin/kadm_ser_wrap.c, lib/kadm/kadm_cli_wrap.c
+	    lib/krb/send_to_kdc.c
+	    movemail/movemail.c, pfrom/popmail.c
+	    server/kerberos.c, slave/kprop.c, kpropd.c
+*/
+
+#define KRB_SHELL_PORT 544
+#define UCB_SHELL_PORT 514
+
+#define KLOGIN_PORT 543
+#define EKLOGIN_PORT 2105
+#define UCB_LOGIN_PORT 513
+
+#define KADM_PORT 751
+#define KERBEROS_PORT 750
+#define KERBEROS_SEC_PORT 88
+#define KRB_PROP_PORT 754
+
+#define KPOP_PORT 1109
+#define POP3_PORT 110
+
+#define KNETD_PORT 2053
+
+/* already in rkinit_private.h */
+#define RKINIT_PORT 2108
diff --git a/mechglue/src/include/kerberosIV/lsb_addr_cmp.h b/mechglue/src/include/kerberosIV/lsb_addr_cmp.h
new file mode 100644
index 000000000..573f2b46c
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/lsb_addr_cmp.h
@@ -0,0 +1,47 @@
+/*
+ * include/kerberosIV/lsb_addr_cmp.h
+ *
+ * Copyright 1988, 1995 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Comparison macros to emulate LSBFIRST comparison results of network
+ * byte-order quantities
+ */
+
+#include "mit-copyright.h"
+#ifndef LSB_ADDR_COMP_DEFS
+#define LSB_ADDR_COMP_DEFS
+
+/* #include "osconf.h" */
+
+/* note that if we don't explicitly know if we're LSBFIRST, the 
+   alternate code is byte order independent and will give the
+   right answer. */
+#ifdef LSBFIRST
+#define lsb_net_ulong_less(x,y) ((x < y) ? -1 : ((x > y) ? 1 : 0))
+#define lsb_net_ushort_less(x,y) ((x < y) ? -1 : ((x > y) ? 1 : 0))
+#else
+/* MSBFIRST */
+#define u_char_comp(x,y) \
+        (((x)>(y))?(1):(((x)==(y))?(0):(-1)))
+/* This is gross, but... */
+#define lsb_net_ulong_less(x, y) long_less_than((u_char *)&x, (u_char *)&y)
+#define lsb_net_ushort_less(x, y) short_less_than((u_char *)&x, (u_char *)&y)
+
+#define long_less_than(x,y) \
+        (u_char_comp((x)[3],(y)[3])?u_char_comp((x)[3],(y)[3]): \
+	 (u_char_comp((x)[2],(y)[2])?u_char_comp((x)[2],(y)[2]): \
+	  (u_char_comp((x)[1],(y)[1])?u_char_comp((x)[1],(y)[1]): \
+	   (u_char_comp((x)[0],(y)[0])))))
+#define short_less_than(x,y) \
+	  (u_char_comp((x)[1],(y)[1])?u_char_comp((x)[1],(y)[1]): \
+	   (u_char_comp((x)[0],(y)[0])))
+
+#endif /* LSBFIRST */
+
+/* For krb4 library internal use only.  */
+extern int krb4int_address_less (struct sockaddr_in *, struct sockaddr_in *);
+
+#endif /*  LSB_ADDR_COMP_DEFS */
diff --git a/mechglue/src/include/kerberosIV/mit-copyright.h b/mechglue/src/include/kerberosIV/mit-copyright.h
new file mode 100644
index 000000000..e00865769
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/mit-copyright.h
@@ -0,0 +1,23 @@
+/* 
+  Copyright (C) 1989 by the Massachusetts Institute of Technology
+
+   Export of this software from the United States of America may
+   require a specific license from the United States Government.
+   It is the responsibility of any person or organization contemplating
+   export to obtain such a license before exporting.
+
+WITHIN THAT CONSTRAINT, Permission to use, copy, modify, and
+distribute this software and its documentation for any purpose and
+without fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation, and that
+the name of M.I.T. not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission.  Furthermore if you modify this software you must label
+your software as modified software and not distribute it in such a
+fashion that it might be confused with the original M.I.T. software.
+M.I.T. makes no representations about the suitability of
+this software for any purpose.  It is provided "as is" without express
+or implied warranty.
+
+  */
diff --git a/mechglue/src/include/kerberosIV/prot.h b/mechglue/src/include/kerberosIV/prot.h
new file mode 100644
index 000000000..c927ac042
--- /dev/null
+++ b/mechglue/src/include/kerberosIV/prot.h
@@ -0,0 +1,323 @@
+/*
+ * include/kerberosIV/prot.h
+ *
+ * Copyright 1985-1994, 2001 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Prototypes for internal functions, mostly related to protocol
+ * encoding and decoding.
+ */
+
+#ifndef PROT_DEFS
+#define PROT_DEFS
+
+#define		KRB_PORT		750	/* PC's don't have
+						 * /etc/services */
+#define		KRB_PROT_VERSION 	4
+#define 	MAX_PKT_LEN		1000
+#define		MAX_TXT_LEN		1000
+
+/* Macro's to obtain various fields from a packet */
+
+#define pkt_version(packet)  (unsigned int) *(packet->dat)
+#define pkt_msg_type(packet) (unsigned int) *(packet->dat+1)
+#define pkt_a_name(packet)   (packet->dat+2)
+#define pkt_a_inst(packet)   \
+	(packet->dat+3+strlen((char *)pkt_a_name(packet)))
+#define pkt_a_realm(packet)  \
+	(pkt_a_inst(packet)+1+strlen((char *)pkt_a_inst(packet)))
+
+/* Macro to obtain realm from application request */
+#define apreq_realm(auth)     (auth->dat + 3)
+
+#define pkt_time_ws(packet) (char *) \
+        (packet->dat+5+strlen((char *)pkt_a_name(packet)) + \
+	 strlen((char *)pkt_a_inst(packet)) + \
+	 strlen((char *)pkt_a_realm(packet)))
+
+#define pkt_no_req(packet) (unsigned short) \
+        *(packet->dat+9+strlen((char *)pkt_a_name(packet)) + \
+	  strlen((char *)pkt_a_inst(packet)) + \
+	  strlen((char *)pkt_a_realm(packet)))
+#define pkt_x_date(packet) (char *) \
+        (packet->dat+10+strlen((char *)pkt_a_name(packet)) + \
+	 strlen((char *)pkt_a_inst(packet)) + \
+	 strlen((char *)pkt_a_realm(packet)))
+#define pkt_err_code(packet) ( (char *) \
+        (packet->dat+9+strlen((char *)pkt_a_name(packet)) + \
+	 strlen((char *)pkt_a_inst(packet)) + \
+	 strlen((char *)pkt_a_realm(packet))))
+#define pkt_err_text(packet) \
+        (packet->dat+13+strlen((char *)pkt_a_name(packet)) + \
+	 strlen((char *)pkt_a_inst(packet)) + \
+	 strlen((char *)pkt_a_realm(packet)))
+
+/*
+ * This remains here for the KDC to use for now, but will go away
+ * soon.
+ */
+
+#define     swap_u_long(x) {\
+ unsigned KRB4_32   _krb_swap_tmp[4];\
+ swab((char *)  &x,    ((char *)  _krb_swap_tmp) +2 ,2); \
+ swab(((char *) &x) +2,((char *)  _krb_swap_tmp),2); \
+ x = _krb_swap_tmp[0];   \
+                           }
+
+/*
+ * New byte swapping routines, much cleaner.
+ *
+ * Should also go away soon though.
+ */
+#define krb4_swab16(val)	((((val) >> 8)&0xFF) | ((val) << 8))
+#define krb4_swab32(val)	((((val)>>24)&0xFF) | (((val)>>8)&0xFF00) | \
+				  (((val)<<8)&0xFF0000) | ((val)<<24))
+
+/*
+ * Macros to encode integers into buffers.  These take a parameter
+ * that is a moving pointer of type (unsigned char *) into the buffer,
+ * and assume that the caller has already bounds-checked.
+ */
+#define KRB4_PUT32BE(p, val)			\
+do {						\
+    (p)[0] = ((KRB_UINT32)(val) >> 24) & 0xff;	\
+    (p)[1] = ((KRB_UINT32)(val) >> 16) & 0xff;	\
+    (p)[2] = ((KRB_UINT32)(val) >> 8)  & 0xff;	\
+    (p)[3] =  (KRB_UINT32)(val)        & 0xff;	\
+    (p) += 4;					\
+} while (0)
+
+#define KRB4_PUT32LE(p, val)			\
+do {						\
+    (p)[0] =  (KRB_UINT32)(val)        & 0xff;	\
+    (p)[1] = ((KRB_UINT32)(val) >> 8)  & 0xff;	\
+    (p)[2] = ((KRB_UINT32)(val) >> 16) & 0xff;	\
+    (p)[3] = ((KRB_UINT32)(val) >> 24) & 0xff;	\
+    (p) += 4;					\
+} while (0)
+
+#define KRB4_PUT32(p, val, le)			\
+do {						\
+    if (le)					\
+	KRB4_PUT32LE((p), (val));		\
+    else					\
+	KRB4_PUT32BE((p), (val));		\
+} while (0)
+
+#define KRB4_PUT16BE(p, val)			\
+do {						\
+    (p)[0] = ((KRB_UINT32)(val) >> 8) & 0xff;	\
+    (p)[1] =  (KRB_UINT32)(val)       & 0xff;	\
+    (p) += 2;					\
+} while (0)
+
+#define KRB4_PUT16LE(p, val)			\
+do {						\
+    (p)[0] =  (KRB_UINT32)(val)       & 0xff;	\
+    (p)[1] = ((KRB_UINT32)(val) >> 8) & 0xff;	\
+    (p) += 2;					\
+} while (0)
+
+#define KRB4_PUT16(p, val, le)			\
+do {						\
+    if (le)					\
+	KRB4_PUT16LE((p), (val));		\
+    else					\
+	KRB4_PUT16BE((p), (val));		\
+} while (0)
+
+/*
+ * Macros to get integers from a buffer.  These take a parameter that
+ * is a moving pointer of type (unsigned char *) into the buffer, and
+ * assume that the caller has already bounds-checked.  In addition,
+ * they assume that val is an unsigned type; ANSI leaves the semantics
+ * of unsigned -> signed conversion as implementation-defined, so it's
+ * unwise to depend on such.
+ */
+#define KRB4_GET32BE(val, p)			\
+do {						\
+    (val)  = (KRB_UINT32)(p)[0] << 24;		\
+    (val) |= (KRB_UINT32)(p)[1] << 16;		\
+    (val) |= (KRB_UINT32)(p)[2] << 8;		\
+    (val) |= (KRB_UINT32)(p)[3];		\
+    (p) += 4;					\
+} while (0)
+
+#define KRB4_GET32LE(val, p)			\
+do {						\
+    (val)  = (KRB_UINT32)(p)[0];		\
+    (val) |= (KRB_UINT32)(p)[1] << 8;		\
+    (val) |= (KRB_UINT32)(p)[2] << 16;		\
+    (val) |= (KRB_UINT32)(p)[3] << 24;		\
+    (p) += 4;					\
+} while(0)
+
+#define KRB4_GET32(val, p, le)			\
+do {						\
+    if (le)					\
+	KRB4_GET32LE((val), (p));		\
+    else					\
+	KRB4_GET32BE((val), (p));		\
+} while (0)
+
+#define KRB4_GET16BE(val, p)			\
+do {						\
+    (val)  = (KRB_UINT32)(p)[0] << 8;		\
+    (val) |= (KRB_UINT32)(p)[1];		\
+    (p) += 2;					\
+} while (0)
+
+#define KRB4_GET16LE(val, p)			\
+do {						\
+    (val)  = (KRB_UINT32)(p)[0];		\
+    (val) |= (KRB_UINT32)(p)[1] << 8;		\
+    (p) += 2;					\
+} while (0)
+
+#define KRB4_GET16(val, p, le)			\
+do {						\
+    if (le)					\
+	KRB4_GET16LE((val), (p));		\
+    else					\
+	KRB4_GET16BE((val), (p));		\
+} while (0)
+
+/* Routines to create and read packets may be found in prot.c */
+
+KTEXT create_auth_reply(char *, char *, char *, long, int, 
+			unsigned long, int, KTEXT);
+KTEXT create_death_packet(char *);
+KTEXT pkt_cipher(KTEXT);
+
+/* getst.c */
+int krb4int_getst(int, char *, int);
+
+/* strnlen.c */
+extern int KRB5_CALLCONV krb4int_strnlen(const char *, int);
+
+/* prot_client.c */
+extern int KRB5_CALLCONV krb4prot_encode_kdc_request(
+    char *, char *, char *,
+    KRB4_32, int,
+    char *, char *,
+    char *, int, int, int,
+    KTEXT);
+extern int KRB5_CALLCONV krb4prot_decode_kdc_reply(
+    KTEXT,
+    int *,
+    char *, char *, char *,
+    long *, int *, unsigned long *, int *, KTEXT);
+extern int KRB5_CALLCONV krb4prot_decode_ciph(
+    KTEXT, int,
+    C_Block,
+    char *, char *, char *,
+    int *, int *, KTEXT, unsigned long *);
+extern int KRB5_CALLCONV krb4prot_encode_apreq(
+    int, char *,
+    KTEXT, KTEXT,
+    int, int, KTEXT);
+extern int KRB5_CALLCONV krb4prot_encode_authent(
+    char *, char *, char *,
+    KRB4_32,
+    int, long,
+    int, int le,
+    KTEXT pkt);
+extern int KRB5_CALLCONV krb4prot_decode_error(
+    KTEXT, int *,
+    char *, char *, char *,
+    unsigned long *, unsigned long *, char *);
+
+/* prot_common.c */
+extern int KRB5_CALLCONV krb4prot_encode_naminstrlm(
+    char *, char *, char *,
+    int, KTEXT, unsigned char **);
+extern int KRB5_CALLCONV krb4prot_decode_naminstrlm(
+    KTEXT, unsigned char **,
+    char *, char *, char *);
+extern int KRB5_CALLCONV krb4prot_decode_header(
+    KTEXT, int *, int *, int *);
+
+/* prot_kdc.c */
+extern int KRB5_CALLCONV krb4prot_encode_kdc_reply(
+    char *, char *, char *,
+    long, int, unsigned long,
+    int, KTEXT, int, int, KTEXT);
+extern int KRB5_CALLCONV krb4prot_encode_ciph(
+    C_Block,
+    char *, char *, char *,
+    unsigned long, int, KTEXT, unsigned long,
+    int, int, KTEXT);
+extern int KRB5_CALLCONV krb4prot_encode_tkt(
+    unsigned int,
+    char *, char *, char *,
+    unsigned long,
+    char *, int, long,
+    char *, char *,
+    int, int, KTEXT tkt);
+extern int KRB5_CALLCONV krb4prot_encode_err_reply(
+    char *, char *, char *,
+    unsigned long, unsigned long, char *,
+    int, int, KTEXT);
+extern int KRB5_CALLCONV krb4prot_decode_kdc_request(
+    KTEXT,
+    int *, char *, char *, char *,
+    long *, int *, char *sname, char *sinst);
+
+/* Message types , always leave lsb for byte order */
+
+#define		AUTH_MSG_KDC_REQUEST			 1<<1
+#define 	AUTH_MSG_KDC_REPLY			 2<<1
+#define		AUTH_MSG_APPL_REQUEST			 3<<1
+#define		AUTH_MSG_APPL_REQUEST_MUTUAL		 4<<1
+#define		AUTH_MSG_ERR_REPLY			 5<<1
+#define		AUTH_MSG_PRIVATE			 6<<1
+#define		AUTH_MSG_SAFE				 7<<1
+#define		AUTH_MSG_APPL_ERR			 8<<1
+#define 	AUTH_MSG_DIE				63<<1
+
+/* values for kerb error codes */
+
+#define		KERB_ERR_OK				 0
+#define		KERB_ERR_NAME_EXP			 1
+#define		KERB_ERR_SERVICE_EXP			 2
+#define		KERB_ERR_AUTH_EXP			 3
+#define		KERB_ERR_PKT_VER			 4
+#define		KERB_ERR_NAME_MAST_KEY_VER		 5
+#define		KERB_ERR_SERV_MAST_KEY_VER		 6
+#define		KERB_ERR_BYTE_ORDER			 7
+#define		KERB_ERR_PRINCIPAL_UNKNOWN		 8
+#define		KERB_ERR_PRINCIPAL_NOT_UNIQUE		 9
+#define		KERB_ERR_NULL_KEY			10
+/* Cygnus extensions for Preauthentication */
+#define         KERB_ERR_PREAUTH_SHORT			11
+#define		KERB_ERR_PREAUTH_MISMATCH		12
+
+/* Return codes from krb4prot_ encoders/decoders */
+
+#define		KRB4PROT_OK				0
+#define		KRB4PROT_ERR_UNDERRUN			1
+#define		KRB4PROT_ERR_OVERRUN			2
+#define		KRB4PROT_ERR_PROT_VERS			3
+#define		KRB4PROT_ERR_MSG_TYPE			4
+#define		KRB4PROT_ERR_GENERIC			255
+
+#endif /* PROT_DEFS */
diff --git a/mechglue/src/include/krb5.hin b/mechglue/src/include/krb5.hin
new file mode 100644
index 000000000..eaaedec8f
--- /dev/null
+++ b/mechglue/src/include/krb5.hin
@@ -0,0 +1,2550 @@
+/*
+ * include/krb5.h
+ *
+ * Copyright 1989,1990,1995,2001, 2003  by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.	Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * General definitions for Kerberos version 5.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef KRB5_GENERAL__
+#define KRB5_GENERAL__
+
+/* By default, do not expose deprecated interfaces. */
+#ifndef KRB5_DEPRECATED
+#define KRB5_DEPRECATED 0
+#endif
+/* Do not expose private interfaces.  Build system will override. */
+#ifndef KRB5_PRIVATE
+#define KRB5_PRIVATE 0
+#endif
+
+#if defined(__MACH__) && defined(__APPLE__)
+#	include <TargetConditionals.h>
+#    if TARGET_RT_MAC_CFM
+#	error "Use KfM 4.0 SDK headers for CFM compilation."
+#    endif
+#endif
+
+#if defined(_MSDOS) || defined(_WIN32)
+#include <win-mac.h>
+#endif
+
+#ifndef KRB5_CONFIG__
+#ifndef KRB5_CALLCONV
+#define KRB5_CALLCONV
+#define KRB5_CALLCONV_C
+#endif /* !KRB5_CALLCONV */
+#endif /* !KRB5_CONFIG__ */
+
+#ifndef KRB5_CALLCONV_WRONG
+#define KRB5_CALLCONV_WRONG
+#endif
+
+#ifndef THREEPARAMOPEN
+#define THREEPARAMOPEN(x,y,z) open(x,y,z)
+#endif
+
+#define KRB5_OLD_CRYPTO
+
+#include <stdlib.h>
+#include <limits.h>		/* for *_MAX */
+
+#ifndef KRB5INT_BEGIN_DECLS
+#if defined(__cplusplus)
+#define KRB5INT_BEGIN_DECLS	extern "C" {
+#define KRB5INT_END_DECLS	}
+#else
+#define KRB5INT_BEGIN_DECLS
+#define KRB5INT_END_DECLS
+#endif
+#endif
+
+KRB5INT_BEGIN_DECLS
+
+#if TARGET_OS_MAC
+#    pragma options align=mac68k
+#endif
+
+/* from profile.h */
+struct _profile_t;
+/* typedef struct _profile_t *profile_t; */
+
+/*
+ * begin wordsize.h
+ */
+
+/*
+ * Word-size related definition.
+ */
+
+typedef	unsigned char	krb5_octet;
+
+#if INT_MAX == 0x7fff
+typedef	int	krb5_int16;
+typedef	unsigned int	krb5_ui_2;
+#elif SHRT_MAX == 0x7fff
+typedef	short	krb5_int16;
+typedef	unsigned short	krb5_ui_2;
+#else
+#error undefined 16 bit type
+#endif
+
+#if INT_MAX == 0x7fffffffL
+typedef	int	krb5_int32;
+typedef	unsigned int	krb5_ui_4;
+#elif LONG_MAX == 0x7fffffffL
+typedef	long	krb5_int32;
+typedef	unsigned long	krb5_ui_4;
+#elif SHRT_MAX == 0x7fffffffL
+typedef	short	krb5_int32;
+typedef	unsigned short	krb5_ui_4;
+#else
+#error: undefined 32 bit type
+#endif
+
+#define VALID_INT_BITS	  INT_MAX
+#define VALID_UINT_BITS	  UINT_MAX
+
+#define KRB5_INT32_MAX	2147483647
+/* this strange form is necessary since - is a unary operator, not a sign
+   indicator */
+#define KRB5_INT32_MIN	(-KRB5_INT32_MAX-1)
+
+#define KRB5_INT16_MAX 65535	
+/* this strange form is necessary since - is a unary operator, not a sign
+   indicator */
+#define KRB5_INT16_MIN	(-KRB5_INT16_MAX-1)
+
+/*
+ * end wordsize.h
+ */
+
+/*
+ * begin "base-defs.h"
+ */
+
+/*
+ * Basic definitions for Kerberos V5 library
+ */
+
+#ifndef FALSE
+#define	FALSE	0
+#endif
+#ifndef TRUE
+#define	TRUE	1
+#endif
+
+typedef	unsigned int krb5_boolean;
+typedef	unsigned int krb5_msgtype;	
+typedef	unsigned int krb5_kvno;	
+
+typedef	krb5_int32 krb5_addrtype;
+typedef krb5_int32 krb5_enctype;
+typedef krb5_int32 krb5_cksumtype;
+typedef krb5_int32 krb5_authdatatype;
+typedef krb5_int32 krb5_keyusage;
+
+typedef krb5_int32	krb5_preauthtype; /* This may change, later on */
+typedef	krb5_int32	krb5_flags;
+typedef krb5_int32	krb5_timestamp;
+typedef	krb5_int32	krb5_error_code;
+typedef krb5_int32	krb5_deltat;
+
+typedef krb5_error_code	krb5_magic;
+
+typedef struct _krb5_data {
+	krb5_magic magic;
+	unsigned int length;
+	char *data;
+} krb5_data;
+
+/* 
+ * Hack length for crypto library to use the afs_string_to_key It is
+ * equivalent to -1 without possible sign extension 
+ * We also overload for an unset salt type length - which is also -1, but
+ * hey, why not....
+*/
+#define SALT_TYPE_AFS_LENGTH UINT_MAX
+#define SALT_TYPE_NO_LENGTH  UINT_MAX
+
+typedef	void * krb5_pointer;
+typedef void const * krb5_const_pointer;
+
+typedef struct krb5_principal_data {
+    krb5_magic magic;
+    krb5_data realm;
+    krb5_data *data;		/* An array of strings */
+    krb5_int32 length;
+    krb5_int32 type;
+} krb5_principal_data;
+
+typedef	krb5_principal_data * krb5_principal;
+
+/*
+ * Per V5 spec on definition of principal types
+ */
+
+/* Name type not known */
+#define KRB5_NT_UNKNOWN		0
+/* Just the name of the principal as in DCE, or for users */
+#define KRB5_NT_PRINCIPAL	1
+/* Service and other unique instance (krbtgt) */
+#define KRB5_NT_SRV_INST	2
+/* Service with host name as instance (telnet, rcommands) */
+#define KRB5_NT_SRV_HST		3
+/* Service with host as remaining components */
+#define KRB5_NT_SRV_XHST	4
+/* Unique ID */
+#define KRB5_NT_UID		5
+
+/* constant version thereof: */
+typedef const krb5_principal_data *krb5_const_principal;
+
+#define krb5_princ_realm(context, princ) (&(princ)->realm)
+#define krb5_princ_set_realm(context, princ,value) ((princ)->realm = *(value))
+#define krb5_princ_set_realm_length(context, princ,value) (princ)->realm.length = (value)
+#define krb5_princ_set_realm_data(context, princ,value) (princ)->realm.data = (value)
+#define	krb5_princ_size(context, princ) (princ)->length
+#define	krb5_princ_type(context, princ) (princ)->type
+#define	krb5_princ_name(context, princ) (princ)->data
+#define	krb5_princ_component(context, princ,i)		\
+	    (((i) < krb5_princ_size(context, princ))	\
+	     ? (princ)->data + (i)			\
+	     : NULL)
+
+/*
+ * end "base-defs.h"
+ */
+
+/*
+ * begin "hostaddr.h"
+ */
+
+/* structure for address */
+typedef struct _krb5_address {
+    krb5_magic magic;
+    krb5_addrtype addrtype;
+    unsigned int length;
+    krb5_octet *contents;
+} krb5_address;
+
+/* per Kerberos v5 protocol spec */
+#define	ADDRTYPE_INET		0x0002
+#define	ADDRTYPE_CHAOS		0x0005
+#define	ADDRTYPE_XNS		0x0006
+#define	ADDRTYPE_ISO		0x0007
+#define ADDRTYPE_DDP		0x0010
+#define ADDRTYPE_INET6		0x0018
+/* not yet in the spec... */
+#define ADDRTYPE_ADDRPORT	0x0100
+#define ADDRTYPE_IPPORT		0x0101
+
+/* macros to determine if a type is a local type */
+#define ADDRTYPE_IS_LOCAL(addrtype) (addrtype & 0x8000)
+
+/*
+ * end "hostaddr.h"
+ */
+
+
+struct _krb5_context;
+typedef struct _krb5_context * krb5_context;
+
+struct _krb5_auth_context;
+typedef struct _krb5_auth_context * krb5_auth_context;
+
+struct _krb5_cryptosystem_entry;
+
+/*
+ * begin "encryption.h"
+ */
+
+typedef struct _krb5_keyblock {
+    krb5_magic magic;
+    krb5_enctype enctype;
+    unsigned int length;
+    krb5_octet *contents;
+} krb5_keyblock;
+
+#ifdef KRB5_OLD_CRYPTO
+typedef struct _krb5_encrypt_block {
+    krb5_magic magic;
+    krb5_enctype crypto_entry;		/* to call krb5_encrypt_size, you need
+					   this.  it was a pointer, but it
+					   doesn't have to be.  gross. */
+    krb5_keyblock *key;
+} krb5_encrypt_block;
+#endif
+
+typedef struct _krb5_checksum {
+    krb5_magic magic;
+    krb5_cksumtype checksum_type;	/* checksum type */
+    unsigned int length;
+    krb5_octet *contents;
+} krb5_checksum;
+
+typedef struct _krb5_enc_data {
+    krb5_magic magic;
+    krb5_enctype enctype;
+    krb5_kvno kvno;
+    krb5_data ciphertext;
+} krb5_enc_data;
+
+/* per Kerberos v5 protocol spec */
+#define	ENCTYPE_NULL		0x0000
+#define	ENCTYPE_DES_CBC_CRC	0x0001	/* DES cbc mode with CRC-32 */
+#define	ENCTYPE_DES_CBC_MD4	0x0002	/* DES cbc mode with RSA-MD4 */
+#define	ENCTYPE_DES_CBC_MD5	0x0003	/* DES cbc mode with RSA-MD5 */
+#define	ENCTYPE_DES_CBC_RAW	0x0004	/* DES cbc mode raw */
+/* XXX deprecated? */
+#define	ENCTYPE_DES3_CBC_SHA	0x0005	/* DES-3 cbc mode with NIST-SHA */
+#define	ENCTYPE_DES3_CBC_RAW	0x0006	/* DES-3 cbc mode raw */
+#define ENCTYPE_DES_HMAC_SHA1	0x0008
+#define ENCTYPE_DES3_CBC_SHA1	0x0010
+#define ENCTYPE_AES128_CTS_HMAC_SHA1_96	0x0011
+#define ENCTYPE_AES256_CTS_HMAC_SHA1_96	0x0012
+#define ENCTYPE_ARCFOUR_HMAC	0x0017
+#define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018
+#define ENCTYPE_UNKNOWN		0x01ff
+
+#define	CKSUMTYPE_CRC32		0x0001
+#define	CKSUMTYPE_RSA_MD4	0x0002
+#define	CKSUMTYPE_RSA_MD4_DES	0x0003
+#define	CKSUMTYPE_DESCBC	0x0004
+/* des-mac-k */
+/* rsa-md4-des-k */
+#define	CKSUMTYPE_RSA_MD5	0x0007
+#define	CKSUMTYPE_RSA_MD5_DES	0x0008
+#define CKSUMTYPE_NIST_SHA	0x0009
+#define CKSUMTYPE_HMAC_SHA1_DES3	0x000c
+#define CKSUMTYPE_HMAC_SHA1_96_AES128	0x000f
+#define CKSUMTYPE_HMAC_SHA1_96_AES256	0x0010
+#define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /*Microsoft md5 hmac cksumtype*/
+
+/* The following are entropy source designations. Whenever
+ * krb5_C_random_add_entropy is called, one of these source  ids is passed
+ * in.  This  allows the library  to better estimate bits of
+ * entropy in the sample and to keep track of what sources of entropy have
+ * contributed enough entropy.  Sources marked internal MUST NOT be
+ * used by applications outside the Kerberos library
+*/
+
+enum {
+  KRB5_C_RANDSOURCE_OLDAPI = 0, /*calls to krb5_C_RANDOM_SEED (INTERNAL)*/
+  KRB5_C_RANDSOURCE_OSRAND = 1, /* /dev/random or equivalent (internal)*/
+  KRB5_C_RANDSOURCE_TRUSTEDPARTY = 2, /* From KDC or other trusted party*/
+  /*This source should be used carefully; data in this category
+   * should be from a third party trusted to give random bits
+   * For example keys issued by the KDC in the application server.
+   */
+  KRB5_C_RANDSOURCE_TIMING = 3, /* Timing of operations*/
+  KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL = 4, /*Protocol data possibly from attacker*/
+  KRB5_C_RANDSOURCE_MAX = 5 /*Do not use; maximum source ID*/
+};
+
+#ifndef krb5_roundup
+/* round x up to nearest multiple of y */
+#define krb5_roundup(x, y) ((((x) + (y) - 1)/(y))*(y))
+#endif /* roundup */
+
+/* macro function definitions to help clean up code */
+
+#if 1
+#define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
+#define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
+#else
+#define krb5_x(ptr,args) ((*(ptr)) args)
+#define krb5_xc(ptr,args) ((*(ptr)) args)
+#endif
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_encrypt
+    (krb5_context context, const krb5_keyblock *key,
+		    krb5_keyusage usage, const krb5_data *cipher_state,
+		    const krb5_data *input, krb5_enc_data *output);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_decrypt
+    (krb5_context context, const krb5_keyblock *key,
+		    krb5_keyusage usage, const krb5_data *cipher_state,
+		    const krb5_enc_data *input, krb5_data *output);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_encrypt_length
+    (krb5_context context, krb5_enctype enctype,
+		    size_t inputlen, size_t *length);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_block_size
+    (krb5_context context, krb5_enctype enctype,
+		    size_t *blocksize);
+
+krb5_error_code KRB5_CALLCONV
+	krb5_c_init_state
+(krb5_context context,
+const krb5_keyblock *key, krb5_keyusage usage,
+krb5_data *new_state);
+
+krb5_error_code KRB5_CALLCONV
+	krb5_c_free_state
+(krb5_context context, const krb5_keyblock *key, krb5_data *state);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_prf (krb5_context, const krb5_keyblock *,
+		krb5_data *in, krb5_data *out);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_prf_length (krb5_context, krb5_enctype, size_t *outlen);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_make_random_key
+    (krb5_context context, krb5_enctype enctype,
+		    krb5_keyblock *k5_random_key);
+
+/* Register a new entropy sample  with the PRNG. may cause
+* the PRNG to be reseeded, although this is not guaranteed.  See previous randsource definitions
+* for information on how each source should be used.
+*/
+krb5_error_code KRB5_CALLCONV
+	krb5_c_random_add_entropy
+(krb5_context context, unsigned int  randsource_id, const krb5_data *data);
+
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_random_make_octets
+    (krb5_context context, krb5_data *data);
+
+/*
+* Collect entropy from the OS if possible. strong requests that as strong 
+* of a source of entropy  as available be used.  Setting strong may 
+* increase the probability of blocking and should not  be used for normal 
+* applications.  Good uses include seeding the PRNG for kadmind
+* and realm setup.
+* If successful is non-null, then successful is set to 1 if the OS provided
+* entropy else zero.
+*/
+krb5_error_code KRB5_CALLCONV
+krb5_c_random_os_entropy
+(krb5_context context, int strong, int *success);
+
+/*deprecated*/ krb5_error_code KRB5_CALLCONV
+    krb5_c_random_seed
+    (krb5_context context, krb5_data *data);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_string_to_key
+    (krb5_context context, krb5_enctype enctype,
+		    const krb5_data *string, const krb5_data *salt,
+		    krb5_keyblock *key);
+krb5_error_code KRB5_CALLCONV
+krb5_c_string_to_key_with_params(krb5_context context,
+				 krb5_enctype enctype,
+				 const krb5_data *string,
+				 const krb5_data *salt,
+				 const krb5_data *params,
+				 krb5_keyblock *key);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_enctype_compare
+    (krb5_context context, krb5_enctype e1, krb5_enctype e2,
+		    krb5_boolean *similar);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_make_checksum
+    (krb5_context context, krb5_cksumtype cksumtype,
+		    const krb5_keyblock *key, krb5_keyusage usage,
+		    const krb5_data *input, krb5_checksum *cksum);
+    
+krb5_error_code KRB5_CALLCONV
+    krb5_c_verify_checksum
+    (krb5_context context, 
+		    const krb5_keyblock *key, krb5_keyusage usage,
+		    const krb5_data *data,
+		    const krb5_checksum *cksum,
+		    krb5_boolean *valid);
+    
+krb5_error_code KRB5_CALLCONV
+    krb5_c_checksum_length
+    (krb5_context context, krb5_cksumtype cksumtype,
+		    size_t *length);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_keyed_checksum_types
+    (krb5_context context, krb5_enctype enctype, 
+		    unsigned int *count, krb5_cksumtype **cksumtypes);
+
+#define KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS		1
+#define KRB5_KEYUSAGE_KDC_REP_TICKET		2
+#define KRB5_KEYUSAGE_AS_REP_ENCPART		3
+#define KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY	4
+#define KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY		5
+#define KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM	6
+#define KRB5_KEYUSAGE_TGS_REQ_AUTH		7
+#define KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY	8
+#define KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY	9
+#define KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM		10
+#define KRB5_KEYUSAGE_AP_REQ_AUTH		11
+#define KRB5_KEYUSAGE_AP_REP_ENCPART		12
+#define KRB5_KEYUSAGE_KRB_PRIV_ENCPART		13
+#define KRB5_KEYUSAGE_KRB_CRED_ENCPART		14
+#define KRB5_KEYUSAGE_KRB_SAFE_CKSUM		15
+#define KRB5_KEYUSAGE_APP_DATA_ENCRYPT		16
+#define KRB5_KEYUSAGE_APP_DATA_CKSUM		17
+#define KRB5_KEYUSAGE_KRB_ERROR_CKSUM		18
+#define KRB5_KEYUSAGE_AD_KDCISSUED_CKSUM	19
+#define KRB5_KEYUSAGE_AD_MTE			20
+#define KRB5_KEYUSAGE_AD_ITE			21
+
+/* XXX need to register these */
+
+#define KRB5_KEYUSAGE_GSS_TOK_MIC		22
+#define KRB5_KEYUSAGE_GSS_TOK_WRAP_INTEG	23
+#define KRB5_KEYUSAGE_GSS_TOK_WRAP_PRIV		24
+
+/* Defined in hardware preauth draft */
+
+#define KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM	25
+#define KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID	26
+#define KRB5_KEYUSAGE_PA_SAM_RESPONSE		27
+
+krb5_boolean KRB5_CALLCONV krb5_c_valid_enctype
+	(krb5_enctype ktype);
+krb5_boolean KRB5_CALLCONV krb5_c_valid_cksumtype
+	(krb5_cksumtype ctype);
+krb5_boolean KRB5_CALLCONV krb5_c_is_coll_proof_cksum
+	(krb5_cksumtype ctype);
+krb5_boolean KRB5_CALLCONV krb5_c_is_keyed_cksum
+	(krb5_cksumtype ctype);
+
+#if KRB5_PRIVATE
+/* Use the above four instead.  */
+krb5_boolean KRB5_CALLCONV valid_enctype
+	(krb5_enctype ktype);
+krb5_boolean KRB5_CALLCONV valid_cksumtype
+	(krb5_cksumtype ctype);
+krb5_boolean KRB5_CALLCONV is_coll_proof_cksum
+	(krb5_cksumtype ctype);
+krb5_boolean KRB5_CALLCONV is_keyed_cksum
+	(krb5_cksumtype ctype);
+#endif
+
+#ifdef KRB5_OLD_CRYPTO
+/*
+ * old cryptosystem routine prototypes.  These are now layered
+ * on top of the functions above.
+ */
+krb5_error_code KRB5_CALLCONV krb5_encrypt
+	(krb5_context context,
+		krb5_const_pointer inptr,
+		krb5_pointer outptr,
+		size_t size,
+		krb5_encrypt_block * eblock,
+		krb5_pointer ivec);
+krb5_error_code KRB5_CALLCONV krb5_decrypt
+	(krb5_context context,
+		krb5_const_pointer inptr,
+		krb5_pointer outptr,
+		size_t size,
+		krb5_encrypt_block * eblock,
+		krb5_pointer ivec);
+krb5_error_code KRB5_CALLCONV krb5_process_key
+	(krb5_context context,
+		krb5_encrypt_block * eblock,
+		const krb5_keyblock * key);
+krb5_error_code KRB5_CALLCONV krb5_finish_key
+	(krb5_context context,
+		krb5_encrypt_block * eblock);
+krb5_error_code KRB5_CALLCONV krb5_string_to_key
+	(krb5_context context,
+		const krb5_encrypt_block * eblock,
+		krb5_keyblock * keyblock,
+		const krb5_data * data,
+		const krb5_data * salt);
+krb5_error_code KRB5_CALLCONV krb5_init_random_key
+	(krb5_context context,
+		const krb5_encrypt_block * eblock,
+		const krb5_keyblock * keyblock,
+		krb5_pointer * ptr);
+krb5_error_code KRB5_CALLCONV krb5_finish_random_key
+	(krb5_context context,
+		const krb5_encrypt_block * eblock,
+		krb5_pointer * ptr);
+krb5_error_code KRB5_CALLCONV krb5_random_key
+	(krb5_context context,
+		const krb5_encrypt_block * eblock,
+		krb5_pointer ptr,
+		krb5_keyblock ** keyblock);
+krb5_enctype KRB5_CALLCONV krb5_eblock_enctype
+	(krb5_context context,
+		const krb5_encrypt_block * eblock);
+krb5_error_code KRB5_CALLCONV krb5_use_enctype
+	(krb5_context context,
+		krb5_encrypt_block * eblock,
+		krb5_enctype enctype);
+size_t KRB5_CALLCONV krb5_encrypt_size
+	(size_t length,
+		krb5_enctype crypto);
+size_t KRB5_CALLCONV krb5_checksum_size
+	(krb5_context context,
+		krb5_cksumtype ctype);
+krb5_error_code KRB5_CALLCONV krb5_calculate_checksum
+	(krb5_context context,
+		krb5_cksumtype ctype,
+		krb5_const_pointer in, size_t in_length,
+		krb5_const_pointer seed, size_t seed_length,
+		krb5_checksum * outcksum);
+krb5_error_code KRB5_CALLCONV krb5_verify_checksum
+	(krb5_context context,
+		krb5_cksumtype ctype,
+		const krb5_checksum * cksum,
+		krb5_const_pointer in, size_t in_length,
+		krb5_const_pointer seed, size_t seed_length);
+
+#if KRB5_PRIVATE
+krb5_error_code KRB5_CALLCONV krb5_random_confounder
+	(size_t, krb5_pointer);
+
+krb5_error_code krb5_encrypt_data
+	(krb5_context context, krb5_keyblock *key, 
+		krb5_pointer ivec, krb5_data *data, 
+		krb5_enc_data *enc_data);
+
+krb5_error_code krb5_decrypt_data
+	(krb5_context context, krb5_keyblock *key, 
+		krb5_pointer ivec, krb5_enc_data *data, 
+		krb5_data *enc_data);
+#endif
+
+#endif /* KRB5_OLD_CRYPTO */
+
+/*
+ * end "encryption.h"
+ */
+
+/*
+ * begin "fieldbits.h"
+ */
+
+/* kdc_options for kdc_request */
+/* options is 32 bits; each host is responsible to put the 4 bytes
+   representing these bits into net order before transmission */
+/* #define	KDC_OPT_RESERVED	0x80000000 */
+#define	KDC_OPT_FORWARDABLE		0x40000000
+#define	KDC_OPT_FORWARDED		0x20000000
+#define	KDC_OPT_PROXIABLE		0x10000000
+#define	KDC_OPT_PROXY			0x08000000
+#define	KDC_OPT_ALLOW_POSTDATE		0x04000000
+#define	KDC_OPT_POSTDATED		0x02000000
+/* #define	KDC_OPT_UNUSED		0x01000000 */
+#define	KDC_OPT_RENEWABLE		0x00800000
+/* #define	KDC_OPT_UNUSED		0x00400000 */
+/* #define	KDC_OPT_RESERVED	0x00200000 */
+/* #define	KDC_OPT_RESERVED	0x00100000 */
+/* #define	KDC_OPT_RESERVED	0x00080000 */
+/* #define	KDC_OPT_RESERVED	0x00040000 */
+#define	KDC_OPT_REQUEST_ANONYMOUS	0x00020000
+/* #define	KDC_OPT_RESERVED	0x00010000 */
+/* #define	KDC_OPT_RESERVED	0x00008000 */
+/* #define	KDC_OPT_RESERVED	0x00004000 */
+/* #define	KDC_OPT_RESERVED	0x00002000 */
+/* #define	KDC_OPT_RESERVED	0x00001000 */
+/* #define	KDC_OPT_RESERVED	0x00000800 */
+/* #define	KDC_OPT_RESERVED	0x00000400 */
+/* #define	KDC_OPT_RESERVED	0x00000200 */
+/* #define	KDC_OPT_RESERVED	0x00000100 */
+/* #define	KDC_OPT_RESERVED	0x00000080 */
+/* #define	KDC_OPT_RESERVED	0x00000040 */
+#define	KDC_OPT_DISABLE_TRANSITED_CHECK	0x00000020
+#define	KDC_OPT_RENEWABLE_OK		0x00000010
+#define	KDC_OPT_ENC_TKT_IN_SKEY		0x00000008
+/* #define	KDC_OPT_UNUSED		0x00000004 */
+#define	KDC_OPT_RENEW			0x00000002
+#define	KDC_OPT_VALIDATE		0x00000001
+
+/*
+ * Mask of ticket flags in the TGT which should be converted into KDC
+ * options when using the TGT to get derivitive tickets.
+ * 
+ *  New mask = KDC_OPT_FORWARDABLE | KDC_OPT_PROXIABLE |
+ *	       KDC_OPT_ALLOW_POSTDATE | KDC_OPT_RENEWABLE
+ */
+#define KDC_TKT_COMMON_MASK		0x54800000
+
+/* definitions for ap_options fields */
+/* ap_options are 32 bits; each host is responsible to put the 4 bytes
+   representing these bits into net order before transmission */
+#define	AP_OPTS_RESERVED		0x80000000
+#define	AP_OPTS_USE_SESSION_KEY		0x40000000
+#define	AP_OPTS_MUTUAL_REQUIRED		0x20000000
+/* #define	AP_OPTS_RESERVED	0x10000000 */
+/* #define	AP_OPTS_RESERVED	0x08000000 */
+/* #define	AP_OPTS_RESERVED	0x04000000 */
+/* #define	AP_OPTS_RESERVED	0x02000000 */
+/* #define	AP_OPTS_RESERVED	0x01000000 */
+/* #define	AP_OPTS_RESERVED	0x00800000 */
+/* #define	AP_OPTS_RESERVED	0x00400000 */
+/* #define	AP_OPTS_RESERVED	0x00200000 */
+/* #define	AP_OPTS_RESERVED	0x00100000 */
+/* #define	AP_OPTS_RESERVED	0x00080000 */
+/* #define	AP_OPTS_RESERVED	0x00040000 */
+/* #define	AP_OPTS_RESERVED	0x00020000 */
+/* #define	AP_OPTS_RESERVED	0x00010000 */
+/* #define	AP_OPTS_RESERVED	0x00008000 */
+/* #define	AP_OPTS_RESERVED	0x00004000 */
+/* #define	AP_OPTS_RESERVED	0x00002000 */
+/* #define	AP_OPTS_RESERVED	0x00001000 */
+/* #define	AP_OPTS_RESERVED	0x00000800 */
+/* #define	AP_OPTS_RESERVED	0x00000400 */
+/* #define	AP_OPTS_RESERVED	0x00000200 */
+/* #define	AP_OPTS_RESERVED	0x00000100 */
+/* #define	AP_OPTS_RESERVED	0x00000080 */
+/* #define	AP_OPTS_RESERVED	0x00000040 */
+/* #define	AP_OPTS_RESERVED	0x00000020 */
+/* #define	AP_OPTS_RESERVED	0x00000010 */
+/* #define	AP_OPTS_RESERVED	0x00000008 */
+/* #define	AP_OPTS_RESERVED	0x00000004 */
+/* #define	AP_OPTS_RESERVED	0x00000002 */
+#define AP_OPTS_USE_SUBKEY	0x00000001
+
+#define AP_OPTS_WIRE_MASK	0xfffffff0
+
+/* definitions for ad_type fields. */
+#define	AD_TYPE_RESERVED	0x8000
+#define	AD_TYPE_EXTERNAL	0x4000
+#define	AD_TYPE_REGISTERED	0x2000
+
+#define AD_TYPE_FIELD_TYPE_MASK	0x1fff
+
+/* Ticket flags */
+/* flags are 32 bits; each host is responsible to put the 4 bytes
+   representing these bits into net order before transmission */
+/* #define	TKT_FLG_RESERVED	0x80000000 */
+#define	TKT_FLG_FORWARDABLE		0x40000000
+#define	TKT_FLG_FORWARDED		0x20000000
+#define	TKT_FLG_PROXIABLE		0x10000000
+#define	TKT_FLG_PROXY			0x08000000
+#define	TKT_FLG_MAY_POSTDATE		0x04000000
+#define	TKT_FLG_POSTDATED		0x02000000
+#define	TKT_FLG_INVALID			0x01000000
+#define	TKT_FLG_RENEWABLE		0x00800000
+#define	TKT_FLG_INITIAL			0x00400000
+#define	TKT_FLG_PRE_AUTH		0x00200000
+#define	TKT_FLG_HW_AUTH			0x00100000
+#define	TKT_FLG_TRANSIT_POLICY_CHECKED	0x00080000
+#define	TKT_FLG_OK_AS_DELEGATE		0x00040000
+#define	TKT_FLG_ANONYMOUS		0x00020000
+/* #define	TKT_FLG_RESERVED	0x00010000 */
+/* #define	TKT_FLG_RESERVED	0x00008000 */
+/* #define	TKT_FLG_RESERVED	0x00004000 */
+/* #define	TKT_FLG_RESERVED	0x00002000 */
+/* #define	TKT_FLG_RESERVED	0x00001000 */
+/* #define	TKT_FLG_RESERVED	0x00000800 */
+/* #define	TKT_FLG_RESERVED	0x00000400 */
+/* #define	TKT_FLG_RESERVED	0x00000200 */
+/* #define	TKT_FLG_RESERVED	0x00000100 */
+/* #define	TKT_FLG_RESERVED	0x00000080 */
+/* #define	TKT_FLG_RESERVED	0x00000040 */
+/* #define	TKT_FLG_RESERVED	0x00000020 */
+/* #define	TKT_FLG_RESERVED	0x00000010 */
+/* #define	TKT_FLG_RESERVED	0x00000008 */
+/* #define	TKT_FLG_RESERVED	0x00000004 */
+/* #define	TKT_FLG_RESERVED	0x00000002 */
+/* #define	TKT_FLG_RESERVED	0x00000001 */
+
+/* definitions for lr_type fields. */
+#define	LR_TYPE_THIS_SERVER_ONLY	0x8000
+
+#define LR_TYPE_INTERPRETATION_MASK	0x7fff
+
+/* definitions for ad_type fields. */
+#define	AD_TYPE_EXTERNAL	0x4000
+#define	AD_TYPE_REGISTERED	0x2000
+
+#define AD_TYPE_FIELD_TYPE_MASK	0x1fff
+#define AD_TYPE_INTERNAL_MASK	0x3fff
+
+/* definitions for msec direction bit for KRB_SAFE, KRB_PRIV */
+#define	MSEC_DIRBIT		0x8000
+#define	MSEC_VAL_MASK		0x7fff
+
+/*
+ * end "fieldbits.h"
+ */
+
+/*
+ * begin "proto.h"
+ */
+
+/* Protocol version number */
+#define	KRB5_PVNO	5
+
+/* Message types */
+
+#define	KRB5_AS_REQ	((krb5_msgtype)10) /* Req for initial authentication */
+#define	KRB5_AS_REP	((krb5_msgtype)11) /* Response to KRB_AS_REQ request */
+#define	KRB5_TGS_REQ	((krb5_msgtype)12) /* TGS request to server */
+#define	KRB5_TGS_REP	((krb5_msgtype)13) /* Response to KRB_TGS_REQ req */
+#define	KRB5_AP_REQ	((krb5_msgtype)14) /* application request to server */
+#define	KRB5_AP_REP	((krb5_msgtype)15) /* Response to KRB_AP_REQ_MUTUAL */
+#define	KRB5_SAFE	((krb5_msgtype)20) /* Safe application message */
+#define	KRB5_PRIV	((krb5_msgtype)21) /* Private application message */
+#define	KRB5_CRED	((krb5_msgtype)22) /* Credential forwarding message */
+#define	KRB5_ERROR	((krb5_msgtype)30) /* Error response */
+
+/* LastReq types */
+#define KRB5_LRQ_NONE			0
+#define KRB5_LRQ_ALL_LAST_TGT		1
+#define KRB5_LRQ_ONE_LAST_TGT		(-1)
+#define KRB5_LRQ_ALL_LAST_INITIAL	2
+#define KRB5_LRQ_ONE_LAST_INITIAL	(-2)
+#define KRB5_LRQ_ALL_LAST_TGT_ISSUED	3
+#define KRB5_LRQ_ONE_LAST_TGT_ISSUED	(-3)
+#define KRB5_LRQ_ALL_LAST_RENEWAL	4
+#define KRB5_LRQ_ONE_LAST_RENEWAL	(-4)
+#define KRB5_LRQ_ALL_LAST_REQ		5
+#define KRB5_LRQ_ONE_LAST_REQ		(-5)
+#define KRB5_LRQ_ALL_PW_EXPTIME		6
+#define KRB5_LRQ_ONE_PW_EXPTIME		(-6)
+
+/* PADATA types */
+#define KRB5_PADATA_NONE		0
+#define	KRB5_PADATA_AP_REQ		1
+#define	KRB5_PADATA_TGS_REQ		KRB5_PADATA_AP_REQ
+#define KRB5_PADATA_ENC_TIMESTAMP	2
+#define	KRB5_PADATA_PW_SALT		3
+#if 0				/* Not used */
+#define KRB5_PADATA_ENC_ENCKEY		4  /* Key encrypted within itself */
+#endif
+#define KRB5_PADATA_ENC_UNIX_TIME	5  /* timestamp encrypted in key */
+#define KRB5_PADATA_ENC_SANDIA_SECURID	6  /* SecurId passcode */
+#define KRB5_PADATA_SESAME		7  /* Sesame project */
+#define KRB5_PADATA_OSF_DCE		8  /* OSF DCE */
+#define KRB5_CYBERSAFE_SECUREID		9  /* Cybersafe */
+#define	KRB5_PADATA_AFS3_SALT		10 /* Cygnus */
+#define KRB5_PADATA_ETYPE_INFO		11 /* Etype info for preauth */
+#define KRB5_PADATA_SAM_CHALLENGE	12 /* draft challenge system */
+#define KRB5_PADATA_SAM_RESPONSE	13 /* draft challenge system response */
+#define KRB5_PADATA_PK_AS_REQ		14 /* PKINIT */
+#define KRB5_PADATA_PK_AS_REP		15 /* PKINIT */
+#define KRB5_PADATA_ETYPE_INFO2 19
+#define KRB5_PADATA_SAM_CHALLENGE_2	30 /* draft challenge system, updated */
+#define KRB5_PADATA_SAM_RESPONSE_2	31 /* draft challenge system, updated */
+    
+#define	KRB5_SAM_USE_SAD_AS_KEY		0x80000000
+#define	KRB5_SAM_SEND_ENCRYPTED_SAD	0x40000000
+#define	KRB5_SAM_MUST_PK_ENCRYPT_SAD	0x20000000 /* currently must be zero */
+
+/* Reserved for SPX pre-authentication. */
+#define KRB5_PADATA_DASS		16
+
+/* Transited encoding types */
+#define	KRB5_DOMAIN_X500_COMPRESS	1
+
+/* alternate authentication types */
+#define	KRB5_ALTAUTH_ATT_CHALLENGE_RESPONSE	64
+
+/* authorization data types */
+#define	KRB5_AUTHDATA_OSF_DCE	64
+#define KRB5_AUTHDATA_SESAME	65
+
+/* password change constants */
+
+#define KRB5_KPASSWD_SUCCESS		0
+#define KRB5_KPASSWD_MALFORMED		1
+#define KRB5_KPASSWD_HARDERROR		2
+#define KRB5_KPASSWD_AUTHERROR		3
+#define KRB5_KPASSWD_SOFTERROR		4
+/* These are Microsoft's extensions in RFC 3244, and it looks like
+   they'll become standardized, possibly with other additions.  */
+#define KRB5_KPASSWD_ACCESSDENIED	5	/* unused */
+#define KRB5_KPASSWD_BAD_VERSION	6
+#define KRB5_KPASSWD_INITIAL_FLAG_NEEDED 7	/* unused */
+
+/*
+ * end "proto.h"
+ */
+
+/* Time set */
+typedef struct _krb5_ticket_times {
+    krb5_timestamp authtime; /* XXX ? should ktime in KDC_REP == authtime
+				in ticket? otherwise client can't get this */ 
+    krb5_timestamp starttime;		/* optional in ticket, if not present,
+					   use authtime */
+    krb5_timestamp endtime;
+    krb5_timestamp renew_till;
+} krb5_ticket_times;
+
+/* structure for auth data */
+typedef struct _krb5_authdata {
+    krb5_magic magic;
+    krb5_authdatatype ad_type;
+    unsigned int length;
+    krb5_octet *contents;
+} krb5_authdata;
+
+/* structure for transited encoding */
+typedef struct _krb5_transited {
+    krb5_magic magic;
+    krb5_octet tr_type;
+    krb5_data tr_contents;
+} krb5_transited;
+
+typedef struct _krb5_enc_tkt_part {
+    krb5_magic magic;
+    /* to-be-encrypted portion */
+    krb5_flags flags;			/* flags */
+    krb5_keyblock *session;		/* session key: includes enctype */
+    krb5_principal client;		/* client name/realm */
+    krb5_transited transited;		/* list of transited realms */
+    krb5_ticket_times times;		/* auth, start, end, renew_till */
+    krb5_address **caddrs;	/* array of ptrs to addresses */
+    krb5_authdata **authorization_data; /* auth data */
+} krb5_enc_tkt_part;
+
+typedef struct _krb5_ticket {
+    krb5_magic magic;
+    /* cleartext portion */
+    krb5_principal server;		/* server name/realm */
+    krb5_enc_data enc_part;		/* encryption type, kvno, encrypted
+					   encoding */
+    krb5_enc_tkt_part *enc_part2;	/* ptr to decrypted version, if
+					   available */
+} krb5_ticket;
+
+/* the unencrypted version */
+typedef struct _krb5_authenticator {
+    krb5_magic magic;
+    krb5_principal client;		/* client name/realm */
+    krb5_checksum *checksum;	/* checksum, includes type, optional */
+    krb5_int32 cusec;			/* client usec portion */
+    krb5_timestamp ctime;		/* client sec portion */
+    krb5_keyblock *subkey;		/* true session key, optional */
+    krb5_ui_4 seq_number;		/* sequence #, optional */
+    krb5_authdata **authorization_data; /* New add by Ari, auth data */
+} krb5_authenticator;
+
+typedef struct _krb5_tkt_authent {
+    krb5_magic magic;
+    krb5_ticket *ticket;
+    krb5_authenticator *authenticator;
+    krb5_flags ap_options;
+} krb5_tkt_authent;
+
+/* credentials:	 Ticket, session key, etc. */
+typedef struct _krb5_creds {
+    krb5_magic magic;
+    krb5_principal client;		/* client's principal identifier */
+    krb5_principal server;		/* server's principal identifier */
+    krb5_keyblock keyblock;		/* session encryption key info */
+    krb5_ticket_times times;		/* lifetime info */
+    krb5_boolean is_skey;		/* true if ticket is encrypted in
+					   another ticket's skey */
+    krb5_flags ticket_flags;		/* flags in ticket */
+    krb5_address **addresses;	/* addrs in ticket */
+    krb5_data ticket;			/* ticket string itself */
+    krb5_data second_ticket;		/* second ticket, if related to
+					   ticket (via DUPLICATE-SKEY or
+					   ENC-TKT-IN-SKEY) */
+    krb5_authdata **authdata;	/* authorization data */
+} krb5_creds;
+
+/* Last request fields */
+typedef struct _krb5_last_req_entry {
+    krb5_magic magic;
+    krb5_int32 lr_type;
+    krb5_timestamp value;
+} krb5_last_req_entry;
+
+/* pre-authentication data */
+typedef struct _krb5_pa_data {
+    krb5_magic magic;
+    krb5_preauthtype  pa_type;
+    unsigned int length;
+    krb5_octet *contents;
+} krb5_pa_data;
+
+typedef struct _krb5_kdc_req {
+    krb5_magic magic;
+    krb5_msgtype msg_type;		/* AS_REQ or TGS_REQ? */
+    krb5_pa_data **padata;	/* e.g. encoded AP_REQ */
+    /* real body */
+    krb5_flags kdc_options;		/* requested options */
+    krb5_principal client;		/* includes realm; optional */
+    krb5_principal server;		/* includes realm (only used if no
+					   client) */
+    krb5_timestamp from;		/* requested starttime */
+    krb5_timestamp till;		/* requested endtime */
+    krb5_timestamp rtime;		/* (optional) requested renew_till */
+    krb5_int32 nonce;			/* nonce to match request/response */
+    int nktypes;			/* # of ktypes, must be positive */
+    krb5_enctype *ktype;		/* requested enctype(s) */
+    krb5_address **addresses;	/* requested addresses, optional */
+    krb5_enc_data authorization_data;	/* encrypted auth data; OPTIONAL */
+    krb5_authdata **unenc_authdata; /* unencrypted auth data,
+					   if available */
+    krb5_ticket **second_ticket;/* second ticket array; OPTIONAL */
+} krb5_kdc_req;
+
+typedef struct _krb5_enc_kdc_rep_part {
+    krb5_magic magic;
+    /* encrypted part: */
+    krb5_msgtype msg_type;		/* krb5 message type */
+    krb5_keyblock *session;		/* session key */
+    krb5_last_req_entry **last_req; /* array of ptrs to entries */
+    krb5_int32 nonce;			/* nonce from request */
+    krb5_timestamp key_exp;		/* expiration date */
+    krb5_flags flags;			/* ticket flags */
+    krb5_ticket_times times;		/* lifetime info */
+    krb5_principal server;		/* server's principal identifier */
+    krb5_address **caddrs;	/* array of ptrs to addresses,
+					   optional */
+} krb5_enc_kdc_rep_part;
+
+typedef struct _krb5_kdc_rep {
+    krb5_magic magic;
+    /* cleartext part: */
+    krb5_msgtype msg_type;		/* AS_REP or KDC_REP? */
+    krb5_pa_data **padata;	/* preauthentication data from KDC */
+    krb5_principal client;		/* client's principal identifier */
+    krb5_ticket *ticket;		/* ticket */
+    krb5_enc_data enc_part;		/* encryption type, kvno, encrypted
+					   encoding */
+    krb5_enc_kdc_rep_part *enc_part2;/* unencrypted version, if available */
+} krb5_kdc_rep;
+
+/* error message structure */
+typedef struct _krb5_error {
+    krb5_magic magic;
+    /* some of these may be meaningless in certain contexts */
+    krb5_timestamp ctime;		/* client sec portion; optional */
+    krb5_int32 cusec;			/* client usec portion; optional */
+    krb5_int32 susec;			/* server usec portion */
+    krb5_timestamp stime;		/* server sec portion */
+    krb5_ui_4 error;			/* error code (protocol error #'s) */
+    krb5_principal client;		/* client's principal identifier;
+					   optional */
+    krb5_principal server;		/* server's principal identifier */
+    krb5_data text;			/* descriptive text */
+    krb5_data e_data;			/* additional error-describing data */
+} krb5_error;
+
+typedef struct _krb5_ap_req {
+    krb5_magic magic;
+    krb5_flags ap_options;		/* requested options */
+    krb5_ticket *ticket;		/* ticket */
+    krb5_enc_data authenticator;	/* authenticator (already encrypted) */
+} krb5_ap_req;
+
+typedef struct _krb5_ap_rep {
+    krb5_magic magic;
+    krb5_enc_data enc_part;
+} krb5_ap_rep;
+
+typedef struct _krb5_ap_rep_enc_part {
+    krb5_magic magic;
+    krb5_timestamp ctime;		/* client time, seconds portion */
+    krb5_int32 cusec;			/* client time, microseconds portion */
+    krb5_keyblock *subkey;		/* true session key, optional */
+    krb5_ui_4 seq_number;		/* sequence #, optional */
+} krb5_ap_rep_enc_part;
+
+typedef struct _krb5_response {
+    krb5_magic magic;
+    krb5_octet message_type;
+    krb5_data response;
+    krb5_int32 expected_nonce;	/* The expected nonce for KDC_REP messages */
+    krb5_timestamp request_time;   /* When we made the request */
+} krb5_response;
+
+typedef struct _krb5_cred_info {
+    krb5_magic magic;
+    krb5_keyblock *session;		/* session key used to encrypt */
+					/* ticket */
+    krb5_principal client;		/* client name/realm, optional */
+    krb5_principal server;		/* server name/realm, optional */
+    krb5_flags flags;			/* ticket flags, optional */
+    krb5_ticket_times times;		/* auth, start, end, renew_till, */
+					/* optional */
+    krb5_address **caddrs;	/* array of ptrs to addresses */
+} krb5_cred_info;
+
+typedef struct _krb5_cred_enc_part {
+    krb5_magic magic;
+    krb5_int32 nonce;			/* nonce, optional */
+    krb5_timestamp timestamp;		/* client time */
+    krb5_int32 usec;			/* microsecond portion of time */
+    krb5_address *s_address;	/* sender address, optional */
+    krb5_address *r_address;	/* recipient address, optional */
+    krb5_cred_info **ticket_info;
+} krb5_cred_enc_part;	 
+
+typedef struct _krb5_cred {
+    krb5_magic magic;
+    krb5_ticket **tickets;	/* tickets */
+    krb5_enc_data enc_part;		/* encrypted part */
+    krb5_cred_enc_part *enc_part2;	/* unencrypted version, if available*/
+} krb5_cred;
+
+/* Sandia password generation structures */
+typedef struct _passwd_phrase_element {
+    krb5_magic magic;
+    krb5_data *passwd;
+    krb5_data *phrase;
+} passwd_phrase_element;
+
+typedef struct _krb5_pwd_data {
+    krb5_magic magic;
+    int sequence_count;
+    passwd_phrase_element **element;
+} krb5_pwd_data;
+
+/* these need to be here so the typedefs are available for the prototypes */
+
+/*
+ * begin "safepriv.h"
+ */
+
+#define KRB5_AUTH_CONTEXT_DO_TIME	0x00000001
+#define KRB5_AUTH_CONTEXT_RET_TIME	0x00000002
+#define KRB5_AUTH_CONTEXT_DO_SEQUENCE	0x00000004
+#define KRB5_AUTH_CONTEXT_RET_SEQUENCE	0x00000008
+#define KRB5_AUTH_CONTEXT_PERMIT_ALL	0x00000010
+#define KRB5_AUTH_CONTEXT_USE_SUBKEY	0x00000020
+ 
+typedef struct krb5_replay_data { 
+    krb5_timestamp	timestamp; 
+    krb5_int32		usec;
+    krb5_ui_4		seq; 
+} krb5_replay_data;
+
+/* flags for krb5_auth_con_genaddrs() */
+#define KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR		0x00000001
+#define KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR		0x00000002
+#define KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR	0x00000004
+#define KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR	0x00000008
+
+/* type of function used as a callback to generate checksum data for
+ * mk_req */
+
+typedef krb5_error_code 
+(KRB5_CALLCONV * krb5_mk_req_checksum_func) (krb5_context, krb5_auth_context , void *,
+			       krb5_data **);
+
+/*
+ * end "safepriv.h"
+ */
+
+
+/*
+ * begin "ccache.h"
+ */
+
+typedef	krb5_pointer	krb5_cc_cursor;	/* cursor for sequential lookup */
+
+struct _krb5_ccache;
+typedef struct _krb5_ccache *krb5_ccache;
+struct _krb5_cc_ops;
+typedef struct _krb5_cc_ops krb5_cc_ops;
+
+/* for retrieve_cred */
+#define	KRB5_TC_MATCH_TIMES		0x00000001
+#define	KRB5_TC_MATCH_IS_SKEY		0x00000002
+#define	KRB5_TC_MATCH_FLAGS		0x00000004
+#define	KRB5_TC_MATCH_TIMES_EXACT	0x00000008
+#define	KRB5_TC_MATCH_FLAGS_EXACT	0x00000010
+#define	KRB5_TC_MATCH_AUTHDATA		0x00000020
+#define	KRB5_TC_MATCH_SRV_NAMEONLY	0x00000040
+#define	KRB5_TC_MATCH_2ND_TKT		0x00000080
+#define	KRB5_TC_MATCH_KTYPE		0x00000100
+#define KRB5_TC_SUPPORTED_KTYPES	0x00000200
+
+/* for set_flags and other functions */
+#define KRB5_TC_OPENCLOSE		0x00000001
+#define KRB5_TC_NOTICKET                0x00000002
+
+const char * KRB5_CALLCONV
+krb5_cc_get_name (krb5_context context, krb5_ccache cache);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_gen_new (krb5_context context, krb5_ccache *cache);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_initialize(krb5_context context, krb5_ccache cache,
+		   krb5_principal principal);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_destroy (krb5_context context, krb5_ccache cache);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_close (krb5_context context, krb5_ccache cache);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_store_cred (krb5_context context, krb5_ccache cache,
+		    krb5_creds *creds);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_retrieve_cred (krb5_context context, krb5_ccache cache,
+		       krb5_flags flags, krb5_creds *mcreds,
+		       krb5_creds *creds);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_get_principal (krb5_context context, krb5_ccache cache,
+		       krb5_principal *principal);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_start_seq_get (krb5_context context, krb5_ccache cache,
+		       krb5_cc_cursor *cursor);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_next_cred (krb5_context context, krb5_ccache cache,
+		   krb5_cc_cursor *cursor, krb5_creds *creds);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_end_seq_get (krb5_context context, krb5_ccache cache,
+		     krb5_cc_cursor *cursor);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_remove_cred (krb5_context context, krb5_ccache cache, krb5_flags flags,
+		     krb5_creds *creds);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_set_flags (krb5_context context, krb5_ccache cache, krb5_flags flags);
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_get_flags (krb5_context context, krb5_ccache cache, krb5_flags *flags);
+
+const char * KRB5_CALLCONV
+krb5_cc_get_type (krb5_context context, krb5_ccache cache);
+
+/*
+ * end "ccache.h"
+ */
+
+/*
+ * begin "rcache.h"
+ */
+
+struct krb5_rc_st;
+typedef struct krb5_rc_st *krb5_rcache;
+
+/*
+ * end "rcache.h"
+ */
+
+/*
+ * begin "keytab.h"
+ */
+
+
+/* XXX */
+#define MAX_KEYTAB_NAME_LEN 1100 /* Long enough for MAXPATHLEN + some extra */
+
+typedef krb5_pointer krb5_kt_cursor;	/* XXX */
+
+typedef struct krb5_keytab_entry_st {
+    krb5_magic magic;
+    krb5_principal principal;	/* principal of this key */
+    krb5_timestamp timestamp;	/* time entry written to keytable */
+    krb5_kvno vno;		/* key version number */
+    krb5_keyblock key;		/* the secret key */
+} krb5_keytab_entry;
+
+#if KRB5_PRIVATE
+struct _krb5_kt_ops;
+typedef struct _krb5_kt {	/* should move into k5-int.h */
+    krb5_magic magic;
+    const struct _krb5_kt_ops *ops;
+    krb5_pointer data;
+} *krb5_keytab;
+#else
+struct _krb5_kt;
+typedef struct _krb5_kt *krb5_keytab;
+#endif
+
+char * KRB5_CALLCONV
+krb5_kt_get_type (krb5_context, krb5_keytab keytab);
+krb5_error_code KRB5_CALLCONV
+krb5_kt_get_name(krb5_context context, krb5_keytab keytab, char *name,
+		 unsigned int namelen);
+krb5_error_code KRB5_CALLCONV
+krb5_kt_close(krb5_context context, krb5_keytab keytab);
+krb5_error_code KRB5_CALLCONV
+krb5_kt_get_entry(krb5_context context, krb5_keytab keytab,
+		  krb5_const_principal principal, krb5_kvno vno,
+		  krb5_enctype enctype, krb5_keytab_entry *entry);
+krb5_error_code KRB5_CALLCONV
+krb5_kt_start_seq_get(krb5_context context, krb5_keytab keytab,
+		      krb5_kt_cursor *cursor);
+krb5_error_code KRB5_CALLCONV
+krb5_kt_next_entry(krb5_context context, krb5_keytab keytab,
+		   krb5_keytab_entry *entry, krb5_kt_cursor *cursor);
+krb5_error_code KRB5_CALLCONV
+krb5_kt_end_seq_get(krb5_context context, krb5_keytab keytab,
+		    krb5_kt_cursor *cursor);
+
+/*
+ * end "keytab.h"
+ */
+
+/*
+ * begin "func-proto.h"
+ */
+
+krb5_error_code KRB5_CALLCONV krb5_init_context
+	(krb5_context *);
+krb5_error_code KRB5_CALLCONV krb5_init_secure_context
+	(krb5_context *);
+void KRB5_CALLCONV krb5_free_context
+	(krb5_context);
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_set_default_in_tkt_ktypes
+	(krb5_context,
+		const krb5_enctype *);
+krb5_error_code krb5_get_default_in_tkt_ktypes
+	(krb5_context,
+		krb5_enctype **);
+
+krb5_error_code krb5_set_default_tgs_ktypes
+	(krb5_context,
+		const krb5_enctype *);
+#endif
+
+krb5_error_code KRB5_CALLCONV 
+krb5_set_default_tgs_enctypes
+	(krb5_context,
+		const krb5_enctype *);
+#if KRB5_PRIVATE
+krb5_error_code KRB5_CALLCONV krb5_get_tgs_ktypes
+	(krb5_context,
+		krb5_const_principal,
+		krb5_enctype **);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_get_permitted_enctypes
+	(krb5_context, krb5_enctype **);
+
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_ktypes
+	(krb5_context, krb5_enctype *);
+
+krb5_boolean krb5_is_permitted_enctype
+	(krb5_context, krb5_enctype);
+#endif
+
+krb5_boolean KRB5_CALLCONV krb5_is_thread_safe(void);
+
+/* libkrb.spec */
+#if KRB5_PRIVATE
+krb5_error_code krb5_kdc_rep_decrypt_proc
+	(krb5_context,
+		const krb5_keyblock *,
+		krb5_const_pointer,
+		krb5_kdc_rep * );
+krb5_error_code KRB5_CALLCONV krb5_decrypt_tkt_part
+	(krb5_context,
+		const krb5_keyblock *,
+		krb5_ticket * );
+krb5_error_code krb5_get_cred_from_kdc
+	(krb5_context,
+		krb5_ccache,		/* not const, as reading may save
+					   state */
+		krb5_creds *,
+		krb5_creds **,
+		krb5_creds *** );
+krb5_error_code krb5_get_cred_from_kdc_validate
+	(krb5_context,
+		krb5_ccache,		/* not const, as reading may save
+					   state */
+		krb5_creds *,
+		krb5_creds **,
+		krb5_creds *** );
+krb5_error_code krb5_get_cred_from_kdc_renew
+	(krb5_context,
+		krb5_ccache,		/* not const, as reading may save
+					   state */
+		krb5_creds *,
+		krb5_creds **,
+		krb5_creds *** );
+#endif
+
+void KRB5_CALLCONV krb5_free_tgt_creds
+	(krb5_context,
+	 krb5_creds **); /* XXX too hard to do with const */
+
+#define	KRB5_GC_USER_USER	1	/* want user-user ticket */
+#define	KRB5_GC_CACHED		2	/* want cached ticket only */
+
+krb5_error_code KRB5_CALLCONV krb5_get_credentials
+	(krb5_context,
+		krb5_flags,
+		krb5_ccache,
+		krb5_creds *,
+		krb5_creds **);
+krb5_error_code KRB5_CALLCONV krb5_get_credentials_validate
+	(krb5_context,
+		krb5_flags,
+		krb5_ccache,
+		krb5_creds *,
+		krb5_creds **);
+krb5_error_code KRB5_CALLCONV krb5_get_credentials_renew
+	(krb5_context,
+		krb5_flags,
+		krb5_ccache,
+		krb5_creds *,
+		krb5_creds **);
+#if KRB5_PRIVATE
+krb5_error_code krb5_get_cred_via_tkt
+	(krb5_context,
+		   krb5_creds *,
+		   krb5_flags,
+		   krb5_address * const *,
+		   krb5_creds *,
+		   krb5_creds **);
+#endif
+krb5_error_code KRB5_CALLCONV krb5_mk_req
+	(krb5_context,
+		krb5_auth_context *,
+		krb5_flags,
+		char *,
+		char *,
+		krb5_data *,
+		krb5_ccache,
+		krb5_data * );
+krb5_error_code KRB5_CALLCONV krb5_mk_req_extended
+	(krb5_context,
+		krb5_auth_context *,
+		krb5_flags,
+		krb5_data *,
+		krb5_creds *,
+		krb5_data * );
+krb5_error_code KRB5_CALLCONV krb5_mk_rep
+	(krb5_context,
+		krb5_auth_context,
+		krb5_data *);
+krb5_error_code KRB5_CALLCONV krb5_rd_rep
+	(krb5_context,
+		krb5_auth_context,
+		const krb5_data *,
+		krb5_ap_rep_enc_part **);
+krb5_error_code KRB5_CALLCONV krb5_mk_error
+	(krb5_context,
+		const krb5_error *,
+		krb5_data * );
+krb5_error_code KRB5_CALLCONV krb5_rd_error
+	(krb5_context,
+		const krb5_data *,
+		krb5_error ** );
+krb5_error_code KRB5_CALLCONV krb5_rd_safe
+	(krb5_context,
+		krb5_auth_context,
+		const krb5_data *,
+		krb5_data *,
+		krb5_replay_data *);
+krb5_error_code KRB5_CALLCONV krb5_rd_priv
+	(krb5_context,
+		krb5_auth_context,
+		const krb5_data *,
+		krb5_data *,
+		krb5_replay_data *);
+krb5_error_code KRB5_CALLCONV krb5_parse_name
+	(krb5_context,
+		const char *,
+		krb5_principal * );
+krb5_error_code KRB5_CALLCONV krb5_unparse_name
+	(krb5_context,
+		krb5_const_principal,
+		char ** );
+krb5_error_code KRB5_CALLCONV krb5_unparse_name_ext
+	(krb5_context,
+		krb5_const_principal,
+		char **,
+		unsigned int *);
+
+krb5_error_code KRB5_CALLCONV krb5_set_principal_realm
+	(krb5_context, krb5_principal, const char *);
+
+krb5_boolean KRB5_CALLCONV_WRONG krb5_address_search
+	(krb5_context,
+		const krb5_address *,
+		krb5_address * const *);
+krb5_boolean KRB5_CALLCONV krb5_address_compare
+	(krb5_context,
+		const krb5_address *,
+		const krb5_address *);
+int KRB5_CALLCONV krb5_address_order
+	(krb5_context,
+		const krb5_address *,
+		const krb5_address *);
+krb5_boolean KRB5_CALLCONV krb5_realm_compare
+	(krb5_context,
+		krb5_const_principal,
+		krb5_const_principal);
+krb5_boolean KRB5_CALLCONV krb5_principal_compare
+	(krb5_context,
+		krb5_const_principal,
+		krb5_const_principal);
+krb5_error_code KRB5_CALLCONV  krb5_init_keyblock
+		(krb5_context, krb5_enctype enctype,
+		size_t length, krb5_keyblock **out); 
+  		/* Initialize a new keyblock and allocate storage
+		 * for the contents of the key, which will be freed along
+		 * with the keyblock when krb5_free_keyblock is called.
+		 * It is legal to pass in a length of 0, in which
+		 * case contents are left unallocated.
+		 */
+krb5_error_code KRB5_CALLCONV krb5_copy_keyblock
+	(krb5_context,
+		const krb5_keyblock *,
+		krb5_keyblock **);
+krb5_error_code KRB5_CALLCONV krb5_copy_keyblock_contents
+	(krb5_context,
+		const krb5_keyblock *,
+		krb5_keyblock *);
+krb5_error_code KRB5_CALLCONV krb5_copy_creds
+	(krb5_context,
+		const krb5_creds *,
+		krb5_creds **);
+krb5_error_code KRB5_CALLCONV krb5_copy_data
+	(krb5_context,
+		const krb5_data *,
+		krb5_data **);
+krb5_error_code KRB5_CALLCONV krb5_copy_principal
+	(krb5_context,
+		krb5_const_principal,
+		krb5_principal *);
+#if KRB5_PRIVATE
+krb5_error_code KRB5_CALLCONV krb5_copy_addr
+	(krb5_context,
+		const krb5_address *,
+		krb5_address **);
+#endif
+krb5_error_code KRB5_CALLCONV krb5_copy_addresses
+	(krb5_context,
+		krb5_address * const *,
+		krb5_address ***);
+krb5_error_code KRB5_CALLCONV krb5_copy_ticket
+	(krb5_context,
+		const krb5_ticket *,
+		krb5_ticket **);
+krb5_error_code KRB5_CALLCONV krb5_copy_authdata
+	(krb5_context,
+		krb5_authdata * const *,
+		krb5_authdata ***);
+krb5_error_code KRB5_CALLCONV krb5_copy_authenticator
+	(krb5_context,
+		const krb5_authenticator *,
+		krb5_authenticator **);
+krb5_error_code KRB5_CALLCONV krb5_copy_checksum
+	(krb5_context,
+		const krb5_checksum *,
+		krb5_checksum **);
+#if KRB5_PRIVATE
+void krb5_init_ets
+	(krb5_context);
+void krb5_free_ets
+	(krb5_context);
+krb5_error_code krb5_generate_subkey
+	(krb5_context,
+		const krb5_keyblock *, krb5_keyblock **);
+krb5_error_code krb5_generate_seq_number
+	(krb5_context,
+		const krb5_keyblock *, krb5_ui_4 *);
+#endif
+krb5_error_code KRB5_CALLCONV krb5_get_server_rcache
+	(krb5_context,
+		const krb5_data *, krb5_rcache *);
+krb5_error_code KRB5_CALLCONV_C krb5_build_principal_ext
+	(krb5_context, krb5_principal *, unsigned int, const char *, ...);
+krb5_error_code KRB5_CALLCONV_C krb5_build_principal
+	(krb5_context, krb5_principal *, unsigned int, const char *, ...);
+#ifdef va_start
+/* XXX depending on varargs include file defining va_start... */
+krb5_error_code KRB5_CALLCONV krb5_build_principal_va
+	(krb5_context,
+		krb5_principal, unsigned int, const char *, va_list);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_425_conv_principal
+	(krb5_context,
+		const char *name,
+		const char *instance, const char *realm,
+		krb5_principal *princ);
+
+krb5_error_code KRB5_CALLCONV krb5_524_conv_principal
+	(krb5_context context, krb5_const_principal princ, 
+		char *name, char *inst, char *realm);
+
+struct credentials;
+int KRB5_CALLCONV krb5_524_convert_creds
+	(krb5_context context, krb5_creds *v5creds,
+	 struct credentials *v4creds);
+#if KRB5_DEPRECATED
+#define krb524_convert_creds_kdc krb5_524_convert_creds
+#define krb524_init_ets(x) (0)
+#endif
+
+/* libkt.spec */
+#if KRB5_PRIVATE
+krb5_error_code KRB5_CALLCONV krb5_kt_register
+	(krb5_context,
+		const struct _krb5_kt_ops * );
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_kt_resolve
+	(krb5_context,
+		const char *,
+		krb5_keytab * );
+krb5_error_code KRB5_CALLCONV krb5_kt_default_name
+	(krb5_context,
+		char *,
+		int );
+krb5_error_code KRB5_CALLCONV krb5_kt_default
+	(krb5_context,
+		krb5_keytab * );
+krb5_error_code KRB5_CALLCONV krb5_free_keytab_entry_contents
+	(krb5_context,
+		krb5_keytab_entry * );
+#if KRB5_PRIVATE
+/* use krb5_free_keytab_entry_contents instead */
+krb5_error_code KRB5_CALLCONV krb5_kt_free_entry
+	(krb5_context,
+		krb5_keytab_entry * );
+#endif
+/* remove and add are functions, so that they can return NOWRITE
+   if not a writable keytab */
+krb5_error_code KRB5_CALLCONV krb5_kt_remove_entry
+	(krb5_context,
+		krb5_keytab,
+		krb5_keytab_entry * );
+krb5_error_code KRB5_CALLCONV krb5_kt_add_entry
+	(krb5_context,
+		krb5_keytab,
+		krb5_keytab_entry * );
+krb5_error_code KRB5_CALLCONV_WRONG krb5_principal2salt
+	(krb5_context,
+		krb5_const_principal, krb5_data *);
+#if KRB5_PRIVATE
+krb5_error_code krb5_principal2salt_norealm
+	(krb5_context,
+		krb5_const_principal, krb5_data *);
+#endif
+/* librc.spec--see rcache.h */
+
+/* libcc.spec */
+krb5_error_code KRB5_CALLCONV krb5_cc_resolve
+	(krb5_context,
+		const char *,
+		krb5_ccache * );
+const char * KRB5_CALLCONV krb5_cc_default_name
+	(krb5_context);
+krb5_error_code KRB5_CALLCONV krb5_cc_set_default_name
+	(krb5_context, const char *);
+krb5_error_code KRB5_CALLCONV krb5_cc_default
+	(krb5_context,
+		krb5_ccache *);
+#if KRB5_PRIVATE
+unsigned int KRB5_CALLCONV krb5_get_notification_message
+	(void);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_cc_copy_creds
+	(krb5_context context,
+			krb5_ccache incc,
+			krb5_ccache outcc);
+
+
+/* chk_trans.c */
+#if KRB5_PRIVATE
+krb5_error_code krb5_check_transited_list
+	(krb5_context, const krb5_data *trans,
+	 const krb5_data *realm1, const krb5_data *realm2);
+#endif
+
+/* free_rtree.c */
+#if KRB5_PRIVATE
+void krb5_free_realm_tree
+	(krb5_context,
+		krb5_principal *);
+#endif
+
+/* krb5_free.c */
+void KRB5_CALLCONV krb5_free_principal
+	(krb5_context, krb5_principal );
+void KRB5_CALLCONV krb5_free_authenticator
+	(krb5_context, krb5_authenticator * );
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_authenticator_contents
+	(krb5_context, krb5_authenticator * );
+#endif
+void KRB5_CALLCONV krb5_free_addresses
+	(krb5_context, krb5_address ** );
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_address
+	(krb5_context, krb5_address * );
+#endif
+void KRB5_CALLCONV krb5_free_authdata
+	(krb5_context, krb5_authdata ** );
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_enc_tkt_part
+	(krb5_context, krb5_enc_tkt_part * );
+#endif
+void KRB5_CALLCONV krb5_free_ticket
+	(krb5_context, krb5_ticket * );
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_tickets
+	(krb5_context, krb5_ticket ** );
+void KRB5_CALLCONV krb5_free_kdc_req
+	(krb5_context, krb5_kdc_req * );
+void KRB5_CALLCONV krb5_free_kdc_rep
+	(krb5_context, krb5_kdc_rep * );
+void KRB5_CALLCONV krb5_free_last_req
+	(krb5_context, krb5_last_req_entry ** );
+void KRB5_CALLCONV krb5_free_enc_kdc_rep_part
+	(krb5_context, krb5_enc_kdc_rep_part * );
+#endif
+void KRB5_CALLCONV krb5_free_error
+	(krb5_context, krb5_error * );
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_ap_req
+	(krb5_context, krb5_ap_req * );
+void KRB5_CALLCONV krb5_free_ap_rep
+	(krb5_context, krb5_ap_rep * );
+void KRB5_CALLCONV krb5_free_cred
+	(krb5_context, krb5_cred *);
+#endif
+void KRB5_CALLCONV krb5_free_creds
+	(krb5_context, krb5_creds *);
+void KRB5_CALLCONV krb5_free_cred_contents
+	(krb5_context, krb5_creds *);
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_cred_enc_part
+	(krb5_context, krb5_cred_enc_part *);
+#endif
+void KRB5_CALLCONV krb5_free_checksum
+	(krb5_context, krb5_checksum *);
+void KRB5_CALLCONV krb5_free_checksum_contents
+	(krb5_context, krb5_checksum *);
+void KRB5_CALLCONV krb5_free_keyblock
+	(krb5_context, krb5_keyblock *);
+void KRB5_CALLCONV krb5_free_keyblock_contents
+	(krb5_context, krb5_keyblock *);
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_pa_data
+	(krb5_context, krb5_pa_data **);
+#endif
+void KRB5_CALLCONV krb5_free_ap_rep_enc_part
+	(krb5_context, krb5_ap_rep_enc_part *);
+#if KRB5_PRIVATE
+void KRB5_CALLCONV krb5_free_tkt_authent
+	(krb5_context, krb5_tkt_authent *);
+void KRB5_CALLCONV krb5_free_pwd_data
+	(krb5_context, krb5_pwd_data *);
+void KRB5_CALLCONV krb5_free_pwd_sequences
+	(krb5_context, passwd_phrase_element **);
+#endif
+void KRB5_CALLCONV krb5_free_data
+	(krb5_context, krb5_data *);
+void KRB5_CALLCONV krb5_free_data_contents
+	(krb5_context, krb5_data *);
+void KRB5_CALLCONV krb5_free_unparsed_name
+	(krb5_context, char *);
+void KRB5_CALLCONV krb5_free_cksumtypes
+	(krb5_context, krb5_cksumtype *);
+
+/* From krb5/os but needed but by the outside world */
+krb5_error_code KRB5_CALLCONV krb5_us_timeofday
+	(krb5_context,
+		krb5_timestamp *,
+		krb5_int32 * );
+krb5_error_code KRB5_CALLCONV krb5_timeofday
+	(krb5_context,
+		krb5_timestamp * );
+		 /* get all the addresses of this host */
+krb5_error_code KRB5_CALLCONV krb5_os_localaddr
+	(krb5_context,
+		krb5_address ***);
+krb5_error_code KRB5_CALLCONV krb5_get_default_realm
+	(krb5_context,
+		 char ** );
+krb5_error_code KRB5_CALLCONV krb5_set_default_realm
+	(krb5_context,
+		   const char * );
+void KRB5_CALLCONV krb5_free_default_realm
+	(krb5_context,
+		   char * );
+krb5_error_code KRB5_CALLCONV krb5_sname_to_principal
+	(krb5_context,
+		const char *,
+		   const char *,
+		   krb5_int32,
+		   krb5_principal *);
+krb5_error_code KRB5_CALLCONV
+krb5_change_password
+	(krb5_context context, krb5_creds *creds, char *newpw,
+			int *result_code, krb5_data *result_code_string,
+			krb5_data *result_string);
+krb5_error_code KRB5_CALLCONV
+krb5_set_password
+	(krb5_context context, krb5_creds *creds, char *newpw, krb5_principal change_password_for,
+			int *result_code, krb5_data *result_code_string, krb5_data *result_string);
+krb5_error_code KRB5_CALLCONV
+krb5_set_password_using_ccache
+	(krb5_context context, krb5_ccache ccache, char *newpw, krb5_principal change_password_for,
+			int *result_code, krb5_data *result_code_string, krb5_data *result_string);
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_set_config_files
+	(krb5_context, const char **);
+
+krb5_error_code KRB5_CALLCONV krb5_get_default_config_files
+	(char ***filenames);
+
+void KRB5_CALLCONV krb5_free_config_files
+	(char **filenames);
+#endif
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_profile
+	(krb5_context, struct _profile_t * /* profile_t */ *);
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_send_tgs
+	(krb5_context,
+		krb5_flags,
+		const krb5_ticket_times *,
+		const krb5_enctype *,
+		krb5_const_principal,
+		krb5_address * const *,
+		krb5_authdata * const *,
+		krb5_pa_data * const *,
+		const krb5_data *,
+		krb5_creds *,
+		krb5_response * );
+#endif
+
+#if KRB5_DEPRECATED
+krb5_error_code KRB5_CALLCONV krb5_get_in_tkt
+	(krb5_context,
+		krb5_flags,
+		krb5_address * const *,
+		krb5_enctype *,
+		krb5_preauthtype *,
+		krb5_error_code ( * )(krb5_context,
+					krb5_enctype,
+					krb5_data *,
+					krb5_const_pointer,
+					krb5_keyblock **),
+		krb5_const_pointer,
+		krb5_error_code ( * )(krb5_context,
+					const krb5_keyblock *,
+					krb5_const_pointer,
+					krb5_kdc_rep * ),
+		krb5_const_pointer,
+		krb5_creds *,
+		krb5_ccache,
+		krb5_kdc_rep ** );
+
+krb5_error_code KRB5_CALLCONV krb5_get_in_tkt_with_password
+	(krb5_context,
+		krb5_flags,
+		krb5_address * const *,
+		krb5_enctype *,
+		krb5_preauthtype *,
+		const char *,
+		krb5_ccache,
+		krb5_creds *,
+		krb5_kdc_rep ** );
+
+krb5_error_code KRB5_CALLCONV krb5_get_in_tkt_with_skey
+	(krb5_context,
+		krb5_flags,
+		krb5_address * const *,
+		krb5_enctype *,
+		krb5_preauthtype *,
+		const krb5_keyblock *,
+		krb5_ccache,
+		krb5_creds *,
+		krb5_kdc_rep ** );
+
+krb5_error_code KRB5_CALLCONV krb5_get_in_tkt_with_keytab
+	(krb5_context,
+		krb5_flags,
+		krb5_address * const *,
+		krb5_enctype *,
+		krb5_preauthtype *,
+		krb5_keytab,
+		krb5_ccache,
+		krb5_creds *,
+		krb5_kdc_rep ** );
+#endif /* KRB5_DEPRECATED */
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_decode_kdc_rep
+	(krb5_context,
+		krb5_data *,
+		const krb5_keyblock *,
+		krb5_kdc_rep ** );
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_rd_req
+	(krb5_context,
+		krb5_auth_context *,
+		const krb5_data *,
+		krb5_const_principal,
+		krb5_keytab,
+		krb5_flags *,
+		krb5_ticket **);
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_rd_req_decoded
+	(krb5_context,
+		krb5_auth_context *,
+		const krb5_ap_req *,
+		krb5_const_principal,
+		krb5_keytab,
+		krb5_flags *,
+		krb5_ticket **);
+
+krb5_error_code krb5_rd_req_decoded_anyflag
+	(krb5_context,
+		krb5_auth_context *,
+		const krb5_ap_req *,
+		krb5_const_principal,
+		krb5_keytab,
+		krb5_flags *,
+		krb5_ticket **);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_kt_read_service_key
+	(krb5_context,
+		krb5_pointer,
+		krb5_principal,
+		krb5_kvno,
+		krb5_enctype,
+		krb5_keyblock **);
+krb5_error_code KRB5_CALLCONV krb5_mk_safe
+	(krb5_context,
+		krb5_auth_context,
+		const krb5_data *,
+		krb5_data *,
+		krb5_replay_data *);
+krb5_error_code KRB5_CALLCONV krb5_mk_priv
+	(krb5_context,
+		krb5_auth_context,
+		const krb5_data *,
+		krb5_data *,
+		krb5_replay_data *);
+#if KRB5_PRIVATE
+krb5_error_code KRB5_CALLCONV krb5_cc_register
+	(krb5_context,
+		krb5_cc_ops *,
+		krb5_boolean );
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_sendauth 
+	(krb5_context,
+		krb5_auth_context *,
+		krb5_pointer,
+		char *,
+		krb5_principal,
+		krb5_principal,
+		krb5_flags,
+		krb5_data *,
+		krb5_creds *,
+		krb5_ccache,
+		krb5_error **,
+		krb5_ap_rep_enc_part **,
+		krb5_creds **);
+	
+krb5_error_code KRB5_CALLCONV krb5_recvauth
+	(krb5_context,
+		krb5_auth_context *,
+		krb5_pointer,
+		char *,
+		krb5_principal,
+		krb5_int32, 
+		krb5_keytab,
+		krb5_ticket **);
+krb5_error_code KRB5_CALLCONV krb5_recvauth_version
+	(krb5_context,
+		krb5_auth_context *,
+		krb5_pointer,
+		krb5_principal,
+		krb5_int32, 
+		krb5_keytab,
+		krb5_ticket **,
+		krb5_data *);
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_walk_realm_tree
+	(krb5_context,
+		const krb5_data *,
+		const krb5_data *,
+		krb5_principal **,
+		int);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_mk_ncred
+	(krb5_context,
+		krb5_auth_context,
+		krb5_creds **,
+		krb5_data **,
+		krb5_replay_data *);
+
+krb5_error_code KRB5_CALLCONV krb5_mk_1cred
+	(krb5_context,
+		krb5_auth_context,
+		krb5_creds *,
+		krb5_data **,
+		krb5_replay_data *);
+
+krb5_error_code KRB5_CALLCONV krb5_rd_cred
+	(krb5_context,
+		krb5_auth_context,
+		krb5_data *,
+		krb5_creds ***,
+		krb5_replay_data *);
+
+krb5_error_code KRB5_CALLCONV krb5_fwd_tgt_creds
+	(krb5_context, 
+		krb5_auth_context,
+		char *,
+		krb5_principal, 
+		krb5_principal, 
+		krb5_ccache,
+		int forwardable,
+		krb5_data *);	
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_init
+	(krb5_context,
+		krb5_auth_context *);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_free
+	(krb5_context,
+		krb5_auth_context);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_setflags
+	(krb5_context,
+		krb5_auth_context,
+		krb5_int32);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getflags
+	(krb5_context,
+		krb5_auth_context,
+		krb5_int32 *);
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_set_checksum_func (krb5_context, krb5_auth_context,
+				 krb5_mk_req_checksum_func, void *);
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_get_checksum_func( krb5_context, krb5_auth_context,
+				 krb5_mk_req_checksum_func *, void **);
+
+krb5_error_code KRB5_CALLCONV_WRONG krb5_auth_con_setaddrs
+	(krb5_context,
+		krb5_auth_context,
+		krb5_address *,
+		krb5_address *);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getaddrs
+	(krb5_context,
+		krb5_auth_context,
+		krb5_address **,
+		krb5_address **);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_setports
+	(krb5_context,
+		krb5_auth_context,
+		krb5_address *,
+		krb5_address *);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_setuseruserkey
+	(krb5_context,
+		krb5_auth_context,
+		krb5_keyblock *);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getkey
+	(krb5_context,
+		krb5_auth_context,
+		krb5_keyblock **);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getsendsubkey(
+    krb5_context, krb5_auth_context, krb5_keyblock **);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getrecvsubkey(
+    krb5_context, krb5_auth_context, krb5_keyblock **);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_setsendsubkey(
+    krb5_context, krb5_auth_context, krb5_keyblock *);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_setrecvsubkey(
+    krb5_context, krb5_auth_context, krb5_keyblock *);
+
+#if KRB5_DEPRECATED
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getlocalsubkey
+	(krb5_context,
+		krb5_auth_context,
+		krb5_keyblock **);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getremotesubkey
+	(krb5_context,
+		krb5_auth_context,
+		krb5_keyblock **);
+#endif
+
+#if KRB5_PRIVATE
+krb5_error_code KRB5_CALLCONV krb5_auth_con_set_req_cksumtype
+	(krb5_context,
+		krb5_auth_context,
+		krb5_cksumtype);
+
+krb5_error_code krb5_auth_con_set_safe_cksumtype
+	(krb5_context,
+		krb5_auth_context,
+		krb5_cksumtype);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getlocalseqnumber
+	(krb5_context,
+		krb5_auth_context,
+		krb5_int32 *);
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getremoteseqnumber
+	(krb5_context,
+		krb5_auth_context,
+		krb5_int32 *);
+
+#if KRB5_DEPRECATED
+krb5_error_code KRB5_CALLCONV krb5_auth_con_initivector
+	(krb5_context,
+		krb5_auth_context);
+#endif
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_auth_con_setivector
+	(krb5_context,
+		krb5_auth_context,
+		krb5_pointer);
+
+krb5_error_code krb5_auth_con_getivector
+	(krb5_context,
+		krb5_auth_context,
+		krb5_pointer *);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_setrcache
+	(krb5_context,
+		krb5_auth_context,
+		krb5_rcache);
+
+krb5_error_code KRB5_CALLCONV_WRONG krb5_auth_con_getrcache
+	(krb5_context,
+		krb5_auth_context,
+		krb5_rcache *);
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_auth_con_setpermetypes
+	(krb5_context,
+	    krb5_auth_context,
+	    const krb5_enctype *);
+
+krb5_error_code krb5_auth_con_getpermetypes
+	(krb5_context,
+	    krb5_auth_context,
+	    krb5_enctype **);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_auth_con_getauthenticator
+	(krb5_context,
+		krb5_auth_context,
+		krb5_authenticator **);
+
+#define KRB5_REALM_BRANCH_CHAR '.'
+
+/*
+ * end "func-proto.h"
+ */
+
+/*
+ * begin stuff from libos.h
+ */
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_read_message (krb5_context, krb5_pointer, krb5_data *);
+krb5_error_code krb5_write_message (krb5_context, krb5_pointer, krb5_data *);
+int krb5_net_read (krb5_context, int , char *, int);
+int krb5_net_write (krb5_context, int , const char *, int);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_read_password
+	(krb5_context,
+		const char *,
+		const char *,
+		char *,
+		unsigned int * );
+krb5_error_code KRB5_CALLCONV krb5_aname_to_localname
+	(krb5_context,
+		krb5_const_principal,
+		int,
+		char * );
+krb5_error_code KRB5_CALLCONV krb5_get_host_realm
+	(krb5_context,
+		const char *,
+		char *** );
+krb5_error_code KRB5_CALLCONV krb5_free_host_realm
+	(krb5_context,
+		char * const * );
+#if KRB5_PRIVATE
+krb5_error_code KRB5_CALLCONV krb5_get_realm_domain
+	(krb5_context,
+		const char *,
+		char ** );
+#endif
+krb5_boolean KRB5_CALLCONV krb5_kuserok
+	(krb5_context,
+		krb5_principal, const char *);
+krb5_error_code KRB5_CALLCONV krb5_auth_con_genaddrs
+	(krb5_context,
+		krb5_auth_context,
+		int, int);
+#if KRB5_PRIVATE
+krb5_error_code krb5_gen_portaddr
+	(krb5_context,
+		const krb5_address *,
+		krb5_const_pointer,
+		krb5_address **);
+krb5_error_code krb5_gen_replay_name
+	(krb5_context,
+		const krb5_address *,
+		const char *,
+		char **);
+krb5_error_code krb5_make_fulladdr
+	(krb5_context,
+		krb5_address *,
+		krb5_address *,
+		krb5_address *);
+#endif
+
+krb5_error_code KRB5_CALLCONV krb5_set_real_time
+	(krb5_context, krb5_timestamp, krb5_int32);
+
+#if KRB5_PRIVATE
+krb5_error_code krb5_set_debugging_time
+	(krb5_context, krb5_timestamp, krb5_int32);
+krb5_error_code krb5_use_natural_time
+	(krb5_context);
+#endif
+krb5_error_code KRB5_CALLCONV krb5_get_time_offsets
+	(krb5_context, krb5_timestamp *, krb5_int32 *);
+#if KRB5_PRIVATE
+krb5_error_code krb5_set_time_offsets
+	(krb5_context, krb5_timestamp, krb5_int32);
+#endif
+
+/* str_conv.c */
+krb5_error_code KRB5_CALLCONV krb5_string_to_enctype
+	(char *, krb5_enctype *);
+krb5_error_code KRB5_CALLCONV krb5_string_to_salttype
+	(char *, krb5_int32 *);
+krb5_error_code KRB5_CALLCONV krb5_string_to_cksumtype
+	(char *, krb5_cksumtype *);
+krb5_error_code KRB5_CALLCONV krb5_string_to_timestamp
+	(char *, krb5_timestamp *);
+krb5_error_code KRB5_CALLCONV krb5_string_to_deltat
+	(char *, krb5_deltat *);
+krb5_error_code KRB5_CALLCONV krb5_enctype_to_string
+	(krb5_enctype, char *, size_t);
+krb5_error_code KRB5_CALLCONV krb5_salttype_to_string
+	(krb5_int32, char *, size_t);
+krb5_error_code KRB5_CALLCONV krb5_cksumtype_to_string
+	(krb5_cksumtype, char *, size_t);
+krb5_error_code KRB5_CALLCONV krb5_timestamp_to_string
+	(krb5_timestamp, char *, size_t);
+krb5_error_code KRB5_CALLCONV krb5_timestamp_to_sfstring
+	(krb5_timestamp, char *, size_t, char *);
+krb5_error_code KRB5_CALLCONV krb5_deltat_to_string
+	(krb5_deltat, char *, size_t);
+
+
+
+/* The name of the Kerberos ticket granting service... and its size */
+#define	KRB5_TGS_NAME		"krbtgt"
+#define KRB5_TGS_NAME_SIZE	6
+
+/* flags for recvauth */
+#define KRB5_RECVAUTH_SKIP_VERSION	0x0001
+#define KRB5_RECVAUTH_BADAUTHVERS	0x0002
+/* initial ticket api functions */
+
+typedef struct _krb5_prompt {
+    char *prompt;
+    int hidden;
+    krb5_data *reply;
+} krb5_prompt;
+
+typedef krb5_error_code (KRB5_CALLCONV *krb5_prompter_fct)(krb5_context context,
+					     void *data,
+					     const char *name,
+					     const char *banner,
+					     int num_prompts,
+					     krb5_prompt prompts[]);
+
+
+krb5_error_code KRB5_CALLCONV
+krb5_prompter_posix (krb5_context context,
+		void *data,
+		const char *name,
+		const char *banner,
+		int num_prompts,
+		krb5_prompt prompts[]);
+
+typedef struct _krb5_get_init_creds_opt {
+    krb5_flags flags;
+    krb5_deltat tkt_life;
+    krb5_deltat renew_life;
+    int forwardable;
+    int proxiable;
+    krb5_enctype *etype_list;
+    int etype_list_length;
+    krb5_address **address_list;
+    krb5_preauthtype *preauth_list;
+    int preauth_list_length;
+    krb5_data *salt;
+} krb5_get_init_creds_opt;
+
+#define KRB5_GET_INIT_CREDS_OPT_TKT_LIFE	0x0001
+#define KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE	0x0002
+#define KRB5_GET_INIT_CREDS_OPT_FORWARDABLE	0x0004
+#define KRB5_GET_INIT_CREDS_OPT_PROXIABLE	0x0008
+#define KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST	0x0010
+#define KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST	0x0020
+#define KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST	0x0040
+#define KRB5_GET_INIT_CREDS_OPT_SALT		0x0080
+
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_init
+(krb5_get_init_creds_opt *opt);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_tkt_life
+(krb5_get_init_creds_opt *opt,
+		krb5_deltat tkt_life);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_renew_life
+(krb5_get_init_creds_opt *opt,
+		krb5_deltat renew_life);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_forwardable
+(krb5_get_init_creds_opt *opt,
+		int forwardable);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_proxiable
+(krb5_get_init_creds_opt *opt,
+		int proxiable);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_etype_list
+(krb5_get_init_creds_opt *opt,
+		krb5_enctype *etype_list,
+		int etype_list_length);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_address_list
+(krb5_get_init_creds_opt *opt,
+		krb5_address **addresses);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_preauth_list
+(krb5_get_init_creds_opt *opt,
+		krb5_preauthtype *preauth_list,
+		int preauth_list_length);
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_salt
+(krb5_get_init_creds_opt *opt,
+		krb5_data *salt);
+
+
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_password
+(krb5_context context,
+		krb5_creds *creds,
+		krb5_principal client,
+		char *password,
+		krb5_prompter_fct prompter,
+		void *data,
+		krb5_deltat start_time,
+		char *in_tkt_service,
+		krb5_get_init_creds_opt *k5_gic_options);
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_keytab
+(krb5_context context,
+		krb5_creds *creds,
+		krb5_principal client,
+		krb5_keytab arg_keytab,
+		krb5_deltat start_time,
+		char *in_tkt_service,
+		krb5_get_init_creds_opt *k5_gic_options);
+
+typedef struct _krb5_verify_init_creds_opt {
+    krb5_flags flags;
+    int ap_req_nofail;
+} krb5_verify_init_creds_opt;
+
+#define KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL	0x0001
+
+void KRB5_CALLCONV
+krb5_verify_init_creds_opt_init
+(krb5_verify_init_creds_opt *k5_vic_options);
+void KRB5_CALLCONV
+krb5_verify_init_creds_opt_set_ap_req_nofail
+(krb5_verify_init_creds_opt *k5_vic_options,
+		int ap_req_nofail);
+
+krb5_error_code KRB5_CALLCONV
+krb5_verify_init_creds
+(krb5_context context,
+		krb5_creds *creds,
+		krb5_principal ap_req_server,
+		krb5_keytab ap_req_keytab,
+		krb5_ccache *ccache,
+		krb5_verify_init_creds_opt *k5_vic_options);
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_validated_creds
+(krb5_context context,
+		krb5_creds *creds,
+		krb5_principal client,
+		krb5_ccache ccache,
+		char *in_tkt_service);
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_renewed_creds
+(krb5_context context,
+		krb5_creds *creds,
+		krb5_principal client,
+		krb5_ccache ccache,
+		char *in_tkt_service);
+
+krb5_error_code KRB5_CALLCONV
+krb5_decode_ticket
+(const krb5_data *code, 
+		krb5_ticket **rep);
+
+void KRB5_CALLCONV
+krb5_appdefault_string
+(krb5_context context,
+		const char *appname,  
+	        const krb5_data *realm,
+ 		const char *option,
+		const char *default_value,
+		char ** ret_value);
+
+void KRB5_CALLCONV
+krb5_appdefault_boolean
+(krb5_context context,
+		const char *appname,  
+	        const krb5_data *realm,
+ 		const char *option,
+		int default_value,
+		int *ret_value);
+
+#if KRB5_PRIVATE
+/*
+ * The realm iterator functions
+ */
+
+krb5_error_code KRB5_CALLCONV krb5_realm_iterator_create
+	(krb5_context context, void **iter_p);
+
+krb5_error_code KRB5_CALLCONV krb5_realm_iterator
+	(krb5_context context, void **iter_p, char **ret_realm);
+
+void KRB5_CALLCONV krb5_realm_iterator_free
+	(krb5_context context, void **iter_p);
+
+void KRB5_CALLCONV krb5_free_realm_string
+	(krb5_context context, char *str);
+#endif
+
+/*
+ * Prompter enhancements
+ */
+
+#define KRB5_PROMPT_TYPE_PASSWORD            0x1
+#define KRB5_PROMPT_TYPE_NEW_PASSWORD        0x2
+#define KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN  0x3
+#define KRB5_PROMPT_TYPE_PREAUTH             0x4
+
+typedef krb5_int32 krb5_prompt_type;
+
+krb5_prompt_type* KRB5_CALLCONV krb5_get_prompt_types
+	(krb5_context context);
+
+#if TARGET_OS_MAC
+#    pragma options align=reset
+#endif
+
+KRB5INT_END_DECLS
+
+/* Don't use this!  We're going to phase it out.  It's just here to keep
+   applications from breaking right away.  */
+#define krb5_const const
+
+#endif /* KRB5_GENERAL__ */
+
diff --git a/mechglue/src/include/krb5/.Sanitize b/mechglue/src/include/krb5/.Sanitize
new file mode 100644
index 000000000..2dcb284b3
--- /dev/null
+++ b/mechglue/src/include/krb5/.Sanitize
@@ -0,0 +1,50 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+AddressXlation.h
+ChangeLog
+MacTCP.h
+Makefile.in
+adm.h
+adm_defs.h
+adm_proto.h
+asn.1
+autoconf.h.in
+configure
+configure.in
+copyright.h
+kdb.h
+kdb_dbc.h
+kdb_dbm.h
+stock
+winsock.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/include/krb5/.rconf b/mechglue/src/include/krb5/.rconf
new file mode 100644
index 000000000..0278bafa0
--- /dev/null
+++ b/mechglue/src/include/krb5/.rconf
@@ -0,0 +1,5 @@
+ignore README.encryption
+copy error_tables
+link stock
+ignore config.h
+ignore osconf.h
diff --git a/mechglue/src/include/krb5/ChangeLog b/mechglue/src/include/krb5/ChangeLog
new file mode 100644
index 000000000..dcce9d0a7
--- /dev/null
+++ b/mechglue/src/include/krb5/ChangeLog
@@ -0,0 +1,1309 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (osconf.h): Always remove osconf.new.
+
+2005-10-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (autoconf.stamp): When running config.status, only
+	rebuild autoconf.h.
+
+2005-09-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* adm_proto.h (krb5_adm_connect, krb5_adm_disconnect,
+	krb5_adm_dbent_to_proto, krb5_adm_proto_to_dbent,
+	krb5_adm_proto_to_ktent, krb5_adm_ktent_to_proto,
+	krb5_free_adm_data, krb5_send_adm_cmd, krb5_send_adm_reply,
+	krb5_read_adm_cmd, krb5_read_adm_reply): Delete declarations,
+	since none of these functions exist.
+
+2005-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (osconf.h): Depend on Makefile.  Always display
+	commands executed for replace-if-newer sequence.
+	(PROCESS_REPLACE): Replace @MODULEDIR with $(KRB5_DB_MODULE_DIR).
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (clean-unix): Don't remove autoconf.h.
+
+	Novell merge.
+	* Makefile.in (LIBDIR): New variable.
+	(PROCESS_REPLACE): Replace @LIBDIR.
+	* adm_proto.h (krb5_key_salt_tuple): Conditionalize incomplete
+	typedef on KRB5_KDB5__ instead of KRB5_ADM_H__ and
+	__KADM5_ADMIN_H__.
+	* adm.h (krb5_key_salt_tuple): Move type definition...
+	* kdb.h (krb5_key_salt_tuple): ...to here.
+	(krb5_dbe_apw, krb5_dbe_ark, krb5_dbe_cpw, krb5_dbe_crk): Use
+	krb5_key_salt_tuple instead of struct __krb5_key_salt_tuple in
+	prototype declarations.
+	(osa_policy_ent_t): Move type definition here from kadm5/adb.h.
+	Change element types from uint32_t to krb5_ui_4.
+	(osa_adb_iter_policy_func): Move type definition here from
+	kadm5/adb.h.
+	(KRB5_TL_DB_ARGS): New macro, defined only if SECURID is defined.
+	(KRB5_KDB_OPEN_RW, KRB5_KDB_OPEN_RO, KRB5_KDB_OPT_SET_DB_NAME,
+	KRB5_KDB_OPT_SET_LOCK_MODE): New macros.
+	(KRB5_DB_LOCKMODE_SHARED, KRB5_DB_LOCKMODE_EXCLUSIVE,
+	KRB5_DB_LOCKMODE_DONTBLOCK, KRB5_DB_LOCKMODE_PERMANENT): New
+	macros.
+	(kdb5_db_create, kdb_def_get_mkey, kdb_def_set_mkey,
+	krb5_db_alloc, krb5_db_clr_error, krb5_db_create_policy,
+	krb5_db_def_fetch_mkey, krb5_db_delete_policy,
+	krb5_db_errcode2string, krb5_db_free, krb5_db_free_master_key,
+	krb5_db_free_policy, krb5_db_get_policy, krb5_db_inited,
+	krb5_db_iter_policy, krb5_db_open, krb5_db_put_policy,
+	krb5_db_set_master_key_ext, krb5_db_set_option,
+	krb5_db_store_master_key, krb5_dbe_def_cpw,
+	krb5_dbe_def_search_enctype, krb5_dbe_update_last_pwd_change,
+	krb5_def_store_mkey, krb5_def_verify_master_key,
+	krb5_free_supported_realms, krb5_key_salt_tuple,
+	krb5_supported_realms, osa_adb_iter_policy_func,
+	osa_policy_ent_rec, osa_policy_ent_t): New (or moved)
+	declarations.
+	(krb5_db_close_database, krb5_db_iterate_ext,
+	krb5_db_open_database, krb5_db_rename, krb5_db_set_lockmode,
+	krb5_db_set_name, krb5_db_set_nonblocking, krb5_db_store_mkey,
+	krb5_dbe_free_contents, krb5_decode_princ_contents,
+	krb5_encode_princ_contents, krb5_encode_princ_dbkey,
+	krb5_free_princ_contents, krb5_free_princ_dbkey,
+	krb5_ser_db_context_init): Declarations deleted (or moved).
+	(krb5_db_create): Changed signature, just one char** arg in
+	addition to context.
+	(krb5_db_delete_principal): Changed argument 1 to non-const
+	principal.
+	(krb5_db_destroy): Changed argument 1 to char**.
+	(krb5_db_free_principal): Changed return type from void to
+	krb5_error_code.
+	(krb5_db_iterate): Changed signature, new char* argument,
+	pointed-to function returns int instead of krb5_error_code.
+
+2005-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (thisconfigdir, mydir): Updated for configure
+	change.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* adm_proto.h, kdb.h, kdb_dbc.h, kdb_kt.h: Don't test macintosh.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac, clean-mac): Targets deleted.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2003-08-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5-config.h: Unused file deleted.
+
+2003-05-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb.h: Add prototype for krb5_db_iterate_ext.
+
+2003-03-05  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_kt.h: Add krb5_ktkdb_set_context.  Update prototype of
+	krb5_ktdb_resolve.  Add krb5_kt_kdb_ops.
+
+2003-03-05  Sam Hartman  <hartmans@mit.edu>
+
+	* Remove kdb_dbm.h
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* kdb.h (KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2): Remove trailing colon,
+	as new implementation of krb5_read_password() appends it.
+
+2002-09-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* adm.h (struct __krb5_realm_params): New field
+	realm_kdc_tcp_ports.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* kwinsock.h, macsock.h: Deleted.
+
+2002-05-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* MacTCP.h, AddressXlation.h: Deleted.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* macsock.h (PROTOTYPE): Don't define.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* adm_defs.h, kdb.h, kdb_dbc.h, kdb_dbm.h, kdb_kt.h, kwinsock.h:
+	Don't explicitly declare pointers or functions FAR any more.  Drop
+	_MSDOS support.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* adm_proto.h: Don't use KRB5_DLLIMP.
+
+2001-09-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* adm.h (struct __krb5_realm_params): Added fields
+	realm_reject_bad_transit, realm_reject_bad_transit_valid; deleted
+	field realm_filler.
+
+2001-07-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb.h: For structs krb5_tl_data (tl_data_length), krb5_key_data
+	(key-data_length), krb5_db_entry (len, e_length) change the
+	storage types from krb5_int16 to krb5_ui_2. This does not require
+	a database version change as the field sizes are the same. Remove
+	the code ifdefed under KRB5_OLD_AND_KRUFTY.
+
+2001-04-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* .cvsignore: Add stamp-h.in
+
+2001-02-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* adm_proto.h (krb5_adm_connect): Declare prompt string const char *. 
+
+2001-01-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* adm_proto.h, kdb.h, kdb_dbc.h, kdb_dbm.h, kdb_kt.h: Make all
+	prototypes unconditional.
+
+2000-05-30  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in, osconf.h: Use bindir and sbindir from configure
+	rather than building them up from EXEC_PREFIX.
+
+2000-5-18	Alexandra Ellwood <lxs@mit.edu>
+
+	* macsock.h: local_addr_fallback_kludge defined to 0
+ 	again... fixed gethostname
+
+2000-5-9	Alexandra Ellwood <lxs@mit.edu>
+
+	* macsock.h: local_addr_fallback_kludge now defined to magic gethostaddr function
+	in the Sockets Library, which does exactly what we want if the search domain is not
+	specified.
+
+1998-11-22  Miro Jurisic  <meeroh@.mit.edu>
+
+	* macsock.h: MacOS: only #define MACHOSTNAMELEN when not
+	already defined
+
+Wed May 19 11:35:18 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Create build rules for windows instead of blindly
+		copying files.  Wrap Unix build rules with !if 0/!endif
+		that get used only in windows build.  People need to
+		remember to keep this !if/!endif in the proper place when
+		they modify this file.
+
+Mon May 17 12:33:58 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add NO_OUTPRE flag to prevent creation of output
+		directory under win32.
+
+Fri May  7 15:26:44 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* adm_proto.h: Fix the existing kludge to deal with the fact that
+		krb5_realm_params is defined in two, count them two,
+		header files.  There's real ugliness here that needs
+		cleaning up eventually, but I don't have the time now to
+		deal with it.
+
+Fri Apr 16 17:07:47 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Don't constantly recreate autoconf.h
+		with #include "win-mac.h"
+
+1999-04-09  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdb.h: Add new TL types provided by Frank Cusack's preauth patch
+		(PR# [krb5-kdc/662])
+
+Tue Nov 17 15:39:32 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kdb.h: Update dbe_crk and dbe_cpw to take a boolean to indicate
+	whether old keys should be retained.
+
+	* Makefile.in (autoconf.stamp): Fix up to deal with config.status
+	not being in the current directory anymore.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+		Add a MY_SUBDIRS macro set to '.' to indicate that there
+		are no subdirectories to be processed by the Makefile.
+
+	* configure.in: Removed and tests moved to parent directory.
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* kdb_dbc.h, kdb.h: update kdb api to be compatible with the new
+	crypto api.
+
+Wed Jul  8 04:30:22 1998  Geoffrey King  <gjking@mit.edu>
+
+	* adm_proto.h: Added prototype for new function krb5_klog_reopen()
+
+Thu Apr 16 23:50:08 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Search for /var/tmp first when determining rcache
+	directory. [krb5-libs/548]
+
+Wed Feb 18 15:52:36 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Sep 30 17:19:16 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Remove references to dbm and ndbm.  Replace
+	HAS_STDLIB_H and NO_STDLIB_H with something more sane.  Replace
+	AC_TIME_WITH_SYS_TIME with more a recent form.  Use AC_CHECK_TYPE
+	to check for time_t instead of erroneously named POSIX_TYPES.
+
+Thu Sep 25 21:50:44 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Replace KRB5_USE_INET, HAS_UNISTD_H, HAS_SETVBUF.
+
+Thu Sep 18 20:42:03 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Replace USE_STRING_H, HAS_STRDUP, HAS_LABS
+
+Mon Sep 15 15:01:49 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_dbm.h: Add const to argument of krb5_dbm_db_get_principal.
+	    Add prototype for krb5_dbm_db_delete_principal.
+
+	* kdb.h: Prototypes for krb5_db_get_principal,
+            krb5_db_delete_principal, krb5_dbe_update_mod_princ_data,
+            krb5_encode_princ_dbkey modified to use const krb5_principals.
+
+Fri Jul 25 15:18:25 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_kt.h: Move support for "kdb" keytab here.
+
+	* kdb.h: Add support for modified kdb API; remove extra arguments
+	for db_set_mkey and db_get_mkey.  Remove all (hopefully) mentions
+	of any particular backend database implementation.  Add flags
+	argument for db_create, allowing caller to specify whether btree
+	or hash methods are to be used in the backend.
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in:
+		all-windows needed :: not :
+		clean up various generated files on all platforms, not just unix
+
+Wed Oct 30 18:55:21 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (LOCALSTATEDIR): Add localstatedir a and sysconfidr
+ 	to substitutions [37]
+for osconf.h
+Mon Aug 26 17:01:11 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdb.h: add KRB5_TL_KADM5_E_DATA
+
+Fri Aug 23 16:20:54 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdb.h: Remove dbm_error and dbm_clearerr from the dispatch table
+		(which eventually should be completely removed.)
+
+Wed Jun 12 00:40:29 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* adm_proto.h: Change usage of INTERFACE to use KRB5_CALLCONV and
+	 	KRB5_DLLIMP.
+
+Mon Jun 10 17:31:29 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* winsock.h: Rename to kwinsock.h.  Recent versions of Microsoft
+		compilers include winsock.h, and the one we have collides
+		with NT errno definitions.  Using the one provided by the
+		compiler is preferable.  If you are using an old version
+		of MSVC that doesn't include winsock.h, then rename
+		kwinsock.h to winsock.h
+
+	* kdb_dbm.h: Don't include kdb_dbm.h for Win-32.
+
+	* kdb.h: Don't include most of kdb.h for Win-32.
+
+Mon May 20 17:57:15 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Remove support for ODBM.
+
+Sun May 19 14:32:19 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Check for uid_t.
+
+Sun May 12 00:46:05 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kdb.h: convert to use new krb5_dbe_* tl_data functions.
+
+	* adm.h (struct __krb5_realm_params): add realm_acl_file
+	
+Tue Apr 30 17:15:57 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Invoke AC_C_CROSS before AC_TRY_RUN to pretty up
+	output format.
+
+	* Makefile.in (autoconf.h): Use timestamp file to prevent repeated
+	rebuilding if file timestamp is out of date but contents wouldn't
+	change.
+
+Tue Apr 30 15:03:34 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* macsock.h: Added prototype for getpeername().
+
+Thu Mar 28 17:57:04 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* AddressXlation.h: Updated to use latest versions from the Apple's
+		MacTCP Universal Interface.  (For PowerPC port).
+
+	* MacTCP.h: New header file from Apple's Universal Interface
+
+	* GetMyIPAddr.h, MacTCPCommonTypes.h, TCPPB.h, UDPPB.h: Removed
+		old MacTCP header files.
+
+Wed Mar 13 17:43:35 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Use AC_HEADER_STDARG.
+
+Wed Jan 24 14:23:07 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* adm.h: Added lines to adm.h which Chris had removed while
+		working on the kadmin revisions.  This allows the existing
+		code to compile.
+
+Mon Jan 22 17:36:00 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Use KRB5_CHECK_PROTOS instead of inlining
+		prototype checking.
+
+Wed Dec 13 03:51:53 1995  Chris Provenzano (proven@mit.edu)
+
+	* kdb.h : Remove mkvno for krb5_db_entry
+
+Tue Dec 12 00:59:17 1995  Chris Provenzano (proven@mit.edu)
+
+	* adm.h: Added principal flag keywords KRB5_ADM_KW_SETFLAGS and
+		KRB5_ADM_KW_UNSETFLAGS because relative flag modification 
+		is just a good idea.
+	* kdb.h: typedef kdb5_dispatch_table so prototypes that need it
+		compile even if KDB5_DISPATCH isn't defined.
+	* kdb_dbc.h: The start of the database context, which should be
+		removed from the krb5_context.
+
+Sun Dec 10 11:02:35 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* adm_proto.h: Add prototype for krb5_input_flag_to_string.
+
+Fri Dec  1 17:16:05 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* adm.h: Added temporary definition of KRB5_ADM_M_EXTRADATA so
+		that we have a tree which compiles.
+
+Tue Nov  7 16:41:14 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdb.h: Added prototype for krb5_dbe_search_enctype().  Changed
+		prototype of krb5_dbe_find_enctype() so that ktype is of
+		type krb5_int32.  (krb5_enctype is unsigned, so -1 doesn't
+		work!) 
+
+Fri Nov 03 04:37:56 1995   Chris Provenzano (proven@mit.edu)
+
+        * adm.h : Constant changes for the new kadmin code.
+	* kdb.h : Added attribute bit KRB5_KDB_NEW_PRINC. This will 
+		allow kadmin administrators with add acls to modify a
+		principal until this bit is cleared. 
+
+Fri Oct  6 21:58:05 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Thu Oct  5 21:33:27 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* adm.h: Remove pport and sport from the krb5_realm_params file,
+		and replace it with ports, which is a char * list of all
+		of the ports which should be listed to for this realm.
+
+Fri Sep 29 14:37:41 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (clean-unix): Remove autoconf.h on make clean
+
+Wed Sep 27 16:00:00 1995  John Rivlin <jrivlin@fusion.com>
+
+	* adm_proto.h: Removed use of prototypes using krb5_db_entry
+		on the Macintosh. 
+
+Tue Sep 26 15:36:20 1995    <tytso@rsts-11.mit.edu>
+
+	* kdb.h, kdb_dbm.h: Add #if !defined(_MSDOS) &&
+		!defined(_MACINTOSH) to prevent these #includes from being
+		used by Mac and PC machines.
+
+Mon Sep 25 16:39:36 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Thu Sep 20 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* macsock.h:  Changes to support TCP streams and change password.
+
+Thu Sep  8 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* k5-config.h:  defined MPW fake stat.h out for metrowerks compiler
+	* macsock.h:  changed SOCKET definition for MACINTOSH to start support for
+		TCP streams
+	* TCPBP.h:  fixed up some prototype problems with out customized tcp sockets
+		for macintosh
+
+Thu Sep  7 15:53:28 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* adm.h (KRB5_ADM_SERVICE_NAME): Use official IANA assigned name
+		for the port, which is kpasswd, not changepw.  Add new
+		define, KRB5_ADM_SERVICE_INSTANCE, which defines the
+		instance name used for the kadmin name.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * adm.h, adm_proto.h kdb.h : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * adm_proto.h : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate.
+
+Thu Aug 31 11:38:58 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add checks for stddef.h and xom.h for use by GSSAPI-V2
+
+
+Tue Aug 29 13:28:10 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb.h - Add prototype for krb5_ser_db_context_init().
+
+
+Mon Aug 21 17:00:58 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm_proto.h - Add krb5_timestamp_to_sfstring() prototype.
+
+
+Tue Aug 15 14:27:02 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb.h - Add prototype for krb5_dbe_find_keytype().
+
+
+Thu Aug 10 14:33:51 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb.h - Always define KRB5_MAX_FAIL_COUNT.
+
+
+Mon Aug 07 11:22:57 1995   Chris Provenzano (proven@mit.edu)
+
+	* kdb.h : Add prototypes for krb5_dbe_{en,de}code_last_pwd_change(),
+		krb5_dbe_{apw,cpw,ark,crk}(),
+
+Fri Aug 4 16:10:34 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm_proto.h - Add prototype definitions for new libkadm functions in
+		keysalt.c dealing with key/salt tuples.
+	* kdb.h - Add encode/decode macros for integers for use between kdb
+		modules.
+
+Thu Aug 03 12:19:52 1995   Chris Provenzano (proven@mit.edu)
+
+	* kdb.h : Added prototype for krb5_dbe_cpw() the new dd entry
+		change password routine.
+
+Mon Jul 31 15:50:25 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm.h - Add new protocol definitions.  Also, add krb5_key_salt_tuple
+		and add it to the krb5_read_realm_params structure so that
+		we have a list of supported key/salt pairs.  Convert keytype
+		and enctype to be the correct datatype.
+	* adm_proto.h - Add string conversion prototypes.
+
+
+Thu Jul 27 15:06:35 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* {asn1,dbm,ext-proto,k5-{config,errors,sockets},libos,los-proto,
+	   mit-des,preauth,rsa-md5,sysincl}.h - Deleted.
+	* Makefile.in - Remove these headers from KRB5_HEADERS.
+	* configure.in - Change AC_INIT to look for kdb.h.
+
+
+Thu Jul 27 02:59:05 1995   Chris Provenzano (proven@mit.edu)
+
+        * kdb.h - Define new kdb format.
+
+Mon Jul 17 15:03:43 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm.h - Add per-realm parameter block data structure
+		(krb5_realm_params).
+	* adm_proto.h - Add dummy declaration for krb5_realm_params if adm.h
+		not included.  Add prototypes for realm parameter functions.
+	* kdb.h - Add stash file parameter to krb5_db_fetch_mkey().
+
+Sun Jul  9 21:47:49 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* los-proto.h: Add krb5_auth_con_genaddrs prototype
+
+Fri Jul 7 15:58:07 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* rsa-md5.h - Add RSA_MD5_DES_CONFOUND_LENGTH - the length of the
+		confounder for RSA_MD5_DES per RFC1510.
+
+Wed July  5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* k5-config.h Added _MACINTOSH for macintosh build conditions
+	* macsock.h made definition of PROTOTYPE conditional
+
+Fri Jun 30 16:13:41 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb.h - Add kdb dispatch table and set routine under KDB5_DISPATCH.
+
+
+Tue Jun 27 16:12:09 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm_proto.h - Change second argument of aprof_get... routines to be
+		const char *.
+	* configure.in, k5-config.h - Reinstate KRB5_PROVIDE_PROTOTYPES.  This
+		is needed for compilers which recognize prototypes but don't
+		set __STDC__ or _WINDOWS.
+
+Thu Jun 22 16:11:07 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* k5-config.h: remove definition for KRB5_PROVIDE_PROTOTYPES
+		because we've reversed the sense
+
+	* configure.in: KBR5_PROVIDE_PROTOTYPES -> KRB5_NO_PROTOTYPES;
+		NO_NESTED_PROTOTYPES -> KRB5_NO_NESTED_PROTOTYPES
+
+	* rsa-md5.h: reverse sense of KRB5_PROVIDE_PROTOTYPES
+
+Thu Jun 22 11:52:07 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm_proto.h - Add prototypes for kadm library profile handling
+		routines.  These are wrappers for profile routines.
+	* kdb.h - Remove KDB_CONVERT_KEY_{TO,OUTOF}_DB.
+
+Wed Jun 21 17:39:25 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Replace krb5_sigtype tests with KRB5_SIGTYPE which
+		has been moved to aclocal.m4
+
+Wed Jun 21 10:44:06 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in: Don't remove autoconf.h when doing a make clean;
+		it's an autoconf generated file.
+
+	* adm_proto.h, asn1.h, ext-proto.h, kdb.h, kdb_dbm.h, los-proto.h,
+		preauth.c: Change PROTOTYPE -> KRB5_PROTOTYPE
+
+Sat Jun 10 22:11:45 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* adm_proto.h: update krb5_auth_context stuff
+
+Fri Jun  9 18:42:30 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Jun 8 14:41:00 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm_proto.h - Add prototypes for logging routines.  Also, if
+		kdb.h has not been included, add null structure for entry
+		data structure so that we don't strictly require kdb.h.
+
+Thu Jun  8 11:11:24 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* Makefile.in (install): Don't install the install/krb5 header files.
+
+Wed Jun  7 16:23:51 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in: Process osconf.h using PREFIX and EXEC_PREFIX
+		instead of KRB5ROOT.
+
+	* k5-config.h: Remove old defines for krb.conf and krb.realms,
+		which are now obsolete.
+
+Mon Jun 5 13:47:30 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm_proto.h - Add new arguments to krb5_adm_connect() for support
+		of specifiable credentials caches and ticket lifetimes.
+
+
+Thu Jun 1 14:28:40 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* adm.h: Change the default admin port to 464.
+
+Tue May 30 17:33:09 1995 Keith Vetter (keithv@fusion.com)
+
+	* adm_proto.h: removed INTERFACE from 2 non-exported functions.
+
+Tue May 30 10:22:57 1995 Keith Vetter (keithv@fusion.com)
+
+	* adm_proto.h: conditionally removed for Windows two prototypes
+	   that use the database.
+	* k5-config.h: bumped MAXPATHLEN and removed need for the kdb.h file.		
+
+Fri May 26 10:17:12 1995 Keith Vetter (keithv@fusion.com)
+
+	* adm_proto.h: added more missing INTERFACE.
+	* los-proto.h: moved in prototype for gmt_mktime().
+
+Thu May 25 19:27:45 1995 Keith Vetter (keithv@fusion.com)
+
+	* adm_proto.h: two function's prototype were missing INTERFACE.
+	* k5-config.h: kadm needs the kdb.h file.
+
+Thu May 25 15:39:31 1995 Keith Vetter (keithv@fusion.com)
+
+	* los-proto.h: moved in the prototype for krb5_make_fulladdr.
+
+Tue May 23 15:33:00 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* k5-config.h, k5-sockets.h: Move the sockets specific setup out
+		  of k5-config.h to k5-sockets.h, and modify k5-int to
+		  include k5-sockets.h (if it is requested by
+		  NEED_SOCKETS) after including krb5.h.  This keeps the
+		  gdb type numbers the same across .o files, so that
+		  recent binuntils can compress the debugging information
+		  in executables linked with a debugging library.
+
+Mon May 22 09:41:39 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in	- (install) Always perform install actions using
+			  $(INSTALL_DATA).
+	* configure.in	- Locate install program.
+
+Sun May 21 15:25:45 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (PROCESS_REPLACE): Replace the RCTMPDIR in stock.h
+		with a configuration determined directory
+
+	* configure.in: Determine which directory to use for the replay
+		cache. (/usr/tmp does not exist on netbsd).
+
+Wed May 10 13:20:47 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (install): Install ET_HEADERS...
+
+Tue May 9 15:17:00 EDT 1995	Paul Park	(pjpark@mit.edu)
+	Add definitions and prototypes for new administrative protocol.
+
+Mon May  8 22:13:15 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* los-proto.h: krb5_read_password - prompt strings should be const
+		char *. 
+		Remove krb5_init_os_context and krb5_free_os_context. (The
+		proper prototypes are already in place i.e.
+		krb5_os_init_context). 
+
+Fri Apr 28 15:14:38 EDT 1995	Paul Park	(pjpark@mit.edu)
+	Remove INTERFACE from prototype definitions in adm_proto.h
+
+Fri Apr 28 11:11:54 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: correct use of --with-krb4 to match top level.
+
+Thu Apr 27 17:39:04 1995 Keith Vetter (keithv@fusion.com)
+
+	* k5-config.h: Added MAXPATHLEN constant.
+	* adm_prot.h: updated prototype.
+
+Thu Apr 27 11:24:24 1995 Keith Vetter (keithv@fusion.com)
+
+	* k5-config.h: Changed over to the new single config file on the PC.
+
+Wed Apr 26 10:41:08 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: Reflect current list of headers to be installed.
+
+Thu Apr 20 11:35:07 1995    <tytso@rsx-11.mit.edu>
+
+	* k5-config.h, configure.in: Remove support for HAS_ANSI_CONST
+		(that was needed only for compatibility with the old imake
+		build; autoconf uses -Dconst=), and HAS_ANSI_VOLATILE,
+		which isn't used at all.
+
+Wed Apr 19 13:25:56 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* func-proto.h: Remove global_context hack. Added prototype for
+		krb5_set_default_realm.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+        * asn1.h, ccache.h, encryption.h, func-pro.h, hostaddr.h, keytab.h,
+          los-prot.h, preauth.h, rcache.h: 
+            removed unneeded INTERFACE from non-api functions.
+        * adm_defs.h, ccache.h, encryption.h, hostaddr.h, k5-free.h, keytab.h,
+          macros.h, rcache.h:
+           Added FAR to pointers visible to the world.
+        * base-def.h, ext-prot.h, rsa-md5.h: __STDC__ condition also 
+           checks for the _WINDOWS define.
+
+Wed Apr 5 16:41:41 1995 Keith Vetter (keithv@fusion.com)
+
+	* los-proto.h, func-proto.h: moved krb5_us_timeofday and 
+           krb5_sname_to_principal from the former to the latter.
+        * base-def.h: added FAR to pointer types for the PC.
+        * func-proto.h: added FAR to pointer types in prototypes but
+           only for functions which are exported.
+
+Fri Mar 31 19:34:47 1995 Keith Vetter (keithv@fusion.com)
+
+	* k5-config.h: defined dup to _dup for STDC stuff on Windows
+
+Fri Mar 31 16:12:28 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in (CONFIG_RULES): Replaced.
+
+Thu Mar 30 15:57:22 1995 Keith Vetter (keithv@fusion.com)
+
+	* func-proto.h: added 2 missing prototypes dealing with auth_con.
+
+Tue Mar 28 19:53:09 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed to reflect deletion of stock/osconf.win.
+        * k5-config.h: added constants for reading default values
+            out of Windows ini files.
+        * los-proto.h: added new prototype for Windows ini stuff.
+
+Tue Mar 28 18:02:41 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (KRB5_HEADERS, install):  Account for file renames.
+	(all-mac):  Add.
+	* configure.in (CONFIG_RULES):  Remove.
+	(krb5_sigtype):  Define as either void or int.
+	* encryption.h:  Insert parentheses in macros to avoid mis-expansion.
+	* k5-config.h:  Further parameterize socket support.
+	* macsock.h:  Support connect(), recv(), send(), getmyipaddr().
+	(WSAGetLastError):  Fix typo -- there's no argument to this macro.
+
+	* k5-errors.h:  Rename errors.h (which duplicated a standard Mac
+	header name, causing a problem).
+	* AddressXlation.h, GetMyIPAddr.h, MacTCPCommonTypes.h, TCPPB.h, 
+	UDPPB.h:  Add MacTCP header files.
+
+Mon Mar 27 09:33:10 1995  Chris Provenzano (proven@mit.edu)
+
+        * func-proto.h (krb5_rd_req(), krb5_rd_req_decode(), krb5_mk_rep(),
+                krb5_recvauth(), and krb5_compat_recvauth(). Added a 
+		krb5_auth_context argument and eliminated many of the 
+		other arguments because they are included in the 
+		krb5_auth_context structure.
+
+Fri Mar 24 14:15:51 1995    <tytso@rsx-11.mit.edu>
+
+	* adm_defs.h (ADM5_DEFAULT_PORT): Add definition of default
+		administration port.
+
+	* Makefile.in (install): Delete the destination header files
+		before copying in the new ones.  Also install autoconf.h.
+		Only install header files if the header file has changed.
+
+Wed Mar 22 11:37:24 1995 Keith Vetter (keithv@fusion.com)
+
+	* k5-config.h: added HAVE_SYS_TYPES_H. Cleaned up the loading
+           of sys/types.h which john added earlier. Specifically, we always
+           have it and it's missing some typedefs used by this code.
+
+Tue Mar 21 18:42:23 1995 Keith Vetter (keithv@fusion.com)
+
+	* k5-config.h: PC: NO_PASSWORD defined and files opened in binary mode.
+	* func-proto.h: added new prototype for notify programs when the 
+           ccache changes, and moved krb5_get_default_realm from los-proto.h.
+        * los-proto.h: moved krb5_get_default_realm into func-proto.h.
+
+Sun Mar 19 12:51:59 1995  John Gilmore  (gnu at toad.com)
+
+	* base-defs.h:  Fix comment that referred to STDARG_PROTOTYPES.
+
+Fri Mar 17 19:12:13 1995  John Gilmore  (gnu at toad.com)
+
+	* k5-config.h:  Move <sys/types.h> handling from ../krb5.h to
+	here, because we need <sys/types.h> or the u_* types to be defined
+	before we include the Unix socket include files a little later in
+	k5-config.h.  We actually add this code twice, once in the MSDOS
+	section and once in the Unix/Mac section.
+	(NEED_SOCKETS):  Also include <net/if.h>, for localaddr.c.
+	* Makefile.in (clean-mac):  Add.
+
+Tue Mar 14 16:50:54 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in: Delete definition for KRB5ROOT and KRB5_INCDIR,
+		since those are defined in pre/config.in.
+
+Thu Mar 16 20:58:22 1995  John Gilmore  (gnu at toad.com)
+
+	* configure.in:  Replace nonstandard CHECK_STDARG with
+	AC_CHECK_HEADERS.  Also check for header file macsock.h, which
+	is a dummy test -- it's false on Unix and PC's, but on the Mac
+	we hand-configure it to be true, to indicate that we want Mac
+	socket support rather than Unix socket support.
+	* base-defs.h, k5-config.h:  Use HAVE_STDARG_H, not STDARG_PROTOTYPES.
+	* k5-config.h (NEED_SOCKETS):  Add new section which brings in
+	socket include files for the appropriate compilation environment
+	(Mac or Unix; Windows already did this).
+	* macsock.h:  New include file, derived from Cygnus Network Security
+	Mac K4 release, for simulating sockets under MacTCP.
+
+Thu Mar 16 12:12:17 1995 Keith Vetter (keithv@fusion.com)
+
+	* k5-config.h: PC change, getting sys_nerr and sys_errlist to work.
+
+Tue Mar 14 17:38:28 1995 Keith Vetter (keithv@fusion.com)
+
+	* k5-config.h: more PC changes, mostly dealing with chmod not 
+	   working as it should on the PC.
+	* func-proto.h, los-proto.h: moved prototypes for krb5_timeofday and
+	   krb5_os_localaddr from los-proto to func-proto. They are needed by
+	   the outside world, specifically kinit.c
+
+Fri Mar 10 14:23:12 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sysincl.h: Removed definition of FD_SETSIZE, FD_SET, FD_CLR,
+		FD_ISSET, and FD_ZERO.  Defining them in favor of using
+		the system include files is almost always wrong.
+
+Fri Mar 10 10:04:41 1995 Chris Provenzano (proven@mit.edu)
+
+	* func-proto.h (krb5_mk_req(), krb5_mk_req_extended(), krb5_rd_rep(),
+		krb5_sendauth(), krb5_mk_priv(), krb5_rd_priv(), krb5_mk_safe(),
+		and krb5_rd_safe()). Added a krb5_auth_context argument and
+		eliminated many of the other arguments because they are 
+		included in the krb5_auth_context structure.
+
+	* fieldbits.h Added #define AP_OPTS_USE_SUBKEY 0x00000001 for a
+		new option to an ap req message. This is mainly a clean way
+		to inform krb5_mk_req() and krb5_mk_req_extended() to 
+		create the subkey without adding an extra argument.
+
+	* safepriv.h Replace safe/priv flags with flags for krb5_auth_context
+		and add krb5_replay_data structure for when the appilication
+		want to do it's own replay detection for safe and priv calls.
+
+
+Thu Mar  9 18:29:24 1995  Mark Eichin  <eichin@cygnus.com>
+
+       * Makefile.in (all-windows): tabs, not spaces.
+
+Tue Mar 7 14:54:02 1995 Keith Vetter (keithv@fusion.com)
+
+	* ccache.h: added windows INTERFACE keyword to all functions.
+        * encryption.h: more segment games for the PC--added NEAR to three
+           external data objects.
+        * wordsize.h: added constants VALID_INT_BTIS and VALID_UINT_BITS for
+           detecting overflow when casting a long to an int.
+        * k5-config.h: numerous PC changes such as adding NEED_LOWLEVEL_IO
+           which enables the read/write level of I/O.
+        * Makefile.in: osconf.h now pulled in from stock/osconf.win.
+
+Thu Mar  2 23:21:46 1995  John Gilmore  (gnu at toad.com)
+
+	Make include files start to work on the Macintosh.
+
+	* configure.in:  Add checks for sys/types.h and sys/stat.h.
+	* k5-config.h:  Remove krb5/ from #include.
+	* sysincl.h:  Avoid <sys/types.h>.  Conditional-include <sys/stat.h>.
+
+Thu Mar 2 13:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* k5-config.h: changed NEED_WINSOCK_H to NEED_SOCKETS
+
+Wed Mar 1 20:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* func-proto.h: fixed up a const attribute to krb5_send_tgs.
+
+Wed Mar 1 17:40:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* func-proto.h: added missing prototype for krb5_mk_cred.
+	* los-proto.h: added windows INTERFACE keyword to all functions,
+	   plus added 2 missing prototypes: krb5_os_init_context and
+	   krb5_os_free_context.
+
+Wed Mar 1 12:48:20 1995 Keith Vetter (keithv@fusion.com)
+
+	* config.h: added defines to pull in winsock.h as needed
+        * rcache.h: added windows INTERFACE keyword to all functions
+        * winsock.h: new file--for windows socket stuff
+
+Wed Mar  1 17:45:13 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in, k5-config.h: Only define labs(x) -> abs(x) if
+		labs() is not defined elsewhere.  (This really shouldn't
+		be here at all, but is the expedient way to deal with lack
+		of labs().)
+
+	* Makefile.in: Change config.h -> k5-config.h and free.h ->
+		k5-free.h to reflect renamed header files for Mac/PC port.
+
+Mon Feb 27 23:47:58 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (osconf.h):  Remove temp file osconf.new.
+
+	* krb5.h:  Rename to ../krb5.h so it can be #included by end users
+	without the use of slashes or extra -I options.  First step in
+	making it stand alone without a train of a dozen other include
+	files tagging along behind.
+
+	* base-defs.h, dbm.h, error_def.h, sysincl.h:  Avoid #include
+	<krb5/...> form; use "..." form.
+
+	* config.h:  Rename to k5-config.h.  This is too common a
+	name, now that we use -I..../include/krb5.
+	* free.h:  Rename to k5-free.h.
+
+	* configure.in (AC_INIT):  Use another file (not krb5.h) as src test.
+
+Mon Feb 27 11:35:49 1995 Keith Vetter (keithv@fusion.com)
+
+        * config.h: added windows interface keyword for varargs functions,
+           added defines to allows <windows.h> to be stdc compliant.
+	* func-proto.h: added windows INTERFACE_C keyword for functions
+           with varargs, and fixed const in prototype for krb5_send_tgs.
+        * preauth.h: added windows INTERFACE keyword to prototypes
+
+Wed Feb 22 17:39:46 1995 Chris Provenzano (proven@mit.edu)
+
+	* func-proto.h (krb5_get_credentials(), krb5_get_cred_from_kdc(),
+		and krb5_sendauth()) replaced krb5_cred * IN/OUT arg with
+		a krb5_cred * IN and a krb5_cred ** OUT arg.
+	* func-proto.h (krb5_mk_req_extended()) Remove kdc_options flag arg
+		and krb5_ccache arg. They are no longer necessary.
+	
+Wed Feb 22 01:45:17 1995 Keith Vetter (keithv@fusion.com)
+
+	* keytab.h: added windows INTERFACE keyword to prototypes
+
+Tue Feb 21 17:31:06 1995 Keith Vetter (keithv@fusion.com)
+
+	* config.h: added HAVE_ERRNO for the windows section
+           changed windows manifest constant from __windows__ 
+           to _MSDOS so that DOS test programs will compile.
+
+Tue Feb 21 12:00:32 1995 Keith Vetter (keithv@fusion.com)
+
+	* asn1.h: added windows INTERFACE keyword to all functions.
+
+Tue Feb 21 17:49:41 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* config.h: get krb5/autoconf.h.
+	* Makefile.in (KRB5_HEADERS): add config.h, remove rsa-md4.h and
+	crc-32.h which aren't here anymore.
+
+Tue Feb 21 0:0:32 1995 Keith Vetter (keithv@fusion.com)
+
+	* func-proto.h: added windows INTERFACE keyword to all functions.
+        * krb5.h: moved two typedefs before inclusion of func-proto.h
+
+Mon Feb 20 16:54:51 1995 Keith Vetter (keithv@fusion.com)
+
+	* encryption.h, los-proto.h, rsa-md5.h: added windows 
+          INTERFACE keyword.
+        * Makefile.in: removed isode cruft ala Feb 10 changes but for windows
+
+Mon Feb 20 12:32:34 1995  John Gilmore  (gnu at toad.com)
+
+	* configure.in:  Flip again.  Use AC_CHECK_HEADERS, but default the
+	symbol-setting.  This is Modern Autoconf Style.
+
+	* config.h:  Create from stock/config.h and stock/config.win.
+	* Makefile.in (BUILT_HEADERS):  Remove config.h.
+	(CONF_REPLACE, CONFSRC, config.h rule):  Remove.  Config.h is
+	a static header file, ever since imake died.  Now it really is.
+	(clean):  Don't remove config.new any more.
+
+Thu Feb 16 20:12:23 1995  John Gilmore  (gnu at toad.com)
+
+	* configure.in:  Use AC_HAVE_HEADER rather than AC_HEADER_CHECK.
+	(Fixes resulting #define names to HAVE_XXX rather than HAS_XXX,
+	which is not only consistent but also matches what's in sysincl.h.)
+
+Mon Feb 6 19:42:7 1995 Keith Vetter (keithv@fusion.com)
+
+        * configure.in: added header checks for sys/param.h and sys/file.h.
+        * encryption.h: added typedef prototype for sum_func function 
+            with the windows api to make microsoft compiler happy.
+        * sysincl.h: conditionally include sys/file.h and sys/param.h since
+            windows doesn't have them.
+        * Makefile.in: 
+           - changed macros with ${...} to $(...) since nmake barfs on {}.
+           - added windows only make preamble 
+           - split the all target into unix and windows branches
+
+Fri Feb 10 14:54:26 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* asn1.h: Removed ISODE cruft -- moved included .h files into
+		asn1.h, to simplify the krb5 header file structure.
+
+	* Makefile.in (ET_HEADERS): Remove isode cruft.
+
+Mon Feb 06 17:19:04 1995 Chris Provenzano  (proven@mit.edu)
+
+	* func-proto.h (krb5_get_in_tkt()) Changed key_proc args to be the
+		following (krb5_context, const krb5_keytype, krb5_data *,
+                krb5_const_pointer, krb5_keyblock **)
+
+	* func-proto.h (krb5_get_in_tkt_*()) Removed krb5_keytype, changed
+		krb5_enctype to krb5_enctype *, changed krb5_preauthtype to
+		krb5_preauthtype *.
+
+	* func-proto.h Added new routine krb5_get_in_tkt_with_keytab().
+
+Fri Feb  3 07:57:31 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Use politically correct name of AC_CHECK_SIZEOF
+		instead of AC_SIZEOF_TYPE.
+
+        * configure.in:
+        * wordsize.h: Don't use BITS16, BITS32, etc. anymore.  Use
+                autoconf's SIZEOF_INT and SIZEOF_LONG definitions to make
+                things work.
+
+Mon Jan 30 15:43:19 1995  Chris Provenzano  (proven@mit.edu)
+
+	* func-proto.h Added krb5_keytype arg to rb5_rdreq_key_proc.
+
+	* func-proto.h (krb5_send_tgs()) Changed krb5_enctype arg to
+		krb5_enctype *, a NULL terminated array of encryption types.
+
+	* func-proto.h Added prototypes for krb5_get_for_creds(),
+		krb5_set_default_in_tkt_etypes(), and
+		krb5_get_default_in_tkt_etypes().
+	
+	* krb5.h Added fields to krb5_context to support default etypes.
+
+Fri Jan 27 00:56:12 1995  Chris Provenzano  (proven@mit.edu)
+
+	* func-proto.h (krb5_kt_read_service_key()) Added krb5_keytype arg.
+	* keytab.h (krb5_kt_get_entry()) Add krb5_keytype arg.
+
+Fri Jan 27 00:56:12 1995  Chris Provenzano  (proven@mit.edu)
+
+	* base-defs.h Typedef krb5_boolean, krb5_msgtype, krb5_kvno,
+                krb5_addrtype, krb5_keytyp, krb5_enctype, krb5_cksumtype,
+                and krb5_authdatatype as unsigned int.
+	* kdb_dbm.h krb5_dbm_db_set_lockmode(), krb5_dbm_db_set_nonblocking()
+		Fix prototypes to use krb5_boolean and not int.
+	* kdb.h krb5_db_set_lockmode(), krb5_db_set_nonblocking()
+		Fix prototypes to use krb5_boolean and not int.
+
+Wed Jan 25 19:26:57 1995  John Gilmore  (gnu at toad.com)
+
+	* crc-32.h:  Move to lib/crypto/crc32; only gets local use.
+	* rsa-md4.h:  Move to lib/crypto/md4; only gets local use.
+
+Wed Jan 25 20:01:36 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in: rewrote remaining tests to use AC_TRY_COMPILE and
+	caching. Added cross-compile case for ANSI stdio test.
+
+Wed Jan 25 17:50:35 1995  Chris Provenzano  (proven@mit.edu)
+
+	* Removed narrow.h and widen.h
+
+Wed Jan 25 17:07:17 1995  Chris Provenzano  (proven@mit.edu)
+
+	* Removed all narrow types and references to wide.h and narrow.h
+	* base-defs.h Typedef krb5_boolean, krb5_msgtype, krb5_kvno,
+		krb5_addrtype, krb5_keytyp, krb5_enctype, krb5_cksumtype,
+		and krb5_authdatatype as int.
+	* kdb.h Made keytype in krb5_encrypted_keyblock explicitly short
+		for backwards compatibility. 
+
+Sun Jan 22 18:17:06 1995  John Gilmore  (gnu@cygnus.com)
+
+	* preauth.h, rsa-md5.h:  Protect against multiple inclusion.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+	* Removed DECLARG and OLDDECLARG from base-defs.h (and any file that
+	  was using it.) The next thing to do is make all narrow types
+	  wide types and remove narrow.h and wide.h.
+
+Thu Jan 12 01:55:54 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (install): constructed headers come from the build
+	tree, not the source tree.
+
+Fri Dec 23 22:29:43 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5.h (krb5_cred): Add enc_part2 member which may point to the
+		unecrypted version, if it's available.
+
+Mon Dec 19 21:53:33 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5.h (krb5_context): Add new typdef for krb5_context.
+
+	* libos.h (krb5_os_context): Add new typedef for krb5_os_context.
+
+	* func-proto.h (krb5_init_context, krb5_free_context): Add new
+	  declarations.
+
+	* los-proto.h (krb5_init_os_context, krb5_free_os_context): Add new
+	  declarations.
+
+Wed Nov 30 16:16:54 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add support for --enable-athena and --with-krb4
+		(to set KRB5_KRB4_COMPAT).
+
+	* Makefile.in: Remove remnants of unifdef support for building
+		osconf.h and config.h, left over from the imake build system.
+
+Mon Nov 21 14:43:14 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* func-proto.h (krb5_encode_kdc_rep, krb5_encrypt_tkt_part):
+		Change to use new function prototypes.
+
+	* encryption.h (krb5_eblock_keytype, krb5_eblock_enctype): Define
+		new macros for finding the key type and encryption type of
+		an encrypion block.
+
+Fri Nov 18 17:53:38 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb.h (KRB5_KDB_SUPPORT_DESMD5): Add new attribute which defines
+		whether or not a server supports DES/MD5.
+
+Fri Nov 18 01:28:47 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (install): elide dependency so $(srcdir) works; use
+	$(INSTALL_DATA).
+	(ET_HEADERS): new variable for the names of the headers that
+	lib/krb5/error_tables builds and installs here (so that they get
+	pushed out to the installed include directory.)
+	(BUILT_HEADERS): locally built headers, for all, install, and
+	clean.
+	(clean): delete built and et headers.
+
+Fri Nov 18 01:15:00 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: use KRB5_POSIX_LOCKS, AC_EGREP_HEADER. (from
+	epeisach).
+
+Thu Nov 10 22:04:19 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* hostaddr.h (krb5_address): Add magic number field.
+
+Tue Nov  8 17:55:47 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* encryption.h (krb5_string_to_key, krb5_random_key): Change
+		internal calling signature to pass in the encryption
+		block, so that the encryption type in the keyblock
+		structure can be properly initialized.
+
+Thu Nov  3 16:38:44 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* encryption.h (krb5_keyblock): Added a field to hold an
+		encryption type in the keyblock field --- so routines have
+		a hint of which encryption type they should use.
+
+	* error_def.h: Add support for the kv5m error table.  (For magic
+		numbers.) 
+
+Mon Oct 31 14:43:07 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Move WITH_CCOPTS and WITH_KRB5ROOT to the
+		beginning of the file.  Otherwise the other tests won't
+		get the CCOPTS flags correct while doing the feature
+		tests. 
+
+Tue Oct 25 23:54:25 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* ext-proto.h (strdup): If the header files have strdup, don't try
+		to redefine it.
+
+Fri Oct 14 00:40:01 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* mit-des.h: Add declaration for krb5_des_md5_cst_entry.
+
+	* mit-des.h: Change name of the des_crc cryptosystem from
+		krb5_des_cst_entry to krb5_des_crc_cst_entry.
+
+Tue Oct  4 14:51:32 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* encryption.h: Cast various potential shorts to ints.  This is
+		not quite right either, but the whole encryption interface
+		needs to be fixed.
+
+	* keytab.h (krb5_kt_ops.resolv): Resolve's first argument is a const.
+
+	* encryption.h: Add magic number to encryption structures.
+
+Mon Oct  3 18:45:55 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb.h: Add magic number to _krb5_db_entry.  (This among other
+	things will cause a backwards incompatible change to the database
+	format.)  The previous magic number changes also force a database
+	format change; we will eventually need to completely redo how we
+	encode the database format, so that it isn't structure layout
+	dependent!
+
+	* Makefile.in: Fix install to obey ${DESTDIR}, copy conf.h and
+		osconf.h from build tree.
+
+	* Makefile.in: Fix "make install" to use $(srcdir) for header files.
+
+Thu Sep 29 15:07:30 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* func_proto.h (krb5_realm_compare): Added prototype for functin
+		donated by OpenVision.  (Compares two realms).
+
+Wed Sep 21 18:10:55 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* func_proto.h (krb5_check_transited_list): Added prototype for
+		function donated by Cybersafe.
+
+Wed Aug 17 16:33:22 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* krb5.h (krb5_enc_kdc_rep_part): Added msg_type field.  Needed
+	for the ASN.1 routines.
+
+Tue Aug 16 22:01:56 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in: change test for USE_SYS_TIME_H to consistent
+	(autoconf style) check for HAVE_SYS_TIME_H with
+	TIME_WITH_SYS_TIME, and use them everywhere.
+	* stock/osauto.h: get rid of USE_TIME_H.
+	* stock/osconf.h: get rid of USE_TIME_H, rename USE_SYS_TIME_H.
+
+Tue Aug  9 02:17:40 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* preauth.h: fix preauth function names as well (timestamp ->
+	unixtime)
+
+Mon Aug  8 22:36:24 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* proto.h: Change preauthentication names to match official names
+	which bcn and I agreed upon.
+
+Tue Aug  2 03:39:14 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* acconfig.h: add HAVE_SETVBUF
+
+	* configure.in: changes to make things saner when checking for
+	ANSI_STDIO
+
+Thu Jul 14 03:31:06 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: some cleanup to not echo cruft
+
+Tue Jun 28 19:09:21 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* error_def.h: folding in Harry's changes
+	* asn1.h: ditto
+	* configure.in: adding ISODE_DEFS, fixing ISODE_INCLUDE to dtrt
+
+Tue Jun 21 23:54:40 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* pulling SEEK_SET, etc. out to avoid redef'ing in unistd.h
+
+Tue Jun 21 00:50:46 1994  Mark W. Eichin  (eichin at mit.edu)
+
+	* sysincl.h: SEEK_SET et. al. defined in terms of L_SET et. al. if
+	they don't already exist.
+
diff --git a/mechglue/src/include/krb5/Makefile.in b/mechglue/src/include/krb5/Makefile.in
new file mode 100644
index 000000000..429b35515
--- /dev/null
+++ b/mechglue/src/include/krb5/Makefile.in
@@ -0,0 +1,74 @@
+thisconfigdir=./../..
+myfulldir=include/krb5
+mydir=include/krb5
+BUILDTOP=$(REL)..$(S)..
+KRB5RCTMPDIR= @KRB5_RCTMPDIR@
+
+##DOSBUILDTOP = ..\..
+NO_OUTPRE=1
+
+KRB5_HEADERS = adm.h adm_proto.h kdb.h kdb_dbm.h winsock.h
+
+# these are installed here for the build from lib/krb5/error_tables but 
+# also need to be in the installed tree
+ET_HEADERS = adm_err.h asn1_err.h kdb5_err.h krb5_err.h
+BUILT_HEADERS = osconf.h
+
+all-unix:: autoconf.h $(BUILT_HEADERS)
+all-windows:: autoconf.h $(BUILT_HEADERS)
+
+##DOS##autoconf.h: ..\win-mac.h
+##DOS##	$(CP) ..\win-mac.h $@
+##DOS##osconf.h: stock\osconf.h
+##DOS##	$(CP) stock\osconf.h $@
+
+# We need to comment out the Unix autoconf.h and osconf.h block below
+# if we're building for Windows.  Thus, we need to enclose them
+# between the lines "##DOS##!if 0" and "##DOS##!endif".  We enclosed
+# the entire section between the long hashed lines to make the block
+# stand out.
+
+###############################################################################
+##DOS##!if 0
+autoconf.h: autoconf.stamp
+autoconf.stamp: $(srcdir)/autoconf.h.in $(thisconfigdir)/config.status
+	(cd $(thisconfigdir) && $(SHELL) config.status $(mydir)/autoconf.h)
+	touch autoconf.stamp
+
+SYSCONFDIR = @sysconfdir@
+LOCALSTATEDIR = @localstatedir@
+BINDIR = @bindir@
+SBINDIR = @sbindir@
+LIBDIR  = @libdir@
+
+PROCESS_REPLACE = -e "s+@KRB5RCTMPDIR+$(KRB5RCTMPDIR)+" \
+		  -e "s+@PREFIX+$(INSTALL_PREFIX)+" \
+		  -e "s+@EXEC_PREFIX+$(INSTALL_EXEC_PREFIX)+" \
+		  -e "s+@BINDIR+$(BINDIR)+" \
+		  -e "s+@LIBDIR+$(LIBDIR)+" \
+		  -e "s+@SBINDIR+$(SBINDIR)+" \
+		  -e "s+@MODULEDIR+$(KRB5_DB_MODULE_DIR)+" \
+	-e 's+@LOCALSTATEDIR+$(LOCALSTATEDIR)+' \
+	-e 's+@SYSCONFDIR+$(SYSCONFDIR)+' 
+
+OSCONFSRC = $(srcdir)/stock/osconf.h
+
+osconf.h: $(OSCONFSRC) Makefile
+	cat $(OSCONFSRC) | sed $(PROCESS_REPLACE) > osconf.new
+	@set -x ; if cmp -s osconf.new osconf.h ; then : osconf.h is current ; \
+	else ($(RM) osconf.h ; $(CP) osconf.new osconf.h) fi
+	$(RM) osconf.new
+##DOS##!endif
+###############################################################################
+
+depend::
+
+install::
+
+clean::
+	$(RM) osconf.new $(BUILT_HEADERS)
+
+clean-unix::
+	$(RM) $(ET_HEADERS) autoconf.stamp
+clean-windows::
+	$(RM) osconf.h autoconf.h autoconf.stamp
diff --git a/mechglue/src/include/krb5/adm.h b/mechglue/src/include/krb5/adm.h
new file mode 100644
index 000000000..86798a830
--- /dev/null
+++ b/mechglue/src/include/krb5/adm.h
@@ -0,0 +1,217 @@
+/*
+ * include/krb5/adm.h
+ *
+ * Copyright 1995,2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+#ifndef	KRB5_ADM_H__
+#define	KRB5_ADM_H__
+
+/*
+ * Kerberos V5 Change Password service name
+ */
+#define	KRB5_ADM_SERVICE_NAME	"kpasswd"
+#define	KRB5_ADM_DEFAULT_PORT	464
+
+#define KRB5_ADM_SERVICE_INSTANCE "changepw"
+
+/*
+ * Maximum password length.
+ */
+#define	KRB5_ADM_MAX_PASSWORD_LEN	512
+
+/*
+ * Protocol command strings.
+ */
+#define	KRB5_ADM_QUIT_CMD	"QUIT"
+#define	KRB5_ADM_CHECKPW_CMD	"CHECKPW"
+#define	KRB5_ADM_CHANGEPW_CMD	"CHANGEPW"
+#define	KRB5_ADM_MOTD_CMD	"MOTD"
+#define	KRB5_ADM_MIME_CMD	"MIME"
+#define	KRB5_ADM_LANGUAGE_CMD	"LANGUAGE"
+
+#define	KRB5_ADM_ADD_PRINC_CMD	"ADD-PRINCIPAL"
+#define	KRB5_ADM_DEL_PRINC_CMD	"DELETE-PRINCIPAL"
+#define	KRB5_ADM_REN_PRINC_CMD	"RENAME-PRINCIPAL"
+#define	KRB5_ADM_MOD_PRINC_CMD	"MODIFY-PRINCIPAL"
+#define	KRB5_ADM_INQ_PRINC_CMD	"INQUIRE-PRINCIPAL"
+#define	KRB5_ADM_EXT_KEY_CMD	"EXTRACT-KEY"
+
+/*
+ * Protocol command strings for the current version of the admin
+ * server.  (Chris had removed them in the version he was working
+ * with.)
+ *
+ * XXX I'm adding them back so the tree works.  We need to take care
+ * of this eventually.
+ */
+#define       KRB5_ADM_CHG_OPW_CMD    "OTHER-CHANGEPW"
+#define       KRB5_ADM_CHG_ORPW_CMD   "OTHER-RANDOM-CHANGEPW"
+#define       KRB5_ADM_ADD_KEY_CMD    "ADD-KEY"
+#define       KRB5_ADM_DEL_KEY_CMD    "DELETE-KEY"
+
+/*
+ * Reply status values.
+ */
+#define	KRB5_ADM_SUCCESS		0
+#define	KRB5_ADM_CMD_UNKNOWN		1
+#define	KRB5_ADM_PW_UNACCEPT		2
+#define	KRB5_ADM_BAD_PW			3
+#define	KRB5_ADM_NOT_IN_TKT		4
+#define	KRB5_ADM_CANT_CHANGE		5
+#define	KRB5_ADM_LANG_NOT_SUPPORTED	6
+
+#define	KRB5_ADM_P_ALREADY_EXISTS	64
+#define	KRB5_ADM_P_DOES_NOT_EXIST	65
+#define	KRB5_ADM_NOT_AUTHORIZED		66
+#define	KRB5_ADM_BAD_OPTION		67
+#define	KRB5_ADM_VALUE_REQUIRED		68
+#define	KRB5_ADM_SYSTEM_ERROR		69
+#define	KRB5_ADM_KEY_DOES_NOT_EXIST	70
+#define	KRB5_ADM_KEY_ALREADY_EXISTS	71
+
+/*
+ * Principal flag keywords.
+ */
+/* Settable only */
+#define	KRB5_ADM_KW_PASSWORD		"PASSWORD"
+#define	KRB5_ADM_KW_APASSWORD		"APASSWORD"
+#define	KRB5_ADM_KW_RANDOMKEY		"RANDOMKEY"
+#define	KRB5_ADM_KW_ARANDOMKEY		"ARANDOMKEY"
+#define	KRB5_ADM_KW_SETFLAGS		"SETFLAGS"
+#define	KRB5_ADM_KW_UNSETFLAGS		"UNSETFLAGS"
+/* Settable and retrievable */
+#define	KRB5_ADM_KW_MAXLIFE		"MAXLIFE"
+#define	KRB5_ADM_KW_MAXRENEWLIFE	"MAXRENEWLIFE"
+#define	KRB5_ADM_KW_EXPIRATION		"EXPIRATION"
+#define	KRB5_ADM_KW_PWEXPIRATION	"PWEXPIRATION"
+#define	KRB5_ADM_KW_FLAGS		"FLAGS"
+#define	KRB5_ADM_KW_AUXDATA		"AUXDATA"
+#define	KRB5_ADM_KW_EXTRADATA		"EXTRADATA"
+/* Retrievable only */
+#define	KRB5_ADM_KW_LASTPWCHANGE	"LASTPWCHANGE"
+#define	KRB5_ADM_KW_LASTSUCCESS		"LASTSUCCESS"
+#define	KRB5_ADM_KW_LASTFAILED		"LASTFAILED"
+#define	KRB5_ADM_KW_FAILCOUNT		"FAILCOUNT"
+#define	KRB5_ADM_KW_KEYDATA		"KEYDATA"
+
+/* Valid mask */
+#define	KRB5_ADM_M_PASSWORD		0x00000001
+#define	KRB5_ADM_M_MAXLIFE		0x00000002
+#define	KRB5_ADM_M_MAXRENEWLIFE		0x00000004
+#define	KRB5_ADM_M_EXPIRATION		0x00000008
+#define	KRB5_ADM_M_PWEXPIRATION		0x00000010
+#define	KRB5_ADM_M_RANDOMKEY		0x00000020
+#define	KRB5_ADM_M_FLAGS		0x00000040
+#define	KRB5_ADM_M_LASTPWCHANGE		0x00000080
+#define	KRB5_ADM_M_LASTSUCCESS		0x00000100
+#define	KRB5_ADM_M_LASTFAILED		0x00000200
+#define	KRB5_ADM_M_FAILCOUNT		0x00000400
+#define	KRB5_ADM_M_AUXDATA		0x00000800
+#define	KRB5_ADM_M_KEYDATA		0x00001000
+#define	KRB5_ADM_M_APASSWORD		0x00002000
+#define	KRB5_ADM_M_ARANDOMKEY		0x00004000
+#define	KRB5_ADM_M_UNUSED_15		0x00008000
+#define	KRB5_ADM_M_UNUSED_16		0x00010000
+#define KRB5_ADM_M_UNUSED_17		0x00020000
+#define	KRB5_ADM_M_UNUSED_18		0x00040000
+#define	KRB5_ADM_M_UNUSED_19		0x00080000
+#define	KRB5_ADM_M_UNUSED_20		0x00100000
+#define	KRB5_ADM_M_UNUSED_21		0x00200000
+#define	KRB5_ADM_M_UNUSED_22		0x00400000
+#define	KRB5_ADM_M_UNUSED_23		0x00800000
+#define	KRB5_ADM_M_UNUSED_24		0x01000000
+#define	KRB5_ADM_M_UNUSED_25		0x02000000
+#define	KRB5_ADM_M_UNUSED_26		0x04000000
+#define	KRB5_ADM_M_UNUSED_27		0x08000000
+#define	KRB5_ADM_M_UNUSED_28		0x10000000
+#define	KRB5_ADM_M_UNUSED_29		0x20000000
+#define	KRB5_ADM_M_GET			0x40000000
+#define	KRB5_ADM_M_SET			0x80000000
+
+#define KRB5_ADM_M_EXTRADATA		0x00000000 /* Hack to get */
+						   /* libkadm to compile */
+
+#define	KRB5_ADM_M_SET_VALID		(KRB5_ADM_M_SET		+ \
+					 KRB5_ADM_M_PASSWORD	+ \
+					 KRB5_ADM_M_APASSWORD	+ \
+					 KRB5_ADM_M_MAXLIFE	+ \
+					 KRB5_ADM_M_MAXRENEWLIFE+ \
+					 KRB5_ADM_M_EXPIRATION	+ \
+					 KRB5_ADM_M_PWEXPIRATION+ \
+					 KRB5_ADM_M_RANDOMKEY	+ \
+					 KRB5_ADM_M_ARANDOMKEY	+ \
+					 KRB5_ADM_M_FLAGS	+ \
+					 KRB5_ADM_M_AUXDATA)
+#define	KRB5_ADM_M_GET_VALID		(KRB5_ADM_M_GET		+ \
+					 KRB5_ADM_M_MAXLIFE	+ \
+					 KRB5_ADM_M_MAXRENEWLIFE+ \
+					 KRB5_ADM_M_EXPIRATION	+ \
+					 KRB5_ADM_M_PWEXPIRATION+ \
+					 KRB5_ADM_M_FLAGS	+ \
+					 KRB5_ADM_M_LASTPWCHANGE+ \
+					 KRB5_ADM_M_LASTSUCCESS	+ \
+					 KRB5_ADM_M_LASTFAILED	+ \
+					 KRB5_ADM_M_FAILCOUNT	+ \
+					 KRB5_ADM_M_AUXDATA	+ \
+					 KRB5_ADM_M_KEYDATA)
+
+/*
+ * Keytab reply components.
+ */
+#define	KRB5_ADM_KT_PRINCIPAL	0
+#define	KRB5_ADM_KT_TIMESTAMP	1
+#define	KRB5_ADM_KT_VNO		2
+#define	KRB5_ADM_KT_KEY_ENCTYPE	3
+#define	KRB5_ADM_KT_KEY_KEY	4
+#define	KRB5_ADM_KT_NCOMPS	5
+
+/*
+ * Data structure returned by krb5_read_realm_params()
+ */
+typedef struct __krb5_realm_params {
+    char *		realm_profile;
+    char *		realm_dbname;
+    char *		realm_mkey_name;
+    char *		realm_stash_file;
+    char *		realm_kdc_ports;
+    char *		realm_kdc_tcp_ports;
+    char *		realm_acl_file;
+    krb5_int32		realm_kadmind_port;
+    krb5_enctype	realm_enctype;
+    krb5_deltat		realm_max_life;
+    krb5_deltat		realm_max_rlife;
+    krb5_timestamp	realm_expiration;
+    krb5_flags		realm_flags;
+    krb5_key_salt_tuple	*realm_keysalts;
+    unsigned int	realm_reject_bad_transit:1;
+    unsigned int	realm_kadmind_port_valid:1;
+    unsigned int	realm_enctype_valid:1;
+    unsigned int	realm_max_life_valid:1;
+    unsigned int	realm_max_rlife_valid:1;
+    unsigned int	realm_expiration_valid:1;
+    unsigned int	realm_flags_valid:1;
+    unsigned int	realm_reject_bad_transit_valid:1;
+    krb5_int32		realm_num_keysalts;
+} krb5_realm_params;
+#endif	/* KRB5_ADM_H__ */
diff --git a/mechglue/src/include/krb5/adm_defs.h b/mechglue/src/include/krb5/adm_defs.h
new file mode 100644
index 000000000..b2b747446
--- /dev/null
+++ b/mechglue/src/include/krb5/adm_defs.h
@@ -0,0 +1,209 @@
+/*
+ * include/krb5/adm_defs.h
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * <<< Description >>>
+ */
+
+
+#ifndef __ADM_DEFINES__
+#define __ADM_DEFINES__
+
+#define ADM5_VERSTR		"ADM5VER1"
+#define ADM5_VERSIZE		strlen(ADM5_VERSTR)
+/* This used to be kerberos_master */
+#define ADM5_PORTNAME		"kerberos-adm"
+#define ADM5_DEFAULT_PORT	752
+#define ADM5_CPW_VERSION	"V5CPWS01"
+#define ADM5_ADM_VERSION	"V5ADMS01"
+#define CPWNAME			"kadmin"
+#define ADMINSTANCE		"admin"
+
+#define ADM_CPW_VERSION         "V5CPWS01"
+#define ADM_MAX_PW_ITERATIONS	5
+#define ADM_MAX_PW_CHOICES	5
+
+#ifdef MACH_PASS
+#define ADM_MAX_PW_LENGTH       8
+#define ADM_MAX_PHRASE_LENGTH	101
+#else
+#define ADM_MAX_PW_LENGTH       255
+#endif
+
+#define CPW_SNAME               ADM5_PORTNAME
+
+#define MAXCPWBUFSIZE 4096
+
+#ifdef unicos61
+#define SIZEOF_INADDR  SIZEOF_in_addr
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+
+/* Server */
+#define KADMIND		0x01
+
+/* Applications */
+#define KPASSWD		0x01
+#define KSRVUTIL	0x02
+#define KADMIN		0x03
+
+/* Operations */
+#define ADDOPER		0x01    /* Add Principal */
+#define CHGOPER		0x02    /* Change Password */
+#define ADROPER         0x03    /* Add principal with random password */
+#define CHROPER         0x04    /* Change to random password */
+#define DELOPER		0x05    /* Delete Principal */
+#define MODOPER		0x06    /* Modify Principal attributes */
+#define INQOPER		0x07    /* Display Principal info */
+#define AD4OPER         0x08    /* Add Principal using v4 string-to-key */
+#define CH4OPER         0x09    /* Change password using v4 string-to-key */
+#define COMPLETE	0x0f
+
+/* Extra Message Types */
+#define SENDDATA1	0x00
+#define SENDDATA2	0x01
+#define SENDDATA3	0x02
+
+/* Unknowns */
+#define KUNKNOWNAPPL	0xff
+#define KUNKNOWNOPER	0xff
+#define KUNKNOWNERR	0xff
+
+typedef struct {
+    char appl_code;
+    char oper_code;
+    char retn_code;
+    char *message;
+} kadmin_requests;
+
+#if 0
+static char *oper_type[] = {
+	"complete",					/* 0 */
+	"addition",					/* 1 */
+	"deletion",					/* 2 */
+	"change",					/* 3 */
+	"modification",					/* 4 */
+	"inquiry"					/* 5 */
+};
+#endif
+
+#define SKYCHANGED	0x00
+#define NSKYRCVD	0x01
+
+
+#if 0
+static char *ksrvutil_message[] = {
+	"Service Key Changed",				/* 0 */
+	"New Key and Version Received"			/* 1 */
+};
+#endif
+
+#define KADMGOOD	0x00
+#define KADMSAG		0x01
+
+#if 0
+static char *kadmind_general_response[] = {
+	"Success",					/* 0 */
+	"Service Access Granted"			/* 1 */
+};
+#endif
+
+
+#define KPASSGOOD	0x00
+#define KPASSBAD	0x01
+
+#if 0
+static char *kadmind_kpasswd_response[] = {
+	"Password Changed",				/* 0 */
+	"Password NOT Changed!"				/* 1 */
+};
+#endif
+
+#define KSRVGOOD	0x00
+#define KSRVBAD		0x01
+#define KSRVCATASTROPHE	0x02
+
+#if 0
+static char *kadmind_ksrvutil_response[] = {
+	"Service Password Change Complete",		/* 0 */
+	"One or More Service Password Change(s) Failed!",	/* 1 */
+	"Database Update Failure - Possible Catastrophe!!"	/* 2 */
+};
+#endif
+
+#define KADMGOOD	0x00
+#define KADMBAD		0x01
+
+#if 0
+static char *kadmind_kadmin_response[] = {
+	"Administrative Service Completed",		/* 0 */
+	"Principal Unknown!",				/* 1 */
+	"Principal Already Exists!",			/* 2 */
+	"Allocation Failure!",				/* 3 */
+	"Password Failure!",				/* 4 */
+	"Protocol Failure!",				/* 5 */
+	"Security Failure!",				/* 6 */
+	"Admin Client Not in ACL List!",			/* 7 */
+	"Database Update Failure - Possible Catastrophe!!"	/* 8 */
+};
+#endif
+
+#define KMODVNO		0x00
+#define KMODATTR	0x01
+
+#ifdef SANDIA
+#define KMODFCNT	0x02
+#endif
+
+#define ATTRPOST	0x00
+#define ATTRNOPOST	0x01
+#define ATTRFOR		0x02
+#define ATTRNOFOR	0x03
+#define ATTRTGT		0x04
+#define ATTRNOTGT	0x05
+#define ATTRREN		0x06
+#define ATTRNOREN	0x07
+#define ATTRPROXY	0x08
+#define ATTRNOPROXY	0x09
+#define ATTRDSKEY	0x0a
+#define ATTRNODSKEY	0x0b
+#define ATTRLOCK	0x0c
+#define ATTRUNLOCK	0x0d
+
+#ifdef SANDIA
+#define ATTRPRE		0x0e
+#define ATTRNOPRE	0x0f
+#define ATTRPWOK	0x10
+#define ATTRPWCHG	0x11
+#define ATTRSID		0x12
+#define ATTRNOSID	0x13
+#endif
+
+#define ATTRNOSVR       0x14
+#define ATTRSVR         0x15
+
+#define BADATTR		0x3f
+
+#endif /* __ADM_DEFINES__ */
diff --git a/mechglue/src/include/krb5/adm_proto.h b/mechglue/src/include/krb5/adm_proto.h
new file mode 100644
index 000000000..65b116bc4
--- /dev/null
+++ b/mechglue/src/include/krb5/adm_proto.h
@@ -0,0 +1,132 @@
+/*
+ * include/krb5/adm_proto.h
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+#ifndef	KRB5_ADM_PROTO_H__
+#define	KRB5_ADM_PROTO_H__
+
+/*
+ * This is ugly, but avoids having to include k5-int or kdb.h for this.
+ */
+#ifndef	KRB5_KDB5__
+struct _krb5_db_entry;
+typedef struct _krb5_db_entry krb5_db_entry;
+#endif	/* KRB5_KDB5__ */
+
+/* Ditto for adm.h */
+
+/*
+ * XXXX krb5_realm params is defined in two header files!!!!
+ * This really needs to be fixed!!!
+ */
+#if !defined(KRB5_ADM_H__) && !defined(__KADM5_ADMIN_H__)
+struct ___krb5_realm_params;
+typedef struct ___krb5_realm_params krb5_realm_params;
+#endif	/* KRB5_ADM_H__ */
+
+#ifndef KRB5_KDB5__
+struct ___krb5_key_salt_tuple;
+typedef struct ___krb5_key_salt_tuple krb5_key_salt_tuple;
+#endif	/* KRB5_KDB5__ */
+
+/*
+ * Function prototypes.
+ */
+
+/* logger.c */
+krb5_error_code krb5_klog_init
+	(krb5_context,
+	 char *,
+	 char *,
+	 krb5_boolean);
+void krb5_klog_close (krb5_context);
+int krb5_klog_syslog (int, const char *, ...);
+void krb5_klog_reopen (krb5_context);
+
+/* alt_prof.c */
+krb5_error_code krb5_aprof_init
+	(char *, char *, krb5_pointer *);
+krb5_error_code krb5_aprof_getvals
+	(krb5_pointer, const char **, char ***);
+krb5_error_code krb5_aprof_get_deltat
+	(krb5_pointer,
+	 const char **,
+	 krb5_boolean,
+	 krb5_deltat *);
+krb5_error_code krb5_aprof_get_string
+	(krb5_pointer, const char **, krb5_boolean, char **);
+krb5_error_code krb5_aprof_get_int32
+	(krb5_pointer,
+	 const char **,
+	 krb5_boolean,
+	 krb5_int32 *);
+krb5_error_code krb5_aprof_finish (krb5_pointer);
+
+krb5_error_code krb5_read_realm_params (krb5_context,
+					char *,
+					char *,
+					char *,
+					krb5_realm_params **);
+krb5_error_code krb5_free_realm_params (krb5_context,
+					krb5_realm_params *);
+
+/* str_conv.c */
+krb5_error_code
+krb5_string_to_flags (char *,
+		      const char *,
+		      const char *,
+		      krb5_flags *);
+krb5_error_code
+krb5_flags_to_string (krb5_flags,
+		      const char *,
+		      char *,
+		      size_t);
+krb5_error_code
+krb5_input_flag_to_string (int, 
+			   char *,
+			   size_t);
+
+/* keysalt.c */
+krb5_boolean
+krb5_keysalt_is_present (krb5_key_salt_tuple *,
+			 krb5_int32,
+			 krb5_enctype,
+			 krb5_int32);
+krb5_error_code
+krb5_keysalt_iterate (krb5_key_salt_tuple *,
+		      krb5_int32,
+		      krb5_boolean,
+		      krb5_error_code (*) (krb5_key_salt_tuple *,
+					   krb5_pointer),
+		      krb5_pointer);
+				     
+krb5_error_code
+krb5_string_to_keysalts (char *,
+			 const char *,
+			 const char *,
+			 krb5_boolean,
+			 krb5_key_salt_tuple **,
+			 krb5_int32 *);
+#endif	/* KRB5_ADM_PROTO_H__ */
diff --git a/mechglue/src/include/krb5/copyright.h b/mechglue/src/include/krb5/copyright.h
new file mode 100644
index 000000000..b1740ce3c
--- /dev/null
+++ b/mechglue/src/include/krb5/copyright.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1989-1994 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
diff --git a/mechglue/src/include/krb5/kdb.h b/mechglue/src/include/krb5/kdb.h
new file mode 100644
index 000000000..c93ac96c4
--- /dev/null
+++ b/mechglue/src/include/krb5/kdb.h
@@ -0,0 +1,498 @@
+/*
+ * include/krb5/kdb.h
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * KDC Database interface definitions.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef KRB5_KDB5__
+#define KRB5_KDB5__
+
+/* Salt types */
+#define KRB5_KDB_SALTTYPE_NORMAL	0
+#define KRB5_KDB_SALTTYPE_V4		1
+#define KRB5_KDB_SALTTYPE_NOREALM	2
+#define KRB5_KDB_SALTTYPE_ONLYREALM	3
+#define KRB5_KDB_SALTTYPE_SPECIAL	4
+#define KRB5_KDB_SALTTYPE_AFS3		5
+
+/* Attributes */
+#define	KRB5_KDB_DISALLOW_POSTDATED	0x00000001
+#define	KRB5_KDB_DISALLOW_FORWARDABLE	0x00000002
+#define	KRB5_KDB_DISALLOW_TGT_BASED	0x00000004
+#define	KRB5_KDB_DISALLOW_RENEWABLE	0x00000008
+#define	KRB5_KDB_DISALLOW_PROXIABLE	0x00000010
+#define	KRB5_KDB_DISALLOW_DUP_SKEY	0x00000020
+#define	KRB5_KDB_DISALLOW_ALL_TIX	0x00000040
+#define	KRB5_KDB_REQUIRES_PRE_AUTH	0x00000080
+#define KRB5_KDB_REQUIRES_HW_AUTH	0x00000100
+#define	KRB5_KDB_REQUIRES_PWCHANGE	0x00000200
+#define KRB5_KDB_DISALLOW_SVR		0x00001000
+#define KRB5_KDB_PWCHANGE_SERVICE	0x00002000
+#define KRB5_KDB_SUPPORT_DESMD5         0x00004000
+#define	KRB5_KDB_NEW_PRINC		0x00008000
+
+/* Creation flags */
+#define KRB5_KDB_CREATE_BTREE		0x00000001
+#define KRB5_KDB_CREATE_HASH		0x00000002
+
+#if !defined(_WIN32)
+
+/*
+ * Note --- these structures cannot be modified without changing the
+ * database version number in libkdb.a, but should be expandable by
+ * adding new tl_data types.
+ */
+typedef struct _krb5_tl_data {
+    struct _krb5_tl_data* tl_data_next;		/* NOT saved */
+    krb5_int16 		  tl_data_type;		
+    krb5_ui_2		  tl_data_length;	
+    krb5_octet 	        * tl_data_contents;	
+} krb5_tl_data;
+
+/* 
+ * If this ever changes up the version number and make the arrays be as
+ * big as necessary.
+ *
+ * Currently the first type is the enctype and the second is the salt type.
+ */
+typedef struct _krb5_key_data {
+    krb5_int16 		  key_data_ver;		/* Version */
+    krb5_int16		  key_data_kvno;	/* Key Version */
+    krb5_int16		  key_data_type[2];	/* Array of types */
+    krb5_ui_2		  key_data_length[2];	/* Array of lengths */
+    krb5_octet 	        * key_data_contents[2];	/* Array of pointers */
+} krb5_key_data;
+
+#define KRB5_KDB_V1_KEY_DATA_ARRAY	2	/* # of array elements */
+
+typedef struct _krb5_keysalt {
+    krb5_int16		  type;	
+    krb5_data		  data;			/* Length, data */
+} krb5_keysalt;
+
+typedef struct _krb5_db_entry_new {
+    krb5_magic 		  magic;		/* NOT saved */
+    krb5_ui_2		  len;			
+    krb5_flags 		  attributes;
+    krb5_deltat		  max_life;
+    krb5_deltat		  max_renewable_life;
+    krb5_timestamp 	  expiration;	  	/* When the client expires */
+    krb5_timestamp 	  pw_expiration;  	/* When its passwd expires */
+    krb5_timestamp 	  last_success;		/* Last successful passwd */
+    krb5_timestamp 	  last_failed;		/* Last failed passwd attempt */
+    krb5_kvno 	 	  fail_auth_count; 	/* # of failed passwd attempt */
+    krb5_int16 		  n_tl_data;
+    krb5_int16 		  n_key_data;
+    krb5_ui_2		  e_length;		/* Length of extra data */
+    krb5_octet		* e_data;		/* Extra data to be saved */
+
+    krb5_principal 	  princ;		/* Length, data */	
+    krb5_tl_data	* tl_data;		/* Linked list */
+    krb5_key_data       * key_data;		/* Array */
+} krb5_db_entry;
+
+typedef struct _osa_policy_ent_t {
+    int               version;
+    char      *name;
+    krb5_ui_4       pw_min_life;
+    krb5_ui_4       pw_max_life;
+    krb5_ui_4       pw_min_length;
+    krb5_ui_4       pw_min_classes;
+    krb5_ui_4       pw_history_num;
+    krb5_ui_4       policy_refcnt;
+} osa_policy_ent_rec, *osa_policy_ent_t;
+
+typedef       void    (*osa_adb_iter_policy_func) (void *, osa_policy_ent_t);
+
+typedef struct __krb5_key_salt_tuple {
+    krb5_enctype	ks_enctype;
+    krb5_int32		ks_salttype;
+} krb5_key_salt_tuple;
+
+
+#define	KRB5_KDB_MAGIC_NUMBER		0xdbdbdbdb
+#define KRB5_KDB_V1_BASE_LENGTH		38
+  
+#define KRB5_TL_LAST_PWD_CHANGE		0x0001
+#define KRB5_TL_MOD_PRINC		0x0002
+#define KRB5_TL_KADM_DATA		0x0003
+#define KRB5_TL_KADM5_E_DATA		0x0004
+#define KRB5_TL_RB1_CHALLENGE		0x0005
+#ifdef SECURID
+#define KRB5_TL_SECURID_STATE           0x0006
+#define KRB5_TL_DB_ARGS                 0x7fff
+#endif /* SECURID */
+    
+/*
+ * Determines the number of failed KDC requests before DISALLOW_ALL_TIX is set
+ * on the principal.
+ */
+#define KRB5_MAX_FAIL_COUNT		5
+
+/* XXX depends on knowledge of krb5_parse_name() formats */
+#define KRB5_KDB_M_NAME		"K/M"	/* Kerberos/Master */
+
+/* prompts used by default when reading the KDC password from the keyboard. */
+#define KRB5_KDC_MKEY_1	"Enter KDC database master key"
+#define KRB5_KDC_MKEY_2	"Re-enter KDC database master key to verify"
+
+
+extern char *krb5_mkey_pwd_prompt1;
+extern char *krb5_mkey_pwd_prompt2;
+
+/*
+ * These macros specify the encoding of data within the database.
+ *
+ * Data encoding is little-endian.
+ */
+#define	krb5_kdb_decode_int16(cp, i16)	\
+	*((krb5_int16 *) &(i16)) = (((krb5_int16) ((unsigned char) (cp)[0]))| \
+			      ((krb5_int16) ((unsigned char) (cp)[1]) << 8))
+#define	krb5_kdb_decode_int32(cp, i32)	\
+	*((krb5_int32 *) &(i32)) = (((krb5_int32) ((unsigned char) (cp)[0]))| \
+			      ((krb5_int32) ((unsigned char) (cp)[1]) << 8) | \
+			      ((krb5_int32) ((unsigned char) (cp)[2]) << 16)| \
+			      ((krb5_int32) ((unsigned char) (cp)[3]) << 24))
+#define	krb5_kdb_encode_int16(i16, cp)	\
+	{							\
+	    (cp)[0] = (unsigned char) ((i16) & 0xff);		\
+	    (cp)[1] = (unsigned char) (((i16) >> 8) & 0xff);	\
+	}
+#define	krb5_kdb_encode_int32(i32, cp)	\
+	{							\
+	    (cp)[0] = (unsigned char) ((i32) & 0xff);		\
+	    (cp)[1] = (unsigned char) (((i32) >> 8) & 0xff);	\
+	    (cp)[2] = (unsigned char) (((i32) >> 16) & 0xff);	\
+	    (cp)[3] = (unsigned char) (((i32) >> 24) & 0xff);	\
+	}
+
+#define KRB5_KDB_OPEN_RW                0
+#define KRB5_KDB_OPEN_RO                1
+
+#define KRB5_KDB_OPT_SET_DB_NAME        0
+#define KRB5_KDB_OPT_SET_LOCK_MODE      1
+
+#define KRB5_DB_LOCKMODE_SHARED       0x0001
+#define KRB5_DB_LOCKMODE_EXCLUSIVE    0x0002
+#define KRB5_DB_LOCKMODE_DONTBLOCK    0x0004
+#define KRB5_DB_LOCKMODE_PERMANENT    0x0008
+
+/* libkdb.spec */
+krb5_error_code krb5_db_open( krb5_context kcontext, char **db_args, int mode );
+krb5_error_code krb5_db_init  ( krb5_context kcontext );
+krb5_error_code krb5_db_create ( krb5_context kcontext, char **db_args );
+krb5_error_code krb5_db_inited  ( krb5_context kcontext );
+krb5_error_code kdb5_db_create ( krb5_context kcontext, char **db_args );
+krb5_error_code krb5_db_fini ( krb5_context kcontext );
+const char * krb5_db_errcode2string ( krb5_context kcontext, long err_code );
+krb5_error_code krb5_db_destroy ( krb5_context kcontext, char **db_args );
+krb5_error_code krb5_db_get_age ( krb5_context kcontext, char *db_name, time_t *t );
+krb5_error_code krb5_db_set_option ( krb5_context kcontext, int option, void *value );
+krb5_error_code krb5_db_lock ( krb5_context kcontext, int lock_mode );
+krb5_error_code krb5_db_unlock ( krb5_context kcontext );
+krb5_error_code krb5_db_get_principal ( krb5_context kcontext,
+					krb5_const_principal search_for,
+					krb5_db_entry *entries,
+					int *nentries,
+					krb5_boolean *more );
+krb5_error_code krb5_db_free_principal ( krb5_context kcontext,
+					 krb5_db_entry *entry,
+					 int count );
+krb5_error_code krb5_db_put_principal ( krb5_context kcontext,
+					krb5_db_entry *entries,
+					int *nentries);
+krb5_error_code krb5_db_delete_principal ( krb5_context kcontext,
+					   krb5_principal search_for,
+					   int *nentries );
+krb5_error_code krb5_db_iterate ( krb5_context kcontext,
+				  char *match_entry,
+				  int (*func) (krb5_pointer, krb5_db_entry *),
+				  krb5_pointer func_arg );
+krb5_error_code krb5_supported_realms ( krb5_context kcontext,
+					char **realms );
+krb5_error_code krb5_free_supported_realms ( krb5_context kcontext,
+					     char **realms );
+krb5_error_code krb5_db_set_master_key_ext ( krb5_context kcontext,
+					     char *pwd,
+					     krb5_keyblock *key );
+krb5_error_code krb5_db_set_mkey ( krb5_context context, 
+				   krb5_keyblock *key);
+krb5_error_code krb5_db_get_mkey ( krb5_context kcontext,
+				   krb5_keyblock **key );
+krb5_error_code krb5_db_free_master_key ( krb5_context kcontext,
+					  krb5_keyblock *key );
+krb5_error_code krb5_db_store_master_key  ( krb5_context kcontext, 
+					    char *db_arg, 
+					    krb5_principal mname,
+					    krb5_keyblock *key,
+					    char *master_pwd);
+krb5_error_code krb5_db_fetch_mkey  ( krb5_context   context,
+				      krb5_principal mname,
+				      krb5_enctype   etype,
+				      krb5_boolean   fromkeyboard,
+				      krb5_boolean   twice,
+				      char          *db_args,
+				      krb5_data     *salt,
+				      krb5_keyblock *key);
+krb5_error_code krb5_db_verify_master_key ( krb5_context kcontext,
+					    krb5_principal mprinc,
+					    krb5_keyblock *mkey );
+krb5_error_code
+krb5_dbe_find_enctype( krb5_context	kcontext,
+		       krb5_db_entry	*dbentp,
+		       krb5_int32		ktype,
+		       krb5_int32		stype,
+		       krb5_int32		kvno,
+		       krb5_key_data	**kdatap);
+
+
+krb5_error_code krb5_dbe_search_enctype ( krb5_context kcontext, 
+					  krb5_db_entry *dbentp, 
+					  krb5_int32 *start, 
+					  krb5_int32 ktype, 
+					  krb5_int32 stype, 
+					  krb5_int32 kvno, 
+					  krb5_key_data **kdatap);
+
+krb5_error_code
+krb5_db_setup_mkey_name ( krb5_context context,
+			  const char *keyname,
+			  const char *realm,
+			  char **fullname,
+			  krb5_principal *principal);
+
+krb5_error_code
+krb5_dbekd_decrypt_key_data( krb5_context 	  context,
+			     const krb5_keyblock	* mkey,
+			     const krb5_key_data	* key_data,
+			     krb5_keyblock 	* dbkey,
+			     krb5_keysalt 	* keysalt);
+
+krb5_error_code
+krb5_dbekd_encrypt_key_data( krb5_context 		  context,
+			     const krb5_keyblock	* mkey,
+			     const krb5_keyblock 	* dbkey,
+			     const krb5_keysalt		* keysalt,
+			     int			  keyver,
+			     krb5_key_data	        * key_data);
+
+krb5_error_code
+krb5_dbe_lookup_mod_princ_data( krb5_context          context,
+				krb5_db_entry       * entry,
+				krb5_timestamp      * mod_time,
+				krb5_principal      * mod_princ);
+ 
+
+krb5_error_code
+krb5_dbe_update_last_pwd_change( krb5_context          context,
+				 krb5_db_entry       * entry,
+				 krb5_timestamp	  stamp);
+
+krb5_error_code
+krb5_dbe_lookup_tl_data( krb5_context          context,
+			 krb5_db_entry       * entry,
+			 krb5_tl_data        * ret_tl_data);
+
+krb5_error_code
+krb5_dbe_create_key_data( krb5_context          context,
+			  krb5_db_entry       * entry);
+
+
+krb5_error_code
+krb5_dbe_update_mod_princ_data( krb5_context          context,
+				krb5_db_entry       * entry,
+				krb5_timestamp        mod_date,
+				krb5_const_principal  mod_princ);
+
+krb5_error_code
+krb5_dbe_update_last_pwd_change( krb5_context          context,
+				 krb5_db_entry       * entry,
+				 krb5_timestamp	  stamp);
+
+void *krb5_db_alloc( krb5_context kcontext,
+		     void *ptr,
+		     size_t size );
+
+void krb5_db_free( krb5_context kcontext,
+		   void *ptr);
+
+
+krb5_error_code
+krb5_dbe_lookup_last_pwd_change( krb5_context          context,
+				 krb5_db_entry       * entry,
+				 krb5_timestamp      * stamp);
+
+krb5_error_code
+krb5_dbe_update_tl_data( krb5_context          context,
+			 krb5_db_entry       * entry,
+			 krb5_tl_data        * new_tl_data);
+
+krb5_error_code
+krb5_dbe_cpw( krb5_context	  kcontext,
+	      krb5_keyblock       * master_key,
+	      krb5_key_salt_tuple	* ks_tuple,
+	      int			  ks_tuple_count,
+	      char 		* passwd,
+	      int			  new_kvno,
+	      krb5_boolean	  keepold,
+	      krb5_db_entry	* db_entry);
+
+krb5_error_code
+krb5_dbe_ark( krb5_context	  context,
+	      krb5_keyblock       * master_key,
+	      krb5_key_salt_tuple	* ks_tuple,
+	      int			  ks_tuple_count,
+	      krb5_db_entry	* db_entry);
+
+krb5_error_code
+krb5_dbe_crk( krb5_context	  context,
+	      krb5_keyblock       * master_key,
+	      krb5_key_salt_tuple	* ks_tuple,
+	      int			  ks_tuple_count,
+	      krb5_boolean	  keepold,
+	      krb5_db_entry	* db_entry);
+
+krb5_error_code
+krb5_dbe_apw( krb5_context	  context,
+	      krb5_keyblock       * master_key,
+	      krb5_key_salt_tuple	* ks_tuple,
+	      int			  ks_tuple_count,
+	      char 		* passwd,
+	      krb5_db_entry	* db_entry);
+
+
+/* default functions. Should not be directly called */
+/*
+ *   Default functions prototype
+ */
+
+krb5_error_code
+krb5_dbe_def_search_enctype( krb5_context kcontext, 
+			     krb5_db_entry *dbentp, 
+			     krb5_int32 *start, 
+			     krb5_int32 ktype, 
+			     krb5_int32 stype, 
+			     krb5_int32 kvno, 
+			     krb5_key_data **kdatap);
+
+krb5_error_code
+krb5_def_store_mkey( krb5_context context,
+		     char *keyfile,
+		     krb5_principal mname,
+		     krb5_keyblock *key,
+		     char *master_pwd);
+
+
+krb5_error_code
+krb5_db_def_fetch_mkey( krb5_context   context,
+			krb5_principal mname,
+			krb5_keyblock *key,
+			int           *kvno,
+			char          *db_args);
+
+krb5_error_code
+krb5_def_verify_master_key( krb5_context context,
+			    krb5_principal mprinc,
+			    krb5_keyblock *mkey);
+
+krb5_error_code kdb_def_set_mkey ( krb5_context kcontext,
+				   char *pwd,
+				   krb5_keyblock *key );
+
+krb5_error_code kdb_def_get_mkey ( krb5_context kcontext,
+				   krb5_keyblock **key );
+
+krb5_error_code
+krb5_dbe_def_cpw( krb5_context	  context,
+		  krb5_keyblock       * master_key,
+		  krb5_key_salt_tuple	* ks_tuple,
+		  int			  ks_tuple_count,
+		  char 		* passwd,
+		  int			  new_kvno,
+		  krb5_boolean	  keepold,
+		  krb5_db_entry	* db_entry);
+
+
+krb5_error_code 
+krb5_db_create_policy( krb5_context kcontext, 
+		       osa_policy_ent_t policy);
+
+krb5_error_code 
+krb5_db_get_policy ( krb5_context kcontext, 
+		     char *name, 
+		     osa_policy_ent_t *policy,
+		     int *nentries);
+
+krb5_error_code 
+krb5_db_put_policy( krb5_context kcontext, 
+		    osa_policy_ent_t policy);
+
+krb5_error_code 
+krb5_db_iter_policy( krb5_context kcontext,
+		     char *match_entry,
+		     osa_adb_iter_policy_func func,
+		     void *data);
+
+krb5_error_code 
+krb5_db_delete_policy( krb5_context kcontext, 
+		       char *policy);
+
+void 
+krb5_db_free_policy( krb5_context kcontext, 
+		     osa_policy_ent_t policy);
+
+void krb5_db_clr_error(void);
+
+#define KRB5_KDB_DEF_FLAGS	0
+
+#endif /* !defined(_WIN32) */
+#endif /* KRB5_KDB5__ */
diff --git a/mechglue/src/include/krb5/kdb_dbc.h b/mechglue/src/include/krb5/kdb_dbc.h
new file mode 100644
index 000000000..e2b300288
--- /dev/null
+++ b/mechglue/src/include/krb5/kdb_dbc.h
@@ -0,0 +1,86 @@
+/*
+ * include/krb5/kdb_dbc.h
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * KDC Database context definitions.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+#ifndef KRB5_KDB5_DBC__
+#define KRB5_KDB5_DBC__
+
+#include "kdb.h"
+	
+/* Per-database context. */
+typedef struct __krb5_db_context {
+    krb5_boolean        db_inited;      /* Context initialized          */
+    char *              db_name;        /* Name of database             */
+    DBM *               db_dbm_ctx;     /* DBM context for database     */
+    char *              db_lf_name;     /* Name of lock file            */
+    int                 db_lf_file;     /* File descriptor of lock file */
+    time_t              db_lf_time;     /* Time last updated            */
+    int                 db_locks_held;  /* Number of times locked       */
+    int                 db_lock_mode;   /* Last lock mode, e.g. greatest*/
+    krb5_boolean        db_nb_locks;    /* [Non]Blocking lock modes     */
+    krb5_keyblock      *db_master_key;  /* Master key of database       */
+    kdb5_dispatch_table *db_dispatch;   /* Dispatch table               */
+} krb5_db_context;
+
+krb5_error_code krb5_ktkdb_resolve
+        (krb5_context, krb5_db_context *, krb5_keytab *);
+
+krb5_error_code krb5_dbm_db_set_mkey
+        (krb5_context,krb5_db_context *,krb5_encrypt_block *);
+
+krb5_error_code krb5_dbm_db_get_mkey
+        (krb5_context,krb5_db_context *,krb5_encrypt_block **);
+
+#endif /* KRB5_KDB5_DBM__ */
diff --git a/mechglue/src/include/krb5/kdb_kt.h b/mechglue/src/include/krb5/kdb_kt.h
new file mode 100644
index 000000000..1dbd7f30d
--- /dev/null
+++ b/mechglue/src/include/krb5/kdb_kt.h
@@ -0,0 +1,42 @@
+/*
+ * include/krb5/kdb_kt.h
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * KDC keytab definitions.
+ */
+
+
+#ifndef KRB5_KDB5_KT_H
+#define KRB5_KDB5_KT_H
+
+#include "kdb.h"
+
+extern struct _krb5_kt_ops krb5_kt_kdb_ops;
+
+krb5_error_code krb5_ktkdb_resolve (krb5_context, const char *, krb5_keytab *);
+
+krb5_error_code krb5_ktkdb_set_context(krb5_context);
+
+#endif /* KRB5_KDB5_DBM__ */
diff --git a/mechglue/src/include/krb5/stock/.Sanitize b/mechglue/src/include/krb5/stock/.Sanitize
new file mode 100644
index 000000000..9a91ab33a
--- /dev/null
+++ b/mechglue/src/include/krb5/stock/.Sanitize
@@ -0,0 +1,33 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+ChangeLog
+osconf.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/include/krb5/stock/ChangeLog b/mechglue/src/include/krb5/stock/ChangeLog
new file mode 100644
index 000000000..cfa6cb4de
--- /dev/null
+++ b/mechglue/src/include/krb5/stock/ChangeLog
@@ -0,0 +1,190 @@
+2005-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* osconf.h (DEFAULT_KDB_LIB_PATH): Use @MODULEDIR.  Don't use a
+	fixed global directory.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	Novell merge.
+	* osconf.h (DEFAULT_KDB_LIB_PATH): Define.
+
+2004-07-09  Jeffrey Altman <jaltman@mit.edu>
+
+    * osconf.h: !!define -> !define
+
+2003-05-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* osconf.h (DEFAULT_KDC_ENCTYPE): Default to des3 now.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+
+    * osconf.h: Added DEFAULT_SECURE_PROFILE_PATH so that KfM will only
+    search paths that start with ~/ (homedir-based) when getting an
+    insecure context.  This is the same as DEFAULT_PROFILE_PATH on all
+    other platforms, which allows us to avoid more references to 
+    TARGET_OS_MAC in krb5 sources.
+
+2002-09-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* osconf.h (DEFAULT_KDC_UDP_PORTLIST): Renamed from
+	DEFAULT_KDC_PORTLIST.
+	(DEFAULT_KDC_TCP_PORTLIST): New macro.
+
+2002-07-03  Alexandra Ellwood <lxs@mit.edu>
+
+	* osconf.h (DEFAULT_PROFILE_PATH): Conditionalized for Mac OS X
+	to look in Mac OS X Preferences file locations.
+	[pullup from 1-2-2-branch]
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* osconf.h: Drop _MSDOS support.
+
+1999-09-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* osconf.h (KPASSWD_PORTNAME): Define.
+
+Tue Jan 20 23:19:53 1998  Tom Yu  <tlyu@mit.edu>
+
+	* osconf.h: Add DEFAULT_KPASSWD_PORT to support Cygnus chpw.
+
+Wed Nov 13 23:58:30 1996  Tom Yu  <tlyu@mit.edu>
+
+	* osconf.h (DEFAULT_KEYTAB_NAME): Change DOS version of this to
+	FILE:%s\\krb5kt to match "krb5cc".
+
+Tue Nov 12 18:40:08 1996  Tom Yu  <tlyu@mit.edu>
+
+	* osconf.h: Change DEFAULT_KEYTAB_NAME to /etc/krb5.keytab under
+	Unix.
+
+Wed Oct 30 19:00:07 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* osconf.h :  Set up to use autoconf-style directories. [37]
+
+Wed Aug 28 16:13:10 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* osconf.h: add KADM5 defaults: KEYTAB, ACL_FILE, PORT
+
+Mon Aug 12 16:58:16 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* osconf.h: add KPROPD_DEFAULT_KDB5_UTIL
+
+Wed Jun 12 00:43:16 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* osconf.h: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS
+
+Tue Mar  5 12:27:18 1996  Richard Basch  <basch@lehman.com>
+
+	* osconf.h (KPROPD_DEFAULT_KDB5_EDIT): kdb5_edit is now in PREFIX/sbin
+
+Sat Feb 24 18:59:39 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* osconf.h (DEFAULT_KEYTAB_NAME): Under windows, let it be
+		%s\v5srvtab.  It will be filled in by the
+		krb5_kt_default_name with the name of windows directory.
+
+Thu Oct  5 21:45:13 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* osconf.h (DEFAULT_KDC_PROFILE): Change the name of the kdc
+		configuration file to be kdc.conf.
+		Added DEFAULT_KDC_PORTLIST.
+
+Tue Sep 26 22:47:15 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* osconf.h (DEFAULT_PROFILE_PATH): look in $(prefix)/lib/krb5.conf
+	if /etc/krb5.conf isn't found.
+
+Fri Sep 29 01:45:27 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* osconf.h: Don't include autoconf.h under Windows, since it
+		doesn't exist.
+
+Wed Sep 13 23:50:02 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* osconf.h (KPROP_DEFAULT_FILE, KPROPD_DEFAULT_FILE,
+	KPROPD_DEFAULT_KDB5_EDIT, KPROPD_DEFAULT_KRB_DB): set defaults
+	correctly for kprop/kpropd in respect to prefix.
+
+Mon Jul 17 15:05:42 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* osconf.h - Add DEFAULT_KEYFILE_STUB which puts the stashfile in
+		the kdc directory instead of the root.  Also, change the
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * osconf.h : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * osconf.h : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate.
+		default ETYPE to DES_CBC_MD5 now that it works.
+
+
+Thu Jun 22 11:53:47 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* osconf.h - Add DEFAULT_KDC_PROFILE and KDC_PROFILE_ENV for KDC
+		profile location.
+
+Thu Jun 8 14:42:56 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* osconf.h - Restore DEFAULT_ADMIN_ACL definition to be
+		.../kadm_old.acl since kadmin.old needs this definition.
+
+Wed Jun  7 16:13:24 1995    <tytso@rsx-11.mit.edu>
+
+	* osconf.h: Use INSTALL and INSTALL_PREFIX instead of KRB5ROOT.
+		How the filenames are determined have been completely
+		revamped.
+
+Sun May 21 15:33:36 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* osconf.h: Setup the RCTMPDIR to be modified by configure. 
+
+Fri Apr 21 21:00:40 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* osconf.h: Add #define's for DEFAULT_PROFILE_FILENAME.  
+
+Tue Mar 28 19:49:56 1995 Keith Vetter (keithv@fusion.com)
+
+	* osconf.h: moved the differing part of osconf.win inside it.
+        * osconf.win: deleted.
+
+Tue Mar 7 15:09:44 1995 Keith Vetter (keithv@fusion.com)
+
+	* osconf.win: new file. Windows version of osconf with valid
+           path names.
+
+Mon Feb 20 12:30:42 1995  John Gilmore  (gnu at toad.com)
+
+	* config.h, config.win:  Remove; merge them both into ../config.h.
+	Now that we aren't using imake, this isn't a generated header file.
+
+Mon Feb 20 15:25:26 1995 Keith Vetter (keithv@fusion.com)
+
+	* config.h: changed API to INTERFACE.
+        * config.win: changed API to INTERFACE and changed BITS16
+           to SIZEOF_INT/SIZEOF_LONG to track an autoconf change.
+
+Mon Feb 6 20:5:58 1995 Keith Vetter (keithv@fusion.com)
+
+	* config.win: new file--windows base template for config.h
+	* config.h: added API definition default of NULL
+
+Thu Jan  5 17:01:03 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Use the service names kerberos and kerberos-sec, instead of
+		kerberos5 and kerberos4 --- the official port name is
+		kerberos, after all!
+
+Wed Nov 30 16:18:29 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* osconf.h, config.h: Remove remnants of unifdef support for
+		building osconf.h and config.h, left over from the imake
+		build system. 
+
+	* osconf.h: Add #ifdef for Athena configuration.
+
+Thu Oct 13 16:58:53 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* config.h: Define PROVIDE_DES_CBC_MD5 so that we include this
+		cryptosystem.
+
diff --git a/mechglue/src/include/krb5/stock/osconf.h b/mechglue/src/include/krb5/stock/osconf.h
new file mode 100644
index 000000000..367109b11
--- /dev/null
+++ b/mechglue/src/include/krb5/stock/osconf.h
@@ -0,0 +1,128 @@
+/*
+ * include/krb5/stock/osconf.h
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Site- and OS- dependant configuration.
+ */
+
+#ifndef KRB5_OSCONF__
+#define KRB5_OSCONF__
+
+#if !defined(_WIN32)
+    /* Don't try to pull in autoconf.h for Windows, since it's not used */
+#ifndef KRB5_AUTOCONF__
+#define KRB5_AUTOCONF__
+#include "autoconf.h"
+#endif
+#endif
+
+#if defined(_WIN32)
+#define DEFAULT_PROFILE_FILENAME "krb5.ini"
+#define	DEFAULT_LNAME_FILENAME	"/aname"
+#define	DEFAULT_KEYTAB_NAME	"FILE:%s\\krb5kt"
+#else /* !_WINDOWS */
+#if TARGET_OS_MAC
+#define DEFAULT_SECURE_PROFILE_PATH "/Library/Preferences/edu.mit.Kerberos:/etc/krb5.conf:@SYSCONFDIR/krb5.conf"
+#define DEFAULT_PROFILE_PATH        ("~/Library/Preferences/edu.mit.Kerberos" ":" DEFAULT_SECURE_PROFILE_PATH)
+#else
+#define DEFAULT_SECURE_PROFILE_PATH	"/etc/krb5.conf:@SYSCONFDIR/krb5.conf"
+#define DEFAULT_PROFILE_PATH        DEFAULT_SECURE_PROFILE_PATH
+#endif
+#define	DEFAULT_KEYTAB_NAME	"FILE:/etc/krb5.keytab"
+#define	DEFAULT_LNAME_FILENAME	"@PREFIX/lib/krb5.aname"
+#endif /* _WINDOWS  */
+
+#define DEFAULT_KDB_FILE        "@LOCALSTATEDIR/krb5kdc/principal"
+#define	DEFAULT_KEYFILE_STUB	"@LOCALSTATEDIR/krb5kdc/.k5."
+#define KRB5_DEFAULT_ADMIN_ACL	"@LOCALSTATEDIR/krb5kdc/krb5_adm.acl"
+/* Used by old admin server */
+#define	DEFAULT_ADMIN_ACL	"@LOCALSTATEDIR/krb5kdc/kadm_old.acl"
+
+/* Location of KDC profile */
+#define	DEFAULT_KDC_PROFILE	"@LOCALSTATEDIR/krb5kdc/kdc.conf"
+#define	KDC_PROFILE_ENV		"KRB5_KDC_PROFILE"
+#define DEFAULT_KDB_LIB_PATH	{ "@MODULEDIR", NULL }
+
+#define	DEFAULT_KDC_ENCTYPE	ENCTYPE_DES3_CBC_SHA1
+#define KDCRCACHE		"dfl:krb5kdc_rcache"
+
+#define KDC_PORTNAME		"kerberos" /* for /etc/services or equiv. */
+#define KDC_SECONDARY_PORTNAME	"kerberos-sec" /* For backwards */
+					    /* compatibility with */
+					    /* port 750 clients */
+
+#define KRB5_DEFAULT_PORT	88
+#define KRB5_DEFAULT_SEC_PORT	750
+
+#define DEFAULT_KPASSWD_PORT	464
+#define KPASSWD_PORTNAME "kpasswd"
+
+#define DEFAULT_KDC_UDP_PORTLIST "88,750"
+#define DEFAULT_KDC_TCP_PORTLIST ""
+
+/*
+ * Defaults for the KADM5 admin system.
+ */
+#define DEFAULT_KADM5_KEYTAB	"@LOCALSTATEDIR/krb5kdc/kadm5.keytab"
+#define DEFAULT_KADM5_ACL_FILE	"@LOCALSTATEDIR/krb5kdc/kadm5.acl"
+#define DEFAULT_KADM5_PORT	749 /* assigned by IANA */
+
+#define MAX_DGRAM_SIZE	4096
+#define MAX_SKDC_TIMEOUT 30
+#define SKDC_TIMEOUT_SHIFT 2		/* left shift of timeout for backoff */
+#define SKDC_TIMEOUT_1 1		/* seconds for first timeout */
+
+#define RCTMPDIR	"@KRB5RCTMPDIR"	/* directory to store replay caches */
+
+#define KRB5_PATH_TTY	"/dev/tty"
+#define KRB5_PATH_LOGIN	"@SBINDIR/login.krb5"
+#define KRB5_PATH_RLOGIN "@BINDIR/rlogin"
+
+#define KRB5_ENV_CCNAME	"KRB5CCNAME"
+
+/*
+ * krb4 kadmin stuff follows
+ */
+
+/* the default syslog file */
+#define KADM_SYSLOG  "@LOCALSTATEDIR/krb5kdc/admin_server.syslog"
+
+/* where to find the bad password table */
+#define PW_CHECK_FILE "@LOCALSTATEDIR/krb5kdc/bad_passwd"
+
+#define DEFAULT_ACL_DIR	"@LOCALSTATEDIR/krb5kdc"
+
+/*
+ * krb5 slave support follows
+ */
+
+#define KPROP_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/slave_datatrans"
+#define KPROPD_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/from_master"
+#define KPROPD_DEFAULT_KDB5_UTIL "@SBINDIR/kdb5_util"
+#define KPROPD_DEFAULT_KDB5_EDIT "@SBINDIR/kdb5_edit"
+#define KPROPD_DEFAULT_KRB_DB DEFAULT_KDB_FILE
+#define KPROPD_ACL_FILE "@LOCALSTATEDIR/krb5kdc/kpropd.acl"
+
+#endif /* KRB5_OSCONF__ */
diff --git a/mechglue/src/include/krb54proto.h b/mechglue/src/include/krb54proto.h
new file mode 100644
index 000000000..d1d16e1ba
--- /dev/null
+++ b/mechglue/src/include/krb54proto.h
@@ -0,0 +1,18 @@
+/*
+ * Kerberos V 5/4 prototypes
+ */
+
+extern krb5_error_code krb54_get_service_keyblock
+	(char *service, char *instance, char *realm,
+		   int kvno, char *file,
+		   krb5_keyblock * keyblock);
+extern int decomp_tkt_krb5
+	(KTEXT tkt, unsigned char *flags, char *pname,
+		   char *pinstance, char *prealm, unsigned KRB4_32 *paddress,
+		   des_cblock session, int *life, unsigned KRB4_32 *time_sec, 
+		   char *sname, char *sinstance, krb5_keyblock *k5key);
+extern int krb_set_key_krb5
+	(krb5_context ctx, krb5_keyblock *key);
+void krb_clear_key_krb5
+	(krb5_context ctx);
+
diff --git a/mechglue/src/include/port-sockets.h b/mechglue/src/include/port-sockets.h
new file mode 100644
index 000000000..d1cf9e6f9
--- /dev/null
+++ b/mechglue/src/include/port-sockets.h
@@ -0,0 +1,187 @@
+#ifndef _PORT_SOCKET_H
+#define _PORT_SOCKET_H
+#if defined(_WIN32)
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+/* Some of our own infrastructure where the WinSock stuff was too hairy
+   to dump into a clean Unix program...  */
+
+typedef WSABUF sg_buf;
+
+#define SG_ADVANCE(SG, N) \
+	((SG)->len < (N)				\
+	 ? (abort(), 0)					\
+	 : ((SG)->buf += (N), (SG)->len -= (N), 0))
+
+#define SG_LEN(SG)		((SG)->len + 0)
+#define SG_BUF(SG)		((SG)->buf + 0)
+#define SG_SET(SG, B, N)	((SG)->buf = (char *)(B),(SG)->len = (N))
+
+#define SOCKET_INITIALIZE()     0
+#define SOCKET_CLEANUP()
+#define SOCKET_ERRNO            (WSAGetLastError())
+#define SOCKET_SET_ERRNO(x)     (WSASetLastError (x))
+#define SOCKET_NFDS(f)          (0)     /* select()'s first arg is ignored */
+#define SOCKET_READ(fd, b, l)   (recv(fd, b, l, 0))
+#define SOCKET_WRITE(fd, b, l)  (send(fd, b, l, 0))
+#define SOCKET_CONNECT		connect	/* XXX */
+#define SOCKET_GETSOCKNAME	getsockname /* XXX */
+#define SOCKET_CLOSE		close /* XXX */
+#define SOCKET_EINTR            WSAEINTR
+
+/* Return -1 for error or number of bytes written.
+   TMP is a temporary variable; must be declared by the caller, and
+   must be used by this macro (to avoid compiler warnings).  */
+/* WSASend returns 0 or SOCKET_ERROR.  */
+#define SOCKET_WRITEV_TEMP DWORD
+#define SOCKET_WRITEV(FD, SG, LEN, TMP)	\
+	(WSASend((FD), (SG), (LEN), &(TMP), 0, 0, 0) ? -1 : (TMP))
+
+#define SHUTDOWN_READ	SD_RECEIVE
+#define SHUTDOWN_WRITE	SD_SEND
+#define SHUTDOWN_BOTH	SD_BOTH
+
+#ifndef EINPROGRESS
+#define EINPROGRESS WSAEINPROGRESS
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+#ifndef ECONNRESET
+#define ECONNRESET  WSAECONNRESET
+#endif
+#ifndef ECONNABORTED
+#define ECONNABORTED WSAECONNABORTED
+#endif
+#ifndef ECONNREFUSED
+#define ECONNREFUSED WSAECONNREFUSED
+#endif
+#ifndef EHOSTUNREACH
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#ifndef ETIMEDOUT
+#define ETIMEDOUT WSAETIMEDOUT
+#endif
+
+#elif defined(__palmos__)
+
+/* If this source file requires it, define struct sockaddr_in
+   (and possibly other things related to network I/O).  */
+
+#include "krb5/autoconf.h"
+#include <netdb.h>
+typedef int socklen_t;
+
+#else /* UNIX variants */
+
+#include "krb5/autoconf.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>		/* For struct sockaddr_in and in_addr */
+#include <arpa/inet.h>		/* For inet_ntoa */
+#include <netdb.h>
+
+#ifndef HAVE_NETDB_H_H_ERRNO
+extern int h_errno;		/* In case it's missing, e.g., HP-UX 10.20. */
+#endif
+
+#include <sys/param.h>		/* For MAXHOSTNAMELEN */
+#include <sys/socket.h>		/* For SOCK_*, AF_*, etc */
+#include <sys/time.h>		/* For struct timeval */
+#include <net/if.h>		/* For struct ifconf, for localaddr.c */
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>		/* For struct iovec, for sg_buf */
+#endif
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>		/* For FIONBIO on Solaris.  */
+#endif
+
+/* Either size_t or int or unsigned int is probably right.  Under
+   SunOS 4, it looks like int is desired, according to the accept man
+   page.  */
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+/* XXX should only be done if sockaddr_storage not found */
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+struct krb5int_sockaddr_storage {
+    struct sockaddr_in s;
+    /* Plenty of slop just in case we get an ipv6 address anyways.  */
+    long extra[16];
+};
+#define sockaddr_storage krb5int_sockaddr_storage
+#endif
+
+/*
+ * Compatability with WinSock calls on MS-Windows...
+ */
+#define	SOCKET		int
+#define	INVALID_SOCKET	((SOCKET)~0)
+#define	closesocket	close
+#define	ioctlsocket	ioctl
+#define	SOCKET_ERROR	(-1)
+
+typedef struct iovec sg_buf;
+
+#define SG_ADVANCE(SG, N) \
+	((SG)->iov_len < (N)					\
+	 ? (abort(), 0)						\
+	 : ((SG)->iov_base = (char *) (SG)->iov_base + (N),	\
+	    (SG)->iov_len -= (N), 0))
+
+#define SG_LEN(SG)		((SG)->iov_len + 0)
+#define SG_BUF(SG)		((char*)(SG)->iov_base + 0)
+#define SG_SET(SG, B, L)	((SG)->iov_base = (char*)(B), (SG)->iov_len = (L))
+
+/* Some of our own infrastructure where the WinSock stuff was too hairy
+   to dump into a clean Unix program...  */
+
+#define	SOCKET_INITIALIZE()	(0)	/* No error (or anything else) */
+#define	SOCKET_CLEANUP()	/* nothing */
+#define	SOCKET_ERRNO		errno
+#define	SOCKET_SET_ERRNO(x)	(errno = (x))
+#define SOCKET_NFDS(f)		((f)+1)	/* select() arg for a single fd */
+#define SOCKET_READ		read
+#define SOCKET_WRITE		write
+#define SOCKET_CONNECT		connect
+#define SOCKET_GETSOCKNAME	getsockname
+#define SOCKET_CLOSE		close
+#define SOCKET_EINTR		EINTR
+#define SOCKET_WRITEV_TEMP int
+/* Use TMP to avoid compiler warnings and keep things consistent with
+   Windoze version.  */
+#define SOCKET_WRITEV(FD, SG, LEN, TMP) \
+	((TMP) = writev((FD), (SG), (LEN)), (TMP))
+
+#define SHUTDOWN_READ	0
+#define SHUTDOWN_WRITE	1
+#define SHUTDOWN_BOTH	2
+
+#ifndef HAVE_INET_NTOP
+#define inet_ntop(AF,SRC,DST,CNT)					    \
+    ((AF) == AF_INET							    \
+     ? ((CNT) < 16							    \
+	? (SOCKET_SET_ERRNO(ENOSPC), (const char *)NULL)		    \
+	: (sprintf((DST), "%d.%d.%d.%d",				    \
+		   ((const unsigned char *)(const void *)(SRC))[0] & 0xff,  \
+		   ((const unsigned char *)(const void *)(SRC))[1] & 0xff,  \
+		   ((const unsigned char *)(const void *)(SRC))[2] & 0xff,  \
+		   ((const unsigned char *)(const void *)(SRC))[3] & 0xff), \
+	   (DST)))							    \
+     : (SOCKET_SET_ERRNO(EAFNOSUPPORT), (const char *)NULL))
+#define HAVE_INET_NTOP
+#endif
+
+#endif /* _WIN32 */
+
+#if !defined(_WIN32)
+/* UNIX or ...?  */
+# ifdef S_SPLINT_S
+extern int socket (int, int, int) /*@*/;
+# endif
+#endif
+
+#endif /*_PORT_SOCKET_H*/
diff --git a/mechglue/src/include/socket-utils.h b/mechglue/src/include/socket-utils.h
new file mode 100644
index 000000000..dcd24ebc7
--- /dev/null
+++ b/mechglue/src/include/socket-utils.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2001,2005 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
+
+#ifndef SOCKET_UTILS_H
+#define SOCKET_UTILS_H
+
+/* Some useful stuff cross-platform for manipulating socket addresses.
+   We assume at least ipv4 sockaddr_in support.  The sockaddr_storage
+   stuff comes from the ipv6 socket api enhancements; socklen_t is
+   provided on some systems; the rest is just convenience for internal
+   use in the krb5 tree.
+
+   Do NOT install this file.  */
+
+/* for HAVE_SOCKLEN_T, KRB5_USE_INET6, etc */
+#include "krb5/autoconf.h"
+/* for sockaddr_storage */
+#include "port-sockets.h"
+/* for "inline" if needed */
+#include "k5-platform.h"
+
+/*
+ * There's a lot of confusion between pointers to different sockaddr
+ * types, and pointers with different degrees of indirection, as in
+ * the locate_kdc type functions.  Use these function to ensure we
+ * don't do something silly like cast a "sockaddr **" to a
+ * "sockaddr_in *".
+ *
+ * The casts to (void *) are to get GCC to shut up about alignment
+ * increasing.
+ */
+static inline struct sockaddr_in *sa2sin (struct sockaddr *sa)
+{
+    return (struct sockaddr_in *) (void *) sa;
+}
+#ifdef KRB5_USE_INET6
+static inline struct sockaddr_in6 *sa2sin6 (struct sockaddr *sa)
+{
+    return (struct sockaddr_in6 *) (void *) sa;
+}
+#endif
+static inline struct sockaddr *ss2sa (struct sockaddr_storage *ss)
+{
+    return (struct sockaddr *) ss;
+}
+static inline struct sockaddr_in *ss2sin (struct sockaddr_storage *ss)
+{
+    return (struct sockaddr_in *) ss;
+}
+#ifdef KRB5_USE_INET6
+static inline struct sockaddr_in6 *ss2sin6 (struct sockaddr_storage *ss)
+{
+    return (struct sockaddr_in6 *) ss;
+}
+#endif
+
+#if !defined (socklen)
+/* socklen_t socklen (struct sockaddr *) */
+#  ifdef HAVE_SA_LEN
+#    define socklen(X) ((X)->sa_len)
+#  else
+#    ifdef KRB5_USE_INET6
+#      define socklen(X) ((X)->sa_family == AF_INET6 ? (socklen_t) sizeof (struct sockaddr_in6) : (X)->sa_family == AF_INET ? (socklen_t) sizeof (struct sockaddr_in) : (socklen_t) sizeof (struct sockaddr))
+#    else
+#      define socklen(X) ((X)->sa_family == AF_INET ? (socklen_t) sizeof (struct sockaddr_in) : (socklen_t) sizeof (struct sockaddr))
+#    endif
+#  endif
+#endif
+
+#endif /* SOCKET_UTILS_H */
diff --git a/mechglue/src/include/spnego-asn1.h b/mechglue/src/include/spnego-asn1.h
new file mode 100644
index 000000000..8070a9f99
--- /dev/null
+++ b/mechglue/src/include/spnego-asn1.h
@@ -0,0 +1,89 @@
+/*
+ * spnego-asn1.h
+ *
+ * Copyright (C) 2002 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This file contains structure definitions 
+ * for the SPNEGO GSSAPI mechanism (RFC 2478).  This file is
+ *an internal interface between the GSSAPI library  and the ASN.1
+ *encoders/decoders for the SPNEGO structures in the krb5 library.
+ */
+
+
+#ifndef _KRB5_SPNEGO_ASN1_H_
+#define _KRB5_SPNEGO_ASN1_h_
+
+#include "k5-int.h"
+
+/* Context flags recognized by SPNEGO*/
+enum {
+  SPNEGO_DELEG_FLAG = 0x80,
+  SPNEGO_MUTUAL_FLAG = 0x40,
+  SPNEGO_ANON_FLAG=0x20,
+  SPNEGO_CONF_FLAG = 0x10
+};
+
+/* Results of a negotiation*/
+enum {
+  SPNEGO_ACCEPT_COMPLETED = 0,
+  SPNEGO_ACCEPT_INCOMPLETE = 1,
+  SPNEGO_REJECT = 2,
+  SPNEGO_UNSPEC_RESULT = 3
+};
+
+typedef krb5_data spnego_oid;
+
+typedef struct _spnego_initiator_token {
+    spnego_oid **mechanisms;
+    krb5_int32 requested_flags;
+    krb5_data mech_token;
+    krb5_data mechlist_mic;
+} spnego_initiator_token;
+
+typedef struct _spnego_acceptor_token {
+    int neg_result;
+    spnego_oid supported_mech;
+    krb5_data response_token;
+    krb5_data mechlist_mic;
+} spnego_acceptor_token;
+
+/*
+ * SPNEGO_PROTOTYPES should be defined in the modules implementing
+ * SPNEGO functions  and in the module implementing the accessor
+ * initializer.  All other modules should access these functions
+ * through the accessor interface.
+ */
+
+#ifdef SPNEGO_PROTOTYPES
+
+krb5_error_code krb5int_encode_spnego_acceptor_token
+(krb5_context , spnego_acceptor_token *,
+	 krb5_data **);
+
+krb5_error_code krb5int_encode_spnego_initiator_token
+(krb5_context, spnego_initiator_token *,
+ krb5_data **out);
+#endif /*SPNEGO_ASN1_PROTOTYPES*/
+
+#endif /*_KRB5_SPNEGO_ASN1_H_*/
diff --git a/mechglue/src/include/syslog.h b/mechglue/src/include/syslog.h
new file mode 100644
index 000000000..f587921e1
--- /dev/null
+++ b/mechglue/src/include/syslog.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *	@(#)syslog.h	7.10 (Berkeley) 6/27/88
+ */
+
+/*
+ *	include/syslog.h
+ */
+
+/*
+ *  Facility codes
+ */
+
+#define LOG_KERN	(0<<3)	/* kernel messages */
+#define LOG_USER	(1<<3)	/* random user-level messages */
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_SYSLOG	(5<<3)	/* messages generated internally by syslogd */
+#define LOG_LPR		(6<<3)	/* line printer subsystem */
+#define LOG_NEWS	(7<<3)	/* network news subsystem */
+#define LOG_UUCP	(8<<3)	/* UUCP subsystem */
+	/* other codes through 15 reserved for system use */
+#define LOG_LOCAL0	(16<<3)	/* reserved for local use */
+#define LOG_LOCAL1	(17<<3)	/* reserved for local use */
+#define LOG_LOCAL2	(18<<3)	/* reserved for local use */
+#define LOG_LOCAL3	(19<<3)	/* reserved for local use */
+#define LOG_LOCAL4	(20<<3)	/* reserved for local use */
+#define LOG_LOCAL5	(21<<3)	/* reserved for local use */
+#define LOG_LOCAL6	(22<<3)	/* reserved for local use */
+#define LOG_LOCAL7	(23<<3)	/* reserved for local use */
+
+#define LOG_NFACILITIES	24	/* maximum number of facilities */
+#define LOG_FACMASK	0x03f8	/* mask to extract facility part */
+
+#define LOG_FAC(p)	(((p) & LOG_FACMASK) >> 3)	/* facility of pri */
+
+/*
+ *  Priorities (these are ordered)
+ */
+
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+
+#define LOG_PRIMASK	0x0007	/* mask to extract priority part (internal) */
+#define LOG_PRI(p)	((p) & LOG_PRIMASK)	/* extract priority */
+
+#define	LOG_MAKEPRI(fac, pri)	(((fac) << 3) | (pri))
+
+#ifdef KERNEL
+#define LOG_PRINTF	-1	/* pseudo-priority to indicate use of printf */
+#endif
+
+/*
+ * arguments to setlogmask.
+ */
+#define	LOG_MASK(pri)	(1 << (pri))		/* mask for one priority */
+#define	LOG_UPTO(pri)	((1 << ((pri)+1)) - 1)	/* all priorities through pri */
+
+/*
+ *  Option flags for openlog.
+ *
+ *	LOG_ODELAY no longer does anything; LOG_NDELAY is the
+ *	inverse of what it used to be.
+ */
+#define	LOG_PID		0x01	/* log the pid with each message */
+#define	LOG_CONS	0x02	/* log on the console if errors in sending */
+#define	LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+#ifndef KERNEL
+extern void syslog  (int , const char *, ... );
+#ifdef va_start				
+/* XXX depending on #define of va_start in <stdarg.h> */
+extern void vsyslog  (int , const char *, va_list );
+#endif
+extern void openlog  (const char *, int , int );
+extern void closelog  (void );
+extern int setlogmask  (int );
+
+#endif
diff --git a/mechglue/src/include/win-mac.h b/mechglue/src/include/win-mac.h
new file mode 100644
index 000000000..ea53cf17f
--- /dev/null
+++ b/mechglue/src/include/win-mac.h
@@ -0,0 +1,213 @@
+/*
+ * This file is now only used on Windows
+ */
+
+/*
+ * type functions split out of here to make things look nicer in the
+ * various include files which need these definitions, as well as in
+ * the util/ directories.
+ */
+
+#ifndef _KRB5_WIN_MAC_H
+#define _KRB5_WIN_MAC_H
+
+#ifdef _WIN32
+
+#define ID_READ_PWD_DIALOG  10000
+#define ID_READ_PWD_PROMPT  10001
+#define ID_READ_PWD_PROMPT2 10002
+#define ID_READ_PWD_PWD     10003
+
+#ifdef RES_ONLY
+
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include <windows.h>
+
+#else /* ! RES_ONLY */
+
+#define SIZEOF_INT      4
+#define SIZEOF_SHORT    2
+#define SIZEOF_LONG     4
+
+#include <windows.h>
+#include <limits.h>
+
+#ifndef SIZE_MAX    /* in case Microsoft defines max size of size_t */
+#ifdef  MAX_SIZE    /* Microsoft defines MAX_SIZE as max size of size_t */
+#define SIZE_MAX MAX_SIZE
+#else
+#define SIZE_MAX UINT_MAX
+#endif
+#endif
+
+/* To ensure backward compatibility of the ABI use 32-bit time_t on 
+ * 32-bit Windows. 
+ */
+#ifdef _KRB5_INT_H
+#ifdef KRB5_GENERAL__
+#error krb5.h included before k5-int.h
+#endif /* KRB5_GENERAL__ */
+#if _INTEGRAL_MAX_BITS >= 64 && _MSC_VER >= 1400 && !defined(_WIN64) && !defined(_USE_32BIT_TIME_T)
+#if defined(_TIME_T_DEFINED) || defined(_INC_IO) || defined(_INC_TIME) || defined(_INC_WCHAR)
+#error time_t has been defined as a 64-bit integer which is incompatible with Kerberos on this platform.
+#endif /* _TIME_T_DEFINED */
+#define _USE_32BIT_TIME_T
+#endif 
+#endif
+
+#ifndef KRB5_CALLCONV
+#  define KRB5_CALLCONV __stdcall
+#  define KRB5_CALLCONV_C __cdecl
+
+/*
+ * Use this to mark an incorrect calling convention that has been
+ * "immortalized" because it was incorrectly exported in a previous
+ * release.
+ */
+
+#  define KRB5_CALLCONV_WRONG KRB5_CALLCONV_C
+
+#endif /* !KRB5_CALLCONV */
+
+#ifndef KRB5_SYSTYPES__
+#define KRB5_SYSTYPES__
+#include <sys/types.h>
+typedef unsigned long	 u_long;      /* Not part of sys/types.h on the pc */
+typedef unsigned int	 u_int;
+typedef unsigned short	 u_short;
+typedef unsigned char	 u_char;
+typedef unsigned int     uint32_t;
+typedef int              int32_t;
+#if _INTEGRAL_MAX_BITS >= 64
+typedef unsigned __int64 uint64_t;
+typedef __int64          int64_t;
+#endif
+#endif /* KRB5_SYSTYPES__ */
+
+#define MAXHOSTNAMELEN  512
+#ifndef MAXPATHLEN
+#define MAXPATHLEN      256            /* Also for Windows temp files */
+#endif
+
+#define HAVE_NETINET_IN_H
+#define MSDOS_FILESYSTEM
+#define HAVE_STRING_H 
+#define HAVE_SRAND
+#define HAVE_ERRNO
+#define HAVE_STRDUP
+#define HAVE_GETADDRINFO
+#define HAVE_GETNAMEINFO
+#define NO_USERID
+#define NO_PASSWORD
+#define HAVE_STRERROR
+#define SYS_ERRLIST_DECLARED
+/* if __STDC_VERSION__ >= 199901L this shouldn't be needed */
+#define inline __inline
+#define KRB5_USE_INET6
+#define NEED_INSIXADDR_ANY
+#define ENABLE_THREADS
+
+#define WM_KERBEROS5_CHANGED "Kerberos5 Changed"
+#ifdef KRB4
+#define WM_KERBEROS_CHANGED "Kerberos Changed"
+#endif
+
+/* Kerberos Windows initialization file */
+#define KERBEROS_INI    "kerberos.ini"
+#ifdef CYGNUS
+#define KERBEROS_HLP    "kerbnet.hlp"
+#else
+#define KERBEROS_HLP	"krb5clnt.hlp"
+#endif
+#define INI_DEFAULTS    "Defaults"
+#define   INI_USER        "User"          /* Default user */
+#define   INI_INSTANCE    "Instance"      /* Default instance */
+#define   INI_REALM       "Realm"         /* Default realm */
+#define   INI_POSITION    "Position"
+#define   INI_OPTIONS     "Options"
+#define   INI_DURATION    "Duration"   /* Ticket duration in minutes */
+#define INI_EXPIRATION  "Expiration" /* Action on expiration (alert or beep) */
+#define   INI_ALERT       "Alert"
+#define   INI_BEEP        "Beep"
+#define   INI_FILES       "Files"
+#ifdef KRB4
+#define   INI_KRB_CONF    "krb.conf"     /* Location of krb.conf file */
+#define   DEF_KRB_CONF    "krb.conf"      /* Default name for krb.conf file */
+#else
+#define INI_KRB5_CONF   "krb5.ini"	/* From k5-config.h */
+#define INI_KRB_CONF    INI_KRB5_CONF	/* Location of krb.conf file */
+#define DEF_KRB_CONF    INI_KRB5_CONF	/* Default name for krb.conf file */
+#define INI_TICKETOPTS  "TicketOptions" /* Ticket options */
+#define   INI_FORWARDABLE  "Forwardable" /* get forwardable tickets */
+#define INI_KRB_CCACHE  "krb5cc"       	/* From k5-config.h */
+#endif
+#define INI_KRB_REALMS  "krb.realms"    /* Location of krb.realms file */
+#define DEF_KRB_REALMS  "krb.realms"    /* Default name for krb.realms file */
+#define INI_RECENT_LOGINS "Recent Logins"    
+#define INI_LOGIN       "Login"
+
+#define HAS_VOID_TYPE
+#define HAVE_STDARG_H
+#define HAVE_SYS_TYPES_H
+#define HAVE_STDLIB_H
+
+/* This controls which encryption routines libcrypto will provide */
+#define PROVIDE_DES_CBC_MD5
+#define PROVIDE_DES_CBC_CRC
+#define PROVIDE_DES_CBC_RAW
+#define PROVIDE_DES_CBC_CKSUM
+#define PROVIDE_CRC32
+#define PROVIDE_RSA_MD4
+#define PROVIDE_RSA_MD5
+/* #define PROVIDE_DES3_CBC_SHA */
+/* #define PROVIDE_DES3_CBC_RAW */
+/* #define PROVIDE_NIST_SHA */
+
+/* Ugly. Microsoft, in stdc mode, doesn't support the low-level i/o
+ * routines directly. Rather, they only export the _<function> version.
+ * The following defines works around this problem. 
+ */
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <fcntl.h>
+#include <io.h>
+#include <process.h>
+
+#ifdef NEED_SYSERROR
+/* Only needed by util/et/error_message.c but let's keep the source clean */
+#define sys_nerr        _sys_nerr
+#define sys_errlist     _sys_errlist
+#endif
+
+/*
+ * Functions with slightly different names on the PC
+ */
+#ifndef strcasecmp
+#define strcasecmp   stricmp
+#endif
+#ifndef strncasecmp
+#define strncasecmp  strnicmp
+#endif
+
+HINSTANCE get_lib_instance(void);
+
+#define GETSOCKNAME_ARG2_TYPE	struct sockaddr
+#define GETSOCKNAME_ARG3_TYPE	size_t
+#define GETPEERNAME_ARG2_TYPE	GETSOCKNAME_ARG2_TYPE
+#define GETPEERNAME_ARG3_TYPE	GETSOCKNAME_ARG3_TYPE
+
+#endif /* !RES_ONLY */
+
+#endif /* _WIN32 */
+
+#define THREEPARAMOPEN(x,y,z) open(x,y,z)
+
+#ifndef KRB5_CALLCONV
+#define KRB5_CALLCONV
+#endif
+
+#ifndef KRB5_CALLCONV_C
+#define KRB5_CALLCONV_C
+#endif
+
+#endif /* _KRB5_WIN_MAC_H */
diff --git a/mechglue/src/kadmin/.Sanitize b/mechglue/src/kadmin/.Sanitize
new file mode 100644
index 000000000..e8c5141f2
--- /dev/null
+++ b/mechglue/src/kadmin/.Sanitize
@@ -0,0 +1,44 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+kpasswd
+ktutil
+v5client
+v5server
+
+Things-to-lose:
+
+v4server
+server
+client
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/kadmin/ChangeLog b/mechglue/src/kadmin/ChangeLog
new file mode 100644
index 000000000..8a0c1cc12
--- /dev/null
+++ b/mechglue/src/kadmin/ChangeLog
@@ -0,0 +1,189 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-04-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't invoke AC_CANONICAL_HOST explicitly,
+	CONFIG_RULES already does it.
+
+2004-02-16  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Invoke KRB5_AC_PRIOCNTL_HACK.
+
+2003-12-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCAL_SUBDIRS): Fix typo in last (undocumented)
+	change.
+
+2003-12-11  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in (DO_ALL): Don't build v4server on v5passwdd
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Call KRB5_AC_NEED_DAEMON instead of checking
+	whether daemon() prototype is needed.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov, config.mk/*: Deleted.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add KRB5_GETSOCKNAME_ARGS
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Test system header files for daemon prototype.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Check for regex.h
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Test for existance of arpa/inet.h
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* configure.in: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-01-20  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* config.mk/netbsd1.def (UTMP_FILE, WTMP_FILE): Update filenames to comply
+		with netbsd system.  (Not actually used by our
+		configuration system, but I'll update the file.)
+		Submitted by ghudson, [krb5-admin/522]
+
+Tue Jan 12 18:26:04 1999  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Define NDBM_PW_CHECK if enable_athena is set to
+	deal with v4kadmind kludge.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Tue Mar  3 10:40:09 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Enable v4 kadmin tests only if athena
+        compatibility is enabled.
+
+Sun Mar  1 21:12:08 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Define S_TOP to contain an absolute pathname
+		to the top of the source tree.
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Move tests from all of kadmin's subdirectories into
+		this configure.in, and make it generate makefiles for all
+		of the subdirectories.
+
+	* Makefile.in: Add a LOCAL_SUBDIRS macro for all subdirectories in
+		the kadmin directory.
+
+Wed Feb 18 15:53:46 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (thisconfigdir): Remove trailing slash.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Nov 13 19:24:36 1996  Tom Yu  <tlyu@mit.edu>
+
+	* testing/Makefile.in (clean): Remove krb5-test-root.
+
+Tue Sep 24 13:29:40 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* configure.in: add testing to subdirs list
+
+Thu Sep 19 08:06:20 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Do not build in v4server if compiling without
+		krb4. 
+
+Wed Sep 11 16:27:04 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* configure.in: no longer build import and export since they
+		are subsumed by kdb5_util.
+
+Tue Sep 10 18:20:51 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: no longer build keytab
+
+Fri Jul 26 15:35:31 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove create
+
+Thu Jul 25 17:24:18 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in (CONFIG_DIRS): added v5passwdd
+
+Fri Jul 12 14:38:30 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in (CONFIG_DIRS): ktutil is still useful
+ 	functionality; add it back to the build.
+
+	* config.mk/architecture: add uname test for NetBSD
+	* config.mk/netbsd1.def: added
+
+Wed Jul 10 16:27:11 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: kdbkeys is no longer necessary.
+	* configure.in (CONFIG_DIRS): added dbutil
+
+Mon Jul  8 16:39:36 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* config.mk/template, config.mk/site.def, config.mk/rules: Add
+	SITEMAKEFILES to specify -f Makefile.ov, add .ct default rule.
+
+Thu Aug 24 19:21:14 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Add ktutil directory
+
+Thu Aug 17 22:44:13 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* configure.in: Build ktutil now.
+
+Fri Jul 7 15:59:15 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS.
+
+Fri Jun  9 19:05:26 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Tue May 9 15:58:33 EDT 1995	Paul Park	(pjpark@mit.edu)
+	Add v5client.
+
+
+Wed Apr 26 16:00:00 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	Added new kpasswd and v5server directories for new protocol based
+	administrative functions.
+
diff --git a/mechglue/src/kadmin/Makefile.in b/mechglue/src/kadmin/Makefile.in
new file mode 100644
index 000000000..3be9036a8
--- /dev/null
+++ b/mechglue/src/kadmin/Makefile.in
@@ -0,0 +1,8 @@
+thisconfigdir=.
+myfulldir=kadmin
+mydir=.
+BUILDTOP=$(REL)..
+LOCAL_SUBDIRS = cli dbutil passwd ktutil server testing
+
+all::
+
diff --git a/mechglue/src/kadmin/cli/ChangeLog b/mechglue/src/kadmin/cli/ChangeLog
new file mode 100644
index 000000000..8c2cda9fc
--- /dev/null
+++ b/mechglue/src/kadmin/cli/ChangeLog
@@ -0,0 +1,524 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* kadmin.c: Include errno.h instead of k5-int.h.
+	* keytab.c: Include errno.h.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KDB_DEP_LIB): Use DL_LIB and THREAD_LINKOPTS
+	instead of explicitly using -ldl and -lpthread.
+
+	Novell merge.
+	* Makefile.in:
+	* kadmin.c:
+
+2005-02-11  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c (kadmin_startup): New flag "-N" to prevent fallback to
+	AUTH_GSSAPI.
+
+	* kadmin.M: Describe "-O" and "-N" flags.
+
+2004-09-17  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install): Use $(INSTALL_SCRIPT) for scripts.
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* kadmin.M: Put space after ".B" directive.
+
+2004-06-24  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c (kadmin_startup): Use host-based service name from
+	kadm5_get_admin_service_name() for SEAM compatibility when old
+	AUTH_GSSAPI not requested.
+
+2004-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c (kadmin_startup): Add option to force old AUTH_GSSAPI
+	flavor.
+
+2004-05-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* kadmin.h, keytab.c: Remove inclusion of k5-int.h.
+
+2004-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* getdate.y: Include krb5.h and kadmin.h.
+	(get_date): Drop second argument; always use NULL.
+	* kadmin.h: Include time.h and/or sys/time.h.
+	(get_date): Declare.
+	* kadmin.c (get_date): Don't declare.
+	(kadmin_parse_princ_args, kadmin_parse_policy_args): Drop second
+	argument to get_date.
+	* Makefile.in (LOCALINCLUDES): Define.
+
+2003-08-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* getdate.y (bcopy): Don't bother with HAVE_BCOPY and HAVE_MEMCPY
+	tests; always define the macro if it's not already defined.
+
+2003-06-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* kadmin.c (strdate): Increase size of buffer to 40.  Use sizeof
+	for length passed to strftime.
+
+2003-05-19  Sam Hartman  <hartmans@mit.edu>
+
+	* kadmin.c (kadmin_startup): Don't register writable keytabs as this is always done by the library now.
+
+2003-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install): Fix typo in k5srvutil.M install rule.
+
+2003-02-06  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (install): Install k5srvutil
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c (kadmin_addprinc, kadmin_cpw): Remove trailing colon,
+	as new implementation of krb5_read_password() appends it.
+
+2002-10-08  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c (quit): Release exclusive lock, if acquired.
+	(kadmin_lock, kadmin_unlock): New functions to call kadm5_lock and
+	kadm5_unlock.
+
+	* kadmin.h: Add kadmin_lock and kadmin_unlock.
+
+	* kadmin_ct.ct: Add lock and unlock commands.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* dump.c: Unused file deleted.
+
+2002-07-29  Jen Selby <jenselby@mit.edu>
+
+	* kadmin.M: corrected documenation of "-k/-t" options.
+	Added documentation for some other options.  Updated the lists
+	of aliases for commands, some command options, and some of
+	the sample output.
+
+2002-06-06  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.M: Remove references to "rename_principal".
+	[pullup from 1-2-2-branch]
+
+2001-10-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* kadmin.c (kadmin_parse_name): Properly advance pointer in
+	certain error cases involving '@'.  Patch from Emily Ratliff,
+	<ratliff@austin.ibm.com>.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* dump.c: Make prototypes unconditional.
+
+2001-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* getdate.y: Provide full prototype for getdate_yylex() and
+	getdate_yyerror(). 
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* getdate.y: Cast argument to isalpha()/isspace()/isdigit() to int.
+
+Mon Feb 26 13:25:50 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* ss_wrapper.c: Include kadmin.h.
+
+	* kadmin.c, keytab.c: Warning cleanup of shadowing variables,
+ 	missing prototypes, assignments within conditionals. variables
+ 	type mismatches.
+
+	* getdate.y: Prototypes in file are for getdate_yylex() and
+ 	getdaye_yyerror() and not yylex()/yyerror().
+
+	* kadmin.h: New header file with ss callback prototypes and global
+ 	variables.
+
+	
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* kadmin.c (kadmin_cpw): Argument to krb5_read_password changed to
+	unsigned int.
+
+2000-10-16  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c (strdur): Print negative durations somewhat (!)
+	sanely.
+	(kadmin_startup): Call krb5_klog_init() to avoid coredumping if
+	kadm5_init() logs something via krb5_klog_syslog().
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* kadmin.c (kadmin_getpol): Change format strings from %d to %ld
+	to match the policy types which are longs.
+
+	* getdate.y: Include stdlib.h if present on system.
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* ss_wrapper.c (main): ss_listen() takes only one argument
+
+2000-06-09  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.M: Update to reflect new -e and -keepold flags.
+
+2000-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* kadmin.c (kadmin_startup): Don't pass keytab_name to printf if
+	it's NULL.
+
+2000-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* strftime.c: Replace with a copy of the one from libkrb5, which
+	isn't under GPL.
+
+2000-03-01  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c (kadmin_cpw): Initialize ks_tuple to NULL.
+
+2000-02-27  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c (kadmin_parse_princ_args): Remove keepold argument to
+	match new kadm5 library.
+	(kadmin_addprinc_usage): Remove keepold argument from usage
+	summary.
+	(kadmin_addprinc): Update kadm5 calls to no longer use keepold.
+
+2000-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* kadmin.c (kadmin_modprinc): Complain if -pw option is given,
+	since it's ignored.  Patch from Matt Crawford.
+
+2000-02-18  Tom Yu  <tlyu@mit.edu>
+
+	* keytab.c (add_usage): Update usage message.
+	(kadmin_keytab_add): Update to deal with explicit keysalt lists.
+	(add_principal): Update to deal with explicit keysalt lists.
+
+	* kadmin.c (kadmin_cpw): Add support for new api.
+	(kadmin_parse_princ_args): Add support for new api, particularly
+	-keepold to keep old keys around and -e to explicitly specify
+	key-salt tuples.
+	(kadmin_addprinc_usage): Update usage accordingly.
+	(kadmin_addprinc): Add support for new api.
+	(kadmin_modprinc): Update to call new parse_princ_args reasonably.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* getdate.y (Convert): Check for year past 2038.
+	(RelativeMonth): Check for error return from Convert.
+	(get_date): Check for error return from RelativeMonth.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-26  Marc Horowitz  <marc@mit.edu>
+
+	* keytab.c (etype_string): replace the hardwired table with a call
+	to krb5_enctype_to_string()
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 18 15:54:11 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash.  Fix up BUILDTOP for new
+	conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Oct  7 19:57:43 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* kadmin.c (quit): Call krb5_free_context.
+
+Thu Sep 18 17:54:10 1997  Tom Yu  <tlyu@mit.edu>
+
+	* memmove.c: Replace USE_STRING_H with something more sane.
+
+Fri Jul 25 15:45:24 1997  Tom Yu  <tlyu@mit.edu>
+
+	* dump.c: Update to new kdb API.
+
+Fri Jun 27 17:37:07 1997  Tom Yu  <tlyu@mit.edu>
+
+	* keytab.c (add_principal): Don't call kadm5_free_key_data; that's
+	Just Wrong here and was causing coredumps.
+
+Wed May 28 13:33:40 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* keytab.c (add_principal): use kadm5_free_key_data
+
+Tue Feb  4 20:56:47 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Tue Dec 17 17:08:04 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* kadmin.c (kadmin_startup): Do not compare an int to NULL.
+
+Tue Dec  3 15:39:11 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.c (kadmin_addprinc): print warning/notice about no policy
+ 	and default policy [krb5-admin/252]
+
+Thu Dec  5 19:30:22 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.M: Missed a ref to /krb5. [279]
+	
+	* kadmin.M: Change example to no longer use /krb5. [PR 279]
+
+	* kadmin.M: v5srvtab -> krb5.keytab [PR 279]
+
+	* kadmin.c (DEFAULT_KEYTAB): v5srvtab -> krb5.keytab [PR 278]
+
+Wed Nov 13 14:29:02 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (clean-unix): Remove getdate.c and kadmin_ct.c.
+
+	* keytab.c (process_keytab): Note that krb5_defkeyname is an
+	internal interface.
+
+	* kadmin.c (kadmin_startup): Note that krb5_defkeyname is an
+	internal interface.
+	
+	* kadmin.c, keytab.c: Revert kt_default_name changes.
+
+Tue Nov 12 22:05:26 1996  Tom Yu  <tlyu@mit.edu>
+
+	* keytab.c (process_keytab): Retrieve *keytab_str using
+	krb5_kt_default_name() to avoid global variable nastiness.
+
+	* kadmin.c (kadmin_startup): Use krb5_kt_set_default_name to
+	change the default keytab name rather than assigning to a library
+	global variable.
+
+Thu Nov  7 20:52:39 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Remove spurious WITH_CCOPTS and KRB_INCLUDE.
+
+Fri Nov  1 11:52:52 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.c (kadmin_cpw): fix typo [krb5-admin/139]
+
+Wed Oct 30 17:35:19 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.M: update ktadd's description [krb5-doc/137]
+
+Fri Oct 18 13:47:01 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.c (kadmin_addprinc): use a studly temporary password when
+ 	creating a principal with a random key (no, the security of this
+ 	operation does not depend on the secrecy of the password)
+ 	[krb5-admin/115]
+ 
+	* getdate.y: remove military timezones and plain integeres as part
+ 	of date specifications, to reduce confusion by redundancy
+ 	[krb5-admin/15]
+
+Wed Oct  9 15:23:51 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.c (kadmin_addprinc): add "default" policy behavior;
+ 	delete kadmin_renprinc entirely, since it is no longer supported
+ 	by the api and there is no ss command for it anyway
+
+	* kadmin.M: document "default" policy behavior.  [krb5-admin/84]
+
+Fri Oct  4 16:37:30 1996  Kevin L Mitchell  <klmitch@mit.edu>
+
+	* kadmin.c (kadmin_renprinc): Changed newcanon to oldcanon in the
+		"make sure blah is removed from acls before reusing"
+		message
+
+Wed Sep 25 16:22:12 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* getdate.y: add lots of comments
+
+Tue Sep 10 00:48:38 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kadmin.c (kadmin_startup): -m doesn't take an argument.
+
+Tue Sep 10 14:15:28 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.M: remove ".so man1/header.doc"
+
+Mon Sep  9 11:14:23 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kadmin.c: Fix the usage messages to state -randkey, not
+ 		-randpass, to conform with what the code (and man pages)
+ 		use.
+
+Thu Sep  5 20:15:12 1996  Ezra Peisach  (epeisach@mit.edu)
+ 
+  	* getdate.y: Declare a private copy of struct timeb (no-one uses
+		the extra return structure in our tree). This works around
+		a bug with Sun's cc cimpiler, and pragma incompatibility
+		in its header files.
+
+Tue Sep  3 22:10:49 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (install): Fixed typo: ($PROG) -> $(PROG)
+
+Thu Aug 29 16:08:10 1996  Jeff Bigler  <jcb@mit.edu>
+
+	* Makefile.in (install): added man pages for kadmin and
+	kadmin.local
+
+Fri Aug 23 14:16:18 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: Use shared libaries if present.
+
+Fri Aug 23 14:47:55 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.c: add newlines to "invalid date spec" msg
+
+	* getdate.y: add "never" as a valid date specification
+
+Wed Aug 21 14:10:36 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.c: memset policy structures before passing them to
+ 	kadm5_*_policy functions, so stack garbage >=2^32 doesn't end up
+ 	in a long field and confuse xdr
+
+Mon Aug 19 12:11:27 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.c: prints absolute 0 dates as "[never]", print mod date
+ 	and by on one line, fix coredump on getprinc -terse
+
+	* Makefile.in: add target for datetest
+
+	* getdate.y: accept dates after 1999
+
+Fri Aug 16 13:46:31 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.c: update addprinc and modprinc usage
+
+Thu Aug 15 20:56:13 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: remove check for -ldbm and -lndbm (old old
+		garbage).
+
+Mon Aug 12 20:20:11 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kadmin.1: Remove rename_principal. Add -maxrenewlife.
+
+	* kadmin.c (kadmin_getprinc): Display the maximum renewable life
+			field. 
+		(kadmin_parse_princ_args): Add -maxrenwlife as a settable
+			field. 
+
+Mon Aug 12 11:47:31 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin_ct.ct: fix typo in add_principal
+
+Sun Aug 11 16:29:27 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* keytab.c: reset static global "quiet" each time; don't print
+ 	whoami on normal status messages
+
+Tue Aug  6 15:18:49 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin_ct.ct: get_{principals,policies} -> list_*; remove
+ 	rename_principal
+
+	* kadmin.c: remove unsupported -salt option from ank usage
+
+Fri Aug  2 13:13:24 1996  Barry Jaspan  <bjaspan@DUN-DUN-NOODLES>
+
+	* keytab.c (add_principal): free_keyblock -> free_keyblock_contents
+
+Wed Jul 31 14:20:50 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.c: Remove delcaration for getpwuid(); already declared in
+		pwd.h.
+
+Fri Jul 26 14:26:08 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (install): Actually install kadmin.local.  (Or
+ 		rather, don't install kadmin.local as kadmin, and then
+ 		reinstall kadmin on top of kadmin.)
+
+Wed Jul 24 00:27:59 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: Don't replace setenv as it isn't used. 
+
+Thu Jul 25 12:11:49 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kadmin.c (quit): Return zero so that we return the proper exit
+		status. 
+		(kadmin_getprivs): Declare function as returning void
+
+Wed Jul 24 14:18:13 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (all): Use $(LD) instead of $(CC) for link stage.
+
+	* dump.c (dump_db): Zero out kadm5_principal_ent_rec structure
+		before passing to rpc code. 
+
+	* kadmin.c (kadmin_addprinc, kadmin_getprinc, kadmin_modprinc):
+		   Zero out structures before passing to rpc code.
+
+
+Tue Jul 23 17:02:04 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in: add dependency for kadmin_ct.o
+
+Fri Jul 19 16:10:39 1996  Marc Horowitz  <marc@mit.edu>
+
+	* ss_wrapper.c (main): ss_execute_line was being called with three
+ 	args.  There are only two, so no error was ever being returned.
+
+Thu Jul 18 19:14:51 1996  Marc Horowitz  <marc@mit.edu>
+
+	* attic/configure.in: removed SS_RULES
+
+	* keytab.c (etype_string): ifdef out des3 reference
+
+	* configure.in: removed SS_RULES
+
+Mon Jul 15 16:56:43 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.1, keytab.c (kadmin_keytab_add): change ktadd usage to
+ 	accept -glob
+
+Tue Jul  9 16:15:46 1996  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in: complete rewrite
+	* configure.in: add the necessary USE_*_LIBRARY macros
+	
+Mon Jul  8 16:45:20 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadmin.1: Update man page for kadm5 changes and functionality.
+	
+
diff --git a/mechglue/src/kadmin/cli/Makefile.in b/mechglue/src/kadmin/cli/Makefile.in
new file mode 100644
index 000000000..ecde8640b
--- /dev/null
+++ b/mechglue/src/kadmin/cli/Makefile.in
@@ -0,0 +1,39 @@
+thisconfigdir=./..
+myfulldir=kadmin/cli
+mydir=cli
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+KDB_DEP_LIB=$(DL_LIB) $(THREAD_LINKOPTS)
+
+PROG = kadmin
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab.o
+
+LOCALINCLUDES=-I$(srcdir)
+
+all:: $(PROG).local $(PROG)
+
+$(PROG).local: $(OBJS) $(SS_DEPLIB) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $(PROG).local $(OBJS) $(SS_LIB) $(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS)
+
+$(PROG): $(OBJS) $(SS_DEPLIB) $(KADMCLNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $(PROG) $(OBJS) $(SS_LIB) $(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
+
+kadmin_ct.o: kadmin_ct.c
+
+install::
+	$(INSTALL_PROGRAM) $(PROG).local ${DESTDIR}$(ADMIN_BINDIR)/$(PROG).local
+	$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+	$(INSTALL_SCRIPT) $(srcdir)/k5srvutil.sh ${DESTDIR}$(ADMIN_BINDIR)/k5srvutil
+	$(INSTALL_DATA) $(srcdir)/k5srvutil.M ${DESTDIR}$(ADMIN_MANDIR)/k5srvutil.8
+	$(INSTALL_DATA) $(srcdir)/$(PROG).M ${DESTDIR}$(ADMIN_MANDIR)/$(PROG).8
+	$(INSTALL_DATA) $(srcdir)/$(PROG).local.M ${DESTDIR}$(ADMIN_MANDIR)/$(PROG).local.8
+
+clean::
+	$(RM) $(PROG).local $(PROG) $(OBJS)
+clean-unix::
+	$(RM) getdate.c kadmin_ct.c
+
+# for testing getdate.y
+datetest: getdate.c
+	$(CC) -o datetest $(ALL_CFLAGS) $(LDFLAGS) $(LDARGS) -DTEST getdate.c
diff --git a/mechglue/src/kadmin/cli/getdate.y b/mechglue/src/kadmin/cli/getdate.y
new file mode 100644
index 000000000..ce1ca5e34
--- /dev/null
+++ b/mechglue/src/kadmin/cli/getdate.y
@@ -0,0 +1,1033 @@
+%{
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**  send any email to Rich.
+**
+**  This grammar has nine shift/reduce conflicts.
+**
+**  This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+#include <string.h>
+
+/* Since the code of getdate.y is not included in the Emacs executable
+   itself, there is no need to #define static in this file.  Even if
+   the code were included in the Emacs executable, it probably
+   wouldn't do any harm to #undef it here; this will only cause
+   problems if we try to write to a static variable, which I don't
+   think this code needs to do.  */
+#ifdef emacs
+#undef static
+#endif
+
+/* The following block of alloca-related preprocessor directives is here
+   solely to allow compilation by non GNU-C compilers of the C parser
+   produced from this file by old versions of bison.  Newer versions of
+   bison include a block similar to this one in bison.simple.  */
+
+#ifdef __GNUC__
+#undef alloca
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX /* for Bison */
+ #pragma alloca
+#else
+void *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if defined(HAVE_STDLIB_H)
+#include <stdlib.h>
+#endif
+
+/* The code at the top of get_date which figures out the offset of the
+   current time zone checks various CPP symbols to see if special
+   tricks are need, but defaults to using the gettimeofday system call.
+   Include <sys/time.h> if that will be used.  */
+
+#if	defined(vms)
+
+#include <types.h>
+#include <time.h>
+
+#else
+
+#include <sys/types.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef timezone
+#undef timezone /* needed for sgi */
+#endif
+
+/*
+** We use the obsolete `struct my_timeb' as part of our interface!
+** Since the system doesn't have it, we define it here;
+** our callers must do likewise.
+*/
+struct my_timeb {
+    time_t		time;		/* Seconds since the epoch	*/
+    unsigned short	millitm;	/* Field not used		*/
+    short		timezone;	/* Minutes west of GMT		*/
+    short		dstflag;	/* Field not used		*/
+};
+#endif	/* defined(vms) */
+
+#if defined (STDC_HEADERS) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+   That loses on systems that don't provide the function, so we have
+   to redefine it here.  */
+#ifndef bcopy
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+extern struct tm	*gmtime();
+extern struct tm	*localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+static int getdate_yylex (void);
+static int getdate_yyerror (char *);
+
+
+#define EPOCH		1970
+#define EPOCH_END	2038 /* assumes 32 bits */
+#define HOUR(x)		((time_t)(x) * 60)
+#define SECSPERDAY	(24L * 60L * 60L)
+
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    char	*name;
+    int		type;
+    time_t	value;
+} TABLE;
+
+
+/*
+**  Daylight-savings mode:  on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+    DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static char	*yyInput;
+static DSTMODE	yyDSTmode;
+static time_t	yyDayOrdinal;
+static time_t	yyDayNumber;
+static int	yyHaveDate;
+static int	yyHaveDay;
+static int	yyHaveRel;
+static int	yyHaveTime;
+static int	yyHaveZone;
+static time_t	yyTimezone;
+static time_t	yyDay;
+static time_t	yyHour;
+static time_t	yyMinutes;
+static time_t	yyMonth;
+static time_t	yySeconds;
+static time_t	yyYear;
+static MERIDIAN	yyMeridian;
+static time_t	yyRelMonth;
+static time_t	yyRelSeconds;
+
+%}
+
+%union {
+    time_t		Number;
+    enum _MERIDIAN	Meridian;
+}
+
+%token	tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token	tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST tNEVER
+
+%type	<Number>	tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type	<Meridian>	tMERIDIAN o_merid
+
+%%
+
+spec	: /* NULL */
+	| spec item
+        | tNEVER {
+	    yyYear = 1970;
+	    yyMonth = 1;
+	    yyDay = 1;
+	    yyHour = yyMinutes = yySeconds = 0;
+	    yyDSTmode = DSToff;
+	    yyTimezone = 0; /* gmt */
+	    yyHaveDate++;
+        }
+	;
+
+item	: time {
+	    yyHaveTime++;
+	}
+	| zone {
+	    yyHaveZone++;
+	}
+	| date {
+	    yyHaveDate++;
+	}
+	| day {
+	    yyHaveDay++;
+	}
+	| rel {
+	    yyHaveRel++;
+	}
+	;
+
+time	: tUNUMBER tMERIDIAN {
+	    yyHour = $1;
+	    yyMinutes = 0;
+	    yySeconds = 0;
+	    yyMeridian = $2;
+	}
+	| tUNUMBER ':' tUNUMBER o_merid {
+	    yyHour = $1;
+	    yyMinutes = $3;
+	    yySeconds = 0;
+	    yyMeridian = $4;
+	}
+	| tUNUMBER ':' tUNUMBER tSNUMBER {
+	    yyHour = $1;
+	    yyMinutes = $3;
+	    yyMeridian = MER24;
+	    yyDSTmode = DSToff;
+	    yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+	}
+	| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+	    yyHour = $1;
+	    yyMinutes = $3;
+	    yySeconds = $5;
+	    yyMeridian = $6;
+	}
+	| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+	    yyHour = $1;
+	    yyMinutes = $3;
+	    yySeconds = $5;
+	    yyMeridian = MER24;
+	    yyDSTmode = DSToff;
+	    yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+	}
+	;
+
+zone	: tZONE {
+	    yyTimezone = $1;
+	    yyDSTmode = DSToff;
+	}
+	| tDAYZONE {
+	    yyTimezone = $1;
+	    yyDSTmode = DSTon;
+	}
+	|
+	  tZONE tDST {
+	    yyTimezone = $1;
+	    yyDSTmode = DSTon;
+	}
+	;
+
+day	: tDAY {
+	    yyDayOrdinal = 1;
+	    yyDayNumber = $1;
+	}
+	| tDAY ',' {
+	    yyDayOrdinal = 1;
+	    yyDayNumber = $1;
+	}
+	| tUNUMBER tDAY {
+	    yyDayOrdinal = $1;
+	    yyDayNumber = $2;
+	}
+	;
+
+date	: tUNUMBER '/' tUNUMBER {
+	    yyMonth = $1;
+	    yyDay = $3;
+	}
+	| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+	    yyMonth = $1;
+	    yyDay = $3;
+	    yyYear = $5;
+	}
+	| tUNUMBER tSNUMBER tSNUMBER {
+	    /* ISO 8601 format.  yyyy-mm-dd.  */
+	    yyYear = $1;
+	    yyMonth = -$2;
+	    yyDay = -$3;
+	}
+	| tUNUMBER tMONTH tSNUMBER {
+	    /* e.g. 17-JUN-1992.  */
+	    yyDay = $1;
+	    yyMonth = $2;
+	    yyYear = -$3;
+	}
+	| tMONTH tUNUMBER {
+	    yyMonth = $1;
+	    yyDay = $2;
+	}
+	| tMONTH tUNUMBER ',' tUNUMBER {
+	    yyMonth = $1;
+	    yyDay = $2;
+	    yyYear = $4;
+	}
+	| tUNUMBER tMONTH {
+	    yyMonth = $2;
+	    yyDay = $1;
+	}
+	| tUNUMBER tMONTH tUNUMBER {
+	    yyMonth = $2;
+	    yyDay = $1;
+	    yyYear = $3;
+	}
+	;
+
+rel	: relunit tAGO {
+	    yyRelSeconds = -yyRelSeconds;
+	    yyRelMonth = -yyRelMonth;
+	}
+	| relunit
+	;
+
+relunit	: tUNUMBER tMINUTE_UNIT {
+	    yyRelSeconds += $1 * $2 * 60L;
+	}
+	| tSNUMBER tMINUTE_UNIT {
+	    yyRelSeconds += $1 * $2 * 60L;
+	}
+	| tMINUTE_UNIT {
+	    yyRelSeconds += $1 * 60L;
+	}
+	| tSNUMBER tSEC_UNIT {
+	    yyRelSeconds += $1;
+	}
+	| tUNUMBER tSEC_UNIT {
+	    yyRelSeconds += $1;
+	}
+	| tSEC_UNIT {
+	    yyRelSeconds++;
+	}
+	| tSNUMBER tMONTH_UNIT {
+	    yyRelMonth += $1 * $2;
+	}
+	| tUNUMBER tMONTH_UNIT {
+	    yyRelMonth += $1 * $2;
+	}
+	| tMONTH_UNIT {
+	    yyRelMonth += $1;
+	}
+	;
+
+o_merid	: /* NULL */ {
+	    $$ = MER24;
+	}
+	| tMERIDIAN {
+	    $$ = $1;
+	}
+	;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",	tMONTH,  1 },
+    { "february",	tMONTH,  2 },
+    { "march",		tMONTH,  3 },
+    { "april",		tMONTH,  4 },
+    { "may",		tMONTH,  5 },
+    { "june",		tMONTH,  6 },
+    { "july",		tMONTH,  7 },
+    { "august",		tMONTH,  8 },
+    { "september",	tMONTH,  9 },
+    { "sept",		tMONTH,  9 },
+    { "october",	tMONTH, 10 },
+    { "november",	tMONTH, 11 },
+    { "december",	tMONTH, 12 },
+    { "sunday",		tDAY, 0 },
+    { "monday",		tDAY, 1 },
+    { "tuesday",	tDAY, 2 },
+    { "tues",		tDAY, 2 },
+    { "wednesday",	tDAY, 3 },
+    { "wednes",		tDAY, 3 },
+    { "thursday",	tDAY, 4 },
+    { "thur",		tDAY, 4 },
+    { "thurs",		tDAY, 4 },
+    { "friday",		tDAY, 5 },
+    { "saturday",	tDAY, 6 },
+    { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",		tMONTH_UNIT,	12 },
+    { "month",		tMONTH_UNIT,	1 },
+    { "fortnight",	tMINUTE_UNIT,	14 * 24 * 60 },
+    { "week",		tMINUTE_UNIT,	7 * 24 * 60 },
+    { "day",		tMINUTE_UNIT,	1 * 24 * 60 },
+    { "hour",		tMINUTE_UNIT,	60 },
+    { "minute",		tMINUTE_UNIT,	1 },
+    { "min",		tMINUTE_UNIT,	1 },
+    { "second",		tSEC_UNIT,	1 },
+    { "sec",		tSEC_UNIT,	1 },
+    { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",	tMINUTE_UNIT,	1 * 24 * 60 },
+    { "yesterday",	tMINUTE_UNIT,	-1 * 24 * 60 },
+    { "today",		tMINUTE_UNIT,	0 },
+    { "now",		tMINUTE_UNIT,	0 },
+    { "last",		tUNUMBER,	-1 },
+    { "this",		tMINUTE_UNIT,	0 },
+    { "next",		tUNUMBER,	2 },
+    { "first",		tUNUMBER,	1 },
+/*  { "second",		tUNUMBER,	2 }, */
+    { "third",		tUNUMBER,	3 },
+    { "fourth",		tUNUMBER,	4 },
+    { "fifth",		tUNUMBER,	5 },
+    { "sixth",		tUNUMBER,	6 },
+    { "seventh",	tUNUMBER,	7 },
+    { "eighth",		tUNUMBER,	8 },
+    { "ninth",		tUNUMBER,	9 },
+    { "tenth",		tUNUMBER,	10 },
+    { "eleventh",	tUNUMBER,	11 },
+    { "twelfth",	tUNUMBER,	12 },
+    { "ago",		tAGO,		1 },
+    { "never",		tNEVER,		0 },
+    { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",	tZONE,     HOUR( 0) },	/* Greenwich Mean */
+    { "ut",	tZONE,     HOUR( 0) },	/* Universal (Coordinated) */
+    { "utc",	tZONE,     HOUR( 0) },
+    { "wet",	tZONE,     HOUR( 0) },	/* Western European */
+    { "bst",	tDAYZONE,  HOUR( 0) },	/* British Summer */
+    { "wat",	tZONE,     HOUR( 1) },	/* West Africa */
+    { "at",	tZONE,     HOUR( 2) },	/* Azores */
+#if	0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",	tZONE,     HOUR( 3) },	/* Brazil Standard */
+    { "gst",	tZONE,     HOUR( 3) },	/* Greenland Standard */
+#endif
+#if 0
+    { "nft",	tZONE,     HOUR(3.5) },	/* Newfoundland */
+    { "nst",	tZONE,     HOUR(3.5) },	/* Newfoundland Standard */
+    { "ndt",	tDAYZONE,  HOUR(3.5) },	/* Newfoundland Daylight */
+#endif
+    { "ast",	tZONE,     HOUR( 4) },	/* Atlantic Standard */
+    { "adt",	tDAYZONE,  HOUR( 4) },	/* Atlantic Daylight */
+    { "est",	tZONE,     HOUR( 5) },	/* Eastern Standard */
+    { "edt",	tDAYZONE,  HOUR( 5) },	/* Eastern Daylight */
+    { "cst",	tZONE,     HOUR( 6) },	/* Central Standard */
+    { "cdt",	tDAYZONE,  HOUR( 6) },	/* Central Daylight */
+    { "mst",	tZONE,     HOUR( 7) },	/* Mountain Standard */
+    { "mdt",	tDAYZONE,  HOUR( 7) },	/* Mountain Daylight */
+    { "pst",	tZONE,     HOUR( 8) },	/* Pacific Standard */
+    { "pdt",	tDAYZONE,  HOUR( 8) },	/* Pacific Daylight */
+    { "yst",	tZONE,     HOUR( 9) },	/* Yukon Standard */
+    { "ydt",	tDAYZONE,  HOUR( 9) },	/* Yukon Daylight */
+    { "hst",	tZONE,     HOUR(10) },	/* Hawaii Standard */
+    { "hdt",	tDAYZONE,  HOUR(10) },	/* Hawaii Daylight */
+    { "cat",	tZONE,     HOUR(10) },	/* Central Alaska */
+    { "ahst",	tZONE,     HOUR(10) },	/* Alaska-Hawaii Standard */
+    { "nt",	tZONE,     HOUR(11) },	/* Nome */
+    { "idlw",	tZONE,     HOUR(12) },	/* International Date Line West */
+    { "cet",	tZONE,     -HOUR(1) },	/* Central European */
+    { "met",	tZONE,     -HOUR(1) },	/* Middle European */
+    { "mewt",	tZONE,     -HOUR(1) },	/* Middle European Winter */
+    { "mest",	tDAYZONE,  -HOUR(1) },	/* Middle European Summer */
+    { "swt",	tZONE,     -HOUR(1) },	/* Swedish Winter */
+    { "sst",	tDAYZONE,  -HOUR(1) },	/* Swedish Summer */
+    { "fwt",	tZONE,     -HOUR(1) },	/* French Winter */
+    { "fst",	tDAYZONE,  -HOUR(1) },	/* French Summer */
+    { "eet",	tZONE,     -HOUR(2) },	/* Eastern Europe, USSR Zone 1 */
+    { "bt",	tZONE,     -HOUR(3) },	/* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",	tZONE,     -HOUR(3.5) },/* Iran */
+#endif
+    { "zp4",	tZONE,     -HOUR(4) },	/* USSR Zone 3 */
+    { "zp5",	tZONE,     -HOUR(5) },	/* USSR Zone 4 */
+#if 0
+    { "ist",	tZONE,     -HOUR(5.5) },/* Indian Standard */
+#endif
+    { "zp6",	tZONE,     -HOUR(6) },	/* USSR Zone 5 */
+#if	0
+    /* For completeness.  NST is also Newfoundland Stanard, and SST is
+     * also Swedish Summer. */
+    { "nst",	tZONE,     -HOUR(6.5) },/* North Sumatra */
+    { "sst",	tZONE,     -HOUR(7) },	/* South Sumatra, USSR Zone 6 */
+#endif	/* 0 */
+    { "wast",	tZONE,     -HOUR(7) },	/* West Australian Standard */
+    { "wadt",	tDAYZONE,  -HOUR(7) },	/* West Australian Daylight */
+#if 0
+    { "jt",	tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",	tZONE,     -HOUR(8) },	/* China Coast, USSR Zone 7 */
+    { "jst",	tZONE,     -HOUR(9) },	/* Japan Standard, USSR Zone 8 */
+    { "kst",	tZONE,     -HOUR(9) },	/* Korean Standard */
+#if 0
+    { "cast",	tZONE,     -HOUR(9.5) },/* Central Australian Standard */
+    { "cadt",	tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+    { "east",	tZONE,     -HOUR(10) },	/* Eastern Australian Standard */
+    { "eadt",	tDAYZONE,  -HOUR(10) },	/* Eastern Australian Daylight */
+    { "gst",	tZONE,     -HOUR(10) },	/* Guam Standard, USSR Zone 9 */
+    { "kdt",	tZONE,     -HOUR(10) },	/* Korean Daylight */
+    { "nzt",	tZONE,     -HOUR(12) },	/* New Zealand */
+    { "nzst",	tZONE,     -HOUR(12) },	/* New Zealand Standard */
+    { "nzdt",	tDAYZONE,  -HOUR(12) },	/* New Zealand Daylight */
+    { "idle",	tZONE,     -HOUR(12) },	/* International Date Line East */
+    {  NULL  }
+};
+
+/* ARGSUSED */
+static int
+yyerror(s)
+    char	*s;
+{
+  return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+    time_t	Hours;
+    time_t	Minutes;
+    time_t	Seconds;
+    MERIDIAN	Meridian;
+{
+    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+	return -1;
+    switch (Meridian) {
+    case MER24:
+	if (Hours < 0 || Hours > 23)
+	    return -1;
+	return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERam:
+	if (Hours < 1 || Hours > 12)
+	    return -1;
+	return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERpm:
+	if (Hours < 1 || Hours > 12)
+	    return -1;
+	return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+    default:
+	abort ();
+    }
+    /* NOTREACHED */
+}
+
+/*
+ * From hh:mm:ss [am|pm] mm/dd/yy [tz], compute and return the number
+ * of seconds since 00:00:00 1/1/70 GMT.
+ */
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+    time_t	Month;
+    time_t	Day;
+    time_t	Year;
+    time_t	Hours;
+    time_t	Minutes;
+    time_t	Seconds;
+    MERIDIAN	Meridian;
+    DSTMODE	DSTmode;
+{
+    static int DaysInMonth[12] = {
+	31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+    };
+    time_t	tod;
+    time_t	Julian;
+    int		i;
+
+    if (Year < 0)
+	Year = -Year;
+    if (Year < 1900)
+	Year += 1900;
+    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+		    ? 29 : 28;
+    if (Year < EPOCH
+	|| Year > EPOCH_END
+	|| Month < 1 || Month > 12
+	/* Lint fluff:  "conversion from long may lose accuracy" */
+	|| Day < 1 || Day > DaysInMonth[(int)--Month])
+	 return -1;
+
+    for (Julian = Day - 1, i = 0; i < Month; i++)
+	Julian += DaysInMonth[i];
+    for (i = EPOCH; i < Year; i++)
+	 Julian += 365 + ((i % 4 == 0) && ((Year % 100 != 0) ||
+					   (Year % 400 == 0)));
+    Julian *= SECSPERDAY;
+    Julian += yyTimezone * 60L;
+    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+	return -1;
+    Julian += tod;
+    if (DSTmode == DSTon
+     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+	Julian -= 60 * 60;
+    return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+    time_t	Start;
+    time_t	Future;
+{
+    time_t	StartDay;
+    time_t	FutureDay;
+
+    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+    time_t	Start;
+    time_t	DayOrdinal;
+    time_t	DayNumber;
+{
+    struct tm	*tm;
+    time_t	now;
+
+    now = Start;
+    tm = localtime(&now);
+    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+    return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+    time_t	Start;
+    time_t	RelMonth;
+{
+    struct tm	*tm;
+    time_t	Month;
+    time_t	Year;
+    time_t	ret;
+
+    if (RelMonth == 0)
+	return 0;
+    tm = localtime(&Start);
+    Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+    Year = Month / 12;
+    Month = Month % 12 + 1;
+    ret = Convert(Month, (time_t)tm->tm_mday, Year,
+		  (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+		  MER24, DSTmaybe);
+    if (ret == -1)
+      return ret;
+    return DSTcorrect(Start, ret);
+}
+
+
+static int
+LookupWord(buff)
+    char		*buff;
+{
+    register char	*p;
+    register char	*q;
+    register const TABLE	*tp;
+    int			i;
+    int			abbrev;
+
+    /* Make it lowercase. */
+    for (p = buff; *p; p++)
+	if (isupper((int) *p))
+	    *p = tolower((int) *p);
+
+    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+	yylval.Meridian = MERam;
+	return tMERIDIAN;
+    }
+    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+	yylval.Meridian = MERpm;
+	return tMERIDIAN;
+    }
+
+    /* See if we have an abbreviation for a month. */
+    if (strlen(buff) == 3)
+	abbrev = 1;
+    else if (strlen(buff) == 4 && buff[3] == '.') {
+	abbrev = 1;
+	buff[3] = '\0';
+    }
+    else
+	abbrev = 0;
+
+    for (tp = MonthDayTable; tp->name; tp++) {
+	if (abbrev) {
+	    if (strncmp(buff, tp->name, 3) == 0) {
+		yylval.Number = tp->value;
+		return tp->type;
+	    }
+	}
+	else if (strcmp(buff, tp->name) == 0) {
+	    yylval.Number = tp->value;
+	    return tp->type;
+	}
+    }
+
+    for (tp = TimezoneTable; tp->name; tp++)
+	if (strcmp(buff, tp->name) == 0) {
+	    yylval.Number = tp->value;
+	    return tp->type;
+	}
+
+    if (strcmp(buff, "dst") == 0) 
+	return tDST;
+
+    for (tp = UnitsTable; tp->name; tp++)
+	if (strcmp(buff, tp->name) == 0) {
+	    yylval.Number = tp->value;
+	    return tp->type;
+	}
+
+    /* Strip off any plural and try the units table again. */
+    i = strlen(buff) - 1;
+    if (buff[i] == 's') {
+	buff[i] = '\0';
+	for (tp = UnitsTable; tp->name; tp++)
+	    if (strcmp(buff, tp->name) == 0) {
+		yylval.Number = tp->value;
+		return tp->type;
+	    }
+	buff[i] = 's';		/* Put back for "this" in OtherTable. */
+    }
+
+    for (tp = OtherTable; tp->name; tp++)
+	if (strcmp(buff, tp->name) == 0) {
+	    yylval.Number = tp->value;
+	    return tp->type;
+	}
+
+    /* Drop out any periods and try the timezone table again. */
+    for (i = 0, p = q = buff; *q; q++)
+	if (*q != '.')
+	    *p++ = *q;
+	else
+	    i++;
+    *p = '\0';
+    if (i)
+	for (tp = TimezoneTable; tp->name; tp++)
+	    if (strcmp(buff, tp->name) == 0) {
+		yylval.Number = tp->value;
+		return tp->type;
+	    }
+
+    return tID;
+}
+
+
+static int
+yylex()
+{
+    register char	c;
+    register char	*p;
+    char		buff[20];
+    int			Count;
+    int			sign;
+
+    for ( ; ; ) {
+	while (isspace((int) *yyInput))
+	    yyInput++;
+
+	c = *yyInput;
+	if (isdigit((int) c) || c == '-' || c == '+') {
+	    if (c == '-' || c == '+') {
+		sign = c == '-' ? -1 : 1;
+		if (!isdigit((int) (*++yyInput)))
+		    /* skip the '-' sign */
+		    continue;
+	    }
+	    else
+		sign = 0;
+	    for (yylval.Number = 0; isdigit((int) (c = *yyInput++)); )
+		yylval.Number = 10 * yylval.Number + c - '0';
+	    yyInput--;
+	    if (sign < 0)
+		yylval.Number = -yylval.Number;
+	    return sign ? tSNUMBER : tUNUMBER;
+	}
+	if (isalpha((int) c)) {
+	    for (p = buff; isalpha((int) (c = *yyInput++)) || c == '.'; )
+		if (p < &buff[sizeof buff - 1])
+		    *p++ = c;
+	    *p = '\0';
+	    yyInput--;
+	    return LookupWord(buff);
+	}
+	if (c != '(')
+	    return *yyInput++;
+	Count = 0;
+	do {
+	    c = *yyInput++;
+	    if (c == '\0')
+		return c;
+	    if (c == '(')
+		Count++;
+	    else if (c == ')')
+		Count--;
+	} while (Count > 0);
+    }
+}
+
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static time_t
+difftm(a, b)
+     struct tm *a, *b;
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  return
+    (
+     (
+      (
+       /* difference in day of year */
+       a->tm_yday - b->tm_yday
+       /* + intervening leap days */
+       +  ((ay >> 2) - (by >> 2))
+       -  (ay/100 - by/100)
+       +  ((ay/100 >> 2) - (by/100 >> 2))
+       /* + difference in years * 365 */
+       +  (time_t)(ay-by) * 365
+       )*24 + (a->tm_hour - b->tm_hour)
+      )*60 + (a->tm_min - b->tm_min)
+     )*60 + (a->tm_sec - b->tm_sec);
+}
+
+/* For get_date extern declaration compatibility check... yuck.  */
+#include <krb5.h>
+#include "kadmin.h"
+
+time_t
+get_date(p)
+    char		*p;
+{
+    struct my_timeb	*now = NULL;
+    struct tm		*tm, gmt;
+    struct my_timeb	ftz;
+    time_t		Start;
+    time_t		tod;
+    time_t		delta;
+
+    yyInput = p;
+    if (now == NULL) {
+        now = &ftz;
+
+	ftz.time = time((time_t *) 0);
+
+	if (! (tm = gmtime (&ftz.time)))
+	    return -1;
+	gmt = *tm;	/* Make a copy, in case localtime modifies *tm.  */
+	ftz.timezone = difftm (&gmt, localtime (&ftz.time)) / 60;
+    }
+
+    tm = localtime(&now->time);
+    yyYear = tm->tm_year;
+    yyMonth = tm->tm_mon + 1;
+    yyDay = tm->tm_mday;
+    yyTimezone = now->timezone;
+    yyDSTmode = DSTmaybe;
+    yyHour = 0;
+    yyMinutes = 0;
+    yySeconds = 0;
+    yyMeridian = MER24;
+    yyRelSeconds = 0;
+    yyRelMonth = 0;
+    yyHaveDate = 0;
+    yyHaveDay = 0;
+    yyHaveRel = 0;
+    yyHaveTime = 0;
+    yyHaveZone = 0;
+
+    /*
+     * When yyparse returns, zero or more of yyHave{Time,Zone,Date,Day,Rel} 
+     * will have been incremented.  The value is number of items of
+     * that type that were found; for all but Rel, more than one is
+     * illegal.
+     *
+     * For each yyHave indicator, the following values are set:
+     *
+     * yyHaveTime:
+     *	yyHour, yyMinutes, yySeconds: hh:mm:ss specified, initialized
+     *				      to zeros above
+     *	yyMeridian: MERam, MERpm, or MER24
+     *	yyTimeZone: time zone specified in minutes
+     *  yyDSTmode: DSToff if yyTimeZone is set, otherwise unchanged
+     *		   (initialized above to DSTmaybe)
+     *
+     * yyHaveZone:
+     *  yyTimezone: as above
+     *  yyDSTmode: DSToff if a non-DST zone is specified, otherwise DSTon
+     *	XXX don't understand interaction with yyHaveTime zone info
+     *
+     * yyHaveDay:
+     *	yyDayNumber: 0-6 for Sunday-Saturday
+     *  yyDayOrdinal: val specified with day ("second monday",
+     *		      Ordinal=2), otherwise 1
+     *
+     * yyHaveDate:
+     *	yyMonth, yyDay, yyYear: mm/dd/yy specified, initialized to
+     *				today above
+     *
+     * yyHaveRel:
+     *	yyRelSeconds: seconds specified with MINUTE_UNITs ("3 hours") or
+     *		      SEC_UNITs ("30 seconds")
+     *  yyRelMonth: months specified with MONTH_UNITs ("3 months", "1
+     *		     year")
+     *
+     * The code following yyparse turns these values into a single
+     * date stamp.
+     */
+    if (yyparse()
+     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+	return -1;
+
+    /*
+     * If an absolute time specified, set Start to the equivalent Unix
+     * timestamp.  Otherwise, set Start to now, and if we do not have
+     * a relatime time (ie: only yyHaveZone), decrement Start to the
+     * beginning of today.
+     *
+     * By having yyHaveDay in the "absolute" list, "next Monday" means
+     * midnight next Monday.  Otherwise, "next Monday" would mean the
+     * time right now, next Monday.  It's not clear to me why the
+     * current behavior is preferred.
+     */
+    if (yyHaveDate || yyHaveTime || yyHaveDay) {
+	Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+		    yyMeridian, yyDSTmode);
+	if (Start < 0)
+	    return -1;
+    }
+    else {
+	Start = now->time;
+	if (!yyHaveRel)
+	    Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+    }
+
+    /*
+     * Add in the relative time specified.  RelativeMonth adds in the
+     * months, accounting for the fact that the actual length of "3
+     * months" depends on where you start counting.
+     *
+     * XXX By having this separate from the previous block, we are
+     * allowing dates like "10:00am 3 months", which means 3 months
+     * from 10:00am today, or even "1/1/99 two days" which means two
+     * days after 1/1/99.
+     *
+     * XXX Shouldn't this only be done if yyHaveRel, just for
+     * thoroughness?
+     */
+    Start += yyRelSeconds;
+    delta = RelativeMonth(Start, yyRelMonth);
+    if (delta == (time_t) -1)
+      return -1;
+    Start += delta;
+
+    /*
+     * Now, if you specified a day of week and counter, add it in.  By
+     * disallowing Date but allowing Time, you can say "5pm next
+     * monday".
+     *
+     * XXX The yyHaveDay && !yyHaveDate restriction should be enforced
+     * above and be able to cause failure.
+     */
+    if (yyHaveDay && !yyHaveDate) {
+	tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+	Start += tod;
+    }
+
+    /* Have to do *something* with a legitimate -1 so it's distinguishable
+     * from the error return value.  (Alternately could set errno on error.) */
+    return Start == -1 ? 0 : Start;
+}
+
+
+#if	defined(TEST)
+
+/* ARGSUSED */
+main(ac, av)
+    int		ac;
+    char	*av[];
+{
+    char	buff[128];
+    time_t	d;
+
+    (void)printf("Enter date, or blank line to exit.\n\t> ");
+    (void)fflush(stdout);
+    while (gets(buff) && buff[0]) {
+	d = get_date(buff, (struct my_timeb *)NULL);
+	if (d == -1)
+	    (void)printf("Bad format - couldn't convert.\n");
+	else
+	    (void)printf("%s", ctime(&d));
+	(void)printf("\t> ");
+	(void)fflush(stdout);
+    }
+    exit(0);
+    /* NOTREACHED */
+}
+#endif	/* defined(TEST) */
diff --git a/mechglue/src/kadmin/cli/k5srvutil.M b/mechglue/src/kadmin/cli/k5srvutil.M
new file mode 100644
index 000000000..b455b7c3c
--- /dev/null
+++ b/mechglue/src/kadmin/cli/k5srvutil.M
@@ -0,0 +1,58 @@
+.\" Copyright 1989, 2003 by the Massachusetts Institute of Technology.
+.\"
+.TH K5SRVUTIL 8
+.SH NAME
+k5srvutil \- host key table (keytab) manipulation utility
+.SH SYNOPSIS
+k5srvutil
+.B operation
+[
+.B \-i 
+] [ 
+.B \-f filename 
+]
+.SH DESCRIPTION
+.I k5srvutil
+allows a system manager to list or change keys currently in his
+keytab or to add new keys to the keytab.
+.PP
+
+Operation must be one of the following:
+.TP 10n
+.I list
+lists the keys in a keytab showing version number and principal
+name.  
+.TP 10n
+.I change
+changes all the keys in the keytab to new randomly-generated keys,
+updating the keys in the Kerberos server's database to match by using the
+kadmin protocol.  If a key's version number doesn't match the
+version number stored in the Kerberos server's database,  then the operation will fail.  The old keys are retained
+so that existing tickets continue to work.
+If the \-i flag is given, 
+.I k5srvutil
+will prompt for yes or no before changing each key.  If the \-k
+option is used, the old and new keys will be displayed.
+.TP 10n
+.I delold
+Deletes keys that are not the most recent version from the keytab.  This operation
+should be used some time after a change operation to  remove old keys.
+If the \-i flag is used, then the program prompts the user
+whether the old keys associated with each principal should be removed.
+.TP 10n
+.I delete
+deletes particular keys in the keytab, interactively prompting for 
+each key.
+
+.PP
+In all cases, the default file used is /etc/krb5.keytab file 
+ unless this is overridden by the \-f option.
+
+
+.I k5srvutil
+uses the kadmin program to edit the keytab in place.  However, old keys are retained, so
+they are available in case of failure.
+
+.SH SEE ALSO
+kadmin(8), ktutil(8)
+
diff --git a/mechglue/src/kadmin/cli/k5srvutil.sh b/mechglue/src/kadmin/cli/k5srvutil.sh
new file mode 100755
index 000000000..70b1b8548
--- /dev/null
+++ b/mechglue/src/kadmin/cli/k5srvutil.sh
@@ -0,0 +1,117 @@
+#!/bin/sh
+
+# list_princs keytab
+# returns a list of principals in the keytab
+# sorted and uniquified
+list_princs() {
+    klist -k $keytab | tail +4 | awk '{print $2}' | sort | uniq
+}
+
+set_command() {
+    if [ x$command != x ] ; then
+	cmd_error Only one command can be specified
+	usage
+	exit 1
+    fi
+    command=$1
+}
+
+#interactive_prompt prompt princ
+# If in interactive mode  return  true if the principal  should be acted on
+# otherwise return true all the time
+interactive_prompt() {
+    if [ $interactive = 0 ] ; then
+	return 0
+    fi
+    printf "%s for %s? [yn]" "$1" "$2"
+    read ans
+    case $ans in
+    n*|N*)
+	return 1
+	;;
+    esac
+    return 0
+    }
+    
+cmd_error() {
+    echo $@ 2>&1
+    }
+
+usage() {
+    echo "Usage: $0 [-i] [-f file] list|change|delete|delold"
+}
+
+
+
+change_key() {
+    princs=`list_princs `
+    for princ in $princs; do
+	if interactive_prompt "Change key " $princ; then
+	    kadmin -k -t $keytab -p $princ -q "ktadd -k $keytab $princ"
+	fi
+    done
+    }
+
+delete_old_keys() {
+    princs=`list_princs `
+    for princ in $princs; do
+	if interactive_prompt "Delete old keys " $princ; then
+	    kadmin -k -t $keytab -p $princ -q "ktrem -k $keytab $princ old"
+	fi
+    done
+    }
+
+delete_keys() {
+    interactive=1
+    princs=`list_princs `
+    for princ in $princs; do
+	if interactive_prompt "Delete all keys " $princ; then
+	    kadmin -p $princ -k -t $keytab -q "ktrem -k $keytab $princ all"
+	fi
+    done
+    }
+
+
+keytab=/etc/krb5.keytab
+interactive=0
+
+while [ $# -gt 0 ] ; do
+    opt=$1
+    shift
+        case $opt in
+	"-f")
+	keytab=$1
+	shift
+	;;
+	"-i")
+	interactive=1
+	;;
+	change|delold|delete|list)
+	set_command $opt
+	;;
+	*)
+	cmd_error Illegal option: $opt
+	usage
+	exit 1
+	;;
+	esac
+done
+	
+
+case $command in
+    change)
+    change_key
+    ;;
+    delold)
+    delete_old_keys
+    ;;
+    delete)
+    delete_keys
+    ;;
+    list)
+    klist -k $keytab
+    ;;
+    *)
+        usage
+	;;
+    esac
diff --git a/mechglue/src/kadmin/cli/kadmin.M b/mechglue/src/kadmin/cli/kadmin.M
new file mode 100644
index 000000000..d9d6abda1
--- /dev/null
+++ b/mechglue/src/kadmin/cli/kadmin.M
@@ -0,0 +1,797 @@
+.TH KADMIN 8
+.SH NAME
+kadmin \- Kerberos V5 database administration program
+.SH SYNOPSYS
+.TP
+.B kadmin
+.ad l
+[\fB\-O\fP | \fB\-N\fP]
+[\fB\-r\fP \fIrealm\fP] [\fB\-p\fP \fIprincipal\fP] [\fB\-q\fP \fIquery\fP]
+.br
+[[\fB-c\fP \fIcache_name\fP] | [\fB-k\fP [\fB-t\fP
+\fIkeytab\fP]]] [\fB\-w\fP \fIpassword\fP] [\fB\-s\fP
+\fIadmin_server\fP[\fI:port\fP]
+.TP "\w'.B kadmin.local\ 'u"
+.B kadmin.local
+[\fB\-r\fP \fIrealm\fP] [\fB\-p\fP \fIprincipal\fP] [\fB\-q\fP \fIquery\fP]
+.br
+[\fB\-d\fP \fIdbname\fP] [\fB\-e \fI"enc:salt ..."\fP] [\fB-m\fP]
+.ad b
+.SH DESCRIPTION
+.B kadmin
+and
+.B kadmin.local
+are command-line interfaces to the Kerberos V5 KADM5 administration
+system.  Both
+.B kadmin
+and
+.B kadmin.local
+provide identical functionalities; the difference is that
+.B kadmin.local
+runs on the master KDC and does not use Kerberos to authenticate to the
+database.  Except as explicitly noted otherwise, this man page will use
+.B kadmin
+to refer to both versions.
+.B kadmin
+provides for the maintenance of Kerberos principals, KADM5 policies, and
+service key tables (keytabs).  
+.PP
+The remote version uses Kerberos authentication and an encrypted RPC, to
+operate securely from anywhere on the network.  It authenticates to the
+KADM5 server using the service principal
+.IR kadmin/admin .
+If the credentials cache contains a ticket for the
+.I kadmin/admin
+principal, and the 
+.B \-c
+.I credentials_cache
+option is specified, that ticket is used to authenticate to KADM5.
+Otherwise, the
+.B -p
+and
+.B -k
+options are used to specify the client Kerberos principal name used to
+authenticate.  Once
+.B kadmin
+has determined the principal name, it requests a
+.I kadmin/admin
+Kerberos service ticket from the KDC, and uses that service ticket to
+authenticate to KADM5.
+.PP
+The local client
+.BR kadmin.local ,
+is intended to run directly on the master KDC without Kerberos
+authentication.  The local version provides all of the functionality of
+the now obsolete
+.IR kdb5_edit (8),
+except for database dump and load, which is now provided by the
+.IR kdb5_util (8)
+utility.
+.PP
+.SH OPTIONS
+.TP
+\fB\-r\fP \fIrealm\fP
+Use
+.I realm
+as the default database realm.
+.TP
+\fB\-p\fP \fIprincipal\fP
+Use
+.I principal
+to authenticate.  Otherwise, kadmin will append "/admin" to the primary
+principal name of the default ccache, the value of the
+.SM USER
+environment variable, or the username as obtained with getpwuid, in
+order of preference.
+.TP
+\fB\-k\fP
+Use a keytab to decrypt the KDC response instead of prompting for a
+password on the TTY.  In this case, the default principal will be
+host/\fIhostname\fP.  If there is not a keytab specified with the
+.B \-t
+option, then the default keytab will be used.
+.TP
+\fB\-t\fP \fIkeytab\fP
+Use
+.I keytab
+to decrypt the KDC response.  This can only be used with the
+.B \-k
+option.
+.TP
+\fB\-c\fP \fIcredentials_cache\fP
+Use
+.I credentials_cache
+as the credentials cache.  The
+.I credentials_cache
+should contain a service ticket for the
+.I kadmin/admin
+service; it can be acquired with the
+.IR kinit (1)
+program.  If this option is not specified,
+.B kadmin
+requests a new service ticket from the KDC, and stores it in its own
+temporary ccache.
+.TP
+\fB\-w\fP \fIpassword\fP
+Use
+.I password
+instead of prompting for one on the TTY.  Note:  placing the password
+for a Kerberos principal with administration access into a shell script
+can be dangerous if unauthorized users gain read access to the script.
+.TP
+\fB\-q\fP \fIquery\fP
+pass
+.I query
+directly to
+.BR kadmin ,
+which will perform
+.I query
+and then exit.  This can be useful for writing scripts.
+.TP
+\fB\-d\fP \fIdbname\fP
+Specifies the name of the Kerberos database.
+.TP
+\fB\-s\fP \fIadmin_server[:port]\fP
+Specifies the admin server which kadmin should contact.
+.TP
+\fB\-m\fP
+Do not authenticate using a keytab.  This option will cause kadmin
+to prompt for the master database password.
+.TP
+\fB\-e\fP \fIenc:salt_list\fP
+Sets the list of encryption types and salt types to be used for any new
+keys created.
+.TP
+.B \-O
+Force use of old AUTH_GSSAPI authentication flavor.
+.TP
+.B \-N
+Prevent fallback to AUTH_GSSAPI authentication flavor.
+.SH DATE FORMAT 
+Various commands in kadmin can take a variety of date formats,
+specifying durations or absolute times.  Examples of valid formats are:
+.sp
+.nf
+.RS
+1 month ago
+2 hours ago
+400000 seconds ago
+last year
+this Monday
+next Monday
+yesterday
+tomorrow
+now
+second Monday
+a fortnight ago
+3/31/92 10:00:07 PST
+January 23, 1987 10:05pm
+22:00 GMT
+.RE
+.fi
+.PP
+Dates which do not have the "ago" specifier default to being absolute
+dates, unless they appear in a field where a duration is expected.  In
+that case the time specifier will be interpreted as relative.
+Specifying "ago" in a duration may result in unexpected behavior.
+.PP
+.SH COMMANDS
+.TP
+\fBadd_principal\fP [\fIoptions\fP] \fInewprinc\fP
+creates the principal
+.IR newprinc ,
+prompting twice for a password.  If no policy is specified with the
+-policy option, and the policy named "default" exists, then that
+policy is assigned to the principal; note that the assignment of the
+policy "default" only occurs automatically when a principal is first
+created, so the policy "default" must already exist for the assignment
+to occur.  This assignment of "default" can be suppressed with the
+-clearpolicy option.  This command requires the 
+.I add
+privilege.  This command has the aliases
+.B addprinc
+and
+.BR ank .
+The options are:
+.RS
+.TP
+\fB\-expire\fP \fIexpdate\fP
+expiration date of the principal
+.TP
+\fB\-pwexpire\fP \fIpwexpdate\fP
+password expiration date
+.TP
+\fB\-maxlife\fP \fImaxlife\fP
+maximum ticket life for the principal
+.TP
+\fB\-maxrenewlife\fP \fImaxrenewlife\fP
+maximum renewable life of tickets for the principal
+.TP
+\fB\-kvno\fP \fIkvno\fP
+explicity set the key version number.
+.TP
+\fB\-policy\fP \fIpolicy\fP
+policy used by this principal.  If no policy is supplied, then if the
+policy "default" exists and the -clearpolicy is not also specified,
+then the policy "default" is used; otherwise, the principal 
+will have no policy, and a warning message will be printed.
+.TP
+\fB\-clearpolicy\fP 
+.B -clearpolicy
+prevents the policy "default" from being assigned when 
+.B -policy
+is not specified.  This option has no effect if the policy "default"
+does not exist.
+.TP
+{\fB\-\fP|\fB+\fP}\fBallow_postdated\fP
+.B -allow_postdated
+prohibits this principal from obtaining postdated tickets.  (Sets the
+.SM KRB5_KDB_DISALLOW_POSTDATED
+flag.)
+.B +allow_postdated
+clears this flag.
+.TP
+{\fB\-\fP|\fB+\fP}\fBallow_forwardable\fP
+.B -allow_forwardable
+prohibits this principal from obtaining forwardable tickets.  (Sets the
+.SM KRB5_KDB_DISALLOW_FORWARDABLE
+flag.)
+.B +allow_forwardable
+clears this flag.
+.TP
+{\fB\-\fP|\fB+\fP}\fBallow_renewable\fP
+.B -allow_renewable
+prohibits this principal from obtaining renewable tickets.  (Sets the
+.SM KRB5_KDB_DISALLOW_RENEWABLE
+flag.)
+.B +allow_renewable
+clears this flag.
+.TP
+{\fB\-\fP|\fB+\fP}\fBallow_proxiable\fP
+.B -allow_proxiable
+prohibits this principal from obtaining proxiable tickets.  (Sets the
+.SM KRB5_KDB_DISALLOW_PROXIABLE
+flag.)
+.B +allow_proxiable
+clears this flag.
+.TP
+{\fB\-\fP|\fB+\fP}\fBallow_dup_skey\fP
+.B -allow_dup_skey
+Disables user-to-user authentication for this principal by prohibiting
+this principal from obtaining a session key for another user.  (Sets the
+.SM KRB5_KDB_DISALLOW_DUP_SKEY
+flag.)
+.B +allow_dup_skey
+clears this flag.
+.TP
+{\fB\-\fP|\fB+\fP}\fBrequires_preauth\fP
+.B +requires_preauth
+requires this principal to preauthenticate before being allowed to
+kinit.  (Sets the
+.SM KRB5_KDB_REQUIRES_PRE_AUTH
+flag.)
+.B -requires_preauth
+clears this flag.
+.TP
+{\fB\-\fP|\fB+\fP}\fBrequires_hwauth\fP
+.B +requires_hwauth
+requires this principal to preauthenticate using a hardware device
+before being allowed to kinit.  (Sets the
+.SM KRB5_KDB_REQUIRES_HW_AUTH
+flag.)
+.B -requires_hwauth
+clears this flag.
+.TP
+{\fB\-\fP|\fB+\fP}\fBallow_svr\fP
+.B -allow_svr
+prohibits the issuance of service tickets for this principal.  (Sets the
+.SM KRB5_KDB_DISALLOW_SVR
+flag.)
+.B +allow_svr
+clears this flag.
+.TP
+{\fB\-\fP|\fB+\fP}\fBallow_tgs_req\fP
+.B \-allow_tgs_req
+specifies that a Ticket-Granting Service (TGS) request for a service
+ticket for this principal is not permitted.  This option is useless for
+most things.
+.B +allow_tgs_req
+clears this flag.  The default is
+.BR +allow_tgs_req .
+In effect,
+.B \-allow_tgs_req
+sets the
+.SM KRB5_KDB_DISALLOW_TGT_BASED
+flag on the principal in the database.
+.TP
+{\fB\-\fP|\fB+\fP}\fBallow_tix\fP
+.B \-allow_tix
+forbids the issuance of any tickets for this principal.
+.B +allow_tix
+clears this flag.  The default is
+.BR +allow_tix .
+In effect,
+.B \-allow_tix
+sets the
+.SM KRB5_KDB_DISALLOW_ALL_TIX
+flag on the principal in the database.
+.TP
+{\fB\-\fP|\fB+\fP}\fBneedchange\fP
+.B +needchange
+sets a flag in attributes field to force a password change;
+.B \-needchange
+clears it.  The default is
+.BR \-needchange .
+In effect,
+.B +needchange
+sets the
+.SM KRB5_KDB_REQUIRES_PWCHANGE
+flag on the principal in the database.
+.TP
+{\fB\-\fP|\fB+\fP}\fBpassword_changing_service\fP
+.B +password_changing_service
+sets a flag in the attributes field marking this as a password change
+service principal (useless for most things).
+.B \-password_changing_service
+clears the flag.  This flag intentionally has a long name.  The default
+is
+.BR \-password_changing_service .
+In effect,
+.B +password_changing_service
+sets the
+.SM KRB5_KDB_PWCHANGE_SERVICE
+flag on the principal in the database.
+.TP
+.B \-randkey
+sets the key of the principal to a random value
+.TP
+\fB\-pw\fP \fIpassword\fP
+sets the key of the principal to the specified string and does not
+prompt for a password.  Note:  using this option in a shell script can
+be dangerous if unauthorized users gain read access to the script.
+.TP
+\fB\-e\fP \fI"enc:salt ..."\fP
+uses the specified list of enctype\-salttype pairs for setting the key
+of the principal.  The quotes are necessary if there are multiple
+enctype\-salttype pairs.  This will not function against kadmin
+daemons earlier than krb5\-1.2.
+.nf
+.TP
+EXAMPLE:
+kadmin: addprinc tlyu/admin
+WARNING: no policy specified for "tlyu/admin@BLEEP.COM";
+defaulting to no policy.
+Enter password for principal tlyu/admin@BLEEP.COM:
+Re-enter password for principal tlyu/admin@BLEEP.COM:
+Principal "tlyu/admin@BLEEP.COM" created.
+kadmin:
+.TP
+ERRORS:
+KADM5_AUTH_ADD (requires "add" privilege)
+KADM5_BAD_MASK (shouldn't happen)
+KADM5_DUP (principal exists already)
+KADM5_UNK_POLICY (policy does not exist)
+KADM5_PASS_Q_* (password quality violations)
+.fi
+.RE
+.TP
+\fBdelete_principal\fP [\fB-force\fP] \fIprincipal\fP
+deletes the specified principal from the database.  This command prompts
+for deletion, unless the
+.B -force
+option is given. This command requires the
+.I delete
+privilege.  Aliased
+to
+.BR delprinc .
+.sp
+.nf
+.RS
+.TP
+EXAMPLE:
+kadmin: delprinc mwm_user
+Are you sure you want to delete the principal
+"mwm_user@BLEEP.COM"? (yes/no): yes
+Principal "mwm_user@BLEEP.COM" deleted.
+Make sure that you have removed this principal from
+all ACLs before reusing.
+kadmin:
+.TP
+ERRORS:
+KADM5_AUTH_DELETE (reequires "delete" privilege)
+KADM5_UNK_PRINC (principal does not exist)
+.RE
+.fi
+.TP
+\fBmodify_principal\fP [\fIoptions\fP] \fIprincipal\fP
+modifies the specified principal, changing the fields as specified.  The
+options are as above for
+.BR add_principal ,
+except that password changing and flags related to password changing
+are forbidden by this command.  In addition, the option
+.B \-clearpolicy
+will clear the current policy of a principal.  This command requires the
+.I modify
+privilege.  Aliased to
+.BR modprinc .
+.sp
+.nf
+.RS
+.TP
+ERRORS:
+KADM5_AUTH_MODIFY (requires "modify" privilege)
+KADM5_UNK_PRINC (principal does not exist)
+KADM5_UNK_POLICY (policy does not exist)
+KADM5_BAD_MASK (shouldn't happen)
+.RE
+.fi
+.TP
+\fBchange_password\fP [\fIoptions\fP] \fIprincipal\fP
+changes the password of
+.IR principal .
+Prompts for a new password if neither
+.B \-randkey
+or
+.B \-pw
+is specified.  Requires the
+.I changepw
+privilege, or that the principal that is running the program to be the
+same as the one changed.  Aliased to
+.BR cpw .
+The following options are available:
+.RS
+.TP
+.B \-randkey
+sets the key of the principal to a random value
+.TP
+\fB\-pw\fP \fIpassword\fP
+set the password to the specified string.  Not recommended.
+.TP
+\fB\-e\fP \fI"enc:salt ..."\fP
+uses the specified list of enctype\-salttype pairs for setting the key
+of the principal.  The quotes are necessary if there are multiple
+enctype\-salttype pairs.  This will not function against kadmin
+daemons earlier than krb5\-1.2.
+.TP
+\fB\-keepold \fP 
+Keeps the previous kvno's keys around.  There is no
+easy way to delete the old keys, and this flag is usually not
+necessary except perhaps for TGS keys.  Don't use this flag unless you
+know what you're doing.
+.nf
+.TP
+EXAMPLE:
+kadmin: cpw systest
+Enter password for principal systest@BLEEP.COM:
+Re-enter password for principal systest@BLEEP.COM:
+Password for systest@BLEEP.COM changed.
+kadmin:
+.TP
+ERRORS:
+KADM5_AUTH_MODIFY (requires the modify privilege)
+KADM5_UNK_PRINC (principal does not exist)
+KADM5_PASS_Q_* (password policy violation errors)
+KADM5_PADD_REUSE (password is in principal's password
+history)
+KADM5_PASS_TOOSOON (current password minimum life not
+expired)
+.RE
+.fi
+.TP
+\fBget_principal\fP [\fB-terse\fP] \fIprincipal\fP
+gets the attributes of
+.IR principal .
+Requires the
+.I inquire
+privilege, or that the principal that is running the the program to be
+the same as the one being listed.  With the
+.B \-terse
+option, outputs fields as quoted tab-separated strings.  Alias
+.BR getprinc .
+.sp
+.nf
+.RS
+.TP
+EXAMPLES:
+kadmin: getprinc tlyu/admin
+Principal: tlyu/admin@BLEEP.COM
+Expiration date: [never]
+Last password change: Mon Aug 12 14:16:47 EDT 1996
+Password expiration date: [none]
+Maximum ticket life: 0 days 10:00:00
+Maximum renewable life: 7 days 00:00:00
+Last modified: Mon Aug 12 14:16:47 EDT 1996 (bjaspan/admin@BLEEP.COM)
+Last successful authentication: [never]
+Last failed authentication: [never]
+Failed password attempts: 0
+Number of keys: 2
+Key: vno 1, DES cbc mode with CRC-32, no salt
+Key: vno 1, DES cbc mode with CRC-32, Version 4
+Attributes:
+Policy: [none]
+kadmin: getprinc -terse systest
+systest@BLEEP.COM	3	86400	604800	1
+785926535	753241234	785900000
+tlyu/admin@BLEEP.COM	786100034	0	0
+kadmin:
+.TP
+ERRORS:
+KADM5_AUTH_GET (requires the get (inquire) privilege)
+KADM5_UNK_PRINC (principal does not exist)
+.RE
+.fi
+.TP
+\fBlist_principals\fP [\fIexpression\fP]
+Retrieves all or some principal names.  
+.I Expression
+is a shell-style glob expression that can contain the wild-card
+characters \&?, *, and []'s.  All principal names matching the
+expression are printed.  If no expression is provided, all principal
+names are printed.  If the expression does not contain an "@" character,
+an "@" character followed by the local realm is appended to the
+expression.  Requires the
+.I list
+priviledge.  Alias
+.BR listprincs ,
+.BR get_principals ,
+.BR get_princs .
+.nf
+.RS
+.TP
+EXAMPLES:
+kadmin:  listprincs test*
+test3@SECURE-TEST.OV.COM
+test2@SECURE-TEST.OV.COM
+test1@SECURE-TEST.OV.COM
+testuser@SECURE-TEST.OV.COM
+kadmin:
+.RE
+.fi
+.TP
+\fBadd_policy\fP [\fIoptions\fP] \fIpolicy\fP
+adds the named policy to the policy database.  Requires the
+.I add
+privilege.  Aliased to
+.BR addpol .
+The following options are available:
+.RS
+.TP
+\fB\-maxlife\fP \fItime\fP
+sets the maximum lifetime of a password
+.TP
+\fB\-minlife\fP \fItime\fP
+sets the minimum lifetime of a password
+.TP
+\fB\-minlength\fP \fIlength\fP
+sets the minimum length of a password
+.TP
+\fB\-minclasses\fP \fInumber\fP
+sets the minimum number of character classes allowed in a password
+.TP
+\fB\-history\fP \fInumber\fP
+sets the number of past keys kept for a principal
+.sp
+.nf
+.TP
+ERRORS:
+KADM5_AUTH_ADD (requires the add privilege)
+KADM5_DUP (policy already exists)
+.fi
+.RE
+.TP
+\fBdelete_policy [\-force]\fP \fIpolicy\fB
+deletes the named policy.  Prompts for confirmation before deletion.
+The command will fail if the policy is in use by any principals.
+Requires the
+.I delete
+privilege.  Alias
+.BR delpol .
+.sp
+.nf
+.RS
+.TP
+EXAMPLE:
+kadmin: del_policy guests
+Are you sure you want to delete the policy "guests"?
+(yes/no): yes
+kadmin:
+.TP
+ERRORS:
+KADM5_AUTH_DELETE (requires the delete privilege)
+KADM5_UNK_POLICY (policy does not exist)
+KADM5_POLICY_REF (reference count on policy is not zero)
+.RE
+.fi
+.TP
+\fBmodify_policy\fP [\fIoptions\fP] \fIpolicy\fP
+modifies the named policy.  Options are as above for
+.BR add_policy .
+Requires the
+.I modify
+privilege.  Alias
+.BR modpol .
+.sp
+.nf
+.RS
+.TP
+ERRORS:
+KADM5_AUTH_MODIFY (requires the modify privilege)
+KADM5_UNK_POLICY (policy does not exist)
+.RE
+.fi
+.TP
+\fBget_policy\fP [\fB\-terse\fP] \fIpolicy\fP
+displays the values of the named policy.  Requires the
+.I inquire
+privilege.  With the
+.B \-terse
+flag, outputs the fields as quoted strings separated by tabs.  Alias
+.BR getpol .
+.nf
+.RS
+.TP
+EXAMPLES:
+kadmin: get_policy admin
+Policy: admin
+Maximum password life: 180 days 00:00:00
+Minimum password life: 00:00:00
+Minimum password length: 6
+Minimum number of password character classes: 2
+Number of old keys kept: 5
+Reference count: 17
+kadmin: get_policy -terse admin
+admin	15552000	0	6	2	5	17
+kadmin:
+.TP
+ERRORS:
+KADM5_AUTH_GET (requires the get privilege)
+KADM5_UNK_POLICY (policy does not exist)
+.RE
+.fi
+.TP
+\fBlist_policies\fP [\fIexpression\fP]
+Retrieves all or some policy names.  
+.I Expression
+is a shell-style glob expression that can contain the wild-card
+characters \&?, *, and []'s.  All policy names matching the expression
+are printed.  If no expression is provided, all existing policy names
+are printed.  Requires the
+.I list
+priviledge.  Alias
+.BR listpols ,
+.BR get_policies ,
+.BR getpols .
+.sp
+.nf
+.RS
+.TP
+EXAMPLES:
+kadmin:  listpols
+test-pol
+dict-only
+once-a-min
+test-pol-nopw
+kadmin:  listpols t*
+test-pol
+test-pol-nopw
+kadmin:
+.RE
+.fi
+.TP
+\fBktadd\fP [\fB\-k\fP \fIkeytab\fP] [\fB\-q\fP] [\fB\-e\fP \fIkeysaltlist\fP]
+.br
+[\fIprincipal\fP | \fB\-glob\fP \fIprinc-exp\fP] [\fI...\fP]
+.br
+Adds a principal or all principals matching
+.I princ-exp
+to a keytab, randomizing each principal's key in the process.  Requires the
+.I inquire
+and 
+.I changepw
+privileges.  An entry for each of the principal's unique encryption types
+is added, ignoring multiple keys with the same encryption type but
+different salt types.  If the
+.B \-k
+argument is not specified, the default keytab
+.I /etc/krb5.keytab
+is used.  If the
+.B \-q
+option is specified, less verbose status information is displayed.
+.sp
+The
+.B -glob
+option requires the
+.I list
+privilege.
+.I princ-exp
+follows the same rules described for the
+.B list_principals
+command.  
+.sp
+.nf
+.RS
+.TP
+EXAMPLE:
+kadmin: ktadd -k /tmp/foo-new-keytab host/foo.mit.edu
+Entry for principal host/foo.mit.edu@ATHENA.MIT.EDU with
+	kvno 3, encryption type DES-CBC-CRC added to keytab
+	WRFILE:/tmp/foo-new-keytab
+kadmin:
+.RE
+.fi
+.TP
+\fBktremove\fP [\fB\-k\fP \fIkeytab\fP] [\fB\-q\fP] \fIprincipal\fP [\fIkvno\fP | \fBall\fP | \fBold\fP]
+Removes entries for the specified principal from a keytab.  Requires no
+permissions, since this does not require database access.  If the string
+"all" is specified, all entries for that principal are removed; if the
+string "old" is specified, all entries for that principal except those
+with the highest kvno are removed.  Otherwise, the value specified is
+parsed as an integer, and all entries whose kvno match that integer are
+removed.  If the
+.B \-k
+argument is not specifeid, the default keytab
+.I /etc/krb5.keytab
+is used.  If the
+.B \-q
+option is specified, less verbose status information is displayed.
+.sp
+.nf
+.RS
+.TP
+EXAMPLE:
+kadmin: ktremove -k /usr/local/var/krb5kdc/kadmind.keytab kadmin/admin
+Entry for principal kadmin/admin with kvno 3 removed
+	from keytab WRFILE:/usr/local/var/krb5kdc/kadmind.keytab.
+kadmin:
+.RE
+.fi
+.SH FILES
+.TP "\w'<dbname>.kadm5.lock\ \ 'u"
+principal.db
+default name for Kerberos principal database
+.TP
+<dbname>.kadm5
+KADM5 administrative database.  (This would be "principal.kadm5", if you
+use the default database name.)  Contains policy information.
+.TP
+<dbname>.kadm5.lock
+lock file for the KADM5 administrative database.  This file works
+backwards from most other lock files.  I.e.,
+.B kadmin
+will exit with an error if this file does
+.I not
+exist.
+.TP
+kadm5.acl
+file containing list of principals and their
+.B kadmin
+administrative privileges.  See
+.IR kadmind (8)
+for a description.
+.TP
+kadm5.keytab
+keytab file for
+.I kadmin/admin
+principal.
+.TP
+kadm5.dict
+file containing dictionary of strings explicitly disallowed as
+passwords.
+.SH HISTORY
+The
+.B kadmin
+prorgam was originally written by Tom Yu at MIT, as an interface to the
+OpenVision Kerberos administration program.
+.SH SEE ALSO
+.IR kerberos (1),
+.IR kpasswd (1),
+.IR kadmind (8)
+.SH BUGS
+.PP
+Command output needs to be cleaned up.
+
+There is no way to delete a key kept around from a "\-keepold" option
+to a password-changing command, other than to do a password change
+without the "\-keepold" option, which will of course cause problems if
+the key is a TGS key.  There will be more powerful key-manipulation
+commands in the future.
diff --git a/mechglue/src/kadmin/cli/kadmin.c b/mechglue/src/kadmin/cli/kadmin.c
new file mode 100644
index 000000000..7af39a661
--- /dev/null
+++ b/mechglue/src/kadmin/cli/kadmin.c
@@ -0,0 +1,1736 @@
+/*
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * kadmin.c: base functions for a kadmin command line interface using
+ * the OVSecure library
+ */
+
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <krb5/adm_proto.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <math.h>
+#include <unistd.h>
+#include <pwd.h>
+/* #include <sys/timeb.h> */
+#include <time.h>
+#include "kadmin.h"
+
+/* special struct to convert flag names for principals
+   to actual krb5_flags for a principal */
+struct pflag {
+    char *flagname;		/* name of flag as typed to CLI */
+    int flaglen;		/* length of string (not counting -,+) */
+    krb5_flags theflag;		/* actual principal flag to set/clear */
+    int set;			/* 0 means clear, 1 means set (on '-') */
+};
+
+static struct pflag flags[] = {
+{"allow_postdated",	15,	KRB5_KDB_DISALLOW_POSTDATED,	1},
+{"allow_forwardable",	17,	KRB5_KDB_DISALLOW_FORWARDABLE,	1},
+{"allow_tgs_req",	13,	KRB5_KDB_DISALLOW_TGT_BASED,	1},
+{"allow_renewable",	15,	KRB5_KDB_DISALLOW_RENEWABLE,	1},
+{"allow_proxiable",	15,	KRB5_KDB_DISALLOW_PROXIABLE,	1},
+{"allow_dup_skey",	14,	KRB5_KDB_DISALLOW_DUP_SKEY,	1},
+{"allow_tix",		9,	KRB5_KDB_DISALLOW_ALL_TIX,	1},
+{"requires_preauth",	16,	KRB5_KDB_REQUIRES_PRE_AUTH,	0},
+{"requires_hwauth",	15,	KRB5_KDB_REQUIRES_HW_AUTH,	0},
+{"needchange",		10,	KRB5_KDB_REQUIRES_PWCHANGE,	0},
+{"allow_svr",		9,	KRB5_KDB_DISALLOW_SVR,		1},
+{"password_changing_service",	25,	KRB5_KDB_PWCHANGE_SERVICE,	0 },
+{"support_desmd5",	14,	KRB5_KDB_SUPPORT_DESMD5,	0 }
+};
+
+static char *prflags[] = {
+    "DISALLOW_POSTDATED",	/* 0x00000001 */
+    "DISALLOW_FORWARDABLE",	/* 0x00000002 */
+    "DISALLOW_TGT_BASED",	/* 0x00000004 */
+    "DISALLOW_RENEWABLE",	/* 0x00000008 */
+    "DISALLOW_PROXIABLE",	/* 0x00000010 */
+    "DISALLOW_DUP_SKEY",	/* 0x00000020 */
+    "DISALLOW_ALL_TIX",		/* 0x00000040 */
+    "REQUIRES_PRE_AUTH",	/* 0x00000080 */
+    "REQUIRES_HW_AUTH",		/* 0x00000100 */
+    "REQUIRES_PWCHANGE",	/* 0x00000200 */
+    "UNKNOWN_0x00000400",	/* 0x00000400 */
+    "UNKNOWN_0x00000800",	/* 0x00000800 */
+    "DISALLOW_SVR",		/* 0x00001000 */
+    "PWCHANGE_SERVICE",		/* 0x00002000 */
+    "SUPPORT_DESMD5",		/* 0x00004000 */
+    "NEW_PRINC",		/* 0x00008000 */
+};
+
+char *getenv();
+int exit_status = 0;
+char *def_realm = NULL;
+char *whoami = NULL;
+
+void *handle = NULL;
+krb5_context context;
+char *ccache_name = NULL;
+
+int locked = 0;
+
+static void usage()
+{
+    fprintf(stderr,
+	    "Usage: %s [-r realm] [-p principal] [-q query] [clnt|local args]\n"
+	    "\tclnt args: [-s admin_server[:port]] [[-c ccache]|[-k [-t keytab]]]\n"
+	    "\tlocal args: [-x db_args]* [-d dbname] [-e \"enc:salt ...\"] [-m]\n"
+	    "where,\n\t[-x db_args]* - any number of database specific arguments.\n"
+	    "\t\t\tLook at each database documentation for supported arguments\n",
+	    whoami);
+    exit(1);
+}
+
+static char *strdur(duration)
+    time_t duration;
+{
+    static char out[50];
+    int neg, days, hours, minutes, seconds;
+
+    if (duration < 0) {
+	duration *= -1;
+	neg = 1;
+    } else
+	neg = 0;
+    days = duration / (24 * 3600);
+    duration %= 24 * 3600;
+    hours = duration / 3600;
+    duration %= 3600;
+    minutes = duration / 60;
+    duration %= 60;
+    seconds = duration;
+    sprintf(out, "%s%d %s %02d:%02d:%02d", neg ? "-" : "",
+	    days, days == 1 ? "day" : "days",
+	    hours, minutes, seconds);
+    return out;
+}
+
+static char *strdate(when)
+    krb5_timestamp when;
+{
+    struct tm *tm;
+    static char out[40];
+    
+    time_t lcltim = when;
+    tm = localtime(&lcltim);
+    strftime(out, sizeof(out), "%a %b %d %H:%M:%S %Z %Y", tm);
+    return out;
+}
+
+/* this is a wrapper to go around krb5_parse_principal so we can set
+   the default realm up properly */
+static krb5_error_code 
+kadmin_parse_name(name, principal)
+    char *name;
+    krb5_principal *principal;
+{
+    char *cp, *fullname;
+    krb5_error_code retval;
+    
+    /* assumes def_realm is initialized! */
+    fullname = (char *)malloc(strlen(name) + 1 + strlen(def_realm) + 1);
+    if (fullname == NULL)
+	return ENOMEM;
+    strcpy(fullname, name);
+    cp = strchr(fullname, '@');
+    while (cp) {
+	if (cp - fullname && *(cp - 1) != '\\')
+	    break;
+	else
+	    cp = strchr(cp + 1, '@');
+    }
+    if (cp == NULL) {
+	strcat(fullname, "@");
+	strcat(fullname, def_realm);
+    }
+    retval = krb5_parse_name(context, fullname, principal);
+    free(fullname);
+    return retval;
+}
+
+char *kadmin_startup(argc, argv)
+    int argc;
+    char *argv[];
+{
+    extern char *optarg;
+    char *princstr = NULL, *keytab_name = NULL, *query = NULL;
+    char *password = NULL;
+    char *luser, *canon, *cp;
+    int optchar, freeprinc = 0, use_keytab = 0;
+    struct passwd *pw;
+    kadm5_ret_t retval;
+    krb5_ccache cc;
+    krb5_principal princ;
+    kadm5_config_params params;
+    char **db_args = NULL;
+    int db_args_size = 0;
+    char *db_name = NULL;
+    char *svcname;
+
+    memset((char *) ¶ms, 0, sizeof(params));
+    
+    retval = krb5_init_context(&context);
+    if (retval) {
+	 com_err(whoami, retval, "while initializing krb5 library");
+	 exit(1);
+    }
+		     
+    while ((optchar = getopt(argc, argv, "x:r:p:kq:w:d:s:mc:t:e:ON")) != EOF) {
+	switch (optchar) {
+	case 'x':
+	  db_args_size++;
+	  {
+	    char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
+	    if( temp == NULL )
+	      {
+		fprintf(stderr,"%s: Cannot initialize. Not enough memory\n",
+			argv[0]);
+		exit(1);
+	      }
+
+	    db_args = temp;
+	  }
+	  db_args[db_args_size-1] = optarg;
+	  db_args[db_args_size]   = NULL;
+	  break;
+	  
+	case 'r':
+	    def_realm = optarg;
+	    break;
+	case 'p':
+	    princstr = optarg;
+	    break;
+        case 'c':
+	    ccache_name = optarg;
+	    break;
+        case 'k':
+	    use_keytab++;
+	    break;
+       case 't':
+	    keytab_name = optarg;
+	    break;
+        case 'w':
+	    password = optarg;
+	    break;
+	case 'q':
+	    query = optarg;
+	    break;
+        case 'd':
+	    /* now db_name is not a seperate argument. It has to be passed as part of the db_args */
+	    if( !db_name )
+	    {
+		db_name = malloc( strlen(optarg) + sizeof("dbname="));
+	    } 
+	    else
+	    {
+		db_name = realloc( db_name, strlen(optarg) + sizeof("dbname="));
+	    }
+
+	    strcpy( db_name, "dbname=");
+	    strcat( db_name, optarg );
+
+	    db_args_size++;
+	    {
+		char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
+		if( temp == NULL )
+		{
+		    fprintf(stderr,"%s: Cannot initialize. Not enough memory\n",
+			    argv[0]);
+		    exit(1);
+		}
+
+		db_args = temp;
+	    }
+	    db_args[db_args_size-1] = db_name;
+	    db_args[db_args_size]   = NULL;
+	    break;
+        case 's':
+	    params.admin_server = optarg;
+	    params.mask |= KADM5_CONFIG_ADMIN_SERVER;
+	    break;
+        case 'm':
+	    params.mkey_from_kbd = 1;
+	    params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+	    break;
+        case 'e':
+	    retval = krb5_string_to_keysalts(optarg,
+					     ", \t",
+					     ":.-",
+					     0,
+					     ¶ms.keysalts,
+					     ¶ms.num_keysalts);
+	    if (retval) {
+		 com_err(whoami, retval, "while parsing keysalts %s", optarg);
+		 exit(1);
+	    }
+	    params.mask |= KADM5_CONFIG_ENCTYPES;
+	    break;
+	case 'O':
+	    params.mask |= KADM5_CONFIG_OLD_AUTH_GSSAPI;
+	    break;
+	case 'N':
+	    params.mask |= KADM5_CONFIG_AUTH_NOFALLBACK;
+	    break;
+	default:
+	    usage();
+	}
+    }
+    if ((ccache_name && use_keytab) ||
+	(keytab_name && !use_keytab))
+	 usage();
+
+    if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) {
+	if (freeprinc)
+	    free(princstr);
+	fprintf(stderr, "%s: unable to get default realm\n", whoami);
+	exit(1);
+    }
+
+    params.mask |= KADM5_CONFIG_REALM;
+    params.realm = def_realm;
+
+    if (params.mask & KADM5_CONFIG_OLD_AUTH_GSSAPI)
+	svcname = KADM5_ADMIN_SERVICE;
+    else
+	svcname = NULL;
+
+    /*
+     * Set cc to an open credentials cache, either specified by the -c
+     * argument or the default.
+     */
+    if (ccache_name == NULL) {
+	 if ((retval = krb5_cc_default(context, &cc))) {
+	      com_err(whoami, retval,
+		      "while opening default credentials cache");
+	      exit(1);
+	 }
+    } else {
+	 if ((retval = krb5_cc_resolve(context, ccache_name, &cc))) {
+	      com_err(whoami, retval,
+		      "while opening credentials cache %s", ccache_name);
+	      exit(1);
+	 }
+    }
+
+    /*
+     * If no principal name is specified: If a ccache was specified
+     * and its primary principal name can be read, it is used, else if
+     * a keytab was specified, the principal name is host/hostname,
+     * otherwise append "/admin" to the primary name of the default
+     * ccache, $USER, or pw_name.
+     *
+     * Gee, 100+ lines to figure out the client principal name.  This
+     * should be compressed...
+     */
+    
+    if (princstr == NULL) {
+	if (ccache_name != NULL &&
+	    !krb5_cc_get_principal(context, cc, &princ)) {
+	     if ((retval = krb5_unparse_name(context, princ, &princstr))) {
+		  com_err(whoami, retval,
+			  "while canonicalizing principal name");
+		  krb5_free_principal(context, princ);
+		  exit(1);
+	     }
+	     krb5_free_principal(context, princ);
+	     freeprinc++;
+	} else if (use_keytab != 0) {
+	     if ((retval = krb5_sname_to_principal(context, NULL,
+						   "host",
+						   KRB5_NT_SRV_HST,
+						   &princ))) {
+		  com_err(whoami, retval,
+			  "creating host service principal");
+		  exit(1);
+	     }
+	     if ((retval = krb5_unparse_name(context, princ, &princstr))) {
+	          com_err(whoami, retval,
+			  "while canonicalizing principal name");
+		  krb5_free_principal(context, princ);
+		  exit(1);
+	     }
+	     krb5_free_principal(context, princ);
+	     freeprinc++;
+	} else if (!krb5_cc_get_principal(context, cc, &princ)) {
+	    char *realm = NULL;
+	    if (krb5_unparse_name(context, princ, &canon)) {
+		fprintf(stderr,
+			"%s: unable to canonicalize principal\n", whoami);
+		krb5_free_principal(context, princ);
+		exit(1);
+	    }
+	    /* strip out realm of principal if it's there */
+	    realm = strchr(canon, '@');
+	    while (realm) {
+		if (realm - canon && *(realm - 1) != '\\')
+		    break;
+		else
+		    realm = strchr(realm, '@');
+	    }
+	    if (realm)
+		*realm++ = '\0';
+	    cp = strchr(canon, '/');
+	    while (cp) {
+		if (cp - canon && *(cp - 1) != '\\')
+		    break;
+		else
+		    cp = strchr(cp, '/');
+	    }
+	    if (cp != NULL)
+		*cp = '\0';
+	    princstr = (char*)malloc(strlen(canon) + 6 /* "/admin" */ +
+				     (realm ? 1 + strlen(realm) : 0) + 1);
+	    if (princstr == NULL) {
+		fprintf(stderr, "%s: out of memory\n", whoami);
+		exit(1);
+	    }
+	    strcpy(princstr, canon);
+	    strcat(princstr, "/admin");
+	    if (realm) {
+		strcat(princstr, "@");
+		strcat(princstr, realm);
+	    }
+	    free(canon);
+	    krb5_free_principal(context, princ);
+	    freeprinc++;
+	} else if ((luser = getenv("USER"))) {
+	    princstr = (char *) malloc(strlen(luser) + 7 /* "/admin@" */
+			      + strlen(def_realm) + 1);
+	    if (princstr == NULL) {
+		fprintf(stderr, "%s: out of memory\n", whoami);
+		exit(1);
+	    }
+	    strcpy(princstr, luser);
+	    strcat(princstr, "/admin");
+	    strcat(princstr, "@");
+	    strcat(princstr, def_realm);
+	    freeprinc++;
+	} else if ((pw = getpwuid(getuid()))) {
+	    princstr = (char *) malloc(strlen(pw->pw_name) + 7 /* "/admin@" */
+			      + strlen(def_realm) + 1);
+	    if (princstr == NULL) {
+		fprintf(stderr, "%s: out of memory\n", whoami);
+		exit(1);
+	    }
+	    strcpy(princstr, pw->pw_name);
+	    strcat(princstr, "/admin@");
+	    strcat(princstr, def_realm);
+	    freeprinc++;
+	} else {
+	    fprintf(stderr, "%s: unable to figure out a principal name\n",
+		    whoami);
+	    exit(1);
+	}
+    }
+
+    retval = krb5_klog_init(context, "admin_server", whoami, 0);
+    if (retval) {
+	com_err(whoami, retval, "while setting up logging");
+	exit(1);
+    }
+
+    /*
+     * Initialize the kadm5 connection.  If we were given a ccache,
+     * use it.  Otherwise, use/prompt for the password.
+     */
+    if (ccache_name) {
+	 printf("Authenticating as principal %s with existing credentials.\n",
+		princstr);
+	 retval = kadm5_init_with_creds(princstr, cc,
+					svcname, 
+					¶ms,
+					KADM5_STRUCT_VERSION,
+					KADM5_API_VERSION_2,
+					db_args,
+					&handle);
+    } else if (use_keytab) {
+	 if (keytab_name)
+	     printf("Authenticating as principal %s with keytab %s.\n",
+		    princstr, keytab_name);
+	 else
+	     printf("Authenticating as principal %s with default keytab.\n",
+		    princstr);
+	 retval = kadm5_init_with_skey(princstr, keytab_name,
+				       svcname, 
+				       ¶ms,
+				       KADM5_STRUCT_VERSION,
+				       KADM5_API_VERSION_2,
+				       db_args,
+				       &handle);
+    } else {
+	 printf("Authenticating as principal %s with password.\n",
+		princstr);
+	 retval = kadm5_init_with_password(princstr, password,
+					   svcname, 
+					   ¶ms,
+					   KADM5_STRUCT_VERSION,
+					   KADM5_API_VERSION_2,
+					   db_args,
+					   &handle);
+    }
+    if (retval) {
+	com_err(whoami, retval, "while initializing %s interface", whoami);
+	if (retval == KADM5_BAD_CLIENT_PARAMS ||
+	    retval == KADM5_BAD_SERVER_PARAMS)
+	     usage();
+	exit(1);
+    }
+    if (freeprinc)
+	free(princstr);
+
+    if( db_name )
+	free(db_name), db_name=NULL;
+
+    if( db_args )
+	free(db_args), db_args=NULL;
+
+    if ((retval = krb5_cc_close(context, cc))) {
+	 com_err(whoami, retval, "while closing ccache %s",
+		 ccache_name);
+	 exit(1);
+    }
+
+    /* register the WRFILE keytab type and set it as the default */
+    {
+#define DEFAULT_KEYTAB "WRFILE:/etc/krb5.keytab"
+	 /* XXX krb5_defkeyname is an internal library global and
+            should go away */
+	 extern char *krb5_defkeyname;
+	 krb5_defkeyname = DEFAULT_KEYTAB;
+    }
+    
+    return query;
+}
+
+int quit()
+{
+    kadm5_ret_t retval;
+
+    if (locked) {
+	retval = kadm5_unlock(handle);
+	if (retval) {
+	    com_err("quit", retval, "while unlocking locked database");
+	    return 1;
+	}
+	locked = 0;
+    }
+
+     kadm5_destroy(handle);
+     if (ccache_name != NULL) {
+	  fprintf(stderr,
+		  "\n\a\a\aAdministration credentials NOT DESTROYED.\n");
+     }
+
+     /* insert more random cleanup here */
+     krb5_klog_close(context);
+     krb5_free_context(context);
+     return 0;
+}
+
+void kadmin_lock(argc, argv)
+    int argc;
+    char *argv[];
+{
+    kadm5_ret_t retval;
+
+    if (locked)
+	return;
+    retval = kadm5_lock(handle);
+    if (retval) {
+	com_err("lock", retval, "");
+	return;
+    }
+    locked = 1;
+}
+
+void kadmin_unlock(argc, argv)
+    int argc;
+    char *argv[];
+{
+    kadm5_ret_t retval;
+
+    if (!locked)
+	return;
+    retval = kadm5_lock(handle);
+    if (retval) {
+	com_err("unlock", retval, "");
+	return;
+    }
+    locked = 0;
+}
+
+void kadmin_delprinc(argc, argv)
+    int argc;
+    char *argv[];
+{
+    kadm5_ret_t retval;
+    krb5_principal princ;
+    char *canon;
+    char reply[5];
+    
+    if (! (argc == 2 ||
+	   (argc == 3 && !strcmp("-force", argv[1])))) {
+	fprintf(stderr, "usage: delete_principal [-force] principal\n");
+	return;
+    }
+    retval = kadmin_parse_name(argv[argc - 1], &princ);
+    if (retval) {
+	com_err("delete_principal", retval, "while parsing principal name");
+	return;
+    }
+    retval = krb5_unparse_name(context, princ, &canon);
+    if (retval) {
+	com_err("delete_principal", retval,
+		"while canonicalizing principal");
+	krb5_free_principal(context, princ);
+	return;
+    }
+    if (argc == 2) {
+	printf("Are you sure you want to delete the principal \"%s\"? (yes/no): ", canon);
+	fgets(reply, sizeof (reply), stdin);
+	if (strcmp("yes\n", reply)) {
+	    fprintf(stderr, "Principal \"%s\" not deleted\n", canon);
+	    free(canon);
+	    krb5_free_principal(context, princ);
+	    return;
+	}
+    }
+    retval = kadm5_delete_principal(handle, princ);
+    krb5_free_principal(context, princ);
+    if (retval) {
+	com_err("delete_principal", retval,
+		"while deleteing principal \"%s\"", canon);
+	free(canon);
+	return;
+    }
+    printf("Principal \"%s\" deleted.\nMake sure that you have removed this principal from all ACLs before reusing.\n", canon);
+    free(canon);
+    return;
+}
+
+void kadmin_cpw(argc, argv)
+    int argc;
+    char *argv[];
+{
+    kadm5_ret_t retval;
+    static char newpw[1024];
+    static char prompt1[1024], prompt2[1024];
+    char *canon;
+    char *pwarg = NULL;
+    int n_ks_tuple = 0, randkey = 0;
+    krb5_boolean keepold = FALSE;
+    krb5_key_salt_tuple *ks_tuple = NULL;
+    krb5_principal princ;
+    char **db_args = NULL;
+    int db_args_size = 0;
+
+    
+    if (argc < 2) {
+	 goto usage;
+    }
+    for (argv++, argc--; argc > 1; argc--, argv++) {
+	if (!strcmp("-x", *argv)) {
+	    argc--;
+	    if( argc < 1 ) {
+		fprintf( stderr, "change_password: missing db argument\n");
+		goto usage;
+	    }
+	    db_args_size++;
+	    {
+		char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
+		if( temp == NULL )
+		{
+		    fprintf(stderr,"change_password: Not enough memory\n");
+		    free( db_args ), db_args = NULL;
+		    exit(1);
+		}
+
+		db_args = temp;
+	    }
+	    db_args[db_args_size-1] = *++argv;
+	    db_args[db_args_size]   = NULL;
+	    continue;
+	}
+	if (!strcmp("-pw", *argv)) {
+	    argc--;
+	    if (argc < 1) {
+		fprintf(stderr, "change_password: missing password arg\n");
+		goto usage;
+	    }
+	    pwarg = *++argv;
+	    continue;
+	}
+	if (!strcmp("-randkey", *argv)) {
+	    randkey++;
+	    continue;
+	}
+	if (!strcmp("-keepold", *argv)) {
+	    keepold = TRUE;
+	    continue;
+	}
+	if (!strcmp("-e", *argv)) {
+	    argc--;
+	    if (argc < 1) {
+		fprintf(stderr,
+			"change_password: missing keysaltlist arg\n");
+		goto usage;
+	    }
+	    retval = krb5_string_to_keysalts(*++argv, ", \t", ":.-", 0,
+					     &ks_tuple, &n_ks_tuple);
+	    if (retval) {
+		com_err("change_password", retval,
+			"while parsing keysalts %s", *argv);
+		return;
+	    }
+	    continue;
+	}
+	goto usage;
+    }
+    retval = kadmin_parse_name(*argv, &princ);
+    if (retval) {
+	com_err("change_password", retval, "while parsing principal name");
+	if (ks_tuple != NULL)
+	    free(ks_tuple);
+	if( db_args ) free(db_args);
+	return;
+    }
+    retval = krb5_unparse_name(context, princ, &canon);
+    if (retval) {
+	com_err("change_password", retval, "while canonicalizing principal");
+	krb5_free_principal(context, princ);
+	if (ks_tuple != NULL)
+	    free(ks_tuple);
+	if( db_args ) free(db_args);
+	return;
+    }
+    if (pwarg != NULL) {
+	if (keepold || ks_tuple != NULL) {
+	    retval = kadm5_chpass_principal_3(handle, princ, keepold,
+					      n_ks_tuple, ks_tuple, pwarg);
+	    if (ks_tuple != NULL)
+		free(ks_tuple);
+	} else {
+	    retval = kadm5_chpass_principal(handle, princ, pwarg);
+	}
+	krb5_free_principal(context, princ);
+	if (retval) {
+	    com_err("change_password", retval,
+		    "while changing password for \"%s\".", canon);
+	    free(canon);
+	    if( db_args ) free(db_args);
+	    return;
+	}
+	printf("Password for \"%s\" changed.\n", canon);
+	free(canon);
+	if( db_args ) free(db_args);
+	return;
+    } else if (randkey) {
+	if (keepold || ks_tuple != NULL) {
+	    retval = kadm5_randkey_principal_3(handle, princ, keepold,
+					       n_ks_tuple, ks_tuple,
+					       NULL, NULL);
+	    if (ks_tuple != NULL)
+		free(ks_tuple);
+	} else {
+	    retval = kadm5_randkey_principal(handle, princ, NULL, NULL);
+	}
+	krb5_free_principal(context, princ);
+	if (retval) {
+	    com_err("change_password", retval,
+		    "while randomizing key for \"%s\".", canon);
+	    free(canon);
+	    if( db_args ) free(db_args);
+	    return;
+	}
+	printf("Key for \"%s\" randomized.\n", canon);
+	free(canon);
+	if( db_args ) free(db_args);
+	return;
+    } else if (argc == 1) {
+	unsigned int i = sizeof (newpw) - 1;
+	
+	sprintf(prompt1, "Enter password for principal \"%.900s\"",
+		*argv);
+	sprintf(prompt2,
+		"Re-enter password for principal \"%.900s\"",
+		*argv);
+	retval = krb5_read_password(context, prompt1, prompt2,
+				    newpw, &i);
+	if (retval) {
+	    com_err("change_password", retval,
+		    "while reading password for \"%s\".", canon);
+	    free(canon);
+	    if (ks_tuple != NULL)
+		free(ks_tuple);
+	    krb5_free_principal(context, princ);
+	    if( db_args ) free(db_args);
+	    return;
+	}
+	if (keepold || ks_tuple != NULL) {
+	    retval = kadm5_chpass_principal_3(handle, princ, keepold,
+					      n_ks_tuple, ks_tuple,
+					      newpw);
+	    if (ks_tuple != NULL)
+		free(ks_tuple);
+	} else {
+	    retval = kadm5_chpass_principal(handle, princ, newpw);
+	}
+	krb5_free_principal(context, princ);
+	memset(newpw, 0, sizeof (newpw));
+	if (retval) {
+	    com_err("change_password", retval,
+		    "while changing password for \"%s\".", canon);
+	    free(canon);
+	    if( db_args ) free(db_args);
+	    return;
+	}
+	printf("Password for \"%s\" changed.\n", canon);
+	free(canon);
+	if( db_args ) free(db_args);
+	return;
+   } else {
+	free(canon);
+	krb5_free_principal(context, princ);
+   usage:
+	if( db_args ) free(db_args);
+	if (ks_tuple != NULL)
+	    free(ks_tuple);
+	fprintf(stderr,
+		"usage: change_password [-randkey] [-keepold] "
+		"[-e keysaltlist] [-pw password] "
+		"principal\n");
+	return;
+   }
+}
+
+static void
+kadmin_free_tl_data( kadm5_principal_ent_t princ )
+{
+    krb5_tl_data *tl_data = princ->tl_data;
+    int n_tl_data         = princ->n_tl_data;
+    int i;
+
+    princ->n_tl_data = 0;
+    princ->tl_data   = NULL;
+
+    for( i = 0; tl_data && (i < n_tl_data); i++ )
+    {
+	krb5_tl_data *next = tl_data->tl_data_next;
+	if( tl_data->tl_data_contents )
+	    free( tl_data->tl_data_contents );
+	free( tl_data );
+	tl_data = next;
+    }
+}
+
+#define KRB5_TL_DB_ARGS 0x7fff
+static int 
+kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, randkey,
+			ks_tuple, n_ks_tuple, caller)
+    int argc;
+    char *argv[];
+    kadm5_principal_ent_t oprinc;
+    long *mask;
+    char **pass;
+    int *randkey;
+    krb5_key_salt_tuple **ks_tuple;
+    int *n_ks_tuple;
+    char *caller;
+{
+    int i, j, attrib_set;
+    time_t date;
+    time_t now;
+    krb5_error_code retval;
+    krb5_tl_data *tl_data, *tail = NULL;
+    
+    *mask = 0;
+    *pass = NULL;
+    *n_ks_tuple = 0;
+    *ks_tuple = NULL;
+    time(&now);
+    *randkey = 0;
+    for (i = 1; i < argc - 1; i++) {
+	attrib_set = 0;
+	if (strlen(argv[i]) == 2 &&
+	    !strcmp("-x",argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+
+	    tl_data = malloc( sizeof(krb5_tl_data) );
+	    if( tl_data == NULL )
+	    {
+		fprintf(stderr, "Not enough memory\n");
+		return ENOMEM;
+	    }
+
+	    memset( tl_data, 0, sizeof(krb5_tl_data));
+	    tl_data->tl_data_type = KRB5_TL_DB_ARGS;
+	    tl_data->tl_data_length  = strlen(argv[i])+1;
+	    tl_data->tl_data_contents = strdup(argv[i]);
+
+	    if( tail )
+	    {
+		tail->tl_data_next = tl_data;
+	    }
+	    else
+	    {
+		oprinc->tl_data = tl_data;
+	    }
+	    tail = tl_data;
+	    oprinc->n_tl_data++;
+	    
+	    if( tl_data->tl_data_contents == NULL )
+	    {
+		fprintf(stderr, "Not enough memory\n");
+		return ENOMEM;
+	    }
+	    *mask |= KADM5_TL_DATA;
+	    continue;
+	}
+	if (strlen(argv[i]) == 7 &&
+	    !strcmp("-expire", argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		date = get_date(argv[i]);
+ 		if (date == (time_t)-1) {
+		     fprintf(stderr, "Invalid date specification \"%s\".\n",
+			     argv[i]);
+		     return -1;
+ 		}
+		oprinc->princ_expire_time = date;
+		*mask |= KADM5_PRINC_EXPIRE_TIME;
+		continue;
+	    }
+	}
+	if (strlen(argv[i]) == 9 &&
+	    !strcmp("-pwexpire", argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		date = get_date(argv[i]);
+ 		if (date == (time_t)-1) {
+		     fprintf(stderr, "Invalid date specification \"%s\".\n",
+			     argv[i]);
+		     return -1;
+ 		}
+		oprinc->pw_expiration = date;
+		*mask |= KADM5_PW_EXPIRATION;
+		continue;
+	    }
+	}
+	if (strlen(argv[i]) == 8 &&
+	    !strcmp("-maxlife", argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		date = get_date(argv[i]);
+ 		if (date == (time_t)-1) {
+		     fprintf(stderr, "Invalid date specification \"%s\".\n",
+			     argv[i]);
+		     return -1;
+ 		}
+		oprinc->max_life = date - now;
+		*mask |= KADM5_MAX_LIFE;
+		continue;
+	    }
+	}
+	if (strlen(argv[i]) == 13 &&
+	    !strcmp("-maxrenewlife", argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		date = get_date(argv[i]);
+ 		if (date == (time_t)-1) {
+		     fprintf(stderr, "Invalid date specification \"%s\".\n",
+			     argv[i]);
+		     return -1;
+ 		}
+		oprinc->max_renewable_life = date - now;
+		*mask |= KADM5_MAX_RLIFE;
+		continue;
+	    }
+	}
+	if (strlen(argv[i]) == 5 &&
+	    !strcmp("-kvno", argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		oprinc->kvno = atoi(argv[i]);
+		*mask |= KADM5_KVNO;
+		continue;
+	    }
+	}
+	if (strlen(argv[i]) == 7 &&
+	    !strcmp("-policy", argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		oprinc->policy = argv[i];
+		*mask |= KADM5_POLICY;
+		continue;
+	    }
+	}
+	if (strlen(argv[i]) == 12 &&
+	    !strcmp("-clearpolicy", argv[i])) {
+	    oprinc->policy = NULL;
+	    *mask |= KADM5_POLICY_CLR;
+	    continue;
+	}
+	if (strlen(argv[i]) == 3 &&
+	    !strcmp("-pw", argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		*pass = argv[i];
+		continue;
+	    }
+	}
+	if (strlen(argv[i]) == 8 &&
+	    !strcmp("-randkey", argv[i])) {
+	    ++*randkey;
+	    continue;
+	}
+	if (!strcmp("-e", argv[i])) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		retval = krb5_string_to_keysalts(argv[i], ", \t", ":.-", 0,
+						 ks_tuple, n_ks_tuple);
+		if (retval) {
+		    com_err(caller, retval,
+			    "while parsing keysalts %s", argv[i]);
+		    return -1;
+		}
+	    }
+	    continue;
+	}
+	for (j = 0; j < sizeof (flags) / sizeof (struct pflag); j++) {
+	    if (strlen(argv[i]) == flags[j].flaglen + 1 &&
+		!strcmp(flags[j].flagname,
+			&argv[i][1] /* strip off leading + or - */)) {
+		if ((flags[j].set && argv[i][0] == '-') ||
+		    (!flags[j].set && argv[i][0] == '+')) {
+		    oprinc->attributes |= flags[j].theflag;
+		    *mask |= KADM5_ATTRIBUTES;
+		    attrib_set++;
+		    break;
+		} else if ((flags[j].set && argv[i][0] == '+') ||
+			   (!flags[j].set && argv[i][0] == '-')) {
+		    oprinc->attributes &= ~flags[j].theflag;
+		    *mask |= KADM5_ATTRIBUTES;
+		    attrib_set++;
+		    break;
+		} else {
+		    return -1;
+		}
+	    }
+	}
+	if (!attrib_set)
+	    return -1;		/* nothing was parsed */
+    }
+    if (i != argc - 1) {
+	return -1;
+    }
+    retval = kadmin_parse_name(argv[i], &oprinc->principal);
+    if (retval) {
+	com_err(caller, retval, "while parsing principal");
+	return -1;
+    }
+    return 0;
+}
+
+static void 
+kadmin_addprinc_usage(func)
+   char *func;
+{
+     fprintf(stderr, "usage: %s [options] principal\n", func);
+     fprintf(stderr, "\toptions are:\n");
+     fprintf(stderr, "\t\t[-x db_princ_args]* [-expire expdate] [-pwexpire pwexpdate] [-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] [-randkey] [-pw password]\n\t\t[-maxrenewlife maxrenewlife]\n\t\t[-e keysaltlist]\n\t\t[{+|-}attribute]\n");
+     fprintf(stderr, "\tattributes are:\n");
+     fprintf(stderr, "%s%s%s",
+	     "\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
+	     "\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n",
+	     "\t\trequires_hwauth needchange allow_svr password_changing_service\n"
+	     "\nwhere,\n\t[-x db_princ_args]* - any number of database specific arguments.\n"
+	     "\t\t\tLook at each database documentation for supported arguments\n");
+}
+
+static void 
+kadmin_modprinc_usage(func)
+   char *func;
+{
+     fprintf(stderr, "usage: %s [options] principal\n", func);
+     fprintf(stderr, "\toptions are:\n");
+     fprintf(stderr, "\t\t[-x db_princ_args]* [-expire expdate] [-pwexpire pwexpdate] [-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] [-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] [{+|-}attribute]\n");
+     fprintf(stderr, "\tattributes are:\n");
+     fprintf(stderr, "%s%s%s",
+	     "\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
+	     "\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n",
+	     "\t\trequires_hwauth needchange allow_svr password_changing_service\n"
+	     "\nwhere,\n\t[-x db_princ_args]* - any number of database specific arguments.\n"
+	     "\t\t\tLook at each database documentation for supported arguments\n"
+	     );
+}
+
+void kadmin_addprinc(argc, argv)
+    int argc;
+    char *argv[];
+{
+    kadm5_principal_ent_rec princ;
+    kadm5_policy_ent_rec defpol;
+    long mask;
+    int randkey = 0, i;
+    int n_ks_tuple;
+    krb5_key_salt_tuple *ks_tuple;
+    char *pass, *canon;
+    krb5_error_code retval;
+    static char newpw[1024], dummybuf[256];
+    static char prompt1[1024], prompt2[1024];
+
+    if (dummybuf[0] == 0) {
+	 for (i = 0; i < 256; i++)
+	      dummybuf[i] = (i+1) % 256;
+    }
+    
+    /* Zero all fields in request structure */
+    memset(&princ, 0, sizeof(princ));
+
+    princ.attributes = 0;
+    if (kadmin_parse_princ_args(argc, argv,
+				&princ, &mask, &pass, &randkey,
+				&ks_tuple, &n_ks_tuple,
+				"add_principal")) {
+	 kadmin_addprinc_usage("add_principal"); 
+	 kadmin_free_tl_data( &princ ); /* need to free ks_tuple also??? */
+	 return;
+    }
+
+    retval = krb5_unparse_name(context, princ.principal, &canon);
+    if (retval) {
+	com_err("add_principal",
+		retval, "while canonicalizing principal");
+	krb5_free_principal(context, princ.principal);
+	if (ks_tuple != NULL)
+	    free(ks_tuple);
+	kadmin_free_tl_data( &princ );
+	return;
+    }
+
+    /*
+     * If -policy was not specified, and -clearpolicy was not
+     * specified, and the policy "default" exists, assign it.  If
+     * -clearpolicy was specified, then KADM5_POLICY_CLR should be
+     * unset, since it is never valid for kadm5_create_principal.
+     */
+    if ((! (mask & KADM5_POLICY)) &&
+	(! (mask & KADM5_POLICY_CLR))) {
+	 if (! kadm5_get_policy(handle, "default", &defpol)) {
+	      fprintf(stderr,
+		"NOTICE: no policy specified for %s; assigning \"default\"\n",
+		      canon);
+	      princ.policy = "default";
+	      mask |= KADM5_POLICY;
+	      (void) kadm5_free_policy_ent(handle, &defpol);
+	 } else
+	      fprintf(stderr,
+	     "WARNING: no policy specified for %s; defaulting to no policy\n",
+		      canon);
+    }
+    mask &= ~KADM5_POLICY_CLR;
+    
+    if (randkey) {		/* do special stuff if -randkey specified */
+	princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; /* set notix */
+	mask |= KADM5_ATTRIBUTES;
+	pass = dummybuf;
+    } else if (pass == NULL) {
+	unsigned int sz = sizeof (newpw) - 1;
+	
+	sprintf(prompt1, "Enter password for principal \"%.900s\"",
+		canon);
+	sprintf(prompt2,
+		"Re-enter password for principal \"%.900s\"",
+		canon);
+	retval = krb5_read_password(context, prompt1, prompt2,
+				    newpw, &sz);
+	if (retval) {
+	    com_err("add_principal", retval,
+		    "while reading password for \"%s\".", canon);
+	    free(canon);
+	    krb5_free_principal(context, princ.principal);
+	    kadmin_free_tl_data( &princ );
+	    return;
+	}
+	pass = newpw;
+    }
+    mask |= KADM5_PRINCIPAL;
+    if (ks_tuple != NULL) {
+	retval = kadm5_create_principal_3(handle, &princ, mask,
+					  n_ks_tuple, ks_tuple, pass);
+    } else {
+	retval = kadm5_create_principal(handle, &princ, mask, pass);
+    }
+    if (retval) {
+	com_err("add_principal", retval, "while creating \"%s\".",
+		canon);
+	krb5_free_principal(context, princ.principal);
+	free(canon);
+	if (ks_tuple != NULL)
+	    free(ks_tuple);
+	kadmin_free_tl_data( &princ );
+	return;
+    }
+    if (randkey) {		/* more special stuff for -randkey */
+	if (ks_tuple != NULL) {
+	    retval = kadm5_randkey_principal_3(handle, princ.principal,
+					       FALSE,
+					       n_ks_tuple, ks_tuple,
+					       NULL, NULL);
+	} else {
+	    retval = kadm5_randkey_principal(handle, princ.principal,
+					     NULL, NULL);
+	}
+	if (retval) {
+	    com_err("add_principal", retval,
+		    "while randomizing key for \"%s\".", canon);
+	    krb5_free_principal(context, princ.principal);
+	    free(canon);
+	    if (ks_tuple != NULL)
+		free(ks_tuple);
+	    kadmin_free_tl_data( &princ );
+	    return;
+	}
+	princ.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX;	/* clear notix */
+	mask = KADM5_ATTRIBUTES;
+	retval = kadm5_modify_principal(handle, &princ, mask);
+	if (retval) {
+	    com_err("add_principal", retval,
+		    "while clearing DISALLOW_ALL_TIX for \"%s\".", canon);
+	    krb5_free_principal(context, princ.principal);
+	    free(canon);
+	    if (ks_tuple != NULL)
+		free(ks_tuple);
+	    kadmin_free_tl_data( &princ );
+	    return;
+	}
+    }
+    krb5_free_principal(context, princ.principal);
+    printf("Principal \"%s\" created.\n", canon);
+    if (ks_tuple != NULL)
+	free(ks_tuple);
+    free(canon);
+    kadmin_free_tl_data( &princ );
+
+}
+
+void kadmin_modprinc(argc, argv)
+    int argc;
+    char *argv[];
+{
+    kadm5_principal_ent_rec princ, oldprinc;
+    krb5_principal kprinc;
+    long mask;
+    krb5_error_code retval;
+    char *pass, *canon;
+    int randkey = 0;
+    int n_ks_tuple = 0;
+    krb5_key_salt_tuple *ks_tuple;
+
+    if (argc < 2) {
+	 kadmin_modprinc_usage("modify_principal");
+	 return;
+    }
+
+    memset(&oldprinc, 0, sizeof(oldprinc));
+    memset(&princ, 0, sizeof(princ));
+
+    retval = kadmin_parse_name(argv[argc - 1], &kprinc);
+    if (retval) {
+	com_err("modify_principal", retval, "while parsing principal");
+	return;
+    }
+    retval = krb5_unparse_name(context, kprinc, &canon);
+    if (retval) {
+	com_err("modify_principal", retval,
+		"while canonicalizing principal");
+	krb5_free_principal(context, kprinc);
+	return;
+    }
+    retval = kadm5_get_principal(handle, kprinc, &oldprinc,
+				 KADM5_PRINCIPAL_NORMAL_MASK);
+    krb5_free_principal(context, kprinc);
+    if (retval) {
+	com_err("modify_principal", retval, "while getting \"%s\".",
+		canon);
+	free(canon);
+	return;
+    }
+    princ.attributes = oldprinc.attributes;
+    kadm5_free_principal_ent(handle, &oldprinc);
+    retval = kadmin_parse_princ_args(argc, argv,
+				     &princ, &mask,
+				     &pass, &randkey,
+				     &ks_tuple, &n_ks_tuple,
+				     "modify_principal");
+    if (ks_tuple != NULL) {
+	free(ks_tuple);
+	kadmin_modprinc_usage("modify_principal");
+	free(canon);
+	kadmin_free_tl_data(&princ);
+	return;
+    }
+    if (retval) {
+	kadmin_modprinc_usage("modify_principal");
+	free(canon);
+	kadmin_free_tl_data(&princ);
+	return;
+    }
+    if (randkey) {
+	fprintf(stderr, "modify_principal: -randkey not allowed\n");
+	krb5_free_principal(context, princ.principal);
+	free(canon);
+	kadmin_free_tl_data(&princ);
+	return;
+    }
+    if (pass) {
+	fprintf(stderr,
+		"modify_principal: -pw not allowed; use change_password\n");
+	krb5_free_principal(context, princ.principal);
+	free(canon);
+	kadmin_free_tl_data(&princ);
+	return;
+    }
+    retval = kadm5_modify_principal(handle, &princ, mask);
+    krb5_free_principal(context, princ.principal);
+    if (retval) {
+	com_err("modify_principal", retval,
+		"while modifying \"%s\".", canon);
+	free(canon);
+	kadmin_free_tl_data(&princ);
+	return;
+    }
+    printf("Principal \"%s\" modified.\n", canon);
+    kadmin_free_tl_data(&princ);
+    free(canon);
+}
+
+void kadmin_getprinc(argc, argv)
+    int argc;
+    char *argv[];
+{
+    kadm5_principal_ent_rec dprinc;
+    krb5_principal princ;
+    krb5_error_code retval;
+    char *canon, *modcanon;
+    int i;
+    
+    if (! (argc == 2 ||
+	   (argc == 3 && !strcmp("-terse", argv[1])))) {
+	fprintf(stderr, "usage: get_principal [-terse] principal\n");
+	return;
+    }
+
+
+    memset(&dprinc, 0, sizeof(dprinc));
+    memset(&princ, 0, sizeof(princ));
+
+    retval = kadmin_parse_name(argv[argc - 1], &princ);
+    if (retval) {
+	com_err("get_principal", retval, "while parsing principal");
+	return;
+    }
+    retval = krb5_unparse_name(context, princ, &canon);
+    if (retval) {
+	com_err("get_principal", retval, "while canonicalizing principal");
+	krb5_free_principal(context, princ);
+	return;
+    }
+    retval = kadm5_get_principal(handle, princ, &dprinc,
+				 KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA);
+    krb5_free_principal(context, princ);
+    if (retval) {
+	com_err("get_principal", retval, "while retrieving \"%s\".", canon);
+	free(canon);
+	return;
+    }
+    retval = krb5_unparse_name(context, dprinc.mod_name, &modcanon);
+    if (retval) {
+	com_err("get_principal", retval, "while unparsing modname");
+	kadm5_free_principal_ent(handle, &dprinc);
+	free(canon);
+	return;
+    }
+    if (argc == 2) {
+	printf("Principal: %s\n", canon);
+	printf("Expiration date: %s\n", dprinc.princ_expire_time ?
+	       strdate(dprinc.princ_expire_time) : "[never]");
+	printf("Last password change: %s\n", dprinc.last_pwd_change ? 
+	       strdate(dprinc.last_pwd_change) : "[never]");
+	printf("Password expiration date: %s\n",
+	       dprinc.pw_expiration ?
+	       strdate(dprinc.pw_expiration) : "[none]");
+	printf("Maximum ticket life: %s\n", strdur(dprinc.max_life));
+	printf("Maximum renewable life: %s\n", strdur(dprinc.max_renewable_life));
+	printf("Last modified: %s (%s)\n", strdate(dprinc.mod_date), modcanon);
+	printf("Last successful authentication: %s\n",
+	       dprinc.last_success ? strdate(dprinc.last_success) :
+	       "[never]"); 
+	printf("Last failed authentication: %s\n",
+	       dprinc.last_failed ? strdate(dprinc.last_failed) :
+	       "[never]");
+	printf("Failed password attempts: %d\n",
+	       dprinc.fail_auth_count);
+	printf("Number of keys: %d\n", dprinc.n_key_data);
+	for (i = 0; i < dprinc.n_key_data; i++) {
+	     krb5_key_data *key_data = &dprinc.key_data[i];
+	     char enctype[BUFSIZ], salttype[BUFSIZ];
+	     
+	     if (krb5_enctype_to_string(key_data->key_data_type[0],
+					enctype, sizeof(enctype)))
+		  sprintf(enctype, "<Encryption type 0x%x>",
+			  key_data->key_data_type[0]);
+	     printf("Key: vno %d, %s, ", key_data->key_data_kvno, enctype);
+	     if (key_data->key_data_ver > 1) {
+		  if (krb5_salttype_to_string(key_data->key_data_type[1],
+					      salttype, sizeof(salttype)))
+		       sprintf(salttype, "<Salt type 0x%x>",
+			       key_data->key_data_type[1]);
+		  printf("%s\n", salttype);
+	     } else
+		  printf("no salt\n");
+	}
+	
+	printf("Attributes:");
+	for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
+	    if (dprinc.attributes & (krb5_flags) 1 << i)
+		printf(" %s", prflags[i]);
+	}
+	printf("\n");
+	printf("Policy: %s\n", dprinc.policy ? dprinc.policy : "[none]");
+    } else {
+	printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\""
+	       "\t%d\t%d\t%d\t%d\t%d",
+	       canon, dprinc.princ_expire_time, dprinc.last_pwd_change,
+	       dprinc.pw_expiration, dprinc.max_life, modcanon,
+	       dprinc.mod_date, dprinc.attributes, dprinc.kvno,
+	       dprinc.mkvno, dprinc.policy ? dprinc.policy : "[none]",
+	       dprinc.max_renewable_life, dprinc.last_success,
+	       dprinc.last_failed, dprinc.fail_auth_count,
+	       dprinc.n_key_data);
+	for (i = 0; i < dprinc.n_key_data; i++)
+	     printf("\t%d\t%d\t%d\t%d",
+		    dprinc.key_data[i].key_data_ver,
+		    dprinc.key_data[i].key_data_kvno,
+		    dprinc.key_data[i].key_data_type[0],
+		    dprinc.key_data[i].key_data_type[1]);
+	printf("\n");
+   }
+    free(modcanon);
+    kadm5_free_principal_ent(handle, &dprinc);
+    free(canon);
+}
+
+void kadmin_getprincs(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    char *expr, **names;
+    int i, count;
+
+    expr = NULL;
+    if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) {
+	fprintf(stderr, "usage: get_principals [expression]\n");
+	return;
+    }
+    retval = kadm5_get_principals(handle, expr, &names, &count);
+    if (retval) {
+	com_err("get_principals", retval, "while retrieving list.");
+	return;
+    }
+    for (i = 0; i < count; i++)
+	 printf("%s\n", names[i]);
+    kadm5_free_name_list(handle, names, count);
+}
+
+static int 
+kadmin_parse_policy_args(argc, argv, policy, mask, caller)
+    int argc;
+    char *argv[];
+    kadm5_policy_ent_t policy;
+    long *mask;
+    char *caller;
+{
+    int i;
+    time_t now;
+    time_t date;
+
+    time(&now);
+    *mask = 0;
+    for (i = 1; i < argc - 1; i++) {
+	if (strlen(argv[i]) == 8 &&
+	    !strcmp(argv[i], "-maxlife")) {
+	    if (++i > argc -2)
+		return -1;
+	    else {
+		date = get_date(argv[i]);
+ 		if (date == (time_t)-1) {
+		     fprintf(stderr, "Invalid date specification \"%s\".\n",
+			     argv[i]);
+		     return -1;
+ 		}
+		policy->pw_max_life = date - now;
+		*mask |= KADM5_PW_MAX_LIFE;
+		continue;
+	    }
+	} else if (strlen(argv[i]) == 8 &&
+		   !strcmp(argv[i], "-minlife")) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		date = get_date(argv[i]);
+ 		if (date == (time_t)-1) {
+		     fprintf(stderr, "Invalid date specification \"%s\".\n",
+			     argv[i]);
+		     return -1;
+ 		}
+		policy->pw_min_life = date - now;
+		*mask |= KADM5_PW_MIN_LIFE;
+		continue;
+	    }
+	} else if (strlen(argv[i]) == 10 &&
+	    !strcmp(argv[i], "-minlength")) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		policy->pw_min_length = atoi(argv[i]);
+		*mask |= KADM5_PW_MIN_LENGTH;
+		continue;
+	    }
+	} else if (strlen(argv[i]) == 11 &&
+		   !strcmp(argv[i], "-minclasses")) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		policy->pw_min_classes = atoi(argv[i]);
+		*mask |= KADM5_PW_MIN_CLASSES;
+		continue;
+	    }
+	} else if (strlen(argv[i]) == 8 &&
+		   !strcmp(argv[i], "-history")) {
+	    if (++i > argc - 2)
+		return -1;
+	    else {
+		policy->pw_history_num = atoi(argv[i]);
+		*mask |= KADM5_PW_HISTORY_NUM;
+		continue;
+	    }
+	} else
+	    return -1;
+    }
+    if (i != argc -1) {
+	fprintf(stderr, "%s: parser lost count!\n", caller);
+	return -1;
+    } else
+	return 0;
+}
+
+static void 
+kadmin_addmodpol_usage(func)
+   char *func;
+{
+     fprintf(stderr, "usage; %s [options] policy\n", func);
+     fprintf(stderr, "\toptions are:\n");
+     fprintf(stderr, "\t\t[-maxlife time] [-minlife time] [-minlength length]\n\t\t[-minclasses number] [-history number]\n");
+}
+
+void kadmin_addpol(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    long mask;
+    kadm5_policy_ent_rec policy;
+
+    memset(&policy, 0, sizeof(policy));
+    if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) {
+	 kadmin_addmodpol_usage("add_policy");
+	 return;
+    } else {
+	policy.policy = argv[argc - 1];
+	mask |= KADM5_POLICY;
+	retval = kadm5_create_policy(handle, &policy, mask);
+	if (retval) {
+	    com_err("add_policy", retval, "while creating policy \"%s\".",
+		    policy.policy);
+	    return;
+	}
+    }
+    return;
+}
+
+void kadmin_modpol(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    long mask;
+    kadm5_policy_ent_rec policy;
+
+    memset(&policy, 0, sizeof(policy));
+    if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
+				 "modify_policy")) {
+	kadmin_addmodpol_usage("modify_policy");
+	return;
+    } else {
+	policy.policy = argv[argc - 1];
+	retval = kadm5_modify_policy(handle, &policy, mask);
+	if (retval) {
+	    com_err("modify_policy", retval, "while modifying policy \"%s\".",
+		    policy.policy);
+	    return;
+	}
+    }
+    return;
+}
+
+void kadmin_delpol(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    char reply[5];
+    
+    if (! (argc == 2 ||
+	   (argc == 3 && !strcmp("-force", argv[1])))) {
+	fprintf(stderr, "usage: delete_policy [-force] policy\n");
+	return;
+    }
+    if (argc == 2) {
+	printf("Are you sure you want to delete the policy \"%s\"? (yes/no): ", argv[1]);
+	fgets(reply, sizeof (reply), stdin);
+	if (strcmp("yes\n", reply)) {
+	    fprintf(stderr, "Policy \"%s\" not deleted.\n", argv[1]);
+	    return;
+	}
+    }
+    retval = kadm5_delete_policy(handle, argv[argc - 1]);
+    if (retval) {
+	com_err("delete_policy:", retval, "while deleting policy \"%s\"",
+		argv[argc - 1]);
+	return;
+    }
+    return;
+}
+
+void kadmin_getpol(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    kadm5_policy_ent_rec policy;
+    
+    if (! (argc == 2 ||
+	   (argc == 3 && !strcmp("-terse", argv[1])))) {
+	fprintf(stderr, "usage: get_policy [-terse] policy\n");
+	return;
+    }
+    retval = kadm5_get_policy(handle, argv[argc - 1], &policy);
+    if (retval) {
+	com_err("get_policy", retval, "while retrieving policy \"%s\".",
+		argv[argc - 1]);
+	return;
+    }
+    if (argc == 2) {
+	printf("Policy: %s\n", policy.policy);
+	printf("Maximum password life: %ld\n", policy.pw_max_life);
+	printf("Minimum password life: %ld\n", policy.pw_min_life);
+	printf("Minimum password length: %ld\n", policy.pw_min_length);
+	printf("Minimum number of password character classes: %ld\n",
+	       policy.pw_min_classes);
+	printf("Number of old keys kept: %ld\n", policy.pw_history_num);
+	printf("Reference count: %ld\n", policy.policy_refcnt);
+    } else {
+	printf("\"%s\"\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\n",
+	       policy.policy, policy.pw_max_life, policy.pw_min_life,
+	       policy.pw_min_length, policy.pw_min_classes,
+	       policy.pw_history_num, policy.policy_refcnt);
+    }
+    kadm5_free_policy_ent(handle, &policy);
+    return;
+}
+
+void kadmin_getpols(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    char *expr, **names;
+    int i, count;
+
+    expr = NULL;
+    if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) {
+	fprintf(stderr, "usage: get_policies [expression]\n");
+	return;
+    }
+    retval = kadm5_get_policies(handle, expr, &names, &count);
+    if (retval) {
+	com_err("get_policies", retval, "while retrieving list.");
+	return;
+    }
+    for (i = 0; i < count; i++)
+	 printf("%s\n", names[i]);
+    kadm5_free_name_list(handle, names, count);
+}
+
+void kadmin_getprivs(argc, argv)
+    int argc;
+    char *argv[];
+{
+    static char *privs[] = {"GET", "ADD", "MODIFY", "DELETE"};
+    krb5_error_code retval;
+    int i;
+    long plist;
+
+    if (argc != 1) {
+	fprintf(stderr, "usage: get_privs\n");
+	return;
+    }
+    retval = kadm5_get_privs(handle, &plist);
+    if (retval) {
+	com_err("get_privs", retval, "while retrieving privileges");
+	return;
+    }
+    printf("current privileges:");
+    for (i = 0; i < sizeof (privs) / sizeof (char *); i++) {
+	if (plist & 1 << i)
+	    printf(" %s", privs[i]);
+    }
+    printf("\n");
+    return;
+}
diff --git a/mechglue/src/kadmin/cli/kadmin.h b/mechglue/src/kadmin/cli/kadmin.h
new file mode 100644
index 000000000..0b6c8eae5
--- /dev/null
+++ b/mechglue/src/kadmin/cli/kadmin.h
@@ -0,0 +1,73 @@
+/*
+ * kadmin/cli/kadmin.h
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Prototypes for kadmin functions called from SS library.
+ */
+
+#ifndef __KADMIN_H__
+#define __KADMIN_H__
+
+/* It would be nice if ss produced a header file we could reference */
+extern char *kadmin_startup(int argc, char *argv[]);
+extern int quit (void);
+extern void kadmin_lock(int argc, char *argv[]);
+extern void kadmin_unlock(int argc, char *argv[]);
+extern void kadmin_delprinc(int argc, char *argv[]);
+extern void kadmin_cpw(int argc, char *argv[]);
+extern void kadmin_addprinc(int argc, char *argv[]);
+extern void kadmin_modprinc(int argc, char *argv[]);
+extern void kadmin_getprinc(int argc, char *argv[]);
+extern void kadmin_getprincs(int argc, char *argv[]);
+extern void kadmin_addpol(int argc, char *argv[]);
+extern void kadmin_modpol(int argc, char *argv[]);
+extern void kadmin_delpol(int argc, char *argv[]);
+extern void kadmin_getpol(int argc, char *argv[]);
+extern void kadmin_getpols(int argc, char *argv[]);
+extern void kadmin_getprivs(int argc, char *argv[]);
+extern void kadmin_keytab_add(int argc, char *argv[]);
+extern void kadmin_keytab_remove(int argc, char *argv[]);
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+extern time_t get_date(char *);
+
+/* Yucky global variables */
+extern krb5_context context;
+extern char *krb5_defkeyname;	 
+extern char *whoami;
+extern void *handle;
+
+#endif /* __KADMIN_H__ */
+
diff --git a/mechglue/src/kadmin/cli/kadmin.local.M b/mechglue/src/kadmin/cli/kadmin.local.M
new file mode 100644
index 000000000..cf447d7e6
--- /dev/null
+++ b/mechglue/src/kadmin/cli/kadmin.local.M
@@ -0,0 +1 @@
+.so man8/kadmin.8
diff --git a/mechglue/src/kadmin/cli/kadmin_ct.ct b/mechglue/src/kadmin/cli/kadmin_ct.ct
new file mode 100644
index 000000000..05a4efb84
--- /dev/null
+++ b/mechglue/src/kadmin/cli/kadmin_ct.ct
@@ -0,0 +1,85 @@
+# Copyright 1994 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+# 
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+# 
+# Command table for kadmin CLI for OVSecure
+#
+
+command_table kadmin_cmds;
+
+request kadmin_addprinc, "Add principal",
+	add_principal, addprinc, ank;
+
+request kadmin_delprinc, "Delete principal",
+	delete_principal, delprinc;
+
+request kadmin_modprinc, "Modify principal",
+	modify_principal, modprinc;
+
+request kadmin_cpw, "Change password",
+	change_password, cpw;
+
+request kadmin_getprinc, "Get principal",
+	get_principal, getprinc;
+
+request kadmin_getprincs, "List principals",
+	list_principals, listprincs, get_principals, getprincs;
+
+request kadmin_addpol, "Add policy",
+	add_policy, addpol;
+
+request kadmin_modpol, "Modify policy",
+	modify_policy, modpol;
+
+request kadmin_delpol, "Delete policy",
+	delete_policy, delpol;
+
+request kadmin_getpol, "Get policy",
+	get_policy, getpol;
+
+request kadmin_getpols, "List policies",
+	list_policies, listpols, get_policies, getpols;
+
+request kadmin_getprivs, "Get privileges",
+	get_privs, getprivs;
+
+request kadmin_keytab_add, "Add entry(s) to a keytab",
+	ktadd, xst;
+
+request kadmin_keytab_remove, "Remove entry(s) from a keytab",
+	ktremove, ktrem;
+
+request kadmin_lock, "Lock database exclusively (use with extreme caution!)",
+	lock;
+
+request kadmin_unlock, "Release exclusive database lock",
+	unlock;
+
+# list_requests is generic -- unrelated to Kerberos
+request	ss_list_requests, "List available requests.",
+	list_requests, lr, "?";
+
+request	ss_quit, "Exit program.",
+	quit, exit, q;
+
+end;
+
diff --git a/mechglue/src/kadmin/cli/keytab.c b/mechglue/src/kadmin/cli/keytab.c
new file mode 100644
index 000000000..77034fedd
--- /dev/null
+++ b/mechglue/src/kadmin/cli/keytab.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <krb5/adm_proto.h>
+#include "kadmin.h"
+
+static int add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,
+			 krb5_boolean keepold,
+			 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
+			 char *princ_str);
+static int remove_principal(char *keytab_str, krb5_keytab keytab, char
+			    *princ_str, char *kvno_str);
+static char *etype_string(krb5_enctype enctype);
+
+static int quiet;
+
+static void add_usage()
+{
+     fprintf(stderr, "Usage: ktadd [-k[eytab] keytab] [-q] [-e keysaltlist] [principal | -glob princ-exp] [...]\n");
+}
+     
+static void rem_usage()
+{
+     fprintf(stderr, "Usage: ktremove [-k[eytab] keytab] [-q] principal [kvno|\"all\"|\"old\"]\n");
+}
+
+static int process_keytab(krb5_context my_context, char **keytab_str,
+		   krb5_keytab *keytab) 
+{
+     int code;
+     
+     if (*keytab_str == NULL) {
+	  /* XXX krb5_defkeyname is an internal library global and
+             should go away */
+	  if (! (*keytab_str = strdup(krb5_defkeyname))) {
+	       com_err(whoami, ENOMEM, "while creating keytab name");
+	       return 1;
+	  }
+	  code = krb5_kt_default(my_context, keytab);
+	  if (code != 0) {
+	       com_err(whoami, code, "while opening default keytab");
+	       free(*keytab_str);
+	       return 1;
+	  }
+     } else {
+	  if (strchr(*keytab_str, ':') != NULL) {
+	       *keytab_str = strdup(*keytab_str);
+	       if (*keytab_str == NULL) {
+		    com_err(whoami, ENOMEM, "while creating keytab name");
+		    return 1;
+	       }
+	  } else {
+	       char *tmp = *keytab_str;
+
+	       *keytab_str = (char *)
+		    malloc(strlen("WRFILE:")+strlen(tmp)+1);
+	       if (*keytab_str == NULL) {
+		    com_err(whoami, ENOMEM, "while creating keytab name");
+		    return 1;
+	       }
+	       sprintf(*keytab_str, "WRFILE:%s", tmp);
+	  }
+	  
+	  code = krb5_kt_resolve(my_context, *keytab_str, keytab);
+	  if (code != 0) {
+	       com_err(whoami, code, "while resolving keytab %s", *keytab_str);
+	       free(keytab_str);
+	       return 1;
+	  }
+     }
+     
+     return 0;
+}
+
+     
+void kadmin_keytab_add(int argc, char **argv)
+{
+     krb5_keytab keytab = 0;
+     char *keytab_str = NULL, **princs;
+     int code, num, i;
+     krb5_error_code retval;
+     int n_ks_tuple = 0;
+     krb5_boolean keepold = FALSE;
+     krb5_key_salt_tuple *ks_tuple = NULL;
+
+     argc--; argv++;
+     quiet = 0;
+     while (argc) {
+	  if (strncmp(*argv, "-k", 2) == 0) {
+	       argc--; argv++;
+	       if (!argc || keytab_str) {
+		    add_usage();
+		    return;
+	       }
+	       keytab_str = *argv;
+	  } else if (strcmp(*argv, "-q") == 0) {
+	       quiet++;
+	  } else if (strcmp(*argv, "-e") == 0) {
+	       argc--;
+	       if (argc < 1) {
+		    add_usage();
+		    return;
+	       }
+	       retval = krb5_string_to_keysalts(*++argv, ", \t", ":.-", 0,
+						&ks_tuple, &n_ks_tuple);
+	       if (retval) {
+		    com_err("ktadd", retval, "while parsing keysalts %s",
+			    *argv);
+
+		    return;
+	       }
+	  } else
+	       break;
+	  argc--; argv++;
+     }
+
+     if (argc == 0) {
+	  add_usage();
+	  return;
+     }
+
+     if (process_keytab(context, &keytab_str, &keytab))
+	  return;
+     
+     while (*argv) {
+	  if (strcmp(*argv, "-glob") == 0) {
+	       if (*++argv == NULL) {
+		    add_usage();
+		    break;
+	       }
+	       
+	       code = kadm5_get_principals(handle, *argv, &princs, &num);
+	       if (code) {
+		    com_err(whoami, code, "while expanding expression \"%s\".",
+			    *argv);
+		    argv++;
+		    continue;
+	       }
+	       
+	       for (i = 0; i < num; i++) 
+		    (void) add_principal(handle, keytab_str, keytab,
+					 keepold, n_ks_tuple, ks_tuple,
+					 princs[i]); 
+	       kadm5_free_name_list(handle, princs, num);
+	  } else
+	       (void) add_principal(handle, keytab_str, keytab,
+				    keepold, n_ks_tuple, ks_tuple,
+				    *argv);
+	  argv++;
+     }
+	  
+     code = krb5_kt_close(context, keytab);
+     if (code != 0)
+	  com_err(whoami, code, "while closing keytab");
+
+     free(keytab_str);
+}
+
+void kadmin_keytab_remove(int argc, char **argv)
+{
+     krb5_keytab keytab = 0;
+     char *keytab_str = NULL;
+     int code;
+
+     argc--; argv++;
+     quiet = 0;
+     while (argc) {
+	  if (strncmp(*argv, "-k", 2) == 0) {
+	       argc--; argv++;
+	       if (!argc || keytab_str) {
+		    rem_usage();
+		    return;
+	       }
+	       keytab_str = *argv;
+	  } else if (strcmp(*argv, "-q") == 0) {
+	       quiet++;
+	  } else
+	       break;
+	  argc--; argv++;
+     }
+
+     if (argc != 1 && argc != 2) {
+	  rem_usage();
+	  return;
+     }
+     if (process_keytab(context, &keytab_str, &keytab))
+	  return;
+
+     (void) remove_principal(keytab_str, keytab, argv[0], argv[1]);
+
+     code = krb5_kt_close(context, keytab);
+     if (code != 0)
+	  com_err(whoami, code, "while closing keytab");
+
+     free(keytab_str);
+}
+
+static 
+int add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,
+		  krb5_boolean keepold, int n_ks_tuple,
+		  krb5_key_salt_tuple *ks_tuple,
+		  char *princ_str) 
+{
+     kadm5_principal_ent_rec princ_rec;
+     krb5_principal princ;
+     krb5_keytab_entry new_entry;
+     krb5_keyblock *keys;
+     int code, nkeys, i;
+
+     (void) memset((char *)&princ_rec, 0, sizeof(princ_rec));
+
+     princ = NULL;
+     keys = NULL;
+     nkeys = 0;
+
+     code = krb5_parse_name(context, princ_str, &princ);
+     if (code != 0) {
+	  com_err(whoami, code, "while parsing -add principal name %s",
+		  princ_str);
+	  goto cleanup;
+     }
+
+     if (keepold || ks_tuple != NULL) {
+	 code = kadm5_randkey_principal_3(lhandle, princ,
+					  keepold, n_ks_tuple, ks_tuple,
+					  &keys, &nkeys);
+     } else {
+	 code = kadm5_randkey_principal(lhandle, princ, &keys, &nkeys);
+     }
+     if (code != 0) {
+	  if (code == KADM5_UNK_PRINC) {
+	       fprintf(stderr, "%s: Principal %s does not exist.\n",
+		       whoami, princ_str);
+	  } else
+	       com_err(whoami, code, "while changing %s's key",
+		       princ_str);
+	  goto cleanup;
+     }
+
+     code = kadm5_get_principal(lhandle, princ, &princ_rec,
+				KADM5_PRINCIPAL_NORMAL_MASK);
+     if (code != 0) {
+	  com_err(whoami, code, "while retrieving principal");
+	  goto cleanup;
+     }
+
+     for (i = 0; i < nkeys; i++) {
+	  memset((char *) &new_entry, 0, sizeof(new_entry));
+	  new_entry.principal = princ;
+	  new_entry.key = keys[i];
+	  new_entry.vno = princ_rec.kvno;
+
+	  code = krb5_kt_add_entry(context, keytab, &new_entry);
+	  if (code != 0) {
+	       com_err(whoami, code, "while adding key to keytab");
+	       (void) kadm5_free_principal_ent(lhandle, &princ_rec);
+	       goto cleanup;
+	  }
+
+	  if (!quiet)
+	       printf("Entry for principal %s with kvno %d, "
+		      "encryption type %s added to keytab %s.\n",
+		      princ_str, princ_rec.kvno,
+		      etype_string(keys[i].enctype), keytab_str);
+     }
+
+     code = kadm5_free_principal_ent(lhandle, &princ_rec);
+     if (code != 0) {
+	  com_err(whoami, code, "while freeing principal entry");
+	  goto cleanup;
+     }
+
+cleanup:
+     if (nkeys) {
+	  for (i = 0; i < nkeys; i++)
+	       krb5_free_keyblock_contents(context, &keys[i]);
+	  free(keys);
+     }
+     if (princ)
+	  krb5_free_principal(context, princ);
+
+     return code;
+}
+
+int remove_principal(char *keytab_str, krb5_keytab keytab, char
+		     *princ_str, char *kvno_str) 
+{
+     krb5_principal princ;
+     krb5_keytab_entry entry;
+     krb5_kt_cursor cursor;
+     enum { UNDEF, SPEC, HIGH, ALL, OLD } mode;
+     int code, did_something;
+     krb5_kvno kvno;
+
+     code = krb5_parse_name(context, princ_str, &princ);
+     if (code != 0) {
+	  com_err(whoami, code, "while parsing principal name %s",
+		  princ_str);
+	  return code;
+     }
+
+     mode = UNDEF;
+     if (kvno_str == NULL) {
+	  mode = HIGH;
+	  kvno = 0;
+     } else if (strcmp(kvno_str, "all") == 0) {
+	  mode = ALL;
+	  kvno = 0;
+     } else if (strcmp(kvno_str, "old") == 0) {
+	  mode = OLD;
+	  kvno = 0;
+     } else {
+	  mode = SPEC;
+	  kvno = atoi(kvno_str);
+     }
+
+     /* kvno is set to specified value for SPEC, 0 otherwise */
+     code = krb5_kt_get_entry(context, keytab, princ, kvno, 0, &entry);
+     if (code != 0) {
+	  if (code == ENOENT) {
+	       fprintf(stderr, "%s: Keytab %s does not exist.\n",
+		       whoami, keytab_str);
+	  } else if (code == KRB5_KT_NOTFOUND) {
+	       if (mode != SPEC)
+		    fprintf(stderr, "%s: No entry for principal "
+			    "%s exists in keytab %s\n",
+			    whoami, princ_str, keytab_str);
+	       else
+		    fprintf(stderr, "%s: No entry for principal "
+			    "%s with kvno %d exists in keytab "
+			    "%s.\n", whoami, princ_str, kvno,
+			    keytab_str);
+	  } else {
+	       com_err(whoami, code, "while retrieving highest kvno "
+		       "from keytab");
+	  }
+	  return code;
+     }
+
+     /* set kvno to spec'ed value for SPEC, highest kvno otherwise */
+     kvno = entry.vno;
+     krb5_kt_free_entry(context, &entry);
+
+     code = krb5_kt_start_seq_get(context, keytab, &cursor);
+     if (code != 0) {
+	  com_err(whoami, code, "while starting keytab scan");
+	  return code;
+     }
+
+     did_something = 0;
+     while ((code = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
+	  if (krb5_principal_compare(context, princ, entry.principal) &&
+	      ((mode == ALL) ||
+	       (mode == SPEC && entry.vno == kvno) ||
+	       (mode == OLD && entry.vno != kvno) ||
+	       (mode == HIGH && entry.vno == kvno))) {
+
+	       /*
+		* Ack!  What a kludge... the scanning functions lock
+		* the keytab so entries cannot be removed while they
+		* are operating.
+		*/
+	       code = krb5_kt_end_seq_get(context, keytab, &cursor);
+	       if (code != 0) {
+		    com_err(whoami, code, "while temporarily ending "
+			    "keytab scan");
+		    return code;
+	       }
+	       code = krb5_kt_remove_entry(context, keytab, &entry);
+	       if (code != 0) {
+		    com_err(whoami, code, "while deleting entry from keytab");
+		    return code;
+	       }
+	       code = krb5_kt_start_seq_get(context, keytab, &cursor);
+	       if (code != 0) {
+		    com_err(whoami, code, "while restarting keytab scan");
+		    return code;
+	       }
+
+	       did_something++;
+	       if (!quiet)
+		    printf("Entry for principal %s with kvno %d "
+			   "removed from keytab %s.\n", 
+			   princ_str, entry.vno, keytab_str);
+	  }
+	  krb5_kt_free_entry(context, &entry);
+     }
+     if (code && code != KRB5_KT_END) {
+	  com_err(whoami, code, "while scanning keytab");
+	  return code;
+     }
+     if ((code = krb5_kt_end_seq_get(context, keytab, &cursor))) {
+	  com_err(whoami, code, "while ending keytab scan");
+	  return code;
+     }
+
+     /*
+      * If !did_someting then mode must be OLD or we would have
+      * already returned with an error.  But check it anyway just to
+      * prevent unexpected error messages...
+      */
+     if (!did_something && mode == OLD) {
+	  fprintf(stderr, "%s: There is only one entry for principal "
+		  "%s in keytab %s\n", whoami, princ_str, keytab_str);
+	  return 1;
+     }
+     
+     return 0;
+}
+
+/*
+ * etype_string(enctype): return a string representation of the
+ * encryption type.  XXX copied from klist.c; this should be a
+ * library function, or perhaps just #defines
+ */
+static char *etype_string(enctype)
+    krb5_enctype enctype;
+{
+    static char buf[100];
+    krb5_error_code ret;
+
+    if ((ret = krb5_enctype_to_string(enctype, buf, sizeof(buf))))
+	sprintf(buf, "etype %d", enctype);
+
+    return buf;
+}
diff --git a/mechglue/src/kadmin/cli/memmove.c b/mechglue/src/kadmin/cli/memmove.c
new file mode 100644
index 000000000..71f586155
--- /dev/null
+++ b/mechglue/src/kadmin/cli/memmove.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define MEMMOVE
+
+/* based on @(#)bcopy.c	5.11 (Berkeley) 6/21/91 */
+
+#include <krb5/osconf.h>
+#include <krb5/config.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * sizeof(word) MUST BE A POWER OF TWO
+ * SO THAT wmask BELOW IS ALL ONES
+ */
+typedef	int word;		/* "word" used for optimal copy speed */
+
+#define	wsize	sizeof(word)
+#define	wmask	(wsize - 1)
+
+/*
+ * Copy a block of memory, handling overlap.
+ * This is the routine that actually implements
+ * (the portable versions of) bcopy, memcpy, and memmove.
+ */
+#ifdef MEMCOPY
+void *
+memcpy(dst0, src0, length)
+#else
+#ifdef MEMMOVE
+void *
+memmove(dst0, src0, length)
+#else
+void
+bcopy(src0, dst0, length)
+#endif
+#endif
+	void *dst0;
+	const void *src0;
+	register size_t length;
+{
+	register char *dst = dst0;
+	register const char *src = src0;
+	register size_t t;
+
+	if (length == 0 || dst == src)		/* nothing to do */
+		goto done;
+
+	/*
+	 * Macros: loop-t-times; and loop-t-times, t>0
+	 */
+#define	TLOOP(s) if (t) TLOOP1(s)
+#define	TLOOP1(s) do { s; } while (--t)
+
+	if ((unsigned long)dst < (unsigned long)src) {
+		/*
+		 * Copy forward.
+		 */
+		t = (int)src;	/* only need low bits */
+		if ((t | (int)dst) & wmask) {
+			/*
+			 * Try to align operands.  This cannot be done
+			 * unless the low bits match.
+			 */
+			if ((t ^ (int)dst) & wmask || length < wsize)
+				t = length;
+			else
+				t = wsize - (t & wmask);
+			length -= t;
+			TLOOP1(*dst++ = *src++);
+		}
+		/*
+		 * Copy whole words, then mop up any trailing bytes.
+		 */
+		t = length / wsize;
+		TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
+		t = length & wmask;
+		TLOOP(*dst++ = *src++);
+	} else {
+		/*
+		 * Copy backwards.  Otherwise essentially the same.
+		 * Alignment works as before, except that it takes
+		 * (t&wmask) bytes to align, not wsize-(t&wmask).
+		 */
+		src += length;
+		dst += length;
+		t = (int)src;
+		if ((t | (int)dst) & wmask) {
+			if ((t ^ (int)dst) & wmask || length <= wsize)
+				t = length;
+			else
+				t &= wmask;
+			length -= t;
+			TLOOP1(*--dst = *--src);
+		}
+		t = length / wsize;
+		TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
+		t = length & wmask;
+		TLOOP(*--dst = *--src);
+	}
+done:
+#if defined(MEMCOPY) || defined(MEMMOVE)
+	return (dst0);
+#else
+	return;
+#endif
+}
diff --git a/mechglue/src/kadmin/cli/ss_wrapper.c b/mechglue/src/kadmin/cli/ss_wrapper.c
new file mode 100644
index 000000000..f73ba8238
--- /dev/null
+++ b/mechglue/src/kadmin/cli/ss_wrapper.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * ss wrapper for kadmin
+ */
+
+#include <krb5.h>
+#include <ss/ss.h>
+#include <stdio.h>
+#include <string.h>
+#include "kadmin.h"
+
+extern ss_request_table kadmin_cmds;
+extern int exit_status;
+extern char *whoami;
+
+int main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    char *request;
+    krb5_error_code retval;
+    int sci_idx, code = 0;
+
+    whoami = ((whoami = strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
+
+    request = kadmin_startup(argc, argv);
+    sci_idx = ss_create_invocation(whoami, "5.0", (char *) NULL,
+				   &kadmin_cmds, &retval);
+    if (retval) {
+	ss_perror(sci_idx, retval, "creating invocation");
+	exit(1);
+    }
+    if (request) {
+	    code = ss_execute_line(sci_idx, request);
+	    if (code != 0) {
+		    ss_perror(sci_idx, code, request);
+		    exit_status++;
+	    }
+    } else
+            retval = ss_listen(sci_idx);
+    return quit() ? 1 : exit_status;
+}
diff --git a/mechglue/src/kadmin/cli/strftime.c b/mechglue/src/kadmin/cli/strftime.c
new file mode 100644
index 000000000..6fb621e41
--- /dev/null
+++ b/mechglue/src/kadmin/cli/strftime.c
@@ -0,0 +1,464 @@
+/*	$NetBSD: strftime.c,v 1.8 1999/02/07 17:33:30 augustss Exp $	*/
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char *sccsid = "@(#)strftime.c	5.11 (Berkeley) 2/24/91";
+#else
+__RCSID("$NetBSD: strftime.c,v 1.8 1999/02/07 17:33:30 augustss Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <string.h>
+#include <time.h>
+
+/* begin krb5 hack - replace stuff that would come from netbsd libc */
+#undef _CurrentTimeLocale
+#define _CurrentTimeLocale (&dummy_locale_info)
+
+struct dummy_locale_info_t {
+    char d_t_fmt[15];
+    char t_fmt_ampm[12];
+    char t_fmt[9];
+    char d_fmt[9];
+    char day[7][10];
+    char abday[7][4];
+    char mon[12][10];
+    char abmon[12][4];
+    char am_pm[2][3];
+};
+static const struct dummy_locale_info_t dummy_locale_info = {
+    "%a %b %d %X %Y",		/* %c */
+    "%I:%M:%S %p",		/* %r */
+    "%H:%M:%S",			/* %X */
+    "%m/%d/%y",			/* %x */
+    { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
+      "Saturday" },
+    { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
+    { "January", "February", "March", "April", "May", "June",
+      "July", "August", "September", "October", "November", "December" },
+    { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
+    { "AM", "PM" },
+};
+#undef  TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+
+#undef  DAYSPERLYEAR
+#define DAYSPERLYEAR 366
+#undef  DAYSPERNYEAR
+#define DAYSPERNYEAR 365
+#undef  DAYSPERWEEK
+#define DAYSPERWEEK 7
+#undef  isleap
+#define isleap(N)	((N % 4) == 0 && (N % 100 != 0 || N % 400 == 0))
+#undef  tzname
+#define tzname my_tzname
+static const char *const tzname[2] = { 0, 0 };
+#undef  tzset
+#define tzset()
+#undef __P
+#define __P(X) X /* we already require ansi c in this tree */
+/* end krb5 hack */
+
+static	int _add __P((const char *, char **, const char *));
+static	int _conv __P((int, int, int, char **, const char *));
+static	int _secs __P((const struct tm *, char **, const char *));
+static	size_t _fmt __P((const char *, const struct tm *, char **,
+	    const char *));
+
+size_t
+strftime(s, maxsize, format, t)
+	char *s;
+	size_t maxsize;
+	const char *format;
+	const struct tm *t;
+{
+	char *pt;
+
+	tzset();
+	if (maxsize < 1)
+		return (0);
+
+	pt = s;
+	if (_fmt(format, t, &pt, s + maxsize)) {
+		*pt = '\0';
+		return (pt - s);
+	} else
+		return (0);
+}
+
+#define SUN_WEEK(t)	(((t)->tm_yday + 7 - \
+				((t)->tm_wday)) / 7)
+#define MON_WEEK(t)	(((t)->tm_yday + 7 - \
+				((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7)
+
+static size_t
+_fmt(format, t, pt, ptlim)
+	const char *format;
+	const struct tm *t;
+	char **pt;
+	const char * const ptlim;
+{
+	for (; *format; ++format) {
+		if (*format == '%') {
+			++format;
+			if (*format == 'E') {
+				/* Alternate Era */
+				++format;
+			} else if (*format == 'O') {
+				/* Alternate numeric symbols */
+				++format;
+			}
+			switch (*format) {
+			case '\0':
+				--format;
+				break;
+			case 'A':
+				if (t->tm_wday < 0 || t->tm_wday > 6)
+					return (0);
+				if (!_add(_CurrentTimeLocale->day[t->tm_wday],
+				    pt, ptlim))
+					return (0);
+				continue;
+
+			case 'a':
+				if (t->tm_wday < 0 || t->tm_wday > 6)
+					return (0);
+				if (!_add(_CurrentTimeLocale->abday[t->tm_wday],
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'B':
+				if (t->tm_mon < 0 || t->tm_mon > 11)
+					return (0);
+				if (!_add(_CurrentTimeLocale->mon[t->tm_mon],
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'b':
+			case 'h':
+				if (t->tm_mon < 0 || t->tm_mon > 11)
+					return (0);
+				if (!_add(_CurrentTimeLocale->abmon[t->tm_mon],
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'C':
+				if (!_conv((t->tm_year + TM_YEAR_BASE) / 100,
+				    2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'c':
+				if (!_fmt(_CurrentTimeLocale->d_t_fmt, t, pt,
+				    ptlim))
+					return (0);
+				continue;
+			case 'D':
+				if (!_fmt("%m/%d/%y", t, pt, ptlim))
+					return (0);
+				continue;
+			case 'd':
+				if (!_conv(t->tm_mday, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'e':
+				if (!_conv(t->tm_mday, 2, ' ', pt, ptlim))
+					return (0);
+				continue;
+			case 'H':
+				if (!_conv(t->tm_hour, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'I':
+				if (!_conv(t->tm_hour % 12 ?
+				    t->tm_hour % 12 : 12, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'j':
+				if (!_conv(t->tm_yday + 1, 3, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'k':
+				if (!_conv(t->tm_hour, 2, ' ', pt, ptlim))
+					return (0);
+				continue;
+			case 'l':
+				if (!_conv(t->tm_hour % 12 ?
+				    t->tm_hour % 12: 12, 2, ' ', pt, ptlim))
+					return (0);
+				continue;
+			case 'M':
+				if (!_conv(t->tm_min, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'm':
+				if (!_conv(t->tm_mon + 1, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'n':
+				if (!_add("\n", pt, ptlim))
+					return (0);
+				continue;
+			case 'p':
+				if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour
+				    >= 12], pt, ptlim))
+					return (0);
+				continue;
+			case 'R':
+				if (!_fmt("%H:%M", t, pt, ptlim))
+					return (0);
+				continue;
+			case 'r':
+				if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t, pt,
+				    ptlim))
+					return (0);
+				continue;
+			case 'S':
+				if (!_conv(t->tm_sec, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 's':
+				if (!_secs(t, pt, ptlim))
+					return (0);
+				continue;
+			case 'T':
+				if (!_fmt("%H:%M:%S", t, pt, ptlim))
+					return (0);
+				continue;
+			case 't':
+				if (!_add("\t", pt, ptlim))
+					return (0);
+				continue;
+			case 'U':
+				if (!_conv(SUN_WEEK(t), 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'u':
+				if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0',
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'V':	/* ISO 8601 week number */
+			case 'G':	/* ISO 8601 year (four digits) */
+			case 'g':	/* ISO 8601 year (two digits) */
+/*
+** From Arnold Robbins' strftime version 3.0:  "the week number of the
+** year (the first Monday as the first day of week 1) as a decimal number
+** (01-53)."
+** (ado, 1993-05-24)
+**
+** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
+** "Week 01 of a year is per definition the first week which has the
+** Thursday in this year, which is equivalent to the week which contains
+** the fourth day of January. In other words, the first week of a new year
+** is the week which has the majority of its days in the new year. Week 01
+** might also contain days from the previous year and the week before week
+** 01 of a year is the last week (52 or 53) of the previous year even if
+** it contains days from the new year. A week starts with Monday (day 1)
+** and ends with Sunday (day 7).  For example, the first week of the year
+** 1997 lasts from 1996-12-30 to 1997-01-05..."
+** (ado, 1996-01-02)
+*/
+				{
+					int	year;
+					int	yday;
+					int	wday;
+					int	w;
+
+					year = t->tm_year + TM_YEAR_BASE;
+					yday = t->tm_yday;
+					wday = t->tm_wday;
+					for ( ; ; ) {
+						int	len;
+						int	bot;
+						int	top;
+
+						len = isleap(year) ?
+							DAYSPERLYEAR :
+							DAYSPERNYEAR;
+						/*
+						** What yday (-3 ... 3) does
+						** the ISO year begin on?
+						*/
+						bot = ((yday + 11 - wday) %
+							DAYSPERWEEK) - 3;
+						/*
+						** What yday does the NEXT
+						** ISO year begin on?
+						*/
+						top = bot -
+							(len % DAYSPERWEEK);
+						if (top < -3)
+							top += DAYSPERWEEK;
+						top += len;
+						if (yday >= top) {
+							++year;
+							w = 1;
+							break;
+						}
+						if (yday >= bot) {
+							w = 1 + ((yday - bot) /
+								DAYSPERWEEK);
+							break;
+						}
+						--year;
+						yday += isleap(year) ?
+							DAYSPERLYEAR :
+							DAYSPERNYEAR;
+					}
+#ifdef XPG4_1994_04_09
+					if ((w == 52
+					     && t->tm_mon == TM_JANUARY)
+					    || (w == 1
+						&& t->tm_mon == TM_DECEMBER))
+						w = 53;
+#endif /* defined XPG4_1994_04_09 */
+					if (*format == 'V') {
+						if (!_conv(w, 2, '0',
+							pt, ptlim))
+							return (0);
+					} else if (*format == 'g') {
+						if (!_conv(year % 100, 2, '0',
+							pt, ptlim))
+							return (0);
+					} else	if (!_conv(year, 4, '0',
+							pt, ptlim))
+							return (0);
+				}
+				continue;
+			case 'W':
+				if (!_conv(MON_WEEK(t), 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'w':
+				if (!_conv(t->tm_wday, 1, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'x':
+				if (!_fmt(_CurrentTimeLocale->d_fmt, t, pt,
+				    ptlim))
+					return (0);
+				continue;
+			case 'X':
+				if (!_fmt(_CurrentTimeLocale->t_fmt, t, pt,
+				    ptlim))
+					return (0);
+				continue;
+			case 'y':
+				if (!_conv((t->tm_year + TM_YEAR_BASE) % 100,
+				    2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'Y':
+				if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0',
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'Z':
+				if (tzname[t->tm_isdst ? 1 : 0] &&
+				    !_add(tzname[t->tm_isdst ? 1 : 0], pt,
+				    ptlim))
+					return (0);
+				continue;
+			case '%':
+			/*
+			 * X311J/88-090 (4.12.3.5): if conversion char is
+			 * undefined, behavior is undefined.  Print out the
+			 * character itself as printf(3) does.
+			 */
+			default:
+				break;
+			}
+		}
+		if (*pt == ptlim)
+			return (0);
+		*(*pt)++ = *format;
+	}
+	return (ptlim - *pt);
+}
+
+static int
+_secs(t, pt, ptlim)
+	const struct tm *t;
+	char **pt;
+	const char * const ptlim;
+{
+	char buf[15];
+	time_t s;
+	char *p;
+	struct tm tmp;
+
+	buf[sizeof (buf) - 1] = '\0';
+	/* Make a copy, mktime(3) modifies the tm struct. */
+	tmp = *t;
+	s = mktime(&tmp);
+	for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10)
+		*p-- = (char)(s % 10 + '0');
+	return (_add(++p, pt, ptlim));
+}
+
+static int
+_conv(n, digits, pad, pt, ptlim)
+	int n, digits;
+	int pad;
+	char **pt;
+	const char * const ptlim;
+{
+	char buf[10];
+	char *p;
+
+	buf[sizeof (buf) - 1] = '\0';
+	for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
+		*p-- = n % 10 + '0';
+	while (p > buf && digits-- > 0)
+		*p-- = pad;
+	return (_add(++p, pt, ptlim));
+}
+
+static int
+_add(str, pt, ptlim)
+	const char *str;
+	char **pt;
+	const char * const ptlim;
+{
+
+	for (;; ++(*pt)) {
+		if (*pt == ptlim)
+			return (0);
+		if ((**pt = *str++) == '\0')
+			return (1);
+	}
+}
diff --git a/mechglue/src/kadmin/configure.in b/mechglue/src/kadmin/configure.in
new file mode 100644
index 000000000..85a97644f
--- /dev/null
+++ b/mechglue/src/kadmin/configure.in
@@ -0,0 +1,65 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_PROG_AWK
+AC_CHECK_HEADERS(unistd.h stdlib.h krb_db.h kdc.h regex.h alloca.h sys/time.h sys/select.h memory.h arpa/inet.h)
+AC_CHECK_FUNCS(ftime timezone getcwd strstr waitpid vsprintf)
+KRB5_AC_NEED_DAEMON
+AC_HEADER_TIME
+CHECK_SIGNALS
+CHECK_WAIT_TYPE
+CHECK_SETJMP
+KRB5_GETSOCKNAME_ARGS
+ath_compat=
+AC_ARG_ENABLE([athena],
+[  --enable-athena         build with MIT Project Athena configuration],
+ath_compat=compat,)
+dnl
+dnl The following are tests for the presence of programs required for testing 
+AC_CHECK_PROG(have_RUNTEST,runtest,runtest)
+AC_CHECK_PROG(have_PERL,perl,perl)
+AC_KRB5_TCL	
+if test "$have_PERL" = perl -a "$have_RUNTEST" = runtest -a "$TCL_LIBS" != ""; then
+ 	DO_TEST=ok
+fi
+AC_SUBST(DO_TEST) 
+dnl
+DO_V4_TEST=
+if test "$have_PERL" = perl -a "$have_RUNTEST" = runtest -a "$TCL_LIBS" != "" -a "$ath_compat" != ""; then
+ 	DO_V4_TEST=ok
+fi
+AC_SUBST(DO_V4_TEST)
+dnl
+dnl For ndbm password checking kludge.
+dnl
+if test "$ath_compat" = "compat"; then
+	AC_DEFINE(NDBM_PW_CHECK)
+fi
+dnl
+dnl The following are substituted into testing/scripts/env-setup.sh
+RBUILD=`pwd`/..
+AC_SUBST(RBUILD)
+case "$srcdir" in
+/*)
+	S_TOP=$srcdir/..
+	;;
+*)
+	S_TOP=`pwd`/$srcdir/..
+	;;
+esac
+AC_SUBST(S_TOP)
+AC_PATH_PROG(PERL,perl)
+AC_PATH_PROG(EXPECT,expect)
+dnl
+KRB5_RUN_FLAGS
+dnl For testing/util/Makefile.in
+if test "$TCL_LIBS" != "" ;  then
+	DO_ALL=tcl
+fi
+AC_SUBST(DO_ALL)
+KRB5_BUILD_PROGRAM
+KRB5_AC_PRIOCNTL_HACK
+dnl
+K5_GEN_FILE(testing/scripts/env-setup.sh:testing/scripts/env-setup.shin)
+V5_AC_OUTPUT_MAKEFILE(. cli dbutil passwd passwd/unit-test ktutil server  testing testing/scripts testing/util)
diff --git a/mechglue/src/kadmin/dbutil/ChangeLog b/mechglue/src/kadmin/dbutil/ChangeLog
new file mode 100644
index 000000000..7d110fb7d
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/ChangeLog
@@ -0,0 +1,956 @@
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KDB_DEP_LIB): Use DL_LIB and THREAD_LINKOPTS
+	instead of explicitly using -ldl and -lpthread.
+
+	Novell merge.
+	* Makefile.in:
+	* dump.c:
+	* kadm5_create.c:
+	* kdb5_create.c:
+	* kdb5_destroy.c:
+	* kdb5_stash.c:
+	* kdb5_util.c:
+	* kdb5_util.h:
+	* ovload.c:
+
+2004-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* loadv4.c (enter_in_v5_db): Terminate argument list of
+	krb5_build_principal with NULL, not 0.  Patch from Nalin
+	Dahyabhai.
+
+2004-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* kadm5_create.c (add_admin_princs): Create kadmin/fqdn
+	principal.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_destroy.c, kdb5_stash.c: Don't declare errno.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* dumpv4.c (v4init):
+	* loadv4.c (dumpfile;): Remove trailing colon, as new implementation
+	of des_read_password() appends it.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-23  Tom Yu  <tlyu@mit.edu>
+
+	* dump.c (dump_db): Update usage comment.  Add "-rev" and
+	"-recurse" flags to permit reverse and recursive dumping of the
+	database, respectively.  Check for dump filename beginning with
+	"-" to avoid accidental dumps to such filenames.
+
+	* kdb5_util.c (usage): Update to match reality, primarily by
+	updating the "dump" usage, but also showing global options before
+	the command, which is how they were being interpreted anyway.
+
+	* kdb5_util.M: Update to match reality.  Document "-mkey_convert",
+	"-new_mkey_file", "-rev", and "-recurse" options to "dump".
+	Document "dump to stdout" behavior.  Show global options before
+	the command.  Make some formatting fixes.  s/binary tree/btree/
+	since the btree back end is actually an n-ary tree.
+
+2002-08-14  Jen Selby <jenselby@mit.edu>
+
+	* dump.c: added -mkey_convert and -new_mkey_file to the usage
+	comment
+
+2002-07-31  Tom Yu  <tlyu@mit.edu>
+
+	* dump.c (master_key_convert): Iterate over freeing
+	key_data->key_data_contents[j] rather than attempting to free
+	key_data->key_data_contents.
+
+2002-07-29  Jen Selby  <jenselby@mit.edu>
+
+	* kdb5_util.M: added documentation for some options.
+
+2002-07-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* dump.c (dump_ov_princ): Remove variable set but unused.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_stash.c (kdb5_stash): Call krb5_c_valid_enctype instead of
+	valid_enctype.
+	* kdb5_util.c (main, open_db_and_mkey): Likewise.
+	* loadv4.c (load_v4db): Likewise.
+
+2002-01-08  Sam Hartman  <hartmans@mit.edu>
+
+	* kdb5_create.c (kdb5_create): Load strong random data
+
+2001-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* dump.c (dump_db): Pass krb5_boolean instead of char * as
+	argument to kb5_db_fetch_mkey().
+
+2001-10-23  Tom Yu  <tlyu@mit.edu>
+
+	* loadv4.c (fixup_database): Don't set SUPPORT_DESMD5 anymore.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* dump.c, kdb5_create.c, kdb5_util.h, loadv4.c, tcl_wrapper.c:
+	Make prototypes unconditional.
+
+2001-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* string_table.c (str_INITING_KCONTEXT): Variable deleted.
+	* string_table.h (str_INITING_KCONTEXT): Declaration deleted.
+	* kadm5_create.c (kadm5_create, kadm5_create_magic_princs): Don't
+	use str_INITING_KCONTEXT, instead provide (different!) messages
+	more appropriate to the actual code.
+
+2001-06-29  Ezra Peisach  <epeisach@mit.edu>
+
+	* nstrtok.h: New file with prototype for nstrtok.
+
+	* ovload.c: Include nstrtok.h
+
+	* strtok.c: Include nstrtok.h for prototype. Declare delim as
+	const char * argument. Delete rcsid. 
+
+	* string_table.c: Delete rcsid.
+
+	* kadm5_create.c (build_name_with_realm): Declare static.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_util.c (main): Change optarg to koptarg to prevent
+	shadowing of getopt function.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_create.c: Include <krb5/adm_proto.h> for
+	krb5_keysalt_iterate() prototype.
+
+2001-06-20  Mitchell Berger  <mitchb@mit.edu>
+
+	* kdb5_create.c (kdb5_create): Fixed typo in com_err message.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* dump.c (name_matches): Cleanup warning of assignments in
+	conditionals.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* dump.c: Include regex.h if exists and if HAVE_REGCOMP
+	defined. Preior to this, regex.h was never included.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* dumpv4.c: Pass C_Block * to des_read_password() as per prototype.
+
+	* loadv4.c: Include k5-int.h before des.h for des_read_password
+	prototype. Pass C_Block * to des_read_password() as per prototype.
+
+	* kdb5_util.h: Add prototype for usage.
+
+	* kdb5_create.c, kdb5_destroy.c, kdb5_stash.c: Include kdb5_util.h
+	for usage() prototype.
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* kadm5_create.c: Add prototype for static
+	add_admin_princs(). Cleanup calling of add_admin_princs() to be
+	consistant with prototype.
+
+	* kdb5_create.c, kdb5_stash.c, kdb5_destroy.c: Cleanup assignments
+	in conditionals.
+
+Mon Feb 26 15:01:27 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* loadv4.c, ovload.c, kdb5_util.h, kdb5_util.c, kadm5_create.c,
+ 	dumpv4.c, dump.c: Compiler warning cleanup including prototypes,
+ 	assignments in conditionals, unused variables, varaibles shadowing
+ 	one-another.
+
+2001-02-08  Tom Yu  <tlyu@mit.edu>
+
+	* loadv4.c: Remove references to KRB_NEVERDATE.
+
+2001-02-05  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_util.M: Fix some formatting nits and document new flags
+	controlling dump formats.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_create.c (kdb5_create): Argument to krb5_read_password
+	changed to unsigned int.
+
+2000-10-16  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_util.M: Update manpage.
+
+	* kdb5_util.c (usage): Update usage message.
+
+	* dumpv4.c (dump_v4_iterator): Add logic to deal with long
+	lifetimes, as well as optionally using short lifetimes.
+
+	* loadv4.c (load_v4db): Add logic to deal with long lifetimes, as
+	well as optionally using short lifetimes.
+
+	* kadm5_create.c (kadm5_create_magic_princs): Add calls to
+	krb5_klog_init() and krb5_klog_close() to avoid coredumping if
+	kadm5_init() calls krb5_klog_syslog().
+
+2000-07-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* dump.c: Various message char arrays turned into macros, to
+	permit gcc to verify format strings and arguments match.  
+	(k5beta6_dump_header, k5beta7_dump_header): Deleted.
+	(dump_ov_princ): Use %lx for aux_attributes.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* dump.c: Add a new dump version, r1_3_version, and make it the
+	default; it will be used in krb5-1.3 and will permit a principal's
+	kadm5 data to be dumped.  This is an interim measure until we
+	redesign the dump format somewhat.
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* ovload.c: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_util.c (main): Do try using com_err in the case that
+	krb5_init_context fails, instead of fprintf of the error number.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Tue Nov  3 16:28:23 1998  Tom Yu  <tlyu@mit.edu>
+
+	* dump.c: Fix up to work with new crypto API.
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* dumpv4, loadv4.c, kdb5_create.c, kdb5_stash.c, kdb5_util.c,
+	kadm5_create.c: convert to new crypto api
+
+Wed Sep 30 00:02:01 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* dump.c: Add support for changing the master key for a database
+		as part of creating a dump of the database.
+
+Thu Aug 20 16:50:00 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_util.c (add_random_key): Fixes to deal with absence of "-e"
+	flag.
+
+Wed Aug 19 14:52:40 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_util.c (add_random_key): New function to create a new
+ 	random key for a principal while retaining the previous kvno's
+ 	keys.  This is only temporary until a reasonable kadm5 interface
+	is made.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdb5_stash.c (argv): 
+	* kdb5_destroy.c (kdb5_destroy): 
+	* kdb5_create.c (kdb5_create): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 18 15:55:06 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+ 	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sun Nov  2 19:09:17 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_util.c: Add flag indicating that policy db is to be closed.
+  		Change '-f" option to "-sf" to indicate stash file on
+ 		command line.
+
+	* kdb5_stash.c (kdb5_stash): Indicate that policy db should be
+	 	closed, free context when done.
+	
+	* kadm5_create.c (kadm5_create): Fix up memory leaks.
+
+Wed Oct 22 15:39:38 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* tcl_wrapper.c: Include either tcl.h or tcl/tcl.h
+
+Fri Jul 25 15:46:24 1997  Tom Yu  <tlyu@mit.edu>
+
+	* loadv4.c:
+	* kdb5_create.c:
+	* kdb5_destroy.c:
+	* dump.c: Update to new kdb API.
+
+Thu Jul 17 12:25:41 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* dump.c (process_k5beta_record): Change variables from char to
+		krb5_octet to match types in krb5_key_data.
+
+	* ovload.c (process_ov_principal): Change "more" variable to
+		krb5_boolean as argument to krb5_db_get_principal. 
+
+Wed Mar 12 01:19:51 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* loadv4.c (argv): Check to see if the global_param's stash file
+		is non-NULL before trying to strdup() it.  [PR#341, PR#394]
+
+Tue Feb  4 21:17:09 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Tue Dec  3 16:04:24 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdb5_util.c: fix multiply defined globals [krb5-admin/260]
+
+Wed Nov 13 00:06:40 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* dump.c (load_db): lock the database directly (having fixed the
+	lock/unlock code) to avoid reopening on every record.
+
+Mon Nov 11 16:50:25 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kadmin/dbutil dumpv4 expiration ("never") fixes
+	* kadmin/dbutil loadv4 stashfile, default fixes
+
+	Fri Sep 27 18:45:43 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* dump.c (read_string): fgetc doesn't return char.
+	
+	Wed Sep 11 23:45:11 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* loadv4.c (enter_in_v5_db): set last_pwd_change from the
+	mod_time, not only the mod_princ_data.
+	
+	Wed Sep 11 00:02:33 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* dumpv4.c (dump_v4_iterator): detect expiration time of "never"
+	and fill in a reasonable default (namely, the Cygnus 96q1 default
+	of 12/31/2009.)
+
+	* loadv4.c (v4_dump_find_default): New function. Scans a dumpfile
+ 	for a "default" entry, which was probably created at kdb_init time
+ 	and probably hasn't changed from either the MIT default of
+ 	12/31/1999 or the Cygnus 96q1 default of 12/31/2009.  Check for
+ 	either value, and replace it with 0, which is understood as
+ 	"never" in V5.  If verbose is set (-v flag), log either the match
+	or the non-matching value.
+	(process_v4_dump): new argument default_exp_time, the value found
+ 	by v4_dump_find_default, actually performs the replacement of
+	matching entries.
+	(load_v4db): call v4_dump_find_default to get the default
+	expiration time.
+	* kdb5_util.M: document the above changes.
+
+	Sun Sep  8 01:02:47 1996  Mark W. Eichin  <eichin@kitten.gen.ma.us>
+
+	* kdb5_util.c (usage): document load_v4 -s stashfile.
+	(main): fix typo in usage message.
+	* kdb5_util.M: document load_v4, including new options, removing
+	previously eliminated -f option.
+	* loadv4.c (load_v4db): support -s stashfile option.
+
+Thu Nov  7 20:53:17 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Remove spurious WITH_KRB4.
+
+Tue Nov  5 16:16:53 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* dump.c (load_db): minor fix to code that verifies the specified
+ 	load version matches the file (autodetect worked anyway)
+
+Fri Oct 18 14:23:41 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* dump.c (load_db): osa_adb_rename_policy_db will create the db,
+ 	so this function doesn't have to [krb5-admin/58]
+
+	* dump.c (dump_k5beta6_iterator): don't dump tl types that are
+ 	special to us and the previous version did not understand
+ 	[krb5-admin/89]
+
+Tue Oct  8 13:35:56 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* dump.c (load_db): rework the way policy database naming and
+ 	renaming is handled; the code no longer depends on being able to
+ 	specify admin_dbname specifically (which is no longer supported by
+ 	the libraries), uses osa_adb_rename_policy instead of doing it
+ 	directly, and will create a policy db if one does not already
+ 	exist.  Automated testing is needed. [krb5-admin/62]
+
+	* dump.c (load_db): rename osa_adb_rename_policy to *_db
+
+Thu Oct  3 18:17:36 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdb5_util.c (ARG_VAL): case second half of ?: operator to char *
+ 	to fix problem on AIX; this should have worked anyway because of
+ 	the , operator but it is easy enough to force the solution, too.
+	[krb5-admin/41]
+
+Tue Sep 10 14:16:40 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_edit.M: remove extra args from .TH
+
+	* kdb5_util.M: remove ".so man1/header.doc"
+
+Mon Sep  9 11:06:29 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* loadv4.c: Don't call get_config_params again, since it's not
+ 		necessary, and breaks the policy database name if it is
+ 		manually set.
+
+Wed Sep  4 17:34:58 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* loadv4.c (load_v4db): Fix argument parsing so that it actually works!
+		Eliminated the -f option, as it is superfluous.  Don't
+		create the policy database if using the -t option, since
+		it'll already exist.
+
+	* kdb5_util.c (usage): Fix usage message so that it's correct for
+	 	load_v4.
+
+Tue Sep  3 22:12:54 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (install): Fixed typo: ($PROG) -> $(PROG)
+
+Thu Aug 29 11:57:09 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* dump.c (dump_db): don't compare apples and iguanas
+
+Sat Aug 24 21:14:45 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* loadv4.c, kdb5_stash.c: Removed unused variable rparams.
+
+Fri Aug 16 12:00:56 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Link with the GSSAPI library, since it's needed
+		for shared libraries.
+
+Mon Aug 12 11:41:57 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdb5_util.c: make mkey_password non-static
+
+	* kdb5_create.c: use global mkey_password
+
+Mon Aug  5 21:24:47 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb5_stash.c (kdb5_stash): Ignore (expected) failure in stashing
+		key when key not already present in returning exit status.
+
+Mon Aug  5 14:36:47 1996  Barry Jaspan  <bjaspan@DUN-DUN-NOODLES>
+
+	* all files: reworked for non-ss usage; kdb5_util_ct.ct and
+        ss_wrapper.c are now obsolete
+
+Thu Aug  1 14:34:51 1996  Barry Jaspan  <bjaspan@DUN-DUN-NOODLES>
+
+	* dump.c, kadm5_create.c, kdb5_create.c: create policy database
+        and kadm5 principals when loading a databas
+
+	* loadv4.c: create empty policy database after loading V4 dump file
+
+	* dumpv4.c (dump_v4db): use global_params.stash_file
+
+	* Makefile.in, Makefile.ov, configure.in, dump.c: add support for
+        dump/load of OV*Secure-compatible format.
+
+Wed Jul 31 14:55:38 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_stash.c (kdb5_stash): Declare optind.
+
+Tue Jul 30 17:51:24 1996  Samuel D Hartman  (hartmans@vorlon)
+
+	* configure.in: Use gssapi library.
+
+Sat Jul 27 02:16:01 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+	* kdb5_create.c (kdb5_create): Ignore (expected) failure in
+		open_db_and_mkey when creating database in returning exit
+		status.
+
+Wed Jul 24 02:57:16 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* loadv4.cdumpv4.c : Fixes for Athena Kerberos
+
+Wed Jul 24 02:47:07 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: Check for kdc.h and krb_db.h for Athena Kerberos.
+
+Tue Jul 23 17:03:42 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in: add dependency for kdb5_util_ct.o
+
+Thu Jul 18 19:22:04 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: removed SS_RULES
+
+Wed Jul 10 19:43:22 1996  Marc Horowitz  <marc@mit.edu>
+
+	* dumpv4.c (configure.in, Makefile.in): make autoconf work after
+ 	barry's carnage
+
+Sun May 12 00:27:44 1996  Marc Horowitz  <marc@mit.edu>
+
+	* loadv4.c (enter_in_v5_db, add_principal), kdb5_edit.c
+ 	(create_db_entry, modent), dumpv4.c (dump_v4_iterator), dump.c
+ 	(dump_k5beta_iterator, process_k5beta_record): convert to use new
+ 	krb5_dbe_* tl_data functions.
+
+	* cpw.c (enter_pwd_key): krb5_dbe_cpw() takes a kvno now.
+
+Tue May  7 23:16:57 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: USE_KADM_LIBRARY replaced by USE_KADMSRV_LIBRARY
+
+Thu Apr 11 19:32:36 1996  Richard Basch  <basch@lehman.com>
+
+	* kdb5_edit.c (extract_v4_srvtab): Use the matching key_data's kvno;
+	don't assume that key_data[0]'s kvno is necessarily the matching
+	key_data's kvno.
+
+Wed Apr 10 19:17:58 1996  Richard Basch  <basch@lehman.com>
+
+	* kdb5_edit.c (extract_v4_srvtab): Translate the principal name to
+	the common V4 name.
+
+Tue Mar 19 18:00:58 1996  Richard Basch  <basch@lehman.com>
+
+	* kdb5_edit.c (extract_v4_srvtab): do not test to make sure we
+	fetched a key of enctype 1 (des-cbc-crc), since we may have gotten
+	another des key from the database, which is just as useful in a
+	v4 srvtab
+
+	* dumpv4.c (dump_v4_iterator): use krb5_524_conv_principal to do the
+	v5 to v4 principal translation, instead of having yet another
+	hard-coded table.
+
+Wed Mar  6 16:17:20 1996  Richard Basch  <basch@lehman.com>
+
+	* dumpv4.c: The V4 master key & schedule was never initialized,
+	so the dump created by dump_v4db was garbage.	Read the V4
+	master key from /.k or prompt for the V4 master key password.
+	  If there is no V4-salt key in the database, but there is a DES
+	key, include it in the V4 dump, in case it is merely a random 
+	service key for which there is no associated password.
+	  Skip over K/M in the V5 database (use the entered V4 master key).
+	  Both krbtgt and afs keys often have domain-qualifed instances.
+
+Tue Mar  5 12:18:22 1996  Richard Basch  <basch@lehman.com>
+
+	* dump.c: POSIX locking requires that the file be opened read-write.
+
+Mon Feb 26 22:42:09 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kdb5_edit.c: new command line option -f stashfile.
+	* kdb5_edit.M: document stashfile option.
+
+Mon Feb 26 22:13:45 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* dump.c (process_k5beta_record): since V4 salt type has no data
+ 	either, only set key_data_ver to 1 for data_type 0 with 0-length
+ 	salt. Also, don't include alternate key if akey has all-zero type
+	and length in both fields.
+
+Sat Feb 24 04:02:18 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* dump.c (process_k5beta_record): encrypted keys used to have 4
+	byte lengths in MSB order, need to convert to 2 byte LSB order
+	lengths before storing. Handle primary key and alternate key.
+
+Fri Feb 23 18:44:10 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kdb5_edit.c (kdb5_edit_Init): set manual_mkey for testing with -P
+
+Wed Feb 14 09:52:18 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb5_edit.c (enter_master_key, set_dbname_help): If master key
+		enctype is unknown, set to DEFAULT_KDC_ENCTYPE.
+
+Tue Feb 13 16:08:07 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb5_edit.c (extract_v4_srvtab): krb5_dbekd_decrypt_key_data
+		takes krb5_key_data *, not **.
+
+Tue Jan 30 18:28:57 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* dump.c (load_db): dbrenerr_fmt prints "from" first, so pass it
+	to fprintf correctly.
+
+Sun Jan 28 14:31:47 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* dump.c (process_k5_record): t2..t9 is only 8 vars, not 9.
+
+Thu Jan 25 16:07:42 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* kdb5_edit.c (extract_srvtab): Extract *all* the keys in a
+        dbentry, not the first one.
+	(extract_v4_srvtab): Attempt to find the right v4 keys.
+
+Wed Jan 24 18:48:38 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* Makefile.in: Remove spurious @DEFS@
+
+
+Wed Dec 13 03:44:58 1995  Chris Provenzano (proven@mit.edu)
+
+        * dump.c, dumpv4.c, kdb5_edit.c, loadv4.c : 
+		Remove mkvno from krb5_db_entry.
+
+Sun Dec 10 11:07:51 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb5_edit.M: Document that modent exists
+
+	* kdb5_edit.c (modent): Add usage as suggested by jhawk@mit.edu.
+
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * kdb5_edit.c : Remove krb5_enctype from krb5_string_to_key() args.
+
+Fri Oct 27 13:37:04 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* dump.c (process_k5_record): Fix off by one in malloc.
+
+Mon Oct  9 16:35:19 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb5_edit.c (extract_v4_srvtab): Extract a one byte version
+		number for v4 srvtabs (from warlord).
+
+Thu Oct  5 10:35:35 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* cpw.c: Declare std_ks_tuple as extern.
+	* kdb5_edit.h: Remove std_ks_tuple declaration as not all sources
+		include adm.h for structures
+
+Tue Oct  3 23:10:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* cpw.c (enter_rnd_key, enter_pwd_key):
+	* kdb5_edit.c (kdb5_edit_Init): Use the kdc.conf file to determine
+		the default list of keysalt tuples to be used.  This is
+		stored in std_ks_tuple, and is used by cpw.c for random
+		keys and when a list of keysalts is not specified.
+
+Mon Sep 18 03:59:47 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb5_edit.c (show_principal): Show key version and last password
+		change. 
+
+	* cpw.c: Fix typo in below change in which list was terminated
+		after third entry. (extra } removed)
+
+Fri Sep 15 14:21:25 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* cpw.c: Add DES_CBC_MD5 and DES_CBC_CRC with the V4 salt as
+		default key/salt tuples to be added.  (Once proven's DES_*
+		folding code is implemented, we can shorten this list.)
+		Eventually, this list should be read in from kdc.conf.
+
+Thu Sep  7 20:41:24 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* loadv4.c (load_v4db): Provide a dummy routine if krb4
+		compatibility is not compiled in. 
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * cpw.c, dump.c, dumpv4.c, kdb5_edit.c, loadv4.c : 
+		s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * cpw.c, dump.c, dumpv4.c, kdb5_edit.c, loadv4.c : Remove krb5_enctype 
+		references, and replace with krb5_keytype where appropriate.
+
+Fri Aug 25 17:37:33 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* dumpv4.c - Fix handle_keys().  It was trying to recreate work that
+		has already been done.
+	* Makefile.in, .Sanitize, loadv4.c, kdb5_ed_ct.ct - Add lddb4, the
+		command to load a v4 dump file.  This is basically, kdb5_
+		convert reconstituted to fit within the framework of kdb5_edit.
+
+Thu Aug 24 19:28:39 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Mon Aug 21 16:45:39 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* dump.c - Completely rework this logic to support old (e.g. Beta 5
+		and previous) dump format and new dump format using the same
+		commands.  This is differentiated by using the "-old" command
+		qualifier.
+
+	* kdb5_edit.M - Add description of -R and -s.  Remove "ascii represen-
+		tation of a decimal number".  Remove "Bugs".
+
+Fri Aug 18 17:06:06 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* ss_wrapper.c - Change sense of fgets() check so scripts work.
+
+
+Tue Aug 15 14:22:50 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* kdb5_edit.c, ss_wrapper.c, cpw.c, kdb5_edit.h - Add support for
+		-s scriptfile and fix up assorted gcc -Wall complaints.
+
+
+Mon Aug 7 17:32:31 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* cpw.c - Use krb5_string_to_keysalts() to generate a list of unique
+		key/salt pairs supplied in argv.
+
+
+Mon Aug 07 11:16:03 1995  Chris Provenzano   (proven@mit.edu)
+
+	* cpw.c : Uses new kdb change password routines for ank, ark, cpw,
+		and crk. Also remove v4 variants of ank and cpw.
+	* krb5_edit.c : Deleted old variants of rotuines now in cpw.c
+	* kdb5_ed_ct.ct, kdb5_edit.M, tcl_wrapper.c: 
+		Removed references to v4 variants of ank and cpw.
+	* kdb5_edit.h (enter_pwd_key()) : Removed proto, it's nolonger 
+		necessary as it's a static routine in cpw.c
+
+Thu Aug 03 12:13:50 1995  Chris Provenzano   (proven@mit.edu)
+
+	* cpw.c : New change password code for kdb5_edit.
+	* dumpv4.c : Get it to compile with new kdb format.
+
+Mon Jul 31 15:47:30 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb5_edit.c - Use libkadm string conversion routines.  These are
+		shared by all utilities.
+	* Makefile.in - Remove getdate.y.
+	* configure.in - Remove getdate.y dependency checks.
+	* getdate.y - Sayonara.
+
+
+Thu Jul 27 15:01:01 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add --with-dbm and check for already checking for dbm.
+
+
+Thu Jul 27 02:59:05 1995   Chris Provenzano (proven@mit.edu)
+
+        * dump.c kdb5_edit.c kdb5_edit.h util.c : Use new kdb format.
+
+Mon Jul 17 15:00:08 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add KADM library.
+	* dumpv4.c - Change calling sequence to krb5_db_fetch_mkey().
+	* kdb5_edit.c - Change calling sequence to krb5_db_fetch_mkey() which
+		uses the stash file.  Add KDC profile reading/handling as a
+		supplement to command line supplied arguments.
+
+
+Wed Jul 12 12:01:04 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Temporarily add --with-kdb4 option.  Default is without
+		kdb4.  Without kdb4 enables a define.  With kdb4 uses -lkdb4 and
+		-l[n]dbm libraries.
+	* dumpv4.c -  Conditionalize references to kdb4 routines with
+		KDB4_DISABLE.  Replace two required routines:
+			kdb_encrypt_key -> pcbc_encrypt
+			kdb_get_master_key -> des_read_password/printf/key_sched
+
+
+Fri Jul 7 15:38:00 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling and LDFLAGS.
+	* configure.in - Add USE_<mumble> and KRB5_LIBRARIES.
+
+
+Thu Jun 15 15:34:59 EDT 1995	Paul Park	(pjpark@mit.edu)
+        * Makefile.in - Change explicit library names to -l<lib> form, and
+                change target link line to use $(LD) and associated flags.
+                Also, for K4, use KRB4_LIB and KRB4_CRYPTO_LIB, these wer
+                split out.
+        * configure.in - Add shared library usage check.
+
+Fri Jun  9 18:14:43 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+	* dumpv4.c: Change name of controlling #ifdef to be
+		KRB5_KRB4_COMPAT instead of KRB4.
+
+Sun May 21 14:20:32 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* dumpv4.c: Include k5-int.h before krb.h so that PROTOTYPE is not
+		redefined. 
+
+Sun May  7 13:46:30 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add AC_HEADER_STDC to define STDC_HEADERS for
+		getdate.y. 
+
+Mon May  1 13:36:41 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb5_edit.c (kdb5_edit_Init): Check the return code from
+		kdb5_init_context().
+
+Fri Apr 28 18:04:26 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (LOCAL_LIBRARIES): put KRB4_LIB inside KLIB, and put
+	KDB4_LIB ahead of them both.
+
+Thu Apr 27 13:47:23 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (LOCAL_LIBRARIES): use KRB4_LIB and KDB4_LIB
+	directly.
+	* configure.in: just use WITH_KRB4.
+
+Wed Apr 19 13:59:47 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb5_edit.c (kdb5_edit_Init): If a default realm is specified
+		(with -r), use krb5_set_default_realm so that created keys
+		will have the correct realm.
+
+Thu Mar 23 23:28:26 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdb5_edit.c (show_principal, parse_princ_args): Add
+		"support_desmd5" flag.
+
+Tue Mar 14 16:29:05 1995    <tytso@rsx-11.mit.edu>
+
+	* ss_wrapper.c (main): Set the return code from ss_execute_line(),
+		so that appropriate error checking is done.
+
+Thu Mar  2 12:18:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 11:53:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 02:06:26 1995  John Gilmore  (gnu at toad.com)
+
+	* dump.c, dumpv4.c, kdb5_edit.c, ss_wrapper.c, tcl_wrapper.c,
+	util.c: Avoid <krb5/...> includes.
+
+Thu Feb 23 19:52:35 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* kdb5_edit.c: add struct timeb and sys/timeb includes from
+	getdate.y.
+	(ftime): new function, in case we don't HAVE_FTIME.
+
+Tue Feb 14 17:55:47 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* kdb5_edit.c: add modent
+	* getdate.y: import get_date
+	* kdbt_ed_ct.ct: add modent
+	* configure.in:
+	* Makefile.in: support for getdate.y
+
+Wed Feb  8 20:08:36 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* kdb5_edit.c (show_principal): make sane and print all useful
+	fields
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+        * Removed all narrow types and references to wide.h and narrow.h
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Mon Dec 19 18:04:11 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in:
+	* Makefile.in:
+	* dumpv4.c (dump_v4db): Do the right thing if we are compiling
+		without V4 support.  (The dump_v4db command is disabled.)
+
+Wed Dec  7 00:07:46 1994    <tytso@rsx-11.mit.edu>
+
+	* dumpv4.c (v4_print_time): gmtime expects a pointer to a time_t,
+		not a long. On most systems these are the same, on
+		others.... 
+
+Wed Nov 16 01:03:42 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* dumpv4.c: new file. New command dump_v4db which creates a v4
+	slave dump out of a v5 database, leaving out any keys which aren't
+	using v4 salt, and any keys that aren't for the current
+	realm. Reencrypts using v4 master key, synthesizes arbitrary
+	master key version number.
+	* configure.in: use WITH_KRB4 for dump support.
+	* kdb5_ed_ct.ct: add new dump_v4 command.
+	* Makefile.in: link in dumpv4.
+
+Fri Oct 14 23:31:49 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* dump.c (load_db): When scanning a database entry, read
+		fail_auth_count into a temporary integer variable, and
+		then copy that into entry.fail_auth_count, which is a
+		char.  
+
+Fri Oct  7 00:01:40 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb5_edit.c (kdb5_edit_Init): Don't let errors in
+		set_dbname_help initially cause the exit status to be set.
+		Commands like load_db don't need a valid database to be
+		opened.
+
+	* ss_wrapper.c (main): Clear code before ss_execute_line, since
+		ss_execute_line doesn't set code to 0 if there are no
+	problems. 
+
+	* kdb5_edit.c (kdb5_edit_Init): Add a new option so that the
+		master key password can be entered on the command line ---
+		for testing only; not documented!!
+
+Mon Oct  3 19:10:47 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
+Thu Sep 29 15:52:22 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* dump.c (update_ok_file): Make sure mod time on the dump_ok file
+		is updated.  (Some systems don't update the mod-time when
+		a file is opened for writing.)
+
+	* Makefile.in: Relink executable when libraries change.
+
+	* kdb5_edit.c (show_principal): Pass variable with correct type to
+		ctime().
+
+	* tcl_wrapper.c (doquit):
+	  ss_wrapper.c (main):
+	  kdb5_edit.c:
+	  dump.c: Exit with a non-zero exit status if there was an error
+	  	  in a executed command.
+
+Thu Sep 15 11:00:30 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* dump.c (load_db): Fix error string on failed fopen. ("for
+		writing" -> "for reading")
+
+
diff --git a/mechglue/src/kadmin/dbutil/Makefile.in b/mechglue/src/kadmin/dbutil/Makefile.in
new file mode 100644
index 000000000..8e0725fe3
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/Makefile.in
@@ -0,0 +1,33 @@
+thisconfigdir=./..
+myfulldir=kadmin/dbutil
+mydir=dbutil
+BUILDTOP=$(REL)..$(S)..
+DEFINES = -DKDB4_DISABLE
+LOCALINCLUDES = -I. @KRB4_INCLUDES@ 
+PROG_LIBPATH=-L$(TOPLIBD) $(KRB4_LIBPATH)
+PROG_RPATH=$(KRB5_LIBDIR)
+KDB_DEP_LIB=$(DL_LIB) $(THREAD_LINKOPTS)
+
+PROG = kdb5_util
+###OBJS	= kdb5_util.o dump.o dumpv4.o loadv4.o \
+###	kdb5_create.o kadm5_create.o string_table.o kdb5_stash.o \
+###	kdb5_destroy.o ovload.o import_err.o strtok.o
+###
+
+OBJS = kdb5_util.o kdb5_create.o kadm5_create.o string_table.o kdb5_destroy.o kdb5_stash.o import_err.o strtok.o dump.o ovload.o
+
+all:: $(PROG)
+
+$(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o $(PROG) $(OBJS) $(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB4COMPAT_LIBS)
+
+import_err.c import_err.h: $(srcdir)/import_err.et
+
+$(OBJS): import_err.h
+
+install::
+	$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+	$(INSTALL_DATA) $(srcdir)/$(PROG).M ${DESTDIR}$(ADMIN_MANDIR)/$(PROG).8
+
+clean::
+	$(RM) $(PROG) $(OBJS) import_err.c import_err.h
diff --git a/mechglue/src/kadmin/dbutil/dump.c b/mechglue/src/kadmin/dbutil/dump.c
new file mode 100644
index 000000000..74f2cde68
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/dump.c
@@ -0,0 +1,2343 @@
+/*
+ * kadmin/dbutil/dump.c
+ *
+ * Copyright 1990,1991,2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Dump a KDC database
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <kadm5/server_internal.h>
+#include <krb5/kdb.h>
+#include <com_err.h>
+#include "kdb5_util.h"
+#if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
+#include <regex.h>
+#endif	/* HAVE_REGEX_H */
+
+/*
+ * Needed for master key conversion.
+ */
+static int			mkey_convert;
+static krb5_keyblock		new_master_keyblock;
+
+static int	backwards;
+static int	recursive;
+
+/*
+ * Use compile(3) if no regcomp present.
+ */
+#if	!defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H)
+#define	INIT		char *sp = instring;
+#define	GETC()		(*sp++)
+#define	PEEKC()		(*sp)
+#define	UNGETC(c)	(--sp)
+#define	RETURN(c)	return(c)
+#define	ERROR(c)	
+#define	RE_BUF_SIZE	1024
+#include <regexp.h>
+#endif	/* !HAVE_REGCOMP && HAVE_REGEXP_H */
+
+struct dump_args {
+    char		*programname;
+    FILE		*ofile;
+    krb5_context	kcontext;
+    char		**names;
+    int			nnames;
+    int			verbose;
+};
+
+static krb5_error_code dump_k5beta_iterator (krb5_pointer,
+					     krb5_db_entry *);
+static krb5_error_code dump_k5beta6_iterator (krb5_pointer,
+					      krb5_db_entry *);
+static krb5_error_code dump_k5beta6_iterator_ext (krb5_pointer,
+						  krb5_db_entry *,
+						  int);
+static krb5_error_code dump_k5beta7_princ (krb5_pointer,
+					   krb5_db_entry *);
+static krb5_error_code dump_k5beta7_princ_ext (krb5_pointer,
+					       krb5_db_entry *,
+					       int);
+static krb5_error_code dump_k5beta7_princ_withpolicy
+			(krb5_pointer, krb5_db_entry *);
+static krb5_error_code dump_ov_princ (krb5_pointer,
+				      krb5_db_entry *);
+static void dump_k5beta7_policy (void *, osa_policy_ent_t);
+
+typedef krb5_error_code (*dump_func)(krb5_pointer,
+				     krb5_db_entry *);
+
+static int process_k5beta_record (char *, krb5_context,
+				  FILE *, int, int *);
+static int process_k5beta6_record (char *, krb5_context,
+				   FILE *, int, int *);
+static int process_k5beta7_record (char *, krb5_context,
+				   FILE *, int, int *);
+static int process_ov_record (char *, krb5_context,
+			      FILE *, int, int *);
+typedef krb5_error_code (*load_func)(char *, krb5_context,
+				     FILE *, int, int *);
+
+typedef struct _dump_version {
+     char *name;
+     char *header;
+     int updateonly;
+     int create_kadm5;
+     dump_func dump_princ;
+     osa_adb_iter_policy_func dump_policy;
+     load_func load_record;
+} dump_version;
+
+dump_version old_version = {
+     "Kerberos version 5 old format",
+     "kdb5_edit load_dump version 2.0\n",
+     0,
+     1,
+     dump_k5beta_iterator,
+     NULL,
+     process_k5beta_record,
+};
+dump_version beta6_version = {
+     "Kerberos version 5 beta 6 format",
+     "kdb5_edit load_dump version 3.0\n",
+     0,
+     1,
+     dump_k5beta6_iterator,
+     NULL,
+     process_k5beta6_record,
+};
+dump_version beta7_version = {
+     "Kerberos version 5",
+     "kdb5_util load_dump version 4\n",
+     0,
+     0,
+     dump_k5beta7_princ,
+     dump_k5beta7_policy,
+     process_k5beta7_record,
+};
+dump_version ov_version = {
+     "OpenV*Secure V1.0",
+     "OpenV*Secure V1.0\t",
+     1,
+     1,
+     dump_ov_princ,
+     dump_k5beta7_policy,
+     process_ov_record
+};
+
+dump_version r1_3_version = {
+     "Kerberos version 5 release 1.3",
+     "kdb5_util load_dump version 5\n",
+     0,
+     0,
+     dump_k5beta7_princ_withpolicy,
+     dump_k5beta7_policy,
+     process_k5beta7_record,
+};
+
+/* External data */
+extern char		*current_dbname;
+extern krb5_boolean	dbactive;
+extern int		exit_status;
+extern krb5_context	util_context;
+extern kadm5_config_params global_params;
+
+/* Strings */
+
+#define k5beta_dump_header	"kdb5_edit load_dump version 2.0\n"
+
+static const char null_mprinc_name[] = "kdb5_dump@MISSING";
+
+/* Message strings */
+#define regex_err		"%s: regular expression error - %s\n"
+#define regex_merr		"%s: regular expression match error - %s\n"
+#define pname_unp_err		"%s: cannot unparse principal name (%s)\n"
+#define mname_unp_err		"%s: cannot unparse modifier name (%s)\n"
+#define nokeys_err		"%s: cannot find any standard key for %s\n"
+#define sdump_tl_inc_err	"%s: tagged data list inconsistency for %s (counted %d, stored %d)\n"
+#define stand_fmt_name		"Kerberos version 5"
+#define old_fmt_name		"Kerberos version 5 old format"
+#define b6_fmt_name		"Kerberos version 5 beta 6 format"
+#define ofopen_error		"%s: cannot open %s for writing (%s)\n"
+#define oflock_error		"%s: cannot lock %s (%s)\n"
+#define dumprec_err		"%s: error performing %s dump (%s)\n"
+#define dumphdr_err		"%s: error dumping %s header (%s)\n"
+#define trash_end_fmt		"%s(%d): ignoring trash at end of line: "
+#define read_name_string	"name string"
+#define read_key_type		"key type"
+#define read_key_data		"key data"
+#define read_pr_data1		"first set of principal attributes"
+#define read_mod_name		"modifier name"
+#define read_pr_data2		"second set of principal attributes"
+#define read_salt_data		"salt data"
+#define read_akey_type		"alternate key type"
+#define read_akey_data		"alternate key data"
+#define read_asalt_type		"alternate salt type"
+#define read_asalt_data		"alternate salt data"
+#define read_exp_data		"expansion data"
+#define store_err_fmt		"%s(%d): cannot store %s(%s)\n"
+#define add_princ_fmt		"%s\n"
+#define parse_err_fmt		"%s(%d): cannot parse %s (%s)\n"
+#define read_err_fmt		"%s(%d): cannot read %s\n"
+#define no_mem_fmt		"%s(%d): no memory for buffers\n"
+#define rhead_err_fmt		"%s(%d): cannot match size tokens\n"
+#define err_line_fmt		"%s: error processing line %d of %s\n"
+#define head_bad_fmt		"%s: dump header bad in %s\n"
+#define read_bytecnt		"record byte count"
+#define read_encdata		"encoded data"
+#define n_name_unp_fmt		"%s(%s): cannot unparse name\n"
+#define n_dec_cont_fmt		"%s(%s): cannot decode contents\n"
+#define read_nint_data		"principal static attributes"
+#define read_tcontents		"tagged data contents"
+#define read_ttypelen		"tagged data type and length"
+#define read_kcontents		"key data contents"
+#define read_ktypelen		"key data type and length"
+#define read_econtents		"extra data contents"
+#define k5beta_fmt_name		"Kerberos version 5 old format"
+#define standard_fmt_name	"Kerberos version 5 format"
+#define no_name_mem_fmt		"%s: cannot get memory for temporary name\n"
+#define ctx_err_fmt		"%s: cannot initialize Kerberos context\n"
+#define stdin_name		"standard input"
+#define remaster_err_fmt	"while re-encoding keys for principal %s with new master key"
+#define restfail_fmt		"%s: %s restore failed\n"
+#define close_err_fmt		"%s: cannot close database (%s)\n"
+#define dbinit_err_fmt		"%s: cannot initialize database (%s)\n"
+#define dblock_err_fmt		"%s: cannot initialize database lock (%s)\n"
+#define dbname_err_fmt		"%s: cannot set database name to %s (%s)\n"
+#define dbdelerr_fmt		"%s: cannot delete bad database %s (%s)\n"
+#define dbunlockerr_fmt		"%s: cannot unlock database %s (%s)\n"
+#define dbrenerr_fmt		"%s: cannot rename database %s to %s (%s)\n"
+#define dbcreaterr_fmt		"%s: cannot create database %s (%s)\n"
+#define dfile_err_fmt		"%s: cannot open %s (%s)\n"
+
+static const char oldoption[] = "-old";
+static const char b6option[] = "-b6";
+static const char b7option[] = "-b7";
+static const char verboseoption[] = "-verbose";
+static const char updateoption[] = "-update";
+static const char hashoption[] = "-hash";
+static const char ovoption[] = "-ov";
+static const char dump_tmptrail[] = "~";
+
+/*
+ * Re-encrypt the key_data with the new master key...
+ */
+static krb5_error_code master_key_convert(context, db_entry)
+    krb5_context	  context;
+    krb5_db_entry	* db_entry;
+{
+    krb5_error_code	retval;
+    krb5_keyblock 	v5plainkey, *key_ptr;
+    krb5_keysalt 	keysalt;
+    int	      i, j;
+    krb5_key_data	new_key_data, *key_data;
+    krb5_boolean	is_mkey;
+
+    is_mkey = krb5_principal_compare(context, master_princ, db_entry->princ);
+
+    if (is_mkey && db_entry->n_key_data != 1)
+	    fprintf(stderr,
+		    "Master key db entry has %d keys, expecting only 1!\n",
+		    db_entry->n_key_data);
+    for (i=0; i < db_entry->n_key_data; i++) {
+	key_data = &db_entry->key_data[i];
+	if (key_data->key_data_length == 0)
+	    continue;
+	retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
+					     key_data, &v5plainkey,
+					     &keysalt);
+	if (retval)
+		return retval;
+
+	memset(&new_key_data, 0, sizeof(new_key_data));
+	key_ptr = is_mkey ? &new_master_keyblock : &v5plainkey;
+	retval = krb5_dbekd_encrypt_key_data(context, &new_master_keyblock,
+					     key_ptr, &keysalt,
+					     key_data->key_data_kvno,
+					     &new_key_data);
+	if (retval)
+		return retval;
+	krb5_free_keyblock_contents(context, &v5plainkey);
+	for (j = 0; j < key_data->key_data_ver; j++) {
+	    if (key_data->key_data_length[j]) {
+		free(key_data->key_data_contents[j]);
+	    }
+	}
+	*key_data = new_key_data;
+    }
+    return 0;
+}
+
+/*
+ * Update the "ok" file.
+ */
+void update_ok_file (file_name)
+     char *file_name;
+{
+	/* handle slave locking/failure stuff */
+	char *file_ok;
+	int fd;
+	static char ok[]=".dump_ok";
+
+	if ((file_ok = (char *)malloc(strlen(file_name) + strlen(ok) + 1))
+	    == NULL) {
+		com_err(progname, ENOMEM,
+			"while allocating filename for update_ok_file");
+		exit_status++;
+		return;
+	}
+	strcpy(file_ok, file_name);
+	strcat(file_ok, ok);
+	if ((fd = open(file_ok, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
+		com_err(progname, errno, "while creating 'ok' file, '%s'",
+			file_ok);
+		exit_status++;
+		free(file_ok);
+		return;
+	}
+	if (write(fd, "", 1) != 1) {
+	    com_err(progname, errno, "while writing to 'ok' file, '%s'",
+		    file_ok);
+	     exit_status++;
+	     free(file_ok);
+	     return;
+	}
+
+	free(file_ok);
+	close(fd);
+	return;
+}
+
+/*
+ * name_matches()	- See if a principal name matches a regular expression
+ *			  or string.
+ */
+static int
+name_matches(name, arglist)
+    char		*name;
+    struct dump_args	*arglist;
+{
+#if	HAVE_REGCOMP
+    regex_t	match_exp;
+    regmatch_t	match_match;
+    int		match_error;
+    char	match_errmsg[BUFSIZ];
+    size_t	errmsg_size;
+#elif	HAVE_REGEXP_H
+    char	regexp_buffer[RE_BUF_SIZE];
+#elif	HAVE_RE_COMP
+    extern char	*re_comp();
+    char	*re_result;
+#endif	/* HAVE_RE_COMP */
+    int		i, match;
+
+    /*
+     * Plow, brute force, through the list of names/regular expressions.
+     */
+    match = (arglist->nnames) ? 0 : 1;
+    for (i=0; i<arglist->nnames; i++) {
+#if	HAVE_REGCOMP
+	/*
+	 * Compile the regular expression.
+	 */
+	match_error = regcomp(&match_exp, arglist->names[i], REG_EXTENDED);
+	if (match_error) {
+	    errmsg_size = regerror(match_error,
+				   &match_exp,
+				   match_errmsg,
+				   sizeof(match_errmsg));
+	    fprintf(stderr, regex_err, arglist->programname, match_errmsg);
+	    break;
+	}
+	/*
+	 * See if we have a match.
+	 */
+	match_error = regexec(&match_exp, name, 1, &match_match, 0);
+	if (match_error) {
+	    if (match_error != REG_NOMATCH) {
+		errmsg_size = regerror(match_error,
+				       &match_exp,
+				       match_errmsg,
+				       sizeof(match_errmsg));
+		fprintf(stderr, regex_merr,
+			arglist->programname, match_errmsg);
+		break;
+	    }
+	}
+	else {
+	    /*
+	     * We have a match.  See if it matches the whole
+	     * name.
+	     */
+	    if ((match_match.rm_so == 0) &&
+		(match_match.rm_eo == strlen(name)))
+		match = 1;
+	}
+	regfree(&match_exp);
+#elif	HAVE_REGEXP_H
+	/*
+	 * Compile the regular expression.
+	 */
+	compile(arglist->names[i],
+		regexp_buffer, 
+		®exp_buffer[RE_BUF_SIZE],
+		'\0');
+	if (step(name, regexp_buffer)) {
+	    if ((loc1 == name) &&
+		(loc2 == &name[strlen(name)]))
+		match = 1;
+	}
+#elif	HAVE_RE_COMP
+	/*
+	 * Compile the regular expression.
+	 */
+	if (re_result = re_comp(arglist->names[i])) {
+	    fprintf(stderr, regex_err, arglist->programname, re_result);
+	    break;
+	}
+	if (re_exec(name))
+	    match = 1;
+#else	/* HAVE_RE_COMP */
+	/*
+	 * If no regular expression support, then just compare the strings.
+	 */
+	if (!strcmp(arglist->names[i], name))
+	    match = 1;
+#endif	/* HAVE_REGCOMP */
+	if (match)
+	    break;
+    }
+    return(match);
+}
+
+static krb5_error_code
+find_enctype(dbentp, enctype, salttype, kentp)
+    krb5_db_entry	*dbentp;
+    krb5_enctype	enctype;
+    krb5_int32		salttype;
+    krb5_key_data	**kentp;
+{
+    int			i;
+    int			maxkvno;
+    krb5_key_data	*datap;
+
+    maxkvno = -1;
+    datap = (krb5_key_data *) NULL;
+    for (i=0; i<dbentp->n_key_data; i++) {
+	if (( (krb5_enctype)dbentp->key_data[i].key_data_type[0] == enctype) &&
+	    ((dbentp->key_data[i].key_data_type[1] == salttype) ||
+	     (salttype < 0))) {
+	    maxkvno = dbentp->key_data[i].key_data_kvno;
+	    datap = &dbentp->key_data[i];
+	}
+    }
+    if (maxkvno >= 0) {
+	*kentp = datap;
+	return(0);
+    }
+    return(ENOENT);    
+}
+
+#if 0
+/*
+ * dump_k5beta_header()	- Make a dump header that is recognizable by Kerberos
+ *			  Version 5 Beta 5 and previous releases.
+ */
+static krb5_error_code
+dump_k5beta_header(arglist)
+    struct dump_args *arglist;
+{
+    /* The old header consists of the leading string */
+    fprintf(arglist->ofile, k5beta_dump_header);
+    return(0);
+}
+#endif
+
+/*
+ * dump_k5beta_iterator()	- Dump an entry in a format that is usable
+ *				  by Kerberos Version 5 Beta 5 and previous
+ *				  releases.
+ */
+static krb5_error_code
+dump_k5beta_iterator(ptr, entry)
+    krb5_pointer	ptr;
+    krb5_db_entry	*entry;
+{
+    krb5_error_code	retval;
+    struct dump_args	*arg;
+    char		*name, *mod_name;
+    krb5_principal	mod_princ;
+    krb5_key_data	*pkey, *akey, nullkey;
+    krb5_timestamp	mod_date, last_pwd_change;
+    int			i;
+
+    /* Initialize */
+    arg = (struct dump_args *) ptr;
+    name = (char *) NULL;
+    mod_name = (char *) NULL;
+    memset(&nullkey, 0, sizeof(nullkey));
+
+    /*
+     * Flatten the principal name.
+     */
+    if ((retval = krb5_unparse_name(arg->kcontext,
+				    entry->princ,
+				    &name))) {
+	fprintf(stderr, pname_unp_err, 
+		arg->programname, error_message(retval));
+	return(retval);
+    }
+
+    /*
+     * Re-encode the keys in the new master key, if necessary.
+     */
+    if (mkey_convert) {
+	retval = master_key_convert(arg->kcontext, entry);
+	if (retval) {
+	    com_err(arg->programname, retval, remaster_err_fmt, name);
+	    return retval;
+	}
+    }
+    
+    /*
+     * If we don't have any match strings, or if our name matches, then
+     * proceed with the dump, otherwise, just forget about it.
+     */
+    if (!arg->nnames || name_matches(name, arg)) {
+	/*
+	 * Deserialize the modifier record.
+	 */
+	mod_name = (char *) NULL;
+	mod_princ = NULL;
+	last_pwd_change = mod_date = 0;
+	pkey = akey = (krb5_key_data *) NULL;
+	if (!(retval = krb5_dbe_lookup_mod_princ_data(arg->kcontext,
+						      entry,
+						      &mod_date,
+						      &mod_princ))) {
+	    if (mod_princ) {
+		/*
+		 * Flatten the modifier name.
+		 */
+		if ((retval = krb5_unparse_name(arg->kcontext,
+						mod_princ,
+						&mod_name)))
+		    fprintf(stderr, mname_unp_err, arg->programname,
+			    error_message(retval));
+		krb5_free_principal(arg->kcontext, mod_princ);
+	    }
+	}
+	if (!mod_name)
+	    mod_name = strdup(null_mprinc_name);
+
+	/*
+	 * Find the last password change record and set it straight.
+	 */
+	if ((retval =
+	     krb5_dbe_lookup_last_pwd_change(arg->kcontext, entry,
+					     &last_pwd_change))) {
+	    fprintf(stderr, nokeys_err, arg->programname, name);
+	    krb5_xfree(mod_name);
+	    krb5_xfree(name);
+	    return(retval);
+	}
+
+	/*
+	 * Find the 'primary' key and the 'alternate' key.
+	 */
+	if ((retval = find_enctype(entry,
+				   ENCTYPE_DES_CBC_CRC,
+				   KRB5_KDB_SALTTYPE_NORMAL,
+				   &pkey)) &&
+	    (retval = find_enctype(entry,
+				   ENCTYPE_DES_CBC_CRC,
+				   KRB5_KDB_SALTTYPE_V4,
+				   &akey))) {
+	    fprintf(stderr, nokeys_err, arg->programname, name);
+	    krb5_xfree(mod_name);
+	    krb5_xfree(name);
+	    return(retval);
+	}
+
+	/* If we only have one type, then ship it out as the primary. */
+	if (!pkey && akey) {
+	    pkey = akey;
+	    akey = &nullkey;
+	}
+	else {
+	    if (!akey)
+		akey = &nullkey;
+	}
+
+	/*
+	 * First put out strings representing the length of the variable
+	 * length data in this record, then the name and the primary key type.
+	 */
+	fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%s\t%d\t", strlen(name),
+		strlen(mod_name),
+		(krb5_int32) pkey->key_data_length[0],
+		(krb5_int32) akey->key_data_length[0],
+		(krb5_int32) pkey->key_data_length[1],
+		(krb5_int32) akey->key_data_length[1],
+		name,
+		(krb5_int32) pkey->key_data_type[0]);
+	for (i=0; i<pkey->key_data_length[0]; i++) {
+	    fprintf(arg->ofile, "%02x", pkey->key_data_contents[0][i]);
+	}
+	/*
+	 * Second, print out strings representing the standard integer
+	 * data in this record.
+	 */
+	fprintf(arg->ofile,
+		"\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%s\t%u\t%u\t%u\t",
+		(krb5_int32) pkey->key_data_kvno,
+		entry->max_life, entry->max_renewable_life,
+		1 /* Fake mkvno */, entry->expiration, entry->pw_expiration,
+		last_pwd_change, entry->last_success, entry->last_failed,
+		entry->fail_auth_count, mod_name, mod_date,
+		entry->attributes, pkey->key_data_type[1]);
+
+	/* Pound out the salt data, if present. */
+	for (i=0; i<pkey->key_data_length[1]; i++) {
+	    fprintf(arg->ofile, "%02x", pkey->key_data_contents[1][i]);
+	}
+	/* Pound out the alternate key type and contents */
+	fprintf(arg->ofile, "\t%u\t", akey->key_data_type[0]);
+	for (i=0; i<akey->key_data_length[0]; i++) {
+	    fprintf(arg->ofile, "%02x", akey->key_data_contents[0][i]);
+	}
+	/* Pound out the alternate salt type and contents */
+	fprintf(arg->ofile, "\t%u\t", akey->key_data_type[1]);
+	for (i=0; i<akey->key_data_length[1]; i++) {
+	    fprintf(arg->ofile, "%02x", akey->key_data_contents[1][i]);
+	}
+	/* Pound out the expansion data. (is null) */
+	for (i=0; i < 8; i++) {
+	    fprintf(arg->ofile, "\t%u", 0);
+	}
+	fprintf(arg->ofile, ";\n");
+	/* If we're blabbing, do it */
+	if (arg->verbose)
+	    fprintf(stderr, "%s\n", name);
+	krb5_xfree(mod_name);
+    }
+    krb5_xfree(name);
+    return(0);
+}
+
+/*
+ * dump_k5beta6_iterator()	- Output a dump record in krb5b6 format.
+ */
+static krb5_error_code
+dump_k5beta6_iterator(ptr, entry)
+    krb5_pointer	ptr;
+    krb5_db_entry	*entry;
+{
+    return dump_k5beta6_iterator_ext(ptr, entry, 0);
+}
+
+static krb5_error_code
+dump_k5beta6_iterator_ext(ptr, entry, kadm)
+    krb5_pointer	ptr;
+    krb5_db_entry	*entry;
+    int			kadm;
+{
+    krb5_error_code	retval;
+    struct dump_args	*arg;
+    char		*name;
+    krb5_tl_data	*tlp;
+    krb5_key_data	*kdata;
+    int			counter, skip, i, j;
+
+    /* Initialize */
+    arg = (struct dump_args *) ptr;
+    name = (char *) NULL;
+
+    /*
+     * Flatten the principal name.
+     */
+    if ((retval = krb5_unparse_name(arg->kcontext,
+				    entry->princ,
+				    &name))) {
+	fprintf(stderr, pname_unp_err, 
+		arg->programname, error_message(retval));
+	return(retval);
+    }
+
+    /*
+     * Re-encode the keys in the new master key, if necessary.
+     */
+    if (mkey_convert) {
+	retval = master_key_convert(arg->kcontext, entry);
+	if (retval) {
+	    com_err(arg->programname, retval, remaster_err_fmt, name);
+	    return retval;
+	}
+    }
+    
+    /*
+     * If we don't have any match strings, or if our name matches, then
+     * proceed with the dump, otherwise, just forget about it.
+     */
+    if (!arg->nnames || name_matches(name, arg)) {
+	/*
+	 * We'd like to just blast out the contents as they would appear in
+	 * the database so that we can just suck it back in, but it doesn't
+	 * lend itself to easy editing.
+	 */
+
+	/*
+	 * The dump format is as follows:
+	 *	len strlen(name) n_tl_data n_key_data e_length
+	 *	name
+	 *	attributes max_life max_renewable_life expiration
+	 *	pw_expiration last_success last_failed fail_auth_count
+	 *	n_tl_data*[type length <contents>]
+	 *	n_key_data*[ver kvno ver*(type length <contents>)]
+	 *	<e_data>
+	 * Fields which are not encapsulated by angle-brackets are to appear
+	 * verbatim.  A bracketed field's absence is indicated by a -1 in its
+	 * place
+	 */
+
+	/*
+	 * Make sure that the tagged list is reasonably correct.
+	 */
+	counter = skip = 0;
+	for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
+	     /*
+	      * don't dump tl data types we know aren't understood by
+	      * earlier revisions [krb5-admin/89]
+	      */
+	     switch (tlp->tl_data_type) {
+	     case KRB5_TL_KADM_DATA:
+		  if (kadm)
+		      counter++;
+		  else
+		      skip++;
+		  break;
+	     default:
+		  counter++;
+		  break;
+	     }
+	}
+	
+	if (counter + skip == entry->n_tl_data) {
+	    /* Pound out header */
+	    fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
+		    (int) entry->len,
+		    strlen(name),
+		    counter,
+		    (int) entry->n_key_data,
+		    (int) entry->e_length,
+		    name);
+	    fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+		    entry->attributes,
+		    entry->max_life,
+		    entry->max_renewable_life,
+		    entry->expiration,
+		    entry->pw_expiration,
+		    entry->last_success,
+		    entry->last_failed,
+		    entry->fail_auth_count);
+	    /* Pound out tagged data. */
+	    for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
+		if (tlp->tl_data_type == KRB5_TL_KADM_DATA && !kadm)
+		     continue; /* see above, [krb5-admin/89] */
+
+		fprintf(arg->ofile, "%d\t%d\t",
+			(int) tlp->tl_data_type,
+			(int) tlp->tl_data_length);
+		if (tlp->tl_data_length)
+		    for (i=0; i<tlp->tl_data_length; i++)
+			fprintf(arg->ofile, "%02x", tlp->tl_data_contents[i]);
+		else
+		    fprintf(arg->ofile, "%d", -1);
+		fprintf(arg->ofile, "\t");
+	    }
+
+	    /* Pound out key data */
+	    for (counter=0; counter<entry->n_key_data; counter++) {
+		kdata = &entry->key_data[counter];
+		fprintf(arg->ofile, "%d\t%d\t",
+			(int) kdata->key_data_ver,
+			(int) kdata->key_data_kvno);
+		for (i=0; i<kdata->key_data_ver; i++) {
+		    fprintf(arg->ofile, "%d\t%d\t",
+			    kdata->key_data_type[i],
+			    kdata->key_data_length[i]);
+		    if (kdata->key_data_length[i])
+			for (j=0; j<kdata->key_data_length[i]; j++)
+			    fprintf(arg->ofile, "%02x",
+				    kdata->key_data_contents[i][j]);
+		    else
+			fprintf(arg->ofile, "%d", -1);
+		    fprintf(arg->ofile, "\t");
+		}
+	    }
+
+	    /* Pound out extra data */
+	    if (entry->e_length)
+		for (i=0; i<entry->e_length; i++)
+		    fprintf(arg->ofile, "%02x", entry->e_data[i]);
+	    else
+		fprintf(arg->ofile, "%d", -1);
+
+	    /* Print trailer */
+	    fprintf(arg->ofile, ";\n");
+
+	    if (arg->verbose)
+		fprintf(stderr, "%s\n", name);
+	}
+	else {
+	    fprintf(stderr, sdump_tl_inc_err,
+		    arg->programname, name, counter+skip,
+		    (int) entry->n_tl_data); 
+	    retval = EINVAL;
+	}
+    }
+    krb5_xfree(name);
+    return(retval);
+}
+
+/*
+ * dump_k5beta7_iterator()	- Output a dump record in krb5b7 format.
+ */
+static krb5_error_code
+dump_k5beta7_princ(ptr, entry)
+    krb5_pointer	ptr;
+    krb5_db_entry	*entry;
+{
+    return dump_k5beta7_princ_ext(ptr, entry, 0);
+}
+
+static krb5_error_code
+dump_k5beta7_princ_ext(ptr, entry, kadm)
+    krb5_pointer	ptr;
+    krb5_db_entry	*entry;
+    int			kadm;
+{
+     krb5_error_code retval;
+     struct dump_args *arg;
+     char *name;
+     int tmp_nnames;
+
+     /* Initialize */
+     arg = (struct dump_args *) ptr;
+     name = (char *) NULL;
+
+     /*
+      * Flatten the principal name.
+      */
+     if ((retval = krb5_unparse_name(arg->kcontext,
+				     entry->princ,
+				     &name))) {
+	  fprintf(stderr, pname_unp_err, 
+		  arg->programname, error_message(retval));
+	  return(retval);
+     }
+     /*
+      * If we don't have any match strings, or if our name matches, then
+      * proceed with the dump, otherwise, just forget about it.
+      */
+     if (!arg->nnames || name_matches(name, arg)) {
+	  fprintf(arg->ofile, "princ\t");
+	  
+	  /* save the callee from matching the name again */
+	  tmp_nnames = arg->nnames;
+	  arg->nnames = 0;
+	  retval = dump_k5beta6_iterator_ext(ptr, entry, kadm);
+	  arg->nnames = tmp_nnames;
+     }
+
+     free(name);
+     return retval;
+}
+
+static krb5_error_code
+dump_k5beta7_princ_withpolicy(ptr, entry)
+    krb5_pointer	ptr;
+    krb5_db_entry	*entry;
+{
+    return dump_k5beta7_princ_ext(ptr, entry, 1);
+}
+
+void dump_k5beta7_policy(void *data, osa_policy_ent_t entry)
+{
+     struct dump_args *arg;
+
+     arg = (struct dump_args *) data;
+     fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", entry->name,
+	     entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
+	     entry->pw_min_classes, entry->pw_history_num,
+	     entry->policy_refcnt);
+}
+
+static void print_key_data(FILE *f, krb5_key_data *key_data)
+{
+     int c;
+     
+     fprintf(f, "%d\t%d\t", key_data->key_data_type[0],
+	     key_data->key_data_length[0]);
+     for(c = 0; c < key_data->key_data_length[0]; c++) 
+	  fprintf(f, "%02x ",
+		  key_data->key_data_contents[0][c]);
+}
+
+/*
+ * Function: print_princ
+ * 
+ * Purpose: output osa_adb_princ_ent data in a human
+ *	    readable format (which is a format suitable for
+ *	    ovsec_adm_import consumption)
+ *
+ * Arguments:
+ *	data		(input) pointer to a structure containing a FILE *
+ *			        and a record counter.
+ *	entry		(input) entry to get dumped.
+ * 	<return value>	void
+ *
+ * Requires:
+ *	nuttin
+ * 
+ * Effects:
+ *	writes data to the specified file pointerp.
+ *
+ * Modifies:
+ *	nuttin
+ * 
+ */
+static krb5_error_code dump_ov_princ(krb5_pointer ptr, krb5_db_entry *kdb)
+{
+    char *princstr;
+    int	x, y, foundcrc;
+    struct dump_args *arg;
+    krb5_tl_data tl_data;
+    osa_princ_ent_rec adb;
+    XDR xdrs;
+
+    arg = (struct dump_args *) ptr;
+    /*
+     * XXX Currently, lookup_tl_data always returns zero; it sets
+     * tl_data->tl_data_length to zero if the type isn't found.
+     * This should be fixed...
+     */
+    /*
+     * XXX Should this function do nothing for a principal with no
+     * admin data, or print a record of "default" values?   See
+     * comment in server_kdb.c to help decide.
+     */
+    tl_data.tl_data_type = KRB5_TL_KADM_DATA;
+    if (krb5_dbe_lookup_tl_data(arg->kcontext, kdb, &tl_data)
+	|| (tl_data.tl_data_length == 0))
+	 return 0;
+
+    memset(&adb, 0, sizeof(adb));
+    xdrmem_create(&xdrs, tl_data.tl_data_contents,
+		  tl_data.tl_data_length, XDR_DECODE);
+    if (! xdr_osa_princ_ent_rec(&xdrs, &adb)) {
+	 xdr_destroy(&xdrs);
+	 return(KADM5_XDR_FAILURE);
+    }
+    xdr_destroy(&xdrs);
+    
+    krb5_unparse_name(arg->kcontext, kdb->princ, &princstr);
+    fprintf(arg->ofile, "princ\t%s\t", princstr);
+    if(adb.policy == NULL)
+	fputc('\t', arg->ofile);
+    else
+	fprintf(arg->ofile, "%s\t", adb.policy);
+    fprintf(arg->ofile, "%lx\t%d\t%d\t%d", adb.aux_attributes,
+	    adb.old_key_len,adb.old_key_next, adb.admin_history_kvno);
+
+    for (x = 0; x < adb.old_key_len; x++) {
+	 foundcrc = 0;
+	 for (y = 0; y < adb.old_keys[x].n_key_data; y++) {
+	      krb5_key_data *key_data = &adb.old_keys[x].key_data[y];
+
+	      if (key_data->key_data_type[0] != ENCTYPE_DES_CBC_CRC)
+		   continue;
+	      if (foundcrc) {
+		   fprintf(stderr, "Warning!  Multiple DES-CBC-CRC keys "
+			   "for principal %s; skipping duplicates.\n",
+			   princstr);
+		   continue;
+	      }
+	      foundcrc++;
+
+	      fputc('\t', arg->ofile);
+	      print_key_data(arg->ofile, key_data);
+	 }
+	 if (!foundcrc)
+	      fprintf(stderr, "Warning!  No DES-CBC-CRC key for principal "
+		      "%s, cannot generate OV-compatible record; skipping\n",
+		      princstr);
+    }
+
+    fputc('\n', arg->ofile);
+    free(princstr);
+    return 0;
+}
+
+/*
+ * usage is:
+ *	dump_db [-old] [-b6] [-b7] [-ov] [-verbose] [-mkey_convert]
+ *		[-new_mkey_file mkey_file] [-rev] [-recurse]
+ *		[filename [principals...]]
+ */
+void
+dump_db(argc, argv)
+    int		argc;
+    char	**argv;
+{
+    FILE		*f;
+    struct dump_args	arglist;
+    char		*programname;
+    char		*ofile;
+    krb5_error_code	kret, retval;
+    dump_version	*dump;
+    int			aindex;
+    krb5_boolean	locked;
+    char		*new_mkey_file = 0;
+	
+    /*
+     * Parse the arguments.
+     */
+    programname = argv[0];
+    if (strrchr(programname, (int) '/'))
+	programname = strrchr(argv[0], (int) '/') + 1;
+    ofile = (char *) NULL;
+    dump = &r1_3_version;
+    arglist.verbose = 0;
+    new_mkey_file = 0;
+    mkey_convert = 0;
+    backwards = 0;
+    recursive = 0;
+
+    /*
+     * Parse the qualifiers.
+     */
+    for (aindex = 1; aindex < argc; aindex++) {
+	if (!strcmp(argv[aindex], oldoption))
+	     dump = &old_version;
+	else if (!strcmp(argv[aindex], b6option))
+	     dump = &beta6_version;
+	else if (!strcmp(argv[aindex], b7option))
+	     dump = &beta7_version;
+	else if (!strcmp(argv[aindex], ovoption))
+	     dump = &ov_version;
+	else if (!strcmp(argv[aindex], verboseoption))
+	    arglist.verbose++;
+	else if (!strcmp(argv[aindex], "-mkey_convert"))
+	    mkey_convert = 1;
+	else if (!strcmp(argv[aindex], "-new_mkey_file")) {
+	    new_mkey_file = argv[++aindex];
+	    mkey_convert = 1;
+        } else if (!strcmp(argv[aindex], "-rev"))
+	    backwards = 1;
+	else if (!strcmp(argv[aindex], "-recurse"))
+	    recursive = 1;
+	else
+	    break;
+    }
+
+    arglist.names = (char **) NULL;
+    arglist.nnames = 0;
+    if (aindex < argc) {
+	ofile = argv[aindex];
+	aindex++;
+	if (aindex < argc) {
+	    arglist.names = &argv[aindex];
+	    arglist.nnames = argc - aindex;
+	}
+    }
+
+    /*
+     * Make sure the database is open.  The policy database only has
+     * to be opened if we try a dump that uses it.
+     */
+    if (!dbactive) {
+	com_err(argv[0], 0, Err_no_database);
+	exit_status++;
+	return;
+    }
+
+    /*
+     * If we're doing a master key conversion, set up for it.
+     */
+    if (mkey_convert) {
+	    if (!valid_master_key) {
+		    /* TRUE here means read the keyboard, but only once */
+		    retval = krb5_db_fetch_mkey(util_context,
+						master_princ,
+						master_keyblock.enctype,
+						TRUE, FALSE,
+						(char *) NULL, 0,
+						&master_keyblock);
+		    if (retval) {
+			    com_err(argv[0], retval,
+				    "while reading master key");
+			    exit(1);
+		    }
+		    retval = krb5_db_verify_master_key(util_context,
+						       master_princ,
+						       &master_keyblock);
+		    if (retval) {
+			    com_err(argv[0], retval,
+				    "while verifying master key");
+			    exit(1);
+		    }
+	    }
+	    new_master_keyblock.enctype = global_params.enctype;
+	    if (new_master_keyblock.enctype == ENCTYPE_UNKNOWN)
+		    new_master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+	    if (!new_mkey_file)
+		    printf("Please enter new master key....\n");
+	    if ((retval = krb5_db_fetch_mkey(util_context, master_princ, 
+					     new_master_keyblock.enctype,
+					     (new_mkey_file == 0) ? 
+					        (krb5_boolean) 1 : 0, 
+					     TRUE, 
+					     new_mkey_file, 0,
+					     &new_master_keyblock))) { 
+		    com_err(argv[0], retval, "while reading new master key");
+		    exit(1);
+	    }
+    }
+
+    kret = 0;
+    locked = 0;
+    if (ofile && strcmp(ofile, "-")) {
+	/*
+	 * Discourage accidental dumping to filenames beginning with '-'.
+	 */
+	if (ofile[0] == '-')
+	    usage();
+	/*
+	 * Make sure that we don't open and truncate on the fopen,
+	 * since that may hose an on-going kprop process.
+	 * 
+	 * We could also control this by opening for read and
+	 * write, doing an flock with LOCK_EX, and then
+	 * truncating the file once we have gotten the lock,
+	 * but that would involve more OS dependencies than I
+	 * want to get into.
+	 */
+	unlink(ofile);
+	if (!(f = fopen(ofile, "w"))) {
+	    fprintf(stderr, ofopen_error,
+		    programname, ofile, error_message(errno));
+	    exit_status++;
+	    return;
+       }
+	if ((kret = krb5_lock_file(util_context,
+				   fileno(f),
+				   KRB5_LOCKMODE_EXCLUSIVE))) {
+	    fprintf(stderr, oflock_error,
+		    programname, ofile, error_message(kret));
+	    exit_status++;
+	}
+	else
+	    locked = 1;
+    } else {
+	f = stdout;
+    }
+    if (f && !(kret)) {
+	arglist.programname = programname;
+	arglist.ofile = f;
+	arglist.kcontext = util_context;
+	fprintf(arglist.ofile, "%s", dump->header);
+	if (dump->header[strlen(dump->header)-1] != '\n')
+	     fputc('\n', arglist.ofile);
+	
+	if ((kret = krb5_db_iterate(util_context,
+				    NULL,
+				    dump->dump_princ,
+				    (krb5_pointer) &arglist))) { /* TBD: backwards and recursive not supported */
+	     fprintf(stderr, dumprec_err,
+		     programname, dump->name, error_message(kret));
+	     exit_status++;
+	}
+	if (dump->dump_policy &&
+	    (kret = krb5_db_iter_policy( util_context, "*", dump->dump_policy,
+					 &arglist))) { 
+	     fprintf(stderr, dumprec_err, programname, dump->name,
+		     error_message(kret));
+	     exit_status++;
+	}
+	if (ofile && f != stdout && !exit_status) {
+	     fclose(f);
+	     update_ok_file(ofile);
+	}
+    }
+    if (locked)
+	(void) krb5_lock_file(util_context, fileno(f), KRB5_LOCKMODE_UNLOCK);
+}
+
+/*
+ * Read a string of bytes while counting the number of lines passed.
+ */
+static int
+read_string(f, buf, len, lp)
+    FILE	*f;
+    char	*buf;
+    int		len;
+    int		*lp;
+{
+    int c;
+    int i, retval;
+
+    retval = 0;
+    for (i=0; i<len; i++) {
+	c = fgetc(f);
+	if (c < 0) {
+	    retval = 1;
+	    break;
+	}
+	if (c == '\n')
+	    (*lp)++;
+	buf[i] = (char) c;
+    }
+    buf[len] = '\0';
+    return(retval);
+}
+
+/*
+ * Read a string of two character representations of bytes.
+ */
+static int
+read_octet_string(f, buf, len)
+    FILE	*f;
+    krb5_octet	*buf;
+    int		len;
+{
+    int c;
+    int i, retval;
+
+    retval = 0;
+    for (i=0; i<len; i++) {
+	if (fscanf(f, "%02x", &c) != 1) {
+	    retval = 1;
+	    break;
+	}
+	buf[i] = (krb5_octet) c;
+    }
+    return(retval);
+}
+
+/*
+ * Find the end of an old format record.
+ */
+static void
+find_record_end(f, fn, lineno)
+    FILE	*f;
+    char	*fn;
+    int		lineno;
+{
+    int	ch;
+
+    if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) {
+	fprintf(stderr, trash_end_fmt, fn, lineno);
+	while (ch != '\n') {
+	    putc(ch, stderr);
+	    ch = fgetc(f);
+	}
+	putc(ch, stderr);
+    }
+}
+
+#if 0
+/*
+ * update_tl_data()	- Generate the tl_data entries.
+ */
+static krb5_error_code
+update_tl_data(kcontext, dbentp, mod_name, mod_date, last_pwd_change)
+    krb5_context	kcontext;
+    krb5_db_entry	*dbentp;
+    krb5_principal	mod_name;
+    krb5_timestamp	mod_date;
+    krb5_timestamp	last_pwd_change;
+{
+    krb5_error_code	kret;
+
+    kret = 0 ;
+
+    /*
+     * Handle modification principal.
+     */
+    if (mod_name) {
+	krb5_tl_mod_princ	mprinc;
+
+	memset(&mprinc, 0, sizeof(mprinc));
+	if (!(kret = krb5_copy_principal(kcontext,
+					 mod_name,
+					 &mprinc.mod_princ))) {
+	    mprinc.mod_date = mod_date;
+	    kret = krb5_dbe_encode_mod_princ_data(kcontext,
+						  &mprinc,
+						  dbentp);
+	}
+	if (mprinc.mod_princ)
+	    krb5_free_principal(kcontext, mprinc.mod_princ);
+    }
+
+    /*
+     * Handle last password change.
+     */
+    if (!kret) {
+	krb5_tl_data	*pwchg;
+	krb5_boolean	linked;
+
+	/* Find a previously existing entry */
+	for (pwchg = dbentp->tl_data;
+	     (pwchg) && (pwchg->tl_data_type != KRB5_TL_LAST_PWD_CHANGE);
+	     pwchg = pwchg->tl_data_next);
+
+	/* Check to see if we found one. */
+	linked = 0;
+	if (!pwchg) {
+	    /* No, allocate a new one */
+	    if ((pwchg = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
+		memset(pwchg, 0, sizeof(krb5_tl_data));
+		if (!(pwchg->tl_data_contents =
+		      (krb5_octet *) malloc(sizeof(krb5_timestamp)))) {
+		    free(pwchg);
+		    pwchg = (krb5_tl_data *) NULL;
+		}
+		else {
+		    pwchg->tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
+		    pwchg->tl_data_length =
+			(krb5_int16) sizeof(krb5_timestamp);
+		}
+	    }
+	}
+	else
+	    linked = 1;
+
+	/* Do we have an entry? */
+	if (pwchg && pwchg->tl_data_contents) {
+	    /* Encode it */
+	    krb5_kdb_encode_int32(last_pwd_change, pwchg->tl_data_contents);
+	    /* Link it in if necessary */
+	    if (!linked) {
+		pwchg->tl_data_next = dbentp->tl_data;
+		dbentp->tl_data = pwchg;
+		dbentp->n_tl_data++;
+	    }
+	}
+	else
+	    kret = ENOMEM;
+    }
+
+    return(kret);
+}
+#endif
+
+/*
+ * process_k5beta_record()	- Handle a dump record in old format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta_record(fname, kcontext, filep, verbose, linenop)
+    char		*fname;
+    krb5_context	kcontext;
+    FILE		*filep;
+    int			verbose;
+    int			*linenop;
+{
+    int			nmatched;
+    int			retval;
+    krb5_db_entry	dbent;
+    int			name_len, mod_name_len, key_len;
+    int			alt_key_len, salt_len, alt_salt_len;
+    char		*name;
+    char		*mod_name;
+    int			tmpint1, tmpint2, tmpint3;
+    int			error;
+    const char		*try2read;
+    int			i;
+    krb5_key_data	*pkey, *akey;
+    krb5_timestamp	last_pwd_change, mod_date;
+    krb5_principal	mod_princ;
+    krb5_error_code	kret;
+
+    try2read = (char *) NULL;
+    (*linenop)++;
+    retval = 1;
+    memset((char *)&dbent, 0, sizeof(dbent));
+
+    /* Make sure we've got key_data entries */
+    if (krb5_dbe_create_key_data(kcontext, &dbent) ||
+	krb5_dbe_create_key_data(kcontext, &dbent)) {
+	krb5_db_free_principal(kcontext, &dbent, 1);
+	return(1);
+    }
+    pkey = &dbent.key_data[0];
+    akey = &dbent.key_data[1];
+
+    /*
+     * Match the sizes.  6 tokens to match.
+     */
+    nmatched = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t",
+		      &name_len, &mod_name_len, &key_len,
+		      &alt_key_len, &salt_len, &alt_salt_len);
+    if (nmatched == 6) {
+        pkey->key_data_length[0] = key_len;
+	akey->key_data_length[0] = alt_key_len;
+	pkey->key_data_length[1] = salt_len;
+	akey->key_data_length[1] = alt_salt_len;
+	name = (char *) NULL;
+	mod_name = (char *) NULL;
+	/*
+	 * Get the memory for the variable length fields.
+	 */
+	if ((name = (char *) malloc((size_t) (name_len + 1))) &&
+	    (mod_name = (char *) malloc((size_t) (mod_name_len + 1))) &&
+	    (!key_len ||
+	     (pkey->key_data_contents[0] = 
+	      (krb5_octet *) malloc((size_t) (key_len + 1)))) &&
+	    (!alt_key_len ||
+	     (akey->key_data_contents[0] = 
+	      (krb5_octet *) malloc((size_t) (alt_key_len + 1)))) &&
+	    (!salt_len ||
+	     (pkey->key_data_contents[1] = 
+	      (krb5_octet *) malloc((size_t) (salt_len + 1)))) &&
+	    (!alt_salt_len ||
+	     (akey->key_data_contents[1] = 
+	      (krb5_octet *) malloc((size_t) (alt_salt_len + 1))))
+	    ) {
+	    error = 0;
+
+	    /* Read the principal name */
+	    if (read_string(filep, name, name_len, linenop)) {
+		try2read = read_name_string;
+		error++;
+	    }
+	    /* Read the key type */
+	    if (!error && (fscanf(filep, "\t%d\t", &tmpint1) != 1)) {
+		try2read = read_key_type;
+		error++;
+	    }
+	    pkey->key_data_type[0] = tmpint1;
+	    /* Read the old format key */
+	    if (!error && read_octet_string(filep,
+					    pkey->key_data_contents[0],
+					    pkey->key_data_length[0])) {
+		try2read = read_key_data;
+		error++;
+	    }
+	    /* convert to a new format key */
+	    /* the encrypted version is stored as the unencrypted key length
+	       (4 bytes, MSB first) followed by the encrypted key. */
+	    if ((pkey->key_data_length[0] > 4)
+		&& (pkey->key_data_contents[0][0] == 0)
+		&& (pkey->key_data_contents[0][1] == 0)) {
+	      /* this really does look like an old key, so drop and swap */
+	      /* the *new* length is 2 bytes, LSB first, sigh. */
+	      size_t shortlen = pkey->key_data_length[0]-4+2;
+	      krb5_octet *shortcopy = (krb5_octet *) malloc(shortlen);
+	      krb5_octet *origdata = pkey->key_data_contents[0];
+	      shortcopy[0] = origdata[3];
+	      shortcopy[1] = origdata[2];
+	      memcpy(shortcopy+2,origdata+4,shortlen-2);
+	      free(origdata);
+	      pkey->key_data_length[0] = shortlen;
+	      pkey->key_data_contents[0] = shortcopy;
+	    }
+	      
+	    /* Read principal attributes */
+	    if (!error && (fscanf(filep,
+				  "\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t",
+				  &tmpint1, &dbent.max_life,
+				  &dbent.max_renewable_life,
+				  &tmpint2, &dbent.expiration,
+				  &dbent.pw_expiration, &last_pwd_change,
+				  &dbent.last_success, &dbent.last_failed,
+				  &tmpint3) != 10)) {
+		try2read = read_pr_data1;
+		error++;
+	    }
+	    pkey->key_data_kvno = tmpint1;
+	    dbent.fail_auth_count = tmpint3;
+	    /* Read modifier name */
+	    if (!error && read_string(filep,
+				      mod_name,
+				      mod_name_len,
+				      linenop)) {
+		try2read = read_mod_name;
+		error++;
+	    }
+	    /* Read second set of attributes */
+	    if (!error && (fscanf(filep, "\t%u\t%u\t%u\t",
+				  &mod_date, &dbent.attributes,
+				  &tmpint1) != 3)) {
+		try2read = read_pr_data2;
+		error++;
+	    }
+	    pkey->key_data_type[1] = tmpint1;
+	    /* Read salt data */
+	    if (!error && read_octet_string(filep,
+					    pkey->key_data_contents[1],
+					    pkey->key_data_length[1])) {
+		try2read = read_salt_data;
+		error++;
+	    }
+	    /* Read alternate key type */
+	    if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
+		try2read = read_akey_type;
+		error++;
+	    }
+	    akey->key_data_type[0] = tmpint1;
+	    /* Read alternate key */
+	    if (!error && read_octet_string(filep,
+					    akey->key_data_contents[0],
+					    akey->key_data_length[0])) {
+		try2read = read_akey_data;
+		error++;
+	    }
+
+	    /* convert to a new format key */
+	    /* the encrypted version is stored as the unencrypted key length
+	       (4 bytes, MSB first) followed by the encrypted key. */
+	    if ((akey->key_data_length[0] > 4)
+		&& (akey->key_data_contents[0][0] == 0)
+		&& (akey->key_data_contents[0][1] == 0)) {
+	      /* this really does look like an old key, so drop and swap */
+	      /* the *new* length is 2 bytes, LSB first, sigh. */
+	      size_t shortlen = akey->key_data_length[0]-4+2;
+	      krb5_octet *shortcopy = (krb5_octet *) malloc(shortlen);
+	      krb5_octet *origdata = akey->key_data_contents[0];
+	      shortcopy[0] = origdata[3];
+	      shortcopy[1] = origdata[2];
+	      memcpy(shortcopy+2,origdata+4,shortlen-2);
+	      free(origdata);
+	      akey->key_data_length[0] = shortlen;
+	      akey->key_data_contents[0] = shortcopy;
+	    }
+	      
+	    /* Read alternate salt type */
+	    if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
+		try2read = read_asalt_type;
+		error++;
+	    }
+	    akey->key_data_type[1] = tmpint1;
+	    /* Read alternate salt data */
+	    if (!error && read_octet_string(filep,
+					    akey->key_data_contents[1],
+					    akey->key_data_length[1])) {
+		try2read = read_asalt_data;
+		error++;
+	    }
+	    /* Read expansion data - discard it */
+	    if (!error) {
+		for (i=0; i<8; i++) {
+		    if (fscanf(filep, "\t%u", &tmpint1) != 1) {
+			try2read = read_exp_data;
+			error++;
+			break;
+		    }
+		}
+		if (!error)
+		    find_record_end(filep, fname, *linenop);
+	    }
+	
+	    /*
+	     * If no error, then we're done reading.  Now parse the names
+	     * and store the database dbent.
+	     */
+	    if (!error) {
+		if (!(kret = krb5_parse_name(kcontext,
+					     name,
+					     &dbent.princ))) {
+		    if (!(kret = krb5_parse_name(kcontext,
+						 mod_name,
+						 &mod_princ))) {
+			if (!(kret =
+			      krb5_dbe_update_mod_princ_data(kcontext,
+							     &dbent,
+							     mod_date,
+							     mod_princ)) &&
+			    !(kret =
+			      krb5_dbe_update_last_pwd_change(kcontext,
+							      &dbent,
+							      last_pwd_change))) {
+			    int one = 1;
+
+			    dbent.len = KRB5_KDB_V1_BASE_LENGTH;
+			    pkey->key_data_ver = (pkey->key_data_type[1] || pkey->key_data_length[1]) ?
+				2 : 1;
+			    akey->key_data_ver = (akey->key_data_type[1] || akey->key_data_length[1]) ?
+				2 : 1;
+			    if ((pkey->key_data_type[0] ==
+				 akey->key_data_type[0]) &&
+				(pkey->key_data_type[1] ==
+				 akey->key_data_type[1]))
+				dbent.n_key_data--;
+			    else if ((akey->key_data_type[0] == 0)
+				     && (akey->key_data_length[0] == 0)
+				     && (akey->key_data_type[1] == 0)
+				     && (akey->key_data_length[1] == 0))
+			        dbent.n_key_data--;
+			    if ((kret = krb5_db_put_principal(kcontext,
+							      &dbent,
+							      &one)) ||
+				(one != 1)) {
+				fprintf(stderr, store_err_fmt,
+					fname, *linenop, name,
+					error_message(kret));
+				error++;
+			    }
+			    else {
+				if (verbose)
+				    fprintf(stderr, add_princ_fmt, name);
+				retval = 0;
+			    }
+			    dbent.n_key_data = 2;
+			}
+			krb5_free_principal(kcontext, mod_princ);
+		    }
+		    else {
+			fprintf(stderr, parse_err_fmt, 
+				fname, *linenop, mod_name, 
+				error_message(kret));
+			error++;
+		    }
+		}
+		else {
+		    fprintf(stderr, parse_err_fmt,
+			    fname, *linenop, name, error_message(kret));
+		    error++;
+		}
+	    }
+	    else {
+		fprintf(stderr, read_err_fmt, fname, *linenop, try2read);
+	    }
+	}
+	else {
+	    fprintf(stderr, no_mem_fmt, fname, *linenop);
+	}
+
+	krb5_db_free_principal(kcontext, &dbent, 1);
+	if (mod_name)
+	    free(mod_name);
+	if (name)
+	    free(name);
+    }
+    else {
+	if (nmatched != EOF)
+	    fprintf(stderr, rhead_err_fmt, fname, *linenop);
+	else
+	    retval = -1;
+    }
+    return(retval);
+}
+
+/*
+ * process_k5beta6_record()	- Handle a dump record in krb5b6 format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta6_record(fname, kcontext, filep, verbose, linenop)
+    char		*fname;
+    krb5_context	kcontext;
+    FILE		*filep;
+    int			verbose;
+    int			*linenop;
+{
+    int			retval;
+    krb5_db_entry	dbentry;
+    krb5_int32		t1, t2, t3, t4, t5, t6, t7, t8, t9;
+    int			nread;
+    int			error;
+    int			i, j, one;
+    char		*name;
+    krb5_key_data	*kp, *kdatap;
+    krb5_tl_data	**tlp, *tl;
+    krb5_octet 		*op;
+    krb5_error_code	kret;
+    const char		*try2read;
+
+    try2read = (char *) NULL;
+    memset((char *) &dbentry, 0, sizeof(dbentry));
+    (*linenop)++;
+    retval = 1;
+    name = (char *) NULL;
+    kp = (krb5_key_data *) NULL;
+    op = (krb5_octet *) NULL;
+    error = 0;
+    kret = 0;
+    nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t", &t1, &t2, &t3, &t4, &t5);
+    if (nread == 5) {
+	/* Get memory for flattened principal name */
+	if (!(name = (char *) malloc((size_t) t2 + 1)))
+	    error++;
+
+	/* Get memory for and form tagged data linked list */
+	tlp = &dbentry.tl_data;
+	for (i=0; i<t3; i++) {
+	    if ((*tlp = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
+		memset(*tlp, 0, sizeof(krb5_tl_data));
+		tlp = &((*tlp)->tl_data_next);
+		dbentry.n_tl_data++;
+	    }
+	    else {
+		error++;
+		break;
+	    }
+	}
+
+	/* Get memory for key list */
+	if (t4 && !(kp = (krb5_key_data *) malloc((size_t)
+						  (t4*sizeof(krb5_key_data)))))
+	    error++;
+
+	/* Get memory for extra data */
+	if (t5 && !(op = (krb5_octet *) malloc((size_t) t5)))
+	    error++;
+
+	if (!error) {
+	    dbentry.len = t1;
+	    dbentry.n_key_data = t4;
+	    dbentry.e_length = t5;
+	    if (kp) {
+		memset(kp, 0, (size_t) (t4*sizeof(krb5_key_data)));
+		dbentry.key_data = kp;
+		kp = (krb5_key_data *) NULL;
+	    }
+	    if (op) {
+		memset(op, 0, (size_t) t5);
+		dbentry.e_data = op;
+		op = (krb5_octet *) NULL;
+	    }
+
+	    /* Read in and parse the principal name */
+	    if (!read_string(filep, name, t2, linenop) &&
+		!(kret = krb5_parse_name(kcontext, name, &dbentry.princ))) {
+
+		/* Get the fixed principal attributes */
+		nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+			       &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9);
+		if (nread == 8) {
+		    dbentry.attributes = (krb5_flags) t2;
+		    dbentry.max_life = (krb5_deltat) t3;
+		    dbentry.max_renewable_life = (krb5_deltat) t4;
+		    dbentry.expiration = (krb5_timestamp) t5;
+		    dbentry.pw_expiration = (krb5_timestamp) t6;
+		    dbentry.last_success = (krb5_timestamp) t7;
+		    dbentry.last_failed = (krb5_timestamp) t8;
+		    dbentry.fail_auth_count = (krb5_kvno) t9;
+		} else {
+		    try2read = read_nint_data;
+		    error++;
+		}
+
+		/*
+		 * Get the tagged data.
+		 *
+		 * Really, this code ought to discard tl data types
+		 * that it knows are special to the current version
+		 * and were not supported in the previous version.
+		 * But it's a pain to implement that here, and doing
+		 * it at dump time has almost as good an effect, so
+		 * that's what I did.  [krb5-admin/89]
+		 */
+		if (!error && dbentry.n_tl_data) {
+		    for (tl = dbentry.tl_data; tl; tl = tl->tl_data_next) {
+			nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
+			if (nread == 2) {
+			    tl->tl_data_type = (krb5_int16) t1;
+			    tl->tl_data_length = (krb5_int16) t2;
+			    if (tl->tl_data_length) {
+				if (!(tl->tl_data_contents =
+				      (krb5_octet *) malloc((size_t) t2+1)) ||
+				    read_octet_string(filep,
+						      tl->tl_data_contents,
+						      t2)) {
+				    try2read = read_tcontents;
+				    error++;
+				    break;
+				}
+			    }
+			    else {
+				/* Should be a null field */
+				nread = fscanf(filep, "%d", &t9);
+				if ((nread != 1) || (t9 != -1)) {
+				    error++;
+				    try2read = read_tcontents;
+				    break;
+				}
+			    }
+			}
+			else {
+			    try2read = read_ttypelen;
+			    error++;
+			    break;
+			}
+		    }
+		}
+
+		/* Get the key data */
+		if (!error && dbentry.n_key_data) {
+		    for (i=0; !error && (i<dbentry.n_key_data); i++) {
+			kdatap = &dbentry.key_data[i];
+			nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
+			if (nread == 2) {
+			    kdatap->key_data_ver = (krb5_int16) t1;
+			    kdatap->key_data_kvno = (krb5_int16) t2;
+
+			    for (j=0; j<t1; j++) {
+				nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
+				if (nread == 2) {
+				    kdatap->key_data_type[j] = t3;
+				    kdatap->key_data_length[j] = t4;
+				    if (t4) {
+					if (!(kdatap->key_data_contents[j] =
+					      (krb5_octet *)
+					      malloc((size_t) t4+1)) ||
+					    read_octet_string(filep,
+							      kdatap->key_data_contents[j],
+							      t4)) {
+					    try2read = read_kcontents;
+					    error++;
+					    break;
+					}
+				    }
+				    else {
+					/* Should be a null field */
+					nread = fscanf(filep, "%d", &t9);
+					if ((nread != 1) || (t9 != -1)) {
+					    error++;
+					    try2read = read_kcontents;
+					    break;
+					}
+				    }
+				}
+				else {
+				    try2read = read_ktypelen;
+				    error++;
+				    break;
+				}
+			    }
+			}
+		    }
+		}
+
+		/* Get the extra data */
+		if (!error && dbentry.e_length) {
+		    if (read_octet_string(filep,
+					  dbentry.e_data,
+					  (int) dbentry.e_length)) {
+			try2read = read_econtents;
+			error++;
+		    }
+		}
+		else {
+		    nread = fscanf(filep, "%d", &t9);
+		    if ((nread != 1) || (t9 != -1)) {
+			error++;
+			try2read = read_econtents;
+		    }
+		}
+
+		/* Finally, find the end of the record. */
+		if (!error)
+		    find_record_end(filep, fname, *linenop);
+
+		/*
+		 * We have either read in all the data or choked.
+		 */
+		if (!error) {
+		    one = 1;
+		    if ((kret = krb5_db_put_principal(kcontext,
+						      &dbentry,
+						      &one))) {
+			fprintf(stderr, store_err_fmt,
+				fname, *linenop,
+				name, error_message(kret));
+		    }
+		    else {
+			if (verbose)
+			    fprintf(stderr, add_princ_fmt, name);
+			retval = 0;
+		    }
+		}
+		else {
+		    fprintf(stderr, read_err_fmt, fname, *linenop, try2read);
+		}
+	    }
+	    else {
+		if (kret)
+		    fprintf(stderr, parse_err_fmt,
+			    fname, *linenop, name, error_message(kret));
+		else
+		    fprintf(stderr, no_mem_fmt, fname, *linenop);
+	    }
+	}
+	else {
+	    fprintf(stderr, rhead_err_fmt, fname, *linenop);
+	}
+
+	if (op)
+	    free(op);
+	if (kp)
+	    free(kp);
+	if (name)
+	    free(name);
+	krb5_db_free_principal(kcontext, &dbentry, 1);
+    }
+    else {
+	if (nread == EOF)
+	    retval = -1;
+    }
+    return(retval);
+}
+
+static int 
+process_k5beta7_policy(fname, kcontext, filep, verbose, linenop, pol_db)
+    char		*fname;
+    krb5_context	kcontext;
+    FILE		*filep;
+    int			verbose;
+    int			*linenop;
+    void *pol_db;
+{
+    osa_policy_ent_rec rec;
+    char namebuf[1024];
+    int nread, ret;
+
+    (*linenop)++;
+    rec.name = namebuf;
+
+    nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d", rec.name,
+		   &rec.pw_min_life, &rec.pw_max_life,
+		   &rec.pw_min_length, &rec.pw_min_classes,
+		   &rec.pw_history_num, &rec.policy_refcnt);
+    if (nread == EOF)
+	 return -1;
+    else if (nread != 7) {
+	 fprintf(stderr, "cannot parse policy on line %d (%d read)\n",
+		 *linenop, nread);
+	 return 1;
+    }
+
+    if ((ret = krb5_db_create_policy(kcontext, &rec))) {
+	 if (ret &&
+	     ((ret = krb5_db_put_policy(kcontext, &rec)))) {
+	      fprintf(stderr, "cannot create policy on line %d: %s\n",
+		      *linenop, error_message(ret));
+	      return 1;
+	 }
+    }
+    if (verbose)
+	 fprintf(stderr, "created policy %s\n", rec.name);
+    
+    return 0;
+}
+
+/*
+ * process_k5beta7_record()	- Handle a dump record in krb5b7 format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta7_record(fname, kcontext, filep, verbose, linenop)
+    char		*fname;
+    krb5_context	kcontext;
+    FILE		*filep;
+    int			verbose;
+    int			*linenop;
+{
+     int nread;
+     char rectype[100];
+
+     nread = fscanf(filep, "%100s\t", rectype);
+     if (nread == EOF)
+	  return -1;
+     else if (nread != 1)
+	  return 1;
+     if (strcmp(rectype, "princ") == 0)
+	  process_k5beta6_record(fname, kcontext, filep, verbose,
+				 linenop);
+     else if (strcmp(rectype, "policy") == 0)
+	  process_k5beta7_policy(fname, kcontext, filep, verbose,
+				 linenop);
+     else {
+	  fprintf(stderr, "unknown record type \"%s\" on line %d\n",
+		  rectype, *linenop);
+	  return 1;
+     }
+
+     return 0;
+}
+
+/*
+ * process_ov_record()	- Handle a dump record in OpenV*Secure 1.0 format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_ov_record(fname, kcontext, filep, verbose, linenop)
+    char		*fname;
+    krb5_context	kcontext;
+    FILE		*filep;
+    int			verbose;
+    int			*linenop;
+{
+     int nread;
+     char rectype[100];
+
+     nread = fscanf(filep, "%100s\t", rectype);
+     if (nread == EOF)
+	  return -1;
+     else if (nread != 1)
+	  return 1;
+     if (strcmp(rectype, "princ") == 0)
+	  process_ov_principal(fname, kcontext, filep, verbose,
+			       linenop);
+     else if (strcmp(rectype, "policy") == 0)
+	  process_k5beta7_policy(fname, kcontext, filep, verbose,
+				 linenop);
+     else if (strcmp(rectype, "End") == 0)
+	  return -1;
+     else {
+	  fprintf(stderr, "unknown record type \"%s\" on line %d\n",
+		  rectype, *linenop);
+	  return 1;
+     }
+
+     return 0;
+}
+
+/*
+ * restore_dump()	- Restore the database from any version dump file.
+ */
+static int
+restore_dump(programname, kcontext, dumpfile, f, verbose, dump)
+    char		*programname;
+    krb5_context	kcontext;
+    char		*dumpfile;
+    FILE		*f;
+    int			verbose;
+    dump_version	*dump;
+{
+    int		error;	
+    int		lineno;
+
+    error = 0;
+    lineno = 1;
+
+    /*
+     * Process the records.
+     */
+    while (!(error = (*dump->load_record)(dumpfile,
+					  kcontext, 
+					  f,
+					  verbose,
+					  &lineno)))
+	 ;
+    if (error != -1)
+	 fprintf(stderr, err_line_fmt, programname, lineno, dumpfile);
+    else
+	 error = 0;
+
+    return(error);
+}
+
+/*
+ * Usage: load_db [-old] [-ov] [-b6] [-b7] [-verbose] [-update] [-hash]
+ *		filename
+ */
+void
+load_db(argc, argv)
+    int		argc;
+    char	**argv;
+{
+    kadm5_config_params newparams;
+    krb5_error_code	kret;
+    krb5_context	kcontext;
+    FILE		*f;
+    extern char		*optarg;
+    extern int		optind;
+    char		*programname;
+    char		*dumpfile;
+    char		*dbname;
+    char		*dbname_tmp;
+    char		buf[BUFSIZ];
+    dump_version	*load;
+    int			update, verbose;
+    krb5_int32		crflags;
+    int			aindex;
+
+    /*
+     * Parse the arguments.
+     */
+    programname = argv[0];
+    if (strrchr(programname, (int) '/'))
+	programname = strrchr(argv[0], (int) '/') + 1;
+    dumpfile = (char *) NULL;
+    dbname = global_params.dbname;
+    load = NULL;
+    update = 0;
+    verbose = 0;
+    crflags = KRB5_KDB_CREATE_BTREE;
+    exit_status = 0;
+    dbname_tmp = (char *) NULL;
+    for (aindex = 1; aindex < argc; aindex++) {
+	if (!strcmp(argv[aindex], oldoption))
+	     load = &old_version;
+	else if (!strcmp(argv[aindex], b6option))
+	     load = &beta6_version;
+	else if (!strcmp(argv[aindex], b7option))
+	     load = &beta7_version;
+	else if (!strcmp(argv[aindex], ovoption))
+	     load = &ov_version;
+	else if (!strcmp(argv[aindex], verboseoption))
+	    verbose = 1;
+	else if (!strcmp(argv[aindex], updateoption))
+	    update = 1;
+	else if (!strcmp(argv[aindex], hashoption))
+	{
+	    db5util_db_args_size++;
+	    {
+		char **temp = realloc( db5util_db_args, sizeof(char*) * (db5util_db_args_size+1)); /* one for NULL */
+		if( temp == NULL )
+		{
+		    com_err(progname, ENOMEM, "while parsing command arguments\n");
+		    exit(1);
+		}
+
+		db5util_db_args = temp;
+	    }
+	    db5util_db_args[db5util_db_args_size-1] = "hash=true";
+	    db5util_db_args[db5util_db_args_size]   = NULL;
+	}
+	else
+	    break;
+    }
+    if ((argc - aindex) != 1) {
+	usage();
+	return;
+    }
+    dumpfile = argv[aindex];
+
+    if (!(dbname_tmp = (char *) malloc(strlen(dbname)+
+				       strlen(dump_tmptrail)+1))) {
+	fprintf(stderr, no_name_mem_fmt, argv[0]);
+	exit_status++;
+	return;
+    }
+    strcpy(dbname_tmp, dbname);
+    strcat(dbname_tmp, dump_tmptrail);
+
+    /*
+     * Initialize the Kerberos context and error tables.
+     */
+    if ((kret = krb5_init_context(&kcontext))) {
+	fprintf(stderr, ctx_err_fmt, programname);
+	free(dbname_tmp);
+	exit_status++;
+	return;
+    }
+
+    if( (kret = krb5_set_default_realm(kcontext, util_context->default_realm)) )
+    {
+	fprintf(stderr, "%s: Unable to set the default realm\n", programname);
+	free(dbname_tmp);
+	exit_status++;
+	return;
+    }
+
+    /*
+     * Open the dumpfile
+     */
+    if (dumpfile) {
+	if ((f = fopen(dumpfile, "r+")) == NULL) {
+	     fprintf(stderr, dfile_err_fmt, programname, dumpfile,
+		     error_message(errno)); 
+	     exit_status++;
+	     return;
+	}
+	if ((kret = krb5_lock_file(kcontext, fileno(f),
+				   KRB5_LOCKMODE_SHARED))) {
+	     fprintf(stderr, "%s: Cannot lock %s: %s\n", programname,
+		     dumpfile, error_message(errno));
+	     exit_status++;
+	     return;
+	}
+    } else
+	f = stdin;
+
+    /*
+     * Auto-detect dump version if we weren't told, verify if we
+     * were told.
+     */
+    fgets(buf, sizeof(buf), f);
+    if (load) {
+	 /* only check what we know; some headers only contain a prefix */
+	 if (strncmp(buf, load->header, strlen(load->header)) != 0) {
+	      fprintf(stderr, head_bad_fmt, programname, dumpfile);
+	      exit_status++;
+	      if (dumpfile) fclose(f);
+	      return;
+	 }
+    } else {
+	 /* perhaps this should be in an array, but so what? */
+	 if (strcmp(buf, old_version.header) == 0)
+	      load = &old_version;
+	 else if (strcmp(buf, beta6_version.header) == 0)
+	      load = &beta6_version;
+	 else if (strcmp(buf, beta7_version.header) == 0)
+	      load = &beta7_version;
+	 else if (strcmp(buf, r1_3_version.header) == 0)
+	      load = &r1_3_version;
+	 else if (strncmp(buf, ov_version.header,
+			  strlen(ov_version.header)) == 0)
+	      load = &ov_version;
+	 else {
+	      fprintf(stderr, head_bad_fmt, programname, dumpfile);
+	      exit_status++;
+	      if (dumpfile) fclose(f);
+	      return;
+	 }
+    }
+    if (load->updateonly && !update) {
+	 fprintf(stderr, "%s: dump version %s can only be loaded with the "
+		 "-update flag\n", programname, load->name);
+	 exit_status++;
+	 return;
+    }
+
+    /*
+     * Cons up params for the new databases.  If we are not in update
+     * mode, we dont create tmp file and then move it to final place. As it is dependent on DB type, this is not done
+     */
+    newparams = global_params;
+    if (! update) {
+	 newparams.mask |= KADM5_CONFIG_DBNAME;
+	 newparams.dbname = dbname_tmp;
+
+	 if ((kret = kadm5_get_config_params(kcontext, NULL, NULL,
+					     &newparams, &newparams))) {
+	      com_err(argv[0], kret,
+		      "while retreiving new configuration parameters");
+	      exit_status++;
+	      return;
+	 }
+    }
+    
+    /*
+     * If not an update restoration, create the database. otherwise open
+     */
+    if (!update) {
+	if((kret = krb5_db_create(kcontext, db5util_db_args))) {
+	    fprintf(stderr, dbcreaterr_fmt,
+		    programname, dbname, error_message(kret));
+	    exit_status++;
+	    kadm5_free_config_params(kcontext, &newparams);
+	    if (dumpfile) fclose(f);
+	    return;
+	}
+    }
+    else
+    /*
+     * Initialize the database.
+     */
+    if ((kret = krb5_db_open(kcontext, db5util_db_args, KRB5_KDB_OPEN_RW))) {
+	fprintf(stderr, dbinit_err_fmt,
+		programname, error_message(kret));
+	exit_status++;
+	goto error;
+    }
+
+
+    /*
+     * If an update restoration, make sure the db is left unusable if
+     * the update fails.
+     */
+    if ((kret = krb5_db_lock(kcontext, update?KRB5_DB_LOCKMODE_PERMANENT: KRB5_DB_LOCKMODE_EXCLUSIVE))) {
+	fprintf(stderr, "%s: %s while permanently locking database\n",
+		programname, error_message(kret));
+	exit_status++;
+	goto error;
+    }
+    
+    if (restore_dump(programname, kcontext, (dumpfile) ? dumpfile : stdin_name,
+		     f, verbose, load)) {
+	 fprintf(stderr, restfail_fmt,
+		 programname, load->name);
+	 exit_status++;
+    }
+
+    if (!update && load->create_kadm5 &&
+	((kret = kadm5_create_magic_princs(&newparams, kcontext)))) {
+	 /* error message printed by create_magic_princs */
+	 exit_status++;
+    }
+    
+    if ((kret = krb5_db_unlock(kcontext))) {
+	 /* change this error? */
+	 fprintf(stderr, dbunlockerr_fmt,
+		 programname, dbname, error_message(kret));
+	 exit_status++;
+    }
+
+    if ((kret = krb5_db_fini(kcontext))) {
+	 fprintf(stderr, close_err_fmt,
+		 programname, error_message(kret));
+	 exit_status++;
+    }
+
+    /* close policy db below */
+
+error:
+    /*
+     * If not an update: if there was an error, destroy the temp database,
+     * otherwise rename it into place.
+     *
+     * If an update: if there was no error, unlock the database.
+     */
+    if (!update) {
+	 if (exit_status) {
+	      if ((kret = krb5_db_destroy(kcontext, db5util_db_args))) {
+		   fprintf(stderr, dbdelerr_fmt,
+			   programname, dbname, error_message(kret));
+		   exit_status++;
+	      }
+	 }
+    }
+
+    if (dumpfile) {
+	 (void) krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_UNLOCK);
+	 fclose(f);
+    }
+
+    if (dbname_tmp)
+	 free(dbname_tmp);
+    krb5_free_context(kcontext);
+}
diff --git a/mechglue/src/kadmin/dbutil/dumpv4.c b/mechglue/src/kadmin/dbutil/dumpv4.c
new file mode 100644
index 000000000..e6bd1f407
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/dumpv4.c
@@ -0,0 +1,462 @@
+/*
+ * admin/edit/dumpv4.c
+ *
+ * Copyright 1990,1991, 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Dump a KDC database into a V4 slave dump.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef KRB5_KRB4_COMPAT
+
+#include "k5-int.h"
+#include "com_err.h"
+
+#include <des.h>
+#include <krb.h>
+#ifdef HAVE_KRB_DB_H
+#include <krb_db.h>
+#endif /*HAVE_KRB_DB_H*/
+#ifdef HAVE_KDC_H
+;/* MKEYFILE is now defined in kdc.h */
+#include <kdc.h>
+#endif /*HAVE_KDC_H*/
+#include <stdio.h>
+#include <kadm5/admin.h>
+#include "kdb5_util.h"
+
+struct dump_record {
+	char	*comerr_name;
+	FILE	*f;
+	krb5_keyblock *v5mkey;
+	C_Block		v4_master_key;
+	Key_schedule	v4_master_key_schedule;
+	long	master_key_version;
+	char	*realm;
+};
+
+
+void update_ok_file();
+
+#define ANAME_SZ 40
+#define INST_SZ 40
+
+static char *v4_mkeyfile = "/.k";
+static int shortlife;
+static krb5_error_code handle_one_key(struct dump_record *arg, 
+				      krb5_keyblock *v5mkey, 
+				      krb5_key_data *v5key, 
+				      des_cblock v4key);
+static int handle_keys(struct dump_record *arg);
+
+static int
+v4init(arg, manual)
+    struct dump_record *arg;
+    int manual;
+{
+    int fd;
+    int ok = 0;
+
+    if (!manual) {
+	fd = open(v4_mkeyfile, O_RDONLY, 0600);
+	if (fd >= 0) {
+	    if (read(fd,arg->v4_master_key,sizeof(C_Block)) == sizeof(C_Block))
+		ok = 1;
+	    close(fd);
+	}
+    }
+    if (!ok) {
+	des_read_password(&arg->v4_master_key, "V4 Kerberos master key", 1);
+	printf("\n");
+    }
+    arg->master_key_version = 1;
+    key_sched(arg->v4_master_key, arg->v4_master_key_schedule);
+
+    return 0;
+}
+
+static void
+v4_print_time(file, timeval)
+    FILE   *file;
+    unsigned long timeval;
+{
+    struct tm *tm;
+    struct tm *gmtime();
+    tm = gmtime((time_t *)&timeval);
+    fprintf(file, " %04d%02d%02d%02d%02d",
+            tm->tm_year < 1900 ? tm->tm_year + 1900: tm->tm_year,
+            tm->tm_mon + 1,
+            tm->tm_mday,
+            tm->tm_hour,
+            tm->tm_min);
+}
+
+
+
+static krb5_error_code
+dump_v4_iterator(ptr, entry)
+    krb5_pointer ptr;
+    krb5_db_entry *entry;
+{
+    struct dump_record *arg = (struct dump_record *) ptr;
+    krb5_principal mod_princ;
+    krb5_timestamp mod_time;
+    krb5_error_code retval;
+    int	i, max_kvno, ok_key;
+
+    struct v4princ {
+	char name[ANAME_SZ+1];
+	char instance[INST_SZ+1];
+	char realm[REALM_SZ+1];
+	int max_life;
+	int kdc_key_ver, key_version, attributes;
+	char mod_name[ANAME_SZ+1];
+	char mod_instance[INST_SZ+1];
+	char mod_realm[REALM_SZ+1];
+    } v4princ, *principal;
+    des_cblock v4key;
+    
+    principal = &v4princ;
+
+    if (strcmp(krb5_princ_realm(util_context, entry->princ)->data, arg->realm))
+	/* skip this because it's a key for a different realm, probably
+	 * a paired krbtgt key */
+	return 0;
+
+    retval = krb5_524_conv_principal(util_context, entry->princ,
+				     principal->name, principal->instance,
+				     principal->realm);
+    if (retval)
+	/* Skip invalid V4 principals */
+	return 0;
+
+    if (!strcmp(principal->name, "K") && !strcmp(principal->instance, "M"))
+	/* The V4 master key is handled specially */
+	return 0;
+
+    if (! principal->name[0])
+	return 0;
+    if (! principal->instance[0])
+	strcpy(principal->instance, "*");
+
+    /* Now move to mod princ */
+    if ((retval = krb5_dbe_lookup_mod_princ_data(util_context,entry,
+						 &mod_time, &mod_princ))){
+	com_err(arg->comerr_name, retval, "while unparsing db entry");
+	exit_status++;
+	return retval;
+    }
+    retval = krb5_524_conv_principal(util_context, mod_princ,
+				     principal->mod_name, principal->mod_instance,
+				     principal->mod_realm);
+    if (retval) {
+	/* Invalid V4 mod principal */
+	principal->mod_name[0] = '\0';
+	principal->mod_instance[0] = '\0';
+    }
+
+    if (! principal->mod_name[0])
+	strcpy(principal->mod_name, "*");
+    if (! principal->mod_instance[0])
+	strcpy(principal->mod_instance, "*");
+    
+    /* OK deal with the key now. */
+    for (max_kvno = i = 0; i < entry->n_key_data; i++) {
+	if (max_kvno < entry->key_data[i].key_data_kvno) {
+	     max_kvno = entry->key_data[i].key_data_kvno;
+	     ok_key = i;
+	}
+    }
+
+    i = ok_key;
+    while (ok_key < entry->n_key_data) {
+	if (max_kvno == entry->key_data[ok_key].key_data_kvno) {
+	    if (entry->key_data[ok_key].key_data_type[1]
+		== KRB5_KDB_SALTTYPE_V4) {
+		goto found_one;
+	    }
+	}
+	ok_key++;
+    }
+
+    /* See if there are any DES keys that may be suitable */
+    ok_key = i;
+    while (ok_key < entry->n_key_data) {
+	if (max_kvno == entry->key_data[ok_key].key_data_kvno) {
+	    krb5_enctype enctype = entry->key_data[ok_key].key_data_type[0];
+	    if ((enctype == ENCTYPE_DES_CBC_CRC) ||
+		(enctype == ENCTYPE_DES_CBC_MD5) ||
+		(enctype == ENCTYPE_DES_CBC_RAW))
+		goto found_one;
+	}
+	ok_key++;
+    }
+    /* skip this because it's a new style key and we can't help it */
+    return 0;
+
+found_one:;
+    principal->key_version = max_kvno;
+    if (!shortlife)
+	principal->max_life = krb_time_to_life(0, entry->max_life);
+    else {
+	principal->max_life = entry->max_life / (60 * 5);
+	if (principal->max_life > 255)
+	    principal->max_life = 255;
+    }
+
+    principal->kdc_key_ver = arg->master_key_version;
+    principal->attributes = 0;	/* ??? not preserved either */
+
+    fprintf(arg->f, "%s %s %d %d %d %d ",
+	    principal->name,
+	    principal->instance,
+	    principal->max_life,
+	    principal->kdc_key_ver,
+	    principal->key_version,
+	    principal->attributes);
+
+    handle_one_key(arg, arg->v5mkey, &entry->key_data[ok_key], v4key);
+
+    for (i = 0; i < 8; i++) {
+	fprintf(arg->f, "%02x", ((unsigned char*)v4key)[i]);
+	if (i == 3) fputc(' ', arg->f);
+    }
+
+    if (entry->expiration == 0) {
+        /* 0 means "never" expire. V4 didn't support that, so rather than
+	   having everything appear to have expired in 1970, we nail in the
+	   Cygnus 96q1 default value.  The value quoted here is directly 
+	   from src/admin/kdb_init.c in Cygnus CNS V4 96q1, and is
+	   roughly 12/31/2009. */
+        v4_print_time(arg->f, 946702799+((365*10+3)*24*60*60));
+    } else {
+    v4_print_time(arg->f, entry->expiration);
+    }
+    v4_print_time(arg->f, mod_time);
+
+    fprintf(arg->f, " %s %s\n", principal->mod_name, principal->mod_instance);
+    return 0;
+}
+
+/*ARGSUSED*/
+void dump_v4db(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	int	i;
+	char	*outname = NULL;
+	FILE	*f;
+	struct dump_record	arg;
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "-S")) {
+			shortlife++;
+			continue;
+		}
+		break;
+	}
+	if (argc - i > 1) {
+		com_err(argv[0], 0, "Usage: %s [-S] filename", argv[0]);
+		exit_status++;
+		return;
+	}
+	if (!dbactive) {
+		com_err(argv[0], 0, Err_no_database);
+		exit_status++;
+		return;
+	}
+	if (argc - i == 1) {
+		outname = argv[i];
+		/*
+		 * Make sure that we don't open and truncate on the fopen,
+		 * since that may hose an on-going kprop process.
+		 * 
+		 * We could also control this by opening for read and
+		 * write, doing an flock with LOCK_EX, and then
+		 * truncating the file once we have gotten the lock,
+		 * but that would involve more OS dependancies than I
+		 * want to get into.
+		 */
+		unlink(outname);
+		if (!(f = fopen(outname, "w"))) {
+			com_err(argv[0], errno,
+				"While opening file %s for writing", outname);
+			exit_status++;
+			return;
+		}
+	} else {
+		f = stdout;
+	}
+
+	arg.comerr_name = argv[0];
+	arg.f = f;
+	v4init(&arg, 0);
+	handle_keys(&arg);
+
+	/* special handling for K.M since it isn't preserved */
+	{
+	  des_cblock v4key;
+	  int i2;
+
+	  /* assume:
+	     max lifetime (255)
+	     key version == 1 (actually, should be whatever the v5 one is)
+	     master key version == key version
+	     args == 0 (none are preserved)
+	     expiration date is the default 2000
+	     last mod time is near zero (arbitrarily.)
+	     creator is db_creation *
+	     */
+
+	  fprintf(f,"K M 255 1 1 0 ");
+	  
+#ifndef	KDB4_DISABLE
+	  kdb_encrypt_key (arg.v4_master_key, v4key, 
+			   arg.v4_master_key, arg.v4_master_key_schedule, 
+			   ENCRYPT);
+#else	/* KDB4_DISABLE */
+	  pcbc_encrypt((C_Block *) arg.v4_master_key,
+		       (C_Block *) v4key,
+		       (long) sizeof(C_Block),
+		       arg.v4_master_key_schedule,
+		       (C_Block *) arg.v4_master_key,
+		       ENCRYPT);
+#endif	/* KDB4_DISABLE */
+
+	  for (i2=0; i2<8; i2++) {
+	    fprintf(f, "%02x", ((unsigned char*)v4key)[i2]);
+	    if (i2 == 3) fputc(' ', f);
+	  }
+	  fprintf(f," 200001010459 197001020000 db_creation *\n");
+	}
+
+	(void) krb5_db_iterate(util_context, dump_v4_iterator, 
+			       (krb5_pointer) &arg);
+	if (argc == 2)
+		fclose(f);
+	if (outname)
+		update_ok_file(outname);
+}
+
+static int handle_keys(arg)
+    struct dump_record *arg;
+{
+    krb5_error_code retval;
+    char *defrealm;
+    char *mkey_name = 0;
+    char *mkey_fullname;
+    krb5_principal l_master_princ;
+
+    if ((retval = krb5_get_default_realm(util_context, &defrealm))) {
+      com_err(arg->comerr_name, retval, 
+	      "while retrieving default realm name");
+      exit(1);
+    }	    
+    arg->realm = defrealm;
+
+    /* assemble & parse the master key name */
+
+    if ((retval = krb5_db_setup_mkey_name(util_context, mkey_name, arg->realm, 
+					  &mkey_fullname, &l_master_princ))) {
+	com_err(arg->comerr_name, retval, "while setting up master key name");
+	exit(1);
+    }
+
+    if ((retval = krb5_db_fetch_mkey(util_context, l_master_princ, 
+				     master_keyblock.enctype, 0,
+				     0, global_params.stash_file, 0,
+				     &master_keyblock))) { 
+	com_err(arg->comerr_name, retval, "while reading master key");
+	exit(1);
+    }
+    arg->v5mkey = &master_keyblock;
+    return(0);
+}
+
+static krb5_error_code
+handle_one_key(arg, v5mkey, v5key, v4key)
+    struct dump_record *arg;
+    krb5_keyblock *v5mkey;
+    krb5_key_data *v5key;
+    des_cblock v4key;
+{
+    krb5_error_code retval;
+
+    krb5_keyblock v5plainkey;
+    /* v4key is the actual v4 key from the file. */
+
+    retval = krb5_dbekd_decrypt_key_data(util_context, v5mkey, v5key, 
+					 &v5plainkey, NULL);
+    if (retval) 
+	return retval;
+
+    memcpy(v4key, v5plainkey.contents, sizeof(des_cblock));
+#ifndef	KDB4_DISABLE
+    kdb_encrypt_key (v4key, v4key, 
+		     arg->v4_master_key, arg->v4_master_key_schedule, 
+		     ENCRYPT);
+#else	/* KDB4_DISABLE */
+    pcbc_encrypt((C_Block *) v4key,
+		 (C_Block *) v4key,
+		 (long) sizeof(C_Block),
+		 arg->v4_master_key_schedule,
+		 (C_Block *) arg->v4_master_key,
+		 ENCRYPT);
+#endif	/* KDB4_DISABLE */
+    return 0;
+}
+
+#else /* KRB5_KRB4_COMPAT */
+void dump_v4db(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	printf("This version of krb5_edit does not support the V4 dump command.\n");
+}
+#endif /* KRB5_KRB4_COMPAT */
diff --git a/mechglue/src/kadmin/dbutil/import_err.et b/mechglue/src/kadmin/dbutil/import_err.et
new file mode 100644
index 000000000..e091fe33c
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/import_err.et
@@ -0,0 +1,26 @@
+error_table imp
+error_code IMPORT_NO_ERR,	    "Successfully imported %d record%s.\n"
+error_code IMPORT_BAD_FILE,	    "Input not recognized as database dump"
+error_code IMPORT_BAD_TOKEN,	    "Bad token in dump file."
+error_code IMPORT_BAD_VERSION,	    "Bad version in dump file"
+error_code IMPORT_BAD_RECORD,	    "Defective record encountered: "
+error_code IMPORT_BAD_FOOTER,	    "Truncated input file detected."
+error_code IMPORT_FAILED,	    "Import of dump failed"
+error_code IMPORT_COUNT_MESSAGE,    "Mismatched record count: %d record%s indicated, %d record%s scanned.\n"
+error_code IMPORT_MISMATCH_COUNT,   "Number of records imported does not match count"
+error_code IMPORT_UNK_OPTION,	    "Unknown command line option.\nUsage: ovsec_adm_import [filename]"
+error_code IMPORT_WARN_DB,	    "Warning -- continuing to import will overwrite existing databases!"
+error_code IMPORT_RENAME_FAILED,    "Database rename Failed!!"
+error_code IMPORT_EXTRA_DATA,	    "Extra data after footer is ignored."
+error_code IMPORT_CONFIRM,	    "Proceed <y|n>?"
+error_code IMPORT_OPEN_DUMP,	    "while opening input file"
+error_code IMPORT_IMPORT,	    "while importing databases"
+error_code IMPORT_TTY,		    "cannot open /dev/tty!!"
+error_code IMPORT_RENAME_OPEN,	    "while opening databases"
+error_code IMPORT_RENAME_LOCK,	    "while acquiring permanent lock"
+error_code IMPORT_RENAME_UNLOCK,    "while releasing permanent lock"
+error_code IMPORT_RENAME_CLOSE,	    "while closing databases"
+error_code IMPORT_SINGLE_RECORD,    ""
+error_code IMPORT_PLURAL_RECORDS,   "s"
+error_code IMPORT_GET_PARAMS,	    "while retrieving configuration parameters"
+end
diff --git a/mechglue/src/kadmin/dbutil/kadm5_create.c b/mechglue/src/kadmin/dbutil/kadm5_create.c
new file mode 100644
index 000000000..a9a9df0cd
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/kadm5_create.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Source$
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "string_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <k5-int.h>
+#include <krb5/kdb.h>
+#include <kadm5/admin.h>
+#include <krb5/adm_proto.h>
+
+
+#include <krb5.h>
+#include <krb5/kdb.h>
+#include "kdb5_util.h"
+
+static int add_admin_princ(void *handle, krb5_context context,
+		    char *name, char *realm, int attrs, int lifetime);
+static int add_admin_princs(void *handle, krb5_context context, char *realm);
+
+#define ERR 1
+#define OK 0
+
+#define ADMIN_LIFETIME 60*60*3 /* 3 hours */
+#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
+
+/*
+ * Function: kadm5_create
+ *
+ * Purpose: create admin principals in KDC database
+ *
+ * Arguments:	params	(r) configuration parameters to use
+ *      
+ * Effects:  Creates KADM5_ADMIN_SERVICE and KADM5_CHANGEPW_SERVICE
+ * principals in the KDC database and sets their attributes
+ * appropriately.
+ */
+int kadm5_create(kadm5_config_params *params)
+{
+     int retval;
+     krb5_context context;
+
+     kadm5_config_params lparams;
+
+     if ((retval = krb5_init_context(&context)))
+	  exit(ERR);
+
+     /*
+      * The lock file has to exist before calling kadm5_init, but
+      * params->admin_lockfile may not be set yet...
+      */
+     if ((retval = kadm5_get_config_params(context, NULL, NULL,
+					   params, &lparams))) {
+	  com_err(progname, retval, "while looking up the Kerberos configuration");
+	  return 1;
+     }
+
+     retval = kadm5_create_magic_princs(&lparams, context);
+
+     kadm5_free_config_params(context, &lparams);
+     krb5_free_context(context);
+
+     return retval;
+}
+
+int kadm5_create_magic_princs(kadm5_config_params *params,
+			      krb5_context context)
+{
+     int retval;
+     void *handle;
+     
+     retval = krb5_klog_init(context, "admin_server", progname, 0);
+     if (retval)
+	  return retval;
+     if ((retval = kadm5_init(progname, NULL, NULL, params,
+			      KADM5_STRUCT_VERSION,
+			      KADM5_API_VERSION_2,
+			      db5util_db_args,
+			      &handle))) {
+	  com_err(progname, retval, "while initializing the Kerberos admin interface");
+	  return retval;
+     }
+
+     retval = add_admin_princs(handle, context, params->realm);
+
+     kadm5_destroy(handle);
+
+     krb5_klog_close(context);
+
+     return retval;
+}
+
+/*
+ * Function: build_name_with_realm
+ *
+ * Purpose: concatenate a name and a realm to form a krb5 name
+ *
+ * Arguments:
+ *
+ * 	name	(input) the name
+ * 	realm	(input) the realm
+ *
+ * Returns:
+ *
+ * 	pointer to name@realm, in allocated memory, or NULL if it
+ * 	cannot be allocated
+ *
+ * Requires: both strings are null-terminated
+ */
+static char *build_name_with_realm(char *name, char *realm)
+{
+     char *n;
+
+     n = (char *) malloc(strlen(name) + strlen(realm) + 2);
+     sprintf(n, "%s@%s", name, realm);
+     return n;
+}
+
+/*
+ * Function: add_admin_princs
+ *
+ * Purpose: create admin principals
+ *
+ * Arguments:
+ *
+ * 	rseed		(input) random seed
+ * 	realm		(input) realm, or NULL for default realm
+ *      <return value>  (output) status, 0 for success, 1 for serious error
+ *      
+ * Requires:
+ *      
+ * Effects:
+ *      
+ * add_admin_princs creates KADM5_ADMIN_SERVICE,
+ * KADM5_CHANGEPW_SERVICE.  If any of these exist a message is
+ * printed.  If any of these existing principal do not have the proper
+ * attributes, a warning message is printed.
+ */
+static int add_admin_princs(void *handle, krb5_context context, char *realm)
+{
+  krb5_error_code ret = 0;
+  char service_name[MAXHOSTNAMELEN + 8];
+  char localname[MAXHOSTNAMELEN];
+  struct hostent *hp;
+
+  if (gethostname(localname, MAXHOSTNAMELEN)) {
+      ret = errno;
+      perror("gethostname");
+      goto clean_and_exit;
+  }
+  hp = gethostbyname(localname);
+  if (hp == NULL) {
+      ret = errno;
+      perror("gethostbyname");
+      goto clean_and_exit;
+  }
+  sprintf(service_name, "kadmin/%s", hp->h_name);
+
+  if ((ret = add_admin_princ(handle, context,
+			     service_name, realm,
+			     KRB5_KDB_DISALLOW_TGT_BASED,
+			     ADMIN_LIFETIME)))
+      goto clean_and_exit;
+
+  if ((ret = add_admin_princ(handle, context,
+			     KADM5_ADMIN_SERVICE, realm,
+			     KRB5_KDB_DISALLOW_TGT_BASED,
+			     ADMIN_LIFETIME)))
+       goto clean_and_exit;
+
+  if ((ret = add_admin_princ(handle, context, 
+			     KADM5_CHANGEPW_SERVICE, realm, 
+			     KRB5_KDB_DISALLOW_TGT_BASED |
+			     KRB5_KDB_PWCHANGE_SERVICE,
+			     CHANGEPW_LIFETIME)))
+       goto clean_and_exit;
+  
+clean_and_exit:
+
+  return ret;
+}
+
+/*
+ * Function: add_admin_princ
+ *
+ * Arguments:
+ *
+ * 	creator		(r) principal to use as "mod_by"
+ * 	rseed		(r) seed for random key generator
+ * 	name		(r) principal name
+ * 	realm		(r) realm name for principal
+ * 	attrs		(r) principal's attributes
+ * 	lifetime	(r) principal's max life, or 0
+ * 	not_unique	(r) error message for multiple entries, never used
+ * 	exists		(r) warning message for principal exists
+ * 	wrong_attrs	(r) warning message for wrong attributes
+ *
+ * Returns:
+ *
+ * 	OK on success
+ * 	ERR on serious errors
+ *
+ * Effects:
+ * 
+ * If the principal is not unique, not_unique is printed (but this
+ * never happens).  If the principal exists, then exists is printed
+ * and if the principals attributes != attrs, wrong_attrs is printed.
+ * Otherwise, the principal is created with mod_by creator and
+ * attributes attrs and max life of lifetime (if not zero).
+ */
+
+int add_admin_princ(void *handle, krb5_context context,
+		    char *name, char *realm, int attrs, int lifetime)
+{
+     char *fullname;
+     krb5_error_code ret;
+     kadm5_principal_ent_rec ent;
+
+     memset(&ent, 0, sizeof(ent));
+
+     fullname = build_name_with_realm(name, realm);
+     ret = krb5_parse_name(context, fullname, &ent.principal);
+     if (ret) {
+	  com_err(progname, ret, str_PARSE_NAME);
+	  return(ERR);
+     }
+     ent.max_life = lifetime;
+     ent.attributes = attrs | KRB5_KDB_DISALLOW_ALL_TIX;
+     
+     ret = kadm5_create_principal(handle, &ent,
+				  (KADM5_PRINCIPAL | KADM5_MAX_LIFE |
+				   KADM5_ATTRIBUTES),
+				  "to-be-random");
+     if (ret) {
+	  if (ret != KADM5_DUP) {
+	       com_err(progname, ret, str_PUT_PRINC, fullname);
+	       krb5_free_principal(context, ent.principal);
+	       free(fullname);
+	       return ERR;
+	  }
+     } else {
+	  /* only randomize key if we created the principal */
+	  ret = kadm5_randkey_principal(handle, ent.principal, NULL, NULL);
+	  if (ret) {
+	       com_err(progname, ret, str_RANDOM_KEY, fullname);
+	       krb5_free_principal(context, ent.principal);
+	       free(fullname);
+	       return ERR;
+	  }
+	  
+	  ent.attributes = attrs;
+	  ret = kadm5_modify_principal(handle, &ent, KADM5_ATTRIBUTES);
+	  if (ret) {
+	       com_err(progname, ret, str_PUT_PRINC, fullname);
+	       krb5_free_principal(context, ent.principal);
+	       free(fullname);
+	       return ERR;
+	  }
+     }
+     
+     krb5_free_principal(context, ent.principal);
+     free(fullname);
+
+     return OK;
+}
diff --git a/mechglue/src/kadmin/dbutil/kdb5_create.c b/mechglue/src/kadmin/dbutil/kdb5_create.c
new file mode 100644
index 000000000..5bd337e47
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/kdb5_create.c
@@ -0,0 +1,441 @@
+/*
+ * kadmin/dbutil/kdb5_create.c
+ *
+ * Copyright 1990,1991,2001, 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Generate (from scratch) a Kerberos KDC database.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <krb5/kdb.h>
+#include <kadm5/server_internal.h>
+#include <kadm5/admin.h>
+#include <krb5/adm_proto.h>
+#include "kdb5_util.h"
+
+enum ap_op {
+    NULL_KEY,				/* setup null keys */
+    MASTER_KEY,				/* use master key as new key */
+    TGT_KEY				/* special handling for tgt key */
+};
+
+krb5_key_salt_tuple def_kslist = { ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL };
+
+struct realm_info {
+    krb5_deltat max_life;
+    krb5_deltat max_rlife;
+    krb5_timestamp expiration;
+    krb5_flags flags;
+    krb5_keyblock *key;
+    krb5_int32 nkslist;
+    krb5_key_salt_tuple *kslist;
+} rblock = { /* XXX */
+    KRB5_KDB_MAX_LIFE,
+    KRB5_KDB_MAX_RLIFE,
+    KRB5_KDB_EXPIRATION,
+    KRB5_KDB_DEF_FLAGS,
+    (krb5_keyblock *) NULL,
+    1,
+    &def_kslist
+};
+
+struct iterate_args {
+    krb5_context	ctx;
+    struct realm_info	*rblock;
+    krb5_db_entry	*dbentp;
+};
+
+static krb5_error_code add_principal 
+	(krb5_context,
+	 krb5_principal,
+	 enum ap_op,
+	 struct realm_info *);
+
+/*
+ * Steps in creating a database:
+ *
+ * 1) use the db calls to open/create a new database
+ *
+ * 2) get a realm name for the new db
+ *
+ * 3) get a master password for the new db; convert to an encryption key.
+ *
+ * 4) create various required entries in the database
+ *
+ * 5) close & exit
+ */
+
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+krb5_data master_salt;
+
+krb5_data tgt_princ_entries[] = {
+	{0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
+	{0, 0, 0} };
+
+krb5_data db_creator_entries[] = {
+	{0, sizeof("db_creation")-1, "db_creation"} };
+
+/* XXX knows about contents of krb5_principal, and that tgt names
+ are of form TGT/REALM@REALM */
+krb5_principal_data tgt_princ = {
+        0,					/* magic number */
+	{0, 0, 0},				/* krb5_data realm */
+	tgt_princ_entries,			/* krb5_data *data */
+	2,					/* int length */
+	KRB5_NT_SRV_INST			/* int type */
+};
+
+krb5_principal_data db_create_princ = {
+        0,					/* magic number */
+	{0, 0, 0},				/* krb5_data realm */
+	db_creator_entries,			/* krb5_data *data */
+	1,					/* int length */
+	KRB5_NT_SRV_INST			/* int type */
+};
+
+extern char *mkey_password;
+
+extern char *progname;
+extern int exit_status;
+extern kadm5_config_params global_params;
+extern krb5_context util_context;
+
+void kdb5_create(argc, argv)
+   int argc;
+   char *argv[];
+{
+    int optchar;
+
+    krb5_error_code retval;
+    char *mkey_fullname;
+    char *pw_str = 0;
+    unsigned int pw_size = 0;
+    int do_stash = 0;
+    krb5_data pwd, seed;
+	   
+    if (strrchr(argv[0], '/'))
+	argv[0] = strrchr(argv[0], '/')+1;
+
+    while ((optchar = getopt(argc, argv, "s")) != -1) {
+	switch(optchar) {
+	case 's':
+	    do_stash++;
+	    break;
+	case 'h':
+	    db5util_db_args_size++;
+	    {
+		char **temp = realloc( db5util_db_args, sizeof(char*) * (db5util_db_args_size+1)); /* one for NULL */
+		if( temp == NULL )
+		{
+		    com_err(progname, ENOMEM, "while parsing command arguments\n");
+		    exit(1);
+		}
+
+		db5util_db_args = temp;
+	    }
+	    db5util_db_args[db5util_db_args_size-1] = "hash=true";
+	    db5util_db_args[db5util_db_args_size]   = NULL;
+	case '?':
+	default:
+	    usage();
+	    return;
+	}
+    }
+
+    rblock.max_life = global_params.max_life;
+    rblock.max_rlife = global_params.max_rlife;
+    rblock.expiration = global_params.expiration;
+    rblock.flags = global_params.flags;
+    rblock.nkslist = global_params.num_keysalts;
+    rblock.kslist = global_params.keysalts;
+
+    printf ("Loading random data\n");
+    retval = krb5_c_random_os_entropy (util_context, 1, NULL);
+    if (retval) {
+      com_err (argv[0], retval, "Loading random data");
+      exit_status++; return;
+    }
+    
+    /* assemble & parse the master key name */
+
+    if ((retval = krb5_db_setup_mkey_name(util_context,
+					  global_params.mkey_name,
+					  global_params.realm,  
+					  &mkey_fullname, &master_princ))) {
+	com_err(argv[0], retval, "while setting up master key name");
+	exit_status++; return;
+    }
+
+    krb5_princ_set_realm_data(util_context, &db_create_princ, global_params.realm);
+    krb5_princ_set_realm_length(util_context, &db_create_princ, strlen(global_params.realm));
+    krb5_princ_set_realm_data(util_context, &tgt_princ, global_params.realm);
+    krb5_princ_set_realm_length(util_context, &tgt_princ, strlen(global_params.realm));
+    krb5_princ_component(util_context, &tgt_princ,1)->data = global_params.realm;
+    krb5_princ_component(util_context, &tgt_princ,1)->length = strlen(global_params.realm);
+
+    printf("Initializing database '%s' for realm '%s',\n\
+master key name '%s'\n",
+	   global_params.dbname, global_params.realm, mkey_fullname);
+
+    if (!mkey_password) {
+	printf("You will be prompted for the database Master Password.\n");
+	printf("It is important that you NOT FORGET this password.\n");
+	fflush(stdout);
+
+	pw_size = 1024;
+	pw_str = malloc(pw_size);
+	
+	retval = krb5_read_password(util_context, KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2,
+				    pw_str, &pw_size);
+	if (retval) {
+	    com_err(argv[0], retval, "while reading master key from keyboard");
+	    exit_status++; return;
+	}
+	mkey_password = pw_str;
+    }
+
+    pwd.data = mkey_password;
+    pwd.length = strlen(mkey_password);
+    retval = krb5_principal2salt(util_context, master_princ, &master_salt);
+    if (retval) {
+	com_err(argv[0], retval, "while calculating master key salt");
+	exit_status++; return;
+    }
+
+    retval = krb5_c_string_to_key(util_context, master_keyblock.enctype, 
+				  &pwd, &master_salt, &master_keyblock);
+    if (retval) {
+	com_err(argv[0], retval, "while transforming master key from password");
+	exit_status++; return;
+    }
+
+    rblock.key = &master_keyblock;
+
+    seed.length = master_keyblock.length;
+    seed.data = master_keyblock.contents;
+
+    if ((retval = krb5_c_random_seed(util_context, &seed))) {
+	com_err(argv[0], retval, "while initializing random key generator");
+	exit_status++; return;
+    }
+    if ((retval = krb5_db_create(util_context,
+				 db5util_db_args))) {
+	com_err(argv[0], retval, "while creating database '%s'",
+		global_params.dbname);
+	exit_status++; return;
+    }
+/*     if ((retval = krb5_db_fini(util_context))) { */
+/*         com_err(argv[0], retval, "while closing current database"); */
+/*         exit_status++; return; */
+/*     } */
+/*     if ((retval = krb5_db_open(util_context, db5util_db_args, KRB5_KDB_OPEN_RW))) { */
+/* 	com_err(argv[0], retval, "while initializing the database '%s'", */
+/* 		global_params.dbname); */
+/* 	exit_status++; return; */
+/*     } */
+    if ((retval = add_principal(util_context, master_princ, MASTER_KEY, &rblock)) ||
+	(retval = add_principal(util_context, &tgt_princ, TGT_KEY, &rblock))) {
+	(void) krb5_db_fini(util_context);
+	com_err(argv[0], retval, "while adding entries to the database");
+	exit_status++; return;
+    }
+    /*
+     * Always stash the master key so kadm5_create does not prompt for
+     * it; delete the file below if it was not requested.  DO NOT EXIT
+     * BEFORE DELETING THE KEYFILE if do_stash is not set.
+     */
+    retval = krb5_db_store_master_key(util_context,
+				      global_params.stash_file,
+				      master_princ,
+				      &master_keyblock,
+				      mkey_password);
+    if (retval) {
+	com_err(argv[0], errno, "while storing key");
+	printf("Warning: couldn't stash master key.\n");
+    }
+    /* clean up */
+    (void) krb5_db_fini(util_context);
+    memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+    free(master_keyblock.contents);
+    if (pw_str) {
+	memset(pw_str, 0, pw_size);
+	free(pw_str);
+    }
+    free(master_salt.data);
+
+    if (kadm5_create(&global_params)) {
+	 if (!do_stash) unlink(global_params.stash_file);
+	 exit_status++;
+	 return;
+    }
+    if (!do_stash) unlink(global_params.stash_file);
+
+    return;
+}
+
+static krb5_error_code
+tgt_keysalt_iterate(ksent, ptr)
+    krb5_key_salt_tuple	*ksent;
+    krb5_pointer	ptr;
+{
+    krb5_context	context;
+    krb5_error_code	kret;
+    struct iterate_args	*iargs;
+    krb5_keyblock	key;
+    krb5_int32		ind;
+    krb5_data	pwd;
+
+    iargs = (struct iterate_args *) ptr;
+    kret = 0;
+
+    context = iargs->ctx;
+
+    /*
+     * Convert the master key password into a key for this particular
+     * encryption system.
+     */
+    pwd.data = mkey_password;
+    pwd.length = strlen(mkey_password);
+    kret = krb5_c_random_seed(context, &pwd);
+    if (kret)
+	return kret;
+
+    if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {
+	ind = iargs->dbentp->n_key_data-1;
+	if (!(kret = krb5_c_make_random_key(context, ksent->ks_enctype,
+					    &key))) {
+	    kret = krb5_dbekd_encrypt_key_data(context,
+					       iargs->rblock->key,
+					       &key, 
+					       NULL,
+					       1,
+					       &iargs->dbentp->key_data[ind]);
+	    krb5_free_keyblock_contents(context, &key);
+	}
+    }
+
+    return(kret);
+}
+
+static krb5_error_code
+add_principal(context, princ, op, pblock)
+    krb5_context context;
+    krb5_principal princ;
+    enum ap_op op;
+    struct realm_info *pblock;
+{
+    krb5_error_code 	  retval;
+    krb5_db_entry 	  entry;
+
+    krb5_timestamp	  now;
+    struct iterate_args	  iargs;
+
+    int			  nentries = 1;
+
+    memset((char *) &entry, 0, sizeof(entry));
+
+    entry.len = KRB5_KDB_V1_BASE_LENGTH;
+    entry.attributes = pblock->flags;
+    entry.max_life = pblock->max_life;
+    entry.max_renewable_life = pblock->max_rlife;
+    entry.expiration = pblock->expiration;
+
+    if ((retval = krb5_copy_principal(context, princ, &entry.princ)))
+	goto error_out;
+
+    if ((retval = krb5_timeofday(context, &now)))
+	goto error_out;
+
+    if ((retval = krb5_dbe_update_mod_princ_data(context, &entry,
+						 now, &db_create_princ)))
+	goto error_out;
+
+    switch (op) {
+    case MASTER_KEY:
+	if ((entry.key_data=(krb5_key_data*)malloc(sizeof(krb5_key_data)))
+	    == NULL)
+	    goto error_out;
+	memset((char *) entry.key_data, 0, sizeof(krb5_key_data));
+	entry.n_key_data = 1;
+
+	entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
+	if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
+						  &master_keyblock, NULL, 
+						  1, entry.key_data)))
+	    return retval;
+	break;
+    case TGT_KEY:
+	iargs.ctx = context;
+	iargs.rblock = pblock;
+	iargs.dbentp = &entry;
+	/*
+	 * Iterate through the key/salt list, ignoring salt types.
+	 */
+	if ((retval = krb5_keysalt_iterate(pblock->kslist,
+					   pblock->nkslist,
+					   1,
+					   tgt_keysalt_iterate,
+					   (krb5_pointer) &iargs)))
+	    return retval;
+	break;
+    case NULL_KEY:
+	return EOPNOTSUPP;
+    default:
+	break;
+    }
+
+    retval = krb5_db_put_principal(context, &entry, &nentries);
+
+error_out:;
+    krb5_db_free_principal(context, &entry, 1);
+    return retval;
+}
diff --git a/mechglue/src/kadmin/dbutil/kdb5_destroy.c b/mechglue/src/kadmin/dbutil/kdb5_destroy.c
new file mode 100644
index 000000000..ea1011b40
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/kdb5_destroy.c
@@ -0,0 +1,112 @@
+/*
+ * admin/destroy/kdb5_destroy.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * kdb_dest(roy): destroy the named database.
+ *
+ * This version knows about DBM format databases.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include "com_err.h"
+#include <kadm5/admin.h>
+#include <krb5/kdb.h>
+#include "kdb5_util.h"
+
+extern int exit_status;
+extern krb5_boolean dbactive;
+extern kadm5_config_params global_params;
+
+char *yes = "yes\n";			/* \n to compare against result of
+					   fgets */
+
+void
+kdb5_destroy(argc, argv)
+    int argc;
+    char *argv[];
+{
+    extern char *optarg;
+    extern int optind;
+    int optchar;
+    char *dbname;
+    char buf[5];
+    krb5_error_code retval1;
+    krb5_context context;
+    int force = 0;
+
+    retval1 = krb5_init_context(&context);
+    if( retval1 )
+    {
+	com_err(argv[0], retval1, "while initializing krb5_context");
+	exit(1);
+    }
+
+    if ((retval1 = krb5_set_default_realm(context,
+					  util_context->default_realm))) {
+	com_err(argv[0], retval1, "while setting default realm name");
+	exit(1);
+    }
+    
+    if (strrchr(argv[0], '/'))
+	argv[0] = strrchr(argv[0], '/')+1;
+
+    dbname = global_params.dbname;
+
+    optind = 1;
+    while ((optchar = getopt(argc, argv, "f")) != -1) {
+	switch(optchar) {
+	case 'f':
+	    force++;
+	    break;
+	case '?':
+	default:
+	    usage();
+	    return;
+	    /*NOTREACHED*/
+	}
+    }
+    if (!force) {
+	printf("Deleting KDC database stored in '%s', are you sure?\n", dbname);
+	printf("(type 'yes' to confirm)? ");
+	if (fgets(buf, sizeof(buf), stdin) == NULL) {
+	    exit_status++; return;
+        }
+	if (strcmp(buf, yes)) {
+	    exit_status++; return;
+        }
+	printf("OK, deleting database '%s'...\n", dbname);
+    }
+
+    retval1 = krb5_db_destroy(context, db5util_db_args);
+    if (retval1) {
+	com_err(argv[0], retval1, "deleting database '%s'",dbname);
+	exit_status++; return;
+    }
+
+    dbactive = FALSE;
+    printf("** Database '%s' destroyed.\n", dbname);
+    return;
+}
diff --git a/mechglue/src/kadmin/dbutil/kdb5_edit.M b/mechglue/src/kadmin/dbutil/kdb5_edit.M
new file mode 100644
index 000000000..217c266b1
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/kdb5_edit.M
@@ -0,0 +1,182 @@
+.\" admin/edit/kdb5_edit.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" 
+.\"
+.TH KDB5_EDIT 8
+.SH NAME
+kdb5_edit \- edit a Kerberos V5 principal database
+.SH SYNOPSIS
+.B kdb5_edit
+[
+.B \-r
+.I realm
+] [
+.B \-d
+.I dbname
+] [
+.B \-k
+.I keytype
+] [
+.B \-M
+.I mkeyname
+] [
+.B \-e
+.I enctype
+] [
+.B \-m
+] [
+.B \-R
+.I command
+] [
+.B \-s
+.I script
+] [
+.B \-f
+.I stashfile
+]
+.br
+.SH DESCRIPTION
+.I kdb5_edit
+allows an administrator to add, delete, and edit entries in a Kerberos
+version 5 principal database.
+After themaster key is verified, commands are to
+.I kdb5_edit
+are issued using one of three mechanisms.  If a single command is supplied 
+using the
+.B \-R
+.I command
+argument, then that single command is processed and execution ceases.  If a
+script file is provided using the 
+.B \-s
+.I script
+argument, then commands are read from this file until either an error occurs
+or an end of file is detected.  Finally, if neither a command or a script is
+specified, the invoker is placed into a shell-like command loop, from which
+[s]he may issue commands to modify the
+database.  
+.PP
+The
+.B \-r
+.I realm
+option specifies the realm of the database;
+by default the realm returned by
+.IR krb5_default_local_realm (3)
+is used.
+.PP
+The
+.B \-d
+.I dbname
+option specifies the name under which the principal database is stored;
+by default the database is in DEFAULT_DBM_FILE (defined in <krb5/osconf.h>).
+.PP
+The
+.B \-k
+.I keytype
+option specifies the key type of the master key in the database; the default is
+the string representation of DEFAULT_KDC_KEYTYPE (defined in <krb5/osconf.h>).
+.PP
+The
+.B \-f
+.I stashfile
+option specifies the filename of the stashed V5 master key. The default is
+defined as DEFAULT_KEYFILE_STUB in <krb5/osconf.h> and is 
+typically $(prefix)/lib/krb5kdc/.k5.REALMNAME. (In previous
+releases, this would have been /.k5.REALMNAME.)
+.PP
+The
+.B \-M
+.I mkeyname
+option specifies the principal name for the master key in the database;
+the default is KRB5_KDB_M_NAME (defined in <krb5/kdb.h>).
+.PP
+The
+.B \-e
+.I enctype
+option specifies the encryption type to be used when placing entries in
+the database; the default is the string representation of DEFAULT_KDC_ETYPE
+(defined in <krb5/osconf.h>).
+.PP
+The
+.B \-m
+option specifies that the master database password should be fetched
+from the keyboard rather than from a file on disk.
+.SH AVAILABLE COMMANDS
+
+The following is a list of commands and their aliases that the system
+administrator may use to manipulate the database:
+
+.IP add_new_key,ank
+Add new entry to Kerberos database (prompting for password)
+
+.IP change_pwd_key,cpw      
+Change key of an entry in the Kerberos database (prompting for password)
+
+.IP add_rnd_key,ark         
+Add new entry to Kerberos database, using a random key
+
+.IP change_rnd_key,crk      
+Change key of an entry in the Kerberos database (select a new random key)
+
+.IP delete_entry,delent,del
+Delete an entry from the database
+
+.IP extract_srvtab,xst,ex_st
+Extract service key table
+
+.IP extract_v4_srvtab,xst4  
+Extract service key table
+
+.IP modify_entry,modent
+Modify entry
+
+.IP list_db,ldb             
+List database entries
+
+.IP dump_db,ddb             
+Dump database entries to a file
+
+.IP load_db,lddb            
+Load database entries from a file
+
+.IP set_dbname,sdbn         
+Change database name
+
+.IP enter_master_key,emk    
+Enter the master key for a database
+
+.IP change_working_directory,cwd,cd
+Change working directory
+
+.IP print_working_direcotry,pwd
+Print working directory
+
+.IP list_requests,lr,?     
+List available requests.
+
+.IP quit,exit,q            
+Exit program.
+
+.SH SEE ALSO
+krb5(3), krb5kdc(8), ss(3)
+.SH BUGS
+
diff --git a/mechglue/src/kadmin/dbutil/kdb5_stash.c b/mechglue/src/kadmin/dbutil/kdb5_stash.c
new file mode 100644
index 000000000..09bea2151
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/kdb5_stash.c
@@ -0,0 +1,182 @@
+/*
+ * admin/stash/kdb5_stash.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Store the master database key in a file.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+#include <kadm5/admin.h>
+#include <stdio.h>
+#include "kdb5_util.h"
+
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+extern kadm5_config_params global_params;
+
+extern int exit_status;
+extern int close_policy_db;
+
+void
+kdb5_stash(argc, argv)
+    int argc;
+    char *argv[];
+{
+    extern char *optarg;
+    extern int optind;
+    int optchar;
+    krb5_error_code retval;
+    char *dbname = (char *) NULL;
+    char *realm = 0;
+    char *mkey_name = 0;
+    char *mkey_fullname;
+    char *keyfile = 0;
+    krb5_context context;
+
+    if (strrchr(argv[0], '/'))
+	argv[0] = strrchr(argv[0], '/')+1;
+
+    retval = krb5_init_context(&context);
+    if( retval )
+    {
+	com_err(argv[0], retval, "while initializing krb5_context");
+	exit(1);
+    }
+
+    if ((retval = krb5_set_default_realm(context,
+					  util_context->default_realm))) {
+	com_err(argv[0], retval, "while setting default realm name");
+	exit(1);
+    }
+
+    dbname = global_params.dbname;
+    realm = global_params.realm;
+    mkey_name = global_params.mkey_name;
+    keyfile = global_params.stash_file;
+
+    optind = 1;
+    while ((optchar = getopt(argc, argv, "f:")) != -1) {
+	switch(optchar) {
+	case 'f':
+	    keyfile = optarg;
+	    break;
+	case '?':
+	default:
+	    usage();
+	    return;
+	}
+    }
+
+    if (!krb5_c_valid_enctype(master_keyblock.enctype)) {
+	char tmp[32];
+	if (krb5_enctype_to_string(master_keyblock.enctype, tmp, sizeof(tmp)))
+	    com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP,
+		    "while setting up enctype %d", master_keyblock.enctype);
+	else
+	    com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP, tmp);
+	exit_status++; return; 
+    }
+
+    /* assemble & parse the master key name */
+    retval = krb5_db_setup_mkey_name(context, mkey_name, realm, 
+				     &mkey_fullname, &master_princ);
+    if (retval) {
+	com_err(argv[0], retval, "while setting up master key name");
+	exit_status++; return; 
+    }
+
+    retval = krb5_db_open(context, db5util_db_args, KRB5_KDB_OPEN_RW);
+    if (retval) {
+	com_err(argv[0], retval, "while initializing the database '%s'",
+		dbname);
+	exit_status++; return; 
+    }
+
+    /* TRUE here means read the keyboard, but only once */
+    retval = krb5_db_fetch_mkey(context, master_princ,
+				master_keyblock.enctype,
+				TRUE, FALSE, (char *) NULL,
+				0, &master_keyblock);
+    if (retval) {
+	com_err(argv[0], retval, "while reading master key");
+	(void) krb5_db_fini(context);
+	exit_status++; return; 
+    }
+
+    retval = krb5_db_verify_master_key(context, master_princ, 
+				       &master_keyblock);
+    if (retval) {
+	com_err(argv[0], retval, "while verifying master key");
+	(void) krb5_db_fini(context);
+	exit_status++; return; 
+    }	
+
+    retval = krb5_db_store_master_key(context, keyfile, master_princ, 
+				      &master_keyblock, NULL);
+    if (retval) {
+	com_err(argv[0], errno, "while storing key");
+	memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+	(void) krb5_db_fini(context);
+	exit_status++; return; 
+    }
+    memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+
+    retval = krb5_db_fini(context);
+    if (retval) {
+	com_err(argv[0], retval, "closing database '%s'", dbname);
+	exit_status++; return; 
+    }
+
+    krb5_free_context(context);
+    exit_status = 0;
+    return; 
+}
diff --git a/mechglue/src/kadmin/dbutil/kdb5_util.M b/mechglue/src/kadmin/dbutil/kdb5_util.M
new file mode 100644
index 000000000..964212b0a
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/kdb5_util.M
@@ -0,0 +1,265 @@
+.TH KDB5_UTIL 8
+.SH NAME
+kdb5_util \- Kerberos database maintainance utility
+.SH SYNOPSIS
+.B kdb5_util
+[\fB\-r\fP\ \fIrealm\fP] [\fB\-d\fP\ \fIdbname\fP]
+[\fB\-k\fP\ \fImkeytype\fP] [\fB\-M\fP\ \fImkeyname\fP]
+[\fB\-sf\fP\ \fIstashfilename\fP]
+[\fB\-m\fP]
+.I command
+.I [command_options]
+.SH DESCRIPTION
+.B kdb5_util
+allows an administrator to perform low-level maintainance procedures on
+the Kerberos and KADM5 database.  Databases can be created, destroyed,
+and dumped to and loaded from
+.SM ASCII
+files.  Additionally,
+.B kdb5_util
+can create a Kerberos master key stash file.
+.B kdb5_util
+subsumes the functionality of and makes obsolete the previous database
+maintainance programs
+.BR kdb5_create ,
+.BR kdb5_edit ,
+.BR kdb5_destroy ,
+and
+.BR kdb5_stash .
+.PP
+When
+.B kdb5_util
+is run, it attempts to acquire the master key and open the database.
+However, execution continues regardless of whether or not
+.B kdb5_util
+successfully opens the database, because the database may not exist yet
+or the stash file may be corrupt.
+.SH COMMAND-LINE OPTIONS
+.TP
+\fB\-r\fP\ \fIrealm\fP
+specifies the Kerberos realm of the database; by default the realm
+returned by
+.IR krb5_default_local_realm (3)
+is used.
+.TP
+\fB\-d\fP\ \fIdbname\fP
+specifies the name under which the principal database is stored; by
+default the database is that listed in
+.IR kdc.conf (5).
+The KADM5 policy database and lock file are also derived from this
+value.
+.TP
+\fB\-k\fP\ \fImkeytype\fP
+specifies the key type of the master key in the database; the default is
+that given in
+.IR kdc.conf .
+.TP
+\fB\-M\fP\ \fImkeyname\fP
+principal name for the master key in the database; the default is
+that given in
+.IR kdc.conf .
+.TP
+.B \-m
+specifies that the master database password should be read from the TTY
+rather than fetched from a file on disk.
+.TP
+\fB\-sf\fP \fIstash_file\fP
+specifies the stash file of the master database password.
+.TP
+\fB\-P\fP \fIpassword\fP
+specifies the master database password.  This option is not recommended.
+.SH COMMANDS
+.TP
+\fBcreate\fP [\fB\-s\fP]
+Creates a new database.  If the
+.B \-s
+option is specified, the stash file is also created.  This command fails
+if the database already exists.  If the command is successful, the
+database is opened just as if it had already existed when the program
+was first run.
+.TP
+\fBdestroy\fP [\fB\-f\fP]
+Destroys the database, first overwriting the disk sectors and then
+unlinking the files, after prompting the user for confirmation.  With
+the
+.B \-f
+argument, does not prompt the user.
+.TP
+\fBstash\fP [\fB\-f\fP\ \fIkeyfile\fP]
+Stores the master principal's keys in a stash file.  The
+.B \-f
+argument can be used to override the keyfile specified at startup.
+.TP
+\fBdump\fP [\fB\-old\fP] [\fB\-b6\fP] [\fB\-b7\fP] [\fB\-ov\fP]
+[\fB\-verbose\fP] [\fB\-mkey_convert\fP]
+[\fB\-new_mkey_file\fP \fImkey_file\fP] [\fB\-rev\fP] [\fB\-recurse\fP]
+[\fIfilename\fP [\fIprincipals...\fP]]
+.br
+Dumps the current Kerberos and KADM5 database into an ASCII file.  By
+default, the database is dumped in current format, "kdb5_util
+load_dumpversion 5".  If
+.I filename
+is not specified, or is the string "\-", the dump is sent to standard
+output.  Options:
+.RS
+.TP
+.B \-old
+causes the dump to be in the Kerberos 5 Beta 5 and earlier dump format
+("kdb5_edit load_dump version 2.0").
+.TP
+.B \-b6
+causes the dump to be in the Kerberos 5 Beta 6 format ("kdb5_edit
+load_dump version 3.0").
+.TP
+.B \-b7
+causes the dump to be in the Kerberos 5 Beta 7 format ("kdb5_util load_dump version 4").  This was the dump format produced on releases prior to 1.2.2.
+.TP
+.B \-ov
+causes the dump to be in
+.I ovsec_adm_export
+format.
+.TP
+.B \-verbose
+causes the name of each principal and policy to be printed as it is
+dumped.
+.TP
+.B \-mkey_convert
+prompts for a new master key.  This new master key will be used to
+re-encrypt the key data in the dumpfile.  The key data in the database
+will not be changed.
+.TP
+.B \-new_mkey_file \fImkey_file\fP
+the filename of a stash file.  The master key in this stash file will
+be used to re-encrypt the key data in the dumpfile.  The key data in
+the database will not be changed.
+.TP
+.B \-rev
+dumps in reverse order.  This may recover principals that do not dump
+normally, in cases where database corruption has occured.
+.TP
+.B \-recurse
+causes the dump to walk the database recursively (btree only).  This
+may recover principals that do not dump normally, in cases where
+database corruption has occured.  In cases of such corruption, this
+option will probably retrieve more principals than the \fB\-rev\fP
+option will.
+.RE
+.TP
+\fBload\fP [\fB\-old\fP] [\fB\-b6\fP] [\fB\-b7\fP] [\fB\-ov\fP] [\fB\-hash\fP]
+[\fB\-verbose\fP] [\fB\-update\fP] \fIfilename dbname\fP [\fIadmin_dbname\fP]
+.br
+Loads a database dump from the named file into the named database.
+Unless the 
+.B \-old
+or 
+.B \-b6
+option is given, the format of the dump file is detected
+automatically and handled as appropriate.  Unless the
+.B \-update
+option is given, 
+.B load
+creates a new database containing only the principals in the dump file,
+overwriting the contents of any previously existing database.  Options:
+.RS
+.TP
+.B \-old
+requires the database to be in the Kerberos 5 Beta 5 and earlier format
+("kdb5_edit load_dump version 2.0").
+.TP
+.B \-b6
+requires the database to be in the Kerberos 5 Beta 6 format ("kdb5_edit
+load_dump version 3.0").
+.TP
+.B \-b7
+requires the database to be in the Kerberos 5 Beta 7 format ("kdb5_util
+load_dump version 4").
+.TP
+.B \-ov
+requires the database to be in
+.I ovsec_adm_import
+format.  Must be used with the
+.B \-update
+option.
+.TP
+.B \-hash
+requires the database to be stored as a hash.  If this option is not
+specified, the database will be stored as a btree.  This option
+is not recommended, as databases stored in hash format are known to
+corrupt data and lose principals.
+.TP
+.B \-verbose
+causes the name of each principal and policy to be printed as it is
+dumped.
+.TP
+.B \-update
+records from the dump file are added to or updated in the existing
+database; otherwise, a new database is created containing only what is
+in the dump file and the old one destroyed upon successful completion.
+.TP
+.B dbname
+is required and overrides the value specified on the command line or the
+default.
+.TP
+.B admin_dbname
+is optional and is derived from
+.B dbname
+if not specified.
+.RE
+.TP
+\fBdump_v4\fP [\fB\-S\fP] [\fIfilename\fP]
+Dumps the current database into the Kerberos 4 database dump format.
+The \-S option specifies the short lifetime algorithm.
+.TP
+\fBload_v4\fP [\fB\-T\fP] [\fB\-v\fP] [\fB\-h\fP] [\fB\-S\fP]
+[\fB\-t\fP] [\fB-n\fP] [\fB\-K\fP] [\fB\-s\fP\ \fIstashfile\fP]
+\fIinputfile\fP
+.br
+Loads a Kerberos 4 database dump file.  Options:
+.RS
+.TP
+.B \-K
+prompts for the V5 master key instead of using the stashed version.
+.TP
+.B \-n
+prompts for the V4 master key, instead of reading from the stash file.
+.TP
+.B \-s \fIstashfile
+gets the V4 master key out of \fIstashfile\fP instead of /.k
+.TP
+.B \-T
+creates a new \fIkrbtgt\fP instead of converting the V4 one.  The V5 server
+will thus not recognize outstanding tickets, so this should be used 
+with caution.
+.TP
+.B \-v
+lists each principal as it is converted or ignored.
+.TP
+.B \-t
+uses a temporary database, then moves that into place, instead of adding 
+the keys to the current database.
+.TP
+.B \-S
+Uses the short lifetime algorithm for conversion.
+.TP
+.B \-h
+Stores the database as a hash instead of a btree.  This option is
+not recommended, as databases stored in hash format are known to
+corrupt data and lose principals.
+.PP
+Note: if the Kerberos 4 database had a default expiration date of 12/31/1999
+or 12/31/2009 (the compiled in defaults for older or newer Kerberos
+releases) then any entries which have the same expiration date will be
+converted to "never" expire in the version 5 database.  If the default
+did not match either value, all expiration dates will be preserved. 
+.PP
+Also, Kerberos 4 stored a single modification time for any change to a
+record; Version 5 stores a seperate modification time and last
+password change time.  In practice, Version 4 "modifications" were
+always password changes.  \fIload_v4\fP copies the value into both
+fields.
+.RE
+.TP
+\fBark\fP
+Adds a random key.
+.SH SEE ALSO
+kadmin(8)
diff --git a/mechglue/src/kadmin/dbutil/kdb5_util.c b/mechglue/src/kadmin/dbutil/kdb5_util.c
new file mode 100644
index 000000000..a95dff702
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/kdb5_util.c
@@ -0,0 +1,600 @@
+/*
+ * admin/edit/kdb5_edit.c
+ *
+ * (C) Copyright 1990,1991, 1996 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Edit a KDC database.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <krb5/adm_proto.h>
+#include <time.h>
+#include "kdb5_util.h"
+
+char	*Err_no_master_msg = "Master key not entered!\n";
+char	*Err_no_database = "Database not currently opened!\n";
+
+/*
+ * XXX Ick, ick, ick.  These global variables shouldn't be global....
+ */
+char *mkey_password = 0;
+
+/*
+ * I can't figure out any way for this not to be global, given how ss
+ * works.
+ */
+
+int exit_status = 0;
+krb5_context util_context;
+kadm5_config_params global_params;
+
+void usage()
+{
+     fprintf(stderr, "Usage: "
+	   "kdb5_util [-x db_args]* [-r realm] [-d dbname] [-k mkeytype] [-M mkeyname]\n"
+	     "\t        [-sf stashfilename] [-m] cmd [cmd_options]\n"
+	     "\tcreate	[-s]\n"
+	     "\tdestroy	[-f]\n"
+	     "\tstash	[-f keyfile]\n"
+	     "\tdump	[-old] [-ov] [-b6] [-verbose]\n"
+	     "\t	[-mkey_convert] [-new_mkey_file mkey_file]\n"
+	     "\t	[-rev] [-recurse] [filename [princs...]]\n"
+	     "\tload	[-old] [-ov] [-b6] [-verbose] [-update] filename\n"
+	     "\tark	[-e etype_list] principal\n"
+	     "\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n"
+	     "\t\t\tLook at each database documentation for supported arguments\n");
+     exit(1);
+}
+
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+krb5_db_entry master_entry;
+int	valid_master_key = 0;
+
+char *progname;
+krb5_boolean manual_mkey = FALSE;
+krb5_boolean dbactive = FALSE;
+
+static int open_db_and_mkey(void);
+
+static void add_random_key(int, char **);
+   
+typedef void (*cmd_func)(int, char **);
+
+struct _cmd_table {
+     char *name;
+     cmd_func func;
+     int opendb;
+} cmd_table[] = {
+     {"create", kdb5_create, 0},
+     {"destroy", kdb5_destroy, 1},
+     {"stash", kdb5_stash, 1},
+     {"dump", dump_db, 1},
+     {"load", load_db, 0},
+/*      {"dump_v4", dump_v4db, 1}, */
+/*      {"load_v4", load_v4db, 0}, */
+     {"ark", add_random_key, 1},
+     {NULL, NULL, 0},
+};
+
+static struct _cmd_table *cmd_lookup(name)
+   char *name;
+{
+     struct _cmd_table *cmd = cmd_table;
+     while (cmd->name) {
+	  if (strcmp(cmd->name, name) == 0)
+	       return cmd;
+	  else
+	       cmd++;
+     }
+     
+     return NULL;
+}
+
+#define ARG_VAL (--argc > 0 ? (koptarg = *(++argv)) : (char *)(usage(), NULL))
+
+char **db5util_db_args = NULL;
+int    db5util_db_args_size = 0;
+     
+int main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    struct _cmd_table *cmd = NULL;
+    char *koptarg, **cmd_argv;	
+    char *db_name_tmp = NULL;
+    int cmd_argc;
+    krb5_error_code retval;
+
+    retval = krb5_init_context(&util_context);
+    if (retval) {
+	    com_err (progname, retval, "while initializing Kerberos code");
+	    exit(1);
+    }
+
+/*     initialize_adb_error_table(); */
+
+    progname = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
+
+    cmd_argv = (char **) malloc(sizeof(char *)*argc);
+    if (cmd_argv == NULL) {
+	 com_err(progname, ENOMEM, "while creating sub-command arguments");
+	 exit(1);
+    }
+    memset(cmd_argv, 0, sizeof(char *)*argc);
+    cmd_argc = 1;
+	 
+    argv++; argc--;
+    while (*argv) {
+       if (strcmp(*argv, "-P") == 0 && ARG_VAL) {
+	    mkey_password = koptarg;
+	    manual_mkey = TRUE;
+       } else if (strcmp(*argv, "-d") == 0 && ARG_VAL) {
+	    global_params.dbname = koptarg;
+	    global_params.mask |= KADM5_CONFIG_DBNAME;
+
+	    db_name_tmp = malloc( strlen(global_params.dbname) + sizeof("dbname="));
+	    if( db_name_tmp == NULL )
+	    {
+		com_err(progname, ENOMEM, "while parsing command arguments");
+		exit(1);
+	    }
+
+	    strcpy( db_name_tmp, "dbname=");
+	    strcat( db_name_tmp, global_params.dbname );
+
+	    db5util_db_args_size++;
+	    {
+		char **temp = realloc( db5util_db_args, sizeof(char*) * (db5util_db_args_size+1)); /* one for NULL */
+		if( temp == NULL )
+		{
+		    com_err(progname, ENOMEM, "while parsing command arguments\n");
+		    exit(1);
+		}
+
+		db5util_db_args = temp;
+	    }
+	    db5util_db_args[db5util_db_args_size-1] = db_name_tmp;
+	    db5util_db_args[db5util_db_args_size]   = NULL;
+
+       } else if (strcmp(*argv, "-x") == 0 && ARG_VAL) {
+	   db5util_db_args_size++;
+	   {
+	       char **temp = realloc( db5util_db_args, sizeof(char*) * (db5util_db_args_size+1)); /* one for NULL */
+	       if( temp == NULL )
+	       {
+		   fprintf(stderr,"%s: Cannot initialize. Not enough memory\n",
+			   argv[0]);
+		   exit(1);
+	       }
+
+	       db5util_db_args = temp;
+	   }
+	   db5util_db_args[db5util_db_args_size-1] = koptarg;
+	   db5util_db_args[db5util_db_args_size]   = NULL;
+
+       } else if (strcmp(*argv, "-r") == 0 && ARG_VAL) {
+	    global_params.realm = koptarg;
+	    global_params.mask |= KADM5_CONFIG_REALM;
+	    /* not sure this is really necessary */
+	    if ((retval = krb5_set_default_realm(util_context,
+						 global_params.realm))) {
+		 com_err(progname, retval, "while setting default realm name");
+		 exit(1);
+	    }
+       } else if (strcmp(*argv, "-k") == 0 && ARG_VAL) {
+	    if (krb5_string_to_enctype(koptarg, &global_params.enctype))
+		 com_err(argv[0], 0, "%s is an invalid enctype", koptarg);
+	    else
+		 global_params.mask |= KADM5_CONFIG_ENCTYPE;
+       } else if (strcmp(*argv, "-M") == 0 && ARG_VAL) {
+	    global_params.mkey_name = koptarg;
+	    global_params.mask |= KADM5_CONFIG_MKEY_NAME;
+       } else if (strcmp(*argv, "-sf") == 0 && ARG_VAL) {
+	    global_params.stash_file = koptarg;
+	    global_params.mask |= KADM5_CONFIG_STASH_FILE;
+       } else if (strcmp(*argv, "-m") == 0) {
+	    manual_mkey = TRUE;
+	    global_params.mkey_from_kbd = 1;
+	    global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+       } else if (cmd_lookup(*argv) != NULL) {
+	    if (cmd_argv[0] == NULL)
+		 cmd_argv[0] = *argv;
+	    else
+		 usage();
+       } else {
+	    cmd_argv[cmd_argc++] = *argv;
+       }
+       argv++; argc--;
+    }
+
+    if (cmd_argv[0] == NULL)
+	 usage();
+    
+    if( !util_context->default_realm )
+    {
+	char *temp = NULL;
+	retval = krb5_get_default_realm(util_context, &temp);
+	if( retval )
+	{
+	    com_err (progname, retval, "while getting default realm");
+	    exit(1);
+	}
+	util_context->default_realm = temp;
+    }
+
+    retval = kadm5_get_config_params(util_context, NULL, NULL,
+				     &global_params, &global_params);
+    if (retval) {
+	 com_err(argv[0], retval, "while retreiving configuration parameters");
+	 exit(1);
+    }
+
+    /*
+     * Dump creates files which should not be world-readable.  It is
+     * easiest to do a single umask call here.
+     */
+    (void) umask(077);
+
+    master_keyblock.enctype = global_params.enctype;
+    if ((master_keyblock.enctype != ENCTYPE_UNKNOWN) &&
+	(!krb5_c_valid_enctype(master_keyblock.enctype))) {
+	com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP,
+		"while setting up enctype %d", master_keyblock.enctype);
+    }
+
+    cmd = cmd_lookup(cmd_argv[0]);
+    if (cmd->opendb && open_db_and_mkey())
+	 return exit_status;
+
+    (*cmd->func)(cmd_argc, cmd_argv);
+
+    if( db_name_tmp )
+	free( db_name_tmp );
+
+    if( db5util_db_args )
+	free(db5util_db_args);
+
+    kadm5_free_config_params(util_context, &global_params);
+    krb5_free_context(util_context);
+    return exit_status;
+}
+
+#if 0
+/*
+ * This function is no longer used in kdb5_util (and it would no
+ * longer work, anyway).
+ */
+void set_dbname(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+
+    if (argc < 3) {
+	com_err(argv[0], 0, "Too few arguments");
+	com_err(argv[0], 0, "Usage: %s dbpathname realmname", argv[0]);
+	exit_status++;
+	return;
+    }
+    if (dbactive) {
+	if ((retval = krb5_db_fini(util_context)) && retval!= KRB5_KDB_DBNOTINITED) {
+	    com_err(argv[0], retval, "while closing previous database");
+	    exit_status++;
+	    return;
+	}
+	if (valid_master_key) {
+	    krb5_free_keyblock_contents(util_context, &master_keyblock);
+	    master_keyblock.contents = NULL;
+	    valid_master_key = 0;
+	}
+	krb5_free_principal(util_context, master_princ);
+	dbactive = FALSE;
+    }
+
+    (void) set_dbname_help(argv[0], argv[1]);
+    return;
+}
+#endif
+
+/*
+ * open_db_and_mkey: Opens the KDC and policy database, and sets the
+ * global master_* variables.  Sets dbactive to TRUE if the databases
+ * are opened, and valid_master_key to 1 if the global master
+ * variables are set properly.  Returns 0 on success, and 1 on
+ * failure, but it is not considered a failure if the master key
+ * cannot be fetched (the master key stash file may not exist when the
+ * program is run).
+ */
+static int open_db_and_mkey()
+{
+    krb5_error_code retval;
+    int nentries;
+    krb5_boolean more;
+    krb5_data scratch, pwd, seed;
+
+    dbactive = FALSE;
+    valid_master_key = 0;
+
+    if ((retval = krb5_db_open(util_context, db5util_db_args, KRB5_KDB_OPEN_RW))) {
+	com_err(progname, retval, "while initializing database");
+	exit_status++;
+	return(1);
+    }
+
+   /* assemble & parse the master key name */
+
+    if ((retval = krb5_db_setup_mkey_name(util_context,
+					  global_params.mkey_name,
+					  global_params.realm, 
+					  0, &master_princ))) {
+	com_err(progname, retval, "while setting up master key name");
+	exit_status++;
+	return(1);
+    }
+    nentries = 1;
+    if ((retval = krb5_db_get_principal(util_context, master_princ, 
+					&master_entry, &nentries, &more))) {
+	com_err(progname, retval, "while retrieving master entry");
+	exit_status++;
+	(void) krb5_db_fini(util_context);
+	return(1);
+    } else if (more) {
+	com_err(progname, KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE,
+		"while retrieving master entry");
+	exit_status++;
+	(void) krb5_db_fini(util_context);
+	return(1);
+    } else if (!nentries) {
+	com_err(progname, KRB5_KDB_NOENTRY, "while retrieving master entry");
+	exit_status++;
+	(void) krb5_db_fini(util_context);
+	return(1);
+    }
+
+    krb5_db_free_principal(util_context, &master_entry, nentries);
+
+    /* the databases are now open, and the master principal exists */
+    dbactive = TRUE;
+    
+    if (mkey_password) {
+	pwd.data = mkey_password;
+	pwd.length = strlen(mkey_password);
+	retval = krb5_principal2salt(util_context, master_princ, &scratch);
+	if (retval) {
+	    com_err(progname, retval, "while calculated master key salt");
+	    return(1);
+	}
+
+	/* If no encryption type is set, use the default */
+	if (master_keyblock.enctype == ENCTYPE_UNKNOWN) {
+	    master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+	    if (!krb5_c_valid_enctype(master_keyblock.enctype))
+		com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
+			"while setting up enctype %d",
+			master_keyblock.enctype);
+	}
+
+	retval = krb5_c_string_to_key(util_context, master_keyblock.enctype, 
+				      &pwd, &scratch, &master_keyblock);
+	if (retval) {
+	    com_err(progname, retval,
+		    "while transforming master key from password");
+	    return(1);
+	}
+	free(scratch.data);
+	mkey_password = 0;
+    } else if ((retval = krb5_db_fetch_mkey(util_context, master_princ, 
+					    master_keyblock.enctype,
+					    manual_mkey, FALSE,
+					    global_params.stash_file,
+					    0, &master_keyblock))) {
+	com_err(progname, retval, "while reading master key");
+	com_err(progname, 0, "Warning: proceeding without master key");
+	exit_status++;
+	return(0);
+    }
+    if ((retval = krb5_db_verify_master_key(util_context, master_princ, 
+					    &master_keyblock))) {
+	com_err(progname, retval, "while verifying master key");
+	exit_status++;
+	krb5_free_keyblock_contents(util_context, &master_keyblock);
+	return(1);
+    }
+
+    seed.length = master_keyblock.length;
+    seed.data = master_keyblock.contents;
+
+    if ((retval = krb5_c_random_seed(util_context, &seed))) {
+	com_err(progname, retval, "while seeding random number generator");
+	exit_status++;
+	memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+	krb5_free_keyblock_contents(util_context, &master_keyblock);
+	return(1);
+    }
+
+    valid_master_key = 1;
+    dbactive = TRUE;
+    return 0;
+}
+
+#ifdef HAVE_GETCWD
+#undef getwd
+#endif
+
+int 
+quit()
+{
+    krb5_error_code retval;
+    static krb5_boolean finished = 0;
+
+    if (finished)
+	return 0;
+    retval = krb5_db_fini(util_context);
+    memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+    finished = TRUE;
+    if (retval && retval != KRB5_KDB_DBNOTINITED) {
+	com_err(progname, retval, "while closing database");
+	exit_status++;
+	return 1;
+    }
+    return 0;
+}
+
+static void
+add_random_key(argc, argv)
+    int argc;
+    char **argv;
+{
+    krb5_error_code ret;
+    krb5_principal princ;
+    krb5_db_entry dbent;
+    int n;
+    krb5_boolean more;
+    krb5_timestamp now;
+
+    krb5_key_salt_tuple *keysalts = NULL;
+    krb5_int32 num_keysalts = 0;
+
+    int free_keysalts;
+    char *me = argv[0];
+    char *ks_str = NULL;
+    char *pr_str;
+
+    if (argc < 2)
+	usage();
+    for (argv++, argc--; *argv; argv++, argc--) {
+	if (!strcmp(*argv, "-e")) {
+	    argv++; argc--;
+	    ks_str = *argv;
+	    continue;
+	} else
+	    break;
+    }
+    if (argc < 1)
+	usage();
+    pr_str = *argv;
+    ret = krb5_parse_name(util_context, pr_str, &princ);
+    if (ret) {
+	com_err(me, ret, "while parsing principal name %s", pr_str);
+	exit_status++;
+	return;
+    }
+    n = 1;
+    ret = krb5_db_get_principal(util_context, princ, &dbent,
+				&n, &more);
+    if (ret) {
+	com_err(me, ret, "while fetching principal %s", pr_str);
+	exit_status++;
+	return;
+    }
+    if (n != 1) {
+	fprintf(stderr, "principal %s not found\n", pr_str);
+	exit_status++;
+	return;
+    }
+    if (more) {
+	fprintf(stderr, "principal %s not unique\n", pr_str);
+	krb5_db_free_principal(util_context, &dbent, 1);
+	exit_status++;
+	return;
+    }
+    ret = krb5_string_to_keysalts(ks_str,
+				  ", \t", ":.-", 0,
+				  &keysalts,
+				  &num_keysalts);
+    if (ret) {
+	com_err(me, ret, "while parsing keysalts %s", ks_str);
+	exit_status++;
+	return;
+    }
+    if (!num_keysalts || keysalts == NULL) {
+	num_keysalts = global_params.num_keysalts;
+	keysalts = global_params.keysalts;
+	free_keysalts = 0;
+    } else
+	free_keysalts = 1;
+    ret = krb5_dbe_ark(util_context, &master_keyblock,
+		       keysalts, num_keysalts,
+		       &dbent);
+    if (free_keysalts)
+	free(keysalts);
+    if (ret) {
+	com_err(me, ret, "while randomizing principal %s", pr_str);
+	krb5_db_free_principal(util_context, &dbent, 1);
+	exit_status++;
+	return;
+    }
+    dbent.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+    ret = krb5_timeofday(util_context, &now);
+    if (ret) {
+	com_err(me, ret, "while getting time");
+	krb5_db_free_principal(util_context, &dbent, 1);
+	exit_status++;
+	return;
+    }
+    ret = krb5_dbe_update_last_pwd_change(util_context, &dbent, now);
+    if (ret) {
+	com_err(me, ret, "while setting changetime");
+	krb5_db_free_principal(util_context, &dbent, 1);
+	exit_status++;
+	return;
+    }
+    ret = krb5_db_put_principal(util_context, &dbent, &n);
+    krb5_db_free_principal(util_context, &dbent, 1);
+    if (ret) {
+	com_err(me, ret, "while saving principal %s", pr_str);
+	exit_status++;
+	return;
+    }
+    printf("%s changed\n", pr_str);
+}
diff --git a/mechglue/src/kadmin/dbutil/kdb5_util.h b/mechglue/src/kadmin/dbutil/kdb5_util.h
new file mode 100644
index 000000000..bb6b0ac64
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/kdb5_util.h
@@ -0,0 +1,87 @@
+/*
+ * admin/edit/kdb5_edit.h
+ *
+ * Copyright 1992 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#define REALM_SEP	'@'
+#define REALM_SEP_STR	"@"
+
+extern char *progname;
+extern char *Err_no_database;
+#ifndef V4_DECLARES_STATIC
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+#endif
+extern krb5_boolean dbactive;
+extern int exit_status;
+extern krb5_context util_context;
+extern kadm5_config_params global_params;
+extern int valid_master_key;
+extern krb5_db_entry master_db;
+extern char **db5util_db_args;
+extern int    db5util_db_args_size;
+
+extern void usage(void);
+
+extern void add_key 
+	(char const *, char const *, 
+		   krb5_const_principal, const krb5_keyblock *, 
+		   krb5_kvno, krb5_keysalt *);
+extern int set_dbname_help
+	(char *, char *);
+
+extern char *kdb5_util_Init (int, char **);
+
+extern int quit (void);
+
+extern int check_for_match
+	(char *, int, krb5_db_entry *, int, int);
+
+extern void parse_token
+	(char *, int *, int *, char *);
+
+extern int create_db_entry (krb5_principal, krb5_db_entry *);
+
+extern int kadm5_create_magic_princs (kadm5_config_params *params,
+						krb5_context context);
+
+extern int process_ov_principal (char *fname, krb5_context kcontext, 
+					   FILE *filep, int verbose, 
+					   int *linenop);
+
+extern void load_db (int argc, char **argv);
+extern void dump_db (int argc, char **argv);
+extern void load_v4db (int argc, char **argv);
+extern void dump_v4db (int argc, char **argv);
+extern void kdb5_create (int argc, char **argv);
+extern void kdb5_destroy (int argc, char **argv);
+extern void kdb5_stash (int argc, char **argv);
+
+extern void update_ok_file (char *file_name);
+
+extern int kadm5_create (kadm5_config_params *params);
+
+void usage (void);
+
diff --git a/mechglue/src/kadmin/dbutil/loadv4.c b/mechglue/src/kadmin/dbutil/loadv4.c
new file mode 100644
index 000000000..672db584b
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/loadv4.c
@@ -0,0 +1,981 @@
+/*
+ * kadmin/dbutil/loadv4.c
+ *
+ * Copyright 1996 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Generate (from scratch) a Kerberos V5 KDC database, filling it in with the
+ * entries from a V4 database.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef KRB5_KRB4_COMPAT
+
+#include "k5-int.h"
+#include "com_err.h"
+
+#include <des.h>
+#include <krb.h>
+#include <krb_db.h>
+/* MKEYFILE is now defined in kdc.h */
+#include <kdc.h>
+
+static C_Block master_key;
+static Key_schedule master_key_schedule;
+
+static char *v4_mkeyfile = "/.k";
+
+#include <kadm5/admin.h>
+#include <stdio.h>
+/* Define to make certain blocks private */
+#define V4_DECLARES_STATIC
+#include "kdb5_util.h"
+#include "kadm5/adb.h"                  /* osa_adb_create_policy_db */
+#include <netinet/in.h>			/* ntohl */
+
+#define PROGNAME argv[0]
+
+enum ap_op {
+    NULL_KEY,				/* setup null keys */
+    MASTER_KEY,				/* use master key as new key */
+    RANDOM_KEY				/* choose a random key */
+};
+
+struct realm_info {
+    krb5_deltat max_life;
+    krb5_deltat max_rlife;
+    krb5_timestamp expiration;
+    krb5_flags flags;
+    krb5_keyblock *key;
+};
+
+static struct realm_info rblock = { /* XXX */
+    KRB5_KDB_MAX_LIFE,
+    KRB5_KDB_MAX_RLIFE,
+    KRB5_KDB_EXPIRATION,
+    KRB5_KDB_DEF_FLAGS,
+    0
+};
+
+static int verbose = 0;
+
+static int shortlife = 0;
+
+static krb5_error_code add_principal 
+		  (krb5_context,
+		   krb5_principal, 
+		   enum ap_op,
+		   struct realm_info *);
+
+static int v4init (char *, int, char *);
+static krb5_error_code enter_in_v5_db (krb5_context,
+				       char *, Principal *);
+static krb5_error_code process_v4_dump (krb5_context, char *,
+					char *, long);
+static krb5_error_code v4_dump_find_default (krb5_context, char *,
+					     char *, long *);
+static krb5_error_code fixup_database (krb5_context, char *);
+	
+static int create_local_tgt = 0;
+
+static krb5_keyblock master_keyblock;
+static krb5_principal master_princ;
+
+static krb5_data tgt_princ_entries[] = {
+	{0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
+	{0, 0, 0} };
+
+static krb5_data db_creator_entries[] = {
+	{0, sizeof("db_creation")-1, "db_creation"} };
+
+/* XXX knows about contents of krb5_principal, and that tgt names
+ are of form TGT/REALM@REALM */
+static krb5_principal_data tgt_princ = {
+        0,					/* magic number */
+	{0, 0, 0},				/* krb5_data realm */
+	tgt_princ_entries,			/* krb5_data *data */
+	2,					/* int length */
+	KRB5_NT_SRV_INST			/* int type */
+};
+
+static krb5_principal_data db_create_princ = {
+        0,					/* magic number */
+	{0, 0, 0},				/* krb5_data realm */
+	db_creator_entries,			/* krb5_data *data */
+	1,					/* int length */
+	KRB5_NT_SRV_INST			/* int type */
+};
+
+
+void
+load_v4db(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    /* The kdb library will default to this, but it is convenient to
+       make it explicit (error reporting and temporary filename generation
+       use it).  */
+    char *dbname = DEFAULT_KDB_FILE;
+    char *v4dumpfile = 0;
+    char *realm = 0;
+    char *mkey_name = 0;
+    char *mkey_fullname;
+    char *defrealm;
+    int v4manual = 0;
+    krb5_boolean read_mkey = 0;
+    int tempdb = 0;
+    char *tempdbname;
+    krb5_context context;
+    char *stash_file = (char *) NULL;
+    int	persist, op_ind;
+    kadm5_config_params newparams;
+    extern kadm5_config_params global_params;
+    long exp_time = 0;
+    krb5_int32 crflags = KRB5_KDB_CREATE_BTREE;
+    krb5_data seed;
+
+    retval = krb5_init_context(&context);
+    if (retval) {
+	fprintf(stderr, "%s: Could not initialize krb5 context.\n", PROGNAME);
+	return;
+    }
+
+    if (strrchr(argv[0], '/'))
+	argv[0] = strrchr(argv[0], '/')+1;
+
+    persist = 1;
+    op_ind = 1;
+    while (persist && (op_ind < argc)) {
+	if (!strcmp(argv[op_ind], "-T")) {
+	    create_local_tgt = 1;
+	}
+	else if (!strcmp(argv[op_ind], "-t")) {
+	    tempdb = 1;
+	}
+	else if (!strcmp(argv[op_ind], "-K")) {
+	    read_mkey = 1;
+	}
+	else if (!strcmp(argv[op_ind], "-v")) {
+	    verbose = 1;
+	}
+	else if (!strcmp(argv[op_ind], "-n")) {
+	    v4manual++;
+	} 
+	else if (!strcmp(argv[op_ind], "-S")) {
+	    shortlife++;
+	}
+	else if (!strcmp(argv[op_ind], "-s")) {
+	    if ((argc - op_ind) >= 1) {
+	        v4_mkeyfile = argv[op_ind+1];
+		op_ind++;
+	    } else {
+		usage();
+	    }
+	}
+	else if (!strcmp(argv[op_ind], "-h")) {
+	    crflags = KRB5_KDB_CREATE_HASH;
+	}
+	else if ((argc - op_ind) >= 1) {
+	    v4dumpfile = argv[op_ind];
+	    op_ind++;
+	}
+	else
+	    usage();
+	op_ind++;
+    }
+
+    realm = global_params.realm;
+    dbname = global_params.dbname;
+    mkey_name = global_params.mkey_name;
+    master_keyblock.enctype = global_params.enctype;
+    if (global_params.stash_file)
+	    stash_file = strdup(global_params.stash_file);
+    rblock.max_life = global_params.max_life;
+    rblock.max_rlife = global_params.max_rlife;
+    rblock.expiration = global_params.expiration;
+    rblock.flags = global_params.flags;
+
+    if (!v4dumpfile) {
+	usage();
+	krb5_free_context(context);
+	return;
+    }
+
+    if (!krb5_c_valid_enctype(master_keyblock.enctype)) {
+	com_err(PROGNAME, KRB5_PROG_KEYTYPE_NOSUPP,
+		"while setting up enctype %d", master_keyblock.enctype);
+	krb5_free_context(context);
+	return;
+    }
+
+    /* If the user has not requested locking, don't modify an existing database. */
+    if (! tempdb) {
+	retval = krb5_db_set_name(context, dbname);
+	if (retval != ENOENT) {
+	    fprintf(stderr,
+		    "%s: The v5 database appears to already exist.\n",
+		    PROGNAME);
+	    krb5_free_context(context);
+	    return;
+	}
+	tempdbname = dbname;
+    } else {
+	size_t dbnamelen = strlen(dbname);
+	tempdbname = malloc(dbnamelen + 2);
+	if (tempdbname == 0) {
+	    com_err(PROGNAME, ENOMEM, "allocating temporary filename");
+	    krb5_free_context(context);
+	    return;
+	}
+	strcpy(tempdbname, dbname);
+	tempdbname[dbnamelen] = '~';
+	tempdbname[dbnamelen+1] = 0;
+	(void) krb5_db_destroy(context, tempdbname);
+    }
+	
+
+    if (!realm) {
+	retval = krb5_get_default_realm(context, &defrealm);
+	if (retval) {
+	    com_err(PROGNAME, retval, "while retrieving default realm name");
+	    krb5_free_context(context);
+	    return;
+	}	    
+	realm = defrealm;
+    }
+
+    /* assemble & parse the master key name */
+    
+    retval = krb5_db_setup_mkey_name(context, mkey_name, realm,
+				     &mkey_fullname, &master_princ);
+    if (retval) {
+	com_err(PROGNAME, retval, "while setting up master key name");
+	krb5_free_context(context);
+	return;
+    }
+
+    krb5_princ_set_realm_data(context, &db_create_princ, realm);
+    krb5_princ_set_realm_length(context, &db_create_princ, strlen(realm));
+    krb5_princ_set_realm_data(context, &tgt_princ, realm);
+    krb5_princ_set_realm_length(context, &tgt_princ, strlen(realm));
+    krb5_princ_component(context, &tgt_princ,1)->data = realm;
+    krb5_princ_component(context, &tgt_princ,1)->length = strlen(realm);
+
+    printf("Initializing database '%s' for realm '%s',\n\
+master key name '%s'\n",
+	   dbname, realm, mkey_fullname);
+
+    if (read_mkey) {
+	puts("You will be prompted for the version 5 database Master Password.");
+	puts("It is important that you NOT FORGET this password.");
+	fflush(stdout);
+    }
+
+
+    retval = krb5_db_fetch_mkey(context, master_princ,
+				master_keyblock.enctype,
+				read_mkey, read_mkey, stash_file, 0, 
+				&master_keyblock);
+    if (retval) {
+	com_err(PROGNAME, retval, "while reading master key");
+	krb5_free_context(context);
+	return;
+    }
+
+    rblock.key = &master_keyblock;
+
+    seed.length = master_keyblock.length;
+    seed.data = master_keyblock.contents;
+
+    retval = krb5_c_random_seed(context, &seed);
+    if (retval) {
+	com_err(PROGNAME, retval, "while initializing random key generator");
+	krb5_free_context(context);
+	return;
+    }
+
+    retval = krb5_db_create(context, tempdbname, crflags);
+    if (retval) {
+	com_err(PROGNAME, retval, "while creating %sdatabase '%s'",
+		tempdb ? "temporary " : "", tempdbname);
+	krb5_free_context(context);
+	return;
+    }
+
+    retval = krb5_db_set_name(context, tempdbname);
+    if (retval) {
+	(void) krb5_db_destroy(context, tempdbname);
+        com_err(PROGNAME, retval, "while setting active database to '%s'",
+                tempdbname);
+	krb5_free_context(context);
+        return;
+    }
+    if (v4init(PROGNAME, v4manual, v4dumpfile)) {
+	(void) krb5_db_destroy(context, tempdbname);
+	krb5_free_context(context);
+	return;
+    }
+    if ((retval = krb5_db_init(context)) || 
+	(retval = krb5_db_open_database(context))) {
+	(void) krb5_db_destroy(context, tempdbname);
+	com_err(PROGNAME, retval, "while initializing the database '%s'",
+		tempdbname);
+	krb5_free_context(context);
+	return;
+    }
+
+    retval = add_principal(context, master_princ, MASTER_KEY, &rblock);
+    if (retval) {
+	(void) krb5_db_fini(context);
+	(void) krb5_db_destroy(context, tempdbname);
+	com_err(PROGNAME, retval, "while adding K/M to the database");
+	krb5_free_context(context);
+	return;
+    }
+
+    if (create_local_tgt &&
+	(retval = add_principal(context, &tgt_princ, RANDOM_KEY, &rblock))) {
+	(void) krb5_db_fini(context);
+	(void) krb5_db_destroy(context, tempdbname);
+	com_err(PROGNAME, retval, "while adding TGT service to the database");
+	krb5_free_context(context);
+	return;
+    }
+
+    retval = v4_dump_find_default(context, v4dumpfile, realm, &exp_time);
+    if (retval) {
+        com_err(PROGNAME, retval, "warning: default entry not found");
+    }
+
+    retval = process_v4_dump(context, v4dumpfile, realm, exp_time);
+    putchar('\n');
+    if (retval)
+	com_err(PROGNAME, retval, "while translating entries to the database");
+    else {
+	retval = fixup_database(context, realm);
+    }
+    
+    /* clean up; rename temporary database if there were no errors */
+    if (retval == 0) {
+	retval = krb5_db_fini (context);
+	if (retval)
+	    com_err(PROGNAME, retval, "while shutting down database");
+	else if (tempdb && (retval = krb5_db_rename(context, tempdbname,
+						    dbname)))
+	    com_err(PROGNAME, retval, "while renaming temporary database");
+    } else {
+	(void) krb5_db_fini (context);
+	if (tempdb)
+	    (void) krb5_db_destroy (context, tempdbname);
+    }
+    memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+
+    /*
+     * Cons up config params for new database; using the global_params
+     * is just fine.
+     */
+    newparams = global_params;
+
+    /*
+     * Always create the policy db, even if we are not loading a dump
+     * file with policy info.
+     */
+    if (!tempdb && (retval = osa_adb_create_policy_db(&newparams))) {
+	com_err(PROGNAME, retval, "while creating policy database");
+	kadm5_free_config_params(context, &newparams);
+	krb5_free_context(context);
+	return;
+    }
+    /*
+     * Create the magic principals in the database.
+     */
+    retval = kadm5_create_magic_princs(&newparams, context);
+    if (retval) {
+	com_err(PROGNAME, retval, "while creating KADM5 principals");
+	krb5_free_context(context);
+	return;
+    }
+    
+    krb5_free_context(context);
+    return;
+}
+
+static int
+v4init(pname, manual, dumpfile)
+char *pname;
+int manual;
+char *dumpfile;
+{
+    int fd;
+    int ok = 0;
+
+    if (!manual) {
+	fd = open(v4_mkeyfile, O_RDONLY, 0600);
+	if (fd >= 0) {
+	    if (read(fd, master_key, sizeof(master_key)) == sizeof(master_key))
+		ok = 1;
+	    close(fd);
+	}
+    }
+    if (!ok) {
+	des_read_password(&master_key, "V4 Kerberos master key", 0);
+	printf("\n");
+    }
+    key_sched(master_key, master_key_schedule);
+    return 0;
+}
+
+static krb5_error_code
+enter_in_v5_db(context, realm, princ)
+krb5_context context;
+char *realm;
+Principal *princ;
+{
+    krb5_db_entry entry;
+    krb5_error_code retval;
+    krb5_keyblock v4v5key;
+    int nentries = 1;
+    des_cblock v4key;
+    char *name;
+    krb5_timestamp	mod_time;
+    krb5_principal	mod_princ;
+    krb5_keysalt	keysalt;
+
+    /* don't convert local TGT if we created a TGT already.... */
+    if (create_local_tgt && !strcmp(princ->name, "krbtgt") &&
+	!strcmp(princ->instance, realm)) {
+	    if (verbose)
+		    printf("\nignoring local TGT: '%s.%s' ...",
+			   princ->name, princ->instance);
+	    return 0;
+    }
+    if (!strcmp(princ->name, KERB_M_NAME) &&
+	!strcmp(princ->instance, KERB_M_INST)) {
+	des_cblock key_from_db;
+	int val;
+
+	/* here's our chance to verify the master key */
+	/*
+	 * use the master key to decrypt the key in the db, had better
+	 * be the same! 
+	 */
+	memcpy(key_from_db, (char *)&princ->key_low, 4);
+	memcpy(((char *) key_from_db) + 4, (char *)&princ->key_high, 4);
+	pcbc_encrypt((C_Block *) &key_from_db,
+		     (C_Block *) &key_from_db,
+		     (long) sizeof(C_Block),
+		     master_key_schedule,
+		     (C_Block *) master_key,
+		     DECRYPT);
+	val = memcmp((char *) master_key, (char *) key_from_db,
+		     sizeof(master_key));
+	memset((char *)key_from_db, 0, sizeof(key_from_db));
+	if (val) {
+	    return KRB5_KDB_BADMASTERKEY;
+	}
+	if (verbose)
+	    printf("\nignoring '%s.%s' ...", princ->name, princ->instance);
+	return 0;
+    }
+    memset((char *) &entry, 0, sizeof(entry));
+    retval = krb5_425_conv_principal(context, princ->name, princ->instance,
+				     realm, &entry.princ);
+    if (retval)
+	return retval;
+    if (verbose) {
+	retval = krb5_unparse_name(context, entry.princ, &name);
+	if (retval)
+	   name = strdup("<not unparsable name!>");
+	if (verbose)
+	    printf("\ntranslating %s...", name);
+	free(name);
+    }
+
+    retval = krb5_build_principal(context, &mod_princ,
+				  strlen(realm), realm, princ->mod_name,
+				  princ->mod_instance[0] ? 
+				  princ->mod_instance : NULL,
+				  NULL);
+    if (retval) {
+	krb5_free_principal(context, entry.princ);
+	return retval;
+    }
+    mod_time = princ->mod_date;
+
+    if (!shortlife)
+	entry.max_life = krb_life_to_time(0, princ->max_life);
+    else
+	entry.max_life = princ->max_life * 60 * 5;
+    entry.max_renewable_life = rblock.max_rlife;
+    entry.len = KRB5_KDB_V1_BASE_LENGTH;
+    entry.expiration = princ->exp_date;
+    entry.attributes = rblock.flags;	/* XXX is there a way to convert
+					   the old attrs? */
+
+    memcpy((char *)v4key, (char *)&(princ->key_low), 4);
+    memcpy((char *) (((char *) v4key) + 4), (char *)&(princ->key_high), 4);
+    pcbc_encrypt((C_Block *) &v4key,
+		 (C_Block *) &v4key,
+		 (long) sizeof(C_Block),
+		 master_key_schedule,
+		 (C_Block *) master_key,
+		 DECRYPT);
+
+    v4v5key.magic = KV5M_KEYBLOCK;
+    v4v5key.contents = (krb5_octet *)v4key;
+    v4v5key.enctype = ENCTYPE_DES_CBC_CRC;
+    v4v5key.length = sizeof(v4key);
+
+    retval = krb5_dbe_create_key_data(context, &entry);
+    if (retval) {
+	krb5_free_principal(context, entry.princ);
+	krb5_free_principal(context, mod_princ);
+	return retval;
+    }
+
+    keysalt.type = KRB5_KDB_SALTTYPE_V4;
+    keysalt.data.length = 0;
+    keysalt.data.data = (char *) NULL;
+    retval = krb5_dbekd_encrypt_key_data(context, rblock.key,
+					 &v4v5key, &keysalt, 
+					 princ->key_version,
+					 &entry.key_data[0]);
+    if (!retval)
+	retval = krb5_dbe_update_mod_princ_data(context, &entry,
+						mod_time, mod_princ);
+    if (!retval)
+        retval = krb5_dbe_update_last_pwd_change(context, &entry, mod_time);
+
+    if (retval) {
+	krb5_db_free_principal(context, &entry, 1);
+	krb5_free_principal(context, mod_princ);
+	return retval;
+    }
+    memset((char *)v4key, 0, sizeof(v4key));
+
+    retval = krb5_db_put_principal(context, &entry, &nentries);
+
+    if (!retval && !strcmp(princ->name, "krbtgt") &&
+	strcmp(princ->instance, realm) && princ->instance[0]) {
+	    krb5_free_principal(context, entry.princ);
+	    retval = krb5_build_principal(context, &entry.princ,
+					  strlen(princ->instance),
+					  princ->instance,
+					  "krbtgt", realm, NULL);
+	    if (retval)
+		    return retval;
+	    retval = krb5_db_put_principal(context, &entry, &nentries);
+    }
+
+    krb5_db_free_principal(context, &entry, 1);
+    krb5_free_principal(context, mod_princ);
+
+    return retval;
+}
+
+static krb5_error_code
+add_principal(context, princ, op, pblock)
+krb5_context context;
+krb5_principal princ;
+enum ap_op op;
+struct realm_info *pblock;
+{
+    krb5_db_entry entry;
+    krb5_error_code retval;
+    krb5_keyblock rkey;
+    int nentries = 1;
+    krb5_timestamp mod_time;
+
+    memset((char *) &entry, 0, sizeof(entry));
+    retval = krb5_copy_principal(context, princ, &entry.princ);
+    if (retval)
+	return(retval);
+    entry.max_life = pblock->max_life;
+    entry.max_renewable_life = pblock->max_rlife;
+    entry.len = KRB5_KDB_V1_BASE_LENGTH;
+    entry.expiration = pblock->expiration;
+    
+    retval = krb5_timeofday(context, &mod_time);
+    if (retval) {
+	krb5_db_free_principal(context, &entry, 1);
+	return retval;
+    }
+    entry.attributes = pblock->flags;
+
+    retval = krb5_dbe_create_key_data(context, &entry);
+    if (retval) {
+	krb5_db_free_principal(context, &entry, 1);
+	return(retval);
+    }
+
+    switch (op) {
+    case MASTER_KEY:
+	entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
+	retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
+					     &master_keyblock,
+					     (krb5_keysalt *) NULL, 1,
+					     &entry.key_data[0]);
+	if (retval) {
+	    krb5_db_free_principal(context, &entry, 1);
+	    return retval;
+	}
+	break;
+    case RANDOM_KEY:
+	retval = krb5_c_make_random_key(context, pblock->key->enctype,
+					&rkey);
+	if (retval) {
+	    krb5_db_free_principal(context, &entry, 1);
+	    return retval;
+	}
+	retval = krb5_dbekd_encrypt_key_data(context, pblock->key,
+					     &rkey, (krb5_keysalt *) NULL, 
+					     1, &entry.key_data[0]);
+	if (retval) {
+	    krb5_db_free_principal(context, &entry, 1);
+	    return(retval);
+	}
+	krb5_free_keyblock_contents(context, &rkey);
+	break;
+    case NULL_KEY:
+	return EOPNOTSUPP;
+    default:
+	break;
+    }
+
+    retval = krb5_dbe_update_mod_princ_data(context, &entry,
+					    mod_time, &db_create_princ);
+    if (!retval)
+	retval = krb5_db_put_principal(context, &entry, &nentries);
+    krb5_db_free_principal(context, &entry, 1);
+    return retval;
+}
+
+/*
+ * Convert a struct tm * to a UNIX time.
+ */
+
+
+#define daysinyear(y) (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
+
+#define SECSPERDAY 24*60*60
+#define SECSPERHOUR 60*60
+#define SECSPERMIN 60
+
+static int cumdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
+			     365};
+
+static int leapyear[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static int nonleapyear[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static long
+maketime(tp, local)
+register struct tm *tp;
+int local;
+{
+    register long retval;
+    int foo;
+    int *marray;
+
+    if (tp->tm_mon < 0 || tp->tm_mon > 11 ||
+	tp->tm_hour < 0 || tp->tm_hour > 23 ||
+	tp->tm_min < 0 || tp->tm_min > 59 ||
+	tp->tm_sec < 0 || tp->tm_sec > 59) /* out of range */
+	return 0;
+
+    retval = 0;
+    if (tp->tm_year < 1900)
+	foo = tp->tm_year + 1900;
+    else
+	foo = tp->tm_year;
+
+    if (foo < 1901 || foo > 2038)	/* year is too small/large */
+	return 0;
+
+    if (daysinyear(foo) == 366) {
+	if (tp->tm_mon > 1)
+	    retval+= SECSPERDAY;	/* add leap day */
+	marray = leapyear;
+    } else
+	marray = nonleapyear;
+
+    if (tp->tm_mday < 0 || tp->tm_mday > marray[tp->tm_mon])
+	return 0;			/* out of range */
+
+    while (--foo >= 1970)
+	retval += daysinyear(foo) * SECSPERDAY;
+
+    retval += cumdays[tp->tm_mon] * SECSPERDAY;
+    retval += (tp->tm_mday-1) * SECSPERDAY;
+    retval += tp->tm_hour * SECSPERHOUR + tp->tm_min * SECSPERMIN + tp->tm_sec;
+
+    if (local) {
+	/* need to use local time, so we retrieve timezone info */
+	struct timezone tz;
+	struct timeval tv;
+	if (gettimeofday(&tv, &tz) < 0) {
+	    /* some error--give up? */
+	    return(retval);
+	}
+	retval += tz.tz_minuteswest * SECSPERMIN;
+    }
+    return(retval);
+}
+
+static long
+time_explode(cp)
+register char *cp;
+{
+    char wbuf[5];
+    struct tm tp;
+    int local;
+
+    memset((char *)&tp, 0, sizeof(tp));
+    
+    if (strlen(cp) > 10) {		/* new format */
+	(void) strncpy(wbuf, cp, 4);
+	wbuf[4] = 0;
+	tp.tm_year = atoi(wbuf);
+	cp += 4;			/* step over the year */
+	local = 0;			/* GMT */
+    } else {				/* old format: local time, 
+					   year is 2 digits, assuming 19xx */
+	wbuf[0] = *cp++;
+	wbuf[1] = *cp++;
+	wbuf[2] = 0;
+	tp.tm_year = 1900 + atoi(wbuf);
+	local = 1;			/* local */
+    }
+
+    wbuf[0] = *cp++;
+    wbuf[1] = *cp++;
+    wbuf[2] = 0;
+    tp.tm_mon = atoi(wbuf)-1;
+
+    wbuf[0] = *cp++;
+    wbuf[1] = *cp++;
+    tp.tm_mday = atoi(wbuf);
+    
+    wbuf[0] = *cp++;
+    wbuf[1] = *cp++;
+    tp.tm_hour = atoi(wbuf);
+    
+    wbuf[0] = *cp++;
+    wbuf[1] = *cp++;
+    tp.tm_min = atoi(wbuf);
+
+
+    return(maketime(&tp, local));
+}
+
+static krb5_error_code
+process_v4_dump(context, dumpfile, realm, default_exp_time)
+krb5_context context;
+char *dumpfile;
+char *realm;
+long default_exp_time;
+{
+    krb5_error_code retval;
+    FILE *input_file;
+    Principal aprinc;
+    char    exp_date_str[50];
+    char    mod_date_str[50];
+    int     temp1, temp2, temp3;
+
+    input_file = fopen(dumpfile, "r");
+    if (!input_file)
+	return errno;
+
+    for (;;) {			/* explicit break on eof from fscanf */
+	int nread;
+
+	memset((char *)&aprinc, 0, sizeof(aprinc));
+	nread = fscanf(input_file,
+		       "%s %s %d %d %d %hd %lx %lx %s %s %s %s\n",
+		       aprinc.name,
+		       aprinc.instance,
+		       &temp1,
+		       &temp2,
+		       &temp3,
+		       &aprinc.attributes,
+		       &aprinc.key_low,
+		       &aprinc.key_high,
+		       exp_date_str,
+		       mod_date_str,
+		       aprinc.mod_name,
+		       aprinc.mod_instance);
+	if (nread != 12) {
+	    retval = nread == EOF ? 0 : KRB5_KDB_DB_CORRUPT;
+	    break;
+	}
+	aprinc.key_low = ntohl (aprinc.key_low);
+	aprinc.key_high = ntohl (aprinc.key_high);
+	aprinc.max_life = (unsigned char) temp1;
+	aprinc.kdc_key_ver = (unsigned char) temp2;
+	aprinc.key_version = (unsigned char) temp3;
+	aprinc.exp_date = time_explode(exp_date_str);
+	if (aprinc.exp_date == default_exp_time)
+	    aprinc.exp_date = 0;
+	aprinc.mod_date = time_explode(mod_date_str);
+	if (aprinc.instance[0] == '*')
+	    aprinc.instance[0] = '\0';
+	if (aprinc.mod_name[0] == '*')
+	    aprinc.mod_name[0] = '\0';
+	if (aprinc.mod_instance[0] == '*')
+	    aprinc.mod_instance[0] = '\0';
+	retval = enter_in_v5_db(context, realm, &aprinc);
+	if (retval)
+	    break;
+    }
+    (void) fclose(input_file);
+    return retval;
+}
+
+static krb5_error_code
+v4_dump_find_default(context, dumpfile, realm, exptime)
+krb5_context context;
+char *dumpfile;
+char *realm;
+long *exptime;
+{
+    krb5_error_code retval = 0;
+    FILE *input_file;
+    Principal aprinc;
+    char    exp_date_str[50];
+    char    mod_date_str[50];
+    int     temp1, temp2, temp3;
+    long foundtime, guess1, guess2;
+
+    /* kdb_init is usually the only thing to touch the time in the 
+       default entry, and everything else just copies that time.  If
+       the site hasn't changed it, we can assume that "never" is an
+       appropriate value for V5.  There have been two values compiled
+       in, typically:
+
+       MIT V4 had the code
+       principal.exp_date = 946702799;
+       strncpy(principal.exp_date_txt, "12/31/99", DATE_SZ);
+
+       Cygnus CNS V4 had the code
+       principal.exp_date = 946702799+((365*10+3)*24*60*60);
+       strncpy(principal.exp_date_txt, "12/31/2009", DATE_SZ);
+
+       However, the dump files only store minutes -- so these values
+       are 59 seconds high.
+
+       Other values could be added later, but in practice these are
+       likely to be the only ones. */
+
+    guess1 = 946702799-59;
+    guess2 = 946702799+((365*10+3)*24*60*60);
+
+    input_file = fopen(dumpfile, "r");
+    if (!input_file)
+	return errno;
+
+    for (;;) {			/* explicit break on eof from fscanf */
+	int nread;
+
+	memset((char *)&aprinc, 0, sizeof(aprinc));
+	nread = fscanf(input_file,
+		       "%s %s %d %d %d %hd %lx %lx %s %s %s %s\n",
+		       aprinc.name,
+		       aprinc.instance,
+		       &temp1,
+		       &temp2,
+		       &temp3,
+		       &aprinc.attributes,
+		       &aprinc.key_low,
+		       &aprinc.key_high,
+		       exp_date_str,
+		       mod_date_str,
+		       aprinc.mod_name,
+		       aprinc.mod_instance);
+	if (nread != 12) {
+	    retval = nread == EOF ? 0 : KRB5_KDB_DB_CORRUPT;
+	    break;
+	}
+	if (!strcmp(aprinc.name, "default")
+	    && !strcmp(aprinc.instance, "*")) {
+	    foundtime = time_explode(exp_date_str);
+	    if (foundtime == guess1 || foundtime == guess2)
+	        *exptime = foundtime;
+	    if (verbose) {
+	        printf("\ndefault expiration found: ");
+	        if (foundtime == guess1) {
+		    printf("MIT or pre96q1 value (1999)");
+		} else if (foundtime == guess2) {
+		    printf("Cygnus CNS post 96q1 value (2009)");
+		} else {
+		    printf("non-default start time (%ld,%s)",
+			   foundtime, exp_date_str);
+		}
+	    }
+	    break;
+	}
+    }
+    (void) fclose(input_file);
+    return retval;
+}
+
+static krb5_error_code fixup_database(context, realm)
+    krb5_context context;
+    char * realm;
+{
+    return 0;
+}
+    
+#else /* KRB5_KRB4_COMPAT */
+void
+load_v4db(argc, argv)
+	int argc;
+	char *argv[];
+{
+	printf("This version of kdb5_util does not support the V4 load command.\n");
+}
+#endif /* KRB5_KRB4_COMPAT */
diff --git a/mechglue/src/kadmin/dbutil/nstrtok.h b/mechglue/src/kadmin/dbutil/nstrtok.h
new file mode 100644
index 000000000..f7f0d4a69
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/nstrtok.h
@@ -0,0 +1,3 @@
+/* Prototype for nstrtok */
+char *nstrtok(char *, const char *delim);
+
diff --git a/mechglue/src/kadmin/dbutil/ovload.c b/mechglue/src/kadmin/dbutil/ovload.c
new file mode 100644
index 000000000..f4338bc90
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/ovload.c
@@ -0,0 +1,212 @@
+#include    <unistd.h>
+#include    <string.h>
+#include    <stdlib.h>
+#ifdef HAVE_MEMORY_H
+#include    <memory.h>
+#endif
+
+#include    <k5-int.h>
+#include <kadm5/admin.h>
+#include <kadm5/server_internal.h>
+#include    <krb5/kdb.h>
+#include    "import_err.h"
+#include    "kdb5_util.h"
+#include    "nstrtok.h"
+
+#define LINESIZE	32768 /* XXX */
+#define PLURAL(count)	(((count) == 1) ? error_message(IMPORT_SINGLE_RECORD) : error_message(IMPORT_PLURAL_RECORDS))
+
+static int parse_pw_hist_ent(current, hist)
+   char *current;
+   osa_pw_hist_ent *hist;
+{
+     int tmp, i, j, ret;
+     char *cp;
+
+     ret = 0;
+     hist->n_key_data = 1;
+
+     hist->key_data = (krb5_key_data *) malloc(hist->n_key_data *
+					       sizeof(krb5_key_data));
+     if (hist->key_data == NULL)
+	  return ENOMEM;
+     memset(hist->key_data, 0, sizeof(krb5_key_data)*hist->n_key_data);
+
+     for (i = 0; i < hist->n_key_data; i++) {
+	  krb5_key_data *key_data = &hist->key_data[i];
+
+	  key_data->key_data_ver = 1;
+	  
+	  if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+	       com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+	       ret = IMPORT_FAILED;
+	       goto done;
+	  }
+	  key_data->key_data_type[0] = atoi(cp);
+
+	  if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+	       com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+	       ret =  IMPORT_FAILED;
+	       goto done;
+	  }
+	  key_data->key_data_length[0] = atoi(cp);
+	  
+	  if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+	       com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+	       ret = IMPORT_FAILED;
+	       goto done;
+	  }
+	  if(!(key_data->key_data_contents[0] =
+	       (krb5_octet *) malloc(key_data->key_data_length[0]+1))) {
+	       ret = ENOMEM;
+	       goto done;
+	  }
+	  for(j = 0; j < key_data->key_data_length[0]; j++) {
+	       if(sscanf(cp, "%02x", &tmp) != 1) {
+		    com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+		    ret = IMPORT_FAILED;
+		    goto done;
+	       }
+	       key_data->key_data_contents[0][j] = tmp;
+	       cp = strchr(cp, ' ') + 1;
+	  }
+     }
+     
+done:
+     return ret;
+}
+
+/*
+ * Function: parse_principal
+ * 
+ * Purpose: parse principal line in db dump file
+ *
+ * Arguments:
+ * 	<return value>	0 on success, error code on failure
+ *
+ * Requires:
+ *	principal database to be opened.
+ *	nstrtok(3) to have a valid buffer in memory.
+ * 
+ * Effects:
+ *	[effects]
+ *
+ * Modifies:
+ *	[modifies]
+ * 
+ */
+int process_ov_principal(fname, kcontext, filep, verbose, linenop)
+    char		*fname;
+    krb5_context	kcontext;
+    FILE		*filep;
+    int			verbose;
+    int			*linenop;
+{
+    XDR			    xdrs;
+    osa_princ_ent_t	    rec;
+    krb5_error_code	    ret;
+    krb5_tl_data	    tl_data;
+    krb5_principal	    princ;
+    krb5_db_entry	    kdb;
+    char		    *current;
+    char		    *cp;
+    int			    x, one;
+    krb5_boolean	    more;
+    char		    line[LINESIZE];
+
+    if (fgets(line, LINESIZE, filep) == (char *) NULL) {
+	 return IMPORT_BAD_FILE;
+    }
+    if((cp = nstrtok(line, "\t")) == NULL)
+	return IMPORT_BAD_FILE;
+    if((rec = (osa_princ_ent_t) malloc(sizeof(osa_princ_ent_rec))) == NULL)
+	return ENOMEM;
+    memset(rec, 0, sizeof(osa_princ_ent_rec));
+    if((ret = krb5_parse_name(kcontext, cp, &princ))) 
+	goto done;
+    krb5_unparse_name(kcontext, princ, ¤t);
+    if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+	com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+	ret =  IMPORT_FAILED;
+	goto done;
+    } else {
+	if(strcmp(cp, "")) {
+	    if((rec->policy = (char *) malloc(strlen(cp)+1)) == NULL)  {
+		ret = ENOMEM;
+		goto done;
+	    }
+	    strcpy(rec->policy, cp);
+	} else rec->policy = NULL;
+    }
+    if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+	com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+	ret = IMPORT_FAILED;
+	goto done;
+    }
+    rec->aux_attributes = strtol(cp, (char  **)NULL, 16);
+    if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+	com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+	ret = IMPORT_FAILED;
+	goto done;
+    }
+    rec->old_key_len = atoi(cp);
+    if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+	com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+	ret = IMPORT_FAILED;
+	goto done;
+    }
+    rec->old_key_next = atoi(cp);
+    if((cp = nstrtok((char *) NULL, "\t")) == NULL) {
+	com_err(NULL, IMPORT_BAD_RECORD, "%s", current);
+	ret = IMPORT_FAILED;
+	goto done;
+    }
+    rec->admin_history_kvno = atoi(cp);
+    if (! rec->old_key_len) {
+       rec->old_keys = NULL;
+    } else {
+       if(!(rec->old_keys = (osa_pw_hist_ent *)
+	    malloc(sizeof(osa_pw_hist_ent) * rec->old_key_len))) {
+	  ret = ENOMEM;
+	  goto done;
+       }
+       memset(rec->old_keys,0,
+	      sizeof(osa_pw_hist_ent) * rec->old_key_len);
+       for(x = 0; x < rec->old_key_len; x++)
+	    parse_pw_hist_ent(current, &rec->old_keys[x]);
+    }
+
+    xdralloc_create(&xdrs, XDR_ENCODE);
+    if (! xdr_osa_princ_ent_rec(&xdrs, rec)) {
+	 xdr_destroy(&xdrs);
+	 ret = KADM5_XDR_FAILURE;
+	 goto done;
+    }
+
+    tl_data.tl_data_type = KRB5_TL_KADM_DATA;
+    tl_data.tl_data_length = xdr_getpos(&xdrs);
+    tl_data.tl_data_contents = (krb5_octet *) xdralloc_getdata(&xdrs);
+
+    one = 1;
+    ret = krb5_db_get_principal(kcontext, princ, &kdb, &one, &more);
+    if (ret)
+	 goto done;
+    
+    ret = krb5_dbe_update_tl_data(kcontext, &kdb, &tl_data);
+    if (ret)
+	 goto done;
+
+    ret = krb5_db_put_principal(kcontext, &kdb, &one);
+    if (ret)
+	 goto done;
+
+    xdr_destroy(&xdrs);
+
+    (*linenop)++;
+
+done:
+    free(current);
+    krb5_free_principal(kcontext, princ);
+    osa_free_princ_ent(rec);
+    return ret;
+}
diff --git a/mechglue/src/kadmin/dbutil/string_table.c b/mechglue/src/kadmin/dbutil/string_table.c
new file mode 100644
index 000000000..1caa1402e
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/string_table.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ * 
+ */
+
+/* String table of messages for kadm5_create */
+
+char *str_PARSE_NAME = "while parsing admin principal name.";
+
+char *str_HISTORY_PARSE_NAME = "while parsing admin history principal name.";
+
+char *str_ADMIN_PRINC_EXISTS = "Warning! Admin principal already exists.";
+
+char *str_CHANGEPW_PRINC_EXISTS = "Warning! Changepw principal already exists.";
+
+char *str_HISTORY_PRINC_EXISTS = "Warning! Admin history principal already exists.";
+
+char *str_ADMIN_PRINC_WRONG_ATTRS = 
+    "Warning! Admin principal has incorrect attributes.\n"
+    "\tDISALLOW_TGT should be set, and max_life should be three hours.\n"
+    "\tThis program will leave them as-is, but beware!.";
+
+char *str_CHANGEPW_PRINC_WRONG_ATTRS = 
+    "Warning! Changepw principal has incorrect attributes.\n"
+    "\tDISALLOW_TGT and PW_CHANGE_SERVICE should both be set, and "
+     "max_life should be five minutes.\n"
+    "\tThis program will leave them as-is, but beware!.";
+
+char *str_HISTORY_PRINC_WRONG_ATTRS = 
+    "Warning! Admin history principal has incorrect attributes.\n"
+    "\tDISALLOW_ALL_TIX should be set.\n" 
+    "\tThis program will leave it as-is, but beware!.";
+
+char *str_CREATED_PRINC_DB =
+	"%s: Admin principal database created (or it already existed).\n"; /* whoami */
+
+char *str_CREATED_POLICY_DB =
+	"%s: Admin policy database created (or it already existed).\n"; /* whoami */
+
+char *str_RANDOM_KEY =
+	"while calling random key for %s.";  /* principal name */
+
+char *str_ENCRYPT_KEY =
+	"while calling encrypt key for %s."; /* principal name */
+
+char *str_PUT_PRINC =
+	"while storing %s in Kerberos database.";  /* principal name */
+
+char *str_CREATING_POLICY_DB = "while creating/opening admin policy database.";
+
+char *str_CLOSING_POLICY_DB = "while closing admin policy database.";
+
+char *str_CREATING_PRINC_DB = "while creating/opening admin principal database.";
+
+char *str_CLOSING_PRINC_DB = "while closing admin principal database.";
+
+char *str_CREATING_PRINC_ENTRY =
+	"while creating admin principal database entry for %s."; /* princ_name */
+
+char *str_A_PRINC = "a principal";
+
+char *str_UNPARSE_PRINC = "while unparsing principal.";
+
+char *str_CREATED_PRINC = "%s: Created %s principal.\n"; /* whoami, princ_name */
+
+char *str_INIT_KDB = "while initializing kdb.";
+
+char *str_NO_KDB = 
+"while initializing kdb.\nThe Kerberos KDC database needs to exist in /krb5.\n\
+If you haven't run kdb5_create you need to do so before running this command.";
+
+
+char *str_INIT_RANDOM_KEY = "while initializing random key generator.";
+
+char *str_TOO_MANY_ADMIN_PRINC = 
+	"while fetching admin princ. Can only have one admin principal.";
+
+char *str_TOO_MANY_CHANGEPW_PRINC = 
+	"while fetching changepw princ. Can only have one changepw principal.";
+
+char *str_TOO_MANY_HIST_PRINC = 
+	"while fetching history princ. Can only have one history principal.";
+
+char *str_WHILE_DESTROYING_ADMIN_SESSION = "while closing session with admin server and destroying tickets.";
diff --git a/mechglue/src/kadmin/dbutil/string_table.h b/mechglue/src/kadmin/dbutil/string_table.h
new file mode 100644
index 000000000..b89b9f1fa
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/string_table.h
@@ -0,0 +1,39 @@
+/*
+  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+  * 
+  * $Header$
+  *
+  */
+ 
+#ifndef _OVSEC_ADM_STRINGS_
+ 
+extern char *str_PARSE_NAME;
+extern char *str_HISTORY_PARSE_NAME;
+extern char *str_ADMIN_PRINC_EXISTS;
+extern char *str_CHANGEPW_PRINC_EXISTS;
+extern char *str_HISTORY_PRINC_EXISTS;
+extern char *str_ADMIN_PRINC_WRONG_ATTRS;
+extern char *str_CHANGEPW_PRINC_WRONG_ATTRS;
+extern char *str_HISTORY_PRINC_WRONG_ATTRS;
+extern char *str_CREATED_PRINC_DB;
+extern char *str_CREATED_POLICY_DB;
+extern char *str_RANDOM_KEY;
+extern char *str_ENCRYPT_KEY;
+extern char *str_PUT_PRINC;
+extern char *str_CREATING_POLICY_DB;
+extern char *str_CLOSING_POLICY_DB;
+extern char *str_CREATING_PRINC_DB;
+extern char *str_CLOSING_PRINC_DB;
+extern char *str_CREATING_PRINC_ENTRY;
+extern char *str_A_PRINC;
+extern char *str_UNPARSE_PRINC;
+extern char *str_CREATED_PRINC;
+extern char *str_INIT_KDB;
+extern char *str_NO_KDB;
+extern char *str_INIT_RANDOM_KEY;
+extern char *str_TOO_MANY_ADMIN_PRINC;
+extern char *str_TOO_MANY_CHANGEPW_PRINC;
+extern char *str_TOO_MANY_HIST_PRINC;
+extern char *str_WHILE_DESTROYING_ADMIN_SESSION;
+ 
+#endif /* _OVSEC_ADM_STRINGS_ */
diff --git a/mechglue/src/kadmin/dbutil/strtok.c b/mechglue/src/kadmin/dbutil/strtok.c
new file mode 100644
index 000000000..80117a31b
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/strtok.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ */
+
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include "nstrtok.h"
+
+/*
+ * Function: nstrtok
+ * 
+ * Purpose: the same as strtok ... just different. does not deal with
+ *	    multiple tokens in row.
+ *
+ * Arguments:
+ *	s	    (input) string to scan
+ *	delim	    (input) list of delimiters
+ * 	<return value> string or null on error.
+ *
+ * Requires:
+ *	nuttin
+ * 
+ * Effects:
+ *	sets last to string
+ *
+ * Modifies:
+ *	last
+ * 
+ */
+
+char *
+nstrtok(s, delim)
+	register char *s;
+	register const char *delim;
+{
+	register const char *spanp;
+	register int c, sc;
+	char *tok;
+	static char *last;
+
+
+	if (s == NULL && (s = last) == NULL)
+		return (NULL);
+
+	/*
+	 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+	 */
+#ifdef OLD	 
+cont:
+	c = *s++;
+	for (spanp = delim; (sc = *spanp++) != 0;) {
+		if (c == sc)
+			goto cont;
+	}
+
+	if (c == 0) {		/* no non-delimiter characters */
+		last = NULL;
+		return (NULL);
+	}
+	tok = s - 1;
+#else
+	tok = s;
+#endif	
+
+	/*
+	 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+	 * Note that delim must have one NUL; we stop if we see that, too.
+	 */
+	for (;;) {
+		c = *s++;
+		spanp = delim;
+		do {
+			if ((sc = *spanp++) == c) {
+				if (c == 0)
+					s = NULL;
+				else
+					s[-1] = 0;
+				last = s;
+				return (tok);
+			}
+		} while (sc != 0);
+	}
+	/* NOTREACHED */
+}
+
diff --git a/mechglue/src/kadmin/dbutil/tcl_wrapper.c b/mechglue/src/kadmin/dbutil/tcl_wrapper.c
new file mode 100644
index 000000000..16721ae6a
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/tcl_wrapper.c
@@ -0,0 +1,241 @@
+/*
+ * admin/edit/tcl_wrapper.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Tcl wrapper for kdb5_edit
+ */
+
+#include "k5-int.h"
+#include "kdb5_edit.h"
+#ifdef HAVE_TCL_H
+#include <tcl.h>
+#elif defined(HAVE_TCL_TCL_H)
+#include <tcl/tcl.h>
+#endif
+
+#define CMDDECL(x) int x(clientData, interp, argc, argv)\
+    ClientData clientData;\
+    Tcl_Interp * interp;\
+    int argc;\
+    char ** argv;
+#define CMDPROTO(x) int x (ClientData, Tcl_Interp, int, char **)
+#define MKCMD(name,cmd) Tcl_CreateCommand(interp, name, cmd,\
+					 (ClientData)NULL,\
+					 (Tcl_CmdDeleteProc *)NULL)
+
+extern int main();
+int *tclDummyMainPtr = (int *) main; /* force ld to suck in main()
+					from libtcl.a */
+extern Tcl_Interp *interp;	/* XXX yes, this is gross,
+				   but we do need it for some things */
+extern int exit_status;
+
+void show_principal (int, char **);
+void add_new_key (int, char **);
+void change_pwd_key (int, char **);
+void add_rnd_key (int, char **);
+void change_rnd_key (int, char **);
+void delete_entry (int, char **);
+void extract_srvtab (krb5_context, int, char **);
+void extract_v4_srvtab (int, char **);
+void list_db (int, char **);
+void dump_db (int, char **);
+void load_db (int, char **);
+void set_dbname (krb5_context, int, char **);
+void enter_master_key (krb5_context, int, char **);
+
+/*
+ * this is mostly stolen from tcl_ExitCmd()
+ * we need to do a few extra things, though...
+ */
+int doquit(clientData, interp, argc, argv)
+    ClientData clientData;
+    Tcl_Interp *interp;
+    int argc;
+    char *argv[];
+{
+    int value;
+
+    if ((argc != 1) && (argc != 2)) {
+	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+		" ?returnCode?\"", (char *) NULL);
+	return TCL_ERROR;
+    }
+    if (argc == 1) {
+	exit(quit() ? 1 : exit_status);
+    }
+    if (Tcl_GetInt(interp, argv[1], &value) != TCL_OK) {
+	return TCL_ERROR;
+    }
+    (void)quit();
+    exit(value);
+    /*NOTREACHED*/
+    return TCL_OK;			/* Better not ever reach this! */
+}
+
+int list_requests(clientData, interp, argc, argv)
+    ClientData clientData;
+    Tcl_Interp *interp;
+    int argc;
+    char *argv[];
+{
+    Tcl_SetResult(interp, "show_principal, show: Show the Kerberos database entry for a principal\nadd_new_key, ank: Add new entry to the Kerberos database (prompting for password\nchange_pwd_key, cpw: Change key of an entry in the Kerberos database (prompting for password)\nadd_rnd_key, ark: Add new entry to Kerberos database, using a random key\nchange_rnd_key, crk: Change key of an entry in the Kerberos database (select a random key)\ndelete_entry, delent: Delete an entry from the database\nextract_srvtab, xst, ex_st: Extract service key table\nextract_v4_srvtab, xst4: Extract service key table\nlist_db, ldb: List database entries\nset_dbname, sdbn: Change database name\nenter_master_key, emk: Enter the master key for a database\nchange_working_directory, cwd, cd: Change working directory\nprint_working_directory, pwd: Print working directory\nlist_requests, lr: List available requests\nquit, exit: Exit program", TCL_STATIC);
+    return TCL_OK;
+}
+
+int wrapper(func, interp, argc, argv)
+    void (*func)();
+    Tcl_Interp *interp;
+    int argc;
+    char *argv[];
+{
+    (*func)(argc, argv);
+    return TCL_OK;
+}
+
+int Tcl_AppInit(interp)
+    Tcl_Interp *interp;
+{
+    int argc;
+    char **argv, **mostly_argv;
+    char *interp_argv, *interp_argv0, *request;
+    Tcl_CmdInfo cmdInfo;
+
+    if (Tcl_Init(interp) == TCL_ERROR)
+	return TCL_ERROR;
+    /*
+     * the following is, admittedly, sorta gross, but the only way
+     * to grab the original argc, argv once the interpreter is running
+     */
+    interp_argv = Tcl_GetVar(interp, "argv", 0);
+    if (interp_argv == NULL)
+	return TCL_ERROR;
+    else if (Tcl_SplitList(interp, interp_argv,
+			   &argc, &mostly_argv) != TCL_OK)
+	return TCL_ERROR;
+    interp_argv0 = Tcl_GetVar(interp, "argv0", 0);
+    if (interp_argv0 == NULL)
+	return TCL_ERROR;
+    if ((argv = (char **)malloc((argc + 1) * sizeof (char *))) == NULL)
+	return TCL_ERROR;
+    argv[0] = interp_argv0;
+    memcpy(argv + 1, mostly_argv, argc++ * sizeof (char *));
+    /*
+     * set up a prompt
+     */
+    if (Tcl_SetVar(interp, "tcl_prompt1",
+		   "puts -nonewline \"kdb5_edit: \"", 0) == NULL)
+	return TCL_ERROR;
+    /*
+     * we don't want arbitrary programs to get exec'd by accident
+     */
+    if (Tcl_SetVar(interp, "auto_noexec", "{}", 0) == NULL)
+	return TCL_ERROR;
+    request = kdb5_edit_Init(argc, argv);
+    Tcl_CallWhenDeleted(interp, doquit,
+			(ClientData)0);
+    Tcl_CreateCommand(interp, "quit", doquit,
+		      (ClientData)0,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "exit", doquit,
+		      (ClientData)0,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "list_requests", list_requests,
+		      (ClientData)0,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "lr", list_requests,
+		      (ClientData)0,
+		      (Tcl_CmdDeleteProc *)0);
+    if (Tcl_GetCommandInfo(interp, "cd", &cmdInfo)) {
+	Tcl_CreateCommand(interp, "cwd", cmdInfo.proc,
+			  (ClientData)0,
+			  (Tcl_CmdDeleteProc *)0);
+	Tcl_CreateCommand(interp, "change_working_directory", cmdInfo.proc,
+			  (ClientData)0,
+			  (Tcl_CmdDeleteProc *)0);
+    }
+    if (Tcl_GetCommandInfo(interp, "pwd", &cmdInfo)) {
+	Tcl_CreateCommand(interp, "print_working_directory", cmdInfo.proc,
+			  (ClientData)0,
+			  (Tcl_CmdDeleteProc *)0);
+    }
+    Tcl_CreateCommand(interp, "show_principal", wrapper, show_principal,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "show", wrapper, show_principal,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "add_new_key", wrapper, add_new_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "ank", wrapper, add_new_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "change_pwd_key", wrapper, change_pwd_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "cpw", wrapper, change_pwd_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "add_rnd_key", wrapper, add_rnd_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "ark", wrapper, add_rnd_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "change_rnd_key", wrapper, change_rnd_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "crk", wrapper, change_rnd_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "delete_entry", wrapper, delete_entry,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "delent", wrapper, delete_entry,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "extract_srvtab", wrapper, extract_srvtab,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "xst", wrapper, extract_srvtab,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "ex_st", wrapper, extract_srvtab,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "extract_v4_srvtab", wrapper, extract_v4_srvtab,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "xv4st", wrapper, extract_v4_srvtab,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "list_db", wrapper, list_db,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "ldb", wrapper, list_db,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "dump_db", wrapper, dump_db,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "ddb", wrapper, dump_db,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "load_db", wrapper, load_db,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "lddb", wrapper, load_db,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "set_dbname", wrapper, set_dbname,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "sdbn", wrapper, set_dbname,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "enter_master_key", wrapper, enter_master_key,
+		      (Tcl_CmdDeleteProc *)0);
+    Tcl_CreateCommand(interp, "emk", wrapper, enter_master_key,
+		      (Tcl_CmdDeleteProc *)0);
+    if (request && (Tcl_Eval(interp, request) == TCL_ERROR))
+	return TCL_ERROR;
+    return TCL_OK;
+}
diff --git a/mechglue/src/kadmin/dbutil/util.c b/mechglue/src/kadmin/dbutil/util.c
new file mode 100644
index 000000000..246a6cb74
--- /dev/null
+++ b/mechglue/src/kadmin/dbutil/util.c
@@ -0,0 +1,158 @@
+/*
+ * admin/edit/util.c
+ *
+ * Copyright 1992 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Utilities for kdb5_edit.
+ * 
+ * Some routines derived from code contributed by the Sandia National
+ * Laboratories.  Sandia National Laboratories also makes no
+ * representations about the suitability of the modifications, or
+ * additions to this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ */
+
+#include "k5-int.h"
+#include "./kdb5_edit.h"
+
+#ifndef HAVE_STRSTR
+char *
+strstr(s1, s2)
+char *s1;
+char *s2;
+{
+   int s2len;
+   int i;
+   char *temp_ptr;
+
+   temp_ptr = s1;
+   for ( i = 0; i < strlen(s1); i++) {
+        if (memcmp(temp_ptr, s2, strlen(s2)) == 0) return(temp_ptr);
+        temp_ptr += 1;
+   }
+   return ((char *) 0);
+}
+#endif	/* HAVE_STRSTR */
+
+void
+parse_token(token_in, must_be_first_char, num_tokens, tokens_out)
+char *token_in;
+int  *must_be_first_char;
+int  *num_tokens;
+char *tokens_out;
+{
+    int i, j;
+    int token_count = 0;
+
+    i = 0;
+    j = 0;
+
+	/* Eliminate Up Front Asterisks */
+    *must_be_first_char = 1;
+    for (i = 0; token_in[i] == '*'; i++) {
+	*must_be_first_char = 0;
+    }
+
+    if (i == strlen(token_in)) {
+	*num_tokens = 0;
+	return;
+    }
+
+	/* Fill first token_out */
+    token_count++;
+    while ((token_in[i] != '*') && (token_in[i] != '\0')) {
+	tokens_out[j] = token_in[i];
+        j++;
+	i++;
+    }
+
+    if (i == strlen(token_in)) {
+	tokens_out[j] = '\0';
+	*num_tokens = token_count;
+	return;
+    }
+
+	/* Then All Subsequent Tokens */
+    while (i < strlen(token_in)) {
+	if (token_in[i] == '*') {
+	   token_count++;
+	   tokens_out[j] = '\t';
+	} else {
+	   tokens_out[j] = token_in[i];
+	}
+	i++;
+	j++;
+    }
+    tokens_out[j] = '\0';
+
+    if (tokens_out[j - 1] == '\t') {
+	token_count--;
+	tokens_out[j - 1] = '\0';
+    }
+
+    *num_tokens = token_count;
+    return;
+}
+
+int
+check_for_match(search_field, must_be_first_character, chk_entry, 
+		num_tokens, type)
+int must_be_first_character;
+char *search_field;
+krb5_db_entry *chk_entry;
+int num_tokens;
+int type;
+{
+    char token1[256];
+    char *found1;
+    char token2[256];
+    char *found2;
+    char token3[256];
+    char *found3;
+    char *local_entry;
+
+    local_entry = chk_entry->princ->data[type].data;
+
+    token1[0] = token2[0] = token3[0] = '\0';
+
+    (void) sscanf(search_field, "%s\t%s\t%s", token1, token2, token3);
+
+    found1 = strstr(local_entry, token1);
+
+    if (must_be_first_character && (found1 != local_entry)) return(0);
+
+    if (found1 && (num_tokens == 1)) return(1);
+
+    if (found1 && (num_tokens > 1)) {
+	found2 = strstr(local_entry, token2);
+	if (found2 && (found2 > found1) && (num_tokens == 2)) return(1);
+    }
+
+    if ((found2 > found1) && (num_tokens == 3)) {
+	found3 = strstr(local_entry, token3);
+       	if (found3 && (found3 > found2) && (found2 > found1)) return(1);
+    }
+    return(0);
+}
+
diff --git a/mechglue/src/kadmin/kdbkeys/ChangeLog b/mechglue/src/kadmin/kdbkeys/ChangeLog
new file mode 100644
index 000000000..27a574699
--- /dev/null
+++ b/mechglue/src/kadmin/kdbkeys/ChangeLog
@@ -0,0 +1,54 @@
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Wed Feb 18 15:55:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Thu Feb 12 10:24:16 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Removed obsolete macros: USE_KADMSRV_LIBRARY,n
+		USE_GSSRPC_LIBRARY, USE_DYN_LIBRARY, USE_KDB5_LIBRARY
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Jul 18 19:44:10 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: removed ET_RULES, replaced with AC_PROG_AWK
+
+Wed Jul 10 01:00:49 1996  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in, configure.in: added autoconf support
+
+	* kdbkeys.c: rename <ovsec_adm/foo.h> to <kadm5/foo.h>, rename
+ 	<krb5/krb5.h to <krb5.h>
+
+Tue Jul  9 13:25:00 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* do-test.pl: rewrite to use kdb5_util instead of kdbkeys
+	
+
diff --git a/mechglue/src/kadmin/kdbkeys/Makefile.in b/mechglue/src/kadmin/kdbkeys/Makefile.in
new file mode 100644
index 000000000..741a9a745
--- /dev/null
+++ b/mechglue/src/kadmin/kdbkeys/Makefile.in
@@ -0,0 +1,18 @@
+thisconfigdir=.
+myfulldir=kadmin/kdbkeys
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+
+PROG = kdbkeys
+OBJS = kdbkeys.o
+
+all:: $(PROG)
+
+$(PROG): $(OBJS) $(DEPLIBS)
+	$(CC) $(LDFLAGS) $(LDARGS) -o $(PROG) $(OBJS) $(LIBS)
+
+install::
+	$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+
+clean::
+	$(RM) $(PROG) $(OBJS)
diff --git a/mechglue/src/kadmin/kdbkeys/do-test.pl b/mechglue/src/kadmin/kdbkeys/do-test.pl
new file mode 100755
index 000000000..7acb425f7
--- /dev/null
+++ b/mechglue/src/kadmin/kdbkeys/do-test.pl
@@ -0,0 +1,56 @@
+#!/afs/athena/contrib/perl/p
+
+#
+# $Id$
+#
+
+$debug = $ARGV[1] || $ENV{'VERBOSE_TEST'};
+
+die "Need a number.\n" if !$ARGV[0];
+
+die "Neither \$TOP nor \$TESTDIR is set.\n" 
+    if (! ($ENV{'TOP'} || $ENV{'TESTDIR'}));
+
+$TESTDIR = ($ENV{'TESTDIR'} || "$ENV{'TOP'}/testing");
+$INITDB = ($ENV{'INITDB'} || "$TESTDIR/scripts/init_db");
+
+for ($i=0; $i<$ARGV[0]; $i++) {
+    print "Trial $i\n" if $debug;
+
+    system("$INITDB > /dev/null 2>&1") &&
+	die "Error in init_db\n";
+
+    open(KEYS,"../dbutil/kdb5_util -R dump_db|") ||
+	die "Couldn't run kdb5_util: $!\n";
+    chop($header = <KEYS>);
+    if ($header ne "kdb5_util load_dump version 4") {
+	die "Cannot operate on dump version \"$header\"; version 4 required.";
+    }
+    while(<KEYS>) {
+	next if ((!/^princ.*kadmin\//) && (!/^princ.*krbtgt/));
+
+	print if $debug > 1;
+
+	split;
+
+	$princ = $_[6];
+	$nkeys = $_[4];
+	$ntls = $_[3];
+	print "$princ: nkeys $nkeys, ntls $ntls\n" if $debug;
+	for ($j = 15 + $ntls*3; $nkeys > 0; $nkeys--) {
+	    $ver = $_[$j++];
+	    $kvno = $_[$j++];
+	    $keytype = $_[$j++];
+	    $keylen = $_[$j++];
+	    $keydata = $_[$j++];
+	    $j += 3 if ($ver > 1);
+
+	    print "$princ, ver $ver, kvno $kvno, type $keytype, len $keylen, "
+		. "data $keydata\n" if $debug;
+	    
+	    die "Duplicated key $princ = $keydata\n" if
+		$keys{$keydata}++;
+	}
+    }
+    close(KEYS);
+}
diff --git a/mechglue/src/kadmin/ktutil/.Sanitize b/mechglue/src/kadmin/ktutil/.Sanitize
new file mode 100644
index 000000000..60b9766ee
--- /dev/null
+++ b/mechglue/src/kadmin/ktutil/.Sanitize
@@ -0,0 +1,40 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+ktutil.c
+ktutil.h
+ktutil_ct.ct
+ktutil_funcs.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/kadmin/ktutil/ChangeLog b/mechglue/src/kadmin/ktutil/ChangeLog
new file mode 100644
index 000000000..fb35124a5
--- /dev/null
+++ b/mechglue/src/kadmin/ktutil/ChangeLog
@@ -0,0 +1,183 @@
+2005-10-12  Tom Yu  <tlyu@mit.edu>
+
+	* ktutil_funcs.c (ktutil_add): Fix malloc size botches reported by
+	Will Fiveash.
+
+2003-05-19  Sam Hartman  <hartmans@mit.edu>
+
+	* ktutil.c (main): Don't register writable keytab ops as they are
+	registered by the library now  
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* ktutil_funcs.c (ktutil_add): Remove trailing colon, as new
+	implementation of krb5_read_password() appends it.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktutil_ct.ct: Add final "end" statement.
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* ktutil.c (ktutil_list): Remove variable set but not used. Also,
+	do not assume that sizeof(time_t) is 32 bits.
+
+2003-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktutil_funcs.c (ktutil_write_srvtab): When keeping only
+	highest-numbered kvno, with some heuristics to deal with
+	wrap-around at 256.
+
+2002-03-02  Sam Hartman  <hartmans@mit.edu>
+
+	* ktutil_funcs.c (ktutil_write_srvtab): Set umask to 077 to avoid
+	public srvtabs.
+	
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktutil.h: Make prototypes unconditional.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Find ktutil_ct.c in build directory.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* ktutil_funcs.c (ktutil_add): Cast argument to isxdigit() to int.
+
+Mon Feb 26 14:27:24 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* ktutil.c, ktutil_funcs.c: Do not shadow system "index" and
+ 	"stime" variables.
+
+	* ktutil.h: Add prototypes for SS callback functions.
+
+2000-12-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktutil.c (ktutil_list): Provide a real usage message.
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (ktutil): Do not link with the V4
+	libraries. Although the program can write out a v4 srvtab, the one
+	necessary function is here.
+
+	* ktutil_funcs.c (ktutil_read_keytab): Add explicit braces to
+	avoid ambiguous `else'.
+	(getstr): register count -> register int count
+
+	* ktutil.c (main): ss_listen() takes only one argument.
+
+2000-05-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktutil_funcs.c (ktutil_write_keytab): Reject a filename that's
+	too long.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-17  Geoffrey King  <gjking@mit.edu>
+
+	* ktutil_funcs.c (ktutil_add): Cleanup newly allocated keytab
+	entry and tail of linked list when an error occurs.
+
+1999-08-16  Geoffrey King  <gjking@mit.edu>
+
+	* ktutil.c (ktutil_add_entry):
+	* ktutil_funcs.c (ktutil_add): Implement addent command to allow
+	creation of new keytab entries by specifying a key or password.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 18 15:56:16 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Sep 30 18:58:09 1997  Tom Yu  <tlyu@mit.edu>
+
+	* ktutil.c: Replace HAS_STDLIB_H with something more sane.
+
+Tue Feb  4 21:11:33 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Nov  7 15:42:17 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ktutil.c (main): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Tue Sep 10 14:17:17 1996  Tom Yu  <tlyu@mit.edu>
+
+	* ktutil.M: remove ".so man1/header.doc"
+
+Thu Aug 29 16:06:39 1996  Jeff Bigler  <jcb@mit.edu>
+
+	* Makefile.in (install): added man page
+
+Thu Jun 13 21:42:11 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to SS_RULES
+
+Fri Jul 12 14:37:47 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in (USE_KADM_LIBRARY): removed.  it wasn't needed.
+
+Tue Mar 19 19:41:31 1996  Richard Basch  <basch@lehman.com>
+
+	* ktutil_funcs.c (ktutil_write_srvtab): use any type of des key
+	in the keytab to create a v4 srvtab
+
+Fri Jan 26 00:06:50 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* ktutil.c (ktutil_list): Implement -e option to show enctypes.
+
+	* ktutil_funcs.c (ktutil_write_srvtab): Write v4 version
+        properly. Previous code was endien dependent.
+
+Mon Dec 25 10:03:15 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ktutil.c (ktutil_write_v4): Call ktutil_write_srvtab not
+		ktutil_write_keytab.
+
+	* ktutil_funcs.c (ktutil_write_srvtab): Clear malloced memory.
+
+
+Thu Sep 07 15:06:57 1995  Chris Provenzano (proven@mit.edu)
+
+	* ktutil_funcs.c : Do appropriate magic for enctype/keytype cleanup.
+
+Thu Aug 24 19:20:26 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Added .Sanitize file.
+
+Mon Aug 21 17:01:40 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* ktutil.c - Remove English-specific date handling and let timestamp_
+		to_sfstring() handle the formatting of the timestamp string.
+
diff --git a/mechglue/src/kadmin/ktutil/Makefile.in b/mechglue/src/kadmin/ktutil/Makefile.in
new file mode 100644
index 000000000..816fb2ec8
--- /dev/null
+++ b/mechglue/src/kadmin/ktutil/Makefile.in
@@ -0,0 +1,58 @@
+thisconfigdir=./..
+myfulldir=kadmin/ktutil
+mydir=ktutil
+BUILDTOP=$(REL)..$(S)..
+LOCALINCLUDES = $(KRB4_INCLUDES)
+PROG_LIBPATH=-L$(TOPLIBD) $(KRB4_LIBPATH)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+OBJS= 	ktutil.o \
+	ktutil_ct.o \
+	ktutil_funcs.o
+
+SRCS= 	$(srcdir)/ktutil.c \
+	ktutil_ct.c \
+	$(srcdir)/ktutil_funcs.c
+
+all:: ktutil
+
+ktutil: ktutil.o $(OBJS) $(SS_DEPLIB) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o ktutil $(OBJS) $(SS_LIB) $(KRB5_BASE_LIBS)
+
+install::
+	$(INSTALL_PROGRAM) ktutil ${DESTDIR}$(ADMIN_BINDIR)/ktutil
+	$(INSTALL_DATA) $(srcdir)/ktutil.M ${DESTDIR}$(ADMIN_MANDIR)/ktutil.8
+
+# needed until we run makedepend
+ktutil_ct.c: ktutil_ct.ct
+
+ktutil_ct.o: ktutil_ct.c
+
+clean::
+	$(RM) ktutil_ct.c
+
+depend:: ktutil_ct.c
+
+clean::
+	$(RM) ktutil
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)ktutil.$(OBJEXT): ktutil.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h ktutil.h $(SRCTOP)/include/krb5/adm_proto.h \
+  $(SS_DEPS)
+$(OUTPRE)ktutil_ct.$(OBJEXT): ktutil_ct.c $(SS_DEPS) \
+  $(COM_ERR_DEPS)
+$(OUTPRE)ktutil_funcs.$(OBJEXT): ktutil_funcs.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h ktutil.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP)
diff --git a/mechglue/src/kadmin/ktutil/ktutil.M b/mechglue/src/kadmin/ktutil/ktutil.M
new file mode 100644
index 000000000..de5fe7cb7
--- /dev/null
+++ b/mechglue/src/kadmin/ktutil/ktutil.M
@@ -0,0 +1,63 @@
+.TH KTUTIL 8
+.SH NAME
+ktutil \- Kerberos keytab file maintenance utility
+.SH SYNOPSIS
+.B ktutil
+.SH DESCRIPTION
+The
+.B ktutil
+command invokes a subshell from which an administrator can read, write,
+or edit entries in a Kerberos V5 keytab or V4 srvtab file.
+.SH COMMANDS
+.TP
+.B list
+Displays the current keylist.  Alias:
+.BR l .
+.TP
+\fBread_kt\fP \fIkeytab\fP
+Read the Kerberos V5 keytab file
+.I keytab
+into the current keylist.  Alias: 
+.B rkt
+.TP
+\fBread_st\fP \fIsrvtab\fP
+Read the Kerberos V4 srvtab file
+.I srvtab
+into the current keylist.  Alias:
+.BR rst .
+.TP
+\fBwrite_kt\fP \fIkeytab\fP
+Write the current keylist into the Kerberos V5 keytab file
+.IR keytab .
+Alias:
+.BR wkt .
+.TP
+\fBwrite_st\fP \fIsrvtab\fP
+Write the current keylist into the Kerberos V4 srvtab file
+.IR srvtab .
+Alias:
+.BR wst .
+.TP
+.B clear_list
+Clear the current keylist.  Alias:
+.BR clear .
+.TP
+\fBdelete_entry\fP \fIslot\fP
+Delets the entry in slot number
+.I slot
+from the current keylist.  Alais:
+.BR delent .
+.TP
+.BR list_requests
+Displays a listing of available commands.  Aliases:
+.BR lr ,
+.BR ? .
+.TP
+.B quit
+Quits
+.BR ktutil .
+Aliases:
+.BR exit ,
+.BR q .
+.SH SEE ALSO
+kadmin(8), kdb5_util(8)
diff --git a/mechglue/src/kadmin/ktutil/ktutil.c b/mechglue/src/kadmin/ktutil/ktutil.c
new file mode 100644
index 000000000..e2464e853
--- /dev/null
+++ b/mechglue/src/kadmin/ktutil/ktutil.c
@@ -0,0 +1,295 @@
+/*
+ * kadmin/ktutil/ktutil.c
+ *
+ * Copyright 1995, 1996 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * SS user interface for ktutil.
+ */
+
+#include "k5-int.h"
+#include "ktutil.h"
+#include <com_err.h>
+#include "adm_proto.h"
+#include <ss/ss.h>
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+extern ss_request_table ktutil_cmds;
+krb5_context kcontext;
+krb5_kt_list ktlist = NULL;
+
+int main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    int sci_idx;
+
+    retval = krb5_init_context(&kcontext);
+    if (retval) {
+        com_err(argv[0], retval, "while initializing krb5");
+	exit(1);
+    }
+    sci_idx = ss_create_invocation("ktutil", "5.0", (char *)NULL,
+				   &ktutil_cmds, &retval);
+    if (retval) {
+	ss_perror(sci_idx, retval, "creating invocation");
+	exit(1);
+    }
+    retval = ss_listen(sci_idx);
+    ktutil_free_kt_list(kcontext, ktlist);
+    exit(0);
+}
+
+void ktutil_clear_list(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+
+    if (argc != 1) {
+	fprintf(stderr, "%s: invalid arguments\n", argv[0]);
+	return;
+    }
+    retval = ktutil_free_kt_list(kcontext, ktlist);
+    if (retval)
+	com_err(argv[0], retval, "while freeing ktlist");
+    ktlist = NULL;
+}
+
+void ktutil_read_v5(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+
+    if (argc != 2) {
+	fprintf(stderr, "%s: must specify keytab to read\n", argv[0]);
+	return;
+    }
+    retval = ktutil_read_keytab(kcontext, argv[1], &ktlist);
+    if (retval)
+	com_err(argv[0], retval, "while reading keytab \"%s\"", argv[1]);
+}
+
+void ktutil_read_v4(argc, argv)
+    int argc;
+    char *argv[];
+{
+#ifdef KRB5_KRB4_COMPAT
+    krb5_error_code retval;
+
+    if (argc != 2) {
+	fprintf(stderr, "%s: must specify the srvtab to read\n", argv[0]);
+	return;
+    }
+    retval = ktutil_read_srvtab(kcontext, argv[1], &ktlist);
+    if (retval)
+	com_err(argv[0], retval, "while reading srvtab \"%s\"", argv[1]);
+#else
+    fprintf(stderr, "%s: krb4 support not configured\n", argv[0]);
+#endif
+}
+
+void ktutil_write_v5(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+
+    if (argc != 2) {
+	fprintf(stderr, "%s: must specify keytab to write\n", argv[0]);
+	return;
+    }
+    retval = ktutil_write_keytab(kcontext, ktlist, argv[1]);
+    if (retval)
+	com_err(argv[0], retval, "while writing keytab \"%s\"", argv[1]);
+}
+
+void ktutil_write_v4(argc, argv)
+    int argc;
+    char *argv[];
+{
+#ifdef KRB5_KRB4_COMPAT
+    krb5_error_code retval;
+
+    if (argc != 2) {
+	fprintf(stderr, "%s: must specify srvtab to write\n", argv[0]);
+	return;
+    }
+    retval = ktutil_write_srvtab(kcontext, ktlist, argv[1]);
+    if (retval)
+	com_err(argv[0], retval, "while writing srvtab \"%s\"", argv[1]);
+#else
+    fprintf(stderr, "%s: krb4 support not configured\n", argv[0]);
+#endif
+}
+
+void ktutil_add_entry(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    char *princ = NULL;
+    char *enctype = NULL;
+    krb5_kvno kvno = 0;
+    int use_pass = 0, use_key = 0, i;    
+
+    for (i = 1; i < argc; i++) {
+	if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-p", 2)) {
+	    princ = argv[++i];
+	    continue;
+	}
+	if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-k", 2)) {
+	    kvno = (krb5_kvno) atoi(argv[++i]);
+	    continue;
+	}
+	if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-e", 2)) {
+	    enctype = argv[++i];
+	    continue;
+	}
+	if ((strlen(argv[i]) == 9) && !strncmp(argv[i], "-password", 9)) {
+	    use_pass++;
+	    continue;
+	}
+	if ((strlen(argv[i]) == 4) && !strncmp(argv[i], "-key", 4)) {
+	    use_key++;
+	    continue;
+	}
+    }
+
+    if (argc != 8 || !(princ && kvno && enctype) || (use_pass+use_key != 1)) {
+        fprintf(stderr, "usage: %s (-key | -password) -p principal "
+		"-k kvno -e enctype\n", argv[0]);
+	return;
+    }
+
+    retval = ktutil_add(kcontext, &ktlist, princ, kvno, enctype, use_pass);
+    if (retval)
+        com_err(argv[0], retval, "while adding new entry");
+}
+
+void ktutil_delete_entry(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+
+    if (argc != 2) {
+	fprintf(stderr, "%s: must specify entry to delete\n", argv[0]);
+	return;
+    }
+    retval = ktutil_delete(kcontext, &ktlist, atoi(argv[1]));
+    if (retval)
+	com_err(argv[0], retval, "while deleting entry %d", atoi(argv[1]));
+}
+
+void ktutil_list(argc, argv)
+    int argc;
+    char *argv[];
+{
+    krb5_error_code retval;
+    krb5_kt_list lp;
+    int show_time = 0, show_keys = 0, show_enctype = 0;
+    int i, j;
+    char *pname;
+
+    for (i = 1; i < argc; i++) {
+	if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-t", 2)) {
+	    show_time++;
+	    continue;
+	}
+	if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-k", 2)) {
+	    show_keys++;
+	    continue;
+	}
+	if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-e", 2)) {
+	    show_enctype++;
+	    continue;
+	}
+
+	fprintf(stderr, "%s: usage: %s [-t] [-k] [-e]\n", argv[0], argv[0]);
+	return;
+    }
+    if (show_time) {
+	printf("slot KVNO Timestamp         Principal\n");
+	printf("---- ---- ----------------- ---------------------------------------------------\n");
+    } else {
+	printf("slot KVNO Principal\n");
+	printf("---- ---- ---------------------------------------------------------------------\n");
+    }
+    for (i = 1, lp = ktlist; lp; i++, lp = lp->next) {
+	retval = krb5_unparse_name(kcontext, lp->entry->principal, &pname);
+	if (retval) {
+	    com_err(argv[0], retval, "while unparsing principal name");
+	    return;
+	}
+	printf("%4d %4d ", i, lp->entry->vno);
+	if (show_time) {
+	    char fmtbuf[18];
+	    char fill;
+	    time_t tstamp;
+
+	    (void) localtime(&tstamp);
+	    lp->entry->timestamp = tstamp;
+	    fill = ' ';
+	    if (!krb5_timestamp_to_sfstring((krb5_timestamp)lp->entry->
+					    	timestamp,
+					    fmtbuf,
+					    sizeof(fmtbuf),
+					    &fill))
+		printf("%s ", fmtbuf);
+	}
+	printf("%40s", pname);
+	if (show_enctype) {
+	    static char buf[256];
+		if ((retval = krb5_enctype_to_string(
+		    lp->entry->key.enctype, buf, 256))) {
+		    com_err(argv[0], retval, "While converting enctype to string");
+		    return;
+		}
+	    printf(" (%s) ", buf);
+	}
+	
+	if (show_keys) {
+	    printf(" (0x");
+	    for (j = 0; j < lp->entry->key.length; j++)
+		printf("%02x", lp->entry->key.contents[j]);
+	    printf(")");
+	}
+	printf("\n");
+	krb5_xfree(pname);
+    }
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/mechglue/src/kadmin/ktutil/ktutil.h b/mechglue/src/kadmin/ktutil/ktutil.h
new file mode 100644
index 000000000..d25c8d998
--- /dev/null
+++ b/mechglue/src/kadmin/ktutil/ktutil.h
@@ -0,0 +1,75 @@
+/*
+ * kadmin/ktutil/ktutil.h
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+typedef struct _krb5_kt_list {
+    struct _krb5_kt_list *next;
+    krb5_keytab_entry *entry;
+} *krb5_kt_list;
+
+krb5_error_code ktutil_free_kt_list (krb5_context, krb5_kt_list);
+
+krb5_error_code ktutil_delete (krb5_context, krb5_kt_list *, int);
+
+krb5_error_code ktutil_add (krb5_context,
+			    krb5_kt_list *,
+			    char *,
+			    krb5_kvno,
+			    char *,
+			    int);
+
+krb5_error_code ktutil_read_keytab (krb5_context,
+				    char *,
+				    krb5_kt_list *);
+
+krb5_error_code ktutil_write_keytab (krb5_context,
+				     krb5_kt_list,
+				     char *);
+
+#ifdef KRB5_KRB4_COMPAT
+krb5_error_code ktutil_read_srvtab (krb5_context,
+				    char *,
+				    krb5_kt_list *);
+krb5_error_code ktutil_write_srvtab (krb5_context,
+				     krb5_kt_list,
+				     char *);
+#endif
+
+void ktutil_add_entry (int, char *[]);
+
+void ktutil_clear_list (int, char *[]);
+
+void ktutil_read_v5 (int, char *[]);
+
+void ktutil_read_v4 (int, char *[]);
+
+void ktutil_write_v5 (int, char *[]);
+
+void ktutil_write_v4 (int, char *[]);
+
+void ktutil_delete_entry (int, char *[]);
+
+void ktutil_list (int, char *[]);
diff --git a/mechglue/src/kadmin/ktutil/ktutil_ct.ct b/mechglue/src/kadmin/ktutil/ktutil_ct.ct
new file mode 100644
index 000000000..0c7ccb689
--- /dev/null
+++ b/mechglue/src/kadmin/ktutil/ktutil_ct.ct
@@ -0,0 +1,59 @@
+# Copyright 1995 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+# 
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+# 
+# Command table for ktutil
+#
+
+command_table ktutil_cmds;
+
+request ktutil_clear_list, "Clear the current keylist.",
+	clear_list, clear;
+
+request ktutil_read_v5, "Read a krb5 keytab into the current keylist.",
+	read_kt, rkt;
+
+request ktutil_read_v4, "Read a krb4 srvtab into the current keylist.",
+	read_st, rst;
+
+request ktutil_write_v5, "Write the current keylist to a krb5 keytab.",
+	write_kt, wkt;
+
+request ktutil_write_v4, "Write the current keylist to a krb4 srvtab.",
+	write_st, wst;
+
+request ktutil_add_entry, "Add an entry to the current keylist.",
+	add_entry, addent;
+
+request ktutil_delete_entry, "Delete an entry from the current keylist.",
+	delete_entry, delent;
+
+request ktutil_list, "List the current keylist.",
+	list, l;
+
+request ss_list_requests, "List available requests.",
+	list_requests, lr, "?";
+
+request ss_quit, "Exit program.",
+	quit, exit, q;
+
+end;
diff --git a/mechglue/src/kadmin/ktutil/ktutil_funcs.c b/mechglue/src/kadmin/ktutil/ktutil_funcs.c
new file mode 100644
index 000000000..649002e21
--- /dev/null
+++ b/mechglue/src/kadmin/ktutil/ktutil_funcs.c
@@ -0,0 +1,556 @@
+/*
+ * kadmin/ktutil/ktutil_funcs.c
+ *
+ *(C) Copyright 1995, 1996 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Utility functions for ktutil.
+ */
+
+#include "k5-int.h"
+#include "ktutil.h"
+#ifdef KRB5_KRB4_COMPAT
+#include "kerberosIV/krb.h"
+#include <stdio.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+
+/*
+ * Free a kt_list
+ */
+krb5_error_code ktutil_free_kt_list(context, list)
+    krb5_context context;
+    krb5_kt_list list;
+{
+    krb5_kt_list lp, prev;
+    krb5_error_code retval = 0;
+
+    for (lp = list; lp;) {
+	retval = krb5_kt_free_entry(context, lp->entry);
+	free((char *)lp->entry);
+	if (retval)
+	    break;
+	prev = lp;
+	lp = lp->next;
+	free((char *)prev);
+    }
+    return retval;
+}
+
+/*
+ * Delete a numbered entry in a kt_list.  Takes a pointer to a kt_list
+ * in case head gets deleted.
+ */
+krb5_error_code ktutil_delete(context, list, idx)
+    krb5_context context;
+    krb5_kt_list *list;
+    int idx;
+{
+    krb5_kt_list lp, prev;
+    int i;
+
+    for (lp = *list, i = 1; lp; prev = lp, lp = lp->next, i++) {
+	if (i == idx) {
+	    if (i == 1)
+		*list = lp->next;
+	    else
+		prev->next = lp->next;
+	    lp->next = NULL;
+	    return ktutil_free_kt_list(context, lp);
+	}
+    }
+    return EINVAL;
+}
+
+/*
+ * Create a new keytab entry and add it to the keytab list.
+ * Based on the value of use_pass, either prompt the user for a
+ * password or key.  If the keytab list is NULL, allocate a new
+ * one first.
+ */
+krb5_error_code ktutil_add(context, list, princ_str, kvno,
+			   enctype_str, use_pass)
+    krb5_context context;
+    krb5_kt_list *list;
+    char *princ_str;
+    krb5_kvno kvno;
+    char *enctype_str;
+    int use_pass;
+{
+    krb5_keytab_entry *entry;
+    krb5_kt_list lp = NULL, prev = NULL;
+    krb5_principal princ;
+    krb5_enctype enctype;
+    krb5_timestamp now;
+    krb5_error_code retval;
+    krb5_data password, salt;
+    krb5_keyblock key;
+    char buf[BUFSIZ];
+    char promptstr[1024];
+
+    char *cp;
+    int i, tmp;
+    unsigned int pwsize = BUFSIZ;
+
+    retval = krb5_parse_name(context, princ_str, &princ);
+    if (retval)
+        return retval;
+    /* now unparse in order to get the default realm appended
+       to princ_str, if no realm was specified */
+    retval = krb5_unparse_name(context, princ, &princ_str);
+    if (retval)
+        return retval;
+    retval = krb5_string_to_enctype(enctype_str, &enctype);
+    if (retval) 
+        return KRB5_BAD_ENCTYPE;
+    retval = krb5_timeofday(context, &now);
+    if (retval)
+        return retval;
+
+    if (*list) {
+        /* point lp at the tail of the list */
+        for (lp = *list; lp->next; lp = lp->next);
+    }
+    entry = (krb5_keytab_entry *) malloc(sizeof(krb5_keytab_entry));
+    if (!entry) {
+        return ENOMEM;
+    }
+    memset((char *) entry, 0, sizeof(*entry));
+
+    if (!lp) {		/* if list is empty, start one */
+        lp = (krb5_kt_list) malloc(sizeof(*lp));
+	if (!lp) {
+	    return ENOMEM;
+	}
+    } else {
+        lp->next = (krb5_kt_list) malloc(sizeof(*lp));
+	if (!lp->next) {
+	    return ENOMEM;
+	}
+	prev = lp;
+	lp = lp->next;
+    }          
+    lp->next = NULL;
+    lp->entry = entry;
+
+    if (use_pass) {
+        password.length = pwsize;
+	password.data = (char *) malloc(pwsize);
+	if (!password.data) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+
+	sprintf(promptstr, "Password for %.1000s", princ_str);
+        retval = krb5_read_password(context, promptstr, NULL, password.data,
+				    &password.length);
+	if (retval)
+	    goto cleanup;
+	retval = krb5_principal2salt(context, princ, &salt);
+	if (retval)
+	    goto cleanup;
+	retval = krb5_c_string_to_key(context, enctype, &password,
+				      &salt, &key);
+	if (retval)
+	    goto cleanup;
+	memset(password.data, 0, password.length);
+	password.length = 0;
+	memcpy(&lp->entry->key, &key, sizeof(krb5_keyblock));
+    } else {
+        printf("Key for %s (hex): ", princ_str);
+	fgets(buf, BUFSIZ, stdin);
+	/*
+	 * We need to get rid of the trailing '\n' from fgets.
+	 * If we have an even number of hex digits (as we should),
+	 * write a '\0' over the '\n'.  If for some reason we have
+	 * an odd number of hex digits, force an even number of hex
+	 * digits by writing a '0' into the last position (the string
+	 * will still be null-terminated).
+	 */
+	buf[strlen(buf) - 1] = strlen(buf) % 2 ? '\0' : '0';
+	if (strlen(buf) == 0) {
+	    fprintf(stderr, "addent: Error reading key.\n");
+	    retval = 0;
+	    goto cleanup;
+	}
+	
+        lp->entry->key.enctype = enctype;
+	lp->entry->key.contents = (krb5_octet *) malloc((strlen(buf) + 1) / 2);
+	if (!lp->entry->key.contents) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+
+	i = 0;
+	for (cp = buf; *cp; cp += 2) {
+	    if (!isxdigit((int) cp[0]) || !isxdigit((int) cp[1])) {
+	        fprintf(stderr, "addent: Illegal character in key.\n");
+		retval = 0;
+		goto cleanup;
+	    }
+	    sscanf(cp, "%02x", &tmp);
+	    lp->entry->key.contents[i++] = (krb5_octet) tmp;
+	}
+	lp->entry->key.length = i;
+    }
+    lp->entry->principal = princ;
+    lp->entry->vno = kvno;
+    lp->entry->timestamp = now;
+
+    if (!*list)
+	*list = lp;
+
+    return 0;
+
+ cleanup:
+    if (prev)
+        prev->next = NULL;
+    ktutil_free_kt_list(context, lp);
+    return retval;
+}
+
+/*
+ * Read in a keytab and append it to list.  If list starts as NULL,
+ * allocate a new one if necessary.
+ */
+krb5_error_code ktutil_read_keytab(context, name, list)
+    krb5_context context;
+    char *name;
+    krb5_kt_list *list;
+{
+    krb5_kt_list lp = NULL, tail = NULL, back = NULL;
+    krb5_keytab kt;
+    krb5_keytab_entry *entry;
+    krb5_kt_cursor cursor;
+    krb5_error_code retval = 0;
+
+    if (*list) {
+	/* point lp at the tail of the list */
+	for (lp = *list; lp->next; lp = lp->next);
+	back = lp;
+    }
+    retval = krb5_kt_resolve(context, name, &kt);
+    if (retval)
+	return retval;
+    retval = krb5_kt_start_seq_get(context, kt, &cursor);
+    if (retval)
+	goto close_kt;
+    for (;;) {
+	entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry));
+	if (!entry) {
+	    retval = ENOMEM;
+	    break;
+	}
+	memset((char *)entry, 0, sizeof (*entry));
+	retval = krb5_kt_next_entry(context, kt, entry, &cursor);
+	if (retval)
+	    break;
+
+	if (!lp) {		/* if list is empty, start one */
+	    lp = (krb5_kt_list)malloc(sizeof (*lp));
+	    if (!lp) {
+		retval = ENOMEM;
+		break;
+	    }
+	} else {
+	    lp->next = (krb5_kt_list)malloc(sizeof (*lp));
+	    if (!lp->next) {
+		retval = ENOMEM;
+		break;
+	    }
+	    lp = lp->next;
+	}
+	if (!tail)
+	    tail = lp;
+	lp->next = NULL;
+	lp->entry = entry;
+    }
+    if (entry)
+	free((char *)entry);
+    if (retval) {
+	if (retval == KRB5_KT_END)
+	    retval = 0;
+	else {
+	    ktutil_free_kt_list(context, tail);
+	    tail = NULL;
+	    if (back)
+		back->next = NULL;
+	}
+    }
+    if (!*list)
+	*list = tail;
+    krb5_kt_end_seq_get(context, kt, &cursor);
+ close_kt:
+    krb5_kt_close(context, kt);
+    return retval;
+}
+
+/*
+ * Takes a kt_list and writes it to the named keytab.
+ */
+krb5_error_code ktutil_write_keytab(context, list, name)
+    krb5_context context;
+    krb5_kt_list list;
+    char *name;
+{
+    krb5_kt_list lp;
+    krb5_keytab kt;
+    char ktname[MAXPATHLEN+sizeof("WRFILE:")+1];
+    krb5_error_code retval = 0;
+
+    strcpy(ktname, "WRFILE:");
+    if (strlen (name) >= MAXPATHLEN)
+	return ENAMETOOLONG;
+    strncat (ktname, name, MAXPATHLEN);
+    retval = krb5_kt_resolve(context, ktname, &kt);
+    if (retval)
+	return retval;
+    for (lp = list; lp; lp = lp->next) {
+	retval = krb5_kt_add_entry(context, kt, lp->entry);
+	if (retval)
+	    break;
+    }
+    krb5_kt_close(context, kt);
+    return retval;
+}
+
+#ifdef KRB5_KRB4_COMPAT
+/*
+ * getstr() takes a file pointer, a string and a count.  It reads from
+ * the file until either it has read "count" characters, or until it
+ * reads a null byte.  When finished, what has been read exists in the
+ * given string "s".  If "count" characters were actually read, the
+ * last is changed to a null, so the returned string is always null-
+ * terminated.  getstr() returns the number of characters read,
+ * including the null terminator.
+ */
+
+static int getstr(fp, s, n)
+    FILE *fp;
+    register char *s;
+    int n;
+{
+    register int count = n;
+    while (fread(s, 1, 1, fp) > 0 && --count)
+        if (*s++ == '\0')
+            return (n - count);
+    *s = '\0';
+    return (n - count);
+}
+
+/*
+ * Read in a named krb4 srvtab and append to list.  Allocate new list
+ * if needed.
+ */
+krb5_error_code ktutil_read_srvtab(context, name, list)
+    krb5_context context;
+    char *name;
+    krb5_kt_list *list;
+{
+    krb5_kt_list lp = NULL, tail = NULL, back = NULL;
+    krb5_keytab_entry *entry;
+    krb5_error_code retval = 0;
+    char sname[SNAME_SZ];	/* name of service */
+    char sinst[INST_SZ];	/* instance of service */
+    char srealm[REALM_SZ];	/* realm of service */
+    unsigned char kvno;		/* key version number */
+    des_cblock key;
+    FILE *fp;
+
+    if (*list) {
+	/* point lp at the tail of the list */
+	for (lp = *list; lp->next; lp = lp->next);
+	back = lp;
+    }
+    fp = fopen(name, "r");
+    if (!fp)
+	return EIO;
+    for (;;) {
+	entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry));
+	if (!entry) {
+	    retval = ENOMEM;
+	    break;
+	}
+	memset((char *)entry, 0, sizeof (*entry));
+	memset(sname, 0, sizeof (sname));
+	memset(sinst, 0, sizeof (sinst));
+	memset(srealm, 0, sizeof (srealm));
+	if (!(getstr(fp, sname, SNAME_SZ) > 0 &&
+	      getstr(fp, sinst, INST_SZ) > 0 &&
+	      getstr(fp, srealm, REALM_SZ) > 0 &&
+	      fread(&kvno, 1, 1, fp) > 0 &&
+	      fread((char *)key, sizeof (key), 1, fp) > 0))
+	    break;
+	entry->magic = KV5M_KEYTAB_ENTRY;
+	entry->timestamp = 0;	/* XXX */
+	entry->vno = kvno;
+	retval = krb5_425_conv_principal(context,
+					 sname, sinst, srealm,
+					 &entry->principal);
+	if (retval)
+	    break;
+	entry->key.magic = KV5M_KEYBLOCK;
+	entry->key.enctype = ENCTYPE_DES_CBC_CRC;
+	entry->key.length = sizeof (key);
+	entry->key.contents = (krb5_octet *)malloc(sizeof (key));
+	if (!entry->key.contents) {
+	    retval = ENOMEM;
+	    break;
+	}
+	memcpy((char *)entry->key.contents, (char *)key, sizeof (key));
+	if (!lp) {		/* if list is empty, start one */
+	    lp = (krb5_kt_list)malloc(sizeof (*lp));
+	    if (!lp) {
+		retval = ENOMEM;
+		break;
+	    }
+	} else {
+	    lp->next = (krb5_kt_list)malloc(sizeof (*lp));
+	    if (!lp->next) {
+		retval = ENOMEM;
+		break;
+	    }
+	    lp = lp->next;
+	}
+	lp->next = NULL;
+	lp->entry = entry;
+	if (!tail)
+	    tail = lp;
+    }
+    if (entry) {
+	if (entry->magic == KV5M_KEYTAB_ENTRY)
+	    krb5_kt_free_entry(context, entry);
+	free((char *)entry);
+    }
+    if (retval) {
+	ktutil_free_kt_list(context, tail);
+	tail = NULL;
+	if (back)
+	    back->next = NULL;
+    }
+    if (!*list)
+	*list = tail;
+    fclose(fp);
+    return retval;
+}
+
+/*
+ * Writes a kt_list out to a krb4 srvtab file.  Note that it first
+ * prunes the kt_list so that it won't contain any keys that are not
+ * the most recent, and ignores keys that are not ENCTYPE_DES.
+ */
+krb5_error_code ktutil_write_srvtab(context, list, name)
+    krb5_context context;
+    krb5_kt_list list;
+    char *name;
+{
+    krb5_kt_list lp, lp1, prev, pruned = NULL;
+    krb5_error_code retval = 0;
+    FILE *fp;
+    char sname[SNAME_SZ];
+    char sinst[INST_SZ];
+    char srealm[REALM_SZ];
+
+    /* First do heinous stuff to prune the list. */
+    for (lp = list; lp; lp = lp->next) {
+	if ((lp->entry->key.enctype != ENCTYPE_DES_CBC_CRC) &&
+	    (lp->entry->key.enctype != ENCTYPE_DES_CBC_MD5) &&
+	    (lp->entry->key.enctype != ENCTYPE_DES_CBC_MD4) &&
+	    (lp->entry->key.enctype != ENCTYPE_DES_CBC_RAW))
+	    continue;
+
+	for (lp1 = pruned; lp1; prev = lp1, lp1 = lp1->next) {
+	    /* Hunt for the current principal in the pruned list */
+	    if (krb5_principal_compare(context,
+				       lp->entry->principal,
+				       lp1->entry->principal))
+		    break;
+	}
+	if (!lp1) {		/* need to add entry to tail of pruned list */
+	    if (!pruned) {
+		pruned = (krb5_kt_list) malloc(sizeof (*pruned));
+		if (!pruned)
+		    return ENOMEM;
+		memset((char *) pruned, 0, sizeof(*pruned));
+		lp1 = pruned;
+	    } else {
+		prev->next
+		    = (krb5_kt_list) malloc(sizeof (*pruned));
+		if (!prev->next) {
+		    retval = ENOMEM;
+		    goto free_pruned;
+		}
+		memset((char *) prev->next, 0, sizeof(*pruned));
+		lp1 = prev->next;
+	    }
+	    lp1->entry = lp->entry;
+	} else {
+	    /* This heuristic should be roughly the same as in the
+	       keytab-reading code in libkrb5.  */
+	    int offset = 0;
+	    if (lp1->entry->vno > 240 || lp->entry->vno > 240) {
+		offset = 128;
+	    }
+#define M(X) (((X) + offset) % 256)
+	    if (M(lp1->entry->vno) < M(lp->entry->vno))
+		/* Check if lp->entry is newer kvno; if so, update */
+		lp1->entry = lp->entry;
+	}
+    }
+    umask(0077); /*Changing umask for all of ktutil is OK
+		  * We don't ever write out anything that should use
+		  * default umask.*/
+    fp = fopen(name, "w");
+    if (!fp) {
+	retval = EIO;
+	goto free_pruned;
+    }
+    for (lp = pruned; lp; lp = lp->next) {
+	unsigned char  kvno;
+	kvno = (unsigned char) lp->entry->vno;
+	retval = krb5_524_conv_principal(context,
+					 lp->entry->principal,
+					 sname, sinst, srealm);
+	if (retval)
+	    break;
+	fwrite(sname, strlen(sname) + 1, 1, fp);
+	fwrite(sinst, strlen(sinst) + 1, 1, fp);
+	fwrite(srealm, strlen(srealm) + 1, 1, fp);
+	fwrite((char *)&kvno, 1, 1, fp);
+	fwrite((char *)lp->entry->key.contents,
+	       sizeof (des_cblock), 1, fp);
+    }
+    fclose(fp);
+ free_pruned:
+    /*
+     * Loop over and free the pruned list; don't use free_kt_list
+     * because that kills the entries.
+     */
+    for (lp = pruned; lp;) {
+	prev = lp;
+	lp = lp->next;
+	free((char *)prev);
+    }
+    return retval;
+}
+#endif /* KRB5_KRB4_COMPAT */
diff --git a/mechglue/src/kadmin/passwd/ChangeLog b/mechglue/src/kadmin/passwd/ChangeLog
new file mode 100644
index 000000000..dec816422
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/ChangeLog
@@ -0,0 +1,178 @@
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	Novell merge.
+	* kpasswd.c:
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd_strings.et: Remove trailing colon, as new implementation
+	of krb5_read_password() appends it.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+Mon Feb 26 13:13:21 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* kpasswd.c, tty_kpasswd.c, xm_kpasswd.c: Compiler warning
+ 	clenups. Use const when apropriate, remove assignments in
+ 	conditionals, remove unnecessary casts.
+
+	* kpasswd.h: New file with prototypes of functions used in
+ 	different files.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* tty_kpasswd.c (read_old_password): Argument pwsize changed to
+	unsigned int.
+
+2000-05-08  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* xm_kpasswd.c (motif_com_err): Don't overflow buffer "buf".
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 18 15:56:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trialing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Thu Feb 12 10:22:47 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Remove unused NetBSD kludge to prevent use of
+		USE_KDB5_LIBRARY, since these macros are obsolete.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Removed use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jan 30 15:29:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove install rules.
+
+Wed Feb  5 22:59:43 1997  Tom Yu  <tlyu@mit.edu>
+
+	* unit-test/configure.in: Tweak TCL_LIB -> TCL_LIBS.
+
+Tue Feb  4 21:06:23 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Wed Nov 27 13:50:03 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* configure.in: Link against kdb5 explicitly on all systems except
+ 		BSD systems, due to hairy shared library issues.  [PR#257]
+ 		n.b., this is only a short-term fix for the 1.0 release.
+  		The correct long-term fix is to not require kadm5 clients
+ 		to need to link against libkdb5 at all.
+	
+Fri Nov 22 18:42:02 1996  Sam Hartman  <hartmans@planet-zorp.MIT.EDU>
+
+	* configure.in: Do not link against kdb5 because this causes
+ 	NetBSD getpwuid to fail. [228]
+
+	* kpasswd.c (kpasswd): Remove cast from uid_t to int. [228]
+
+Wed Nov 20 16:00:49 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* unit-test/Makefile.in (unit-test-): warn more loudly about unrun
+ 	tests
+
+Wed Nov 13 19:23:15 1996  Tom Yu  <tlyu@mit.edu>
+
+	* unit-test/Makefile.in (clean): Remove logfiles.
+
+Sun Nov 10 09:40:48 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in, configure.in: Check for Perl, tcl, and runtest and
+	 	only run tests if present.
+	
+Thu Sep 26 17:50:23 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* unit-test/Makefile.in, unit-test/kpasswd.0/principal.exp: use
+ 	whoami instead of user (USER princ now created by init_db)
+
+Fri Sep 20 17:32:19 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* configure.in: add unit-test subdirectory
+
+	* unit-test/: create configure.in and Makefile.in
+	
+Tue Sep 10 14:17:45 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.M: remove ".so man1/header.doc"
+
+Sat Sep  7 02:13:32 1996  Sam Hartman  <hartmans@planet-zorp.MIT.EDU>
+
+	* Makefile.in (install): Fix BINDIR to be CLIENT_BINDIR
+
+Fri Aug 23 14:17:42 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (install): Install in bin not sbin.
+
+Thu Aug 15 19:30:18 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add USE_KDB5_LIBRARY to pick up -ldb.  Recent
+ 		changes to db-ndbm.h and k5-int.h cause ndbm.h to no
+ 		longer be included, which means that the dbm_error and
+ 		dbm_clearerr are no longer necessarily macros (as they
+ 		often are in ndbm.h), so must be pulled in from libdb.
+
+Mon Aug 12 12:01:28 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* configure.in, Makefile.in: don't build kpasswd.local (not really
+ 	needed)
+
+Tue Aug  6 11:35:45 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* kpasswd.c (kpasswd): call ovsec_kadm_init with
+		KADM5_CHANGEPW_SERVICE so that ovsec principals don't need
+		to exist in the db.
+
+Mon Jul 22 04:07:02 1996  Marc Horowitz  <marc@mit.edu>
+
+	* tty_kpasswd.c: main returns int, not void
+
+Thu Jul 18 19:46:24 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: removed ET_RULES, replaced with AC_PROG_AWK
+
+Wed Jul 10 01:28:12 1996  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in, configure.in: added autoconf support
+
+Tue Jul  9 15:03:13 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kpasswd.c, tty_kpasswd.c, xm_kpasswd.c: renamed
+ 	<ovsec_admin/foo.h> to <kadm5/foo.h>
+
+	* configure.in (CONFIG_DIRS): build the subdirs for the new admin
+ 	system, not the old one.
+
diff --git a/mechglue/src/kadmin/passwd/Kpasswd b/mechglue/src/kadmin/passwd/Kpasswd
new file mode 100644
index 000000000..a7ec03161
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/Kpasswd
@@ -0,0 +1,46 @@
+*xm_ovpasswd.title:		PW-CHG-GUI
+*form.shadowThickness:		2
+
+*foreground:			black
+*background:			grey80
+*topShadowColor:		grey95
+*bottomShadowColor:		grey20
+*fontList:			-*-helvetica-medium-r-*-*-14-*
+*main_lbl.fontList:		-*-helvetica-bold-r-*-*-14-*
+*XmForm.Spacing:		5
+
+*main_lbl.labelString:		Changing password.
+*old_lbl.labelString:		Old password:
+*new_lbl.labelString:		New password:
+*again_lbl.labelString:		New password (again):
+*sep.leftOffset:		0
+*sep.rightOffset:		0
+*Quit.labelString:		Quit
+*Help.labelString:		Help
+
+*main_lbl.alignment:		ALIGNMENT_CENTER
+*lbl_form*alignment:		ALIGNMENT_END
+*scroll_win.shadowThickness:	0
+
+*scroll_text.value:		\
+Enter your old password below, and press return.  You will not be able to see what you\n\
+are typing.  After correctly entering your old password, you will be prompted twice for\n\
+your new password.  Other messages and directions will appear in this space as necessary.
+*scroll_text.rows:			5
+*scroll_text.columns:			66
+*scroll_text.scrollHorizontal:		FALSE
+*scroll_text.cursorPositionVisible:	FALSE
+
+*help_dlg_popup.title:		PW-CHG-GUI Help
+*help_dlg.messageString:	\
+Welcome to the Kerberos password changing GUI.\n\
+\n\
+In the main window, enter your old password when prompted.  After verifying\n\
+your old password, the policy governing your password will be displayed, and\n\
+you will be prompted for a new password.  You will then be asked to enter it\n\
+a second time, to make sure you have not made any typos.  Assuming that\n\
+your new password complies with your password policy, you should receive\n\
+an acknowledgement that your password has been changed.\n\
+\n\
+If an error occurs, the process will start over from the beginning.  You may\n\
+exit the application at any time by pressing the "Quit" button.
diff --git a/mechglue/src/kadmin/passwd/Makefile.in b/mechglue/src/kadmin/passwd/Makefile.in
new file mode 100644
index 000000000..6d5f6aa86
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/Makefile.in
@@ -0,0 +1,24 @@
+thisconfigdir=./..
+myfulldir=kadmin/passwd
+mydir=passwd
+BUILDTOP=$(REL)..$(S)..
+LOCALINCLUDES = -I.
+DEFINES = -DUSE_KADM5_API_VERSION=1
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+LOCAL_SUBDIRS = unit-test
+
+PROG = kpasswd
+OBJS = tty_kpasswd.o kpasswd.o kpasswd_strings.o
+
+all:: $(PROG)
+
+kpasswd_strings.c kpasswd_strings.h: $(srcdir)/kpasswd_strings.et
+
+$(OBJS): kpasswd_strings.h
+
+$(PROG): $(OBJS) $(KADMCLNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $(PROG) $(OBJS) $(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
+
+clean::
+	$(RM) kpasswd_strings.c kpasswd_strings.h $(PROG) $(OBJS)
diff --git a/mechglue/src/kadmin/passwd/kpasswd.M b/mechglue/src/kadmin/passwd/kpasswd.M
new file mode 100644
index 000000000..185c1f595
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/kpasswd.M
@@ -0,0 +1,70 @@
+.\" kadmin/kpasswd/kpasswd.M
+.\" 
+.\" Copyright 1995 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH KPASSWD 1
+.SH NAME
+kpasswd \- change a user's Kerberos password
+.SH SYNOPSIS
+.B kpasswd
+[\fIprincipal\fP]
+.SH DESCRIPTION
+.PP
+The
+.I kpasswd
+command is used to change a Kerberos principal's password.
+.I Kpasswd
+prompts for the current Kerberos password, which is used to obtain a 
+.B changepw
+ticket from the
+.SM KDC
+for the user's Kerberos realm.  If
+.B kpasswd
+successfully obtains the
+.B changepw
+ticket, the user is prompted twice for the new password, and the
+password is changed.
+.PP
+If the principal is governed by a policy that specifies the length and/or
+number of character classes required in the new password, the new
+password must conform to the policy.  (The five character classes are
+lower case, upper case, numbers, punctuation, and all other characters.)
+.SH OPTIONS
+.TP
+.I principal
+change the password for the Kerberos principal
+.IR principal .
+Otherwise, the principal is derived from the identity of the user
+invoking the
+.I kpasswd
+command.
+.SH FILES
+.TP "\w'/tmp/tkt_kadm_[pid]'u"
+/tmp/tkt_kadm_[pid]
+temporary credentials cache for the lifetime of the password changing
+operation.  ([pid] is the process-ID of the kpasswd process.)
+.SH SEE ALSO
+kadmin(8), kadmind(8)
+.SH BUGS
+If
+.B kpasswd
+is suspended, the changepw tickets may not be destroyed.
diff --git a/mechglue/src/kadmin/passwd/kpasswd.c b/mechglue/src/kadmin/passwd/kpasswd.c
new file mode 100644
index 000000000..ca47fca5b
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/kpasswd.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved.
+ * 
+ * $Header$
+ *
+ *
+ */
+
+static char rcsid[] = "$Id$";
+
+#include <kadm5/admin.h>
+#include <krb5.h>
+
+#include "kpasswd_strings.h"
+#define string_text error_message
+
+#include "kpasswd.h"
+
+#include <stdio.h>
+#include <pwd.h>
+#include <string.h>
+
+extern char *whoami;
+
+
+#define MISC_EXIT_STATUS 6
+
+/*
+ * Function: kpasswd
+ *
+ * Purpose: Initialize and call lower level routines to change a password
+ *
+ * Arguments:
+ *
+ *	context		(r) krb5_context to use
+ *	argc/argv	(r) principal name to use, optional
+ *	read_old_password (f) function to read old password
+ *	read_new_password (f) function to read new and change password
+ *	display_intro_message (f) function to display intro message
+ *	whoami		(extern) argv[0]
+ *	
+ * Returns:
+ *                      exit status of 0 for success
+ *			1 principal unknown
+ *			2 old password wrong
+ *			3 cannot initialize admin server session
+ *			4 new passwd mismatch or error trying to change pw
+ *                      5 password not typed
+ *                      6 misc error
+ *                      7 incorrect usage
+ *      
+ * Requires:
+ *	Passwords cannot be more than 255 characters long.
+ *      
+ * Effects:
+ *
+ * If argc is 2, the password for the principal specified in argv[1]
+ * is changed; otherwise, the principal of the default credential
+ * cache or username is used.  display_intro_message is called with
+ * the arguments KPW_STR_CHANGING_PW_FOR and the principal name.
+ * read_old_password is then called to prompt for the old password.
+ * The admin system is then initialized, the principal's policy
+ * retrieved and explained, if appropriate, and finally
+ * read_new_password is called to read the new password and change the
+ * principal's password (presumably ovsec_kadm_chpass_principal).
+ * admin system is de-initialized before the function returns.
+ *      
+ * Modifies:
+ *
+ * Changes the principal's password.
+ *
+ */
+int
+kpasswd(context, argc, argv)
+   krb5_context context;
+   int argc;
+   char *argv[];
+{
+  int code;
+  krb5_ccache ccache = NULL;
+  krb5_principal princ = 0;
+  char *princ_str;
+  struct passwd *pw = 0;
+  unsigned int pwsize;
+  char password[255];  /* I don't really like 255 but that's what kinit uses */
+  char msg_ret[1024], admin_realm[1024];
+  ovsec_kadm_principal_ent_t principal_entry = NULL;
+  ovsec_kadm_policy_ent_t policy_entry = NULL;
+  void *server_handle;
+
+  if (argc > 2) {
+      com_err(whoami, KPW_STR_USAGE, 0);
+      return(7);
+      /*NOTREACHED*/
+    }
+
+  /************************************
+   *  Get principal name to change    * 
+   ************************************/
+
+  /* Look on the command line first, followed by the default credential
+     cache, followed by defaulting to the Unix user name */
+
+  if (argc == 2)
+    princ_str = strdup(argv[1]);
+  else {
+    code = krb5_cc_default(context, &ccache);
+    /* If we succeed, find who is in the credential cache */
+    if (code == 0) {
+      /* Get default principal from cache if one exists */
+      code = krb5_cc_get_principal(context, ccache, &princ);
+      /* if we got a principal, unparse it, otherwise get out of the if
+	 with an error code */
+      (void) krb5_cc_close(context, ccache);
+      if (code == 0) {
+	code = krb5_unparse_name(context, princ, &princ_str);
+	if (code != 0) {
+	  com_err(whoami,  code, string_text(KPW_STR_UNPARSE_NAME));
+	  return(MISC_EXIT_STATUS);
+	}
+      }
+    }
+
+    /* this is a crock.. we want to compare against */
+    /* "KRB5_CC_DOESNOTEXIST" but there is no such error code, and */
+    /* both the file and stdio types return FCC_NOFILE.  If there is */
+    /* ever another ccache type (or if the error codes are ever */
+    /* fixed), this code will have to be updated. */
+    if (code && code != KRB5_FCC_NOFILE) {
+      com_err(whoami, code, string_text(KPW_STR_WHILE_LOOKING_AT_CC));
+      return(MISC_EXIT_STATUS);
+    }
+
+    /* if either krb5_cc failed check the passwd file */
+    if (code != 0) {
+      pw = getpwuid( getuid());
+      if (pw == NULL) {
+	com_err(whoami, 0, string_text(KPW_STR_NOT_IN_PASSWD_FILE));
+	return(MISC_EXIT_STATUS);
+      }
+      princ_str = strdup(pw->pw_name);
+    }
+  }    
+  
+  display_intro_message(string_text(KPW_STR_CHANGING_PW_FOR), princ_str);
+
+  /* Need to get a krb5_principal, unless we started from with one from
+     the credential cache */
+
+  if (! princ) {
+      code = krb5_parse_name (context, princ_str, &princ);
+      if (code != 0) {
+	  com_err(whoami, code, string_text(KPW_STR_PARSE_NAME), princ_str);
+	  free(princ_str);
+	  return(MISC_EXIT_STATUS);
+      }
+  }
+  
+  pwsize = sizeof(password);
+  code = read_old_password(context, password, &pwsize);
+
+  if (code != 0) {
+    memset(password, 0, sizeof(password));
+    com_err(whoami, code, string_text(KPW_STR_WHILE_READING_PASSWORD));
+    krb5_free_principal(context, princ);
+    free(princ_str);
+    return(MISC_EXIT_STATUS);
+  }
+  if (pwsize == 0) {
+    memset(password, 0, sizeof(password));
+    com_err(whoami, 0, string_text(KPW_STR_NO_PASSWORD_READ));
+    krb5_free_principal(context, princ);
+    free(princ_str);
+    return(5);
+  }
+
+  admin_realm[0] = '\0';
+  strncat(admin_realm, krb5_princ_realm(context, princ)->data, 
+	  krb5_princ_realm(context, princ)->length);
+
+  code = ovsec_kadm_init(princ_str, password, KADM5_CHANGEPW_SERVICE,
+			 admin_realm /* we probably should take a -r */
+			             /* someday */,
+			 OVSEC_KADM_STRUCT_VERSION,
+			 OVSEC_KADM_API_VERSION_1,
+			 NULL,
+			 &server_handle);
+  if (code != 0) {
+    if (code == OVSEC_KADM_BAD_PASSWORD)
+      com_err(whoami, 0, string_text(KPW_STR_OLD_PASSWORD_INCORRECT));
+    else 
+      com_err(whoami, 0, string_text(KPW_STR_CANT_OPEN_ADMIN_SERVER), admin_realm,
+	      error_message(code));
+    krb5_free_principal(context, princ);
+    free(princ_str);
+    return((code == OVSEC_KADM_BAD_PASSWORD)?2:3);
+  }
+
+  /* Explain policy restrictions on new password if any. */
+  /* Note: copy of this exists in login (kverify.c/get_verified_in_tkt). */
+
+  code = ovsec_kadm_get_principal(server_handle, princ, &principal_entry);
+  if (code != 0) {
+    com_err(whoami, 0,
+	    string_text((code == OVSEC_KADM_UNK_PRINC)
+			? KPW_STR_PRIN_UNKNOWN : KPW_STR_CANT_GET_POLICY_INFO),
+	    princ_str);
+    krb5_free_principal(context, princ);
+    free(princ_str);
+    (void) ovsec_kadm_destroy(server_handle);
+    return((code == OVSEC_KADM_UNK_PRINC) ? 1 : MISC_EXIT_STATUS);
+  }
+  if ((principal_entry->aux_attributes & OVSEC_KADM_POLICY) != 0) {
+    code = ovsec_kadm_get_policy(server_handle,
+				 principal_entry->policy, &policy_entry);
+    if (code != 0) {
+      /* doesn't matter which error comes back, there's no nice recovery
+	 or need to differentiate to the user */
+      com_err(whoami, 0,
+	      string_text(KPW_STR_CANT_GET_POLICY_INFO), princ_str);
+      (void) ovsec_kadm_free_principal_ent(server_handle, principal_entry);
+      krb5_free_principal(context, princ);
+      free(princ_str);
+      (void) ovsec_kadm_destroy(server_handle);
+      return(MISC_EXIT_STATUS);
+    }
+    com_err(whoami, 0, string_text(KPW_STR_POLICY_EXPLANATION),
+	    princ_str, principal_entry->policy,
+	    policy_entry->pw_min_length, policy_entry->pw_min_classes);
+
+    code = ovsec_kadm_free_principal_ent(server_handle, principal_entry);
+    if (code) {
+	(void) ovsec_kadm_free_policy_ent(server_handle, policy_entry);
+	krb5_free_principal(context, princ);
+	free(princ_str);
+	com_err(whoami, code, string_text(KPW_STR_WHILE_FREEING_PRINCIPAL));
+	(void) ovsec_kadm_destroy(server_handle);
+	return(MISC_EXIT_STATUS);
+    }
+
+    code = ovsec_kadm_free_policy_ent(server_handle, policy_entry);
+    if (code) {
+	krb5_free_principal(context, princ);
+	free(princ_str);
+	com_err(whoami, code, string_text(KPW_STR_WHILE_FREEING_POLICY));
+	(void) ovsec_kadm_destroy(server_handle);
+	return(MISC_EXIT_STATUS);
+    }
+  }
+  else {
+    /* kpasswd *COULD* output something here to encourage the choice
+       of good passwords, in the absence of an enforced policy. */
+      code = ovsec_kadm_free_principal_ent(server_handle, principal_entry);
+      if (code) {
+	  krb5_free_principal(context, princ);
+	  free(princ_str);
+	  com_err(whoami, code, string_text(KPW_STR_WHILE_FREEING_PRINCIPAL));
+	  (void) ovsec_kadm_destroy(server_handle);
+	  return(MISC_EXIT_STATUS);
+      }
+  }
+
+  pwsize = sizeof(password);
+  code = read_new_password(server_handle, password, &pwsize, msg_ret, princ);
+  memset(password, 0, sizeof(password));
+
+  if (code)
+    com_err(whoami, 0, msg_ret);
+
+  krb5_free_principal(context, princ);
+  free(princ_str);
+
+  (void) ovsec_kadm_destroy(server_handle);
+  
+  if (code == KRB5_LIBOS_CANTREADPWD)
+     return(5);
+  else if (code)
+     return(4);
+  else
+     return(0);
+}
diff --git a/mechglue/src/kadmin/passwd/kpasswd.h b/mechglue/src/kadmin/passwd/kpasswd.h
new file mode 100644
index 000000000..577ab386f
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/kpasswd.h
@@ -0,0 +1,46 @@
+/*
+ * kadmin/passwd/kpasswd.h
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Prototypes for the kpasswd program callback functions.
+ */
+
+#ifndef __KPASSWD_H__
+#define __KPASSWD_H__
+
+int kpasswd(krb5_context context, int argc, char *argv[]);
+
+long read_old_password(krb5_context context, char *password, 
+		       unsigned int *pwsize);
+
+long read_new_password(void *server_handle, char *password, 
+		       unsigned int *pwsize, char *msg_ret, 
+		       krb5_principal princ);
+
+void display_intro_message(const char *fmt_string, const char *arg_string);
+
+#endif /* __KPASSWD_H__ */
+
+
diff --git a/mechglue/src/kadmin/passwd/kpasswd_strings.et b/mechglue/src/kadmin/passwd/kpasswd_strings.et
new file mode 100644
index 000000000..7e826d270
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/kpasswd_strings.et
@@ -0,0 +1,76 @@
+#
+# Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved.
+#
+# String table of messages for kpasswd
+
+
+error_table kpws
+
+# /* M1 */
+error_code KPW_STR_USAGE, "Usage: kpasswd [principal_name]."
+
+error_code KPW_STR_PRIN_UNKNOWN,
+	"Kerberos principal name %s is not recognized."
+#       /* <name> */
+
+# /* M2 */
+error_code KPW_STR_WHILE_LOOKING_AT_CC,
+	"while reading principal name from credential cache."
+
+# /* M4 */ 
+error_code KPW_STR_OLD_PASSWORD_INCORRECT,
+	"Old Kerberos password is incorrect. Please try again."
+
+# /* M5 */
+error_code KPW_STR_CANT_OPEN_ADMIN_SERVER,
+"Cannot establish a session with the Kerberos administrative server for\n\
+realm %s. %s."
+# /* <realm-name>, <Specific error message from admin server library>. */
+
+# /* M6 */
+error_code KPW_STR_NEW_PASSWORD_MISMATCH,
+	"New passwords do not match - password not changed.\n"
+
+# /* M7 */
+error_code KPW_STR_PASSWORD_CHANGED, "Kerberos password changed.\n"
+
+# /* M13 */
+error_code KPW_STR_PASSWORD_NOT_CHANGED, "Password not changed."
+
+error_code KPW_STR_PARSE_NAME, "when parsing name %s."
+error_code KPW_STR_UNPARSE_NAME, "when unparsing name."
+error_code KPW_STR_NOT_IN_PASSWD_FILE,	"Unable to identify user from password file."
+
+# /* M3 */
+error_code KPW_STR_CHANGING_PW_FOR, "Changing password for %s."
+# /* principal@realm */
+
+error_code KPW_STR_OLD_PASSWORD_PROMPT, "Old password"
+error_code KPW_STR_WHILE_READING_PASSWORD, "while reading new password."
+
+# /* M4 */
+error_code KPW_STR_NO_PASSWORD_READ,
+"You must type a password. Passwords must be at least one character long."
+
+# /* M14 */
+error_code KPW_STR_WHILE_TRYING_TO_CHANGE, "while trying to change password."
+
+error_code KPW_STR_WHILE_DESTROYING_ADMIN_SESSION,
+"while closing session with admin server and destroying tickets."
+
+error_code KPW_STR_WHILE_FREEING_PRINCIPAL,
+"while freeing admin principal entry"
+
+error_code KPW_STR_WHILE_FREEING_POLICY,
+"while freeing admin policy entry"
+
+error_code KPW_STR_CANT_GET_POLICY_INFO,
+"Could not get password policy information for principal %s."
+# /* principal@realm */
+
+error_code KPW_STR_POLICY_EXPLANATION,
+"%s's password is controlled by the policy %s, which\nrequires a minimum of %u characters from at least %u classes (the five classes\nare lowercase, uppercase, numbers, punctuation, and all other characters)."
+# /* principal_name policy_name min_length min_classes */
+
+end
+
diff --git a/mechglue/src/kadmin/passwd/tty_kpasswd.c b/mechglue/src/kadmin/passwd/tty_kpasswd.c
new file mode 100644
index 000000000..189409140
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/tty_kpasswd.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved.
+ * 
+ * $Header$
+ *
+ *
+ */
+
+static char rcsid[] = "$Id$";
+
+#include <kadm5/admin.h>
+#include <krb5.h>
+
+#include "kpasswd_strings.h"
+#define string_text error_message
+
+#include "kpasswd.h"
+#include <stdio.h>
+#include <pwd.h>
+#include <string.h>
+
+char *whoami;
+
+void display_intro_message(fmt_string, arg_string)
+     const char *fmt_string;
+     const char *arg_string;
+{
+  com_err(whoami, 0, fmt_string, arg_string);
+}
+
+long read_old_password(context, password, pwsize)
+     krb5_context context;
+     char *password;
+     unsigned int *pwsize;
+{
+  long code = krb5_read_password(context,
+			 string_text(KPW_STR_OLD_PASSWORD_PROMPT),  
+			 0, password, pwsize);
+  return code;
+}
+
+long read_new_password(server_handle, password, pwsize, msg_ret, princ)
+     void *server_handle;
+     char *password;
+     unsigned int *pwsize;
+     char *msg_ret;
+     krb5_principal princ;
+{
+  return (ovsec_kadm_chpass_principal_util(server_handle, princ, NULL, 
+					   NULL /* don't need new pw back */,
+					   msg_ret));
+}
+
+
+/*
+ * main() for tty version of kpasswd.c
+ */
+int
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+  krb5_context context;
+  int retval;
+
+  whoami = (whoami = strrchr(argv[0], '/')) ? whoami + 1 : argv[0];
+
+  retval = krb5_init_context(&context);
+  if (retval) {
+       com_err(whoami, retval, "initializing krb5 context");
+       exit(retval);
+  }
+  initialize_kpws_error_table();
+
+  retval = kpasswd(context, argc, argv);
+
+  if (!retval)
+    printf(string_text(KPW_STR_PASSWORD_CHANGED));
+
+  exit(retval);
+}
diff --git a/mechglue/src/kadmin/passwd/unit-test/ChangeLog b/mechglue/src/kadmin/passwd/unit-test/ChangeLog
new file mode 100644
index 000000000..a7b9083c6
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/unit-test/ChangeLog
@@ -0,0 +1,62 @@
+2004-02-16  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (unit-test-body): Add PRIOCNTL_HACK.
+
+	* config/unix.exp: Add PRIOCNTL_HACK.
+
+2003-05-09  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.0/changing.exp: Replace ovpasswd with kpasswd.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-11-02  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.0/changing.exp: 
+	* lib/helpers.exp: Make checks for password prompts more lenient.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2000-02-23  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.0/changing.exp: Add a sleep to avoid a race with the
+	setup script.  If this isn't here, it is possible that the initial
+	change of pol2's password may happen too soon.
+
+2000-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* lib/helpers.exp: Fix to call kinit and kdestroy with the -5 flag
+	to accomodate new program behavior.
+
+2000-01-24  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.0/changing.exp: Fix y2k bug.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 18 15:57:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
diff --git a/mechglue/src/kadmin/passwd/unit-test/Makefile.in b/mechglue/src/kadmin/passwd/unit-test/Makefile.in
new file mode 100644
index 000000000..5445a2811
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/unit-test/Makefile.in
@@ -0,0 +1,27 @@
+thisconfigdir=./../..
+myfulldir=kadmin/passwd/unit-test
+mydir=passwd/unit-test
+BUILDTOP=$(REL)..$(S)..$(S)..
+check unit-test:: unit-test-@DO_TEST@
+
+unit-test-:
+	@echo "+++"
+	@echo "+++ WARNING: kpasswd unit tests not run."
+	@echo "+++ Either tcl, runtest, or Perl is unavailable."
+	@echo "+++"
+
+unit-test-ok:: unit-test-setup unit-test-body unit-test-cleanup
+
+unit-test-body::	
+	$(ENV_SETUP) $(RUNTEST) --tool kpasswd KPASSWD=../kpasswd \
+		KINIT=$(BUILDTOP)/clients/kinit/kinit \
+		KDESTROY=$(BUILDTOP)/clients/kdestroy/kdestroy \
+		PRIOCNTL_HACK=@PRIOCNTL_HACK@
+
+unit-test-setup::
+	$(ENV_SETUP) $(START_SERVERS)
+
+unit-test-cleanup::
+	$(ENV_SETUP) $(STOP_SERVERS)
+clean::
+	$(RM) dbg.log kpasswd.sum kpasswd.log
diff --git a/mechglue/src/kadmin/passwd/unit-test/config/unix.exp b/mechglue/src/kadmin/passwd/unit-test/config/unix.exp
new file mode 100644
index 000000000..bd8382e19
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/unit-test/config/unix.exp
@@ -0,0 +1,74 @@
+# Hack around Solaris 9 kernel race condition that causes last output
+# from a pty to get dropped.
+if { $PRIOCNTL_HACK } {
+    catch {exec priocntl -s -c FX -m 30 -p 30 -i pid [getpid]}
+    rename spawn oldspawn
+    proc spawn { args } {
+	upvar 1 spawn_id spawn_id
+	set newargs {}
+	set inflags 1
+	set eatnext 0
+	foreach arg $args {
+	    if { $arg == "-ignore" \
+		     || $arg == "-open" \
+		     || $arg == "-leaveopen" } {
+		lappend newargs $arg
+		set eatnext 1
+		continue
+	    }
+	    if [string match "-*" $arg] {
+		lappend newargs $arg
+		continue
+	    }
+	    if { $eatnext } {
+		set eatnext 0
+		lappend newargs $arg
+		continue
+	    }
+	    if { $inflags } {
+		set inflags 0
+		set newargs [concat $newargs {priocntl -e -c FX -p 0}]
+	    }
+	    lappend newargs $arg
+	}
+	set pid [eval oldspawn $newargs]
+	return $pid
+    }
+}
+
+#
+# kpasswd_version -- extract and print the version number of kpasswd
+#
+
+proc kpasswd_version {} {
+	global KPASSWD
+	catch "exec ident $KPASSWD" tmp
+	if [regexp {Id: kpasswd.c,v ([0-9]+\.[0-9]+)} $tmp \
+		dummy version] then {
+		clone_output "$KPASSWD version $version\n"
+	} else {
+		clone_output "$KPASSWD version <unknown>\n"
+	}
+}
+#
+# kpasswd_load -- loads the program
+#
+proc kpasswd_load {} {
+	#
+}
+
+# kpasswd_exit -- clean up and exit
+proc kpasswd_exit {} {
+	#
+}
+
+#
+# kpasswd_start -- start kpasswd running
+#
+proc kpasswd_start { args } {
+	global KPASSWD
+	global spawn_id
+
+	verbose "% $KPASSWD $args" 1
+	eval spawn $KPASSWD $args
+}
diff --git a/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/changing.exp b/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/changing.exp
new file mode 100644
index 000000000..740d7e62b
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/changing.exp
@@ -0,0 +1,105 @@
+#
+# $Id$
+#
+
+set timeout 15
+
+load_lib "helpers.exp"
+
+if [info exist env(DEBUG)] { debug 1 }
+
+#
+# Here are the tests
+#
+
+test_3pass {test2} {D.5: different new passwords} test2 test2 test2 foobar \
+	4 {New passwords do not match - password not changed.}
+
+test_3pass {test2} {D.7.5: empty/empty} test2 test2 {} {} \
+	5 {You must type a password.  Passwords must be at least one character long.}
+
+test_3pass {test2} {D.6: empty/non-empty} test2 test2 {} test2 \
+	4 {New passwords do not match - password not changed.}
+
+test_3pass {test2} {D.7: non-empty/empty} test2 test2 test2 {} \
+	4 {New passwords do not match - password not changed.}
+
+
+test_win {test1} {D.8: change password} test1 test1 newpass
+
+test_win {test1} {D.9: test changed password} test1 newpass test1
+
+mytest "D.22: No policy description was shown" test1 4 {
+	-re "Changing password for test1.*\\.$s+Old password:\[^\n\]*$"
+		{ send "test1\n" }
+} {
+	-re "$s+.*$s+.*$s+.*char.*classes.*"
+		{ myfail "policy description displayed" }
+	timeout { mypass }
+} {
+	-re "^$s+New password:\[^\n\]*$"
+		{ send "newpass\n" }
+} {
+	-re "^$s+New password \\(again\\):\[^\n\]*\$"
+		{ send "ssapwen\n" }
+} {
+	-re "$s+New passwords do not match - password not changed."
+		{ mypass }
+}
+
+test_3pass {pol1} {D.10: new password too short} pol1 pol111111 que que \
+	4 {New password is too short.  Please choose a password which is at least [0-9]+ characters long.}
+
+test_3pass {pol1} {D.13: too few char classes in new password} pol1 \
+	pol111111 123456789 123456789 \
+	4 {New password does not have enough character classes.  The character classes are: - lower-case letters, - upper-case letters, - digits, - punctuation, and - all other characters \(e.g., control characters\). Please choose a password with at least [0-9]+ character classes.}
+
+test_3pass {pol1} {D.14: new password in dictionary} pol1 \
+	pol111111 Discordianism Discordianism \
+	4 {New password was found in a dictionary of possible passwords and therefore may be easily guessed.  Please choose another password.  See the kpasswd man page for help in choosing a good password.}
+
+test_win {pol1} {successful change} pol1 pol111111 polAAAAAA
+# fail "successful change: XXXX password history is majorly broken"
+
+test_3pass {pol1} {D.11: new password same as old} pol1 \
+	polAAAAAA polAAAAAA polAAAAAA \
+	4 {New password was used previously.  Please choose a different password.}
+
+test_3pass {pol1} {D.12: new password in history} pol1 \
+	polAAAAAA pol111111 pol111111 \
+	4 {New password was used previously.  Please choose a different password.}
+
+mytest "D.18: Policy description was shown" pol1 4 {
+	-re "Changing password for pol1.*\\.$s+Old password:\[^\n\]*$"
+		{ send "polAAAAAA\n" }
+} {
+	-re "$s+.*$s+.*$s+.*8 char.*2 classes.*$s+New password:\[^\n\]*$"
+		{ send "newpass1234\n" }
+} {
+	-re "^$s+New password \\(again\\):\[^\n\]*$"
+		{ send "newpass4321\n" }
+} {
+	-re "$s+New passwords do not match - password not changed."
+		{ mypass }
+}
+
+# restore pol1's password to its initial value; see discussion in 
+# secure-kpasswd/2204 about secure-releng/2191 if you are confused
+test_win {pol1} {successful change} pol1 polAAAAAA polBBBBBB
+test_win {pol1} {successful change} pol1 polBBBBBB polCCCCCC
+test_win {pol1} {successful change} pol1 polCCCCCC pol111111
+
+verbose "(sleeping 30 seconds)"
+catch "exec sleep 30"
+
+test_win {pol2} {successful change} pol2 pol222222 polbbbbbb
+
+test_3pass {pol2} {D.15: too soon to change password} pol2 \
+	polbbbbbb pol222222 pol222222 \
+	4 {Password cannot be changed because it was changed too recently.  Please wait until .*[12][0-9][0-9][0-9] before you change it.  If you need to change your password before then, contact your system security administrator.}
+
+verbose "(sleeping 30 seconds)"
+catch "exec sleep 30"
+
+test_win {pol2} {password min life passed} pol2 polbbbbbb pol222222
+
diff --git a/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/connecting.exp b/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/connecting.exp
new file mode 100644
index 000000000..2cda17a6a
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/connecting.exp
@@ -0,0 +1,29 @@
+#
+# $Id$
+#
+
+set timeout 15
+
+load_lib "helpers.exp"
+
+if [info exist env(DEBUG)] { debug 1 }
+
+#
+# Here are the tests
+#
+
+test_initerr {test2} {C.4: empty old password (XXXX)} test2 {} \
+	5 {You must type a password.  Passwords must be at least one character long.}
+
+test_initerr {test2} {C.5: incorrect old password} test2 foobar \
+	2 "Old Kerberos password is incorrect. Please try again."
+
+# set timeout 60
+#
+#test_initerr {test2@SECURE-TEST-DEAD.OV.COM} {C.8: server up, daemon down} \
+#	test2 test2 \
+#	3 "" 
+#
+#test_initerr {test2@SECURE-TEST-DOWN.OV.COM} {C.8.5: server down} \
+#	test2 test2 \
+#	3 "${initerr_str}Cannot contact any KDC for requested realm"
diff --git a/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/principal.exp b/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/principal.exp
new file mode 100644
index 000000000..9cfff69f6
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/principal.exp
@@ -0,0 +1,60 @@
+#
+# $Id$
+#
+
+set timeout 15
+
+load_lib "helpers.exp"
+
+if [info exist env(DEBUG)] { debug 1 }
+
+#
+# Here are the tests
+#
+
+if {[info exists env(KRB5CCNAME)]} {
+	unset env(KRB5CCNAME)
+}
+kdestroy
+
+#### no principal specified
+
+if {[info exists env(USER)]} {
+    set whoami $env(USER)
+} else {
+    set whoami [exec whoami]
+}
+
+test_win {} {B.7: default nonexisting ccache(1)} $whoami $whoami newpass
+test_win {} {B.7: default nonexisting ccache(2)} $whoami newpass $whoami
+
+kinit test2 test2
+test_win {} {B.4: default existing cache containing existing principal} \
+	test2 test2 newpass
+kdestroy
+
+set env(KRB5CCNAME) FILE:/tmp/ovsec_adm_test_ccache
+kinit test2 newpass
+test_win {} {B.3: specified existing cache containing existing principal} \
+	test2 newpass test2
+kdestroy
+unset env(KRB5CCNAME)
+
+#### principal on command line
+
+#
+test_win {test2} {B.14: existing principal, no realm} test2 test2 newpass
+
+#
+test_initerr {bogus} {B.15, C.6: non-existent principal, no realm} bogus bogus \
+	3 "${initerr_str}Client not found in Kerberos database"
+
+#
+test_win {test2@SECURE-TEST.OV.COM} {B.16: existing principal, with realm} \
+	test2 newpass test2
+
+#
+test_initerr {bogus@SECURE-TEST.OV.COM} \
+	{B.17: non-existent principal, with realm} \
+	bogus bogus \
+	3 "${initerr_str}Client not found in Kerberos database"
diff --git a/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/usage.exp b/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/usage.exp
new file mode 100644
index 000000000..e132bab2f
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/unit-test/kpasswd.0/usage.exp
@@ -0,0 +1,26 @@
+#
+# $Id$
+#
+
+set timeout 15
+
+load_lib "helpers.exp"
+
+#
+# Here are the tests
+#
+
+mytest {A.1: two args} {foo bar} 7 {
+	-re {[a-z./]+passwd: Usage: [a-z./]+passwd \[principal_name\]} { mypass }
+}
+
+mytest {A.2: three args} {foo bar baz} 7 {
+	-re {[a-z./]+passwd: Usage: [a-z./]+passwd \[principal_name\]} { mypass }
+}
+
+set env(KRB5CCNAME) bogus_type:bogus_ccname
+mytest {B.5: malformed ccache name} {} 6 {
+	-re {[a-z./]+passwd: Unknown credential cache type while reading principal name from credential cache} { mypass }
+}
+unset env(KRB5CCNAME)
+
diff --git a/mechglue/src/kadmin/passwd/unit-test/lib/helpers.exp b/mechglue/src/kadmin/passwd/unit-test/lib/helpers.exp
new file mode 100644
index 000000000..25b71a20e
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/unit-test/lib/helpers.exp
@@ -0,0 +1,217 @@
+#
+# $Id$
+#
+
+global s
+set s "\[\r\n\t\ \]"
+
+if {[info commands exp_version] != {}} {
+	set exp_version_4 [regexp {^4} [exp_version]]
+} else {
+	set exp_version_4 [regexp {^4} [expect_version]]
+}
+
+# Backward compatibility until we're using expect 5 everywhere
+if {$exp_version_4} {
+	global wait_error_index wait_errno_index wait_status_index
+	set wait_error_index 0
+	set wait_errno_index 1
+	set wait_status_index 1
+} else {
+	set wait_error_index 2
+	set wait_errno_index 3
+	set wait_status_index 3
+}
+
+proc myfail { comment } {
+	global mytest_name
+	global mytest_status
+	wait
+	fail "$mytest_name: $comment"
+	set mytest_status 1
+}
+
+proc mypass {} {
+}
+
+##
+## When you expect on an id, and eof is detected, the spawn_id is closed.
+## It may be waited for, but calling expect or close on this id is an ERROR!
+##
+
+proc mytest { name kpargs status args } {
+	global spawn_id
+	global timeout
+	global mytest_name
+	global mytest_status
+	global wait_error_index wait_errno_index wait_status_index
+
+	verbose "starting test: $name"
+
+	set mytest_name "$name"
+
+	eval kpasswd_start $kpargs
+
+	# at the end, eof is success
+
+	lappend args { eof { if {[regexp "\[\r\n\]$" $expect_out(buffer)] == 0} { myfail "final status message not newline-terminated" } } }
+
+	# for each test argument....
+	# rep invariant:  when this foreach ends, the id is close'd, but
+	#   not wait'ed.
+
+	foreach test $args {
+		set mytest_status 0
+
+		# treat the arg as an expect parameter
+		# if failure, the process will be closed and waited.
+
+		uplevel 1 "expect {
+			$test
+			timeout { close; myfail \"timeout\"}
+			eof { myfail \"eof read before expected message string\" }
+		}"			
+
+		if {$mytest_status == 1} { return }
+	}
+
+	# at this point, the id is closed and we can wait on it.
+
+	set ret [wait]
+	verbose "% Exit $ret" 1
+	if {[lindex $ret $wait_error_index] == -1} {
+		fail "$name: wait returned error [lindex $ret $wait_errno_index]"
+	} else {
+		if { [lindex $ret $wait_status_index] == $status ||
+		     (($status<0) && ([lindex $ret $wait_status_index] == ($status+256))) } {
+			pass "$name"
+		} else {
+			fail "$name: unexpected return status [lindex $ret $wait_status_index], should be $status"
+		}
+	}
+}
+
+proc kinit { princ pass } {
+	global env;
+        global KINIT
+	spawn -noecho $KINIT -5 $princ;
+
+	expect {
+		-re "Password for .*:\[^\n\]*$"
+		    {send "$pass\n"}
+		timeout {puts "Timeout waiting for prompt" ; close }
+	}
+
+	# this necessary so close(1) in the child will not sleep waiting for
+	# the parent, which is us, to read pending data.
+
+	expect {
+		eof {}
+	}
+	wait
+}
+
+proc kdestroy {} {
+        global KDESTROY
+	global errorCode errorInfo
+	global env
+
+	if {[info exists errorCode]} {
+		set saveErrorCode $errorCode
+	}
+	if {[info exists errorInfo]} {
+		set saveErrorInfo $errorInfo
+	}
+	catch "system $KDESTROY -5 2>/dev/null"
+	if {[info exists saveErrorCode]} {
+		set errorCode $saveErrorCode
+	} elseif {[info exists errorCode]} {
+		unset errorCode
+	}
+	if {[info exists saveErrorInfo]} {
+		set errorInfo $saveErrorInfo
+	} elseif {[info exists errorInfo]} {
+		unset errorInfo
+	}
+}
+
+global initerr_str
+global initerr_regexp
+set initerr_str "Cannot establish a session with the Kerberos administrative server for realm \[^\r\n\]*\\. "
+set initerr_regexp "Cannot establish a session with the Kerberos administrative server for$s+realm \[^\r\n\]*\\.$s+"
+
+proc test_win { args name princ pass1 { pass2 "\001\001" } } {
+	global s
+	global initerr_regexp
+
+	if { $pass2 == "\001\001" } { set pass2 "$pass1" }
+
+	mytest "$name" $args 0 {
+		-re "Changing password for $princ.*\\.$s+Old password:\[^\n\]*$"
+			{ send "$pass1\n" }
+	} {
+		-re "Old Kerberos password is incorrect. Please try again."
+			{ close; myfail "Old password incorrect" }
+		-re "${initerr_regexp}(.+\[^\r\n\t\ \])\r\n"
+			{ close; myfail "init error: $expect_out(1,string)" }
+		-re "$s+New password:\[^\n\]*$"
+			{ send "$pass2\n" }
+		-re "$s+.*$s+.*$s+.*$s+New password:\[^\n\]*$"
+			{ send "$pass2\n" }
+	} {
+		-re "$s+New password \\(again\\):\[^\n\]*$"
+			{ send "$pass2\n" }
+	} {
+		-re "$s+Kerberos password changed."
+			{ mypass }
+		-re "$s+Password changed."
+			{ close; myfail "Wrong message on success." }
+	}
+}
+
+proc test_initerr { args name princ pass status err } {
+	global s
+	global initerr_regexp
+
+	regsub -all "$s+" $err "$s+" err2
+
+	mytest "$name" $args $status {
+		-re "Changing password for $princ.*\\.$s+Old password:\[^\n\]*$"
+			{ send "$pass\n" }
+	} {
+		-re "$err2"
+			{ mypass }
+		-re "Old Kerberos password is incorrect. Please try again."
+			{ close; myfail "Old password incorrect" }
+		-re "${initerr_regexp}(.+)\r\n"
+			{ close; myfail "init error: $expect_out(1,string)" }
+	}
+}
+
+proc test_3pass { args name princ pass1 pass2 pass3 status err } {
+	global s
+	global initerr_regexp
+
+	regsub -all "$s+" $err "$s+" err2
+
+	mytest "$name" $args $status {
+		-re "Changing password for $princ.*\\.$s+Old password:\[^\n\]*$"
+			{ send "$pass1\n" }
+	} {
+		-re "Old Kerberos password is incorrect. Please try again."
+			{ close; myfail "Old password incorrect" }
+		-re "${initerr_regexp}(.+)\r\n"
+			{ close; myfail "init error: $expect_out(1,string)" }
+		-re "$s+New password:\[^\n\]*$"
+			{ send "$pass2\n" }
+		-re "$s+.*$s+.*$s+.*$s+New password:\[^\n\]*$"
+			{ send "$pass2\n" }
+	} {
+		-re "$s+New password \\(again\\):\[^\n\]*$"
+			{ send "$pass3\n" }
+	} {
+		-re "$s+$err2"
+			{ mypass }
+	}
+}
+
diff --git a/mechglue/src/kadmin/passwd/xm_kpasswd.c b/mechglue/src/kadmin/passwd/xm_kpasswd.c
new file mode 100644
index 000000000..66976208a
--- /dev/null
+++ b/mechglue/src/kadmin/passwd/xm_kpasswd.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved.
+ * 
+ * $Header$
+ *
+ *
+ */
+
+static char rcsid_2[] = "$Id$";
+
+#include <kadm5/admin.h>
+#include <krb5.h>
+
+#include "kpasswd_strings.h"
+#define string_text error_message
+#define initialize_kpasswd_strings initialize_kpws_error_table
+
+#include <stdio.h>
+#include <pwd.h>
+#include <string.h>
+
+char *whoami;
+
+#include <Xm/Xm.h>
+#include <Xm/MessageB.h>
+#include <Xm/ScrolledW.h>
+#include <Xm/Form.h>
+#include <Xm/Text.h>
+#include <Xm/PushB.h>
+#include <Xm/Label.h>
+#include <Xm/Separator.h>
+#include <X11/cursorfont.h>
+#include <X11/Shell.h>
+
+Widget toplevel, scroll_text, prompt_text;
+Widget quit_btn, help_btn, old_lbl, new_lbl, again_lbl, main_lbl;
+XtAppContext app_con;
+int looping;
+int retval=0;
+
+
+/***************************************************************************
+ *
+ *  A few utility functions for setting/unsetting the busy cursor
+ *  (i.e. the watch cursor).
+ */
+static void
+SetCursor(w,c)
+     Widget w;
+     Cursor c;
+{
+  while (XtIsSubclass(w, shellWidgetClass) != True)
+    w = XtParent(w);
+
+  XDefineCursor(XtDisplay(w), XtWindow(w), c);
+  XFlush(XtDisplay(w));
+}
+
+ 
+static void
+SetStandardCursor()
+{
+  static Cursor ArrowCursor = (Cursor)NULL;
+ 
+  if (ArrowCursor == (Cursor)NULL)
+    ArrowCursor = XCreateFontCursor(XtDisplay(toplevel), XC_top_left_arrow);
+  SetCursor(toplevel, ArrowCursor);
+}
+
+ 
+static void
+SetWatchCursor()
+{
+  static Cursor WatchCursor = (Cursor)NULL;
+
+  if (WatchCursor == (Cursor)NULL)
+    WatchCursor = XCreateFontCursor(XtDisplay(toplevel), XC_watch);
+  SetCursor(toplevel, WatchCursor);
+}
+
+
+/***************************************************************************
+ *
+ *  Set up a com_err hook, for displaying to a motif scrolling widget.
+ */
+
+#if __STDC__
+#	include <stdarg.h>
+#else /* varargs: not STDC or no <stdarg> */
+	/* Non-ANSI, always take <varargs.h> path. */
+#	undef VARARGS
+#	define VARARGS 1
+#	include <varargs.h>
+#endif /* varargs */
+
+static void
+#ifdef __STDC__
+motif_com_err (const char *whoami, long code, const char *fmt, va_list args)
+#else
+motif_com_err (whoami, code, fmt, args)
+    const char *whoami;
+    long code;
+    const char *fmt;
+    va_list args;
+#endif
+{
+  XEvent event;
+  char buf[2048];
+
+  buf[0] = '\0';
+
+  if (whoami)
+    {
+      strncpy(buf, whoami, sizeof(buf) - 1);
+      buf[sizeof(buf) - 1] = '\0';
+      strncat(buf, ": ", sizeof(buf) - 1 - strlen(buf));
+    }
+  if (code)
+    {
+      buf[sizeof(buf) - 1] = '\0';
+      strncat(buf, error_message(code), sizeof(buf) - 1 - strlen(buf));
+      strncat(buf, " ", sizeof(buf) - 1 - strlen(buf));
+    }
+  if (fmt)
+    {
+      vsprintf(buf + strlen(buf), fmt, args);
+    }
+
+  XtVaSetValues(scroll_text, XmNvalue, buf, NULL);
+
+  for (; XtAppPending(app_con); )
+    {
+      XtAppNextEvent(app_con, &event);
+      XtDispatchEvent(&event);
+    }
+}
+
+
+/***************************************************************************
+ *
+ *  Function to display help widget.
+ */
+static void
+help()
+{
+  static Widget help_dlg = NULL;
+
+  if (!help_dlg)
+    {
+      help_dlg = XmCreateInformationDialog(toplevel, "help_dlg", NULL,
+					   0);
+      XtUnmanageChild(XmMessageBoxGetChild(help_dlg, XmDIALOG_CANCEL_BUTTON));
+      XtUnmanageChild(XmMessageBoxGetChild(help_dlg, XmDIALOG_HELP_BUTTON));
+    }
+  XtManageChild(help_dlg);
+}
+
+
+/***************************************************************************
+ *
+ *  Unset the global "looping" when we want to get out of reading a
+ *  password.
+ */
+static void
+unset_looping()
+{
+  looping = 0;
+}
+
+
+/***************************************************************************
+ *
+ *  Function to exit the gui.  Callback on the "Exit" button.
+ */
+static void
+quit()
+{
+  exit(retval);
+}
+
+
+/***************************************************************************
+ *
+ *  Set up motif widgets, callbacks, etc.
+ */
+static void
+create_widgets(argc, argv)
+     int *argc;
+     char *argv[];
+{
+  Widget form, lbl_form,
+  	sep,
+  	scroll_win;
+  Pixel bg;
+
+  toplevel = XtAppInitialize(&app_con, "Kpasswd", NULL, 0, argc, argv,
+			     NULL, NULL, 0);
+  form = XtCreateManagedWidget("form", xmFormWidgetClass, toplevel, NULL, 0);
+  quit_btn = XtVaCreateManagedWidget("Quit", xmPushButtonWidgetClass,
+				form,
+				XmNleftAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_FORM,
+				NULL);
+  XtAddCallback(quit_btn, XmNactivateCallback, quit, 0);
+  help_btn = XtVaCreateManagedWidget("Help", xmPushButtonWidgetClass,
+				form,
+				XmNrightAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_FORM,
+				/* XmNshowAsDefault, TRUE, */
+				NULL);
+  XtAddCallback(help_btn, XmNactivateCallback, help, 0);
+  sep = XtVaCreateManagedWidget("sep", xmSeparatorWidgetClass,
+				form,
+				XmNleftAttachment, XmATTACH_FORM,
+				XmNrightAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_WIDGET,
+				XmNbottomWidget, quit_btn,
+				NULL);
+  lbl_form = XtVaCreateManagedWidget("lbl_form", xmFormWidgetClass,
+				form,
+				XmNspacing, 0,
+				XmNleftAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_WIDGET,
+				XmNbottomWidget, sep,
+				NULL);
+  old_lbl = XtVaCreateManagedWidget("old_lbl", xmLabelWidgetClass,
+				lbl_form,
+				XmNtopAttachment, XmATTACH_FORM,
+				XmNleftAttachment, XmATTACH_FORM,
+				XmNrightAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_FORM,
+				NULL);
+  new_lbl = XtVaCreateManagedWidget("new_lbl", xmLabelWidgetClass,
+				lbl_form,
+				XmNtopAttachment, XmATTACH_FORM,
+				XmNleftAttachment, XmATTACH_FORM,
+				XmNrightAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_FORM,
+				NULL);
+  again_lbl = XtVaCreateManagedWidget("again_lbl", xmLabelWidgetClass,
+				lbl_form,
+				XmNtopAttachment, XmATTACH_FORM,
+				XmNleftAttachment, XmATTACH_FORM,
+				XmNrightAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_FORM,
+				NULL);
+  prompt_text = XtVaCreateManagedWidget("prompt_text", xmTextWidgetClass,
+				form,
+				XmNeditMode, XmSINGLE_LINE_EDIT,
+				XmNleftAttachment, XmATTACH_WIDGET,
+				XmNleftWidget, lbl_form,
+				XmNrightAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_WIDGET,
+				XmNbottomWidget, sep,
+				NULL);
+  XtAddCallback(prompt_text, XmNactivateCallback, unset_looping, 0);
+  XtVaGetValues(prompt_text, XmNbackground, &bg, NULL);
+  XtVaSetValues(prompt_text, XmNforeground, bg, NULL);
+
+  main_lbl = XtVaCreateWidget("main_lbl", xmLabelWidgetClass,
+				form,
+				XmNtopAttachment, XmATTACH_FORM,
+				XmNleftAttachment, XmATTACH_FORM,
+				XmNrightAttachment, XmATTACH_FORM,
+				NULL);
+  scroll_win = XtVaCreateManagedWidget("scroll_win",
+				xmScrolledWindowWidgetClass,
+				form,
+				XmNscrollingPolicy, XmAPPLICATION_DEFINED,
+				XmNscrollBarDisplayPolicy, XmSTATIC,
+				XmNtopAttachment, XmATTACH_WIDGET,
+				XmNtopWidget, main_lbl,
+				XmNleftAttachment, XmATTACH_FORM,
+				XmNrightAttachment, XmATTACH_FORM,
+				XmNbottomAttachment, XmATTACH_WIDGET,
+				XmNbottomWidget, prompt_text,
+				NULL);
+  scroll_text = XtVaCreateManagedWidget("scroll_text", xmTextWidgetClass,
+				scroll_win,
+				XmNeditMode, XmMULTI_LINE_EDIT,
+				XmNeditable, FALSE,
+				NULL);
+  XtRealizeWidget(toplevel);
+}
+
+
+/***************************************************************************
+ *
+ *  
+ */
+static long
+read_password(password, pwsize)
+     char *password;
+     int *pwsize;
+{
+  XEvent event;
+  char *text_val;
+
+  /* OK, this next part is gross...  but this is due to the fact that	*/
+  /* this is not your traditional X program, which would be event	*/
+  /* driven.  Instead, this program is more 'CLI' in nature, so we	*/
+  /* handle the dialogs synchronously... 				*/
+
+  XtVaSetValues(prompt_text, XmNmaxLength, *pwsize, XmNvalue, "", NULL);
+  for (looping=1; looping; )
+    {
+      XtAppNextEvent(app_con, &event);
+      XtDispatchEvent(&event);
+    }
+  XtVaGetValues(prompt_text, XmNvalue, &text_val, NULL);
+  *pwsize = strlen(text_val);
+  strcpy(password, text_val);
+  memset(text_val, 0, *pwsize);
+  XtVaSetValues(prompt_text, XmNvalue, text_val, NULL);
+  return(0);
+}
+  
+
+/***************************************************************************
+ *
+ *  
+ */
+void
+display_intro_message(fmt_string, arg_string)
+     const char *fmt_string;
+     const char *arg_string;
+{
+  XmString xmstr;
+  char buf[1024];
+
+  sprintf(buf, fmt_string, arg_string);
+
+  xmstr = XmStringCreateLtoR(buf, XmSTRING_DEFAULT_CHARSET);
+  XtVaSetValues(main_lbl, XmNlabelString, xmstr, NULL);
+  XmStringFree(xmstr);
+  XtManageChild(main_lbl);
+}
+
+
+long
+read_old_password(context, password, pwsize)
+     krb5_context context;
+     char *password;
+     unsigned int *pwsize;
+{
+  long code;
+
+  XtManageChild(old_lbl);
+  code = read_password(password, pwsize);
+  SetWatchCursor();
+  return code;
+}
+
+long
+read_new_password(server_handle, password, pwsize, msg_ret, princ)
+     void *server_handle;
+     char *password;
+     unsigned int *pwsize;
+     char *msg_ret;
+     krb5_principal princ;
+{
+  char *password2 = (char *) malloc(*pwsize * sizeof(char));
+  int pwsize2 = *pwsize;
+
+  SetStandardCursor();
+
+  if (password2 == NULL)
+    {
+      strcpy(msg_ret, error_message(ENOMEM));
+      SetWatchCursor();
+      return(ENOMEM);
+    }
+
+  XtManageChild(new_lbl); XtUnmanageChild(old_lbl);
+  read_password(password, pwsize);
+  XtManageChild(again_lbl); XtUnmanageChild(new_lbl);
+  read_password(password2, &pwsize2);
+
+  if (strcmp(password, password2))
+    {
+      memset(password, 0, *pwsize);
+
+      memset(password2, 0, pwsize2);
+      free(password2);
+      
+      strcpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH));
+      SetWatchCursor();
+      return(KRB5_LIBOS_BADPWDMATCH);
+    }
+
+  memset(password2, 0, pwsize2);
+  free(password2);
+
+  SetWatchCursor();
+  return (ovsec_kadm_chpass_principal_util(server_handle, princ, password,
+                                            NULL /* don't need new pw back */,
+                                            msg_ret));
+}
+  
+
+/***************************************************************************
+ *
+ *
+ */
+void
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+  krb5_context context;
+  int code;
+
+  initialize_kpasswd_strings();
+
+  whoami = (whoami = strrchr(argv[0], '/')) ? whoami + 1 : argv[0];
+
+  (void) set_com_err_hook(motif_com_err);
+
+  create_widgets(&argc, argv);
+  XmProcessTraversal(prompt_text, XmTRAVERSE_CURRENT);
+
+  if (retval = krb5_init_context(&context)) {
+       com_err(whoami, retval, "initializing krb5 context");
+       exit(retval);
+  }
+
+  while (1)
+    {
+      retval = kpasswd(context, argc, argv);
+      SetStandardCursor();
+
+      if (!retval)
+	com_err(0, 0, string_text(KPW_STR_PASSWORD_CHANGED));
+
+      if (retval == 0)		/* 0 is success, so presumably the user */
+				/* is done. */
+	XmProcessTraversal(quit_btn, XmTRAVERSE_CURRENT);
+
+      if ((retval == 1) ||	/* the rest are "fatal", so we should */
+	  (retval == 3) ||	/* "force" the user to quit... */
+	  (retval == 6) ||
+	  (retval == 7))
+	{
+	  XtSetSensitive(prompt_text, FALSE);
+	  XmProcessTraversal(quit_btn, XmTRAVERSE_CURRENT);
+	  XtAppMainLoop(app_con);
+	}
+    }
+
+  /* NOTREACHED */
+  exit(retval);
+}
diff --git a/mechglue/src/kadmin/scripts/inst-hdrs.sh b/mechglue/src/kadmin/scripts/inst-hdrs.sh
new file mode 100755
index 000000000..242be89e9
--- /dev/null
+++ b/mechglue/src/kadmin/scripts/inst-hdrs.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+dir=$1; shift
+while [ $# -gt 0 ]; do
+	file=$1
+	cmp -s $file $dir/$file
+	if [ $? != 0 ]; then
+		echo "+ rm $dir/$file"
+		rm -f $dir/$file
+		echo "+ cp $file $dir/$file"
+		cp $file $dir/$file
+	fi
+	shift
+done
diff --git a/mechglue/src/kadmin/server/ChangeLog b/mechglue/src/kadmin/server/ChangeLog
new file mode 100644
index 000000000..a84ddc8f0
--- /dev/null
+++ b/mechglue/src/kadmin/server/ChangeLog
@@ -0,0 +1,480 @@
+2005-10-12  Tom Yu  <tlyu@mit.edu>
+
+	* misc.h, misc.c (schpw_util_wrapper): Rename from
+	chpass_util_wrapper to make functionality a little more obvious.
+
+	* schpw.c (process_chpw_request): Update for rename of
+	chpass_util_wrapper.
+
+	* misc.c (randkey_principal_wrapper_3, schpw_util_wrapper) 
+	(chpass_principal_wrapper_3): Update for check_min_life.
+
+	* misc.h, misc.c (check_min_life): Change to take return error
+	string from KADM5_PASS_TOOSOON, adapted from patch from Shawn
+	Emery.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* kadm_rpc_svc.c, server_stubs.c: Rename all RPC functions from
+	_1_svc to _2_svc to match current program version number.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KDB_DEP_LIB): Use DL_LIB and THREAD_LINKOPTS
+	instead of explicitly using -ldl and -lpthread.
+
+	Novell merge.
+	* Makefile.in:
+	* misc.c:
+	* ovsec_kadmd.c:
+	* server_stubs.c:
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* schpw.c (NEED_SOCKETS): Don't define.
+
+2004-10-28  Tom Yu  <tlyu@mit.edu>
+
+	* misc.c (check_min_life): Actually return a value on success.
+
+2004-10-27  Tom Yu  <tlyu@mit.edu>
+
+	* misc.c, misc.h: New function check_min_life(), containing common
+	code from wrapper functions.  New function chpass_util_wrapper(),
+	which does min_life checking prior to calling
+	kadm5_chpass_principal_util().
+
+	* schpw.c (process_chpw_request): Call chpass_util_wrapper().
+
+2004-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c (kadm_svc_run): Don't use rpc_dtablesize().
+
+2004-08-20  Alexandra Ellwood <lxs@mit.edu>
+
+        * ovsec_kadmd.c (main), server_stubs.c (*): 
+        renamed acl_* functions to kadm5int_acl_*
+
+2004-06-26  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c (log_badverf): Fix a missed rpc_u_int32.
+
+2004-06-25  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c (log_badverf): Use rpcproc_t instead of
+	rpc_u_int32 in procnames.
+
+2004-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc_svc.c (check_rpcsec_auth, gss_to_krb5_name): New
+	functions to check service name for RPCSEC_GSS.
+	(kadm_1): Add service name check for RPCSEC_GSS.
+
+	* ovsec_kadmd.c (main): Setup logging calllbacks for RPCSEC_GSS.
+	Use GSS_C_N_NAME for acceptor name for RPCSEC_GSS.
+	(log_badverf): Handle null client and server names.
+
+	* server_stubs.c (rqst2name): New function to return appropriate
+	gss_name_t for a given auth flavor (RPCSEC_GSS and AUTH_GSSAPI use
+	different field names).
+
+2004-05-27  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc_svc.c (kadm_1): Allow RPCSEC_GSS; remove
+	AUTH_GSSAPI_COMPAT.
+
+	* misc.h (kadm_1): Conditionalize prototype on SVC_GETARGS rather
+	than on an inclusion-protection macro.
+
+	* ovsec_kadmd.c (main): Add preliminary support for RPCSEC_GSS.
+	(do_schpw, kadm_svc_run): Update some names.
+
+2004-03-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* ovsec_kadmd.c (main): Use any handy krb5 context to register
+	the KDB keytab type, we don't need to pluck it out of the GSSAPI
+	krb5 mechanism.
+	(gctx): Variable deleted.
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (OBJS, $(PROG)): Link against apputils lib instead
+	of using LIBOBJS.
+
+2003-09-02  Alexandra Ellwood  <lxs@mit.edu>
+
+	* ovsec_kadmd.c: Added Apple password server support.
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (OBJS): Use @LIBOBJS@.
+
+2003-05-27  Tom Yu  <tlyu@mit.edu>
+
+	* schpw.c (process_chpw_request): Log chpw requests.
+
+2003-05-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* schpw.c (process_chpw_request): Return KRB5_KPASSWD_BAD_VERSION
+	if the version number isn't 1.
+
+2003-03-07  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c (REQUIRED_PARAMS): Remove
+	KADM5_CONFIG_ADMIN_KEYTAB.
+	(do_schpw): Use kdb keytab.
+
+2003-03-05  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): Add gssapi directories in order to
+	get internal includes.
+
+	* ovsec_kadmd.c (main): Go through contortions to set up a kdb
+	keytab for gssapi, so we can avoid needing a file-based keytab.
+
+2003-01-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* ovsec_kadmd.c (do_schpw): Use socklen_t when passing address to
+	socket functions.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-12-09  Sam Hartman  <hartmans@mit.edu>
+
+	* misc.h: Fix prototypes for *_wrapper_3 to be consistent with
+	sources. 
+
+2002-12-09  Ezra Peisach  <epeisach@bu.edu>
+
+	* misc.h: Rename prototypes from chpass_principal_wrapper and
+	randkey_principal_wrapper to chpass_principal_wrapper_3 and
+	randkey_principal_wrapper_3
+
+2002-10-08  Tom Yu  <tlyu@mit.edu>
+
+	* misc.c (chpass_principal_wrapper_3): Renamed from
+	chpass_principal_wrapper; calls chpass_principal_3 now.
+	(randkey_principal_wrapper_3): Renamed from
+	randkey_principal_wrapper; calls randkey_principal_3 now.  Patch
+	from Ben Cox.
+
+	* server_stubs.c (chpass_principal_1_svc)
+	(chpass_principal3_1_svc): Call chpass_principal_wrapper_3.
+	(chrand_principal_1_svc, chrand_principal3_1_svc): Call
+	randkey_principal_wrapper_3.  Patch from Ben Cox.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-01  Tom Yu  <tlyu@mit.edu>
+
+	* server_stubs.c: Check return value from unparse_name() in lots
+	of places.  Patch from Mark Levinson; fixes [krb5-admin/1140].
+
+2002-01-08  Sam Hartman  <hartmans@mit.edu>
+
+	* ovsec_kadmd.c (main): Get random data from /dev/random
+	(main): If we can't set gssapi names, hint that the keytab might be at fault
+
+2001-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* schpw.c (process_chpw_request): Use GETSOCKNAME_ARG3_TYPE
+	instead of int as argument to getsockname().
+
+2001-06-29  Ezra Peisach  <epeisach@mit.edu>
+
+	* misc.c, server_stubs.c: Nuke rcsid.
+
+	* misc.h: Add prototypes for kadm_1 and process_chpw_request.
+
+	* ovsec_kadmd.c: Include misc.h and remove prototype for
+	process_chpw_request and kadm_1. 
+
+	* kadm_rpc_svc.c, schpw.c: Include misc.h for prototypes.
+
+2001-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* server_glue_v1.c: Include misc.h for prototypes.
+
+	* ovsec_kadmd.c: Declare usage() and display_status() static.
+	Flush out static prototype for display_status_1().
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* ovsec_kadmd.c: Change prototype for process_chpw_request
+ 	prototype argument from sin to sockin. Get rid of global params
+ 	variable.
+
+	* schpw.c: Change function declaration as well.
+	
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* ovsec_kadmd.c: Add prototype for daemon if needed.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* ovsec_kadmd.c (main): Make format string to sprintf specify that
+	long arguments are present.
+
+	* kadm_rpc_svc.c: Include arpa/inet.h (if present) for inet_ntoa
+	prototype. Include adm_proto.h for krb5_klog_syslog() prototype.
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* misc.c, schpw.c: Cleanup assignments in conditionals.
+
+2001-02-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* kadm_rpc_svc.c, server_stubs.c: Rename all server side dispatch
+        routines to end in _svc so as to not conflict with prototypes of
+        client side handlers.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* ovsec_kadmd.c (do_schpw): Cast arguments to sendto() which take int.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* server_stubs.c: Kludge to rename xdr_free() properly.
+
+2000-06-29  Tom Yu  <tlyu@mit.edu>
+
+	* schpw.c (process_chpw_request): Add new argument to call to
+	chpass_principal_util()
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* kadm_rpc_svc.c: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-03-16  Ken Raeburn  <raeburn@mit.edu>
+	    Matt Crawford  <crawdad@fnal.gov>
+
+	* server_stubs.c: All callers of acl_check updated to add new
+	restriction argument.  Impose any provided restrictions on add- or
+	modify-principal operations; pass NULL pointer for all other
+	operations including rename-principal.
+
+2000-02-27  Tom Yu  <tlyu@mit.edu>
+
+	* server_stubs.c (create_principal3_1): Remove keepold argument.
+
+2000-02-18  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc_svc.c (kadm_1): Update to include new api functions.
+
+	* ovsec_kadmd.c (log_badverf): Update proc_names.
+
+2000-02-17  Tom Yu  <tlyu@mit.edu>
+
+	* server_stubs.c: Add create_principal3_1, chpass_principal3_1,
+	setkey_principal3_1, and chrand_principal3_1 to do the obvious
+	things.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Tue May 11 23:59:55 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ovsec_kadmd.c (main): Fix how we specify the OID.
+
+Fri May  7 17:15:17 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ovsec_kadmd.c: Remove dependency on gssapi_krb5.h by using
+ 		gss_str_to_oid() to get the necessary oid for the
+ 		krb5_name name type.  Also added #include files to get
+ 		prototypes and fixed some gcc -Wall nits.  Fixed calls to
+ 		krb5_klog_close() to pass the krb5_context as an argument.
+
+Mon Mar  1 21:24:49 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c (log_badverf): Actually make a real lookup table
+	for procedure numbers.  Also, if we don't find the procedure
+	number, just log the number rather than falling off the end of an
+	array.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* ovsec_kadmd.c: add calls to a new function
+	_svcauth_gssapi_unset_names() to clean up memory when shutting
+	down.  Use krb5_overridekeyname instead of krb5_defkeyname, so the
+	command line takes precedence over the environment.
+
+Wed Jul 22 00:28:57 1998  Geoffrey King  <gjking@mit.edu>
+
+	* ovsec_kadmd.c (main): Cast gss_nt_krb5_name to
+	        gss_OID to avoid compiler warnings.
+
+Tue Jul 21 16:36:51 1998  Geoffrey King  <gjking@mit.edu>
+
+	* ovsec_kadmd.c: Call krb5_klog_reopen in kadm_svc_run
+		upon receiving a SIGHUP.  Use sigaction instead of
+		signal if POSIX_SIGNALS is defined.  All of the calls
+		to signal and sigaction are now in a separate function
+		setup_signal_handlers, as the kdc code does.  Also,
+		since reset_db no longer does anything, change the name
+		of signal_request_reset to the more descriptive
+		signal_request_hup, and request_reset_db to 
+		request_hup (paralleling the nomenclature in the kdc
+		code).
+
+Mon Jul 20 11:28:39 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* schpw.c (process_chpw_request): Cast to krb5_octet * instead of
+	 	char * for krb5_address.contents type.
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 25 14:00:32 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* schpw.c (process_chpw_request): Free memory of allocated for
+	        local address.
+
+	* ovsec_kadmd.c (do_schpw): Call krb5_kt_close to free memory
+	 	allocated.
+
+Wed Feb 18 15:58:30 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Sat Feb 14 22:01:30 1998  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c (kadm_svc_run): Fix naming of _rpc_dtablesize()
+	that was missed earlier.
+
+Fri Feb 13 21:37:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc_svc.c: Punt naughty RCS keywords.  Update header
+	locations.
+
+	* ovsec_kadmd.c: Update header locations.  Punt naughty RCS
+	keywords.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 21 00:00:34 1998  Tom Yu  <tlyu@mit.edu>
+
+	* schpw.c: New file.  Support for Cygnus chpw.
+
+	* ovsec_kadmd.c: Add support for Cygnus chpw.
+
+	* Makefile.in (OBJS): Add schpw.o.
+
+Tue Oct 14 21:06:16 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* server_stubs.c (CHANGEPW_SERVICE): Modify to free allocated
+ 	        memory in request.
+		(setup_gss_names): Free memory in case of failure.
+		(chrand_principal_1): Call free_server_handle for failure
+		   cleanup.
+	
+	* ovsec_kadmd.c (main): Cleanup memory by calling acl_finish,
+	 	gss_release_name, and krb5_free_context
+
+Tue Jul  1 02:36:55 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc_svc.c, server_stubs.c: Add support for setv4key.
+
+Mon Mar 31 17:42:03 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadm_rpc_svc.c, server_stubs.c: add support for setkey_principal
+
+Tue Feb  4 20:59:31 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Wed Dec  4 15:29:30 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* ovsec_kadmd.c (main): fix duplicated error strings
+ 	[krb5-admin/234]
+
+Tue Nov 19 16:48:50 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* ovsec_kadmd.c: don't syslog \n's
+
+Wed Nov 13 14:29:34 1996  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c (main): Note that krb5_defkeyname is an internal
+	interface.
+
+	* ovsec_kadmd.c (main): Revert kt_default_name changes.
+
+Tue Nov 12 22:07:05 1996  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c (main): Use krb5_kt_set_default_name() rather than
+	mucking about with global variables.
+
+Fri Sep 27 16:37:47 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* ovsec_kadmd.c (main): krb5_klog_syslog doesn't understand %m
+
+Tue Sep 10 14:18:12 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kadmind.M: remove ".so man1/header.doc", fix up .TH call
+
+Tue Sep  3 22:11:25 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (install): Fix typo: ($PROG) -> $(PROG)
+
+Thu Aug 29 16:11:01 1996  Jeff Bigler  <jcb@viola.cygnus.com>
+
+	* Makefile.in (install): added kadmind man page
+
+Mon Aug 12 11:48:19 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* ovsec_kadmd.c (main): strip path components of whoami
+
+Thu Aug  1 15:57:08 1996  Barry Jaspan  <bjaspan@DUN-DUN-NOODLES>
+
+	* ovsec_kadmd.c (main): remove useless hex value from error message
+
+Wed Jul 31 15:22:10 1996  Tom Yu  <tlyu@mit.edu>
+
+	* ovsec_kadmd.c: Revert prior change due to netdb.h shuffle
+
+	* ovsec_kadmd.c: remove #include <netdb.h> (already gotten by
+		kadm5/kadm_rpc.h)
+
+Wed Jul 24 18:34:33 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* ovsec_kadmd.c (main): Put the #ifdef SO_REUSEADDR at the
+		beginning of the line to avoid cpp breakage.
+
+Wed Jul 24 14:28:04 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (CFLAGS): Use $(LD) instead of $(CC) for linking.
+
+Mon Jul 22 04:16:15 1996  Marc Horowitz  <marc@mit.edu>
+
+	* ovsec_kadmd.c (main): open the socket with SO_REUSEADDR.  The
+ 	old server did this, and the tests require it on some platforms.
+
+Tue Jul  9 16:04:53 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kadm_rpc_svc.c: renamed <ovsec_admin/foo.h> to <kadm5/foo.h>
+	* configure.in: cosmetic changes.
+	* Makefile.in: complete rewrite.
diff --git a/mechglue/src/kadmin/server/Makefile.in b/mechglue/src/kadmin/server/Makefile.in
new file mode 100644
index 000000000..391e89773
--- /dev/null
+++ b/mechglue/src/kadmin/server/Makefile.in
@@ -0,0 +1,26 @@
+thisconfigdir=./..
+myfulldir=kadmin/server
+mydir=server
+BUILDTOP=$(REL)..$(S)..
+KDB_DEP_LIB=$(DL_LIB) $(THREAD_LINKOPTS)
+
+LOCALINCLUDES = -I$(SRCTOP)/lib/gssapi/generic -I$(SRCTOP)/lib/gssapi/krb5 \
+	-I$(BUILDTOP)/lib/gssapi/generic -I$(BUILDTOP)/lib/gssapi/krb5
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+PROG = kadmind
+OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o schpw.o misc.o server_glue_v1.o
+
+all:: $(PROG)
+
+$(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS) $(APPUTILS_DEPLIB)
+	$(CC_LINK) -o $(PROG) $(OBJS) $(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS) $(APPUTILS_LIB)
+
+install::
+	$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(SERVER_BINDIR)/$(PROG)
+	$(INSTALL_DATA) $(srcdir)/$(PROG).M ${DESTDIR}$(SERVER_MANDIR)/$(PROG).8
+
+clean::
+	$(RM) $(PROG) $(OBJS)
diff --git a/mechglue/src/kadmin/server/acls.l b/mechglue/src/kadmin/server/acls.l
new file mode 100644
index 000000000..aee4801e9
--- /dev/null
+++ b/mechglue/src/kadmin/server/acls.l
@@ -0,0 +1,190 @@
+%{
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ * 
+ * $Log$
+ * Revision 1.3  1996/07/22 20:28:49  marc
+ * this commit includes all the changes on the OV_9510_INTEGRATION and
+ * OV_MERGE branches.  This includes, but is not limited to, the new openvision
+ * admin system, and major changes to gssapi to add functionality, and bring
+ * the implementation in line with rfc1964.  before committing, the
+ * code was built and tested for netbsd and solaris.
+ *
+ * Revision 1.2.4.1  1996/07/18 03:03:31  marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.2.2.1  1996/06/20  21:56:31  marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.2  1993/11/05  07:47:46  bjaspan
+ * add and use cmp_gss_names, fix regexp bug
+ *
+ * Revision 1.1  1993/11/05  07:08:48  bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+enum tokens {
+     NEWLINE = 257,
+     COMMA,
+     SEMI,
+
+     GET = 300,
+     ADD,
+     MODIFY,
+     DELETE,
+
+     ID = 350,
+};
+
+typedef union {
+     char *s;
+} toktype;
+
+toktype tokval;
+int acl_lineno = 0;
+
+%}
+
+%%
+
+\n		acl_lineno++; 
+[ \t]*		;
+[ ]*#.*		;
+","		return (COMMA);
+";"		return (SEMI);
+"get"		return (GET);
+"add"		return (ADD);
+"modify"	return (MODIFY);
+"delete"	return (DELETE);
+^[^ \t\n]+		{ tokval.s = yytext; return (ID); }
+
+%%
+     
+#include <string.h>
+#include <syslog.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <ovsec_admin/admin.h>
+
+typedef struct _entry {
+     gss_name_t gss_name;
+     char *name;
+     u_int privs;
+     struct _entry *next;
+} acl_entry;
+
+static acl_entry *acl_head = NULL;
+
+static void error(char *msg);
+
+int parse_aclfile(FILE *acl_file)
+{
+     OM_uint32 gssstat, minor_stat;
+     gss_buffer_desc in_buf;
+     acl_entry *entry;
+     enum tokens tok;
+
+     yyin = acl_file;
+
+     acl_lineno = 1;
+     while ((tok = yylex()) != 0) {
+	  if (tok != ID) {
+	       error("expected identifier");
+	       goto error;
+	  }
+
+	  entry = (acl_entry *) malloc(sizeof(acl_entry));
+	  if (entry == NULL) {
+	       error("out of memory");
+	       goto error;
+	  }
+	  entry->name = strdup(tokval.s);
+	  entry->privs = 0;
+	  while (1) {
+	       switch (tok = yylex()) {
+	       case GET:
+		    entry->privs |= OVSEC_KADM_PRIV_GET;
+		    break;
+	       case ADD:
+		    entry->privs |= OVSEC_KADM_PRIV_ADD;
+		    break;
+	       case MODIFY:
+		    entry->privs |= OVSEC_KADM_PRIV_MODIFY;
+		    break;
+	       case DELETE:
+		    entry->privs |= OVSEC_KADM_PRIV_DELETE;
+		    break;
+	       default:
+		    error("expected privilege");
+		    goto error;
+	       }
+	       tok = yylex();
+	       if (tok == COMMA)
+		    continue;
+	       else if (tok == SEMI)
+		    break;
+	       else {
+		    error("expected comma or semicolon");
+		    goto error;
+	       }
+	  }
+
+	  in_buf.value = entry->name;
+	  in_buf.length = strlen(entry->name) + 1;
+	  gssstat = gss_import_name(&minor_stat, &in_buf,
+				    gss_nt_krb5_name, &entry->gss_name);
+	  if (gssstat != GSS_S_COMPLETE) {
+	       error("invalid name");
+	       goto error;
+	  }
+	  
+	  if (acl_head == NULL) {
+	       entry->next = NULL;
+	       acl_head = entry;
+	  } else {
+	       entry->next = acl_head;
+	       acl_head = entry;
+	  }
+     }
+     return 0;
+
+error:
+     return 1;
+}
+
+int acl_check(gss_name_t caller, int priv)
+{
+     acl_entry *entry;
+     
+     entry = acl_head;
+     while (entry) {
+	  if (cmp_gss_names(entry->gss_name, caller) && entry->privs & priv)
+	       return 1;
+	  entry = entry->next;
+     }
+     return 0;
+}
+
+int cmp_gss_names(gss_name_t name1, gss_name_t name2)
+{
+     OM_uint32 minor_stat;
+     int eq;
+     (void) gss_compare_name(&minor_stat, name1, name2, &eq);
+     return eq;
+}
+
+static void error(char *msg)
+{
+     syslog(LOG_ERR, "Error while parsing acl file, line %d: %s\n",
+	    acl_lineno, msg);
+}
+
+yywrap() { return(1); }
diff --git a/mechglue/src/kadmin/server/kadm_rpc_svc.c b/mechglue/src/kadmin/server/kadm_rpc_svc.c
new file mode 100644
index 000000000..b01d95794
--- /dev/null
+++ b/mechglue/src/kadmin/server/kadm_rpc_svc.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <gssrpc/rpc.h>
+#include <gssapi/gssapi_krb5.h> /* for gss_nt_krb5_name */
+#include <syslog.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <kadm5/kadm_rpc.h>
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <adm_proto.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include "misc.h"
+#include "kadm5/server_internal.h"
+
+extern void *global_server_handle;
+
+static int check_rpcsec_auth(struct svc_req *);
+static int gss_to_krb5_name(struct svc_req *, krb5_context, gss_name_t, krb5_principal *, gss_buffer_t);
+
+void log_badauth(OM_uint32 major, OM_uint32 minor,
+		 struct sockaddr_in *addr, char *data);
+/*
+ * Function: kadm_1
+ * 
+ * Purpose: RPC proccessing procedure.
+ *	    originally generated from rpcgen
+ *
+ * Arguments:
+ *	rqstp		    (input) rpc request structure
+ *	transp		    (input) rpc transport structure
+ *	(input/output)
+ * 	<return value>
+ *
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+
+void kadm_1(rqstp, transp)
+   struct svc_req *rqstp;
+   register SVCXPRT *transp;
+{
+     union {
+	  cprinc_arg create_principal_2_arg;
+	  dprinc_arg delete_principal_2_arg;
+	  mprinc_arg modify_principal_2_arg;
+	  rprinc_arg rename_principal_2_arg;
+	  gprinc_arg get_principal_2_arg;
+	  chpass_arg chpass_principal_2_arg;
+	  chrand_arg chrand_principal_2_arg;
+	  cpol_arg create_policy_2_arg;
+	  dpol_arg delete_policy_2_arg;
+	  mpol_arg modify_policy_2_arg;
+	  gpol_arg get_policy_2_arg;
+	  setkey_arg setkey_principal_2_arg;
+	  setv4key_arg setv4key_principal_2_arg;
+	  cprinc3_arg create_principal3_2_arg;
+	  chpass3_arg chpass_principal3_2_arg;
+	  chrand3_arg chrand_principal3_2_arg;
+	  setkey3_arg setkey_principal3_2_arg;
+     } argument;
+     char *result;
+     bool_t (*xdr_argument)(), (*xdr_result)();
+     char *(*local)();
+
+     if (rqstp->rq_cred.oa_flavor != AUTH_GSSAPI &&
+	 !check_rpcsec_auth(rqstp)) {
+	  krb5_klog_syslog(LOG_ERR, "Authentication attempt failed: %s, "
+		 "RPC authentication flavor %d",
+		 inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr),
+		 rqstp->rq_cred.oa_flavor);
+	  svcerr_weakauth(transp);
+	  return;
+     }
+     
+     switch (rqstp->rq_proc) {
+     case NULLPROC:
+	  (void) svc_sendreply(transp, xdr_void, (char *)NULL);
+	  return;
+	  
+     case CREATE_PRINCIPAL:
+	  xdr_argument = xdr_cprinc_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) create_principal_2_svc;
+	  break;
+	  
+     case DELETE_PRINCIPAL:
+	  xdr_argument = xdr_dprinc_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) delete_principal_2_svc;
+	  break;
+	  
+     case MODIFY_PRINCIPAL:
+	  xdr_argument = xdr_mprinc_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) modify_principal_2_svc;
+	  break;
+	  
+     case RENAME_PRINCIPAL:
+	  xdr_argument = xdr_rprinc_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) rename_principal_2_svc;
+	  break;
+	  
+     case GET_PRINCIPAL:
+	  xdr_argument = xdr_gprinc_arg;
+	  xdr_result = xdr_gprinc_ret;
+	  local = (char *(*)()) get_principal_2_svc;
+	  break;
+
+     case GET_PRINCS:
+	  xdr_argument = xdr_gprincs_arg;
+	  xdr_result = xdr_gprincs_ret;
+	  local = (char *(*)()) get_princs_2_svc;
+	  break;
+	  
+     case CHPASS_PRINCIPAL:
+	  xdr_argument = xdr_chpass_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) chpass_principal_2_svc;
+	  break;
+
+     case SETV4KEY_PRINCIPAL:
+	  xdr_argument = xdr_setv4key_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) setv4key_principal_2_svc;
+	  break;
+
+     case SETKEY_PRINCIPAL:
+	  xdr_argument = xdr_setkey_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) setkey_principal_2_svc;
+	  break;
+	  
+     case CHRAND_PRINCIPAL:
+	  xdr_argument = xdr_chrand_arg;
+	  xdr_result = xdr_chrand_ret;
+	  local = (char *(*)()) chrand_principal_2_svc;
+	  break;
+	  
+     case CREATE_POLICY:
+	  xdr_argument = xdr_cpol_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) create_policy_2_svc;
+	  break;
+	  
+     case DELETE_POLICY:
+	  xdr_argument = xdr_dpol_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) delete_policy_2_svc;
+	  break;
+	  
+     case MODIFY_POLICY:
+	  xdr_argument = xdr_mpol_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) modify_policy_2_svc;
+	  break;
+	  
+     case GET_POLICY:
+	  xdr_argument = xdr_gpol_arg;
+	  xdr_result = xdr_gpol_ret;
+	  local = (char *(*)()) get_policy_2_svc;
+	  break;
+
+     case GET_POLS:
+	  xdr_argument = xdr_gpols_arg;
+	  xdr_result = xdr_gpols_ret;
+	  local = (char *(*)()) get_pols_2_svc;
+	  break;
+	  
+     case GET_PRIVS:
+	  xdr_argument = xdr_u_int32;
+	  xdr_result = xdr_getprivs_ret;
+	  local = (char *(*)()) get_privs_2_svc;
+	  break;
+
+     case INIT:
+	  xdr_argument = xdr_u_int32;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) init_2_svc;
+	  break;
+
+     case CREATE_PRINCIPAL3:
+	  xdr_argument = xdr_cprinc3_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) create_principal3_2_svc;
+	  break;
+
+     case CHPASS_PRINCIPAL3:
+	  xdr_argument = xdr_chpass3_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) chpass_principal3_2_svc;
+	  break;
+
+     case CHRAND_PRINCIPAL3:
+	  xdr_argument = xdr_chrand3_arg;
+	  xdr_result = xdr_chrand_ret;
+	  local = (char *(*)()) chrand_principal3_2_svc;
+	  break;
+
+     case SETKEY_PRINCIPAL3:
+	  xdr_argument = xdr_setkey3_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) setkey_principal3_2_svc;
+	  break;
+
+     default:
+	  krb5_klog_syslog(LOG_ERR, "Invalid KADM5 procedure number: %s, %d",
+		 inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr),
+		 rqstp->rq_proc);
+	  svcerr_noproc(transp);
+	  return;
+     }
+     memset((char *)&argument, 0, sizeof(argument));
+     if (!svc_getargs(transp, xdr_argument, &argument)) {
+	  svcerr_decode(transp);
+	  return;
+     }
+     result = (*local)(&argument, rqstp);
+     if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+	  krb5_klog_syslog(LOG_ERR, "WARNING! Unable to send function results, "
+		 "continuing.");
+	  svcerr_systemerr(transp);
+     }
+     if (!svc_freeargs(transp, xdr_argument, &argument)) {
+	  krb5_klog_syslog(LOG_ERR, "WARNING! Unable to free arguments, "
+		 "continuing.");
+     }
+     return;
+}
+
+static int
+check_rpcsec_auth(struct svc_req *rqstp)
+{
+     gss_ctx_id_t ctx;
+     krb5_context kctx;
+     OM_uint32 maj_stat, min_stat;
+     gss_name_t name;
+     krb5_principal princ;
+     int ret, success;
+     krb5_data *c1, *c2, *realm;
+     gss_buffer_desc gss_str;
+     kadm5_server_handle_t handle;
+
+     success = 0;
+     handle = (kadm5_server_handle_t)global_server_handle;
+
+     if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS)
+	  return 0;
+
+     ctx = rqstp->rq_svccred;
+
+     maj_stat = gss_inquire_context(&min_stat, ctx, NULL, &name,
+				    NULL, NULL, NULL, NULL, NULL);
+     if (maj_stat != GSS_S_COMPLETE) {
+	  krb5_klog_syslog(LOG_ERR, "check_rpcsec_auth: "
+			   "failed inquire_context, stat=%u", maj_stat);
+	  log_badauth(maj_stat, min_stat,
+		      &rqstp->rq_xprt->xp_raddr, NULL);
+	  goto fail_name;
+     }
+
+     kctx = handle->context;
+     ret = gss_to_krb5_name(rqstp, kctx, name, &princ, &gss_str);
+     if (ret == 0)
+	  goto fail_name;
+
+     /*
+      * Since we accept with GSS_C_NO_NAME, the client can authenticate
+      * against the entire kdb.  Therefore, ensure that the service
+      * name is something reasonable.
+      */
+     if (krb5_princ_size(kctx, princ) != 2)
+	  goto fail_princ;
+
+     c1 = krb5_princ_component(kctx, princ, 0);
+     c2 = krb5_princ_component(kctx, princ, 1);
+     realm = krb5_princ_realm(kctx, princ);
+     if (strncmp(handle->params.realm, realm->data, realm->length) == 0
+	 && strncmp("kadmin", c1->data, c1->length) == 0) {
+
+	  if (strncmp("history", c2->data, c2->length) == 0)
+	       goto fail_princ;
+	  else
+	       success = 1;
+     }
+
+fail_princ:
+     if (!success) {
+	 krb5_klog_syslog(LOG_ERR, "bad service principal %.*s",
+			  gss_str.length, gss_str.value);
+     }
+     gss_release_buffer(&min_stat, &gss_str);
+     krb5_free_principal(kctx, princ);
+fail_name:
+     gss_release_name(&min_stat, &name);
+     return success;
+}
+
+static int
+gss_to_krb5_name(struct svc_req *rqstp, krb5_context ctx, gss_name_t gss_name,
+		 krb5_principal *princ, gss_buffer_t gss_str)
+{
+     OM_uint32 status, minor_stat;
+     gss_OID gss_type;
+     char *str;
+     int success;
+
+     status = gss_display_name(&minor_stat, gss_name, gss_str, &gss_type);
+     if ((status != GSS_S_COMPLETE) || (gss_type != gss_nt_krb5_name)) {
+	  krb5_klog_syslog(LOG_ERR,
+			   "gss_to_krb5_name: "
+			   "failed display_name status %d", status);
+	  log_badauth(status, minor_stat,
+		      &rqstp->rq_xprt->xp_raddr, NULL);
+	  return 0;
+     }
+     str = malloc(gss_str->length +1);
+     if (str == NULL)
+	  return 0;
+     *str = '\0';
+
+     strncat(str, gss_str->value, gss_str->length);
+     success = (krb5_parse_name(ctx, str, princ) == 0);
+     free(str);
+     return success;
+}
diff --git a/mechglue/src/kadmin/server/kadmind.M b/mechglue/src/kadmin/server/kadmind.M
new file mode 100644
index 000000000..3d359be3c
--- /dev/null
+++ b/mechglue/src/kadmin/server/kadmind.M
@@ -0,0 +1,243 @@
+.TH KADMIND 8
+.SH NAME
+kadmind \- KADM5 administration server
+.SH SYNOPSIS
+.B kadmind
+[\fB-r\fP \fIrealm\fP] [\fB\-m\fP] [\fB\-nofork\fP] [\fB\-port\fP
+\fIport-number\fP]
+.SH DESCRIPTION
+This command starts the KADM5 administration server.  The administration
+server runs on the master Kerberos server, which stores the KDC
+principal database and the KADM5 policy database.  
+.B Kadmind
+accepts remote requests to administer the information in these
+databases.  Remote requests are sent, for example, by
+.IR kadmin (8)
+and the
+.IR kpasswd (1)
+command, both of which are clients of
+.BR kadmind .
+.PP
+.B kadmind
+requires a number of configuration files to be set up in order
+for it to work:
+.TP "\w'kdc.conf\ \ 'u"
+kdc.conf
+The KDC configuration file contains configuration informatin for the KDC
+and the KADM5 system.  
+.B Kadmind
+understands a number of variable settings in this file, some of whch are
+mandatory and some of which are optional.  See the CONFIGURATION VALUES
+section below.
+.TP
+keytab
+.B Kadmind
+requires a keytab containing correct entries for the 
+.I kadmin/admin
+and
+.I kadmin/changepw
+principals for every realm that kadmind will answer requests for.  The
+keytab can be created with the
+.IR kadmin (8)
+client.  The location of the keytab is determined by the
+.I admin_keytab
+configuration variable (see CONFIGURATION VALUES).
+.TP
+ACL file
+.BR Kadmind 's
+ACL (access control list) tells it which principals are allowed to
+perform KADM5 administration actions.  The path of the ACL file is
+specified via the acl_file configuration variable (see CONFIGURATION
+VALUES).  The syntax of the ACL file is specified in the ACL FILE SYNTAX
+section below.
+.PP
+After the server begins running, it puts itself in the background and
+disassociates itself from its controlling terminal.
+.SH OPTIONS
+.TP
+\fB\-r\fP \fIrealm\fP
+specifies the default realm that kadmind will serve; if it is not
+specified, the default realm of the host is used.  
+.B kadmind
+will answer requests for any realm that exists in the local KDC database
+and for which the appropriate principals are in its keytab.
+.TP
+.B \-m
+specifies that the master database password should be fetched from the
+keyboard rather than from a file on disk.  Note that the server gets the
+password prior to putting itself in the background; in combination with
+the -nofork option, you must place it in the background by hand.
+.TP
+.B \-nofork
+specifies that the server does not put itself in the background and does
+not disassociate itself from the terminal.  In normal operation, you
+should always allow the server place itself in the background.
+.TP
+\fB\-port\fP \fIport-number\fB
+specifies the port on which the administration server listens for
+connections.  The default is is controlled by the 
+.I kadmind_port
+configuration variable (see below).
+.SH CONFIGURATION VALUES
+.PP
+In addition to the relations defined in kdc.conf(5), kadmind
+understands the following relations, all of which should
+appear in the [realms] section:
+.TP
+acl_file
+The path of kadmind's ACL file.  Mandatory.  No default.
+.TP
+dict_file
+The path of kadmind's password dictionary.  A principal with any
+password policy will not be allowed to select any password in the
+dictionary.  Optional.  No default.
+.TP
+admin_keytab
+The name of the keytab containing entries for the principals
+.I kadmin/admin
+and
+.I kadmin/changepw
+in each realm that
+.B kadmind
+will serve.  The default is the value of the 
+.SM KRB5_KTNAME
+environment variable, if defined.  Mandatory.
+.TP
+kadmind_port
+The
+.SM TCP
+port on which
+.B kadmind
+will listen.  The default is 749.
+.SH ACL FILE SYNTAX
+.PP
+The ACL file controls which principals can or cannot perform which
+administrative functions.  For operations that affect principals, the
+ACL file also controls which principals can operate on which other
+principals.  This file can contain comment lines, null lines or lines
+which contain ACL entries.  Comment lines start with the sharp sign
+(\fB\&#\fP) and continue until the end of the line.  Lines containing ACL
+entries have the format of
+.B principal
+.I whitespace
+.B operation-mask
+[\fIwhitespace\fP \fBoperation-target\fP]
+.PP
+Ordering is important.  The first matching entry is the one which will
+control access for a particular principal on a particular principal.
+.PP
+.IP principal
+may specify a partially or fully qualified Kerberos version 5
+principal name.  Each component of the name may be wildcarded using
+the asterisk (
+.B *
+) character.
+.IP operation-target
+[Optional] may specify a partially or fully qualified Kerberos version 5
+principal name.  Each component of the name may be wildcarded using the
+asterisk (
+.B *
+) character.
+.IP operation-mask
+Specifies what operations may or may not be peformed by a principal
+matching a particular entry.  This is a string of one or more of the
+following list of characters or their upper-case counterparts.  If the
+character is upper-case, then the operation is disallowed.  If the
+character is lower-case, then the operation is permitted.
+.RS
+.TP 5
+.B a
+[Dis]allows the addition of principals or policies in the database.
+.sp -1v
+.TP
+.B d
+[Dis]allows the deletion of principals or policies in the database.
+.sp -1v
+.TP
+.B m
+[Dis]allows the modification of principals or policies in the database.
+.sp -1v
+.TP
+.B c
+[Dis]allows the changing of passwords for principals in the database.
+.sp -1v
+.TP
+.B i
+[Dis]allows inquiries to the database.
+.sp -1v
+.TP
+.B l
+[Dis]allows the listing of principals or policies in the database.
+.sp -1v
+.TP
+.B x
+Short for
+.IR admcil .
+.sp -1v
+.TP
+.B \&*
+Same as
+.BR x .
+.RE
+Some examples of valid entries here are:
+.TP
+.I user/instance@realm adm
+A standard fully qualified name.  The
+.B operation-mask
+only applies to this principal and specifies that [s]he may add,
+delete or modify principals and policies, but not change anybody
+else's password.
+.TP
+.I user/instance@realm cim service/instance@realm
+A standard fully qualified name and a standard fully qualified target.  The
+.B operation-mask
+only applies to this principal operating on this target and specifies that
+[s]he may change the target's password, request information about the
+target and modify it.
+.TP
+.I user/*@realm ac
+A wildcarded name.  The
+.B operation-mask
+applies to all principals in realm "realm" whose first component is
+"user" and specifies that [s]he may add principals and change
+anybody's password.
+.TP
+.I user/*@realm i */instance@realm
+A wildcarded name and target.  The
+.B operation-mask
+applies to all principals in realm "realm" whose first component is
+"user" and specifies that [s]he may perform
+inquiries on principals whose second component is "instance" and realm
+is "realm".
+.SH FILES
+.TP "\w'<dbname>.kadm5.lock\ 'u"
+principal.db
+default name for Kerberos principal database
+.TP
+<dbname>.kadm5
+KADM5 administrative database.  (This would be "principal.kadm5", if you
+use the default database name.)  Contains policy information.
+.TP
+<dbname>.kadm5.lock
+lock file for the KADM5 administrative database.  This file works
+backwards from most other lock files.  I.e.,
+.B kadmin
+will exit with an error if this file does
+.I not
+exist.
+.TP
+kadm5.acl
+file containing list of principals and their
+.B kadmin
+administrative privileges.  See above for a description.
+.TP
+kadm5.keytab
+keytab file for
+.I kadmin/admin
+principal.
+.TP
+kadm5.dict
+file containing dictionary of strings explicitly disallowed as
+passwords.
+.SH SEE ALSO
+kpasswd(1), kadmin(8), kdb5_util(8), kadm5_export(8), kadm5_import(8)
diff --git a/mechglue/src/kadmin/server/misc.c b/mechglue/src/kadmin/server/misc.c
new file mode 100644
index 000000000..c623e55bd
--- /dev/null
+++ b/mechglue/src/kadmin/server/misc.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ */
+
+#include    <k5-int.h>
+#include    <krb5/kdb.h>
+#include    <kadm5/server_internal.h>
+#include    "misc.h"
+
+/*
+ * Function: chpass_principal_wrapper_3
+ * 
+ * Purpose: wrapper to kadm5_chpass_principal that checks to see if
+ *	    pw_min_life has been reached. if not it returns an error.
+ *	    otherwise it calls kadm5_chpass_principal
+ *
+ * Arguments:
+ *	principal	(input) krb5_principals whose password we are
+ *				changing
+ *	keepold 	(input) whether to preserve old keys
+ *	n_ks_tuple	(input) the number of key-salt tuples in ks_tuple
+ *	ks_tuple	(input) array of tuples indicating the caller's
+ *				requested enctypes/salttypes
+ *	password	(input) password we are going to change to.
+ * 	<return value>	0 on success error code on failure.
+ *
+ * Requires:
+ *	kadm5_init to have been run.
+ * 
+ * Effects:
+ *	calls kadm5_chpass_principal which changes the kdb and the
+ *	the admin db.
+ *
+ */
+kadm5_ret_t
+chpass_principal_wrapper_3(void *server_handle,
+			   krb5_principal principal,
+			   krb5_boolean keepold,
+			   int n_ks_tuple,
+			   krb5_key_salt_tuple *ks_tuple,
+			   char *password)
+{
+    kadm5_ret_t			ret;
+
+    ret = check_min_life(server_handle, principal, NULL, 0);
+    if (ret)
+	 return ret;
+
+    return kadm5_chpass_principal_3(server_handle, principal,
+				    keepold, n_ks_tuple, ks_tuple,
+				    password);
+}
+
+
+/*
+ * Function: randkey_principal_wrapper_3
+ * 
+ * Purpose: wrapper to kadm5_randkey_principal which checks the
+ *	    password's min. life.
+ *
+ * Arguments:
+ *	principal	    (input) krb5_principal whose password we are
+ *				    changing
+ *	keepold 	(input) whether to preserve old keys
+ *	n_ks_tuple	(input) the number of key-salt tuples in ks_tuple
+ *	ks_tuple	(input) array of tuples indicating the caller's
+ *				requested enctypes/salttypes
+ *	key		    (output) new random key
+ * 	<return value>	    0, error code on error.
+ *
+ * Requires:
+ *	kadm5_init	 needs to be run
+ * 
+ * Effects:
+ *	calls kadm5_randkey_principal
+ *
+ */
+kadm5_ret_t
+randkey_principal_wrapper_3(void *server_handle,
+			    krb5_principal principal,
+			    krb5_boolean keepold,
+			    int n_ks_tuple,
+			    krb5_key_salt_tuple *ks_tuple,
+			    krb5_keyblock **keys, int *n_keys)
+{
+    kadm5_ret_t			ret;
+
+    ret = check_min_life(server_handle, principal, NULL, 0);
+    if (ret)
+	 return ret;
+    return kadm5_randkey_principal_3(server_handle, principal,
+				     keepold, n_ks_tuple, ks_tuple,
+				     keys, n_keys);
+}
+
+kadm5_ret_t
+schpw_util_wrapper(void *server_handle, krb5_principal princ,
+		   char *new_pw, char **ret_pw,
+		   char *msg_ret, unsigned int msg_len)
+{
+    kadm5_ret_t ret;
+
+    ret = check_min_life(server_handle, princ, msg_ret, msg_len);
+    if (ret)
+	return ret;
+
+    return kadm5_chpass_principal_util(server_handle, princ,
+				       new_pw, ret_pw,
+				       msg_ret, msg_len);
+}
+
+kadm5_ret_t
+check_min_life(void *server_handle, krb5_principal principal,
+	       char *msg_ret, unsigned int msg_len)
+{
+    krb5_int32			now;
+    kadm5_ret_t			ret;
+    kadm5_policy_ent_rec	pol;
+    kadm5_principal_ent_rec	princ;
+    kadm5_server_handle_t	handle = server_handle;
+
+    if (msg_ret != NULL)
+	*msg_ret = '\0';
+
+    ret = krb5_timeofday(handle->context, &now);
+    if (ret)
+	return ret;
+
+    ret = kadm5_get_principal(handle->lhandle, principal, 
+			      &princ, KADM5_PRINCIPAL_NORMAL_MASK);
+    if(ret) 
+	 return ret;
+    if(princ.aux_attributes & KADM5_POLICY) {
+	if((ret=kadm5_get_policy(handle->lhandle,
+				 princ.policy, &pol)) != KADM5_OK) {
+	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
+	    return ret;
+	}
+	if((now - princ.last_pwd_change) < pol.pw_min_life &&
+	   !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+	    if (msg_ret != NULL) {
+		time_t until;
+		char *time_string, *ptr, *errstr;
+
+		until = princ.last_pwd_change + pol.pw_min_life;
+
+		time_string = ctime(&until);
+		errstr = error_message(CHPASS_UTIL_PASSWORD_TOO_SOON);
+
+		if (strlen(errstr) + strlen(time_string) >= msg_len) {
+		    *errstr = '\0';
+		} else {
+		    if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
+			*ptr = '\0';
+		    sprintf(msg_ret, errstr, time_string);
+		}
+	    }
+
+	    (void) kadm5_free_policy_ent(handle->lhandle, &pol);
+	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
+	    return KADM5_PASS_TOOSOON;
+	}
+
+	ret = kadm5_free_policy_ent(handle->lhandle, &pol);
+	if (ret) {
+	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
+	    return ret;
+        }
+    }
+
+    return kadm5_free_principal_ent(handle->lhandle, &princ);
+}
diff --git a/mechglue/src/kadmin/server/misc.h b/mechglue/src/kadmin/server/misc.h
new file mode 100644
index 000000000..b519ba079
--- /dev/null
+++ b/mechglue/src/kadmin/server/misc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1994 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ */
+
+kadm5_ret_t
+chpass_principal_wrapper_3(void *server_handle,
+			   krb5_principal principal,
+			   krb5_boolean keepold,
+			   int n_ks_tuple,
+			   krb5_key_salt_tuple *ks_tuple,
+			   char *password);
+
+kadm5_ret_t
+randkey_principal_wrapper_3(void *server_handle,
+			    krb5_principal principal,
+			    krb5_boolean keepold,
+			    int n_ks_tuple,
+			    krb5_key_salt_tuple *ks_tuple,
+			    krb5_keyblock **keys, int *n_keys);
+
+kadm5_ret_t
+schpw_util_wrapper(void *server_handle, krb5_principal princ,
+		   char *new_pw, char **ret_pw,
+		   char *msg_ret, unsigned int msg_len);
+
+kadm5_ret_t check_min_life(void *server_handle, krb5_principal principal,
+			   char *msg_ret, unsigned int msg_len);
+
+kadm5_ret_t kadm5_get_principal_v1(void *server_handle,
+				   krb5_principal principal, 
+				   kadm5_principal_ent_t_v1 *ent);
+
+kadm5_ret_t kadm5_get_policy_v1(void *server_handle, kadm5_policy_t name,
+				kadm5_policy_ent_t *ent);
+
+
+krb5_error_code process_chpw_request(krb5_context context, 
+				     void *server_handle, 
+				     char *realm, int s, 
+				     krb5_keytab keytab, 
+				     struct sockaddr_in *sockin, 
+				     krb5_data *req, krb5_data *rep);
+
+#ifdef SVC_GETARGS
+void  kadm_1(struct svc_req *, SVCXPRT *);
+#endif
diff --git a/mechglue/src/kadmin/server/ovsec_kadmd.c b/mechglue/src/kadmin/server/ovsec_kadmd.c
new file mode 100644
index 000000000..31cc25223
--- /dev/null
+++ b/mechglue/src/kadmin/server/ovsec_kadmd.c
@@ -0,0 +1,1215 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include    <stdio.h>
+#include    <signal.h>
+#include    <syslog.h>
+#include    <sys/types.h>
+#ifdef _AIX
+#include    <sys/select.h>
+#endif
+#include    <sys/time.h>
+#include    <sys/socket.h>
+#include    <unistd.h>
+#include    <netinet/in.h>
+#include    <arpa/inet.h>  /* inet_ntoa */
+#include    <netdb.h>
+#include    <gssrpc/rpc.h>
+#include    <gssapi/gssapi.h>
+#include    "gssapiP_krb5.h" /* for kg_get_context */
+#include    <gssrpc/auth_gssapi.h>
+#include    <kadm5/admin.h>
+#include    <kadm5/kadm_rpc.h>
+#include    <kadm5/server_acl.h>
+#include    <krb5/adm_proto.h>
+#include    "krb5/kdb_kt.h"	/* for krb5_ktkdb_set_context */
+#include    <string.h>
+#include    "kadm5/server_internal.h" /* XXX for kadm5_server_handle_t */
+
+#include    "misc.h"
+
+#ifdef PURIFY
+#include    "purify.h"
+
+int	signal_pure_report = 0;
+int	signal_pure_clear = 0;
+void	request_pure_report(int);
+void	request_pure_clear(int);
+#endif /* PURIFY */
+
+#if defined(NEED_DAEMON_PROTO)
+extern int daemon(int, int);
+#endif
+
+volatile int	signal_request_exit = 0;
+volatile int	signal_request_hup = 0;
+void    setup_signal_handlers(void);
+void	request_exit(int);
+void	request_hup(int);
+void	reset_db(void);
+void	sig_pipe(int);
+void	kadm_svc_run(kadm5_config_params *params);
+
+#ifdef POSIX_SIGNALS
+static struct sigaction s_action;
+#endif /* POSIX_SIGNALS */
+
+
+#define	TIMEOUT	15
+
+gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL;
+gss_name_t gss_kadmin_name = NULL;
+void *global_server_handle;
+
+/*
+ * This is a kludge, but the server needs these constants to be
+ * compatible with old clients.  They are defined in <kadm5/admin.h>,
+ * but only if USE_KADM5_API_VERSION == 1.
+ */
+#define OVSEC_KADM_ADMIN_SERVICE	"ovsec_adm/admin"
+#define OVSEC_KADM_CHANGEPW_SERVICE	"ovsec_adm/changepw"
+
+extern krb5_keyblock master_keyblock;
+
+char *build_princ_name(char *name, char *realm);
+void log_badauth(OM_uint32 major, OM_uint32 minor,
+		 struct sockaddr_in *addr, char *data);
+void log_badverf(gss_name_t client_name, gss_name_t server_name,
+		 struct svc_req *rqst, struct rpc_msg *msg,
+		 char *data);
+void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg, char
+		 *error, char *data);
+void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor);
+void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
+				  int rec);
+	
+int schpw;
+void do_schpw(int s, kadm5_config_params *params);
+
+#ifdef USE_PASSWORD_SERVER
+void kadm5_set_use_password_server (void);
+#endif
+
+/*
+ * Function: usage
+ * 
+ * Purpose: print out the server usage message
+ *
+ * Arguments:
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+
+static void usage()
+{
+     fprintf(stderr, "Usage: kadmind [-x db_args]* [-r realm] [-m] [-nofork] "
+#ifdef USE_PASSWORD_SERVER
+             "[-passwordserver] "
+#endif
+	     "[-port port-number]\n"
+	     "\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n"
+	     "\t\t\tLook at each database documentation for supported arguments\n"
+	     );
+     exit(1);
+}
+
+/*
+ * Function: display_status
+ *
+ * Purpose: displays GSS-API messages
+ *
+ * Arguments:
+ *
+ * 	msg		a string to be displayed with the message
+ * 	maj_stat	the GSS-API major status code
+ * 	min_stat	the GSS-API minor status code
+ *
+ * Effects:
+ *
+ * The GSS-API messages associated with maj_stat and min_stat are
+ * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
+ * followed by a newline.
+ */
+static void display_status_1(char *, OM_uint32, int);
+
+static void display_status(msg, maj_stat, min_stat)
+     char *msg;
+     OM_uint32 maj_stat;
+     OM_uint32 min_stat;
+{
+     display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
+     display_status_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static void display_status_1(m, code, type)
+     char *m;
+     OM_uint32 code;
+     int type;
+{
+	OM_uint32 maj_stat, min_stat;
+	gss_buffer_desc msg;
+	OM_uint32 msg_ctx;
+     
+	msg_ctx = 0;
+	while (1) {
+		maj_stat = gss_display_status(&min_stat, code,
+					      type, GSS_C_NULL_OID,
+					      &msg_ctx, &msg);
+		fprintf(stderr, "GSS-API error %s: %s\n", m,
+			(char *)msg.value); 
+		(void) gss_release_buffer(&min_stat, &msg);
+	  
+		if (!msg_ctx)
+			break;
+	}
+}
+
+
+/* XXX yuck.  the signal handlers need this */
+static krb5_context context;
+
+static krb5_context hctx;
+
+int main(int argc, char *argv[])
+{
+     register	SVCXPRT *transp;
+     extern	char *optarg;
+     extern	int optind, opterr;
+     int ret, nofork, oldnames = 0;
+     OM_uint32 OMret, major_status, minor_status;
+     char *whoami;
+     gss_buffer_desc in_buf;
+     struct sockaddr_in addr;
+     int s;
+     auth_gssapi_name names[4];
+     gss_buffer_desc gssbuf;
+     gss_OID nt_krb5_name_oid;
+     kadm5_config_params params;
+     char **db_args      = NULL;
+     int    db_args_size = 0;
+
+     setvbuf(stderr, NULL, _IONBF, 0);
+
+     /* This is OID value the Krb5_Name NameType */
+     gssbuf.value = "{1 2 840 113554 1 2 2 1}";
+     gssbuf.length = strlen(gssbuf.value);
+     major_status = gss_str_to_oid(&minor_status, &gssbuf, &nt_krb5_name_oid);
+     if (major_status != GSS_S_COMPLETE) {
+	     fprintf(stderr, "Couldn't create KRB5 Name NameType OID\n");
+	     display_status("str_to_oid", major_status, minor_status);
+	     exit(1);
+     }
+     
+     names[0].name = names[1].name = names[2].name = names[3].name = NULL;
+     names[0].type = names[1].type = names[2].type = names[3].type =
+	     nt_krb5_name_oid;
+
+#ifdef PURIFY
+     purify_start_batch();
+#endif /* PURIFY */
+     whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
+
+     nofork = 0;
+
+     memset((char *) ¶ms, 0, sizeof(params));
+     
+     argc--; argv++;
+     while (argc) {
+          if (strcmp(*argv, "-x") == 0) {
+	       argc--; argv++;
+	       if (!argc)
+		    usage();
+	       db_args_size++;
+	       {
+		   char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
+		   if( temp == NULL )
+		   {
+		       fprintf(stderr,"%s: cannot initialize. Not enough memory\n",
+			       whoami);
+		       exit(1);
+		   }
+		   db_args = temp;
+	       }
+	       db_args[db_args_size-1] = *argv;
+	       db_args[db_args_size]   = NULL;
+	  }else if (strcmp(*argv, "-r") == 0) {
+	       argc--; argv++;
+	       if (!argc)
+		    usage();
+	       params.realm = *argv;
+	       params.mask |= KADM5_CONFIG_REALM;
+	       argc--; argv++;
+	       continue;
+	  } else if (strcmp(*argv, "-m") == 0) {
+	       params.mkey_from_kbd = 1;
+	       params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+	  } else if (strcmp(*argv, "-nofork") == 0) {
+	       nofork = 1;
+#ifdef USE_PASSWORD_SERVER
+          } else if (strcmp(*argv, "-passwordserver") == 0) {
+              kadm5_set_use_password_server ();
+#endif              
+	  } else if(strcmp(*argv, "-port") == 0) {
+	    argc--; argv++;
+	    if(!argc)
+	      usage();
+	    params.kadmind_port = atoi(*argv);
+	    params.mask |= KADM5_CONFIG_KADMIND_PORT;
+	  } else
+	       break;
+	  argc--; argv++;
+     }
+     
+     if (argc != 0)
+	  usage();
+
+     if ((ret = krb5_init_context(&context))) {
+	  fprintf(stderr, "%s: %s while initializing context, aborting\n",
+		  whoami, error_message(ret));
+	  exit(1);
+     }
+
+     krb5_klog_init(context, "admin_server", whoami, 1);
+
+
+     krb5_klog_syslog(LOG_INFO, "Seeding random number generator");
+          ret = krb5_c_random_os_entropy(context, 1, NULL);
+	  if(ret) {
+	    krb5_klog_syslog(LOG_ERR, "Error getting random seed: %s, aborting",
+			     error_message(ret));
+	    exit(1);
+	  }
+	  
+     if((ret = kadm5_init("kadmind", NULL,
+			  NULL, ¶ms,
+			  KADM5_STRUCT_VERSION,
+			  KADM5_API_VERSION_2,
+			  db_args,
+			  &global_server_handle)) != 
+	KADM5_OK) {
+	 const char *e_txt = error_message(ret);
+	  krb5_klog_syslog(LOG_ERR, "%s while initializing, aborting",
+		 e_txt);
+	  fprintf(stderr, "%s: %s while initializing, aborting\n",
+		  whoami, e_txt);
+	  krb5_klog_close(context);
+	  exit(1);
+     }
+
+     if( db_args )
+     {
+	 free(db_args), db_args=NULL;
+     }
+     
+     if ((ret = kadm5_get_config_params(context, NULL, NULL, ¶ms,
+					¶ms))) {
+	 const char *e_txt = error_message(ret);
+	  krb5_klog_syslog(LOG_ERR, "%s: %s while initializing, aborting",
+			   whoami, e_txt);
+	  fprintf(stderr, "%s: %s while initializing, aborting\n",
+		  whoami, e_txt);
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);
+	  exit(1);
+     }
+
+#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE)
+
+     if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
+	  krb5_klog_syslog(LOG_ERR, "%s: Missing required configuration values "
+			   "while initializing, aborting", whoami,
+			   (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
+	  fprintf(stderr, "%s: Missing required configuration values "
+		  "(%lx) while initializing, aborting\n", whoami,
+		  (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
+	  krb5_klog_close(context);
+	  kadm5_destroy(global_server_handle);
+	  exit(1);
+     }
+
+     memset(&addr, 0, sizeof(addr));
+     addr.sin_family = AF_INET;
+     addr.sin_addr.s_addr = INADDR_ANY;
+     addr.sin_port = htons(params.kadmind_port);
+
+     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	 const char *e_txt = error_message(errno);
+	  krb5_klog_syslog(LOG_ERR, "Cannot create TCP socket: %s",
+			   e_txt);
+	  fprintf(stderr, "Cannot create TCP socket: %s",
+		  e_txt);
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);	  
+	  exit(1);
+     }
+
+     if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	 const char *e_txt = error_message(errno);
+	 krb5_klog_syslog(LOG_ERR,
+			   "cannot create simple chpw socket: %s",
+			   e_txt);
+	 fprintf(stderr, "Cannot create simple chpw socket: %s",
+		 e_txt);
+	 kadm5_destroy(global_server_handle);
+	 krb5_klog_close(context);
+	 exit(1);
+     }
+
+#ifdef SO_REUSEADDR
+     /* the old admin server turned on SO_REUSEADDR for non-default
+	port numbers.  this was necessary, on solaris, for the tests
+	to work.  jhawk argues that the debug and production modes
+	should be the same.  I think I agree, so I'm always going to set
+	SO_REUSEADDR.  The other option is to have the unit tests wait
+	until the port is useable, or use a different port each time.  
+	--marc */
+
+     {
+	 int	allowed;
+
+	 allowed = 1;
+	 if (setsockopt(s,
+			SOL_SOCKET,
+			SO_REUSEADDR,
+			(char *) &allowed,
+			sizeof(allowed)) < 0) {
+	     const char *e_txt = error_message(errno);
+	     krb5_klog_syslog(LOG_ERR, "Cannot set SO_REUSEADDR: %s",
+			      e_txt);
+	     fprintf(stderr, "Cannot set SO_REUSEADDR: %s",
+		     e_txt);
+	     kadm5_destroy(global_server_handle);
+	     krb5_klog_close(context);	  
+	     exit(1);
+	 }
+	 if (setsockopt(schpw, SOL_SOCKET, SO_REUSEADDR,
+			(char *) &allowed, sizeof(allowed)) < 0) {
+	     const char *e_txt = error_message(errno);
+	     krb5_klog_syslog(LOG_ERR, "main",
+			      "cannot set SO_REUSEADDR on simple chpw socket: %s", 
+			      e_txt);
+	     fprintf(stderr,
+		     "Cannot set SO_REUSEADDR on simple chpw socket: %s",
+ 		     e_txt);
+ 	     kadm5_destroy(global_server_handle);
+ 	     krb5_klog_close(context);
+	 }
+
+     }
+#endif /* SO_REUSEADDR */
+     memset(&addr, 0, sizeof(addr));
+     addr.sin_family = AF_INET;
+     addr.sin_addr.s_addr = INADDR_ANY;
+     addr.sin_port = htons(params.kadmind_port);
+
+     if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	  int oerrno = errno;
+	  const char *e_txt = error_message(errno);
+	  fprintf(stderr, "%s: Cannot bind socket.\n", whoami);
+	  fprintf(stderr, "bind: %s\n", e_txt);
+	  errno = oerrno;
+	  krb5_klog_syslog(LOG_ERR, "Cannot bind socket: %s",
+			   e_txt);
+	  if(oerrno == EADDRINUSE) {
+	       char *w = strrchr(whoami, '/');
+	       if (w) {
+		    w++;
+	       }
+	       else {
+		    w = whoami;
+	       }
+	       fprintf(stderr,
+"This probably means that another %s process is already\n"
+"running, or that another program is using the server port (number %d)\n"
+"after being assigned it by the RPC portmap daemon.  If another\n"
+"%s is already running, you should kill it before\n"
+"restarting the server.  If, on the other hand, another program is\n"
+"using the server port, you should kill it before running\n"
+"%s, and ensure that the conflict does not occur in the\n"
+"future by making sure that %s is started on reboot\n"
+		       "before portmap.\n", w, ntohs(addr.sin_port), w, w, w);
+	       krb5_klog_syslog(LOG_ERR, "Check for already-running %s or for "
+		      "another process using port %d", w,
+		      htons(addr.sin_port));
+	  }
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);
+	  exit(1);
+     }
+     memset(&addr, 0, sizeof(addr));
+     addr.sin_family = AF_INET;
+     addr.sin_addr.s_addr = INADDR_ANY;
+     /* XXX */
+     addr.sin_port = htons(params.kpasswd_port);
+
+     if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+	  char portbuf[32];
+	  int oerrno = errno;
+	  const char *e_txt = error_message(errno);
+	  fprintf(stderr, "%s: Cannot bind socket.\n", whoami);
+	  fprintf(stderr, "bind: %s\n", e_txt);
+	  errno = oerrno;
+	  sprintf(portbuf, "%d", ntohs(addr.sin_port));
+	  krb5_klog_syslog(LOG_ERR, "cannot bind simple chpw socket: %s",
+			   e_txt);
+	  if(oerrno == EADDRINUSE) {
+	       char *w = strrchr(whoami, '/');
+	       if (w) {
+		    w++;
+	       }
+	       else {
+		    w = whoami;
+	       }
+	       fprintf(stderr,
+"This probably means that another %s process is already\n"
+"running, or that another program is using the server port (number %d).\n"
+"If another %s is already running, you should kill it before\n"
+"restarting the server.\n",
+		       w, ntohs(addr.sin_port), w);
+ 	  }
+ 	  kadm5_destroy(global_server_handle);
+ 	  krb5_klog_close(context);
+	  exit(1);
+     }
+     
+     transp = svctcp_create(s, 0, 0);
+     if(transp == NULL) {
+	  fprintf(stderr, "%s: Cannot create RPC service.\n", whoami);
+	  krb5_klog_syslog(LOG_ERR, "Cannot create RPC service: %m");
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);	  
+	  exit(1);
+     }
+     if(!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) {
+	  fprintf(stderr, "%s: Cannot register RPC service.\n", whoami);
+	  krb5_klog_syslog(LOG_ERR, "Cannot register RPC service, failing.");
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);	  
+	  exit(1);
+     }
+
+     names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm);
+     names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm);
+     names[2].name = build_princ_name(OVSEC_KADM_ADMIN_SERVICE, params.realm);
+     names[3].name = build_princ_name(OVSEC_KADM_CHANGEPW_SERVICE,
+				      params.realm); 
+     if (names[0].name == NULL || names[1].name == NULL ||
+	 names[2].name == NULL || names[3].name == NULL) {
+	  krb5_klog_syslog(LOG_ERR,
+			   "Cannot build GSS-API authentication names, "
+			   "failing.");
+	  fprintf(stderr, "%s: Cannot build GSS-API authentication names.\n",
+		  whoami);
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);	  
+	  exit(1);
+     }
+
+     /*
+      * Go through some contortions to point gssapi at a kdb keytab.
+      * This prevents kadmind from needing to use an actual file-based
+      * keytab.
+      */
+     /* XXX extract kadm5's krb5_context */
+     hctx = ((kadm5_server_handle_t)global_server_handle)->context;
+     /* Set ktkdb's internal krb5_context. */
+     ret = krb5_ktkdb_set_context(hctx);
+     if (ret) {
+	  krb5_klog_syslog(LOG_ERR, "Can't set kdb keytab's internal context.");
+	  goto kterr;
+     }
+     /* XXX master_keyblock is in guts of lib/kadm5/server_kdb.c */
+     ret = krb5_db_set_mkey(hctx, &master_keyblock);
+     if (ret) {
+	  krb5_klog_syslog(LOG_ERR, "Can't set master key for kdb keytab.");
+	  goto kterr;
+     }
+     ret = krb5_kt_register(context, &krb5_kt_kdb_ops);
+     if (ret) {
+	  krb5_klog_syslog(LOG_ERR, "Can't register kdb keytab.");
+	  goto kterr;
+     }
+     /* Tell gssapi about the kdb keytab. */
+     ret = krb5_gss_register_acceptor_identity("KDB:");
+     if (ret) {
+	  krb5_klog_syslog(LOG_ERR, "Can't register acceptor keytab.");
+	  goto kterr;
+     }
+kterr:
+     if (ret) {
+	  krb5_klog_syslog(LOG_ERR, "%s", error_message(ret));
+	  fprintf(stderr, "%s: Can't set up keytab for RPC.\n", whoami);
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);
+	  exit(1);
+     }
+
+     /*
+      * Try to acquire creds for the old OV services as well as the
+      * new names, but if that fails just fall back on the new names.
+      */
+     if (svcauth_gssapi_set_names(names, 4) == TRUE)
+	  oldnames++;
+     if (!oldnames && svcauth_gssapi_set_names(names, 2) == FALSE) {
+	  krb5_klog_syslog(LOG_ERR,
+			   "Cannot set GSS-API authentication names (keytab not present?), "
+			   "failing.");
+	  fprintf(stderr, "%s: Cannot set GSS-API authentication names.\n",
+		  whoami);
+	  svcauth_gssapi_unset_names();
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);	  
+	  exit(1);
+     }
+
+     /* if set_names succeeded, this will too */
+     in_buf.value = names[1].name;
+     in_buf.length = strlen(names[1].name) + 1;
+     (void) gss_import_name(&OMret, &in_buf, nt_krb5_name_oid,
+			    &gss_changepw_name);
+     if (oldnames) {
+	  in_buf.value = names[3].name;
+	  in_buf.length = strlen(names[3].name) + 1;
+	  (void) gss_import_name(&OMret, &in_buf, nt_krb5_name_oid,
+				 &gss_oldchangepw_name);
+     }
+
+     svcauth_gssapi_set_log_badauth_func(log_badauth, NULL);
+     svcauth_gssapi_set_log_badverf_func(log_badverf, NULL);
+     svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL);
+     
+     svcauth_gss_set_log_badauth_func(log_badauth, NULL);
+     svcauth_gss_set_log_badverf_func(log_badverf, NULL);
+     svcauth_gss_set_log_miscerr_func(log_miscerr, NULL);
+     
+     if (svcauth_gss_set_svc_name(GSS_C_NO_NAME) != TRUE) {
+	 fprintf(stderr, "%s: Cannot initialize RPCSEC_GSS service name.\n",
+		 whoami);
+	 exit(1);
+     }
+
+     if ((ret = kadm5int_acl_init(context, 0, params.acl_file))) {
+	  krb5_klog_syslog(LOG_ERR, "Cannot initialize acl file: %s",
+		 error_message(ret));
+	  fprintf(stderr, "%s: Cannot initialize acl file: %s\n",
+		  whoami, error_message(ret));
+	  svcauth_gssapi_unset_names();
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);
+	  exit(1);
+     }
+
+     if (!nofork && (ret = daemon(0, 0))) {
+	  ret = errno;
+	  krb5_klog_syslog(LOG_ERR, "Cannot detach from tty: %s", error_message(ret));
+	  fprintf(stderr, "%s: Cannot detach from tty: %s\n",
+		  whoami, error_message(ret));
+	  svcauth_gssapi_unset_names();
+	  kadm5_destroy(global_server_handle);
+	  krb5_klog_close(context);
+	  exit(1);
+     }
+     
+     setup_signal_handlers();
+     krb5_klog_syslog(LOG_INFO, "starting");
+     kadm_svc_run(¶ms);
+     krb5_klog_syslog(LOG_INFO, "finished, exiting");
+
+     /* Clean up memory, etc */
+     svcauth_gssapi_unset_names();
+     kadm5_destroy(global_server_handle);
+     close(s);
+     kadm5int_acl_finish(context, 0);
+     if(gss_changepw_name) {
+          (void) gss_release_name(&OMret, &gss_changepw_name);
+     }
+     if(gss_oldchangepw_name) {
+          (void) gss_release_name(&OMret, &gss_oldchangepw_name);
+     }
+     for(s = 0 ; s < 4; s++) {
+          if (names[s].name) {
+	        free(names[s].name);
+	  }
+     }
+
+     krb5_klog_close(context);
+     krb5_free_context(context);
+     exit(2);
+}
+
+/*
+ * Function: setup_signal_handlers
+ *
+ * Purpose: Setup signal handling functions using POSIX's sigaction()
+ * if possible, otherwise with System V's signal().
+ */
+
+void setup_signal_handlers(void) {
+#ifdef POSIX_SIGNALS
+     (void) sigemptyset(&s_action.sa_mask);
+     s_action.sa_handler = request_exit;
+     (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
+     (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
+     (void) sigaction(SIGQUIT, &s_action, (struct sigaction *) NULL);
+     s_action.sa_handler = request_hup;
+     (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
+     s_action.sa_handler = sig_pipe;
+     (void) sigaction(SIGPIPE, &s_action, (struct sigaction *) NULL);
+#ifdef PURIFY
+     s_action.sa_handler = request_pure_report;
+     (void) sigaction(SIGUSR1, &s_action, (struct sigaction *) NULL);
+     s_action.sa_handler = request_pure_clear;
+     (void) sigaction(SIGUSR2, &s_action, (struct sigaction *) NULL);
+#endif /* PURIFY */
+#else /* POSIX_SIGNALS */
+     signal(SIGINT, request_exit);
+     signal(SIGTERM, request_exit);
+     signal(SIGQUIT, request_exit);
+     signal(SIGHUP, request_hup);
+     signal(SIGPIPE, sig_pipe);
+#ifdef PURIFY
+     signal(SIGUSR1, request_pure_report);
+     signal(SIGUSR2, request_pure_clear);
+#endif /* PURIFY */
+#endif /* POSIX_SIGNALS */
+}
+
+/*
+ * Function: kadm_svc_run
+ * 
+ * Purpose: modified version of sunrpc svc_run.
+ *	    which closes the database every TIMEOUT seconds.
+ *
+ * Arguments:
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+
+void kadm_svc_run(params)
+kadm5_config_params *params;
+{
+     fd_set	rfd;
+     struct	timeval	    timeout;
+     
+     while(signal_request_exit == 0) {
+	  if (signal_request_hup) {
+	      reset_db();
+	      krb5_klog_reopen(context);
+	      signal_request_hup = 0;
+	  }
+#ifdef PURIFY
+	  if (signal_pure_report)	/* check to see if a report */
+					/* should be dumped... */
+	    {
+	      purify_new_reports();
+	      signal_pure_report = 0;
+	    }
+	  if (signal_pure_clear)	/* ...before checking whether */
+					/* the info should be cleared. */
+	    {
+	      purify_clear_new_reports();
+	      signal_pure_clear = 0;
+	    }
+#endif /* PURIFY */
+	  timeout.tv_sec = TIMEOUT;
+	  timeout.tv_usec = 0;
+	  rfd = svc_fdset;
+	  FD_SET(schpw, &rfd);
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+	  switch(select(max(schpw, svc_maxfd) + 1,
+			(fd_set *) &rfd, NULL, NULL, &timeout)) {
+	  case -1:
+	       if(errno == EINTR)
+		    continue;
+	       perror("select");
+	       return;
+	  case 0:
+	       reset_db();
+	       break;
+	  default:
+	      if (FD_ISSET(schpw, &rfd))
+		  do_schpw(schpw, params);
+	      else
+		  svc_getreqset(&rfd);
+	  }
+     }
+}
+
+#ifdef PURIFY
+/*
+ * Function: request_pure_report
+ * 
+ * Purpose: sets flag saying the server got a signal and that it should
+ *		dump a purify report when convenient.
+ *
+ * Arguments:
+ * Requires:
+ * Effects:
+ * Modifies:
+ *	sets signal_pure_report to one
+ */
+
+void request_pure_report(int signum)
+{
+     krb5_klog_syslog(LOG_DEBUG, "Got signal to request a Purify report");
+     signal_pure_report = 1;
+     return;
+}
+
+/*
+ * Function: request_pure_clear
+ * 
+ * Purpose: sets flag saying the server got a signal and that it should
+ *		dump a purify report when convenient, then clear the
+ *		purify tables.
+ *
+ * Arguments:
+ * Requires:
+ * Effects:
+ * Modifies:
+ *	sets signal_pure_report to one
+ *	sets signal_pure_clear to one
+ */
+
+void request_pure_clear(int signum)
+{
+     krb5_klog_syslog(LOG_DEBUG, "Got signal to request a Purify report and clear the old Purify info");
+     signal_pure_report = 1;
+     signal_pure_clear = 1;
+     return;
+}
+#endif /* PURIFY */
+
+/*
+ * Function: request_hup
+ * 
+ * Purpose: sets flag saying the server got a signal and that it should
+ *		reset the database files when convenient.
+ *
+ * Arguments:
+ * Requires:
+ * Effects:
+ * Modifies:
+ *	sets signal_request_hup to one
+ */
+
+void request_hup(int signum)
+{
+     signal_request_hup = 1;
+     return;
+}
+
+/*
+ * Function: reset_db
+ * 
+ * Purpose: flushes the currently opened database files to disk.
+ *
+ * Arguments:
+ * Requires:
+ * Effects:
+ * 
+ * Currently, just sets signal_request_reset to 0.  The kdb and adb
+ * libraries used to be sufficiently broken that it was prudent to
+ * close and reopen the databases periodically.  They are no longer
+ * that broken, so this function is not necessary.
+ */
+void reset_db(void)
+{
+#ifdef notdef
+     kadm5_ret_t ret;
+     
+     if (ret = kadm5_flush(global_server_handle)) {
+	  krb5_klog_syslog(LOG_ERR, "FATAL ERROR!  %s while flushing databases.  "
+		 "Databases may be corrupt!  Aborting.",
+		 error_message(ret));
+	  krb5_klog_close(context);
+	  exit(3);
+     }
+#endif
+
+     return;
+}
+
+/*
+ * Function: request_exit
+ * 
+ * Purpose: sets flags saying the server got a signal and that it
+ *	    should exit when convient.
+ *
+ * Arguments:
+ * Requires:
+ * Effects:
+ *	modifies signal_request_exit which ideally makes the server exit
+ *	at some point.
+ *
+ * Modifies:
+ *	signal_request_exit
+ */
+
+void request_exit(int signum)
+{
+     krb5_klog_syslog(LOG_DEBUG, "Got signal to request exit");
+     signal_request_exit = 1;
+     return;
+}
+
+/*
+ * Function: sig_pipe
+ *
+ * Purpose: SIGPIPE handler
+ *
+ * Effects: krb5_klog_syslogs a message that a SIGPIPE occurred and returns,
+ * thus causing the read() or write() to fail and, presumable, the RPC
+ * to recover.  Otherwise, the process aborts.
+ */
+void sig_pipe(int unused)
+{
+     krb5_klog_syslog(LOG_NOTICE, "Warning: Received a SIGPIPE; probably a "
+	    "client aborted.  Continuing.");
+     return;
+}
+
+/*
+ * Function: build_princ_name
+ * 
+ * Purpose: takes a name and a realm and builds a string that can be
+ *	    consumed by krb5_parse_name.
+ *
+ * Arguments:
+ *	name		    (input) name to be part of principal
+ *	realm		    (input) realm part of principal
+ * 	<return value>	    char * pointing to "name@realm"
+ *
+ * Requires:
+ *	name be non-null.
+ * 
+ * Effects:
+ * Modifies:
+ */
+
+char *build_princ_name(char *name, char *realm)
+{
+     char *fullname;
+
+     fullname = (char *) malloc(strlen(name) + 1 +
+				(realm ? strlen(realm) + 1 : 0));
+     if (fullname == NULL)
+	  return NULL;
+     if (realm)
+	  sprintf(fullname, "%s@%s", name, realm);
+     else
+	  strcpy(fullname, name);
+     return fullname;
+}
+
+/*
+ * Function: log_badverf
+ *
+ * Purpose: Call from GSS-API Sun RPC for garbled/forged/replayed/etc
+ * messages.
+ *
+ * Argiments:
+ * 	client_name	(r) GSS-API client name
+ * 	server_name	(r) GSS-API server name
+ * 	rqst		(r) RPC service request
+ * 	msg		(r) RPC message
+ * 	data		(r) arbitrary data (NULL), not used
+ *
+ * Effects:
+ *
+ * Logs the invalid request via krb5_klog_syslog(); see functional spec for
+ * format.
+ */
+void log_badverf(gss_name_t client_name, gss_name_t server_name,
+		 struct svc_req *rqst, struct rpc_msg *msg, char
+		 *data)
+{
+     struct procnames {
+	  rpcproc_t proc;
+	  const char *proc_name;
+     };
+     static const struct procnames proc_names[] = {
+	  {1, "CREATE_PRINCIPAL"},
+	  {2, "DELETE_PRINCIPAL"},
+	  {3, "MODIFY_PRINCIPAL"},
+	  {4, "RENAME_PRINCIPAL"},
+	  {5, "GET_PRINCIPAL"},
+	  {6, "CHPASS_PRINCIPAL"},
+	  {7, "CHRAND_PRINCIPAL"},
+	  {8, "CREATE_POLICY"},
+	  {9, "DELETE_POLICY"},
+	  {10, "MODIFY_POLICY"},
+	  {11, "GET_POLICY"},
+	  {12, "GET_PRIVS"},
+	  {13, "INIT"},
+	  {14, "GET_PRINCS"},
+	  {15, "GET_POLS"},
+	  {16, "SETKEY_PRINCIPAL"},
+	  {17, "SETV4KEY_PRINCIPAL"},
+	  {18, "CREATE_PRINCIPAL3"},
+	  {19, "CHPASS_PRINCIPAL3"},
+	  {20, "CHRAND_PRINCIPAL3"},
+	  {21, "SETKEY_PRINCIPAL3"}
+     };
+#define NPROCNAMES (sizeof (proc_names) / sizeof (struct procnames))
+     OM_uint32 minor;
+     gss_buffer_desc client, server;
+     gss_OID gss_type;
+     char *a;
+     rpcproc_t proc;
+     int i;
+     const char *procname;
+
+     (void) gss_display_name(&minor, client_name, &client, &gss_type);
+     (void) gss_display_name(&minor, server_name, &server, &gss_type);
+     if (client.value == NULL)
+	 client.value = "(null)";
+     if (server.value == NULL)
+	 server.value = "(null)";
+     a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
+
+     proc = msg->rm_call.cb_proc;
+     procname = NULL;
+     for (i = 0; i < NPROCNAMES; i++) {
+	  if (proc_names[i].proc == proc) {
+	       procname = proc_names[i].proc_name;
+	       break;
+	  }
+     }
+     if (procname != NULL)
+	  krb5_klog_syslog(LOG_NOTICE, "WARNING! Forged/garbled request: %s, "
+			   "claimed client = %s, server = %s, addr = %s",
+			   procname, client.value,
+			   server.value, a);
+     else
+	  krb5_klog_syslog(LOG_NOTICE, "WARNING! Forged/garbled request: %d, "
+			   "claimed client = %s, server = %s, addr = %s",
+			   proc, client.value,
+			   server.value, a);
+
+     (void) gss_release_buffer(&minor, &client);
+     (void) gss_release_buffer(&minor, &server);
+}
+
+/*
+ * Function: log_miscerr
+ *
+ * Purpose: Callback from GSS-API Sun RPC for miscellaneous errors
+ *
+ * Arguments:
+ * 	rqst		(r) RPC service request
+ * 	msg		(r) RPC message
+ *	error		(r) error message from RPC
+ * 	data		(r) arbitrary data (NULL), not used
+ *
+ * Effects:
+ *
+ * Logs the error via krb5_klog_syslog(); see functional spec for
+ * format.
+ */
+void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
+		 char *error, char *data)
+{
+     char *a;
+     
+     a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
+     krb5_klog_syslog(LOG_NOTICE, "Miscellaneous RPC error: %s, %s", a, error);
+}
+
+
+
+/*
+ * Function: log_badauth
+ *
+ * Purpose: Callback from GSS-API Sun RPC for authentication
+ * failures/errors.
+ *
+ * Arguments:
+ * 	major 		(r) GSS-API major status
+ * 	minor		(r) GSS-API minor status
+ * 	addr		(r) originating address
+ * 	data		(r) arbitrary data (NULL), not used
+ *
+ * Effects:
+ *
+ * Logs the GSS-API error via krb5_klog_syslog(); see functional spec for
+ * format.
+ */
+void log_badauth(OM_uint32 major, OM_uint32 minor,
+		 struct sockaddr_in *addr, char *data)
+{
+     char *a;
+     
+     /* Authentication attempt failed: <IP address>, <GSS-API error */
+     /* strings> */
+
+     a = inet_ntoa(addr->sin_addr);
+
+     krb5_klog_syslog(LOG_NOTICE, "Authentication attempt failed: %s, GSS-API "
+	    "error strings are:", a);
+     log_badauth_display_status("   ", major, minor);
+     krb5_klog_syslog(LOG_NOTICE, "   GSS-API error strings complete.");
+}
+
+void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor)
+{
+     log_badauth_display_status_1(msg, major, GSS_C_GSS_CODE, 0);
+     log_badauth_display_status_1(msg, minor, GSS_C_MECH_CODE, 0);
+}
+
+void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
+				  int rec)
+{
+     OM_uint32 gssstat, minor_stat;
+     gss_buffer_desc msg;
+     OM_uint32 msg_ctx;
+
+     msg_ctx = 0;
+     while (1) {
+	  gssstat = gss_display_status(&minor_stat, code,
+				       type, GSS_C_NULL_OID,
+				       &msg_ctx, &msg);
+	  if (gssstat != GSS_S_COMPLETE) {
+ 	       if (!rec) {
+		    log_badauth_display_status_1(m,gssstat,GSS_C_GSS_CODE,1); 
+		    log_badauth_display_status_1(m, minor_stat,
+						 GSS_C_MECH_CODE, 1);
+	       } else
+		    krb5_klog_syslog(LOG_ERR, "GSS-API authentication error %s: "
+			   "recursive failure!", msg);
+	       return;
+	  }
+
+	  krb5_klog_syslog(LOG_NOTICE, "%s %s", m, (char *)msg.value); 
+	  (void) gss_release_buffer(&minor_stat, &msg);
+	  
+	  if (!msg_ctx)
+	       break;
+     }
+}
+
+void do_schpw(int s1, kadm5_config_params *params)
+{
+    krb5_error_code ret;
+    /* XXX buffer = ethernet mtu */
+    char req[1500];
+    int len;
+    struct sockaddr_in from;
+    socklen_t fromlen;
+    krb5_keytab kt;
+    krb5_data reqdata, repdata;
+    int s2;
+
+    fromlen = sizeof(from);
+    if ((len = recvfrom(s1, req, sizeof(req), 0, (struct sockaddr *)&from,
+			&fromlen)) < 0) {
+	krb5_klog_syslog(LOG_ERR, "chpw: Couldn't receive request: %s",
+			 error_message(errno));
+	return;
+    }
+
+    if ((ret = krb5_kt_resolve(context, "KDB:", &kt))) {
+	krb5_klog_syslog(LOG_ERR, "chpw: Couldn't open admin keytab %s",
+			 error_message(ret));
+	return;
+    }
+
+    reqdata.length = len;
+    reqdata.data = req;
+
+    /* this is really obscure.  s1 is used for all communications.  it
+       is left unconnected in case the server is multihomed and routes
+       are asymmetric.  s2 is connected to resolve routes and get
+       addresses.  this is the *only* way to get proper addresses for
+       multihomed hosts if routing is asymmetric.  
+
+       A related problem in the server, but not the client, is that
+       many os's have no way to disconnect a connected udp socket, so
+       the s2 socket needs to be closed and recreated for each
+       request.  The s1 socket must not be closed, or else queued
+       requests will be lost.
+
+       A "naive" client implementation (one socket, no connect,
+       hostname resolution to get the local ip addr) will work and
+       interoperate if the client is single-homed. */
+
+    if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	krb5_klog_syslog(LOG_ERR, "cannot create connecting socket: %s",
+			 error_message(errno));
+	fprintf(stderr, "Cannot create connecting socket: %s",
+		error_message(errno));
+	svcauth_gssapi_unset_names();
+	kadm5_destroy(global_server_handle);
+	krb5_klog_close(context);	  
+	exit(1);
+    }
+
+    if (connect(s2, (struct sockaddr *) &from, sizeof(from)) < 0) {
+	krb5_klog_syslog(LOG_ERR, "chpw: Couldn't connect to client: %s",
+			 error_message(errno));
+	goto cleanup;
+    }
+
+    if ((ret = process_chpw_request(context, global_server_handle,
+				    params->realm, s2, kt, &from,
+				    &reqdata, &repdata))) {
+	krb5_klog_syslog(LOG_ERR, "chpw: Error processing request: %s", 
+			 error_message(ret));
+    }
+
+    close(s2);
+
+    if (repdata.length == 0) {
+	/* just return.  This means something really bad happened */
+        goto cleanup;
+    }
+
+    len = sendto(s1, repdata.data, (int) repdata.length, 0,
+		 (struct sockaddr *) &from, sizeof(from));
+
+    if (len < (int) repdata.length) {
+	krb5_xfree(repdata.data);
+
+	krb5_klog_syslog(LOG_ERR, "chpw: Error sending reply: %s", 
+			 error_message(errno));
+	goto cleanup;
+    }
+
+    krb5_xfree(repdata.data);
+
+cleanup:
+    krb5_kt_close(context, kt);
+
+    return;
+}
+
diff --git a/mechglue/src/kadmin/server/schpw.c b/mechglue/src/kadmin/server/schpw.c
new file mode 100644
index 000000000..8c676c08c
--- /dev/null
+++ b/mechglue/src/kadmin/server/schpw.c
@@ -0,0 +1,406 @@
+#include "k5-int.h"
+#include <kadm5/admin.h>
+#include <syslog.h>
+#include <krb5/adm_proto.h>	/* krb5_klog_syslog */
+#include <stdio.h>
+#include <errno.h>
+
+#include "misc.h"
+
+#ifndef GETSOCKNAME_ARG3_TYPE
+#define GETSOCKNAME_ARG3_TYPE int
+#endif
+
+krb5_error_code
+process_chpw_request(context, server_handle, realm, s, keytab, sockin, 
+		     req, rep)
+     krb5_context context;
+     void *server_handle;
+     char *realm;
+     int s;
+     krb5_keytab keytab;
+     struct sockaddr_in *sockin;
+     krb5_data *req;
+     krb5_data *rep;
+{
+    krb5_error_code ret;
+    char *ptr;
+    int plen, vno;
+    krb5_address local_kaddr, remote_kaddr;
+    int allocated_mem = 0;  
+    krb5_data ap_req, ap_rep;
+    krb5_auth_context auth_context;
+    krb5_principal changepw;
+    krb5_ticket *ticket;
+    krb5_data cipher, clear;
+    struct sockaddr local_addr, remote_addr;
+    GETSOCKNAME_ARG3_TYPE addrlen;
+    krb5_replay_data replay;
+    krb5_error krberror;
+    int numresult;
+    char strresult[1024];
+    char *clientstr;
+
+    ret = 0;
+    rep->length = 0;
+
+    auth_context = NULL;
+    changepw = NULL;
+    ap_rep.length = 0;
+    ticket = NULL;
+    clear.length = 0;
+    cipher.length = 0;
+
+    if (req->length < 4) {
+	/* either this, or the server is printing bad messages,
+	   or the caller passed in garbage */
+	ret = KRB5KRB_AP_ERR_MODIFIED;
+	numresult = KRB5_KPASSWD_MALFORMED;
+	strcpy(strresult, "Request was truncated");
+	goto chpwfail;
+    }
+
+    ptr = req->data;
+
+    /* verify length */
+
+    plen = (*ptr++ & 0xff);
+    plen = (plen<<8) | (*ptr++ & 0xff);
+
+    if (plen != req->length)
+	return(KRB5KRB_AP_ERR_MODIFIED);
+
+    /* verify version number */
+
+    vno = (*ptr++ & 0xff) ;
+    vno = (vno<<8) | (*ptr++ & 0xff);
+
+    if (vno != 1) {
+	ret = KRB5KDC_ERR_BAD_PVNO;
+	numresult = KRB5_KPASSWD_BAD_VERSION;
+	sprintf(strresult,
+		"Request contained unknown protocol version number %d", vno);
+	goto chpwfail;
+    }
+
+    /* read, check ap-req length */
+
+    ap_req.length = (*ptr++ & 0xff);
+    ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff);
+
+    if (ptr + ap_req.length >= req->data + req->length) {
+	ret = KRB5KRB_AP_ERR_MODIFIED;
+	numresult = KRB5_KPASSWD_MALFORMED;
+	strcpy(strresult, "Request was truncated in AP-REQ");
+	goto chpwfail;
+    }
+
+    /* verify ap_req */
+
+    ap_req.data = ptr;
+    ptr += ap_req.length;
+
+    ret = krb5_auth_con_init(context, &auth_context);
+    if (ret) {
+	numresult = KRB5_KPASSWD_HARDERROR;
+	strcpy(strresult, "Failed initializing auth context");
+	goto chpwfail;
+    }
+
+    ret = krb5_auth_con_setflags(context, auth_context,
+				 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+    if (ret) {
+	numresult = KRB5_KPASSWD_HARDERROR;
+	strcpy(strresult, "Failed initializing auth context");
+	goto chpwfail;
+    }
+	
+    ret = krb5_build_principal(context, &changepw, strlen(realm), realm,
+			       "kadmin", "changepw", NULL);
+    if (ret) {
+	numresult = KRB5_KPASSWD_HARDERROR;
+	strcpy(strresult, "Failed building kadmin/changepw principal");
+	goto chpwfail;
+    }
+
+    ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab,
+		      NULL, &ticket);
+
+    if (ret) {
+	numresult = KRB5_KPASSWD_AUTHERROR;
+	strcpy(strresult, "Failed reading application request");
+	goto chpwfail;
+    }
+
+    /* set up address info */
+
+    addrlen = sizeof(local_addr);
+
+    if (getsockname(s, &local_addr, &addrlen) < 0) {
+	ret = errno;
+	numresult = KRB5_KPASSWD_HARDERROR;
+	strcpy(strresult, "Failed getting server internet address");
+	goto chpwfail;
+    }
+
+    /* some brain-dead OS's don't return useful information from
+     * the getsockname call.  Namely, windows and solaris.  */
+
+    if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) {
+	local_kaddr.addrtype = ADDRTYPE_INET;
+	local_kaddr.length =
+	    sizeof(((struct sockaddr_in *) &local_addr)->sin_addr);
+	local_kaddr.contents = 
+	    (krb5_octet *) &(((struct sockaddr_in *) &local_addr)->sin_addr);
+    } else {
+	krb5_address **addrs;
+
+	krb5_os_localaddr(context, &addrs);
+	local_kaddr.magic = addrs[0]->magic;
+	local_kaddr.addrtype = addrs[0]->addrtype;
+	local_kaddr.length = addrs[0]->length;
+	local_kaddr.contents = malloc(addrs[0]->length);
+	memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
+	allocated_mem++;
+
+	krb5_free_addresses(context, addrs);
+    }
+
+    addrlen = sizeof(remote_addr);
+
+    if (getpeername(s, &remote_addr, &addrlen) < 0) {
+	ret = errno;
+	numresult = KRB5_KPASSWD_HARDERROR;
+	strcpy(strresult, "Failed getting client internet address");
+	goto chpwfail;
+    }
+
+    remote_kaddr.addrtype = ADDRTYPE_INET;
+    remote_kaddr.length =
+	sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr);
+    remote_kaddr.contents = 
+	(krb5_octet *) &(((struct sockaddr_in *) &remote_addr)->sin_addr);
+    
+    remote_kaddr.addrtype = ADDRTYPE_INET;
+    remote_kaddr.length = sizeof(sockin->sin_addr);
+    remote_kaddr.contents = (krb5_octet *) &sockin->sin_addr;
+    
+    /* mk_priv requires that the local address be set.
+       getsockname is used for this.  rd_priv requires that the
+       remote address be set.  recvfrom is used for this.  If
+       rd_priv is given a local address, and the message has the
+       recipient addr in it, this will be checked.  However, there
+       is simply no way to know ahead of time what address the
+       message will be delivered *to*.  Therefore, it is important
+       that either no recipient address is in the messages when
+       mk_priv is called, or that no local address is passed to
+       rd_priv.  Both is a better idea, and I have done that.  In
+       summary, when mk_priv is called, *only* a local address is
+       specified.  when rd_priv is called, *only* a remote address
+       is specified.  Are we having fun yet?  */
+
+    ret = krb5_auth_con_setaddrs(context, auth_context, NULL,
+			     &remote_kaddr);
+    if (ret) {
+	numresult = KRB5_KPASSWD_HARDERROR;
+	strcpy(strresult, "Failed storing client internet address");
+	goto chpwfail;
+    }
+
+    /* verify that this is an AS_REQ ticket */
+
+    if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) {
+	numresult = KRB5_KPASSWD_AUTHERROR;
+	strcpy(strresult, "Ticket must be derived from a password");
+	goto chpwfail;
+    }
+
+    /* construct the ap-rep */
+
+    ret = krb5_mk_rep(context, auth_context, &ap_rep);
+    if (ret) {
+	numresult = KRB5_KPASSWD_AUTHERROR;
+	strcpy(strresult, "Failed replying to application request");
+	goto chpwfail;
+    }
+
+    /* decrypt the new password */
+
+    cipher.length = (req->data + req->length) - ptr;
+    cipher.data = ptr;
+
+    ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay);
+    if (ret) {
+	numresult = KRB5_KPASSWD_HARDERROR;
+	strcpy(strresult, "Failed decrypting request");
+	goto chpwfail;
+    }
+
+    ret = krb5_unparse_name(context, ticket->enc_part2->client, &clientstr);
+    if (ret) {
+	numresult = KRB5_KPASSWD_HARDERROR;
+	strcpy(strresult, "Failed unparsing client name for log");
+	goto chpwfail;
+    }
+    /* change the password */
+
+    ptr = (char *) malloc(clear.length+1);
+    memcpy(ptr, clear.data, clear.length);
+    ptr[clear.length] = '\0';
+
+    ret = schpw_util_wrapper(server_handle, ticket->enc_part2->client,
+			     ptr, NULL, strresult, sizeof(strresult));
+
+    /* zap the password */
+    memset(clear.data, 0, clear.length);
+    memset(ptr, 0, clear.length);
+    krb5_xfree(clear.data);
+    free(ptr);
+    clear.length = 0;
+
+    krb5_klog_syslog(LOG_NOTICE, "chpw request from %s for %s: %s",
+		     inet_ntoa(((struct sockaddr_in *)&remote_addr)->sin_addr),
+		     clientstr, ret ? error_message(ret) : "success");
+    krb5_free_unparsed_name(context, clientstr);
+
+    if (ret) {
+	if ((ret != KADM5_PASS_Q_TOOSHORT) && 
+	    (ret != KADM5_PASS_REUSE) && (ret != KADM5_PASS_Q_CLASS) && 
+	    (ret != KADM5_PASS_Q_DICT) && (ret != KADM5_PASS_TOOSOON))
+	    numresult = KRB5_KPASSWD_HARDERROR;
+	else
+	    numresult = KRB5_KPASSWD_SOFTERROR;
+	/* strresult set by kadb5_chpass_principal_util() */
+	goto chpwfail;
+    }
+
+    /* success! */
+
+    numresult = KRB5_KPASSWD_SUCCESS;
+    strcpy(strresult, "");
+
+chpwfail:
+
+    clear.length = 2 + strlen(strresult);
+    clear.data = (char *) malloc(clear.length);
+
+    ptr = clear.data;
+
+    *ptr++ = (numresult>>8) & 0xff;
+    *ptr++ = numresult & 0xff;
+
+    memcpy(ptr, strresult, strlen(strresult));
+
+    cipher.length = 0;
+
+    if (ap_rep.length) {
+	ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr,
+				     NULL);
+	if (ret) {
+	    numresult = KRB5_KPASSWD_HARDERROR;
+	    strcpy(strresult,
+		   "Failed storing client and server internet addresses");
+	} else {
+	    ret = krb5_mk_priv(context, auth_context, &clear, &cipher,
+			       &replay);
+	    if (ret) {
+		numresult = KRB5_KPASSWD_HARDERROR;
+		strcpy(strresult, "Failed encrypting reply");
+	    }
+	}
+    }
+
+    /* if no KRB-PRIV was constructed, then we need a KRB-ERROR.
+       if this fails, just bail.  there's nothing else we can do. */
+
+    if (cipher.length == 0) {
+	/* clear out ap_rep now, so that it won't be inserted in the
+           reply */
+
+	if (ap_rep.length) {
+	    krb5_xfree(ap_rep.data);
+	    ap_rep.length = 0;
+	}
+
+	krberror.ctime = 0;
+	krberror.cusec = 0;
+	krberror.susec = 0;
+	ret = krb5_timeofday(context, &krberror.stime);
+	if (ret)
+	    goto bailout;
+
+	/* this is really icky.  but it's what all the other callers
+	   to mk_error do. */
+	krberror.error = ret;
+	krberror.error -= ERROR_TABLE_BASE_krb5;
+	if (krberror.error < 0 || krberror.error > 128)
+	    krberror.error = KRB_ERR_GENERIC;
+
+	krberror.client = NULL;
+
+	ret = krb5_build_principal(context, &krberror.server,
+				   strlen(realm), realm,
+				   "kadmin", "changepw", NULL);
+	if (ret)
+	    goto bailout;
+	krberror.text.length = 0;
+	krberror.e_data = clear;
+
+	ret = krb5_mk_error(context, &krberror, &cipher);
+
+	krb5_free_principal(context, krberror.server);
+
+	if (ret)
+	    goto bailout;
+    }
+
+    /* construct the reply */
+
+    rep->length = 6 + ap_rep.length + cipher.length;
+    rep->data = (char *) malloc(rep->length);
+    ptr = rep->data;
+
+    /* length */
+
+    *ptr++ = (rep->length>>8) & 0xff;
+    *ptr++ = rep->length & 0xff;
+
+    /* version == 0x0001 big-endian */
+
+    *ptr++ = 0;
+    *ptr++ = 1;
+
+    /* ap_rep length, big-endian */
+
+    *ptr++ = (ap_rep.length>>8) & 0xff;
+    *ptr++ = ap_rep.length & 0xff;
+
+    /* ap-rep data */
+
+    if (ap_rep.length) {
+	memcpy(ptr, ap_rep.data, ap_rep.length);
+	ptr += ap_rep.length;
+    }
+
+    /* krb-priv or krb-error */
+
+    memcpy(ptr, cipher.data, cipher.length);
+
+bailout:
+    if (auth_context)
+	krb5_auth_con_free(context, auth_context);
+    if (changepw)
+	krb5_free_principal(context, changepw);
+    if (ap_rep.length)
+	krb5_xfree(ap_rep.data);
+    if (ticket)
+	krb5_free_ticket(context, ticket);
+    if (clear.length)
+	krb5_xfree(clear.data);
+    if (cipher.length)
+	krb5_xfree(cipher.data);
+    if (allocated_mem) 
+        krb5_xfree(local_kaddr.contents);
+
+    return(ret);
+}
diff --git a/mechglue/src/kadmin/server/server_glue_v1.c b/mechglue/src/kadmin/server/server_glue_v1.c
new file mode 100644
index 000000000..dfd6430f1
--- /dev/null
+++ b/mechglue/src/kadmin/server/server_glue_v1.c
@@ -0,0 +1,32 @@
+#define USE_KADM5_API_VERSION 1
+#include <kadm5/admin.h>
+#include "misc.h"
+
+/*
+ * In server_stubs.c, kadmind has to be able to call kadm5 functions
+ * with the arguments appropriate for any api version.  Because of the
+ * prototypes in admin.h, however, the compiler will only allow one
+ * set of arguments to be passed.  This file exports the old api
+ * definitions with a different name, so they can be called from
+ * server_stubs.c, and just passes on the call to the real api
+ * function; it uses the old api version, however, so it can actually
+ * call the real api functions whereas server_stubs.c cannot.
+ *
+ * This is most useful for functions like kadm5_get_principal that
+ * take a different number of arguments based on API version.  For
+ * kadm5_get_policy, the same thing could be accomplished with
+ * typecasts instead.
+ */
+
+kadm5_ret_t kadm5_get_principal_v1(void *server_handle,
+				  krb5_principal principal, 
+				  kadm5_principal_ent_t_v1 *ent)
+{
+     return kadm5_get_principal(server_handle, principal, ent);
+}
+
+kadm5_ret_t kadm5_get_policy_v1(void *server_handle, kadm5_policy_t name,
+				kadm5_policy_ent_t *ent)
+{
+     return kadm5_get_policy(server_handle, name, ent);
+}
diff --git a/mechglue/src/kadmin/server/server_stubs.c b/mechglue/src/kadmin/server/server_stubs.c
new file mode 100644
index 000000000..e3d6709cf
--- /dev/null
+++ b/mechglue/src/kadmin/server/server_stubs.c
@@ -0,0 +1,1916 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ */
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h> /* for gss_nt_krb5_name */
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include <kadm5/server_internal.h>
+#include <kadm5/server_acl.h>
+#include <syslog.h>
+#include <arpa/inet.h>  /* inet_ntoa */
+#include <krb5/adm_proto.h>  /* krb5_klog_syslog */
+#include "misc.h"
+
+#define LOG_UNAUTH  "Unauthorized request: %s, %s, client=%s, service=%s, addr=%s"
+#define	LOG_DONE    "Request: %s, %s, %s, client=%s, service=%s, addr=%s"
+
+extern gss_name_t 			gss_changepw_name;
+extern gss_name_t			gss_oldchangepw_name;
+extern void *				global_server_handle;
+
+#define CHANGEPW_SERVICE(rqstp) \
+	(cmp_gss_names_rel_1(acceptor_name(rqstp->rq_svccred), gss_changepw_name) |\
+	 (gss_oldchangepw_name && \
+	  cmp_gss_names_rel_1(acceptor_name(rqstp->rq_svccred), \
+			gss_oldchangepw_name)))
+
+
+static int gss_to_krb5_name(kadm5_server_handle_t handle,
+		     gss_name_t gss_name, krb5_principal *princ);
+
+static int gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str);
+
+static gss_name_t acceptor_name(gss_ctx_id_t context);
+
+static gss_name_t rqst2name(struct svc_req *rqstp);
+
+static int cmp_gss_names(gss_name_t n1, gss_name_t n2)
+{
+   OM_uint32 emaj, emin;
+   int equal;
+
+   if (GSS_ERROR(emaj = gss_compare_name(&emin, n1, n2, &equal)))
+      return(0);
+
+   return(equal);
+}
+
+/* Does a comparison of the names and then releases the first entity */
+/* For use above in CHANGEPW_SERVICE */
+static int cmp_gss_names_rel_1(gss_name_t n1, gss_name_t n2)
+{
+   OM_uint32 min_stat;
+   int ret;
+
+   ret = cmp_gss_names(n1, n2);
+   if (n1) (void) gss_release_name(&min_stat, &n1);
+   return ret;
+}
+
+/*
+ * Function check_handle
+ *
+ * Purpose: Check a server handle and return a com_err code if it is
+ * invalid or 0 if it is valid.
+ *
+ * Arguments:
+ *
+ * 	handle		The server handle.
+ */
+
+static int check_handle(void *handle)
+{
+     CHECK_HANDLE(handle);
+     return 0;
+}
+
+/*
+ * Function: new_server_handle
+ *
+ * Purpose: Constructs a server handle suitable for passing into the
+ * server library API functions, by folding the client's API version
+ * and calling principal into the server handle returned by
+ * kadm5_init.
+ *
+ * Arguments:
+ * 	api_version	(input) The API version specified by the client
+ * 	rqstp		(input) The RPC request
+ * 	handle		(output) The returned handle
+ *	<return value>	(output) An error code, or 0 if no error occurred
+ * 
+ * Effects:
+ * 	Returns a pointer to allocated storage containing the server
+ * 	handle.  If an error occurs, then no allocated storage is
+ *	returned, and the return value of the function will be a
+ * 	non-zero com_err code.
+ *      
+ *      The allocated storage for the handle should be freed with
+ * 	free_server_handle (see below) when it is no longer needed.
+ */
+
+static kadm5_ret_t new_server_handle(krb5_ui_4 api_version,
+					  struct svc_req *rqstp,
+					  kadm5_server_handle_t
+					  *out_handle)
+{
+     kadm5_server_handle_t handle;
+
+     if (! (handle = (kadm5_server_handle_t)
+	    malloc(sizeof(*handle))))
+	  return ENOMEM;
+
+     *handle = *(kadm5_server_handle_t)global_server_handle;
+     handle->api_version = api_version;
+
+     if (! gss_to_krb5_name(handle, rqst2name(rqstp),
+			    &handle->current_caller)) {
+	  free(handle);
+	  return KADM5_FAILURE;
+     }
+
+     *out_handle = handle;
+     return 0;
+}
+
+/*
+ * Function: free_server_handle
+ *
+ * Purpose: Free handle memory allocated by new_server_handle
+ *
+ * Arguments:
+ * 	handle		(input/output) The handle to free
+ */
+static void free_server_handle(kadm5_server_handle_t handle)
+{
+     krb5_free_principal(handle->context, handle->current_caller);
+     free(handle);
+}
+
+/*
+ * Function: setup_gss_names
+ *
+ * Purpose: Create printable representations of the client and server
+ * names.
+ *
+ * Arguments:
+ * 	rqstp		(r) the RPC request
+ * 	client_name	(w) the gss_buffer_t for the client name
+ * 	server_name	(w) the gss_buffer_t for the server name
+ *
+ * Effects:
+ *
+ * Unparses the client and server names into client_name and
+ * server_name, both of which must be freed by the caller.  Returns 0
+ * on success and -1 on failure.
+ */
+static 
+int setup_gss_names(struct svc_req *rqstp,
+		    gss_buffer_desc *client_name,
+		    gss_buffer_desc *server_name)
+{
+     OM_uint32 maj_stat, min_stat;
+     gss_name_t server_gss_name;
+
+     if (gss_name_to_string(rqst2name(rqstp), client_name) != 0)
+	  return -1;
+     maj_stat = gss_inquire_context(&min_stat, rqstp->rq_svccred, NULL,
+				    &server_gss_name, NULL, NULL, NULL,
+				    NULL, NULL);
+     if (maj_stat != GSS_S_COMPLETE) {
+	  gss_release_buffer(&min_stat, client_name);
+          gss_release_name(&min_stat, &server_gss_name);
+	  return -1;
+     }
+     if (gss_name_to_string(server_gss_name, server_name) != 0) {
+	  gss_release_buffer(&min_stat, client_name);
+          gss_release_name(&min_stat, &server_gss_name);
+	  return -1;
+     }
+     gss_release_name(&min_stat, &server_gss_name);
+     return 0;
+}
+
+static gss_name_t acceptor_name(gss_ctx_id_t context)
+{
+     OM_uint32 maj_stat, min_stat;
+     gss_name_t name;
+     
+     maj_stat = gss_inquire_context(&min_stat, context, NULL, &name,
+				    NULL, NULL, NULL, NULL, NULL);
+     if (maj_stat != GSS_S_COMPLETE)
+	  return NULL;
+     return name;
+}
+     
+static int cmp_gss_krb5_name(kadm5_server_handle_t handle,
+		      gss_name_t gss_name, krb5_principal princ)
+{
+     krb5_principal princ2;
+     int status;
+
+     if (! gss_to_krb5_name(handle, gss_name, &princ2))
+	  return 0;
+     status = krb5_principal_compare(handle->context, princ, princ2);
+     krb5_free_principal(handle->context, princ2);
+     return status;
+}
+
+static int gss_to_krb5_name(kadm5_server_handle_t handle,
+		     gss_name_t gss_name, krb5_principal *princ)
+{
+     OM_uint32 status, minor_stat;
+     gss_buffer_desc gss_str;
+     gss_OID gss_type;
+     int success;
+
+     status = gss_display_name(&minor_stat, gss_name, &gss_str, &gss_type);
+     if ((status != GSS_S_COMPLETE) || (gss_type != gss_nt_krb5_name))
+	  return 0;
+     success = (krb5_parse_name(handle->context, gss_str.value, princ) == 0);
+     gss_release_buffer(&minor_stat, &gss_str);
+     return success;
+}
+
+static int
+gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str)
+{
+     OM_uint32 status, minor_stat;
+     gss_OID gss_type;
+
+     status = gss_display_name(&minor_stat, gss_name, str, &gss_type);
+     if ((status != GSS_S_COMPLETE) || (gss_type != gss_nt_krb5_name))
+	  return 1;
+     return 0;
+}
+
+generic_ret *
+create_principal_2_svc(cprinc_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		ret;
+    char			*prime_arg;
+    gss_buffer_desc		client_name, service_name;
+    OM_uint32			minor_stat;
+    kadm5_server_handle_t	handle;
+    restriction_t		*rp;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (CHANGEPW_SERVICE(rqstp)
+	|| !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_ADD,
+		      arg->rec.principal, &rp)
+	|| kadm5int_acl_impose_restrictions(handle->context,
+				   &arg->rec, &arg->mask, rp)) {
+	 ret.code = KADM5_AUTH_ADD;
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_create_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    } else {
+	 ret.code = kadm5_create_principal((void *)handle,
+						&arg->rec, arg->mask,
+						arg->passwd);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_create_principal",
+		prime_arg, ret.err_str,
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+
+ exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+create_principal3_2_svc(cprinc3_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		ret;
+    char			*prime_arg;
+    gss_buffer_desc		client_name, service_name;
+    OM_uint32			minor_stat;
+    kadm5_server_handle_t	handle;
+    restriction_t		*rp;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (CHANGEPW_SERVICE(rqstp)
+	|| !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_ADD,
+		      arg->rec.principal, &rp)
+	|| kadm5int_acl_impose_restrictions(handle->context,
+				   &arg->rec, &arg->mask, rp)) {
+	 ret.code = KADM5_AUTH_ADD;
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_create_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    } else {
+	 ret.code = kadm5_create_principal_3((void *)handle,
+					     &arg->rec, arg->mask,
+					     arg->n_ks_tuple,
+					     arg->ks_tuple,
+					     arg->passwd);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_create_principal",
+		prime_arg, ret.err_str, 
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+delete_principal_2_svc(dprinc_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+    
+    if (CHANGEPW_SERVICE(rqstp)
+	|| !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_DELETE,
+		      arg->princ, NULL)) {
+	 ret.code = KADM5_AUTH_DELETE;
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_delete_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    } else {
+	 ret.code = kadm5_delete_principal((void *)handle, arg->princ);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_delete_principal", prime_arg, 
+                ret.err_str,
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free(prime_arg);
+    free_server_handle(handle);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+ exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+
+    return &ret;
+}
+
+generic_ret *
+modify_principal_2_svc(mprinc_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+    restriction_t		    *rp;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (CHANGEPW_SERVICE(rqstp)
+	|| !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
+		      arg->rec.principal, &rp)
+	|| kadm5int_acl_impose_restrictions(handle->context,
+				   &arg->rec, &arg->mask, rp)) {
+	 ret.code = KADM5_AUTH_MODIFY;
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_modify_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    } else {
+	 ret.code = kadm5_modify_principal((void *)handle, &arg->rec,
+						arg->mask);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_modify_principal",
+ 	        prime_arg, ret.err_str,
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+rename_principal_2_svc(rprinc_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		ret;
+    char			*prime_arg1,
+				*prime_arg2;
+    char			prime_arg[BUFSIZ];
+    gss_buffer_desc		client_name,
+				service_name;
+    OM_uint32			minor_stat;
+    kadm5_server_handle_t	handle;
+    restriction_t		*rp;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->src, &prime_arg1) ||
+        krb5_unparse_name(handle->context, arg->dest, &prime_arg2)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+    sprintf(prime_arg, "%s to %s", prime_arg1, prime_arg2);
+
+    ret.code = KADM5_OK;
+    if (! CHANGEPW_SERVICE(rqstp)) {
+	 if (!kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			ACL_DELETE, arg->src, NULL))
+	      ret.code = KADM5_AUTH_DELETE;
+	 /* any restrictions at all on the ADD kills the RENAME */
+	 if (!kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			ACL_ADD, arg->dest, &rp) || rp) {
+	      if (ret.code == KADM5_AUTH_DELETE)
+		   ret.code = KADM5_AUTH_INSUFFICIENT;
+	      else
+		   ret.code = KADM5_AUTH_ADD;
+	 }
+    } else
+	 ret.code = KADM5_AUTH_INSUFFICIENT;
+    if (ret.code != KADM5_OK) {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_rename_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    } else {
+	 ret.code = kadm5_rename_principal((void *)handle, arg->src,
+						arg->dest);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_rename_principal",
+		prime_arg, ret.err_str,
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    free(prime_arg1);
+    free(prime_arg2);    
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+gprinc_ret *
+get_principal_2_svc(gprinc_arg *arg, struct svc_req *rqstp)
+{
+    static gprinc_ret		    ret;
+    kadm5_principal_ent_t_v1	    e;
+    char			    *prime_arg, *funcname;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_gprinc_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    funcname = handle->api_version == KADM5_API_VERSION_1 ?
+	 "kadm5_get_principal (V1)" : "kadm5_get_principal";
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (! cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
+	(CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+					       rqst2name(rqstp),
+					       ACL_INQUIRE,
+					       arg->princ,
+					       NULL))) {
+	 ret.code = KADM5_AUTH_GET;
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, funcname,
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    } else {
+	 if (handle->api_version == KADM5_API_VERSION_1) {
+	      ret.code  = kadm5_get_principal_v1((void *)handle,
+						 arg->princ, &e); 
+	      if(ret.code == KADM5_OK) {
+		   memcpy(&ret.rec, e, sizeof(kadm5_principal_ent_rec_v1));
+		   free(e);
+	      }
+	 } else {
+	      ret.code  = kadm5_get_principal((void *)handle,
+					      arg->princ, &ret.rec,
+					      arg->mask);
+	 }
+	 
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname,
+		prime_arg,  
+		ret.err_str,
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+gprincs_ret *
+get_princs_2_svc(gprincs_arg *arg, struct svc_req *rqstp)
+{
+    static gprincs_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_gprincs_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    prime_arg = arg->exp;
+    if (prime_arg == NULL)
+	 prime_arg = "*";
+
+    if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+					      rqst2name(rqstp),
+					      ACL_LIST,
+					      NULL,
+					      NULL)) {
+	 ret.code = KADM5_AUTH_LIST;
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_get_principals",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    } else {
+	 ret.code  = kadm5_get_principals((void *)handle,
+					       arg->exp, &ret.princs,
+					       &ret.count);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_principals",
+		prime_arg,  
+		ret.err_str,
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+chpass_principal_2_svc(chpass_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+	 ret.code = chpass_principal_wrapper_3((void *)handle, arg->princ,
+					       FALSE, 0, NULL, arg->pass);
+    } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+	       kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			 ACL_CHANGEPW, arg->princ, NULL)) {
+	 ret.code = kadm5_chpass_principal((void *)handle, arg->princ,
+						arg->pass);
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_chpass_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_CHANGEPW;
+    }
+
+    if(ret.code != KADM5_AUTH_CHANGEPW) {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_chpass_principal", 
+	       prime_arg, ret.err_str,
+	       client_name.value, service_name.value,
+	       inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+chpass_principal3_2_svc(chpass3_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+	 ret.code = chpass_principal_wrapper_3((void *)handle, arg->princ,
+					       arg->keepold,
+					       arg->n_ks_tuple,
+					       arg->ks_tuple,
+					       arg->pass);
+    } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+	       kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			 ACL_CHANGEPW, arg->princ, NULL)) {
+	 ret.code = kadm5_chpass_principal_3((void *)handle, arg->princ,
+					     arg->keepold,
+					     arg->n_ks_tuple,
+					     arg->ks_tuple,
+					     arg->pass);
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_chpass_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_CHANGEPW;
+    }
+
+    if(ret.code != KADM5_AUTH_CHANGEPW) {
+	if( ret.code == 0 )
+	    ret.err_str = "success";
+	else
+	    ret.err_str = error_message(ret.code);
+
+	krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_chpass_principal", 
+	       prime_arg, ret.err_str, 
+	       client_name.value, service_name.value,
+	       inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	/* xdr free frees this string. so make a copy */
+	ret.err_str = strdup( ret.err_str ); 
+	/* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+setv4key_principal_2_svc(setv4key_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (!(CHANGEPW_SERVICE(rqstp)) &&
+	       kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			 ACL_SETKEY, arg->princ, NULL)) {
+	 ret.code = kadm5_setv4key_principal((void *)handle, arg->princ,
+					     arg->keyblock);
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_setv4key_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_SETKEY;
+    }
+
+    if(ret.code != KADM5_AUTH_SETKEY) {
+	if( ret.code == 0 )
+	    ret.err_str = "success";
+	else
+	    ret.err_str = error_message(ret.code);
+
+	krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_setv4key_principal", 
+	       prime_arg, ret.err_str, 
+	       client_name.value, service_name.value,
+	       inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	/* xdr free frees this string. so make a copy */
+	ret.err_str = strdup( ret.err_str ); 
+	/* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+setkey_principal_2_svc(setkey_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (!(CHANGEPW_SERVICE(rqstp)) &&
+	       kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			 ACL_SETKEY, arg->princ, NULL)) {
+	 ret.code = kadm5_setkey_principal((void *)handle, arg->princ,
+					   arg->keyblocks, arg->n_keys);
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_setkey_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_SETKEY;
+    }
+
+    if(ret.code != KADM5_AUTH_SETKEY) {
+	if( ret.code == 0 )
+	    ret.err_str = "success";
+	else
+	    ret.err_str = error_message(ret.code);
+
+	krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_setkey_principal", 
+	       prime_arg, ret.err_str, 
+	       client_name.value, service_name.value,
+	       inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	/* xdr free frees this string. so make a copy */
+	ret.err_str = strdup( ret.err_str ); 
+	/* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+setkey_principal3_2_svc(setkey3_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (!(CHANGEPW_SERVICE(rqstp)) &&
+	       kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			 ACL_SETKEY, arg->princ, NULL)) {
+	 ret.code = kadm5_setkey_principal_3((void *)handle, arg->princ,
+					     arg->keepold,
+					     arg->n_ks_tuple,
+					     arg->ks_tuple,
+					     arg->keyblocks, arg->n_keys);
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_setkey_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_SETKEY;
+    }
+
+    if(ret.code != KADM5_AUTH_SETKEY) {
+	if( ret.code == 0 )
+	    ret.err_str = "success";
+	else
+	    ret.err_str = error_message(ret.code);
+
+	krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_setkey_principal", 
+	       prime_arg, ret.err_str, 
+	       client_name.value, service_name.value,
+	       inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	/* xdr free frees this string. so make a copy */
+	ret.err_str = strdup( ret.err_str ); 
+	/* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+chrand_ret *
+chrand_principal_2_svc(chrand_arg *arg, struct svc_req *rqstp)
+{
+    static chrand_ret		ret;
+    krb5_keyblock		*k;
+    int				nkeys;
+    char			*prime_arg, *funcname;
+    gss_buffer_desc		client_name,
+	    			service_name;
+    OM_uint32			minor_stat;
+    kadm5_server_handle_t	handle;
+
+    xdr_free(xdr_chrand_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    funcname = handle->api_version == KADM5_API_VERSION_1 ?
+	 "kadm5_randkey_principal (V1)" : "kadm5_randkey_principal";
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+	 ret.code = randkey_principal_wrapper_3((void *)handle, arg->princ,
+						FALSE, 0, NULL, &k, &nkeys);
+    } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+	       kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			 ACL_CHANGEPW, arg->princ, NULL)) {
+	 ret.code = kadm5_randkey_principal((void *)handle, arg->princ,
+					    &k, &nkeys);
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, funcname,
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_CHANGEPW;
+    }
+
+    if(ret.code == KADM5_OK) {
+	 if (handle->api_version == KADM5_API_VERSION_1) {
+	      krb5_copy_keyblock_contents(handle->context, k, &ret.key);
+	      krb5_free_keyblock(handle->context, k);
+	 } else {
+	      ret.keys = k;
+	      ret.n_keys = nkeys;
+	 }
+    }
+
+    if(ret.code != KADM5_AUTH_CHANGEPW) {
+	if( ret.code == 0 )
+	    ret.err_str = "success";
+	else
+	    ret.err_str = error_message(ret.code);
+
+	krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname,
+	       prime_arg, ret.err_str, 
+	       client_name.value, service_name.value,
+	       inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	/* xdr free frees this string. so make a copy */
+	ret.err_str = strdup( ret.err_str ); 
+	/* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+chrand_ret *
+chrand_principal3_2_svc(chrand3_arg *arg, struct svc_req *rqstp)
+{
+    static chrand_ret		ret;
+    krb5_keyblock		*k;
+    int				nkeys;
+    char			*prime_arg, *funcname;
+    gss_buffer_desc		client_name,
+	    			service_name;
+    OM_uint32			minor_stat;
+    kadm5_server_handle_t	handle;
+
+    xdr_free(xdr_chrand_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    funcname = handle->api_version == KADM5_API_VERSION_1 ?
+	 "kadm5_randkey_principal (V1)" : "kadm5_randkey_principal";
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 goto exit_func;
+    }
+
+    if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+	 ret.code = randkey_principal_wrapper_3((void *)handle, arg->princ,
+						arg->keepold,
+						arg->n_ks_tuple,
+						arg->ks_tuple,
+						&k, &nkeys);
+    } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+	       kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			 ACL_CHANGEPW, arg->princ, NULL)) {
+	 ret.code = kadm5_randkey_principal_3((void *)handle, arg->princ,
+					      arg->keepold,
+					      arg->n_ks_tuple,
+					      arg->ks_tuple,
+					      &k, &nkeys);
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, funcname,
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_CHANGEPW;
+    }
+
+    if(ret.code == KADM5_OK) {
+	 if (handle->api_version == KADM5_API_VERSION_1) {
+	      krb5_copy_keyblock_contents(handle->context, k, &ret.key);
+	      krb5_free_keyblock(handle->context, k);
+	 } else {
+	      ret.keys = k;
+	      ret.n_keys = nkeys;
+	 }
+    }
+
+    if(ret.code != KADM5_AUTH_CHANGEPW) {
+	if( ret.code == 0 )
+	    ret.err_str = "success";
+	else
+	    ret.err_str = error_message(ret.code);
+
+	krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname,
+	       prime_arg, ret.err_str, 
+	       client_name.value, service_name.value,
+	       inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+create_policy_2_svc(cpol_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;    
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    prime_arg = arg->rec.policy;
+
+    if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+					      rqst2name(rqstp),
+					      ACL_ADD, NULL, NULL)) {
+	 ret.code = KADM5_AUTH_ADD;
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_create_policy",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 
+    } else {
+	 ret.code = kadm5_create_policy((void *)handle, &arg->rec,
+					     arg->mask);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_create_policy",
+		((prime_arg == NULL) ? "(null)" : prime_arg),
+		ret.err_str, 
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));	 
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+delete_policy_2_svc(dpol_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;    
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    prime_arg = arg->name;
+    
+    if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+					      rqst2name(rqstp),
+					      ACL_DELETE, NULL, NULL)) {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_delete_policy",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_DELETE;
+    } else {
+	 ret.code = kadm5_delete_policy((void *)handle, arg->name);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_delete_policy",
+		((prime_arg == NULL) ? "(null)" : prime_arg),
+		ret.err_str, 
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));	 
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+generic_ret *
+modify_policy_2_svc(mpol_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;    
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    prime_arg = arg->rec.policy;
+
+    if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+					      rqst2name(rqstp),
+					      ACL_MODIFY, NULL, NULL)) {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_modify_policy",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_MODIFY;
+    } else {
+	 ret.code = kadm5_modify_policy((void *)handle, &arg->rec,
+					     arg->mask);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_modify_policy",
+		((prime_arg == NULL) ? "(null)" : prime_arg),	    
+		ret.err_str, 
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));	
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+gpol_ret * 
+get_policy_2_svc(gpol_arg *arg, struct svc_req *rqstp)
+{
+    static gpol_ret		ret;
+    kadm5_ret_t		ret2;
+    char			*prime_arg, *funcname;
+    gss_buffer_desc		client_name,
+				service_name;
+    OM_uint32			minor_stat;    
+    kadm5_policy_ent_t	e;
+    kadm5_principal_ent_rec	caller_ent;
+    kadm5_server_handle_t	handle;
+
+    xdr_free(xdr_gpol_ret,  &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    funcname = handle->api_version == KADM5_API_VERSION_1 ?
+	 "kadm5_get_policy (V1)" : "kadm5_get_policy";
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    prime_arg = arg->name;
+
+    ret.code = KADM5_AUTH_GET;
+    if (!CHANGEPW_SERVICE(rqstp) && kadm5int_acl_check(handle->context,
+					      rqst2name(rqstp),
+					      ACL_INQUIRE, NULL, NULL))
+	 ret.code = KADM5_OK;
+    else {
+	 ret.code = kadm5_get_principal(handle->lhandle,
+					handle->current_caller,
+					&caller_ent,
+					KADM5_PRINCIPAL_NORMAL_MASK);
+	 if (ret.code == KADM5_OK) {
+	      if (caller_ent.aux_attributes & KADM5_POLICY &&
+		  strcmp(caller_ent.policy, arg->name) == 0) {
+		   ret.code = KADM5_OK;
+	      } else ret.code = KADM5_AUTH_GET;
+	      ret2 = kadm5_free_principal_ent(handle->lhandle,
+					      &caller_ent);
+	      ret.code = ret.code ? ret.code : ret2;
+	 }
+    }
+    
+    if (ret.code == KADM5_OK) {
+	 if (handle->api_version == KADM5_API_VERSION_1) {
+	      ret.code  = kadm5_get_policy_v1((void *)handle, arg->name, &e);
+	      if(ret.code == KADM5_OK) {
+		   memcpy(&ret.rec, e, sizeof(kadm5_policy_ent_rec));
+		   free(e);
+	      }
+	 } else {
+	      ret.code = kadm5_get_policy((void *)handle, arg->name,
+					  &ret.rec);
+	 }
+	 
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname,
+		((prime_arg == NULL) ? "(null)" : prime_arg),
+		ret.err_str, 
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));	 
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, funcname,
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    }
+    free_server_handle(handle);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+
+}
+
+gpols_ret *
+get_pols_2_svc(gpols_arg *arg, struct svc_req *rqstp)
+{
+    static gpols_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_gpols_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 goto exit_func;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 goto exit_func;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 goto exit_func;
+    }
+    prime_arg = arg->exp;
+    if (prime_arg == NULL)
+	 prime_arg = "*";
+
+    if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+					      rqst2name(rqstp),
+					      ACL_LIST, NULL, NULL)) {
+	 ret.code = KADM5_AUTH_LIST;
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_get_policies",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    } else {
+	 ret.code  = kadm5_get_policies((void *)handle,
+					       arg->exp, &ret.pols,
+					       &ret.count);
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_policies",
+		prime_arg,  
+		ret.err_str, 
+		client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    free_server_handle(handle);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+    return &ret;
+}
+
+getprivs_ret * get_privs_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp)
+{
+     static getprivs_ret	    ret;
+     gss_buffer_desc		    client_name, service_name;
+     OM_uint32			    minor_stat;
+     kadm5_server_handle_t	    handle;
+
+     xdr_free(xdr_getprivs_ret, &ret);
+
+     if ((ret.code = new_server_handle(*arg, rqstp, &handle)))
+	  goto exit_func;
+
+     if ((ret.code = check_handle((void *)handle))) {
+	  free_server_handle(handle);
+	  goto exit_func;
+     }
+
+     ret.api_version = handle->api_version;
+
+     if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	  ret.code = KADM5_FAILURE;
+	  goto exit_func;
+     }
+
+     ret.code = kadm5_get_privs((void *)handle, &ret.privs);
+     if( ret.code == 0 )
+	 ret.err_str = "success";
+     else
+	 ret.err_str = error_message(ret.code);
+
+     krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_privs",
+	    client_name.value, 
+	    ret.err_str, 
+	    client_name.value, service_name.value,
+	    inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+
+     /* xdr free frees this string. so make a copy */
+     ret.err_str = strdup( ret.err_str ); 
+     /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+
+     free_server_handle(handle);
+     gss_release_buffer(&minor_stat, &client_name);
+     gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+    if( ret.err_str == NULL )
+    {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+    }
+     return &ret;
+}
+
+generic_ret *init_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp)
+{
+     static generic_ret		ret;
+     gss_buffer_desc		client_name,
+	 			service_name;
+     kadm5_server_handle_t	handle;
+     OM_uint32			minor_stat;
+
+     xdr_free(xdr_generic_ret, &ret);
+
+     if ((ret.code = new_server_handle(*arg, rqstp, &handle)))
+	  goto exit_func;
+     if (! (ret.code = check_handle((void *)handle))) {
+	 ret.api_version = handle->api_version;
+     }
+
+     free_server_handle(handle);
+
+     if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	  ret.code = KADM5_FAILURE;
+	  goto exit_func;
+     }
+
+     krb5_klog_syslog(LOG_NOTICE, LOG_DONE ", flavor=%d",
+	    (ret.api_version == KADM5_API_VERSION_1 ?
+	     "kadm5_init (V1)" : "kadm5_init"),
+	    client_name.value,
+	    (ret.code == 0) ? "success" : error_message(ret.code),
+	    client_name.value, service_name.value,
+	    inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr),
+	    rqstp->rq_cred.oa_flavor);
+     gss_release_buffer(&minor_stat, &client_name);
+     gss_release_buffer(&minor_stat, &service_name);
+	    
+exit_func:
+     if( ret.err_str == NULL )
+     {
+	 if( ret.code == 0 )
+	     ret.err_str = "success";
+	 else
+	     ret.err_str = error_message(ret.code);
+
+	 /* xdr free frees this string. so make a copy */
+	 ret.err_str = strdup( ret.err_str ); 
+	 /* no need to check for NULL. Even if it is NULL, atleast error_code will be returned */
+     }
+     return(&ret);
+}
+
+static gss_name_t
+rqst2name(struct svc_req *rqstp)
+{
+
+     if (rqstp->rq_cred.oa_flavor == RPCSEC_GSS)
+	  return rqstp->rq_clntname;
+     else
+	  return rqstp->rq_clntcred;
+}
diff --git a/mechglue/src/kadmin/testing/ChangeLog b/mechglue/src/kadmin/testing/ChangeLog
new file mode 100644
index 000000000..1233a0876
--- /dev/null
+++ b/mechglue/src/kadmin/testing/ChangeLog
@@ -0,0 +1,42 @@
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 18 15:58:53 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
diff --git a/mechglue/src/kadmin/testing/Makefile.in b/mechglue/src/kadmin/testing/Makefile.in
new file mode 100644
index 000000000..c164a7e24
--- /dev/null
+++ b/mechglue/src/kadmin/testing/Makefile.in
@@ -0,0 +1,10 @@
+thisconfigdir=./..
+myfulldir=kadmin/testing
+mydir=testing
+BUILDTOP=$(REL)..$(S)..
+LOCAL_SUBDIRS = scripts util
+
+all::
+
+clean::
+	-$(RM) -r krb5-test-root
diff --git a/mechglue/src/kadmin/testing/proto/ChangeLog b/mechglue/src/kadmin/testing/proto/ChangeLog
new file mode 100644
index 000000000..1b72cb4e9
--- /dev/null
+++ b/mechglue/src/kadmin/testing/proto/ChangeLog
@@ -0,0 +1,63 @@
+2005-08-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.conf.proto: Change db module name to be more obviously not
+	magic.  Point db_module_dir to the fakedest installed version.
+
+2005-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.conf.proto: Add a bunch of db module info that should be in
+	kdc.conf.proto, but is sought here for now.
+
+2000-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc.conf.proto: Use des3 master key.
+
+2000-05-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5.conf.proto: Set dns_fallback=no.
+
+	* kdc.conf.proto: Add des3 to supported_enctypes.
+
+Wed Jan 21 12:44:25 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdc.conf.proto: Add kpasswd_port line so kadmind can start as
+        non-root for testing.
+
+Mon Mar 31 17:42:33 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krb5.conf.proto: add support for setkey_principal (support more enctypes)
+
+Tue Oct 15 16:24:33 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krb5.conf.proto: s/localhost/__LOCALHOST__/
+
+Fri Sep 27 17:12:48 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krb5.conf.proto: parameterize kdc hostname for remote server
+ 	testing
+
+Thu Sep 26 17:47:23 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krb5.conf.proto, kdc.conf.proto: use K5ROOT instead of /krb5
+
+Wed Sep 25 16:20:29 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdc.conf.proto: remove admin_dbname and admin_lockfile
+
+Fri Sep 20 16:54:44 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krb5.conf.proto: change logging to /krb5/syslog
+
+Wed Sep 18 12:37:46 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdc.conf.proto: remove max_life spec, use default
+
+Mon Jul 15 17:11:35 1996  Marc Horowitz  <marc@mit.edu>
+
+	* krb5.conf.proto: specify a default_keytab_name in /krb5
+
+Fri Jul 12 14:46:17 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kdc.conf.proto: put the stash file in /krb5, so that the root
+ 	dir does not need to be writeable.  also, the admin system
+ 	requires a reference in the conf file to admin_keytab
diff --git a/mechglue/src/kadmin/testing/proto/kdc.conf.proto b/mechglue/src/kadmin/testing/proto/kdc.conf.proto
new file mode 100644
index 000000000..6f9edeb5b
--- /dev/null
+++ b/mechglue/src/kadmin/testing/proto/kdc.conf.proto
@@ -0,0 +1,16 @@
+[kdcdefaults]
+	kdc_ports = 1750 
+
+[realms]
+	__REALM__ = {
+		profile = __K5ROOT__/krb5.conf
+		database_name = __K5ROOT__/kdb5
+		admin_keytab = __K5ROOT__/ovsec_adm.srvtab
+		key_stash_file = __K5ROOT__/.k5.__REALM__
+		acl_file = __K5ROOT__/ovsec_adm.acl
+		dict_file = __K5ROOT__/ovsec_adm.dict
+		kadmind_port = 1751
+		kpasswd_port = 1752
+		master_key_type = des3-hmac-sha1
+		supported_enctypes = des3-hmac-sha1:normal des-cbc-crc:normal des-cbc-crc:v4 des-cbc-md5:normal des-cbc-raw:normal
+	}
diff --git a/mechglue/src/kadmin/testing/proto/krb5.conf.proto b/mechglue/src/kadmin/testing/proto/krb5.conf.proto
new file mode 100644
index 000000000..465720dbb
--- /dev/null
+++ b/mechglue/src/kadmin/testing/proto/krb5.conf.proto
@@ -0,0 +1,30 @@
+[libdefaults]
+	default_realm = __REALM__
+	default_keytab_name = FILE:__K5ROOT__/v5srvtab
+	dns_fallback = no
+
+[realms]
+	__REALM__ = {
+		kdc = __KDCHOST__:1750
+		admin_server = __KDCHOST__:1751
+# THIS SHOULD BE IN KDC.CONF INSTEAD!
+		database_module = foobar_db2_module_blah
+	}
+
+[domain_realm]
+	__LOCALHOST__ = __REALM__
+	__KDCHOST__ = __REALM__
+
+[logging]
+	admin_server = FILE:__K5ROOT__/syslog
+	kdc = FILE:__K5ROOT__/syslog
+	default = FILE:__K5ROOT__/syslog
+
+
+# THIS SHOULD BE IN KDC.CONF INSTEAD!
+[db_modules]
+	db_module_dir = __MODDIR__
+	foobar_db2_module_blah = {
+		db_library = db2
+		database_name = __K5ROOT__/kdb5
+	}
diff --git a/mechglue/src/kadmin/testing/proto/ovsec_adm.dict b/mechglue/src/kadmin/testing/proto/ovsec_adm.dict
new file mode 100644
index 000000000..b54e3a85e
--- /dev/null
+++ b/mechglue/src/kadmin/testing/proto/ovsec_adm.dict
@@ -0,0 +1,3 @@
+Abyssinia
+Discordianism
+foo
diff --git a/mechglue/src/kadmin/testing/scripts/ChangeLog b/mechglue/src/kadmin/testing/scripts/ChangeLog
new file mode 100644
index 000000000..59a925093
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/ChangeLog
@@ -0,0 +1,277 @@
+2005-08-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* env-setup.shin: Export $libdir.
+	* init_db: Substitue __MODDIR__ with the fakedest module
+	directory.
+	* start_servers: Likewise.
+
+2004-09-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* start_servers_local: If one of the servers failed to start, log
+	info about which start file was not found.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* env-setup.shin: Substitute FAKEDEST.  Substitue "$" for "$$".
+
+2003-12-05  Tom Yu  <tlyu@mit.edu>
+
+	* env-setup.shin: Allow BUILDTOP substitution.
+
+2003-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* start_servers_local: Set KRB5RCACHEDIR.
+	* stop_servers_local: Set KRB5RCACHEDIR.  Use the correct filename
+	when deleting the replay cache file.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-12-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_db (qualname): If "kdb5_util create" fails, exit.
+
+	* env-setup.shin: Set KRB5CCNAME to something under $K5ROOT.
+
+2002-10-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* start_servers_local: If $USER isn't set, use $LOGNAME.  If
+	ovsec_kadm_srv_tcl invocation to do some initialization fails,
+	exit rather than continuing.
+
+2002-10-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* start_servers_local: Set names of replay cache and log files to
+	be per-user, since they're in system-wide shared directories.
+
+2002-10-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* start_servers_local: Telnet to 127.0.0.1, not "localhost", to
+	probe for kadmind, since kadmind does IPv4 only.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2000-06-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* env-setup.shin: Do not override the EXPECT environment variable
+		if set.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Sun Mar  1 21:13:06 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (env-setup.stmp): If env-setup.stamp needs to be
+ 		rebuilt, set CONFIG_FILES so that we only regenerate that
+ 		one file.
+
+	* env-setup.shin: Rename SRCTOPDIR to S_TOP, which has been
+		fixed to deal with absolute source paths.
+
+Sat Feb 28 18:54:42 1998  Tom Yu  <tlyu@mit.edu>
+
+	* env-setup.shin (STOP): SRCTOP -> SRCTOPDIR.
+
+	* Makefile.in (env-setup.stamp): Fix up to use $(thisconfigdir).
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 18 15:59:31 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Thu Feb 12 16:16:22 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented out AC_OUTPUT to allow autoreconf to
+	rebuild the configure script.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sun Feb  9 01:07:37 1997  Tom Yu  <tlyu@mit.edu>
+
+	* env-setup.shin: Fix to deal with multiple variables in
+	KRB5_RUN_ENV.
+
+Sat Feb  8 22:12:32 1997  Tom Yu  <tlyu@mit.edu>
+
+	* env-setup.shin: Hack to deal with new usage of KRB5_RUN_ENV.
+
+Tue Dec  3 15:28:53 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* init_db: be verbose when $SRVTCL doesn't exist, instead of just
+ 	failing [krb5-admin/245]
+
+Thu Dec  5 19:34:09 1996  Tom Yu  <tlyu@mit.edu>
+
+	* save_files.sh (files): Also save /etc/krb5.keytab. [PR 278]
+
+Thu Nov 14 15:28:16 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* env-setup.shin, init_db, save_files.sh, start_servers,
+ 	start_servers_local, stop_servers, stop_servers_local: move
+ 	VERBOSE_TEST -> VERBOSE logic to env-setup.sh, make everything
+ 	else inherit from it, and fix the sense of the test (Tom got it
+ 	backwards); also fix init_db so that kdb5_util create is not
+ 	always verbose
+
+Wed Nov 13 17:12:51 1996  Tom Yu  <tlyu@mit.edu>
+
+	* env-setup.shin: Explicitly set KRB5CCNAME so the user's ccache
+	doesn't get blown away.
+
+Tue Nov 12 14:59:31 1996  Tom Yu  <tlyu@mit.edu>
+
+	* init_db, save_files.sh, start_servers, start_servers_local,
+ 	stop_servers, stop_servers_local: Fix test of $VERBOSE_TEST so
+ 	that $VERBOSE only gets set if $VERBOSE_TEST is not empty.
+
+Mon Nov 11 14:25:15 1996  Tom Yu  <tlyu@mit.edu>
+
+	* init_db, save_files.sh, start_servers_local, stop_servers,
+ 	stop_servers_local: Use temp files rather than a here document to
+ 	provide input to eval'ed commands; Ultrix sh is broken wrt here
+	documents redirected to eval commands.
+
+	* start_servers, start_servers_local, init_db: Use ${FOO+bar} and
+	${FOO=baz} rather than ${FOO:+bar} and ${FOO:=baz} because of
+	Ultrix /bin/sh lossage.
+
+Thu Nov  7 13:56:25 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* env-setup.shin (foo): Use single quotes around @KRB5_RUN_ENV@ so
+		that bash doesn't try to expand $(TOPLIBD) in the echo line.
+
+Tue Nov  5 08:07:06 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* start_servers_local: kadmin/tcl/util.t is in source tree.
+
+Tue Oct 29 12:19:45 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* init_db: put KRB5_RUN_ENV_CSH in setup.csh
+
+	* env-setup.shin: create KRB5_RUN_ENV_CSH for init_db
+	
+Fri Oct 18 16:15:45 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (env-setup.stamp): Add dependency upon Makefile.
+
+Thu Oct 17 18:28:36 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* qualname.plin: Downcase the FQDN for keytab use. [krb5-libs/116]
+
+Tue Oct 15 18:39:58 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* env-setup.shin: Support for build tree shared library
+		environment setup. [krb5-admin/80]
+
+	* configure.in (RBUILD): Pass in proper top of build tree (not
+		.. path) as this is build tree independent.
+
+Tue Oct 15 16:22:52 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* env-setup.shin: set $QUALNAME to the right path
+
+	* start_servers, init_db: use qualname of local host, not
+ 	localhost, in krb5.conf
+
+Tue Oct 15 06:39:58 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: Added standard rules for .plin -> .pl 
+
+	* *.plin: Renamed from *.pl.in
+
+Thu Oct 10 17:32:22 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* env-setup.shin (EXPECT): Subsititute path for expect from
+		autoconf. 
+
+	* configure.in: Check for expect.
+
+Thu Oct  3 13:16:19 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* env-setup.shin: Renamed env-setup.sh for autoconf use.
+
+	* init_db, start_servers, start_servers_local, stop_servers:
+		Invoke scripts from source directory or build tree as needed.
+
+	* configure.in, Makefile.in: generate env-setup.sh with proper
+		paths already.
+
+
+Wed Oct  2 13:41:04 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in, Makefile.in: Let autoconf determine path to perl.
+
+Fri Sep 27 14:12:59 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* start_servers, start_servers_local, stop_servers, init_db,
+ 	env-setup.sh: first pass at making TEST_SERVER remote server
+ 	testing work
+
+	* env-setup.sh: set K5ROOT to $TESTDIR/krb5-test-root by default,
+ 	but use an absolute path
+
+Thu Sep 26 17:48:32 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* env-setup.sh, init_db, start_servers_local: use K5ROOT instead
+ 	of /krb5
+
+Thu Sep 26 11:45:56 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* qualname.pl.in: Renamed old qualname to here as perl path needs
+		updating. 
+
+	* Makefile.in (GEN_SCRIPTS): Add qualname.pl
+
+	* start_servers_local, env-setup.sh (QUALNAME): Replace with
+		qualname.pl. 
+
+Tue Sep 24 13:28:54 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* create Makefile.in and configure.in
+
+Mon Sep 23 15:38:58 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* stop_servers_local: delete krb5kdc_rcache after stopping kdc
+
+	* Makefile.ov: create restore_files.sh as symlink to save_files.sh
+
+Wed Sep 11 17:01:06 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* make-host-keytab.pl.in: use kadmin instead of kadm5_keytab
+
+Mon Aug 12 11:36:57 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* init_db: use kdb5_util instead of kdb5_create
+
+Fri Jul 12 14:48:20 1996  Marc Horowitz  <marc@mit.edu>
+
+	* stop_servers_local (true, false): use the path to find these,
+ 	instead of looking in /bin explicitly.
+
+	* start_servers_local (/usr/tmp): /usr/tmp doesn't exist on some
+ 	systems.  Check for that and /var/tmp, and use the one which
+ 	exists.  (true, false): use the path to find these, instead of
+ 	looking in /bin explicitly.
+
+	* make-host-keytab.pl.in: perl5 requires that @ in strings be
+ 	backwhacked.  (EDIT_KEYTAB): ovsec_adm_keytab is now kadm5_keytab.
+	
+  	* init_db: kadmin_create should be kdb5_create
+
diff --git a/mechglue/src/kadmin/testing/scripts/Makefile.in b/mechglue/src/kadmin/testing/scripts/Makefile.in
new file mode 100644
index 000000000..3f58e9248
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/Makefile.in
@@ -0,0 +1,37 @@
+thisconfigdir=./../..
+myfulldir=kadmin/testing/scripts
+mydir=testing/scripts
+BUILDTOP=$(REL)..$(S)..$(S)..
+PERL=@PERL@
+
+.SUFFIXES: .plin .pl
+
+GEN_SCRIPTS = compare_dump.pl fixup-conf-files.pl make-host-keytab.pl \
+	simple_dump.pl verify_xrunner_report.pl qualname.pl
+
+all:: env-setup.sh $(GEN_SCRIPTS) restore_files.sh 
+
+# Should only rebuild env_setup.sh here (use CONFIG_FILES=), but the weird krb5
+# makefile post-processing is unconditional and would trash the makefile.
+env-setup.sh: env-setup.stamp
+env-setup.stamp: $(srcdir)/env-setup.shin $(thisconfigdir)/config.status \
+		Makefile 
+	cd $(thisconfigdir) && \
+		CONFIG_FILES=./testing/scripts/env-setup.sh:./testing/scripts/env-setup.shin $(SHELL) \
+		config.status
+	chmod +x env-setup.sh
+	touch env-setup.stamp
+
+restore_files.sh:
+	rm -f restore_files.sh
+	ln -s $(srcdir)/save_files.sh restore_files.sh
+
+.plin.pl: 
+	-rm -f $@.tmp
+	echo "#!$(PERL)" > $@.tmp
+	sed 1d $< >> $@.tmp
+	chmod +x $@.tmp
+	mv $@.tmp $@
+
+clean::
+	-rm -f $(GEN_SCRIPTS) *.tmp env-setup.sh env-setup.stamp restore_files.sh
diff --git a/mechglue/src/kadmin/testing/scripts/compare_dump.plin b/mechglue/src/kadmin/testing/scripts/compare_dump.plin
new file mode 100755
index 000000000..df93df4a0
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/compare_dump.plin
@@ -0,0 +1,242 @@
+#!/usr/local/bin/perl
+
+#
+# $Id$
+#
+
+# $debug = 1;
+
+sub usage { die "usage: $0 before after changes\n";}
+
+sub unique {
+    local(@list) = @_;
+    local(%ary);
+
+    print "unique? ",join(" ",@list),"\n" if $debug;
+
+    foreach (@list) {
+	return(0) if $ary{$_}++;
+    }
+
+    1;
+}
+
+$before = shift(@ARGV) || &usage;
+$debug++ if $before =~ /^-d/;
+$before = shift(@ARGV) || &usage if $debug;
+$after = shift(@ARGV) || &usage;
+$changes = shift(@ARGV) || &usage;
+@ARGV && &usage;
+
+%policy =
+    (
+     "FIRST",2,
+     "pw_min_life",2,
+     "pw_max_life",3,
+     "pw_min_length",4,
+     "pw_min_classes",5,
+     "pw_history_num",6,
+     "policy_refcnt",7,
+     "LAST",7,
+     );
+
+%princ =
+    (
+     "FIRST",2,
+     "kvno",2,
+     "mod_name",3,
+     "max_life",4,
+     "princ_expire_time",5,
+     "expiration",5,
+     "pw_expiration",6,
+     "attributes",7,
+     "policy",8,
+     "aux_attributes",9,
+     "LAST",9,
+     );
+
+%keytab =
+    (
+     "LAST",-1,
+     );
+
+sub re { # @_ = ($cnt, $line)
+    local($cnt, $line) = @_;
+    local(@fields) = split(' ',$line);
+
+    @list = ('\S+') x $cnt;
+    for $f (@fields[3..$#fields]) {
+	($f =~ /=/) || die "Bad field: $f in $_";
+	if (!defined($this{$`})) { die "Bad parameter $` in $_"; }
+
+        if (($list[$this{$`}] = $') eq '\S+') {
+	    $list[$this{$`}] = '[^\s]+';
+	}
+    }
+    
+    join('\s+',@list)."\$";
+}
+
+open(CHANGES, $changes) || die "Couldn't open $changes: $!\n";
+
+while(<CHANGES>) {
+    next if s/^\s*\#\#\!\s*\#//;
+    next if !s/^\s*\#\#\!\s*//;
+
+    split;
+
+    if ($_[1] =~ /princ/) {
+	%this = %princ;
+	$this = "princ";
+    } elsif ($_[1] =~ /policy/) {
+	%this = %policy;
+	$this = "policy";
+    } elsif ($_[1] =~ /keytab/) {
+	%this = %keytab;
+	$this = $_[1];
+    } else {
+	die "Bad line: $_";
+    }
+
+    $cnt = $this{"LAST"}+1;
+
+    if ($_[0] =~ /add/) {
+	$diff{"+$this\t$_[2]"} = &re($cnt,$_);
+    } elsif ($_[0] =~ /delete/) {
+	$diff{"-$this\t$_[2]"} = &re($cnt,$_);
+    } elsif ($_[0] =~ /changefrom/) {
+	$diff{"-$this\t$_[2]"} = &re($cnt,$_);
+    } elsif ($_[0] =~ /changeto/) {
+	$ndiff{"-$this\t$_[2]"} = &re($cnt,$_);
+    } else {
+	die "Bad line: $_";
+    }
+}
+
+close(CHANGES);
+
+if ($debug) {
+    for (keys %diff) {
+	print " %diff: \"$_\" /$diff{$_}/\n";
+    }
+
+    for (keys %ndiff) {
+	print "%ndiff: \"$_\" /$ndiff{$_}/\n";
+    }
+
+    print "\n";
+}
+
+open(DIFF,"gdiff -u0 $before $after|") || die "Couldn't diff: $!\n";
+
+$warnings = 0;
+
+while(<DIFF>) {
+    next if /^\+{3}/;
+    next if /^\-{3}/;
+    next if /^@@/;
+
+    print "LINE: $_" if $debug;
+
+    split;
+
+    $key = "$_[0]\t$_[1]";
+    $re = $diff{$key};
+
+    delete $diff{$key};
+
+    print "%diff: \"$key\" /$re/\n" if $debug;
+
+    if (!$re) {
+	warn "Unexpected: \"$key\"\n";
+	$warnings++;
+	next;
+    }
+
+    if (!/$re/) {
+	warn "Failed: $key\n";
+	$warnings++;
+	next;
+    }
+
+    if ($new = $ndiff{$key}) {
+	delete $ndiff{$key};
+
+	@new = split(/\\s\+/, $new);
+	for ($i=1;$i<@new;$i++) {
+	    print "NEW: $new[$i]\n" if $debug;
+
+	    if ($new[$i] ne '\S+') {
+		$_[$i] = $new[$i];
+	    }
+	}
+	$_[0] =~ s/^\-//;
+	$key =~ s/^\-/\+/;
+
+	$diff{$key} = join("\t",@_);
+    }
+}
+
+close(DIFF);
+
+open(BEFORE, $before) || die "Couldn't open $before: $!\n";
+
+while(<BEFORE>) {
+    next if !/^keytab/;
+
+    split;
+
+    if (!$seen{$key = $_[0]." ".$_[1]}++) {
+	$key =~ s/-\d+$//;
+	$ktkeys{$key} .= " ".$_[2];
+	$kttimes{$key} .= " ".$_[3];
+    }
+}
+
+close(BEFORE);
+
+open(AFTER, $after) || die "Couldn't open $after: $!\n";
+
+while(<AFTER>) {
+    next if !/^keytab/;
+
+    split;
+
+    if (!$seen{$key = $_[0]." ".$_[1]}++) {
+	$key =~ s/-\d+$//;
+	$ktkeys{$key} .= " ".$_[2];
+	$kttimes{$key} .= " ".$_[3];
+    }
+}
+
+close(AFTER);
+
+for (keys %diff) {
+    warn "Unseen: \"$_\" /$diff{$_}/\n";
+    $warnings++;
+}
+
+for (keys %ndiff) {
+    warn "Unseen changes: \"$_\" /$ndiff{$_}/\n";
+    $warnings++;
+}
+
+for (keys %ktkeys) {
+    if (!&unique(split(' ',$ktkeys{$_}))) {
+	warn "Some keys not unique for $_\n";
+	$warnings++;
+    }
+}
+
+for (keys %kttimes) {
+    if (!&unique(split(' ',$kttimes{$_}))) {
+	warn "Some timestamps not unique for $_\n";
+	$warnings++;
+    }
+}
+
+if ($warnings) {
+    warn "$warnings warnings.\n";
+}
+
+exit($warnings);
diff --git a/mechglue/src/kadmin/testing/scripts/env-setup.shin b/mechglue/src/kadmin/testing/scripts/env-setup.shin
new file mode 100755
index 000000000..03e6d065e
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/env-setup.shin
@@ -0,0 +1,118 @@
+#!/bin/sh
+#
+# The KADM5 unit tests were developed to work under gmake.  As a
+# result, they expect to inherit a number of environment variables.
+# Rather than rewrite the tests, we simply use this script as an
+# execution wrapper that sets all the necessary environment variables
+# before running the program specified on its command line.
+#
+# The variable settings all came from OV's config.mk.
+#
+# Usage: env-setup.sh <command line>
+#
+
+TOP=@RBUILD@/kadmin
+STOP=@S_TOP@/kadmin
+export TOP
+export STOP
+# These two may be needed in case $libdir references them.
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@ ; eval "libdir=$libdir"; export libdir
+
+# The shared library run time setup
+TOPLIBD=@RBUILD@/lib
+PROG_LIBPATH=-L@RBUILD@/lib
+BUILDTOP=@RBUILD@
+# XXX kludge!
+PROG_RPATH=@RBUILD@/lib
+# XXX more kludge!
+FAKEDEST=@RBUILD@/util/fakedest
+# This converts $(TOPLIBD) to $TOPLIBD
+cat > /tmp/env_setup$$ <<\EOF
+@KRB5_RUN_ENV@
+EOF
+
+foo=`sed -e 's/(//g' -e 's/)//g' -e 's/\\\$\\\$/\$/g' /tmp/env_setup$$`
+eval $foo
+
+# This will get put in setup.csh for convenience
+KRB5_RUN_ENV_CSH=`eval echo "$foo" | \
+	sed -e 's/\([^=]*\)=\(.*\)/setenv \1 \2/g' \
+	-e 's/export [^ ;]*;//g'`
+export KRB5_RUN_ENV_CSH
+rm /tmp/env_setup$$
+
+TESTDIR=$TOP/testing; export TESTDIR
+STESTDIR=$STOP/testing; export STESTDIR
+if [ "$K5ROOT" = "" ]; then
+	K5ROOT="`cd $TESTDIR; pwd`/krb5-test-root"
+	export K5ROOT
+fi
+
+# If $VERBOSE_TEST is non-null, enter verbose mode.  Set $VERBOSE to
+# true or false so its exit status identifies the mode.
+if test x$VERBOSE_TEST = x; then
+	VERBOSE=false
+else
+	VERBOSE=true
+fi
+export VERBOSE
+
+REALM=SECURE-TEST.OV.COM; export REALM
+
+if test x$EXPECT = x; then
+    EXPECT=@EXPECT@; export EXPECT
+fi
+
+COMPARE_DUMP=$TESTDIR/scripts/compare_dump.pl; export COMPARE_DUMP
+FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl
+export FIX_CONF_FILES
+INITDB=$STESTDIR/scripts/init_db; export INITDB
+MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl; export MAKE_KEYTAB
+LOCAL_MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl
+export LOCAL_MAKE_KEYTAB
+RESTORE_FILES=$TESTDIR/scripts/restore_files.sh; export RESTORE_FILES
+SAVE_FILES=$STESTDIR/scripts/save_files.sh; export SAVE_FILES
+SIMPLE_DUMP=$TESTDIR/scripts/simple_dump.pl; export SIMPLE_DUMP
+QUALNAME=$TESTDIR/scripts/qualname.pl; export QUALNAME
+TCLUTIL=$STESTDIR/tcl/util.t; export TCLUTIL
+BSDDB_DUMP=$TESTDIR/util/bsddb_dump; export BSDDB_DUMP
+CLNTTCL=$TESTDIR/util/ovsec_kadm_clnt_tcl; export CLNTTCL
+SRVTCL=$TESTDIR/util/ovsec_kadm_srv_tcl; export SRVTCL
+
+KRB5_CONFIG=$K5ROOT/krb5.conf; export KRB5_CONFIG
+KRB5_KDC_PROFILE=$K5ROOT/kdc.conf; export KRB5_KDC_PROFILE
+KRB5_KTNAME=$K5ROOT/ovsec_adm.srvtab; export KRB5_KTNAME
+KRB5CCNAME=$K5ROOT/krb5cc_unit-test; export KRB5CCNAME
+
+if [ "$TEST_SERVER" != "" ]; then
+	MAKE_KEYTAB="$MAKE_KEYTAB -server $TEST_SERVER"
+fi
+if [ "$TEST_PATH" != "" ]; then
+	MAKE_KEYTAB="$MAKE_KEYTAB -top $TEST_PATH"
+fi
+
+if [ "x$PS_ALL" = "x" ]; then
+	ps -axwwu >/dev/null 2>&1
+	ps_bsd=$?
+
+	ps -ef >/dev/null 2>&1
+	ps_sysv=$?
+
+	if [ $ps_bsd = 0 -a $ps_sysv = 1 ]; then
+		PS_ALL="ps -auxww"
+		PS_PID="ps -auxww"
+	elif [ $ps_bsd = 1 -a $ps_sysv = 0 ]; then
+		PS_ALL="ps -ef"
+		PS_PID="ps -fp"
+	else
+		PS_ALL="ps -auxww"
+		PS_PID="ps -auxww"
+		echo "WARNING!  Cannot auto-detect ps type, assuming BSD."
+	fi
+
+	export PS_ALL PS_PID
+fi
+
+exec ${1+"$@"}
diff --git a/mechglue/src/kadmin/testing/scripts/find-make.sh b/mechglue/src/kadmin/testing/scripts/find-make.sh
new file mode 100755
index 000000000..904730dfa
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/find-make.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+POSSIBILITIES='
+/usr/local/bin/gmake
+/usr/local/bin/make
+'
+
+for file in $POSSIBILITIES; do
+	if [ -f $file ]; then
+		echo $file
+		exit 0
+	fi
+done
+
+echo gmake
+echo '$0 could not find make!' 1>&2
+exit 1
+
diff --git a/mechglue/src/kadmin/testing/scripts/fixup-conf-files.plin b/mechglue/src/kadmin/testing/scripts/fixup-conf-files.plin
new file mode 100755
index 000000000..d7834d1c7
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/fixup-conf-files.plin
@@ -0,0 +1,344 @@
+#!/usr/local/bin/perl
+#
+# Usage: fixup-conf-files.pl [-server hostname]
+
+$verbose = $ENV{'VERBOSE_TEST'};
+$archos = $ENV{'ARCH_OS'};
+
+$REALM = "SECURE-TEST.OV.COM";
+
+sub replace {
+    local($old, $new, $backup) = @_;
+    local($dev, $ino, $mode);
+
+    $new = $old.".new" if !$new;
+    $backup = $old.".bak" if !$backup;
+
+    chmod($mode,$new) if (($dev, $ino, $mode) = stat($old));
+
+    unlink($backup);
+    link($old, $backup) || die "couldn't make backup link: $backup: $!\n"
+	if -e $old;
+    rename($new, $old) || die "couldn't rename $old to $new: $!\n";
+}
+
+if (@ARGV == 2 && $ARGV[0] eq "-server") {
+    $servername = $ARGV[1];
+} elsif (@ARGV != 0) {
+    print STDERR "Usage: $0 fixup-conf-files.pl [-server hostname]\n";
+}
+
+sub canonicalize_name {
+    local($hostname) = @_;
+    local($d, $addr, $addrtype);
+    
+    ($host,$d,$addrtype,$d,$addr) = gethostbyname($hostname);
+    die "couldn't get hostname $hostname\n" if !$host;
+    ($host) = gethostbyaddr($addr,$addrtype);
+    die "couldn't reverse-resolve $hostname\n" if !$host;
+    return $host;
+}
+
+## Get server's canonical hostname.
+if ($servername) {
+    $serverhost = $servername;
+} else {
+    chop ($serverhost = `hostname`);
+}
+$serverhost = &canonicalize_name($serverhost);
+
+## Get local canonical hostname
+chop($localhost=`hostname`);
+$localhost = &canonicalize_name($localhost);
+
+## parse krb.conf
+
+if (open(KCONF, "/etc/athena/krb.conf")) {
+    chop($hrealm = <KCONF>);
+
+    $confok = 0;
+
+    while(<KCONF>) {
+	$confs .= $_ if !/^$REALM\s+/o;
+	$confok = 1 if /^$REALM\s+$serverhost\s+admin\s+server$/oi;
+    }
+
+    close(KCONF);
+}
+
+## rewrite krb.conf if necessary.
+
+if (($hrealm ne $REALM) || !$confok) {
+    print "Rewriting /etc/athena/krb.conf...\n" if $verbose;
+
+    open(KCONF, ">/etc/athena/krb.conf.new") ||
+	die "couldn't open /etc/athena/krb.conf.new: $!\n";
+
+    print KCONF "$REALM\n";
+    print KCONF "$REALM $serverhost admin server\n";
+    print KCONF $confs;
+
+    close(KCONF);
+
+    &replace("/etc/athena/krb.conf");
+}
+
+## parse krb.realms
+
+if (open(KREALMS, "/etc/athena/krb.realms")) {
+    $serverrealmok = 0;
+    $localrealmok = 0;
+
+    while(<KREALMS>) {
+	$realms .= $_
+	    if !/^$serverhost\s+$REALM$/oi && !/^$localhost\s+$REALM$/oi;
+	$serverrealmok = 1 if /^$serverhost\s+$REALM$/oi;
+	$localrealmok = 1 if /^$localhost\s+$REALM$/oi;
+    }
+
+    close(KREALMS);
+}
+
+## rewrite krb.realms if necessary.
+
+if (!$serverrealmok || !$localrealmok) {
+    print "Rewriting /etc/athean/krb.realms...\n" if $verbose;
+
+    open(KREALMS, ">/etc/athena/krb.realms.new") ||
+	die "couldn't open /etc/athena/krb.realms.new: $!\n";
+
+    print KREALMS "$serverhost $REALM\n";
+    print KREALMS "$localhost $REALM\n" if ($localhost ne $serverhost);
+    print KREALMS $realms;
+
+    close(KREALMS);
+
+    &replace("/etc/athena/krb.realms");
+}
+
+# ## read /etc/passwd
+# 
+# open(PASSWD, "/etc/passwd") || die "couldn't open /etc/passwd: $!\n";
+# 
+# $passok = 0;
+# 
+# if ($archos ne "solaris2.3") {
+#     %mypass =
+# 	(
+# 	 "root", crypt("testroot","St"),
+# 	 "testenc", crypt("notath","HJ"),
+# 	 "testuser", "KERBEROS5",
+# 	 "pol1", "KERBEROS5",
+# 	 "pol2", "KERBEROS5",
+# 	 "pol3", "KERBEROS5",
+# 	 );
+# } else {
+#     %mypass =
+# 	(
+# 	 "root", "x", 
+# 	 "testenc", "x",
+# 	 "testuser", "x",
+# 	 "pol1", "x",
+# 	 "pol2", "x", 
+# 	 "pol3", "x",
+# 	 );
+#     %myshadow =
+# 	(
+# 	 "root", crypt("testroot","St"),
+# 	 "testenc", crypt("notath","HJ"),
+# 	 "testuser", "KERBEROS5",
+# 	 "pol1", "KERBEROS5",
+# 	 "pol2", "KERBEROS5",
+# 	 "pol3", "KERBEROS5",
+# 	 );
+# }    
+# 
+# $chpw = 0;
+# 
+# while(<PASSWD>) {
+#     if (/^([^:]+):([^:]+):/ && $mypass{$1}) {
+# 	$users{$1}++;
+# 	if ($2 ne $mypass{$1}) {
+# 	    s/^([^:]+):([^:]+):/$1:$mypass{$1}:/;
+# 	    $chpw++;
+# 	}
+#     }
+#     $pass .= $_;
+# }
+# 
+# $passok = 1;
+# 
+# for (keys %mypass) {
+#     if (!$users{$_}) {
+# 	$pass .= "$_:$mypass{$_}:32765:101::/tmp:/bin/csh\n";
+# 	$passok = 0;
+#     }
+# }
+# close(PASSWD);
+# 
+# ## rewrite passwd if necessary.
+# 
+# if ($chpw || !$passok) {
+#     print "Rewriting /etc/passwd...\n" if $verbose;
+# 
+#     open(PASSWD, ">/etc/passwd.new") ||
+# 	die "couldn't open /etc/passwd.new: $!\n";
+# 
+#     print PASSWD $pass;
+# 
+#     close(PASSWD);
+# 
+#     &replace("/etc/passwd");
+# }
+# 
+# if ($archos eq "solaris2.3") {
+# 
+# ## read /etc/shadow
+# 
+#     open(SHADOW, "/etc/shadow") || die "couldn't open /etc/shadow: $!\n";
+# 
+#     $shadowok = 0;
+#     $chpw = 0;
+#     %users = ();
+# 
+#     while(<SHADOW>) {
+# 	if (/^([^:]+):([^:]+):/ && $myshadow{$1}) {
+# 	    $users{$1}++;
+# 	    if ($2 ne $myshadow{$1}) {
+# 		s/^([^:]+):([^:]+):/$1:$myshadow{$1}:/;
+# 		$chpw++;
+# 	    }
+# 	}
+# 	$shadow .= $_;
+#     }
+#     
+#     $shadowok = 1;
+#     
+#     for (keys %myshadow) {
+# 	if (!$users{$_}) {
+# 	    $shadow .= "$_:$myshadow{$_}:6445::::::\n";
+# 	    $shadowok = 0;
+# 	}
+#     }
+#     close(SHADOW);
+#     
+# ## rewrite shadow if necessary.
+#     
+#     if ($chpw || !$shadowok) {
+# 	print "Rewriting /etc/shadow...\n" if $verbose;
+# 	
+# 	open(SHADOW, ">/etc/shadow.new") ||
+# 	    die "couldn't open /etc/shadow.new: $!\n";
+# 	
+# 	print SHADOW $shadow;
+# 	
+# 	close(SHADOW);
+# 	
+# 	&replace("/etc/shadow");
+#     }
+# }
+# 
+# if ($archos eq "aix3.2") {
+# 
+# ## read /etc/security/passwd
+# 
+#     open(SHADOW, "/etc/security/passwd") || die "couldn't open /etc/security/passwd: $!\n";
+# 
+#     $shadowok = 0;
+#     %users = ();
+# 
+#     while(<SHADOW>) {
+# 	if (/^([^:]+):\s*$/ && $mypass{$1}) {
+# 	    $user = $1;
+# 	    $users{$user}++;
+# 	    # arrange for the user to have a password entry and none other
+# 	    while (<SHADOW>) {
+# 		last if (!/=/);
+# 	    }
+# 	    $shadow .= "$user:\n\tpassword = KERBEROS5\n\n";
+# 	} else {
+# 	    $shadow .= $_;
+# 	}
+#     }
+#     
+#     $shadowok = 1;
+#     
+#     for (keys %mypass) {
+# 	if (!$users{$_}) {
+# 	    $shadow .= "$_:\n\tpassword = KERBEROS5\n\n";
+# 	    $shadowok = 0;
+# 	}
+#     }
+#     close(SHADOW);
+#     
+# ## rewrite shadow if necessary.
+#     
+#     if (!$shadowok) {
+# 	print "Rewriting /etc/security/passwd...\n" if $verbose;
+# 	
+# 	open(SHADOW, ">/etc/security/passwd.new") ||
+# 	    die "couldn't open /etc/security/passwd.new: $!\n";
+# 	
+# 	print SHADOW $shadow;
+# 	
+# 	close(SHADOW);
+# 	
+# 	&replace("/etc/security/passwd");
+#     }
+# }
+# 
+# open(SERVICES, "/etc/services") || die "couldn't open /etc/services: $!\n";
+# open(NEW_SERVICES, ">/etc/services.new") ||
+#     die "couldn't open /etc/services.new: $!\n";
+# 
+# print "Rewriting /etc/services...\n" if $verbose;
+# 
+# @needed_services = ('klogin', 'kshell', 'kerberos', 'kerberos-sec',
+# 		    'kerberos5', 'kerberos4', 'kerberos_master', 
+# 		    'passwd_server', 'eklogin', 'krb5_prop',
+# 		    'kerberos_adm', 'kerberos-adm');
+# for (@needed_services) {
+#     $needed_services{$_}++;
+# }
+# 
+# while (<SERVICES>) {
+#     m/^\s*([^\#\s][^\s]+)/;
+#     if ($needed_services{$1}) {
+# 	print "+ Commenting out old entry: $1\n" if $verbose;
+# 	print NEW_SERVICES "# $_";
+#     } else {
+# 	print NEW_SERVICES $_;
+#     }
+# }
+# 
+# close(SERVICES);
+# 
+# print NEW_SERVICES <<EOF || die "writing to /etc/services.new: $!\n";
+# 
+# klogin		543/tcp				# Kerberos authenticated rlogin
+# kshell          544/tcp         cmd             # and remote shell
+# kerberos	88/udp 		kdc		# Kerberos authentication--udp
+# kerberos	88/tcp 		kdc		# Kerberos authentication--tcp
+# kerberos-sec	750/udp 			# Kerberos authentication--udp
+# kerberos-sec	750/tcp 			# Kerberos authentication--tcp
+# kerberos5	88/udp 		kdc		# Kerberos authentication--udp
+# kerberos5	88/tcp 		kdc		# Kerberos authentication--tcp
+# kerberos4	750/udp 			# Kerberos authentication--udp
+# kerberos4	750/tcp 			# Kerberos authentication--tcp
+# kerberos_master	751/udp 			# Kerberos authentication
+# kerberos_master	751/tcp 			# Kerberos authentication
+# passwd_server	752/udp				# Kerberos passwd server
+# eklogin		2105/tcp			# Kerberos encrypted rlogin
+# krb5_prop	754/tcp				# Kerberos slave propagation
+# kerberos_adm	752/tcp				# Kerberos 5 admin/changepw
+# kerberos-adm	752/tcp				# Kerberos 5 admin/changepw
+# EOF
+# 
+# close(NEW_SERVICES) || die "error closing /etc/services.new: $!\n";
+# 
+# rename("/etc/services", "/etc/services.old") ||
+#     die "couldn't rename /etc/services to /etc/services.old: $!\n";
+# rename("/etc/services.new", "/etc/services") ||
+#     die "couldn't rename /etc/services.new to /etc/services: $!\n";
+# unlink("/etc/services.old") || die "couldn't unlink /etc/services: $!\n";
+# 
diff --git a/mechglue/src/kadmin/testing/scripts/init_db b/mechglue/src/kadmin/testing/scripts/init_db
new file mode 100755
index 000000000..5ebacc091
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/init_db
@@ -0,0 +1,227 @@
+#!/bin/sh
+
+if $VERBOSE; then
+	REDIRECT=
+else
+	REDIRECT='>/dev/null'
+fi
+
+# Requires that $K5ROOT, /etc/krb.conf, and .k5.$REALM be world-writeable.
+
+if [ "$TOP" = "" ]; then
+	echo "init_db: Environment variable \$TOP must point to top of build tree" 1>&2
+	exit 1
+fi
+
+if [ "$STOP" = "" ]; then
+	echo "init_db: Environment variable \$STOP must point to top of source tree" 1>&2
+	exit 1
+fi
+
+if [ "$libdir" = "" ]; then
+	echo "init_db: Environment variable \$libdir must point to library install directory" 1>&2
+	exit 1
+fi
+
+IROOT=$TOP/..
+ADMIN=$TOP/dbutil
+BIN=$IROOT/bin
+ETC=$IROOT/etc
+MODDIR=$TOP/../util/fakedest$libdir/db-modules
+SBIN=$TOP/keytab:$TOP/server
+DUMMY=${REALM=SECURE-TEST.OV.COM}; export REALM
+
+if [ ! -d $MODDIR ]; then
+	echo "+++" 1>&2
+	echo "+++ Error!  $MODDIR does not exist!" 1>&2
+	echo "+++ The MODDIR variable should point to the directory in which" 1>&2
+	echo "+++ database modules have been installed for testing." 1>&2
+	echo "+++" 1>&2
+	exit 1
+fi
+
+DUMMY=${TESTDIR=$TOP/testing}; export TESTDIR
+DUMMY=${STESTDIR=$STOP/testing}
+DUMMY=${SRVTCL=$TESTDIR/util/ovsec_kadm_srv_tcl}; export SRVTCL
+DUMMY=${TCLUTIL=$STESTDIR/tcl/util.t}; export TCLUTIL
+DUMMY=${LOCAL_MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl}
+
+PATH=$ADMIN:$BIN:$ETC:$SBIN:$PATH; export PATH
+
+if [ ! -x $SRVTCL ]; then
+	echo "+++" 1>&2
+	echo "+++ Error!  $SRVTCL does not exist!" 1>&2
+	echo "+++ It was probably not compiled because TCL was not available.  If you" 1>&2
+	echo "+++ now have TCL installed, cd into that directory, re-run configure" 1>&2 
+	echo "+++ with the --with-tcl option, and then re-run make." 1>&2
+	echo "+++" 1>&2
+
+	exit 1
+fi
+
+rm -rf $K5ROOT/*
+if [ -d $K5ROOT ]; then
+	true
+else
+	mkdir $K5ROOT
+fi
+
+# touch $K5ROOT/syslog
+# for pid in `$PS_ALL | awk '/syslogd/ && !/awk/  {print $2}'` ; do
+# 	case "$pid" in
+# 		xxx) ;;
+# 		*)
+# 			if $VERBOSE; then $PS_PID$pid | grep -v COMMAND; fi
+# 			kill -1 $pid
+# 			;;
+# 	esac
+# done
+
+qualname=`$QUALNAME`
+
+sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
+	-e "s/__KDCHOST__/$qualname/g" \
+	-e "s/__LOCALHOST__/$qualname/g" \
+	-e "s#__MODDIR__#$MODDIR#g" \
+	< $STESTDIR/proto/krb5.conf.proto > $K5ROOT/krb5.conf
+sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
+	< $STESTDIR/proto/kdc.conf.proto > $K5ROOT/kdc.conf
+
+eval kdb5_util -r $REALM create -P mrroot -s $REDIRECT || exit 1
+
+cp $STESTDIR/proto/ovsec_adm.dict $K5ROOT/ovsec_adm.dict
+
+cat - > /tmp/init_db$$ <<\EOF
+source $env(TCLUTIL)
+set r $env(REALM)
+if {[info exists env(USER)]} {
+    set whoami $env(USER)
+} else {
+    set whoami [exec whoami]
+}
+
+set cmds {
+    {ovsec_kadm_init $env(SRVTCL) mrroot null $r $OVSEC_KADM_STRUCT_VERSION \
+	    $OVSEC_KADM_API_VERSION_1 server_handle}
+
+    {ovsec_kadm_create_policy $server_handle "test-pol 0 10000 8 2 3 0" \
+	    {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LENGTH OVSEC_KADM_PW_MIN_CLASSES OVSEC_KADM_PW_MAX_LIFE OVSEC_KADM_PW_HISTORY_NUM}}
+    {ovsec_kadm_create_policy $server_handle "once-a-min 30 0 0 0 0 0" \
+	    {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LIFE}}
+    {ovsec_kadm_create_policy $server_handle "dict-only 0 0 0 0 0 0" \
+	    {OVSEC_KADM_POLICY}}
+    {ovsec_kadm_create_policy $server_handle [simple_policy test-pol-nopw] \
+	    {OVSEC_KADM_POLICY}}
+
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal testuser@$r] {OVSEC_KADM_PRINCIPAL} notathena}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal test1@$r] {OVSEC_KADM_PRINCIPAL} test1}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal test2@$r] {OVSEC_KADM_PRINCIPAL} test2}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal test3@$r] {OVSEC_KADM_PRINCIPAL} test3}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/get@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/modify@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/delete@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/add@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/none@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/rename@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/mod-add@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/mod-delete@$r] {OVSEC_KADM_PRINCIPAL} \
+	    admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/get-add@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/get-delete@$r] {OVSEC_KADM_PRINCIPAL} \
+	    admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/get-mod@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/no-add@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal admin/no-delete@$r] {OVSEC_KADM_PRINCIPAL} admin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [princ_w_pol pol1@$r test-pol] {OVSEC_KADM_PRINCIPAL \
+	    OVSEC_KADM_POLICY} pol111111}
+    {ovsec_kadm_create_principal $server_handle \
+	    [princ_w_pol pol2@$r once-a-min] {OVSEC_KADM_PRINCIPAL \
+	    OVSEC_KADM_POLICY} pol222222}
+    {ovsec_kadm_create_principal $server_handle \
+	    [princ_w_pol pol3@$r dict-only] {OVSEC_KADM_PRINCIPAL \
+	    OVSEC_KADM_POLICY} pol333333}
+    {ovsec_kadm_create_principal $server_handle \
+	    [princ_w_pol admin/get-pol@$r test-pol-nopw] \
+	    {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} StupidAdmin}
+    {ovsec_kadm_create_principal $server_handle \
+	    [princ_w_pol admin/pol@$r test-pol-nopw] {OVSEC_KADM_PRINCIPAL \
+	    OVSEC_KADM_POLICY} StupidAdmin}
+
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal changepw/kerberos] \
+            {OVSEC_KADM_PRINCIPAL} {XXX THIS IS WRONG}}
+
+    {ovsec_kadm_create_principal $server_handle \
+	    [simple_principal $whoami] \
+	    {OVSEC_KADM_PRINCIPAL} $whoami}
+
+    {ovsec_kadm_destroy $server_handle}
+}
+
+foreach cmd $cmds {
+    if {[catch $cmd output]} {
+	puts stderr "Error!  Command: $cmd\nError: $output"
+	exit 1
+    } else {
+	puts stdout $output
+    }
+}
+EOF
+eval "$SRVTCL < /tmp/init_db$$ $REDIRECT"
+rm /tmp/init_db$$
+
+if [ $? -ne 0 ]; then
+	echo "Error in $SRVTCL!" 1>&2
+	exit 1
+fi
+
+cat > $K5ROOT/ovsec_adm.acl <<EOF
+admin@$REALM			admcil
+admin/get@$REALM		il
+admin/modify@$REALM		mc
+admin/delete@$REALM		d
+admin/add@$REALM		a
+admin/get-pol@$REALM		il
+admin/rename@$REALM		adil
+admin/mod-add@$REALM		amc
+admin/mod-delete@$REALM		mcd
+admin/get-add@$REALM		ail
+admin/get-delete@$REALM		ild
+admin/get-mod@$REALM		ilmc
+admin/no-add@$REALM		mcdil
+admin/no-delete@$REALM		amcil
+changepw/kerberos@$REALM	cil
+
+EOF
+
+eval $LOCAL_MAKE_KEYTAB -princ kadmin/admin -princ kadmin/changepw -princ ovsec_adm/admin -princ ovsec_adm/changepw $K5ROOT/ovsec_adm.srvtab $REDIRECT
+
+# Create $K5ROOT/setup.csh to make it easy to run other programs against
+# the test db
+cat > $K5ROOT/setup.csh <<EOF
+setenv KRB5_CONFIG $KRB5_CONFIG
+setenv KRB5_KDC_PROFILE $KRB5_KDC_PROFILE
+setenv KRB5_KTNAME $KRB5_KTNAME
+$KRB5_RUN_ENV_CSH
+EOF
+
diff --git a/mechglue/src/kadmin/testing/scripts/make-host-keytab.plin b/mechglue/src/kadmin/testing/scripts/make-host-keytab.plin
new file mode 100755
index 000000000..ad509c35c
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/make-host-keytab.plin
@@ -0,0 +1,144 @@
+#!/usr/local/bin/perl 
+
+$server = undef;
+@princs = ();
+$top = undef;
+
+($whoami = $0) =~ s,.*/,,;
+$usage = "Usage: $whoami [ -server server ] [ -princ principal ]
+		[ -top dirname ] [ -verbose ] filename
+	Server defaults to the local host.
+	Default principals are host/hostname\@SECURE-TEST.OV.COM and
+	  test/hostname\@SECURE-TEST.OV.COM.
+	If any principals are specified, the default principals are
+	  not added to the srvtab.
+	The string \"xCANONHOSTx\" in a principal specification will be
+	  replaced by the canonical host name of the local host.";
+
+@ORIG_ARGV = @ARGV;
+
+while (($_ = $ARGV[0]) && /^-/) {
+    shift;
+    if (/^-server$/) {
+	($server = shift) || die "Missing argument to $_ option.\n$usage\n";
+    }
+    elsif (/^-princ$/) {
+	($princ = shift) || die "Missing argument to $_ option.\n$usage\n";
+	push(@princs, $princ);
+    }
+    elsif (/^-top$/) {
+	($top = shift) || die "Missing argument to $_ option.\n$usage\n";
+    }
+    elsif (/^-verbose$/) {
+	$verbose++;
+    }
+    elsif (/^--$/) {
+	last;
+    }
+    else {
+	die "Unknown option $_.\n$usage\n";
+    }
+}
+
+@princs = ("host/xCANONHOSTx\@SECURE-TEST.OV.COM",
+	   "test/xCANONHOSTx\@SECURE-TEST.OV.COM")
+    if (! @princs);
+
+$ktfile = shift(@ARGV) || die "need a keytab file\n";
+
+$verbose++ if ($ENV{'VERBOSE_TEST'});
+
+print "In $0 @ORIG_ARGV...\n" if ($verbose);
+
+chop ($canonhost = `hostname`);
+
+($canonhost,$aliases,$addrtype,$length,@addrs) = gethostbyname($canonhost);
+die "couldn't get canonical hostname\n" if !($canonhost && @addrs);
+($canonhost) = gethostbyaddr($addrs[0],$addrtype);
+die "couldn't get canonical hostname\n" if (!$canonhost);
+
+for (@princs) {
+    s/xCANONHOSTx/$canonhost/g;
+}
+
+die "Neither \$TOP nor \$TESTDIR is set, and -top not specified.\n"
+    if (! ($top || $ENV{'TOP'} || $ENV{'TESTDIR'}));
+
+$top = $ENV{'TOP'} if (! $top);
+$TESTDIR = ($ENV{'TESTDIR'} || "$top/testing");
+$MAKE_KEYTAB = ($ENV{'MAKE_KEYTAB'} || "$TESTDIR/scripts/$whoami");
+$SRVTCL = ($ENV{'SRVTCL'} || "$TESTDIR/util/ovsec_kadm_srv_tcl");
+$TCLUTIL = ($ENV{'TCLUTIL'} || "$TESTDIR/tcl/util.t");
+# This'll be wrong sometimes
+$RSH_CMD = ($ENV{'RSH_CMD'} || '/usr/ucb/rsh');
+$KADMIN = ($ENV{'KADMIN'} || "$top/cli/kadmin.local");
+
+if ($server) {
+# XXX Using /usr/ucb/rsh for now.
+
+# Strip command line options because we're adding our own.
+
+    $MAKE_KEYTAB =~ s/ .*//;
+
+    if ($ENV{'TOP'} && ($top ne $ENV{'TOP'})) {
+# Replace the old TOP with the new one where necessary
+	for ('TESTDIR', 'SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+	    eval "\$$_ =~ s/^\$ENV{'TOP'}/\$top/;";
+	}
+
+# Make the paths as short as possible so our command line isn't too long.
+#	for ('SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+#	    eval "\$$_ =~ s/^\$TESTDIR/\\\\\\\$TESTDIR/;";
+#	}
+#	for ('TESTDIR', 'SRVTCL', 'TCLUTIL', 'MAKE_KEYTAB') {
+#	    eval "\$$_ =~ s/^\$top/\\\\\\\$TOP/;";
+#	}
+    }
+
+    $cmd = "cd $top; \\`testing/scripts/find-make.sh\\` execute TOP=$top ";
+    $cmd .= "VERBOSE_TEST=$verbose " if ($verbose);
+    $cmd .= "TESTDIR=$TESTDIR ";
+    $cmd .= "SRVTCL=$SRVTCL ";
+    $cmd .= "TCLUTIL=$TCLUTIL ";
+
+    $cmd .= "CMD='$MAKE_KEYTAB ";
+    for (@princs) {
+	$cmd .= "-princ $_ ";
+    }
+    $cmd .= " /tmp/make-keytab.$canonhost.$$'";#';
+
+    $cmd = "$RSH_CMD $server -l root -n \"$cmd\"";
+
+    $cmd2 = "$RSH_CMD $server -l root -n \"cat /tmp/make-keytab.$canonhost.$$\" > $ktfile";
+
+    $cmd3 = "$RSH_CMD $server -l root -n \"rm /tmp/make-keytab.$canonhost.$$\"";
+
+    for ($cmd, $cmd2, $cmd3) {
+	print "$_\n" if ($verbose);
+
+	system($_) && die "Couldn't run $_: $!.\n";
+    }
+}
+else {
+    $redirect = "> /dev/null" if (! $verbose);
+
+    # We can ignore errors here, because the ktadd below will fail if
+    # this fails for any reason other than "principal exists"
+    for (@princs) {
+	next if (/^kadmin/);
+	$cmd = "$KADMIN -q 'ank -randkey $_' $redirect 2>&1";
+	system($cmd);
+    }
+    
+    $cmd = "$KADMIN -q 'ktadd -k $ktfile ";
+    $cmd .= " -q " if (! $verbose);
+    $cmd .= "@princs' $redirect";
+    if (system "$cmd") {
+	sleep(1);
+	die "Error in system($cmd)\n";
+    }
+}
+
+if (! -f $ktfile) {
+    die "$ktfile not created.\n";
+}
diff --git a/mechglue/src/kadmin/testing/scripts/qualname.plin b/mechglue/src/kadmin/testing/scripts/qualname.plin
new file mode 100755
index 000000000..883b7dfc8
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/qualname.plin
@@ -0,0 +1,20 @@
+#!/afs/athena/contrib/perl/p
+
+if ($#ARGV == -1) {
+    chop($hostname = `hostname`);
+} else {
+    $hostname = $ARGV[0];
+}
+
+if (! (($type,$addr) = (gethostbyname($hostname))[2,4])) {
+    print STDERR "No such host: $hostname\n";
+    exit(1);
+}
+if (! ($qualname = (gethostbyaddr($addr,$type))[0])) {
+    print STDERR "No address information for host $hostname\n";
+    exit(1);
+}
+
+$qualname =~ tr/A-Z/a-z/;	# lowercase our name for keytab use.
+print "$qualname\n";
+
diff --git a/mechglue/src/kadmin/testing/scripts/save_files.sh b/mechglue/src/kadmin/testing/scripts/save_files.sh
new file mode 100755
index 000000000..72182036f
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/save_files.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+while [ $# -gt 0 ] ; do
+	case $1 in
+		-start_servers)
+			start_servers=$1
+			;;
+	esac
+	shift
+done
+
+# files="/etc/inetd.conf /etc/syslog.conf /etc/krb.conf \
+# 	/etc/krb.realms /etc/passwd /etc/services /etc/v5srvtab \
+# 	/etc/rc.local /etc/shadow /etc/security/passwd /.k5login \
+# 	/.secure/etc/passwd /etc/athena/inetd.conf"
+
+files="/etc/krb.conf /etc/krb.realms /etc/athena/krb.conf \
+	/etc/athena/krb.realms /etc/v5srvtab /etc/krb5.keytab"
+
+name=`basename $0`
+
+make_dne_name()
+{
+	dne_name="/tmp/"`echo $1 | sed -e 's,/,#,g'`".did-not-exist"
+}
+	
+for f in $files ; do
+	if [ "$name" = "save_files.sh" ]; then
+		if [ -f $f.pre-secure ]; then 
+			if $VERBOSE; then
+			     echo "Warning!  $f.pre-secure exists, not saving."
+			fi
+		elif [ ! -f $f ]; then
+			make_dne_name $f
+			cp /dev/null $dne_name
+		else
+			cp $f $f.pre-secure
+		fi
+	else
+		make_dne_name $f
+		if [ -f $dne_name ]; then
+			rm -f $f $dne_name
+		elif [ ! -f $f.pre-secure ]; then
+			if [ "x$start_servers" = "x" ]; then
+			  echo "Warning!  $f.pre-secure does not exist!" 1>&2
+			fi
+		else
+			if cp $f.pre-secure $f; then
+				rm $f.pre-secure
+			else
+				echo "Warning! cp failed!" 1>&2
+			fi
+		fi
+	fi
+done
+
+# DUMMY=${INETD:=/etc/inetd}
+# if $VERBOSE; then
+# 	echo "Killing and restarting $INETD"
+# fi
+# kill `$PS_ALL | awk '/inetd/ && !/awk/ {print $2}'`
+# $INETD
diff --git a/mechglue/src/kadmin/testing/scripts/simple_dump.plin b/mechglue/src/kadmin/testing/scripts/simple_dump.plin
new file mode 100755
index 000000000..ea94ab2d1
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/simple_dump.plin
@@ -0,0 +1,88 @@
+#!/usr/local/bin/perl
+
+#
+# $Id$
+#
+
+## ovsec_adm_export format
+## [0]"policy" [1]name [2]pw_min_life [3]pw_max_life [4]pw_min_length [5]pw_min_classes [6]pw_history_num [7]policy_refcnt
+## [0]"princ" [1]name [2]policy [3]aux_attributes [4]old_key_len [5]admin_history_kvno [6..]old_keys
+$oaevers = "1.0";
+
+open(SORT, "|sort") || die "Couldn't open pipe to sort for output: $!\n";
+
+open(OAE, "$ENV{'TOP'}/install/admin/ovsec_adm_export|") ||
+    die "Couldn't get oae: $!\n";
+
+$header = <OAE>;
+
+die "Not ovsec_adm_export output\n"
+    if ($header !~ /^OpenV\*Secure V(\d+\.\d+)/);
+
+$stdinvers = $1;
+
+die "Expected oae version $oaevers, got $stdinvers instead.\n"
+    if $stdinvers ne $oaevers;
+
+while(<OAE>) {
+    if (/^End of Database/) {
+	last;
+    } elsif (/^policy/) {
+	print SORT;
+    } elsif (/^princ/) {
+	split(/\t/);
+
+	$_[2] = "\"\"" if !$_[2];
+
+	$_[3] = hex("0x".$_[3]);
+
+	$princ{$_[1]} = sprintf("%s\t0x%04x",@_[2,3]);
+    }
+}
+
+## kdb_edit ddb format
+## [0]strlen(principal) [1]strlen(mod_name) [2]key.length [3]alt_key.length [4]salt_length [5]alt_salt_length [6]principal [7]key.key_type [8]key.contents [9]kvno [10]max_life [11]max_renewable_life [12]mkvno [13]expiration [14]pw_expiration [15]last_pwd_change [16]last_success [17]last_failed [18]fail_auth_count [19]mod_name [20]mod_date [21]attributes [22]salt_type [23]salt [24]alt_key.contents [25]alt_salt [26..33]expansion*8;
+$ddbvers = "2.0";
+
+open(DDB, "$ENV{'TOP'}/install/admin/kdb5_edit -r SECURE-TEST.OV.COM -R ddb|") ||
+    die "Couldn't get ddb: $!\n";
+
+$header = <DDB>;
+
+die "Not a kdb5_edit ddb\n"
+    if ($header !~ /^kdb5_edit load_dump version (\d+\.\d+)/);
+
+$stdinvers = $1;
+
+die "Expected ddb version $ddbvers, got $stdinvers instead.\n"
+    if $stdinvers ne $ddbvers;
+
+## [6]principal [9]kvno [19]mod_name [10]max_life [13]expiration [14]pw_expiration [21]attributes // [2]policy [3]aux_attributes
+
+while(<DDB>) {
+    split;
+
+    print SORT join("\t","princ",(@_)[6,9,19,10,13,14],
+		    sprintf("0x%04x",$_[21]),
+		    $princ{$_[6]}),"\n";
+}
+
+close(DDB);
+
+for $keytab (@ARGV) {
+    open(KLIST, "$ENV{'TOP'}/install/bin/klist -k -t -K FILE:$keytab|") ||
+	die "Couldn't list $keytab: $!\n";
+
+    $dummy = <KLIST>;
+    $dummy = <KLIST>;
+    $dummy = <KLIST>;
+
+    while(<KLIST>) {
+	s/^\s+//;
+	split;
+	printf(SORT "keytab:FILE:%s\t%s-%s\t%s\t%s,%s\n",$keytab,
+	       @_[3,0,4,1,2]);
+    }
+}
+
+close(SORT);
diff --git a/mechglue/src/kadmin/testing/scripts/start_servers b/mechglue/src/kadmin/testing/scripts/start_servers
new file mode 100755
index 000000000..b59d97b91
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/start_servers
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# Usage: start_servers [hostname [path]]
+#
+# This script turns a host into a OpenV*Secure primary server for the
+# realm SECURE-TEST.OV.COM.  If no arguments are specified,
+# the local host is affected.  Otherwise, the host hostname is
+# affected; the path argument is the top of the Secure install tree on
+# that host, and if it is not specified the current canonical value of
+# TOP is used.
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${STESTDIR=$STOP/testing}
+DUMMY=${SAVE_FILES=$STESTDIR/scripts/save_files.sh}
+DUMMY=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${START_SERVERS_LOCAL=$STESTDIR/scripts/start_servers_local}
+# This'll be wrong sometimes
+DUMMY=${RSH_CMD=rsh}
+
+local=1
+
+if [ $# -gt 0 ]; then
+	if [ $# != 1 -a $# != 2 ]; then
+		echo "Usage: $0 [hostname [path]]" 1>&2
+		exit 1
+	fi
+
+	local=0
+	hostname=$1
+	if [ $# = 1 ]; then
+		rempath=`sh -c "cd $TOP && pwd"`
+	else
+		rempath=$2
+	fi
+fi
+
+if [ $local = 0 ]; then
+
+	# Fix up the local krb5.conf to point to the remote 
+	localname=`$QUALNAME`
+	sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
+		-e "s/__KDCHOST__/$hostname/g" \
+		-e "s/__LOCALHOST__/$localname/g" \
+		-e "s#__MODDIR__#$TOP/../util/fakedest$libdir/db-modules#g"\
+		< $STESTDIR/proto/krb5.conf.proto > $K5ROOT/krb5.conf
+
+# Using /usr/ucb/rsh and getting rid of "-k $REALM" until we get
+# around to fixing the fact that Kerberos rsh doesn't strip out "-k
+# REALM" when falling back.
+
+	START_SERVERS_LOCAL=`echo $START_SERVERS_LOCAL|sed "s%$TOP%$rempath%"`
+	CMD="$RSH_CMD $hostname -n \
+	  \"sh -c 'VERBOSE_TEST=$VERBOSE_TEST TOP=$rempath \
+	    $rempath/testing/scripts/env-setup.sh \
+		$START_SERVERS_LOCAL $rempath'\""
+
+	if $VERBOSE; then
+		echo "+++"
+		echo "+++ Begin execution of start_servers_local on $hostname"
+		echo "+++"
+		echo $CMD
+	fi
+	eval $CMD
+	if $VERBOSE; then
+		echo "+++"
+		echo "+++ End execution of start_servers_local on $hostname"
+		echo "+++"
+	fi
+else
+	$START_SERVERS_LOCAL
+fi
+
diff --git a/mechglue/src/kadmin/testing/scripts/start_servers_local b/mechglue/src/kadmin/testing/scripts/start_servers_local
new file mode 100755
index 000000000..37f438a25
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/start_servers_local
@@ -0,0 +1,212 @@
+#!/bin/sh
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${STESTDIR=$STOP/testing}
+DUMMY=${SAVE_FILES=$STESTDIR/scripts/save_files.sh}
+DUMMY=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${INITDB=$STESTDIR/scripts/init_db}
+DUMMY=${SRVTCL=$TESTDIR/util/ovsec_kadm_srv_tcl}; export SRVTCL
+DUMMY=${LOCAL_MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl}
+DUMMY=${STOP_SERVERS_LOCAL=$STESTDIR/scripts/stop_servers_local}
+DUMMY=${KRB5RCACHEDIR=$TESTDIR} ; export KRB5RCACHEDIR
+
+if [ -d /usr/tmp ]; then
+	usrtmp=/usr/tmp
+else
+	usrtmp=/var/tmp
+fi
+
+$STOP_SERVERS_LOCAL -start_servers
+
+if $VERBOSE; then
+	REDIRECT=
+else
+	REDIRECT='>/dev/null'
+fi
+
+v4files=false
+while :; do
+	case $1 in
+	-keysalt)
+		shift
+		if [ $# -gt 0 ]; then
+			keysalts="$keysalts $1"
+		else
+			break
+		fi
+		;;
+	-kdcport)
+		shift
+		if [ $# -gt 0 ]; then
+			kdcport=$1
+		else
+			break
+		fi
+		;;
+	-v4files)
+		if [ "`whoami`" != "root" ]; then
+			echo "You must be root to use -v4files!" 1>&2
+			exit 1
+		fi
+		v4files=true
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
+
+if [ $# -gt 1 ]; then
+	echo "Usage: $0 [-kdcport port] [-keysalts tuple] ... [top]" 1>&2
+	exit 1
+elif [ $# = 1 ]; then
+	TOP=$1
+	export TOP
+fi
+
+# fixup the system config files
+if $v4files; then
+	$SAVE_FILES || exit 1
+	$FIX_CONF_FILES || exit 1
+fi
+
+# create a fresh db
+
+$INITDB "$keysalts" || exit 1
+
+# Post-process the config files based on our arguments
+if [ "$keysalts" != "" ]; then
+	sedcmd="s/\([ 	]*supported_enctypes =\).*/\1 $keysalts/"
+	sed -e "$sedcmd" < $K5ROOT/kdc.conf > $K5ROOT/kdc.conf.new
+	mv $K5ROOT/kdc.conf.new $K5ROOT/kdc.conf
+fi
+if [ "$kdcport" != "" ] ; then
+	sedcmd="s/\(kdc_ports = .*\)[ 	]*/\1, $kdcport/"
+	sed -e "$sedcmd" < $K5ROOT/kdc.conf > $K5ROOT/kdc.conf.new
+	mv $K5ROOT/kdc.conf.new $K5ROOT/kdc.conf
+fi
+
+# allow admin to krlogin as root (for cleanup)
+DUMMY=${REALM=SECURE-TEST.OV.COM}; export REALM
+hostname=`hostname`
+QUALNAME=`$TOP/testing/scripts/qualname.pl $hostname`; export QUALNAME
+
+cat - > /tmp/start_servers_local$$ <<\EOF
+source $env(STOP)/testing/tcl/util.t
+set r $env(REALM)
+set q $env(QUALNAME)
+puts stdout [ovsec_kadm_init $env(SRVTCL) mrroot null $r \
+	$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle]
+puts stdout [ovsec_kadm_create_principal $server_handle \
+	[simple_principal host/$q@$r] {OVSEC_KADM_PRINCIPAL} notathena]
+puts stdout [ovsec_kadm_destroy $server_handle]
+EOF
+eval "$SRVTCL < /tmp/start_servers_local$$ $REDIRECT"
+x=$?
+rm /tmp/start_servers_local$$
+if test $x != 0 ; then exit 1 ; fi
+
+# rm -f /etc/v5srvtab
+# eval $LOCAL_MAKE_KEYTAB -princ host/xCANONHOSTx /etc/v5srvtab $REDIRECT
+
+# run the servers (from the build tree)
+
+adm_start_file=/tmp/adm_server_start.$$
+kdc_start_file=/tmp/kdc_server_start.$$
+
+rm -f $kdc_start_file
+
+if test "x$USER" = x ; then
+  USER=$LOGNAME ; export USER
+fi
+
+kdc_args="-R dfl:kdc_rcache.$USER"
+
+(trap "" 2; cd $TOP/../kdc; ./krb5kdc $kdc_args; touch $kdc_start_file) \
+	< /dev/null > $usrtmp/kdc-log.$USER 2>&1 &
+
+s=10
+max_s=60
+sofar_s=0
+timewait_s=300
+
+while true; do
+	rm -f $adm_start_file
+
+	(sleep 5; cd $TOP/server; ./kadmind $ovadm_args; \
+		touch $adm_start_file) < /dev/null > $usrtmp/kadm-log.$USER 2>&1 &
+
+	# wait until they start
+
+	while [ $sofar_s -le $max_s ]; do
+		if $VERBOSE; then
+			echo "Sleeping for $s seconds to allow servers" \
+				"to start..."
+		fi
+
+		sofar_s=`expr $sofar_s + $s`
+
+		sleep $s
+
+		if [ -f $adm_start_file -a -f $kdc_start_file ]; then
+			break
+		fi
+
+	done
+
+	if [ $sofar_s -le $max_s ]; then
+		if $VERBOSE; then
+			LOG_USER='log_user 1'
+		else
+			LOG_USER='log_user 0'
+		fi
+		if $EXPECT <<EOF
+		$LOG_USER
+#		spawn telnet localhost 1751
+# Connect to 127.0.0.1 explicitly, so failure to connect to ::1 will not
+# cause bogus errors.
+		spawn telnet 127.0.0.1 1751
+		expect {
+			"Connection refused" {
+				close
+				wait
+				exit 1
+			}
+			"Connected" {
+				send "close\n"
+				close
+				wait
+				exit 0
+			}
+			default {
+				catch {close}
+				wait
+				exit 1
+			}
+		}
+EOF
+		then
+			rm -f $kdc_start_file $adm_start_file
+			break
+		else
+			if $VERBOSE; then
+				echo "Could not connect to Admin server;" \
+					"attempting restart ($sofar_s" \
+					"seconds so far)."
+			fi
+			max_s=$timewait_s
+			continue
+		fi
+	else
+		echo "Admin server or KDC failed to start after $sofar_s" \
+			"seconds." 1>&2
+		if [ ! -f $adm_start_file ]; then
+		    echo "  No admin server start file $adm_start_file." 1>&2
+		fi
+		if [ ! -f $kdc_start_file ]; then
+		    echo "  No KDC start file $adm_start_file." 1>&2
+		fi
+		exit 1
+	fi
+done
diff --git a/mechglue/src/kadmin/testing/scripts/stop_servers b/mechglue/src/kadmin/testing/scripts/stop_servers
new file mode 100755
index 000000000..9542fada8
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/stop_servers
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# Usage: stop_servers [hostname [path]]
+#
+# This script turns a host into a OpenV*Secure primary server for the
+# realm SECURE-TEST.OV.COM.  If no arguments are specified,
+# the local host is affected.  Otherwise, the host hostname is
+# affected; the path argument is the top of the Secure install tree on
+# that host, and if it is not specified the current canonical value of
+# TOP is used.
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${STESTDIR=$STOP/testing}
+DUMMY=${FIX_CONF_FILES=$TESTDIR/scripts/fixup-conf-files.pl}
+DUMMY=${STOP_SERVERS_LOCAL=$STESTDIR/scripts/stop_servers_local}
+# This'll be wrong sometimes
+DUMMY=${RSH_CMD=rsh}
+DUMMY=${RESTORE_FILES=$TESTDIR/scripts/restore_files.sh}
+
+local=1
+
+if [ $# -gt 0 ]; then
+	if [ $# != 1 -a $# != 2 ]; then
+		echo "Usage: $0 [hostname [path]]" 1>&2
+		exit 1
+	fi
+
+	local=0
+	hostname=$1
+	if [ $# = 1 ]; then
+		rempath=`sh -c "cd $TOP && pwd"`
+	else
+		rempath=$2
+	fi
+fi
+
+if [ $local = 0 ]; then
+	if $VERBOSE; then
+		echo "+++ Stopping servers on remote host $hostname..."
+	fi
+
+	STOP_SERVERS_LOCAL=`echo $STOP_SERVERS_LOCAL | sed "s%$TOP%$rempath%"`
+	CMD="$RSH_CMD $hostname -n \
+	      \"sh -c 'VERBOSE_TEST=$VERBOSE_TEST TOP=$rempath \
+		$rempath/testing/scripts/env-setup.sh \
+		   $STOP_SERVERS_LOCAL $rempath'\""
+
+	if $VERBOSE; then
+		echo "+++"
+		echo "+++ Begin execution of stop_servers_local on $hostname"
+		echo "+++"
+		echo $CMD
+	fi
+	eval $CMD
+	if $VERBOSE; then
+		echo "+++"
+		echo "+++ End execution of stop_servers_local on $hostname"
+		echo "+++"
+	fi
+else
+	$STOP_SERVERS_LOCAL
+fi
diff --git a/mechglue/src/kadmin/testing/scripts/stop_servers_local b/mechglue/src/kadmin/testing/scripts/stop_servers_local
new file mode 100755
index 000000000..15700f501
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/stop_servers_local
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${RESTORE_FILES=$TESTDIR/scripts/restore_files.sh}
+DUMMY=${KRB5RCACHEDIR=$TESTDIR}
+
+v4files=false
+while [ $# -gt 0 ] ; do
+	case $1 in
+		-start_servers)
+			start_servers=$1
+			;;
+		-v4files)
+			v4files=true
+			;;
+		*) 
+			TOP=$1
+			export TOP
+			;;
+	esac
+	shift
+done
+
+# kill any running servers.
+
+if $VERBOSE; then echo "Killing servers:"; fi
+
+for pid in xxx \
+	`$PS_ALL | grep krb5kdc | grep -v grep | awk '{print $2}'` \
+	`$PS_ALL | grep kadmind | grep -v grep | awk '{print $2}'` \
+	; do
+	case "$pid" in
+		xxx)
+			;;
+		*)
+			if $VERBOSE; then $PS_PID$pid | grep -v COMMAND; fi
+			kill $pid
+			;;
+	esac
+done
+
+# Destroy the kdc replay cache so we don't lose if we try to run the
+# KDC as another unix user.
+if test "x$USER" = x ; then
+  USER=$LOGNAME
+fi
+rm -f $KRB5RCACHEDIR/krb5kdc_rcache.$USER
+
+# restore saved system config files
+if $v4files; then
+	$RESTORE_FILES $start_servers
+fi
+exit 0
diff --git a/mechglue/src/kadmin/testing/scripts/verify_xrunner_report.plin b/mechglue/src/kadmin/testing/scripts/verify_xrunner_report.plin
new file mode 100755
index 000000000..9d83c3ea2
--- /dev/null
+++ b/mechglue/src/kadmin/testing/scripts/verify_xrunner_report.plin
@@ -0,0 +1,38 @@
+#!/usr/local/bin/perl
+
+sub usage { die "usage: $0 reportfile\n"; }
+
+$report = shift(@ARGV) || die &usage;
+
+open(REPORT, $report) || die "Couldn't open $report: $!\n";
+
+while(<REPORT>) {
+    if (/Process termination:/ && !/\bOK\b/) {
+	warn "Process termination not OK\n";
+	$warnings++;
+    } elsif (/Number of detected mismatches:\s*(\d+)/ && ($1 ne "0")) {
+	warn "Number of detected mismatches = $1\n";
+	$warnings++;
+    } elsif (/Detailed Results Description/) {
+	break;
+    }
+}
+
+while(<REPORT>) {
+    next if !/^\d+\s+/;
+
+    split;
+
+    if (($_[2] ne "run") &&
+	($_[2] ne "OK") &&
+	($_[2] ne "end-of-test")) {
+	warn "Unexpected result code $_[2] from test $_[4]\n";
+	$warnings++;
+    }
+}
+
+if ($warnings) {
+    warn "$warnings warnings.\n";
+}
+
+exit($warnings);
diff --git a/mechglue/src/kadmin/testing/tcl/util.t b/mechglue/src/kadmin/testing/tcl/util.t
new file mode 100644
index 000000000..f4688aeee
--- /dev/null
+++ b/mechglue/src/kadmin/testing/tcl/util.t
@@ -0,0 +1,61 @@
+proc simple_principal {name} {
+    return "{$name} 0 0 0 0 {$name} 0 0 0 0 null 0"
+}
+
+proc princ_w_pol {name policy} {
+    return "{$name} 0 0 0 0 {$name} 0 0 0 0 {$policy} 0"
+}
+
+proc simple_policy {name} {
+    return "{$name} 0 0 0 0 0 0"
+}
+
+proc config_params {masks values} {
+    if {[llength $masks] != [llength $values]} {
+	error "config_params: length of mask and values differ"
+    }
+
+    set params [list $masks 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 {}]
+    for {set i 0} {$i < [llength $masks]} {incr i} {
+	set mask [lindex $masks $i]
+	set value [lindex $values $i]
+	switch -glob -- $mask {
+	    "KADM5_CONFIG_REALM" {set params [lreplace $params 1 1 $value]}
+	    "KADM5_CONFIG_PROFILE" {set params [lreplace $params 2 2 $value]}
+	    "KADM5_CONFIG_KADMIND_PORT" {
+		set params [lreplace $params 3 3 $value]}
+	    "KADM5_CONFIG_ADMIN_SERVER" {
+		set params [lreplace $params 4 4 $value]}
+	    "KADM5_CONFIG_DBNAME" {set params [lreplace $params 5 5 $value]}
+	    "KADM5_CONFIG_ADBNAME" {set params [lreplace $params 6 6 $value]}
+	    "KADM5_CONFIG_ADB_LOCKFILE" {
+		set params [lreplace $params 7 7 $value]}
+	    "KADM5_CONFIG_ADMIN_KEYTAB" {
+		set params [lreplace $params 8 8 $value]}
+	    "KADM5_CONFIG_ACL_FILE" {set params [lreplace $params 9 9 $value]}
+	    "KADM5_CONFIG_DICT_FILE" {
+		set params [lreplace $params 10 10 $value]}
+	    "KADM5_CONFIG_MKEY_FROM_KBD" {
+		set params [lreplace $params 11 11 $value]}
+	    "KADM5_CONFIG_STASH_FILE" {
+		set params [lreplace $params 12 12 $value]}
+	    "KADM5_CONFIG_MKEY_NAME" {
+		set params [lreplace $params 13 13 $value]}
+	    "KADM5_CONFIG_ENCTYPE" {set params [lreplace $params 14 14 $value]}
+	    "KADM5_CONFIG_MAX_LIFE" {
+		set params [lreplace $params 15 15 $value]}
+	    "KADM5_CONFIG_MAX_RLIFE" {
+		set params [lreplace $params 16 16 $value]}
+	    "KADM5_CONFIG_EXPIRATION" {
+		set params [lreplace $params 17 17 $value]}
+	    "KADM5_CONFIG_FLAGS" {set params [lreplace $params 18 18 $value]}
+	    "KADM5_CONFIG_ENCTYPES" {
+		set params [lreplace $params 19 20 [llength $value] $value]}
+	    "*" {error "config_params: unknown mask $mask"}
+	}
+    }
+    return $params
+}
+
+	    
+
diff --git a/mechglue/src/kadmin/testing/util/ChangeLog b/mechglue/src/kadmin/testing/util/ChangeLog
new file mode 100644
index 000000000..ad3aff92c
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/ChangeLog
@@ -0,0 +1,220 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* tcl_kadm5.c, tcl_ovsec_kadm.c: Don't include k5-int.h.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KDB_DEP_LIB): Use THREAD_LINKOPTS instead of
+	explicitly using -lpthread.
+
+	Novell merge.
+	* Makefile.in:
+	* tcl_kadm5.c:
+	* tcl_ovsec_kadm.c:
+
+2005-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* tcl_kadm5.c (unparse_err): Add entries for KRB5_CC_NOTFOUND and
+	KRB5_FCC_NOFILE, to handle changes in client_init.c.
+
+2004-07-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* tcl_kadm5.c (parse_flags, parse_keysalts, parse_key_data,
+	parse_tl_data, parse_principal_ent, parse_policy_ent): Use
+	Tcl_Free, not free, to release storage allocated by
+	Tcl_SplitList.
+	* tcl_ovsec_kadm.c (parse_flags, parse_principal_ent,
+	parse_policy_ent): Likewise.
+
+2003-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (DEFINES): New variable.  Define HAS_STDARG for Tcl
+	headers.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-11-04  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Use $(TCL_MAYBE_RPATH).
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* tcl_kadm5.c (unparse_err): Handle
+	KADM5_MISSING_KRB5_CONF_PARAMS.
+
+2002-07-15  Ezra Peisach  <epeisach@med-dotty.bu.edu>
+
+	* tcl_kadm5.c: Cleanup warnings for variables set but not used.
+	* tcl_ovsec_kadm.c (unparse_err): Likewise.
+
+2002-03-07  Ken Raeburn  <raeburn@mit.edu>
+	
+	* tcl_kadm5.c (unparse_err): Print error message, not just number,
+	to stderr for unrecognized error code.
+	* tcl_ovsec_kadm.c (unparse_err): Likewise.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): All files live in srcdir.
+
+2001-07-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* tcl_kadm5.h: File with prototypes for Tcl_kadm5_init and
+ 	Tcl_ovsec_kadm_init.
+
+	* tcl_kadm5.c: Include tcl_kadm5.h. Declare
+	tcl_kadm5_{rename,chpass,get}_principal,
+	tcl_kadm5_chpass_principal_util, tcl_kadm5_randkey_principal,
+	tcl_kadm5_{create,delete,modify,get}_policy,
+	tcl_kadm5_free_{principal,policy}_ent, tcl_kadm5_get_privs as static.
+
+	* test.c, tcl_ovsec_kadm.c: Include tcl_kadm5.h.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* tcl_kadm5.c: Cleanup assignments in conditionals.
+
+	* test.c: Add prototype for Tcl_ovsec_kadm_init() and Tcl_kadm5_init().
+
+2001-04-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* tcl_kadm5.c, tcl_ovsec_kadm.c: Cleanup of assignments in
+	conditionals, missing prototypes, etc.
+
+2000-05-23  Tom Yu  <tlyu@mit.edu>
+
+	* tcl_kadm5.c (tcl_kadm5_chpass_principal_util): Add new argument
+	to call to chpass_principal_util().
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Thu Jul 16 10:20:20 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* tcl_kadm5.c (parse_tl_data): Change cast from char * to
+	        krb5_octet *.
+	(tcl_kadm5_free_principal_ent, tcl_kadm5_free_policy_ent): Add
+ 	        cast to value returned by Tcl_GetHashValue.
+
+	* tcl_ovsec_kadm.c (tcl_ovsec_kadm_free_principal_ent): Cast
+    	        return of Tcl_GetHashValue.
+
+Fri Feb 27 23:32:38 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the kadmin
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel kadmin configure.in
+
+Wed Feb 18 16:00:13 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Oct 22 15:40:34 1997  Ezra Peisach  <epeisach@dumpster.rose.brandeis.edu>
+
+	* test.c, tcl_ovsec_kadm.c, tcl_krb5_hash.c, tcl_kadm5.c: Include
+	 	either tcl.h or tcl/tcl.h
+
+Mon Mar 31 17:43:06 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.in: be more verbose if Tcl is unavailable
+
+Wed Feb  5 22:57:53 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Fri Dec  6 00:04:10 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* test.c: Change test looking for tcl 7.05 and greater to be tcl
+		7.04 and greater, since BSDI ships with tcl 7.04, and
+		needs this change.  [PR#282]
+
+Thu Dec  5 22:47:27 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* tcl_ovsec_kadm.c: 
+	* tcl_kadm5.c: Remove #include of <malloc.h>, which is not
+ 		guaranteed to be there.  #include of <stdlib.h> is all you
+ 		need for malloc(), per ANSI.  [PR#281]
+
+Wed Nov 13 09:55:05 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean): Remove built programs.
+
+Thu Nov  7 20:53:45 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Remove spurious WITH_CCOPTS and KRB_INCLUDE.
+
+Thu Nov  7 13:09:33 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* tcl_kadm5.c: don't assume tl_data_contents is null-terminated,
+ 	and zero allocated princ before parsing it
+	(unparse_err): add new finer-grained conf file error codes
+
+Thu Nov  7 11:36:15 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* tcl_kadm5.c (parse_keysalts, parse_tl_data): Do not free memory
+		twice. 
+
+	* Makefile.in: Use $(LD) instead of $(CC) for linking.
+
+Fri Nov  1 13:16:43 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* tcl_kadm5.c (unparse_err): update for new tl_data semantics
+ 	[krb5-admin/140]
+
+Mon Oct 21 16:31:35 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* tcl_kadm5.c: add unparse ability for V2 principal fields
+ 	[krb5-admin/20]
+
+Fri Oct 18 13:23:46 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* tcl_kadm5.c (unparse_principal_ent): don't unparse allocated
+ 	fields that were not requested in mask to get_principal
+
+Mon Oct 14 07:01:34 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: Only attempt to build programs if Tcl present.
+
+	* configure.in: Test for existance of Tcl libraries.
+
+Thu Sep 26 11:31:57 1996  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* Makefile.in: Link with -ltcl -lm. Order the Makefile so programs
+		are built.
+
+Tue Sep 24 13:29:14 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* create Makefile.in and configure.in
+
+Mon Aug 12 11:50:42 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.ov: add $(REGEXLIB)
+
+Fri Jul 12 15:04:52 1996  Marc Horowitz  <marc@mit.edu>
+
+	* tcl_ovsec_kadm.c: renamed <ovsec_admin/foo.h> to <kadm5/foo.h>
diff --git a/mechglue/src/kadmin/testing/util/Makefile.in b/mechglue/src/kadmin/testing/util/Makefile.in
new file mode 100644
index 000000000..80197388a
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/Makefile.in
@@ -0,0 +1,70 @@
+thisconfigdir=./../..
+myfulldir=kadmin/testing/util
+mydir=testing/util
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = $(TCL_INCLUDES) -I$(BUILDTOP)/lib/kdb/
+# Force Tcl headers to use stdarg.h, because krb5 does too, and if
+# Tcl uses varargs.h it'll just mess things up.
+DEFINES= -DHAS_STDARG
+KRB5_PTHREAD_LIB=$(THREAD_LINKOPTS) 
+
+PROG_LIBPATH=-L$(TOPLIBD) $(TCL_LIBPATH)
+PROG_RPATH=$(KRB5_LIBDIR)$(TCL_RPATH)
+
+SRCS	=	$(srcdir)/tcl_ovsec_kadm.c $(srcdir)/tcl_kadm5.c $(srcdir)/test.c
+OBJS	=	tcl_ovsec_kadm.o tcl_kadm5.o test.o
+
+CLNTPROG=	ovsec_kadm_clnt_tcl
+SRVPROG	=	ovsec_kadm_srv_tcl
+
+DO_ALL=@DO_ALL@
+
+all:: all-$(DO_ALL)
+
+all-::
+	@echo "+++"
+	@echo "+++ WARNING: Tcl not available.  The kadm5 tests will not be run."
+	@echo "+++"
+
+all-tcl:: $(CLNTPROG) $(SRVPROG)
+
+$(SRVPROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $(SRVPROG) $(OBJS) $(TCL_MAYBE_RPATH) \
+		$(KADMSRV_LIBS) $(KRB5_PTHREAD_LIB) $(KRB5_BASE_LIBS) $(TCL_LIBS)
+
+$(CLNTPROG): $(OBJS) $(KADMCLNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $(CLNTPROG) $(OBJS) $(TCL_MAYBE_RPATH) \
+		$(KRB5_PTHREAD_LIB) $(KADMCLNT_LIBS) $(KRB5_BASE_LIBS) $(TCL_LIBS)
+
+bsddb_dump: bsddb_dump.o
+	$(CC_LINK) -o bsddb_dump bsddb_dump.o $(KADMSRV_LIBS)
+
+clean:: 
+	$(RM) $(CLNTPROG) $(SRVPROG)
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)tcl_ovsec_kadm.$(OBJEXT): tcl_ovsec_kadm.c \
+  $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h tcl_kadm5.h \
+  $(BUILDTOP)/lib/kdb/adb_err.h
+$(OUTPRE)tcl_kadm5.$(OBJEXT): tcl_kadm5.c $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/lib/kdb/adb_err.h tcl_kadm5.h
+$(OUTPRE)test.$(OBJEXT): test.c tcl_kadm5.h
diff --git a/mechglue/src/kadmin/testing/util/bsddb_dump.c b/mechglue/src/kadmin/testing/util/bsddb_dump.c
new file mode 100644
index 000000000..ba69b8461
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/bsddb_dump.c
@@ -0,0 +1,64 @@
+/*
+ * $Id$
+ */
+
+#include <sys/file.h>
+#include <fcntl.h>
+#include <db.h>
+#include <stdio.h>
+
+main(int argc, char *argv[])
+{
+   char *file;
+   DB *db;
+   DBT dbkey, dbdata;
+   int code, i;
+
+   HASHINFO	info;
+
+   info.hash = NULL;
+   info.bsize = 256;
+   info.ffactor = 8;
+   info.nelem = 25000;
+   info.lorder = 0;
+
+   if (argc != 2) {
+      fprintf(stderr, "usage: argv[0] dbfile\n");
+      exit(2);
+   }
+	      
+   file = argv[1];
+
+   if((db = dbopen(file, O_RDWR, 0666, DB_HASH, &info)) == NULL) {
+      perror("Opening db file");
+      exit(1);
+   }
+
+   if ((code = (*db->seq)(db, &dbkey, &dbdata, R_FIRST)) == -1) { 
+      perror("starting db iteration");
+      exit(1);
+   }
+
+   while (code == 0) {
+      for (i=0; i<dbkey.size; i++)
+	 printf("%02x", (int) ((unsigned char *) dbkey.data)[i]);
+      printf("\t");
+      for (i=0; i<dbdata.size; i++)
+	 printf("%02x", (int) ((unsigned char *) dbdata.data)[i]);
+      printf("\n");
+
+      code = (*db->seq)(db, &dbkey, &dbdata, R_NEXT);
+   }
+
+   if (code == -1) {
+      perror("during db iteration");
+      exit(1);
+   }
+
+   if ((*db->close)(db) == -1) {
+      perror("closing db");
+      exit(1);
+   }
+
+   exit(0);
+}
diff --git a/mechglue/src/kadmin/testing/util/tcl_kadm5.c b/mechglue/src/kadmin/testing/util/tcl_kadm5.c
new file mode 100644
index 000000000..3907efdf0
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/tcl_kadm5.c
@@ -0,0 +1,2554 @@
+#include <stdio.h>
+#include <string.h>
+#if HAVE_TCL_H
+#include <tcl.h>
+#elif HAVE_TCL_TCL_H
+#include <tcl/tcl.h>
+#endif
+#define USE_KADM5_API_VERSION 2
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <adb_err.h>
+#include "tcl_kadm5.h"
+
+struct flagval {
+     char *name;
+     krb5_flags val;
+};
+
+/* XXX This should probably be in the hash table like server_handle */
+static krb5_context context;
+
+static struct flagval krb5_flags_array[] = {
+     {"KRB5_KDB_DISALLOW_POSTDATED", KRB5_KDB_DISALLOW_POSTDATED},
+     {"KRB5_KDB_DISALLOW_FORWARDABLE", KRB5_KDB_DISALLOW_FORWARDABLE},
+     {"KRB5_KDB_DISALLOW_TGT_BASED", KRB5_KDB_DISALLOW_TGT_BASED},
+     {"KRB5_KDB_DISALLOW_RENEWABLE", KRB5_KDB_DISALLOW_RENEWABLE},
+     {"KRB5_KDB_DISALLOW_PROXIABLE", KRB5_KDB_DISALLOW_PROXIABLE},
+     {"KRB5_KDB_DISALLOW_DUP_SKEY", KRB5_KDB_DISALLOW_DUP_SKEY},
+     {"KRB5_KDB_DISALLOW_ALL_TIX", KRB5_KDB_DISALLOW_ALL_TIX},
+     {"KRB5_KDB_REQUIRES_PRE_AUTH", KRB5_KDB_REQUIRES_PRE_AUTH},
+     {"KRB5_KDB_REQUIRES_HW_AUTH", KRB5_KDB_REQUIRES_HW_AUTH},
+     {"KRB5_KDB_REQUIRES_PWCHANGE", KRB5_KDB_REQUIRES_PWCHANGE},
+     {"KRB5_KDB_DISALLOW_SVR", KRB5_KDB_DISALLOW_SVR},
+     {"KRB5_KDB_PWCHANGE_SERVICE", KRB5_KDB_PWCHANGE_SERVICE}
+};
+
+static struct flagval aux_attributes[] = {
+     {"KADM5_POLICY",   KADM5_POLICY}
+};
+
+static struct flagval principal_mask_flags[] = {
+     {"KADM5_PRINCIPAL", KADM5_PRINCIPAL},
+     {"KADM5_PRINC_EXPIRE_TIME", KADM5_PRINC_EXPIRE_TIME},
+     {"KADM5_PW_EXPIRATION", KADM5_PW_EXPIRATION},
+     {"KADM5_LAST_PWD_CHANGE", KADM5_LAST_PWD_CHANGE},
+     {"KADM5_ATTRIBUTES", KADM5_ATTRIBUTES},
+     {"KADM5_MAX_LIFE", KADM5_MAX_LIFE},
+     {"KADM5_MOD_TIME", KADM5_MOD_TIME},
+     {"KADM5_MOD_NAME", KADM5_MOD_NAME},
+     {"KADM5_KVNO", KADM5_KVNO},
+     {"KADM5_MKVNO", KADM5_MKVNO},
+     {"KADM5_AUX_ATTRIBUTES", KADM5_AUX_ATTRIBUTES},
+     {"KADM5_POLICY", KADM5_POLICY},
+     {"KADM5_POLICY_CLR", KADM5_POLICY_CLR},
+     {"KADM5_MAX_RLIFE", KADM5_MAX_RLIFE},
+     {"KADM5_LAST_SUCCESS", KADM5_LAST_SUCCESS},
+     {"KADM5_LAST_FAILED", KADM5_LAST_FAILED},
+     {"KADM5_FAIL_AUTH_COUNT", KADM5_FAIL_AUTH_COUNT},
+     {"KADM5_KEY_DATA", KADM5_KEY_DATA},
+     {"KADM5_TL_DATA", KADM5_TL_DATA},
+     {"KADM5_PRINCIPAL_NORMAL_MASK", KADM5_PRINCIPAL_NORMAL_MASK}
+};
+
+static struct flagval policy_mask_flags[] = {
+     {"KADM5_POLICY", KADM5_POLICY},
+     {"KADM5_PW_MAX_LIFE", KADM5_PW_MAX_LIFE},
+     {"KADM5_PW_MIN_LIFE", KADM5_PW_MIN_LIFE},
+     {"KADM5_PW_MIN_LENGTH", KADM5_PW_MIN_LENGTH},
+     {"KADM5_PW_MIN_CLASSES", KADM5_PW_MIN_CLASSES},
+     {"KADM5_PW_HISTORY_NUM", KADM5_PW_HISTORY_NUM},
+     {"KADM5_REF_COUNT", KADM5_REF_COUNT}
+};
+
+static struct flagval config_mask_flags[] = {
+     {"KADM5_CONFIG_REALM", KADM5_CONFIG_REALM},
+     {"KADM5_CONFIG_DBNAME", KADM5_CONFIG_DBNAME},
+     {"KADM5_CONFIG_MKEY_NAME", KADM5_CONFIG_MKEY_NAME},
+     {"KADM5_CONFIG_MAX_LIFE", KADM5_CONFIG_MAX_LIFE},
+     {"KADM5_CONFIG_MAX_RLIFE", KADM5_CONFIG_MAX_RLIFE},
+     {"KADM5_CONFIG_EXPIRATION", KADM5_CONFIG_EXPIRATION},
+     {"KADM5_CONFIG_FLAGS", KADM5_CONFIG_FLAGS},
+     {"KADM5_CONFIG_ADMIN_KEYTAB", KADM5_CONFIG_ADMIN_KEYTAB},
+     {"KADM5_CONFIG_STASH_FILE", KADM5_CONFIG_STASH_FILE},
+     {"KADM5_CONFIG_ENCTYPE", KADM5_CONFIG_ENCTYPE},
+     {"KADM5_CONFIG_ADBNAME", KADM5_CONFIG_ADBNAME},
+     {"KADM5_CONFIG_ADB_LOCKFILE", KADM5_CONFIG_ADB_LOCKFILE},
+     {"KADM5_CONFIG_PROFILE", KADM5_CONFIG_PROFILE},
+     {"KADM5_CONFIG_ACL_FILE", KADM5_CONFIG_ACL_FILE},
+     {"KADM5_CONFIG_KADMIND_PORT", KADM5_CONFIG_KADMIND_PORT},
+     {"KADM5_CONFIG_ENCTYPES", KADM5_CONFIG_ENCTYPES},
+     {"KADM5_CONFIG_ADMIN_SERVER", KADM5_CONFIG_ADMIN_SERVER},
+     {"KADM5_CONFIG_DICT_FILE", KADM5_CONFIG_DICT_FILE},
+     {"KADM5_CONFIG_MKEY_FROM_KBD", KADM5_CONFIG_MKEY_FROM_KBD},
+};
+
+static struct flagval priv_flags[] = {
+     {"KADM5_PRIV_GET", KADM5_PRIV_GET},
+     {"KADM5_PRIV_ADD", KADM5_PRIV_ADD},
+     {"KADM5_PRIV_MODIFY", KADM5_PRIV_MODIFY},
+     {"KADM5_PRIV_DELETE", KADM5_PRIV_DELETE}
+};
+    
+
+static char *arg_error = "wrong # args";
+
+static Tcl_HashTable *struct_table = 0;
+
+static int put_server_handle(Tcl_Interp *interp, void *handle, char **name)
+{
+    int i = 1, newPtr = 0;
+    static char buf[20];
+    Tcl_HashEntry *entry;
+
+    if (! struct_table) {
+	if (! (struct_table =
+	       malloc(sizeof(*struct_table)))) {
+	    fprintf(stderr, "Out of memory!\n");
+	    exit(1); /* XXX */
+	}
+	Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+    }
+
+    do {
+	/*
+	 * Handles from ovsec_kadm_init() and kadm5_init() should not
+	 * be mixed during unit tests, but the API would happily
+	 * accept them.  Making the hash entry names different in
+	 * tcl_kadm.c and tcl_ovsec_kadm.c ensures that GET_HANDLE
+	 * will fail if presented a handle from the other API.
+	 */
+	sprintf(buf, "kadm5_handle%d", i);
+	entry = Tcl_CreateHashEntry(struct_table, buf, &newPtr);
+	i++;
+    } while (! newPtr);
+
+    Tcl_SetHashValue(entry, handle);
+
+    *name = buf;
+
+    return TCL_OK;
+}
+
+static int get_server_handle(Tcl_Interp *interp, char *name, void **handle) 
+{
+    Tcl_HashEntry *entry;
+
+    if(!strcasecmp(name, "null"))
+	*handle = 0;
+    else {
+	if (! (struct_table &&
+	       (entry = Tcl_FindHashEntry(struct_table, name)))) {
+	     if (strncmp(name, "ovsec_kadm_handle", 17) == 0)
+		  Tcl_AppendResult(interp, "ovsec_kadm handle "
+				   "specified for kadm5 api: ", name, 0);
+	     else 
+		  Tcl_AppendResult(interp, "unknown server handle ", name, 0);
+	    return TCL_ERROR;
+	}
+	*handle = (void *) Tcl_GetHashValue(entry);
+    }
+    return TCL_OK;
+}
+
+static int remove_server_handle(Tcl_Interp *interp, char *name) 
+{
+    Tcl_HashEntry *entry;
+
+    if (! (struct_table &&
+	   (entry = Tcl_FindHashEntry(struct_table, name)))) {
+	Tcl_AppendResult(interp, "unknown server handle ", name, 0);
+	return TCL_ERROR;
+    }
+
+    Tcl_SetHashValue(entry, NULL);
+    return TCL_OK;
+}
+
+#define GET_HANDLE(num_args, ignored) \
+    void *server_handle; \
+    char *whoami = argv[0]; \
+    argv++, argc--; \
+    if (argc != num_args + 1) { \
+	Tcl_AppendResult(interp, whoami, ": ", arg_error, 0); \
+	return TCL_ERROR; \
+    } \
+    { \
+	int ltcl_ret; \
+	if ((ltcl_ret = get_server_handle(interp, argv[0], &server_handle)) \
+	    != TCL_OK) { \
+	    return ltcl_ret; \
+	} \
+    } \
+    argv++, argc--;
+
+static Tcl_HashTable *create_flag_table(struct flagval *flags, int size)
+{
+     Tcl_HashTable *table;
+     Tcl_HashEntry *entry;
+     int i;
+
+     if (! (table = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_InitHashTable(table, TCL_STRING_KEYS);
+
+     for (i = 0; i < size; i++) {
+	  int newPtr;
+	       
+	  if (! (entry = Tcl_CreateHashEntry(table, flags[i].name, &newPtr))) {
+	       fprintf(stderr, "Out of memory!\n");
+	       exit(1); /* XXX */
+	  }
+
+	  Tcl_SetHashValue(entry, &flags[i].val);
+     }
+
+     return table;
+}
+
+
+static Tcl_DString *unparse_str(char *in_str)
+{
+     Tcl_DString *str;
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     if (! in_str) {
+	  Tcl_DStringAppend(str, "null", -1);
+     }
+     else {
+	  Tcl_DStringAppend(str, in_str, -1);
+     }
+
+     return str;
+}
+
+
+	  
+static int parse_str(Tcl_Interp *interp, char *in_str, char **out_str)
+{
+     if (! in_str) {
+	  *out_str = 0;
+     }
+     else if (! strcasecmp(in_str, "null")) {
+	  *out_str = 0;
+     }
+     else {
+	  *out_str = in_str;
+     }
+     return TCL_OK;
+}
+
+
+static void set_ok(Tcl_Interp *interp, char *string)
+{
+     Tcl_SetResult(interp, "OK", TCL_STATIC);
+     Tcl_AppendElement(interp, "KADM5_OK");
+     Tcl_AppendElement(interp, string);
+}
+
+
+
+static Tcl_DString *unparse_err(kadm5_ret_t code)
+{
+     char *code_string;
+     const char *error_string;
+     Tcl_DString *dstring;
+
+     switch (code) {
+     case KADM5_FAILURE: code_string = "KADM5_FAILURE"; break;
+     case KADM5_AUTH_GET: code_string = "KADM5_AUTH_GET"; break;
+     case KADM5_AUTH_ADD: code_string = "KADM5_AUTH_ADD"; break;
+     case KADM5_AUTH_MODIFY:
+	  code_string = "KADM5_AUTH_MODIFY"; break;
+     case KADM5_AUTH_DELETE:
+	  code_string = "KADM5_AUTH_DELETE"; break;
+     case KADM5_AUTH_INSUFFICIENT:
+	  code_string = "KADM5_AUTH_INSUFFICIENT"; break;
+     case KADM5_BAD_DB: code_string = "KADM5_BAD_DB"; break;
+     case KADM5_DUP: code_string = "KADM5_DUP"; break;
+     case KADM5_RPC_ERROR: code_string = "KADM5_RPC_ERROR"; break;
+     case KADM5_NO_SRV: code_string = "KADM5_NO_SRV"; break;
+     case KADM5_BAD_HIST_KEY:
+	  code_string = "KADM5_BAD_HIST_KEY"; break;
+     case KADM5_NOT_INIT: code_string = "KADM5_NOT_INIT"; break;
+     case KADM5_INIT: code_string = "KADM5_INIT"; break;
+     case KADM5_BAD_PASSWORD:
+	  code_string = "KADM5_BAD_PASSWORD"; break;
+     case KADM5_UNK_PRINC: code_string = "KADM5_UNK_PRINC"; break;
+     case KADM5_UNK_POLICY: code_string = "KADM5_UNK_POLICY"; break;
+     case KADM5_BAD_MASK: code_string = "KADM5_BAD_MASK"; break;
+     case KADM5_BAD_CLASS: code_string = "KADM5_BAD_CLASS"; break;
+     case KADM5_BAD_LENGTH: code_string = "KADM5_BAD_LENGTH"; break;
+     case KADM5_BAD_POLICY: code_string = "KADM5_BAD_POLICY"; break;
+     case KADM5_BAD_HISTORY: code_string = "KADM5_BAD_HISTORY"; break;
+     case KADM5_BAD_PRINCIPAL:
+	  code_string = "KADM5_BAD_PRINCIPAL"; break;
+     case KADM5_BAD_AUX_ATTR:
+	  code_string = "KADM5_BAD_AUX_ATTR"; break;
+     case KADM5_PASS_Q_TOOSHORT:
+	  code_string = "KADM5_PASS_Q_TOOSHORT"; break;
+     case KADM5_PASS_Q_CLASS:
+	  code_string = "KADM5_PASS_Q_CLASS"; break;
+     case KADM5_PASS_Q_DICT:
+	  code_string = "KADM5_PASS_Q_DICT"; break;
+     case KADM5_PASS_REUSE: code_string = "KADM5_PASS_REUSE"; break;
+     case KADM5_PASS_TOOSOON:
+	  code_string = "KADM5_PASS_TOOSOON"; break;
+     case KADM5_POLICY_REF:
+	  code_string = "KADM5_POLICY_REF"; break;
+     case KADM5_PROTECT_PRINCIPAL:
+	  code_string = "KADM5_PROTECT_PRINCIPAL"; break;
+     case KADM5_BAD_SERVER_HANDLE:
+	  code_string = "KADM5_BAD_SERVER_HANDLE"; break;
+     case KADM5_BAD_STRUCT_VERSION:
+     	  code_string = "KADM5_BAD_STRUCT_VERSION"; break;
+     case KADM5_OLD_STRUCT_VERSION:
+	  code_string = "KADM5_OLD_STRUCT_VERSION"; break;
+     case KADM5_NEW_STRUCT_VERSION:
+	  code_string = "KADM5_NEW_STRUCT_VERSION"; break;
+     case KADM5_BAD_API_VERSION:
+	  code_string = "KADM5_BAD_API_VERSION"; break;
+     case KADM5_OLD_LIB_API_VERSION:
+     	  code_string = "KADM5_OLD_LIB_API_VERSION"; break;
+     case KADM5_OLD_SERVER_API_VERSION:
+     	  code_string = "KADM5_OLD_SERVER_API_VERSION"; break;
+     case KADM5_NEW_LIB_API_VERSION:
+     	  code_string = "KADM5_NEW_LIB_API_VERSION"; break;
+     case KADM5_NEW_SERVER_API_VERSION:
+	  code_string = "KADM5_NEW_SERVER_API_VERSION"; break;
+     case KADM5_SECURE_PRINC_MISSING:
+	  code_string = "KADM5_SECURE_PRINC_MISSING"; break;
+     case KADM5_NO_RENAME_SALT:
+	  code_string = "KADM5_NO_RENAME_SALT"; break;
+     case KADM5_BAD_CLIENT_PARAMS:
+	  code_string = "KADM5_BAD_CLIENT_PARAMS"; break;
+     case KADM5_BAD_SERVER_PARAMS:
+	  code_string = "KADM5_BAD_SERVER_PARAMS"; break;
+     case KADM5_AUTH_LIST:
+	  code_string = "KADM5_AUTH_LIST"; break;
+     case KADM5_AUTH_CHANGEPW:
+	  code_string = "KADM5_AUTH_CHANGEPW"; break;
+     case KADM5_GSS_ERROR: code_string = "KADM5_GSS_ERROR"; break;
+     case KADM5_BAD_TL_TYPE: code_string = "KADM5_BAD_TL_TYPE"; break; 
+     case KADM5_MISSING_CONF_PARAMS:
+	  code_string = "KADM5_MISSING_CONF_PARAMS"; break;
+     case KADM5_BAD_SERVER_NAME:
+	  code_string = "KADM5_BAD_SERVER_NAME"; break;
+     case KADM5_MISSING_KRB5_CONF_PARAMS:
+	  code_string = "KADM5_MISSING_KRB5_CONF_PARAMS"; break;
+
+
+     case OSA_ADB_DUP: code_string = "OSA_ADB_DUP"; break;
+     case OSA_ADB_NOENT: code_string = "ENOENT"; break;
+     case OSA_ADB_DBINIT: code_string = "OSA_ADB_DBINIT"; break;
+     case OSA_ADB_BAD_POLICY: code_string = "Bad policy name"; break;
+     case OSA_ADB_BAD_PRINC: code_string = "Bad principal name"; break;
+     case OSA_ADB_BAD_DB: code_string = "Invalid database."; break;
+     case OSA_ADB_XDR_FAILURE: code_string = "OSA_ADB_XDR_FAILURE"; break;
+     case OSA_ADB_BADLOCKMODE: code_string = "OSA_ADB_BADLOCKMODE"; break;
+     case OSA_ADB_CANTLOCK_DB: code_string = "OSA_ADB_CANTLOCK_DB"; break;
+     case OSA_ADB_NOTLOCKED: code_string = "OSA_ADB_NOTLOCKED"; break;
+     case OSA_ADB_NOLOCKFILE: code_string = "OSA_ADB_NOLOCKFILE"; break;
+     case OSA_ADB_NOEXCL_PERM: code_string = "OSA_ADB_NOEXCL_PERM"; break;
+
+     case KRB5_KDB_INUSE: code_string = "KRB5_KDB_INUSE"; break;
+     case KRB5_KDB_UK_SERROR: code_string = "KRB5_KDB_UK_SERROR"; break;
+     case KRB5_KDB_UK_RERROR: code_string = "KRB5_KDB_UK_RERROR"; break;
+     case KRB5_KDB_UNAUTH: code_string = "KRB5_KDB_UNAUTH"; break;
+     case KRB5_KDB_NOENTRY: code_string = "KRB5_KDB_NOENTRY"; break;
+     case KRB5_KDB_ILL_WILDCARD: code_string = "KRB5_KDB_ILL_WILDCARD"; break;
+     case KRB5_KDB_DB_INUSE: code_string = "KRB5_KDB_DB_INUSE"; break;
+     case KRB5_KDB_DB_CHANGED: code_string = "KRB5_KDB_DB_CHANGED"; break;
+     case KRB5_KDB_TRUNCATED_RECORD:
+	  code_string = "KRB5_KDB_TRUNCATED_RECORD"; break;
+     case KRB5_KDB_RECURSIVELOCK:
+	  code_string = "KRB5_KDB_RECURSIVELOCK"; break;
+     case KRB5_KDB_NOTLOCKED: code_string = "KRB5_KDB_NOTLOCKED"; break;
+     case KRB5_KDB_BADLOCKMODE: code_string = "KRB5_KDB_BADLOCKMODE"; break;
+     case KRB5_KDB_DBNOTINITED: code_string = "KRB5_KDB_DBNOTINITED"; break;
+     case KRB5_KDB_DBINITED: code_string = "KRB5_KDB_DBINITED"; break;
+     case KRB5_KDB_ILLDIRECTION: code_string = "KRB5_KDB_ILLDIRECTION"; break;
+     case KRB5_KDB_NOMASTERKEY: code_string = "KRB5_KDB_NOMASTERKEY"; break;
+     case KRB5_KDB_BADMASTERKEY: code_string = "KRB5_KDB_BADMASTERKEY"; break;
+     case KRB5_KDB_INVALIDKEYSIZE:
+	  code_string = "KRB5_KDB_INVALIDKEYSIZE"; break;
+     case KRB5_KDB_CANTREAD_STORED:
+	  code_string = "KRB5_KDB_CANTREAD_STORED"; break;
+     case KRB5_KDB_BADSTORED_MKEY:
+	  code_string = "KRB5_KDB_BADSTORED_MKEY"; break;
+     case KRB5_KDB_CANTLOCK_DB: code_string = "KRB5_KDB_CANTLOCK_DB"; break;
+     case KRB5_KDB_DB_CORRUPT: code_string = "KRB5_KDB_DB_CORRUPT"; break;
+
+     case KRB5_PARSE_ILLCHAR: code_string = "KRB5_PARSE_ILLCHAR"; break;
+     case KRB5_PARSE_MALFORMED: code_string = "KRB5_PARSE_MALFORMED"; break;
+     case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN"; break;
+     case KRB5_REALM_UNKNOWN: code_string = "KRB5_REALM_UNKNOWN"; break;
+     case KRB5_KDC_UNREACH: code_string = "KRB5_KDC_UNREACH"; break;
+     case KRB5_KDCREP_MODIFIED: code_string = "KRB5_KDCREP_MODIFIED"; break;
+     case KRB5KRB_AP_ERR_BAD_INTEGRITY: code_string  = "KRB5KRB_AP_ERR_BAD_INTEGRITY"; break;
+     case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN"; break;
+     case KRB5_CONFIG_BADFORMAT: code_string = "KRB5_CONFIG_BADFORMAT"; break;
+
+     case KRB5_CC_NOTFOUND: code_string = "KRB5_CC_NOTFOUND"; break;
+     case KRB5_FCC_NOFILE: code_string = "KRB5_FCC_NOFILE"; break;
+
+     case EINVAL: code_string = "EINVAL"; break;
+     case ENOENT: code_string = "ENOENT"; break;
+
+     default:
+	 fprintf(stderr, "**** CODE %d (%s) ***\n", code,
+		 error_message (code));
+	 code_string = "UNKNOWN";
+	 break;
+     }
+
+     error_string = error_message(code);
+
+     if (! (dstring = (Tcl_DString *) malloc(sizeof(Tcl_DString)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX Do we really want to exit?  Ok if this is */
+		   /* just a test program, but what about if it gets */
+		   /* used for other things later? */
+     }
+
+     Tcl_DStringInit(dstring);
+
+     if (! (Tcl_DStringAppendElement(dstring, "ERROR") &&
+	    Tcl_DStringAppendElement(dstring, code_string) &&
+	    Tcl_DStringAppendElement(dstring, error_string))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+     
+     return dstring;
+}
+
+
+
+static void stash_error(Tcl_Interp *interp, krb5_error_code code)
+{
+     Tcl_DString *dstring = unparse_err(code);
+     Tcl_DStringResult(interp, dstring);
+     Tcl_DStringFree(dstring);
+     free(dstring);
+}
+
+static Tcl_DString *unparse_key_data(krb5_key_data *key_data, int n_key_data)
+{
+     Tcl_DString *str;
+     char buf[2048];
+     int i, j;
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+     for (i = 0; i < n_key_data; i++) {
+	  krb5_key_data *key = &key_data[i];
+
+	  Tcl_DStringStartSublist(str);
+	  sprintf(buf, "%d", key->key_data_type[0]);
+	  Tcl_DStringAppendElement(str, buf);
+	  sprintf(buf, "%d", key->key_data_ver > 1 ?
+		  key->key_data_type[1] : -1);
+	  Tcl_DStringAppendElement(str, buf);
+	  if (key->key_data_contents[0]) {
+	       sprintf(buf, "0x");
+	       for (j = 0; j < key->key_data_length[0]; j++) {
+		    sprintf(buf + 2*(j+1), "%02x",
+			    key->key_data_contents[0][j]);
+	       }
+	  } else *buf = '\0';
+	  Tcl_DStringAppendElement(str, buf);
+	  Tcl_DStringEndSublist(str);
+     }
+     
+     return str;
+}
+
+static Tcl_DString *unparse_tl_data(krb5_tl_data *tl_data, int n_tl_data)
+{
+     Tcl_DString *str;
+     char buf[2048];
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+     Tcl_DStringStartSublist(str);
+     for (; tl_data; tl_data = tl_data->tl_data_next) {
+	  Tcl_DStringStartSublist(str);
+	  sprintf(buf, "%d", tl_data->tl_data_type);
+	  Tcl_DStringAppendElement(str, buf);
+	  sprintf(buf, "%d", tl_data->tl_data_length);
+	  Tcl_DStringAppendElement(str, buf);
+	  Tcl_DStringAppend(str, " ", 1);
+	  Tcl_DStringAppend(str, tl_data->tl_data_contents,
+			    tl_data->tl_data_length);
+	  Tcl_DStringEndSublist(str);
+     }
+     Tcl_DStringEndSublist(str);
+     
+     return str;
+}
+
+static Tcl_DString *unparse_flags(struct flagval *array, int size,
+				  krb5_int32 flags)
+{
+     int i;
+     Tcl_DString *str;
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     for (i = 0; i < size; i++) {
+	  if (flags & array[i].val) {
+	       Tcl_DStringAppendElement(str, array[i].name);
+	  }
+     }
+
+     return str;
+}
+
+
+static int parse_flags(Tcl_Interp *interp, Tcl_HashTable *table,
+		       struct flagval *array, int size, char *str,
+		       krb5_flags *flags)
+{
+     int tmp, argc, i, retcode = TCL_OK;
+     char **argv;
+     Tcl_HashEntry *entry;
+
+     if (Tcl_GetInt(interp, str, &tmp) == TCL_OK) {
+	  *flags = tmp;
+	  return TCL_OK;
+     }
+     Tcl_ResetResult(interp);
+
+     if (Tcl_SplitList(interp, str, &argc, &argv) != TCL_OK) {
+	  return TCL_ERROR;
+     }
+
+     if (! table) {
+	  table = create_flag_table(array, size);
+     }
+
+     *flags = 0;
+
+     for (i = 0; i < argc; i++) {
+	  if (! (entry = Tcl_FindHashEntry(table, argv[i]))) {
+	       Tcl_AppendResult(interp, "unknown krb5 flag ", argv[i], 0);
+	       retcode = TCL_ERROR;
+	       break;
+	  }
+	  *flags |= *(krb5_flags *) Tcl_GetHashValue(entry);
+     }
+  
+     Tcl_Free(argv);
+     return(retcode);
+}
+
+static Tcl_DString *unparse_privs(krb5_flags flags)
+{
+     return unparse_flags(priv_flags, sizeof(priv_flags) /
+			  sizeof(struct flagval), flags);
+}
+
+
+static Tcl_DString *unparse_krb5_flags(krb5_flags flags)
+{
+     return unparse_flags(krb5_flags_array, sizeof(krb5_flags_array) /
+			  sizeof(struct flagval), flags);
+}
+
+static int parse_krb5_flags(Tcl_Interp *interp, char *str, krb5_flags *flags)
+{
+     krb5_flags tmp;
+     static Tcl_HashTable *table = 0;
+     int tcl_ret;
+     
+     if ((tcl_ret = parse_flags(interp, table, krb5_flags_array,
+				sizeof(krb5_flags_array) /
+				sizeof(struct flagval),
+				str, &tmp)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     *flags = tmp;
+     return TCL_OK;
+}
+
+static Tcl_DString *unparse_aux_attributes(krb5_int32 flags)
+{
+     return unparse_flags(aux_attributes, sizeof(aux_attributes) /
+			  sizeof(struct flagval), flags);
+}
+
+
+static int parse_aux_attributes(Tcl_Interp *interp, char *str, long *flags)
+{
+     krb5_flags tmp;
+     static Tcl_HashTable *table = 0;
+     int tcl_ret;
+     
+     if ((tcl_ret = parse_flags(interp, table, aux_attributes,
+				sizeof(aux_attributes) /
+				sizeof(struct flagval),
+				str, &tmp)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     *flags = tmp;
+     return TCL_OK;
+}
+
+static int parse_principal_mask(Tcl_Interp *interp, char *str, krb5_int32 *flags)
+{
+     krb5_flags tmp;
+     static Tcl_HashTable *table = 0;
+     int tcl_ret;
+     
+     if ((tcl_ret = parse_flags(interp, table, principal_mask_flags,
+				sizeof(principal_mask_flags) /
+				sizeof(struct flagval),
+				str, &tmp)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     *flags = tmp;
+     return TCL_OK;
+}
+
+static int parse_policy_mask(Tcl_Interp *interp, char *str, krb5_int32 *flags)
+{
+     krb5_flags tmp;
+     static Tcl_HashTable *table = 0;
+     int tcl_ret;
+     
+     if ((tcl_ret = parse_flags(interp, table, policy_mask_flags,
+				sizeof(policy_mask_flags) /
+				sizeof(struct flagval),
+				str, &tmp)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     *flags = tmp;
+     return TCL_OK;
+}
+
+
+static Tcl_DString *unparse_principal_ent(kadm5_principal_ent_t princ,
+					  krb5_int32 mask)
+{
+     Tcl_DString *str, *tmp_dstring;
+     char *tmp;
+     char buf[20];
+     krb5_error_code krb5_ret;
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     tmp = 0; /* It looks to me from looking at the library source */
+	      /* code for krb5_parse_name that the pointer passed into */
+	      /* it should be initialized to 0 if I want it do be */
+	      /* allocated automatically. */
+     if (mask & KADM5_PRINCIPAL) {
+          krb5_ret = krb5_unparse_name(context, princ->principal, &tmp);
+	  if (krb5_ret) {
+	       /* XXX Do we want to return an error?  Not sure. */
+	       Tcl_DStringAppendElement(str, "[unparseable principal]");
+	  }
+	  else {
+	       Tcl_DStringAppendElement(str, tmp);
+	       free(tmp);
+	  }
+     } else
+	  Tcl_DStringAppendElement(str, "null");
+
+     sprintf(buf, "%d", princ->princ_expire_time);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->last_pwd_change);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->pw_expiration);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->max_life);
+     Tcl_DStringAppendElement(str, buf);
+
+     tmp = 0;
+     if (mask & KADM5_MOD_NAME) {
+	  if ((krb5_ret = krb5_unparse_name(context, princ->mod_name, &tmp))) {
+	       /* XXX */
+	       Tcl_DStringAppendElement(str, "[unparseable principal]");
+	  }
+	  else {
+	       Tcl_DStringAppendElement(str, tmp);
+	       free(tmp);
+	  }
+     } else
+	  Tcl_DStringAppendElement(str, "null");
+
+     sprintf(buf, "%d", princ->mod_date);
+     Tcl_DStringAppendElement(str, buf);
+
+     if (mask & KADM5_ATTRIBUTES) {
+	  tmp_dstring = unparse_krb5_flags(princ->attributes);
+	  Tcl_DStringAppendElement(str, tmp_dstring->string);
+	  Tcl_DStringFree(tmp_dstring);
+	  free(tmp_dstring);
+     } else
+	  Tcl_DStringAppendElement(str, "null");
+
+     sprintf(buf, "%d", princ->kvno);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->mkvno);
+     Tcl_DStringAppendElement(str, buf);
+
+     /* XXX This may be dangerous, because the contents of the policy */
+     /* field are undefined if the POLICY bit isn't set.  However, I */
+     /* think it's a bug for the field not to be null in that case */
+     /* anyway, so we should assume that it will be null so that we'll */
+     /* catch it if it isn't. */
+     
+     tmp_dstring = unparse_str(princ->policy);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+
+     tmp_dstring = unparse_aux_attributes(princ->aux_attributes);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+
+     sprintf(buf, "%d", princ->max_renewable_life);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->last_success);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->last_failed);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->fail_auth_count);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->n_key_data);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->n_tl_data);
+     Tcl_DStringAppendElement(str, buf);
+
+     tmp_dstring = unparse_key_data(princ->key_data, princ->n_key_data);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+
+     tmp_dstring = unparse_tl_data(princ->tl_data, princ->n_tl_data);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+     
+     return str;
+}
+
+static int parse_keysalts(Tcl_Interp *interp, char *list,
+			  krb5_key_salt_tuple **keysalts,
+			  int num_keysalts)
+{
+     char **argv, **argv1 = NULL;
+     int i, tmp, argc, argc1, retcode;
+
+     *keysalts = NULL;
+     if (list == NULL)
+	  return TCL_OK;
+     
+     if ((retcode = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+	  return retcode;
+     }
+     if (argc != num_keysalts) {
+	  sprintf(interp->result, "%d keysalts specified, "
+		  "but num_keysalts is %d", argc, num_keysalts);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     *keysalts = (krb5_key_salt_tuple *)
+	  malloc(sizeof(krb5_key_salt_tuple)*num_keysalts);
+     for (i = 0; i < num_keysalts; i++) {
+	  if ((retcode = Tcl_SplitList(interp, argv[i], &argc1, &argv1)) !=
+	      TCL_OK) { 
+	       goto finished;
+	  }
+	  if (argc1 != 2) {
+	       sprintf(interp->result, "wrong # fields in keysalt "
+		       "(%d should be 2)", argc1);
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  /* XXX this used to be argv1[1] too! */
+	  if ((retcode = Tcl_GetInt(interp, argv1[0], &tmp))
+	      != TCL_OK) {
+	       Tcl_AppendElement(interp, "while parsing ks_enctype");
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  (*keysalts)[i].ks_enctype = tmp;
+	  if ((retcode = Tcl_GetInt(interp, argv1[1], &tmp))
+	      != TCL_OK) {
+	       Tcl_AppendElement(interp, "while parsing ks_salttype");
+	       goto finished;
+	  }
+	  (*keysalts)[i].ks_salttype = tmp;
+
+	  Tcl_Free(argv1);
+	  argv1 = NULL;
+     }
+
+finished:
+     if (argv1) {
+	  Tcl_Free(argv1);
+     }
+     Tcl_Free(argv);
+     return retcode;
+}
+
+static int parse_key_data(Tcl_Interp *interp, char *list,
+			  krb5_key_data **key_data,
+			  int n_key_data)
+{
+     char **argv;
+     int argc, retcode;
+
+     *key_data = NULL;
+     if (list == NULL) {
+	  if (n_key_data != 0) {
+	       sprintf(interp->result, "0 key_datas specified, "
+		       "but n_key_data is %d", n_key_data);
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  } else
+	       return TCL_OK;
+     }
+     
+     if ((retcode = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+	  return retcode;
+     }
+     if (argc != n_key_data) {
+	  sprintf(interp->result, "%d key_datas specified, "
+		  "but n_key_data is %d", argc, n_key_data);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if (argc != 0) {
+	  sprintf(interp->result, "cannot parse key_data yet");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+finished:
+     Tcl_Free(argv);
+     return retcode;
+}
+
+static int parse_tl_data(Tcl_Interp *interp, char *list,
+			 krb5_tl_data **tlp,
+			 int n_tl_data)
+{
+     krb5_tl_data *tl, *tl2;
+     char **argv, **argv1 = NULL;
+     int i, tmp, argc, argc1, retcode;
+
+     *tlp = NULL;
+     if (list == NULL) {
+	  if (n_tl_data != 0) {
+	       sprintf(interp->result, "0 tl_datas specified, "
+		       "but n_tl_data is %d", n_tl_data);
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  } else
+	       return TCL_OK;
+     }
+     
+     if ((retcode = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+	  return retcode;
+     }
+     if (argc != n_tl_data) {
+	  sprintf(interp->result, "%d tl_datas specified, "
+		  "but n_tl_data is %d", argc, n_tl_data);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     tl = tl2 = NULL;
+     for (i = 0; i < n_tl_data; i++) {
+	  tl2 = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
+	  memset(tl2, 0, sizeof(krb5_tl_data));
+	  tl2->tl_data_next = tl;
+	  tl = tl2;
+     }
+     tl2 = tl;
+	  
+     for (i = 0; i < n_tl_data; i++) {
+	  if ((retcode = Tcl_SplitList(interp, argv[i], &argc1, &argv1)) !=
+	      TCL_OK) { 
+	       goto finished;
+	  }
+	  if (argc1 != 3) {
+	       sprintf(interp->result, "wrong # fields in tl_data "
+		       "(%d should be 3)", argc1);
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  if ((retcode = Tcl_GetInt(interp, argv1[0], &tmp))
+	      != TCL_OK) {
+	       Tcl_AppendElement(interp, "while parsing tl_data_type");
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  tl->tl_data_type = tmp;
+	  if ((retcode = Tcl_GetInt(interp, argv1[1], &tmp))
+	      != TCL_OK) {
+	       Tcl_AppendElement(interp, "while parsing tl_data_length");
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  tl->tl_data_length = tmp;
+	  if (tl->tl_data_length != strlen(argv1[2])) {
+	       sprintf(interp->result, "specified length %d does not "
+		       "match length %d of string \"%s\"", tmp,
+		       strlen(argv1[2]), argv1[2]);
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  tl->tl_data_contents = (krb5_octet *) malloc(tmp+1);
+	  strcpy((char *) tl->tl_data_contents, argv1[2]);
+
+	  Tcl_Free(argv1);
+	  argv1 = NULL;
+	  tl = tl->tl_data_next;
+     }
+     if (tl != NULL) {
+	  sprintf(interp->result, "tl is not NULL!");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     *tlp = tl2;
+
+finished:
+     if (argv1) {
+	  Tcl_Free(argv1);
+     }
+     Tcl_Free(argv);
+     return retcode;
+}
+
+static int parse_config_params(Tcl_Interp *interp, char *list,
+			       kadm5_config_params *params)
+{
+     static Tcl_HashTable *table = 0;
+     char **argv = NULL;
+     int tmp, argc, retcode;
+
+     memset(params, 0, sizeof(kadm5_config_params));
+     if (list == NULL)
+	  return TCL_OK;
+     
+     if ((retcode = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+	  return retcode;
+     }
+
+     if (argc != 21) {
+	  sprintf(interp->result,
+		  "wrong # args in config params structure (%d should be 21)", 
+		  argc);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if ((retcode = parse_flags(interp, table, config_mask_flags,
+				sizeof(config_mask_flags) /
+				sizeof(struct flagval),
+				argv[0], &tmp)) != TCL_OK) {
+	  goto finished;
+     }
+     params->mask = tmp;
+
+     if ((retcode = parse_str(interp, argv[1], ¶ms->realm)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing realm name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = parse_str(interp, argv[2], ¶ms->profile)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing profile name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = Tcl_GetInt(interp, argv[3], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing kadmind_port");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     params->kadmind_port = tmp;
+     if ((retcode = parse_str(interp, argv[4], ¶ms->admin_server))
+	 != TCL_OK) { 
+	  Tcl_AppendElement(interp, "while parsing profile name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = parse_str(interp, argv[5], ¶ms->dbname)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing profile name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = parse_str(interp, argv[6], ¶ms->admin_dbname)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing admin_dbname name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = parse_str(interp, argv[7], ¶ms->admin_lockfile)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing admin_lockfile name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = parse_str(interp, argv[8], ¶ms->admin_keytab)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing admin_keytab name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = parse_str(interp, argv[9], ¶ms->acl_file)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing acl_file name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = parse_str(interp, argv[10], ¶ms->dict_file)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing dict_file name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = Tcl_GetInt(interp, argv[11], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing mkey_from_kbd");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     params->mkey_from_kbd = tmp;
+     if ((retcode = parse_str(interp, argv[12], ¶ms->stash_file)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing stash_file name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = parse_str(interp, argv[13], ¶ms->mkey_name)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing mkey_name name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((retcode = Tcl_GetInt(interp, argv[14], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing enctype");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     params->enctype = tmp;
+     if ((retcode = Tcl_GetInt(interp, argv[15], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing max_life");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     params->max_life = tmp;
+     if ((retcode = Tcl_GetInt(interp, argv[16], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing max_rlife");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     params->max_rlife = tmp;
+     if ((retcode = Tcl_GetInt(interp, argv[17], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing expiration");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     params->expiration = tmp;
+     if ((retcode = parse_krb5_flags(interp, argv[18], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing flags");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     params->flags = tmp;
+     if ((retcode = Tcl_GetInt(interp, argv[19], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing num_keysalts");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     params->num_keysalts = tmp;
+     if ((retcode = parse_keysalts(interp, argv[20], ¶ms->keysalts,
+				   params->num_keysalts)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing keysalts");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+finished:
+     return retcode;
+}
+     
+static int parse_principal_ent(Tcl_Interp *interp, char *list,
+			       kadm5_principal_ent_t *out_princ)
+{
+     kadm5_principal_ent_t princ;
+     krb5_error_code krb5_ret;
+     int tcl_ret;
+     int argc;
+     char **argv;
+     int tmp;
+     int retcode = TCL_OK;
+
+     if ((tcl_ret = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     if (argc != 12 && argc != 20) {
+	  sprintf(interp->result,
+             "wrong # args in principal structure (%d should be 12 or 20)",
+		  argc);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if (! (princ = malloc(sizeof *princ))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+     memset(princ, 0, sizeof(*princ));
+     
+     if ((krb5_ret = krb5_parse_name(context, argv[0], &princ->principal)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing principal");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     /*
+      * All of the numerical values parsed here are parsed into an
+      * "int" and then assigned into the structure in case the actual
+      * width of the field in the Kerberos structure is different from
+      * the width of an integer.
+      */
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[1], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing princ_expire_time");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->princ_expire_time = tmp;
+     
+     if ((tcl_ret = Tcl_GetInt(interp, argv[2], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing last_pwd_change");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->last_pwd_change = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[3], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_expiration");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->pw_expiration = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[4], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing max_life");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->max_life = tmp;
+
+     if ((krb5_ret = krb5_parse_name(context, argv[5], &princ->mod_name)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing mod_name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+	  
+     if ((tcl_ret = Tcl_GetInt(interp, argv[6], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing mod_date");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->mod_date = tmp;
+
+     if ((tcl_ret = parse_krb5_flags(interp, argv[7], &princ->attributes))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing attributes");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[8], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing kvno");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->kvno = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[9], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing mkvno");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->mkvno = tmp;
+
+     if ((tcl_ret = parse_str(interp, argv[10], &princ->policy)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if(princ->policy != NULL) {
+	if(!(princ->policy = strdup(princ->policy))) {
+	    fprintf(stderr, "Out of memory!\n");
+	    exit(1);
+	}
+     }
+
+     if ((tcl_ret = parse_aux_attributes(interp, argv[11],
+					 &princ->aux_attributes)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing aux_attributes");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if (argc == 12) goto finished;
+     
+     if ((tcl_ret = Tcl_GetInt(interp, argv[12], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing max_renewable_life");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->max_renewable_life = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[13], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing last_success");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->last_success = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[14], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing last_failed");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->last_failed = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[15], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing fail_auth_count");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->fail_auth_count = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[16], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing n_key_data");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->n_key_data = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[17], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing n_tl_data");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->n_tl_data = tmp;
+
+     if ((tcl_ret = parse_key_data(interp, argv[18],
+				   &princ->key_data,
+				   princ->n_key_data)) != TCL_OK) { 
+	  Tcl_AppendElement(interp, "while parsing key_data");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if ((tcl_ret = parse_tl_data(interp, argv[19],
+				  &princ->tl_data,
+				  princ->n_tl_data)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing tl_data");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+finished:
+     Tcl_Free(argv);
+     *out_princ = princ;
+     return retcode;
+}
+
+
+static void free_principal_ent(kadm5_principal_ent_t *princ)
+{
+     krb5_free_principal(context, (*princ)->principal);
+     krb5_free_principal(context, (*princ)->mod_name);
+     free(*princ);
+     *princ = 0;
+}
+
+static Tcl_DString *unparse_policy_ent(kadm5_policy_ent_t policy)
+{
+     Tcl_DString *str, *tmp_dstring;
+     char buf[20];
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     tmp_dstring = unparse_str(policy->policy);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+     
+     sprintf(buf, "%ld", policy->pw_min_life);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->pw_max_life);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->pw_min_length);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->pw_min_classes);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->pw_history_num);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->policy_refcnt);
+     Tcl_DStringAppendElement(str, buf);
+
+     return str;
+}
+
+     
+     
+static int parse_policy_ent(Tcl_Interp *interp, char *list,
+			    kadm5_policy_ent_t *out_policy)
+{
+     kadm5_policy_ent_t policy;
+     int tcl_ret;
+     int argc;
+     char **argv;
+     int tmp;
+     int retcode = TCL_OK;
+
+     if ((tcl_ret = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     if (argc != 7) {
+	  sprintf(interp->result, "wrong # args in policy structure (%d should be 7)",
+		  argc);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if (! (policy = malloc(sizeof *policy))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+  
+     if ((tcl_ret = parse_str(interp, argv[0], &policy->policy)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if(policy->policy != NULL) {
+	if (! (policy->policy = strdup(policy->policy))) {
+	    fprintf(stderr, "Out of memory!\n");
+	    exit(1); /* XXX */
+	}
+     }
+     
+     /*
+      * All of the numerical values parsed here are parsed into an
+      * "int" and then assigned into the structure in case the actual
+      * width of the field in the Kerberos structure is different from
+      * the width of an integer.
+      */
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[1], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_min_life");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_min_life = tmp;
+     
+     if ((tcl_ret = Tcl_GetInt(interp, argv[2], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_max_life");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_max_life = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[3], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_min_length");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_min_length = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[4], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_min_classes");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_min_classes = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[5], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_history_num");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_history_num = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[6], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy_refcnt");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->policy_refcnt = tmp;
+
+finished:
+     Tcl_Free(argv);
+     *out_policy = policy;
+     return retcode;
+}
+
+
+static void free_policy_ent(kadm5_policy_ent_t *policy)
+{
+     free(*policy);
+     *policy = 0;
+}
+
+static Tcl_DString *unparse_keytype(krb5_enctype enctype)
+{
+     Tcl_DString *str;
+     char buf[50];
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     switch (enctype) {
+	  /* XXX is this right? */
+     case ENCTYPE_NULL: Tcl_DStringAppend(str, "ENCTYPE_NULL", -1); break;
+     case ENCTYPE_DES_CBC_CRC:
+	  Tcl_DStringAppend(str, "ENCTYPE_DES_CBC_CRC", -1); break;
+     default:
+	  sprintf(buf, "UNKNOWN KEYTYPE (0x%x)", enctype);
+	  Tcl_DStringAppend(str, buf, -1);
+	  break;
+     }
+
+     return str;
+}
+	  
+	  
+static Tcl_DString *unparse_keyblocks(krb5_keyblock *keyblocks, int num_keys)
+{
+     Tcl_DString *str;
+     Tcl_DString *keytype;
+     int i, j;
+     
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     for (j = 0; j < num_keys; j++) {
+	  krb5_keyblock *keyblock = &keyblocks[j];
+	  
+	  Tcl_DStringStartSublist(str);
+
+	  keytype = unparse_keytype(keyblock->enctype);
+	  Tcl_DStringAppendElement(str, keytype->string);
+	  Tcl_DStringFree(keytype);
+	  free(keytype);
+	  if (keyblock->length == 0) {
+	       Tcl_DStringAppendElement(str, "0x00");
+	  }
+	  else {
+	       Tcl_DStringAppendElement(str, "0x");
+	       for (i = 0; i < keyblock->length; i++) {
+		    char buf[3];
+		    sprintf(buf, "%02x", (int) keyblock->contents[i]);
+		    Tcl_DStringAppend(str, buf, -1);
+	       }
+	  }
+
+	  Tcl_DStringEndSublist(str);
+     }
+     
+
+     return str;
+}
+
+enum init_type { INIT_NONE, INIT_PASS, INIT_CREDS };
+     
+static int _tcl_kadm5_init_any(enum init_type init_type, ClientData clientData,
+			Tcl_Interp *interp, int argc, char *argv[])
+{
+     kadm5_ret_t ret;
+     char *client_name, *pass, *service_name;
+     int tcl_ret;
+     krb5_ui_4 struct_version, api_version;
+     char *handle_var;
+     void *server_handle;
+     char *handle_name, *params_str;
+     char *whoami = argv[0];
+     kadm5_config_params params;
+
+     argv++, argc--;
+
+     krb5_init_context(&context);
+
+     if (argc != 7) {
+	  Tcl_AppendResult(interp, whoami, ": ", arg_error, 0);
+	  return TCL_ERROR;
+     }
+
+     if (((tcl_ret = parse_str(interp, argv[0], &client_name)) != TCL_OK) ||
+	 ((tcl_ret = parse_str(interp, argv[1], &pass)) != TCL_OK) ||
+	 ((tcl_ret = parse_str(interp, argv[2], &service_name)) != TCL_OK) ||
+	 ((tcl_ret = parse_str(interp, argv[3], ¶ms_str)) != TCL_OK) ||
+	 ((tcl_ret = parse_config_params(interp, params_str, ¶ms))
+	  != TCL_OK) ||
+	 ((tcl_ret = Tcl_GetInt(interp, argv[4], (int *) &struct_version)) !=
+	  TCL_OK) ||
+	 ((tcl_ret = Tcl_GetInt(interp, argv[5], (int *) &api_version)) !=
+	  TCL_OK)) {
+	  return tcl_ret;
+     }
+
+     handle_var = argv[6];
+
+     if (! (handle_var && *handle_var)) {
+	 Tcl_SetResult(interp, "must specify server handle variable name",
+		       TCL_STATIC);
+	 return TCL_ERROR;
+     }
+
+     if (init_type == INIT_CREDS) {
+	  krb5_ccache cc;
+	  
+	  if (pass == NULL) {
+	       if ((ret = krb5_cc_default(context, &cc))) {
+		    stash_error(interp, ret);
+		    return TCL_ERROR;
+	       }
+	  } else {
+	       if ((ret = krb5_cc_resolve(context, pass, &cc))) {
+		    stash_error(interp, ret);
+		    return TCL_ERROR;
+	       }
+	  }
+
+	  ret = kadm5_init_with_creds(client_name, cc, service_name,
+				      ¶ms, struct_version,
+				      api_version, NULL, &server_handle); 
+	  
+	  (void) krb5_cc_close(context, cc);
+     } else
+	  ret = kadm5_init(client_name, pass, service_name, ¶ms,
+			   struct_version, api_version, NULL, &server_handle);
+
+     if (ret != KADM5_OK) {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+
+     if ((tcl_ret = put_server_handle(interp, server_handle, &handle_name))
+	 != TCL_OK) {
+	 return tcl_ret;
+     }
+     
+     if (! Tcl_SetVar(interp, handle_var, handle_name, TCL_LEAVE_ERR_MSG)) {
+	 return TCL_ERROR;
+     }
+     
+     set_ok(interp, "KADM5 API initialized.");
+     return TCL_OK;
+}
+
+static int tcl_kadm5_init(ClientData clientData, Tcl_Interp *interp,
+			  int argc, char *argv[])
+{
+     return _tcl_kadm5_init_any(INIT_PASS, clientData, interp, argc, argv);
+}
+
+static int tcl_kadm5_init_with_creds(ClientData clientData, Tcl_Interp *interp,
+				     int argc, char *argv[])
+{
+     return _tcl_kadm5_init_any(INIT_CREDS, clientData, interp, argc, argv);
+}
+
+static int tcl_kadm5_destroy(ClientData clientData, Tcl_Interp *interp,
+			     int argc, char *argv[])
+{
+     kadm5_ret_t ret;
+     int tcl_ret;
+
+     GET_HANDLE(0, 0);
+
+     ret = kadm5_destroy(server_handle);
+
+     if (ret != KADM5_OK) {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+
+     if ((tcl_ret = remove_server_handle(interp, argv[-1])) != TCL_OK) {
+	 return tcl_ret;
+     }
+     
+     set_ok(interp, "KADM5 API deinitialized.");
+     return TCL_OK;
+}	  
+
+static int tcl_kadm5_create_principal(ClientData clientData, 
+				      Tcl_Interp *interp,
+				      int argc, char *argv[])
+{
+     int tcl_ret;
+     kadm5_ret_t ret;
+     int retcode = TCL_OK;
+     char *princ_string;
+     kadm5_principal_ent_t princ = 0;
+     krb5_int32 mask;
+     char *pw;
+#ifdef OVERRIDE     
+     int override_qual;
+#endif     
+
+     GET_HANDLE(3, 0);
+
+     if ((tcl_ret = parse_str(interp, argv[0], &princ_string)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing principal");
+	  return tcl_ret;
+     }
+
+     if (princ_string &&
+	 ((tcl_ret = parse_principal_ent(interp, princ_string, &princ))
+	  != TCL_OK)) {
+	  return tcl_ret;
+     }
+
+     if ((tcl_ret = parse_principal_mask(interp, argv[1], &mask)) != TCL_OK) {
+	  retcode = tcl_ret;
+	  goto finished;
+     }
+
+     if ((tcl_ret = parse_str(interp, argv[2], &pw)) != TCL_OK) {
+	  retcode = tcl_ret;
+	  goto finished;
+     }
+#ifdef OVERRIDE
+     if ((tcl_ret = Tcl_GetBoolean(interp, argv[3], &override_qual)) !=
+	 TCL_OK) {
+	  retcode = tcl_ret;
+	  goto finished;
+     }
+#endif     
+
+#ifdef OVERRIDE
+     ret = kadm5_create_principal(server_handle, princ, mask, pw,
+				       override_qual);
+#else
+     ret = kadm5_create_principal(server_handle, princ, mask, pw);
+#endif     
+
+     if (ret != KADM5_OK) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     else {
+	  set_ok(interp, "Principal created.");
+     }
+
+finished:
+     if (princ) {
+	  free_principal_ent(&princ);
+     }
+     return retcode;
+}
+
+
+
+static int tcl_kadm5_delete_principal(ClientData clientData, 
+				      Tcl_Interp *interp,
+				      int argc, char *argv[])
+{
+     krb5_principal princ;
+     krb5_error_code krb5_ret;
+     kadm5_ret_t ret;
+     int tcl_ret;
+     char *name;
+     
+     GET_HANDLE(1, 0);
+
+     if((tcl_ret = parse_str(interp, argv[0], &name)) != TCL_OK)
+	return tcl_ret;
+     if(name != NULL) {
+	if ((krb5_ret = krb5_parse_name(context, name, &princ))) {
+	    stash_error(interp, krb5_ret);
+	    Tcl_AppendElement(interp, "while parsing principal");
+	    return TCL_ERROR;
+	}
+     } else princ = NULL;
+     ret = kadm5_delete_principal(server_handle, princ);
+
+     if(princ != NULL) 
+	krb5_free_principal(context, princ);
+
+     if (ret != KADM5_OK) {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+     else {
+	  set_ok(interp, "Principal deleted.");
+	  return TCL_OK;
+     }
+}
+
+
+
+static int tcl_kadm5_modify_principal(ClientData clientData, 
+				      Tcl_Interp *interp,
+				      int argc, char *argv[])
+{
+     char *princ_string;
+     kadm5_principal_ent_t princ = 0;
+     int tcl_ret;
+     krb5_int32 mask;
+     int retcode = TCL_OK;
+     kadm5_ret_t ret;
+
+     GET_HANDLE(2, 0);
+
+     if ((tcl_ret = parse_str(interp, argv[0], &princ_string)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing principal");
+	  return tcl_ret;
+     }
+
+     if (princ_string &&
+	 ((tcl_ret = parse_principal_ent(interp, princ_string, &princ))
+	  != TCL_OK)) {
+	  return tcl_ret;
+     }
+     
+     if ((tcl_ret = parse_principal_mask(interp, argv[1], &mask)) != TCL_OK) {
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     ret = kadm5_modify_principal(server_handle, princ, mask);
+
+     if (ret != KADM5_OK) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+     else {
+	  set_ok(interp, "Principal modified.");
+     }
+
+finished:
+     if (princ) {
+	  free_principal_ent(&princ);
+     }
+     return retcode;
+}
+
+
+static int tcl_kadm5_rename_principal(ClientData clientData, 
+				      Tcl_Interp *interp,
+				      int argc, char *argv[])
+{
+     krb5_principal source, target;
+     krb5_error_code krb5_ret;
+     kadm5_ret_t ret;
+     int retcode = TCL_OK;
+
+     GET_HANDLE(2, 0);
+
+     if ((krb5_ret = krb5_parse_name(context, argv[0], &source)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing source");
+	  return TCL_ERROR;
+     }
+
+     if ((krb5_ret = krb5_parse_name(context, argv[1], &target)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing target");
+	  krb5_free_principal(context, source);
+	  return TCL_ERROR;
+     }
+
+     ret = kadm5_rename_principal(server_handle, source, target);
+
+     if (ret == KADM5_OK) {
+	  set_ok(interp, "Principal renamed.");
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+     krb5_free_principal(context, source);
+     krb5_free_principal(context, target);
+     return retcode;
+}
+
+
+	  
+static int tcl_kadm5_chpass_principal(ClientData clientData, 
+				      Tcl_Interp *interp,
+				      int argc, char *argv[])
+{
+     krb5_principal princ;
+     char *pw;
+#ifdef OVERRIDE     
+     int override_qual;
+#endif     
+     krb5_error_code krb5_ret;
+     int retcode = TCL_OK;
+     kadm5_ret_t ret;
+
+     GET_HANDLE(2, 0);
+
+     if ((krb5_ret = krb5_parse_name(context, argv[0], &princ)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing principal name");
+	  return TCL_ERROR;
+     }
+
+     if (parse_str(interp, argv[1], &pw) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing password");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+#ifdef OVERRIDE
+     if (Tcl_GetBoolean(interp, argv[2], &override_qual) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing override_qual");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     
+     ret = kadm5_chpass_principal(server_handle,
+				       princ, pw, override_qual);
+#else
+     ret = kadm5_chpass_principal(server_handle, princ, pw);
+#endif     
+
+     if (ret == KADM5_OK) {
+	  set_ok(interp, "Password changed.");
+	  goto finished;
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     krb5_free_principal(context, princ);
+     return retcode;
+}
+
+
+
+static int tcl_kadm5_chpass_principal_util(ClientData clientData,
+					   Tcl_Interp *interp,
+					   int argc, char *argv[])
+{
+     krb5_principal princ;
+     char *new_pw;
+#ifdef OVERRIDE     
+     int override_qual;
+#endif     
+     char *pw_ret, *pw_ret_var;
+     char msg_ret[1024], *msg_ret_var;
+     krb5_error_code krb5_ret;
+     kadm5_ret_t ret;
+     int retcode = TCL_OK;
+
+     GET_HANDLE(4, 0);
+
+     if ((krb5_ret = krb5_parse_name(context, argv[0], &princ)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing principal name");
+	  return TCL_ERROR;
+     }
+
+     if (parse_str(interp, argv[1], &new_pw) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing new password");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+#ifdef OVERRIDE
+     if (Tcl_GetBoolean(interp, argv[2], &override_qual) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing override_qual");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+#endif
+     if (parse_str(interp, argv[3], &pw_ret_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_ret variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if (parse_str(interp, argv[4], &msg_ret_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing msg_ret variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     ret = kadm5_chpass_principal_util(server_handle, princ, new_pw,
+#ifdef OVERRIDE     
+					    override_qual,
+#endif					    
+					    pw_ret_var ? &pw_ret : 0,
+					    msg_ret_var ? msg_ret : 0,
+				            msg_ret_var ? sizeof(msg_ret) : 0);
+
+     if (ret == KADM5_OK) {
+	  if (pw_ret_var &&
+	      (! Tcl_SetVar(interp, pw_ret_var, pw_ret,
+			    TCL_LEAVE_ERR_MSG))) {
+	       Tcl_AppendElement(interp, "while setting pw_ret variable");
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  if (msg_ret_var &&
+	      (! Tcl_SetVar(interp, msg_ret_var, msg_ret,
+			    TCL_LEAVE_ERR_MSG))) {
+	       Tcl_AppendElement(interp,
+				 "while setting msg_ret variable");
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  set_ok(interp, "Password changed.");
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     krb5_free_principal(context, princ);
+     return retcode;
+}
+
+
+
+static int tcl_kadm5_randkey_principal(ClientData clientData, 
+				       Tcl_Interp *interp,
+				       int argc, char *argv[])
+{
+     krb5_principal princ;
+     krb5_keyblock *keyblocks;
+     int num_keys;
+     char *keyblock_var, *num_var, buf[50];
+     Tcl_DString *keyblock_dstring = 0;
+     krb5_error_code krb5_ret;
+     kadm5_ret_t ret;
+     int retcode = TCL_OK;
+
+     GET_HANDLE(3, 0);
+
+     if ((krb5_ret = krb5_parse_name(context, argv[0], &princ)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing principal name");
+	  return TCL_ERROR;
+     }
+
+     if (parse_str(interp, argv[1], &keyblock_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing keyblock variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if (parse_str(interp, argv[2], &num_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing keyblock variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     ret = kadm5_randkey_principal(server_handle,
+				   princ, keyblock_var ? &keyblocks : 0,
+				   num_var ? &num_keys : 0);
+
+     if (ret == KADM5_OK) {
+	  if (keyblock_var) {
+	       keyblock_dstring = unparse_keyblocks(keyblocks, num_keys);
+	       if (! Tcl_SetVar(interp, keyblock_var,
+				keyblock_dstring->string,
+				TCL_LEAVE_ERR_MSG)) {
+		    Tcl_AppendElement(interp,
+				      "while setting keyblock variable");
+		    retcode = TCL_ERROR;
+		    goto finished;
+	       }
+	  }
+	  if (num_var) {
+	       sprintf(buf, "%d", num_keys);
+	       if (! Tcl_SetVar(interp, num_var, buf,
+				TCL_LEAVE_ERR_MSG)) {
+		    Tcl_AppendElement(interp,
+				      "while setting num_keys variable");
+	       }
+	  }
+	  set_ok(interp, "Key randomized.");
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     krb5_free_principal(context, princ);
+     if (keyblock_dstring) {
+	  Tcl_DStringFree(keyblock_dstring);
+	  free(keyblock_dstring);
+     }
+     return retcode;
+}
+
+
+
+static int tcl_kadm5_get_principal(ClientData clientData, Tcl_Interp *interp,
+				   int argc, char *argv[])
+{
+     krb5_principal princ;
+     kadm5_principal_ent_rec ent;
+     Tcl_DString *ent_dstring = 0;
+     char *ent_var;
+     char *name;
+     krb5_error_code krb5_ret;
+     int tcl_ret;
+     kadm5_ret_t ret = -1;
+     krb5_int32 mask;
+     int retcode = TCL_OK;
+     
+     GET_HANDLE(3, 1);
+
+     if((tcl_ret = parse_str(interp, argv[0], &name)) != TCL_OK)
+	return tcl_ret;
+     if(name != NULL) {
+	if ((krb5_ret = krb5_parse_name(context, name, &princ)) != 0) {
+	    stash_error(interp, krb5_ret);
+	    Tcl_AppendElement(interp, "while parsing principal name");
+	    return TCL_ERROR;
+	}
+     } else princ = NULL;
+
+     if ((tcl_ret = parse_str(interp, argv[1], &ent_var)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing entry variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if ((tcl_ret = parse_principal_mask(interp, argv[2], &mask)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing principal mask");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     
+     ret = kadm5_get_principal(server_handle, princ, ent_var ? &ent : 0,
+			       mask);
+
+     if (ret == KADM5_OK) {
+	  if (ent_var) {
+	       ent_dstring = unparse_principal_ent(&ent, mask);
+	       if (! Tcl_SetVar(interp, ent_var, ent_dstring->string,
+				TCL_LEAVE_ERR_MSG)) {
+		    Tcl_AppendElement(interp,
+				      "while setting entry variable");
+		    retcode = TCL_ERROR;
+		    goto finished;
+	       }
+	       set_ok(interp, "Principal retrieved.");
+	  }
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     if (ent_dstring) {
+	  Tcl_DStringFree(ent_dstring);
+	  free(ent_dstring);
+     }
+     if(princ != NULL)
+	krb5_free_principal(context, princ);
+     if (ret == KADM5_OK && ent_var &&
+	 (ret = kadm5_free_principal_ent(server_handle, &ent)) &&
+	 (retcode == TCL_OK)) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+     return retcode;
+}
+     
+static int tcl_kadm5_create_policy(ClientData clientData, Tcl_Interp *interp,
+				   int argc, char *argv[])
+{
+     int tcl_ret;
+     kadm5_ret_t ret;
+     int retcode = TCL_OK;
+     char *policy_string;
+     kadm5_policy_ent_t policy = 0;
+     krb5_int32 mask;
+
+     GET_HANDLE(2, 0);
+
+     if ((tcl_ret = parse_str(interp, argv[0], &policy_string)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy");
+	  return tcl_ret;
+     }
+
+     if (policy_string &&
+	 ((tcl_ret = parse_policy_ent(interp, policy_string, &policy))
+	  != TCL_OK)) {
+	  return tcl_ret;
+     }
+
+     if ((tcl_ret = parse_policy_mask(interp, argv[1], &mask)) != TCL_OK) {
+	  retcode = tcl_ret;
+	  goto finished;
+     }
+
+     ret = kadm5_create_policy(server_handle, policy, mask);
+
+     if (ret != KADM5_OK) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     else {
+	  set_ok(interp, "Policy created.");
+     }
+
+finished:
+     if (policy) {
+	  free_policy_ent(&policy);
+     }
+     return retcode;
+}
+
+
+
+static int tcl_kadm5_delete_policy(ClientData clientData, Tcl_Interp *interp,
+				   int argc, char *argv[])
+{
+     kadm5_ret_t ret;
+     char *policy;
+
+     GET_HANDLE(1, 0);
+
+     if (parse_str(interp, argv[0], &policy) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy name");
+	  return TCL_ERROR;
+     }
+     
+     ret = kadm5_delete_policy(server_handle, policy);
+
+     if (ret != KADM5_OK) {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+     else {
+	  set_ok(interp, "Policy deleted.");
+	  return TCL_OK;
+     }
+}
+
+
+
+static int tcl_kadm5_modify_policy(ClientData clientData, Tcl_Interp *interp,
+				   int argc, char *argv[])
+{
+     char *policy_string;
+     kadm5_policy_ent_t policy = 0;
+     int tcl_ret;
+     krb5_int32 mask;
+     int retcode = TCL_OK;
+     kadm5_ret_t ret;
+
+     GET_HANDLE(2, 0);
+
+     if ((tcl_ret = parse_str(interp, argv[0], &policy_string)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy");
+	  return tcl_ret;
+     }
+
+     if (policy_string &&
+	 ((tcl_ret = parse_policy_ent(interp, policy_string, &policy))
+	  != TCL_OK)) {
+	  return tcl_ret;
+     }
+
+     if ((tcl_ret = parse_policy_mask(interp, argv[1], &mask)) != TCL_OK) {
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     ret = kadm5_modify_policy(server_handle, policy, mask);
+
+     if (ret != KADM5_OK) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+     else {
+	  set_ok(interp, "Policy modified.");
+     }
+
+finished:
+     if (policy) {
+	  free_policy_ent(&policy);
+     }
+     return retcode;
+}
+
+
+static int tcl_kadm5_get_policy(ClientData clientData, Tcl_Interp *interp,
+				int argc, char *argv[])
+{
+     kadm5_policy_ent_rec ent;
+     Tcl_DString *ent_dstring = 0;
+     char *policy;
+     char *ent_var;
+     kadm5_ret_t ret;
+     int retcode = TCL_OK;
+
+     GET_HANDLE(2, 1);
+
+     if (parse_str(interp, argv[0], &policy) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy name");
+	  return TCL_ERROR;
+     }
+     
+     if (parse_str(interp, argv[1], &ent_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing entry variable name");
+	  return TCL_ERROR;
+     }
+     
+     ret = kadm5_get_policy(server_handle, policy, ent_var ? &ent : 0);
+
+     if (ret == KADM5_OK) {
+	  if (ent_var) {
+	       ent_dstring = unparse_policy_ent(&ent);
+	       if (! Tcl_SetVar(interp, ent_var, ent_dstring->string,
+				TCL_LEAVE_ERR_MSG)) {
+		    Tcl_AppendElement(interp,
+				      "while setting entry variable");
+		    retcode = TCL_ERROR;
+		    goto finished;
+	       }
+	       set_ok(interp, "Policy retrieved.");
+	  }
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     if (ent_dstring) {
+	  Tcl_DStringFree(ent_dstring);
+	  free(ent_dstring);
+     }
+     if (ent_var && ret == KADM5_OK &&
+	 (ret = kadm5_free_policy_ent(server_handle, &ent)) &&
+	 (retcode == TCL_OK)) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+     return retcode;
+}
+
+     
+     
+static int tcl_kadm5_free_principal_ent(ClientData clientData,
+					Tcl_Interp *interp,
+					int argc, char *argv[])
+{
+     char *ent_name;
+     kadm5_principal_ent_t ent;
+     kadm5_ret_t ret;
+
+     GET_HANDLE(1, 0);
+
+     if (parse_str(interp, argv[0], &ent_name) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing entry name");
+	  return TCL_ERROR;
+     }
+
+     if ((! ent_name) &&
+	 (ret = kadm5_free_principal_ent(server_handle, 0))) {
+	 stash_error(interp, ret);
+	 return TCL_ERROR;
+     }
+     else {
+	  Tcl_HashEntry *entry;
+
+	  if (strncmp(ent_name, "principal", sizeof("principal")-1)) {
+	       Tcl_AppendResult(interp, "invalid principal handle \"",
+				ent_name, "\"", 0);
+	       return TCL_ERROR;
+	  }
+	  if (! struct_table) {
+	       if (! (struct_table = malloc(sizeof(*struct_table)))) {
+		    fprintf(stderr, "Out of memory!\n");
+		    exit(1); /* XXX */
+	       }
+	       Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+	  }
+	  
+	  if (! (entry = Tcl_FindHashEntry(struct_table, ent_name))) {
+	       Tcl_AppendResult(interp, "principal handle \"", ent_name,
+				"\" not found", 0);
+	       return TCL_ERROR;
+	  }
+
+	  ent = (kadm5_principal_ent_t) Tcl_GetHashValue(entry);
+
+	  ret = kadm5_free_principal_ent(server_handle, ent);
+	  if (ret != KADM5_OK) {
+	      stash_error(interp, ret);
+	      return TCL_ERROR;
+	  }
+	  Tcl_DeleteHashEntry(entry);
+     }
+     set_ok(interp, "Principal freed.");
+     return TCL_OK;
+}
+	  
+		    
+static int tcl_kadm5_free_policy_ent(ClientData clientData,
+				     Tcl_Interp *interp,
+				     int argc, char *argv[])
+{
+     char *ent_name;
+     kadm5_policy_ent_t ent;
+     kadm5_ret_t ret;
+
+     GET_HANDLE(1, 0);
+
+     if (parse_str(interp, argv[0], &ent_name) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing entry name");
+	  return TCL_ERROR;
+     }
+
+     if ((! ent_name) &&
+	 (ret = kadm5_free_policy_ent(server_handle, 0))) {
+	 stash_error(interp, ret);
+	 return TCL_ERROR;
+     }
+     else {
+	  Tcl_HashEntry *entry;
+
+	  if (strncmp(ent_name, "policy", sizeof("policy")-1)) {
+	       Tcl_AppendResult(interp, "invalid principal handle \"",
+				ent_name, "\"", 0);
+	       return TCL_ERROR;
+	  }
+	  if (! struct_table) {
+	       if (! (struct_table = malloc(sizeof(*struct_table)))) {
+		    fprintf(stderr, "Out of memory!\n");
+		    exit(1); /* XXX */
+	       }
+	       Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+	  }
+	  
+	  if (! (entry = Tcl_FindHashEntry(struct_table, ent_name))) {
+	       Tcl_AppendResult(interp, "policy handle \"", ent_name,
+				"\" not found", 0);
+	       return TCL_ERROR;
+	  }
+
+	  ent = (kadm5_policy_ent_t) Tcl_GetHashValue(entry);
+
+	  if ((ret = kadm5_free_policy_ent(server_handle, ent)) != KADM5_OK) {
+	      stash_error(interp, ret);
+	      return TCL_ERROR;
+	  }
+	  Tcl_DeleteHashEntry(entry);
+     }
+     set_ok(interp, "Policy freed.");
+     return TCL_OK;
+}
+	  
+		    
+static int tcl_kadm5_get_privs(ClientData clientData, Tcl_Interp *interp,
+			       int argc, char *argv[])
+{
+     char *set_ret;
+     kadm5_ret_t ret;
+     char *priv_var;
+     long privs;
+
+     GET_HANDLE(1, 0);
+
+     if (parse_str(interp, argv[0], &priv_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing privs variable name");
+	  return TCL_ERROR;
+     }
+
+     ret = kadm5_get_privs(server_handle, priv_var ? &privs : 0);
+
+     if (ret == KADM5_OK) {
+	  if (priv_var) {
+	       Tcl_DString *str = unparse_privs(privs);
+	       set_ret = Tcl_SetVar(interp, priv_var, str->string,
+				    TCL_LEAVE_ERR_MSG);
+	       Tcl_DStringFree(str);
+	       free(str);
+	       if (! set_ret) {
+		    Tcl_AppendElement(interp, "while setting priv variable");
+		    return TCL_ERROR;
+	       }
+	  }
+	  set_ok(interp, "Privileges retrieved.");
+	  return TCL_OK;
+     }
+     else {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+}
+		    
+
+void Tcl_kadm5_init(Tcl_Interp *interp)
+{
+    char buf[20];
+
+     Tcl_SetVar(interp, "KADM5_ADMIN_SERVICE",
+		KADM5_ADMIN_SERVICE, TCL_GLOBAL_ONLY);
+     Tcl_SetVar(interp, "KADM5_CHANGEPW_SERVICE",
+		KADM5_CHANGEPW_SERVICE, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", KADM5_STRUCT_VERSION);
+     Tcl_SetVar(interp, "KADM5_STRUCT_VERSION", buf, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", KADM5_API_VERSION_1);
+     Tcl_SetVar(interp, "KADM5_API_VERSION_1", buf, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", KADM5_API_VERSION_2);
+     Tcl_SetVar(interp, "KADM5_API_VERSION_2", buf, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", KADM5_API_VERSION_MASK);
+     Tcl_SetVar(interp, "KADM5_API_VERSION_MASK", buf, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", KADM5_STRUCT_VERSION_MASK);
+     Tcl_SetVar(interp, "KADM5_STRUCT_VERSION_MASK", buf,
+		TCL_GLOBAL_ONLY);
+
+     Tcl_CreateCommand(interp, "kadm5_init", tcl_kadm5_init, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_init_with_creds",
+		       tcl_kadm5_init_with_creds, 0, 0); 
+     Tcl_CreateCommand(interp, "kadm5_destroy", tcl_kadm5_destroy, 0,
+		       0);
+     Tcl_CreateCommand(interp, "kadm5_create_principal",
+		       tcl_kadm5_create_principal, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_delete_principal",
+		       tcl_kadm5_delete_principal, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_modify_principal",
+		       tcl_kadm5_modify_principal, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_rename_principal",
+		       tcl_kadm5_rename_principal, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_chpass_principal",
+		       tcl_kadm5_chpass_principal, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_chpass_principal_util",
+		       tcl_kadm5_chpass_principal_util, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_randkey_principal",
+		       tcl_kadm5_randkey_principal, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_get_principal",
+		       tcl_kadm5_get_principal, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_create_policy",
+		       tcl_kadm5_create_policy, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_delete_policy",
+		       tcl_kadm5_delete_policy, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_modify_policy",
+		       tcl_kadm5_modify_policy, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_get_policy",
+		       tcl_kadm5_get_policy, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_free_principal_ent",
+		       tcl_kadm5_free_principal_ent, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_free_policy_ent",
+		       tcl_kadm5_free_policy_ent, 0, 0);
+     Tcl_CreateCommand(interp, "kadm5_get_privs",
+		       tcl_kadm5_get_privs, 0, 0);
+}
diff --git a/mechglue/src/kadmin/testing/util/tcl_kadm5.h b/mechglue/src/kadmin/testing/util/tcl_kadm5.h
new file mode 100644
index 000000000..7e237753a
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/tcl_kadm5.h
@@ -0,0 +1,4 @@
+
+void Tcl_kadm5_init(Tcl_Interp *interp);
+void Tcl_ovsec_kadm_init(Tcl_Interp *interp);
+
diff --git a/mechglue/src/kadmin/testing/util/tcl_krb5_hash.c b/mechglue/src/kadmin/testing/util/tcl_krb5_hash.c
new file mode 100644
index 000000000..7fe1b8f74
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/tcl_krb5_hash.c
@@ -0,0 +1,167 @@
+/*
+ * All of the TCL krb5 functions which return (or place into output
+ * variables) structures or pointers to structures that can't be
+ * represented as tcl native types, do so by returning a handle for
+ * the appropriate structure.  The handle is a string of the form
+ * "type$id", where "type" is the type of datum represented by the
+ * handle and "id" is a unique identifier for it.  This handle can
+ * then be used later by the caller to refer to the object, and
+ * internally to retrieve the actually datum from the appropriate hash
+ * table.
+ *
+ * The functions in this file do four things:
+ * 
+ * 1) Given a pointer to a datum and a string representing the type of
+ * datum to which the pointer refers, create a new handle for the
+ * datum, store the datum in the hash table using the new handle as
+ * its key, and return the new handle.
+ *
+ * 2) Given a handle, locate and return the appropriate hash table
+ * datum.
+ *
+ * 3) Given a handle, look through a table of types and unparse
+ * functions to figure out what function to call to get a string
+ * representation of the datum, call it with the appropriate pointer
+ * (obtained from the hash table) as an argument, and return the
+ * resulting string as the unparsed form of the datum.
+ *
+ * 4) Given a handle, remove that handle and its associated datum from
+ * the hash table (but don't free it -- it's assumed to have already
+ * been freed by the caller).
+ */
+
+#if HAVE_TCL_H
+#include <tcl.h>
+#elif HAVE_TCL_TCL_H
+#include <tcl/tcl.h>
+#endif
+#include <assert.h>
+
+#define SEP_STR "$"
+
+static char *memory_error = "out of memory";
+
+/*
+ * Right now, we're only using one hash table.  However, at some point
+ * in the future, we might decide to use a separate hash table for
+ * every type.  Therefore, I'm putting this function in as an
+ * abstraction so it's the only thing we'll have to change if we
+ * decide to do that.
+ *
+ * Also, this function allows us to put in just one place the code for
+ * checking to make sure that the hash table exists and initializing
+ * it if it doesn't.
+ */
+
+static TclHashTable *get_hash_table(Tcl_Interp *interp,
+				    char *type)
+{
+     static Tcl_HashTable *hash_table = 0;
+
+     if (! hash_table) {
+	  if (! (hash_table = malloc(sizeof(*hash_table)))) {
+	       Tcl_SetResult(interp, memory_error, TCL_STATIC);
+	       return 0;
+	  }
+	  Tcl_InitHashTable(hash_table, TCL_STRING_KEYS);
+     }
+     return hash_table;
+}
+
+#define MAX_ID 999999999
+#define ID_BUF_SIZE 10
+
+static Tcl_HashEntry *get_new_handle(Tcl_Interp *interp,
+				     char *type)
+{
+     static unsigned long int id_counter = 0;
+     Tcl_DString *handle;
+     char int_buf[ID_BUF_SIZE];
+     
+     if (! (handle = malloc(sizeof(*handle)))) {
+	  Tcl_SetResult(interp, memory_error, TCL_STATIC);
+	  return 0;
+     }
+     Tcl_DStringInit(handle);
+
+     assert(id_counter <= MAX_ID);
+
+     sprintf(int_buf, "%d", id_counter++);
+
+     Tcl_DStringAppend(handle, type, -1);
+     Tcl_DStringAppend(handle, SEP_STR, -1);
+     Tcl_DStringAppend(handle, int_buf, -1);
+
+     return handle;
+}
+     
+     
+Tcl_DString *tcl_krb5_create_object(Tcl_Interp *interp,
+				    char *type,
+				    ClientData datum)
+{
+     Tcl_HashTable *table;
+     Tcl_DString *handle;
+     Tcl_HashEntry *entry;
+     int entry_created = 0;
+
+     if (! (table = get_hash_table(interp, type))) {
+	  return 0;
+     }
+
+     if (! (handle = get_new_handle(interp, type))) {
+	  return 0;
+     }
+
+     if (! (entry = Tcl_CreateHashEntry(table, handle, &entry_created))) {
+	  Tcl_SetResult(interp, "error creating hash entry", TCL_STATIC);
+	  Tcl_DStringFree(handle);
+	  return TCL_ERROR;
+     }
+
+     assert(entry_created);
+
+     Tcl_SetHashValue(entry, datum);
+
+     return handle;
+}
+
+ClientData tcl_krb5_get_object(Tcl_Interp *interp,
+			       char *handle)
+{
+     char *myhandle, *id_ptr;
+     Tcl_HashTable *table;
+     Tcl_HashEntry *entry;
+
+     if (! (myhandle = strdup(handle))) {
+	  Tcl_SetResult(interp, memory_error, TCL_STATIC);
+	  return 0;
+     }
+
+     if (! (id_ptr = index(myhandle, *SEP_STR))) {
+	  free(myhandle);
+	  Tcl_ResetResult(interp);
+	  Tcl_AppendResult(interp, "malformatted handle \"", handle,
+			   "\"", 0);
+	  return 0;
+     }
+
+     *id_ptr = '\0';
+     
+     if (! (table = get_hash_table(interp, myhandle))) {
+	  free(myhandle);
+	  return 0;
+     }
+
+     free(myhandle);
+
+     if (! (entry = Tcl_FindHashEntry(table, handle))) {
+	  Tcl_ResetResult(interp);
+	  Tcl_AppendResult(interp, "no object corresponding to handle \"",
+			   handle, "\"", 0);
+	  return 0;
+     }
+
+     return(Tcl_GetHashValue(entry));
+}
+
diff --git a/mechglue/src/kadmin/testing/util/tcl_ovsec_kadm.c b/mechglue/src/kadmin/testing/util/tcl_ovsec_kadm.c
new file mode 100644
index 000000000..68eb3f7f8
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/tcl_ovsec_kadm.c
@@ -0,0 +1,2029 @@
+#include <stdio.h>
+#include <string.h>
+#if HAVE_TCL_H
+#include <tcl.h>
+#elif HAVE_TCL_TCL_H
+#include <tcl/tcl.h>
+#endif
+#define USE_KADM5_API_VERSION 1
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "tcl_kadm5.h"
+#include <adb_err.h>
+
+struct flagval {
+     char *name;
+     krb5_flags val;
+};
+
+/* XXX This should probably be in the hash table like server_handle */
+static krb5_context context;
+
+struct flagval krb5_flags_array[] = {
+     {"KRB5_KDB_DISALLOW_POSTDATED", KRB5_KDB_DISALLOW_POSTDATED},
+     {"KRB5_KDB_DISALLOW_FORWARDABLE", KRB5_KDB_DISALLOW_FORWARDABLE},
+     {"KRB5_KDB_DISALLOW_TGT_BASED", KRB5_KDB_DISALLOW_TGT_BASED},
+     {"KRB5_KDB_DISALLOW_RENEWABLE", KRB5_KDB_DISALLOW_RENEWABLE},
+     {"KRB5_KDB_DISALLOW_PROXIABLE", KRB5_KDB_DISALLOW_PROXIABLE},
+     {"KRB5_KDB_DISALLOW_DUP_SKEY", KRB5_KDB_DISALLOW_DUP_SKEY},
+     {"KRB5_KDB_DISALLOW_ALL_TIX", KRB5_KDB_DISALLOW_ALL_TIX},
+     {"KRB5_KDB_REQUIRES_PRE_AUTH", KRB5_KDB_REQUIRES_PRE_AUTH},
+     {"KRB5_KDB_REQUIRES_HW_AUTH", KRB5_KDB_REQUIRES_HW_AUTH},
+     {"KRB5_KDB_REQUIRES_PWCHANGE", KRB5_KDB_REQUIRES_PWCHANGE},
+     {"KRB5_KDB_DISALLOW_SVR", KRB5_KDB_DISALLOW_SVR},
+     {"KRB5_KDB_PWCHANGE_SERVICE", KRB5_KDB_PWCHANGE_SERVICE}
+};
+
+struct flagval aux_attributes[] = {
+     {"OVSEC_KADM_POLICY",   OVSEC_KADM_POLICY}
+};
+
+struct flagval principal_mask_flags[] = {
+     {"OVSEC_KADM_PRINCIPAL", OVSEC_KADM_PRINCIPAL},
+     {"OVSEC_KADM_PRINC_EXPIRE_TIME", OVSEC_KADM_PRINC_EXPIRE_TIME},
+     {"OVSEC_KADM_PW_EXPIRATION", OVSEC_KADM_PW_EXPIRATION},
+     {"OVSEC_KADM_LAST_PWD_CHANGE", OVSEC_KADM_LAST_PWD_CHANGE},
+     {"OVSEC_KADM_ATTRIBUTES", OVSEC_KADM_ATTRIBUTES},
+     {"OVSEC_KADM_MAX_LIFE", OVSEC_KADM_MAX_LIFE},
+     {"OVSEC_KADM_MOD_TIME", OVSEC_KADM_MOD_TIME},
+     {"OVSEC_KADM_MOD_NAME", OVSEC_KADM_MOD_NAME},
+     {"OVSEC_KADM_KVNO", OVSEC_KADM_KVNO},
+     {"OVSEC_KADM_MKVNO", OVSEC_KADM_MKVNO},
+     {"OVSEC_KADM_AUX_ATTRIBUTES", OVSEC_KADM_AUX_ATTRIBUTES},
+     {"OVSEC_KADM_POLICY", OVSEC_KADM_POLICY},
+     {"OVSEC_KADM_POLICY_CLR", OVSEC_KADM_POLICY_CLR}
+};
+
+struct flagval policy_mask_flags[] = {
+     {"OVSEC_KADM_POLICY", OVSEC_KADM_POLICY},
+     {"OVSEC_KADM_PW_MAX_LIFE", OVSEC_KADM_PW_MAX_LIFE},
+     {"OVSEC_KADM_PW_MIN_LIFE", OVSEC_KADM_PW_MIN_LIFE},
+     {"OVSEC_KADM_PW_MIN_LENGTH", OVSEC_KADM_PW_MIN_LENGTH},
+     {"OVSEC_KADM_PW_MIN_CLASSES", OVSEC_KADM_PW_MIN_CLASSES},
+     {"OVSEC_KADM_PW_HISTORY_NUM", OVSEC_KADM_PW_HISTORY_NUM},
+     {"OVSEC_KADM_REF_COUNT", OVSEC_KADM_REF_COUNT}
+};
+
+struct flagval priv_flags[] = {
+     {"OVSEC_KADM_PRIV_GET", OVSEC_KADM_PRIV_GET},
+     {"OVSEC_KADM_PRIV_ADD", OVSEC_KADM_PRIV_ADD},
+     {"OVSEC_KADM_PRIV_MODIFY", OVSEC_KADM_PRIV_MODIFY},
+     {"OVSEC_KADM_PRIV_DELETE", OVSEC_KADM_PRIV_DELETE}
+};
+    
+
+static char *arg_error = "wrong # args";
+
+static Tcl_HashTable *struct_table = 0;
+
+static int put_server_handle(Tcl_Interp *interp, void *handle, char **name)
+{
+    int i = 1, newPtr = 0;
+    static char buf[20];
+    Tcl_HashEntry *entry;
+
+    if (! struct_table) {
+	if (! (struct_table =
+	       malloc(sizeof(*struct_table)))) {
+	    fprintf(stderr, "Out of memory!\n");
+	    exit(1); /* XXX */
+	}
+	Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+    }
+
+    do {
+	/*
+	 * Handles from ovsec_kadm_init() and kadm5_init() should not
+	 * be mixed during unit tests, but the API would happily
+	 * accept them.  Making the hash entry names different in
+	 * tcl_kadm.c and tcl_ovsec_kadm.c ensures that GET_HANDLE
+	 * will fail if presented a handle from the other API.
+	 */
+	sprintf(buf, "ovsec_kadm_handle%d", i);
+	entry = Tcl_CreateHashEntry(struct_table, buf, &newPtr);
+	i++;
+    } while (! newPtr);
+
+    Tcl_SetHashValue(entry, handle);
+
+    *name = buf;
+
+    return TCL_OK;
+}
+
+static int get_server_handle(Tcl_Interp *interp, char *name, void **handle) 
+{
+    Tcl_HashEntry *entry;
+
+    if(!strcasecmp(name, "null"))
+	*handle = 0;
+    else {
+	if (! (struct_table &&
+	       (entry = Tcl_FindHashEntry(struct_table, name)))) {
+	     if (strncmp(name, "kadm5_handle", 12) == 0)
+		  Tcl_AppendResult(interp, "kadm5 handle specified "
+				   "for ovsec_kadm api: ", name, 0);
+	     else 
+		  Tcl_AppendResult(interp, "unknown server handle ", name, 0);
+	    return TCL_ERROR;
+	}
+	*handle = (void *) Tcl_GetHashValue(entry);
+    }
+    return TCL_OK;
+}
+
+static int remove_server_handle(Tcl_Interp *interp, char *name) 
+{
+    Tcl_HashEntry *entry;
+
+    if (! (struct_table &&
+	   (entry = Tcl_FindHashEntry(struct_table, name)))) {
+	Tcl_AppendResult(interp, "unknown server handle ", name, 0);
+	return TCL_ERROR;
+    }
+
+    Tcl_DeleteHashEntry(entry);
+    return TCL_OK;
+}
+
+#define GET_HANDLE(num_args, do_dostruct) \
+    void *server_handle; \
+    int dostruct = 0; \
+    char *whoami = argv[0]; \
+    argv++, argc--; \
+    if ((argc > 0) && (! strcmp(argv[0], "-struct"))) { \
+	if (! do_dostruct) { \
+	    Tcl_AppendResult(interp, "-struct isn't a valid option for ", \
+			     whoami, 0); \
+	    return TCL_ERROR; \
+	} \
+	dostruct++; \
+	argv++, argc--; \
+    } \
+    if (argc != num_args + 1) { \
+	Tcl_AppendResult(interp, whoami, ": ", arg_error, 0); \
+	return TCL_ERROR; \
+    } \
+    { \
+	int htcl_ret; \
+	if ((htcl_ret = get_server_handle(interp, argv[0], &server_handle)) \
+	    != TCL_OK) { \
+	    return htcl_ret; \
+	} \
+    } \
+    argv++, argc--;
+
+static Tcl_HashTable *create_flag_table(struct flagval *flags, int size)
+{
+     Tcl_HashTable *table;
+     Tcl_HashEntry *entry;
+     int i;
+
+     if (! (table = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_InitHashTable(table, TCL_STRING_KEYS);
+
+     for (i = 0; i < size; i++) {
+	  int newPtr;
+	       
+	  if (! (entry = Tcl_CreateHashEntry(table, flags[i].name, &newPtr))) {
+	       fprintf(stderr, "Out of memory!\n");
+	       exit(1); /* XXX */
+	  }
+
+	  Tcl_SetHashValue(entry, &flags[i].val);
+     }
+
+     return table;
+}
+
+
+static Tcl_DString *unparse_str(char *in_str)
+{
+     Tcl_DString *str;
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     if (! in_str) {
+	  Tcl_DStringAppend(str, "null", -1);
+     }
+     else {
+	  Tcl_DStringAppend(str, in_str, -1);
+     }
+
+     return str;
+}
+
+
+	  
+static int parse_str(Tcl_Interp *interp, char *in_str, char **out_str)
+{
+     if (! in_str) {
+	  *out_str = 0;
+     }
+     else if (! strcasecmp(in_str, "null")) {
+	  *out_str = 0;
+     }
+     else {
+	  *out_str = in_str;
+     }
+     return TCL_OK;
+}
+
+
+static void set_ok(Tcl_Interp *interp, char *string)
+{
+     Tcl_SetResult(interp, "OK", TCL_STATIC);
+     Tcl_AppendElement(interp, "OVSEC_KADM_OK");
+     Tcl_AppendElement(interp, string);
+}
+
+
+
+static Tcl_DString *unparse_err(ovsec_kadm_ret_t code)
+{
+     char *code_string;
+     const char *error_string;
+     Tcl_DString *dstring;
+
+     switch (code) {
+     case OVSEC_KADM_FAILURE: code_string = "OVSEC_KADM_FAILURE"; break;
+     case OVSEC_KADM_AUTH_GET: code_string = "OVSEC_KADM_AUTH_GET"; break;
+     case OVSEC_KADM_AUTH_ADD: code_string = "OVSEC_KADM_AUTH_ADD"; break;
+     case OVSEC_KADM_AUTH_MODIFY:
+	  code_string = "OVSEC_KADM_AUTH_MODIFY"; break;
+     case OVSEC_KADM_AUTH_DELETE:
+	  code_string = "OVSEC_KADM_AUTH_DELETE"; break;
+     case OVSEC_KADM_AUTH_INSUFFICIENT:
+	  code_string = "OVSEC_KADM_AUTH_INSUFFICIENT"; break;
+     case OVSEC_KADM_BAD_DB: code_string = "OVSEC_KADM_BAD_DB"; break;
+     case OVSEC_KADM_DUP: code_string = "OVSEC_KADM_DUP"; break;
+     case OVSEC_KADM_RPC_ERROR: code_string = "OVSEC_KADM_RPC_ERROR"; break;
+     case OVSEC_KADM_NO_SRV: code_string = "OVSEC_KADM_NO_SRV"; break;
+     case OVSEC_KADM_BAD_HIST_KEY:
+	  code_string = "OVSEC_KADM_BAD_HIST_KEY"; break;
+     case OVSEC_KADM_NOT_INIT: code_string = "OVSEC_KADM_NOT_INIT"; break;
+     case OVSEC_KADM_INIT: code_string = "OVSEC_KADM_INIT"; break;
+     case OVSEC_KADM_BAD_PASSWORD:
+	  code_string = "OVSEC_KADM_BAD_PASSWORD"; break;
+     case OVSEC_KADM_UNK_PRINC: code_string = "OVSEC_KADM_UNK_PRINC"; break;
+     case OVSEC_KADM_UNK_POLICY: code_string = "OVSEC_KADM_UNK_POLICY"; break;
+     case OVSEC_KADM_BAD_MASK: code_string = "OVSEC_KADM_BAD_MASK"; break;
+     case OVSEC_KADM_BAD_CLASS: code_string = "OVSEC_KADM_BAD_CLASS"; break;
+     case OVSEC_KADM_BAD_LENGTH: code_string = "OVSEC_KADM_BAD_LENGTH"; break;
+     case OVSEC_KADM_BAD_POLICY: code_string = "OVSEC_KADM_BAD_POLICY"; break;
+     case OVSEC_KADM_BAD_HISTORY: code_string = "OVSEC_KADM_BAD_HISTORY"; break;
+     case OVSEC_KADM_BAD_PRINCIPAL:
+	  code_string = "OVSEC_KADM_BAD_PRINCIPAL"; break;
+     case OVSEC_KADM_BAD_AUX_ATTR:
+	  code_string = "OVSEC_KADM_BAD_AUX_ATTR"; break;
+     case OVSEC_KADM_PASS_Q_TOOSHORT:
+	  code_string = "OVSEC_KADM_PASS_Q_TOOSHORT"; break;
+     case OVSEC_KADM_PASS_Q_CLASS:
+	  code_string = "OVSEC_KADM_PASS_Q_CLASS"; break;
+     case OVSEC_KADM_PASS_Q_DICT:
+	  code_string = "OVSEC_KADM_PASS_Q_DICT"; break;
+     case OVSEC_KADM_PASS_REUSE: code_string = "OVSEC_KADM_PASS_REUSE"; break;
+     case OVSEC_KADM_PASS_TOOSOON:
+	  code_string = "OVSEC_KADM_PASS_TOOSOON"; break;
+     case OVSEC_KADM_POLICY_REF:
+	  code_string = "OVSEC_KADM_POLICY_REF"; break;
+     case OVSEC_KADM_PROTECT_PRINCIPAL:
+	  code_string = "OVSEC_KADM_PROTECT_PRINCIPAL"; break;
+     case OVSEC_KADM_BAD_SERVER_HANDLE:
+	  code_string = "OVSEC_KADM_BAD_SERVER_HANDLE"; break;
+     case OVSEC_KADM_BAD_STRUCT_VERSION:
+     	  code_string = "OVSEC_KADM_BAD_STRUCT_VERSION"; break;
+     case OVSEC_KADM_OLD_STRUCT_VERSION:
+	  code_string = "OVSEC_KADM_OLD_STRUCT_VERSION"; break;
+     case OVSEC_KADM_NEW_STRUCT_VERSION:
+	  code_string = "OVSEC_KADM_NEW_STRUCT_VERSION"; break;
+     case OVSEC_KADM_BAD_API_VERSION:
+	  code_string = "OVSEC_KADM_BAD_API_VERSION"; break;
+     case OVSEC_KADM_OLD_LIB_API_VERSION:
+     	  code_string = "OVSEC_KADM_OLD_LIB_API_VERSION"; break;
+     case OVSEC_KADM_OLD_SERVER_API_VERSION:
+     	  code_string = "OVSEC_KADM_OLD_SERVER_API_VERSION"; break;
+     case OVSEC_KADM_NEW_LIB_API_VERSION:
+     	  code_string = "OVSEC_KADM_NEW_LIB_API_VERSION"; break;
+     case OVSEC_KADM_NEW_SERVER_API_VERSION:
+	  code_string = "OVSEC_KADM_NEW_SERVER_API_VERSION"; break;
+     case OVSEC_KADM_SECURE_PRINC_MISSING:
+	  code_string = "OVSEC_KADM_SECURE_PRINC_MISSING"; break;
+     case KADM5_NO_RENAME_SALT:
+	  code_string = "KADM5_NO_RENAME_SALT"; break;
+     case KADM5_BAD_CLIENT_PARAMS:
+	  code_string = "KADM5_BAD_CLIENT_PARAMS"; break;
+     case KADM5_BAD_SERVER_PARAMS:
+	  code_string = "KADM5_BAD_SERVER_PARAMS"; break;
+     case KADM5_AUTH_LIST:
+	  code_string = "KADM5_AUTH_LIST"; break;
+     case KADM5_AUTH_CHANGEPW:
+	  code_string = "KADM5_AUTH_CHANGEPW"; break;
+     case OSA_ADB_DUP: code_string = "OSA_ADB_DUP"; break;
+     case OSA_ADB_NOENT: code_string = "ENOENT"; break;
+     case OSA_ADB_DBINIT: code_string = "OSA_ADB_DBINIT"; break;
+     case OSA_ADB_BAD_POLICY: code_string = "Bad policy name"; break;
+     case OSA_ADB_BAD_PRINC: code_string = "Bad principal name"; break;
+     case OSA_ADB_BAD_DB: code_string = "Invalid database."; break;
+     case OSA_ADB_XDR_FAILURE: code_string = "OSA_ADB_XDR_FAILURE"; break;
+     case KRB5_KDB_INUSE: code_string = "KRB5_KDB_INUSE"; break;
+     case KRB5_KDB_UK_SERROR: code_string = "KRB5_KDB_UK_SERROR"; break;
+     case KRB5_KDB_UK_RERROR: code_string = "KRB5_KDB_UK_RERROR"; break;
+     case KRB5_KDB_UNAUTH: code_string = "KRB5_KDB_UNAUTH"; break;
+     case KRB5_KDB_NOENTRY: code_string = "KRB5_KDB_NOENTRY"; break;
+     case KRB5_KDB_ILL_WILDCARD: code_string = "KRB5_KDB_ILL_WILDCARD"; break;
+     case KRB5_KDB_DB_INUSE: code_string = "KRB5_KDB_DB_INUSE"; break;
+     case KRB5_KDB_DB_CHANGED: code_string = "KRB5_KDB_DB_CHANGED"; break;
+     case KRB5_KDB_TRUNCATED_RECORD:
+	  code_string = "KRB5_KDB_TRUNCATED_RECORD"; break;
+     case KRB5_KDB_RECURSIVELOCK:
+	  code_string = "KRB5_KDB_RECURSIVELOCK"; break;
+     case KRB5_KDB_NOTLOCKED: code_string = "KRB5_KDB_NOTLOCKED"; break;
+     case KRB5_KDB_BADLOCKMODE: code_string = "KRB5_KDB_BADLOCKMODE"; break;
+     case KRB5_KDB_DBNOTINITED: code_string = "KRB5_KDB_DBNOTINITED"; break;
+     case KRB5_KDB_DBINITED: code_string = "KRB5_KDB_DBINITED"; break;
+     case KRB5_KDB_ILLDIRECTION: code_string = "KRB5_KDB_ILLDIRECTION"; break;
+     case KRB5_KDB_NOMASTERKEY: code_string = "KRB5_KDB_NOMASTERKEY"; break;
+     case KRB5_KDB_BADMASTERKEY: code_string = "KRB5_KDB_BADMASTERKEY"; break;
+     case KRB5_KDB_INVALIDKEYSIZE:
+	  code_string = "KRB5_KDB_INVALIDKEYSIZE"; break;
+     case KRB5_KDB_CANTREAD_STORED:
+	  code_string = "KRB5_KDB_CANTREAD_STORED"; break;
+     case KRB5_KDB_BADSTORED_MKEY:
+	  code_string = "KRB5_KDB_BADSTORED_MKEY"; break;
+     case KRB5_KDB_CANTLOCK_DB: code_string = "KRB5_KDB_CANTLOCK_DB"; break;
+     case KRB5_KDB_DB_CORRUPT: code_string = "KRB5_KDB_DB_CORRUPT"; break;
+     case KRB5_PARSE_ILLCHAR: code_string = "KRB5_PARSE_ILLCHAR"; break;
+     case KRB5_PARSE_MALFORMED: code_string = "KRB5_PARSE_MALFORMED"; break;
+     case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN"; break;
+     case KRB5_REALM_UNKNOWN: code_string = "KRB5_REALM_UNKNOWN"; break;
+     case KRB5_KDC_UNREACH: code_string = "KRB5_KDC_UNREACH"; break;
+     case KRB5_KDCREP_MODIFIED: code_string = "KRB5_KDCREP_MODIFIED"; break;
+     case KRB5KRB_AP_ERR_BAD_INTEGRITY: code_string  = "KRB5KRB_AP_ERR_BAD_INTEGRITY"; break;
+     case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: code_string = "KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN"; break;
+     case EINVAL: code_string = "EINVAL"; break;
+     case ENOENT: code_string = "ENOENT"; break;
+     default:
+	 fprintf(stderr, "**** CODE %d (%s) ***\n", code,
+		 error_message (code));
+	 code_string = "UNKNOWN";
+	 break;
+     }
+
+     error_string = error_message(code);
+
+     if (! (dstring = (Tcl_DString *) malloc(sizeof(Tcl_DString)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX Do we really want to exit?  Ok if this is */
+		   /* just a test program, but what about if it gets */
+		   /* used for other things later? */
+     }
+
+     Tcl_DStringInit(dstring);
+
+     if (! (Tcl_DStringAppendElement(dstring, "ERROR") &&
+	    Tcl_DStringAppendElement(dstring, code_string) &&
+	    Tcl_DStringAppendElement(dstring, error_string))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+     
+     return dstring;
+}
+
+
+
+static void stash_error(Tcl_Interp *interp, krb5_error_code code)
+{
+     Tcl_DString *dstring = unparse_err(code);
+     Tcl_DStringResult(interp, dstring);
+     Tcl_DStringFree(dstring);
+     free(dstring);
+}
+
+
+
+static Tcl_DString *unparse_flags(struct flagval *array, int size,
+				  krb5_int32 flags)
+{
+     int i;
+     Tcl_DString *str;
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     for (i = 0; i < size; i++) {
+	  if (flags & array[i].val) {
+	       Tcl_DStringAppendElement(str, array[i].name);
+	  }
+     }
+
+     return str;
+}
+
+
+static int parse_flags(Tcl_Interp *interp, Tcl_HashTable *table,
+		       struct flagval *array, int size, char *str,
+		       krb5_flags *flags)
+{
+     int tmp, argc, i, retcode = TCL_OK;
+     char **argv;
+     Tcl_HashEntry *entry;
+
+     if (Tcl_GetInt(interp, str, &tmp) == TCL_OK) {
+	  *flags = tmp;
+	  return TCL_OK;
+     }
+     Tcl_ResetResult(interp);
+
+     if (Tcl_SplitList(interp, str, &argc, &argv) != TCL_OK) {
+	  return TCL_ERROR;
+     }
+
+     if (! table) {
+	  table = create_flag_table(array, size);
+     }
+
+     *flags = 0;
+
+     for (i = 0; i < argc; i++) {
+	  if (! (entry = Tcl_FindHashEntry(table, argv[i]))) {
+	       Tcl_AppendResult(interp, "unknown krb5 flag ", argv[i], 0);
+	       retcode = TCL_ERROR;
+	       break;
+	  }
+	  *flags |= *(krb5_flags *) Tcl_GetHashValue(entry);
+     }
+  
+     Tcl_Free(argv);
+     return(retcode);
+}
+
+static Tcl_DString *unparse_privs(krb5_flags flags)
+{
+     return unparse_flags(priv_flags, sizeof(priv_flags) /
+			  sizeof(struct flagval), flags);
+}
+
+
+static Tcl_DString *unparse_krb5_flags(krb5_flags flags)
+{
+     return unparse_flags(krb5_flags_array, sizeof(krb5_flags_array) /
+			  sizeof(struct flagval), flags);
+}
+
+static int parse_krb5_flags(Tcl_Interp *interp, char *str, krb5_flags *flags)
+{
+     krb5_flags tmp;
+     static Tcl_HashTable *table = 0;
+     int tcl_ret;
+     
+     if ((tcl_ret = parse_flags(interp, table, krb5_flags_array,
+				sizeof(krb5_flags_array) /
+				sizeof(struct flagval),
+				str, &tmp)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     *flags = tmp;
+     return TCL_OK;
+}
+
+static Tcl_DString *unparse_aux_attributes(krb5_int32 flags)
+{
+     return unparse_flags(aux_attributes, sizeof(aux_attributes) /
+			  sizeof(struct flagval), flags);
+}
+
+
+static int parse_aux_attributes(Tcl_Interp *interp, char *str, long *flags)
+{
+     krb5_flags tmp;
+     static Tcl_HashTable *table = 0;
+     int tcl_ret;
+     
+     if ((tcl_ret = parse_flags(interp, table, aux_attributes,
+				sizeof(aux_attributes) /
+				sizeof(struct flagval),
+				str, &tmp)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     *flags = tmp;
+     return TCL_OK;
+}
+
+static int parse_principal_mask(Tcl_Interp *interp, char *str, krb5_int32 *flags)
+{
+     krb5_flags tmp;
+     static Tcl_HashTable *table = 0;
+     int tcl_ret;
+     
+     if ((tcl_ret = parse_flags(interp, table, principal_mask_flags,
+				sizeof(principal_mask_flags) /
+				sizeof(struct flagval),
+				str, &tmp)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     *flags = tmp;
+     return TCL_OK;
+}
+
+
+static int parse_policy_mask(Tcl_Interp *interp, char *str, krb5_int32 *flags)
+{
+     krb5_flags tmp;
+     static Tcl_HashTable *table = 0;
+     int tcl_ret;
+     
+     if ((tcl_ret = parse_flags(interp, table, policy_mask_flags,
+				sizeof(policy_mask_flags) /
+				sizeof(struct flagval),
+				str, &tmp)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     *flags = tmp;
+     return TCL_OK;
+}
+
+
+static Tcl_DString *unparse_principal_ent(ovsec_kadm_principal_ent_t princ)
+{
+     Tcl_DString *str, *tmp_dstring;
+     char *tmp;
+     char buf[20];
+     krb5_error_code krb5_ret;
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     tmp = 0; /* It looks to me from looking at the library source */
+	      /* code for krb5_parse_name that the pointer passed into */
+	      /* it should be initialized to 0 if I want it do be */
+	      /* allocated automatically. */
+     krb5_ret = krb5_unparse_name(context, princ->principal, &tmp);
+     if (krb5_ret) {
+	  /* XXX Do we want to return an error?  Not sure. */
+	  Tcl_DStringAppendElement(str, "[unparseable principal]");
+     }
+     else {
+	  Tcl_DStringAppendElement(str, tmp);
+	  free(tmp);
+     }
+
+     sprintf(buf, "%d", princ->princ_expire_time);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->last_pwd_change);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->pw_expiration);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->max_life);
+     Tcl_DStringAppendElement(str, buf);
+
+     tmp = 0;
+     krb5_ret = krb5_unparse_name(context, princ->mod_name, &tmp);
+     if (krb5_ret) {
+	  /* XXX */
+	  Tcl_DStringAppendElement(str, "[unparseable principal]");
+     }
+     else {
+	  Tcl_DStringAppendElement(str, tmp);
+	  free(tmp);
+     }
+
+     sprintf(buf, "%d", princ->mod_date);
+     Tcl_DStringAppendElement(str, buf);
+
+     tmp_dstring = unparse_krb5_flags(princ->attributes);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+
+     sprintf(buf, "%d", princ->kvno);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%d", princ->mkvno);
+     Tcl_DStringAppendElement(str, buf);
+
+     /* XXX This may be dangerous, because the contents of the policy */
+     /* field are undefined if the POLICY bit isn't set.  However, I */
+     /* think it's a bug for the field not to be null in that case */
+     /* anyway, so we should assume that it will be null so that we'll */
+     /* catch it if it isn't. */
+     
+     tmp_dstring = unparse_str(princ->policy);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+
+     tmp_dstring = unparse_aux_attributes(princ->aux_attributes);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+
+     return str;
+}
+
+     
+     
+static int parse_principal_ent(Tcl_Interp *interp, char *list,
+			       ovsec_kadm_principal_ent_t *out_princ)
+{
+     ovsec_kadm_principal_ent_t princ;
+     krb5_error_code krb5_ret;
+     int tcl_ret;
+     int argc;
+     char **argv;
+     int tmp;
+     int retcode = TCL_OK;
+
+     if ((tcl_ret = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     if (argc != 12) {
+	  sprintf(interp->result, "wrong # args in principal structure (%d should be 12)",
+		  argc);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if (! (princ = malloc(sizeof *princ))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+  
+     if ((krb5_ret = krb5_parse_name(context, argv[0], &princ->principal)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing principal");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     /*
+      * All of the numerical values parsed here are parsed into an
+      * "int" and then assigned into the structure in case the actual
+      * width of the field in the Kerberos structure is different from
+      * the width of an integer.
+      */
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[1], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing princ_expire_time");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->princ_expire_time = tmp;
+     
+     if ((tcl_ret = Tcl_GetInt(interp, argv[2], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing last_pwd_change");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->last_pwd_change = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[3], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_expiration");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->pw_expiration = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[4], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing max_life");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->max_life = tmp;
+
+     if ((krb5_ret = krb5_parse_name(context, argv[5], &princ->mod_name)) != 0) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing mod_name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+	  
+     if ((tcl_ret = Tcl_GetInt(interp, argv[6], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing mod_date");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->mod_date = tmp;
+
+     if ((tcl_ret = parse_krb5_flags(interp, argv[7], &princ->attributes))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing attributes");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[8], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing kvno");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->kvno = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[9], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing mkvno");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     princ->mkvno = tmp;
+
+     if ((tcl_ret = parse_str(interp, argv[10], &princ->policy)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     if(princ->policy != NULL) {
+	if(!(princ->policy = strdup(princ->policy))) {
+	    fprintf(stderr, "Out of memory!\n");
+	    exit(1);
+	}
+     }
+
+     if ((tcl_ret = parse_aux_attributes(interp, argv[11],
+					 &princ->aux_attributes)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing aux_attributes");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+finished:
+     Tcl_Free(argv);
+     *out_princ = princ;
+     return retcode;
+}
+
+
+static void free_principal_ent(ovsec_kadm_principal_ent_t *princ)
+{
+     krb5_free_principal(context, (*princ)->principal);
+     krb5_free_principal(context, (*princ)->mod_name);
+     free(*princ);
+     *princ = 0;
+}
+
+static Tcl_DString *unparse_policy_ent(ovsec_kadm_policy_ent_t policy)
+{
+     Tcl_DString *str, *tmp_dstring;
+     char buf[20];
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     tmp_dstring = unparse_str(policy->policy);
+     Tcl_DStringAppendElement(str, tmp_dstring->string);
+     Tcl_DStringFree(tmp_dstring);
+     free(tmp_dstring);
+     
+     sprintf(buf, "%ld", policy->pw_min_life);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->pw_max_life);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->pw_min_length);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->pw_min_classes);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->pw_history_num);
+     Tcl_DStringAppendElement(str, buf);
+
+     sprintf(buf, "%ld", policy->policy_refcnt);
+     Tcl_DStringAppendElement(str, buf);
+
+     return str;
+}
+
+     
+     
+static int parse_policy_ent(Tcl_Interp *interp, char *list,
+			    ovsec_kadm_policy_ent_t *out_policy)
+{
+     ovsec_kadm_policy_ent_t policy;
+     int tcl_ret;
+     int argc;
+     char **argv;
+     int tmp;
+     int retcode = TCL_OK;
+
+     if ((tcl_ret = Tcl_SplitList(interp, list, &argc, &argv)) != TCL_OK) {
+	  return tcl_ret;
+     }
+
+     if (argc != 7) {
+	  sprintf(interp->result, "wrong # args in policy structure (%d should be 7)",
+		  argc);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if (! (policy = malloc(sizeof *policy))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+  
+     if ((tcl_ret = parse_str(interp, argv[0], &policy->policy)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if(policy->policy != NULL) {
+	if (! (policy->policy = strdup(policy->policy))) {
+	    fprintf(stderr, "Out of memory!\n");
+	    exit(1); /* XXX */
+	}
+     }
+     
+     /*
+      * All of the numerical values parsed here are parsed into an
+      * "int" and then assigned into the structure in case the actual
+      * width of the field in the Kerberos structure is different from
+      * the width of an integer.
+      */
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[1], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_min_life");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_min_life = tmp;
+     
+     if ((tcl_ret = Tcl_GetInt(interp, argv[2], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_max_life");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_max_life = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[3], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_min_length");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_min_length = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[4], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_min_classes");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_min_classes = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[5], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_history_num");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->pw_history_num = tmp;
+
+     if ((tcl_ret = Tcl_GetInt(interp, argv[6], &tmp))
+	 != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy_refcnt");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     policy->policy_refcnt = tmp;
+
+finished:
+     Tcl_Free(argv);
+     *out_policy = policy;
+     return retcode;
+}
+
+
+static void free_policy_ent(ovsec_kadm_policy_ent_t *policy)
+{
+     free(*policy);
+     *policy = 0;
+}
+
+static Tcl_DString *unparse_keytype(krb5_enctype enctype)
+{
+     Tcl_DString *str;
+     char buf[50];
+
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     switch (enctype) {
+	  /* XXX is this right? */
+     case ENCTYPE_NULL: Tcl_DStringAppend(str, "ENCTYPE_NULL", -1); break;
+     case ENCTYPE_DES_CBC_CRC:
+	  Tcl_DStringAppend(str, "ENCTYPE_DES_CBC_CRC", -1); break;
+     default:
+	  sprintf(buf, "UNKNOWN KEYTYPE (0x%x)", enctype);
+	  Tcl_DStringAppend(str, buf, -1);
+	  break;
+     }
+
+     return str;
+}
+	  
+	  
+static Tcl_DString *unparse_keyblock(krb5_keyblock *keyblock)
+{
+     Tcl_DString *str;
+     Tcl_DString *keytype;
+     int i;
+     
+     if (! (str = malloc(sizeof(*str)))) {
+	  fprintf(stderr, "Out of memory!\n");
+	  exit(1); /* XXX */
+     }
+
+     Tcl_DStringInit(str);
+
+     keytype = unparse_keytype(keyblock->enctype);
+     Tcl_DStringAppendElement(str, keytype->string);
+     Tcl_DStringFree(keytype);
+     free(keytype);
+     if (keyblock->length == 0) {
+	  Tcl_DStringAppendElement(str, "0x00");
+     }
+     else {
+	  Tcl_DStringAppendElement(str, "0x");
+	  for (i = 0; i < keyblock->length; i++) {
+	       char buf[3];
+	       sprintf(buf, "%02x", (int) keyblock->contents[i]);
+	       Tcl_DStringAppend(str, buf, -1);
+	  }
+     }
+
+     return str;
+}
+
+
+
+static int tcl_ovsec_kadm_init(ClientData clientData, Tcl_Interp *interp,
+			       int argc, char *argv[])
+{
+     ovsec_kadm_ret_t ret;
+     char *client_name, *pass, *service_name, *realm;
+     int tcl_ret;
+     krb5_ui_4 struct_version, api_version;
+     char *handle_var;
+     void *server_handle;
+     char *handle_name;
+     char *whoami = argv[0];
+
+     argv++, argc--;
+
+     krb5_init_context(&context);
+
+     if (argc != 7) {
+	  Tcl_AppendResult(interp, whoami, ": ", arg_error, 0);
+	  return TCL_ERROR;
+     }
+
+     if (((tcl_ret = parse_str(interp, argv[0], &client_name)) != TCL_OK) ||
+	 ((tcl_ret = parse_str(interp, argv[1], &pass)) != TCL_OK) ||
+	 ((tcl_ret = parse_str(interp, argv[2], &service_name)) != TCL_OK) ||
+	 ((tcl_ret = parse_str(interp, argv[3], &realm)) != TCL_OK) ||
+	 ((tcl_ret = Tcl_GetInt(interp, argv[4], (int *) &struct_version)) !=
+	  TCL_OK) ||
+	 ((tcl_ret = Tcl_GetInt(interp, argv[5], (int *) &api_version)) !=
+	  TCL_OK)) {
+	  return tcl_ret;
+     }
+
+     handle_var = argv[6];
+
+     if (! (handle_var && *handle_var)) {
+	 Tcl_SetResult(interp, "must specify server handle variable name",
+		       TCL_STATIC);
+	 return TCL_ERROR;
+     }
+     
+     ret = ovsec_kadm_init(client_name, pass, service_name, realm,
+			   struct_version, api_version, NULL, &server_handle);
+
+     if (ret != OVSEC_KADM_OK) {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+
+     if ((tcl_ret = put_server_handle(interp, server_handle, &handle_name))
+	 != TCL_OK) {
+	 return tcl_ret;
+     }
+     
+     if (! Tcl_SetVar(interp, handle_var, handle_name, TCL_LEAVE_ERR_MSG)) {
+	 return TCL_ERROR;
+     }
+     
+     set_ok(interp, "OV Admin system initialized.");
+     return TCL_OK;
+}
+
+
+
+static int tcl_ovsec_kadm_destroy(ClientData clientData, Tcl_Interp *interp,
+				  int argc, char *argv[])
+{
+     ovsec_kadm_ret_t ret;
+     int tcl_ret;
+
+     GET_HANDLE(0, 0);
+
+     ret = ovsec_kadm_destroy(server_handle);
+
+     if (ret != OVSEC_KADM_OK) {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+
+     if ((tcl_ret = remove_server_handle(interp, argv[-1])) != TCL_OK) {
+	 return tcl_ret;
+     }
+     
+     set_ok(interp, "OV Admin system deinitialized.");
+     return TCL_OK;
+}	  
+
+static int tcl_ovsec_kadm_create_principal(ClientData clientData, 
+					   Tcl_Interp *interp,
+					   int argc, char *argv[])
+{
+     int tcl_ret;
+     ovsec_kadm_ret_t ret;
+     int retcode = TCL_OK;
+     char *princ_string;
+     ovsec_kadm_principal_ent_t princ = 0;
+     krb5_int32 mask;
+     char *pw;
+#ifdef OVERRIDE     
+     int override_qual;
+#endif     
+
+     GET_HANDLE(3, 0);
+
+     if ((tcl_ret = parse_str(interp, argv[0], &princ_string)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing principal");
+	  return tcl_ret;
+     }
+
+     if (princ_string &&
+	 ((tcl_ret = parse_principal_ent(interp, princ_string, &princ))
+	  != TCL_OK)) {
+	  return tcl_ret;
+     }
+
+     if ((tcl_ret = parse_principal_mask(interp, argv[1], &mask)) != TCL_OK) {
+	  retcode = tcl_ret;
+	  goto finished;
+     }
+
+     if ((tcl_ret = parse_str(interp, argv[2], &pw)) != TCL_OK) {
+	  retcode = tcl_ret;
+	  goto finished;
+     }
+#ifdef OVERRIDE
+     if ((tcl_ret = Tcl_GetBoolean(interp, argv[3], &override_qual)) !=
+	 TCL_OK) {
+	  retcode = tcl_ret;
+	  goto finished;
+     }
+#endif     
+
+#ifdef OVERRIDE
+     ret = ovsec_kadm_create_principal(server_handle, princ, mask, pw,
+				       override_qual);
+#else
+     ret = ovsec_kadm_create_principal(server_handle, princ, mask, pw);
+#endif     
+
+     if (ret != OVSEC_KADM_OK) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     else {
+	  set_ok(interp, "Principal created.");
+     }
+
+finished:
+     if (princ) {
+	  free_principal_ent(&princ);
+     }
+     return retcode;
+}
+
+
+
+static int tcl_ovsec_kadm_delete_principal(ClientData clientData, 
+					   Tcl_Interp *interp,
+					   int argc, char *argv[])
+{
+     krb5_principal princ;
+     krb5_error_code krb5_ret;
+     ovsec_kadm_ret_t ret;
+     int tcl_ret;
+     char *name;
+     
+     GET_HANDLE(1, 0);
+
+     if((tcl_ret = parse_str(interp, argv[0], &name)) != TCL_OK)
+	return tcl_ret;
+     if(name != NULL) {
+        krb5_ret = krb5_parse_name(context, name, &princ);
+	if (krb5_ret) {
+	    stash_error(interp, krb5_ret);
+	    Tcl_AppendElement(interp, "while parsing principal");
+	    return TCL_ERROR;
+	}
+     } else princ = NULL;
+     ret = ovsec_kadm_delete_principal(server_handle, princ);
+
+     if(princ != NULL) 
+	krb5_free_principal(context, princ);
+
+     if (ret != OVSEC_KADM_OK) {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+     else {
+	  set_ok(interp, "Principal deleted.");
+	  return TCL_OK;
+     }
+}
+
+
+
+static int tcl_ovsec_kadm_modify_principal(ClientData clientData, 
+					   Tcl_Interp *interp,
+					   int argc, char *argv[])
+{
+     char *princ_string;
+     ovsec_kadm_principal_ent_t princ = 0;
+     int tcl_ret;
+     krb5_int32 mask;
+     int retcode = TCL_OK;
+     ovsec_kadm_ret_t ret;
+
+     GET_HANDLE(2, 0);
+
+     if ((tcl_ret = parse_str(interp, argv[0], &princ_string)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing principal");
+	  return tcl_ret;
+     }
+
+     if (princ_string &&
+	 ((tcl_ret = parse_principal_ent(interp, princ_string, &princ))
+	  != TCL_OK)) {
+	  return tcl_ret;
+     }
+     
+     if ((tcl_ret = parse_principal_mask(interp, argv[1], &mask)) != TCL_OK) {
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     ret = ovsec_kadm_modify_principal(server_handle, princ, mask);
+
+     if (ret != OVSEC_KADM_OK) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+     else {
+	  set_ok(interp, "Principal modified.");
+     }
+
+finished:
+     if (princ) {
+	  free_principal_ent(&princ);
+     }
+     return retcode;
+}
+
+
+static int tcl_ovsec_kadm_rename_principal(ClientData clientData,
+					   Tcl_Interp *interp,
+					   int argc, char *argv[])
+{
+     krb5_principal source, target;
+     krb5_error_code krb5_ret;
+     ovsec_kadm_ret_t ret;
+     int retcode = TCL_OK;
+
+     GET_HANDLE(2, 0);
+
+     krb5_ret = krb5_parse_name(context, argv[0], &source);
+     if (krb5_ret) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing source");
+	  return TCL_ERROR;
+     }
+
+     krb5_ret = krb5_parse_name(context, argv[1], &target);
+     if (krb5_ret) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing target");
+	  krb5_free_principal(context, source);
+	  return TCL_ERROR;
+     }
+
+     ret = ovsec_kadm_rename_principal(server_handle, source, target);
+
+     if (ret == OVSEC_KADM_OK) {
+	  set_ok(interp, "Principal renamed.");
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+     krb5_free_principal(context, source);
+     krb5_free_principal(context, target);
+     return retcode;
+}
+
+
+	  
+static int tcl_ovsec_kadm_chpass_principal(ClientData clientData, 
+					   Tcl_Interp *interp,
+					   int argc, char *argv[])
+{
+     krb5_principal princ;
+     char *pw;
+#ifdef OVERRIDE     
+     int override_qual;
+#endif     
+     krb5_error_code krb5_ret;
+     int retcode = TCL_OK;
+     ovsec_kadm_ret_t ret;
+
+     GET_HANDLE(2, 0);
+
+     krb5_ret = krb5_parse_name(context, argv[0], &princ);
+     if (krb5_ret) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing principal name");
+	  return TCL_ERROR;
+     }
+
+     if (parse_str(interp, argv[1], &pw) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing password");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+#ifdef OVERRIDE
+     if (Tcl_GetBoolean(interp, argv[2], &override_qual) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing override_qual");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     
+     ret = ovsec_kadm_chpass_principal(server_handle,
+				       princ, pw, override_qual);
+#else
+     ret = ovsec_kadm_chpass_principal(server_handle, princ, pw);
+#endif     
+
+     if (ret == OVSEC_KADM_OK) {
+	  set_ok(interp, "Password changed.");
+	  goto finished;
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     krb5_free_principal(context, princ);
+     return retcode;
+}
+
+
+
+static int tcl_ovsec_kadm_chpass_principal_util(ClientData clientData,
+						Tcl_Interp *interp,
+						int argc, char *argv[])
+{
+     krb5_principal princ;
+     char *new_pw;
+#ifdef OVERRIDE     
+     int override_qual;
+#endif     
+     char *pw_ret, *pw_ret_var;
+     char msg_ret[1024], *msg_ret_var;
+     krb5_error_code krb5_ret;
+     ovsec_kadm_ret_t ret;
+     int retcode = TCL_OK;
+
+     GET_HANDLE(4, 0);
+
+     if ((krb5_ret = krb5_parse_name(context, argv[0], &princ))) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing principal name");
+	  return TCL_ERROR;
+     }
+
+     if (parse_str(interp, argv[1], &new_pw) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing new password");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+#ifdef OVERRIDE
+     if (Tcl_GetBoolean(interp, argv[2], &override_qual) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing override_qual");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+#endif
+     if (parse_str(interp, argv[3], &pw_ret_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing pw_ret variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     if (parse_str(interp, argv[4], &msg_ret_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing msg_ret variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     ret = ovsec_kadm_chpass_principal_util(server_handle, princ, new_pw,
+#ifdef OVERRIDE     
+					    override_qual,
+#endif					    
+					    pw_ret_var ? &pw_ret : 0,
+					    msg_ret_var ? msg_ret : 0);
+
+     if (ret == OVSEC_KADM_OK) {
+	  if (pw_ret_var &&
+	      (! Tcl_SetVar(interp, pw_ret_var, pw_ret,
+			    TCL_LEAVE_ERR_MSG))) {
+	       Tcl_AppendElement(interp, "while setting pw_ret variable");
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  if (msg_ret_var &&
+	      (! Tcl_SetVar(interp, msg_ret_var, msg_ret,
+			    TCL_LEAVE_ERR_MSG))) {
+	       Tcl_AppendElement(interp,
+				 "while setting msg_ret variable");
+	       retcode = TCL_ERROR;
+	       goto finished;
+	  }
+	  set_ok(interp, "Password changed.");
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     krb5_free_principal(context, princ);
+     return retcode;
+}
+
+
+
+static int tcl_ovsec_kadm_randkey_principal(ClientData clientData,
+					    Tcl_Interp *interp,
+					    int argc, char *argv[])
+{
+     krb5_principal princ;
+     krb5_keyblock *keyblock;
+     char *keyblock_var;
+     Tcl_DString *keyblock_dstring = 0;
+#ifdef OVERRIDE     
+     int override_qual;
+#endif     
+     krb5_error_code krb5_ret;
+     ovsec_kadm_ret_t ret;
+     int retcode = TCL_OK;
+
+     GET_HANDLE(2, 0);
+
+     if ((krb5_ret = krb5_parse_name(context, argv[0], &princ))) {
+	  stash_error(interp, krb5_ret);
+	  Tcl_AppendElement(interp, "while parsing principal name");
+	  return TCL_ERROR;
+     }
+
+     if (parse_str(interp, argv[1], &keyblock_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing keyblock variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+#ifdef OVERRIDE
+     if (Tcl_GetBoolean(interp, argv[2], &override_qual) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing override_qual");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     ret = ovsec_kadm_randkey_principal(server_handle,
+					princ, keyblock_var ? &keyblock : 0,
+					override_qual);
+#else
+     ret = ovsec_kadm_randkey_principal(server_handle,
+					princ, keyblock_var ? &keyblock : 0);
+#endif					
+
+     if (ret == OVSEC_KADM_OK) {
+	  if (keyblock_var) {
+	       keyblock_dstring = unparse_keyblock(keyblock);
+	       if (! Tcl_SetVar(interp, keyblock_var,
+				keyblock_dstring->string,
+				TCL_LEAVE_ERR_MSG)) {
+		    Tcl_AppendElement(interp,
+				      "while setting keyblock variable");
+		    retcode = TCL_ERROR;
+		    goto finished;
+	       }
+	  }
+	  set_ok(interp, "Key randomized.");
+	  
+     }
+     else {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     krb5_free_principal(context, princ);
+     if (keyblock_dstring) {
+	  Tcl_DStringFree(keyblock_dstring);
+	  free(keyblock_dstring);
+     }
+     return retcode;
+}
+
+
+
+static int tcl_ovsec_kadm_get_principal(ClientData clientData,
+					Tcl_Interp *interp,
+					int argc, char *argv[])
+{
+     krb5_principal princ;
+     ovsec_kadm_principal_ent_t ent;
+     Tcl_DString *ent_dstring = 0;
+     char *ent_var;
+     char *name;
+     krb5_error_code krb5_ret;
+     int tcl_ret;
+     ovsec_kadm_ret_t ret;
+     int retcode = TCL_OK;
+     
+     GET_HANDLE(2, 1);
+
+     if((tcl_ret = parse_str(interp, argv[0], &name)) != TCL_OK)
+	return tcl_ret;
+     if(name != NULL) {
+	if ((krb5_ret = krb5_parse_name(context, name, &princ))) {
+	    stash_error(interp, krb5_ret);
+	    Tcl_AppendElement(interp, "while parsing principal name");
+	    return TCL_ERROR;
+	}
+     } else princ = NULL;
+
+     if ((tcl_ret = parse_str(interp, argv[1], &ent_var)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing entry variable name");
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     
+     ret = ovsec_kadm_get_principal(server_handle, princ, ent_var ? &ent : 0);
+
+     if (ret == OVSEC_KADM_OK) {
+	  if (ent_var) {
+	       if (dostruct) {
+		    char buf[20];
+		    int i = 1, newPtr = 0;
+		    Tcl_HashEntry *entry;
+		    
+		    if (! struct_table) {
+			 if (! (struct_table =
+				malloc(sizeof(*struct_table)))) {
+			      fprintf(stderr, "Out of memory!\n");
+			      exit(1); /* XXX */
+			 }
+			 Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+		    }
+
+		    do {
+			 sprintf(buf, "principal%d", i);
+			 entry = Tcl_CreateHashEntry(struct_table, buf,
+						     &newPtr);
+			 i++;
+		    } while (! newPtr);
+
+		    Tcl_SetHashValue(entry, ent);
+		    if (! Tcl_SetVar(interp, ent_var, buf,
+				     TCL_LEAVE_ERR_MSG)) {
+			 Tcl_AppendElement(interp,
+					   "while setting entry variable");
+			 Tcl_DeleteHashEntry(entry);
+			 retcode = TCL_ERROR;
+			 goto finished;
+		    }
+		    set_ok(interp, "Principal structure retrieved.");
+	       }
+	       else {
+		    ent_dstring = unparse_principal_ent(ent);
+		    if (! Tcl_SetVar(interp, ent_var, ent_dstring->string,
+				     TCL_LEAVE_ERR_MSG)) {
+			 Tcl_AppendElement(interp,
+					   "while setting entry variable");
+			 retcode = TCL_ERROR;
+			 goto finished;
+		    }
+		    set_ok(interp, "Principal retrieved.");
+	       }
+	  }
+     }
+     else {
+	  ent = 0;
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     if (ent_dstring) {
+	  Tcl_DStringFree(ent_dstring);
+	  free(ent_dstring);
+     }
+     if(princ != NULL)
+	krb5_free_principal(context, princ);
+     if (ent && ((! dostruct) || (retcode != TCL_OK))) {
+	 if ((ret = ovsec_kadm_free_principal_ent(server_handle, ent)) &&
+	     (retcode == TCL_OK)) {
+	     stash_error(interp, ret);
+	     retcode = TCL_ERROR;
+	 }
+     }
+     return retcode;
+}
+     
+static int tcl_ovsec_kadm_create_policy(ClientData clientData,
+					Tcl_Interp *interp,
+					int argc, char *argv[])
+{
+     int tcl_ret;
+     ovsec_kadm_ret_t ret;
+     int retcode = TCL_OK;
+     char *policy_string;
+     ovsec_kadm_policy_ent_t policy = 0;
+     krb5_int32 mask;
+
+     GET_HANDLE(2, 0);
+
+     if ((tcl_ret = parse_str(interp, argv[0], &policy_string)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy");
+	  return tcl_ret;
+     }
+
+     if (policy_string &&
+	 ((tcl_ret = parse_policy_ent(interp, policy_string, &policy))
+	  != TCL_OK)) {
+	  return tcl_ret;
+     }
+
+     if ((tcl_ret = parse_policy_mask(interp, argv[1], &mask)) != TCL_OK) {
+	  retcode = tcl_ret;
+	  goto finished;
+     }
+
+     ret = ovsec_kadm_create_policy(server_handle, policy, mask);
+
+     if (ret != OVSEC_KADM_OK) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+     else {
+	  set_ok(interp, "Policy created.");
+     }
+
+finished:
+     if (policy) {
+	  free_policy_ent(&policy);
+     }
+     return retcode;
+}
+
+
+
+static int tcl_ovsec_kadm_delete_policy(ClientData clientData,
+					Tcl_Interp *interp,
+					int argc, char *argv[])
+{
+     ovsec_kadm_ret_t ret;
+     char *policy;
+
+     GET_HANDLE(1, 0);
+
+     if (parse_str(interp, argv[0], &policy) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy name");
+	  return TCL_ERROR;
+     }
+     
+     ret = ovsec_kadm_delete_policy(server_handle, policy);
+
+     if (ret != OVSEC_KADM_OK) {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+     else {
+	  set_ok(interp, "Policy deleted.");
+	  return TCL_OK;
+     }
+}
+
+
+
+static int tcl_ovsec_kadm_modify_policy(ClientData clientData,
+					Tcl_Interp *interp,
+					int argc, char *argv[])
+{
+     char *policy_string;
+     ovsec_kadm_policy_ent_t policy = 0;
+     int tcl_ret;
+     krb5_int32 mask;
+     int retcode = TCL_OK;
+     ovsec_kadm_ret_t ret;
+
+     GET_HANDLE(2, 0);
+
+     if ((tcl_ret = parse_str(interp, argv[0], &policy_string)) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy");
+	  return tcl_ret;
+     }
+
+     if (policy_string &&
+	 ((tcl_ret = parse_policy_ent(interp, policy_string, &policy))
+	  != TCL_OK)) {
+	  return tcl_ret;
+     }
+
+     if ((tcl_ret = parse_policy_mask(interp, argv[1], &mask)) != TCL_OK) {
+	  retcode = TCL_ERROR;
+	  goto finished;
+     }
+
+     ret = ovsec_kadm_modify_policy(server_handle, policy, mask);
+
+     if (ret != OVSEC_KADM_OK) {
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+     else {
+	  set_ok(interp, "Policy modified.");
+     }
+
+finished:
+     if (policy) {
+	  free_policy_ent(&policy);
+     }
+     return retcode;
+}
+
+
+static int tcl_ovsec_kadm_get_policy(ClientData clientData,
+				     Tcl_Interp *interp,
+				     int argc, char *argv[])
+{
+     ovsec_kadm_policy_ent_t ent;
+     Tcl_DString *ent_dstring = 0;
+     char *policy;
+     char *ent_var;
+     ovsec_kadm_ret_t ret;
+     int retcode = TCL_OK;
+
+     GET_HANDLE(2, 1);
+
+     if (parse_str(interp, argv[0], &policy) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing policy name");
+	  return TCL_ERROR;
+     }
+     
+     if (parse_str(interp, argv[1], &ent_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing entry variable name");
+	  return TCL_ERROR;
+     }
+     
+     ret = ovsec_kadm_get_policy(server_handle, policy, ent_var ? &ent : 0);
+
+     if (ret == OVSEC_KADM_OK) {
+	  if (ent_var) {
+	       if (dostruct) {
+		    char buf[20];
+		    int i = 1, newPtr = 0;
+		    Tcl_HashEntry *entry;
+		    
+		    if (! struct_table) {
+			 if (! (struct_table =
+				malloc(sizeof(*struct_table)))) {
+			      fprintf(stderr, "Out of memory!\n");
+			      exit(1); /* XXX */
+			 }
+			 Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+		    }
+
+		    do {
+			 sprintf(buf, "policy%d", i);
+			 entry = Tcl_CreateHashEntry(struct_table, buf,
+						     &newPtr);
+			 i++;
+		    } while (! newPtr);
+
+		    Tcl_SetHashValue(entry, ent);
+		    if (! Tcl_SetVar(interp, ent_var, buf,
+				     TCL_LEAVE_ERR_MSG)) {
+			 Tcl_AppendElement(interp,
+					   "while setting entry variable");
+			 Tcl_DeleteHashEntry(entry);
+			 retcode = TCL_ERROR;
+			 goto finished;
+		    }
+		    set_ok(interp, "Policy structure retrieved.");
+	       }
+	       else {
+		    ent_dstring = unparse_policy_ent(ent);
+		    if (! Tcl_SetVar(interp, ent_var, ent_dstring->string,
+				     TCL_LEAVE_ERR_MSG)) {
+			 Tcl_AppendElement(interp,
+					   "while setting entry variable");
+			 retcode = TCL_ERROR;
+			 goto finished;
+		    }
+		    set_ok(interp, "Policy retrieved.");
+	       }
+	  }
+     }
+     else {
+	  ent = 0;
+	  stash_error(interp, ret);
+	  retcode = TCL_ERROR;
+     }
+
+finished:
+     if (ent_dstring) {
+	  Tcl_DStringFree(ent_dstring);
+	  free(ent_dstring);
+     }
+     if (ent && ((! dostruct) || (retcode != TCL_OK))) {
+	 if ((ret = ovsec_kadm_free_policy_ent(server_handle, ent)) &&
+	     (retcode == TCL_OK)) {
+	     stash_error(interp, ret);
+	     retcode = TCL_ERROR;
+	 }
+     }
+     return retcode;
+}
+
+     
+     
+static int tcl_ovsec_kadm_free_principal_ent(ClientData clientData,
+					     Tcl_Interp *interp,
+					     int argc, char *argv[])
+{
+     char *ent_name;
+     ovsec_kadm_principal_ent_t ent;
+     ovsec_kadm_ret_t ret;
+
+     GET_HANDLE(1, 0);
+
+     if (parse_str(interp, argv[0], &ent_name) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing entry name");
+	  return TCL_ERROR;
+     }
+
+     if ((! ent_name) &&
+	 (ret = ovsec_kadm_free_principal_ent(server_handle, 0))) {
+	 stash_error(interp, ret);
+	 return TCL_ERROR;
+     }
+     else {
+	  Tcl_HashEntry *entry;
+
+	  if (strncmp(ent_name, "principal", sizeof("principal")-1)) {
+	       Tcl_AppendResult(interp, "invalid principal handle \"",
+				ent_name, "\"", 0);
+	       return TCL_ERROR;
+	  }
+	  if (! struct_table) {
+	       if (! (struct_table = malloc(sizeof(*struct_table)))) {
+		    fprintf(stderr, "Out of memory!\n");
+		    exit(1); /* XXX */
+	       }
+	       Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+	  }
+	  
+	  if (! (entry = Tcl_FindHashEntry(struct_table, ent_name))) {
+	       Tcl_AppendResult(interp, "principal handle \"", ent_name,
+				"\" not found", 0);
+	       return TCL_ERROR;
+	  }
+
+	  ent = (ovsec_kadm_principal_ent_t) Tcl_GetHashValue(entry);
+
+	  if ((ret = ovsec_kadm_free_principal_ent(server_handle, ent))) {
+	      stash_error(interp, ret);
+	      return TCL_ERROR;
+	  }
+	  Tcl_DeleteHashEntry(entry);
+     }
+     set_ok(interp, "Principal freed.");
+     return TCL_OK;
+}
+	  
+		    
+static int tcl_ovsec_kadm_free_policy_ent(ClientData clientData,
+					  Tcl_Interp *interp,
+					  int argc, char *argv[])
+{
+     char *ent_name;
+     ovsec_kadm_policy_ent_t ent;
+     ovsec_kadm_ret_t ret;
+
+     GET_HANDLE(1, 0);
+
+     if (parse_str(interp, argv[0], &ent_name) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing entry name");
+	  return TCL_ERROR;
+     }
+
+     if ((! ent_name) &&
+	 (ret = ovsec_kadm_free_policy_ent(server_handle, 0))) {
+	 stash_error(interp, ret);
+	 return TCL_ERROR;
+     }
+     else {
+	  Tcl_HashEntry *entry;
+
+	  if (strncmp(ent_name, "policy", sizeof("policy")-1)) {
+	       Tcl_AppendResult(interp, "invalid principal handle \"",
+				ent_name, "\"", 0);
+	       return TCL_ERROR;
+	  }
+	  if (! struct_table) {
+	       if (! (struct_table = malloc(sizeof(*struct_table)))) {
+		    fprintf(stderr, "Out of memory!\n");
+		    exit(1); /* XXX */
+	       }
+	       Tcl_InitHashTable(struct_table, TCL_STRING_KEYS);
+	  }
+	  
+	  if (! (entry = Tcl_FindHashEntry(struct_table, ent_name))) {
+	       Tcl_AppendResult(interp, "policy handle \"", ent_name,
+				"\" not found", 0);
+	       return TCL_ERROR;
+	  }
+
+	  ent = (ovsec_kadm_policy_ent_t) Tcl_GetHashValue(entry);
+
+	  if ((ret = ovsec_kadm_free_policy_ent(server_handle, ent))) {
+	      stash_error(interp, ret);
+	      return TCL_ERROR;
+	  }
+	  Tcl_DeleteHashEntry(entry);
+     }
+     set_ok(interp, "Policy freed.");
+     return TCL_OK;
+}
+	  
+		    
+static int tcl_ovsec_kadm_get_privs(ClientData clientData, Tcl_Interp *interp,
+				    int argc, char *argv[])
+{
+     char *set_ret;
+     ovsec_kadm_ret_t ret;
+     char *priv_var;
+     long privs;
+
+     GET_HANDLE(1, 0);
+
+     if (parse_str(interp, argv[0], &priv_var) != TCL_OK) {
+	  Tcl_AppendElement(interp, "while parsing privs variable name");
+	  return TCL_ERROR;
+     }
+
+     ret = ovsec_kadm_get_privs(server_handle, priv_var ? &privs : 0);
+
+     if (ret == OVSEC_KADM_OK) {
+	  if (priv_var) {
+	       Tcl_DString *str = unparse_privs(privs);
+	       set_ret = Tcl_SetVar(interp, priv_var, str->string,
+				    TCL_LEAVE_ERR_MSG);
+	       Tcl_DStringFree(str);
+	       free(str);
+	       if (! set_ret) {
+		    Tcl_AppendElement(interp, "while setting priv variable");
+		    return TCL_ERROR;
+	       }
+	  }
+	  set_ok(interp, "Privileges retrieved.");
+	  return TCL_OK;
+     }
+     else {
+	  stash_error(interp, ret);
+	  return TCL_ERROR;
+     }
+}
+		    
+
+void Tcl_ovsec_kadm_init(Tcl_Interp *interp)
+{
+    char buf[20];
+
+     Tcl_SetVar(interp, "OVSEC_KADM_ADMIN_SERVICE",
+		OVSEC_KADM_ADMIN_SERVICE, TCL_GLOBAL_ONLY);
+     Tcl_SetVar(interp, "OVSEC_KADM_CHANGEPW_SERVICE",
+		OVSEC_KADM_CHANGEPW_SERVICE, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", OVSEC_KADM_STRUCT_VERSION);
+     Tcl_SetVar(interp, "OVSEC_KADM_STRUCT_VERSION", buf, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", OVSEC_KADM_API_VERSION_1);
+     Tcl_SetVar(interp, "OVSEC_KADM_API_VERSION_1", buf, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", OVSEC_KADM_API_VERSION_MASK);
+     Tcl_SetVar(interp, "OVSEC_KADM_API_VERSION_MASK", buf, TCL_GLOBAL_ONLY);
+    (void) sprintf(buf, "%d", OVSEC_KADM_STRUCT_VERSION_MASK);
+     Tcl_SetVar(interp, "OVSEC_KADM_STRUCT_VERSION_MASK", buf,
+		TCL_GLOBAL_ONLY);
+
+     Tcl_CreateCommand(interp, "ovsec_kadm_init", tcl_ovsec_kadm_init, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_destroy", tcl_ovsec_kadm_destroy, 0,
+		       0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_create_principal",
+		       tcl_ovsec_kadm_create_principal, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_delete_principal",
+		       tcl_ovsec_kadm_delete_principal, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_modify_principal",
+		       tcl_ovsec_kadm_modify_principal, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_rename_principal",
+		       tcl_ovsec_kadm_rename_principal, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_chpass_principal",
+		       tcl_ovsec_kadm_chpass_principal, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_chpass_principal_util",
+		       tcl_ovsec_kadm_chpass_principal_util, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_randkey_principal",
+		       tcl_ovsec_kadm_randkey_principal, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_get_principal",
+		       tcl_ovsec_kadm_get_principal, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_create_policy",
+		       tcl_ovsec_kadm_create_policy, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_delete_policy",
+		       tcl_ovsec_kadm_delete_policy, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_modify_policy",
+		       tcl_ovsec_kadm_modify_policy, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_get_policy",
+		       tcl_ovsec_kadm_get_policy, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_free_principal_ent",
+		       tcl_ovsec_kadm_free_principal_ent, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_free_policy_ent",
+		       tcl_ovsec_kadm_free_policy_ent, 0, 0);
+     Tcl_CreateCommand(interp, "ovsec_kadm_get_privs",
+		       tcl_ovsec_kadm_get_privs, 0, 0);
+}
diff --git a/mechglue/src/kadmin/testing/util/tcl_ovsec_kadm_syntax b/mechglue/src/kadmin/testing/util/tcl_ovsec_kadm_syntax
new file mode 100644
index 000000000..3fc77fbcb
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/tcl_ovsec_kadm_syntax
@@ -0,0 +1,57 @@
+Here's a brief summary of the syntax of the tcl versions of the
+ovsec_kadm commands:
+
+string		Can be a string or "null" which will turn into a null pointer
+principal_ent	A 12-field list in the order of the principal_ent
+		structure: {string number number number number string
+			    number mask number number string mask}
+		It can also be "null", like a string, to indicate that
+		a null structure pointer should be used.
+mask		Either a number, representing the actual value of the
+		mask, or a sequence of symbols in a list.  Example:
+		{PRINCIPAL ATTRIBUTES} is a valid principal mask.
+boolean		"1", "0", "true", "false", etc.
+varname		The name of a Tcl variable, or "null" to not assign.
+policy_ent	Similar to principal_ent, but with seven fields,
+		instead of 12.  The first is a string, and the rest
+		are numbers.
+
+init
+		client_name:string pass:string service_name:string
+		realm:string struct_version:int api_version:int
+		server_handle_ret:varname
+destroy
+		server_handle:string
+create_principal
+		server_handle:string principal:principal_ent
+		mask:principal_mask password:string
+delete_principal
+		server_handle:string name:string
+modify_principal
+		server_handle:string principal_principal_ent
+		mask:principal_mask
+rename_principal
+		server_handle:string source:string target:string
+chpass_principal
+		server_handle:string name:string password:string
+chpass_principal_util
+		server_handle:string name:string password:string
+		pw_ret:varname msg_ret:varname
+randkey_principal
+		server_handle:string name:string keyblock_var:varname
+get_principal [-struct]
+		server_handle:string name:string princ_var:varname
+create_policy
+		server_handle:string policy:policy_ent mask:policy_mask
+delete_policy
+		server_handle:string name:string
+modify_policy
+		server_handle:string policy:policy_ent mask:policy_mask
+get_policy [-struct]
+		server_handle:string name:string policy_var:varname
+free_principal_ent
+		server_handle:string handle:string
+free_policy_ent
+		server_handle:string handle:string
+get_privs
+		server_handle:string privs:priv_var
diff --git a/mechglue/src/kadmin/testing/util/test.c b/mechglue/src/kadmin/testing/util/test.c
new file mode 100644
index 000000000..dabd927d0
--- /dev/null
+++ b/mechglue/src/kadmin/testing/util/test.c
@@ -0,0 +1,37 @@
+#if HAVE_TCL_H
+#include <tcl.h>
+#elif HAVE_TCL_TCL_H
+#include <tcl/tcl.h>
+#endif
+#include "tcl_kadm5.h"
+
+#define _TCL_MAIN ((TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 704)
+
+#if _TCL_MAIN
+int
+main(argc, argv)
+    int argc;			/* Number of command-line arguments. */
+    char **argv;		/* Values of command-line arguments. */
+{
+    Tcl_Main(argc, argv, Tcl_AppInit);
+    return 0;			/* Needed only to prevent compiler warning. */
+}
+#else
+/*
+ * The following variable is a special hack that allows applications
+ * to be linked using the procedure "main" from the Tcl library.  The
+ * variable generates a reference to "main", which causes main to
+ * be brought in from the library (and all of Tcl with it).
+ */
+
+extern int main();
+int *tclDummyMainPtr = (int *) main;
+#endif
+
+int Tcl_AppInit(Tcl_Interp *interp)
+{
+     Tcl_ovsec_kadm_init(interp);
+     Tcl_kadm5_init(interp);
+
+     return(TCL_OK);
+}
diff --git a/mechglue/src/kdc/.Sanitize b/mechglue/src/kdc/.Sanitize
new file mode 100644
index 000000000..ad970fa3c
--- /dev/null
+++ b/mechglue/src/kdc/.Sanitize
@@ -0,0 +1,58 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+.saberinit
+ChangeLog
+Makefile.in
+configure
+configure.in
+dispatch.c
+do_as_req.c
+do_tgs_req.c
+extern.c
+extern.h
+kdc5_err.et
+kdc_preauth.c
+kdc_util.c
+kdc_util.h
+kerberos_v4.c
+krb5kdc.M
+main.c
+migration.doc
+network.c
+policy.c
+policy.h
+replay.c
+rtest.c
+rtest.good
+rtscript
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/kdc/.rconf b/mechglue/src/kdc/.rconf
new file mode 100644
index 000000000..ae50e63d8
--- /dev/null
+++ b/mechglue/src/kdc/.rconf
@@ -0,0 +1,5 @@
+ignore rtest.c
+ignore rtscript
+ignore .saberinit
+ignore don.log
+ignore rtest.good
diff --git a/mechglue/src/kdc/.saberinit b/mechglue/src/kdc/.saberinit
new file mode 100644
index 000000000..d79f57ed0
--- /dev/null
+++ b/mechglue/src/kdc/.saberinit
@@ -0,0 +1,35 @@
+suppress 223
+suppress 285
+suppress 33 on v4_klog
+suppress 34 on v4_klog
+suppress 36 on sendto
+suppress 35
+suppress 287 on usage
+suppress 287 on sin
+suppress 349 on krb_err_txt
+suppress 349 on krbONE
+suppress 349 on _ctype_
+suppress 340
+suppress 341
+suppress 346
+suppress 226 on error
+load -G main.o kdc5_err.o kdc_util.o network.o policy.o	-I../include
+load -G do_as_req.o do_tgs_req.o extern.o	-I../include
+make SRCS=dispatch.c saber
+load -G kerberos_v4.c -DBACKWARD_COMPAT -DVARARGS -I../include/kerberosIV -I../include -I../include/stdc-incl
+cd  /site/Don/krb5/kdc
+load -G ../lib/kdb/libkdb.a ../lib/libkrb5.a
+load -G ../lib/des/libdes.a ../lib/os-4.3/libos.a ../lib/crc-32/libcrc32.a
+load -G /mit/isode/isode-6.0/@sys/lib/libisode.a
+load -G -lkrb -ldes -lcom_err
+setopt load_flags -I/mit/krb5/vax-cc/include
+link
+unload /site/Don/krb5/lib/kdb/libkdb.a(decrypt_key.o)
+cd     /site/Don/krb5/lib/kdb
+make SRCS=decrypt_key.c saber
+unload /site/Don/krb5/lib/des/libdes.a(enc_dec.o)
+unload /site/Don/krb5/lib/des/libdes.a(new_rn_key.o)
+cd     /site/Don/krb5/lib/des
+make SRCS=enc_dec.c saber
+make SRCS=new_rn_key.c saber
+run
diff --git a/mechglue/src/kdc/ChangeLog b/mechglue/src/kdc/ChangeLog
new file mode 100644
index 000000000..d0b588580
--- /dev/null
+++ b/mechglue/src/kdc/ChangeLog
@@ -0,0 +1,2118 @@
+2005-11-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (listen_and_process): Make local variable 'sout'
+	static.
+
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* fakeka.c: Include errno.h.
+	(main): Pass extra null-pointer argument to
+	kadm5_init_with_password for new db_args argument added by DAL
+	changes.
+
+2005-10-13  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_preauth.c (etype_info_as_rep_helper): New function; shared
+	code for handling ETYPE-INFO and ETYPE-INFO2.  Checks request for
+	"newer" enctypes and does not return an ETYPE-INFO if any "newer"
+	enctypes are present in the request.  Reported by Will Fiveash.
+	(return_etype_info2, return_etype_info): Implement in terms of
+	etype_info_as_rep_helper.
+
+2005-10-12  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_preauth.c (return_etype_info2): Apply patch from Will
+	Fiveash to use reply key's enctype, not the long-term key's
+	enctype, to avoid some enctype similarity problems.
+
+2005-07-12  Tom Yu  <tlyu@mit.edu>
+
+	* do_as_req.c (prepare_error_as):
+	* do_tgs_req.c (prepare_error_tgs): Free scratch only if no error,
+	to avoid double-free.  Thanks to Daniel Wachdorf for discovering
+	these.  Part of fix for MITKRB5-SA-2005-002 [CAN-2005-1174,
+	VU#259798].
+
+	* network.c (process_packet): Initialize response to NULL.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KDB_DEP_LIB): Use DL_LIB and THREAD_LINKOPTS
+	instead of explicitly using -ldl and -lpthread.
+
+	Novell merge.
+	* Makefile.in:
+	* main.c:
+
+2005-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* kerberos_v4.c: Include autoconf.h before testing
+	KRB5_KRB4_COMPAT.
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* dispatch.c (NEED_SOCKETS): Don't define.
+	* do_as_req.c (NEED_SOCKETS): Don't define.
+	* do_tgs_req.c (NEED_SOCKETS): Don't define.
+	* network.c (NEED_SOCKETS): Don't define.
+
+2004-09-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (closedown_network): Free each connection data
+	structure while closing file descriptors.
+
+	* kdc_util.h (sockaddr2p): Don't declare.
+
+2004-07-23  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (kerberos_v4): Duplicate backdating fix for
+	APPL_REQUEST as well.  Fix comments.
+
+2004-06-07  Ezra Peisach  <epeisach@mit.edu.edu>
+
+	* network.c (paddr): Use unsigned int for length.
+	(kdc_conn_type): Declare CONN_ enumerated types in connection as
+	distinct type.
+	(add_fd): Declare as taking enum type instead of simply
+	integer. Prevents assignment of interger to an enum.
+	(process_tcp_connection): Remove variable assigned to but never used.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c: Include foreachaddr.h, not foreachaddr.c.
+
+2004-04-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (setup_a_tcp_listener): Try to turn the IPV6_V6ONLY
+	socket option on, not off, and do it before calling bind.
+	(setup_tcp_listener_ports): Don't do it here any more.
+	(setup_udp_port): Ignore AF_DLI addresses.
+
+2004-03-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (delete_fd): Free pointed-to data after removing it
+	from the connection set.
+	(kill_tcp_connection): Move delete_fd call to the end.
+	(accept_tcp_connection): Decrement connection counter again if we
+	drop the incoming connection for lack of buffer space.
+
+2004-03-15  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (verify_sam_response): Free unparsed names
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Removed.  Directory configured from top level
+	now.
+	* Makefile.in (thisconfigdir, mydir): Updated.
+	(MY_SUBDIRS): Define to just ".".
+
+2004-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't check for --enable-athena and don't define
+	ATHENA_DES3_KLUDGE.
+
+2004-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (setup_a_tcp_listener): Call setreuseaddr before
+	calling bind.
+	(setup_tcp_listener_ports): Don't call setreuseaddr.  Log info
+	about socket option IPV6_V6ONLY in unsupported and success cases.
+
+2004-02-24  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* kerberos_v4.c (compat_decrypt_key): As below.
+
+	* kdc_preauth.c (enctype_requires_etype_info_2): As below.
+
+	* main.c (initialize_realms): Remove support for marc 3des with length
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (OBJS, krb5kdc, fakeka): Link against apputils lib
+	instead of using LIBOBJ.
+
+2004-02-19  Ken Hornstein  <kenh@mit.edu>
+
+	* fakeka.c (main): Bug from David Thompson <thomas@cs.wisc.edu>.
+	Bug originally introduced during conversion from bcopy() to
+	memcpy().
+
+2004-02-12  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_util.c (validate_tgs_request): Fix logic error
+
+2004-02-09  Tom Yu  <tlyu@mit.edu>
+
+	* main.c (init_realm): Apply patch from Will Fiveash to use
+	correct TCP listening ports.
+
+2004-02-06  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* kdc_util.c:  Ignore unknown TGS options
+
+2004-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* kerberos_v4.c (kerberos_v4): Only backdate the rquest in the
+	issued ticket.  Client libraries tend to verify that the
+	backdating falls within clockskew.  a
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Call KRB5_AC_NEED_DAEMON instead of checking
+	whether daemon() prototype is needed.
+	* Makefile.in (OBJS, fakeka): Use @LIBOBJS@.
+
+2003-06-03  Tom Yu  <tlyu@mit.edu>
+
+	* extern.h (master_princ): Remove realm_mkvno, realm_tgskey,
+	realm_tgskvno, realm_kstypes, realm_nkstypes.  They're not needed
+	anymore.
+
+	* main.c (finish_realm): Remove references to realm_kstypes,
+	realm_tgskey.
+	(init_realm): Don't bother with realm_kstypes.  Don't bother
+	looking up the master kvno.  Don't bother caching the TGS key.
+	None of these were being used.
+
+2003-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* main.c (init_realm): Use KRB5_KDB_MAX_RLIFE, not
+	KRB5_KDB_MAX_LIFE, as default for realm's max renewable lifetime.
+
+2003-05-23  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (_make_etype_info_entry): Add flag to know if we
+	are producing etype_info2 so we know whether filling in s2kparams
+	is allowed.    In the etype_info2 case support afs3 salts.
+	(etype_info_helper): Pass in flag
+	(return_etype_info2): And here
+
+2003-05-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc_preauth.c (return_etype_info2): After encoding the
+	etype_info2 and copying the pointers to the pa_data, free the
+	krb5_data pointer.
+
+2003-05-22  Sam Hartman  <hartmans@mit.edu>
+
+	* do_tgs_req.c (process_tgs_req): LOG transited check disabled as info not error
+
+	* kdc_util.c (validate_as_request): Only reject options we
+	understand and believe are inappropriate for AS requests. Per
+	spec, unknown options are ignored.
+
+2003-05-14  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (check_padata): Allow bad_integrity to be returned to a client
+
+2003-05-08  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (return_pw_salt): Don't return pw-salt if the
+	client's enctype list  mandates it supports enctype-info2
+
+2003-05-09  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_util.c (kdc_process_tgs_req): Rename getremotesubkey ->
+	getrecvsubkey.
+
+2003-05-07  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (get_etype_info): Patch from Sun to reorganize
+	code and make sure that even for md5 the database order is
+	preserved. 
+	(enctype_requires_etype_info_2): new function; determines wether a
+	particular enctype in a client request means that the client  is
+	required to support etype_info2 by Kerberos clarifications.
+	(etype_info_helper): Renamed from get_etype_info  to abstract out
+	code in common between etype_info and etype_info2
+	(get_enctype_info): Return etype info only if request contains no
+	enctypes that  require etype_info2
+	(return_etype_info2): New function.
+
+2003-04-02  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (get_etype_info): Avoid infinite loop if request
+	does not contain des-cbc-crc and database does 
+
+2003-04-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* do_tgs_req.c (process_tgs_req): Check that principal name
+	component 1 is present before examining it.
+	* kdc_util.c (krb5_is_tgs_principal, validate_tgs_request): Check
+	principal name length before examining components.
+
+2003-03-28  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_preauth.c (verify_enc_timestamp): Save decryption error, in
+	case we get NO_MATCHING_KEY later.  This allows us to log a more
+	sane error if an incorrect password is used for encrypting the
+	enc-timestamp preauth.
+
+2003-03-16  Sam Hartman  <hartmans@mit.edu>
+
+	* main.c (initialize_realms): Add support to call
+	enable_v4_crossrealm if the user wants insecure operation 
+
+	* kerberos_v4.c: Add enable_v4_crossrealm.  By default krb4
+	cross-realm is not allowed as it is insecure.  Also, remove
+	support for generating krb4 tickets encrypted in 3DES as they are
+	insecure. 
+
+	* kdc_util.h: Define enable_v4_crossrealm, new function to enable
+	secure krb4 cross-realm authentication 
+
+2003-03-05  Tom Yu  <tlyu@mit.edu>
+
+	* main.c (init_realm): Update call to krb5_ktdb_resolve().
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Default to --disable-fakeka.
+
+2003-02-20  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (get_etype_info): fix typo to that caused infinite
+	look in previous change 
+
+2003-02-14  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (request_contains_enctype): New function
+	(get_etype_info): Use it to filter out enctypes not requested by
+	the client 
+
+2003-02-08  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* Makefile.in, configure.in, fakeka.c: New file to implement
+	a basic kaserver using the KDC database.
+
+2003-02-04  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5kdc.M: Document default v4 mode of none
+
+	* kerberos_v4.c (KDC_V4_DEFAULT_MODE):  Default to no v4 support
+	instead of nopreauth  
+
+2003-01-21  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (check_padata): Permit returning KRB5KRB_AP_ERR_SKEW
+
+2003-01-12  Ezra Peisach  <epeisach@bu.edu>
+
+	* kdc_util.h, replay.c, main.c: Pass global krb5_context to
+	kdc_free_lookaside() instead of per realm one - which has been
+	freed by time invoked.
+
+2003-01-03  Ezra Peisach  <epeisach@bu.edu>
+
+	* main.c: On exit, free more allocated memory, including:
+	realm_tcp_ports data, kdc_realmlist, close the replay cache, and
+	free the lookaside cache.
+
+	* network.c (FREE_SET_DATA): Do not free a NULL pointer.
+
+	* replay.c, kdc_util.h: Add kdc_free_lookaside() to clear the lookaside
+	cache on shutdown - to search for memory leaks.
+
+	* rtest.c (main): Do not allocate or free a NULL pointer.
+
+2002-12-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* kerberos_v4.c (process_v4): Use a temporary variable for the
+	current time instead of an incorrect pointer cast.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (kerberos_v4): Use krb_get_err_text() instead of
+	krb_err_txt array.
+
+2002-11-26  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Update dependencies.
+
+	* kerberos_v4.c: Inline some stuff formerly in krb_conf.h until we
+	get a chance to fix it properly.
+
+2002-11-03  Tom Yu  <tlyu@mit.edu>
+
+	* do_as_req.c (process_as_req): Fix previous patch; it caused an
+	uninitialized pointer to be dereferenced under certain error
+	conditions.
+
+2002-10-27  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_util.c (add_to_transited): Don't include trailing null in transited encoding length; doing so breaks using codee
+
+2002-10-05  Tom Yu  <tlyu@mit.edu>
+
+	* do_as_req.c (process_as_req): Apply fix from Kevin Coffman to
+	avoid leaking padata.
+
+2002-09-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (struct connection): New field start_time.
+	(tcp_data_counter, max_tcp_data_connections): New variables.
+	(kill_tcp_connection): New function.
+	(process_tcp_connection): Use it.  Log reason for rejecting
+	connection if the requested buffer size is too large.
+	(accept_tcp_connection): If there are too many TCP connections
+	already, shut down the oldest one.
+	(setup_network, listen_and_process, process_tcp_connection,
+	service_conn): Delete debugging code.
+	(process_packet): Use socklen_t where appropriate.
+
+2002-09-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c: Include sys/filio.h if available.
+
+	* extern.h (struct __kdc_realm_data): New field realm_tcp_ports.
+	* main.c (init_realm): Fill it in.  New argument for default tcp
+	ports; rename old def_ports argument to def_udp_ports.
+	(initialize_realms): Get default tcp ports from "kdc_tcp_ports"
+	entry in config file, falling back to DEFAULT_KDC_TCP_PORTLIST.
+	Use DEFAULT_KDC_UDP_PORTLIST for UDP.
+	* network.c: Include port-sockets.h, socket-utils.h, cm.h.
+	(setup_tcp_listener_ports): New function, creates a TCP listener
+	socket for each port number previously specified.  Tries to do
+	both IPv6 and IPv4 if possible.
+	(setup_a_tcp_listener): New function, creates a TCP socket to
+	listen on at the supplied socket address.
+	(sstate): New variable.
+	(setup_network): Initialize sstate.  Parse TCP port number
+	specification string, and call setup_tcp_listener_ports.
+	(listen_and_process): Use krb5int_cm_call_select, and invoke the
+	service routine specified in the connection info, passing it flags
+	indicating which select fd sets listed the connection.
+	(accept_tcp_connection): New function, handles a TCP listener
+	socket and creates a TCP data connection.
+	(process_tcp_connection): New function, handles incoming or
+	outgoing data on a TCP data stream.
+	(udp_port_fds, udp_port_nums, n_udp_ports, max_udp_ports):
+	Deleted.
+	(n_sockets, max_udp_sockets, select_fds, select_nfds): Deleted.
+	(ipv6_enabled, setreuseaddr, setv6only, paddr, setnbio,
+	setnolinger): New helper functions.
+	(struct connection): New type, encapsulating all per-connection
+	data.
+	(SET, FOREACH_ELT, GROW_SET, ADD, DEL, FREE_SET_DATA): New
+	macros.
+	(connections, udp_port_data, tcp_port_data): New variables.
+	(n_sockets, conns): New macros.
+	(add_udp_port): Renamed from add_port, rewritten to use set macros
+	above.
+	(add_tcp_port): New function, parallel to udp version.
+	(add_fd): Rewritten to manage a set of connection info records
+	instead of just file descriptors.
+	(add_udp_fd, add_tcp_listener_fd, add_tcp_data_fd, delete_fd): New
+	helper functions.
+	(setup_udp_port): Renamed from setup_port.  Uses set macros.
+	(klog_handler): New function, not compiled currently.
+	(init_addr): New function, split out work of initializing a
+	krb5_fulladdr from a socket address from process_packet.
+	(process_packet): Now takes connection info pointer and select
+	flags as arguments.
+	(closedown_network): Use set macros in cleanup.
+
+2002-09-15  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (check_princ): Call strftime() with correct number
+	of arguments.
+
+2002-09-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* kerberos_v4.c: Always include stdarg.h, not varargs.h.
+	(v4_klog): Always declare and define stdarg version.
+	(krb4_stime): Deleted.
+	(check_princ): Use strftime instead.
+
+2002-09-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* main.c (initialize_realms): Include replay cache name in error
+	if it can't be initialized.
+
+	* kerberos_v4.c (kerb_get_principal): Include kvno when logging
+	failure to find a key.
+	(v4_klog): Include explicit do-nothing default case in switch
+	statement.
+
+2002-09-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* dispatch.c, do_as_req.c, do_tgs_req.c, kdc_preauth.c,
+	kdc_util.c, kerberos_v4.c, main.c, network.c, policy.c, replay.c,
+	rtest.c: Use prototype-style function definitions and
+	declarations.  Don't declare errno.
+
+	* do_as_req.c (prepare_error_as): New argument, the error message
+	text as determined *before* possibly replacing the error code with
+	"generic error".
+	(process_as_req): Fill it in based on 'status', or the error
+	message corresponding to the error code to be returned.
+	* do_tgs_req.c (prepare_error_tgs): New argument, the error
+	message text as determined *before* possibly replacing the error
+	code with "generic error".
+	(process_tgs_req): Fill it in based on 'status', or the error
+	message corresponding to the error code to be returned.
+
+	* network.c (process_packet): Call inet_ntop directly.
+	* sock2p.c: Deleted.
+	* Makefile.in (SRCS, OBJS): Drop it.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-15  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c: For consistency, check for both DISALLOW_ALL_TIX
+	and DISALLOW_SVR when looking up services.
+
+2002-08-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (setup_port): Ignore AF_LINK addresses.  Log address
+	family number if unrecognized.
+
+2002-07-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc_util.h (ADDRTYPE2FAMILY): New macro.
+	* do_as_req.c (process_as_req): Use inet_ntop instead of
+	inet_ntoa.
+	* do_tgs_req.c (process_tgs_req): Ditto.
+	* dispatch.c (dispatch): Fix inet_ntop code, and use it always.
+	* kerberos_v4.c (process_v4): Check address family before copying
+	out an IPv4 address.  Log if not IPv4, but continue.
+	* network.c (set_sa_port): New function.
+	(setup_port): Use it.  Combine IPv4 and IPv6 paths; IPv6 still
+	enabled now.  Modify supplied sockaddr instead of making a copy.
+	(process_packet): SADDR is now sockaddr_storage.  Use socket-utils
+	macros instead of casting.  Enable the IPv6 code.
+	* dispatch.c, do_as_req.c, do_tgs_req.c: Define NEED_SOCKETS
+	before including k5-int.h.
+	* network.c: Include fake-addrinfo.h.
+
+2002-07-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (process_packet): Now static.  Drop unused "portnum"
+	argument.  Change caller.
+	* kdc_util.h (process_packet): Delete declaration.
+
+	* sock2p.c (inet_ntop): Disable definition; it should be provided
+	by the socket support header files.
+	* kdc_util.h (inet_ntop): Delete declaration. 
+
+2002-06-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* dispatch.c (dispatch): Remove arg "portnum"; update callers.
+	* do_as_req.c (process_as_req): Ditto.
+	* do_tgs_req.c (process_tgs_req): Ditto.
+	* kerberos_v4.c (process_v4): Remove arg "is_secondary"; update
+	callers.
+	* kdc_util.h (dispatch, process_as_req, process_tgs_req,
+	process_v4): Update prototypes.
+	* main.c (init_realm): Remove unused variable.
+
+2002-06-24  Sam Hartman  <hartmans@mit.edu>
+
+	* kdc_preauth.c (get_etype_info): We get KRB5_KDB_NO_MATCHING_KEY
+	not ENOENT; per 5.27 of kdb_xdr.c.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* do_as_req.c (process_as_req): Call krb5_c_valid_enctype instead
+	of valid_enctype.
+	* do_tgs_req.c (process_tgs_req): Likewise.
+	* kdc_util.c (select_session_keytype): Likewise.
+	(comp_cksum): Similarly for valid_cksumtype, is_coll_proof_cksum.
+
+2002-02-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c: Include foreachaddr.c.
+	(printaddr, printifaddr, addr_eq, foreach_localaddr): Deleted.
+	* Makefile.in ($(OUTPRE)network.$(OBJEXT)): Updated dependencies.
+
+2002-01-08  Sam Hartman  <hartmans@mit.edu>
+
+	* dispatch.c (dispatch): Add timing data between requests to PRNG
+	(dispatch): Grab random data from OS every hour
+
+2001-12-14  Ezra Peisach  <epeisach@mit.edu>
+
+	* main.c (main, init_realm): Get rid of variables set but never used. 
+
+2001-12-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc_util.c (subrealm, add_to_transited): Unsigned vs. signed int
+	fixes.
+
+2001-11-26  Sam Hartman  <hartmans@mit.edu>
+
+	* main.c (init_realm): Don't seed from current time;
+	krb5_init_context already does that.
+
+2001-10-25  Tom Yu  <tlyu@mit.edu>
+
+	* do_as_req.c (process_as_req: Treat SUPPORT_DESMD5 as if it were
+	always cleared.
+
+	* do_tgs_req.c (process_tgs_req): Treat SUPPORT_DESMD5 as if it
+	were always cleared.
+
+2001-10-24  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_util.c (select_session_keytype): Don't issue session key
+	enctype that is not in permitted_enctypes.
+	(dbentry_supports_enctype): For now, always treat SUPPORT_DESMD5
+	as if it were cleared.
+
+2001-10-12  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_util.c (ktypes2str, rep_etypes2str): Clean up somewhat.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* do_tgs_req.c (process_tgs_req): Fix logging of bad transit path
+	info.
+
+2001-09-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* do_tgs_req.c (process_tgs_req): If disable-transited-check
+	option isn't set, try to verify transit path.  If
+	reject_bad_transit flag is set and transit path isn't verified,
+	reject the request.  Use a temporary variable to simplify
+	references to the second ticket.
+	* extern.h (struct __kdc_realm_data): Add new field
+	realm_reject_bad_transit.
+	(find_realm_data): Declare.
+	(reject_bad_transit): New macro.
+	* main.c (find_realm_data): Delete declaration.
+	(init_realm): Copy reject-bad-transit value or use default.
+	* rtest.c (find_realm_data): Define dummy version.
+
+2001-09-24  Mitchell Berger  <mitchb@mit.edu>
+
+	* krb5kdc.M: Document the -n option.  Thanks to Dennis Davis
+	<D.H.Davis@bath.ac.uk>
+
+2001-07-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Include stdlib.h in test for swab declaration.
+
+2001-07-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* rtest.c: Provide a prototype for krb5_klog_syslog() dummy handler.
+
+2001-06-29  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add check for ifaddrs.h, which missing.
+
+2001-06-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* network.c (setup_port): Change sin to sin4 to prevent shadowing.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Test for daemon prototype.
+	
+	* main.c: Provide daemon prototype if needed.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use optional argument to KRB5_NEED_PROTO so test
+	for swab existance removed.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc_preauth.c: Include prototypes for mit_des_fixup_key_parity
+	and mit_des_is_weak_key here as no other "public" header file
+	defines it. Needed for return_sam_data() code. 
+
+	* configure.in: Test for unistd.h and existance of swab() prototype.
+
+	* kerberos_v4.c: If swab() prototype needed, provide. 
+
+2001-06-19  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_util.c (ktypes2str): New function; construct a string
+	containing a list of enctypes, given a number and list of
+	enctypes.
+	(rep_etypes2str): New function; construct a string indicating all
+	three enctypes associated with a KDC reply.
+
+	* kdc_util.h: Add prototypes for ktypes2str() and
+	rep_etypes2str().
+
+	* do_as_req.c (process_as_req): Call ktypes2str() and
+	rep_etypes2str() as appropriate.
+
+	* do_tgs_req.c (process_tgs_req): Call ktypes2str() and
+	rep_etypes2str() as appropriate.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* network.c (setup_network): Cast argument to isspace() to int.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc_preauth.c: Include adm_proto.h for krb5_klog_syslog()
+	prototype.
+
+	* main.c: Include des.h for des_init_random_number_generator()
+	prototype.
+
+	* network.c: Include adm_proto.h for krb5_klog_syslog()
+	prototype. Pass kdc_context to krb5_klog_reopen().
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* kerberos_v4.c: Get rid of file wide static krb5_error_code. Cast
+	argument to sleep to unsigned int.
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc_util.c (add_to_transited): Add braces to provide unambiguous
+	if - if - else statements. 
+
+	* kdc_preauth.c (verify_sam_response): Cleanup assignments in
+	conditionals.
+	* main.c (main): Likewise. 
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't use HAS_ANSI_VOLATILE.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* do_as_req.c, do_tgs_req.c, kdc_preauth.c, kdc_util.h,
+	kerberos_v4.c, main.c, policy.h: Don't use macros PROTOTYPE or
+	KRB5_PROTOTYPE.
+	* kerberos_v4.c (req_act_vno): Delete variable definition.
+	(kerberos_v4): Don't set it.
+
+2001-03-08  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* do_as_req.c: If KRBCONF_KDC_MODIFIES_KDB defined, produce code
+	that compiles and works.
+
+	* kdc_util.h: Add prototype for process_v4_mode() for main.c to use.
+
+	* kerberos_v4.c: Do not shadow progname and more variables.
+
+	* rtest.c (make_princ): Declare static.
+
+	* sock2p.c: Include kdc_util.h for prototypes.
+
+2001-02-08  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (kerberos_v4): Remove references to
+	KRB_NEVERDATE.
+
+2000-12-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c: Don't include net/if.h if ARPHRD_ETHER is defined.
+	Fix suggested by Kevin Coffman <kwc@citi.umich.edu> for OpenBSD,
+	which breaks on multiple inclusions of net/if.h.
+
+	* configure.in: Look for ifaddrs.h.
+	* network.c (printaddr, printifaddr, addr_eq, foreach_localaddr):
+	Update from lib/krb5/os/localaddr.c, including getifaddrs
+	support.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Get rid of test for termios.h. The kdc does not use it.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc_preauth.c (get_etype_info): Initialize length of
+	etype_info_entry to KRB5_ETYPE_NO_SALT. Before copying salt into
+	etype_info_entry, test that salt length (from get_salt_from_key())
+	is not SALT_TYPE_NO_LENGTH.
+
+	* kdc_util.c (get_salt_from_key): Initialize salt type to
+	SALT_TYPE_NO_LENGTH (instead of -1).
+
+	* network.c (process_packet): Cast length in sendto() call to int. 
+
+2000-10-06  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (kerb_get_principal): Modify to take a pointer to
+	a krb5_deltat in order to return the life in seconds.  Also, use
+	time_to_life() to compute krb4 life.
+	(check_princ): Modify to pass a pointer to a krb5_deltat to
+	kerb_get_principal().
+	(set_tgtkey): Update for new kerb_get_principal() call signature.
+	(kerberos_v4): Update for new check_princ() call signature.
+	Modify lifetime computations to use lifetimes in seconds.
+	Back-date issue time if necessary.
+
+2000-09-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* dispatch.c (dispatch): inet_ntop() returns const char *.
+
+2000-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* main.c (initialize_realms): For "cannot initialize realm"
+	messages, tell the user to check the log file.  Print out an error
+	message as well as logging it if retrieving the default realm name
+	fails.
+
+	* kerberos_v4.c (kerberos_v4): Mask requested-life byte value with
+	0xff to avoid sign-extension problems.
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (rtest): Link in the kdb5 library.
+
+2000-05-17  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (process_v4): Zero out v4_pkt.mbz.
+	(kerberos_v4): Fix handling of APPL_REQUEST messages to deal with
+	ridiculously long realms, etc.  Fix up some calls to
+	kerb_err_reply() to be more useful.  Set req_*_ptr before any
+	possible calls to kerb_err_reply().
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kdc_util.c (add_to_transited): Use strncpy/strncat when building
+        data in buffers so as not to overrun "prev", "current", and "exp".
+	* kerberos_v4.c (process_v4): Don't assume that the realm is null-
+	terminated.
+	(set_tgtkey): Truncate realm name if it's too long.
+
+2000-04-28  Ken Raeburn  <raeburn@mit.edu>
+	    Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kdc_util.c (add_to_transited): Use strncpy/strncat when building
+	data in buffers.  Fix some limit checks.
+	* kerberos_v4.c (kerb_err_reply): Use strncat so as not to overrun
+	error buffer.
+
+2000-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c: Include stddef.h.
+	(foreach_localaddr): Check each address against previously used
+	addresses, and skip duplicates, in case multiple interfaces have
+	the same address.
+
+2000-04-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* network.c (foreach_localaddr): If called functions fail, drop
+	out of loop and return nonzero.
+
+2000-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* sock2p.c: New file.
+	(inet_ntop): Define if system doesn't provide it.
+	(sockaddr2p): New function.
+	* Makefile.in (SRCS, OBJS): Add sock2p.
+	* kdc_util.h (inet_ntop, sockaddr2p): Declare them.
+
+	* network.c (add_fd): New function.  Reallocate udp_port_fds array
+	as needed here.
+	(setup_port): Use add_fd to record new sockets.  Use inet_ntop
+	unconditionally.  Disable ipv6 support until process_packet and
+	friends will support it.
+	(process_packet): Ignore ECONNREFUSED when reading UDP packets.
+	Fill in port field of faddr properly, dependent on address
+	family.  Use sockaddr2p when logging source address.
+
+2000-03-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* replay.c, kdb_util.h (kdc_check_lookaside, kdc_insert_lookaside): 
+	Make second argument const to keep handle compiler warnings.
+
+2000-03-01  Tom Yu  <tlyu@mit.edu>
+
+	* main.c: Move kdc_initialize_rcache() to kdc_util.c
+
+	* kdc_util.c (kdc_initialize_rcache): Move kdc_initialize_rcache()
+	back here since it's needed for rtest to work.  process_tgs_req()
+	which is called from rtest needs to call kdc_intiialize_rcache()
+	and we can't very well link rtest with main.o
+
+	* kdc_preauth.c (verify_sam_response): Ooops.  Get rc_lifetime
+	from kdc_util, since it's actually declared there.
+
+	* configure.in: Fix --enable-kdc-replay-cache to actually default
+	to "yes".
+
+	* kdc_preauth.c (verify_sam_response): Declare and set rc_lifetime
+	for real.
+
+2000-02-29  Tom Yu  <tlyu@mit.edu>
+
+	* dispatch.c: Include some more net-related headers.
+	(dispatch): Fix ifndef HAVE_INET_NTOP branch.
+
+2000-02-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: New enable-kdc-replay-cache arg.  Define
+	USE_RCACHE when enabled, NOCACHE when disabled.  Defaults to
+	enabled.
+	* Makefile.in (DEFINES): Don't define NOCACHE any more.
+
+2000-02-25  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Check for sys/sockio.h
+
+	* network.c: Conditionally include sys/sockio.h for SIOC* if
+	necessary.
+	(process_packet): Bracket AF_INET6 branch of a switch statement
+	with an ifdef.
+
+2000-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Invoke KRB5_AC_INET6.
+	* network.c (max_udp_sockets): New variable.
+	(setup_port): Add IPv6 support.  Reallocate udp_port_fds array as
+	needed here.
+	(add_port): Don't do buggy udp_port_fds allocation here.
+	(setup_network): On failure, exit.
+	(process_packet): Handle inet6 addresses when building
+	krb5_address structure.
+
+2000-02-25  Ken Raeburn  <raeburn@mit.edu>
+	    Alec H. Peterson  <ahp@hilander.com>
+
+	* configure.in: Invoke KRB5_SOCKADDR_SA_LEN.
+	* network.c: Include <sys/ioctl.h>, <syslog.h>, <net/if.h>.
+	(foreach_localaddr): New function, copied from
+	lib/krb5/os/localaddr.c.
+	(NEED_SOCKETS): Define before including k5-int.h.
+	(n_sockets): New variable.
+	(setup_port): New function; creates listening udp ports given an
+	address.
+	(setup_network): Call foreach_localaddr to set up listening
+	sockets on each local address, so we can always respond from the
+	receiving address.
+	(listen_and_process): Use n_sockets as upper bound of loop.
+
+2000-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* kerberos_v4.c (v4_klog): Don't treat the formatted text as a
+	format string.  (Patch from Mike Friedman,
+	mikef@ack.Berkeley.EDU.)
+
+2000-02-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc_preauth.c (get_preauth_hint_list): Log a message if preauth
+	is required but no preauth types are available.
+	(return_sam_data): Fix typo in figuring length of data to XOR when
+	merging keys.  Just return 0 if no input preauth data is
+	available.
+
+2000-02-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc_preauth.c: Include <syslog.h>.
+	(struct _krb5_preauth_systems, preauth_systems): Add new NAME
+	field, for logging debug info.
+	(check_padata): Call krb5_klog_syslog instead of com_err.
+	(missing_required_preauth, check_padata): Added debugging
+	krb5_klog_syslog calls, currently disabled.
+	(sam_inst_map): Add {} around array element initializers to keep
+	gcc quiet.
+	(get_sam_edata): Delete unused variable I.
+
+	Patches from Frank Cusack for hw-preauth replay detection.
+	* main.c (rc_lifetime): New global variables.
+	(kdc_initialize_rcache): Initialize rc_lifetime from context
+	clockskew.
+	(setup_sam): New function; initializes psr_key.
+	(main): Call setup_sam.
+	* kdc_preauth.c (get_sam_edata): Fill in new fields of PSR.  Use
+	psr_key for encrypting instead of database master key.
+	(verify_sam_response): Use psr_key instead of database master
+	key.  Do replay detection if USE_RCACHE is defined.
+	(get_sam_edata): Clear SC and PSR structures before using them.
+	Set new FLAGS field of PSR.
+	(return_sam_data): New function.
+	(preauth_systems): Use return_sam_data in sam-response entry.
+	* extern.c (psr_key): Define.
+	* extern.h (psr_key): Declare.
+
+	* kdc_preauth.c (get_sam_edata, verify_sam_response): Add parens
+	around assignments in if statements, to keep "gcc -Wall" quiet.
+	(return_sam_data): Delete unused variable padata.
+
+	* main.c (kdc_current_rcname): Declare only if USE_RCACHE is
+	defined.
+
+2000-01-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* dispatch.c (dispatch): Log address and port number of detected
+	retransmits.
+
+	* kdc_util.c (select_session_keytype): Revert 1999-09-01 changes;
+	now always use any requested type indicated as supported by the db
+	entry.
+
+1999-10-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* dispatch.c (dispatch): Make message in lookaside case less
+	suggestive of replay attacks, since it can result from normal
+	packet loss causing retransmissions.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-13  Tom Yu  <tlyu@mit.edu>
+
+	* do_tgs_req.c (process_tgs_req): Don't try to take the 2nd
+	component of a principal that doesn't have 2 components.
+
+1999-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc_util.c (select_session_keytype): If none of the requested
+	ktypes are NULL or single-DES, force des-cbc-crc.
+
+1999-08-18  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (compat_decrypt_key): Align DES3 enctypes with
+	current names.
+	(kerb_get_principal): Align DES3 enctypes with current names.
+
+1999-06-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (CFLAGS): Define NOCACHE.
+	(DEFINES): Commented out, since it's unused.
+	* dispatch.c (dispatch): If NOCACHE is defined, don't call
+	lookaside buffer code.
+	* replay.c: Disable all code if NOCACHE is defined.
+
+1999-06-28  Tom Yu  <tlyu@mit.edu>
+
+	* replay.c (MATCH): Fix up to compare the correct components of
+	the input address.
+
+Fri Apr 30 00:05:07 1999  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (kerberos_v4): Fix bug where krb_create_ticket()
+	was getting called for an APPL_REQUEST even when there was no
+	single-DES key, resulting in random weirdness.
+
+Wed Feb 17 17:07:43 1999  Tom Yu  <tlyu@mit.edu>
+
+	* do_as_req.c (process_as_req): Fix to assign kvno to
+	reply.enc_part after encryption, since krb5_c_encrypt() now
+	explicitly initializes all fields of a krb5_enc_data.
+
+1998-12-17  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdc_preauth.c (check_padata): If preauth fails because the
+		preauth data from the client was of an unknown type, and
+		the principal does not require preauth, then the preauth
+		should be disregarded.  [krb5-kdc/652]
+
+Mon Jan  4 23:50:45 1999  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in (withval): Conditinalize ATHENA_DES3_KLUDGE on
+	--enable-athena.
+
+	* main.c (initialize_realms): Kludge to disable
+	des3-marc-hmac-sha1 from the command line.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* do_as_req.c, do_tgs_req.c, extern.h, kdc_preauth.c, kdc_util.c,
+	kerberos_v4.c, main.c: conver to new crypto api.
+
+Fri Sep 25 19:47:26 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (check_princ): Re-order if statements that check
+	for null keys to make Purify shut up.
+
+Thu Sep 17 18:21:51 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_util.c (kdc_get_server_key): Fix to not use cached tgs key
+	to prevent lossage when it might be out of date by always fetching
+	the correct kvno for the ticket out of the database.
+
+Tue Sep  1 19:34:30 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (compat_decrypt_key): Add
+ 	ENCTYPE_LOCAL_DES3_HMAC_SHA1 to the list of keytypes to bash.
+	(kerb_get_principal): Add ENCTYPE_LOCAL_DES3_HMAC_SHA1 to the list
+ 	of searched enctypes.
+
+Wed Aug 19 13:37:00 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c (set_tgtkey): Add kvno arg to fetch an explicit
+	kvno.  Also compare kvno as well as realm when caching the TGT
+	key.  Declare as static.
+	(kerb_get_principal): Add kvno argument to permit searching for
+	an explicit kvno.
+	(kerberos_v4): Extract the kvno directly out of the krb_req, since
+	we know what the format is.
+
+Wed Aug 12 18:40:08 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c: Add macro K4KDC_ENCTYPE_OK to determine whether a
+	given enctype is compatible with single-DES krb4.
+	(compat_decrypt_key): Declare as static.  Change call signature to
+	include an output krb5_keyblock as well as an input to determine
+	whether the principal should be treated as a service principal.
+	Bash the enctype of the keyblock to raw des3 if it's full-blown
+	des3.
+	(kerb_get_principal): Add k5key and issrv arguments as in
+	compat_decrypt_key, mostly to pass them on there.  Hardcode a
+	search order that includes des3 for looking up service keys.
+	(kerberos_v4): Call krb_create_ticket or krb_cr_tkt_krb5 as
+	appropriate to the key type.  While we're at it, s/ktbtgt/krbtgt/
+	just to avoid confusing people.
+	(check_princ): Add k5key and issrv args for as in
+	compat_decrypt_key.  Fix up null key detection to only operate if
+	it's a single-des key.
+	(set_tgtkey): Call krb_set_key_krb5 if appropriate.
+
+Tue Jul 21 20:29:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* replay.c (kdc_check_lookaside):
+	(kdc_insert_lookaside): Add code to originating address of packet,
+ 	as krb4 initial ticket requests don't contain an address.  This
+ 	would cause a subtle problem wherein two simultaneous krb4 initial
+ 	ticket requests for the same principal originating from different
+ 	addresses would result in both replies containing the same
+	address.
+
+	* kdc_util.h: Modify prototype for lookaside functions.
+
+	* dispatch.c (dispatch): Update to new calling conventions of the
+	lookaside functions.
+
+Wed Jul 15 18:32:07 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add CHECK_SIGNALS so that POSIX_SIGNALS gets
+	defined.
+
+	* main.c (request_hup): Remove call to signal, as this isn't
+	needed on BSD-ish systems and for sysV-ish systems we use
+	sigaction anyway.
+	(setup_signal_handlers): Fix typo.
+
+Sat Jul 11 01:38:05 1998  Geoffrey King  <gjking@mit.edu>
+
+	* main.c: Added a call to signal() in request_hup()
+	        so that the signal handler gets reset after
+	        each SIGHUP, since this does not happen
+	        automatically in System V's signal handling
+	        system.
+
+Wed Jul  8 04:36:28 1998  Geoffrey King  <gjking@mit.edu>
+
+	* extern.h: Added declaration for new variable
+	        signal_requests_hup, which is set when the KDC
+	        is sent a SIGHUP
+	
+	* extern.c: Added definition for signal_requests_hup
+
+	* main.c: Added new signal handling code for SIGHUP, including
+	        the new function request_hup()
+
+	* network.c: Check signal_requests_hup in the main KDC loop
+
+Fri May  8 18:46:59 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kerberos_v4.c (krb4_stime): Print 4 digit years in Krb4 log
+	 	entries to avoid Y2K issues.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* main.c (initialize_realms): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Fri Mar 20 17:13:46 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_util.c (add_to_transited): Check lengths, fix up comma
+	quoting somewhat (though things are still way broken).
+
+Fri Feb 20 15:58:21 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kdc_preauth.c (get_preauth_hint_list): Don't add the pseudo
+		preauth type KRB5_PADATA_PW_SALT to the hint list of
+		supported preauthentication systems, since it doesn't help
+		to send it.  (And it may screw up Cygnus KerbNet clients.)
+
+Wed Feb 18 16:04:22 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (thisconfigdir): Remove trailing slash.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Feb  5 19:17:25 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c: Move macro definition of klog earlier so that it
+	actually gets used inside process_v4().
+
+Wed Feb  4 14:15:20 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kerberos_v4.c (process_v4): Check the length of the incoming V4
+		packet before copying it into the KTEXT_ST variable.
+		(kerberos_v4): Make sure the strings in the V4 request
+		structures aren't no longer than they are allowed to be.
+
+Wed Jan 28 08:56:07 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5kdc.M: Document V4 mode handling [krb5-kdc/464].
+
+Wed Jan 21 15:15:58 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* rtest.c (main): returns int, not void. ANSI X3.159-1989
+	2.1.2.2.1 says so, and gcc now warns about it.
+
+Fri Jan 16 03:33:50 1998  Tom Yu  <tlyu@mit.edu>
+
+	* do_tgs_req.c: Add some explicit settings of errcode so that the
+ 	cleanup code doesn't try to construct a bogus error reply, which
+ 	was causing coredumps in the lookaside code.
+
+Thu Dec 11 23:29:41 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kerberos_v4.c: Don't include sys/socket.h or netdb.h, as krb.h
+	already gets those and Ultrix doesn't protect them against
+	multiple inclusion.
+
+Mon Nov 24 19:57:48 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* do_tgs_req.c (process_tgs_req): Add check to make sure cname and
+		sname are non-NULL when syslogging an error because the
+		principals don't match.
+	
+	* kdc_util.c (limit_string): Check to make sure the input string
+		is non-NULL before operating on it.
+
+Thu Nov 13 20:40:01 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* do_tgs_req.c (process_tgs_req): Only try to return a TGT for a
+		"closer" realm if the request was for a TGT in the first
+		place.  [krb5-kdc/459]
+
+Wed Nov 12 14:47:46 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* do_as_req.c (process_as_req): Reset master key after closing and
+ 	 	reopening DB when KDC_UPDATES_KDB compiled
+ 	 	in. [krb5-kdc/495 by Tony Mione]
+
+Mon Nov 10 20:03:14 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kdc_util.c (kdc_process_tgs_req): If not using the reply cache,
+		properly handle a failure return from
+		krb5_rd_req_decode_anyflag().
+
+Wed Oct  8 12:20:35 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* main.c (main): Initialize kdc error table with
+	        initialize_kdc_error_table().
+
+Thu Sep 25 21:19:08 1997  Tom Yu  <tlyu@mit.edu>
+
+	* network.c: Replace KRB5_USE_IENT with something more sane.
+
+	* do_tgs_req.c: Replace KRB5_USE_INET with something more sane.
+
+	* main.c: Replace KRB5_USE_INET with something more sane.
+
+	* do_as_req.c: Replace KRB5_USE_INET with something more sane.
+
+Wed Sep 24 11:56:50 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdc_util.c (add_to_transited): Fix up memory leaks, clean out
+        new memory allocated, allocate buffers to max size
+        needed. [based on krb5-kdc/461 by Ken Hornstein].
+
+	* rtest.c: Rewrite code to use context and current krb5_principal
+	        structure.
+
+	* configure.in: Add KRB5_RUN_FLAGS
+
+	* Makefile.in (rtest): Compile rtest and run during make check.
+
+
+Tue Sep 23 13:25:35 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kerberos_v4.c (check_princ): Add checks for V5 kdc flags
+	        including REQUIRES_PWCHANGE, DISALLOW_ALL_TIX,
+	        REQUIRES_PREAUTH. Adds support for parsing the V4 options.
+		[krb5-kdc/464].
+
+	* main.c (main): Add option -4 to specify V4 handling mode.
+
+Mon Aug 18 12:29:08 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* do_tgs_req.c (process_tgs_req): Initialize authtime to 0 so it
+        is set before potentially used in case the packet has an error.
+
+	* kdc_preauth.c (get_sam_edata): Remove unused variables.
+
+	* kdc_util.h: Added prototype for setup_server_realm().
+
+	* main.c (get_realm_port): Removed unused function.
+	         (setup_server_realm): Moved prototype to kdc_util.h
+
+Wed Jul 30 18:29:19 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_util.c: 
+	* main.c: Don't use an rcache.
+
+Fri Jul 25 15:44:07 1997  Tom Yu  <tlyu@mit.edu>
+
+	* main.c (init_realm): Fix to use new ktkdb.
+
+Tue Jul 15 01:55:56 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kdc_preauth.c (get_sam_edata): Don't goto cleanup if SAM is not
+	used; this prevents freeing an unallocated keyblock.
+
+Thu May 29 21:08:24 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* do_as_req.c (process_as_req), do_tgs_req (process_tgs_req): Use
+		limit_string() to make sure the length of cname and sname
+		are reasonable.
+
+	* kdc_util.c (limit_string): New function which limits the strings
+		that will end up in log files to "reasonable" lengths.
+
+Tue Feb 18 09:56:16 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* kerberos_v4.c: Remove include of krb4-proto.h
+
+Tue Feb 18 18:51:09 1997  Richard Basch  <basch@lehman.com>
+
+	* do_as_req.c do_tgs_req.c kdc_preauth.c kdc_util.c main.c
+	replay.c kerberos_v4.c:
+		Replace krb5_xfree with appropriate free routine.
+
+Thu Feb  6 00:09:46 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Remove logger.c target before copying over it.
+		This avoids permission problems if the source is read-only
+		and later changes.
+
+Wed Jan  1 22:56:16 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc_preauth.c (get_sam_edata): Use proper interface to
+		krb5_db_get_principal. Also if SAM is not an option, do
+		not return as a possible type to client. [krb5-kdc/310]
+
+Fri Jan 31 21:39:04 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (LOCALINCLUDE): Change  KRB4_INCLUDE to KRB4_INCLUDES
+
+Fri Jan 31 19:45:13 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Sat Nov 23 17:26:22 1996  Mark Eichin  <eichin@kitten.gen.ma.us>
+
+	* [krb5-libs/149] only generate requests that you can actually
+	handle.
+	
+	Tue Sep  3 22:53:56 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kdc_preauth.c (get_preauth_hint_list): detect ap->get_edata
+	return status and don't pass back hint if it failed.
+	(get_etype_info): malloc one more word in entry for end marker.
+
+Wed Nov 20 11:25:05 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* main.c (initialize_realms): krb5_aprof_init can succeed while
+ 	leaving aprof == NULL, but krb5_aprof_finish will fail.  This is
+ 	just more grossness that needs to be redone when the kdc.conf
+ 	interface is reworked.
+
+Thu Nov  7 12:27:21 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdc_preauth.c (check_padata): Fixed error handling; in order for
+		check_preauth to return successfully, there must be at
+		least one preauth which succeeded, and no REQUIRED preauth
+		system which failed.  If a preauth is marked SUFFICIENT,
+		then the rest of the preauth list aren't checked.  Fixed
+		bug where when none of the preauth types were recognized,
+		an error message corresponding to stack garbage was printed.
+
+Wed Nov  6 12:00:48 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* main.c (argv): Check the error return from krb5_init_context(),
+ 		and print an error message if necessary.
+
+Mon Nov  4 22:29:30 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* main.c (initialize_realms): Remove rather pointless use of
+ 		krb5.conf to find the kdc.conf used to get the default
+ 		port list.  It's not useful for anything else, and will
+		just confuse people.
+		(init_realm): Reformat function to be readable.  Add error
+		checking to call of krb5_read_realm_params
+
+Wed Sep 18 16:03:26 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kdc_util.c: Added magic number to initializer of nolrentry.
+
+Tue Sep 10 14:18:41 1996  Tom Yu  <tlyu@mit.edu>
+
+	* krb5kdc.M: remove ".so man1/header.doc"
+
+Fri Aug 23 14:22:45 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* kerberos_v4.c (check_princ): Assume an expiration date of zero means never expire.
+
+Thu Aug  1 11:13:46 1996  Ezra Peisach  <epeisach@dumpster.rose.brandeis.edu>
+
+	* configure.in (withval): Link -ldyn as it is needed by the kadm5
+		shared library.  
+
+Wed Jul 24 02:29:19 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* kerberos_v4.c (set_tgtkey): s/KRB4_#@/krb5_ui_4 so we work with
+ 	athena Kerberos.
+
+
+
+Tue Jul 23 22:26:29 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Build logger.o from the libkadm5 directory.  This
+ 		is prepatory work towards eliminating the dependency on
+ 		libkadm5.  Ultimately we will probably need to rethink how
+		the library structure for krb5....
+
+	* configure.in: Add -lgssapi and -lgssrpc to libraries linked with
+ 		krb5kdc since they are needed for shared libraries.  This
+ 		is a horrible hack....
+
+
+Thu Jun 13 22:09:34 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to ET_RULES
+
+Sun Jun  9 23:03:06 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* main.c (finish_realm): Do not invoke krb5_finish_key if
+		encryption block is not set.
+
+Sun May 12 01:17:05 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: USE_KADM_LIBRARY replaced by USE_KADMSRV_LIBRARY
+
+Tue May  7 18:19:59 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	Thu May  2 22:52:56 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kdc_util.c (kdc_process_tgs_req): call
+	krb5_rd_req_decoded_anyflag instead of krb5_rd_req_decoded, so
+	that invalid tickets can be used to validate themselves. Add
+	explicit check that if the ticket is TKT_FLG_INVALID, then
+	KDC_OPT_VALIDATE was requested.
+
+Mon May  6 12:15:36 1996  Richard Basch  <basch@lehman.com>
+
+	* main.c: Fixed various abstraction violations where the code knew
+	the internals of eblock->crypto_entry.
+
+Wed Feb 28 13:07:28 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* main.c: Move com_err.h after k5-int.h include.
+
+Tue Feb 27 17:33:44 1996  Richard Basch  <basch@lehman.com>
+
+	* main.c:
+	Do not repeat random number generator initializations, as memory
+	is allocated and never reclaimed.  Also fixed the V4 random number
+	generator initialization (a DES_CBC_CRC random number is generated
+	and used as a seed for the V4 routine, but the generation function
+	was being called with the wrong arguments).
+
+	* do_as_req.c:
+	Memory was occassionally being freed twice because the pointer was
+	not re-initialized to NULL after it was freed.
+
+Sun Feb 25 16:04:10 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* main.c (initialize_realms): missing indirection for conf_val in
+	alternate profile code. (This should really be in a library...)
+
+Sat Feb  3 22:37:55 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* network.c (add_port): sunos realloc doesn't handle a NULL
+	pointer, so protect with a macro.
+
+Sat Feb 10 02:46:27 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* main.c (initialize_realms): look for [kdc] profile=path for
+	default alternate kdc profile (environment variable still
+	overrides it.)
+
+Wed Feb 21 23:28:33 1996  Richard Basch  <basch@lehman.com>
+
+	* kerberos_v4.c: Improve checking of DES keys
+
+	* main.c: Do not assume the master key is DES; instead initialize
+		the V4 random key generator from a random key after the
+		DES_CBC_CRC generator has been initialized.
+
+Tue Feb 20 16:50:59 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kerberos_v4.c (kerberos_v4): Use strong random number generator
+
+	* main.c (main): Initialize Kerberos V4's random number generator.
+
+Sat Jan 27 00:53:41 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* network.c (setup_network): strtol is good enough for port
+	number, and sunos doesn't have strtoul (and nothing else in the
+	tree uses it.)
+	(add_port): use proper old-style definition.
+	
+Wed Dec 13 03:51:53 1995  Chris Provenzano (proven@mit.edu)
+
+        * kerberos_v4.c : Remove mkvno for krb5_db_entry
+
+Tue Dec 12 01:10:34 1995  Chris Provenzano (proven@mit.edu)
+
+	* extern.h: Added a krb5_keytab to the realm context. The keytab
+		should be associated with a krb5_db_context which will
+		make having a krb5_context unnecessary in the realm context.
+	* kdc_util.c kdc_process_tgs_req(): Use the realm keytab instead
+		of faking up a user-to-user key to pass to krb5_rd_req_decode().
+	* main.c: Added code to use the new database keytab routines.
+
+Mon Dec 11 16:58:31 1995  Chris Provenzano (proven@mit.edu)
+
+	* kdc_preauth.c return_padata(): Initialize local variable "size" 
+		to 0 before using it.
+
+Thu Nov 30 20:57:11 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* kdc_preauth.c: #@&^(!! Ultrix cc sucks.  Typedef to function
+		pointer rather than function prototype to avoid lossage.
+
+Wed Nov 29 13:31:39 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* do_tgs_req.c (process_tgs_req): Removed extra eblock argument
+		from call to krb5_encode_kdc_rep.
+
+Fri Nov 17 22:41:37 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* do_as_req.c (process_as_req): Removed extra eblock argument from
+		call to krb5_encode_kdc_rep.
+
+Mon Nov 13 19:40:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdc_util.h: Added new prototypes for return_padata() and
+	        check_padata().
+
+	* kdc_preauth.c (return_padata): New function which calls out to
+		each preauth type to see if it is necessary to return
+		preauth data or not.
+	(return_pw_salt): New function responsible for returning the
+		KRB5_PW_SALT preauth information.
+
+	* do_as_req.c (process_as_req):  Move creation of the PW_SALT
+		preauthentication step into kdc_preauth.c.  Call
+		return_pdata() which is responsible for all padata info
+		which is returned by the KDC in the KRB_AS_REP message.
+
+
+Thu Nov  9 00:05:55 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdc_preauth.c (get_etype_info): Added function to return the
+		etype_info preauth hint to the client.
+
+	* kdc_util.c (get_salt_from_key): Added new function which
+		determines the salting information from the krb5_key_data
+		structure.
+
+	* main.c (kdc_initialize_rcache): Replace use of krb5_clockskew
+		with context->clockskew.
+
+Wed Nov  8 02:57:15 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdc_util.c (): Added new helper functions
+		dbentry_has_key_for_enctype(), dbentry_supports_enctype(),
+		and select_session_keytype().
+
+	* kdc_preauth.c: Added support for the ENC_TIMESTAMP
+		preauthentication scheme.
+
+	* do_tgs_req.c (process_tgs_req): Fixed the keytype/enctype
+		selection criteria for the server key, and the ticket
+		session key.
+
+	* do_as_req.c (process_as_req): Added calls to the kdc
+		preauthentication verification routines.  Fixed the
+		keytype/enctype selection criteria for the client key, the
+		server key, and the ticket session key.
+
+	* main.c (finish_realm): Make sure all parts of the realm
+		structure are freed properly.
+		(main): Free the kcontext krb5_context.
+
+Fri Oct  6 00:07:49 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdc_preauth.c (get_preauth_hint_list): Fix missing indirection
+		in get_hint_list.
+
+	* kdc_util.c (validate_as_request): Remove preauthentication
+		check; this is handled in do_as_req.c
+
+	* do_tgs_req.c (process_tgs_req): Use a slightly more compressed
+		logging format.
+
+	* do_as_req.c (process_as_req): Unify the logging and error packet
+		production, to make sure that both logging and an error
+		packet is returned for each error condition.  Pass 
+		e_data to prepare_as_error so that the proper
+		preauthentication hint list can be passed back to the client.
+
+Thu Oct  5 21:23:12 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* network.c (setup_network):
+	* main.c (initialize_realms): Massive revamp of how the network
+		ports are setup.  The default port list for a realm is
+		read from [kdcdefaults]/kdc_ports from the kdc.conf file.
+		For each realm, a list of ports can be specified in 
+		[realms]/<realm>/kdc_ports.  
+
+	* extern.h (kdc_realm_t): Remove realm_pport and realm_sport, and
+		added realm_ports.
+
+	* do_tgs_req.c (process_tgs_req):
+	* do_as_req.c (process_as_req):
+	* dispatch.c (dispatch): Pass the portnumber of the incoming
+		request down to process_as_req and process_tgs_req,
+		instead of the boolean "is_secondary".
+
+	* kerberos_v4.c (kerb_get_principal, kerberos_v4): Fix gcc -Wall
+		flames, by fixing signed vs. unsigned types.
+
+Mon Sep 18 11:16:30 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* main.c (init_realm): strdup KRB5_KDB_M_NAME if we use it, to
+	avoid free'ing a constant later.
+
+Fri Sep 15 01:33:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* main.c (init_realm): Stop after finding the first TGS key which
+		matches an entry in the key/salt list.  (Typo; added
+		missing '!')
+
+Sun Sep 10 10:51:29 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* main.c (init_realm): When checking for master key in valid
+		enctypes, do not stop after checking only the first type.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * do_as_req.c, do_tgs_req.c, kdc_util.c, kerberos_v4.c, main.c : 
+		s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * do_as_req.c, do_tgs_req.c, kerberos_v4.c, main.c: Remove krb5_enctype
+		references, and replace with krb5_keytype where appropriate.
+
+Mon Sep  4 14:10:26 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* do_as_req.c, do_tgs_req.c, kdc_util.c, kdc_util.h, policy.c: Add
+		const declarations to variables pointing to error strings
+		in order to make everything self consistant.
+
+Fri Sep  1 23:28:29 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdc_preauth.c: New file, to contain the server-side
+		preauthentication routines.
+
+	* do_as_req.c (process_as_req): Move preauthentication code to
+		kdc_preauth.c, for better modularity.
+
+	* do_as_req.c (prepare_error_as): Add new argument to this
+		function so that the e_data field may be passed in and
+		included in the KRB_ERROR messsage which is passed back to
+		the user.
+
+Mon Aug 21 17:03:53 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* main.c - Interpret -k and -e arguments as strings instead of string
+		representations of integers (e.g. -e des-cbc-md5).
+	* krb5kdc.M - Remove "ascii representation of a decimal number".
+
+
+Thu Aug 17 13:49:14 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* do_as_req.c - Close and re-open the database after performing a
+		database update.  This is the cleanest way to flush out the
+		update without reorganizing the code.
+
+Wed Aug 16 02:45:19 1995  Chris Provenzano <proven@mit.edu>
+
+        * do_as_req.c: Pass fds to krb5_lock_file() and krb5_unlock_file()
+	* do_as_req.c: Add a missing #ifdef KRBCONF_KDC_MODIFIES_KDB
+		for update_client and updating the database.
+
+Tue Aug 15 14:32:54 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* extern.h - Add key/salt list to per-realm data.
+	* main.c - Save or generate per-realm key/salt list.  Use this list
+		to determine which key to use from the list of server keys.
+		Fix gcc -Wall complaints.
+	* do_as_req.c - Batch KRBCONF_KDC_MODIFIES_KDB updates after the
+		response is issued.  Use krb5_dbe_find_keytype() to find the
+		appropriate key in the list of keys.  Find appropriate client
+		key instead of using the key in slot 0.  Fix gcc -Wall moans.
+	* kdc_util.c - Use per-realm key/salt list to determine which key to
+		use from the list of server keys.  Fix gcc -Wall complaints.
+	* kerberos_v4.c - Use krb5_dbe_find_keytype() to find appropriate key.
+		Fix gcc -Wall complaints.
+
+Thu Aug 10 14:52:24 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* do_as_req.c - Add missing variable when KRBCONF_KDC_MODIFIES_KDB on.
+
+
+Thu Aug 03 12:22:34 1995 Chris Provenzano (proven@mit.edu)
+
+	* do_as_req.c : Fix bug from new kdb changes.
+	* kerberos_v4.c : Use new db format.
+
+Thu Aug 3 11:49:35 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* do_as_req.c - Ensure that padata is null with normal salt.
+	* kerberos_v4.c - Give the compiler something to compile when Kerberos
+		V4 is disabled.
+
+Thu Jul 27 15:10:58 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add --with-vague-errors and --with-kdc-kdb-update
+		which define KRBCONF_VAGUE_ERRORS and KRBCONF_KDC_MODIFIES_KDB
+		which replace the definitions that used to be in k5-config.h.
+	* kdc_util.c - Cast argument to fetch_asn1_field which caused a
+		compiler moan.
+	* kerberos_v4.c - Use KRB5_PROTOTYPE for v4_klog which is set correctly
+		for the compiler.  Some compilers (e.g. OSF/1 native) understand
+		prototypes even when not in STDC mode.
+		Also use KRB5_MIT_DES_KEYSIZE instead of MIT_DES_KEYSIZE.
+
+
+Thu Jul 27 02:59:05 1995 Chris Provenzano (proven@mit.edu)
+
+        * do_as_req.c do_tgs_req.c kdc_util.c main.c : Use new kdb format.
+
+Mon Jul 17 15:13:09 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* main.c - Gut KDC profile handling logic and move it to lib/kadm/
+		alt_prof.c because it's now used by admin and kadmin programs.
+		Remove explicit stash file handling logic and supply stash
+		file name to krb5_db_fetch_mkey() since it can now handle a
+		non-default stash file name.
+
+Thu Jul 13 19:51:33 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* main.c: Include netinet/in.h if we're using IP.
+
+Wed Jul 12 12:19:44 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* main.c - Reorganize KDC profile handling so that the hierarchy for
+		locating per-realm data is [realms]->realm->tag.  Add
+		[kdcdefaults] section with primary_ports and secondary_ports
+		to list ports to listen on.  Consolidate all port location here
+		from network.c.  Add -s flag and change meaning of -p flag to
+		be the default if none specified in KDC or Kerberos profile.
+	* network.c - Open list of primary ports and then per-realm ports.
+		Handle secondary ports just like primary ports except that
+		bind failures are only warnings.  Support more than one
+		secondary port.
+	* extern,kdc_util.h - Add supporting definitions.
+	* krb5kdc.M - update description of -p and add description of -s.
+
+Tue Jul 11 07:35:12 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kerberos_v4.c: Add prototype for set_tgtkey
+
+Mon Jul 10 17:01:15 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kerberos_v4.c: Add prototypes for compat_decrypt_key,
+		kerb_get_principal, check_princ, v4_klog
+
+	* network.c (process_packet): Make prog a const char *. 
+
+	* main.c: Add prototypes for find_realm_data, setup_server_realm,
+		usage, request_exit, setup_signal_handlers, initialize_realms,
+			finish_realms. 
+
+	* kdc_util.h: Add prototypes for against_local_policy_as,
+		against_local_policy_tgs, validate_as_request,
+		validate_tgs_request, fetch_asn1_field,
+		kdc_initialize_rcache, process_packet.
+
+Sat Jul  8 17:40:10 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kerberos_v4.c (v4_klog): Also log L_KRB_PERR error messages, so
+		we know when there are protocol problems.
+
+Fri Jul 7 16:05:57 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling and LDFLAGS.
+	* configure.in - Add USE_<mumble> and KRB5_LIBRARIES.
+	* kdc_util.c(comp_cksum) - Use krb5_verify_checksum to verify cksum.
+
+
+Fri Jun 30 14:38:09 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add --with-dbm to select between Berkeley and DBM
+		KDC database format.
+
+Thu Jun 29 06:50:08 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* kerberos_v4.c (check_princ): delete master_key_version check,
+	since we never actually set it.
+	(main): elide original V4 server code to avoid confusion when
+	looking for variable references.
+	(type_2_v5err): reformat for 79 columns instead of 80 and
+	conditionalize out since it is unused (though still informative.)
+
+Tue Jun 27 15:59:48 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* main.c - Change profile name hierarchy storage to const char *.  Add
+		signal name argument to signal handler to conform to prototype.
+	* kerberos_v4.c - Cast key to (char *) to conform to prototype.
+
+
+Thu Jun 22 15:24:16 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* main.c - Change option parsing logic to support multiple realms.
+		Use alternate profile routines from libkadm to support reading
+		values from it.
+	* dispatch.c - Setup global realm context before calling process_as_
+		req().
+	* do_as_req.c - Change KDB_CONVERT_KEY_OUTOF_DB to decrypt_key call.
+	* do_tgs_req.c - Setup global realm context from our service principal
+		name.
+	* extern.c - Remove per-realm global data.  Replace this with list
+		of per-realm data with a pointer to the active request's realm.
+	* extern.h - Change per-realm global data names to #define's.  This
+		is to avoid having to rewrite everything to pass a pointer to
+		the active realm.
+	* kdc_util.c - Change "kdc_context" to "kcontext" because of #defines
+		in extern.h.  Also add logic after call to rd_req_decoded
+		to see if it failed because of a rcache error.  If so, then
+		reinitialize the replay cache and retry it.
+		Also change KDB_CONVERT_KEY_OUTOF_DB to decrypt_key.
+	* kerberos_v4.c - Remove extraneous definition of master_encblock.
+	* krb5kdc.M - Add definition of -p, add vague reference to kdc.conf
+		manpage and describe multiple realms briefly.
+	* network.c - Change udp_port_fd to a list of fds to support having
+		multiple ports to listen on.
+
+
+Thu Jun 15 17:55:21 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+		Also, remove DBMLIB, it was not used. Also, for K4, use
+		KRB4_LIB and KRB4_CRYPTO_LIB, these were
+                split out.
+	* configure.in - Remove dbm library checks, these are no longer needed
+		with the Berkeley database code.  Also, add shared library
+		usage check.
+
+Tue Jun 13 12:44:20 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* network.c: Base inclusion of sys/select.h on whether it exists
+        instead of a specific test for AIX.
+
+	* configure.in: Test for sys/select.h
+
+Mon Jun 12 20:01:23 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdc_util.c (kdc_process_tgs_req): Set the auth_context rcache to
+		null before freeing auth_context. This keeps the rcache
+		valid. 
+
+Sat Jun 10 23:04:31 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* kdc_util.c: krb5_auth_context redefinitions
+
+Fri Jun  9 19:13:08 1995    <tytso@rsx-11.mit.edu>
+
+	* dispatch.c, kdc_util.h, kerberos_v4.c: Use KRB5_KRB4_COMPAT
+		instead of KRB4 for determining whether to compile in
+		Kerberos V4 backwards compatibility
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Jun  8 23:35:27 1995    <tytso@rsx-11.mit.edu>
+
+	* do_as_req.c, do_tgs_req.c, kdc_util.c, kerberos_v4.c, main.c,
+		network.c: Fix -Wall nits.
+
+Thu Jun 8 14:52:40 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add libkadm.
+	* dispatch.c, do_as_req.c, do_tgs_req.c, kdc_util.c, kerberos_v4.c
+		main.c - Include adm_proto.h and change syslog calls to
+		calls to krb5_klog_syslog.
+
+Fri May 26 17:50:39 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in	- Define KDBDEPLIB.
+
+Sat May 20 22:28:52 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kerberos_v4.c: Port to OSF/1. (change longs to KRB4_32)
+
+Sat Apr 29 00:13:16 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdc_util.c (kdc_process_tgs_req): Make sure apreq->ticket gets
+		freed, since it isn't being passed back to the caller 
+		(anymore).
+
+Fri Apr 28 21:28:45 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* do_tgs_req.c (process_tgs_req): Free header_ticket when we're
+		done with it.  (Prevents massive memory leak).
+
+	* Makefile.in (depend): Use $(LD) instead of $(CC) so that we can
+		do purify checking.
+
+Fri Apr 28 18:05:52 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (KLIB): put KRB4_LIB inside KLIB.
+
+Thu Apr 27 13:52:22 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (krb5kdc): use KRB4_LIB directly.
+	* configure.in: use WITH_KRB4 as-is.
+
+Wed Apr 26 11:23:11 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: need HAS_ANSI_VOLATILE for signal_requests_exit.
+
+Sat Apr 22 00:36:37 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* network.c (setup_network): Don't rely on krb5_kdc_portname and
+		krb5_kdc_sec_portname anymore.  Use the #define'd versions.
+
+Fri Mar 31 16:50:07 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* main.c (main): Make sure the context is initialized before it is
+	  	used.
+
+Mon Mar 27 07:56:26 1995 Chris Provenzano (proven@mit.edu)
+
+	* kdc_util.c Use new calling conventions for krb5_rd_req_decoded().
+
+Fri Mar 24 14:58:07 1995    <tytso@rsx-11.mit.edu>
+
+	* replay.c: The KDC replay cache needs to store the database
+		modification time, so that if the database is modified in
+		between when it receives a request and when it receives a
+		replay of the same request, it knows to throw away the
+		replay cache entry and generate a new response (since the
+		record in the database on which the response is based may
+		have been modified). 
+
+	* main.c (kdc_com_err_proc): Use syslog() instead of vsyslog().
+
+Sat Mar 18 18:59:45 1995  John Gilmore  (gnu at toad.com)
+
+	* kerberos_v4.c:  Replace STDARG_PROTOTYPES with HAVE_STDARG_H.
+
+Tue Mar 14 15:25:38 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in, Makefile.in: Use the libdes425 library so that the
+		DES code doesn't get dragged in twice.
+
+	* kdc_util.c (validate_as_request): Allow a client to obtain a
+		password changing ticket, even if the client's key is
+		expired.
+
+	* main.c (usage, process_args, main): The KDC will disassociate
+		itself from the terminal by default, unless the -n option
+		is given.
+
+Thu Mar  2 12:16:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:30:27 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE and ISODE_DEFS, replace check
+		for -lsocket and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 02:27:11 1995  John Gilmore  (gnu at toad.com)
+
+	* *.[ch]:  Avoid <krb5/...> and <com_err.h> includes.
+
+Fri Feb 10 14:35:42 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* do_tgs_req.c (process_tgs_req): krb5_use_keytype() was being
+		called when the argument was a encryption type.   Change
+		use to krb5_use_cstype().  Actually, any use of
+		krb5_use_keytype() is a bug by definition.
+
+Wed Feb 01 21:07:03 1995  Chris Provenzano (proven@mit.edu)
+
+	* kdc_util.c (kdc_rdreq_keyproc()) Add krb5_keytype() arg.
+
+Wed Jan 25 23:20:07 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* network.c (setup_network), main.c (process_args): Allow the
+		primary port that the KDC listens on be configurable on the
+		command line.  If the appropriate /etc/services entries
+		aren't found, use compiled in defaults.
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+        * Removed all narrow types and references to wide.h and narrow.h
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Thu Dec  8 00:33:05 1994    <tytso@rsx-11.mit.edu>
+
+	* do_tgs_req.c (prepare_error_tgs): Don't free the passed in
+		ticket; it will be freed as part of other structures.
+
+	* do_tgs_req.c (process_tgs_req): Set the encryption type in the
+		reply structure, and set the eblock type accordingly.
+
+Wed Dec  7 13:36:34 1994    <tytso@rsx-11.mit.edu>
+
+	* do_as_req.c (process_as_req): Set the encryption type in the
+		reply_encpart structure.
+
+	* kdc_util.c (validate_as_request): 
+	* policy.c (against_local_policy_as): Move requirement that an AS
+		request must include the addresses field to the local
+		policy routine.  (Not required by RFC).
+
+	* main.c (setup_com_err): Initialize the kdc5 error table (the
+		kdb5 error table is already initialized)
+
+Wed Nov 30 16:37:26 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* confiugre.in: Add appropriate help text for --with-krb4
+		option.
+
+Mon Nov 21 17:23:50 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* do_tgs_req.c (process_tgs_req):
+	* do_as_req.c (process_as_req): Use the list of encryption types
+		passed as part of the KDC request to determine which
+		encryption to use for encrypting the ticket.  The
+		encryption must be one that is supported by the KDC, as
+		well as being one which is marked as being supported by
+		the server of the ticket.  In a AS request, also use this
+		encryption for encrypting the KDC response.  In a TGS
+		request, use the encryption type of the TGT authenticator
+		to determine how to encrypt the KDC response. 
+
+Tue Nov  8 17:51:30 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* do_tgs_req.c (process_tgs_req): Use published interface to call
+		krb5_random_key().
+
+Mon Nov  7 22:11:01 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kerberos_v4.c: Don't define functions manually, but pull in the
+	appropriate include files (com_err.h, krb5/ext-proto.h,
+	krb5/los-proto.h, etc.)
+
+	* kdc_util.c (kdc_process_tgs_req): Fix lineage check so that we
+		don't fail if we're cross-authenticating with a realm with
+		the same length as our own.  ('||' should have been '&&')
+
+Fri Nov  4 17:47:46 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* do_as_req.c (process_as_req): Use published interface to call
+		krb5_random_key().
+
+Fri Oct 14 00:31:14 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* main.c (process_args): Select the cryptosystem to be used using
+		krb5_use_cstype() instead of using a implementation
+		specific assignment.  Also, allow the encryption type to
+		be specified using a command line option.
+
+Tue Oct 11 22:11:09 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* do_as_req.c (process_as_req): Don't assume that the request
+		server's realm name is null terminated.  Compare the
+		request server against changepw/kerberos using
+		krb5_principal_compare.
+
+Tue Oct  4 16:42:16 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdc_util.c (kdc_rdreq_keyproc): Add widen.h and narrow.h around
+		keyproc call so that the argument types are widened.
+
+Mon Oct  3 13:13:48 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
+	* Makefile.in: Remove krb5kdc on make clean
+
+Fri Sep 30 22:13:13 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* extern.c: Add placeholder for magic number
+
+Thu Sep 29 00:03:59 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executable when library changes.
+
+Wed Sep 21 17:40:56 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdc_util.c, kdc_util.h (realm_compare): Change realm_compare so
+		that both arguments are principals.  This makes it less
+		confusing....
+
+	* kdc_util.c (add_to_transited): Folded in Tony Andrea's changes
+		so that add_to_transited doesn't assume that the contents
+		of a krb5_data->data are null terminated.
+
+	* do_tgs_req.c (process_tgs_req): Add the realm of the presented
+	  tgt if it is different from the local realm (cross-realm) and it
+	  is different than the realm of the client (since the realm of
+	  the client is already implicitly part of the transited list and
+	  should not be explicitly listed).
+
+Thu Aug 18 18:17:59 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* configure.in:
+	* Makefile.in: Move optional link with $(KRB4)/lib/libdes.a to
+	configure.in.
+
+Thu Aug  4 15:13:27 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in:
+	* kerberos_v4.c: don't include <sgtty.h> if POSIX_TERMIOS is
+	defined.
+
+Sat Jul 16 09:16:33 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in: hopefully make dbm libs dtrt
+
+Sat Jul 16 01:59:02 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* do_as_req.c: Sanitie error return codes
+	* kdc_util.c (validate_tgs_request): Fix error handling for bogus
+	TGS renew/forward/etc. requests.  Sanitize error return codes.
+
+Fri Jul  8 00:33:45 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in:
+	* Makefile.in: back out changes because of possible breakage under
+	Ultrix, among other things
+
+Wed Jul  6 22:54:59 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in:
+	* Makefile.in: fixes to suck in -lndbm or -ldbm if needed
+
+Tue Jun 28 19:43:54 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* main.c: fix explicit calls to initialize_foo_error_table
+
+	* do_tgs_req.c:
+	* configure.in: folding in Harry's changes
+
diff --git a/mechglue/src/kdc/Makefile.in b/mechglue/src/kdc/Makefile.in
new file mode 100644
index 000000000..a77d323c6
--- /dev/null
+++ b/mechglue/src/kdc/Makefile.in
@@ -0,0 +1,192 @@
+thisconfigdir=..
+myfulldir=kdc
+mydir=kdc
+BUILDTOP=$(REL)..
+# -DUSE_RCACHE - enable replay cache for KDC
+# -DNOCACHE    - disable lookaside cache, which is used to resend previous
+#                response to replay (i.e., *don't* define this if you
+#                define USE_RCACHE)
+# These are now set in configure.in.
+DEFINES = # -DNOCACHE
+RUN_SETUP = @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD) $(KRB4_LIBPATH)
+KDB5_LIB_DEPS=$(DL_LIB) $(THREAD_LINKOPTS)
+PROG_RPATH=$(KRB5_LIBDIR)
+FAKEKA=@FAKEKA@
+
+all:: krb5kdc rtest $(FAKEKA)
+
+# DEFINES = -DBACKWARD_COMPAT $(KRB4DEF)
+
+LOCALINCLUDES = @KRB4_INCLUDES@ -I.
+SRCS= \
+	kdc5_err.c \
+	$(srcdir)/dispatch.c \
+	$(srcdir)/do_as_req.c \
+	$(srcdir)/do_tgs_req.c \
+	$(srcdir)/kdc_util.c \
+	$(srcdir)/kdc_preauth.c \
+	$(SRCTOP)/lib/kadm5/logger.c \
+	$(srcdir)/main.c \
+	$(srcdir)/network.c \
+	$(srcdir)/policy.c \
+	$(srcdir)/extern.c \
+	$(srcdir)/replay.c \
+	$(srcdir)/kerberos_v4.c
+
+OBJS= \
+	kdc5_err.o \
+	dispatch.o \
+	do_as_req.o \
+	do_tgs_req.o \
+	kdc_util.o \
+	kdc_preauth.o \
+	logger.o \
+	main.o \
+	network.o \
+	policy.o \
+	extern.o \
+	replay.o \
+	kerberos_v4.o
+
+RT_OBJS= rtest.o \
+	kdc_util.o \
+	policy.o \
+	extern.o
+
+depend:: kdc5_err.c
+
+logger.c: $(SRCTOP)/lib/kadm5/logger.c
+	$(RM) $@
+	$(CP) $(SRCTOP)/lib/kadm5/logger.c $@
+
+logger.o: logger.c
+
+kdc5_err.c: kdc5_err.et
+
+kdc5_err.h: kdc5_err.et
+
+kdc5_err.o: kdc5_err.h
+
+krb5kdc: $(OBJS) $(KADMSRV_DEPLIBS) $(KRB4COMPAT_DEPLIBS) $(APPUTILS_DEPLIB)
+	$(CC_LINK) -o krb5kdc $(OBJS) $(KADMSRV_LIBS) $(KDB5_LIB_DEPS) $(KRB4COMPAT_LIBS) $(APPUTILS_LIB)
+
+rtest: $(RT_OBJS) $(KDB5_DEPLIBS) $(KADM_COMM_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o rtest $(RT_OBJS) $(KDB5_LIBS) $(KDB5_LIB_DEPS) $(KADM_COMM_LIBS) $(KRB5_BASE_LIBS)
+
+fakeka: fakeka.o $(KADMSRV_DEPLIBS) $(KRB4COMPAT_DEPLIBS) $(APPUTILS_DEPLIB)
+	$(CC_LINK) -o fakeka fakeka.o $(KADMSRV_LIBS) $(KRB4COMPAT_LIBS) $(APPUTILS_LIB)
+
+check-unix:: rtest
+	KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ;\
+	$(RUN_SETUP) $(srcdir)/rtscript > test.out
+	cmp test.out $(srcdir)/rtest.good
+	$(RM) test.out
+
+install::
+	$(INSTALL_PROGRAM) krb5kdc ${DESTDIR}$(SERVER_BINDIR)/krb5kdc
+	$(INSTALL_DATA) $(srcdir)/krb5kdc.M ${DESTDIR}$(SERVER_MANDIR)/krb5kdc.8
+	f=$(FAKEKA); \
+	if test -n "$$f" ; then \
+		$(INSTALL_PROGRAM) $$f ${DESTDIR}$(SERVER_BINDIR)/$$f; \
+	fi
+
+clean::
+	$(RM) kdc5_err.h kdc5_err.c krb5kdc logger.c rtest.o rtest
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)kdc5_err.$(OBJEXT): kdc5_err.c $(COM_ERR_DEPS)
+$(OUTPRE)dispatch.$(OBJEXT): dispatch.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/syslog.h \
+  kdc_util.h extern.h $(SRCTOP)/include/krb5/adm_proto.h
+$(OUTPRE)do_as_req.$(OBJEXT): do_as_req.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/syslog.h \
+  kdc_util.h policy.h $(SRCTOP)/include/krb5/adm.h $(SRCTOP)/include/krb5/adm_proto.h \
+  extern.h
+$(OUTPRE)do_tgs_req.$(OBJEXT): do_tgs_req.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/syslog.h \
+  kdc_util.h policy.h extern.h $(SRCTOP)/include/krb5/adm_proto.h
+$(OUTPRE)kdc_util.$(OBJEXT): kdc_util.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h kdc_util.h extern.h $(SRCTOP)/include/syslog.h \
+  $(SRCTOP)/include/krb5/adm.h $(SRCTOP)/include/krb5/adm_proto.h
+$(OUTPRE)kdc_preauth.$(OBJEXT): kdc_preauth.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h kdc_util.h extern.h $(SRCTOP)/include/krb5/adm_proto.h \
+  $(SRCTOP)/include/syslog.h
+$(OUTPRE)logger.$(OBJEXT): $(SRCTOP)/lib/kadm5/logger.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/krb5/adm_proto.h $(SRCTOP)/include/syslog.h
+$(OUTPRE)main.$(OBJEXT): main.c $(SRCTOP)/include/syslog.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/krb5/adm.h $(SRCTOP)/include/krb5/adm_proto.h \
+  kdc_util.h extern.h kdc5_err.h $(SRCTOP)/include/krb5/kdb_kt.h \
+  $(SRCTOP)/include/kerberosIV/des.h
+$(OUTPRE)network.$(OBJEXT): network.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h kdc_util.h extern.h kdc5_err.h \
+  $(SRCTOP)/include/krb5/adm_proto.h $(SRCTOP)/include/syslog.h \
+  $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/cm.h \
+  $(SRCTOP)/include/foreachaddr.h
+$(OUTPRE)policy.$(OBJEXT): policy.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h kdc_util.h
+$(OUTPRE)extern.$(OBJEXT): extern.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h extern.h
+$(OUTPRE)replay.$(OBJEXT): replay.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h kdc_util.h extern.h
+$(OUTPRE)kerberos_v4.$(OBJEXT): kerberos_v4.c $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h kdc_util.h $(SRCTOP)/include/krb5/adm_proto.h \
+  $(SRCTOP)/include/syslog.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(SRCTOP)/include/kerberosIV/klog.h $(SRCTOP)/include/kerberosIV/prot.h \
+  $(SRCTOP)/include/kerberosIV/krb_db.h $(SRCTOP)/include/kerberosIV/kdc.h \
+  extern.h
diff --git a/mechglue/src/kdc/dispatch.c b/mechglue/src/kdc/dispatch.c
new file mode 100644
index 000000000..0432661d7
--- /dev/null
+++ b/mechglue/src/kdc/dispatch.c
@@ -0,0 +1,115 @@
+/*
+ * kdc/dispatch.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Dispatch an incoming packet.
+ */
+
+#include "k5-int.h"
+#include <syslog.h>
+#include "kdc_util.h"
+#include "extern.h"
+#include "adm_proto.h"
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+static krb5_int32 last_usec = 0, last_os_random = 0;
+
+krb5_error_code
+dispatch(krb5_data *pkt, const krb5_fulladdr *from, krb5_data **response)
+{
+
+    krb5_error_code retval;
+    krb5_kdc_req *as_req;
+    krb5_int32 now, now_usec;
+    
+    /* decode incoming packet, and dispatch */
+
+#ifndef NOCACHE
+    /* try the replay lookaside buffer */
+    if (kdc_check_lookaside(pkt, from, response)) {
+	/* a hit! */
+	const char *name = 0;
+	char buf[46];
+
+	name = inet_ntop (ADDRTYPE2FAMILY (from->address->addrtype),
+			  from->address->contents, buf, sizeof (buf));
+	if (name == 0)
+	    name = "[unknown address type]";
+	krb5_klog_syslog(LOG_INFO,
+			 "DISPATCH: repeated (retransmitted?) request from %s, resending previous response",
+			 name);
+	return 0;
+    }
+#endif
+    retval = krb5_crypto_us_timeofday(&now, &now_usec);
+    if (retval == 0) {
+      krb5_int32 usec_difference = now_usec-last_usec;
+      krb5_data data;
+      if(last_os_random == 0)
+	last_os_random = now;
+      /* Grab random data from OS every hour*/
+      if(now-last_os_random >= 60*60) {
+	krb5_c_random_os_entropy(kdc_context, 0, NULL);
+	last_os_random = now;
+      }
+      
+      data.length = sizeof(krb5_int32);
+      data.data = (void *) &usec_difference;
+      
+      krb5_c_random_add_entropy(kdc_context,
+				KRB5_C_RANDSOURCE_TIMING, &data);
+      last_usec = now_usec;
+    }
+    /* try TGS_REQ first; they are more common! */
+
+    if (krb5_is_tgs_req(pkt)) {
+	retval = process_tgs_req(pkt, from, response);
+    } else if (krb5_is_as_req(pkt)) {
+	if (!(retval = decode_krb5_as_req(pkt, &as_req))) {
+	    /*
+	     * setup_server_realm() sets up the global realm-specific data
+	     * pointer.
+	     */
+	    if (!(retval = setup_server_realm(as_req->server))) {
+		retval = process_as_req(as_req, from, response);
+	    }
+	    krb5_free_kdc_req(kdc_context, as_req);
+	}
+    }
+#ifdef KRB5_KRB4_COMPAT
+    else if (pkt->data[0] == 4)		/* old version */
+	retval = process_v4(pkt, from, response);
+#endif
+    else
+	retval = KRB5KRB_AP_ERR_MSG_TYPE;
+#ifndef NOCACHE
+    /* put the response into the lookaside buffer */
+    if (!retval)
+	kdc_insert_lookaside(pkt, from, *response);
+#endif
+
+    return retval;
+}
diff --git a/mechglue/src/kdc/do_as_req.c b/mechglue/src/kdc/do_as_req.c
new file mode 100644
index 000000000..2916cfee0
--- /dev/null
+++ b/mechglue/src/kdc/do_as_req.c
@@ -0,0 +1,532 @@
+/*
+ * kdc/do_as_req.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * KDC Routines to deal with AS_REQ's
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+
+#include <syslog.h>
+#ifdef HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif	/* hpux */
+#endif /* HAVE_NETINET_IN_H */
+
+#include "kdc_util.h"
+#include "policy.h"
+#include "adm.h"
+#include "adm_proto.h"
+#include "extern.h"
+
+static krb5_error_code prepare_error_as (krb5_kdc_req *, int, krb5_data *, 
+					 krb5_data **, const char *);
+
+/*ARGSUSED*/
+krb5_error_code
+process_as_req(krb5_kdc_req *request, const krb5_fulladdr *from,
+	       krb5_data **response)
+{
+    krb5_db_entry client, server;
+    krb5_kdc_rep reply;
+    krb5_enc_kdc_rep_part reply_encpart;
+    krb5_ticket ticket_reply;
+    krb5_enc_tkt_part enc_tkt_reply;
+    krb5_error_code errcode;
+    int c_nprincs = 0, s_nprincs = 0;
+    krb5_boolean more;
+    krb5_timestamp kdc_time, authtime;
+    krb5_keyblock session_key;
+    krb5_keyblock encrypting_key;
+    const char *status;
+    krb5_key_data  *server_key, *client_key;
+    krb5_enctype useenctype;
+#ifdef	KRBCONF_KDC_MODIFIES_KDB
+    krb5_boolean update_client = 0;
+#endif	/* KRBCONF_KDC_MODIFIES_KDB */
+    krb5_data e_data;
+    register int i;
+    krb5_timestamp until, rtime;
+    char *cname = 0, *sname = 0;
+    const char *fromstring = 0;
+    char ktypestr[128];
+    char rep_etypestr[128];
+    char fromstringbuf[70];
+
+    ticket_reply.enc_part.ciphertext.data = 0;
+    e_data.data = 0;
+    encrypting_key.contents = 0;
+    reply.padata = 0;
+    session_key.contents = 0;
+
+    ktypes2str(ktypestr, sizeof(ktypestr),
+	       request->nktypes, request->ktype);
+
+    fromstring = inet_ntop(ADDRTYPE2FAMILY (from->address->addrtype),
+			   from->address->contents,
+			   fromstringbuf, sizeof(fromstringbuf));
+    if (!fromstring)
+	fromstring = "<unknown>";
+
+    if (!request->client) {
+	status = "NULL_CLIENT";
+	errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+	goto errout;
+    }
+    if ((errcode = krb5_unparse_name(kdc_context, request->client, &cname))) {
+	status = "UNPARSING_CLIENT";
+	goto errout;
+    }
+    limit_string(cname);
+    if (!request->server) {
+	status = "NULL_SERVER";
+	errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+	goto errout;
+    }
+    if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
+	status = "UNPARSING_SERVER";
+	goto errout;
+    }
+    limit_string(sname);
+    
+    c_nprincs = 1;
+    if ((errcode = krb5_db_get_principal(kdc_context, request->client,
+					 &client, &c_nprincs, &more))) {
+	status = "LOOKING_UP_CLIENT";
+	c_nprincs = 0;
+	goto errout;
+    }
+    if (more) {
+	status = "NON-UNIQUE_CLIENT";
+	errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
+	goto errout;
+    } else if (c_nprincs != 1) {
+	status = "CLIENT_NOT_FOUND";
+#ifdef KRBCONF_VAGUE_ERRORS
+	errcode = KRB5KRB_ERR_GENERIC;
+#else
+	errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+#endif
+	goto errout;
+    }
+    
+    s_nprincs = 1;
+    if ((errcode = krb5_db_get_principal(kdc_context, request->server, &server,
+					 &s_nprincs, &more))) {
+	status = "LOOKING_UP_SERVER";
+	goto errout;
+    }
+    if (more) {
+	status = "NON-UNIQUE_SERVER";
+	errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
+	goto errout;
+    } else if (s_nprincs != 1) {
+	status = "SERVER_NOT_FOUND";
+	errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+	goto errout;
+    }
+
+    if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) {
+	status = "TIMEOFDAY";
+	goto errout;
+    }
+
+    if ((errcode = validate_as_request(request, client, server,
+				      kdc_time, &status))) {
+	if (!status) 
+	    status = "UNKNOWN_REASON";
+	errcode += ERROR_TABLE_BASE_krb5;
+	goto errout;
+    }
+      
+    /*
+     * Select the keytype for the ticket session key.
+     */
+    if ((useenctype = select_session_keytype(kdc_context, &server,
+					     request->nktypes,
+					     request->ktype)) == 0) {
+	/* unsupported ktype */
+	status = "BAD_ENCRYPTION_TYPE";
+	errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+	goto errout;
+    }
+
+    if ((errcode = krb5_c_make_random_key(kdc_context, useenctype,
+					  &session_key))) {
+	status = "RANDOM_KEY_FAILED";
+	goto errout;
+    }
+
+    ticket_reply.server = request->server;
+
+    enc_tkt_reply.flags = 0;
+    setflag(enc_tkt_reply.flags, TKT_FLG_INITIAL);
+
+    	/* It should be noted that local policy may affect the  */
+        /* processing of any of these flags.  For example, some */
+        /* realms may refuse to issue renewable tickets         */
+
+    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
+	setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
+
+    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE))
+	    setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
+
+    if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
+	    setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
+
+    enc_tkt_reply.session = &session_key;
+    enc_tkt_reply.client = request->client;
+    enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
+    enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
+
+    enc_tkt_reply.times.authtime = kdc_time;
+
+    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
+	setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
+	setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
+	enc_tkt_reply.times.starttime = request->from;
+    } else
+	enc_tkt_reply.times.starttime = kdc_time;
+    
+    until = (request->till == 0) ? kdc_infinity : request->till;
+
+    enc_tkt_reply.times.endtime =
+	min(until,
+	    min(enc_tkt_reply.times.starttime + client.max_life,
+		min(enc_tkt_reply.times.starttime + server.max_life,
+		    enc_tkt_reply.times.starttime + max_life_for_realm)));
+
+    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
+	!isflagset(client.attributes, KRB5_KDB_DISALLOW_RENEWABLE) &&
+	(enc_tkt_reply.times.endtime < request->till)) {
+
+	/* we set the RENEWABLE option for later processing */
+
+	setflag(request->kdc_options, KDC_OPT_RENEWABLE);
+	request->rtime = request->till;
+    }
+    rtime = (request->rtime == 0) ? kdc_infinity : request->rtime;
+
+    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) {
+	/*
+	 * XXX Should we squelch the output renew_till to be no
+	 * earlier than the endtime of the ticket? 
+	 */
+	setflag(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
+	enc_tkt_reply.times.renew_till =
+	    min(rtime, enc_tkt_reply.times.starttime +
+		       min(client.max_renewable_life,
+			   min(server.max_renewable_life,
+			       max_renewable_life_for_realm)));
+    } else
+	enc_tkt_reply.times.renew_till = 0; /* XXX */
+
+    /* starttime is optional, and treated as authtime if not present.
+       so we can nuke it if it matches */
+    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
+	enc_tkt_reply.times.starttime = 0;
+
+    enc_tkt_reply.caddrs = request->addresses;
+    enc_tkt_reply.authorization_data = 0;
+
+    /* 
+     * Check the preauthentication if it is there.
+     */
+    if (request->padata) {
+	errcode = check_padata(kdc_context, &client, request, &enc_tkt_reply);
+	if (errcode) {
+#ifdef KRBCONF_KDC_MODIFIES_KDB
+	    /*
+	     * Note: this doesn't work if you're using slave servers!!!
+	     * It also causes the database to be modified (and thus
+	     * need to be locked) frequently.
+	     */
+	    if (client.fail_auth_count < KRB5_MAX_FAIL_COUNT) {
+		client.fail_auth_count = client.fail_auth_count + 1;
+		if (client.fail_auth_count == KRB5_MAX_FAIL_COUNT) { 
+		    client.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
+		}
+	    }
+	    client.last_failed = kdc_time;
+	    update_client = 1;
+#endif
+	    status = "PREAUTH_FAILED";
+#ifdef KRBCONF_VAGUE_ERRORS
+	    errcode = KRB5KRB_ERR_GENERIC;
+#endif
+	    goto errout;
+	} 
+    }
+
+    /*
+     * Final check before handing out ticket: If the client requires
+     * preauthentication, verify that the proper kind of
+     * preauthentication was carried out.
+     */
+    status = missing_required_preauth(&client, &server, &enc_tkt_reply);
+    if (status) {
+	errcode = KRB5KDC_ERR_PREAUTH_REQUIRED;
+	get_preauth_hint_list(request, &client, &server, &e_data);
+	goto errout;
+    }
+
+    ticket_reply.enc_part2 = &enc_tkt_reply;
+
+    /*
+     * Find the server key
+     */
+    if ((errcode = krb5_dbe_find_enctype(kdc_context, &server,
+					 -1, /* ignore keytype */
+					 -1,		/* Ignore salttype */
+					 0,		/* Get highest kvno */
+					 &server_key))) {
+	status = "FINDING_SERVER_KEY";
+	goto errout;
+    }
+
+    /* convert server.key into a real key (it may be encrypted
+       in the database) */
+    if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock, 
+					       server_key, &encrypting_key,
+					       NULL))) {
+	status = "DECRYPT_SERVER_KEY";
+	goto errout;
+    }
+	
+    errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key, &ticket_reply);
+    krb5_free_keyblock_contents(kdc_context, &encrypting_key);
+    encrypting_key.contents = 0;
+    if (errcode) {
+	status = "ENCRYPTING_TICKET";
+	goto errout;
+    }
+    ticket_reply.enc_part.kvno = server_key->key_data_kvno;
+
+    /*
+     * Find the appropriate client key.  We search in the order specified
+     * by request keytype list.
+     */
+    client_key = (krb5_key_data *) NULL;
+    for (i = 0; i < request->nktypes; i++) {
+	useenctype = request->ktype[i];
+	if (!krb5_c_valid_enctype(useenctype))
+	    continue;
+
+	if (!krb5_dbe_find_enctype(kdc_context, &client, useenctype, -1,
+				   0, &client_key))
+	    break;
+    }
+    if (!(client_key)) {
+	/* Cannot find an appropriate key */
+	status = "CANT_FIND_CLIENT_KEY";
+	errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+	goto errout;
+    }
+
+    /* convert client.key_data into a real key */
+    if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock, 
+					       client_key, &encrypting_key,
+					       NULL))) {
+	status = "DECRYPT_CLIENT_KEY";
+	goto errout;
+    }
+    encrypting_key.enctype = useenctype;
+
+    /* Start assembling the response */
+    reply.msg_type = KRB5_AS_REP;
+    reply.client = request->client;
+    reply.ticket = &ticket_reply;
+    reply_encpart.session = &session_key;
+    if ((errcode = fetch_last_req_info(&client, &reply_encpart.last_req))) {
+	status = "FETCH_LAST_REQ";
+	goto errout;
+    }
+    reply_encpart.nonce = request->nonce;
+    reply_encpart.key_exp = client.expiration;
+    reply_encpart.flags = enc_tkt_reply.flags;
+    reply_encpart.server = ticket_reply.server;
+
+    /* copy the time fields EXCEPT for authtime; it's location
+       is used for ktime */
+    reply_encpart.times = enc_tkt_reply.times;
+    reply_encpart.times.authtime = authtime = kdc_time;
+
+    reply_encpart.caddrs = enc_tkt_reply.caddrs;
+
+    /* Fetch the padata info to be returned */
+    errcode = return_padata(kdc_context, &client, request, &reply, client_key,
+			    &encrypting_key);
+    if (errcode) {
+	status = "KDC_RETURN_PADATA";
+	goto errout;
+    }
+
+    /* now encode/encrypt the response */
+
+    reply.enc_part.enctype = encrypting_key.enctype;
+
+    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart, 
+				  0, &encrypting_key,  &reply, response);
+    krb5_free_keyblock_contents(kdc_context, &encrypting_key);
+    encrypting_key.contents = 0;
+    reply.enc_part.kvno = client_key->key_data_kvno;
+
+    if (errcode) {
+	status = "ENCODE_KDC_REP";
+	goto errout;
+    }
+    
+    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
+       can use them in raw form if needed.  But, we don't... */
+    memset(reply.enc_part.ciphertext.data, 0, reply.enc_part.ciphertext.length);
+    free(reply.enc_part.ciphertext.data);
+
+    rep_etypes2str(rep_etypestr, sizeof(rep_etypestr), &reply);
+    krb5_klog_syslog(LOG_INFO,
+		     "AS_REQ (%s) %s: ISSUE: authtime %d, "
+		     "%s, %s for %s",
+		     ktypestr,
+	             fromstring, authtime,
+		     rep_etypestr,
+		     cname, sname);
+
+#ifdef	KRBCONF_KDC_MODIFIES_KDB
+    /*
+     * If we get this far, we successfully did the AS_REQ.
+     */
+    client.last_success = kdc_time;
+    client.fail_auth_count = 0;
+    update_client = 1;
+#endif	/* KRBCONF_KDC_MODIFIES_KDB */
+
+errout:
+    if (status)
+        krb5_klog_syslog(LOG_INFO, "AS_REQ (%s) %s: %s: %s for %s%s%s",
+			 ktypestr,
+	       fromstring, status, 
+	       cname ? cname : "<unknown client>",
+	       sname ? sname : "<unknown server>",
+	       errcode ? ", " : "",
+	       errcode ? error_message(errcode) : "");
+    if (errcode) {
+	if (status == 0)
+	    status = error_message (errcode);
+	errcode -= ERROR_TABLE_BASE_krb5;
+	if (errcode < 0 || errcode > 128)
+	    errcode = KRB_ERR_GENERIC;
+	    
+	errcode = prepare_error_as(request, errcode, &e_data, response,
+				   status);
+    }
+
+    if (encrypting_key.contents)
+	krb5_free_keyblock_contents(kdc_context, &encrypting_key);
+    if (reply.padata)
+	krb5_free_pa_data(kdc_context, reply.padata);
+
+    if (cname)
+	    free(cname);
+    if (sname)
+	    free(sname);
+    if (c_nprincs) {
+#ifdef	KRBCONF_KDC_MODIFIES_KDB
+	if (update_client) {
+	    krb5_db_put_principal(kdc_context, &client, &c_nprincs);
+	    /*
+	     * ptooey.  We want krb5_db_sync() or something like that.
+	     */
+	    krb5_db_fini(kdc_context);
+	    if (kdc_active_realm->realm_dbname)
+		krb5_db_set_name(kdc_active_realm->realm_context,
+				 kdc_active_realm->realm_dbname);
+	    krb5_db_init(kdc_context);
+	    /* Reset master key */
+	    krb5_db_set_mkey(kdc_context, &kdc_active_realm->realm_mkey);
+	}
+#endif	/* KRBCONF_KDC_MODIFIES_KDB */
+	krb5_db_free_principal(kdc_context, &client, c_nprincs);
+    }
+    if (s_nprincs)
+	krb5_db_free_principal(kdc_context, &server, s_nprincs);
+    if (session_key.contents)
+	krb5_free_keyblock_contents(kdc_context, &session_key);
+    if (ticket_reply.enc_part.ciphertext.data) {
+	memset(ticket_reply.enc_part.ciphertext.data , 0,
+	       ticket_reply.enc_part.ciphertext.length);
+	free(ticket_reply.enc_part.ciphertext.data);
+    }
+
+    krb5_free_data_contents(kdc_context, &e_data);
+    
+    return errcode;
+}
+
+static krb5_error_code
+prepare_error_as (krb5_kdc_req *request, int error, krb5_data *e_data,
+		  krb5_data **response, const char *status)
+{
+    krb5_error errpkt;
+    krb5_error_code retval;
+    krb5_data *scratch;
+    
+    errpkt.ctime = request->nonce;
+    errpkt.cusec = 0;
+
+    if ((retval = krb5_us_timeofday(kdc_context, &errpkt.stime,
+				    &errpkt.susec)))
+	return(retval);
+    errpkt.error = error;
+    errpkt.server = request->server;
+    errpkt.client = request->client;
+    errpkt.text.length = strlen(status)+1;
+    if (!(errpkt.text.data = malloc(errpkt.text.length)))
+	return ENOMEM;
+    (void) strcpy(errpkt.text.data, status);
+
+    if (!(scratch = (krb5_data *)malloc(sizeof(*scratch)))) {
+	free(errpkt.text.data);
+	return ENOMEM;
+    }
+    if (e_data && e_data->data) {
+	errpkt.e_data = *e_data;
+    } else {
+	errpkt.e_data.length = 0;
+	errpkt.e_data.data = 0;
+    }
+
+    retval = krb5_mk_error(kdc_context, &errpkt, scratch);
+    free(errpkt.text.data);
+    if (retval)
+	free(scratch);
+    else 
+	*response = scratch;
+
+    return retval;
+}
diff --git a/mechglue/src/kdc/do_tgs_req.c b/mechglue/src/kdc/do_tgs_req.c
new file mode 100644
index 000000000..d85d4b58c
--- /dev/null
+++ b/mechglue/src/kdc/do_tgs_req.c
@@ -0,0 +1,816 @@
+/*
+ * kdc/do_tgs_req.c
+ *
+ * Copyright 1990,1991,2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * KDC Routines to deal with TGS_REQ's
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+
+#include <syslog.h>
+#ifdef HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+#endif
+
+#include "kdc_util.h"
+#include "policy.h"
+#include "extern.h"
+#include "adm_proto.h"
+
+
+static void find_alternate_tgs (krb5_kdc_req *, krb5_db_entry *,
+				krb5_boolean *, int *);
+
+static krb5_error_code prepare_error_tgs (krb5_kdc_req *, krb5_ticket *,
+					  int, const char *, krb5_data **,
+					  const char *);
+
+/*ARGSUSED*/
+krb5_error_code
+process_tgs_req(krb5_data *pkt, const krb5_fulladdr *from,
+		krb5_data **response)
+{
+    krb5_keyblock * subkey;
+    krb5_kdc_req *request = 0;
+    krb5_db_entry server;
+    krb5_kdc_rep reply;
+    krb5_enc_kdc_rep_part reply_encpart;
+    krb5_ticket ticket_reply, *header_ticket = 0;
+    int st_idx = 0;
+    krb5_enc_tkt_part enc_tkt_reply;
+    krb5_transited enc_tkt_transited;
+    int newtransited = 0;
+    krb5_error_code retval = 0;
+    int nprincs = 0;
+    krb5_boolean more;
+    krb5_timestamp kdc_time, authtime=0;
+    krb5_keyblock session_key;
+    krb5_timestamp until, rtime;
+    krb5_keyblock encrypting_key;
+    krb5_key_data  *server_key;
+    char *cname = 0, *sname = 0, *tmp = 0;
+    const char *fromstring = 0;
+    krb5_last_req_entry *nolrarray[2], nolrentry;
+/*    krb5_address *noaddrarray[1]; */
+    krb5_enctype useenctype;
+    int	errcode, errcode2;
+    register int i;
+    int firstpass = 1;
+    const char	*status = 0;
+    char ktypestr[128];
+    char rep_etypestr[128];
+    char fromstringbuf[70];
+
+    session_key.contents = 0;
+    
+    retval = decode_krb5_tgs_req(pkt, &request);
+    if (retval)
+	return retval;
+
+    ktypes2str(ktypestr, sizeof(ktypestr),
+	       request->nktypes, request->ktype);
+    /*
+     * setup_server_realm() sets up the global realm-specific data pointer.
+     */
+    if ((retval = setup_server_realm(request->server)))
+	return retval;
+
+    fromstring = inet_ntop(ADDRTYPE2FAMILY(from->address->addrtype),
+			   from->address->contents,
+			   fromstringbuf, sizeof(fromstringbuf));
+    if (!fromstring)
+	fromstring = "<unknown>";
+
+    if ((errcode = krb5_unparse_name(kdc_context, request->server, &sname))) {
+	status = "UNPARSING SERVER";
+	goto cleanup;
+    }
+    limit_string(sname);
+
+   /* errcode = kdc_process_tgs_req(request, from, pkt, &req_authdat); */
+    errcode = kdc_process_tgs_req(request, from, pkt, &header_ticket, &subkey);
+
+    if (header_ticket && header_ticket->enc_part2 &&
+	(errcode2 = krb5_unparse_name(kdc_context, 
+				      header_ticket->enc_part2->client,
+				      &cname))) {
+	status = "UNPARSING CLIENT";
+	errcode = errcode2;
+	goto cleanup;
+    }
+    limit_string(cname);
+    
+    if (errcode) {
+	status = "PROCESS_TGS";
+	goto cleanup;
+    }
+
+    if (!header_ticket) {
+	errcode = KRB5_NO_TKT_SUPPLIED;	/* XXX? */
+	status="UNEXPECTED NULL in header_ticket";
+	goto cleanup;
+    }
+    
+    /*
+     * We've already dealt with the AP_REQ authentication, so we can
+     * use header_ticket freely.  The encrypted part (if any) has been
+     * decrypted with the session key.
+     */
+
+    authtime = header_ticket->enc_part2->times.authtime;
+
+    /* XXX make sure server here has the proper realm...taken from AP_REQ
+       header? */
+
+    nprincs = 1;
+    if ((errcode = krb5_db_get_principal(kdc_context, request->server, &server,
+					&nprincs, &more))) {
+	status = "LOOKING_UP_SERVER";
+	nprincs = 0;
+	goto cleanup;
+    }
+tgt_again:
+    if (more) {
+	status = "NON_UNIQUE_PRINCIPAL";
+	errcode = KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
+	goto cleanup;
+    } else if (nprincs != 1) {
+	/*
+	 * might be a request for a TGT for some other realm; we
+	 * should do our best to find such a TGS in this db
+	 */
+	if (firstpass && krb5_is_tgs_principal(request->server) == TRUE) {
+	    if (krb5_princ_size(kdc_context, request->server) == 2) {
+		krb5_data *server_1 =
+		    krb5_princ_component(kdc_context, request->server, 1);
+		krb5_data *tgs_1 =
+		    krb5_princ_component(kdc_context, tgs_server, 1);
+
+		if (!tgs_1 || server_1->length != tgs_1->length ||
+		    memcmp(server_1->data, tgs_1->data, tgs_1->length)) {
+		    krb5_db_free_principal(kdc_context, &server, nprincs);
+		    find_alternate_tgs(request, &server, &more, &nprincs);
+		    firstpass = 0;
+		    goto tgt_again;
+		}
+	    }
+	}
+	krb5_db_free_principal(kdc_context, &server, nprincs);
+	status = "UNKNOWN_SERVER";
+	errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+	goto cleanup;
+    }
+
+    if ((errcode = krb5_timeofday(kdc_context, &kdc_time))) {
+	status = "TIME_OF_DAY";
+	goto cleanup;
+    }
+    
+    if ((retval = validate_tgs_request(request, server, header_ticket,
+				      kdc_time, &status))) {
+	if (!status)
+	    status = "UNKNOWN_REASON";
+	errcode = retval + ERROR_TABLE_BASE_krb5;
+	goto cleanup;
+    }
+
+    /*
+     * We pick the session keytype here....
+     * 
+     * Some special care needs to be taken in the user-to-user
+     * case, since we don't know what keytypes the application server
+     * which is doing user-to-user authentication can support.  We
+     * know that it at least must be able to support the encryption
+     * type of the session key in the TGT, since otherwise it won't be
+     * able to decrypt the U2U ticket!  So we use that in preference
+     * to anything else.
+     */
+    useenctype = 0;
+    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
+	krb5_keyblock *	st_sealing_key;
+	krb5_kvno 	st_srv_kvno;
+	krb5_enctype	etype;
+
+	/*
+	 * Get the key for the second ticket, and decrypt it.
+	 */
+	if ((errcode = kdc_get_server_key(request->second_ticket[st_idx],
+					 &st_sealing_key,
+					 &st_srv_kvno))) {
+	    status = "2ND_TKT_SERVER";
+	    goto cleanup;
+	}
+	errcode = krb5_decrypt_tkt_part(kdc_context, st_sealing_key,
+				       request->second_ticket[st_idx]);
+	krb5_free_keyblock(kdc_context, st_sealing_key);
+	if (errcode) {
+	    status = "2ND_TKT_DECRYPT";
+	    goto cleanup;
+	}
+	
+	etype = request->second_ticket[st_idx]->enc_part2->session->enctype;
+	if (!krb5_c_valid_enctype(etype)) {
+	    status = "BAD_ETYPE_IN_2ND_TKT";
+	    errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+	    goto cleanup;
+	}
+	
+	for (i = 0; i < request->nktypes; i++) {
+	    if (request->ktype[i] == etype) {
+		useenctype = etype;
+		break;
+	    }
+	}
+    }
+
+    /*
+     * Select the keytype for the ticket session key.
+     */
+    if ((useenctype == 0) &&
+	(useenctype = select_session_keytype(kdc_context, &server,
+					     request->nktypes,
+					     request->ktype)) == 0) {
+	/* unsupported ktype */
+	status = "BAD_ENCRYPTION_TYPE";
+	errcode = KRB5KDC_ERR_ETYPE_NOSUPP;
+	goto cleanup;
+    }
+    
+    errcode = krb5_c_make_random_key(kdc_context, useenctype, &session_key);
+
+    if (errcode) {
+	/* random key failed */
+	status = "RANDOM_KEY_FAILED";
+	goto cleanup;
+    }
+
+    ticket_reply.server = request->server; /* XXX careful for realm... */
+
+    enc_tkt_reply.flags = 0;
+    enc_tkt_reply.times.starttime = 0;
+
+    /*
+     * Fix header_ticket's starttime; if it's zero, fill in the
+     * authtime's value.
+     */
+    if (!(header_ticket->enc_part2->times.starttime))
+	header_ticket->enc_part2->times.starttime =
+	    header_ticket->enc_part2->times.authtime;
+
+    /* don't use new addresses unless forwarded, see below */
+
+    enc_tkt_reply.caddrs = header_ticket->enc_part2->caddrs;
+    /* noaddrarray[0] = 0; */
+    reply_encpart.caddrs = 0;		/* optional...don't put it in */
+
+    /* It should be noted that local policy may affect the  */
+    /* processing of any of these flags.  For example, some */
+    /* realms may refuse to issue renewable tickets         */
+
+    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE))
+	setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
+
+    if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
+	setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
+
+	/* include new addresses in ticket & reply */
+
+	enc_tkt_reply.caddrs = request->addresses;
+	reply_encpart.caddrs = request->addresses;
+    }	
+    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_FORWARDED))
+	setflag(enc_tkt_reply.flags, TKT_FLG_FORWARDED);
+
+    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE))
+	setflag(enc_tkt_reply.flags, TKT_FLG_PROXIABLE);
+
+    if (isflagset(request->kdc_options, KDC_OPT_PROXY)) {
+	setflag(enc_tkt_reply.flags, TKT_FLG_PROXY);
+
+	/* include new addresses in ticket & reply */
+
+	enc_tkt_reply.caddrs = request->addresses;
+	reply_encpart.caddrs = request->addresses;
+    }
+
+    if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE))
+	setflag(enc_tkt_reply.flags, TKT_FLG_MAY_POSTDATE);
+
+    if (isflagset(request->kdc_options, KDC_OPT_POSTDATED)) {
+	setflag(enc_tkt_reply.flags, TKT_FLG_POSTDATED);
+	setflag(enc_tkt_reply.flags, TKT_FLG_INVALID);
+	enc_tkt_reply.times.starttime = request->from;
+    } else
+	enc_tkt_reply.times.starttime = kdc_time;
+
+    if (isflagset(request->kdc_options, KDC_OPT_VALIDATE)) {
+	/* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
+	   to the caller */
+	ticket_reply = *(header_ticket);
+	enc_tkt_reply = *(header_ticket->enc_part2);
+	clear(enc_tkt_reply.flags, TKT_FLG_INVALID);
+    }
+
+    if (isflagset(request->kdc_options, KDC_OPT_RENEW)) {
+	krb5_deltat old_life;
+
+	/* BEWARE of allocation hanging off of ticket & enc_part2, it belongs
+	   to the caller */
+	ticket_reply = *(header_ticket);
+	enc_tkt_reply = *(header_ticket->enc_part2);
+
+	old_life = enc_tkt_reply.times.endtime - enc_tkt_reply.times.starttime;
+
+	enc_tkt_reply.times.starttime = kdc_time;
+	enc_tkt_reply.times.endtime =
+	    min(header_ticket->enc_part2->times.renew_till,
+		kdc_time + old_life);
+    } else {
+	/* not a renew request */
+	enc_tkt_reply.times.starttime = kdc_time;
+	until = (request->till == 0) ? kdc_infinity : request->till;
+	enc_tkt_reply.times.endtime =
+	    min(until, min(enc_tkt_reply.times.starttime + server.max_life,
+			   min(enc_tkt_reply.times.starttime + max_life_for_realm,
+			       header_ticket->enc_part2->times.endtime)));
+	if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE_OK) &&
+	    (enc_tkt_reply.times.endtime < request->till) &&
+	    isflagset(header_ticket->enc_part2->flags,
+		  TKT_FLG_RENEWABLE)) {
+	    setflag(request->kdc_options, KDC_OPT_RENEWABLE);
+	    request->rtime =
+		min(request->till,
+		    header_ticket->enc_part2->times.renew_till);
+	}
+    }
+    rtime = (request->rtime == 0) ? kdc_infinity : request->rtime;
+
+    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) {
+	/* already checked above in policy check to reject request for a
+	   renewable ticket using a non-renewable ticket */
+	setflag(enc_tkt_reply.flags, TKT_FLG_RENEWABLE);
+	enc_tkt_reply.times.renew_till =
+	    min(rtime,
+		min(header_ticket->enc_part2->times.renew_till,
+		    enc_tkt_reply.times.starttime +
+		    min(server.max_renewable_life,
+			max_renewable_life_for_realm)));
+    } else {
+	enc_tkt_reply.times.renew_till = 0;
+    }
+    
+    /*
+     * Set authtime to be the same as header_ticket's
+     */
+    enc_tkt_reply.times.authtime = header_ticket->enc_part2->times.authtime;
+    
+    /*
+     * Propagate the preauthentication flags through to the returned ticket.
+     */
+    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_PRE_AUTH))
+	setflag(enc_tkt_reply.flags, TKT_FLG_PRE_AUTH);
+
+    if (isflagset(header_ticket->enc_part2->flags, TKT_FLG_HW_AUTH))
+	setflag(enc_tkt_reply.flags, TKT_FLG_HW_AUTH);
+    
+    /* starttime is optional, and treated as authtime if not present.
+       so we can nuke it if it matches */
+    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
+	enc_tkt_reply.times.starttime = 0;
+
+    /* assemble any authorization data */
+    if (request->authorization_data.ciphertext.data) {
+	krb5_data scratch;
+
+	scratch.length = request->authorization_data.ciphertext.length;
+	if (!(scratch.data =
+	      malloc(request->authorization_data.ciphertext.length))) {
+	    status = "AUTH_NOMEM";
+	    errcode = ENOMEM;
+	    goto cleanup;
+	}
+
+	if ((errcode = krb5_c_decrypt(kdc_context,
+				      header_ticket->enc_part2->session,
+				      KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
+				      0, &request->authorization_data,
+				      &scratch))) {
+	    status = "AUTH_ENCRYPT_FAIL";
+	    free(scratch.data);
+	    goto cleanup;
+	}
+
+	/* scratch now has the authorization data, so we decode it */
+	errcode = decode_krb5_authdata(&scratch, &(request->unenc_authdata));
+	free(scratch.data);
+	if (errcode) {
+	    status = "AUTH_DECODE";
+	    goto cleanup;
+	}
+
+	if ((errcode =
+	     concat_authorization_data(request->unenc_authdata,
+				       header_ticket->enc_part2->authorization_data, 
+				       &enc_tkt_reply.authorization_data))) {
+	    status = "CONCAT_AUTH";
+	    goto cleanup;
+	}
+    } else
+	enc_tkt_reply.authorization_data =
+	    header_ticket->enc_part2->authorization_data;
+
+    enc_tkt_reply.session = &session_key;
+    enc_tkt_reply.client = header_ticket->enc_part2->client;
+    enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
+    enc_tkt_reply.transited.tr_contents = empty_string; /* equivalent of "" */
+
+    /*
+     * Only add the realm of the presented tgt to the transited list if 
+     * it is different than the local realm (cross-realm) and it is different
+     * than the realm of the client (since the realm of the client is already
+     * implicitly part of the transited list and should not be explicitly
+     * listed).
+     */
+
+    /* realm compare is like strcmp, but knows how to deal with these args */
+    if (realm_compare(header_ticket->server, tgs_server) ||
+	realm_compare(header_ticket->server, enc_tkt_reply.client)) {
+	/* tgt issued by local realm or issued by realm of client */
+	enc_tkt_reply.transited = header_ticket->enc_part2->transited;
+    } else {
+	/* tgt issued by some other realm and not the realm of the client */
+	/* assemble new transited field into allocated storage */
+	if (header_ticket->enc_part2->transited.tr_type !=
+	    KRB5_DOMAIN_X500_COMPRESS) {
+	    status = "BAD_TRTYPE";
+	    errcode = KRB5KDC_ERR_TRTYPE_NOSUPP;
+	    goto cleanup;
+	}
+	enc_tkt_transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
+	enc_tkt_transited.tr_contents.data = 0;
+	enc_tkt_transited.tr_contents.length = 0;
+	enc_tkt_reply.transited = enc_tkt_transited;
+	if ((errcode =
+	     add_to_transited(&header_ticket->enc_part2->transited.tr_contents,
+			      &enc_tkt_reply.transited.tr_contents,
+			      header_ticket->server,
+			      enc_tkt_reply.client,
+			      request->server))) {
+	    status = "ADD_TR_FAIL";
+	    goto cleanup;
+	}
+	newtransited = 1;
+    }
+    if (!isflagset (request->kdc_options, KDC_OPT_DISABLE_TRANSITED_CHECK)) {
+	errcode = krb5_check_transited_list (kdc_context,
+					     &enc_tkt_reply.transited.tr_contents,
+					     krb5_princ_realm (kdc_context, header_ticket->enc_part2->client),
+					     krb5_princ_realm (kdc_context, request->server));
+	if (errcode == 0) {
+	    setflag (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED);
+	} else if (errcode == KRB5KRB_AP_ERR_ILL_CR_TKT)
+	    krb5_klog_syslog (LOG_INFO,
+			      "bad realm transit path from '%s' to '%s' via '%.*s'",
+			      cname ? cname : "<unknown client>",
+			      sname ? sname : "<unknown server>",
+			      enc_tkt_reply.transited.tr_contents.length,
+			      enc_tkt_reply.transited.tr_contents.data);
+	else
+	    krb5_klog_syslog (LOG_ERR,
+			      "unexpected error checking transit from '%s' to '%s' via '%.*s': %s",
+			      cname ? cname : "<unknown client>",
+			      sname ? sname : "<unknown server>",
+			      enc_tkt_reply.transited.tr_contents.length,
+			      enc_tkt_reply.transited.tr_contents.data,
+			      error_message (errcode));
+    } else
+	krb5_klog_syslog (LOG_INFO, "not checking transit path");
+    if (reject_bad_transit
+	&& !isflagset (enc_tkt_reply.flags, TKT_FLG_TRANSIT_POLICY_CHECKED)) {
+	errcode = KRB5KDC_ERR_POLICY;
+	status = "BAD_TRANSIT";
+	goto cleanup;
+    }
+
+    ticket_reply.enc_part2 = &enc_tkt_reply;
+
+    /*
+     * If we are doing user-to-user authentication, then make sure
+     * that the client for the second ticket matches the request
+     * server, and then encrypt the ticket using the session key of
+     * the second ticket.
+     */
+    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
+	/*
+	 * Make sure the client for the second ticket matches
+	 * requested server.
+	 */
+	krb5_enc_tkt_part *t2enc = request->second_ticket[st_idx]->enc_part2;
+	krb5_principal client2 = t2enc->client;
+	if (!krb5_principal_compare(kdc_context, request->server, client2)) {
+		if ((errcode = krb5_unparse_name(kdc_context, client2, &tmp)))
+			tmp = 0;
+		krb5_klog_syslog(LOG_INFO,
+				 "TGS_REQ %s: 2ND_TKT_MISMATCH: "
+				 "authtime %d, %s for %s, 2nd tkt client %s",
+				 fromstring, authtime,
+				 cname ? cname : "<unknown client>",
+				 sname ? sname : "<unknown server>",
+				 tmp ? tmp : "<unknown>");
+		errcode = KRB5KDC_ERR_SERVER_NOMATCH;
+		goto cleanup;
+	}
+	    
+	ticket_reply.enc_part.kvno = 0;
+	ticket_reply.enc_part.enctype = t2enc->session->enctype;
+	if ((errcode = krb5_encrypt_tkt_part(kdc_context, t2enc->session,
+					     &ticket_reply))) {
+	    status = "2ND_TKT_ENCRYPT";
+	    goto cleanup;
+	}
+	st_idx++;
+    } else {
+	/*
+	 * Find the server key
+	 */
+	if ((errcode = krb5_dbe_find_enctype(kdc_context, &server,
+					     -1, /* ignore keytype */
+					     -1, /* Ignore salttype */
+					     0,		/* Get highest kvno */
+					     &server_key))) {
+	    status = "FINDING_SERVER_KEY";
+	    goto cleanup;
+	}
+	/* convert server.key into a real key (it may be encrypted
+	 *        in the database) */
+	if ((errcode = krb5_dbekd_decrypt_key_data(kdc_context,
+						   &master_keyblock, 
+						   server_key, &encrypting_key,
+						   NULL))) {
+	    status = "DECRYPT_SERVER_KEY";
+	    goto cleanup;
+	}
+	errcode = krb5_encrypt_tkt_part(kdc_context, &encrypting_key,
+					&ticket_reply);
+	krb5_free_keyblock_contents(kdc_context, &encrypting_key);
+	if (errcode) {
+	    status = "TKT_ENCRYPT";
+	    goto cleanup;
+	}
+	ticket_reply.enc_part.kvno = server_key->key_data_kvno;
+    }
+
+    /* Start assembling the response */
+    reply.msg_type = KRB5_TGS_REP;
+    reply.padata = 0;		/* always */
+    reply.client = header_ticket->enc_part2->client;
+    reply.enc_part.kvno = 0;		/* We are using the session key */
+    reply.ticket = &ticket_reply;
+
+    reply_encpart.session = &session_key;
+    reply_encpart.nonce = request->nonce;
+
+    /* copy the time fields EXCEPT for authtime; its location
+       is used for ktime */
+    reply_encpart.times = enc_tkt_reply.times;
+    reply_encpart.times.authtime = header_ticket->enc_part2->times.authtime;
+
+    /* starttime is optional, and treated as authtime if not present.
+       so we can nuke it if it matches */
+    if (enc_tkt_reply.times.starttime == enc_tkt_reply.times.authtime)
+	enc_tkt_reply.times.starttime = 0;
+
+    nolrentry.lr_type = KRB5_LRQ_NONE;
+    nolrentry.value = 0;
+    nolrarray[0] = &nolrentry;
+    nolrarray[1] = 0;
+    reply_encpart.last_req = nolrarray;	/* not available for TGS reqs */
+    reply_encpart.key_exp = 0;		/* ditto */
+    reply_encpart.flags = enc_tkt_reply.flags;
+    reply_encpart.server = ticket_reply.server;
+    
+    /* use the session key in the ticket, unless there's a subsession key
+       in the AP_REQ */
+
+    reply.enc_part.enctype = subkey ? subkey->enctype :
+		    header_ticket->enc_part2->session->enctype;
+    errcode = krb5_encode_kdc_rep(kdc_context, KRB5_TGS_REP, &reply_encpart, 
+				  subkey ? 1 : 0,
+				  subkey ? subkey :
+				  header_ticket->enc_part2->session,
+				  &reply, response);
+    if (errcode) {
+	status = "ENCODE_KDC_REP";
+    } else {
+	status = "ISSUE";
+    }
+
+    memset(ticket_reply.enc_part.ciphertext.data, 0,
+	   ticket_reply.enc_part.ciphertext.length);
+    free(ticket_reply.enc_part.ciphertext.data);
+    /* these parts are left on as a courtesy from krb5_encode_kdc_rep so we
+       can use them in raw form if needed.  But, we don't... */
+    memset(reply.enc_part.ciphertext.data, 0,
+	   reply.enc_part.ciphertext.length);
+    free(reply.enc_part.ciphertext.data);
+    
+cleanup:
+    if (status) {
+	if (!errcode)
+	    rep_etypes2str(rep_etypestr, sizeof(rep_etypestr), &reply);
+        krb5_klog_syslog(LOG_INFO,
+			 "TGS_REQ (%s) %s: %s: authtime %d, "
+			 "%s%s %s for %s%s%s",
+			 ktypestr,
+			 fromstring, status, authtime,
+			 !errcode ? rep_etypestr : "",
+			 !errcode ? "," : "",
+			 cname ? cname : "<unknown client>",
+			 sname ? sname : "<unknown server>",
+			 errcode ? ", " : "",
+			 errcode ? error_message(errcode) : "");
+    }
+    
+    if (errcode) {
+	if (status == 0)
+	    status = error_message (errcode);
+	errcode -= ERROR_TABLE_BASE_krb5;
+	if (errcode < 0 || errcode > 128)
+	    errcode = KRB_ERR_GENERIC;
+	    
+	retval = prepare_error_tgs(request, header_ticket, errcode,
+				   fromstring, response, status);
+    }
+    
+    if (header_ticket)
+	krb5_free_ticket(kdc_context, header_ticket);
+    if (request)
+	krb5_free_kdc_req(kdc_context, request);
+    if (cname)
+	free(cname);
+    if (sname)
+	free(sname);
+    if (nprincs)
+	krb5_db_free_principal(kdc_context, &server, 1);
+    if (session_key.contents)
+	krb5_free_keyblock_contents(kdc_context, &session_key);
+    if (newtransited)
+	free(enc_tkt_reply.transited.tr_contents.data); 
+
+    return retval;
+}
+
+static krb5_error_code
+prepare_error_tgs (krb5_kdc_req *request, krb5_ticket *ticket, int error,
+		   const char *ident, krb5_data **response, const char *status)
+{
+    krb5_error errpkt;
+    krb5_error_code retval;
+    krb5_data *scratch;
+
+    errpkt.ctime = request->nonce;
+    errpkt.cusec = 0;
+
+    if ((retval = krb5_us_timeofday(kdc_context, &errpkt.stime,
+				    &errpkt.susec)))
+	return(retval);
+    errpkt.error = error;
+    errpkt.server = request->server;
+    if (ticket && ticket->enc_part2)
+	errpkt.client = ticket->enc_part2->client;
+    else
+	errpkt.client = 0;
+    errpkt.text.length = strlen(status) + 1;
+    if (!(errpkt.text.data = malloc(errpkt.text.length)))
+	return ENOMEM;
+    (void) strcpy(errpkt.text.data, status);
+
+    if (!(scratch = (krb5_data *)malloc(sizeof(*scratch)))) {
+	free(errpkt.text.data);
+	return ENOMEM;
+    }
+    errpkt.e_data.length = 0;
+    errpkt.e_data.data = 0;
+
+    retval = krb5_mk_error(kdc_context, &errpkt, scratch);
+    free(errpkt.text.data);
+    if (retval)
+	free(scratch);
+    else
+	*response = scratch;
+
+    return retval;
+}
+
+/*
+ * The request seems to be for a ticket-granting service somewhere else,
+ * but we don't have a ticket for the final TGS.  Try to give the requestor
+ * some intermediate realm.
+ */
+static void
+find_alternate_tgs(krb5_kdc_req *request, krb5_db_entry *server,
+		   krb5_boolean *more, int *nprincs)
+{
+    krb5_error_code retval;
+    krb5_principal *plist, *pl2;
+    krb5_data tmp;
+
+    *nprincs = 0;
+    *more = FALSE;
+
+    /*
+     * Call to krb5_princ_component is normally not safe but is so
+     * here only because find_alternate_tgs() is only called from
+     * somewhere that has already checked the number of components in
+     * the principal.
+     */
+    if ((retval = krb5_walk_realm_tree(kdc_context, 
+		      krb5_princ_realm(kdc_context, request->server),
+		      krb5_princ_component(kdc_context, request->server, 1),
+				      &plist, KRB5_REALM_BRANCH_CHAR)))
+	return;
+
+    /* move to the end */
+    for (pl2 = plist; *pl2; pl2++);
+
+    /* the first entry in this array is for krbtgt/local@local, so we
+       ignore it */
+    while (--pl2 > plist) {
+	*nprincs = 1;
+	tmp = *krb5_princ_realm(kdc_context, *pl2);
+	krb5_princ_set_realm(kdc_context, *pl2, 
+			     krb5_princ_realm(kdc_context, tgs_server));
+	retval = krb5_db_get_principal(kdc_context, *pl2, server, nprincs, more);
+	krb5_princ_set_realm(kdc_context, *pl2, &tmp);
+	if (retval) {
+	    *nprincs = 0;
+	    *more = FALSE;
+	    krb5_free_realm_tree(kdc_context, plist);
+	    return;
+	}
+	if (*more) {
+	    krb5_db_free_principal(kdc_context, server, *nprincs);
+	    continue;
+	} else if (*nprincs == 1) {
+	    /* Found it! */
+	    krb5_principal tmpprinc;
+	    char *sname;
+
+	    tmp = *krb5_princ_realm(kdc_context, *pl2);
+	    krb5_princ_set_realm(kdc_context, *pl2, 
+				 krb5_princ_realm(kdc_context, tgs_server));
+	    if ((retval = krb5_copy_principal(kdc_context, *pl2, &tmpprinc))) {
+		krb5_db_free_principal(kdc_context, server, *nprincs);
+		krb5_princ_set_realm(kdc_context, *pl2, &tmp);
+		continue;
+	    }
+	    krb5_princ_set_realm(kdc_context, *pl2, &tmp);
+
+	    krb5_free_principal(kdc_context, request->server);
+	    request->server = tmpprinc;
+	    if (krb5_unparse_name(kdc_context, request->server, &sname)) {
+		krb5_klog_syslog(LOG_INFO,
+		       "TGS_REQ: issuing alternate <un-unparseable> TGT");
+	    } else {
+		krb5_klog_syslog(LOG_INFO,
+		       "TGS_REQ: issuing TGT %s", sname);
+		free(sname);
+	    }
+	    return;
+	}
+	krb5_db_free_principal(kdc_context, server, *nprincs);
+	continue;
+    }
+
+    *nprincs = 0;
+    *more = FALSE;
+    krb5_free_realm_tree(kdc_context, plist);
+    return;
+}
diff --git a/mechglue/src/kdc/extern.c b/mechglue/src/kdc/extern.c
new file mode 100644
index 000000000..fa3e0af43
--- /dev/null
+++ b/mechglue/src/kdc/extern.c
@@ -0,0 +1,42 @@
+/*
+ * kdc/extern.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * allocations of extern stuff
+ */
+
+#include "k5-int.h"
+#include "extern.h"
+
+/* real declarations of KDC's externs */
+kdc_realm_t	**kdc_realmlist = (kdc_realm_t **) NULL;
+int		kdc_numrealms = 0;
+kdc_realm_t	*kdc_active_realm = (kdc_realm_t *) NULL;
+krb5_data empty_string = {0, 0, ""};
+krb5_timestamp kdc_infinity = KRB5_INT32_MAX; /* XXX */
+krb5_rcache	kdc_rcache = (krb5_rcache) NULL;
+krb5_keyblock	psr_key;
+
+volatile int signal_requests_exit = 0;	/* gets set when signal hits */
+volatile int signal_requests_hup = 0;   /* ditto */
diff --git a/mechglue/src/kdc/extern.h b/mechglue/src/kdc/extern.h
new file mode 100644
index 000000000..d4db86aac
--- /dev/null
+++ b/mechglue/src/kdc/extern.h
@@ -0,0 +1,99 @@
+/*
+ * kdc/extern.h
+ *
+ * Copyright 1990,2001 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * <<< Description >>>
+ */
+
+#ifndef __KRB5_KDC_EXTERN__
+#define __KRB5_KDC_EXTERN__
+
+typedef struct __kdc_realm_data {
+    /*
+     * General Kerberos per-realm data.
+     */
+    char *		realm_name;	/* Realm name			    */
+/* XXX the real context should go away once the db_context is done. 
+ * The db_context is then associated with the realm keytab using 
+ * krb5_ktkdb_resolv(). There should be nothing in the context which 
+ * cannot span multiple realms -- proven */
+    krb5_context	realm_context;	/* Context to be used for realm	    */
+    krb5_keytab		realm_keytab; 	/* keytab to be used for this realm */
+    char *		realm_profile;	/* Profile file for this realm	    */
+    /*
+     * Database per-realm data.
+     */
+    char *		realm_dbname;	/* Database name for realm	    */
+    char *		realm_stash;	/* Stash file name for realm	    */
+    char *		realm_mpname;	/* Master principal name for realm  */
+    krb5_principal	realm_mprinc;	/* Master principal for realm	    */
+    krb5_keyblock	realm_mkey;	/* Master key for this realm	    */
+    /*
+     * TGS per-realm data.
+     */
+    krb5_principal	realm_tgsprinc;	/* TGS principal for this realm	    */
+    /*
+     * Other per-realm data.
+     */
+    char		*realm_ports;	/* Per-realm KDC UDP port */
+    char		*realm_tcp_ports; /* Per-realm KDC TCP port */
+    /*
+     * Per-realm parameters.
+     */
+    krb5_deltat		realm_maxlife;	/* Maximum ticket life for realm    */
+    krb5_deltat		realm_maxrlife;	/* Maximum renewable life for realm */
+    krb5_boolean	realm_reject_bad_transit; /* Accept unverifiable transited_realm ? */
+} kdc_realm_t;
+
+extern kdc_realm_t	**kdc_realmlist;
+extern int		kdc_numrealms;
+extern kdc_realm_t	*kdc_active_realm;
+
+kdc_realm_t *find_realm_data (char *, krb5_ui_4);
+
+/*
+ * Replace previously used global variables with the active (e.g. request's)
+ * realm data.  This allows us to support multiple realms with minimal logic
+ * changes.
+ */
+#define	kdc_context			kdc_active_realm->realm_context
+#define	max_life_for_realm		kdc_active_realm->realm_maxlife
+#define	max_renewable_life_for_realm	kdc_active_realm->realm_maxrlife
+#define	master_keyblock			kdc_active_realm->realm_mkey
+#define	master_princ			kdc_active_realm->realm_mprinc
+#define	tgs_server_struct		*(kdc_active_realm->realm_tgsprinc)
+#define	tgs_server			kdc_active_realm->realm_tgsprinc
+#define	dbm_db_name			kdc_active_realm->realm_dbname
+#define	primary_port			kdc_active_realm->realm_pport
+#define reject_bad_transit		kdc_active_realm->realm_reject_bad_transit
+
+/* various externs for KDC */
+extern krb5_data 	empty_string;	/* an empty string */
+extern krb5_timestamp 	kdc_infinity;	/* greater than all other timestamps */
+extern krb5_rcache	kdc_rcache;	/* replay cache */
+extern krb5_keyblock	psr_key;	/* key for predicted sam response */
+
+extern volatile int signal_requests_exit;
+extern volatile int signal_requests_hup;
+#endif /* __KRB5_KDC_EXTERN__ */
diff --git a/mechglue/src/kdc/fakeka.c b/mechglue/src/kdc/fakeka.c
new file mode 100644
index 000000000..5d098dc5c
--- /dev/null
+++ b/mechglue/src/kdc/fakeka.c
@@ -0,0 +1,1395 @@
+/*
+ * COPYRIGHT NOTICE
+ * Copyright (c) 1994 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * Converted to Kerberos 5 by Ken Hornstein <kenh@cmf.nrl.navy.mil>
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <kerberosIV/krb.h>
+#include <kerberosIV/des.h>
+
+#ifndef LINT
+static char rcsid[]=
+	"$Id$";
+#endif
+
+/*
+ * Misc macros
+ */
+
+#define PAD_TO(x, a) (((u_long)(x) + (a) - 1) & ~((a) - 1))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define MAXFORWARDERS 10
+#define HEADER_LEN 8
+
+/*
+ * Error values from kautils.h
+ * 
+ * The security errors are:
+ * 	KABADTICKET, KABADSERVER, KABADUSER, and KACLOCKSKEW
+ */
+
+#define KADATABASEINCONSISTENT                   (180480L)
+#define KANOENT                                  (180484L)
+#define KABADREQUEST                             (180490L)     
+#define KABADTICKET                              (180504L)
+#define KABADSERVER                              (180507L)
+#define KABADUSER                                (180508L)
+#define KACLOCKSKEW                              (180514L)
+#define KAINTERNALERROR                          (180518L)
+
+
+/*
+ * Type definitions
+ */
+
+typedef struct packet {
+    char *base;
+    int len;
+    char data[1024];
+} *packet_t;
+
+typedef struct rx_header {
+    u_int rx_epoch;
+    u_int rx_cid;
+    u_int rx_callnum;
+    u_int rx_seq;
+    u_int rx_serial;
+    u_char rx_type;
+    u_char rx_flags;
+    u_char rx_userstatus;
+    u_char rx_securityindex;
+    u_short rx_spare;
+    u_short rx_service;
+    u_int rx_request;
+} *rx_t;
+
+
+/*
+ * Global vars
+ */
+
+char *progname = "fakeka";		/* needed by libkdb.a */
+char *localrealm = NULL;
+char *localcell = NULL;
+krb5_timestamp req_time;
+kadm5_config_params realm_params;
+int debug = 0;
+
+
+/*
+ * This is a table for the "infamous" CMU ticket lifetime conversion.  If
+ * the lifetime is greater than 128, use this table
+ */
+#define MAX_TICKET_LIFETIME 2592000
+static long cmu_seconds[] =
+{
+  38400,  41055,  43894,  46929,  50174,  53643,  57352,  61318,
+  65558,  70091,  74937,  80119,  85658,  91581,  97914,  104684,
+  111922,  119661,  127935,  136781,  146239,  156350,  167161,  178720,
+  191077,  204289,  218415,  233517,  249663,  266926,  285383,  305116,
+  326213,  348769,  372885,  398668,  426233,  455705,  487215,  520903,
+  556921,  595430,  636600,  680618,  727679,  777995,  831789,  889303,
+  950794,  1016536,  1086825,  1161973,  1242317,  1328217,  1420057,  1518246,
+  1623225,  1735463,  1855462,  1983757,  2120924,  2267575,  2424366, 2591999,
+  0
+};
+
+#if	__STDC__
+/*
+ * Prototypes for all the functions we define
+ */
+
+void perrorexit(char *);
+void pexit(char *);
+char *kaerror(int);
+int get_princ_key(krb5_context, void *, kadm5_principal_ent_t, des_cblock,
+		  des_key_schedule);
+int check_princ(krb5_context, void *, char *, char *, kadm5_principal_ent_t);
+
+int make_reply_packet(krb5_context, void *, packet_t, int, int, int,
+		      char *, char *, char *, char *,
+		      des_cblock, des_key_schedule, char *);
+
+int Authenticate(krb5_context, void *, char *, packet_t, packet_t);
+int GetTicket(krb5_context, void *, char *, packet_t, packet_t);
+void process(krb5_context, void *, char *, packet_t, packet_t);
+#endif
+
+
+/*
+ * Helpers for exiting with errors
+ */
+
+void perrorexit(str)
+char *str;
+{
+    perror(str);
+    exit(1);
+}
+
+void pexit(str)
+char *str;
+{
+    printf("%s\n", str);
+    exit(1);
+}
+
+
+/*
+ * Translate error codes into strings.
+ */
+
+char *kaerror(e)
+int e;
+{
+    static char buf[1024];
+
+    switch (e) {
+    case KADATABASEINCONSISTENT:
+	return "database is inconsistent";
+    case KANOENT:
+	return "principal does not exist";
+    case KABADREQUEST:
+	return "request was malformed (bad password)";
+    case KABADTICKET:
+	return "ticket was malformed, invalid, or expired";
+    case KABADSERVER:
+	return "cannot issue tickets for this service";
+    case KABADUSER:
+	return "principal expired";
+    case KACLOCKSKEW:
+	return "client time is too far skewed";
+    case KAINTERNALERROR:
+	return "internal error in fakeka, help!";
+    default:
+	sprintf(buf, "impossible error code %d, help!", e);
+	return buf;
+    }
+    /*NOTREACHED*/
+}
+
+/*
+ * Syslog facilities
+ */
+typedef struct {
+	int num;
+	char *string;
+} facility_mapping;
+
+static facility_mapping mappings[] = {
+#ifdef LOG_KERN   
+	{ LOG_KERN, "KERN" },
+#endif
+#ifdef LOG_USER
+	{ LOG_USER, "USER" },
+#endif
+#ifdef LOG_MAIL
+	{ LOG_MAIL, "MAIL" },
+#endif
+#ifdef LOG_DAEMON
+	{ LOG_DAEMON, "DAEMON" },
+#endif
+#ifdef LOG_AUTH
+	{ LOG_AUTH, "AUTH" },
+#endif
+#ifdef LOG_LPR
+	{ LOG_LPR, "LPR" },
+#endif
+#ifdef LOG_NEWS
+	{ LOG_NEWS, "NEWS" },
+#endif
+#ifdef LOG_UUCP
+	{ LOG_UUCP, "UUCP" },
+#endif
+#ifdef LOG_CRON
+	{ LOG_CRON, "CRON" },
+#endif
+#ifdef LOG_LOCAL0
+	{ LOG_LOCAL0, "LOCAL0" },
+#endif
+#ifdef LOG_LOCAL1
+	{ LOG_LOCAL1, "LOCAL1" },
+#endif
+#ifdef LOG_LOCAL2
+	{ LOG_LOCAL2, "LOCAL2" },
+#endif
+#ifdef LOG_LOCAL3
+	{ LOG_LOCAL3, "LOCAL3" },
+#endif
+#ifdef LOG_LOCAL4
+	{ LOG_LOCAL4, "LOCAL4" },
+#endif
+#ifdef LOG_LOCAL5
+	{ LOG_LOCAL5, "LOCAL5" },
+#endif
+#ifdef LOG_LOCAL6
+	{ LOG_LOCAL6, "LOCAL6" },
+#endif
+#ifdef LOG_LOCAL7
+	{ LOG_LOCAL7, "LOCAL7" },
+#endif
+	{ 0, NULL }
+};
+
+
+/*
+ * Get the principal's key and key schedule from the db record.
+ *
+ * Life is more complicated in the V5 world.  Since we can have different
+ * encryption types, we have to make sure that we get back a DES key.
+ * Also, we have to try to get back a AFS3 or V4 salted key, since AFS
+ * doesn't know about a V5 style salt.
+ */
+
+int get_princ_key(context, handle, p, k, s)
+krb5_context context;
+void *handle;
+kadm5_principal_ent_t p;
+des_cblock k;
+des_key_schedule s;
+{	
+    int rv;
+    krb5_keyblock kb;
+    kadm5_ret_t retval;
+
+    /*
+     * We need to call kadm5_decrypt_key to decrypt the key data
+     * from the principal record.  We _must_ have a encryption type
+     * of DES_CBC_CRC, and we prefer having a salt type of AFS 3 (but
+     * a V4 salt will work as well).  If that fails, then return any
+     * type of key we can find.
+     *
+     * Note that since this uses kadm5_decrypt_key, it means it has to
+     * be compiled with the kadm5srv library.
+     */
+
+    if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
+				    KRB5_KDB_SALTTYPE_AFS3, 0, &kb,
+				    NULL, NULL)))
+	if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
+					KRB5_KDB_SALTTYPE_V4, 0, &kb,
+					NULL, NULL)))
+		if ((retval = kadm5_decrypt_key(handle, p, ENCTYPE_DES_CBC_CRC,
+						-1, 0, &kb, NULL, NULL))) {
+			syslog(LOG_ERR, "Couldn't find any matching key: %s",
+			       error_message(retval));
+			return KAINTERNALERROR;
+		}
+
+    /*
+     * Copy the data from our krb5_keyblock to the des_cblock.  Make sure
+     * the size of our key matches the V4/AFS des_cblock.
+     */
+
+    if (kb.length != sizeof(des_cblock)) {
+	krb5_free_keyblock_contents(context, &kb);
+	syslog(LOG_ERR, "Principal key size of %d didn't match C_Block size"
+	       " %d", kb.length, sizeof(des_cblock));
+	return KAINTERNALERROR;
+    }
+
+    memcpy((char *) k, (char *) kb.contents, sizeof(des_cblock));
+
+    krb5_free_keyblock_contents(context, &kb);
+
+    /*
+     * Calculate the des key schedule
+     */
+
+    rv = des_key_sched(k, s);
+    if (rv) {
+	memset((void *) k, 0, sizeof(k));
+	memset((void *)s, 0, sizeof(s));
+	return KAINTERNALERROR;
+    }
+    return 0;
+}
+
+
+/*
+ * Fetch principal from db and validate it.
+ *
+ * Note that this always fetches the key data from the principal (but it
+ * doesn't decrypt it).
+ */
+
+int check_princ(context, handle, name, inst, p)
+krb5_context context;
+void *handle;
+char *name, *inst;
+kadm5_principal_ent_t p;
+{
+    krb5_principal princ;
+    krb5_error_code code;
+    kadm5_ret_t retcode;
+
+    /*
+     * Screen out null principals. They are causing crashes here
+     * under HPUX-10.20. - vwelch@ncsa.uiuc.edu 1/6/98
+     */
+    if (!name || (name[0] == '\0')) {
+	syslog(LOG_ERR, "screening out null principal");
+	return KANOENT;
+    }
+
+    /*
+     * Build a principal from the name and instance (the realm is always
+     * the same).
+     */
+
+    if ((code = krb5_build_principal_ext(context, &princ, strlen(localrealm),
+					 localrealm, strlen(name), name,
+					 strlen(inst), inst, 0))) {
+	syslog(LOG_ERR, "could not build principal: %s", error_message(code));
+	return KAINTERNALERROR;
+    }
+
+    /*
+     * Fetch the principal from the database -- also fetch the key data.
+     * Note that since this retrieves the key data, it has to be linked with
+     * the kadm5srv library.
+     */
+
+    if ((retcode = kadm5_get_principal(handle, princ, p,
+				       KADM5_PRINCIPAL_NORMAL_MASK |
+				       KADM5_KEY_DATA))) {
+	if (retcode == KADM5_UNK_PRINC) {
+	    krb5_free_principal(context, princ);
+	    syslog(LOG_INFO, "principal %s.%s does not exist", name, inst);
+	    return KANOENT;
+	} else {
+	    krb5_free_principal(context, princ);
+	    syslog(LOG_ERR, "kadm5_get_principal failed: %s",
+		   error_message(retcode));
+	    return KAINTERNALERROR;
+	}
+    }
+
+    krb5_free_principal(context, princ);
+
+    /*
+     * Check various things - taken from the KDC code.
+     *
+     * Since we're essentially bypassing the KDC, we need to make sure
+     * that we don't give out a ticket that we shouldn't.
+     */
+
+    /*
+     * Has the principal expired?
+     */
+
+    if (p->princ_expire_time && p->princ_expire_time < req_time) {
+	kadm5_free_principal_ent(handle, p);
+	return KABADUSER;
+    }
+
+    /*
+     * Has the principal's password expired?  Note that we don't
+     * check for the PWCHANGE_SERVICE flag here, since we don't
+     * support password changing.  We do support the REQUIRES_PWCHANGE
+     * flag, though.
+     */
+
+    if ((p->pw_expiration && p->pw_expiration < req_time) ||
+	(p->attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+	kadm5_free_principal_ent(handle, p);
+	return KABADUSER;
+    }
+
+    /*
+     * See if the principal is locked out
+     */
+
+    if (p->attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
+	kadm5_free_principal_ent(handle, p);
+	return KABADUSER;
+    }
+
+    /*
+     * There's no way we can handle hardware preauth, so
+     * disallow tickets with this flag set.
+     */
+
+    if (p->attributes & KRB5_KDB_REQUIRES_HW_AUTH) {
+	kadm5_free_principal_ent(handle, p);
+	return KABADUSER;
+    }
+
+    /*
+     * Must be okay, then
+     */
+
+    return 0;
+}
+
+
+/*
+ * Create an rx reply packet in "packet" using the provided data.
+ * The caller is responsible for zeroing key and sched.
+ */
+
+int make_reply_packet(context, handle, reply, challenge_response, start_time,
+		      end_time, cname, cinst, sname, sinst, key, sched, label)
+krb5_context context;
+void *handle;
+packet_t reply;
+int challenge_response, start_time, end_time;
+char *cname, *cinst, *sname, *sinst;
+des_cblock key;
+des_key_schedule sched;
+char *label;
+{
+    int rv, n, maxn, v4life, *enclenp, *ticklenp;
+    u_char *p, *enc, *ticket;
+    kadm5_principal_ent_rec cprinc, sprinc;
+    des_cblock skey, new_session_key;
+    des_key_schedule ssched;
+    krb5_deltat lifetime;
+
+    rv = 0;
+
+    rv = check_princ(context, handle, cname, cinst, &cprinc);
+    if (rv)
+	return rv;
+
+    rv = check_princ(context, handle, sname, sinst, &sprinc);
+    if (rv) {
+	kadm5_free_principal_ent(handle, &cprinc);
+	return rv;
+    }
+
+    /* 
+     * Bound ticket lifetime by max lifetimes of user and service.
+     *
+     * Since V5 already stores everything in Unix epoch timestamps like
+     * AFS, these calculations are much simpler.
+     */
+
+    lifetime = end_time - start_time;
+    lifetime = min(lifetime, cprinc.max_life);
+    lifetime = min(lifetime, sprinc.max_life);
+    lifetime = min(lifetime, realm_params.max_life);
+
+    end_time = start_time + lifetime;
+
+    /*
+     * But we have to convert back to V4-style lifetimes
+     */
+
+    v4life = lifetime / 300;
+    if (v4life > 127) {
+	/*
+	 * Use the CMU algorithm instead
+	 */
+	long *clist = cmu_seconds;
+	while (*clist && *clist < lifetime) clist++;
+	v4life = 128 + (clist - cmu_seconds);
+    }
+
+    /*
+     * If this is for afs and the instance is the local cell name
+     * then we assume we added the instance in GetTickets to
+     * identify the afs key in the kerberos database. This is for
+     * cases where the afs cell name is different from the kerberos
+     * realm name. We now want to remove the instance so it doesn't
+     * cause klog to barf.
+     */
+    if (!strcmp(sname, "afs") && (strcasecmp(sinst, localcell) == 0))
+	sinst[0] = '\0';
+
+    /*
+     * All the data needed to construct the ticket is ready, so do it.
+     */
+
+    p = (unsigned char *) reply->base;
+    maxn = reply->len;
+    n = 0;
+
+#define ERR(x) do { rv = x ; goto error; } while (0)
+#define ADVANCE(x) { if ((n += x) > maxn) ERR(KAINTERNALERROR); else p += x;}
+#define PUT_CHAR(x) { *p = (x); ADVANCE(1); }
+#define PUT_INT(x) { int q = ntohl(x); memcpy(p, (char *)&q, 4); ADVANCE(4); }
+#define PUT_STR(x) { strcpy((char *) p, x); ADVANCE(strlen(x) + 1); }
+
+    ADVANCE(28);
+    PUT_INT(0x2bc);
+
+    enclenp = (int *)p;
+    PUT_INT(0);		/* filled in later */
+
+    enc = p;
+    PUT_INT(0);
+    PUT_INT(challenge_response);
+
+    /*
+     * new_session_key is created here, and remains in the clear
+     * until just before we return.
+     */
+    des_new_random_key(new_session_key);
+    memcpy(p, new_session_key, 8);
+
+    ADVANCE(8);
+    PUT_INT(start_time);
+    PUT_INT(end_time);
+    PUT_INT(sprinc.kvno);
+
+    ticklenp = (int *)p;
+    PUT_INT(0);		/* filled in later */
+
+    PUT_STR(cname);
+    PUT_STR(cinst);
+    PUT_STR("");
+    PUT_STR(sname);
+    PUT_STR(sinst);
+
+    ticket = p;
+    PUT_CHAR(0);	/* flags, always 0 */
+    PUT_STR(cname);
+    PUT_STR(cinst);
+    PUT_STR("");
+    PUT_INT(0);		/* would be ip address */
+
+    memcpy(p, new_session_key, 8);
+
+    ADVANCE(8);
+
+    PUT_CHAR(v4life);
+    PUT_INT(start_time);
+    PUT_STR(sname);
+    PUT_STR(sinst);
+
+    ADVANCE(PAD_TO(p - ticket, 8) - (p - ticket));
+
+    *ticklenp = ntohl(p - ticket);
+
+    rv = get_princ_key(context, handle, &sprinc, skey, ssched);
+    if (rv)
+	return rv;
+    des_pcbc_encrypt((C_Block *) ticket, (C_Block *) ticket, p - ticket,
+		     ssched, (C_Block *) skey, ENCRYPT);
+    memset(skey, 0, sizeof(skey));
+    memset(ssched, 0, sizeof(ssched));
+
+    PUT_STR(label);	/* "tgsT" or "gtkt" */
+    ADVANCE(-1);	/* back up over string terminator */
+
+    ADVANCE(PAD_TO(p - enc, 8) - (p - enc));
+#undef	ERR
+#undef	ADVANCE
+#undef	PUT_CHAR
+#undef	PUT_INT
+#undef	PUT_STR
+
+    *enclenp = ntohl(p - enc);
+    des_pcbc_encrypt((C_Block *) enc, (C_Block *) enc, p - enc, sched,
+		     (C_Block *) key, ENCRYPT);
+    reply->len = n;
+
+  error:
+    memset(new_session_key, 0, sizeof(new_session_key));
+    kadm5_free_principal_ent(handle, &cprinc);
+    kadm5_free_principal_ent(handle, &sprinc);
+
+    return rv;
+}
+
+#define ERR(x) do { rv = x; goto error; } while (0)
+#define ADVANCE(x) { if ((n += x) > maxn) ERR(KABADREQUEST); else p += x; }
+#define GET_INT(x) { int q; memcpy((char *)&q, p, 4); x = ntohl(q); ADVANCE(4); }
+#define GET_CHAR(x) { x = *p; ADVANCE(1); }
+#define GET_PSTR(x) \
+    { \
+	GET_INT(len); \
+	if (len > sizeof(x) - 1) ERR(KABADREQUEST); \
+	memcpy(x, p, len); \
+	x[len] = 0; \
+	ADVANCE(PAD_TO(len, 4)); \
+    }
+
+#define GET_STR(x) \
+    { \
+	len = strlen(p); \
+	if (len > sizeof(x) - 1) ERR(KABADREQUEST); \
+	strcpy(x, p); \
+	ADVANCE(len + 1); \
+    }
+
+
+/*
+ * Process an Authenticate request.
+ */
+
+int Authenticate(context, handle, from, req, reply)
+krb5_context context;
+void *handle;
+char *from;
+packet_t req, reply;
+{
+    int rv, n, maxn;
+    int len, start_time, end_time, challenge;
+    char name[ANAME_SZ+1], inst[INST_SZ+1], *p;
+    kadm5_principal_ent_rec cprinc;
+    des_cblock ckey;
+    des_key_schedule csched;
+    int free_princ_ent = 0;
+
+    rv = 0;
+
+    p = req->base;
+    maxn = req->len;
+    n = 0;
+
+    ADVANCE(32);
+
+    GET_PSTR(name);
+    GET_PSTR(inst);
+
+    if (debug)
+	fprintf(stderr, "Authenticating %s.%s\n", name, inst);
+
+    rv = check_princ(context, handle, name, inst, &cprinc);
+    if (rv)
+	ERR(rv);
+
+    free_princ_ent = 1;
+
+    GET_INT(start_time);
+    GET_INT(end_time);
+
+    GET_INT(len);
+    if (len != 8)
+	ERR(KABADREQUEST);
+
+    /*
+     * ckey and csched are set here and remain in the clear
+     * until just before we return.
+     */
+
+    rv = get_princ_key(context, handle, &cprinc, ckey, csched);
+    if (rv)
+	ERR(rv);
+    des_pcbc_encrypt((C_Block *) p, (C_Block *) p, 8, csched,
+		     (C_Block *) ckey, DECRYPT);
+
+    GET_INT(challenge);
+
+    rv = memcmp(p, "gTGS", 4);
+    if (rv)
+	ERR(KABADREQUEST);
+    ADVANCE(4);
+
+    /* ignore the rest */
+    ADVANCE(8);
+
+    /*
+     * We have all the data from the request, now generate the reply.
+     */
+
+    rv =  make_reply_packet(context, handle, reply, challenge + 1, start_time,
+   			    end_time, name, inst, "krbtgt", localcell,
+			    ckey, csched, "tgsT");
+  error:
+    memset(ckey, 0, sizeof(ckey));
+    memset(csched, 0, sizeof(csched));
+
+    syslog(LOG_INFO, "authenticate: %s.%s from %s", name, inst, from);
+    if (rv) {
+	syslog(LOG_INFO, "... failed due to %s", kaerror(rv));
+    }
+    if (free_princ_ent)
+	kadm5_free_principal_ent(handle, &cprinc);
+    return rv;
+}
+
+
+/*
+ * Process a GetTicket rpc.
+ */
+
+int GetTicket(context, handle, from, req, reply)
+krb5_context context;
+void *handle;
+char *from;
+packet_t req, reply;
+{
+    int rv, n, maxn, len, ticketlen;
+    char *p;
+    u_int kvno, start_time, end_time, times[2], flags, ipaddr;
+    u_int tgt_start_time, tgt_end_time, lifetime;
+    char rname[ANAME_SZ+1], rinst[INST_SZ+1];	/* requested principal */
+    char sname[ANAME_SZ+1], sinst[INST_SZ+1];	/* service principal (TGT) */
+    char cname[ANAME_SZ+1], cinst[INST_SZ+1];	/* client principal */
+    char cell[REALM_SZ+1], realm[REALM_SZ+1];
+    char enctimes[8 + 1], ticket[1024];
+    u_char tgt_lifetime;
+    kadm5_principal_ent_rec cprinc;
+    des_cblock ckey, session_key;
+    des_key_schedule csched, session_sched;
+    int free_princ_ent = 0;
+
+    rv = 0;
+
+    /* 
+     * Initialize these so we don't crash trying to print them in
+     * case they don't get filled in.
+     */
+    strcpy(rname, "Unknown");
+    strcpy(rinst, "Unknown");
+    strcpy(sname, "Unknown");
+    strcpy(sinst, "Unknown");
+    strcpy(cname, "Unknown");
+    strcpy(cinst, "Unknown");
+    strcpy(cell, "Unknown");
+    strcpy(realm, "Unknown");
+    
+    p = req->base;
+    maxn = req->len;
+    n = 0;
+
+    ADVANCE(32);
+
+    GET_INT(kvno);
+
+    GET_PSTR(cell);
+    if (!cell[0])
+	strcpy(cell, localcell);
+
+    if (debug)
+	fprintf(stderr, "Cell is %s\n", cell);
+
+    memset(ticket, 0, sizeof(ticket));
+    GET_PSTR(ticket);
+    ticketlen = len;	/* hacky hack hack */
+    GET_PSTR(rname);
+    GET_PSTR(rinst);
+
+    if (debug)
+	fprintf(stderr, "Request for %s/%s\n", rname, rinst);
+
+    GET_PSTR(enctimes);	/* still encrypted */
+    if (len != 8)	/* hack and hack again */
+	ERR(KABADREQUEST);
+
+    /* ignore the rest */
+    ADVANCE(8);
+
+    /*
+     * That's it for the packet, now decode the embedded ticket.
+     */
+
+    rv = check_princ(context, handle, "krbtgt", cell, &cprinc);
+    if (rv)
+	ERR(rv);
+
+    free_princ_ent = 1;
+
+    rv = get_princ_key(context, handle, &cprinc, ckey, csched);
+    if (rv)
+	ERR(rv);
+    des_pcbc_encrypt((C_Block *) ticket, (C_Block *) ticket, ticketlen, csched,
+		     (C_Block *) ckey, DECRYPT);
+    memset(ckey, 0, sizeof(ckey));
+    memset(csched, 0, sizeof(csched));
+
+    /*
+     * The ticket's session key is now in the clear in the ticket buffer.
+     * We zero it just before returning.
+     */
+
+    p = ticket;
+    maxn = ticketlen;
+    n = 0;
+
+    GET_CHAR(flags);
+    GET_STR(cname);
+    GET_STR(cinst);
+    GET_STR(realm);
+    GET_INT(ipaddr);
+    memcpy(session_key, p, 8);
+    ADVANCE(8);
+
+    GET_CHAR(tgt_lifetime);
+    GET_INT(tgt_start_time);
+    GET_STR(sname);
+    GET_STR(sinst);
+
+    if (debug)
+	fprintf(stderr,
+		"ticket: %s.%s@%s for %s.%s\n",
+		cname, cinst, realm, sname, sinst);
+
+    /*
+     * ok, we've got the ticket unpacked.
+     * now decrypt the start and end times.
+     */
+
+    rv = des_key_sched(session_key, session_sched);
+    if (rv) 
+	ERR(KABADTICKET);
+
+    des_ecb_encrypt((C_Block *) enctimes, (C_Block *) times, session_sched,
+		    DECRYPT);
+    start_time = ntohl(times[0]);
+    end_time = ntohl(times[1]);
+
+    /*
+     * All the info we need is now available.
+     * Now validate the request.
+     */
+
+    /*
+     * This translator requires that the flags and IP address
+     * in the ticket be zero, because we always set them that way,
+     * and we want to accept only tickets that we generated.
+     * 
+     * Are the flags and IP address fields 0?
+     */
+    if (flags || ipaddr) {
+	if (debug)
+	    fprintf(stderr, "ERROR: flags or ipaddr field non-zero\n");
+	ERR(KABADTICKET);
+    }
+    /*
+     * Is the supplied ticket a tgt?
+     */
+    if (strcmp(sname, "krbtgt")) {
+	if (debug)
+	    fprintf(stderr, "ERROR: not for krbtgt service\n");
+	ERR(KABADTICKET);
+    }
+
+    /*
+     * This translator does not allow MIT-style cross-realm access.
+     * Is this a cross-realm ticket?
+     */
+    if (strcasecmp(sinst, localcell)) {
+	if (debug)
+	    fprintf(stderr,
+		    "ERROR: Service instance (%s) differs from local cell\n",
+		    sinst);
+	ERR(KABADTICKET);
+    }
+
+    /*
+     * This translator does not issue cross-realm tickets,
+     * since klog doesn't use this feature.
+     * Is the request for a cross-realm ticket?
+     */
+    if (strcasecmp(cell, localcell)) {
+	if (debug)
+	    fprintf(stderr, "ERROR: Cell %s != local cell", cell);
+	ERR(KABADTICKET);
+    }
+
+    /*
+     * Even if we later decide to issue cross-realm tickets,
+     * we should not permit "realm hopping".
+     * This means that the client's realm should match
+     * the realm of the tgt with whose key we are supposed
+     * to decrypt the ticket.  I think.
+     */
+    if (*realm && strcasecmp(realm, cell)) {
+	if (debug)
+	    fprintf(stderr, "ERROR: Realm %s != cell %s\n", realm, cell);
+	ERR(KABADTICKET);
+    }
+
+    /*
+     * This translator issues service tickets only for afs,
+     * since klog is the only client that should be using it.
+     * Is the requested service afs?
+     *
+     * Note: to make EMT work, we're allowing tickets for emt/admin and
+     * adm/admin.
+     */
+    if (! ((strcmp(rname, "afs") == 0 && ! *rinst) ||
+	   (strcmp(rname, "emt") == 0 && strcmp(rinst, "admin") == 0) ||
+	   (strcmp(rname, "adm") == 0 && strcmp(rinst, "admin") == 0)))
+	ERR(KABADSERVER);
+
+    /*
+     * If the local realm name and cell name differ and the user
+     * is in the local cell and has requested a ticket of afs. (no
+     * instance, then we actually want to get a ticket for
+     * afs/<cell name>@<realm name>
+     */
+    if ((strcmp(rname, "afs") == 0) && !*rinst &&
+	strcmp(localrealm, localcell) &&
+	(strcasecmp(cell, localcell) == 0)) {
+	char *c;
+
+	strcpy(rinst, localcell);
+
+	for (c = rinst; *c != NULL; c++)
+	    *c = (char) tolower( (int) *c);
+
+	if (debug)
+	    fprintf(stderr, "Getting ticket for afs/%s\n", localcell);
+    }
+   
+    /*
+     * Even if we later decide to issue service tickets for
+     * services other than afs, we should still disallow
+     * the "changepw" and "krbtgt" services.
+     */
+    if (!strcmp(rname, "changepw") || !strcmp(rname, "krbtgt"))
+	ERR(KABADSERVER);
+
+    /*
+     * Is the tgt valid yet?  (ie. is the start time in the future)
+     */
+    if (req_time < tgt_start_time - CLOCK_SKEW) {
+	if (debug)
+	    fprintf(stderr, "ERROR: Ticket not yet valid\n");
+	ERR(KABADTICKET);
+    }
+
+    /*
+     * Has the tgt expired?  (ie. is the end time in the past)
+     *
+     * Sigh, convert from V4 lifetimes back to Unix epoch times.
+     */
+
+    if (tgt_lifetime < 128)
+	tgt_end_time = tgt_start_time + tgt_lifetime * 300;
+    else if (tgt_lifetime < 192)
+	tgt_end_time = tgt_start_time + cmu_seconds[tgt_lifetime - 128];
+    else
+	tgt_end_time = tgt_start_time + MAX_TICKET_LIFETIME;
+
+    if (tgt_end_time < req_time) {
+	if (debug)
+	    fprintf(stderr, "ERROR: Ticket expired\n");
+	ERR(KABADTICKET);
+    }
+
+    /*
+     * This translator uses the requested start time as a cheesy
+     * authenticator, since the KA protocol does not have an
+     * explicit authenticator.  We can do this since klog always
+     * requests a start time equal to the current time.
+     * 
+     * Is the requested start time approximately now?
+     */
+    if (abs(req_time - start_time) > CLOCK_SKEW)
+	ERR(KACLOCKSKEW);
+
+    /*
+     * The new ticket's lifetime is the minimum of:
+     * 1.  remainder of tgt's lifetime
+     * 2.  requested lifetime
+     * 
+     * This is further limited by the client and service's max lifetime
+     * in make_reply_packet().
+     */
+
+    lifetime = tgt_end_time - req_time;
+    lifetime = min(lifetime, end_time - start_time);
+    end_time = req_time + lifetime;
+
+    /*
+     * We have all the data from the request, now generate the reply.
+     */
+
+    rv = make_reply_packet(context, handle, reply, 0, start_time, end_time,
+			   cname, cinst, rname, rinst,
+			   session_key, session_sched, "gtkt");
+  error:
+    memset(ticket, 0, sizeof(ticket));
+    memset(session_key, 0, sizeof(session_key));
+    memset(session_sched, 0, sizeof(session_sched));
+
+    if (free_princ_ent)
+	kadm5_free_principal_ent(handle, &cprinc);
+
+    syslog(LOG_INFO, "getticket: %s.%s from %s for %s.%s",
+	   cname, cinst, from, rname, rinst);
+    if (rv) {
+	syslog(LOG_INFO, "... failed due to %s", kaerror(rv));
+    }
+    return rv;
+}
+
+
+#undef	ERR
+#undef	ADVANCE
+#undef	GET_INT
+#undef	GET_PSTR
+#undef	GET_STR
+
+/*
+ * Convert the request into a reply.
+ * Returns 0 on success.
+ */
+
+void process(context, handle, from, req, reply)
+krb5_context context;
+void *handle;
+char *from;
+packet_t req, reply;
+{
+    int rv;
+    rx_t req_rx = (rx_t)req->base;
+    rx_t reply_rx = (rx_t)reply->base;
+    int service, request;
+
+    service = ntohs(req_rx->rx_service);
+    request = ntohl(req_rx->rx_request);
+
+    /* ignore everything but type 1 */
+    if (req_rx->rx_type != 1) {
+	reply->len = 0;
+	return;
+    }
+
+    /* copy the rx header and change the flags */
+    *reply_rx = *req_rx;
+    reply_rx->rx_flags = 4;
+
+    rv = -1;
+
+    if (service == 0x2db && (request == 0x15 || request == 0x16)) {
+	if (debug)
+	    fprintf(stderr, "Handling Authenticate request\n");
+	rv = Authenticate(context, handle, from, req, reply);
+    }
+    if (service == 0x2dc && request == 0x17) {
+	if (debug)
+	    fprintf(stderr, "Handling GetTicket request\n");
+	rv = GetTicket(context, handle, from, req, reply);
+    }
+/*
+    if (service == 0x2db && request == 0x1) {
+	rv = Authenticate_old(from, req, reply);
+    }
+    if (service == 0x2dc && request == 0x3) {
+	rv = GetTicket_old(from, req, reply);
+    }
+ */
+    if (rv == -1) {
+	syslog(LOG_INFO, "bogus request %d/%d", service, request);
+	rv = KABADREQUEST;
+    }
+
+    if (rv) {
+	/* send the error back to rx */
+	reply->len = sizeof (*reply_rx);
+
+	reply_rx->rx_type = 4;
+	reply_rx->rx_flags = 0;
+	reply_rx->rx_request = ntohl(rv);
+    }
+}
+
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+    int s, rv, ch, mflag = 0;
+    u_short port;
+    struct sockaddr_in sin;
+    int forwarders[MAXFORWARDERS], num_forwarders;
+    krb5_context context;
+    krb5_error_code code;
+    krb5_keyblock mkey;
+    krb5_principal master_princ;
+    kadm5_principal_ent_rec master_princ_rec;
+    void *handle;
+    facility_mapping *mapping;
+    int facility = LOG_DAEMON;
+
+    extern char *optarg;
+
+    port = 7004;
+    num_forwarders = 0;
+
+    /*
+     * Parse args.
+     */
+    while ((ch = getopt(argc, argv, "c:df:l:mp:r:")) != -1) {
+	switch (ch) {
+	case 'c':
+	    localcell = optarg;
+	    break;
+	case 'd':
+	    debug++;
+	    break;
+	case 'f': {
+	    struct hostent *hp;
+
+	    if (num_forwarders++ >= MAXFORWARDERS)
+		pexit("too many forwarders\n");
+
+	    hp = gethostbyname(optarg);
+	    if (!hp) {
+		printf("unknown host %s\n", optarg);
+		exit(1);
+	    }
+	    forwarders[num_forwarders - 1] = *(int *)hp->h_addr;
+
+	    break;
+	}
+	case 'l':
+	    for (mapping = mappings; mapping->string != NULL; mapping++)
+		if (strcmp(mapping->string, optarg) == 0)
+		    break;
+
+		if (mapping->string == NULL) {
+		    printf("Unknown facility \"%s\"\n", optarg);
+		    exit(1);
+		}
+
+		facility = mapping->num;
+		break;
+	case 'm':
+	    mflag = 1;
+	    break;
+	case 'p':
+	    if (isdigit(*optarg)) {
+		port = atoi(optarg);
+	    }
+	    else {
+		struct servent *sp;
+
+		sp = getservbyname(optarg, "udp");
+		if (!sp) {
+		    printf("unknown service %s\n", optarg);
+		    exit(1);
+		}
+		port = sp->s_port;
+	    }
+	    break;
+	case 'r':
+	    localrealm = optarg;
+	    break;
+	default:
+	    printf("usage: %s [-c cell] [-d] [-f forwarder-host] [-l facility ] [-p port] [-r realm]\n",
+		   argv[0]);
+	    exit(1);
+	}
+    }
+
+    openlog("fakeka", LOG_PID, facility);
+
+    port = htons(port);
+
+    /*
+     * Set up the socket.
+     */
+
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0)
+	perrorexit("Couldn't create socket");
+
+    sin.sin_family = AF_INET;
+    sin.sin_addr.s_addr = 0;
+    sin.sin_port = port;
+
+    rv = bind(s, (struct sockaddr *)&sin, sizeof(sin));
+    if (rv < 0)
+	perrorexit("Couldn't bind socket");
+
+    /*
+     * Initialize kerberos stuff and kadm5 stuff.
+     */
+
+    if ((code = krb5_init_context(&context))) {
+	com_err(argv[0], code, "while initializing Kerberos");
+	exit(1);
+    }
+
+    if (!localrealm && (code = krb5_get_default_realm(context, &localrealm))) {
+	com_err(argv[0], code, "while getting local realm");
+	exit(1);
+    }
+
+    if (!localcell)
+	localcell = localrealm;
+
+    if ((code = kadm5_init_with_password(progname, NULL, KADM5_ADMIN_SERVICE,
+					 NULL, KADM5_STRUCT_VERSION,
+					 KADM5_API_VERSION_2,
+					 (char **) NULL, /* db_args */
+					 &handle))) {
+	com_err(argv[0], code, "while initializing Kadm5");
+	exit(1);
+    }
+
+    if ((code = kadm5_get_config_params(context, NULL, NULL, NULL,
+					&realm_params))) {
+	com_err(argv[0], code, "while getting realm parameters");
+	exit(1);
+    }
+
+    if (! (realm_params.mask & KADM5_CONFIG_MAX_LIFE)) {
+	fprintf(stderr, "Cannot determine maximum ticket lifetime\n");
+	exit(1);
+    }
+
+    /*
+     * We need to initialize the random number generator for DES.  Use
+     * the master key to do this.
+     */
+
+    if ((code = krb5_parse_name(context, realm_params.mask &
+				KADM5_CONFIG_MKEY_NAME ?
+				realm_params.mkey_name : "K/M",
+				&master_princ))) {
+	com_err(argv[0], code, "while parsing master key name");
+	exit(1);
+    }
+
+    if ((code = kadm5_get_principal(handle, master_princ, &master_princ_rec,
+				    KADM5_KEY_DATA))) {
+	com_err(argv[0], code, "while getting master key data");
+	exit(1);
+    }
+
+    if ((code = kadm5_decrypt_key(handle, &master_princ_rec,
+				  ENCTYPE_DES_CBC_CRC, -1, 0, &mkey, NULL,
+				  NULL))) {
+	com_err(argv[0], code, "while decrypting the master key");
+	exit(1);
+    }
+
+    des_init_random_number_generator(mkey.contents);
+
+    krb5_free_keyblock_contents(context, &mkey);
+
+    kadm5_free_principal_ent(handle, &master_princ_rec);
+
+    krb5_free_principal(context, master_princ);
+
+    /*
+     * Fork and go into the background, if requested
+     */
+
+    if (!debug && mflag && daemon(0, 0)) {
+	com_err(argv[0], errno, "while detaching from tty");
+    }
+
+    /*
+     * rpc server loop.
+     */
+
+    for (;;) {
+	struct packet req, reply;
+	int sinlen, packetlen, i, forwarded;
+	char *from;
+
+	sinlen = sizeof(sin);
+	forwarded = 0;
+
+	memset(req.data, 0, sizeof(req.data));
+	rv = recvfrom(s, req.data, sizeof(req.data),
+		      0, (struct sockaddr *)&sin, &sinlen);
+
+	if (rv < 0) {
+	    syslog(LOG_ERR, "recvfrom failed: %m");
+	    sleep(1);
+	    continue;
+	}
+	packetlen = rv;
+
+	for (i = 0; i < num_forwarders; i++) {
+	    if (sin.sin_addr.s_addr == forwarders[i]) {
+		forwarded = 1;
+		break;
+	    }
+	}
+
+	if ((code = krb5_timeofday(context, &req_time))) {
+		syslog(LOG_ERR, "krb5_timeofday failed: %s",
+		       error_message(code));
+		continue;
+	}
+
+	memset(reply.data, 0, sizeof(reply.data));
+	req.len = packetlen;
+	req.base = req.data;
+	reply.base = reply.data;
+	reply.len = sizeof(reply.data);
+
+	if (forwarded) {
+	    struct in_addr ia;
+
+	    memcpy(&ia.s_addr, req.data, 4);
+	    from = inet_ntoa(ia);
+	    /*
+	     * copy the forwarder header and adjust the bases and lengths.
+	     */
+	    memcpy(reply.data, req.data, HEADER_LEN);
+	    req.base += HEADER_LEN;
+	    req.len -= HEADER_LEN;
+	    reply.base += HEADER_LEN;
+	    reply.len -= HEADER_LEN;
+	}
+	else {
+	    from = inet_ntoa(sin.sin_addr);
+	}
+
+	process(context, handle, from, &req, &reply);
+
+	if (reply.len == 0)
+	    continue;
+
+	if (forwarded) {
+	    /* re-adjust the length to account for the forwarder header */
+	    reply.len += HEADER_LEN;
+	}
+
+	rv = sendto(s, reply.data, reply.len,
+		    0, (struct sockaddr *)&sin, sinlen);
+	if (rv < 0) {
+	    syslog(LOG_ERR, "sendto failed: %m");
+	    sleep(1);
+	}
+    }
+    /*NOTREACHED*/
+}
diff --git a/mechglue/src/kdc/kdc5_err.et b/mechglue/src/kdc/kdc5_err.et
new file mode 100644
index 000000000..9d0ce877c
--- /dev/null
+++ b/mechglue/src/kdc/kdc5_err.et
@@ -0,0 +1,35 @@
+#
+# kdc/kdc5_err.et
+#
+# Copyright 1990 by the Massachusetts Institute of Technology.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+#
+# KDC internal error table.
+
+error_table	kdc5
+
+error_code KDC5_RCSID,		"$Id$"
+error_code KDC5_NOPORT,		"No server port found"
+error_code KDC5_NONET,		"Network not initialized"
+error_code KDC5_IO_RESPONSE,	"Short write while sending response"
+
+end
diff --git a/mechglue/src/kdc/kdc_preauth.c b/mechglue/src/kdc/kdc_preauth.c
new file mode 100644
index 000000000..0fcb62a74
--- /dev/null
+++ b/mechglue/src/kdc/kdc_preauth.c
@@ -0,0 +1,1604 @@
+/*
+ * kdc/kdc_preauth.c
+ *
+ * Copyright 1995, 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Preauthentication routines for the KDC.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "kdc_util.h"
+#include "extern.h"
+#include <stdio.h>
+#include "adm_proto.h"
+#include <syslog.h>
+
+#include <assert.h>
+
+/* XXX This is ugly and should be in a header file somewhere */
+#ifndef KRB5INT_DES_TYPES_DEFINED
+#define KRB5INT_DES_TYPES_DEFINED
+typedef unsigned char des_cblock[8];	/* crypto-block size */
+#endif
+typedef des_cblock mit_des_cblock;
+extern void mit_des_fixup_key_parity (mit_des_cblock );
+extern int mit_des_is_weak_key (mit_des_cblock );
+
+typedef krb5_error_code (*verify_proc)
+    (krb5_context, krb5_db_entry *client,
+		    krb5_kdc_req *request,
+		    krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data);
+
+typedef krb5_error_code (*edata_proc)
+    (krb5_context, krb5_kdc_req *request,
+		    krb5_db_entry *client, krb5_db_entry *server,
+		    krb5_pa_data *data);
+
+typedef krb5_error_code (*return_proc)
+    (krb5_context, krb5_pa_data * padata, 
+		    krb5_db_entry *client,
+		    krb5_kdc_req *request, krb5_kdc_rep *reply,
+		    krb5_key_data *client_key,
+		    krb5_keyblock *encrypting_key,
+		    krb5_pa_data **send_pa);
+
+typedef struct _krb5_preauth_systems {
+    char *	name;
+    int		type;
+    int		flags;
+    edata_proc	get_edata;
+    verify_proc	verify_padata;
+    return_proc return_padata;
+} krb5_preauth_systems;
+
+static krb5_error_code verify_enc_timestamp
+    (krb5_context, krb5_db_entry *client,
+		    krb5_kdc_req *request,
+		    krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data);
+
+static krb5_error_code get_etype_info
+    (krb5_context, krb5_kdc_req *request,
+		    krb5_db_entry *client, krb5_db_entry *server,
+		    krb5_pa_data *data);
+static krb5_error_code
+get_etype_info2(krb5_context context, krb5_kdc_req *request,
+	       krb5_db_entry *client, krb5_db_entry *server,
+		  krb5_pa_data *pa_data);
+static krb5_error_code
+etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata, 
+			 krb5_db_entry *client,
+			 krb5_kdc_req *request, krb5_kdc_rep *reply,
+			 krb5_key_data *client_key,
+			 krb5_keyblock *encrypting_key,
+			 krb5_pa_data **send_pa,
+			 int etype_info2);
+
+static krb5_error_code
+return_etype_info(krb5_context, krb5_pa_data * padata, 
+		  krb5_db_entry *client,
+		  krb5_kdc_req *request, krb5_kdc_rep *reply,
+		  krb5_key_data *client_key,
+		  krb5_keyblock *encrypting_key,
+		  krb5_pa_data **send_pa);
+
+static krb5_error_code
+return_etype_info2(krb5_context, krb5_pa_data * padata, 
+		   krb5_db_entry *client,
+		   krb5_kdc_req *request, krb5_kdc_rep *reply,
+		   krb5_key_data *client_key,
+		   krb5_keyblock *encrypting_key,
+		   krb5_pa_data **send_pa);
+
+static krb5_error_code return_pw_salt
+    (krb5_context, krb5_pa_data * padata, 
+		    krb5_db_entry *client,
+		    krb5_kdc_req *request, krb5_kdc_rep *reply,
+		    krb5_key_data *client_key,
+		    krb5_keyblock *encrypting_key,
+		    krb5_pa_data **send_pa);
+
+/* SAM preauth support */
+static krb5_error_code verify_sam_response
+    (krb5_context, krb5_db_entry *client,
+		    krb5_kdc_req *request,
+		    krb5_enc_tkt_part * enc_tkt_reply, krb5_pa_data *data);
+
+static krb5_error_code get_sam_edata
+    (krb5_context, krb5_kdc_req *request,
+		    krb5_db_entry *client, krb5_db_entry *server,
+		    krb5_pa_data *data);
+static krb5_error_code return_sam_data
+    (krb5_context, krb5_pa_data * padata, 
+		    krb5_db_entry *client,
+		    krb5_kdc_req *request, krb5_kdc_rep *reply,
+		    krb5_key_data *client_key,
+		    krb5_keyblock *encrypting_key,
+		    krb5_pa_data **send_pa);
+/*
+ * Preauth property flags
+ */
+#define PA_HARDWARE	0x00000001
+#define PA_REQUIRED	0x00000002
+#define PA_SUFFICIENT	0x00000004
+	/* Not really a padata, so don't include it in the etype list*/
+#define PA_PSEUDO	0x00000008 
+
+static krb5_preauth_systems preauth_systems[] = {
+    {
+	"timestamp",
+        KRB5_PADATA_ENC_TIMESTAMP,
+        0,
+        0,
+	verify_enc_timestamp,
+	0
+    },
+    {
+	"etype-info",
+	KRB5_PADATA_ETYPE_INFO,
+	0,
+	get_etype_info,
+	0,
+	return_etype_info
+    },
+    {
+	"etype-info2",
+	KRB5_PADATA_ETYPE_INFO2,
+	0,
+	get_etype_info2,
+	0,
+	return_etype_info2
+    },
+    {
+	"pw-salt",
+	KRB5_PADATA_PW_SALT,
+	PA_PSEUDO,		/* Don't include this in the error list */
+	0, 
+	0,
+	return_pw_salt
+    },
+    {
+	"sam-response",
+	KRB5_PADATA_SAM_RESPONSE,
+	0,
+	0,
+	verify_sam_response,
+	return_sam_data
+    },
+    {
+	"sam-challenge",
+	KRB5_PADATA_SAM_CHALLENGE,
+	PA_HARDWARE,		/* causes get_preauth_hint_list to use this */
+	get_sam_edata,
+	0,
+	0
+    },
+    { "[end]", -1,}
+};
+
+#define MAX_PREAUTH_SYSTEMS (sizeof(preauth_systems)/sizeof(preauth_systems[0]))
+
+static krb5_error_code
+find_pa_system(int type, krb5_preauth_systems **preauth)
+{
+    krb5_preauth_systems 	*ap = preauth_systems;
+    
+    while ((ap->type != -1) && (ap->type != type))
+	ap++;
+    if (ap->type == -1)
+	return(KRB5_PREAUTH_BAD_TYPE);
+    *preauth = ap;
+    return 0;
+} 
+
+const char *missing_required_preauth(krb5_db_entry *client,
+				     krb5_db_entry *server,
+				     krb5_enc_tkt_part *enc_tkt_reply)
+{
+#if 0
+    /*
+     * If this is the pwchange service, and the pre-auth bit is set,
+     * allow it even if the HW preauth would normally be required.
+     * 
+     * Sandia national labs wanted this for some strange reason... we
+     * leave it disabled normally.
+     */
+    if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) &&
+	isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
+	return 0;
+#endif
+    
+#ifdef DEBUG
+    krb5_klog_syslog (LOG_DEBUG,
+		      "client needs %spreauth, %shw preauth; request has %spreauth, %shw preauth",
+		      isflagset (client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) ? "" : "no ",
+		      isflagset (client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ? "" : "no ",
+		      isflagset (enc_tkt_reply->flags, TKT_FLG_PRE_AUTH) ? "" : "no ",
+		      isflagset (enc_tkt_reply->flags, TKT_FLG_HW_AUTH) ? "" : "no ");
+#endif
+
+    if (isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
+	 !isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
+	return "NEEDED_PREAUTH";
+
+    if (isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
+	!isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
+	return "NEEDED_HW_PREAUTH";
+
+    return 0;
+}
+
+void get_preauth_hint_list(krb5_kdc_req *request, krb5_db_entry *client,
+			   krb5_db_entry *server, krb5_data *e_data)
+{
+    int hw_only;
+    krb5_preauth_systems *ap;
+    krb5_pa_data **pa_data, **pa;
+    krb5_data *edat;
+    krb5_error_code retval;
+    
+    /* Zero these out in case we need to abort */
+    e_data->length = 0;
+    e_data->data = 0;
+    
+    hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH);
+    pa_data = malloc(sizeof(krb5_pa_data *) * (MAX_PREAUTH_SYSTEMS+1));
+    if (pa_data == 0)
+	return;
+    memset(pa_data, 0, sizeof(krb5_pa_data *) * (MAX_PREAUTH_SYSTEMS+1));
+    pa = pa_data;
+
+    for (ap = preauth_systems; ap->type != -1; ap++) {
+	if (hw_only && !(ap->flags & PA_HARDWARE))
+	    continue;
+	if (ap->flags & PA_PSEUDO)
+	    continue;
+	*pa = malloc(sizeof(krb5_pa_data));
+	if (*pa == 0)
+	    goto errout;
+	memset(*pa, 0, sizeof(krb5_pa_data));
+	(*pa)->magic = KV5M_PA_DATA;
+	(*pa)->pa_type = ap->type;
+	if (ap->get_edata) {
+	  retval = (ap->get_edata)(kdc_context, request, client, server, *pa);
+	  if (retval) {
+	    /* just failed on this type, continue */
+	    free(*pa);
+	    *pa = 0;
+	    continue;
+	  }
+	}
+	pa++;
+    }
+    if (pa_data[0] == 0) {
+	krb5_klog_syslog (LOG_INFO,
+			  "%spreauth required but hint list is empty",
+			  hw_only ? "hw" : "");
+    }
+    retval = encode_krb5_padata_sequence((const krb5_pa_data **) pa_data,
+					 &edat);
+    if (retval)
+	goto errout;
+    *e_data = *edat;
+    free(edat);
+
+errout:
+    krb5_free_pa_data(kdc_context, pa_data);
+    return;
+}
+
+/*
+ * This routine is called to verify the preauthentication information
+ * for a V5 request.
+ * 	
+ * Returns 0 if the pre-authentication is valid, non-zero to indicate
+ * an error code of some sort.
+ */
+
+krb5_error_code
+check_padata (krb5_context context, krb5_db_entry *client,
+	      krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply)
+{
+    krb5_error_code retval = 0;
+    krb5_pa_data **padata;
+    krb5_preauth_systems *pa_sys;
+    int			pa_ok = 0, pa_found = 0;
+
+    if (request->padata == 0)
+	return 0;
+
+#ifdef DEBUG
+    krb5_klog_syslog (LOG_DEBUG, "checking padata");
+#endif
+    for (padata = request->padata; *padata; padata++) {
+#ifdef DEBUG
+	krb5_klog_syslog (LOG_DEBUG, ".. pa_type 0x%x", (*padata)->pa_type);
+#endif
+	if (find_pa_system((*padata)->pa_type, &pa_sys))
+	    continue;
+#ifdef DEBUG
+	krb5_klog_syslog (LOG_DEBUG, ".. pa_type %s", pa_sys->name);
+#endif
+	if (pa_sys->verify_padata == 0)
+	    continue;
+	pa_found++;
+	retval = pa_sys->verify_padata(context, client, request,
+				       enc_tkt_reply, *padata);
+	if (retval) {
+	    krb5_klog_syslog (LOG_INFO, "preauth (%s) verify failure: %s",
+			      pa_sys->name, error_message (retval));
+	    if (pa_sys->flags & PA_REQUIRED) {
+		pa_ok = 0;
+		break;
+	    }
+	} else {
+#ifdef DEBUG
+	    krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
+#endif
+	    pa_ok = 1;
+	    if (pa_sys->flags & PA_SUFFICIENT) 
+		break;
+	}
+    }
+    if (pa_ok)
+	return 0;
+
+    /* pa system was not found, but principal doesn't require preauth */
+    if (!pa_found &&
+        !isflagset(client->attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
+        !isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH))
+       return 0;
+
+    if (!pa_found)
+	krb5_klog_syslog (LOG_INFO, "no valid preauth type found: %s",
+			  error_message (retval));
+/* The following switch statement allows us
+ * to return some preauth system errors back to the client.
+ */
+        switch(retval) {
+	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+    case KRB5KRB_AP_ERR_SKEW:
+	return retval;
+    default:
+	return KRB5KDC_ERR_PREAUTH_FAILED;
+    }
+}
+
+/*
+ * return_padata creates any necessary preauthentication
+ * structures which should be returned by the KDC to the client
+ */
+krb5_error_code
+return_padata(krb5_context context, krb5_db_entry *client,
+	      krb5_kdc_req *request, krb5_kdc_rep *reply,
+	      krb5_key_data *client_key, krb5_keyblock *encrypting_key)
+{
+    krb5_error_code		retval;
+    krb5_pa_data **		padata;
+    krb5_pa_data **		send_pa_list;
+    krb5_pa_data **		send_pa;
+    krb5_pa_data *		pa = 0;
+    krb5_preauth_systems *	ap;
+    int 			size = 0;
+
+    for (ap = preauth_systems; ap->type != -1; ap++) {
+	if (ap->return_padata)
+	    size++;
+    }
+
+    if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
+	return ENOMEM;
+
+    send_pa = send_pa_list;
+    *send_pa = 0;
+    
+    for (ap = preauth_systems; ap->type != -1; ap++) {
+	if (ap->return_padata == 0)
+	    continue;
+	pa = 0;
+	if (request->padata) {
+	    for (padata = request->padata; *padata; padata++) {
+		if ((*padata)->pa_type == ap->type) {
+		    pa = *padata;
+		    break;
+		}
+	    }
+	}
+	if ((retval = ap->return_padata(context, pa, client, request, reply,
+					client_key, encrypting_key, send_pa)))
+	    goto cleanup;
+
+	if (*send_pa)
+	    send_pa++;
+	*send_pa = 0;
+    }
+    
+    retval = 0;
+
+    if (send_pa_list[0]) {
+	reply->padata = send_pa_list;
+	send_pa_list = 0;
+    }
+    
+cleanup:
+    if (send_pa_list)
+	krb5_free_pa_data(context, send_pa_list);
+    return (retval);
+}
+
+static krb5_boolean
+enctype_requires_etype_info_2(krb5_enctype enctype)
+{
+    switch(enctype) {
+    case ENCTYPE_DES_CBC_CRC:
+    case ENCTYPE_DES_CBC_MD4:
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES3_CBC_SHA1:
+    case ENCTYPE_DES3_CBC_RAW:
+    case ENCTYPE_ARCFOUR_HMAC:
+    case ENCTYPE_ARCFOUR_HMAC_EXP :
+	return 0;
+    default:
+	if (krb5_c_valid_enctype(enctype))
+	    return 1;
+	else return 0;
+    }
+}
+
+static krb5_boolean
+request_contains_enctype (krb5_context context,  const krb5_kdc_req *request,
+			  krb5_enctype enctype)
+{
+    int i;
+    for (i =0; i < request->nktypes; i++)
+	if (request->ktype[i] == enctype)
+	    return 1;
+    return 0;
+}
+
+
+static krb5_error_code
+verify_enc_timestamp(krb5_context context, krb5_db_entry *client,
+		     krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
+		     krb5_pa_data *pa)
+{
+    krb5_pa_enc_ts *		pa_enc = 0;
+    krb5_error_code		retval;
+    krb5_data			scratch;
+    krb5_data			enc_ts_data;
+    krb5_enc_data 		*enc_data = 0;
+    krb5_keyblock		key;
+    krb5_key_data *		client_key;
+    krb5_int32			start;
+    krb5_timestamp		timenow;
+    krb5_error_code		decrypt_err;
+
+    scratch.data = pa->contents;
+    scratch.length = pa->length;
+
+    enc_ts_data.data = 0;
+    
+    if ((retval = decode_krb5_enc_data(&scratch, &enc_data)) != 0)
+	goto cleanup;
+
+    enc_ts_data.length = enc_data->ciphertext.length;
+    if ((enc_ts_data.data = (char *) malloc(enc_ts_data.length)) == NULL)
+	goto cleanup;
+
+    start = 0;
+    decrypt_err = 0;
+    while (1) {
+	if ((retval = krb5_dbe_search_enctype(context, client,
+					      &start, enc_data->enctype,
+					      -1, 0, &client_key)))
+	    goto cleanup;
+
+	if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock, 
+						  client_key, &key, NULL)))
+	    goto cleanup;
+
+	key.enctype = enc_data->enctype;
+
+	retval = krb5_c_decrypt(context, &key, KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
+				0, enc_data, &enc_ts_data);
+	krb5_free_keyblock_contents(context, &key);
+	if (retval == 0)
+	    break;
+	else
+	    decrypt_err = retval;
+    }
+
+    if ((retval = decode_krb5_pa_enc_ts(&enc_ts_data, &pa_enc)) != 0)
+	goto cleanup;
+
+    if ((retval = krb5_timeofday(context, &timenow)) != 0)
+	goto cleanup;
+    
+    if (labs(timenow - pa_enc->patimestamp) > context->clockskew) {
+	retval = KRB5KRB_AP_ERR_SKEW;
+	goto cleanup;
+    }
+
+    setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
+
+    retval = 0;
+    
+cleanup:
+    if (enc_data) {
+	krb5_free_data_contents(context, &enc_data->ciphertext);
+	free(enc_data);
+    }
+    krb5_free_data_contents(context, &enc_ts_data);
+    if (pa_enc)
+	free(pa_enc);
+    /*
+     * If we get NO_MATCHING_KEY and decryption previously failed, and
+     * we failed to find any other keys of the correct enctype after
+     * that failed decryption, it probably means that the password was
+     * incorrect.
+     */
+    if (retval == KRB5_KDB_NO_MATCHING_KEY && decrypt_err != 0)
+	retval = decrypt_err;
+    return retval;
+}
+
+static krb5_error_code
+_make_etype_info_entry(krb5_context context,
+		       krb5_kdc_req *request, krb5_key_data *client_key,
+		       krb5_enctype etype, krb5_etype_info_entry **entry,
+		       int etype_info2)
+{
+    krb5_data			salt;
+    krb5_etype_info_entry *	tmp_entry; 
+    krb5_error_code		retval;
+
+    if ((tmp_entry = malloc(sizeof(krb5_etype_info_entry))) == NULL)
+       return ENOMEM;
+
+    salt.data = 0;
+
+    tmp_entry->magic = KV5M_ETYPE_INFO_ENTRY;
+    tmp_entry->etype = etype;
+    tmp_entry->length = KRB5_ETYPE_NO_SALT;
+    tmp_entry->salt = 0;
+    tmp_entry->s2kparams.data = NULL;
+    tmp_entry->s2kparams.length = 0;
+    retval = get_salt_from_key(context, request->client,
+			       client_key, &salt);
+    if (retval)
+	goto fail;
+    if (etype_info2 && client_key->key_data_ver > 1 &&
+	client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_AFS3) {
+	switch (etype) {
+	case ENCTYPE_DES_CBC_CRC:
+	case ENCTYPE_DES_CBC_MD4:
+	case ENCTYPE_DES_CBC_MD5:
+	    tmp_entry->s2kparams.data = malloc(1);
+	    if (tmp_entry->s2kparams.data == NULL) {
+		retval = ENOMEM;
+		goto fail;
+	    }
+	    tmp_entry->s2kparams.length = 1;
+	    tmp_entry->s2kparams.data[0] = 1;
+	    break;
+	default:
+	    break;
+	}
+    }
+
+    if (salt.length >= 0) {
+	tmp_entry->length = salt.length;
+	tmp_entry->salt = (unsigned char *) salt.data;
+	salt.data = 0;
+    }
+    *entry = tmp_entry;
+    return 0;
+
+fail:
+    if (tmp_entry) {
+	if (tmp_entry->s2kparams.data)
+	    free(tmp_entry->s2kparams.data);
+	free(tmp_entry);
+    }
+    if (salt.data)
+	free(salt.data);
+    return retval;
+}
+/*
+ * This function returns the etype information for a particular
+ * client, to be passed back in the preauth list in the KRB_ERROR
+ * message.  It supports generating both etype_info  and etype_info2
+ *  as most of the work is the same.   
+ */
+static krb5_error_code
+etype_info_helper(krb5_context context, krb5_kdc_req *request,
+	       krb5_db_entry *client, krb5_db_entry *server,
+	       krb5_pa_data *pa_data, int etype_info2)
+{
+    krb5_etype_info_entry **	entry = 0;
+    krb5_key_data		*client_key;
+    krb5_error_code		retval;
+    krb5_data *			scratch;
+    krb5_enctype		db_etype;
+    int 			i = 0;
+    int 			start = 0;
+    int				seen_des = 0;
+
+    entry = malloc((client->n_key_data * 2 + 1) * sizeof(krb5_etype_info_entry *));
+    if (entry == NULL)
+	return ENOMEM;
+    entry[0] = NULL;
+
+    while (1) {
+	retval = krb5_dbe_search_enctype(context, client, &start, -1,
+					 -1, 0, &client_key);
+	if (retval == KRB5_KDB_NO_MATCHING_KEY)
+	    break;
+	if (retval)
+	    goto cleanup;
+	db_etype = client_key->key_data_type[0];
+	if (db_etype == ENCTYPE_DES_CBC_MD4)
+	    db_etype = ENCTYPE_DES_CBC_MD5;
+	
+	if (request_contains_enctype(context, request, db_etype)) {
+	    assert(etype_info2 ||
+		   !enctype_requires_etype_info_2(db_etype));
+	    if ((retval = _make_etype_info_entry(context, request, client_key,
+			    db_etype, &entry[i], etype_info2)) != 0) {
+		goto cleanup;
+	    }
+	    entry[i+1] = 0;
+	    i++;
+	}
+
+	/* 
+	 * If there is a des key in the kdb, try the "similar" enctypes,
+	 * avoid duplicate entries. 
+	 */
+	if (!seen_des) {
+	    switch (db_etype) {
+	    case ENCTYPE_DES_CBC_MD5:
+		db_etype = ENCTYPE_DES_CBC_CRC;
+		break;
+	    case ENCTYPE_DES_CBC_CRC:
+		db_etype = ENCTYPE_DES_CBC_MD5;
+		break;
+	    default:
+		continue;
+
+	    }
+	    if (request_contains_enctype(context, request, db_etype)) {
+		if ((retval = _make_etype_info_entry(context, request,
+				client_key, db_etype, &entry[i], etype_info2)) != 0) {
+		    goto cleanup;
+		}
+		entry[i+1] = 0;
+		i++;
+	    }
+	    seen_des++;
+	}
+    }
+    if (etype_info2)
+	retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry,
+				    &scratch);
+    else 	retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry,
+				    &scratch);
+    if (retval)
+	goto cleanup;
+    pa_data->contents = (unsigned char *)scratch->data;
+    pa_data->length = scratch->length;
+    free(scratch);
+
+    retval = 0;
+
+cleanup:
+    if (entry)
+	krb5_free_etype_info(context, entry);
+    return retval;
+}
+
+static krb5_error_code
+get_etype_info(krb5_context context, krb5_kdc_req *request,
+	       krb5_db_entry *client, krb5_db_entry *server,
+	       krb5_pa_data *pa_data)
+{
+  int i;
+    for (i=0;  i < request->nktypes; i++) {
+	if (enctype_requires_etype_info_2(request->ktype[i])) 
+	    return KRB5KDC_ERR_PADATA_TYPE_NOSUPP ;;;; /*Caller will
+							* skip this
+							* type*/
+    }
+    return etype_info_helper(context, request, client, server, pa_data, 0);
+}
+
+static krb5_error_code
+get_etype_info2(krb5_context context, krb5_kdc_req *request,
+	       krb5_db_entry *client, krb5_db_entry *server,
+	       krb5_pa_data *pa_data)
+{
+    return etype_info_helper( context, request, client, server, pa_data, 1);
+}
+
+static krb5_error_code
+etype_info_as_rep_helper(krb5_context context, krb5_pa_data * padata, 
+			 krb5_db_entry *client,
+			 krb5_kdc_req *request, krb5_kdc_rep *reply,
+			 krb5_key_data *client_key,
+			 krb5_keyblock *encrypting_key,
+			 krb5_pa_data **send_pa,
+			 int etype_info2)
+{
+    int i;
+    krb5_error_code retval;
+    krb5_pa_data *tmp_padata;
+    krb5_etype_info_entry **entry = NULL;
+    krb5_data *scratch = NULL;
+
+    /*
+     * Skip PA-ETYPE-INFO completely if AS-REQ lists any "newer"
+     * enctypes.
+     */
+    if (!etype_info2) {
+	for (i = 0; i < request->nktypes; i++) {
+	    if (enctype_requires_etype_info_2(request->ktype[i])) {
+		*send_pa = NULL;
+		return 0;
+	    }
+	}
+    }
+
+    tmp_padata = malloc( sizeof(krb5_pa_data));
+    if (tmp_padata == NULL)
+	return ENOMEM;
+    if (etype_info2)
+	tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO2;
+    else
+	tmp_padata->pa_type = KRB5_PADATA_ETYPE_INFO;
+
+    entry = malloc(2 * sizeof(krb5_etype_info_entry *));
+    if (entry == NULL) {
+	retval = ENOMEM;
+	goto cleanup;
+    }
+    entry[0] = NULL;
+    entry[1] = NULL;
+    retval = _make_etype_info_entry(context, request,
+				    client_key, encrypting_key->enctype,
+				    entry, etype_info2);
+    if (retval)
+	goto cleanup;
+
+    if (etype_info2)
+	retval = encode_krb5_etype_info2((const krb5_etype_info_entry **) entry, &scratch);
+    else
+	retval = encode_krb5_etype_info((const krb5_etype_info_entry **) entry, &scratch);
+
+    if (retval)
+	goto cleanup;
+    tmp_padata->contents = scratch->data;
+    tmp_padata->length = scratch->length;
+    *send_pa = tmp_padata;
+
+    /* For cleanup - we no longer own the contents of the krb5_data 
+     * only to pointer to the krb5_data
+     */
+    scratch->data = 0;
+
+ cleanup:
+    if (entry)
+	krb5_free_etype_info(context, entry);
+    if (retval) {
+	if (tmp_padata)
+	    free(tmp_padata);
+    }
+    if (scratch)
+	    krb5_free_data(context, scratch);
+    return retval;
+}
+
+static krb5_error_code
+return_etype_info2(krb5_context context, krb5_pa_data * padata, 
+		   krb5_db_entry *client,
+		   krb5_kdc_req *request, krb5_kdc_rep *reply,
+		   krb5_key_data *client_key,
+		   krb5_keyblock *encrypting_key,
+		   krb5_pa_data **send_pa)
+{
+    return etype_info_as_rep_helper(context, padata, client, request, reply,
+				    client_key, encrypting_key, send_pa, 1);
+}
+
+
+static krb5_error_code
+return_etype_info(krb5_context context, krb5_pa_data * padata, 
+		  krb5_db_entry *client,
+		  krb5_kdc_req *request, krb5_kdc_rep *reply,
+		  krb5_key_data *client_key,
+		  krb5_keyblock *encrypting_key,
+		  krb5_pa_data **send_pa)
+{
+    return etype_info_as_rep_helper(context, padata, client, request, reply,
+				    client_key, encrypting_key, send_pa, 0);
+}
+
+static krb5_error_code
+return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
+	       krb5_db_entry *client, krb5_kdc_req *request,
+	       krb5_kdc_rep *reply, krb5_key_data *client_key,
+	       krb5_keyblock *encrypting_key, krb5_pa_data **send_pa)
+{
+    krb5_error_code	retval;
+    krb5_pa_data *	padata;
+    krb5_data *		scratch;
+    krb5_data		salt_data;
+    int i;
+    
+    for (i = 0; i < request->nktypes; i++) {
+	if (enctype_requires_etype_info_2(request->ktype[i]))
+	    return 0;
+    }
+    if (client_key->key_data_ver == 1 ||
+	client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)
+	return 0;
+
+    if ((padata = malloc(sizeof(krb5_pa_data))) == NULL)
+	return ENOMEM;
+    padata->magic = KV5M_PA_DATA;
+    padata->pa_type = KRB5_PADATA_PW_SALT;
+    
+    switch (client_key->key_data_type[1]) {
+    case KRB5_KDB_SALTTYPE_V4:
+	/* send an empty (V4) salt */
+	padata->contents = 0;
+	padata->length = 0;
+	break;
+    case KRB5_KDB_SALTTYPE_NOREALM:
+	if ((retval = krb5_principal2salt_norealm(kdc_context, 
+						   request->client,
+						   &salt_data)))
+	    goto cleanup;
+	padata->contents = (krb5_octet *)salt_data.data;
+	padata->length = salt_data.length;
+	break;
+    case KRB5_KDB_SALTTYPE_AFS3:
+	/* send an AFS style realm-based salt */
+	/* for now, just pass the realm back and let the client
+	   do the work. In the future, add a kdc configuration
+	   variable that specifies the old cell name. */
+	padata->pa_type = KRB5_PADATA_AFS3_SALT;
+	/* it would be just like ONLYREALM, but we need to pass the 0 */
+	scratch = krb5_princ_realm(kdc_context, request->client);
+	if ((padata->contents = malloc(scratch->length+1)) == NULL) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+	memcpy(padata->contents, scratch->data, scratch->length);
+	padata->length = scratch->length+1;
+	padata->contents[scratch->length] = 0;
+	break;
+    case KRB5_KDB_SALTTYPE_ONLYREALM:
+	scratch = krb5_princ_realm(kdc_context, request->client);
+	if ((padata->contents = malloc(scratch->length)) == NULL) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+	memcpy(padata->contents, scratch->data, scratch->length);
+	padata->length = scratch->length;
+	break;
+    case KRB5_KDB_SALTTYPE_SPECIAL:
+	if ((padata->contents = malloc(client_key->key_data_length[1]))
+	    == NULL) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+	memcpy(padata->contents, client_key->key_data_contents[1],
+	       client_key->key_data_length[1]);
+	padata->length = client_key->key_data_length[1];
+	break;
+    default:
+	free(padata);
+	return 0;
+    }
+
+    *send_pa = padata;
+    return 0;
+    
+cleanup:
+    free(padata);
+    return retval;
+}
+
+static krb5_error_code
+return_sam_data(krb5_context context, krb5_pa_data *in_padata,
+		krb5_db_entry *client, krb5_kdc_req *request,
+		krb5_kdc_rep *reply, krb5_key_data *client_key,
+		krb5_keyblock *encrypting_key, krb5_pa_data **send_pa)
+{
+    krb5_error_code	retval;
+    krb5_data		scratch;
+    int			i;
+
+    krb5_sam_response		*sr = 0;
+    krb5_predicted_sam_response	*psr = 0;
+
+    if (in_padata == 0)
+	return 0;
+
+    /*
+     * We start by doing the same thing verify_sam_response() does:
+     * extract the psr from the padata (which is an sr). Nothing
+     * here should generate errors! We've already successfully done
+     * all this once.
+     */
+
+    scratch.data = in_padata->contents;
+    scratch.length = in_padata->length;
+    
+    if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
+	com_err("krb5kdc", retval,
+		"return_sam_data(): decode_krb5_sam_response failed");
+	goto cleanup;
+    }
+
+    {
+	krb5_enc_data tmpdata;
+
+	tmpdata.enctype = ENCTYPE_UNKNOWN;
+	tmpdata.ciphertext = sr->sam_track_id;
+
+	scratch.length = tmpdata.ciphertext.length;
+	if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+
+	if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
+				     &tmpdata, &scratch))) {
+	    com_err("krb5kdc", retval,
+		    "return_sam_data(): decrypt track_id failed");
+	    free(scratch.data);
+	    goto cleanup;
+	}
+    }
+
+    if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
+	com_err("krb5kdc", retval,
+		"return_sam_data(): decode_krb5_predicted_sam_response failed");
+	free(scratch.data);
+	goto cleanup;
+    }
+
+    /* We could use sr->sam_flags, but it may be absent or altered. */
+    if (psr->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
+	com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
+		"Unsupported SAM flag must-pk-encrypt-sad");
+	goto cleanup;
+    }
+    if (psr->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
+	/* No key munging */
+	goto cleanup;
+    }
+    if (psr->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
+	/* Use sam_key instead of client key */
+	krb5_free_keyblock_contents(context, encrypting_key);
+	krb5_copy_keyblock_contents(context, &psr->sam_key, encrypting_key);
+	/* XXX Attach a useful pa_data */
+	goto cleanup;
+    }
+
+    /* Otherwise (no flags set), we XOR the keys */
+    /* XXX The passwords-04 draft is underspecified here wrt different
+	   key types. We will do what I hope to get into the -05 draft. */
+    {
+	krb5_octet *p = encrypting_key->contents;
+	krb5_octet *q = psr->sam_key.contents;
+	int length = ((encrypting_key->length < psr->sam_key.length)
+		      ? encrypting_key->length
+		      : psr->sam_key.length);
+
+	for (i = 0; i < length; i++)
+	    p[i] ^= q[i];
+    }
+
+    /* Post-mixing key correction */
+    switch (encrypting_key->enctype) {
+    case ENCTYPE_DES_CBC_CRC:
+    case ENCTYPE_DES_CBC_MD4:
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES_CBC_RAW:
+	mit_des_fixup_key_parity(encrypting_key->contents);
+	if (mit_des_is_weak_key(encrypting_key->contents))
+	    ((krb5_octet *) encrypting_key->contents)[7] ^= 0xf0;
+	break;
+
+    /* XXX case ENCTYPE_DES3_CBC_MD5: listed in 1510bis-04 draft */
+    case ENCTYPE_DES3_CBC_SHA: /* XXX deprecated? */
+    case ENCTYPE_DES3_CBC_RAW:
+    case ENCTYPE_DES3_CBC_SHA1:
+	for (i = 0; i < 3; i++) {
+	    mit_des_fixup_key_parity(encrypting_key->contents + i * 8);
+	    if (mit_des_is_weak_key(encrypting_key->contents + i * 8))
+		((krb5_octet *) encrypting_key->contents)[7 + i * 8] ^= 0xf0;
+	}
+	break;
+
+    default:
+	com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
+		"Unimplemented keytype for SAM key mixing");
+	goto cleanup;
+    }
+
+    /* XXX Attach a useful pa_data */
+cleanup:
+    if (sr)
+	krb5_free_sam_response(context, sr);
+    if (psr)
+	krb5_free_predicted_sam_response(context, psr);
+
+    return retval;
+}
+    
+static struct {
+  char* name;
+  int   sam_type;
+} *sam_ptr, sam_inst_map[] = {
+  { "SNK4", PA_SAM_TYPE_DIGI_PATH, },
+  { "SECURID", PA_SAM_TYPE_SECURID, },
+  { "GRAIL", PA_SAM_TYPE_GRAIL, },
+  { 0, 0 },
+};
+
+static krb5_error_code
+get_sam_edata(krb5_context context, krb5_kdc_req *request,
+	      krb5_db_entry *client, krb5_db_entry *server,
+	      krb5_pa_data *pa_data)
+{
+    krb5_error_code		retval;
+    krb5_sam_challenge		sc;
+    krb5_predicted_sam_response	psr;
+    krb5_data *			scratch;
+    krb5_keyblock encrypting_key;
+    char response[9];
+    char inputblock[8];
+    krb5_data predict_response;
+
+    memset(&sc, 0, sizeof(sc));
+    memset(&psr, 0, sizeof(psr));
+
+    /* Given the client name we can figure out what type of preauth
+       they need. The spec is currently for querying the database for
+       names that match the types of preauth used. Later we should
+       make this mapping show up in kdc.conf. In the meantime, we
+       hardcode the following:
+		/SNK4 -- Digital Pathways SNK/4 preauth.
+		/GRAIL -- experimental preauth
+       The first one found is used. See sam_inst_map above.
+
+       For SNK4 in particular, the key in the database is the key for
+       the device; kadmin needs a special interface for it.
+     */
+
+    {
+      int npr = 1;
+      krb5_boolean more;
+      krb5_db_entry assoc;
+      krb5_key_data  *assoc_key;
+      krb5_principal newp;
+      int probeslot;
+
+      sc.sam_type = 0;
+
+      retval = krb5_copy_principal(kdc_context, request->client, &newp);
+      if (retval) {
+	com_err("krb5kdc", retval, "copying client name for preauth probe");
+	return retval;
+      }
+
+      probeslot = krb5_princ_size(context, newp)++;
+      krb5_princ_name(kdc_context, newp) = 
+	realloc(krb5_princ_name(kdc_context, newp),
+		krb5_princ_size(context, newp) * sizeof(krb5_data));
+
+      for(sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++) {
+	krb5_princ_component(kdc_context,newp,probeslot)->data = sam_ptr->name;
+	krb5_princ_component(kdc_context,newp,probeslot)->length = 
+	  strlen(sam_ptr->name);
+	npr = 1;
+	retval = krb5_db_get_principal(kdc_context, newp, &assoc, &npr, &more);
+	if(!retval && npr) {
+	  sc.sam_type = sam_ptr->sam_type;
+	  break;
+	}
+      }
+
+      krb5_princ_component(kdc_context,newp,probeslot)->data = 0;
+      krb5_princ_component(kdc_context,newp,probeslot)->length = 0;
+      krb5_princ_size(context, newp)--;
+
+      krb5_free_principal(kdc_context, newp);
+
+      /* if sc.sam_type is set, it worked */
+      if (sc.sam_type) {
+	/* so use assoc to get the key out! */
+	{
+	  /* here's what do_tgs_req does */
+	  retval = krb5_dbe_find_enctype(kdc_context, &assoc,
+					 ENCTYPE_DES_CBC_RAW,
+					 KRB5_KDB_SALTTYPE_NORMAL,
+					 0,		/* Get highest kvno */
+					 &assoc_key);
+	  if (retval) {
+	    char *sname;
+	    krb5_unparse_name(kdc_context, request->client, &sname);
+	    com_err("krb5kdc", retval, 
+		    "snk4 finding the enctype and key <%s>", sname);
+	    free(sname);
+	    return retval;
+	  }
+	  /* convert server.key into a real key */
+	  retval = krb5_dbekd_decrypt_key_data(kdc_context,
+					       &master_keyblock, 
+					       assoc_key, &encrypting_key,
+					       NULL);
+	  if (retval) {
+	    com_err("krb5kdc", retval, 
+		    "snk4 pulling out key entry");
+	    return retval;
+	  }
+	  /* now we can use encrypting_key... */
+	}
+      } else {
+	/* SAM is not an option - so don't return as hint */
+	return KRB5_PREAUTH_BAD_TYPE;
+      }
+    }
+    sc.magic = KV5M_SAM_CHALLENGE;
+    psr.sam_flags = sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY;
+
+    /* Replay prevention */
+    if ((retval = krb5_copy_principal(context, request->client, &psr.client)))
+	return retval;
+#ifdef USE_RCACHE
+    if ((retval = krb5_us_timeofday(context, &psr.stime, &psr.susec)))
+	return retval;
+#endif /* USE_RCACHE */
+
+    switch (sc.sam_type) {
+    case PA_SAM_TYPE_GRAIL:
+      sc.sam_type_name.data = "Experimental System";
+      sc.sam_type_name.length = strlen(sc.sam_type_name.data);
+      sc.sam_challenge_label.data = "experimental challenge label";
+      sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
+      sc.sam_challenge.data = "12345";
+      sc.sam_challenge.length = strlen(sc.sam_challenge.data);
+
+#if 0 /* Enable this to test "normal" (no flags set) mode.  */
+      psr.sam_flags = sc.sam_flags = 0;
+#endif
+
+      psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
+      /* string2key on sc.sam_challenge goes in here */
+      /* eblock is just to set the enctype */
+      {
+	const krb5_enctype type = ENCTYPE_DES_CBC_MD5;
+
+	if ((retval = krb5_c_string_to_key(context, type, &sc.sam_challenge,
+					   0 /* salt */, &psr.sam_key)))
+	    goto cleanup;
+
+	if ((retval = encode_krb5_predicted_sam_response(&psr, &scratch)))
+	    goto cleanup;
+	
+	{
+	    size_t enclen;
+	    krb5_enc_data tmpdata;
+
+	    if ((retval = krb5_c_encrypt_length(context,
+						psr_key.enctype,
+						scratch->length, &enclen)))
+		goto cleanup;
+
+	    if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
+		retval = ENOMEM;
+		goto cleanup;
+	    }
+	    tmpdata.ciphertext.length = enclen;
+
+	    if ((retval = krb5_c_encrypt(context, &psr_key,
+					 /* XXX */ 0, 0, scratch, &tmpdata)))
+		goto cleanup;
+
+	    sc.sam_track_id = tmpdata.ciphertext;
+	}
+      }
+
+      sc.sam_response_prompt.data = "response prompt";
+      sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
+      sc.sam_pk_for_sad.length = 0;
+      sc.sam_nonce = 0;
+      /* Generate checksum */
+      /*krb5_checksum_size(context, ctype)*/
+      /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
+	seed_length,outcksum) */
+      /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
+	seed_length) */
+#if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
+      sc.sam_cksum.contents = (krb5_octet *)
+	malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
+      if (sc.sam_cksum.contents == NULL) return(ENOMEM);
+
+      retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
+				       sc.sam_challenge.data,
+				       sc.sam_challenge.length,
+				       psr.sam_key.contents, /* key */
+				       psr.sam_key.length, /* key length */
+				       &sc.sam_cksum);
+      if (retval) { free(sc.sam_cksum.contents); return(retval); }
+#endif /* 0 */
+      
+      retval = encode_krb5_sam_challenge(&sc, &scratch);
+      if (retval) goto cleanup;
+      pa_data->magic = KV5M_PA_DATA;
+      pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
+      pa_data->contents = scratch->data;
+      pa_data->length = scratch->length;
+      
+      retval = 0;
+      break;
+    case PA_SAM_TYPE_DIGI_PATH:
+      sc.sam_type_name.data = "Digital Pathways";
+      sc.sam_type_name.length = strlen(sc.sam_type_name.data);
+#if 1
+      sc.sam_challenge_label.data = "Enter the following on your keypad";
+      sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
+#endif
+      /* generate digit string, take it mod 1000000 (six digits.) */
+      {
+	int j;
+	krb5_keyblock session_key;
+	char outputblock[8];
+	int i;
+
+	session_key.contents = 0;
+
+	memset(inputblock, 0, 8);
+
+	retval = krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_CRC,
+					&session_key);
+
+	if (retval) {
+	  /* random key failed */
+	  com_err("krb5kdc", retval,"generating random challenge for preauth");
+	  return retval;
+	}
+	/* now session_key has a key which we can pick bits out of */
+	/* we need six decimal digits. Grab 6 bytes, div 2, mod 10 each. */
+	if (session_key.length != 8) {
+	  com_err("krb5kdc", retval = KRB5KDC_ERR_ETYPE_NOSUPP,
+		  "keytype didn't match code expectations");
+	  return retval;
+	}
+	for(i = 0; i<6; i++) {
+	  inputblock[i] = '0' + ((session_key.contents[i]/2) % 10);
+	}
+	if (session_key.contents)
+	  krb5_free_keyblock_contents(kdc_context, &session_key);
+
+	/* retval = krb5_finish_key(kdc_context, &eblock); */
+	/* now we have inputblock containing the 8 byte input to DES... */
+	sc.sam_challenge.data = inputblock;
+	sc.sam_challenge.length = 6;
+
+	encrypting_key.enctype = ENCTYPE_DES_CBC_RAW;
+
+	if (retval) {
+	  com_err("krb5kdc", retval, "snk4 processing key");
+	}
+
+	{
+	    krb5_data plain;
+	    krb5_enc_data cipher;
+
+	    plain.length = 8;
+	    plain.data = inputblock;
+
+	    /* XXX I know this is enough because of the fixed raw enctype.
+	       if it's not, the underlying code will return a reasonable
+	       error, which should never happen */
+	    cipher.ciphertext.length = 8;
+	    cipher.ciphertext.data = outputblock;
+
+	    if ((retval = krb5_c_encrypt(kdc_context, &encrypting_key,
+					 /* XXX */ 0, 0, &plain, &cipher))) {
+		com_err("krb5kdc", retval, "snk4 response generation failed");
+		return retval;
+	    }
+	}
+
+	/* now output block is the raw bits of the response; convert it
+	   to display form */
+	for (j=0; j<4; j++) {
+	  char n[2];
+	  int k;
+	  n[0] = outputblock[j] & 0xf;
+	  n[1] = (outputblock[j]>>4) & 0xf;
+	  for (k=0; k<2; k++) {
+	    if(n[k] > 9) n[k] = ((n[k]-1)>>2);
+	    /* This is equivalent to:
+	       if(n[k]>=0xa && n[k]<=0xc) n[k] = 2;
+	       if(n[k]>=0xd && n[k]<=0xf) n[k] = 3;
+	       */
+	  }
+	  /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */
+	  /* for v5, we just generate a string */
+	  response[2*j+0] = '0' + n[1];
+	  response[2*j+1] = '0' + n[0];
+	  /* and now, response has what we work with. */
+	}
+	response[8] = 0;
+	predict_response.data = response;
+	predict_response.length = 8;
+#if 0				/* for debugging, hack the output too! */
+sc.sam_challenge_label.data = response;
+sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
+#endif
+      }
+
+      psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
+      /* string2key on sc.sam_challenge goes in here */
+      /* eblock is just to set the enctype */
+      {
+	retval = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
+				      &predict_response, 0 /* salt */,
+				      &psr.sam_key);
+	if (retval) goto cleanup;
+
+	retval = encode_krb5_predicted_sam_response(&psr, &scratch);
+	if (retval) goto cleanup;
+	
+	{
+	    size_t enclen;
+	    krb5_enc_data tmpdata;
+
+	    if ((retval = krb5_c_encrypt_length(context,
+						psr_key.enctype,
+						scratch->length, &enclen)))
+		goto cleanup;
+
+	    if ((tmpdata.ciphertext.data = (char *) malloc(enclen)) == NULL) {
+		retval = ENOMEM;
+		goto cleanup;
+	    }
+	    tmpdata.ciphertext.length = enclen;
+
+	    if ((retval = krb5_c_encrypt(context, &psr_key,
+					 /* XXX */ 0, 0, scratch, &tmpdata)))
+		goto cleanup;
+
+	    sc.sam_track_id = tmpdata.ciphertext;
+	}
+	if (retval) goto cleanup;
+      }
+
+      sc.sam_response_prompt.data = "Enter the displayed response";
+      sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
+      sc.sam_pk_for_sad.length = 0;
+      sc.sam_nonce = 0;
+      /* Generate checksum */
+      /*krb5_checksum_size(context, ctype)*/
+      /*krb5_calculate_checksum(context,ctype,in,in_length,seed,
+	seed_length,outcksum) */
+      /*krb5_verify_checksum(context,ctype,cksum,in,in_length,seed,
+	seed_length) */
+#if 0 /* XXX a) glue appears broken; b) this gives up the SAD */
+      sc.sam_cksum.contents = (krb5_octet *)
+	malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
+      if (sc.sam_cksum.contents == NULL) return(ENOMEM);
+
+      retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
+				       sc.sam_challenge.data,
+				       sc.sam_challenge.length,
+				       psr.sam_key.contents, /* key */
+				       psr.sam_key.length, /* key length */
+				       &sc.sam_cksum);
+      if (retval) { free(sc.sam_cksum.contents); return(retval); }
+#endif /* 0 */
+      
+      retval = encode_krb5_sam_challenge(&sc, &scratch);
+      if (retval) goto cleanup;
+      pa_data->magic = KV5M_PA_DATA;
+      pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
+      pa_data->contents = scratch->data;
+      pa_data->length = scratch->length;
+      
+      retval = 0;
+      break;
+    }
+
+cleanup:
+    krb5_free_keyblock_contents(context, &encrypting_key);
+    return retval;
+}
+
+static krb5_error_code
+verify_sam_response(krb5_context context, krb5_db_entry *client,
+		    krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply,
+		    krb5_pa_data *pa)
+{
+    krb5_error_code		retval;
+    krb5_data			scratch;
+    krb5_sam_response		*sr = 0;
+    krb5_predicted_sam_response	*psr = 0;
+    krb5_enc_sam_response_enc	*esre = 0;
+    krb5_timestamp		timenow;
+    char			*princ_req = 0, *princ_psr = 0;
+
+    scratch.data = pa->contents;
+    scratch.length = pa->length;
+    
+    if ((retval = decode_krb5_sam_response(&scratch, &sr))) {
+	scratch.data = 0;
+	com_err("krb5kdc", retval, "decode_krb5_sam_response failed");
+	goto cleanup;
+    }
+
+    /* XXX We can only handle the challenge/response model of SAM.
+	   See passwords-04, par 4.1, 4.2 */
+    {
+      krb5_enc_data tmpdata;
+
+      tmpdata.enctype = ENCTYPE_UNKNOWN;
+      tmpdata.ciphertext = sr->sam_track_id;
+
+      scratch.length = tmpdata.ciphertext.length;
+      if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
+	  retval = ENOMEM;
+	  goto cleanup;
+      }
+
+      if ((retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
+				   &tmpdata, &scratch))) {
+	  com_err("krb5kdc", retval, "decrypt track_id failed");
+	  goto cleanup;
+      }
+    }
+
+    if ((retval = decode_krb5_predicted_sam_response(&scratch, &psr))) {
+	com_err("krb5kdc", retval,
+		"decode_krb5_predicted_sam_response failed -- replay attack?");
+	goto cleanup;
+    }
+
+    /* Replay detection */
+    if ((retval = krb5_unparse_name(context, request->client, &princ_req)))
+	goto cleanup;
+    if ((retval = krb5_unparse_name(context, psr->client, &princ_psr)))
+	goto cleanup;
+    if (strcmp(princ_req, princ_psr) != 0) {
+	com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
+		"Principal mismatch in SAM psr! -- replay attack?");
+	goto cleanup;
+    }
+
+    if ((retval = krb5_timeofday(context, &timenow)))
+	goto cleanup;
+
+#ifdef USE_RCACHE
+    {
+	krb5_donot_replay rep;
+	extern krb5_deltat rc_lifetime;
+	/*
+	 * Verify this response came back in a timely manner.
+	 * We do this b/c otherwise very old (expunged from the rcache)
+	 * psr's would be able to be replayed.
+	 */
+	if (timenow - psr->stime > rc_lifetime) {
+	    com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
+	    "SAM psr came back too late! -- replay attack?");
+	    goto cleanup;
+	}
+
+	/* Now check the replay cache. */
+	rep.client = princ_psr;
+	rep.server = "SAM/rc";  /* Should not match any principal name. */
+	rep.ctime = psr->stime;
+	rep.cusec = psr->susec;
+	retval = krb5_rc_store(kdc_context, kdc_rcache, &rep);
+	if (retval) {
+	    com_err("krb5kdc", retval, "SAM psr replay attack!");
+	    goto cleanup;
+	}
+    }
+#endif /* USE_RCACHE */
+
+
+    {
+	free(scratch.data);
+	scratch.length = sr->sam_enc_nonce_or_ts.ciphertext.length;
+	if ((scratch.data = (char *) malloc(scratch.length)) == NULL) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+
+	if ((retval = krb5_c_decrypt(context, &psr->sam_key, /* XXX */ 0,
+				     0, &sr->sam_enc_nonce_or_ts, &scratch))) {
+	    com_err("krb5kdc", retval, "decrypt nonce_or_ts failed");
+	    goto cleanup;
+	}
+    }
+
+    if ((retval = decode_krb5_enc_sam_response_enc(&scratch, &esre))) {
+	com_err("krb5kdc", retval, "decode_krb5_enc_sam_response_enc failed");
+	goto cleanup;
+    }
+
+    if (esre->sam_timestamp != sr->sam_patimestamp) {
+      retval = KRB5KDC_ERR_PREAUTH_FAILED;
+      goto cleanup;
+    }
+    
+    if (labs(timenow - sr->sam_patimestamp) > context->clockskew) {
+	retval = KRB5KRB_AP_ERR_SKEW;
+	goto cleanup;
+    }
+
+    setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
+
+  cleanup:
+    if (retval)
+	com_err("krb5kdc", retval, "sam verify failure");
+    if (scratch.data) free(scratch.data);
+    if (sr) free(sr);
+    if (psr) free(psr);
+    if (esre) free(esre);
+    if (princ_psr) free(princ_psr);
+    if (princ_req) free(princ_req);
+
+    return retval;
+}
diff --git a/mechglue/src/kdc/kdc_util.c b/mechglue/src/kdc/kdc_util.c
new file mode 100644
index 000000000..071555bd9
--- /dev/null
+++ b/mechglue/src/kdc/kdc_util.c
@@ -0,0 +1,1578 @@
+/*
+ * kdc/kdc_util.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Utility functions for the KDC implementation.
+ */
+
+#include "k5-int.h"
+#include "kdc_util.h"
+#include "extern.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <syslog.h>
+#include "adm.h"
+#include "adm_proto.h"
+#include <limits.h>
+
+#ifdef USE_RCACHE
+static char *kdc_current_rcname = (char *) NULL;
+krb5_deltat rc_lifetime; /* See kdc_initialize_rcache() */
+#endif
+
+#ifdef USE_RCACHE
+/*
+ * initialize the replay cache.
+ */
+krb5_error_code
+kdc_initialize_rcache(krb5_context kcontext, char *rcache_name)
+{
+    krb5_error_code	retval;
+    char		*rcname;
+    char		*sname;
+
+    rcname = (rcache_name) ? rcache_name : kdc_current_rcname;
+
+    /* rc_lifetime used elsewhere to verify we're not */
+    /*  replaying really old data                     */
+    rc_lifetime = kcontext->clockskew;
+
+    if (!rcname)
+	rcname = KDCRCACHE;
+    if (!(retval = krb5_rc_resolve_full(kcontext, &kdc_rcache, rcname))) {
+	/* Recover or initialize the replay cache */
+	if (!(retval = krb5_rc_recover(kcontext, kdc_rcache)) ||
+	    !(retval = krb5_rc_initialize(kcontext,
+					  kdc_rcache,
+					  kcontext->clockskew))
+	    ) {
+	    /* Expunge the replay cache */
+	    if (!(retval = krb5_rc_expunge(kcontext, kdc_rcache))) {
+		sname = kdc_current_rcname;
+		kdc_current_rcname = strdup(rcname);
+		if (sname)
+		    free(sname);
+	    }
+	}
+	if (retval)
+	    krb5_rc_close(kcontext, kdc_rcache);
+    }
+    return(retval);
+}
+#endif
+
+/*
+ * concatenate first two authdata arrays, returning an allocated replacement.
+ * The replacement should be freed with krb5_free_authdata().
+ */
+krb5_error_code
+concat_authorization_data(krb5_authdata **first, krb5_authdata **second,
+			  krb5_authdata ***output)
+{
+    register int i, j;
+    register krb5_authdata **ptr, **retdata;
+
+    /* count up the entries */
+    i = 0;
+    if (first)
+	for (ptr = first; *ptr; ptr++)
+	    i++;
+    if (second)
+	for (ptr = second; *ptr; ptr++)
+	    i++;
+    
+    retdata = (krb5_authdata **)malloc((i+1)*sizeof(*retdata));
+    if (!retdata)
+	return ENOMEM;
+    retdata[i] = 0;			/* null-terminated array */
+    for (i = 0, j = 0, ptr = first; j < 2 ; ptr = second, j++)
+	while (ptr && *ptr) {
+	    /* now walk & copy */
+	    retdata[i] = (krb5_authdata *)malloc(sizeof(*retdata[i]));
+	    if (!retdata[i]) {
+		krb5_free_authdata(kdc_context, retdata);
+		return ENOMEM;
+	    }
+	    *retdata[i] = **ptr;
+	    if (!(retdata[i]->contents =
+		  (krb5_octet *)malloc(retdata[i]->length))) {
+		free((char *)retdata[i]);
+		retdata[i] = 0;
+		krb5_free_authdata(kdc_context, retdata);
+		return ENOMEM;
+	    }
+	    memcpy((char *) retdata[i]->contents,
+		   (char *)(*ptr)->contents,
+		   retdata[i]->length);
+
+	    ptr++;
+	    i++;
+	}
+    *output = retdata;
+    return 0;
+}
+
+krb5_boolean
+realm_compare(krb5_principal princ1, krb5_principal princ2)
+{
+  krb5_data *realm1 = krb5_princ_realm(kdc_context, princ1);
+  krb5_data *realm2 = krb5_princ_realm(kdc_context, princ2);
+
+  return((realm1->length == realm2->length) &&
+         !memcmp(realm1->data, realm2->data, realm1->length));
+}
+
+/*
+ * Returns TRUE if the kerberos principal is the name of a Kerberos ticket
+ * service.
+ */
+krb5_boolean krb5_is_tgs_principal(krb5_principal principal)
+{
+	if ((krb5_princ_size(kdc_context, principal) > 0) &&
+	    (krb5_princ_component(kdc_context, principal, 0)->length ==
+	     KRB5_TGS_NAME_SIZE) &&
+	    (!memcmp(krb5_princ_component(kdc_context, principal, 0)->data,
+		     KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE)))
+		return TRUE;
+	return FALSE;
+}
+
+/*
+ * given authentication data (provides seed for checksum), verify checksum
+ * for source data.
+ */
+static krb5_error_code
+comp_cksum(krb5_context kcontext, krb5_data *source, krb5_ticket *ticket,
+	   krb5_checksum *his_cksum)
+{
+    krb5_error_code 	  retval;
+    krb5_boolean	  valid;
+
+    if (!krb5_c_valid_cksumtype(his_cksum->checksum_type)) 
+	return KRB5KDC_ERR_SUMTYPE_NOSUPP;
+
+    /* must be collision proof */
+    if (!krb5_c_is_coll_proof_cksum(his_cksum->checksum_type))
+	return KRB5KRB_AP_ERR_INAPP_CKSUM;
+
+    /* verify checksum */
+    if ((retval = krb5_c_verify_checksum(kcontext, ticket->enc_part2->session,
+					 KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
+					 source, his_cksum, &valid)))
+	return(retval);
+
+    if (!valid)
+	return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
+
+    return(0);
+}
+
+krb5_error_code 
+kdc_process_tgs_req(krb5_kdc_req *request, const krb5_fulladdr *from,
+		    krb5_data *pkt, krb5_ticket **ticket,
+		    krb5_keyblock **subkey)
+{
+    krb5_pa_data       ** tmppa;
+    krb5_ap_req 	* apreq;
+    krb5_error_code 	  retval;
+    krb5_data		  scratch1;
+    krb5_data 		* scratch = NULL;
+    krb5_boolean 	  foreign_server = FALSE;
+    krb5_auth_context 	  auth_context = NULL;
+    krb5_authenticator	* authenticator = NULL;
+    krb5_checksum 	* his_cksum = NULL;
+/*    krb5_keyblock 	* key = NULL;*/
+/*    krb5_kvno 		  kvno = 0;*/
+
+    if (!request->padata)
+	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+    for (tmppa = request->padata; *tmppa; tmppa++) {
+	if ((*tmppa)->pa_type == KRB5_PADATA_AP_REQ)
+	    break;
+    }
+    if (!*tmppa)			/* cannot find any AP_REQ */
+	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+
+    scratch1.length = (*tmppa)->length;
+    scratch1.data = (char *)(*tmppa)->contents;
+    if ((retval = decode_krb5_ap_req(&scratch1, &apreq)))
+	return retval;
+    
+    if (isflagset(apreq->ap_options, AP_OPTS_USE_SESSION_KEY) ||
+	isflagset(apreq->ap_options, AP_OPTS_MUTUAL_REQUIRED)) {
+	krb5_klog_syslog(LOG_INFO, "TGS_REQ: SESSION KEY or MUTUAL");
+	retval = KRB5KDC_ERR_POLICY;
+	goto cleanup;
+    }
+
+    /* If the "server" principal in the ticket is not something
+       in the local realm, then we must refuse to service the request
+       if the client claims to be from the local realm.
+       
+       If we don't do this, then some other realm's nasty KDC can
+       claim to be authenticating a client from our realm, and we'll
+       give out tickets concurring with it!
+       
+       we set a flag here for checking below.
+       */
+    if ((krb5_princ_realm(kdc_context, apreq->ticket->server)->length !=
+	 krb5_princ_realm(kdc_context, tgs_server)->length) ||
+	memcmp(krb5_princ_realm(kdc_context, apreq->ticket->server)->data,
+	       krb5_princ_realm(kdc_context, tgs_server)->data,
+	       krb5_princ_realm(kdc_context, tgs_server)->length))
+	foreign_server = TRUE;
+
+    if ((retval = krb5_auth_con_init(kdc_context, &auth_context)))
+	goto cleanup;
+
+    if ((retval = krb5_auth_con_setaddrs(kdc_context, auth_context, NULL,
+					 from->address)) )
+	goto cleanup_auth_context;
+#ifdef USE_RCACHE
+    if ((retval = krb5_auth_con_setrcache(kdc_context, auth_context,
+					  kdc_rcache)))
+	goto cleanup_auth_context;
+#endif
+
+/*
+    if ((retval = kdc_get_server_key(apreq->ticket, &key, &kvno)))
+	goto cleanup_auth_context;
+*/
+
+    /*
+     * XXX This is currently wrong but to fix it will require making a 
+     * new keytab for groveling over the kdb.
+     */
+/*
+    retval = krb5_auth_con_setuseruserkey(kdc_context, auth_context, key);
+    krb5_free_keyblock(kdc_context, key);
+    if (retval) 
+	goto cleanup_auth_context;
+*/
+
+    if ((retval = krb5_rd_req_decoded_anyflag(kdc_context, &auth_context, apreq, 
+				      apreq->ticket->server, 
+				      kdc_active_realm->realm_keytab,
+				      NULL, ticket))) {
+#ifdef USE_RCACHE
+	/*
+	 * I'm not so sure that this is right, but it's better than nothing
+	 * at all.
+	 *
+	 * If we choke in the rd_req because of the replay cache, then attempt
+	 * to reinitialize the replay cache because somebody could have deleted
+	 * it from underneath us (e.g. a cron job)
+	 */
+	if ((retval == KRB5_RC_IO_IO) ||
+	    (retval == KRB5_RC_IO_UNKNOWN)) {
+	    (void) krb5_rc_close(kdc_context, kdc_rcache);
+	    kdc_rcache = (krb5_rcache) NULL;
+	    if (!(retval = kdc_initialize_rcache(kdc_context, (char *) NULL))) {
+		if ((retval = krb5_auth_con_setrcache(kdc_context, auth_context,
+						      kdc_rcache)) ||
+		    (retval = krb5_rd_req_decoded_anyflag(kdc_context, &auth_context,
+						  apreq, apreq->ticket->server,
+				      		 kdc_active_realm->realm_keytab,
+						  NULL, ticket))
+		    )
+		    goto cleanup_auth_context;
+	    }
+	} else
+	    goto cleanup_auth_context; 
+#else
+	goto cleanup_auth_context; 
+#endif
+    }
+
+    /* "invalid flag" tickets can must be used to validate */
+    if (isflagset((*ticket)->enc_part2->flags, TKT_FLG_INVALID)
+	&& !isflagset(request->kdc_options, KDC_OPT_VALIDATE)) {
+        retval = KRB5KRB_AP_ERR_TKT_INVALID;
+	goto cleanup_auth_context;
+    }
+
+    if ((retval = krb5_auth_con_getrecvsubkey(kdc_context,
+					      auth_context, subkey)))
+	goto cleanup_auth_context;
+
+    if ((retval = krb5_auth_con_getauthenticator(kdc_context, auth_context,
+						 &authenticator)))
+	goto cleanup_auth_context;
+
+    /* Check for a checksum */
+    if (!(his_cksum = authenticator->checksum)) {
+	retval = KRB5KRB_AP_ERR_INAPP_CKSUM; 
+	goto cleanup_authenticator;
+    }
+
+    /* make sure the client is of proper lineage (see above) */
+    if (foreign_server) {
+	krb5_data *tkt_realm = krb5_princ_realm(kdc_context, 
+						(*ticket)->enc_part2->client);
+	krb5_data *tgs_realm = krb5_princ_realm(kdc_context, tgs_server);
+	if (tkt_realm->length == tgs_realm->length &&
+	    !memcmp(tkt_realm->data, tgs_realm->data, tgs_realm->length)) {
+	    /* someone in a foreign realm claiming to be local */
+	    krb5_klog_syslog(LOG_INFO, "PROCESS_TGS: failed lineage check");
+	    retval = KRB5KDC_ERR_POLICY;
+	    goto cleanup_authenticator;
+	}
+    }
+
+    /*
+     * Check application checksum vs. tgs request
+     * 	 
+     * We try checksumming the req-body two different ways: first we
+     * try reaching into the raw asn.1 stream (if available), and
+     * checksum that directly; if that fails, then we try encoding
+     * using our local asn.1 library.
+     */
+    if (pkt && (fetch_asn1_field((unsigned char *) pkt->data,
+				 1, 4, &scratch1) >= 0)) {
+	if (comp_cksum(kdc_context, &scratch1, *ticket, his_cksum)) {
+	    if (!(retval = encode_krb5_kdc_req_body(request, &scratch))) 
+	        retval = comp_cksum(kdc_context, scratch, *ticket, his_cksum);
+	    krb5_free_data(kdc_context, scratch);
+	}
+    }
+
+cleanup_authenticator:
+    krb5_free_authenticator(kdc_context, authenticator);
+
+cleanup_auth_context:
+    /* We do not want the free of the auth_context to close the rcache */
+#ifdef USE_RCACHE
+    (void)  krb5_auth_con_setrcache(kdc_context, auth_context, 0);
+#endif
+    krb5_auth_con_free(kdc_context, auth_context);
+
+cleanup:
+    krb5_free_ap_req(kdc_context, apreq);
+    return retval;
+}
+
+/* XXX This function should no longer be necessary. 
+ * The KDC should take the keytab associated with the realm and pass that to 
+ * the krb5_rd_req_decode(). --proven
+ *
+ * It's actually still used by do_tgs_req() for u2u auth, and not too
+ * much else. -- tlyu
+ */
+krb5_error_code
+kdc_get_server_key(krb5_ticket *ticket, krb5_keyblock **key, krb5_kvno *kvno)
+{
+    krb5_error_code 	  retval;
+    krb5_db_entry 	  server;
+    krb5_boolean 	  more;
+    int	nprincs;
+    krb5_key_data	* server_key;
+
+    nprincs = 1;
+
+    if ((retval = krb5_db_get_principal(kdc_context, ticket->server,
+					&server, &nprincs,
+					&more))) {
+	return(retval);
+    }
+    if (more) {
+	krb5_db_free_principal(kdc_context, &server, nprincs);
+	return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
+    } else if (nprincs != 1) {
+	char *sname;
+
+	krb5_db_free_principal(kdc_context, &server, nprincs);
+	if (!krb5_unparse_name(kdc_context, ticket->server, &sname)) {
+	    krb5_klog_syslog(LOG_ERR,"TGS_REQ: UNKNOWN SERVER: server='%s'",
+			     sname);
+	    free(sname);
+	}
+	return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
+    }
+    retval = krb5_dbe_find_enctype(kdc_context, &server,
+				   ticket->enc_part.enctype, -1,
+				   ticket->enc_part.kvno, &server_key);
+    if (retval)
+	goto errout;
+    if (!server_key) {
+	retval = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+	goto errout;
+    }
+    *kvno = server_key->key_data_kvno;
+    if ((*key = (krb5_keyblock *)malloc(sizeof **key))) {
+	retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock,
+					     server_key,
+					     *key, NULL);
+    } else
+	retval = ENOMEM;
+errout:
+    krb5_db_free_principal(kdc_context, &server, nprincs);
+    return retval;
+}
+
+/* This probably wants to be updated if you support last_req stuff */
+
+static krb5_last_req_entry nolrentry = { KV5M_LAST_REQ_ENTRY, KRB5_LRQ_NONE, 0 };
+static krb5_last_req_entry *nolrarray[] = { &nolrentry, 0 };
+
+krb5_error_code
+fetch_last_req_info(krb5_db_entry *dbentry, krb5_last_req_entry ***lrentry)
+{
+    *lrentry = nolrarray;
+    return 0;
+}
+
+
+/* XXX!  This is a temporary place-holder */
+
+krb5_error_code
+check_hot_list(krb5_ticket *ticket)
+{
+    return 0;
+}
+
+
+#define MAX_REALM_LN 500
+
+
+/* 
+ * subrealm - determine if r2 is a subrealm of r1
+ *
+ *            SUBREALM takes two realms, r1 and r2, and 
+ *            determines if r2 is a subrealm of r1.   
+ *            r2 is a subrealm of r1 if (r1 is a prefix
+ *            of r2 AND r1 and r2 begin with a /) or if 
+ *            (r1 is a suffix of r2 and neither r1 nor r2
+ *            begin with a /).
+ *
+ * RETURNS:   If r2 is a subrealm, and r1 is a prefix, the number
+ *            of characters in the suffix of r2 is returned as a
+ *            negative number.
+ *
+ *            If r2 is a subrealm, and r1 is a suffix, the number
+ *            of characters in the prefix of r2 is returned as a
+ *            positive number.
+ *
+ *            If r2 is not a subrealm, SUBREALM returns 0.
+ */
+static  int
+subrealm(char *r1, char *r2)
+{
+    size_t l1,l2;
+    l1 = strlen(r1);
+    l2 = strlen(r2);
+    if(l2 <= l1) return(0);
+    if((*r1 == '/') && (*r2 == '/') && (strncmp(r1,r2,l1) == 0)) return(l1-l2);
+    if((*r1 != '/') && (*r2 != '/') && (strncmp(r1,r2+l2-l1,l1) == 0))
+	return(l2-l1);
+    return(0);
+}
+
+/*
+ * add_to_transited  Adds the name of the realm which issued the
+ *                   ticket granting ticket on which the new ticket to
+ *                   be issued is based (note that this is the same as
+ *                   the realm of the server listed in the ticket
+ *                   granting ticket. 
+ *
+ * ASSUMPTIONS:  This procedure assumes that the transited field from
+ *               the existing ticket granting ticket already appears
+ *               in compressed form.  It will add the new realm while
+ *               maintaining that form.   As long as each successive
+ *               realm is added using this (or a similar) routine, the
+ *               transited field will be in compressed form.  The
+ *               basis step is an empty transited field which is, by
+ *               its nature, in its most compressed form.
+ *
+ * ARGUMENTS: krb5_data *tgt_trans  Transited field from TGT
+ *            krb5_data *new_trans  The transited field for the new ticket
+ *            krb5_principal tgs    Name of ticket granting server
+ *                                  This includes the realm of the KDC
+ *                                  that issued the ticket granting
+ *                                  ticket.  This is the realm that is
+ *                                  to be added to the transited field.
+ *            krb5_principal client Name of the client
+ *            krb5_principal server The name of the requested server.
+ *                                  This may be the an intermediate
+ *                                  ticket granting server.
+ *
+ *            The last two argument are needed since they are
+ *            implicitly part of the transited field of the new ticket
+ *            even though they are not explicitly listed.
+ *
+ * RETURNS:   krb5_error_code - Success, or out of memory
+ *
+ * MODIFIES:  new_trans:  ->length will contain the length of the new
+ *                        transited field.
+ * 
+ *                        If ->data was not null when this procedure
+ *                        is called, the memory referenced by ->data
+ *                        will be deallocated. 
+ *
+ *                        Memory will be allocated for the new transited field
+ *                        ->data will be updated to point to the newly
+ *                        allocated memory.  
+ *
+ * BUGS:  The space allocated for the new transited field is the
+ *        maximum that might be needed given the old transited field,
+ *        and the realm to be added.  This length is calculated
+ *        assuming that no compression of the new realm is possible.
+ *        This has no adverse consequences other than the allocation
+ *        of more space than required.  
+ *
+ *        This procedure will not yet use the null subfield notation,
+ *        and it will get confused if it sees it.
+ *
+ *        This procedure does not check for quoted commas in realm
+ *        names.
+ */
+
+krb5_error_code 
+add_to_transited(krb5_data *tgt_trans, krb5_data *new_trans,
+		 krb5_principal tgs, krb5_principal client,
+		 krb5_principal server)
+{
+  krb5_error_code retval;
+  char        *realm;
+  char        *trans;
+  char        *otrans, *otrans_ptr;
+
+  /* The following are for stepping through the transited field     */
+
+  char        prev[MAX_REALM_LN];
+  char        next[MAX_REALM_LN];
+  char        current[MAX_REALM_LN];
+  char        exp[MAX_REALM_LN];      /* Expanded current realm name     */
+
+  int	      i;
+  int         clst, nlst;    /* count of last character in current and next */
+  int         pl, pl1;       /* prefix length                               */
+  int         added;         /* TRUE = new realm has been added             */
+
+  if (!(realm = (char *) malloc(krb5_princ_realm(kdc_context, tgs)->length+1))) {
+    return(ENOMEM);
+  }
+  memcpy(realm, krb5_princ_realm(kdc_context, tgs)->data, 
+	 krb5_princ_realm(kdc_context, tgs)->length);
+  realm[krb5_princ_realm(kdc_context, tgs)->length] = '\0';
+
+  if (!(otrans = (char *) malloc(tgt_trans->length+1))) {
+    free(realm);
+    return(ENOMEM);
+  }
+  memcpy(otrans, tgt_trans->data, tgt_trans->length);
+  otrans[tgt_trans->length] = '\0';
+  /* Keep track of start so we can free */
+  otrans_ptr = otrans;
+
+  /* +1 for null, 
+     +1 for extra comma which may be added between
+     +1 for potential space when leading slash in realm */
+  if (!(trans = (char *) malloc(strlen(realm) + strlen(otrans) + 3))) {
+    retval = ENOMEM;
+    goto fail;
+  }
+
+  if (new_trans->data)  free(new_trans->data);
+  new_trans->data = trans;
+  new_trans->length = 0;
+
+  trans[0] = '\0';
+
+  /* For the purpose of appending, the realm preceding the first */
+  /* realm in the transited field is considered the null realm   */
+
+  prev[0] = '\0';
+
+  /* read field into current */
+  for (i = 0; *otrans != '\0';) {
+      if (*otrans == '\\') {
+	  if (*(++otrans) == '\0')
+	      break;
+	  else
+	      continue;
+      }
+      if (*otrans == ',') {
+	  otrans++;
+	  break;
+      }
+      current[i++] = *otrans++;
+      if (i >= MAX_REALM_LN) {
+	  retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	  goto fail;
+      }
+  }
+  current[i] = '\0';
+
+  added = (krb5_princ_realm(kdc_context, client)->length == strlen(realm) &&
+           !strncmp(krb5_princ_realm(kdc_context, client)->data, realm, strlen(realm))) ||
+          (krb5_princ_realm(kdc_context, server)->length == strlen(realm) &&
+           !strncmp(krb5_princ_realm(kdc_context, server)->data, realm, strlen(realm)));
+
+  while (current[0]) {
+
+    /* figure out expanded form of current name */
+
+    clst = strlen(current) - 1;
+    if (current[0] == ' ') {
+      strncpy(exp, current+1, sizeof(exp) - 1);
+      exp[sizeof(exp) - 1] = '\0';
+    }
+    else if ((current[0] == '/') && (prev[0] == '/')) {
+      strncpy(exp, prev, sizeof(exp) - 1);
+      exp[sizeof(exp) - 1] = '\0';
+      if (strlen(exp) + strlen(current) + 1 >= MAX_REALM_LN) {
+	retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	goto fail;
+      }
+      strncat(exp, current, sizeof(exp) - 1 - strlen(exp));
+    }
+    else if (current[clst] == '.') {
+      strncpy(exp, current, sizeof(exp) - 1);
+      exp[sizeof(exp) - 1] = '\0';
+      if (strlen(exp) + strlen(prev) + 1 >= MAX_REALM_LN) {
+	retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	goto fail;
+      }
+      strncat(exp, prev, sizeof(exp) - 1 - strlen(exp));
+    }
+    else {
+      strncpy(exp, current, sizeof(exp) - 1);
+      exp[sizeof(exp) - 1] = '\0';
+    }
+
+    /* read field into next */
+    for (i = 0; *otrans != '\0';) {
+	if (*otrans == '\\') {
+	    if (*(++otrans) == '\0')
+		break;
+	    else
+		continue;
+	}
+	if (*otrans == ',') {
+	    otrans++;
+	    break;
+	}
+	next[i++] = *otrans++;
+	if (i >= MAX_REALM_LN) {
+	    retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	    goto fail;
+	}
+    }
+    next[i] = '\0';
+    nlst = i - 1;
+
+    if (!strcmp(exp, realm))  added = TRUE;
+
+    /* If we still have to insert the new realm */
+
+    if (!added) {
+
+      /* Is the next field compressed?  If not, and if the new */
+      /* realm is a subrealm of the current realm, compress    */
+      /* the new realm, and insert immediately following the   */
+      /* current one.  Note that we can not do this if the next*/
+      /* field is already compressed since it would mess up    */
+      /* what has already been done.  In most cases, this is   */
+      /* not a problem because the realm to be added will be a */
+      /* subrealm of the next field too, and we will catch     */
+      /* it in a future iteration.                             */
+
+      if ((next[nlst] != '.') && (next[0] != '/') &&
+          (pl = subrealm(exp, realm))) {
+        added = TRUE;
+	current[sizeof(current) - 1] = '\0';
+	if (strlen(current) + (pl>0?pl:-pl) + 2 >= MAX_REALM_LN) {
+	  retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	  goto fail;
+	}
+        strncat(current, ",", sizeof(current) - 1 - strlen(current));
+        if (pl > 0) {
+          strncat(current, realm, (unsigned) pl);
+        }
+        else {
+          strncat(current, realm+strlen(realm)+pl, (unsigned) (-pl));
+        }
+      }
+
+      /* Whether or not the next field is compressed, if the    */
+      /* realm to be added is a superrealm of the current realm,*/
+      /* then the current realm can be compressed.  First the   */
+      /* realm to be added must be compressed relative to the   */
+      /* previous realm (if possible), and then the current     */
+      /* realm compressed relative to the new realm.  Note that */
+      /* if the realm to be added is also a superrealm of the   */
+      /* previous realm, it would have been added earlier, and  */
+      /* we would not reach this step this time around.         */
+
+      else if ((pl = subrealm(realm, exp))) {
+        added      = TRUE;
+        current[0] = '\0';
+        if ((pl1 = subrealm(prev,realm))) {
+	  if (strlen(current) + (pl1>0?pl1:-pl1) + 1 >= MAX_REALM_LN) {
+	    retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	    goto fail;
+	  }
+          if (pl1 > 0) {
+            strncat(current, realm, (unsigned) pl1);
+          }
+          else {
+            strncat(current, realm+strlen(realm)+pl1, (unsigned) (-pl1));
+          }
+        }
+        else { /* If not a subrealm */
+          if ((realm[0] == '/') && prev[0]) {
+	    if (strlen(current) + 2 >= MAX_REALM_LN) {
+	      retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	      goto fail;
+	    }
+	    strncat(current, " ", sizeof(current) - 1 - strlen(current));
+	    current[sizeof(current) - 1] = '\0';
+          }
+	  if (strlen(current) + strlen(realm) + 1 >= MAX_REALM_LN) {
+	    retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	    goto fail;
+	  }
+          strncat(current, realm, sizeof(current) - 1 - strlen(current));
+	  current[sizeof(current) - 1] = '\0';
+        }
+	if (strlen(current) + (pl>0?pl:-pl) + 2 >= MAX_REALM_LN) {
+	  retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	  goto fail;
+	}
+        strncat(current,",", sizeof(current) - 1 - strlen(current));
+	current[sizeof(current) - 1] = '\0';
+        if (pl > 0) {
+          strncat(current, exp, (unsigned) pl);
+        }
+        else {
+          strncat(current, exp+strlen(exp)+pl, (unsigned)(-pl));
+        }
+      }
+    }
+
+    if (new_trans->length != 0) {
+      if (strlen(trans) + 2 >= MAX_REALM_LN) {
+	retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	goto fail;
+      }
+      strcat(trans, ",");
+    }
+    if (strlen(trans) + strlen(current) + 1 >= MAX_REALM_LN) {
+      retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+      goto fail;
+    }
+    strcat(trans, current);
+    new_trans->length = strlen(trans);
+
+    strncpy(prev, exp, sizeof(prev) - 1);
+    prev[sizeof(prev) - 1] = '\0';
+    strncpy(current, next, sizeof(current) - 1);
+    current[sizeof(current) - 1] = '\0';
+  }
+
+  if (!added) {
+    if (new_trans->length != 0) {
+      if (strlen(trans) + 2 >= MAX_REALM_LN) {
+	retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	goto fail;
+      }
+      strcat(trans, ",");
+    }
+    if((realm[0] == '/') && trans[0]) {
+      if (strlen(trans) + 2 >= MAX_REALM_LN) {
+	retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+	goto fail;
+      }
+      strcat(trans, " ");
+    }
+    if (strlen(trans) + strlen(realm) + 1 >= MAX_REALM_LN) {
+      retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+      goto fail;
+    }
+    strcat(trans, realm);
+    new_trans->length = strlen(trans);
+  }
+
+  retval = 0;
+fail:
+  free(realm);
+  free(otrans_ptr);
+  return (retval);
+}
+
+/*
+ * Routines that validate a AS request; checks a lot of things.  :-)
+ *
+ * Returns a Kerberos protocol error number, which is _not_ the same
+ * as a com_err error number!
+ */
+#define AS_INVALID_OPTIONS (KDC_OPT_FORWARDED | KDC_OPT_PROXY |\
+KDC_OPT_VALIDATE | KDC_OPT_RENEW | KDC_OPT_ENC_TKT_IN_SKEY)
+int
+validate_as_request(register krb5_kdc_req *request, krb5_db_entry client,
+		    krb5_db_entry server, krb5_timestamp kdc_time,
+		    const char **status)
+{
+    int		errcode;
+    
+    /*
+     * If an option is set that is only allowed in TGS requests, complain.
+     */
+    if (request->kdc_options & AS_INVALID_OPTIONS) {
+	*status = "INVALID AS OPTIONS";
+	return KDC_ERR_BADOPTION;
+    }
+
+    /* The client's password must not be expired, unless the server is
+      a KRB5_KDC_PWCHANGE_SERVICE. */
+    if (client.pw_expiration && client.pw_expiration < kdc_time &&
+	!isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
+	*status = "CLIENT KEY EXPIRED";
+#ifdef KRBCONF_VAGUE_ERRORS
+	return(KRB_ERR_GENERIC);
+#else
+	return(KDC_ERR_KEY_EXP);
+#endif
+    }
+
+    /* The client must not be expired */
+    if (client.expiration && client.expiration < kdc_time) {
+	*status = "CLIENT EXPIRED";
+#ifdef KRBCONF_VAGUE_ERRORS
+	return(KRB_ERR_GENERIC);
+#else
+	return(KDC_ERR_NAME_EXP);
+#endif
+    }
+
+    /* The server must not be expired */
+    if (server.expiration && server.expiration < kdc_time) {
+	*status = "SERVICE EXPIRED";
+	    return(KDC_ERR_SERVICE_EXP);
+    }
+
+    /*
+     * If the client requires password changing, then only allow the 
+     * pwchange service.
+     */
+    if (isflagset(client.attributes, KRB5_KDB_REQUIRES_PWCHANGE) &&
+	!isflagset(server.attributes, KRB5_KDB_PWCHANGE_SERVICE)) {
+	*status = "REQUIRED PWCHANGE";
+	return(KDC_ERR_KEY_EXP);
+    }
+
+    /* Client and server must allow postdating tickets */
+    if ((isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) ||
+	 isflagset(request->kdc_options, KDC_OPT_POSTDATED)) && 
+	(isflagset(client.attributes, KRB5_KDB_DISALLOW_POSTDATED) ||
+	 isflagset(server.attributes, KRB5_KDB_DISALLOW_POSTDATED))) {
+	*status = "POSTDATE NOT ALLOWED";
+	return(KDC_ERR_CANNOT_POSTDATE);
+    }
+    
+    /* Client and server must allow forwardable tickets */
+    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE) &&
+	(isflagset(client.attributes, KRB5_KDB_DISALLOW_FORWARDABLE) ||
+	 isflagset(server.attributes, KRB5_KDB_DISALLOW_FORWARDABLE))) {
+	*status = "FORWARDABLE NOT ALLOWED";
+	return(KDC_ERR_POLICY);
+    }
+    
+    /* Client and server must allow renewable tickets */
+    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE) &&
+	(isflagset(client.attributes, KRB5_KDB_DISALLOW_RENEWABLE) ||
+	 isflagset(server.attributes, KRB5_KDB_DISALLOW_RENEWABLE))) {
+	*status = "RENEWABLE NOT ALLOWED";
+	return(KDC_ERR_POLICY);
+    }
+    
+    /* Client and server must allow proxiable tickets */
+    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE) &&
+	(isflagset(client.attributes, KRB5_KDB_DISALLOW_PROXIABLE) ||
+	 isflagset(server.attributes, KRB5_KDB_DISALLOW_PROXIABLE))) {
+	*status = "PROXIABLE NOT ALLOWED";
+	return(KDC_ERR_POLICY);
+    }
+    
+    /* Check to see if client is locked out */
+    if (isflagset(client.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
+	*status = "CLIENT LOCKED OUT";
+	return(KDC_ERR_C_PRINCIPAL_UNKNOWN);
+    }
+
+    /* Check to see if server is locked out */
+    if (isflagset(server.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
+	*status = "SERVICE LOCKED OUT";
+	return(KDC_ERR_S_PRINCIPAL_UNKNOWN);
+    }
+	
+    /* Check to see if server is allowed to be a service */
+    if (isflagset(server.attributes, KRB5_KDB_DISALLOW_SVR)) {
+	*status = "SERVICE NOT ALLOWED";
+	return(KDC_ERR_S_PRINCIPAL_UNKNOWN);
+    }
+
+    /*
+     * Check against local policy
+     */
+    errcode = against_local_policy_as(request, server, client,
+				      kdc_time, status); 
+    if (errcode)
+	return errcode;
+
+    return 0;
+}
+
+#define ASN1_ID_CLASS	(0xc0)
+#define ASN1_ID_TYPE    (0x20)
+#define ASN1_ID_TAG	(0x1f)	
+#define ASN1_CLASS_UNIV	(0)
+#define ASN1_CLASS_APP	(1)
+#define ASN1_CLASS_CTX	(2)
+#define ASN1_CLASS_PRIV	(3)
+#define asn1_id_constructed(x) 	(x & ASN1_ID_TYPE)
+#define asn1_id_primitive(x) 	(!asn1_id_constructed(x))
+#define asn1_id_class(x)	((x & ASN1_ID_CLASS) >> 6)
+#define asn1_id_tag(x)		(x & ASN1_ID_TAG)
+
+/*
+ * asn1length - return encoded length of value.
+ *
+ * passed a pointer into the asn.1 stream, which is updated
+ * to point right after the length bits.
+ *
+ * returns -1 on failure.
+ */
+static int
+asn1length(unsigned char **astream)
+{
+    int length;		/* resulting length */
+    int sublen;		/* sublengths */
+    int blen;		/* bytes of length */ 
+    unsigned char *p;	/* substring searching */	
+
+    if (**astream & 0x80) {
+        blen = **astream & 0x7f;
+	if (blen > 3) {
+	   return(-1);
+	}
+	for (++*astream, length = 0; blen; ++*astream, blen--) {
+	    length = (length << 8) | **astream;
+	}
+	if (length == 0) {
+		/* indefinite length, figure out by hand */
+	    p = *astream;
+	    p++;
+	    while (1) {
+		/* compute value length. */
+		if ((sublen = asn1length(&p)) < 0) {
+		    return(-1);
+		}
+		p += sublen;
+                /* check for termination */
+		if ((!*p++) && (!*p)) {
+		    p++;
+		    break;
+		}
+	    }
+	    length = p - *astream;	 
+	}
+    } else {
+	length = **astream;
+	++*astream;
+    } 
+   return(length);
+}
+
+/*
+ * fetch_asn1_field - return raw asn.1 stream of subfield.
+ *
+ * this routine is passed a context-dependent tag number and "level" and returns
+ * the size and length of the corresponding level subfield.
+ *
+ * levels and are numbered starting from 1.  
+ *
+ * returns 0 on success, -1 otherwise.
+ */
+int
+fetch_asn1_field(unsigned char *astream, unsigned int level,
+		 unsigned int field, krb5_data *data)
+{
+    unsigned char *estream;	/* end of stream */
+    int classes;		/* # classes seen so far this level */
+    unsigned int levels = 0;		/* levels seen so far */
+    int lastlevel = 1000;       /* last level seen */
+    int length;			/* various lengths */
+    int tag;			/* tag number */
+    unsigned char savelen;      /* saved length of our field */
+
+    classes = -1;
+    /* we assume that the first identifier/length will tell us 
+       how long the entire stream is. */
+    astream++;
+    estream = astream;
+    if ((length = asn1length(&astream)) < 0) {
+	return(-1);
+    }
+    estream += length;
+    /* search down the stream, checking identifiers.  we process identifiers
+       until we hit the "level" we want, and then process that level for our
+       subfield, always making sure we don't go off the end of the stream.  */
+    while (astream < estream) {
+	if (!asn1_id_constructed(*astream)) {
+	    return(-1);
+	}
+        if (asn1_id_class(*astream) == ASN1_CLASS_CTX) {
+            if ((tag = (int)asn1_id_tag(*astream)) <= lastlevel) {
+                levels++;
+                classes = -1;
+            }
+            lastlevel = tag; 
+            if (levels == level) {
+	        /* in our context-dependent class, is this the one we're looking for ? */
+	        if (tag == field) {
+		    /* return length and data */ 
+		    astream++;
+		    savelen = *astream;
+		    if ((data->length = asn1length(&astream)) < 0) {
+		        return(-1);
+	 	    }
+		    /* if the field length is indefinite, we will have to subtract two
+                       (terminating octets) from the length returned since we don't want
+                       to pass any info from the "wrapper" back.  asn1length will always return
+                       the *total* length of the field, not just what's contained in it */ 
+		    if ((savelen & 0xff) == 0x80) {
+		      data->length -=2 ;
+		    }
+		    data->data = (char *)astream;
+		    return(0);
+	        } else if (tag <= classes) {
+		    /* we've seen this class before, something must be wrong */
+		    return(-1);
+	        } else {
+		    classes = tag;
+	        }
+	    }
+        }
+        /* if we're not on our level yet, process this value.  otherwise skip over it */
+	astream++;
+	if ((length = asn1length(&astream)) < 0) {
+	    return(-1);
+	}
+	if (levels == level) {
+	    astream += length;
+	}
+    }
+    return(-1);
+}	
+
+/*
+ * Routines that validate a TGS request; checks a lot of things.  :-)
+ *
+ * Returns a Kerberos protocol error number, which is _not_ the same
+ * as a com_err error number!
+ */
+#define TGS_OPTIONS_HANDLED (KDC_OPT_FORWARDABLE | KDC_OPT_FORWARDED | \
+			     KDC_OPT_PROXIABLE | KDC_OPT_PROXY | \
+			     KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \
+			     KDC_OPT_RENEWABLE | KDC_OPT_RENEWABLE_OK | \
+			     KDC_OPT_ENC_TKT_IN_SKEY | KDC_OPT_RENEW | \
+			     KDC_OPT_VALIDATE)
+
+#define NO_TGT_OPTION (KDC_OPT_FORWARDED | KDC_OPT_PROXY | KDC_OPT_RENEW | \
+		       KDC_OPT_VALIDATE)
+
+int
+validate_tgs_request(register krb5_kdc_req *request, krb5_db_entry server,
+		     krb5_ticket *ticket, krb5_timestamp kdc_time,
+		     const char **status)
+{
+    int		errcode;
+    int		st_idx = 0;
+
+    /*
+     * If an illegal option is set, ignore it.
+     */
+    request->kdc_options &= TGS_OPTIONS_HANDLED;
+
+    /* Check to see if server has expired */
+    if (server.expiration && server.expiration < kdc_time) {
+	*status = "SERVICE EXPIRED";
+	return(KDC_ERR_SERVICE_EXP);
+    }
+
+    /*
+     * Verify that the server principal in authdat->ticket is correct
+     * (either the ticket granting service or the service that was
+     * originally requested)
+     */
+    if (request->kdc_options & NO_TGT_OPTION) {
+	if (!krb5_principal_compare(kdc_context, ticket->server, request->server)) {
+	    *status = "SERVER DIDN'T MATCH TICKET FOR RENEW/FORWARD/ETC";
+	    return(KDC_ERR_SERVER_NOMATCH);
+	}
+    } else {
+	/*
+	 * OK, we need to validate the krbtgt service in the ticket.
+	 *
+	 * The krbtgt service is of the form:
+	 * 		krbtgt/realm-A@realm-B
+	 *
+	 * Realm A is the "server realm"; the realm of the
+	 * server of the requested ticket must match this realm.
+	 * Of course, it should be a realm serviced by this KDC.
+	 *
+	 * Realm B is the "client realm"; this is what should be
+	 * added to the transited field.  (which is done elsewhere)
+	 */
+
+	/* Make sure there are two components... */
+	if (krb5_princ_size(kdc_context, ticket->server) != 2) {
+	    *status = "BAD TGS SERVER LENGTH";
+	    return KRB_AP_ERR_NOT_US;
+	}
+	/* ...that the first component is krbtgt... */
+	if (!krb5_is_tgs_principal(ticket->server)) {
+	    *status = "BAD TGS SERVER NAME";
+	    return KRB_AP_ERR_NOT_US;
+	}
+	/* ...and that the second component matches the server realm... */
+	if ((krb5_princ_size(kdc_context, ticket->server) <= 1) ||
+	    (krb5_princ_component(kdc_context, ticket->server, 1)->length !=
+	     krb5_princ_realm(kdc_context, request->server)->length) ||
+	    memcmp(krb5_princ_component(kdc_context, ticket->server, 1)->data,
+		   krb5_princ_realm(kdc_context, request->server)->data,
+		   krb5_princ_realm(kdc_context, request->server)->length)) {
+	    *status = "BAD TGS SERVER INSTANCE";
+	    return KRB_AP_ERR_NOT_US;
+	}
+	/* XXX add check that second component must match locally
+	 * supported realm?
+	 */
+
+	/* Server must allow TGS based issuances */
+	if (isflagset(server.attributes, KRB5_KDB_DISALLOW_TGT_BASED)) {
+	    *status = "TGT BASED NOT ALLOWED";
+	    return(KDC_ERR_POLICY);
+	}
+    }
+	    
+    /* TGS must be forwardable to get forwarded or forwardable ticket */
+    if ((isflagset(request->kdc_options, KDC_OPT_FORWARDED) ||
+	 isflagset(request->kdc_options, KDC_OPT_FORWARDABLE)) &&
+	!isflagset(ticket->enc_part2->flags, TKT_FLG_FORWARDABLE)) {
+	*status = "TGT NOT FORWARDABLE";
+
+	return KDC_ERR_BADOPTION;
+    }
+
+    /* TGS must be proxiable to get proxiable ticket */    
+    if ((isflagset(request->kdc_options, KDC_OPT_PROXY) ||
+	 isflagset(request->kdc_options, KDC_OPT_PROXIABLE)) &&
+	!isflagset(ticket->enc_part2->flags, TKT_FLG_PROXIABLE)) {
+	*status = "TGT NOT PROXIABLE";
+	return KDC_ERR_BADOPTION;
+    }
+
+    /* TGS must allow postdating to get postdated ticket */
+    if ((isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) ||
+	  isflagset(request->kdc_options, KDC_OPT_POSTDATED)) &&
+	!isflagset(ticket->enc_part2->flags, TKT_FLG_MAY_POSTDATE)) {
+	*status = "TGT NOT POSTDATABLE";
+	return KDC_ERR_BADOPTION;
+    }
+
+    /* can only validate invalid tix */
+    if (isflagset(request->kdc_options, KDC_OPT_VALIDATE) &&
+	!isflagset(ticket->enc_part2->flags, TKT_FLG_INVALID)) {
+	*status = "VALIDATE VALID TICKET";
+	return KDC_ERR_BADOPTION;
+    }
+
+    /* can only renew renewable tix */
+    if ((isflagset(request->kdc_options, KDC_OPT_RENEW) ||
+	  isflagset(request->kdc_options, KDC_OPT_RENEWABLE)) &&
+	!isflagset(ticket->enc_part2->flags, TKT_FLG_RENEWABLE)) {
+	*status = "TICKET NOT RENEWABLE";
+	return KDC_ERR_BADOPTION;
+    }
+
+    /* can not proxy ticket granting tickets */
+    if (isflagset(request->kdc_options, KDC_OPT_PROXY) &&
+	(!request->server->data ||
+	 request->server->data[0].length != KRB5_TGS_NAME_SIZE ||
+	 memcmp(request->server->data[0].data, KRB5_TGS_NAME,
+		KRB5_TGS_NAME_SIZE))) {
+	*status = "CAN'T PROXY TGT";
+	return KDC_ERR_BADOPTION;
+    }
+    
+    /* Server must allow forwardable tickets */
+    if (isflagset(request->kdc_options, KDC_OPT_FORWARDABLE) &&
+	isflagset(server.attributes, KRB5_KDB_DISALLOW_FORWARDABLE)) {
+	*status = "NON-FORWARDABLE TICKET";
+	return(KDC_ERR_POLICY);
+    }
+    
+    /* Server must allow renewable tickets */
+    if (isflagset(request->kdc_options, KDC_OPT_RENEWABLE) &&
+	isflagset(server.attributes, KRB5_KDB_DISALLOW_RENEWABLE)) {
+	*status = "NON-RENEWABLE TICKET";
+	return(KDC_ERR_POLICY);
+    }
+    
+    /* Server must allow proxiable tickets */
+    if (isflagset(request->kdc_options, KDC_OPT_PROXIABLE) &&
+	isflagset(server.attributes, KRB5_KDB_DISALLOW_PROXIABLE)) {
+	*status = "NON-PROXIABLE TICKET";
+	return(KDC_ERR_POLICY);
+    }
+    
+    /* Server must allow postdated tickets */
+    if (isflagset(request->kdc_options, KDC_OPT_ALLOW_POSTDATE) &&
+	isflagset(server.attributes, KRB5_KDB_DISALLOW_POSTDATED)) {
+	*status = "NON-POSTDATABLE TICKET";
+	return(KDC_ERR_CANNOT_POSTDATE);
+    }
+    
+    /* Server must allow DUP SKEY requests */
+    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY) &&
+	isflagset(server.attributes, KRB5_KDB_DISALLOW_DUP_SKEY)) {
+	*status = "DUP_SKEY DISALLOWED";
+	return(KDC_ERR_POLICY);
+    }
+
+    /* Server must not be locked out */
+    if (isflagset(server.attributes, KRB5_KDB_DISALLOW_ALL_TIX)) {
+	*status = "SERVER LOCKED OUT";
+	return(KDC_ERR_S_PRINCIPAL_UNKNOWN);
+    }
+	
+    /* Server must be allowed to be a service */
+    if (isflagset(server.attributes, KRB5_KDB_DISALLOW_SVR)) {
+	*status = "SERVER NOT ALLOWED";
+	return(KDC_ERR_S_PRINCIPAL_UNKNOWN);
+    }
+
+    /* Check the hot list */
+    if (check_hot_list(ticket)) {
+	*status = "HOT_LIST";
+	return(KRB_AP_ERR_REPEAT);
+    }
+    
+    /* Check the start time vs. the KDC time */
+    if (isflagset(request->kdc_options, KDC_OPT_VALIDATE)) {
+	if (ticket->enc_part2->times.starttime > kdc_time) {
+	    *status = "NOT_YET_VALID";
+	    return(KRB_AP_ERR_TKT_NYV);
+	}
+    }
+    
+    /*
+     * Check the renew_till time.  The endtime was already
+     * been checked in the initial authentication check.
+     */
+    if (isflagset(request->kdc_options, KDC_OPT_RENEW) &&
+	(ticket->enc_part2->times.renew_till < kdc_time)) {
+	*status = "TKT_EXPIRED";
+	return(KRB_AP_ERR_TKT_EXPIRED);
+    }
+    
+    /*
+     * Checks for ENC_TKT_IN_SKEY:
+     *
+     * (1) Make sure the second ticket exists
+     * (2) Make sure it is a ticket granting ticket
+     */
+    if (isflagset(request->kdc_options, KDC_OPT_ENC_TKT_IN_SKEY)) {
+	if (!request->second_ticket ||
+	    !request->second_ticket[st_idx]) {
+	    *status = "NO_2ND_TKT";
+	    return(KDC_ERR_BADOPTION);
+	}
+	if (!krb5_principal_compare(kdc_context, request->second_ticket[st_idx]->server,
+				    tgs_server)) {
+		*status = "2ND_TKT_NOT_TGS";
+		return(KDC_ERR_POLICY);
+	}
+	st_idx++;
+    }
+
+    /* Check for hardware preauthentication */
+    if (isflagset(server.attributes, KRB5_KDB_REQUIRES_HW_AUTH) &&
+	!isflagset(ticket->enc_part2->flags,TKT_FLG_HW_AUTH)) {
+	*status = "NO HW PREAUTH";
+	return KRB_ERR_GENERIC;
+    }
+
+    /* Check for any kind of preauthentication */
+    if (isflagset(server.attributes, KRB5_KDB_REQUIRES_PRE_AUTH) &&
+	!isflagset(ticket->enc_part2->flags, TKT_FLG_PRE_AUTH)) {
+	*status = "NO PREAUTH";
+	return KRB_ERR_GENERIC;
+    }
+    
+    /*
+     * Check local policy
+     */
+    errcode = against_local_policy_tgs(request, server, ticket, status);
+    if (errcode)
+	return errcode;
+    
+    
+    return 0;
+}
+
+/*
+ * This function returns 1 if the dbentry has a key for a specified
+ * keytype, and 0 if not.
+ */
+int
+dbentry_has_key_for_enctype(krb5_context context, krb5_db_entry *client,
+			    krb5_enctype enctype)
+{
+    krb5_error_code	retval;
+    krb5_key_data	*datap;
+
+    retval = krb5_dbe_find_enctype(context, client, enctype,
+				   -1, 0, &datap);
+    if (retval)
+	return 0;
+    else
+	return 1;
+}
+
+/*
+ * This function returns 1 if the entity referenced by this
+ * structure can support the a particular encryption system, and 0 if
+ * not.
+ *
+ * XXX eventually this information should be looked up in the
+ * database.  Since it isn't, we use some hueristics and attribute
+ * options bits for now.
+ */
+int
+dbentry_supports_enctype(krb5_context context, krb5_db_entry *client,
+			 krb5_enctype enctype)
+{
+    /*
+     * If it's DES_CBC_MD5, there's a bit in the attribute mask which
+     * checks to see if we support it.  For now, treat it as always
+     * clear.
+     *
+     * In theory everything's supposed to support DES_CBC_MD5, but
+     * that's not the reality....
+     */
+    if (enctype == ENCTYPE_DES_CBC_MD5)
+	return 0;
+
+    /*
+     * XXX we assume everything can understand DES_CBC_CRC
+     */
+    if (enctype == ENCTYPE_DES_CBC_CRC)
+	return 1;
+    
+    /*
+     * If we have a key for the encryption system, we assume it's
+     * supported.
+     */
+    return dbentry_has_key_for_enctype(context, client, enctype);
+}
+
+/*
+ * This function returns the keytype which should be selected for the
+ * session key.  It is based on the ordered list which the user
+ * requested, and what the KDC and the application server can support.
+ */
+krb5_enctype
+select_session_keytype(krb5_context context, krb5_db_entry *server,
+		       int nktypes, krb5_enctype *ktype)
+{
+    int		i;
+    
+    for (i = 0; i < nktypes; i++) {
+	if (!krb5_c_valid_enctype(ktype[i]))
+	    continue;
+
+	if (!krb5_is_permitted_enctype(context, ktype[i]))
+	    continue;
+
+	if (dbentry_supports_enctype(context, server, ktype[i]))
+	    return ktype[i];
+    }
+    return 0;
+}
+
+/*
+ * This function returns salt information for a particular client_key
+ */
+krb5_error_code
+get_salt_from_key(krb5_context context, krb5_principal client,
+		  krb5_key_data *client_key, krb5_data *salt)
+{
+    krb5_error_code		retval;
+    krb5_data *			realm;
+    
+    salt->data = 0;
+    salt->length = SALT_TYPE_NO_LENGTH;
+    
+    if (client_key->key_data_ver == 1)
+	return 0;
+
+    switch (client_key->key_data_type[1]) {
+    case KRB5_KDB_SALTTYPE_NORMAL:
+	break;
+    case KRB5_KDB_SALTTYPE_V4:
+	/* send an empty (V4) salt */
+	salt->data = 0;
+	salt->length = 0;
+	break;
+    case KRB5_KDB_SALTTYPE_NOREALM:
+	if ((retval = krb5_principal2salt_norealm(context, client, salt)))
+	    return retval;
+	break;
+    case KRB5_KDB_SALTTYPE_AFS3:
+	/* send the same salt as with onlyrealm - but with no type info,
+	   we just hope they figure it out on the other end. */
+	/* fall through to onlyrealm: */
+    case KRB5_KDB_SALTTYPE_ONLYREALM:
+	realm = krb5_princ_realm(context, client);
+	salt->length = realm->length;
+	if ((salt->data = malloc(realm->length)) == NULL)
+	    return ENOMEM;
+	memcpy(salt->data, realm->data, realm->length);
+	break;
+    case KRB5_KDB_SALTTYPE_SPECIAL:
+	salt->length = client_key->key_data_length[1];
+	if ((salt->data = malloc(salt->length)) == NULL)
+	    return ENOMEM;
+	memcpy(salt->data, client_key->key_data_contents[1], salt->length);
+	break;
+    }
+    return 0;
+}
+
+/*
+ * Limit strings to a "reasonable" length to prevent crowding out of
+ * other useful information in the log entry
+ */
+#define NAME_LENGTH_LIMIT 128
+
+void limit_string(char *name)
+{
+	int	i;
+
+	if (!name)
+		return;
+
+	if (strlen(name) < NAME_LENGTH_LIMIT)
+		return;
+
+	i = NAME_LENGTH_LIMIT-4;
+	name[i++] = '.';
+	name[i++] = '.';
+	name[i++] = '.';
+	name[i] = '\0';
+	return;
+}
+
+/*
+ * L10_2 = log10(2**x), rounded up; log10(2) ~= 0.301.
+ */
+#define L10_2(x) ((int)(((x * 301) + 999) / 1000))
+
+/*
+ * Max length of sprintf("%ld") for an int of type T; includes leading
+ * minus sign and terminating NUL.
+ */
+#define D_LEN(t) (L10_2(sizeof(t) * CHAR_BIT) + 2)
+
+void
+ktypes2str(char *s, size_t len, int nktypes, krb5_enctype *ktype)
+{
+    int i;
+    char stmp[D_LEN(krb5_enctype) + 1];
+    char *p;
+
+    if (nktypes < 0
+	|| len < (sizeof(" etypes {...}") + D_LEN(int))) {
+	*s = '\0';
+	return;
+    }
+
+    sprintf(s, "%d etypes {", nktypes);
+    for (i = 0; i < nktypes; i++) {
+	sprintf(stmp, "%s%ld", i ? " " : "", (long)ktype[i]);
+	if (strlen(s) + strlen(stmp) + sizeof("}") > len)
+	    break;
+	strcat(s, stmp);
+    }
+    if (i < nktypes) {
+	/*
+	 * We broke out of the loop. Try to truncate the list.
+	 */
+	p = s + strlen(s);
+	while (p - s + sizeof("...}") > len) {
+	    while (p > s && *p != ' ' && *p != '{')
+		*p-- = '\0';
+	    if (p > s && *p == ' ') {
+		*p-- = '\0';
+		continue;
+	    }
+	}
+	strcat(s, "...");
+    }
+    strcat(s, "}");
+    return;
+}
+
+void
+rep_etypes2str(char *s, size_t len, krb5_kdc_rep *rep)
+{
+    char stmp[sizeof("ses=") + D_LEN(krb5_enctype)];
+
+    if (len < (3 * D_LEN(krb5_enctype)
+	       + sizeof("etypes {rep= tkt= ses=}"))) {
+	*s = '\0';
+	return;
+    }
+
+    sprintf(s, "etypes {rep=%ld", (long)rep->enc_part.enctype);
+
+    if (rep->ticket != NULL) {
+	sprintf(stmp, " tkt=%ld", (long)rep->ticket->enc_part.enctype);
+	strcat(s, stmp);
+    }
+
+    if (rep->ticket != NULL
+	&& rep->ticket->enc_part2 != NULL
+	&& rep->ticket->enc_part2->session != NULL) {
+	sprintf(stmp, " ses=%ld",
+		(long)rep->ticket->enc_part2->session->enctype);
+	strcat(s, stmp);
+    }
+    strcat(s, "}");
+    return;
+}
diff --git a/mechglue/src/kdc/kdc_util.h b/mechglue/src/kdc/kdc_util.h
new file mode 100644
index 000000000..cdf32bd7d
--- /dev/null
+++ b/mechglue/src/kdc/kdc_util.h
@@ -0,0 +1,194 @@
+/*
+ * kdc/kdc_util.h
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Declarations for policy.c
+ */
+
+#ifndef __KRB5_KDC_UTIL__
+#define __KRB5_KDC_UTIL__
+
+typedef struct _krb5_fulladdr {
+    krb5_address *	address;
+    krb5_ui_4		port;
+} krb5_fulladdr;
+
+krb5_error_code check_hot_list (krb5_ticket *);
+krb5_boolean realm_compare (krb5_principal, krb5_principal);
+krb5_boolean krb5_is_tgs_principal (krb5_principal);
+krb5_error_code add_to_transited (krb5_data *,
+					    krb5_data *,
+					    krb5_principal,
+					    krb5_principal,
+					    krb5_principal);
+krb5_error_code compress_transited (krb5_data *,
+					      krb5_principal,
+					      krb5_data *);
+krb5_error_code concat_authorization_data (krb5_authdata **,
+						     krb5_authdata **,
+						     krb5_authdata ***);
+krb5_error_code fetch_last_req_info (krb5_db_entry *,
+					       krb5_last_req_entry ***);
+
+krb5_error_code kdc_convert_key (krb5_keyblock *,
+					   krb5_keyblock *,
+					   int);
+krb5_error_code kdc_process_tgs_req 
+	(krb5_kdc_req *,
+	           const krb5_fulladdr *,
+	           krb5_data *,
+	           krb5_ticket **,
+	           krb5_keyblock **);
+
+krb5_error_code kdc_get_server_key (krb5_ticket *,
+					      krb5_keyblock **,
+					      krb5_kvno *);
+
+int validate_as_request (krb5_kdc_req *, krb5_db_entry, 
+					  krb5_db_entry, krb5_timestamp,
+					  const char **);
+
+int validate_tgs_request (krb5_kdc_req *, krb5_db_entry, 
+					  krb5_ticket *, krb5_timestamp,
+					  const char **);
+
+int fetch_asn1_field (unsigned char *, unsigned int, unsigned int,
+				 krb5_data *);
+
+int
+dbentry_has_key_for_enctype (krb5_context context,
+				       krb5_db_entry *client,
+				       krb5_enctype enctype);
+    
+int
+dbentry_supports_enctype (krb5_context context,
+				    krb5_db_entry *client,
+				    krb5_enctype enctype);
+
+krb5_enctype
+select_session_keytype (krb5_context context,
+				  krb5_db_entry *server,
+				  int nktypes,
+				  krb5_enctype *ktypes);
+
+krb5_error_code
+get_salt_from_key (krb5_context, krb5_principal,
+			     krb5_key_data *, krb5_data *);
+
+void limit_string (char *name);
+
+void
+ktypes2str(char *s, size_t len, int nktypes, krb5_enctype *ktype);
+
+void
+rep_etypes2str(char *s, size_t len, krb5_kdc_rep *rep);
+
+/* do_as_req.c */
+krb5_error_code process_as_req (krb5_kdc_req *,
+					  const krb5_fulladdr *,
+					  krb5_data ** );
+
+/* do_tgs_req.c */
+krb5_error_code process_tgs_req (krb5_data *,
+					   const krb5_fulladdr *,
+					   krb5_data ** );
+/* dispatch.c */
+krb5_error_code dispatch (krb5_data *,
+				    const krb5_fulladdr *,
+				    krb5_data **);
+
+/* main.c */
+krb5_error_code kdc_initialize_rcache (krb5_context, char *);
+
+krb5_error_code setup_server_realm (krb5_principal);
+
+/* network.c */
+krb5_error_code listen_and_process (const char *);
+krb5_error_code setup_network (const char *);
+krb5_error_code closedown_network (const char *);
+
+/* policy.c */
+int against_local_policy_as (krb5_kdc_req *, krb5_db_entry,
+					krb5_db_entry, krb5_timestamp,
+					const char **);
+
+int against_local_policy_tgs (krb5_kdc_req *, krb5_db_entry,
+					krb5_ticket *, const char **);
+
+/* kdc_preauth.c */
+const char * missing_required_preauth
+    (krb5_db_entry *client, krb5_db_entry *server,
+	       krb5_enc_tkt_part *enc_tkt_reply);
+void get_preauth_hint_list (krb5_kdc_req * request,
+				      krb5_db_entry *client,
+				      krb5_db_entry *server,
+				      krb5_data *e_data);
+krb5_error_code check_padata
+    (krb5_context context, krb5_db_entry *client,
+	       krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply);
+    
+krb5_error_code return_padata
+    (krb5_context context, krb5_db_entry *client,
+	       krb5_kdc_req *request, krb5_kdc_rep *reply,
+	       krb5_key_data *client_key, krb5_keyblock *encrypting_key);
+    
+/* replay.c */
+krb5_boolean kdc_check_lookaside (krb5_data *, const krb5_fulladdr *,
+					    krb5_data **);
+void kdc_insert_lookaside (krb5_data *, const krb5_fulladdr *,
+				     krb5_data *);
+void kdc_free_lookaside(krb5_context);
+
+/* which way to convert key? */
+#define CONVERT_INTO_DB	0
+#define CONVERT_OUTOF_DB 1
+
+#define isflagset(flagfield, flag) (flagfield & (flag))
+#define setflag(flagfield, flag) (flagfield |= (flag))
+#define clear(flagfield, flag) (flagfield &= ~(flag))
+
+#ifdef KRB5_KRB4_COMPAT
+krb5_error_code process_v4 (const krb5_data *,
+				      const krb5_fulladdr *,
+				      krb5_data **);
+void process_v4_mode (const char *, const char *);
+void enable_v4_crossrealm(char *);
+#else
+#define process_v4(foo,bar,quux,foobar)	KRB5KRB_AP_ERR_BADVERSION
+#endif
+
+#ifndef	min
+#define	min(a, b)	((a) < (b) ? (a) : (b))
+#define	max(a, b)	((a) > (b) ? (a) : (b))
+#endif
+
+#ifdef KRB5_USE_INET6
+#define ADDRTYPE2FAMILY(X) \
+  ((X) == ADDRTYPE_INET6 ? AF_INET6 : (X) == ADDRTYPE_INET ? AF_INET : -1)
+#else
+#define ADDRTYPE2FAMILY(X) \
+  ((X) == ADDRTYPE_INET ? AF_INET : -1)
+#endif
+
+#endif /* __KRB5_KDC_UTIL__ */
diff --git a/mechglue/src/kdc/kerberos_v4.c b/mechglue/src/kdc/kerberos_v4.c
new file mode 100644
index 000000000..72db8a5d7
--- /dev/null
+++ b/mechglue/src/kdc/kerberos_v4.c
@@ -0,0 +1,1203 @@
+/*
+ * kdc/kerberos_v4.c
+ *
+ * Copyright 1985, 1986, 1987, 1988,1991 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "krb5/autoconf.h"
+#ifdef KRB5_KRB4_COMPAT
+#define BACKWARD_COMPAT
+
+#include "k5-int.h"
+#include "kdc_util.h"
+#include "adm_proto.h"
+
+#include <stdarg.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#include <time.h>
+#endif
+#include <sys/file.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <string.h>
+
+/* v4 include files:
+ */
+#include <krb.h>
+#include <des.h>
+#include <klog.h>
+#include <prot.h>
+#include <krb_db.h>
+#include <kdc.h>
+
+#ifdef NEED_SWAB_PROTO
+extern void swab(const void *, void *, size_t );
+#endif
+
+static int compat_decrypt_key (krb5_key_data *, C_Block,
+					 krb5_keyblock *, int);
+static int kerb_get_principal (char *, char *, Principal *, int,
+					 int *, krb5_keyblock *, krb5_kvno,
+					 int, krb5_deltat *);
+static int check_princ (char *, char *, int, Principal *,
+				  krb5_keyblock *, int, krb5_deltat *);
+
+char * v4_klog (int, const char *, ...);
+#define klog v4_klog
+
+/* take this out when we don't need it anymore */
+int krbONE = 1;
+/* XXX inline former contents of krb_conf.h for now */
+/* Byte ordering */
+extern int krbONE;
+#define		HOST_BYTE_ORDER	(* (char *) &krbONE)
+#define		MSB_FIRST		0	/* 68000, IBM RT/PC */
+#define		LSB_FIRST		1	/* Vax, PC8086 */
+
+int     f;
+
+/* XXX several files in libkdb know about this */
+char *progname;
+
+#ifndef BACKWARD_COMPAT
+static Key_schedule master_key_schedule;
+static C_Block master_key;
+#endif
+
+static struct timeval kerb_time;
+static Principal a_name_data;	/* for requesting user */
+static Principal s_name_data;	/* for services requested */
+static C_Block session_key;
+
+static char log_text[512];
+static char *lt;
+
+/* fields within the received request packet */
+static u_char req_msg_type;
+static u_char req_version;
+static char *req_name_ptr;
+static char *req_inst_ptr;
+static char *req_realm_ptr;
+
+static krb5_ui_4 req_time_ws;
+
+static char local_realm[REALM_SZ];
+
+static long n_auth_req;
+static long n_appl_req;
+
+static long pause_int = -1;
+
+static void hang(void);
+
+
+/* v4/v5 backwards-compatibility stub routines,
+ * which allow the v5 server to handle v4 packets
+ * by invoking substantially-unaltered v4 server code.
+ * this is only necessary during the installation's conversion to v5.
+ * process_v4() is invoked by v5's dispatch() routine;
+ * when the v4 server needs to access the v5 database,
+ * it calls the other stubs.
+ *
+ * until all kerberized application-programs are updated,
+ * this approach inflates the v5 server's code size,
+ * but it's easier to debug than a concurrent, subordinate v4 server would be.
+ */
+
+/*
+ * v5 include files:
+ */
+#include "com_err.h"
+#include "extern.h"		/* to pick up master_princ */
+
+static krb5_data *response;
+
+void kerberos_v4 (struct sockaddr_in *, KTEXT);
+void kerb_err_reply (struct sockaddr_in *, KTEXT, long, char *);
+static int set_tgtkey (char *, krb5_kvno, krb5_boolean);
+
+/* Attributes converted from V5 to V4 - internal representation */
+#define V4_KDB_REQUIRES_PREAUTH  0x1
+#define V4_KDB_DISALLOW_ALL_TIX  0x2
+#define V4_KDB_REQUIRES_PWCHANGE 0x4
+#define V4_KDB_DISALLOW_SVR      0x8
+
+/* v4 compatibitly mode switch */
+#define KDC_V4_NONE		0	/* Don't even respond to packets */
+#define KDC_V4_DISABLE		1	/* V4 requests return an error */
+#define	KDC_V4_FULL		2	/* Preauth required go through */
+#define KDC_V4_NOPREAUTH	3	/* Preauth required disallowed */
+
+#define KDC_V4_DEFAULT_MODE KDC_V4_NONE
+/* Flag on how to handle v4 */
+static int		kdc_v4;
+
+struct v4mode_lookup_entry {
+    int                 mode;                   /* Mode setting */
+    const char *	v4_specifier;		/* How to recognize it	*/
+};
+
+static const struct v4mode_lookup_entry  v4mode_table[] = {
+/*  mode                input specifier */
+{ KDC_V4_NONE,          "none"          },
+{ KDC_V4_DISABLE,       "disable"       }, 
+{ KDC_V4_FULL,          "full"          },
+{ KDC_V4_NOPREAUTH,     "nopreauth"     }
+};
+
+static const int v4mode_table_nents = sizeof(v4mode_table)/
+				      sizeof(v4mode_table[0]);
+
+static int allow_v4_crossrealm = 0;
+
+void process_v4_mode(const char *program_name, const char *string)
+{
+    int i, found;
+
+    found = 0;
+    kdc_v4 = KDC_V4_DEFAULT_MODE;
+
+    if(!string) return;  /* Set to default mode */
+    
+    for (i=0; i<v4mode_table_nents; i++) {
+	if (!strcasecmp(string, v4mode_table[i].v4_specifier)) {
+	    found = 1;
+	    kdc_v4 = v4mode_table[i].mode;
+	    break;
+	}
+    }
+
+    if(!found) {
+      /* It is considered fatal if we request a mode that is not found */
+	com_err(program_name, 0, "invalid v4_mode %s", string);
+	exit(1);
+    }
+    return;
+}
+
+void enable_v4_crossrealm ( char *programname) {
+    allow_v4_crossrealm = 1;
+    krb5_klog_syslog(LOG_ERR, "Enabling v4 cross-realm compatibility; this is a known security hole");
+}
+
+krb5_error_code
+process_v4(const krb5_data *pkt, const krb5_fulladdr *client_fulladdr,
+	   krb5_data **resp)
+{
+    struct sockaddr_in client_sockaddr;
+    krb5_address *addr = client_fulladdr->address;
+    krb5_error_code retval;
+    krb5_timestamp now;
+    KTEXT_ST v4_pkt;
+    char *lrealm;
+
+    /* Check if disabled completely */
+    if (kdc_v4 == KDC_V4_NONE) {
+	(void) klog(L_KRB_PERR, "Disabled KRB V4 request");
+	return KRB5KDC_ERR_BAD_PVNO;
+    }
+
+    
+    if ((retval = krb5_timeofday(kdc_context, &now)))
+        return(retval);
+    kerb_time.tv_sec = now;
+
+    if (!*local_realm) {		/* local-realm name already set up */
+	lrealm = master_princ->realm.data;
+	if (master_princ->realm.length < sizeof(local_realm)) {
+	    memcpy(local_realm, lrealm, master_princ->realm.length);
+	    local_realm[master_princ->realm.length] = '\0';
+	} else
+	    retval = KRB5_CONFIG_NOTENUFSPACE;
+    }
+    /* convert client_fulladdr to client_sockaddr:
+     */
+    client_sockaddr.sin_family	= AF_INET;
+    client_sockaddr.sin_port	= client_fulladdr->port;
+    if (client_fulladdr->address->addrtype != ADDRTYPE_INET) {
+	klog(L_KRB_PERR, "got krb4 request from non-ipv4 address");
+	client_sockaddr.sin_addr.s_addr = 0;
+    } else
+	memcpy(&client_sockaddr.sin_addr, addr->contents, 
+	       sizeof client_sockaddr.sin_addr);
+    memset( client_sockaddr.sin_zero, 0, sizeof client_sockaddr.sin_zero);
+
+    /* convert v5 packet structure to v4's.
+     * this copy is gross, but necessary:
+     */
+    if (pkt->length > MAX_KTXT_LEN) {
+	    (void) klog(L_KRB_PERR, "V4 request too long.");
+	    return KRB5KRB_ERR_FIELD_TOOLONG;
+    }
+    v4_pkt.length = pkt->length;
+    v4_pkt.mbz = 0;
+    memcpy( v4_pkt.dat, pkt->data, pkt->length);
+
+    kerberos_v4( &client_sockaddr, &v4_pkt);
+    *resp = response;
+    return(retval);
+}
+
+char * v4_klog( int type, const char *format, ...)
+{
+    int logpri = LOG_INFO;
+    va_list pvar;
+    va_start(pvar, format);
+
+    switch (type) {
+    case L_ERR_SEXP:
+    case L_ERR_NKY:
+    case L_ERR_NUN:
+    case L_ERR_UNK:
+    case L_KRB_PERR:
+	logpri = LOG_ERR;
+    case L_INI_REQ:
+    case L_NTGT_INTK:
+    case L_TKT_REQ:
+    case L_APPL_REQ:
+	strcpy(log_text, "PROCESS_V4:");
+	vsprintf(log_text+strlen(log_text), format, pvar);
+	krb5_klog_syslog(logpri, "%s", log_text);
+    default:
+	/* ignore the other types... */
+	;
+    }
+    va_end(pvar);
+    return(log_text);
+}
+
+static
+int krb4_sendto(int s, const char *msg, int len, int flags,
+		const struct sockaddr *to, int to_len)
+{
+    if (  !(response = (krb5_data *) malloc( sizeof *response))) {
+	return ENOMEM;
+    }
+    if ( !(response->data = (char *) malloc( len))) {
+	krb5_free_data(kdc_context,  response);
+	return ENOMEM;
+    }
+    response->length = len;
+    memcpy( response->data, msg, len);
+    return( 0);
+}
+static void
+hang(void)
+{
+    if (pause_int == -1) {
+        klog(L_KRB_PERR, "Kerberos will pause so as not to loop init");
+     /* for (;;)
+            pause(); */
+    } else {
+        char buf[256];
+        sprintf(buf,
+	   "Kerberos will wait %d seconds before dying so as not to loop init",
+		(int) pause_int);
+        klog(L_KRB_PERR, buf);
+        sleep((unsigned) pause_int);
+        klog(L_KRB_PERR, "Do svedania....\n");
+     /* exit(1); */
+    }
+}
+#define kdb_encrypt_key( in, out, mk, mks, e_d_flag)
+#define LONGLEN 4
+#define K4KDC_ENCTYPE_OK(e)			\
+((e) == ENCTYPE_DES_CBC_CRC			\
+ || (e) == ENCTYPE_DES_CBC_MD4			\
+ || (e) == ENCTYPE_DES_CBC_MD5			\
+ || (e) == ENCTYPE_DES_CBC_RAW)
+
+/* take a v5 keyblock, masquerading as a v4 key,
+ * decrypt it, and convert the resulting v5 keyblock
+ * to a real v4 key.
+ * this is ugly, but it saves changing more v4 code.
+ *
+ * Also, keep old krb5_keyblock around in case we want to use it later.
+ */
+static int
+compat_decrypt_key (krb5_key_data *in5, unsigned char *out4,
+		    krb5_keyblock *out5, int issrv)
+{
+    krb5_error_code retval;
+
+    out5->contents = NULL;
+    memset(out4, 0, sizeof(out4));
+    retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_keyblock,
+					 in5, out5, NULL);
+    if (retval) {
+	lt = klog(L_DEATH_REQ, "KDC can't decrypt principal's key.");
+	out5->contents = NULL;
+	return(retval);
+    }
+    if (K4KDC_ENCTYPE_OK(out5->enctype)) {
+	if (out5->length == KRB5_MIT_DES_KEYSIZE) 
+	    memcpy(out4, out5->contents, out5->length);
+	else {
+	    lt = klog(L_DEATH_REQ, "internal keysize error in kdc");
+	    krb5_free_keyblock_contents(kdc_context, out5);
+	    out5->contents = NULL;
+	    retval = -1;
+	}
+    } else {
+	if (!issrv) {
+	    lt = klog(L_DEATH_REQ, "incompatible principal key type.");
+	    krb5_free_keyblock_contents(kdc_context, out5);
+	    out5->contents = NULL;
+	    retval = -1;
+	} else {
+	    /* KLUDGE! If it's a non-raw des3 key, bash its enctype */
+	    if (out5->enctype == ENCTYPE_DES3_CBC_SHA1 )
+		out5->enctype = ENCTYPE_DES3_CBC_RAW;
+	}
+    }
+    return(retval);
+}
+
+/* array of name-components + NULL ptr
+ */
+
+/*
+ * Previously this code returned either a v4 key or a v5 key  and you
+ * could tell from the enctype of the v5 key whether the v4 key was
+ * useful.  Now we return both keys so the code can try both des3 and
+ * des decryption.  We fail if the ticket doesn't have a v4 key.
+ * Also, note as a side effect, the v5 key is basically useless  in
+ * the client case.  It is still returned so the caller can free it.
+ */
+static int
+kerb_get_principal(char *name, char *inst, /* could have wild cards */
+		   Principal *principal,
+		   int maxn,	/* max # name structs to return */
+		   int *more,	/* more tuples than room for */
+		   krb5_keyblock *k5key, krb5_kvno kvno,
+		   int issrv,	/* true if retrieving a service key */
+		   krb5_deltat *k5life)
+{
+    /* Note that this structure should not be passed to the
+       krb5_free* functions, because the pointers within it point
+       to data with other references.  */
+    krb5_principal search;
+
+    krb5_db_entry entries;	/* filled in by krb5_db_get_principal() */
+    int nprinc;			/* how many found */
+    krb5_boolean more5;		/* are there more? */
+    C_Block k;
+    short toggle = 0;
+    unsigned long *date;
+    char* text;
+    struct tm *tp;
+    krb5_key_data *pkey;
+    krb5_error_code retval;
+
+    *more = 0;
+    if ( maxn > 1) {
+	lt = klog(L_DEATH_REQ, "KDC V4 is requesting too many principals");
+	return( 0);
+    }
+    /* begin setting up the principal structure
+     * with the first info we have:
+     */
+    memcpy( principal->name,     name, 1 + strlen( name));
+    memcpy( principal->instance, inst, 1 + strlen( inst));
+
+    /* the principal-name format changed between v4 & v5:
+     *     v4: name.instance@realm
+     *     v5: realm/name/instance
+     *     in v5, null instance means the null-component doesn't exist.
+     */
+
+    if ((retval = krb5_425_conv_principal(kdc_context, name, inst, 
+					  local_realm, &search)))
+	return(0);
+
+    if ((retval = krb5_db_get_principal(kdc_context, search, &entries, 
+					&nprinc, &more5))) {
+        krb5_free_principal(kdc_context, search);
+        return(0);
+    }
+    principal->key_low = principal->key_high = 0;
+    krb5_free_principal(kdc_context, search);
+
+    if (nprinc < 1) {
+        *more = (int)more5 || (nprinc > maxn);
+        return(nprinc);
+    } 
+
+    if (!issrv) {
+	if (krb5_dbe_find_enctype(kdc_context,
+				  &entries,
+				  ENCTYPE_DES_CBC_CRC,
+				  KRB5_KDB_SALTTYPE_V4,
+				  kvno,
+				  &pkey) &&
+	    krb5_dbe_find_enctype(kdc_context,
+				  &entries,
+				  ENCTYPE_DES_CBC_CRC,
+				  -1,
+				  kvno,
+				  &pkey)) {
+	    lt = klog(L_KRB_PERR,
+		      "KDC V4: principal %s.%s isn't V4 compatible",
+		      name, inst);
+	    krb5_db_free_principal(kdc_context, &entries, nprinc);
+	    return(0);
+	}
+    } else {
+	if ( krb5_dbe_find_enctype(kdc_context, &entries,
+				  ENCTYPE_DES_CBC_CRC,
+				  KRB5_KDB_SALTTYPE_V4, kvno, &pkey) &&
+	    krb5_dbe_find_enctype(kdc_context, &entries,
+				  ENCTYPE_DES_CBC_CRC,
+				  -1, kvno, &pkey)) {
+	    lt = klog(L_KRB_PERR,
+		      "KDC V4: failed to find key for %s.%s #%d",
+		      name, inst, kvno);
+	    krb5_db_free_principal(kdc_context, &entries, nprinc);
+	    return(0);
+	}
+    }
+
+    if (!compat_decrypt_key(pkey, k, k5key, issrv)) {
+ 	memcpy( &principal->key_low, k, LONGLEN);
+       	memcpy( &principal->key_high, (krb5_ui_4 *) k + 1, LONGLEN);
+    }
+    memset(k, 0, sizeof k);
+    if (issrv) {
+	krb5_free_keyblock_contents (kdc_context, k5key);
+      	if (krb5_dbe_find_enctype(kdc_context, &entries,
+				  ENCTYPE_DES3_CBC_RAW,
+				  -1, kvno, &pkey) &&
+	    krb5_dbe_find_enctype(kdc_context, &entries,
+				  ENCTYPE_DES3_CBC_SHA1,
+				  -1, kvno, &pkey) &&
+	    krb5_dbe_find_enctype(kdc_context, &entries,
+				  ENCTYPE_DES_CBC_CRC,
+				  KRB5_KDB_SALTTYPE_V4, kvno, &pkey) &&
+	    krb5_dbe_find_enctype(kdc_context, &entries,
+				  ENCTYPE_DES_CBC_CRC,
+				  -1, kvno, &pkey)) {
+	    lt = klog(L_KRB_PERR,
+		      "KDC V4: failed to find key for %s.%s #%d (after having found it once)",
+		      name, inst, kvno);
+	    krb5_db_free_principal(kdc_context, &entries, nprinc);
+	    return(0);
+	}
+	compat_decrypt_key(pkey, k, k5key, issrv);
+    memset (k, 0, sizeof k);
+	}
+
+
+    /*
+     * Convert v5's entries struct to v4's Principal struct:
+     * v5's time-unit for lifetimes is 1 sec, while v4 uses 5 minutes,
+     * and gets weirder above (128 * 300) seconds.
+     */
+    principal->max_life = krb_time_to_life(0, entries.max_life);
+    if (k5life != NULL)
+	*k5life = entries.max_life;
+    /*
+     * This is weird, but the intent is that the expiration is the minimum
+     * of the principal expiration and key expiration
+     */
+    principal->exp_date = (unsigned long) 
+        entries.expiration && entries.pw_expiration ?
+        min(entries.expiration, entries.pw_expiration) :
+        (entries.pw_expiration ? entries.pw_expiration :
+        entries.expiration);
+/*    principal->mod_date = (unsigned long) entries.mod_date; */
+/* Set the master key version to 1. It's not really useful because all keys
+ * will be encrypted in the same master key version, and digging out the 
+ * actual key version will be harder than it's worth --proven */
+/*    principal->kdc_key_ver = entries.mkvno; */
+    principal->kdc_key_ver = 1;
+    principal->key_version = pkey->key_data_kvno;
+    /* We overload the attributes with the relevant v5 ones */
+    principal->attributes = 0;
+    if (isflagset(entries.attributes,  KRB5_KDB_REQUIRES_HW_AUTH) ||
+	isflagset(entries.attributes,  KRB5_KDB_REQUIRES_PRE_AUTH)) {
+          principal->attributes |= V4_KDB_REQUIRES_PREAUTH;
+    }
+    if (isflagset(entries.attributes,  KRB5_KDB_DISALLOW_ALL_TIX)) {
+          principal->attributes |= V4_KDB_DISALLOW_ALL_TIX;
+    }
+    if (issrv && isflagset(entries.attributes, KRB5_KDB_DISALLOW_SVR)) {
+	principal->attributes |= V4_KDB_DISALLOW_SVR;
+    }
+    if (isflagset(entries.attributes,  KRB5_KDB_REQUIRES_PWCHANGE)) {
+          principal->attributes |= V4_KDB_REQUIRES_PWCHANGE;
+    }
+
+    /* set up v4 format of each date's text: */
+    for ( date = &principal->exp_date, text = principal->exp_date_txt;
+	  toggle ^= 1;
+	  date = &principal->mod_date, text = principal->mod_date_txt) {
+	tp = localtime( (time_t *) date);
+	sprintf( text, "%4d-%02d-%02d",
+		 tp->tm_year > 1900 ? tp->tm_year : tp->tm_year + 1900,
+		 tp->tm_mon + 1, tp->tm_mday); /* January is 0, not 1 */
+    }
+    /*
+     * free the storage held by the v5 entry struct,
+     * which was allocated by krb5_db_get_principal().
+     * this routine clears the keyblock's contents for us.
+     */
+    krb5_db_free_principal(kdc_context, &entries, nprinc);
+    *more = (int) more5 || (nprinc > maxn);
+    return( nprinc);
+}
+
+static void str_length_check(char *str, int max_size)
+{
+	int	i;
+	char	*cp;
+
+	for (i=0, cp = str; i < max_size-1; i++, cp++) {
+		if (*cp == 0)
+			return;
+	}
+	*cp = 0;
+}
+
+void
+kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
+{
+    static KTEXT_ST rpkt_st;
+    KTEXT   rpkt = &rpkt_st;
+    static KTEXT_ST ciph_st;
+    KTEXT   ciph = &ciph_st;
+    static KTEXT_ST tk_st;
+    KTEXT   tk = &tk_st;
+    static KTEXT_ST auth_st;
+    KTEXT   auth = &auth_st;
+    AUTH_DAT ad_st;
+    AUTH_DAT *ad = &ad_st;
+
+
+    static struct in_addr client_host;
+    static int msg_byte_order;
+    static int swap_bytes;
+    static u_char k_flags;
+ /* char   *p_name, *instance; */
+    int     lifetime = 0;
+    int     i;
+    C_Block key;
+    Key_schedule key_s;
+    char   *ptr;
+
+    krb5_keyblock k5key;
+    krb5_kvno kvno;
+    krb5_deltat sk5life, ck5life;
+    KRB4_32 v4endtime, v4req_end;
+
+    k5key.contents = NULL;	/* in case we have to free it */
+
+    ciph->length = 0;
+
+    client_host = client->sin_addr;
+
+    /* eval macros and correct the byte order and alignment as needed */
+    req_version = pkt_version(pkt);	/* 1 byte, version */
+    req_msg_type = pkt_msg_type(pkt);	/* 1 byte, Kerberos msg type */
+
+    /* set these to point to something safe */
+    req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+
+    /* check if disabled, but we tell client */
+    if (kdc_v4 == KDC_V4_DISABLE) {
+	lt = klog(L_KRB_PERR,
+	"KRB will not handle v4 request from %s",
+		  inet_ntoa(client_host));
+	/* send an error reply */
+	req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+	kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt);
+	return;
+    }
+
+    /* check packet version */
+    if (req_version != KRB_PROT_VERSION) {
+	lt = klog(L_KRB_PERR,
+	"KRB prot version mismatch: KRB =%d request = %d",
+		  KRB_PROT_VERSION, req_version, 0);
+	/* send an error reply */
+	req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+	kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt);
+	return;
+    }
+    msg_byte_order = req_msg_type & 1;
+
+    swap_bytes = 0;
+    if (msg_byte_order != HOST_BYTE_ORDER) {
+	swap_bytes++;
+    }
+    klog(L_KRB_PINFO,
+	"Prot version: %d, Byte order: %d, Message type: %d",
+	 (int) req_version, msg_byte_order, req_msg_type);
+
+    switch (req_msg_type & ~1) {
+
+    case AUTH_MSG_KDC_REQUEST:
+	{
+	    int    req_life;	/* Requested liftime */
+	    unsigned int request_backdate =  0; /*How far to backdate
+						  in seconds.*/
+	    char   *service;	/* Service name */
+	    char   *instance;	/* Service instance */
+#ifdef notdef
+	    int     kerno;	/* Kerberos error number */
+#endif
+	    n_auth_req++;
+	    tk->length = 0;
+	    k_flags = 0;	/* various kerberos flags */
+
+
+	    /* set up and correct for byte order and alignment */
+	    req_name_ptr = (char *) pkt_a_name(pkt);
+	    str_length_check(req_name_ptr, ANAME_SZ);
+	    req_inst_ptr = (char *) pkt_a_inst(pkt);
+	    str_length_check(req_inst_ptr, INST_SZ);
+	    req_realm_ptr = (char *) pkt_a_realm(pkt);
+	    str_length_check(req_realm_ptr, REALM_SZ);
+	    memcpy(&req_time_ws, pkt_time_ws(pkt), sizeof(req_time_ws));
+	    /* time has to be diddled */
+	    if (swap_bytes) {
+		swap_u_long(req_time_ws);
+	    }
+	    ptr = (char *) pkt_time_ws(pkt) + 4;
+
+	    req_life = (*ptr++) & 0xff;
+
+	    service = ptr;
+	    str_length_check(service, SNAME_SZ);
+	    instance = ptr + strlen(service) + 1;
+	    str_length_check(instance, INST_SZ);
+
+	    rpkt = &rpkt_st;
+
+	    klog(L_INI_REQ,
+	    "Initial ticket request Host: %s User: \"%s\" \"%s\"",
+	       inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0);
+
+	    if ((i = check_princ(req_name_ptr, req_inst_ptr, 0,
+				 &a_name_data, &k5key, 0, &ck5life))) {
+		kerb_err_reply(client, pkt, i, "check_princ failed");
+		a_name_data.key_low = a_name_data.key_high = 0;
+		krb5_free_keyblock_contents(kdc_context, &k5key);
+		return;
+	    }
+	    /* don't use k5key for client */
+	    krb5_free_keyblock_contents(kdc_context, &k5key);
+	    tk->length = 0;	/* init */
+	    if (strcmp(service, "krbtgt"))
+		klog(L_NTGT_INTK,
+		    "INITIAL request from %s.%s for %s.%s", req_name_ptr,
+		    req_inst_ptr, service, instance, 0);
+	    /* this does all the checking */
+	    if ((i = check_princ(service, instance, lifetime,
+				 &s_name_data, &k5key, 1, &sk5life))) {
+		kerb_err_reply(client, pkt, i, "check_princ failed");
+		a_name_data.key_high = a_name_data.key_low = 0;
+		s_name_data.key_high = s_name_data.key_low = 0;
+		krb5_free_keyblock_contents(kdc_context, &k5key);
+		return;
+	    }
+	    /* Bound requested lifetime with service and user */
+	    v4req_end = krb_life_to_time(kerb_time.tv_sec, req_life);
+	    v4req_end = min(v4req_end, kerb_time.tv_sec + ck5life);
+	    v4req_end = min(v4req_end, kerb_time.tv_sec + sk5life);
+	    lifetime = krb_time_to_life(kerb_time.tv_sec, v4req_end);
+	    v4endtime = krb_life_to_time(kerb_time.tv_sec, lifetime);
+	    /*
+	     * Adjust issue time backwards if necessary, due to
+	     * roundup in krb_time_to_life().
+	     */
+	    if (v4endtime > v4req_end)
+		request_backdate = v4endtime - v4req_end;
+
+#ifdef NOENCRYPTION
+	    memset(session_key, 0, sizeof(C_Block));
+#else
+	    /* random session key */
+	    des_new_random_key(session_key);
+#endif
+
+	    /* unseal server's key from master key */
+	    memcpy( key,                &s_name_data.key_low,  4);
+	    memcpy( ((krb5_ui_4 *) key) + 1, &s_name_data.key_high, 4);
+
+	    s_name_data.key_low = s_name_data.key_high = 0;
+	    kdb_encrypt_key(key, key, master_key,
+			    master_key_schedule, DECRYPT);
+	    /* construct and seal the ticket */
+	    /* We always issue des tickets; the 3des tickets are a broken hack*/
+	    krb_create_ticket(tk, k_flags, a_name_data.name,
+			      a_name_data.instance, local_realm,
+			      client_host.s_addr, (char *) session_key,
+			      lifetime, kerb_time.tv_sec - request_backdate,
+			      s_name_data.name, s_name_data.instance,
+			      key);
+
+	    krb5_free_keyblock_contents(kdc_context, &k5key);
+	    memset(key, 0, sizeof(key));
+	    memset(key_s, 0, sizeof(key_s));
+
+	    /*
+	     * get the user's key, unseal it from the server's key, and
+	     * use it to seal the cipher 
+	     */
+
+	    /* a_name_data.key_low a_name_data.key_high */
+	    memcpy( key,                &a_name_data.key_low,  4);
+	    memcpy( ((krb5_ui_4 *) key) + 1, &a_name_data.key_high, 4);
+	    a_name_data.key_low= a_name_data.key_high = 0;
+
+	    /* unseal the a_name key from the master key */
+	    kdb_encrypt_key(key, key, master_key, 
+			    master_key_schedule, DECRYPT);
+
+	    create_ciph(ciph, session_key, s_name_data.name,
+			s_name_data.instance, local_realm, lifetime,
+		  s_name_data.key_version, tk, kerb_time.tv_sec, key);
+
+	    /* clear session key */
+	    memset(session_key, 0, sizeof(session_key));
+
+	    memset(key, 0, sizeof(key));
+
+
+
+	    /* always send a reply packet */
+	    rpkt = create_auth_reply(req_name_ptr, req_inst_ptr,
+		req_realm_ptr, req_time_ws, 0, a_name_data.exp_date,
+		a_name_data.key_version, ciph);
+	    krb4_sendto(f, (char *) rpkt->dat, rpkt->length, 0,
+		   (struct sockaddr *) client, S_AD_SZ);
+	    memset(&a_name_data, 0, sizeof(a_name_data));
+	    memset(&s_name_data, 0, sizeof(s_name_data));
+	    break;
+	}
+    case AUTH_MSG_APPL_REQUEST:
+	{
+	    krb5_ui_4  time_ws;	/* Workstation time */
+	    int    req_life;	/* Requested liftime */
+	    char   *service;	/* Service name */
+	    char   *instance;	/* Service instance */
+	    int     kerno = 0;	/* Kerberos error number */
+	    unsigned int request_backdate =  0; /*How far to backdate
+						  in seconds.*/
+	    char    tktrlm[REALM_SZ];
+
+	    n_appl_req++;
+	    tk->length = 0;
+	    k_flags = 0;	/* various kerberos flags */
+
+	    auth->mbz = 0;	/* pkt->mbz already zeroed */
+	    auth->length = 4 + strlen((char *)pkt->dat + 3);
+	    if (auth->length + 1 > MAX_KTXT_LEN) {
+		lt = klog(L_KRB_PERR,
+			  "APPL request with realm length too long from %s",
+			  inet_ntoa(client_host));
+		kerb_err_reply(client, pkt, RD_AP_INCON,
+			       "realm length too long");
+		return;
+	    }
+
+	    auth->length += (int) *(pkt->dat + auth->length) +
+		(int) *(pkt->dat + auth->length + 1) + 2;
+	    if (auth->length > MAX_KTXT_LEN) {
+		lt = klog(L_KRB_PERR,
+			  "APPL request with funky tkt or req_id length from %s",
+			  inet_ntoa(client_host));
+		kerb_err_reply(client, pkt, RD_AP_INCON,
+			       "funky tkt or req_id length");
+		return;
+	    }
+
+	    memcpy(auth->dat, pkt->dat, auth->length);
+
+	    strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
+	    tktrlm[REALM_SZ-1] = '\0';
+	    kvno = (krb5_kvno)auth->dat[2];
+	    if ((!allow_v4_crossrealm)&&strcmp(tktrlm, local_realm) != 0) {
+	      lt = klog(L_ERR_UNK,
+			"Cross realm ticket from %s denied by policy,", tktrlm);
+	      kerb_err_reply(client, pkt,
+			       KERB_ERR_PRINCIPAL_UNKNOWN, lt);
+		return;
+	    }
+	    if (set_tgtkey(tktrlm, kvno, 0)) {
+	      lt = klog(L_ERR_UNK,
+			  "FAILED set_tgtkey realm %s, kvno %d. Host: %s ",
+			  tktrlm, kvno, inet_ntoa(client_host));
+		/* no better error code */
+		kerb_err_reply(client, pkt,
+			       KERB_ERR_PRINCIPAL_UNKNOWN, lt);
+		return;
+	    }
+	    kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
+		ad, 0);
+	    if (kerno) {
+		if (set_tgtkey(tktrlm, kvno, 1)) {
+		    lt = klog(L_ERR_UNK,
+			      "FAILED 3des set_tgtkey realm %s, kvno %d. Host: %s ",
+			      tktrlm, kvno, inet_ntoa(client_host));
+		    /* no better error code */
+		    kerb_err_reply(client, pkt,
+				   KERB_ERR_PRINCIPAL_UNKNOWN, lt);
+		    return;
+		}
+		kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
+				   ad, 0);
+	    }
+
+	    if (kerno) {
+		klog(L_ERR_UNK, "FAILED krb_rd_req from %s: %s",
+		     inet_ntoa(client_host), krb_get_err_text(kerno));
+		req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+		kerb_err_reply(client, pkt, kerno, "krb_rd_req failed");
+		return;
+	    }
+	    ptr = (char *) pkt->dat + auth->length;
+
+	    memcpy(&time_ws, ptr, 4);
+	    ptr += 4;
+
+	    req_life = (*ptr++) & 0xff;
+
+	    service = ptr;
+	    str_length_check(service, SNAME_SZ);
+	    instance = ptr + strlen(service) + 1;
+	    str_length_check(instance, INST_SZ);
+
+	    klog(L_APPL_REQ, "APPL Request %s.%s@%s on %s for %s.%s",
+	     ad->pname, ad->pinst, ad->prealm,
+	     inet_ntoa(client_host), service, instance, 0);
+	    req_name_ptr = ad->pname;
+	    req_inst_ptr = ad->pinst;
+	    req_realm_ptr = ad->prealm;
+
+	    if (strcmp(ad->prealm, tktrlm)) {
+		kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN,
+		     "Can't hop realms");
+		return;
+	    }
+	    if (!strcmp(service, "changepw")) {
+		kerb_err_reply(client, pkt, KERB_ERR_PRINCIPAL_UNKNOWN,
+		     "Can't authorize password changed based on TGT");
+		return;
+	    }
+	    kerno = check_princ(service, instance, req_life,
+				&s_name_data, &k5key, 1, &sk5life);
+	    if (kerno) {
+		kerb_err_reply(client, pkt, kerno, "check_princ failed");
+		s_name_data.key_high = s_name_data.key_low = 0;
+		krb5_free_keyblock_contents(kdc_context, &k5key);
+		return;
+	    }
+	    /* Bound requested lifetime with service and user */
+	    v4endtime = krb_life_to_time((KRB4_32)ad->time_sec, ad->life);
+	    v4req_end = krb_life_to_time(kerb_time.tv_sec, req_life);
+	    v4req_end = min(v4endtime, v4req_end);
+	    v4req_end = min(v4req_end, kerb_time.tv_sec + sk5life);
+
+	    lifetime = krb_time_to_life(kerb_time.tv_sec, v4req_end);
+	    v4endtime = krb_life_to_time(kerb_time.tv_sec, lifetime);
+	    /*
+	     * Adjust issue time backwards if necessary, due to
+	     * roundup in krb_time_to_life().
+	     */
+	    if (v4endtime > v4req_end)
+		request_backdate = v4endtime - v4req_end;
+
+	    /* unseal server's key from master key */
+	    memcpy(key,                &s_name_data.key_low,  4);
+	    memcpy(((krb5_ui_4 *) key) + 1, &s_name_data.key_high, 4);
+	    s_name_data.key_low = s_name_data.key_high = 0;
+	    kdb_encrypt_key(key, key, master_key,
+			    master_key_schedule, DECRYPT);
+	    /* construct and seal the ticket */
+
+#ifdef NOENCRYPTION
+	    memset(session_key, 0, sizeof(C_Block));
+#else
+	    /* random session key */
+	    des_new_random_key(session_key);
+#endif
+
+	    /* ALways issue des tickets*/
+	    krb_create_ticket(tk, k_flags, ad->pname, ad->pinst,
+			      ad->prealm, client_host.s_addr,
+			      (char *) session_key, lifetime,
+			      kerb_time.tv_sec - request_backdate,
+			      s_name_data.name, s_name_data.instance,
+			      key);
+	    krb5_free_keyblock_contents(kdc_context, &k5key);
+	    memset(key, 0, sizeof(key));
+	    memset(key_s, 0, sizeof(key_s));
+
+	    create_ciph(ciph, session_key, service, instance,
+			local_realm,
+			lifetime, s_name_data.key_version, tk,
+			kerb_time.tv_sec, ad->session);
+
+	    /* clear session key */
+	    memset(session_key, 0, sizeof(session_key));
+
+	    memset(ad->session, 0, sizeof(ad->session));
+
+	    rpkt = create_auth_reply(ad->pname, ad->pinst,
+				     ad->prealm, time_ws,
+				     0, 0, 0, ciph);
+	    krb4_sendto(f, (char *) rpkt->dat, rpkt->length, 0,
+		   (struct sockaddr *) client, S_AD_SZ);
+	    memset(&s_name_data, 0, sizeof(s_name_data));
+	    break;
+	}
+
+
+#ifdef notdef_DIE
+    case AUTH_MSG_DIE:
+	{
+	    lt = klog(L_DEATH_REQ,
+	        "Host: %s User: \"%s\" \"%s\" Kerberos killed",
+	        inet_ntoa(client_host), req_name_ptr, req_inst_ptr, 0);
+	    exit(0);
+	}
+#endif /* notdef_DIE */
+
+    default:
+	{
+	    lt = klog(L_KRB_PERR,
+		"Unknown message type: %d from %s port %u",
+		req_msg_type, inet_ntoa(client_host),
+		ntohs(client->sin_port));
+	    break;
+	}
+    }
+}
+
+
+
+/*
+ * kerb_er_reply creates an error reply packet and sends it to the
+ * client. 
+ */
+
+void
+kerb_err_reply(struct sockaddr_in *client, KTEXT pkt, long int err, char *string)
+{
+    static KTEXT_ST e_pkt_st;
+    KTEXT   e_pkt = &e_pkt_st;
+    static char e_msg[128];
+
+    strcpy(e_msg, "\nKerberos error -- ");
+    strncat(e_msg, string, sizeof(e_msg) - 1 - 19);
+    cr_err_reply(e_pkt, req_name_ptr, req_inst_ptr, req_realm_ptr,
+		 req_time_ws, err, e_msg);
+    krb4_sendto(f, (char *) e_pkt->dat, e_pkt->length, 0,
+	   (struct sockaddr *) client, S_AD_SZ);
+
+}
+
+static int
+check_princ(char *p_name, char *instance, int lifetime, Principal *p,
+	    krb5_keyblock *k5key, int issrv, krb5_deltat *k5life)
+{
+    static int n;
+    static int more;
+ /* long trans; */
+
+    n = kerb_get_principal(p_name, instance, p, 1, &more, k5key, 0,
+			   issrv, k5life);
+    klog(L_ALL_REQ,
+	 "Principal: \"%s\", Instance: \"%s\" Lifetime = %d n = %d",
+	 p_name, instance, lifetime, n, 0);
+    
+    if (n < 0) {
+	lt = klog(L_KRB_PERR, "Database unavailable!");
+	p->key_high = p->key_low = 0;    
+	hang();
+    }
+    
+    /*
+     * if more than one p_name, pick one, randomly create a session key,
+     * compute maximum lifetime, lookup authorizations if applicable,
+     * and stuff into cipher. 
+     */
+    if (n == 0) {
+	/* service unknown, log error, skip to next request */
+	lt = klog(L_ERR_UNK, "UNKNOWN \"%s\" \"%s\"", p_name,
+	    instance, 0);
+	return KERB_ERR_PRINCIPAL_UNKNOWN;
+    }
+    if (more) {
+	/* not unique, log error */
+	lt = klog(L_ERR_NUN, "Principal NOT UNIQUE \"%s\" \"%s\"",
+		  p_name, instance, 0);
+	return KERB_ERR_PRINCIPAL_NOT_UNIQUE;
+    }
+
+    /*
+     * Check our V5 stuff first.
+     */
+
+    /*
+     * Does the principal have REQUIRES_PWCHANGE set?
+     */
+    if (isflagset(p->attributes, V4_KDB_REQUIRES_PWCHANGE)) {
+	lt = klog(L_ERR_SEXP, "V5 REQUIRES_PWCHANGE set "
+		  "\"%s\" \"%s\"", p_name, instance);
+	return KERB_ERR_NAME_EXP;
+    }
+
+    /*
+     * Does the principal have DISALLOW_ALL_TIX set?
+     */
+    if (isflagset(p->attributes, V4_KDB_DISALLOW_ALL_TIX)) {
+	lt = klog(L_ERR_SEXP, "V5 DISALLOW_ALL_TIX set: "
+		  "\"%s\" \"%s\"", p_name, instance);
+	/* Not sure of a better error to return */
+	return KERB_ERR_NAME_EXP;
+    }
+
+    if (isflagset(p->attributes, V4_KDB_DISALLOW_SVR)) {
+	lt = klog(L_ERR_SEXP, "V5 DISALLOW_SVR set: "
+		  "\"%s\" \"%s\"", p_name, instance);
+	/* Not sure of a better error to return */
+	return KERB_ERR_NAME_EXP;
+    }
+
+    /*
+     * Does the principal require preauthentication?
+     */
+    if ((kdc_v4 == KDC_V4_NOPREAUTH) &&
+	isflagset(p->attributes, V4_KDB_REQUIRES_PREAUTH)) {
+        lt = klog(L_ERR_SEXP, "V5 REQUIRES_PREAUTH set: "
+		  "\"%s\" \"%s\"", p_name, instance);
+	/* Not sure of a better error to return */
+	return KERB_ERR_AUTH_EXP;
+/*	return KERB_ERR_NAME_EXP;*/
+    }
+
+    /* If the user's key is null, we want to return an error */
+    if (k5key->contents != NULL && K4KDC_ENCTYPE_OK(k5key->enctype)) {
+	if ((p->key_low == 0) && (p->key_high == 0)) {
+	    /* User has a null key */
+	    lt = klog(L_ERR_NKY, "Null key \"%s\" \"%s\"", p_name,
+		      instance, 0);
+	    return KERB_ERR_NULL_KEY;
+	}
+    }
+    /* make sure the service hasn't expired */
+    if (((u_long) p->exp_date != 0)&&
+	((u_long) p->exp_date <(u_long) kerb_time.tv_sec)) {
+	/* service did expire, log it */
+	char timestr[40];
+	struct tm *tm;
+	time_t t = p->exp_date;
+
+	tm = localtime(&t);
+	if (!strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm))
+	    timestr[0] = '\0';
+	lt = klog(L_ERR_SEXP,
+		  "EXPIRED \"%s\" \"%s\"  %s", p->name, p->instance, timestr);
+	return KERB_ERR_NAME_EXP;
+    }
+    /* ok is zero */
+    return 0;
+}
+
+
+/* Set the key for krb_rd_req so we can check tgt */
+static int
+set_tgtkey(char *r, krb5_kvno kvno, krb5_boolean use_3des)
+{
+    int     n;
+    static char lastrealm[REALM_SZ] = "";
+    static int last_kvno = 0;
+    static krb5_boolean last_use_3des = 0;
+    static int more;
+    Principal p_st;
+    Principal *p = &p_st;
+    C_Block key;
+    krb5_keyblock k5key;
+
+    k5key.contents = NULL;
+    if (!strcmp(lastrealm, r) && last_kvno == kvno && last_use_3des == use_3des)
+	return (KSUCCESS);
+
+/*  log("Getting key for %s", r); */
+
+    n = kerb_get_principal("krbtgt", r, p, 1, &more, &k5key, kvno, 1, NULL);
+    if (n == 0)
+	return (KFAILURE);
+
+    if (isflagset(p->attributes, V4_KDB_DISALLOW_ALL_TIX)) {
+	lt = klog(L_ERR_SEXP,
+		  "V5 DISALLOW_ALL_TIX set: \"krbtgt\" \"%s\"", r);
+	krb5_free_keyblock_contents(kdc_context, &k5key);
+	return KFAILURE;
+    }
+
+    if (isflagset(p->attributes, V4_KDB_DISALLOW_SVR)) {
+	lt = klog(L_ERR_SEXP, "V5 DISALLOW_SVR set: \"krbtgt\" \"%s\"", r);
+	krb5_free_keyblock_contents(kdc_context, &k5key);
+	return KFAILURE;
+    }
+
+    if (use_3des&&!K4KDC_ENCTYPE_OK(k5key.enctype)) {
+	krb_set_key_krb5(kdc_context, &k5key);
+	strncpy(lastrealm, r, sizeof(lastrealm) - 1);
+	lastrealm[sizeof(lastrealm) - 1] = '\0';
+	last_kvno = kvno;
+	last_use_3des = use_3des;
+    } else {
+	/* unseal tgt key from master key */
+	memcpy(key,                &p->key_low,  4);
+	memcpy(((krb5_ui_4 *) key) + 1, &p->key_high, 4);
+	kdb_encrypt_key(key, key, master_key,
+			master_key_schedule, DECRYPT);
+	krb_set_key((char *) key, 0);
+	strncpy(lastrealm, r, sizeof(lastrealm) - 1);
+	lastrealm[sizeof(lastrealm) - 1] = '\0';
+	last_kvno = kvno;
+    }
+    krb5_free_keyblock_contents(kdc_context, &k5key);
+    return (KSUCCESS);
+}
+
+#else	/* KRB5_KRB4_COMPAT */
+#include "k5-int.h"
+#endif /* KRB5_KRB4_COMPAT */
diff --git a/mechglue/src/kdc/krb5kdc.M b/mechglue/src/kdc/krb5kdc.M
new file mode 100644
index 000000000..d6f69b645
--- /dev/null
+++ b/mechglue/src/kdc/krb5kdc.M
@@ -0,0 +1,154 @@
+.\" kdc/krb5kdc.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\"
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH KRB5KDC 8
+.SH NAME
+krb5kdc \- Kerberos V5 KDC
+.SH SYNOPSIS
+.B krb5kdc
+[
+.B \-d
+.I dbname
+] [
+.B \-k
+.I keytype
+] [
+.B \-M
+.I mkeyname
+] [
+.B \-p
+.I portnum
+] [
+.B \-m
+] [
+.B \-r
+.I realm
+] [
+.B \-4
+.I v4mode
+] [
+.B \-n
+]
+.br
+.SH DESCRIPTION
+.I krb5kdc
+is the Kerberos version 5 Authentication Service and Key Distribution
+Center (AS/KDC).
+.PP
+The
+.B \-r
+.I realm
+option specifies the realm for which the server should provide service;
+by default the realm returned by
+.IR krb5_default_local_realm (3)
+is used.
+.PP
+The
+.B \-d
+.I dbname
+option specifies the name under which the principal database can be found; by
+default the database is in DEFAULT_DBM_FILE.
+.PP
+The
+.B \-k
+.I keytype
+option specifies the key type of the master key in the database; the default
+is KEYTYPE_DES.
+.PP
+The
+.B \-M
+.I mkeyname
+option specifies the principal name for the master key in the database;
+the default is KRB5_KDB_M_NAME (usually "K/M" in the KDC's realm).
+.PP
+The
+.B \-p
+.I portnum
+option specifies the default UDP port number which the KDC should listen on for
+Kerberos version 5 requests.  This value is used when no port is specified in
+the KDC profile and when no port is specified in the Kerberos configuration
+file.
+If no value is available, then the value in /etc/services for service
+"kerberos" is used.
+.PP
+The
+.B \-m
+option specifies that the master database password should be fetched
+from the keyboard rather than from a file on disk.
+.PP
+The
+.B \-4
+option specifies how the KDC responds to kerberos IV requests for
+tickets.  The command line option overrides the value in the KDC
+profile.  The possible values are 
+.I none,
+.I disable,
+.I full
+or
+.I nopreauth.
+These instruct the KDC to not respond to V4 packets, to
+respond with a version skew error, to issue tickets for all database
+entries, and to issue tickets for all but preauthentication required
+database entries respectively. The default behaviour is as if 
+.I none
+was specified.
+.PP
+The
+.B \-n
+option specifies that the KDC does not put itself in the background
+and does not disassociate itself from the terminal.  In normal
+operation, you should always allow the KDC to place itself in
+the background.
+.PP
+The KDC may service requests for multiple realms (maximum 32 realms).  The
+realms are listed on the command line.  Per-realm options that can be
+specified on the command line pertain for each realm that follows it and are
+superceded by subsequent definitions of the same option.  For example, 
+.PP
+.B krb5kdc
+.B \-p
+.I 2001
+.B \-r
+.I REALM1
+.B \-p
+.I 2002
+.B \-r
+.I REALM2
+.B \-r
+.I REALM3
+.PP
+specifies that the KDC listen on port 2001 for REALM1 and on port 2002 for
+REALM2 and REALM3.  Additionally, per-realm parameters may be specified in the
+.I kdc.conf
+file.  The location of this file may be specified by the
+.I KRB5_KDC_PROFILE
+environment variable.  Parameters specified in this file take precedence over
+options specified on the command line.  See the
+.I kdc.conf(5)
+description for further details.
+.SH SEE ALSO
+krb5(3), kdb5_util(8), kdc.conf(5)
+.SH BUGS
+
+It should fork and go into the background when it finishes reading the
+master password from the terminal.
diff --git a/mechglue/src/kdc/main.c b/mechglue/src/kdc/main.c
new file mode 100644
index 000000000..c5ecdec7a
--- /dev/null
+++ b/mechglue/src/kdc/main.c
@@ -0,0 +1,755 @@
+/*
+ * kdc/main.c
+ *
+ * Copyright 1990,2001 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Main procedure body for the KDC server process.
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "adm.h"
+#include "adm_proto.h"
+#include "kdc_util.h"
+#include "extern.h"
+#include "kdc5_err.h"
+#include "kdb_kt.h"
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef KRB5_KRB4_COMPAT
+#include <des.h>
+#endif
+
+#if defined(NEED_DAEMON_PROTO)
+extern int daemon(int, int);
+#endif
+
+void usage (char *);
+
+krb5_sigtype request_exit (int);
+krb5_sigtype request_hup  (int);
+
+void setup_signal_handlers (void);
+
+krb5_error_code setup_sam (void);
+
+void initialize_realms (krb5_context, int, char **);
+
+void finish_realms (char *);
+
+static int nofork = 0;
+static int rkey_init_done = 0;
+
+#ifdef POSIX_SIGNALS
+static struct sigaction s_action;
+#endif /* POSIX_SIGNALS */
+
+#define	KRB5_KDC_MAX_REALMS	32
+
+/*
+ * Find the realm entry for a given realm.
+ */
+kdc_realm_t *
+find_realm_data(char *rname, krb5_ui_4 rsize)
+{
+    int i;
+    for (i=0; i<kdc_numrealms; i++) {
+	if ((rsize == strlen(kdc_realmlist[i]->realm_name)) &&
+	    !strncmp(rname, kdc_realmlist[i]->realm_name, rsize))
+	    return(kdc_realmlist[i]);
+    }
+    return((kdc_realm_t *) NULL);
+}
+
+krb5_error_code
+setup_server_realm(krb5_principal sprinc)
+{
+    krb5_error_code	kret;
+    kdc_realm_t		*newrealm;
+
+    kret = 0;
+    if (kdc_numrealms > 1) {
+	if (!(newrealm = find_realm_data(sprinc->realm.data,
+					 (krb5_ui_4) sprinc->realm.length)))
+	    kret = ENOENT;
+	else
+	    kdc_active_realm = newrealm;
+    }
+    else
+	kdc_active_realm = kdc_realmlist[0];
+    return(kret);
+}
+
+static void
+finish_realm(kdc_realm_t *rdp)
+{
+    if (rdp->realm_dbname)
+	free(rdp->realm_dbname);
+    if (rdp->realm_mpname)
+	free(rdp->realm_mpname);
+    if (rdp->realm_stash)
+	free(rdp->realm_stash);
+    if (rdp->realm_ports)
+	free(rdp->realm_ports);
+    if (rdp->realm_tcp_ports)
+	free(rdp->realm_tcp_ports);
+    if (rdp->realm_keytab)
+	krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
+    if (rdp->realm_context) {
+	if (rdp->realm_mprinc)
+	    krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
+	if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
+	    memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
+	    free(rdp->realm_mkey.contents);
+	}
+	krb5_db_fini(rdp->realm_context);
+	if (rdp->realm_tgsprinc)
+	    krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
+	krb5_free_context(rdp->realm_context);
+    }
+    memset((char *) rdp, 0, sizeof(*rdp));
+    free(rdp);
+}
+
+/*
+ * Initialize a realm control structure from the alternate profile or from
+ * the specified defaults.
+ *
+ * After we're complete here, the essence of the realm is embodied in the
+ * realm data and we should be all set to begin operation for that realm.
+ */
+static krb5_error_code
+init_realm(char *progname, kdc_realm_t *rdp, char *realm, 
+	   char *def_mpname, krb5_enctype def_enctype, char *def_udp_ports,
+	   char *def_tcp_ports, krb5_boolean def_manual, char **db_args)
+{
+    krb5_error_code	kret;
+    krb5_boolean	manual;
+    krb5_realm_params	*rparams;
+
+    memset((char *) rdp, 0, sizeof(kdc_realm_t));
+    if (!realm) {
+	kret = EINVAL;
+	goto whoops;
+    }
+	
+    rdp->realm_name = realm;
+    kret = krb5_init_context(&rdp->realm_context);
+    if (kret) {
+	com_err(progname, kret, "while getting context for realm %s",
+		realm);
+	goto whoops;
+    }
+
+    kret = krb5_read_realm_params(rdp->realm_context, rdp->realm_name,
+				  (char *) NULL, (char *) NULL, &rparams);
+    if (kret) {
+	com_err(progname, kret, "while reading realm parameters");
+	goto whoops;
+    }
+    
+    /* Handle profile file name */
+    if (rparams && rparams->realm_profile)
+	rdp->realm_profile = strdup(rparams->realm_profile);
+
+    /* Handle master key name */
+    if (rparams && rparams->realm_mkey_name)
+	rdp->realm_mpname = strdup(rparams->realm_mkey_name);
+    else
+	rdp->realm_mpname = (def_mpname) ? strdup(def_mpname) :
+	    strdup(KRB5_KDB_M_NAME);
+
+    /* Handle KDC ports */
+    if (rparams && rparams->realm_kdc_ports)
+	rdp->realm_ports = strdup(rparams->realm_kdc_ports);
+    else
+	rdp->realm_ports = strdup(def_udp_ports);
+    if (rparams && rparams->realm_kdc_tcp_ports)
+	rdp->realm_tcp_ports = strdup(rparams->realm_kdc_tcp_ports);
+    else
+	rdp->realm_tcp_ports = strdup(def_tcp_ports);
+
+    /* Handle stash file */
+    if (rparams && rparams->realm_stash_file) {
+	rdp->realm_stash = strdup(rparams->realm_stash_file);
+	manual = FALSE;
+    } else
+	manual = def_manual;
+
+    /* Handle master key type */
+    if (rparams && rparams->realm_enctype_valid)
+	rdp->realm_mkey.enctype = (krb5_enctype) rparams->realm_enctype;
+    else
+	rdp->realm_mkey.enctype = manual ? def_enctype : ENCTYPE_UNKNOWN;
+
+    /* Handle reject-bad-transit flag */
+    if (rparams && rparams->realm_reject_bad_transit_valid)
+	rdp->realm_reject_bad_transit = rparams->realm_reject_bad_transit;
+    else
+	rdp->realm_reject_bad_transit = 1;
+
+    /* Handle ticket maximum life */
+    rdp->realm_maxlife = (rparams && rparams->realm_max_life_valid) ?
+	rparams->realm_max_life : KRB5_KDB_MAX_LIFE;
+
+    /* Handle ticket renewable maximum life */
+    rdp->realm_maxrlife = (rparams && rparams->realm_max_rlife_valid) ?
+	rparams->realm_max_rlife : KRB5_KDB_MAX_RLIFE;
+
+    if (rparams)
+	krb5_free_realm_params(rdp->realm_context, rparams);
+
+    /*
+     * We've got our parameters, now go and setup our realm context.
+     */
+
+    /* Set the default realm of this context */
+    if ((kret = krb5_set_default_realm(rdp->realm_context, realm))) {
+	com_err(progname, kret, "while setting default realm to %s",
+		realm);
+	goto whoops;
+    }
+
+    /* first open the database  before doing anything */
+#ifdef KRBCONF_KDC_MODIFIES_KDB    
+    if ((kret = krb5_db_open(rdp->realm_context, db_args, KRB5_KDB_OPEN_RW))) {
+#else
+    if ((kret = krb5_db_open(rdp->realm_context, db_args, KRB5_KDB_OPEN_RO))) {
+#endif
+	com_err(progname, kret,
+		"while initializing database for realm %s", realm);
+	goto whoops;
+    }
+
+    /* Assemble and parse the master key name */
+    if ((kret = krb5_db_setup_mkey_name(rdp->realm_context, rdp->realm_mpname,
+					rdp->realm_name, (char **) NULL,
+					&rdp->realm_mprinc))) {
+	com_err(progname, kret,
+		"while setting up master key name %s for realm %s",
+		rdp->realm_mpname, realm);
+	goto whoops;
+    }
+
+    /*
+     * Get the master key.
+     */
+    if ((kret = krb5_db_fetch_mkey(rdp->realm_context, rdp->realm_mprinc,
+				   rdp->realm_mkey.enctype, manual,
+				   FALSE, rdp->realm_stash,
+				   0, &rdp->realm_mkey))) {
+	com_err(progname, kret,
+		"while fetching master key %s for realm %s",
+		rdp->realm_mpname, realm);
+	goto whoops;
+    }
+
+    /* Verify the master key */
+    if ((kret = krb5_db_verify_master_key(rdp->realm_context,
+					  rdp->realm_mprinc,
+					  &rdp->realm_mkey))) {
+	com_err(progname, kret,
+		"while verifying master key for realm %s", realm);
+	goto whoops;
+    }
+
+    if ((kret = krb5_db_set_mkey(rdp->realm_context, &rdp->realm_mkey))) {
+	com_err(progname, kret,
+		"while setting master key for realm %s", realm);
+	goto whoops;
+    }
+
+    /* Set up the keytab */
+    if ((kret = krb5_ktkdb_resolve(rdp->realm_context, NULL,
+				   &rdp->realm_keytab))) {
+	com_err(progname, kret,
+		"while resolving kdb keytab for realm %s", realm);
+	goto whoops;
+    }
+
+    /* Preformat the TGS name */
+    if ((kret = krb5_build_principal(rdp->realm_context, &rdp->realm_tgsprinc,
+				     strlen(realm), realm, KRB5_TGS_NAME,
+				     realm, (char *) NULL))) {
+	com_err(progname, kret,
+		"while building TGS name for realm %s", realm);
+	goto whoops;
+    }
+
+    if (!rkey_init_done) {
+	krb5_data seed;
+#ifdef KRB5_KRB4_COMPAT
+	krb5_keyblock temp_key;
+#endif
+	/*
+	 * If all that worked, then initialize the random key
+	 * generators.
+	 */
+
+	seed.length = rdp->realm_mkey.length;
+	seed.data = rdp->realm_mkey.contents;
+
+	if ((kret = krb5_c_random_add_entropy(rdp->realm_context,
+					     KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed)))
+	    goto whoops;
+
+#ifdef KRB5_KRB4_COMPAT
+	if ((kret = krb5_c_make_random_key(rdp->realm_context,
+					   ENCTYPE_DES_CBC_CRC, &temp_key))) {
+	    com_err(progname, kret,
+		    "while initializing V4 random key generator");
+	    goto whoops;
+	}
+
+	(void) des_init_random_number_generator(temp_key.contents);
+	krb5_free_keyblock_contents(rdp->realm_context, &temp_key);
+#endif
+	rkey_init_done = 1;
+    }
+ whoops:
+    /*
+     * If we choked, then clean up any dirt we may have dropped on the floor.
+     */
+    if (kret) {
+        
+	finish_realm(rdp);
+    }
+    return(kret);
+}
+
+krb5_sigtype
+request_exit(int signo)
+{
+    signal_requests_exit = 1;
+
+#ifdef POSIX_SIGTYPE
+    return;
+#else
+    return(0);
+#endif
+}
+
+krb5_sigtype
+request_hup(int signo)
+{
+    signal_requests_hup = 1;
+
+#ifdef POSIX_SIGTYPE
+    return;
+#else
+    return(0);
+#endif
+}
+
+void
+setup_signal_handlers(void)
+{
+#ifdef POSIX_SIGNALS
+    (void) sigemptyset(&s_action.sa_mask);
+    s_action.sa_flags = 0;
+    s_action.sa_handler = request_exit;
+    (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
+    (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
+    s_action.sa_handler = request_hup;
+    (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
+#else  /* POSIX_SIGNALS */
+    signal(SIGINT, request_exit);
+    signal(SIGTERM, request_exit);
+    signal(SIGHUP, request_hup);
+#endif /* POSIX_SIGNALS */
+
+    return;
+}
+
+krb5_error_code
+setup_sam(void)
+{
+    return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key);
+}
+
+void
+usage(char *name)
+{
+    fprintf(stderr, "usage: %s [-x db_args]* [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-4 v4mode] [-X] [-n]\n"
+	    "\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n"
+	    "\t\t\tLook at each database documentation for supported arguments\n",
+	    name);
+    return;
+}
+
+void
+initialize_realms(krb5_context kcontext, int argc, char **argv)
+{
+    int 		c;
+    char		*db_name = (char *) NULL;
+    char		*mkey_name = (char *) NULL;
+    char		*rcname = KDCRCACHE;
+    char		*lrealm;
+    krb5_error_code	retval;
+    krb5_enctype	menctype = ENCTYPE_UNKNOWN;
+    kdc_realm_t		*rdatap;
+    krb5_boolean	manual = FALSE;
+    char		*default_udp_ports = 0;
+    char		*default_tcp_ports = 0;
+    krb5_pointer	aprof;
+    const char		*hierarchy[3];
+    char               **db_args      = NULL;
+    int                  db_args_size = 0;
+
+#ifdef KRB5_KRB4_COMPAT
+    char                *v4mode = 0;
+#endif
+    extern char *optarg;
+
+    if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) {
+	hierarchy[0] = "kdcdefaults";
+	hierarchy[1] = "kdc_ports";
+	hierarchy[2] = (char *) NULL;
+	if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_udp_ports))
+	    default_udp_ports = 0;
+	hierarchy[1] = "kdc_tcp_ports";
+	if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_tcp_ports))
+	    default_tcp_ports = 0;
+#ifdef KRB5_KRB4_COMPAT
+	hierarchy[1] = "v4_mode";
+	if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &v4mode))
+	    v4mode = 0;
+#endif
+	/* aprof_init can return 0 with aprof == NULL */
+	if (aprof)
+	     krb5_aprof_finish(aprof);
+    }
+    if (default_udp_ports == 0)
+	default_udp_ports = strdup(DEFAULT_KDC_UDP_PORTLIST);
+    if (default_tcp_ports == 0)
+	default_tcp_ports = strdup(DEFAULT_KDC_TCP_PORTLIST);
+    /*
+     * Loop through the option list.  Each time we encounter a realm name,
+     * use the previously scanned options to fill in for defaults.
+     */
+    while ((c = getopt(argc, argv, "x:r:d:mM:k:R:e:p:s:n4:X3")) != -1) {
+	switch(c) {
+	case 'x':
+	    db_args_size++;
+	    {
+		char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
+		if( temp == NULL )
+		{
+		    fprintf(stderr,"%s: KDC cannot initialize. Not enough memory\n",
+			    argv[0]);
+		    exit(1);
+		}
+
+		db_args = temp;
+	    }
+	    db_args[db_args_size-1] = optarg;
+	    db_args[db_args_size]   = NULL;
+	  break;
+
+	case 'r':			/* realm name for db */
+	    if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
+		if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
+		    if ((retval = init_realm(argv[0], rdatap, optarg, 
+					     mkey_name, menctype,
+					     default_udp_ports,
+					     default_tcp_ports, manual, db_args))) {
+			fprintf(stderr,"%s: cannot initialize realm %s - see log file for details\n",
+				argv[0], optarg);
+			exit(1);
+		    }
+		    kdc_realmlist[kdc_numrealms] = rdatap;
+		    kdc_numrealms++;
+		    free(db_args), db_args=NULL, db_args_size = 0;
+		}
+		else
+		{
+			fprintf(stderr,"%s: cannot initialize realm %s. Not enough memory\n",
+				argv[0], optarg);
+			exit(1);
+		}
+	    }
+	    break;
+	case 'd':			/* pathname for db */
+	    /* now db_name is not a seperate argument. It has to be passed as part of the db_args */
+	    if( db_name == NULL )
+	    {
+		db_name = malloc(1025);
+		if( db_name == NULL )
+		{
+			fprintf(stderr,"%s: KDC cannot initialize. Not enough memory\n",
+				argv[0] );
+			exit(1);
+		}
+
+		sprintf( db_name, "dbname=%s", optarg);
+	    }
+
+	    db_args_size++;
+	    {
+		char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
+		if( temp == NULL )
+		{
+		    fprintf(stderr,"%s: KDC cannot initialize. Not enough memory\n",
+			    argv[0]);
+		    exit(1);
+		}
+
+		db_args = temp;
+	    }
+	    db_args[db_args_size-1] = db_name;
+	    db_args[db_args_size]   = NULL;
+	    break;
+	case 'm':			/* manual type-in of master key */
+	    manual = TRUE;
+	    if (menctype == ENCTYPE_UNKNOWN)
+		menctype = ENCTYPE_DES_CBC_CRC;
+	    break;
+	case 'M':			/* master key name in DB */
+	    mkey_name = optarg;
+	    break;
+	case 'n':
+	    nofork++;			/* don't detach from terminal */
+	    break;
+	case 'k':			/* enctype for master key */
+	    if (krb5_string_to_enctype(optarg, &menctype))
+		com_err(argv[0], 0, "invalid enctype %s", optarg);
+	    break;
+	case 'R':
+	    rcname = optarg;
+	    break;
+	case 'p':
+	    if (default_udp_ports)
+		free(default_udp_ports);
+	    default_udp_ports = strdup(optarg);
+#if 0 /* not yet */
+	    if (default_tcp_ports)
+		free(default_tcp_ports);
+	    default_tcp_ports = strdup(optarg);
+#endif
+	    break;
+	case '4':
+#ifdef KRB5_KRB4_COMPAT
+	    if (v4mode)
+		free(v4mode);
+	    v4mode = strdup(optarg);
+#endif
+	    break;
+	case 'X':
+#ifdef KRB5_KRB4_COMPAT
+		enable_v4_crossrealm(argv[0]);
+#endif
+		break;
+	case '?':
+	default:
+	    usage(argv[0]);
+	    exit(1);
+	}
+    }
+
+#ifdef KRB5_KRB4_COMPAT
+    /*
+     * Setup the v4 mode 
+     */
+    process_v4_mode(argv[0], v4mode);
+#endif
+
+    /*
+     * Check to see if we processed any realms.
+     */
+    if (kdc_numrealms == 0) {
+	/* no realm specified, use default realm */
+	if ((retval = krb5_get_default_realm(kcontext, &lrealm))) {
+	    com_err(argv[0], retval,
+		    "while attempting to retrieve default realm");
+	    fprintf (stderr, "%s: %s, attempting to retrieve default realm\n",
+		     argv[0], error_message (retval));
+	    exit(1);
+	}
+	if ((rdatap = (kdc_realm_t *) malloc(sizeof(kdc_realm_t)))) {
+	    if ((retval = init_realm(argv[0], rdatap, lrealm, 
+				     mkey_name, menctype, default_udp_ports,
+				     default_tcp_ports, manual, db_args))) {
+		fprintf(stderr,"%s: cannot initialize realm %s - see log file for details\n",
+			argv[0], lrealm);
+		exit(1);
+	    }
+	    kdc_realmlist[0] = rdatap;
+	    kdc_numrealms++;
+	}
+    }
+
+#ifdef USE_RCACHE
+    /*
+     * Now handle the replay cache.
+     */
+    if ((retval = kdc_initialize_rcache(kcontext, rcname))) {
+	com_err(argv[0], retval, "while initializing KDC replay cache '%s'",
+		rcname);
+	exit(1);
+    }
+#endif
+
+    /* Ensure that this is set for our first request. */
+    kdc_active_realm = kdc_realmlist[0];
+    if (default_udp_ports)
+	free(default_udp_ports);
+    if (default_tcp_ports)
+	free(default_tcp_ports);
+    if (db_args)
+	free(db_args);
+    if (db_name)
+	free(db_name);
+
+    return;
+}
+
+void
+finish_realms(char *prog)
+{
+    int i;
+
+    for (i = 0; i < kdc_numrealms; i++) {
+	finish_realm(kdc_realmlist[i]);
+	kdc_realmlist[i] = 0;
+    }
+}
+
+/*
+ outline:
+
+ process args & setup
+
+ initialize database access (fetch master key, open DB)
+
+ initialize network
+
+ loop:
+ 	listen for packet
+
+	determine packet type, dispatch to handling routine
+		(AS or TGS (or V4?))
+
+	reflect response
+
+	exit on signal
+
+ clean up secrets, close db
+
+ shut down network
+
+ exit
+ */
+
+int main(int argc, char **argv)
+{
+    krb5_error_code	retval;
+    krb5_context	kcontext;
+    int errout = 0;
+
+    if (strrchr(argv[0], '/'))
+	argv[0] = strrchr(argv[0], '/')+1;
+
+    if (!(kdc_realmlist = (kdc_realm_t **) malloc(sizeof(kdc_realm_t *) * 
+						  KRB5_KDC_MAX_REALMS))) {
+	fprintf(stderr, "%s: cannot get memory for realm list\n", argv[0]);
+	exit(1);
+    }
+    memset((char *) kdc_realmlist, 0,
+	   (size_t) (sizeof(kdc_realm_t *) * KRB5_KDC_MAX_REALMS));
+
+    /*
+     * A note about Kerberos contexts: This context, "kcontext", is used
+     * for the KDC operations, i.e. setup, network connection and error
+     * reporting.  The per-realm operations use the "realm_context"
+     * associated with each realm.
+     */
+    retval = krb5_init_context(&kcontext);
+    if (retval) {
+	    com_err(argv[0], retval, "while initializing krb5");
+	    exit(1);
+    }
+    krb5_klog_init(kcontext, "kdc", argv[0], 1);
+    /* N.B.: After this point, com_err sends output to the KDC log
+       file, and not to stderr.  */
+
+    initialize_kdc5_error_table();
+
+    /*
+     * Scan through the argument list
+     */
+    initialize_realms(kcontext, argc, argv);
+
+    setup_signal_handlers();
+
+    retval = setup_sam();
+    if (retval) {
+	com_err(argv[0], retval, "while initializing SAM");
+	finish_realms(argv[0]);
+	return 1;
+    }
+
+    if ((retval = setup_network(argv[0]))) {
+	com_err(argv[0], retval, "while initializing network");
+	finish_realms(argv[0]);
+	return 1;
+    }
+    if (!nofork && daemon(0, 0)) {
+	com_err(argv[0], errno, "while detaching from tty");
+	finish_realms(argv[0]);
+	return 1;
+    }
+    krb5_klog_syslog(LOG_INFO, "commencing operation");
+    if ((retval = listen_and_process(argv[0]))) {
+	com_err(argv[0], retval, "while processing network requests");
+	errout++;
+    }
+    if ((retval = closedown_network(argv[0]))) {
+	com_err(argv[0], retval, "while shutting down network");
+	errout++;
+    }
+    krb5_klog_syslog(LOG_INFO, "shutting down");
+    krb5_klog_close(kdc_context);
+    finish_realms(argv[0]);
+    if (kdc_realmlist) 
+      free(kdc_realmlist);
+#ifdef USE_RCACHE
+    (void) krb5_rc_close(kcontext, kdc_rcache);
+#endif
+#ifndef NOCACHE
+    kdc_free_lookaside(kcontext);
+#endif
+    krb5_free_context(kcontext);
+    return errout;
+}
+
+
+
+
diff --git a/mechglue/src/kdc/migration.doc b/mechglue/src/kdc/migration.doc
new file mode 100644
index 000000000..d3613ac0d
--- /dev/null
+++ b/mechglue/src/kdc/migration.doc
@@ -0,0 +1,59 @@
+This document describes the protocols & procedures necessary to allow
+a large krb4 site like MIT to migrate smoothly to krb5.
+
+The problem we have to solve is that v4 clients don't know about the v5
+string-to-key function, which incorporates the user's name, instance, and realm
+into his private key, along with his password.
+It happens that our solution also solves a related problem: the v5 str2key
+function prevents a site from changing its realm-name, as when the company gets
+bought by another.
+
+PROTOCOLS:
+
+The compatibilty kdc will mark v5-style entries with an attribute bit.
+
+the v5 get_in_tkt clients (kinit, login, etc) all will be able to perform
+v4 str2key; this will allow users with v4 passwords to gain v5 tickets.
+When a user's entry contains a v5-style password, and he uses v5 kinit,
+the kinit protocol will have the kdc send a cleartext realm-unique string
+(initially null) along with the (password+realm)-encrypted tgt.
+When such a user runs v4 kinit, he loses.
+
+Mapping the realm-name to a realm-id string happens in a kdc-configuration file,
+possibly in the first line of krb.conf .
+
+These things will not happen until we deploy a kpasswd that can replace
+v4-style passwords with v5-style ones.
+It would be nice to provide a "convert" flag, that allows you to upgrade
+without having to change your password's text.
+
+PROCEDURES:
+
+Initially, administrators should deploy the v5 kdc (with its built-in
+v4 compatibility), a v4 kadmin server, and a v5 kadmin server.
+The v5 kadmin server will at this time continue to use the v4 str2key function,
+so all of the passwords in the database will be v4 compatible.
+
+the compatibility versions of the get_in_tkt clients (kinit, login, etc)
+should be deployed when most of the campus' software can handle v5.
+When a v4 user runs v5 kinit, he gets v5 tickets unawares.
+Vice-versa, the user loses.
+
+The users are then weaned from v4 in three (two?) steps:
+   first, we change kpasswd to convert v4-style passwords to v5-style,
+   once the site converts most of its various clients and daemons to v5 krb.
+   the kdc now needs to be able to send a non-null realm-id string to kinit.
+
+   second, we turn off the v4 kadmin server (simultaneous with 1 or 3?).
+
+   third, but optionally, we turn off the v4-compatibility glue in the kdc.
+
+Every user who runs the converting kpasswd becomes unable to run v4 clients
+thereafter; we assume that a user who converts has continued access to
+other v5 clients. the conversion code can warn him.
+
+We continue to run the v4 kadmin because users of v4 kpasswd may not yet have
+ready access to v5 clients.
+
+Note that the database's conversion commences gradually with the deployment
+of the converting kpasswd, so this deployment doesn't have to be instantaneous.
diff --git a/mechglue/src/kdc/network.c b/mechglue/src/kdc/network.c
new file mode 100644
index 000000000..af5e7d036
--- /dev/null
+++ b/mechglue/src/kdc/network.c
@@ -0,0 +1,1088 @@
+/*
+ * kdc/network.c
+ *
+ * Copyright 1990,2000 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Network code for Kerberos v5 KDC.
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "kdc_util.h"
+#include "extern.h"
+#include "kdc5_err.h"
+#include "adm_proto.h"
+#include <sys/ioctl.h>
+#include <syslog.h>
+
+#include <stddef.h>
+#include <ctype.h>
+#include "port-sockets.h"
+#include "socket-utils.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+/* for SIOCGIFCONF, etc. */
+#include <sys/sockio.h>
+#endif
+#include <sys/time.h>
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <arpa/inet.h>
+
+#ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>		/* FIONBIO */
+#endif
+
+#include "fake-addrinfo.h"
+
+/* Misc utility routines.  */
+static void
+set_sa_port(struct sockaddr *addr, int port)
+{
+    switch (addr->sa_family) {
+    case AF_INET:
+	sa2sin(addr)->sin_port = port;
+	break;
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+	sa2sin6(addr)->sin6_port = port;
+	break;
+#endif
+    default:
+	break;
+    }
+}
+
+static int ipv6_enabled()
+{
+#ifdef KRB5_USE_INET6
+    static int result = -1;
+    if (result == -1) {
+	int s;
+	s = socket(AF_INET6, SOCK_STREAM, 0);
+	if (s >= 0) {
+	    result = 1;
+	    close(s);
+	} else
+	    result = 0;
+    }
+    return result;
+#else
+    return 0;
+#endif
+}
+
+static int
+setreuseaddr(int sock, int value)
+{
+    return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
+}
+
+#if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
+static int
+setv6only(int sock, int value)
+{
+    return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
+}
+#endif
+
+
+static const char *paddr (struct sockaddr *sa)
+{
+    static char buf[100];
+    char portbuf[10];
+    if (getnameinfo(sa, socklen(sa),
+		    buf, sizeof(buf), portbuf, sizeof(portbuf),
+		    NI_NUMERICHOST|NI_NUMERICSERV))
+	strcpy(buf, "<unprintable>");
+    else {
+	unsigned int len = sizeof(buf) - strlen(buf);
+	char *p = buf + strlen(buf);
+	if (len > 2+strlen(portbuf)) {
+	    *p++ = '.';
+	    len--;
+	    strncpy(p, portbuf, len);
+	}
+    }
+    return buf;
+}
+
+/* KDC data.  */
+
+enum kdc_conn_type { CONN_UDP, CONN_TCP_LISTENER, CONN_TCP };
+
+/* Per-connection info.  */
+struct connection {
+    int fd;
+    enum kdc_conn_type type;
+    void (*service)(struct connection *, const char *, int);
+    union {
+	/* Type-specific information.  */
+	struct {
+	    int x;
+	} udp;
+	struct {
+	    int x;
+	} tcp_listener;
+	struct {
+	    /* connection */
+	    struct sockaddr_storage addr_s;
+	    socklen_t addrlen;
+	    char addrbuf[56];
+	    krb5_fulladdr faddr;
+	    krb5_address kaddr;
+	    /* incoming */
+	    size_t bufsiz;
+	    size_t offset;
+	    char *buffer;
+	    size_t msglen;
+	    /* outgoing */
+	    krb5_data *response;
+	    unsigned char lenbuf[4];
+	    sg_buf sgbuf[2];
+	    sg_buf *sgp;
+	    int sgnum;
+	    /* crude denial-of-service avoidance support */
+	    time_t start_time;
+	} tcp;
+    } u;
+};
+
+
+#define SET(TYPE) struct { TYPE *data; int n, max; }
+
+/* Start at the top and work down -- this should allow for deletions
+   without disrupting the iteration, since we delete by overwriting
+   the element to be removed with the last element.  */
+#define FOREACH_ELT(set,idx,vvar) \
+  for (idx = set.n-1; idx >= 0 && (vvar = set.data[idx], 1); idx--)
+
+#define GROW_SET(set, incr, tmpptr) \
+  (((int)(set.max + incr) < set.max					\
+    || (((size_t)((int)(set.max + incr) * sizeof(set.data[0]))		\
+	 / sizeof(set.data[0]))						\
+	!= (set.max + incr)))						\
+   ? 0				/* overflow */				\
+   : ((tmpptr = realloc(set.data,					\
+			(int)(set.max + incr) * sizeof(set.data[0])))	\
+      ? (set.data = tmpptr, set.max += incr, 1)				\
+      : 0))
+
+/* 1 = success, 0 = failure */
+#define ADD(set, val, tmpptr) \
+  ((set.n < set.max || GROW_SET(set, 10, tmpptr))			\
+   ? (set.data[set.n++] = val, 1)					\
+   : 0)
+
+#define DEL(set, idx) \
+  (set.data[idx] = set.data[--set.n], 0)
+
+#define FREE_SET_DATA(set) if(set.data) free(set.data);                 \
+   (set.data = 0, set.max = 0)
+
+
+/* Set<struct connection *> connections; */
+static SET(struct connection *) connections;
+#define n_sockets	connections.n
+#define conns		connections.data
+
+/* Set<u_short> udp_port_data, tcp_port_data; */
+static SET(u_short) udp_port_data, tcp_port_data;
+
+#include "cm.h"
+
+static struct select_state sstate;
+
+static krb5_error_code add_udp_port(int port)
+{
+    int	i;
+    void *tmp;
+    u_short val;
+    u_short s_port = port;
+
+    if (s_port != port)
+	return EINVAL;
+
+    FOREACH_ELT (udp_port_data, i, val)
+	if (s_port == val)
+	    return 0;
+    if (!ADD(udp_port_data, s_port, tmp))
+	return ENOMEM;
+    return 0;
+}
+
+static krb5_error_code add_tcp_port(int port)
+{
+    int	i;
+    void *tmp;
+    u_short val;
+    u_short s_port = port;
+
+    if (s_port != port)
+	return EINVAL;
+
+    FOREACH_ELT (tcp_port_data, i, val)
+	if (s_port == val)
+	    return 0;
+    if (!ADD(tcp_port_data, s_port, tmp))
+	return ENOMEM;
+    return 0;
+}
+
+
+#define USE_AF AF_INET
+#define USE_TYPE SOCK_DGRAM
+#define USE_PROTO 0
+#define SOCKET_ERRNO errno
+#include "foreachaddr.h"
+
+struct socksetup {
+    const char *prog;
+    krb5_error_code retval;
+};
+
+static struct connection *
+add_fd (struct socksetup *data, int sock, enum kdc_conn_type conntype,
+	void (*service)(struct connection *, const char *, int))
+{
+    struct connection *newconn;
+    void *tmp;
+
+    newconn = malloc(sizeof(*newconn));
+    if (newconn == 0) {
+	data->retval = errno;
+	com_err(data->prog, errno,
+		"cannot allocate storage for connection info");
+	return 0;
+    }
+    if (!ADD(connections, newconn, tmp)) {
+	data->retval = errno;
+	com_err(data->prog, data->retval, "cannot save socket info");
+	free(newconn);
+	return 0;
+    }
+
+    memset(newconn, 0, sizeof(*newconn));
+    newconn->type = conntype;
+    newconn->fd = sock;
+    newconn->service = service;
+    return newconn;
+}
+
+static void process_packet(struct connection *, const char *, int);
+static void accept_tcp_connection(struct connection *, const char *, int);
+static void process_tcp_connection(struct connection *, const char *, int);
+
+static struct connection *
+add_udp_fd (struct socksetup *data, int sock)
+{
+    return add_fd(data, sock, CONN_UDP, process_packet);
+}
+
+static struct connection *
+add_tcp_listener_fd (struct socksetup *data, int sock)
+{
+    return add_fd(data, sock, CONN_TCP_LISTENER, accept_tcp_connection);
+}
+
+static struct connection *
+add_tcp_data_fd (struct socksetup *data, int sock)
+{
+    return add_fd(data, sock, CONN_TCP, process_tcp_connection);
+}
+
+static void
+delete_fd (struct connection *xconn)
+{
+    struct connection *conn;
+    int i;
+
+    FOREACH_ELT(connections, i, conn)
+	if (conn == xconn) {
+	    DEL(connections, i);
+	    break;
+	}
+    free(xconn);
+}
+
+static int
+setnbio(int sock)
+{
+    static const int one = 1;
+    return ioctlsocket(sock, FIONBIO, (const void *)&one);
+}
+
+static int
+setnolinger(int s)
+{
+    static const struct linger ling = { 0, 0 };
+    return setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
+}
+
+/* Returns -1 or socket fd.  */
+static int
+setup_a_tcp_listener(struct socksetup *data, struct sockaddr *addr)
+{
+    int sock;
+
+    sock = socket(addr->sa_family, SOCK_STREAM, 0);
+    if (sock == -1) {
+	com_err(data->prog, errno, "Cannot create TCP server socket on %s",
+		paddr(addr));
+	return -1;
+    }
+    if (setreuseaddr(sock, 1) < 0)
+	com_err(data->prog, errno,
+		"Cannot enable SO_REUSEADDR on fd %d", sock);
+#ifdef KRB5_USE_INET6
+    if (addr->sa_family == AF_INET6) {
+#ifdef IPV6_V6ONLY
+	if (setv6only(sock, 1))
+	    com_err(data->prog, errno, "setsockopt(IPV6_V6ONLY,1) failed");
+	else
+	    com_err(data->prog, 0, "setsockopt(IPV6_V6ONLY,1) worked");
+#else
+	krb5_klog_syslog(LOG_INFO, "no IPV6_V6ONLY socket option support");
+#endif /* IPV6_V6ONLY */
+    }
+#endif /* KRB5_USE_INET6 */
+    if (bind(sock, addr, socklen(addr)) == -1) {
+	com_err(data->prog, errno,
+		"Cannot bind TCP server socket on %s", paddr(addr));
+	close(sock);
+	return -1;
+    }
+    if (listen(sock, 5) < 0) {
+	com_err(data->prog, errno, "Cannot listen on TCP server socket on %s",
+		paddr(addr));
+	close(sock);
+	return -1;
+    }
+    if (setnbio(sock)) {
+	com_err(data->prog, errno,
+		"cannot set listening tcp socket on %s non-blocking",
+		paddr(addr));
+	close(sock);
+	return -1;
+    }
+    if (setnolinger(sock)) {
+	com_err(data->prog, errno, "disabling SO_LINGER on TCP socket on %s",
+		paddr(addr));
+	close(sock);
+	return -1;
+    }
+    return sock;
+}
+
+static int
+setup_tcp_listener_ports(struct socksetup *data)
+{
+    struct sockaddr_in sin4;
+#ifdef KRB5_USE_INET6
+    struct sockaddr_in6 sin6;
+#endif
+    int i, port;
+
+    memset(&sin4, 0, sizeof(sin4));
+    sin4.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+    sin4.sin_len = sizeof(sin4);
+#endif
+    sin4.sin_addr.s_addr = INADDR_ANY;
+
+#ifdef KRB5_USE_INET6
+    memset(&sin6, 0, sizeof(sin6));
+    sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+    sin6.sin6_len = sizeof(sin6);
+#endif
+    sin6.sin6_addr = in6addr_any;
+#endif
+
+    FOREACH_ELT (tcp_port_data, i, port) {
+	int s4, s6;
+
+	set_sa_port((struct sockaddr *)&sin4, htons(port));
+	if (!ipv6_enabled()) {
+	    s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
+	    if (s4 < 0)
+		return -1;
+	    s6 = -1;
+	} else {
+#ifndef KRB5_USE_INET6
+	    abort();
+#else
+	    s4 = s6 = -1;
+
+	    set_sa_port((struct sockaddr *)&sin6, htons(port));
+
+	    s6 = setup_a_tcp_listener(data, (struct sockaddr *)&sin6);
+	    if (s6 < 0)
+		return -1;
+
+	    s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
+#endif /* KRB5_USE_INET6 */
+	}
+
+	/* Sockets are created, prepare to listen on them.  */
+	if (s4 >= 0) {
+	    FD_SET(s4, &sstate.rfds);
+	    if (s4 >= sstate.max)
+		sstate.max = s4 + 1;
+	    if (add_tcp_listener_fd(data, s4) == 0)
+		close(s4);
+	    else
+		krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s",
+				 s4, paddr((struct sockaddr *)&sin4));
+	}
+#ifdef KRB5_USE_INET6
+	if (s6 >= 0) {
+	    FD_SET(s6, &sstate.rfds);
+	    if (s6 >= sstate.max)
+		sstate.max = s6 + 1;
+	    if (add_tcp_listener_fd(data, s6) == 0) {
+		close(s6);
+		s6 = -1;
+	    } else
+		krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s",
+				 s6, paddr((struct sockaddr *)&sin6));
+	    if (s4 < 0)
+		krb5_klog_syslog(LOG_INFO,
+				 "assuming IPv6 socket accepts IPv4");
+	}
+#endif
+    }
+    return 0;
+}
+
+static int
+setup_udp_port(void *P_data, struct sockaddr *addr)
+{
+    struct socksetup *data = P_data;
+    int sock = -1, i;
+    char haddrbuf[NI_MAXHOST];
+    int err;
+    u_short port;
+
+    err = getnameinfo(addr, socklen(addr), haddrbuf, sizeof(haddrbuf),
+		      0, 0, NI_NUMERICHOST);
+    if (err)
+	strcpy(haddrbuf, "<unprintable>");
+
+    switch (addr->sa_family) {
+    case AF_INET:
+	break;
+#ifdef AF_INET6
+    case AF_INET6:
+#ifdef KRB5_USE_INET6
+	break;
+#else
+	{
+	    static int first = 1;
+	    if (first) {
+		krb5_klog_syslog (LOG_INFO, "skipping local ipv6 addresses");
+		first = 0;
+	    }
+	    return 0;
+	}
+#endif
+#endif
+#ifdef AF_LINK /* some BSD systems, AIX */
+    case AF_LINK:
+	return 0;
+#endif
+#ifdef AF_DLI /* Direct Link Interface - DEC Ultrix/OSF1 link layer? */
+    case AF_DLI:
+	return 0;
+#endif
+    default:
+	krb5_klog_syslog (LOG_INFO,
+			  "skipping unrecognized local address family %d",
+			  addr->sa_family);
+	return 0;
+    }
+
+    FOREACH_ELT (udp_port_data, i, port) {
+	sock = socket (addr->sa_family, SOCK_DGRAM, 0);
+	if (sock == -1) {
+	    data->retval = errno;
+	    com_err(data->prog, data->retval,
+		    "Cannot create server socket for port %d address %s",
+		    port, haddrbuf);
+	    return 1;
+	}
+	set_sa_port(addr, htons(port));
+	if (bind (sock, (struct sockaddr *)addr, socklen (addr)) == -1) {
+	    data->retval = errno;
+	    com_err(data->prog, data->retval,
+		    "Cannot bind server socket to port %d address %s",
+		    port, haddrbuf);
+	    return 1;
+	}
+	FD_SET (sock, &sstate.rfds);
+	if (sock >= sstate.max)
+	    sstate.max = sock + 1;
+	krb5_klog_syslog (LOG_INFO, "listening on fd %d: udp %s", sock,
+			  paddr((struct sockaddr *)addr));
+	if (add_udp_fd (data, sock) == 0)
+	    return 1;
+    }
+    return 0;
+}
+
+#if 1
+static void klog_handler(const void *data, size_t len)
+{
+    static char buf[BUFSIZ];
+    static int bufoffset;
+    void *p;
+
+#define flush_buf() \
+  (bufoffset						\
+   ? (((buf[0] == 0 || buf[0] == '\n')			\
+       ? (fork()==0?abort():(void)0)			\
+       : (void)0),					\
+      krb5_klog_syslog(LOG_INFO, "%s", buf),		\
+      memset(buf, 0, sizeof(buf)),			\
+      bufoffset = 0)					\
+   : 0)
+
+    p = memchr(data, 0, len);
+    if (p)
+	len = (const char *)p - (const char *)data;
+scan_for_newlines:
+    if (len == 0)
+	return;
+    p = memchr(data, '\n', len);
+    if (p) {
+	if (p != data)
+	    klog_handler(data, (size_t)((const char *)p - (const char *)data));
+	flush_buf();
+	len -= ((const char *)p - (const char *)data) + 1;
+	data = 1 + (const char *)p;
+	goto scan_for_newlines;
+    } else if (len > sizeof(buf) - 1 || len + bufoffset > sizeof(buf) - 1) {
+	size_t x = sizeof(buf) - len - 1;
+	klog_handler(data, x);
+	flush_buf();
+	len -= x;
+	data = (const char *)data + x;
+	goto scan_for_newlines;
+    } else {
+	memcpy(buf + bufoffset, data, len);
+	bufoffset += len;
+    }
+}
+#endif
+
+/* XXX */
+extern int krb5int_debug_sendto_kdc;
+extern void (*krb5int_sendtokdc_debug_handler)(const void*, size_t);
+
+krb5_error_code
+setup_network(const char *prog)
+{
+    struct socksetup setup_data;
+    krb5_error_code retval;
+    char *cp;
+    int i, port;
+
+    FD_ZERO(&sstate.rfds);
+    FD_ZERO(&sstate.wfds);
+    FD_ZERO(&sstate.xfds);
+    sstate.max = 0;
+
+/*    krb5int_debug_sendto_kdc = 1; */
+    krb5int_sendtokdc_debug_handler = klog_handler;
+
+    /* Handle each realm's ports */
+    for (i=0; i<kdc_numrealms; i++) {
+	cp = kdc_realmlist[i]->realm_ports;
+	while (cp && *cp) {
+	    if (*cp == ',' || isspace((int) *cp)) {
+		cp++;
+		continue;
+	    }
+	    port = strtol(cp, &cp, 10);
+	    if (cp == 0)
+		break;
+	    retval = add_udp_port(port);
+	    if (retval)
+		return retval;
+	}
+
+	cp = kdc_realmlist[i]->realm_tcp_ports;
+	while (cp && *cp) {
+	    if (*cp == ',' || isspace((int) *cp)) {
+		cp++;
+		continue;
+	    }
+	    port = strtol(cp, &cp, 10);
+	    if (cp == 0)
+		break;
+	    retval = add_tcp_port(port);
+	    if (retval)
+		return retval;
+	}
+    }
+
+    setup_data.prog = prog;
+    setup_data.retval = 0;
+    krb5_klog_syslog (LOG_INFO, "setting up network...");
+    /* To do: Use RFC 2292 interface (or follow-on) and IPV6_PKTINFO,
+       so we might need only one UDP socket; fall back to binding
+       sockets on each address only if IPV6_PKTINFO isn't
+       supported.  */
+    if (foreach_localaddr (&setup_data, setup_udp_port, 0, 0)) {
+	return setup_data.retval;
+    }
+    setup_tcp_listener_ports(&setup_data);
+    krb5_klog_syslog (LOG_INFO, "set up %d sockets", n_sockets);
+    if (n_sockets == 0) {
+	com_err(prog, 0, "no sockets set up?");
+	exit (1);
+    }
+
+    return 0;
+}
+
+static void init_addr(krb5_fulladdr *faddr, struct sockaddr *sa)
+{
+    switch (sa->sa_family) {
+    case AF_INET:
+	faddr->address->addrtype = ADDRTYPE_INET;
+	faddr->address->length = 4;
+	faddr->address->contents = (krb5_octet *) &sa2sin(sa)->sin_addr;
+	faddr->port = ntohs(sa2sin(sa)->sin_port);
+	break;
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+	if (IN6_IS_ADDR_V4MAPPED(&sa2sin6(sa)->sin6_addr)) {
+	    faddr->address->addrtype = ADDRTYPE_INET;
+	    faddr->address->length = 4;
+	    faddr->address->contents = 12 + (krb5_octet *) &sa2sin6(sa)->sin6_addr;
+	} else {
+	    faddr->address->addrtype = ADDRTYPE_INET6;
+	    faddr->address->length = 16;
+	    faddr->address->contents = (krb5_octet *) &sa2sin6(sa)->sin6_addr;
+	}
+	faddr->port = ntohs(sa2sin6(sa)->sin6_port);
+	break;
+#endif
+    default:
+	faddr->address->addrtype = -1;
+	faddr->address->length = 0;
+	faddr->address->contents = 0;
+	faddr->port = 0;
+	break;
+    }
+}
+
+static void process_packet(struct connection *conn, const char *prog,
+			   int selflags)
+{
+    int cc;
+    socklen_t saddr_len;
+    krb5_fulladdr faddr;
+    krb5_error_code retval;
+    struct sockaddr_storage saddr;
+    krb5_address addr;
+    krb5_data request;
+    krb5_data *response;
+    char pktbuf[MAX_DGRAM_SIZE];
+    int port_fd = conn->fd;
+
+    response = NULL;
+    saddr_len = sizeof(saddr);
+    cc = recvfrom(port_fd, pktbuf, sizeof(pktbuf), 0,
+		  (struct sockaddr *)&saddr, &saddr_len);
+    if (cc == -1) {
+	if (errno != EINTR
+	    /* This is how Linux indicates that a previous
+	       transmission was refused, e.g., if the client timed out
+	       before getting the response packet.  */
+	    && errno != ECONNREFUSED
+	    )
+	    com_err(prog, errno, "while receiving from network");
+	return;
+    }
+    if (!cc)
+	return;		/* zero-length packet? */
+
+    request.length = cc;
+    request.data = pktbuf;
+    faddr.address = &addr;
+    init_addr(&faddr, ss2sa(&saddr));
+    /* this address is in net order */
+    if ((retval = dispatch(&request, &faddr, &response))) {
+	com_err(prog, retval, "while dispatching (udp)");
+	return;
+    }
+    cc = sendto(port_fd, response->data, (socklen_t) response->length, 0,
+		(struct sockaddr *)&saddr, saddr_len);
+    if (cc == -1) {
+	char addrbuf[46];
+        krb5_free_data(kdc_context, response);
+	if (inet_ntop(((struct sockaddr *)&saddr)->sa_family,
+		      addr.contents, addrbuf, sizeof(addrbuf)) == 0) {
+	    strcpy(addrbuf, "?");
+	}
+	com_err(prog, errno, "while sending reply to %s/%d",
+		addrbuf, faddr.port);
+	return;
+    }
+    if (cc != response->length) {
+	krb5_free_data(kdc_context, response);
+	com_err(prog, 0, "short reply write %d vs %d\n",
+		response->length, cc);
+	return;
+    }
+    krb5_free_data(kdc_context, response);
+    return;
+}
+
+static int tcp_data_counter;
+static int max_tcp_data_connections = 30;
+
+static void kill_tcp_connection(struct connection *);
+
+static void accept_tcp_connection(struct connection *conn, const char *prog,
+				  int selflags)
+{
+    int s;
+    struct sockaddr_storage addr_s;
+    struct sockaddr *addr = (struct sockaddr *)&addr_s;
+    socklen_t addrlen = sizeof(addr_s);
+    struct socksetup sockdata;
+    struct connection *newconn;
+    char tmpbuf[10];
+
+    s = accept(conn->fd, addr, &addrlen);
+    if (s < 0)
+	return;
+    setnbio(s), setnolinger(s);
+
+    sockdata.prog = prog;
+    sockdata.retval = 0;
+
+    newconn = add_tcp_data_fd(&sockdata, s);
+    if (newconn == 0)
+	return;
+
+    if (getnameinfo((struct sockaddr *)&addr_s, addrlen,
+		    newconn->u.tcp.addrbuf, sizeof(newconn->u.tcp.addrbuf),
+		    tmpbuf, sizeof(tmpbuf),
+		    NI_NUMERICHOST | NI_NUMERICSERV))
+	strcpy(newconn->u.tcp.addrbuf, "???");
+    else {
+	char *p, *end;
+	p = newconn->u.tcp.addrbuf;
+	end = p + sizeof(newconn->u.tcp.addrbuf);
+	p += strlen(p);
+	if (end - p > 2 + strlen(tmpbuf)) {
+	    *p++ = '.';
+	    strcpy(p, tmpbuf);
+	}
+    }
+#if 0
+    krb5_klog_syslog(LOG_INFO, "accepted TCP connection on socket %d from %s",
+		     s, newconn->u.tcp.addrbuf);
+#endif
+
+    newconn->u.tcp.addr_s = addr_s;
+    newconn->u.tcp.addrlen = addrlen;
+    newconn->u.tcp.bufsiz = 1024 * 1024;
+    newconn->u.tcp.buffer = malloc(newconn->u.tcp.bufsiz);
+    newconn->u.tcp.start_time = time(0);
+
+    if (++tcp_data_counter > max_tcp_data_connections) {
+	struct connection *oldest_tcp = NULL;
+	struct connection *c;
+	int i;
+
+	krb5_klog_syslog(LOG_INFO, "too many connections");
+
+	FOREACH_ELT (connections, i, c) {
+	    if (c->type != CONN_TCP)
+		continue;
+	    if (c == newconn)
+		continue;
+#if 0
+	    krb5_klog_syslog(LOG_INFO, "fd %d started at %ld", c->fd,
+			     c->u.tcp.start_time);
+#endif
+	    if (oldest_tcp == NULL
+		|| oldest_tcp->u.tcp.start_time > c->u.tcp.start_time)
+		oldest_tcp = c;
+	}
+	if (oldest_tcp != NULL) {
+	    krb5_klog_syslog(LOG_INFO, "dropping tcp fd %d from %s",
+			     oldest_tcp->fd, oldest_tcp->u.tcp.addrbuf);
+	    kill_tcp_connection(oldest_tcp);
+	}
+    }
+    if (newconn->u.tcp.buffer == 0) {
+	com_err(prog, errno, "allocating buffer for new TCP session from %s",
+		newconn->u.tcp.addrbuf);
+	delete_fd(newconn);
+	close(s);
+	tcp_data_counter--;
+	return;
+    }
+    newconn->u.tcp.offset = 0;
+    newconn->u.tcp.faddr.address = &newconn->u.tcp.kaddr;
+    init_addr(&newconn->u.tcp.faddr, ss2sa(&newconn->u.tcp.addr_s));
+    SG_SET(&newconn->u.tcp.sgbuf[0], newconn->u.tcp.lenbuf, 4);
+    SG_SET(&newconn->u.tcp.sgbuf[1], 0, 0);
+
+    FD_SET(s, &sstate.rfds);
+    if (sstate.max <= s)
+	sstate.max = s + 1;
+}
+
+static void
+kill_tcp_connection(struct connection *conn)
+{
+    if (conn->u.tcp.response)
+	krb5_free_data(kdc_context, conn->u.tcp.response);
+    if (conn->u.tcp.buffer)
+	free(conn->u.tcp.buffer);
+    FD_CLR(conn->fd, &sstate.rfds);
+    FD_CLR(conn->fd, &sstate.wfds);
+    if (sstate.max == conn->fd + 1)
+	while (sstate.max > 0
+	       && ! FD_ISSET(sstate.max-1, &sstate.rfds)
+	       && ! FD_ISSET(sstate.max-1, &sstate.wfds)
+	       /* && ! FD_ISSET(sstate.max-1, &sstate.xfds) */
+	    )
+	    sstate.max--;
+    close(conn->fd);
+    conn->fd = -1;
+    delete_fd(conn);
+    tcp_data_counter--;
+}
+
+static void
+process_tcp_connection(struct connection *conn, const char *prog, int selflags)
+{
+    if (selflags & SSF_WRITE) {
+	ssize_t nwrote;
+	SOCKET_WRITEV_TEMP tmp;
+
+	nwrote = SOCKET_WRITEV(conn->fd, conn->u.tcp.sgp, conn->u.tcp.sgnum,
+			       tmp);
+	if (nwrote < 0) {
+	    goto kill_tcp_connection;
+	}
+	if (nwrote == 0)
+	    /* eof */
+	    goto kill_tcp_connection;
+	while (nwrote) {
+	    sg_buf *sgp = conn->u.tcp.sgp;
+	    if (nwrote < SG_LEN(sgp)) {
+		SG_ADVANCE(sgp, nwrote);
+		nwrote = 0;
+	    } else {
+		nwrote -= SG_LEN(sgp);
+		conn->u.tcp.sgp++;
+		conn->u.tcp.sgnum--;
+		if (conn->u.tcp.sgnum == 0 && nwrote != 0)
+		    abort();
+	    }
+	}
+	if (conn->u.tcp.sgnum == 0) {
+	    /* finished sending */
+	    /* should go back to reading */
+	    goto kill_tcp_connection;
+	}
+    } else if (selflags & SSF_READ) {
+	/* Read message length and data into one big buffer, already
+	   allocated at connect time.  If we have a complete message,
+	   we stop reading, so we should only be here if there is no
+	   data in the buffer, or only an incomplete message.  */
+	size_t len;
+	ssize_t nread;
+	if (conn->u.tcp.offset < 4) {
+	    /* msglen has not been computed */
+	    /* XXX Doing at least two reads here, letting the kernel
+	       worry about buffering.  It'll be faster when we add
+	       code to manage the buffer here.  */
+	    len = 4 - conn->u.tcp.offset;
+	    nread = SOCKET_READ(conn->fd,
+				conn->u.tcp.buffer + conn->u.tcp.offset, len);
+	    if (nread < 0)
+		/* error */
+		goto kill_tcp_connection;
+	    if (nread == 0)
+		/* eof */
+		goto kill_tcp_connection;
+	    conn->u.tcp.offset += nread;
+	    if (conn->u.tcp.offset == 4) {
+		unsigned char *p = (unsigned char *)conn->u.tcp.buffer;
+		conn->u.tcp.msglen = ((p[0] << 24)
+				      | (p[1] << 16)
+				      | (p[2] <<  8)
+				      | p[3]);
+		if (conn->u.tcp.msglen > conn->u.tcp.bufsiz - 4) {
+		    /* message too big */
+		    krb5_klog_syslog(LOG_ERR, "TCP client %s wants %lu bytes, cap is %lu",
+				     conn->u.tcp.addrbuf, (unsigned long) conn->u.tcp.msglen,
+				     (unsigned long) conn->u.tcp.bufsiz - 4);
+		    /* XXX Should return an error.  */
+		    goto kill_tcp_connection;
+		}
+	    }
+	} else {
+	    /* msglen known */
+	    krb5_data request;
+	    krb5_error_code err;
+
+	    len = conn->u.tcp.msglen - (conn->u.tcp.offset - 4);
+	    nread = SOCKET_READ(conn->fd,
+				conn->u.tcp.buffer + conn->u.tcp.offset, len);
+	    if (nread < 0)
+		/* error */
+		goto kill_tcp_connection;
+	    if (nread == 0)
+		/* eof */
+		goto kill_tcp_connection;
+	    conn->u.tcp.offset += nread;
+	    if (conn->u.tcp.offset < conn->u.tcp.msglen + 4)
+		return;
+	    /* have a complete message, and exactly one message */
+	    request.length = conn->u.tcp.msglen;
+	    request.data = conn->u.tcp.buffer + 4;
+	    err = dispatch(&request, &conn->u.tcp.faddr,
+			   &conn->u.tcp.response);
+	    if (err) {
+		com_err(prog, err, "while dispatching (tcp)");
+		goto kill_tcp_connection;
+	    }
+	    conn->u.tcp.lenbuf[0] = 0xff & (conn->u.tcp.response->length >> 24);
+	    conn->u.tcp.lenbuf[1] = 0xff & (conn->u.tcp.response->length >> 16);
+	    conn->u.tcp.lenbuf[2] = 0xff & (conn->u.tcp.response->length >> 8);
+	    conn->u.tcp.lenbuf[3] = 0xff & (conn->u.tcp.response->length >> 0);
+	    SG_SET(&conn->u.tcp.sgbuf[1], conn->u.tcp.response->data,
+		   conn->u.tcp.response->length);
+	    conn->u.tcp.sgp = conn->u.tcp.sgbuf;
+	    conn->u.tcp.sgnum = 2;
+	    FD_CLR(conn->fd, &sstate.rfds);
+	    FD_SET(conn->fd, &sstate.wfds);
+	}
+    } else
+	abort();
+
+    return;
+
+kill_tcp_connection:
+    kill_tcp_connection(conn);
+}
+
+static void service_conn(struct connection *conn, const char *prog,
+			 int selflags)
+{
+    conn->service(conn, prog, selflags);
+}
+
+krb5_error_code
+listen_and_process(const char *prog)
+{
+    int			nfound;
+    /* This struct contains 3 fd_set objects; on some platforms, they
+       can be rather large.  Making this static avoids putting all
+       that junk on the stack.  */
+    static struct select_state sout;
+    int			i, sret;
+    krb5_error_code	err;
+
+    if (conns == (struct connection **) NULL)
+	return KDC5_NONET;
+    
+    while (!signal_requests_exit) {
+	if (signal_requests_hup) {
+	    krb5_klog_reopen(kdc_context);
+	    signal_requests_hup = 0;
+	}
+	sstate.end_time.tv_sec = sstate.end_time.tv_usec = 0;
+	err = krb5int_cm_call_select(&sstate, &sout, &sret);
+	if (err) {
+	    com_err(prog, err, "while selecting for network input(1)");
+	    continue;
+	}
+	if (sret == -1) {
+	    if (errno != EINTR)
+		com_err(prog, errno, "while selecting for network input(2)");
+	    continue;
+	}
+	nfound = sret;
+	for (i=0; i<n_sockets && nfound > 0; i++) {
+	    int sflags = 0;
+	    if (conns[i]->fd < 0)
+		abort();
+	    if (FD_ISSET(conns[i]->fd, &sout.rfds))
+		sflags |= SSF_READ, nfound--;
+	    if (FD_ISSET(conns[i]->fd, &sout.wfds))
+		sflags |= SSF_WRITE, nfound--;
+	    if (sflags)
+		service_conn(conns[i], prog, sflags);
+	}
+    }
+    return 0;
+}
+
+krb5_error_code
+closedown_network(const char *prog)
+{
+    int i;
+    struct connection *conn;
+
+    if (conns == (struct connection **) NULL)
+	return KDC5_NONET;
+
+    FOREACH_ELT (connections, i, conn) {
+	if (conn->fd >= 0)
+	    (void) close(conn->fd);
+	DEL (connections, i);
+	/* There may also be per-connection data in the tcp structure
+	   (tcp.buffer, tcp.response) that we're not freeing here.
+	   That should only happen if we quit with a connection in
+	   progress.  */
+	free(conn);
+    }
+    FREE_SET_DATA(connections);
+    FREE_SET_DATA(udp_port_data);
+    FREE_SET_DATA(tcp_port_data);
+
+    return 0;
+}
+
+#endif /* INET */
diff --git a/mechglue/src/kdc/policy.c b/mechglue/src/kdc/policy.c
new file mode 100644
index 000000000..8c0b69272
--- /dev/null
+++ b/mechglue/src/kdc/policy.c
@@ -0,0 +1,75 @@
+/*
+ * kdc/policy.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Policy decision routines for KDC.
+ */
+
+#include "k5-int.h"
+#include "kdc_util.h"
+
+int
+against_local_policy_as(register krb5_kdc_req *request, krb5_db_entry client,
+			krb5_db_entry server, krb5_timestamp kdc_time,
+			const char **status)
+{
+#if 0
+     /* An AS request must include the addresses field */
+    if (request->addresses == 0) {
+	*status = "NO ADDRESS";
+	return KRB5KDC_ERR_POLICY;
+    }
+#endif
+    
+    return 0;			/* not against policy */
+}
+
+/*
+ * This is where local policy restrictions for the TGS should placed.
+ */
+krb5_error_code
+against_local_policy_tgs(register krb5_kdc_req *request, krb5_db_entry server,
+			 krb5_ticket *ticket, const char **status)
+{
+#if 0
+    /*
+     * For example, if your site wants to disallow ticket forwarding,
+     * you might do something like this:
+     */
+    
+    if (isflagset(request->kdc_options, KDC_OPT_FORWARDED)) {
+	*status = "FORWARD POLICY";
+	return KRB5KDC_ERR_POLICY;
+    }
+#endif
+    
+    return 0;				/* not against policy */
+}
+
+
+
+
+
+
+
diff --git a/mechglue/src/kdc/policy.h b/mechglue/src/kdc/policy.h
new file mode 100644
index 000000000..fe8307625
--- /dev/null
+++ b/mechglue/src/kdc/policy.h
@@ -0,0 +1,39 @@
+/*
+ * kdc/policy.h
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Declarations for policy.c
+ */
+
+#ifndef __KRB5_KDC_POLICY__
+#define __KRB5_KDC_POLICY__
+
+extern int against_postdate_policy (krb5_timestamp);
+
+extern int against_flag_policy_as (const krb5_kdc_req *);
+
+extern int against_flag_policy_tgs (const krb5_kdc_req *,
+					      const krb5_ticket *);
+
+#endif /* __KRB5_KDC_POLICY__ */
diff --git a/mechglue/src/kdc/replay.c b/mechglue/src/kdc/replay.c
new file mode 100644
index 000000000..736abb73b
--- /dev/null
+++ b/mechglue/src/kdc/replay.c
@@ -0,0 +1,190 @@
+/*
+ * kdc/replay.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Replay lookaside cache for the KDC, to avoid extra work.
+ *
+ */
+
+#include "k5-int.h"
+#include "kdc_util.h"
+#include "extern.h"
+
+#ifndef NOCACHE
+
+typedef struct _krb5_kdc_replay_ent {
+    struct _krb5_kdc_replay_ent *next;
+    int num_hits;
+    krb5_int32 timein;
+    time_t db_age;
+    krb5_data *req_packet;
+    krb5_data *reply_packet;
+    krb5_address *addr;		/* XXX should these not be pointers? */
+} krb5_kdc_replay_ent;
+
+static krb5_kdc_replay_ent root_ptr = {0};
+
+static int hits = 0;
+static int calls = 0;
+static int max_hits_per_entry = 0;
+static int num_entries = 0;
+
+#define STALE_TIME	2*60		/* two minutes */
+#define STALE(ptr) ((abs((ptr)->timein - timenow) >= STALE_TIME) ||	\
+		    ((ptr)->db_age != db_age))
+
+#define MATCH(ptr) (((ptr)->req_packet->length == inpkt->length) &&	\
+		    !memcmp((ptr)->req_packet->data, inpkt->data,	\
+			    inpkt->length) &&				\
+		    ((ptr)->addr->length == from->address->length) &&	\
+		    !memcmp((ptr)->addr->contents,			\
+			    from->address->contents,			\
+			    from->address->length)&&			\
+		    ((ptr)->db_age == db_age))
+/* XXX
+   Todo:  quench the size of the queue...
+ */
+
+/* return TRUE if outpkt is filled in with a packet to reply with,
+   FALSE if the caller should do the work */
+
+krb5_boolean
+kdc_check_lookaside(krb5_data *inpkt, const krb5_fulladdr *from,
+		    krb5_data **outpkt)
+{
+    krb5_int32 timenow;
+    register krb5_kdc_replay_ent *eptr, *last, *hold;
+    time_t db_age;
+
+    if (krb5_timeofday(kdc_context, &timenow) || 
+	krb5_db_get_age(kdc_context, 0, &db_age))
+	return FALSE;
+
+    calls++;
+
+    /* search for a replay entry in the queue, possibly removing
+       stale entries while we're here */
+
+    if (root_ptr.next) {
+	for (last = &root_ptr, eptr = root_ptr.next;
+	     eptr;
+	     eptr = eptr->next) {
+	    if (MATCH(eptr)) {
+		eptr->num_hits++;
+		hits++;
+
+		if (krb5_copy_data(kdc_context, eptr->reply_packet, outpkt))
+		    return FALSE;
+		else
+		    return TRUE;
+		/* return here, don't bother flushing even if it is stale.
+		   if we just matched, we may get another retransmit... */
+	    }
+	    if (STALE(eptr)) {
+		/* flush it and collect stats */
+		max_hits_per_entry = max(max_hits_per_entry, eptr->num_hits);
+		krb5_free_data(kdc_context, eptr->req_packet);
+		krb5_free_data(kdc_context, eptr->reply_packet);
+		krb5_free_address(kdc_context, eptr->addr);
+		hold = eptr;
+		last->next = eptr->next;
+		eptr = last;
+		free(hold);
+	    } else {
+		/* this isn't it, just move along */
+		last = eptr;
+	    }
+	}
+    }
+    return FALSE;
+}
+
+/* insert a request & reply into the lookaside queue.  assumes it's not
+   already there, and can fail softly due to other weird errors. */
+
+void
+kdc_insert_lookaside(krb5_data *inpkt, const krb5_fulladdr *from,
+		     krb5_data *outpkt)
+{
+    register krb5_kdc_replay_ent *eptr;    
+    krb5_int32 timenow;
+    time_t db_age;
+
+    if (krb5_timeofday(kdc_context, &timenow) || 
+	krb5_db_get_age(kdc_context, 0, &db_age))
+	return;
+
+    /* this is a new entry */
+    eptr = (krb5_kdc_replay_ent *)calloc(1, sizeof(*eptr));
+    if (!eptr)
+	return;
+    eptr->timein = timenow;
+    eptr->db_age = db_age;
+    /*
+     * This is going to hurt a lot malloc()-wise due to the need to
+     * allocate memory for the krb5_data and krb5_address elements.
+     * ARGH!
+     */
+    if (krb5_copy_data(kdc_context, inpkt, &eptr->req_packet)) {
+	free(eptr);
+	return;
+    }
+    if (krb5_copy_data(kdc_context, outpkt, &eptr->reply_packet)) {
+	krb5_free_data(kdc_context, eptr->req_packet);
+	free(eptr);
+	return;
+    }
+    if (krb5_copy_addr(kdc_context, from->address, &eptr->addr)) {
+	krb5_free_data(kdc_context, eptr->req_packet);
+	krb5_free_data(kdc_context, eptr->reply_packet);
+	free(eptr);
+	return;
+    }
+    eptr->next = root_ptr.next;
+    root_ptr.next = eptr;
+    num_entries++;
+    return;
+}
+
+/* frees memory associated with the lookaside queue for memory profiling */
+void
+kdc_free_lookaside(krb5_context kcontext)
+{
+    register krb5_kdc_replay_ent *eptr, *last, *hold;
+    if (root_ptr.next) {
+        for (last = &root_ptr, eptr = root_ptr.next;
+	     eptr; eptr = eptr->next) {
+		krb5_free_data(kcontext, eptr->req_packet);
+		krb5_free_data(kcontext, eptr->reply_packet);
+		krb5_free_address(kcontext, eptr->addr);
+		hold = eptr;
+		last->next = eptr->next;
+		eptr = last;
+		free(hold);
+	}
+    }
+}
+
+#endif /* NOCACHE */
diff --git a/mechglue/src/kdc/rtest.c b/mechglue/src/kdc/rtest.c
new file mode 100644
index 000000000..d63e92fcf
--- /dev/null
+++ b/mechglue/src/kdc/rtest.c
@@ -0,0 +1,116 @@
+/*
+ * kdc/rtest.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include "kdc_util.h"
+#include "extern.h"
+
+void krb5_klog_syslog(void);
+
+static krb5_principal 
+make_princ(krb5_context ctx, const char *str, const char *prog)
+{
+    krb5_principal ret;
+    char *dat;
+
+    if(!(ret = (krb5_principal) malloc(sizeof(krb5_principal_data)))) {
+	  com_err(prog, ENOMEM, "while allocating principal data");
+	  exit(3);
+    }
+    memset(ret, 0, sizeof(krb5_principal_data));
+
+    /* We do not include the null... */
+    if(!(dat = (char *) malloc(strlen(str)))) {
+	  com_err(prog, ENOMEM, "while allocating principal realm data");
+	  exit(3);
+    }
+    memcpy(dat, str, strlen(str));
+    krb5_princ_set_realm_data(ctx, ret, dat);
+    krb5_princ_set_realm_length(ctx, ret, strlen(str));
+    
+    return ret;
+}
+
+int
+main(int argc, char **argv)
+{
+	krb5_data otrans;
+	krb5_data ntrans;
+	krb5_principal tgs, cl, sv;
+	krb5_error_code kret;
+	kdc_realm_t	kdc_realm;
+
+	if (argc < 4) {
+	    fprintf(stderr, "not enough args\n");
+	    exit(1);
+	}
+
+
+	/* Get a context */
+	kret = krb5_init_context(&kdc_realm.realm_context);
+	if (kret) {
+	  com_err(argv[0], kret, "while getting krb5 context");
+	  exit(2);
+	}
+	/* Needed so kdc_context will work */
+	kdc_active_realm = &kdc_realm;
+
+	ntrans.length = 0;
+	ntrans.data = 0;
+
+	otrans.length = strlen(argv[1]);
+	if (otrans.length) 
+	  otrans.data = (char *) malloc(otrans.length);
+	else 
+	  otrans.data = 0;
+	memcpy(otrans.data,argv[1], otrans.length);
+
+	tgs = make_princ(kdc_context, argv[2], argv[0]);
+	cl  = make_princ(kdc_context, argv[3], argv[0]);
+	sv  = make_princ(kdc_context, argv[4], argv[0]);
+	
+	add_to_transited(&otrans,&ntrans,tgs,cl,sv);
+
+	printf("%s\n",ntrans.data);
+
+	/* Free up all memory so we can profile for leaks */
+	if (otrans.data)
+	  free(otrans.data);
+	free(ntrans.data);
+
+	krb5_free_principal(kdc_realm.realm_context, tgs);
+	krb5_free_principal(kdc_realm.realm_context, cl);
+	krb5_free_principal(kdc_realm.realm_context, sv);
+	krb5_free_context(kdc_realm.realm_context);
+
+	exit(0);
+    }
+
+void krb5_klog_syslog(void) {}
+kdc_realm_t *find_realm_data (char *rname, krb5_ui_4 rsize) { return 0; }
diff --git a/mechglue/src/kdc/rtest.good b/mechglue/src/kdc/rtest.good
new file mode 100644
index 000000000..4eecf6e30
--- /dev/null
+++ b/mechglue/src/kdc/rtest.good
@@ -0,0 +1,26 @@
+ATHENA.MIT.EDU
+MIT.EDU,ATHENA.
+EDU,MIT.,ATHENA.
+EDU,MIT.,ATHENA.,WASHINGTON.EDU
+EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.
+EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.,SUB2W.
+EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.,SUB2W.,SUB3W.CS.WASHINGTON.EDU
+EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.,SUB2W.
+EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.,SUB2W.
+EDU,ATHENA.MIT.,SUB2M.,WASHINGTON.EDU,CS.
+/EDU/MIT/ATHENA
+/EDU/MIT,/ATHENA
+/EDU/MIT,/ATHENA
+/EDU,/MIT,/ATHENA
+/EDU,/MIT,/ATHENA, /EDU/WASHINGTON
+/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS
+/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS,/SUB2W
+/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS,/SUB2W, /EDU/WASHINGTON/CS/SUB3W
+/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS,/SUB2W
+/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS,/SUB2W
+/EDU,/MIT/ATHENA,/SUB2M, /EDU/WASHINGTON,/CS
+EDU,MIT.,ATHENA.,ATEST., /COM,/HP,/APOLLO
+EDU,MIT.,ATHENA., /COM,/HP,/APOLLO,/HTEST
+/COM,/HP,/APOLLO,EDU,MIT.,ATHENA.,ATEST.
+/COM,/HP,/APOLLO,ATHENA.MIT.EDU
+EDU,MIT.,ATHENA., /COM/HP/APOLLO/HTEST
diff --git a/mechglue/src/kdc/rtscript b/mechglue/src/kdc/rtscript
new file mode 100755
index 000000000..8803e3325
--- /dev/null
+++ b/mechglue/src/kdc/rtscript
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+#
+#  Copyright 1991 by the Massachusetts Institute of Technology.
+#  All Rights Reserved.
+# 
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+# 
+# should print out contents of rtest.good
+#
+./rtest "" ATHENA.MIT.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest ATHENA.MIT.EDU MIT.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "MIT.EDU,ATHENA." EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "EDU,MIT.,ATHENA." WASHINGTON.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "EDU,MIT.,ATHENA.,WASHINGTON.EDU" CS.WASHINGTON.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS." SUB2W.CS.WASHINGTON.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.,SUB2W." SUB3W.CS.WASHINGTON.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.,SUB2W." SUB1W.CS.WASHINGTON.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.,SUB2W." SUB1M.ATHENA.MIT.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "EDU,SUB2M.ATHENA.MIT.,WASHINGTON.EDU,CS." ATHENA.MIT.EDU SUB1W.CS.WASHINGTON.EDU SUB1M.ATHENA.MIT.EDU
+./rtest "" /EDU/MIT/ATHENA /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest /EDU/MIT/ATHENA /EDU/MIT /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest " /EDU/MIT/ATHENA" /EDU/MIT /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/EDU/MIT,/ATHENA" /EDU /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/EDU,/MIT,/ATHENA" /EDU/WASHINGTON /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/EDU,/MIT,/ATHENA, /EDU/WASHINGTON" /EDU/WASHINGTON/CS /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS" /EDU/WASHINGTON/CS/SUB2W /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS,/SUB2W" /EDU/WASHINGTON/CS/SUB3W /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS,/SUB2W" /EDU/WASHINGTON/CS/SUB1W /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/EDU,/MIT,/ATHENA, /EDU/WASHINGTON,/CS,/SUB2W" /EDU/MIT/ATHENA/SUB1M /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/EDU,/MIT/ATHENA/SUB2M, /EDU/WASHINGTON,/CS" /EDU/MIT/ATHENA /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "EDU,MIT.,ATHENA., /COM,/HP,/APOLLO" ATEST.ATHENA.MIT.EDU /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "EDU,MIT.,ATHENA., /COM,/HP,/APOLLO" /COM/HP/APOLLO/HTEST /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/COM,/HP,/APOLLO,EDU,MIT.,ATHENA." ATEST.ATHENA.MIT.EDU /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "/COM,/HP,/APOLLO" ATHENA.MIT.EDU /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
+./rtest "EDU,MIT.,ATHENA." /COM/HP/APOLLO/HTEST /EDU/WASHINGTON/CS/SUB1W /EDU/MIT/ATHENA/SUB1M
diff --git a/mechglue/src/krb5-config.M b/mechglue/src/krb5-config.M
new file mode 100644
index 000000000..c0a0fa140
--- /dev/null
+++ b/mechglue/src/krb5-config.M
@@ -0,0 +1,74 @@
+.\" krb5-config.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\"
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH KRB5-CONFIG 1
+.SH NAME
+krb5-config \- tool for linking against MIT Kerberos libraries
+.SH SYNOPSIS
+.B krb5-config
+[ \fB--help\fP | \fB--all\fP | \fB--version\fP | \fB--vendor\fP | \fB--prefix\fP | 
+\fB--exec-prefix\fP | \fB--cflags\fP | \fB--libs\fP libraries ]
+.br
+.SH DESCRIPTION
+.I krb5-config
+tells the application programmer what special flags to use to compile
+and link programs against the installed Kerberos libraries.
+.SH OPTIONS
+.TP
+\fB\--help\fP
+print usage message.  This is the default.
+.TP
+\fB\--all\fP
+prints version, vendor, prefix and exec-prefix.
+.TP
+\fB\--version\fP
+prints the version of the installed Kerberos implementation.
+.TP
+\fB\--vendor\fP
+prints the vendor of the installed Kerberos implementation.
+.TP
+\fB\--prefix\fP 
+prints the prefix with which Kerberos was built.
+.TP
+\fB\--exec-prefix\fP 
+prints the exec-prefix with which Kerberos was built.
+.TP
+\fB\--cflags\fP 
+prints the compiler flags with which Kerberos was built.
+.TP
+\fB\--libs\fP \fIlibraries\fP 
+list compiler options required to link with \fIlibraries\fP.  Possible 
+values for \fIlibraries\fP are:
+.sp
+.nf
+.in +.5i
+krb5         Kerberos 5 application
+gssapi       GSSAPI application with Kerberos 5 bindings
+krb4         Kerberos 4 application
+kadm-client  Kadmin client
+kadm-server  Kadmin server
+kdb          Application that accesses the kerberos database
+.in -.5i
+.fi
+.SH SEE ALSO
+kerberos(1), cc(1)
diff --git a/mechglue/src/krb5-config.in b/mechglue/src/krb5-config.in
new file mode 100755
index 000000000..dc9baa465
--- /dev/null
+++ b/mechglue/src/krb5-config.in
@@ -0,0 +1,221 @@
+#!/bin/sh
+
+# Copyright 2001, 2002, 2003 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+#
+
+# Configurable parameters set by autoconf
+version_string="Kerberos 5 release @KRB5_VERSION@"
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+CC_LINK='@CC_LINK@'
+KRB4_LIB=@KRB4_LIB@
+DES425_LIB=@DES425_LIB@
+KDB5_DB_LIB=@KDB5_DB_LIB@
+LDFLAGS='@LDFLAGS@'
+RPATH_FLAG='@RPATH_FLAG@'
+PTHREAD_CFLAGS='@PTHREAD_CFLAGS@'
+
+LIBS='@LIBS@'
+GEN_LIB=@GEN_LIB@
+
+# Defaults for program
+library=krb5
+
+# Some constants
+vendor_string="Massachusetts Institute of Technology"
+
+# Process arguments
+# Yes, we are sloppy, library specifications can come before options
+while test $# != 0; do
+    case $1 in
+	--all)
+	    do_all=1
+	    ;;
+	--cflags)
+	    do_cflags=1
+	    ;;
+	--deps)
+	    do_deps=1
+	    ;;
+	--exec-prefix)
+	    do_exec_prefix=1
+	    ;;
+	--help)
+	    do_help=1
+	    ;;
+	--libs)
+	    do_libs=1
+	    ;;
+	--prefix)
+	    do_prefix=1
+	    ;;
+	--vendor)
+	    do_vendor=1
+	    ;;
+	--version)
+	    do_version=1
+	    ;;
+	krb5)
+	    library=krb5
+	    ;;
+	gssapi)
+	    library=gssapi
+	    ;;
+	krb4)
+	    library=krb4
+	    ;;
+	kadm-client)
+	    library=kadm_client
+	    ;;
+	kadm-server)
+	    library=kadm_server
+	    ;;
+	kdb)
+	    library=kdb
+	    ;;
+	*)
+	    echo "$0: Unknown option \`$1' -- use \`--help' for usage"
+	    exit 1
+    esac
+    shift
+done
+
+# If required options - provide help
+if test -z "$do_all" -a -z "$do_version" -a -z "$do_vendor" -a -z "$do_prefix" -a -z "$do_vendor" -a -z "$do_exec_prefix" -a -z "$do_cflags" -a -z "$do_libs"; then
+    do_help=1
+fi
+
+
+if test -n "$do_help"; then
+    echo "Usage: $0 [OPTIONS] [LIBRARIES]"
+    echo "Options:"
+    echo "        [--help]          Help"
+    echo "        [--all]           Display version, vendor, and various values"
+    echo "        [--version]       Version information"
+    echo "        [--vendor]        Vendor information"
+    echo "        [--prefix]        Kerberos installed prefix"
+    echo "        [--exec-prefix]   Kerberos installed exec_prefix"
+    echo "        [--cflags]        Compile time CFLAGS"
+    echo "        [--libs]          List libraries required to link [LIBRARIES]"
+    echo "Libraries:"
+    echo "        krb5              Kerberos 5 application"
+    echo "        gssapi            GSSAPI application with Kerberos 5 bindings"
+    echo "        krb4              Kerberos 4 application"
+    echo "        kadm-client       Kadmin client"
+    echo "        kadm-server       Kadmin server"
+    echo "        kdb               Application that accesses the kerberos database"
+    exit 0
+fi
+
+if test -n "$do_all"; then
+    all_exit=
+    do_version=1
+    do_prefix=1
+    do_exec_prefix=1
+    do_vendor=1
+    title_version="Version:     "
+    title_prefix="Prefix:      "
+    title_exec_prefix="Exec_prefix: "
+    title_vendor="Vendor:      "
+else
+    all_exit="exit 0"
+fi
+
+if test -n "$do_version"; then
+    echo "$title_version$version_string"
+    $all_exit
+fi
+
+if test -n "$do_vendor"; then
+    echo "$title_vendor$vendor_string"
+    $all_exit
+fi
+
+if test -n "$do_prefix"; then
+    echo "$title_prefix$prefix"
+    $all_exit
+fi
+
+if test -n "$do_exec_prefix"; then
+    echo "$title_exec_prefix$exec_prefix"
+    $all_exit
+fi
+
+if test -n "$do_cflags"; then
+    echo "-I${includedir}"
+fi
+
+
+if test -n "$do_libs"; then
+    # Ugly gross hack for our build tree
+    lib_flags=`echo $CC_LINK | sed -e 's/\$(CC)//' \
+	    -e 's/\$(PURE)//' \
+	    -e 's#\$(PROG_RPATH)#'$libdir'#' \
+	    -e 's#\$(PROG_LIBPATH)#-L'$libdir'#' \
+	    -e 's#\$(RPATH_FLAG)#'"$RPATH_FLAG"'#' \
+	    -e 's#\$(LDFLAGS)#'"$LDFLAGS"'#' \
+	    -e 's#\$(PTHREAD_CFLAGS)#'"$PTHREAD_CFLAGS"'#' \
+	    -e 's#\$(CFLAGS)#'"$CFLAGS"'#'`
+
+    if test $library = 'kdb'; then
+	lib_flags="$lib_flags -lkdb5 $KDB5_DB_LIB"
+	library=krb5
+    fi
+
+    if test $library = 'kadm_server'; then
+	lib_flags="$lib_flags -lkadm5srv -lkdb5 $KDB5_DB_LIB"
+	library=kadm_common
+    fi
+
+    if test $library = 'kadm_client'; then
+	lib_flags="$lib_flags -lkadm5clnt"
+	library=kadm_common
+    fi
+
+    if test $library = 'kadm_common'; then
+	lib_flags="$lib_flags -lgssrpc"
+	library=gssapi
+    fi
+
+    if test $library = 'gssapi'; then
+	lib_flags="$lib_flags -lgssapi_krb5"
+	library=krb5
+    fi
+
+    if test $library = 'krb4'; then
+	lib_flags="$lib_flags $KRB4_LIB $DES425_LIB"
+	library=krb5
+    fi
+
+    if test $library = 'krb5'; then
+	lib_flags="$lib_flags -lkrb5 -lk5crypto -lcom_err -lkrb5support $GEN_LIB $LIBS"
+    fi
+
+    echo $lib_flags
+fi
+
+exit 0
diff --git a/mechglue/src/krb524/.Sanitize b/mechglue/src/krb524/.Sanitize
new file mode 100644
index 000000000..52d0746f8
--- /dev/null
+++ b/mechglue/src/krb524/.Sanitize
@@ -0,0 +1,45 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+README
+configure
+configure.in
+cnv_tkt_skey.c
+conv_princ.c
+conv_tkt.c
+k524init.c
+krb524d.h
+krb524_prot
+krb524d.c
+test.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/krb524/ChangeLog b/mechglue/src/krb524/ChangeLog
new file mode 100644
index 000000000..9bf6ff104
--- /dev/null
+++ b/mechglue/src/krb524/ChangeLog
@@ -0,0 +1,1014 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb524d.c: Include k5-int.h instead of krb5.h.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KDB_DEP_LIB): Use DL_LIB and THREAD_LINKOPTS
+	instead of explicitly using -ldl and -lpthread.
+
+	Novell merge.
+	* Makefile.in:
+	* krb524d.c:
+
+2004-09-08  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-unix): Install krb524d manpage.
+
+2004-09-07  Alexandra Ellwood  <lxs@mit.edu>
+
+	* krb524d.M: Added a man page for krb524d.
+
+2004-08-31  Tom Yu  <tlyu@mit.edu>
+
+	* krb524d.c: Fix double-free vulnerabilities.
+
+2004-08-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb524d.c (do_connection): Use socklen_t for the size of the
+	address from recvfrom.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Removed.  Directory configured from top level
+	now.
+	* Makefile.in (thisconfigdir, mydir): Updated.
+	(MY_SUBDIRS): Define to just ".".
+
+2004-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't invoke macros for library build support.
+	Don't look for awk.
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SERVER_OBJS, krb524d): Link against apputils lib
+	instead of using LIBOBJS.
+
+2003-12-15  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean-unix): Clean up more files now that STLIBOBS
+	is not used (introduced in 1491). Some files were missed.
+
+2003-09-02  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Apply patch from Cesar
+	Garcia to fix lifetime computation.
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Call KRB5_AC_NEED_DAEMON instead of checking
+	whether daemon() prototype is needed.
+	* Makefile.in (SERVER_OBJS): Use @LIBOBJS@.
+
+2003-08-11  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Call krb_create_ticket
+	instead of local version.  Remove local version of
+	krb_create_ticket.  This file no longer gets included into a
+	krb524 library, so accessing internal functions isn't that big of
+	an issue anymore.
+
+2003-06-12  Tom Yu  <tlyu@mit.edu>
+
+	* krb524.c (krb524_convert_creds_kdc, krb524_init_ets): Mark as
+	KRB5_CALLCONV_WRONG.
+	(krb524_init_ets): Takes a krb5_context.
+
+2003-06-09  Tom Yu  <tlyu@mit.edu>
+
+	* krb524.c: Fix copyright notice.
+
+2003-06-05  Jeffrey Altman  <jaltman@mit.edu>
+
+	* Makefile.in: Build krb524.dll on Windows.
+
+	* krb524.c: New file; stub for Windows krb524.dll.
+
+2003-06-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* k524init.c (main): Remove debugging printf.
+
+2003-05-29  Alexandra Ellwood  <lxs@mit.edu>
+
+	* krb524d.h: removed invalid Mac pragmas
+
+2003-05-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* k524init.c (main): Call krb5_524_convert_creds instead of
+	krb524_convert_creds_kdc.
+
+	* Makefile.in ($(OUTPRE)k524init.exe): Don't depend on K524DEP.
+
+2003-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_creds.c, encode.c, globals.c, sendmsg.c: Deleted.  Contents
+	added to krb5 library.
+	* getcred.c, misc.c: Deleted.
+	* krb524.h: Library declarations moved to krb5.hin and k5-int.h.
+	Remainder renamed to krb524d.h.
+	* krb524_err.et: Moved to lib/krb5/error_tables.
+	* cnv_tkt_skey.c: Include krb524d.h, not krb524.h.
+	(krb524d_debug): Define new variable.  Replace all references to
+	krb524_debug.
+	* conv_princ.c: Don't include krb524.h.
+	* k524init.c: Don't include krb524.h.
+	(main): Don't call krb524_init_ets.
+	* krb524d.c: Include krb524d.h, not krb524.h.
+	(encode_v4tkt): New function pointer variable.
+	(main): Initialize it using krb5int_accessor.
+	* test.c: Don't include krb524.h.
+	(main): Don't set krb524_debug, and don't call krb524_init_ets.
+	* Makefile.in: Don't pull in library makefile fragments.
+	(LIB, LIBMAJOR, LIBMINOR, RELDIR): Deleted.
+	(KRB524_DEPLIB, KRB524_LIB, STOBJLISTS, STLIBOBJS): Deleted.
+	(GENS, KRB524_HDR, KRB524_ERR_HDR): Deleted.
+	(SRCS): Remove deleted/moved files.
+	(all-unix): Don't depend on $(GENS) on includes.
+	(includes, all-windows): Don't depend on headers.
+	($(KRB524_HDR), $(KRB524_ERR_HDR)): Delete rules.
+	(all-windows): Comment out dependency on $(K524LIB) for now.
+	(CLIENT_OBJS, SERVER_OBJS): New variables.
+	(krb524test, krb524d, k524init): Don't use KRB524_*LIB, just
+	KRB5_*LIB.  Use *_OBJS lists.
+	(install-unix, clean-unix, clean-windows): Don't install or clean
+	libs or headers.
+	(krb524_err.c): Target deleted.
+
+2003-04-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* krb524d.c (do_connection): Use krb5_princ_size rather than
+	direct structure field access.
+
+2003-03-16  Sam Hartman  <hartmans@mit.edu>
+
+	* krb524d.c (handle_classic_v4): Do not support 3des enctypes as
+	they are insecure.  Also, by default do not allow krb4
+	cross-realm.
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Don't support 3des tickets
+
+2003-03-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Extract source IP
+	address in its proper size, not as 'long'.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+    * cnv_tkt_skey.c, conv_creds.c, conv_princ.c, encode.c, sendmsg.c: 
+      Removed Mac-specific includes.
+    
+    * conv_creds.c: If we are on the Mac and using the CCAPI, set
+      the string_to_key type to MIT.
+      
+    * krb524.h: Removed enumsalwaysint because there are no enums in this 
+      header.  Also include krb524_err with <> because on Mac OS X both
+      are public headers and should not be included with "".
+      
+    * Makefile.in: set KRB524_PRIVATE while building so that Darwin builds
+      see these prototypes.  Otherwise the Darwin build will fail.
+
+2003-01-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (clean-windows): Remove $(GENS).
+	(krb524_err.c): Depend on krb524_err.et.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_INSTALL.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2002-12-06  Tom Yu  <tlyu@mit.edu>
+
+	* sendmsg.c (krb524_sendto_kdc): Update calls to locate_server()
+	and locate_kdc() to restrict protocol family to IPv4.
+
+2002-09-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (EXTRADEPSRCS): New variable.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(KRB524_HDR), $(KRB524_ERR_HDR)): Quote target of
+	copy on Windows.
+
+2002-08-27  Sam Hartman  <hartmans@mit.edu>
+
+	* README: Document  new afs_krb5 configuration information
+
+	* krb524d.c (afs_return_v4): New function  to determine if we have
+	been configured to return v4 tickets for afs or use the afs
+	krb5-encpart proposal
+	(do_connection):  Call afs_return_v4 and use its result
+
+	2002-08-26  Sam Hartman  <hartmans@mit.edu>
+
+	* RELEASE_NOTES: Delete OV release notes now with 100% incorrect
+	content 
+
+2002-08-22  Sam Hartman  <hartmans@mit.edu>
+
+	* krb524d.c (do_connection): Add support for  AFS
+	krb5-encpart-only per discussion with jhutz and lha
+	(handle_classic_v4): Split out code for handling v4 tickets since
+	it needs to be called multiple times
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-15  Tom Yu  <tlyu@mit.edu>
+
+	* krb524d.c (kdc_get_server_key): Check for DISALLOW_ALL_TIX and
+	DISALLOW_SVR when looking up server key.
+
+2002-07-24  Ezra Peisach  <epeisach@bu.edu>
+
+	* krb524.h: Need to include port-sockets.h before socket-utils.h
+	for windows for struct sockaddr_in.
+
+2002-07-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* krb524.h: Include socket-utils.h instead of port-sockets.h for
+	socklen_t definition.
+
+2002-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendmsg.c (krb524_sendto_kdc): Accept new arguments for local
+	address; pass them through to sendto_udp.
+	* krb524.h: Include port-sockets.h.
+	(krb524_sendto_kdc): Update declaration.
+	* conv_creds.c: Include socket-utils.h.
+	(krb524_convert_creds_kdc): Get local-address info from
+	krb524_sendto_kdc.  On Mac, store the IPv4 address in the v4
+	credentials.
+
+2002-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendmsg.c (krb524_sendto_kdc): Accept new args for local address
+	return, pass them through to sendto_udp.
+	* conv_creds.c: Include socket-utils.h.
+	(krb524_convert_creds_kdc): 
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_creds.c: Include port-sockets.h instead of winsock.h or
+	netinet/in.h.
+	* krb524.h: Forward-declare struct types sockaddr, sockaddr_in.
+
+2002-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb524.h: Put # for cpp directives in first column.
+
+2002-07-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendmsg.c (krb524_sendto_kdc): Update sendto_udp calling
+	sequence; pass 0 for now.
+
+2002-06-14  Tom Yu  <tlyu@mit.edu>
+
+	* krb524.h: Change multiple-inclusion test macro to not stomp on
+	implementation namespace.  Fix up BEGIN_DECLS.
+
+	* krb524.h: Back out erroneous merge of post-1.2.5 change
+	temporarily.
+
+2002-06-14  Alexandra Ellwood <lxs@mit.edu>
+
+	* krb524.h: Updated C++ protection to not interfere with emacs
+	auto indentation and added KRB524_PRIVATE macro for Mac OS X to
+	control visibility of function prototypes
+
+	* krb524.h: Added C++ protection and Mac pragmas
+
+	* krb524.h, cnv_tkt_skey.c, conv_creds.c, conv_princ.c, encode.c,
+	misc.c, sendmsg.c: Updated header paths on Mac OS X so that we
+	correctly include the autogenerated krb524.h
+
+	* conv_creds.c, cnv_tkt_skey.c: added cast to remove warning.
+
+	* krb524.h: Updated to new Mac OS header layout.
+
+	* sendmsg.c: k5-int.h should be included as a local header
+
+	[pullups from 1-2-2-branch]
+
+2002-06-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (WINLIBS): Use ws2_32.lib instead of wsock32.lib.
+
+2002-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendmsg.c: Include fake-addrinfo.h.  Don't include
+	sys/select.h.
+	(krb524_sendto_kdc): Update for addrlist, locate_server,
+	locate_kdc changes.  Rip out network code and call
+	internals.sendto_udp instead.
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* encode.c, cnv_tkt_skey.c: Need port-sockets.h for Win32 (now
+	that using WIN32_LEAN_AND_MEAN).
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb524d.c (lookup_service_key): Copy key block and free up
+	keytab entry data.
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb524d.c (cleanup_and_exit): Call krb5_klog_close().
+
+	* encode.c (encode_bytes, decode_bytes): Make length field
+	unsigned to clean up unsigned/signed warnings.
+
+2001-10-10  Ken Raeburn  <raeburn@mit.edu>
+	    Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in (KRB524_ERR_HDR): New variable.
+	(includes): Depend on headers in include directory, not local
+	ones.  Don't define any commands to run here.
+	($(KRB524_HDR), $(KRB524_ERR_HDR)): Define UNIX and Windows
+	versions of commands to run for these targets.
+	(../include/krb524_err.h): Delete dependence on "includes".
+
+2001-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Put "##WIN32##" prefix on lines added in last
+	change, otherwise UNIX Make complains about STLIBOBJS referencing
+	itself.
+
+2001-09-28  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add KRB524_STATIC_HACK for Windows build so that we
+	can generate a k524init binary that has an static copy of the krb5
+	library and does not depend on krb5 nor krb524 DLLs.  This is so
+	that we can distribute a standalone k524init binary before 1.3
+	goes out.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Use $(srcdir).
+	(../include/krb524_err.h): Force build of "includes".
+
+2001-08-08    <epeisach@mit.edu>
+
+	* cnv_tkt_skey.c (HOST_BYTE_ORDER): When casting const int * to
+	const char * instead of simply char *.
+
+2001-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* conv_creds.c: Nuke prototype in file.
+
+	* krb524.h: Replace profile for krb524_send_message() with
+ 	krb524_sendto_kdc(). (krb524_send_message no longer exists).
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Test need for daemon prototype.
+
+	* krb524d.c: Provide daemon prototype if needed.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb524d.c: Include <krb5/adm_proto.h> for krb5_log_init()
+	prototype.
+	(cleanup_and_exit) Conditionalize krb5_kt_close on keytab being
+	non-null.
+
+2001-06-20  Mitchell Berger  <mitchb@mit.edu>
+
+	* krb524d.c: Call krb5_klog_init before the first point where the
+	klog facility may be used, delete ifdef'd out code to make that
+	call from later in the file, conditionalize kadm5_destroy on the
+	handle being non-null, and correct an indentation error.
+
+2001-06-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendmsg.c (krb524_sendto_kdc): Use new locate_server interface.
+
+2001-06-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* test.c (print_key): Pass in des_cblock* instead of char *.
+	(krb5_print_keyblock): Cast argument to C_Block_print to des_cblock *. 
+	(krb4_print_ticket): For printf formats expecting a long, cast
+	arguments as such.
+
+2001-06-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for unistd.h.
+	* k524init.c: Only include unistd.h if it's available.
+
+	* krb524d.c: Include stdarg.h.
+	(main): Accept new argument -p to indicate port number to use;
+	fall back to KRB524_SERVICE and then KRB524_PORT.  In error
+	messages, use only part of program name following last '/'.
+	(usage): Updated.
+	(krb5_free_keyblock_contents): Delete disabled function.
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* k524init.c: Inculde unistd.h for getopt() prototype.
+
+	* test.c (do_remote): Comment out unused variables. 
+
+	* sendmsg.c (krb524_sendto_kdc): Cleanup assignment in conditional.
+
+2001-05-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendmsg.c (krb524_sendto_kdc): Do fallback if KRB5_REALM_UNKNOWN
+	is returned, as might happen if the DNS support is not enabled.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_creds.c (broken, krb524_convert_creds_plain): Unused code
+	deleted.
+
+	* sendmsg.c (krb524_sendto_kdc): Updated to use new
+	krb5int_locate_server function, via internals-accessor hook.
+
+2001-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* k524init.c (prog): New variable.
+	(main): Set it, and use it when printing error messages.  When
+	reinitializing v4 ticket file, reject case where client and server
+	realms are different.  Print krb4 errors properly.
+
+	* conv_princ.c (krb524_convert_princs): Accept new arg SREALM,
+	passed through to krb5_524_conv_principal.
+	* krb524.h (krb524_convert_princs): Update prototype.
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Pass extra arg.
+	Reject tickets with transited realms for simplicity.
+	* conv_creds.c (krb524_convert_creds_plain): Pass extra arg.  Use
+	the server realm instead of the client realm.
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Permit non-CRC DES
+	enctypes; patch from Assar Westerlund.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_creds.c, encode.c, krb524.h, test.c: Always use prototypes,
+	don't use macros PROTOTYPE and KRB5_PROTOTYPE.
+
+2001-03-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb524d.c: Provide prototypes for local functions.
+
+	* test.c: Declare local functions static.
+
+2001-02-05  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Avoid double-free;
+	caller should free v5tkt.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* encode.c, krb524.h: encode_v4tkt() and decode_v4tkt() now take
+	unsigned int * lengths.
+
+	* krb524d.c (do_connection): Cast length fields in recvfrom() and
+	sendto() calls to int.
+
+	* sendmsg.c (krb524_sendto_kdc): Cast length fields in recv() and
+	send() calls to int.
+
+2000-10-06  Tom Yu  <tlyu@mit.edu>
+
+	* conv_creds.c (krb524_convert_creds_plain): Use time_to_life()
+	and life_to_time() to do lifetime calculations, including the
+	adjustment of start time, to match server-side calculations.
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Use time_to_life() and
+	life_to_time() to do lifetime calculations.  Adjust start time
+	backwards to deal with roundup so ticket expires at correct time.
+
+2000-10-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb524d.c (do_connection): Do not assume that sizeof(int) == 4. 
+
+	* encode.c (encode_int32, decode_int32): Do not assume 
+	sizeof(int) == 4.
+
+	* conv_creds.c (krb524_convert_creds_kdc): Do not assume
+	sizeof(int) == 4 in network packet. 
+
+	* cnv_tkt_skey.c (krb524int_krb_cr_tkt_int): Ensure that OTW flags
+	is one byte long. An error was introduced when prototypes were
+	widened.
+
+	* Makefile.in (includes): When testing to see if krb524_err.h
+	exists in the include directory, compare against the build trees
+	version.
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Install krb524.h and krb524_err.h header file so
+	applications can include for prototypes.
+
+2000-08-09  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c: Fix up static prototypes for
+	krb524int_krb_create_ticket(), krb524int_krb_cr_tkt_krb5(), and
+	krb524int_krb_cr_tkt_int(), as well as their definitions, so that
+	there aren't bare identifiers in the prototypes and so that there
+	aren't narrow types in the definitions.
+
+2000-07-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Fix build so we don't try to build an extra lib.
+	Fix up krb524 build so we default to krb5's krb4 but can use an
+	alternate.
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Make krb524 library and k524init program build on
+	Windows.
+
+	* krb524.def, libinit.c: Files needed to build on Windows.
+
+	* k524init.c: Use public krb_in_tkt() with realm paramter instead of
+	potentially private in_tkt() w/o realm parameter (which does not
+	even exist w/o the realm paramter in some krb4 libraries).  Use
+	krb_save_credentials() instead of tf_init() then
+	tf_save_credentials() then tf_close().
+
+	* cnv_tkt_skey.c: Put copy of krb_cr_tkt_krb5() and
+	krb_create_ticket() as static functions in this file, calling them
+	krb524int_*().  Call these functions instead of the ones in the
+	MIT krb4 library included in the krb5 tree.
+	
+	* conv_princ.c: Remove unused headers.
+
+	* k524init.c, cnv_tkt_skey.c, conv_creds.c, encode.c, misc.c,
+	sendmsg.c, test.c: Do not include Unix headers on Windows.
+
+	* sendmsg.c (krb524_sendto_kdc): Fix call to krb5_locate_kdc() to
+	use right number and types of parameters.  Use krb5int_accessor()
+	to get at internals: krb5_locate_kdc(), krb5_max_dgram_size,
+	krb5_skdc_timeout_1, and krb5_skdc_timeout_shift.  (The latter 3
+	should probably be #defines...)
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* getcred.c (main): Use correct parameters for krb5_cc_default()
+	in case someone actually wants to build this file.
+	
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-18  Tom Yu  <tlyu@mit.edu>
+
+	* krb524d.c (do_connection): Convert to using new symbol for
+	DES3.
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Convert to using new
+	symbol for DES3.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Tue Sep  1 19:35:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Add
+	ENCTYPE_LOCAL_DES3_HMAC_SHA1 to the list of enctypes to bash.
+
+	* krb524d.c (do_connection): Add ENCTYPE_LOCAL_DES3_HMAC_SHA1 to
+	the list of enctypes to search.
+
+Wed Aug 19 13:40:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Call krb_cr_tkt_krb5
+	if necessary, depending on th enctype.  Force enctype to be raw
+	DES3 if it's another DES3 type.
+
+	* krb524d.c (kdc_get_server_key): Add integer kvno argument,
+ 	rename previous kvno arg as kvnop, to distinguish returned (found)
+	kvno from the input kvno.
+	(lookup_service_key): Add kvnop argument to allow for returned
+	kvno.
+	(do_connection): Search for DES3 keys as well as DES.  Get the
+	found kvno as well, and use that instead of the kvno of the
+	incoming ticket.
+
+Fri Jul 24 19:38:58 1998  Geoffrey King  <gjking@mit.edu>
+
+	* krb524d.c (main): Fork into the background by default, also
+	add a -nofork command line option.
+
+Sat Jul 18 22:10:29 1998  Geoffrey King  <gjking@mit.edu>
+
+	* krb524d.c (main): Remove the variable use_other_realm.
+	It is not actually necessary for the new -r realm code.
+
+Fri Jul 17 04:11:47 1998  Geoffrey King  <gjking@mit.edu>
+
+	* krb524d.c (main): Accept a -r command line option to specify
+	a realm other than the default one.
+
+Wed Jun 17 16:35:37 1998  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Handle null address
+	fields; actually use saddr (the address from the UDP header) to
+	generate the ticket address rather than just checking against it.
+
+	* conv_creds.c (krb524_convert_creds_plain): Punt address checks.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* k524init.c (main): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Wed Feb 18 16:04:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (thisconfigdir): Remove trailing slash.
+
+Thu Feb 12 21:58:56 1998  Tom Yu  <tlyu@mit.edu>
+
+	* sendmsg.c: Explicitly include k5-int.h in order to get proper
+	prototype of krb5_locate_kdc().
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Dec 11 23:30:30 1997  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c:
+	* conv_creds.c:
+	* conv_princ.c:
+	* encode.c:
+	* k524init.c:
+	* krb524d.c:
+	* misc.c:
+	* test.c: Don't include netdb.h or sys/socket.h if krb.h is
+	included; this works around an Ultrix bug where those headers
+	aren't protected against multiple inclusion.
+
+Mon Aug 18 13:02:31 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add AC_PROG_INSTALL as we do install here.
+
+Mon Aug 11 21:12:11 1997  Tom Yu  <tlyu@mit.edu>
+
+	* convt_tkt.c: Delete; it's not needed anymore.
+
+	* test.c: Remove reference to krb524_convert_creds_addr, as that
+	doesn't exist anymore.
+
+	* conv_creds.c: Clean up substantially to be less convoluted.
+
+	* sendmsg.c: Fix to not do a full series of timeouts on each
+	server; loop over the whole list before increasing the timeout.
+
+	* configure.in: Update to use the new library build system to
+	build libkrb524.
+
+	* Makefile.in: Update to reflect changes in the library.  Also,
+	use the new library build system to build libkrb524.
+
+Thu Aug  7 17:34:59 1997  Tom Yu  <tlyu@mit.edu>
+
+	* cnv_tkt_skey.c:
+	* krb524.h:
+	* krb524d.c: Add jik's patches for multihomed hosts.  Fixes
+	krb5-misc/275.
+
+Tue Feb 18 09:53:10 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* k524init.c, test.c, cnv_tkt_skey.c: Remove include of krb4-proto.h
+
+Tue Feb  4 20:13:37 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fix up krb4 library handling properly (hopefully).
+
+Sun Feb  2 10:06:22 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in, Makefile.in: Update to new build system rules
+
+Thu Dec  5 23:27:00 1996  Tom Yu  <tlyu@mit.edu>
+
+	* krb524d.c (main): Ignore SIGHUP for now. [27]
+
+Thu Dec  5 23:12:29 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Change the issue time
+		of the V4 ticket to be the current time (since the
+		lifetime of the V4 ticket was calculated assuming that the
+		issue time would be the current time).  [PR#283,PR#22]
+
+Mon Nov 11 16:23:32 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb524d.c (do_connection): only free v4/v5 keyblock contents and
+	v5 ticket *once*, in cleanup branch at the end.
+
+Thu Nov  7 15:45:16 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* test.c (main): 
+	* krb524d.c (main): 
+	* k524init.c (main): 
+	* getcred.c (main): Check the error return from
+ 		krb5_init_context(), and print an error message if
+ 		necessary.
+
+Wed Jul 24 02:18:02 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* test.c (krb4_print_ticket): s/KRB4_INT4/krb5_ui_4 so we work
+ 	with Athena Kerberos4.
+
+Wed Jul 24 01:14:27 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* encode.c: s/PROTOTYPE/KRB5_PROTOTYPE
+
+	* krb524.h (KRB5_PROTOTYPE): Use KRB5_PROTOTYPE not PROTOTYPE because the include file is installed and PROTOTYPE wasn't defined anyway. 
+
+Wed Jul 31 17:05:25 1996  Tom Yu  <tlyu@mit.edu>
+
+	* krb524d.c: Revert prior change due to shuffling of netdb.h
+
+Tue Jul 30 19:58:22 1996  Tom Yu  <tlyu@mit.edu>
+
+	* krb524d.c: Remove #include <netdb.h> (already gotten by
+		kadm5/admin.h)
+
+Fri Jul 19 20:22:47 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: added AC_PROG_AWK and USE_GSSAPI_LIBRARY
+
+Tue Jul  9 16:14:33 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krb524d.c: use kadm5 instead of kdb
+
+Tue Jul  9 07:16:39 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* test.c (krb4_print_ticket): Change addr to unsigned KRB4_32 from
+		long. 
+
+	* conv_creds.c (krb524_convert_creds_plain): Change addr to a four
+		byte unsigned integer (from long).
+
+Thu Jun 13 22:10:30 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to ET_RULES
+
+Mon May  6 12:09:44 1996  Richard Basch  <basch@lehman.com>
+
+	* conv_creds.c: Fallback to slave kdc's wasn't working; it was not
+		handling the error code KRB524_NOTRESP as an indicator that
+		the kdc is unreachable.
+
+Sun Mar 31 01:17:26 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): use context->clockskew
+	in all time bound checks.
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): for time periods that
+	would occupy greater than 128 ticks, use the CMU algorithm, based
+	on the table cmu_seconds. (In conjunction with the previous
+	changes, even non-CMU clients can be used for the full lifetime of
+	a V5 ticket by rerunning krb524init when their lower
+	interpretation of the end time is expired.)
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): rather than apply fit
+ 	an extended v5 lifetime into a v4 range, give out a v4 ticket with
+ 	as much of the v5 lifetime is available "now" instead.
+
+Tue Mar 19 17:07:44 1996  Richard Basch  <basch@lehman.com>
+
+	* conv_creds.c (krb524_convert_creds_plain):
+	if the v5 lifetime is greater than the max v4 lifetime, use the max
+	v4 lifetime (0xff), rather than masking it with 0xff.
+
+Fri Jan 12 04:37:23 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): rather than apply fit
+ 	an extended v5 lifetime into a v4 range, give out a v4 ticket with
+ 	as much of the v5 lifetime is available "now" instead.
+
+Sat Jan 27 01:31:12 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krb524d.c (kdc_get_server_key): If an enctype is given, then use
+        iit even after falling back from trying a v4salt.  If we don't, we
+        have a good chance fo getting the DES3 TGT service key, and that
+        just doesn't do what we want.
+
+Thu Jan 25 02:07:46 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* cnv_tkt_skey.c (krb524_convert_tkt_skey): Take both a v5 and v4
+ 	service key.  Use the v5 service key to decrypt the v5 ticket, and
+ 	the v4 service key to encrypt the v4 ticket.
+
+	* krb524d.c (do_connection): Use a separate v5 and v4 service key
+ 	so that if the KDC chooses to encrypt the v5 ticket in something
+ 	besides ENCTYPE_DES_CBC_CRC, we don't lose.  Also, make sure we
+ 	free keyblock contents and tickets on error.
+	(lookup_service_key): Pass enctype to kdc_get_server_key
+
+	(kdc_get_server_key):  Only try for v4 salt if the enctype is
+	DES_CRC.  Take enctype as an argument.  This creates a problem
+	if the server key has a normal and v4 salt of ENCTYPE_DES_CBC_CRC
+	but I can't think of a good answer to this.
+
+
+	* k524init.c (main):  Use crc32 not md5.
+
+Wed Jan 24 20:05:47 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* krb524d.c (kdc_get_server_key): Try to find a v4 salt type key,
+ 	else try any des_crc32 key, else fail.
+	(do_connection): Lookup a crc32 key not an md5 key.
+	(init_master): Handle reading kdc profile.
+
+Sun Nov 12 04:29:08 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* conv_creds.c (krb524_convert_creds_kdc): loop through all of the
+	addresses returned by krb5_locate_kdc, don't just try the first one.
+	* krb524d.c (do_connection): check for particular failures of
+	decode_krb5_ticket, as well as for messages that are one int long
+	(which will eliminate our own error replies.)
+
+Mon Oct  9 11:34:24 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: s/test/krb524test/ to handle screw case where test
+		is built and interferes with configure.
+
+Mon Sep 25 00:15:47 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb524d.c (do_connection): if recvfrom failed, just return,
+	don't try to use the (likely invalid) sockaddr in a reply message.
+
+Thu Sep 14 17:36:11 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb524d.c (usage): needs to get context to pass to
+	cleanup_and_exit so it does get freed, since it is allocated
+	before parsing arguments.
+	(main): change caller as well.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+
+        * cnv_tkt_skey.c, conv_creds.c, get_cred.c k524init.c krb524d.c,
+	* test.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Wed Sep  6 00:11:53 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb524d.c (main): set timeout inside while loop to prevent spin.
+	(cleanup_and_exit): free master_princ or close keytab, and free
+	the global context, to eliminate spurious storage use in malloc
+	debugging.
+	(init_master): free realm.
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * cnv_tkt_skey.c, getcred.c, k524init.c, krb524d.c, test.c : 
+		Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate.
+
+Thu Aug 24 18:40:22 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+
+Mon Aug 07 11:25:53 1995  Chris Provenzano  (proven@mitedu)
+
+	* krb524d.c: Hacks to get it to compile with new kdb format.
+
+
+Thu Jul 27 15:14:15 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krb524d.c - Use the etype which is supplied in the krb5_keytype_array
+		specified by the master key type.
+
+
+Mon Jul 17 15:15:01 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krb524d.c - Add NULL stash file argument to krb5_db_fetch_mkey().
+
+
+
+Fri Jul 7 16:07:21 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling and LDFLAGS.
+	* configure.in - Add USE_<mumble> and KRB5_LIBRARIES.
+
+Thu Jul 13 17:22:17 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in :  Include sys/select.h if present.
+
+
+
+Fri Jun 30 14:38:56 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add --with-dbm to select between Berkeley and DBM
+		KDC database format.
+
+Wed Jun 28 20:14:35 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* test.c: use PROTOTYPE.
+
+Wed Jun 28 17:32:51 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* test.c, k524init.c, getcred.c: rewrote for old style definitiions.
+	* encode.c: use PROTOTYPE instead of KRB5_PROTOTYPE.
+
+Wed Jun 28 03:04:38 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb524d.c: changed main, krb5_free_keyblock_contents to use old
+	style definitions.
+
+Tue Jun 27 20:27:06 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* encode.c: make declarations use KRB5_PROTOTYPE, and use old
+	style definitions, per V5 coding style.
+
+Tue Jun 27 15:54:57 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* cnv_tkt_skey.c - Cast key contents argument to conform to prototype.
+	* encode.c - Cast argument to match argument list of encode_bytes().
+	* krb524d.c - Add signal name argument to conform to prototype.
+	* sendmsg.c - Cast second argument to connect(2).
+	* test.c - Cast arguments to print_key() and ctime(3).  Cast assignment
+		to key.contents.
+
+
+Thu Jun 22 11:55:23 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krb524d.c - Change KRB_CONVERT_KEY_OUTOF_DB to decrypt_key calls.
+
+
+Fri Jun 16 17:09:09 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* k524init.c - Inline code from krb_save_credentials, it doesn't
+		exist for some K4 (e.g. /usr/athena).
+
+
+Thu Jun 15 17:56:43 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Wed Jun 14 19:28:33 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: added install rules
+
+Fri Jun  9 19:16:49 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Tue Jun  6 20:59:56 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* test.c (do_remote): Case sockaddr_in * to sockaddr * in calling
+		krb524_convert_creds_addr. 
+		(krb4_print_ticket): issue_time should be a KRB4_32
+
+	* encode.c (encode_v4tkt): Cast a the unsigned long mbz field of
+		KTEXT to krb5_int32 for call to encode_int32.
+
+	* conv_creds.c (krb524_convert_creds_addr): Cast sockaddr * to
+		sockaddr_in *. 
+
+Tue Jun 6 17:25:20 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in : Change $(ARCHIVE) to $(ARADD) so that updates to the
+		library replace modules instead of appending them.
+	* cnv_tkt_skey.c, conv_creds.c : Concatenate the two strings which
+		comprise the print format.  Some compilers cannot deal with
+		<string><string> (e.g. Ultrix).
+
+Mon Jun  5 22:25:33 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in, cnv_tkt_skey.c, conv_creds.c, conv_princ.c,
+		conv_tkt.c, encode.c, getcred.c, k524init.c, krb524.h,
+		krb524d.c, misc.c, sendmsg.c, test.c, configure.in:
+		Updated to use autoconf, and to use the new Kerberos
+		library API.  
+		
+Wed Mar 27 21:15:00 1995  Keith Vetter (keithv@fusion.com)
+
+	* renamed conv_tkt_skey.c to cnv_tkt_skey.c for DOS 8.3
+	   compatability.
+	* Makefile: reflected the above change
+
+Tue Feb 28 02:31:22 1995  John Gilmore  (gnu at toad.com)
+
+	* README, *.[ch]:  Avoid <...> includes for our include files.
+
+Thu Sep 15 10:47:27 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile, README, RELEASE_NOTES, conv_creds.c, conv_princ.c,
+	conv_tkt.c, conv_tkt.c, conv_tkt_skey.c, encode.c, getcred.c,
+	globals.c, k524init.c, krb524.h, krb524_err.et, krb524d.c, misc.c,
+	test.c: Applied new copyright notice (1993, Geer Zolat Associates
+		--> 1994, OpenVision Technologies, Inc.)
+
+
+	
+
+
+
diff --git a/mechglue/src/krb524/Makefile.in b/mechglue/src/krb524/Makefile.in
new file mode 100644
index 000000000..d7ecfa810
--- /dev/null
+++ b/mechglue/src/krb524/Makefile.in
@@ -0,0 +1,149 @@
+thisconfigdir=..
+myfulldir=krb524
+mydir=krb524
+BUILDTOP=$(REL)..
+KDB_DEP_LIB=$(DL_LIB) $(THREAD_LINKOPTS)
+
+# Copyright 1994 by OpenVision Technologies, Inc.
+# 
+# Permission to use, copy, modify, distribute, and sell this software
+# and its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appears in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of OpenVision not be used
+# in advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. OpenVision makes no
+# representations about the suitability of this software for any
+# purpose.  It is provided "as is" without express or implied warranty.
+# 
+# OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+# 
+
+DEFINES = -DUSE_MASTER -DKRB524_PRIVATE=1
+PROG_LIBPATH=-L$(TOPLIBD) $(KRB4_LIBPATH)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+##WIN32##!ifdef USE_ALTERNATE_KRB4_INCLUDES
+##WIN32##KRB4_INCLUDES=-I$(USE_ALTERNATE_KRB4_INCLUDES)
+##WIN32##!endif
+
+##WIN32##!ifdef USE_ALTERNATE_KRB4_LIB
+##WIN32##K4LIB=$(USE_ALTERNATE_KRB4_LIB)
+##WIN32##!endif
+
+K524LIB = $(OUTPRE)krb524.lib
+K524DEP = $(K524LIB)
+K524DEF = krb524.def
+WINLIBS = kernel32.lib ws2_32.lib user32.lib shell32.lib oldnames.lib \
+	version.lib advapi32.lib gdi32.lib
+
+LOCALINCLUDES= $(KRB4_INCLUDES) -I. -I$(srcdir)
+
+# Library sources
+SRCS	= \
+	$(srcdir)/conv_princ.c \
+	$(srcdir)/cnv_tkt_skey.c \
+	$(srcdir)/libinit.c	\
+    $(srcdir)/krb524.c
+
+EXTRADEPSRCS = \
+	$(srcdir)/test.c \
+	$(srcdir)/k524init.c \
+	$(srcdir)/krb524d.c
+
+##WIN32##!ifdef KRB524_STATIC_HACK
+##WIN32##LPREFIX=..\lib
+##WIN32##K5_GLUE=$(LPREFIX)\$(OUTPRE)k5_glue.obj
+##WIN32##KLIBS = $(LPREFIX)\krb5\$(OUTPRE)krb5.lib \
+##WIN32##	$(LPREFIX)\crypto\$(OUTPRE)crypto.lib \
+##WIN32##	$(BUILDTOP)\util\profile\$(OUTPRE)profile.lib \
+##WIN32##	$(LPREFIX)\des425\$(OUTPRE)des425.lib
+##WIN32##KLIB=$(KLIBS) $(DNSLIBS) $(K5_GLUE) $(CLIB)
+##WIN32##STLIBOBJS=$(STLIBOBJS:libinit=globals)
+##WIN32##K524DEP=$(STLIBOBJS)
+##WIN32##!endif
+
+all-unix:: krb524d krb524test k524init
+
+all-windows:: $(OUTPRE)k524init.exe $(K524LIB)
+
+krb524test: test.o $(KRB5_DEPLIB) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o krb524test test.o $(KRB5_LIB) $(KRB4COMPAT_LIBS)
+
+SERVER_OBJS= krb524d.o cnv_tkt_skey.o conv_princ.o
+CLIENT_OBJS= $(OUTPRE)k524init.$(OBJEXT)
+
+krb524d: $(SERVER_OBJS) $(KADMSRV_DEPLIBS) $(KRB5_DEPLIB) $(KRB4COMPAT_DEPLIBS) $(APPUTILS_DEPLIB)
+	$(CC_LINK) -o krb524d $(SERVER_OBJS) $(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_LIB) $(KRB4COMPAT_LIBS) $(APPUTILS_LIB)
+
+k524init: $(CLIENT_OBJS) $(KRB5_DEPLIB) $(KRB4COMPAT_DEPLIBS)
+	$(CC_LINK) -o k524init $(CLIENT_OBJS) $(KRB5_LIB) $(KRB4COMPAT_LIBS)
+
+$(K524LIB): $(OUTPRE)krb524.$(OBJEXT) $(OUTPRE)libinit.$(OBJEXT) $(KLIB) $(CLIB)
+	link $(DLL_LINKOPTS) -def:$(K524DEF) -out:$*.dll $** $(WINLIBS)
+
+$(OUTPRE)k524init.exe: $(OUTPRE)k524init.$(OBJEXT) $(KLIB) $(K4LIB) $(CLIB) $(BUILDTOP)\util\windows\$(OUTPRE)getopt.lib
+	link $(EXE_LINKOPTS) -out:$@ $** $(WINLIBS)
+
+install-unix::
+	$(INSTALL_PROGRAM) krb524d $(DESTDIR)$(SERVER_BINDIR)/krb524d
+	$(INSTALL_PROGRAM) k524init $(DESTDIR)$(CLIENT_BINDIR)/krb524init
+	$(INSTALL_DATA) $(srcdir)/krb524d.M $(DESTDIR)$(SERVER_MANDIR)/krb524d.8
+
+clean-unix::
+	$(RM) $(OBJS) core *~ *.bak #*
+	$(RM) krb524test krb524d k524init test.o $(CLIENT_OBJS) $(SERVER_OBJS)
+
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)conv_princ.$(OBJEXT): conv_princ.c $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h
+$(OUTPRE)cnv_tkt_skey.$(OBJEXT): cnv_tkt_skey.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  krb524d.h
+$(OUTPRE)libinit.$(OBJEXT): libinit.c
+$(OUTPRE)krb524.$(OBJEXT): krb524.c
+$(OUTPRE)test.$(OBJEXT): test.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(KRB_ERR_H_DEP)
+$(OUTPRE)k524init.$(OBJEXT): k524init.c $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h
+$(OUTPRE)krb524d.$(OBJEXT): krb524d.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(SRCTOP)/include/krb5/adm_proto.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  krb524d.h
diff --git a/mechglue/src/krb524/README b/mechglue/src/krb524/README
new file mode 100644
index 000000000..dd7ca9c23
--- /dev/null
+++ b/mechglue/src/krb524/README
@@ -0,0 +1,154 @@
+Copyright 1994 by OpenVision Technologies, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appears in all copies and
+that both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of OpenVision not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission. OpenVision makes no
+representations about the suitability of this software for any
+purpose.  It is provided "as is" without express or implied warranty.
+
+OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+
+Kerberos V5 to Kerberos V4 Credentials Converting Service, ALPHA RELEASE
+========================================================================
+
+krb524 is a service that converts Kerberos V5 credentials into
+Kerberos V4 credentials suitable for use with applications that for
+whatever reason do not use V5 directly.  The service consists of a
+server that has access to the secret key of the Kerberos service for
+which credentials will be converted, and a library for use by client
+programs that wish to use the server.
+
+The protocol is simple.  Suppose that a client C wishes to obtain V4
+credentials for a V5 service S by using the krb524 server.  The
+notation {C,S}_n represents a Vn service ticket for S for use by C.
+
+(1) C obtains V5 credentials, including a ticket {C,S}_5, for S by the
+normal V5 means.
+
+(2) C transmits {C,S}_5 to KRB524.
+
+(3) KRB524 converts {C,S}_5 into {C,S}_4.
+
+(4) KRB524 transmits {C,S}_4 to C.
+
+(5) C creates a V4 credentials strucuture from the plaintext
+information in the V5 credential and {C,S}_4.
+
+Steps (2) through (4) are encapsulated in a single function call in
+the krb524 library.
+
+An alternate conversion is provided for AFS servers that support the
+encrypted part of a krb5 ticket as an AFS token.  If the krb524d is
+converting a principal whose first component is afs and if the
+encrypted part of the ticket fits in 344 bytes, then it will default
+to simply returning the encrypted part of the ticket as a token.  If
+it turns out that the AFS server does not support the ticket, then
+users will get an unknown key version error and the krb524d must be
+configured to use v4 tickets for this AFS service.
+
+
+Obviously, not all V5 credentials can be completely converted to V4
+credentials, since the former is a superset of the latter.  The
+precise semantics of the conversion function are still undecided.
+UTSL.
+
+Programs contained in this release
+======================================================================
+
+krb524d [-m[aster]] [-k[eytab]]
+
+The krb524 server.  It accepts UDP requests on the krb524 service
+port, specified in /etc/services, or on port 4444 by default.  (A
+request for an official port assignment is underway.)  The -m argument
+causes krb524d to access the KDC master database directly; the -k
+argument causes krb524d to use the default keytab (and therefore only
+be able to convert tickets for services in the keytab).  Only one of
+-m or -k can be specified.
+
+test -remote server client service
+
+A test program that obtains a V5 credential for {client,service},
+converts it to a V4 credential, and prints out the entire contents of
+both versions.  It prompts for service's secret key, which it needs to
+decrypt both tickets in order to print them out.  Enter it as an eight
+digit ASCII hex number.
+
+k524init [-n] [-p principal]
+
+Convert a V5 credential into a V4 credential and store it in a V4
+ticket file.  The client is 'principal', or krbtgt at the V5 ccache's
+default principal's realm if not specified.  The -n argument causes
+the new ticket to be added to the existing ticket file; otherwise, the
+ticket file is initialized.
+
+Configuring krb524d AFS Conversion
+======================================================================
+
+The krb524d looks in the appdefaults  section of krb5.conf for an
+application called afs_krb5 to determine whether  afs principals
+support encrypted ticket parts as tokens.  The following configuration
+fragment says that afs/sipb.mit.edu@ATHENA.MIT.EDU supports the new
+token format but afs@ATHENA.MIT.EDU and
+afs/athena.mit.edu@ATHENA.MIT.EDU do not.  Note that the default is to
+assume afs servers support the new format.
+
+[appdefaults]
+afs_krb5 = { 
+	ATHENA.MIT.EDU = {
+		# This stanza describes principals in the
+		#ATHENA.MIT.EDU realm
+		afs = false
+		afs/athena.mit.edu = false
+		afs/sipb.mit.edu = true
+	}
+}
+
+
+Using libkrb524.a
+======================================================================
+
+To use libkrb524.a, #include "krb524.h", link against libkrb524.a,
+call krb524_init_ets() at the beginning of your program, and call one
+of the following two functions:
+
+int krb524_convert_creds_addr(krb5_creds *v5creds, CREDENTIALS *v4creds,
+			 struct sockaddr *saddr)
+
+int krb524_convert_creds_kdc(krb5_creds *v5creds, CREDENTIALS *v4creds)
+
+Both convert the V5 credential in v5creds into a V4 credential in
+v4creds.  One assumes krb524d is running on the KDC, the other uses an
+explicit host.  You only need to specify the address for saddr; the
+port is filled in automatically.
+
+Unresolved issues / Bugs
+======================================================================
+
+o krb524d requires access to the secret key of any service to be
+converted.  Should krb524d run on the KDC or on individual server
+machines?  The latter is more paranoid, since it prevents bugs in
+krb524d from provided unauthorized access to the master database.
+However, it also requires the client to provide the address of the
+server to be used.  The client will usually have this information
+(since presumably it will be sending the converted V4 credentials to
+the same server) but it may not be in a convenient form.  It seems
+"cleaner" to have krb524d run on the KDC.
+
+o Even if krb524d uses keytabs on server machines, it needs to be more
+flexible.  You only want to run one krb524d per host, so it has to be
+able to scan multiple keytabs.  This might get logistically messy.
+
+o This code is of alpha quality.  Bugs, omissions, memory leaks, and
+perhaps security holes still remain.  Do not use it (yet) in a
+production environment.
diff --git a/mechglue/src/krb524/cnv_tkt_skey.c b/mechglue/src/krb524/cnv_tkt_skey.c
new file mode 100644
index 000000000..97d8bbfdd
--- /dev/null
+++ b/mechglue/src/krb524/cnv_tkt_skey.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2003  by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.	Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "k5-int.h"		/* we need krb5_context::clockskew */
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef _WIN32
+#include "port-sockets.h"
+#else
+#include <sys/time.h>
+#include <netinet/in.h>
+#endif
+#include <krb.h>
+#include "krb524d.h"
+
+static int krb524d_debug = 0;
+
+/*
+ * Convert a v5 ticket for server to a v4 ticket, using service key
+ * skey for both.
+ */
+int krb524_convert_tkt_skey(context, v5tkt, v4tkt, v5_skey, v4_skey,
+			    saddr)
+     krb5_context context;
+     krb5_ticket *v5tkt;
+     KTEXT_ST *v4tkt;
+     krb5_keyblock *v5_skey, *v4_skey;
+     struct sockaddr_in *saddr;
+{
+     char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
+     char sname[ANAME_SZ], sinst[INST_SZ], srealm[REALM_SZ];
+     krb5_enc_tkt_part *v5etkt;
+     int ret, lifetime, v4endtime;
+     krb5_timestamp server_time;
+     struct sockaddr_in *sinp = (struct sockaddr_in *)saddr;
+     krb5_address kaddr;
+
+     v5tkt->enc_part2 = NULL;
+     if ((ret = krb5_decrypt_tkt_part(context, v5_skey, v5tkt))) {
+	  return ret;
+     }
+     v5etkt = v5tkt->enc_part2;
+
+     if (v5etkt->transited.tr_contents.length != 0) {
+	 /* Some intermediate realms transited -- do we accept them?
+
+	    Simple answer: No.
+
+	    More complicated answer: Check our local config file to
+	    see if the path is correct, and base the answer on that.
+	    This denies the krb4 application server any ability to do
+	    its own validation as krb5 servers can.
+
+	    Fast answer: Not right now.  */
+	  krb5_free_enc_tkt_part(context, v5etkt);
+	  v5tkt->enc_part2 = NULL;
+	  return KRB5KRB_AP_ERR_ILL_CR_TKT;
+     }
+     /* We could also encounter a case where luser@R1 gets a ticket
+	for krbtgt/R3@R2, and then tries to convert it.  But the
+	converted ticket would be one the v4 KDC code should reject
+	anyways.  So we don't need to worry about it here.  */
+
+     if ((ret = krb524_convert_princs(context, v5etkt->client, v5tkt->server,
+				     pname, pinst, prealm, sname,
+				     sinst, srealm))) {
+	  krb5_free_enc_tkt_part(context, v5etkt);
+	  v5tkt->enc_part2 = NULL;
+	  return ret;
+     }
+     if ((v5etkt->session->enctype != ENCTYPE_DES_CBC_CRC &&
+	  v5etkt->session->enctype != ENCTYPE_DES_CBC_MD4 &&
+	  v5etkt->session->enctype != ENCTYPE_DES_CBC_MD5) ||
+	 v5etkt->session->length != sizeof(C_Block)) {
+	  if (krb524d_debug)
+	       fprintf(stderr, "v5 session keyblock type %d length %d != C_Block size %d\n",
+		       v5etkt->session->enctype,
+		       v5etkt->session->length,
+		       (int) sizeof(C_Block));
+	  krb5_free_enc_tkt_part(context, v5etkt);
+	  v5tkt->enc_part2 = NULL;
+	  return KRB524_BADKEY;
+     }
+     
+     /* V4 has no concept of authtime or renew_till, so ignore them */
+     if (v5etkt->times.starttime == 0)
+	  v5etkt->times.starttime = v5etkt->times.authtime;
+     /* rather than apply fit an extended v5 lifetime into a v4 range,
+	give out a v4 ticket with as much of the v5 lifetime is available
+	"now" instead. */
+     if ((ret = krb5_timeofday(context, &server_time))) {
+         if (krb524d_debug)
+	      fprintf(stderr, "krb5_timeofday failed!\n");
+	 krb5_free_enc_tkt_part(context, v5etkt);
+	 v5tkt->enc_part2 = NULL;
+	 return ret;       
+     }
+     if ((server_time + context->clockskew >= v5etkt->times.starttime)
+	 && (server_time - context->clockskew <= v5etkt->times.endtime)) {
+	  lifetime = krb_time_to_life(server_time, v5etkt->times.endtime);
+	  v4endtime = krb_life_to_time(server_time, lifetime);
+	  /*
+	   * Adjust start time backwards if the lifetime value
+	   * returned by krb_time_to_life() maps to a longer lifetime
+	   * than that of the original krb5 ticket.
+	   */
+	  if (v4endtime > v5etkt->times.endtime)
+	      server_time -= v4endtime - v5etkt->times.endtime;
+     } else {
+          if (krb524d_debug)
+	       fprintf(stderr, "v5 ticket time out of bounds\n");
+	  krb5_free_enc_tkt_part(context, v5etkt);
+	  v5tkt->enc_part2 = NULL;
+	  if (server_time+context->clockskew < v5etkt->times.starttime)
+	       return KRB5KRB_AP_ERR_TKT_NYV;
+	  else if (server_time-context->clockskew > v5etkt->times.endtime)
+	       return KRB5KRB_AP_ERR_TKT_EXPIRED;
+	  else /* shouldn't happen, but just in case... */
+	    return KRB5KRB_AP_ERR_TKT_NYV;
+     }
+
+     kaddr.addrtype = ADDRTYPE_INET;
+     kaddr.length = sizeof(sinp->sin_addr);
+     kaddr.contents = (krb5_octet *)&sinp->sin_addr;
+
+     if (!krb5_address_search(context, &kaddr, v5etkt->caddrs)) {
+	 if (krb524d_debug)
+	     fprintf(stderr, "Invalid v5creds address information.\n");
+	 krb5_free_enc_tkt_part(context, v5etkt);
+	 v5tkt->enc_part2 = NULL;
+	 return KRB524_BADADDR;
+     }
+
+     if (krb524d_debug)
+	printf("startime = %ld, authtime = %ld, lifetime = %ld\n",
+	       (long) v5etkt->times.starttime,
+	       (long) v5etkt->times.authtime,
+	       (long) lifetime);
+
+     /* XXX are there V5 flags we should map to V4 equivalents? */
+     if (v4_skey->enctype == ENCTYPE_DES_CBC_CRC) {
+	 ret = krb_create_ticket(v4tkt,
+				 0, /* flags */			     
+				 pname,
+				 pinst,
+				 prealm,
+				 sinp->sin_addr.s_addr,
+				 (char *) v5etkt->session->contents,
+				 lifetime,
+				 /* issue_data */
+				 server_time,
+				 sname,
+				 sinst,
+				 v4_skey->contents);
+     }
+     else abort();
+     krb5_free_enc_tkt_part(context, v5etkt);
+     v5tkt->enc_part2 = NULL;
+     if (ret == KSUCCESS)
+	  return 0;
+     else
+	  return KRB524_V4ERR;
+}
diff --git a/mechglue/src/krb524/conv_princ.c b/mechglue/src/krb524/conv_princ.c
new file mode 100644
index 000000000..3359981ba
--- /dev/null
+++ b/mechglue/src/krb524/conv_princ.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "krb5.h"
+#include <krb.h>
+
+int krb524_convert_princs(context, client, server, pname, pinst, prealm, 
+			  sname, sinst, srealm)
+     krb5_context context;
+     krb5_principal client, server;
+     char *pname, *pinst, *prealm, *sname, *sinst, *srealm;
+{
+     int ret;
+     
+     if ((ret = krb5_524_conv_principal(context, client, pname, pinst, 
+					prealm)))
+	  return ret;
+     
+     return krb5_524_conv_principal(context, server, sname, sinst, srealm);
+}
diff --git a/mechglue/src/krb524/k524init.c b/mechglue/src/krb524/k524init.c
new file mode 100644
index 000000000..9a988205f
--- /dev/null
+++ b/mechglue/src/krb524/k524init.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <krb5.h>
+#include "com_err.h"
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <netinet/in.h>
+#endif
+
+#include <krb.h>
+
+extern int optind;
+extern char *optarg;
+char *prog = "k524init";
+
+int main(argc, argv)
+     int argc;
+     char **argv;
+{
+     krb5_principal client, server;
+     krb5_ccache cc;
+     krb5_creds increds, *v5creds;
+     CREDENTIALS v4creds;
+     int code;
+     int option;
+     char *princ = NULL;
+     int nodelete = 0;
+     int lose = 0;
+     krb5_context context;
+     krb5_error_code retval;
+
+     if (argv[0]) {
+	 prog = strrchr (argv[0], '/');
+	 if (prog)
+	     prog++;
+	 else
+	     prog = argv[0];
+     }
+
+     retval = krb5_init_context(&context);
+     if (retval) {
+	     com_err(prog, retval, "while initializing krb5");
+	     exit(1);
+     }
+
+     while(((option =  getopt(argc, argv, "p:n")) != -1)) {
+	 switch(option) {
+	   case 'p':
+	     princ = optarg;
+	     break;
+	   case 'n':
+	     nodelete++;
+	     break;
+	   default:
+	     lose++;
+	     break;
+	 }
+     }
+
+     if (lose || (argc - optind > 1)) {
+	 fprintf(stderr, "Usage: %s [-p principal] [-n]\n", prog);
+	 exit(1);
+     }
+
+     if ((code = krb5_cc_default(context, &cc))) {
+	  com_err(prog, code, "opening default credentials cache");
+	  exit(1);
+     }
+
+     if ((code = krb5_cc_get_principal(context, cc, &client))) {
+	 com_err(prog, code, "while retrieving user principal name");
+	 exit(1);
+     }
+
+     if (princ) {
+	 if ((code = krb5_parse_name(context, princ, &server))) {
+	     com_err(prog, code, "while parsing service principal name");
+	     exit(1);
+	 }
+     } else {
+	 if ((code = krb5_build_principal(context, &server, 
+					  krb5_princ_realm(context, client)->length,
+					  krb5_princ_realm(context, client)->data,
+					  "krbtgt",
+					  krb5_princ_realm(context, client)->data,
+					  NULL))) {
+	     com_err(prog, code, "while creating service principal name");
+	     exit(1);
+	 }
+     }
+
+     if (!nodelete) {
+	 krb5_data *crealm = krb5_princ_realm (context, client);
+	 krb5_data *srealm = krb5_princ_realm (context, server);
+	 if (crealm->length != srealm->length
+	     || memcmp (crealm->data, srealm->data, crealm->length)) {
+	     /* Since krb4 ticket files don't store the realm name
+		separately, and the client realm is assumed to be the
+		realm of the first ticket, let's not store an initial
+		ticket with the wrong realm name, since it'll confuse
+		other programs.  */
+	     fprintf (stderr,
+		      "%s: Client and server principals' realm names are different;\n"
+		      "\tbecause of limitations in the krb4 ticket file implementation,\n"
+		      "\tthis doesn't work for an initial ticket.  Try `%s -n'\n"
+		      "\tif you already have other krb4 tickets, or convert the\n"
+		      "\tticket-granting ticket from your home realm.\n",
+		      prog, prog);
+	     exit (1);
+	 }
+     }
+
+     memset((char *) &increds, 0, sizeof(increds));
+     increds.client = client;
+     increds.server = server;
+     increds.times.endtime = 0;
+     increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+     if ((code = krb5_get_credentials(context, 0, cc, &increds, &v5creds))) {
+	  com_err(prog, code, "getting V5 credentials");
+	  exit(1);
+     }
+
+     if ((code = krb5_524_convert_creds(context, v5creds, &v4creds))) {
+	  com_err(prog, code, "converting to V4 credentials");
+	  exit(1);
+     }
+     
+     /* this is stolen from the v4 kinit */
+
+     if (!nodelete) {
+	 /* initialize ticket cache */
+	 code = krb_in_tkt(v4creds.pname,v4creds.pinst,v4creds.realm);
+	 if (code != KSUCCESS) {
+	     fprintf (stderr, "%s: %s trying to create the V4 ticket file",
+		      prog, krb_get_err_text (code));
+	     exit(1);
+	 }
+     }
+
+     /* stash ticket, session key, etc. for future use */
+     /* This routine does *NOT* return one of the usual com_err codes.  */
+     if ((code = krb_save_credentials(v4creds.service, v4creds.instance,
+				      v4creds.realm, v4creds.session,
+				      v4creds.lifetime, v4creds.kvno,
+				      &(v4creds.ticket_st), 
+				      v4creds.issue_date))) {
+	 fprintf (stderr, "%s: %s trying to save the V4 ticket\n",
+		  prog, krb_get_err_text (code));
+	 exit(1);
+     }
+
+     exit(0);
+}
diff --git a/mechglue/src/krb524/krb524.c b/mechglue/src/krb524/krb524.c
new file mode 100644
index 000000000..1eff72f00
--- /dev/null
+++ b/mechglue/src/krb524/krb524.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2003 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#ifdef _WIN32
+#include "krb5.h"
+
+#ifdef krb524_convert_creds_kdc
+#undef krb524_convert_creds_kdc
+#endif
+#ifdef krb524_init_ets
+#undef krb524_init_ets
+#endif
+
+int KRB5_CALLCONV_WRONG
+krb524_convert_creds_kdc(krb5_context context, krb5_creds *v5creds, struct credentials *v4creds)
+{
+	return(krb5_524_convert_creds(context,v5creds,v4creds));
+}
+
+void KRB5_CALLCONV_WRONG
+krb524_init_ets(krb5_context context)
+{
+	/* no-op */
+}
+#endif /* _WIN32 */
diff --git a/mechglue/src/krb524/krb524.def b/mechglue/src/krb524/krb524.def
new file mode 100644
index 000000000..e9ebfa033
--- /dev/null
+++ b/mechglue/src/krb524/krb524.def
@@ -0,0 +1,13 @@
+;----------------------------------------------------
+;   KRB524.DEF - KRB524.DLL module definition file
+;----------------------------------------------------
+
+; ****************************************************************************
+; Do not add any function to this file until you make sure the calling
+; convention for the exported function is KRB5_CALLCONV
+; ****************************************************************************
+
+
+EXPORTS
+    krb524_convert_creds_kdc
+    krb524_init_ets
diff --git a/mechglue/src/krb524/krb524_prot b/mechglue/src/krb524/krb524_prot
new file mode 100644
index 000000000..f83854d77
--- /dev/null
+++ b/mechglue/src/krb524/krb524_prot
@@ -0,0 +1,11 @@
+Protocol:
+
+	-> ASN.1 encoded V5 ticket
+	<- int status_code, [int kvno, encode_v4tkt encoded KTEXT_ST]
+
+kvno and V4 ticket are only included if status_code is zero.
+
+The kvno for the converted ticket is sent explicitly because the field
+is ASN.1 encoded in the krb5_creds structure; the client would have to
+decode (but not decrypt) the entire krb5_ticket structure to get it,
+which would be inefficient.
diff --git a/mechglue/src/krb524/krb524d.M b/mechglue/src/krb524/krb524d.M
new file mode 100644
index 000000000..dee00cf81
--- /dev/null
+++ b/mechglue/src/krb524/krb524d.M
@@ -0,0 +1,74 @@
+.\" krb524/krb524d.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\"
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" "
+.TH KRB524D 8
+.SH NAME
+krb524d \- Version 5 to Version 4 Credentials Conversion Daemon
+.SH SYNOPSIS
+.B krb524d
+[
+.B \-m[aster]
+|
+.B \-k[eytab]
+] [
+.B \-r
+.I realm
+] [
+.B \-nofork
+] [
+.B \-p
+.I portnum
+]
+.br
+.SH DESCRIPTION
+.I krb524d
+is the Kerberos Version 5 to Version 4 Credentials Conversion daemon.  
+It works in conjuction with a krb5kdc to allow clients to acquire Kerberos 
+version 4 tickets from Kerberos version 5 tickets without specifying a password.
+.SH OPTIONS
+.TP
+\fB\-m[aster]\fP
+Use the KDC database to convert credentials.  This option cannot be combined with
+\fB\-k[eytab]\fP.
+.TP
+\fB\-k[eytab]\fP
+Use the default keytab to convert credentials. This option cannot be combined with
+\fB\-m[aster]\fP.  
+.TP
+\fB\-r\fP \fIrealm\fP
+Convert credentials for \fIrealm\fP; by default the realm returned by
+.IR krb5_default_local_realm (3)
+is used.
+.TP
+\fB\-nofork\fP
+specifies that krb524d not fork on launch.  Useful for debugging purposes.
+.TP
+\fB\-p\fP \fIportnum\fP 
+specifies the default UDP port number which krb524d should listen on for
+Kerberos 524 requests.  This value is used when no port is specified in
+the KDC profile and when no port is specified in the Kerberos configuration
+file.
+If no value is available, then the value in /etc/services for service
+"krb524" is used.
+.SH SEE ALSO
+kerberos(1), krb5kdc(8), kdb5_util(8), kdc.conf(5)
diff --git a/mechglue/src/krb524/krb524d.c b/mechglue/src/krb524/krb524d.c
new file mode 100644
index 000000000..7572af419
--- /dev/null
+++ b/mechglue/src/krb524/krb524d.c
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2002 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <krb5/adm_proto.h>
+#include <com_err.h>
+#include <stdarg.h>
+
+#include <assert.h>
+#include <stdio.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <netinet/in.h>
+
+#include <krb.h>
+#include "krb524d.h"
+
+#if defined(NEED_DAEMON_PROTO)
+extern int daemon(int, int);
+#endif
+
+#define TIMEOUT 60
+#define TKT_BUFSIZ 2048
+#define MSGSIZE 8192
+
+char *whoami;
+int signalled = 0;
+static int debug = 0;
+void *handle = NULL;
+
+int use_keytab, use_master;
+int allow_v4_crossrealm = 0;
+char *keytab = NULL;
+krb5_keytab kt;
+
+void init_keytab(krb5_context), 
+    init_master(krb5_context, kadm5_config_params *),
+    cleanup_and_exit(int, krb5_context);
+krb5_error_code do_connection(int, krb5_context);
+krb5_error_code lookup_service_key(krb5_context, krb5_principal, 
+				   krb5_enctype, krb5_kvno, 
+				   krb5_keyblock *, krb5_kvno *);
+krb5_error_code  kdc_get_server_key(krb5_context, krb5_principal, 
+				    krb5_keyblock *, krb5_kvno *,
+				    krb5_enctype, krb5_kvno);
+
+static krb5_error_code
+handle_classic_v4 (krb5_context context, krb5_ticket *v5tkt,
+		   struct sockaddr_in *saddr,
+		   krb5_data *tktdata, krb5_kvno *v4kvno);
+static krb5_error_code 
+afs_return_v4(krb5_context, const krb5_principal , int *use_v5);
+
+static void usage(context)
+     krb5_context context;
+{
+     fprintf(stderr, "Usage: %s [-k[eytab]] [-m[aster] [-r realm]] [-nofork] [-p portnum]\n", whoami);
+     cleanup_and_exit(1, context);
+}
+
+static RETSIGTYPE request_exit(signo)
+     int signo;
+{
+     signalled = 1;
+}
+
+int (*encode_v4tkt)(KTEXT, char *, unsigned int *) = 0;
+
+int main(argc, argv)
+     int argc;
+     char **argv;
+{
+     struct servent *serv;
+     struct sockaddr_in saddr;
+     struct timeval timeout;
+     int ret, s, nofork;
+     fd_set rfds;
+     krb5_context context;
+     krb5_error_code retval;
+     kadm5_config_params config_params;
+     unsigned long port = 0;
+
+     whoami = ((whoami = strrchr(argv[0], '/')) ? whoami + 1 : argv[0]);
+
+     retval = krb5_init_context(&context);
+     if (retval) {
+	     com_err(whoami, retval, "while initializing krb5");
+	     exit(1);
+     }
+
+     {
+	 krb5int_access k5int;
+	 retval = krb5int_accessor(&k5int, KRB5INT_ACCESS_VERSION);
+	 if (retval != 0) {
+	     com_err(whoami, retval,
+		     "while accessing krb5 library internal support");
+	     exit(1);
+	 }
+	 encode_v4tkt = k5int.krb524_encode_v4tkt;
+	 if (encode_v4tkt == NULL) {
+	     com_err(whoami, 0,
+		     "krb4 support disabled in krb5 support library");
+	     exit(1);
+	 }
+     }
+
+     argv++; argc--;
+     use_master = use_keytab = nofork = 0;
+     config_params.mask = 0;
+     
+     while (argc) {
+       if (strncmp(*argv, "-X", 2) == 0) {
+	 allow_v4_crossrealm = 1;
+       }
+       else if (strncmp(*argv, "-k", 2) == 0)
+	       use_keytab = 1;
+	  else if (strncmp(*argv, "-m", 2) == 0)
+	       use_master = 1;
+	  else if (strcmp(*argv, "-nofork") == 0)
+	       nofork = 1;
+	  else if (strcmp(*argv, "-r") == 0) {
+	       argv++; argc--;
+	       if (argc == 0 || !use_master)
+		    usage(context);
+	       config_params.mask |= KADM5_CONFIG_REALM;
+	       config_params.realm = *argv;
+	  }
+	  else if (strcmp(*argv, "-p") == 0) {
+	      char *endptr = 0;
+	      argv++; argc--;
+	      if (argc == 0)
+		  usage (context);
+	      if (port != 0) {
+		  com_err (whoami, 0,
+			   "port number may only be specified once");
+		  exit (1);
+	      }
+	      port = strtoul (*argv, &endptr, 0);
+	      if (*endptr != '\0' || port > 65535 || port == 0) {
+		  com_err (whoami, 0,
+			   "invalid port number %s, must be 1..65535\n",
+			   *argv);
+		  exit (1);
+	      }
+	  }
+	  else
+	       break;
+	  argv++; argc--;
+     }
+     if (argc || use_keytab + use_master > 1 ||
+	 use_keytab + use_master == 0) {
+	  use_keytab = use_master = 0;
+	  usage(context);
+     }
+     
+     signal(SIGINT, request_exit);
+     signal(SIGHUP, SIG_IGN);
+     signal(SIGTERM, request_exit);
+
+     krb5_klog_init(context, "krb524d", whoami, !nofork);
+
+     if (use_keytab)
+	  init_keytab(context);
+     if (use_master)
+	  init_master(context, &config_params);
+
+     memset((char *) &saddr, 0, sizeof(struct sockaddr_in));
+     saddr.sin_family = AF_INET;
+     saddr.sin_addr.s_addr = INADDR_ANY;
+     if (port == 0) {
+	 serv = getservbyname(KRB524_SERVICE, "udp");
+	 if (serv == NULL) {
+	     com_err(whoami, 0, "service entry `%s' not found, using %d",
+		     KRB524_SERVICE, KRB524_PORT);
+	     saddr.sin_port = htons(KRB524_PORT);
+	 } else
+	     saddr.sin_port = serv->s_port;
+     } else
+	 saddr.sin_port = htons(port);
+	  
+     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	  com_err(whoami, errno, "creating main socket");
+	  cleanup_and_exit(1, context);
+     }
+     if ((ret = bind(s, (struct sockaddr *) &saddr,
+		     sizeof(struct sockaddr_in))) < 0) {
+	  com_err(whoami, errno, "binding main socket");
+	  cleanup_and_exit(1, context);
+     }
+     if (!nofork && daemon(0, 0)) {
+	 com_err(whoami, errno, "while detaching from tty");
+	 cleanup_and_exit(1, context);
+     }
+
+     while (1) {
+	  FD_ZERO(&rfds);
+	  FD_SET(s, &rfds);
+	  timeout.tv_sec = TIMEOUT;
+	  timeout.tv_usec = 0;
+
+	  ret = select(s+1, &rfds, NULL, NULL, &timeout);
+	  if (signalled)
+	       cleanup_and_exit(0, context);
+	  else if (ret == 0) {
+	       if (use_master) {
+		    ret = kadm5_flush(handle);
+		    if (ret && ret != KRB5_KDB_DBNOTINITED) {
+			 com_err(whoami, ret, "closing kerberos database");
+			 cleanup_and_exit(1, context);
+		    }
+	       }
+	  } else if (ret < 0 && errno != EINTR) {
+	       com_err(whoami, errno, "in select");
+	       cleanup_and_exit(1, context);
+	  } else if (FD_ISSET(s, &rfds)) {
+	       if (debug)
+		    printf("received packet\n");
+	       if ((ret = do_connection(s, context))) {
+		    com_err(whoami, ret, "handling packet");
+	       }
+	  } else
+	       com_err(whoami, 0, "impossible situation occurred!");
+     }
+
+     cleanup_and_exit(0, context);
+}
+
+void cleanup_and_exit(ret, context)
+     int ret;
+     krb5_context context;
+{
+     if (use_master && handle) {
+	  (void) kadm5_destroy(handle);
+     }
+     if (use_keytab && kt) krb5_kt_close(context, kt);
+     krb5_klog_close(context);
+     krb5_free_context(context);
+     exit(ret);
+}
+
+void init_keytab(context)
+     krb5_context context;
+{
+     int ret;
+     use_keytab = 0;
+     if (keytab == NULL) {
+	  if ((ret = krb5_kt_default(context, &kt))) {
+	       com_err(whoami, ret, "while opening default keytab");
+	       cleanup_and_exit(1, context);
+	  }
+     } else {
+	  if ((ret = krb5_kt_resolve(context, keytab, &kt))) {
+	       com_err(whoami, ret, "while resolving keytab %s",
+		       keytab);
+	       cleanup_and_exit(1, context);
+	  }
+     }
+     use_keytab = 1;		/* now safe to close keytab */
+}
+
+void init_master(context, params)
+     krb5_context context;
+     kadm5_config_params *params;
+{
+     int ret;
+
+     use_master = 0;
+     if ((ret = kadm5_init(whoami, NULL, KADM5_ADMIN_SERVICE, params,
+			   KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, NULL,
+			   &handle))) {
+	  com_err(whoami, ret, "initializing kadm5 library");
+	  cleanup_and_exit(1, context);
+     }
+     use_master = 1;		/* now safe to close kadm5 */
+}
+
+krb5_error_code do_connection(s, context)
+     int s;
+     krb5_context context;
+{
+     struct sockaddr saddr;
+     krb5_ticket *v5tkt = 0;
+     krb5_data msgdata, tktdata;
+     char msgbuf[MSGSIZE], tktbuf[TKT_BUFSIZ], *p;
+     int ret;
+     socklen_t saddrlen;
+     krb5_int32 n; /* Must be 4 bytes */
+     krb5_kvno v4kvno;
+
+     msgdata.data = msgbuf;
+     msgdata.length = MSGSIZE;
+     tktdata.data = tktbuf;
+     tktdata.length = TKT_BUFSIZ;
+     saddrlen = sizeof(struct sockaddr);
+     ret = recvfrom(s, msgdata.data, (int) msgdata.length, 0, &saddr, &saddrlen);
+     if (ret < 0) {
+       /* if recvfrom fails, we probably don't have a valid saddr to 
+	  use for the reply, so don't even try to respond. */
+       return errno;
+     }
+     if (debug)
+	  printf("message received\n");
+
+     if ((ret = decode_krb5_ticket(&msgdata, &v5tkt))) {
+          switch (ret) {
+	  case KRB5KDC_ERR_BAD_PVNO:
+	  case ASN1_MISPLACED_FIELD:
+	  case ASN1_MISSING_FIELD:
+	  case ASN1_BAD_ID:
+	  case KRB5_BADMSGTYPE:
+	    /* don't even answer parse errors */
+	    return ret;
+	    break;
+	  default:
+	    /* try and recognize our own error packet */
+	    if (msgdata.length == sizeof(krb5_int32))
+	      return KRB5_BADMSGTYPE;
+	    else
+	      goto error;
+	  }
+     }
+     if (debug)
+	  printf("V5 ticket decoded\n");
+     
+     if( krb5_princ_size(context, v5tkt->server) >= 1
+	 &&krb5_princ_component(context, v5tkt->server, 0)->length == 3
+	 &&strncmp(krb5_princ_component(context, v5tkt->server, 0)->data,
+		   "afs", 3) == 0) {
+	 krb5_data *enc_part;
+	 int use_v5;
+	 if ((ret = afs_return_v4(context, v5tkt->server,
+				  &use_v5)) != 0) 
+	     goto error;
+	 if ((ret = encode_krb5_enc_data( &v5tkt->enc_part, &enc_part)) != 0) 
+	     goto error;
+	 if (!(use_v5 )|| enc_part->length >= 344) {
+	     krb5_free_data(context, enc_part);
+	     if ((ret = handle_classic_v4(context, v5tkt,
+					 (struct sockaddr_in *) &saddr, &tktdata,
+					 &v4kvno)) != 0)
+		 goto error;
+	 } else {
+	   KTEXT_ST fake_v4tkt;
+	   fake_v4tkt.mbz = 0;
+	   fake_v4tkt.length = enc_part->length;
+	   memcpy(fake_v4tkt.dat, enc_part->data, enc_part->length);
+	     v4kvno = (0x100-0x2b); /*protocol constant indicating  v5
+				     * enc part only*/
+	     krb5_free_data(context, enc_part);
+	     ret = encode_v4tkt(&fake_v4tkt, tktdata.data, &tktdata.length);
+	 }
+     } else {
+	 if ((ret = handle_classic_v4(context, v5tkt,
+				     (struct sockaddr_in *) &saddr, &tktdata,
+				     &v4kvno)) != 0)
+	     goto error;
+     }
+     
+	error:
+     /* create the reply */
+     p = msgdata.data;
+     msgdata.length = 0;
+     
+     n = htonl(ret);
+     memcpy(p, (char *) &n, sizeof(krb5_int32));
+     p += sizeof(krb5_int32);
+     msgdata.length += sizeof(krb5_int32);
+
+     if (ret)
+	  goto write_msg;
+
+     n = htonl(v4kvno);
+     memcpy(p, (char *) &n, sizeof(krb5_int32));
+     p += sizeof(krb5_int32);
+     msgdata.length += sizeof(krb5_int32);
+
+     memcpy(p, tktdata.data, tktdata.length);
+     p += tktdata.length;
+     msgdata.length += tktdata.length;
+
+write_msg:
+     if (ret)
+	  (void) sendto(s, msgdata.data, (int) msgdata.length, 0, &saddr, saddrlen);
+     else
+	  if (sendto(s, msgdata.data, msgdata.length, 0, &saddr, saddrlen)<0)
+	       ret = errno;
+     if (debug)
+	  printf("reply written\n");
+     if (v5tkt)
+       krb5_free_ticket(context, v5tkt);
+     
+	       
+     return ret;
+}
+
+krb5_error_code lookup_service_key(context, p, ktype, kvno, key, kvnop)
+     krb5_context context;
+     krb5_principal p;
+     krb5_enctype ktype;
+     krb5_kvno kvno;
+     krb5_keyblock *key;
+     krb5_kvno *kvnop;
+{
+     int ret;
+     krb5_keytab_entry entry;
+
+     if (use_keytab) {
+	  if ((ret = krb5_kt_get_entry(context, kt, p, kvno, ktype, &entry)))
+	       return ret;
+	  *key = entry.key;
+	  key->contents = malloc(key->length);
+	  if (key->contents)
+	      memcpy(key->contents, entry.key.contents, key->length);
+	  else if (key->length) {
+	      /* out of memory? */
+	      ret = errno;
+	      memset (key, 0, sizeof (*key));
+	      return ret;
+	  }
+
+	  krb5_kt_free_entry(context, &entry);
+	  return 0;
+     } else if (use_master) {
+	  return kdc_get_server_key(context, p, key, kvnop, ktype, kvno);
+     }
+     return 0;
+}
+
+krb5_error_code kdc_get_server_key(context, service, key, kvnop, ktype, kvno)
+    krb5_context context;
+    krb5_principal service;
+    krb5_keyblock *key;
+    krb5_kvno *kvnop;
+    krb5_enctype ktype;
+    krb5_kvno kvno;
+{
+    krb5_error_code ret;
+    kadm5_principal_ent_rec server;
+    
+    if ((ret = kadm5_get_principal(handle, service, &server,
+				   KADM5_KEY_DATA|KADM5_ATTRIBUTES)))
+	 return ret;
+
+    if (server.attributes & KRB5_KDB_DISALLOW_ALL_TIX
+	|| server.attributes & KRB5_KDB_DISALLOW_SVR) {
+	kadm5_free_principal_ent(handle, &server);
+	return KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
+    }
+
+    /*
+     * We try kadm5_decrypt_key twice because in the case of a
+     * ENCTYPE_DES_CBC_CRC key, we prefer to find a krb4 salt type
+     * over a normal key.  Note this may create a problem if the
+     * server key is passworded and has both a normal and v4 salt.
+     * There is no good solution to this.
+     */
+    if ((ret = kadm5_decrypt_key(handle,
+				 &server,
+				 ktype,
+				 (ktype == ENCTYPE_DES_CBC_CRC) ? 
+				 KRB5_KDB_SALTTYPE_V4 : -1,
+				 kvno,
+				 key, NULL, kvnop)) &&
+	(ret = kadm5_decrypt_key(handle,
+				 &server,
+				 ktype,
+				 -1,
+				 kvno,
+				 key, NULL, kvnop))) {
+	 kadm5_free_principal_ent(handle, &server);
+	 return (KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
+    }
+
+    kadm5_free_principal_ent(handle, &server);
+    return ret;
+}
+
+/*
+ * We support two  kinds of v4 credentials.  There are real v4
+ *   credentials, and  a Kerberos v5 enc part masquerading as a krb4
+ *  credential to be used by modern AFS implementations; this function
+ *  handles the classic v4 case.
+ */
+
+static krb5_error_code
+handle_classic_v4 (krb5_context context, krb5_ticket *v5tkt,
+		   struct sockaddr_in *saddr,
+		   krb5_data *tktdata, krb5_kvno *v4kvno)
+{
+    krb5_error_code ret;
+    krb5_keyblock v5_service_key, v4_service_key;
+     KTEXT_ST v4tkt;
+
+    v5_service_key.contents = NULL;
+    v4_service_key.contents = NULL;
+    
+             if ((ret = lookup_service_key(context, v5tkt->server,
+				   v5tkt->enc_part.enctype,
+				   v5tkt->enc_part.kvno,
+				   &v5_service_key, NULL)))
+	  goto error;
+
+     if ( (ret = lookup_service_key(context, v5tkt->server,
+				   ENCTYPE_DES_CBC_CRC,
+				   0,
+				   &v4_service_key, v4kvno)))
+	 goto error;
+
+     if (debug)
+	  printf("service key retrieved\n");
+     if ((ret = krb5_decrypt_tkt_part(context, &v5_service_key, v5tkt))) {
+       goto error;
+     }
+
+    if (!(allow_v4_crossrealm || krb5_realm_compare(context, v5tkt->server,
+						    v5tkt->enc_part2->client))) {
+ret =  KRB5KDC_ERR_POLICY ;
+ goto error;
+    }
+    krb5_free_enc_tkt_part(context, v5tkt->enc_part2);
+    v5tkt->enc_part2= NULL;
+
+         ret = krb524_convert_tkt_skey(context, v5tkt, &v4tkt, &v5_service_key,
+				   &v4_service_key,
+				   (struct sockaddr_in *)saddr);
+     if (ret)
+	  goto error;
+
+     if (debug)
+	  printf("credentials converted\n");
+
+     ret = encode_v4tkt(&v4tkt, tktdata->data, &tktdata->length);
+     if (ret)
+	  goto error;
+     if (debug)
+	  printf("v4 credentials encoded\n");
+
+ error:
+     if (v5tkt->enc_part2) {
+	 krb5_free_enc_tkt_part(context, v5tkt->enc_part2);
+	 v5tkt->enc_part2 = NULL;
+     }
+
+     if(v5_service_key.contents)
+       krb5_free_keyblock_contents(context, &v5_service_key);
+     if (v4_service_key.contents)
+	 krb5_free_keyblock_contents(context, &v4_service_key);
+     return ret;
+}
+
+/*
+ * afs_return_v4: a predicate to determine whether we want to try
+ * using the afs krb5 encrypted part encoding or whether we  just
+ * return krb4.  Takes a principal, and checks the configuration file.
+ */
+static krb5_error_code 
+afs_return_v4 (krb5_context context, const krb5_principal princ,
+	       int *use_v5)
+{
+    krb5_error_code ret;
+    char *unparsed_name;
+    char *cp;
+    krb5_data realm;
+    assert(use_v5 != NULL);
+    ret = krb5_unparse_name(context, princ, &unparsed_name);
+        if (ret != 0)
+	return ret;
+/* Trim out trailing realm component into separate string.*/
+    for (cp = unparsed_name; *cp != '\0'; cp++) {
+	if (*cp == '\\') {
+	    cp++; /* We trust unparse_name not to leave a singleton
+		   * backslash*/
+	    continue;
+	}
+	if (*cp == '@') {
+	    *cp = '\0';
+	    realm.data = cp+1;
+	    realm.length = strlen((char *) realm.data);
+	    	    break;
+	}
+    }
+     krb5_appdefault_boolean(context, "afs_krb5",
+				  &realm, unparsed_name, 1,
+				  use_v5);
+    krb5_free_unparsed_name(context, unparsed_name);
+    return ret;
+}
diff --git a/mechglue/src/krb524/krb524d.h b/mechglue/src/krb524/krb524d.h
new file mode 100644
index 000000000..33be97157
--- /dev/null
+++ b/mechglue/src/krb524/krb524d.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef KRB524INT_H
+#define KRB524INT_H
+
+#include "port-sockets.h"
+#include "kerberosIV/krb.h"
+
+#ifndef KRB524INT_BEGIN_DECLS
+#ifdef __cplusplus
+#define KRB524INT_BEGIN_DECLS	extern "C" {
+#define KRB524INT_END_DECLS	}
+#else
+#define KRB524INT_BEGIN_DECLS
+#define KRB524INT_END_DECLS
+#endif
+#endif
+
+KRB524INT_BEGIN_DECLS
+
+int krb524_convert_tkt_skey
+	(krb5_context context, krb5_ticket *v5tkt, KTEXT_ST *v4tkt, 
+		   krb5_keyblock *v5_skey, krb5_keyblock *v4_skey,
+			struct sockaddr_in *saddr);
+
+/* conv_princ.c */
+
+int krb524_convert_princs
+	(krb5_context context, krb5_principal client, krb5_principal server,
+	 char *pname, char *pinst, char *prealm,
+	 char *sname, char *sinst, char *srealm);
+
+KRB524INT_END_DECLS
+
+#endif /* KRB524INT_H */
diff --git a/mechglue/src/krb524/libinit.c b/mechglue/src/krb524/libinit.c
new file mode 100644
index 000000000..22aeea9f8
--- /dev/null
+++ b/mechglue/src/krb524/libinit.c
@@ -0,0 +1,27 @@
+#ifdef _WIN32
+#include <windows.h>
+
+BOOL
+WINAPI
+DllMain(
+    HANDLE hModule,
+    DWORD fdwReason,
+    LPVOID lpReserved
+    )
+{
+    switch (fdwReason)
+    {
+	case DLL_PROCESS_ATTACH:
+	    break;
+	case DLL_THREAD_ATTACH:
+	    break;
+	case DLL_THREAD_DETACH:
+	    break;
+	case DLL_PROCESS_DETACH:
+	    break;
+	default:
+	    return FALSE;
+    }
+    return TRUE;
+}
+#endif
diff --git a/mechglue/src/krb524/test.c b/mechglue/src/krb524/test.c
new file mode 100644
index 000000000..d0cb92181
--- /dev/null
+++ b/mechglue/src/krb524/test.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "k5-int.h"
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/types.h>
+
+#ifndef _WIN32
+#include <netinet/in.h>
+#endif
+
+#include <des.h>
+#include <krb.h>
+#include "com_err.h"
+
+#define KEYSIZE 8
+#define CRED_BUFSIZ 2048
+
+#define krb5_print_addrs
+
+void do_local (krb5_creds *, krb5_keyblock *),
+     do_remote (krb5_context, krb5_creds *, char *, krb5_keyblock *);
+
+static 
+void print_key(msg, key)
+     char *msg;
+     des_cblock *key;
+{
+     printf("%s: ", msg);
+     C_Block_print(key);
+     printf("\n");
+}
+
+static
+void print_time(msg, t)
+     char *msg;
+     int t;
+{
+     printf("%s: %d, %s", msg, t, ctime((time_t *) &t));
+}
+
+static
+void krb5_print_times(msg, t)
+     char *msg;
+     krb5_ticket_times *t;
+{
+     printf("%s: Start: %d, %s", msg, t->starttime, 
+	    ctime((time_t *) &t->starttime));
+     printf("%s: End: %d, %s", msg, t->endtime, 
+	    ctime((time_t *) &t->endtime));
+     printf("%s: Auth: %d, %s", msg, t->authtime, 
+	    ctime((time_t *) &t->authtime));
+     printf("%s: Renew: %d, %s", msg, t->renew_till, 
+	    ctime((time_t *) &t->renew_till));
+}
+
+static
+void krb5_print_keyblock(msg, key)
+     char *msg;
+     krb5_keyblock *key;
+{
+     printf("%s: Keytype: %d\n", msg, key->enctype);
+     printf("%s: Length: %d\n", msg, key->length);
+     printf("%s: Key: ", msg);
+     C_Block_print((des_cblock *) key->contents);
+     printf("\n");
+}
+
+static
+void krb5_print_ticket(context, ticket_data, key)
+     krb5_context context;
+     krb5_data *ticket_data;
+     krb5_keyblock *key;
+{
+     char *p;
+     krb5_ticket *tkt;
+     int ret;
+
+     if ((ret = decode_krb5_ticket(ticket_data, &tkt))) {
+	  com_err("test", ret, "decoding ticket");
+	  exit(1);
+     }
+     if ((ret = krb5_decrypt_tkt_part(context, key, tkt))) {
+	  com_err("test", ret, "decrypting V5 ticket for print");
+	  exit(1);
+     }
+     
+     krb5_unparse_name(context, tkt->server, &p);
+     printf("Ticket: Server: %s\n", p);
+     free(p);
+     printf("Ticket: kvno: %d\n", tkt->enc_part.kvno);
+     printf("Ticket: Flags: 0x%08x\n", tkt->enc_part2->flags);
+     krb5_print_keyblock("Ticket: Session Keyblock",
+			 tkt->enc_part2->session);
+     krb5_unparse_name(context, tkt->enc_part2->client, &p);
+     printf("Ticket: Client: %s\n", p);
+     free(p);
+     krb5_print_times("Ticket: Times", &tkt->enc_part2->times);
+     printf("Ticket: Address 0: %08lx\n",
+	    *((unsigned long *) tkt->enc_part2->caddrs[0]->contents));
+     
+     krb5_free_ticket(context, tkt);
+}
+
+static
+void krb5_print_creds(context, creds, secret_key)
+     krb5_context context;
+     krb5_creds *creds;
+     krb5_keyblock *secret_key;
+{
+     char *p;
+     
+     krb5_unparse_name(context, creds->client, &p);
+     printf("Client: %s\n", p);
+     free(p);
+     krb5_unparse_name(context, creds->server, &p);
+     printf("Server: %s\n", p);
+     free(p);
+     krb5_print_keyblock("Session key", &creds->keyblock);
+     krb5_print_times("Times", &creds->times);
+     printf("is_skey: %s\n", creds->is_skey ? "True" : "False");
+     printf("Flags: 0x%08x\n", creds->ticket_flags);
+#if 0
+     krb5_print_addrs(creds->addresses);
+#endif
+     krb5_print_ticket(context, &creds->ticket, secret_key);
+     /* krb5_print_ticket(context, &creds->second_ticket, secret_key); */
+}
+
+static
+void krb4_print_ticket(ticket, secret_key)
+     KTEXT ticket;
+     krb5_keyblock *secret_key;
+{
+     char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
+     char sname[ANAME_SZ], sinst[INST_SZ];
+     unsigned char flags;
+     krb5_ui_4 addr;
+     krb5_ui_4 issue_time;
+     C_Block session_key;
+     int life;
+     Key_schedule keysched;
+     
+     int ret;
+     
+     if (des_key_sched(secret_key->contents, keysched)) {
+	  fprintf(stderr, "Bug in DES key somewhere.\n");
+	  exit(1);
+     }
+     
+     ret = decomp_ticket(ticket, &flags, pname, pinst, prealm, &addr,
+			 session_key, &life, &issue_time, sname,
+			 sinst,  secret_key->contents, keysched);
+     if (ret != KSUCCESS) {
+	  fprintf(stderr, "krb4 decomp_ticket failed\n");
+	  exit(1);
+     }
+     printf("Ticket: Client: %s.%s@%s\n", pname, pinst, prealm);
+     printf("Ticket: Service: %s.%s\n", sname, sinst);
+     printf("Ticket: Address: %08lx\n", (long) addr);
+     print_key("Ticket: Session Key", (char *) session_key);
+     printf("Ticket: Lifetime: %d\n", life);
+     printf("Ticket: Issue Date: %ld, %s", (long) issue_time, 
+	    ctime((time_t *) &issue_time));
+}
+
+static
+void krb4_print_creds(creds, secret_key)
+     CREDENTIALS *creds;
+     krb5_keyblock *secret_key;
+{
+     printf("Client: %s.%s@%s\n", creds->pname, creds->pinst,
+	    creds->realm);
+     printf("Service: %s.%s@%s\n", creds->service, creds->instance,
+	    creds->realm);
+     print_key("Session key", (char *) creds->session);
+     printf("Lifetime: %d\n", creds->lifetime);
+     printf("Key Version: %d\n", creds->kvno);
+     print_time("Issue Date", creds->issue_date);
+     krb4_print_ticket(&creds->ticket_st, secret_key);
+}
+
+static
+void usage()
+{
+     fprintf(stderr, "Usage: test [-remote server] client service\n");
+     exit(1);
+}
+
+int main(argc, argv)
+     int argc;
+     char **argv;
+{
+     krb5_principal client, server;
+     krb5_ccache cc;
+     krb5_creds increds, *v5creds;
+     krb5_keyblock key;
+     char keybuf[KEYSIZE], buf[BUFSIZ];
+     int i, ret, local;
+     char *remote;
+     krb5_context context;
+     krb5_error_code retval;
+
+#if 0
+     krb524_debug = 1;
+#endif
+
+     retval = krb5_init_context(&context);
+     if (retval) {
+	     com_err(argv[0], retval, "while initializing krb5");
+	     exit(1);
+     }
+
+     local = 0;
+     remote = NULL;
+     argc--; argv++;
+     while (argc) {
+	  if (strcmp(*argv, "-local") == 0)
+	       local++;
+#if 0
+	  else if (strcmp(*argv, "-remote") == 0) {
+	       argc--; argv++;
+	       if (!argc)
+		    usage();
+	       remote = *argv;
+	  }
+#endif
+	  else
+	       break;
+	  argc--; argv++;
+     }
+     if (argc != 2)
+	  usage();
+
+     if ((ret = krb5_parse_name(context, argv[0], &client))) {
+	  com_err("test", ret, "parsing client name");
+	  exit(1);
+     }
+     if ((ret = krb5_parse_name(context, argv[1], &server))) {
+	  com_err("test", ret, "parsing server name");
+	  exit(1);
+     }
+     if ((ret = krb5_cc_default(context, &cc))) {
+	  com_err("test", ret, "opening default credentials cache");
+	  exit(1);
+     }
+     
+     memset((char *) &increds, 0, sizeof(increds));
+     increds.client = client;
+     increds.server = server;
+     increds.times.endtime = 0;
+     increds.keyblock.enctype = ENCTYPE_DES_CBC_MD5;
+     if ((ret = krb5_get_credentials(context, 0, cc, &increds, &v5creds))) {
+	  com_err("test", ret, "getting V5 credentials");
+	  exit(1);
+     }
+
+     /* We need the service key in order to locally decrypt both */
+     /* tickets for testing */
+     printf("Service's key: ");
+     fflush(stdout);
+     fgets(buf, BUFSIZ, stdin);
+     for (i = 0; i < 8; i++) {
+	  unsigned char c;
+	  c = buf[2*i];
+	  if (c >= '0' && c <= '9')
+	       c -= '0';
+	  else if (c >= 'a' && c <= 'z')
+	       c = c - 'a' + 0xa;
+	  keybuf[i] = c << 4;
+	  c = buf[2*i+1];
+	  if (c >= '0' && c <= '9')
+	       c -= '0';
+	  else if (c >= 'a' && c <= 'z')
+	       c = c - 'a' + 0xa;
+	  keybuf[i] += c;
+     }
+     
+     key.enctype = ENCTYPE_DES_CBC_MD5;
+     key.length = KEYSIZE; /* presumably */
+     key.contents = (krb5_octet *) keybuf;
+
+     do_remote(context, v5creds, remote, &key);
+     exit(0);
+}
+
+void do_remote(context, v5creds, server, key)
+     krb5_context context;
+     krb5_creds *v5creds;
+     char *server;
+     krb5_keyblock *key;
+{
+#if 0
+     struct sockaddr_in saddr;
+     struct hostent *hp;
+#endif
+     CREDENTIALS v4creds;
+     int ret;
+
+     printf("\nV5 credentials:\n");
+     krb5_print_creds(context, v5creds, key);
+
+#if 0
+     if (strcmp(server, "kdc") != 0) {
+	  hp = gethostbyname(server);
+	  if (hp == NULL) {
+	       fprintf(stderr, "test: host %s does not exist.\n", server);
+	       exit(1);
+	  }
+	  memset((char *) &saddr, 0, sizeof(struct sockaddr_in));
+	  saddr.sin_family = AF_INET;
+	  memcpy((char *) &saddr.sin_addr.s_addr, hp->h_addr,
+		 sizeof(struct in_addr));
+	  
+	  if ((ret = krb524_convert_creds_addr(context, v5creds, &v4creds, 
+					      (struct sockaddr *) &saddr))) {
+	       com_err("test", ret, "converting credentials on %s",
+		       server);
+	       exit(1);
+	  }
+     } else
+#endif
+     {
+	  if ((ret = krb524_convert_creds_kdc(context, v5creds, &v4creds))) {
+	       com_err("test", ret, "converting credentials via kdc");
+	       exit(1);
+	  }
+     }
+     
+     printf("\nV4 credentials:\n");
+     krb4_print_creds(&v4creds, key);
+}
diff --git a/mechglue/src/lib/.Sanitize b/mechglue/src/lib/.Sanitize
new file mode 100644
index 000000000..a669a93bd
--- /dev/null
+++ b/mechglue/src/lib/.Sanitize
@@ -0,0 +1,56 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+Makefile.in
+configure
+configure.in
+crypto
+des425
+exports.crypto
+exports.des425
+exports.kdb5
+exports.krb5
+glue4.c
+gssapi
+gssapi.def
+kadm
+kdb
+krb4
+krb5
+krb5.saber.source
+krb5.saber.warnings
+libkrb5.def
+win_glue.c
+winsock.def
+
+Things-to-lose:
+kdb4
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/.rconf b/mechglue/src/lib/.rconf
new file mode 100644
index 000000000..0be003a69
--- /dev/null
+++ b/mechglue/src/lib/.rconf
@@ -0,0 +1,2 @@
+ignore des.old
+ignore FOO
diff --git a/mechglue/src/lib/ChangeLog b/mechglue/src/lib/ChangeLog
new file mode 100644
index 000000000..cdbd1d1df
--- /dev/null
+++ b/mechglue/src/lib/ChangeLog
@@ -0,0 +1,824 @@
+2005-10-31  Jeffrey Altman <jaltman@mit.edu>
+
+	* gssapi32.def:  export missing functions
+        	gss_krb5_set_allowable_enctypes
+	        gss_krb5_export_lucid_sec_context
+	        gss_krb5_free_lucid_sec_context
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	Novell merge.
+	* Makefile.in (LOCAL_SUBDIRS): Build kdb after rpc.
+	* krb5.saber.source: Deleted.
+
+2005-04-22  Jeffrey Altman <jaltman@mit.edu>
+
+        * win_glue.c:  Remove calls to WSAStartup/WSACleanup because
+        they can result in deadlocks when called from DllMain().
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* win_glue.c (NEED_SOCKETS): Don't define.
+
+2005-02-16  Jeffrey Altman <jaltman@mit.edu>
+
+        * gssapi32.def: export the missing DATA symbols
+
+2005-01-03  Jeffrey Altman <jaltman@mit.edu>
+
+        * krb5_32.def: export krb5_is_thread_safe()
+
+2004-12-18  Jeffrey Altman <jaltman@mit.edu>
+
+        * krb5_32.def: mark krb5_principal2salt as using the wrong 
+          calling convention.
+
+2004-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+        *.cvsignore, Makefile.in: rename krb5support32.def to k5sprt32.def
+
+2004-09-24  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (RCFLAGS): Add -I$(SRCTOP) to get patchlevel.h.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SLIBS, SDEF, S_GLUE, COMERR_GLUE, PROF_GLUE,
+	SGLUE): New variables.
+	(NO_GLUE): Deleted.
+	(CGLUE, PGLUE): Use new separate glue files instead of no_glue.
+	(SRES) [WIN32]: New variable.
+	($(SRES), $(SLIB)) [WIN32]: New targets.
+	($(CLIB), $(PLIB), $(KLIB), $(GLIB)) [WIN32]: Depend on and link
+	against $(SLIB) too.
+	($(SDEF)): New target.  Generate Windows export list from common
+	symbol list.
+	($(COMERR_GLUE), $(PROF_GLUE), $(S_GLUE)): New targets.
+
+	* win_glue.c (control): Reference add/remove_error_table only if
+	building for krb4 library.  Add calls to library init/fini
+	functions for other libraries.  For support library, also call a
+	hook function on DLL_THREAD_DETACH.  If no recognized
+	library-specific macro is defined, don't compile.
+	(DllMain): Do call control() on DLL_THREAD_DETACH.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Don't set.
+	(all-mac, clean-mac): Targets deleted.
+
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* exports.crypto, exports.des425, exports.kdb5, exports.krb5:
+	Unused files deleted.
+
+2004-03-31  Jeffrey Altman <jaltman@mit.edu>
+
+    * Makefile.in: Delay Load the ADVAPI32.DLL and SECUR32.DLL libraries
+      to enable the KRB5_32.DLL to load on Windows 9x systems which do
+      not support the LSA Kerberos functionality.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCAL_SUBDIRS): Renamed from MY_SUBDIRS.
+
+2004-02-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Add apputils.
+	(CLEANLIBS): Add libapputils.a.
+
+2003-12-18  Jeffrey Altman <jaltman@mit.edu>
+
+        * krb5_32.def: Remove exports added on 2003-12-13.  Moved
+          to krb5int_accessor
+
+2003-12-13  Jeffrey Altman <jaltman@mit.edu>
+   
+        * krb4_32.def: Remove exports from KfM not yet compiled in KfW
+            krb_ad_tkt, krb_pw_tkt, kuserok, tkt_string, FSp_xxx
+        
+        * krb5_32.def: Add exports of private functions necessary for 
+            building new gssapi32.dll:
+              krb5int_c_mandatory_cksumtype   ; PRIVATE GSSAPI k5-int.h
+              krb5_ser_pack_int64             ; PRIVATE GSSAPI k5-int.h
+              krb5_ser_unpack_int64           ; PRIVATE GSSAPI k5-int.h
+
+2003-12-11  Jeffrey Altman <jaltman@mit.edu>
+
+        * Makefile.in: Add secur32.lib to libraries necessary to build 
+          krb5_32.dll.  Necessary to support the new MSLSA ccache type.
+
+2003-12-08  Jeffrey Altman <jaltman@mit.edu>
+
+        * krb4_32.def: Add exports for functions exported by KfM
+
+2003-07-21  Alexandra Ellwood  <lxs@mit.edu>
+
+        * krb5_32.def: Export krb5_principal2salt.
+
+2003-07-18  Jeffrey Altman <jaltman@mit.edu>
+
+    * gssapi32.def: Export GSS OID constants
+
+2003-07-09  Alexandra Ellwood  <lxs@mit.edu>
+
+        * krb5_32.def: Export krb5_get_permitted_enctypes and 
+        krb5_set_real_time for Samba.
+
+2003-05-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_32.def: Add krb5_524_convert_creds.
+
+2003-05-08  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5_32.def: Add krb5_c_string_to_key_with_params
+
+2003-05-09  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_32.def: Add krb5_auth_con_getrecvsubkey,
+	krb5_auth_con_getsendsubkey, krb5_auth_con_setrecvsubkey,
+	krb5_auth_con_setsendsubkey.
+
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5_32.def: Add krb5_set_password and krb5_set_password_using_ccache
+
+2003-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (K4LIBS): Revert previous.
+
+	* krb5_32.def: Add afs_string_to_key, which is now needed by the
+	krb4 library.
+
+	* Makefile.in (K4LIBS): Add des425.lib.
+
+2003-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_32.def: Export krb5_rc_close, krb5_free_enc_tkt_part, and
+	krb5_decrypt_tkt_part, for GSSAPI.
+
+2003-01-12  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_32.def: Merge from 1-2-2-branch.
+
+2003-01-06  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5_32.def: Export krb5_auth_con_*_checksum_func
+
+2002-12-02  Tom Yu  <tlyu@mit.edu>
+
+	* win_glue.c: Put kadm_err.et references back in.
+
+2002-11-18  Tom Yu  <tlyu@mit.edu>
+
+	* win_glue.c (control): Remove references to the "kadm" error
+	table for now.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Don't list krb5util.
+	(CLEANLIBS): Don't delete libkrb5util.a.
+
+2002-06-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (WINLIBS): Use ws2_32.lib instead of wsock32.lib.
+
+2001-11-16  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5_32.def: Export krb5_set_default_tgs_enctypes
+
+2001-10-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Add krb5_kt_* functions: krb5_kt_close,
+	krb5_kt_get_entry, krb5_kt_get_name, krb5_kt_get_type,
+	krb5_kt_start_seq_get, krb5_kt_next_entry, and krb5_kt_end_seq_get.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (RCFLAGS): Don't define _MSDOS_.
+
+	* win_glue.c: Don't explicitly declare pointers FAR any more.
+
+2001-07-27  Danilo Almeida  <dalmeida@mit.edu>
+
+	* gssapi32.def: Do no export gss_mech_krb5.
+
+2001-07-27  Danilo Almeida  <dalmeida@mit.edu>
+
+	* gssapi32.def: Export gss_mech_krb5 as DATA.  Mark all exported
+	variables as DATA.
+
+2001-01-22  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Add krb5_rc_close() so gssapi builds.
+
+2000-07-29  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Add missing krb5_cc_store_cred().
+
+2000-07-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Add krb5_cc_* functions.
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb4_32.def: Add krb_in_tkt.
+
+	* krb5_32.def: Add krb5int_accessor.
+
+2000-06-02  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win_glue.c (GetCallingAppVerInfo, krb5_vercheck): Use
+	APPVERINFO_SIZE-sized buffers instead of hard-coding a number
+	everywhere.  Document the buffer size in funciton documentation.
+
+	* krb5_32.def: Add krb5int_cc_default for the benefit of GSS API DLL.
+
+2000-05-23  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* win_glue.c (GetCallingAppVerInfo): Don't overfill buffers
+	"AppTitle", "AppVer", and "AppIni".
+
+2000-05-15      Jeffrey Altman          <jaltman@columbia.edu>
+
+        * krb5_32.def -- Added exports for new public functions
+
+               krb5_appdefault_string
+               krb5_appdefault_boolean
+
+2000-05-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Reflect something closer to the reality of
+	what we would like to do for 1.3.
+
+2000-05-03  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* win_glue.c (do_timebomb): Don't overflow buffer "buf".
+
+2000-04-29  Jeffrey Altman <jaltman@columbia.edu>
+
+        * krb5_32.def: Add krb5_get_tgs_ktypes, krb5_free_ktypes for gssapi
+
+2000-03-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Add krb5_get_prompt_types.
+
+2000-02-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Replace decode_krb5_ticket with krb5_decode_ticket.
+	Add documentation about adding things to DEF file.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Use DLL_LINKOPTS to link DLL.  Remove dependence of
+	mit directory for version server support.  Remove references to
+	SAP.  Remove DNS defines.
+
+	* winsock.def, comerr16.def, gssapi16.def, krb4_16.def,
+	krb5_16.def, sapgss16.def, sapkrb16.def, xpprof16.def: Remove
+	obsolete DEF files.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-26  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Export krb5_kuserok.
+
+1999-07-22  Jeffrey Altman <jaltman@columbia.edu>
+
+        * krb5_32.def
+          add additional exports:
+
+          krb5_address_search
+ 	  krb5_auth_con_getrcache
+ 	  krb5_c_enctype_compare
+
+1999-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fix jaltman's changes so they don't break the unix
+	build.
+
+1999-06-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_32.def: Add krb5_get_default_config_files and 
+		krb5_free_config_files.
+
+1999-06-08  Danilo Almeida  <dalmeida@mit.edu>
+
+	* win_glue.c (krb5_vercheck): Only do version checking once per
+		use of the DLL.
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+Mon May 17 19:50:53 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Use only one resource file per binary.
+
+	* krb5.rc: Remove silly _MSDOS #ifdef.
+
+Mon May 17 12:37:25 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Get rid of win16 support/clutter.  Build separate
+		resource files for each library.  Link resource files
+		directly instead of excplicitly converting to object
+		files.
+
+Wed May 12 00:27:37 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssapi32.def: Add krb5-specific extensions so they are exported
+		from the DLL.
+
+Mon May 10 15:14:34 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Fri May  7 18:27:08 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* xpprof32.def, krb4_32.def, gssapi32.def, comerr32.del: Remove
+		Win16 directives to get rid of warnings.
+
+Fri May  7 12:10:50 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* xpprof32.def: Add profile_abandon to the list of exported
+	 	functions.
+
+Sat Apr 17 01:21:15 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5_32.def: Add krb5_cc_set_default_name to the list of
+		exported functions.
+
+	* gssapi32.def: Add krb5 specific extension functions:
+		gss_krb5_get_tkt_flags, gss_krb5_copy_ccache, and 
+		gss_krb5_ccache_name... to the list of exported functions
+		in the DLL.
+
+1999-03-31  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* win_glue.c (control): Call krb5_stdcc_shutdown when detaching
+		the krb5 library.
+
+	* Makefile.in: Remove reference to the windows Krbcc32.dll
+		library, since this is now dynamically loaded.
+
+Mon Feb  8 22:08:22 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Link in the ccapi import library under windows.
+
+	* krb5_16.def, krb5_32.def: Added a number of miscellaneous
+ 		functions to the DLL exports list so that things build
+ 		under Windows again.
+
+1999-01-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, configure.in: Move the responsibility for
+		generating the Makefile in this directory to the top-level
+		configure script.  The local configure.in script has been
+		deleted.
+
+Sat Dec  5 01:11:00 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5_32.def: Fixed exports file to reflect new crypto library
+		and related changes.
+
+1998-05-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5_32.def: Change the DLL export list to include
+		krb5_auth_con_setrcache, krb5_get_server_rcache,
+		krb5_cc_default_name, krb5_change_password,
+		krb5_mcc_ops, and all of the Cygnus
+		krb5_get_init_creds functions.  Remove the old libkadm
+		functions, as they are no longer available.
+
+Sun May 24 22:31:39 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (CLEANLIBS): Remove lib/kadm from the list of
+		directories built in the windows build.
+
+Wed Feb 18 16:04:58 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (thisconfigdir): Remove trailing slash.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Nov 19 10:33:19 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean-unix): Do not remove libraries here as the
+	 	Makefile that created the symlink now removes it.
+
+Tue Oct 21 23:29:18 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* win_glue.c: Add checks so that code doesn't bomb out if the
+		version resource is missing a Title or Version record.
+
+Fri Aug  1 22:03:24 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in, krb5.rc, version.rc: Add support for adding a
+		Windows Version resource to all of the DLL files.
+
+Tue Jul 29 23:09:31 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Remove msvcrt.lib from the explicit WINLIBS link
+ 		line since we're now using /MD and have removed the
+ 		/nodefaultlibs switch.  For now, build debug versions of
+		the libraries.
+
+	* krb5_16.def, krb5_32.def, sapkrb16.def: Add decode_krb5_ap_req
+ 		to the exported functions list, since the GSSAPI krb5
+ 		mechanism routine needs access to this internal routine.
+		
+Thu May  1 22:56:04 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, win_glue.c, sapkrb16.def, sapkrb32.def: Write
+		special case hack for the SAP kerberos libraries since we
+		can't make the version server code correctly read out the
+		version resource from SAPGUI.EXE for some reason....
+
+Tue Apr 29 06:22:03 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* win_glue.c (CallVersionServer): Add code to get the version
+		resource from the calling application and use that to call
+		the Version server.
+
+Fri Mar 28 01:51:09 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssapi16.def, gssapi32.def: Added the V2 calls
+ 		gss_canonicalize_name(), gss_export_name(),
+ 		gss_duplicate_name() to the list of calls exported by the
+ 		DLL.
+
+Wed Mar 19 14:15:42 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Fix up name of the SAP Kerberos glue library to be
+		platform dependent (sapkrb16.dll, sapkrb32.dll).  Fix
+		makefile rules to work correctly after NT port.
+
+Mon Mar  3 14:52:58 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Change KRB5 to krb5 for Mac subdirs.
+
+Tue Feb 25 01:03:41 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: krb5_32.lib now also depends on gdi32.lib
+
+Thu Feb 20 23:30:32 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Build krb4 dll; it built all the objs (win16/32)
+
+Mon Feb 17 19:40:55 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Build krb4 library under Win16/Win32
+	* krb4_16.def krb4_32.def: DLL definition files for krb4 library
+	* krb5_16.def krb5_32.def: Export various des routines (krb4 dll)
+	* win_glue.c: krb4 library support added
+
+Fri Feb 14 16:40:03 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Build separate ComErr DLL
+	* comerr16.def comerr32.def: ComErr exported API
+	* krb5_16.def krb5_32.def: Removed ComErr/Win16 entries
+	* no_glue.c: Dummy stub for ComErr (win16/win32)
+	* win_glue.c: Win32 DLL startup/exit code added
+
+Sat Feb  8 12:21:53 1997  Richard Basch  <basch@lehman.com>
+
+	* krb5_16.def krb5_32.def:
+		Export krb5_get_credentials_renew,krb5_get_credentials_validate
+
+	* Makefile.in:
+		Use WLIB definition in config/windows.in
+		Attempt at making a functional SAP library build
+
+Tue Feb  4 15:52:34 1997  Richard Basch  <basch@lehman.com>
+
+	* krb5_16.def krb5_32.def: New ComErr interface definitions
+
+	* gssapi32.def krb5_32.def:
+		Remove unsupported statements (EXETYPE, RESIDENTNAME)
+
+	* gssapi16.def krb5_16.def: Need to declare the library name (win16)
+
+Thu Jan 30 21:27:07 1997  Richard Basch  <basch@lehman.com>
+
+	* krb5_16.def krb5_32.def: 
+		Export krb5_decrypt, krb5_encrypt,
+		krb5_string_to_key, krb5_process_key, krb5_finish_key,
+		krb5_init_random_key, krb5_finish_random_key,
+		krb5_random_key, krb5_eblock_enctype
+	* Makefile.in
+		Win32 - Link against MSVCRT.LIB (runtime library)
+
+Sat Dec 21 01:23:48 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* win_glue.c: Change the timebomb to be June 1, 1997.  Make the
+		timebomb exit the application more gracefully.
+
+Fri Dec 20 18:20:32 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5_16.def: Change name of library in file to be krb5_16.def
+	 	[PR#302]
+
+Sat Nov 23 00:25:25 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+	
+	* libkrb5.def: Renamed to krb5_16.def [PR#204]
+
+	* Makefile.in (all-windows): Change name of dll from krb5_16.dll,
+		which will be the final name of the DLL. [PR#204]
+
+Wed Nov 20 18:28:47 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (clean-windows): Change the name of the Windows (16)
+		dll to be krb516.dll, instead of libkrb5.dll
+
+Fri Jul 12 20:32:29 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* win_glue.c: Added TIMEBOMB_INFO string which tells the user the
+ 	 	URL to look for more information about getting the new
+ 	 	version of the product.
+
+Wed Jul 10 20:32:22 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* win_glue.c (krb5_win_do_init): New routine which does the
+		timebomb and version server checking.  Windows 3.1 doesn't
+		allow you to do any messaging calls in LibMain, so the
+		timebomb and version server code was moved to
+		krb5_win_do_init(), which is called by krb5_init_context().
+
+Tue Jul  9 17:31:57 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in (CONFIG_DIRS): add rpc subdir
+
+Tue Jul  9 16:44:22 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* win_glue.c: Add a quick hack so we can time-bomb the libkrb5.dll
+		and sapkrb5.dll when we compile them at MIT.
+	
+	* Makefile.in (sap_glue.obj): Build the sapkrb5.dll with the
+		timebomb enabled (since we couldn't get the version server
+		code working).
+
+Wed Jun 12 12:52:30 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (lib-windows): Replace spaces with tab
+
+Mon Jun 10 23:40:48 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (lib-windows): Add production rule for sapkrb5.dll.
+		Don't include config/windows.in, since that's included
+		by wconfig.
+
+	* win_glue.c: Add a quick hack for krb5-SAP so that we call
+		the version server --- this is conditionalized on
+		SAP_VERSERV, which is only defined when we build
+		sapkrb5.dll.
+
+Sat Jun  8 09:58:41 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Remove kdb4 library building
+
+Thu Jun  6 00:04:38 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Don't pass $(LIBCMD) on the command
+		line.  It's set in the windows.in prologue for all Makefiles anyway.
+
+Tue May  7 20:18:13 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: libdes425 now depends on libkrb5.
+
+Fri Mar 15 15:21:32 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (CLEANLIBS): Add libkrb5util.a and libgssapi.a
+
+Thu Feb 29 16:49:33 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* win_glue.c: Make sure WSACleanup() is called when the DLL exits.
+		Note that calls to WSAStartup and WSACleanup must be in
+		matched pairs.  If there is a missing WSACleanup call when
+		a program exits, under Lan Workplace, the name resolver
+		will stop working.
+
+Tue Feb 27 18:47:17 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapi.def: We have implemented gss_inquire_names_for_mech, not
+	        gss_inquire_mechs_for_name.
+	
+Sat Feb 24 18:47:41 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapi.def: Add new GSSAPI V2 calls. (XXX we still need to get
+		the official function numbers defined for them.)
+
+Wed Feb  7 00:23:18 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Sun Dec  3 11:50:09 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Move krb5 before krb4 and add krb5util.
+
+Wed Oct 25 14:56:26 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (lib-windows): For the windows, add the oldnames
+		library to the link lines for gssapi.dll and libkrb5.dll
+
+Tue Oct 10 21:45:51 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Added the "/nod" option to the gssapi.dll and
+		libkrb5.dll linker commands.  This prevents the linker
+		from searching the llibcew.lib library for some externals
+		which are already in ldllcew.lib.  This is what we want
+		since we are building a DLL. Without the "/nod" option we
+		get a bunch of duplicate definitions.
+
+Fri Sep 29 14:19:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (CLEANLIBS): Clean up make clean procedures.  The
+		files to be removed are defined in CLEANLIBS, for both the
+		Unix and Mac platforms.
+
+Mon Sep 25 16:26:53 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+	* configure.in: Remove custom MAKE_SUBDIRS line with the
+		standard DO_SUBDIRS rule, which works now that we're
+		revamping how the foo-$(WHAT) system works.
+
+Wed Jul 12 12:25:15 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Temporarily add --with-kdb4 to select building of
+		kdb4 directory.  Default is disabled.
+
+
+Thu Jun 15 17:57:26 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Do not build K4 directories if we're not supposed to.
+		Remove LinkFile() logic and put it in each subdirectory.
+
+Wed Jun 14 07:36:46 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean-unix): Remove shared library symlinks
+
+	* configure.in: Create symlinks to libdes425.a
+		If shared libraries enabled, symlink the .so libraries
+
+Fri Jun  9 18:53:30 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Sun Jun  4 20:50:31 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Change order of library building to allow for
+		proper dependency order for shared libraries.
+
+Tue May 30 18:54:42 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: removed des425 stuff for Windows.
+
+Tue May 30 17:38:47 1995 Keith Vetter (keithv@fusion.com)
+
+	* libkrb5.def: added missing kadm routine name.
+
+Tue May 30 10:21:21 1995 Keith Vetter (keithv@fusion.com)
+
+	* libkrb5.def: added kadm exported routines.
+
+Fri May 26 10:18:04 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: add kadm directory for the PC.
+
+Tue May 23 22:25:03 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean-unix): Remove symlinks to libkrb4.a and
+		libkdb4.a. 
+
+Tue May  2 21:39:26 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: nuke spurious whitespace from blank line
+
+
+Fri Apr 28 15:32:54 EDT 1995	Paul Park	(pjpark@mit.edu)
+	Add kadm to list of directories to be built.
+
+Thu Apr 27 14:31:01 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: make links for libkrb4 and libkdb4.
+
+Wed Apr 27 11:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: need to include profile.lib in the DLL.
+
+Thu Apr 27 13:32:35 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: add kdb4 directory.
+
+Thu Apr 27 11:54:19 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: add krb4 directory (still needs to be
+	conditionalized on unix)
+
+Thu Apr 20 12:16:50 1995 Keith Vetter (keithv@fusion.com)
+
+	* win_glue.c: include k5-int.h instead of krb5.h.
+
+Mon Apr 17 17:47:07 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: forgot about the rule to make gssapi.lib on the PC.
+
+Wed Apr 12 14:40:30 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in, configure.in: Move dependency for all-$WHAT back
+		into Makefile.in so that the Windows port can pick up the
+		line (since it doesn't use configure).  Instead, change
+		the name of target which causes the subdirectories to be
+		built under Unix, and make that a dependency for all-unix.
+		Gross, but this should fix things for both DOS and Windows.
+
+Thu Apr 13 16:56:50 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in, libkrb5.def, gssapi.def (new): 
+           Spec says we need a gssapi.dll & gssapi.lib.
+        * Makefile.in: re-inserted make-$(ALL) rule.
+
+Wed Apr 5 16:27:53 1995 Keith Vetter (keithv@fusion.com)
+
+	* libkrb5.def: added krb5_us_timeofday to export list
+
+Fri Mar 31 16:15:59 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in, configure.in: Move the dependency which causes
+		all-$(WHAT) to be built so that it occurs after the "make
+		all" subdirectories rule.
+
+Thu Mar 30 15:46:23 1995 Keith Vetter (keithv@fusion.com)
+
+	* libkrb5.def: removed the masses of exported files, leaving just
+	   the ones needed by telnet and cns plus the gssapi ones.
+
+Tue Mar 28 18:26:01 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (clean-mac):  Add.
+	* configure.in (LinkFile's):  Put `./' on libraries to ease Mac
+	translation.
+	(AppendRule all-unix):  Rename from AppendRule all.
+
+Thu Mar 23 14:26:35 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: also produces a map for the dll.
+
+Tue Mar 21 18:59:15 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: added xxx-MAC targets for macintosh compatibility,
+	   and added gssapi to libkrb5 dll.
+	* libkrb5.def: added gssapi routines to the export section.
+
+Thu Mar 16 15:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: fixed up a typo.
+
+Wed Mar 15 22:45:33 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: I had missed some dependencies on the PC build.
+
+Wed Mar 15 20:45:33 1995 Keith Vetter (keithv@fusion.com)
+
+	* libkrb5.def, winsock.def, win_glue.c: new files for making DLL.
+        * Makefile.in: On the PC it recurses into all subdirs and builds
+           libkrb5.dll.
+
+Tue Feb 28 01:33:52 1995  John Gilmore  (gnu at toad.com)
+
+	* glue4.c:  Avoid <krb5/...> includes.
+
+Thu Oct  6 20:06:06 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add recursive "make check" target.
+
+Mon Oct  3 23:38:03 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Don't build the krb425 library.  It is deprecated.
+
+Fri Sep 30 16:35:16 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Also delete libkdb5.a on make clean.
+
+Thu Aug  4 03:39:23 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: make install fixes
+
diff --git a/mechglue/src/lib/Makefile.in b/mechglue/src/lib/Makefile.in
new file mode 100644
index 000000000..3e34ef0ef
--- /dev/null
+++ b/mechglue/src/lib/Makefile.in
@@ -0,0 +1,180 @@
+thisconfigdir=./..
+myfulldir=lib
+mydir=lib
+LOCAL_SUBDIRS=crypto krb5 des425 @KRB4@ gssapi rpc kdb kadm5 apputils
+BUILDTOP=$(REL)..
+
+all-unix::
+
+CLEANLIBS = libkrb5.a libkdb5.a libcrypto.a libgssapi_krb5.a libdes425.a \
+	libkrb425.a libkadm.a libkrb4.a libcom_err.a libpty.a \
+	libss.a libgssapi.a libapputils.a \
+	libkrb5.so libcrypto.so libkrb4.so libdes425.so
+
+clean-unix::
+
+clean-windows::
+
+# Windows stuff to make krb5 and gssapi DLLs.
+
+##MIT##!if !defined(VS_INC)
+##MIT##!message Must define VS_INC to point to version server include dir!
+##MIT##!error
+##MIT##!endif
+##MIT##!if !defined(VS_LIB)
+##MIT##!message Must define VS_LIB to point to version server library!
+##MIT##!error
+##MIT##!endif
+##MIT##MITLIBS=$(VS_LIB)
+##MIT##MITFLAGS=-I$(VS_INC) /DVERSERV=1
+
+SLIBS = $(BUILDTOP)\util\support\$(OUTPRE)k5sprt32.lib
+CLIBS = $(BUILDTOP)\util\et\$(OUTPRE)comerr.lib
+PLIBS = $(BUILDTOP)\util\profile\$(OUTPRE)profile.lib
+KLIBS = krb5\$(OUTPRE)krb5.lib crypto\$(OUTPRE)crypto.lib \
+	$(BUILDTOP)\util\profile\$(OUTPRE)profile.lib \
+	des425\$(OUTPRE)des425.lib
+GLIBS = gssapi\$(OUTPRE)gssapi.lib
+K4LIBS = krb4\$(OUTPRE)krb4.lib
+
+SDEF = k5sprt32.def
+CDEF = comerr32.def
+PDEF = xpprof32.def
+KDEF = krb5_32.def
+GDEF = gssapi32.def
+K4DEF = krb4_32.def
+
+KRB5RC = krb5.rc
+VERSIONRC = $(BUILDTOP)\windows\version.rc
+
+WINLIBS = kernel32.lib ws2_32.lib user32.lib shell32.lib oldnames.lib \
+	version.lib secur32.lib advapi32.lib gdi32.lib delayimp.lib
+WINDLLFLAGS = $(DLL_LINKOPTS) -base:0x1c000000 /DELAYLOAD:secur32.dll \
+	/DELAYLOAD:advapi32.dll /DELAY:UNLOAD /DELAY:NOBIND
+
+S_GLUE=$(OUTPRE)support_glue.obj
+K5_GLUE=$(OUTPRE)k5_glue.obj
+K4_GLUE=$(OUTPRE)k4_glue.obj
+GSS_GLUE=$(OUTPRE)gss_glue.obj
+COMERR_GLUE=$(OUTPRE)comerr_glue.obj
+PROF_GLUE=$(OUTPRE)prof_glue.obj
+
+SGLUE=$(S_GLUE)
+CGLUE=$(COMERR_GLUE)
+PGLUE=$(PROF_GLUE)
+KGLUE=$(K5_GLUE)
+GGLUE=$(GSS_GLUE)
+K4GLUE=$(K4_GLUE)
+
+RCFLAGS=$(CPPFLAGS) -I$(SRCTOP) -D_WIN32 -DRES_ONLY
+
+##WIN32##SRES=$(SLIB:.lib=.res)
+##WIN32##CRES=$(CLIB:.lib=.res)
+##WIN32##PRES=$(PLIB:.lib=.res)
+##WIN32##KRES=$(KLIB:.lib=.res)
+##WIN32##GRES=$(GLIB:.lib=.res)
+##WIN32##K4RES=$(K4LIB:.lib=.res)
+
+##WIN32##$(SRES): $(VERSIONRC)
+##WIN32##	$(RC) $(RCFLAGS) -DSUPPORT_LIB -fo $@ -r $**
+##WIN32##$(CRES): $(VERSIONRC)
+##WIN32##	$(RC) $(RCFLAGS) -DCE_LIB -fo $@ -r $**
+##WIN32##$(PRES): $(VERSIONRC)
+##WIN32##	$(RC) $(RCFLAGS) -DPROF_LIB -fo $@ -r $**
+##WIN32##$(KRES): $(KRB5RC)
+##WIN32##	$(RC) $(RCFLAGS) -DKRB5_LIB -fo $@ -r $**
+##WIN32##$(K4RES): $(VERSIONRC)
+##WIN32##	$(RC) $(RCFLAGS) -DKRB4_LIB -fo $@ -r $**
+##WIN32##$(GRES): $(VERSIONRC)
+##WIN32##	$(RC) $(RCFLAGS) -DGSSAPI_LIB -fo $@ -r $**
+##WIN32##$(KRB5RC): $(VERSIONRC)
+
+##WIN32##$(SLIB): $(SDEF) $(SLIBS) $(SGLUE) $(SRES)
+##WIN32##	link $(WINDLLFLAGS) -def:$(SDEF) -out:$*.dll \
+##WIN32##	  $(SLIBS) $(SGLUE) $(SRES) $(WINLIBS)
+$(SDEF): ..\util\support\libkrb5support.exports
+	echo EXPORTS > $(SDEF).new
+	type ..\util\support\libkrb5support.exports >> $(SDEF).new
+	-$(RM) $(SDEF)
+	ren $(SDEF).new $(SDEF)
+
+##WIN32##$(CLIB): $(CDEF) $(CLIBS) $(CGLUE) $(CRES) $(SLIB)
+##WIN32##	link $(WINDLLFLAGS) -def:$(CDEF) -out:$*.dll \
+##WIN32##	  $(CLIBS) $(CGLUE) $(CRES) $(SLIB) $(WINLIBS)
+
+##WIN32##$(PLIB): $(PDEF) $(PLIBS) $(PGLUE) $(PRES) $(CLIB) $(SLIB)
+##WIN32##	link $(WINDLLFLAGS) -def:$(PDEF) -out:$*.dll \
+##WIN32##	  $(PLIBS) $(PGLUE) $(PRES) $(CLIB) $(SLIB) $(WINLIBS)
+
+##WIN32##$(KLIB): $(KDEF) $(KLIBS) $(KGLUE) $(KRES) $(CLIB) $(SLIB) $(MITLIBS) $(DNSLIBS)
+##WIN32##	link $(WINDLLFLAGS) -def:$(KDEF) -out:$*.dll \
+##WIN32##	  $(KLIBS) $(KGLUE) $(KRES) $(CLIB) $(SLIB) $(MITLIBS) $(DNSLIBS) $(WINLIBS)
+
+##WIN32##$(GLIB): $(GDEF) $(GLIBS) $(GGLUE) $(GRES) $(KLIB) $(CLIB) $(SLIB)
+##WIN32##	link $(WINDLLFLAGS) -def:$(GDEF) -out:$*.dll \
+##WIN32##	  $(GLIBS) $(GGLUE) $(GRES) $(KLIB) $(CLIB) $(SLIB) $(WINLIBS)
+
+##WIN32##$(K4LIB): $(K4DEF) $(K4LIBS) $(K4GLUE) $(K4RES) $(KLIB) $(CLIB) $(PLIB)
+##WIN32##	link $(WINDLLFLAGS) -def:$(K4DEF) -out:$*.dll \
+##WIN32##	  $(K4LIBS) $(K4GLUE) $(K4RES) $(KLIB) $(CLIB) $(PLIB) $(WINLIBS)
+
+$(K5_GLUE): win_glue.c
+	$(CC) $(ALL_CFLAGS) $(MITFLAGS) /c /DKRB5=1 /Fo$@ $**
+$(K4_GLUE): win_glue.c
+	$(CC) $(ALL_CFLAGS) /c /DKRB4=1 /Fo$@ $**
+$(GSS_GLUE): win_glue.c
+	$(CC) $(ALL_CFLAGS) /c /DGSSAPI=1 /Fo$@ $**
+$(COMERR_GLUE): win_glue.c
+	$(CC) $(ALL_CFLAGS) /c /DCOMERR=1 /Fo$@ $**
+$(PROF_GLUE): win_glue.c
+	$(CC) $(ALL_CFLAGS) /c /DPROFILELIB=1 /Fo$@ $**
+$(S_GLUE): win_glue.c
+	$(CC) $(ALL_CFLAGS) /c /DSUPPORTLIB=1 /Fo$@ $**
+
+# Build Convenience
+comerr.lib: $(CLIB)
+krb4.lib:   $(K4LIB)
+krb5.lib:   $(KLIB)
+gssapi.lib: $(GLIB)
+profile.lib: $(PLIB)
+
+all-windows:: 
+	@echo Making in lib\crypto
+	cd crypto
+	$(MAKE) -$(MFLAGS)
+	@echo Making in lib\krb5
+	cd ..\krb5
+	$(MAKE) -$(MFLAGS)
+	@echo Making in lib\des425
+	cd ..\des425
+	$(MAKE) -$(MFLAGS) 
+	@echo Making in lib\krb4
+	cd ..\krb4
+	$(MAKE) -$(MFLAGS) 
+	@echo Making in lib\gssapi
+	cd ..\gssapi
+	$(MAKE) -$(MFLAGS) 
+	@echo Making in lib
+	cd ..
+
+all-windows:: lib-windows
+lib-windows:: krb5.lib gssapi.lib krb4.lib 
+
+clean-windows::
+	@echo Making clean in lib\crypto
+	cd crypto
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in lib\krb5
+	cd ..\krb5
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in lib\des425
+	cd ..\des425
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in lib\krb4
+	cd ..\krb4
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in lib\gssapi
+	cd ..\gssapi
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in lib
+	cd ..
diff --git a/mechglue/src/lib/apputils/ChangeLog b/mechglue/src/lib/apputils/ChangeLog
new file mode 100644
index 000000000..50aa6f21e
--- /dev/null
+++ b/mechglue/src/lib/apputils/ChangeLog
@@ -0,0 +1,14 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-02-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* New directory.
+	* Makefile.in, configure.in, dummy.c, daemon.c: Moved here from
+	util/apputils.
+
diff --git a/mechglue/src/lib/apputils/Makefile.in b/mechglue/src/lib/apputils/Makefile.in
new file mode 100644
index 000000000..be596f91a
--- /dev/null
+++ b/mechglue/src/lib/apputils/Makefile.in
@@ -0,0 +1,48 @@
+prefix=@prefix@
+bindir=@bindir@
+datadir=@datadir@
+mydatadir=$(datadir)/apputils
+thisconfigdir=.
+myfulldir=lib/apputils
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+RELDIR=../lib/apputils
+SED = sed
+
+##DOS##BUILDTOP = ..\..
+##DOS##LIBNAME=$(OUTPRE)apputils.lib
+##DOS##XTRA=
+##DOS##OBJFILE=$(OUTPRE)apputils.lst
+
+# LIBOBJS may or may not contain daemon.o; dummy.o is just here to
+# avoid having an empty library.
+STLIBOBJS=dummy.o @LIBOBJS@
+STOBJLISTS=OBJS.ST
+LIBBASE=apputils
+
+all-unix:: all-liblinks
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+install-unix:: install-libs
+
+LINTFLAGS=-uhvb 
+LINTFILES= daemon.c
+LIBOBJS=$(OUTPRE)daemon.$(OBJEXT)
+
+SRCS=	$(srcdir)/daemon.c \
+	$(srcdir)/dummy.c
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+daemon.so daemon.po $(OUTPRE)daemon.$(OBJEXT): daemon.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+dummy.so dummy.po $(OUTPRE)dummy.$(OBJEXT): dummy.c
diff --git a/mechglue/src/lib/apputils/configure.in b/mechglue/src/lib/apputils/configure.in
new file mode 100644
index 000000000..73e9a87aa
--- /dev/null
+++ b/mechglue/src/lib/apputils/configure.in
@@ -0,0 +1,6 @@
+K5_AC_INIT(daemon.c)
+CONFIG_RULES
+AC_REPLACE_FUNCS(daemon)
+KRB5_BUILD_LIBRARY_STATIC
+KRB5_BUILD_LIBOBJS
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/lib/apputils/daemon.c b/mechglue/src/lib/apputils/daemon.c
new file mode 100644
index 000000000..00dde4882
--- /dev/null
+++ b/mechglue/src/lib/apputils/daemon.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <unistd.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
+int
+daemon(nochdir, noclose)
+	int nochdir, noclose;
+{
+	int cpid;
+
+	if ((cpid = fork()) == -1)
+		return (-1);
+	if (cpid)
+		exit(0);
+#ifdef HAVE_SETSID
+	(void) setsid();
+#else
+#ifndef TIOCNOTTY
+	setpgrp();
+#else
+	{
+		int n;
+	    
+		/*
+		 * The open below may hang on pseudo ttys if the person
+		 * who starts named logs out before this point.  Thus,
+		 * the need for the timer.
+		 */
+		alarm(120);
+		n = open("/dev/tty", O_RDWR);
+		alarm(0);
+		if (n > 0) {
+			(void) ioctl(n, TIOCNOTTY, (char *)NULL);
+			(void) close(n);
+		}
+	}
+#endif
+#endif
+	if (!nochdir)
+		(void) chdir("/");
+	if (!noclose) {
+		int devnull = open(_PATH_DEVNULL, O_RDWR, 0);
+
+		if (devnull != -1) {
+			(void) dup2(devnull, 0);
+			(void) dup2(devnull, 1);
+			(void) dup2(devnull, 2);
+			if (devnull > 2)
+				(void) close(devnull);
+		}
+	}
+	return (0);
+}
diff --git a/mechglue/src/lib/apputils/dummy.c b/mechglue/src/lib/apputils/dummy.c
new file mode 100644
index 000000000..d5b6cc08d
--- /dev/null
+++ b/mechglue/src/lib/apputils/dummy.c
@@ -0,0 +1 @@
+int lib_server_dummy = 0;
diff --git a/mechglue/src/lib/ccapi/ChangeLog b/mechglue/src/lib/ccapi/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/client/ChangeLog b/mechglue/src/lib/ccapi/client/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/client/NTMakefile b/mechglue/src/lib/ccapi/client/NTMakefile
new file mode 100644
index 000000000..09ef9df38
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/NTMakefile
@@ -0,0 +1,22 @@
+!INCLUDE <WIN32.MAK>
+
+CFLAGS = -I../include
+
+CCAPI_OBJS = cacheapi.obj context.obj ccache.obj credentials.obj ccache_iterator.obj \
+             credentials_iterator.obj ccstring.obj marshall.obj msg.obj 
+
+CCAPI_LIB = ccapi.lib
+
+$(CCAPI_LIB): $(CCAPI_OBJS)
+        $(implib) /NOLOGO /OUT:$@ $**
+
+CCAPI_DLLFILE = krbcc32.dll
+
+
+
+$(CCAPI_DLLFILE): $(CCAPI_LIB)
+        $(DLLGUILINK) -def:windows\krbcc32.def
+        $(DLLPREP)
+
+clean:
+        del *.obj *.lib
diff --git a/mechglue/src/lib/ccapi/client/cacheapi.c b/mechglue/src/lib/ccapi/client/cacheapi.c
new file mode 100644
index 000000000..2c874bec0
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/cacheapi.c
@@ -0,0 +1,118 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CredentialsCache.h>
+#include "ccache.h"
+#include "ccache_iterator.h"
+#include "context.h"
+#include "msg.h"
+#include "msg_headers.h"
+
+cc_int32 
+cc_initialize (	cc_context_t*		outContext,
+                cc_int32		inVersion,
+                cc_int32*		outSupportedVersion,
+                char const**		outVendor)
+{
+    static char vendor[128] = "";
+    cc_msg_t     *request;
+    ccmsg_init_t *request_header;
+    cc_msg_t     *response;
+    ccmsg_init_resp_t *response_header;
+    cc_int32 code;
+
+    if ((inVersion != ccapi_version_2) &&
+         (inVersion != ccapi_version_3) &&
+         (inVersion != ccapi_version_4) &&
+         (inVersion != ccapi_version_5)) {
+
+        if (outSupportedVersion != NULL) {
+            *outSupportedVersion = ccapi_version_5;
+        }
+        return ccErrBadAPIVersion;
+    }   
+
+    request_header = (ccmsg_init_t*)malloc(sizeof(ccmsg_init_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    request_header->in_version = inVersion;
+
+    code = cci_msg_new(ccmsg_INIT, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_init_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_init_resp_t *)response->header;
+        *outSupportedVersion = response_header->out_version;
+        code = cc_context_int_new(outContext, response_header->out_ctx, response_header->out_version);
+
+        if (!vendor[0]) {
+            char * string;
+            code = cci_msg_retrieve_blob(response, response_header->vendor_offset, response_header->vendor_length, &string);
+            strncpy(vendor, string, sizeof(vendor)-1);
+            vendor[sizeof(vendor)-1] = '\0';
+            free(string);
+        } 
+        *outVendor = vendor;
+
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
diff --git a/mechglue/src/lib/ccapi/client/ccache.c b/mechglue/src/lib/ccapi/client/ccache.c
new file mode 100644
index 000000000..5de3880e4
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/ccache.c
@@ -0,0 +1,1098 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+
+/* ccache.c */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CredentialsCache.h>
+#include "credentials.h"
+#include "ccache.h"
+#include "msg.h"
+#include "msg_headers.h"
+
+cc_int32
+cc_int_ccache_new( cc_ccache_t * pccache, cc_handle hctx, cc_handle hccache )
+{
+    cc_int_ccache_t ccache = (cc_int_ccache_t)malloc(sizeof(cc_int_ccache_d));
+    if ( ccache == NULL )
+        return ccErrNoMem;
+
+    ccache->functions = (cc_ccache_f*)malloc(sizeof(cc_ccache_f));
+    if ( ccache->functions == NULL ) {
+        free(ccache);
+        return ccErrNoMem;
+    }
+
+    ccache->functions->release = cc_int_ccache_release;
+    ccache->functions->destroy = cc_int_ccache_destroy;
+    ccache->functions->set_default = cc_int_ccache_set_default;
+    ccache->functions->get_credentials_version = cc_int_ccache_get_credentials_version;
+    ccache->functions->get_name = cc_int_ccache_get_name;
+    ccache->functions->get_principal = cc_int_ccache_get_principal;
+    ccache->functions->set_principal = cc_int_ccache_set_principal;
+    ccache->functions->store_credentials = cc_int_ccache_store_credentials;
+    ccache->functions->remove_credentials = cc_int_ccache_remove_credentials;
+    ccache->functions->new_credentials_iterator = cc_int_ccache_new_credentials_iterator;
+    ccache->functions->move = cc_int_ccache_move;
+    ccache->functions->lock = cc_int_ccache_lock;
+    ccache->functions->unlock = cc_int_ccache_unlock;
+    ccache->functions->get_last_default_time = cc_int_ccache_get_last_default_time;
+    ccache->functions->get_change_time = cc_int_ccache_get_change_time;
+    ccache->functions->compare = cc_int_ccache_compare;
+    ccache->functions->get_kdc_time_offset = cc_int_ccache_get_kdc_time_offset;
+    ccache->functions->set_kdc_time_offset = cc_int_ccache_set_kdc_time_offset;
+    ccache->functions->clear_kdc_time_offset = cc_int_ccache_clear_kdc_time_offset;
+
+    ccache->magic = CC_CCACHE_MAGIC;
+    ccache->ctx = hctx;
+    ccache->handle = hccache;
+
+    *pccache = (cc_ccache_t)ccache;
+
+    return ccNoError;
+}
+
+cc_int32    
+cc_int_ccache_release( cc_ccache_t ccache )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_release_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_release_t*)malloc(sizeof(ccmsg_ccache_release_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_RELEASE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_release_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    free(int_ccache->functions);
+    free(int_ccache);
+    return code;
+}
+
+
+cc_int32    
+cc_int_ccache_destroy( cc_ccache_t ccache )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_destroy_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_destroy_t*)malloc(sizeof(ccmsg_ccache_destroy_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_DESTROY, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_destroy_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    free(ccache);
+    return code;
+}
+
+
+cc_int32
+cc_int_ccache_set_default( cc_ccache_t ccache )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_set_default_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_set_default_t*)malloc(sizeof(ccmsg_ccache_set_default_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_SET_DEFAULT, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_set_default_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_get_credentials_version( cc_ccache_t ccache,
+                                   cc_uint32* credentials_version)
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_get_creds_version_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_get_creds_version_t*)malloc(sizeof(ccmsg_ccache_get_creds_version_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_GET_CREDS_VERSION, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_get_creds_version_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        ccmsg_ccache_get_creds_version_resp_t * response_header = (ccmsg_ccache_get_creds_version_resp_t*)response->header;
+        *credentials_version = response_header->version;
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_get_name( cc_ccache_t ccache,
+                    cc_string_t* name )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_get_name_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_get_name_t*)malloc(sizeof(ccmsg_ccache_get_name_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_GET_NAME, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_get_name_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        char * string;
+        ccmsg_ccache_get_name_resp_t * response_header = (ccmsg_ccache_get_name_resp_t*)response->header;
+        code = cci_msg_retrieve_blob(response, response_header->name_offset, 
+                                      response_header->name_len, &string);
+        if (code == ccNoError) {
+            code = cc_string_new(&name, string);
+            free(string);
+        }
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_get_principal( cc_ccache_t ccache,
+                        cc_uint32 credentials_version,
+                        cc_string_t* principal )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_get_principal_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_get_principal_t*)malloc(sizeof(ccmsg_ccache_get_principal_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+    request_header->version = credentials_version;
+
+    code = cci_msg_new(ccmsg_CCACHE_GET_PRINCIPAL, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_get_principal_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        char * string;
+        ccmsg_ccache_get_principal_resp_t * response_header = (ccmsg_ccache_get_principal_resp_t*)response->header;
+        code = cci_msg_retrieve_blob(response, response_header->principal_offset, 
+                                      response_header->principal_len, &string);
+        if (code == ccNoError) {
+            code = cc_string_new(&principal, string);
+            free(string);
+        }
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_set_principal( cc_ccache_t ccache,
+                         cc_uint32 credentials_version,
+                         const char* principal )
+{
+    cc_uint32   blob_pos;
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_set_principal_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_set_principal_t*)malloc(sizeof(ccmsg_ccache_set_principal_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+    request_header->version = credentials_version;
+
+    code = cci_msg_new(ccmsg_CCACHE_GET_PRINCIPAL, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_data_blob(request, (void*)principal, strlen(principal) + 1, &blob_pos);
+    if (code != ccNoError) {
+        cci_msg_destroy(request);
+        free(request_header);
+        return code;
+    }
+    
+    request_header->principal_offset = blob_pos;
+    request_header->principal_len = strlen(principal) + 1;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_set_principal_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_new_credentials_iterator( cc_ccache_t ccache,
+                                        cc_credentials_iterator_t* iterator )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_creds_iterator_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_creds_iterator_t*)malloc(sizeof(ccmsg_ccache_creds_iterator_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_CREDS_ITERATOR, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_creds_iterator_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        ccmsg_ccache_creds_iterator_resp_t * response_header = (ccmsg_ccache_creds_iterator_resp_t*)response->header;
+        code = cc_int_credentials_iterator_new(iterator, response_header->iterator);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_store_credentials( cc_ccache_t ccache,
+                             const cc_credentials_union* credentials )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_store_creds_t *request_header;
+    cc_msg_t        *response;
+    char            *flat_cred = 0;
+    cc_uint32       flat_cred_len = 0;
+    cc_uint32       blob_pos;
+    cc_int32 code;
+
+    if ( ccache == NULL || credentials == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_store_creds_t*)malloc(sizeof(ccmsg_ccache_store_creds_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_STORE_CREDS, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    switch ( credentials->version ) {
+    case cc_credentials_v4:
+        code = cci_creds_v4_marshall(credentials->credentials.credentials_v4, &flat_cred, &flat_cred_len);
+        break;
+    case cc_credentials_v5:
+        code = cci_creds_v5_marshall(credentials->credentials.credentials_v5, &flat_cred, &flat_cred_len);
+        break;
+    default:
+        cci_msg_destroy(request);
+        free(request_header);
+        return ccErrBadCredentialsVersion;
+    }
+    if (code != ccNoError) {
+        cci_msg_destroy(request);
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_data_blob(request, (void*)flat_cred, flat_cred_len, &blob_pos);
+    if (code != ccNoError) {
+        cci_msg_destroy(request);
+        free(request_header);
+        return code;
+    }
+    
+    request_header->creds_version = credentials->version;
+    request_header->creds_offset = blob_pos;
+    request_header->creds_len = flat_cred_len;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_store_creds_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    free(flat_cred);
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_remove_credentials( cc_ccache_t ccache,
+                              cc_credentials_t credentials )
+{
+    cc_int_ccache_t int_ccache;
+    cc_int_credentials_t  int_creds;
+    cc_msg_t        *request;
+    ccmsg_ccache_rem_creds_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL || credentials == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+    int_creds  = (cc_int_credentials_t)credentials;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    if ( int_creds->magic != CC_CREDS_MAGIC )
+        return ccErrInvalidCredentials;
+
+    request_header = (ccmsg_ccache_rem_creds_t*)malloc(sizeof(ccmsg_ccache_rem_creds_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+    request_header->creds  = int_creds->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_REM_CREDS, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_rem_creds_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+
+cc_int32
+cc_int_ccache_move( cc_ccache_t source,
+                    cc_ccache_t destination )
+{
+    cc_int_ccache_t int_ccache_source;
+    cc_int_ccache_t int_ccache_dest;
+    cc_msg_t        *request;
+    ccmsg_ccache_move_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( source == NULL || destination == NULL )
+        return ccErrBadParam;
+
+    int_ccache_source = (cc_int_ccache_t)source;
+    int_ccache_dest = (cc_int_ccache_t)destination;
+
+    if ( int_ccache_source->magic != CC_CCACHE_MAGIC ||
+         int_ccache_dest->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    if ( int_ccache_source->ctx != int_ccache_dest->ctx )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ccache_move_t*)malloc(sizeof(ccmsg_ccache_move_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CCACHE_MOVE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    request_header->ctx = int_ccache_source->ctx;
+    request_header->ccache_source = int_ccache_source->handle;
+    request_header->ccache_dest = int_ccache_dest->handle;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_move_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}       
+
+cc_int_ccache_lock( cc_ccache_t ccache,
+                cc_uint32 lock_type,
+                cc_uint32 block )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_lock_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL || 
+         (lock_type != cc_lock_read && lock_type != cc_lock_write) ||
+         (block != cc_lock_block && block != cc_lock_noblock) )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_lock_t*)malloc(sizeof(ccmsg_ccache_lock_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CCACHE_LOCK, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+    request_header->lock_type;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_lock_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+
+        // TODO: if (block == cc_lock_block) .....
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_unlock( cc_ccache_t ccache )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_unlock_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_unlock_t*)malloc(sizeof(ccmsg_ccache_unlock_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CCACHE_UNLOCK, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_unlock_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+
+cc_int32
+cc_int_ccache_get_last_default_time( cc_ccache_t ccache,
+                                     cc_time_t* time_offset )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_get_last_default_time_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_get_last_default_time_t*)malloc(sizeof(ccmsg_ccache_get_last_default_time_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_GET_LAST_DEFAULT_TIME, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_get_last_default_time_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        ccmsg_ccache_get_last_default_time_resp_t * response_header = (ccmsg_ccache_get_last_default_time_resp_t*)response->header;
+        *time_offset = response_header->last_default_time;
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_get_change_time( cc_ccache_t ccache,
+                           cc_time_t* time )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_get_change_time_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_get_change_time_t*)malloc(sizeof(ccmsg_ccache_get_change_time_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_GET_CHANGE_TIME, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_get_change_time_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        ccmsg_ccache_get_change_time_resp_t * response_header = (ccmsg_ccache_get_change_time_resp_t*)response->header;
+        *time = response_header->time;
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_compare( cc_ccache_t ccache,
+                   cc_ccache_t compare_to,
+                   cc_uint32* equal )
+{
+    cc_int_ccache_t int_ccache;
+    cc_int_ccache_t int_compare_to;
+    cc_msg_t        *request;
+    ccmsg_ccache_compare_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+    int_compare_to = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC ||
+         int_compare_to->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_compare_t*)malloc(sizeof(ccmsg_ccache_compare_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache1 = int_ccache->handle;
+    request_header->ccache2 = int_compare_to->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_COMPARE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_compare_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        ccmsg_ccache_compare_resp_t * response_header = (ccmsg_ccache_compare_resp_t*)response->header;
+        *equal = response_header->is_equal;
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32	
+cc_int_ccache_get_kdc_time_offset( cc_ccache_t ccache,
+                               cc_int32	credentials_version,
+                               cc_time_t*	time_offset )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_get_kdc_time_offset_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_get_kdc_time_offset_t*)malloc(sizeof(ccmsg_ccache_get_kdc_time_offset_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+    request_header->creds_version = credentials_version;
+
+    code = cci_msg_new(ccmsg_CCACHE_GET_KDC_TIME_OFFSET, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_get_kdc_time_offset_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        ccmsg_ccache_get_kdc_time_offset_resp_t * response_header = (ccmsg_ccache_get_kdc_time_offset_resp_t*)response->header;
+        *time_offset = response_header->offset;
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_ccache_set_kdc_time_offset( cc_ccache_t ccache,
+                               cc_int32	credentials_version,
+                               cc_time_t	time_offset )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_set_kdc_time_offset_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_set_kdc_time_offset_t*)malloc(sizeof(ccmsg_ccache_set_kdc_time_offset_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+    request_header->creds_version = credentials_version;
+
+    code = cci_msg_new(ccmsg_CCACHE_SET_KDC_TIME_OFFSET, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_set_kdc_time_offset_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+                                
+cc_int32
+cc_int_ccache_clear_kdc_time_offset( cc_ccache_t	ccache,
+                                 cc_int32	credentials_version )
+{
+    cc_int_ccache_t int_ccache;
+    cc_msg_t        *request;
+    ccmsg_ccache_clear_kdc_time_offset_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_ccache = (cc_int_ccache_t)ccache;
+
+    if ( int_ccache->magic != CC_CCACHE_MAGIC )
+        return ccErrInvalidCCache;
+
+    request_header = (ccmsg_ccache_clear_kdc_time_offset_t*)malloc(sizeof(ccmsg_ccache_clear_kdc_time_offset_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_ccache->ctx;
+    request_header->ccache = int_ccache->handle;
+    request_header->creds_version = credentials_version;
+
+    code = cci_msg_new(ccmsg_CCACHE_CLEAR_KDC_TIME_OFFSET, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_clear_kdc_time_offset_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+
diff --git a/mechglue/src/lib/ccapi/client/ccache.h b/mechglue/src/lib/ccapi/client/ccache.h
new file mode 100644
index 000000000..e3b3993ee
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/ccache.h
@@ -0,0 +1,146 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* ccache.h */
+
+#define CC_CCACHE_MAGIC ('C'<<24 | 'C'<<16 | 'A'<<8 | 'C')
+
+struct cc_int_ccache_d {
+    cc_ccache_f*	functions;
+#if TARGET_OS_MAC
+    const cc_ccache_f*	otherFunctions;
+#endif
+    cc_uint32           magic;
+    cc_handle           handle;
+    cc_handle           ctx;
+};
+typedef struct cc_int_ccache_d  cc_int_ccache_d;
+typedef cc_int_ccache_d*        cc_int_ccache_t;
+
+
+cc_int32
+cc_int_ccache_new( cc_ccache_t * pccache, cc_handle hctx, cc_handle hccache );
+
+cc_int32    
+cc_int_ccache_release( cc_ccache_t ccache );
+
+cc_int32    
+cc_int_ccache_destroy( cc_ccache_t ccache );
+
+cc_int32
+cc_int_ccache_set_default( cc_ccache_t ccache );
+
+cc_int32
+cc_int_ccache_get_credentials_version( cc_ccache_t ccache,
+                                  cc_uint32* credentials_version);   
+
+cc_int32
+cc_int_ccache_get_name( cc_ccache_t ccache,
+                   cc_string_t* name );
+
+cc_int32
+cc_int_ccache_get_principal( cc_ccache_t ccache,
+                        cc_uint32 credentials_version,
+                        cc_string_t* principal );
+
+cc_int32
+cc_int_ccache_set_principal( cc_ccache_t ccache,
+                        cc_uint32 credentials_version,
+                        const char* principal );
+
+cc_int32
+cc_int_ccache_store_credentials( cc_ccache_t ccache,
+                            const cc_credentials_union* credentials );
+
+cc_int32
+cc_int_ccache_remove_credentials( cc_ccache_t ccache,
+                              cc_credentials_t credentials );
+
+cc_int32
+cc_int_ccache_new_credentials_iterator( cc_ccache_t ccache,
+                                        cc_credentials_iterator_t* iterator );
+
+cc_int32
+cc_int_ccache_move( cc_ccache_t source,
+               cc_ccache_t destination );
+
+cc_int32
+cc_int_ccache_lock( cc_ccache_t ccache,
+               cc_uint32 block,
+               cc_uint32 lock_type );
+
+cc_int32
+cc_int_ccache_unlock( cc_ccache_t ccache );
+
+cc_int32
+cc_int_ccache_get_last_default_time( cc_ccache_t ccache,
+                                cc_time_t* time );
+
+cc_int32
+cc_int_ccache_get_change_time( cc_ccache_t ccache,
+                          cc_time_t* time );
+
+cc_int32
+cc_int_ccache_compare( cc_ccache_t ccache,
+                  cc_ccache_t compare_to,
+                  cc_uint32* equal );
+
+cc_int32	
+cc_int_ccache_get_kdc_time_offset( cc_ccache_t ccache,
+                              cc_int32	credentials_version,
+                              cc_time_t*	time_offset );
+
+cc_int32
+cc_int_ccache_set_kdc_time_offset( cc_ccache_t ccache,
+                              cc_int32	credentials_version,
+                              cc_time_t	time_offset );
+                                
+cc_int32
+cc_int_ccache_clear_kdc_time_offset( cc_ccache_t	ccache,
+                                cc_int32	credentials_version );
+
+
+cc_int32
+cc_int_ccache_compat_clone( cc_int_ccache_t     ccache,
+                            cc_int_ccache_t    *clone );
+
diff --git a/mechglue/src/lib/ccapi/client/ccache_iterator.c b/mechglue/src/lib/ccapi/client/ccache_iterator.c
new file mode 100644
index 000000000..03266b1bb
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/ccache_iterator.c
@@ -0,0 +1,179 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* ccache_iterator.c */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CredentialsCache.h>
+#include "ccache_iterator.h"
+#include "msg.h"
+#include "msg_headers.h"
+
+
+cc_int32
+cc_int_ccache_iterator_new( cc_ccache_iterator_t * piter,
+                            cc_handle ctx,
+                            cc_handle handle )
+{
+    cc_int_ccache_iterator_t iter;
+
+    if ( piter == NULL )
+        return ccErrBadParam;
+
+    iter = (cc_int_ccache_iterator_t) malloc( sizeof(cc_int_ccache_iterator_d) );
+    if ( iter == NULL )
+        return ccErrNoMem;
+
+    iter->functions = (cc_ccache_iterator_f*)malloc( sizeof(cc_ccache_iterator_f));
+    if ( iter->functions ) {
+        free(iter);
+        return ccErrNoMem;
+    }
+
+    iter->functions->release = cc_int_ccache_iterator_release;
+    iter->functions->next = cc_int_ccache_iterator_next;
+    iter->magic = CC_CCACHE_ITER_MAGIC;
+    iter->ctx = ctx;
+    iter->handle = handle;
+
+    *piter = (cc_ccache_iterator_t)iter;
+    return ccNoError;
+}
+
+cc_int32
+cc_int_ccache_iterator_release( cc_ccache_iterator_t iter )
+{
+    cc_int_ccache_iterator_t int_iter;
+    cc_msg_t        *request;
+    ccmsg_ccache_iterator_release_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+
+    if ( iter == NULL )
+        return ccErrBadParam;
+
+    int_iter = (cc_int_ccache_iterator_t) iter;
+
+    if ( int_iter->magic != CC_CCACHE_ITER_MAGIC )
+        return ccErrInvalidCCacheIterator;
+
+    request_header = (ccmsg_ccache_iterator_release_t*)malloc(sizeof(ccmsg_ccache_iterator_release_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_iter->ctx;
+    request_header->iterator = int_iter->handle;
+    code = cci_msg_new(ccmsg_CCACHE_ITERATOR_RELEASE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_iterator_release_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+
+    free(int_iter->functions);
+    free(int_iter);
+    return ccNoError;
+}
+
+cc_int32
+cc_int_ccache_iterator_next( cc_ccache_iterator_t iter,
+                             cc_ccache_t * ccache )
+{
+    cc_int_ccache_iterator_t int_iter;
+    cc_msg_t        *request;
+    ccmsg_ccache_iterator_next_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrBadParam;
+
+    int_iter = (cc_int_ccache_iterator_t)iter;
+
+    if ( int_iter->magic != CC_CCACHE_ITER_MAGIC )
+        return ccErrInvalidCCacheIterator;
+
+    request_header = (ccmsg_ccache_iterator_next_t*)malloc(sizeof(ccmsg_ccache_iterator_next_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_iter->ctx;
+    request_header->iterator = int_iter->handle;
+
+    code = cci_msg_new(ccmsg_CCACHE_ITERATOR_NEXT, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_iterator_next_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        ccmsg_ccache_iterator_next_resp_t * response_header = (ccmsg_ccache_iterator_next_resp_t*)response->header;
+        code = cc_ccache_new(ccache, int_iter->ctx, response_header->ccache);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
diff --git a/mechglue/src/lib/ccapi/client/ccache_iterator.h b/mechglue/src/lib/ccapi/client/ccache_iterator.h
new file mode 100644
index 000000000..c55d72ee6
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/ccache_iterator.h
@@ -0,0 +1,85 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* ccache_iterator.h */
+
+#define CC_CCACHE_ITER_MAGIC ('C'<<24 | 'C'<<16 | 'I'<<8 | 'T')
+
+struct cc_int_ccache_iterator_d {
+    cc_ccache_iterator_f*	functions;
+#if TARGET_OS_MAC
+    cc_ccache_iterator_f*	otherFunctions;
+#endif
+    cc_uint32           magic;
+    cc_handle           handle;
+    cc_handle           ctx;
+
+    cc_uint32           repeat_count;
+    cc_ccache_t         compat_copy;
+};
+typedef struct cc_int_ccache_iterator_d cc_int_ccache_iterator_d;
+typedef cc_int_ccache_iterator_d*	cc_int_ccache_iterator_t;
+
+
+cc_int32
+cc_int_ccache_iterator_new( cc_ccache_iterator_t * piter,
+                            cc_handle ctx,
+                            cc_handle handle );
+
+cc_int32
+cc_int_ccache_iterator_release( cc_ccache_iterator_t iter );
+
+cc_int32
+cc_int_ccache_iterator_next( cc_ccache_iterator_t iter,
+                             cc_ccache_t * ccache );
+
+cc_int32
+cc_int_ccache_iterator_set_repeat_count( cc_int_ccache_iterator_t iter, 
+                                         cc_uint32 count );
+
+cc_int32
+cc_int_ccache_iterator_get_repeat_count( cc_int_ccache_iterator_t iter, 
+                                         cc_uint32 * count );
+
+
+
diff --git a/mechglue/src/lib/ccapi/client/ccstring.c b/mechglue/src/lib/ccapi/client/ccstring.c
new file mode 100644
index 000000000..419bfef77
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/ccstring.c
@@ -0,0 +1,94 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* ccstring.c */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <CredentialsCache.h>
+#include "ccstring.h"
+
+cc_int32
+cc_int_string_new( cc_string_t * pstring, char * data )
+{
+    cc_int_string_t string = (cc_int_string_t)malloc(sizeof(cc_int_string_d));
+    if ( string == NULL )
+        return ccErrNoMem;
+
+    string->functions = (cc_string_f *)malloc(sizeof(cc_string_f));
+    if ( string->functions == NULL ) {
+        free(string);
+        return ccErrNoMem;
+    }
+
+    string->magic = CC_STRING_MAGIC;
+    string->functions->release = cc_int_string_release;
+
+    string->data = strdup(data);
+    if ( string->data == NULL ) {
+        free(string->functions);
+        free(string);
+        return ccErrNoMem;
+    }
+
+    *pstring = (cc_string_t)string;
+    return ccNoError;
+}
+
+cc_int32
+cc_int_string_release( cc_string_t str )
+{
+    cc_int_string_t int_string;
+    if ( str == NULL )
+        return ccErrBadParam;
+
+    int_string = (cc_int_string_t)str;
+    if ( int_string->magic != CC_STRING_MAGIC )
+        return ccErrInvalidString;
+
+    free(int_string->functions);
+    free(int_string->data);
+    free(int_string);
+    return ccNoError;
+}
diff --git a/mechglue/src/lib/ccapi/client/ccstring.h b/mechglue/src/lib/ccapi/client/ccstring.h
new file mode 100644
index 000000000..9e0ad223f
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/ccstring.h
@@ -0,0 +1,65 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* ccstring.h */
+
+#define CC_STRING_MAGIC ('S'<<24 | 'T'<<16 | 'R'<<8 | 'I')
+
+struct cc_int_string_d {
+    char*         data;
+    cc_string_f*  functions;
+#if TARGET_OS_MAC
+    cc_string_f*  otherFunctions;
+#endif
+    cc_uint32           magic;
+};
+typedef struct cc_int_string_d cc_int_string_d;
+typedef cc_int_string_d*    cc_int_string_t;
+
+cc_int32
+cc_int_string_new( cc_string_t * pstring, char * data );
+
+cc_int32
+cc_int_string_release( cc_string_t string );
+
+
diff --git a/mechglue/src/lib/ccapi/client/context.c b/mechglue/src/lib/ccapi/client/context.c
new file mode 100644
index 000000000..86c41b8e7
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/context.c
@@ -0,0 +1,849 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* context.c */                                                 
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CredentialsCache.h>
+#include "context.h"
+#include "msg.h"
+#include "msg_headers.h"
+
+cc_int32
+cc_int_context_new( cc_context_t * pcontext, cc_handle handle, cc_uint32 version )
+{
+    cc_int_context_t context = (cc_int_context_t)malloc(sizeof(cc_int_context_d));
+    if (context == NULL)
+        return ccErrNoMem;
+
+    context->functions = (cc_context_f*)malloc(sizeof(cc_context_f));
+    if (context->functions == NULL) {
+        free(context);
+        return ccErrNoMem;
+    }
+
+    context->functions->release = cc_int_context_release;
+    context->functions->get_change_time = cc_int_context_get_change_time;
+    context->functions->get_default_ccache_name = cc_int_context_get_default_ccache_name;
+    context->functions->open_ccache = cc_int_context_open_ccache;
+    context->functions->open_default_ccache = cc_int_context_open_default_ccache;
+    context->functions->create_ccache = cc_int_context_create_ccache;
+    context->functions->create_default_ccache = cc_int_context_create_default_ccache;
+    context->functions->create_new_ccache = cc_int_context_create_new_ccache;
+    context->functions->new_ccache_iterator = cc_int_context_new_ccache_iterator;
+    context->functions->lock = cc_int_context_lock;
+    context->functions->unlock = cc_int_context_unlock;
+    context->functions->compare = cc_int_context_compare;
+
+    context->magic = CC_CONTEXT_MAGIC;
+    context->handle = handle;
+    context->api_version = version;
+
+    *pcontext = (cc_context_t)context;
+    return ccNoError;
+}
+
+cc_int32    
+cc_int_context_release( cc_context_t context )
+{
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ctx_release_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( context == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ctx_release_t*)malloc(sizeof(ccmsg_ctx_release_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_context->handle;
+
+    code = cci_msg_new(ccmsg_CTX_RELEASE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ctx_release_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    free(int_context->functions);
+    free(int_context);
+    return code;
+}
+
+cc_int32
+cc_int_context_get_change_time( cc_context_t context,
+                                cc_time_t* time)
+{
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ctx_get_change_time_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ctx_get_change_time_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL || time == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ctx_get_change_time_t*)malloc(sizeof(ccmsg_ctx_get_change_time_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_context->handle;
+
+    code = cci_msg_new(ccmsg_CTX_GET_CHANGE_TIME, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ctx_get_change_time_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_ctx_get_change_time_resp_t*)response->header;
+        *time = response_header->time;
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_get_default_ccache_name( cc_context_t context,
+                                        cc_string_t* name )
+{
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ctx_get_default_ccache_name_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ctx_get_default_ccache_name_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL || name == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ctx_get_default_ccache_name_t*)malloc(sizeof(ccmsg_ctx_get_default_ccache_name_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_context->handle;
+
+    code = cci_msg_new(ccmsg_CTX_GET_DEFAULT_CCACHE_NAME, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ctx_get_default_ccache_name_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        char * string;
+        response_header = (ccmsg_ctx_get_default_ccache_name_resp_t*)response->header;
+        code = cci_msg_retrieve_blob(response, response_header->name_offset, 
+                                     response_header->name_len, &string);
+        if (code == ccNoError) {
+            code = cc_string_new(&name, string);
+            free(string);
+        }
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_compare( cc_context_t context,
+                        cc_context_t compare_to,
+                        cc_uint32* equal )
+{
+    cc_int_context_t int_context, int_compare_to;
+    cc_msg_t        *request;
+    ccmsg_ctx_compare_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ctx_compare_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL || compare_to == NULL || 
+         equal == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+    int_compare_to = (cc_int_context_t)compare_to;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC ||
+         int_compare_to->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ctx_compare_t*)malloc(sizeof(ccmsg_ctx_compare_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx1 = int_context->handle;
+    request_header->ctx2 = int_compare_to->handle;
+
+    code = cci_msg_new(ccmsg_CTX_COMPARE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ctx_compare_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_ctx_compare_resp_t*)response->header;
+        *equal = response_header->is_equal;
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+
+cc_int32
+cc_int_context_new_ccache_iterator( cc_context_t context,
+                                    cc_ccache_iterator_t* iterator )
+{
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ctx_new_ccache_iterator_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ctx_new_ccache_iterator_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL || iterator == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ctx_new_ccache_iterator_t*)malloc(sizeof(ccmsg_ctx_new_ccache_iterator_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_context->handle;
+
+    code = cci_msg_new(ccmsg_CTX_NEW_CCACHE_ITERATOR, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ctx_new_ccache_iterator_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_ctx_new_ccache_iterator_resp_t*)response->header;
+        code = cc_int_ccache_iterator_new(iterator, int_context->handle, response_header->iterator);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_open_ccache( cc_context_t context,
+                            const char* name,
+                            cc_ccache_t* ccache )
+{
+    cc_uint32 blob_pos;
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ccache_open_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ccache_open_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL || name == NULL || ccache == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ccache_open_t*)malloc(sizeof(ccmsg_ccache_open_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CCACHE_OPEN, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_data_blob(request, (void *)name, strlen(name) + 1, &blob_pos);
+    if (code != ccNoError) {
+        cci_msg_destroy(request);
+        free(request_header);
+        return code;
+    }
+    
+    request_header->ctx = int_context->handle;
+    request_header->name_offset = blob_pos;
+    request_header->name_len = strlen(name) + 1;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_open_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_ccache_open_resp_t*)response->header;
+        code = cc_cache_new(ccache, response_header->ccache);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_open_default_ccache( cc_context_t context,
+                                    cc_ccache_t* ccache)
+{
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ccache_open_default_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ccache_open_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL || ccache == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ccache_open_default_t*)malloc(sizeof(ccmsg_ccache_open_default_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CCACHE_OPEN_DEFAULT, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    request_header->ctx = int_context->handle;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_open_default_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_ccache_open_resp_t*)response->header;
+        code = cc_cache_new(ccache, response_header->ccache);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_create_ccache( cc_context_t context,
+                              const char* name,
+                              cc_uint32 cred_vers,
+                              const char* principal, 
+                              cc_ccache_t* ccache )
+{
+    cc_uint32 blob_pos;
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ccache_create_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ccache_create_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL || name == NULL || 
+         cred_vers == 0 || cred_vers > cc_credentials_v4_v5 ||
+         principal == NULL || ccache == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ccache_create_t*)malloc(sizeof(ccmsg_ccache_create_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CCACHE_CREATE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_data_blob(request, (void *)name, strlen(name) + 1, &blob_pos);
+    if (code != ccNoError) {
+        cci_msg_destroy(request);
+        free(request_header);
+        return code;
+    }
+    
+    request_header->ctx = int_context->handle;
+    request_header->version = cred_vers;
+    request_header->name_offset = blob_pos;
+    request_header->name_len = strlen(name) + 1;
+
+    code = cci_msg_add_data_blob(request, (void *)principal, strlen(principal) + 1, &blob_pos);
+    if (code != ccNoError) {
+        cci_msg_destroy(request);
+        free(request_header);
+        return code;
+    }
+    request_header->principal_offset = blob_pos;
+    request_header->principal_len = strlen(principal) + 1;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_create_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_ccache_create_resp_t*)response->header;
+        code = cc_cache_new(ccache, response_header->ccache);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_create_default_ccache( cc_context_t context,
+                                      cc_uint32 cred_vers,
+                                      const char* principal, 
+                                      cc_ccache_t* ccache )
+{
+    cc_uint32 blob_pos;
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ccache_create_default_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ccache_create_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL ||
+         cred_vers == 0 || cred_vers > cc_credentials_v4_v5 ||
+         principal == NULL || ccache == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ccache_create_default_t*)malloc(sizeof(ccmsg_ccache_create_default_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CCACHE_CREATE_DEFAULT, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    request_header->ctx = int_context->handle;
+    request_header->version = cred_vers;
+
+    code = cci_msg_add_data_blob(request, (void *)principal, strlen(principal) + 1, &blob_pos);
+    if (code != ccNoError) {
+        cci_msg_destroy(request);
+        free(request_header);
+        return code;
+    }
+    request_header->principal_offset = blob_pos;
+    request_header->principal_len = strlen(principal) + 1;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_create_default_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_ccache_create_resp_t*)response->header;
+        code = cc_cache_new(ccache, response_header->ccache);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_create_new_ccache( cc_context_t context,
+                                  cc_uint32 cred_vers,
+                                  const char* principal, 
+                                  cc_ccache_t* ccache )
+{
+    cc_uint32 blob_pos;
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ccache_create_unique_t *request_header;
+    cc_msg_t        *response;
+    ccmsg_ccache_create_resp_t *response_header;
+    cc_int32 code;
+
+    if ( context == NULL ||
+         cred_vers == 0 || cred_vers > cc_credentials_v4_v5 ||
+         principal == NULL || ccache == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ccache_create_unique_t*)malloc(sizeof(ccmsg_ccache_create_unique_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CCACHE_CREATE_UNIQUE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    request_header->ctx = int_context->handle;
+    request_header->version = cred_vers;
+
+    code = cci_msg_add_data_blob(request, (void *)principal, strlen(principal) + 1, &blob_pos);
+    if (code != ccNoError) {
+        cci_msg_destroy(request);
+        free(request_header);
+        return code;
+    }
+    request_header->principal_offset = blob_pos;
+    request_header->principal_len = strlen(principal) + 1;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ccache_create_unique_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_ccache_create_resp_t*)response-> header;
+        code = cc_cache_new(ccache, response_header->ccache);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+ 
+cc_int32
+cc_int_context_lock( cc_context_t context,
+                     cc_uint32 lock_type,
+                     cc_uint32 block )
+{
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ctx_lock_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( context == NULL || 
+         (lock_type != cc_lock_read && lock_type != cc_lock_write) ||
+         (block != cc_lock_block && block != cc_lock_noblock) )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ctx_lock_t*)malloc(sizeof(ccmsg_ctx_lock_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CTX_LOCK, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    request_header->ctx = int_context->handle;
+    request_header->lock_type;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ctx_lock_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+
+        // TODO: if (block == cc_lock_block) .....
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_unlock( cc_context_t context )
+{
+    cc_int_context_t int_context;
+    cc_msg_t        *request;
+    ccmsg_ctx_unlock_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( context == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    request_header = (ccmsg_ctx_unlock_t*)malloc(sizeof(ccmsg_ctx_unlock_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CTX_UNLOCK, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    request_header->ctx = int_context->handle;
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_ctx_unlock_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_clone( cc_context_t      inContext,
+                      cc_context_t*     outContext,
+                      cc_int32          requestedVersion,
+                      cc_int32*         supportedVersion,
+                      char const**      vendor )
+{
+    cc_int_context_t int_context, new_context;
+    static char vendor_st[128] = "";
+    cc_msg_t     *request;
+    ccmsg_clone_t *request_header;
+    cc_msg_t     *response;
+    ccmsg_clone_resp_t *response_header;
+    cc_int32 code;
+
+    if ( inContext == NULL ||
+         outContext == NULL ||
+         supportedVersion == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    if ((requestedVersion != ccapi_version_2) &&
+         (requestedVersion != ccapi_version_3) &&
+         (requestedVersion != ccapi_version_4) &&
+         (requestedVersion != ccapi_version_5)) {
+
+        if (supportedVersion != NULL) {
+            *supportedVersion = ccapi_version_5;
+        }
+        return ccErrBadAPIVersion;
+    }   
+
+    request_header = (ccmsg_clone_t*)malloc(sizeof(ccmsg_clone_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+
+    request_header->ctx = int_context->handle;
+    request_header->in_version = requestedVersion;
+
+    code = cci_msg_new(ccmsg_INIT, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_init_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        response_header = (ccmsg_clone_resp_t *)response->header;
+        *supportedVersion = response_header->out_version;
+        code = cc_int_context_new(outContext, response_header->out_ctx, response_header->out_version);
+
+        if (!vendor_st[0]) {
+            char * string;
+            code = cci_msg_retrieve_blob(response, response_header->vendor_offset, response_header->vendor_length, &string);
+            strncpy(vendor_st, string, sizeof(vendor_st)-1);
+            vendor_st[sizeof(vendor_st)-1] = '\0';
+            free(string);
+        } 
+        *vendor = vendor_st;
+
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
+
+cc_int32
+cc_int_context_get_version( cc_context_t        context,
+                            cc_int32*           version )
+{
+    cc_int_context_t int_context;
+    cc_int32 code;
+
+    if ( context == NULL ||
+         version == NULL )
+        return ccErrBadParam;
+
+    int_context = (cc_int_context_t)context;
+
+    if ( int_context->magic != CC_CONTEXT_MAGIC )
+        return ccErrInvalidContext;
+
+    *version = int_context->api_version;
+    return ccNoError;
+}
+
+
diff --git a/mechglue/src/lib/ccapi/client/context.h b/mechglue/src/lib/ccapi/client/context.h
new file mode 100644
index 000000000..cd5ca678d
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/context.h
@@ -0,0 +1,131 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* context.h */
+
+#define CC_CONTEXT_MAGIC ('C'<<24 | 'C'<<16 | 'T'<<8 | 'X')
+
+struct cc_int_context {
+    cc_context_f*	functions;
+
+    cc_uint32           magic;
+#ifdef CCAPI_V2_COMPAT
+    cc_uint32           version;
+#endif
+    cc_uint32           api_version;
+    cc_handle           handle;
+};
+typedef struct cc_int_context cc_int_context_d;
+typedef cc_int_context_d*     cc_int_context_t;
+
+cc_int32
+cc_int_context_new( cc_context_t *pcontext, cc_handle handle, cc_uint32 version );
+
+cc_int32    
+cc_int_context_release( cc_context_t context );
+
+cc_int32
+cc_int_context_get_change_time( cc_context_t context,
+                                cc_time_t* time);
+
+cc_int32
+cc_int_context_get_default_ccache_name( cc_context_t context,
+                                        cc_string_t* name );
+
+cc_int32
+cc_int_context_open_ccache( cc_context_t context,
+                            const char* name,
+                            cc_ccache_t* ccache );
+
+cc_int32
+cc_int_context_open_default_ccache( cc_context_t context,
+                                    cc_ccache_t* ccache );
+
+cc_int32
+cc_int_context_create_ccache( cc_context_t context,
+                              const char* name,
+                              cc_uint32 cred_vers,
+                              const char* principal, 
+                              cc_ccache_t* ccache );
+
+cc_int32
+cc_int_context_create_default_ccache( cc_context_t context,
+                                      cc_uint32 cred_vers,
+                                      const char* principal, 
+                                      cc_ccache_t* ccache );
+
+cc_int32
+cc_int_context_create_new_ccache( cc_context_t context,
+                                  cc_uint32 cred_vers,
+                                  const char* principal, 
+                                  cc_ccache_t* ccache );
+ 
+cc_int32
+cc_int_context_new_ccache_iterator( cc_context_t context,
+                                    cc_ccache_iterator_t* iterator );
+
+cc_int32
+cc_int_context_lock( cc_context_t context,
+                     cc_uint32 lock_type,
+                     cc_uint32 block );
+
+cc_int32
+cc_int_context_unlock( cc_context_t context );
+
+cc_int32
+cc_int_context_compare( cc_context_t context,
+                        cc_context_t compare_to,
+                        cc_uint32*   equal );
+
+cc_int32
+cc_int_context_clone( cc_context_t      inContext,
+                      cc_context_t*     outContext,
+                      cc_int32          requestedVersion,
+                      cc_int32*         supportedVersion,
+                      char const**      vendor );
+
+cc_int32
+cc_int_context_get_version( cc_context_t        context,
+                            cc_int32*           version );
+
+
diff --git a/mechglue/src/lib/ccapi/client/credentials.c b/mechglue/src/lib/ccapi/client/credentials.c
new file mode 100644
index 000000000..b0a3df2b7
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/credentials.c
@@ -0,0 +1,181 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* credentials.c */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CredentialsCache.h>
+#include "credentials.h"
+#include "msg.h"
+#include "msg_headers.h"
+
+
+cc_int32
+cc_int_credentials_new( cc_credentials_t *pcredentials, cc_uint32 version, 
+                    cc_handle ctx, cc_handle ccache, cc_handle handle, 
+                    char * data, cc_uint32 len )
+{
+    cc_int_credentials_t credentials;
+    cc_int32 code;
+    
+    if ( pcredentials == NULL )
+        return ccErrBadParam;
+
+    credentials = (cc_int_credentials_t)malloc(sizeof(cc_int_credentials_d));
+    if ( credentials == NULL )
+        return ccErrNoMem;
+
+    credentials->data = (cc_credentials_union *)malloc(sizeof(cc_credentials_union));
+    if ( credentials->data == NULL ) {
+        free(credentials);
+        return ccErrNoMem;
+    }
+
+    credentials->functions = (cc_credentials_f *)malloc(sizeof(cc_credentials_f));
+    if ( credentials->functions == NULL ) {
+        free(credentials->data);
+        free(credentials);
+        return ccErrNoMem;
+    }
+
+    credentials->functions->release = cc_int_credentials_release;
+    credentials->functions->compare = cc_int_credentials_compare;
+    credentials->magic = CC_CREDS_MAGIC;
+    credentials->ctx = ctx;
+    credentials->ccache = ccache;
+    credentials->handle = handle;
+
+    switch ( version ) {
+    case cc_credentials_v4:
+        code = cci_cred_v4_unmarshall(data, len, credentials->data);
+        break;
+    case cc_credentials_v5:
+        code = cci_cred_v5_unmarshall(data, len, credentials->data);
+        break;
+    default:
+        free(credentials);
+        return ccErrBadCredentialsVersion;
+    }
+
+    *pcredentials = (cc_credentials_t)credentials;
+    return ccNoError;
+}
+
+
+cc_int32
+cc_int_credentials_release( cc_credentials_t creds )
+{
+    cc_int_credentials_t int_creds;
+    unsigned short i;
+
+    if ( creds == NULL )
+        return ccErrBadParam;
+
+    int_creds = (cc_int_credentials_t)creds;
+
+    if ( int_creds->magic != CC_CREDS_MAGIC )
+        return ccErrInvalidCredentials;
+
+    switch (int_creds->data->version) {
+    case cc_credentials_v4:
+        free(int_creds->data->credentials.credentials_v4);
+        break;
+    case cc_credentials_v5:
+        if ( int_creds->data->credentials.credentials_v5->client )
+            free(int_creds->data->credentials.credentials_v5->client);
+        if ( int_creds->data->credentials.credentials_v5->server )
+            free(int_creds->data->credentials.credentials_v5->server );
+        if ( int_creds->data->credentials.credentials_v5->keyblock.data )
+            free(int_creds->data->credentials.credentials_v5->keyblock.data);
+        if ( int_creds->data->credentials.credentials_v5->ticket.data )
+            free(int_creds->data->credentials.credentials_v5->ticket.data);
+        if ( int_creds->data->credentials.credentials_v5->second_ticket.data )
+            free(int_creds->data->credentials.credentials_v5->second_ticket.data);
+        if ( int_creds->data->credentials.credentials_v5->addresses ) {
+            for ( i=0; int_creds->data->credentials.credentials_v5->addresses[i]; i++) {
+                if (int_creds->data->credentials.credentials_v5->addresses[i]->data)
+                    free(int_creds->data->credentials.credentials_v5->addresses[i]->data);
+            }
+            free(int_creds->data->credentials.credentials_v5->addresses);
+        }
+        if ( int_creds->data->credentials.credentials_v5->authdata ) {
+            for ( i=0; int_creds->data->credentials.credentials_v5->authdata[i]; i++) {
+                if ( int_creds->data->credentials.credentials_v5->authdata[i]->data )
+                    free(int_creds->data->credentials.credentials_v5->authdata[i]->data);
+            }
+            free(int_creds->data->credentials.credentials_v5->authdata);
+        }
+        break;
+    default:
+        return ccErrBadCredentialsVersion;
+    }
+
+    free(int_creds->functions);
+    free(int_creds->data);
+    free(int_creds);
+    return ccNoError;
+}
+
+cc_int32
+cc_int_credentials_compare( cc_credentials_t credentials,
+                        cc_credentials_t compare_to,
+                        cc_uint32* equal )
+{
+    cc_int_credentials_t int_credentials;
+    cc_int_credentials_t int_compare_to;
+
+    if ( credentials == NULL || compare_to == NULL || equal == NULL )
+        return ccErrBadParam;
+
+    
+    if ( int_credentials->magic != CC_CREDS_MAGIC ||
+         int_compare_to->magic != CC_CREDS_MAGIC )
+        return ccErrInvalidCredentials;
+
+    int_credentials = (cc_int_credentials_t)credentials;
+    int_compare_to  = (cc_int_credentials_t)compare_to;
+
+    *equal = (int_credentials->handle == int_compare_to->handle);
+    return ccNoError;
+}
diff --git a/mechglue/src/lib/ccapi/client/credentials.h b/mechglue/src/lib/ccapi/client/credentials.h
new file mode 100644
index 000000000..320c61825
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/credentials.h
@@ -0,0 +1,94 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* credentials.h */
+
+#define CC_CREDS_MAGIC ('C'<<24 | 'R'<<16 | 'E'<<8 | 'D')
+
+struct cc_int_credentials_d {
+    cc_credentials_union* data;
+    cc_credentials_f* functions;
+#if TARGET_OS_MAC
+    cc_credentials_f*     otherFunctions;
+#endif
+    cc_uint32   magic;
+    cc_handle   ctx;
+    cc_handle   ccache;
+    cc_handle   handle;
+};
+typedef struct cc_int_credentials_d cc_int_credentials_d;
+typedef cc_int_credentials_d* cc_int_credentials_t;
+
+cc_int32
+cc_int_credentials_new( cc_credentials_t * pcredentials, cc_uint32 version, 
+                    cc_handle ctx, cc_handle ccache, cc_handle handle, 
+                    char * data, cc_uint32 len);
+
+cc_int32
+cc_int_credentials_release( cc_credentials_t credentials );
+
+cc_int32
+cc_int_credentials_compare( cc_credentials_t credentials,
+                        cc_credentials_t compare_to,
+                        cc_uint32* equal );
+
+cc_int32
+cci_creds_v4_marshall( cc_credentials_v4_t * creds, 
+                       char ** flat, 
+                       cc_uint32 * len);
+
+cc_int32
+cci_creds_v5_marshall( cc_credentials_v5_t * creds, 
+                       char ** flat, 
+                       cc_uint32 * len);
+
+cc_int32
+cci_creds_v4_unmarshall( char * flat, 
+                             cc_uint32 len,
+                             cc_credentials_union * creds);
+
+cc_int32
+cci_creds_v5_unmarshall( char * flat, 
+                         cc_uint32 len,
+                         cc_credentials_union * creds);
+
diff --git a/mechglue/src/lib/ccapi/client/credentials_iterator.c b/mechglue/src/lib/ccapi/client/credentials_iterator.c
new file mode 100644
index 000000000..b7333daf3
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/credentials_iterator.c
@@ -0,0 +1,187 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* credentials_iterator.c */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CredentialsCache.h>
+#include "credentials_iterator.h"
+#include "msg.h"
+#include "msg_headers.h"
+
+
+cc_int32
+cc_int_credentials_iterator_new( cc_credentials_iterator_t * piter, 
+                                 cc_handle ctx,
+                                 cc_handle ccache,
+                                 cc_handle handle )
+{
+    cc_int_credentials_iterator_t iter;
+
+    if ( piter == NULL )
+        return ccErrBadParam;
+
+    iter = (cc_int_credentials_iterator_t) malloc( sizeof(cc_int_credentials_iterator_d) );
+    if ( iter == NULL )
+        return ccErrNoMem;
+
+    iter->functions = (cc_credentials_iterator_f*)malloc(sizeof(cc_credentials_iterator_f));
+    if ( iter->functions == NULL ) {
+        free(iter);
+        return ccErrNoMem;
+    }
+
+    iter->functions->release = cc_int_credentials_iterator_release;
+    iter->functions->next = cc_int_credentials_iterator_next;
+    iter->magic = CC_CREDS_ITER_MAGIC;
+    iter->ctx = ctx;
+    iter->ccache = ccache;
+    iter->handle = handle;
+
+    *piter = (cc_credentials_iterator_t) iter;
+    return ccNoError;
+}
+
+cc_int32
+cc_int_credentials_iterator_release( cc_credentials_iterator_t iter )
+{
+    cc_int_credentials_iterator_t int_iter;
+    cc_msg_t        *request;
+    ccmsg_creds_iterator_release_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( iter == NULL )
+        return ccErrBadParam;
+
+    int_iter = (cc_int_credentials_iterator_t) iter;
+
+    if ( int_iter->magic != CC_CREDS_ITER_MAGIC )
+        return ccErrInvalidCredentialsIterator;
+
+    request_header = (ccmsg_creds_iterator_release_t*)malloc(sizeof(ccmsg_creds_iterator_release_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_iter->ctx;
+    request_header->ccache = int_iter->ccache;
+    request_header->iterator = int_iter->handle;
+    code = cci_msg_new(ccmsg_CREDS_ITERATOR_RELEASE, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_creds_iterator_release_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        code = ccNoError;
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+
+    free(int_iter->functions);
+    free(int_iter);
+    return ccNoError;
+}
+
+cc_int32
+cc_int_credentials_iterator_next( cc_credentials_iterator_t iter,
+                                  cc_credentials_t * credentials )
+{
+    cc_int_credentials_iterator_t int_iter;
+    cc_msg_t        *request;
+    ccmsg_creds_iterator_next_t *request_header;
+    cc_msg_t        *response;
+    cc_int32 code;
+
+    if ( credentials == NULL )
+        return ccErrBadParam;
+
+    int_iter = (cc_int_credentials_iterator_t)iter;
+
+    if ( int_iter->magic != CC_CREDS_ITER_MAGIC )
+        return ccErrInvalidCredentialsIterator;
+
+    request_header = (ccmsg_creds_iterator_next_t*)malloc(sizeof(ccmsg_creds_iterator_next_t));
+    if (request_header == NULL)
+        return ccErrNoMem;
+    request_header->ctx = int_iter->ctx;
+    request_header->ccache = int_iter->ccache;
+    request_header->iterator = int_iter->handle;
+
+    code = cci_msg_new(ccmsg_CREDS_ITERATOR_NEXT, &request);
+    if (code != ccNoError) {
+        free(request_header);
+        return code;
+    }
+
+    code = cci_msg_add_header(request, request_header, sizeof(ccmsg_creds_iterator_next_t));
+
+    code = cci_perform_rpc(request, &response);
+
+    if (response->type == ccmsg_NACK) {
+        ccmsg_nack_t * nack_header = (ccmsg_nack_t *)response->header;
+        code = nack_header->err_code;
+    } else if (response->type == ccmsg_ACK) {
+        char * blob;
+        ccmsg_creds_iterator_next_resp_t * response_header = (ccmsg_creds_iterator_next_resp_t*)response->header;
+        code = cci_msg_retrieve_blob(response, response_header->creds_offset, response_header->creds_len, &blob);
+        code = cc_credentials_new(credentials, response_header->version,
+                                  int_iter->ctx, int_iter->ccache, response_header->creds_handle, 
+                                  blob, response_header->creds_len);
+        free(blob);
+    } else {
+        code = ccErrBadInternalMessage;
+    }
+    cci_msg_destroy(request);
+    cci_msg_destroy(response);
+    return code;
+}
diff --git a/mechglue/src/lib/ccapi/client/credentials_iterator.h b/mechglue/src/lib/ccapi/client/credentials_iterator.h
new file mode 100644
index 000000000..2a6f8edf2
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/credentials_iterator.h
@@ -0,0 +1,72 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* credentials_iterator.h */
+
+#define CC_CREDS_ITER_MAGIC ('C'<<24 | 'R'<<16 | 'I'<<8 | 'T')
+
+struct cc_int_credentials_iterator_d {
+    cc_credentials_iterator_f*	functions;
+#if TARGET_OS_MAC
+    cc_credentials_iterator_f*	otherFunctions;
+#endif
+    cc_uint32   magic;
+    cc_handle   handle;
+    cc_handle   ccache;
+    cc_handle   ctx;
+};
+typedef struct cc_int_credentials_iterator_d cc_int_credentials_iterator_d;
+typedef cc_int_credentials_iterator_d*	cc_int_credentials_iterator_t;
+
+
+cc_int32
+cc_int_credentials_iterator_new( cc_credentials_iterator_t * piter, cc_handle ctx, cc_handle ccache, cc_handle iter );
+
+cc_int32
+cc_int_credentials_iterator_release( cc_credentials_iterator_t iter );
+
+cc_int32
+cc_int_credentials_iterator_next( cc_credentials_iterator_t iter,
+                                  cc_credentials_t * credentials );
+
+
diff --git a/mechglue/src/lib/ccapi/client/mac/ChangeLog b/mechglue/src/lib/ccapi/client/mac/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/mac/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/client/windows/ChangeLog b/mechglue/src/lib/ccapi/client/windows/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/client/windows/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/include/ChangeLog b/mechglue/src/lib/ccapi/include/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/include/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/include/CredentialsCache.h b/mechglue/src/lib/ccapi/include/CredentialsCache.h
new file mode 100644
index 000000000..dd60fa46d
--- /dev/null
+++ b/mechglue/src/lib/ccapi/include/CredentialsCache.h
@@ -0,0 +1,567 @@
+/* $Copyright:
+ *
+ * Copyright 1998-2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* $Header$ */
+
+/*
+ * Declarations for Credentials Cache API Library
+ *
+ * API specification: <http://web.mit.edu/pismere/kerberos/ccache-api-v2.html>
+ *
+ *	Revision 1: Frank Dabek, 6/4/1998
+ *	Revision 2: meeroh, 2/24/1999
+ *      Revision 3: meeroh, 11/12/1999
+ *      Revision 4: jaltman, 10/27/2004
+ *
+ */
+ 
+#ifndef __CREDENTIALSCACHE__
+#define __CREDENTIALSCACHE__
+
+#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
+	#include <TargetConditionals.h>
+    #if TARGET_RT_MAC_CFM
+        #error "Use KfM 4.0 SDK headers for CFM compilation."
+    #endif
+#endif
+
+#if TARGET_OS_MAC
+    #include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if TARGET_OS_MAC
+    #if defined(__MWERKS__)
+        #pragma import on
+        #pragma enumsalwaysint on
+    #endif
+    #pragma options align=mac68k
+#endif
+
+#include <time.h>
+
+/*
+ * Constants
+ */
+ 
+/* API versions */
+enum {
+    ccapi_version_2 = 2,
+    ccapi_version_3 = 3,
+    ccapi_version_4 = 4,
+    ccapi_version_5 = 5
+};
+ 
+/* Errors */
+enum {
+    ccNoError							= 0,
+
+    ccIteratorEnd						= 201,
+    ccErrBadParam,
+    ccErrNoMem,
+    ccErrInvalidContext,
+    ccErrInvalidCCache,
+
+    ccErrInvalidString,					/* 206 */
+    ccErrInvalidCredentials,
+    ccErrInvalidCCacheIterator,
+    ccErrInvalidCredentialsIterator,
+    ccErrInvalidLock,
+
+    ccErrBadName,						/* 211 */
+    ccErrBadCredentialsVersion,
+    ccErrBadAPIVersion,
+    ccErrContextLocked,
+    ccErrContextUnlocked,
+
+    ccErrCCacheLocked,					/* 216 */
+    ccErrCCacheUnlocked,
+    ccErrBadLockType,
+    ccErrNeverDefault,
+    ccErrCredentialsNotFound,
+
+    ccErrCCacheNotFound,					/* 221 */
+    ccErrContextNotFound,
+    ccErrServerUnavailable,
+    ccErrServerInsecure,
+    ccErrServerCantBecomeUID,
+    
+    ccErrTimeOffsetNotSet,				/* 226 */
+    ccErrBadInternalMessage,
+    ccErrNotImplemented
+};
+
+/* Credentials versions */
+enum {
+    cc_credentials_v4 = 1,
+    cc_credentials_v5 = 2,
+    cc_credentials_v4_v5 = 3
+};
+
+/* Lock types */
+enum {
+    cc_lock_read = 1,
+    cc_lock_write = 2
+};
+
+/* Locking Modes */
+enum {
+    cc_lock_noblock = 0,
+    cc_lock_block = 1
+};
+
+/*
+ * Basic types
+ */
+ 
+typedef char           cc_int8;
+typedef unsigned char  cc_uint8;
+typedef int            cc_int32;
+typedef unsigned int   cc_uint32;
+typedef time_t         cc_time_t;
+typedef void *         cc_handle;
+
+/*
+ * API types
+ */
+ 
+/* Forward declarations */
+struct cc_context_f;
+typedef struct cc_context_f cc_context_f;
+
+struct cc_ccache_f;
+typedef struct cc_ccache_f cc_ccache_f;
+
+struct cc_ccache_iterator_f;
+typedef struct cc_ccache_iterator_f cc_ccache_iterator_f;
+
+struct cc_ccache_iterator_f;
+typedef struct cc_credentials_iterator_f cc_credentials_iterator_f;
+
+struct cc_string_f;
+typedef struct cc_string_f cc_string_f;
+
+struct cc_credentials_f;
+typedef struct cc_credentials_f cc_credentials_f;
+
+/* Credentials types */
+
+enum {	/* Make sure all of these are multiples of four (for alignment sanity) */
+    cc_v4_name_size		= 40,
+    cc_v4_instance_size	= 40,
+    cc_v4_realm_size	= 40,
+    cc_v4_ticket_size	= 1254
+};
+
+enum cc_string_to_key_type {
+    cc_v4_stk_afs = 0,
+    cc_v4_stk_des = 1,
+    cc_v4_stk_columbia_special = 2,
+    cc_v4_stk_krb5 = 3,
+    cc_v4_stk_unknown = 4
+};
+
+struct cc_credentials_v4_t {
+    cc_uint32			version;
+    char			principal [cc_v4_name_size];
+    char			principal_instance [cc_v4_instance_size];
+    char			service [cc_v4_name_size];
+    char			service_instance [cc_v4_instance_size];
+    char			realm [cc_v4_realm_size];
+    unsigned char		session_key [8];
+    cc_int32			kvno;
+    cc_int32			string_to_key_type;
+    cc_time_t			issue_date;
+    cc_int32			lifetime;
+    cc_uint32			address;
+    cc_int32			ticket_size;
+    unsigned char		ticket [cc_v4_ticket_size];
+};      
+typedef struct cc_credentials_v4_t cc_credentials_v4_t;
+
+struct cc_data {
+    cc_uint32			type;
+    cc_uint32			length;
+    void*			data;
+};      
+typedef struct cc_data cc_data;
+
+struct cc_credentials_v5_t {
+    char*			client;
+    char*			server;
+    cc_data			keyblock;
+    cc_time_t			authtime;
+    cc_time_t			starttime;
+    cc_time_t			endtime;
+    cc_time_t			renew_till;
+    cc_uint32			is_skey;
+    cc_uint32			ticket_flags;
+    cc_data**			addresses;
+    cc_data			ticket;
+    cc_data			second_ticket;
+    cc_data**			authdata;
+};      
+typedef struct cc_credentials_v5_t cc_credentials_v5_t;
+
+struct cc_credentials_union {
+    cc_int32			version;
+    union {
+        cc_credentials_v4_t*	credentials_v4;
+        cc_credentials_v5_t*	credentials_v5;
+    }				credentials;
+};
+typedef struct cc_credentials_union cc_credentials_union;
+
+/* Exposed parts */
+
+struct cc_context_d {
+    const cc_context_f*	functions;
+#if TARGET_OS_MAC
+    const cc_context_f*	otherFunctions;
+#endif
+};
+typedef struct cc_context_d cc_context_d;
+typedef cc_context_d*	cc_context_t;
+
+struct cc_ccache_d {
+    const cc_ccache_f*	functions;
+#if TARGET_OS_MAC
+    const cc_ccache_f*	otherFunctions;
+#endif
+};
+typedef struct cc_ccache_d cc_ccache_d;
+typedef cc_ccache_d*	cc_ccache_t;
+
+struct cc_ccache_iterator_d {
+    const cc_ccache_iterator_f*	functions;
+#if TARGET_OS_MAC
+    const cc_ccache_iterator_f*	otherFunctions;
+#endif
+};
+typedef struct cc_ccache_iterator_d cc_ccache_iterator_d;
+typedef cc_ccache_iterator_d*	cc_ccache_iterator_t;
+
+struct cc_credentials_iterator_d {
+    const cc_credentials_iterator_f*	functions;
+#if TARGET_OS_MAC
+    const cc_credentials_iterator_f*	otherFunctions;
+#endif
+};
+typedef struct cc_credentials_iterator_d cc_credentials_iterator_d;
+typedef cc_credentials_iterator_d*	cc_credentials_iterator_t;
+
+struct cc_string_d {
+    const char*			data;
+    const cc_string_f*	functions;
+#if TARGET_OS_MAC
+    const cc_string_f*	otherFunctions;
+#endif
+};
+typedef struct cc_string_d cc_string_d;
+typedef cc_string_d*	cc_string_t;
+
+struct cc_credentials_d {
+    const cc_credentials_union* data;
+    const cc_credentials_f* functions;
+#if TARGET_OS_MAC
+    const cc_credentials_f*	otherFunctions;
+#endif
+};
+typedef struct cc_credentials_d cc_credentials_d;
+typedef cc_credentials_d* cc_credentials_t;
+
+/* Function pointer structs */
+
+struct  cc_context_f {
+    cc_int32    (*release) (
+                                cc_context_t context);
+    cc_int32    (*get_change_time) (
+                                cc_context_t context,
+                                cc_time_t* time);
+    cc_int32    (*get_default_ccache_name) (
+                                cc_context_t context,
+                                cc_string_t* name);
+    cc_int32    (*open_ccache) (
+                                cc_context_t context,
+                                const char* name,
+                                cc_ccache_t* ccache);
+    cc_int32    (*open_default_ccache) (
+                                cc_context_t context,
+                                cc_ccache_t* ccache);
+    cc_int32    (*create_ccache) (
+                                cc_context_t context,
+                                const char* name,
+                                cc_uint32 cred_vers,
+                                const char* principal, 
+                                cc_ccache_t* ccache);
+    cc_int32    (*create_default_ccache) (
+                                cc_context_t context,
+                                cc_uint32 cred_vers,
+                                const char* principal, 
+                                cc_ccache_t* ccache);
+    cc_int32    (*create_new_ccache) (
+                                cc_context_t context,
+                                cc_uint32 cred_vers,
+                                const char* principal, 
+                                cc_ccache_t* ccache);
+    cc_int32    (*new_ccache_iterator) (
+                                cc_context_t context,
+                                cc_ccache_iterator_t* iterator);
+    cc_int32    (*lock) (
+                                cc_context_t context,
+                                cc_uint32 lock_type,
+                                cc_uint32 block);
+    cc_int32    (*unlock) (
+                                cc_context_t context);
+    cc_int32    (*compare) (
+                                cc_context_t context,
+                                cc_context_t compare_to,
+                                cc_uint32* equal);
+};
+
+struct cc_ccache_f {
+    cc_int32    (*release) (
+                                 cc_ccache_t ccache);
+    cc_int32    (*destroy) (
+                                 cc_ccache_t ccache);
+    cc_int32    (*set_default) (
+                                 cc_ccache_t ccache);
+    cc_int32    (*get_credentials_version) (
+                                 cc_ccache_t ccache,
+                                 cc_uint32* credentials_version);
+    cc_int32    (*get_name) (
+                                 cc_ccache_t ccache,
+                                 cc_string_t* name);
+    cc_int32    (*get_principal) (
+                                 cc_ccache_t ccache,
+                                 cc_uint32 credentials_version,
+                                 cc_string_t* principal);
+    cc_int32    (*set_principal) (
+                                 cc_ccache_t ccache,
+                                 cc_uint32 credentials_version,
+                                 const char* principal);
+    cc_int32    (*store_credentials) (
+                                 cc_ccache_t ccache,
+                                 const cc_credentials_union* credentials);
+    cc_int32    (*remove_credentials) (
+                                 cc_ccache_t ccache,
+                                 cc_credentials_t credentials);
+    cc_int32    (*new_credentials_iterator) (
+                                 cc_ccache_t ccache,
+                                 cc_credentials_iterator_t* iterator);
+    cc_int32    (*move) (
+                                 cc_ccache_t source,
+                                 cc_ccache_t destination);
+    cc_int32    (*lock) (
+                                 cc_ccache_t ccache,
+                                 cc_uint32 block,
+                                 cc_uint32 lock_type);
+    cc_int32    (*unlock) (
+                                 cc_ccache_t ccache);
+    cc_int32    (*get_last_default_time) (
+                                 cc_ccache_t ccache,
+                                 cc_time_t* time);
+    cc_int32    (*get_change_time) (
+                                 cc_ccache_t ccache,
+                                 cc_time_t* time);
+    cc_int32    (*compare) (
+                                cc_ccache_t ccache,
+                                cc_ccache_t compare_to,
+                                cc_uint32* equal);
+    cc_int32	(*get_kdc_time_offset) (
+                                cc_ccache_t ccache,
+                                cc_int32	credentials_version,
+                                cc_time_t*	time_offset);
+    cc_int32	(*set_kdc_time_offset) (
+                                cc_ccache_t ccache,
+                                cc_int32	credentials_version,
+                                cc_time_t	time_offset);
+                                
+    cc_int32	(*clear_kdc_time_offset) (
+                                cc_ccache_t	ccache,
+                                cc_int32	credentials_version);
+};
+
+struct cc_string_f {
+    cc_int32	(*release) (
+                                cc_string_t string);
+};
+
+struct cc_credentials_f {
+    cc_int32	(*release) (
+                                cc_credentials_t credentials);
+    cc_int32    (*compare) (
+                                cc_credentials_t credentials,
+                                cc_credentials_t compare_to,
+                                cc_uint32* equal);
+};
+
+			   
+struct cc_ccache_iterator_f {
+    cc_int32    (*release) (
+                                 cc_ccache_iterator_t iter);
+    cc_int32    (*next) (
+                                 cc_ccache_iterator_t iter,
+                                 cc_ccache_t* ccache);
+};
+
+struct cc_credentials_iterator_f {
+    cc_int32    (*release) (
+                                 cc_credentials_iterator_t iter);
+    cc_int32    (*next) (
+                                 cc_credentials_iterator_t iter,
+                                 cc_credentials_t* ccache);
+};
+
+/*
+ * API functions
+ */
+ 
+cc_int32 cc_initialize (
+	cc_context_t*		outContext,
+	cc_int32			inVersion,
+	cc_int32*			outSupportedVersion,
+	char const**		outVendor);
+	
+/*
+ * Convenience macros
+ */
+ 
+#define		cc_context_release(context)												\
+			((context) -> functions -> release (context))
+#define		cc_context_get_change_time(context, time)								\
+			((context) -> functions -> get_change_time (context, time))
+#define		cc_context_get_default_ccache_name(context, name)						\
+			((context) -> functions -> get_default_ccache_name (context, name))
+#define		cc_context_open_ccache(context, name, ccache)							\
+			((context) -> functions -> open_ccache (context, name, ccache))
+#define		cc_context_open_default_ccache(context, ccache)							\
+			((context) -> functions -> open_default_ccache (context, ccache))
+#define		cc_context_create_ccache(context, name, version, principal, ccache)		\
+			((context) -> functions -> create_ccache (context, name, version, principal, ccache))
+#define		cc_context_create_default_ccache(context, version, principal, ccache)	\
+			((context) -> functions -> create_default_ccache (context, version, principal, ccache))
+#define		cc_context_create_new_ccache(context, version, principal, ccache)		\
+			((context) -> functions -> create_new_ccache (context, version, principal, ccache))
+#define		cc_context_new_ccache_iterator(context, iterator)						\
+			((context) -> functions -> new_ccache_iterator (context, iterator))
+#define		cc_context_lock(context, type, lock)									\
+			((context) -> functions -> lock (context, type, lock))
+#define		cc_context_unlock(context)												\
+			((context) -> functions -> unlock (context))
+#define		cc_context_compare(context, compare_to, equal)							\
+			((context) -> functions -> compare (context, compare_to, equal))
+
+#define		cc_ccache_release(ccache)												\
+			((ccache) -> functions -> release (ccache))
+#define		cc_ccache_destroy(ccache)												\
+			((ccache) -> functions -> destroy (ccache))
+#define		cc_ccache_set_default(ccache)											\
+			((ccache) -> functions -> set_default (ccache))
+#define		cc_ccache_get_credentials_version(ccache, version)						\
+			((ccache) -> functions -> get_credentials_version (ccache, version))
+#define		cc_ccache_get_name(ccache, name)										\
+			((ccache) -> functions -> get_name (ccache, name))
+#define		cc_ccache_get_principal(ccache, version, principal)						\
+			((ccache) -> functions -> get_principal (ccache, version, principal))
+#define		cc_ccache_set_principal(ccache, version, principal)						\
+			((ccache) -> functions -> set_principal (ccache, version, principal))
+#define		cc_ccache_store_credentials(ccache, credentials)						\
+			((ccache) -> functions -> store_credentials (ccache, credentials))
+#define		cc_ccache_remove_credentials(ccache, credentials)						\
+			((ccache) -> functions -> remove_credentials (ccache, credentials))
+#define		cc_ccache_new_credentials_iterator(ccache, iterator)					\
+			((ccache) -> functions -> new_credentials_iterator (ccache, iterator))
+#define		cc_ccache_lock(ccache, lock)											\
+			((ccache) -> functions -> lock (ccache, lock))
+#define		cc_ccache_unlock(ccache, unlock)										\
+			((ccache) -> functions -> unlock (ccache, unlock))
+#define		cc_ccache_get_last_default_time(ccache, time)							\
+			((ccache) -> functions -> get_last_default_time (ccache, time))
+#define		cc_ccache_get_change_time(ccache, time)									\
+			((ccache) -> functions -> get_change_time (ccache, time))
+#define		cc_ccache_move(source, destination)										\
+			((source) -> functions -> move (source, destination))
+#define		cc_ccache_compare(ccache, compare_to, equal)							\
+			((ccache) -> functions -> compare (ccache, compare_to, equal))
+#define		cc_ccache_get_kdc_time_offset(ccache, version, time)					\
+            ((ccache) -> functions -> get_kdc_time_offset (version, time))
+#define		cc_ccache_set_kdc_time_offset(ccache, version, time)					\
+            ((ccache) -> functions -> set_kdc_time_offset (version, time))
+#define		cc_ccache_clear_kdc_time_offset(ccache, version)						\
+            ((ccache) -> functions -> clear_kdc_time_offset (version))
+
+#define		cc_string_release(string)												\
+			((string) -> functions -> release (string))
+
+#define		cc_credentials_release(credentials)										\
+			((credentials) -> functions -> release (credentials))
+#define		cc_credentials_compare(credentials, compare_to, equal)					\
+			((credentials) -> functions -> compare (credentials, compare_to, equal))
+
+#define		cc_ccache_iterator_release(iterator)									\
+			((iterator) -> functions -> release (iterator))
+#define		cc_ccache_iterator_next(iterator, ccache)								\
+			((iterator) -> functions -> next (iterator, ccache))
+	
+#define		cc_credentials_iterator_release(iterator)								\
+			((iterator) -> functions -> release (iterator))
+#define		cc_credentials_iterator_next(iterator, credentials)						\
+			((iterator) -> functions -> next (iterator, credentials))
+			
+#if TARGET_OS_MAC
+    #if defined(__MWERKS__)
+        #pragma enumsalwaysint reset
+        #pragma import reset
+    #endif
+	#pragma options align=reset
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CREDENTIALSCACHE__ */
diff --git a/mechglue/src/lib/ccapi/include/CredentialsCache2.h b/mechglue/src/lib/ccapi/include/CredentialsCache2.h
new file mode 100644
index 000000000..401e093f4
--- /dev/null
+++ b/mechglue/src/lib/ccapi/include/CredentialsCache2.h
@@ -0,0 +1,308 @@
+/* $Copyright:
+ *
+ * Copyright 1998-2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+/*
+ * This is backwards compatibility for CCache API v2 clients to be able to run 
+ * against the CCache API v3 library
+ */
+ 
+#ifndef __CREDENTIALSCACHE2__
+#define __CREDENTIALSCACHE2__
+ 
+#include <Kerberos/CredentialsCache.h>
+#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
+	#include <TargetConditionals.h>
+    #if TARGET_RT_MAC_CFM
+        #error "Use KfM 4.0 SDK headers for CFM compilation."
+    #endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if TARGET_OS_MAC
+    #if defined(__MWERKS__)
+        #pragma import on
+        #pragma enumsalwaysint on
+    #endif
+    #pragma options align=mac68k
+#endif
+
+/* Some old types get directly mapped to new types */
+
+typedef cc_context_d apiCB;
+typedef cc_ccache_d ccache_p;
+typedef cc_credentials_iterator_d ccache_cit_creds;
+typedef cc_ccache_iterator_d ccache_cit_ccache;
+typedef cc_data cc_data_compat;
+typedef cc_int32 cc_cred_vers;
+typedef cc_int32 cc_result;
+
+/* This doesn't exist in API v3 */
+typedef cc_uint32 cc_flags;
+
+/* Credentials types are visible to the caller so we have to keep binary compatibility */
+
+typedef struct cc_credentials_v5_compat {
+    char*			client;
+    char*			server;
+    cc_data_compat		keyblock;
+    cc_time_t			authtime;
+    cc_time_t			starttime;
+    cc_time_t			endtime;
+    cc_time_t			renew_till;
+    cc_uint32			is_skey;
+    cc_uint32			ticket_flags;
+    cc_data_compat**	        addresses;
+    cc_data_compat		ticket;
+    cc_data_compat		second_ticket;
+    cc_data_compat**	        authdata;
+} cc_credentials_v5_compat;
+ 
+enum {
+    MAX_V4_CRED_LEN = 1250
+};
+ 
+enum {
+    KRB_NAME_SZ = 40,
+    KRB_INSTANCE_SZ = 40,
+    KRB_REALM_SZ = 40
+};
+ 
+typedef struct cc_credentials_v4_compat {
+    unsigned char	kversion;
+    char		principal[KRB_NAME_SZ+1];
+    char		principal_instance[KRB_INSTANCE_SZ+1];
+    char		service[KRB_NAME_SZ+1];
+    char		service_instance[KRB_INSTANCE_SZ+1];
+    char		realm[KRB_REALM_SZ+1];
+    unsigned char	session_key[8];
+    cc_int32		kvno;
+    cc_int32		str_to_key;
+    long		issue_date;
+    cc_int32		lifetime;
+    cc_uint32		address;
+    cc_int32		ticket_sz;
+    unsigned char	ticket[MAX_V4_CRED_LEN];
+    unsigned long	oops;
+} cc_credentials_v4_compat;
+
+typedef union cred_ptr_union_compat {
+    cc_credentials_v4_compat*	pV4Cred;
+    cc_credentials_v5_compat*	pV5Cred;
+} cred_ptr_union_compat;
+ 
+typedef struct cred_union {
+    cc_int32				cred_type;  // cc_cred_vers
+    cred_ptr_union_compat	cred;
+} cred_union;
+
+/* NC info structure is gone in v3 */
+
+struct infoNC {
+    char*	name;
+    char*	principal;
+    cc_int32	vers;
+};
+
+typedef struct infoNC infoNC;
+
+/* Some old type names */
+
+typedef cc_credentials_v4_compat V4Cred_type;
+typedef cc_credentials_v5_compat cc_creds;
+struct ccache_cit;
+typedef struct ccache_cit ccache_cit;
+
+enum {
+    CC_API_VER_2 = ccapi_version_2
+};
+
+enum {
+    CC_NOERROR,
+    CC_BADNAME,
+    CC_NOTFOUND,
+    CC_END,
+    CC_IO,
+    CC_WRITE,
+    CC_NOMEM,
+    CC_FORMAT,
+    CC_LOCKED,
+    CC_BAD_API_VERSION,
+    CC_NO_EXIST,
+    CC_NOT_SUPP,
+    CC_BAD_PARM,
+    CC_ERR_CACHE_ATTACH,
+    CC_ERR_CACHE_RELEASE,
+    CC_ERR_CACHE_FULL,
+    CC_ERR_CRED_VERSION
+};      
+
+enum {
+    CC_CRED_UNKNOWN,
+    CC_CRED_V4,
+    CC_CRED_V5,
+    CC_CRED_MAX
+};
+
+cc_int32 cc_shutdown (
+        apiCB**				ioContext);
+	
+cc_int32 cc_get_NC_info (
+	apiCB*				inContext,
+	infoNC***			outInfo);
+	
+cc_int32 cc_get_change_time (
+	apiCB*				inContext,
+	cc_time_t*			outTime);
+	
+cc_int32 cc_open (
+	apiCB*				inContext,
+	const char*			inName,
+	cc_int32			inVersion,
+	cc_uint32			inFlags,
+	ccache_p**			outCCache);
+	
+cc_int32 cc_create (
+	apiCB*				inContext,
+	const char*			inName,
+	const char*			inPrincipal,
+	cc_int32			inVersion,
+	cc_uint32			inFlags,
+	ccache_p**			outCCache);
+	
+cc_int32 cc_close (
+	apiCB*				inContext,
+	ccache_p**			ioCCache);
+	
+cc_int32 cc_destroy (
+	apiCB*				inContext,
+	ccache_p**			ioCCache);
+	
+cc_int32 cc_seq_fetch_NCs_begin (
+	apiCB*				inContext,
+	ccache_cit**		outIterator);
+
+cc_int32 cc_seq_fetch_NCs_next (
+	apiCB*				inContext,
+	ccache_p**			outCCache,
+	ccache_cit*			inIterator);
+
+cc_int32 cc_seq_fetch_NCs_end (
+	apiCB*				inContext,
+	ccache_cit**		ioIterator);
+
+cc_int32 cc_get_name (
+	apiCB*				inContext,
+	ccache_p*			inCCache,
+	char**				outName);
+	
+cc_int32 cc_get_cred_version (
+	apiCB*				inContext,
+	ccache_p*			inCCache,
+	cc_int32*			outVersion);
+	
+cc_int32 cc_set_principal (
+	apiCB*				inContext,
+	ccache_p*			inCCache,
+	cc_int32			inVersion,
+	char*				inPrincipal);
+	
+cc_int32 cc_get_principal (
+	apiCB*				inContext,
+	ccache_p*			inCCache,
+	char**				outPrincipal);
+	
+cc_int32 cc_store (
+	apiCB*				inContext,
+	ccache_p*			inCCache,
+	cred_union			inCredentials);
+
+cc_int32 cc_remove_cred (
+	apiCB*				inContext,
+	ccache_p*			inCCache,
+	cred_union			inCredentials);
+
+cc_int32 cc_seq_fetch_creds_begin (
+	apiCB*				inContext,
+	const ccache_p*		inCCache,
+	ccache_cit**		outIterator);
+
+cc_int32 cc_seq_fetch_creds_next (
+	apiCB*				inContext,
+	cred_union**		outCreds,
+	ccache_cit*			inIterator);
+	
+cc_int32 cc_seq_fetch_creds_end (
+	apiCB*				inContext,
+	ccache_cit**		ioIterator);
+	
+cc_int32 cc_free_principal (
+	apiCB*				inContext,
+	char**				ioPrincipal);
+
+cc_int32 cc_free_name (
+	apiCB*				inContext,
+	char**				ioName);
+
+cc_int32 cc_free_creds (
+	apiCB*				inContext,
+	cred_union**		creds);
+
+cc_int32 cc_free_NC_info (
+	apiCB*				inContext,
+	infoNC***			ioInfo);
+	
+#if TARGET_OS_MAC
+    #if defined(__MWERKS__)
+        #pragma enumsalwaysint reset
+        #pragma import reset
+    #endif
+	#pragma options align=reset
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CREDENTIALSCACHE2__ */
\ No newline at end of file
diff --git a/mechglue/src/lib/ccapi/include/marshall.h b/mechglue/src/lib/ccapi/include/marshall.h
new file mode 100644
index 000000000..19b9463b0
--- /dev/null
+++ b/mechglue/src/lib/ccapi/include/marshall.h
@@ -0,0 +1,93 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+#define FLAT_CREDS_V5_VERSION   1
+struct cc_flat_data {
+    cc_uint32                   type;
+    cc_uint32                   length;
+    cc_uint32                   data;
+};
+typedef struct cc_flat_data cc_flat_data;
+
+struct cci_flat_creds_v5 {
+    cc_uint32                   version;        /* version of this structure */
+    cc_flat_data                client;
+    cc_flat_data                server;
+    cc_flat_data		keyblock;
+    cc_time_t			authtime;
+    cc_time_t			starttime;
+    cc_time_t			endtime;
+    cc_time_t			renew_till;
+    cc_uint32			is_skey;
+    cc_uint32			ticket_flags;
+    cc_uint32                   address_count;
+    cc_uint32                   addresses; /* offset to array */
+    cc_flat_data		ticket;
+    cc_flat_data		second_ticket;
+    cc_uint32                   authdata_count;
+    cc_uint32 			authdata;  /* offset to array */
+};
+
+cc_int32
+cci_creds_v4_marshall( cc_credentials_v4_t * creds, 
+                       char ** flat, 
+                       cc_uint32 * len);
+
+cc_int32
+cci_creds_v4_unmarshall( char * flat, 
+                         cc_uint32 len,
+                         cc_credentials_union * creds);
+
+cc_int32
+cci_creds_v5_marshall( cc_credentials_v5_t * creds, 
+                       char ** pflat, 
+                       cc_uint32 * plen);
+
+cc_int32
+cci_creds_v5_unmarshall( char * flat, 
+                         cc_uint32 len,
+                         cc_credentials_union * creds_union);
+
+
+
+
diff --git a/mechglue/src/lib/ccapi/include/msg.h b/mechglue/src/lib/ccapi/include/msg.h
new file mode 100644
index 000000000..0d712d666
--- /dev/null
+++ b/mechglue/src/lib/ccapi/include/msg.h
@@ -0,0 +1,146 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Verifiable, extensible message format.
+ *
+ * Format:
+ * <size of header block (header_len)>
+ * <size of *entire* message, including previous field (flat_len)>
+ * <message type (type)>
+ * <type specific header (header)>
+ * <magic number (magic)>
+ * <data blob 1 length>
+ * <data blob 1>
+ * <data blob 2 length>
+ * <data blob 2>
+ * ...
+ * <magic number (magic)>
+ *
+ * If the header has variable length data it is included in the data blobs. 
+ * The header field has the offset from the beginning of the message of the 1st 
+ * byte of the data and the length of the data.
+ *
+ */
+
+#ifndef __CC_MSG_H__
+#define __CC_MSG_H__
+
+#include "CredentialsCache.h"
+
+struct  cc_msg_t {
+    cc_uint32 type;			/*type of message*/
+    cc_uint8 *flat;			/*flattened representation of this message*/
+    cc_uint8 *header;			/*fixed length header determined by message type*/
+    cc_uint32 flat_len;			/*length of flat rep*/
+    cc_uint32 header_len;		/*length of header*/
+    cc_uint32 magic;			/*magic number for verification purposes*/
+    cc_generic_list_head_t* data_blobs;	/*variable length data*/
+};      
+typedef struct cc_msg_t cc_msg_t;
+
+/*Types of messages*/
+enum {
+    ccmsg_ACK,
+    ccmsg_NACK,
+    ccmsg_INIT,
+    ccmsg_CTX_RELEASE,
+    ccmsg_CTX_GET_CHANGE_TIME,
+    ccmsg_CTX_GET_DEFAULT_CCACHE_NAME,
+    ccmsg_CTX_COMPARE,
+    ccmsg_CTX_NEW_CCACHE_ITERATOR,
+    ccmsg_CTX_LOCK,
+    ccmsg_CTX_UNLOCK,
+    ccmsg_CTX_CLONE,
+    ccmsg_CCACHE_OPEN,
+    ccmsg_CCACHE_OPEN_DEFAULT,
+    ccmsg_CCACHE_CREATE,
+    ccmsg_CCACHE_CREATE_DEFAULT,
+    ccmsg_CCACHE_CREATE_UNIQUE,
+    ccmsg_CCACHE_RELEASE,
+    ccmsg_CCACHE_DESTROY,
+    ccmsg_CCACHE_SET_DEFAULT,
+    ccmsg_CCACHE_GET_CREDS_VERSION,
+    ccmsg_CCACHE_GET_NAME,
+    ccmsg_CCACHE_GET_PRINCIPAL,
+    ccmsg_CCACHE_SET_PRINCIPAL,
+    ccmsg_CCACHE_CREDS_ITERATOR,
+    ccmsg_CCACHE_STORE_CREDS,
+    ccmsg_CCACHE_REM_CREDS,
+    ccmsg_CCACHE_GET_LAST_DEFAULT_TIME,
+    ccmsg_CCACHE_GET_CHANGE_TIME,
+    ccmsg_CCACHE_MOVE,
+    ccmsg_CCACHE_COMPARE,
+    ccmsg_CCACHE_GET_KDC_TIME_OFFSET,
+    ccmsg_CCACHE_SET_KDC_TIME_OFFSET,
+    ccmsg_CCACHE_CLEAR_KDC_TIME_OFFSET,
+    ccmsg_CCACHE_ITERATOR_RELEASE,
+    ccmsg_CCACHE_ITERATOR_NEXT,
+    ccmsg_CCACHE_LOCK,
+    ccmsg_CCACHE_UNLOCK,
+    ccmsg_CREDS_ITERATOR_RELEASE,
+    ccmsg_CREDS_ITERATOR_NEXT,
+    ccmsg_CREDS_RELEASE,
+    ccmsg_CREDS_V4,
+    ccmsg_CREDS_V5
+};      
+
+#define CC_MSG_MAX_SIZE	1073741824 /*2^30*/
+#define CC_MSG_MAX_TYPE ccmsg_CREDS_V5
+#define BLOB_LEN (sizeof(cc_uint32))
+#define MAGIC_DATA_LEN (sizeof(cc_uint32))
+#define MAGIC_HEAD_LEN (sizeof(cc_uint32))
+
+cc_int32 cci_msg_new(cc_uint32 type, cc_msg_t** msgpp);
+cc_int32 cci_msg_calc_size(cc_msg_t* msg, cc_uint32 * sizep);
+cc_int32 cci_msg_calc_header_size(cc_msg_t* msg, cc_uint32 * sizep);
+cc_int32 cci_msg_add_data_blob(cc_msg_t* msg, void *data, cc_uint32 len, cc_uint32 * sizep);
+cc_int32 cci_msg_add_header(cc_msg_t* msg, void *header, cc_uint32 header_len);
+cc_int32 cci_msg_calc_blob_pos(cc_msg_t* msg, void *data, cc_uint32 len, cc_uint32 * sizep);
+cc_int32 cci_msg_flatten(cc_msg_t* msg, void **);
+cc_int32 cci_msg_calc_magic(void *flat, int flat_len, cc_uint32 * sizep);
+cc_int32 cci_msg_verify(void* flat, int flat_len, cc_uint32 * sizep);
+cc_int32 cci_msg_unflatten(void *flat, int flat_len, cc_msg_t** msgpp);
+cc_int32 cci_msg_retrieve_blob(cc_msg_t* msg, cc_uint32 blob_offset, cc_uint32 blob_len, void **);
+cc_int32 cci_msg_destroy(cc_msg_t* msg);
+#endif /*__CC_MSG_H__*/
diff --git a/mechglue/src/lib/ccapi/include/msg_headers.h b/mechglue/src/lib/ccapi/include/msg_headers.h
new file mode 100644
index 000000000..a27c2d2f1
--- /dev/null
+++ b/mechglue/src/lib/ccapi/include/msg_headers.h
@@ -0,0 +1,429 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Message type specific header structures.
+ *
+ */
+
+#ifndef __MSG_HEADERS_H__
+#define __MSG_HEADERS_H__
+
+#include "CredentialsCache.h"
+
+/*
+ * All header structs must have sizes divisible by 4, and
+ * all individual fields within the structs must also have
+ * size divisible by 4. This is to ensure correct alignment
+ * and stop different compilers from inserting padding bytes in
+ * different places.
+ */
+
+struct ccmsg_ctx_only_t {
+    cc_handle ctx;
+};
+typedef struct ccmsg_ctx_only_t ccmsg_ctx_only_t;
+
+struct ccmsg_nack_t {
+    cc_uint32	err_code;	/*error code that caused failure*/
+};
+typedef struct ccmsg_nack_t ccmsg_nack_t;
+
+struct ccmsg_init_t {
+    cc_uint32	in_version;		/*client API version*/
+};
+struct ccmsg_init_resp_t {
+    cc_handle	out_ctx;		/*handle on this ctx*/
+    cc_uint32	out_version;		/*server API version*/
+    cc_uint32	vendor_offset;		/*offset of vendor blob*/
+    cc_uint32	vendor_length;		/*length of vendor blob*/
+};      
+typedef struct ccmsg_init_t ccmsg_init_t;
+typedef struct ccmsg_init_resp_t ccmsg_init_resp_t;
+
+struct ccmsg_clone_t {
+    cc_handle   ctx;
+    cc_uint32	in_version;		/*client API version*/
+};
+struct ccmsg_clone_resp_t {
+    cc_handle	out_ctx;		/*handle on this ctx*/
+    cc_uint32	out_version;		/*server API version*/
+    cc_uint32	vendor_offset;		/*offset of vendor blob*/
+    cc_uint32	vendor_length;		/*length of vendor blob*/
+};      
+typedef struct ccmsg_clone_t ccmsg_clone_t;
+typedef struct ccmsg_clone_resp_t ccmsg_clone_resp_t;
+
+struct ccmsg_ctx_release_t {
+    cc_handle 	ctx;	/*# of ctx to release*/
+};
+typedef struct ccmsg_ctx_release_t ccmsg_ctx_release_t;
+
+struct ccmsg_ctx_get_change_time_t {
+    cc_handle	ctx;
+};
+struct ccmsg_ctx_get_change_time_resp_t {
+    cc_time_t	time;
+};
+typedef struct ccmsg_ctx_get_change_time_t ccmsg_ctx_get_change_time_t;
+typedef struct ccmsg_ctx_get_change_time_resp_t ccmsg_ctx_get_change_time_resp_t;
+
+struct ccmsg_ctx_get_default_ccache_name_t {
+    cc_handle	ctx;
+};
+struct ccmsg_ctx_get_default_ccache_name_resp_t {
+    cc_uint32	name_offset;
+    cc_uint32	name_len;
+};
+typedef struct ccmsg_ctx_get_default_ccache_name_t ccmsg_ctx_get_default_ccache_name_t;
+typedef struct ccmsg_ctx_get_default_ccache_name_resp_t ccmsg_ctx_get_default_ccache_name_resp_t;
+
+struct ccmsg_ctx_compare_t {
+    cc_handle	ctx1;
+    cc_handle	ctx2;
+};
+struct ccmsg_ctx_compare_resp_t {
+    cc_uint32	is_equal;	
+};
+typedef struct ccmsg_ctx_compare_t ccmsg_ctx_compare_t;
+typedef struct ccmsg_ctx_compare_resp_t ccmsg_ctx_compare_resp_t;
+
+struct ccmsg_ctx_new_ccache_iterator_t {
+    cc_handle	ctx;
+};
+struct ccmsg_ctx_new_ccache_iterator_resp_t {
+    cc_handle	iterator;
+};
+typedef struct ccmsg_ctx_new_ccache_iterator_t ccmsg_ctx_new_ccache_iterator_t;
+typedef struct ccmsg_ctx_new_ccache_iterator_resp_t ccmsg_ctx_new_ccache_iterator_resp_t;
+
+struct ccmsg_ctx_lock_t {
+    cc_handle   ctx;
+    cc_uint32   lock_type;
+};
+typedef struct ccmsg_ctx_lock_t ccmsg_ctx_lock_t;
+
+struct ccmsg_ctx_unlock_t {
+    cc_handle   ctx;
+};
+typedef struct ccmsg_ctx_unlock_t ccmsg_ctx_unlock_t;
+
+struct ccmsg_ccache_open_t {
+    cc_handle	ctx;
+    cc_uint32	name_offset;
+    cc_uint32	name_len;
+};      
+struct ccmsg_ccache_open_resp_t {
+    cc_handle	ccache;
+};
+typedef struct ccmsg_ccache_open_t ccmsg_ccache_open_t;
+typedef struct ccmsg_ccache_open_resp_t ccmsg_ccache_open_resp_t;
+
+struct ccmsg_ccache_open_default_t {
+    cc_handle	ctx;
+};
+typedef struct ccmsg_ccache_open_default_t ccmsg_ccache_open_default_t;
+
+struct ccmsg_ccache_create_t {
+    cc_handle	ctx;
+    cc_uint32	version;
+    cc_uint32	principal_offset;
+    cc_uint32	principal_len;
+    cc_uint32	name_offset;
+    cc_uint32	name_len;
+};
+struct ccmsg_ccache_create_default_t {
+    cc_handle	ctx;
+    cc_uint32	version;
+    cc_uint32	principal_offset;
+    cc_uint32	principal_len;
+};
+struct ccmsg_ccache_create_unique_t {
+    cc_handle	ctx;
+    cc_uint32	version;
+    cc_uint32	principal_offset;
+    cc_uint32	principal_len;
+};
+
+struct ccmsg_ccache_create_resp_t {
+    cc_handle	ccache;
+};
+typedef struct ccmsg_ccache_create_t ccmsg_ccache_create_t;
+typedef struct ccmsg_ccache_create_default_t ccmsg_ccache_create_default_t;
+typedef struct ccmsg_ccache_create_unique_t ccmsg_ccache_create_unique_t;
+typedef struct ccmsg_ccache_create_resp_t ccmsg_ccache_create_resp_t;
+
+struct ccmsg_ccache_release_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+};
+typedef struct ccmsg_ccache_release_t ccmsg_ccache_release_t;
+
+struct ccmsg_ccache_destroy_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+};
+typedef struct ccmsg_ccache_destroy_t ccmsg_ccache_destroy_t;
+
+struct ccmsg_ccache_set_default_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+};
+typedef struct ccmsg_ccache_set_default_t ccmsg_ccache_set_default_t;
+
+struct ccmsg_ccache_get_creds_version_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+};
+struct ccmsg_ccache_get_creds_version_resp_t {
+    cc_uint32	version;
+};
+typedef struct ccmsg_ccache_get_creds_version_t ccmsg_ccache_get_creds_version_t;
+typedef struct ccmsg_ccache_get_creds_version_resp_t ccmsg_ccache_get_creds_version_resp_t;
+
+struct ccmsg_ccache_get_name_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+};
+struct ccmsg_ccache_get_name_resp_t {
+    cc_uint32	name_offset;
+    cc_uint32	name_len;
+};      
+typedef struct ccmsg_ccache_get_name_t ccmsg_ccache_get_name_t;
+typedef struct ccmsg_ccache_get_name_resp_t ccmsg_ccache_get_name_resp_t;
+
+struct ccmsg_ccache_get_principal_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_uint32	version;
+};
+struct ccmsg_ccache_get_principal_resp_t {
+    cc_uint32	principal_offset;
+    cc_uint32	principal_len;
+};
+typedef struct ccmsg_ccache_get_principal_t ccmsg_ccache_get_principal_t;
+typedef struct ccmsg_ccache_get_principal_resp_t ccmsg_ccache_get_principal_resp_t;
+
+struct ccmsg_ccache_set_principal_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_uint32	version;	
+    cc_uint32	principal_offset;
+    cc_uint32	principal_len;
+};
+typedef struct ccmsg_ccache_set_principal_t ccmsg_ccache_set_principal_t;
+
+struct ccmsg_ccache_creds_iterator_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+};
+struct ccmsg_ccache_creds_iterator_resp_t {
+    cc_handle	iterator;
+};
+typedef struct ccmsg_ccache_creds_iterator_t ccmsg_ccache_creds_iterator_t;
+typedef struct ccmsg_ccache_creds_iterator_resp_t ccmsg_ccache_creds_iterator_resp_t;
+
+struct ccmsg_ccache_store_creds_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_uint32   creds_version;
+    cc_uint32	creds_offset;
+    cc_uint32	creds_len;
+};
+typedef struct ccmsg_ccache_store_creds_t ccmsg_ccache_store_creds_t;
+
+struct ccmsg_ccache_rem_creds_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_handle   creds;
+};
+typedef struct ccmsg_ccache_rem_creds_t ccmsg_ccache_rem_creds_t;
+
+struct ccmsg_ccache_lock_t {
+    cc_handle	ctx;
+    cc_handle   ccache;
+    cc_uint32   lock_type;
+};
+typedef struct ccmsg_ccache_lock_t ccmsg_ccache_lock_t;
+
+struct ccmsg_ccache_unlock_t {
+    cc_handle	ctx;
+    cc_handle   ccache;
+};
+typedef struct ccmsg_ccache_unlock_t ccmsg_ccache_unlock_t;
+
+struct ccmsg_ccache_move_t {
+    cc_handle	ctx;
+    cc_handle	ccache_source;
+    cc_handle   ccache_dest;
+};
+typedef struct ccmsg_ccache_move_t ccmsg_ccache_move_t;
+
+struct ccmsg_ccache_get_last_default_time_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+};
+struct ccmsg_ccache_get_last_default_time_resp_t {
+    cc_time_t	last_default_time;
+};
+typedef struct ccmsg_ccache_get_last_default_time_t ccmsg_ccache_get_last_default_time_t;
+typedef struct ccmsg_ccache_get_last_default_time_resp_t ccmsg_ccache_get_last_default_time_resp_t;
+
+struct ccmsg_ccache_get_change_time_t {
+    cc_handle   ctx;
+    cc_handle	ccache;
+};
+struct ccmsg_ccache_get_change_time_resp_t {
+    cc_time_t	time;
+};
+typedef struct ccmsg_ccache_get_change_time_t ccmsg_ccache_get_change_time_t;
+typedef struct ccmsg_ccache_get_change_time_resp_t ccmsg_ccache_get_change_time_resp_t;
+
+struct ccmsg_ccache_compare_t {
+    cc_handle	ctx;
+    cc_handle	ccache1;
+    cc_handle	ccache2;
+};
+struct ccmsg_ccache_compare_resp_t {
+    cc_uint32	is_equal;
+};
+typedef struct ccmsg_ccache_compare_t ccmsg_ccache_compare_t;
+typedef struct ccmsg_ccache_compare_resp_t ccmsg_ccache_compare_resp_t;
+
+struct ccmsg_ccache_get_kdc_time_offset_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_int32    creds_version;
+};      
+struct ccmsg_ccache_get_kdc_time_offset_resp_t {
+    cc_time_t	offset;
+};
+typedef struct ccmsg_ccache_get_kdc_time_offset_t ccmsg_ccache_get_kdc_time_offset_t;
+typedef struct ccmsg_ccache_get_kdc_time_offset_resp_t ccmsg_ccache_get_kdc_time_offset_resp_t;
+
+struct ccmsg_ccache_set_kdc_time_offset_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_time_t	offset;
+    cc_int32    creds_version;
+};
+typedef struct ccmsg_ccache_set_kdc_time_offset_t ccmsg_ccache_set_kdc_time_offset_t;
+
+struct ccmsg_ccache_clear_kdc_time_offset_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_int32    creds_version;
+};
+typedef struct ccmsg_ccache_clear_kdc_time_offset_t ccmsg_ccache_clear_kdc_time_offset_t;
+
+struct ccmsg_ccache_iterator_release_t {
+    cc_handle	ctx;
+    cc_handle	iterator;
+};
+typedef struct ccmsg_ccache_iterator_release_t ccmsg_ccache_iterator_release_t;
+
+struct ccmsg_ccache_iterator_next_t {
+    cc_handle	ctx;
+    cc_handle	iterator;
+};
+struct ccmsg_ccache_iterator_next_resp_t {
+    cc_handle	ccache;
+};
+typedef struct ccmsg_ccache_iterator_next_t ccmsg_ccache_iterator_next_t;
+typedef struct ccmsg_ccache_iterator_next_resp_t ccmsg_ccache_iterator_next_resp_t;
+
+struct ccmsg_creds_iterator_release_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_handle	iterator;
+};
+typedef struct ccmsg_creds_iterator_release_t ccmsg_creds_iterator_release_t;
+
+struct ccmsg_creds_iterator_next_t {
+    cc_handle	ctx;
+    cc_handle	ccache;
+    cc_handle	iterator;
+};
+struct ccmsg_creds_iterator_next_resp_t {
+    cc_uint32	version;
+    cc_handle   creds_handle;
+    cc_uint32	creds_offset;
+    cc_uint32	creds_len;
+};
+typedef struct ccmsg_creds_iterator_next_t ccmsg_creds_iterator_next_t;
+typedef struct ccmsg_creds_iterator_next_resp_t ccmsg_creds_iterator_next_resp_t;
+
+struct ccmsg_creds_v4_t {
+    cc_uint32 offset;
+    cc_uint32 len;
+};
+typedef struct ccmsg_creds_v4_t ccmsg_creds_v4_t;
+
+struct ccmsg_creds_v5_t {
+    cc_uint32 client_offset;
+    cc_uint32 client_len;
+    cc_uint32 server_offset;
+    cc_uint32 server_len;
+    cc_uint32 keyblock_offset;
+    cc_uint32 keyblock_len;
+    cc_time_t authtime;
+    cc_time_t starttime;
+    cc_time_t endtime;
+    cc_time_t renewtime;
+    cc_uint32 is_skey;
+    cc_uint32 ticket_flags;
+    cc_uint32 address_count;
+    cc_uint32 address_offset;
+    cc_uint32 address_len;
+    cc_uint32 ticket_offset;
+    cc_uint32 ticket_len;
+    cc_uint32 ticket2_offset;
+    cc_uint32 ticket2_len;
+    cc_uint32 authdata_count;
+    cc_uint32 authdata_offset;
+    cc_uint32 authdata_len;
+};
+typedef struct ccmsg_creds_v5_t ccmsg_creds_v5_t;
+
+
+#endif /*__MSG_HEADERS_H__*/
diff --git a/mechglue/src/lib/ccapi/mac/ChangeLog b/mechglue/src/lib/ccapi/mac/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/mac/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/marshall.c b/mechglue/src/lib/ccapi/marshall.c
new file mode 100644
index 000000000..7027d6561
--- /dev/null
+++ b/mechglue/src/lib/ccapi/marshall.c
@@ -0,0 +1,378 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/* marshall.c */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <CredentialsCache.h>
+#include "msg.h"
+#include "msg_headers.h"
+#include "marshall.h"
+
+cc_int32
+cci_creds_v4_marshall( cc_credentials_v4_t * creds, 
+                       char ** flat, 
+                       cc_uint32 * len)
+{
+    cc_msg_t *  msg;
+    ccmsg_creds_v4_t * header;
+    cc_uint32   blob_pos;
+    cc_int32    code;
+
+    if ( creds == NULL || flat == NULL || len == NULL )
+        return ccErrBadParam;
+
+    header = (ccmsg_creds_v4_t *)malloc(sizeof(ccmsg_creds_v4_t));
+    if ( header == NULL )
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_CREDS_V4, &msg);
+
+    code = cci_msg_add_header(msg, header, sizeof(ccmsg_creds_v4_t));
+
+    code = cci_msg_add_data_blob(msg, creds, sizeof(cc_credentials_v4_t), &blob_pos);
+
+    header->offset = blob_pos;
+    header->len    = sizeof(cc_credentials_v4_t);
+
+    code = cci_msg_flatten( msg, NULL );
+
+    *flat = msg->flat;
+    *len  = msg->flat_len;
+    msg->flat = NULL;
+    msg->flat_len = 0;
+
+    cci_msg_destroy(msg);
+
+    return ccNoError;
+}
+
+cc_int32
+cci_creds_v4_unmarshall( char * flat, 
+                         cc_uint32 len,
+                         cc_credentials_union * creds)
+{
+    cc_msg_t * msg; 
+    ccmsg_creds_v4_t * header;
+    cc_int32   code;
+
+    if ( flat == NULL || len == 0 || creds == NULL )
+        return ccErrBadParam;
+
+    code = cci_msg_unflatten( flat, len, &msg );
+
+    header = (ccmsg_creds_v4_t *)msg->header;
+
+    creds->version = cc_credentials_v4;
+    code = cci_msg_retrieve_blob(msg, header->offset, header->len, &creds->credentials.credentials_v4);
+
+    cci_msg_destroy(msg);
+
+    return ccNoError;
+}
+
+
+cc_int32
+cci_creds_cc_data_array_count_entries( cc_data ** array, cc_uint32 * pcount)
+{
+    cc_uint32 count;
+
+    if (array == NULL) {
+        *pcount = 0;
+        return ccNoError;
+    }
+
+    for ( count=0; array[count] != NULL ; count++) ;
+
+    *pcount = count;
+    return ccNoError;
+}
+
+cc_int32
+cci_creds_v5_compute_flat_size( cc_credentials_v5_t * creds, cc_uint32 * plen)
+{
+    cc_uint32 len;
+    cc_uint32 i, count;
+
+    len = sizeof(struct cci_flat_creds_v5);
+
+    if (creds->client)
+        len += strlen(creds->client) + 1;
+
+    if (creds->server)
+        len += strlen(creds->server) + 1;
+
+    len += creds->keyblock.length;
+
+    cci_creds_cc_data_array_count_entries( creds->addresses, &count );
+    len += count * sizeof(cc_flat_data);
+    for ( i=0; i<count; i++ ) {
+        len += creds->addresses[i]->length;
+    }
+
+    len += creds->ticket.length;
+    len += creds->second_ticket.length;
+
+    cci_creds_cc_data_array_count_entries( creds->authdata, &count );
+    len += count * sizeof(cc_flat_data);
+    for ( i=0; i<count; i++ ) {
+        len += creds->authdata[i]->length;
+    }
+
+    *plen = len;
+    return ccNoError;
+}
+
+cc_int32
+cci_creds_v5_marshall( cc_credentials_v5_t * creds, 
+                       char ** pflat, 
+                       cc_uint32 * plen)
+{
+    cc_uint32 len;
+    char * flat;
+    struct cci_flat_creds_v5 * header;
+    cc_uint32 offset;
+    cc_uint32 i;
+
+    if ( creds == NULL || pflat == NULL || plen == NULL )
+        return ccErrBadParam;
+
+    cci_creds_v5_compute_flat_size(creds, &len);
+
+    flat = (char *)malloc(len);
+    if ( flat == NULL )
+        return ccErrNoMem;
+    memset(flat, 0, len);
+
+    offset = sizeof(struct cci_flat_creds_v5);
+    header = (struct cci_flat_creds_v5 *)flat;
+    header->version = FLAT_CREDS_V5_VERSION;
+    if (creds->client) {
+        header->client.length = strlen(creds->client) + 1;
+        header->client.data = offset;
+        memcpy(flat + offset, creds->client, header->client.length);
+        offset += header->client.length;
+    }
+
+    if (creds->server) {
+        header->server.length = strlen(creds->server) + 1;
+        header->server.data = offset;
+        memcpy(flat + offset, creds->server, header->server.length);
+        offset += header->server.length;
+    }
+
+    header->keyblock.type = creds->keyblock.type;
+    if (creds->keyblock.length) {
+        header->keyblock.length = creds->keyblock.length;
+        header->keyblock.data = offset;
+        memcpy(flat + offset, creds->keyblock.data, header->keyblock.length);
+        offset += header->keyblock.length;
+    }           
+
+    header->authtime = creds->authtime;
+    header->starttime = creds->starttime;
+    header->endtime = creds->endtime;
+    header->renew_till = creds->renew_till;
+    header->is_skey = creds->is_skey;
+    header->ticket_flags = creds->ticket_flags;
+
+    cci_creds_cc_data_array_count_entries( creds->addresses, &header->address_count );
+    if ( header->address_count ) {
+        cc_flat_data * addresses = (cc_flat_data *)flat + offset;
+        header->addresses = offset;
+        offset += header->address_count * sizeof(cc_flat_data);
+
+        for ( i=0; i<header->address_count; i++ ) {
+            addresses[i].type = creds->addresses[i]->type;
+            if (creds->addresses[i]->length) {
+                addresses[i].length = creds->addresses[i]->length;
+                addresses[i].data = offset;
+                memcpy(flat + offset, creds->addresses[i]->data, addresses[i].length);
+                offset += addresses[i].length;
+            }
+        }
+    }
+
+    header->ticket.type = creds->ticket.type;
+    if (creds->ticket.length) {
+        header->ticket.length = creds->ticket.length;
+        header->ticket.data = offset;
+        memcpy(flat + offset, creds->ticket.data, header->ticket.length);
+        offset += header->ticket.length;
+    }           
+
+    header->second_ticket.type = creds->second_ticket.type;
+    if (creds->second_ticket.length) {
+        header->second_ticket.length = creds->second_ticket.length;
+        header->second_ticket.data = offset;
+        memcpy(flat + offset, creds->second_ticket.data, header->second_ticket.length);
+        offset += header->second_ticket.length;
+    }           
+
+    cci_creds_cc_data_array_count_entries( creds->authdata, &header->authdata_count );
+    if ( header->authdata_count ) {
+        cc_flat_data * authdata = (cc_flat_data *)flat + offset;
+        header->authdata = offset;
+        offset += header->authdata_count * sizeof(cc_flat_data);
+
+        for ( i=0; i<header->authdata_count; i++ ) {
+            authdata[i].type = creds->authdata[i]->type;
+            if (creds->authdata[i]->length) {
+                authdata[i].length = creds->authdata[i]->length;
+                authdata[i].data = offset;
+                memcpy(flat + offset, creds->authdata[i]->data, authdata[i].length);
+                offset += authdata[i].length;
+            }
+        }
+    }
+
+    *pflat = flat;
+    *plen = len;
+    return ccNoError;
+}
+
+
+// TODO: a much better job of checking for out of memory errors
+//       and validating that we do not read beyond the flat input
+//       data buffer
+
+cc_int32
+cci_creds_v5_unmarshall( char * flat, 
+                         cc_uint32 len,
+                         cc_credentials_union * creds_union)
+{
+    struct cci_flat_creds_v5 * header;
+    cc_credentials_v5_t * creds;
+    cc_flat_data * flat_data;
+    cc_uint32  i;
+    cc_int32   code;
+
+    if ( flat == NULL || len == 0 || creds_union == NULL )
+        return ccErrBadParam;
+
+    creds_union->version = cc_credentials_v5;
+
+    header = (struct cci_flat_creds_v5 *)flat;
+
+    if ( header->version != FLAT_CREDS_V5_VERSION )
+        return ccErrBadParam;
+
+    creds = (cc_credentials_v5_t *)malloc(sizeof(cc_credentials_v5_t));
+    if ( creds == NULL )
+        return ccErrNoMem;
+    memset(creds, 0, sizeof(ccmsg_creds_v5_t));
+
+    if ( header->client.length ) {
+        creds->client = (char *)malloc(header->client.length);
+        memcpy(creds->client, flat + header->client.data, header->client.length);
+    }
+
+    if ( header->server.length ) {
+        creds->server = (char *)malloc(header->server.length);
+        memcpy(creds->server, flat + header->server.data, header->server.length);
+    }
+
+    creds->keyblock.type = header->keyblock.type;
+    if ( header->keyblock.length ) {
+        creds->keyblock.length = header->keyblock.length;
+        creds->keyblock.data = malloc(creds->keyblock.length);
+        memcpy(creds->keyblock.data, flat + header->keyblock.data, creds->keyblock.length);
+    }
+
+    creds->authtime = header->authtime;
+    creds->starttime = header->starttime;
+    creds->endtime = header->endtime;
+    creds->renew_till = header->renew_till;
+    creds->is_skey = header->is_skey;
+    creds->ticket_flags = header->ticket_flags;
+
+    creds->addresses = (cc_data **) malloc((header->address_count + 1) * sizeof(cc_data *));
+    flat_data = (cc_flat_data *)flat + header->addresses;
+    for ( i=0 ; i < header->address_count ; i++ ) {
+        creds->addresses[i] = (cc_data *)malloc(sizeof(cc_data));
+        creds->addresses[i]->type = flat_data[i].type;
+        creds->addresses[i]->length = flat_data[i].length;
+        if ( flat_data[i].length ) {
+            creds->addresses[i]->data = malloc(flat_data[i].length);
+            memcpy(creds->addresses[i]->data, flat + flat_data[i].data, flat_data[i].length);
+        } else {
+            creds->addresses[i]->data = NULL;
+        }
+    }
+    creds->addresses[i] = NULL;
+
+    creds->ticket.type = header->ticket.type;
+    if ( header->ticket.length ) {
+        creds->ticket.length = header->ticket.length;
+        creds->ticket.data = malloc(creds->ticket.length);
+        memcpy(creds->ticket.data, flat + header->ticket.data, creds->ticket.length);
+    }
+
+    creds->second_ticket.type = header->second_ticket.type;
+    if ( header->second_ticket.length ) {
+        creds->second_ticket.length = header->second_ticket.length;
+        creds->second_ticket.data = malloc(creds->second_ticket.length);
+        memcpy(creds->second_ticket.data, flat + header->second_ticket.data, creds->second_ticket.length);
+    }
+
+    creds->authdata = (cc_data **) malloc((header->authdata_count + 1) * sizeof(cc_data *));
+    flat_data = (cc_flat_data *)flat + header->authdata;
+    for ( i=0 ; i < header->authdata_count ; i++ ) {
+        creds->authdata[i] = (cc_data *)malloc(sizeof(cc_data));
+        creds->authdata[i]->type = flat_data[i].type;
+        creds->authdata[i]->length = flat_data[i].length;
+        if ( flat_data[i].length ) {
+            creds->authdata[i]->data = malloc(flat_data[i].length);
+            memcpy(creds->authdata[i]->data, flat + flat_data[i].data, flat_data[i].length);
+        } else {
+            creds->authdata[i]->data = NULL;
+        }
+    }
+    creds->authdata[i] = NULL;
+
+    creds_union->credentials.credentials_v5 = creds;
+
+    return ccNoError;
+}
+
diff --git a/mechglue/src/lib/ccapi/msg.c b/mechglue/src/lib/ccapi/msg.c
new file mode 100644
index 000000000..f5f074aa0
--- /dev/null
+++ b/mechglue/src/lib/ccapi/msg.c
@@ -0,0 +1,582 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Verifiable, extensible message format.
+ */
+
+#include "CredentialsCache.h"
+#include "msg.h"
+#include "datastore.h"
+
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * cci_msg_new()
+ *
+ * Purpose: Allocate and initialize a new cc_msg_t structure
+ *
+ * Return:  non-NULL, the msg
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ *
+ */
+cc_int32
+cci_msg_new(cc_uint32 type, cc_msg_t** msgpp) 
+{
+    // type should be validated.  If invalid set error to ccErrBadParam
+    cc_msg_t* msg;
+    
+    if ( type > CC_MSG_MAX_TYPE || msgpp == NULL )
+        return ccErrBadParam;
+
+    msg = (cc_msg_t*)malloc(sizeof(cc_msg_t));
+    if (msg == NULL)
+        return ccErrNoMem;
+
+    msg->type = type;
+    msg->flat = NULL;
+    msg->header = NULL;
+    msg->flat_len = 0;
+    msg->header_len = 0;
+    msg->magic = 0;
+    cci_generic_list_new(&msg->data_blobs);
+    if (msg->data_blobs == NULL) {
+        // pass on error from previous call
+        free(msg);
+        return ccErrNoMem;
+    }
+
+    *msgpp = msg;     
+    return ccNoError;
+}
+
+/**
+ * cci_msg_calc_header_size()
+ *
+ * Purpose: Calculates the size of the header
+ *
+ * Return:  the size in bytes
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_msg_calc_header_size(cc_msg_t* msg, cc_uint32 * lenp) 
+{
+    int header_len = 12; /* header size, entire size, type */
+
+    if ( msg == NULL || lenp == NULL )
+        return ccErrBadParam;
+
+    header_len += msg->header_len;
+    *lenp = header_len;
+    return ccNoError;
+}
+
+/**
+ * cci_msg_calc_size()
+ *
+ * Purpose: Calculates the size of the message
+ *          (does not include the magic bytes)
+ *
+ * Return:  the size in bytes
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32 
+cci_msg_calc_size(cc_msg_t* msg, cc_uint32 * lenp) 
+{
+    cc_uint32 flat_len;
+    cc_generic_list_node_t* gen_node;
+    cc_generic_iterate_t* gen_iterator;
+	cc_int32 code;
+
+    if ( msg == NULL || lenp == NULL ) 
+        return ccErrBadParam;
+
+    code = cci_msg_calc_header_size(msg, &flat_len);
+    if (code != ccNoError)
+        goto bad;
+
+    code = cci_generic_list_iterator(msg->data_blobs, &gen_iterator);
+    if ( code != ccNoError )
+        goto bad;
+
+    while (cci_generic_iterate_has_next(gen_iterator)) {
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);
+        if (code != ccNoError)
+            break;
+        flat_len += gen_node->len + BLOB_LEN;
+    }
+    cci_generic_free_iterator(gen_iterator);
+    if (code != ccNoError)
+        goto bad;
+
+    flat_len += MAGIC_HEAD_LEN + MAGIC_DATA_LEN;
+    *lenp = flat_len;
+
+  bad:
+    return code;
+}
+
+/**
+ * cci_msg_add_data_blob()
+ *
+ * Purpose: Adds 'len' bytes of data to the msg
+ *
+ * Return: 
+ *
+ * Errors: 
+ *
+ */
+cc_int32 
+cci_msg_add_data_blob(cc_msg_t* msg, void *data, cc_uint32 len, cc_uint32 *lenp) 
+{
+    cc_int32 code;
+
+    if (msg == NULL || data == NULL || len <= 0 || lenp == NULL)
+        return ccErrBadParam;
+
+    code = cci_generic_list_append(msg->data_blobs, data, len, NULL);
+    if ( code != ccNoError )
+        return code;
+    return cci_msg_calc_blob_pos(msg, data, len, lenp);
+}
+
+/**
+ * cc_msg_
+ *
+ * Purpose:
+ *
+ * Return: 
+ *
+ * Errors: 
+ *
+ */
+cc_int32 
+cci_msg_calc_blob_pos(cc_msg_t* msg, void *data, cc_uint32 len, cc_uint32 * posp) 
+{
+    cc_uint32 pos;
+    cc_generic_list_node_t* gen_node;
+    cc_generic_iterate_t* gen_iterator;
+    cc_int32 code;
+
+    code = cci_msg_calc_header_size(msg, &pos);
+    pos += sizeof(cc_uint32); /*+ sizeof(cc_uint32) for magic*/
+
+    code = cci_generic_list_iterator(msg->data_blobs, &gen_iterator);
+    while (cci_generic_iterate_has_next(gen_iterator)) {
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);
+        if (gen_node->len != len && gen_node->data != data) {
+            pos += gen_node->len + sizeof(cc_uint32);
+        } else {
+            cci_generic_free_iterator(gen_iterator);
+            *posp = pos + sizeof(cc_uint32);
+            return ccNoError;
+        }
+    }
+    
+    cci_generic_free_iterator(gen_iterator);
+    return ccIteratorEnd;
+}
+
+/**
+ * cc_msg_
+ *
+ * Purpose:
+ *
+ * Return: 
+ *
+ * Errors: 
+ *
+ */
+cc_int32 
+cci_msg_add_header(cc_msg_t* msg, void *header, cc_uint32 header_len) 
+{
+    if ( msg == NULL || header == NULL )
+        return ccErrBadParam;
+
+    msg->header = header;
+    msg->header_len = header_len;
+    return ccNoError;
+}
+
+
+/**
+ * cc_msg_
+ *
+ * Purpose:
+ *
+ * Return: 
+ *
+ * Errors: 
+ *
+ */
+cc_int32
+cci_msg_flatten(cc_msg_t* msg, void **flatpp) 
+{
+    cc_generic_list_node_t* gen_node;
+    cc_generic_iterate_t* gen_iterator;
+    char *cur_pos;
+    cc_uint32 zero = 0;
+    cc_uint32 magic = 0;
+    cc_uint32 msg_len;
+    cc_int32 code;
+
+    if (msg == NULL || flatpp == NULL)
+        return ccErrBadParam;
+
+    code = cci_msg_calc_size(msg,&msg->flat_len);
+    if ( code != ccNoError )
+        return code;
+
+    if (msg->flat_len > CC_MSG_MAX_SIZE)
+        return ccErrBadParam;
+
+    msg->flat = (void *)malloc(msg->flat_len);
+    if (msg->flat == NULL)
+        return ccErrNoMem;
+    
+    cur_pos = msg->flat;
+
+    memcpy(cur_pos,&msg->header_len,sizeof(cc_uint32));
+    cur_pos+=sizeof(cc_uint32);
+
+    memcpy(cur_pos,&msg->flat_len,sizeof(cc_uint32));
+    cur_pos+=sizeof(cc_uint32);
+
+    memcpy(cur_pos,&msg->type,sizeof(cc_uint32));
+    cur_pos+=sizeof(cc_uint32);
+
+    memcpy(cur_pos, msg->header, msg->header_len);
+    cur_pos += msg->header_len;
+
+    memcpy(cur_pos, &zero, sizeof(cc_uint32)); /*will be magic number later*/
+    cur_pos += sizeof(cc_uint32);
+
+    code = cci_generic_list_iterator(msg->data_blobs,&gen_iterator);
+    if ( code != ccNoError ) {
+        free(msg->flat);
+        return code;
+    }
+
+    while (cci_generic_iterate_has_next(gen_iterator)) {
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);
+        if (code != ccNoError) {
+            free(gen_iterator);
+            free(msg->flat);
+            return code;
+        }
+        memcpy(cur_pos, &gen_node->len, sizeof(cc_uint32));
+        cur_pos+=sizeof(cc_uint32);
+		
+        memcpy(cur_pos, gen_node->data, gen_node->len);
+        cur_pos += gen_node->len;
+    }
+    free(gen_iterator);
+
+    memcpy(cur_pos, &zero, sizeof(cc_uint32)); /*magic number will go here later*/
+    cur_pos += sizeof(cc_uint32);
+
+    if (cur_pos - (char *)msg->flat != msg->flat_len) {
+        printf("ERRORR cur_pos - msg->flat = %d\n",msg->flat_len);
+    }
+
+    cci_msg_calc_magic(msg->flat, msg->flat_len, &magic);
+    printf("magic = %d\n",magic);
+	
+    cci_msg_calc_header_size(msg, &msg_len);
+    memcpy((char *)msg->flat + msg_len, &magic, sizeof(cc_uint32));
+    memcpy((char *)msg->flat + msg->flat_len - sizeof(cc_uint32), &magic, sizeof(cc_uint32));
+
+    if ( flatpp != NULL )
+        *flatpp = msg->flat;
+    return ccNoError;
+}
+
+/**
+ * cc_msg_
+ *
+ * Purpose:
+ *
+ * Return: 
+ *
+ * Errors: 
+ *
+ */
+cc_int32
+cci_msg_calc_magic(void *flat, int flat_len, cc_uint32 * magicp)
+{
+    cc_uint32 magic = 0;
+    int i;
+	
+    for (i = 0; i < flat_len; i += sizeof(cc_uint32)) {
+        magic = magic ^ *(int *)((char *)flat + i);
+    }
+    *magicp = magic;
+    return ccNoError;
+}
+
+/**
+ * cc_msg_
+ *
+ * Purpose:
+ *
+ * Return: 
+ *
+ * Errors: 
+ *
+ */
+cc_int32 
+cci_msg_verify(void *flat, int flat_len, cc_uint32 * validp)  
+{
+    cc_uint32 *magic1, *magic2;
+    cc_uint32 *pheader_len;
+    cc_uint32 *ptotal_len;
+    cc_uint32 *pblob_len;
+    cc_uint32 *ptype;
+    cc_uint32 num_blobs = 0;
+    cc_uint32 zero = 0;
+    cc_uint32 msg_magic, msg_magic2;
+
+    if (flat == NULL || flat_len <= 0 || validp == NULL)
+        return ccErrBadParam;
+
+    pheader_len = flat;
+    ptotal_len = (cc_uint32 *)((char *)pheader_len + sizeof(cc_uint32));
+    ptype = (cc_uint32 *)((char *)ptotal_len + sizeof(cc_uint32));
+
+    if (*ptotal_len != flat_len) {
+        *validp = 0;
+        return ccNoError;
+    }
+    
+    if (*pheader_len > flat_len) {
+        /*too weak. We could verify header_len against type spec header.*/
+        *validp = 0;
+        return ccNoError;
+    }
+    if (*ptype > CC_MSG_MAX_TYPE) {
+        *validp = 0;
+        return ccNoError;
+    }
+
+    magic1 = (cc_uint32 *)((char *)ptype + sizeof(cc_uint32) + *pheader_len); 
+    if ((char *)magic1 - (char *)flat == (flat_len - 8)) {
+        /*There are no data blobs*/
+        magic2 = (cc_uint32 *)((char *)magic1 + sizeof(cc_uint32));
+        num_blobs = 0;
+    } else {
+        pblob_len = (cc_uint32 *)((char *)magic1 + sizeof(cc_uint32));
+        num_blobs = 1;
+
+        while (*pblob_len + sizeof(cc_uint32) + ((char *)pblob_len - (char *)flat) < (flat_len - sizeof(cc_uint32))) {
+            pblob_len = (cc_uint32 *)((char *)pblob_len + *pblob_len + sizeof(cc_uint32));
+            num_blobs++;
+        }
+
+        if (*pblob_len + sizeof(cc_uint32) + ((char *)pblob_len - (char *)flat) != (flat_len - sizeof(cc_uint32))) {
+            /*blobs didn't line up*/
+            *validp = 0;
+            return ccNoError;
+        }
+        magic2 = (cc_uint32 *)((char *)pblob_len + *pblob_len + sizeof(cc_uint32)); /*2nd magic should be directly after the last blob*/
+    }
+	
+    if (*magic1 != *magic2) {
+        *validp = 0;
+        return ccNoError;
+    }
+    msg_magic = *magic1;
+
+    printf("%d %d\n", (char *)magic1 - (char *)flat, (char *)magic2 - (char *)flat);
+
+    memcpy(magic1, &zero, sizeof(cc_uint32));
+    memcpy(magic2, &zero, sizeof(cc_uint32));
+    cci_msg_calc_magic(flat, flat_len, &msg_magic2);
+    if (msg_magic != msg_magic2) {
+        *validp = 0;
+        return ccNoError;
+    }
+    memcpy(magic1, &msg_magic, sizeof(cc_uint32));
+    memcpy(magic2, &msg_magic, sizeof(cc_uint32));
+
+    *validp = 1;
+    return ccNoError;
+}
+
+/**
+ * cc_msg_
+ *
+ * Purpose:
+ *
+ * Return: 
+ *
+ * Errors: 
+ *
+ */
+cc_int32
+cci_msg_unflatten(void *flat, int flat_len, cc_msg_t** msgpp) 
+{
+    cc_msg_t* msg;
+    char *cur_pos;
+    cc_uint32 blob_len;
+    char *blob;
+    cc_uint32 valid;
+    cc_int32 code;
+
+    if ( flat == NULL || flat_len <= 0 || msgpp == NULL )
+        return ccErrBadParam;
+
+    code = cci_msg_new(0, &msg);
+    if (code)
+        return code;
+
+    cci_msg_verify(flat, flat_len, &valid);
+    if (valid != 1) {
+        cci_msg_destroy(msg);
+        return ccErrBadParam;
+    }
+
+    cur_pos = flat;
+    msg->flat = flat;
+
+    msg->header_len = *(cc_uint32 *)cur_pos;
+    cur_pos += sizeof(cc_uint32);
+
+    msg->flat_len = *(cc_uint32 *)cur_pos;
+    cur_pos += sizeof(cc_uint32);
+
+    msg->type = *(cc_uint32 *)cur_pos;
+    cur_pos += sizeof(cc_uint32);
+
+    msg->header = (void *)malloc(msg->header_len);
+    if (msg->header == NULL) {
+        cci_msg_destroy(msg);
+        return ccErrNoMem;
+    }
+    memcpy(msg->header, cur_pos, msg->header_len);
+    cur_pos += msg->header_len;
+	
+    msg->magic = *(cc_uint32 *)cur_pos;
+    cur_pos += sizeof(cc_uint32);
+
+    if (cur_pos - (char *)flat != flat_len - 8) { /*at least 1 blob*/
+        blob_len = *(cc_uint32 *)cur_pos;
+        while (blob_len + (cur_pos - (char *)flat) + sizeof(cc_uint32) <= flat_len - sizeof(cc_uint32)) {
+            blob = (void *)malloc(blob_len);
+            if (blob == NULL) {
+                cci_msg_destroy(msg);
+                return ccErrNoMem;
+            }
+            memcpy(blob, cur_pos + sizeof(cc_uint32), blob_len);
+            cci_generic_list_append(msg->data_blobs, blob, blob_len, NULL);
+
+            cur_pos += sizeof(cc_uint32) + blob_len;
+            blob_len = *(int *)cur_pos;
+        }
+    }
+    *msgpp = msg;
+    return ccNoError;
+}
+
+cc_int32
+cci_msg_retrieve_blob(cc_msg_t* msg, cc_uint32 blob_offset, cc_uint32 blob_len, void **blobp) 
+{
+    cc_generic_iterate_t*	gen_iterator;
+    cc_generic_list_node_t*	gen_node;
+    void *ret;
+    cc_uint32                   blob_pos;
+    cc_int32                    code;
+
+    /*Ensure that the message has been unflattened*/
+    if ( msg == NULL || msg->flat == NULL || blob_offset > msg->flat_len || 
+         blob_len > msg->flat_len - blob_offset || blobp == NULL)
+        return ccErrBadParam;
+
+    code = cci_generic_list_iterator(msg->data_blobs, &gen_iterator);
+    while (cci_generic_iterate_has_next(gen_iterator)) {
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);
+        code = cci_msg_calc_blob_pos(msg, gen_node->data, gen_node->len, &blob_pos);
+        if (blob_pos == blob_offset && gen_node->len == blob_len)  {
+            free(gen_iterator);
+            ret = (void *)malloc(blob_len);
+            if (ret == NULL)
+                return ccErrNoMem;
+            memcpy(ret,(char *)msg->flat + blob_offset, blob_len);	
+            *blobp = ret;
+            return ccNoError;
+        }
+    }
+    free(gen_iterator);
+    return ccIteratorEnd;
+}
+
+/**
+ * cc_msg_
+ *
+ * Purpose:
+ *
+ * Return: 
+ *
+ * Errors: 
+ *
+ */
+cc_int32 
+cci_msg_destroy(cc_msg_t* msg) 
+{
+    if (msg->flat != NULL) 
+        free(msg->flat);
+    if (msg->header != NULL)
+        free(msg->flat);
+    cci_generic_list_destroy(msg->data_blobs);
+    free(msg);
+    return ccNoError;
+}
+
diff --git a/mechglue/src/lib/ccapi/server/ChangeLog b/mechglue/src/lib/ccapi/server/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/server/NTMakefile b/mechglue/src/lib/ccapi/server/NTMakefile
new file mode 100644
index 000000000..671b6905f
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/NTMakefile
@@ -0,0 +1,30 @@
+# Makefile for the CCAPI Generic Server
+
+!INCLUDE <WIN32.MAK>
+
+CFLAGS = -I../include
+
+CCAPI_LIB = ../lib/ccapi.lib
+WINLIBS = user32.lib advapi32.lib
+CCSOBJS = context.obj ccache.obj lists.obj rpc_auth.obj serv_ops.obj
+
+all: t_lists.exe t_msg.exe t_ccache.exe t_context.exe ccapi_server.exe
+
+t_lists.exe: t_lists.obj $(CCSOBJS) $(CCAPI_LIB)
+        link -out:$@ t_lists.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+t_msg.exe: t_msg.obj $(CCSOBJS) $(CCAPI_LIB)
+        link -out:$@ t_msg.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+t_ccache.exe: t_ccache.obj $(CCSOBJS) $(CCAPI_LIB)
+        link -out:$@ t_ccache.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+t_context.exe: t_context.obj $(CCSOBJS) $(CCAPI_LIB)
+        link -out:$@ t_context.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+ccapi_server.exe: main.obj $(CCSOBJS) $(CCAPI_LIB)
+        link -out:$@ main.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+clean: 
+	del *.obj *.exe
+
diff --git a/mechglue/src/lib/ccapi/server/ccache.c b/mechglue/src/lib/ccapi/server/ccache.c
new file mode 100644
index 000000000..2c3a745af
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/ccache.c
@@ -0,0 +1,703 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Manages ccache objects.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+/**
+ * ccache_new()
+ * 
+ * Purpose: Allocate and initialize new credentials cache for the specified principal
+ *          and version
+ * 
+ * Return:  ccNoError - success
+ *          ccErrInvalidString - name or principal is NULL
+ *          ccErrBadCredentialsVersion - unsupported creds type
+ *          ccErrBadParam - outCcachepp is NULL
+ *          ccErrNoMem - malloc failed
+ */
+cc_int32
+cci_ccache_new( char *name, char *principal, int cred_vers, 
+                cc_server_ccache_t** outCCachepp)
+{
+    cc_server_ccache_t* ccache;
+
+    if (name == NULL || principal == NULL)
+        return ccErrInvalidString;
+
+    if (cred_vers != cc_credentials_v4 && cred_vers != cc_credentials_v5 && 
+         cred_vers != cc_credentials_v4_v5)
+        return ccErrBadCredentialsVersion;
+
+    if (outCCachepp == NULL)
+        return ccErrBadParam;
+
+    ccache = (cc_server_ccache_t*)malloc(sizeof(cc_server_ccache_t));
+    if (ccache == NULL)
+        return ccErrNoMem;
+
+    ccache->name = name;
+    ccache->principal_v4 = NULL;
+    ccache->principal_v5 = NULL;
+    ccache->changed = time(NULL);
+    ccache->kdc_offset = 0;
+    ccache->last_default = 0;
+    cci_generic_list_new(&ccache->active_iterators);
+    cci_credentials_list_new(&ccache->creds);
+    ccache->is_default = 0;
+    ccache->kdc_set = 0;
+    ccache->versions = cred_vers;
+    ccache->mycontext = NULL;
+
+    cci_ccache_set_principal(ccache, cred_vers, principal);
+    *outCCachepp = ccache;
+    return ccNoError;
+}
+
+/**
+ * cci_ccache_check_version()
+ * 
+ * Purpose: Check to see if the ccache and the creds have compatible versions. 
+ * 
+ * Return:  ccNoError and compat = 1 if they are compatible 
+ *          ccNoError and compat = 0 if they are not compatible
+ * 
+ * Errors:  ccErrInvalidCCache - ccache is NULL
+ *          ccErrBadParam - either creds or compat are NULL
+ */
+cc_int32 
+cci_ccache_check_version( const cc_server_ccache_t *ccache,
+                          const cc_credentials_union* creds,
+                          cc_uint32* compat)
+{
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+
+    if (creds == NULL || compat == NULL)
+        return ccErrBadParam;
+
+    if (ccache->versions == cc_credentials_v4_v5)
+        *compat = 1;
+    else if (ccache->versions == creds->version)
+        *compat = 1;
+    else
+        *compat = 0;
+
+    return ccNoError;
+}
+
+/** 
+cci_ccache_check_principal()
+
+Check to see if the client principal from the credentials matches
+the principal associated with the cache.
+
+* Return:  ccNoError and compat = 1 if they are compatible 
+*          ccNoError and compat = 0 if they are not compatible
+* 
+* Errors:  ccErrInvalidCCache - ccache is NULL
+*          ccErrBadParam - either creds or compat are NULL
+*          ccErrBadCredentialVersion - unsupported credential type
+*/
+cc_int32 
+cci_ccache_check_principal( const cc_server_ccache_t *ccache,
+                            const cc_credentials_union* creds,
+                            cc_uint32* compat)
+{
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+
+    if (creds == NULL || compat == NULL)
+        return ccErrBadParam;
+
+    if (creds->version == cc_credentials_v4) {
+        if (strcmp(creds->credentials.credentials_v4->principal, ccache->principal_v4) == 0) 
+            *compat = 1;
+        else 
+            *compat = 0;
+    } else if (creds->version == cc_credentials_v5) {
+        if (strcmp(creds->credentials.credentials_v5->client, ccache->principal_v5) == 0)
+            *compat = 1;
+        else 
+            *compat = 0;
+    } else {        
+        return ccErrBadCredentialsVersion;
+    }
+    return ccNoError;
+}
+
+
+/** 
+ * cci_ccache_store_creds()
+ *
+ * Purpose: Stores the provided credentials into the provided cache.  Validates the
+ *          ability of the cache to store credentials of the given version and client
+ *          principal.
+ *
+ * Return:  0 on success
+ *         -1 on error
+ *
+ * Errors: ccErrNoMem
+ *         ccErrBadCredentialsVersion
+ *         ccErrBadInvalidCredentials
+ *         ccErrInvalidCache
+ *         ccErrBadParam
+ */
+cc_int32 
+cci_ccache_store_creds(cc_server_ccache_t *ccache, const cc_credentials_union* credentials) 
+{
+    cc_server_credentials_t* stored_cred=NULL;
+    cc_uint32 valid_version, valid_principal;
+    cc_int32 code;
+
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+    
+    if (credentials == NULL)
+        return ccErrBadParam;
+
+    code = cci_ccache_check_version(ccache, credentials, &valid_version);
+    if (code != ccNoError) {
+        /* pass error on to caller */
+        goto bad;
+    }
+    code = cci_ccache_check_principal(ccache, credentials, &valid_principal);
+    if (code != ccNoError) {
+        /* pass error on to caller */
+        goto bad;
+    }
+    if (valid_version && valid_principal) {
+        stored_cred = (cc_server_credentials_t*)malloc(sizeof(cc_server_credentials_t));
+        if (stored_cred == NULL) {
+            code = ccErrNoMem;
+            goto bad;
+        }
+        memcpy(&stored_cred->creds, credentials, sizeof(cc_credentials_union));
+
+        if (credentials->version == cc_credentials_v4) {
+            stored_cred->creds.credentials.credentials_v4 = (cc_credentials_v4_t*)malloc(sizeof(cc_credentials_v4_t));
+            if (stored_cred->creds.credentials.credentials_v4 == NULL) {
+                code = ccErrNoMem;
+                goto bad;
+            }
+
+            memcpy(stored_cred->creds.credentials.credentials_v4, credentials->credentials.credentials_v4, sizeof(cc_credentials_v4_t));
+        } else if (credentials->version == cc_credentials_v5) {
+            stored_cred->creds.credentials.credentials_v5 = (cc_credentials_v5_t*)malloc(sizeof(cc_credentials_v5_t));
+            if (stored_cred->creds.credentials.credentials_v5 == NULL) {
+                code = ccErrNoMem;
+                goto bad;
+            }
+
+            memcpy(stored_cred->creds.credentials.credentials_v5, credentials->credentials.credentials_v5, sizeof(cc_credentials_v5_t));
+        } else {
+            code = ccErrBadCredentialsVersion;
+            goto bad;
+        }
+
+        code = cci_credentials_list_append(ccache->creds, stored_cred, NULL);
+        if ( code != ccNoError ) {
+            /* pass error on to caller */
+            goto bad;
+        }
+        if (ccache->creds->head->data == (cc_uint8 *)stored_cred) 
+            stored_cred->is_default = 1; /*we're first on the list, so we're default*/
+
+        cci_ccache_changed(ccache);
+        return ccNoError;
+    } else {
+#ifdef DEBUG
+        printf("vers: %d\tprincipal: %d\n",
+                valid_version, valid_principal);
+#endif /* DEBUG */
+        code = ccErrInvalidCredentials;
+        goto bad;
+    }
+
+  bad:
+    if (stored_cred)
+        free(stored_cred);
+    return code;      /* error */
+}
+
+/**
+ * cci_ccache_changed()
+ *
+ * Purpose: Updates the last update time for the ccache and its associated context.
+ *          Provides a location from which interested parties should be notified
+ *          of cache updates.
+ *
+ * Return:  none
+ *
+ * Errors:  none
+ */
+void 
+cci_ccache_changed(cc_server_ccache_t* ccache) 
+{
+    ccache->changed = time(NULL);
+    if (ccache->mycontext != NULL)
+        ccache->mycontext->changed = time(NULL);
+
+    /* XXX - notify registered listeners when implemented */
+}
+
+/**
+ * cci_ccache_rem_creds()
+ *
+ * Purpose: Removes the specified credential object from the specified cache if
+ *          it exists
+ *
+ * Return:  0 on success (credential is not in the cache)
+ *         -1 on error
+ *
+ * Errors: ccErrBadParam, ccErrNoMem (from cc_credentials_list_iterator)
+ *
+ * Verify: does the memory associated with stored_cred->creds need to be freed?
+ *
+ */
+cc_int32 
+cci_ccache_rem_creds(cc_server_ccache_t *ccache, const cc_credentials_union* credentials) 
+{
+    cc_credentials_iterate_t* credentials_iterator=NULL, *active;
+    cc_generic_iterate_t* generic_iterator=NULL;
+    cc_credentials_list_node_t* credentials_node;
+    cc_generic_list_node_t* generic_node;
+    cc_server_credentials_t* stored_cred;
+    cc_int8 changed = 0;
+    cc_int32 code = 0;
+
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+
+    if (credentials == NULL)
+        return ccErrBadParam;
+
+    code = cci_credentials_list_iterator(ccache->creds, &credentials_iterator);
+    if (code != ccNoError) {
+        /* pass error to caller */
+        goto cleanup;
+    }
+
+    while (cci_credentials_iterate_has_next(credentials_iterator)) {
+        code = cci_credentials_iterate_next(credentials_iterator, &credentials_node);
+        stored_cred = (cc_server_credentials_t*)credentials_node->data;
+        if (memcmp(&stored_cred->creds,credentials,sizeof(cc_credentials_union)) == 0) {
+            /* XXX - do we need to free(stored_cred->creds) ? */
+            free(credentials_node->data);
+            changed = 1;
+		
+            /*If any iterator's next points to the deleted node, make it point to the next node*/
+            code = cci_generic_list_iterator(ccache->active_iterators, &generic_iterator);
+            while (cci_generic_iterate_has_next(generic_iterator)) {
+                code = cci_generic_iterate_next(generic_iterator, &generic_node);			
+                active = (cc_credentials_iterate_t*)generic_node->data;
+                if (active->next == credentials_node) 
+                    active->next = active->next->next;
+            }
+            code = cci_generic_free_iterator(generic_iterator);
+            generic_iterator = NULL;
+
+            if (credentials_node == ccache->creds->head) { /*removing the default, must make next cred default*/
+                code = cci_credentials_list_remove_element(ccache->creds, credentials_node);
+
+                if (ccache->creds->head != NULL)
+                    ((cc_server_credentials_t*)ccache->creds->head->data)->is_default = 1;
+            } else {
+                code = cci_credentials_list_remove_element(ccache->creds, credentials_node);
+            }
+            break;
+        }
+    }
+
+  cleanup:
+    if (changed)
+        cci_ccache_changed(ccache);
+    if (credentials_iterator)
+        cci_credentials_free_iterator(credentials_iterator);
+    if (generic_iterator)
+        cci_generic_free_iterator(generic_iterator);
+    return code;
+}
+
+/**
+ * cci_ccache_move()
+ * 
+ * Purpose: Destroys the existing contents of the destination and copies
+ *          all credentials from the source to the destination
+ *
+ * Return:  0 on success
+ *         -1 on error
+ *
+ * Errors:  ccBadNoMem
+ *
+ */
+
+cc_int32 
+cci_ccache_move(cc_server_ccache_t *source, cc_server_ccache_t* destination) 
+{
+    cc_generic_list_node_t* node;
+    cc_generic_iterate_t* iterator;
+    cc_credentials_iterate_t* cur;
+    cc_int32 code;
+
+    if (source == NULL || destination == NULL)
+        return ccErrBadParam;
+	
+    code = cci_credentials_list_destroy(destination->creds);
+    if ( code != ccNoError )
+        return code;
+
+    code = cci_credentials_list_copy(source->creds, &destination->creds);
+    if ( code != ccNoError ) 
+        return code;
+
+    destination->versions = source->versions;
+    destination->kdc_offset = source->kdc_offset;
+    destination->last_default = 0;
+
+    /*reset all active iterators to point to the head of the new creds list*/
+    if (destination->active_iterators->head != NULL) {
+        code = cci_generic_list_iterator(destination->active_iterators, &iterator);
+        while (cci_generic_iterate_has_next(iterator)) {
+            code = cci_generic_iterate_next(iterator, &node);
+            cur = (cc_credentials_iterate_t*)node->data;
+            cur->next = destination->creds->head;
+        }
+        code = cci_generic_free_iterator(iterator);
+    }
+
+    cci_ccache_changed(destination);
+    return code;
+}
+
+/**
+ * cci_ccache_get_kdc_time_offset()
+ * 
+ * Purpose: Retrieves the kdc_time_offset from the ccache if set
+ *
+ * Return:  0 on success
+ *         -1 on error
+ *
+ * Errors:  ccErrBadParam, ccErrTimeOffsetNotSet
+ *
+ */
+cc_int32 
+cci_ccache_get_kdc_time_offset(cc_server_ccache_t* ccache, cc_time_t* offset) 
+{
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+    
+    if (offset == NULL)
+        return ccErrBadParam;
+
+    if (!ccache->kdc_set)
+        return ccErrTimeOffsetNotSet;
+
+    *offset = ccache->kdc_offset;
+    return ccNoError;
+}
+
+/**
+ * cci_ccache_set_kdc_time_offset()
+ *
+ * Purpose: Sets the kdc time offset in the designated ccache
+ * 
+ * Return:  0 on success
+ *         -1 on error
+ * 
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32 
+cci_ccache_set_kdc_time_offset(cc_server_ccache_t* ccache, cc_time_t offset) 
+{
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+
+    ccache->kdc_offset = offset;
+    ccache->kdc_set = 1;
+    cci_ccache_changed(ccache);
+
+    return ccNoError;
+}
+
+/**
+ * cci_ccache_clear_kdc_time_offset()
+ *
+ * Purpose: Clear the kdc time offset in the designated ccache
+ *
+ * Return:  0 on success
+ *         -1 on error
+ *
+ * Errors: ccErrBadParam
+ */
+cc_int32 
+cci_ccache_clear_kdc_time_offset(cc_server_ccache_t* ccache) 
+{
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+
+    ccache->kdc_offset = 0;
+    ccache->kdc_set = 0;
+    cci_ccache_changed(ccache);
+
+    return ccNoError;
+}
+
+/**
+ * cci_ccache_new_iterator()
+ *
+ * Purpose: Retrieve an iterator for the designated cache
+ *
+ * Return:  0 on success
+ *         -1 on error
+ *
+ * Errors: ccErrBadParam, ccBadNoMem
+ */
+cc_int32 
+cci_ccache_new_iterator(cc_server_ccache_t* ccache, cc_credentials_iterate_t** iterator)
+{
+    cc_int32 code;
+
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+
+    if (iterator == NULL)
+        return ccErrBadParam;
+
+    code = cci_credentials_list_iterator(ccache->creds, iterator);
+    if (code != ccNoError)
+        return code;
+
+    code = cci_generic_list_prepend(ccache->active_iterators, *iterator, sizeof(cc_credentials_iterate_t), NULL);
+    if (code != ccNoError)
+        return code;
+
+    return ccNoError;
+}
+
+/**
+ * cci_ccache_get_principal()
+ * 
+ * Purpose: Retrieves the client principal associated with the designated cache.
+ *          The value is returned 
+ * Return:
+ *
+ * Errors:
+ */
+cc_int32 
+cci_ccache_get_principal(cc_server_ccache_t* ccache, cc_int32 version, char ** principal) 
+{
+    char *p = NULL;
+    
+    switch ( version ) {
+    case cc_credentials_v4:
+        p = ccache->principal_v4;
+        break;
+    case cc_credentials_v5:
+        p = ccache->principal_v5;
+        break;
+    default:
+        return ccErrBadCredentialsVersion;
+    }
+
+    *principal = (char *)malloc(strlen(p)+1);
+    if ( *principal == NULL )
+        return ccErrNoMem;
+
+    strcpy(*principal, p);
+    return ccNoError;
+}
+
+/**
+ * Purpose: Releases the memory associated with a ccache principal
+ * 
+ * Return:
+ *
+ * Errors:
+ *
+ */
+cc_int32
+cci_ccache_free_principal(char * principal)
+{
+    if ( principal == NULL )
+        return ccErrBadParam;
+
+    free(principal);
+    return ccNoError;
+}
+
+/**
+ * ccache_set_principal()
+ *
+ * Purpose: Assigns a principal to the designated ccache and credential version.
+ *          If the api version is 2, the cache is cleared of all existing
+ *          credentials.
+ *
+ * Return:  0 on success
+ *         -1 on error
+ *
+ * Errors: ccErrNoMem, ccErrBadCredentialsVersion
+ */
+cc_int32 
+cci_ccache_set_principal( cc_server_ccache_t* ccache, cc_int32 cred_version, 
+                          char* principal)
+{
+    cc_generic_iterate_t* generic_iterator;
+    cc_generic_list_node_t* generic_node;
+    cc_ccache_iterate_t* ccache_iterator;
+    cc_int32 code = ccNoError;
+
+    if (ccache == NULL)
+        return ccErrInvalidCCache;
+    
+    if (principal == NULL)
+        return ccErrInvalidString;
+
+    switch (cred_version) {
+    case cc_credentials_v4:
+    case cc_credentials_v4_v5:
+        ccache->principal_v4 = (char *)malloc(strlen(principal) + 1);
+        if (ccache->principal_v4 == NULL)
+            return ccErrNoMem;
+        strcpy(ccache->principal_v4, principal);
+        if (cred_version != cc_credentials_v4_v5)
+            break;
+        /* fall-through if we are v4_v5 */
+    case cc_credentials_v5:
+        ccache->principal_v5 = (char *)malloc(strlen(principal) + 1);
+        if (ccache->principal_v5 == NULL) {
+            if (cred_version == cc_credentials_v4_v5) {
+                free(ccache->principal_v4);
+                ccache->principal_v4 = NULL;
+            }
+            return ccErrNoMem;
+        }
+        strcpy(ccache->principal_v5, principal);
+        break;
+    default:
+        return ccErrBadCredentialsVersion;
+    }
+
+    /*For API version 2 clients set_principal implies a flush of all creds*/
+    if (ccache->mycontext != NULL && ccache->mycontext->api_version == ccapi_version_2) {
+        cci_credentials_list_destroy(ccache->creds);
+        cci_credentials_list_new(&ccache->creds);
+
+        /*clean up active_iterators*/
+        code = cci_generic_list_iterator(ccache->active_iterators, &generic_iterator);
+        if (code == ccNoError) {
+            while (cci_generic_iterate_has_next(generic_iterator)) {
+                code = cci_generic_iterate_next(generic_iterator, &generic_node);
+                ccache_iterator = (cc_ccache_iterate_t*)generic_node->data;
+                ccache_iterator->next = NULL;
+            }
+        }
+    }
+
+    cci_ccache_changed(ccache);
+
+    return code;
+}
+
+/**
+ * cci_ccache_destroy()
+ *
+ * Purpose: Destroys an existing ccache 
+ *
+ * Return:  0 on success
+ *         -1 on errors
+ *
+ * Errors:  ccErrBadParam
+ */
+cc_int32 
+cci_ccache_destroy(cc_server_ccache_t* ccache) 
+{
+    cc_int32 code;
+
+    if ( ccache == NULL )
+        return ccErrInvalidCCache;
+
+    code = cci_generic_list_destroy(ccache->active_iterators);
+    code = cci_credentials_list_destroy(ccache->creds);
+
+    if (ccache->mycontext != NULL)
+        code = cci_context_rem_ccache(ccache->mycontext, ccache);
+
+    return code;
+}
+
+/**
+ * cci_ccache_compare()
+ *
+ * Purpose: Returns a boolean value indicating if two caches are identical
+ *          Implemented as pointer equivalence.
+ *
+ * Return:  1 if TRUE
+ *          0 if FALSE
+ *
+ * Errors:  No errors
+ */
+cc_int32 
+cci_ccache_compare(cc_server_ccache_t* ccache1, cc_server_ccache_t* ccache2, cc_uint32 *result) 
+{
+    if ( ccache1 == NULL || ccache2 == NULL )
+        return ccErrInvalidCCache;
+
+    if (ccache1 == ccache2)
+        *result = 1;
+    else 
+        *result = 0;
+
+    return ccNoError;
+}
+
diff --git a/mechglue/src/lib/ccapi/server/context.c b/mechglue/src/lib/ccapi/server/context.c
new file mode 100644
index 000000000..f405a4def
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/context.c
@@ -0,0 +1,325 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Functions to manipulate datastore layer contexts.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+int cc_myversion = 5;
+char cc_vendor[] = "MIT C lang CCache V5";
+char cc_default_ccache_name[] = "krb5cc";
+
+
+cc_int32
+cci_context_new( int api_version, cc_auth_info_t* auth_info, 
+                 cc_session_info_t* session_info, cc_server_context_t** outContextpp )
+{
+    cc_server_context_t* ctx;
+	
+    if ( outContextpp == NULL )
+        return ccErrBadParam;
+
+	ctx = (cc_server_context_t*)malloc(sizeof(cc_server_context_t));
+    if (ctx == NULL)
+        return ccErrNoMem;
+		
+    cci_ccache_list_new(&ctx->ccaches);
+    cci_generic_list_new(&ctx->active_iterators);	
+    ctx->api_version = api_version;
+    ctx->auth_info = auth_info;
+    ctx->session_info = session_info;
+    ctx->changed = time(NULL);
+
+    *outContextpp = ctx;
+    return ccNoError;
+}
+
+cc_int32
+cci_context_get_default_ccache_name(cc_server_context_t* ctx, char ** outNamepp) 
+{
+    cc_server_ccache_t* default_ccache;
+
+    if (outNamepp == NULL)
+        return ccErrBadParam;
+    
+    if (ctx == NULL)
+        return ccErrInvalidContext;
+
+    if (ctx->ccaches->head != NULL) {
+        default_ccache = (cc_server_ccache_t*)ctx->ccaches->head->data;
+        *outNamepp = default_ccache->name;
+    } else {
+        *outNamepp = cc_default_ccache_name;
+    }
+    return ccNoError;
+}
+
+
+cc_int32
+cci_context_find_ccache( cc_server_context_t* ctx, char *name, 
+                         cc_server_ccache_t** outCcachepp )
+{
+    cc_ccache_iterate_t* ccache_iterator;
+    cc_ccache_list_node_t* ccache_node;
+    cc_server_ccache_t* ccache;
+	cc_int32 code;
+
+    if (ctx == NULL) 
+        return ccErrInvalidContext;
+    
+    if (name == NULL)
+        return ccErrInvalidString;
+
+    if (outCcachepp == NULL)
+        return ccErrBadParam;
+
+    code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+    while (cci_ccache_iterate_has_next(ccache_iterator)) {
+        code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+        ccache = (cc_server_ccache_t *)ccache_node->data;
+        if (strcmp(ccache->name, name) == 0)  {
+            free(ccache_iterator);
+            *outCcachepp = ccache;
+            return ccNoError;
+        }
+    }
+    free(ccache_iterator);
+    return ccErrCCacheNotFound;
+}       
+
+cc_int32
+cci_context_open_ccache( cc_server_context_t* ctx, char *name, 
+                         cc_server_ccache_t** outCcachepp )
+{
+    return cci_context_find_ccache(ctx, name, outCcachepp);
+}
+
+
+cc_int32
+cci_context_create_ccache( cc_server_context_t* ctx, char *name, int creds_version, 
+                           char *principal, cc_server_ccache_t** outCcachepp )
+{
+    cc_server_ccache_t* ccache;
+    cc_int32 code;
+
+    if (ctx == NULL) 
+        return ccErrInvalidContext;
+    
+    if (outCcachepp == NULL)
+        return ccErrBadParam;
+
+    if (name == NULL || principal == NULL)
+        return ccErrInvalidString;
+
+    if (creds_version != cc_credentials_v4 && creds_version != cc_credentials_v5 && 
+         creds_version != cc_credentials_v4_v5)
+        return ccErrBadCredentialsVersion;
+	
+    code = cci_context_find_ccache(ctx, name, &ccache);
+    if (code == ccNoError) {
+        code = cci_ccache_set_principal(ccache, creds_version, principal);
+    } else {
+        code = cci_ccache_new(name, principal, creds_version, &ccache);
+        if (code != ccNoError)
+            return code;	/*let caller deal with error*/
+
+        ccache->mycontext = ctx;
+        ctx->changed = time(NULL);
+        cci_ccache_list_append(ctx->ccaches, ccache, NULL);
+
+        if (ctx->ccaches->head->data == (cc_uint8 *)ccache) {
+            ccache->is_default = 1;
+        }
+    }
+    *outCcachepp = ccache;
+    return ccNoError;
+}
+
+cc_int32
+cci_context_create_default_ccache( cc_server_context_t* ctx, int creds_version, 
+                                   char *principal, cc_server_ccache_t** outCcachepp )
+{
+    cc_server_ccache_t* ccache, *old_default;
+    cc_int32 code;
+
+    if (ctx == NULL) 
+        return ccErrInvalidContext;
+    
+    if (outCcachepp == NULL)
+        return ccErrBadParam;
+
+    if (principal == NULL)
+        return ccErrInvalidString;
+
+    if (creds_version != cc_credentials_v4 && creds_version != cc_credentials_v5 && 
+         creds_version != cc_credentials_v4_v5)
+        return ccErrBadCredentialsVersion;
+	
+    code = cci_context_find_ccache(ctx, cc_default_ccache_name, &ccache);
+    if (code == ccNoError) {
+        cci_ccache_set_principal(ccache, creds_version, principal);
+    } else {
+        code = cci_ccache_new(cc_default_ccache_name, principal, creds_version, &ccache);
+        if (code != ccNoError)
+            return code;	/*let caller deal with error*/
+
+        ccache->mycontext = ctx;
+        ccache->is_default = 1;
+        ctx->changed = time(NULL);
+	
+        if (ctx->ccaches->head != NULL) {
+            old_default = (cc_server_ccache_t *)ctx->ccaches->head->data;
+            old_default->is_default = 0;
+            old_default->last_default = time(NULL);
+        }
+
+        cci_ccache_list_prepend(ctx->ccaches, ccache, NULL);
+    }
+    *outCcachepp = ccache;
+    return ccNoError;
+}
+
+cc_int32
+cci_context_ccache_iterator(cc_server_context_t* ctx, cc_ccache_iterate_t** iterpp) 
+{
+    cc_ccache_iterate_t* ccache_iterator;
+    cc_int32 code;
+
+    if (ctx == NULL) 
+        return ccErrInvalidContext;
+    
+    if (iterpp == NULL)
+        return ccErrBadParam;
+
+    code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+    if (code != ccNoError)
+        return code;
+    cci_generic_list_prepend(ctx->active_iterators, ccache_iterator, sizeof(cc_ccache_iterate_t), NULL);
+
+    *iterpp = ccache_iterator;
+    return ccNoError;
+}
+
+cc_int32 
+cci_context_compare(cc_server_context_t* a, cc_server_context_t* b) 
+{
+    if (a == b)
+        return 1;
+    else
+        return 0;
+}
+
+cc_int32 
+cci_context_destroy(cc_server_context_t* ctx) 
+{
+    cc_ccache_iterate_t* ccache_iterator;
+    cc_ccache_list_node_t* ccache_node;
+    cc_server_ccache_t* ccache;
+    cc_int32 code;
+
+    if (ctx == NULL) 
+        return ccErrInvalidContext;
+
+    cci_generic_list_destroy(ctx->active_iterators);
+	
+    code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+    while (cci_ccache_iterate_has_next(ccache_iterator)) {
+        code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+        ccache = (cc_server_ccache_t *)ccache_node->data;
+        ccache_node->data = NULL;
+        cci_ccache_destroy(ccache);
+    }
+    cci_ccache_list_destroy(ctx->ccaches);
+
+    return ccNoError;
+}
+
+cc_int32 
+cci_context_rem_ccache(cc_server_context_t* ctx, cc_server_ccache_t* ccache) 
+{
+    cc_ccache_iterate_t* ccache_iterator;
+    cc_ccache_iterate_t* active_ccache_iterator;
+    cc_ccache_list_node_t* ccache_node;
+    cc_server_ccache_t* list_ccache;
+    cc_generic_list_node_t* gen_node;
+    cc_generic_iterate_t* gen_iterator;
+    cc_int32 code;
+
+    if (ctx == NULL) 
+        return ccErrInvalidContext;
+
+    if (ccache == NULL) 
+        return ccErrInvalidCCache;
+
+    code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+    while (cci_ccache_iterate_has_next(ccache_iterator)) {
+        code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+        list_ccache = (cc_server_ccache_t *)ccache_node->data;
+
+        if (list_ccache == ccache) {
+            code = cci_generic_list_iterator(ctx->active_iterators, &gen_iterator);
+            while (cci_generic_iterate_has_next(gen_iterator)) {
+                code = cci_generic_iterate_next(gen_iterator, &gen_node);
+                active_ccache_iterator = (cc_server_ccache_t *)gen_node->data;
+                if (active_ccache_iterator->next == ccache_node) {
+                    active_ccache_iterator->next = active_ccache_iterator->next->next;
+                }
+            }
+            free(gen_iterator);
+            code = cci_ccache_list_remove_element(ctx->ccaches, ccache_node);
+            break;
+        }
+    }
+    free(ccache_iterator);
+    return ccNoError;
+}
+
diff --git a/mechglue/src/lib/ccapi/server/datastore.h b/mechglue/src/lib/ccapi/server/datastore.h
new file mode 100644
index 000000000..a92c60636
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/datastore.h
@@ -0,0 +1,231 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+/*
+ * Prototypes and data structures for datastore.
+ *
+ */
+
+
+#ifndef __CCDATASTOREH__
+#define __CCDATASTOREH__
+
+#include "CredentialsCache.h"
+#include "rpc_auth.h"
+
+enum cc_list_type {
+    generic = 0,
+    context,
+    cache,
+    credentials
+};
+
+struct cc_generic_list_node_t {
+    cc_uint8* 				data;
+    cc_uint32 	        		len;
+    struct cc_generic_list_node_t*	next;
+    struct cc_generic_list_node_t*	prev;
+};
+typedef struct cc_generic_list_node_t cc_generic_list_node_t;
+
+struct cc_generic_list_head_t {
+    enum cc_list_type                   type;
+    cc_generic_list_node_t*		head;
+    cc_generic_list_node_t*		tail; 
+};      
+typedef struct cc_generic_list_head_t cc_generic_list_head_t;
+
+
+struct cc_generic_iterate_t {
+    cc_generic_list_node_t*     	next;
+};
+typedef struct cc_generic_iterate_t cc_generic_iterate_t;
+
+typedef cc_generic_list_head_t cc_context_list_head_t;
+typedef cc_generic_list_node_t cc_context_list_node_t;
+
+typedef cc_generic_list_head_t cc_ccache_list_head_t;
+typedef cc_generic_list_node_t cc_ccache_list_node_t;
+
+typedef cc_generic_list_head_t cc_credentials_list_head_t;
+typedef cc_generic_list_node_t cc_credentials_list_node_t;
+
+struct cc_context_iterate_t {
+    cc_context_list_node_t*	next;
+};
+typedef struct cc_context_iterate_t cc_context_iterate_t;
+
+struct cc_ccache_iterate_t {
+    cc_ccache_list_node_t*	next;
+};
+typedef struct cc_ccache_iterate_t cc_ccache_iterate_t;
+
+struct cc_credentials_iterate_t {
+    cc_credentials_list_node_t*	next;
+};
+typedef struct cc_credentials_iterate_t cc_credentials_iterate_t;
+
+struct cc_lock_t {
+    cc_uint32                           read_locks;             /* count of read locks (>= 0) */
+    cc_uint32                           write_locks;            /* count of write locks (0 or 1) */
+    void *                              platform_data;          /* platform specific implementation data */
+};
+typedef struct cc_lock cc_lock_t;
+
+
+struct cc_server_context_t {
+    cc_ccache_list_head_t*		ccaches;		/*our ccaches*/
+    cc_generic_list_head_t*		active_iterators;	/*active ccache iterators*/
+    cc_int32			        api_version;		/*Version our client passed in on init (ccapi_version_X) */
+    cc_auth_info_t*			auth_info;		/*auth info passed in from RPC*/
+    cc_session_info_t*		        session_info;		/*session info passed in from RPC*/
+    cc_time_t			        changed;		/*date of last change to this context*/
+    cc_int32                            error;                  /*last error code*/
+    cc_lock_t                           locks;                  /*are we locked?*/
+};                                                              
+typedef struct cc_server_context_t cc_server_context_t;
+
+struct cc_server_ccache_t {
+    char*				name;			/*name of this ccache*/
+    char*				principal_v4;		/*v4 principal associated with this cache*/
+    char*				principal_v5;		/*v5 principal associated with this cache*/
+    cc_uint32			        versions;		/*versions of creds supported (from cc_credentials enum in CredentialsCache.h)*/
+    cc_time_t			        changed;		/*date of last change to ccache*/
+    cc_int32			        kdc_set;		/*is the KDC time offset initialized?*/
+    cc_time_t		        	kdc_offset;		/*offset of our clock relative kdc*/
+    cc_time_t			        last_default;		/*the last date when we were default*/
+    cc_int32			        is_default;		/*is this the default cred on this ccache?*/
+    cc_generic_list_head_t*		active_iterators;	/*iterators which clients have opened on this cache*/
+    cc_credentials_list_head_t*	creds;				/*list of creds stored in this ccache*/
+    cc_server_context_t*		mycontext;		/*context to which I belong*/
+    cc_lock_t                           locks;                  /*are we locked?*/
+};
+typedef struct cc_server_ccache_t cc_server_ccache_t;
+
+struct cc_server_credentials_t {
+    cc_int32			        is_default;		/*Are we the default cred? (first in list)*/
+    cc_credentials_union		creds;
+};
+typedef struct cc_server_credentials_t cc_server_credentials_t;
+
+
+/*Note: cci means Credential Cache Internal, to differentiate from exported API macros*/
+
+cc_int32 cci_generic_iterate_has_next(cc_generic_iterate_t *iterate);
+cc_int32 cci_generic_iterate_next(cc_generic_iterate_t *iterate, cc_generic_list_node_t**);
+
+cc_int32 cci_generic_list_new(cc_generic_list_head_t **);
+cc_int32 cci_generic_list_append(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t**);
+cc_int32 cci_generic_list_prepend(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t**);
+cc_int32 cci_generic_list_remove_element(cc_generic_list_head_t* head, cc_generic_list_node_t* rem);
+cc_int32 cci_generic_free_element(cc_generic_list_node_t* node);
+cc_int32 cci_generic_list_destroy(cc_generic_list_head_t* head);
+cc_int32 cci_generic_list_copy(cc_generic_list_head_t* head, cc_generic_list_head_t**);
+cc_int32 cci_generic_list_iterator(cc_generic_list_head_t *head, cc_generic_iterate_t**);
+cc_int32 cci_generic_free_iterator(cc_generic_iterate_t* iterator);
+
+cc_int32 cci_context_iterate_has_next(struct cc_context_iterate_t *iterate);
+cc_int32 cci_context_iterate_next(struct cc_context_iterate_t *iterate, cc_context_list_node_t**);
+
+cc_int32 cci_ccache_iterate_has_next(struct cc_ccache_iterate_t *iterate);
+cc_int32 cci_ccache_iterate_next(struct cc_ccache_iterate_t *iterate, cc_ccache_list_node_t**);
+
+cc_int32 cci_credentials_iterate_has_next(cc_credentials_iterate_t *iterate);
+cc_int32 cci_credentials_iterate_next(cc_credentials_iterate_t *iterate, cc_credentials_list_node_t **);
+
+cc_int32 cci_context_list_new(cc_context_list_head_t**);
+cc_int32 cci_context_list_append(cc_context_list_head_t *head, cc_server_context_t *data, cc_context_list_node_t**);
+cc_int32 cci_context_list_prepend(cc_context_list_head_t *head, cc_server_context_t *data, cc_context_list_node_t**);
+cc_int32 cci_context_list_remove_element(cc_context_list_head_t* head, cc_context_list_node_t* rem);
+cc_int32 cci_context_list_iterator(cc_context_list_head_t *head, struct cc_context_iterate_t**);
+cc_int32 cci_context_free_iterator(struct cc_context_iterate_t *iterator);
+cc_int32 cci_context_list_destroy(cc_context_list_head_t* head) ;
+cc_int32 cci_context_list_copy(cc_context_list_head_t* head, cc_context_list_head_t**);
+
+cc_int32 cci_ccache_list_new(cc_ccache_list_head_t**);
+cc_int32 cci_ccache_list_append(cc_ccache_list_head_t *head, cc_server_ccache_t *data, cc_ccache_list_node_t**);
+cc_int32 cci_ccache_list_prepend(cc_ccache_list_head_t *head, cc_server_ccache_t *data, cc_ccache_list_node_t**);
+cc_int32 cci_ccache_list_remove_element(cc_ccache_list_head_t* head, cc_ccache_list_node_t* rem);
+cc_int32 cci_ccache_list_iterator(cc_ccache_list_head_t *head, struct cc_ccache_iterate_t**);
+cc_int32 cci_ccache_free_iterator(struct cc_ccache_iterate_t *iterator);
+cc_int32 cci_ccache_list_destroy(cc_ccache_list_head_t* head) ;
+cc_int32 cci_ccache_list_copy(cc_ccache_list_head_t* head, cc_ccache_list_head_t**);
+
+
+cc_int32 cci_credentials_list_new(cc_credentials_list_head_t**);
+cc_int32 cci_credentials_list_append(cc_credentials_list_head_t *head, cc_server_credentials_t *data, cc_credentials_list_node_t**);
+cc_int32 cci_credentials_list_prepend(cc_credentials_list_head_t *head, cc_server_credentials_t *data, cc_credentials_list_node_t**);
+cc_int32 cci_credentials_list_remove_element(cc_credentials_list_head_t* head, cc_credentials_list_node_t* rem);
+cc_int32 cci_credentials_list_iterator(cc_credentials_list_head_t *head, cc_credentials_iterate_t**);
+cc_int32 cci_credentials_free_iterator(cc_credentials_iterate_t* iterator);
+cc_int32 cci_credentials_list_destroy(cc_credentials_list_head_t* head) ;
+cc_int32 cci_credentials_list_copy(cc_credentials_list_head_t* head, cc_credentials_list_head_t**) ;
+
+
+cc_int32 cci_context_new(int api_version, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_server_context_t** ) ;
+cc_int32 cci_context_get_default_ccache_name(cc_server_context_t* ctx, char **);
+cc_int32 cci_context_find_ccache(cc_server_context_t* ctx, char *name, cc_server_ccache_t**);
+cc_int32 cci_context_open_ccache(cc_server_context_t* ctx, char *name, cc_server_ccache_t** );
+cc_int32 cci_context_create_ccache(cc_server_context_t* ctx, char *name, int creds_version, char *principal, cc_server_ccache_t**);
+cc_int32 cci_context_create_default_ccache(cc_server_context_t* ctx, int creds_version, char *principal, cc_server_ccache_t**);
+cc_int32 cci_context_ccache_iterator(cc_server_context_t* ctx, cc_ccache_iterate_t**);
+cc_int32 cci_context_compare(cc_server_context_t* a, cc_server_context_t* b);
+cc_int32 cci_context_destroy(cc_server_context_t* ctx);
+cc_int32 cci_context_rem_ccache(cc_server_context_t* ctx, cc_server_ccache_t* ccache);
+
+cc_int32 cci_ccache_new(char *name, char *principal, int cred_vers, cc_server_ccache_t**);
+cc_int32 cci_ccache_check_version(const cc_server_ccache_t *ccache, const cc_credentials_union* creds, cc_uint32* compat);
+cc_int32 cci_ccache_check_principal(const cc_server_ccache_t *ccache, const cc_credentials_union* creds, cc_uint32* compat);
+cc_int32 cci_ccache_store_creds(cc_server_ccache_t *ccache, const cc_credentials_union* credentials);
+cc_int32 cci_ccache_rem_creds(cc_server_ccache_t *ccache, const cc_credentials_union* credentials);
+cc_int32 cci_ccache_move(cc_server_ccache_t *source, cc_server_ccache_t* destination);
+cc_int32 cci_ccache_get_kdc_time_offset(cc_server_ccache_t* ccache, cc_time_t* offset);
+cc_int32 cci_ccache_set_kdc_time_offset(cc_server_ccache_t* ccache, cc_time_t offset);
+cc_int32 cci_ccache_clear_kdc_time_offset(cc_server_ccache_t* ccache);
+cc_int32 cci_ccache_new_iterator(cc_server_ccache_t* ccache, cc_credentials_iterate_t** iterator);
+cc_int32 cci_ccache_get_principal(cc_server_ccache_t* ccache, cc_int32 version, char ** principal);
+cc_int32 cci_ccache_set_principal(cc_server_ccache_t* ccache, cc_int32 version, char * principal);
+cc_int32 cci_ccache_free_principal(char * principal);
+cc_int32 cci_ccache_destroy(cc_server_ccache_t* ccache);
+void	 cci_ccache_changed(cc_server_ccache_t* ccache);
+cc_int32 cci_ccache_compare(cc_server_ccache_t* ccache1, cc_server_ccache_t* ccache2, cc_uint32 *result);
+#endif /*__CCDATASTOREH__*/
diff --git a/mechglue/src/lib/ccapi/server/lists.c b/mechglue/src/lib/ccapi/server/lists.c
new file mode 100644
index 000000000..882ecb7a0
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/lists.c
@@ -0,0 +1,996 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+
+/*
+ * Lists implementation.
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+/**
+ * cci_generic_iterate_has_next()
+ *
+ * Purpose: Determine if an iterator has a next element
+ *
+ * Return:  1 if another element exists
+ *          0 if no additional elements exist
+ *
+ * Errors:  None
+ *
+ */
+cc_int32 
+cci_generic_iterate_has_next(cc_generic_iterate_t *iterate) 
+{
+    return ((iterate == NULL || iterate->next == NULL) ? 0 : 1);
+}
+
+/**
+ * cci_generic_iterate_next()
+ *
+ * Purpose: Retrieve the next element from an iterator and advance
+ *          the iterator
+ *
+ * Return:  non-NULL, the next element in the iterator
+ *          NULL, the iterator list is empty or iterator is invalid
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_iterate_next(cc_generic_iterate_t *iterator, cc_generic_list_node_t** nodepp) 
+{
+    cc_generic_list_node_t* ret;
+    
+    if (iterator == NULL || nodepp == NULL)
+        return ccErrBadParam;
+
+    ret = iterator->next;
+    if (iterator->next != NULL)
+        iterator->next = iterator->next->next;
+
+    *nodepp = ret;
+    return ccNoError;
+}
+
+/**
+ * cci_context_iterate_has_next()
+ *
+ * Purpose: Determine if a context iterator has a next element
+ *
+ * Return:  1 if another element exists
+ *          0 if no additional elements exist
+ */
+cc_int32 
+cci_context_iterate_has_next(cc_context_iterate_t *iterate) 
+{
+    if ( iterate == NULL )
+        return 0;
+    
+    return cci_generic_iterate_has_next((cc_generic_iterate_t*)iterate);
+}
+
+/**
+ * cci_context_iterate_next()
+ *
+ * Purpose: Retrieve the next element from a context iterator and advance
+ *          the iterator
+ *
+ * Return:  non-NULL, the next element in the iterator
+ *          NULL, the iterator list is empty or iterator is invalid
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_context_iterate_next(cc_context_iterate_t *iterate, cc_context_list_node_t ** nodepp)
+{
+    if ( iterate == NULL || nodepp == NULL)
+        return ccErrBadParam;
+    
+    return cci_generic_iterate_next((cc_generic_iterate_t*)iterate,(cc_context_list_node_t**)nodepp);
+}
+
+/**
+ * cci_ccache_iterate_has_next()
+ *
+ * Purpose: Determine if a cache iterator has a next element
+ *
+ * Return:  1 if another element exists
+ *          0 if no additional elements exist
+ *         -1 if error
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32 
+cci_ccache_iterate_has_next(cc_ccache_iterate_t *iterate) 
+{
+    if ( iterate == NULL )
+        return 0;
+    return cci_generic_iterate_has_next((cc_generic_iterate_t*)iterate);
+}
+
+/**
+ * cci_ccache_iterate_next()
+ * 
+ * Purpose: Retrieve the next element from a ccache iterator and advance
+ *          the iterator
+ *
+ * Return:  non-NULL, the next element in the iterator
+ *          NULL, the iterator list is empty or iterator is invalid
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_iterate_next(cc_ccache_iterate_t *iterate, cc_ccache_list_node_t ** nodepp)
+{
+    if ( iterate == NULL || nodepp == NULL)
+        return ccErrBadParam;
+    
+    return cci_generic_iterate_next((cc_generic_iterate_t*)iterate, (cc_ccache_list_node_t**)nodepp);
+}
+
+/**
+ * cci_credentials_iterate_has_next()
+ *
+ * Purpose: Determine if a credentials iterator has a next element
+ *
+ * Return:  1 if another element exists
+ *          0 if no additional elements exist
+ *         -1 if error
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32 
+cci_credentials_iterate_has_next(cc_credentials_iterate_t *iterate) 
+{
+    if ( iterate == NULL )
+        return 0;
+    
+    return cci_generic_iterate_has_next((cc_generic_iterate_t*)iterate);
+}
+
+/**
+ * cci_credentials_iterate_next()
+ * 
+ * Purpose: Retrieve the next element from a credentials iterator and advance
+ *          the iterator
+ *
+ * Return:  non-NULL, the next element in the iterator
+ *          NULL, the iterator list is empty or iterator is invalid
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_iterate_next(cc_credentials_iterate_t *iterate, cc_credentials_list_node_t** nodepp) 
+{
+    if ( iterate == NULL || nodepp == NULL )
+        return ccErrBadParam;
+    return cci_generic_iterate_next((cc_generic_iterate_t*)iterate, (cc_credentials_list_node_t**)nodepp);
+}
+
+/**
+ * cci_generic_list_new()
+ *
+ * Purpose: Allocate new generic list
+ *
+ * Return:  non-NULL, an empty list
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ *
+ */
+cc_int32
+cci_generic_list_new(cc_generic_list_head_t ** listpp) 
+{
+    cc_generic_list_head_t* ret = (cc_generic_list_head_t *)malloc(sizeof(cc_generic_list_head_t));
+    if (ret == NULL)
+        return ccErrNoMem;
+	
+	ret->type = generic;
+    ret->head = ret->tail = NULL;
+    *listpp = ret;
+
+    return ccNoError;
+}
+
+/**
+ * cci_generic_list_append()
+ *
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data' 
+ *
+ * Return:  non-NULL, a pointer to the newly allocated node
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_list_append(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t** nodepp) 
+{
+    cc_generic_list_node_t* new_node;
+
+    if ( data == NULL || len == 0 )
+        return ccErrBadParam;
+
+    new_node = (cc_generic_list_node_t *)malloc(sizeof(cc_generic_list_node_t));
+    if (new_node == NULL)
+        return ccErrNoMem;
+
+    new_node->data = malloc(len);
+    if ( new_node->data == NULL ) {
+        free(new_node);
+        return ccErrNoMem;         
+    }
+    
+    memcpy(new_node->data,data,len);
+    new_node->len = len;
+
+    if (head->head == NULL) { /*empty list*/
+        head->head = new_node;
+        head->tail = new_node;
+	    new_node->next = new_node->prev = NULL;
+    } else {
+        new_node->prev = head->tail;
+        head->tail->next = new_node;
+        head->tail = new_node;
+		new_node->next = NULL;
+    }
+	if (nodepp != NULL)
+	    *nodepp = new_node;
+    return ccNoError;
+}
+
+/**
+ * cci_generic_list_prepend()
+ *
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return:  non-NULL, a pointer to the newly allocated node
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem, ccErrBadParam
+ *
+ */
+cc_int32 
+cci_generic_list_prepend(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t** nodepp) 
+{
+    cc_generic_list_node_t* new_node;
+
+    if ( data == NULL || len == 0 )
+        return ccErrBadParam;
+
+    new_node = (cc_generic_list_node_t *)malloc(sizeof(cc_generic_list_node_t));
+    if (new_node == NULL)
+        return ccErrNoMem;
+
+    new_node->data = malloc(len);
+    if ( new_node->data == NULL ) {
+        free(new_node);
+        return ccErrNoMem;
+    }
+    
+    memcpy(new_node->data,data,len);
+    new_node->len = len;
+	
+    if (head->head == NULL) { /*empty list*/
+        head->head = new_node;
+        head->tail = new_node;
+        new_node->prev = new_node->next = NULL;
+    } else {
+        new_node->next = head->head;
+        head->head->prev = new_node;
+        new_node->prev = NULL;
+        head->head = new_node;
+    }
+
+	if (nodepp != NULL)
+		*nodepp = new_node;
+
+    return ccNoError;
+}
+
+/**
+ * cci_generic_list_remove_element()
+ *
+ * Purpose: Remove a node from the list
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32 
+cci_generic_list_remove_element(cc_generic_list_head_t* head, cc_generic_list_node_t* rem) 
+{
+    if (head->head == NULL || rem == NULL)
+        return ccErrBadParam;
+
+    if (head->head == rem && head->tail == rem) { /*removing only element of list*/
+        head->head = head->tail = NULL;
+    } else if (head->head == rem) { /*removing head*/
+        head->head = head->head->next;
+    } else if (head->tail == rem) { /*removing tail*/
+        head->tail = head->tail->prev;
+        head->tail->next = NULL;
+    } else {
+        rem->prev->next = rem->next;
+        rem->next->prev = rem->prev;
+    }
+    free(rem);
+    return ccNoError;
+}
+
+/**
+ * cci_generic_free_element()
+ *
+ * Purpose: Free the memory associated with a node
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_free_element(cc_generic_list_node_t* node)
+{
+    if ( node == NULL )
+        return ccErrBadParam;
+
+    if ( node->data ) {
+        free(node->data);
+        node->data = NULL;
+    }
+    node->len = 0;
+    node->next = node->prev = NULL;
+    free(node);
+    return ccNoError;
+}
+
+
+/**
+ * cci_generic_list_destroy()
+ *
+ * Purpose: Deallocate a list and all of its contents
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ */
+cc_int32
+cci_generic_list_destroy(cc_generic_list_head_t* head) 
+{
+    cc_generic_list_node_t *cur, *next;
+    cc_int32 ret = ccNoError;
+
+    if ( head == NULL )
+        return ccErrBadParam;
+	
+    for (cur = head->head; ret == ccNoError && cur != NULL; cur = next) {
+        next = cur->next;
+        ret = cci_generic_free_element(cur);
+    }       
+    free(head);
+    return(ret);
+}
+
+/**
+ * cci_context_list_destroy()
+ *
+ * Purpose: Deallocate a list and all of its contents
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ */
+cc_int32
+cci_context_list_destroy(cc_context_list_head_t* head) 
+{
+    return cci_generic_list_destroy((cc_generic_list_head_t*)head);
+}
+
+/**
+ * cci_ccache_list_destroy()
+ *
+ * Purpose: Deallocate a list and all of its contents
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ */
+cc_int32
+cci_ccache_list_destroy(cc_ccache_list_head_t* head) 
+{
+    return cci_generic_list_destroy((cc_generic_list_head_t*)head);
+}
+
+/**
+ * cci_credentials_list_destroy()
+ *
+ * Purpose: Deallocate a list and all of its contents
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ */
+cc_int32
+cci_credentials_list_destroy(cc_credentials_list_head_t* head) 
+{
+    return cci_generic_list_destroy((cc_generic_list_head_t*)head);
+}
+
+/**
+ * cci_generic_list_copy()
+ *
+ * Purpose: Copy a list
+ *
+ * Return:  non-NULL, a new list
+ *          NULL, failure
+ *
+ * Errors:  ccErrBadParam, ccErrNoMem
+ *
+ */
+cc_int32
+cci_generic_list_copy(cc_generic_list_head_t* head, cc_generic_list_head_t** headpp) 
+{
+    cc_generic_list_head_t* copy;
+    cc_generic_list_node_t *src_node, *dst_node;
+    cc_int32 code;
+
+    if (head == NULL || headpp == NULL)
+        return ccErrBadParam;
+
+    code = cci_generic_list_new(©);
+    if (code != ccNoError)
+        return code;
+
+    for (src_node = head->head; src_node != NULL; src_node = src_node->next) {
+        code = cci_generic_list_append(copy, src_node->data, src_node->len, &dst_node);
+        if (code != ccNoError) {
+            cci_generic_list_destroy(copy);
+            return code;
+        }
+    }
+    *headpp = copy;
+    return ccNoError;
+}
+
+/**
+ * cci_context_list_copy()
+ *
+ * Purpose: Copy a list
+ *
+ * Return:  non-NULL, a new list
+ *          NULL, failure
+ *
+ * Errors:  ccErrBadParam, ccErrNoMem
+ *
+ */
+cc_int32
+cci_context_list_copy(cc_context_list_head_t* head, cc_context_list_head_t** headpp ) 
+{
+    return cci_generic_list_copy((cc_generic_list_head_t*)head, (cc_context_list_head_t **)headpp);
+}
+
+/**
+ * cci_ccache_list_copy()
+ *
+ * Purpose: Copy a list
+ *
+ * Return:  non-NULL, a new list
+ *          NULL, failure
+ *
+ * Errors:  ccErrBadParam, ccErrNoMem
+ */
+cc_int32
+cci_ccache_list_copy(cc_ccache_list_head_t* head, cc_ccache_list_head_t** headpp)
+{
+    return cci_generic_list_copy((cc_generic_list_head_t*)head, (cc_ccache_list_head_t **)headpp);
+}
+
+/**
+ * cci_credentials_list_copy()
+ *
+ * Purpose: Copy a list
+ *
+ * Return:  non-NULL, a new list
+ *          NULL, failure
+ *
+ * Errors:  ccErrBadParam, ccErrNoMem
+ *
+ */
+cc_int32
+cci_credentials_list_copy(cc_credentials_list_head_t* head, cc_credentials_list_head_t** headpp) 
+{
+    return cci_generic_list_copy((cc_generic_list_head_t*)head, (cc_credentials_list_head_t **)headpp);
+}
+
+
+/**
+ * cci_generic_list_iterator()
+ *
+ * Purpose: Allocate an iterator for the specified list
+ *
+ * Return:  non-NULL, an iterator
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ *
+ */
+cc_int32
+cci_generic_list_iterator(cc_generic_list_head_t *head, cc_generic_iterate_t** headpp) 
+{
+    cc_generic_iterate_t* iterator;
+
+    if ( head == NULL || headpp == NULL )
+        return ccErrBadParam;
+
+    iterator = (cc_generic_iterate_t*)malloc(sizeof(cc_generic_iterate_t));
+    if (iterator == NULL)
+        return ccErrNoMem;
+    
+    iterator->next = head->head;
+    *headpp = iterator;
+    return ccNoError;
+}
+
+/**
+ * cci_generic_free_iterator()
+ *
+ * Purpose: Deallocate memory associated with an iterator
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_free_iterator(cc_generic_iterate_t* iterator)
+{
+    if ( iterator == NULL )
+        return ccErrBadParam;
+
+    iterator->next = NULL;
+    free(iterator);
+    return ccNoError;
+}
+
+
+/**
+ * cci_context_list_new()
+ *
+ * Purpose: Allocate a new context list
+ *
+ * Return:  non-NULL, a new list
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ *
+ */
+cc_int32
+cci_context_list_new(cc_context_list_head_t ** headpp) 
+{
+    cc_context_list_head_t *ret;
+    
+    if ( headpp == NULL )
+        return ccErrBadParam;
+
+    ret = (cc_context_list_head_t *)malloc(sizeof(cc_context_list_head_t));
+    if (ret == NULL)
+        return ccErrNoMem;
+    ret->head = ret->tail = NULL;
+    *headpp = ret;
+    return ccNoError;
+}
+
+/**
+ * cci_context_list_append()
+ *
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data' 
+ *
+ * Return:  non-NULL, a pointer to the newly allocated node
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_context_list_append(cc_context_list_head_t *head, cc_server_context_t *data, cc_context_list_node_t** nodepp) 
+{
+    return cci_generic_list_append((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_context_t), (cc_context_list_node_t**)nodepp);
+}
+
+/**
+ * cci_context_list_prepend()
+ *
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data' 
+ *
+ * Return:  non-NULL, a pointer to the newly allocated node
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_context_list_prepend(cc_context_list_head_t *head, cc_server_context_t *data, cc_context_list_node_t** nodepp ) 
+{
+    return cci_generic_list_prepend((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_context_t), (cc_context_list_node_t**)nodepp);
+}
+
+/**
+ * cci_context_list_remove_element
+ *
+ * Purpose: Remove a node from the list
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ */
+cc_int32
+cci_context_list_remove_element(cc_context_list_head_t* head, cc_context_list_node_t* rem) 
+{
+    return cci_generic_list_remove_element((cc_generic_list_head_t*)head, (cc_generic_list_node_t*)rem);
+}
+
+/**
+ * cci_context_list_iterator()
+ *
+ * Purpose: Allocate an iterator for the specified list
+ *
+ * Return:  non-NULL, an iterator
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ *
+ */
+cc_int32
+cci_context_list_iterator(cc_context_list_head_t *head, cc_context_iterate_t** iterpp) 
+{
+    cc_context_iterate_t* iterator;
+    
+    if ( head == NULL || iterpp == NULL )
+        return ccErrBadParam;
+
+    iterator = (cc_context_iterate_t*)malloc(sizeof(cc_context_iterate_t));
+    if (iterator == NULL)
+        return ccErrNoMem;
+
+    iterator->next = head->head;
+    *iterpp = iterator;
+    return ccNoError;
+}
+
+/**
+ * cci_context_free_iterator()
+ *
+ * Purpose: Deallocate memory associated with an iterator
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_context_free_iterator(cc_context_iterate_t* iterator)
+{
+    if ( iterator == NULL )
+        return ccErrBadParam;
+
+    iterator->next = NULL;
+    free(iterator);
+    return ccNoError;
+}
+
+/**
+ * cci_ccache_list_new()
+ *
+ * Purpose: Allocate a new ccache list
+ *
+ * Return:  non-NULL, a new list
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ */
+cc_int32
+cci_ccache_list_new(cc_ccache_list_head_t ** listpp)
+{
+    cc_ccache_list_head_t *ret;
+    
+    if ( listpp == NULL )
+        return ccErrBadParam;
+
+    ret = (cc_ccache_list_head_t *)malloc(sizeof(cc_ccache_list_head_t));
+    if (ret == NULL)
+        return ccErrNoMem;
+
+    ret->head = ret->tail = NULL;
+    *listpp = ret;
+    return ccNoError;
+}
+
+/**
+ * cci_ccache_list_append()
+ *
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data' 
+ *
+ * Return:  non-NULL, a pointer to the newly allocated node
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_list_append(cc_ccache_list_head_t *head, cc_server_ccache_t *data, cc_ccache_list_node_t** nodepp) 
+{
+    return cci_generic_list_append((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_ccache_t), (cc_ccache_list_node_t**)nodepp);
+}
+
+/**
+ * cci_ccache_list_prepend()
+ *
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data' 
+ *
+ * Return:  non-NULL, a pointer to the newly allocated node
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_list_prepend(cc_ccache_list_head_t *head, cc_server_ccache_t *data, cc_ccache_list_node_t** nodepp) 
+{
+    return cci_generic_list_prepend((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_ccache_t), (cc_ccache_list_node_t**)nodepp);
+}
+
+/**
+ * cci_ccache_list_remove_element()
+ *
+ * Purpose: Remove a node from the list
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_list_remove_element(cc_ccache_list_head_t* head, cc_ccache_list_node_t* rem) 
+{
+    return cci_generic_list_remove_element((cc_generic_list_head_t*)head, (cc_generic_list_node_t*)rem);
+}
+
+/**
+ * cci_ccache_list_iterator()
+ *
+ * Purpose: Allocate an iterator for the specified list
+ *
+ * Return:  non-NULL, an iterator
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ *
+ */
+cc_int32
+cci_ccache_list_iterator(cc_ccache_list_head_t *head, cc_ccache_iterate_t** iterpp) 
+{
+    cc_ccache_iterate_t* iterator;
+    
+    if ( head == NULL || iterpp == NULL )
+        return ccErrBadParam;
+
+    iterator = (cc_ccache_iterate_t*)malloc(sizeof(cc_ccache_iterate_t));
+    if (iterator == NULL)
+        return ccErrNoMem;
+
+    iterator->next = head->head;
+    *iterpp = iterator;
+    return ccNoError;
+}
+
+/**
+ * cci_ccache_free_iterator()
+ *
+ * Purpose: Deallocate memory associated with an iterator
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_free_iterator(cc_ccache_iterate_t* iterator)
+{
+    if ( iterator == NULL )
+        return ccErrBadParam;
+
+    iterator->next = NULL;
+    free(iterator);
+    return ccNoError;
+}
+
+/**
+ * cci_credentials_list_new()
+ *
+ * Purpose: Allocate a new ccache list
+ *
+ * Return:  non-NULL, a new list
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ *
+ */
+cc_int32
+cci_credentials_list_new(cc_credentials_list_head_t ** list) 
+{
+    if ( list == NULL )
+        return ccErrBadParam;
+
+    *list = (cc_credentials_list_head_t *)malloc(sizeof(cc_credentials_list_head_t));
+    if (*list == NULL)
+        return ccErrNoMem;
+
+    (*list)->head = (*list)->tail = NULL;
+    return ccNoError;
+}
+
+/**
+ * cci_credentials_list_append()
+ *
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data' 
+ *
+ * Return:  non-NULL, a pointer to the newly allocated node
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_list_append(cc_credentials_list_head_t *head, cc_server_credentials_t *data, cc_credentials_list_node_t** nodepp ) 
+{
+    return cci_generic_list_append((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_credentials_t), (cc_credentials_list_node_t**)nodepp);
+}
+
+/**
+ * cci_credentials_list_prepend()
+ *
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data' 
+ *
+ * Return:  non-NULL, a pointer to the newly allocated node
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_list_prepend(cc_credentials_list_head_t *head, cc_server_credentials_t *data, cc_credentials_list_node_t** nodepp) 
+{
+    return cci_generic_list_prepend((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_credentials_t), (cc_credentials_list_node_t**)nodepp);
+}
+
+/**
+ * cci_credentials_list_remove_element()
+ *
+ * Purpose: Remove a node from the list
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32 
+cci_credentials_list_remove_element(cc_credentials_list_head_t* head, cc_credentials_list_node_t* rem) 
+{
+    return cci_generic_list_remove_element((cc_generic_list_head_t*)head, (cc_generic_list_node_t*)rem);
+}
+
+/**
+ * cci_credentials_list_iterator()
+ *
+ * Purpose: Allocate an iterator for the specified list
+ *
+ * Return:  non-NULL, an iterator
+ *          NULL, failure
+ *
+ * Errors:  ccErrNoMem
+ *
+ */
+cc_int32
+cci_credentials_list_iterator(cc_credentials_list_head_t *head, cc_credentials_iterate_t** iterpp) 
+{
+    cc_credentials_iterate_t* iterator;
+    
+    if ( head == NULL || iterpp == NULL )
+        return ccErrBadParam;
+
+    iterator = (cc_credentials_iterate_t*)malloc(sizeof(cc_credentials_iterate_t));
+    if (iterator == NULL)
+        return ccErrNoMem;
+
+    iterator->next = head->head;
+    *iterpp = iterator;
+    return ccNoError;
+}
+
+/**
+ * cci_credentials_free_iterator()
+ *
+ * Purpose: Deallocate memory associated with an iterator
+ *
+ * Return:  0, success
+ *         -1, failure
+ *
+ * Errors:  ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_free_iterator(cc_credentials_iterate_t* iterator)
+{
+    if ( iterator == NULL )
+        return ccErrBadParam;
+
+    iterator->next = NULL;
+    free(iterator);
+    return ccNoError;
+}
+
diff --git a/mechglue/src/lib/ccapi/server/mac/ChangeLog b/mechglue/src/lib/ccapi/server/mac/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/mac/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/server/rpc_auth.c b/mechglue/src/lib/ccapi/server/rpc_auth.c
new file mode 100644
index 000000000..dd338e010
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/rpc_auth.c
@@ -0,0 +1,63 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Stubs for rpc_auth.
+ */
+
+#include "CredentialsCache.h"
+#include "rpc_auth.h"
+
+cc_int32 
+cci_rpc_is_authorized( cc_auth_info_t* msg_auth, cc_session_info_t* msg_session, cc_auth_info_t* stored_auth, 
+                       cc_session_info_t* stored_session, cc_uint32 * authorizedp) 
+{
+    if (msg_auth == stored_auth && msg_session == stored_session)
+        *authorizedp = 1;
+    else
+        *authorizedp = 0;
+
+    return ccNoError;
+}
+
+
diff --git a/mechglue/src/lib/ccapi/server/rpc_auth.h b/mechglue/src/lib/ccapi/server/rpc_auth.h
new file mode 100644
index 000000000..21d7db501
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/rpc_auth.h
@@ -0,0 +1,71 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+
+/*
+ * Types for RPC auth + session info
+ *
+ */
+
+#ifndef __RPC_AUTH_H__
+#define __RPC_AUTH_H__
+
+#include "CredentialsCache.h"
+
+/*preliminary*/
+struct cc_auth_info_t {
+    cc_uint8 *info;
+    cc_uint32  len;
+};
+typedef struct cc_auth_info_t cc_auth_info_t;
+
+/*preliminary*/
+struct cc_session_info_t {
+    cc_uint8 *info;
+    cc_uint32  len;
+};
+typedef struct cc_session_info_t cc_session_info_t;
+
+cc_int32 cci_rpc_is_authorized(cc_auth_info_t* msg_auth, cc_session_info_t* msg_session, cc_auth_info_t* stored_auth, cc_session_info_t* stored_session, cc_uint32 *authorizedp);
+
+#endif /*__RPC_AUTH_H__*/
diff --git a/mechglue/src/lib/ccapi/server/serv_ops.c b/mechglue/src/lib/ccapi/server/serv_ops.c
new file mode 100644
index 000000000..30a108a34
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/serv_ops.c
@@ -0,0 +1,1500 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Server side implementation of each API function.
+ */
+
+#include "CredentialsCache.h"
+#include "serv_ops.h"
+#include "datastore.h"
+#include "rpc_auth.h"
+#include "msg_headers.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+cc_context_list_head_t* AllContexts = NULL;
+type_to_op_mapping_t* TypeToOpMapping = NULL;
+
+extern int cc_err_code;
+extern int cc_myversion;
+extern char cc_vendor[];
+
+cc_int32 
+cci_serv_initialize(void) 
+{
+    cc_int32 code;
+
+    code = cci_context_list_new(&AllContexts);
+    if ( code != ccNoError )
+        return code;
+    TypeToOpMapping = (type_to_op_mapping_t*)malloc(sizeof(type_to_op_mapping_t));
+    if (TypeToOpMapping == NULL) {
+        cci_context_list_destroy(AllContexts);
+        return ccErrNoMem;
+    }
+
+    TypeToOpMapping->operations[ccmsg_INIT] = ccop_INIT;
+    TypeToOpMapping->operations[ccmsg_CTX_RELEASE] = ccop_CTX_RELEASE;
+    TypeToOpMapping->operations[ccmsg_CTX_GET_CHANGE_TIME] = ccop_CTX_GET_CHANGE_TIME;
+    TypeToOpMapping->operations[ccmsg_CTX_GET_DEFAULT_CCACHE_NAME] = ccop_CTX_GET_DEFAULT_CCACHE_NAME;
+    TypeToOpMapping->operations[ccmsg_CTX_COMPARE] = ccop_CTX_COMPARE;
+    TypeToOpMapping->operations[ccmsg_CTX_NEW_CCACHE_ITERATOR] = ccop_CTX_NEW_CCACHE_ITERATOR;
+    TypeToOpMapping->operations[ccmsg_CTX_LOCK] = ccop_CTX_LOCK;
+    TypeToOpMapping->operations[ccmsg_CTX_UNLOCK] = ccop_CTX_UNLOCK;
+    TypeToOpMapping->operations[ccmsg_CTX_CLONE] = ccop_CTX_CLONE;
+    TypeToOpMapping->operations[ccmsg_CCACHE_OPEN] = ccop_CCACHE_OPEN;
+    TypeToOpMapping->operations[ccmsg_CCACHE_OPEN_DEFAULT] = ccop_CCACHE_OPEN_DEFAULT;
+    TypeToOpMapping->operations[ccmsg_CCACHE_CREATE] = ccop_CCACHE_CREATE;
+    TypeToOpMapping->operations[ccmsg_CCACHE_CREATE_DEFAULT] = ccop_CCACHE_CREATE_DEFAULT;
+    TypeToOpMapping->operations[ccmsg_CCACHE_CREATE_UNIQUE] = ccop_CCACHE_CREATE_UNIQUE;
+    TypeToOpMapping->operations[ccmsg_CCACHE_RELEASE] = ccop_CCACHE_RELEASE;
+    TypeToOpMapping->operations[ccmsg_CCACHE_DESTROY] = ccop_CCACHE_DESTROY;
+    TypeToOpMapping->operations[ccmsg_CCACHE_SET_DEFAULT] = ccop_CCACHE_SET_DEFAULT;
+    TypeToOpMapping->operations[ccmsg_CCACHE_GET_CREDS_VERSION] = ccop_CCACHE_GET_CREDS_VERSION;
+    TypeToOpMapping->operations[ccmsg_CCACHE_GET_NAME] = ccop_CCACHE_GET_NAME;
+    TypeToOpMapping->operations[ccmsg_CCACHE_GET_PRINCIPAL] = ccop_CCACHE_GET_PRINCIPAL;
+    TypeToOpMapping->operations[ccmsg_CCACHE_SET_PRINCIPAL] = ccop_CCACHE_SET_PRINCIPAL;
+    TypeToOpMapping->operations[ccmsg_CCACHE_CREDS_ITERATOR] = ccop_CCACHE_CREDS_ITERATOR;
+    TypeToOpMapping->operations[ccmsg_CCACHE_STORE_CREDS] = ccop_CCACHE_STORE_CREDS;
+    TypeToOpMapping->operations[ccmsg_CCACHE_REM_CREDS] = ccop_CCACHE_REM_CREDS;
+    TypeToOpMapping->operations[ccmsg_CCACHE_GET_LAST_DEFAULT_TIME] = ccop_CCACHE_GET_LAST_DEFAULT_TIME;
+    TypeToOpMapping->operations[ccmsg_CCACHE_GET_CHANGE_TIME] = ccop_CCACHE_GET_CHANGE_TIME;
+    TypeToOpMapping->operations[ccmsg_CCACHE_COMPARE] = ccop_CCACHE_COMPARE;
+    TypeToOpMapping->operations[ccmsg_CCACHE_GET_KDC_TIME_OFFSET] = ccop_CCACHE_GET_KDC_TIME_OFFSET;
+    TypeToOpMapping->operations[ccmsg_CCACHE_SET_KDC_TIME_OFFSET] = ccop_CCACHE_SET_KDC_TIME_OFFSET;
+    TypeToOpMapping->operations[ccmsg_CCACHE_CLEAR_KDC_TIME_OFFSET] = ccop_CCACHE_CLEAR_KDC_TIME_OFFSET;
+    TypeToOpMapping->operations[ccmsg_CCACHE_ITERATOR_RELEASE] = ccop_CCACHE_ITERATOR_RELEASE;
+    TypeToOpMapping->operations[ccmsg_CCACHE_ITERATOR_NEXT] = ccop_CCACHE_ITERATOR_NEXT;
+    TypeToOpMapping->operations[ccmsg_CREDS_ITERATOR_RELEASE] = ccop_CREDS_ITERATOR_RELEASE;
+    TypeToOpMapping->operations[ccmsg_CREDS_ITERATOR_NEXT] = ccop_CREDS_ITERATOR_NEXT;
+    TypeToOpMapping->operations[ccmsg_CREDS_RELEASE] = ccop_CREDS_RELEASE;
+
+    return ccNoError;
+};
+
+cc_int32 
+cci_serv_process_msg(cc_msg_t * msg, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** resp_msg) 
+{
+    cc_server_context_t* ctx;
+    ccmsg_ctx_only_t* header = (ccmsg_ctx_only_t *)msg->header;
+    cc_int32 code;
+
+    if (msg == NULL || msg->header == NULL || auth_info == NULL || session_info == NULL)
+        return ccErrBadParam;
+
+    if (AllContexts == NULL) {
+        code = cci_serv_initialize();
+        if ( code != ccNoError )
+            return code;
+    }
+	
+    if (msg->type == ccmsg_INIT) {
+        return TypeToOpMapping->operations[msg->type] (NULL, auth_info, session_info, msg, resp_msg);
+    } else {
+        if (msg->header_len < sizeof(ccmsg_ctx_only_t)) {
+            return ccErrBadParam;
+        }
+
+        code = cci_serv_find_ctx_by_handle(header->ctx, auth_info, session_info, &ctx);
+        if (code != ccNoError) {
+            cci_serv_make_nack(ccErrContextNotFound, auth_info, session_info, resp_msg);
+            return code;
+        }
+        return TypeToOpMapping->operations[msg->type] (ctx, auth_info, session_info, msg, resp_msg);
+    }
+}
+
+/*deprecated*/
+cc_int32
+cci_serv_find_ctx(cc_auth_info_t* auth_info, cc_session_info_t* session_info,
+                  cc_server_context_t** ctxpp)
+{
+    cc_context_iterate_t* ctx_iterator;
+    cc_context_list_node_t* ctx_node;
+    cc_server_context_t* ctx;
+    cc_int32 code;
+    cc_uint32 authorized;
+
+    code = cci_context_list_iterator(AllContexts, &ctx_iterator);
+    if (code != ccNoError)
+        return code;
+
+    while (cci_context_iterate_has_next(ctx_iterator)) {
+        code = cci_context_iterate_next(ctx_iterator, &ctx_node);
+        if (code != ccNoError) {
+            cci_context_free_iterator(ctx_iterator);
+            return code;
+        }
+        ctx = (cc_server_context_t *)ctx_node->data;
+        code = cci_rpc_is_authorized(auth_info, session_info, ctx->auth_info, ctx->session_info, &authorized);
+        if (code != ccNoError) {
+            cci_context_free_iterator(ctx_iterator);
+            return code;
+        }
+
+        if (authorized) {
+            cci_context_free_iterator(ctx_iterator);
+            *ctxpp = ctx;
+            return ccNoError;
+        }
+    }
+    cci_context_free_iterator(ctx_iterator);
+    return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_find_ctx_by_handle(cc_handle ctx_num, cc_auth_info_t* auth, cc_session_info_t* session, cc_server_context_t** ctxpp) 
+{
+    cc_server_context_t* input_ctx = (cc_server_context_t*)ctx_num;
+    cc_context_iterate_t* ctx_iterator;
+    cc_context_list_node_t* ctx_node;
+    cc_server_context_t* ctx;
+    cc_uint32 authorized;
+    cc_int32 code;
+
+    code = cci_context_list_iterator(AllContexts, &ctx_iterator);
+    if (code != ccNoError)
+        return code;
+
+    while (cci_context_iterate_has_next(ctx_iterator)) {
+        code = cci_context_iterate_next(ctx_iterator, &ctx_node);
+        ctx = (cc_server_context_t *)ctx_node->data;
+        if (code != ccNoError) {
+            cci_context_free_iterator(ctx_iterator);
+            return code;
+        }
+
+        code = cci_rpc_is_authorized(auth, session, ctx->auth_info, ctx->session_info, &authorized);
+        if (code != ccNoError) {
+            cci_context_free_iterator(ctx_iterator);
+            return code;
+        }
+
+        if (ctx == input_ctx && authorized) {
+            cci_context_free_iterator(ctx_iterator);
+            *ctxpp = ctx;
+            return ccNoError;
+        }
+    }
+    cci_context_free_iterator(ctx_iterator);
+    return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_find_ccache_by_handle(cc_server_context_t* ctx, cc_handle ccache, cc_server_ccache_t** ccachepp ) 
+{
+    cc_ccache_iterate_t* ccache_iterator;
+    cc_ccache_list_node_t* ccache_node;
+    cc_server_ccache_t* stored_ccache;
+    cc_server_ccache_t* target_ccache = (cc_server_ccache_t*)ccache;
+    cc_int32 code;
+
+    code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+    if (code != ccNoError)
+        return code;
+
+    while (cci_ccache_iterate_has_next(ccache_iterator)) {
+        code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+        if (code != ccNoError) {
+            cci_ccache_free_iterator(ccache_iterator);
+            return code;
+        }
+
+        stored_ccache = (cc_server_ccache_t *)ccache_node->data;
+	
+        if (stored_ccache == target_ccache) {
+            cci_ccache_free_iterator(ccache_iterator);
+            *ccachepp = stored_ccache;
+            return ccNoError;
+        }
+    }
+    cci_ccache_free_iterator(ccache_iterator);
+    return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_find_ccache_iterator_by_handle(cc_server_context_t* ctx, cc_handle iterator, cc_generic_list_node_t** nodepp ) 
+{
+    cc_generic_iterate_t* gen_iterator;
+    cc_generic_list_node_t* gen_node;
+    cc_ccache_iterate_t* stored_iterator;
+    cc_ccache_iterate_t* target_iterator = (cc_ccache_iterate_t*)iterator;
+    cc_int32 code;
+
+    code = cci_generic_list_iterator(ctx->active_iterators, &gen_iterator);
+    if (code != ccNoError) 
+        return code;
+
+    while (cci_generic_iterate_has_next(gen_iterator)) {
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);
+        if (code != ccNoError) {
+            cci_generic_free_iterator(gen_iterator);
+            return code;
+        }
+
+        stored_iterator = (cc_ccache_iterate_t *)gen_node->data;
+        if (stored_iterator == target_iterator) {
+            cci_generic_free_iterator(gen_iterator);
+            *nodepp = gen_node;
+            return ccNoError;
+        }
+    }
+    cci_generic_free_iterator(gen_iterator);
+    return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_find_creds_iterator_by_handle(cc_server_ccache_t* ccache, cc_handle iterator, cc_generic_list_node_t** nodepp) 
+{
+    cc_generic_iterate_t* gen_iterator;
+    cc_generic_list_node_t* gen_node;
+    cc_ccache_iterate_t* stored_iterator;
+    cc_ccache_iterate_t* target_iterator = (cc_ccache_iterate_t*)iterator;
+    cc_int32 code;
+
+    code = cci_generic_list_iterator(ccache->active_iterators, &gen_iterator);
+    if (code != ccNoError)
+        return code;
+
+    while (cci_generic_iterate_has_next(gen_iterator)) {
+        code = cci_generic_iterate_next(gen_iterator, &gen_node);
+        if (code != ccNoError) {
+            cci_generic_free_iterator(gen_iterator);
+            return code;
+        }
+
+        stored_iterator = (cc_ccache_iterate_t *)gen_node->data;
+        if (stored_iterator == target_iterator) {
+            cci_generic_free_iterator(gen_iterator);
+            *nodepp = gen_node;
+            return ccNoError;
+        }
+    }
+    cci_generic_free_iterator(gen_iterator);
+    return ccIteratorEnd;
+}       
+
+cc_int32 
+cci_serv_make_nack(cc_int32 err_code, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** resp_msg) 
+{
+    ccmsg_nack_t* nack_header;
+    cc_int32 code;
+
+    code = cci_msg_new(ccmsg_NACK, resp_msg);
+    if (code != ccNoError) 
+        return code;
+
+    nack_header = (ccmsg_nack_t*)malloc(sizeof(ccmsg_nack_t));
+    if (nack_header == NULL) {
+        cci_msg_destroy(*resp_msg);
+        *resp_msg = 0;
+        return ccErrNoMem;
+    }
+
+    nack_header->err_code = err_code;;
+    code = cci_msg_add_header(*resp_msg, nack_header, sizeof(ccmsg_nack_t));
+    if (code != ccNoError) {
+        cci_msg_destroy(*resp_msg);
+        *resp_msg = 0;
+        return code;
+    }
+
+    return ccNoError;
+}
+
+cc_int32 
+cci_serv_make_ack(void * header, cc_int32 header_len, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** resp_msg) 
+{
+    cc_int32 code;
+
+    code = cci_msg_new(ccmsg_ACK, resp_msg);
+    if (code != ccNoError)
+        return code;
+
+    if (header != NULL) {
+        code = cci_msg_add_header(*resp_msg, header, header_len);
+        if (code != ccNoError) {
+            cci_msg_destroy(*resp_msg);
+            resp_msg = 0;
+            return code;
+        }
+    }
+    return ccNoError;
+}
+
+cc_int32 
+ccop_INIT( cc_server_context_t* ctx,            /* not used */
+           cc_auth_info_t* auth_info,
+           cc_session_info_t* session_info,
+           cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    cc_uint32 blob_pos;
+    cc_server_context_t *new_ctx;
+    ccmsg_init_resp_t *resp_header;
+    ccmsg_init_t *header = (ccmsg_init_t *)msg->header;
+    cc_context_list_node_t* ctx_node;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_init_t)) {
+        return ccErrBadParam;
+    }
+
+    code = cci_context_new(header->in_version, auth_info, session_info, &new_ctx);
+    if (code != ccNoError) {
+        return code;
+    }
+
+    code = cci_context_list_append(AllContexts, ctx, &ctx_node);
+    if (code != ccNoError) {
+        cci_context_destroy(new_ctx);
+        return code;
+    }
+
+    resp_header = (ccmsg_init_resp_t*)malloc(sizeof(ccmsg_init_resp_t));
+    if (resp_header == NULL) {
+        cci_context_destroy(new_ctx);
+        return ccErrNoMem;
+    }
+
+    code = cci_msg_new(ccmsg_ACK, resp_msg);
+    if (code != ccNoError) {
+        free(resp_header);
+        cci_context_destroy(new_ctx);
+        return code;
+    }
+    code = cci_msg_add_data_blob(*resp_msg, cc_vendor, strlen(cc_vendor) + 1, &blob_pos);
+    if (code != ccNoError) {
+        free(resp_header);
+        cci_context_destroy(new_ctx);
+        cci_msg_destroy(*resp_msg);
+        *resp_msg = 0;
+        return code;
+    }
+
+    resp_header->out_ctx = new_ctx;
+    resp_header->out_version = cc_myversion;
+    resp_header->vendor_offset = blob_pos;
+    resp_header->vendor_length = strlen(cc_vendor) + 1;
+    code = cci_msg_add_header(*resp_msg, resp_header, sizeof(ccmsg_init_resp_t));
+    if (code != ccNoError) {
+        free(resp_header);
+        cci_context_destroy(new_ctx);
+        cci_msg_destroy(*resp_msg);
+        *resp_msg = 0;
+        return code;
+    }
+
+    return ccNoError;
+}       
+
+cc_int32 
+ccop_CTX_RELEASE( cc_server_context_t* ctx,
+                  cc_auth_info_t* auth_info,
+                  cc_session_info_t* session_info,
+                  cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ctx_release_t* header = (ccmsg_ctx_release_t *)msg->header;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ctx_release_t)) {
+        return ccErrBadParam;
+    }
+
+    code = cci_context_destroy(header->ctx);
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CTX_GET_CHANGE_TIME( cc_server_context_t* ctx,
+                          cc_auth_info_t* auth_info,
+                          cc_session_info_t* session_info,
+                          cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ctx_get_change_time_resp_t* resp_header;
+    ccmsg_ctx_get_change_time_t *header = (ccmsg_ctx_get_change_time_t *)msg->header;
+
+    *resp_msg = 0;
+	
+    if (msg->header_len != sizeof(ccmsg_ctx_get_change_time_t)) {
+        return ccErrBadParam;
+    }
+
+    resp_header = (ccmsg_ctx_get_change_time_resp_t*)malloc(sizeof(ccmsg_ctx_get_change_time_resp_t));
+    if (resp_header == NULL) {
+        return ccErrNoMem;
+    }
+
+    resp_header->time = ctx->changed;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ctx_get_change_time_resp_t), auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CTX_GET_DEFAULT_CCACHE_NAME( cc_server_context_t* ctx,
+                                  cc_auth_info_t* auth_info,
+                                  cc_session_info_t* session_info,
+                                  cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    char * name;
+    ccmsg_ctx_get_default_ccache_name_resp_t* resp_header;
+    ccmsg_ctx_get_default_ccache_name_t* header = (ccmsg_ctx_get_default_ccache_name_t *)msg->header;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ctx_get_default_ccache_name_t)) {
+        return ccErrBadParam;
+    }
+	
+    code = cci_context_get_default_ccache_name(ctx, &name);
+    if (code != ccNoError)
+        return code;
+
+    code = cci_msg_new(ccmsg_ACK, resp_msg);
+    if (code != ccNoError) 
+        return code;
+	
+    resp_header = (ccmsg_ctx_get_default_ccache_name_resp_t*)malloc(sizeof(ccmsg_ctx_get_default_ccache_name_resp_t));	
+    if (resp_header == NULL) {
+        cci_msg_destroy(*resp_msg);
+        *resp_msg = 0;
+        return ccErrNoMem;
+    }
+
+    code = cci_msg_add_data_blob(*resp_msg, name, strlen(name) + 1, &resp_header->name_offset);
+    resp_header->name_len = strlen(name) + 1;
+    return ccNoError;
+}
+
+cc_int32 
+ccop_CTX_COMPARE(cc_server_context_t* ctx,
+                  cc_auth_info_t* auth_info,
+                  cc_session_info_t* session_info,
+                  cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    cc_server_context_t *ctx2;
+    ccmsg_ctx_compare_resp_t* resp_header;
+    ccmsg_ctx_compare_t* header = (ccmsg_ctx_compare_t *)msg->header;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ctx_compare_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ctx_by_handle(header->ctx2, auth_info, session_info, &ctx2);
+
+    resp_header = (ccmsg_ctx_compare_resp_t*)malloc(sizeof(ccmsg_ctx_compare_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->is_equal = cci_context_compare(ctx, ctx2);
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ctx_compare_resp_t), auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CTX_NEW_CCACHE_ITERATOR(cc_server_context_t* ctx,
+                              cc_auth_info_t* auth_info,
+                              cc_session_info_t* session_info,
+                              cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    cc_ccache_iterate_t* ccache_iterator;
+    ccmsg_ctx_new_ccache_iterator_resp_t* resp_header;
+    ccmsg_ctx_new_ccache_iterator_t* header = (ccmsg_ctx_new_ccache_iterator_t*)msg->header;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ctx_new_ccache_iterator_t))
+        return ccErrBadParam;
+
+    code = cci_context_ccache_iterator(ctx,&ccache_iterator);
+
+    resp_header = (ccmsg_ctx_new_ccache_iterator_resp_t*)malloc(sizeof(ccmsg_ctx_new_ccache_iterator_resp_t));
+    if (resp_header == NULL) 
+        return ccErrNoMem;
+
+    resp_header->iterator = ccache_iterator;
+
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ctx_new_ccache_iterator_resp_t), auth_info, session_info, resp_msg);
+}       
+
+cc_int32
+ccop_CTX_LOCK( cc_server_context_t* ctx,
+               cc_auth_info_t* auth_info,
+               cc_session_info_t* session_info,
+               cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    // TODO
+    return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CTX_UNLOCK( cc_server_context_t* ctx,
+                 cc_auth_info_t* auth_info,
+                 cc_session_info_t* session_info,
+                 cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    // TODO
+    return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CTX_CLONE( cc_server_context_t* ctx,
+                cc_auth_info_t* auth_info,
+                cc_session_info_t* session_info,
+                cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    // TODO
+    return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32 
+ccop_CCACHE_OPEN(cc_server_context_t* ctx,
+                  cc_auth_info_t* auth_info,
+                  cc_session_info_t* session_info,
+                  cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    char *name;
+    cc_server_ccache_t* ccache;
+    ccmsg_ccache_open_resp_t* resp_header;
+    ccmsg_ccache_open_t* header = (ccmsg_ccache_open_t*)msg->header;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_open_t))
+        return ccErrBadParam;
+
+    code = cci_msg_retrieve_blob(msg, header->name_offset, header->name_len, &name);
+    code = cci_context_find_ccache(ctx, name, &ccache);
+
+    free(name);
+
+    if (ccache == NULL)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    resp_header = (ccmsg_ccache_open_resp_t*)malloc(sizeof(ccmsg_ccache_open_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->ccache = ccache;
+    cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_open_resp_t), auth_info, session_info, resp_msg);
+    return ccNoError;
+}       
+
+cc_int32 
+ccop_CCACHE_OPEN_DEFAULT(cc_server_context_t* ctx,
+                          cc_auth_info_t* auth_info,
+                          cc_session_info_t* session_info,
+                          cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_open_default_t* header = (ccmsg_ccache_open_default_t*)msg->header;
+    ccmsg_ccache_open_resp_t* resp_header;
+    cc_server_ccache_t* ccache;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_open_default_t)) 
+        return ccErrBadParam;
+
+    if (ctx->ccaches->head->data == NULL)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+    
+    ccache = (cc_server_ccache_t*) ctx->ccaches->head->data;
+
+    resp_header = (ccmsg_ccache_open_resp_t*)malloc(sizeof(ccmsg_ccache_open_resp_t));
+    if (resp_header == NULL) 
+        return ccErrNoMem;
+
+    resp_header->ccache = ccache;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_open_resp_t), auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_CREATE(cc_server_context_t* ctx,
+                    cc_auth_info_t* auth_info,
+                    cc_session_info_t* session_info,
+                    cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_create_resp_t* resp_header;
+    ccmsg_ccache_create_t* header = (ccmsg_ccache_create_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    char* principal;
+    char* name;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_create_t)) 
+        return ccErrBadParam;
+
+    code = cci_msg_retrieve_blob(msg, header->principal_offset, header->principal_len, &principal);
+    if (code != ccNoError) 
+        return code;
+    principal[header->principal_len] = '\0'; /*Ensure null termination*/
+
+    code = cci_msg_retrieve_blob(msg, header->name_offset, header->name_len, &name);
+    if (code != ccNoError) 
+        return code;
+    name[header->name_len] = '\0'; /*Ensure null termination*/
+
+    code = cci_context_create_ccache(ctx, name, header->version, principal, &ccache);
+    if (code != ccNoError)
+        return code;
+
+    resp_header = (ccmsg_ccache_create_resp_t*)malloc(sizeof(ccmsg_ccache_create_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->ccache = ccache;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_create_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32 
+ccop_CCACHE_CREATE_DEFAULT( cc_server_context_t* ctx,
+                            cc_auth_info_t* auth_info,
+                            cc_session_info_t* session_info,
+                            cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_create_resp_t* resp_header;
+    ccmsg_ccache_create_t* header = (ccmsg_ccache_create_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    char* principal;
+    char* name;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_create_t)) 
+        return ccErrBadParam;
+
+    code = cci_msg_retrieve_blob(msg, header->principal_offset, header->principal_len, &principal);
+    if (code != ccNoError) 
+        return code;
+    principal[header->principal_len] = '\0'; /*Ensure null termination*/
+
+    code = cci_context_get_default_ccache_name(ctx, &name);
+    if (code != ccNoError)
+        return code;
+
+    code = cci_context_create_ccache(ctx, name, header->version, principal, &ccache);
+    if (code != ccNoError)
+        return code;
+
+    resp_header = (ccmsg_ccache_create_resp_t*)malloc(sizeof(ccmsg_ccache_create_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->ccache = ccache;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_create_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32 
+ccop_CCACHE_CREATE_UNIQUE( cc_server_context_t* ctx,
+                           cc_auth_info_t* auth_info,
+                           cc_session_info_t* session_info,
+                           cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_create_resp_t* resp_header;
+    ccmsg_ccache_create_t* header = (ccmsg_ccache_create_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    char* principal;
+    char* name;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_create_t)) 
+        return ccErrBadParam;
+
+    code = cci_msg_retrieve_blob(msg, header->principal_offset, header->principal_len, &principal);
+    if (code != ccNoError) 
+        return code;
+    principal[header->principal_len] = '\0'; /*Ensure null termination*/
+
+    // TODO: Generate a unique ccache name 
+
+    code = cci_context_create_ccache(ctx, name, header->version, principal, &ccache);
+    if (code != ccNoError)
+        return code;
+
+    resp_header = (ccmsg_ccache_create_resp_t*)malloc(sizeof(ccmsg_ccache_create_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->ccache = ccache;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_create_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32 
+ccop_CCACHE_RELEASE( cc_server_context_t* ctx,
+                     cc_auth_info_t* auth_info,
+                     cc_session_info_t* session_info,
+                     cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    // TODO: This is probably wrong.  
+    return ccop_CCACHE_DESTROY(ctx, auth_info, session_info, msg, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_DESTROY( cc_server_context_t* ctx,
+                     cc_auth_info_t* auth_info,
+                     cc_session_info_t* session_info,
+                     cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_release_t* header = (ccmsg_ccache_release_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_release_t)) 
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    cci_ccache_destroy(ccache);
+
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32 
+ccop_CCACHE_SET_DEFAULT(cc_server_context_t* ctx,
+                         cc_auth_info_t* auth_info,
+                         cc_session_info_t* session_info,
+                         cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    cc_server_ccache_t* ccache, *stored_ccache, *old_default;
+    ccmsg_ccache_set_default_t* header = (ccmsg_ccache_set_default_t*)msg->header;
+    cc_ccache_iterate_t* ccache_iterator;
+    cc_ccache_list_node_t* ccache_node;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_set_default_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    if (ccache == (cc_server_ccache_t*)ctx->ccaches->head->data) /*already default*/
+        return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+
+    old_default = (cc_server_ccache_t*)ctx->ccaches->head->data;
+    old_default->last_default = time(NULL);
+
+    code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    while (cci_ccache_iterate_has_next(ccache_iterator)) {
+        code = cci_ccache_iterate_next(ccache_iterator,&ccache_node);
+        stored_ccache = (cc_server_ccache_t*)ccache_node->data;
+
+        if (stored_ccache == ccache) {
+            ccache_node->data = NULL; /*don't want list removal code free()ing ccache*/
+            cci_ccache_list_remove_element(ctx->ccaches, ccache_node);
+            cci_ccache_list_prepend(ctx->ccaches, ccache, NULL);
+            break;
+        }
+    }       
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_GET_CREDS_VERSION(cc_server_context_t* ctx,
+                               cc_auth_info_t* auth_info,
+                               cc_session_info_t* session_info,
+                               cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_get_creds_version_t* header = (ccmsg_ccache_get_creds_version_t*)msg->header;
+    ccmsg_ccache_get_creds_version_resp_t* resp_header;
+    cc_server_ccache_t* ccache;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_get_creds_version_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    resp_header = (ccmsg_ccache_get_creds_version_resp_t*)malloc(sizeof(ccmsg_ccache_get_creds_version_resp_t));	
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->version = ccache->versions;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_get_creds_version_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32 
+ccop_CCACHE_GET_NAME(cc_server_context_t* ctx,
+                      cc_auth_info_t* auth_info,
+                      cc_session_info_t* session_info,
+                      cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_get_name_t* header = (ccmsg_ccache_get_name_t*)msg->header;
+    ccmsg_ccache_get_name_resp_t* resp_header;
+    cc_server_ccache_t* ccache;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_get_name_resp_t)) 
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (ccache == NULL)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    resp_header = (ccmsg_ccache_get_name_resp_t*)malloc(sizeof(ccmsg_ccache_get_name_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    code = cci_msg_new(ccmsg_ACK, resp_msg);
+    if (code != ccNoError)
+        return code;
+
+    code = cci_msg_add_data_blob(*resp_msg, ccache->name, strlen(ccache->name) + 1, &resp_header->name_offset);
+    resp_header->name_len = strlen(ccache->name) + 1;
+    cci_msg_add_header(*resp_msg, resp_header, sizeof(ccmsg_ccache_get_name_resp_t));
+
+    return ccNoError;
+}       
+
+cc_int32 
+ccop_CCACHE_GET_PRINCIPAL(cc_server_context_t* ctx,
+                           cc_auth_info_t* auth_info,
+                           cc_session_info_t* session_info,
+                           cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_get_principal_t* header = (ccmsg_ccache_get_principal_t*)msg->header;
+    ccmsg_ccache_get_principal_resp_t* resp_header;
+    cc_server_ccache_t* ccache;
+    char * principal;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_get_principal_t)) 
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    code = cci_ccache_get_principal(ccache, header->version, &principal);
+    if (code != ccNoError)
+        return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+    code = cci_msg_new(ccmsg_ACK, resp_msg);
+    if (code != ccNoError) 
+        return code;
+
+    resp_header = (ccmsg_ccache_get_principal_resp_t*)malloc(sizeof(ccmsg_ccache_get_principal_resp_t));
+    if (resp_header == NULL) 
+        return ccErrNoMem;
+
+    code = cci_msg_add_data_blob(*resp_msg, principal, strlen(principal) + 1, &resp_header->principal_offset);
+    cci_msg_add_header(*resp_msg, resp_header, sizeof(ccmsg_ccache_get_principal_resp_t));
+
+    return ccNoError;
+}       
+
+cc_int32 
+ccop_CCACHE_SET_PRINCIPAL(cc_server_context_t* ctx,
+                           cc_auth_info_t* auth_info,
+                           cc_session_info_t* session_info,
+                           cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_set_principal_t* header = (ccmsg_ccache_set_principal_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    char *principal;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_set_principal_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    code = cci_msg_retrieve_blob(msg, header->principal_offset, header->principal_len, &principal);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+    code = cci_ccache_set_principal(ccache, header->version, principal);
+    if (code != ccNoError)
+        return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_CREDS_ITERATOR(cc_server_context_t* ctx,
+                            cc_auth_info_t* auth_info,
+                            cc_session_info_t* session_info,
+                            cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    cc_server_ccache_t* ccache;
+    cc_credentials_iterate_t* creds_iterator;
+    ccmsg_ccache_creds_iterator_t* header = (ccmsg_ccache_creds_iterator_t*)msg->header;
+    ccmsg_ccache_creds_iterator_resp_t* resp_header;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_creds_iterator_t)) 
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    code = cci_ccache_new_iterator(ccache, &creds_iterator);
+    if (code != ccNoError)
+        return code;
+
+    resp_header = (ccmsg_ccache_creds_iterator_resp_t*)malloc(sizeof(ccmsg_ccache_creds_iterator_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->iterator = creds_iterator;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_creds_iterator_resp_t), auth_info, session_info, resp_msg);
+}       
+
+
+static cc_int32
+cci_credentials_union_release( cc_credentials_union * creds )
+{
+    int i;
+
+    switch (creds->version) {
+    case cc_credentials_v4:
+        free(creds->credentials.credentials_v4);
+        break;
+    case cc_credentials_v5:
+        if ( creds->credentials.credentials_v5->client )
+            free(creds->credentials.credentials_v5->client);
+        if ( creds->credentials.credentials_v5->server )
+            free(creds->credentials.credentials_v5->server );
+        if ( creds->credentials.credentials_v5->keyblock.data )
+            free(creds->credentials.credentials_v5->keyblock.data);
+        if ( creds->credentials.credentials_v5->ticket.data )
+            free(creds->credentials.credentials_v5->ticket.data);
+        if ( creds->credentials.credentials_v5->second_ticket.data )
+            free(creds->credentials.credentials_v5->second_ticket.data);
+        if ( creds->credentials.credentials_v5->addresses ) {
+            for ( i=0; creds->credentials.credentials_v5->addresses[i]; i++) {
+                if (creds->credentials.credentials_v5->addresses[i]->data)
+                    free(creds->credentials.credentials_v5->addresses[i]->data);
+            }
+            free(creds->credentials.credentials_v5->addresses);
+        }
+        if ( creds->credentials.credentials_v5->authdata ) {
+            for ( i=0; creds->credentials.credentials_v5->authdata[i]; i++) {
+                if ( creds->credentials.credentials_v5->authdata[i]->data )
+                    free(creds->credentials.credentials_v5->authdata[i]->data);
+            }
+            free(creds->credentials.credentials_v5->authdata);
+        }
+        break;
+    default:
+        return ccErrBadCredentialsVersion;
+    }        
+    return ccNoError;
+}
+
+cc_int32 
+ccop_CCACHE_STORE_CREDS(cc_server_context_t* ctx,
+                         cc_auth_info_t* auth_info,
+                         cc_session_info_t* session_info,
+                         cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_store_creds_t* header = (ccmsg_ccache_store_creds_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    char                 *flat_creds;
+    cc_credentials_union *creds;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_store_creds_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    // TODO: This code is too simplistic.  cc_credential_unions are not flat
+    // structures and must be flattened.  That means that although we can 
+    // store a flat blob in the message we will need to decode the blob
+    // into the actual object.  
+    code = cci_msg_retrieve_blob(msg, header->creds_offset, header->creds_len, &flat_creds);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+    creds = (cc_credentials_union *)malloc(sizeof(cc_credentials_union));
+    if ( creds == NULL )
+        return ccErrNoMem;
+
+    switch ( creds->version ) {        
+    case cc_credentials_v4:
+        code = cci_creds_v4_unmarshall(flat_creds, header->creds_len, creds);
+        break;                                 
+    case cc_credentials_v5:
+        code = cci_creds_v5_unmarshall(flat_creds, header->creds_len, creds);
+        break;
+    default:
+        return cci_serv_make_nack(ccErrBadCredentialsVersion, auth_info, session_info, resp_msg);
+    }
+    if (code != ccNoError)
+        return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+    code = cci_ccache_store_creds(ccache, creds);
+    cci_credentials_union_release(creds);
+    if (code != ccNoError) {
+        return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+    }
+
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_REM_CREDS(cc_server_context_t* ctx,
+                       cc_auth_info_t* auth_info,
+                       cc_session_info_t* session_info,
+                       cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_rem_creds_t* header = (ccmsg_ccache_rem_creds_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    cc_credentials_union *creds;
+    cc_int32 code;
+
+    *resp_msg = 0;
+    if (msg->header_len != sizeof(ccmsg_ccache_rem_creds_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    code = cci_ccache_rem_creds(ccache, header->creds);
+    if (code != ccNoError)
+        return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}               
+
+cc_int32
+ccop_CCACHE_LOCK( cc_server_context_t* ctx,
+                  cc_auth_info_t* auth_info,
+                  cc_session_info_t* session_info,
+                  cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    // TODO
+    return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_UNLOCK( cc_server_context_t* ctx,
+                    cc_auth_info_t* auth_info,
+                    cc_session_info_t* session_info,
+                    cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    // TODO
+    return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_MOVE( cc_server_context_t* ctx,
+                  cc_auth_info_t* auth_info,
+                  cc_session_info_t* session_info,
+                  cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    // TODO
+    return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+
+cc_int32 
+ccop_CCACHE_GET_LAST_DEFAULT_TIME(cc_server_context_t* ctx,
+                                   cc_auth_info_t* auth_info,
+                                   cc_session_info_t* session_info,
+                                   cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_get_last_default_time_t* header = (ccmsg_ccache_get_last_default_time_t*)msg->header;
+    ccmsg_ccache_get_last_default_time_resp_t* resp_header;
+    cc_server_ccache_t* ccache;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_get_last_default_time_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    resp_header = (ccmsg_ccache_get_last_default_time_resp_t*)malloc(sizeof(ccmsg_ccache_get_last_default_time_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->last_default_time = ccache->last_default;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_get_last_default_time_resp_t), auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_GET_CHANGE_TIME( cc_server_context_t* ctx,
+                          cc_auth_info_t* auth_info,
+                          cc_session_info_t* session_info,
+                          cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_get_change_time_resp_t* resp_header;
+    ccmsg_ccache_get_change_time_t *header = (ccmsg_ccache_get_change_time_t *)msg->header;
+    cc_server_ccache_t* ccache = (cc_server_ccache_t *)header->ccache;
+
+    *resp_msg = 0;
+	
+    if (msg->header_len != sizeof(ccmsg_ccache_get_change_time_t)) {
+        return ccErrBadParam;
+    }
+
+    resp_header = (ccmsg_ccache_get_change_time_resp_t*)malloc(sizeof(ccmsg_ccache_get_change_time_resp_t));
+    if (resp_header == NULL) {
+        return ccErrNoMem;
+    }
+
+    resp_header->time = ccache->changed;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_get_change_time_resp_t), auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_COMPARE(cc_server_context_t* ctx,
+                     cc_auth_info_t* auth_info,
+                     cc_session_info_t* session_info,
+                     cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_compare_t* header = (ccmsg_ccache_compare_t*)msg->header;
+    ccmsg_ccache_compare_resp_t* resp_header;
+    cc_server_ccache_t* ccache1, *ccache2;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_compare_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache1, &ccache1);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache2, &ccache2);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    resp_header = (ccmsg_ccache_compare_resp_t*)malloc(sizeof(ccmsg_ccache_compare_resp_t));	
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    cci_ccache_compare(ccache1, ccache2, &resp_header->is_equal);
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_compare_resp_t), auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_GET_KDC_TIME_OFFSET(cc_server_context_t* ctx,
+                                 cc_auth_info_t* auth_info,
+                                 cc_session_info_t* session_info,
+                                 cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_get_kdc_time_offset_t* header = (ccmsg_ccache_get_kdc_time_offset_t*)msg->header;
+    ccmsg_ccache_get_kdc_time_offset_resp_t* resp_header;
+    cc_server_ccache_t* ccache;
+    cc_time_t offset;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_get_kdc_time_offset_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    // TODO How is the header->creds_version supposed to be used?
+
+    code = cci_ccache_get_kdc_time_offset(ccache, &offset);
+    if (code != ccNoError)
+        return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+    resp_header = (ccmsg_ccache_get_kdc_time_offset_resp_t*)malloc(sizeof(ccmsg_ccache_get_kdc_time_offset_resp_t));
+    if (resp_header == NULL)
+        return ccErrNoMem;
+
+    resp_header->offset = offset;
+    return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_get_kdc_time_offset_resp_t), auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_SET_KDC_TIME_OFFSET(cc_server_context_t* ctx,
+                                 cc_auth_info_t* auth_info,
+                                 cc_session_info_t* session_info,
+                                 cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_set_kdc_time_offset_t* header = (ccmsg_ccache_set_kdc_time_offset_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_set_kdc_time_offset_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    // TODO How is the header->creds_version supposed to be used?
+
+    cci_ccache_set_kdc_time_offset(ccache, header->offset);
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_CLEAR_KDC_TIME_OFFSET(cc_server_context_t* ctx,
+                                   cc_auth_info_t* auth_info,
+                                   cc_session_info_t* session_info,
+                                   cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_clear_kdc_time_offset_t* header = (ccmsg_ccache_clear_kdc_time_offset_t*)msg->header;
+    cc_server_ccache_t* ccache;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_clear_kdc_time_offset_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    // TODO How is the header->creds_version supposed to be used?
+
+    cci_ccache_clear_kdc_time_offset(ccache);
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}               
+
+cc_int32 
+ccop_CCACHE_ITERATOR_RELEASE(cc_server_context_t* ctx,
+                              cc_auth_info_t* auth_info,
+                              cc_session_info_t* session_info,
+                              cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    cc_generic_list_node_t* gen_node;
+    ccmsg_ccache_iterator_release_t* header = (ccmsg_ccache_iterator_release_t*)msg->header;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_iterator_release_t)) 
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_iterator_by_handle(ctx, header->iterator, &gen_node);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+    code = cci_generic_list_remove_element(ctx->active_iterators, gen_node);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CCACHE_ITERATOR_NEXT(cc_server_context_t* ctx,
+                           cc_auth_info_t* auth_info,
+                           cc_session_info_t* session_info,
+                           cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_ccache_iterator_release_t* header = (ccmsg_ccache_iterator_release_t*)msg->header;
+    ccmsg_ccache_iterator_next_resp_t* resp_header;
+    cc_generic_list_node_t* gen_node;
+    cc_ccache_iterate_t* ccache_iterator;
+	cc_ccache_list_node_t *ccache_node;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_ccache_iterator_next_t)) 
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_iterator_by_handle(ctx, header->iterator, &gen_node);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+    ccache_iterator = (cc_ccache_iterate_t*)gen_node->data;
+    if (cci_ccache_iterate_has_next(ccache_iterator)) {
+        resp_header = (ccmsg_ccache_iterator_next_resp_t*)malloc(sizeof(ccmsg_ccache_iterator_next_resp_t));
+        if (resp_header == NULL)
+            return ccErrNoMem;
+
+        code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+        if (code != ccNoError) 
+            return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+		resp_header->ccache = ccache_node;
+        return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_iterator_next_resp_t), auth_info, session_info, resp_msg);
+    } else {
+        return cci_serv_make_nack(ccIteratorEnd, auth_info, session_info, resp_msg);
+    }
+}       
+
+cc_int32 
+ccop_CREDS_ITERATOR_RELEASE(cc_server_context_t* ctx,
+                             cc_auth_info_t* auth_info,
+                             cc_session_info_t* session_info,
+                             cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    cc_generic_list_node_t* gen_node;
+    cc_server_ccache_t* ccache;
+    ccmsg_creds_iterator_release_t* header = (ccmsg_creds_iterator_release_t*)msg->header;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_creds_iterator_release_t)) 
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    code = cci_serv_find_creds_iterator_by_handle(ccache, header->iterator, &gen_node);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+    code = cci_generic_list_remove_element(ccache->active_iterators, gen_node);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+    return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}       
+
+cc_int32 
+ccop_CREDS_ITERATOR_NEXT(cc_server_context_t* ctx,
+                          cc_auth_info_t* auth_info,
+                          cc_session_info_t* session_info,
+                          cc_msg_t *msg, cc_msg_t **resp_msg) 
+{
+    ccmsg_creds_iterator_next_t* header = (ccmsg_creds_iterator_next_t*)msg->header;
+    ccmsg_creds_iterator_next_resp_t* resp_header;
+    cc_credentials_iterate_t* creds_iterator;
+    cc_generic_list_node_t* gen_node;
+    cc_credentials_list_node_t* creds_node;
+    cc_server_ccache_t* ccache;
+    cc_server_credentials_t* stored_creds;
+    cc_credentials_union *creds_union;
+    cc_int32 code;
+
+    *resp_msg = 0;
+
+    if (msg->header_len != sizeof(ccmsg_creds_iterator_next_t))
+        return ccErrBadParam;
+
+    code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+    if (code != ccNoError)
+        return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+    code = cci_serv_find_creds_iterator_by_handle(ccache, header->iterator, &gen_node);
+    if (code != ccNoError) 
+        return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+    creds_iterator = (cc_credentials_iterate_t*)gen_node->data;
+    if (cci_credentials_iterate_has_next(creds_iterator)) {
+        code = cci_msg_new(ccmsg_ACK, resp_msg);
+        if (code != ccNoError)
+            return code;
+
+        resp_header = (ccmsg_creds_iterator_next_resp_t*)malloc(sizeof(ccmsg_creds_iterator_next_resp_t));
+        if (resp_header == NULL)
+            return ccErrNoMem;
+
+        code = cci_credentials_iterate_next(creds_iterator, &creds_node);
+        stored_creds = (cc_server_credentials_t*)creds_node->data;
+        creds_union = &stored_creds->creds;
+
+        code = cci_msg_add_data_blob(*resp_msg, creds_union, sizeof(cc_credentials_union), &resp_header->creds_offset);
+        code = cci_msg_add_header(*resp_msg, resp_header, sizeof(ccmsg_creds_iterator_next_resp_t));
+    } else {
+        cci_serv_make_nack(ccIteratorEnd, auth_info, session_info, resp_msg);
+    }
+    return ccNoError;
+}       
+
+cc_int32 
+ccop_CREDS_RELEASE( cc_server_context_t* ctx,
+                    cc_auth_info_t* auth_info,
+                    cc_session_info_t* session_info,
+                    cc_msg_t *msg, cc_msg_t **resp_msg) 
+{       
+        
+    cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+    return ccNoError;
+}       
diff --git a/mechglue/src/lib/ccapi/server/serv_ops.h b/mechglue/src/lib/ccapi/server/serv_ops.h
new file mode 100644
index 000000000..f43956685
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/serv_ops.h
@@ -0,0 +1,321 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Prototypes for serv_ops.c
+ */
+
+#ifndef __SERV_OPS_H__
+#define __SERV_OPS_H__
+
+#include "CredentialsCache.h"
+#include "rpc_auth.h"
+#include "msg.h"
+#include "datastore.h"
+
+struct type_to_op_mapping_t {
+    cc_int32 (*operations[CC_MSG_MAX_TYPE]) (
+                        cc_server_context_t* ctx,
+			cc_auth_info_t* auth_info,
+			cc_session_info_t* session_info,
+			cc_msg_t *msg,
+                        cc_msg_t **resp_msg);
+};
+typedef struct type_to_op_mapping_t type_to_op_mapping_t;
+
+cc_int32 cci_serv_initialize(void);
+cc_int32 cci_serv_process_msg(cc_msg_t * msg, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** resp_msg);
+cc_int32 cci_serv_find_ctx(cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_server_context_t** contextp);
+cc_int32 cci_serv_find_ctx_by_handle(cc_handle ctx_handle, cc_auth_info_t *auth, cc_session_info_t* session, cc_server_context_t** contextp);
+cc_int32 cci_serv_find_ccache_by_handle(cc_server_context_t* ctx, cc_handle ccache_handle, cc_server_ccache_t** ccachep) ;
+cc_int32 cci_serv_find_ccache_iterator_by_handle(cc_server_context_t* ctx, cc_handle iterator, cc_generic_list_node_t** nodep);
+cc_int32 cci_serv_find_creds_iterator_by_handle(cc_server_ccache_t* ccache, cc_handle iterator, cc_generic_list_node_t** nodep);
+cc_int32 cci_serv_make_nack(cc_int32 err_code, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** msgp);
+cc_int32 cci_serv_make_ack(void * header, cc_int32 header_len, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** msgp);
+
+cc_int32 ccop_INIT( 
+        cc_server_context_t* ctx,
+        cc_auth_info_t* auth_info,
+        cc_session_info_t* session_info,
+        cc_msg_t *msg,
+        cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_RELEASE(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_GET_CHANGE_TIME(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_GET_DEFAULT_CCACHE_NAME(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_COMPARE(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_NEW_CCACHE_ITERATOR(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CTX_LOCK( cc_server_context_t* ctx,
+               cc_auth_info_t* auth_info,
+               cc_session_info_t* session_info,
+               cc_msg_t *msg, 
+               cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CTX_UNLOCK( cc_server_context_t* ctx,
+                 cc_auth_info_t* auth_info,
+                 cc_session_info_t* session_info,
+                 cc_msg_t *msg, 
+                 cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CTX_CLONE( cc_server_context_t* ctx,
+                cc_auth_info_t* auth_info,
+                cc_session_info_t* session_info,
+                cc_msg_t *msg, 
+                cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_OPEN(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_OPEN_DEFAULT(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_CREATE(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 
+ccop_CCACHE_CREATE_DEFAULT( cc_server_context_t* ctx,
+                            cc_auth_info_t* auth_info,
+                            cc_session_info_t* session_info,
+                            cc_msg_t *msg, 
+                            cc_msg_t **resp_msg);
+
+cc_int32 
+ccop_CCACHE_CREATE_UNIQUE( cc_server_context_t* ctx,
+                           cc_auth_info_t* auth_info,
+                           cc_session_info_t* session_info,
+                           cc_msg_t *msg, 
+                           cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_RELEASE(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_DESTROY(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_SET_DEFAULT(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_CREDS_VERSION(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_NAME(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_PRINCIPAL(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_SET_PRINCIPAL(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_CREDS_ITERATOR(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_STORE_CREDS(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_REM_CREDS(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_LAST_DEFAULT_TIME(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 
+ccop_CCACHE_GET_CHANGE_TIME( 
+        cc_server_context_t* ctx,
+        cc_auth_info_t* auth_info,
+        cc_session_info_t* session_info,
+        cc_msg_t *msg, 
+        cc_msg_t **resp_msg) ;
+
+cc_int32 ccop_CCACHE_COMPARE(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_KDC_TIME_OFFSET(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_SET_KDC_TIME_OFFSET(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_CLEAR_KDC_TIME_OFFSET(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_ITERATOR_RELEASE(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_ITERATOR_NEXT(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CREDS_ITERATOR_RELEASE(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CREDS_ITERATOR_NEXT(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+
+cc_int32 ccop_CREDS_RELEASE(
+	cc_server_context_t* ctx,
+	cc_auth_info_t* auth_info,
+	cc_session_info_t* session_info,
+	cc_msg_t *msg,
+	cc_msg_t **resp_msg);
+#endif /*__SERV_OPS_H__*/
diff --git a/mechglue/src/lib/ccapi/server/windows/ChangeLog b/mechglue/src/lib/ccapi/server/windows/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/server/windows/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/unit-test/ChangeLog b/mechglue/src/lib/ccapi/unit-test/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/unit-test/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/ccapi/unit-test/t_ccache.c b/mechglue/src/lib/ccapi/unit-test/t_ccache.c
new file mode 100644
index 000000000..6ef33ea23
--- /dev/null
+++ b/mechglue/src/lib/ccapi/unit-test/t_ccache.c
@@ -0,0 +1,115 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+int main() {
+    cc_server_credentials_t *cred1, *cred2, *cred3;
+    cc_credentials_iterate_t* iterator;
+    cc_server_credentials_t* stored_cred;
+    cc_credentials_list_node_t *node;
+    cc_server_ccache_t *c1, *c2;
+    char p1[] = "Spike";
+    char p2[] = "Jeff";
+    int i;
+    cc_int32 code;
+
+    code = cci_ccache_new("The first", p1, cc_credentials_v4_v5, &c1);
+    code = cci_ccache_new("The 2nd", p2, cc_credentials_v4_v5, &c2);
+
+    cred1 = (cc_server_credentials_t*)malloc(sizeof(cc_server_credentials_t));
+    memset(cred1,0,sizeof(cc_server_credentials_t));
+    cred2 = (cc_server_credentials_t*)malloc(sizeof(cc_server_credentials_t));
+    memset(cred2,0,sizeof(cc_server_credentials_t));
+    cred3 = (cc_server_credentials_t*)malloc(sizeof(cc_server_credentials_t));
+    memset(cred3,0,sizeof(cc_server_credentials_t));
+
+    cred1->creds.version = cred2->creds.version = cc_credentials_v4;
+    cred3->creds.version = cc_credentials_v5;
+
+    cred1->creds.credentials.credentials_v4 = (cc_credentials_v4_t*)malloc(sizeof(cc_credentials_v4_t));
+    memset(cred1->creds.credentials.credentials_v4,0,sizeof(cc_credentials_v4_t));
+    cred2->creds.credentials.credentials_v4 = (cc_credentials_v4_t*)malloc(sizeof(cc_credentials_v4_t));
+    memset(cred2->creds.credentials.credentials_v4,0,sizeof(cc_credentials_v4_t));
+    cred3->creds.credentials.credentials_v5 = (cc_credentials_v5_t*)malloc(sizeof(cc_credentials_v5_t));
+    memset(cred3->creds.credentials.credentials_v5,0,sizeof(cc_credentials_v5_t));
+
+    strncpy(cred1->creds.credentials.credentials_v4->principal, p1, strlen(p1));
+    strncpy(cred2->creds.credentials.credentials_v4->principal, p1, strlen(p1));
+    cred3->creds.credentials.credentials_v5->client = p1;
+
+    code = cci_ccache_store_creds(c1, &cred1->creds);
+    printf("(c1, cred1) -> %d\n",code);
+
+    code = cci_ccache_store_creds(c1, &cred2->creds);
+    printf("(c1, cred2) -> %d\n",code);
+
+    code = cci_ccache_store_creds(c2, &cred3->creds);
+    printf("(c2, cred3) -> %d\n",code);
+
+    code = cci_ccache_store_creds(c1, &cred3->creds);
+    printf("(c1, cred3) -> %d\n",code);
+
+    i = 0;
+    code = cci_ccache_move(c1, c2);
+    code = cci_ccache_destroy(c1);
+    code = cci_ccache_new_iterator(c2, &iterator);
+    while (cci_credentials_iterate_has_next(iterator)) {
+        i++;
+        code = cci_credentials_iterate_next(iterator, &node);
+        stored_cred = (cc_server_credentials_t *)node->data;
+        printf("%d %d %s\n", stored_cred->is_default, stored_cred->creds.version, stored_cred->creds.credentials.credentials_v4->principal);
+
+        if (i == 1) {
+            code = cci_ccache_rem_creds(c2,&cred2->creds);
+            printf("(c2 rem cred2) -> %d\n",code);
+        }
+    }
+    return 0;
+}
+
diff --git a/mechglue/src/lib/ccapi/unit-test/t_context.c b/mechglue/src/lib/ccapi/unit-test/t_context.c
new file mode 100644
index 000000000..9e35d9abf
--- /dev/null
+++ b/mechglue/src/lib/ccapi/unit-test/t_context.c
@@ -0,0 +1,115 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+
+/*testing code*/
+int main() {
+    int uid = 1;
+    int session = 1;
+    cc_server_ccache_t *ccache;
+    cc_credentials_union* creds;
+    cc_ccache_iterate_t* ccache_iterator;
+    cc_ccache_list_node_t* ccache_node;
+    cc_credentials_iterate_t* creds_iterator;
+    cc_credentials_list_node_t* creds_node;
+    cc_server_credentials_t* server_creds;
+    cc_auth_info_t* auth_info = NULL;
+    cc_session_info_t* session_info = NULL;
+    cc_server_context_t* ctx = NULL;
+    char *name;
+    int i;
+    cc_int32 code;
+
+    code = cci_context_new(5, auth_info, session_info, &ctx);
+    code = cci_context_create_default_ccache(ctx, cc_credentials_v4, "Spike", &ccache);
+    code = cci_context_get_default_ccache_name(ctx, &name);
+    code = cci_context_open_ccache(ctx, name, &ccache);
+	
+    for (i = 0; i < 5; i++) {
+        creds = (cc_credentials_union*)malloc(sizeof(cc_credentials_union));
+        creds->version = cc_credentials_v4;
+        creds->credentials.credentials_v4 = (cc_credentials_v4_t*)malloc(sizeof(cc_credentials_v4_t));
+        strcpy(creds->credentials.credentials_v4->principal, "Spike");
+
+        code = cci_ccache_store_creds(ccache, creds);
+    }
+
+    code = cci_context_create_ccache(ctx, "ccache 2", cc_credentials_v4, "Jeff", &ccache);
+    code = cci_context_open_ccache(ctx, "ccache 2", &ccache);
+	
+    for (i = 0; i < 5; i++) {
+        creds = (cc_credentials_union*)malloc(sizeof(cc_credentials_union));
+        creds->version = cc_credentials_v4;
+        creds->credentials.credentials_v4 = (cc_credentials_v4_t*)malloc(sizeof(cc_credentials_v4_t));
+        strcpy(creds->credentials.credentials_v4->principal, "Jeff");
+
+        cci_ccache_store_creds(ccache, creds);
+    }
+
+    code = cci_context_ccache_iterator(ctx, &ccache_iterator);
+    while (cci_ccache_iterate_has_next(ccache_iterator)) {
+        code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+        ccache = (cc_server_ccache_t *)ccache_node->data;
+        printf("%x for %s %s default = %d v %d\n",
+               ccache, ccache->principal_v4, ccache->principal_v5, 
+               ccache->is_default, ccache->versions);
+
+        code = cci_ccache_new_iterator(ccache, &creds_iterator);
+        while (cci_credentials_iterate_has_next(creds_iterator)) {
+            code = cci_credentials_iterate_next(creds_iterator, &creds_node);
+            server_creds = (cc_server_credentials_t *)creds_node->data;	
+            printf("\t%s %d\n", 
+                   server_creds->creds.credentials.credentials_v4->principal, 
+                   creds->version);
+        }
+    }       
+    return 0;
+}
diff --git a/mechglue/src/lib/ccapi/unit-test/t_lists.c b/mechglue/src/lib/ccapi/unit-test/t_lists.c
new file mode 100644
index 000000000..4c8450bb7
--- /dev/null
+++ b/mechglue/src/lib/ccapi/unit-test/t_lists.c
@@ -0,0 +1,100 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+
+int main() {
+    cc_generic_list_head_t* head;
+    cc_generic_list_head_t* copy;// = cc_generic_list_copy(head);
+    cc_generic_list_node_t *head_node,*tail,*middle, *node;
+    cc_generic_iterate_t* iterate;
+    int x1 = 1;
+    int x2 = 2;
+    int x3 = 3;
+    int x4 = 4;
+    int x5 = 5;
+    int x6 = 6;
+    cc_int32 code;
+
+    code = cci_generic_list_new(&head);
+    code = cci_generic_list_append(head,&x4,sizeof(x4),NULL);
+    code = cci_generic_list_append(head,&x5,sizeof(x5),NULL);
+    code = cci_generic_list_append(head,&x6,sizeof(x6),&tail);
+
+    code = cci_generic_list_prepend(head,&x3,sizeof(x3),&middle);
+    code = cci_generic_list_prepend(head,&x2,sizeof(x2),NULL);
+    code = cci_generic_list_prepend(head,&x1,sizeof(x1), &head_node);
+
+    code = cci_generic_list_iterator(head, &iterate);
+    while (cci_generic_iterate_has_next(iterate)) {
+        code = cci_generic_iterate_next(iterate, &node);
+        printf("%d\n",*((int *)(node->data)));
+    }
+    printf("----------\n");
+    cci_generic_list_remove_element(head,head_node);
+    cci_generic_list_remove_element(head,middle);
+    cci_generic_list_remove_element(head,tail);
+
+    code = cci_generic_list_iterator(head, &iterate);
+    while (cci_generic_iterate_has_next(iterate)) {
+        code = cci_generic_iterate_next(iterate, &node);
+        printf("%d\n",*((int *)(node->data)));
+    }
+
+    printf("----------\n");
+    code = cci_generic_list_copy(head, ©);
+    code = cci_generic_list_iterator(copy, &iterate);
+    while (cci_generic_iterate_has_next(iterate)) {
+        code = cci_generic_iterate_next(iterate, &node);
+        printf("%d\n",*((int *)(node->data)));
+    }
+
+    cci_generic_list_destroy(copy);
+    return 0;
+}       
diff --git a/mechglue/src/lib/ccapi/unit-test/t_msg.c b/mechglue/src/lib/ccapi/unit-test/t_msg.c
new file mode 100644
index 000000000..b3a31a871
--- /dev/null
+++ b/mechglue/src/lib/ccapi/unit-test/t_msg.c
@@ -0,0 +1,88 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+#include "CredentialsCache.h"
+#include "msg.h"
+#include "datastore.h"
+
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+#include <string.h>
+
+/*testing code*/
+int main() 
+{
+    cc_msg_t* msg;
+    double header = 4.05;
+    char blob1[] = "This is blob one.1234";
+    int blob2 = 2;
+    char blob3[] = "This is blob 3.";
+    int pos1,pos2,pos3;
+    void *flat;
+    char *p;
+    cc_uint32 valid = 0;
+    cc_int32 code;
+
+    code = cci_msg_new(ccmsg_INIT, &msg);
+    code = cci_msg_add_header(msg, &header, sizeof(double));
+    //cc_msg_add_header(msg, NULL, 0);
+    code = cci_msg_add_data_blob(msg, blob1, strlen(blob1) + 1,&pos1);
+    code = cci_msg_add_data_blob(msg, &blob2, sizeof(int),&pos2);
+    code = cci_msg_add_data_blob(msg, blob3, strlen(blob3) + 1,&pos3);
+
+    cci_msg_flatten(msg,&flat);
+
+    printf("%s\n",(char *)((char *)msg->flat + pos1));
+    printf("%d\n",*(int *)((char *)msg->flat + pos2));
+    printf("%s\n",(char *)((char *)msg->flat + pos3));
+
+    cci_msg_verify(msg->flat, msg->flat_len, &valid);
+    printf("%d\n",valid);
+
+    code = cci_msg_unflatten(msg->flat, msg->flat_len, &msg);
+
+    code = cci_msg_retrieve_blob(msg, pos3, strlen(blob3) + 1, &p);
+    printf("%s PPP\n",p);
+    return 0;
+}
diff --git a/mechglue/src/lib/ccapi/unit-test/t_server.c b/mechglue/src/lib/ccapi/unit-test/t_server.c
new file mode 100644
index 000000000..d4d998466
--- /dev/null
+++ b/mechglue/src/lib/ccapi/unit-test/t_server.c
@@ -0,0 +1,185 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ * 
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT).  No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ * 
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner.  It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+
+#include "CredentialsCache.h"
+#include "serv_ops.h"
+#include "datastore.h"
+#include "rpc_auth.h"
+#include "msg_headers.h"
+
+#include <stdlib.h>
+
+static int 
+read_flat_msg(char ** flat_msg, cc_uint32 * flat_len)
+{               
+    
+    /* TODO - read length of message */
+    *flat_len = 999;
+
+    *flat_msg = (char *)malloc(*flat_len);
+
+    /* TODO - read message into buffer */
+
+    return 0;
+}
+
+static int
+send_flat_msg(char * flag_msg, cc_uint32 flat_len)
+{
+        
+    return 0;
+}
+
+static int 
+obtain_auth_info(cc_auth_info_t ** auth)
+{
+    if (auth == NULL)
+        return ccErrBadParam;
+
+    *auth = malloc(sizeof(cc_auth_info_t));
+    if (auth == NULL)
+        return ccErrNoMem;
+    
+    memset(*auth,0,sizeof(cc_auth_info_t));
+
+    /* TODO: obtain real auth data from connection */
+
+    return ccNoError;
+}
+
+static int
+destroy_auth_info(cc_auth_info_t * auth)
+{
+    if (auth == NULL)
+        return ccErrBadParam;
+
+    if (auth->info)
+        free(auth->info);
+
+    free(auth);
+
+    return ccNoError;
+}
+
+static int 
+obtain_session_info(cc_session_info_t ** session)
+{
+    if (session == NULL)
+        return ccErrBadParam;
+
+    *session = malloc(sizeof(cc_session_info_t));
+    if (session == NULL)
+        return ccErrNoMem;
+    
+    memset(*session,0,sizeof(cc_session_info_t));
+
+    /* TODO: obtain real session data from connection */
+
+    return ccNoError;
+}
+
+static int
+destroy_session_info(cc_session_info_t * session)
+{
+    if (session == NULL)
+        return ccErrBadParam;
+
+    if (session->info)
+        free(session->info);
+
+    free(session);
+
+    return ccNoError;
+}
+
+
+int
+main(void)
+{
+    cc_msg_t *          msg;
+    cc_msg_t *          resp;
+    cc_auth_info_t    * auth_info;
+    cc_session_info_t * session_info;
+    cc_int32            code;
+
+    if ( cci_serv_initialize() != ccNoError )
+        return 1;
+
+    while ( 1 ) {
+        msg = (cc_msg_t *)malloc(sizeof(cc_msg_t));
+
+        /* read message */
+        if (read_flat_msg(&msg->flat, &msg->flat_len))
+            continue;
+
+        /* unflatten message */
+        code = cci_msg_unflatten(msg->flat, msg->flat_len, &msg); 
+
+        /* obtain auth info */
+        code = obtain_auth_info(&auth_info);
+
+        /* obtain session info */
+        code = obtain_session_info(&session_info);
+
+        /* process message */
+        code = cci_serv_process_msg(msg, auth_info, session_info, &resp);
+
+        /* flatten response */
+        code = cci_msg_flatten(resp, NULL);
+
+        /* send response */
+        code = send_flat_msg(resp->flat, resp->flat_len);
+
+        code = destroy_auth_info(auth_info);
+
+        code = destroy_session_info(session_info);
+
+        /* free message */
+        code = cci_msg_destroy(msg);
+
+        /* free response */
+        code = cci_msg_destroy(resp);
+    }
+    return 0;
+}
diff --git a/mechglue/src/lib/ccapi/windows/ChangeLog b/mechglue/src/lib/ccapi/windows/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/mechglue/src/lib/ccapi/windows/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27   Jeffrey Altman  <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/mechglue/src/lib/comerr32.def b/mechglue/src/lib/comerr32.def
new file mode 100644
index 000000000..6bf326f30
--- /dev/null
+++ b/mechglue/src/lib/comerr32.def
@@ -0,0 +1,10 @@
+;LIBRARY		COMERR32
+DESCRIPTION	'DLL for ComErr'
+HEAPSIZE	8192
+
+EXPORTS
+	com_err
+	com_err_va
+	error_message
+	add_error_table
+	remove_error_table
diff --git a/mechglue/src/lib/crypto/.Sanitize b/mechglue/src/lib/crypto/.Sanitize
new file mode 100644
index 000000000..b2f048e7a
--- /dev/null
+++ b/mechglue/src/lib/crypto/.Sanitize
@@ -0,0 +1,50 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+crc32
+cryptoconf.c
+decrypt_data.c
+des
+des3_raw.c
+des3_sha.c
+des_crc.c
+des_md5.c
+encrypt_data.c
+md4
+md5
+os
+raw_des.c
+sha
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/crypto/ChangeLog b/mechglue/src/lib/crypto/ChangeLog
new file mode 100644
index 000000000..66c87632f
--- /dev/null
+++ b/mechglue/src/lib/crypto/ChangeLog
@@ -0,0 +1,1117 @@
+2006-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_nfold$(EXEEXT)): Include support library.
+
+2006-01-11  Sam Hartman  <hartmans@mit.edu>
+
+	* keyblocks.c (krb5int_c_free_keyblock): Remove krb5_callconv modifier
+
+2005-11-28  Tom Yu  <tlyu@mit.edu>
+
+	* t_cts.c, vectors.c: Don't include krb5.h.
+
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_hmac.c, t_pkcs5.c: Don't include krb5.h.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* keyblocks.c (krb5int_c_free_keyblock): Call
+	krb5int_c_free_keyblock_contents instead of
+	krb5_free_keyblock_contents.
+
+2005-05-19  Sam Hartman  <hartmans@mit.edu>
+
+	* keyblocks.c :  File to contain memory management for keyblocks
+	moved from libkrb5  
+
+	* Makefile.in (SRCS):  keyblocks.c is new
+
+	* etypes.c: Add PRF for AES
+
+	* Makefile.in (t_prf$(EXEEXT)): New output for prf test framework
+
+2005-05-18  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in :  Add prf.c
+
+	* prf.c t_prf.c: New file
+
+	* etypes.c: Adjust structures to support the PRF declarations.
+
+2005-03-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * keyed_cksum.c: (krb5_c_is_keyed_cksum): this is a boolean 
+          function.  It should not return -1U on error.  Instead return
+          0 (false) so that the caller doesn't think it succeeded.
+
+          The only two callers are rd_safe and mk_safe.  Neither checks
+          for special cases.
+
+2005-01-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* prng.c (krb5int_prng_init): Incorporate do_yarrow_init body.
+	Don't check inited variable.
+	(inited): Variable deleted.
+	(krb5_c_random_make_octets, krb5int_prng_cleanup): Don't check
+	it.
+	(do_yarrow_init): Deleted.
+
+2005-01-12  Tom Yu  <tlyu@mit.edu>
+
+	* prng.c (read_entropy_from_device): Use ssize_t, not size_t, so
+	read() returning -1 doesn't cause trouble.
+
+2004-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* prng.c (do_yarrow_init): Move mutex initialization here.
+	(krb5int_prng_init): Don't do it here.
+
+2004-11-15  Sam Hartman  <hartmans@mit.edu>
+
+	* t_prng.expected t_prng.reseedtest-expected :  Update expected
+	PRNG test output and confirm that reseeds and gates happen correctly.
+
+2004-10-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* prng.c (yarrow_lock): Rename to krb5int_yarrow_lock via macro,
+	and change to be non-static.
+	(krb5int_prng_init): Call do_yarrow_init here.
+	(krb5_c_random_add_entropy): Don't call it here.  Don't lock the
+	mutex, either.
+	(krb5_c_random_make_octets): Don't lock the mutex.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Don't set.
+
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_DIRS, SHLIB_EXPLIBS, SHLIB_EXPDEPLIBS): Set
+	to depend on the new support library.
+	(SHLIB_LIBS): Don't define.
+	(SHLIB_RDIRS): Set.
+
+	* configure.in: Use BUILD_LIBRARY_WITH_DEPS instead of the no-deps
+	version.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* prng.c (init_once): Variable deleted.
+	(krb5_c_random_add_entropy): Do the initialization once, using
+	the yarrow_lock mutex instead of k5_once to protect it.
+
+2004-05-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_nfold.c (fold_kerberos): Change nbytes argument to unsigned.
+
+	* t_encrypt.c (compare_results): Declare static.
+	(main): Free allocated memory before exit.
+
+2004-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_encrypt, t_prng, t_hmac, t_pkcs5, vectors,
+	t_cts): Link test programs against thread support library.
+
+2004-05-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* libk5crypto.exports: Add the DES tables back in; libdes425 uses
+	them directly.
+
+2004-05-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for endian.h and machine/endian.h.
+
+2004-04-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* crypto_libinit.c (initialized): Variable deleted.
+	(cryptoint_initialize_library, cryptoint_cleanup_library): Use new
+	macros for automatic shared library init/fini functions.
+	(prng_cleanup): Declaration deleted.
+	(krb5int_prng_init, krb5int_prng_cleanup): Declare.
+	(cryptoint_initialize_library): Call krb5int_prng_init.
+	(krb5int_crypto_init): New function, checks that
+	cryptoint_initialize_library was called successfully.
+	(cryptoint_cleanup_library): Call krb5int_prng_cleanup only if the
+	initializer ran.
+	* crypto_libinit.h: Deleted.
+	* prng.c: Include k5-thread.h.
+	(init_once, init_error, yarrow_lock): New variables.
+	(krb5int_prng_init): New function; finish initializing the mutex
+	lock.
+	(do_yarrow_init): New function.
+	(krb5_c_random_add_entropy): Call it once only.  Lock the mutex
+	before processing the input.
+	(krb5_c_random_make_octets): Lock the mutex before extracting
+	random bytes.
+	(krb5int_prng_cleanup): Destroy the mutex.
+
+	* Makefile.in (LIBINITFUNC, LIBFINIFUNC): New variables.
+
+	* libk5crypto.exports: Drop the library init/fini functions and
+	the DES tables from the export list.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libk5crypto.exports: New file.
+
+2004-03-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* pbkdf2.c (hmac1): Make a local copy of the supplied keyblock
+	structure, in case we want to modify it.
+
+2004-03-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* prng.c (krb5int_prng_cleanup): Renamed from prng_cleanup.
+	* crypto_libinit.c: Include k5-int.h.
+	(cryptoint_cleanup_library): Updated call.
+
+2004-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't check for --enable-athena and don't define
+	ATHENA_DES3_KLUDGE.
+
+2004-02-24  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* etypes.c: Remove ENCTYPE_LOCAL_DES3_HMAC_SHA1
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* block_size.c, checksum_length.c, cksumtype_to_string.c,
+	coll_proof_cksum.c, decrypt.c, encrypt.c, encrypt_length.c,
+	enctype_compare.c, enctype_to_string.c, hmac.c,
+	keyed_checksum_types.c, keyed_cksum.c, make_checksum.c,
+	make_random_key.c, nfold.c, old_api_glue.c, prng.c,
+	string_to_cksumtype.c, string_to_enctype.c, string_to_key.c,
+	valid_cksumtype.c, valid_enctype.c, verify_checksum.c: Use ANSI C
+	style function definitions.
+
+2004-02-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_encrypt.c (compare_results): New function.
+	(main): Use it to check decryption results against the original
+	plaintext.  When testing with cipher state, encrypt and then
+	decrypt (and verify) two messages.
+	* Makefile.in (t_encrypt$(EXEEXT)): Depend on CRYPTO_DEPLIB.
+
+2004-02-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_cts.c (test_cts): Process encryption and decryption IVs
+	separately, make sure they match, and display the value.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* etypes.c (krb5_enctypes_list): Fill in required_ctype field.
+	* mandatory_sumtype.c: New file.
+	* Makefile.in (SRCS, OBJS, STLIBOBJS): Build it.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* block_size.c (krb5_c_block_size): Read new numeric fields for
+	key/block/hash sizes instead of calling functions.
+	* checksum_length.c (krb5_c_checksum_length): Likewise.
+	* combine_keys.c (krb5int_c_combine_keys, dr): Likewise.
+	* hmac.c (krb5_hmac): Likewise.
+	* make_checksum.c (krb5_c_make_checksum): Likewise.
+	* make_random_key.c (krb5_c_make_random_key): Likewise.
+	* pbkdf2.c (hmac1): Likewise.
+	* string_to_key.c (krb5_c_string_to_key_with_params): Likewise.
+	* t_hmac.c (hmac1): Likewise.
+
+2003-07-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* pbkdf2.c (foo): Never call com_err.
+
+2003-06-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* checksum_length.c (krb5_c_checksum_length): Handle trunc_size.
+
+2003-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* cksumtypes.c (krb5_cksumtypes_list): Add aes128/256 hmacs, with
+	new trunc_size field.
+
+	* make_checksum.c (krb5_c_make_checksum): If trunc_size is
+	specified, shrink the computed checksum down to the indicated
+	size.
+
+2003-06-05  Sam Hartman  <hartmans@mit.edu>
+
+	* string_to_key.c (krb5_c_string_to_key_with_params): Only allow
+	AFS s2k  for DES enctypes
+
+2003-05-15  Sam Hartman  <hartmans@mit.edu>
+
+	* combine_keys.c (enctype_ok): new function to determine if we support combine_keys for a particular enctype
+
+2003-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* etypes.c (krb5_enctypes_list): Add names aes128-cts and
+	aes256-cts as aliases.
+
+2003-05-13  Sam Hartman  <hartmans@mit.edu>
+
+	* t_encrypt.c: Add aes enctypes
+
+2003-05-08  Sam Hartman  <hartmans@mit.edu>
+
+	* string_to_key.c: Move krb5_c_string_to_key_with_params to krb5.h
+
+2003-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* pbkdf2.c (krb5int_pbkdf2): Provide a temporary buffer for the
+	output from F, if the remaining space in the output buffer isn't
+	big enough.  Free the temporary buffers before returning.
+
+	* etypes.c (krb5_enctypes_list): Use krb5int_aes_encrypt_length,
+	and krb5int_aes_dk_encrypt, and krb5int_aes_dk_decrypt for AES.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+
+    * prng.c: use Unix randomness sources on Mac OS X.
+
+2003-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (OBJFILELIST, OBJFILEDEP) [##DOS]: Add aes.lst.
+	(all-windows, clean-windows, check-windows): Process aes
+	directory.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* etypes.c: Include aes_s2k.h.
+	(krb5_enctypes): Add AES enctypes.  Update s2k function names.
+	* pbkdf2.c (krb5int_pbkdf2): Now static.  Output data descriptor
+	is const.
+	(krb5int_pbkdf2_hmac_sha1_128, krb5int_pbkdf2_hmac_sha1_256):
+	Deleted.
+	* string_to_key.c (krb5_c_string_to_key_with_params): Renamed from
+	krb5_c_string_to_key, takes new params argument and passes it
+	through.  Declare before use.
+	(krb5_c_string_to_key): New function, passes null params.
+
+	* t_pkcs5.c (test_pbkdf2_rfc3211): Update calls to
+	krb5int_pbkdf2_hmac_sha1 for new API.
+	* vectors.c (test_mit_des_s2k): Update krb5_des_string_to_key call
+	for new API.
+	* Makefile.in: Update dependencies.
+
+2003-03-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* pbkdf2.c (F): Now takes krb5_data for password and salt.
+	(krb5int_pbkdf2, krb5int_pbkdf2_hmac_sha1,
+	krb5int_pbkdf2_hmac_sha1_128, krb5int_pbkdf2_hmac_sha1_256):
+	Likewise, and for output also.
+	* vectors.c (test_pbkdf2): Calls updated.
+	(main): Run pbkdf2 tests.
+
+2003-02-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes: New directory, containing AES implementation from Brian
+	Gladstone, tweaked a little for the krb5 build system.
+	* configure.in: Build its makefile.
+	* Makefile.in (LOCAL_SUBDIRS, LOCALINCLUDES, STOBJLISTS,
+	SUBDIROBJLISTS): Add aes entries.
+
+	* t_cts.c: New test file.
+	* Makefile.in (EXTRADEPSRCS): Add t_cts.
+	(t_cts$(EXEEXT)): New rule.
+
+	* Makefile.in (SRCS, OBJS, STLIBOBJS): Add pbkdf2.
+	(EXTRADEPSRCS): Remove pbkdf2.c.
+	(t_pkcs5$(EXEEXT)): Don't list pbkdf2.$(OBJEXT).
+
+	* t_nfold.c (fold_kerberos): New function.
+	(main): Call it with different lengths.
+	* vectors.c: Include ctype.h and hash_provider.h.
+	(test_nfold, test_mit_des_s2k, test_s2k, test_dr_dk): Test case
+	data now static and const.
+	(test_nfold): Add "Q" and "ba" tests from Simon Josefsson.
+	(GCLEF): New macro.
+	(test_mit_des_s2k): Add GCLEF test case.  Fill in "key" at run
+	time, not as initialization.
+	(test_s2k): Added GCLEF test case.
+	(krb5int_enc_aes128, krb5int_enc_aes256): Declare.
+	(combine_keys, test_des3_combine, k5_des3_make_key): Functions
+	deleted.
+	(whoami): New variable.
+	(printd, printk): New functions.
+	(test_pbkdf2): New function.
+	(main): Initialize whoami.  Test nfold only for now.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_ARCHIVE,
+	AC_PROG_ARCHIVE_ADD, AC_PROG_RANLIB, AC_PROG_INSTALL.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* pbkdf2.c, t_encrypt.c, t_hmac.c, t_nfold.c: Cleanup unused
+	variables. Signed vs unsigned cleanup. Ensure variables set before
+	use.
+
+2002-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* old_api_glue.c (krb5_encrypt, krb5_decrypt,
+	krb5_calculate_checksum, krb5_verify_checksum): Clean up use of
+	"const" in API.
+
+2002-12-06  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (clean): Clean up more test executables and object
+	files.
+
+2002-11-03  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* combine_keys.c: Fix up calling convention to match prototype
+	in k5-int.h
+
+2002-10-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (check-unix): Don't run t_pkcs5.
+
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* Makefile.in, combine_keys.c: New file to implement
+	key-combination algorithm.
+
+2002-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* pbkdf2.c, t_hmac.c, t_pkcs5.c: New files.
+	* Makefile.in (EXTRADEPSRCS): New variable.
+	(t_hmac$(EXEEXT), t_pkcs5$(EXEEXT), vectors$(EXEEXT)): New
+	targets.
+	(check-unix): Depend on and run t_hmac and t_pkcs5.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SUBDIROBJLISTS): New variable.
+
+2002-06-19  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (clean): Add t_prng and t_prng.o
+
+2002-06-07  Alexandra Ellwood <lxs@mit.edu>
+	
+	* crypto_libinit.h: Changed macros so you can include
+	crypto_libinit.h and krb5_libinit.h at the same time.
+	[pullup from 1-2-2-branch]
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* coll_proof_cksum.c (krb5_c_is_coll_proof_cksum): Rename function
+	from is_coll_proof_cksum, keeping old name as a wrapper function.
+	* keyed_cksum.c (krb5_c_is_keyed_cksum): Likewise.
+	* valid_cksumtype.c (krb5_c_valid_cksumtype): Likewise.
+	* valid_enctype.c (krb5_c_valid_enctype): Likewise.
+
+2002-03-28  Sam Hartman  <hartmans@mit.edu>
+
+	* t_encrypt.c (main): Test krb5_init_keyblock
+
+2002-01-14  Sam Hartman  <hartmans@mit.edu>
+
+	* t_prng.expected: Update to be correct for 0 MSW in v_i calculation.
+
+2002-01-08  Sam Hartman  <hartmans@tir-na-nogth.mit.edu>
+
+	* prng.c (krb5_c_random_os_entropy):  Implement.
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_encrypt.c (main): Free memory when finished to test for memory
+	leaks.
+
+2001-11-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (check-unix): Use $(srcdir) in file specification
+	for input to t_prng.
+
+2001-11-19  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (check-unix): Run t_prng
+
+2001-11-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do yarrow subdir on Windows.
+	
+2001-11-19  Sam Hartman  <hartmans@mit.edu>
+
+	* t_prng.c (main): Fix seeding bug in t_prng
+
+	* t_prng.reseedtest: New test; description in t_prng.reseedtest-comments
+
+	* t_prng.c (main): If we request 0 bytes of output don't try to
+	get output 
+
+2001-11-15  Sam Hartman  <hartmans@mit.edu>
+
+	* t_prng.c: New file for PRNG tests
+
+	* prng.c (krb5_c_random_seed): Deprecated in favor of
+	krb5_c_random_add_entropy 
+
+2001-11-14  Sam Hartman  <hartmans@mit.edu>
+
+	* prng.c :  adapt to yarrow
+
+2001-11-09  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in Makefile.in: Generate makefile for yarrow
+
+2001-11-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* state.c (krb5_c_init_state, krb5_c_free_state): Use
+	KRB5_CALLCONV.
+
+2001-11-06  Sam Hartman  <hartmans@tir-na-nogth.mit.edu>
+
+	* state.c: New file
+
+	* default_state.c: New file.
+
+2001-10-29  Jeff Altman   <jaltman@columbia.edu>
+
+        * Makefile.in - Windows configuration for src/lib/crypto/arcfour
+          directory
+
+2001-10-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_encrypt.c: Argument to krb5_c_encrypt_length must be size_t
+ 	instead of int (which is the length in krb5_data) or unaligned
+ 	access occurs on Dec OSF machines.
+
+2001-10-23  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (RUN_SETUP): Include so make check works correctly
+
+	* etypes.c: Add Heimdal aliases  arcfour-hmac-md5
+
+	* cksumtypes.c: hmac-md5-rc4 keyed checksum added
+
+	* etypes.c: arcfour-hmac enctype added
+
+	* configure.in Makefile.in :  New subdir: arcfour
+
+	* verify_checksum.c (krb5_c_verify_checksum): Add usage argument to verify call
+
+2001-10-22  Sam Hartman  <hartmans@mit.edu>
+
+	* make_checksum.c (krb5_c_make_checksum):  Include key usage
+
+2001-10-19  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (check-unix):  Run t_encrypt
+
+	* t_encrypt.c:  New file to contain generic encryption system
+	black-box tests ; currently primitive,  but useful for rc4 work
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* block_size.c, checksum_length.c, cksumtype_to_string.c,
+	coll_proof_cksum.c, decrypt.c, encrypt.c, encrypt_length.c,
+	enctype_compare.c, enctype_to_string.c, keyed_checksum_types.c,
+	keyed_cksum.c, make_checksum.c, make_random_key.c, old_api_glue.c,
+	prng.c, string_to_cksumtype.c, string_to_enctype.c,
+	string_to_key.c, valid_cksumtype.c, valid_enctype.c,
+	verify_checksum.c: Don't use KRB5_DLLIMP.  Don't explicitly
+	declare pointers FAR any more.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Use $(srcdir) not $(subdir).
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* crypto_libinit.c: Include crypto_libinit.h for prototypes.
+
+2001-07-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* vectors.c: Include string.h.
+	(printhex, printstringhex, printdata, printkey, test_nfold,
+	test_mit_des_s2k, test_s2k, test_des3_s2k, test_des3_combine): Now
+	static.
+	(test_nfold): Pass unsigned first arg to printhex.
+	(test_mit_des_s2k, test_s2k, combine_keys, test_des3_combine,
+	spew_keys, test_dr_dk): Change structure field initializations to
+	assignments, to be palatable to more compilers.
+	(test_s2k): Remove superfluous argument to printf.
+	(test_des3_combine): Return type is void.
+	(keyToData): Drop "inline" spec.
+	(main): Only run some of the tests.
+
+2001-06-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* vectors.c: New file.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_nfold.c (main): Cast argument to printf to be consistant with
+	format. 
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* make_checksum.c (krb5_c_make_checksum): Add cast assigning to
+	krb5_data data field.
+	* make_random_key.c (krb5_c_make_random_key): Likewise.
+	* hmac.c (krb5_hmac): Likewise.
+	* old-api_glue.c (krb5_init_random_key, krb5_decrypt_data):
+	Likewise.
+	* prng.c (krb5_c_make_random_octets): Likewise.
+	* verify_checksum.c (krb5_c_verify_checksum): Likewise.
+
+	* prng.c (krb5_c_random_seed): Cast argument to krb5_nfold.
+
+	* keyed_cksum.c (is_keyed_cksum): Use -1U to keep compiler quiet,
+	since return type is not signed.
+
+2001-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_nfold.c: Include assert.h.
+	(printhex, printstringhex, rfc_tests): New routines.
+	(ASIZE): New macro.
+	(main): Call rfc_tests.
+
+2001-03-10  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* make_random_key.c, old_api_glue.c: Do not use a variable named
+	random that might shadow a system header file definition.
+
+2001-03-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* cksumtypes.c, etypes.c, prng.c: Use krb5int_ prefix for internal
+	"provider" structures.
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* prng.c: Clean up some comments.
+	(enc): Use des3 now.
+
+	* decrypt.c, encrypt.c, hmac.c, make_checksum.c, nfold.c,
+	old_api_glue.c, string_to_key.c, verify_checksum.c: Use const
+	instead of krb5_const.
+
+2001-01-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* make_checksum.c (krb5_c_make_checksum): Clear checksum contents
+	pointer after freeing it in error case.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* nfold.c (krb5_nfold): inbots and outbits are now unsigned int. 
+
+	* prng.c: Local variable random_count is now unsigned int. 
+
+2000-06-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* crypto_libinit.c: Add prototype for prng_cleanup().
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* prng.c (prng_cleanup): Ensure memory allocated before calling free.
+
+2000-06-03  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in(LIBMAJOR, LIBMINOR): Bump library version.
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* configure.in, nfold.c: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-01-24  Tom Yu  <tlyu@mit.edu>
+
+	* crypto_libinit.c: Add terminating newline; use 0 and 1 instead
+	of false and true.
+
+Fri Jan 21 22:47:00 2000  Miro Jurisic  <meeroh@mit.edu>
+
+	* Makefile.in: added crypto_libinit.[co]
+	* crypto_libinit.[ch]: new files, contain library initialization
+		and cleanup code
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* cksumtypes.c (krb5_cksumtypes_list, krb5_cksumtypes_length): Now
+	const.
+	* cksumtypes.h (krb5_cksumtypes_list, krb5_cksumtypes_length):
+	Updated decls.
+	* etypes.c (krb5_enctypes_list, krb5_enctypes_length): Now const.
+	* etypes.h (krb5_enctypes_list, krb5_enctypes_length): Updated
+	decls.
+	* make_random_key.c (krb5_c_make_random_key): Pointers to
+	enc_provider table now point to const.
+	* prng.c (enc): Now static and const, and points to const.
+	* string_to_key.c (krb5_c_string_to_key): Ditto.
+
+	* hmac.c (krb5_hmac): Put extra parens around if(a=b) constructs
+	to keep gcc happy.
+	* make_random_key.c (krb5_c_make_random_key): Ditto.
+	* old_api_glue.c (krb5_encrypt, krb5_decrypt, krb5_random_key,
+	krb5_calculate_checksum, krb5_verify_checksum, krb5_encrypt_data,
+	krb5_decrypt_data): Ditto.
+	* prng.c (krb5_c_random_make_octets): Ditto.
+	* string_to_key.c (krb5_c_string_to_key): Ditto.
+	* verify_checksum.c (krb5_c_verify_checksum): Ditto.
+
+	* make_checksum.c: Include dk.h.
+
+	* nfold.c (krb5_nfold): Delete unused variables.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-26  Tom Yu  <tlyu@mit.edu>
+
+	* etypes.c: Add aliases "des" for "des-cbc-md5", "des3-hmac-sha1"
+	and "des3-cbc-sha1-kd" for "des3-cbc-sha1".
+
+	* cksumtypes.c: Add alias "hmac-sha1-des3-kd".
+
+1999-08-18  Tom Yu  <tlyu@mit.edu>
+
+	* etypes.c: Update des3-cbc-sha1 to alignt with new number
+	assignments.
+
+	* cksumtypes.c: Update hmac-sha1-des3 to align with new number
+	assignments.
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+Mon May 10 15:15:00 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Tue Jan  5 00:06:02 1999  Tom Yu  <tlyu@mit.edu>
+
+	* make_checksum.c (krb5_c_make_checksum): Note the fact that we're
+	punting on dealing with backwards compat with length-included
+	checksums.
+
+	* etypes.c: Add ENCTYPE_LOCAL_DES3_HMAC_SHA1 as a temporary
+	kludge.  Note that this is added to the end of the array so other
+	code can lop off the last member of the array and the right thing
+	will happen so that it is possible to disable des3-marc-hmac-sha1
+	from the KDC command line, for instance.
+
+	* configure.in: Conditionalize ATHENA_DES3_KLUDGE on
+	--enable-athena.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Thu Dec  3 23:37:28 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Added missing "cd .." necessary for making this
+ 		compile under Windows.  Also added missing *.lst files to
+ 		OBJFILELIST.
+
+Fri Nov  6 10:23:32 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* keyhash_provider/Makefile.in: Fix to allow building out of the
+ 	source tree.
+
+Tue Sep 22 21:19:01 1998  Tom Yu  <tlyu@mit.edu>
+
+	* prng.c (krb5_c_random_make_octets): Fix to nfold into 15 bytes,
+	not one byte.
+
+Mon Sep 21 15:23:19 1998  Tom Yu  <tlyu@mit.edu>
+
+	* prng.c (krb5_c_random_seed): Fix memory leak.
+
+Mon Sep 14 23:21:17 1998  Tom Yu  <tlyu@mit.edu>
+
+	* old/decrypt.c (krb5_old_decrypt): Fix memory leak.
+
+Tue Sep  1 19:33:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* etypes.c: Add ETYPE_LOCAL_DES3_HMAC_SHA1 to deal with marc's
+	des3 code.  ETYPE_DES3_HMAC_SHA1 remains the same for now.
+
+Mon Aug 17 23:40:11 1998  Tom Yu  <tlyu@mit.edu>
+
+	* keyhash_provider/k5_md4des.c (k5_md4des_verify): Add
+	compatibility for krb5-beta5 checksums.
+
+	* keyhash_provider/k5_md5des.c (k5_md5des_verify): Add
+	compatibility for krb5-beta5 checksums.  Fix typos similar to
+	those corrected in k5_md4des.c.
+
+Sun Jul 19 12:00:00 1998  Marc Horowitz <marc@mit.edu>
+
+	* *.c: replace the crypto layer.
+
+Wed Apr 15 18:02:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (LIB): Rename to k5crypto.
+
+Wed Feb 18 16:05:11 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 15:19:37 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define LOCAL_SUBDIRS to recurse into the
+		subdirectories (crc32, md5, os, etc.)
+
+	* configure.in: Create the makefiles for all of the subdirectories
+		and move all of the configure.in tests from the
+		subdirectories into this configure.in.
+	
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Oct 14 15:34:44 1997  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in: Bump major version due to possible size changes.
+
+Fri Feb 21 18:40:13 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (OBJS): Move in crypto_glue.c as krb5_glue.c; avoid
+        libcrypto depending on libkrb5
+     
+
+Sat Feb 22 01:37:23 1997  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+	* Makefile.in (LIBMINOR): Bump minor version
+
+Sun Dec 29 21:52:44 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to use new library build procedure.
+
+Sat Nov 23 00:22:20 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* cryptoconf.c: Also zero out the entries in cryptoconf, to make
+		sure no one tries to use triple DES and SHA.
+
+Fri Nov 22 20:49:13 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in (enableval): Disable triple DES and SHA, since
+		what's there isn't the final triple DES.  [PR#231]
+
+Mon Nov 18 20:38:24 1996  Ezra Peisach  <epeisach@mit.edu>
+ [krb5-libs/201]
+	* configure.in: Set shared library version to 1.0.
+
+Thu Jun  6 00:04:38 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Don't pass $(LIBCMD) on the command
+		line.  It's set in the windows.in prologue for all Makefiles anyway.
+
+Thu Jun  6 00:03:05 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Include sha in the list of
+		subdirectories for the Macintosh
+
+Mon May 20 10:59:23 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* Makefile.in (libcrypto.$(STEXT): deal with new improved
+		libupdate
+
+Sat May 18 13:34:01 1996  Ezra Peisach  (epeisach@paris)
+
+	* des3_sha.c: Add static keywords in function declarartions to
+		match earlier declarations. 
+
+Tue May 14 15:14:20 1996  Richard Basch  <basch@lehman.com>
+
+	* cryptoconf.c:
+		replaced sha-des3 cksum with hmac-sha
+
+	* des_crc.c des_md5.c:
+		set the length field of the cksum structure.
+
+	* des3_sha.c:
+		Increase the confounder length to 24 bytes.
+		Set the length of the cksum structure.
+
+Fri May 10 01:34:46 1996  Richard Basch  <basch@lehman.com>
+
+	* configure.in cryptoconf.c des3_sha.c:
+	Support enctype-des3-sha, cksum-sha, cksum-sha-des3
+
+	* Removed des3_md5.c (and all des3-md5 support).
+
+Tue Apr 30 00:38:14 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* Makefile.in (libcrypto.$(STEXT)): Remove before creating.
+
+Thu May  2 18:48:35 1996  Richard Basch  <basch@lehman.com>
+
+	* des3_md5.c des3_raw.c: use the new common random routines for
+		des & des3 (the old des3 routines have been removed)
+
+Sat Mar 30 22:52:46 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* cryptoconf.c: Fixed comments describing the various checksum
+	        types.  (Added numbers, and fixed a mistake in a
+		description of an undefined checksum type.)
+
+Thu Mar 28 09:49:08 1996  Richard Basch  <basch@lehman.com>
+
+	* cryptoconf.c: Added support for CKSUMTYPE_RSA_MD5_DES3 and
+		ENCTYPE_DES3_CBC_RAW
+
+	* des3_md5.c: Abstraction correction: use sizeof(mit_des3_cblock)
+
+	* configure.in:
+		Cosmetic renaming of des-cbc-raw configuration vars.
+		Added support for des3-cbc-raw.
+
+	* des3_raw.c: New file (support ENCTYPE_DES3_CBC_RAW)
+
+Mon Mar 11 10:59:40 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* des_crc.c (mit_des_crc_decrypt_func): Add const to pointer
+		cast for suncc warning.
+
+Wed Feb  7 00:23:18 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Mon Nov 13 11:30:10 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* encrypt_data.c (krb5_encrypt_data): New file.  A generic routine
+		for encrypting data in a krb5_data structure.  Fills in a
+		krb5_enc_data structure.
+
+	* decrypt_data.c (krb5_decrypt_data): New file.  A generic routine
+		for decrypting data in a krb5_enc_data structure.  Fills
+		in a krb5_data structure.
+
+	* Makefile.in (SRCS): Added decrypt_data.c and encrypt_data.c to
+		list of files to be compiled.
+
+Fri Oct  6 22:01:04 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Thu Oct  5 21:32:33 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* cryptoconf.c: Change types of krb5_max_enctype and
+		krb5_max_cksumtype to be krb5_enctype and krb5_cksumtype,
+		to fix some gcc -Wall flames.
+
+Mon Oct  2 10:34:12 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in (V5_MAKE_SHARED_LIB): Change for version 0.1 of
+		shared library. Remove install lines which are in aclocal.m4
+
+Mon Sep 25 16:26:53 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+	* configure.in: Don't include "all:: all-$(WHAT)" at the end of
+		the Makefile.  That's now included at the very beginning
+		by pre.in
+
+Wed Sep 13 10:26:37 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: moved shared rule to all-unix:: target.
+	* des_crc.c, des_md5.c, raw_des.c: had a volatile/const mismatch
+	   which needs a cast to resolve.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * cryptoconf.c, des_crc.c, des_md5.c raw_des.c
+		s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * cryptoconf.c : Remove krb5_csarray.
+	* cryptoconf.c, des_crc.c, des_md5.c, raw_des.c : Remove krb5_enctype 
+		references, and replace with krb5_keytype where appropriate.
+
+Thu Aug 24 17:55:47 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* des_crc.c, des_md5.c, raw_des.c: Remove casting in call to
+		mit_des_cbc_encrypt. 
+
+Thu Jul 27 15:15:46 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add --enable-{des-cbc-md5,des-cbc-crc,raw-des-cbc,
+		des-cbc-cksum,crc32,rsa-md4,rsa-md5} which set the appropriate
+		preprocessor flags which used to be set in k5-config.h.
+	* cryptoconf.c - Set the KEYTYPE_DES entry to the DES-CBC-MD5 entry
+		if enabled, then the DES-CBC-CRC entry, if enabled, then to
+		null.
+
+Fri Jun 23 12:16:52 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* configure.in: krb5_cv_staticlibs_enabled, not
+        krb5_cv_enable_staticlibs
+
+Thu Jun 22 18:34:26 1995  Sam Hartman  (hartmans@tardis)
+
+	* configure.in: Changed to new scheme for static libs.
+
+
+
+Fri Jun 16 11:14:50 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add install target for shared library.
+
+
+Thu Jun 15 17:58:41 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add definitions for shared library building rules.
+		Add explicit dependency on "shared" since we probably need it.
+	* configure.in - Create symlinks for archive and shared library when
+		we build them.
+
+Fri Jun  9 18:52:19 1995    <tytso@rsx-11.mit.edu>
+
+	* des_crc.c, des_md5.c: Fix -Wall nits.
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Thu May 25 22:15:18 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for shared libraries.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+        * *.h added FAR to pointers visible at to the world.
+
+Tue Mar 28 20:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: more of nmake's strange behavior. Problem goes
+	   away with the addition of a nop line.
+
+Wed Mar 22 11:28:08 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: put back '##DOSLIBNAME' since it makes the .c.obj rule
+	   put the object file into that library.
+	* Makefile.in: strange nmake error 'missing ) on macro invocation' 
+	   which only appeared intermitantly and only when invoked 
+           recursively. Fixed (I hope) by interchanging some lines.
+
+Thu Mar 16 21:10:37 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (CFLAGS):  Avoid continuation line that starts with
+	dash; it confuses the Unix->MPW makefile converter.
+	(##DOSLIBNAME):  No longer needed since DLL built one level up.
+	(all-mac):  Add.
+	(libcrypto.a):  Use explicit "./" on paths to DONE files, to
+	help Unix->MPW makefile converter with rotten Mac pathname conventions.
+
+Wed Mar 15 20:23:17 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: cleaned up for the PC
+
+Tue Mar 14 17:31:01 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: removed all DLL stuff--it now happens up a directory.
+	* win_glue.c, libcrypto.def: removed
+
+Tue Mar 7 17:26:06 1995 Keith Vetter (keithv@fusion.com)
+
+	* cryptoco.c: Added more windows syntactic sugar for segmenting.
+
+Fri Mar 3 19:15:54 1995 Keith Vetter (keithv@fusion.com)
+
+	* libcrypto.def: added 3 entry points for methods for pulling
+           in data from a DLL.
+        * Makefile.in: libcrypto.lib depends upon libcrypto.def
+
+Thu Mar 2 17:43:25 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: added rules to make a DLL from a lib.
+        * win_glue.c, librcrypto.def: needed for making a DLL.
+
+Tue Feb 28 00:15:06 1995  John Gilmore  (gnu at toad.com)
+
+	* cryptoconf.c, des_md5.c:  Avoid <krb5/...> includes.
+
+Fri Feb  3 02:44:07 1995  John Gilmore  <gnu@cygnus.com>
+
+	Rename files so that they work in the DOS LIB command,
+	which amazingly finds dashes in mid-name and treats them
+	like option switches.
+
+	* des-crc.c => des_crc.c
+	* des-md5.c => des_md5.c
+	* raw-des.c => raw_des.c
+	* Makefile.in:  changed to match.
+
+Thu Feb  2 02:59:58 1995  John Gilmore  <gnu@cygnus.com>
+
+	* Makefile.in (CFLAGS):  Handle $(srcdir) properly in -I options.
+
+Wed Jan 25 19:55:59 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (CFLAGS):  Add -I options to pick up include files
+	from the various algorithm subdirs.
+	* cryptoconf.c, des-crc.c, des-md5.c, raw-des.c:  Replace most
+	<.../...> include files with "..." includes.
+
+Tue Oct 18 15:46:01 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* des-crc.c (mit_des_crc_decrypt_func): cast key->key->contents to
+	krb5_pointer to satisfy sunos cc about :? argument types.
+	(mit_des_crc_encrypt_funct): ditto.
+	* raw-des.c (mit_raw_des_decrypt_func): ditto.
+	(mit_raw_des_encrypt_func): ditto.
+	* des-md5.c (mit_des_md5_decrypt_funct): cast zero_ivec.
+	(mit_des_md5_encrypt_funct): ditto.
+
+Fri Oct 14 00:37:08 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+    	* cryptoconf.c: Add support for the new cryptosystem DES/MD5.
+
+	* Makefile.in: Add support for new files des-crc.c, des-md5.c, and
+		raw-des.c
+
+Thu Oct  6 20:07:41 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add recursive "make check" target.
+
+Mon Oct  3 21:11:56 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR)
+
+Thu Aug  4 03:40:24 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: oops check for install
+
+	* Makefile.in: make install fixes
+
diff --git a/mechglue/src/lib/crypto/ISSUES b/mechglue/src/lib/crypto/ISSUES
new file mode 100644
index 000000000..c2122805d
--- /dev/null
+++ b/mechglue/src/lib/crypto/ISSUES
@@ -0,0 +1,16 @@
+Issues to be addressed for src/lib/crypto: -*- text -*-
+
+Many files here and in subdirectories pollute the namespace.
+However, some applications wanting to directly use some of those
+routines will expect those names to be available.
+
+Workaround: Shared library export lists?  Define and export internal
+names, and provide wrapper library code or weak functions under the
+polluting names?
+
+Some routines assume "int" is big enough to describe all buffers that
+may be supplied.
+
+The prng here is poor.  It should not use n-fold as a mixing function,
+because it's possible that the input will be structured in some way
+that may interact poorly with the n-fold algorithm.
diff --git a/mechglue/src/lib/crypto/Makefile.in b/mechglue/src/lib/crypto/Makefile.in
new file mode 100644
index 000000000..ed2e103b3
--- /dev/null
+++ b/mechglue/src/lib/crypto/Makefile.in
@@ -0,0 +1,643 @@
+thisconfigdir=.
+myfulldir=lib/crypto
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCAL_SUBDIRS=crc32 des dk enc_provider hash_provider keyhash_provider \
+	md4 md5 old raw sha1 arcfour yarrow aes
+LOCALINCLUDES = -I$(srcdir)/enc_provider \
+	-I$(srcdir)/hash_provider -I$(srcdir)/keyhash_provider \
+	-I$(srcdir)/aes \
+	-I$(srcdir)/old -I$(srcdir)/raw -I$(srcdir)/dk -I$(srcdir)/arcfour \
+	-I$(srcdir)/yarrow -I$(srcdir)/sha1
+RUN_SETUP = @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+EXTRADEPSRCS=\
+	$(srcdir)/t_nfold.c	\
+	$(srcdir)/t_encrypt.c	\
+	$(srcdir)/t_prf.c \
+	$(srcdir)/t_prng.c	\
+	$(srcdir)/t_hmac.c	\
+	$(srcdir)/t_pkcs5.c	\
+	$(srcdir)/t_cts.c	\
+	$(srcdir)/vectors.c
+
+##DOSBUILDTOP = ..\..
+##DOSLIBNAME=$(OUTPRE)crypto.lib
+##DOSOBJFILE=$(OUTPRE)crypto.lst
+##DOSOBJFILELIST=@$(OUTPRE)crypto.lst @$(OUTPRE)des.lst @$(OUTPRE)md4.lst @$(OUTPRE)md5.lst @$(OUTPRE)sha1.lst @$(OUTPRE)arcfour.lst @$(OUTPRE)crc32.lst @$(OUTPRE)dk.lst @$(OUTPRE)old.lst @$(OUTPRE)raw.lst @$(OUTPRE)enc_prov.lst @$(OUTPRE)hash_pro.lst @$(OUTPRE)kh_pro.lst @$(OUTPRE)yarrow.lst @$(OUTPRE)aes.lst
+##DOSOBJFILEDEP =$(OUTPRE)crypto.lst $(OUTPRE)des.lst $(OUTPRE)md4.lst $(OUTPRE)md5.lst $(OUTPRE)sha1.lst $(OUTPRE)arcfour.lst $(OUTPRE)crc32.lst $(OUTPRE)dk.lst $(OUTPRE)old.lst $(OUTPRE)raw.lst $(OUTPRE)enc_prov.lst $(OUTPRE)hash_pro.lst $(OUTPRE)kh_pro.lst $(OUTPRE)aes.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+STLIBOBJS=\
+	block_size.o		\
+	checksum_length.o	\
+	cksumtype_to_string.o	\
+	cksumtypes.o		\
+	coll_proof_cksum.o	\
+	combine_keys.o	\
+	crypto_libinit.o	\
+	default_state.o \
+	decrypt.o		\
+	encrypt.o		\
+	encrypt_length.o	\
+	enctype_compare.o	\
+	enctype_to_string.o	\
+	etypes.o		\
+	hmac.o			\
+	keyblocks.o \
+	keyed_cksum.o		\
+	keyed_checksum_types.o	\
+	make_checksum.o		\
+	make_random_key.o	\
+	mandatory_sumtype.o	\
+	nfold.o			\
+	old_api_glue.o		\
+	pbkdf2.o		\
+	prf.o \
+	prng.o			\
+	state.o \
+	string_to_cksumtype.o	\
+	string_to_enctype.o	\
+	string_to_key.o		\
+	valid_cksumtype.o	\
+	valid_enctype.o		\
+	verify_checksum.o
+
+OBJS=\
+	$(OUTPRE)block_size.$(OBJEXT)		\
+	$(OUTPRE)checksum_length.$(OBJEXT)	\
+	$(OUTPRE)cksumtype_to_string.$(OBJEXT)	\
+	$(OUTPRE)cksumtypes.$(OBJEXT)		\
+	$(OUTPRE)coll_proof_cksum.$(OBJEXT)	\
+	$(OUTPRE)combine_keys.$(OBJEXT)	\
+	$(OUTPRE)crypto_libinit.$(OBJEXT)	\
+	$(OUTPRE)default_state.$(OBJEXT) \
+	$(OUTPRE)decrypt.$(OBJEXT)		\
+	$(OUTPRE)encrypt.$(OBJEXT)		\
+	$(OUTPRE)encrypt_length.$(OBJEXT)	\
+	$(OUTPRE)enctype_compare.$(OBJEXT)	\
+	$(OUTPRE)enctype_to_string.$(OBJEXT)	\
+	$(OUTPRE)etypes.$(OBJEXT)		\
+	$(OUTPRE)hmac.$(OBJEXT)			\
+	$(OUTPRE)keyblocks.$(OBJEXT) \
+	$(OUTPRE)keyed_cksum.$(OBJEXT)		\
+	$(OUTPRE)keyed_checksum_types.$(OBJEXT)	\
+	$(OUTPRE)make_checksum.$(OBJEXT)	\
+	$(OUTPRE)make_random_key.$(OBJEXT)	\
+	$(OUTPRE)mandatory_sumtype.$(OBJEXT)	\
+	$(OUTPRE)nfold.$(OBJEXT)		\
+	$(OUTPRE)old_api_glue.$(OBJEXT)		\
+	$(OUTPRE)pbkdf2.$(OBJEXT)		\
+	$(OUTPRE)prf.$(OBJEXT) \
+	$(OUTPRE)prng.$(OBJEXT)			\
+	$(OUTPRE)state.$(OBJEXT) \
+	$(OUTPRE)string_to_cksumtype.$(OBJEXT)	\
+	$(OUTPRE)string_to_enctype.$(OBJEXT)	\
+	$(OUTPRE)string_to_key.$(OBJEXT)	\
+	$(OUTPRE)valid_cksumtype.$(OBJEXT)	\
+	$(OUTPRE)valid_enctype.$(OBJEXT)	\
+	$(OUTPRE)verify_checksum.$(OBJEXT)
+
+SRCS=\
+	$(srcdir)/block_size.c		\
+	$(srcdir)/checksum_length.c	\
+	$(srcdir)/cksumtype_to_string.c	\
+	$(srcdir)/cksumtypes.c		\
+	$(srcdir)/coll_proof_cksum.c	\
+	$(srcdir)/combine_keys.c	\
+	$(srcdir)/crypto_libinit.c	\
+	$(srcdir)/default_state.c \
+	$(srcdir)/decrypt.c		\
+	$(srcdir)/encrypt.c		\
+	$(srcdir)/encrypt_length.c	\
+	$(srcdir)/enctype_compare.c	\
+	$(srcdir)/enctype_to_string.c	\
+	$(srcdir)/etypes.c		\
+	$(srcdir)/hmac.c		\
+	$(srcdir)/keyblocks.c \
+	$(srcdir)/keyed_cksum.c		\
+	$(srcdir)/keyed_checksum_types.c\
+	$(srcdir)/make_checksum.c	\
+	$(srcdir)/make_random_key.c	\
+	$(srcdir)/mandatory_sumtype.c	\
+	$(srcdir)/nfold.c		\
+	$(srcdir)/old_api_glue.c	\
+	$(srcdir)/pbkdf2.c	\
+	$(srcdir)/prf.c \
+	$(srcdir)/prng.c		\
+	$(srcdir)/state.c \
+	$(srcdir)/string_to_cksumtype.c	\
+	$(srcdir)/string_to_enctype.c	\
+	$(srcdir)/string_to_key.c	\
+	$(srcdir)/valid_cksumtype.c	\
+	$(srcdir)/valid_enctype.c	\
+	$(srcdir)/verify_checksum.c
+
+
+LIBBASE=k5crypto
+LIBMAJOR=3
+LIBMINOR=0
+LIBINITFUNC=cryptoint_initialize_library
+LIBFINIFUNC=cryptoint_cleanup_library
+RELDIR=crypto
+
+STOBJLISTS=crc32/OBJS.ST des/OBJS.ST dk/OBJS.ST enc_provider/OBJS.ST \
+	hash_provider/OBJS.ST keyhash_provider/OBJS.ST md4/OBJS.ST \
+	md5/OBJS.ST old/OBJS.ST raw/OBJS.ST sha1/OBJS.ST arcfour/OBJS.ST \
+	aes/OBJS.ST \
+	yarrow/OBJS.ST \
+	OBJS.ST
+SUBDIROBJLISTS=crc32/OBJS.ST des/OBJS.ST dk/OBJS.ST enc_provider/OBJS.ST \
+	hash_provider/OBJS.ST keyhash_provider/OBJS.ST md4/OBJS.ST \
+	md5/OBJS.ST old/OBJS.ST raw/OBJS.ST sha1/OBJS.ST arcfour/OBJS.ST \
+	aes/OBJS.ST \
+	yarrow/OBJS.ST
+
+# No dependencies.  Record places to find this shared object if the target
+# link editor and loader support it.
+DEPLIBS=
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_EXPLIBS= $(SUPPORT_LIB) $(LIBS)
+SHLIB_EXPDEPLIBS= $(SUPPORT_DEPLIB)
+SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@
+SHLIB_LIBDIRS= @SHLIB_LIBDIRS@
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-liblinks
+install-unix:: install-libs
+
+libcrypto.lib:
+	libdir crypto.lib
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+check-unix:: t_nfold t_encrypt t_prf t_prng t_hmac t_pkcs5
+	$(RUN_SETUP) ./t_nfold
+	$(RUN_SETUP) ./t_encrypt
+	$(RUN_SETUP) ./t_prng <$(srcdir)/t_prng.seed >t_prng.output && \
+	diff t_prng.output $(srcdir)/t_prng.expected
+	$(RUN_SETUP) ./t_hmac
+
+#	$(RUN_SETUP) ./t_pkcs5
+
+t_nfold$(EXEEXT): t_nfold.$(OBJEXT) nfold.$(OBJEXT) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_nfold.$(OBJEXT) nfold.$(OBJEXT) $(SUPPORT_LIB)
+
+t_encrypt$(EXEEXT): t_encrypt.$(OBJEXT) nfold.$(OBJEXT) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_encrypt.$(OBJEXT)  -lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB)
+
+t_prf$(EXEEXT): t_prf.$(OBJEXT) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_prf.$(OBJEXT)  -lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB)
+
+t_prng$(EXEEXT): t_prng.$(OBJEXT) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_prng.$(OBJEXT)  -lk5crypto -lcom_err $(SUPPORT_LIB)
+
+t_hmac$(EXEEXT): t_hmac.$(OBJEXT) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_hmac.$(OBJEXT) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB)
+
+t_pkcs5$(EXEEXT): t_pkcs5.$(OBJEXT) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_pkcs5.$(OBJEXT) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB)
+
+vectors$(EXEEXT): vectors.$(OBJEXT) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ vectors.$(OBJEXT) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB)
+
+t_cts$(EXEEXT): t_cts.$(OBJEXT) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_cts.$(OBJEXT) \
+		$(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB)
+
+
+clean::
+	$(RM) t_nfold.o t_nfold t_encrypt t_encrypt.o t_prng.o t_prng \
+		t_hmac.o t_hmac t_pkcs5.o t_pkcs5 pbkdf2.o
+	-$(RM) t_prng.output
+
+all-windows::
+	cd crc32
+	@echo Making in crypto\crc32
+	$(MAKE) -$(MFLAGS)
+	cd ..\des
+	@echo Making in crypto\des
+	$(MAKE) -$(MFLAGS)
+	cd ..\dk
+	@echo Making in crypto\dk
+	$(MAKE) -$(MFLAGS)
+	cd ..\enc_provider
+	@echo Making in crypto\enc_provider
+	$(MAKE) -$(MFLAGS)
+	cd ..\hash_provider
+	@echo Making in crypto\hash_provider
+	$(MAKE) -$(MFLAGS)
+	cd ..\keyhash_provider
+	@echo Making in crypto\keyhash_provider
+	$(MAKE) -$(MFLAGS)
+	cd ..\md4
+	@echo Making in crypto\md4
+	$(MAKE) -$(MFLAGS)
+	cd ..\md5
+	@echo Making in crypto\md5
+	$(MAKE) -$(MFLAGS)
+	cd ..\old
+	@echo Making in crypto\old
+	$(MAKE) -$(MFLAGS)
+	cd ..\raw
+	@echo Making in crypto\raw
+	$(MAKE) -$(MFLAGS)
+	cd ..\sha1
+	@echo Making in crypto\sha1
+	$(MAKE) -$(MFLAGS)
+	cd ..\arcfour
+	@echo Making in crypto\arcfour
+	$(MAKE) -$(MFLAGS)
+	cd ..\yarrow
+	@echo Making in crypto\yarrow
+	$(MAKE) -$(MFLAGS)
+	cd ..\aes
+	@echo Making in crypto\aes
+	$(MAKE) -$(MFLAGS)
+	cd ..
+
+clean-windows::
+	cd crc32
+	@echo Making in clean crypto\crc32
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\des
+	@echo Making clean in crypto\des
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\dk
+	@echo Making clean in crypto\dk
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\enc_provider
+	@echo Making clean in crypto\enc_provider
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\hash_provider
+	@echo Making clean in crypto\hash_provider
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\keyhash_provider
+	@echo Making clean in crypto\keyhash_provider
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\md4
+	@echo Making clean in crypto\md4
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\md5
+	@echo Making clean in crypto\md5
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\old
+	@echo Making clean in crypto\old
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\raw
+	@echo Making clean in crypto\raw
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\sha1
+	@echo Making clean in crypto\sha1
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\arcfour
+	@echo Making clean in crypto\arcfour
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\yarrow
+	@echo Making clean in crypto\yarrow
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\aes
+	@echo Making clean in crypto\aes
+	$(MAKE) -$(MFLAGS) clean
+	cd ..
+
+check-windows::
+	cd crc32
+	@echo Making in check crypto\crc32
+	$(MAKE) -$(MFLAGS) check
+	cd ..\des
+	@echo Making check in crypto\des
+	$(MAKE) -$(MFLAGS) check
+	cd ..\dk
+	@echo Making check in crypto\dk
+	$(MAKE) -$(MFLAGS) check
+	cd ..\enc_provider
+	@echo Making check in crypto\enc_provider
+	$(MAKE) -$(MFLAGS) check
+	cd ..\hash_provider
+	@echo Making check in crypto\hash_provider
+	$(MAKE) -$(MFLAGS) check
+	cd ..\keyhash_provider
+	@echo Making check in crypto\keyhash_provider
+	$(MAKE) -$(MFLAGS) check
+	cd ..\md4
+	@echo Making check in crypto\md4
+	$(MAKE) -$(MFLAGS) check
+	cd ..\md5
+	@echo Making check in crypto\md5
+	$(MAKE) -$(MFLAGS) check
+	cd ..\old
+	@echo Making check in crypto\old
+	$(MAKE) -$(MFLAGS) check
+	cd ..\raw
+	@echo Making check in crypto\raw
+	$(MAKE) -$(MFLAGS) check
+	cd ..\sha1
+	@echo Making check in crypto\sha1
+	$(MAKE) -$(MFLAGS) check
+	cd ..\arcfour
+	@echo Making check in crypto\arcfour
+	$(MAKE) -$(MFLAGS) check
+	cd ..\yarrow
+	@echo Making check in crypto\yarrow
+	$(MAKE) -$(MFLAGS) check
+	cd ..\aes
+	@echo Making check in crypto\aes
+	$(MAKE) -$(MFLAGS) check
+	cd ..
+
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+block_size.so block_size.po $(OUTPRE)block_size.$(OBJEXT): \
+  block_size.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+checksum_length.so checksum_length.po $(OUTPRE)checksum_length.$(OBJEXT): \
+  checksum_length.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cksumtypes.h
+cksumtype_to_string.so cksumtype_to_string.po $(OUTPRE)cksumtype_to_string.$(OBJEXT): \
+  cksumtype_to_string.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cksumtypes.h
+cksumtypes.so cksumtypes.po $(OUTPRE)cksumtypes.$(OBJEXT): \
+  cksumtypes.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/hash_provider/hash_provider.h $(srcdir)/keyhash_provider/keyhash_provider.h \
+  cksumtypes.h
+coll_proof_cksum.so coll_proof_cksum.po $(OUTPRE)coll_proof_cksum.$(OBJEXT): \
+  coll_proof_cksum.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cksumtypes.h
+combine_keys.so combine_keys.po $(OUTPRE)combine_keys.$(OBJEXT): \
+  combine_keys.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h $(srcdir)/dk/dk.h
+crypto_libinit.so crypto_libinit.po $(OUTPRE)crypto_libinit.$(OBJEXT): \
+  crypto_libinit.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+default_state.so default_state.po $(OUTPRE)default_state.$(OBJEXT): \
+  default_state.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+decrypt.so decrypt.po $(OUTPRE)decrypt.$(OBJEXT): decrypt.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+encrypt.so encrypt.po $(OUTPRE)encrypt.$(OBJEXT): encrypt.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+encrypt_length.so encrypt_length.po $(OUTPRE)encrypt_length.$(OBJEXT): \
+  encrypt_length.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+enctype_compare.so enctype_compare.po $(OUTPRE)enctype_compare.$(OBJEXT): \
+  enctype_compare.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+enctype_to_string.so enctype_to_string.po $(OUTPRE)enctype_to_string.$(OBJEXT): \
+  enctype_to_string.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+etypes.so etypes.po $(OUTPRE)etypes.$(OBJEXT): etypes.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/enc_provider/enc_provider.h $(srcdir)/hash_provider/hash_provider.h \
+  etypes.h $(srcdir)/old/old.h $(srcdir)/raw/raw.h $(srcdir)/dk/dk.h \
+  $(srcdir)/arcfour/arcfour.h $(srcdir)/aes/aes_s2k.h
+hmac.so hmac.po $(OUTPRE)hmac.$(OBJEXT): hmac.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h
+keyblocks.so keyblocks.po $(OUTPRE)keyblocks.$(OBJEXT): \
+  keyblocks.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+keyed_cksum.so keyed_cksum.po $(OUTPRE)keyed_cksum.$(OBJEXT): \
+  keyed_cksum.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cksumtypes.h
+keyed_checksum_types.so keyed_checksum_types.po $(OUTPRE)keyed_checksum_types.$(OBJEXT): \
+  keyed_checksum_types.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h cksumtypes.h
+make_checksum.so make_checksum.po $(OUTPRE)make_checksum.$(OBJEXT): \
+  make_checksum.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cksumtypes.h etypes.h $(srcdir)/dk/dk.h
+make_random_key.so make_random_key.po $(OUTPRE)make_random_key.$(OBJEXT): \
+  make_random_key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+mandatory_sumtype.so mandatory_sumtype.po $(OUTPRE)mandatory_sumtype.$(OBJEXT): \
+  mandatory_sumtype.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+nfold.so nfold.po $(OUTPRE)nfold.$(OBJEXT): nfold.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+old_api_glue.so old_api_glue.po $(OUTPRE)old_api_glue.$(OBJEXT): \
+  old_api_glue.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+pbkdf2.so pbkdf2.po $(OUTPRE)pbkdf2.$(OBJEXT): pbkdf2.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/hash_provider/hash_provider.h
+prf.so prf.po $(OUTPRE)prf.$(OBJEXT): prf.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h etypes.h
+prng.so prng.po $(OUTPRE)prng.$(OBJEXT): prng.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/enc_provider/enc_provider.h \
+  $(srcdir)/yarrow/yarrow.h $(srcdir)/yarrow/ytypes.h \
+  $(srcdir)/yarrow/yhash.h $(srcdir)/sha1/shs.h $(srcdir)/yarrow/ycipher.h
+state.so state.po $(OUTPRE)state.$(OBJEXT): state.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+string_to_cksumtype.so string_to_cksumtype.po $(OUTPRE)string_to_cksumtype.$(OBJEXT): \
+  string_to_cksumtype.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cksumtypes.h
+string_to_enctype.so string_to_enctype.po $(OUTPRE)string_to_enctype.$(OBJEXT): \
+  string_to_enctype.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+string_to_key.so string_to_key.po $(OUTPRE)string_to_key.$(OBJEXT): \
+  string_to_key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+valid_cksumtype.so valid_cksumtype.po $(OUTPRE)valid_cksumtype.$(OBJEXT): \
+  valid_cksumtype.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cksumtypes.h
+valid_enctype.so valid_enctype.po $(OUTPRE)valid_enctype.$(OBJEXT): \
+  valid_enctype.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+verify_checksum.so verify_checksum.po $(OUTPRE)verify_checksum.$(OBJEXT): \
+  verify_checksum.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cksumtypes.h
+t_nfold.so t_nfold.po $(OUTPRE)t_nfold.$(OBJEXT): t_nfold.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+t_encrypt.so t_encrypt.po $(OUTPRE)t_encrypt.$(OBJEXT): \
+  t_encrypt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  etypes.h
+t_prf.so t_prf.po $(OUTPRE)t_prf.$(OBJEXT): t_prf.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+t_prng.so t_prng.po $(OUTPRE)t_prng.$(OBJEXT): t_prng.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+t_hmac.so t_hmac.po $(OUTPRE)t_hmac.$(OBJEXT): t_hmac.c \
+  $(srcdir)/hash_provider/hash_provider.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h
+t_pkcs5.so t_pkcs5.po $(OUTPRE)t_pkcs5.$(OBJEXT): t_pkcs5.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+t_cts.so t_cts.po $(OUTPRE)t_cts.$(OBJEXT): t_cts.c \
+  $(srcdir)/hash_provider/hash_provider.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h
+vectors.so vectors.po $(OUTPRE)vectors.$(OBJEXT): vectors.c \
+  $(srcdir)/hash_provider/hash_provider.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h
diff --git a/mechglue/src/lib/crypto/aes/ChangeLog b/mechglue/src/lib/crypto/aes/ChangeLog
new file mode 100644
index 000000000..980251358
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/ChangeLog
@@ -0,0 +1,82 @@
+2005-05-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (aes-gen): Use CC_LINK.  Reported by Mike Friedman.
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* aesopt.h: On PalmOS, include FloatMgr.h to get endianness flag.
+	(ENC_UNROLL, DEC_UNROLL, ENC_ROUND, LAST_ENC_ROUND, DEC_ROUND,
+	LAST_DEC_ROUND, KEY_SCHED): If CONFIG_SMALL is defined, set to
+	NONE or NO_TABLES as appropriate.
+
+	* aes_s2k.c (krb5int_aes_string_to_key): Widen bytes of iteration
+	count before shifting.
+
+	* Makefile.in (all-unix): Don't build aes-gen by default, leave it
+	for 'make check'.
+
+2004-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* vbaxam.doc: File deleted.
+
+2004-05-25  Tom Yu  <tlyu@mit.edu>
+
+	* aesopt.h (PLATFORM_BYTE_ORDER): Treat _WIN32 as always
+	little-endian.  Default to little-endian if there's no other
+	compile-time way to detect endianness, noting it as a guess.
+	(SAFE_IO): Error out if SAFE_IO is not set and endianness was
+	guessed.
+
+2004-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (aes-test): Link test program against thread support
+	library.
+
+2004-05-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* aesopt.h (PLATFORM_BYTE_ORDER): Check for _MIPSEB, _MIPSEL.  If
+	endian.h or machine/endian.h is available, include it instead of
+	sys/param.h.  Don't mess around with multibyte character
+	constants.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes_s2k.c (DEFAULT_ITERATION_COUNT): New macro; define to 4096.
+	(MAX_ITERATION_COUNT): New macro.
+	(krb5int_aes_string_to_key): Use them.
+
+2003-04-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* uitypes.h: Use inttypes.h if HAVE_INTTYPES_H is defined.
+
+2003-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes_s2k.c (krb5int_aes_string_to_key): Return an error if the
+	supplied iteration count is really, really large.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes_s2k.c, aes_s2k.h: New files.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Build aes_s2k.
+	(LOCALINCLUDES): Add dk directory.
+	(GEN_OBJS): New variable.
+	(aes-gen): Use GEN_OBJS.
+
+2003-02-28  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (clean): Cleanup testing objects and outputs
+
+2003-02-05  Ezra Peisach  <epeisach@.bu.edu>
+
+	* Makefile.in (run-aes-test): Add $(RUN_SETUP) so that if
+	compiling only shared libraries, LD_LIBRARY_PATH is set for test.
+
+2003-02-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* New directory, with Briad Gladstone's implementation of AES,
+	tweaked for the MIT krb5 build system.
+
diff --git a/mechglue/src/lib/crypto/aes/Makefile.in b/mechglue/src/lib/crypto/aes/Makefile.in
new file mode 100644
index 000000000..c37eea42e
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/Makefile.in
@@ -0,0 +1,89 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/aes
+mydir=aes
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../dk
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=aes
+##DOS##OBJFILE=..\$(OUTPRE)aes.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS=\
+	aescrypt.o	\
+	aestab.o	\
+	aeskey.o	\
+	aes_s2k.o
+
+OBJS=\
+	$(OUTPRE)aescrypt.$(OBJEXT)	\
+	$(OUTPRE)aestab.$(OBJEXT)	\
+	$(OUTPRE)aeskey.$(OBJEXT)	\
+	$(OUTPRE)aes_s2k.$(OBJEXT)
+
+SRCS=\
+	$(srcdir)/aescrypt.c	\
+	$(srcdir)/aestab.c	\
+	$(srcdir)/aeskey.c	\
+	$(srcdir)/aes_s2k.c
+
+GEN_OBJS=\
+	$(OUTPRE)aescrypt.$(OBJEXT)	\
+	$(OUTPRE)aestab.$(OBJEXT)	\
+	$(OUTPRE)aeskey.$(OBJEXT)
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs # aes-gen
+
+includes:: depend
+
+depend:: $(SRCS)
+
+aes-gen: aes-gen.o $(GEN_OBJS)
+	$(CC_LINK) -o aes-gen aes-gen.o $(GEN_OBJS)
+
+run-aes-gen: aes-gen
+	./aes-gen > kresults.out
+
+check:: run-aes-gen
+
+aes-test: aes-test.$(OBJEXT) $(CRYPTO_DEPLIB)
+	$(CC_LINK) -o aes-test aes-test.$(OBJEXT) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB)
+
+check:: run-aes-test
+run-aes-test: aes-test
+	$(RUN_SETUP) ./aes-test -k > vk.txt
+	cmp vk.txt $(srcdir)/expect-vk.txt
+	$(RUN_SETUP) ./aes-test > vt.txt
+	cmp vt.txt $(srcdir)/expect-vt.txt
+
+clean-unix:: clean-libobjs
+
+clean::
+	-$(RM) aes-gen aes-gen.o vt.txt vk.txt kresults.out aes-test aes-test.o
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+aescrypt.so aescrypt.po $(OUTPRE)aescrypt.$(OBJEXT): \
+  aescrypt.c aesopt.h aes.h uitypes.h
+aestab.so aestab.po $(OUTPRE)aestab.$(OBJEXT): aestab.c \
+  aesopt.h aes.h uitypes.h
+aeskey.so aeskey.po $(OUTPRE)aeskey.$(OBJEXT): aeskey.c \
+  aesopt.h aes.h uitypes.h
+aes_s2k.so aes_s2k.po $(OUTPRE)aes_s2k.$(OBJEXT): aes_s2k.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../dk/dk.h aes_s2k.h
diff --git a/mechglue/src/lib/crypto/aes/aes-gen.c b/mechglue/src/lib/crypto/aes/aes-gen.c
new file mode 100644
index 000000000..855e6a470
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aes-gen.c
@@ -0,0 +1,326 @@
+/*
+ * To be compiled against the AES code from:
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael/index.htm
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "aes.h"
+
+#define B 16U
+unsigned char key[16];
+unsigned char test_case_len[] = { B+1, 2*B-1, 2*B, 2*B+1, 3*B-1, 3*B, 4*B, };
+#define NTESTS (sizeof(test_case_len))
+struct {
+    unsigned char ivec[16];
+    unsigned char input[4*16];
+    unsigned char output[4*16];
+} test_case[NTESTS];
+aes_ctx ctx, dctx;
+
+static void init ()
+{
+    int i, j, r;
+
+    srand(42);
+    for (i = 0; i < 16; i++)
+	key[i] = 0xff & rand();
+    memset(test_case, 0, sizeof(test_case));
+    for (i = 0; i < NTESTS; i++)
+	for (j = 0; j < test_case_len[i]; j++) {
+	    test_case[i].input[j] = 0xff & rand();
+	}
+
+    r = aes_enc_key (key, sizeof(key), &ctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    r = aes_dec_key (key, sizeof(key), &dctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+}
+
+static void hexdump(const unsigned char *ptr, size_t len)
+{
+    int i;
+    for (i = 0; i < len; i++)
+	printf ("%s%02X", (i % 16 == 0) ? "\n    " : " ", ptr[i]);
+}
+
+static void fips_test ()
+{
+    static const unsigned char fipskey[16] = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+    };
+    static const unsigned char input[16] = {
+	0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+	0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    };
+    static const unsigned char expected[16] = {
+	0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
+	0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a,
+    };
+    unsigned char output[16];
+    unsigned char tmp[16];
+    aes_ctx fipsctx;
+    int r;
+
+    printf ("FIPS test:\nkey:");
+    hexdump (fipskey, 16);
+    printf ("\ninput:");
+    hexdump (input, 16);
+    r = aes_enc_key (fipskey, sizeof(fipskey), &fipsctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    r = aes_enc_blk (input, output, &fipsctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    printf ("\noutput:");
+    hexdump (output, 16);
+    printf ("\n");
+    if (memcmp(expected, output, 16))
+	fprintf(stderr, "wrong results!!!\n"), exit (1);
+    r = aes_dec_key (fipskey, sizeof(fipskey), &fipsctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    r = aes_dec_blk (output, tmp, &fipsctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    if (memcmp(input, tmp, 16))
+	fprintf(stderr, "decryption failed!!\n"), exit(1);
+    printf ("ok.\n\n");
+}
+
+static void
+xor (unsigned char *out, const unsigned char *a, const unsigned char *b)
+{
+    int i;
+    for (i = 0; i < B; i++)
+	out[i] = a[i] ^ b[i];
+}
+
+static void
+ecb_enc (unsigned char *out, unsigned char *in, unsigned int len)
+{
+    int i, r;
+    for (i = 0; i < len; i += 16) {
+	r = aes_enc_blk (in + i, out + i, &ctx);
+	if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    }
+    if (i != len) abort ();
+}
+
+static void
+ecb_dec (unsigned char *out, unsigned char *in, unsigned int len)
+{
+    int i, r;
+    for (i = 0; i < len; i += 16) {
+	r = aes_dec_blk (in + i, out + i, &dctx);
+	if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    }
+    if (i != len) abort ();
+}
+
+#define D(X) (printf("%s %d: %s=",__FUNCTION__,__LINE__, #X),hexdump(X,B),printf("\n"))
+
+#undef D
+#define D(X)
+
+static void
+cbc_enc (unsigned char *out, unsigned char *in, unsigned char *iv,
+	 unsigned int len)
+{
+    int i, r;
+    unsigned char tmp[B];
+    D(iv);
+    memcpy (tmp, iv, B);
+    for (i = 0; i < len; i += B) {
+	D(in+i);
+	xor (tmp, tmp, in + i);
+	D(tmp);
+	r = aes_enc_blk (tmp, out + i, &ctx);
+	if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+	memcpy (tmp, out + i, B);
+	D(out+i);
+    }
+    if (i != len) abort ();
+}
+
+static void
+cbc_dec (unsigned char *out, unsigned char *in, unsigned char *iv,
+	 unsigned int len)
+{
+    int i, r;
+    unsigned char tmp[B];
+    memcpy (tmp, iv, B);
+    for (i = 0; i < len; i += B) {
+	r = aes_dec_blk (in + i, tmp, &dctx);
+	if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+	xor (tmp, tmp, iv);
+	iv = in + i;
+	memcpy (out + i, tmp, B);
+    }
+    if (i != len) abort ();
+}
+
+static void
+cts_enc (unsigned char *out, unsigned char *in, unsigned char *iv,
+	 unsigned int len)
+{
+    int r;
+    unsigned int len2;
+    unsigned char pn1[B], pn[B], cn[B], cn1[B];
+
+    if (len < B + 1) abort ();
+    len2 = (len - B - 1) & ~(B-1);
+    cbc_enc (out, in, iv, len2);
+    out += len2;
+    in += len2;
+    len -= len2;
+    if (len2)
+	iv = out - B;
+    if (len <= B || len > 2 * B)
+	abort ();
+    printf ("(did CBC mode for %d)\n", len2);
+
+    D(in);
+    xor (pn1, in, iv);
+    D(pn1);
+    r = aes_enc_blk (pn1, cn, &ctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    D(cn);
+    memset (pn, 0, sizeof(pn));
+    memcpy (pn, in+B, len-B);
+    D(pn);
+    xor (pn, pn, cn);
+    D(pn);
+    r = aes_enc_blk (pn, cn1, &ctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    D(cn1);
+    memcpy(out, cn1, B);
+    memcpy(out+B, cn, len-B);
+}
+
+static void
+cts_dec (unsigned char *out, unsigned char *in, unsigned char *iv,
+	 unsigned int len)
+{
+    int r;
+    unsigned int len2;
+    unsigned char pn1[B], pn[B], cn[B], cn1[B];
+
+    if (len < B + 1) abort ();
+    len2 = (len - B - 1) & ~(B-1);
+    cbc_dec (out, in, iv, len2);
+    out += len2;
+    in += len2;
+    len -= len2;
+    if (len2)
+	iv = in - B;
+    if (len <= B || len > 2 * B)
+	abort ();
+
+    memcpy (cn1, in, B);
+    r = aes_dec_blk (cn1, pn, &dctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    memset (cn, 0, sizeof(cn));
+    memcpy (cn, in+B, len-B);
+    xor (pn, pn, cn);
+    memcpy (cn+len-B, pn+len-B, 2*B-len);
+    r = aes_dec_blk (cn, pn1, &dctx);
+    if (!r) fprintf(stderr, "error, line %d\n", __LINE__), exit(1);
+    xor (pn1, pn1, iv);
+    memcpy(out, pn1, B);
+    memcpy(out+B, pn, len-B);
+}
+
+static void ecb_test ()
+{
+    int testno;
+    unsigned char tmp[4*B];
+
+    printf ("ECB tests:\n");
+    printf ("key:");
+    hexdump (key, sizeof(key));
+    for (testno = 0; testno < NTESTS; testno++) {
+	unsigned len = (test_case_len[testno] + 15) & ~15;
+	printf ("\ntest %d - %d bytes\n", testno, len);
+	printf ("input:");
+	hexdump (test_case[testno].input, len);
+	printf ("\n");
+	ecb_enc (test_case[testno].output, test_case[testno].input, len);
+	printf ("output:");
+	hexdump (test_case[testno].output, len);
+	printf ("\n");
+	ecb_dec (tmp, test_case[testno].output, len);
+	if (memcmp (tmp, test_case[testno].input, len)) {
+	    printf ("ecb decrypt failed!!");
+	    hexdump (tmp, len);
+	    printf ("\n");
+	    exit (1);
+	}
+    }
+    printf ("\n");
+}
+
+unsigned char ivec[16] = { 0 };
+
+static void cbc_test ()
+{
+    int testno;
+    unsigned char tmp[4*B];
+
+    printf ("CBC tests:\n");
+    printf ("initial vector:");
+    hexdump (ivec, sizeof(ivec));
+    for (testno = 0; testno < NTESTS; testno++) {
+	unsigned len = (test_case_len[testno] + 15) & ~15;
+	printf ("\ntest %d - %d bytes\n", testno, len);
+	printf ("input:");
+	hexdump (test_case[testno].input, len);
+	printf ("\n");
+	cbc_enc (test_case[testno].output, test_case[testno].input, ivec, len);
+	printf ("output:");
+	hexdump (test_case[testno].output, len);
+	printf ("\n");
+	cbc_dec (tmp, test_case[testno].output, ivec, len);
+	if (memcmp (tmp, test_case[testno].input, len)) {
+	    printf("cbc decrypt failed!!");
+	    hexdump (tmp, len);
+	    printf ("\n");
+	    exit(1);
+	}
+    }
+    printf ("\n");
+}
+
+static void cts_test ()
+{
+    int testno;
+    unsigned char tmp[4*B];
+
+    printf ("CTS tests:\n");
+    printf ("initial vector:");
+    hexdump (ivec, sizeof(ivec));
+    for (testno = 0; testno < NTESTS; testno++) {
+	unsigned int len = test_case_len[testno];
+	printf ("\ntest %d - %d bytes\n", testno, len);
+	printf ("input:");
+	hexdump (test_case[testno].input, len);
+	printf ("\n");
+	cts_enc (test_case[testno].output, test_case[testno].input, ivec, len);
+	printf ("output:");
+	hexdump (test_case[testno].output, len);
+	printf ("\n");
+	cts_dec (tmp, test_case[testno].output, ivec, len);
+	if (memcmp (tmp, test_case[testno].input, len))
+	    fprintf (stderr, "cts decrypt failed!!\n"), exit(1);
+    }
+    printf ("\n");
+}
+
+int main ()
+{
+    init ();
+    fips_test ();
+
+    ecb_test();
+    cbc_test();
+    cts_test();
+
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/aes/aes-test.c b/mechglue/src/lib/crypto/aes/aes-test.c
new file mode 100644
index 000000000..c05fd26e3
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aes-test.c
@@ -0,0 +1,138 @@
+/*
+ * lib/crypto/aes/aes-test.c
+ *
+ * Copyright (C) 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Subset of NIST tests for AES; specifically, the variable-key and
+ * variable-text tests for 128- and 256-bit keys.
+ */
+
+#include <stdio.h>
+#include "k5-int.h"
+
+static char key[32];
+static char plain[16], cipher[16], zero[16];
+
+static krb5_keyblock enc_key;
+static krb5_data ivec;
+static krb5_data in, out;
+static void init()
+{
+    enc_key.contents = key;
+    enc_key.length = 16;
+    ivec.data = zero;
+    ivec.length = 16;
+    in.data = plain;
+    in.length = 16;
+    out.data = cipher;
+    out.length = 16;
+}
+static void enc()
+{
+    krb5int_aes_encrypt(&enc_key, &ivec, &in, &out);
+}
+
+static void hexdump(const char *label, const char *cp, int len)
+{
+    printf("%s=", label);
+    while (len--) printf("%02X", 0xff & *cp++);
+    printf("\n");
+}
+
+static void set_bit(char *ptr, int bitnum)
+{
+    int bytenum;
+    bytenum = bitnum / 8;
+    bitnum %= 8;
+    /* First bit is the high bit! */
+    ptr[bytenum] = 1 << (7 - bitnum);
+}
+
+/* Variable-Key tests */
+static void vk_test_1(int len)
+{
+    int i;
+
+    enc_key.length = len;
+    printf("\nKEYSIZE=%d\n\n", len * 8);
+    memset(plain, 0, sizeof(plain));
+    hexdump("PT", plain, 16);
+    for (i = 0; i < len * 8; i++) {
+	memset(key, 0, len);
+	set_bit(key, i);
+	printf("\nI=%d\n", i+1);
+	hexdump("KEY", key, len);
+	enc();
+	hexdump("CT", cipher, 16);
+    }
+    printf("\n==========\n");
+}
+static void vk_test()
+{
+    vk_test_1(16);
+    vk_test_1(32);
+}
+
+/* Variable-Text tests */
+static void vt_test_1(int len)
+{
+    int i;
+
+    enc_key.length = len;
+    printf("\nKEYSIZE=%d\n\n", len * 8);
+    memset(key, 0, len);
+    hexdump("KEY", key, len);
+    for (i = 0; i < 16 * 8; i++) {
+	memset(plain, 0, sizeof(plain));
+	set_bit(plain, i);
+	printf("\nI=%d\n", i+1);
+	hexdump("PT", plain, 16);
+	enc();
+	hexdump("CT", cipher, 16);
+    }
+    printf("\n==========\n");
+}
+static void vt_test()
+{
+    vt_test_1(16);
+    vt_test_1(32);
+}
+
+
+int main (int argc, char *argv[])
+{
+    if (argc > 2 || (argc == 2 && strcmp(argv[1], "-k"))) {
+	fprintf(stderr,
+		"usage:\t%s -k\tfor variable-key tests\n"
+		"   or:\t%s   \tfor variable-plaintext tests\n",
+		argv[0], argv[0]);
+	return 1;
+    }
+    init();
+    if (argc == 2)
+	vk_test();
+    else
+	vt_test();
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/aes/aes.h b/mechglue/src/lib/crypto/aes/aes.h
new file mode 100644
index 000000000..ac1c1b89e
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aes.h
@@ -0,0 +1,97 @@
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explcit or implied warranties
+ in respect of any properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 21/01/2002
+
+ This file contains the definitions required to use AES (Rijndael) in C.
+*/
+
+#ifndef _AES_H
+#define _AES_H
+
+#include "uitypes.h"
+
+/*  BLOCK_SIZE is in BYTES: 16, 24, 32 or undefined for aes.c and 16, 20, 
+    24, 28, 32 or undefined for aespp.c.  When left undefined a slower 
+    version that provides variable block length is compiled.    
+*/
+
+#define BLOCK_SIZE  16
+
+/* key schedule length (in 32-bit words)    */
+
+#if !defined(BLOCK_SIZE)
+#define KS_LENGTH   128
+#else
+#define KS_LENGTH   4 * BLOCK_SIZE
+#endif
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+typedef uint16_t    aes_fret;   /* type for function return value       */
+#define aes_bad     0           /* bad function return value            */
+#define aes_good    1           /* good function return value           */
+#ifndef AES_DLL                 /* implement normal or DLL functions    */
+#define aes_rval    aes_fret
+#else
+#define aes_rval    aes_fret __declspec(dllexport) _stdcall
+#endif
+
+typedef struct                      /* the AES context for encryption   */
+{   uint32_t    k_sch[KS_LENGTH];   /* the encryption key schedule      */
+    uint32_t    n_rnd;              /* the number of cipher rounds      */
+    uint32_t    n_blk;              /* the number of bytes in the state */
+} aes_ctx;
+
+/* for Kerberos 5 tree -- hide names!  */
+#define aes_blk_len	krb5int_aes_blk_len
+#define aes_enc_key	krb5int_aes_enc_key
+#define aes_enc_blk	krb5int_aes_enc_blk
+#define aes_dec_key	krb5int_aes_dec_key
+#define aes_dec_blk	krb5int_aes_dec_blk
+#define fl_tab		krb5int_fl_tab
+#define ft_tab		krb5int_ft_tab
+#define il_tab		krb5int_il_tab
+#define im_tab		krb5int_im_tab
+#define it_tab		krb5int_it_tab
+#define rcon_tab	krb5int_rcon_tab
+
+aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]);
+
+aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+
+aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/aes.txt b/mechglue/src/lib/crypto/aes/aes.txt
new file mode 100644
index 000000000..b644b5eb4
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aes.txt
@@ -0,0 +1,70 @@
+
+An AES (Rijndael) Implementation in C/C++ (as specified in FIPS-197)
+--------------------------------------------------------------------
+
+The source code files are as follows:
+
+1. aes.h:       the header file required to use AES in C
+2. aescpp.h     the header file required to use AES in C++
+3. aescrypt.c   the main C source code file for encryption and decryption
+4. aeskey.c     the main C source code file for the key schedule
+5. aestab.c     the main file for the AES tables
+6. aesopt.h     the file for common code and for setting build options
+7. aescrypt.asm a faster alternative to 3 above in assembler (using NASM)
+8. uitypes.h    a file for defining fixed length unsigned integer types
+9. aescrypp.c   an alternative to 3 for all Rijndael block and key sizes 
+10.aeskeypp.c   an alternative to 4 for all Rijndael block and key sizes 
+11.aesxam.c     an example of AES use
+
+Source files 9 and 10 are much slower than 4 and 5 for normal use and
+should not be used unless support for 20 and 28 byte blocks and keys
+is necessary.  Files 4 and 5 provide support for block and key sizes
+of 16, 24 and 32 bytes (fixed or variable) but the assemler code in 
+file 7 only supports the 16 byte AES block length. It does, however,
+offer the three key sizes when used with file 4. The use of files 4
+and 5 (or 9 and 10) with variable block size should be avoided since 
+the code is much faster when the block size is fixed.
+
+The VC++ AES Development Project
+--------------------------------
+
+The VC++ SOlution contains the following sub-projects
+
+1. aes_asm      this project tests the assembler code implementation
+2. aes_dll      this project builds the DLL version
+3. aes_gav      this project re-creates the test vector files and
+                optionally checks them against a reference set
+4. aes_rav      this project checks the values produced by the code
+                against the values in the test vector files
+5. aes_tmr      this project measures the speed of the code
+6. aes_tst      this project is set up to test the extended version
+                of Rijndael with block and key sizes of 16, 20, 24,
+                28 and 32 bytes
+7. aes_xam      this project builds the example of AES use in a 
+                simple file encryption program
+                
+Note that the paths for the various directories have to be set up in 
+aestst.h
+
+The AES and Rijndael Test Vector Files
+--------------------------------------
+
+These files fall in the following groups (where <nn> is a two digit
+number):
+
+1. ecbvk<nn>.txt  ECB vectors with variable key
+2. ecbvt<nn>.txt  ECB vectors with variable text
+3. ecbnk<nn>.txt  new ECB vectors with variable key 
+4. ecbnt<nn>.txt  new ECB vectors with variable text
+5. ecbme<nn>.txt  ECB monte carlo encryption test vectors
+6. ecbmd<nn>.txt  ECB monte carlo decryption test vectors
+7. cbcme<nn>.txt  CBC monte carlo encryption test vectors
+8. cbcmd<nn>.txt  CBC monte carlo decryption test vectors
+
+The first digit of the numeric suffix on the filename gives the 
+block size in 32bit units and the second numeric digit gives the
+key size.  For example, the file ecbvk44.txt provides the test 
+vectors for ECB encryption with a 128 bit block size and a 128 
+bit key size.
+
+   Brian Gladman <brg@gladman.uk.net>
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/aes_s2k.c b/mechglue/src/lib/crypto/aes/aes_s2k.c
new file mode 100644
index 000000000..68d3111bf
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aes_s2k.c
@@ -0,0 +1,93 @@
+/*
+ * lib/crypto/aes/aes_s2k.c
+ *
+ * Copyright 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5int_aes_string_to_key
+ */
+
+#include "k5-int.h"
+#include "dk.h"
+#include "aes_s2k.h"
+
+#define DEFAULT_ITERATION_COUNT		4096 /* was 0xb000L in earlier drafts */
+#define MAX_ITERATION_COUNT		0x1000000L
+
+krb5_error_code
+krb5int_aes_string_to_key(const struct krb5_enc_provider *enc,
+			  const krb5_data *string,
+			  const krb5_data *salt,
+			  const krb5_data *params,
+			  krb5_keyblock *key)
+{
+    unsigned long iter_count;
+    krb5_data out;
+    static const krb5_data usage = { KV5M_DATA, 8, "kerberos" };
+    krb5_error_code err;
+
+    if (params) {
+	unsigned char *p = (unsigned char *) params->data;
+	if (params->length != 4)
+	    return KRB5_ERR_BAD_S2K_PARAMS;
+	/* The first two need casts in case 'int' is 16 bits.  */
+	iter_count = (((unsigned long)p[0] << 24)
+		      | ((unsigned long)p[1] << 16)
+		      | (p[2] <<  8)
+		      | (p[3]));
+	if (iter_count == 0) {
+	    iter_count = (1L << 16) << 16;
+	    if (((iter_count >> 16) >> 16) != 1)
+		return KRB5_ERR_BAD_S2K_PARAMS;
+	}
+    } else
+	iter_count = DEFAULT_ITERATION_COUNT;
+
+    /* This is not a protocol specification constraint; this is an
+       implementation limit, which should eventually be controlled by
+       a config file.  */
+    if (iter_count >= MAX_ITERATION_COUNT)
+	return KRB5_ERR_BAD_S2K_PARAMS;
+
+    /*
+     * Dense key space, no parity bits or anything, so take a shortcut
+     * and use the key contents buffer for the generated bytes.
+     */
+    out.data = (char *) key->contents;
+    out.length = key->length;
+    if (out.length != 16 && out.length != 32)
+	return KRB5_CRYPTO_INTERNAL;
+
+    err = krb5int_pbkdf2_hmac_sha1 (&out, iter_count, string, salt);
+    if (err) {
+	memset(out.data, 0, out.length);
+	return err;
+    }
+
+    err = krb5_derive_key (enc, key, key, &usage);
+    if (err) {
+	memset(out.data, 0, out.length);
+	return err;
+    }
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/aes/aes_s2k.h b/mechglue/src/lib/crypto/aes/aes_s2k.h
new file mode 100644
index 000000000..b6804a991
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aes_s2k.h
@@ -0,0 +1,4 @@
+extern krb5_error_code
+krb5int_aes_string_to_key (const struct krb5_enc_provider *,
+			   const krb5_data *, const krb5_data *,
+			   const krb5_data *, krb5_keyblock *key);
diff --git a/mechglue/src/lib/crypto/aes/aescpp.h b/mechglue/src/lib/crypto/aes/aescpp.h
new file mode 100644
index 000000000..e685485e1
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aescpp.h
@@ -0,0 +1,55 @@
+
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ TERMS
+
+ Redistribution and use in source and binary forms, with or without 
+ modification, are permitted subject to the following conditions:
+
+  1. Redistributions of source code must retain the above copyright 
+     notice, this list of conditions and the following disclaimer. 
+
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the 
+     documentation and/or other materials provided with the distribution. 
+
+  3. The copyright holder's name must not be used to endorse or promote 
+     any products derived from this software without his specific prior 
+     written permission. 
+
+ This software is provided 'as is' with no express or implied warranties 
+ of correctness or fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 21/01/2002
+
+ This file contains the definitions required to use AES (Rijndael) in C++.
+*/
+
+#ifndef _AESCPP_H
+#define _AESCPP_H
+
+#include "aes.h"
+
+class AESclass
+{   aes_ctx cx[1];
+public:
+#if defined(BLOCK_SIZE)
+    AESclass()                          { cx->n_blk = BLOCK_SIZE; cx->n_rnd = 0; }
+#else
+    AESclass(unsigned int blen = 16)    { cx->n_blk = blen; cx->n_rnd = 0; }
+#endif
+    aes_rval blk_len(unsigned int blen) { return aes_blk_len(blen, cx); }
+    aes_rval enc_key(const unsigned char in_key[], unsigned int klen)
+            { return aes_enc_key(in_key, klen, cx); }
+    aes_rval dec_key(const unsigned char in_key[], unsigned int klen)
+            { return aes_dec_key(in_key, klen, cx); }
+    aes_rval enc_blk(const unsigned char in_blk[], unsigned char out_blk[])
+            { return aes_enc_blk(in_blk, out_blk, cx); }
+    aes_rval dec_blk(const unsigned char in_blk[], unsigned char out_blk[])
+            { return aes_dec_blk(in_blk, out_blk, cx); }
+};
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/aescrypp.c b/mechglue/src/lib/crypto/aes/aescrypp.c
new file mode 100644
index 000000000..87b634179
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aescrypp.c
@@ -0,0 +1,487 @@
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explcit or implied warranties
+ in respect of any properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 21/01/2002
+
+ This file contains the code for implementing encryption and decryption
+ for AES (Rijndael) for block and key sizes of 16, 20, 24, 28 and 32 bytes.
+ It can optionally be replaced by code written in assembler using NASM.
+*/
+
+#include "aesopt.h"
+
+#define unused  77  /* Sunset Strip */
+
+#define si(y,x,k,c) s(y,c) = word_in(x + 4 * c) ^ k[c]
+#define so(y,x,c)   word_out(y + 4 * c, s(x,c))
+
+#if BLOCK_SIZE == 16
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[4],y[4]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
+ /* 
+   the following defines prevent the compiler requiring the declaration
+   of generated but unused variables in the fwd_var and inv_var macros
+ */
+#define b04 unused
+#define b05 unused
+#define b06 unused
+#define b07 unused
+#define b14 unused
+#define b15 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
+
+#elif BLOCK_SIZE == 20
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[5],y[5]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,y##0,y##1,y##2,y##3,y##4
+#define b05 unused
+#define b06 unused
+#define b07 unused
+#define b15 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3); s(y,4) = s(x,4); 
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); si(y,x,k,4)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); so(y,x,4)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); rm(y,x,k,4)
+
+#elif BLOCK_SIZE == 24
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[6],y[6]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5, \
+                        y##0,y##1,y##2,y##3,y##4,y##5
+#define b06 unused
+#define b07 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
+                        s(y,4) = s(x,4); s(y,5) = s(x,5);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \
+                        si(y,x,k,3); si(y,x,k,4); si(y,x,k,5)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); \
+                        so(y,x,3); so(y,x,4); so(y,x,5)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \
+                        rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5)
+
+#elif BLOCK_SIZE == 28
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[7],y[7]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5,x##6 \
+                        y##0,y##1,y##2,y##3,y##4,y##5,y##6
+#define b07 unused
+#define b17 unused
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
+                        s(y,4) = s(x,4); s(y,5) = s(x,5);; s(y,6) = s(x,6);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \
+                        si(y,x,k,3); si(y,x,k,4); si(y,x,k,5); si(y,x,k,6)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); \
+                        so(y,x,3); so(y,x,4); so(y,x,5); so(y,x,6)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \
+                        rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6)
+#else
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[8],y[8]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \
+                        y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
+                        s(y,4) = s(x,4); s(y,5) = s(x,5); \
+                        s(y,6) = s(x,6); s(y,7) = s(x,7);
+
+#if BLOCK_SIZE == 32
+
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \
+                        si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \
+                        so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \
+                        rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7)
+#else
+
+#define state_in(y,x,k) \
+switch(nc) \
+{   case 8: si(y,x,k,7); \
+    case 7: si(y,x,k,6); \
+    case 6: si(y,x,k,5); \
+    case 5: si(y,x,k,4); \
+    case 4: si(y,x,k,3); si(y,x,k,2); \
+            si(y,x,k,1); si(y,x,k,0); \
+}
+
+#define state_out(y,x) \
+switch(nc) \
+{   case 8: so(y,x,7); \
+    case 7: so(y,x,6); \
+    case 6: so(y,x,5); \
+    case 5: so(y,x,4); \
+    case 4: so(y,x,3); so(y,x,2); \
+            so(y,x,1); so(y,x,0); \
+}
+
+#if defined(FAST_VARIABLE)
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{   case 8: rm(y,x,k,7); rm(y,x,k,6); \
+            rm(y,x,k,5); rm(y,x,k,4); \
+            rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+    case 7: rm(y,x,k,6); rm(y,x,k,5); \
+            rm(y,x,k,4); rm(y,x,k,3); \
+            rm(y,x,k,2); rm(y,x,k,1); \
+            rm(y,x,k,0); \
+            break; \
+    case 6: rm(y,x,k,5); rm(y,x,k,4); \
+            rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+    case 5: rm(y,x,k,4); rm(y,x,k,3); \
+            rm(y,x,k,2); rm(y,x,k,1); \
+            rm(y,x,k,0); \
+            break; \
+    case 4: rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+}
+#else
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{   case 8: rm(y,x,k,7); \
+    case 7: rm(y,x,k,6); \
+    case 6: rm(y,x,k,5); \
+    case 5: rm(y,x,k,4); \
+    case 4: rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+}
+
+#endif
+
+#endif
+#endif
+
+#if defined(ENCRYPTION)
+
+/* I am grateful to Frank Yellin for the following construction
+   (and that for decryption) which, given the column (c) of the 
+   output state variable, gives the input state variables which 
+   are needed for each row (r) of the state.
+
+   For the fixed block size options, compilers should reduce these 
+   two expressions to fixed variable references. But for variable 
+   block size code conditional clauses will sometimes be returned.
+
+   y = output word, x = input word, r = row, c = column for r = 0, 
+   1, 2 and 3 = column accessed for row r.
+*/
+
+#define fwd_var(x,r,c) \
+ ( r==0 ?           \
+    ( c==0 ? s(x,0) \
+    : c==1 ? s(x,1) \
+    : c==2 ? s(x,2) \
+    : c==3 ? s(x,3) \
+    : c==4 ? s(x,4) \
+    : c==5 ? s(x,5) \
+    : c==6 ? s(x,6) \
+    : s(x,7))       \
+ : r==1 ?           \
+    ( c==0 ? s(x,1) \
+    : c==1 ? s(x,2) \
+    : c==2 ? s(x,3) \
+    : c==3 ? nc==4 ? s(x,0) : s(x,4) \
+    : c==4 ? nc==5 ? s(x,0) : s(x,5) \
+    : c==5 ? nc==6 ? s(x,0) : s(x,6) \
+    : c==6 ? nc==7 ? s(x,0) : s(x,7) \
+    : s(x,0))       \
+ : r==2 ?           \
+    ( c==0 ? nc==8 ? s(x,3) : s(x,2) \
+    : c==1 ? nc==8 ? s(x,4) : s(x,3) \
+    : c==2 ? nc==8 ? s(x,5) : nc==4 ? s(x,0) : s(x,4) \
+    : c==3 ? nc==8 ? s(x,6) : nc==5 ? s(x,0) : nc==4 ? s(x,1) : s(x,5) \
+    : c==4 ? nc==8 ? s(x,7) : nc==7 ? s(x,6) : nc==6 ? s(x,0) : s(x,1) \
+    : c==5 ? nc==6 ? s(x,1) : s(x,0) \
+    : c==6 ? s(x,1) \
+    : s(x,2))       \
+ :                  \
+    ( c==0 ? nc>6  ? s(x,4) : s(x,3) \
+    : c==1 ? nc>6  ? s(x,5) : nc==4 ? s(x,0) : s(x,4) \
+    : c==2 ? nc>6  ? s(x,6) : nc==6 ? s(x,5) : nc==5 ? s(x,0) : s(x,1) \
+    : c==3 ? nc==8 ? s(x,7) : nc==5 ? s(x,1) : nc==4 ? s(x,2) : s(x,0) \
+    : c==4 ? nc==8 ? s(x,0) : nc==5 ? s(x,2) : s(x,1) \
+    : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+    : c==6 ? nc==8 ? s(x,2) : s(x,3) \
+    : s(x,3)))
+
+#if defined(FT4_SET)
+#undef  dec_fmvars
+#define dec_fmvars
+#define fwd_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c)
+#elif defined(FT1_SET)
+#undef  dec_fmvars
+#define dec_fmvars
+#define fwd_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c)
+#else
+#define fwd_rnd(y,x,k,c)    s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c]
+#endif
+
+#if defined(FL4_SET)
+#define fwd_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c)
+#elif defined(FL1_SET)
+#define fwd_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c)
+#else
+#define fwd_lrnd(y,x,k,c)   s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c]
+#endif
+
+aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1])
+{   uint32_t        locals(b0, b1);
+    const uint32_t  *kp = cx->k_sch;
+    dec_fmvars  /* declare variables for fwd_mcol() if needed */
+
+    if(!(cx->n_blk & 1)) return aes_bad;
+
+#if (ENC_UNROLL == FULL)
+
+    state_in((cx->n_rnd & 1 ? b1 : b0), in_blk, kp); 
+    kp += (cx->n_rnd - 9) * nc;
+
+    switch(cx->n_rnd)
+    {
+    case 14:    round(fwd_rnd,  b1, b0, kp - 4 * nc);
+    case 13:    round(fwd_rnd,  b0, b1, kp - 3 * nc);
+    case 12:    round(fwd_rnd,  b1, b0, kp - 2 * nc);
+    case 11:    round(fwd_rnd,  b0, b1, kp -     nc);
+    case 10:    round(fwd_rnd,  b1, b0, kp         );             
+                round(fwd_rnd,  b0, b1, kp +     nc);
+                round(fwd_rnd,  b1, b0, kp + 2 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 3 * nc);
+                round(fwd_rnd,  b1, b0, kp + 4 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 5 * nc);
+                round(fwd_rnd,  b1, b0, kp + 6 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 7 * nc);
+                round(fwd_rnd,  b1, b0, kp + 8 * nc);
+                round(fwd_lrnd, b0, b1, kp + 9 * nc);
+    }
+#else
+    {   uint32_t    rnd;
+
+        state_in(b0, in_blk, kp); 
+
+#if (ENC_UNROLL == PARTIAL)
+
+        for(rnd = 0; rnd < (cx->n_rnd - 1) >> 1; ++rnd)
+        {
+            kp += nc;
+            round(fwd_rnd, b1, b0, kp); 
+            kp += nc;
+            round(fwd_rnd, b0, b1, kp); 
+        }
+
+        if(cx->n_rnd & 1) 
+        {
+            l_copy(b1, b0);
+        }
+        else
+        {
+            kp += nc;
+            round(fwd_rnd,  b1, b0, kp); 
+        }
+#else
+        for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd)
+        {
+            kp += nc;
+            round(fwd_rnd, b1, b0, kp); 
+            l_copy(b0, b1); 
+        }
+#endif
+        kp += nc;
+        round(fwd_lrnd, b0, b1, kp);
+    }
+#endif
+
+    state_out(out_blk, b0);
+    return aes_good;
+}
+
+#endif
+
+#if defined(DECRYPTION)
+
+#define inv_var(x,r,c) \
+ ( r==0 ?           \
+    ( c==0 ? s(x,0) \
+    : c==1 ? s(x,1) \
+    : c==2 ? s(x,2) \
+    : c==3 ? s(x,3) \
+    : c==4 ? s(x,4) \
+    : c==5 ? s(x,5) \
+    : c==6 ? s(x,6) \
+    : s(x,7))       \
+ : r==1 ?           \
+    ( c==0 ? nc==8 ? s(x,7) : nc==7 ? s(x,6) : nc==6 ? s(x,5) : nc==5 ? s(x,4) : s(x,3) \
+    : c==1 ? s(x,0) \
+    : c==2 ? s(x,1) \
+    : c==3 ? s(x,2) \
+    : c==4 ? s(x,3) \
+    : c==5 ? s(x,4) \
+    : c==6 ? s(x,5) \
+    : s(x,6))       \
+ : r==2 ?           \
+    ( c==0 ? nc>6  ? s(x,5) : nc==6 ? s(x,4) : nc==5 ? s(x,3) : s(x,2) \
+    : c==1 ? nc>6  ? s(x,6) : nc==6 ? s(x,5) : nc==5 ? s(x,4) : s(x,3) \
+    : c==2 ? nc==8 ? s(x,7) : s(x,0) \
+    : c==3 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==4 ? nc==8 ? s(x,1) : s(x,2) \
+    : c==5 ? nc==8 ? s(x,2) : s(x,3) \
+    : c==6 ? nc==8 ? s(x,3) : s(x,4) \
+    : s(x,4))       \
+ :                  \
+    ( c==0 ? nc==8 ? s(x,4) : nc==5 ? s(x,2) : nc==4 ? s(x,1) : s(x,3) \
+    : c==1 ? nc==8 ? s(x,5) : nc==5 ? s(x,3) : nc==4 ? s(x,2) : s(x,4) \
+    : c==2 ? nc==8 ? s(x,6) : nc==5 ? s(x,4) : nc==4 ? s(x,3) : s(x,5) \
+    : c==3 ? nc==8 ? s(x,7) : nc==7 ? s(x,6) : s(x,0) \
+    : c==4 ? nc>6  ? s(x,0) : s(x,1) \
+    : c==5 ? nc==6 ? s(x,2) : s(x,1) \
+    : c==6 ? s(x,2) \
+    : s(x,3)))
+
+#if defined(IT4_SET)
+#undef  dec_imvars
+#define dec_imvars
+#define inv_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c)
+#elif defined(IT1_SET)
+#undef  dec_imvars
+#define dec_imvars
+#define inv_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c)
+#else
+#define inv_rnd(y,x,k,c)    s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c])
+#endif
+
+#if defined(IL4_SET)
+#define inv_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c)
+#elif defined(IL1_SET)
+#define inv_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c)
+#else
+#define inv_lrnd(y,x,k,c)   s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]
+#endif
+
+aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1])
+{   uint32_t        locals(b0, b1);
+    const uint32_t  *kp = cx->k_sch + nc * cx->n_rnd;
+    dec_imvars  /* declare variables for inv_mcol() if needed */
+
+    if(!(cx->n_blk & 2)) return aes_bad;
+
+#if (DEC_UNROLL == FULL)
+
+    state_in((cx->n_rnd & 1 ? b1 : b0), in_blk, kp); 
+    kp = cx->k_sch + 9 * nc;
+
+    switch(cx->n_rnd)
+    {
+    case 14:    round(inv_rnd,  b1, b0, kp + 4 * nc);
+    case 13:    round(inv_rnd,  b0, b1, kp + 3 * nc);
+    case 12:    round(inv_rnd,  b1, b0, kp + 2 * nc);
+    case 11:    round(inv_rnd,  b0, b1, kp +     nc);
+    case 10:    round(inv_rnd,  b1, b0, kp         );             
+                round(inv_rnd,  b0, b1, kp -     nc);
+                round(inv_rnd,  b1, b0, kp - 2 * nc); 
+                round(inv_rnd,  b0, b1, kp - 3 * nc);
+                round(inv_rnd,  b1, b0, kp - 4 * nc); 
+                round(inv_rnd,  b0, b1, kp - 5 * nc);
+                round(inv_rnd,  b1, b0, kp - 6 * nc); 
+                round(inv_rnd,  b0, b1, kp - 7 * nc);
+                round(inv_rnd,  b1, b0, kp - 8 * nc);
+                round(inv_lrnd, b0, b1, kp - 9 * nc);
+    }
+#else
+    {   uint32_t    rnd;
+
+        state_in(b0, in_blk, kp); 
+
+#if (DEC_UNROLL == PARTIAL)
+
+        for(rnd = 0; rnd < (cx->n_rnd - 1) >> 1; ++rnd)
+        {
+            kp -= nc;
+            round(inv_rnd, b1, b0, kp); 
+            kp -= nc;
+            round(inv_rnd, b0, b1, kp); 
+        }
+
+        if(cx->n_rnd & 1) 
+        {
+            l_copy(b1, b0);
+        }
+        else
+        {       
+            kp -= nc;
+            round(inv_rnd,  b1, b0, kp); 
+        }
+#else
+        for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd)
+        {
+            kp -= nc;
+            round(inv_rnd, b1, b0, kp); 
+            l_copy(b0, b1); 
+        }
+#endif
+        kp -= nc;
+        round(inv_lrnd, b0, b1, kp);
+    }
+#endif
+
+    state_out(out_blk, b0);
+    return aes_good;
+}
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/aescrypt.asm b/mechglue/src/lib/crypto/aes/aescrypt.asm
new file mode 100644
index 000000000..35a6818b6
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aescrypt.asm
@@ -0,0 +1,402 @@
+
+; -------------------------------------------------------------------------
+; Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+; All rights reserved.
+;
+; LICENSE TERMS
+;
+; The free distribution and use of this software in both source and binary 
+; form is allowed (with or without changes) provided that:
+;
+;   1. distributions of this source code include the above copyright 
+;      notice, this list of conditions and the following disclaimer;
+;
+;   2. distributions in binary form include the above copyright
+;      notice, this list of conditions and the following disclaimer
+;      in the documentation and/or other associated materials;
+;
+;   3. the copyright holder's name is not used to endorse products 
+;      built using this software without specific written permission.
+;
+; DISCLAIMER
+;
+; This software is provided 'as is' with no explcit or implied warranties
+; in respect of any properties, including, but not limited to, correctness 
+; and fitness for purpose.
+; -------------------------------------------------------------------------
+; Issue Date: 15/01/2002
+
+; An AES (Rijndael) implementation for the Pentium MMX family using the NASM
+; assembler <http://www.web-sites.co.uk/nasm/>. This version only implements
+; the standard AES block length (128 bits, 16 bytes) with the same interface
+; as that used in my C/C++ implementation.   This code does not preserve the
+; eax, ecx or edx registers or the artihmetic status flags. However, the ebx, 
+; esi, edi, and ebp registers are preserved across calls.    Only encryption
+; and decryption are implemented here, the key schedule code being that from
+; compiling aes.c with USE_ASM defined.  This code uses VC++ register saving
+; conentions; if it is used with another compiler, its conventions for using
+; and saving registers will need to be checked.
+
+    section .text use32
+
+; aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+; aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+
+    global  _aes_enc_blk
+    global  _aes_dec_blk
+    
+    extern  _ft_tab
+    extern  _fl_tab
+    extern  _it_tab
+    extern  _il_tab
+
+;%define USE_MMX   ; include this to use MMX registers for temporary storage
+;%define USE_EMMS    ; include this if you make use of floating point operations
+
+%ifdef  USE_MMX
+%ifdef  USE_EMMS
+%define EMMS_ON
+%endif
+%endif
+
+tlen:   equ  1024   ; length of each of 4 'xor' arrays (256 32-bit words)
+
+; offsets to parameters with one register pushed onto stack
+
+in_blk: equ     8   ; input byte array address parameter
+out_blk:equ    12   ; output byte array address parameter
+ctx:    equ    16   ; AES context structure
+
+; offsets in context structure
+
+ksch:   equ     0   ; encryption key schedule base address
+nrnd:   equ   256   ; number of rounds
+nblk:   equ   260   ; number of rounds
+
+; register mapping for encrypt and decrypt subroutines
+
+%define r0  eax
+%define r1  ebx
+%define r2  ecx
+%define r3  edx
+%define r4  esi
+%define r5  edi
+%define r6  ebp
+
+%define eaxl  al
+%define eaxh  ah
+%define ebxl  bl
+%define ebxh  bh
+%define ecxl  cl
+%define ecxh  ch
+%define edxl  dl
+%define edxh  dh
+
+; This macro takes a 32-bit word representing a column and uses
+; each of its four bytes to index into four tables of 256 32-bit
+; words to obtain values that are then xored into the appropriate
+; output registers r0, r1, r4 or r5.  
+
+; Parameters:
+;   %1  out_state[0]
+;   %2  out_state[1]
+;   %3  out_state[2]
+;   %4  out_state[3]
+;   %5  table base address
+;   %6  input register for the round (destroyed)
+;   %7  scratch register for the round
+
+%macro do_col 7
+
+    movzx   %7,%6l
+    xor     %1,[4*%7+%5]
+    movzx   %7,%6h
+    shr     %6,16
+    xor     %2,[4*%7+%5+tlen]
+    movzx   %7,%6l
+    movzx   %6,%6h
+    xor     %3,[4*%7+%5+2*tlen] 
+    xor     %4,[4*%6+%5+3*tlen]
+
+%endmacro
+
+; initialise output registers from the key schedule
+
+%macro do_fcol 8
+
+    mov     %1,[%8]
+    movzx   %7,%6l
+    mov     %2,[%8+12]
+    xor     %1,[4*%7+%5]
+    mov     %4,[%8+ 4]
+    movzx   %7,%6h
+    shr     %6,16
+    xor     %2,[4*%7+%5+tlen]
+    movzx   %7,%6l
+    movzx   %6,%6h
+    xor     %4,[4*%6+%5+3*tlen]
+    mov     %6,%3
+    mov     %3,[%8+ 8]
+    xor     %3,[4*%7+%5+2*tlen] 
+
+%endmacro
+
+; initialise output registers from the key schedule
+
+%macro do_icol 8
+
+    mov     %1,[%8]
+    movzx   %7,%6l
+    mov     %2,[%8+ 4]
+    xor     %1,[4*%7+%5]
+    mov     %4,[%8+12]
+    movzx   %7,%6h
+    shr     %6,16
+    xor     %2,[4*%7+%5+tlen]
+    movzx   %7,%6l
+    movzx   %6,%6h
+    xor     %4,[4*%6+%5+3*tlen]
+    mov     %6,%3
+    mov     %3,[%8+ 8]
+    xor     %3,[4*%7+%5+2*tlen] 
+
+%endmacro
+
+; These macros implement either MMX or stack based local variables
+
+%ifdef  USE_MMX
+
+%macro  save 2
+    movd    mm%1,%2
+%endmacro
+
+%macro  restore 2
+    movd    %1,mm%2
+%endmacro
+
+%else
+
+%macro  save 2
+    mov     [esp+4*%1],%2
+%endmacro
+
+%macro  restore 2
+    mov     %1,[esp+4*%2]
+%endmacro
+
+%endif
+
+; This macro performs a forward encryption cycle. It is entered with
+; the first previous round column values in r0, r1, r4 and r5 and
+; exits with the final values in the same registers, using the MMX
+; registers mm0-mm1 for temporary storage
+
+%macro fwd_rnd 1-2 _ft_tab
+
+; mov current column values into the MMX registers
+
+    mov     r2,r0
+    save    0,r1
+    save    1,r5
+
+; compute new column values
+
+    do_fcol r0,r5,r4,r1, %2, r2,r3, %1
+    do_col  r4,r1,r0,r5, %2, r2,r3
+    restore r2,0
+    do_col  r1,r0,r5,r4, %2, r2,r3
+    restore r2,1
+    do_col  r5,r4,r1,r0, %2, r2,r3
+
+%endmacro
+
+; This macro performs an inverse encryption cycle. It is entered with
+; the first previous round column values in r0, r1, r4 and r5 and
+; exits with the final values in the same registers, using the MMX
+; registers mm0-mm1 for temporary storage
+
+%macro inv_rnd 1-2 _it_tab
+
+; mov current column values into the MMX registers
+
+    mov     r2,r0
+    save    0,r1
+    save    1,r5
+
+; compute new column values
+
+    do_icol r0,r1,r4,r5, %2, r2,r3, %1
+    do_col  r4,r5,r0,r1, %2, r2,r3
+    restore r2,0
+    do_col  r1,r4,r5,r0, %2, r2,r3
+    restore r2,1
+    do_col  r5,r0,r1,r4, %2, r2,r3
+
+%endmacro
+
+; AES (Rijndael) Encryption Subroutine
+
+_aes_enc_blk:
+    push    ebp
+    mov     ebp,[esp+ctx]       ; pointer to context
+    xor     eax,eax
+    test    [ebp+nblk],byte 1
+    je      .0
+    cmp     eax,[ebp+nrnd]      ; encryption/decryption flags
+    jne     short .1
+.0: pop     ebp
+    ret            
+
+; CAUTION: the order and the values used in these assigns 
+; rely on the register mappings
+
+.1: push    ebx
+    mov     r2,[esp+in_blk+4]
+    push    esi
+    mov     r3,[ebp+nrnd]   ; number of rounds
+    push    edi
+    lea     r6,[ebp+ksch]   ; key pointer
+
+; input four columns and xor in first round key
+
+    mov     r0,[r2]
+    mov     r1,[r2+4]
+    mov     r4,[r2+8]
+    mov     r5,[r2+12]
+    xor     r0,[r6]
+    xor     r1,[r6+4]
+    xor     r4,[r6+8]
+    xor     r5,[r6+12]
+
+%ifndef USE_MMX
+    sub     esp,8           ; space for register saves on stack
+%endif
+    add     r6,16           ; increment to next round key   
+    sub     r3,10          
+    je      .4              ; 10 rounds for 128-bit key
+    add     r6,32  
+    sub     r3,2
+    je      .3              ; 12 rounds for 128-bit key
+    add     r6,32  
+
+.2: fwd_rnd r6-64           ; 14 rounds for 128-bit key
+    fwd_rnd r6-48  
+.3: fwd_rnd r6-32           ; 12 rounds for 128-bit key
+    fwd_rnd r6-16  
+.4: fwd_rnd r6              ; 10 rounds for 128-bit key
+    fwd_rnd r6+ 16 
+    fwd_rnd r6+ 32
+    fwd_rnd r6+ 48
+    fwd_rnd r6+ 64
+    fwd_rnd r6+ 80
+    fwd_rnd r6+ 96
+    fwd_rnd r6+112
+    fwd_rnd r6+128
+    fwd_rnd r6+144,_fl_tab  ; last round uses a different table
+
+; move final values to the output array.  CAUTION: the 
+; order of these assigns rely on the register mappings
+
+%ifndef USE_MMX
+    add     esp,8
+%endif
+    mov     r6,[esp+out_blk+12]
+    mov     [r6+12],r5
+    pop     edi
+    mov     [r6+8],r4
+    pop     esi
+    mov     [r6+4],r1
+    pop     ebx
+    mov     [r6],r0
+    pop     ebp
+    mov     eax,1
+%ifdef  EMMS_ON
+    emms
+%endif
+    ret
+
+; AES (Rijndael) Decryption Subroutine
+
+_aes_dec_blk:
+    push    ebp
+    mov     ebp,[esp+ctx]       ; pointer to context
+    xor     eax,eax
+    test    [ebp+nblk],byte 2
+    je      .0
+    cmp     eax,[ebp+nrnd]      ; encryption/decryption flags
+    jne     short .1
+.0: pop     ebp
+    ret            
+
+; CAUTION: the order and the values used in these assigns 
+; rely on the register mappings
+
+.1: push    ebx
+    mov     r2,[esp+in_blk+4]
+    push    esi
+    mov     r3,[ebp+nrnd]   ; number of rounds
+    push    edi
+    lea     r6,[ebp+ksch]   ; key pointer
+    mov     r0,r3
+    shl     r0,4
+    add     r6,r0
+    
+; input four columns and xor in first round key
+
+    mov     r0,[r2]
+    mov     r1,[r2+4]
+    mov     r4,[r2+8]
+    mov     r5,[r2+12]
+    xor     r0,[r6]
+    xor     r1,[r6+4]
+    xor     r4,[r6+8]
+    xor     r5,[r6+12]
+
+%ifndef USE_MMX
+    sub     esp,8           ; space for register saves on stack
+%endif
+    sub     r6,16           ; increment to next round key   
+    sub     r3,10          
+    je      .4              ; 10 rounds for 128-bit key
+    sub     r6,32  
+    sub     r3,2
+    je      .3              ; 12 rounds for 128-bit key
+    sub     r6,32  
+
+.2: inv_rnd r6+64           ; 14 rounds for 128-bit key 
+    inv_rnd r6+48  
+.3: inv_rnd r6+32           ; 12 rounds for 128-bit key
+    inv_rnd r6+16  
+.4: inv_rnd r6              ; 10 rounds for 128-bit key
+    inv_rnd r6- 16 
+    inv_rnd r6- 32
+    inv_rnd r6- 48
+    inv_rnd r6- 64
+    inv_rnd r6- 80
+    inv_rnd r6- 96
+    inv_rnd r6-112
+    inv_rnd r6-128
+    inv_rnd r6-144,_il_tab  ; last round uses a different table
+
+; move final values to the output array.  CAUTION: the 
+; order of these assigns rely on the register mappings
+
+%ifndef USE_MMX
+    add     esp,8
+%endif
+    mov     r6,[esp+out_blk+12]
+    mov     [r6+12],r5
+    pop     edi
+    mov     [r6+8],r4
+    pop     esi
+    mov     [r6+4],r1
+    pop     ebx
+    mov     [r6],r0
+    pop     ebp
+    mov     eax,1
+%ifdef  EMMS_ON
+    emms
+%endif
+    ret
+
+    end
diff --git a/mechglue/src/lib/crypto/aes/aescrypt.c b/mechglue/src/lib/crypto/aes/aescrypt.c
new file mode 100644
index 000000000..9db66e284
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aescrypt.c
@@ -0,0 +1,421 @@
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explcit or implied warranties
+ in respect of any properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 21/01/2002
+
+ This file contains the code for implementing encryption and decryption
+ for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It  
+ can optionally be replaced by code written in assembler using NASM.
+*/
+
+#include "aesopt.h"
+
+#if defined(BLOCK_SIZE) && (BLOCK_SIZE & 7)
+#error An illegal block size has been specified.
+#endif  
+
+#define unused  77  /* Sunset Strip */
+
+#define si(y,x,k,c) s(y,c) = word_in(x + 4 * c) ^ k[c]
+#define so(y,x,c)   word_out(y + 4 * c, s(x,c))
+
+#if BLOCK_SIZE == 16
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[4],y[4]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
+ /* 
+   the following defines prevent the compiler requiring the declaration
+   of generated but unused variables in the fwd_var and inv_var macros
+ */
+#define b04 unused
+#define b05 unused
+#define b06 unused
+#define b07 unused
+#define b14 unused
+#define b15 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
+
+#elif BLOCK_SIZE == 24
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[6],y[6]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5, \
+                        y##0,y##1,y##2,y##3,y##4,y##5
+#define b06 unused
+#define b07 unused
+#define b16 unused
+#define b17 unused
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
+                        s(y,4) = s(x,4); s(y,5) = s(x,5);
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \
+                        si(y,x,k,3); si(y,x,k,4); si(y,x,k,5)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); \
+                        so(y,x,3); so(y,x,4); so(y,x,5)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \
+                        rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5)
+#else
+
+#if defined(ARRAYS)
+#define locals(y,x)     x[8],y[8]
+#else
+#define locals(y,x)     x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \
+                        y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7
+#endif
+#define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
+                        s(y,2) = s(x,2); s(y,3) = s(x,3); \
+                        s(y,4) = s(x,4); s(y,5) = s(x,5); \
+                        s(y,6) = s(x,6); s(y,7) = s(x,7);
+
+#if BLOCK_SIZE == 32
+
+#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \
+                        si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7)
+#define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \
+                        so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7)
+#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \
+                        rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7)
+#else
+
+#define state_in(y,x,k) \
+switch(nc) \
+{   case 8: si(y,x,k,7); si(y,x,k,6); \
+    case 6: si(y,x,k,5); si(y,x,k,4); \
+    case 4: si(y,x,k,3); si(y,x,k,2); \
+            si(y,x,k,1); si(y,x,k,0); \
+}
+
+#define state_out(y,x) \
+switch(nc) \
+{   case 8: so(y,x,7); so(y,x,6); \
+    case 6: so(y,x,5); so(y,x,4); \
+    case 4: so(y,x,3); so(y,x,2); \
+            so(y,x,1); so(y,x,0); \
+}
+
+#if defined(FAST_VARIABLE)
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{   case 8: rm(y,x,k,7); rm(y,x,k,6); \
+            rm(y,x,k,5); rm(y,x,k,4); \
+            rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+    case 6: rm(y,x,k,5); rm(y,x,k,4); \
+            rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+    case 4: rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+            break; \
+}
+#else
+
+#define round(rm,y,x,k) \
+switch(nc) \
+{   case 8: rm(y,x,k,7); rm(y,x,k,6); \
+    case 6: rm(y,x,k,5); rm(y,x,k,4); \
+    case 4: rm(y,x,k,3); rm(y,x,k,2); \
+            rm(y,x,k,1); rm(y,x,k,0); \
+}
+
+#endif
+
+#endif
+#endif
+
+#if defined(ENCRYPTION)
+
+/* I am grateful to Frank Yellin for the following construction
+   (and that for decryption) which, given the column (c) of the 
+   output state variable, gives the input state variables which 
+   are needed in its computation for each row (r) of the state.
+
+   For the fixed block size options, compilers should be able to 
+   reduce this complex expression (and the equivalent one for 
+   decryption) to a static variable reference at compile time. 
+   But for variable block size code, there will be some limbs on
+   which conditional clauses will be returned.
+*/
+
+/* y = output word, x = input word, r = row, c = column for r = 0, 
+   1, 2 and 3 = column accessed for row r.
+*/
+
+#define fwd_var(x,r,c) \
+ ( r==0 ?           \
+    ( c==0 ? s(x,0) \
+    : c==1 ? s(x,1) \
+    : c==2 ? s(x,2) \
+    : c==3 ? s(x,3) \
+    : c==4 ? s(x,4) \
+    : c==5 ? s(x,5) \
+    : c==6 ? s(x,6) \
+    : s(x,7))       \
+ : r==1 ?           \
+    ( c==0 ? s(x,1) \
+    : c==1 ? s(x,2) \
+    : c==2 ? s(x,3) \
+    : c==3 ? nc==4 ? s(x,0) : s(x,4) \
+    : c==4 ? s(x,5) \
+    : c==5 ? nc==8 ? s(x,6) : s(x,0) \
+    : c==6 ? s(x,7) \
+    : s(x,0))       \
+ : r==2 ?           \
+    ( c==0 ? nc==8 ? s(x,3) : s(x,2) \
+    : c==1 ? nc==8 ? s(x,4) : s(x,3) \
+    : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
+    : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
+    : c==4 ? nc==8 ? s(x,7) : s(x,0) \
+    : c==5 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==6 ? s(x,1) \
+    : s(x,2))       \
+ :                  \
+    ( c==0 ? nc==8 ? s(x,4) : s(x,3) \
+    : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \
+    : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \
+    : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \
+    : c==4 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+    : c==6 ? s(x,2) \
+    : s(x,3)))
+
+#if defined(FT4_SET)
+#undef  dec_fmvars
+#define dec_fmvars
+#define fwd_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c)
+#elif defined(FT1_SET)
+#undef  dec_fmvars
+#define dec_fmvars
+#define fwd_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c)
+#else
+#define fwd_rnd(y,x,k,c)    s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c]
+#endif
+
+#if defined(FL4_SET)
+#define fwd_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c)
+#elif defined(FL1_SET)
+#define fwd_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c)
+#else
+#define fwd_lrnd(y,x,k,c)   s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c]
+#endif
+
+aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1])
+{   uint32_t        locals(b0, b1);
+    const uint32_t  *kp = cx->k_sch;
+    dec_fmvars  /* declare variables for fwd_mcol() if needed */
+
+    if(!(cx->n_blk & 1)) return aes_bad;
+
+    state_in(b0, in_blk, kp); 
+
+#if (ENC_UNROLL == FULL)
+
+    kp += (cx->n_rnd - 9) * nc;
+
+    switch(cx->n_rnd)
+    {
+    case 14:    round(fwd_rnd,  b1, b0, kp - 4 * nc); 
+                round(fwd_rnd,  b0, b1, kp - 3 * nc);
+    case 12:    round(fwd_rnd,  b1, b0, kp - 2 * nc); 
+                round(fwd_rnd,  b0, b1, kp -     nc);
+    case 10:    round(fwd_rnd,  b1, b0, kp         );             
+                round(fwd_rnd,  b0, b1, kp +     nc);
+                round(fwd_rnd,  b1, b0, kp + 2 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 3 * nc);
+                round(fwd_rnd,  b1, b0, kp + 4 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 5 * nc);
+                round(fwd_rnd,  b1, b0, kp + 6 * nc); 
+                round(fwd_rnd,  b0, b1, kp + 7 * nc);
+                round(fwd_rnd,  b1, b0, kp + 8 * nc);
+                round(fwd_lrnd, b0, b1, kp + 9 * nc);
+    }
+#else
+    
+#if (ENC_UNROLL == PARTIAL)
+    {   uint32_t    rnd;
+        for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd)
+        {
+            kp += nc;
+            round(fwd_rnd, b1, b0, kp); 
+            kp += nc;
+            round(fwd_rnd, b0, b1, kp); 
+        }
+        kp += nc;
+        round(fwd_rnd,  b1, b0, kp);
+#else
+    {   uint32_t    rnd, *p0 = b0, *p1 = b1, *pt;
+        for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd)
+        {
+            kp += nc;
+            round(fwd_rnd, p1, p0, kp); 
+            pt = p0, p0 = p1, p1 = pt;
+        }
+#endif
+        kp += nc;
+        round(fwd_lrnd, b0, b1, kp);
+    }
+#endif
+
+    state_out(out_blk, b0);
+    return aes_good;
+}
+
+#endif
+
+#if defined(DECRYPTION)
+
+#define inv_var(x,r,c) \
+ ( r==0 ?           \
+    ( c==0 ? s(x,0) \
+    : c==1 ? s(x,1) \
+    : c==2 ? s(x,2) \
+    : c==3 ? s(x,3) \
+    : c==4 ? s(x,4) \
+    : c==5 ? s(x,5) \
+    : c==6 ? s(x,6) \
+    : s(x,7))       \
+ : r==1 ?           \
+    ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \
+    : c==1 ? s(x,0) \
+    : c==2 ? s(x,1) \
+    : c==3 ? s(x,2) \
+    : c==4 ? s(x,3) \
+    : c==5 ? s(x,4) \
+    : c==6 ? s(x,5) \
+    : s(x,6))       \
+ : r==2 ?           \
+    ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
+    : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
+    : c==2 ? nc==8 ? s(x,7) : s(x,0) \
+    : c==3 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==4 ? nc==8 ? s(x,1) : s(x,2) \
+    : c==5 ? nc==8 ? s(x,2) : s(x,3) \
+    : c==6 ? s(x,3) \
+    : s(x,4))       \
+ :                  \
+    ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \
+    : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \
+    : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \
+    : c==3 ? nc==8 ? s(x,7) : s(x,0) \
+    : c==4 ? nc==8 ? s(x,0) : s(x,1) \
+    : c==5 ? nc==8 ? s(x,1) : s(x,2) \
+    : c==6 ? s(x,2) \
+    : s(x,3)))
+
+#if defined(IT4_SET)
+#undef  dec_imvars
+#define dec_imvars
+#define inv_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c)
+#elif defined(IT1_SET)
+#undef  dec_imvars
+#define dec_imvars
+#define inv_rnd(y,x,k,c)    s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c)
+#else
+#define inv_rnd(y,x,k,c)    s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c])
+#endif
+
+#if defined(IL4_SET)
+#define inv_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c)
+#elif defined(IL1_SET)
+#define inv_lrnd(y,x,k,c)   s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c)
+#else
+#define inv_lrnd(y,x,k,c)   s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]
+#endif
+
+aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1])
+{   uint32_t        locals(b0, b1);
+    const uint32_t  *kp = cx->k_sch + nc * cx->n_rnd;
+    dec_imvars  /* declare variables for inv_mcol() if needed */
+
+    if(!(cx->n_blk & 2)) return aes_bad;
+
+    state_in(b0, in_blk, kp);
+
+#if (DEC_UNROLL == FULL)
+
+    kp = cx->k_sch + 9 * nc;
+    switch(cx->n_rnd)
+    {
+    case 14:    round(inv_rnd,  b1, b0, kp + 4 * nc);
+                round(inv_rnd,  b0, b1, kp + 3 * nc);
+    case 12:    round(inv_rnd,  b1, b0, kp + 2 * nc);
+                round(inv_rnd,  b0, b1, kp + nc    );
+    case 10:    round(inv_rnd,  b1, b0, kp         );             
+                round(inv_rnd,  b0, b1, kp -     nc);
+                round(inv_rnd,  b1, b0, kp - 2 * nc); 
+                round(inv_rnd,  b0, b1, kp - 3 * nc);
+                round(inv_rnd,  b1, b0, kp - 4 * nc); 
+                round(inv_rnd,  b0, b1, kp - 5 * nc);
+                round(inv_rnd,  b1, b0, kp - 6 * nc); 
+                round(inv_rnd,  b0, b1, kp - 7 * nc);
+                round(inv_rnd,  b1, b0, kp - 8 * nc);
+                round(inv_lrnd, b0, b1, kp - 9 * nc);
+    }
+#else
+    
+#if (DEC_UNROLL == PARTIAL)
+    {   uint32_t    rnd;
+        for(rnd = 0; rnd < (cx->n_rnd >> 1) - 1; ++rnd)
+        {
+            kp -= nc; 
+            round(inv_rnd, b1, b0, kp); 
+            kp -= nc; 
+            round(inv_rnd, b0, b1, kp); 
+        }
+        kp -= nc;
+        round(inv_rnd, b1, b0, kp);
+#else
+    {   uint32_t    rnd, *p0 = b0, *p1 = b1, *pt;
+        for(rnd = 0; rnd < cx->n_rnd - 1; ++rnd)
+        {
+            kp -= nc;
+            round(inv_rnd, p1, p0, kp); 
+            pt = p0, p0 = p1, p1 = pt;
+        }
+#endif
+        kp -= nc;
+        round(inv_lrnd, b0, b1, kp);
+    }
+#endif
+
+    state_out(out_blk, b0);
+    return aes_good;
+}
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/aeskey.c b/mechglue/src/lib/crypto/aes/aeskey.c
new file mode 100644
index 000000000..970a26fca
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aeskey.c
@@ -0,0 +1,363 @@
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explcit or implied warranties
+ in respect of any properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 21/01/2002
+
+ This file contains the code for implementing the key schedule for AES 
+ (Rijndael) for block and key sizes of 16, 24, and 32 bytes.
+*/
+
+#include "aesopt.h"
+
+#if defined(BLOCK_SIZE) && (BLOCK_SIZE & 7)
+#error An illegal block size has been specified.
+#endif  
+
+/* Subroutine to set the block size (if variable) in bytes, legal
+   values being 16, 24 and 32. 
+*/
+
+#if !defined(BLOCK_SIZE) && defined(SET_BLOCK_LENGTH)
+
+aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1])
+{
+#if !defined(FIXED_TABLES)
+    if(!tab_init) gen_tabs();
+#endif
+
+    if((blen & 7) || blen < 16 || blen > 32) 
+    {     
+        cx->n_blk = 0; return aes_bad;
+    }
+
+    cx->n_blk = blen;
+    return aes_good;
+}
+
+#endif
+
+/* Initialise the key schedule from the user supplied key. The key
+   length is now specified in bytes - 16, 24 or 32 as appropriate.
+   This corresponds to bit lengths of 128, 192 and 256 bits, and
+   to Nk values of 4, 6 and 8 respectively.
+
+   The following macros implement a single cycle in the key 
+   schedule generation process. The number of cycles needed 
+   for each cx->n_col and nk value is:
+ 
+    nk =             4  5  6  7  8
+    ------------------------------
+    cx->n_col = 4   10  9  8  7  7
+    cx->n_col = 5   14 11 10  9  9
+    cx->n_col = 6   19 15 12 11 11
+    cx->n_col = 7   21 19 16 13 14
+    cx->n_col = 8   29 23 19 17 14
+*/
+
+#if defined(ENCRYPTION_KEY_SCHEDULE)
+
+#define ke4(k,i) \
+{   k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \
+    k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \
+}
+#define kel4(k,i) \
+{   k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \
+    k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \
+}
+
+#define ke6(k,i) \
+{   k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \
+    k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \
+    k[6*(i)+10] = ss[4] ^= ss[3]; k[6*(i)+11] = ss[5] ^= ss[4]; \
+}
+#define kel6(k,i) \
+{   k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \
+    k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \
+}
+
+#define ke8(k,i) \
+{   k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \
+    k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \
+    k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); k[8*(i)+13] = ss[5] ^= ss[4]; \
+    k[8*(i)+14] = ss[6] ^= ss[5]; k[8*(i)+15] = ss[7] ^= ss[6]; \
+}
+#define kel8(k,i) \
+{   k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \
+    k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \
+}
+
+aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1])
+{   uint32_t    ss[8]; 
+
+#if !defined(FIXED_TABLES)
+    if(!tab_init) gen_tabs();
+#endif
+
+#if !defined(BLOCK_SIZE)
+    if(!cx->n_blk) cx->n_blk = 16;
+#else
+    cx->n_blk = BLOCK_SIZE;
+#endif
+    
+    cx->n_blk = (cx->n_blk & ~3U) | 1;
+
+    cx->k_sch[0] = ss[0] = word_in(in_key     );
+    cx->k_sch[1] = ss[1] = word_in(in_key +  4);
+    cx->k_sch[2] = ss[2] = word_in(in_key +  8);
+    cx->k_sch[3] = ss[3] = word_in(in_key + 12);
+
+#if (BLOCK_SIZE == 16) && (ENC_UNROLL != NONE)
+
+    switch(klen)
+    {
+    case 16:    ke4(cx->k_sch, 0); ke4(cx->k_sch, 1); 
+                ke4(cx->k_sch, 2); ke4(cx->k_sch, 3);
+                ke4(cx->k_sch, 4); ke4(cx->k_sch, 5); 
+                ke4(cx->k_sch, 6); ke4(cx->k_sch, 7);
+                ke4(cx->k_sch, 8); kel4(cx->k_sch, 9); 
+                cx->n_rnd = 10; break;
+    case 24:    cx->k_sch[4] = ss[4] = word_in(in_key + 16);
+                cx->k_sch[5] = ss[5] = word_in(in_key + 20);
+                ke6(cx->k_sch, 0); ke6(cx->k_sch, 1); 
+                ke6(cx->k_sch, 2); ke6(cx->k_sch, 3);
+                ke6(cx->k_sch, 4); ke6(cx->k_sch, 5); 
+                ke6(cx->k_sch, 6); kel6(cx->k_sch, 7); 
+                cx->n_rnd = 12; break;
+    case 32:    cx->k_sch[4] = ss[4] = word_in(in_key + 16);
+                cx->k_sch[5] = ss[5] = word_in(in_key + 20);
+                cx->k_sch[6] = ss[6] = word_in(in_key + 24);
+                cx->k_sch[7] = ss[7] = word_in(in_key + 28);
+                ke8(cx->k_sch, 0); ke8(cx->k_sch, 1); 
+                ke8(cx->k_sch, 2); ke8(cx->k_sch, 3);
+                ke8(cx->k_sch, 4); ke8(cx->k_sch, 5); 
+                kel8(cx->k_sch, 6); 
+                cx->n_rnd = 14; break;
+    default:    cx->n_rnd = 0; return aes_bad; 
+    }
+#else
+    {   uint32_t i, l;
+        cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6;
+        l = (nc * cx->n_rnd + nc - 1) / (klen >> 2);
+
+        switch(klen)
+        {
+        case 16:    for(i = 0; i < l; ++i)
+                        ke4(cx->k_sch, i);
+                    break;
+        case 24:    cx->k_sch[4] = ss[4] = word_in(in_key + 16);
+                    cx->k_sch[5] = ss[5] = word_in(in_key + 20);
+                    for(i = 0; i < l; ++i)
+                        ke6(cx->k_sch, i);
+                    break;
+        case 32:    cx->k_sch[4] = ss[4] = word_in(in_key + 16);
+                    cx->k_sch[5] = ss[5] = word_in(in_key + 20);
+                    cx->k_sch[6] = ss[6] = word_in(in_key + 24);
+                    cx->k_sch[7] = ss[7] = word_in(in_key + 28);
+                    for(i = 0; i < l; ++i)
+                        ke8(cx->k_sch,  i);
+                    break;
+        default:    cx->n_rnd = 0; return aes_bad; 
+        }
+    }
+#endif
+
+    return aes_good;
+}
+
+#endif
+
+#if defined(DECRYPTION_KEY_SCHEDULE)
+
+#if (DEC_ROUND != NO_TABLES)
+#define d_vars  dec_imvars
+#define ff(x)   inv_mcol(x)
+#else
+#define ff(x)   (x)
+#define d_vars
+#endif
+
+#if 1
+#define kdf4(k,i) \
+{   ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; ss[1] = ss[1] ^ ss[3]; ss[2] = ss[2] ^ ss[3]; ss[3] = ss[3]; \
+    ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; \
+    ss[4] ^= k[4*(i)];   k[4*(i)+4] = ff(ss[4]); ss[4] ^= k[4*(i)+1]; k[4*(i)+5] = ff(ss[4]); \
+    ss[4] ^= k[4*(i)+2]; k[4*(i)+6] = ff(ss[4]); ss[4] ^= k[4*(i)+3]; k[4*(i)+7] = ff(ss[4]); \
+}
+#define kd4(k,i) \
+{   ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
+    k[4*(i)+4] = ss[4] ^= k[4*(i)]; k[4*(i)+5] = ss[4] ^= k[4*(i)+1]; \
+    k[4*(i)+6] = ss[4] ^= k[4*(i)+2]; k[4*(i)+7] = ss[4] ^= k[4*(i)+3]; \
+}
+#define kdl4(k,i) \
+{   ss[4] = ls_box(ss[(i+3) % 4], 3) ^ rcon_tab[i]; ss[i % 4] ^= ss[4]; \
+    k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; k[4*(i)+5] = ss[1] ^ ss[3]; \
+    k[4*(i)+6] = ss[0]; k[4*(i)+7] = ss[1]; \
+}
+#else
+#define kdf4(k,i) \
+{   ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+ 4] = ff(ss[0]); ss[1] ^= ss[0]; k[4*(i)+ 5] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[4*(i)+ 6] = ff(ss[2]); ss[3] ^= ss[2]; k[4*(i)+ 7] = ff(ss[3]); \
+}
+#define kd4(k,i) \
+{   ss[4] = ls_box(ss[3],3) ^ rcon_tab[i]; \
+    ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[4*(i)+ 4] = ss[4] ^= k[4*(i)]; \
+    ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[4] ^= k[4*(i)+ 1]; \
+    ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[4] ^= k[4*(i)+ 2]; \
+    ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[4] ^= k[4*(i)+ 3]; \
+}
+#define kdl4(k,i) \
+{   ss[0] ^= ls_box(ss[3],3) ^ rcon_tab[i]; k[4*(i)+ 4] = ss[0]; ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[1]; \
+    ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[2]; ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[3]; \
+}
+#endif
+
+#define kdf6(k,i) \
+{   ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 6] = ff(ss[0]); ss[1] ^= ss[0]; k[6*(i)+ 7] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[6*(i)+ 8] = ff(ss[2]); ss[3] ^= ss[2]; k[6*(i)+ 9] = ff(ss[3]); \
+    ss[4] ^= ss[3]; k[6*(i)+10] = ff(ss[4]); ss[5] ^= ss[4]; k[6*(i)+11] = ff(ss[5]); \
+}
+#define kd6(k,i) \
+{   ss[6] = ls_box(ss[5],3) ^ rcon_tab[i]; \
+    ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[6*(i)+ 6] = ss[6] ^= k[6*(i)]; \
+    ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1]; \
+    ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2]; \
+    ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3]; \
+    ss[4] ^= ss[3]; k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4]; \
+    ss[5] ^= ss[4]; k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5]; \
+}
+#define kdl6(k,i) \
+{   ss[0] ^= ls_box(ss[5],3) ^ rcon_tab[i]; k[6*(i)+ 6] = ss[0]; ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[1]; \
+    ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[2]; ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[3]; \
+}
+
+#define kdf8(k,i) \
+{   ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 8] = ff(ss[0]); ss[1] ^= ss[0]; k[8*(i)+ 9] = ff(ss[1]); \
+    ss[2] ^= ss[1]; k[8*(i)+10] = ff(ss[2]); ss[3] ^= ss[2]; k[8*(i)+11] = ff(ss[3]); \
+    ss[4] ^= ls_box(ss[3],0); k[8*(i)+12] = ff(ss[4]); ss[5] ^= ss[4]; k[8*(i)+13] = ff(ss[5]); \
+    ss[6] ^= ss[5]; k[8*(i)+14] = ff(ss[6]); ss[7] ^= ss[6]; k[8*(i)+15] = ff(ss[7]); \
+}
+#define kd8(k,i) \
+{   uint32_t g = ls_box(ss[7],3) ^ rcon_tab[i]; \
+    ss[0] ^= g; g = ff(g); k[8*(i)+ 8] = g ^= k[8*(i)]; \
+    ss[1] ^= ss[0]; k[8*(i)+ 9] = g ^= k[8*(i)+ 1]; \
+    ss[2] ^= ss[1]; k[8*(i)+10] = g ^= k[8*(i)+ 2]; \
+    ss[3] ^= ss[2]; k[8*(i)+11] = g ^= k[8*(i)+ 3]; \
+    g = ls_box(ss[3],0); \
+    ss[4] ^= g; g = ff(g); k[8*(i)+12] = g ^= k[8*(i)+ 4]; \
+    ss[5] ^= ss[4]; k[8*(i)+13] = g ^= k[8*(i)+ 5]; \
+    ss[6] ^= ss[5]; k[8*(i)+14] = g ^= k[8*(i)+ 6]; \
+    ss[7] ^= ss[6]; k[8*(i)+15] = g ^= k[8*(i)+ 7]; \
+}
+#define kdl8(k,i) \
+{   ss[0] ^= ls_box(ss[7],3) ^ rcon_tab[i]; k[8*(i)+ 8] = ss[0]; ss[1] ^= ss[0]; k[8*(i)+ 9] = ss[1]; \
+    ss[2] ^= ss[1]; k[8*(i)+10] = ss[2]; ss[3] ^= ss[2]; k[8*(i)+11] = ss[3]; \
+}
+
+aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1])
+{   uint32_t    ss[8]; 
+    d_vars
+
+#if !defined(FIXED_TABLES)
+    if(!tab_init) gen_tabs();
+#endif
+
+#if !defined(BLOCK_SIZE)
+    if(!cx->n_blk) cx->n_blk = 16;
+#else
+    cx->n_blk = BLOCK_SIZE;
+#endif
+
+    cx->n_blk = (cx->n_blk & ~3U) | 2;
+
+    cx->k_sch[0] = ss[0] = word_in(in_key     );
+    cx->k_sch[1] = ss[1] = word_in(in_key +  4);
+    cx->k_sch[2] = ss[2] = word_in(in_key +  8);
+    cx->k_sch[3] = ss[3] = word_in(in_key + 12);
+
+#if (BLOCK_SIZE == 16) && (DEC_UNROLL != NONE)
+
+    switch(klen)
+    {
+    case 16:    kdf4(cx->k_sch, 0); kd4(cx->k_sch, 1); 
+                kd4(cx->k_sch, 2); kd4(cx->k_sch, 3);
+                kd4(cx->k_sch, 4); kd4(cx->k_sch, 5); 
+                kd4(cx->k_sch, 6); kd4(cx->k_sch, 7);
+                kd4(cx->k_sch, 8); kdl4(cx->k_sch, 9); 
+                cx->n_rnd = 10; break;
+    case 24:    cx->k_sch[4] = ff(ss[4] = word_in(in_key + 16));
+                cx->k_sch[5] = ff(ss[5] = word_in(in_key + 20));
+                kdf6(cx->k_sch, 0); kd6(cx->k_sch, 1); 
+                kd6(cx->k_sch, 2); kd6(cx->k_sch, 3);
+                kd6(cx->k_sch, 4); kd6(cx->k_sch, 5); 
+                kd6(cx->k_sch, 6); kdl6(cx->k_sch, 7); 
+                cx->n_rnd = 12; break;
+    case 32:    cx->k_sch[4] = ff(ss[4] = word_in(in_key + 16));
+                cx->k_sch[5] = ff(ss[5] = word_in(in_key + 20));
+                cx->k_sch[6] = ff(ss[6] = word_in(in_key + 24));
+                cx->k_sch[7] = ff(ss[7] = word_in(in_key + 28));
+                kdf8(cx->k_sch, 0); kd8(cx->k_sch, 1); 
+                kd8(cx->k_sch, 2); kd8(cx->k_sch, 3);
+                kd8(cx->k_sch, 4); kd8(cx->k_sch, 5); 
+                kdl8(cx->k_sch, 6); 
+                cx->n_rnd = 14; break;
+    default:    cx->n_rnd = 0; return aes_bad; 
+    }
+#else
+    {   uint32_t i, l;
+        cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6;
+        l = (nc * cx->n_rnd + nc - 1) / (klen >> 2);
+
+        switch(klen)
+        {
+        case 16: 
+                    for(i = 0; i < l; ++i)
+                        ke4(cx->k_sch, i);
+                    break;
+        case 24:    cx->k_sch[4] = ss[4] = word_in(in_key + 16);
+                    cx->k_sch[5] = ss[5] = word_in(in_key + 20);
+                    for(i = 0; i < l; ++i)
+                        ke6(cx->k_sch, i);
+                    break;
+        case 32:    cx->k_sch[4] = ss[4] = word_in(in_key + 16);
+                    cx->k_sch[5] = ss[5] = word_in(in_key + 20);
+                    cx->k_sch[6] = ss[6] = word_in(in_key + 24);
+                    cx->k_sch[7] = ss[7] = word_in(in_key + 28);
+                    for(i = 0; i < l; ++i)
+                        ke8(cx->k_sch,  i);
+                    break;
+        default:    cx->n_rnd = 0; return aes_bad; 
+        }
+#if (DEC_ROUND != NO_TABLES)
+        for(i = nc; i < nc * cx->n_rnd; ++i)
+            cx->k_sch[i] = inv_mcol(cx->k_sch[i]);
+#endif
+    }
+#endif
+
+    return aes_good;
+}
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/aeskeypp.c b/mechglue/src/lib/crypto/aes/aeskeypp.c
new file mode 100644
index 000000000..89fd9006d
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aeskeypp.c
@@ -0,0 +1,399 @@
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explcit or implied warranties
+ in respect of any properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 21/01/2002
+
+ This file contains the code for implementing the key schedule for AES 
+ (Rijndael) for block and key sizes of 16, 20, 24, 28 and 32 bytes.
+*/
+
+#include "aesopt.h"
+
+/* Subroutine to set the block size (if variable) in bytes, legal
+   values being 16, 24 and 32. 
+*/
+
+#if !defined(BLOCK_SIZE) && defined(SET_BLOCK_LENGTH)
+
+/* Subroutine to set the block size (if variable) in bytes, legal
+   values being 16, 24 and 32. 
+*/
+
+aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1])
+{
+#if !defined(FIXED_TABLES)
+    if(!tab_init) gen_tabs();
+#endif
+
+    if((blen & 3) || blen < 16 || blen > 32) 
+    {     
+        cx->n_blk = 0; return aes_bad;
+    }
+
+    cx->n_blk = blen;
+    return aes_good;
+}
+
+#endif
+
+/* Initialise the key schedule from the user supplied key. The key
+   length is now specified in bytes - 16, 24 or 32 as appropriate.
+   This corresponds to bit lengths of 128, 192 and 256 bits, and
+   to Nk values of 4, 6 and 8 respectively.
+
+   The following macros implement a single cycle in the key 
+   schedule generation process. The number of cycles needed 
+   for each cx->n_blk and nk value is:
+ 
+    nk =             4  5  6  7  8
+    ------------------------------
+    cx->n_blk = 4   10  9  8  7  7
+    cx->n_blk = 5   14 11 10  9  9
+    cx->n_blk = 6   19 15 12 11 11
+    cx->n_blk = 7   21 19 16 13 14
+    cx->n_blk = 8   29 23 19 17 14
+*/
+
+/* Initialise the key schedule from the user supplied key. The key
+   length is now specified in bytes - 16, 20, 24, 28 or 32 as 
+   appropriate. This corresponds to bit lengths of 128, 160, 192,
+   224 and 256 bits, and to Nk values of 4, 5, 6, 7 & 8 respectively.
+ */
+
+#define mx(t,f) (*t++ = inv_mcol(*f),f++)
+#define cp(t,f) *t++ = *f++
+
+#if   BLOCK_SIZE == 16
+#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s)
+#elif BLOCK_SIZE == 20
+#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+                    cp(d,s)
+#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+                    mx(d,s)
+#elif BLOCK_SIZE == 24
+#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+                    cp(d,s); cp(d,s)
+#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+                    mx(d,s); mx(d,s)
+#elif BLOCK_SIZE == 28
+#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+                    cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+                    mx(d,s); mx(d,s); mx(d,s)
+#elif BLOCK_SIZE == 32
+#define cpy(d,s)    cp(d,s); cp(d,s); cp(d,s); cp(d,s); \
+                    cp(d,s); cp(d,s); cp(d,s); cp(d,s)
+#define mix(d,s)    mx(d,s); mx(d,s); mx(d,s); mx(d,s); \
+                    mx(d,s); mx(d,s); mx(d,s); mx(d,s)
+#else
+
+#define cpy(d,s) \
+switch(nc) \
+{   case 8: cp(d,s); \
+    case 7: cp(d,s); \
+    case 6: cp(d,s); \
+    case 5: cp(d,s); \
+    case 4: cp(d,s); cp(d,s); \
+            cp(d,s); cp(d,s); \
+}
+
+#define mix(d,s) \
+switch(nc) \
+{   case 8: mx(d,s); \
+    case 7: mx(d,s); \
+    case 6: mx(d,s); \
+    case 5: mx(d,s); \
+    case 4: mx(d,s); mx(d,s); \
+            mx(d,s); mx(d,s); \
+}
+
+#endif
+
+/*  The following macros implement a single cycle in the key 
+    schedule generation process. The number of cycles needed 
+    for each cx->n_blk and nk value is:
+ 
+    nk =      4  5  6  7  8
+    -----------------------
+    cx->n_blk = 4   10  9  8  7  7
+    cx->n_blk = 5   14 11 10  9  9
+    cx->n_blk = 6   19 15 12 11 11
+    cx->n_blk = 7   21 19 16 13 14
+    cx->n_blk = 8   29 23 19 17 14
+*/
+
+#define ks4(i) \
+{   p ^= ls_box(s,3) ^ rcon_tab[i]; q ^= p; r ^= q; s ^= r; \
+    cx->k_sch[4*(i)+4] = p; \
+    cx->k_sch[4*(i)+5] = q; \
+    cx->k_sch[4*(i)+6] = r; \
+    cx->k_sch[4*(i)+7] = s; \
+}
+
+#define ks5(i) \
+{   p ^= ls_box(t,3) ^ rcon_tab[i]; q ^= p; \
+    r ^= q; s ^= r; t ^= s; \
+    cx->k_sch[5*(i)+ 5] = p; \
+    cx->k_sch[5*(i)+ 6] = q; \
+    cx->k_sch[5*(i)+ 7] = r; \
+    cx->k_sch[5*(i)+ 8] = s; \
+    cx->k_sch[5*(i)+ 9] = t; \
+}
+
+#define ks6(i) \
+{   p ^= ls_box(u,3) ^ rcon_tab[i]; q ^= p; \
+    r ^= q; s ^= r; t ^= s; u ^= t; \
+    cx->k_sch[6*(i)+ 6] = p; \
+    cx->k_sch[6*(i)+ 7] = q; \
+    cx->k_sch[6*(i)+ 8] = r; \
+    cx->k_sch[6*(i)+ 9] = s; \
+    cx->k_sch[6*(i)+10] = t; \
+    cx->k_sch[6*(i)+11] = u; \
+}
+
+#define ks7(i) \
+{   p ^= ls_box(v,3) ^ rcon_tab[i]; q ^= p; r ^= q; s ^= r; \
+    t ^= ls_box(s,0); u ^= t; v ^= u; \
+    cx->k_sch[7*(i)+ 7] = p; \
+    cx->k_sch[7*(i)+ 8] = q; \
+    cx->k_sch[7*(i)+ 9] = r; \
+    cx->k_sch[7*(i)+10] = s; \
+    cx->k_sch[7*(i)+11] = t; \
+    cx->k_sch[7*(i)+12] = u; \
+    cx->k_sch[7*(i)+13] = v; \
+}
+
+#define ks8(i) \
+{   p ^= ls_box(w,3) ^ rcon_tab[i]; q ^= p; r ^= q; s ^= r; \
+    t ^= ls_box(s,0); u ^= t; v ^= u; w ^= v; \
+    cx->k_sch[8*(i)+ 8] = p; \
+    cx->k_sch[8*(i)+ 9] = q; \
+    cx->k_sch[8*(i)+10] = r; \
+    cx->k_sch[8*(i)+11] = s; \
+    cx->k_sch[8*(i)+12] = t; \
+    cx->k_sch[8*(i)+13] = u; \
+    cx->k_sch[8*(i)+14] = v; \
+    cx->k_sch[8*(i)+15] = w; \
+}
+
+#if defined(ENCRYPTION_KEY_SCHEDULE)
+
+aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1])
+{   uint32_t    i,p,q,r,s,t,u,v,w;
+
+#if !defined(FIXED_TABLES)
+    if(!tab_init) gen_tabs();
+#endif
+
+#if !defined(BLOCK_SIZE)
+    if(!cx->n_blk) cx->n_blk = 16;
+#else
+    cx->n_blk = BLOCK_SIZE;
+#endif
+
+    cx->n_blk = (cx->n_blk & ~3) | 1;
+    cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6;
+
+    cx->k_sch[0] = p = word_in(in_key     );
+    cx->k_sch[1] = q = word_in(in_key +  4);
+    cx->k_sch[2] = r = word_in(in_key +  8);
+    cx->k_sch[3] = s = word_in(in_key + 12);
+
+#if BLOCK_SIZE == 16 && defined(UNROLL)
+
+    switch(klen >> 2)
+    {
+    case 4: ks4(0); ks4(1); ks4(2); ks4(3);
+            ks4(4); ks4(5); ks4(6); ks4(7);
+            ks4(8); ks4(9); 
+            cx->n_rnd = 10; break;
+    case 5: cx->k_sch[4] = t = word_in(in_key + 16);
+            ks5(0); ks5(1); ks5(2); ks5(3);
+            ks5(4); ks5(5); ks5(6); ks5(7); 
+            ks5(8);  
+            cx->n_rnd = 11; break;
+    case 6: cx->k_sch[4] = t = word_in(in_key + 16);
+            cx->k_sch[5] = u = word_in(in_key + 20);
+            ks6(0); ks6(1); ks6(2); ks6(3);
+            ks6(4); ks6(5); ks6(6); ks6(7); 
+            cx->n_rnd = 12; break;
+    case 7: cx->k_sch[4] = t = word_in(in_key + 16);
+            cx->k_sch[5] = u = word_in(in_key + 20);
+            cx->k_sch[6] = v = word_in(in_key + 24);
+            ks7(0); ks7(1); ks7(2); ks7(3);
+            ks7(4); ks7(5); ks7(6); 
+            cx->n_rnd = 13; break;
+    case 8: cx->k_sch[4] = t = word_in(in_key + 16);
+            cx->k_sch[5] = u = word_in(in_key + 20);
+            cx->k_sch[6] = v = word_in(in_key + 24);
+            cx->k_sch[7] = w = word_in(in_key + 28);
+            ks8(0); ks8(1); ks8(2); ks8(3);
+            ks8(4); ks8(5); ks8(6); 
+            cx->n_rnd = 14; break;
+    default:cx->n_rnd = 0; return aes_bad;
+    }
+#else
+    cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6;
+    {
+        uint32_t l = (nc * (cx->n_rnd + 1) - 1) / (klen >> 2);
+        switch(klen >> 2)
+        {
+        case 4: for(i = 0; i < l; ++i)
+                    ks4(i);
+                break;
+        case 5: cx->k_sch[4] = t = word_in(in_key + 16);
+                for(i = 0; i < l; ++i)
+                    ks5(i);
+                break;
+        case 6: cx->k_sch[4] = t = word_in(in_key + 16);
+                cx->k_sch[5] = u = word_in(in_key + 20);
+                for(i = 0; i < l; ++i)
+                    ks6(i);
+                break;
+        case 7: cx->k_sch[4] = t = word_in(in_key + 16);
+                cx->k_sch[5] = u = word_in(in_key + 20);
+                cx->k_sch[6] = v = word_in(in_key + 24);
+                for(i = 0; i < l; ++i)
+                    ks7(i);
+                break;
+        case 8: cx->k_sch[4] = t = word_in(in_key + 16);
+                cx->k_sch[5] = u = word_in(in_key + 20);
+                cx->k_sch[6] = v = word_in(in_key + 24);
+                cx->k_sch[7] = w = word_in(in_key + 28);
+                for(i = 0; i < l; ++i)
+                    ks8(i);
+                break;
+        }
+    }
+#endif
+
+    return aes_good;
+}
+
+#endif
+
+#if defined(DECRYPTION_KEY_SCHEDULE)
+
+aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1])
+{   uint32_t    i,p,q,r,s,t,u,v,w;
+    dec_imvars
+
+#if !defined(FIXED_TABLES)
+    if(!tab_init) gen_tabs();
+#endif
+
+#if !defined(BLOCK_SIZE)
+    if(!cx->n_blk) cx->n_blk = 16;
+#else
+    cx->n_blk = BLOCK_SIZE;
+#endif
+
+    cx->n_blk = (cx->n_blk & ~3) | 2;
+    cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6;
+
+    cx->k_sch[0] = p = word_in(in_key     );
+    cx->k_sch[1] = q = word_in(in_key +  4);
+    cx->k_sch[2] = r = word_in(in_key +  8);
+    cx->k_sch[3] = s = word_in(in_key + 12);
+
+#if BLOCK_SIZE == 16 && defined(UNROLL)
+
+    switch(klen >> 2)
+    {
+    case 4: ks4(0); ks4(1); ks4(2); ks4(3);
+            ks4(4); ks4(5); ks4(6); ks4(7);
+            ks4(8); ks4(9); 
+            cx->n_rnd = 10; break;
+    case 5: cx->k_sch[4] = t = word_in(in_key + 16);
+            ks5(0); ks5(1); ks5(2); ks5(3);
+            ks5(4); ks5(5); ks5(6); ks5(7); 
+            ks5(8);  
+            cx->n_rnd = 11; break;
+    case 6: cx->k_sch[4] = t = word_in(in_key + 16);
+            cx->k_sch[5] = u = word_in(in_key + 20);
+            ks6(0); ks6(1); ks6(2); ks6(3);
+            ks6(4); ks6(5); ks6(6); ks6(7); 
+            cx->n_rnd = 12; break;
+    case 7: cx->k_sch[4] = t = word_in(in_key + 16);
+            cx->k_sch[5] = u = word_in(in_key + 20);
+            cx->k_sch[6] = v = word_in(in_key + 24);
+            ks7(0); ks7(1); ks7(2); ks7(3);
+            ks7(4); ks7(5); ks7(6); 
+            cx->n_rnd = 13; break;
+    case 8: cx->k_sch[4] = t = word_in(in_key + 16);
+            cx->k_sch[5] = u = word_in(in_key + 20);
+            cx->k_sch[6] = v = word_in(in_key + 24);
+            cx->k_sch[7] = w = word_in(in_key + 28);
+            ks8(0); ks8(1); ks8(2); ks8(3);
+            ks8(4); ks8(5); ks8(6); 
+            cx->n_rnd = 14; break;
+    default:cx->n_rnd = 0; return aes_bad;
+    }
+#else
+    cx->n_rnd = ((klen >> 2) > nc ? (klen >> 2) : nc) + 6;
+    {
+        uint32_t l = (nc * (cx->n_rnd + 1) - 1) / (klen >> 2);
+        switch(klen >> 2)
+        {
+        case 4: for(i = 0; i < l; ++i)
+                    ks4(i);
+                break;
+        case 5: cx->k_sch[4] = t = word_in(in_key + 16);
+                for(i = 0; i < l; ++i)
+                    ks5(i);
+                break;
+        case 6: cx->k_sch[4] = t = word_in(in_key + 16);
+                cx->k_sch[5] = u = word_in(in_key + 20);
+                for(i = 0; i < l; ++i)
+                    ks6(i);
+                break;
+        case 7: cx->k_sch[4] = t = word_in(in_key + 16);
+                cx->k_sch[5] = u = word_in(in_key + 20);
+                cx->k_sch[6] = v = word_in(in_key + 24);
+                for(i = 0; i < l; ++i)
+                    ks7(i);
+                break;
+        case 8: cx->k_sch[4] = t = word_in(in_key + 16);
+                cx->k_sch[5] = u = word_in(in_key + 20);
+                cx->k_sch[6] = v = word_in(in_key + 24);
+                cx->k_sch[7] = w = word_in(in_key + 28);
+                for(i = 0; i < l; ++i)
+                    ks8(i);
+                break;
+        }
+    }
+#endif
+
+#if (DEC_ROUND != NO_TABLES)
+    for(i = nc; i < nc * cx->n_rnd; ++i)
+        cx->k_sch[i] = inv_mcol(cx->k_sch[i]);
+#endif
+
+    return aes_good;
+}
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/aesopt.h b/mechglue/src/lib/crypto/aes/aesopt.h
new file mode 100644
index 000000000..9aa1654da
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aesopt.h
@@ -0,0 +1,849 @@
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explcit or implied warranties
+ in respect of any properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 07/02/2002
+
+ This file contains the compilation options for AES (Rijndael) and code 
+ that is common across encryption, key scheduling and table generation.
+
+
+    OPERATION
+ 
+    These source code files implement the AES algorithm Rijndael designed by
+    Joan Daemen and Vincent Rijmen. The version in aes.c is designed for 
+    block and key sizes of 128, 192 and 256 bits (16, 24 and 32 bytes) while 
+    that in aespp.c provides for block and keys sizes of 128, 160, 192, 224 
+    and 256 bits (16, 20, 24, 28 and 32 bytes).  This file is a common header 
+    file for these two implementations and for aesref.c, which is a reference 
+    implementation.
+    
+    This version is designed for flexibility and speed using operations on
+    32-bit words rather than operations on bytes.  It provides aes_both fixed 
+    and  dynamic block and key lengths and can also run with either big or 
+    little endian internal byte order (see aes.h).  It inputs block and key 
+    lengths in bytes with the legal values being  16, 24 and 32 for aes.c and 
+    16, 20, 24, 28 and 32 for aespp.c
+ 
+    THE CIPHER INTERFACE
+
+    uint8_t         (an unsigned  8-bit type)
+    uint32_t        (an unsigned 32-bit type)
+    aes_fret        (a signed 16 bit type for function return values)
+    aes_good        (value != 0, a good return)
+    aes_bad         (value == 0, an error return)
+    struct aes_ctx  (structure for the cipher encryption context)
+    struct aes_ctx  (structure for the cipher decryption context)
+    aes_rval        the function return type (aes_fret if not DLL)
+
+    C subroutine calls:
+
+      aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]);
+      aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+      aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+
+      aes_rval aes_dec_len(unsigned int blen, aes_ctx cx[1]);
+      aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+      aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+
+    IMPORTANT NOTE: If you are using this C interface and your compiler does 
+    not set the memory used for objects to zero before use, you will need to 
+    ensure that cx.s_flg is set to zero before using these subroutine calls.
+
+    C++ aes class subroutines:
+
+      class AESclass    for encryption
+      class AESclass    for decryption
+
+      aes_rval len(unsigned int blen = 16);
+      aes_rval key(const unsigned char in_key[], unsigned int klen);
+      aes_rval blk(const unsigned char in_blk[], unsigned char out_blk[]);
+
+      aes_rval len(unsigned int blen = 16);
+      aes_rval key(const unsigned char in_key[], unsigned int klen);
+      aes_rval blk(const unsigned char in_blk[], unsigned char out_blk[]);
+
+    The block length inputs to set_block and set_key are in numbers of
+    BYTES, not bits.  The calls to subroutines must be made in the above 
+    order but multiple calls can be made without repeating earlier calls
+    if their parameters have not changed. If the cipher block length is
+    variable but set_blk has not been called before cipher operations a
+    value of 16 is assumed (that is, the AES block size). In contrast to 
+    earlier versions the block and key length parameters are now checked
+    for correctness and the encryption and decryption routines check to 
+    ensure that an appropriate key has been set before they are called.
+
+    COMPILATION 
+
+    The files used to provide AES (Rijndael) are
+
+    a. aes.h for the definitions needed for use in C.
+    b. aescpp.h for the definitions needed for use in C++. 
+    c. aesopt.h for setting compilation options (also includes common
+       code).
+    d. aescrypt.c for encryption and decrytpion, or
+    e. aescrypt.asm for encryption and decryption using assembler code.
+    f. aeskey.c for key scheduling.
+    g. aestab.c for table loading or generation.
+    h. uitypes.h for defining fixed length unsigned integers.
+
+    The assembler code uses the NASM assembler. The above files provice
+    block and key lengths of 16, 24 and 32 bytes (128, 192 and 256 bits).
+    If aescrypp.c and aeskeypp.c are used instead of aescrypt.c and
+    aeskey.c respectively, the block and key lengths can then be 16, 20,
+    24, 28 or 32 bytes. However this code has not been optimised to the 
+    same extent and is hence slower (esepcially for the AES block size
+    of 16 bytes).
+
+    To compile AES (Rijndael) for use in C code use aes.h and exclude
+    the AES_DLL define in aes.h
+
+    To compile AES (Rijndael) for use in in C++ code use aescpp.h and
+    exclude the AES_DLL define in aes.h
+
+    To compile AES (Rijndael) in C as a Dynamic Link Library DLL) use
+    aes.h, include the AES_DLL define and compile the DLL.  If using 
+    the test files to test the DLL, exclude aes.c from the test build
+    project and compile it with the same defines as used for the DLL 
+    (ensure that the DLL path is correct)
+
+    CONFIGURATION OPTIONS (here and in aes.h)
+
+    a. define BLOCK_SIZE in aes.h to set the cipher block size (16, 24 
+       or 32 for the standard code, or 16, 20, 24, 28 or 32 for the 
+       extended code) or leave this undefined for dynamically variable 
+       block size (this will result in much slower code).
+    b. set AES_DLL in aes.h if AES (Rijndael) is to be compiled as a DLL
+    c. You may need to set PLATFORM_BYTE_ORDER to define the byte order. 
+    d. If you want the code to run in a specific internal byte order, then
+       INTERNAL_BYTE_ORDER must be set accordingly.
+    e. set other configuration options decribed below.
+*/ 
+
+#ifndef _AESOPT_H
+#define _AESOPT_H
+
+/*  START OF CONFIGURATION OPTIONS
+
+    USE OF DEFINES
+  
+    Later in this section there are a number of defines that control the 
+    operation of the code.  In each section, the purpose of each define is 
+    explained so that the relevant form can be included or excluded by 
+    setting either 1's or 0's respectively on the branches of the related 
+    #if clauses.
+*/
+
+/*  1. PLATFORM SPECIFIC INCLUDES */
+
+#if /* defined(__GNUC__) || */ defined(__GNU_LIBRARY__)
+#  include <endian.h>
+#  include <byteswap.h>
+#elif defined(__CRYPTLIB__)
+#  if defined( INC_ALL )
+#    include "crypt.h"
+#  elif defined( INC_CHILD )
+#    include "../crypt.h"
+#  else
+#    include "crypt.h"
+#  endif
+#  if defined(DATA_LITTLEENDIAN)
+#    define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#  else
+#    define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN
+#  endif
+#elif defined(_MSC_VER)
+#  include <stdlib.h>
+#elif defined(__m68k__) && defined(__palmos__)
+#  include <FloatMgr.h> /* defines BIG_ENDIAN */
+#elif defined(_MIPSEB)
+#  define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN
+#elif defined(_MIPSEL)
+#  define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#elif defined(_WIN32)
+#  define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#elif !defined(_WIN32)
+#  include <stdlib.h>
+#  if defined(HAVE_ENDIAN_H)
+#    include <endian.h>
+#  elif defined(HAVE_MACHINE_ENDIAN_H)
+#    include <machine/endian.h>
+#  else
+#    include <sys/param.h>
+#  endif
+#endif
+
+/*  2. BYTE ORDER IN 32-BIT WORDS
+
+    To obtain the highest speed on processors with 32-bit words, this code 
+    needs to determine the order in which bytes are packed into such words.
+    The following block of code is an attempt to capture the most obvious 
+    ways in which various environemnts specify heir endian definitions. It 
+    may well fail, in which case the definitions will need to be set by 
+    editing at the points marked **** EDIT HERE IF NECESSARY **** below.
+*/
+#define AES_LITTLE_ENDIAN   1234 /* byte 0 is least significant (i386) */
+#define AES_BIG_ENDIAN      4321 /* byte 0 is most significant (mc68k) */
+
+#if !defined(PLATFORM_BYTE_ORDER)
+#if defined(LITTLE_ENDIAN) || defined(BIG_ENDIAN)
+#  if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
+#    if defined(BYTE_ORDER)
+#      if   (BYTE_ORDER == LITTLE_ENDIAN)
+#        define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#      elif (BYTE_ORDER == BIG_ENDIAN)
+#        define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN
+#      endif
+#    endif
+#  elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) 
+#    define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#  elif !defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
+#    define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN
+#  endif
+#elif defined(_LITTLE_ENDIAN) || defined(_BIG_ENDIAN)
+#  if defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
+#    if defined(_BYTE_ORDER)
+#      if   (_BYTE_ORDER == _LITTLE_ENDIAN)
+#        define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#      elif (_BYTE_ORDER == _BIG_ENDIAN)
+#        define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN
+#      endif
+#    endif
+#  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) 
+#    define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#  elif !defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
+#    define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN
+#  endif
+#elif 0     /* **** EDIT HERE IF NECESSARY **** */
+#define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#elif 0     /* **** EDIT HERE IF NECESSARY **** */
+#define PLATFORM_BYTE_ORDER AES_BIG_ENDIAN
+#elif 1
+#define PLATFORM_BYTE_ORDER AES_LITTLE_ENDIAN
+#define UNKNOWN_BYTE_ORDER	/* we're guessing */
+#endif
+#endif
+
+/*  3. ASSEMBLER SUPPORT
+    
+    If the assembler code is used for encryption and decryption this file only 
+    provides key scheduling so the following defines are used
+*/
+#ifdef  AES_ASM
+#define ENCRYPTION_KEY_SCHEDULE
+#define DECRYPTION_KEY_SCHEDULE
+#endif
+
+/*  4. FUNCTIONS REQUIRED
+
+    This implementation provides five main subroutines which provide for
+    setting block length, setting encryption and decryption keys and for
+    encryption and decryption. When the assembler code is not being used
+    the following definition blocks allow the selection of the routines
+    that are to be included in the compilation.
+*/
+#if 1
+#ifndef AES_ASM
+#define SET_BLOCK_LENGTH
+#endif
+#endif
+
+#if 1
+#ifndef AES_ASM
+#define ENCRYPTION_KEY_SCHEDULE
+#endif
+#endif
+
+#if 1
+#ifndef AES_ASM
+#define DECRYPTION_KEY_SCHEDULE
+#endif
+#endif
+
+#if 1
+#ifndef AES_ASM
+#define ENCRYPTION
+#endif
+#endif
+
+#if 1
+#ifndef AES_ASM
+#define DECRYPTION
+#endif
+#endif
+
+/*  5. BYTE ORDER WITHIN 32 BIT WORDS
+
+    The fundamental data processing units in Rijndael are 8-bit bytes. The 
+    input, output and key input are all enumerated arrays of bytes in which 
+    bytes are numbered starting at zero and increasing to one less than the 
+    number of bytes in the array in question. This enumeration is only used 
+    for naming bytes and does not imply any adjacency or order relationship 
+    from one byte to another. When these inputs and outputs are considered 
+    as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to 
+    byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. 
+    In this implementation bits are numbered from 0 to 7 starting at the 
+    numerically least significant end of each byte (bit n represents 2^n).
+
+    However, Rijndael can be implemented more efficiently using 32-bit 
+    words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
+    into word[n]. While in principle these bytes can be assembled into words 
+    in any positions, this implementation only supports the two formats in 
+    which bytes in adjacent positions within words also have adjacent byte
+    numbers. This order is called big-endian if the lowest numbered bytes 
+    in words have the highest numeric significance and little-endian if the 
+    opposite applies. 
+    
+    This code can work in either order irrespective of the order used by the 
+    machine on which it runs. Normally the internal byte order will be set
+    to the order of the processor on which the code is to be run but this
+    define can be used to reverse this in special situations
+*/
+#if 1
+#define INTERNAL_BYTE_ORDER PLATFORM_BYTE_ORDER
+#elif defined(AES_LITTLE_ENDIAN)
+#define INTERNAL_BYTE_ORDER AES_LITTLE_ENDIAN
+#elif defined(AES_BIG_ENDIAN)
+#define INTERNAL_BYTE_ORDER AES_BIG_ENDIAN
+#endif
+
+/*  6. FAST INPUT/OUTPUT OPERATIONS.  
+
+    On some machines it is possible to improve speed by transferring the 
+    bytes in the input and output arrays to and from the internal 32-bit 
+    variables by addressing these arrays as if they are arrays of 32-bit 
+    words.  On some machines this will always be possible but there may 
+    be a large performance penalty if the byte arrays are not aligned on 
+    the normal word boundaries. On other machines this technique will 
+    lead to memory access errors when such 32-bit word accesses are not
+    properly aligned. The option SAFE_IO avoids such problems but will 
+    often be slower on those machines that support misaligned access 
+    (especially so if care is taken to align the input  and output byte 
+    arrays on 32-bit word boundaries). If SAFE_IO is not defined it is 
+    assumed that access to byte arrays as if they are arrays of 32-bit 
+    words will not cause problems when such accesses are misaligned.
+*/
+#if 1
+#define SAFE_IO
+#endif
+
+/*
+ * If PLATFORM_BYTE_ORDER does not match the actual machine byte
+ * order, the fast word-access code will cause incorrect results.
+ * Therefore, SAFE_IO is required when the byte order is unknown.
+ */
+#if !defined(SAFE_IO) && defined(UNKNOWN_BYTE_ORDER)
+#  error "SAFE_IO must be defined if machine byte order is unknown."
+#endif
+
+/*  7. LOOP UNROLLING
+
+    The code for encryption and decrytpion cycles through a number of rounds
+    that can be implemented either in a loop or by expanding the code into a 
+    long sequence of instructions, the latter producing a larger program but
+    one that will often be much faster. The latter is called loop unrolling.
+    There are also potential speed advantages in expanding two iterations in
+    a loop with half the number of iterations, which is called partial loop
+    unrolling.  The following options allow partial or full loop unrolling 
+    to be set independently for encryption and decryption
+*/
+#if !defined(CONFIG_SMALL)
+#define ENC_UNROLL  FULL
+#elif 0
+#define ENC_UNROLL  PARTIAL
+#else
+#define ENC_UNROLL  NONE
+#endif
+
+#if !defined(CONFIG_SMALL)
+#define DEC_UNROLL  FULL
+#elif 0
+#define DEC_UNROLL  PARTIAL
+#else
+#define DEC_UNROLL  NONE
+#endif
+
+/*  8. FIXED OR DYNAMIC TABLES
+
+    When this section is included the tables used by the code are compiled 
+    statically into the binary file.  Otherwise they are computed once when 
+    the code is first used.
+*/
+#if 1
+#define FIXED_TABLES
+#endif
+
+/*  9. FAST FINITE FIELD OPERATIONS
+
+    If this section is included, tables are used to provide faster finite 
+    field arithmetic (this has no effect if FIXED_TABLES is defined).
+*/
+#if 1
+#define FF_TABLES
+#endif
+
+/*  10. INTERNAL STATE VARIABLE FORMAT
+
+    The internal state of Rijndael is stored in a number of local 32-bit 
+    word varaibles which can be defined either as an array or as individual 
+    names variables. Include this section if you want to store these local
+    varaibles in arrays. Otherwise individual local variables will be used.
+*/
+#if 1
+#define ARRAYS
+#endif
+
+/* In this implementation the columns of the state array are each held in
+   32-bit words. The state array can be held in various ways: in an array
+   of words, in a number of individual word variables or in a number of 
+   processor registers. The following define maps a variable name x and
+   a column number c to the way the state array variable is to be held.
+   The first define below maps the state into an array x[c] whereas the 
+   second form maps the state into a number of individual variables x0,
+   x1, etc.  Another form could map individual state colums to machine
+   register names.
+*/
+
+#if defined(ARRAYS)
+#define s(x,c) x[c]
+#else
+#define s(x,c) x##c
+#endif
+
+/*  11. VARIABLE BLOCK SIZE SPEED
+
+    This section is only relevant if you wish to use the variable block
+    length feature of the code.  Include this section if you place more
+    emphasis on speed rather than code size.
+*/
+#if 1
+#define FAST_VARIABLE
+#endif
+
+/*  12. INTERNAL TABLE CONFIGURATION
+
+    This cipher proceeds by repeating in a number of cycles known as 'rounds'
+    which are implemented by a round function which can optionally be speeded
+    up using tables.  The basic tables are each 256 32-bit words, with either 
+    one or four tables being required for each round function depending on
+    how much speed is required. The encryption and decryption round functions
+    are different and the last encryption and decrytpion round functions are
+    different again making four different round functions in all.
+
+    This means that:
+      1. Normal encryption and decryption rounds can each use either 0, 1 
+         or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
+      2. The last encryption and decryption rounds can also use either 0, 1 
+         or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
+
+    Include or exclude the appropriate definitions below to set the number
+    of tables used by this implementation.
+*/
+
+#if !defined(CONFIG_SMALL)   /* set tables for the normal encryption round */
+#define ENC_ROUND   FOUR_TABLES
+#elif 0
+#define ENC_ROUND   ONE_TABLE
+#else
+#define ENC_ROUND   NO_TABLES
+#endif
+
+#if !defined(CONFIG_SMALL)       /* set tables for the last encryption round */
+#define LAST_ENC_ROUND  FOUR_TABLES
+#elif 0
+#define LAST_ENC_ROUND  ONE_TABLE
+#else
+#define LAST_ENC_ROUND  NO_TABLES
+#endif
+
+#if !defined(CONFIG_SMALL)   /* set tables for the normal decryption round */
+#define DEC_ROUND   FOUR_TABLES
+#elif 0
+#define DEC_ROUND   ONE_TABLE
+#else
+#define DEC_ROUND   NO_TABLES
+#endif
+
+#if !defined(CONFIG_SMALL)       /* set tables for the last decryption round */
+#define LAST_DEC_ROUND  FOUR_TABLES
+#elif 0
+#define LAST_DEC_ROUND  ONE_TABLE
+#else
+#define LAST_DEC_ROUND  NO_TABLES
+#endif
+
+/*  The decryption key schedule can be speeded up with tables in the same
+    way that the round functions can.  Include or exclude the following 
+    defines to set this requirement.
+*/
+#if !defined(CONFIG_SMALL)
+#define KEY_SCHED   FOUR_TABLES
+#elif 0
+#define KEY_SCHED   ONE_TABLE
+#else
+#define KEY_SCHED   NO_TABLES
+#endif
+
+/* END OF CONFIGURATION OPTIONS */
+
+#define NO_TABLES   0   /* DO NOT CHANGE */
+#define ONE_TABLE   1   /* DO NOT CHANGE */
+#define FOUR_TABLES 4   /* DO NOT CHANGE */
+#define NONE        0   /* DO NOT CHANGE */
+#define PARTIAL     1   /* DO NOT CHANGE */
+#define FULL        2   /* DO NOT CHANGE */
+
+#if defined(BLOCK_SIZE) && ((BLOCK_SIZE & 3) || BLOCK_SIZE < 16 || BLOCK_SIZE > 32)
+#error An illegal block size has been specified.
+#endif  
+
+#if !defined(BLOCK_SIZE)
+#define RC_LENGTH    29
+#else
+#define RC_LENGTH   5 * BLOCK_SIZE / 4 - (BLOCK_SIZE == 16 ? 10 : 11)
+#endif
+
+/* Disable at least some poor combinations of options */
+
+#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
+#undef  LAST_ENC_ROUND
+#define LAST_ENC_ROUND  NO_TABLES
+#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
+#undef  LAST_ENC_ROUND
+#define LAST_ENC_ROUND  ONE_TABLE 
+#endif
+
+#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
+#undef  ENC_UNROLL
+#define ENC_UNROLL  NONE
+#endif
+
+#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
+#undef  LAST_DEC_ROUND
+#define LAST_DEC_ROUND  NO_TABLES
+#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
+#undef  LAST_DEC_ROUND
+#define LAST_DEC_ROUND  ONE_TABLE 
+#endif
+
+#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
+#undef  DEC_UNROLL
+#define DEC_UNROLL  NONE
+#endif
+
+#include "aes.h"
+
+ /*
+   upr(x,n):  rotates bytes within words by n positions, moving bytes to
+              higher index positions with wrap around into low positions
+   ups(x,n):  moves bytes by n positions to higher index positions in 
+              words but without wrap around
+   bval(x,n): extracts a byte from a word
+ */
+
+#if (INTERNAL_BYTE_ORDER == AES_LITTLE_ENDIAN)
+#if defined(_MSC_VER)
+#define upr(x,n)        _lrotl((x), 8 * (n))
+#else
+#define upr(x,n)        (((x) << (8 * (n))) | ((x) >> (32 - 8 * (n))))
+#endif
+#define ups(x,n)        ((x) << (8 * (n)))
+#define bval(x,n)       ((uint8_t)((x) >> (8 * (n))))
+#define bytes2word(b0, b1, b2, b3)  \
+        (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
+#endif
+
+#if (INTERNAL_BYTE_ORDER == AES_BIG_ENDIAN)
+#define upr(x,n)        (((x) >> (8 * (n))) | ((x) << (32 - 8 * (n))))
+#define ups(x,n)        ((x) >> (8 * (n))))
+#define bval(x,n)       ((uint8_t)((x) >> (24 - 8 * (n))))
+#define bytes2word(b0, b1, b2, b3)  \
+        (((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (b3))
+#endif
+
+#if defined(SAFE_IO)
+
+#define word_in(x)      bytes2word((x)[0], (x)[1], (x)[2], (x)[3])
+#define word_out(x,v)   { (x)[0] = bval(v,0); (x)[1] = bval(v,1);   \
+                          (x)[2] = bval(v,2); (x)[3] = bval(v,3);   }
+
+#elif (INTERNAL_BYTE_ORDER == PLATFORM_BYTE_ORDER)
+
+#define word_in(x)      *(uint32_t*)(x)
+#define word_out(x,v)   *(uint32_t*)(x) = (v)
+
+#else
+
+#if !defined(bswap_32)
+#if !defined(_MSC_VER)
+#define _lrotl(x,n)     (((x) <<  n) | ((x) >> (32 - n)))
+#endif
+#define bswap_32(x)     ((_lrotl((x),8) & 0x00ff00ff) | (_lrotl((x),24) & 0xff00ff00)) 
+#endif
+
+#define word_in(x)      bswap_32(*(uint32_t*)(x))
+#define word_out(x,v)   *(uint32_t*)(x) = bswap_32(v)
+
+#endif
+
+/* the finite field modular polynomial and elements */
+
+#define WPOLY   0x011b
+#define BPOLY     0x1b
+
+/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+#define m1  0x80808080
+#define m2  0x7f7f7f7f
+#define FFmulX(x)  ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY))
+
+/* The following defines provide alternative definitions of FFmulX that might
+   give improved performance if a fast 32-bit multiply is not available. Note
+   that a temporary variable u needs to be defined where FFmulX is used.
+
+#define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) 
+#define m4  (0x01010101 * BPOLY)
+#define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) 
+*/
+
+/* Work out which tables are needed for the different options   */
+
+#ifdef  AES_ASM
+#ifdef  ENC_ROUND
+#undef  ENC_ROUND
+#endif
+#define ENC_ROUND   FOUR_TABLES
+#ifdef  LAST_ENC_ROUND
+#undef  LAST_ENC_ROUND
+#endif
+#define LAST_ENC_ROUND  FOUR_TABLES
+#ifdef  DEC_ROUND
+#undef  DEC_ROUND
+#endif
+#define DEC_ROUND   FOUR_TABLES
+#ifdef  LAST_DEC_ROUND
+#undef  LAST_DEC_ROUND
+#endif
+#define LAST_DEC_ROUND  FOUR_TABLES
+#ifdef  KEY_SCHED
+#undef  KEY_SCHED
+#define KEY_SCHED   FOUR_TABLES
+#endif
+#endif
+
+#if defined(ENCRYPTION) || defined(AES_ASM)
+#if ENC_ROUND == ONE_TABLE
+#define FT1_SET
+#elif ENC_ROUND == FOUR_TABLES
+#define FT4_SET
+#else
+#define SBX_SET
+#endif
+#if LAST_ENC_ROUND == ONE_TABLE
+#define FL1_SET
+#elif LAST_ENC_ROUND == FOUR_TABLES
+#define FL4_SET
+#elif !defined(SBX_SET)
+#define SBX_SET
+#endif
+#endif
+
+#if defined(DECRYPTION) || defined(AES_ASM)
+#if DEC_ROUND == ONE_TABLE
+#define IT1_SET
+#elif DEC_ROUND == FOUR_TABLES
+#define IT4_SET
+#else
+#define ISB_SET
+#endif
+#if LAST_DEC_ROUND == ONE_TABLE
+#define IL1_SET
+#elif LAST_DEC_ROUND == FOUR_TABLES
+#define IL4_SET
+#elif !defined(ISB_SET)
+#define ISB_SET
+#endif
+#endif
+
+#if defined(ENCRYPTION_KEY_SCHEDULE) || defined(DECRYPTION_KEY_SCHEDULE)
+#if KEY_SCHED == ONE_TABLE
+#define LS1_SET
+#define IM1_SET
+#elif KEY_SCHED == FOUR_TABLES
+#define LS4_SET
+#define IM4_SET
+#elif !defined(SBX_SET)
+#define SBX_SET
+#endif
+#endif
+
+#ifdef  FIXED_TABLES
+#define prefx   extern const
+#else
+#define prefx   extern
+extern uint8_t  tab_init;
+void gen_tabs(void);
+#endif
+
+prefx uint32_t  rcon_tab[29];
+
+#ifdef  SBX_SET
+prefx uint8_t s_box[256];
+#endif
+
+#ifdef  ISB_SET
+prefx uint8_t inv_s_box[256];
+#endif
+
+#ifdef  FT1_SET
+prefx uint32_t ft_tab[256];
+#endif
+
+#ifdef  FT4_SET
+prefx uint32_t ft_tab[4][256];
+#endif
+
+#ifdef  FL1_SET
+prefx uint32_t fl_tab[256];
+#endif
+
+#ifdef  FL4_SET
+prefx uint32_t fl_tab[4][256];
+#endif
+
+#ifdef  IT1_SET
+prefx uint32_t it_tab[256];
+#endif
+
+#ifdef  IT4_SET
+prefx uint32_t it_tab[4][256];
+#endif
+
+#ifdef  IL1_SET
+prefx uint32_t il_tab[256];
+#endif
+
+#ifdef  IL4_SET
+prefx uint32_t il_tab[4][256];
+#endif
+
+#ifdef  LS1_SET
+#ifdef  FL1_SET
+#undef  LS1_SET
+#else
+prefx uint32_t ls_tab[256];
+#endif
+#endif
+
+#ifdef  LS4_SET
+#ifdef  FL4_SET
+#undef  LS4_SET
+#else
+prefx uint32_t ls_tab[4][256];
+#endif
+#endif
+
+#ifdef  IM1_SET
+prefx uint32_t im_tab[256];
+#endif
+
+#ifdef  IM4_SET
+prefx uint32_t im_tab[4][256];
+#endif
+
+/* Set the number of columns in nc.  Note that it is important  */
+/* that nc is a constant which is known at compile time if the  */
+/* highest speed version of the code is needed                  */
+
+#if defined(BLOCK_SIZE)
+#define nc  (BLOCK_SIZE >> 2)
+#else
+#define nc  (cx->n_blk >> 2)
+#endif
+
+/* generic definitions of Rijndael macros that use of tables    */
+
+#define no_table(x,box,vf,rf,c) bytes2word( \
+    box[bval(vf(x,0,c),rf(0,c))], \
+    box[bval(vf(x,1,c),rf(1,c))], \
+    box[bval(vf(x,2,c),rf(2,c))], \
+    box[bval(vf(x,3,c),rf(3,c))])
+
+#define one_table(x,op,tab,vf,rf,c) \
+ (     tab[bval(vf(x,0,c),rf(0,c))] \
+  ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \
+  ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \
+  ^ op(tab[bval(vf(x,3,c),rf(3,c))],3))
+
+#define four_tables(x,tab,vf,rf,c) \
+ (  tab[0][bval(vf(x,0,c),rf(0,c))] \
+  ^ tab[1][bval(vf(x,1,c),rf(1,c))] \
+  ^ tab[2][bval(vf(x,2,c),rf(2,c))] \
+  ^ tab[3][bval(vf(x,3,c),rf(3,c))])
+
+#define vf1(x,r,c)  (x)
+#define rf1(r,c)    (r)
+#define rf2(r,c)    ((r-c)&3)
+
+/* perform forward and inverse column mix operation on four bytes in long word x in */
+/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros.  */
+
+#define dec_fmvars
+#if defined(FM4_SET)    /* not currently used */
+#define fwd_mcol(x)     four_tables(x,fm_tab,vf1,rf1,0)
+#elif defined(FM1_SET)  /* not currently used */
+#define fwd_mcol(x)     one_table(x,upr,fm_tab,vf1,rf1,0)
+#else
+#undef  dec_fmvars
+#define dec_fmvars      uint32_t f1, f2;
+#define fwd_mcol(x)     (f1 = (x), f2 = FFmulX(f1), f2 ^ upr(f1 ^ f2, 3) ^ upr(f1, 2) ^ upr(f1, 1))
+#endif
+
+#define dec_imvars
+#if defined(IM4_SET)
+#define inv_mcol(x)     four_tables(x,im_tab,vf1,rf1,0)
+#elif defined(IM1_SET)
+#define inv_mcol(x)     one_table(x,upr,im_tab,vf1,rf1,0)
+#else
+#undef  dec_imvars
+#define dec_imvars      uint32_t    f2, f4, f8, f9;
+#define inv_mcol(x) \
+    (f9 = (x), f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \
+    f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1))
+#endif
+
+#if defined(FL4_SET)
+#define ls_box(x,c)     four_tables(x,fl_tab,vf1,rf2,c)
+#elif   defined(LS4_SET)
+#define ls_box(x,c)     four_tables(x,ls_tab,vf1,rf2,c)
+#elif defined(FL1_SET)
+#define ls_box(x,c)     one_table(x,upr,fl_tab,vf1,rf2,c)
+#elif defined(LS1_SET)
+#define ls_box(x,c)     one_table(x,upr,ls_tab,vf1,rf2,c)
+#else
+#define ls_box(x,c)     no_table(x,s_box,vf1,rf2,c)
+#endif
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/aessrc.url b/mechglue/src/lib/crypto/aes/aessrc.url
new file mode 100644
index 000000000..0758737db
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aessrc.url
@@ -0,0 +1 @@
+http://fp.gladman.plus.com/cryptography_technology/rijndael/index.htm
diff --git a/mechglue/src/lib/crypto/aes/aestab.c b/mechglue/src/lib/crypto/aes/aestab.c
new file mode 100644
index 000000000..7a5d69f7d
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/aestab.c
@@ -0,0 +1,494 @@
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explcit or implied warranties
+ in respect of any properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 07/02/2002
+*/
+
+#include "aesopt.h"
+
+#if defined(FIXED_TABLES) || !defined(FF_TABLES) 
+
+/*  finite field arithmetic operations */
+
+#define f2(x)   ((x<<1) ^ (((x>>7) & 1) * WPOLY))
+#define f4(x)   ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
+#define f8(x)   ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \
+                        ^ (((x>>5) & 4) * WPOLY))
+#define f3(x)   (f2(x) ^ x)
+#define f9(x)   (f8(x) ^ x)
+#define fb(x)   (f8(x) ^ f2(x) ^ x)
+#define fd(x)   (f8(x) ^ f4(x) ^ x)
+#define fe(x)   (f8(x) ^ f4(x) ^ f2(x))
+
+#endif
+
+#if defined(FIXED_TABLES)
+
+#define sb_data(w) \
+    w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
+    w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
+    w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
+    w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
+    w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
+    w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
+    w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
+    w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
+    w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
+    w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
+    w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
+    w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
+    w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
+    w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
+    w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
+    w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
+    w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
+    w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
+    w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
+    w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
+    w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
+    w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
+    w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
+    w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
+    w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
+    w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
+    w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
+    w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
+    w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
+    w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
+    w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
+    w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16)
+
+#define isb_data(w) \
+    w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
+    w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
+    w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
+    w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
+    w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
+    w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
+    w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
+    w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
+    w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
+    w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
+    w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
+    w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
+    w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
+    w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
+    w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
+    w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
+    w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
+    w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
+    w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
+    w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
+    w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
+    w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
+    w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
+    w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
+    w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
+    w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
+    w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
+    w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
+    w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
+    w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
+    w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
+    w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d),
+
+#define mm_data(w) \
+    w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
+    w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
+    w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
+    w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
+    w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
+    w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
+    w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
+    w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
+    w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
+    w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
+    w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
+    w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
+    w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
+    w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
+    w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
+    w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
+    w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
+    w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
+    w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
+    w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
+    w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
+    w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
+    w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
+    w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
+    w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
+    w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
+    w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
+    w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
+    w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
+    w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
+    w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
+    w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff)
+
+#define h0(x)   (x)
+
+/*  These defines are used to ensure tables are generated in the 
+    right format depending on the internal byte order required
+*/
+
+#define w0(p)   bytes2word(p, 0, 0, 0)
+#define w1(p)   bytes2word(0, p, 0, 0)
+#define w2(p)   bytes2word(0, 0, p, 0)
+#define w3(p)   bytes2word(0, 0, 0, p)
+
+/*  Number of elements required in this table for different
+    block and key lengths is:
+
+    Rcon Table      key length (bytes)
+    Length          16  20  24  28  32
+                ---------------------
+    block     16 |  10   9   8   7   7
+    length    20 |  14  11  10   9   9
+    (bytes)   24 |  19  15  12  11  11
+              28 |  24  19  16  13  13
+              32 |  29  23  19  17  14
+
+    this table can be a table of bytes if the key schedule
+    code is adjusted accordingly
+*/
+
+#define u0(p)   bytes2word(f2(p), p, p, f3(p))
+#define u1(p)   bytes2word(f3(p), f2(p), p, p)
+#define u2(p)   bytes2word(p, f3(p), f2(p), p)
+#define u3(p)   bytes2word(p, p, f3(p), f2(p))
+
+#define v0(p)   bytes2word(fe(p), f9(p), fd(p), fb(p))
+#define v1(p)   bytes2word(fb(p), fe(p), f9(p), fd(p))
+#define v2(p)   bytes2word(fd(p), fb(p), fe(p), f9(p))
+#define v3(p)   bytes2word(f9(p), fd(p), fb(p), fe(p))
+
+const uint32_t rcon_tab[29] =
+{
+    w0(0x01), w0(0x02), w0(0x04), w0(0x08),
+    w0(0x10), w0(0x20), w0(0x40), w0(0x80),
+    w0(0x1b), w0(0x36), w0(0x6c), w0(0xd8),
+    w0(0xab), w0(0x4d), w0(0x9a), w0(0x2f),
+    w0(0x5e), w0(0xbc), w0(0x63), w0(0xc6),
+    w0(0x97), w0(0x35), w0(0x6a), w0(0xd4),
+    w0(0xb3), w0(0x7d), w0(0xfa), w0(0xef),
+    w0(0xc5)
+};
+
+#ifdef  SBX_SET
+const uint8_t s_box[256] = { sb_data(h0) };
+#endif
+#ifdef  ISB_SET
+const uint8_t inv_s_box[256] = { isb_data(h0) };
+#endif
+
+#ifdef  FT1_SET
+const uint32_t ft_tab[256] = { sb_data(u0) };
+#endif
+#ifdef  FT4_SET
+const uint32_t ft_tab[4][256] = 
+    { {  sb_data(u0) }, {  sb_data(u1) }, {  sb_data(u2) }, {  sb_data(u3) } };
+#endif
+
+#ifdef  FL1_SET
+const uint32_t fl_tab[256] = { sb_data(w0) };
+#endif
+#ifdef  FL4_SET
+const uint32_t fl_tab[4][256] = 
+    { {  sb_data(w0) }, {  sb_data(w1) }, {  sb_data(w2) }, {  sb_data(w3) } };
+#endif
+
+#ifdef  IT1_SET
+const uint32_t it_tab[256] = { isb_data(v0) };
+#endif
+#ifdef  IT4_SET
+const uint32_t it_tab[4][256] =
+    { { isb_data(v0) }, { isb_data(v1) }, { isb_data(v2) }, { isb_data(v3) } };
+#endif
+
+#ifdef  IL1_SET
+const uint32_t il_tab[256] = { isb_data(w0) };
+#endif
+#ifdef  IL4_SET
+const uint32_t il_tab[4][256] = 
+    { { isb_data(w0) }, { isb_data(w1) }, { isb_data(w2) }, { isb_data(w3) } };
+#endif
+
+#ifdef  LS1_SET
+const uint32_t ls_tab[256] = { sb_data(w0) };
+#endif
+#ifdef  LS4_SET
+const uint32_t ls_tab[4][256] =
+    { {  sb_data(w0) }, {  sb_data(w1) }, {  sb_data(w2) }, {  sb_data(w3) } };
+#endif
+
+#ifdef  IM1_SET
+const uint32_t im_tab[256] = { mm_data(v0) };
+#endif
+#ifdef  IM4_SET
+const uint32_t im_tab[4][256] = 
+    { {  mm_data(v0) }, {  mm_data(v1) }, {  mm_data(v2) }, {  mm_data(v3) } };
+#endif
+
+#else   /* dynamic table generation */
+
+uint8_t tab_init = 0;
+
+#define const
+
+uint32_t  rcon_tab[RC_LENGTH];
+
+#ifdef  SBX_SET
+uint8_t s_box[256];
+#endif
+#ifdef  ISB_SET
+uint8_t inv_s_box[256];
+#endif
+
+#ifdef  FT1_SET
+uint32_t ft_tab[256];
+#endif
+#ifdef  FT4_SET
+uint32_t ft_tab[4][256];
+#endif
+
+#ifdef  FL1_SET
+uint32_t fl_tab[256];
+#endif
+#ifdef  FL4_SET
+uint32_t fl_tab[4][256];
+#endif
+
+#ifdef  IT1_SET
+uint32_t it_tab[256];
+#endif
+#ifdef  IT4_SET
+uint32_t it_tab[4][256];
+#endif
+
+#ifdef  IL1_SET
+uint32_t il_tab[256];
+#endif
+#ifdef  IL4_SET
+uint32_t il_tab[4][256];
+#endif
+
+#ifdef  LS1_SET
+uint32_t ls_tab[256];
+#endif
+#ifdef  LS4_SET
+uint32_t ls_tab[4][256];
+#endif
+
+#ifdef  IM1_SET
+uint32_t im_tab[256];
+#endif
+#ifdef  IM4_SET
+uint32_t im_tab[4][256];
+#endif
+
+#if !defined(FF_TABLES)
+
+/*  Generate the tables for the dynamic table option
+
+    It will generally be sensible to use tables to compute finite 
+    field multiplies and inverses but where memory is scarse this 
+    code might sometimes be better. But it only has effect during
+    initialisation so its pretty unimportant in overall terms.
+*/
+
+/*  return 2 ^ (n - 1) where n is the bit number of the highest bit
+    set in x with x in the range 1 < x < 0x00000200.   This form is
+    used so that locals within fi can be bytes rather than words
+*/
+
+static uint8_t hibit(const uint32_t x)
+{   uint8_t r = (uint8_t)((x >> 1) | (x >> 2));
+    
+    r |= (r >> 2);
+    r |= (r >> 4);
+    return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint8_t fi(const uint8_t x)
+{   uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+    if(x < 2) return x;
+
+    for(;;)
+    {
+        if(!n1) return v1;
+
+        while(n2 >= n1)
+        {   
+            n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
+        }
+        
+        if(!n2) return v2;
+
+        while(n1 >= n2)
+        {   
+            n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
+        }
+    }
+}
+
+#else
+
+/* define the finite field multiplies required for Rijndael */
+
+#define f2(x) ((x) ? pow[log[x] + 0x19] : 0)
+#define f3(x) ((x) ? pow[log[x] + 0x01] : 0)
+#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0)
+#define fb(x) ((x) ? pow[log[x] + 0x68] : 0)
+#define fd(x) ((x) ? pow[log[x] + 0xee] : 0)
+#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0)
+#define fi(x) ((x) ?   pow[255 - log[x]]: 0)
+
+#endif
+
+/* The forward and inverse affine transformations used in the S-box */
+
+#define fwd_affine(x) \
+    (w = (uint32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(uint8_t)(w^(w>>8)))
+
+#define inv_affine(x) \
+    (w = (uint32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(uint8_t)(w^(w>>8)))
+
+void gen_tabs(void)
+{   uint32_t  i, w;
+
+#if defined(FF_TABLES)
+
+    uint8_t  pow[512], log[256];
+
+    /*  log and power tables for GF(2^8) finite field with
+        WPOLY as modular polynomial - the simplest primitive
+        root is 0x03, used here to generate the tables
+    */
+
+    i = 0; w = 1; 
+    do
+    {   
+        pow[i] = (uint8_t)w;
+        pow[i + 255] = (uint8_t)w;
+        log[w] = (uint8_t)i++;
+        w ^=  (w << 1) ^ (w & 0x80 ? WPOLY : 0);
+    }
+    while (w != 1);
+
+#endif
+
+    for(i = 0, w = 1; i < RC_LENGTH; ++i)
+    {
+        rcon_tab[i] = bytes2word(w, 0, 0, 0);
+        w = f2(w);
+    }
+
+    for(i = 0; i < 256; ++i)
+    {   uint8_t    b;
+
+        b = fwd_affine(fi((uint8_t)i));
+        w = bytes2word(f2(b), b, b, f3(b));
+
+#ifdef  SBX_SET
+        s_box[i] = b;
+#endif
+
+#ifdef  FT1_SET                 /* tables for a normal encryption round */
+        ft_tab[i] = w;
+#endif
+#ifdef  FT4_SET
+        ft_tab[0][i] = w;
+        ft_tab[1][i] = upr(w,1);
+        ft_tab[2][i] = upr(w,2);
+        ft_tab[3][i] = upr(w,3);
+#endif
+        w = bytes2word(b, 0, 0, 0);
+
+#ifdef  FL1_SET                 /* tables for last encryption round (may also   */
+        fl_tab[i] = w;          /* be used in the key schedule)                 */
+#endif
+#ifdef  FL4_SET
+        fl_tab[0][i] = w;
+        fl_tab[1][i] = upr(w,1);
+        fl_tab[2][i] = upr(w,2);
+        fl_tab[3][i] = upr(w,3);
+#endif
+
+#ifdef  LS1_SET                 /* table for key schedule if fl_tab above is    */
+        ls_tab[i] = w;          /* not of the required form                     */
+#endif
+#ifdef  LS4_SET
+        ls_tab[0][i] = w;
+        ls_tab[1][i] = upr(w,1);
+        ls_tab[2][i] = upr(w,2);
+        ls_tab[3][i] = upr(w,3);
+#endif
+
+        b = fi(inv_affine((uint8_t)i));
+        w = bytes2word(fe(b), f9(b), fd(b), fb(b));
+
+#ifdef  IM1_SET                 /* tables for the inverse mix column operation  */
+        im_tab[b] = w;
+#endif
+#ifdef  IM4_SET
+        im_tab[0][b] = w;
+        im_tab[1][b] = upr(w,1);
+        im_tab[2][b] = upr(w,2);
+        im_tab[3][b] = upr(w,3);
+#endif
+
+#ifdef  ISB_SET
+        inv_s_box[i] = b;
+#endif
+#ifdef  IT1_SET                 /* tables for a normal decryption round */
+        it_tab[i] = w;
+#endif
+#ifdef  IT4_SET
+        it_tab[0][i] = w;
+        it_tab[1][i] = upr(w,1);
+        it_tab[2][i] = upr(w,2);
+        it_tab[3][i] = upr(w,3);
+#endif
+        w = bytes2word(b, 0, 0, 0);
+#ifdef  IL1_SET                 /* tables for last decryption round */
+        il_tab[i] = w;
+#endif
+#ifdef  IL4_SET
+        il_tab[0][i] = w;
+        il_tab[1][i] = upr(w,1);
+        il_tab[2][i] = upr(w,2);
+        il_tab[3][i] = upr(w,3);
+#endif
+    }
+
+    tab_init = 1;
+}
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/expect-vk.txt b/mechglue/src/lib/crypto/aes/expect-vk.txt
new file mode 100644
index 000000000..bbd2c587b
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/expect-vk.txt
@@ -0,0 +1,1548 @@
+
+KEYSIZE=128
+
+PT=00000000000000000000000000000000
+
+I=1
+KEY=80000000000000000000000000000000
+CT=0EDD33D3C621E546455BD8BA1418BEC8
+
+I=2
+KEY=40000000000000000000000000000000
+CT=C0CC0C5DA5BD63ACD44A80774FAD5222
+
+I=3
+KEY=20000000000000000000000000000000
+CT=2F0B4B71BC77851B9CA56D42EB8FF080
+
+I=4
+KEY=10000000000000000000000000000000
+CT=6B1E2FFFE8A114009D8FE22F6DB5F876
+
+I=5
+KEY=08000000000000000000000000000000
+CT=9AA042C315F94CBB97B62202F83358F5
+
+I=6
+KEY=04000000000000000000000000000000
+CT=DBE01DE67E346A800C4C4B4880311DE4
+
+I=7
+KEY=02000000000000000000000000000000
+CT=C117D2238D53836ACD92DDCDB85D6A21
+
+I=8
+KEY=01000000000000000000000000000000
+CT=DC0ED85DF9611ABB7249CDD168C5467E
+
+I=9
+KEY=00800000000000000000000000000000
+CT=807D678FFF1F56FA92DE3381904842F2
+
+I=10
+KEY=00400000000000000000000000000000
+CT=0E53B3FCAD8E4B130EF73AEB957FB402
+
+I=11
+KEY=00200000000000000000000000000000
+CT=969FFD3B7C35439417E7BDE923035D65
+
+I=12
+KEY=00100000000000000000000000000000
+CT=A99B512C19CA56070491166A1503BF15
+
+I=13
+KEY=00080000000000000000000000000000
+CT=6E9985252126EE344D26AE369D2327E3
+
+I=14
+KEY=00040000000000000000000000000000
+CT=B85F4809F904C275491FCDCD1610387E
+
+I=15
+KEY=00020000000000000000000000000000
+CT=ED365B8D7D20C1F5D53FB94DD211DF7B
+
+I=16
+KEY=00010000000000000000000000000000
+CT=B3A575E86A8DB4A7135D604C43304896
+
+I=17
+KEY=00008000000000000000000000000000
+CT=89704BCB8E69F846259EB0ACCBC7F8A2
+
+I=18
+KEY=00004000000000000000000000000000
+CT=C56EE7C92197861F10D7A92B90882055
+
+I=19
+KEY=00002000000000000000000000000000
+CT=92F296F6846E0EAF9422A5A24A08B069
+
+I=20
+KEY=00001000000000000000000000000000
+CT=E67E32BB8F11DEB8699318BEE9E91A60
+
+I=21
+KEY=00000800000000000000000000000000
+CT=B08EEF85EAF626DD91B65C4C3A97D92B
+
+I=22
+KEY=00000400000000000000000000000000
+CT=661083A6ADDCE79BB4E0859AB5538013
+
+I=23
+KEY=00000200000000000000000000000000
+CT=55DFE2941E0EB10AFC0B333BD34DE1FE
+
+I=24
+KEY=00000100000000000000000000000000
+CT=6BFE5945E715C9662609770F8846087A
+
+I=25
+KEY=00000080000000000000000000000000
+CT=79848E9C30C2F8CDA8B325F7FED2B139
+
+I=26
+KEY=00000040000000000000000000000000
+CT=7A713A53B99FEF34AC04DEEF80965BD0
+
+I=27
+KEY=00000020000000000000000000000000
+CT=18144A2B46620D32C3C32CE52D49257F
+
+I=28
+KEY=00000010000000000000000000000000
+CT=872E827C70887C80749F7B8BB1847C7E
+
+I=29
+KEY=00000008000000000000000000000000
+CT=6B86C6A4FE6A60C59B1A3102F8DE49F3
+
+I=30
+KEY=00000004000000000000000000000000
+CT=9848BB3DFDF6F532F094679A4C231A20
+
+I=31
+KEY=00000002000000000000000000000000
+CT=925AD528E852E329B2091CD3F1C2BCEE
+
+I=32
+KEY=00000001000000000000000000000000
+CT=80DF436544B0DD596722E46792A40CD8
+
+I=33
+KEY=00000000800000000000000000000000
+CT=525DAF18F93E83E1E74BBBDDE4263BBA
+
+I=34
+KEY=00000000400000000000000000000000
+CT=F65C9D2EE485D24701FFA3313B9D5BE6
+
+I=35
+KEY=00000000200000000000000000000000
+CT=E4FC8D8BCA06425BDF94AFA40FCC14BA
+
+I=36
+KEY=00000000100000000000000000000000
+CT=A53F0A5CA1E4E6440BB975FF320DE6F8
+
+I=37
+KEY=00000000080000000000000000000000
+CT=D55313B9394080462E87E02899B553F0
+
+I=38
+KEY=00000000040000000000000000000000
+CT=34A71D761F71BCD344384C7F97D27906
+
+I=39
+KEY=00000000020000000000000000000000
+CT=233F3D819599612EBC89580245C996A8
+
+I=40
+KEY=00000000010000000000000000000000
+CT=B4F1374E5268DBCB676E447529E53F89
+
+I=41
+KEY=00000000008000000000000000000000
+CT=0816BD27861D2BA891D1044E39951E96
+
+I=42
+KEY=00000000004000000000000000000000
+CT=F3BE9EA3F10C73CA64FDE5DB13A951D1
+
+I=43
+KEY=00000000002000000000000000000000
+CT=2448086A8106FBD03048DDF857D3F1C8
+
+I=44
+KEY=00000000001000000000000000000000
+CT=670756E65BEC8B68F03D77CDCDCE7B91
+
+I=45
+KEY=00000000000800000000000000000000
+CT=EF968CF0D36FD6C6EFFD225F6FB44CA9
+
+I=46
+KEY=00000000000400000000000000000000
+CT=2E8767157922E3826DDCEC1B0CC1E105
+
+I=47
+KEY=00000000000200000000000000000000
+CT=78CE7EEC670E45A967BAB17E26A1AD36
+
+I=48
+KEY=00000000000100000000000000000000
+CT=3C5CEE825655F098F6E81A2F417DA3FB
+
+I=49
+KEY=00000000000080000000000000000000
+CT=67BFDB431DCE1292200BC6F5207ADB12
+
+I=50
+KEY=00000000000040000000000000000000
+CT=7540FD38E447C0779228548747843A6F
+
+I=51
+KEY=00000000000020000000000000000000
+CT=B85E513301F8A936EA9EC8A21A85B5E6
+
+I=52
+KEY=00000000000010000000000000000000
+CT=04C67DBF16C11427D507A455DE2C9BC5
+
+I=53
+KEY=00000000000008000000000000000000
+CT=03F75EB8959E55079CFFB4FF149A37B6
+
+I=54
+KEY=00000000000004000000000000000000
+CT=74550287F666C63BB9BC7838433434B0
+
+I=55
+KEY=00000000000002000000000000000000
+CT=7D537200195EBC3AEFD1EAAB1C385221
+
+I=56
+KEY=00000000000001000000000000000000
+CT=CE24E4D40C68A82B535CBD3C8E21652A
+
+I=57
+KEY=00000000000000800000000000000000
+CT=AB20072405AA8FC40265C6F1F3DC8BC0
+
+I=58
+KEY=00000000000000400000000000000000
+CT=6CFD2CF688F566B093F67B9B3839E80A
+
+I=59
+KEY=00000000000000200000000000000000
+CT=BD95977E6B7239D407A012C5544BF584
+
+I=60
+KEY=00000000000000100000000000000000
+CT=DF9C0130AC77E7C72C997F587B46DBE0
+
+I=61
+KEY=00000000000000080000000000000000
+CT=E7F1B82CADC53A648798945B34EFEFF2
+
+I=62
+KEY=00000000000000040000000000000000
+CT=932C6DBF69255CF13EDCDB72233ACEA3
+
+I=63
+KEY=00000000000000020000000000000000
+CT=5C76002BC7206560EFE550C80B8F12CC
+
+I=64
+KEY=00000000000000010000000000000000
+CT=F6B7BDD1CAEEBAB574683893C4475484
+
+I=65
+KEY=00000000000000008000000000000000
+CT=A920E37CC6DC6B31DA8C0169569F5034
+
+I=66
+KEY=00000000000000004000000000000000
+CT=919380ECD9C778BC513148B0C28D65FD
+
+I=67
+KEY=00000000000000002000000000000000
+CT=EE67308DD3F2D9E6C2170755E5784BE1
+
+I=68
+KEY=00000000000000001000000000000000
+CT=3CC73E53B85609023A05E149B223AE09
+
+I=69
+KEY=00000000000000000800000000000000
+CT=983E8AF7CF05EBB28D71EB841C9406E6
+
+I=70
+KEY=00000000000000000400000000000000
+CT=0F3099B2D31FA5299EE5BF43193287FC
+
+I=71
+KEY=00000000000000000200000000000000
+CT=B763D84F38C27FE6931DCEB6715D4DB6
+
+I=72
+KEY=00000000000000000100000000000000
+CT=5AE3C9B0E3CC29C0C61565CD01F8A248
+
+I=73
+KEY=00000000000000000080000000000000
+CT=F58083572CD90981958565D48D2DEE25
+
+I=74
+KEY=00000000000000000040000000000000
+CT=7E6255EEF8F70C0EF10337AAB1CCCEF8
+
+I=75
+KEY=00000000000000000020000000000000
+CT=AAD4BAC34DB22821841CE2F631961902
+
+I=76
+KEY=00000000000000000010000000000000
+CT=D7431C0409BB1441BA9C6858DC7D4E81
+
+I=77
+KEY=00000000000000000008000000000000
+CT=EF9298C65E339F6E801A59C626456993
+
+I=78
+KEY=00000000000000000004000000000000
+CT=53FE29F68FF541ABC3F0EF3350B72F7E
+
+I=79
+KEY=00000000000000000002000000000000
+CT=F6BBA5C10DB02529E2C2DA3FB582CC14
+
+I=80
+KEY=00000000000000000001000000000000
+CT=E4239AA37FC531A386DAD1126FC0E9CD
+
+I=81
+KEY=00000000000000000000800000000000
+CT=8F7758F857D15BBE7BFD0E416404C365
+
+I=82
+KEY=00000000000000000000400000000000
+CT=D273EB57C687BCD1B4EA7218A509E7B8
+
+I=83
+KEY=00000000000000000000200000000000
+CT=65D64F8D76E8B3423FA25C4EB58A210A
+
+I=84
+KEY=00000000000000000000100000000000
+CT=623D802B4EC450D66A16625702FCDBE0
+
+I=85
+KEY=00000000000000000000080000000000
+CT=7496460CB28E5791BAEAF9B68FB00022
+
+I=86
+KEY=00000000000000000000040000000000
+CT=34EA600F18BB0694B41681A49D510C1D
+
+I=87
+KEY=00000000000000000000020000000000
+CT=5F8FF0D47D5766D29B5D6E8F46423BD8
+
+I=88
+KEY=00000000000000000000010000000000
+CT=225F9286C5928BF09F84D3F93F541959
+
+I=89
+KEY=00000000000000000000008000000000
+CT=B21E90D25DF383416A5F072CEBEB1FFB
+
+I=90
+KEY=00000000000000000000004000000000
+CT=4AEFCDA089318125453EB9E8EB5E492E
+
+I=91
+KEY=00000000000000000000002000000000
+CT=4D3E75C6CD40EC4869BC85158591ADB8
+
+I=92
+KEY=00000000000000000000001000000000
+CT=63A8B904405436A1B99D7751866771B7
+
+I=93
+KEY=00000000000000000000000800000000
+CT=64F0DAAE47529199792EAE172BA53293
+
+I=94
+KEY=00000000000000000000000400000000
+CT=C3EEF84BEA18225D515A8C852A9047EE
+
+I=95
+KEY=00000000000000000000000200000000
+CT=A44AC422B47D47B81AF73B3E9AC9596E
+
+I=96
+KEY=00000000000000000000000100000000
+CT=D16E04A8FBC435094F8D53ADF25F5084
+
+I=97
+KEY=00000000000000000000000080000000
+CT=EF13DC34BAB03E124EEAD8B6BF44B532
+
+I=98
+KEY=00000000000000000000000040000000
+CT=D94799075C24DCC067AF0D392049250D
+
+I=99
+KEY=00000000000000000000000020000000
+CT=14F431771EDDCE4764C21A2254B5E3C8
+
+I=100
+KEY=00000000000000000000000010000000
+CT=7039329F36F2ED682B02991F28D64679
+
+I=101
+KEY=00000000000000000000000008000000
+CT=124EE24EDE5551639DB8B8B941F6141D
+
+I=102
+KEY=00000000000000000000000004000000
+CT=C2852879A34D5184E478EC918B993FEE
+
+I=103
+KEY=00000000000000000000000002000000
+CT=86A806A3525B93E432053C9AB5ABBEDF
+
+I=104
+KEY=00000000000000000000000001000000
+CT=C1609BF5A4F07E37C17A36366EC23ECC
+
+I=105
+KEY=00000000000000000000000000800000
+CT=7E81E7CB92159A51FFCEA331B1E8EA53
+
+I=106
+KEY=00000000000000000000000000400000
+CT=37A7BE002856C5A59A6E03EAFCE7729A
+
+I=107
+KEY=00000000000000000000000000200000
+CT=BDF98A5A4F91E890C9A1D1E5FAAB138F
+
+I=108
+KEY=00000000000000000000000000100000
+CT=4E96ACB66E051F2BC739CC3D3E34A26B
+
+I=109
+KEY=00000000000000000000000000080000
+CT=EE996CDD120EB86E21ECFA49E8E1FCF1
+
+I=110
+KEY=00000000000000000000000000040000
+CT=61B9E6B579DBF6070C351A1440DD85FF
+
+I=111
+KEY=00000000000000000000000000020000
+CT=AC369E484316440B40DFC83AA96E28E7
+
+I=112
+KEY=00000000000000000000000000010000
+CT=0A2D16DE985C76D45C579C1159413BBE
+
+I=113
+KEY=00000000000000000000000000008000
+CT=DA3FDC38DA1D374FA4802CDA1A1C6B0F
+
+I=114
+KEY=00000000000000000000000000004000
+CT=B842523D4C41C2211AFE43A5800ADCE3
+
+I=115
+KEY=00000000000000000000000000002000
+CT=9E2CDA90D8E992DBA6C73D8229567192
+
+I=116
+KEY=00000000000000000000000000001000
+CT=D49583B781D9E20F5BE101415957FC49
+
+I=117
+KEY=00000000000000000000000000000800
+CT=EF09DA5C12B376E458B9B8670032498E
+
+I=118
+KEY=00000000000000000000000000000400
+CT=A96BE0463DA774461A5E1D5A9DD1AC10
+
+I=119
+KEY=00000000000000000000000000000200
+CT=32CEE3341060790D2D4B1362EF397090
+
+I=120
+KEY=00000000000000000000000000000100
+CT=21CEA416A3D3359D2C4D58FB6A035F06
+
+I=121
+KEY=00000000000000000000000000000080
+CT=172AEAB3D507678ECAF455C12587ADB7
+
+I=122
+KEY=00000000000000000000000000000040
+CT=B6F897941EF8EBFF9FE80A567EF38478
+
+I=123
+KEY=00000000000000000000000000000020
+CT=A9723259D94A7DC662FB0C782CA3F1DD
+
+I=124
+KEY=00000000000000000000000000000010
+CT=2F91C984B9A4839F30001B9F430493B4
+
+I=125
+KEY=00000000000000000000000000000008
+CT=0472406345A610B048CB99EE0EF3FA0F
+
+I=126
+KEY=00000000000000000000000000000004
+CT=F5F39086646F8C05ED16EFA4B617957C
+
+I=127
+KEY=00000000000000000000000000000002
+CT=26D50F485A30408D5AF47A5736292450
+
+I=128
+KEY=00000000000000000000000000000001
+CT=0545AAD56DA2A97C3663D1432A3D1C84
+
+==========
+
+KEYSIZE=256
+
+PT=00000000000000000000000000000000
+
+I=1
+KEY=8000000000000000000000000000000000000000000000000000000000000000
+CT=E35A6DCB19B201A01EBCFA8AA22B5759
+
+I=2
+KEY=4000000000000000000000000000000000000000000000000000000000000000
+CT=5075C2405B76F22F553488CAE47CE90B
+
+I=3
+KEY=2000000000000000000000000000000000000000000000000000000000000000
+CT=49DF95D844A0145A7DE01C91793302D3
+
+I=4
+KEY=1000000000000000000000000000000000000000000000000000000000000000
+CT=E7396D778E940B8418A86120E5F421FE
+
+I=5
+KEY=0800000000000000000000000000000000000000000000000000000000000000
+CT=05F535C36FCEDE4657BE37F4087DB1EF
+
+I=6
+KEY=0400000000000000000000000000000000000000000000000000000000000000
+CT=D0C1DDDD10DA777C68AB36AF51F2C204
+
+I=7
+KEY=0200000000000000000000000000000000000000000000000000000000000000
+CT=1C55FB811B5C6464C4E5DE1535A75514
+
+I=8
+KEY=0100000000000000000000000000000000000000000000000000000000000000
+CT=52917F3AE957D5230D3A2AF57C7B5A71
+
+I=9
+KEY=0080000000000000000000000000000000000000000000000000000000000000
+CT=C6E3D5501752DD5E9AEF086D6B45D705
+
+I=10
+KEY=0040000000000000000000000000000000000000000000000000000000000000
+CT=A24A9C7AF1D9B1E17E1C9A3E711B3FA7
+
+I=11
+KEY=0020000000000000000000000000000000000000000000000000000000000000
+CT=B881ECA724A6D43DBC6B96F6F59A0D20
+
+I=12
+KEY=0010000000000000000000000000000000000000000000000000000000000000
+CT=EC524D9A24DFFF2A9639879B83B8E137
+
+I=13
+KEY=0008000000000000000000000000000000000000000000000000000000000000
+CT=34C4F345F5466215A037F443635D6F75
+
+I=14
+KEY=0004000000000000000000000000000000000000000000000000000000000000
+CT=5BA5055BEDB8895F672E29F2EB5A355D
+
+I=15
+KEY=0002000000000000000000000000000000000000000000000000000000000000
+CT=B3F692AA3A435259EBBEF9B51AD1E08D
+
+I=16
+KEY=0001000000000000000000000000000000000000000000000000000000000000
+CT=414FEB4376F2C64A5D2FBB2ED531BA7D
+
+I=17
+KEY=0000800000000000000000000000000000000000000000000000000000000000
+CT=A20D519E3BCA3303F07E81719F61605E
+
+I=18
+KEY=0000400000000000000000000000000000000000000000000000000000000000
+CT=A08D10E520AF811F45BD60A2DC0DC4B1
+
+I=19
+KEY=0000200000000000000000000000000000000000000000000000000000000000
+CT=B06893A8C563C430E6F3858826EFBBE4
+
+I=20
+KEY=0000100000000000000000000000000000000000000000000000000000000000
+CT=0FFEE26AE2D3929C6BD9C6BEDFF84409
+
+I=21
+KEY=0000080000000000000000000000000000000000000000000000000000000000
+CT=4D0F5E906ED77801FC0EF53EDC5F9E2B
+
+I=22
+KEY=0000040000000000000000000000000000000000000000000000000000000000
+CT=8B6EC00119AD8B026DCE56EA7DEFE930
+
+I=23
+KEY=0000020000000000000000000000000000000000000000000000000000000000
+CT=69026591D43363EE9D83B5007F0B484E
+
+I=24
+KEY=0000010000000000000000000000000000000000000000000000000000000000
+CT=27135D86950C6A2F86872706279A4761
+
+I=25
+KEY=0000008000000000000000000000000000000000000000000000000000000000
+CT=35E6DB8723F281DA410C3AC8535ED77C
+
+I=26
+KEY=0000004000000000000000000000000000000000000000000000000000000000
+CT=57427CF214B8C28E4BBF487CCB8D0E09
+
+I=27
+KEY=0000002000000000000000000000000000000000000000000000000000000000
+CT=6DF01BF56E5131AC87F96E99CAB86367
+
+I=28
+KEY=0000001000000000000000000000000000000000000000000000000000000000
+CT=3856C5B55790B768BBF7D43031579BCF
+
+I=29
+KEY=0000000800000000000000000000000000000000000000000000000000000000
+CT=1E6ED8FB7C15BC4D2F63BA7037ED44D0
+
+I=30
+KEY=0000000400000000000000000000000000000000000000000000000000000000
+CT=E1B2ED6CD8D93D455534E401156D4BCF
+
+I=31
+KEY=0000000200000000000000000000000000000000000000000000000000000000
+CT=EFBCCA5BDFDAD10E875F02336212CE36
+
+I=32
+KEY=0000000100000000000000000000000000000000000000000000000000000000
+CT=0B777F02FD18DCE2646DCFE868DFAFAD
+
+I=33
+KEY=0000000080000000000000000000000000000000000000000000000000000000
+CT=C8A104B5693D1B14F5BF1F10100BF508
+
+I=34
+KEY=0000000040000000000000000000000000000000000000000000000000000000
+CT=4CCE6615244AFCB38408FECE219962EA
+
+I=35
+KEY=0000000020000000000000000000000000000000000000000000000000000000
+CT=F99E7845D3A255B394C9C050CBA258B1
+
+I=36
+KEY=0000000010000000000000000000000000000000000000000000000000000000
+CT=B4AFBB787F9BCFB7B55FDF447F611295
+
+I=37
+KEY=0000000008000000000000000000000000000000000000000000000000000000
+CT=AE1C426A697FAF2808B7EF6ADDB5C020
+
+I=38
+KEY=0000000004000000000000000000000000000000000000000000000000000000
+CT=7572F92811A85B9BDD38DEAD9945BCAE
+
+I=39
+KEY=0000000002000000000000000000000000000000000000000000000000000000
+CT=71BC7AA46E43FB95A181527D9F6A360F
+
+I=40
+KEY=0000000001000000000000000000000000000000000000000000000000000000
+CT=5542EF2923066F1EC8F546DD0D8E7CA8
+
+I=41
+KEY=0000000000800000000000000000000000000000000000000000000000000000
+CT=6B92317C7D623790B748FDD7EFC42422
+
+I=42
+KEY=0000000000400000000000000000000000000000000000000000000000000000
+CT=0FE7C097E899C71EF045360F8D6C25CF
+
+I=43
+KEY=0000000000200000000000000000000000000000000000000000000000000000
+CT=4ECE7EE107D0264D04693151C25B9DF6
+
+I=44
+KEY=0000000000100000000000000000000000000000000000000000000000000000
+CT=FD6AE687CBFCA9E301045888D3BB9605
+
+I=45
+KEY=0000000000080000000000000000000000000000000000000000000000000000
+CT=476B579C8556C7254424902CC1D6D36E
+
+I=46
+KEY=0000000000040000000000000000000000000000000000000000000000000000
+CT=4133CBCDFDD6B8860A1FC18665D6D71B
+
+I=47
+KEY=0000000000020000000000000000000000000000000000000000000000000000
+CT=3B36EC2664798C108B816812C65DFDC7
+
+I=48
+KEY=0000000000010000000000000000000000000000000000000000000000000000
+CT=364E20A234FEA385D48DC5A09C9E70CF
+
+I=49
+KEY=0000000000008000000000000000000000000000000000000000000000000000
+CT=4A4BA25969DE3F5EE5642C71AAD0EFD1
+
+I=50
+KEY=0000000000004000000000000000000000000000000000000000000000000000
+CT=E42CBAAE43297F67A76C1C501BB79E36
+
+I=51
+KEY=0000000000002000000000000000000000000000000000000000000000000000
+CT=23CEDEDA4C15B4C037E8C61492217937
+
+I=52
+KEY=0000000000001000000000000000000000000000000000000000000000000000
+CT=A1719147A1F4A1A1180BD16E8593DCDE
+
+I=53
+KEY=0000000000000800000000000000000000000000000000000000000000000000
+CT=AB82337E9FB0EC60D1F25A1D0014192C
+
+I=54
+KEY=0000000000000400000000000000000000000000000000000000000000000000
+CT=74BF2D8FC5A8388DF1A3A4D7D33FC164
+
+I=55
+KEY=0000000000000200000000000000000000000000000000000000000000000000
+CT=D5B493317E6FBC6FFFD664B3C491368A
+
+I=56
+KEY=0000000000000100000000000000000000000000000000000000000000000000
+CT=BA767381586DA56A2A8D503D5F7ADA0B
+
+I=57
+KEY=0000000000000080000000000000000000000000000000000000000000000000
+CT=E8E6BC57DFE9CCADB0DECABF4E5CF91F
+
+I=58
+KEY=0000000000000040000000000000000000000000000000000000000000000000
+CT=3C8E5A5CDC9CEED90815D1F84BB2998C
+
+I=59
+KEY=0000000000000020000000000000000000000000000000000000000000000000
+CT=283843020BA38F056001B2FD585F7CC9
+
+I=60
+KEY=0000000000000010000000000000000000000000000000000000000000000000
+CT=D8ADC7426F623ECE8741A70621D28870
+
+I=61
+KEY=0000000000000008000000000000000000000000000000000000000000000000
+CT=D7C5C215592D06F00E6A80DA69A28EA9
+
+I=62
+KEY=0000000000000004000000000000000000000000000000000000000000000000
+CT=52CF6FA433C3C870CAC70190358F7F16
+
+I=63
+KEY=0000000000000002000000000000000000000000000000000000000000000000
+CT=F63D442A584DA71786ADEC9F3346DF75
+
+I=64
+KEY=0000000000000001000000000000000000000000000000000000000000000000
+CT=549078F4B0CA7079B45F9A5ADAFAFD99
+
+I=65
+KEY=0000000000000000800000000000000000000000000000000000000000000000
+CT=F2A5986EE4E9984BE2BAFB79EA8152FA
+
+I=66
+KEY=0000000000000000400000000000000000000000000000000000000000000000
+CT=8A74535017B4DB2776668A1FAE64384C
+
+I=67
+KEY=0000000000000000200000000000000000000000000000000000000000000000
+CT=E613342F57A97FD95DC088711A5D0ECD
+
+I=68
+KEY=0000000000000000100000000000000000000000000000000000000000000000
+CT=3FFAEBF6B22CF1DC82AE17CD48175B01
+
+I=69
+KEY=0000000000000000080000000000000000000000000000000000000000000000
+CT=BAFD52EFA15C248CCBF9757735E6B1CE
+
+I=70
+KEY=0000000000000000040000000000000000000000000000000000000000000000
+CT=7AF94BC018D9DDD4539D2DD1C6F4000F
+
+I=71
+KEY=0000000000000000020000000000000000000000000000000000000000000000
+CT=FE177AD61CA0FDB281086FBA8FE76803
+
+I=72
+KEY=0000000000000000010000000000000000000000000000000000000000000000
+CT=74DBEA15E2E9285BAD163D7D534251B6
+
+I=73
+KEY=0000000000000000008000000000000000000000000000000000000000000000
+CT=23DD21331B3A92F200FE56FF050FFE74
+
+I=74
+KEY=0000000000000000004000000000000000000000000000000000000000000000
+CT=A69C5AA34AB20A858CAFA766EACED6D8
+
+I=75
+KEY=0000000000000000002000000000000000000000000000000000000000000000
+CT=3F72BB4DF2A4F941A4A09CB78F04B97A
+
+I=76
+KEY=0000000000000000001000000000000000000000000000000000000000000000
+CT=72CC43577E1FD5FD14622D24D97FCDCC
+
+I=77
+KEY=0000000000000000000800000000000000000000000000000000000000000000
+CT=D83AF8EBE93E0B6B99CAFADE224937D1
+
+I=78
+KEY=0000000000000000000400000000000000000000000000000000000000000000
+CT=44042329128D56CAA8D084C8BD769D1E
+
+I=79
+KEY=0000000000000000000200000000000000000000000000000000000000000000
+CT=14102D72290DE4F2C430ADD1ED64BA1D
+
+I=80
+KEY=0000000000000000000100000000000000000000000000000000000000000000
+CT=449124097B1ECD0AE7065206DF06F03C
+
+I=81
+KEY=0000000000000000000080000000000000000000000000000000000000000000
+CT=D060A99F8CC153A42E11E5F97BD7584A
+
+I=82
+KEY=0000000000000000000040000000000000000000000000000000000000000000
+CT=65605B3EA9261488D53E48602ADEA299
+
+I=83
+KEY=0000000000000000000020000000000000000000000000000000000000000000
+CT=C5E5CAD7A208DE8EA6BE049EFE5C7346
+
+I=84
+KEY=0000000000000000000010000000000000000000000000000000000000000000
+CT=4C280C46D2181646048DD5BC0C0831A5
+
+I=85
+KEY=0000000000000000000008000000000000000000000000000000000000000000
+CT=5DD65CF37F2A0929559AABAFDA08E730
+
+I=86
+KEY=0000000000000000000004000000000000000000000000000000000000000000
+CT=31F2335CAAF264172F69A693225E6D22
+
+I=87
+KEY=0000000000000000000002000000000000000000000000000000000000000000
+CT=3E28B35F99A72662590DA96426DD377F
+
+I=88
+KEY=0000000000000000000001000000000000000000000000000000000000000000
+CT=570F40F5D7B20441486578ED344343BE
+
+I=89
+KEY=0000000000000000000000800000000000000000000000000000000000000000
+CT=C54308AD1C9E3B19F8B7417873045A8C
+
+I=90
+KEY=0000000000000000000000400000000000000000000000000000000000000000
+CT=CBF335E39CE13ADE2B696179E8FD0CE1
+
+I=91
+KEY=0000000000000000000000200000000000000000000000000000000000000000
+CT=9C2FBF422355D8293083D51F4A3C18A9
+
+I=92
+KEY=0000000000000000000000100000000000000000000000000000000000000000
+CT=5ED8B5A31ECEFAB16C9AA6986DA67BCE
+
+I=93
+KEY=0000000000000000000000080000000000000000000000000000000000000000
+CT=627815DCFC814ABC75900041B1DD7B59
+
+I=94
+KEY=0000000000000000000000040000000000000000000000000000000000000000
+CT=9EF3E82A50A59F166260494F7A7F2CC3
+
+I=95
+KEY=0000000000000000000000020000000000000000000000000000000000000000
+CT=878CD0D8D920888B5935D6C351128737
+
+I=96
+KEY=0000000000000000000000010000000000000000000000000000000000000000
+CT=E44429474D6FC3084EB2A6B8B46AF754
+
+I=97
+KEY=0000000000000000000000008000000000000000000000000000000000000000
+CT=EBAACF9641D54E1FB18D0A2BE4F19BE5
+
+I=98
+KEY=0000000000000000000000004000000000000000000000000000000000000000
+CT=13B3BF497CEE780E123C7E193DEA3A01
+
+I=99
+KEY=0000000000000000000000002000000000000000000000000000000000000000
+CT=6E8F381DE00A41161F0DF03B4155BFD4
+
+I=100
+KEY=0000000000000000000000001000000000000000000000000000000000000000
+CT=35E4F29BBA2BAE01144910783C3FEF49
+
+I=101
+KEY=0000000000000000000000000800000000000000000000000000000000000000
+CT=55B17BD66788CEAC366398A31F289FFB
+
+I=102
+KEY=0000000000000000000000000400000000000000000000000000000000000000
+CT=11341F56C0D6D1008D28741DAA7679CE
+
+I=103
+KEY=0000000000000000000000000200000000000000000000000000000000000000
+CT=4DF7253DF421D83358BDBE924745D98C
+
+I=104
+KEY=0000000000000000000000000100000000000000000000000000000000000000
+CT=BAE2EE651116D93EDC8E83B5F3347BE1
+
+I=105
+KEY=0000000000000000000000000080000000000000000000000000000000000000
+CT=F9721ABD06709157183AF3965A659D9D
+
+I=106
+KEY=0000000000000000000000000040000000000000000000000000000000000000
+CT=19A1C252A613FE2860A4AE6D75CE6FA3
+
+I=107
+KEY=0000000000000000000000000020000000000000000000000000000000000000
+CT=B5DDB2F5D9752C949FBDE3FFF5556C6E
+
+I=108
+KEY=0000000000000000000000000010000000000000000000000000000000000000
+CT=81B044FCFFC78ECCFCD171AAD0405C66
+
+I=109
+KEY=0000000000000000000000000008000000000000000000000000000000000000
+CT=C640566D3C06020EB2C42F1D62E56A9B
+
+I=110
+KEY=0000000000000000000000000004000000000000000000000000000000000000
+CT=EA6C4BCF425291679FDFFD26A424FBCC
+
+I=111
+KEY=0000000000000000000000000002000000000000000000000000000000000000
+CT=57F6901465D9440D9F15EE2CBA5A4090
+
+I=112
+KEY=0000000000000000000000000001000000000000000000000000000000000000
+CT=FBCFA74CADC7406260F63D96C8AAB6B1
+
+I=113
+KEY=0000000000000000000000000000800000000000000000000000000000000000
+CT=DFF4F096CEA211D4BBDACA033D0EC7D1
+
+I=114
+KEY=0000000000000000000000000000400000000000000000000000000000000000
+CT=1EE5190D551F0F42F675227A381296A9
+
+I=115
+KEY=0000000000000000000000000000200000000000000000000000000000000000
+CT=F98E1905012E580F097623C10B93054F
+
+I=116
+KEY=0000000000000000000000000000100000000000000000000000000000000000
+CT=E7D43743D21DD3C9F168C86856558B9A
+
+I=117
+KEY=0000000000000000000000000000080000000000000000000000000000000000
+CT=632A9DDA730DAB67593C5D08D8AC1059
+
+I=118
+KEY=0000000000000000000000000000040000000000000000000000000000000000
+CT=E084317000715B9057BC9DE9F3AB6124
+
+I=119
+KEY=0000000000000000000000000000020000000000000000000000000000000000
+CT=61F9EF33A0BB4E666C2ED99101919FAB
+
+I=120
+KEY=0000000000000000000000000000010000000000000000000000000000000000
+CT=6DC1D68A11834657D46703C22578D59A
+
+I=121
+KEY=0000000000000000000000000000008000000000000000000000000000000000
+CT=53AC1548863D3D16F1D4DC7242E05F2C
+
+I=122
+KEY=0000000000000000000000000000004000000000000000000000000000000000
+CT=E82CD587A408306AD78CEAE0916B9F8C
+
+I=123
+KEY=0000000000000000000000000000002000000000000000000000000000000000
+CT=0FD2D40EA6AD17A3A767F0A8600D6295
+
+I=124
+KEY=0000000000000000000000000000001000000000000000000000000000000000
+CT=AD84CC8255ADB39DFCA23F92761AE7E9
+
+I=125
+KEY=0000000000000000000000000000000800000000000000000000000000000000
+CT=F4F20CF7D51BEE7DA024A2B11A7ECA0B
+
+I=126
+KEY=0000000000000000000000000000000400000000000000000000000000000000
+CT=5057691B85D9CE93A193214DB0A016B6
+
+I=127
+KEY=0000000000000000000000000000000200000000000000000000000000000000
+CT=0F58C960876390BDEF4BB6BE95CAA1EE
+
+I=128
+KEY=0000000000000000000000000000000100000000000000000000000000000000
+CT=9A3E66EEBC21BC0BD9430B341EF465FA
+
+I=129
+KEY=0000000000000000000000000000000080000000000000000000000000000000
+CT=20415035F34B8BCBCB28ABF07F78F0D4
+
+I=130
+KEY=0000000000000000000000000000000040000000000000000000000000000000
+CT=AC89FC7BA10479EBF10DE65BCEF89B3C
+
+I=131
+KEY=0000000000000000000000000000000020000000000000000000000000000000
+CT=068FA75A30BE443171AF3F6FEB1A20D2
+
+I=132
+KEY=0000000000000000000000000000000010000000000000000000000000000000
+CT=50E02F213246C525A8C27700CA34B502
+
+I=133
+KEY=0000000000000000000000000000000008000000000000000000000000000000
+CT=227DA47D5A0906DB3AB042BB0A695FB6
+
+I=134
+KEY=0000000000000000000000000000000004000000000000000000000000000000
+CT=8663AC30ED12514F1DE46777F4514BFC
+
+I=135
+KEY=0000000000000000000000000000000002000000000000000000000000000000
+CT=A987D4BC12E1DE9F4B6DF43567C34A8B
+
+I=136
+KEY=0000000000000000000000000000000001000000000000000000000000000000
+CT=6D5A0370F599ACA605F63B04E5143D0C
+
+I=137
+KEY=0000000000000000000000000000000000800000000000000000000000000000
+CT=9809266E378B07B7AFDB3BAA97B7E442
+
+I=138
+KEY=0000000000000000000000000000000000400000000000000000000000000000
+CT=8F753252B30CCCACE12D9A301F4D5090
+
+I=139
+KEY=0000000000000000000000000000000000200000000000000000000000000000
+CT=032465F6C0CE34D41962F561692A1AFF
+
+I=140
+KEY=0000000000000000000000000000000000100000000000000000000000000000
+CT=C50E9AD5BEB8F3B00821DD47FF8AC093
+
+I=141
+KEY=0000000000000000000000000000000000080000000000000000000000000000
+CT=9C6FEA3D46268D54A6829B2AD25BB276
+
+I=142
+KEY=0000000000000000000000000000000000040000000000000000000000000000
+CT=0FD8575E87706F561343D7B3A41E044A
+
+I=143
+KEY=0000000000000000000000000000000000020000000000000000000000000000
+CT=BEE9BEB3739540D88CBCE77925F0A114
+
+I=144
+KEY=0000000000000000000000000000000000010000000000000000000000000000
+CT=D24EAEE7FFFBAC3D6F26C2DCE0DCDE28
+
+I=145
+KEY=0000000000000000000000000000000000008000000000000000000000000000
+CT=47771A90398FF0F7FA821C2F8F5E1398
+
+I=146
+KEY=0000000000000000000000000000000000004000000000000000000000000000
+CT=4639741B6F84B135AD118C8249B64ED0
+
+I=147
+KEY=0000000000000000000000000000000000002000000000000000000000000000
+CT=8EE5505EC85567697A3306F250A27720
+
+I=148
+KEY=0000000000000000000000000000000000001000000000000000000000000000
+CT=7C8A19AC1AEFBC5E0119D91A5F05D4C2
+
+I=149
+KEY=0000000000000000000000000000000000000800000000000000000000000000
+CT=5141B9B672E54773B672E3A6C424887B
+
+I=150
+KEY=0000000000000000000000000000000000000400000000000000000000000000
+CT=B5A2D3CD206653C6402F34FB0AE3613D
+
+I=151
+KEY=0000000000000000000000000000000000000200000000000000000000000000
+CT=0F5BD9408738231D114B0A82753279A3
+
+I=152
+KEY=0000000000000000000000000000000000000100000000000000000000000000
+CT=FEF033FF4268EA487FC74C5E43A45338
+
+I=153
+KEY=0000000000000000000000000000000000000080000000000000000000000000
+CT=A3EDC09DCD529B113910D904AD855581
+
+I=154
+KEY=0000000000000000000000000000000000000040000000000000000000000000
+CT=AB8FBB6F27A0AC7C55B59FDD36B72F1C
+
+I=155
+KEY=0000000000000000000000000000000000000020000000000000000000000000
+CT=EEA44D5ED4D769CC930CD83D8999EC46
+
+I=156
+KEY=0000000000000000000000000000000000000010000000000000000000000000
+CT=6972276803AE9AA7C6F431AB10979C34
+
+I=157
+KEY=0000000000000000000000000000000000000008000000000000000000000000
+CT=86DEAA9F39244101818178474D7DBDE9
+
+I=158
+KEY=0000000000000000000000000000000000000004000000000000000000000000
+CT=88C6B466EA361D662D8D08CBF181F4FE
+
+I=159
+KEY=0000000000000000000000000000000000000002000000000000000000000000
+CT=91AB2C6B7C63FF59F7CBEEBF91B20B95
+
+I=160
+KEY=0000000000000000000000000000000000000001000000000000000000000000
+CT=2DFE6C146AD5B3D8C3C1718F13B48E01
+
+I=161
+KEY=0000000000000000000000000000000000000000800000000000000000000000
+CT=C7CFF1623451711391A302EEC3584AAA
+
+I=162
+KEY=0000000000000000000000000000000000000000400000000000000000000000
+CT=089FE845CC05011686C66019D18BE050
+
+I=163
+KEY=0000000000000000000000000000000000000000200000000000000000000000
+CT=08C8410B9B427211A67124B0DCCEAD48
+
+I=164
+KEY=0000000000000000000000000000000000000000100000000000000000000000
+CT=8D91592F5566085254784606334D7629
+
+I=165
+KEY=0000000000000000000000000000000000000000080000000000000000000000
+CT=3298FEAAF2E1201D6299FF8846639C97
+
+I=166
+KEY=0000000000000000000000000000000000000000040000000000000000000000
+CT=C497CB9F0BDFE0EFC8C2F3F90760AA72
+
+I=167
+KEY=0000000000000000000000000000000000000000020000000000000000000000
+CT=2788AFD046E0309CBE4424690DA2AB89
+
+I=168
+KEY=0000000000000000000000000000000000000000010000000000000000000000
+CT=E9891707F25EF29FEE372890D4258982
+
+I=169
+KEY=0000000000000000000000000000000000000000008000000000000000000000
+CT=DB041D94A23D45D4D4DCED5A030CAF61
+
+I=170
+KEY=0000000000000000000000000000000000000000004000000000000000000000
+CT=FFAFDBF0ECB18DF9EA02C27077448E6D
+
+I=171
+KEY=0000000000000000000000000000000000000000002000000000000000000000
+CT=2DAAA42A7D0A1D3B0E4761D99CF2150A
+
+I=172
+KEY=0000000000000000000000000000000000000000001000000000000000000000
+CT=3B7A54CB7CF30ABE263DD6ED5BFE8D63
+
+I=173
+KEY=0000000000000000000000000000000000000000000800000000000000000000
+CT=EEFA090174C590C448A55D43648F534A
+
+I=174
+KEY=0000000000000000000000000000000000000000000400000000000000000000
+CT=9E15798731ED42F43EA2740A691DA872
+
+I=175
+KEY=0000000000000000000000000000000000000000000200000000000000000000
+CT=31FBD661540A5DEAAD1017CFD3909EC8
+
+I=176
+KEY=0000000000000000000000000000000000000000000100000000000000000000
+CT=CDA9AE05F224140E28CB951721B44D6A
+
+I=177
+KEY=0000000000000000000000000000000000000000000080000000000000000000
+CT=0C5BC512C60A1EAC3434EFB1A8FBB182
+
+I=178
+KEY=0000000000000000000000000000000000000000000040000000000000000000
+CT=AA863610DEEEEB62D045E87EA30B59B5
+
+I=179
+KEY=0000000000000000000000000000000000000000000020000000000000000000
+CT=6AC2448DE568D279C7EEBE1DF403920C
+
+I=180
+KEY=0000000000000000000000000000000000000000000010000000000000000000
+CT=E2011E3D292B26888AE801215FD0CB40
+
+I=181
+KEY=0000000000000000000000000000000000000000000008000000000000000000
+CT=E06F3E15EE3A61672D1C99BADE5B9DBE
+
+I=182
+KEY=0000000000000000000000000000000000000000000004000000000000000000
+CT=BB7027F0548CF6712CEB4C7A4B28E178
+
+I=183
+KEY=0000000000000000000000000000000000000000000002000000000000000000
+CT=061EC21FB70FADBDF87C3BD2AE23825B
+
+I=184
+KEY=0000000000000000000000000000000000000000000001000000000000000000
+CT=4C21F26FE94ABBAC381352375314C3EB
+
+I=185
+KEY=0000000000000000000000000000000000000000000000800000000000000000
+CT=F7CEE6DD99909C2B569EEDA61ED8942E
+
+I=186
+KEY=0000000000000000000000000000000000000000000000400000000000000000
+CT=CE98C4A876C65E4CCB261EBB1D9DF7F5
+
+I=187
+KEY=0000000000000000000000000000000000000000000000200000000000000000
+CT=A5491881CF833C3604ABC08044F402AC
+
+I=188
+KEY=0000000000000000000000000000000000000000000000100000000000000000
+CT=A1BA16E64CCCB3087D57A768507B0BFC
+
+I=189
+KEY=0000000000000000000000000000000000000000000000080000000000000000
+CT=D55951E202D2949EBD3BE43120C738BF
+
+I=190
+KEY=0000000000000000000000000000000000000000000000040000000000000000
+CT=EBB8E43069E69F450EFEC65DCD52B7FD
+
+I=191
+KEY=0000000000000000000000000000000000000000000000020000000000000000
+CT=2B292135663B4AA5ABFE9423D57E7EE9
+
+I=192
+KEY=0000000000000000000000000000000000000000000000010000000000000000
+CT=E91BF974B3BE3AD966249D8655292A85
+
+I=193
+KEY=0000000000000000000000000000000000000000000000008000000000000000
+CT=384365998EAA9562236CC58F6ADF9610
+
+I=194
+KEY=0000000000000000000000000000000000000000000000004000000000000000
+CT=C2E997012AA3D4D8D359C9A947CBE69F
+
+I=195
+KEY=0000000000000000000000000000000000000000000000002000000000000000
+CT=F49421204148BA213BE87E2D5C22B0BF
+
+I=196
+KEY=0000000000000000000000000000000000000000000000001000000000000000
+CT=82ED0ED9953AA92E4DF30929CA65C00F
+
+I=197
+KEY=0000000000000000000000000000000000000000000000000800000000000000
+CT=291EB1D11653C8479437C74A977F5106
+
+I=198
+KEY=0000000000000000000000000000000000000000000000000400000000000000
+CT=BCB997B1939B8983ABD550D6025683E3
+
+I=199
+KEY=0000000000000000000000000000000000000000000000000200000000000000
+CT=1FBA2592C6F489775CAADA71F9B983E9
+
+I=200
+KEY=0000000000000000000000000000000000000000000000000100000000000000
+CT=969F66F217AF1A3DB9E41C1B29039824
+
+I=201
+KEY=0000000000000000000000000000000000000000000000000080000000000000
+CT=A54BB7D6B17E423AC0A7744C19073CB8
+
+I=202
+KEY=0000000000000000000000000000000000000000000000000040000000000000
+CT=B0AC6E6578D1021F47DCF9748A32EAD5
+
+I=203
+KEY=0000000000000000000000000000000000000000000000000020000000000000
+CT=B87B361C3B7B194C77A4358D4669153E
+
+I=204
+KEY=0000000000000000000000000000000000000000000000000010000000000000
+CT=46A133847F96EAA8282A799DC8899D58
+
+I=205
+KEY=0000000000000000000000000000000000000000000000000008000000000000
+CT=2265EC3A9F2D5C9547A091CC8CFB18EA
+
+I=206
+KEY=0000000000000000000000000000000000000000000000000004000000000000
+CT=54CBF3A6FC4FE56D426117AA1FFD1DDE
+
+I=207
+KEY=0000000000000000000000000000000000000000000000000002000000000000
+CT=5312877CCEAB6CFB0905394A370A8003
+
+I=208
+KEY=0000000000000000000000000000000000000000000000000001000000000000
+CT=7190BD6EC613FE38B84ECFE28F702FE4
+
+I=209
+KEY=0000000000000000000000000000000000000000000000000000800000000000
+CT=D1FA5B9CA89A43B04C05F0EF29EF68CD
+
+I=210
+KEY=0000000000000000000000000000000000000000000000000000400000000000
+CT=808285751548ED934FD1056D2D9AE8BA
+
+I=211
+KEY=0000000000000000000000000000000000000000000000000000200000000000
+CT=2758DEF3E7B95A9AE89777BE64D5A6CF
+
+I=212
+KEY=0000000000000000000000000000000000000000000000000000100000000000
+CT=07D81F87DB3E0ACC82B01E08FB22F3C1
+
+I=213
+KEY=0000000000000000000000000000000000000000000000000000080000000000
+CT=8DA250E5553D650711A75EE1CB4FD1C7
+
+I=214
+KEY=0000000000000000000000000000000000000000000000000000040000000000
+CT=A93D946BD0E87F32719DF5F158CEE669
+
+I=215
+KEY=0000000000000000000000000000000000000000000000000000020000000000
+CT=03945236EC2A4D4EAF30B8ABEB54330D
+
+I=216
+KEY=0000000000000000000000000000000000000000000000000000010000000000
+CT=11CC35301F24B79DDE31AEA2D1354F88
+
+I=217
+KEY=0000000000000000000000000000000000000000000000000000008000000000
+CT=E73715B3E8D9A290F44AE6FFBF247E5D
+
+I=218
+KEY=0000000000000000000000000000000000000000000000000000004000000000
+CT=7345E07732B71CB158BBF64CCA5C5B96
+
+I=219
+KEY=0000000000000000000000000000000000000000000000000000002000000000
+CT=6E128F296D24705A1924FD9B70C4ED04
+
+I=220
+KEY=0000000000000000000000000000000000000000000000000000001000000000
+CT=95A789776F036783FBD330947083F54F
+
+I=221
+KEY=0000000000000000000000000000000000000000000000000000000800000000
+CT=360DEC2533EA4AA2E3E54FD3DE2906EB
+
+I=222
+KEY=0000000000000000000000000000000000000000000000000000000400000000
+CT=E68EFD7FECF4D601EA22727BD764965B
+
+I=223
+KEY=0000000000000000000000000000000000000000000000000000000200000000
+CT=9065C64A8BFF44AC33EDBB611CF83D7B
+
+I=224
+KEY=0000000000000000000000000000000000000000000000000000000100000000
+CT=8F33C8DF2A7A51CE8090E8F123BC3723
+
+I=225
+KEY=0000000000000000000000000000000000000000000000000000000080000000
+CT=807F391FFBA8291BA625623210F99018
+
+I=226
+KEY=0000000000000000000000000000000000000000000000000000000040000000
+CT=5E8B3F3A701522CE5CAA761C929D6292
+
+I=227
+KEY=0000000000000000000000000000000000000000000000000000000020000000
+CT=3BA404DC38735A78289E3809E8364835
+
+I=228
+KEY=0000000000000000000000000000000000000000000000000000000010000000
+CT=D23BEDBAD229F8305DC425B6B759DCC9
+
+I=229
+KEY=0000000000000000000000000000000000000000000000000000000008000000
+CT=44880F21CF5913040AE376AEE2A10AD8
+
+I=230
+KEY=0000000000000000000000000000000000000000000000000000000004000000
+CT=9BC98E29D057C0E828C3B5CCE69256C1
+
+I=231
+KEY=0000000000000000000000000000000000000000000000000000000002000000
+CT=B293CC7A975DA141A68279368057CC41
+
+I=232
+KEY=0000000000000000000000000000000000000000000000000000000001000000
+CT=8D60FB87ACD91385B313BE5F1D7BD30F
+
+I=233
+KEY=0000000000000000000000000000000000000000000000000000000000800000
+CT=2C8E56132D70291B303C48FDF75543CD
+
+I=234
+KEY=0000000000000000000000000000000000000000000000000000000000400000
+CT=D1F80035B826791F6CE4E59B7DB1BB0D
+
+I=235
+KEY=0000000000000000000000000000000000000000000000000000000000200000
+CT=42CE6224FC36469339A133DD08173BD4
+
+I=236
+KEY=0000000000000000000000000000000000000000000000000000000000100000
+CT=61817155EA41BCBA2AF7F06AE7CBF585
+
+I=237
+KEY=0000000000000000000000000000000000000000000000000000000000080000
+CT=D1923A9866068D2EF5FB77D57C3315B6
+
+I=238
+KEY=0000000000000000000000000000000000000000000000000000000000040000
+CT=B37CBDB5D719F49691CA968EF2E84140
+
+I=239
+KEY=0000000000000000000000000000000000000000000000000000000000020000
+CT=EC974E653A055D7F8F22171030F68E1D
+
+I=240
+KEY=0000000000000000000000000000000000000000000000000000000000010000
+CT=DDE5D3B9AAD9C32213BB3675A822499C
+
+I=241
+KEY=0000000000000000000000000000000000000000000000000000000000008000
+CT=D3B6E9216EA1AE57EB1C628A3C38AB78
+
+I=242
+KEY=0000000000000000000000000000000000000000000000000000000000004000
+CT=82C99ECC69472B7E96324B042AE8B87A
+
+I=243
+KEY=0000000000000000000000000000000000000000000000000000000000002000
+CT=97144DC5338C43600F84439C0AA0D147
+
+I=244
+KEY=0000000000000000000000000000000000000000000000000000000000001000
+CT=400AC4A0BBADA1DB2121EB144C7E5209
+
+I=245
+KEY=0000000000000000000000000000000000000000000000000000000000000800
+CT=EFD9D550EB419ED278F4885A490AB54C
+
+I=246
+KEY=0000000000000000000000000000000000000000000000000000000000000400
+CT=2AB7816E149B7C0404C88A8857793670
+
+I=247
+KEY=0000000000000000000000000000000000000000000000000000000000000200
+CT=5B591DFF9E8DEE15BAD24C025DBCA481
+
+I=248
+KEY=0000000000000000000000000000000000000000000000000000000000000100
+CT=0C06633E30721C3749F49AD8CBF2B754
+
+I=249
+KEY=0000000000000000000000000000000000000000000000000000000000000080
+CT=96D6D31A41B5123B2035FD91A921D4CA
+
+I=250
+KEY=0000000000000000000000000000000000000000000000000000000000000040
+CT=E7F6C34D86668BC2805CA7793C5E86AD
+
+I=251
+KEY=0000000000000000000000000000000000000000000000000000000000000020
+CT=F46DFF5FF500D6879C4D3E45CF0CF0F3
+
+I=252
+KEY=0000000000000000000000000000000000000000000000000000000000000010
+CT=60D842D9C61DA7495C116197B7CECBBE
+
+I=253
+KEY=0000000000000000000000000000000000000000000000000000000000000008
+CT=D45B24EDB673353EBDF248B8FA06B67A
+
+I=254
+KEY=0000000000000000000000000000000000000000000000000000000000000004
+CT=119EAEBCC165D0BD02C0D35DC82EF992
+
+I=255
+KEY=0000000000000000000000000000000000000000000000000000000000000002
+CT=E673143680414ADA301D0ED34626B9FE
+
+I=256
+KEY=0000000000000000000000000000000000000000000000000000000000000001
+CT=6B6CFE160A6263631B292F879EEFF926
+
+==========
diff --git a/mechglue/src/lib/crypto/aes/expect-vt.txt b/mechglue/src/lib/crypto/aes/expect-vt.txt
new file mode 100644
index 000000000..02b238c04
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/expect-vt.txt
@@ -0,0 +1,1036 @@
+
+KEYSIZE=128
+
+KEY=00000000000000000000000000000000
+
+I=1
+PT=80000000000000000000000000000000
+CT=3AD78E726C1EC02B7EBFE92B23D9EC34
+
+I=2
+PT=40000000000000000000000000000000
+CT=45BC707D29E8204D88DFBA2F0B0CAD9B
+
+I=3
+PT=20000000000000000000000000000000
+CT=161556838018F52805CDBD6202002E3F
+
+I=4
+PT=10000000000000000000000000000000
+CT=F5569B3AB6A6D11EFDE1BF0A64C6854A
+
+I=5
+PT=08000000000000000000000000000000
+CT=64E82B50E501FBD7DD4116921159B83E
+
+I=6
+PT=04000000000000000000000000000000
+CT=BAAC12FB613A7DE11450375C74034041
+
+I=7
+PT=02000000000000000000000000000000
+CT=BCF176A7EAAD8085EBACEA362462A281
+
+I=8
+PT=01000000000000000000000000000000
+CT=47711816E91D6FF059BBBF2BF58E0FD3
+
+I=9
+PT=00800000000000000000000000000000
+CT=B970DFBE40698AF1638FE38BD3DF3B2F
+
+I=10
+PT=00400000000000000000000000000000
+CT=F95B59A44F391E14CF20B74BDC32FCFF
+
+I=11
+PT=00200000000000000000000000000000
+CT=720F74AE04A2A435B9A7256E49378F5B
+
+I=12
+PT=00100000000000000000000000000000
+CT=2A0445F61D36BFA7E277070730CF76DA
+
+I=13
+PT=00080000000000000000000000000000
+CT=8D0536B997AEFEC1D94011BAB6699A03
+
+I=14
+PT=00040000000000000000000000000000
+CT=674F002E19F6ED47EFF319E51FAD4498
+
+I=15
+PT=00020000000000000000000000000000
+CT=292C02C5CB9163C80AC0F6CF1DD8E92D
+
+I=16
+PT=00010000000000000000000000000000
+CT=FA321CF18EF5FE727DD82A5C1E945141
+
+I=17
+PT=00008000000000000000000000000000
+CT=A5A7AFE1034C39CCCEBE3C584BC0BE05
+
+I=18
+PT=00004000000000000000000000000000
+CT=4FF5A52E697E77D081205DBDB21CEA39
+
+I=19
+PT=00002000000000000000000000000000
+CT=209E88DC94C9003000CE0769AF7B7166
+
+I=20
+PT=00001000000000000000000000000000
+CT=5DEE41AF864CB4B650E5F51551824D38
+
+I=21
+PT=00000800000000000000000000000000
+CT=A79A63FA7E4503AE6D6E09F5F9053030
+
+I=22
+PT=00000400000000000000000000000000
+CT=A48316749FAE7FAC7002031A6AFD8BA7
+
+I=23
+PT=00000200000000000000000000000000
+CT=D6EEE8A7357A0E1D64262CA9C337AC42
+
+I=24
+PT=00000100000000000000000000000000
+CT=B013CA8A62A858053E9FB667ED39829E
+
+I=25
+PT=00000080000000000000000000000000
+CT=DF6EA9E4538A45A52D5C1A43C88F4B55
+
+I=26
+PT=00000040000000000000000000000000
+CT=7D03BA451371591D3FD5547D9165C73B
+
+I=27
+PT=00000020000000000000000000000000
+CT=0E0426281A6277E186499D365D5F49FF
+
+I=28
+PT=00000010000000000000000000000000
+CT=DBC02169DD2059E6CC4C57C1FEDF5AB4
+
+I=29
+PT=00000008000000000000000000000000
+CT=826590E05D167DA6F00DCC75E22788EB
+
+I=30
+PT=00000004000000000000000000000000
+CT=34A73F21A04421D9786335FAAB49423A
+
+I=31
+PT=00000002000000000000000000000000
+CT=ED347D0E0128EE1A7392A1D36AB78AA9
+
+I=32
+PT=00000001000000000000000000000000
+CT=EE944B2FE6E9FC888042608DA9615F75
+
+I=33
+PT=00000000800000000000000000000000
+CT=9E7C85A909EF7218BA7947CFB4718F46
+
+I=34
+PT=00000000400000000000000000000000
+CT=811AE07A0B2B1F816587FA73699AE77D
+
+I=35
+PT=00000000200000000000000000000000
+CT=68466FBF43C2FE13D4B18F7EC5EA745F
+
+I=36
+PT=00000000100000000000000000000000
+CT=D20B015C7191B219780956E6101F9354
+
+I=37
+PT=00000000080000000000000000000000
+CT=5939D5C1BBF54EE1B3E326D757BDDE25
+
+I=38
+PT=00000000040000000000000000000000
+CT=B1FDAFE9A0240E8FFEA19CE94B5105D3
+
+I=39
+PT=00000000020000000000000000000000
+CT=D62962ECE02CDD68C06BDFEFB2F9495B
+
+I=40
+PT=00000000010000000000000000000000
+CT=B3BB2DE6F3C26587BA8BAC4F7AD9499A
+
+I=41
+PT=00000000008000000000000000000000
+CT=E0B1072D6D9FF703D6FBEF77852B0A6B
+
+I=42
+PT=00000000004000000000000000000000
+CT=D8DD51C907F478DE0228E83E61FD1758
+
+I=43
+PT=00000000002000000000000000000000
+CT=A42DFFE6E7C1671C06A25236FDD10017
+
+I=44
+PT=00000000001000000000000000000000
+CT=25ACF141550BFAB9EF451B6C6A5B2163
+
+I=45
+PT=00000000000800000000000000000000
+CT=4DA7FCA3949B16E821DBC84F19581018
+
+I=46
+PT=00000000000400000000000000000000
+CT=7D49B6347CBCC8919C7FA96A37A7A215
+
+I=47
+PT=00000000000200000000000000000000
+CT=900024B29A08C6721B95BA3B753DDB4D
+
+I=48
+PT=00000000000100000000000000000000
+CT=6D2182FB283B6934D90BA7848CAB5E66
+
+I=49
+PT=00000000000080000000000000000000
+CT=F73EF01B448D23A4D90DE8B2F9666E7A
+
+I=50
+PT=00000000000040000000000000000000
+CT=4AD9CDA2418643E9A3D926AF5E6B0412
+
+I=51
+PT=00000000000020000000000000000000
+CT=7CAEC8E7E5953997D545B033201C8C5B
+
+I=52
+PT=00000000000010000000000000000000
+CT=3C43CA1F6B6864503E27B48D88230CF5
+
+I=53
+PT=00000000000008000000000000000000
+CT=44F779B93108FE9FEEC880D79BA74488
+
+I=54
+PT=00000000000004000000000000000000
+CT=9E50E8D9CFD3A682A78E527C9072A1CF
+
+I=55
+PT=00000000000002000000000000000000
+CT=68D000CBC838BBE3C505D6F814C01F28
+
+I=56
+PT=00000000000001000000000000000000
+CT=2CB2A9FEC1ACD1D9B0FA05205E304F57
+
+I=57
+PT=00000000000000800000000000000000
+CT=01EB2806606E46444520A5CC6180CD4B
+
+I=58
+PT=00000000000000400000000000000000
+CT=DAA9B25168CC702326F217F1A0C0B162
+
+I=59
+PT=00000000000000200000000000000000
+CT=3E07E648975D9578D03555B1755807ED
+
+I=60
+PT=00000000000000100000000000000000
+CT=0B45F52E802C8B8DE09579425B80B711
+
+I=61
+PT=00000000000000080000000000000000
+CT=659595DA0B68F6DF0DD6CA77202986E1
+
+I=62
+PT=00000000000000040000000000000000
+CT=05FF42873893536E58C8FA98A45C73C4
+
+I=63
+PT=00000000000000020000000000000000
+CT=B5B03421DE8BBFFC4EADEC767339A9BD
+
+I=64
+PT=00000000000000010000000000000000
+CT=788BCD111ECF73D4E78D2E21BEF55460
+
+I=65
+PT=00000000000000008000000000000000
+CT=909CD9EC6790359F982DC6F2393D5315
+
+I=66
+PT=00000000000000004000000000000000
+CT=332950F361535FF24EFAC8C76293F12C
+
+I=67
+PT=00000000000000002000000000000000
+CT=A68CCD4E330FFDA9D576DA436DB53D75
+
+I=68
+PT=00000000000000001000000000000000
+CT=27C8A1CCFDB0B015D1ED5B3E77143791
+
+I=69
+PT=00000000000000000800000000000000
+CT=D76A4B95887A77DF610DD3E1D3B20325
+
+I=70
+PT=00000000000000000400000000000000
+CT=C068AB0DE71C66DAE83C361EF4B2D989
+
+I=71
+PT=00000000000000000200000000000000
+CT=C2120BCD49EDA9A288B3B4BE79AC8158
+
+I=72
+PT=00000000000000000100000000000000
+CT=0C546F62BF2773CD0F564FCECA7BA688
+
+I=73
+PT=00000000000000000080000000000000
+CT=18F3462BEDE4920213CCB66DAB1640AA
+
+I=74
+PT=00000000000000000040000000000000
+CT=FE42F245EDD0E24B216AEBD8B392D690
+
+I=75
+PT=00000000000000000020000000000000
+CT=3D3EEBC8D3D1558A194C2D00C337FF2B
+
+I=76
+PT=00000000000000000010000000000000
+CT=29AAEDF043E785DB42836F79BE6CBA28
+
+I=77
+PT=00000000000000000008000000000000
+CT=215F90C6744E2944358E78619159A611
+
+I=78
+PT=00000000000000000004000000000000
+CT=8606B1AA9E1D548E5442B06551E2C6DC
+
+I=79
+PT=00000000000000000002000000000000
+CT=987BB4B8740EC0EDE7FEA97DF033B5B1
+
+I=80
+PT=00000000000000000001000000000000
+CT=C0A3500DA5B0AE07D2F450930BEEDF1B
+
+I=81
+PT=00000000000000000000800000000000
+CT=525FDF8312FE8F32C781481A8DAAAE37
+
+I=82
+PT=00000000000000000000400000000000
+CT=BFD2C56AE5FB9C9DE33A6944572A6487
+
+I=83
+PT=00000000000000000000200000000000
+CT=7975A57A425CDF5AA1FA929101F650B0
+
+I=84
+PT=00000000000000000000100000000000
+CT=BF174BC49609A8709B2CD8366DAA79FE
+
+I=85
+PT=00000000000000000000080000000000
+CT=06C50C43222F56C874B1704E9F44BF7D
+
+I=86
+PT=00000000000000000000040000000000
+CT=0CEC48CD34043EA29CA3B8ED5278721E
+
+I=87
+PT=00000000000000000000020000000000
+CT=9548EA34A1560197B304D0ACB8A1698D
+
+I=88
+PT=00000000000000000000010000000000
+CT=22F9E9B1BD73B6B5B7D3062C986272F3
+
+I=89
+PT=00000000000000000000008000000000
+CT=FEE8E934BD0873295059002230E298D4
+
+I=90
+PT=00000000000000000000004000000000
+CT=1B08E2E3EB820D139CB4ABBDBE81D00D
+
+I=91
+PT=00000000000000000000002000000000
+CT=0021177681E4D90CEAF69DCED0145125
+
+I=92
+PT=00000000000000000000001000000000
+CT=4A8E314452CA8A8A3619FC54BC423643
+
+I=93
+PT=00000000000000000000000800000000
+CT=65047474F7222C94C6965425FF1BFD0A
+
+I=94
+PT=00000000000000000000000400000000
+CT=E123F551A9C4A8489622B16F961A9AA4
+
+I=95
+PT=00000000000000000000000200000000
+CT=EF05530948B80915028BB2B6FE429380
+
+I=96
+PT=00000000000000000000000100000000
+CT=72535B7FE0F0F777CEDCD55CD77E2DDF
+
+I=97
+PT=00000000000000000000000080000000
+CT=3423D8EFC31FA2F4C365C77D8F3B5C63
+
+I=98
+PT=00000000000000000000000040000000
+CT=DE0E51C264663F3C5DBC59580A98D8E4
+
+I=99
+PT=00000000000000000000000020000000
+CT=B2D9391166680947AB09264156719679
+
+I=100
+PT=00000000000000000000000010000000
+CT=10DB79F23B06D263835C424AF749ADB7
+
+I=101
+PT=00000000000000000000000008000000
+CT=DDF72D27E6B01EC107EA3E005B59563B
+
+I=102
+PT=00000000000000000000000004000000
+CT=8266B57485A5954A4236751DE07F6694
+
+I=103
+PT=00000000000000000000000002000000
+CT=669A501E1F1ADE6E5523DE01D6DBC987
+
+I=104
+PT=00000000000000000000000001000000
+CT=C20C48F2989725D461D1DB589DC0896E
+
+I=105
+PT=00000000000000000000000000800000
+CT=DE35158E7810ED1191825D2AA98FA97D
+
+I=106
+PT=00000000000000000000000000400000
+CT=4FE294F2C0F34D0671B693A237EBDDC8
+
+I=107
+PT=00000000000000000000000000200000
+CT=087AE74B10CCBFDF6739FEB9559C01A4
+
+I=108
+PT=00000000000000000000000000100000
+CT=5DC278970B7DEF77A5536C77AB59C207
+
+I=109
+PT=00000000000000000000000000080000
+CT=7607F078C77085184EAA9B060C1FBFFF
+
+I=110
+PT=00000000000000000000000000040000
+CT=9DB841531BCBE7998DAD19993FB3CC00
+
+I=111
+PT=00000000000000000000000000020000
+CT=D6A089B654854A94560BAE13298835B8
+
+I=112
+PT=00000000000000000000000000010000
+CT=E1E223C4CF90CC5D195B370D65114622
+
+I=113
+PT=00000000000000000000000000008000
+CT=1CBED73C50D053BDAD372CEEE54836A1
+
+I=114
+PT=00000000000000000000000000004000
+CT=D309E69376D257ADF2BFDA152B26555F
+
+I=115
+PT=00000000000000000000000000002000
+CT=740F7649117F0DEE6EAA7789A9994C36
+
+I=116
+PT=00000000000000000000000000001000
+CT=76AE64417C297184D668C5FD908B3CE5
+
+I=117
+PT=00000000000000000000000000000800
+CT=6095FEA4AA8035591F1787A819C48787
+
+I=118
+PT=00000000000000000000000000000400
+CT=D1FF4E7ACD1C79967FEBAB0F7465D450
+
+I=119
+PT=00000000000000000000000000000200
+CT=5F5AD3C42B9489557BB63BF49ECF5F8A
+
+I=120
+PT=00000000000000000000000000000100
+CT=FB56CC09B680B1D07C5A52149E29F07C
+
+I=121
+PT=00000000000000000000000000000080
+CT=FF49B8DF4A97CBE03833E66197620DAD
+
+I=122
+PT=00000000000000000000000000000040
+CT=5E070ADE533D2E090ED0F5BE13BC0983
+
+I=123
+PT=00000000000000000000000000000020
+CT=3AB4FB1D2B7BA376590A2C241D1F508D
+
+I=124
+PT=00000000000000000000000000000010
+CT=58B2431BC0BEDE02550F40238969EC78
+
+I=125
+PT=00000000000000000000000000000008
+CT=0253786E126504F0DAB90C48A30321DE
+
+I=126
+PT=00000000000000000000000000000004
+CT=200211214E7394DA2089B6ACD093ABE0
+
+I=127
+PT=00000000000000000000000000000002
+CT=0388DACE60B6A392F328C2B971B2FE78
+
+I=128
+PT=00000000000000000000000000000001
+CT=58E2FCCEFA7E3061367F1D57A4E7455A
+
+==========
+
+KEYSIZE=256
+
+KEY=0000000000000000000000000000000000000000000000000000000000000000
+
+I=1
+PT=80000000000000000000000000000000
+CT=DDC6BF790C15760D8D9AEB6F9A75FD4E
+
+I=2
+PT=40000000000000000000000000000000
+CT=C7098C217C334D0C9BDF37EA13B0822C
+
+I=3
+PT=20000000000000000000000000000000
+CT=60F0FB0D4C56A8D4EEFEC5264204042D
+
+I=4
+PT=10000000000000000000000000000000
+CT=73376FBBF654D0686E0E84001477106B
+
+I=5
+PT=08000000000000000000000000000000
+CT=2F443B52BA5F0C6EA0602C7C4FD259B6
+
+I=6
+PT=04000000000000000000000000000000
+CT=75D11B0E3A68C4223D88DBF017977DD7
+
+I=7
+PT=02000000000000000000000000000000
+CT=779B38D15BFFB63D8D609D551A5CC98E
+
+I=8
+PT=01000000000000000000000000000000
+CT=5275F3D86B4FB8684593133EBFA53CD3
+
+I=9
+PT=00800000000000000000000000000000
+CT=1CEF2074B336CEC62F12DEA2F6AB1481
+
+I=10
+PT=00400000000000000000000000000000
+CT=1AEF5ABBAD9D7160874578DCD8BAE172
+
+I=11
+PT=00200000000000000000000000000000
+CT=46C525DB17E72F26BF03216846B6F609
+
+I=12
+PT=00100000000000000000000000000000
+CT=E24411F941BBE08788781E3EC52CBAA4
+
+I=13
+PT=00080000000000000000000000000000
+CT=83A3DEDD1DD27018F6A6477E40527581
+
+I=14
+PT=00040000000000000000000000000000
+CT=B68F8A2CDBAB0C923C67FC8F0F1087DE
+
+I=15
+PT=00020000000000000000000000000000
+CT=649944A70C32BF87A7409E7AE128FDE8
+
+I=16
+PT=00010000000000000000000000000000
+CT=2846526D67387539C89314DE9E0C2D02
+
+I=17
+PT=00008000000000000000000000000000
+CT=A9A0B8402E53C70DD1688054BA58DDFD
+
+I=18
+PT=00004000000000000000000000000000
+CT=4A72E6E1B79C83AC4BE3EBA5699EED48
+
+I=19
+PT=00002000000000000000000000000000
+CT=B0E36B867BA4FF2B77D0614B0E364E4C
+
+I=20
+PT=00001000000000000000000000000000
+CT=49B57DE141F6418E3090F24DDD4014B6
+
+I=21
+PT=00000800000000000000000000000000
+CT=A6C0D5B9797258E1987AC5F6CD20146D
+
+I=22
+PT=00000400000000000000000000000000
+CT=426CF4BDCAA369175965D26E7C71EEA2
+
+I=23
+PT=00000200000000000000000000000000
+CT=E27F484CE54BC99BC1A52BDA3B518A26
+
+I=24
+PT=00000100000000000000000000000000
+CT=D16D186284C7E6EE64B8104E0EF20BA5
+
+I=25
+PT=00000080000000000000000000000000
+CT=6431F8538AD54E1E044A9F71F8EF556B
+
+I=26
+PT=00000040000000000000000000000000
+CT=ECD57CEB451D27EB96C55B2042257E8E
+
+I=27
+PT=00000020000000000000000000000000
+CT=4F0F188DC911B1954AFBC734C9F68872
+
+I=28
+PT=00000010000000000000000000000000
+CT=B54DEF0337626B65614E81EDFDE620F3
+
+I=29
+PT=00000008000000000000000000000000
+CT=6655D8074CAE0B90B0D3A3FE72D4D9DB
+
+I=30
+PT=00000004000000000000000000000000
+CT=C6B74B6B9EB4FC0C9A237DB1B616D09A
+
+I=31
+PT=00000002000000000000000000000000
+CT=D7B5D076EA56EC2B20791D7AD51CCF8F
+
+I=32
+PT=00000001000000000000000000000000
+CT=FE160C224BF003CE3BDDC90CB52ED22C
+
+I=33
+PT=00000000800000000000000000000000
+CT=5E00DA9BA94B5EC0D258D8A8002E0F6A
+
+I=34
+PT=00000000400000000000000000000000
+CT=09AC6DCFF4DACFF1651E2BA212A292A3
+
+I=35
+PT=00000000200000000000000000000000
+CT=B283617E318D99AF83A05D9810BA89F7
+
+I=36
+PT=00000000100000000000000000000000
+CT=0B5F70CCB40B0EF2538AE9B4A9770B35
+
+I=37
+PT=00000000080000000000000000000000
+CT=43282BF180248FB517839B37F4DDAAE4
+
+I=38
+PT=00000000040000000000000000000000
+CT=DDBD534C8B2E6D30A268F88C55AD765B
+
+I=39
+PT=00000000020000000000000000000000
+CT=A41A164E50EC2D9F175E752B755E0B5C
+
+I=40
+PT=00000000010000000000000000000000
+CT=37BFF99FF2F7AA97779E4ADF6F13FB10
+
+I=41
+PT=00000000008000000000000000000000
+CT=9BA4F7BD298152903A683C4CEC669216
+
+I=42
+PT=00000000004000000000000000000000
+CT=5FB750C7CE10DE7B4504248914D0DA06
+
+I=43
+PT=00000000002000000000000000000000
+CT=3E748BFA108E086F51D56EC74A9E0FB9
+
+I=44
+PT=00000000001000000000000000000000
+CT=31D4E56B99F5B73C1B8437DF332AFB98
+
+I=45
+PT=00000000000800000000000000000000
+CT=9DC6717B84FC55D266E7B1D9B5C52A5F
+
+I=46
+PT=00000000000400000000000000000000
+CT=8EF8BA007F23C0A50FC120E07041BCCD
+
+I=47
+PT=00000000000200000000000000000000
+CT=C58F38E1839FC1918A12B8C9E88C66B6
+
+I=48
+PT=00000000000100000000000000000000
+CT=B695D72A3FCF508C4050E12E40061C2D
+
+I=49
+PT=00000000000080000000000000000000
+CT=5D2736AD478A50583BC8C11BEFF16D7A
+
+I=50
+PT=00000000000040000000000000000000
+CT=DF0EACA8F17847AD41F9578F14C7B56B
+
+I=51
+PT=00000000000020000000000000000000
+CT=E5AA14AD48AD0A3C47CC35D5F8020E51
+
+I=52
+PT=00000000000010000000000000000000
+CT=11BE6C8F58EBD8CEF1A53F591A68E8CE
+
+I=53
+PT=00000000000008000000000000000000
+CT=ECFE7BAFCBF42C1FEE015488770B3053
+
+I=54
+PT=00000000000004000000000000000000
+CT=E552649F8D8EC4A1E1CD6DF50B6E6777
+
+I=55
+PT=00000000000002000000000000000000
+CT=521C0629DE93B9119CDB1DDC5809DDEA
+
+I=56
+PT=00000000000001000000000000000000
+CT=CB38A62A0BAB1784156BA038CBA99BF6
+
+I=57
+PT=00000000000000800000000000000000
+CT=76CCEE8AAACD394DE1EEF3DDA10CB54B
+
+I=58
+PT=00000000000000400000000000000000
+CT=6AFF910FA1D5673140E2DB59B8416049
+
+I=59
+PT=00000000000000200000000000000000
+CT=064A12C0EF73FB386801BF4F35F3120D
+
+I=60
+PT=00000000000000100000000000000000
+CT=2240E374929D5B1BB8FF0FFDDDF640EC
+
+I=61
+PT=00000000000000080000000000000000
+CT=D4BA15C904C7692185DE85C02052E180
+
+I=62
+PT=00000000000000040000000000000000
+CT=1714A315AB0166728A44CD91D4AE9018
+
+I=63
+PT=00000000000000020000000000000000
+CT=6C970BDD9F0E222722EA31A1D12DD0AD
+
+I=64
+PT=00000000000000010000000000000000
+CT=F5956EDF02BD36A401BBB6CE77C3D3FB
+
+I=65
+PT=00000000000000008000000000000000
+CT=0CA11F122CCD7C259DC597EED3DF9BC4
+
+I=66
+PT=00000000000000004000000000000000
+CT=50109AB4912AD2560B206F331B62EB6C
+
+I=67
+PT=00000000000000002000000000000000
+CT=DBE7C91A4175614889A2D4BEFD64845E
+
+I=68
+PT=00000000000000001000000000000000
+CT=0D3322853A571A6B46B79C0228E0DD25
+
+I=69
+PT=00000000000000000800000000000000
+CT=96E4EE0BB9A11C6FB8522F285BADDEB6
+
+I=70
+PT=00000000000000000400000000000000
+CT=96705C52D2CFCE82E630C93477C79C49
+
+I=71
+PT=00000000000000000200000000000000
+CT=C50130AED6A126149D71F3888C83C232
+
+I=72
+PT=00000000000000000100000000000000
+CT=4816EFE3DEB380566EBA0C17BF582090
+
+I=73
+PT=00000000000000000080000000000000
+CT=0390857B4C8C98E4CF7A2B6F3394C507
+
+I=74
+PT=00000000000000000040000000000000
+CT=422E73A02025EBE8B8B5D6E0FA24FCB2
+
+I=75
+PT=00000000000000000020000000000000
+CT=3271AA7F4BF1D7C38050A43076D4FF76
+
+I=76
+PT=00000000000000000010000000000000
+CT=D2074946F0D37B8975607BFC2E70234C
+
+I=77
+PT=00000000000000000008000000000000
+CT=1A509194C1270AB92E5A42D3A9F8D98B
+
+I=78
+PT=00000000000000000004000000000000
+CT=512438946360CCC4A5C6D73F6EED7130
+
+I=79
+PT=00000000000000000002000000000000
+CT=98CFCDEC46EBEA1A286B3004F2746A0D
+
+I=80
+PT=00000000000000000001000000000000
+CT=A1CF369949677A3AF3D58E3EABF2741B
+
+I=81
+PT=00000000000000000000800000000000
+CT=D84C2E1A0E4A52166FA8FF6889D1E5E2
+
+I=82
+PT=00000000000000000000400000000000
+CT=4AD91CCEEF60119B5078FD162D2735DE
+
+I=83
+PT=00000000000000000000200000000000
+CT=2860793D818E97AAFF1D339D7702438D
+
+I=84
+PT=00000000000000000000100000000000
+CT=6F9068BE73364AE250D89D78A6C9CE6F
+
+I=85
+PT=00000000000000000000080000000000
+CT=024FC3FEF4883FEB1A8DD005305FECCE
+
+I=86
+PT=00000000000000000000040000000000
+CT=08A61FE0816D75EA15EB3C9FB9CCDED6
+
+I=87
+PT=00000000000000000000020000000000
+CT=449C86DFA13F260175CE39797686FFA4
+
+I=88
+PT=00000000000000000000010000000000
+CT=4FFFFC29A59858E1133F2BFB1A8A4817
+
+I=89
+PT=00000000000000000000008000000000
+CT=19425D1F6480B25096561295697DC2B7
+
+I=90
+PT=00000000000000000000004000000000
+CT=31974727ECDD2C77C3A428FC3A8CB3FC
+
+I=91
+PT=00000000000000000000002000000000
+CT=A57CD704B3C95E744D08DF443458F2F5
+
+I=92
+PT=00000000000000000000001000000000
+CT=486D8C193DB1ED73ACB17990442FC40B
+
+I=93
+PT=00000000000000000000000800000000
+CT=5E4DBF4E83AB3BC055B9FCC7A6B3A763
+
+I=94
+PT=00000000000000000000000400000000
+CT=ACF2E0A693FBBCBA4D41B861E0D89E37
+
+I=95
+PT=00000000000000000000000200000000
+CT=32A7CB2AE066A51D2B78FC4B4CFCB608
+
+I=96
+PT=00000000000000000000000100000000
+CT=677D494DBB73CAF55C1990158DA12F14
+
+I=97
+PT=00000000000000000000000080000000
+CT=082A0D2367512ADF0D75A151BFBE0A17
+
+I=98
+PT=00000000000000000000000040000000
+CT=5E5BB7337923C482CE8CBA249E6A8C7D
+
+I=99
+PT=00000000000000000000000020000000
+CT=D3001BA7C7026EE3E5003179530AFCFC
+
+I=100
+PT=00000000000000000000000010000000
+CT=46EC44F8931E629FE8FD8961312EDDE1
+
+I=101
+PT=00000000000000000000000008000000
+CT=C5F8ECD79C7B30E81D17E32079969310
+
+I=102
+PT=00000000000000000000000004000000
+CT=5B8AD6919E24CAEBCC55401AEE0C9802
+
+I=103
+PT=00000000000000000000000002000000
+CT=C2302B7E701B5CC7F8B29E3516DBBFA6
+
+I=104
+PT=00000000000000000000000001000000
+CT=A1D04D6A76F9F7A94D49FAA64A87F244
+
+I=105
+PT=00000000000000000000000000800000
+CT=7FB6F92D35B5CB6C631600EDB9E860BA
+
+I=106
+PT=00000000000000000000000000400000
+CT=B2EF7078BCFACE07AEEC3F9B48830EB3
+
+I=107
+PT=00000000000000000000000000200000
+CT=F475A7493D24C7036E53390374C378B3
+
+I=108
+PT=00000000000000000000000000100000
+CT=B36802AC987377A37BD8EADC97C57D60
+
+I=109
+PT=00000000000000000000000000080000
+CT=ADDCD3D19689C4DDC738CE5F69DC9505
+
+I=110
+PT=00000000000000000000000000040000
+CT=0DAF8CA22884915403C0F0BB1F4BD74F
+
+I=111
+PT=00000000000000000000000000020000
+CT=4AF36BAE2660503B3248E4685059FD05
+
+I=112
+PT=00000000000000000000000000010000
+CT=7D5631814DD8E917D97A0D514C743971
+
+I=113
+PT=00000000000000000000000000008000
+CT=BC3352500FC0CBB9DB5B5F6B491C1BE8
+
+I=114
+PT=00000000000000000000000000004000
+CT=6A4A30BA87E87AF65C90AEB7AFEDC76B
+
+I=115
+PT=00000000000000000000000000002000
+CT=77E6125897668AC8E73E8C79A6FF8336
+
+I=116
+PT=00000000000000000000000000001000
+CT=3FA9D39104EBB323C7AAAA248960DD1E
+
+I=117
+PT=00000000000000000000000000000800
+CT=FAD75AD76AB10ADC49036B250E229D39
+
+I=118
+PT=00000000000000000000000000000400
+CT=2FACAA5FE35B228A16AC74088D702EC4
+
+I=119
+PT=00000000000000000000000000000200
+CT=88B6CBCFDFEF8AD91720A1BB69A1F33E
+
+I=120
+PT=00000000000000000000000000000100
+CT=C7E9D250998632D444356242EF04058D
+
+I=121
+PT=00000000000000000000000000000080
+CT=B14DAD8D3D9153F46C0D3A1AD63C7A05
+
+I=122
+PT=00000000000000000000000000000040
+CT=60ABA678A506608D0845966D29B5F790
+
+I=123
+PT=00000000000000000000000000000020
+CT=482DC43F2388EF25D24144E144BD834E
+
+I=124
+PT=00000000000000000000000000000010
+CT=1490A05A7CEE43BDE98B56E309DC0126
+
+I=125
+PT=00000000000000000000000000000008
+CT=ABFA77CD6E85DA245FB0BDC5E52CFC29
+
+I=126
+PT=00000000000000000000000000000004
+CT=DD4AB1284D4AE17B41E85924470C36F7
+
+I=127
+PT=00000000000000000000000000000002
+CT=CEA7403D4D606B6E074EC5D3BAF39D18
+
+I=128
+PT=00000000000000000000000000000001
+CT=530F8AFBC74536B9A963B4F1C4CB738B
+
+==========
diff --git a/mechglue/src/lib/crypto/aes/test/Readme.txt b/mechglue/src/lib/crypto/aes/test/Readme.txt
new file mode 100644
index 000000000..69dbb5b9c
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/Readme.txt
@@ -0,0 +1,22 @@
+README
+
+Algorithm:	Rijndael
+Submitter:	Joan Daemen and Vincent Rijmen
+
+Test values: Known Answer Tests and Monte Carlo Tests
+-----------------------------------------------------------
+
+This directory contains the following files:
+
+Readme.txt: 	This file.
+
+cbc_d_m.txt:	Test values for the CBC decryption MCT.
+cbc_e_m.txt:	Test values for the CBC encryption MCT.
+ecb_d_m.txt:	Test values for the ECB decryption MCT.
+ecb_e_m.txt:	Test values for the ECB encryption MCT.
+ecb_vk.txt: 	Test values for the Variable Key KAT.
+ecb_vt.txt:	      Test values for the Variable Text KAT.
+ecb_iv.txt:	      Test values for the Intermediate Values KAT.
+ecb_iv.readme:	Detailed information about the Intermediate Values KAT.
+ecb_tbl.txt:	Test values for the Table KAT.
+
diff --git a/mechglue/src/lib/crypto/aes/test/cbc_d_m.txt b/mechglue/src/lib/crypto/aes/test/cbc_d_m.txt
new file mode 100644
index 000000000..e216f3b87
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/cbc_d_m.txt
@@ -0,0 +1,7224 @@
+
+=========================
+
+FILENAME:  "cbc_d_m.txt"
+
+Cipher Block Chaining (CBC) Mode - DECRYPTION
+Monte Carlo Test
+
+Algorithm Name: Rijndael
+Principal Submitter: Joan Daemen
+
+==========
+
+KEYSIZE=128
+
+I=0
+KEY=00000000000000000000000000000000
+IV=00000000000000000000000000000000
+CT=00000000000000000000000000000000
+PT=FACA37E0B0C85373DF706E73F7C9AF86
+
+I=1
+KEY=FACA37E0B0C85373DF706E73F7C9AF86
+IV=52D0C29FF8793A519BD6A8289FC80E6A
+CT=FACA37E0B0C85373DF706E73F7C9AF86
+PT=F5372F9735C5685F1DA362AF6ECB2940
+
+I=2
+KEY=0FFD1877850D3B2CC2D30CDC990286C6
+IV=DD74BB1AC6F0F866C7992C61F59D5594
+CT=F5372F9735C5685F1DA362AF6ECB2940
+PT=5496A4C29C7670F61B5D5DF6181F5947
+
+I=3
+KEY=5B6BBCB5197B4BDAD98E512A811DDF81
+IV=3795C88134F7C011433397D1443FEB3A
+CT=5496A4C29C7670F61B5D5DF6181F5947
+PT=940CC5A2AF4F1F8D1862B47BCF63E4CA
+
+I=4
+KEY=CF677917B6345457C1ECE5514E7E3B4B
+IV=0FC1413900225B47AF9E139E1650EA23
+CT=940CC5A2AF4F1F8D1862B47BCF63E4CA
+PT=08832415D97820DE305A58A9AD111A9E
+
+I=5
+KEY=C7E45D026F4C7489F1B6BDF8E36F21D5
+IV=3032F64674FA243D61DF8C16313D81F3
+CT=08832415D97820DE305A58A9AD111A9E
+PT=BD4089775FD1BDB0A6C4F36D1DDAA93E
+
+I=6
+KEY=7AA4D475309DC93957724E95FEB588EB
+IV=47D7F440B43888F173AE5A492F1A99F8
+CT=BD4089775FD1BDB0A6C4F36D1DDAA93E
+PT=AB9955F74612859267D61FEA85A75ADC
+
+I=7
+KEY=D13D8182768F4CAB30A4517F7B12D237
+IV=6D9E57242195D27771D1C7A748378AB0
+CT=AB9955F74612859267D61FEA85A75ADC
+PT=168F213FB678D8A46D0E55EFD1C49BB3
+
+I=8
+KEY=C7B2A0BDC0F7940F5DAA0490AAD64984
+IV=1B98968FB5ABD95930525C1257DEB364
+CT=168F213FB678D8A46D0E55EFD1C49BB3
+PT=3C4CEECFF9560501C5D8C901D87C8E7B
+
+I=9
+KEY=FBFE4E7239A1910E9872CD9172AAC7FF
+IV=35EB7B6D3F63AAE927C5346C9C2CB91D
+CT=3C4CEECFF9560501C5D8C901D87C8E7B
+PT=9D206BE0CC60296BF3A486A8C69778EF
+
+I=10
+KEY=66DE2592F5C1B8656BD64B39B43DBF10
+IV=226646B36D8E9B9279F94378CCBF8FBA
+CT=9D206BE0CC60296BF3A486A8C69778EF
+PT=9DA7B8094BD0F0BEA26848C84B8E083C
+
+I=11
+KEY=FB799D9BBE1148DBC9BE03F1FFB3B72C
+IV=3E3A2B0E1C70A19BCD7222708AA94F26
+CT=9DA7B8094BD0F0BEA26848C84B8E083C
+PT=6A93B2F318C14C2D3E58455B86A4F5D7
+
+I=12
+KEY=91EA2F68A6D004F6F7E646AA791742FB
+IV=1F256942B3CD691858A20664BB24545E
+CT=6A93B2F318C14C2D3E58455B86A4F5D7
+PT=4A19AC6C6FEB654D3675A2BE32E5A820
+
+I=13
+KEY=DBF38304C93B61BBC193E4144BF2EADB
+IV=631F2EDE05C1C950BCE67DF53BA53ED6
+CT=4A19AC6C6FEB654D3675A2BE32E5A820
+PT=799EAB8E9C864A13490FD6B089F764C5
+
+I=14
+KEY=A26D288A55BD2BA8889C32A4C2058E1E
+IV=F6AD064E0DBF4AF4AA5165E1FE0E86FA
+CT=799EAB8E9C864A13490FD6B089F764C5
+PT=2FA3F38CA1216C6D911C1779F333413E
+
+I=15
+KEY=8DCEDB06F49C47C5198025DD3136CF20
+IV=DA039AC5F4EDCD84472B23CFA1252EC3
+CT=2FA3F38CA1216C6D911C1779F333413E
+PT=2FC703AD6A7DAF8B0BDDD8586C1D67D0
+
+I=16
+KEY=A209D8AB9EE1E84E125DFD855D2BA8F0
+IV=341B5FDA8AB434461A7B7A87EF0C530C
+CT=2FC703AD6A7DAF8B0BDDD8586C1D67D0
+PT=54723CABFBE32DEEDFEBF4292A5710FA
+
+I=17
+KEY=F67BE4006502C5A0CDB609AC777CB80A
+IV=2C42AD577B0BE057555C3FCB6FC0089E
+CT=54723CABFBE32DEEDFEBF4292A5710FA
+PT=6B1E2A8C1A9CBB95D1B34AAFE15A78D3
+
+I=18
+KEY=9D65CE8C7F9E7E351C0543039626C0D9
+IV=E5E06583A834BF16118ED5FA401A2D6F
+CT=6B1E2A8C1A9CBB95D1B34AAFE15A78D3
+PT=F4E57BFAB65375B3AD49CD78814F0C16
+
+I=19
+KEY=6980B576C9CD0B86B14C8E7B1769CCCF
+IV=71E59389FF6F992225B32960593F9362
+CT=F4E57BFAB65375B3AD49CD78814F0C16
+PT=90A31B5934FCF6822526C973114BD953
+
+I=20
+KEY=F923AE2FFD31FD04946A47080622159C
+IV=2A4B31492B9BAEC402C255978BB96D40
+CT=90A31B5934FCF6822526C973114BD953
+PT=61F88BA8D438A0FD23F0101465C7FD4E
+
+I=21
+KEY=98DB258729095DF9B79A571C63E5E8D2
+IV=607640CEA12DCF7F188B2B65C7F4153D
+CT=61F88BA8D438A0FD23F0101465C7FD4E
+PT=F62D206DF53F41CA898F3A8EB6A843FF
+
+I=22
+KEY=6EF605EADC361C333E156D92D54DAB2D
+IV=D69C32E12303361B465BE9A484BCA723
+CT=F62D206DF53F41CA898F3A8EB6A843FF
+PT=364BC3F9FDA5FB1AEEA7691550A58320
+
+I=23
+KEY=58BDC6132193E729D0B2048785E8280D
+IV=C207B8347B8DB8BC6845827BB6986B0E
+CT=364BC3F9FDA5FB1AEEA7691550A58320
+PT=DAA6386A073CD1653E9A9DB0A97970BA
+
+I=24
+KEY=821BFE7926AF364CEE2899372C9158B7
+IV=6C5D2B186393280253D6922A8421C3A9
+CT=DAA6386A073CD1653E9A9DB0A97970BA
+PT=AAF74F0E0A0141A811853AE8B120BC00
+
+I=25
+KEY=28ECB1772CAE77E4FFADA3DF9DB1E4B7
+IV=3CB62EF0E649027DDDB76206D0F4D355
+CT=AAF74F0E0A0141A811853AE8B120BC00
+PT=22A0F9611447C1A85F397DD79E3206F9
+
+I=26
+KEY=0A4C481638E9B64CA094DE080383E24E
+IV=C4320FA90686AE0F9E979CBF1391F6D6
+CT=22A0F9611447C1A85F397DD79E3206F9
+PT=1871ABDEAA7E057E76D41ED9191FAC39
+
+I=27
+KEY=123DE3C89297B332D640C0D11A9C4E77
+IV=FBFD18AADF7C5E8E96EB976A535BF312
+CT=1871ABDEAA7E057E76D41ED9191FAC39
+PT=BF52994F41B1DEF78C6A057642C52D89
+
+I=28
+KEY=AD6F7A87D3266DC55A2AC5A7585963FE
+IV=C195141578ADF4C92113C8A9A63FF072
+CT=BF52994F41B1DEF78C6A057642C52D89
+PT=3EAFB00E3B4A0E6DF74743A7EDAD0FE4
+
+I=29
+KEY=93C0CA89E86C63A8AD6D8600B5F46C1A
+IV=D1C4E98C4A9AC79B7CCBC052ACF78913
+CT=3EAFB00E3B4A0E6DF74743A7EDAD0FE4
+PT=4393544AB2387A93496D683C2B8970C7
+
+I=30
+KEY=D0539EC35A54193BE400EE3C9E7D1CDD
+IV=80517C6341DAF4DCBCCAE452F3040147
+CT=4393544AB2387A93496D683C2B8970C7
+PT=51DAC594293708A918E9EFC04F7F2F1C
+
+I=31
+KEY=81895B5773631192FCE901FCD10233C1
+IV=69DE50406B4E3E8A94C1367E1E3D5464
+CT=51DAC594293708A918E9EFC04F7F2F1C
+PT=035B64F06C8166000C82BF15CC88446D
+
+I=32
+KEY=82D23FA71FE27792F06BBEE91D8A77AC
+IV=8EA2E38145BBD79881B7EB31B8818A21
+CT=035B64F06C8166000C82BF15CC88446D
+PT=F3EFFA770A21741551F309E1967CC2E4
+
+I=33
+KEY=713DC5D015C30387A198B7088BF6B548
+IV=0DCAA309668E11509828152553FF2306
+CT=F3EFFA770A21741551F309E1967CC2E4
+PT=62BA0548E7AD136BEB4E38AECD7942D9
+
+I=34
+KEY=1387C098F26E10EC4AD68FA6468FF791
+IV=D031FCA5F3C88926CC3BDDC448537B69
+CT=62BA0548E7AD136BEB4E38AECD7942D9
+PT=38E3D4C7AF0C3E494F1D580AC5430634
+
+I=35
+KEY=2B64145F5D622EA505CBD7AC83CCF1A5
+IV=6FFA5A45EDA60294B0224EEB8C36C455
+CT=38E3D4C7AF0C3E494F1D580AC5430634
+PT=2231EB6A6588CBCB56B930B7F1CF9E04
+
+I=36
+KEY=0955FF3538EAE56E5372E71B72036FA1
+IV=B5375674631ECC3334A318993CB81F9A
+CT=2231EB6A6588CBCB56B930B7F1CF9E04
+PT=59692274C130D6820287EA10F7E64602
+
+I=37
+KEY=503CDD41F9DA33EC51F50D0B85E529A3
+IV=A93D6E028B5C2BD17A29C6CA1617A0A2
+CT=59692274C130D6820287EA10F7E64602
+PT=5975A95327DE7749EA8DEDC580E5E8C7
+
+I=38
+KEY=09497412DE0444A5BB78E0CE0500C164
+IV=26E00CB161145FCD00C39BC4FB1E5CBB
+CT=5975A95327DE7749EA8DEDC580E5E8C7
+PT=D1F7E36BC8FF4439820CB617E745A9CC
+
+I=39
+KEY=D8BE977916FB009C397456D9E24568A8
+IV=72E78D9E15C8FBA864C6C40CEBB190B8
+CT=D1F7E36BC8FF4439820CB617E745A9CC
+PT=76FB4F20C902E9AA89854440631092B5
+
+I=40
+KEY=AE45D859DFF9E936B0F112998155FA1D
+IV=4B6C585FEF52490EA62BAAD08FAA3DCF
+CT=76FB4F20C902E9AA89854440631092B5
+PT=6D7D4487DCD624B2FC5002DFE7D2D347
+
+I=41
+KEY=C3389CDE032FCD844CA110466687295A
+IV=E94FD23A598DDE077CD1DAEE97FDADD9
+CT=6D7D4487DCD624B2FC5002DFE7D2D347
+PT=7297F8F85B21E1A5CB902DCC5F6738F9
+
+I=42
+KEY=B1AF6426580E2C2187313D8A39E011A3
+IV=86E495D31EEFCBC30064414FBD78FAE5
+CT=7297F8F85B21E1A5CB902DCC5F6738F9
+PT=4A6978AACC6968931FB1B83D53D31FEF
+
+I=43
+KEY=FBC61C8C946744B2988085B76A330E4C
+IV=6BA7664AB5ED4F7956D6C3FAA7C42961
+CT=4A6978AACC6968931FB1B83D53D31FEF
+PT=6B63FAAF9DB43A2B6025F29B1D6A331C
+
+I=44
+KEY=90A5E62309D37E99F8A5772C77593D50
+IV=37D17D1702EA34A3C75376AA0F9D24AD
+CT=6B63FAAF9DB43A2B6025F29B1D6A331C
+PT=8317A07BEE0BF16B88D7D197884AC6CF
+
+I=45
+KEY=13B24658E7D88FF27072A6BBFF13FB9F
+IV=29B89B238062495C260AF44C63AA809F
+CT=8317A07BEE0BF16B88D7D197884AC6CF
+PT=0443BFEBCA7C85CBD0CB66AB9D75425D
+
+I=46
+KEY=17F1F9B32DA40A39A0B9C0106266B9C2
+IV=08CF82854AE07429C4A866AA727CEA2E
+CT=0443BFEBCA7C85CBD0CB66AB9D75425D
+PT=6B1EB033CB844F9BDD96BA2C67D139C7
+
+I=47
+KEY=7CEF4980E62045A27D2F7A3C05B78005
+IV=05579F3E0017EBF6083756DC0A50A2E9
+CT=6B1EB033CB844F9BDD96BA2C67D139C7
+PT=E7904CBFB41EBE4178B4D633AFC9B311
+
+I=48
+KEY=9B7F053F523EFBE3059BAC0FAA7E3314
+IV=E6B2CB0CE57E02A230DCD16C08614823
+CT=E7904CBFB41EBE4178B4D633AFC9B311
+PT=96EAAA148F05FAD1F0FC06E135EC5DF8
+
+I=49
+KEY=0D95AF2BDD3B0132F567AAEE9F926EEC
+IV=4268294B10AD58BE9E570A9485963682
+CT=96EAAA148F05FAD1F0FC06E135EC5DF8
+PT=9F2F712F62DE747EE479A0A74384B196
+
+I=50
+KEY=92BADE04BFE5754C111E0A49DC16DF7A
+IV=A5C558F5D4658089CD9FB295EDAE64DB
+CT=9F2F712F62DE747EE479A0A74384B196
+PT=9CF7F00094C4E2D96D752C2312FC135E
+
+I=51
+KEY=0E4D2E042B2197957C6B266ACEEACC24
+IV=1CE301F294BDF4C906E5F0A6FA7C22BB
+CT=9CF7F00094C4E2D96D752C2312FC135E
+PT=ABA58D548DB6E9BE977FDDC85E16C2DE
+
+I=52
+KEY=A5E8A350A6977E2BEB14FBA290FC0EFA
+IV=66C1FF1E4B52A3542B48306EC33F171D
+CT=ABA58D548DB6E9BE977FDDC85E16C2DE
+PT=802948E1A5177FBE97ABA26B996FDF1B
+
+I=53
+KEY=25C1EBB1038001957CBF59C90993D1E1
+IV=197A546DEB2E19E17507276B9ED95135
+CT=802948E1A5177FBE97ABA26B996FDF1B
+PT=67D931C0946ECDF2F8E41000726D1A56
+
+I=54
+KEY=4218DA7197EECC67845B49C97BFECBB7
+IV=D11DA3CE92ADA0686F7BF12A4796D9F7
+CT=67D931C0946ECDF2F8E41000726D1A56
+PT=386C68821385E8CFCDD5678FE2AA89F8
+
+I=55
+KEY=7A74B2F3846B24A8498E2E469954424F
+IV=4DDE413EBC3F30E2F3A9F48DA1258DAF
+CT=386C68821385E8CFCDD5678FE2AA89F8
+PT=1638C741EFE3B1CC45C7754783350825
+
+I=56
+KEY=6C4C75B26B8895640C495B011A614A6A
+IV=5B4F013B085E3A04A16A409E8C3BB270
+CT=1638C741EFE3B1CC45C7754783350825
+PT=91AB00C3828D3DF72BEC487EF4652567
+
+I=57
+KEY=FDE77571E905A89327A5137FEE046F0D
+IV=98074F522144682FF1498C61581F8B0E
+CT=91AB00C3828D3DF72BEC487EF4652567
+PT=BC5BA874D2F3039837528993FB275EBA
+
+I=58
+KEY=41BCDD053BF6AB0B10F79AEC152331B7
+IV=B65C1A6F80CA024B92176D57061ECDFE
+CT=BC5BA874D2F3039837528993FB275EBA
+PT=B7DE1BEE1867F4DC3F974E0D8B416DB0
+
+I=59
+KEY=F662C6EB23915FD72F60D4E19E625C07
+IV=7268C08FA807D83C9830F54A59F32662
+CT=B7DE1BEE1867F4DC3F974E0D8B416DB0
+PT=19769B9EB30B8DE5FD640ACE78F01F0A
+
+I=60
+KEY=EF145D75909AD232D204DE2FE692430D
+IV=B260792BAB22BAAB6CCF3AE1DD3A0F85
+CT=19769B9EB30B8DE5FD640ACE78F01F0A
+PT=2079F2C0A0DE164CD41FCE29D8CE3178
+
+I=61
+KEY=CF6DAFB53044C47E061B10063E5C7275
+IV=6ABCE7B41E112B91B8E6BC0DBE37600C
+CT=2079F2C0A0DE164CD41FCE29D8CE3178
+PT=0D3A678FAB06E743A9134C103B39B61D
+
+I=62
+KEY=C257C83A9B42233DAF085C160565C468
+IV=CEB1E776DBEF46BF8B949C0AF0EBEAD2
+CT=0D3A678FAB06E743A9134C103B39B61D
+PT=80339ADB34BCDE3384D66170373AEEAC
+
+I=63
+KEY=426452E1AFFEFD0E2BDE3D66325F2AC4
+IV=EAAC373FCA05E610C1C5D4437AFD5631
+CT=80339ADB34BCDE3384D66170373AEEAC
+PT=38D52D75E5783A08FBFE622633D6CF47
+
+I=64
+KEY=7AB17F944A86C706D0205F400189E583
+IV=2A25ED6933CAAA95569ADA1AC7480942
+CT=38D52D75E5783A08FBFE622633D6CF47
+PT=3204F1EACBB520A69F0939F45BC82041
+
+I=65
+KEY=48B58E7E8133E7A04F2966B45A41C5C2
+IV=9C6819799DAF61111ACC3C0ECEB0F8BF
+CT=3204F1EACBB520A69F0939F45BC82041
+PT=16BD33EE541798BEE114E9D7F9141A9C
+
+I=66
+KEY=5E08BD90D5247F1EAE3D8F63A355DF5E
+IV=C181F4DF1EE0E13BF76044A3DA5E3BC4
+CT=16BD33EE541798BEE114E9D7F9141A9C
+PT=A0A68CF016C6AD8DAC4D5634EAADEBE5
+
+I=67
+KEY=FEAE3160C3E2D2930270D95749F834BB
+IV=2A4EE2CD011AF421616789DB790354FD
+CT=A0A68CF016C6AD8DAC4D5634EAADEBE5
+PT=FCE7D92FD0B3A1C7920558F653E1019B
+
+I=68
+KEY=0249E84F13517354907581A11A193520
+IV=A7F7E2B701F34F308C0F28514DFAA15F
+CT=FCE7D92FD0B3A1C7920558F653E1019B
+PT=F16A084B2DE16D5E3E5405665DE3C623
+
+I=69
+KEY=F323E0043EB01E0AAE2184C747FAF303
+IV=6D319828AAA75DFE99BEEDD21B983C7D
+CT=F16A084B2DE16D5E3E5405665DE3C623
+PT=CE20AE629887DF02064F2D9DB092E1DB
+
+I=70
+KEY=3D034E66A637C108A86EA95AF76812D8
+IV=9484E76149F41901AF8AFD3152C56506
+CT=CE20AE629887DF02064F2D9DB092E1DB
+PT=B457A655282213C1B7C5C2A206C7FCB9
+
+I=71
+KEY=8954E8338E15D2C91FAB6BF8F1AFEE61
+IV=329E089DC915BD71B1F8D0713BFC4F97
+CT=B457A655282213C1B7C5C2A206C7FCB9
+PT=A89B8F7541FFF719A3C7DE1577CE1C3F
+
+I=72
+KEY=21CF6746CFEA25D0BC6CB5ED8661F25E
+IV=FA381CAC5777234E6DF8A28A4E6671D8
+CT=A89B8F7541FFF719A3C7DE1577CE1C3F
+PT=C4E73D25647350527C1F93F6C1D90296
+
+I=73
+KEY=E5285A63AB997582C073261B47B8F0C8
+IV=082ACF3D2661514F0E00BDABC9015946
+CT=C4E73D25647350527C1F93F6C1D90296
+PT=34BF6DECECFE1C9AE3AA34B6DB3741EF
+
+I=74
+KEY=D197378F4767691823D912AD9C8FB127
+IV=3E56B658F899B6DBBA4EAF6E629F3555
+CT=34BF6DECECFE1C9AE3AA34B6DB3741EF
+PT=FD86C78538176DC5D48BE2EC6B89D581
+
+I=75
+KEY=2C11F00A7F7004DDF752F041F70664A6
+IV=765B823193F2738E6CACBB0154C941B1
+CT=FD86C78538176DC5D48BE2EC6B89D581
+PT=524E035AB9DEB29E467B9586A90F3A42
+
+I=76
+KEY=7E5FF350C6AEB643B12965C75E095EE4
+IV=DE2B3EC0A3FF29EC67BBE1B124E9451A
+CT=524E035AB9DEB29E467B9586A90F3A42
+PT=83DE1E768EED94BA09E623845A057834
+
+I=77
+KEY=FD81ED26484322F9B8CF4643040C26D0
+IV=A5CF4D996D8460E71DDA938461BB884B
+CT=83DE1E768EED94BA09E623845A057834
+PT=D8381D17B9BCF942F408DBB2B7B2D6B7
+
+I=78
+KEY=25B9F031F1FFDBBB4CC79DF1B3BEF067
+IV=899696B8EDC4E8B60489742A2559C909
+CT=D8381D17B9BCF942F408DBB2B7B2D6B7
+PT=BF1D8175015D0A0341427DE1F7DDE379
+
+I=79
+KEY=9AA47144F0A2D1B80D85E0104463131E
+IV=AD76D13B2F2A3F938F5C810A38A83D09
+CT=BF1D8175015D0A0341427DE1F7DDE379
+PT=58114DEFF8CFF10F06B390EB01B13394
+
+I=80
+KEY=C2B53CAB086D20B70B3670FB45D2208A
+IV=9EC540C144AB57D4E5A9185F55E71E50
+CT=58114DEFF8CFF10F06B390EB01B13394
+PT=53E72B9603CE221F0160791DF51F6B3E
+
+I=81
+KEY=9152173D0BA302A80A5609E6B0CD4BB4
+IV=B780257238CA60FD998819B2D04CEB92
+CT=53E72B9603CE221F0160791DF51F6B3E
+PT=AF0238554AAFFB0FB5DFAC35E3CE8F4C
+
+I=82
+KEY=3E502F68410CF9A7BF89A5D35303C4F8
+IV=3509BC884089ADEB90137A39AEA75CFC
+CT=AF0238554AAFFB0FB5DFAC35E3CE8F4C
+PT=20844D3F4F637B974D38B7E5F1C84205
+
+I=83
+KEY=1ED462570E6F8230F2B11236A2CB86FD
+IV=52BAB07EB72804630E4BD769F0172FDA
+CT=20844D3F4F637B974D38B7E5F1C84205
+PT=68404E006D2F16572EDFAE636A62C537
+
+I=84
+KEY=76942C5763409467DC6EBC55C8A943CA
+IV=E4B417D85F36F3A25CF04AB05157F247
+CT=68404E006D2F16572EDFAE636A62C537
+PT=13C8DF4117D4EA3645F1825700F8FFA5
+
+I=85
+KEY=655CF31674947E51999F3E02C851BC6F
+IV=3FE0683442B6B5DF515209DE16F8FD4B
+CT=13C8DF4117D4EA3645F1825700F8FFA5
+PT=42307D929439F2723202A5206D640431
+
+I=86
+KEY=276C8E84E0AD8C23AB9D9B22A535B85E
+IV=33FAD11D9D4057E7ED989F1520450C32
+CT=42307D929439F2723202A5206D640431
+PT=5ED8AF875ACF37BE8FAAC16D4AB8072B
+
+I=87
+KEY=79B42103BA62BB9D24375A4FEF8DBF75
+IV=807852E5AD0EB5E0C3A2AAF18DFB14F9
+CT=5ED8AF875ACF37BE8FAAC16D4AB8072B
+PT=79C950A45ECDC8B676A5CFF324A81DA8
+
+I=88
+KEY=007D71A7E4AF732B529295BCCB25A2DD
+IV=516BC35B52C26C99E21C0147CB7DD99E
+CT=79C950A45ECDC8B676A5CFF324A81DA8
+PT=595C3DDCFBD90661A3A70B94C470A26B
+
+I=89
+KEY=59214C7B1F76754AF1359E280F5500B6
+IV=FDABDD4BD60725F5E640629416F417D3
+CT=595C3DDCFBD90661A3A70B94C470A26B
+PT=7957CF3989083D25B54C6890EC58DB0C
+
+I=90
+KEY=20768342967E486F4479F6B8E30DDBBA
+IV=CADFADF417898DE3786D5DF869396611
+CT=7957CF3989083D25B54C6890EC58DB0C
+PT=6C1E8DF34FC80DD2ECA00A1EDC5FC239
+
+I=91
+KEY=4C680EB1D9B645BDA8D9FCA63F521983
+IV=A7DF9FA44AA2B49B9E26C6148CCAF36F
+CT=6C1E8DF34FC80DD2ECA00A1EDC5FC239
+PT=72B5A426C9DC3B336756FB10B00626CE
+
+I=92
+KEY=3EDDAA97106A7E8ECF8F07B68F543F4D
+IV=50FF574915D407A97A74CC399DE2D901
+CT=72B5A426C9DC3B336756FB10B00626CE
+PT=194826159D7FAB9166D64F1DD6F627B0
+
+I=93
+KEY=27958C828D15D51FA95948AB59A218FD
+IV=A1E3BC848C019B6FC3F7072F9A866C52
+CT=194826159D7FAB9166D64F1DD6F627B0
+PT=0186B2316FC29104D3549C49F92AE414
+
+I=94
+KEY=26133EB3E2D7441B7A0DD4E2A088FCE9
+IV=4DBA42F1031AE32016524C7F86781528
+CT=0186B2316FC29104D3549C49F92AE414
+PT=373384DB7383D3A4914C0141BB104B81
+
+I=95
+KEY=1120BA68915497BFEB41D5A31B98B768
+IV=FFCB87107AC596D71BA807902D524247
+CT=373384DB7383D3A4914C0141BB104B81
+PT=25465CE5FA2AD65D75586064A18516A8
+
+I=96
+KEY=3466E68D6B7E41E29E19B5C7BA1DA1C0
+IV=55879596C3F0A295FA00CFEF1B056248
+CT=25465CE5FA2AD65D75586064A18516A8
+PT=2311A52CEC4A16B5F4FCA613BC0BDB83
+
+I=97
+KEY=177743A1873457576AE513D406167A43
+IV=B1A7DABF3D2384BF8754B829659B3989
+CT=2311A52CEC4A16B5F4FCA613BC0BDB83
+PT=357F4BF62308CD5C48F34E9E644DD515
+
+I=98
+KEY=22080857A43C9A0B22165D4A625BAF56
+IV=72BF477FE8CF428CFA856323E18B3135
+CT=357F4BF62308CD5C48F34E9E644DD515
+PT=17758539D1896B92BFB811D30C9BA134
+
+I=99
+KEY=357D8D6E75B5F1999DAE4C996EC00E62
+IV=4CBA048DFA50910EC94FE5D6AA5DD502
+CT=17758539D1896B92BFB811D30C9BA134
+PT=372B6DCEE44D18D3791C4E8FB0A91971
+
+I=100
+KEY=0256E0A091F8E94AE4B20216DE691713
+IV=86F4F670CA3B191B860D6C8A9A35A872
+CT=372B6DCEE44D18D3791C4E8FB0A91971
+PT=66D3FABC4885C1F4897D9160C152D570
+
+I=101
+KEY=64851A1CD97D28BE6DCF93761F3BC263
+IV=08490B2E8588FE564F0112D76D6108E9
+CT=66D3FABC4885C1F4897D9160C152D570
+PT=926278E71894F32B5E2A5A1F5FA695E7
+
+I=102
+KEY=F6E762FBC1E9DB9533E5C969409D5784
+IV=D3A2E4AFFDD8A7CC1498EF0E812087B7
+CT=926278E71894F32B5E2A5A1F5FA695E7
+PT=A455F5D65D91563D9C15E6B745F29531
+
+I=103
+KEY=52B2972D9C788DA8AFF02FDE056FC2B5
+IV=6CB8822EA67C247A6A0CBAD830B3562C
+CT=A455F5D65D91563D9C15E6B745F29531
+PT=4544371A5E3A8E7AD9885AECD3868AF3
+
+I=104
+KEY=17F6A037C24203D276787532D6E94846
+IV=93E3CAD8BE023F6451ADAA525988A974
+CT=4544371A5E3A8E7AD9885AECD3868AF3
+PT=8473F4F1D77AC1F46706EBD108CB48A5
+
+I=105
+KEY=938554C61538C226117E9EE3DE2200E3
+IV=A7E7B354606EF4C1D00BF4F128CCE966
+CT=8473F4F1D77AC1F46706EBD108CB48A5
+PT=787ADE453DCE2FA7F6F24CD33C9A5CDC
+
+I=106
+KEY=EBFF8A8328F6ED81E78CD230E2B85C3F
+IV=97A2CF706C1871B502D15B028C5F0D80
+CT=787ADE453DCE2FA7F6F24CD33C9A5CDC
+PT=E6A7E5B65DC124FBE1C1FFFE18A34D8A
+
+I=107
+KEY=0D586F357537C97A064D2DCEFA1B11B5
+IV=9BBDCAF2A3CC7FC5BF6285631A4636FD
+CT=E6A7E5B65DC124FBE1C1FFFE18A34D8A
+PT=6A391E9F475546720836312BBEB0B3A9
+
+I=108
+KEY=676171AA32628F080E7B1CE544ABA21C
+IV=603EEDE91F925A2228537E8BDD26C96B
+CT=6A391E9F475546720836312BBEB0B3A9
+PT=D75086BA446563AAB1873FDEBE611D67
+
+I=109
+KEY=B031F7107607ECA2BFFC233BFACABF7B
+IV=546B8CA37AACE2BC2C85014F2ACD6315
+CT=D75086BA446563AAB1873FDEBE611D67
+PT=63A4D826625CBD9F10083E62330BCFBC
+
+I=110
+KEY=D3952F36145B513DAFF41D59C9C170C7
+IV=BC2E6E9DD10152C8281B798F711A9334
+CT=63A4D826625CBD9F10083E62330BCFBC
+PT=41275EFDFC86B5BDCCCDCA2BBFA5B90D
+
+I=111
+KEY=92B271CBE8DDE4806339D7727664C9CA
+IV=D940A8D1B3448AA9148C7F6DFC266B00
+CT=41275EFDFC86B5BDCCCDCA2BBFA5B90D
+PT=56AC1BCB285044710D26EFC42A0ABA56
+
+I=112
+KEY=C41E6A00C08DA0F16E1F38B65C6E739C
+IV=214238FF5F4D01F3A6694EC80E15BCF7
+CT=56AC1BCB285044710D26EFC42A0ABA56
+PT=5AF2877973AB9787E42202AC0C6E7538
+
+I=113
+KEY=9EECED79B32637768A3D3A1A500006A4
+IV=561B4934904E327F3B3639CED6C7A995
+CT=5AF2877973AB9787E42202AC0C6E7538
+PT=787F52F6D9CD9085D782B95FD68F70F8
+
+I=114
+KEY=E693BF8F6AEBA7F35DBF8345868F765C
+IV=06B93FB1A99BD387A091509B8C6D3482
+CT=787F52F6D9CD9085D782B95FD68F70F8
+PT=E7B1DB917C92E488C6B02AC4C42AFD79
+
+I=115
+KEY=0122641E1679437B9B0FA98142A58B25
+IV=1D57A61FED51218BD8C1357CE58F21EB
+CT=E7B1DB917C92E488C6B02AC4C42AFD79
+PT=2FBAB770D511EACA849F654DE429DE84
+
+I=116
+KEY=2E98D36EC368A9B11F90CCCCA68C55A1
+IV=CB311C43EC32D59941CEF81BB9CF4E57
+CT=2FBAB770D511EACA849F654DE429DE84
+PT=A8FE17AEA961C2A450DD5EAABAA19613
+
+I=117
+KEY=8666C4C06A096B154F4D92661C2DC3B2
+IV=B9D7B74D62DD89A01EE3093A5C2A0470
+CT=A8FE17AEA961C2A450DD5EAABAA19613
+PT=D9E598A4DBAF82BDF9474BE13B997FF5
+
+I=118
+KEY=5F835C64B1A6E9A8B60AD98727B4BC47
+IV=6398D8A38C38A9B54DCF18C0D76758BA
+CT=D9E598A4DBAF82BDF9474BE13B997FF5
+PT=291DB2BC325CD7A94032E7C1208921A5
+
+I=119
+KEY=769EEED883FA3E01F6383E46073D9DE2
+IV=4774C7E1BB97117BCA26A897B9302EFA
+CT=291DB2BC325CD7A94032E7C1208921A5
+PT=DFC55866F85055F06E752E04AAC4C36A
+
+I=120
+KEY=A95BB6BE7BAA6BF1984D1042ADF95E88
+IV=BDA0616700CD2817FE4425F6F541E8C1
+CT=DFC55866F85055F06E752E04AAC4C36A
+PT=7CACB3A88E7114F7737B05D0FB3AF7F3
+
+I=121
+KEY=D5F70516F5DB7F06EB36159256C3A97B
+IV=1EF4836BD363B89EE73911B14EBE9262
+CT=7CACB3A88E7114F7737B05D0FB3AF7F3
+PT=3282F1F6B3C04E325FB13E85D18CDBBC
+
+I=122
+KEY=E775F4E0461B3134B4872B17874F72C7
+IV=E35D47CEDBD30701A64FE504C6BC4199
+CT=3282F1F6B3C04E325FB13E85D18CDBBC
+PT=BFB9748A3C825CDA3EA5D001F6AD305F
+
+I=123
+KEY=58CC806A7A996DEE8A22FB1671E24298
+IV=7A3676377E0B4F815B4B8C9A98DCAB4D
+CT=BFB9748A3C825CDA3EA5D001F6AD305F
+PT=B33787380A4C3BD5B32EC335916F9229
+
+I=124
+KEY=EBFB075270D5563B390C3823E08DD0B1
+IV=B3E40B27DBF6D985D4F57BD4D2899DC8
+CT=B33787380A4C3BD5B32EC335916F9229
+PT=BCD5E40A3B4885ACA82BEC952BA8A973
+
+I=125
+KEY=572EE3584B9DD3979127D4B6CB2579C2
+IV=897608FE3238F80CD24192CC64F4F695
+CT=BCD5E40A3B4885ACA82BEC952BA8A973
+PT=793E22E0B01FFE63E89C84A0D0FE1216
+
+I=126
+KEY=2E10C1B8FB822DF479BB50161BDB6BD4
+IV=D84401CF83566FEA8FB859C446C22632
+CT=793E22E0B01FFE63E89C84A0D0FE1216
+PT=96858A96FEB19712B10A44FBF8E633D9
+
+I=127
+KEY=B8954B2E0533BAE6C8B114EDE33D580D
+IV=7210E127BFB706EF9CD24139C0927E01
+CT=96858A96FEB19712B10A44FBF8E633D9
+PT=28A34CC75A215117331D6B88387E16F8
+
+I=128
+KEY=903607E95F12EBF1FBAC7F65DB434EF5
+IV=744B8DD281919F79FC529DA15AA0F18F
+CT=28A34CC75A215117331D6B88387E16F8
+PT=43FE41DC9FFB88F93ADC43D41BA3E4B2
+
+I=129
+KEY=D3C84635C0E96308C1703CB1C0E0AA47
+IV=5C7379A90F1E47F88C7424E8CD31E55D
+CT=43FE41DC9FFB88F93ADC43D41BA3E4B2
+PT=66D6D0E84CEB8672D38DDE557CCCFFF6
+
+I=130
+KEY=B51E96DD8C02E57A12FDE2E4BC2C55B1
+IV=529B92CD068415627C4BE49874347F98
+CT=66D6D0E84CEB8672D38DDE557CCCFFF6
+PT=F817D013CB041CA41B6D611ED261FAE9
+
+I=131
+KEY=4D0946CE4706F9DE099083FA6E4DAF58
+IV=9B4452DD48C3EECEFDB6A6CFAE670117
+CT=F817D013CB041CA41B6D611ED261FAE9
+PT=56420C70CC459A131CD531EDC39ED6E9
+
+I=132
+KEY=1B4B4ABE8B4363CD1545B217ADD379B1
+IV=264ABBC30CC98DA3C06B935B1364A317
+CT=56420C70CC459A131CD531EDC39ED6E9
+PT=650DA8C4CB11E4ABFE8841D20443BB04
+
+I=133
+KEY=7E46E27A40528766EBCDF3C5A990C2B5
+IV=DBABF7B18568FED50C69DA0C9AA5395D
+CT=650DA8C4CB11E4ABFE8841D20443BB04
+PT=94E6CE02AE253F3BE4A59775CAB7B11B
+
+I=134
+KEY=EAA02C78EE77B85D0F6864B0632773AE
+IV=F0D2E456CE063CB68988C1C397038480
+CT=94E6CE02AE253F3BE4A59775CAB7B11B
+PT=124F09DAC6A45E6077DCECE971B24ED1
+
+I=135
+KEY=F8EF25A228D3E63D78B4885912953D7F
+IV=C19A6D2D35E606E552580B002023C966
+CT=124F09DAC6A45E6077DCECE971B24ED1
+PT=AAD649FD1168DFCB431A7216571ED4C1
+
+I=136
+KEY=52396C5F39BB39F63BAEFA4F458BE9BE
+IV=DF1A307B1D25BC2751ECDC791EC51B16
+CT=AAD649FD1168DFCB431A7216571ED4C1
+PT=992749C940CBBB0944F5248E8D65268C
+
+I=137
+KEY=CB1E2596797082FF7F5BDEC1C8EECF32
+IV=D8B0466FC4344C6BF4E57584E5F48A36
+CT=992749C940CBBB0944F5248E8D65268C
+PT=FF16B9246C325A3B96250875A9D5C4BE
+
+I=138
+KEY=34089CB21542D8C4E97ED6B4613B0B8C
+IV=B8C3E4ECF57631CE1EEA74AD99545BA2
+CT=FF16B9246C325A3B96250875A9D5C4BE
+PT=72EDB906165FE6A19E02435AC6457C9A
+
+I=139
+KEY=46E525B4031D3E65777C95EEA77E7716
+IV=9C4F78D05257C64D752C576B5BB16245
+CT=72EDB906165FE6A19E02435AC6457C9A
+PT=0C2F00362B8733D343DCAF884A6BFD46
+
+I=140
+KEY=4ACA2582289A0DB634A03A66ED158A50
+IV=C51122198D2FD566ACA1BD07C28BCC7A
+CT=0C2F00362B8733D343DCAF884A6BFD46
+PT=C7F5C00F42695CF7870240DA73D487F7
+
+I=141
+KEY=8D3FE58D6AF35141B3A27ABC9EC10DA7
+IV=14769B7962371925822C42F0411BDC65
+CT=C7F5C00F42695CF7870240DA73D487F7
+PT=F4BC8A4310A4CD2F396F43B81BD060EB
+
+I=142
+KEY=79836FCE7A579C6E8ACD390485116D4C
+IV=CDA4414DF23427B937D586C1A8164479
+CT=F4BC8A4310A4CD2F396F43B81BD060EB
+PT=1B996A525174C35466103BCBD53ECB9C
+
+I=143
+KEY=621A059C2B235F3AECDD02CF502FA6D0
+IV=1DA9E7C02BE868E118E4B9BF5928BFCF
+CT=1B996A525174C35466103BCBD53ECB9C
+PT=2B4EC5CB9DE50257B5901C6D49B5EB54
+
+I=144
+KEY=4954C057B6C65D6D594D1EA2199A4D84
+IV=55433149AA93215BF53CB8FE66CD683A
+CT=2B4EC5CB9DE50257B5901C6D49B5EB54
+PT=5A5B9ACA3BDA951DC4C4DFB7DD15AD18
+
+I=145
+KEY=130F5A9D8D1CC8709D89C115C48FE09C
+IV=695C69EA8C4257D2758364AFF6387DA0
+CT=5A5B9ACA3BDA951DC4C4DFB7DD15AD18
+PT=5BB08593BA52E94F07CB14FF564AF299
+
+I=146
+KEY=48BFDF0E374E213F9A42D5EA92C51205
+IV=665463164601CD0045C684729CDD5E7D
+CT=5BB08593BA52E94F07CB14FF564AF299
+PT=DB1840467889551150026A90E3FC272F
+
+I=147
+KEY=93A79F484FC7742ECA40BF7A7139352A
+IV=355C4B87A682712460C80ABA630F7BE8
+CT=DB1840467889551150026A90E3FC272F
+PT=9F7BD8EF96A1ECC75B4E3031E65FE8FC
+
+I=148
+KEY=0CDC47A7D96698E9910E8F4B9766DDD6
+IV=FBF20FEC0A9E9B530DD3745955A1960C
+CT=9F7BD8EF96A1ECC75B4E3031E65FE8FC
+PT=DCF003E1DDD4B52F5B680568B42EEECF
+
+I=149
+KEY=D02C444604B22DC6CA668A2323483319
+IV=04EADC638E309466B9500B1C3A308856
+CT=DCF003E1DDD4B52F5B680568B42EEECF
+PT=DDD2F2AEFEF4A4641747699170DF0129
+
+I=150
+KEY=0DFEB6E8FA4689A2DD21E3B253973230
+IV=FB521123E5BB45F1AC7083C382B95E10
+CT=DDD2F2AEFEF4A4641747699170DF0129
+PT=7D6C54E4369E965513DE1E95E8A37433
+
+I=151
+KEY=7092E20CCCD81FF7CEFFFD27BB344603
+IV=0E71300101915AEE97563493B4B2EFB9
+CT=7D6C54E4369E965513DE1E95E8A37433
+PT=B7F5C4275EF7D3A23E8E9A4BC2BCA700
+
+I=152
+KEY=C767262B922FCC55F071676C7988E103
+IV=8BBC970D4E24F6F1A92859BBAE70B757
+CT=B7F5C4275EF7D3A23E8E9A4BC2BCA700
+PT=679FA9A8AB3EE2F0663D4DC95FEC3847
+
+I=153
+KEY=A0F88F8339112EA5964C2AA52664D944
+IV=B8D28B6903859465F996A0DF491DDAAA
+CT=679FA9A8AB3EE2F0663D4DC95FEC3847
+PT=914DCEAC5B00940A415C2144DAA1EF03
+
+I=154
+KEY=31B5412F6211BAAFD7100BE1FCC53647
+IV=06E1FF99E63E0EDDA1D95682B541D026
+CT=914DCEAC5B00940A415C2144DAA1EF03
+PT=A718031A531395DA071B828A10A2B9DC
+
+I=155
+KEY=96AD423531022F75D00B896BEC678F9B
+IV=F18546028693CC0A72E218460AC932E9
+CT=A718031A531395DA071B828A10A2B9DC
+PT=19D996B9FF549029D800CF977C0E0A88
+
+I=156
+KEY=8F74D48CCE56BF5C080B46FC90698513
+IV=7E98DAFA8DE35537A0B0AA8FA32E01DF
+CT=19D996B9FF549029D800CF977C0E0A88
+PT=6A7D514FBE9963987E0EE5DD22FDC8BD
+
+I=157
+KEY=E50985C370CFDCC47605A321B2944DAE
+IV=071F44277D12AD6E653FB747C11BEFB7
+CT=6A7D514FBE9963987E0EE5DD22FDC8BD
+PT=AB07C464DF72DF58411A7CBF906F43A6
+
+I=158
+KEY=4E0E41A7AFBD039C371FDF9E22FB0E08
+IV=BDA8979A0DE78999AE0659D2744BC21B
+CT=AB07C464DF72DF58411A7CBF906F43A6
+PT=A8ABC34FF51FD998427A7837BB0F22BB
+
+I=159
+KEY=E6A582E85AA2DA047565A7A999F42CB3
+IV=3CA763C4375A6C70F072B52C42A02560
+CT=A8ABC34FF51FD998427A7837BB0F22BB
+PT=9E82A41AB2A2748695663075C5BF1C09
+
+I=160
+KEY=782726F2E800AE82E00397DC5C4B30BA
+IV=B1DD4DC8715CA0B8BA3426395B61ABA4
+CT=9E82A41AB2A2748695663075C5BF1C09
+PT=3C891AEFC6645F3C23A2E3A2E1A522EF
+
+I=161
+KEY=44AE3C1D2E64F1BEC3A1747EBDEE1255
+IV=932F28E3FC0F85A0E703AD6079A68CC0
+CT=3C891AEFC6645F3C23A2E3A2E1A522EF
+PT=D4FDD9C3D36E80E0AFA95ABEC2E62FB9
+
+I=162
+KEY=9053E5DEFD0A715E6C082EC07F083DEC
+IV=1AD1530DE6274BBA3A097004D85DF8FA
+CT=D4FDD9C3D36E80E0AFA95ABEC2E62FB9
+PT=9FACBB106FBF34D9B25A83AD4F45AA38
+
+I=163
+KEY=0FFF5ECE92B54587DE52AD6D304D97D4
+IV=8412EAA361AB8193AD529FA36944FE3D
+CT=9FACBB106FBF34D9B25A83AD4F45AA38
+PT=E95628B6A14326AC153B228C0DD25063
+
+I=164
+KEY=E6A9767833F6632BCB698FE13D9FC7B7
+IV=9F1D906FD25CCCA7565D82CDA44B4A57
+CT=E95628B6A14326AC153B228C0DD25063
+PT=7B1ECD07E452D593D00E326F8FD9F2B5
+
+I=165
+KEY=9DB7BB7FD7A4B6B81B67BD8EB2463502
+IV=9C91B12734A86451492400EE5759C190
+CT=7B1ECD07E452D593D00E326F8FD9F2B5
+PT=A99874C1ECA463D335B37179348AEF4F
+
+I=166
+KEY=342FCFBE3B00D56B2ED4CCF786CCDA4D
+IV=9060C6E8E2B51E5F1000860ECB5A608C
+CT=A99874C1ECA463D335B37179348AEF4F
+PT=F9296E658C3048C58FE6404AB6E0186C
+
+I=167
+KEY=CD06A1DBB7309DAEA1328CBD302CC221
+IV=ADCB427405EDF8078622AFC6C731D3EF
+CT=F9296E658C3048C58FE6404AB6E0186C
+PT=8D3A4ABFB8F57AEBB1284B78BFDD240D
+
+I=168
+KEY=403CEB640FC5E745101AC7C58FF1E62C
+IV=4CED30477756892A49FE6358700F5DE7
+CT=8D3A4ABFB8F57AEBB1284B78BFDD240D
+PT=7C71310D5241B8B461847FA7E2B4D506
+
+I=169
+KEY=3C4DDA695D845FF1719EB8626D45332A
+IV=52A3B8E21588368AA3AD2131B283B34C
+CT=7C71310D5241B8B461847FA7E2B4D506
+PT=380A1E2925FC8061FBC69B08B4C7C6C8
+
+I=170
+KEY=0447C4407878DF908A58236AD982F5E2
+IV=B7AD265DF50ABD77C1D1D02BAF06CEBD
+CT=380A1E2925FC8061FBC69B08B4C7C6C8
+PT=6931E262570F27732A75629A384492CA
+
+I=171
+KEY=6D7626222F77F8E3A02D41F0E1C66728
+IV=DD7D3CA7F6CE54775836734B10685A99
+CT=6931E262570F27732A75629A384492CA
+PT=336D0AB3F9A793469C544E98CFDC8AD6
+
+I=172
+KEY=5E1B2C91D6D06BA53C790F682E1AEDFE
+IV=54087C05437049FBAFC9BF6C56AD16CC
+CT=336D0AB3F9A793469C544E98CFDC8AD6
+PT=0098A640F1D04E5557F748B80215082A
+
+I=173
+KEY=5E838AD1270025F06B8E47D02C0FE5D4
+IV=DD13A93C7FAEF14820D6A168AF9969DB
+CT=0098A640F1D04E5557F748B80215082A
+PT=48660EDDC3ACAC1A814AE088650DE007
+
+I=174
+KEY=16E5840CE4AC89EAEAC4A758490205D3
+IV=589C43A680F7AE6E15DE25FD50F18BED
+CT=48660EDDC3ACAC1A814AE088650DE007
+PT=047740C48160A14563C0049316C7B78E
+
+I=175
+KEY=1292C4C865CC28AF8904A3CB5FC5B25D
+IV=22DB095AF8268D37AC536FDA3A81B7C2
+CT=047740C48160A14563C0049316C7B78E
+PT=D9679ABB1AED1524E8DA2ECA89172853
+
+I=176
+KEY=CBF55E737F213D8B61DE8D01D6D29A0E
+IV=77FDCCC9BAB3B7E81D7B9D14540ED3A7
+CT=D9679ABB1AED1524E8DA2ECA89172853
+PT=C774AD9EF683A59747AB41DA044471C4
+
+I=177
+KEY=0C81F3ED89A2981C2675CCDBD296EBCA
+IV=2E266970512C0F6D404367978C70B5C6
+CT=C774AD9EF683A59747AB41DA044471C4
+PT=927C98AFDE6F108268A306A1A818EE89
+
+I=178
+KEY=9EFD6B4257CD889E4ED6CA7A7A8E0543
+IV=E2B0A0F146E931136932D8188B7DC980
+CT=927C98AFDE6F108268A306A1A818EE89
+PT=D3C11AF1EF255D65EAAEE5B5C5BF3CD9
+
+I=179
+KEY=4D3C71B3B8E8D5FBA4782FCFBF31399A
+IV=ABA118A590A8A69D41D20ED13F7DA4C9
+CT=D3C11AF1EF255D65EAAEE5B5C5BF3CD9
+PT=760B1C47EB476A246CE41163B7425C7B
+
+I=180
+KEY=3B376DF453AFBFDFC89C3EAC087365E1
+IV=8A395FFEE93FF820FBC086932216324F
+CT=760B1C47EB476A246CE41163B7425C7B
+PT=4EEAE25D1654A461D6A56896EDFFEAB7
+
+I=181
+KEY=75DD8FA945FB1BBE1E39563AE58C8F56
+IV=82D68DE458D38127E2A17DA736BC1651
+CT=4EEAE25D1654A461D6A56896EDFFEAB7
+PT=BD7ABD27F3515B9FD337ADADBA5E9EC9
+
+I=182
+KEY=C8A7328EB6AA4021CD0EFB975FD2119F
+IV=95757C38F4CB26C29DF174FD8B1F35E8
+CT=BD7ABD27F3515B9FD337ADADBA5E9EC9
+PT=E32EF56DE91CC21C158822BDB841A02C
+
+I=183
+KEY=2B89C7E35FB6823DD886D92AE793B1B3
+IV=AFFB434005E300E99E815A8E5B46E159
+CT=E32EF56DE91CC21C158822BDB841A02C
+PT=578B7692D68BD4D65A159C9CCDC81F64
+
+I=184
+KEY=7C02B171893D56EB829345B62A5BAED7
+IV=15E783551969F275EF25A429F68BA0DB
+CT=578B7692D68BD4D65A159C9CCDC81F64
+PT=0F70D77F31DE8F0010628377C8E4A1C3
+
+I=185
+KEY=7372660EB8E3D9EB92F1C6C1E2BF0F14
+IV=078B6E3FC7C79D52A5C49847A7C5D0BB
+CT=0F70D77F31DE8F0010628377C8E4A1C3
+PT=A4F29F6A50A4A15789D4647774C96997
+
+I=186
+KEY=D780F964E84778BC1B25A2B696766683
+IV=C9B2C903F131856C0D8218146479513A
+CT=A4F29F6A50A4A15789D4647774C96997
+PT=7AD4F764911F8F1E8C9356F00B1468EE
+
+I=187
+KEY=AD540E007958F7A297B6F4469D620E6D
+IV=780DAD9DBA12DDC713ECF44057B8B56E
+CT=7AD4F764911F8F1E8C9356F00B1468EE
+PT=A00EAFD28A95C7F39137773F28F9A0D3
+
+I=188
+KEY=0D5AA1D2F3CD305106818379B59BAEBE
+IV=6643BF26488FB21BCDAA7D4FABAA5BC3
+CT=A00EAFD28A95C7F39137773F28F9A0D3
+PT=FC884EEEB73B2F66C97D742A441B0463
+
+I=189
+KEY=F1D2EF3C44F61F37CFFCF753F180AADD
+IV=7B707442550BF1FA4C1B74F0DC3237FC
+CT=FC884EEEB73B2F66C97D742A441B0463
+PT=9C260AA82C6902B068495B4844507F7D
+
+I=190
+KEY=6DF4E594689F1D87A7B5AC1BB5D0D5A0
+IV=8329E8DE2980225DA61158BF467B1D79
+CT=9C260AA82C6902B068495B4844507F7D
+PT=1C12FEAA35AD2DD21DE6411C3A3BB6D5
+
+I=191
+KEY=71E61B3E5D323055BA53ED078FEB6375
+IV=EFD514D7CF3FAC49DBB5BB3505B9B18F
+CT=1C12FEAA35AD2DD21DE6411C3A3BB6D5
+PT=15F26D34E8E1037A5A2393CEA5DB396B
+
+I=192
+KEY=6414760AB5D3332FE0707EC92A305A1E
+IV=9EFC37C295552B965B29A23AC2788D8B
+CT=15F26D34E8E1037A5A2393CEA5DB396B
+PT=76F0C79955566A0A091AA46E0C59455E
+
+I=193
+KEY=12E4B193E0855925E96ADAA726691F40
+IV=5BA54E33128A7526A9130E632BE00D65
+CT=76F0C79955566A0A091AA46E0C59455E
+PT=1EA06231EBEEB995E2F94B88A4004333
+
+I=194
+KEY=0C44D3A20B6BE0B00B93912F82695C73
+IV=9B1C6FA42510E530D2282BF8C5516DCE
+CT=1EA06231EBEEB995E2F94B88A4004333
+PT=16C36348884B32AC1CB1DE2D3C158981
+
+I=195
+KEY=1A87B0EA8320D21C17224F02BE7CD5F2
+IV=F755F641EED4C828DCBECC327D93F4AF
+CT=16C36348884B32AC1CB1DE2D3C158981
+PT=6581A3FB5F61C6C1904F35E787BF552D
+
+I=196
+KEY=7F061311DC4114DD876D7AE539C380DF
+IV=5D799F356C1672707716C47DA4384C01
+CT=6581A3FB5F61C6C1904F35E787BF552D
+PT=0BA11F8EE845E03641928825B3344994
+
+I=197
+KEY=74A70C9F3404F4EBC6FFF2C08AF7C94B
+IV=89A5592031795CEAECF1C1F274813818
+CT=0BA11F8EE845E03641928825B3344994
+PT=1CF907A6C8A33C7806819EB97B854588
+
+I=198
+KEY=685E0B39FCA7C893C07E6C79F1728CC3
+IV=BBE87558AF456066B9CE3EBB8729D554
+CT=1CF907A6C8A33C7806819EB97B854588
+PT=722BB2E53CE7846F40B5EA18AF1430B0
+
+I=199
+KEY=1A75B9DCC0404CFC80CB86615E66BC73
+IV=2CC42E6DA36883482ACB5D9D92823186
+CT=722BB2E53CE7846F40B5EA18AF1430B0
+PT=E667D6A95E9C56BB56E4436CC1B69874
+
+I=200
+KEY=FC126F759EDC1A47D62FC50D9FD02407
+IV=F18DD0388BF5692B7394BAFDC4854308
+CT=E667D6A95E9C56BB56E4436CC1B69874
+PT=3C9A76798C468470EEBC5F7B915879A3
+
+I=201
+KEY=C088190C129A9E3738939A760E885DA4
+IV=8262D8603FE0F4AE8BF5795690992F1C
+CT=3C9A76798C468470EEBC5F7B915879A3
+PT=3CAFB994BDEF76370D8A5129B63BECDB
+
+I=202
+KEY=FC27A098AF75E8003519CB5FB8B3B17F
+IV=AB090F7A86CFD9A7C1BD8869BBB4D27B
+CT=3CAFB994BDEF76370D8A5129B63BECDB
+PT=50D037733D2C3242024BD322ADDF01CB
+
+I=203
+KEY=ACF797EB9259DA423752187D156CB0B4
+IV=3581D6724722C3892C712B2AA1066824
+CT=50D037733D2C3242024BD322ADDF01CB
+PT=0D7CB755305EF09692FCED530CCC1336
+
+I=204
+KEY=A18B20BEA2072AD4A5AEF52E19A0A382
+IV=9D0DAD6448895ECBE05F8DC73E014E3C
+CT=0D7CB755305EF09692FCED530CCC1336
+PT=D66389E01F44C60B26BCF3F9B39DAB55
+
+I=205
+KEY=77E8A95EBD43ECDF831206D7AA3D08D7
+IV=7BDC3CD62CD79C7E6CB8FAE104175DE4
+CT=D66389E01F44C60B26BCF3F9B39DAB55
+PT=CC9F59409D636BE5C555AC2841650CD7
+
+I=206
+KEY=BB77F01E2020873A4647AAFFEB580400
+IV=A4FBE42983B236097E40C1E244B14748
+CT=CC9F59409D636BE5C555AC2841650CD7
+PT=34804672FCEF79481269B1D254DDCAF9
+
+I=207
+KEY=8FF7B66CDCCFFE72542E1B2DBF85CEF9
+IV=700B37E771E88E5DCD9C81D6FD16B995
+CT=34804672FCEF79481269B1D254DDCAF9
+PT=62FC00FDF1F6BF44FFBEB5BED5589A64
+
+I=208
+KEY=ED0BB6912D394136AB90AE936ADD549D
+IV=F3A9954079382ACD97C3EC198522AE69
+CT=62FC00FDF1F6BF44FFBEB5BED5589A64
+PT=F7901904A02544E064400A2625121C4C
+
+I=209
+KEY=1A9BAF958D1C05D6CFD0A4B54FCF48D1
+IV=3799F5DEF76C56F8B0A69889B85760AA
+CT=F7901904A02544E064400A2625121C4C
+PT=A915D55AE8E14497F2693A55F83041F5
+
+I=210
+KEY=B38E7ACF65FD41413DB99EE0B7FF0924
+IV=5421F3F4CDD3C6F9BF38184BC61904AA
+CT=A915D55AE8E14497F2693A55F83041F5
+PT=66EA0D0968631F3BDA46921078E495C1
+
+I=211
+KEY=D56477C60D9E5E7AE7FF0CF0CF1B9CE5
+IV=3B87243EE38BD474E4CBF34A7C592CFC
+CT=66EA0D0968631F3BDA46921078E495C1
+PT=283826367D00718849A6539EE8CAD8BF
+
+I=212
+KEY=FD5C51F0709E2FF2AE595F6E27D1445A
+IV=0FB53077D2BC27C544CD400A28212291
+CT=283826367D00718849A6539EE8CAD8BF
+PT=B15EA2718FB406D457C8B96530EDC014
+
+I=213
+KEY=4C02F381FF2A2926F991E60B173C844E
+IV=8BFE654E422E9BCCE7F1357053E1130C
+CT=B15EA2718FB406D457C8B96530EDC014
+PT=44238CE0F1765C7983BF408D5ECFA2BA
+
+I=214
+KEY=08217F610E5C755F7A2EA68649F326F4
+IV=86841D597FA91F54CBAD3C57FC1FC492
+CT=44238CE0F1765C7983BF408D5ECFA2BA
+PT=BB6408099CA64F1216D204865449E967
+
+I=215
+KEY=B345776892FA3A4D6CFCA2001DBACF93
+IV=849198CEA19F4AD76013D172867A0D20
+CT=BB6408099CA64F1216D204865449E967
+PT=B7E109C6813E686ADA396DDB277AD960
+
+I=216
+KEY=04A47EAE13C45227B6C5CFDB3AC016F3
+IV=9C5E0182124701DA958CF68E1B9F8CC1
+CT=B7E109C6813E686ADA396DDB277AD960
+PT=65C77CB822CA10AE1F95B91F0A3F6436
+
+I=217
+KEY=61630216310E4289A95076C430FF72C5
+IV=2BB9026F793A64A325E02B922E3A51DD
+CT=65C77CB822CA10AE1F95B91F0A3F6436
+PT=48E9DB9FC3F883AD28A0299561444197
+
+I=218
+KEY=298AD989F2F6C12481F05F5151BB3352
+IV=6BE0B03639C858D8F2CAE00EFE8FECCA
+CT=48E9DB9FC3F883AD28A0299561444197
+PT=02B277AB327BCB5C91831BD376DC5211
+
+I=219
+KEY=2B38AE22C08D0A781073448227676143
+IV=ADC033E3EEC3705031D2FB24205823A2
+CT=02B277AB327BCB5C91831BD376DC5211
+PT=FE288D6703CF6AB1635483305A82F192
+
+I=220
+KEY=D5102345C34260C97327C7B27DE590D1
+IV=F637C38CB5DF86458225143E157B9415
+CT=FE288D6703CF6AB1635483305A82F192
+PT=B07BF02F795D13D972D5D6E556E8BA37
+
+I=221
+KEY=656BD36ABA1F731001F211572B0D2AE6
+IV=824B7BBB3A339BF045C3CFEA9FD842B9
+CT=B07BF02F795D13D972D5D6E556E8BA37
+PT=D4661C2E102C6644724DA54BE291215D
+
+I=222
+KEY=B10DCF44AA33155473BFB41CC99C0BBB
+IV=21FA242B2B9FFF0C7DC6B712A38A333B
+CT=D4661C2E102C6644724DA54BE291215D
+PT=F7EDEE448559A6ACD68815B6EEAF6E38
+
+I=223
+KEY=46E021002F6AB3F8A537A1AA27336583
+IV=390906ECE51C92800D620E1CD1FD3574
+CT=F7EDEE448559A6ACD68815B6EEAF6E38
+PT=07257C91424F65E6752470A6960DF6D9
+
+I=224
+KEY=41C55D916D25D61ED013D10CB13E935A
+IV=918A010EC2B106DE32A220315999DF7D
+CT=07257C91424F65E6752470A6960DF6D9
+PT=CCB4F3FCFFDEE9E93DD3AB4CC2DB870E
+
+I=225
+KEY=8D71AE6D92FB3FF7EDC07A4073E51454
+IV=7CF6B4948C4E04ED235F2CC96B0A6B49
+CT=CCB4F3FCFFDEE9E93DD3AB4CC2DB870E
+PT=C455220E8C8847FF2592074A53104105
+
+I=226
+KEY=49248C631E737808C8527D0A20F55551
+IV=4839E74C868786D0A109603CF98F1100
+CT=C455220E8C8847FF2592074A53104105
+PT=B4D0F5B4C15D7AD556ED4964A94C898F
+
+I=227
+KEY=FDF479D7DF2E02DD9EBF346E89B9DCDE
+IV=5C6D9649E47FAA8A2DCAFB317B6BC0EA
+CT=B4D0F5B4C15D7AD556ED4964A94C898F
+PT=B515D2904555793DDC142618DCFF8464
+
+I=228
+KEY=48E1AB479A7B7BE042AB1276554658BA
+IV=E3573B4137C13BBA6CDD10D71042B8F6
+CT=B515D2904555793DDC142618DCFF8464
+PT=2C272D6589E2E6EE09067882795E9FB9
+
+I=229
+KEY=64C6862213999D0E4BAD6AF42C18C703
+IV=08E335104FC5D18E2C11EF34B805F060
+CT=2C272D6589E2E6EE09067882795E9FB9
+PT=B38E39322245C4A2E170EBF36D764AD5
+
+I=230
+KEY=D748BF1031DC59ACAADD8107416E8DD6
+IV=E134D0DEA38A23983766DA18DADA70E0
+CT=B38E39322245C4A2E170EBF36D764AD5
+PT=E7556255602B48D7CAC710A004FFFD2E
+
+I=231
+KEY=301DDD4551F7117B601A91A7459170F8
+IV=301C2808833418F45D5F97FB09A99504
+CT=E7556255602B48D7CAC710A004FFFD2E
+PT=D4356D51B1C486AAC8BCF2F65312758C
+
+I=232
+KEY=E428B014E03397D1A8A6635116830574
+IV=264D556FA9A9D73510F562BBF983A4F7
+CT=D4356D51B1C486AAC8BCF2F65312758C
+PT=B4D003D6C542B576A3EAEC8F1B017F5B
+
+I=233
+KEY=50F8B3C2257122A70B4C8FDE0D827A2F
+IV=8821647AD3E9E529909E60D0F75DA400
+CT=B4D003D6C542B576A3EAEC8F1B017F5B
+PT=10056819F314FF21114BE6209AB5508C
+
+I=234
+KEY=40FDDBDBD665DD861A0769FE97372AA3
+IV=CBD574F4DB1EFEE4E2EC9485D1192E04
+CT=10056819F314FF21114BE6209AB5508C
+PT=6E7AA061FE85B6F8972CB0E793BE0CB0
+
+I=235
+KEY=2E877BBA28E06B7E8D2BD91904892613
+IV=4F98EE1501681EC0E7834FE941DF6C6B
+CT=6E7AA061FE85B6F8972CB0E793BE0CB0
+PT=45E0C0014219D77686E82E74E60608CA
+
+I=236
+KEY=6B67BBBB6AF9BC080BC3F76DE28F2ED9
+IV=1D34CAB2FF836A7E6568823784519170
+CT=45E0C0014219D77686E82E74E60608CA
+PT=ACF686F9D6723EAFDBFE512AB3A8C6B1
+
+I=237
+KEY=C7913D42BC8B82A7D03DA6475127E868
+IV=BEA74B4435F9F79D39B8CCE1F090D4B8
+CT=ACF686F9D6723EAFDBFE512AB3A8C6B1
+PT=F11FE34D158D40DEA10033BCE0253F30
+
+I=238
+KEY=368EDE0FA906C279713D95FBB102D758
+IV=DF30EE5D8CA298BE630DDE4B6D8AD7AA
+CT=F11FE34D158D40DEA10033BCE0253F30
+PT=4E970ACAB8B19C942C85FAA7825C5E67
+
+I=239
+KEY=7819D4C511B75EED5DB86F5C335E893F
+IV=DC3CCC928C02710EE91391032A3B557D
+CT=4E970ACAB8B19C942C85FAA7825C5E67
+PT=0FF6C292507CF135036E04A391210466
+
+I=240
+KEY=77EF165741CBAFD85ED66BFFA27F8D59
+IV=7CC57A486E05E36F852278450C03D39F
+CT=0FF6C292507CF135036E04A391210466
+PT=BBEF94C8179E7A124492A252507D58E7
+
+I=241
+KEY=CC00829F5655D5CA1A44C9ADF202D5BE
+IV=BBB92F65197F8D6B388191E78E90A858
+CT=BBEF94C8179E7A124492A252507D58E7
+PT=BAF11150DD418ED7C28072A718815954
+
+I=242
+KEY=76F193CF8B145B1DD8C4BB0AEA838CEA
+IV=99DA5A29F934BE23EB74B6DE4E8CC740
+CT=BAF11150DD418ED7C28072A718815954
+PT=A935099B91A35655C850939D2FED1569
+
+I=243
+KEY=DFC49A541AB70D4810942897C56E9983
+IV=92401B7E92A49FA5A6905E51E49D51C2
+CT=A935099B91A35655C850939D2FED1569
+PT=F60E1B5D10CDA17FC762798B86B8708D
+
+I=244
+KEY=29CA81090A7AAC37D7F6511C43D6E90E
+IV=C2A57521674EB0FB3E46DE2CC1DCF419
+CT=F60E1B5D10CDA17FC762798B86B8708D
+PT=0B976079B61F46E7F3CCCD17E23D872F
+
+I=245
+KEY=225DE170BC65EAD0243A9C0BA1EB6E21
+IV=66970AE807FED1E3581496C9FBE5FF50
+CT=0B976079B61F46E7F3CCCD17E23D872F
+PT=FB44F0094A5FC03BD0A27391E58D0AA3
+
+I=246
+KEY=D9191179F63A2AEBF498EF9A44666482
+IV=ED7B2ED1AFF7DB9B514D6E4DFAEA484B
+CT=FB44F0094A5FC03BD0A27391E58D0AA3
+PT=41A534A69AD25FEB39BB9F754F15D8FE
+
+I=247
+KEY=98BC25DF6CE87500CD2370EF0B73BC7C
+IV=B7E8C7F08BCE1CF1CC2568E18C18C92B
+CT=41A534A69AD25FEB39BB9F754F15D8FE
+PT=022B28D4F7355E14F99F654B6C35BC16
+
+I=248
+KEY=9A970D0B9BDD2B1434BC15A46746006A
+IV=F2EF32464FC7E5F3D397C259CB963B7F
+CT=022B28D4F7355E14F99F654B6C35BC16
+PT=28F18EA03ADEB36C40FD8FBC590EC6C8
+
+I=249
+KEY=B26683ABA103987874419A183E48C6A2
+IV=687E822CCFC5800E88E59ED7DEC1409D
+CT=28F18EA03ADEB36C40FD8FBC590EC6C8
+PT=661F9AEA300100333D64FCDD1212C663
+
+I=250
+KEY=D47919419102984B492566C52C5A00C1
+IV=3922BB08EE1B4CC75881D1D6F66B8EE0
+CT=661F9AEA300100333D64FCDD1212C663
+PT=11C4D360F585EDF544D5479AE1ABDBE6
+
+I=251
+KEY=C5BDCA21648775BE0DF0215FCDF1DB27
+IV=9B7C0D7D0EA8CAD77B331F2E0CA1E639
+CT=11C4D360F585EDF544D5479AE1ABDBE6
+PT=2E4695733B01CC78993E6EB464784223
+
+I=252
+KEY=EBFB5F525F86B9C694CE4FEBA9899904
+IV=A2BF273F12FE1F4B2F56A86CAFD9C5BF
+CT=2E4695733B01CC78993E6EB464784223
+PT=1CC514E9F4B13FFEF3B076DAC8C62877
+
+I=253
+KEY=F73E4BBBAB378638677E3931614FB173
+IV=1D4960EBE667AC5DE5ED767183838846
+CT=1CC514E9F4B13FFEF3B076DAC8C62877
+PT=3B1A7D179DDED66A37F3053B8B231EEA
+
+I=254
+KEY=CC2436AC36E95052508D3C0AEA6CAF99
+IV=974643FDFDB695A44B7EF8676A2B87DD
+CT=3B1A7D179DDED66A37F3053B8B231EEA
+PT=620A4E7A25E8D05779C0FB8CEBA55A74
+
+I=255
+KEY=AE2E78D613018005294DC78601C9F5ED
+IV=C9A1D92DB7D553DCAEB3BB81B489257A
+CT=620A4E7A25E8D05779C0FB8CEBA55A74
+PT=93508503278ECECE65D67B5F50962C4E
+
+I=256
+KEY=3D7EFDD5348F4ECB4C9BBCD9515FD9A3
+IV=108E736F1DCD178A8648F6AA6D527732
+CT=93508503278ECECE65D67B5F50962C4E
+PT=EA9E953D8B62FFAFF9FAFB97F614D65C
+
+I=257
+KEY=D7E068E8BFEDB164B561474EA74B0FFF
+IV=B893A94302C0DAFB19D7B6656085DCA9
+CT=EA9E953D8B62FFAFF9FAFB97F614D65C
+PT=1452ED26E774029EF30D272F8548C2F8
+
+I=258
+KEY=C3B285CE5899B3FA466C60612203CD07
+IV=668FF6719E5A29A99876227EEDE5818F
+CT=1452ED26E774029EF30D272F8548C2F8
+PT=4083167E5ED1A1A449C1825B84F321E1
+
+I=259
+KEY=833193B00648125E0FADE23AA6F0ECE6
+IV=9F6375A022543AB8303368A235813F02
+CT=4083167E5ED1A1A449C1825B84F321E1
+PT=9206639D076685FD2078F9B984B7A03F
+
+I=260
+KEY=1137F02D012E97A32FD51B8322474CD9
+IV=1B95128E90B110AED9D543D2A996271F
+CT=9206639D076685FD2078F9B984B7A03F
+PT=AAA3F2BD0126DFD5007DD2835CCB0109
+
+I=261
+KEY=BB940290000848762FA8C9007E8C4DD0
+IV=BB2E26A9CDEF9D1B2940EFFBA1971A5D
+CT=AAA3F2BD0126DFD5007DD2835CCB0109
+PT=B58BB3761519C1726D75AE96313FB7DE
+
+I=262
+KEY=0E1FB1E61511890442DD67964FB3FA0E
+IV=68D3EC37EE43E3F24072F69F2DFA768D
+CT=B58BB3761519C1726D75AE96313FB7DE
+PT=4558CD47C012B7293396D7EDFE3CEA85
+
+I=263
+KEY=4B477CA1D5033E2D714BB07BB18F108B
+IV=F7E107DBF4DDBF7974B699536A4E2803
+CT=4558CD47C012B7293396D7EDFE3CEA85
+PT=6F43B6B28AEF5DD1B66279ACAAB9A589
+
+I=264
+KEY=2404CA135FEC63FCC729C9D71B36B502
+IV=B3E6DA8DE5DDF7ED6F832D1306A1C04A
+CT=6F43B6B28AEF5DD1B66279ACAAB9A589
+PT=1BA743E148BC164C4C8324D665B5A3BD
+
+I=265
+KEY=3FA389F2175075B08BAAED017E8316BF
+IV=8BBBB56B39893C8F286561EF6E47E66A
+CT=1BA743E148BC164C4C8324D665B5A3BD
+PT=49A40365092DD1360D916AAEAFD03FC1
+
+I=266
+KEY=76078A971E7DA486863B87AFD153297E
+IV=48BA08703A306F772E78F660173A26B3
+CT=49A40365092DD1360D916AAEAFD03FC1
+PT=DF7DEB5968D683AAA274B0D5D3F9AA03
+
+I=267
+KEY=A97A61CE76AB272C244F377A02AA837D
+IV=0C7832F9CDF65DADA7FA809B8DE709C3
+CT=DF7DEB5968D683AAA274B0D5D3F9AA03
+PT=69689E97E9B166DA53E25BDFBCAF4A97
+
+I=268
+KEY=C012FF599F1A41F677AD6CA5BE05C9EA
+IV=05BC03F59CD8C5FAE4A7240E6168CF41
+CT=69689E97E9B166DA53E25BDFBCAF4A97
+PT=5F87DC71EF2918F75A94E43007FF50E6
+
+I=269
+KEY=9F952328703359012D398895B9FA990C
+IV=4233E654802B55155E158B650B64718E
+CT=5F87DC71EF2918F75A94E43007FF50E6
+PT=4F170790775A6A147E99D251C401969A
+
+I=270
+KEY=D08224B80769331553A05AC47DFB0F96
+IV=4AEAE53003D5085F5963CC36C4589941
+CT=4F170790775A6A147E99D251C401969A
+PT=E566D46360EF38E5CFF0C2E7E7E0D679
+
+I=271
+KEY=35E4F0DB67860BF09C5098239A1BD9EF
+IV=F6CBFF51F6E59B7AAA9EB1261707429A
+CT=E566D46360EF38E5CFF0C2E7E7E0D679
+PT=F7189C4B9E1048ED66D9B7CCD089C5F9
+
+I=272
+KEY=C2FC6C90F996431DFA892FEF4A921C16
+IV=0A05A4BFBBCC8B3E218C123A95FFF475
+CT=F7189C4B9E1048ED66D9B7CCD089C5F9
+PT=68FB0909789DBFA672BEEF5DF0017B63
+
+I=273
+KEY=AA076599810BFCBB8837C0B2BA936775
+IV=DF1A3AF147E72C2CEAE5D8713D52F572
+CT=68FB0909789DBFA672BEEF5DF0017B63
+PT=AF2784590089186BED3A48ADC1B68562
+
+I=274
+KEY=0520E1C08182E4D0650D881F7B25E217
+IV=BFDC5ECF596F5F3CFFEAAF4B961209FA
+CT=AF2784590089186BED3A48ADC1B68562
+PT=E8C29D3C129AB8FA797EFDCE4CE4D4F2
+
+I=275
+KEY=EDE27CFC93185C2A1C7375D137C136E5
+IV=49195E71516D5117C26814F98FD94C31
+CT=E8C29D3C129AB8FA797EFDCE4CE4D4F2
+PT=6ACF2AE12C38DB520F49E6C90D4B8F03
+
+I=276
+KEY=872D561DBF208778133A93183A8AB9E6
+IV=E4FA7788D6E7AFBD08884BFCFA74D30C
+CT=6ACF2AE12C38DB520F49E6C90D4B8F03
+PT=78FEA3B57D6176C44CE753FB01416CA6
+
+I=277
+KEY=FFD3F5A8C241F1BC5FDDC0E33BCBD540
+IV=08E333F43615229D95E7C425A04EA2B7
+CT=78FEA3B57D6176C44CE753FB01416CA6
+PT=5030D7131ABBD7AC323BA31B602B776E
+
+I=278
+KEY=AFE322BBD8FA26106DE663F85BE0A22E
+IV=64BDE35106D9A66A4216EA20F6C52D06
+CT=5030D7131ABBD7AC323BA31B602B776E
+PT=14B32E8BD3BD9D82613E32536E6A9F91
+
+I=279
+KEY=BB500C300B47BB920CD851AB358A3DBF
+IV=8FB9E6BDCD50610E97CF731216CFE698
+CT=14B32E8BD3BD9D82613E32536E6A9F91
+PT=1F22542AFCE63AA92CCDAF45F8DAEEF0
+
+I=280
+KEY=A472581AF7A1813B2015FEEECD50D34F
+IV=E18B3C5EDA8CDA9E94A376CEEF687D9F
+CT=1F22542AFCE63AA92CCDAF45F8DAEEF0
+PT=FC986510E3ED40994D1C33201D0EDB27
+
+I=281
+KEY=58EA3D0A144CC1A26D09CDCED05E0868
+IV=D1828C9DDB263064AD259A2360B3DFBA
+CT=FC986510E3ED40994D1C33201D0EDB27
+PT=06C1CE557C9AC5D40560CF2D40DCC47C
+
+I=282
+KEY=5E2BF35F68D60476686902E39082CC14
+IV=3454FD0698CC8CD949970509C23E50F6
+CT=06C1CE557C9AC5D40560CF2D40DCC47C
+PT=4287FA420FD9AFCAB7E290273BDF4054
+
+I=283
+KEY=1CAC091D670FABBCDF8B92C4AB5D8C40
+IV=C2F0C044A975ADBD20DE56858A074886
+CT=4287FA420FD9AFCAB7E290273BDF4054
+PT=447AFDD3ACF0DEEB0385799789FBAFF0
+
+I=284
+KEY=58D6F4CECBFF7557DC0EEB5322A623B0
+IV=299C337821B0779A7ADC3A04316A6373
+CT=447AFDD3ACF0DEEB0385799789FBAFF0
+PT=BA0BBC980827E87EEA51E66C92C96B31
+
+I=285
+KEY=E2DD4856C3D89D29365F0D3FB06F4881
+IV=2368291AD179C3C143E636898EB3E104
+CT=BA0BBC980827E87EEA51E66C92C96B31
+PT=77A6131415B251049423FFFB1F3A8A3A
+
+I=286
+KEY=957B5B42D66ACC2DA27CF2C4AF55C2BB
+IV=14300EA81B57E102AEDD97CCD466E18A
+CT=77A6131415B251049423FFFB1F3A8A3A
+PT=A7AEC0CC599D56347A72D934DDAC7899
+
+I=287
+KEY=32D59B8E8FF79A19D80E2BF072F9BA22
+IV=FD62415C90DACCD22EC364877DB0CB24
+CT=A7AEC0CC599D56347A72D934DDAC7899
+PT=1B1100FCB9F85D8CCFDEC5865083B44D
+
+I=288
+KEY=29C49B72360FC79517D0EE76227A0E6F
+IV=6CB24892D26E43E63819C372D5EB4F6D
+CT=1B1100FCB9F85D8CCFDEC5865083B44D
+PT=33E9BBD018604F301C2543878FCCCA5C
+
+I=289
+KEY=1A2D20A22E6F88A50BF5ADF1ADB6C433
+IV=50D84A03998B897D1AE217FEA9A955C4
+CT=33E9BBD018604F301C2543878FCCCA5C
+PT=07163D652DB035C091830042D6047DF3
+
+I=290
+KEY=1D3B1DC703DFBD659A76ADB37BB2B9C0
+IV=092DF26C855F07690836203E3E1790D0
+CT=07163D652DB035C091830042D6047DF3
+PT=AD6647AF8EFCD4F3B2ECDB4D6FFFC1EB
+
+I=291
+KEY=B05D5A688D236996289A76FE144D782B
+IV=68634C941957E3F58F71BE37D7C5C78B
+CT=AD6647AF8EFCD4F3B2ECDB4D6FFFC1EB
+PT=D2B51122154D10F67D2C07BD75D5E8E2
+
+I=292
+KEY=62E84B4A986E796055B67143619890C9
+IV=3C85044F6438FAA021BB7985A63A959D
+CT=D2B51122154D10F67D2C07BD75D5E8E2
+PT=4131E9296FECD2DF35EDFBF0CBD0E54B
+
+I=293
+KEY=23D9A263F782ABBF605B8AB3AA487582
+IV=46D47F3F12B6ADD5580CE8CE7C7359CD
+CT=4131E9296FECD2DF35EDFBF0CBD0E54B
+PT=5AEA3E73A6EC0D9D683A3526AC1C0E58
+
+I=294
+KEY=79339C10516EA6220861BF9506547BDA
+IV=D3C58B190FDA0838C770C2185C553D97
+CT=5AEA3E73A6EC0D9D683A3526AC1C0E58
+PT=A21B17CB4588C30CAD6DF25A5E83E273
+
+I=295
+KEY=DB288BDB14E6652EA50C4DCF58D799A9
+IV=870E7F0E3109712E84C58BEC0E7032F6
+CT=A21B17CB4588C30CAD6DF25A5E83E273
+PT=0021FF3BB8336E607B8DE10117005230
+
+I=296
+KEY=DB0974E0ACD50B4EDE81ACCE4FD7CB99
+IV=2FC82B298A60FC40DA3EFD4E800DB063
+CT=0021FF3BB8336E607B8DE10117005230
+PT=2EFA32680ECD84891B447393F7C1AC88
+
+I=297
+KEY=F5F34688A2188FC7C5C5DF5DB8166711
+IV=E1B86C9FC466B72BE40F65973FC41FC4
+CT=2EFA32680ECD84891B447393F7C1AC88
+PT=722117C1EE83FBA840EFEE86A930579F
+
+I=298
+KEY=87D251494C9B746F852A31DB1126308E
+IV=48E347A705B6E322153BFE567931346F
+CT=722117C1EE83FBA840EFEE86A930579F
+PT=A684344231EC4C03726A0DC20EADA36D
+
+I=299
+KEY=2156650B7D77386CF7403C191F8B93E3
+IV=4CD618E5F959FC4C66602263F6C5C652
+CT=A684344231EC4C03726A0DC20EADA36D
+PT=F40BFBEAC1C1BD1621FBAE1B605BD092
+
+I=300
+KEY=D55D9EE1BCB6857AD6BB92027FD04371
+IV=5A41E8952E6B1C551C4691DE9C0A4B6D
+CT=F40BFBEAC1C1BD1621FBAE1B605BD092
+PT=6ECDBFB3947C7E81C7BD4BE93B603728
+
+I=301
+KEY=BB90215228CAFBFB1106D9EB44B07459
+IV=52E2726B0855F993E1075077B3AB1E77
+CT=6ECDBFB3947C7E81C7BD4BE93B603728
+PT=71E051375A3B974FE523DA47862E24AE
+
+I=302
+KEY=CA70706572F16CB4F42503ACC29E50F7
+IV=76B6637161FBE4760FCE90E9868B441A
+CT=71E051375A3B974FE523DA47862E24AE
+PT=CC6CFBCF9A62A3AE55F6B040673B25B3
+
+I=303
+KEY=061C8BAAE893CF1AA1D3B3ECA5A57544
+IV=5563B0C2350A4ED76EE0C322480884FB
+CT=CC6CFBCF9A62A3AE55F6B040673B25B3
+PT=DA71B26C4EE3FB1FD413FD0757B379E6
+
+I=304
+KEY=DC6D39C6A670340575C04EEBF2160CA2
+IV=45C1C5DAF8DE9170C01E554DD36C564E
+CT=DA71B26C4EE3FB1FD413FD0757B379E6
+PT=BCD4BC394FFB46207EF0A8EC9883BD55
+
+I=305
+KEY=60B985FFE98B72250B30E6076A95B1F7
+IV=38E5B69E6D82A760BFD65CBAACC56F8A
+CT=BCD4BC394FFB46207EF0A8EC9883BD55
+PT=FD997E7A7B77E5DF637182399779AF75
+
+I=306
+KEY=9D20FB8592FC97FA6841643EFDEC1E82
+IV=8EB39B261910419E43B178DCD6803572
+CT=FD997E7A7B77E5DF637182399779AF75
+PT=71749C51136457B604CD8B4C193928A8
+
+I=307
+KEY=EC5467D48198C04C6C8CEF72E4D5362A
+IV=6DFA447305215066A0B5671E5AB80951
+CT=71749C51136457B604CD8B4C193928A8
+PT=DF48D76E54B4264304B0EC036DFDADDE
+
+I=308
+KEY=331CB0BAD52CE60F683C037189289BF4
+IV=8C2B316ECA96DB57322853E07BE47AB3
+CT=DF48D76E54B4264304B0EC036DFDADDE
+PT=5E2BD374B9856C573A4DEBF1B8F453EC
+
+I=309
+KEY=6D3763CE6CA98A585271E88031DCC818
+IV=E541AC59CFDBEA97D1AE5221F849838E
+CT=5E2BD374B9856C573A4DEBF1B8F453EC
+PT=D7F97B76A8D3076D343A22459EC4765D
+
+I=310
+KEY=BACE18B8C47A8D35664BCAC5AF18BE45
+IV=B359889A22B9502571E4817C47BC5348
+CT=D7F97B76A8D3076D343A22459EC4765D
+PT=E24F05EEE812BD3389AC0AAC4172F5C6
+
+I=311
+KEY=58811D562C683006EFE7C069EE6A4B83
+IV=33F8D881A783051987103096B6C734C3
+CT=E24F05EEE812BD3389AC0AAC4172F5C6
+PT=A2AB44CC9C41A8748201DA6F9429AB39
+
+I=312
+KEY=FA2A599AB02998726DE61A067A43E0BA
+IV=2028704442AE252BCF1D081C5EE2D80B
+CT=A2AB44CC9C41A8748201DA6F9429AB39
+PT=E8FA100D1D28186196BAF990A80109AA
+
+I=313
+KEY=12D04997AD018013FB5CE396D242E910
+IV=6384E3612062BC6850C94C3B14934A6F
+CT=E8FA100D1D28186196BAF990A80109AA
+PT=683AEF47A8990E2F8AAD8813789069B1
+
+I=314
+KEY=7AEAA6D005988E3C71F16B85AAD280A1
+IV=12F78728F3B0EFAC7D304257E47ED5C8
+CT=683AEF47A8990E2F8AAD8813789069B1
+PT=F3121C95A5BACDEAEFA87C4EE40B6C6D
+
+I=315
+KEY=89F8BA45A02243D69E5917CB4ED9ECCC
+IV=FE654BC69677E13383C4206BFB7896A6
+CT=F3121C95A5BACDEAEFA87C4EE40B6C6D
+PT=AE9701378E128847A2669B516795D586
+
+I=316
+KEY=276FBB722E30CB913C3F8C9A294C394A
+IV=E79D5C468BCBA36A79B74F32F28FA635
+CT=AE9701378E128847A2669B516795D586
+PT=D97D988A40C5B323794F160FE8639262
+
+I=317
+KEY=FE1223F86EF578B245709A95C12FAB28
+IV=4F3055450C627AD4712E042666AC0812
+CT=D97D988A40C5B323794F160FE8639262
+PT=32381BA55D5C0C91D683D57593772496
+
+I=318
+KEY=CC2A385D33A9742393F34FE052588FBE
+IV=172165B468B83B62B41A2B4310461193
+CT=32381BA55D5C0C91D683D57593772496
+PT=4D555F31A60F1007B96FBB458B06A619
+
+I=319
+KEY=817F676C95A664242A9CF4A5D95E29A7
+IV=5D5EEBEA67DCD5F7851619F1BAA6414E
+CT=4D555F31A60F1007B96FBB458B06A619
+PT=23D1AC0F18C20FCE7E5CC4619F8376D5
+
+I=320
+KEY=A2AECB638D646BEA54C030C446DD5F72
+IV=54154B82B5820D5892DABD15B403345D
+CT=23D1AC0F18C20FCE7E5CC4619F8376D5
+PT=2E55905A38F818CC04D8A792D2007332
+
+I=321
+KEY=8CFB5B39B59C73265018975694DD2C40
+IV=AC47D7619A587DC8213B749918FCFEA8
+CT=2E55905A38F818CC04D8A792D2007332
+PT=010F3396885F8F6BF15170B8E6D221BD
+
+I=322
+KEY=8DF468AF3DC3FC4DA149E7EE720F0DFD
+IV=6CE249D2E89C61ACD029AA3C122427D1
+CT=010F3396885F8F6BF15170B8E6D221BD
+PT=4DB3972D9851B8A4B3150A43210D36F0
+
+I=323
+KEY=C047FF82A59244E9125CEDAD53023B0D
+IV=07A578889914E113C1C4DE01DC4B1DE4
+CT=4DB3972D9851B8A4B3150A43210D36F0
+PT=84F64CFFD705E82704FF3DA4FC074B34
+
+I=324
+KEY=44B1B37D7297ACCE16A3D009AF057039
+IV=CE73ADCD7BCF1807C084276EDD765256
+CT=84F64CFFD705E82704FF3DA4FC074B34
+PT=5964DF8E8D656846EE574635787F7B18
+
+I=325
+KEY=1DD56CF3FFF2C488F8F4963CD77A0B21
+IV=679903574013011E62CC5798B9633607
+CT=5964DF8E8D656846EE574635787F7B18
+PT=E28E7E3AA93802BEEFE258F38F5D2E5C
+
+I=326
+KEY=FF5B12C956CAC6361716CECF5827257D
+IV=678D8583A022C60BCE2C227627A548B2
+CT=E28E7E3AA93802BEEFE258F38F5D2E5C
+PT=D297684A7C50765C413BFA37B5E1E256
+
+I=327
+KEY=2DCC7A832A9AB06A562D34F8EDC6C72B
+IV=4EF9AACC21733B65B4DD0B1F105D4037
+CT=D297684A7C50765C413BFA37B5E1E256
+PT=9EF5F9A2B14B090A201DE74E4CF714C8
+
+I=328
+KEY=B33983219BD1B9607630D3B6A131D3E3
+IV=5CC41FCC9EC19619BA06D10BBC6E1F5F
+CT=9EF5F9A2B14B090A201DE74E4CF714C8
+PT=81EF000CF6CA737E0F449927E66F6392
+
+I=329
+KEY=32D6832D6D1BCA1E79744A91475EB071
+IV=6DE60CE2986CF80C5D588FA1F9A8C3A0
+CT=81EF000CF6CA737E0F449927E66F6392
+PT=3BE177EE9F8F7BE3BCE0FAA70C0A5025
+
+I=330
+KEY=0937F4C3F294B1FDC594B0364B54E054
+IV=BE2F86A52BEED4497790D6134CF0D64E
+CT=3BE177EE9F8F7BE3BCE0FAA70C0A5025
+PT=DD313134DB126529F349808B3E766795
+
+I=331
+KEY=D406C5F72986D4D436DD30BD752287C1
+IV=A89E52478FDEF91AF151097CED84579C
+CT=DD313134DB126529F349808B3E766795
+PT=330203EA36484C8E091F00CD2255E599
+
+I=332
+KEY=E704C61D1FCE985A3FC2307057776258
+IV=1AEF7BA63A3E3B6D2EB8EB1980D3E581
+CT=330203EA36484C8E091F00CD2255E599
+PT=E28A47CDB7DB0351006C1D9FB227FCEF
+
+I=333
+KEY=058E81D0A8159B0B3FAE2DEFE5509EB7
+IV=F67C7FCF8C5AA1574A165D8CBE694BF4
+CT=E28A47CDB7DB0351006C1D9FB227FCEF
+PT=ACF869797690853BE142BB7BAC735FC8
+
+I=334
+KEY=A976E8A9DE851E30DEEC96944923C17F
+IV=636F181C4735E700897928BFC60A43EB
+CT=ACF869797690853BE142BB7BAC735FC8
+PT=60FF9BF36809DAEB94F823FC6458B26A
+
+I=335
+KEY=C989735AB68CC4DB4A14B5682D7B7315
+IV=0829C0EE6B170C490C7A73401761CEAA
+CT=60FF9BF36809DAEB94F823FC6458B26A
+PT=17630CBEAB904F7996301515F24A1F27
+
+I=336
+KEY=DEEA7FE41D1C8BA2DC24A07DDF316C32
+IV=A4E0624D86F1098D2DD4D0408897ACED
+CT=17630CBEAB904F7996301515F24A1F27
+PT=A1E35C3E2FA1B1DB11DB96E7DD58AB37
+
+I=337
+KEY=7F0923DA32BD3A79CDFF369A0269C705
+IV=D3639A296FF168ED773785CFCACD1015
+CT=A1E35C3E2FA1B1DB11DB96E7DD58AB37
+PT=14F5408460708A69A22A2023B01969CE
+
+I=338
+KEY=6BFC635E52CDB0106FD516B9B270AECB
+IV=37CD0428A0C08CC6AABAAA05D8830557
+CT=14F5408460708A69A22A2023B01969CE
+PT=516991CA6530D20AB121394F51288880
+
+I=339
+KEY=3A95F29437FD621ADEF42FF6E358264B
+IV=FB52F5A95F2E3665D44F0AEACB88B108
+CT=516991CA6530D20AB121394F51288880
+PT=FB0C32B66729736F8E5EC8C92D80FDC5
+
+I=340
+KEY=C199C02250D4117550AAE73FCED8DB8E
+IV=403B43C740215D94E8FBAE22846D3B0A
+CT=FB0C32B66729736F8E5EC8C92D80FDC5
+PT=C243054D022E7E9EFC21F965C71D63EB
+
+I=341
+KEY=03DAC56F52FA6FEBAC8B1E5A09C5B865
+IV=663796B211E7F6E05B4A107B16A904B0
+CT=C243054D022E7E9EFC21F965C71D63EB
+PT=6CA56F6792355B2A7A60A4467A85F71E
+
+I=342
+KEY=6F7FAA08C0CF34C1D6EBBA1C73404F7B
+IV=A23B73DF1477EC98202135164C6EF1AB
+CT=6CA56F6792355B2A7A60A4467A85F71E
+PT=BC590C8B427B013F873B2F5F8D66D5D1
+
+I=343
+KEY=D326A68382B435FE51D09543FE269AAA
+IV=E84DF462C62D594AAD94C33C446E18FC
+CT=BC590C8B427B013F873B2F5F8D66D5D1
+PT=D37CAA9BEA300FF6219349DBA25DA0A6
+
+I=344
+KEY=005A0C1868843A087043DC985C7B3A0C
+IV=9AAD322884EBE93D0FA084E144600174
+CT=D37CAA9BEA300FF6219349DBA25DA0A6
+PT=AE50C328AFFC39A103C767C1FD337449
+
+I=345
+KEY=AE0ACF30C77803A97384BB59A1484E45
+IV=9CEE91362FB0D50ABCEB58EF49EC3614
+CT=AE50C328AFFC39A103C767C1FD337449
+PT=882939453C6E156CD023B468EDD16C95
+
+I=346
+KEY=2623F675FB1616C5A3A70F314C9922D0
+IV=5626126CC424BF26D92C822442E4221E
+CT=882939453C6E156CD023B468EDD16C95
+PT=B9A97FE0DEF66604F6CE928AAB532EC2
+
+I=347
+KEY=9F8A899525E070C155699DBBE7CA0C12
+IV=E5BB374C14E36FD0C2D5F9191C967EC7
+CT=B9A97FE0DEF66604F6CE928AAB532EC2
+PT=6ED0FF2FE8DA900A33AE20F7C1C2E457
+
+I=348
+KEY=F15A76BACD3AE0CB66C7BD4C2608E845
+IV=4493B9F0FF63D392273302B6932C8F77
+CT=6ED0FF2FE8DA900A33AE20F7C1C2E457
+PT=B7583A56BED55067A520B4F5E5C1528F
+
+I=349
+KEY=46024CEC73EFB0ACC3E709B9C3C9BACA
+IV=12E2BFD3EAB69E5132E3CDF8BAFBD45E
+CT=B7583A56BED55067A520B4F5E5C1528F
+PT=28874485575E292B0C83E1B568019BF0
+
+I=350
+KEY=6E85086924B19987CF64E80CABC8213A
+IV=3CEFDC726C919CA265CD6C28A05DE542
+CT=28874485575E292B0C83E1B568019BF0
+PT=A35D16BBB96BF3F9E06D96EDA9BB44BB
+
+I=351
+KEY=CDD81ED29DDA6A7E2F097EE102736581
+IV=4AE79901700F018D1E5D95A9FAD762F2
+CT=A35D16BBB96BF3F9E06D96EDA9BB44BB
+PT=367E6880D369D482E7E64CFCD1BCC870
+
+I=352
+KEY=FBA676524EB3BEFCC8EF321DD3CFADF1
+IV=52EEDB058A8E1FE7C651D484F86F941F
+CT=367E6880D369D482E7E64CFCD1BCC870
+PT=32B33E97C94953392A738A964DB121FC
+
+I=353
+KEY=C91548C587FAEDC5E29CB88B9E7E8C0D
+IV=B3704291187E9D55901DD237EC1E2F24
+CT=32B33E97C94953392A738A964DB121FC
+PT=965A9A0C0287AB8535436E95CC9BFB99
+
+I=354
+KEY=5F4FD2C9857D4640D7DFD61E52E57794
+IV=B3878FC256FA4F9ED0BA05FF51C0CE2A
+CT=965A9A0C0287AB8535436E95CC9BFB99
+PT=367A5C93099ACF72353DAC320A3B766E
+
+I=355
+KEY=69358E5A8CE78932E2E27A2C58DE01FA
+IV=774EA78AECAF5A1D7CC1785DE91CAB01
+CT=367A5C93099ACF72353DAC320A3B766E
+PT=116EDEB1D0E6F8D1BB58AF648429B792
+
+I=356
+KEY=785B50EB5C0171E359BAD548DCF7B668
+IV=FB1EC4218C5F733A54DEA7F753F45D68
+CT=116EDEB1D0E6F8D1BB58AF648429B792
+PT=EF3C679822E3A906F380CD07EBE65F09
+
+I=357
+KEY=976737737EE2D8E5AA3A184F3711E961
+IV=8BBE09AFE41C5A78EBA0524212AC570F
+CT=EF3C679822E3A906F380CD07EBE65F09
+PT=291B066A30A3B11681D414A4BB5311D5
+
+I=358
+KEY=BE7C31194E4169F32BEE0CEB8C42F8B4
+IV=4E8F651C06778A964AA7D43999E41FD6
+CT=291B066A30A3B11681D414A4BB5311D5
+PT=764F8FD22FE0BD98852F259EA6DC6F7C
+
+I=359
+KEY=C833BECB61A1D46BAEC129752A9E97C8
+IV=E90A35007EE7F001D1F5982BF2477C82
+CT=764F8FD22FE0BD98852F259EA6DC6F7C
+PT=66016373A6B1A3797A1B2D2B19B73126
+
+I=360
+KEY=AE32DDB8C7107712D4DA045E3329A6EE
+IV=46FF289808B1AF6B290CB5AF05747085
+CT=66016373A6B1A3797A1B2D2B19B73126
+PT=3367064ECF5CA978001887DBDE40DE5A
+
+I=361
+KEY=9D55DBF6084CDE6AD4C28385ED6978B4
+IV=9BAC8819E1CA613CFAA730FBC2034168
+CT=3367064ECF5CA978001887DBDE40DE5A
+PT=5C4F01D47C9DA94DE95FC26763CC1146
+
+I=362
+KEY=C11ADA2274D177273D9D41E28EA569F2
+IV=A5CE34A846E1D0A737963C49FAD6378E
+CT=5C4F01D47C9DA94DE95FC26763CC1146
+PT=D41D854E42863F161E76A2397020C321
+
+I=363
+KEY=15075F6C3657483123EBE3DBFE85AAD3
+IV=2CC823722DD3E8F15035875ED43513E2
+CT=D41D854E42863F161E76A2397020C321
+PT=1C542DC0B54A053471AF583C909AB3C4
+
+I=364
+KEY=095372AC831D4D055244BBE76E1F1917
+IV=9799D03B6AD46BECD981279B35DF707C
+CT=1C542DC0B54A053471AF583C909AB3C4
+PT=958D0254D7AFE1E678A9844DF4F4D18D
+
+I=365
+KEY=9CDE70F854B2ACE32AED3FAA9AEBC89A
+IV=E0E401C7BA5E319F0D60AB765CBEE176
+CT=958D0254D7AFE1E678A9844DF4F4D18D
+PT=C54888169B30587E732BD7213EE5B1A3
+
+I=366
+KEY=5996F8EECF82F49D59C6E88BA40E7939
+IV=711DA6521732E6868111DCC1C835F9DF
+CT=C54888169B30587E732BD7213EE5B1A3
+PT=446F234FCADA809A8B2E167A86C9EB36
+
+I=367
+KEY=1DF9DBA105587407D2E8FEF122C7920F
+IV=B7008BC907C546A56743C292185C2B02
+CT=446F234FCADA809A8B2E167A86C9EB36
+PT=6AD93BC7E18B48810664CD1C528BA6C4
+
+I=368
+KEY=7720E066E4D33C86D48C33ED704C34CB
+IV=4D7DD98183E56F71D72DB76187FC5F95
+CT=6AD93BC7E18B48810664CD1C528BA6C4
+PT=0D75BD2B8683FB819EB7F71E2E0836A7
+
+I=369
+KEY=7A555D4D6250C7074A3BC4F35E44026C
+IV=F4DCFB73BBE7EB5348D56F81BCBC0971
+CT=0D75BD2B8683FB819EB7F71E2E0836A7
+PT=8CBE14862E93FE011A4F45518C7258FA
+
+I=370
+KEY=F6EB49CB4CC33906507481A2D2365A96
+IV=5432FBF1480AA398F09CA5AF375FA394
+CT=8CBE14862E93FE011A4F45518C7258FA
+PT=4026D669905762F0790B6497646A2D4D
+
+I=371
+KEY=B6CD9FA2DC945BF6297FE535B65C77DB
+IV=CA462DC9F029A8311CA45A4116DADC1D
+CT=4026D669905762F0790B6497646A2D4D
+PT=A8CD2E187CF274756E5736D420853435
+
+I=372
+KEY=1E00B1BAA0662F834728D3E196D943EE
+IV=4FC9E7688352F4700C5F380BFD1F4FB2
+CT=A8CD2E187CF274756E5736D420853435
+PT=A99410B60322340E279C87D3D26793AA
+
+I=373
+KEY=B794A10CA3441B8D60B4543244BED044
+IV=4D90B1A30EB7E957FAE3DC8C132F4F42
+CT=A99410B60322340E279C87D3D26793AA
+PT=D136F990196C667EC35E3A0492C39968
+
+I=374
+KEY=66A2589CBA287DF3A3EA6E36D67D492C
+IV=6FAD87F358F0C702C5E9E599093219ED
+CT=D136F990196C667EC35E3A0492C39968
+PT=8CE49C1BAACAB69432DDA2FF4250C7B2
+
+I=375
+KEY=EA46C48710E2CB679137CCC9942D8E9E
+IV=2B6FF495B7E482360E31949C7C9B2E2B
+CT=8CE49C1BAACAB69432DDA2FF4250C7B2
+PT=7942B80F57EA24FA200451B37899F9E2
+
+I=376
+KEY=93047C884708EF9DB1339D7AECB4777C
+IV=21FDC4C9B03A1A9A3F87FF9AAC80FAAE
+CT=7942B80F57EA24FA200451B37899F9E2
+PT=DE156D56E199FDBB2600DBF9FC254003
+
+I=377
+KEY=4D1111DEA6911226973346831091377F
+IV=387612E399C62916B394A9FC6BC0F059
+CT=DE156D56E199FDBB2600DBF9FC254003
+PT=C302C494D910640271695324E64B0992
+
+I=378
+KEY=8E13D54A7F817624E65A15A7F6DA3EED
+IV=34BCABDE4646BCC05CAF7E61CBF1F8D2
+CT=C302C494D910640271695324E64B0992
+PT=110CE84E5B81867CE4FCCD1BBB5FD792
+
+I=379
+KEY=9F1F3D042400F05802A6D8BC4D85E97F
+IV=C7898DA9ABF2A3D364C228A83525B04F
+CT=110CE84E5B81867CE4FCCD1BBB5FD792
+PT=7B94C0E4849AD65291F0F7BD464C544C
+
+I=380
+KEY=E48BFDE0A09A260A93562F010BC9BD33
+IV=00E079EEBC47AF3ED3796DBF4A2B55FC
+CT=7B94C0E4849AD65291F0F7BD464C544C
+PT=D6518596BB53E44452393BD4440D805C
+
+I=381
+KEY=32DA78761BC9C24EC16F14D54FC43D6F
+IV=03E168F8AF2303593E0F936648D253DC
+CT=D6518596BB53E44452393BD4440D805C
+PT=0C4B51FB33380BB215F29F3FCE7CA0DA
+
+I=382
+KEY=3E91298D28F1C9FCD49D8BEA81B89DB5
+IV=15E1ECD59BC092C974FA4738C66D9604
+CT=0C4B51FB33380BB215F29F3FCE7CA0DA
+PT=3FC98D86A558B711807930AAA391C9BF
+
+I=383
+KEY=0158A40B8DA97EED54E4BB402229540A
+IV=303BD4A407015A9E899816E0FABF288D
+CT=3FC98D86A558B711807930AAA391C9BF
+PT=85D77D90C312FE938F6C1983014BD572
+
+I=384
+KEY=848FD99B4EBB807EDB88A2C323628178
+IV=E018FA96FD433CFD162E8E67D4F37015
+CT=85D77D90C312FE938F6C1983014BD572
+PT=4F49C1740EA88B5767CE36C95158DD63
+
+I=385
+KEY=CBC618EF40130B29BC46940A723A5C1B
+IV=84013D3E2AA0C77650644CD6862096A7
+CT=4F49C1740EA88B5767CE36C95158DD63
+PT=E6F1409ABA890AC3A50FC4AAD82E1872
+
+I=386
+KEY=2D375875FA9A01EA194950A0AA144469
+IV=8BFD137593BFF254414349F1147B9BFF
+CT=E6F1409ABA890AC3A50FC4AAD82E1872
+PT=66F6E29696CFDC72EE905636614D2A72
+
+I=387
+KEY=4BC1BAE36C55DD98F7D90696CB596E1B
+IV=8EC295602FB66C4A2DCA65F66B07E010
+CT=66F6E29696CFDC72EE905636614D2A72
+PT=553B45792AE0625B357C4B68A4BB767F
+
+I=388
+KEY=1EFAFF9A46B5BFC3C2A54DFE6FE21864
+IV=5999E221475D06295451E52FF88F9F97
+CT=553B45792AE0625B357C4B68A4BB767F
+PT=FAB6F53166BFDB89DF68D46D423C243E
+
+I=389
+KEY=E44C0AAB200A644A1DCD99932DDE3C5A
+IV=49D1944CBD7BE00C671B8E996F9A3EB9
+CT=FAB6F53166BFDB89DF68D46D423C243E
+PT=308DDB3FE0415C46AE450C78FC5F2558
+
+I=390
+KEY=D4C1D194C04B380CB38895EBD1811902
+IV=9785FEE180794318514967B4199CFB93
+CT=308DDB3FE0415C46AE450C78FC5F2558
+PT=6659969D1BD493A3851E75981BACCCB0
+
+I=391
+KEY=B2984709DB9FABAF3696E073CA2DD5B2
+IV=4FD1DAE14DB75AC0E6C94388805AC3B5
+CT=6659969D1BD493A3851E75981BACCCB0
+PT=B56B950D84DCA131FD8A5E2601037B36
+
+I=392
+KEY=07F3D2045F430A9ECB1CBE55CB2EAE84
+IV=3ED415E7DDDADD2DC7F0376E6CA42EFE
+CT=B56B950D84DCA131FD8A5E2601037B36
+PT=8648F40FA13018563E6F1A799D9FCD91
+
+I=393
+KEY=81BB260BFE7312C8F573A42C56B16315
+IV=FEAF76717C0905A601509BD68C6D08E5
+CT=8648F40FA13018563E6F1A799D9FCD91
+PT=66DE6D7A74B36C7EE2737DA526F5C8CD
+
+I=394
+KEY=E7654B718AC07EB61700D9897044ABD8
+IV=2B808C340320DD64AB9278A9D9A3E247
+CT=66DE6D7A74B36C7EE2737DA526F5C8CD
+PT=9BB0D29CDA21452F60B5897186F3FAFB
+
+I=395
+KEY=7CD599ED50E13B9977B550F8F6B75123
+IV=D2EB48117E2E9FB2058800DE1A442799
+CT=9BB0D29CDA21452F60B5897186F3FAFB
+PT=489CDC3A2C1AE7510E03AE36D5EAB0E5
+
+I=396
+KEY=344945D77CFBDCC879B6FECE235DE1C6
+IV=427765E0671AA6D32634447687E9B209
+CT=489CDC3A2C1AE7510E03AE36D5EAB0E5
+PT=1D65D0E1235AE47DBCC2C65B59892C4C
+
+I=397
+KEY=292C95365FA138B5C57438957AD4CD8A
+IV=D75E9F074D965FE902287B3BB1483315
+CT=1D65D0E1235AE47DBCC2C65B59892C4C
+PT=E75B7AE5A8C3B93F15D0E3EBD04E1B4B
+
+I=398
+KEY=CE77EFD3F762818AD0A4DB7EAA9AD6C1
+IV=5455FD9A01E04E48CA777CF8185697ED
+CT=E75B7AE5A8C3B93F15D0E3EBD04E1B4B
+PT=11F4A35F6C225A9DF1CA6BAF92E11B07
+
+I=399
+KEY=DF834C8C9B40DB17216EB0D1387BCDC6
+IV=3C608F664492626B2208DC92E819411A
+CT=11F4A35F6C225A9DF1CA6BAF92E11B07
+PT=9B8FB71E035CEFF9CBFA1346E5ACEFE0
+
+==========
+
+KEYSIZE=192
+
+I=0
+KEY=000000000000000000000000000000000000000000000000
+IV=00000000000000000000000000000000
+CT=00000000000000000000000000000000
+PT=5DF678DD17BA4E75B61768C6ADEF7C7B
+
+I=1
+KEY=8AB601AF30C47B225DF678DD17BA4E75B61768C6ADEF7C7B
+IV=3B243F1A9BA094EE8AB601AF30C47B22
+CT=5DF678DD17BA4E75B61768C6ADEF7C7B
+PT=F9604074F8FA45AC71959888DD056F9F
+
+I=2
+KEY=D443B8E25A882D05A49638A9EF400BD9C782F04E70EA13E4
+IV=467E32A79443B0735EF5B94D6A4C5627
+CT=F9604074F8FA45AC71959888DD056F9F
+PT=98A957EA6DBE623B7E08F919812A3898
+
+I=3
+KEY=5742DCD38C8FD46D3C3F6F4382FE69E2B98A0957F1C02B7C
+IV=B9E1062EEDD9A1ED83016431D607F968
+CT=98A957EA6DBE623B7E08F919812A3898
+PT=AD6D29D6482764BB4BC27A87AE5CD877
+
+I=4
+KEY=B33625F7872DE4A191524695CAD90D59F24873D05F9CF30B
+IV=BD1AAC94D2D39445E474F9240BA230CC
+CT=AD6D29D6482764BB4BC27A87AE5CD877
+PT=DA5EB591FDC48F0D9E4EBD373E5717A3
+
+I=5
+KEY=35DA9F0A5DB187964B0CF304371D82546C06CEE761CBE4A8
+IV=4782561ED717916986ECBAFDDA9C6337
+CT=DA5EB591FDC48F0D9E4EBD373E5717A3
+PT=3F6E771434E26D4FA5A57CEF9DEE05D6
+
+I=6
+KEY=A8182E4F8FD8C7987462841003FFEF1BC9A3B208FC25E17E
+IV=093273C6E96EA5399DC2B145D269400E
+CT=3F6E771434E26D4FA5A57CEF9DEE05D6
+PT=F8FBFC8CBDD4AA8E8DA58DEA7F2F344C
+
+I=7
+KEY=71A581F408C35DA48C99789CBE2B459544063FE2830AD532
+IV=3900E8650CA62A25D9BDAFBB871B9A3C
+CT=F8FBFC8CBDD4AA8E8DA58DEA7F2F344C
+PT=B969AA871D3B35C260D8B36C7E9E8913
+
+I=8
+KEY=BCD0E4B5F0B7FB5035F0D21BA310705724DE8C8EFD945C21
+IV=0E2BCF13C2A18FF5CD756541F874A6F4
+CT=B969AA871D3B35C260D8B36C7E9E8913
+PT=6205EECCDD965D45339A2DFE85F52AD7
+
+I=9
+KEY=A2796321044D9F5557F53CD77E862D121744A170786176F6
+IV=8B935AB4C17D24D21EA98794F4FA6405
+CT=6205EECCDD965D45339A2DFE85F52AD7
+PT=6BC27204DA1B9BC27E463D0E71557D99
+
+I=10
+KEY=AD4506295D5309603C374ED3A49DB6D069029C7E09340B6F
+IV=A9AF68AB4EFDB7770F3C6508591E9635
+CT=6BC27204DA1B9BC27E463D0E71557D99
+PT=DB1576A8F1BD88F73E6938E72F9C6DCD
+
+I=11
+KEY=61ECB6C8660E5E20E722387B55203E27576BA49926A866A2
+IV=DF83746D72419F65CCA9B0E13B5D5740
+CT=DB1576A8F1BD88F73E6938E72F9C6DCD
+PT=150D14977B15FD304890D7B9C4F8536E
+
+I=12
+KEY=03679C91B6C57828F22F2CEC2E35C3171FFB7320E25035CC
+IV=59D101131EA2FD7F628B2A59D0CB2608
+CT=150D14977B15FD304890D7B9C4F8536E
+PT=7AE22B73B412A81D0BCF422C68DA37F8
+
+I=13
+KEY=9A087B9DBC37B12988CD079F9A276B0A1434310C8A8A0234
+IV=F26F03A3C84A49F0996FE70C0AF2C901
+CT=7AE22B73B412A81D0BCF422C68DA37F8
+PT=2D1584CE9B85E7264228A8AFF8FAFF01
+
+I=14
+KEY=07489932E5335B38A5D8835101A28C2C561C99A37270FD35
+IV=E76AB1C798119F5D9D40E2AF5904EA11
+CT=2D1584CE9B85E7264228A8AFF8FAFF01
+PT=C1067030225453E808F1FF324C44BE7F
+
+I=15
+KEY=DC3726E33013BC9964DEF36123F6DFC45EED66913E34434A
+IV=55010D6199E792E3DB7FBFD1D520E7A1
+CT=C1067030225453E808F1FF324C44BE7F
+PT=3AD7DBD96BB69D63BE39B9A16574AC74
+
+I=16
+KEY=EDD4EC10B074A36C5E0928B8484042A7E0D4DF305B40EF3E
+IV=18C6FE6D0A2FDD7E31E3CAF380671FF5
+CT=3AD7DBD96BB69D63BE39B9A16574AC74
+PT=3D5D82A4C06B9DDCCC8A6B8BF228482F
+
+I=17
+KEY=23824573BD3CE30D6354AA1C882BDF7B2C5EB4BBA968A711
+IV=E1DEAECBCFC06BCCCE56A9630D484061
+CT=3D5D82A4C06B9DDCCC8A6B8BF228482F
+PT=C0E5F9618F2FAB97EA82F8164DC89860
+
+I=18
+KEY=AAA43BC528933502A3B1537D070474ECC6DC4CADE4A03F71
+IV=2CE22FDF7E87B7CC89267EB695AFD60F
+CT=C0E5F9618F2FAB97EA82F8164DC89860
+PT=6942155FC9EF8F7CFE37CD6FED03CECF
+
+I=19
+KEY=A2686C442D636D31CAF34622CEEBFB9038EB81C209A3F1BE
+IV=B7772CF7B44B856308CC578105F05833
+CT=6942155FC9EF8F7CFE37CD6FED03CECF
+PT=6BA4C261F5173862A6789FB026099571
+
+I=20
+KEY=29F645A446D84EACA15784433BFCC3F29E931E722FAA64CF
+IV=15CA23A60D99FFF68B9E29E06BBB239D
+CT=6BA4C261F5173862A6789FB026099571
+PT=AA9E8C6497CAC6B0C8CC92F8DFE7B455
+
+I=21
+KEY=5E9165527010387F0BC90827AC360542565F8C8AF04DD09A
+IV=53193227307BBE49776720F636C876D3
+CT=AA9E8C6497CAC6B0C8CC92F8DFE7B455
+PT=7DA426C712E7F2F35087D6AA31CF56AB
+
+I=22
+KEY=92DC0EEE09F5169E766D2EE0BED1F7B106D85A20C1828631
+IV=85A3D20949963F95CC4D6BBC79E52EE1
+CT=7DA426C712E7F2F35087D6AA31CF56AB
+PT=09B9FF5E5833B6CE0010C3D0C4A84C19
+
+I=23
+KEY=C45B938E7C18B4107FD4D1BEE6E2417F06C899F0052ACA28
+IV=292A007187D730B956879D6075EDA28E
+CT=09B9FF5E5833B6CE0010C3D0C4A84C19
+PT=178F7AC0FF63C33683A001F5C4171316
+
+I=24
+KEY=03D99546E931B761685BAB7E1981824985689805C13DD93E
+IV=A8D8CD3B96215FCDC78206C895290371
+CT=178F7AC0FF63C33683A001F5C4171316
+PT=C39B82763CF6901170902BE6DC1B9305
+
+I=25
+KEY=B52384CAC0B230F5ABC0290825771258F5F8B3E31D264A3B
+IV=451968C3AA8D0319B6FA118C29838794
+CT=C39B82763CF6901170902BE6DC1B9305
+PT=85D827F61EC17FD00B10356292C863E2
+
+I=26
+KEY=DCF617A990AC4CBB2E180EFE3BB66D88FEE886818FEE29D9
+IV=575103DAEFD233E269D59363501E7C4E
+CT=85D827F61EC17FD00B10356292C863E2
+PT=535BAC956D5CAB917E1A1BC28E82F28F
+
+I=27
+KEY=14D0FCAFFD961CFD7D43A26B56EAC61980F29D43016CDB56
+IV=7DE780ACCF9F1896C826EB066D3A5046
+CT=535BAC956D5CAB917E1A1BC28E82F28F
+PT=7E73E89F187EA6D5F5A3044A19C85941
+
+I=28
+KEY=AF5BFBC086F1392203304AF44E9460CC7551990918A48217
+IV=633F0251217DECEDBB8B076F7B6725DF
+CT=7E73E89F187EA6D5F5A3044A19C85941
+PT=B0976DFD4F0620203AC4ED89D395BAFF
+
+I=29
+KEY=79FFB93DCF243047B3A72709019240EC4F957480CB3138E8
+IV=C1AAE3E35613DAADD6A442FD49D50965
+CT=B0976DFD4F0620203AC4ED89D395BAFF
+PT=5ECB838EC7F9F2E7ADBD719599F829B9
+
+I=30
+KEY=681F54ADA7685555ED6CA487C66BB20BE228051552C91151
+IV=4F00D9CD31BE1CC611E0ED90684C6512
+CT=5ECB838EC7F9F2E7ADBD719599F829B9
+PT=8DDA96BD88D3D756306D249ABF99F5F9
+
+I=31
+KEY=8663BEBF11817A3060B6323A4EB8655DD245218FED50E4A8
+IV=7CC24DC4B003DE90EE7CEA12B6E92F65
+CT=8DDA96BD88D3D756306D249ABF99F5F9
+PT=479E96E558540B71508FEF3173A6FC68
+
+I=32
+KEY=831519BE48B0021A2728A4DF16EC6E2C82CACEBE9EF618C0
+IV=59FFA792DC8618070576A7015931782A
+CT=479E96E558540B71508FEF3173A6FC68
+PT=080EA053745BEEBDBC5F7D964EEBD2F7
+
+I=33
+KEY=AFC20AF72699543A2F26048C62B780913E95B328D01DCA37
+IV=4E5BDD875324CAC02CD713496E295620
+CT=080EA053745BEEBDBC5F7D964EEBD2F7
+PT=B5A58D345C0260A9E274E2E593B76C44
+
+I=34
+KEY=46AEAF002B9A297E9A8389B83EB5E038DCE151CD43AAA673
+IV=C67419FDA89E68B1E96CA5F70D037D44
+CT=B5A58D345C0260A9E274E2E593B76C44
+PT=5200F2D475CA388841CB0DD02C7EB7F6
+
+I=35
+KEY=1598E4DD7DA3D7B0C8837B6C4B7FD8B09D2A5C1D6FD41185
+IV=9F5C74A1FE2DFF2153364BDD5639FECE
+CT=5200F2D475CA388841CB0DD02C7EB7F6
+PT=B2639C2D26BF2CAF2371CA3A4F3D3476
+
+I=36
+KEY=FE63AA4A158B41AE7AE0E7416DC0F41FBE5B962720E925F3
+IV=2DC59704D531C890EBFB4E976828961E
+CT=B2639C2D26BF2CAF2371CA3A4F3D3476
+PT=C758ADC41E334CCBF34C40E2AEAA3852
+
+I=37
+KEY=86B214FA7F89CE06BDB84A8573F3B8D44D17D6C58E431DA1
+IV=D0982ADEECE45CCC78D1BEB06A028FA8
+CT=C758ADC41E334CCBF34C40E2AEAA3852
+PT=F8E0AA1E780F18A50371CBCB1B63E83F
+
+I=38
+KEY=C0C34A59DC653DCE4558E09B0BFCA0714E661D0E9520F59E
+IV=A252B0F29766A24B46715EA3A3ECF3C8
+CT=F8E0AA1E780F18A50371CBCB1B63E83F
+PT=554B524391A7A1679210CFC0152A65CE
+
+I=39
+KEY=3CF3D7DDFFF704231013B2D89A5B0116DC76D2CE800A9050
+IV=42EE716B821C18FCFC309D84239239ED
+CT=554B524391A7A1679210CFC0152A65CE
+PT=3273E6C51751407B7E4ECDED7970746D
+
+I=40
+KEY=7FCC684C43B958F02260541D8D0A416DA2381F23F97AE43D
+IV=A4FCB2B8AB7158B9433FBF91BC4E5CD3
+CT=3273E6C51751407B7E4ECDED7970746D
+PT=D90B75848AC14ACA3CAD9AF2A15F315F
+
+I=41
+KEY=240724B451241314FB6B219907CB0BA79E9585D15825D562
+IV=5C4FA1918B04D5F85BCB4CF8129D4BE4
+CT=D90B75848AC14ACA3CAD9AF2A15F315F
+PT=753C59B87C45B21D527527C6C2DDEB0D
+
+I=42
+KEY=F0BEECC2DB5D16F98E5778217B8EB9BACCE0A2179AF83E6F
+IV=4E41A4AB69AEE73FD4B9C8768A7905ED
+CT=753C59B87C45B21D527527C6C2DDEB0D
+PT=156E851810ADB0BF2D28B6150D32CAC7
+
+I=43
+KEY=C2FB954C95633B5B9B39FD396B230905E1C8140297CAF4A8
+IV=983906FA7F156CF33245798E4E3E2DA2
+CT=156E851810ADB0BF2D28B6150D32CAC7
+PT=26E671DACE32070A601796207BD045B5
+
+I=44
+KEY=BF0BD4C6DDBE22DABDDF8CE3A5110E0F81DF8222EC1AB11D
+IV=B3188D29356783AF7DF0418A48DD1981
+CT=26E671DACE32070A601796207BD045B5
+PT=ADAD9072859250A8590F6F54C24E5A77
+
+I=45
+KEY=2E4F07AD61768CC010721C9120835EA7D8D0ED762E54EB6A
+IV=639F27016A9D99B99144D36BBCC8AE1A
+CT=ADAD9072859250A8590F6F54C24E5A77
+PT=AC8AD3933D51D5D71CA90FB73A53F6AD
+
+I=46
+KEY=9963998A6F982462BCF8CF021DD28B70C479E2C114071DC7
+IV=B2A3ACB0CE942F13B72C9E270EEEA8A2
+CT=AC8AD3933D51D5D71CA90FB73A53F6AD
+PT=7319F2825648168F07D525618DA9979A
+
+I=47
+KEY=417FD42690AAE310CFE13D804B9A9DFFC3ACC7A099AE8A5D
+IV=EBB0EF7CE1ACF152D81C4DACFF32C772
+CT=7319F2825648168F07D525618DA9979A
+PT=4FC19392439D6CBE6699419355E0590B
+
+I=48
+KEY=30CD3A2A0910C7268020AE120807F141A5358633CC4ED356
+IV=4DCACE79E4C3ADFE71B2EE0C99BA2436
+CT=4FC19392439D6CBE6699419355E0590B
+PT=047FF92A523900A3C46D906163927DDD
+
+I=49
+KEY=F13EE3ACC9C19E4C845F57385A3EF1E261581652AFDCAE8B
+IV=E260680204844E6FC1F3D986C0D1596A
+CT=047FF92A523900A3C46D906163927DDD
+PT=2DAE78D178D069918CCC11D675E09655
+
+I=50
+KEY=91556C720DC982D5A9F12FE922EE9873ED940784DA3C38DE
+IV=A4E4973E74B61315606B8FDEC4081C99
+CT=2DAE78D178D069918CCC11D675E09655
+PT=6315A6A029ED7FC5AB3CD38D8DAE561A
+
+I=51
+KEY=9120A23E63AF3BC2CAE489490B03E7B646A8D40957926EC4
+IV=C02DA24531C794BD0075CE4C6E66B917
+CT=6315A6A029ED7FC5AB3CD38D8DAE561A
+PT=65A796C69B769E59D34AD19803F117C6
+
+I=52
+KEY=5C6847E25C66145DAF431F8F907579EF95E2059154637902
+IV=0D72A6B0F3959C89CD48E5DC3FC92F9F
+CT=65A796C69B769E59D34AD19803F117C6
+PT=70770D19D03DF488FB627F460A225F39
+
+I=53
+KEY=F5ECA4C905FF0EC2DF34129640488D676E807AD75E41263B
+IV=2F60424B5062D978A984E32B59991A9F
+CT=70770D19D03DF488FB627F460A225F39
+PT=C8A66A2CD18286D2148230BAB7D81E11
+
+I=54
+KEY=FF86E251C5EC6129179278BA91CA0BB57A024A6DE999382A
+IV=CC7330AE077936B10A6A4698C0136FEB
+CT=C8A66A2CD18286D2148230BAB7D81E11
+PT=FC0B47BA3E51927A632F457A919818DC
+
+I=55
+KEY=5C0A7344D6FD6983EB993F00AF9B99CF192D0F17780120F6
+IV=CA119AEE5576E06EA38C9115131108AA
+CT=FC0B47BA3E51927A632F457A919818DC
+PT=AEEDB360C58C4CDC7ACE87AA1A4B785B
+
+I=56
+KEY=426948BD499E8A9845748C606A17D51363E388BD624A58AD
+IV=920C491DE39D52501E633BF99F63E31B
+CT=AEEDB360C58C4CDC7ACE87AA1A4B785B
+PT=737ECC4294FF69495DC37DC795EC13CE
+
+I=57
+KEY=F8AD0E545AA212E6360A4022FEE8BC5A3E20F57AF7A64B63
+IV=B975B70450A41A2DBAC446E9133C987E
+CT=737ECC4294FF69495DC37DC795EC13CE
+PT=3E7CDC26CCC69E02D08248224A22961E
+
+I=58
+KEY=C2834233A26DCD8A08769C04322E2258EEA2BD58BD84DD7D
+IV=A88326DC57AB80FC3A2E4C67F8CFDF6C
+CT=3E7CDC26CCC69E02D08248224A22961E
+PT=88177B6502254344A364023BCAD29E79
+
+I=59
+KEY=962D892D6CDED6798061E761300B611C4DC6BF6377564304
+IV=D95CFF470B1796D754AECB1ECEB31BF3
+CT=88177B6502254344A364023BCAD29E79
+PT=A10FA825EB6DA0E242D9A381F607472D
+
+I=60
+KEY=3ADA98C76065214A216E4F44DB66C1FE0F1F1CE281510429
+IV=FBD25798351AF35DACF711EA0CBBF733
+CT=A10FA825EB6DA0E242D9A381F607472D
+PT=6B5EE3A222DF46560A12E91C006D303F
+
+I=61
+KEY=C6AB975CF71B6DDF4A30ACE6F9B987A8050DF5FE813C3416
+IV=6CDB3875008754DAFC710F9B977E4C95
+CT=6B5EE3A222DF46560A12E91C006D303F
+PT=A0047B92A93ACF32138A818B6E32B3EE
+
+I=62
+KEY=FFD0E16A5C955EBAEA34D7745083489A16877475EF0E87F8
+IV=F7061CA37B11E445397B7636AB8E3365
+CT=A0047B92A93ACF32138A818B6E32B3EE
+PT=1707FC063700E98FF5FDA98A07A8A1C7
+
+I=63
+KEY=AA71EC7061FA246CFD332B726783A115E37ADDFFE8A6263F
+IV=1853E27FC0689E6755A10D1A3D6F7AD6
+CT=1707FC063700E98FF5FDA98A07A8A1C7
+PT=06320FA4C0E2F42B364B991243FA053D
+
+I=64
+KEY=D8685685696CBF5CFB0124D6A761553ED53144EDAB5C2302
+IV=E19A3BEC7EBCA3C87219BAF508969B30
+CT=06320FA4C0E2F42B364B991243FA053D
+PT=BB70503E9715D653710C0630211755A7
+
+I=65
+KEY=28C2AFFA406EF763407174E83074836DA43D42DD8A4B76A5
+IV=5F3BCA36562AFA82F0AAF97F2902483F
+CT=BB70503E9715D653710C0630211755A7
+PT=D632FEF42560770DF318C570AFC85285
+
+I=66
+KEY=260B8E0723E9AF3D96438A1C1514F460572587AD25832420
+IV=328A42D3898A81C20EC921FD6387585E
+CT=D632FEF42560770DF318C570AFC85285
+PT=B1C847FFF455D002E55FCFAF4A4F69A4
+
+I=67
+KEY=F39D3CD6A68DC6BC278BCDE3E1412462B27A48026FCC4D84
+IV=C89E7B4C1BAED0FAD596B2D185646981
+CT=B1C847FFF455D002E55FCFAF4A4F69A4
+PT=9C484252E1FE52CD2DFCCAA3E0118F07
+
+I=68
+KEY=61A9714C87B94F27BBC38FB100BF76AF9F8682A18FDDC283
+IV=56B7D716EC6F9A6D92344D9A2134899B
+CT=9C484252E1FE52CD2DFCCAA3E0118F07
+PT=85A142323B9877E86F3A5874EA613E87
+
+I=69
+KEY=B504BE17C673E81F3E62CD833B270147F0BCDAD565BCFC04
+IV=BEF2C82884510475D4ADCF5B41CAA738
+CT=85A142323B9877E86F3A5874EA613E87
+PT=53D0EF74268F55C1B6CA84415E5A2F6F
+
+I=70
+KEY=1A63CC27BE45C5106DB222F71DA8548646765E943BE6D36B
+IV=CC958CC3874510F0AF67723078362D0F
+CT=53D0EF74268F55C1B6CA84415E5A2F6F
+PT=7B7DB0F3EFAD244FFCC6991452001DF6
+
+I=71
+KEY=4B17520C49F46EAF16CF9204F20570C9BAB0C78069E6CE9D
+IV=48D7C0690532AFCC51749E2BF7B1ABBF
+CT=7B7DB0F3EFAD244FFCC6991452001DF6
+PT=DD0661DCA2BE8C20E95B3A84CCACDB10
+
+I=72
+KEY=1ADE412393310021CBC9F3D850BBFCE953EBFD04A54A158D
+IV=4B96B2D0CCADFF7D51C9132FDAC56E8E
+CT=DD0661DCA2BE8C20E95B3A84CCACDB10
+PT=E505435777F3781121A4A374684E3268
+
+I=73
+KEY=493467065AE405B82ECCB08F274884F8724F5E70CD0427E5
+IV=1E8116EB95B94AFC53EA2625C9D50599
+CT=E505435777F3781121A4A374684E3268
+PT=EF4B4E997DA0DCCBDBB36C020D03E8B5
+
+I=74
+KEY=4C94816DF6EBDEF5C187FE165AE85833A9FC3272C007CF50
+IV=29094410F6017E5805A0E66BAC0FDB4D
+CT=EF4B4E997DA0DCCBDBB36C020D03E8B5
+PT=FA9BAB377C654ED894024BEBDCED2FA0
+
+I=75
+KEY=697A0BC179C07A633B1C5521268D16EB3DFE79991CEAE0F0
+IV=83DD12597A405FB725EE8AAC8F2BA496
+CT=FA9BAB377C654ED894024BEBDCED2FA0
+PT=DD1FDA63382552D007F6F8E995820640
+
+I=76
+KEY=D40786ED2A6C15E8E6038F421EA8443B3A0881708968E6B0
+IV=2F3AE5594D9CCEDCBD7D8D2C53AC6F8B
+CT=DD1FDA63382552D007F6F8E995820640
+PT=C5FF0EB50BA651F436D0566385860ADA
+
+I=77
+KEY=9D47680C0159F69A23FC81F7150E15CF0CD8D7130CEEEC6A
+IV=1BCFAD6802C41B9A4940EEE12B35E372
+CT=C5FF0EB50BA651F436D0566385860ADA
+PT=67AE61A77D77CBFD48C080B21313BBAB
+
+I=78
+KEY=86E61E031542D2DB4452E0506879DE32441857A11FFD57C1
+IV=3DF4DA1F65C739511BA1760F141B2441
+CT=67AE61A77D77CBFD48C080B21313BBAB
+PT=68C8512217CB9C3BBF28011FA5BED044
+
+I=79
+KEY=4F93757DE614CB1D2C9AB1727FB24209FB3056BEBA438785
+IV=B2C15424EF4E4637C9756B7EF35619C6
+CT=68C8512217CB9C3BBF28011FA5BED044
+PT=233898C850826172965695499748A1B0
+
+I=80
+KEY=C56E54BBB54B22CC0FA229BA2F30237B6D66C3F72D0B2635
+IV=DC2FF5992D9383EF8AFD21C6535FE9D1
+CT=233898C850826172965695499748A1B0
+PT=70069F5E963A820D640B40697BD24716
+
+I=81
+KEY=A1EF05CB5AAE7A977FA4B6E4B90AA176096D839E56D96123
+IV=EE8CB982124A394C64815170EFE5585B
+CT=70069F5E963A820D640B40697BD24716
+PT=B136CA2EF42A9CFF53410554B28A8F65
+
+I=82
+KEY=ACEC084A8CED2F4FCE927CCA4D203D895A2C86CAE453EE46
+IV=515D8B6C167EC8570D030D81D64355D8
+CT=B136CA2EF42A9CFF53410554B28A8F65
+PT=123600CD1B5A664430413021DDC8CBBE
+
+I=83
+KEY=8325A9391B4E106ADCA47C07567A5BCD6A6DB6EB399B25F8
+IV=5A55A24EC8154E532FC9A17397A33F25
+CT=123600CD1B5A664430413021DDC8CBBE
+PT=8ECCA03E10D415557C4E7D92DDBFD791
+
+I=84
+KEY=DB877966BE0E84575268DC3946AE4E981623CB79E424F269
+IV=659705F3774E141758A2D05FA540943D
+CT=8ECCA03E10D415557C4E7D92DDBFD791
+PT=CB70B675AC6BF92237F1C479516E7E6A
+
+I=85
+KEY=59027658DEC2B5DE99186A4CEAC5B7BA21D20F00B54A8C03
+IV=C9B803CE2D57D26F82850F3E60CC3189
+CT=CB70B675AC6BF92237F1C479516E7E6A
+PT=5D99D06E9BEB82AB1CE22201E8467DBC
+
+I=86
+KEY=652E430F984201E0C481BA22712E35113D302D015D0CF1BF
+IV=1838FACBEAC13CF73C2C35574680B43E
+CT=5D99D06E9BEB82AB1CE22201E8467DBC
+PT=11D7AED0B552D62677DEB874BF7CF8ED
+
+I=87
+KEY=8377A2C11B73082DD55614F2C47CE3374AEE9575E2700952
+IV=068170C7E11427DFE659E1CE833109CD
+CT=11D7AED0B552D62677DEB874BF7CF8ED
+PT=74B108D32ABE8401D22F2C3FB008F670
+
+I=88
+KEY=7B89A5C45B0A22BBA1E71C21EEC2673698C1B94A5278FF22
+IV=5283DAD6FA2B605DF8FE070540792A96
+CT=74B108D32ABE8401D22F2C3FB008F670
+PT=7883BD8C4DA81C21C4A5847AD801B7AE
+
+I=89
+KEY=101261A4D23FDA13D964A1ADA36A7B175C643D308A79488C
+IV=E2ED92DE4829CB526B9BC4608935F8A8
+CT=7883BD8C4DA81C21C4A5847AD801B7AE
+PT=C865B27C21F6F6E681759C318607D2B9
+
+I=90
+KEY=E6A6A13B7A64EB51110113D1829C8DF1DD11A1010C7E9A35
+IV=AB325AD4F1FF1C52F6B4C09FA85B3142
+CT=C865B27C21F6F6E681759C318607D2B9
+PT=E31D7AC0E8ADB302BC6C23A0B1D693ED
+
+I=91
+KEY=64D366C4F61E139BF21C69116A313EF3617D82A1BDA809D8
+IV=A5201D1770A12A898275C7FF8C7AF8CA
+CT=E31D7AC0E8ADB302BC6C23A0B1D693ED
+PT=CAE6A97EE64228EEEF02E135944C5C62
+
+I=92
+KEY=B006CEF05093DE2238FAC06F8C73161D8E7F639429E455BA
+IV=62BD7E3EA22E26BAD4D5A834A68DCDB9
+CT=CAE6A97EE64228EEEF02E135944C5C62
+PT=B7AEF117099F799BB0752C7260A2DFB5
+
+I=93
+KEY=160AFF18C06B6C4A8F54317885EC6F863E0A4FE649468A0F
+IV=AEBB967838133F64A60C31E890F8B268
+CT=B7AEF117099F799BB0752C7260A2DFB5
+PT=81CCC6EDAD41D9C7986D4E175C71551D
+
+I=94
+KEY=21112CBE896259CE0E98F79528ADB641A66701F11537DF12
+IV=B695BBE7FA331039371BD3A649093584
+CT=81CCC6EDAD41D9C7986D4E175C71551D
+PT=9039E01C6485040A2EDAF4C27FE93870
+
+I=95
+KEY=60272333C1B4CCC39EA117894C28B24B88BDF5336ADEE762
+IV=4EE830907337D60241360F8D48D6950D
+CT=9039E01C6485040A2EDAF4C27FE93870
+PT=44D359DBE4BE436D5133CD81B72DB5C7
+
+I=96
+KEY=25C676A781511A98DA724E52A896F126D98E38B2DDF352A5
+IV=38491C9FD517260445E1559440E5D65B
+CT=44D359DBE4BE436D5133CD81B72DB5C7
+PT=7B47F95ED30563BE218E40DB4EAAE836
+
+I=97
+KEY=59A7B7512B5DC429A135B70C7B939298F80078699359BA93
+IV=1FD8B8BA8B0492E67C61C1F6AA0CDEB1
+CT=7B47F95ED30563BE218E40DB4EAAE836
+PT=C417F6A6824B165D4C26D631F77E45AC
+
+I=98
+KEY=82E6CF234BC0AA10652241AAF9D884C5B426AE586427FF3F
+IV=5FB017B65FE4AF34DB417872609D6E39
+CT=C417F6A6824B165D4C26D631F77E45AC
+PT=41EC9A06B318A4D06636ED5403F46CB7
+
+I=99
+KEY=82D69A1D747CF6E024CEDBAC4AC02015D210430C67D39388
+IV=1CC1F56321366F420030553E3FBC5CF0
+CT=41EC9A06B318A4D06636ED5403F46CB7
+PT=38E467F81D919F0A1704E9F5CDF4D5FC
+
+I=100
+KEY=29EFCA26B9C67E141C2ABC545751BF1FC514AAF9AA274674
+IV=A83BDBF4326AE806AB39503BCDBA88F4
+CT=38E467F81D919F0A1704E9F5CDF4D5FC
+PT=A08359A20D6F405018F8180A3E8D0FD1
+
+I=101
+KEY=AB20AC8C3C5DA5BEBCA9E5F65A3EFF4FDDECB2F394AA49A5
+IV=A14B10E1A998B04E82CF66AA859BDBAA
+CT=A08359A20D6F405018F8180A3E8D0FD1
+PT=A16C303138057144A3ECA63E7398DC93
+
+I=102
+KEY=86C5E861B9CEAF041DC5D5C7623B8E0B7E0014CDE7329536
+IV=181D943EA950561D2DE544ED85930ABA
+CT=A16C303138057144A3ECA63E7398DC93
+PT=EA1A2E30D890D01979D2BCE1EBE6C922
+
+I=103
+KEY=90321C401E4B6B30F7DFFBF7BAAB5E1207D2A82C0CD45C14
+IV=12BDB944D898BC5A16F7F421A785C434
+CT=EA1A2E30D890D01979D2BCE1EBE6C922
+PT=C0D620FCF33031DAD617ADBE8F6D13AC
+
+I=104
+KEY=84964C3B41FE8E4F3709DB0B499B6FC8D1C5059283B94FB8
+IV=0615AD27B29C55F814A4507B5FB5E57F
+CT=C0D620FCF33031DAD617ADBE8F6D13AC
+PT=EC4B9AEDBE44C4B74B693D08AA1D175A
+
+I=105
+KEY=6C6361F2C87BC168DB4241E6F7DFAB7F9AAC389A29A458E2
+IV=E79F33FFCD79681CE8F52DC989854F27
+CT=EC4B9AEDBE44C4B74B693D08AA1D175A
+PT=F34D426225ADEC3BD2580BF21EF24B3E
+
+I=106
+KEY=FDA3FB79F1A16865280F0384D272474448F43368375613DC
+IV=1DFE18B10032D35F91C09A8B39DAA90D
+CT=F34D426225ADEC3BD2580BF21EF24B3E
+PT=E14841B0D0CC1E698DE8053B9F1621E1
+
+I=107
+KEY=562D3BF792909255C947423402BE592DC51C3653A840323D
+IV=247A46C43AE54F1FAB8EC08E6331FA30
+CT=E14841B0D0CC1E698DE8053B9F1621E1
+PT=D21381B5032426EC3582BBD23739E04E
+
+I=108
+KEY=9D375E6E32C30A801B54C381019A7FC1F09E8D819F79D273
+IV=E05018C26DC38BBDCB1A6599A05398D5
+CT=D21381B5032426EC3582BBD23739E04E
+PT=82034FF505FE67B94373770348A934E5
+
+I=109
+KEY=7D1A900B515478DB99578C7404641878B3EDFA82D7D0E696
+IV=498AEA38AB55250CE02DCE656397725B
+CT=82034FF505FE67B94373770348A934E5
+PT=018B5B1787138D222F6B39C1291ECD2C
+
+I=110
+KEY=E74B55A39F67C54298DCD7638377955A9C86C343FECE2BBA
+IV=DD89DF396236F9A59A51C5A8CE33BD99
+CT=018B5B1787138D222F6B39C1291ECD2C
+PT=CABCB7EA14E821726602272A46CEB825
+
+I=111
+KEY=D3FFFE0F27D9200352606089979FB428FA84E469B800939F
+IV=A707D154BAC28BDC34B4ABACB8BEE541
+CT=CABCB7EA14E821726602272A46CEB825
+PT=0840D09DF2B14ED4B340D32101D68A54
+
+I=112
+KEY=485EC313821A37095A20B014652EFAFC49C43748B9D619CB
+IV=ADEF6A8A49BF208B9BA13D1CA5C3170A
+CT=0840D09DF2B14ED4B340D32101D68A54
+PT=5EB0166FB04AF38F9EA60929FD641844
+
+I=113
+KEY=E841074638A154D90490A67BD5640973D7623E6144B2018F
+IV=B1956D86A4F79E40A01FC455BABB63D0
+CT=5EB0166FB04AF38F9EA60929FD641844
+PT=2ECBDAFBD0336A436D89FC12944750EC
+
+I=114
+KEY=17E86798DB7A64E42A5B7C8005576330BAEBC273D0F55163
+IV=0AFFE19CA1425218FFA960DEE3DB303D
+CT=2ECBDAFBD0336A436D89FC12944750EC
+PT=A326D8C07EF7A21302A3C6A9C67C371A
+
+I=115
+KEY=D1A6F2AB7C130A60897DA4407BA0C123B84804DA16896679
+IV=6F630069CD0333BDC64E9533A7696E84
+CT=A326D8C07EF7A21302A3C6A9C67C371A
+PT=6D06DDFB9B12A71298E32318F582EF72
+
+I=116
+KEY=C7D58104581CB5C5E47B79BBE0B2663120AB27C2E30B890B
+IV=80E47BA8410247C5167373AF240FBFA5
+CT=6D06DDFB9B12A71298E32318F582EF72
+PT=E1391A50F140E255A9B2E628F25B9B1D
+
+I=117
+KEY=00D8EEC433F7D68E054263EB11F284648919C1EA11501216
+IV=96F652822C5D4496C70D6FC06BEB634B
+CT=E1391A50F140E255A9B2E628F25B9B1D
+PT=1418A2DC8D6DBA4942932D6944011D8A
+
+I=118
+KEY=71D444358CCCF986115AC1379C9F3E2DCB8AEC8355510F9C
+IV=410374DE0D8A79FA710CAAF1BF3B2F08
+CT=1418A2DC8D6DBA4942932D6944011D8A
+PT=A70A2C48CF5786868844274B8C493C56
+
+I=119
+KEY=B9FD9626EC74A129B650ED7F53C8B8AB43CECBC8D91833CA
+IV=8362FAE290801C25C829D21360B858AF
+CT=A70A2C48CF5786868844274B8C493C56
+PT=3484BA42558B199E8477B8F8280CDE91
+
+I=120
+KEY=94CAEE912A7B443582D4573D0643A135C7B97330F114ED5B
+IV=F6ABE3F0A7FFC9E02D3778B7C60FE51C
+CT=3484BA42558B199E8477B8F8280CDE91
+PT=5D79433F85C7D4C258487080E340F049
+
+I=121
+KEY=1D2F762CF08FAE0ADFAD1402838475F79FF103B012541D12
+IV=A0C57652FBF9107C89E598BDDAF4EA3F
+CT=5D79433F85C7D4C258487080E340F049
+PT=C51891EA2E68BC60E84912A91F470201
+
+I=122
+KEY=9E691D03A3AEB6491AB585E8ADECC99777B811190D131F13
+IV=8426C338234DB9E183466B2F53211843
+CT=C51891EA2E68BC60E84912A91F470201
+PT=F946FD67DD7F92A7A6B93B4F71F70243
+
+I=123
+KEY=61EA6FD274C07ADDE3F3788F70935B30D1012A567CE41D50
+IV=2C2AF70B07E9E6F9FF8372D1D76ECC94
+CT=F946FD67DD7F92A7A6B93B4F71F70243
+PT=B4CB0EFF14F8CDC693CC8E7DCEE8E0B0
+
+I=124
+KEY=84F27E5BF8B55DA657387670646B96F642CDA42BB20CFDE0
+IV=693782638B439464E51811898C75277B
+CT=B4CB0EFF14F8CDC693CC8E7DCEE8E0B0
+PT=EF6DDB56AAE9CFFE128FB3776DD94D20
+
+I=125
+KEY=5B1111EADAECDD73B855AD26CE8259085042175CDFD5B0C0
+IV=A14AAEF7A1BF063BDFE36FB1225980D5
+CT=EF6DDB56AAE9CFFE128FB3776DD94D20
+PT=4ACC6AF28293A647093AE788BA778835
+
+I=126
+KEY=A924DC707FB16DF1F299C7D44C11FF4F5978F0D465A238F5
+IV=3F7E73BFA24B0C02F235CD9AA55DB082
+CT=4ACC6AF28293A647093AE788BA778835
+PT=5A7989DC61AD6B66B3E83A29168BEDB9
+
+I=127
+KEY=164FBEF9EBAEEF03A8E04E082DBC9429EA90CAFD7329D54C
+IV=2FB4F1A000B78156BF6B6289941F82F2
+CT=5A7989DC61AD6B66B3E83A29168BEDB9
+PT=246A94AB8488B39C52DE68E8CA5AE0D2
+
+I=128
+KEY=B1F4A368B64A78EC8C8ADAA3A93427B5B84EA215B973359E
+IV=5D178EC8305B804FA7BB1D915DE497EF
+CT=246A94AB8488B39C52DE68E8CA5AE0D2
+PT=F7C758F8DC8FC0891907EBBF299F70B8
+
+I=129
+KEY=9161A39C256814AA7B4D825B75BBE73CA14949AA90EC4526
+IV=C87E61A9434EB29F209500F493226C46
+CT=F7C758F8DC8FC0891907EBBF299F70B8
+PT=E2D82C5506BEFA7D7BF032E4C72141CF
+
+I=130
+KEY=0BFDA1B2CF4B15199995AE0E73051D41DAB97B4E57CD04E9
+IV=5D00992780D9832B9A9C022EEA2301B3
+CT=E2D82C5506BEFA7D7BF032E4C72141CF
+PT=F3A0DF1793FC88117E87478FD9E5A1A8
+
+I=131
+KEY=F8F5F6016FECDCAF6A357119E0F99550A43E3CC18E28A541
+IV=2800EECA83EB078CF30857B3A0A7C9B6
+CT=F3A0DF1793FC88117E87478FD9E5A1A8
+PT=BEB572C53E9985218ED9012BAB4A9F5B
+
+I=132
+KEY=84F3E0D153E140D6D48003DCDE6010712AE73DEA25623A1A
+IV=E2BEAF80F4A1DDA27C0616D03C0D9C79
+CT=BEB572C53E9985218ED9012BAB4A9F5B
+PT=7F4B21C4B7466149CB890B77AC538752
+
+I=133
+KEY=B69E5A72FE9B1B85ABCB221869267138E16E369D8931BD48
+IV=FE0A667B9B2BDD29326DBAA3AD7A5B53
+CT=7F4B21C4B7466149CB890B77AC538752
+PT=4B239C8F83F0A10DC6A3497CC3CF9C8E
+
+I=134
+KEY=0BCF87D2538E0EADE0E8BE97EAD6D03527CD7FE14AFE21C6
+IV=878250C5EA7834CFBD51DDA0AD151528
+CT=4B239C8F83F0A10DC6A3497CC3CF9C8E
+PT=89F2B4B8C5AB2988CDEA61F4D4A1BCD4
+
+I=135
+KEY=97A4FDCD2E0C993E691A0A2F2F7DF9BDEA271E159E5F9D12
+IV=95E34D44C3E2FE319C6B7A1F7D829793
+CT=89F2B4B8C5AB2988CDEA61F4D4A1BCD4
+PT=C622E28004842564F193C0E58AB40FCB
+
+I=136
+KEY=38F0A45980CEF0B9AF38E8AF2BF9DCD91BB4DEF014EB92D9
+IV=1BC195727D154539AF545994AEC26987
+CT=C622E28004842564F193C0E58AB40FCB
+PT=DF360FBC1607BCC1E6EE9088AEE62EC7
+
+I=137
+KEY=6638E0333D7A6765700EE7133DFE6018FD5A4E78BA0DBC1E
+IV=F0AB65A69AA4486A5EC8446ABDB497DC
+CT=DF360FBC1607BCC1E6EE9088AEE62EC7
+PT=9A8E5BFE223FA9D747164FC1C98B9CDC
+
+I=138
+KEY=5103611D32D7A1EFEA80BCED1FC1C9CFBA4C01B9738620C2
+IV=A6617B5DA41B2A32373B812E0FADC68A
+CT=9A8E5BFE223FA9D747164FC1C98B9CDC
+PT=F0143DD4EC3A85F9FA4D5579BD7268A1
+
+I=139
+KEY=64FD310AF27CF98C1A948139F3FB4C36400154C0CEF44863
+IV=EBCB744B477F25E635FE5017C0AB5863
+CT=F0143DD4EC3A85F9FA4D5579BD7268A1
+PT=C5C1FED629BF81EE343E4DAEE6BC4D44
+
+I=140
+KEY=9390B012FA7D48D9DF557FEFDA44CDD8743F196E28480527
+IV=7AF352D33C08F3FEF76D81180801B155
+CT=C5C1FED629BF81EE343E4DAEE6BC4D44
+PT=26C4460F0B79E16263C38C240C276E5C
+
+I=141
+KEY=F578E5DF6818CB58F99139E0D13D2CBA17FC954A246F6B7B
+IV=05DA148A4EB4D12966E855CD92658381
+CT=26C4460F0B79E16263C38C240C276E5C
+PT=E0E249ADB3A39EE2BB48959426874123
+
+I=142
+KEY=F23F67282BAFE10E1973704D629EB258ACB400DE02E82A58
+IV=7748B1652DE54EF9074782F743B72A56
+CT=E0E249ADB3A39EE2BB48959426874123
+PT=C2299AAE24C941DC44E5D492BC492FED
+
+I=143
+KEY=5CAC16BD99EC5067DB5AEAE34657F384E851D44CBEA105B5
+IV=4F599B9C20378305AE937195B243B169
+CT=C2299AAE24C941DC44E5D492BC492FED
+PT=780DA1D6FD961DA4756375A15B8BA620
+
+I=144
+KEY=9FF7C1766F7F6F9FA3574B35BBC1EE209D32A1EDE52AA395
+IV=044A8C7FFE220414C35BD7CBF6933FF8
+CT=780DA1D6FD961DA4756375A15B8BA620
+PT=E63FE8BE6566E9ECCCDBEC442BCCCBD5
+
+I=145
+KEY=3EA408C4CD15E6F24568A38BDEA707CC51E94DA9CEE66840
+IV=05DE81CD5892F1FEA153C9B2A26A896D
+CT=E63FE8BE6566E9ECCCDBEC442BCCCBD5
+PT=19F5E5DDDF0F6FABA9B16B732C6058B8
+
+I=146
+KEY=29FF0DD567A810385C9D465601A86867F85826DAE28630F8
+IV=0A2A8BF3BE53E2B5175B0511AABDF6CA
+CT=19F5E5DDDF0F6FABA9B16B732C6058B8
+PT=41FCD9F8972431F43669863F37B4A18C
+
+I=147
+KEY=842E4C2F46849E731D619FAE968C5993CE31A0E5D5329174
+IV=1EABD419CA4C0D0BADD141FA212C8E4B
+CT=41FCD9F8972431F43669863F37B4A18C
+PT=9857CFE1CFE1046F88DF3EB8ECC92E40
+
+I=148
+KEY=8EE3344CCB9DE2038536504F596D5DFC46EE9E5D39FBBF34
+IV=FA266CF1AF82A2250ACD78638D197C70
+CT=9857CFE1CFE1046F88DF3EB8ECC92E40
+PT=DE4C55865FB82BDA1FC0D024791C1B22
+
+I=149
+KEY=DEEEC86215A6098D5B7A05C906D57626592E4E7940E7A416
+IV=F9B4CFCA36A1B0AB500DFC2EDE3BEB8E
+CT=DE4C55865FB82BDA1FC0D024791C1B22
+PT=077F866BF30097D12650855C71B7DB9C
+
+I=150
+KEY=50872D11A2E463D65C0583A2F5D5E1F77F7ECB2531507F8A
+IV=53D4E4CE2C06FCC38E69E573B7426A5B
+CT=077F866BF30097D12650855C71B7DB9C
+PT=670BBCB81CDE03B883D9B784124F5851
+
+I=151
+KEY=7DE3AF7C8550901C3B0E3F1AE90BE24FFCA77CA1231F27DB
+IV=C26330B1219C4B4A2D64826D27B4F3CA
+CT=670BBCB81CDE03B883D9B784124F5851
+PT=D6141C300F5E5119E1B5F4BBF415A6DD
+
+I=152
+KEY=BB126D64220A8DB9ED1A232AE655B3561D12881AD70A8106
+IV=74D773D0F053239CC6F1C218A75A1DA5
+CT=D6141C300F5E5119E1B5F4BBF415A6DD
+PT=8F742130206F1047FE9CAAE4F2C31B19
+
+I=153
+KEY=9845C3A02214A55D626E021AC63AA311E38E22FE25C99A1F
+IV=7EC0B4E8BD4BD3EB2357AEC4001E28E4
+CT=8F742130206F1047FE9CAAE4F2C31B19
+PT=47D0D28AF3164CC77FBAB5C015CAC1C9
+
+I=154
+KEY=BBC47FAB874E0ED425BED090352CEFD69C34973E30035BD6
+IV=833EC00D894BD8502381BC0BA55AAB89
+CT=47D0D28AF3164CC77FBAB5C015CAC1C9
+PT=3202B04CFC260747BF839FF754A01E26
+
+I=155
+KEY=BCC028DA5F286DE017BC60DCC90AE89123B708C964A345F0
+IV=8BCC8079D2175F4407045771D8666334
+CT=3202B04CFC260747BF839FF754A01E26
+PT=75E9FBADAD8885FB2398427EE94C5899
+
+I=156
+KEY=352B0CD3E3BA0EB462559B7164826D6A002F4AB78DEF1D69
+IV=0B159F18C1F33EA389EB2409BC926354
+CT=75E9FBADAD8885FB2398427EE94C5899
+PT=90DA906982058C84D2E75B5DAE0EA756
+
+I=157
+KEY=6F32D4393B37EA77F28F0B18E687E1EED2C811EA23E1BA3F
+IV=2F5C35DA76038E4F5A19D8EAD88DE4C3
+CT=90DA906982058C84D2E75B5DAE0EA756
+PT=705C22072FDFB807A49BAE0FD4D254AF
+
+I=158
+KEY=5740616769DDF57482D3291FC95859E97653BFE5F733EE90
+IV=B276B0CE56828D683872B55E52EA1F03
+CT=705C22072FDFB807A49BAE0FD4D254AF
+PT=A966EE217CF2BDBC17A0BB55AE769FEB
+
+I=159
+KEY=C9E379BDBC05CC402BB5C73EB5AAE45561F304B05945717B
+IV=E1F41EF2147CB5CE9EA318DAD5D83934
+CT=A966EE217CF2BDBC17A0BB55AE769FEB
+PT=239D761F1F0437935464C4959546B6BB
+
+I=160
+KEY=7B2C4F503FCC91AE0828B121AAAED3C63597C025CC03C7C0
+IV=6F90097C7822030DB2CF36ED83C95DEE
+CT=239D761F1F0437935464C4959546B6BB
+PT=499477B6476BA58CAEF81290ABDD46C4
+
+I=161
+KEY=42BC1C4F29D1801D41BCC697EDC5764A9B6FD2B567DE8104
+IV=1571EE53AE1ACAEF3990531F161D11B3
+CT=499477B6476BA58CAEF81290ABDD46C4
+PT=ACC1FB947EB4C7F115871859CD254D96
+
+I=162
+KEY=9BE24C041BF4DEECED7D3D039371B1BB8EE8CAECAAFBCC92
+IV=E24F4DBEF2122A73D95E504B32255EF1
+CT=ACC1FB947EB4C7F115871859CD254D96
+PT=85DC9D7ADF342B0733CF9812CFD58F0A
+
+I=163
+KEY=83BEBEB5727649F268A1A0794C459ABCBD2752FE652E4398
+IV=AF0690E77B1F140B185CF2B16982971E
+CT=85DC9D7ADF342B0733CF9812CFD58F0A
+PT=7ED8B4DCBD1D13BEA5C819E99ECF75AA
+
+I=164
+KEY=7020802D561D88AD167914A5F158890218EF4B17FBE13632
+IV=F0AC93D8DDD31D5BF39E3E98246BC15F
+CT=7ED8B4DCBD1D13BEA5C819E99ECF75AA
+PT=C81F0464C2DE212229370C7A4ED2E890
+
+I=165
+KEY=39F8EA2D638410ABDE6610C13386A82031D8476DB533DEA2
+IV=FD6338FAE6F6B00B49D86A0035999806
+CT=C81F0464C2DE212229370C7A4ED2E890
+PT=23A0FA99C632BCC62A035A09514C3EBA
+
+I=166
+KEY=52FA33F30EFD8D0FFDC6EA58F5B414E61BDB1D64E47FE018
+IV=04C6E0136D8E04C16B02D9DE6D799DA4
+CT=23A0FA99C632BCC62A035A09514C3EBA
+PT=9F7F1081AE4B6AD51D395D764D2D5B68
+
+I=167
+KEY=95C21BD9257B233A62B9FAD95BFF7E3306E24012A952BB70
+IV=72410E03AAE65889C738282A2B86AE35
+CT=9F7F1081AE4B6AD51D395D764D2D5B68
+PT=5F088092968BF4AF04BF862A6721DF2B
+
+I=168
+KEY=058F749326AE1DD53DB17A4BCD748A9C025DC638CE73645B
+IV=D678325E266D12D7904D6F4A03D53EEF
+CT=5F088092968BF4AF04BF862A6721DF2B
+PT=15670F60D1D70E129418AC14A425DD70
+
+I=169
+KEY=23D2D59C5EF4AF3D28D6752B1CA3848E96456A2C6A56B92B
+IV=BB7B672A91E9A61A265DA10F785AB2E8
+CT=15670F60D1D70E129418AC14A425DD70
+PT=3273AC9D250F729AE790A941739C79BF
+
+I=170
+KEY=E11B1F94517914C81AA5D9B639ACF61471D5C36D19CAC094
+IV=AB84F623EFA11728C2C9CA080F8DBBF5
+CT=3273AC9D250F729AE790A941739C79BF
+PT=9B135880CB56A8E6CF3A364CC6E02175
+
+I=171
+KEY=66F867085DBE626581B68136F2FA5EF2BEEFF521DF2AE1E1
+IV=01ED899C8DC9C09E87E3789C0CC776AD
+CT=9B135880CB56A8E6CF3A364CC6E02175
+PT=681D6FC5447CCFE1152156CFF6172B6A
+
+I=172
+KEY=98505FCD27DAB39EE9ABEEF3B6869113ABCEA3EE293DCA8B
+IV=A58C8285C31035B1FEA838C57A64D1FB
+CT=681D6FC5447CCFE1152156CFF6172B6A
+PT=6E30DF3FBD67A5FD491E315EF3A268A0
+
+I=173
+KEY=9F904A41C19B57A9879B31CC0BE134EEE2D092B0DA9FA22B
+IV=6F46DCB3A84FD96907C0158CE641E437
+CT=6E30DF3FBD67A5FD491E315EF3A268A0
+PT=5B4980E24D8F9CABE017991326FBBE95
+
+I=174
+KEY=A330D5A6779731D6DCD2B12E466EA84502C70BA3FC641CBE
+IV=C5BDAB77E0CA95463CA09FE7B60C667F
+CT=5B4980E24D8F9CABE017991326FBBE95
+PT=7324530BF94BD80D286C9BE2FE4113D3
+
+I=175
+KEY=20F008DE76D7968AAFF6E225BF2570482AAB904102250F6D
+IV=32F5EC4AEBB997C583C0DD780140A75C
+CT=7324530BF94BD80D286C9BE2FE4113D3
+PT=B163425AB21DF6AFBD2C7000E777E902
+
+I=176
+KEY=0F48153B232E71F41E95A07F0D3886E79787E041E552E66F
+IV=3D1854E0C481B28E2FB81DE555F9E77E
+CT=B163425AB21DF6AFBD2C7000E777E902
+PT=EB1A6C86C3811E3081325F35BA7F2DCA
+
+I=177
+KEY=96EE2134FD40CA34F58FCCF9CEB998D716B5BF745F2DCBA5
+IV=8629366A8B8E266499A6340FDE6EBBC0
+CT=EB1A6C86C3811E3081325F35BA7F2DCA
+PT=E9675AF0035C3F8E9D5E58D0652BF5C7
+
+I=178
+KEY=BF754C828BFE309B1CE89609CDE5A7598BEBE7A43A063E62
+IV=566D5FCEC3FF7D43299B6DB676BEFAAF
+CT=E9675AF0035C3F8E9D5E58D0652BF5C7
+PT=24B4DA85EEFAA123948C6B5E0E07EB08
+
+I=179
+KEY=F0223B4AF5C885B4385C4C8C231F067A1F678CFA3401D56A
+IV=67B98EC651B057104F5777C87E36B52F
+CT=24B4DA85EEFAA123948C6B5E0E07EB08
+PT=753CFEBBB9E623453B8BB2976B8D7BD4
+
+I=180
+KEY=04665169E091DEF74D60B2379AF9253F24EC3E6D5F8CAEBE
+IV=BC3806A9E56A1DACF4446A2315595B43
+CT=753CFEBBB9E623453B8BB2976B8D7BD4
+PT=6949284723B4F795D530B366FAE70876
+
+I=181
+KEY=9CABB1CFD4E46F8324299A70B94DD2AAF1DC8D0BA56BA6C8
+IV=8C864563BB8D45A098CDE0A63475B174
+CT=6949284723B4F795D530B366FAE70876
+PT=D43FED9A25C62349787F0336BFFBBFEB
+
+I=182
+KEY=4407065E88AE79D9F01677EA9C8BF1E389A38E3D1A901923
+IV=539CC5888B34198FD8ACB7915C4A165A
+CT=D43FED9A25C62349787F0336BFFBBFEB
+PT=030733E175916579F582A778B261DA1C
+
+I=183
+KEY=84D1EE80E8FA54DEF311440BE91A949A7C212945A8F1C33F
+IV=78306F4F56DEF759C0D6E8DE60542D07
+CT=030733E175916579F582A778B261DA1C
+PT=F7B1ABE4B4AE3CB726F9A88B06D4552A
+
+I=184
+KEY=E885BEA6176A75D804A0EFEF5DB4A82D5AD881CEAE259615
+IV=3AC80B78F744208A6C545026FF902106
+CT=F7B1ABE4B4AE3CB726F9A88B06D4552A
+PT=DA984A2C346A4B758E066EB509079168
+
+I=185
+KEY=2E0317B2DB3F9893DE38A5C369DEE358D4DEEF7BA722077D
+IV=FC74E03B1068A6FEC686A914CC55ED4B
+CT=DA984A2C346A4B758E066EB509079168
+PT=21F473636EF27B91F29BB1CE67908763
+
+I=186
+KEY=850E1B37E1F7DD89FFCCD6A0072C98C926455EB5C0B2801E
+IV=7DFD76EE7EF97796AB0D0C853AC8451A
+CT=21F473636EF27B91F29BB1CE67908763
+PT=9EEF6E211CC8EDBD3C4FBE3E14B13C70
+
+I=187
+KEY=655D365D66CAA5C36123B8811BE475741A0AE08BD403BC6E
+IV=33318C04CC0B3CBDE0532D6A873D784A
+CT=9EEF6E211CC8EDBD3C4FBE3E14B13C70
+PT=8AB49333CA7B2E58E7B24536BB34DEE7
+
+I=188
+KEY=BE3C315647F981DCEB972BB2D19F5B2CFDB8A5BD6F376289
+IV=79D06A0D66B5C2B1DB61070B2133241F
+CT=8AB49333CA7B2E58E7B24536BB34DEE7
+PT=323D1E775FD729005DA7A2853A855ED4
+
+I=189
+KEY=3126E544A65724C4D9AA35C58E48722CA01F073855B23C5D
+IV=CC5C9D95685AF1228F1AD412E1AEA518
+CT=323D1E775FD729005DA7A2853A855ED4
+PT=E283016FEDADEBA2BEC7ADB5A8DEA8B9
+
+I=190
+KEY=BCF052AFAFA4852D3B2934AA63E5998E1ED8AA8DFD6C94E4
+IV=2753144E0A26D9FE8DD6B7EB09F3A1E9
+CT=E283016FEDADEBA2BEC7ADB5A8DEA8B9
+PT=9A9BB977D53BBD47550DC60A49AFA0FA
+
+I=191
+KEY=ECB724A85CBC7B58A1B28DDDB6DE24C94BD56C87B4C3341E
+IV=27F910046A94AA3B50477607F318FE75
+CT=9A9BB977D53BBD47550DC60A49AFA0FA
+PT=AF4C7AC3B02C1B077E8F97B59AE52A21
+
+I=192
+KEY=BCA9E9794F9004AB0EFEF71E06F23FCE355AFB322E261E3F
+IV=8AF06705FE272571501ECDD1132C7FF3
+CT=AF4C7AC3B02C1B077E8F97B59AE52A21
+PT=A97DEE2A64DFA7C198B6A4F21E80F7DF
+
+I=193
+KEY=10DCC14B9A309E25A7831934622D980FADEC5FC030A6E9E0
+IV=B04E1C6FC657B8AEAC752832D5A09A8E
+CT=A97DEE2A64DFA7C198B6A4F21E80F7DF
+PT=34E8228A24C7A16F9ED3F4B9A94AA70D
+
+I=194
+KEY=9CB6EE6AAEFAFBED936B3BBE46EA3960333FAB7999EC4EED
+IV=6A966EBB8F80A1608C6A2F2134CA65C8
+CT=34E8228A24C7A16F9ED3F4B9A94AA70D
+PT=99E6CA896906CBAA9B8D01155D1DB162
+
+I=195
+KEY=461916712E8BD6F10A8DF1372FECF2CAA8B2AA6CC4F1FF8F
+IV=EAF849974783FAA7DAAFF81B80712D1C
+CT=99E6CA896906CBAA9B8D01155D1DB162
+PT=6009B53EB4690C1F1F10639F1FD7640A
+
+I=196
+KEY=5B9B91A966F9CE146A8444099B85FED5B7A2C9F3DB269B85
+IV=3FB045D182F781EB1D8287D8487218E5
+CT=6009B53EB4690C1F1F10639F1FD7640A
+PT=88ED4BC34A27F4C4B480B99857EBF541
+
+I=197
+KEY=404F7D8B0E966F02E2690FCAD1A20A110322706B8CCD6EC4
+IV=49C0F4571BAEBE4C1BD4EC22686FA116
+CT=88ED4BC34A27F4C4B480B99857EBF541
+PT=B88F0E3E01FEDF97766AC6B762D2EBC3
+
+I=198
+KEY=CB2EA99F330A3A865AE601F4D05CD5867548B6DCEE1F8507
+IV=2518DA0D88C02EC38B61D4143D9C5584
+CT=B88F0E3E01FEDF97766AC6B762D2EBC3
+PT=C1C167FF37E89937DCB8D79C9BC9EC74
+
+I=199
+KEY=913C795CF72CD1219B27660BE7B44CB1A9F0614075D66973
+IV=37769A59390261FB5A12D0C3C426EBA7
+CT=C1C167FF37E89937DCB8D79C9BC9EC74
+PT=64D912270A1E60192CDAAD8168219E56
+
+I=200
+KEY=05F19DF919E44144FFFE742CEDAA2CA8852ACCC11DF7F725
+IV=63E9D4D1BDD7FEAD94CDE4A5EEC89065
+CT=64D912270A1E60192CDAAD8168219E56
+PT=C9AD2DBB1C686A67A3E21A5659576A2B
+
+I=201
+KEY=099D0DCE5E4E194236535997F1C246CF26C8D69744A09D0E
+IV=A01E3F917EF4652F0C6C903747AA5806
+CT=C9AD2DBB1C686A67A3E21A5659576A2B
+PT=244C740B4B136C6C480D0147163868D1
+
+I=202
+KEY=EA1F242E9C75C712121F2D9CBAD12AA36EC5D7D05298F5DF
+IV=C9D2288C473BCB3EE38229E0C23BDE50
+CT=244C740B4B136C6C480D0147163868D1
+PT=A6B125A9C570CC3ECBB5D302ADB96E34
+
+I=203
+KEY=CD5D7C91FBDC81A1B4AE08357FA1E69DA57004D2FF219BEB
+IV=871F525F8ED73B7F274258BF67A946B3
+CT=A6B125A9C570CC3ECBB5D302ADB96E34
+PT=0F9862A4A21E1FB365135C07577FB3EE
+
+I=204
+KEY=F7D9B8C22BDC8005BB366A91DDBFF92EC06358D5A85E2805
+IV=01BB0A9A8737C19D3A84C453D00001A4
+CT=0F9862A4A21E1FB365135C07577FB3EE
+PT=D833DB436E1751B882D03FADF683690B
+
+I=205
+KEY=83F81E3CED72F22F6305B1D2B3A8A89642B367785EDD410E
+IV=80E0E7001CCA60CA7421A6FEC6AE722A
+CT=D833DB436E1751B882D03FADF683690B
+PT=0AE2C64D2C577C420F26F2F48AA58D62
+
+I=206
+KEY=63310E5F2F8F0E0769E7779F9FFFD4D44D95958CD478CC6C
+IV=57E54995CDC9417DE0C91063C2FDFC28
+CT=0AE2C64D2C577C420F26F2F48AA58D62
+PT=B0E2976AA3891A2C71AFEB063E3C4383
+
+I=207
+KEY=F3AE2989B3980DC9D905E0F53C76CEF83C3A7E8AEA448FEF
+IV=999DD6C2B1C528E2909F27D69C1703CE
+CT=B0E2976AA3891A2C71AFEB063E3C4383
+PT=16F8A305177ECDBA15403FE5D8EEF60D
+
+I=208
+KEY=52CF17D8DEA4CE5ACFFD43F02B080342297A416F32AA79E2
+IV=C9F5BC961057F845A1613E516D3CC393
+CT=16F8A305177ECDBA15403FE5D8EEF60D
+PT=A607A3EE165E82711B30B44CF4E0C4CF
+
+I=209
+KEY=E22ADE79E75FE58E69FAE01E3D568133324AF523C64ABD2D
+IV=E153F25DD207351AB0E5C9A139FB2BD4
+CT=A607A3EE165E82711B30B44CF4E0C4CF
+PT=5191CDD0D077AD6BE956AF8E8E39FECA
+
+I=210
+KEY=38C58EA4EA1E8D4C386B2DCEED212C58DB1C5AAD487343E7
+IV=F55357187F06B142DAEF50DD0D4168C2
+CT=5191CDD0D077AD6BE956AF8E8E39FECA
+PT=F63A42508522E5F09C31F160298E8E6F
+
+I=211
+KEY=8C29CD4F1330EF25CE516F9E6803C9A8472DABCD61FDCD88
+IV=2CBD520E6F6F89C7B4EC43EBF92E6269
+CT=F63A42508522E5F09C31F160298E8E6F
+PT=E58ED2EA8671DC5D527CDE01C6D9655D
+
+I=212
+KEY=3650C9671F38CD752BDFBD74EE7215F5155175CCA724A8D5
+IV=73CA969AECA5574BBA7904280C082250
+CT=E58ED2EA8671DC5D527CDE01C6D9655D
+PT=5FFCACC68357B6709F5B10D48C65EA40
+
+I=213
+KEY=6F68A078A75FF5A1742311B26D25A3858A0A65182B414295
+IV=DEA2D7D8F9FE3E7D5938691FB86738D4
+CT=5FFCACC68357B6709F5B10D48C65EA40
+PT=10BBA695F25C1F9412DB80F59F937F84
+
+I=214
+KEY=9E08E5F9EEC5A7606498B7279F79BC1198D1E5EDB4D23D11
+IV=20E4DE61513233E5F1604581499A52C1
+CT=10BBA695F25C1F9412DB80F59F937F84
+PT=36CAF539734BCAF8250595E5E5DB3E94
+
+I=215
+KEY=F72A5636B3A2D23B5252421EEC3276E9BDD4700851090385
+IV=9DEBE05128A2A1A06922B3CF5D67755B
+CT=36CAF539734BCAF8250595E5E5DB3E94
+PT=C64074C9A34850C6FD1B12CD8AE9EF30
+
+I=216
+KEY=D74FABF587AB10AA941236D74F7A262F40CF62C5DBE0ECB5
+IV=DEF3A637247B78C02065FDC33409C291
+CT=C64074C9A34850C6FD1B12CD8AE9EF30
+PT=DF663CE4199BC64ACB9B6F99D69EC679
+
+I=217
+KEY=8D12BAEA80612A284B740A3356E1E0658B540D5C0D7E2ACC
+IV=7D9C0365E66F1A355A5D111F07CA3A82
+CT=DF663CE4199BC64ACB9B6F99D69EC679
+PT=CD1BCBDCE7F8C008177E25B83604EE83
+
+I=218
+KEY=57B4196767474175866FC1EFB119206D9C2A28E43B7AC44F
+IV=41846FA05FC28ABCDAA6A38DE7266B5D
+CT=CD1BCBDCE7F8C008177E25B83604EE83
+PT=CD7E96FE44368C4AD22E9D4F6BE3C2C2
+
+I=219
+KEY=CBA15BF34D728F0E4B115711F52FAC274E04B5AB5099068D
+IV=873A6522E20108C09C1542942A35CE7B
+CT=CD7E96FE44368C4AD22E9D4F6BE3C2C2
+PT=BCC88D6EAF2E41D9AA6E7C91DADCF92E
+
+I=220
+KEY=D3071140E7C7E244F7D9DA7F5A01EDFEE46AC93A8A45FFA3
+IV=A50F782EA949C2A718A64AB3AAB56D4A
+CT=BCC88D6EAF2E41D9AA6E7C91DADCF92E
+PT=1FFD3EC8E0D0AD8F3D23961703C0C445
+
+I=221
+KEY=3F44AB6E12394D24E824E4B7BAD14071D9495F2D89853BE6
+IV=501500DC8A97D00BEC43BA2EF5FEAF60
+CT=1FFD3EC8E0D0AD8F3D23961703C0C445
+PT=1D3D85A9A4BF101E12CC79640D716AC6
+
+I=222
+KEY=D6B97A7D0CEBEA71F519611E1E6E506FCB85264984F45120
+IV=84933D2D2F1F6C13E9FDD1131ED2A755
+CT=1D3D85A9A4BF101E12CC79640D716AC6
+PT=A2228D0483F9CF74CAA301FD30D7DB68
+
+I=223
+KEY=E86CCBF22BAF7B31573BEC1A9D979F1B012627B4B4238A48
+IV=4AE5BFEB7168981E3ED5B18F27449140
+CT=A2228D0483F9CF74CAA301FD30D7DB68
+PT=D43E1D2C7447B7C08BCA25F8371AEECF
+
+I=224
+KEY=0279786975DB97998305F136E9D028DB8AEC024C83396487
+IV=2FC19D77503C0296EA15B39B5E74ECA8
+CT=D43E1D2C7447B7C08BCA25F8371AEECF
+PT=4F97B6C0B7D10763CD5CE3A45855FEC0
+
+I=225
+KEY=7F842708B71AD43BCC9247F65E012FB847B0E1E8DB6C9A47
+IV=BAC3ED277430C4537DFD5F61C2C143A2
+CT=4F97B6C0B7D10763CD5CE3A45855FEC0
+PT=067B1521895AE654CA0C20492A9714B8
+
+I=226
+KEY=2FA21F709793A1C7CAE952D7D75BC9EC8DBCC1A1F1FB8EFF
+IV=66014BDC0AD70ABB50263878208975FC
+CT=067B1521895AE654CA0C20492A9714B8
+PT=E07E7A1D3F39E45E3A755A82EE3C2EBC
+
+I=227
+KEY=671468BAD93EDBD32A9728CAE8622DB2B7C99B231FC7A043
+IV=47BFF88E3EC2E8DC48B677CA4EAD7A14
+CT=E07E7A1D3F39E45E3A755A82EE3C2EBC
+PT=0933D51670E8918147A56816B838BC74
+
+I=228
+KEY=9749A2F6B448445023A4FDDC988ABC33F06CF335A7FF1C37
+IV=58F8C33F4725EED2F05DCA4C6D769F83
+CT=0933D51670E8918147A56816B838BC74
+PT=E90570CDFC2CDCC99826780CA7CD7A1C
+
+I=229
+KEY=C43D753C2489B403CAA18D1164A660FA684A8B390032662B
+IV=C4027E5BF29E96A65374D7CA90C1F053
+CT=E90570CDFC2CDCC99826780CA7CD7A1C
+PT=65B6C303491459554CDDA630AAB36C12
+
+I=230
+KEY=32F2C804DF89C908AF174E122DB239AF24972D09AA810A39
+IV=51DE94724DCE9B10F6CFBD38FB007D0B
+CT=65B6C303491459554CDDA630AAB36C12
+PT=A0B1694685785EFBDD6DB8E4FC312BC4
+
+I=231
+KEY=9431549183D690920FA62754A8CA6754F9FA95ED56B021FD
+IV=5CBDC9F06F45D2F5A6C39C955C5F599A
+CT=A0B1694685785EFBDD6DB8E4FC312BC4
+PT=C271A8F639D1A293F4B8899428F618C2
+
+I=232
+KEY=0AA1211F2A2134DACDD78FA2911BC5C70D421C797E46393F
+IV=E52D7ACAF5DFAF799E90758EA9F7A448
+CT=C271A8F639D1A293F4B8899428F618C2
+PT=AB7968C2A1859D5AEBFAEB201910B672
+
+I=233
+KEY=88BFBDDC6D21FC0E66AEE760309E589DE6B8F75967568F4D
+IV=15AF9C49191BF995821E9CC34700C8D4
+CT=AB7968C2A1859D5AEBFAEB201910B672
+PT=59D394BB9C41BE21C050A9DF2DD94C2B
+
+I=234
+KEY=05AB922FA8B6F5FF3F7D73DBACDFE6BC26E85E864A8FC366
+IV=0FB568270892E7A98D142FF3C59709F1
+CT=59D394BB9C41BE21C050A9DF2DD94C2B
+PT=43F89BAE0DCCB0EAF30411E6239A753C
+
+I=235
+KEY=7A7ED7932DED53767C85E875A1135656D5EC4F606915B65A
+IV=48F1E1DAEE9C16CD7FD545BC855BA689
+CT=43F89BAE0DCCB0EAF30411E6239A753C
+PT=8196A2F49E2508443F86B294D71A5D5E
+
+I=236
+KEY=8955F595C21BF3AAFD134A813F365E12EA6AFDF4BE0FEB04
+IV=B3DEB1ED557CB477F32B2206EFF6A0DC
+CT=8196A2F49E2508443F86B294D71A5D5E
+PT=5ED45F8741E7FC5C77CAACA9D3DFA26D
+
+I=237
+KEY=09205C9C2A528A5BA3C715067ED1A24E9DA0515D6DD04969
+IV=3742941BC0992AAC8075A909E84979F1
+CT=5ED45F8741E7FC5C77CAACA9D3DFA26D
+PT=F60C9F9616A03B40655CB733EE1C3B68
+
+I=238
+KEY=46DAA0A9A034745355CB8A906871990EF8FCE66E83CC7201
+IV=A3E1EA7D9E5BA6CE4FFAFC358A66FE08
+CT=F60C9F9616A03B40655CB733EE1C3B68
+PT=E73F7E14A3A245B1E594F659D996ED06
+
+I=239
+KEY=DA145A69C9D459E1B2F4F484CBD3DCBF1D6810375A5A9F07
+IV=F5D4EB0EAB3486D29CCEFAC069E02DB2
+CT=E73F7E14A3A245B1E594F659D996ED06
+PT=52651C2039168170765B235D85BF6CEC
+
+I=240
+KEY=61CD045E05969B9FE091E8A4F2C55DCF6B33336ADFE5F3EB
+IV=F7162437A85A186ABBD95E37CC42C27E
+CT=52651C2039168170765B235D85BF6CEC
+PT=665C920C4BB95B5C716D60AE9C30DB1B
+
+I=241
+KEY=BDF9F289D095660D86CD7AA8B97C06931A5E53C443D528F0
+IV=ADD7416105DB0CF0DC34F6D7D503FD92
+CT=665C920C4BB95B5C716D60AE9C30DB1B
+PT=F6E1D36CF7D41F70885587A85B897EA2
+
+I=242
+KEY=4CBAF7692571D8C5702CA9C44EA819E3920BD46C185C5652
+IV=9FBF3815905FCD9FF14305E0F5E4BEC8
+CT=F6E1D36CF7D41F70885587A85B897EA2
+PT=137DB7F20F98671E37F55E401D0482E2
+
+I=243
+KEY=CEBF572BB09CC72963511E3641307EFDA5FE8A2C0558D4B0
+IV=0C3951BDCA9582CA8205A04295ED1FEC
+CT=137DB7F20F98671E37F55E401D0482E2
+PT=72125C79A48573158496EFCC5CA552D4
+
+I=244
+KEY=0D8978CF8179CBBF1143424FE5B50DE8216865E059FD8664
+IV=898422AB0DB951B1C3362FE431E50C96
+CT=72125C79A48573158496EFCC5CA552D4
+PT=6B12016832DE435A963FFFA857824CF7
+
+I=245
+KEY=180D2DA794FEAF777A514327D76B4EB2B7579A480E7FCA93
+IV=0B47A508EAD8008015845568158764C8
+CT=6B12016832DE435A963FFFA857824CF7
+PT=18693A241FB5687CF3A793B9B7EE4B15
+
+I=246
+KEY=3D6C36453DCA611462387903C8DE26CE44F009F1B9918186
+IV=857CC19C3E72C1AD25611BE2A934CE63
+CT=18693A241FB5687CF3A793B9B7EE4B15
+PT=4E04BD363AFC26BDDD3D98892A7C705A
+
+I=247
+KEY=8B626E8D8E075BCE2C3CC435F222007399CD917893EDF1DC
+IV=6E4FCD034F6E2AF5B60E58C8B3CD3ADA
+CT=4E04BD363AFC26BDDD3D98892A7C705A
+PT=06FB2C371C3F54518AA0A2766CE1CCF3
+
+I=248
+KEY=A5ECEB5BAE22C2E72AC7E802EE1D5422136D330EFF0C3D2F
+IV=4A23E1EFBB43855E2E8E85D620259929
+CT=06FB2C371C3F54518AA0A2766CE1CCF3
+PT=D7DE2C298EB1EF273A6386986BDEC555
+
+I=249
+KEY=B25537EEFD5BDA7AFD19C42B60ACBB05290EB59694D2F87A
+IV=9034BBDBF74A369E17B9DCB55379189D
+CT=D7DE2C298EB1EF273A6386986BDEC555
+PT=0F4A1CEA83DA845DEC063ADFF173F424
+
+I=250
+KEY=39FEF1C45697DABCF253D8C1E3763F58C5088F4965A10C5E
+IV=2B5EF64E50A2CF5F8BABC62AABCC00C6
+CT=0F4A1CEA83DA845DEC063ADFF173F424
+PT=CE27F8AF55009D3658D166B960CA12D6
+
+I=251
+KEY=5657BBA1106032F13C74206EB676A26E9DD9E9F0056B1E88
+IV=CE96953F749BBFD66FA94A6546F7E84D
+CT=CE27F8AF55009D3658D166B960CA12D6
+PT=BF1458E052637EFC0EEF352621606029
+
+I=252
+KEY=A1BC53DEFD62921A8360788EE415DC929336DCD6240B7EA1
+IV=B944FC42142E4940F7EBE87FED02A0EB
+CT=BF1458E052637EFC0EEF352621606029
+PT=E4D96706DB5B0DA8FA429BB65BFBE4D8
+
+I=253
+KEY=DAC8C0328BA4104167B91F883F4ED13A697447607FF09A79
+IV=A8D8E3A3BB687ECC7B7493EC76C6825B
+CT=E4D96706DB5B0DA8FA429BB65BFBE4D8
+PT=1B11FF1367FE94F7759D1BEC40B8FDCC
+
+I=254
+KEY=03AE3AA5E62CA4927CA8E09B58B045CD1CE95C8C3F4867B5
+IV=35D7DB1466E14E3ED966FA976D88B4D3
+CT=1B11FF1367FE94F7759D1BEC40B8FDCC
+PT=0989D688C947C616AC13B63892E35E74
+
+I=255
+KEY=EAD5A60BB601C1147521361391F783DBB0FAEAB4ADAB39C1
+IV=59BA56CC11EFA9A2E97B9CAE502D6586
+CT=0989D688C947C616AC13B63892E35E74
+PT=978C150575871FB2C8847AA0CB092108
+
+I=256
+KEY=C608EE8A971A0383E2AD2316E4709C69787E901466A218C9
+IV=253A79448D79B0B72CDD4881211BC297
+CT=978C150575871FB2C8847AA0CB092108
+PT=D08629CCCF6B869B10768DE9E2984B2E
+
+I=257
+KEY=D8EB4FC4230D3E39322B0ADA2B1B1AF268081DFD843A53E7
+IV=E9A7FDB26A37B6601EE3A14EB4173DBA
+CT=D08629CCCF6B869B10768DE9E2984B2E
+PT=E320AECF3803401AB95E09EB50A6EDA5
+
+I=258
+KEY=E3F18E12233B5A30D10BA41513185AE8D1561416D49CBE42
+IV=4C6B62E3E6658BE73B1AC1D600366409
+CT=E320AECF3803401AB95E09EB50A6EDA5
+PT=D29E97683C9989C75D5D73EAADC23EE2
+
+I=259
+KEY=7D9DEAA58D97A2FC0395337D2F81D32F8C0B67FC795E80A0
+IV=414A2961119CE4D79E6C64B7AEACF8CC
+CT=D29E97683C9989C75D5D73EAADC23EE2
+PT=8D859D878DF32FDD26AF4984D48A1BD2
+
+I=260
+KEY=E4A19E3554E8D73B8E10AEFAA272FCF2AAA42E78ADD49B72
+IV=9DF8066FCF854065993C7490D97F75C7
+CT=8D859D878DF32FDD26AF4984D48A1BD2
+PT=7B524B71439722F0555D4681F7EEAAC9
+
+I=261
+KEY=0C93CDDA4435E903F542E58BE1E5DE02FFF968F95A3A31BB
+IV=9529BF1B1ACEEDA5E83253EF10DD3E38
+CT=7B524B71439722F0555D4681F7EEAAC9
+PT=8C8ECC9829F06F73497EA90D48CD7FC5
+
+I=262
+KEY=637747C6EF7B72B579CC2913C815B171B687C1F412F74E7E
+IV=ADC9666D259469516FE48A1CAB4E9BB6
+CT=8C8ECC9829F06F73497EA90D48CD7FC5
+PT=6E416C2563212821F0D8E7D75297B11F
+
+I=263
+KEY=7E4BB22E1A7C4E25178D4536AB349950465F26234060FF61
+IV=C3BE9A54FDDA99731D3CF5E8F5073C90
+CT=6E416C2563212821F0D8E7D75297B11F
+PT=EFC73DFA5FB87EA16284E25D22360C2F
+
+I=264
+KEY=62B7D329DC5EA208F84A78CCF48CE7F124DBC47E6256F34E
+IV=E2145312DF24CBDB1CFC6107C622EC2D
+CT=EFC73DFA5FB87EA16284E25D22360C2F
+PT=1191FC5E2EFA9F19004C7D00E1F4D8B1
+
+I=265
+KEY=039B0E1DE399831EE9DB8492DA7678E82497B97E83A22BFF
+IV=0931D0D100EEB87D612CDD343FC72116
+CT=1191FC5E2EFA9F19004C7D00E1F4D8B1
+PT=717B1B902086B97296B7E97BC01C259E
+
+I=266
+KEY=CB02B3C8CA4A0C9498A09F02FAF0C19AB220500543BE0E61
+IV=65D0C1DFC85C7FB9C899BDD529D38F8A
+CT=717B1B902086B97296B7E97BC01C259E
+PT=569097DA8C43871CC5A55AC150ABCD31
+
+I=267
+KEY=5FFAEE959D35C247CE3008D876B3468677850AC41315C350
+IV=7A4A448600ACA08994F85D5D577FCED3
+CT=569097DA8C43871CC5A55AC150ABCD31
+PT=4046F3DF53DFC1B56400501F08200FE0
+
+I=268
+KEY=0CA33FAAA4B25FEB8E76FB07256C873313855ADB1B35CCB0
+IV=C83E2121AA25A5295359D13F39879DAC
+CT=4046F3DF53DFC1B56400501F08200FE0
+PT=87C5362AAF3F31B05C92189E38FD9C66
+
+I=269
+KEY=5B782B675EE9A8A509B3CD2D8A53B6834F17424523C850D6
+IV=567E0CD5EAFC699457DB14CDFA5BF74E
+CT=87C5362AAF3F31B05C92189E38FD9C66
+PT=03A5CD79734810F4D9559FDC97A4B1A1
+
+I=270
+KEY=B069B5DCAADA727F0A160054F91BA6779642DD99B46CE177
+IV=5397ED8A6DF7641EEB119EBBF433DADA
+CT=03A5CD79734810F4D9559FDC97A4B1A1
+PT=1B1ECDDFD726C66594DF7B050F6758FF
+
+I=271
+KEY=52477DE5EFBAE2621108CD8B2E3D6012029DA69CBB0BB988
+IV=52151355DA4369C8E22EC8394560901D
+CT=1B1ECDDFD726C66594DF7B050F6758FF
+PT=26E9A7A560DD36D9767A51DA06301BBD
+
+I=272
+KEY=6E59FF11BED37F8837E16A2E4EE056CB74E7F746BD3BA235
+IV=FB1A5F8FA1C3D1F43C1E82F451699DEA
+CT=26E9A7A560DD36D9767A51DA06301BBD
+PT=C2FAB5CDDB329F2EA1E1459251A3CB1B
+
+I=273
+KEY=504DE2EC58CE17BBF51BDFE395D2C9E5D506B2D4EC98692E
+IV=6BCD90C4D648AB783E141DFDE61D6833
+CT=C2FAB5CDDB329F2EA1E1459251A3CB1B
+PT=4293D0A26E81DBE9FED6113B1954D59F
+
+I=274
+KEY=CC6C6C4150E763AAB7880F41FB53120C2BD0A3EFF5CCBCB1
+IV=0F61DAA62B7E95A79C218EAD08297411
+CT=4293D0A26E81DBE9FED6113B1954D59F
+PT=5DC81F054088DB9B3D1F8AD4BACC2039
+
+I=275
+KEY=BD3B4967A596578FEA401044BBDBC99716CF293B4F009C88
+IV=0C6435697122955071572526F5713425
+CT=5DC81F054088DB9B3D1F8AD4BACC2039
+PT=B6FB950586C671E968FFC709B79E8AF8
+
+I=276
+KEY=9A08B753E07CD6535CBB85413D1DB87E7E30EE32F89E1670
+IV=377A670B7487B3EB2733FE3445EA81DC
+CT=B6FB950586C671E968FFC709B79E8AF8
+PT=ED69B1E52F5F095EFF0AC73A76039B65
+
+I=277
+KEY=E5FAA83242346B4EB1D234A41242B120813A29088E9D8D15
+IV=DBEEED8784AD80B57FF21F61A248BD1D
+CT=ED69B1E52F5F095EFF0AC73A76039B65
+PT=FBC0C9A6FBC2CCD02BF5A009B43FE903
+
+I=278
+KEY=44770F6B1653E2754A12FD02E9807DF0AACF89013AA26416
+IV=7D9B061A6209E0FAA18DA7595467893B
+CT=FBC0C9A6FBC2CCD02BF5A009B43FE903
+PT=ADBE2B6C2C979C90E019991C5E81F69E
+
+I=279
+KEY=89A3B49BBE885D34E7ACD66EC517E1604AD6101D64239288
+IV=5495C29E4DDA4E26CDD4BBF0A8DBBF41
+CT=ADBE2B6C2C979C90E019991C5E81F69E
+PT=E382D6611C0B2591BE9B7B6BC66D479D
+
+I=280
+KEY=457D838277C2797B042E000FD91CC4F1F44D6B76A24ED515
+IV=0303BB8A65CCE419CCDE3719C94A244F
+CT=E382D6611C0B2591BE9B7B6BC66D479D
+PT=7A39D5BFC7ADB6B7539A1AA45A31A7E5
+
+I=281
+KEY=814AD70FBAF9D8AA7E17D5B01EB17246A7D771D2F87F72F0
+IV=550BD125E57ADE94C437548DCD3BA1D1
+CT=7A39D5BFC7ADB6B7539A1AA45A31A7E5
+PT=3CB8FF426FF48FA93EFAEDC559833C86
+
+I=282
+KEY=89599F584B46337342AF2AF27145FDEF992D9C17A1FC4E76
+IV=45800DE7659A8FD008134857F1BFEBD9
+CT=3CB8FF426FF48FA93EFAEDC559833C86
+PT=2F5C7660310DE65B1C5254E2176A15CA
+
+I=283
+KEY=8EF84BDE14C7412B6DF35C9240481BB4857FC8F5B6965BBC
+IV=5142FFEADEC300C107A1D4865F817258
+CT=2F5C7660310DE65B1C5254E2176A15CA
+PT=7A3056742CF8CFDE9CBEAE32607E8DE3
+
+I=284
+KEY=F076085EE3EA165617C30AE66CB0D46A19C166C7D6E8D65F
+IV=02FBB83EDCB092957E8E4380F72D577D
+CT=7A3056742CF8CFDE9CBEAE32607E8DE3
+PT=B2B7B7551B2A1D59601003C6EDD70A78
+
+I=285
+KEY=7D74D286D9CEC1C3A574BDB3779AC93379D165013B3FDC27
+IV=890E42EAA4C59B078D02DAD83A24D795
+CT=B2B7B7551B2A1D59601003C6EDD70A78
+PT=8B617CCD9B1289F485167DC13126795C
+
+I=286
+KEY=8BA3AA3C04001B9D2E15C17EEC8840C7FCC718C00A19A57B
+IV=F96182D81751ECCAF6D778BADDCEDA5E
+CT=8B617CCD9B1289F485167DC13126795C
+PT=D4800EE4A5E29A18C655AD5CE23063F9
+
+I=287
+KEY=E51B3BF1DF7B0D54FA95CF9A496ADADF3A92B59CE829C682
+IV=46297563D303DF226EB891CDDB7B16C9
+CT=D4800EE4A5E29A18C655AD5CE23063F9
+PT=4A6008072DCEB7602BF120F0984FF1D6
+
+I=288
+KEY=82091A039C558D36B0F5C79D64A46DBF1163956C70663754
+IV=28E82D15BAC860EA671221F2432E8062
+CT=4A6008072DCEB7602BF120F0984FF1D6
+PT=B05CD61BC646851726441B147FBB1AD3
+
+I=289
+KEY=C503B4B113DE349700A91186A2E2E8A837278E780FDD2D87
+IV=342F9FDEEEBE130A470AAEB28F8BB9A1
+CT=B05CD61BC646851726441B147FBB1AD3
+PT=33E1834199EE6CD5C6F950D4823B2337
+
+I=290
+KEY=4B06065B748AFB69334892C73B0C847DF1DEDEAC8DE60EB0
+IV=02928C43C0FF24968E05B2EA6754CFFE
+CT=33E1834199EE6CD5C6F950D4823B2337
+PT=BA0BD1FFA54258361D3A8BD9F3C689E4
+
+I=291
+KEY=AD0B10216B5D496B894343389E4EDC4BECE455757E208754
+IV=50DC56062E88C9CAE60D167A1FD7B202
+CT=BA0BD1FFA54258361D3A8BD9F3C689E4
+PT=4911046D8F1D2BCF54F22B5A83AF5AE1
+
+I=292
+KEY=AF6CC229A2618121C05247551153F784B8167E2FFD8FDDB5
+IV=A7CC6A2B280A9DE80267D208C93CC84A
+CT=4911046D8F1D2BCF54F22B5A83AF5AE1
+PT=254CA1983D7B794911B455E857CE902B
+
+I=293
+KEY=66413E8C7D11836FE51EE6CD2C288ECDA9A22BC7AA414D9E
+IV=D01066ADC643A032C92DFCA5DF70024E
+CT=254CA1983D7B794911B455E857CE902B
+PT=B0A100E60D0404D123D10AE78E9CFFCB
+
+I=294
+KEY=D13AF271F9C3337455BFE62B212C8A1C8A73212024DDB255
+IV=20D00A218F07ECEDB77BCCFD84D2B01B
+CT=B0A100E60D0404D123D10AE78E9CFFCB
+PT=D4CD0CC7D2EBAB050108E94365D34FAA
+
+I=295
+KEY=8B3C7094C3AD8B018172EAECF3C721198B7BC863410EFDFF
+IV=EC5F46869A00FFC25A0682E53A6EB875
+CT=D4CD0CC7D2EBAB050108E94365D34FAA
+PT=DF913CC34675469401CCA41DB50BFBA4
+
+I=296
+KEY=7DCF9D4559C3EA3A5EE3D62FB5B2678D8AB76C7EF405065B
+IV=8718728B7105A417F6F3EDD19A6E613B
+CT=DF913CC34675469401CCA41DB50BFBA4
+PT=5B09F0AF91EA41851A232543E97A6ED4
+
+I=297
+KEY=C3E6C2A9975117B605EA2680245826089094493D1D7F688F
+IV=21D001128A401EBFBE295FECCE92FD8C
+CT=5B09F0AF91EA41851A232543E97A6ED4
+PT=8544DFD1E46D14FF1B0E9CF43A7E9EB6
+
+I=298
+KEY=54C6D7971066FDD380AEF951C03532F78B9AD5C92701F639
+IV=F861E1C66C3F21779720153E8737EA65
+CT=8544DFD1E46D14FF1B0E9CF43A7E9EB6
+PT=586696A67E355CCDC41AD16D87786773
+
+I=299
+KEY=B47A128050D1FC84D8C86FF7BE006E3A4F8004A4A079914A
+IV=55A87D49D3640887E0BCC51740B70157
+CT=586696A67E355CCDC41AD16D87786773
+PT=6C7FF8D2F033B33C729C556E0731ACFF
+
+I=300
+KEY=C66EA18D75351D93B4B797254E33DD063D1C51CAA7483DB5
+IV=7224A11A5D122A607214B30D25E4E117
+CT=6C7FF8D2F033B33C729C556E0731ACFF
+PT=BC031D9B497C64B15EE143CF4D2130B1
+
+I=301
+KEY=00432A82295B2C6708B48ABE074FB9B763FD1205EA690D04
+IV=61D8239BE618CC39C62D8B0F5C6E31F4
+CT=BC031D9B497C64B15EE143CF4D2130B1
+PT=325D14CCDE09311A8069C5522FD050FD
+
+I=302
+KEY=E03B01935511FA7E3AE99E72D94688ADE394D757C5B95DF9
+IV=339B83266B282A96E0782B117C4AD619
+CT=325D14CCDE09311A8069C5522FD050FD
+PT=FA25D0913004A26A3232F743ACC7677E
+
+I=303
+KEY=47F79639F27D47E9C0CC4EE3E9422AC7D1A62014697E3A87
+IV=C5F60E2EC86A0971A7CC97AAA76CBD97
+CT=FA25D0913004A26A3232F743ACC7677E
+PT=61AA67B567F1CE94326B4711F8115727
+
+I=304
+KEY=EE86C028A3B01E7EA16629568EB3E453E3CD6705916F6DA0
+IV=4037462A5B08A27FA971561151CD5997
+CT=61AA67B567F1CE94326B4711F8115727
+PT=35D0FD8AFF6CBDF34065CED4796D9D27
+
+I=305
+KEY=EE88DBE9CCC930CB94B6D4DC71DF59A0A3A8A9D1E802F087
+IV=20CB619D26A05953000E1BC16F792EB5
+CT=35D0FD8AFF6CBDF34065CED4796D9D27
+PT=DD69B839EAE7D0DF79F5D06140D54325
+
+I=306
+KEY=C77ADB703861D01649DF6CE59B38897FDA5D79B0A8D7B3A2
+IV=16CFCF6A4F3272EA29F20099F4A8E0DD
+CT=DD69B839EAE7D0DF79F5D06140D54325
+PT=CA93E79E612893AA0D979ABDF5CA788A
+
+I=307
+KEY=3F486F048B5D9716834C8B7BFA101AD5D7CAE30D5D1DCB28
+IV=58332C3A8F187A96F832B474B33C4700
+CT=CA93E79E612893AA0D979ABDF5CA788A
+PT=39974A1C62DF12F62EC9F75704B0EFA8
+
+I=308
+KEY=B9022C8EA2C6FEF4BADBC16798CF0823F903145A59AD2480
+IV=3C09D97EFC480CD6864A438A299B69E2
+CT=39974A1C62DF12F62EC9F75704B0EFA8
+PT=B840EFC34BCD941BF551E437D633BB3A
+
+I=309
+KEY=D22317E3BB60B9FA029B2EA4D3029C380C52F06D8F9E9FBA
+IV=C755A4CF1FAD90046B213B6D19A6470E
+CT=B840EFC34BCD941BF551E437D633BB3A
+PT=979F6217FD73CAB73A1DE1FACF68542C
+
+I=310
+KEY=E196EBBFCDA64F7095044CB32E71568F364F119740F6CB96
+IV=D342A7B4EF6CB49F33B5FC5C76C6F68A
+CT=979F6217FD73CAB73A1DE1FACF68542C
+PT=A290A25CFBCB1BEE137AFB860BB2CF29
+
+I=311
+KEY=B756B878A99088B83794EEEFD5BA4D612535EA114B4404BF
+IV=D92C9835E799541056C053C76436C7C8
+CT=A290A25CFBCB1BEE137AFB860BB2CF29
+PT=7E99249836CA5167C88BD3431C78C2E0
+
+I=312
+KEY=2515F524203B507E490DCA77E3701C06EDBE3952573CC65F
+IV=FD7219F6C131C4BD92434D5C89ABD8C6
+CT=7E99249836CA5167C88BD3431C78C2E0
+PT=5B7DAB9C2148A2B7ACCE4723D1D63B3F
+
+I=313
+KEY=28A33899811FE9B7127061EBC238BEB141707E7186EAFD60
+IV=F6B29A78141D8F8A0DB6CDBDA124B9C9
+CT=5B7DAB9C2148A2B7ACCE4723D1D63B3F
+PT=12BAE3836257C52B88ECEEAAE8DE3B80
+
+I=314
+KEY=85C6089FEF19163500CA8268A06F7B9AC99C90DB6E34C6E0
+IV=AE11E9BE14B4ECB1AD6530066E06FF82
+CT=12BAE3836257C52B88ECEEAAE8DE3B80
+PT=71C5D9F8747D428DE30736C4DD33E3E5
+
+I=315
+KEY=86665ED5DA56FE90710F5B90D41239172A9BA61FB3072505
+IV=2CBAA91201D1980B03A0564A354FE8A5
+CT=71C5D9F8747D428DE30736C4DD33E3E5
+PT=D824A3FB80554CCD519D730D25EED2AF
+
+I=316
+KEY=F6D0840D75423D5CA92BF86B544775DA7B06D51296E9F7AA
+IV=66AA086063C3768C70B6DAD8AF14C3CC
+CT=D824A3FB80554CCD519D730D25EED2AF
+PT=C974BCBE88ACA9D29312192BE52885BD
+
+I=317
+KEY=56F2FDAAB52A8691605F44D5DCEBDC08E814CC3973C17217
+IV=14D16CCEDE70F435A02279A7C068BBCD
+CT=C974BCBE88ACA9D29312192BE52885BD
+PT=23B74C4B5E661FA157F571F4C13AA3AE
+
+I=318
+KEY=676109782F02525643E8089E828DC3A9BFE1BDCDB2FBD1B9
+IV=46BB517768227D1D3193F4D29A28D4C7
+CT=23B74C4B5E661FA157F571F4C13AA3AE
+PT=BDF2A1A79D553C85F5867B2BD5259A82
+
+I=319
+KEY=D21B20B085B317EDFE1AA9391FD8FF2C4A67C6E667DE4B3B
+IV=054B26F10A7F2D69B57A29C8AAB145BB
+CT=BDF2A1A79D553C85F5867B2BD5259A82
+PT=1E02970BE31FEE63C9BCCC79FB41F670
+
+I=320
+KEY=3CF3F93D44647FB7E0183E32FCC7114F83DB0A9F9C9FBD4B
+IV=C44342FC579F9083EEE8D98DC1D7685A
+CT=1E02970BE31FEE63C9BCCC79FB41F670
+PT=70F71372F64174D7C8757F043812439F
+
+I=321
+KEY=2C83CB76D99E054E90EF2D400A8665984BAE759BA48DFED4
+IV=884B46D9FBE7D99C1070324B9DFA7AF9
+CT=70F71372F64174D7C8757F043812439F
+PT=46B20E91579B5CC0ADE9327478DF25FA
+
+I=322
+KEY=0ADEA18FAA36E94BD65D23D15D1D3958E64747EFDC52DB2E
+IV=F256BC3206E11E9C265D6AF973A8EC05
+CT=46B20E91579B5CC0ADE9327478DF25FA
+PT=51FE245369F67740615E159E28C2D56C
+
+I=323
+KEY=E0C00F8BFD4ADCD087A3078234EB4E1887195271F4900E42
+IV=836F6756B9EC572DEA1EAE04577C359B
+CT=51FE245369F67740615E159E28C2D56C
+PT=58A1B407358C1F9783A05C0A43D5B4FB
+
+I=324
+KEY=EEA0B17E70A6FC53DF02B3850167518F04B90E7BB745BAB9
+IV=0E584BF6D72F08310E60BEF58DEC2083
+CT=58A1B407358C1F9783A05C0A43D5B4FB
+PT=6212DD8752996CC4D747790D5F2BC7E7
+
+I=325
+KEY=B6E49EEA07D03112BD106E0253FE3D4BD3FE7776E86E7D5E
+IV=2BA760FB0CC14D1858442F947776CD41
+CT=6212DD8752996CC4D747790D5F2BC7E7
+PT=DB16C25BDE0B95F4EC7B34FA2096E6A6
+
+I=326
+KEY=F64DCEBA5E71D73E6606AC598DF5A8BF3F85438CC8F89BF8
+IV=674AA4866EE9988E40A9505059A1E62C
+CT=DB16C25BDE0B95F4EC7B34FA2096E6A6
+PT=BB98BBB3289F3B5A96C5D3DA92F8CD0F
+
+I=327
+KEY=23CBCCA3D63DABB8DD9E17EAA56A93E5A94090565A0056F7
+IV=E3D676539CBD9676D5860219884C7C86
+CT=BB98BBB3289F3B5A96C5D3DA92F8CD0F
+PT=324C1661B1E289EA3DAC27AF14E026C5
+
+I=328
+KEY=D6F7C4A098C4E809EFD2018B14881A0F94ECB7F94EE07032
+IV=E7FB3F340E160FB5F53C08034EF943B1
+CT=324C1661B1E289EA3DAC27AF14E026C5
+PT=6EDA104789445C38F66EC2562F95FBDB
+
+I=329
+KEY=4B795FAB98879223810811CC9DCC4637628275AF61758BE9
+IV=C5E830814D72E9449D8E9B0B00437A2A
+CT=6EDA104789445C38F66EC2562F95FBDB
+PT=C834C54858181891C7D654A7502C0B60
+
+I=330
+KEY=AA317465E376BAF2493CD484C5D45EA6A554210831598089
+IV=2388FCCDB47CB5DBE1482BCE7BF128D1
+CT=C834C54858181891C7D654A7502C0B60
+PT=9C5F5599557D176050BBAC4258B87F66
+
+I=331
+KEY=B601C39C0E5F02DED563811D90A949C6F5EF8D4A69E1FFEF
+IV=10C2528D377387311C30B7F9ED29B82C
+CT=9C5F5599557D176050BBAC4258B87F66
+PT=ED5F51A6AFA843D467E21F6C68992273
+
+I=332
+KEY=44A1FE3F8349D500383CD0BB3F010A12920D92260178DD9C
+IV=9E73D9FB1D2471E8F2A03DA38D16D7DE
+CT=ED5F51A6AFA843D467E21F6C68992273
+PT=D7A5F18382F892264008F75707254D95
+
+I=333
+KEY=568F031D75B9B48FEF992138BDF99834D2056571065D9009
+IV=DEC9B60FA5A91887122EFD22F6F0618F
+CT=D7A5F18382F892264008F75707254D95
+PT=D13A34D9F57884ECEE2FA1A412584BE4
+
+I=334
+KEY=72CFCCE9FE5EB48A3EA315E148811CD83C2AC4D51405DBED
+IV=75C70261D0C49D692440CFF48BE70005
+CT=D13A34D9F57884ECEE2FA1A412584BE4
+PT=064D550098F0813D145A2AA296064CCF
+
+I=335
+KEY=58448186BD1ED1FC38EE40E1D0719DE52870EE7782039722
+IV=754A1B79A75BD3B32A8B4D6F43406576
+CT=064D550098F0813D145A2AA296064CCF
+PT=D7CD7D2B23E42F7A9808D48C28982743
+
+I=336
+KEY=6FF7BCC770079D57EF233DCAF395B29FB0783AFBAA9BB061
+IV=25EE1F4D8F257C6437B33D41CD194CAB
+CT=D7CD7D2B23E42F7A9808D48C28982743
+PT=6F55D4C7A13F08A1D936C5F0177040CA
+
+I=337
+KEY=7ECBB104AA3505E58076E90D52AABA3E694EFF0BBDEBF0AB
+IV=E21F1527B69B89C8113C0DC3DA3298B2
+CT=6F55D4C7A13F08A1D936C5F0177040CA
+PT=7F061908571CDDBC1F8F82A31A3AF1F9
+
+I=338
+KEY=135D99B5F2482FFAFF70F00505B6678276C17DA8A7D10152
+IV=5DA54CDB26A0DC2D6D9628B1587D2A1F
+CT=7F061908571CDDBC1F8F82A31A3AF1F9
+PT=30AB085953DE3E8027DE0C8A185A7D02
+
+I=339
+KEY=3C76458A987B66F0CFDBF85C56685902511F7122BF8B7C50
+IV=E0614E072D2563DD2F2BDC3F6A33490A
+CT=30AB085953DE3E8027DE0C8A185A7D02
+PT=92C915E98AEBF6265C43A66AC5B40787
+
+I=340
+KEY=EBD41B4484EA67A05D12EDB5DC83AF240D5CD7487A3F7BD7
+IV=6EA27DF02FA0A9A9D7A25ECE1C910150
+CT=92C915E98AEBF6265C43A66AC5B40787
+PT=E9AC0996F97FFBA0F7C860A089CDF99F
+
+I=341
+KEY=85B6BBBC8E2243D3B4BEE42325FC5484FA94B7E8F3F28248
+IV=46D915F802932C936E62A0F80AC82473
+CT=E9AC0996F97FFBA0F7C860A089CDF99F
+PT=BA1D082EDB28E255CB37AFEDB497D43A
+
+I=342
+KEY=BDA8736E56DDB34F0EA3EC0DFED4B6D131A3180547655672
+IV=0A7B9BCBE89E4CDE381EC8D2D8FFF09C
+CT=BA1D082EDB28E255CB37AFEDB497D43A
+PT=63298FE15A14C4A4E582C57772A0581E
+
+I=343
+KEY=9B5DC0C3B097B7CE6D8A63ECA4C07275D421DD7235C50E6C
+IV=81F4666446CB470526F5B3ADE64A0481
+CT=63298FE15A14C4A4E582C57772A0581E
+PT=AE79390C6789DFCF7110BA93281E9895
+
+I=344
+KEY=E64DDC6A55048E35C3F35AE0C349ADBAA53167E11DDB96F9
+IV=DB4439803A1ACA807D101CA9E59339FB
+CT=AE79390C6789DFCF7110BA93281E9895
+PT=2C9DF2ED511595756E5CF6D33442D3A3
+
+I=345
+KEY=9C75AC9CBA0918CDEF6EA80D925C38CFCB6D91322999455A
+IV=B73DBACA0C10AD0A7A3870F6EF0D96F8
+CT=2C9DF2ED511595756E5CF6D33442D3A3
+PT=90FDAEAEDC379128B73515CB2AAC9B7A
+
+I=346
+KEY=A045744F6BB9205F7F9306A34E6BA9E77C5884F90335DE20
+IV=356BBCDD4EBDA8F93C30D8D3D1B03892
+CT=90FDAEAEDC379128B73515CB2AAC9B7A
+PT=E66EA385E1F20791090CA24ADB250AFC
+
+I=347
+KEY=48E94FAC40CFC94B99FDA526AF99AE76755426B3D810D4DC
+IV=ABAF17EBE3658829E8AC3BE32B76E914
+CT=E66EA385E1F20791090CA24ADB250AFC
+PT=A17C6802F4322D97C6966B523B54CF88
+
+I=348
+KEY=3FC9CD7847FF49D73881CD245BAB83E1B3C24DE1E3441B54
+IV=7D25F4EE8B874E2D772082D40730809C
+CT=A17C6802F4322D97C6966B523B54CF88
+PT=CBEC825D143BF30C58B608B58ABFB618
+
+I=349
+KEY=D4464B5CD3CFAD06F36D4F794F9070EDEB74455469FBAD4C
+IV=93D0E88641960F8EEB8F86249430E4D1
+CT=CBEC825D143BF30C58B608B58ABFB618
+PT=D7A8E224DAA4DB7629790D3D4D5A8560
+
+I=350
+KEY=73DD2DA38114D0BD24C5AD5D9534AB9BC20D486924A1282C
+IV=3E6B8F8084BAA391A79B66FF52DB7DBB
+CT=D7A8E224DAA4DB7629790D3D4D5A8560
+PT=EB7EAD5CF27BA091DEF8D7839EFD7C90
+
+I=351
+KEY=CDA609EB23BB90EBCFBB0001674F0B0A1CF59FEABA5C54BC
+IV=8EEE61573B01F1E4BE7B2448A2AF4056
+CT=EB7EAD5CF27BA091DEF8D7839EFD7C90
+PT=2EFA41B666ECBBB1D699C1FB8CA9E175
+
+I=352
+KEY=768FCC098B8F48FFE14141B701A3B0BBCA6C5E1136F5B5C9
+IV=60BC671273707E17BB29C5E2A834D814
+CT=2EFA41B666ECBBB1D699C1FB8CA9E175
+PT=44D7245914CF3BF73831D4225BD32FDD
+
+I=353
+KEY=91F2FFA6BB520FD1A59665EE156C8B4CF25D8A336D269A14
+IV=21187FBCFC5E01BEE77D33AF30DD472E
+CT=44D7245914CF3BF73831D4225BD32FDD
+PT=E9FA049C77C326A4F03D2C9E740DE4A1
+
+I=354
+KEY=2FC9C39B5DBC560E4C6C617262AFADE80260A6AD192B7EB5
+IV=72912E59A0095846BE3B3C3DE6EE59DF
+CT=E9FA049C77C326A4F03D2C9E740DE4A1
+PT=9A62281465C72FDAA73E00E343A99BC3
+
+I=355
+KEY=F401ED3768BC72D4D60E496607688232A55EA64E5A82E576
+IV=88022668FE843060DBC82EAC350024DA
+CT=9A62281465C72FDAA73E00E343A99BC3
+PT=FAD9ADA4B98A4141A2857F93F6F71DEB
+
+I=356
+KEY=1AD741BDF8A18D8E2CD7E4C2BEE2C37307DBD9DDAC75F89D
+IV=F98FECC470C84631EED6AC8A901DFF5A
+CT=FAD9ADA4B98A4141A2857F93F6F71DEB
+PT=630453171FEE434834490229830E1C1A
+
+I=357
+KEY=24F7B99681335EAD4FD3B7D5A10C803B3392DBF42F7BE487
+IV=5D69B4D81847DABD3E20F82B7992D323
+CT=630453171FEE434834490229830E1C1A
+PT=DE613189001598BA6AE67F259F9FD349
+
+I=358
+KEY=60E401E96083FF2291B2865CA11918815974A4D1B0E437CE
+IV=AADE84AD4127FCDA4413B87FE1B0A18F
+CT=DE613189001598BA6AE67F259F9FD349
+PT=CA18925634072DEC80F2F724A0F24235
+
+I=359
+KEY=66831E7F4FC51DB95BAA140A951E356DD98653F5101675FB
+IV=1C1E2F698C5DD62006671F962F46E29B
+CT=CA18925634072DEC80F2F724A0F24235
+PT=B289F06551C56B77F5CDF7B321E0E8E3
+
+I=360
+KEY=48FB1A5B41F634D5E923E46FC4DB5E1A2C4BA44631F69D18
+IV=6A872620ED13A14B2E7804240E33296C
+CT=B289F06551C56B77F5CDF7B321E0E8E3
+PT=13B1F93DD388A192D6FB836C90E0E022
+
+I=361
+KEY=F13FA6E33170F596FA921D521753FF88FAB0272AA1167D3A
+IV=40BF714207DA180BB9C4BCB87086C143
+CT=13B1F93DD388A192D6FB836C90E0E022
+PT=298B7B19A27EA1BE9574588A5885F64B
+
+I=362
+KEY=CE171639A4DDA77DD319664BB52D5E366FC47FA0F9938B71
+IV=8FB32729166E154F3F28B0DA95AD52EB
+CT=298B7B19A27EA1BE9574588A5885F64B
+PT=11FA000C73485654A8918360DF3C1F5E
+
+I=363
+KEY=9322B0E9AE4D6B20C2E36647C6650862C755FCC026AF942F
+IV=809DE75B169C56BE5D35A6D00A90CC5D
+CT=11FA000C73485654A8918360DF3C1F5E
+PT=05533E642958E2F6F29BB1848BE225CB
+
+I=364
+KEY=21B86D89874D627FC7B05823EF3DEA9435CE4D44AD4DB1E4
+IV=81CF24C876471695B29ADD602900095F
+CT=05533E642958E2F6F29BB1848BE225CB
+PT=613DB485B9565B4889887282A3C8CFB5
+
+I=365
+KEY=6E5AD95BDDA04D12A68DECA6566BB1DCBC463FC60E857E51
+IV=7E3AC16D28733BD84FE2B4D25AED2F6D
+CT=613DB485B9565B4889887282A3C8CFB5
+PT=0CDDDA3B3375430B601BA1CCBD567284
+
+I=366
+KEY=807937B80E55E814AA50369D651EF2D7DC5D9E0AB3D30CD5
+IV=C49324EE3A928684EE23EEE3D3F5A506
+CT=0CDDDA3B3375430B601BA1CCBD567284
+PT=C47A6E22A123AB6397F9C2AFFA6D45AB
+
+I=367
+KEY=20B3595EFE3D3DA76E2A58BFC43D59B44BA45CA549BE497E
+IV=B188E4D3A2AC3F42A0CA6EE6F068D5B3
+CT=C47A6E22A123AB6397F9C2AFFA6D45AB
+PT=71592AFCA1FEEE8AB6D6CEF22C14A21D
+
+I=368
+KEY=A97EAD081EDF66D11F73724365C3B73EFD72925765AAEB63
+IV=0DFF90FA3722469289CDF456E0E25B76
+CT=71592AFCA1FEEE8AB6D6CEF22C14A21D
+PT=F4E0C4BCF8B386CF1BD457BD1FB65646
+
+I=369
+KEY=DA90448D67D59E3CEB93B6FF9D7031F1E6A6C5EA7A1CBD25
+IV=154DB6488872217073EEE985790AF8ED
+CT=F4E0C4BCF8B386CF1BD457BD1FB65646
+PT=9ED1119909322C280FE92B7840792605
+
+I=370
+KEY=CF62D3016C8507F17542A76694421DD9E94FEE923A659B20
+IV=ED45F0A7D33FC08515F2978C0B5099CD
+CT=9ED1119909322C280FE92B7840792605
+PT=F812615F1BE701E74FCEEFC288303C7C
+
+I=371
+KEY=C2681849C663E45A8D50C6398FA51C3EA6810150B255A75C
+IV=19E09027253115100D0ACB48AAE6E3AB
+CT=F812615F1BE701E74FCEEFC288303C7C
+PT=25897C51C5FEDBFDC630BF8E9F3B2875
+
+I=372
+KEY=F47C452077541CEEA8D9BA684A5BC7C360B1BEDE2D6E8F29
+IV=2C2EE28C518163DF36145D69B137F8B4
+CT=25897C51C5FEDBFDC630BF8E9F3B2875
+PT=9929E5E9F0CA00D0E02022E2FCFAFC3F
+
+I=373
+KEY=F7BF8679C8D86E2C31F05F81BA91C71380919C3CD1947316
+IV=FCF0C5D85049463103C3C359BF8C72C2
+CT=9929E5E9F0CA00D0E02022E2FCFAFC3F
+PT=3B603A3FDAA669E7C965708C9789E329
+
+I=374
+KEY=9312EDA0B14017910A9065BE6037AEF449F4ECB0461D903F
+IV=364CDACF5762B18864AD6BD9799879BD
+CT=3B603A3FDAA669E7C965708C9789E329
+PT=AC33F7B1A778C36617668C98E20B318A
+
+I=375
+KEY=D5BC989407D78D82A6A3920FC74F6D925E926028A416A1B5
+IV=5FB00506C71711D046AE7534B6979A13
+CT=AC33F7B1A778C36617668C98E20B318A
+PT=B408AF5509EF45E0AEDF12570FAE3651
+
+I=376
+KEY=6BBB14591C12578112AB3D5ACEA02872F04D727FABB897E4
+IV=D41F58F192CF60D6BE078CCD1BC5DA03
+CT=B408AF5509EF45E0AEDF12570FAE3651
+PT=39EB055E027AC0DEA5992B7BA3753AB5
+
+I=377
+KEY=3F71566EA7D07EBF2B403804CCDAE8AC55D4590408CDAD51
+IV=7E495DEC2224696554CA4237BBC2293E
+CT=39EB055E027AC0DEA5992B7BA3753AB5
+PT=832B01D2AD4F0EE077244CF9B6ABE31C
+
+I=378
+KEY=0BDC563CE47527D1A86B39D66195E64C22F015FDBE664E4D
+IV=4FE13E98163C3F7734AD005243A5596E
+CT=832B01D2AD4F0EE077244CF9B6ABE31C
+PT=926EB7E17FA4262D1D390D83CDAC6FB2
+
+I=379
+KEY=07D4D606747858B63A058E371E31C0613FC9187E73CA21FF
+IV=12D459160DCFFEFE0C08803A900D7F67
+CT=926EB7E17FA4262D1D390D83CDAC6FB2
+PT=DBFBC3313F86C26BA54B9F69BA93C665
+
+I=380
+KEY=84BE014D4BFA8ACCE1FE4D0621B7020A9A828717C959E79A
+IV=179322B7D19F3A38836AD74B3F82D27A
+CT=DBFBC3313F86C26BA54B9F69BA93C665
+PT=39B00A1A655B298F56271B2BDBA6B16B
+
+I=381
+KEY=A921F537F5F324CAD84E471C44EC2B85CCA59C3C12FF56F1
+IV=D4B03D3AB6FF79D22D9FF47ABE09AE06
+CT=39B00A1A655B298F56271B2BDBA6B16B
+PT=7C5DABBF7C7951808DCD35DB2617B763
+
+I=382
+KEY=3BB6AACEEEC21A9FA413ECA338957A054168A9E734E8E192
+IV=5C92A3C4C3C8567792975FF91B313E55
+CT=7C5DABBF7C7951808DCD35DB2617B763
+PT=BD88FB3B815415503D4F9264AFEA7887
+
+I=383
+KEY=008F402C3524BCA8199B1798B9C16F557C273B839B029915
+IV=08360D06E31B3AA43B39EAE2DBE6A637
+CT=BD88FB3B815415503D4F9264AFEA7887
+PT=B2813AFBC477618F4C6A436C97AA26F2
+
+I=384
+KEY=8AB9F9FC4EE8B2D4AB1A2D637DB60EDA304D78EF0CA8BFE7
+IV=DCF7EF19F68916268A36B9D07BCC0E7C
+CT=B2813AFBC477618F4C6A436C97AA26F2
+PT=1E96D52E46B1D73EB00778B203946F28
+
+I=385
+KEY=CA9D4CE917399619B58CF84D3B07D9E4804A005D0F3CD0CF
+IV=63A112DB63DDECB54024B51559D124CD
+CT=1E96D52E46B1D73EB00778B203946F28
+PT=C03D770FE4B1733C5E59DD68F0060D5A
+
+I=386
+KEY=1D8268F833FC772575B18F42DFB6AAD8DE13DD35FF3ADD95
+IV=8B7AC769F85BA650D71F241124C5E13C
+CT=C03D770FE4B1733C5E59DD68F0060D5A
+PT=6495A8A3667DEDE2CAB58BA3B2F7034E
+
+I=387
+KEY=CCCEE884786AF28A112427E1B9CB473A14A656964DCDDEDB
+IV=280C5BD88E3B88ACD14C807C4B9685AF
+CT=6495A8A3667DEDE2CAB58BA3B2F7034E
+PT=4CC3C2AC85EBD619E708988C9FEC60C6
+
+I=388
+KEY=8B85284B2B06874D5DE7E54D3C209123F3AECE1AD221BE1D
+IV=62E112946391FEFB474BC0CF536C75C7
+CT=4CC3C2AC85EBD619E708988C9FEC60C6
+PT=1522371FD5D53919F52CD97258CEBDA7
+
+I=389
+KEY=B2EBBE81CF234A7E48C5D252E9F5A83A068217688AEF03BA
+IV=8A936BAE971C0C9F396E96CAE425CD33
+CT=1522371FD5D53919F52CD97258CEBDA7
+PT=4AA882DCB39AA79E8439E9ECE9F4F3BD
+
+I=390
+KEY=043B9FDDEC299802026D508E5A6F0FA482BBFE84631BF007
+IV=6FA7FCDBA3B1BCA5B6D0215C230AD27C
+CT=4AA882DCB39AA79E8439E9ECE9F4F3BD
+PT=28C1E45D8D01AD148FA7D7C4F41ACE04
+
+I=391
+KEY=1074F9BD3FFD4EAF2AACB4D3D76EA2B00D1C294097013E03
+IV=1210BAF1D69B23FE144F6660D3D4D6AD
+CT=28C1E45D8D01AD148FA7D7C4F41ACE04
+PT=3ABE04FC59C3BDF9D7721902DEFCB439
+
+I=392
+KEY=D97F3440E3684D291012B02F8EAD1F49DA6E304249FD8A3A
+IV=C271800852E147D5C90BCDFDDC950386
+CT=3ABE04FC59C3BDF9D7721902DEFCB439
+PT=3A563A6A047E16123B289B047BB54C4E
+
+I=393
+KEY=49A10E68A38B02F42A448A458AD3095BE146AB463248C674
+IV=9DB6856C7E01CF3690DE3A2840E34FDD
+CT=3A563A6A047E16123B289B047BB54C4E
+PT=F8CB54B8D16274E9A20C0F026866E52F
+
+I=394
+KEY=9DD96DCFD4A1B11FD28FDEFD5BB17DB2434AA4445A2E235B
+IV=233C069312D97A03D47863A7772AB3EB
+CT=F8CB54B8D16274E9A20C0F026866E52F
+PT=0302D25C39BF21F67F1AF2E1951D40F9
+
+I=395
+KEY=746E55928D7E549DD18D0CA1620E5C443C5056A5CF3363A2
+IV=B6086C5FEEE9A078E9B7385D59DFE582
+CT=0302D25C39BF21F67F1AF2E1951D40F9
+PT=721192A3A5140DD63D93E0D6ACC4A4B8
+
+I=396
+KEY=7E6FC505EAAB07E4A39C9E02C71A519201C3B67363F7C71A
+IV=9828A03F0ADCE33E0A01909767D55379
+CT=721192A3A5140DD63D93E0D6ACC4A4B8
+PT=1C0F7440EF41FF18E263392741AD9D8B
+
+I=397
+KEY=D13AD442CAE026C3BF93EA42285BAE8AE3A08F54225A5A91
+IV=4FC707A846B4469AAF551147204B2127
+CT=1C0F7440EF41FF18E263392741AD9D8B
+PT=442F978615AC3983AA5ABEA81AD1ACA6
+
+I=398
+KEY=043A4EFFCD44EEB1FBBC7DC43DF7970949FA31FC388BF637
+IV=05D58B4A88A961AFD5009ABD07A4C872
+CT=442F978615AC3983AA5ABEA81AD1ACA6
+PT=E75C29413A33AA1210F36AADEC02FCEE
+
+I=399
+KEY=81492E2C6296C9341CE0548507C43D1B59095B51D4890AD9
+IV=D89794EAA1791507857360D3AFD22785
+CT=E75C29413A33AA1210F36AADEC02FCEE
+PT=6342BFDDD2F6610350458B6695463484
+
+==========
+
+KEYSIZE=256
+
+I=0
+KEY=0000000000000000000000000000000000000000000000000000000000000000
+IV=00000000000000000000000000000000
+CT=00000000000000000000000000000000
+PT=4804E1818FE6297519A3E88C57310413
+
+I=1
+KEY=098E3797788EA3BCD5477BF1660373944804E1818FE6297519A3E88C57310413
+IV=098E3797788EA3BCD5477BF166037394
+CT=4804E1818FE6297519A3E88C57310413
+PT=D36C27EBB8FA0BC9FA368DF850FD45FB
+
+I=2
+KEY=D949E143F98BDE24BD40A256F9E369339B68C66A371C22BCE395657407CC41E8
+IV=D0C7D6D481057D986807D9A79FE01AA7
+CT=D36C27EBB8FA0BC9FA368DF850FD45FB
+PT=EBCB4DC84155682856D94B442BC597EE
+
+I=3
+KEY=296352DA0158E197EBC80771EC1ECC7D70A38BA276494A94B54C2E302C09D606
+IV=F02AB399F8D33FB35688A52715FDA54E
+CT=EBCB4DC84155682856D94B442BC597EE
+PT=23AA6A6B4BE8C04E19707CA330804C4E
+
+I=4
+KEY=5D3E9E2EA4DEDDB65A58DADB5B9679BC5309E1C93DA18ADAAC3C52931C899A48
+IV=745DCCF4A5863C21B190DDAAB788B5C1
+CT=23AA6A6B4BE8C04E19707CA330804C4E
+PT=9B1AA0F33416484BA68740E821F95CD3
+
+I=5
+KEY=E35024184CCA14687DB19E13093D2A31C813413A09B7C2910ABB127B3D70C69B
+IV=BE6EBA36E814C9DE27E944C852AB538D
+CT=9B1AA0F33416484BA68740E821F95CD3
+PT=8A8C6ADF453CB7A2FC4F3690FF7C6F23
+
+I=6
+KEY=FDC6EB83FF93BA06DE2D09CB33F05406429F2BE54C8B7533F6F424EBC20CA9B8
+IV=1E96CF9BB359AE6EA39C97D83ACD7E37
+CT=8A8C6ADF453CB7A2FC4F3690FF7C6F23
+PT=B104182A3D85B857FB342BD06063E989
+
+I=7
+KEY=7177668BAC9407FB2835524D58F1311EF39B33CF710ECD640DC00F3BA26F4031
+IV=8CB18D085307BDFDF6185B866B016518
+CT=B104182A3D85B857FB342BD06063E989
+PT=68AD7EB507FAEE8FF54E5B7EB4314208
+
+I=8
+KEY=790AE8470B39A60E9F32F4025B2251849B364D7A76F423EBF88E5445165E0239
+IV=087D8ECCA7ADA1F5B707A64F03D3609A
+CT=68AD7EB507FAEE8FF54E5B7EB4314208
+PT=99736D55B2730FDBC4FCD9128A3E6F06
+
+I=9
+KEY=4EAF05AC15913059B6B0E43EFA7ADC1C0245202FC4872C303C728D579C606D3F
+IV=37A5EDEB1EA896572982103CA1588D98
+CT=99736D55B2730FDBC4FCD9128A3E6F06
+PT=DF326CEE98EE253C855D171D93AA9455
+
+I=10
+KEY=55EE1CCDBA5A04040F4212DFBF6ABC89DD774CC15C69090CB92F9A4A0FCAF96A
+IV=1B411961AFCB345DB9F2F6E145106095
+CT=DF326CEE98EE253C855D171D93AA9455
+PT=B4E41BD5257CD7AF0A6F020BEE5F4067
+
+I=11
+KEY=6190A91725B7D4E8DD42F3F3B4E42E14699357147915DEA3B3409841E195B90D
+IV=347EB5DA9FEDD0ECD200E12C0B8E929D
+CT=B4E41BD5257CD7AF0A6F020BEE5F4067
+PT=3608F41CA4C677E74F48B113D9B336B0
+
+I=12
+KEY=0A93E973CCBAC75C9C0AA05502A43E945F9BA308DDD3A944FC08295238268FBD
+IV=6B034064E90D13B4414853A6B6401080
+CT=3608F41CA4C677E74F48B113D9B336B0
+PT=FB54DBB9C0C7176C4C9E1E4E6688B570
+
+I=13
+KEY=584CCAEDD52F491A935D892AD132F75AA4CF78B11D14BE28B096371C5EAE3ACD
+IV=52DF239E19958E460F57297FD396C9CE
+CT=FB54DBB9C0C7176C4C9E1E4E6688B570
+PT=F40A6A6AE95E9D163D88AAE9A2D359BC
+
+I=14
+KEY=0DD784E96CAB96D702DD3972E95317FD50C512DBF44A233E8D1E9DF5FC7D6371
+IV=559B4E04B984DFCD9180B0583861E0A7
+CT=F40A6A6AE95E9D163D88AAE9A2D359BC
+PT=0FE04B8BB249E49E24FEB6FFE106121C
+
+I=15
+KEY=2BC3A4EBD80215F0130EC1F76821BC515F2559504603C7A0A9E02B0A1D7B716D
+IV=26142002B4A9832711D3F8858172ABAC
+CT=0FE04B8BB249E49E24FEB6FFE106121C
+PT=EBA4EF8D541919A0D0947359344D61C9
+
+I=16
+KEY=0B5856BE9A78457868F7CF9C9C58EF7AB481B6DD121ADE0079745853293610A4
+IV=209BF255427A50887BF90E6BF479532B
+CT=EBA4EF8D541919A0D0947359344D61C9
+PT=06484C36A29BD3CA7CBAB7FBEA47313B
+
+I=17
+KEY=C004F13C83AA1FD5C2A592D27B47C437B2C9FAEBB0810DCA05CEEFA8C371219F
+IV=CB5CA78219D25AADAA525D4EE71F2B4D
+CT=06484C36A29BD3CA7CBAB7FBEA47313B
+PT=376157B7DB3B027980C5EF0E88B3F9EF
+
+I=18
+KEY=AD89203CAD17908C4F44F3FD2D61505385A8AD5C6BBA0FB3850B00A64BC2D870
+IV=6D8DD1002EBD8F598DE1612F56269464
+CT=376157B7DB3B027980C5EF0E88B3F9EF
+PT=756783C2F0EE73BBD81B908F660AA6F7
+
+I=19
+KEY=FBE990A6247EABC0CD5090DF0C566E01F0CF2E9E9B547C085D1090292DC87E87
+IV=5660B09A89693B4C8214632221373E52
+CT=756783C2F0EE73BBD81B908F660AA6F7
+PT=6CC64B773ECDFA9749DB33197F7EA0AB
+
+I=20
+KEY=FEC46AD20DA3E667B26D79B11A82A40F9C0965E9A599869F14CBA33052B6DE2C
+IV=052DFA7429DD4DA77F3DE96E16D4CA0E
+CT=6CC64B773ECDFA9749DB33197F7EA0AB
+PT=9230E4DCA927E2F8E617A2EBC4F11477
+
+I=21
+KEY=F4396B035E4E1BD914877124D1CD4B370E3981350CBE6467F2DC01DB9647CA5B
+IV=0AFD01D153EDFDBEA6EA0895CB4FEF38
+CT=9230E4DCA927E2F8E617A2EBC4F11477
+PT=6ACD9F3939A86EE4236A3C060D2F5C3C
+
+I=22
+KEY=49C90E620094D6A85E75BD886FAFE79264F41E0C35160A83D1B63DDD9B689667
+IV=BDF065615EDACD714AF2CCACBE62ACA5
+CT=6ACD9F3939A86EE4236A3C060D2F5C3C
+PT=E5F4F050827F69B60B417063AC1060E4
+
+I=23
+KEY=1AED4D36938AB2D5D884EF2F106D2CEF8100EE5CB7696335DAF74DBE3778F683
+IV=53244354931E647D86F152A77FC2CB7D
+CT=E5F4F050827F69B60B417063AC1060E4
+PT=5CE4B0B3C32700B6B887E05A88EE0239
+
+I=24
+KEY=EF14B937F6E0F19AC8ADBD208DD60EE5DDE45EEF744E63836270ADE4BF96F4BA
+IV=F5F9F401656A434F1029520F9DBB220A
+CT=5CE4B0B3C32700B6B887E05A88EE0239
+PT=4794284E2BB56A47332E84AD7A2006A2
+
+I=25
+KEY=182581A233332DDCD43C25AF9AA3AD7F9A7076A15FFB09C4515E2949C5B6F218
+IV=F7313895C5D3DC461C91988F1775A39A
+CT=4794284E2BB56A47332E84AD7A2006A2
+PT=C8AE2CAA7C257508C3AB75BE28D2602F
+
+I=26
+KEY=ABE7FE236E28332AE7A74A9EA03B97A952DE5A0B23DE7CCC92F55CF7ED649237
+IV=B3C27F815D1B1EF6339B6F313A983AD6
+CT=C8AE2CAA7C257508C3AB75BE28D2602F
+PT=A9FD4B9D4833B647FF60F8013C3B5B9D
+
+I=27
+KEY=08248BDC5F9186DCD65DA6344A10C57EFB2311966BEDCA8B6D95A4F6D15FC9AA
+IV=A3C375FF31B9B5F631FAECAAEA2B52D7
+CT=A9FD4B9D4833B647FF60F8013C3B5B9D
+PT=C871D7B4C0167DCFDD79AF1DEAC49D4F
+
+I=28
+KEY=BF29FB1B11AA7DB8742FF06458C384853352C622ABFBB744B0EC0BEB3B9B54E5
+IV=B70D70C74E3BFB64A272565012D341FB
+CT=C871D7B4C0167DCFDD79AF1DEAC49D4F
+PT=E2DE7BAC726C404FC7BA5099E39409CA
+
+I=29
+KEY=1810253DDF0CC5ECE2381FB4C2BEEDCCD18CBD8ED997F70B77565B72D80F5D2F
+IV=A739DE26CEA6B8549617EFD09A7D6949
+CT=E2DE7BAC726C404FC7BA5099E39409CA
+PT=D4A8257110EF7FFE2A1F026B28D7483A
+
+I=30
+KEY=F343D1EC9AEB200B65DB4AA369F6A47E052498FFC97888F55D495919F0D81515
+IV=EB53F4D145E7E5E787E35517AB4849B2
+CT=D4A8257110EF7FFE2A1F026B28D7483A
+PT=9EA25895CFEAEAD224095C4687726D06
+
+I=31
+KEY=86A93B0F219E1FFEBC0E4BA0334046AA9B86C06A069262277940055F77AA7813
+IV=75EAEAE3BB753FF5D9D501035AB6E2D4
+CT=9EA25895CFEAEAD224095C4687726D06
+PT=5C5DD66E7AD197DA86844D53C8ACEA0E
+
+I=32
+KEY=2278C61356CB0A951DAE3B6DC76868C9C7DB16047C43F5FDFFC4480CBF06921D
+IV=A4D1FD1C7755156BA1A070CDF4282E63
+CT=5C5DD66E7AD197DA86844D53C8ACEA0E
+PT=011959D35C8FE620E1C49D1804912F26
+
+I=33
+KEY=E1972A31ACF850A22CBC592AF6CAF6F0C6C24FD720CC13DD1E00D514BB97BD3B
+IV=C3EFEC22FA335A373112624731A29E39
+CT=011959D35C8FE620E1C49D1804912F26
+PT=895DDA7BB43DC3060B41DA70CAE4D2ED
+
+I=34
+KEY=BB4A76B5E8FD3820CC5D4A44F527E6704F9F95AC94F1D0DB15410F6471736FD6
+IV=5ADD5C8444056882E0E1136E03ED1080
+CT=895DDA7BB43DC3060B41DA70CAE4D2ED
+PT=94E8BBC942B4127A0A8EBEC59319CF57
+
+I=35
+KEY=4D98C60F0FA316B2DA3D11CFB3B9FE0CDB772E65D645C2A11FCFB1A1E26AA081
+IV=F6D2B0BAE75E2E9216605B8B469E187C
+CT=94E8BBC942B4127A0A8EBEC59319CF57
+PT=274FE85E229321D4A6B2E9D4F0D3830F
+
+I=36
+KEY=A9FC5AC4A7B3550BC34E4BA94C0D328BFC38C63BF4D6E375B97D587512B9238E
+IV=E4649CCBA81043B919735A66FFB4CC87
+CT=274FE85E229321D4A6B2E9D4F0D3830F
+PT=256AC08E72D79B0CB7457B26769AC226
+
+I=37
+KEY=1C44DEF03398188AC1B2EF6A6E91A33FD95206B5860178790E3823536423E1A8
+IV=B5B88434942B4D8102FCA4C3229C91B4
+CT=256AC08E72D79B0CB7457B26769AC226
+PT=366D17A14CA0FC192DBB731C1C305874
+
+I=38
+KEY=3D80B92C01F9721032366B20D97DC097EF3F1114CAA184602383504F7813B9DC
+IV=21C467DC32616A9AF384844AB7EC63A8
+CT=366D17A14CA0FC192DBB731C1C305874
+PT=000B4A6054663874ECAE310144BA9377
+
+I=39
+KEY=48DD38DC16A4CE76338C95A866C1C795EF345B749EC7BC14CF2D614E3CA92AAB
+IV=755D81F0175DBC6601BAFE88BFBC0702
+CT=000B4A6054663874ECAE310144BA9377
+PT=32B32D65566626D794FB296CA816B0A8
+
+I=40
+KEY=C62EFA02F23FE796799BF9151FBFD8D7DD877611C8A19AC35BD6482294BF9A03
+IV=8EF3C2DEE49B29E04A176CBD797E1F42
+CT=32B32D65566626D794FB296CA816B0A8
+PT=D743A090101B1BAF5B83E8C06517E193
+
+I=41
+KEY=91400A96EEADA906ABD4C3F6863CE4750AC4D681D8BA816C0055A0E2F1A87B90
+IV=576EF0941C924E90D24F3AE399833CA2
+CT=D743A090101B1BAF5B83E8C06517E193
+PT=2DE61760BEE8F811B3FEB44D2C566DB0
+
+I=42
+KEY=9983EAD4BF987E39644D7D0963F93DB62722C1E16652797DB3AB14AFDDFE1620
+IV=08C3E0425135D73FCF99BEFFE5C5D9C3
+CT=2DE61760BEE8F811B3FEB44D2C566DB0
+PT=E97598EFFED4128DCCCDD7A04D8405E1
+
+I=43
+KEY=B72929D2D02A00D36E7C3BD11CDB9FA4CE57590E98866BF07F66C30F907A13C1
+IV=2EAAC3066FB27EEA0A3146D87F22A212
+CT=E97598EFFED4128DCCCDD7A04D8405E1
+PT=5983276B92B95898302385F5156B6201
+
+I=44
+KEY=CC9928E45F7885515986E0D431F3288E97D47E650A3F33684F4546FA851171C0
+IV=7BB001368F52858237FADB052D28B72A
+CT=5983276B92B95898302385F5156B6201
+PT=ABDEFF06E04995FD2C5472D05056A0A3
+
+I=45
+KEY=59A2D8FCED30176B73FF5642BCE4A9163C0A8163EA76A6956311342AD547D163
+IV=953BF018B248923A2A79B6968D178198
+CT=ABDEFF06E04995FD2C5472D05056A0A3
+PT=E4210D117B05F3EADC8AF75D1A80B823
+
+I=46
+KEY=FFCCE373B679DE040165054D9EECA460D82B8C729173557FBF9BC377CFC76940
+IV=A66E3B8F5B49C96F729A530F22080D76
+CT=E4210D117B05F3EADC8AF75D1A80B823
+PT=4786111E1B0F2CA78E43CC0D154BC1EA
+
+I=47
+KEY=36E29D3C942DBC6A12B53088632260649FAD9D6C8A7C79D831D80F7ADA8CA8AA
+IV=C92E7E4F2254626E13D035C5FDCEC404
+CT=4786111E1B0F2CA78E43CC0D154BC1EA
+PT=122DC3B40007BA36BC7E7EE808911DAE
+
+I=48
+KEY=3692660415E53226D2758E60FD6E3F5F8D805ED88A7BC3EE8DA67192D21DB504
+IV=0070FB3881C88E4CC0C0BEE89E4C5F3B
+CT=122DC3B40007BA36BC7E7EE808911DAE
+PT=5E443EC882C1B938C2A4C412D3A92FDF
+
+I=49
+KEY=E3C167B38A29EDFBDC37A50F434C7056D3C4601008BA7AD64F02B58001B49ADB
+IV=D55301B79FCCDFDD0E422B6FBE224F09
+CT=5E443EC882C1B938C2A4C412D3A92FDF
+PT=14A8F43BA8829B134D6BD110E6D43F92
+
+I=50
+KEY=8AD38A575E425D347C5B5BFB08A5173CC76C942BA038E1C502696490E760A549
+IV=6912EDE4D46BB0CFA06CFEF44BE9676A
+CT=14A8F43BA8829B134D6BD110E6D43F92
+PT=025982911796C2FE34C89157BF2959BD
+
+I=51
+KEY=AE4ABA37DD2C3C5109B13C3DD9FCB67EC53516BAB7AE233B36A1F5C75849FCF4
+IV=24993060836E616575EA67C6D159A142
+CT=025982911796C2FE34C89157BF2959BD
+PT=BC658642A8EEBEC6DBE2A76BCD70799B
+
+I=52
+KEY=31AC934C58BF87AD1EE4357BBE315175795090F81F409DFDED4352AC9539856F
+IV=9FE6297B8593BBFC1755094667CDE70B
+CT=BC658642A8EEBEC6DBE2A76BCD70799B
+PT=132CE1CC36EFE58A4A53534B962D2D70
+
+I=53
+KEY=79F7C18CA600203D404363908749B22F6A7C713429AF7877A71001E70314A81F
+IV=485B52C0FEBFA7905EA756EB3978E35A
+CT=132CE1CC36EFE58A4A53534B962D2D70
+PT=8D2BA39F08ED00BEB51543C0FCCFA57C
+
+I=54
+KEY=162A4089A1E46EAB5C9592BF1F98BCC2E757D2AB214278C912054227FFDB0D63
+IV=6FDD810507E44E961CD6F12F98D10EED
+CT=8D2BA39F08ED00BEB51543C0FCCFA57C
+PT=2E8D05A8A3066094025FE07F3A53A94E
+
+I=55
+KEY=DB5F33F93F2B795EDA54095937B79E4CC9DAD7038244185D105AA258C588A42D
+IV=CD7573709ECF17F586C19BE6282F228E
+CT=2E8D05A8A3066094025FE07F3A53A94E
+PT=D39EC2261C53AD45F91627E1B1F62D22
+
+I=56
+KEY=CCA770427DF8CF5350864D4E86E6D8891A4415259E17B518E94C85B9747E890F
+IV=17F843BB42D3B60D8AD24417B15146C5
+CT=D39EC2261C53AD45F91627E1B1F62D22
+PT=F517DC01890C3D300520B6CE343B7F94
+
+I=57
+KEY=25F53E7CC6590220E9426296568DE496EF53C924171B8828EC6C33774045F69B
+IV=E9524E3EBBA1CD73B9C42FD8D06B3C1F
+CT=F517DC01890C3D300520B6CE343B7F94
+PT=ECBCCBB21AC2D07E3ECACD26D42E4444
+
+I=58
+KEY=6D4A92C82C6C3D44CED65D76BB33B23E03EF02960DD95856D2A6FE51946BB2DF
+IV=48BFACB4EA353F6427943FE0EDBE56A8
+CT=ECBCCBB21AC2D07E3ECACD26D42E4444
+PT=6FF7C241A5FF025FAA8C4DAF5E0950AE
+
+I=59
+KEY=A3D0AB0A0F8EDF232D111458D3B8B1C66C18C0D7A8265A09782AB3FECA62E271
+IV=CE9A39C223E2E267E3C7492E688B03F8
+CT=6FF7C241A5FF025FAA8C4DAF5E0950AE
+PT=3B7E4B74F021F9E995627DE42B03D7D8
+
+I=60
+KEY=A8E2D59CF188CDA75C80FA49889F7EE357668BA35807A3E0ED48CE1AE16135A9
+IV=0B327E96FE0612847191EE115B27CF25
+CT=3B7E4B74F021F9E995627DE42B03D7D8
+PT=6759C15ED1049A51953E814C2445F3C6
+
+I=61
+KEY=092010B28BD3C8E59D09CE85169190BB303F4AFD890339B178764F56C524C66F
+IV=A1C2C52E7A5B0542C18934CC9E0EEE58
+CT=6759C15ED1049A51953E814C2445F3C6
+PT=05F681CB7984491E2CE5B1025F860BEB
+
+I=62
+KEY=538E3068E1059FE89C27D5F19405274835C9CB36F08770AF5493FE549AA2CD84
+IV=5AAE20DA6AD6570D012E1B748294B7F3
+CT=05F681CB7984491E2CE5B1025F860BEB
+PT=E046F5B143CEEAC44EF520F2C3BFA96E
+
+I=63
+KEY=78B5D2551099875910844A17ABBACD64D58F3E87B3499A6B1A66DEA6591D64EA
+IV=2B3BE23DF19C18B18CA39FE63FBFEA2C
+CT=E046F5B143CEEAC44EF520F2C3BFA96E
+PT=0F508DD1BCC6C520A81AE7EC75361179
+
+I=64
+KEY=8D6E7E66F496C358A369EF7C49D117A3DADFB3560F8F5F4BB27C394A2C2B7593
+IV=F5DBAC33E40F4401B3EDA56BE26BDAC7
+CT=0F508DD1BCC6C520A81AE7EC75361179
+PT=BAE114FFF19FD11336D454BF0FF6954D
+
+I=65
+KEY=781164DD6F90037E9896672FD24F1AF6603EA7A9FE108E5884A86DF523DDE0DE
+IV=F57F1ABB9B06C0263BFF88539B9E0D55
+CT=BAE114FFF19FD11336D454BF0FF6954D
+PT=FE73CE62C227459729E8FDC9116EC6BB
+
+I=66
+KEY=9268D6C0E8DE5AFBCCE137EADE6293E49E4D69CB3C37CBCFAD40903C32B32665
+IV=EA79B21D874E5985547750C50C2D8912
+CT=FE73CE62C227459729E8FDC9116EC6BB
+PT=B13971219C12C12A8308213759196B0D
+
+I=67
+KEY=701EB5AEF8262D8634B53AF1768ED68E2F7418EAA0250AE52E48B10B6BAA4D68
+IV=E276636E10F8777DF8540D1BA8EC456A
+CT=B13971219C12C12A8308213759196B0D
+PT=4F5A36173C16ED45F5D36B9D1AED84FF
+
+I=68
+KEY=40D027792516E1FE962F63B9C939677C602E2EFD9C33E7A0DB9BDA967147C997
+IV=30CE92D7DD30CC78A29A5948BFB7B1F2
+CT=4F5A36173C16ED45F5D36B9D1AED84FF
+PT=9FB89D6FEFE606058FE40B5492643596
+
+I=69
+KEY=CAAFC0DD2E4FC86AC19B40BC34F14630FF96B39273D5E1A5547FD1C2E323FC01
+IV=8A7FE7A40B59299457B42305FDC8214C
+CT=9FB89D6FEFE606058FE40B5492643596
+PT=F6D0717F197CBAE383B55117FCBE07AC
+
+I=70
+KEY=CE03D67B6DAB9CFAA0C20129475620230946C2ED6AA95B46D7CA80D51F9DFBAD
+IV=04AC16A643E454906159419573A76613
+CT=F6D0717F197CBAE383B55117FCBE07AC
+PT=7747114FF82F8C7568BE51912CFDB51A
+
+I=71
+KEY=DDCEDD32E5F0D26F7707DAE453288B537E01D3A29286D733BF74D14433604EB7
+IV=13CD0B49885B4E95D7C5DBCD147EAB70
+CT=7747114FF82F8C7568BE51912CFDB51A
+PT=E75313A8DFA7EB0AD1664B14D2DBE284
+
+I=72
+KEY=6B032958C3379BD4BEC22CD4271EB4589952C00A4D213C396E129A50E1BBAC33
+IV=B6CDF46A26C749BBC9C5F63074363F0B
+CT=E75313A8DFA7EB0AD1664B14D2DBE284
+PT=42FEDBDC4F0BD11DA42163D76E952DC7
+
+I=73
+KEY=1710F6CF86EDB5F1364F19CA676ED69BDBAC1BD6022AED24CA33F9878F2E81F4
+IV=7C13DF9745DA2E25888D351E407062C3
+CT=42FEDBDC4F0BD11DA42163D76E952DC7
+PT=6E0166BA404B3AEFACCA8E972F087EA5
+
+I=74
+KEY=9D9711F138D0C2D1003E2C99BB0F0447B5AD7D6C4261D7CB66F97710A026FF51
+IV=8A87E73EBE3D772036713553DC61D2DC
+CT=6E0166BA404B3AEFACCA8E972F087EA5
+PT=644A1DCFCA2EC01C3E8911768837D99E
+
+I=75
+KEY=1BD7E446FADA5507ECE26BBB635045E7D1E760A3884F17D758706666281126CF
+IV=8640F5B7C20A97D6ECDC4722D85F41A0
+CT=644A1DCFCA2EC01C3E8911768837D99E
+PT=4E69AE75BD37DB8024DBD1A11D6D414E
+
+I=76
+KEY=3454FD4B259FB4C086288ADAFF6464CD9F8ECED63578CC577CABB7C7357C6781
+IV=2F83190DDF45E1C76ACAE1619C34212A
+CT=4E69AE75BD37DB8024DBD1A11D6D414E
+PT=F63964784AD35374EAFC933AC11A48B6
+
+I=77
+KEY=97EFD593918FB16F2D6889C118C5ED4469B7AAAE7FAB9F23965724FDF4662F37
+IV=A3BB28D8B41005AFAB40031BE7A18989
+CT=F63964784AD35374EAFC933AC11A48B6
+PT=51CBF7F67A22DA909567D67F1919ECEF
+
+I=78
+KEY=481E90BC31903905C08D0E5AEF79A514387C5D58058945B30330F282ED7FC3D8
+IV=DFF1452FA01F886AEDE5879BF7BC4850
+CT=51CBF7F67A22DA909567D67F1919ECEF
+PT=9AE181DE8DB65E7E242926091A17D0B1
+
+I=79
+KEY=35A4F86146CED63BDCB485B0AE4C205AA29DDC86883F1BCD2719D48BF7681369
+IV=7DBA68DD775EEF3E1C398BEA4135854E
+CT=9AE181DE8DB65E7E242926091A17D0B1
+PT=47E15B5AC96A7FDB805F3B8862D9055F
+
+I=80
+KEY=5ECF20C5884FDF95C2B7C17D40CD6923E57C87DC41556416A746EF0395B11636
+IV=6B6BD8A4CE8109AE1E0344CDEE814979
+CT=47E15B5AC96A7FDB805F3B8862D9055F
+PT=1806C474A1ECE5D8183E725804FB92C3
+
+I=81
+KEY=AC473047ADF97E75C100CBBD73FA0892FD7A43A8E0B981CEBF789D5B914A84F5
+IV=F288108225B6A1E003B70AC0333761B1
+CT=1806C474A1ECE5D8183E725804FB92C3
+PT=0A0615424DAD4EFC25EC43B13C672727
+
+I=82
+KEY=6620AE39484EDD0EC21A3E3F659537DDF77C56EAAD14CF329A94DEEAAD2DA3D2
+IV=CA679E7EE5B7A37B031AF582166F3F4F
+CT=0A0615424DAD4EFC25EC43B13C672727
+PT=551639A520D0D043CAD42CB02900D5EF
+
+I=83
+KEY=04D696BB056CC59492B376CB3A0286EAA26A6F4F8DC41F715040F25A842D763D
+IV=62F638824D22189A50A948F45F97B137
+CT=551639A520D0D043CAD42CB02900D5EF
+PT=DF906B0E72FEACC9B45381B992E23A5A
+
+I=84
+KEY=0AED1F2A6660BDBA660E00137E38C1C97DFA0441FF3AB3B8E41373E316CF4C67
+IV=0E3B8991630C782EF4BD76D8443A4723
+CT=DF906B0E72FEACC9B45381B992E23A5A
+PT=D477C6287D05C0F83B27B1FD91F5F908
+
+I=85
+KEY=E0A51B848A913A860FD2C39941C8C3A1A98DC269823F7340DF34C21E873AB56F
+IV=EA4804AEECF1873C69DCC38A3FF00268
+CT=D477C6287D05C0F83B27B1FD91F5F908
+PT=6AB7E109C085B0BA7C8A8B76482F9C80
+
+I=86
+KEY=A8B0500EC0292EF668A03E8293E235BAC33A236042BAC3FAA3BE4968CF1529EF
+IV=48154B8A4AB814706772FD1BD22AF61B
+CT=6AB7E109C085B0BA7C8A8B76482F9C80
+PT=71A31000A5763A0C79B6353E39FFBE84
+
+I=87
+KEY=34C53C34901B693F4611F20F1DD5125EB2993360E7CCF9F6DA087C56F6EA976B
+IV=9C756C3A503247C92EB1CC8D8E3727E4
+CT=71A31000A5763A0C79B6353E39FFBE84
+PT=B5B377EBEBC0B32A5A0C7E2A2504C32A
+
+I=88
+KEY=A13850B9164EF60EB77E06819605AC01072A448B0C0C4ADC8004027CD3EE5441
+IV=95FD6C8D86559F31F16FF48E8BD0BE5F
+CT=B5B377EBEBC0B32A5A0C7E2A2504C32A
+PT=B74459D1E7C5CF9106C362572FE9C917
+
+I=89
+KEY=37261F6D588FF9028A23319CE02DDA71B06E1D5AEBC9854D86C7602BFC079D56
+IV=961E4FD44EC10F0C3D5D371D76287670
+CT=B74459D1E7C5CF9106C362572FE9C917
+PT=5777A0854A6E00DB0B6B199BDD35447A
+
+I=90
+KEY=085A7B276E58B9175204A87D74B9E78AE719BDDFA1A785968DAC79B02132D92C
+IV=3F7C644A36D74015D82799E194943DFB
+CT=5777A0854A6E00DB0B6B199BDD35447A
+PT=01CC73B6EE44403DFED2C91D6F0DC441
+
+I=91
+KEY=61DC99DD0C1470F511D79DCC2541002AE6D5CE694FE3C5AB737EB0AD4E3F1D6D
+IV=6986E2FA624CC9E243D335B151F8E7A0
+CT=01CC73B6EE44403DFED2C91D6F0DC441
+PT=8993161CF3E75DE836BB2C1955581DB6
+
+I=92
+KEY=AEB68207F1E4395794BA7E28CE9BF7996F46D875BC04984345C59CB41B6700DB
+IV=CF6A1BDAFDF049A2856DE3E4EBDAF7B3
+CT=8993161CF3E75DE836BB2C1955581DB6
+PT=2A4D6929ED3A66E71EFC40F1840CD649
+
+I=93
+KEY=DBF8A8AED7B6D7BCFD1B5BEEC3F01AC0450BB15C513EFEA45B39DC459F6BD692
+IV=754E2AA92652EEEB69A125C60D6BED59
+CT=2A4D6929ED3A66E71EFC40F1840CD649
+PT=596CE09B1176A9FB5A9973086A0E4C12
+
+I=94
+KEY=1A61C7F2FB652E256190C0896F800CD61C6751C74048575F01A0AF4DF5659A80
+IV=C1996F5C2CD3F9999C8B9B67AC701616
+CT=596CE09B1176A9FB5A9973086A0E4C12
+PT=B57AC41360C13F6831689C311BD0ED2C
+
+I=95
+KEY=FC3828E6A9487698231D11C10C353F2DA91D95D42089683730C8337CEEB577AC
+IV=E659EF14522D58BD428DD14863B533FB
+CT=B57AC41360C13F6831689C311BD0ED2C
+PT=F58AA69EEBF25943C728FA26524DE154
+
+I=96
+KEY=9D16CAD42D19D1A3B9CB12566745B2765C97334ACB7B3174F7E0C95ABCF896F8
+IV=612EE2328451A73B9AD603976B708D5B
+CT=F58AA69EEBF25943C728FA26524DE154
+PT=4A678FED6C5E5898A47F2DFE9DF71DF2
+
+I=97
+KEY=D9A8554717435E69EFD4A617CA70B0D216F0BCA7A72569EC539FE4A4210F8B0A
+IV=44BE9F933A5A8FCA561FB441AD3502A4
+CT=4A678FED6C5E5898A47F2DFE9DF71DF2
+PT=38011537A04E6C4A81510899741F2FFC
+
+I=98
+KEY=AA9D9A7B4E187F8D78AAEE11967A20A42EF1A990076B05A6D2CEEC3D5510A4F6
+IV=7335CF3C595B21E4977E48065C0A9076
+CT=38011537A04E6C4A81510899741F2FFC
+PT=6472060F536BC5F83A3C247F63C3580E
+
+I=99
+KEY=90A5D8CD93F0AE068E8DC72CA5DD6E184A83AF9F5400C05EE8F2C84236D3FCF8
+IV=3A3842B6DDE8D18BF627293D33A74EBC
+CT=6472060F536BC5F83A3C247F63C3580E
+PT=08B99B59D0584DAC0412796871FE3F27
+
+I=100
+KEY=489520777A18D5BF65B85AAEA29DB3D8423A34C684588DF2ECE0B12A472DC3DF
+IV=D830F8BAE9E87BB9EB359D820740DDC0
+CT=08B99B59D0584DAC0412796871FE3F27
+PT=E8B8579DF9E918B3D24C18E17068AD66
+
+I=101
+KEY=69542EE000ACEEFB5E0EB471F3CD0927AA82635B7DB195413EACA9CB37456EB9
+IV=21C10E977AB43B443BB6EEDF5150BAFF
+CT=E8B8579DF9E918B3D24C18E17068AD66
+PT=9B6C3234993F6900B3E572B5A43CA644
+
+I=102
+KEY=E88C863186548F35DF6EFB48743B7C1831EE516FE48EFC418D49DB7E9379C8FD
+IV=81D8A8D186F861CE81604F3987F6753F
+CT=9B6C3234993F6900B3E572B5A43CA644
+PT=E0A2962A02698489813292D33D02D0AB
+
+I=103
+KEY=C9DD7904D060B79B83F97A1FC93E50DED14CC745E6E778C80C7B49ADAE7B1856
+IV=2151FF35563438AE5C978157BD052CC6
+CT=E0A2962A02698489813292D33D02D0AB
+PT=10C80B22D8EC54B855E103D6B76C03BC
+
+I=104
+KEY=D208B7A87003A507561FA5C7422A85C5C184CC673E0B2C70599A4A7B19171BEA
+IV=1BD5CEACA063129CD5E6DFD88B14D51B
+CT=10C80B22D8EC54B855E103D6B76C03BC
+PT=CE88B76CC2223EB68BA9B5852C1921DB
+
+I=105
+KEY=27B0E1BF8EA57E8AD51BC3FA278369780F0C7B0BFC2912C6D233FFFE350E3A31
+IV=F5B85617FEA6DB8D8304663D65A9ECBD
+CT=CE88B76CC2223EB68BA9B5852C1921DB
+PT=00401EEE034A193C86A23152AF4B767E
+
+I=106
+KEY=45E37A710D9E754EE90B7C1DBB894DC20F4C65E5FF630BFA5491CEAC9A454C4F
+IV=62539BCE833B0BC43C10BFE79C0A24BA
+CT=00401EEE034A193C86A23152AF4B767E
+PT=CEF1DC8A618BF71C68720E6EEDE31EEF
+
+I=107
+KEY=B432E78F49D50B045C8B598EEA3D4142C1BDB96F9EE8FCE63CE3C0C277A652A0
+IV=F1D19DFE444B7E4AB580259351B40C80
+CT=CEF1DC8A618BF71C68720E6EEDE31EEF
+PT=EF8FB3790627F31E5CBF21B31FF942DE
+
+I=108
+KEY=F5CE9C0AF13DA60D32912620673AEE572E320A1698CF0FF8605CE171685F107E
+IV=41FC7B85B8E8AD096E1A7FAE8D07AF15
+CT=EF8FB3790627F31E5CBF21B31FF942DE
+PT=2EF1C697D948D712AA177855B0D56650
+
+I=109
+KEY=DA14D71084F47D87385EF58128C7517F00C3CC814187D8EACA4B9924D88A762E
+IV=2FDA4B1A75C9DB8A0ACFD3A14FFDBF28
+CT=2EF1C697D948D712AA177855B0D56650
+PT=0A20E82375680D134FE05AC74E3A0217
+
+I=110
+KEY=B68F8C980984E2508E9706117256A4A70AE324A234EFD5F985ABC3E396B07439
+IV=6C9B5B888D709FD7B6C9F3905A91F5D8
+CT=0A20E82375680D134FE05AC74E3A0217
+PT=46AF886AB871A3DABDEB32F1738E180B
+
+I=111
+KEY=078A8955ECB2F6ACB249E2DB36B660794C4CACC88C9E76233840F112E53E6C32
+IV=B10505CDE53614FC3CDEE4CA44E0C4DE
+CT=46AF886AB871A3DABDEB32F1738E180B
+PT=79949181E3D20A3042C1E7BDAE73330B
+
+I=112
+KEY=7CB2A8360EE65417A979D9B5D4A32D2935D83D496F4C7C137A8116AF4B4D5F39
+IV=7B382163E254A2BB1B303B6EE2154D50
+CT=79949181E3D20A3042C1E7BDAE73330B
+PT=12C5E55F6EA47BC44392AE9FB888C1FB
+
+I=113
+KEY=E5835F97C4FF1B007D695DD0E72324A9271DD81601E807D73913B830F3C59EC2
+IV=9931F7A1CA194F17D410846533800980
+CT=12C5E55F6EA47BC44392AE9FB888C1FB
+PT=FCA15AB64A01FA6E89FE41F72A67D9E8
+
+I=114
+KEY=50932FF04CCCE411AA0541726C1C4CD7DBBC82A04BE9FDB9B0EDF9C7D9A2472A
+IV=B51070678833FF11D76C1CA28B3F687E
+CT=FCA15AB64A01FA6E89FE41F72A67D9E8
+PT=7B75EC39F707C3C90691BE561AD5CAC6
+
+I=115
+KEY=ECAEC5FD6AF5F7DF2587C1A40CB046ADA0C96E99BCEE3E70B67C4791C3778DEC
+IV=BC3DEA0D263913CE8F8280D660AC0A7A
+CT=7B75EC39F707C3C90691BE561AD5CAC6
+PT=1D3D15FFA0B69EFA8E146301411DFA49
+
+I=116
+KEY=82F88C3850CC3D111C2125F34840A9A2BDF47B661C58A08A38682490826A77A5
+IV=6E5649C53A39CACE39A6E45744F0EF0F
+CT=1D3D15FFA0B69EFA8E146301411DFA49
+PT=34AFB3D6F0BD9ACB6954BB96B1067F9E
+
+I=117
+KEY=702FEC9E7F0D2369FF35D4B7A1269AD3895BC8B0ECE53A41513C9F06336C083B
+IV=F2D760A62FC11E78E314F144E9663371
+CT=34AFB3D6F0BD9ACB6954BB96B1067F9E
+PT=899E4C8192661CCA7C73CDFBC3DCA2F3
+
+I=118
+KEY=A1DF98E4585C1A4C15C42AD0782C925000C584317E83268B2D4F52FDF0B0AAC8
+IV=D1F0747A27513925EAF1FE67D90A0883
+CT=899E4C8192661CCA7C73CDFBC3DCA2F3
+PT=3097C0413291E217FB0E3A8A2D908C12
+
+I=119
+KEY=9F9082177BF33D8AF6131018E1EFD49F305244704C12C49CD6416877DD2026DA
+IV=3E4F1AF323AF27C6E3D73AC899C346CF
+CT=3097C0413291E217FB0E3A8A2D908C12
+PT=6C71968295905F881F95DC8BA481CA72
+
+I=120
+KEY=B7E5B267EDBFFD4DB4526BA2A1978C105C23D2F2D9829B14C9D4B4FC79A1ECA8
+IV=28753070964CC0C742417BBA4078588F
+CT=6C71968295905F881F95DC8BA481CA72
+PT=96D0AB98DBD0CB94A68FC41BEF0B418D
+
+I=121
+KEY=127FAA6C94663FA9008A1FB7A419C036CAF3796A025250806F5B70E796AAAD25
+IV=A59A180B79D9C2E4B4D87415058E4C26
+CT=96D0AB98DBD0CB94A68FC41BEF0B418D
+PT=9E3E4428A911FB328A9F89D7D5E527DB
+
+I=122
+KEY=1B9493F07E7E5F07473E6997AE15CCDC54CD3D42AB43ABB2E5C4F930434F8AFE
+IV=09EB399CEA1860AE47B476200A0C0CEA
+CT=9E3E4428A911FB328A9F89D7D5E527DB
+PT=0DB5EF3481A9945BAF2E499B5CDE8DDC
+
+I=123
+KEY=7B2B8201EEF1601C44006A6D7E06EE355978D2762AEA3FE94AEAB0AB1F910722
+IV=60BF11F1908F3F1B033E03FAD01322E9
+CT=0DB5EF3481A9945BAF2E499B5CDE8DDC
+PT=C0569DD7DCAE99859D3987B04FFD8CF0
+
+I=124
+KEY=B2D7FEE25A564FA00CEDC8E05BAC7F7D992E4FA1F644A66CD7D3371B506C8BD2
+IV=C9FC7CE3B4A72FBC48EDA28D25AA9148
+CT=C0569DD7DCAE99859D3987B04FFD8CF0
+PT=D8AF74B5BB8E632299D32E8DD4DDA012
+
+I=125
+KEY=5A06C176A290538BC549CAA8041539A941813B144DCAC54E4E00199684B12BC0
+IV=E8D13F94F8C61C2BC9A402485FB946D4
+CT=D8AF74B5BB8E632299D32E8DD4DDA012
+PT=0821FB911EDE8CDCD97DDAEDCCDB7B1C
+
+I=126
+KEY=1318D23A3A966D16FDEEE300571F3A8549A0C08553144992977DC37B486A50DC
+IV=491E134C98063E9D38A729A8530A032C
+CT=0821FB911EDE8CDCD97DDAEDCCDB7B1C
+PT=BCB2831AF3721C020FC1D683C19AEBEA
+
+I=127
+KEY=D6D24AA79B3CA4434CCE2B1470B4FE18F512439FA066559098BC15F889F0BB36
+IV=C5CA989DA1AAC955B120C81427ABC49D
+CT=BCB2831AF3721C020FC1D683C19AEBEA
+PT=BE869BB3C18EB622CCAC81B6F5B62CC4
+
+I=128
+KEY=5F62348BCD9ADB23A19E683400D968404B94D82C61E8E3B25410944E7C4697F2
+IV=89B07E2C56A67F60ED504320706D9658
+CT=BE869BB3C18EB622CCAC81B6F5B62CC4
+PT=C8D3EDD549FEA614B4F2348F82DE5531
+
+I=129
+KEY=A64795E417B7C9344185F6B0C66C096B834735F9281645A6E0E2A0C1FE98C2C3
+IV=F925A16FDA2D1217E01B9E84C6B5612B
+CT=C8D3EDD549FEA614B4F2348F82DE5531
+PT=4049BDBD9C302D8F2E06F10D34317784
+
+I=130
+KEY=CD1F9AB35436014B0CF7ECE9FF98C2BDC30E8844B4266829CEE451CCCAA9B547
+IV=6B580F574381C87F4D721A5939F4CBD6
+CT=4049BDBD9C302D8F2E06F10D34317784
+PT=E1338EA5C5462E8C458E5546FA60324D
+
+I=131
+KEY=78F7558C14BB5100CE93CD49C22BE2D9223D06E1716046A58B6A048A30C9870A
+IV=B5E8CF3F408D504BC26421A03DB32064
+CT=E1338EA5C5462E8C458E5546FA60324D
+PT=055984AA929F4D45F5812DC719D4EF24
+
+I=132
+KEY=2DBC5092C4C7AB427576EBA2855E00562764824BE3FF0BE07EEB294D291D682E
+IV=554B051ED07CFA42BBE526EB4775E28F
+CT=055984AA929F4D45F5812DC719D4EF24
+PT=ABC519C4290C69D98BF7AC2A56767202
+
+I=133
+KEY=68FA1D8FE36FC5B48A7486FBB34A7B598CA19B8FCAF36239F51C85677F6B1A2C
+IV=45464D1D27A86EF6FF026D5936147B0F
+CT=ABC519C4290C69D98BF7AC2A56767202
+PT=C825E44799B1739A1F4CB406BBEABEDD
+
+I=134
+KEY=A2302849850FD33D4048B898DB6C7B0244847FC8534211A3EA503161C481A4F1
+IV=CACA35C666601689CA3C3E636826005B
+CT=C825E44799B1739A1F4CB406BBEABEDD
+PT=D24EE8D56CE09AFE1061B4016ADD61F7
+
+I=135
+KEY=9B2E669EA4BB938072E6E97B0ACF834E96CA971D3FA28B5DFA318560AE5CC506
+IV=391E4ED721B440BD32AE51E3D1A3F84C
+CT=D24EE8D56CE09AFE1061B4016ADD61F7
+PT=50FECB118EABF93BB97102E9212C883D
+
+I=136
+KEY=A07C5EBAC9D0F862AD525C76460B4BA9C6345C0CB1097266434087898F704D3B
+IV=3B5238246D6B6BE2DFB4B50D4CC4C8E7
+CT=50FECB118EABF93BB97102E9212C883D
+PT=C370C26BD3805211A4679399DFA4DDCB
+
+I=137
+KEY=414C776222058D6285574741B2B4D11D05449E6762892077E727141050D490F0
+IV=E13029D8EBD5750028051B37F4BF9AB4
+CT=C370C26BD3805211A4679399DFA4DDCB
+PT=79715A04DF9216268C77A152CA96C2F6
+
+I=138
+KEY=5E54A416470FE8BA263C0FC88FD884297C35C463BD1B36516B50B5429A425206
+IV=1F18D374650A65D8A36B48893D6C5534
+CT=79715A04DF9216268C77A152CA96C2F6
+PT=06DF18B5FAF35F03FE22E39CAE430655
+
+I=139
+KEY=98C55CFFB53FA72345EF936283F64BB17AEADCD647E86952957256DE34015453
+IV=C691F8E9F2304F9963D39CAA0C2ECF98
+CT=06DF18B5FAF35F03FE22E39CAE430655
+PT=1AED42EB32C4BAEAF9946818AA00C324
+
+I=140
+KEY=B8332B1EE5D6A4E1BBFA20AEAE22330560079E3D752CD3B86CE63EC69E019777
+IV=20F677E150E903C2FE15B3CC2DD478B4
+CT=1AED42EB32C4BAEAF9946818AA00C324
+PT=D276B6A6D480165A944572EF76D4B3E8
+
+I=141
+KEY=6E50753A2A0814A778FA2BC773C6A7A2B271289BA1ACC5E2F8A34C29E8D5249F
+IV=D6635E24CFDEB046C3000B69DDE494A7
+CT=D276B6A6D480165A944572EF76D4B3E8
+PT=BA46F59DFADC6CA2CBB7D80E33D7B24B
+
+I=142
+KEY=D8E1763EAD728AB8AA2284964BE586880837DD065B70A94033149427DB0296D4
+IV=B6B10304877A9E1FD2D8AF513823212A
+CT=BA46F59DFADC6CA2CBB7D80E33D7B24B
+PT=FC9B9F7B5120E1D8B2DD58D211EFF053
+
+I=143
+KEY=458CB146C73342F9D5EE4364C400E8E5F4AC427D0A50489881C9CCF5CAED6687
+IV=9D6DC7786A41C8417FCCC7F28FE56E6D
+CT=FC9B9F7B5120E1D8B2DD58D211EFF053
+PT=6AD8BCAEFF6F0BF9F360FF601C9B7A43
+
+I=144
+KEY=F1FBE00DA1F634ACACB6E2F4F15C11179E74FED3F53F436172A93395D6761CC4
+IV=B477514B66C576557958A190355CF9F2
+CT=6AD8BCAEFF6F0BF9F360FF601C9B7A43
+PT=BB6E45D060E186323AC2B50CFB988856
+
+I=145
+KEY=3FBC35054FFF43657936BB676A5C5D1F251ABB0395DEC553486B86992DEE9492
+IV=CE47D508EE0977C9D58059939B004C08
+CT=BB6E45D060E186323AC2B50CFB988856
+PT=31B6157397933EE35DEE5B40FE7237BB
+
+I=146
+KEY=D49B4E96F8FC2D91FBED3985C53BEB8314ACAE70024DFBB01585DDD9D39CA329
+IV=EB277B93B7036EF482DB82E2AF67B69C
+CT=31B6157397933EE35DEE5B40FE7237BB
+PT=EFEB82ED91C5C60FB8F910542804B57B
+
+I=147
+KEY=8D4ABC926827F066B4391FF4B3D6EC99FB472C9D93883DBFAD7CCD8DFB981652
+IV=59D1F20490DBDDF74FD4267176ED071A
+CT=EFEB82ED91C5C60FB8F910542804B57B
+PT=E30D071737AB9991F000302502BE84A6
+
+I=148
+KEY=086A14365F781B2FAF533B1534F458D2184A2B8AA423A42E5D7CFDA8F92692F4
+IV=8520A8A4375FEB491B6A24E18722B44B
+CT=E30D071737AB9991F000302502BE84A6
+PT=856AF9DF9A9FE5038B75C98E0E1C720F
+
+I=149
+KEY=A64DE8CF2DF04ADB60E88C769F7025BC9D20D2553EBC412DD6093426F73AE0FB
+IV=AE27FCF9728851F4CFBBB763AB847D6E
+CT=856AF9DF9A9FE5038B75C98E0E1C720F
+PT=D84910F298F91E081480A912B1AF32D6
+
+I=150
+KEY=C52575277A0BD189E2F746FC51CA77844569C2A7A6455F25C2899D344695D22D
+IV=63689DE857FB9B52821FCA8ACEBA5238
+CT=D84910F298F91E081480A912B1AF32D6
+PT=57E4A4A2D639D414ED7F82583B4FFA52
+
+I=151
+KEY=CB9A5219490F7EE31B030ECE521C589B128D6605707C8B312FF61F6C7DDA287F
+IV=0EBF273E3304AF6AF9F4483203D62F1F
+CT=57E4A4A2D639D414ED7F82583B4FFA52
+PT=1CECC8218392F2047C0B70BEBFCC5846
+
+I=152
+KEY=AA6412AAC8FC309E6BCDFFD1DA01B6470E61AE24F3EE793553FD6FD2C2167039
+IV=61FE40B381F34E7D70CEF11F881DEEDC
+CT=1CECC8218392F2047C0B70BEBFCC5846
+PT=EC2B86A04DB2B4F41830E5EA035531E3
+
+I=153
+KEY=EFF5BC892E47F4C7EA859969255AC665E24A2884BE5CCDC14BCD8A38C14341DA
+IV=4591AE23E6BBC459814866B8FF5B7022
+CT=EC2B86A04DB2B4F41830E5EA035531E3
+PT=8A1A8EE6E08F61E99FC37AC177881C8A
+
+I=154
+KEY=D62E9405D7402765E30FDAD7A29B2E716850A6625ED3AC28D40EF0F9B6CB5D50
+IV=39DB288CF907D3A2098A43BE87C1E814
+CT=8A1A8EE6E08F61E99FC37AC177881C8A
+PT=F21583AC8C5F03C19A1A9B856C97D6E0
+
+I=155
+KEY=D49F229B7DB6973EDE6BD14AB20234379A4525CED28CAFE94E146B7CDA5C8BB0
+IV=02B1B69EAAF6B05B3D640B9D10991A46
+CT=F21583AC8C5F03C19A1A9B856C97D6E0
+PT=323191D5997CF0424B7F5501CBD55B17
+
+I=156
+KEY=08B1021CD316864EF5B370CBF891FD27A874B41B4BF05FAB056B3E7D1189D0A7
+IV=DC2E2087AEA011702BD8A1814A93C910
+CT=323191D5997CF0424B7F5501CBD55B17
+PT=B2BBCC6E54CB33319536A81174B0D73B
+
+I=157
+KEY=786AE1D89ECC32C8883D984E7DC5FD0A1ACF78751F3B6C9A905D966C6539079C
+IV=70DBE3C44DDAB4867D8EE8858554002D
+CT=B2BBCC6E54CB33319536A81174B0D73B
+PT=6E4ADDA6895734D891F328C6D0C71467
+
+I=158
+KEY=E6C7441B75AF8701E29376287A126CB07485A5D3966C584201AEBEAAB5FE13FB
+IV=9EADA5C3EB63B5C96AAEEE6607D791BA
+CT=6E4ADDA6895734D891F328C6D0C71467
+PT=8BED3D2AAB5271F90EE5335520E87AA2
+
+I=159
+KEY=22D515400072783951742ACDF2FA6DC8FF6898F93D3E29BB0F4B8DFF95166959
+IV=C412515B75DDFF38B3E75CE588E80178
+CT=8BED3D2AAB5271F90EE5335520E87AA2
+PT=D3059CA1B293AA1F52D459643C5FAB5C
+
+I=160
+KEY=D6E6A383AF38A1CD2889A5F79A23CE512C6D04588FAD83A45D9FD49BA949C205
+IV=F433B6C3AF4AD9F479FD8F3A68D9A399
+CT=D3059CA1B293AA1F52D459643C5FAB5C
+PT=C20D8580ACA043B0ED2F409EEA42C0F0
+
+I=161
+KEY=AA95A47ADECB61AAD1A05DA0CE6B17BDEE6081D8230DC014B0B09405430B02F5
+IV=7C7307F971F3C067F929F8575448D9EC
+CT=C20D8580ACA043B0ED2F409EEA42C0F0
+PT=61C0D0081F176C53DE83B70608201EE6
+
+I=162
+KEY=168A56A528A70354AD74C59A8AF33A508FA051D03C1AAC476E3323034B2B1C13
+IV=BC1FF2DFF66C62FE7CD4983A44982DED
+CT=61C0D0081F176C53DE83B70608201EE6
+PT=C016536FEFC08B69867AB2946FFBE011
+
+I=163
+KEY=92157F38953622D8C0E191DAC4179A6A4FB602BFD3DA272EE849919724D0FC02
+IV=849F299DBD91218C6D9554404EE4A03A
+CT=C016536FEFC08B69867AB2946FFBE011
+PT=6923FF03C812710270438F67EF2F42D1
+
+I=164
+KEY=CCB6779947D31DF17182FB54555B49422695FDBC1BC8562C980A1EF0CBFFBED3
+IV=5EA308A1D2E53F29B1636A8E914CD328
+CT=6923FF03C812710270438F67EF2F42D1
+PT=0D1674014AD9DC2150E073E2FCF006A8
+
+I=165
+KEY=22AA52C07B42CFEB5E75687D395D86092B8389BD51118A0DC8EA6D12370FB87B
+IV=EE1C25593C91D21A2FF793296C06CF4B
+CT=0D1674014AD9DC2150E073E2FCF006A8
+PT=6399A65CC66E9318F2CEE1103B8FFB90
+
+I=166
+KEY=527EF084271AC57F5D33F2E7C7BE1FF1481A2FE1977F19153A248C020C8043EB
+IV=70D4A2445C580A9403469A9AFEE399F8
+CT=6399A65CC66E9318F2CEE1103B8FFB90
+PT=511CBDD6CFA31788A43C765301D6BAAB
+
+I=167
+KEY=D826E762C9EA31B6F4415B3AE5ED888B1906923758DC0E9D9E18FA510D56F940
+IV=8A5817E6EEF0F4C9A972A9DD2253977A
+CT=511CBDD6CFA31788A43C765301D6BAAB
+PT=B04E78AB18AE3F5B825087D9D5794BD7
+
+I=168
+KEY=B4C2DEE60A738C428B187EC3A3A4A982A948EA9C407231C61C487D88D82FB297
+IV=6CE43984C399BDF47F5925F946492109
+CT=B04E78AB18AE3F5B825087D9D5794BD7
+PT=6B013F9A972D82BD5A87DA6C1DD5FD0F
+
+I=169
+KEY=C4A41F8C4B26391F6C0D629C6B052BD8C249D506D75FB37B46CFA7E4C5FA4F98
+IV=7066C16A4155B55DE7151C5FC8A1825A
+CT=6B013F9A972D82BD5A87DA6C1DD5FD0F
+PT=9005F8243C6486F63590E7508503719C
+
+I=170
+KEY=91A18F2681FCACE1C80DC772BD0F2628524C2D22EB3B358D735F40B440F93E04
+IV=550590AACADA95FEA400A5EED60A0DF0
+CT=9005F8243C6486F63590E7508503719C
+PT=39DEEEC3D3AEEBBF4B573462B375B5E4
+
+I=171
+KEY=E8FF0EE1269AFDCA213F69757C84704D6B92C3E13895DE32380874D6F38C8BE0
+IV=795E81C7A766512BE932AE07C18B5665
+CT=39DEEEC3D3AEEBBF4B573462B375B5E4
+PT=1910F8E7C3D863784058CB35D674AEEB
+
+I=172
+KEY=F00751EFCCECA0ECA3C252F396B4078E72823B06FB4DBD4A7850BFE325F8250B
+IV=18F85F0EEA765D2682FD3B86EA3077C3
+CT=1910F8E7C3D863784058CB35D674AEEB
+PT=4A71250E55629D3C5CC62B18B4B67653
+
+I=173
+KEY=383A1B81E82B8174A9B9F0AF9EA498A338F31E08AE2F2076249694FB914E5358
+IV=C83D4A6E24C721980A7BA25C08109F2D
+CT=4A71250E55629D3C5CC62B18B4B67653
+PT=19CBB63FBB92C7A10B676DBB5EB29060
+
+I=174
+KEY=A6695341053BD5B1E15A6CD73DEF84E12138A83715BDE7D72FF1F940CFFCC338
+IV=9E5348C0ED1054C548E39C78A34B1C42
+CT=19CBB63FBB92C7A10B676DBB5EB29060
+PT=18BA0A45E67D2CFEC691203FC2509837
+
+I=175
+KEY=71B4C384EF619E5D6CADBFC7D53564913982A272F3C0CB29E960D97F0DAC5B0F
+IV=D7DD90C5EA5A4BEC8DF7D310E8DAE070
+CT=18BA0A45E67D2CFEC691203FC2509837
+PT=7699C8550933C30D630AC16D8DA6F13D
+
+I=176
+KEY=7D0527970FD45C35817091A317A2EAB04F1B6A27FAF308248A6A1812800AAA32
+IV=0CB1E413E0B5C268EDDD2E64C2978E21
+CT=7699C8550933C30D630AC16D8DA6F13D
+PT=78FE8EEC14618ED34F63E8671434ADA7
+
+I=177
+KEY=204ECE43E91409C515077FACC37C4DF837E5E4CBEE9286F7C509F075943E0795
+IV=5D4BE9D4E6C055F09477EE0FD4DEA748
+CT=78FE8EEC14618ED34F63E8671434ADA7
+PT=0907F75149A74B49F302D2C08CF18AF5
+
+I=178
+KEY=8E80DC69B6CC0F0D7F1F0BE6E9F178AD3EE2139AA735CDBE360B22B518CF8D60
+IV=AECE122A5FD806C86A18744A2A8D3555
+CT=0907F75149A74B49F302D2C08CF18AF5
+PT=FE24023BCABCD83E6212FA53E7320D92
+
+I=179
+KEY=5152CCE87D9CCC930D7B376C4F1B334BC0C611A16D8915805419D8E6FFFD80F2
+IV=DFD21081CB50C39E72643C8AA6EA4BE6
+CT=FE24023BCABCD83E6212FA53E7320D92
+PT=9526CDED534CB3366306F8C731F87CD6
+
+I=180
+KEY=00C9D78F67F1B63181ADE21A02675C6755E0DC4C3EC5A6B6371F2021CE05FC24
+IV=519B1B671A6D7AA28CD6D5764D7C6F2C
+CT=9526CDED534CB3366306F8C731F87CD6
+PT=801F005EA2E9287FFD8D9B01BE8E2205
+
+I=181
+KEY=442603CF6A012BDB23086BD7EFD7396ED5FFDC129C2C8EC9CA92BB20708BDE21
+IV=44EFD4400DF09DEAA2A589CDEDB06509
+CT=801F005EA2E9287FFD8D9B01BE8E2205
+PT=7558994ACE0299E34EB586B832C98560
+
+I=182
+KEY=B153C7C49983077FB0C79C30266A487AA0A74558522E172A84273D9842425B41
+IV=F575C40BF3822CA493CFF7E7C9BD7114
+CT=7558994ACE0299E34EB586B832C98560
+PT=324273A52FFBFBCAC5401CFCD3075C98
+
+I=183
+KEY=0E038D82F7FAD738824EF9FEB6F6627692E536FD7DD5ECE041672164914507D9
+IV=BF504A466E79D047328965CE909C2A0C
+CT=324273A52FFBFBCAC5401CFCD3075C98
+PT=509E651E053E85340A5B545AA0E40A71
+
+I=184
+KEY=B2237D5D0E16B5F9A8FD7274F4CA1206C27B53E378EB69D44B3C753E31A10DA8
+IV=BC20F0DFF9EC62C12AB38B8A423C7070
+CT=509E651E053E85340A5B545AA0E40A71
+PT=1716AB4DCAB205D62EF356E4C565BA70
+
+I=185
+KEY=CBE25CF8F3CAB9849F44F330AD8B17E1D56DF8AEB2596C0265CF23DAF4C4B7D8
+IV=79C121A5FDDC0C7D37B98144594105E7
+CT=1716AB4DCAB205D62EF356E4C565BA70
+PT=093CA7764E7F6828EF210E89D3D01C73
+
+I=186
+KEY=2BF3C06B0CAE728C8A6134634D5DEAF1DC515FD8FC26042A8AEE2D532714ABAB
+IV=E0119C93FF64CB081525C753E0D6FD10
+CT=093CA7764E7F6828EF210E89D3D01C73
+PT=86F8B39DB10EB8B3CFED4C98BBBFFAE1
+
+I=187
+KEY=A2C742CFF575CA98D3261BE7DA99E3935AA9EC454D28BC99450361CB9CAB514A
+IV=893482A4F9DBB81459472F8497C40962
+CT=86F8B39DB10EB8B3CFED4C98BBBFFAE1
+PT=8BF9C14617B3CE1511ABBD484439D041
+
+I=188
+KEY=F8AB8BAD8F2C5A54ED4C80AD094A36D4D1502D035A9B728C54A8DC83D892810B
+IV=5A6CC9627A5990CC3E6A9B4AD3D3D547
+CT=8BF9C14617B3CE1511ABBD484439D041
+PT=C41B937B1D5E10D982C7850685997862
+
+I=189
+KEY=4DBA6859C8D681253E8F6278BE76D87D154BBE7847C56255D66F59855D0BF969
+IV=B511E3F447FADB71D3C3E2D5B73CEEA9
+CT=C41B937B1D5E10D982C7850685997862
+PT=467114F3F33C8BA65AA76C297E9DA11C
+
+I=190
+KEY=2738E652A9F41B48B443B487B2AF6D7C533AAA8BB4F9E9F38CC835AC23965875
+IV=6A828E0B61229A6D8ACCD6FF0CD9B501
+CT=467114F3F33C8BA65AA76C297E9DA11C
+PT=CB9D772C72BC5BB3E18087CABADDE5B2
+
+I=191
+KEY=A1C138E8AFAA19465AE9BD1968C19E8798A7DDA7C645B2406D48B266994BBDC7
+IV=86F9DEBA065E020EEEAA099EDA6EF3FB
+CT=CB9D772C72BC5BB3E18087CABADDE5B2
+PT=678837A26F65190F44107C19A01F97E6
+
+I=192
+KEY=CD73AF62C6130630324F71F35042BC9AFF2FEA05A920AB4F2958CE7F39542A21
+IV=6CB2978A69B91F7668A6CCEA3883221D
+CT=678837A26F65190F44107C19A01F97E6
+PT=E395804E9F2D61447B5207AA438F7D98
+
+I=193
+KEY=F076EAF59DAC3F3975E9CBED6697A21B1CBA6A4B360DCA0B520AC9D57ADB57B9
+IV=3D0545975BBF390947A6BA1E36D51E81
+CT=E395804E9F2D61447B5207AA438F7D98
+PT=CA6E3E780C170E950306FEE08CAB46D9
+
+I=194
+KEY=87DD7A9906E626E1AC55611A52EBC196D6D454333A1AC49E510C3735F6701160
+IV=77AB906C9B4A19D8D9BCAAF7347C638D
+CT=CA6E3E780C170E950306FEE08CAB46D9
+PT=419B7C538E827E431B2C2BA5AEB95373
+
+I=195
+KEY=C8D569C710030750FDA3A48E748BED26974F2860B498BADD4A201C9058C94213
+IV=4F08135E16E521B151F6C59426602CB0
+CT=419B7C538E827E431B2C2BA5AEB95373
+PT=1D6607B51B0DA629C62D00CB20870FEA
+
+I=196
+KEY=A3A22E3CED89316BC747E3326CB53C448A292FD5AF951CF48C0D1C5B784E4DF9
+IV=6B7747FBFD8A363B3AE447BC183ED162
+CT=1D6607B51B0DA629C62D00CB20870FEA
+PT=58169D0006C9031C7CCE502F086B0CD6
+
+I=197
+KEY=DDB2F456CFE201D5E1DD9EFC6593813FD23FB2D5A95C1FE8F0C34C747025412F
+IV=7E10DA6A226B30BE269A7DCE0926BD7B
+CT=58169D0006C9031C7CCE502F086B0CD6
+PT=8001E1BDAE24A2A9ABE102C2BEB4AD70
+
+I=198
+KEY=A990048427C8E19BABE1D0BB5D6A83CA523E53680778BD415B224EB6CE91EC5F
+IV=7422F0D2E82AE04E4A3C4E4738F902F5
+CT=8001E1BDAE24A2A9ABE102C2BEB4AD70
+PT=EA143E99846F5DF1C1A2AD0565D3AE45
+
+I=199
+KEY=5074E20E5B70B571A7155A3AAFE3AF2AB82A6DF18317E0B09A80E3B3AB42421A
+IV=F9E4E68A7CB854EA0CF48A81F2892CE0
+CT=EA143E99846F5DF1C1A2AD0565D3AE45
+PT=C1EBFE1B00D813BB5AC9E4B007977B19
+
+I=200
+KEY=50315F6BF520F26A044751215225348179C193EA83CFF30BC0490703ACD53903
+IV=0045BD65AE50471BA3520B1BFDC69BAB
+CT=C1EBFE1B00D813BB5AC9E4B007977B19
+PT=3476AA08CB11F13D8DD858CF10472D03
+
+I=201
+KEY=03D2536F9830D74A9B2AEDD1508CE4764DB739E248DE02364D915FCCBC921400
+IV=53E30C046D1025209F6DBCF002A9D0F7
+CT=3476AA08CB11F13D8DD858CF10472D03
+PT=C79BED3BB201F29B65CDF5709654317C
+
+I=202
+KEY=4AC2173AD99E09ECCB4A647AF96C26F98A2CD4D9FADFF0AD285CAABC2AC6257C
+IV=4910445541AEDEA6506089ABA9E0C28F
+CT=C79BED3BB201F29B65CDF5709654317C
+PT=E5E144D56A2FF95D644D51E73AEAE922
+
+I=203
+KEY=9F46778CA9C15CB9978C0DF359056F3D6FCD900C90F009F04C11FB5B102CCC5E
+IV=D58460B6705F55555CC66989A06949C4
+CT=E5E144D56A2FF95D644D51E73AEAE922
+PT=38582F30FDE74A162CCD85955C2E48FC
+
+I=204
+KEY=63038F8EA2934D0C65F181BE92B9664A5795BF3C6D1743E660DC7ECE4C0284A2
+IV=FC45F8020B5211B5F27D8C4DCBBC0977
+CT=38582F30FDE74A162CCD85955C2E48FC
+PT=266E808D7E9206C9294F0349D1CEF1DA
+
+I=205
+KEY=D43CC15DCAB5047B8C67D61F1735C6A471FB3FB11385452F49937D879DCC7578
+IV=B73F4ED368264977E99657A1858CA0EE
+CT=266E808D7E9206C9294F0349D1CEF1DA
+PT=8E3D1F7DC678C32352782D52E4CD44D5
+
+I=206
+KEY=9979232A388E0E6C766279CFE7E047B4FFC620CCD5FD860C1BEB50D5790131AD
+IV=4D45E277F23B0A17FA05AFD0F0D58110
+CT=8E3D1F7DC678C32352782D52E4CD44D5
+PT=DDC8075418E2A649D4E78144528682F9
+
+I=207
+KEY=43479EA72BF3B417CF224B15749043C5220E2798CD1F2045CF0CD1912B87B354
+IV=DA3EBD8D137DBA7BB94032DA93700471
+CT=DDC8075418E2A649D4E78144528682F9
+PT=4096B4F51C77C8A00A5308D8C3175B6A
+
+I=208
+KEY=7AE39630885C3ACDCF915625141DF45A6298936DD168E8E5C55FD949E890E83E
+IV=39A40897A3AF8EDA00B31D30608DB79F
+CT=4096B4F51C77C8A00A5308D8C3175B6A
+PT=60D0385ECE913BEC6760BAA0BCCDE853
+
+I=209
+KEY=82496ADB8A91DAE80C249D2BD8F00C990248AB331FF9D309A23F63E9545D006D
+IV=F8AAFCEB02CDE025C3B5CB0ECCEDF8C3
+CT=60D0385ECE913BEC6760BAA0BCCDE853
+PT=79A86909141C27366744FC614808705B
+
+I=210
+KEY=EF7FEE5E3FDAC015E8016A7A9D3EB8677BE0C23A0BE5F43FC57B9F881C557036
+IV=6D368485B54B1AFDE425F75145CEB4FE
+CT=79A86909141C27366744FC614808705B
+PT=9817CE82A9D821189878991B32360409
+
+I=211
+KEY=A400D423453A59F64968E8B80140AAF6E3F70CB8A23DD5275D0306932E63743F
+IV=4B7F3A7D7AE099E3A16982C29C7E1291
+CT=9817CE82A9D821189878991B32360409
+PT=C3259E5D4A3E82FDC862E862E4449DA2
+
+I=212
+KEY=B9280C8996C8BEC6888CB4D9D1E76B0620D292E5E80357DA9561EEF1CA27E99D
+IV=1D28D8AAD3F2E730C1E45C61D0A7C1F0
+CT=C3259E5D4A3E82FDC862E862E4449DA2
+PT=F035078B9A3E45B4ED561F001DB21E47
+
+I=213
+KEY=9686D9BB259CD14FA7D58C9789932385D0E7956E723D126E7837F1F1D795F7DA
+IV=2FAED532B3546F892F59384E58744883
+CT=F035078B9A3E45B4ED561F001DB21E47
+PT=596B9F7F2122A11C599626B16B6AC340
+
+I=214
+KEY=736E847DDC4C794A3AA2E22C1AF85EF1898C0A11531FB37221A1D740BCFF349A
+IV=E5E85DC6F9D0A8059D776EBB936B7D74
+CT=596B9F7F2122A11C599626B16B6AC340
+PT=800FCC5CE3B08CFFDD70FB5270DED220
+
+I=215
+KEY=728D3E35CD653621D41E591530770B370983C64DB0AF3F8DFCD12C12CC21E6BA
+IV=01E3BA4811294F6BEEBCBB392A8F55C6
+CT=800FCC5CE3B08CFFDD70FB5270DED220
+PT=5515A58EB0013D2EE561BD2826761209
+
+I=216
+KEY=929F6FD8250BAD33FAE4ED108843A2645C9663C300AE02A319B0913AEA57F4B3
+IV=E01251EDE86E9B122EFAB405B834A953
+CT=5515A58EB0013D2EE561BD2826761209
+PT=8B7B3AB73287CEAAA0098D41F0B3A28B
+
+I=217
+KEY=3F54C218B02F6097C3F31A05F5CCB8C4D7ED59743229CC09B9B91C7B1AE45638
+IV=ADCBADC09524CDA43917F7157D8F1AA0
+CT=8B7B3AB73287CEAAA0098D41F0B3A28B
+PT=90CDCF132600F622D1339197B441A4C0
+
+I=218
+KEY=2F60AEE4E6A6F7109193112BC756D7F24720966714293A2B688A8DECAEA5F2F8
+IV=10346CFC5689978752600B2E329A6F36
+CT=90CDCF132600F622D1339197B441A4C0
+PT=EA089BEC0DEE1305828522B8AD4F5A99
+
+I=219
+KEY=33623A9F86F3AF456D92076B132E46A3AD280D8B19C7292EEA0FAF5403EAA861
+IV=1C02947B60555855FC011640D4789151
+CT=EA089BEC0DEE1305828522B8AD4F5A99
+PT=339C14562AE38F84BE0FB1569C234287
+
+I=220
+KEY=6291ED0B63ED8C18A713DDCBFCA054E19EB419DD3324A6AA54001E029FC9EAE6
+IV=51F3D794E51E235DCA81DAA0EF8E1242
+CT=339C14562AE38F84BE0FB1569C234287
+PT=31050E95B1F08B9139EF7F8D42110978
+
+I=221
+KEY=7BEF1BE3E67AA478C5D9F50350D221CCAFB1174882D42D3B6DEF618FDDD8E39E
+IV=197EF6E88597286062CA28C8AC72752D
+CT=31050E95B1F08B9139EF7F8D42110978
+PT=18DE66E3B58C9ABAB99987826AF0D0AF
+
+I=222
+KEY=3DEB69283844069B400C2E7127B8CD2EB76F71AB3758B781D476E60DB7283331
+IV=460472CBDE3EA2E385D5DB72776AECE2
+CT=18DE66E3B58C9ABAB99987826AF0D0AF
+PT=B75D11E28C94DB969FE009B984DA956B
+
+I=223
+KEY=754C5BEC642540EC8BAD0778773CA8E700326049BBCC6C174B96EFB433F2A65A
+IV=48A732C45C614677CBA12909508465C9
+CT=B75D11E28C94DB969FE009B984DA956B
+PT=7CEEE835FC734108785B367A28C62058
+
+I=224
+KEY=01B0A659138DEE7CF1EFA11DD0A209247CDC887C47BF2D1F33CDD9CE1B348602
+IV=74FCFDB577A8AE907A42A665A79EA1C3
+CT=7CEEE835FC734108785B367A28C62058
+PT=F1E848F6C257D6D56B4FBCA36900614C
+
+I=225
+KEY=F9531CEDC3C5C76A90195BF1E5FB5ED98D34C08A85E8FBCA5882656D7234E74E
+IV=F8E3BAB4D048291661F6FAEC355957FD
+CT=F1E848F6C257D6D56B4FBCA36900614C
+PT=7B06A193C8B84977E56B382D424D2A78
+
+I=226
+KEY=D409DB9768430BCA0E2B68BA1CFE93A5F63261194D50B2BDBDE95D403079CD36
+IV=2D5AC77AAB86CCA09E32334BF905CD7C
+CT=7B06A193C8B84977E56B382D424D2A78
+PT=413356E3367ACBDD88ADA6DF5E09FFC6
+
+I=227
+KEY=8425B50A014625BA114ABAC1585C3F68B70137FA7B2A79603544FB9F6E7032F0
+IV=502C6E9D69052E701F61D27B44A2ACCD
+CT=413356E3367ACBDD88ADA6DF5E09FFC6
+PT=13B524E8AEBFE32CC9559B500D9E9A82
+
+I=228
+KEY=3ED2EEDFF8C12697C9CEB18B8DC86798A4B41312D5959A4CFC1160CF63EEA872
+IV=BAF75BD5F987032DD8840B4AD59458F0
+CT=13B524E8AEBFE32CC9559B500D9E9A82
+PT=91775D8DF510277669BC11697965AE99
+
+I=229
+KEY=B3C35FF0F6B2DDCF5522A35E75040BB135C34E9F2085BD3A95AD71A61A8B06EB
+IV=8D11B12F0E73FB589CEC12D5F8CC6C29
+CT=91775D8DF510277669BC11697965AE99
+PT=0AA5B5A593FED4CE1FD66736774649D2
+
+I=230
+KEY=5581EEED032A31D6F8077BEED79ABB1E3F66FB3AB37B69F48A7B16906DCD4F39
+IV=E642B11DF598EC19AD25D8B0A29EB0AF
+CT=0AA5B5A593FED4CE1FD66736774649D2
+PT=3DB595E23D32347092E5D94A8376DB5D
+
+I=231
+KEY=2337ABB014AD70D3E290033BD6FC75D702D36ED88E495D84189ECFDAEEBB9464
+IV=76B6455D178741051A9778D50166CEC9
+CT=3DB595E23D32347092E5D94A8376DB5D
+PT=2AF2DEC9D2D4F0BA81D1FC88E421C034
+
+I=232
+KEY=7C8A43D8CA68E782BBD49C18477683052821B0115C9DAD3E994F33520A9A5450
+IV=5FBDE868DEC5975159449F23918AF6D2
+CT=2AF2DEC9D2D4F0BA81D1FC88E421C034
+PT=8AF90FCCBEDCDF709AEE93FEF45C03EC
+
+I=233
+KEY=37FDC789E91F58F691931C86C4505926A2D8BFDDE241724E03A1A0ACFEC657BC
+IV=4B7784512377BF742A47809E8326DA23
+CT=8AF90FCCBEDCDF709AEE93FEF45C03EC
+PT=8E98DF785A601DF26465D9A0D163D650
+
+I=234
+KEY=57C30D92BD234BE693F15534768970FC2C4060A5B8216FBC67C4790C2FA581EC
+IV=603ECA1B543C1310026249B2B2D929DA
+CT=8E98DF785A601DF26465D9A0D163D650
+PT=21D3EAC95A088A548E5C0E56001BD103
+
+I=235
+KEY=1F9A07E73DB0530F84B6DB88C5EA0AFD0D938A6CE229E5E8E998775A2FBE50EF
+IV=48590A75809318E917478EBCB3637A01
+CT=21D3EAC95A088A548E5C0E56001BD103
+PT=48A8853D9E4E4A6351E5F5734911D569
+
+I=236
+KEY=219E87740C05905A3DAC677C78C5E6D4453B0F517C67AF8BB87D822966AF8586
+IV=3E04809331B5C355B91ABCF4BD2FEC29
+CT=48A8853D9E4E4A6351E5F5734911D569
+PT=C75ECB64A655DC6803FC976A1CAE78A9
+
+I=237
+KEY=D445B2CF4C6B8AF073FCDFF8907C4B278265C435DA3273E3BB8115437A01FD2F
+IV=F5DB35BB406E1AAA4E50B884E8B9ADF3
+CT=C75ECB64A655DC6803FC976A1CAE78A9
+PT=F063E6C6A62D07B1CA90594CB9041DE4
+
+I=238
+KEY=3DECAA3153A9658A2CAA5578AF2C55CD720622F37C1F745271114C0FC305E0CB
+IV=E9A918FE1FC2EF7A5F568A803F501EEA
+CT=F063E6C6A62D07B1CA90594CB9041DE4
+PT=45F375DDBA20D20CB6C5EAB28AA85D06
+
+I=239
+KEY=31766034845DF8A1AEDFC70CE3CD5B1D37F5572EC63FA65EC7D4A6BD49ADBDCD
+IV=0C9ACA05D7F49D2B827592744CE10ED0
+CT=45F375DDBA20D20CB6C5EAB28AA85D06
+PT=5D117AAC285D5A6948390FDAFBDACAD5
+
+I=240
+KEY=BF17727E1D5DCA94C9CCA8E11DFBF22A6AE42D82EE62FC378FEDA967B2777718
+IV=8E61124A9900323567136FEDFE36A937
+CT=5D117AAC285D5A6948390FDAFBDACAD5
+PT=C8B61B172D930641A88E9E13236E11F9
+
+I=241
+KEY=B82DB30F4271245293FC4CB6A0C10D4FA2523695C3F1FA7627633774911966E1
+IV=073AC1715F2CEEC65A30E457BD3AFF65
+CT=C8B61B172D930641A88E9E13236E11F9
+PT=FE05708E08F8568BB55175CEEF9E0433
+
+I=242
+KEY=28AE9BD5E181AC41CF2F9B4710DD160C5C57461BCB09ACFD923242BA7E8762D2
+IV=908328DAA3F088135CD3D7F1B01C1B43
+CT=FE05708E08F8568BB55175CEEF9E0433
+PT=D7DB71EAC2EF31AE105227E34134AD3C
+
+I=243
+KEY=437D385B59B4AB247A5BCFC0C0F8596F8B8C37F109E69D53826065593FB3CFEE
+IV=6BD3A38EB8350765B5745487D0254F63
+CT=D7DB71EAC2EF31AE105227E34134AD3C
+PT=ECD51D08C870983992708FC1FDFA9D15
+
+I=244
+KEY=4EF45D9C1FCA58D42D9E7E2E9C7D0B8F67592AF9C196056A1010EA98C24952FB
+IV=0D8965C7467EF3F057C5B1EE5C8552E0
+CT=ECD51D08C870983992708FC1FDFA9D15
+PT=F436BA32E9D089248AC47E40AA6B4BAC
+
+I=245
+KEY=D3F16D0CF75471A24F273B3E8EF0A3A0936F90CB28468C4E9AD494D868221957
+IV=9D053090E89E297662B94510128DA82F
+CT=F436BA32E9D089248AC47E40AA6B4BAC
+PT=F43E89C3DBD391B5778B30A36A9E42F3
+
+I=246
+KEY=953E7AB7369425A4F396D764F3EA047F67511908F3951DFBED5FA47B02BC5BA4
+IV=46CF17BBC1C05406BCB1EC5A7D1AA7DF
+CT=F43E89C3DBD391B5778B30A36A9E42F3
+PT=B12ABB428A29703B929EFDB0031694D1
+
+I=247
+KEY=C8DDFEFD3C72822B72C78757EE8EF856D67BA24A79BC6DC07FC159CB01AACF75
+IV=5DE3844A0AE6A78F815150331D64FC29
+CT=B12ABB428A29703B929EFDB0031694D1
+PT=79F19D2BD0A025D2D9822A28F5304446
+
+I=248
+KEY=870A25E9511D3F1BCFA941DA41FD00C0AF8A3F61A91C4812A64373E3F49A8B33
+IV=4FD7DB146D6FBD30BD6EC68DAF73F896
+CT=79F19D2BD0A025D2D9822A28F5304446
+PT=C52D5EF8D7A1353F5C1FF7BA33F9ED97
+
+I=249
+KEY=178B86564949AE1A0CE50E61F4D3F8776AA761997EBD7D2DFA5C8459C76366A4
+IV=9081A3BF18549101C34C4FBBB52EF8B7
+CT=C52D5EF8D7A1353F5C1FF7BA33F9ED97
+PT=82FAB7DF4BE409880B8F66210DE8D2E5
+
+I=250
+KEY=C3F845809E635052F94076E1F3026779E85DD646355974A5F1D3E278CA8BB441
+IV=D473C3D6D72AFE48F5A5788007D19F0E
+CT=82FAB7DF4BE409880B8F66210DE8D2E5
+PT=52C05722F125348666DFCF0F2D052530
+
+I=251
+KEY=34AE823E21F4C45784F2E125CF5039FCBA9D8164C47C4023970C2D77E78E9171
+IV=F756C7BEBF9794057DB297C43C525E85
+CT=52C05722F125348666DFCF0F2D052530
+PT=DE7FAAF4A10D4D5404847FA080C1DC1C
+
+I=252
+KEY=9D1EEFC6B62427F5A2CBB2047AB0E41B64E22B9065710D77938852D7674F4D6D
+IV=A9B06DF897D0E3A226395321B5E0DDE7
+CT=DE7FAAF4A10D4D5404847FA080C1DC1C
+PT=49327927599012EE87FF64F45AC9A9AE
+
+I=253
+KEY=2C7B21A79BE0B5B0E4DCC427DE8D91572DD052B73CE11F99147736233D86E4C3
+IV=B165CE612DC4924546177623A43D754C
+CT=49327927599012EE87FF64F45AC9A9AE
+PT=6E11B9F592DD99CD94F8999D9476F4CF
+
+I=254
+KEY=F4A72FB6D161B9E15A41576C5A7CBF3F43C1EB42AE3C8654808FAFBEA9F0100C
+IV=D8DC0E114A810C51BE9D934B84F12E68
+CT=6E11B9F592DD99CD94F8999D9476F4CF
+PT=108AC1FE3E008D1C3058917157003E2C
+
+I=255
+KEY=2E5FE97C58B060C9BACA9E9CC14CFC89534B2ABC903C0B48B0D73ECFFEF02E20
+IV=DAF8C6CA89D1D928E08BC9F09B3043B6
+CT=108AC1FE3E008D1C3058917157003E2C
+PT=B315EF45A3BD77688AD0976EF5DCA26B
+
+I=256
+KEY=9D763A80B96B112E1DAEA50A98C0B6F7E05EC5F933817C203A07A9A10B2C8C4B
+IV=B329D3FCE1DB71E7A7643B96598C4A7E
+CT=B315EF45A3BD77688AD0976EF5DCA26B
+PT=7BF8DABED803049DF8D1F34ED00536F7
+
+I=257
+KEY=DF5F07523E7E305B48AAD9C205AE826C9BA61F47EB8278BDC2D65AEFDB29BABC
+IV=42293DD28715217555047CC89D6E349B
+CT=7BF8DABED803049DF8D1F34ED00536F7
+PT=E55FE84DF3137D16E74DC01A1BFDA4A7
+
+I=258
+KEY=80CF537EC8836ADD0FB72F35B2EF703D7EF9F70A189105AB259B9AF5C0D41E1B
+IV=5F90542CF6FD5A86471DF6F7B741F251
+CT=E55FE84DF3137D16E74DC01A1BFDA4A7
+PT=6019F9DA2DFDCDCB14C2C6CE5B34432D
+
+I=259
+KEY=4469D3622A022CFB7614C9C9EB36E6031EE00ED0356CC86031595C3B9BE05D36
+IV=C4A6801CE281462679A3E6FC59D9963E
+CT=6019F9DA2DFDCDCB14C2C6CE5B34432D
+PT=6D2788861A8F9526D1EC8A6A8AFBA629
+
+I=260
+KEY=DED804546FA6B0BCD8C9FD9119616F9873C786562FE35D46E0B5D651111BFB1F
+IV=9AB1D73645A49C47AEDD3458F257899B
+CT=6D2788861A8F9526D1EC8A6A8AFBA629
+PT=81D5CDEA70E433A2A341FFB13ECCEC54
+
+I=261
+KEY=24FD3D900606EEF8F31156D30EA094ADF2124BBC5F076EE443F429E02FD7174B
+IV=FA2539C469A05E442BD8AB4217C1FB35
+CT=81D5CDEA70E433A2A341FFB13ECCEC54
+PT=F74B4869E92F918A95B508E382A83FA6
+
+I=262
+KEY=C24CA269EAADDFBA060AAF15C2265DE6055903D5B628FF6ED6412103AD7F28ED
+IV=E6B19FF9ECAB3142F51BF9C6CC86C94B
+CT=F74B4869E92F918A95B508E382A83FA6
+PT=EF3293511A17D0E089A8F88E396B4F31
+
+I=263
+KEY=789C94E8D2B6D6FD022ED678F42E796CEA6B9084AC3F2F8E5FE9D98D941467DC
+IV=BAD03681381B09470424796D3608248A
+CT=EF3293511A17D0E089A8F88E396B4F31
+PT=0D70FCE243309D716D8FA672A11EBCB8
+
+I=264
+KEY=B8DFB47D720C26AE22AD6C87785CCB97E71B6C66EF0FB2FF32667FFF350ADB64
+IV=C0432095A0BAF0532083BAFF8C72B2FB
+CT=0D70FCE243309D716D8FA672A11EBCB8
+PT=831365AB30D062F2B1C051A9EA03AEEB
+
+I=265
+KEY=938BCEFF0FD9AEC61CF2B0509A645A19640809CDDFDFD00D83A62E56DF09758F
+IV=2B547A827DD588683E5FDCD7E238918E
+CT=831365AB30D062F2B1C051A9EA03AEEB
+PT=EFE7E9DC254FF4AA70ABF327566A5448
+
+I=266
+KEY=BBF0C86D05BF543EC3B9A9240833187F8BEFE011FA9024A7F30DDD71896321C7
+IV=287B06920A66FAF8DF4B197492574266
+CT=EFE7E9DC254FF4AA70ABF327566A5448
+PT=2D41BEE483BD2BAD16026AD7AA5ABA07
+
+I=267
+KEY=B744A9326EC1D56CBFF51D969D075C7DA6AE5EF5792D0F0AE50FB7A623399BC0
+IV=0CB4615F6B7E81527C4CB4B295344402
+CT=2D41BEE483BD2BAD16026AD7AA5ABA07
+PT=079460C9B745A53999932C5ECFE6A37B
+
+I=268
+KEY=AE49C59DD393E9EC9030AEDAD7FC61FEA13A3E3CCE68AA337C9C9BF8ECDF38BB
+IV=190D6CAFBD523C802FC5B34C4AFB3D83
+CT=079460C9B745A53999932C5ECFE6A37B
+PT=CE7C5851D0437368FEDC7E39270A7430
+
+I=269
+KEY=8176855633B6FB2445BDDC2FD8D299576F46666D1E2BD95B8240E5C1CBD54C8B
+IV=2F3F40CBE02512C8D58D72F50F2EF8A9
+CT=CE7C5851D0437368FEDC7E39270A7430
+PT=A0C3F2D688E4370AD2F08C09B28DBCC1
+
+I=270
+KEY=050E71C47B278C5825DE84513A732D11CF8594BB96CFEE5150B069C87958F04A
+IV=8478F4924891777C6063587EE2A1B446
+CT=A0C3F2D688E4370AD2F08C09B28DBCC1
+PT=BE472E609ABB030B96739A959EDBDD21
+
+I=271
+KEY=502E4BDCF449E96CB16D5B6C097D20CC71C2BADB0C74ED5AC6C3F35DE7832D6B
+IV=55203A188F6E653494B3DF3D330E0DDD
+CT=BE472E609ABB030B96739A959EDBDD21
+PT=FE4227D6AC71519FA0F2078433DF69CA
+
+I=272
+KEY=C3DDDE6B2E80381010569BC093561F628F809D0DA005BCC56631F4D9D45C44A1
+IV=93F395B7DAC9D17CA13BC0AC9A2B3FAE
+CT=FE4227D6AC71519FA0F2078433DF69CA
+PT=3F8439C7648C5C2B5877643C536E14F9
+
+I=273
+KEY=1CC65CB104317D620D729EDEB4C4B512B004A4CAC489E0EE3E4690E587325058
+IV=DF1B82DA2AB145721D24051E2792AA70
+CT=3F8439C7648C5C2B5877643C536E14F9
+PT=E189B969BF38C8A2F38BF3F12267B5B4
+
+I=274
+KEY=D121C8556039F07E231F9E88DE60572B518D1DA37BB1284CCDCD6314A555E5EC
+IV=CDE794E464088D1C2E6D00566AA4E239
+CT=E189B969BF38C8A2F38BF3F12267B5B4
+PT=EF15CCEC56DCD62681FC7564A1095ECD
+
+I=275
+KEY=C87070F4AA767BE043B29FE3AF258C91BE98D14F2D6DFE6A4C311670045CBB21
+IV=1951B8A1CA4F8B9E60AD016B7145DBBA
+CT=EF15CCEC56DCD62681FC7564A1095ECD
+PT=BD38CD579A7124DD0814DB21FC0E7D96
+
+I=276
+KEY=08167C643CA7CAD8729B17EB91918AC103A01C18B71CDAB74425CD51F852C6B7
+IV=C0660C9096D1B138312988083EB40650
+CT=BD38CD579A7124DD0814DB21FC0E7D96
+PT=565F580B61E456544D8D553948AD95FD
+
+I=277
+KEY=55BB77ED49C419EEA418365F2750857355FF4413D6F88CE309A89868B0FF534A
+IV=5DAD0B897563D336D68321B4B6C10FB2
+CT=565F580B61E456544D8D553948AD95FD
+PT=1AA68EAC78C2B5BFF996F0B58C56432F
+
+I=278
+KEY=8FEC3C85819F24EE1DA186AB212A19D44F59CABFAE3A395CF03E68DD3CA91065
+IV=DA574B68C85B3D00B9B9B0F4067A9CA7
+CT=1AA68EAC78C2B5BFF996F0B58C56432F
+PT=65660FBF6C166604D9E717671488D734
+
+I=279
+KEY=D1D19B25C23EA5923D45493905B867D12A3FC500C22C5F5829D97FBA2821C751
+IV=5E3DA7A043A1817C20E4CF9224927E05
+CT=65660FBF6C166604D9E717671488D734
+PT=477CBD97B467AA1AAB738E294092FAA3
+
+I=280
+KEY=E1972BE045093EC4475DCE6351CDEDCB6D437897764BF54282AAF19368B33DF2
+IV=3046B0C587379B567A18875A54758A1A
+CT=477CBD97B467AA1AAB738E294092FAA3
+PT=C0ED90D90AE11390A275BD03BE00E1D5
+
+I=281
+KEY=6F622A270D77AE65084E2070343E8C7FADAEE84E7CAAE6D220DF4C90D6B3DC27
+IV=8EF501C7487E90A14F13EE1365F361B4
+CT=C0ED90D90AE11390A275BD03BE00E1D5
+PT=296FED9B8CF7C532721A2188DDB1A441
+
+I=282
+KEY=FF7209EA94C0401544991FDB57F77F2084C105D5F05D23E052C56D180B027866
+IV=901023CD99B7EE704CD73FAB63C9F35F
+CT=296FED9B8CF7C532721A2188DDB1A441
+PT=4AE1C2EB8D1CEB5804FA992708150590
+
+I=283
+KEY=73C6F94AD63DE39C289AE20179FDDDD7CE20C73E7D41C8B8563FF43F03177DF6
+IV=8CB4F0A042FDA3896C03FDDA2E0AA2F7
+CT=4AE1C2EB8D1CEB5804FA992708150590
+PT=A4EAC8940C12F9CEAC78DFDC99DF68B4
+
+I=284
+KEY=A7369886016682F6075678509FFB86ED6ACA0FAA71533176FA472BE39AC81542
+IV=D4F061CCD75B616A2FCC9A51E6065B3A
+CT=A4EAC8940C12F9CEAC78DFDC99DF68B4
+PT=70B05A9959E7C4E4545BB3AECCD8B33D
+
+I=285
+KEY=F01B9FF32CE9CA699F69ADBBC209BBD21A7A553328B4F592AE1C984D5610A67F
+IV=572D07752D8F489F983FD5EB5DF23D3F
+CT=70B05A9959E7C4E4545BB3AECCD8B33D
+PT=F4978960F1382713A5A7183B9694DE85
+
+I=286
+KEY=FF05A97961A5CA725CD2E1B2A9D58304EEEDDC53D98CD2810BBB8076C08478FA
+IV=0F1E368A4D4C001BC3BB4C096BDC38D6
+CT=F4978960F1382713A5A7183B9694DE85
+PT=EDCC3B8D26928086F1C6727833405424
+
+I=287
+KEY=AA4DB35CCBD936D13D1B7DB64638B99A0321E7DEFF1E5207FA7DF20EF3C42CDE
+IV=55481A25AA7CFCA361C99C04EFED3A9E
+CT=EDCC3B8D26928086F1C6727833405424
+PT=12A36AC1DA72345291CF206FA04F102F
+
+I=288
+KEY=611E32BF030B7B377AEC338C7FA6D88311828D1F256C66556BB2D261538B3CF1
+IV=CB5381E3C8D24DE647F74E3A399E6119
+CT=12A36AC1DA72345291CF206FA04F102F
+PT=8DA0003E090444453B932F0CDBBFA54E
+
+I=289
+KEY=43E230241EF150AC761C1307C43C3E209C228D212C6822105021FD6D883499BF
+IV=22FC029B1DFA2B9B0CF0208BBB9AE6A3
+CT=8DA0003E090444453B932F0CDBBFA54E
+PT=A3D9F2112895CEA937A2B18ABB589CC0
+
+I=290
+KEY=1FE38E9028DAC8A1E65A04C78BD0E7523FFB7F3004FDECB967834CE7336C057F
+IV=5C01BEB4362B980D904617C04FECD972
+CT=A3D9F2112895CEA937A2B18ABB589CC0
+PT=191EE02B9FED198599B5BC2F36271ABB
+
+I=291
+KEY=5FFD20799D7A7E7A328BD57B13F6E52F26E59F1B9B10F53CFE36F0C8054B1FC4
+IV=401EAEE9B5A0B6DBD4D1D1BC9826027D
+CT=191EE02B9FED198599B5BC2F36271ABB
+PT=EFC32006AE746D1E3F65E6C7ADF32804
+
+I=292
+KEY=EFEFD2A0F1917EB5BFD2337260E11023C926BF1D35649822C153160FA8B837C0
+IV=B012F2D96CEB00CF8D59E6097317F50C
+CT=EFC32006AE746D1E3F65E6C7ADF32804
+PT=F9C49B0BFFA354EEBBE3DE29BF9D2623
+
+I=293
+KEY=7676D792019D370A67526977EC5FDB5B30E22416CAC7CCCC7AB0C826172511E3
+IV=99990532F00C49BFD8805A058CBECB78
+CT=F9C49B0BFFA354EEBBE3DE29BF9D2623
+PT=EAEAE4BFF789E64D80D88CE5BC0E15CC
+
+I=294
+KEY=69202B4EB33EB35987DD82026714F603DA08C0A93D4E2A81FA6844C3AB2B042F
+IV=1F56FCDCB2A38453E08FEB758B4B2D58
+CT=EAEAE4BFF789E64D80D88CE5BC0E15CC
+PT=96C362F59FD2457A5ED68A116B4AA682
+
+I=295
+KEY=DE8B4CC7995B3E061E126157B0C2AF984CCBA25CA29C6FFBA4BECED2C061A2AD
+IV=B7AB67892A658D5F99CFE355D7D6599B
+CT=96C362F59FD2457A5ED68A116B4AA682
+PT=5498BE46DCE840F7B593BE2BC0D252CB
+
+I=296
+KEY=1BFE119E1B63BA06E9A590709A2985D218531C1A7E742F0C112D70F900B3F066
+IV=C5755D5982388400F7B7F1272AEB2A4A
+CT=5498BE46DCE840F7B593BE2BC0D252CB
+PT=697482966F491ACB46E7171A4813D916
+
+I=297
+KEY=9E6361F9775A88FAAD09711E9691798C71279E8C113D35C757CA67E348A02970
+IV=859D70676C3932FC44ACE16E0CB8FC5E
+CT=697482966F491ACB46E7171A4813D916
+PT=A799874DC7721D96DEEFAB5FE1A01A8E
+
+I=298
+KEY=7D1EF621D3ADC4BD4EC1861167FA5B0CD6BE19C1D64F28518925CCBCA90033FE
+IV=E37D97D8A4F74C47E3C8F70FF16B2280
+CT=A799874DC7721D96DEEFAB5FE1A01A8E
+PT=2D19344625CF5E6DE07EE960F4AEC5CF
+
+I=299
+KEY=7DFD0BE692B47C022DC789EF5291D2F5FBA72D87F380763C695B25DC5DAEF631
+IV=00E3FDC74119B8BF63060FFE356B89F9
+CT=2D19344625CF5E6DE07EE960F4AEC5CF
+PT=F80C5143F173AE672DA4DDC8272C13EF
+
+I=300
+KEY=A78C66D30475B93F0A87E6E4A8BFA3AE03AB7CC402F3D85B44FFF8147A82E5DE
+IV=DA716D3596C1C53D27406F0BFA2E715B
+CT=F80C5143F173AE672DA4DDC8272C13EF
+PT=76BDB7A63614A41C9D52718B3514E03C
+
+I=301
+KEY=9542E4B9D92DAF7B463C83DA257422B37516CB6234E77C47D9AD899F4F9605E2
+IV=32CE826ADD5816444CBB653E8DCB811D
+CT=76BDB7A63614A41C9D52718B3514E03C
+PT=93F65B7B961EE6B623A026576FF8890B
+
+I=302
+KEY=6932CD66A25D1DE274C7D5DF540917BFE6E09019A2F99AF1FA0DAFC8206E8CE9
+IV=FC7029DF7B70B29932FB5605717D350C
+CT=93F65B7B961EE6B623A026576FF8890B
+PT=FA5BEB508ABCBCB1B1D56C0E207A032D
+
+I=303
+KEY=595CCC3640445FF5BBF303FF7845AB821CBB7B49284526404BD8C3C600148FC4
+IV=306E0150E2194217CF34D6202C4CBC3D
+CT=FA5BEB508ABCBCB1B1D56C0E207A032D
+PT=BFAEA3EB7C617567EB302D571DBF2811
+
+I=304
+KEY=BF5382311BF88FC9E32D5BADC832BE48A315D8A254245327A0E8EE911DABA7D5
+IV=E60F4E075BBCD03C58DE5852B07715CA
+CT=BFAEA3EB7C617567EB302D571DBF2811
+PT=4B0E63933414184D43B0AA714AA31E02
+
+I=305
+KEY=B50A2FF8FAC6820638CCBA3A0CA6519CE81BBB3160304B6AE35844E05708B9D7
+IV=0A59ADC9E13E0DCFDBE1E197C494EFD4
+CT=4B0E63933414184D43B0AA714AA31E02
+PT=0073CA04B300003AF3C1035C664E0646
+
+I=306
+KEY=1A32AA7CA8B5D83C47F56C5D24EDBD38E8687135D3304B50109947BC3146BF91
+IV=AF38858452735A3A7F39D667284BECA4
+CT=0073CA04B300003AF3C1035C664E0646
+PT=75CFE6D4A4F05D8EBB5C614AC7FB48C8
+
+I=307
+KEY=C321C5381F5A334C8B82DD2F0E4C73AE9DA797E177C016DEABC526F6F6BDF759
+IV=D9136F44B7EFEB70CC77B1722AA1CE96
+CT=75CFE6D4A4F05D8EBB5C614AC7FB48C8
+PT=B0D8DB37DF5C3A87B9E5D562283E8FEE
+
+I=308
+KEY=40879EA19753F0F22B1C1BF438A446532D7F4CD6A89C2C591220F394DE8378B7
+IV=83A65B998809C3BEA09EC6DB36E835FD
+CT=B0D8DB37DF5C3A87B9E5D562283E8FEE
+PT=9C885637CC7666C04B424DD6EF1F3EDB
+
+I=309
+KEY=B6824C9F800B1E7825135F250DB99FC8B1F71AE164EA4A995962BE42319C466C
+IV=F605D23E1758EE8A0E0F44D1351DD99B
+CT=9C885637CC7666C04B424DD6EF1F3EDB
+PT=3E7F4437656E63E0ADC6C764B20FE92D
+
+I=310
+KEY=7FA3CDE5856B1F0D9AE33E9E6ED1532E8F885ED601842979F4A479268393AF41
+IV=C921817A05600175BFF061BB6368CCE6
+CT=3E7F4437656E63E0ADC6C764B20FE92D
+PT=B19CCFDAADEC54C8DD5F4FD53D3C5824
+
+I=311
+KEY=3E3ABA34DB005D9FF2CEF1321BCD018E3E14910CAC687DB129FB36F3BEAFF765
+IV=419977D15E6B4292682DCFAC751C52A0
+CT=B19CCFDAADEC54C8DD5F4FD53D3C5824
+PT=84F7D061322A4042913C0BD14F5F1391
+
+I=312
+KEY=FB474D499955CB1F37FBA309DD55E09DBAE3416D9E423DF3B8C73D22F1F0E4F4
+IV=C57DF77D42559680C535523BC698E113
+CT=84F7D061322A4042913C0BD14F5F1391
+PT=CBCD716DA9C53D7AFFFE65B780926660
+
+I=313
+KEY=7C1D07031362A7439F9DD5272DAD1D9B712E3000378700894739589571628294
+IV=875A4A4A8A376C5CA866762EF0F8FD06
+CT=CBCD716DA9C53D7AFFFE65B780926660
+PT=F605D205704496C5BFCEE88130920CDE
+
+I=314
+KEY=7E9E72A6032523643F0965E8BFCB0793872BE20547C3964CF8F7B01441F08E4A
+IV=028375A510478427A094B0CF92661A08
+CT=F605D205704496C5BFCEE88130920CDE
+PT=CFA8B47DEB5770925EA29484D82CDBB4
+
+I=315
+KEY=518CA0A8C81E9DDCE1060410C69F0ACE48835678AC94E6DEA655249099DC55FE
+IV=2F12D20ECB3BBEB8DE0F61F879540D5D
+CT=CFA8B47DEB5770925EA29484D82CDBB4
+PT=1065AD49D2DD48EB9540F23A69469B92
+
+I=316
+KEY=45E6A5A17D8D1AEA04CD8E184D0A1BF758E6FB317E49AE353315D6AAF09ACE6C
+IV=146A0509B5938736E5CB8A088B951139
+CT=1065AD49D2DD48EB9540F23A69469B92
+PT=DB12EE00C65069CFEA509BA5BD5BB6BC
+
+I=317
+KEY=FC8F8F7F8A440A6CEB920D4311851B3A83F41531B819C7FAD9454D0F4DC178D0
+IV=B9692ADEF7C91086EF5F835B5C8F00CD
+CT=DB12EE00C65069CFEA509BA5BD5BB6BC
+PT=B66316FB3CCC9B262A34C205AE43F42B
+
+I=318
+KEY=42D666DF2C1575E3B346FCBCD208AD9F359703CA84D55CDCF3718F0AE3828CFB
+IV=BE59E9A0A6517F8F58D4F1FFC38DB6A5
+CT=B66316FB3CCC9B262A34C205AE43F42B
+PT=4C851D9BDC164194A6D1FDE274C06D1B
+
+I=319
+KEY=786B9456901DFA9FF85C686DEEDCA02079121E5158C31D4855A072E89742E1E0
+IV=3ABDF289BC088F7C4B1A94D13CD40DBF
+CT=4C851D9BDC164194A6D1FDE274C06D1B
+PT=5507F1EB271BDBC0A6DD8BBAEC843A05
+
+I=320
+KEY=C79B5CD424E592D392FECD3233CEA70B2C15EFBA7FD8C688F37DF9527BC6DBE5
+IV=BFF0C882B4F8684C6AA2A55FDD12072B
+CT=5507F1EB271BDBC0A6DD8BBAEC843A05
+PT=BB10EF7C98DE0255C836D5319B94B166
+
+I=321
+KEY=10ABC5B835E6E6BD02E90B63D22EF9E7970500C6E706C4DD3B4B2C63E0526A83
+IV=D730996C1103746E9017C651E1E05EEC
+CT=BB10EF7C98DE0255C836D5319B94B166
+PT=E8B797AFDC378DB47F172260963A6E2C
+
+I=322
+KEY=75E05AAAB4E6981A20E4177D214B81EA7FB297693B314969445C0E03766804AF
+IV=654B9F1281007EA7220D1C1EF365780D
+CT=E8B797AFDC378DB47F172260963A6E2C
+PT=58ED1CC5A208A0E7340167E79F5DA7C2
+
+I=323
+KEY=A69FECC296D12216128BD1D2C48B373D275F8BAC9939E98E705D69E4E935A36D
+IV=D37FB6682237BA0C326FC6AFE5C0B6D7
+CT=58ED1CC5A208A0E7340167E79F5DA7C2
+PT=FEDA5FB215819B441BE18B0AED27A1FD
+
+I=324
+KEY=7EED1776E603DD6C20F08B4C6B121525D985D41E8CB872CA6BBCE2EE04120290
+IV=D872FBB470D2FF7A327B5A9EAF992218
+CT=FEDA5FB215819B441BE18B0AED27A1FD
+PT=7CD64E29A704F13688DB206F7F337685
+
+I=325
+KEY=D4479A0AF29AF7145EC3FB89FEF8BBA7A5539A372BBC83FCE367C2817B217415
+IV=AAAA8D7C14992A787E3370C595EAAE82
+CT=7CD64E29A704F13688DB206F7F337685
+PT=25D6728244F28F79D1BC707BE94ECA13
+
+I=326
+KEY=7FB45D09003B25EFEB5F68CCB7E09C008085E8B56F4E0C8532DBB2FA926FBE06
+IV=ABF3C703F2A1D2FBB59C9345491827A7
+CT=25D6728244F28F79D1BC707BE94ECA13
+PT=47AF03717893A10D7F40D5A3D9B82534
+
+I=327
+KEY=35EE9428D4EC49EC103EDF32F4FBEE16C72AEBC417DDAD884D9B67594BD79B32
+IV=4A5AC921D4D76C03FB61B7FE431B7216
+CT=47AF03717893A10D7F40D5A3D9B82534
+PT=B6C25C0E4CA560707588321AAF41119C
+
+I=328
+KEY=B12C0149A6EDD2DC3742D10822FEDDF771E8B7CA5B78CDF838135543E4968AAE
+IV=84C2956172019B30277C0E3AD60533E1
+CT=B6C25C0E4CA560707588321AAF41119C
+PT=09137DF5460434E863647B4B50E17A60
+
+I=329
+KEY=CFEC596CE216B14A955E7CBC095C198678FBCA3F1D7CF9105B772E08B477F0CE
+IV=7EC0582544FB6396A21CADB42BA2C471
+CT=09137DF5460434E863647B4B50E17A60
+PT=17A26688B271E9765F41C71CD8CF0C25
+
+I=330
+KEY=35903FF91CC199C048C6C031AA2F4FC96F59ACB7AF0D10660436E9146CB8FCEB
+IV=FA7C6695FED7288ADD98BC8DA373564F
+CT=17A26688B271E9765F41C71CD8CF0C25
+PT=62E3C4D53DECB83FCD5F57D1971D58FB
+
+I=331
+KEY=F262476804B79C1F85FEB875CCD5FC3E0DBA686292E1A859C969BEC5FBA5A410
+IV=C7F27891187605DFCD38784466FAB3F7
+CT=62E3C4D53DECB83FCD5F57D1971D58FB
+PT=3495C5855D819B6FF779FC7AC59BEB53
+
+I=332
+KEY=DC61E5CFC9BAE6B23B894486AD478ADD392FADE7CF6033363E1042BF3E3E4F43
+IV=2E03A2A7CD0D7AADBE77FCF3619276E3
+CT=3495C5855D819B6FF779FC7AC59BEB53
+PT=7440ABE9E1374208CFBCCC18ADC6089F
+
+I=333
+KEY=C9D2E747A1A6D594CCAE434B7605C8FB4D6F060E2E57713EF1AC8EA793F847DC
+IV=15B30288681C3326F72707CDDB424226
+CT=7440ABE9E1374208CFBCCC18ADC6089F
+PT=B6802F0F62A28AF7326CDB2144E8DE87
+
+I=334
+KEY=99FEF610CFFFACBE8C6AD0A2B0C8F8A7FBEF29014CF5FBC9C3C05586D710995B
+IV=502C11576E59792A40C493E9C6CD305C
+CT=B6802F0F62A28AF7326CDB2144E8DE87
+PT=B84D7D91E60C131F6F042D403D85C47B
+
+I=335
+KEY=91EB2713A930B6A53993029D5A056B4143A25490AAF9E8D6ACC478C6EA955D20
+IV=0815D10366CF1A1BB5F9D23FEACD93E6
+CT=B84D7D91E60C131F6F042D403D85C47B
+PT=4DDF64827A16F90B5E6B306E8F227DB7
+
+I=336
+KEY=C15019D3523304CC9231B33C53C7FE1E0E7D3012D0EF11DDF2AF48A865B72097
+IV=50BB3EC0FB03B269ABA2B1A109C2955F
+CT=4DDF64827A16F90B5E6B306E8F227DB7
+PT=FDF6E5B6486E11839EB3A7F5C3898F54
+
+I=337
+KEY=E24B749901384F48B2E740C51175E311F38BD5A49881005E6C1CEF5DA63EAFC3
+IV=231B6D4A530B4B8420D6F3F942B21D0F
+CT=FDF6E5B6486E11839EB3A7F5C3898F54
+PT=841EF37B4AF82CC5EB00E11775079D81
+
+I=338
+KEY=44B7FFFA042DCA1BF276D4911D4B0BE2779526DFD2792C9B871C0E4AD3393242
+IV=A6FC8B6305158553409194540C3EE8F3
+CT=841EF37B4AF82CC5EB00E11775079D81
+PT=1725AF7F70B65FBB060D29B3BCDF0A31
+
+I=339
+KEY=B724B2CD569E436B20594E10576934BF60B089A0A2CF7320811127F96FE63873
+IV=F3934D3752B38970D22F9A814A223F5D
+CT=1725AF7F70B65FBB060D29B3BCDF0A31
+PT=2CCC6D09954E5FE6C6A87E18950EED02
+
+I=340
+KEY=E9EB02E31CABD14DFF231F1F649294044C7CE4A937812CC647B959E1FAE8D571
+IV=5ECFB02E4A359226DF7A510F33FBA0BB
+CT=2CCC6D09954E5FE6C6A87E18950EED02
+PT=C82C82AF68EACE2AF22C3266F898F573
+
+I=341
+KEY=90C8F71B05BE122AFE5D58A7A1AAB666845066065F6BE2ECB5956B8702702002
+IV=7923F5F81915C367017E47B8C5382262
+CT=C82C82AF68EACE2AF22C3266F898F573
+PT=377F6966928959F2D68F3A2BD0EA3735
+
+I=342
+KEY=1BE70B607CF9A9E35DF916C4CC103FEBB32F0F60CDE2BB1E631A51ACD29A1737
+IV=8B2FFC7B7947BBC9A3A44E636DBA898D
+CT=377F6966928959F2D68F3A2BD0EA3735
+PT=3A8CCF4943B9866A9ABBEC0BA46F25DB
+
+I=343
+KEY=631B2C30FEA26433F0CBCD01B1CE974089A3C0298E5B3D74F9A1BDA776F532EC
+IV=78FC2750825BCDD0AD32DBC57DDEA8AB
+CT=3A8CCF4943B9866A9ABBEC0BA46F25DB
+PT=3B767EAB7F0C2D24BBE5565E93DC3E24
+
+I=344
+KEY=8785E70A8CD45A8FE1E4382DC62D563DB2D5BE82F15710504244EBF9E5290CC8
+IV=E49ECB3A72763EBC112FF52C77E3C17D
+CT=3B767EAB7F0C2D24BBE5565E93DC3E24
+PT=619610C6A4A8E9B196E65D2E5D463968
+
+I=345
+KEY=B49BAD1E8EB8B9CF7F32048A81E5BCD3D343AE4455FFF9E1D4A2B6D7B86F35A0
+IV=331E4A14026CE3409ED63CA747C8EAEE
+CT=619610C6A4A8E9B196E65D2E5D463968
+PT=F12AF66580B33C3113C45CF5EFD52F4F
+
+I=346
+KEY=3C92453C6342B6CDC18BFE05241EB5D922695821D54CC5D0C766EA2257BA1AEF
+IV=8809E822EDFA0F02BEB9FA8FA5FB090A
+CT=F12AF66580B33C3113C45CF5EFD52F4F
+PT=A427E0B2CD34285167999A9F18295D26
+
+I=347
+KEY=24A1F21CA68CF23F1674BF5328219987864EB8931878ED81A0FF70BD4F9347C9
+IV=1833B720C5CE44F2D7FF41560C3F2C5E
+CT=A427E0B2CD34285167999A9F18295D26
+PT=85F5855ACB2741070E1C89F904CBDBEA
+
+I=348
+KEY=B5479F4D4A0DBBFFBF86C576009F241403BB3DC9D35FAC86AEE3F9444B589C23
+IV=91E66D51EC8149C0A9F27A2528BEBD93
+CT=85F5855ACB2741070E1C89F904CBDBEA
+PT=295D7A02348A185F5C54113C734E9003
+
+I=349
+KEY=AA9CE82B0B649063C874699C71E8A94E2AE647CBE7D5B4D9F2B7E87838160C20
+IV=1FDB776641692B9C77F2ACEA71778D5A
+CT=295D7A02348A185F5C54113C734E9003
+PT=E466F369B840296AAB1A24ED32A19F51
+
+I=350
+KEY=A2BA72E2906E04C42C0047EF222FFFE6CE80B4A25F959DB359ADCC950AB79371
+IV=08269AC99B0A94A7E4742E7353C756A8
+CT=E466F369B840296AAB1A24ED32A19F51
+PT=099CEB8099DD025E4A57015168F75388
+
+I=351
+KEY=EA9B425CCD937976EB04693F16C4DAC4C71C5F22C6489FED13FACDC46240C0F9
+IV=482130BE5DFD7DB2C7042ED034EB2522
+CT=099CEB8099DD025E4A57015168F75388
+PT=E40CD2C0A7E7CB35C64AEB396338A801
+
+I=352
+KEY=D31BCE56BA19A7CB6057C5F2CCB3786223108DE261AF54D8D5B026FD017868F8
+IV=39808C0A778ADEBD8B53ACCDDA77A2A6
+CT=E40CD2C0A7E7CB35C64AEB396338A801
+PT=12E94732A52D15C624A8E554AB54C9A4
+
+I=353
+KEY=F0CD039C509E0EFF71B18AE3FEEB186D31F9CAD0C482411EF118C3A9AA2CA15C
+IV=23D6CDCAEA87A93411E64F113258600F
+CT=12E94732A52D15C624A8E554AB54C9A4
+PT=241C32C2C0C5C6CBE4BB354C054C68D7
+
+I=354
+KEY=0579BEABF73DD177C1F1F0827DA20BA115E5F812044787D515A3F6E5AF60C98B
+IV=F5B4BD37A7A3DF88B0407A61834913CC
+CT=241C32C2C0C5C6CBE4BB354C054C68D7
+PT=E4EA5643CF19EF64820A1B591DE1C378
+
+I=355
+KEY=99C7C61F7153FFA0F07380D052431667F10FAE51CB5E68B197A9EDBCB2810AF3
+IV=9CBE78B4866E2ED7318270522FE11DC6
+CT=E4EA5643CF19EF64820A1B591DE1C378
+PT=BC86D5465171B667CE837F874D933FF4
+
+I=356
+KEY=C2A65A0A2E71F6E7E2BD9FBB5049F7914D897B179A2FDED6592A923BFF123507
+IV=5B619C155F22094712CE1F6B020AE1F6
+CT=BC86D5465171B667CE837F874D933FF4
+PT=EEB9DC4EBD27720AD3527A1323D85413
+
+I=357
+KEY=B635E7EFD987991CD29414B3EBAB2EA4A330A7592708ACDC8A78E828DCCA6114
+IV=7493BDE5F7F66FFB30298B08BBE2D935
+CT=EEB9DC4EBD27720AD3527A1323D85413
+PT=78591E006B877AC6880834E3F98FD6B0
+
+I=358
+KEY=F5849125E52B6DF3CD8144DDB64178DDDB69B9594C8FD61A0270DCCB2545B7A4
+IV=43B176CA3CACF4EF1F15506E5DEA5679
+CT=78591E006B877AC6880834E3F98FD6B0
+PT=8F9A67CF96F4608D56923CB267855F3F
+
+I=359
+KEY=41885734A072249ADE0091A0AD87F47854F3DE96DA7BB69754E2E07942C0E89B
+IV=B40CC611455949691381D57D1BC68CA5
+CT=8F9A67CF96F4608D56923CB267855F3F
+PT=1B0B8D9118CBECBA2D5AD17A261F9D56
+
+I=360
+KEY=FF1A5B86E3545D9CB01A1222EC99A81C4FF85307C2B05A2D79B8310364DF75CD
+IV=BE920CB2432679066E1A8382411E5C64
+CT=1B0B8D9118CBECBA2D5AD17A261F9D56
+PT=6225E63F0C1A5DE00FD63032908A51F3
+
+I=361
+KEY=836FB4DC9C17E5AD70404B41CC4A043E2DDDB538CEAA07CD766E0131F455243E
+IV=7C75EF5A7F43B831C05A596320D3AC22
+CT=6225E63F0C1A5DE00FD63032908A51F3
+PT=7C66E540C016FB81A345E10331FCAFF3
+
+I=362
+KEY=63CA7D0E2675E43626B5311A7BA7131B51BB50780EBCFC4CD52BE032C5A98BCD
+IV=E0A5C9D2BA62019B56F57A5BB7ED1725
+CT=7C66E540C016FB81A345E10331FCAFF3
+PT=2F010053D3C59BB8ACB5B13B197A4204
+
+I=363
+KEY=6B5C4A2DD70FFF3023B2A775BECF05607EBA502BDD7967F4799E5109DCD3C9C9
+IV=08963723F17A1B060507966FC568167B
+CT=2F010053D3C59BB8ACB5B13B197A4204
+PT=8918E06B8619B43E859171A345E246AE
+
+I=364
+KEY=575661F811B8D8B50980A55848A48949F7A2B0405B60D3CAFC0F20AA99318F67
+IV=3C0A2BD5C6B727852A32022DF66B8C29
+CT=8918E06B8619B43E859171A345E246AE
+PT=60FF920A8495AD880459737525C109D6
+
+I=365
+KEY=5FACBE49DE8F64786918067E7E361681975D224ADFF57E42F85653DFBCF086B1
+IV=08FADFB1CF37BCCD6098A32636929FC8
+CT=60FF920A8495AD880459737525C109D6
+PT=03F09A2C18DB8BAE5CCC93B9165A1D16
+
+I=366
+KEY=9BFDA5803AC1C3004F0B138885DE59FE94ADB866C72EF5ECA49AC066AAAA9BA7
+IV=C4511BC9E44EA778261315F6FBE84F7F
+CT=03F09A2C18DB8BAE5CCC93B9165A1D16
+PT=52CB3AF36047F4D14C2EAEE3C3F8AF2A
+
+I=367
+KEY=614239035D7EF489DE2F88FDB6188EC3C6668295A769013DE8B46E856952348D
+IV=FABF9C8367BF378991249B7533C6D73D
+CT=52CB3AF36047F4D14C2EAEE3C3F8AF2A
+PT=249794B3822BB06708B5D5777D297C40
+
+I=368
+KEY=20BEFE90BA9C7EE9CFB1E569FE354258E2F116262542B15AE001BBF2147B48CD
+IV=41FCC793E7E28A60119E6D94482DCC9B
+CT=249794B3822BB06708B5D5777D297C40
+PT=1836AE59EAE452DAC108618DECD666BD
+
+I=369
+KEY=E11E8BF6DE253E4FBADEDFD44B34BE15FAC7B87FCFA6E3802109DA7FF8AD2E70
+IV=C1A0756664B940A6756F3ABDB501FC4D
+CT=1836AE59EAE452DAC108618DECD666BD
+PT=20EE84DEB0E7B0C83D74CE251AA1615C
+
+I=370
+KEY=D519038D457B4BCD9DD50C8F64FE2F2ADA293CA17F4153481C7D145AE20C4F2C
+IV=3407887B9B5E7582270BD35B2FCA913F
+CT=20EE84DEB0E7B0C83D74CE251AA1615C
+PT=6FA7D3584A2E4B803AC1AC07B09931A2
+
+I=371
+KEY=82F1611CFB9E7AF9F9274C6BF1B96BEBB58EEFF9356F18C826BCB85D52957E8E
+IV=57E86291BEE5313464F240E4954744C1
+CT=6FA7D3584A2E4B803AC1AC07B09931A2
+PT=A7B8F8AC07BAB843F4E7942A6E4A85D5
+
+I=372
+KEY=DFF5A6DE8ADE9AB78CF1E637F44FD3351236175532D5A08BD25B2C773CDFFB5B
+IV=5D04C7C27140E04E75D6AA5C05F6B8DE
+CT=A7B8F8AC07BAB843F4E7942A6E4A85D5
+PT=7F3C3702404E6E013474A0AA0EF85527
+
+I=373
+KEY=9C6A11136F64F462E7C5CB30049CDA056D0A2057729BCE8AE62F8CDD3227AE7C
+IV=439FB7CDE5BA6ED56B342D07F0D30930
+CT=7F3C3702404E6E013474A0AA0EF85527
+PT=7C0C44DC96872DEE0BAC71DDBDCC84E3
+
+I=374
+KEY=2C95624ADD9B1E09F13AE579333B22BB1106648BE41CE364ED83FD008FEB2A9F
+IV=B0FF7359B2FFEA6B16FF2E4937A7F8BE
+CT=7C0C44DC96872DEE0BAC71DDBDCC84E3
+PT=B9E4597C562E9B5C0E6815E64F767CE9
+
+I=375
+KEY=CBB3F14A21E49825990B89E7D07BC386A8E23DF7B2327838E3EBE8E6C09D5676
+IV=E7269300FC7F862C68316C9EE340E13D
+CT=B9E4597C562E9B5C0E6815E64F767CE9
+PT=4B37A1FD978F50BE9EA482CFBEACFA08
+
+I=376
+KEY=65B742FFD29D9B07F3956625AED7382EE3D59C0A25BD28867D4F6A297E31AC7E
+IV=AE04B3B5F37903226A9EEFC27EACFBA8
+CT=4B37A1FD978F50BE9EA482CFBEACFA08
+PT=D3406B71FFC847C364199666A808C43A
+
+I=377
+KEY=6C6A4DE74AF6C443B4F6A1C7DAB4A28E3095F77BDA756F451956FC4FD6396844
+IV=09DD0F18986B5F444763C7E274639AA0
+CT=D3406B71FFC847C364199666A808C43A
+PT=94744ECE39108CB8084DF8A17C49CDCC
+
+I=378
+KEY=AD09E82AFAA9F5168CD9B83F44C096A0A4E1B9B5E365E3FD111B04EEAA70A588
+IV=C163A5CDB05F3155382F19F89E74342E
+CT=94744ECE39108CB8084DF8A17C49CDCC
+PT=45EF43A20D7F174DA1463DDA678BBFFB
+
+I=379
+KEY=DC29CBF4E8B92311A9AA788C437A8EDDE10EFA17EE1AF4B0B05D3934CDFB1A73
+IV=712023DE1210D6072573C0B307BA187D
+CT=45EF43A20D7F174DA1463DDA678BBFFB
+PT=4480FB073AA197507E376C56B824C753
+
+I=380
+KEY=93308B36D3A2E1A952B96FE4687B2DF9A58E0110D4BB63E0CE6A556275DFDD20
+IV=4F1940C23B1BC2B8FB1317682B01A324
+CT=4480FB073AA197507E376C56B824C753
+PT=C8BBB77D206EF37C7C40DB175D105271
+
+I=381
+KEY=9682C995955D18471758C504201E93AC6D35B66DF4D5909CB22A8E7528CF8F51
+IV=05B242A346FFF9EE45E1AAE04865BE55
+CT=C8BBB77D206EF37C7C40DB175D105271
+PT=50C0B9001C716D53470FC9B011191402
+
+I=382
+KEY=60854B33BE79B0E631B1AF9046C46D153DF50F6DE8A4FDCFF52547C539D69B53
+IV=F60782A62B24A8A126E96A9466DAFEB9
+CT=50C0B9001C716D53470FC9B011191402
+PT=8DB5367A34C5E5B93486AB07CA8BB02E
+
+I=383
+KEY=7EE74E63D01F31D44B3860471B0BE50FB0403917DC611876C1A3ECC2F35D2B7D
+IV=1E6205506E6681327A89CFD75DCF881A
+CT=8DB5367A34C5E5B93486AB07CA8BB02E
+PT=4F9B922C88C1750829D9088F16EDB529
+
+I=384
+KEY=A65EE6CE576182F487D2C21C4F8539F3FFDBAB3B54A06D7EE87AE44DE5B09E54
+IV=D8B9A8AD877EB320CCEAA25B548EDCFC
+CT=4F9B922C88C1750829D9088F16EDB529
+PT=05A705F6B55D3ACF3E95E8264FEFFDCC
+
+I=385
+KEY=64F9A7DF5DA898C968746F96692F1892FA7CAECDE1FD57B1D6EF0C6BAA5F6398
+IV=C2A741110AC91A3DEFA6AD8A26AA2161
+CT=05A705F6B55D3ACF3E95E8264FEFFDCC
+PT=D1FB7C1A698990AC81068D08BE1CE91F
+
+I=386
+KEY=019663655974433AD5731BC4388A067D2B87D2D78874C71D57E9816314438A87
+IV=656FC4BA04DCDBF3BD07745251A51EEF
+CT=D1FB7C1A698990AC81068D08BE1CE91F
+PT=A1CD24AAFCEE3A60A025B983D10D8E54
+
+I=387
+KEY=16EF87A84F0627345CED6385A62374778A4AF67D749AFD7DF7CC38E0C54E04D3
+IV=1779E4CD1672640E899E78419EA9720A
+CT=A1CD24AAFCEE3A60A025B983D10D8E54
+PT=B9064D063D2C8D8D935B53CBEF3224E2
+
+I=388
+KEY=80931C61E23BA976FFC9288F74AD876D334CBB7B49B670F064976B2B2A7C2031
+IV=967C9BC9AD3D8E42A3244B0AD28EF31A
+CT=B9064D063D2C8D8D935B53CBEF3224E2
+PT=8AD3B2222D84A4B25DC1311378027207
+
+I=389
+KEY=227ACE0315678DEE433049D8CDFEE2D8B99F09596432D44239565A38527E5236
+IV=A2E9D262F75C2498BCF96157B95365B5
+CT=8AD3B2222D84A4B25DC1311378027207
+PT=3A7FC9D43F1F997FAF4931101C5B5FD4
+
+I=390
+KEY=11799A22D50C53A89EDF396B7C7565AD83E0C08D5B2D4D3D961F6B284E250DE2
+IV=33035421C06BDE46DDEF70B3B18B8775
+CT=3A7FC9D43F1F997FAF4931101C5B5FD4
+PT=930860056FE2FDDC10059D09385C0415
+
+I=391
+KEY=58DE85D9975D5F8A16C47C834568EF1D10E8A08834CFB0E1861AF621767909F7
+IV=49A71FFB42510C22881B45E8391D8AB0
+CT=930860056FE2FDDC10059D09385C0415
+PT=F41CCB823840FF7D16C6990A14E591D9
+
+I=392
+KEY=3C8567CD05AF33761FE05FBDC2596EBFE4F46B0A0C8F4F9C90DC6F2B629C982E
+IV=645BE21492F26CFC0924233E873181A2
+CT=F41CCB823840FF7D16C6990A14E591D9
+PT=82899B698456363C175791B845D5736F
+
+I=393
+KEY=F50F05CBDDFEBE7A656EE5C08CC24FF5667DF06388D979A0878BFE932749EB41
+IV=C98A6206D8518D0C7A8EBA7D4E9B214A
+CT=82899B698456363C175791B845D5736F
+PT=CF85BFDA1DFF5ADFFAF1B3E000B407F3
+
+I=394
+KEY=B44AA91A374D1C5A7BD00557CBD24962A9F84FB99526237F7D7A4D7327FDECB2
+IV=4145ACD1EAB3A2201EBEE09747100697
+CT=CF85BFDA1DFF5ADFFAF1B3E000B407F3
+PT=34EEA75CC20C6EDEE9A5379C3B5CF01A
+
+I=395
+KEY=4C401127C0AFABBEA4C93FD80BA009CC9D16E8E5572A4DA194DF7AEF1CA11CA8
+IV=F80AB83DF7E2B7E4DF193A8FC07240AE
+CT=34EEA75CC20C6EDEE9A5379C3B5CF01A
+PT=27C6392ABE790B448CC9216B3FCF5454
+
+I=396
+KEY=44D59CB8EBCC91362462D1D8FE193270BAD0D1CFE95346E518165B84236E48FC
+IV=08958D9F2B633A8880ABEE00F5B93BBC
+CT=27C6392ABE790B448CC9216B3FCF5454
+PT=2C39AC10C7D51B61D8F437D9BAA24A55
+
+I=397
+KEY=E42795DA2BF8FA7A3B0E83923A5E243196E97DDF2E865D84C0E26C5D99CC02A9
+IV=A0F20962C0346B4C1F6C524AC4471641
+CT=2C39AC10C7D51B61D8F437D9BAA24A55
+PT=F828BC735827C106E61F8FFFE9453A77
+
+I=398
+KEY=7F05DC0CD80178018D3A90E4A0CE63156EC1C1AC76A19C8226FDE3A2708938DE
+IV=9B2249D6F3F9827BB63413769A904724
+CT=F828BC735827C106E61F8FFFE9453A77
+PT=DF8129A79852FEE2A8015A2379A7215B
+
+I=399
+KEY=935560C6072D897477D71AC4C12188D0B140E80BEEF362608EFCB981092E1985
+IV=EC50BCCADF2CF175FAED8A2061EFEBC5
+CT=DF8129A79852FEE2A8015A2379A7215B
+PT=CD6429CF3F81F8B4F82BC627A8283096
+
+===========
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/test/cbc_e_m.txt b/mechglue/src/lib/crypto/aes/test/cbc_e_m.txt
new file mode 100644
index 000000000..cd344785f
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/cbc_e_m.txt
@@ -0,0 +1,7224 @@
+
+=========================
+
+FILENAME:  "cbc_e_m.txt"
+
+Cipher Block Chaining (CBC) Mode - ENCRYPTION
+Monte Carlo Test
+
+Algorithm Name: Rijndael
+Principal Submitter: Joan Daemen
+
+==========
+
+KEYSIZE=128
+
+I=0
+KEY=00000000000000000000000000000000
+IV=00000000000000000000000000000000
+PT=00000000000000000000000000000000
+CT=8A05FC5E095AF4848A08D328D3688E3D
+
+I=1
+KEY=8A05FC5E095AF4848A08D328D3688E3D
+IV=8A05FC5E095AF4848A08D328D3688E3D
+PT=204F17E2444381F6114FF53934C0BCD3
+CT=192D9B3AA10BB2F7846CCBA0085C657A
+
+I=2
+KEY=93286764A85146730E641888DB34EB47
+IV=192D9B3AA10BB2F7846CCBA0085C657A
+PT=983BF6F5A6DFBCDAA19370666E83A99A
+CT=40D8DAF6D1FDA0A073B3BD18B7695D2E
+
+I=3
+KEY=D3F0BD9279ACE6D37DD7A5906C5DB669
+IV=40D8DAF6D1FDA0A073B3BD18B7695D2E
+PT=C48CD503A21C8AD0B2483EF15F79571D
+CT=3EDBE80D69A1D2248CA55FC17C4EF3C5
+
+I=4
+KEY=ED2B559F100D34F7F172FA51101345AC
+IV=3EDBE80D69A1D2248CA55FC17C4EF3C5
+PT=6A49A07B90CE830C20BC239646D936C0
+CT=D87891CF573C99EAE4349A70CA099415
+
+I=5
+KEY=3553C4504731AD1D15466021DA1AD1B9
+IV=D87891CF573C99EAE4349A70CA099415
+PT=0ACB9A969946F523317BB932CE1561A4
+CT=24E8F1013F479BBE655DF088C9316BC7
+
+I=6
+KEY=11BB3551787636A3701B90A9132BBA7E
+IV=24E8F1013F479BBE655DF088C9316BC7
+PT=3DFC8683C1D626A26E2513EB747E8B0F
+CT=2C92E80D8D1F70B411C28BD9FDABF21D
+
+I=7
+KEY=3D29DD5CF569461761D91B70EE804863
+IV=2C92E80D8D1F70B411C28BD9FDABF21D
+PT=FAE2D6A36DBD17199F257643C89EB608
+CT=A61810A2798A70A9D2B37E88DEF9AE0F
+
+I=8
+KEY=9B31CDFE8CE336BEB36A65F83079E66C
+IV=A61810A2798A70A9D2B37E88DEF9AE0F
+PT=CB97F090318A6B10F5044EB8333ECDD6
+CT=0034FA480DE6F65D98D30B026118718F
+
+I=9
+KEY=9B0537B68105C0E32BB96EFA516197E3
+IV=0034FA480DE6F65D98D30B026118718F
+PT=1B8030AC682BA677A7A3ACDC7FB33BB6
+CT=BEA24548CBC4A6630C9F1251F2C3DC51
+
+I=10
+KEY=25A772FE4AC1668027267CABA3A24BB2
+IV=BEA24548CBC4A6630C9F1251F2C3DC51
+PT=D0524282C9AC395508CB2991822E8F42
+CT=4F278DD0B06CBFBAA928635E7CA81B68
+
+I=11
+KEY=6A80FF2EFAADD93A8E0E1FF5DF0A50DA
+IV=4F278DD0B06CBFBAA928635E7CA81B68
+PT=49EA900E2F61DF8CDEA7D479F59C4C30
+CT=EDFF930BB183F8DAC2FC0BD01AD65882
+
+I=12
+KEY=877F6C254B2E21E04CF21425C5DC0858
+IV=EDFF930BB183F8DAC2FC0BD01AD65882
+PT=A1BBEB4E44EF725497B8C589192CC900
+CT=A6FE530E9509D48BAF30F601D04DB19D
+
+I=13
+KEY=21813F2BDE27F56BE3C2E2241591B9C5
+IV=A6FE530E9509D48BAF30F601D04DB19D
+PT=4AD71402771A83F41F7E3AC004150CB7
+CT=FF1148A2E07401F7291B418D62618B65
+
+I=14
+KEY=DE9077893E53F49CCAD9A3A977F032A0
+IV=FF1148A2E07401F7291B418D62618B65
+PT=AC47A1FD3490D6E809D40D4BEB8FF639
+CT=4420D4686F7A4D77A72810E89A5E0DF1
+
+I=15
+KEY=9AB0A3E15129B9EB6DF1B341EDAE3F51
+IV=4420D4686F7A4D77A72810E89A5E0DF1
+PT=F22E1865DD87A88238173FC693C382E7
+CT=A4C7DE5DF9E2B6A20A1E22F8D7496ACD
+
+I=16
+KEY=3E777DBCA8CB0F4967EF91B93AE7559C
+IV=A4C7DE5DF9E2B6A20A1E22F8D7496ACD
+PT=929EFB34B1C552221B648A3D2C678EC9
+CT=D93DBCCA25FA4D9D8C37B3F107FCFA3C
+
+I=17
+KEY=E74AC1768D3142D4EBD822483D1BAFA0
+IV=D93DBCCA25FA4D9D8C37B3F107FCFA3C
+PT=771C61ABB1E9BAB6F678336C8193307E
+CT=75F491C2EA85184ACA3C96B769FA9698
+
+I=18
+KEY=92BE50B467B45A9E21E4B4FF54E13938
+IV=75F491C2EA85184ACA3C96B769FA9698
+PT=55E42F98CCED821FE211D29674E77F48
+CT=A9C7536B77265ECBF7AC5ECD1EF5DDE2
+
+I=19
+KEY=3B7903DF10920455D648EA324A14E4DA
+IV=A9C7536B77265ECBF7AC5ECD1EF5DDE2
+PT=56BC0FA54F6F1E04A9A8893D3964EA68
+CT=3C749BF7EFA55CE924D1B33291C2B586
+
+I=20
+KEY=070D9828FF3758BCF2995900DBD6515C
+IV=3C749BF7EFA55CE924D1B33291C2B586
+PT=45D9BBBB1F3BB33EE182F09C90B1661C
+CT=C4708DBAEBD202CDD2054DDCB1AF7BAB
+
+I=21
+KEY=C37D159214E55A71209C14DC6A792AF7
+IV=C4708DBAEBD202CDD2054DDCB1AF7BAB
+PT=37765B154264AD781BBE5F5717DE7038
+CT=87457FD2EE747645576A27F46B00EC30
+
+I=22
+KEY=44386A40FA912C3477F633280179C6C7
+IV=87457FD2EE747645576A27F46B00EC30
+PT=A7150BBC7BE3837E145AB83E554B49DE
+CT=E25743DAD8E627803DA6C5E587C82384
+
+I=23
+KEY=A66F299A22770BB44A50F6CD86B1E543
+IV=E25743DAD8E627803DA6C5E587C82384
+PT=173343A8488146FC9E4B59C2DF42BAF3
+CT=0D0A78CD5E3EB40F92FB55351122E92B
+
+I=24
+KEY=AB6551577C49BFBBD8ABA3F897930C68
+IV=0D0A78CD5E3EB40F92FB55351122E92B
+PT=3B68CFE78B5DEA8F5165A2034D8C2823
+CT=1921B523A2F9B5F53C740D451C9FCE0C
+
+I=25
+KEY=B244E474DEB00A4EE4DFAEBD8B0CC264
+IV=1921B523A2F9B5F53C740D451C9FCE0C
+PT=FDDD484B52C7F3A32F4514BEF5A646E3
+CT=6EAC2BB6EDF35C1267FF4F10700F3CD7
+
+I=26
+KEY=DCE8CFC23343565C8320E1ADFB03FEB3
+IV=6EAC2BB6EDF35C1267FF4F10700F3CD7
+PT=CDAD592E5467AD1FA1B71D8AC050FCE0
+CT=D9624E40A8C9A2C58ABEDBAEB865DC1F
+
+I=27
+KEY=058A81829B8AF499099E3A03436622AC
+IV=D9624E40A8C9A2C58ABEDBAEB865DC1F
+PT=F9E90A4D7A9EF66818004CBC47C8C6EA
+CT=DE15C7322B32738BB493E7FA27AFE6E2
+
+I=28
+KEY=DB9F46B0B0B88712BD0DDDF964C9C44E
+IV=DE15C7322B32738BB493E7FA27AFE6E2
+PT=FE3CC4AE4A13AC8946407CEEE220290B
+CT=5822C79D627AD8A0C4975873D62C5E11
+
+I=29
+KEY=83BD812DD2C25FB2799A858AB2E59A5F
+IV=5822C79D627AD8A0C4975873D62C5E11
+PT=A5106EBD8888CC3A6884AC8E8EA9C97A
+CT=F5AD0473A4228662D9F76E7A5ED4DBDD
+
+I=30
+KEY=7610855E76E0D9D0A06DEBF0EC314182
+IV=F5AD0473A4228662D9F76E7A5ED4DBDD
+PT=4F30B073FB95CD0F0317E749F20E7A7D
+CT=4B39DA1FA331CFEB1D6713054C6E9474
+
+I=31
+KEY=3D295F41D5D1163BBD0AF8F5A05FD5F6
+IV=4B39DA1FA331CFEB1D6713054C6E9474
+PT=4850735E17F01A3B131E1B78B3A6EB96
+CT=32D1BE8640859CFAB16D64CE8795729B
+
+I=32
+KEY=0FF8E1C795548AC10C679C3B27CAA76D
+IV=32D1BE8640859CFAB16D64CE8795729B
+PT=A8C4B9E0069935CB046ACBB49C0B1205
+CT=47DC1150929AA9610938CB0CFE92995E
+
+I=33
+KEY=4824F09707CE23A0055F5737D9583E33
+IV=47DC1150929AA9610938CB0CFE92995E
+PT=13F5DA56D399A7DAA004D0BE76845E68
+CT=BCA6BD8971837B8A81B923E5B2ED0D83
+
+I=34
+KEY=F4824D1E764D582A84E674D26BB533B0
+IV=BCA6BD8971837B8A81B923E5B2ED0D83
+PT=8397C79E02FDFE6B7D47FA0181EA453A
+CT=23D991B7DA5E96966830E7B40B5A2D8A
+
+I=35
+KEY=D75BDCA9AC13CEBCECD6936660EF1E3A
+IV=23D991B7DA5E96966830E7B40B5A2D8A
+PT=18987E5504E23C0F862BCA8DFFC2B07F
+CT=17AA31C49F584DEF77C8E7891B11652B
+
+I=36
+KEY=C0F1ED6D334B83539B1E74EF7BFE7B11
+IV=17AA31C49F584DEF77C8E7891B11652B
+PT=A34D44CC1C6E171D7D48447F87E2F2C1
+CT=DD1F90F66D4062E6823F0F229562D110
+
+I=37
+KEY=1DEE7D9B5E0BE1B519217BCDEE9CAA01
+IV=DD1F90F66D4062E6823F0F229562D110
+PT=C9793582E22B8840BBAA3D7669208CCC
+CT=8F5B876777F7CA903B1D6346AA8BDAE7
+
+I=38
+KEY=92B5FAFC29FC2B25223C188B441770E6
+IV=8F5B876777F7CA903B1D6346AA8BDAE7
+PT=730EACFEE3817A94B88117ABB3F9CDE4
+CT=388780BA989C0A8BB5BD9E4086D91EF7
+
+I=39
+KEY=AA327A46B16021AE978186CBC2CE6E11
+IV=388780BA989C0A8BB5BD9E4086D91EF7
+PT=F004D3A14C6C94FA2D39BE0C71119658
+CT=7F4C33E4F5C055C05DB4B7691061B307
+
+I=40
+KEY=D57E49A244A0746ECA3531A2D2AFDD16
+IV=7F4C33E4F5C055C05DB4B7691061B307
+PT=575F86A5D1637CB86449F8BC0F1573D3
+CT=F6FE1919F174065AB31AC43E0D733A81
+
+I=41
+KEY=238050BBB5D47234792FF59CDFDCE797
+IV=F6FE1919F174065AB31AC43E0D733A81
+PT=14F8E2DB61B05E094CA4C0E9DA7800EE
+CT=4CB876F2DC169F955E639C6C916340A6
+
+I=42
+KEY=6F38264969C2EDA1274C69F04EBFA731
+IV=4CB876F2DC169F955E639C6C916340A6
+PT=F88BA2E4AA4ABDD381778DFD1DA1856F
+CT=AEEB80B469D89E45BC3426B6CCC50440
+
+I=43
+KEY=C1D3A6FD001A73E49B784F46827AA371
+IV=AEEB80B469D89E45BC3426B6CCC50440
+PT=195F74019B65C0F7D724491BDE8C8B88
+CT=2FD7CCDBDB2B2037C104F0A707A11EDA
+
+I=44
+KEY=EE046A26DB3153D35A7CBFE185DBBDAB
+IV=2FD7CCDBDB2B2037C104F0A707A11EDA
+PT=FF51887AB5FEC9C97CB61BB2DE9CDBC6
+CT=8DF7BB99B781C63F4F8B2A7D5DFF2960
+
+I=45
+KEY=63F3D1BF6CB095EC15F7959CD82494CB
+IV=8DF7BB99B781C63F4F8B2A7D5DFF2960
+PT=A35AAB0055E99FA980D59B242B8C6257
+CT=7D96ECC20571E9E85C16E3BDADA374CA
+
+I=46
+KEY=1E653D7D69C17C0449E176217587E001
+IV=7D96ECC20571E9E85C16E3BDADA374CA
+PT=02CC392194874CD531025588C96E2D22
+CT=AA1DC2E69CE582DFA9A1B435854FCBB1
+
+I=47
+KEY=B478FF9BF524FEDBE040C214F0C82BB0
+IV=AA1DC2E69CE582DFA9A1B435854FCBB1
+PT=94CC5DB118EF53C904B0EEC23AC650FD
+CT=DA0CA33BCCE4ABA1936833127D1F5E25
+
+I=48
+KEY=6E745CA039C0557A7328F1068DD77595
+IV=DA0CA33BCCE4ABA1936833127D1F5E25
+PT=52F009E929526E923BE4F43B66876725
+CT=B5E80FF4DADD69BB7493B9F72A752811
+
+I=49
+KEY=DB9C5354E31D3CC107BB48F1A7A25D84
+IV=B5E80FF4DADD69BB7493B9F72A752811
+PT=6B88B42E99E5B4F838064A711B71DE1F
+CT=5CDDCE45516C6D1654647A1A541AC435
+
+I=50
+KEY=87419D11B27151D753DF32EBF3B899B1
+IV=5CDDCE45516C6D1654647A1A541AC435
+PT=9E25CBDD8E2D7D68FF72932E35879175
+CT=3C7E88A9A6462D08ADA5910A3FCE611A
+
+I=51
+KEY=BB3F15B814377CDFFE7AA3E1CC76F8AB
+IV=3C7E88A9A6462D08ADA5910A3FCE611A
+PT=72A4EF1D82A3AC5C1DFDF8C4DCFB9F6E
+CT=E428200E1C3BE9A5141F73590B7473B8
+
+I=52
+KEY=5F1735B6080C957AEA65D0B8C7028B13
+IV=E428200E1C3BE9A5141F73590B7473B8
+PT=7CD8053F2FD743A44CC39F75C1E81075
+CT=AB3B8A79653E884053AFC8C14504AF77
+
+I=53
+KEY=F42CBFCF6D321D3AB9CA187982062464
+IV=AB3B8A79653E884053AFC8C14504AF77
+PT=0731077A8B6854CB90AFFAE3A3B199C4
+CT=53B7DFD6D12DDE7966C62FCC1946A4AC
+
+I=54
+KEY=A79B6019BC1FC343DF0C37B59B4080C8
+IV=53B7DFD6D12DDE7966C62FCC1946A4AC
+PT=E4E26CA1DA697F30E0542763313A79B7
+CT=6DEC201BBB90B66A3B2DFF4FA1DDF7C4
+
+I=55
+KEY=CA774002078F7529E421C8FA3A9D770C
+IV=6DEC201BBB90B66A3B2DFF4FA1DDF7C4
+PT=C2CF11681C4767A78B2F95AFB50CF155
+CT=F535B7CD4135A39E0E344BD2CFA14B83
+
+I=56
+KEY=3F42F7CF46BAD6B7EA158328F53C3C8F
+IV=F535B7CD4135A39E0E344BD2CFA14B83
+PT=606618948C1ED454B9B0F92435381D2D
+CT=209AC483682C48AA197BB64417127656
+
+I=57
+KEY=1FD8334C2E969E1DF36E356CE22E4AD9
+IV=209AC483682C48AA197BB64417127656
+PT=8F8A70AADF2F8BFB5E137F86AC83D32F
+CT=76F5F43A888D7F22D698A73810ED5B15
+
+I=58
+KEY=692DC776A61BE13F25F69254F2C311CC
+IV=76F5F43A888D7F22D698A73810ED5B15
+PT=E9E8AEBF16A5F4E1C26B4A385163E844
+CT=625C62F33C9548F2651FB0A08BF45286
+
+I=59
+KEY=0B71A5859A8EA9CD40E922F47937434A
+IV=625C62F33C9548F2651FB0A08BF45286
+PT=C69CFD36C50EBA06E3B3C4AB7C9B694E
+CT=3931CE6DF783063F26920D4048B00C82
+
+I=60
+KEY=32406BE86D0DAFF2667B2FB431874FC8
+IV=3931CE6DF783063F26920D4048B00C82
+PT=5DFE322DD692BA8DD9CD328A5AF9A3B7
+CT=A3CA3ECE725C84281144052A80EA5176
+
+I=61
+KEY=918A55261F512BDA773F2A9EB16D1EBE
+IV=A3CA3ECE725C84281144052A80EA5176
+PT=4BBD16BF74226F816767A7207C672C9A
+CT=94552690A231354F8F9BEF295E55F142
+
+I=62
+KEY=05DF73B6BD601E95F8A4C5B7EF38EFFC
+IV=94552690A231354F8F9BEF295E55F142
+PT=7055D0C535B2B0501FF6AAEE46E03818
+CT=771908987F00C2D822897E7EEA148F29
+
+I=63
+KEY=72C67B2EC260DC4DDA2DBBC9052C60D5
+IV=771908987F00C2D822897E7EEA148F29
+PT=7336B9D4977BDDA811C0C5EBEA539574
+CT=7AA84598115B181863081AFCC239EDD2
+
+I=64
+KEY=086E3EB6D33BC455B925A135C7158D07
+IV=7AA84598115B181863081AFCC239EDD2
+PT=5296C8546532BAEACBEC9F29916FB6B2
+CT=3D95967035AF639B2D2814DEB9B7F86A
+
+I=65
+KEY=35FBA8C6E694A7CE940DB5EB7EA2756D
+IV=3D95967035AF639B2D2814DEB9B7F86A
+PT=430880F5576C7783BC1336F900DDD037
+CT=4D70AAD2FC9EF403B463A72DB4CFE640
+
+I=66
+KEY=788B02141A0A53CD206E12C6CA6D932D
+IV=4D70AAD2FC9EF403B463A72DB4CFE640
+PT=E489B93778DE0C42FEFB6122ECA46BDC
+CT=165DDB405546934E81CB6B0B89B4A40E
+
+I=67
+KEY=6ED6D9544F4CC083A1A579CD43D93723
+IV=165DDB405546934E81CB6B0B89B4A40E
+PT=8E5481ACD58BFC5D141C1F71CDE91E37
+CT=693775A3661CE9D0E4CB4888431C64A5
+
+I=68
+KEY=07E1ACF729502953456E314500C55386
+IV=693775A3661CE9D0E4CB4888431C64A5
+PT=4AAA5E507EFB9FAD15E5F4C77F46AF89
+CT=C42391D50B1210C67B6AD642745A4DAC
+
+I=69
+KEY=C3C23D22224239953E04E707749F1E2A
+IV=C42391D50B1210C67B6AD642745A4DAC
+PT=4E0748F8716801B099494037485B8BA4
+CT=A4CB7F010AC42B4C3C14F02353F3644A
+
+I=70
+KEY=67094223288612D902101724276C7A60
+IV=A4CB7F010AC42B4C3C14F02353F3644A
+PT=0B7B41D57885DB37A2FC355C8D03FF3C
+CT=1BB0CBD24537B36EB555BE8C0FEC3A1F
+
+I=71
+KEY=7CB989F16DB1A1B7B745A9A82880407F
+IV=1BB0CBD24537B36EB555BE8C0FEC3A1F
+PT=4696F9A564354194142AB7B8630B4279
+CT=18B10BAE39D4FA58F586A067A8E38BC5
+
+I=72
+KEY=6408825F54655BEF42C309CF8063CBBA
+IV=18B10BAE39D4FA58F586A067A8E38BC5
+PT=0B59EBABAB994F2DDB3DE383454BECE8
+CT=C09C6670B93ECD303BA53DE58DD81A64
+
+I=73
+KEY=A494E42FED5B96DF7966342A0DBBD1DE
+IV=C09C6670B93ECD303BA53DE58DD81A64
+PT=2F897F3385E71133CEC8367411E830A3
+CT=45EA7CB9119DF7367294F9FE36D4A09F
+
+I=74
+KEY=E17E9896FCC661E90BF2CDD43B6F7141
+IV=45EA7CB9119DF7367294F9FE36D4A09F
+PT=8CDE9D975B51A098F4CAC93DC58C002F
+CT=02DDD735439A8AE03E976E629A6C992C
+
+I=75
+KEY=E3A34FA3BF5CEB093565A3B6A103E86D
+IV=02DDD735439A8AE03E976E629A6C992C
+PT=1E20571F82C2C6884A6F90A23FD3A925
+CT=B040686B866AE80A88B899031F2F0EE4
+
+I=76
+KEY=53E327C839360303BDDD3AB5BE2CE689
+IV=B040686B866AE80A88B899031F2F0EE4
+PT=0851624711970ADE2F456D5DAFB17E05
+CT=201756BC061706513264A3C489D95A0C
+
+I=77
+KEY=73F471743F2105528FB9997137F5BC85
+IV=201756BC061706513264A3C489D95A0C
+PT=E8B1410DE742136E71F54D31FEAA72EB
+CT=2EF27C31AA488648FCE0F1804D658092
+
+I=78
+KEY=5D060D459569831A735968F17A903C17
+IV=2EF27C31AA488648FCE0F1804D658092
+PT=97E0CA84C9B22C8942C7FC5088EAED04
+CT=7545F1D9C8F5F8B441EDCDAF00462344
+
+I=79
+KEY=2843FC9C5D9C7BAE32B4A55E7AD61F53
+IV=7545F1D9C8F5F8B441EDCDAF00462344
+PT=7B5572C09E998656B55C53748CF77C21
+CT=347875EFD6BD978CD1B2EA949F7E2358
+
+I=80
+KEY=1C3B89738B21EC22E3064FCAE5A83C0B
+IV=347875EFD6BD978CD1B2EA949F7E2358
+PT=A30001AA29D70B0A141B8FC8B9B2E210
+CT=9C956408BA335CCC9F02F31CC45FD5E6
+
+I=81
+KEY=80AEED7B3112B0EE7C04BCD621F7E9ED
+IV=9C956408BA335CCC9F02F31CC45FD5E6
+PT=839783D75859393B215010F63159FA45
+CT=B70E700F4A7ED08618754960B83BD0F2
+
+I=82
+KEY=37A09D747B6C60686471F5B699CC391F
+IV=B70E700F4A7ED08618754960B83BD0F2
+PT=1E3C630BC8C34BF8822686043D14E4D6
+CT=4721B6796F82D47D6EEB9CB11A19605E
+
+I=83
+KEY=70812B0D14EEB4150A9A690783D55941
+IV=4721B6796F82D47D6EEB9CB11A19605E
+PT=CEE1B977E8B75623CC4E2C4F4765FE2A
+CT=3382E1B076680BBBE7C451582016DD11
+
+I=84
+KEY=4303CABD6286BFAEED5E385FA3C38450
+IV=3382E1B076680BBBE7C451582016DD11
+PT=02365457AB60C892A0C34A7067AB7608
+CT=AB581732E06B90AA0C835C1C7B6D18B5
+
+I=85
+KEY=E85BDD8F82ED2F04E1DD6443D8AE9CE5
+IV=AB581732E06B90AA0C835C1C7B6D18B5
+PT=222B7ED84C648C12FFDD6E8E13EEC651
+CT=3E2E592CEEAD3B5E16860E80E406E882
+
+I=86
+KEY=D67584A36C40145AF75B6AC33CA87467
+IV=3E2E592CEEAD3B5E16860E80E406E882
+PT=7D24BD646EEBA44ED27B11DA42D72FF8
+CT=9163F6DBE0D8BB79A154D92E37A07E1C
+
+I=87
+KEY=471672788C98AF23560FB3ED0B080A7B
+IV=9163F6DBE0D8BB79A154D92E37A07E1C
+PT=42B571FFB3275F5A8E26616A3F0E3403
+CT=E1340E61513FE8146F29E111392E2C3A
+
+I=88
+KEY=A6227C19DDA74737392652FC32262641
+IV=E1340E61513FE8146F29E111392E2C3A
+PT=6EFD16D48E03B6E1CD74777ABC891DA8
+CT=3D703B4FD8A8A7F015D0FD47DE0C5A28
+
+I=89
+KEY=9B524756050FE0C72CF6AFBBEC2A7C69
+IV=3D703B4FD8A8A7F015D0FD47DE0C5A28
+PT=7956129687AC95397E14821A17F267DE
+CT=C5C6D2BAABDBE0B82CDFFFE7A92C8344
+
+I=90
+KEY=5E9495ECAED4007F0029505C4506FF2D
+IV=C5C6D2BAABDBE0B82CDFFFE7A92C8344
+PT=AC661770332FE0A45B80791C3A5D1241
+CT=6F7BDE1BD17C5B10064B52EB54EE90B0
+
+I=91
+KEY=31EF4BF77FA85B6F066202B711E86F9D
+IV=6F7BDE1BD17C5B10064B52EB54EE90B0
+PT=1DE0702C81667A979E5E3542DA95C5AD
+CT=DC7E35D5B02AFF4B92C190265E01C0F8
+
+I=92
+KEY=ED917E22CF82A42494A392914FE9AF65
+IV=DC7E35D5B02AFF4B92C190265E01C0F8
+PT=A491CB4321C757FD353B560C0B3EA4D0
+CT=D753F5A6C5D7E17F4024FD8675B23E7F
+
+I=93
+KEY=3AC28B840A55455BD4876F173A5B911A
+IV=D753F5A6C5D7E17F4024FD8675B23E7F
+PT=418FA3B3E9B4E463D04AC3A3361DCA57
+CT=B635529E8080B33E9AD6D79B8203112D
+
+I=94
+KEY=8CF7D91A8AD5F6654E51B88CB8588037
+IV=B635529E8080B33E9AD6D79B8203112D
+PT=C87E4ED505989807D1DBDA4769804EA3
+CT=43E763CD1B9EE4BC474B79C1E0DA2564
+
+I=95
+KEY=CF10BAD7914B12D9091AC14D5882A553
+IV=43E763CD1B9EE4BC474B79C1E0DA2564
+PT=042F084454D0EE01AB00D3921E1BCA06
+CT=C799956FF8A7A05B71123EBC4AA09C0C
+
+I=96
+KEY=08892FB869ECB2827808FFF11222395F
+IV=C799956FF8A7A05B71123EBC4AA09C0C
+PT=9A8E40400C51A438DCE498AD3455DE51
+CT=76679B0E26B1B6CA2A8D90944777C57F
+
+I=97
+KEY=7EEEB4B64F5D044852856F655555FC20
+IV=76679B0E26B1B6CA2A8D90944777C57F
+PT=227E122D3AF18A3CAA973B33B3356CE7
+CT=B2F52396F02D2DFFE36C5F9238AC1EBE
+
+I=98
+KEY=CC1B9720BF7029B7B1E930F76DF9E29E
+IV=B2F52396F02D2DFFE36C5F9238AC1EBE
+PT=0D9CDD97E2FE0E78CF16B1596DC20ABA
+CT=7C8EDD3A079835954238E0FE4872AAE1
+
+I=99
+KEY=B0954A1AB8E81C22F3D1D009258B487F
+IV=7C8EDD3A079835954238E0FE4872AAE1
+PT=925A7ECD233B3B3CCDE2221A03C5F720
+CT=D7C9FD3EF010C8577087591149D5640F
+
+I=100
+KEY=675CB72448F8D475835689186C5E2C70
+IV=D7C9FD3EF010C8577087591149D5640F
+PT=59FEFBE5179F0E7E48F3D97CDA314FF5
+CT=2608CCE6BA917551DEF84FA7BCA9B23C
+
+I=101
+KEY=41547BC2F269A1245DAEC6BFD0F79E4C
+IV=2608CCE6BA917551DEF84FA7BCA9B23C
+PT=7F24A1BA8762294194F76322A6B28A16
+CT=EFF1513B52D5D74D2202898AC99552C4
+
+I=102
+KEY=AEA52AF9A0BC76697FAC4F351962CC88
+IV=EFF1513B52D5D74D2202898AC99552C4
+PT=79B43F27F3E144C4EFBF383698A1EC90
+CT=B4B3B020D44D059666E86D22072916B5
+
+I=103
+KEY=1A169AD974F173FF194422171E4BDA3D
+IV=B4B3B020D44D059666E86D22072916B5
+PT=8BF20B60B4774354857BA2979CD396F9
+CT=6F1A3D43CC2171A808AE8D38396DE1D1
+
+I=104
+KEY=750CA79AB8D0025711EAAF2F27263BEC
+IV=6F1A3D43CC2171A808AE8D38396DE1D1
+PT=74955DDACFB8A5467D069F1EF341248B
+CT=47C23A68DA351C22EBF86FDBD8F723B4
+
+I=105
+KEY=32CE9DF262E51E75FA12C0F4FFD11858
+IV=47C23A68DA351C22EBF86FDBD8F723B4
+PT=25D7A186ED990020E10A23C5CFB1CEF9
+CT=D5F2E2C2CED730479D87E0AF0FEF8A73
+
+I=106
+KEY=E73C7F30AC322E326795205BF03E922B
+IV=D5F2E2C2CED730479D87E0AF0FEF8A73
+PT=13480F2EDCCB62B8F9A7DF98238571FC
+CT=F29A46A7F1B1D1D4F5FE30E569D7A801
+
+I=107
+KEY=15A639975D83FFE6926B10BE99E93A2A
+IV=F29A46A7F1B1D1D4F5FE30E569D7A801
+PT=75E138123B5A98596303ACF9DAEEA714
+CT=9F6E9A13913DF78AC67BD20303AF49B5
+
+I=108
+KEY=8AC8A384CCBE086C5410C2BD9A46739F
+IV=9F6E9A13913DF78AC67BD20303AF49B5
+PT=DBD0AE00FD06761626366EB251412A32
+CT=46AC9F42239B22A163CE0FDEAA103D44
+
+I=109
+KEY=CC643CC6EF252ACD37DECD6330564EDB
+IV=46AC9F42239B22A163CE0FDEAA103D44
+PT=B8768A8AF461C9547D1F982FE90E96B6
+CT=95D7C8F969B0EEB03FEC257043597315
+
+I=110
+KEY=59B3F43F8695C47D0832E813730F3DCE
+IV=95D7C8F969B0EEB03FEC257043597315
+PT=3D20CC8AD484048251C7A81C7E3CA59C
+CT=6B74AF42435BC640A826EC443207574E
+
+I=111
+KEY=32C75B7DC5CE023DA014045741086A80
+IV=6B74AF42435BC640A826EC443207574E
+PT=BF719F78B23BAFD4A50634BCD9361095
+CT=31E3919F36D79FBF61884227110C10FF
+
+I=112
+KEY=0324CAE2F3199D82C19C467050047A7F
+IV=31E3919F36D79FBF61884227110C10FF
+PT=E1D32740BB8B6D67AD3038887899F090
+CT=A1CD90683CE041D6CA20780176FDD5F4
+
+I=113
+KEY=A2E95A8ACFF9DC540BBC3E7126F9AF8B
+IV=A1CD90683CE041D6CA20780176FDD5F4
+PT=3069EA97F092ACDCF41649377B8FCBC8
+CT=7220F866A10DC711DC1D277B4C8F204D
+
+I=114
+KEY=D0C9A2EC6EF41B45D7A1190A6A768FC6
+IV=7220F866A10DC711DC1D277B4C8F204D
+PT=B0563A5E0EE1E2B96F3F7D04EE39EA7C
+CT=CF81CA348B98C532B172F032AE0A6FED
+
+I=115
+KEY=1F4868D8E56CDE7766D3E938C47CE02B
+IV=CF81CA348B98C532B172F032AE0A6FED
+PT=B1B78BD75C30DD4E1E198ACB98B498A6
+CT=99C990D64D27D47ED0C1E7F186AC6674
+
+I=116
+KEY=8681F80EA84B0A09B6120EC942D0865F
+IV=99C990D64D27D47ED0C1E7F186AC6674
+PT=D413E3CC66E9938E4E0CFC1975E38C8C
+CT=30C7DAD86FEF77C43A44A3EF8B116354
+
+I=117
+KEY=B64622D6C7A47DCD8C56AD26C9C1E50B
+IV=30C7DAD86FEF77C43A44A3EF8B116354
+PT=CD85D9334481AE85B8816233CA4AF7DB
+CT=9E717B45239DD908138837154B803654
+
+I=118
+KEY=28375993E439A4C59FDE9A338241D35F
+IV=9E717B45239DD908138837154B803654
+PT=925BA3760D655D5B788802DDE25732BB
+CT=4A6E32C01709EBCCC9BCA43FD5DFDFB3
+
+I=119
+KEY=62596B53F3304F0956623E0C579E0CEC
+IV=4A6E32C01709EBCCC9BCA43FD5DFDFB3
+PT=0AA6264BFCC7BD07FA8F94E1EF739633
+CT=7263392DC9DA868BC0317A6D4AD52553
+
+I=120
+KEY=103A527E3AEAC982965344611D4B29BF
+IV=7263392DC9DA868BC0317A6D4AD52553
+PT=FB385BD8ECE7C4DFE2351D851141888D
+CT=AA49B1DDA3AF4D05D861667E88AD61AB
+
+I=121
+KEY=BA73E3A3994584874E32221F95E64814
+IV=AA49B1DDA3AF4D05D861667E88AD61AB
+PT=510E13E20BB06EAD335F10F2C69831D3
+CT=3AC256A92F69AF35DB05DDCA61CF1EE4
+
+I=122
+KEY=80B1B50AB62C2BB29537FFD5F42956F0
+IV=3AC256A92F69AF35DB05DDCA61CF1EE4
+PT=0A07CAA0EC6CB726F1A38847253BECB6
+CT=037497736381429A5E5A139C44A6C64A
+
+I=123
+KEY=83C52279D5AD6928CB6DEC49B08F90BA
+IV=037497736381429A5E5A139C44A6C64A
+PT=864FEF67C8902757E2CFB28DA2EF3C8D
+CT=5393D7F9F37A5B9F1F82C1BE20435149
+
+I=124
+KEY=D056F58026D732B7D4EF2DF790CCC1F3
+IV=5393D7F9F37A5B9F1F82C1BE20435149
+PT=ED2D2A671677067B30540D4C9D86905F
+CT=2969AC5FB94EC76209C6DF58F6B8AA01
+
+I=125
+KEY=F93F59DF9F99F5D5DD29F2AF66746BF2
+IV=2969AC5FB94EC76209C6DF58F6B8AA01
+PT=67ED14454DAD764C1772BCB1E0527954
+CT=150F94E1940F9D2ACC735F79B0912A06
+
+I=126
+KEY=EC30CD3E0B9668FF115AADD6D6E541F4
+IV=150F94E1940F9D2ACC735F79B0912A06
+PT=517A4852F68370EDD879E32F52FD4D2B
+CT=6EFD8E4E4C096A2033B3DA8A1F0066AF
+
+I=127
+KEY=82CD4370479F02DF22E9775CC9E5275B
+IV=6EFD8E4E4C096A2033B3DA8A1F0066AF
+PT=DBF4CAD912437115658E5BA5E1724739
+CT=899D9126CD85D2D4053AD9EE7156041B
+
+I=128
+KEY=0B50D2568A1AD00B27D3AEB2B8B32340
+IV=899D9126CD85D2D4053AD9EE7156041B
+PT=69B302F96AFCF802AC639EBABC52ECFB
+CT=819E4B8319807088FF306E125E52DAD3
+
+I=129
+KEY=8ACE99D5939AA083D8E3C0A0E6E1F993
+IV=819E4B8319807088FF306E125E52DAD3
+PT=F5CA57371833F0AF98F0EC02DFE518ED
+CT=4DFA3739235D14660DF7D5FDE36F6567
+
+I=130
+KEY=C734AEECB0C7B4E5D514155D058E9CF4
+IV=4DFA3739235D14660DF7D5FDE36F6567
+PT=29BBD9264B9792BED8A8EFA43F943A7D
+CT=4EA36ECCBCCD9FAFD8FB588BD53826A7
+
+I=131
+KEY=8997C0200C0A2B4A0DEF4DD6D0B6BA53
+IV=4EA36ECCBCCD9FAFD8FB588BD53826A7
+PT=149120CFC3D7C671F287AA77A4A3EF97
+CT=0282357C78C8944A5520AF80506DE30D
+
+I=132
+KEY=8B15F55C74C2BF0058CFE25680DB595E
+IV=0282357C78C8944A5520AF80506DE30D
+PT=02C2E0CCB12F5216213D493325F38FC3
+CT=C827C36F654137A2BB127D1782285B10
+
+I=133
+KEY=43323633118388A2E3DD9F4102F3024E
+IV=C827C36F654137A2BB127D1782285B10
+PT=FA1693AD90401791FF9093A562EC66EB
+CT=3723A94BC91032BF8DB599ABEFB784D1
+
+I=134
+KEY=74119F78D893BA1D6E6806EAED44869F
+IV=3723A94BC91032BF8DB599ABEFB784D1
+PT=5410CBE33ABB58AB0B0E86F5817E6F2C
+CT=26A520B5B475632EE8806648BFC028AF
+
+I=135
+KEY=52B4BFCD6CE6D93386E860A25284AE30
+IV=26A520B5B475632EE8806648BFC028AF
+PT=B01A11D200C24F4333029DE3BFF49601
+CT=36D5E00E0A53D7CE1498215AFA686905
+
+I=136
+KEY=64615FC366B50EFD927041F8A8ECC735
+IV=36D5E00E0A53D7CE1498215AFA686905
+PT=252E4460E9A391D54CE9E516663E59AE
+CT=829F0B7B17ED5F2FB7A014A6CD9D8052
+
+I=137
+KEY=E6FE54B8715851D225D0555E65714767
+IV=829F0B7B17ED5F2FB7A014A6CD9D8052
+PT=BCC51A6493F6847BEA8219329F67308D
+CT=BAB1D358D08DA13BEC485051F2EBFE2E
+
+I=138
+KEY=5C4F87E0A1D5F0E9C998050F979AB949
+IV=BAB1D358D08DA13BEC485051F2EBFE2E
+PT=D89236011B3C2338E95322D4716AEE59
+CT=29BA99F8CF8B48134B1330E75BD7254E
+
+I=139
+KEY=75F51E186E5EB8FA828B35E8CC4D9C07
+IV=29BA99F8CF8B48134B1330E75BD7254E
+PT=21D0EB5857C93A0D4D75253E1020C00E
+CT=9D557274FE14AA69673441117A2D7DA2
+
+I=140
+KEY=E8A06C6C904A1293E5BF74F9B660E1A5
+IV=9D557274FE14AA69673441117A2D7DA2
+PT=3C3BB454584C4C7570089B6E631BA035
+CT=543EF50A024E77ACE685BD0BBB47232D
+
+I=141
+KEY=BC9E99669204653F033AC9F20D27C288
+IV=543EF50A024E77ACE685BD0BBB47232D
+PT=8ED890BC903AEAC7C3C685980EDB3370
+CT=884BD68868D89DE9DEDB2D95A8B992FB
+
+I=142
+KEY=34D54FEEFADCF8D6DDE1E467A59E5073
+IV=884BD68868D89DE9DEDB2D95A8B992FB
+PT=684DEBD6DEDE24BD0F4F8AFA47F08AEF
+CT=DB00984CAEB14CF5A1FDE8E8E9C03830
+
+I=143
+KEY=EFD5D7A2546DB4237C1C0C8F4C5E6843
+IV=DB00984CAEB14CF5A1FDE8E8E9C03830
+PT=C42B245443F2695F306455199C7C76FE
+CT=0CA808425E8EBDDD5519130F4900329F
+
+I=144
+KEY=E37DDFE00AE309FE29051F80055E5ADC
+IV=0CA808425E8EBDDD5519130F4900329F
+PT=1655F89334CCB6ED8E140088997BD2D1
+CT=0DAE2F85CD81874DCD7368277D0C386D
+
+I=145
+KEY=EED3F065C7628EB3E47677A7785262B1
+IV=0DAE2F85CD81874DCD7368277D0C386D
+PT=2B7A2DF6E0CAC83837AFDC8B2134E6A6
+CT=E3BF66A6784432E6CE61B769C3CFDB35
+
+I=146
+KEY=0D6C96C3BF26BC552A17C0CEBB9DB984
+IV=E3BF66A6784432E6CE61B769C3CFDB35
+PT=8FED19E77B9690EC8F70272364B4EB74
+CT=473925552401311F24EE4F40B5A3ECB5
+
+I=147
+KEY=4A55B3969B278D4A0EF98F8E0E3E5531
+IV=473925552401311F24EE4F40B5A3ECB5
+PT=032D9AF654037E2586B12CF031E4AB4C
+CT=E9E1E4ACF3F4E25CB8093F6B27665DFF
+
+I=148
+KEY=A3B4573A68D36F16B6F0B0E5295808CE
+IV=E9E1E4ACF3F4E25CB8093F6B27665DFF
+PT=E6EF26B3721F6C772D231584DD480441
+CT=2D9F85D63FED609876DF97F0E6B85564
+
+I=149
+KEY=8E2BD2EC573E0F8EC02F2715CFE05DAA
+IV=2D9F85D63FED609876DF97F0E6B85564
+PT=E641EBC4A734C71669D948F1BEEE675A
+CT=3A61F4BED09FD7A7AED71E9FD53D2EE3
+
+I=150
+KEY=B44A265287A1D8296EF8398A1ADD7349
+IV=3A61F4BED09FD7A7AED71E9FD53D2EE3
+PT=36DB43747CD9215857886A0DE2008509
+CT=6BE2AD95F4A642F3FD73D9543B53D479
+
+I=151
+KEY=DFA88BC773079ADA938BE0DE218EA730
+IV=6BE2AD95F4A642F3FD73D9543B53D479
+PT=58A73313B31B8C1EB3C144C9363EE94B
+CT=BF198D336DF857BFBA069634C25CF45B
+
+I=152
+KEY=60B106F41EFFCD65298D76EAE3D2536B
+IV=BF198D336DF857BFBA069634C25CF45B
+PT=E0974E1BBEFE21422ECED27858535F87
+CT=7945132F6F7EED6B61E1CF9C47E2AB2A
+
+I=153
+KEY=19F415DB7181200E486CB976A430F841
+IV=7945132F6F7EED6B61E1CF9C47E2AB2A
+PT=6F36B63A1A8B426282CA4E61B7E37B3A
+CT=AF441F330C8C199E9776D92A92B02216
+
+I=154
+KEY=B6B00AE87D0D3990DF1A605C3680DA57
+IV=AF441F330C8C199E9776D92A92B02216
+PT=99AD2B814D3A4C0E1C27D4251C55C74A
+CT=F34463A538E46E87B0F24EAA36B674A7
+
+I=155
+KEY=45F4694D45E957176FE82EF60036AEF0
+IV=F34463A538E46E87B0F24EAA36B674A7
+PT=6D05C19E42D0561C198A10FA55F4C870
+CT=5D54D3C72D55015D0149FA1591208824
+
+I=156
+KEY=18A0BA8A68BC564A6EA1D4E3911626D4
+IV=5D54D3C72D55015D0149FA1591208824
+PT=7AA7A04DE8CD21F59BA5369CA175CEC3
+CT=D2EBE35C33210B39CD4F443BB577DBD8
+
+I=157
+KEY=CA4B59D65B9D5D73A3EE90D82461FD0C
+IV=D2EBE35C33210B39CD4F443BB577DBD8
+PT=2DA2A48FE13FA4DD5271A02FB7F98AEC
+CT=2F4AD89C0D915DF978160E9E882AD28E
+
+I=158
+KEY=E501814A560C008ADBF89E46AC4B2F82
+IV=2F4AD89C0D915DF978160E9E882AD28E
+PT=82EB831B9FF9DA7D06553A456133766B
+CT=09A04C7CBED3D60ADB6CFDD012DEED17
+
+I=159
+KEY=ECA1CD36E8DFD68000946396BE95C295
+IV=09A04C7CBED3D60ADB6CFDD012DEED17
+PT=8D4FD1CE8CB9745E9E65182D94F8307A
+CT=193C6FAB40C87C7029983EDD52628400
+
+I=160
+KEY=F59DA29DA817AAF0290C5D4BECF74695
+IV=193C6FAB40C87C7029983EDD52628400
+PT=F06A061082E499E65A5DED0D22323F57
+CT=7166BD655D8128E7B09D37B38478B480
+
+I=161
+KEY=84FB1FF8F596821799916AF8688FF215
+IV=7166BD655D8128E7B09D37B38478B480
+PT=DCEC808551EA98534E1A9EDF457125DA
+CT=5DFAAFB695D34A7AF2D39CD2D01FD4BD
+
+I=162
+KEY=D901B04E6045C86D6B42F62AB89026A8
+IV=5DFAAFB695D34A7AF2D39CD2D01FD4BD
+PT=FAE59C96604D062F49C8C93FA7E4D5FC
+CT=85F63AFC88A1CED4E73B849C295692F2
+
+I=163
+KEY=5CF78AB2E8E406B98C7972B691C6B45A
+IV=85F63AFC88A1CED4E73B849C295692F2
+PT=7FE1EA6A7A525A7E0222D6269F7D6A40
+CT=DC60A8554BF9E783D0E92283EC0D00AF
+
+I=164
+KEY=809722E7A31DE13A5C9050357DCBB4F5
+IV=DC60A8554BF9E783D0E92283EC0D00AF
+PT=89C93828CE30D4CD7025D9F2CF864371
+CT=EF10720E8F10FBABC96BB5F4E5287D12
+
+I=165
+KEY=6F8750E92C0D1A9195FBE5C198E3C9E7
+IV=EF10720E8F10FBABC96BB5F4E5287D12
+PT=A8DEA35D4A712ACE8F38A2CA2CB6BCFB
+CT=EED271733DC7B81AD09C86C8F8D69255
+
+I=166
+KEY=8155219A11CAA28B4567630960355BB2
+IV=EED271733DC7B81AD09C86C8F8D69255
+PT=6720AD239EFECF5785B238D4DA39DD6A
+CT=DC47B1FAC154CB0C39ADF4C92F8C2902
+
+I=167
+KEY=5D129060D09E69877CCA97C04FB972B0
+IV=DC47B1FAC154CB0C39ADF4C92F8C2902
+PT=D41DEA3BC44CC552B5ACCFEEFAF225F5
+CT=AD4828834513730BF275C854D35BF09E
+
+I=168
+KEY=F05AB8E3958D1A8C8EBF5F949CE2822E
+IV=AD4828834513730BF275C854D35BF09E
+PT=5059DA9258A7DE12865E1E2173399BC9
+CT=82CA6B085A452CFDFFBDE5C7B738CDAB
+
+I=169
+KEY=7290D3EBCFC836717102BA532BDA4F85
+IV=82CA6B085A452CFDFFBDE5C7B738CDAB
+PT=9625B8A444C3E4D3554A8C6E33E1B810
+CT=4F44C38189E1011970690D0ED4BCB9C7
+
+I=170
+KEY=3DD4106A46293768016BB75DFF66F642
+IV=4F44C38189E1011970690D0ED4BCB9C7
+PT=373FBCA7529A9FA9AF77295FC55B0BEE
+CT=27BE0578B0F898C04133AA4D3C1A5A7C
+
+I=171
+KEY=1A6A1512F6D1AFA840581D10C37CAC3E
+IV=27BE0578B0F898C04133AA4D3C1A5A7C
+PT=37FC0A286DFFD5A76643D1D45C858F64
+CT=B9C70B34F78F3DA7796C32D0918474A5
+
+I=172
+KEY=A3AD1E26015E920F39342FC052F8D89B
+IV=B9C70B34F78F3DA7796C32D0918474A5
+PT=E1EAC69AA2A8F05B8747E2624D00F4BB
+CT=846985C471F10676E63BCD09C32506F3
+
+I=173
+KEY=27C49BE270AF9479DF0FE2C991DDDE68
+IV=846985C471F10676E63BCD09C32506F3
+PT=6EB0046D9C6854C63447296F4F6D3D21
+CT=F754559746C52113C29AF782E96B6105
+
+I=174
+KEY=D090CE75366AB56A1D95154B78B6BF6D
+IV=F754559746C52113C29AF782E96B6105
+PT=F65269422328F40D8A53F4F14DB88583
+CT=AE6B4EABF8DC479A1E3F8C3F30A4A797
+
+I=175
+KEY=7EFB80DECEB6F2F003AA9974481218FA
+IV=AE6B4EABF8DC479A1E3F8C3F30A4A797
+PT=765B38DC041DEC130A3A294D9F89A16D
+CT=87645926B9D85AC4AB023D2104CC3FA2
+
+I=176
+KEY=F99FD9F8776EA834A8A8A4554CDE2758
+IV=87645926B9D85AC4AB023D2104CC3FA2
+PT=8070950120E0FBE07C70B171364AD173
+CT=0125D51139CE00DB848B8A9AD3FEB90B
+
+I=177
+KEY=F8BA0CE94EA0A8EF2C232ECF9F209E53
+IV=0125D51139CE00DB848B8A9AD3FEB90B
+PT=1EF45DD2CD61667469569CFAD445341C
+CT=E1651756A2C0D132C671D74748244E49
+
+I=178
+KEY=19DF1BBFEC6079DDEA52F988D704D01A
+IV=E1651756A2C0D132C671D74748244E49
+PT=26BEF7E8A3D0AC50DC64B8215CCBC44F
+CT=94049FBD554A6CFFE7927D6EC07D6242
+
+I=179
+KEY=8DDB8402B92A15220DC084E61779B258
+IV=94049FBD554A6CFFE7927D6EC07D6242
+PT=803F34FA967583623D0CA4D76FC56787
+CT=974BBE04952D8F0DD70F4353FEB092EB
+
+I=180
+KEY=1A903A062C079A2FDACFC7B5E9C920B3
+IV=974BBE04952D8F0DD70F4353FEB092EB
+PT=023E5D307CE85244144D59A53DB504E7
+CT=2615B9F94F9024EA616648FF15E3B65F
+
+I=181
+KEY=3C8583FF6397BEC5BBA98F4AFC2A96EC
+IV=2615B9F94F9024EA616648FF15E3B65F
+PT=1A84130B09CE3E7AB1F400B9FE295BEB
+CT=39A2A3B6EFB5EBE805CBAD5817EAEEDA
+
+I=182
+KEY=052720498C22552DBE622212EBC07836
+IV=39A2A3B6EFB5EBE805CBAD5817EAEEDA
+PT=B83609055302D99DE46B7153AE3DFCE2
+CT=93F72B839E2AD731B5E894B56ADADCF4
+
+I=183
+KEY=96D00BCA1208821C0B8AB6A7811AA4C2
+IV=93F72B839E2AD731B5E894B56ADADCF4
+PT=85E69EBDE13C05526EA8AE1D24B487F3
+CT=D0ADA333801DFDBFC2420B73CD2B92A5
+
+I=184
+KEY=467DA8F992157FA3C9C8BDD44C313667
+IV=D0ADA333801DFDBFC2420B73CD2B92A5
+PT=F24782E953B9B1BBF3B925659C99415B
+CT=F59A3D0B65E8F16DC73CCD6C27E8C705
+
+I=185
+KEY=B3E795F2F7FD8ECE0EF470B86BD9F162
+IV=F59A3D0B65E8F16DC73CCD6C27E8C705
+PT=73BE517552E054D78583BEA03B84A245
+CT=7904DBE3A103D936EB4B960C180B0651
+
+I=186
+KEY=CAE34E1156FE57F8E5BFE6B473D2F733
+IV=7904DBE3A103D936EB4B960C180B0651
+PT=91998E9582D8357DD5D8B95A9D85912F
+CT=C2DE0D0145A45DEABD6DE1FD62161EB1
+
+I=187
+KEY=083D4310135A0A1258D2074911C4E982
+IV=C2DE0D0145A45DEABD6DE1FD62161EB1
+PT=2A5D4EC49712B9CF1E2D9C6C5EFACC2A
+CT=974264BDC574C738243DDC008EC4C15A
+
+I=188
+KEY=9F7F27ADD62ECD2A7CEFDB499F0028D8
+IV=974264BDC574C738243DDC008EC4C15A
+PT=F74520C3745B9B9F9D19642AA57451FB
+CT=F4EE51C2ECC32F4806F9C8588880525B
+
+I=189
+KEY=6B91766F3AEDE2627A16131117807A83
+IV=F4EE51C2ECC32F4806F9C8588880525B
+PT=4A7D6FC6712F451F58DF0AC2D517189E
+CT=F4978F5F53AA4C336BEE0C62F432B44F
+
+I=190
+KEY=9F06F9306947AE5111F81F73E3B2CECC
+IV=F4978F5F53AA4C336BEE0C62F432B44F
+PT=00DAD17491C973991FEC296972B691BC
+CT=09DAA53C2E394BF83113BE48E5D0CCA2
+
+I=191
+KEY=96DC5C0C477EE5A920EBA13B0662026E
+IV=09DAA53C2E394BF83113BE48E5D0CCA2
+PT=C00943704C1336F01A1D23FD98BE7E8B
+CT=D0DE529664BF241DBED3168DA5BC1B28
+
+I=192
+KEY=46020E9A23C1C1B49E38B7B6A3DE1946
+IV=D0DE529664BF241DBED3168DA5BC1B28
+PT=A07FAD9770CC32C5680F33A2D67044A4
+CT=F6A44922B3744BE96C46742A79A49CBB
+
+I=193
+KEY=B0A647B890B58A5DF27EC39CDA7A85FD
+IV=F6A44922B3744BE96C46742A79A49CBB
+PT=D5450C670BE84169AD1E62C5ECB8365F
+CT=47D229908D4C1EA34E429C34B7D635F5
+
+I=194
+KEY=F7746E281DF994FEBC3C5FA86DACB008
+IV=47D229908D4C1EA34E429C34B7D635F5
+PT=9E90D30BE92104667A16522237D645A6
+CT=6463AC2096842A0958ACF45370C0626F
+
+I=195
+KEY=9317C2088B7DBEF7E490ABFB1D6CD267
+IV=6463AC2096842A0958ACF45370C0626F
+PT=74382A7BF713DE8E8D17AE389E03C3AC
+CT=ECDCEF7613C362D288AC23D38722DC4C
+
+I=196
+KEY=7FCB2D7E98BEDC256C3C88289A4E0E2B
+IV=ECDCEF7613C362D288AC23D38722DC4C
+PT=DB2EC6F41A72F426D9F5DBC65CEC1C5C
+CT=DFE2DA423ACE2DFB053265E9E9B214E2
+
+I=197
+KEY=A029F73CA270F1DE690EEDC173FC1AC9
+IV=DFE2DA423ACE2DFB053265E9E9B214E2
+PT=35998CB9958DC9DE0550FC3EA722D571
+CT=5EBCA79BF99165D9FFE355D9B24ECB5D
+
+I=198
+KEY=FE9550A75BE1940796EDB818C1B2D194
+IV=5EBCA79BF99165D9FFE355D9B24ECB5D
+PT=9BDA7BC96736FE2140911C98E8E02E1C
+CT=782D3EFD5F599E8D3C85D06128677EC2
+
+I=199
+KEY=86B86E5A04B80A8AAA686879E9D5AF56
+IV=782D3EFD5F599E8D3C85D06128677EC2
+PT=8014C1F398E4DCC7F4E5E09E5FAFB080
+CT=E01AE2D961F31BBAE3DA7429627572AB
+
+I=200
+KEY=66A28C83654B113049B21C508BA0DDFD
+IV=E01AE2D961F31BBAE3DA7429627572AB
+PT=97D66D66D1731EEFF14519620616A10B
+CT=BC41ED9D568D6ED36212C92DEEB40A0E
+
+I=201
+KEY=DAE3611E33C67FE32BA0D57D6514D7F3
+IV=BC41ED9D568D6ED36212C92DEEB40A0E
+PT=F7646B60C237ED24F467141980EB4F00
+CT=CB8DF2D164E5B4AB3193D02E71959F63
+
+I=202
+KEY=116E93CF5723CB481A33055314814890
+IV=CB8DF2D164E5B4AB3193D02E71959F63
+PT=4A3A241B26AC7A1C88AA2FB750DF6E5A
+CT=E396FB47A686ABAA350B84C250E5EAE9
+
+I=203
+KEY=F2F86888F1A560E22F3881914464A279
+IV=E396FB47A686ABAA350B84C250E5EAE9
+PT=A71348309D176A072167C4B1B8A295C0
+CT=29AF21F96564EB591E9A60B1BE88DEC7
+
+I=204
+KEY=DB57497194C18BBB31A2E120FAEC7CBE
+IV=29AF21F96564EB591E9A60B1BE88DEC7
+PT=BC528364EF78D6432177FE0CF1CDECD1
+CT=34CD9D96D4455AE0C15B6B970F1EC905
+
+I=205
+KEY=EF9AD4E74084D15BF0F98AB7F5F2B5BB
+IV=34CD9D96D4455AE0C15B6B970F1EC905
+PT=18972F6992299533EE23AA5824C25892
+CT=2E05E3E2079A055310FD9318590A6F41
+
+I=206
+KEY=C19F3705471ED408E00419AFACF8DAFA
+IV=2E05E3E2079A055310FD9318590A6F41
+PT=5441FF0D0A4062D5D0DF29BF2FDA85B4
+CT=47D4EAECE59C733EEFCB7B9D5BE95A98
+
+I=207
+KEY=864BDDE9A282A7360FCF6232F7118062
+IV=47D4EAECE59C733EEFCB7B9D5BE95A98
+PT=ED3E19B5AB5389AA3A58D97F6604F4C0
+CT=00525B7D5BFC0651AEF6770F6281E6DC
+
+I=208
+KEY=86198694F97EA167A139153D959066BE
+IV=00525B7D5BFC0651AEF6770F6281E6DC
+PT=8BD4869C88A9BD3DCFE89B98B93F6EB3
+CT=AFB2215E6DC04E9467F44227FD4BDB98
+
+I=209
+KEY=29ABA7CA94BEEFF3C6CD571A68DBBD26
+IV=AFB2215E6DC04E9467F44227FD4BDB98
+PT=6E7269FC27BDCC42D64CEF41A612F771
+CT=7B769B90279C95E31D8B3D792FA27FA8
+
+I=210
+KEY=52DD3C5AB3227A10DB466A634779C28E
+IV=7B769B90279C95E31D8B3D792FA27FA8
+PT=E00316E79DC10D179002B1BACC146027
+CT=E3870CDE5CF99B7C4C489AF81153002F
+
+I=211
+KEY=B15A3084EFDBE16C970EF09B562AC2A1
+IV=E3870CDE5CF99B7C4C489AF81153002F
+PT=FB2FC78A79C33225E6EAAA06B76FA793
+CT=4DFC91F8971635348EF35141E8C291F7
+
+I=212
+KEY=FCA6A17C78CDD45819FDA1DABEE85356
+IV=4DFC91F8971635348EF35141E8C291F7
+PT=69C8EE14F21832BB077F1A5414851FFE
+CT=DA51BE36F96AA8C80DED9DB2A701D72F
+
+I=213
+KEY=26F71F4A81A77C9014103C6819E98479
+IV=DA51BE36F96AA8C80DED9DB2A701D72F
+PT=766EC1664D2194E0F89B69861A4A8501
+CT=2ACA6359CD935CA2294F9FB5A50F4993
+
+I=214
+KEY=0C3D7C134C3420323D5FA3DDBCE6CDEA
+IV=2ACA6359CD935CA2294F9FB5A50F4993
+PT=1D95E551169BD538836CC349BC6B1772
+CT=315518F0AC6C1DC9939CB802336DA968
+
+I=215
+KEY=3D6864E3E0583DFBAEC31BDF8F8B6482
+IV=315518F0AC6C1DC9939CB802336DA968
+PT=4F6BFE727AECDAB5A32DF8CFFC43D6A9
+CT=34C3ECD89376B4D771CA0669C2C3E26C
+
+I=216
+KEY=09AB883B732E892CDF091DB64D4886EE
+IV=34C3ECD89376B4D771CA0669C2C3E26C
+PT=AA8B1DA2E015D482EE08FA2B4A2B77B6
+CT=A3F4DD9DDC375C90579C274527612C6E
+
+I=217
+KEY=AA5F55A6AF19D5BC88953AF36A29AA80
+IV=A3F4DD9DDC375C90579C274527612C6E
+PT=2EE6982D9E0AA5FCB61F3E66E52A0D6D
+CT=C45C9E4DE76782E2599BD73B132BFE90
+
+I=218
+KEY=6E03CBEB487E575ED10EEDC879025410
+IV=C45C9E4DE76782E2599BD73B132BFE90
+PT=6E58E5B1EDF1BFABAD643D8223F0FA81
+CT=32221DA62DA2B441B5E66A197A5C69F1
+
+I=219
+KEY=5C21D64D65DCE31F64E887D1035E3DE1
+IV=32221DA62DA2B441B5E66A197A5C69F1
+PT=D5A81DF4B6BE17A531478961D78CAB46
+CT=E1FEB5C31B1671F15DC1F7713E5DD7FE
+
+I=220
+KEY=BDDF638E7ECA92EE392970A03D03EA1F
+IV=E1FEB5C31B1671F15DC1F7713E5DD7FE
+PT=D360948141A1D3ECFF5E8D6BDC022685
+CT=FF07F02135FB458D63EE68C4B1463A99
+
+I=221
+KEY=42D893AF4B31D7635AC718648C45D086
+IV=FF07F02135FB458D63EE68C4B1463A99
+PT=E3C1E44333C9307E90EE2FBA6A7708A5
+CT=1AE4E8466B84B59EECF5E6BEB6140DF2
+
+I=222
+KEY=583C7BE920B562FDB632FEDA3A51DD74
+IV=1AE4E8466B84B59EECF5E6BEB6140DF2
+PT=653AA343CE35F72E2ADB5FFCD2DFCBA8
+CT=3CB44BC123DDCD55B812D265CC5E974E
+
+I=223
+KEY=648830280368AFA80E202CBFF60F4A3A
+IV=3CB44BC123DDCD55B812D265CC5E974E
+PT=E96A66BFE5F0E8083A01664A47226672
+CT=BB6C54E118FA895F2AC4CC036166E390
+
+I=224
+KEY=DFE464C91B9226F724E4E0BC9769A9AA
+IV=BB6C54E118FA895F2AC4CC036166E390
+PT=A5B240D8E5731E1BFA7C4FDFB4EED81F
+CT=DA20870677A6214F26FDACBA81B41882
+
+I=225
+KEY=05C4E3CF6C3407B802194C0616DDB128
+IV=DA20870677A6214F26FDACBA81B41882
+PT=92FF6EAB4A6D1AD3941E6A91D8C9105B
+CT=F079AA86FC9FD361DBA0C21CCD4B0F6C
+
+I=226
+KEY=F5BD494990ABD4D9D9B98E1ADB96BE44
+IV=F079AA86FC9FD361DBA0C21CCD4B0F6C
+PT=DFF005175EF746B83CB00AC13337E248
+CT=B6021E0AA1A921C7BCC3FDAB1C3EA44A
+
+I=227
+KEY=43BF57433102F51E657A73B1C7A81A0E
+IV=B6021E0AA1A921C7BCC3FDAB1C3EA44A
+PT=DDDC1AA804AD13813C6AEA540557C097
+CT=41F0E4AB03801DCE585727B7C41F48BD
+
+I=228
+KEY=024FB3E83282E8D03D2D540603B752B3
+IV=41F0E4AB03801DCE585727B7C41F48BD
+PT=4C6421E5A487C9C452958CAB38AC7098
+CT=6EFDD855BAF2D13437C01097ABB633DE
+
+I=229
+KEY=6CB26BBD887039E40AED4491A801616D
+IV=6EFDD855BAF2D13437C01097ABB633DE
+PT=2A11519D5463F2B96A5E0FCE6E4710D7
+CT=5E8243E5C54A109CCC0BF622A299EF68
+
+I=230
+KEY=323028584D3A2978C6E6B2B30A988E05
+IV=5E8243E5C54A109CCC0BF622A299EF68
+PT=252145DACAD23E8B85AB7637B22C42F2
+CT=2C9A476418F01C589ADC0CA10BF4A183
+
+I=231
+KEY=1EAA6F3C55CA35205C3ABE12016C2F86
+IV=2C9A476418F01C589ADC0CA10BF4A183
+PT=A22C36DC7D00645FEFE8683EA4231787
+CT=DA3A4AC19EF6A0F950E26B00834AFE41
+
+I=232
+KEY=C49025FDCB3C95D90CD8D5128226D1C7
+IV=DA3A4AC19EF6A0F950E26B00834AFE41
+PT=B0DC92D3B4878156B768923286F0433F
+CT=10BBC2A8C8F650FD8EED7CC9F5EAD05D
+
+I=233
+KEY=D42BE75503CAC5248235A9DB77CC019A
+IV=10BBC2A8C8F650FD8EED7CC9F5EAD05D
+PT=83A9338157091D4AECAF60E887AE09F7
+CT=757993A70F78B25F02FA0355E04DE27B
+
+I=234
+KEY=A15274F20CB2777B80CFAA8E9781E3E1
+IV=757993A70F78B25F02FA0355E04DE27B
+PT=9D818ACA2C753E7314F51699D3062031
+CT=E2E74C76C09516135876D54AFC940D80
+
+I=235
+KEY=43B53884CC276168D8B97FC46B15EE61
+IV=E2E74C76C09516135876D54AFC940D80
+PT=BDD36F881F8D1FC56780E291D1359EE1
+CT=22F76A2DB98544549DEA21FFCDC2B943
+
+I=236
+KEY=614252A975A2253C45535E3BA6D75722
+IV=22F76A2DB98544549DEA21FFCDC2B943
+PT=4C9C16802A4BB1202D4FAC9E76C57A43
+CT=166B0FF778D72B6102D6ADF990A70A23
+
+I=237
+KEY=77295D5E0D750E5D4785F3C236705D01
+IV=166B0FF778D72B6102D6ADF990A70A23
+PT=0045ECDDAA51EE6FDB226E2D9471F46C
+CT=D7724DC8A1413BC1B9D6F305794426F0
+
+I=238
+KEY=A05B1096AC34359CFE5300C74F347BF1
+IV=D7724DC8A1413BC1B9D6F305794426F0
+PT=25C55C60290DF3D0DC3274CD2AE0ED21
+CT=41F0196DFE0B1F664A107D12A6FF3D79
+
+I=239
+KEY=E1AB09FB523F2AFAB4437DD5E9CB4688
+IV=41F0196DFE0B1F664A107D12A6FF3D79
+PT=9A44454F7A335C89BEFF1D94D3FDB320
+CT=3F37D7ADFB9933FFBAC1F7D07F31046E
+
+I=240
+KEY=DE9CDE56A9A619050E828A0596FA42E6
+IV=3F37D7ADFB9933FFBAC1F7D07F31046E
+PT=03D7F09054233696BEF84AB8D5B77091
+CT=02D226A748153C27A723F02461FFF913
+
+I=241
+KEY=DC4EF8F1E1B32522A9A17A21F705BBF5
+IV=02D226A748153C27A723F02461FFF913
+PT=D5C82A6F048A2AA0E5CF4F1EDADD68B3
+CT=4BD7486C212E7F78228478BBF0A7AD3D
+
+I=242
+KEY=9799B09DC09D5A5A8B25029A07A216C8
+IV=4BD7486C212E7F78228478BBF0A7AD3D
+PT=936431AD9F800606240C33EAF661D3DA
+CT=3EFE00CA0A96AF4425E683512DAC0164
+
+I=243
+KEY=A967B057CA0BF51EAEC381CB2A0E17AC
+IV=3EFE00CA0A96AF4425E683512DAC0164
+PT=280DC27864BED0D548B5B4F9A7FA38DE
+CT=7023640C8D6B02F6C4C7E007C169C592
+
+I=244
+KEY=D944D45B4760F7E86A0461CCEB67D23E
+IV=7023640C8D6B02F6C4C7E007C169C592
+PT=CD0F58962915E5A514E5D6DA8BB868E8
+CT=D08419A75363E9622FAA09DB589915F1
+
+I=245
+KEY=09C0CDFC14031E8A45AE6817B3FEC7CF
+IV=D08419A75363E9622FAA09DB589915F1
+PT=09A6099FDDDBBC15EE79224B01C49DF0
+CT=6CDD2B0279D9DB3C71329C1BB2C24C2F
+
+I=246
+KEY=651DE6FE6DDAC5B6349CF40C013C8BE0
+IV=6CDD2B0279D9DB3C71329C1BB2C24C2F
+PT=B24B11FD8A6FC6B2703FFBEBC85B6C44
+CT=CCB0F6F32BDE2339A1842A7EDC8C99C7
+
+I=247
+KEY=A9AD100D4604E68F9518DE72DDB01227
+IV=CCB0F6F32BDE2339A1842A7EDC8C99C7
+PT=2E471506C55D1762CDB9EAEF29E23C01
+CT=DAD62227A5F328CC33F054EEB346E3D3
+
+I=248
+KEY=737B322AE3F7CE43A6E88A9C6EF6F1F4
+IV=DAD62227A5F328CC33F054EEB346E3D3
+PT=5598344020E32F9B2C509D06F4E7804A
+CT=18DE226F7CAA4EF2712A223C4709C9E2
+
+I=249
+KEY=6BA510459F5D80B1D7C2A8A029FF3816
+IV=18DE226F7CAA4EF2712A223C4709C9E2
+PT=549A87BE74B62BAC3F0FDC2A878F5669
+CT=DB082C8D70948B6BF08D4848E4DB0231
+
+I=250
+KEY=B0AD3CC8EFC90BDA274FE0E8CD243A27
+IV=DB082C8D70948B6BF08D4848E4DB0231
+PT=08946428BF90FBF0951A35D6FB72A48A
+CT=29CBD3E3F2074514E63A7B2A651AB031
+
+I=251
+KEY=9966EF2B1DCE4ECEC1759BC2A83E8A16
+IV=29CBD3E3F2074514E63A7B2A651AB031
+PT=7EBEC38F7787EE1BDD6A648334FA3076
+CT=0037935821278E879BCBB2FBE4ECC23E
+
+I=252
+KEY=99517C733CE9C0495ABE29394CD24828
+IV=0037935821278E879BCBB2FBE4ECC23E
+PT=01D77828928164A830C249D96AC6F8B4
+CT=47501831F9DF42C234E9FE9169075888
+
+I=253
+KEY=DE016442C536828B6E57D7A825D510A0
+IV=47501831F9DF42C234E9FE9169075888
+PT=608349FF8FFC31B072CFA7DF649E15B8
+CT=BC10B1D412BC05404B2E38A1D75DA421
+
+I=254
+KEY=6211D596D78A87CB2579EF09F288B481
+IV=BC10B1D412BC05404B2E38A1D75DA421
+PT=B16325BD78FC0451216FF476D4CAE293
+CT=6ABD8010E9CBAE61E05A9E30C622B501
+
+I=255
+KEY=08AC55863E4129AAC523713934AA0180
+IV=6ABD8010E9CBAE61E05A9E30C622B501
+PT=E613C244F74C61B078C9E59E06E7AD85
+CT=E896B8BD539C30D9A58E5EF6629B279C
+
+I=256
+KEY=E03AED3B6DDD197360AD2FCF5631261C
+IV=E896B8BD539C30D9A58E5EF6629B279C
+PT=6CFF7A909AAB2C0DC61FB8F11B45E661
+CT=30D15AAA05F56FA2D21E9974FB3FF5DA
+
+I=257
+KEY=D0EBB791682876D1B2B3B6BBAD0ED3C6
+IV=30D15AAA05F56FA2D21E9974FB3FF5DA
+PT=6BFAC8E8FB9C3D5AF813B4DF90AD863B
+CT=43B99F3DA3C1BCCE9038118E2968EFA1
+
+I=258
+KEY=935228ACCBE9CA1F228BA73584663C67
+IV=43B99F3DA3C1BCCE9038118E2968EFA1
+PT=064D09E9F5104602E191DC39F18E6A1A
+CT=EBC5796519BE4E05262A10D56FA0F72D
+
+I=259
+KEY=789751C9D257841A04A1B7E0EBC6CB4A
+IV=EBC5796519BE4E05262A10D56FA0F72D
+PT=C2B528D69ED3028A359D4472D98807A7
+CT=5F2B51DD025E775A63DFE5B9FBF54986
+
+I=260
+KEY=27BC0014D009F340677E5259103382CC
+IV=5F2B51DD025E775A63DFE5B9FBF54986
+PT=D5CF62940967AF7225F79E87136751F5
+CT=F56D88E433CEA445C6E4D6298DFB6C27
+
+I=261
+KEY=D2D188F0E3C75705A19A84709DC8EEEB
+IV=F56D88E433CEA445C6E4D6298DFB6C27
+PT=3BE3171202E762846D2CA00FB2CB141A
+CT=4C168A0129F2D48E249777A366D1AEF1
+
+I=262
+KEY=9EC702F1CA35838B850DF3D3FB19401A
+IV=4C168A0129F2D48E249777A366D1AEF1
+PT=5B82A34141C236FAED7E1A78D3C426C4
+CT=E11FEBEF79E425480442D45A8C105B44
+
+I=263
+KEY=7FD8E91EB3D1A6C3814F278977091B5E
+IV=E11FEBEF79E425480442D45A8C105B44
+PT=86CFADD3F1B368B3A6E57148CA343D38
+CT=5F5F3548BDBB2A5337FBF07DF76526DD
+
+I=264
+KEY=2087DC560E6A8C90B6B4D7F4806C3D83
+IV=5F5F3548BDBB2A5337FBF07DF76526DD
+PT=A4474ACA97100C7A357A66119D678798
+CT=013ADA262021F88617773CF478067EC8
+
+I=265
+KEY=21BD06702E4B7416A1C3EB00F86A434B
+IV=013ADA262021F88617773CF478067EC8
+PT=6D66801C39DB803B5DA5A80E30DB0D89
+CT=F46BE70F65FC5641318292AE0C79E5C5
+
+I=266
+KEY=D5D6E17F4BB72257904179AEF413A68E
+IV=F46BE70F65FC5641318292AE0C79E5C5
+PT=C9499B32D8F47313EB351139DB81AB25
+CT=8573A25F86C7784BF7A0153DF812805C
+
+I=267
+KEY=50A54320CD705A1C67E16C930C0126D2
+IV=8573A25F86C7784BF7A0153DF812805C
+PT=4B09D37A4A57B320C34B1D70F74EB36A
+CT=036913128A2B71CE3D05D52D61E48E86
+
+I=268
+KEY=53CC5032475B2BD25AE4B9BE6DE5A854
+IV=036913128A2B71CE3D05D52D61E48E86
+PT=EA3A92794B204C0345765CEE2A04AF27
+CT=5A53E929182859CC28D4EB1CB9579B71
+
+I=269
+KEY=099FB91B5F73721E723052A2D4B23325
+IV=5A53E929182859CC28D4EB1CB9579B71
+PT=2714E38858426C5631BB2BB4FA289985
+CT=DF4BD734DEC60475D47FE40502439AAE
+
+I=270
+KEY=D6D46E2F81B5766BA64FB6A7D6F1A98B
+IV=DF4BD734DEC60475D47FE40502439AAE
+PT=69AC3FD2273926E2DAD3F5BED9F21491
+CT=EBCCD0B121C4009EA7F038F30F5B6B05
+
+I=271
+KEY=3D18BE9EA07176F501BF8E54D9AAC28E
+IV=EBCCD0B121C4009EA7F038F30F5B6B05
+PT=07520CD471E27BAC35387DB47E706784
+CT=299FE603BBA51BD1582CBD42BC9568EA
+
+I=272
+KEY=1487589D1BD46D2459933316653FAA64
+IV=299FE603BBA51BD1582CBD42BC9568EA
+PT=39598B70B8EB190049823472E3596E42
+CT=68DD98FE52B454F85D6F6A6C742223FA
+
+I=273
+KEY=7C5AC063496039DC04FC597A111D899E
+IV=68DD98FE52B454F85D6F6A6C742223FA
+PT=C7E13ABBBA75F527AB1320DD930B24F1
+CT=906B569E44263A4E6F41A52802D3FC59
+
+I=274
+KEY=EC3196FD0D4603926BBDFC5213CE75C7
+IV=906B569E44263A4E6F41A52802D3FC59
+PT=9F5D8E50F06895D5D7E6D1DAA247D45F
+CT=E5ECBDCC55A9D952BE0F93DFA0FE2C31
+
+I=275
+KEY=09DD2B3158EFDAC0D5B26F8DB33059F6
+IV=E5ECBDCC55A9D952BE0F93DFA0FE2C31
+PT=EC3F35C1E6371F106443BD1446D58A0A
+CT=4837A3D703E80BFE50D742E378956F3A
+
+I=276
+KEY=41EA88E65B07D13E85652D6ECBA536CC
+IV=4837A3D703E80BFE50D742E378956F3A
+PT=7998C3B7B5C94540DFC5BF777D700D48
+CT=DF1564E5E47503A779020D27394571E9
+
+I=277
+KEY=9EFFEC03BF72D299FC672049F2E04725
+IV=DF1564E5E47503A779020D27394571E9
+PT=63BEA75A2440C5D123F335F72137B0B6
+CT=5147239C3F6E4A158989BE96C0275D41
+
+I=278
+KEY=CFB8CF9F801C988C75EE9EDF32C71A64
+IV=5147239C3F6E4A158989BE96C0275D41
+PT=09C656A0DFCF893DDBE5E2B3D88E5F1F
+CT=7E4DEE30DED62EE15CD957530B62559D
+
+I=279
+KEY=B1F521AF5ECAB66D2937C98C39A54FF9
+IV=7E4DEE30DED62EE15CD957530B62559D
+PT=71DC22F489DD422CDE09F01DAA427567
+CT=6F62D6359F07F6BDBB4C02BBE50B273C
+
+I=280
+KEY=DE97F79AC1CD40D0927BCB37DCAE68C5
+IV=6F62D6359F07F6BDBB4C02BBE50B273C
+PT=C2A9BC94CAE48DBEB37B4B506AD4336A
+CT=902D9E9F82DE4E66E42B4FEA79AF4077
+
+I=281
+KEY=4EBA690543130EB6765084DDA50128B2
+IV=902D9E9F82DE4E66E42B4FEA79AF4077
+PT=69EE7E15EEC2EA953A32E1714961BA9E
+CT=72CB5DE8AF6CDC60A00A15CEAF249DBD
+
+I=282
+KEY=3C7134EDEC7FD2D6D65A91130A25B50F
+IV=72CB5DE8AF6CDC60A00A15CEAF249DBD
+PT=4C0A3B88FDFAEFEC38858A927C38AE6A
+CT=68C2BFA5DE837B927BD75C6DE6008595
+
+I=283
+KEY=54B38B4832FCA944AD8DCD7EEC25309A
+IV=68C2BFA5DE837B927BD75C6DE6008595
+PT=CE75CCA2D7B0199EB1DA7E33A0E50AB7
+CT=4FFCCBB31FB1FCC0FCB38F0B557BE67A
+
+I=284
+KEY=1B4F40FB2D4D5584513E4275B95ED6E0
+IV=4FFCCBB31FB1FCC0FCB38F0B557BE67A
+PT=E0ECA2ABC1F389B149E746CFB039539E
+CT=249FB11DF8C0ED1F346F6D69B8FD0470
+
+I=285
+KEY=3FD0F1E6D58DB89B65512F1C01A3D290
+IV=249FB11DF8C0ED1F346F6D69B8FD0470
+PT=BFA871CA5EC16C0B353679782BE04394
+CT=8127E6D8EEC1111518065EDC34CD4B4C
+
+I=286
+KEY=BEF7173E3B4CA98E7D5771C0356E99DC
+IV=8127E6D8EEC1111518065EDC34CD4B4C
+PT=1EF816C565B2F56E772C96AD5C92842D
+CT=C8DC75AE1E2DBD005D94E69D6776C498
+
+I=287
+KEY=762B62902561148E20C3975D52185D44
+IV=C8DC75AE1E2DBD005D94E69D6776C498
+PT=9F2B9873F88EBF21A3BB3DCD853C812E
+CT=861D4FF061E85D44173252244F143692
+
+I=288
+KEY=F0362D60448949CA37F1C5791D0C6BD6
+IV=861D4FF061E85D44173252244F143692
+PT=6CDEA8A806516A1A0E1CBB5AA123862A
+CT=16DA4EE5C5044F66EFCC313754FBCD9E
+
+I=289
+KEY=E6EC6385818D06ACD83DF44E49F7A648
+IV=16DA4EE5C5044F66EFCC313754FBCD9E
+PT=5B637BB469073B5E54EC006F47C4D546
+CT=C2C50037BBBEC252B7D5CF10C38BD665
+
+I=290
+KEY=242963B23A33C4FE6FE83B5E8A7C702D
+IV=C2C50037BBBEC252B7D5CF10C38BD665
+PT=38DADBF2BA4A80A6A190D9E2AA245167
+CT=721222A5A67E96246DA1B9C59B67DDD5
+
+I=291
+KEY=563B41179C4D52DA0249829B111BADF8
+IV=721222A5A67E96246DA1B9C59B67DDD5
+PT=CB52378F6E4E7FCB1891D3BB4D086B9F
+CT=D28B8F54E8BDA9A20965984D5DA27FC9
+
+I=292
+KEY=84B0CE4374F0FB780B2C1AD64CB9D231
+IV=D28B8F54E8BDA9A20965984D5DA27FC9
+PT=E66015A1B848EF190F981DEFEDB98C93
+CT=012C5D9B847C9583B0BE03999D24E277
+
+I=293
+KEY=859C93D8F08C6EFBBB92194FD19D3046
+IV=012C5D9B847C9583B0BE03999D24E277
+PT=F5B2BAD53323A52A2B99CC12782CD6F9
+CT=D1EFB7E7A34F75887038FC4827E894C1
+
+I=294
+KEY=5473243F53C31B73CBAAE507F675A487
+IV=D1EFB7E7A34F75887038FC4827E894C1
+PT=11C0C41C3F547B5D7FC94115327AB3D5
+CT=2CF97D8995AA8FDC4C05205D3D8B757F
+
+I=295
+KEY=788A59B6C66994AF87AFC55ACBFED1F8
+IV=2CF97D8995AA8FDC4C05205D3D8B757F
+PT=3F911029D8B69CA1A323A277090B9C07
+CT=44BB04C6253F3ADD454264EA97490475
+
+I=296
+KEY=3C315D70E356AE72C2EDA1B05CB7D58D
+IV=44BB04C6253F3ADD454264EA97490475
+PT=9D7724EFD1AE76904458EF1360953AA4
+CT=5D6F876E4FDD6921B243EB1F6EF50F82
+
+I=297
+KEY=615EDA1EAC8BC75370AE4AAF3242DA0F
+IV=5D6F876E4FDD6921B243EB1F6EF50F82
+PT=44A26554FE355D95706431B344701B03
+CT=5F3226B39DF230163D2C474F04BAD36E
+
+I=298
+KEY=3E6CFCAD3179F7454D820DE036F80961
+IV=5F3226B39DF230163D2C474F04BAD36E
+PT=5D8B62C8CD3B04451A599989F3165530
+CT=A247CF8E1D8F480DA4155DA846A2B64E
+
+I=299
+KEY=9C2B33232CF6BF48E9975048705ABF2F
+IV=A247CF8E1D8F480DA4155DA846A2B64E
+PT=610D3798E62E9338D5987BAC82D48CD7
+CT=2A92B5AAEA43CFBAA62842DEE7F43A19
+
+I=300
+KEY=B6B98689C6B570F24FBF129697AE8536
+IV=2A92B5AAEA43CFBAA62842DEE7F43A19
+PT=F77943AA429BCCC5253156474E719389
+CT=7D475AFF824080E9C95D4E49D4F5090D
+
+I=301
+KEY=CBFEDC7644F5F01B86E25CDF435B8C3B
+IV=7D475AFF824080E9C95D4E49D4F5090D
+PT=5E6269D157164B2C544D3052E9DB8553
+CT=AD4628B05F5A765E557015B4A41505EA
+
+I=302
+KEY=66B8F4C61BAF8645D392496BE74E89D1
+IV=AD4628B05F5A765E557015B4A41505EA
+PT=77126BD6C08A094981FEC9E2DE91B2BF
+CT=59C24F269E3884A4F8E3F9FB05BF448F
+
+I=303
+KEY=3F7ABBE0859702E12B71B090E2F1CD5E
+IV=59C24F269E3884A4F8E3F9FB05BF448F
+PT=7775F90D2189E91B75AB8AD93C0D44F2
+CT=B72873115D4761B8BAEB5B5892B79DF8
+
+I=304
+KEY=8852C8F1D8D06359919AEBC8704650A6
+IV=B72873115D4761B8BAEB5B5892B79DF8
+PT=03D9C45A2A152ADAA53E1D42AB33555B
+CT=FE0C3F22E6B467DC1C628C928D03DB5B
+
+I=305
+KEY=765EF7D33E6404858DF8675AFD458BFD
+IV=FE0C3F22E6B467DC1C628C928D03DB5B
+PT=279791AC4189634A6066BCDCAA2EF9B4
+CT=7F3ABBA943C8E3EF19C3BA2C98C9685F
+
+I=306
+KEY=09644C7A7DACE76A943BDD76658CE3A2
+IV=7F3ABBA943C8E3EF19C3BA2C98C9685F
+PT=E46E5FB6019BA52524A383A18A89583A
+CT=C96D250343B134241221490AB39931DB
+
+I=307
+KEY=C00969793E1DD34E861A947CD615D279
+IV=C96D250343B134241221490AB39931DB
+PT=A3A544B8982C2F9EA0CD0ABC4D6392E2
+CT=951D54AABDF6F5B70E700C4896EB2685
+
+I=308
+KEY=55143DD383EB26F9886A983440FEF4FC
+IV=951D54AABDF6F5B70E700C4896EB2685
+PT=43FEB2051478A02BA1F054C9E82F0209
+CT=1F90165BE29C6C86D09AD07B1C006CA6
+
+I=309
+KEY=4A842B8861774A7F58F0484F5CFE985A
+IV=1F90165BE29C6C86D09AD07B1C006CA6
+PT=558AD95B25BAB5205FB7E529C96E5B59
+CT=40C0A0427C12AB1F72A7ADF96F82D437
+
+I=310
+KEY=0A448BCA1D65E1602A57E5B6337C4C6D
+IV=40C0A0427C12AB1F72A7ADF96F82D437
+PT=BABA13A1244DEFF5E4A2AB8183775773
+CT=FB08FDF3BF4394BA1A92C45B7F5F3060
+
+I=311
+KEY=F14C7639A22675DA30C521ED4C237C0D
+IV=FB08FDF3BF4394BA1A92C45B7F5F3060
+PT=46E036ECCDBE88931E552E45CBBC2BDC
+CT=311AE8C2B7CB633178874BDEEEE0602F
+
+I=312
+KEY=C0569EFB15ED16EB48426A33A2C31C22
+IV=311AE8C2B7CB633178874BDEEEE0602F
+PT=4D5C919959478AD0D9862BA509233102
+CT=1DC85D9A8877C79698C7D1C1610CBAE9
+
+I=313
+KEY=DD9EC3619D9AD17DD085BBF2C3CFA6CB
+IV=1DC85D9A8877C79698C7D1C1610CBAE9
+PT=D423E31E9FD6E4F4373FA7AD31CC6011
+CT=FC55E7BEA15BD539EDACB202F0218D4A
+
+I=314
+KEY=21CB24DF3CC104443D2909F033EE2B81
+IV=FC55E7BEA15BD539EDACB202F0218D4A
+PT=52C2C696A4343C0F280A3BC8F6AA19EA
+CT=FFD9FECD3A4EC194568A96C5A899E8D2
+
+I=315
+KEY=DE12DA12068FC5D06BA39F359B77C353
+IV=FFD9FECD3A4EC194568A96C5A899E8D2
+PT=3B2266FAB514211E8E33AFA566898083
+CT=DC1A545F354365A0002180BACCE0AD25
+
+I=316
+KEY=02088E4D33CCA0706B821F8F57976E76
+IV=DC1A545F354365A0002180BACCE0AD25
+PT=DC20E6BD8B8AC822CF2B505E580E6A80
+CT=51CF4C11F15B8B565B875F769C2FD37F
+
+I=317
+KEY=53C7C25CC2972B26300540F9CBB8BD09
+IV=51CF4C11F15B8B565B875F769C2FD37F
+PT=67B4C3E2AFC3402901549265186303FB
+CT=A118B7E5B10DAB4DDB449877AB1E6897
+
+I=318
+KEY=F2DF75B9739A806BEB41D88E60A6D59E
+IV=A118B7E5B10DAB4DDB449877AB1E6897
+PT=971952EE322CD68462B4CE8B772BBA48
+CT=A2988AAC94D8A7EFB32B34CC07911F3E
+
+I=319
+KEY=5047FF15E7422784586AEC426737CAA0
+IV=A2988AAC94D8A7EFB32B34CC07911F3E
+PT=64C2665506EDDED98EC55D2CCED7762C
+CT=86AEB7B90565D05293A8D9146880C307
+
+I=320
+KEY=D6E948ACE227F7D6CBC235560FB709A7
+IV=86AEB7B90565D05293A8D9146880C307
+PT=A5E7E411209DD2A34AA8CDA3153A69E4
+CT=27746442FAC1DF26B11A55251AAFD865
+
+I=321
+KEY=F19D2CEE18E628F07AD860731518D1C2
+IV=27746442FAC1DF26B11A55251AAFD865
+PT=83A41EF5F664A909BC47939D7858C221
+CT=619A164C3F2119FFCA3832A5EA958E01
+
+I=322
+KEY=90073AA227C7310FB0E052D6FF8D5FC3
+IV=619A164C3F2119FFCA3832A5EA958E01
+PT=1F5A31EBB2C515728DB07EE3160D03CD
+CT=DEE1692D386EF5A8861BE5D8A4630906
+
+I=323
+KEY=4EE6538F1FA9C4A736FBB70E5BEE56C5
+IV=DEE1692D386EF5A8861BE5D8A4630906
+PT=297B343F5EE6221FB6CC40E0C836B387
+CT=B2BA45B0A776A950C32DD5F302201FC3
+
+I=324
+KEY=FC5C163FB8DF6DF7F5D662FD59CE4906
+IV=B2BA45B0A776A950C32DD5F302201FC3
+PT=CC3601DC94B13116DF3012860A522D2D
+CT=6D141746B23B4E1EF20DFE6C14D6ECE4
+
+I=325
+KEY=914801790AE423E907DB9C914D18A5E2
+IV=6D141746B23B4E1EF20DFE6C14D6ECE4
+PT=FE07DA9A6E8B712B1FDFC3C1CC87146D
+CT=0D80E8F5557A88A271133F8929125C72
+
+I=326
+KEY=9CC8E98C5F9EAB4B76C8A318640AF990
+IV=0D80E8F5557A88A271133F8929125C72
+PT=EBDC0192755A685D6275532E93D33890
+CT=B88A629A8E22A78BAF98C9E623F48134
+
+I=327
+KEY=24428B16D1BC0CC0D9506AFE47FE78A4
+IV=B88A629A8E22A78BAF98C9E623F48134
+PT=78AD3067BE2E9536ADB58DA49D7CA6DA
+CT=0A9C2D318240F4FA4FF91CC5D23A371F
+
+I=328
+KEY=2EDEA62753FCF83A96A9763B95C44FBB
+IV=0A9C2D318240F4FA4FF91CC5D23A371F
+PT=04C72A08CCC36B4211AFE98637C4CEFF
+CT=A42618A89B9E618DDD7A983081E086B9
+
+I=329
+KEY=8AF8BE8FC86299B74BD3EE0B1424C902
+IV=A42618A89B9E618DDD7A983081E086B9
+PT=22D4A346027B8E5FEE1C0C0C45CA7DCB
+CT=7CC4479AE05A295723F27545E1A46B7B
+
+I=330
+KEY=F63CF9152838B0E068219B4EF580A279
+IV=7CC4479AE05A295723F27545E1A46B7B
+PT=05090A5C8F3CD0E7F7EA11B33CDF3C1D
+CT=815BCEB2A29EA2A491C8E39B117790EC
+
+I=331
+KEY=776737A78AA61244F9E978D5E4F73295
+IV=815BCEB2A29EA2A491C8E39B117790EC
+PT=7B40F8A4AC0E4C6BD73A59FFC91CA77D
+CT=E4ED412F3ECDD4B7409BEEAEDC2C755F
+
+I=332
+KEY=938A7688B46BC6F3B972967B38DB47CA
+IV=E4ED412F3ECDD4B7409BEEAEDC2C755F
+PT=047E2E4681A97ED20308F1FE4B132F7B
+CT=10153209AED4115329587180D65A0B97
+
+I=333
+KEY=839F44811ABFD7A0902AE7FBEE814C5D
+IV=10153209AED4115329587180D65A0B97
+PT=32671E6C0D28744AB457587BBB6DD21E
+CT=847F781EDF77A870C4EA99CCC1721917
+
+I=334
+KEY=07E03C9FC5C87FD054C07E372FF3554A
+IV=847F781EDF77A870C4EA99CCC1721917
+PT=EC3159B002B95054F00D57049D91E32B
+CT=05CC06529764F6747FCB2B62569C428C
+
+I=335
+KEY=022C3ACD52AC89A42B0B5555796F17C6
+IV=05CC06529764F6747FCB2B62569C428C
+PT=9A930743113957D10EC643D8D8034C73
+CT=D1C7957073C2A44D9483DD11F3FA2B1E
+
+I=336
+KEY=D3EBAFBD216E2DE9BF8888448A953CD8
+IV=D1C7957073C2A44D9483DD11F3FA2B1E
+PT=2E061A5B483D0D834D3019954E54CF80
+CT=0AC3300C59DB7A76A1E16DC5BF167B70
+
+I=337
+KEY=D9289FB178B5579F1E69E581358347A8
+IV=0AC3300C59DB7A76A1E16DC5BF167B70
+PT=2A6E00DF7820913341D26EF611A7BEC1
+CT=5A5A1BE396D3C56DB0690B92A925D8D8
+
+I=338
+KEY=83728452EE6692F2AE00EE139CA69F70
+IV=5A5A1BE396D3C56DB0690B92A925D8D8
+PT=E871C79BA6132F15C80A85F4BC732E77
+CT=829ABA07496E1269437680257308029D
+
+I=339
+KEY=01E83E55A708809BED766E36EFAE9DED
+IV=829ABA07496E1269437680257308029D
+PT=5955643AB76251E6AF97BC2490D09A72
+CT=3FEDBF80B703D067126EF55B02A41175
+
+I=340
+KEY=3E0581D5100B50FCFF189B6DED0A8C98
+IV=3FEDBF80B703D067126EF55B02A41175
+PT=32BCF86ECA6CCE8F9C1C87AD9FDF8238
+CT=B59D6C5FCA91EDBFE75E795638CAD286
+
+I=341
+KEY=8B98ED8ADA9ABD431846E23BD5C05E1E
+IV=B59D6C5FCA91EDBFE75E795638CAD286
+PT=01A08051FC1D98C1BDAE4CA1D41D91E6
+CT=21CB8EF8BBE6C371A26BFF92701C3D1A
+
+I=342
+KEY=AA536372617C7E32BA2D1DA9A5DC6304
+IV=21CB8EF8BBE6C371A26BFF92701C3D1A
+PT=5F5D891DF8D595D3FEDAEF0174B0A1D1
+CT=23D0FB6489113D3D4AA6470210698391
+
+I=343
+KEY=89839816E86D430FF08B5AABB5B5E095
+IV=23D0FB6489113D3D4AA6470210698391
+PT=54FEAB37EFCD36D28E943DD85E803812
+CT=45F0556ED9A8ED0E1C8B0A0BA648E069
+
+I=344
+KEY=CC73CD7831C5AE01EC0050A013FD00FC
+IV=45F0556ED9A8ED0E1C8B0A0BA648E069
+PT=7AF4BC398ACAD37F526BDE12F3ED59ED
+CT=C41E115EE06FFE5DED10480A1BE5B720
+
+I=345
+KEY=086DDC26D1AA505C011018AA0818B7DC
+IV=C41E115EE06FFE5DED10480A1BE5B720
+PT=CF15E4B6DDF60A4EE0CB6CBFA8AD499B
+CT=1098A41E2C97C9D70626E4D1841F5CC1
+
+I=346
+KEY=18F57838FD3D998B0736FC7B8C07EB1D
+IV=1098A41E2C97C9D70626E4D1841F5CC1
+PT=BAD4050A0013AB8BC556F367AB634D94
+CT=D9B58211EB935246A5E04FCD3BE10B54
+
+I=347
+KEY=C140FA2916AECBCDA2D6B3B6B7E6E049
+IV=D9B58211EB935246A5E04FCD3BE10B54
+PT=CEFF0AF7EF4EA7EF3B0E8BF7FB756E77
+CT=50FAE8C770EF7F9D5FE93B090B9D5C66
+
+I=348
+KEY=91BA12EE6641B450FD3F88BFBC7BBC2F
+IV=50FAE8C770EF7F9D5FE93B090B9D5C66
+PT=3B8C412B4156B413AD06CB181B4C5EAA
+CT=E47249D4B5F24FF415B0E669EBF471B1
+
+I=349
+KEY=75C85B3AD3B3FBA4E88F6ED6578FCD9E
+IV=E47249D4B5F24FF415B0E669EBF471B1
+PT=56C612C5C594CAFB7B1CE8131E786DF0
+CT=6AF057199C217EECB886D940F61B91C5
+
+I=350
+KEY=1F380C234F9285485009B796A1945C5B
+IV=6AF057199C217EECB886D940F61B91C5
+PT=5629EF768743AB63D5B79B511C0A6BEF
+CT=A5A76C330984D34310D021A6C2BDE9BC
+
+I=351
+KEY=BA9F60104616560B40D996306329B5E7
+IV=A5A76C330984D34310D021A6C2BDE9BC
+PT=ED8DF427A02692C09D7AAEF2EDAA1249
+CT=8AAEFBA5DE0AAA41D947E3238B279913
+
+I=352
+KEY=30319BB5981CFC4A999E7513E80E2CF4
+IV=8AAEFBA5DE0AAA41D947E3238B279913
+PT=949339605F30310FC557F2CA4815B034
+CT=9408BCB67EA573E7B5359B67918C16B9
+
+I=353
+KEY=A4392703E6B98FAD2CABEE7479823A4D
+IV=9408BCB67EA573E7B5359B67918C16B9
+PT=03607642CBBCCA2134837AC4BB452682
+CT=90660AF3DD0EAC1B61BB60EB49408586
+
+I=354
+KEY=345F2DF03BB723B64D108E9F30C2BFCB
+IV=90660AF3DD0EAC1B61BB60EB49408586
+PT=DE00E32930E14BD4297F9D789D0C25A1
+CT=1C48AC020174C0D87443229C113E2838
+
+I=355
+KEY=281781F23AC3E36E3953AC0321FC97F3
+IV=1C48AC020174C0D87443229C113E2838
+PT=9CA7A04855F8404176D7D30B594B65AC
+CT=7ACCB3FD4F9C7A5BFB83A969EB6D211A
+
+I=356
+KEY=52DB320F755F9935C2D0056ACA91B6E9
+IV=7ACCB3FD4F9C7A5BFB83A969EB6D211A
+PT=DC0B392E998A347ECB789A51A09F1B1D
+CT=22BED79EF2CAFF83BE8CEE5D7001DE21
+
+I=357
+KEY=7065E591879566B67C5CEB37BA9068C8
+IV=22BED79EF2CAFF83BE8CEE5D7001DE21
+PT=07210334590A9314031D98F7DFBB84B9
+CT=44B16879886BC331407D1E7C7F247A04
+
+I=358
+KEY=34D48DE80FFEA5873C21F54BC5B412CC
+IV=44B16879886BC331407D1E7C7F247A04
+PT=27DDF18405E56989E59ED442C8825DD6
+CT=2787AD57159450916A45C72D0E074D53
+
+I=359
+KEY=135320BF1A6AF51656643266CBB35F9F
+IV=2787AD57159450916A45C72D0E074D53
+PT=4F43202A454BB0F3A9440DA558BEE228
+CT=3C1B83C66CEEEB27644BC66ACC3117E8
+
+I=360
+KEY=2F48A37976841E31322FF40C07824877
+IV=3C1B83C66CEEEB27644BC66ACC3117E8
+PT=28ED6A88BDE4ADEFDA5C0F629109A7A3
+CT=B6009481F8C5D3EE37C645CF238238A1
+
+I=361
+KEY=994837F88E41CDDF05E9B1C3240070D6
+IV=B6009481F8C5D3EE37C645CF238238A1
+PT=48DC5A3700CD4A7A9B066DC0E2667544
+CT=C1A20854601D7A81CAC51E9237BDC030
+
+I=362
+KEY=58EA3FACEE5CB75ECF2CAF5113BDB0E6
+IV=C1A20854601D7A81CAC51E9237BDC030
+PT=1F84C71120B50FDF715B60DB69DECBE0
+CT=663EDB4EFD3F6AC2259A43C926ACE66D
+
+I=363
+KEY=3ED4E4E21363DD9CEAB6EC983511568B
+IV=663EDB4EFD3F6AC2259A43C926ACE66D
+PT=D6F9C59367A57E1DBDC2F4627524BC9A
+CT=CA84A10F987212D75B744A7966ABBABA
+
+I=364
+KEY=F45045ED8B11CF4BB1C2A6E153BAEC31
+IV=CA84A10F987212D75B744A7966ABBABA
+PT=1D8BC84060844CE5C40C716F2190C2BB
+CT=ABAEEB339C4D150E894392444E021710
+
+I=365
+KEY=5FFEAEDE175CDA45388134A51DB8FB21
+IV=ABAEEB339C4D150E894392444E021710
+PT=1300843AABCFB110198F0F0102C0A4D5
+CT=DBA9A1F8EE9AB8300D0273F71EAC5D1C
+
+I=366
+KEY=84570F26F9C66275358347520314A63D
+IV=DBA9A1F8EE9AB8300D0273F71EAC5D1C
+PT=1EA11B05D7DA9D770BA9AB619267B7A3
+CT=4921F1CB4A9AA6594C205D8FF0B2DEC9
+
+I=367
+KEY=CD76FEEDB35CC42C79A31ADDF3A678F4
+IV=4921F1CB4A9AA6594C205D8FF0B2DEC9
+PT=9ABA414156563E88A8CCDB3BD226F66C
+CT=4CF623AC6E145E2D61CAD28BFBF1F1E5
+
+I=368
+KEY=8180DD41DD489A011869C85608578911
+IV=4CF623AC6E145E2D61CAD28BFBF1F1E5
+PT=FEF20625FA0C788DB8A20298F6933F6F
+CT=67C491A5CA1A065980BDECE44B7979F1
+
+I=369
+KEY=E6444CE417529C5898D424B2432EF0E0
+IV=67C491A5CA1A065980BDECE44B7979F1
+PT=79C4A475D0E064D72D48AF6357A0E6A0
+CT=529766CDD1223ED05C055108F91E6526
+
+I=370
+KEY=B4D32A29C670A288C4D175BABA3095C6
+IV=529766CDD1223ED05C055108F91E6526
+PT=0758AA9195AE8684B9FEEBEF8E1226AE
+CT=2AEC009219ECD0499DD729352C220E7D
+
+I=371
+KEY=9E3F2ABBDF9C72C159065C8F96129BBB
+IV=2AEC009219ECD0499DD729352C220E7D
+PT=886713433798AB16E87A8AD3A8CD0C87
+CT=0DE2A7554E343B6FFC6D1ECF4A8AF0DD
+
+I=372
+KEY=93DD8DEE91A849AEA56B4240DC986B66
+IV=0DE2A7554E343B6FFC6D1ECF4A8AF0DD
+PT=984E8BA3DFFB4E9A1244D65BEA7DC594
+CT=8111340B4AF2CD82FF15447143069276
+
+I=373
+KEY=12CCB9E5DB5A842C5A7E06319F9EF910
+IV=8111340B4AF2CD82FF15447143069276
+PT=A4F6C8ACF4F1050D11E42FEF1B6C8B68
+CT=BB4693FA1399583EACB21D2675E6D156
+
+I=374
+KEY=A98A2A1FC8C3DC12F6CC1B17EA782846
+IV=BB4693FA1399583EACB21D2675E6D156
+PT=C5DBE1A937D6EA2FDD9A1A2FD25217B9
+CT=BC01B078339637D796F822B7E58D968D
+
+I=375
+KEY=158B9A67FB55EBC5603439A00FF5BECB
+IV=BC01B078339637D796F822B7E58D968D
+PT=DBD0494B0FE3149F8BCB8A70D344E811
+CT=600C1EFBDCA314A6F9714DEE413B9BD2
+
+I=376
+KEY=7587849C27F6FF639945744E4ECE2519
+IV=600C1EFBDCA314A6F9714DEE413B9BD2
+PT=FCA88DCB484317D7F886E7437BC9E669
+CT=2E3788A647105DD0A286E2EFFD469C99
+
+I=377
+KEY=5BB00C3A60E6A2B33BC396A1B388B980
+IV=2E3788A647105DD0A286E2EFFD469C99
+PT=65AF28E41B3DA5ACE3B2CC9A25EAD28C
+CT=5411E48B57058A52C8560423BCFFBCD2
+
+I=378
+KEY=0FA1E8B137E328E1F39592820F770552
+IV=5411E48B57058A52C8560423BCFFBCD2
+PT=6DD82A9F1CF0A5134A76899B04BE37D5
+CT=C3F69C8ED682BF252D5119D1695126E1
+
+I=379
+KEY=CC57743FE16197C4DEC48B53662623B3
+IV=C3F69C8ED682BF252D5119D1695126E1
+PT=DE729AB3803144FD958D8597396BC8ED
+CT=0941B78975FD2945B4AA81E8C58E3CB2
+
+I=380
+KEY=C516C3B6949CBE816A6E0ABBA3A81F01
+IV=0941B78975FD2945B4AA81E8C58E3CB2
+PT=D8404E7A17254EB40683A8919A9563B4
+CT=BF647E0346C013E138A2F0B06E7BB142
+
+I=381
+KEY=7A72BDB5D25CAD6052CCFA0BCDD3AE43
+IV=BF647E0346C013E138A2F0B06E7BB142
+PT=214089EC2996CE9FA2BBFEFBCAC03509
+CT=AFDA67B9451FF758CC87BBD93C7D4BE4
+
+I=382
+KEY=D5A8DA0C97435A389E4B41D2F1AEE5A7
+IV=AFDA67B9451FF758CC87BBD93C7D4BE4
+PT=9406E9D4FB4592A609BBDB23CE5F9D7F
+CT=B18202E4CA510695540371A8B6523616
+
+I=383
+KEY=642AD8E85D125CADCA48307A47FCD3B1
+IV=B18202E4CA510695540371A8B6523616
+PT=FEE45BE0503B4093747AFCEA9881D30D
+CT=64E149A4A1840F93D675B041ED81D45A
+
+I=384
+KEY=00CB914CFC96533E1C3D803BAA7D07EB
+IV=64E149A4A1840F93D675B041ED81D45A
+PT=880368D5609350167C7826DA30DCFF59
+CT=65A363E9837DFBBDA2688E6F4FBE6C35
+
+I=385
+KEY=6568F2A57FEBA883BE550E54E5C36BDE
+IV=65A363E9837DFBBDA2688E6F4FBE6C35
+PT=29C5940D09A8723B441FC469C909813A
+CT=2A47FDF5BF600891DF4D9E8AA34748BA
+
+I=386
+KEY=4F2F0F50C08BA012611890DE46842364
+IV=2A47FDF5BF600891DF4D9E8AA34748BA
+PT=20AF0FF7BAC0F468C12BD2816A8B1620
+CT=68A637E4B94EC150C84A6EBB005BB79B
+
+I=387
+KEY=278938B479C56142A952FE6546DF94FF
+IV=68A637E4B94EC150C84A6EBB005BB79B
+PT=42906D013A3F0A426B01B489ECA6CAD7
+CT=A090CA02FCD40F01CA0D1A699E30C164
+
+I=388
+KEY=8719F2B685116E43635FE40CD8EF559B
+IV=A090CA02FCD40F01CA0D1A699E30C164
+PT=05A02D4D7D90BCA74ECE791CD865CB88
+CT=F70109F0EBBA56959B3013565E2BDFFC
+
+I=389
+KEY=7018FB466EAB38D6F86FF75A86C48A67
+IV=F70109F0EBBA56959B3013565E2BDFFC
+PT=C373AB7B8F770212F9D5CEF40099086C
+CT=67221CC1F104809B8A5D35431963812D
+
+I=390
+KEY=173AE7879FAFB84D7232C2199FA70B4A
+IV=67221CC1F104809B8A5D35431963812D
+PT=8C59B2A7FD50EC66ABACC0531BE33237
+CT=E06166175F68155DB86E268F3C5524AE
+
+I=391
+KEY=F75B8190C0C7AD10CA5CE496A3F22FE4
+IV=E06166175F68155DB86E268F3C5524AE
+PT=D39790AED2970355A6337AAD2CA4D501
+CT=85E89883242A3B68F4AAF922646EB385
+
+I=392
+KEY=72B31913E4ED96783EF61DB4C79C9C61
+IV=85E89883242A3B68F4AAF922646EB385
+PT=87D4160C7C97476D0884A22B5983AA65
+CT=038C79FDFAA0B4F4AD9DC336F46CACDF
+
+I=393
+KEY=713F60EE1E4D228C936BDE8233F030BE
+IV=038C79FDFAA0B4F4AD9DC336F46CACDF
+PT=3B59088B5ADC77E4B3FC31897C6389B5
+CT=F6C92ECB3332E5E93C9DE29F27F94BB3
+
+I=394
+KEY=87F64E252D7FC765AFF63C1D14097B0D
+IV=F6C92ECB3332E5E93C9DE29F27F94BB3
+PT=68BA9BEBB40B3E35D2E577A2831CF9DB
+CT=7B72342488233DAD5ACF0A8D54EA9E8B
+
+I=395
+KEY=FC847A01A55CFAC8F539369040E3E586
+IV=7B72342488233DAD5ACF0A8D54EA9E8B
+PT=7816251219B8C7F009ADD7A1898D02CF
+CT=45CBA66AD6045917C3E8257D3ECBECDB
+
+I=396
+KEY=B94FDC6B7358A3DF36D113ED7E28095D
+IV=45CBA66AD6045917C3E8257D3ECBECDB
+PT=F542FEAB12E2EA9AE761E58108784E37
+CT=82E289465F5838036B9880C33AEBCB83
+
+I=397
+KEY=3BAD552D2C009BDC5D49932E44C3C2DE
+IV=82E289465F5838036B9880C33AEBCB83
+PT=3B8208791DAE56383CC2BCB44097C9D3
+CT=F02F2B89DE46D01F46AD95C82AF0C20E
+
+I=398
+KEY=CB827EA4F2464BC31BE406E66E3300D0
+IV=F02F2B89DE46D01F46AD95C82AF0C20E
+PT=3F2C0F7A0AEAB04F318C661ABCFED153
+CT=8D4FAF6332578524301ACA22AD86965B
+
+I=399
+KEY=46CDD1C7C011CEE72BFECCC4C3B5968B
+IV=8D4FAF6332578524301ACA22AD86965B
+PT=A27200B51D69AAC22F1C567F8BCEABFA
+CT=2F844CBF78EBA70DA7A49601388F1AB6
+
+==========
+
+KEYSIZE=192
+
+I=0
+KEY=000000000000000000000000000000000000000000000000
+IV=00000000000000000000000000000000
+PT=00000000000000000000000000000000
+CT=7BD966D53AD8C1BB85D2ADFAE87BB104
+
+I=1
+KEY=506339DAE3B35BEB7BD966D53AD8C1BB85D2ADFAE87BB104
+IV=7BD966D53AD8C1BB85D2ADFAE87BB104
+PT=0555C410F44C7AA4506339DAE3B35BEB
+CT=869C061BE9CFEAB5D285B0724A9A8970
+
+I=2
+KEY=74D3414C2374367BFD4560CED3172B0E57571D88A2E13874
+IV=869C061BE9CFEAB5D285B0724A9A8970
+PT=C6FB25A188CF7F3F24B07896C0C76D90
+CT=9E58A52B3840DBE16E8063A18220FEE4
+
+I=3
+KEY=DDE2DF4EEC312FA3631DC5E5EB57F0EF39D77E2920C1C690
+IV=9E58A52B3840DBE16E8063A18220FEE4
+PT=84E3D4168A8469A6A9319E02CF4519D8
+CT=730A256C202B9D57F3C0D73AD4B6CBED
+
+I=4
+KEY=9D973AECAF19E9951017E089CB7C6DB8CA17A913F4770D7D
+IV=730A256C202B9D57F3C0D73AD4B6CBED
+PT=E000CE26CD3185B44075E5A24328C636
+CT=E79EF11C5C1FD1AB75280BCFFCFE89D4
+
+I=5
+KEY=7A52007B2C40C9F4F78911959763BC13BF3FA2DC088984A9
+IV=E79EF11C5C1FD1AB75280BCFFCFE89D4
+PT=19D79403BB238816E7C53A9783592061
+CT=65744444724F1052D0B8674EDC8083B5
+
+I=6
+KEY=40D50426A8D09F3292FD55D1E52CAC416F87C592D409071C
+IV=65744444724F1052D0B8674EDC8083B5
+PT=FDFA33685E2B5BBC3A87045D849056C6
+CT=23C6377D3D076491AD93E2B6112289C7
+
+I=7
+KEY=6FD062412FE1AE4EB13B62ACD82BC8D0C2142724C52B8EDB
+IV=23C6377D3D076491AD93E2B6112289C7
+PT=5056DDDEF15831502F0566678731317C
+CT=F13A83088536BF30E5E9018BE57D7D89
+
+I=8
+KEY=EB4DB5F469D0EE9B4001E1A45D1D77E027FD26AF2056F352
+IV=F13A83088536BF30E5E9018BE57D7D89
+PT=0EE535A4A524668F849DD7B5463140D5
+CT=3F496CB19B21C37159528BF345473E6D
+
+I=9
+KEY=AA6E5744B909D9A87F488D15C63CB4917EAFAD5C6511CD3F
+IV=3F496CB19B21C37159528BF345473E6D
+PT=3A11F90EB51C81ED4123E2B0D0D93733
+CT=CF79C1EDEE17A68DC7E673006AEC90D9
+
+I=10
+KEY=64AB0C0C9471B77FB0314CF8282B121CB949DE5C0FFD5DE6
+IV=CF79C1EDEE17A68DC7E673006AEC90D9
+PT=85187E7F91280A5BCEC55B482D786ED7
+CT=92D1757BEBCE6E0406407819AF82353F
+
+I=11
+KEY=9E5720C1DC2E285C22E03983C3E57C18BF09A645A07F68D9
+IV=92D1757BEBCE6E0406407819AF82353F
+PT=45147511BC08EC76FAFC2CCD485F9F23
+CT=8C0228F57523D746E67D27A8E6C426D9
+
+I=12
+KEY=EBBB8245582E4367AEE21176B6C6AB5E597481ED46BB4E00
+IV=8C0228F57523D746E67D27A8E6C426D9
+PT=73B9EEAC644CBB8875ECA28484006B3B
+CT=D0025BF1FC35DD9BDA20F42DF775AF71
+
+I=13
+KEY=5F938EE9CC63C9E87EE04A874AF376C5835475C0B1CEE171
+IV=D0025BF1FC35DD9BDA20F42DF775AF71
+PT=DE2507F01BC8B212B4280CAC944D8A8F
+CT=3FDDD3E04B2CBE79BB07D82182CD3787
+
+I=14
+KEY=B94E2EC5F6E86EDC413D996701DFC8BC3853ADE13303D6F6
+IV=3FDDD3E04B2CBE79BB07D82182CD3787
+PT=90CE32BCC16C20F7E6DDA02C3A8BA734
+CT=F7B491E4C40B60BE8ACF16D68E3ED60F
+
+I=15
+KEY=DE41ABD8C44F5DF6B6890883C5D4A802B29CBB37BD3D00F9
+IV=F7B491E4C40B60BE8ACF16D68E3ED60F
+PT=B7ACCA62BB9974BC670F851D32A7332A
+CT=7ED4055D367CB31A4CF1CC17132E00B5
+
+I=16
+KEY=E2A57C71F23BC4DEC85D0DDEF3A81B18FE6D7720AE13004C
+IV=7ED4055D367CB31A4CF1CC17132E00B5
+PT=1CA59C2384797B803CE4D7A936749928
+CT=8D50A87F14D466323929BB52FA60FA42
+
+I=17
+KEY=2FA1A78B8BCC301C450DA5A1E77C7D2AC744CC725473FA0E
+IV=8D50A87F14D466323929BB52FA60FA42
+PT=0A623319F2A051ACCD04DBFA79F7F4C2
+CT=7C02D378606FC33DFCEF8AA2A000383E
+
+I=18
+KEY=A949CE493892DF58390F76D98713BE173BAB46D0F473C230
+IV=7C02D378606FC33DFCEF8AA2A000383E
+PT=EE8F5FF6A7FF813386E869C2B35EEF44
+CT=CAE55B9CCBB5A68EBF0D2AB55E079FD4
+
+I=19
+KEY=E159445FE4201A6CF3EA2D454CA6189984A66C65AA745DE4
+IV=CAE55B9CCBB5A68EBF0D2AB55E079FD4
+PT=9699456986535C4648108A16DCB2C534
+CT=9056685FBFECC7A6143DB5AC314DAC88
+
+I=20
+KEY=EE4F7BF96BF1163E63BC451AF34ADF3F909BD9C99B39F16C
+IV=9056685FBFECC7A6143DB5AC314DAC88
+PT=16D6C34C3B57AC0A0F163FA68FD10C52
+CT=4D6A5542F0680CE37E88119141F321F5
+
+I=21
+KEY=27F8CEE0120E8A0F2ED610580322D3DCEE13C858DACAD099
+IV=4D6A5542F0680CE37E88119141F321F5
+PT=337839926E36EC77C9B7B51979FF9C31
+CT=78E16D6027F0D190E78825C2F52E5364
+
+I=22
+KEY=0AF4D3D8EB9FF18A56377D3824D2024C099BED9A2FE483FD
+IV=78E16D6027F0D190E78825C2F52E5364
+PT=8F96B66F934467C72D0C1D38F9917B85
+CT=82A81B33F80A105DD7D9CC6DDFECDB96
+
+I=23
+KEY=AD2AFC821170D967D49F660BDCD81211DE4221F7F008586B
+IV=82A81B33F80A105DD7D9CC6DDFECDB96
+PT=E2CB8E6E329C6660A7DE2F5AFAEF28ED
+CT=0BCD68A063BA3540B3E04C885DF45BD0
+
+I=24
+KEY=5B50EE72BD6CE837DF520EABBF6227516DA26D7FADFC03BB
+IV=0BCD68A063BA3540B3E04C885DF45BD0
+PT=31A14C64CD8BCC8FF67A12F0AC1C3150
+CT=DB27EA5834BF572EA50E03E0773C1010
+
+I=25
+KEY=BF4D8A58F54D47620475E4F38BDD707FC8AC6E9FDAC013AB
+IV=DB27EA5834BF572EA50E03E0773C1010
+PT=26755B5C0BE60998E41D642A4821AF55
+CT=655A896243B5E86B2F74299A317A2E4C
+
+I=26
+KEY=8DC190D88B17EAB9612F6D91C8689814E7D84705EBBA3DE7
+IV=655A896243B5E86B2F74299A317A2E4C
+PT=C6920ADCED82F661328C1A807E5AADDB
+CT=9F45472FDBB732C745AD228810392EA2
+
+I=27
+KEY=B44071C6F14CDA97FE6A2ABE13DFAAD3A275658DFB831345
+IV=9F45472FDBB732C745AD228810392EA2
+PT=2178DFA9784E563E3981E11E7A5B302E
+CT=9F985FBF08235845E396BFCE54BCE7C8
+
+I=28
+KEY=A3C12E42B53D829E61F275011BFCF29641E3DA43AF3FF48D
+IV=9F985FBF08235845E396BFCE54BCE7C8
+PT=44977E2274DA25AE17815F8444715809
+CT=033EAF4FAC934D123012279B1663C80B
+
+I=29
+KEY=8FD2B79E25E39C4A62CCDA4EB76FBF8471F1FDD8B95C3C86
+IV=033EAF4FAC934D123012279B1663C80B
+PT=425088D4626CD7972C1399DC90DE1ED4
+CT=A962CB4707B0048BB81F4225EFC85E48
+
+I=30
+KEY=3D68793EF46B8125CBAE1109B0DFBB0FC9EEBFFD569462CE
+IV=A962CB4707B0048BB81F4225EFC85E48
+PT=EF21ED587C272175B2BACEA0D1881D6F
+CT=6F3A0D63A22C003F7F65B09098F667DB
+
+I=31
+KEY=6A4FB651BE9D0BAFA4941C6A12F3BB30B68B0F6DCE620515
+IV=6F3A0D63A22C003F7F65B09098F667DB
+PT=16054E60B460B2D15727CF6F4AF68A8A
+CT=8BB46230FF03665765F2E5AAEA14104F
+
+I=32
+KEY=3F5991D63C15A1822F207E5AEDF0DD67D379EAC72476155A
+IV=8BB46230FF03665765F2E5AAEA14104F
+PT=82D0B12FEA88917F551627878288AA2D
+CT=8E1A664131FAB09E786E111C3C20A7BB
+
+I=33
+KEY=456F69D38929ED82A13A181BDC0A6DF9AB17FBDB1856B2E1
+IV=8E1A664131FAB09E786E111C3C20A7BB
+PT=1384D3B7CAEB528A7A36F805B53C4C00
+CT=92D99BF1D71026D2BF78E32421E34E52
+
+I=34
+KEY=658891F63379484C33E383EA0B1A4B2B146F18FF39B5FCB3
+IV=92D99BF1D71026D2BF78E32421E34E52
+PT=9F60C3117269E88920E7F825BA50A5CE
+CT=7DB6782C68EC5FC75A2A75E4EA7B4071
+
+I=35
+KEY=9193E2EACE8423F64E55FBC663F614EC4E456D1BD3CEBCC2
+IV=7DB6782C68EC5FC75A2A75E4EA7B4071
+PT=232ECA0370EBD920F41B731CFDFD6BBA
+CT=D76A1E73E977533E6D7C74277DAFEB48
+
+I=36
+KEY=F4C34FE273D0FCB5993FE5B58A8147D22339193CAE61578A
+IV=D76A1E73E977533E6D7C74277DAFEB48
+PT=5BCD8C6C4D14321F6550AD08BD54DF43
+CT=4A69E9081DDD43A6061700C7DA8F5E73
+
+I=37
+KEY=DC82C155896C5D5CD3560CBD975C0474252E19FB74EE09F9
+IV=4A69E9081DDD43A6061700C7DA8F5E73
+PT=C914BB961EA890D828418EB7FABCA1E9
+CT=91EE5BE28C27F055258BC3E1F37E2DEC
+
+I=38
+KEY=08F1655EA3656F1C42B8575F1B7BF42100A5DA1A87902415
+IV=91EE5BE28C27F055258BC3E1F37E2DEC
+PT=11804F73D788115CD473A40B2A093240
+CT=86B9BE5AFD2A8A49E2651C314CAE0918
+
+I=39
+KEY=59D7EFD92140A147C401E905E6517E68E2C0C62BCB3E2D0D
+IV=86B9BE5AFD2A8A49E2651C314CAE0918
+PT=6E2A1E436926174E51268A878225CE5B
+CT=C642F5ED78DB76738A89296B1C4A0932
+
+I=40
+KEY=F6E75E7867D0FB4A02431CE89E8A081B6849EF40D774243F
+IV=C642F5ED78DB76738A89296B1C4A0932
+PT=15896B8B864CF068AF30B1A146905A0D
+CT=24288AE027547E499EBADE9260C8F037
+
+I=41
+KEY=9A048C2BC98E15B2266B9608B9DE7652F6F331D2B7BCD408
+IV=24288AE027547E499EBADE9260C8F037
+PT=FF9A330C205DC3006CE3D253AE5EEEF8
+CT=BD9B3D670D24EDDA1EAD1DB06C8A83C7
+
+I=42
+KEY=97E8C017644E9FED9BF0AB6FB4FA9B88E85E2C62DB3657CF
+IV=BD9B3D670D24EDDA1EAD1DB06C8A83C7
+PT=C9A3916C34A7CCD90DEC4C3CADC08A5F
+CT=1FCCBC65C44E4680E1593EE0EEFEA9A9
+
+I=43
+KEY=3A2862113BD3312D843C170A70B4DD080907128235C8FE66
+IV=1FCCBC65C44E4680E1593EE0EEFEA9A9
+PT=EAF9C4A80EE93585ADC0A2065F9DAEC0
+CT=2C0004064936696B10D039D9795BABC7
+
+I=44
+KEY=33FAE356C0C96F17A83C130C3982B46319D72B5B4C9355A1
+IV=2C0004064936696B10D039D9795BABC7
+PT=4181525880CA468909D28147FB1A5E3A
+CT=79F193EB9A9A48464FF007D73E9B4106
+
+I=45
+KEY=2136A7940C9B9FAFD1CD80E7A318FC2556272C8C720814A7
+IV=79F193EB9A9A48464FF007D73E9B4106
+PT=2899D75DFB84950E12CC44C2CC52F0B8
+CT=DA12307CE9A6BA0FCE5A76AE1747E619
+
+I=46
+KEY=0C839679750274320BDFB09B4ABE462A987D5A22654FF2BE
+IV=DA12307CE9A6BA0FCE5A76AE1747E619
+PT=2C71B8623CA5BF292DB531ED7999EB9D
+CT=A59997FA19B58BC71CB05E7140386C94
+
+I=47
+KEY=4D3CDB92797645C1AE462761530BCDED84CD045325779E2A
+IV=A59997FA19B58BC71CB05E7140386C94
+PT=63F4FC202A1B921241BF4DEB0C7431F3
+CT=49E65D7422398035DD1E4EBAD37C699D
+
+I=48
+KEY=38082D7CC27EBABBE7A07A1571324DD859D34AE9F60BF7B7
+IV=49E65D7422398035DD1E4EBAD37C699D
+PT=7F0E2FD5D4B5A0CB7534F6EEBB08FF7A
+CT=64DF24483FC73174FB6482A6E2B895E0
+
+I=49
+KEY=1557398CFBFF31F8837F5E5D4EF57CACA2B7C84F14B36257
+IV=64DF24483FC73174FB6482A6E2B895E0
+PT=0F525FCF2A1E3D612D5F14F039818B43
+CT=028880CC8AA1B92CB807F1102663E658
+
+I=50
+KEY=229C31F1D34A529581F7DE91C454C5801AB0395F32D0840F
+IV=028880CC8AA1B92CB807F1102663E658
+PT=219604B99FF2BE7B37CB087D28B5636D
+CT=FAC8B66D1BA7849392CC235D0276110E
+
+I=51
+KEY=C75DE76D40D536277B3F68FCDFF34113887C1A0230A69501
+IV=FAC8B66D1BA7849392CC235D0276110E
+PT=3319C80C038E565FE5C1D69C939F64B2
+CT=79770F286419EEFD855868EC4ADF3775
+
+I=52
+KEY=5F0B08B451490B27024867D4BBEAAFEE0D2472EE7A79A274
+IV=79770F286419EEFD855868EC4ADF3775
+PT=E173A8580816CAFA9856EFD9119C3D00
+CT=FC0AA487B09DF657DB58DBF83E13E137
+
+I=53
+KEY=E86E8BFBF1D65541FE42C3530B7759B9D67CA916446A4343
+IV=FC0AA487B09DF657DB58DBF83E13E137
+PT=01274C45F202C22CB765834FA09F5E66
+CT=9691EA44FC67CA29E50E7FF7DBC4D0CA
+
+I=54
+KEY=7849550CA6CCD87268D32917F71093903372D6E19FAE9389
+IV=9691EA44FC67CA29E50E7FF7DBC4D0CA
+PT=026BD493499B7BA99027DEF7571A8D33
+CT=5206F7CF45A59FD6444CCBB6B034CF45
+
+I=55
+KEY=52D81D6104DBF6DF3AD5DED8B2B50C46773E1D572F9A5CCC
+IV=5206F7CF45A59FD6444CCBB6B034CF45
+PT=33CA15B3D921E7752A91486DA2172EAD
+CT=F4A41D18E3EF9DE46917BADB1B5EC613
+
+I=56
+KEY=36FB680165ABD632CE71C3C0515A91A21E29A78C34C49ADF
+IV=F4A41D18E3EF9DE46917BADB1B5EC613
+PT=65F3084285AA869464237560617020ED
+CT=6C4154D3245D2546979118A36120A911
+
+I=57
+KEY=6E7548B98AA0640AA23097137507B4E489B8BF2F55E433CE
+IV=6C4154D3245D2546979118A36120A911
+PT=6CF540F502D90886588E20B8EF0BB238
+CT=2A52376A7E494ADEDD53A416F73FE9C0
+
+I=58
+KEY=A0D840A0E3CC1EA58862A0790B4EFE3A54EB1B39A2DBDA0E
+IV=2A52376A7E494ADEDD53A416F73FE9C0
+PT=708AE2375F305572CEAD0819696C7AAF
+CT=7A0EF052184147EA279839380B3DBB32
+
+I=59
+KEY=153CF68E4A1C1FCEF26C502B130FB9D073732201A9E6613C
+IV=7A0EF052184147EA279839380B3DBB32
+PT=A8267215107D3DD0B5E4B62EA9D0016B
+CT=F193B80D57571F94A4F5373149163AA1
+
+I=60
+KEY=E0B0657A66C37D8703FFE8264458A644D7861530E0F05B9D
+IV=F193B80D57571F94A4F5373149163AA1
+PT=EE4B04302CB02990F58C93F42CDF6249
+CT=A28E99815C930AC05ADA4524A7E5968C
+
+I=61
+KEY=94760F8A93926E4DA17171A718CBAC848D5C50144715CD11
+IV=A28E99815C930AC05ADA4524A7E5968C
+PT=34D122B717CBA59174C66AF0F55113CA
+CT=6F9342E7915613450E823EC9A781DAA3
+
+I=62
+KEY=0B352460A1579376CEE23340899DBFC183DE6EDDE09417B2
+IV=6F9342E7915613450E823EC9A781DAA3
+PT=D8689ED21F3EA8E29F432BEA32C5FD3B
+CT=584BB944532A830F7F8DCDBE42E7DBFC
+
+I=63
+KEY=999A5CEB73DFCC1796A98A04DAB73CCEFC53A363A273CC4E
+IV=584BB944532A830F7F8DCDBE42E7DBFC
+PT=4E87F73D46D0C0AF92AF788BD2885F61
+CT=4AC372A4D3273C71F69D50168A9235A1
+
+I=64
+KEY=42C59FFD5AA69C11DC6AF8A0099000BF0ACEF37528E1F9EF
+IV=4AC372A4D3273C71F69D50168A9235A1
+PT=324DC9C2D34E95F9DB5FC31629795006
+CT=60E53CC2D5E4900D48A0C5F7EE3BC810
+
+I=65
+KEY=843EBDEF0CEEBA5BBC8FC462DC7490B2426E3682C6DA31FF
+IV=60E53CC2D5E4900D48A0C5F7EE3BC810
+PT=8B94F018A7115B3AC6FB22125648264A
+CT=4BD7DF7DFD03A24809B751F59FACF417
+
+I=66
+KEY=98E40853FA954FF5F7581B1F217732FA4BD967775976C5E8
+IV=4BD7DF7DFD03A24809B751F59FACF417
+PT=109C734AC21ED2631CDAB5BCF67BF5AE
+CT=B7A3CF7E58A413C5065E9CFD23C750F9
+
+I=67
+KEY=5419462C5329544A40FBD46179D3213F4D87FB8A7AB19511
+IV=B7A3CF7E58A413C5065E9CFD23C750F9
+PT=8CA507ACCDB3A793CCFD4E7FA9BC1BBF
+CT=6285C3D0FD2645192C5DD046D73414CE
+
+I=68
+KEY=B58628819840885D227E17B184F5642661DA2BCCAD8581DF
+IV=6285C3D0FD2645192C5DD046D73414CE
+PT=7DE48BAD03BB9F53E19F6EADCB69DC17
+CT=583FBCEB09646CEC19D00620E5455FD5
+
+I=69
+KEY=73F7F00EF22ED1B07A41AB5A8D9108CA780A2DEC48C0DE0A
+IV=583FBCEB09646CEC19D00620E5455FD5
+PT=126D3F2A0BC1B168C671D88F6A6E59ED
+CT=886A5273055AF7AE37EFB726DC90FD9E
+
+I=70
+KEY=69735F80F0B876DAF22BF92988CBFF644FE59ACA94502394
+IV=886A5273055AF7AE37EFB726DC90FD9E
+PT=0B4D3F58D83D866A1A84AF8E0296A76A
+CT=FD068F02BB6C2611EF78CD963EF2F78F
+
+I=71
+KEY=92E5FF32D46494880F2D762B33A7D975A09D575CAAA2D41B
+IV=FD068F02BB6C2611EF78CD963EF2F78F
+PT=705667CBCC87BF3DFB96A0B224DCE252
+CT=34713FD3FA07F0B3F94EC0FB17BB465F
+
+I=72
+KEY=A0DF9DCB873A1ADC3B5C49F8C9A029C659D397A7BD199244
+IV=34713FD3FA07F0B3F94EC0FB17BB465F
+PT=4BF66F55275D6CB3323A62F9535E8E54
+CT=82C8A179661207B7FE178A266C607074
+
+I=73
+KEY=2D1604ADAA49C3FBB994E881AFB22E71A7C41D81D179E230
+IV=82C8A179661207B7FE178A266C607074
+PT=167203BBB933707A8DC999662D73D927
+CT=DCDBCC8D11C632CB220C6E95B399A1CC
+
+I=74
+KEY=7D2C4B0C0D0B001A654F240CBE741CBA85C8731462E043FC
+IV=DCDBCC8D11C632CB220C6E95B399A1CC
+PT=668F998350BDA831503A4FA1A742C3E1
+CT=8827EBFCB24470266D5C0BA05D5974A4
+
+I=75
+KEY=BE3A4CF21186C2C7ED68CFF00C306C9CE89478B43FB93758
+IV=8827EBFCB24470266D5C0BA05D5974A4
+PT=B8D1D48F3C41094EC31607FE1C8DC2DD
+CT=61E59DECE1AEFFDEB9B216828953D70F
+
+I=76
+KEY=D0CE372842DC32508C8D521CED9E934251266E36B6EAE057
+IV=61E59DECE1AEFFDEB9B216828953D70F
+PT=49A4495257D08AA56EF47BDA535AF097
+CT=ECD04FFB385CCC1D13C312A5C31810DE
+
+I=77
+KEY=E7274C14C4163169605D1DE7D5C25F5F42E57C9375F2F089
+IV=ECD04FFB385CCC1D13C312A5C31810DE
+PT=3EED6F60FD9050A737E97B3C86CA0339
+CT=D9C90455AFBF5465F89752FB6F60BDFF
+
+I=78
+KEY=71E35A00CAFB898BB99419B27A7D0B3ABA722E681A924D76
+IV=D9C90455AFBF5465F89752FB6F60BDFF
+PT=5CE6E7F07945191396C416140EEDB8E2
+CT=F6E795B326CFD6CCC0E230E4FE770878
+
+I=79
+KEY=79DFA388989B29204F738C015CB2DDF67A901E8CE4E5450E
+IV=F6E795B326CFD6CCC0E230E4FE770878
+PT=314A5784B7909F89083CF9885260A0AB
+CT=6B3A00F05F79F25E4E9EDA81034A9B7B
+
+I=80
+KEY=75F6D5983AE6D7AC24498CF103CB2FA8340EC40DE7AFDE75
+IV=6B3A00F05F79F25E4E9EDA81034A9B7B
+PT=DEC42B1A6184FDF80C297610A27DFE8C
+CT=6A19BEA8826427E309BD55BCBBE246B4
+
+I=81
+KEY=E47EEE65549BF1634E50325981AF084B3DB391B15C4D98C1
+IV=6A19BEA8826427E309BD55BCBBE246B4
+PT=63C46CFF49FF13B291883BFD6E7D26CF
+CT=738C0B0E580C0B1ED488DDE8502CB754
+
+I=82
+KEY=E6DBE45547556F403DDC3957D9A30355E93B4C590C612F95
+IV=738C0B0E580C0B1ED488DDE8502CB754
+PT=E951F5C902BD351502A50A3013CE9E23
+CT=389E33F3DAB3FAB7B2ACB853C0150B8D
+
+I=83
+KEY=EBA5A1BDF9FC558905420AA40310F9E25B97F40ACC742418
+IV=389E33F3DAB3FAB7B2ACB853C0150B8D
+PT=54EFC45B4036B60D0D7E45E8BEA93AC9
+CT=EACAE8A4B5CCBDB28ED2162670DBD4B1
+
+I=84
+KEY=B570945030615F75EF88E200B6DC4450D545E22CBCAFF0A9
+IV=EACAE8A4B5CCBDB28ED2162670DBD4B1
+PT=7F3BA6FE23AE45665ED535EDC99D0AFC
+CT=535FEA61623ECD22FA1A95BF95320252
+
+I=85
+KEY=F332D3DE8556F82EBCD70861D4E289722F5F7793299DF2FB
+IV=535FEA61623ECD22FA1A95BF95320252
+PT=8FEB6943B22437D34642478EB537A75B
+CT=CD23D928E1D3221E4D3C51670C071276
+
+I=86
+KEY=1402D325D7EBA90871F4D1493531AB6C626326F4259AE08D
+IV=CD23D928E1D3221E4D3C51670C071276
+PT=8B01EE4509B58B49E73000FB52BD5126
+CT=56DC7F1BE2CC26A369B3BCA71BF8FAB8
+
+I=87
+KEY=389C95DC5BF411B62728AE52D7FD8DCF0BD09A533E621A35
+IV=56DC7F1BE2CC26A369B3BCA71BF8FAB8
+PT=9BFE561402B07B4C2C9E46F98C1FB8BE
+CT=A059CFB443009F0ACD8E5051BD16C837
+
+I=88
+KEY=89180FBFF0A12019877161E694FD12C5C65ECA028374D202
+IV=A059CFB443009F0ACD8E5051BD16C837
+PT=C8D55810C7A22E30B1849A63AB5531AF
+CT=62CEB7D9A6D23B40CFD75990D1040BA4
+
+I=89
+KEY=08BE01CF1E620DBEE5BFD63F322F2985098993925270D9A6
+IV=62CEB7D9A6D23B40CFD75990D1040BA4
+PT=F888764A970B03BC81A60E70EEC32DA7
+CT=F6D89003ABBF003AF013EB221AF17F99
+
+I=90
+KEY=5EB9AC53FC544ADE1367463C999029BFF99A78B04881A63F
+IV=F6D89003ABBF003AF013EB221AF17F99
+PT=26A25CFC1E699D8B5607AD9CE2364760
+CT=74C9E920DC16396E89774B82E7803EF5
+
+I=91
+KEY=D8FAD6E8CDC96CEF67AEAF1C458610D170ED3332AF0198CA
+IV=74C9E920DC16396E89774B82E7803EF5
+PT=76AFDD045A30FAA486437ABB319D2631
+CT=A5B997689B88AAC0611C2963C8C1B7CE
+
+I=92
+KEY=7E774E64A5F209B2C2173874DE0EBA1111F11A5167C02F04
+IV=A5B997689B88AAC0611C2963C8C1B7CE
+PT=ABF525144D3415DEA68D988C683B655D
+CT=7A2F39D97547C3CD336577E41C0483ED
+
+I=93
+KEY=0406C21AE6E015E0B83801ADAB4979DC22946DB57BC4ACE9
+IV=7A2F39D97547C3CD336577E41C0483ED
+PT=E0C2466426630D1B7A718C7E43121C52
+CT=67899F7D0890E90383C05A7984604241
+
+I=94
+KEY=D9249A4AFDF40BEADFB19ED0A3D990DFA15437CCFFA4EEA8
+IV=67899F7D0890E90383C05A7984604241
+PT=07E55341FCD016D7DD2258501B141E0A
+CT=7B1CBCD270B09E9A1D15714D8366D174
+
+I=95
+KEY=B2242464CD4D2448A4AD2202D3690E45BC4146817CC23FDC
+IV=7B1CBCD270B09E9A1D15714D8366D174
+PT=25C6E62F44ABFF406B00BE2E30B92FA2
+CT=C86E27E5CA4461CE656D893A16477966
+
+I=96
+KEY=602CDF824C043C836CC305E7192D6F8BD92CCFBB6A8546BA
+IV=C86E27E5CA4461CE656D893A16477966
+PT=3F9D262E375F057BD208FBE6814918CB
+CT=8129054CF746CB79112942AE35142E4D
+
+I=97
+KEY=73F82C9EE4B4D0E8EDEA00ABEE6BA4F2C8058D155F9168F7
+IV=8129054CF746CB79112942AE35142E4D
+PT=7BC798EAC4C17B2D13D4F31CA8B0EC6B
+CT=36F21910B1677AF19586E55E360FB8DD
+
+I=98
+KEY=E5FC538A60CC29A3DB1819BB5F0CDE035D83684B699ED02A
+IV=36F21910B1677AF19586E55E360FB8DD
+PT=D3E39037253E5BAA96047F148478F94B
+CT=BA7CE80E0853D264368EE61D8E71EEBE
+
+I=99
+KEY=D9381EF81441B6C16164F1B5575F0C676B0D8E56E7EF3E94
+IV=BA7CE80E0853D264368EE61D8E71EEBE
+PT=DE4FFDFADB81FABB3CC44D72748D9F62
+CT=971AD82D1F46F1087B37103B4BE5DD8C
+
+I=100
+KEY=A0BF8B4740D929C9F67E29984819FD6F103A9E6DAC0AE318
+IV=971AD82D1F46F1087B37103B4BE5DD8C
+PT=FE6355B5D860522B798795BF54989F08
+CT=D17268155EE586F352BB031929441700
+
+I=101
+KEY=477A0AB591FFEC5C270C418D16FC7B9C42819D74854EF418
+IV=D17268155EE586F352BB031929441700
+PT=166A50EEE05F4A39E7C581F2D126C595
+CT=2CD84FB5B587BE8B04638A9EDBA17AE2
+
+I=102
+KEY=50005B4C4B11BFB20BD40E38A37BC51746E217EA5EEF8EFA
+IV=2CD84FB5B587BE8B04638A9EDBA17AE2
+PT=1296DC2C1741EB2A177A51F9DAEE53EE
+CT=8C2A5A31951FB2D9E8D35CD3C007B8B3
+
+I=103
+KEY=E1E88DDBA5D849DF87FE5409366477CEAE314B399EE83649
+IV=8C2A5A31951FB2D9E8D35CD3C007B8B3
+PT=57C5E1A070E3C2AEB1E8D697EEC9F66D
+CT=AA9E935BA264C9FD0C07072AF8499CD7
+
+I=104
+KEY=D465F0FB195068CF2D60C7529400BE33A2364C1366A1AA9E
+IV=AA9E935BA264C9FD0C07072AF8499CD7
+PT=77D0522670E00BD7358D7D20BC882110
+CT=A22DF6CE12C75FB99F5159A1E3E4249F
+
+I=105
+KEY=4DEB1B5E6398E4AD8F4D319C86C7E18A3D6715B285458E01
+IV=A22DF6CE12C75FB99F5159A1E3E4249F
+PT=D6F96D22896A2574998EEBA57AC88C62
+CT=B356102A9158C569469E61093146B9F0
+
+I=106
+KEY=D73E5CA946860BDD3C1B21B6179F24E37BF974BBB40337F1
+IV=B356102A9158C569469E61093146B9F0
+PT=2E72F61FC21F57A09AD547F7251EEF70
+CT=AB2BABFB88D3C3ACE4CBA81E0E250AD3
+
+I=107
+KEY=6B592CE635873DE197308A4D9F4CE74F9F32DCA5BA263D22
+IV=AB2BABFB88D3C3ACE4CBA81E0E250AD3
+PT=39B02C01155705C9BC67704F7301363C
+CT=8A4AC90E9095479F3C02DE7B08C01F1C
+
+I=108
+KEY=1026EE98CAC684081D7A43430FD9A0D0A33002DEB2E6223E
+IV=8A4AC90E9095479F3C02DE7B08C01F1C
+PT=14F49DBECEE88DBB7B7FC27EFF41B9E9
+CT=62E4E3C43938D014D90C4A1D8CD09639
+
+I=109
+KEY=20972278E7C0FFC17F9EA08736E170C47A3C48C33E36B407
+IV=62E4E3C43938D014D90C4A1D8CD09639
+PT=56EFB0EA336A674930B1CCE02D067BC9
+CT=5E8EB865BFC1999D57A67280E37CA129
+
+I=110
+KEY=2BEE1A1965A7F17C211018E28920E9592D9A3A43DD4A152E
+IV=5E8EB865BFC1999D57A67280E37CA129
+PT=9CF6F073F2F0C7CB0B79386182670EBD
+CT=D3B98A4562FAB47ED3D09C55E75EE51B
+
+I=111
+KEY=EB85E491647FD6ACF2A992A7EBDA5D27FE4AA6163A14F035
+IV=D3B98A4562FAB47ED3D09C55E75EE51B
+PT=61964EF472752F21C06BFE8801D827D0
+CT=CF3D65AEEDD747416AF436A3B909828F
+
+I=112
+KEY=E94E6286941EC36D3D94F709060D1A6694BE90B5831D72BA
+IV=CF3D65AEEDD747416AF436A3B909828F
+PT=6C0B536EA1099A4202CB8617F06115C1
+CT=5DB0625B34C01C47490B5200E8A205FC
+
+I=113
+KEY=F5D756E568CA6BA06024955232CD0621DDB5C2B56BBF7746
+IV=5DB0625B34C01C47490B5200E8A205FC
+PT=08D5CD9945D190AB1C993463FCD4A8CD
+CT=771B5C66F79E262FAAC6F92F128669CB
+
+I=114
+KEY=462C74E6E222DE77173FC934C553200E77733B9A79391E8D
+IV=771B5C66F79E262FAAC6F92F128669CB
+PT=5628EC55D7AB7634B3FB22038AE8B5D7
+CT=31C436E7CA7343A93AA0B74A38CCDAC0
+
+I=115
+KEY=5062F2489F4C68FE26FBFFD30F2063A74DD38CD041F5C44D
+IV=31C436E7CA7343A93AA0B74A38CCDAC0
+PT=F279C45DBD75C458164E86AE7D6EB689
+CT=845320B41FD6F1D4DBB36D19D8A4A268
+
+I=116
+KEY=5A27EC509FED17B6A2A8DF6710F692739660E1C999516625
+IV=845320B41FD6F1D4DBB36D19D8A4A268
+PT=7C0CB5E4FFE703260A451E1800A17F48
+CT=D8F9FB52BE1B342D6FBBB8A7FCDEFD89
+
+I=117
+KEY=E925EC8E99BF11E97A512435AEEDA65EF9DB596E658F9BAC
+IV=D8F9FB52BE1B342D6FBBB8A7FCDEFD89
+PT=187F3648643AF8E6B30200DE0652065F
+CT=240647A32D765031C79D8893CC19EBA9
+
+I=118
+KEY=5574034BCE64FADD5E576396839BF66F3E46D1FDA9967005
+IV=240647A32D765031C79D8893CC19EBA9
+PT=AF808097E0C68C8FBC51EFC557DBEB34
+CT=2A3805A7D773F9C00635779752C9CCE7
+
+I=119
+KEY=D842A9983BBDAA5E746F663154E80FAF3873A66AFB5FBCE2
+IV=2A3805A7D773F9C00635779752C9CCE7
+PT=D44486CCC61C68588D36AAD3F5D95083
+CT=2219F0C7A805BEC4A4931F84CBFFC598
+
+I=120
+KEY=CD622302BD70E2CD567696F6FCEDB16B9CE0B9EE30A0797A
+IV=2219F0C7A805BEC4A4931F84CBFFC598
+PT=67DA1BC4F2BC2F3315208A9A86CD4893
+CT=8B1F4353CF6969888BBD6654AB65C2A8
+
+I=121
+KEY=80A1D0CA7667F291DD69D5A53384D8E3175DDFBA9BC5BBD2
+IV=8B1F4353CF6969888BBD6654AB65C2A8
+PT=D114FDA8E61BEAC44DC3F3C8CB17105C
+CT=B6F0C0F016A1FA033C37D1128D9B2EF3
+
+I=122
+KEY=2C9B755C3B8B44416B991555252522E02B6A0EA8165E9521
+IV=B6F0C0F016A1FA033C37D1128D9B2EF3
+PT=738DBCE3EE7E70EAAC3AA5964DECB6D0
+CT=14FB0A67CB0729CA25152581D8C3FEEF
+
+I=123
+KEY=5D05BDFBF482E4D37F621F32EE220B2A0E7F2B29CE9D6BCE
+IV=14FB0A67CB0729CA25152581D8C3FEEF
+PT=D3186497981F294B719EC8A7CF09A092
+CT=14C988C52C7ED50EBD10219F1F58C213
+
+I=124
+KEY=9E044D195FA8557C6BAB97F7C25CDE24B36F0AB6D1C5A9DD
+IV=14C988C52C7ED50EBD10219F1F58C213
+PT=C062585284FDE540C301F0E2AB2AB1AF
+CT=1FE7E153E69F95F102624ACEB9067FA1
+
+I=125
+KEY=2B116B6F1FD581C6744C76A424C34BD5B10D407868C3D67C
+IV=1FE7E153E69F95F102624ACEB9067FA1
+PT=F18294D40CAA674DB5152676407DD4BA
+CT=AB43B2C61C9F23B96EFE293C6730A98F
+
+I=126
+KEY=EAF1AFBDD2CEDB9ADF0FC462385C686CDFF369440FF37FF3
+IV=AB43B2C61C9F23B96EFE293C6730A98F
+PT=7D465730C5422413C1E0C4D2CD1B5A5C
+CT=B1413F447CA81C678287EE2366544547
+
+I=127
+KEY=4FA6C7DA7A84D4CB6E4EFB2644F4740B5D74876769A73AB4
+IV=B1413F447CA81C678287EE2366544547
+PT=C7BFA1BFA26828F7A5576867A84A0F51
+CT=7AE90F988557F3A41BBDB4B69C5FF56A
+
+I=128
+KEY=C9B0E3C7CEF4003014A7F4BEC1A387AF46C933D1F5F8CFDE
+IV=7AE90F988557F3A41BBDB4B69C5FF56A
+PT=5173C32806105AD18616241DB470D4FB
+CT=F2EF675645D284F042FAEBE87AE3ECAE
+
+I=129
+KEY=DB855274F6CC030BE64893E88471035F0433D8398F1B2370
+IV=F2EF675645D284F042FAEBE87AE3ECAE
+PT=6DF6B7F917B2F8431235B1B33838033B
+CT=30D4F068BC2FDEC79CF81A4FA641A495
+
+I=130
+KEY=F37DBF11472A4F87D69C6380385EDD9898CBC276295A87E5
+IV=30D4F068BC2FDEC79CF81A4FA641A495
+PT=F4C98D268B7D175728F8ED65B1E64C8C
+CT=0CEB234560B935E5B08C7EA2AA4A962D
+
+I=131
+KEY=1A2F5A0827B2F861DA7740C558E7E87D2847BCD4831011C8
+IV=0CEB234560B935E5B08C7EA2AA4A962D
+PT=9873E312B815DC81E952E5196098B7E6
+CT=7BED84EFC02836F6D165AD27DEEF2B21
+
+I=132
+KEY=9C815F2A4EC42D02A19AC42A98CFDE8BF92211F35DFF3AE9
+IV=7BED84EFC02836F6D165AD27DEEF2B21
+PT=D8765DE55131DC4186AE05226976D563
+CT=C36FEDCB97DA734243A20C49D5942DD1
+
+I=133
+KEY=9A12CC40F3C185AA62F529E10F15ADC9BA801DBA886B1738
+IV=C36FEDCB97DA734243A20C49D5942DD1
+PT=18B252CEB124BD110693936ABD05A8A8
+CT=94C9A6BDB97522FACEE2E869C3C48FB0
+
+I=134
+KEY=F08C23DDC110ED40F63C8F5CB6608F337462F5D34BAF9888
+IV=94C9A6BDB97522FACEE2E869C3C48FB0
+PT=154FF810E3F0CE586A9EEF9D32D168EA
+CT=AFC8D15F80F19F942FCA22DA0DF79937
+
+I=135
+KEY=B1224FF7293C5DC559F45E03369110A75BA8D709465801BF
+IV=AFC8D15F80F19F942FCA22DA0DF79937
+PT=259A6B069CA3273C41AE6C2AE82CB085
+CT=5AADC1716B2ED4FC7CA9825A32EA2FB1
+
+I=136
+KEY=D29A829813CC5B4103599F725DBFC45B2701555374B22E0E
+IV=5AADC1716B2ED4FC7CA9825A32EA2FB1
+PT=CB78C574D9B1B9EF63B8CD6F3AF00684
+CT=EACB8D3001640F340DFB459CD8D162BD
+
+I=137
+KEY=1049116DD39F7B30E99212425CDBCB6F2AFA10CFAC634CB3
+IV=EACB8D3001640F340DFB459CD8D162BD
+PT=DF461D135DE19FA2C2D393F5C0532071
+CT=9115EB33739C04AAE22765621A8852C5
+
+I=138
+KEY=A129CBBF89658D977887F9712F47CFC5C8DD75ADB6EB1E76
+IV=9115EB33739C04AAE22765621A8852C5
+PT=E32AF908A190B95FB160DAD25AFAF6A7
+CT=B171D8AC24C6873B54F42D5DAC51ED34
+
+I=139
+KEY=EE7226D88DFA48DFC9F621DD0B8148FE9C2958F01ABAF342
+IV=B171D8AC24C6873B54F42D5DAC51ED34
+PT=0A669BB00E2123B54F5BED67049FC548
+CT=CFFC81B70593A36D022248D1CBE7FC58
+
+I=140
+KEY=C907918503B2C1C0060AA06A0E12EB939E0B1021D15D0F1A
+IV=CFFC81B70593A36D022248D1CBE7FC58
+PT=E9B1E6FA006D4CEE2775B75D8E48891F
+CT=0B3B02FC8A8D677B8077D7FDF9EB0396
+
+I=141
+KEY=E468A0560DB602C10D31A296849F8CE81E7CC7DC28B60C8C
+IV=0B3B02FC8A8D677B8077D7FDF9EB0396
+PT=AA3626C69662AE442D6F31D30E04C301
+CT=2C78C31D4B2EBAEF54CB6D04C4375196
+
+I=142
+KEY=EB8BCD80D3E35CCB2149618BCFB136074AB7AAD8EC815D1A
+IV=2C78C31D4B2EBAEF54CB6D04C4375196
+PT=5017BD9EB52514180FE36DD6DE555E0A
+CT=67D2DD54A0881186DFA6A608C036CE61
+
+I=143
+KEY=7065D92686BA37E9469BBCDF6F39278195110CD02CB7937B
+IV=67D2DD54A0881186DFA6A608C036CE61
+PT=6CBC1C2DAA3A7F7B9BEE14A655596B22
+CT=62163C88A40E7CFF7522A3DC32F30BCF
+
+I=144
+KEY=E0B4AE9D6C9A5A92248D8057CB375B7EE033AF0C1E4498B4
+IV=62163C88A40E7CFF7522A3DC32F30BCF
+PT=0F6C44EE5E2587A790D177BBEA206D7B
+CT=B84A631DE451F109C48785DE3D4099C2
+
+I=145
+KEY=DDCDB4F73AA0C8789CC7E34A2F66AA7724B42AD223040176
+IV=B84A631DE451F109C48785DE3D4099C2
+PT=EE1EA5C5340C2F263D791A6A563A92EA
+CT=D438E983DB81DA9341CE1AC45F4E7E52
+
+I=146
+KEY=813604E941CBDF6448FF0AC9F4E770E4657A30167C4A7F24
+IV=D438E983DB81DA9341CE1AC45F4E7E52
+PT=08E1F94874432DBD5CFBB01E7B6B171C
+CT=0E1C069CB75D4EDF4243D1E6D7175425
+
+I=147
+KEY=D64EB9DE5A3B546B46E30C5543BA3E3B2739E1F0AB5D2B01
+IV=0E1C069CB75D4EDF4243D1E6D7175425
+PT=CFCDC1C0EFE678FB5778BD371BF08B0F
+CT=CBC0ED542E26A1943926EF7897A79E97
+
+I=148
+KEY=D1659785D1D551948D23E1016D9C9FAF1E1F0E883CFAB596
+IV=CBC0ED542E26A1943926EF7897A79E97
+PT=1FEA178A348CAE8B072B2E5B8BEE05FF
+CT=C743A7B60EB7C24867DA82AFF15ED18A
+
+I=149
+KEY=05786C3E1FBE51864A6046B7632B5DE779C58C27CDA4641C
+IV=C743A7B60EB7C24867DA82AFF15ED18A
+PT=3A4EF6696CD26875D41DFBBBCE6B0012
+CT=EA23014227CF7B563AEFF86DB947FAC4
+
+I=150
+KEY=CE1E5D5BF32BF0CAA04347F544E426B1432A744A74E39ED8
+IV=EA23014227CF7B563AEFF86DB947FAC4
+PT=DFDF9B4032986E90CB663165EC95A14C
+CT=EAF762B60A106C03B76742E69CEE385A
+
+I=151
+KEY=F8EAC01B3F7E925A4AB425434EF44AB2F44D36ACE80DA682
+IV=EAF762B60A106C03B76742E69CEE385A
+PT=2BDC6EAB1D86311D36F49D40CC556290
+CT=E6CC0491C3509240ED848AE304CC3385
+
+I=152
+KEY=BF5AE8B244244B4BAC7821D28DA4D8F219C9BC4FECC19507
+IV=E6CC0491C3509240ED848AE304CC3385
+PT=81D4E28E02717AB347B028A97B5AD911
+CT=11EE9D22AC798AB5FEF6C6188845F425
+
+I=153
+KEY=5C6538235111334FBD96BCF021DD5247E73F7A5764846122
+IV=11EE9D22AC798AB5FEF6C6188845F425
+PT=DDE402413BB09DFBE33FD09115357804
+CT=3F054911089500FD2CD0645DBFE2A8D3
+
+I=154
+KEY=FAC914FA6B6CA1AB8293F5E1294852BACBEF1E0ADB66C9F1
+IV=3F054911089500FD2CD0645DBFE2A8D3
+PT=345343E023AC39FFA6AC2CD93A7D92E4
+CT=7538E78DE8FC09D203010C61422E6B5A
+
+I=155
+KEY=1E62F54271EA4374F7AB126CC1B45B68C8EE126B9948A2AB
+IV=7538E78DE8FC09D203010C61422E6B5A
+PT=0EC4357C476EB76AE4ABE1B81A86E2DF
+CT=3A4D0093A2B7FF807BAA6A815538507E
+
+I=156
+KEY=5AD3B884BE5653BBCDE612FF6303A4E8B34478EACC70F2D5
+IV=3A4D0093A2B7FF807BAA6A815538507E
+PT=F59FD86893B7DF7244B14DC6CFBC10CF
+CT=2C2FD7DF94FDDC2CA1C05EF5878583FF
+
+I=157
+KEY=B9039E1678902ECCE1C9C520F7FE78C41284261F4BF5712A
+IV=2C2FD7DF94FDDC2CA1C05EF5878583FF
+PT=4600E6CCD65B575AE3D02692C6C67D77
+CT=59C9FA2E4A2227C3E5B831899A3CCBFD
+
+I=158
+KEY=394A8245256D72B8B8003F0EBDDC5F07F73C1796D1C9BAD7
+IV=59C9FA2E4A2227C3E5B831899A3CCBFD
+PT=3030D8E24F7BEA0580491C535DFD5C74
+CT=DEAFC4A07A3FB5D5AA09FF6A2515AB4A
+
+I=159
+KEY=2496931DFCFF2E7166AFFBAEC7E3EAD25D35E8FCF4DC119D
+IV=DEAFC4A07A3FB5D5AA09FF6A2515AB4A
+PT=63CD1CC241B267791DDC1158D9925CC9
+CT=B1B0AED275FCE241B5726E943B37C130
+
+I=160
+KEY=53CBA419E5CED1C8D71F557CB21F0893E8478668CFEBD0AD
+IV=B1B0AED275FCE241B5726E943B37C130
+PT=85F4E06A05C8704A775D37041931FFB9
+CT=B0DFD3EF3AF538791E69AF59CAA7B8CC
+
+I=161
+KEY=DFB0E5440EB582F667C0869388EA30EAF62E2931054C6861
+IV=B0DFD3EF3AF538791E69AF59CAA7B8CC
+PT=B7BDA6C504797C8B8C7B415DEB7B533E
+CT=220F810B0D5A9ED8794932D0BF6150D6
+
+I=162
+KEY=B26A70894070BC9B45CF079885B0AE328F671BE1BA2D38B7
+IV=220F810B0D5A9ED8794932D0BF6150D6
+PT=0113567BFAC19EB86DDA95CD4EC53E6D
+CT=56C77682CA1A041B312061F3FB9A1A59
+
+I=163
+KEY=36EDA74B7133D5871308711A4FAAAA29BE477A1241B722EE
+IV=56C77682CA1A041B312061F3FB9A1A59
+PT=4D39AD87258968FA8487D7C23143691C
+CT=4F18208E63B2D84CC7A0707617DD7B63
+
+I=164
+KEY=F7589312CE997AFE5C1051942C18726579E70A64566A598D
+IV=4F18208E63B2D84CC7A0707617DD7B63
+PT=1B82F5C849E0F965C1B53459BFAAAF79
+CT=85CE0310DEFB36474B38C4347D7EEE8B
+
+I=165
+KEY=F770FC7B1E183E31D9DE5284F2E3442232DFCE502B14B706
+IV=85CE0310DEFB36474B38C4347D7EEE8B
+PT=7B56EBC47E780FB000286F69D08144CF
+CT=CB5AE674DB1426618F577BBD63309EA4
+
+I=166
+KEY=79AD3040CCC9FD521284B4F029F76243BD88B5ED482429A2
+IV=CB5AE674DB1426618F577BBD63309EA4
+PT=47A5B213BC3DF61B8EDDCC3BD2D1C363
+CT=1E26AB2D8B156913995FCAC1ABD99D68
+
+I=167
+KEY=10BB9597F823B61F0CA21FDDA2E20B5024D77F2CE3FDB4CA
+IV=1E26AB2D8B156913995FCAC1ABD99D68
+PT=D31FC11C9FD6E7F86916A5D734EA4B4D
+CT=84E0E24F155E5EFCA9AE9C5F2F26BD25
+
+I=168
+KEY=E1264A2AD33800FF8842FD92B7BC55AC8D79E373CCDB09EF
+IV=84E0E24F155E5EFCA9AE9C5F2F26BD25
+PT=F77FE11AE4BEB403F19DDFBD2B1BB6E0
+CT=B41973B0D807A43A822EB57555B818D4
+
+I=169
+KEY=A19ABDD25ED272693C5B8E226FBBF1960F5756069963113B
+IV=B41973B0D807A43A822EB57555B818D4
+PT=FECAAA8EA9C1883640BCF7F88DEA7296
+CT=949634E68FB9086AE623EAF5E867D4A5
+
+I=170
+KEY=DD904ECCC94F64D0A8CDBAC4E002F9FCE974BCF37104C59E
+IV=949634E68FB9086AE623EAF5E867D4A5
+PT=E8A413C2ADB97D387C0AF31E979D16B9
+CT=96BE2B618F8A961E5DC892F429A8B6FC
+
+I=171
+KEY=1B83C20396D7D0D33E7391A56F886FE2B4BC2E0758AC7362
+IV=96BE2B618F8A961E5DC892F429A8B6FC
+PT=1408434BF0C3432BC6138CCF5F98B403
+CT=C0A9596F56E48F459D2C405F47DCA44C
+
+I=172
+KEY=B04C71DBEA60DB15FEDAC8CA396CE0A729906E581F70D72E
+IV=C0A9596F56E48F459D2C405F47DCA44C
+PT=5E7F070C7EE8A852ABCFB3D87CB70BC6
+CT=A4739C93911C72C959E89544500843BD
+
+I=173
+KEY=9BFC8026BC1D965B5AA95459A870926E7078FB1C4F789493
+IV=A4739C93911C72C959E89544500843BD
+PT=718C23D1F537A6E72BB0F1FD567D4D4E
+CT=4D581200B1E446CC3AD306138BF2898B
+
+I=174
+KEY=FEA9DF8F4FECB3ED17F146591994D4A24AABFD0FC48A1D18
+IV=4D581200B1E446CC3AD306138BF2898B
+PT=E4DD231D871795E065555FA9F3F125B6
+CT=E53EFC19D8048073167B1473C5EBA6D9
+
+I=175
+KEY=62DF036D6F96D937F2CFBA40C19054D15CD0E97C0161BBC1
+IV=E53EFC19D8048073167B1473C5EBA6D9
+PT=9AB809114F10C3FD9C76DCE2207A6ADA
+CT=BDB0C3D9732DE5813C4C72CF01FF5194
+
+I=176
+KEY=CFEF04F0343587004F7F7999B2BDB150609C9BB3009EEA55
+IV=BDB0C3D9732DE5813C4C72CF01FF5194
+PT=B4CFE094F8B4EEE5AD30079D5BA35E37
+CT=D00B5B980D8B10DF3D7D4C0BE5975C1C
+
+I=177
+KEY=CBF2C475C11FA6B89F742201BF36A18F5DE1D7B8E509B649
+IV=D00B5B980D8B10DF3D7D4C0BE5975C1C
+PT=34B39728291953DC041DC085F52A21B8
+CT=ADF5CDFDCC23AD8AD111454B2DB69013
+
+I=178
+KEY=C96820A08056F7C23281EFFC73150C058CF092F3C8BF265A
+IV=ADF5CDFDCC23AD8AD111454B2DB69013
+PT=4C8152CCAA0A23AC029AE4D54149517A
+CT=F070979F68BAEBBD6CE8CE8A549C0E12
+
+I=179
+KEY=61A6BBDB58B4C9D4C2F178631BAFE7B8E0185C799C232848
+IV=F070979F68BAEBBD6CE8CE8A549C0E12
+PT=0B6AF20EF8550A1BA8CE9B7BD8E23E16
+CT=8A75D276384A4F468B459466A304D418
+
+I=180
+KEY=D3EC560DE8B1BBEE4884AA1523E5A8FE6B5DC81F3F27FC50
+IV=8A75D276384A4F468B459466A304D418
+PT=259A18BABFD09145B24AEDD6B005723A
+CT=B7C04F66EB771CBD97F948098E23C655
+
+I=181
+KEY=16FE806749FDDF8CFF44E573C892B443FCA48016B1043A05
+IV=B7C04F66EB771CBD97F948098E23C655
+PT=E00B5E4B3D9E64D0C512D66AA14C6462
+CT=29FB08289BD19BCC0FEB0F433D5CACEE
+
+I=182
+KEY=9CC345922C8912D5D6BFED5B53432F8FF34F8F558C5896EB
+IV=29FB08289BD19BCC0FEB0F433D5CACEE
+PT=07BAA266554EAE0C8A3DC5F56574CD59
+CT=495C245E2F3CC52499B9C1AD7C4484BA
+
+I=183
+KEY=7DDDCF7DE759FDEC9FE3C9057C7FEAAB6AF64EF8F01C1251
+IV=495C245E2F3CC52499B9C1AD7C4484BA
+PT=2E5360D5563EB7D4E11E8AEFCBD0EF39
+CT=68267051421D3AFA19A2E43D501B940B
+
+I=184
+KEY=4BA2EAD4106DD4B7F7C5B9543E62D0517354AAC5A007865A
+IV=68267051421D3AFA19A2E43D501B940B
+PT=050EBC6942F92D95367F25A9F734295B
+CT=1781558A2A8B7C29AC82D6610B67E3CF
+
+I=185
+KEY=CFCCD4ECD20E051CE044ECDE14E9AC78DFD67CA4AB606595
+IV=1781558A2A8B7C29AC82D6610B67E3CF
+PT=1AC90B21EB197E26846E3E38C263D1AB
+CT=BF5FE87A2E882A64493850EC3A0E93A5
+
+I=186
+KEY=C9EA5F992C77DD9C5F1B04A43A61861C96EE2C48916EF630
+IV=BF5FE87A2E882A64493850EC3A0E93A5
+PT=58F997704D085DC506268B75FE79D880
+CT=8F43A961964E3452094E8E71295177CD
+
+I=187
+KEY=1136648F9E0A53C3D058ADC5AC2FB24E9FA0A239B83F81FD
+IV=8F43A961964E3452094E8E71295177CD
+PT=086041AB29E423EFD8DC3B16B27D8E5F
+CT=BF69230BAB6200B7828DC04A13B88E83
+
+I=188
+KEY=47040E2D6DFBE3006F318ECE074DB2F91D2D6273AB870F7E
+IV=BF69230BAB6200B7828DC04A13B88E83
+PT=57865A8650D3202056326AA2F3F1B0C3
+CT=A012FAEE65E2C4F0AC22CB63AB75E35D
+
+I=189
+KEY=868F8310E79C0473CF23742062AF7609B10FA91000F2EC23
+IV=A012FAEE65E2C4F0AC22CB63AB75E35D
+PT=F3ABB47DAE94B82EC18B8D3D8A67E773
+CT=F35BBD3C516F86384DA3BB6B5CCC8B37
+
+I=190
+KEY=5C71ADCE480714DA3C78C91C33C0F031FCAC127B5C3E6714
+IV=F35BBD3C516F86384DA3BB6B5CCC8B37
+PT=CDB3E57FA6DDFF9FDAFE2EDEAF9B10A9
+CT=627A15E65B37C2B9575E8A781271AE64
+
+I=191
+KEY=B603092BC5FD004F5E02DCFA68F73288ABF298034E4FC970
+IV=627A15E65B37C2B9575E8A781271AE64
+PT=7E04F9A0F723DF00EA72A4E58DFA1495
+CT=15427D27E783A5476345C83F3E8A3319
+
+I=192
+KEY=4DB5A9F825C5E8C24B40A1DD8F7497CFC8B7503C70C5FA69
+IV=15427D27E783A5476345C83F3E8A3319
+PT=842B94BE25E8747BFBB6A0D3E038E88D
+CT=35812AFD1A90B0B7D52B45EAD9CAF083
+
+I=193
+KEY=D4F2CCC0734F9ACD7EC18B2095E427781D9C15D6A90F0AEA
+IV=35812AFD1A90B0B7D52B45EAD9CAF083
+PT=3FAB7D4C741B8CD499476538568A720F
+CT=C1A59CD3D9E6650F0D16947D26BFC20D
+
+I=194
+KEY=CB28A8313E133469BF6417F34C024277108A81AB8FB0C8E7
+IV=C1A59CD3D9E6650F0D16947D26BFC20D
+PT=37AC888DCE5CDFD31FDA64F14D5CAEA4
+CT=CB0313E9A046711866CA65702A45CDB6
+
+I=195
+KEY=C5BFEB8246ABAF467467041AEC44336F7640E4DBA5F50551
+IV=CB0313E9A046711866CA65702A45CDB6
+PT=326C9E3EB49138ED0E9743B378B89B2F
+CT=ACE8FC6C6ABBC8124FE35C7976585DF6
+
+I=196
+KEY=110891F8FDF0F254D88FF87686FFFB7D39A3B8A2D3AD58A7
+IV=ACE8FC6C6ABBC8124FE35C7976585DF6
+PT=964239EB84C57F61D4B77A7ABB5B5D12
+CT=0762EF13B80A8B77D04AF797B67D5AA6
+
+I=197
+KEY=EFF558976586AC91DFED17653EF5700AE9E94F3565D00201
+IV=0762EF13B80A8B77D04AF797B67D5AA6
+PT=5ECA17ADFE3C2C21FEFDC96F98765EC5
+CT=B60CC9CD9DE93E2A6FB0B59369B1628E
+
+I=198
+KEY=4494A36EABE3555E69E1DEA8A31C4E208659FAA60C61608F
+IV=B60CC9CD9DE93E2A6FB0B59369B1628E
+PT=7A659E803888296BAB61FBF9CE65F9CF
+CT=73258A43C7DA66FFE4DC9384FC7A60C1
+
+I=199
+KEY=1780249B48B8F7561AC454EB64C628DF62856922F01B004E
+IV=73258A43C7DA66FFE4DC9384FC7A60C1
+PT=8D9C3DCF612320B4531487F5E35BA208
+CT=F0F5D51C06F2D900CC4BE8D3512CA4B6
+
+I=200
+KEY=9FF03D1E23BD9959EA3181F76234F1DFAECE81F1A137A4F8
+IV=F0F5D51C06F2D900CC4BE8D3512CA4B6
+PT=F002AEC878B80A0B887019856B056E0F
+CT=E1321C52A51D9345296A0EF2A9DC9CC5
+
+I=201
+KEY=6042967162EDA50B0B039DA5C729629A87A48F0308EB383D
+IV=E1321C52A51D9345296A0EF2A9DC9CC5
+PT=C5EA4A519D9BAF8FFFB2AB6F41503C52
+CT=ED79D8FC9C60B583E29D0A65A6A5F321
+
+I=202
+KEY=250C416206B9D0A9E67A45595B49D71965398566AE4ECB1C
+IV=ED79D8FC9C60B583E29D0A65A6A5F321
+PT=34D771B44B3943DE454ED713645475A2
+CT=7A08F9096109535C262407EB323EF7BC
+
+I=203
+KEY=6357BC1B7B12F1C09C72BC503A408445431D828D9C703CA0
+IV=7A08F9096109535C262407EB323EF7BC
+PT=60A1EEAE2B16841A465BFD797DAB2169
+CT=24C7F1A39F8B2F03C256F5C59B69C31A
+
+I=204
+KEY=18BF29D147A9675BB8B54DF3A5CBAB46814B77480719FFBA
+IV=24C7F1A39F8B2F03C256F5C59B69C31A
+PT=BFD7B314F959298B7BE895CA3CBB969B
+CT=7DDA5DF3CC7C69AA490FB597888396B2
+
+I=205
+KEY=E8B13C48FBABCD19C56F100069B7C2ECC844C2DF8F9A6908
+IV=7DDA5DF3CC7C69AA490FB597888396B2
+PT=23F8A60BD2354901F00E1599BC02AA42
+CT=04CEB4BE252293A822C77B9C4C27822B
+
+I=206
+KEY=BF275C4D9FC54BC0C1A1A4BE4C955144EA83B943C3BDEB23
+IV=04CEB4BE252293A822C77B9C4C27822B
+PT=2182C0577EAA3C2A57966005646E86D9
+CT=0F24034642E351984620BB2647F5D649
+
+I=207
+KEY=40B459144A6415C2CE85A7F80E7600DCACA3026584483D6A
+IV=0F24034642E351984620BB2647F5D649
+PT=F59318D1D3D9A9E0FF930559D5A15E02
+CT=DB98808C46668D79AB059C5554CEEB1A
+
+I=208
+KEY=D5A01AB42D709E6A151D277448108DA507A69E30D086D670
+IV=DB98808C46668D79AB059C5554CEEB1A
+PT=49CF142E621D1A8D951443A067148BA8
+CT=15C32FE5E9BCA5F8D09EA2E4D145FE3D
+
+I=209
+KEY=8191AB3C11B4B72700DE0891A1AC285DD7383CD401C3284D
+IV=15C32FE5E9BCA5F8D09EA2E4D145FE3D
+PT=5C1E9B721987B8BF5431B1883CC4294D
+CT=AA7CA217D0514CA4F20C50293121E8D8
+
+I=210
+KEY=69D24875B8A5B5D1AAA2AA8671FD64F925346CFD30E2C095
+IV=AA7CA217D0514CA4F20C50293121E8D8
+PT=8239553D8FB88E17E843E349A91102F6
+CT=C4068B901CB07904F843BF6F3CDC4FF8
+
+I=211
+KEY=12BAE3B5B2C03E746EA421166D4D1DFDDD77D3920C3E8F6D
+IV=C4068B901CB07904F843BF6F3CDC4FF8
+PT=80D797C671D3BFF67B68ABC00A658BA5
+CT=9F835417C4D622DB52651897DC23E1C3
+
+I=212
+KEY=1A0CFD7FA1284652F1277501A99B3F268F12CB05D01D6EAE
+IV=9F835417C4D622DB52651897DC23E1C3
+PT=C36513D78FBBFDCC08B61ECA13E87826
+CT=0156C998E85BE92F0EF998442204EB19
+
+I=213
+KEY=7829D1FE113103B0F071BC9941C0D60981EB5341F21985B7
+IV=0156C998E85BE92F0EF998442204EB19
+PT=000894F1AF39A67562252C81B01945E2
+CT=6A554057C0A3EB723B693258BC5E899D
+
+I=214
+KEY=D719D37FC9087D2F9A24FCCE81633D7BBA8261194E470C2A
+IV=6A554057C0A3EB723B693258BC5E899D
+PT=B92413276BF142D0AF300281D8397E9F
+CT=395F80E405813D97576954A23C77C2CA
+
+I=215
+KEY=39E173517A321A5AA37B7C2A84E200ECEDEB35BB7230CEE0
+IV=395F80E405813D97576954A23C77C2CA
+PT=AA95F2BD255DBE23EEF8A02EB33A6775
+CT=1B1BC5D3DABD536E91177EF1BF2B7E39
+
+I=216
+KEY=EE1FB67D907C597BB860B9F95E5F53827CFC4B4ACD1BB0D9
+IV=1B1BC5D3DABD536E91177EF1BF2B7E39
+PT=985E81E0BF5FF6EFD7FEC52CEA4E4321
+CT=20F42326749CC7CCD54188DEA46F4EC1
+
+I=217
+KEY=41D333EC5E537B8098949ADF2AC3944EA9BDC3946974FE18
+IV=20F42326749CC7CCD54188DEA46F4EC1
+PT=901FD7D22F220608AFCC8591CE2F22FB
+CT=AFFC6F2668097B58A0CFF619A3FDD1CB
+
+I=218
+KEY=F6E392EF75572C6A3768F5F942CAEF160972358DCA892FD3
+IV=AFFC6F2668097B58A0CFF619A3FDD1CB
+PT=45AEB51360C50AB1B730A1032B0457EA
+CT=1B75CF440CE8521069599B7889F21C1D
+
+I=219
+KEY=47C82CF46472D3732C1D3ABD4E22BD06602BAEF5437B33CE
+IV=1B75CF440CE8521069599B7889F21C1D
+PT=7E931056CC33D22CB12BBE1B1125FF19
+CT=F6079ADBAA8D28F371F0156B170FB7BD
+
+I=220
+KEY=DDA62A9922B04902DA1AA066E4AF95F511DBBB9E54748473
+IV=F6079ADBAA8D28F371F0156B170FB7BD
+PT=2BE3DA337C9187109A6E066D46C29A71
+CT=7D2FC16B26971DDC20C6F7510C47B352
+
+I=221
+KEY=570C8CA5236A2E65A735610DC2388829311D4CCF58333721
+IV=7D2FC16B26971DDC20C6F7510C47B352
+PT=43596064590570F88AAAA63C01DA6767
+CT=5FBA845FB25FE6AE015E4E8A228ED645
+
+I=222
+KEY=6CEA158ED663A4B7F88FE55270676E87304302457ABDE164
+IV=5FBA845FB25FE6AE015E4E8A228ED645
+PT=1E265F0AA9A20C603BE6992BF5098AD2
+CT=A729E250D736A43966DD0D9C461ECEC0
+
+I=223
+KEY=AACCE3387C0DF35D5FA60702A751CABE569E0FD93CA32FA4
+IV=A729E250D736A43966DD0D9C461ECEC0
+PT=B08AAE113CCE6226C626F6B6AA6E57EA
+CT=A8192E964A74A6ABDB463ECFA483A1E3
+
+I=224
+KEY=207F19ABDA13F728F7BF2994ED256C158DD8311698208E47
+IV=A8192E964A74A6ABDB463ECFA483A1E3
+PT=858CF92E6B1793448AB3FA93A61E0475
+CT=060C7CCCD58E6348518161C7878AA71B
+
+I=225
+KEY=AB05AD81CF07091AF1B3555838AB0F5DDC5950D11FAA295C
+IV=060C7CCCD58E6348518161C7878AA71B
+PT=424D175035503C728B7AB42A1514FE32
+CT=8ECAA12830B0C5B4C6950E69AFD31B66
+
+I=226
+KEY=3A8E1CC01464AF9B7F79F470081BCAE91ACC5EB8B079323A
+IV=8ECAA12830B0C5B4C6950E69AFD31B66
+PT=6E5A94391F1FE5A9918BB141DB63A681
+CT=65C3A891192324A7FA3C882B2C09CB8D
+
+I=227
+KEY=8004AB13CF38B3ED1ABA5CE11138EE4EE0F0D6939C70F9B7
+IV=65C3A891192324A7FA3C882B2C09CB8D
+PT=584E219335CA4642BA8AB7D3DB5C1C76
+CT=F29F8735A403414621F2100AF38A500C
+
+I=228
+KEY=D37BB962CFC53E77E825DBD4B53BAF08C102C6996FFAA9BB
+IV=F29F8735A403414621F2100AF38A500C
+PT=CCB996C23C627D4D537F127100FD8D9A
+CT=9C6A7655E25E9231E46C0D3B57C7FCAB
+
+I=229
+KEY=C23B3C983C79179A744FAD8157653D39256ECBA2383D5510
+IV=9C6A7655E25E9231E46C0D3B57C7FCAB
+PT=5D727E12D3932F56114085FAF3BC29ED
+CT=6C5AA7364755AF599AB6F86EC8B24C52
+
+I=230
+KEY=4462CD1DD817170C18150AB710309260BFD833CCF08F1942
+IV=6C5AA7364755AF599AB6F86EC8B24C52
+PT=D7A99C8F3BC37AD08659F185E46E0096
+CT=821D7EAC8FD041C0C8CF1011661FBB9E
+
+I=231
+KEY=1BA52BEF2B010D169A08741B9FE0D3A0771723DD9690A2DC
+IV=821D7EAC8FD041C0C8CF1011661FBB9E
+PT=704F3525510FCC745FC7E6F2F3161A1A
+CT=44591D71D64FC38010E402874853E9BC
+
+I=232
+KEY=C6A6818229CC65E6DE51696A49AF102067F3215ADEC34B60
+IV=44591D71D64FC38010E402874853E9BC
+PT=5D5769AE155C9F43DD03AA6D02CD68F0
+CT=E5647FF6C843543E484FC13B58A345B9
+
+I=233
+KEY=41F27DD5905B299C3B35169C81EC441E2FBCE06186600ED9
+IV=E5647FF6C843543E484FC13B58A345B9
+PT=ADF29030DFDFCCEE8754FC57B9974C7A
+CT=E6EA42E2F046D3ED75081A50770563D1
+
+I=234
+KEY=3A8018855EDC80D2DDDF547E71AA97F35AB4FA31F1656D08
+IV=E6EA42E2F046D3ED75081A50770563D1
+PT=096F74717D5583477B726550CE87A94E
+CT=D75682FE37396887659E87895F1C6441
+
+I=235
+KEY=6C94C2634142DA310A89D6804693FF743F2A7DB8AE790949
+IV=D75682FE37396887659E87895F1C6441
+PT=F1B527DD4935FBDE5614DAE61F9E5AE3
+CT=15755CFE84E113AA751E4D5BB098ABC7
+
+I=236
+KEY=4BA407D7C6426C641FFC8A7EC272ECDE4A3430E31EE1A28E
+IV=15755CFE84E113AA751E4D5BB098ABC7
+PT=7C4433DCC314DBD72730C5B48700B655
+CT=B048F209CE1B1FAEC33392D2D8F326A1
+
+I=237
+KEY=A56FD7BCEEA55474AFB478770C69F3708907A231C612842F
+IV=B048F209CE1B1FAEC33392D2D8F326A1
+PT=D40C7CD8D80C8C6CEECBD06B28E73810
+CT=8E1F4830F94004C286C39D0EC014A963
+
+I=238
+KEY=0730B7B664CFD1E321AB3047F529F7B20FC43F3F06062D4C
+IV=8E1F4830F94004C286C39D0EC014A963
+PT=B16772FE8C8A573FA25F600A8A6A8597
+CT=3FB92771D2BE2D33C40AB0409998B229
+
+I=239
+KEY=0A08E43B13C57EB41E1217362797DA81CBCE8F7F9F9E9F65
+IV=3FB92771D2BE2D33C40AB0409998B229
+PT=D4883476825EA2D30D38538D770AAF57
+CT=190106DE79836016C57A16BBBA6893D2
+
+I=240
+KEY=195B7E1B67872B0D071311E85E14BA970EB499C425F60CB7
+IV=190106DE79836016C57A16BBBA6893D2
+PT=3B8F4F140FDFFB6B13539A20744255B9
+CT=C06398537B4F534203D57184543E6516
+
+I=241
+KEY=BE0C4A8A9B581D16C77089BB255BE9D50D61E84071C869A1
+IV=C06398537B4F534203D57184543E6516
+PT=E50D127AE258061DA7573491FCDF361B
+CT=FF615CCC9F2D3DBB3074C835ECE4224E
+
+I=242
+KEY=662A224DAB1233C83811D577BA76D46E3D1520759D2C4BEF
+IV=FF615CCC9F2D3DBB3074C835ECE4224E
+PT=347C976D20470968D82668C7304A2EDE
+CT=B5FB1BCCBC838B87FDB10FEFE6CDC45B
+
+I=243
+KEY=F4F3B47D9CC8BA798DEACEBB06F55FE9C0A42F9A7BE18FB4
+IV=B5FB1BCCBC838B87FDB10FEFE6CDC45B
+PT=BC276D1002C5DD8292D9963037DA89B1
+CT=151F88A44A76568FAC756011B827778D
+
+I=244
+KEY=7EA3C03193B737DE98F5461F4C8309666CD14F8BC3C6F839
+IV=151F88A44A76568FAC756011B827778D
+PT=BCD9054596EE644E8A50744C0F7F8DA7
+CT=C1B0B6FDD717881442496794A2C890F2
+
+I=245
+KEY=C4D94D5C4169EE4B5945F0E29B9481722E98281F610E68CB
+IV=C1B0B6FDD717881442496794A2C890F2
+PT=3D7F68D3014F3BEDBA7A8D6DD2DED995
+CT=181100A04881DCF9813E4A22C6C1BB3B
+
+I=246
+KEY=A9A9483D9FC46DD34154F042D3155D8BAFA6623DA7CFD3F0
+IV=181100A04881DCF9813E4A22C6C1BB3B
+PT=0FE2E2A97DFFB4966D700561DEAD8398
+CT=AA4BEC4007C38C7B86B6F9EED33E5EB1
+
+I=247
+KEY=5F08A3C09F4AE90BEB1F1C02D4D6D1F029109BD374F18D41
+IV=AA4BEC4007C38C7B86B6F9EED33E5EB1
+PT=C2392264CE43C57AF6A1EBFD008E84D8
+CT=A0756CCDA72462CD89DF9990C0FE6676
+
+I=248
+KEY=6A1A4F2D25DFC9F94B6A70CF73F2B33DA0CF0243B40FEB37
+IV=A0756CCDA72462CD89DF9990C0FE6676
+PT=A6650A3432CCA74A3512ECEDBA9520F2
+CT=F5044AECC6F35C99FCDBA26DD15E1474
+
+I=249
+KEY=B475174A46D0CDC2BE6E3A23B501EFA45C14A02E6551FF43
+IV=F5044AECC6F35C99FCDBA26DD15E1474
+PT=07967DE17DEB720CDE6F5867630F043B
+CT=60645B559E7321D7FA8A3F925CFC0FA4
+
+I=250
+KEY=8DBB9D8A4A2E7E61DE0A61762B72CE73A69E9FBC39ADF0E7
+IV=60645B559E7321D7FA8A3F925CFC0FA4
+PT=D8D3FD2077545DD039CE8AC00CFEB3A3
+CT=C4C6FD53A2572D643AA631FB85B84D0B
+
+I=251
+KEY=97D34E4B3B9E081A1ACC9C258925E3179C38AE47BC15BDEC
+IV=C4C6FD53A2572D643AA631FB85B84D0B
+PT=F31D8F3C8AC67E081A68D3C171B0767B
+CT=E1A0E460E2D1483FE954F26F45CCE7A0
+
+I=252
+KEY=5372C72A4ABF72D9FB6C78456BF4AB28756C5C28F9D95A4C
+IV=E1A0E460E2D1483FE954F26F45CCE7A0
+PT=422C5429CE7BD811C4A1896171217AC3
+CT=2695923CFB2141F05A0F144FF021BD36
+
+I=253
+KEY=A8CA6DB8A8758322DDF9EA7990D5EAD82F63486709F8E77A
+IV=2695923CFB2141F05A0F144FF021BD36
+PT=780771C65FCB907BFBB8AA92E2CAF1FB
+CT=A9820B527F71E95CC1F53033149FB26F
+
+I=254
+KEY=62ABF1F4178F3C73747BE12BEFA40384EE9678541D675515
+IV=A9820B527F71E95CC1F53033149FB26F
+PT=CCC14BD8DF1CA8A4CA619C4CBFFABF51
+CT=2BAD4E8CD7D6420D36DC2F8E77DCA072
+
+I=255
+KEY=C79B767D31D9F0FC5FD6AFA738724189D84A57DA6ABBF567
+IV=2BAD4E8CD7D6420D36DC2F8E77DCA072
+PT=1EFF63C71B10DCC7A53087892656CC8F
+CT=C21303AAB04E2CAF1893396DD405B265
+
+I=256
+KEY=1F3C7FF71340DEEC9DC5AC0D883C6D26C0D96EB7BEBE4702
+IV=C21303AAB04E2CAF1893396DD405B265
+PT=209270B7768E5553D8A7098A22992E10
+CT=B220025B5307C9D5D1EEB4B427E7263F
+
+I=257
+KEY=867CB381E6D532B32FE5AE56DB3BA4F31137DA039959613D
+IV=B220025B5307C9D5D1EEB4B427E7263F
+PT=8546A6C9B4CEF0229940CC76F595EC5F
+CT=B925C660EBE409050DA369E58C601F4D
+
+I=258
+KEY=33B33F93622E509296C0683630DFADF61C94B3E615397E70
+IV=B925C660EBE409050DA369E58C601F4D
+PT=1F4930242C2951C4B5CF8C1284FB6221
+CT=67DA7B4BEAB2152D21C54F389F9282D4
+
+I=259
+KEY=E8EC3394AF44DD34F11A137DDA6DB8DB3D51FCDE8AABFCA4
+IV=67DA7B4BEAB2152D21C54F389F9282D4
+PT=41611AE93BE61306DB5F0C07CD6A8DA6
+CT=4C116D3ED0B021129CCD1764D132A72D
+
+I=260
+KEY=92F61F4CB5794268BD0B7E430ADD99C9A19CEBBA5B995B89
+IV=4C116D3ED0B021129CCD1764D132A72D
+PT=E7B1E63FBD5B4CA77A1A2CD81A3D9F5C
+CT=FE1C3096C14AF2A4DC840207BFFFC0AF
+
+I=261
+KEY=08DC826B4DDBAC4D43174ED5CB976B6D7D18E9BDE4669B26
+IV=FE1C3096C14AF2A4DC840207BFFFC0AF
+PT=9A0D034B1931FD599A2A9D27F8A2EE25
+CT=ED500812A10CC6C4EED0836871F85AA9
+
+I=262
+KEY=486EBC43A876FF2AAE4746C76A9BADA993C86AD5959EC18F
+IV=ED500812A10CC6C4EED0836871F85AA9
+PT=8237641B58069AFD40B23E28E5AD5367
+CT=0AD90C1C13E7C1318057A417C0B9B97C
+
+I=263
+KEY=F340D2CAC4645595A49E4ADB797C6C98139FCEC2552778F3
+IV=0AD90C1C13E7C1318057A417C0B9B97C
+PT=905119E1F11E4B04BB2E6E896C12AABF
+CT=B260FFA5806A4A6D8845FA6146A565ED
+
+I=264
+KEY=DF326741BD1EE2FF16FEB57EF91626F59BDA34A313821D1E
+IV=B260FFA5806A4A6D8845FA6146A565ED
+PT=4F639233904531162C72B58B797AB76A
+CT=2D27A1A3968E30EBCA463C8709D0FD83
+
+I=265
+KEY=D4C684692E05983C3BD914DD6F98161E519C08241A52E09D
+IV=2D27A1A3968E30EBCA463C8709D0FD83
+PT=428B700FB3CD18790BF4E328931B7AC3
+CT=D350CCF3B440006C9F18E99DD5B69920
+
+I=266
+KEY=9DD5275FFDCD5D2DE889D82EDBD81672CE84E1B9CFE479BD
+IV=D350CCF3B440006C9F18E99DD5B69920
+PT=97F4A6256A9E22FB4913A336D3C8C511
+CT=F5A0571EB7E4719B862EBC47141EA319
+
+I=267
+KEY=0A3B329A4973D7A21D298F306C3C67E948AA5DFEDBFADAA4
+IV=F5A0571EB7E4719B862EBC47141EA319
+PT=E355F7EBA4DAC16B97EE15C5B4BE8A8F
+CT=4F18730073D3E78CAD356441F1317B2D
+
+I=268
+KEY=3BB3A19EF4EB8A755231FC301FEF8065E59F39BF2ACBA189
+IV=4F18730073D3E78CAD356441F1317B2D
+PT=A20B3B6C41E88E9D31889304BD985DD7
+CT=AEAECB17B9009AAF1E4E9CC02653194B
+
+I=269
+KEY=4B9DDD2F821CE4D1FC9F3727A6EF1ACAFBD1A57F0C98B8C2
+IV=AEAECB17B9009AAF1E4E9CC02653194B
+PT=5D2E4A96F9BB4AD4702E7CB176F76EA4
+CT=26851709960A42D5711EBDC7D40535FC
+
+I=270
+KEY=D7273499C5BA2842DA1A202E30E5581F8ACF18B8D89D8D3E
+IV=26851709960A42D5711EBDC7D40535FC
+PT=202534EA0A1952A19CBAE9B647A6CC93
+CT=FF8BFFB98EDA7E54664AE879551B5497
+
+I=271
+KEY=7870FF6B66070AB02591DF97BE3F264BEC85F0C18D86D9A9
+IV=FF8BFFB98EDA7E54664AE879551B5497
+PT=365CFE282B9508CFAF57CBF2A3BD22F2
+CT=D0809C84A97221E6F8DCB483B38EC7E1
+
+I=272
+KEY=F4E6DFDF4A081200F5114313174D07AD145944423E081E48
+IV=D0809C84A97221E6F8DCB483B38EC7E1
+PT=915323F59134AB838C9620B42C0F18B0
+CT=DC8A24B8DECF81E0412DBF10127119EC
+
+I=273
+KEY=336A7C81A4BE3FE9299B67ABC982864D5574FB522C7907A4
+IV=DC8A24B8DECF81E0412DBF10127119EC
+PT=0FC4387E49F666B8C78CA35EEEB62DE9
+CT=84E370DF6CA478BA85FC0874393CE442
+
+I=274
+KEY=F8ADC39E17CDDEB0AD781774A526FEF7D088F3261545E3E6
+IV=84E370DF6CA478BA85FC0874393CE442
+PT=34BFEFD3E43D8EE0CBC7BF1FB373E159
+CT=2C109A8363D1D0FB69CA77ABFA922F05
+
+I=275
+KEY=2B26D271208BD64F81688DF7C6F72E0CB942848DEFD7CCE3
+IV=2C109A8363D1D0FB69CA77ABFA922F05
+PT=D28D86D5199E7E30D38B11EF374608FF
+CT=F1749EFE66D339BC99AE4D9F63C90490
+
+I=276
+KEY=ACB8D3E6F5A45F0C701C1309A02417B020ECC9128C1EC873
+IV=F1749EFE66D339BC99AE4D9F63C90490
+PT=2ADAFA1911C5E9BD879E0197D52F8943
+CT=3B2A7C4278E1F071BFA29A6B0BFF4A15
+
+I=277
+KEY=CCEE75264DD770C44B366F4BD8C5E7C19F4E537987E18266
+IV=3B2A7C4278E1F071BFA29A6B0BFF4A15
+PT=84E244B62DF08DC76056A6C0B8732FC8
+CT=A35F83A5EE0B1C3B9DAD76DEAED96D72
+
+I=278
+KEY=F8F9239CDB5CC963E869ECEE36CEFBFA02E325A72938EF14
+IV=A35F83A5EE0B1C3B9DAD76DEAED96D72
+PT=F0B652F296CF162B341756BA968BB9A7
+CT=D5867FFE2FB75E309D3345611B25E3B0
+
+I=279
+KEY=509A10ABA5EAF2963DEF93101979A5CA9FD060C6321D0CA4
+IV=D5867FFE2FB75E309D3345611B25E3B0
+PT=C47D42AE34131463A86333377EB63BF5
+CT=6E136F01638AFBE3554218431DF44E7E
+
+I=280
+KEY=9B52C39C38F16CCE53FCFC117AF35E29CA9278852FE942DA
+IV=6E136F01638AFBE3554218431DF44E7E
+PT=78E05783EAEBE1BDCBC8D3379D1B9E58
+CT=FB6ACD3D0CF805374AD07EF5C038EBF6
+
+I=281
+KEY=2044F086923D5E43A896312C760B5B1E80420670EFD1A92C
+IV=FB6ACD3D0CF805374AD07EF5C038EBF6
+PT=02415B8E4D915492BB16331AAACC328D
+CT=0086C26DA11540FF5F485D7B238FD98C
+
+I=282
+KEY=12CE4C4109606CD7A810F341D71E1BE1DF0A5B0BCC5E70A0
+IV=0086C26DA11540FF5F485D7B238FD98C
+PT=0A2988237132B0B3328ABCC79B5D3294
+CT=F2E94C71A2AE0FCB096D8259B931CF8D
+
+I=283
+KEY=21BBCDA7FBC5229C5AF9BF3075B0142AD667D952756FBF2D
+IV=F2E94C71A2AE0FCB096D8259B931CF8D
+PT=4234B6C7F1CE98A3337581E6F2A54E4B
+CT=3B52E7834263C6790763706943741FD8
+
+I=284
+KEY=BB451732881A996161AB58B337D3D253D104A93B361BA0F5
+IV=3B52E7834263C6790763706943741FD8
+PT=F8509FB57E14501F9AFEDA9573DFBBFD
+CT=93FCA9F122CB707213D0CD72D8E6BF74
+
+I=285
+KEY=857D076E9A127A84F257F1421518A221C2D46449EEFD1F81
+IV=93FCA9F122CB707213D0CD72D8E6BF74
+PT=AA4D07DFAD030BE03E38105C1208E3E5
+CT=50717568D21862AECFAA898337405C96
+
+I=286
+KEY=1BCFD020D63709E0A226842AC700C08F0D7EEDCAD9BD4317
+IV=50717568D21862AECFAA898337405C96
+PT=7B488D7BBB2D538E9EB2D74E4C257364
+CT=0338D74260CB6CBB1B220DE7E4CC0BCF
+
+I=287
+KEY=CCDDF5D0BBCE202DA11E5368A7CBAC34165CE02D3D7148D8
+IV=0338D74260CB6CBB1B220DE7E4CC0BCF
+PT=16E01F8B3E94AC26D71225F06DF929CD
+CT=698AD17BB2F5F06C0465BEE34A7DCEDD
+
+I=288
+KEY=B7F556BC9BB4DC49C8948213153E5C5812395ECE770C8605
+IV=698AD17BB2F5F06C0465BEE34A7DCEDD
+PT=3ED0C80AFDEFE8BF7B28A36C207AFC64
+CT=E20129557F795C2B1CC32A5494824A4B
+
+I=289
+KEY=4B00D75969C3549C2A95AB466A4700730EFA749AE38ECC4E
+IV=E20129557F795C2B1CC32A5494824A4B
+PT=20BE0CD6C2244384FCF581E5F27788D5
+CT=C2F9DD55E91F4796636FEC9745410087
+
+I=290
+KEY=5EDCC5155BA684A4E86C7613835847E56D95980DA6CFCCC9
+IV=C2F9DD55E91F4796636FEC9745410087
+PT=B2DF53DF1139FB9915DC124C3265D038
+CT=015D51CD3568EB4EC210B58FFA89A409
+
+I=291
+KEY=21BA26AC6880AACDE93127DEB630ACABAF852D825C4668C0
+IV=015D51CD3568EB4EC210B58FFA89A409
+PT=401094B8B47CBDC87F66E3B933262E69
+CT=2987D39C19E6997957BDD0CAF010F778
+
+I=292
+KEY=BBA7ABC0A20CCBDEC0B6F442AFD635D2F838FD48AC569FB8
+IV=2987D39C19E6997957BDD0CAF010F778
+PT=EFC30498827AAD9A9A1D8D6CCA8C6113
+CT=E01AA987C9520EF8EBF53E97371D056B
+
+I=293
+KEY=5322D81BAA29410320AC5DC566843B2A13CDC3DF9B4B9AD3
+IV=E01AA987C9520EF8EBF53E97371D056B
+PT=685D6F660D40105CE88573DB08258ADD
+CT=D1265ABFCFA75FC65E94983BFF75CD48
+
+I=294
+KEY=19DF73EBF1CEF669F18A077AA92364EC4D595BE4643E579B
+IV=D1265ABFCFA75FC65E94983BFF75CD48
+PT=DD6E090E9981E5F24AFDABF05BE7B76A
+CT=605FDD1CA95B8FE1A5E26DBA10241914
+
+I=295
+KEY=F7D1D0CA3DAA851891D5DA660078EB0DE8BB365E741A4E8F
+IV=605FDD1CA95B8FE1A5E26DBA10241914
+PT=9F8442EE8B5A325FEE0EA321CC647371
+CT=76D67121FDEAEB6B81DBB29565F71E8E
+
+I=296
+KEY=FFFF200EA04824E9E703AB47FD920066696084CB11ED5001
+IV=76D67121FDEAEB6B81DBB29565F71E8E
+PT=5AF386509F0C8BAA082EF0C49DE2A1F1
+CT=7E1D833DC8D73228B7DFDE918E31E5E7
+
+I=297
+KEY=2A7D40B689490FC7991E287A3545324EDEBF5A5A9FDCB5E6
+IV=7E1D833DC8D73228B7DFDE918E31E5E7
+PT=02AB05F508ACDD21D58260B829012B2E
+CT=D6CA06D415EA5D750B5D06C252645A43
+
+I=298
+KEY=134154161A39E2CF4FD42EAE20AF6F3BD5E25C98CDB8EFA5
+IV=D6CA06D415EA5D750B5D06C252645A43
+PT=E63873AE14DD3BA8393C14A09370ED08
+CT=BFEA32E77BC1607921C54027C01C3EDF
+
+I=299
+KEY=AD8AF90935A6B455F03E1C495B6E0F42F4271CBF0DA4D17A
+IV=BFEA32E77BC1607921C54027C01C3EDF
+PT=BAD47B1FBF949870BECBAD1F2F9F569A
+CT=A86FFC9A91C79AFE47899B3934F3E05E
+
+I=300
+KEY=D88A2E828514CEC25851E0D3CAA995BCB3AE878639573124
+IV=A86FFC9A91C79AFE47899B3934F3E05E
+PT=2A2115074A9767747500D78BB0B27A97
+CT=507ED155CC3ED3B1922BBC166812A7FE
+
+I=301
+KEY=2CDDF1A577A3C86C082F31860697460D21853B90514596DA
+IV=507ED155CC3ED3B1922BBC166812A7FE
+PT=308D27178ABA22BCF457DF27F2B706AE
+CT=87F4EEA7CD2438F3EDCB650824A2D638
+
+I=302
+KEY=2B9D006908018D648FDBDF21CBB37EFECC4E5E9875E740E2
+IV=87F4EEA7CD2438F3EDCB650824A2D638
+PT=28F6C452D061E3DB0740F1CC7FA24508
+CT=DBA57DDA73A4E987EA32EF113877E908
+
+I=303
+KEY=FC69838410D06425547EA2FBB8179779267CB1894D90A9EA
+IV=DBA57DDA73A4E987EA32EF113877E908
+PT=91CFB50FFBE97D8AD7F483ED18D1E941
+CT=1720ED3E3B685A19CDA66BD09BD4DA5F
+
+I=304
+KEY=541AAB6191E2C51F435E4FC5837FCD60EBDADA59D64473B5
+IV=1720ED3E3B685A19CDA66BD09BD4DA5F
+PT=78FF980C48FAEBA0A87328E58132A13A
+CT=ED2E260103CAA77598FD195D02B484C8
+
+I=305
+KEY=761B0A3F50E2ACC1AE7069C480B56A157327C304D4F0F77D
+IV=ED2E260103CAA77598FD195D02B484C8
+PT=8C01554039D8F8EE2201A15EC10069DE
+CT=A9F0E16716B3AC14E06F18F5AEECB541
+
+I=306
+KEY=70056CD35CF430D5078088A39606C6019348DBF17A1C423C
+IV=A9F0E16716B3AC14E06F18F5AEECB541
+PT=C139651464D1614B061E66EC0C169C14
+CT=A41DDF008E0D52B627982D4196C3069E
+
+I=307
+KEY=EE1932746487B7BEA39D57A3180B94B7B4D0F6B0ECDF44A2
+IV=A41DDF008E0D52B627982D4196C3069E
+PT=C617572884721A3D9E1C5EA73873876B
+CT=44E5304E35A21660C450FAF84D87B13B
+
+I=308
+KEY=13D43E4526F8243FE77867ED2DA982D770800C48A158F599
+IV=44E5304E35A21660C450FAF84D87B13B
+PT=9C72E08DD264D6B7FDCD0C31427F9381
+CT=173B2C7A54A1A3CF3D39DCB68DA1C539
+
+I=309
+KEY=7CB72DE2CAED4080F0434B97790821184DB9D0FE2CF930A0
+IV=173B2C7A54A1A3CF3D39DCB68DA1C539
+PT=4DF3764F679E29446F6313A7EC1564BF
+CT=F1A167A3EB8F3FAB9F9B1570475ED15A
+
+I=310
+KEY=A7E6340A1278A3E801E22C3492871EB3D222C58E6BA7E1FA
+IV=F1A167A3EB8F3FAB9F9B1570475ED15A
+PT=2ED419EA11AAF8F3DB5119E8D895E368
+CT=2C5C5B10E285FE6C7E4750D2F9C1BD23
+
+I=311
+KEY=4B535B4D088F09192DBE77247002E0DFAC65955C92665CD9
+IV=2C5C5B10E285FE6C7E4750D2F9C1BD23
+PT=A3E9EA99771D0C02ECB56F471AF7AAF1
+CT=A12B4A15DBFAE2E7D4A7A792CD3C121A
+
+I=312
+KEY=2F0E7BAD76DC0A718C953D31ABF8023878C232CE5F5A4EC3
+IV=A12B4A15DBFAE2E7D4A7A792CD3C121A
+PT=1CC105D2604628B7645D20E07E530368
+CT=65CE700B785D901C5E5E08F7E74BB296
+
+I=313
+KEY=6111C386DE35C954E95B4D3AD3A59224269C3A39B811FC55
+IV=65CE700B785D901C5E5E08F7E74BB296
+PT=F902717AF7F0794E4E1FB82BA8E9C325
+CT=E7F3BD1056C504285FFC7F65B395DCAE
+
+I=314
+KEY=3B8F85E6FD28C4610EA8F02A8560960C7960455C0B8420FB
+IV=E7F3BD1056C504285FFC7F65B395DCAE
+PT=20A5529420D6D4C35A9E4660231D0D35
+CT=6CC36458ADECCA8B7198FD272A8C76C8
+
+I=315
+KEY=D404C97E089F240B626B9472288C5C8708F8B87B21085633
+IV=6CC36458ADECCA8B7198FD272A8C76C8
+PT=1094639F6723C9B0EF8B4C98F5B7E06A
+CT=D01C3C1E036D804563F04926ED203146
+
+I=316
+KEY=4779B44770085E18B277A86C2BE1DCC26B08F15DCC286775
+IV=D01C3C1E036D804563F04926ED203146
+PT=A482437681DFE307937D7D3978977A13
+CT=319D579DE9E55C8A3B2097EE8C93375F
+
+I=317
+KEY=22362304D7417BB483EAFFF1C2048048502866B340BB502A
+IV=319D579DE9E55C8A3B2097EE8C93375F
+PT=7AF0C8274B5C243B654F9743A74925AC
+CT=5F722165B8B422E088814B77A6B4D8E4
+
+I=318
+KEY=06FDA49350C16FEADC98DE947AB0A2A8D8A92DC4E60F88CE
+IV=5F722165B8B422E088814B77A6B4D8E4
+PT=A37964FA3E8145EF24CB87978780145E
+CT=C0417773DFD3FC83C2CE12D388F5DD8F
+
+I=319
+KEY=366245F8CBC490611CD9A9E7A5635E2B1A673F176EFA5541
+IV=C0417773DFD3FC83C2CE12D388F5DD8F
+PT=5D7E1E14F7BD7DB6309FE16B9B05FF8B
+CT=2EAE64B58C18AC7ADD2EE62896AB708D
+
+I=320
+KEY=A1BB8A9F9BE8F1383277CD52297BF251C749D93FF85125CC
+IV=2EAE64B58C18AC7ADD2EE62896AB708D
+PT=3ADC6991BF15554F97D9CF67502C6159
+CT=069FC966F8A985AD41617CB0148D2B96
+
+I=321
+KEY=7AB228E4114C14AB34E80434D1D277FC8628A58FECDC0E5A
+IV=069FC966F8A985AD41617CB0148D2B96
+PT=4405B80CCE92FD71DB09A27B8AA4E593
+CT=13459A0239A33BC41424A5D03C6B2864
+
+I=322
+KEY=78D1BC27E5CBBB1D27AD9E36E8714C38920C005FD0B7263E
+IV=13459A0239A33BC41424A5D03C6B2864
+PT=B9BAA861988616CD026394C3F487AFB6
+CT=08DA968A2BAEB9B763EB42BF555A2BFA
+
+I=323
+KEY=F53B033A22EA1D7B2F7708BCC3DFF58FF1E742E085ED0DC4
+IV=08DA968A2BAEB9B763EB42BF555A2BFA
+PT=30654265AD0FB24E8DEABF1DC721A666
+CT=E8412BDC1E75AC8E2C28552E2195795E
+
+I=324
+KEY=4928B51AF5C2408CC7362360DDAA5901DDCF17CEA478749A
+IV=E8412BDC1E75AC8E2C28552E2195795E
+PT=EEB05E487EEB907FBC13B620D7285DF7
+CT=E01839F95680D27E048383236D59EE85
+
+I=325
+KEY=C4DB91EAFC4C26D7272E1A998B2A8B7FD94C94EDC9219A1F
+IV=E01839F95680D27E048383236D59EE85
+PT=BA0160229D7471FE8DF324F0098E665B
+CT=D41902E6BE946CEB1612CFEE2F33F7CD
+
+I=326
+KEY=B550731E659834A1F337187F35BEE794CF5E5B03E6126DD2
+IV=D41902E6BE946CEB1612CFEE2F33F7CD
+PT=7DC970AFAF99BA6C718BE2F499D41276
+CT=326C3523173D62E9E145592E7A774311
+
+I=327
+KEY=5F87F6C2402B2352C15B2D5C2283857D2E1B022D9C652EC3
+IV=326C3523173D62E9E145592E7A774311
+PT=24ED6DAE1B24CC2BEAD785DC25B317F3
+CT=DDAE8AFF94604FFA82AE4FFB06953C01
+
+I=328
+KEY=3636C04061996CD01CF5A7A3B6E3CA87ACB54DD69AF012C2
+IV=DDAE8AFF94604FFA82AE4FFB06953C01
+PT=98E262805B8D9FD169B1368221B24F82
+CT=0D75DCFA4941BCE658DB2C71CB270BE7
+
+I=329
+KEY=64B9A0DE7DDA73C011807B59FFA27661F46E61A751D71925
+IV=0D75DCFA4941BCE658DB2C71CB270BE7
+PT=2BC34C226D41D8CE528F609E1C431F10
+CT=D70ED1DCDB9420E4B4A0D2A7C5148DE3
+
+I=330
+KEY=F64196479D35F74BC68EAA852436568540CEB30094C394C6
+IV=D70ED1DCDB9420E4B4A0D2A7C5148DE3
+PT=1015CB1E4569986C92F83699E0EF848B
+CT=524314DCCF2ADE5F8C3D241824C2BA73
+
+I=331
+KEY=686AB32115A2884C94CDBE59EB1C88DACCF39718B0012EB5
+IV=524314DCCF2ADE5F8C3D241824C2BA73
+PT=FB8B49053F724B7D9E2B256688977F07
+CT=7C579324F7251EDF95BDE2320104ACA6
+
+I=332
+KEY=34DD68E6F442F6D9E89A2D7D1C399605594E752AB1058213
+IV=7C579324F7251EDF95BDE2320104ACA6
+PT=A3B71504A8DAA3515CB7DBC7E1E07E95
+CT=921A66278A6D1E61D4B509F199F8FE55
+
+I=333
+KEY=19C9F40A858DD9EA7A804B5A965488648DFB7CDB28FD7C46
+IV=921A66278A6D1E61D4B509F199F8FE55
+PT=B0B651905E1B38FB2D149CEC71CF2F33
+CT=F2C37CF94514C902A0E438159C2C9F5F
+
+I=334
+KEY=B68812FC7D4E40D6884337A3D34041662D1F44CEB4D1E319
+IV=F2C37CF94514C902A0E438159C2C9F5F
+PT=7DE03F498839F8DAAF41E6F6F8C3993C
+CT=4596A25A85D06BCC74F686F8F1E8C203
+
+I=335
+KEY=2836F982CA563379CDD595F956902AAA59E9C2364539211A
+IV=4596A25A85D06BCC74F686F8F1E8C203
+PT=D5425E42151014ED9EBEEB7EB71873AF
+CT=0BA46EFA61FB07430C51D7CE267E1F47
+
+I=336
+KEY=BC8C7F9051C98892C671FB03376B2DE955B815F863473E5D
+IV=0BA46EFA61FB07430C51D7CE267E1F47
+PT=5D060EEC179C1B9E94BA86129B9FBBEB
+CT=49F7D7D7BAB7795A4E74A854C8C1AC53
+
+I=337
+KEY=E661F49B22BC92358F862CD48DDC54B31BCCBDACAB86920E
+IV=49F7D7D7BAB7795A4E74A854C8C1AC53
+PT=C598926A437A27A45AED8B0B73751AA7
+CT=0EB97E32AEC4CE3959197C5B72C1ABC5
+
+I=338
+KEY=E625AB8664BCF057813F52E623189A8A42D5C1F7D94739CB
+IV=0EB97E32AEC4CE3959197C5B72C1ABC5
+PT=B7272C4D712F9CF500445F1D46006262
+CT=DA9F53564E69AED610BCCAD13C00A241
+
+I=339
+KEY=75FC1D46AFD886915BA001B06D71345C52690B26E5479B8A
+IV=DA9F53564E69AED610BCCAD13C00A241
+PT=FE7513CF9353BBF093D9B6C0CB6476C6
+CT=7F61B6F9B7C14EB6179F2DA597EC1183
+
+I=340
+KEY=F92D3201DA84422024C1B749DAB07AEA45F6268372AB8A09
+IV=7F61B6F9B7C14EB6179F2DA597EC1183
+PT=4E4D3DF58D7D9C338CD12F47755CC4B1
+CT=F9216373C300AA9BE96BD8C98F9716B7
+
+I=341
+KEY=680384A1E522C848DDE0D43A19B0D071AC9DFE4AFD3C9CBE
+IV=F9216373C300AA9BE96BD8C98F9716B7
+PT=1A7B30192D54142E912EB6A03FA68A68
+CT=8512BA1B57BC04EF3C021DB1EC3CA9C6
+
+I=342
+KEY=DE3B85BD09EC93B858F26E214E0CD49E909FE3FB11003578
+IV=8512BA1B57BC04EF3C021DB1EC3CA9C6
+PT=86587FF85D73F77FB638011CECCE5BF0
+CT=FA582C37D4063D61428C886A9FD54C84
+
+I=343
+KEY=C574CA7322F443FBA2AA42169A0AE9FFD2136B918ED579FC
+IV=FA582C37D4063D61428C886A9FD54C84
+PT=3A7425A8B7BC3A941B4F4FCE2B18D043
+CT=7571B4D46CBC671964AB5BDE9C843DCF
+
+I=344
+KEY=078109812EFBA9DBD7DBF6C2F6B68EE6B6B8304F12514433
+IV=7571B4D46CBC671964AB5BDE9C843DCF
+PT=5224060F0848F028C2F5C3F20C0FEA20
+CT=DA9EB72D65D492FE88B819674B8433C1
+
+I=345
+KEY=5BF7FA2E15A87C850D4541EF93621C183E00292859D577F2
+IV=DA9EB72D65D492FE88B819674B8433C1
+PT=2622B2A19CBBAD065C76F3AF3B53D55E
+CT=C66EF470CEDDD499AE6214E75DE9051B
+
+I=346
+KEY=ECBE2377CAF0C9E9CB2BB59F5DBFC88190623DCF043C72E9
+IV=C66EF470CEDDD499AE6214E75DE9051B
+PT=833F22A76D51E360B749D959DF58B56C
+CT=57407E3DEFFF753E879619424FCE5713
+
+I=347
+KEY=4EAB83DA78D60CB09C6BCBA2B240BDBF17F4248D4BF225FA
+IV=57407E3DEFFF753E879619424FCE5713
+PT=25781A534FB9192CA215A0ADB226C559
+CT=644D89381439E7BBED7DC344CBF4C886
+
+I=348
+KEY=C4977EF1F6271D6CF826429AA6795A04FA89E7C98006ED7C
+IV=644D89381439E7BBED7DC344CBF4C886
+PT=E8EDD9AA25A8C5B08A3CFD2B8EF111DC
+CT=CA4B2680D0EE8E28818BE8DE8D625ADC
+
+I=349
+KEY=80212F6D11C6DAE2326D641A7697D42C7B020F170D64B7A0
+IV=CA4B2680D0EE8E28818BE8DE8D625ADC
+PT=8F667EEDB79E930644B6519CE7E1C78E
+CT=5497F477AD5E65BB748A781533F1BCEF
+
+I=350
+KEY=A05DF1DF7E0393A566FA906DDBC9B1970F8877023E950B4F
+IV=5497F477AD5E65BB748A781533F1BCEF
+PT=099FDB76E6D21788207CDEB26FC54947
+CT=C8C541B359BF1B53441C4EFFFD2F65AF
+
+I=351
+KEY=3970F236F800D18BAE3FD1DE8276AAC44B9439FDC3BA6EE0
+IV=C8C541B359BF1B53441C4EFFFD2F65AF
+PT=C79FA2079ECCEBCD992D03E98603422E
+CT=E59765A861DE0168161EA1360B5966A9
+
+I=352
+KEY=8ED3BFA3E4C9453C4BA8B476E3A8ABAC5D8A98CBC8E30849
+IV=E59765A861DE0168161EA1360B5966A9
+PT=AFBCD48F06709730B7A34D951CC994B7
+CT=5A65435BD1B4DB742E8AFF8C402927FC
+
+I=353
+KEY=2A3F01E56E45895B11CDF72D321C70D87300674788CA2FB5
+IV=5A65435BD1B4DB742E8AFF8C402927FC
+PT=CF684F64B8CCD2EDA4ECBE468A8CCC67
+CT=551AF68D50D23408F47214C0B18E6C8A
+
+I=354
+KEY=CA12AC8D17941E6244D701A062CE44D0877273873944433F
+IV=551AF68D50D23408F47214C0B18E6C8A
+PT=561072AC144854C1E02DAD6879D19739
+CT=ADFF035C89E040A4C3CCE190D6CB7283
+
+I=355
+KEY=D1CA1B08A51B5086E92802FCEB2E047444BE9217EF8F31BC
+IV=ADFF035C89E040A4C3CCE190D6CB7283
+PT=827ADE7D0F329D9A1BD8B785B28F4EE4
+CT=425F5596D3FD37243EE59D6FC1F5ADCC
+
+I=356
+KEY=54EC325FE63AA470AB77576A38D333507A5B0F782E7A9C70
+IV=425F5596D3FD37243EE59D6FC1F5ADCC
+PT=4AAF21E64F8DBDB0852629574321F4F6
+CT=D85520FE860C9F320CDC8192A900F499
+
+I=357
+KEY=5B4612BC35BFC12473227794BEDFAC6276878EEA877A68E9
+IV=D85520FE860C9F320CDC8192A900F499
+PT=0D046A402A1860C70FAA20E3D3856554
+CT=11C20F3ACED79B37402B2F04886D4CC7
+
+I=358
+KEY=5052384CE705101562E078AE7008375536ACA1EE0F17242E
+IV=11C20F3ACED79B37402B2F04886D4CC7
+PT=7546E6521BBBFAFE0B142AF0D2BAD131
+CT=BCDA339266E3AFB779AF17CE34218BE5
+
+I=359
+KEY=F7ECFB2AA4FC6DE2DE3A4B3C16EB98E24F03B6203B36AFCB
+IV=BCDA339266E3AFB779AF17CE34218BE5
+PT=85DF7958789E9090A7BEC36643F97DF7
+CT=300D46EAB6466314BB00DBC869C77F4E
+
+I=360
+KEY=1E27229506EC9555EE370DD6A0ADFBF6F4036DE852F1D085
+IV=300D46EAB6466314BB00DBC869C77F4E
+PT=C6CED700614467A0E9CBD9BFA210F8B7
+CT=51735C075A14FE95D4A02F527A9474D3
+
+I=361
+KEY=857F653E1E811CABBF4451D1FAB9056320A342BA2865A456
+IV=51735C075A14FE95D4A02F527A9474D3
+PT=53D436401D6811B19B5847AB186D89FE
+CT=827017531E56980C4357549D0E70114F
+
+I=362
+KEY=1BCE612F3A5262223D344682E4EF9D6F63F416272615B519
+IV=827017531E56980C4357549D0E70114F
+PT=4C1BD17FFD65AB2C9EB1041124D37E89
+CT=751BCA9516123906561FB8AF2208CEE1
+
+I=363
+KEY=7C7034EC27524FC3482F8C17F2FDA46935EBAE88041D7BF8
+IV=751BCA9516123906561FB8AF2208CEE1
+PT=7C23D6E77039F35267BE55C31D002DE1
+CT=82CAFBBE859FA80B2A8E58CEC074B01A
+
+I=364
+KEY=7F31EEE0447BB53CCAE577A977620C621F65F646C469CBE2
+IV=82CAFBBE859FA80B2A8E58CEC074B01A
+PT=B91FF7759419BBB10341DA0C6329FAFF
+CT=B7614376C9BAFC92E17E39D2BDF1F2EF
+
+I=365
+KEY=E705144BCE40FC987D8434DFBED8F0F0FE1BCF947998390D
+IV=B7614376C9BAFC92E17E39D2BDF1F2EF
+PT=72B3472217AC80979834FAAB8A3B49A4
+CT=A63BA38FDDFE99D28BA447871BBA6211
+
+I=366
+KEY=15C813D2D9AD1494DBBF97506326692275BF881362225B1C
+IV=A63BA38FDDFE99D28BA447871BBA6211
+PT=349F8E5FAE004B51F2CD079917EDE80C
+CT=C87E448872E619419766CB46787F2581
+
+I=367
+KEY=B12B790C217821DA13C1D3D811C07063E2D943551A5D7E9D
+IV=C87E448872E619419766CB46787F2581
+PT=EC474C794E3C8322A4E36ADEF8D5354E
+CT=73DD478F7F41857F7A5DE7EDF3F1AF7B
+
+I=368
+KEY=1CFA6A54B3E572DC601C94576E81F51C9884A4B8E9ACD1E6
+IV=73DD478F7F41857F7A5DE7EDF3F1AF7B
+PT=48F8361EF11F94C1ADD11358929D5306
+CT=8B85DE2CBE5C96CBDFE16064079754D9
+
+I=369
+KEY=6718C10E683F4D73EB994A7BD0DD63D74765C4DCEE3B853F
+IV=8B85DE2CBE5C96CBDFE16064079754D9
+PT=59BFDA108542EDDB7BE2AB5ADBDA3FAF
+CT=56FF53384CED780F604F86EC0CE26B26
+
+I=370
+KEY=704ED4F1E96776A2BD6619439C301BD8272A4230E2D9EE19
+IV=56FF53384CED780F604F86EC0CE26B26
+PT=468FDBDB8BC26B5A175615FF81583BD1
+CT=7B0C2436262A262C5FAFC3A9B786DB00
+
+I=371
+KEY=67AFB86317B622B2C66A3D75BA1A3DF478858199555F3519
+IV=7B0C2436262A262C5FAFC3A9B786DB00
+PT=768BE978E5E8CA6E17E16C92FED15410
+CT=D32206D5D1521AB667516391810F5719
+
+I=372
+KEY=0BF4E0C32EA3D69615483BA06B4827421FD4E208D4506200
+IV=D32206D5D1521AB667516391810F5719
+PT=1943C5D93D10A0E36C5B58A03915F424
+CT=6BCE2BEC0D5A0DA9051AF2B34A873694
+
+I=373
+KEY=924D1C527572A2EF7E86104C66122AEB1ACE10BB9ED75494
+IV=6BCE2BEC0D5A0DA9051AF2B34A873694
+PT=E3020D099D0841C299B9FC915BD17479
+CT=3BEBA6BA0762BF5FAA4D26B70071B4A9
+
+I=374
+KEY=CFA41DB53F2F8766456DB6F6617095B4B083360C9EA6E03D
+IV=3BEBA6BA0762BF5FAA4D26B70071B4A9
+PT=31F7316F0D1012CD5DE901E74A5D2589
+CT=C4253CED7F88DF97596B08A15BAEF533
+
+I=375
+KEY=E2B9D43008C1537281488A1B1EF84A23E9E83EADC508150E
+IV=C4253CED7F88DF97596B08A15BAEF533
+PT=00365D6755A898E62D1DC98537EED414
+CT=2D4EB6BA84D1C0C978EA20C1693BB75C
+
+I=376
+KEY=43EA75DFD5B35CCBAC063CA19A298AEA91021E6CAC33A252
+IV=2D4EB6BA84D1C0C978EA20C1693BB75C
+PT=599279C68B67A988A153A1EFDD720FB9
+CT=03698CC5E133AD8855B847C124FD2778
+
+I=377
+KEY=8F2C76FCFBD8060DAF6FB0647B1A2762C4BA59AD88CE852A
+IV=03698CC5E133AD8855B847C124FD2778
+PT=47EFAF7E090B94B5CCC603232E6B5AC6
+CT=8D44C11C25ADE5631E05FAAECCA70AF7
+
+I=378
+KEY=E02084775A2E1A4E222B71785EB7C201DABFA30344698FDD
+IV=8D44C11C25ADE5631E05FAAECCA70AF7
+PT=394EC624EBC0D79E6F0CF28BA1F61C43
+CT=5EB407847213D5E950C66787B140BC35
+
+I=379
+KEY=D8208A70940589F47C9F76FC2CA417E88A79C484F52933E8
+IV=5EB407847213D5E950C66787B140BC35
+PT=F28816D227AC09F538000E07CE2B93BA
+CT=2D4FBD74A027526BADC8C2A433963C22
+
+I=380
+KEY=858193C76AFE48D951D0CB888C83458327B10620C6BF0FCA
+IV=2D4FBD74A027526BADC8C2A433963C22
+PT=FBAA6C644F8E08885DA119B7FEFBC12D
+CT=FA2DAE761EBBFDE4B77CBCD2381165DB
+
+I=381
+KEY=DA9A9F800056FC6EABFD65FE9238B86790CDBAF2FEAE6A11
+IV=FA2DAE761EBBFDE4B77CBCD2381165DB
+PT=F66A574C26D0F15C5F1B0C476AA8B4B7
+CT=DB18F5B16BF19C2BCCA36091A302BF38
+
+I=382
+KEY=BD2AB07F036032AB70E5904FF9C9244C5C6EDA635DACD529
+IV=DB18F5B16BF19C2BCCA36091A302BF38
+PT=04B0C1A19C6D38B467B02FFF0336CEC5
+CT=D3F01581B21DF4E470EE595CAB44912C
+
+I=383
+KEY=7EF57F6BDE41D79CA31585CE4BD4D0A82C80833FF6E84405
+IV=D3F01581B21DF4E470EE595CAB44912C
+PT=83BF32E0F3F3CEE7C3DFCF14DD21E537
+CT=10C69B9A04E0851B63D85D025BBACA29
+
+I=384
+KEY=22057A9912BB6B76B3D31E544F3455B34F58DE3DAD528E2C
+IV=10C69B9A04E0851B63D85D025BBACA29
+PT=150ACC96322893CC5CF005F2CCFABCEA
+CT=2743FE5769DDA5D591318E200AF672D0
+
+I=385
+KEY=742A2117B51176E69490E00326E9F066DE69501DA7A4FCFC
+IV=2743FE5769DDA5D591318E200AF672D0
+PT=93246C1A26F66DAF562F5B8EA7AA1D90
+CT=5CA8FC8DB4A20B2CA8AB86B1B40DA1A1
+
+I=386
+KEY=3C09F8C3B20BE749C8381C8E924BFB4A76C2D6AC13A95D5D
+IV=5CA8FC8DB4A20B2CA8AB86B1B40DA1A1
+PT=D91806E0F3451C374823D9D4071A91AF
+CT=25701E4C6685C98333566EB75498AEB7
+
+I=387
+KEY=DD0386F2D0D1E8FFED4802C2F4CE32C94594B81B4731F3EA
+IV=25701E4C6685C98333566EB75498AEB7
+PT=701A5D7027053688E10A7E3162DA0FB6
+CT=E4A5889FC49B62F767F61F1D2810801A
+
+I=388
+KEY=BB9A1FA7287B0D3D09ED8A5D3055503E2262A7066F2173F0
+IV=E4A5889FC49B62F767F61F1D2810801A
+PT=A110B0A38255279B66999955F8AAE5C2
+CT=F1A9BDA2045F3EAE2AB9CEE2AD352270
+
+I=389
+KEY=21B561DC3C44B5A5F84437FF340A6E9008DB69E4C2145180
+IV=F1A9BDA2045F3EAE2AB9CEE2AD352270
+PT=1562CF8420963B479A2F7E7B143FB898
+CT=E7E2BA657D3482A4825D643B8C01B52E
+
+I=390
+KEY=60A0FA1F5FA435401FA68D9A493EEC348A860DDF4E15E4AE
+IV=E7E2BA657D3482A4825D643B8C01B52E
+PT=930490633BC4EDC941159BC363E080E5
+CT=2FDBCD145EB8620594834B0D63BBD137
+
+I=391
+KEY=7DD1686F811E4017307D408E17868E311E0546D22DAE3599
+IV=2FDBCD145EB8620594834B0D63BBD137
+PT=4BB1C43F4ABC51CD1D719270DEBA7557
+CT=B703658AD9FFCDE05E2C7E252990402E
+
+I=392
+KEY=18203DC5AAA632F5877E2504CE7943D1402938F7043E75B7
+IV=B703658AD9FFCDE05E2C7E252990402E
+PT=47931942F275F05E65F155AA2BB872E2
+CT=5B79CB7FA90D3BB5A979A4588D4DE434
+
+I=393
+KEY=9F6D532CBAF42FCDDC07EE7B67747864E9509CAF89739183
+IV=5B79CB7FA90D3BB5A979A4588D4DE434
+PT=E3A36DF4EB896B4D874D6EE910521D38
+CT=61BF460521E67B3CAC638F3298EF9310
+
+I=394
+KEY=ED4F97BC99036E83BDB8A87E469203584533139D119C0293
+IV=61BF460521E67B3CAC638F3298EF9310
+PT=55EABDF72CCB5D737222C49023F7414E
+CT=8A27D87B53B2FB8BBAFF7851AF1D51F2
+
+I=395
+KEY=E1B9A7291D885F8E379F70051520F8D3FFCC6BCCBE815361
+IV=8A27D87B53B2FB8BBAFF7851AF1D51F2
+PT=D30271EA236E948F0CF63095848B310D
+CT=15075FDCBD2D6FC15B9A3841A2D58C34
+
+I=396
+KEY=976B101EE3E10E0822982FD9A80D9712A456538D1C54DF55
+IV=15075FDCBD2D6FC15B9A3841A2D58C34
+PT=879EED3434159D8076D2B737FE695186
+CT=6896582462983FAAE443078F9768B339
+
+I=397
+KEY=A7A3277BF5F605FC4A0E77FDCA95A8B8401554028B3C6C6C
+IV=6896582462983FAAE443078F9768B339
+PT=89DDABE96D1069ED30C8376516170BF4
+CT=96FE6B921416B667AA5B34D2D2E25747
+
+I=398
+KEY=DD57026B1D4E32A8DCF01C6FDE831EDFEA4E60D059DE3B2B
+IV=96FE6B921416B667AA5B34D2D2E25747
+PT=8144C8BB09FC72827AF42510E8B83754
+CT=EEDC3677AB7B57829F6D733F8090DA8A
+
+I=399
+KEY=B4D1BDF297DC0574322C2A1875F8495D752313EFD94EE1A1
+IV=EEDC3677AB7B57829F6D733F8090DA8A
+PT=510F7A55799B39786986BF998A9237DC
+CT=BA50C94440C04A8C0899D42658E25437
+
+==========
+
+KEYSIZE=256
+
+I=0
+KEY=0000000000000000000000000000000000000000000000000000000000000000
+IV=00000000000000000000000000000000
+PT=00000000000000000000000000000000
+CT=FE3C53653E2F45B56FCD88B2CC898FF0
+
+I=1
+KEY=B2493DE29713367D9FAA93469F8EF596FE3C53653E2F45B56FCD88B2CC898FF0
+IV=FE3C53653E2F45B56FCD88B2CC898FF0
+PT=B2493DE29713367D9FAA93469F8EF596
+CT=7CE2ABAF8BEF23C4816DC8CE842048A7
+
+I=2
+KEY=33A36646FE56F70DC0C51A3117E639F182DEF8CAB5C06671EEA0407C48A9C757
+IV=7CE2ABAF8BEF23C4816DC8CE842048A7
+PT=81EA5BA46945C1705F6F89778868CC67
+CT=50CD14A12C6852D39654C816BFAF9AC2
+
+I=3
+KEY=0D6A3DACE75B104CA8A303A32670BF3AD213EC6B99A834A278F4886AF7065D95
+IV=50CD14A12C6852D39654C816BFAF9AC2
+PT=3EC95BEA190DE74168661992319686CB
+CT=3F411DAD0E339FE281637133BF46BD13
+
+I=4
+KEY=A53BE0709BF686A7DB7C3848D81AB66BED52F1C6979BAB40F997F9594840E086
+IV=3F411DAD0E339FE281637133BF46BD13
+PT=A851DDDC7CAD96EB73DF3BEBFE6A0951
+CT=5BA2C7663A4061719A7CCC2AF2A3EE8A
+
+I=5
+KEY=ECF3490CB7717A5236A3A94811BEBF13B6F036A0ADDBCA3163EB3573BAE30E0C
+IV=5BA2C7663A4061719A7CCC2AF2A3EE8A
+PT=49C8A97C2C87FCF5EDDF9100C9A40978
+CT=F105031CE7E5111317745C64F4F6D150
+
+I=6
+KEY=CE8A062A2A9F9EDE2EFB43A8602BB47847F535BC4A3EDB22749F69174E15DF5C
+IV=F105031CE7E5111317745C64F4F6D150
+PT=22794F269DEEE48C1858EAE071950B6B
+CT=C8F030398A873550A34386D9A153D833
+
+I=7
+KEY=2BE39545B8FC27444178BF0004C7F1048F050585C0B9EE72D7DCEFCEEF46076F
+IV=C8F030398A873550A34386D9A153D833
+PT=E569936F9263B99A6F83FCA864EC457C
+CT=519CF42C0BBFCBD79679089BC5E963B4
+
+I=8
+KEY=80E9C0F78F99E309935C0A69B961D787DE99F1A9CB0625A541A5E7552AAF64DB
+IV=519CF42C0BBFCBD79679089BC5E963B4
+PT=AB0A55B23765C44DD224B569BDA62683
+CT=64AC8FEA3B83584E9B7379B48F88B7A4
+
+I=9
+KEY=48DDBDA704BA7702960820A0D2CA485CBA357E43F0857DEBDAD69EE1A527D37F
+IV=64AC8FEA3B83584E9B7379B48F88B7A4
+PT=C8347D508B23940B05542AC96BAB9FDB
+CT=2B1F53F35A308673E9B1E004C32B2080
+
+I=10
+KEY=D26C4C6BE601D63BDDE6F1A49B5124CB912A2DB0AAB5FB9833677EE5660CF3FF
+IV=2B1F53F35A308673E9B1E004C32B2080
+PT=9AB1F1CCE2BBA1394BEED104499B6C97
+CT=0DAE66B5741FE38E544D9EC4E90ABDAF
+
+I=11
+KEY=D241355DB8FC5F23D0D207F72E290F189C844B05DEAA1816672AE0218F064E50
+IV=0DAE66B5741FE38E544D9EC4E90ABDAF
+PT=002D79365EFD89180D34F653B5782BD3
+CT=D00122636CC0D9D62E614EAF0963C448
+
+I=12
+KEY=1BC3268A0B674A05B2FC6E18460231564C856966B26AC1C0494BAE8E86658A18
+IV=D00122636CC0D9D62E614EAF0963C448
+PT=C98213D7B39B1526622E69EF682B3E4E
+CT=30EF014D1766651C524B3CC82F0140C6
+
+I=13
+KEY=50BE5951A5C2403C52425897C442A8457C6A682BA50CA4DC1B009246A964CADE
+IV=30EF014D1766651C524B3CC82F0140C6
+PT=4B7D7FDBAEA50A39E0BE368F82409913
+CT=BAD488702B447FABEC2074E1DD37E631
+
+I=14
+KEY=C007EE52430FF98EDD206C94ED349DE6C6BEE05B8E48DB77F720E6A774532CEF
+IV=BAD488702B447FABEC2074E1DD37E631
+PT=90B9B703E6CDB9B28F623403297635A3
+CT=EC3862EB60E7D8D0827645BD690F71B8
+
+I=15
+KEY=AE37C1DBEBF9B269E8D10CC4F046F9FC2A8682B0EEAF03A77556A31A1D5C5D57
+IV=EC3862EB60E7D8D0827645BD690F71B8
+PT=6E302F89A8F64BE735F160501D72641A
+CT=6073D1F25F3697C1E07384C67D71D8AE
+
+I=16
+KEY=86E8B9050AB24200E3757B67F08761534AF55342B1999466952527DC602D85F9
+IV=6073D1F25F3697C1E07384C67D71D8AE
+PT=28DF78DEE14BF0690BA477A300C198AF
+CT=90EF55AB8837792F82CF0F002E36F8DB
+
+I=17
+KEY=DE93EA10BB6DC2B0A6D3919561CE5AE4DA1A06E939AEED4917EA28DC4E1B7D22
+IV=90EF55AB8837792F82CF0F002E36F8DB
+PT=587B5315B1DF80B045A6EAF291493BB7
+CT=063783CB1A2137732D10CA6233C5CE93
+
+I=18
+KEY=3D147E3727A1FEB2C6F36AB9DF772E97DC2D8522238FDA3A3AFAE2BE7DDEB3B1
+IV=063783CB1A2137732D10CA6233C5CE93
+PT=E38794279CCC3C026020FB2CBEB97473
+CT=79C5CEEE64BFD33948D2E08EBE25B7E9
+
+I=19
+KEY=34586C52923969647663A0D69436D7D1A5E84BCC4730090372280230C3FB0458
+IV=79C5CEEE64BFD33948D2E08EBE25B7E9
+PT=094C1265B59897D6B090CA6F4B41F946
+CT=87DFB65D575F56670DB739C988FD7DE5
+
+I=20
+KEY=53724BF79612A7F0237927604619DD592237FD91106F5F647F9F3BF94B0679BD
+IV=87DFB65D575F56670DB739C988FD7DE5
+PT=672A27A5042BCE94551A87B6D22F0A88
+CT=643F46BC77A5FE2434753B9C38142583
+
+I=21
+KEY=8FBC30746F29985FFFA43C8BD3C4FC664608BB2D67CAA1404BEA006573125C3E
+IV=643F46BC77A5FE2434753B9C38142583
+PT=DCCE7B83F93B3FAFDCDD1BEB95DD213F
+CT=FD774BD6874EA7C0D790A5015440B664
+
+I=22
+KEY=9A61A910701A4A42873549F78D3D9FD1BB7FF0FBE08406809C7AA5642752EA5A
+IV=FD774BD6874EA7C0D790A5015440B664
+PT=15DD99641F33D21D7891757C5EF963B7
+CT=BFCEF4403428F5C96C24C249962371D4
+
+I=23
+KEY=8D98738F6DF30113AF69A7A61C1582EE04B104BBD4ACF349F05E672DB1719B8E
+IV=BFCEF4403428F5C96C24C249962371D4
+PT=17F9DA9F1DE94B51285CEE5191281D3F
+CT=CC79F35C41F0E6C0EB03472B1D13029E
+
+I=24
+KEY=976C27F1A15FF6780043636FC4777090C8C8F7E7955C15891B5D2006AC629910
+IV=CC79F35C41F0E6C0EB03472B1D13029E
+PT=1AF4547ECCACF76BAF2AC4C9D862F27E
+CT=0629B80F94FBC2C1984985B9F3B85BDD
+
+I=25
+KEY=E8934C533DED166F58D65C9E60A906A5CEE14FE801A7D7488314A5BF5FDAC2CD
+IV=0629B80F94FBC2C1984985B9F3B85BDD
+PT=7FFF6BA29CB2E01758953FF1A4DE7635
+CT=F2A70F4ED1A836696841D523F2650B55
+
+I=26
+KEY=8116688C16D2C26D162C4D813FB267103C4640A6D00FE121EB55709CADBFC998
+IV=F2A70F4ED1A836696841D523F2650B55
+PT=698524DF2B3FD4024EFA111F5F1B61B5
+CT=A9B5565EB9B5D5DAC52BE0F449FBE11A
+
+I=27
+KEY=5A7062E77C6D20563AFD0BFDAAE04BE995F316F869BA34FB2E7E9068E4442882
+IV=A9B5565EB9B5D5DAC52BE0F449FBE11A
+PT=DB660A6B6ABFE23B2CD1467C95522CF9
+CT=E47F675379D4CE3DDABA0F906BE014B2
+
+I=28
+KEY=4DDC0A5938F4A3DC1AF8D3AFD3DF6198718C71AB106EFAC6F4C49FF88FA43C30
+IV=E47F675379D4CE3DDABA0F906BE014B2
+PT=17AC68BE4499838A2005D852793F2A71
+CT=7B95AB0E030C70B7940ECDAEFCA570A5
+
+I=29
+KEY=E287EFC66626600AF3453F68BE53E5250A19DAA513628A7160CA525673014C95
+IV=7B95AB0E030C70B7940ECDAEFCA570A5
+PT=AF5BE59F5ED2C3D6E9BDECC76D8C84BD
+CT=E854E5DE0C42D57B869C29FC8D5AFFF3
+
+I=30
+KEY=7F3415A538F60B24A58447E1D38805B3E24D3F7B1F205F0AE6567BAAFE5BB366
+IV=E854E5DE0C42D57B869C29FC8D5AFFF3
+PT=9DB3FA635ED06B2E56C178896DDBE096
+CT=4E55EDEDC35CDEAB3BFB2B5D39871625
+
+I=31
+KEY=59E5F5ECC5693DA07046636094970E8CAC18D296DC7C81A1DDAD50F7C7DCA543
+IV=4E55EDEDC35CDEAB3BFB2B5D39871625
+PT=26D1E049FD9F3684D5C22481471F0B3F
+CT=3355C2CC762E58FA941E0004209CA710
+
+I=32
+KEY=0B62CF7EA869036A529E9D184574CD609F4D105AAA52D95B49B350F3E7400253
+IV=3355C2CC762E58FA941E0004209CA710
+PT=52873A926D003ECA22D8FE78D1E3C3EC
+CT=9B86680D69D38870268D42E78EDA2B50
+
+I=33
+KEY=CEDC9CCC4DC42CB055EDC50597EE24DF04CB7857C381512B6F3E1214699A2903
+IV=9B86680D69D38870268D42E78EDA2B50
+PT=C5BE53B2E5AD2FDA0773581DD29AE9BF
+CT=05DD4896F08EEAA6A53FA7BCF183F538
+
+I=34
+KEY=CA30B422016C86247D75B618D19247AC011630C1330FBB8DCA01B5A89819DC3B
+IV=05DD4896F08EEAA6A53FA7BCF183F538
+PT=04EC28EE4CA8AA942898731D467C6373
+CT=F81E56F4390D65C7959348A6FBD8A94E
+
+I=35
+KEY=B7096A2EC0259DA21ACA6DBE637A9F15F90866350A02DE4A5F92FD0E63C17575
+IV=F81E56F4390D65C7959348A6FBD8A94E
+PT=7D39DE0CC1491B8667BFDBA6B2E8D8B9
+CT=4364CA2D90FA256084DF8E2FCDC62AB3
+
+I=36
+KEY=436C0894D4436149EE685F0061BDF3AEBA6CAC189AF8FB2ADB4D7321AE075FC6
+IV=4364CA2D90FA256084DF8E2FCDC62AB3
+PT=F46562BA1466FCEBF4A232BE02C76CBB
+CT=0991DE19A5ABE5F7E8AE24120789B9AB
+
+I=37
+KEY=44E1636AFF962EC4F1C446A89B9393C6B3FD72013F531EDD33E35733A98EE66D
+IV=0991DE19A5ABE5F7E8AE24120789B9AB
+PT=078D6BFE2BD54F8D1FAC19A8FA2E6068
+CT=0F4EF4FA608671AC5F71063CF6C1EBDE
+
+I=38
+KEY=44289918A9E99F859FC2F604FE38B86EBCB386FB5FD56F716C92510F5F4F0DB3
+IV=0F4EF4FA608671AC5F71063CF6C1EBDE
+PT=00C9FA72567FB1416E06B0AC65AB2BA8
+CT=2D6A2A1CC9D208C16236BBC9451EC5E1
+
+I=39
+KEY=BE5907C77B0939D20575F27427A2C3FE91D9ACE7960767B00EA4EAC61A51C852
+IV=2D6A2A1CC9D208C16236BBC9451EC5E1
+PT=FA719EDFD2E0A6579AB70470D99A7B90
+CT=237A8DFBA42708BBF7E540766F2059F1
+
+I=40
+KEY=CD97125720F2002207AC44C456CDDF0DB2A3211C32206F0BF941AAB0757191A3
+IV=237A8DFBA42708BBF7E540766F2059F1
+PT=73CE15905BFB39F002D9B6B0716F1CF3
+CT=2D1AB5CF3E9C27ADA9FB45F15007A7BB
+
+I=41
+KEY=123F64F2A28C80C2F6E000F69C8E5A639FB994D30CBC48A650BAEF4125763618
+IV=2D1AB5CF3E9C27ADA9FB45F15007A7BB
+PT=DFA876A5827E80E0F14C4432CA43856E
+CT=7039C9AF1E10FE99A91483EA578AE6DD
+
+I=42
+KEY=6CD69C4F5AD7CB5E9E4574F6A48FDB28EF805D7C12ACB63FF9AE6CAB72FCD0C5
+IV=7039C9AF1E10FE99A91483EA578AE6DD
+PT=7EE9F8BDF85B4B9C68A574003801814B
+CT=116DD8566366A19EEAF2F3E744B3EF9C
+
+I=43
+KEY=C73969C7D6D057003E2E215D94978792FEED852A71CA17A1135C9F4C364F3F59
+IV=116DD8566366A19EEAF2F3E744B3EF9C
+PT=ABEFF5888C079C5EA06B55AB30185CBA
+CT=648A801EF27E77D964BB751A32B8CFE8
+
+I=44
+KEY=E0960DD6E807F3D0B5DF057D0D1E6DCC9A67053483B4607877E7EA5604F7F0B1
+IV=648A801EF27E77D964BB751A32B8CFE8
+PT=27AF64113ED7A4D08BF124209989EA5E
+CT=D18AE728717C535049868FA6F1B4294E
+
+I=45
+KEY=466AE043435C6CCA67FF1C5D4B4175DA4BEDE21CF2C833283E6165F0F543D9FF
+IV=D18AE728717C535049868FA6F1B4294E
+PT=A6FCED95AB5B9F1AD2201920465F1816
+CT=169B55360728DA8F582C488F2569411F
+
+I=46
+KEY=27E1BC4931601D667CD807454D58B2BB5D76B72AF5E0E9A7664D2D7FD02A98E0
+IV=169B55360728DA8F582C488F2569411F
+PT=618B5C0A723C71AC1B271B180619C761
+CT=67DADCF7C31CA394F46F18AB1AEA022E
+
+I=47
+KEY=2D4EB1F3A709F0A4CA5E2CD47F8F10123AAC6BDD36FC4A33922235D4CAC09ACE
+IV=67DADCF7C31CA394F46F18AB1AEA022E
+PT=0AAF0DBA9669EDC2B6862B9132D7A2A9
+CT=A5D49BDF099335166BBFDCBE29C90B80
+
+I=48
+KEY=2A90CE470EB8C9400B056307D53452BE9F78F0023F6F7F25F99DE96AE309914E
+IV=A5D49BDF099335166BBFDCBE29C90B80
+PT=07DE7FB4A9B139E4C15B4FD3AABB42AC
+CT=5AFC238F19E369E77278593C6E20A946
+
+I=49
+KEY=90B696E9A0792BFF7BF21BE373731CB5C584D38D268C16C28BE5B0568D293808
+IV=5AFC238F19E369E77278593C6E20A946
+PT=BA2658AEAEC1E2BF70F778E4A6474E0B
+CT=2861A363922099D0F0B2A5AD2A5F421E
+
+I=50
+KEY=4FE5C563B7DB98C6B9CCA52F313FBAFCEDE570EEB4AC8F127B5715FBA7767A16
+IV=2861A363922099D0F0B2A5AD2A5F421E
+PT=DF53538A17A2B339C23EBECC424CA649
+CT=D76E51B6EA5F74D0116C4D16EDD0DFAC
+
+I=51
+KEY=EBF784D98E40372429819EE23BE85B723A8B21585EF3FBC26A3B58ED4AA6A5BA
+IV=D76E51B6EA5F74D0116C4D16EDD0DFAC
+PT=A41241BA399BAFE2904D3BCD0AD7E18E
+CT=6214F5E50EC99F40B86951CE395C8315
+
+I=52
+KEY=C01A5093C6A29CEED72D14D903BD17E8589FD4BD503A6482D252092373FA26AF
+IV=6214F5E50EC99F40B86951CE395C8315
+PT=2BEDD44A48E2ABCAFEAC8A3B38554C9A
+CT=6CFC2188E40E806BBE277988B924627E
+
+I=53
+KEY=A8C3A10380B6D4D1CEFABF57F3C695193463F535B434E4E96C7570ABCADE44D1
+IV=6CFC2188E40E806BBE277988B924627E
+PT=68D9F1904614483F19D7AB8EF07B82F1
+CT=B98E851902AEC129FD1607DECA9E0669
+
+I=54
+KEY=B828711ABA1D06408099944287112DE58DED702CB69A25C091637775004042B8
+IV=B98E851902AEC129FD1607DECA9E0669
+PT=10EBD0193AABD2914E632B1574D7B8FC
+CT=DBDA9DB56E6FF915D67D7DEE541DD6A3
+
+I=55
+KEY=3B0E9FE343D665ABB3706243EF023C765637ED99D8F5DCD5471E0A9B545D941B
+IV=DBDA9DB56E6FF915D67D7DEE541DD6A3
+PT=8326EEF9F9CB63EB33E9F60168131193
+CT=399802CE3FF3878A73C7D85E19FDD54B
+
+I=56
+KEY=9270D72D972B46C8E630FBD1AA67FBED6FAFEF57E7065B5F34D9D2C54DA04150
+IV=399802CE3FF3878A73C7D85E19FDD54B
+PT=A97E48CED4FD2363554099924565C79B
+CT=40FABA067414961FD964EC91196943E3
+
+I=57
+KEY=017211AC512541BFBDD0292385AA20862F5555519312CD40EDBD3E5454C902B3
+IV=40FABA067414961FD964EC91196943E3
+PT=9302C681C60E07775BE0D2F22FCDDB6B
+CT=6BF1125E581341510FD02B9450886B17
+
+I=58
+KEY=AC2652A877F924710178641D20B239B944A4470FCB018C11E26D15C0044169A4
+IV=6BF1125E581341510FD02B9450886B17
+PT=AD54430426DC65CEBCA84D3EA518193F
+CT=74871D2EF6D1F29181B0A2530885EEC8
+
+I=59
+KEY=0BF012A9F0CB194C1F00893D4803E10130235A213DD07E8063DDB7930CC4876C
+IV=74871D2EF6D1F29181B0A2530885EEC8
+PT=A7D6400187323D3D1E78ED2068B1D8B8
+CT=2A2DC9F5CB47C94D430ECAAAB1D0811E
+
+I=60
+KEY=8D22EEEA013E327509E84630166331DB1A0E93D4F697B7CD20D37D39BD140672
+IV=2A2DC9F5CB47C94D430ECAAAB1D0811E
+PT=86D2FC43F1F52B3916E8CF0D5E60D0DA
+CT=BC318E32957CE6577CD06E2D3166CD1F
+
+I=61
+KEY=1C4909D11840D978FD7232D0FBC0E6A3A63F1DE663EB519A5C0313148C72CB6D
+IV=BC318E32957CE6577CD06E2D3166CD1F
+PT=916BE73B197EEB0DF49A74E0EDA3D778
+CT=E9858DBB1B5145ABB598ADE882346DDB
+
+I=62
+KEY=DD2ED3C6FCE0034F19259D57A35B60CF4FBA905D78BA1431E99BBEFC0E46A6B6
+IV=E9858DBB1B5145ABB598ADE882346DDB
+PT=C167DA17E4A0DA37E457AF87589B866C
+CT=1E04B15BBF727BEAC33C0C26141636DD
+
+I=63
+KEY=81C434CDF7EABAA49252EC86DFE15FBA51BE2106C7C86FDB2AA7B2DA1A50906B
+IV=1E04B15BBF727BEAC33C0C26141636DD
+PT=5CEAE70B0B0AB9EB8B7771D17CBA3F75
+CT=EB21AED731D594017F5729262A1E23B4
+
+I=64
+KEY=AEF6BF8323CAE4C2270CC5E51B0A3BFFBA9F8FD1F61DFBDA55F09BFC304EB3DF
+IV=EB21AED731D594017F5729262A1E23B4
+PT=2F328B4ED4205E66B55E2963C4EB6445
+CT=EB73CFADA0ACB98B37091CB81489CC7C
+
+I=65
+KEY=BC3BD548867FA82FF80EF67B38016A1E51EC407C56B1425162F9874424C77FA3
+IV=EB73CFADA0ACB98B37091CB81489CC7C
+PT=12CD6ACBA5B54CEDDF02339E230B51E1
+CT=1FEEF226D6759E8813B98A5D43B2F22A
+
+I=66
+KEY=E1F5760C694DBE5688A0241B5517B4B14E02B25A80C4DCD971400D1967758D89
+IV=1FEEF226D6759E8813B98A5D43B2F22A
+PT=5DCEA344EF32167970AED2606D16DEAF
+CT=9C591D087F0F45C8AE3DEC9C455FE200
+
+I=67
+KEY=ABF2D79C472D0159FA9AE646D0C0FC9CD25BAF52FFCB9911DF7DE185222A6F89
+IV=9C591D087F0F45C8AE3DEC9C455FE200
+PT=4A07A1902E60BF0F723AC25D85D7482D
+CT=62C4F4D7E4AC5ABC03BECA3CA56DA4FD
+
+I=68
+KEY=E58A351A4DD79A2ED6D386E11A8563F2B09F5B851B67C3ADDCC32BB98747CB74
+IV=62C4F4D7E4AC5ABC03BECA3CA56DA4FD
+PT=4E78E2860AFA9B772C4960A7CA459F6E
+CT=AD8557C0D04675CC312C7A106D5C8B83
+
+I=69
+KEY=BCF7BB1010AF5CEB05E06339689067E31D1A0C45CB21B661EDEF51A9EA1B40F7
+IV=AD8557C0D04675CC312C7A106D5C8B83
+PT=597D8E0A5D78C6C5D333E5D872150411
+CT=80159F4F5E0C2DC07D3CD3C52A1A8E6D
+
+I=70
+KEY=328BB8EB86055D2BB52A02E40BB5D2C39D0F930A952D9BA190D3826CC001CE9A
+IV=80159F4F5E0C2DC07D3CD3C52A1A8E6D
+PT=8E7C03FB96AA01C0B0CA61DD6325B520
+CT=F58A2EE5A5BDE8CA0A96F4F4B64BE737
+
+I=71
+KEY=F192AE51D926A2B68C38EA4E48A0590F6885BDEF3090736B9A457698764A29AD
+IV=F58A2EE5A5BDE8CA0A96F4F4B64BE737
+PT=C31916BA5F23FF9D3912E8AA43158BCC
+CT=B4C0DD55013AEFE12D94F31B861134CC
+
+I=72
+KEY=5EE48E38C2C805E2AACC89AD8682E552DC4560BA31AA9C8AB7D18583F05B1D61
+IV=B4C0DD55013AEFE12D94F31B861134CC
+PT=AF7620691BEEA75426F463E3CE22BC5D
+CT=FD8B06AEF9B3C25D11B950A6648276BB
+
+I=73
+KEY=F425B9BF4D114251736EE7FCDB430B6721CE6614C8195ED7A668D52594D96BDA
+IV=FD8B06AEF9B3C25D11B950A6648276BB
+PT=AAC137878FD947B3D9A26E515DC1EE35
+CT=31BE8DF4A8A749FBF11AB07D8479A10B
+
+I=74
+KEY=61A2D5337BCB827887F884AD98C67BEA1070EBE060BE172C5772655810A0CAD1
+IV=31BE8DF4A8A749FBF11AB07D8479A10B
+PT=95876C8C36DAC029F49663514385708D
+CT=E9A2EF0C882781788D50033B79FE181F
+
+I=75
+KEY=E930B2277AC4475FB0A94519F60DE552F9D204ECE8999654DA226663695ED2CE
+IV=E9A2EF0C882781788D50033B79FE181F
+PT=88926714010FC5273751C1B46ECB9EB8
+CT=17FFCD5A010709A2737570E038D63B27
+
+I=76
+KEY=B944CE978DF68F8FBFF0A5EA62AAC299EE2DC9B6E99E9FF6A95716835188E9E9
+IV=17FFCD5A010709A2737570E038D63B27
+PT=50747CB0F732C8D00F59E0F394A727CB
+CT=E12B89FA1B1DD3B29F02219FD3D7D3D2
+
+I=77
+KEY=0E2D7FCEB557462267BED2CCA8B48CD70F06404CF2834C443655371C825F3A3B
+IV=E12B89FA1B1DD3B29F02219FD3D7D3D2
+PT=B769B15938A1C9ADD84E7726CA1E4E4E
+CT=75AE99B6022B08E36FB88A6F4D7698BF
+
+I=78
+KEY=8046D73D60912221694B2AFE703EDB167AA8D9FAF0A844A759EDBD73CF29A284
+IV=75AE99B6022B08E36FB88A6F4D7698BF
+PT=8E6BA8F3D5C664030EF5F832D88A57C1
+CT=CF32DCE11FDB098A6435315342796064
+
+I=79
+KEY=20716D6975C32231968BF76725144CBAB59A051BEF734D2D3DD88C208D50C2E0
+IV=CF32DCE11FDB098A6435315342796064
+PT=A037BA5415520010FFC0DD99552A97AC
+CT=80F12B261317C66F21AC811230848468
+
+I=80
+KEY=AD5A2011E425AFFD57E7191336D37D25356B2E3DFC648B421C740D32BDD44688
+IV=80F12B261317C66F21AC811230848468
+PT=8D2B4D7891E68DCCC16CEE7413C7319F
+CT=F2C6B70C19A5748C6D2B5DE41544854F
+
+I=81
+KEY=49D4228508C789105CF457D10FA56048C7AD9931E5C1FFCE715F50D6A890C3C7
+IV=F2C6B70C19A5748C6D2B5DE41544854F
+PT=E48E0294ECE226ED0B134EC239761D6D
+CT=A31FB3535978DAA555DD617FAB27A97A
+
+I=82
+KEY=67CE710A3E778CB4A37D1F2274D4462D64B22A62BCB9256B248231A903B76ABD
+IV=A31FB3535978DAA555DD617FAB27A97A
+PT=2E1A538F36B005A4FF8948F37B712665
+CT=97336ECFAE89015E0B5A7D1C154C71BF
+
+I=83
+KEY=A87C517EF43CACC6D41EEB661DD1142CF38144AD123024352FD84CB516FB1B02
+IV=97336ECFAE89015E0B5A7D1C154C71BF
+PT=CFB22074CA4B20727763F44469055201
+CT=466CD227A6A9D5FC3C0579064530FCE0
+
+I=84
+KEY=D73F926A5B5DD8F5B82DE8F77E0E0697B5ED968AB499F1C913DD35B353CBE7E2
+IV=466CD227A6A9D5FC3C0579064530FCE0
+PT=7F43C314AF6174336C33039163DF12BB
+CT=4F444B4554E965A113DC0097AA8FAD7A
+
+I=85
+KEY=7A19BE1C42A13B85B754834E9808DF4BFAA9DDCFE070946800013524F9444A98
+IV=4F444B4554E965A113DC0097AA8FAD7A
+PT=AD262C7619FCE3700F796BB9E606D9DC
+CT=F7078ABE7617867274CBBEDA1082B987
+
+I=86
+KEY=D256675EDBF987B5CA86C21DE177C6A00DAE57719667121A74CA8BFEE9C6F31F
+IV=F7078ABE7617867274CBBEDA1082B987
+PT=A84FD9429958BC307DD24153797F19EB
+CT=676ACAB66B04597F1A33FF462BD5E0EE
+
+I=87
+KEY=C025616AB6F89BB1B90AA0E8F63FF1CC6AC49DC7FD634B656EF974B8C21313F1
+IV=676ACAB66B04597F1A33FF462BD5E0EE
+PT=127306346D011C04738C62F51748376C
+CT=BF66B8DD1E540A4FED759FDB9A44B439
+
+I=88
+KEY=2A437D44D93C25B3233FB168D63751A5D5A2251AE337412A838CEB635857A7C8
+IV=BF66B8DD1E540A4FED759FDB9A44B439
+PT=EA661C2E6FC4BE029A3511802008A069
+CT=EC8DBB5B3FE245180856B312D3052A87
+
+I=89
+KEY=838278123F0261D1F287C9FF94CA4A55392F9E41DCD504328BDA58718B528D4F
+IV=EC8DBB5B3FE245180856B312D3052A87
+PT=A9C10556E63E4462D1B8789742FD1BF0
+CT=02E1E60312BB371912C35E3EBC6EA755
+
+I=90
+KEY=64F3A47C8C7CFA9FF2AC88637C598E6A3BCE7842CE6E332B9919064F373C2A1A
+IV=02E1E60312BB371912C35E3EBC6EA755
+PT=E771DC6EB37E9B4E002B419CE893C43F
+CT=73D7499EBB38716D71CCB737CFFFA3FB
+
+I=91
+KEY=585ABE6B779F22400FC2AC3B55B39E91481931DC75564246E8D5B178F8C389E1
+IV=73D7499EBB38716D71CCB737CFFFA3FB
+PT=3CA91A17FBE3D8DFFD6E245829EA10FB
+CT=CEE7721855B7381D369ECC1C9337BB02
+
+I=92
+KEY=7BC1E883465CBBB9BA624FF99308259386FE43C420E17A5BDE4B7D646BF432E3
+IV=CEE7721855B7381D369ECC1C9337BB02
+PT=239B56E831C399F9B5A0E3C2C6BBBB02
+CT=B6F48D369383974D163E4F17FDFC59EF
+
+I=93
+KEY=70032AF50BB5E080D4AA7722CEDC7DA9300ACEF2B362ED16C875327396086B0C
+IV=B6F48D369383974D163E4F17FDFC59EF
+PT=0BC2C2764DE95B396EC838DB5DD4583A
+CT=E8372DA404126C63190626D95583629D
+
+I=94
+KEY=5C61B59BDA2FF51D4F4F740578466EA9D83DE356B7708175D17314AAC38B0991
+IV=E8372DA404126C63190626D95583629D
+PT=2C629F6ED19A159D9BE50327B69A1300
+CT=F717B53E51665D0854C895EA1D1D7E77
+
+I=95
+KEY=59A35E82B9C8D8FF25CFC5BAD979A9052F2A5668E616DC7D85BB8140DE9677E6
+IV=F717B53E51665D0854C895EA1D1D7E77
+PT=05C2EB1963E72DE26A80B1BFA13FC7AC
+CT=7D3EE90EEF7C16872F98296977AA9557
+
+I=96
+KEY=5BC419836F7C4F57957E13E39B2181455214BF66096ACAFAAA23A829A93CE2B1
+IV=7D3EE90EEF7C16872F98296977AA9557
+PT=02674701D6B497A8B0B1D65942582840
+CT=6DCD0C4B5633078FDEA9AE24781CB212
+
+I=97
+KEY=E6D2BB67584AA2FAAE1D0DAD8C9C60253FD9B32D5F59CD75748A060DD12050A3
+IV=6DCD0C4B5633078FDEA9AE24781CB212
+PT=BD16A2E43736EDAD3B631E4E17BDE160
+CT=6515251260A73AE868E992B6D49579C5
+
+I=98
+KEY=57637851C3C08A2923EBD2FEA27472DC5ACC963F3FFEF79D1C6394BB05B52966
+IV=6515251260A73AE868E992B6D49579C5
+PT=B1B1C3369B8A28D38DF6DF532EE812F9
+CT=1A40C2C15F03867E81F951B545396BB4
+
+I=99
+KEY=E08E94110F1E64554848AB1966299B7D408C54FE60FD71E39D9AC50E408C42D2
+IV=1A40C2C15F03867E81F951B545396BB4
+PT=B7EDEC40CCDEEE7C6BA379E7C45DE9A1
+CT=DD331F336D669EFD37106099EA51010D
+
+I=100
+KEY=17F2544156745EC108BF97DA806752C39DBF4BCD0D9BEF1EAA8AA597AADD43DF
+IV=DD331F336D669EFD37106099EA51010D
+PT=F77CC050596A3A9440F73CC3E64EC9BE
+CT=0EF37EC0B6071874FF68926D98A0EEAB
+
+I=101
+KEY=C97ABFF115E20A6C72A6206DB63EC0FD934C350DBB9CF76A55E237FA327DAD74
+IV=0EF37EC0B6071874FF68926D98A0EEAB
+PT=DE88EBB0439654AD7A19B7B73659923E
+CT=DA1DAEB42178A7657A40BD72A06CEDDC
+
+I=102
+KEY=77AB469FBC999BB2922D460413E2012049519BB99AE4500F2FA28A88921140A8
+IV=DA1DAEB42178A7657A40BD72A06CEDDC
+PT=BED1F96EA97B91DEE08B6669A5DCC1DD
+CT=E78523134FC8EAA77CC85E0EEC60FCD3
+
+I=103
+KEY=4F88FA6F4053B3A15094ED532C2F47DCAED4B8AAD52CBAA8536AD4867E71BC7B
+IV=E78523134FC8EAA77CC85E0EEC60FCD3
+PT=3823BCF0FCCA2813C2B9AB573FCD46FC
+CT=BC540D1838D7AD8E8B1C44B96684DD31
+
+I=104
+KEY=D178E105443700CFEE007AB3BAA71E4C1280B5B2EDFB1726D876903F18F5614A
+IV=BC540D1838D7AD8E8B1C44B96684DD31
+PT=9EF01B6A0464B36EBE9497E096885990
+CT=6C6B95A5D8F4E7F1A5864DDBFCDCEED8
+
+I=105
+KEY=8F6A589BA0ED1A67FE426368A7E523047EEB2017350FF0D77DF0DDE4E4298F92
+IV=6C6B95A5D8F4E7F1A5864DDBFCDCEED8
+PT=5E12B99EE4DA1AA8104219DB1D423D48
+CT=B58C92AE19B332621E7A4E5512C88596
+
+I=106
+KEY=147895B157BF16B87C32AAA17480A886CB67B2B92CBCC2B5638A93B1F6E10A04
+IV=B58C92AE19B332621E7A4E5512C88596
+PT=9B12CD2AF7520CDF8270C9C9D3658B82
+CT=4D1D90F007BB5099C382E69C9CD1F7E5
+
+I=107
+KEY=4C8441FCEBBD595999864A6CC37F7EDB867A22492B07922CA008752D6A30FDE1
+IV=4D1D90F007BB5099C382E69C9CD1F7E5
+PT=58FCD44DBC024FE1E5B4E0CDB7FFD65D
+CT=7F59920056EC32FA48F8A9CCCFFE437A
+
+I=108
+KEY=CD922EEA60F0F136A799C650F5D4B030F923B0497DEBA0D6E8F0DCE1A5CEBE9B
+IV=7F59920056EC32FA48F8A9CCCFFE437A
+PT=81166F168B4DA86F3E1F8C3C36ABCEEB
+CT=A546F57E48A783694577D59F7FD01D9E
+
+I=109
+KEY=90DE3ECB26E68BDD3C4B7AB9B9CDE6195C654537354C23BFAD87097EDA1EA305
+IV=A546F57E48A783694577D59F7FD01D9E
+PT=5D4C102146167AEB9BD2BCE94C195629
+CT=6342B8CB1E493F916585FF1BBFC42AB3
+
+I=110
+KEY=ADF1869FEA15122394E1F6FF6B51E5DE3F27FDFC2B051C2EC802F66565DA89B6
+IV=6342B8CB1E493F916585FF1BBFC42AB3
+PT=3D2FB854CCF399FEA8AA8C46D29C03C7
+CT=052AEDF54016429320B04243E308ECFE
+
+I=111
+KEY=DF52D7982845CBAEB4E56592906B63943A0D10096B135EBDE8B2B42686D26548
+IV=052AEDF54016429320B04243E308ECFE
+PT=72A35107C250D98D2004936DFB3A864A
+CT=EE147A64DC2E31222A3A14B133769ACE
+
+I=112
+KEY=5D6B5899612FF15825029DEB0B37CB4ED4196A6DB73D6F9FC288A097B5A4FF86
+IV=EE147A64DC2E31222A3A14B133769ACE
+PT=82398F01496A3AF691E7F8799B5CA8DA
+CT=8330EF868E72D33172D7DEC7B440056C
+
+I=113
+KEY=FC23917C478894C9490A6585CCB8A716572985EB394FBCAEB05F7E5001E4FAEA
+IV=8330EF868E72D33172D7DEC7B440056C
+PT=A148C9E526A765916C08F86EC78F6C58
+CT=DC83E3727C4E9754A82BFCFFD924ACB3
+
+I=114
+KEY=BCD556FA7AFA27F9675F45922924DFA68BAA669945012BFA187482AFD8C05659
+IV=DC83E3727C4E9754A82BFCFFD924ACB3
+PT=40F6C7863D72B3302E552017E59C78B0
+CT=C0B97D9320DC3E893953E1D93859D3E4
+
+I=115
+KEY=A0F23A11C85F008CFEC20F76BD6751054B131B0A65DD157321276376E09985BD
+IV=C0B97D9320DC3E893953E1D93859D3E4
+PT=1C276CEBB2A52775999D4AE494438EA3
+CT=8C28875C39211D01A084A59BA71D0C31
+
+I=116
+KEY=2BB58C8FE9FE5BAEC5DB3F6A7EB98187C73B9C565CFC087281A3C6ED4784898C
+IV=8C28875C39211D01A084A59BA71D0C31
+PT=8B47B69E21A15B223B19301CC3DED082
+CT=7865E390E8019259A117669082ED5CCC
+
+I=117
+KEY=6035A1AC1F0C1871EA06773DEA40B5C5BF5E7FC6B4FD9A2B20B4A07DC569D540
+IV=7865E390E8019259A117669082ED5CCC
+PT=4B802D23F6F243DF2FDD485794F93442
+CT=DC7BA7C54217B8DEE966C0672DBE79CD
+
+I=118
+KEY=CCA70BB373BA65736D25078BB99980F66325D803F6EA22F5C9D2601AE8D7AC8D
+IV=DC7BA7C54217B8DEE966C0672DBE79CD
+PT=AC92AA1F6CB67D02872370B653D93533
+CT=CBB60FB6BE7240A2037CDA46DAAAC4E4
+
+I=119
+KEY=E6D9E4347ABCE875CDFB026A9B1CE767A893D7B548986257CAAEBA5C327D6869
+IV=CBB60FB6BE7240A2037CDA46DAAAC4E4
+PT=2A7EEF8709068D06A0DE05E122856791
+CT=3B0863884DCFFDAAE439E3BCFC2E0491
+
+I=120
+KEY=90C0678C9B9796FACBD3A9E8E40A46E6939BB43D05579FFD2E9759E0CE536CF8
+IV=3B0863884DCFFDAAE439E3BCFC2E0491
+PT=761983B8E12B7E8F0628AB827F16A181
+CT=1407CDBD04CA6450D15A276B0E45D500
+
+I=121
+KEY=A3505D86BF4B95AEC0F720B4CBDF4985879C7980019DFBADFFCD7E8BC016B9F8
+IV=1407CDBD04CA6450D15A276B0E45D500
+PT=33903A0A24DC03540B24895C2FD50F63
+CT=94B64DF8376EAF94F24EB0457DF81418
+
+I=122
+KEY=EAD741BA44D8637A4D49A089E4A122F2132A347836F354390D83CECEBDEEADE0
+IV=94B64DF8376EAF94F24EB0457DF81418
+PT=49871C3CFB93F6D48DBE803D2F7E6B77
+CT=6E2DE304D4A21A218291FD9B59FED9BF
+
+I=123
+KEY=278551B22B73239BF36E61370FFF43EA7D07D77CE2514E188F123355E410745F
+IV=6E2DE304D4A21A218291FD9B59FED9BF
+PT=CD5210086FAB40E1BE27C1BEEB5E6118
+CT=72A1E7B22D6B8B8C38C4CCD545466879
+
+I=124
+KEY=C7046CA82928EA5AE1E6998399A090BB0FA630CECF3AC594B7D6FF80A1561C26
+IV=72A1E7B22D6B8B8C38C4CCD545466879
+PT=E0813D1A025BC9C11288F8B4965FD351
+CT=F5F1B011C644D119625733433C3DBB40
+
+I=125
+KEY=82AF7079A309A3B1367E4DC8EE90B8C5FA5780DF097E148DD581CCC39D6BA766
+IV=F5F1B011C644D119625733433C3DBB40
+PT=45AB1CD18A2149EBD798D44B7730287E
+CT=FDD90319FC2878AE4E23CE63C6660D1A
+
+I=126
+KEY=EB439411E1412BA8D6DB9F3052753D3F078E83C6F5566C239BA202A05B0DAA7C
+IV=FDD90319FC2878AE4E23CE63C6660D1A
+PT=69ECE46842488819E0A5D2F8BCE585FA
+CT=0B3948AEFD674622289CB41E3F668A5C
+
+I=127
+KEY=C2FDF3EB8C01693C7FB990CE6D7F56E10CB7CB6808312A01B33EB6BE646B2020
+IV=0B3948AEFD674622289CB41E3F668A5C
+PT=29BE67FA6D404294A9620FFE3F0A6BDE
+CT=9F5BF60EB5CCF9D9F3A20DA569209636
+
+I=128
+KEY=ECF0B5C32A3163495086894AB263166D93EC3D66BDFDD3D8409CBB1B0D4BB616
+IV=9F5BF60EB5CCF9D9F3A20DA569209636
+PT=2E0D4628A6300A752F3F1984DF1C408C
+CT=3FED40A5796B3D1FF8805E5EF8922511
+
+I=129
+KEY=259CAA194EE9BE90B2B1E7654CBDCD03AC017DC3C496EEC7B81CE545F5D99307
+IV=3FED40A5796B3D1FF8805E5EF8922511
+PT=C96C1FDA64D8DDD9E2376E2FFEDEDB6E
+CT=2973A39E09EF5F4F42B29E6730ECC127
+
+I=130
+KEY=FAAB18CE5FA7895BAA9EC69A55F690208572DE5DCD79B188FAAE7B22C5355220
+IV=2973A39E09EF5F4F42B29E6730ECC127
+PT=DF37B2D7114E37CB182F21FF194B5D23
+CT=F8C4C1A86B0665E2124CFFA9128FFEFD
+
+I=131
+KEY=3806BAB3764E794DF526A17BCE0112877DB61FF5A67FD46AE8E2848BD7BAACDD
+IV=F8C4C1A86B0665E2124CFFA9128FFEFD
+PT=C2ADA27D29E9F0165FB867E19BF782A7
+CT=90996F6629A41FC86A9520DD33AE5B3F
+
+I=132
+KEY=B7F781357E024140C3797D01C286E72BED2F70938FDBCBA28277A456E414F7E2
+IV=90996F6629A41FC86A9520DD33AE5B3F
+PT=8FF13B86084C380D365FDC7A0C87F5AC
+CT=9DAFB2F259BFD18945A0A6EFF9A81A75
+
+I=133
+KEY=B67D37A8E281AFD015C38A72F5662BEE7080C261D6641A2BC7D702B91DBCED97
+IV=9DAFB2F259BFD18945A0A6EFF9A81A75
+PT=018AB69D9C83EE90D6BAF77337E0CCC5
+CT=C89F523289AE2A7C8F796C2252CB0597
+
+I=134
+KEY=A47B97F34FB4A8F219ED7A59EFE40080B81F90535FCA305748AE6E9B4F77E800
+IV=C89F523289AE2A7C8F796C2252CB0597
+PT=1206A05BAD3507220C2EF02B1A822B6E
+CT=3AACC4E5DE152BB1730C6D10C9A81A0A
+
+I=135
+KEY=E8EBBFDA61B6BC6735953F8E448B5E0282B354B681DF1BE63BA2038B86DFF20A
+IV=3AACC4E5DE152BB1730C6D10C9A81A0A
+PT=4C9028292E0214952C7845D7AB6F5E82
+CT=1E315BFFFDC3DA42438E683263B496DD
+
+I=136
+KEY=EE950FF3D603DECEE18F4ACF99A623589C820F497C1CC1A4782C6BB9E56B64D7
+IV=1E315BFFFDC3DA42438E683263B496DD
+PT=067EB029B7B562A9D41A7541DD2D7D5A
+CT=9B021A44CD9FF920DFE1EC97B3EE8AE4
+
+I=137
+KEY=E073E1149A4A605E041167F3739F17240780150DB1833884A7CD872E5685EE33
+IV=9B021A44CD9FF920DFE1EC97B3EE8AE4
+PT=0EE6EEE74C49BE90E59E2D3CEA39347C
+CT=4F62EE03D7A8337ECB3DCC0EA5444C2D
+
+I=138
+KEY=BF449E4B7DFA404D3F18C0266725F67248E2FB0E662B0BFA6CF04B20F3C1A21E
+IV=4F62EE03D7A8337ECB3DCC0EA5444C2D
+PT=5F377F5FE7B020133B09A7D514BAE156
+CT=AC8767B1E15D6D1ECACCCBF2D0FAB043
+
+I=139
+KEY=3AB2898399D0F8467B37A5C916D9117AE4659CBF877666E4A63C80D2233B125D
+IV=AC8767B1E15D6D1ECACCCBF2D0FAB043
+PT=85F617C8E42AB80B442F65EF71FCE708
+CT=9CA6E27F1966AE133CB7B98C2B13C1DA
+
+I=140
+KEY=06A09B6D5A6BCA82B26D0625F2A89FA178C37EC09E10C8F79A8B395E0828D387
+IV=9CA6E27F1966AE133CB7B98C2B13C1DA
+PT=3C1212EEC3BB32C4C95AA3ECE4718EDB
+CT=B7A6788E6D9886047D1450B093F5B6FE
+
+I=141
+KEY=79A26263675E11BE581DDEA79A20CAACCF65064EF3884EF3E79F69EE9BDD6579
+IV=B7A6788E6D9886047D1450B093F5B6FE
+PT=7F02F90E3D35DB3CEA70D8826888550D
+CT=5C1785DC27BC301DEAFAEF325A4CCBFD
+
+I=142
+KEY=21DEF781026D9ACB4108C6F9847C635F93728392D4347EEE0D6586DCC191AE84
+IV=5C1785DC27BC301DEAFAEF325A4CCBFD
+PT=587C95E265338B751915185E1E5CA9F3
+CT=9577E8F6DF5921C4B518974A2F1FCF07
+
+I=143
+KEY=EB000BAA170733EA4D077BDD7DA1623506056B640B6D5F2AB87D1196EE8E6183
+IV=9577E8F6DF5921C4B518974A2F1FCF07
+PT=CADEFC2B156AA9210C0FBD24F9DD016A
+CT=09F8E3DA7C5E39F2F13C2B72001D1D56
+
+I=144
+KEY=D56A1025AB5F7B5F943B3AECAF87A2800FFD88BE773366D849413AE4EE937CD5
+IV=09F8E3DA7C5E39F2F13C2B72001D1D56
+PT=3E6A1B8FBC5848B5D93C4131D226C0B5
+CT=7344F33968E177F3864908F02915739A
+
+I=145
+KEY=876077EA9BDB2134098B73CAD4411D997CB97B871FD2112BCF083214C7860F4F
+IV=7344F33968E177F3864908F02915739A
+PT=520A67CF30845A6B9DB049267BC6BF19
+CT=EC286360EF2A54CE894ED06ACF39970C
+
+I=146
+KEY=AA9943761AD545F47EBCF5CD4584C3B3909118E7F0F845E54646E27E08BF9843
+IV=EC286360EF2A54CE894ED06ACF39970C
+PT=2DF9349C810E64C07737860791C5DE2A
+CT=89F4BE70D36A05C84FD2124F6A69786B
+
+I=147
+KEY=5C285D3FD07EF5F6664B1F4C4CA771E31965A6972392402D0994F03162D6E028
+IV=89F4BE70D36A05C84FD2124F6A69786B
+PT=F6B11E49CAABB00218F7EA810923B250
+CT=9A65E99C06E0744056365C4A26CD001F
+
+I=148
+KEY=F28851656D77922A55655DBE4610993683004F0B2572346D5FA2AC7B441BE037
+IV=9A65E99C06E0744056365C4A26CD001F
+PT=AEA00C5ABD0967DC332E42F20AB7E8D5
+CT=566ECB7B317C81CF87BC483B4B6CF417
+
+I=149
+KEY=62428DD3F6B04C564CA6D9DA9A9A64B3D56E8470140EB5A2D81EE4400F771420
+IV=566ECB7B317C81CF87BC483B4B6CF417
+PT=90CADCB69BC7DE7C19C38464DC8AFD85
+CT=16E3F727D2D4CC2E88C2A4B0DFEF34AF
+
+I=150
+KEY=78A68A0EC33E2C0198538C1EA591AF46C38D7357C6DA798C50DC40F0D098208F
+IV=16E3F727D2D4CC2E88C2A4B0DFEF34AF
+PT=1AE407DD358E6057D4F555C43F0BCBF5
+CT=6F6606018F5491FC43864FC29B572551
+
+I=151
+KEY=4EFBCF71F7A0DA7564DAF1F0488AA933ACEB7556498EE870135A0F324BCF05DE
+IV=6F6606018F5491FC43864FC29B572551
+PT=365D457F349EF674FC897DEEED1B0675
+CT=BC07194E716B4D78F64E14B6E5762439
+
+I=152
+KEY=A4BBF15395604071DF929A4922A129DD10EC6C1838E5A508E5141B84AEB921E7
+IV=BC07194E716B4D78F64E14B6E5762439
+PT=EA403E2262C09A04BB486BB96A2B80EE
+CT=BF1994171481FB4F84AB092F437EA9C7
+
+I=153
+KEY=665F10926596E8F5691ACE10AA5075AEAFF5F80F2C645E4761BF12ABEDC78820
+IV=BF1994171481FB4F84AB092F437EA9C7
+PT=C2E4E1C1F0F6A884B688545988F15C73
+CT=254FE05D25B67D3BF6C2688F46A7FAD8
+
+I=154
+KEY=15F4BA29EBAAF160AC95507FDA03D7D58ABA185209D2237C977D7A24AB6072F8
+IV=254FE05D25B67D3BF6C2688F46A7FAD8
+PT=73ABAABB8E3C1995C58F9E6F7053A27B
+CT=A03B8DB2C1C9B6C574A8499C6E5869CF
+
+I=155
+KEY=96A760AB52E1D6A5ACFCA016E98D0BA12A8195E0C81B95B9E3D533B8C5381B37
+IV=A03B8DB2C1C9B6C574A8499C6E5869CF
+PT=8353DA82B94B27C50069F069338EDC74
+CT=088F141F097F659145DE8E1EDB2300B5
+
+I=156
+KEY=7C06F9EE0327C811CEE3CC3B2B492620220E81FFC164F028A60BBDA61E1B1B82
+IV=088F141F097F659145DE8E1EDB2300B5
+PT=EAA1994551C61EB4621F6C2DC2C42D81
+CT=43703327BFDAF109F6F9C5969D3C7649
+
+I=157
+KEY=0F8AC1E3014DD99D1A440A693CB73B51617EB2D87EBE012150F2783083276DCB
+IV=43703327BFDAF109F6F9C5969D3C7649
+PT=738C380D026A118CD4A7C65217FE1D71
+CT=BDAC873D0A674CDA98105DC3070F7BE4
+
+I=158
+KEY=E595998ABEF32CABDD4A441B4042BF8BDCD235E574D94DFBC8E225F38428162F
+IV=BDAC873D0A674CDA98105DC3070F7BE4
+PT=EA1F5869BFBEF536C70E4E727CF584DA
+CT=A1A89122CF532FBC69E74A70F1E7346F
+
+I=159
+KEY=FBA3999F7BF540184E9BE7715CA8C0497D7AA4C7BB8A6247A1056F8375CF2240
+IV=A1A89122CF532FBC69E74A70F1E7346F
+PT=1E360015C5066CB393D1A36A1CEA7FC2
+CT=68C2A6FF8EABE7EA05E5DD6093C00129
+
+I=160
+KEY=65AF7CB5F5CEF75FEF0BF5F746D7DD7D15B80238352185ADA4E0B2E3E60F2369
+IV=68C2A6FF8EABE7EA05E5DD6093C00129
+PT=9E0CE52A8E3BB747A19012861A7F1D34
+CT=1EA92E63C6926082B04F69E658CFA478
+
+I=161
+KEY=7D3BA807729873EB2021AC1817B2C7D30B112C5BF3B3E52F14AFDB05BEC08711
+IV=1EA92E63C6926082B04F69E658CFA478
+PT=1894D4B2875684B4CF2A59EF51651AAE
+CT=45A943F0B6430ABA20C562469AE98A6D
+
+I=162
+KEY=5ECAEF5BF4EC899C7BFAEE2F50B864924EB86FAB45F0EF95346AB94324290D7C
+IV=45A943F0B6430ABA20C562469AE98A6D
+PT=23F1475C8674FA775BDB4237470AA341
+CT=6CDF579A8429606CC9BC56D010845954
+
+I=163
+KEY=8D394BD1C8C1D1F8A67A3BA16530662A22673831C1D98FF9FDD6EF9334AD5428
+IV=6CDF579A8429606CC9BC56D010845954
+PT=D3F3A48A3C2D5864DD80D58E358802B8
+CT=96E9E19694DB9931AC09A7B6296FEAA8
+
+I=164
+KEY=9ABEC4725C717368463710CB2D45774DB48ED9A7550216C851DF48251DC2BE80
+IV=96E9E19694DB9931AC09A7B6296FEAA8
+PT=17878FA394B0A290E04D2B6A48751167
+CT=176C9B9B32A539F35BDFB21B38C42134
+
+I=165
+KEY=3CA1E23510949D81242F16DE0E9B2B3AA3E2423C67A72F3B0A00FA3E25069FB4
+IV=176C9B9B32A539F35BDFB21B38C42134
+PT=A61F26474CE5EEE96218061523DE5C77
+CT=06004480169FB7B6D4DBA7453A85E54D
+
+I=166
+KEY=2A72AA0C7EAA3113480EF57A83C272D7A5E206BC7138988DDEDB5D7B1F837AF9
+IV=06004480169FB7B6D4DBA7453A85E54D
+PT=16D348396E3EAC926C21E3A48D5959ED
+CT=FF2F4F6E32133CE8C70252937FE5BDA6
+
+I=167
+KEY=90C0C8FC5B65BE92E643956293A70AF35ACD49D2432BA46519D90FE86066C75F
+IV=FF2F4F6E32133CE8C70252937FE5BDA6
+PT=BAB262F025CF8F81AE4D601810657824
+CT=0972CCC79C412DB6FBC5918B8E6EAB7C
+
+I=168
+KEY=E0AF49BAC4BD146E83C884327FFB682353BF8515DF6A89D3E21C9E63EE086C23
+IV=0972CCC79C412DB6FBC5918B8E6EAB7C
+PT=706F81469FD8AAFC658B1150EC5C62D0
+CT=2D8C668310308FCF7B3E325F50AA89E5
+
+I=169
+KEY=E5C29451893B7B94249E89469E58DEAD7E33E396CF5A061C9922AC3CBEA2E5C6
+IV=2D8C668310308FCF7B3E325F50AA89E5
+PT=056DDDEB4D866FFAA7560D74E1A3B68E
+CT=8342DD95F1040E763C82E36F8F74822F
+
+I=170
+KEY=4A9AD7CAFA46AE63362069120B502D33FD713E033E5E086AA5A04F5331D667E9
+IV=8342DD95F1040E763C82E36F8F74822F
+PT=AF58439B737DD5F712BEE0549508F39E
+CT=8CA83627884D9B7A62F096BD37C14EFF
+
+I=171
+KEY=21AEFC00E7CC2942F319630702ECCC6B71D90824B6139310C750D9EE06172916
+IV=8CA83627884D9B7A62F096BD37C14EFF
+PT=6B342BCA1D8A8721C5390A1509BCE158
+CT=13073AB95C0C0587372564189A4C176F
+
+I=172
+KEY=7E615F002723795F6E37182ECC0C429E62DE329DEA1F9697F075BDF69C5B3E79
+IV=13073AB95C0C0587372564189A4C176F
+PT=5FCFA300C0EF501D9D2E7B29CEE08EF5
+CT=247A01C6A7072F64CB463E6580DA222E
+
+I=173
+KEY=C2A25232803E901B35080B5CA64DEC2646A4335B4D18B9F33B3383931C811C57
+IV=247A01C6A7072F64CB463E6580DA222E
+PT=BCC30D32A71DE9445B3F13726A41AEB8
+CT=562355D078402DA76B0CCAAC2BE63DAE
+
+I=174
+KEY=46C06B83AD1C5CD849C53A11C05137141087668B35589454503F493F376721F9
+IV=562355D078402DA76B0CCAAC2BE63DAE
+PT=846239B12D22CCC37CCD314D661CDB32
+CT=841B1644CCE1BF9DB0D537733047DB7F
+
+I=175
+KEY=CB3AD5FB9E07D380841D712E7A71FC15949C70CFF9B92BC9E0EA7E4C0720FA86
+IV=841B1644CCE1BF9DB0D537733047DB7F
+PT=8DFABE78331B8F58CDD84B3FBA20CB01
+CT=DE34C065627DB86A2D0AE89FB31BDA86
+
+I=176
+KEY=240CFC15D60F6AE4A53D2C25BD71DD6E4AA8B0AA9BC493A3CDE096D3B43B2000
+IV=DE34C065627DB86A2D0AE89FB31BDA86
+PT=EF3629EE4808B96421205D0BC700217B
+CT=38DD744B95756614261178685FBF097F
+
+I=177
+KEY=FAA7CBA4AAAD9576591C12233960F1C87275C4E10EB1F5B7EBF1EEBBEB84297F
+IV=38DD744B95756614261178685FBF097F
+PT=DEAB37B17CA2FF92FC213E0684112CA6
+CT=DC1CF4E4633355111AD09BE1C6BC1E39
+
+I=178
+KEY=29E0D33A81FFDCE220D1587C36C5EB09AE6930056D82A0A6F121755A2D383746
+IV=DC1CF4E4633355111AD09BE1C6BC1E39
+PT=D347189E2B52499479CD4A5F0FA51AC1
+CT=2A5DC4E8C16753D202B638E5003AF83D
+
+I=179
+KEY=956C5751C5B439990A006DB1B52336E78434F4EDACE5F374F3974DBF2D02CF7B
+IV=2A5DC4E8C16753D202B638E5003AF83D
+PT=BC8C846B444BE57B2AD135CD83E6DDEE
+CT=70F5676DC7646EA8F8A913AE6AD21949
+
+I=180
+KEY=8AD9D44BC9018FD05B103360575592FEF4C193806B819DDC0B3E5E1147D0D632
+IV=70F5676DC7646EA8F8A913AE6AD21949
+PT=1FB5831A0CB5B64951105ED1E276A419
+CT=C44DA6A603A1E9C02F18123D5CAD5291
+
+I=181
+KEY=DA77F2DA5CD7148B15FE8CA898C9A25E308C35266820741C24264C2C1B7D84A3
+IV=C44DA6A603A1E9C02F18123D5CAD5291
+PT=50AE269195D69B5B4EEEBFC8CF9C30A0
+CT=53C2D89EC4D5867DC79168D21C9B8755
+
+I=182
+KEY=4A4FD6AED6825A2A0C2114460F029EDA634EEDB8ACF5F261E3B724FE07E603F6
+IV=53C2D89EC4D5867DC79168D21C9B8755
+PT=903824748A554EA119DF98EE97CB3C84
+CT=79B9DABE5171A614CAFDEA11637A1800
+
+I=183
+KEY=29102930967275801BD019D6766FDA1A1AF73706FD845475294ACEEF649C1BF6
+IV=79B9DABE5171A614CAFDEA11637A1800
+PT=635FFF9E40F02FAA17F10D90796D44C0
+CT=8AB92FA5EA50F1185112FE4D8D2FCC21
+
+I=184
+KEY=F4ABA34B232C18EAD6D367320651C374904E18A317D4A56D785830A2E9B3D7D7
+IV=8AB92FA5EA50F1185112FE4D8D2FCC21
+PT=DDBB8A7BB55E6D6ACD037EE4703E196E
+CT=FB97C84040732D7B308C5959059D90A9
+
+I=185
+KEY=FB140F98A79F5D5D68B80301CB7B640E6BD9D0E357A7881648D469FBEC2E477E
+IV=FB97C84040732D7B308C5959059D90A9
+PT=0FBFACD384B345B7BE6B6433CD2AA77A
+CT=D0D0119D500519BF5B4770C494B41680
+
+I=186
+KEY=BC98221C0792D22B6EB258E57DB0D8B0BB09C17E07A291A91393193F789A51FE
+IV=D0D0119D500519BF5B4770C494B41680
+PT=478C2D84A00D8F76060A5BE4B6CBBCBE
+CT=94842399FC93828D30979DAD9210B827
+
+I=187
+KEY=C92F345AC3CB803EA91C123F97E7005A2F8DE2E7FB31132423048492EA8AE9D9
+IV=94842399FC93828D30979DAD9210B827
+PT=75B71646C4595215C7AE4ADAEA57D8EA
+CT=5BDB886E7A7DBBA8679704F13F44B981
+
+I=188
+KEY=3EACAF51FEA9A9886D0B9D1B6BA8436574566A89814CA88C44938063D5CE5058
+IV=5BDB886E7A7DBBA8679704F13F44B981
+PT=F7839B0B3D6229B6C4178F24FC4F433F
+CT=A2DA893257EE0F732A80FC52887A0788
+
+I=189
+KEY=72E26FEDC250C5FED59FE29C966B61FAD68CE3BBD6A2A7FF6E137C315DB457D0
+IV=A2DA893257EE0F732A80FC52887A0788
+PT=4C4EC0BC3CF96C76B8947F87FDC3229F
+CT=2F7877481B1162B01616C9F3268B4C44
+
+I=190
+KEY=901C1268AD3582E6A9FA4C5CBB99D07EF9F494F3CDB3C54F7805B5C27B3F1B94
+IV=2F7877481B1162B01616C9F3268B4C44
+PT=E2FE7D856F6547187C65AEC02DF2B184
+CT=9FFA4AF8D0F096CC40A9F879076211E0
+
+I=191
+KEY=EAF814EC49F2254E4933FAF977D7BEEC660EDE0B1D43538338AC4DBB7C5D0A74
+IV=9FFA4AF8D0F096CC40A9F879076211E0
+PT=7AE40684E4C7A7A8E0C9B6A5CC4E6E92
+CT=886097F5BC20C157A605CBEFCA5663D7
+
+I=192
+KEY=8ED70BBA192093A0C9AD62E86C27091FEE6E49FEA16392D49EA98654B60B69A3
+IV=886097F5BC20C157A605CBEFCA5663D7
+PT=642F1F5650D2B6EE809E98111BF0B7F3
+CT=00DBBB84F52B3C9B28325161072753B6
+
+I=193
+KEY=18280464C9E683CFFF9B75A5FD74EE96EEB5F27A5448AE4FB69BD735B12C3A15
+IV=00DBBB84F52B3C9B28325161072753B6
+PT=96FF0FDED0C6106F3636174D9153E789
+CT=714A27832B326F0A8FA745012DE4D936
+
+I=194
+KEY=F464EE1298B09059016082CCC5ABC0129FFFD5F97F7AC145393C92349CC8E323
+IV=714A27832B326F0A8FA745012DE4D936
+PT=EC4CEA7651561396FEFBF76938DF2E84
+CT=5DE8A5CDBA7A6111A646AA17CA5324D4
+
+I=195
+KEY=EE7301D63C482593ABB33CF4A57F1101C2177034C500A0549F7A3823569BC7F7
+IV=5DE8A5CDBA7A6111A646AA17CA5324D4
+PT=1A17EFC4A4F8B5CAAAD3BE3860D4D113
+CT=EA197ECF36E63616EBB0D9D7C1BD9A22
+
+I=196
+KEY=10528506D50D143EAC40D83731DD55F0280E0EFBF3E6964274CAE1F497265DD5
+IV=EA197ECF36E63616EBB0D9D7C1BD9A22
+PT=FE2184D0E94531AD07F3E4C394A244F1
+CT=798349D56EC37993B0E131F8E3F64860
+
+I=197
+KEY=438E1B672254504B972927644802ED36518D472E9D25EFD1C42BD00C74D015B5
+IV=798349D56EC37993B0E131F8E3F64860
+PT=53DC9E61F75944753B69FF5379DFB8C6
+CT=545E4CD72E74F5A91B29DDBA60BCEB5A
+
+I=198
+KEY=7E32F16A4E2E125A95FF9963C6F9796105D30BF9B3511A78DF020DB6146CFEEF
+IV=545E4CD72E74F5A91B29DDBA60BCEB5A
+PT=3DBCEA0D6C7A421102D6BE078EFB9457
+CT=084142F2C892DCF8A37A509DF0D669BC
+
+I=199
+KEY=B1BEC1C124A0941D0BA6C75239C17E250D92490B7BC3C6807C785D2BE4BA9753
+IV=084142F2C892DCF8A37A509DF0D669BC
+PT=CF8C30AB6A8E86479E595E31FF380744
+CT=0A96C326C9D642F1F84C8772BCF8EB4A
+
+I=200
+KEY=80D7A5A2AE29B42143046D45B6B6B36C07048A2DB21584718434DA5958427C19
+IV=0A96C326C9D642F1F84C8772BCF8EB4A
+PT=316964638A89203C48A2AA178F77CD49
+CT=273916ED09A517CE5C6A294D82E78980
+
+I=201
+KEY=4D1C892DF27868BBB0FE803145C1D731203D9CC0BBB093BFD85EF314DAA5F599
+IV=273916ED09A517CE5C6A294D82E78980
+PT=CDCB2C8F5C51DC9AF3FAED74F377645D
+CT=7183A7C83964ECFB2A1E44FFCFEBB7C1
+
+I=202
+KEY=8C9B28041ECD5149A51207ACE38F0D0351BE3B0882D47F44F240B7EB154E4258
+IV=7183A7C83964ECFB2A1E44FFCFEBB7C1
+PT=C187A129ECB539F215EC879DA64EDA32
+CT=6015DF395D795DECA0A2F833E3614000
+
+I=203
+KEY=FF175C7C745BB06E51EEDAA4F2C61E0F31ABE431DFAD22A852E24FD8F62F0258
+IV=6015DF395D795DECA0A2F833E3614000
+PT=738C74786A96E127F4FCDD081149130C
+CT=B6B466B56B0E994E672072C273BA067D
+
+I=204
+KEY=0C84C64E1BB3B86E9AF5A8405D950B3A871F8284B4A3BBE635C23D1A85950425
+IV=B6B466B56B0E994E672072C273BA067D
+PT=F3939A326FE80800CB1B72E4AF531535
+CT=C8566E37DF2E2958DDD5D2DB49889BA8
+
+I=205
+KEY=5FF4C2A08B85338172D2779BF789DA234F49ECB36B8D92BEE817EFC1CC1D9F8D
+IV=C8566E37DF2E2958DDD5D2DB49889BA8
+PT=537004EE90368BEFE827DFDBAA1CD119
+CT=C4A8D14DB86637E94AF515764BC7DF44
+
+I=206
+KEY=BD81DE1813AEC9BAFDDC90E4A563CB338BE13DFED3EBA557A2E2FAB787DA40C9
+IV=C4A8D14DB86637E94AF515764BC7DF44
+PT=E2751CB8982BFA3B8F0EE77F52EA1110
+CT=5707495E4CBA3727FBA5D7F4F61AF35C
+
+I=207
+KEY=AE1B09CB7D99BAC0A71B3E83815F10A2DCE674A09F51927059472D4371C0B395
+IV=5707495E4CBA3727FBA5D7F4F61AF35C
+PT=139AD7D36E37737A5AC7AE67243CDB91
+CT=C770CD182DFF66E4D6A7BFEFE2820AE1
+
+I=208
+KEY=4F7491F03447293C42DE8393E7AD91741B96B9B8B2AEF4948FE092AC9342B974
+IV=C770CD182DFF66E4D6A7BFEFE2820AE1
+PT=E16F983B49DE93FCE5C5BD1066F281D6
+CT=E2044134ACD21D5AD026671BDC0CB2E4
+
+I=209
+KEY=A747EF80608CED4309800CA0B1C73081F992F88C1E7CE9CE5FC6F5B74F4E0B90
+IV=E2044134ACD21D5AD026671BDC0CB2E4
+PT=E8337E7054CBC47F4B5E8F33566AA1F5
+CT=303CF7780126AD06B5272A8350639C93
+
+I=210
+KEY=E5EBF5E471F2CA9F38492F604438B9C0C9AE0FF41F5A44C8EAE1DF341F2D9703
+IV=303CF7780126AD06B5272A8350639C93
+PT=42AC1A64117E27DC31C923C0F5FF8941
+CT=DACCD42953603A1321CAD9C236454598
+
+I=211
+KEY=B5E5C9211A5C43F2267B4A2411FC2CC21362DBDD4C3A7EDBCB2B06F62968D29B
+IV=DACCD42953603A1321CAD9C236454598
+PT=500E3CC56BAE896D1E32654455C49502
+CT=F9AB4D1D8255E83B330031EBE2ECE5C6
+
+I=212
+KEY=8D78453D63A2DD8D08BF5F250F2581CFEAC996C0CE6F96E0F82B371DCB84375D
+IV=F9AB4D1D8255E83B330031EBE2ECE5C6
+PT=389D8C1C79FE9E7F2EC415011ED9AD0D
+CT=0F28E2D4CC948D36E18F80184A594841
+
+I=213
+KEY=2E921775036404FD9939EE83C9585481E5E1741402FB1BD619A4B70581DD7F1C
+IV=0F28E2D4CC948D36E18F80184A594841
+PT=A3EA524860C6D9709186B1A6C67DD54E
+CT=A4756EAB45BCF716A52038C729E420C6
+
+I=214
+KEY=9F86FEF42701B1D779BD46BE515680FC41941ABF4747ECC0BC848FC2A8395FDA
+IV=A4756EAB45BCF716A52038C729E420C6
+PT=B114E9812465B52AE084A83D980ED47D
+CT=9834425E009006673E777E3552E83D20
+
+I=215
+KEY=2212046FFD03BA552089FBF7B2F3EF32D9A058E147D7EAA782F3F1F7FAD162FA
+IV=9834425E009006673E777E3552E83D20
+PT=BD94FA9BDA020B825934BD49E3A56FCE
+CT=AEA572D530A3694EAFF6DFDE30B80D5A
+
+I=216
+KEY=F73BB21F916D8011751AFDDDCD130A6477052A34777483E92D052E29CA696FA0
+IV=AEA572D530A3694EAFF6DFDE30B80D5A
+PT=D529B6706C6E3A445593062A7FE0E556
+CT=86394E06B621147758CAB012852035A6
+
+I=217
+KEY=EE44A367A3CDDFED7DBD980BF731B4E5F13C6432C155979E75CF9E3B4F495A06
+IV=86394E06B621147758CAB012852035A6
+PT=197F117832A05FFC08A765D63A22BE81
+CT=3CBC18C1AC02C0A7595199E08F1F552B
+
+I=218
+KEY=1558BABB3DCD830F693E7950F736BCADCD807CF36D5757392C9E07DBC0560F2D
+IV=3CBC18C1AC02C0A7595199E08F1F552B
+PT=FB1C19DC9E005CE21483E15B00070848
+CT=5A9CFD8BFE10CF7FBD0F9A3FAF6C117B
+
+I=219
+KEY=D083F58141F5E5AF3D5479739D55780D971C81789347984691919DE46F3A1E56
+IV=5A9CFD8BFE10CF7FBD0F9A3FAF6C117B
+PT=C5DB4F3A7C3866A0546A00236A63C4A0
+CT=61A437D4E2F1C3779F1EBE906C5D2C12
+
+I=220
+KEY=C60824F2DDC67623D270974E9F87BD27F6B8B6AC71B65B310E8F237403673244
+IV=61A437D4E2F1C3779F1EBE906C5D2C12
+PT=168BD1739C33938CEF24EE3D02D2C52A
+CT=FC675EE1B12B47410A20CFAC23FD20EE
+
+I=221
+KEY=F73A715AD84DB0A6F55AD584922001920ADFE84DC09D1C7004AFECD8209A12AA
+IV=FC675EE1B12B47410A20CFAC23FD20EE
+PT=313255A8058BC685272A42CA0DA7BCB5
+CT=82E3FB6189716D94C8E9D30E1ECCABC4
+
+I=222
+KEY=6ABBDCE21E2ECECBCAA3473897A2E178883C132C49EC71E4CC463FD63E56B96E
+IV=82E3FB6189716D94C8E9D30E1ECCABC4
+PT=9D81ADB8C6637E6D3FF992BC0582E0EA
+CT=BD84DCE4994B505EED71596B454BDF85
+
+I=223
+KEY=0D4F68CDB9B53B08E22DDDFE4FD5FCC035B8CFC8D0A721BA213766BD7B1D66EB
+IV=BD84DCE4994B505EED71596B454BDF85
+PT=67F4B42FA79BF5C3288E9AC6D8771DB8
+CT=1B3AA490C6E874BA77CE55D71789616C
+
+I=224
+KEY=3D8E3121698DD7E9D1835EFF5FA02DB22E826B58164F550056F9336A6C940787
+IV=1B3AA490C6E874BA77CE55D71789616C
+PT=30C159ECD038ECE133AE83011075D172
+CT=D6EE171B39B5E40535FBF5A7CB4C6953
+
+I=225
+KEY=1A5B2249CA785F0DB58FF5B07CCCFCDEF86C7C432FFAB1056302C6CDA7D86ED4
+IV=D6EE171B39B5E40535FBF5A7CB4C6953
+PT=27D51368A3F588E4640CAB4F236CD16C
+CT=8691BE10D13B4C08246938750EE33643
+
+I=226
+KEY=48AD5DEF217F83DC5039ECD1191ABE3A7EFDC253FEC1FD0D476BFEB8A93B5897
+IV=8691BE10D13B4C08246938750EE33643
+PT=52F67FA6EB07DCD1E5B6196165D642E4
+CT=E40AD0EE818639E37349E1132B138D63
+
+I=227
+KEY=FEB84B0B264A8A6FB8D4DE065DA68A479AF712BD7F47C4EE34221FAB8228D5F4
+IV=E40AD0EE818639E37349E1132B138D63
+PT=B61516E4073509B3E8ED32D744BC347D
+CT=6E40A22767A39C978F279D40B447099D
+
+I=228
+KEY=2FE79FCC3C959901BAAEE8C55B71D01FF4B7B09A18E45879BB0582EB366FDC69
+IV=6E40A22767A39C978F279D40B447099D
+PT=D15FD4C71ADF136E027A36C306D75A58
+CT=C2DE8C5200F6FCBF1A4D6178909DF110
+
+I=229
+KEY=C3EB1424EFD0ACDF3670C4943CB2CF5936693CC81812A4C6A148E393A6F22D79
+IV=C2DE8C5200F6FCBF1A4D6178909DF110
+PT=EC0C8BE8D34535DE8CDE2C5167C31F46
+CT=104CBECB1134CAE09B2FE8C5CE2E0901
+
+I=230
+KEY=DF9F70702DA816906F3907575DF4D3032625820309266E263A670B5668DC2478
+IV=104CBECB1134CAE09B2FE8C5CE2E0901
+PT=1C746454C278BA4F5949C3C361461C5A
+CT=65287F66F01AC054B1051D700EDDBF2B
+
+I=231
+KEY=F6C4CE3006A43EFBE18C5FF305F32C37430DFD65F93CAE728B62162666019B53
+IV=65287F66F01AC054B1051D700EDDBF2B
+PT=295BBE402B0C286B8EB558A45807FF34
+CT=4933D44FD414225CB1E6951240D28150
+
+I=232
+KEY=3963CE7465D89FBE550649326262DB450A3E292A2D288C2E3A84833426D31A03
+IV=4933D44FD414225CB1E6951240D28150
+PT=CFA70044637CA145B48A16C16791F772
+CT=3733351F76DE0E07581F84600E38EFDD
+
+I=233
+KEY=42468662273D8CB3EFAB19DBC802888B3D0D1C355BF68229629B075428EBF5DE
+IV=3733351F76DE0E07581F84600E38EFDD
+PT=7B25481642E5130DBAAD50E9AA6053CE
+CT=F16F22EB9CCD854591AE2FC28E1D4B59
+
+I=234
+KEY=E2B3E5EA6573FC8ABE4E890FA4F5502DCC623EDEC73B076CF3352896A6F6BE87
+IV=F16F22EB9CCD854591AE2FC28E1D4B59
+PT=A0F56388424E703951E590D46CF7D8A6
+CT=1D607C6E9BAD454DD5DE785F2A78F990
+
+I=235
+KEY=FDB55AF96E09AF677AA4737992E13C9ED10242B05C96422126EB50C98C8E4717
+IV=1D607C6E9BAD454DD5DE785F2A78F990
+PT=1F06BF130B7A53EDC4EAFA7636146CB3
+CT=7B16B6A8F88E05F6A9A036A67CB8A2B6
+
+I=236
+KEY=E546D74518CF4AA64B399EA321C570CAAA14F418A41847D78F4B666FF036E5A1
+IV=7B16B6A8F88E05F6A9A036A67CB8A2B6
+PT=18F38DBC76C6E5C1319DEDDAB3244C54
+CT=63AD66FCF9D52195CD0339443F554311
+
+I=237
+KEY=2F9B91A24BEF0E503DC576E4F8D32C16C9B992E45DCD664242485F2BCF63A6B0
+IV=63AD66FCF9D52195CD0339443F554311
+PT=CADD46E7532044F676FCE847D9165CDC
+CT=6293FBB897D8F0C60171BEA3072CA512
+
+I=238
+KEY=97B7DF112EFFE9279D5EDF932889D84BAB2A695CCA1596844339E188C84F03A2
+IV=6293FBB897D8F0C60171BEA3072CA512
+PT=B82C4EB36510E777A09BA977D05AF45D
+CT=9555D7F244448C80E965CE6AB7EF0F7B
+
+I=239
+KEY=39F26B429FE4111DAA984F03112B339F3E7FBEAE8E511A04AA5C2FE27FA00CD9
+IV=9555D7F244448C80E965CE6AB7EF0F7B
+PT=AE45B453B11BF83A37C6909039A2EBD4
+CT=FA242C9DB2984E9EFA8CD98AE7C29D6F
+
+I=240
+KEY=64C6D001CB3C8AFC24A72DA11D172727C45B92333CC9549A50D0F668986291B6
+IV=FA242C9DB2984E9EFA8CD98AE7C29D6F
+PT=5D34BB4354D89BE18E3F62A20C3C14B8
+CT=2998B59B0441F068D7F3FCE7AEAA6FD9
+
+I=241
+KEY=FE56E2EB2434CA49D46A684DBCE2426CEDC327A83888A4F287230A8F36C8FE6F
+IV=2998B59B0441F068D7F3FCE7AEAA6FD9
+PT=9A9032EAEF0840B5F0CD45ECA1F5654B
+CT=A3F77BBA27BA88F33D4330EB2CC0EFBA
+
+I=242
+KEY=0F9B3CAD0EDFA9C429F3A005C78FE9F84E345C121F322C01BA603A641A0811D5
+IV=A3F77BBA27BA88F33D4330EB2CC0EFBA
+PT=F1CDDE462AEB638DFD99C8487B6DAB94
+CT=9C751C64BCB82229ABA5130353455CCB
+
+I=243
+KEY=1725A4C019FB909FB1DE2ACA00E9A33DD2414076A38A0E2811C52967494D4D1E
+IV=9C751C64BCB82229ABA5130353455CCB
+PT=18BE986D1724395B982D8ACFC7664AC5
+CT=540DE482B7170E925FA4B429F6BCD458
+
+I=244
+KEY=E2A619367235AA4611A72FD4FAF68FB3864CA4F4149D00BA4E619D4EBFF19946
+IV=540DE482B7170E925FA4B429F6BCD458
+PT=F583BDF66BCE3AD9A079051EFA1F2C8E
+CT=6AADE1E1A12F5C83AF434CAD95B29678
+
+I=245
+KEY=8629FB2CC8C06A07EC910681499E917FECE14515B5B25C39E122D1E32A430F3E
+IV=6AADE1E1A12F5C83AF434CAD95B29678
+PT=648FE21ABAF5C041FD362955B3681ECC
+CT=11308758A1C2075FEAECD260867CA343
+
+I=246
+KEY=5EDD76C395D2A0D3D547CFB394B439EAFDD1C24D14705B660BCE0383AC3FAC7D
+IV=11308758A1C2075FEAECD260867CA343
+PT=D8F48DEF5D12CAD439D6C932DD2AA895
+CT=14C9A904A3909A8FF44D88E22F8626DF
+
+I=247
+KEY=AF3FA8D6034564D7151C3933C7986CFCE9186B49B7E0C1E9FF838B6183B98AA2
+IV=14C9A904A3909A8FF44D88E22F8626DF
+PT=F1E2DE159697C404C05BF680532C5516
+CT=A042D7F391A37E5A3EDB3022400EC797
+
+I=248
+KEY=8ACC720216DBDBDB4C213FE65E575A09495ABCBA2643BFB3C158BB43C3B74D35
+IV=A042D7F391A37E5A3EDB3022400EC797
+PT=25F3DAD4159EBF0C593D06D599CF36F5
+CT=439FEF326223A65F7A555C6231178190
+
+I=249
+KEY=F2882A52603203A71895A5870CCF7EE40AC55388446019ECBB0DE721F2A0CCA5
+IV=439FEF326223A65F7A555C6231178190
+PT=7844585076E9D87C54B49A61529824ED
+CT=6FE1286C19AA3BC802F1C6C7B58DB4C4
+
+I=250
+KEY=57EFB10BFC21E28397A9D5E5A533D35B65247BE45DCA2224B9FC21E6472D7861
+IV=6FE1286C19AA3BC802F1C6C7B58DB4C4
+PT=A5679B599C13E1248F3C7062A9FCADBF
+CT=C38D763981392FF038573CA341DD8EA1
+
+I=251
+KEY=19328A5147BC2E7C5149DA257487D734A6A90DDDDCF30DD481AB1D4506F0F6C0
+IV=C38D763981392FF038573CA341DD8EA1
+PT=4EDD3B5ABB9DCCFFC6E00FC0D1B4046F
+CT=5FD553A2848C683B138D50F2741B124D
+
+I=252
+KEY=ED66DE43FE0F966850EF6754E21B69A0F97C5E7F587F65EF92264DB772EBE48D
+IV=5FD553A2848C683B138D50F2741B124D
+PT=F4545412B9B3B81401A6BD71969CBE94
+CT=910CDCBE38068A51185A879FF2B45B9C
+
+I=253
+KEY=E53D9016DE7DF4E2377968864B6F69F8687082C16079EFBE8A7CCA28805FBF11
+IV=910CDCBE38068A51185A879FF2B45B9C
+PT=085B4E552072628A67960FD2A9740058
+CT=E0A0E68A14893501D75BC42B8EFC6F96
+
+I=254
+KEY=C88C4383E2D16541765E5DB85957C59188D0644B74F0DABF5D270E030EA3D087
+IV=E0A0E68A14893501D75BC42B8EFC6F96
+PT=2DB1D3953CAC91A34127353E1238AC69
+CT=A66DD21DA627347F962A0AB7DCA887ED
+
+I=255
+KEY=6F01CC5C22DE71C7C2D5B429AA756A392EBDB656D2D7EEC0CB0D04B4D20B576A
+IV=A66DD21DA627347F962A0AB7DCA887ED
+PT=A78D8FDFC00F1486B48BE991F322AFA8
+CT=87551BC7A6B6D9B76239CB8A31FF1993
+
+I=256
+KEY=DAC405506CD3779FC2400B459B7C6B6EA9E8AD9174613777A934CF3EE3F44EF9
+IV=87551BC7A6B6D9B76239CB8A31FF1993
+PT=B5C5C90C4E0D06580095BF6C31090157
+CT=B909B206A041F33EB3AC7ED481DFBA21
+
+I=257
+KEY=E482333E6FBAA8427A2E30D56069E0B810E11F97D420C4491A98B1EA622BF4D8
+IV=B909B206A041F33EB3AC7ED481DFBA21
+PT=3E46366E0369DFDDB86E3B90FB158BD6
+CT=DE5E71F446794D3402400C96FBFEB93F
+
+I=258
+KEY=176CAD69CD20690B95DA40B95C43AC54CEBF6E639259897D18D8BD7C99D54DE7
+IV=DE5E71F446794D3402400C96FBFEB93F
+PT=F3EE9E57A29AC149EFF4706C3C2A4CEC
+CT=175A7C580A99E985A2FD2F185D9BAADB
+
+I=259
+KEY=FA4DD79A64960C8264624CDF215B54A1D9E5123B98C060F8BA259264C44EE73C
+IV=175A7C580A99E985A2FD2F185D9BAADB
+PT=ED217AF3A9B66589F1B80C667D18F8F5
+CT=413EB5D166C1D196F0239FF34D184013
+
+I=260
+KEY=49855C1008EAF59432518A9F3807A0B398DBA7EAFE01B16E4A060D978956A72F
+IV=413EB5D166C1D196F0239FF34D184013
+PT=B3C88B8A6C7CF9165633C640195CF412
+CT=69A3A63C580336296FF826600C754747
+
+I=261
+KEY=849D231AE9F90F233F328BE6EE0AC180F17801D6A602874725FE2BF78523E068
+IV=69A3A63C580336296FF826600C754747
+PT=CD187F0AE113FAB70D630179D60D6133
+CT=B9AF0CA2B502C2DEB66834BD729AA528
+
+I=262
+KEY=40E3F7EA3E7CFBDBF57935DBB124CF7F48D70D741300459993961F4AF7B94540
+IV=B9AF0CA2B502C2DEB66834BD729AA528
+PT=C47ED4F0D785F4F8CA4BBE3D5F2E0EFF
+CT=99E16968796AB521FC460A8DF6744FA8
+
+I=263
+KEY=4FDF8D16B85E527490FBE95EA34138D6D136641C6A6AF0B86FD015C701CD0AE8
+IV=99E16968796AB521FC460A8DF6744FA8
+PT=0F3C7AFC8622A9AF6582DC851265F7A9
+CT=7B871B0153657949D1FE7259E16791B7
+
+I=264
+KEY=6AD7099EA6DC50F5CC836C3EB934CF92AAB17F1D390F89F1BE2E679EE0AA9B5F
+IV=7B871B0153657949D1FE7259E16791B7
+PT=250884881E8202815C7885601A75F744
+CT=8D6B80EAC01BF7E204A79DD14BFDB71A
+
+I=265
+KEY=0860DD776AD2014ED90D0837A5A298B627DAFFF7F9147E13BA89FA4FAB572C45
+IV=8D6B80EAC01BF7E204A79DD14BFDB71A
+PT=62B7D4E9CC0E51BB158E64091C965724
+CT=DAD6A83408559AD3003C6995DC099303
+
+I=266
+KEY=9E8757199D96CA08B9C3CEF817E902B8FD0C57C3F141E4C0BAB593DA775EBF46
+IV=DAD6A83408559AD3003C6995DC099303
+PT=96E78A6EF744CB4660CEC6CFB24B9A0E
+CT=AA6EF32AFC8AA6ADCDE86D86CC59AFB4
+
+I=267
+KEY=483AD9696154B929F35016B648F5952B5762A4E90DCB426D775DFE5CBB0710F2
+IV=AA6EF32AFC8AA6ADCDE86D86CC59AFB4
+PT=D6BD8E70FCC273214A93D84E5F1C9793
+CT=713F9516A55FBFA4AE8155EC12A3AB5D
+
+I=268
+KEY=027B7F5F83B26099A4CE8FCC1AB84529265D31FFA894FDC9D9DCABB0A9A4BBAF
+IV=713F9516A55FBFA4AE8155EC12A3AB5D
+PT=4A41A636E2E6D9B0579E997A524DD002
+CT=B2E4BEAF6DB84214E379B89697191379
+
+I=269
+KEY=D7AEFAD28855BB04A9604527F8376CAF94B98F50C52CBFDD3AA513263EBDA8D6
+IV=B2E4BEAF6DB84214E379B89697191379
+PT=D5D5858D0BE7DB9D0DAECAEBE28F2986
+CT=9FE3B8941D9F85B1400CC45B7BDE8E9F
+
+I=270
+KEY=B5EBE7CB901F69E61EC6F011E6A46A2E0B5A37C4D8B33A6C7AA9D77D45632649
+IV=9FE3B8941D9F85B1400CC45B7BDE8E9F
+PT=62451D19184AD2E2B7A6B5361E930681
+CT=E9ABFC5563B4AD1718EF4A91F7D60913
+
+I=271
+KEY=571805B63BC20F5784AF56FDB71CBCD7E2F1CB91BB07977B62469DECB2B52F5A
+IV=E9ABFC5563B4AD1718EF4A91F7D60913
+PT=E2F3E27DABDD66B19A69A6EC51B8D6F9
+CT=D825DC1C8C73A84BDFEFD9799D9E3960
+
+I=272
+KEY=9EED79D9ABB11094FB4475ED2EC042133AD4178D37743F30BDA944952F2B163A
+IV=D825DC1C8C73A84BDFEFD9799D9E3960
+PT=C9F57C6F90731FC37FEB231099DCFEC4
+CT=7D0DC4C31259FD0A46D2D2282F1FE22E
+
+I=273
+KEY=EF905E20846E064A3B3281FD2BD59AB647D9D34E252DC23AFB7B96BD0034F414
+IV=7D0DC4C31259FD0A46D2D2282F1FE22E
+PT=717D27F92FDF16DEC076F4100515D8A5
+CT=93FAFC16EFF504A9D2B791A272A78135
+
+I=274
+KEY=8F219C67ACF0F1C745FA0ABBADE96015D4232F58CAD8C69329CC071F72937521
+IV=93FAFC16EFF504A9D2B791A272A78135
+PT=60B1C247289EF78D7EC88B46863CFAA3
+CT=EF387517F8C781A79700C8196DCA6F1A
+
+I=275
+KEY=48C6408FD8FA84D30DD53B83B31C425D3B1B5A4F321F4734BECCCF061F591A3B
+IV=EF387517F8C781A79700C8196DCA6F1A
+PT=C7E7DCE8740A7514482F31381EF52248
+CT=A6166002C7239645D55494BB64840B26
+
+I=276
+KEY=1C9EB0648715CA5738A4FD27A63693A09D0D3A4DF53CD1716B985BBD7BDD111D
+IV=A6166002C7239645D55494BB64840B26
+PT=5458F0EB5FEF4E843571C6A4152AD1FD
+CT=FB35646B2008AD29AFF508B94179F223
+
+I=277
+KEY=4AA2E4BAC74E8CD9AEA969550D27877866385E26D5347C58C46D53043AA4E33E
+IV=FB35646B2008AD29AFF508B94179F223
+PT=563C54DE405B468E960D9472AB1114D8
+CT=59C1692D4598AD622B6586A06892E11D
+
+I=278
+KEY=B9F5A3BAAA0C2F6EA5E835F6E6E5D50E3FF9370B90ACD13AEF08D5A452360223
+IV=59C1692D4598AD622B6586A06892E11D
+PT=F35747006D42A3B70B415CA3EBC25276
+CT=3131E251A6A4AC7226A1809553198AB8
+
+I=279
+KEY=EF46814F8656D3D8ABAF3B08EFEBC3150EC8D55A36087D48C9A95531012F889B
+IV=3131E251A6A4AC7226A1809553198AB8
+PT=56B322F52C5AFCB60E470EFE090E161B
+CT=2E30D8D5B7B636307A6D354FBED41A2D
+
+I=280
+KEY=3DFBE0FE20F0421CAABD62E2CDB0E60F20F80D8F81BE4B78B3C4607EBFFB92B6
+IV=2E30D8D5B7B636307A6D354FBED41A2D
+PT=D2BD61B1A6A691C4011259EA225B251A
+CT=6D791952F9416FC09B78517A2FFE986F
+
+I=281
+KEY=5197CF05753D155C5B08A5EB51B82F2D4D8114DD78FF24B828BC310490050AD9
+IV=6D791952F9416FC09B78517A2FFE986F
+PT=6C6C2FFB55CD5740F1B5C7099C08C922
+CT=37A8E0B9375AD5669A396D980D68D0F3
+
+I=282
+KEY=B3EFE2F914264AAAB7C7FD9C4843619E7A29F4644FA5F1DEB2855C9C9D6DDA2A
+IV=37A8E0B9375AD5669A396D980D68D0F3
+PT=E2782DFC611B5FF6ECCF587719FB4EB3
+CT=BC65630DB71EE8DA2194E5DFBC48360E
+
+I=283
+KEY=CAAB7758FF4AFF39A98C2202A26165CFC64C9769F8BB19049311B9432125EC24
+IV=BC65630DB71EE8DA2194E5DFBC48360E
+PT=794495A1EB6CB5931E4BDF9EEA220451
+CT=9C47136C1B510BFCEFA7F6659BDA08C2
+
+I=284
+KEY=CC38852E17544DB004372C4A3AA3DFDB5A0B8405E3EA12F87CB64F26BAFFE4E6
+IV=9C47136C1B510BFCEFA7F6659BDA08C2
+PT=0693F276E81EB289ADBB0E4898C2BA14
+CT=68AC57D13EC53C250FEBFC64B1992B1C
+
+I=285
+KEY=108FE55553F353DFABD421E15A18C9F532A7D3D4DD2F2EDD735DB3420B66CFFA
+IV=68AC57D13EC53C250FEBFC64B1992B1C
+PT=DCB7607B44A71E6FAFE30DAB60BB162E
+CT=9A8C11E031E57B77138A3637784D1D71
+
+I=286
+KEY=C432EA6E854DE8C191C6F0ED4A2BF1D7A82BC234ECCA55AA60D78575732BD28B
+IV=9A8C11E031E57B77138A3637784D1D71
+PT=D4BD0F3BD6BEBB1E3A12D10C10333822
+CT=3BBB1E76A491A5AA145ED931BB886333
+
+I=287
+KEY=980941D5FEFD458061B1B443E39818299390DC42485BF00074895C44C8A3B1B8
+IV=3BBB1E76A491A5AA145ED931BB886333
+PT=5C3BABBB7BB0AD41F07744AEA9B3E9FE
+CT=F79F1B46F57BDD36B58DDA33619D3920
+
+I=288
+KEY=B4FF33FB094612B6A3438A285C3AEA41640FC704BD202D36C1048677A93E8898
+IV=F79F1B46F57BDD36B58DDA33619D3920
+PT=2CF6722EF7BB5736C2F23E6BBFA2F268
+CT=F1C3ED72D0B6D917DD6F8AE86CFD8CBF
+
+I=289
+KEY=BC81027596771F9C591BE6C61762B1E795CC2A766D96F4211C6B0C9FC5C30427
+IV=F1C3ED72D0B6D917DD6F8AE86CFD8CBF
+PT=087E318E9F310D2AFA586CEE4B585BA6
+CT=EAF1AACEEB9F9BE0E880911BFEEAC2AC
+
+I=290
+KEY=D41458000DDED43B83DAA81B1D7FFB597F3D80B886096FC1F4EB9D843B29C68B
+IV=EAF1AACEEB9F9BE0E880911BFEEAC2AC
+PT=68955A759BA9CBA7DAC14EDD0A1D4ABE
+CT=7B35179E67E9B40346F7DE6356EDC98F
+
+I=291
+KEY=FACDC2B3BA9E125B2A734DE75F99F48C04089726E1E0DBC2B21C43E76DC40F04
+IV=7B35179E67E9B40346F7DE6356EDC98F
+PT=2ED99AB3B740C660A9A9E5FC42E60FD5
+CT=0EDE849D7E56B296B12C1EDF37436A8D
+
+I=292
+KEY=E73022253439EB4464CE0B205BBB0F1F0AD613BB9FB6695403305D385A876589
+IV=0EDE849D7E56B296B12C1EDF37436A8D
+PT=1DFDE0968EA7F91F4EBD46C70422FB93
+CT=D02F1EAF3CF6A6B681BAF8ECB921FFC4
+
+I=293
+KEY=9F3671205266DC4F7C771EBA74265F36DAF90D14A340CFE2828AA5D4E3A69A4D
+IV=D02F1EAF3CF6A6B681BAF8ECB921FFC4
+PT=78065305665F370B18B9159A2F9D5029
+CT=E365BE1A125C6930DFDCBB33E6937EC5
+
+I=294
+KEY=111A3E012C9D5CB2967E8BD22907D6F7399CB30EB11CA6D25D561EE70535E488
+IV=E365BE1A125C6930DFDCBB33E6937EC5
+PT=8E2C4F217EFB80FDEA0995685D2189C1
+CT=C5B24EEC5CDD17AA56838B09EC4AB725
+
+I=295
+KEY=15DA3EE4EE9A560B05493FFC971713A5FC2EFDE2EDC1B1780BD595EEE97F53AD
+IV=C5B24EEC5CDD17AA56838B09EC4AB725
+PT=04C000E5C2070AB99337B42EBE10C552
+CT=4D8A43CD28BBCB86953FA55A409BF130
+
+I=296
+KEY=2C8B30484D954192818342F3766C1415B1A4BE2FC57A7AFE9EEA30B4A9E4A29D
+IV=4D8A43CD28BBCB86953FA55A409BF130
+PT=39510EACA30F179984CA7D0FE17B07B0
+CT=A524A6329E6DCE041F72459234ECDE78
+
+I=297
+KEY=0F162BAD5F298EE0B0164CFED6A7AC271480181D5B17B4FA819875269D087CE5
+IV=A524A6329E6DCE041F72459234ECDE78
+PT=239D1BE512BCCF7231950E0DA0CBB832
+CT=90BBC5130D1C06182F737FE7F0FCD00D
+
+I=298
+KEY=62744CA02B6684D05A91F2049D403480843BDD0E560BB2E2AEEB0AC16DF4ACE8
+IV=90BBC5130D1C06182F737FE7F0FCD00D
+PT=6D62670D744F0A30EA87BEFA4BE798A7
+CT=35F293EDDEC8D9446A4ACD34602839B5
+
+I=299
+KEY=21F5373DA5D6BF15BC163383F62EA92FB1C94EE388C36BA6C4A1C7F50DDC955D
+IV=35F293EDDEC8D9446A4ACD34602839B5
+PT=43817B9D8EB03BC5E687C1876B6E9DAF
+CT=E45CF478D7C84325143165F58B041A13
+
+I=300
+KEY=4CF4A508B4DF37A831916353620DC1F45595BA9B5F0B2883D090A20086D88F4E
+IV=E45CF478D7C84325143165F58B041A13
+PT=6D019235110988BD8D8750D0942368DB
+CT=964983C30745D7EEA1BD5E287DAC466C
+
+I=301
+KEY=35C99C004D01E89F94A9B3BC79C492D7C3DC3958584EFF6D712DFC28FB74C922
+IV=964983C30745D7EEA1BD5E287DAC466C
+PT=793D3908F9DEDF37A538D0EF1BC95323
+CT=6834813D8403A963AD36C1A18CA605C0
+
+I=302
+KEY=F185723D6A2D2A6F9F4B9194A444AA2AABE8B865DC4D560EDC1B3D8977D2CCE2
+IV=6834813D8403A963AD36C1A18CA605C0
+PT=C44CEE3D272CC2F00BE22228DD8038FD
+CT=61F35AA76E1E0EC2D5E4F4F432B68260
+
+I=303
+KEY=B571B0BC6CFD2BA23611FB9A900A31FACA1BE2C2B25358CC09FFC97D45644E82
+IV=61F35AA76E1E0EC2D5E4F4F432B68260
+PT=44F4C28106D001CDA95A6A0E344E9BD0
+CT=DD081A96602E6665B860466B8D14050E
+
+I=304
+KEY=2A5757156C596DE633D0D8908011C3771713F854D27D3EA9B19F8F16C8704B8C
+IV=DD081A96602E6665B860466B8D14050E
+PT=9F26E7A900A4464405C1230A101BF28D
+CT=5BF18EA3D7F3ED1D941EA1B995313B98
+
+I=305
+KEY=DA008B517FA48E908A72B8525CC31AEF4CE276F7058ED3B425812EAF5D417014
+IV=5BF18EA3D7F3ED1D941EA1B995313B98
+PT=F057DC4413FDE376B9A260C2DCD2D998
+CT=74C361B6A13013E9ABF6841601513539
+
+I=306
+KEY=E313244DC22AC16C1D59AC494AA728D738211741A4BEC05D8E77AAB95C10452D
+IV=74C361B6A13013E9ABF6841601513539
+PT=3913AF1CBD8E4FFC972B141B16643238
+CT=9937614570FD404D5B39BA43D3A20602
+
+I=307
+KEY=92A7173E943CBA80AF56203552625E8AA1167604D4438010D54E10FA8FB2432F
+IV=9937614570FD404D5B39BA43D3A20602
+PT=71B4337356167BECB20F8C7C18C5765D
+CT=726FCDDF8E6738B51D767828EBDFC71E
+
+I=308
+KEY=242C75C141A58DC403020E52421BB347D379BBDB5A24B8A5C83868D2646D8431
+IV=726FCDDF8E6738B51D767828EBDFC71E
+PT=B68B62FFD5993744AC542E671079EDCD
+CT=78F735344BF10EED47969F1C02ECBF8C
+
+I=309
+KEY=5247008C3EB79AA67E5D2E0B95D0AC3AAB8E8EEF11D5B6488FAEF7CE66813BBD
+IV=78F735344BF10EED47969F1C02ECBF8C
+PT=766B754D7F1217627D5F2059D7CB1F7D
+CT=7D6A6CA54B084105DF6A778A4913BB04
+
+I=310
+KEY=06E7C1A6C8BC6A3355A86F61B41E70C6D6E4E24A5ADDF74D50C480442F9280B9
+IV=7D6A6CA54B084105DF6A778A4913BB04
+PT=54A0C12AF60BF0952BF5416A21CEDCFC
+CT=11F0A303D6C0ED5E18F40248AF1A794B
+
+I=311
+KEY=D7722746B58D494BE9B97F586CA4BB0AC71441498C1D1A134830820C8088F9F2
+IV=11F0A303D6C0ED5E18F40248AF1A794B
+PT=D195E6E07D312378BC111039D8BACBCC
+CT=2A715E8AC7101415E65EBF34CC4CD786
+
+I=312
+KEY=98B1E5954DE8000B6FFFE98D918B6237ED651FC34B0D0E06AE6E3D384CC42E74
+IV=2A715E8AC7101415E65EBF34CC4CD786
+PT=4FC3C2D3F8654940864696D5FD2FD93D
+CT=965E8AF93D390E424C9F4F1FBF9D98A5
+
+I=313
+KEY=74B910207ACD1D7C801724D53ED6BBC47B3B953A76340044E2F17227F359B6D1
+IV=965E8AF93D390E424C9F4F1FBF9D98A5
+PT=EC08F5B537251D77EFE8CD58AF5DD9F3
+CT=294782DD29C65B6C445C5D92F50E6D19
+
+I=314
+KEY=3E1AD36FDCC33F6B3425B5D52717845E527C17E75FF25B28A6AD2FB50657DBC8
+IV=294782DD29C65B6C445C5D92F50E6D19
+PT=4AA3C34FA60E2217B432910019C13F9A
+CT=E22098E7EDBEECC49FA8E31B76E925CA
+
+I=315
+KEY=BE9F93FE153DF61370F6709F8265DCCDB05C8F00B24CB7EC3905CCAE70BEFE02
+IV=E22098E7EDBEECC49FA8E31B76E925CA
+PT=80854091C9FEC97844D3C54AA5725893
+CT=24E80C1F59A4EA36044358E0C0D4F29D
+
+I=316
+KEY=A790F593CFA1643BD2EB3A1AAB8176A294B4831FEBE85DDA3D46944EB06A0C9F
+IV=24E80C1F59A4EA36044358E0C0D4F29D
+PT=190F666DDA9C9228A21D4A8529E4AA6F
+CT=63CF21803941B521532FF36F9FBFC7BD
+
+I=317
+KEY=0CF6F000352B4B583E4AEE707D111DC9F77BA29FD2A9E8FB6E6967212FD5CB22
+IV=63CF21803941B521532FF36F9FBFC7BD
+PT=AB660593FA8A2F63ECA1D46AD6906B6B
+CT=250941C1D45C82B0D9C381293CDD833A
+
+I=318
+KEY=1F875BCF1967857990EC97864B1EA9F8D272E35E06F56A4BB7AAE60813084818
+IV=250941C1D45C82B0D9C381293CDD833A
+PT=1371ABCF2C4CCE21AEA679F6360FB431
+CT=8303B962DAFC4A225C0FD6EA60D29CF4
+
+I=319
+KEY=42FE25BF51418FE7A7C7A1828219E1DB51715A3CDC092069EBA530E273DAD4EC
+IV=8303B962DAFC4A225C0FD6EA60D29CF4
+PT=5D797E7048260A9E372B3604C9074823
+CT=29E2DB359FAB42C0A83A4059A059CB51
+
+I=320
+KEY=6C821A4893FE0EAC88FC1F98BD44AD0A7893810943A262A9439F70BBD3831FBD
+IV=29E2DB359FAB42C0A83A4059A059CB51
+PT=2E7C3FF7C2BF814B2F3BBE1A3F5D4CD1
+CT=02BDB7EC18279FA9B7788D95FEB4000E
+
+I=321
+KEY=411670D389D0A04859FDC26DE5AAD1297A2E36E55B85FD00F4E7FD2E2D371FB3
+IV=02BDB7EC18279FA9B7788D95FEB4000E
+PT=2D946A9B1A2EAEE4D101DDF558EE7C23
+CT=3960A92A34967F13B754F2265A6F68C1
+
+I=322
+KEY=851BCD18F6043DE625BBEA33E1E860E3434E9FCF6F13821343B30F0877587772
+IV=3960A92A34967F13B754F2265A6F68C1
+PT=C40DBDCB7FD49DAE7C46285E0442B1CA
+CT=EF396AB8613AC6083932734D38869458
+
+I=323
+KEY=1944F363F3143A380F26BD4831A6BD9EAC77F5770E29441B7A817C454FDEE32A
+IV=EF396AB8613AC6083932734D38869458
+PT=9C5F3E7B051007DE2A9D577BD04EDD7D
+CT=CB73B8D257CC1A8235E48DA0E6AECC4E
+
+I=324
+KEY=C2F3C203F591C78914E31BA1E083AB9867044DA559E55E994F65F1E5A9702F64
+IV=CB73B8D257CC1A8235E48DA0E6AECC4E
+PT=DBB731600685FDB11BC5A6E9D1251606
+CT=3B0B12757B5D1B6E0130FCC306E9DBAA
+
+I=325
+KEY=0DCB66B972631AFBB1DA22F1418EE1C45C0F5FD022B845F74E550D26AF99F4CE
+IV=3B0B12757B5D1B6E0130FCC306E9DBAA
+PT=CF38A4BA87F2DD72A5393950A10D4A5C
+CT=CCEF4079CE8FAF0E6B8CD4C8751059E1
+
+I=326
+KEY=8FF976D3C735506D86A3540664F1C40590E01FA9EC37EAF925D9D9EEDA89AD2F
+IV=CCEF4079CE8FAF0E6B8CD4C8751059E1
+PT=8232106AB5564A96377976F7257F25C1
+CT=D835D2FA5583D9B2C16424960163DF7F
+
+I=327
+KEY=3499925B26E4F846CAA230EC069F127F48D5CD53B9B4334BE4BDFD78DBEA7250
+IV=D835D2FA5583D9B2C16424960163DF7F
+PT=BB60E488E1D1A82B4C0164EA626ED67A
+CT=4634485DB5D9C40FA2F6EF36E477F0B7
+
+I=328
+KEY=7A133EEC3DD747FE38A3370F8927A3C70EE1850E0C6DF744464B124E3F9D82E7
+IV=4634485DB5D9C40FA2F6EF36E477F0B7
+PT=4E8AACB71B33BFB8F20107E38FB8B1B8
+CT=AE30CD2A5D84CEF10B9C15EE1FE20CEB
+
+I=329
+KEY=F573665345317BAB5F14881777A0D789A0D1482451E939B54DD707A0207F8E0C
+IV=AE30CD2A5D84CEF10B9C15EE1FE20CEB
+PT=8F6058BF78E63C5567B7BF18FE87744E
+CT=B3926CDE5BFB1363DCCA28CDA2DC4CD8
+
+I=330
+KEY=FEFB661FA786BF2DA1B70FD7D06B86E8134324FA0A122AD6911D2F6D82A3C2D4
+IV=B3926CDE5BFB1363DCCA28CDA2DC4CD8
+PT=0B88004CE2B7C486FEA387C0A7CB5161
+CT=633388FA9EAE0DB2036F63CB2E21C266
+
+I=331
+KEY=BFC495DFBA60078708D992724C9201577070AC0094BC276492724CA6AC8200B2
+IV=633388FA9EAE0DB2036F63CB2E21C266
+PT=413FF3C01DE6B8AAA96E9DA59CF987BF
+CT=54ACB838D247D26A1544B2E42F18CF3F
+
+I=332
+KEY=EB0113E4FFE1201B59EAE94706B2571F24DC143846FBF50E8736FE42839ACF8D
+IV=54ACB838D247D26A1544B2E42F18CF3F
+PT=54C5863B4581279C51337B354A205648
+CT=B9210B8A8639CA5C94A1CF1169F89DDB
+
+I=333
+KEY=0E1D5F7873FD6440227C5529AEB4C7999DFD1FB2C0C23F5213973153EA625256
+IV=B9210B8A8639CA5C94A1CF1169F89DDB
+PT=E51C4C9C8C1C445B7B96BC6EA8069086
+CT=8990488561B43B03CF9FE631E2E7D5E7
+
+I=334
+KEY=8B2759471137DBF37906B394EFEF96D2146D5737A1760451DC08D762088587B1
+IV=8990488561B43B03CF9FE631E2E7D5E7
+PT=853A063F62CABFB35B7AE6BD415B514B
+CT=9DCE77D8CCC0F041FA717C28474E9A30
+
+I=335
+KEY=0D4B29E8D6F39CA01BC01CE73E2834C689A320EF6DB6F4102679AB4A4FCB1D81
+IV=9DCE77D8CCC0F041FA717C28474E9A30
+PT=866C70AFC7C4475362C6AF73D1C7A214
+CT=E1DA174FE5848D21735E55B91CA48A9B
+
+I=336
+KEY=55228F6FF93B7DE9304CD75991C133A5687937A0883279315527FEF3536F971A
+IV=E1DA174FE5848D21735E55B91CA48A9B
+PT=5869A6872FC8E1492B8CCBBEAFE90763
+CT=C578F53AD69AD508711E674F8DD2A843
+
+I=337
+KEY=35CA943437046860F72A1F8554127676AD01C29A5EA8AC39243999BCDEBD3F59
+IV=C578F53AD69AD508711E674F8DD2A843
+PT=60E81B5BCE3F1589C766C8DCC5D345D3
+CT=177A50196260D3F0A3F97423899EBEE2
+
+I=338
+KEY=B8C3B8414C112FC2E2E848733D5CF69CBA7B92833CC87FC987C0ED9F572381BB
+IV=177A50196260D3F0A3F97423899EBEE2
+PT=8D092C757B1547A215C257F6694E80EA
+CT=6B03A799C51C7D0A9D3C9929617E69B1
+
+I=339
+KEY=E82B651AE5740119104FE3284CE780E4D178351AF9D402C31AFC74B6365DE80A
+IV=6B03A799C51C7D0A9D3C9929617E69B1
+PT=50E8DD5BA9652EDBF2A7AB5B71BB7678
+CT=8D4C7C1157422E7B6DDA47C5C2C246F4
+
+I=340
+KEY=3C0B660F2B78F768812AC671D3107AD85C34490BAE962CB877263373F49FAEFE
+IV=8D4C7C1157422E7B6DDA47C5C2C246F4
+PT=D4200315CE0CF671916525599FF7FA3C
+CT=787B3C51094569BC1F139102964DF5AF
+
+I=341
+KEY=A197B59C700A4786E840733047964FD4244F755AA7D345046835A27162D25B51
+IV=787B3C51094569BC1F139102964DF5AF
+PT=9D9CD3935B72B0EE696AB5419486350C
+CT=AE02945B4E63AC35B6AC2DFA2DF3CEBA
+
+I=342
+KEY=00E75C4B909D44A94FA20EDA6C3628418A4DE101E9B0E931DE998F8B4F2195EB
+IV=AE02945B4E63AC35B6AC2DFA2DF3CEBA
+PT=A170E9D7E097032FA7E27DEA2BA06795
+CT=AC4AACD3597FE73F519F7CEDAFE6E000
+
+I=343
+KEY=4626BE31853C15DE412EF2A42328D47326074DD2B0CF0E0E8F06F366E0C775EB
+IV=AC4AACD3597FE73F519F7CEDAFE6E000
+PT=46C1E27A15A151770E8CFC7E4F1EFC32
+CT=5EB8B35708A135E041603BA323663F34
+
+I=344
+KEY=1733A037E76437411F49821D948A098978BFFE85B86E3BEECE66C8C5C3A14ADF
+IV=5EB8B35708A135E041603BA323663F34
+PT=51151E066258229F5E6770B9B7A2DDFA
+CT=6674FB922570377334A4F22D13E95BD8
+
+I=345
+KEY=8474275A2E4D5E5448EB8D34B65EE7081ECB05179D1E0C9DFAC23AE8D0481107
+IV=6674FB922570377334A4F22D13E95BD8
+PT=9347876DC929691557A20F2922D4EE81
+CT=F0E3F09C0350C0172E449A01F24AB828
+
+I=346
+KEY=765AA3F4014B8475CF832DE6128F7F2DEE28F58B9E4ECC8AD486A0E92202A92F
+IV=F0E3F09C0350C0172E449A01F24AB828
+PT=F22E84AE2F06DA218768A0D2A4D19825
+CT=CC156010299679ADEE9CC000FD5C90E5
+
+I=347
+KEY=DD3D3AFC83B7EEBC58CE35B35719B587223D959BB7D8B5273A1A60E9DF5E39CA
+IV=CC156010299679ADEE9CC000FD5C90E5
+PT=AB67990882FC6AC9974D18554596CAAA
+CT=80354EDEA10038E903C4896313236CE5
+
+I=348
+KEY=4764BB8C98BCF3FD4A21A370AE5432BBA208DB4516D88DCE39DEE98ACC7D552F
+IV=80354EDEA10038E903C4896313236CE5
+PT=9A5981701B0B1D4112EF96C3F94D873C
+CT=15140DC26F383EB99425FB51D445CC98
+
+I=349
+KEY=DF729AB7D09BC85489F8AD373EBDDA70B71CD68779E0B377ADFB12DB183899B7
+IV=15140DC26F383EB99425FB51D445CC98
+PT=9816213B48273BA9C3D90E4790E9E8CB
+CT=163465787010C97D3C2023D803F62556
+
+I=350
+KEY=A945B0C5997C596B5155A6BCA5055127A128B3FF09F07A0A91DB31031BCEBCE1
+IV=163465787010C97D3C2023D803F62556
+PT=76372A7249E7913FD8AD0B8B9BB88B57
+CT=23E861D557EE72534C8B729240E3A54F
+
+I=351
+KEY=0E1C166F2B947D14D0C7E6ABD280A31E82C0D22A5E1E0859DD5043915B2D19AE
+IV=23E861D557EE72534C8B729240E3A54F
+PT=A759A6AAB2E8247F819240177785F239
+CT=652CA6A199D7DBC37936FCD70636989F
+
+I=352
+KEY=208A37149072011877E3E85B3DC7F4A7E7EC748BC7C9D39AA466BF465D1B8131
+IV=652CA6A199D7DBC37936FCD70636989F
+PT=2E96217BBBE67C0CA7240EF0EF4757B9
+CT=7C29D6F4788553E3C50A48027478A98F
+
+I=353
+KEY=A8FFCB194C077EEED66632AEBE01652E9BC5A27FBF4C8079616CF744296328BE
+IV=7C29D6F4788553E3C50A48027478A98F
+PT=8875FC0DDC757FF6A185DAF583C69189
+CT=7B886FC819D625B224F2516901788E88
+
+I=354
+KEY=3716969BDDBF04FF4010D4667CCA994AE04DCDB7A69AA5CB459EA62D281BA636
+IV=7B886FC819D625B224F2516901788E88
+PT=9FE95D8291B87A119676E6C8C2CBFC64
+CT=3EAB925C025F379153CE2C7191026976
+
+I=355
+KEY=991D0D313717C7AC62537C8572DE094BDEE65FEBA4C5925A16508A5CB919CF40
+IV=3EAB925C025F379153CE2C7191026976
+PT=AE0B9BAAEAA8C3532243A8E30E149001
+CT=B9904B8BDF431FDDB9166086C9D3E24C
+
+I=356
+KEY=315772BB82A3DD286FE5891934B19434677614607B868D87AF46EADA70CA2D0C
+IV=B9904B8BDF431FDDB9166086C9D3E24C
+PT=A84A7F8AB5B41A840DB6F59C466F9D7F
+CT=3C7029336ECCA5D352DB9D0C060D3830
+
+I=357
+KEY=C99E4E6A8C1D42A9E431FF8B2A8ACA615B063D53154A2854FD9D77D676C7153C
+IV=3C7029336ECCA5D352DB9D0C060D3830
+PT=F8C93CD10EBE9F818BD476921E3B5E55
+CT=4AF4290AA79EB96435D2D3FC745033D7
+
+I=358
+KEY=55317B8B407B7D089ED2CEF7BE80E99111F21459B2D49130C84FA42A029726EB
+IV=4AF4290AA79EB96435D2D3FC745033D7
+PT=9CAF35E1CC663FA17AE3317C940A23F0
+CT=BFCA0B6B31AAD81F1BDC743B48B7CCA4
+
+I=359
+KEY=6EAE6D8B06AA25493BA3608357D71404AE381F32837E492FD393D0114A20EA4F
+IV=BFCA0B6B31AAD81F1BDC743B48B7CCA4
+PT=3B9F160046D15841A571AE74E957FD95
+CT=89C1D565569A12A68B2E808AB5CFA2E3
+
+I=360
+KEY=3245D7C1F5571A1329E1B2303F8A689D27F9CA57D5E45B8958BD509BFFEF48AC
+IV=89C1D565569A12A68B2E808AB5CFA2E3
+PT=5CEBBA4AF3FD3F5A1242D2B3685D7C99
+CT=EC8EEAED7894646B1D1A5E058ED41178
+
+I=361
+KEY=1DE05811428569D3F89CF1C01AF434AFCB7720BAAD703FE245A70E9E713B59D4
+IV=EC8EEAED7894646B1D1A5E058ED41178
+PT=2FA58FD0B7D273C0D17D43F0257E5C32
+CT=92802F392579C66AD72D2E85776720E8
+
+I=362
+KEY=0A8FB6D844AB0B73C05A121085E07FFE59F70F838809F988928A201B065C793C
+IV=92802F392579C66AD72D2E85776720E8
+PT=176FEEC9062E62A038C6E3D09F144B51
+CT=461DBCF9894F5319FE772F6529FBCEC0
+
+I=363
+KEY=4E6818B3BBEF69FA7ABEC1EBE2E54CDC1FEAB37A0146AA916CFD0F7E2FA7B7FC
+IV=461DBCF9894F5319FE772F6529FBCEC0
+PT=44E7AE6BFF446289BAE4D3FB67053322
+CT=794CA9DC41BAE95D415A6D1119582763
+
+I=364
+KEY=4A1EABB13924B188441724141F1C88A966A61AA640FC43CC2DA7626F36FF909F
+IV=794CA9DC41BAE95D415A6D1119582763
+PT=0476B30282CBD8723EA9E5FFFDF9C475
+CT=B761EAF5CC07651BD33D8BF93913EAE8
+
+I=365
+KEY=FFE4E48F8D96710A1BE7DBE36F4905CDD1C7F0538CFB26D7FE9AE9960FEC7A77
+IV=B761EAF5CC07651BD33D8BF93913EAE8
+PT=B5FA4F3EB4B2C0825FF0FFF770558D64
+CT=0B5146EB77161E60D6D1E2FAEAE80694
+
+I=366
+KEY=7A4F383AF4BB2DC6588E75EE82C7D9CFDA96B6B8FBED38B7284B0B6CE5047CE3
+IV=0B5146EB77161E60D6D1E2FAEAE80694
+PT=85ABDCB5792D5CCC4369AE0DED8EDC02
+CT=07635064CE85F6AE17961AF1F2B44469
+
+I=367
+KEY=EFFE7F8BBBEC8BEC83FA199102763BEDDDF5E6DC3568CE193FDD119D17B0388A
+IV=07635064CE85F6AE17961AF1F2B44469
+PT=95B147B14F57A62ADB746C7F80B1E222
+CT=3A9CD5F30C421FF333BA2C2F0A7AD07D
+
+I=368
+KEY=1DF51B7A35E11E2AF79E8C59094A1ECFE769332F392AD1EA0C673DB21DCAE8F7
+IV=3A9CD5F30C421FF333BA2C2F0A7AD07D
+PT=F20B64F18E0D95C6746495C80B3C2522
+CT=F60032C249CF561CB02421DA189A57D1
+
+I=369
+KEY=CC09FFE72A10AE27FE14934A6628AB83116901ED70E587F6BC431C680550BF26
+IV=F60032C249CF561CB02421DA189A57D1
+PT=D1FCE49D1FF1B00D098A1F136F62B54C
+CT=EAD5844B160C08F9CDAA15FD5936EF26
+
+I=370
+KEY=09C84CA0DA0B9FD79D3090E690BAB419FBBC85A666E98F0F71E909955C665000
+IV=EAD5844B160C08F9CDAA15FD5936EF26
+PT=C5C1B347F01B31F0632403ACF6921F9A
+CT=26AD72F011133FD4CED8F38A1ABE7D73
+
+I=371
+KEY=74FA53C172A2003EC5933F486FCC7BBFDD11F75677FAB0DBBF31FA1F46D82D73
+IV=26AD72F011133FD4CED8F38A1ABE7D73
+PT=7D321F61A8A99FE958A3AFAEFF76CFA6
+CT=F115FBC0D3F386527176D1DF6AD4B38A
+
+I=372
+KEY=0E5BA209B7BC28D184E73BD37F35C1312C040C96A4093689CE472BC02C0C9EF9
+IV=F115FBC0D3F386527176D1DF6AD4B38A
+PT=7AA1F1C8C51E28EF4174049B10F9BA8E
+CT=27ED0BA04734E70317BF58E11B0DD051
+
+I=373
+KEY=9404D9139B6597D1F7C7519713C6CBC80BE90736E33DD18AD9F8732137014EA8
+IV=27ED0BA04734E70317BF58E11B0DD051
+PT=9A5F7B1A2CD9BF0073206A446CF30AF9
+CT=24080A577426F8F270A13F3A5F3DB546
+
+I=374
+KEY=E72476BC679C8DCBAB92BBA5D48BF6D32FE10D61971B2978A9594C1B683CFBEE
+IV=24080A577426F8F270A13F3A5F3DB546
+PT=7320AFAFFCF91A1A5C55EA32C74D3D1B
+CT=A754CC0464E35B387435790505F2DCE5
+
+I=375
+KEY=4548DE389CCAD4A65B02A9B5FE90930188B5C165F3F87240DD6C351E6DCE270B
+IV=A754CC0464E35B387435790505F2DCE5
+PT=A26CA884FB56596DF09012102A1B65D2
+CT=D9AED2566884E97D081EADB45780AA7D
+
+I=376
+KEY=2E54365B503140D0EC9074DFA05F4B2C511B13339B7C9B3DD57298AA3A4E8D76
+IV=D9AED2566884E97D081EADB45780AA7D
+PT=6B1CE863CCFB9476B792DD6A5ECFD82D
+CT=9FA221E082CAD838AB4B210A8794BD8F
+
+I=377
+KEY=7C9FB092B8A96465076E14C575E9A8F0CEB932D319B643057E39B9A0BDDA30F9
+IV=9FA221E082CAD838AB4B210A8794BD8F
+PT=52CB86C9E89824B5EBFE601AD5B6E3DC
+CT=AAEA6DE5734CF14BED503512EB071C2A
+
+I=378
+KEY=90AB85A18F2B0255D4F43AF5E98DAA7E64535F366AFAB24E93698CB256DD2CD3
+IV=AAEA6DE5734CF14BED503512EB071C2A
+PT=EC34353337826630D39A2E309C64028E
+CT=1359A157B415EB63E038AB7354E6B0F2
+
+I=379
+KEY=9135D4D54A1CE6BBF4F23AFDE23F537C770AFE61DEEF592D735127C1023B9C21
+IV=1359A157B415EB63E038AB7354E6B0F2
+PT=019E5174C537E4EE200600080BB2F902
+CT=0764EBDBFAE8FD447244408A5153CC3B
+
+I=380
+KEY=4B5F1BC60EF5DCE83474A3970EB2ABA8706E15BA2407A4690115674B5368501A
+IV=0764EBDBFAE8FD447244408A5153CC3B
+PT=DA6ACF1344E93A53C086996AEC8DF8D4
+CT=A31F69E0055E8D4162AC06C088925FBA
+
+I=381
+KEY=9DD8E8D75BE2E4D1BC70B30DAE0B375FD3717C5A2159292863B9618BDBFA0FA0
+IV=A31F69E0055E8D4162AC06C088925FBA
+PT=D687F311551738398804109AA0B99CF7
+CT=EB84AC035534CDF1698E660F529E0EC7
+
+I=382
+KEY=4A2B2FC8446B4C2575CFE584A490680238F5D059746DE4D90A37078489640167
+IV=EB84AC035534CDF1698E660F529E0EC7
+PT=D7F3C71F1F89A8F4C9BF56890A9B5F5D
+CT=9236D37A28C2CF29237127173B93C5D5
+
+I=383
+KEY=9BE42576823EEAADB34657A5CBB44B21AAC303235CAF2BF029462093B2F7C4B2
+IV=9236D37A28C2CF29237127173B93C5D5
+PT=D1CF0ABEC655A688C689B2216F242323
+CT=86C122CFA62B1356FEE33FECF598ACC9
+
+I=384
+KEY=5DFC1838B052E95A948D0AC31736CBE62C0221ECFA8438A6D7A51F7F476F687B
+IV=86C122CFA62B1356FEE33FECF598ACC9
+PT=C6183D4E326C03F727CB5D66DC8280C7
+CT=8A9926125B1CA354B1D7A9FED0850FEE
+
+I=385
+KEY=2B12FA914EE7674EADED81C47A67A1B4A69B07FEA1989BF26672B68197EA6795
+IV=8A9926125B1CA354B1D7A9FED0850FEE
+PT=76EEE2A9FEB58E1439608B076D516A52
+CT=AD99A2A427BFF7A17C375DB38764EBFC
+
+I=386
+KEY=10607DE088CB92382089EF99B7C054280B02A55A86276C531A45EB32108E8C69
+IV=AD99A2A427BFF7A17C375DB38764EBFC
+PT=3B728771C62CF5768D646E5DCDA7F59C
+CT=0E141FD7D6928E7B7885638B6334947C
+
+I=387
+KEY=605ECCB38F9FFD9DAB2DB523313FFADB0516BA8D50B5E22862C088B973BA1815
+IV=0E141FD7D6928E7B7885638B6334947C
+PT=703EB15307546FA58BA45ABA86FFAEF3
+CT=996CB8723B08B99A4959072DC8A73292
+
+I=388
+KEY=C6371257BDA461F3A4D2F1ED5DD4B0B69C7A02FF6BBD5BB22B998F94BB1D2A87
+IV=996CB8723B08B99A4959072DC8A73292
+PT=A669DEE4323B9C6E0FFF44CE6CEB4A6D
+CT=72966BAA5E4D7FA9129088F2C072E301
+
+I=389
+KEY=DDD8877C25005F9B8336823CBF4D4B1DEEEC695535F0241B390907667B6FC986
+IV=72966BAA5E4D7FA9129088F2C072E301
+PT=1BEF952B98A43E6827E473D1E299FBAB
+CT=32C321C999A2D68EA4517D332C785FC4
+
+I=390
+KEY=00882DCBC6CFDED1A2ED7D9892F494A5DC2F489CAC52F2959D587A5557179642
+IV=32C321C999A2D68EA4517D332C785FC4
+PT=DD50AAB7E3CF814A21DBFFA42DB9DFB8
+CT=391D95DD63982E0A9AF3980A234DB5B9
+
+I=391
+KEY=234B9097BD6519EFE106103720AC937DE532DD41CFCADC9F07ABE25F745A23FB
+IV=391D95DD63982E0A9AF3980A234DB5B9
+PT=23C3BD5C7BAAC73E43EB6DAFB25807D8
+CT=D3A279EE1BABABA71DB01DC35EBA879D
+
+I=392
+KEY=AFF7D52D959CC7E41F1F3FF3CA2425053690A4AFD46177381A1BFF9C2AE0A466
+IV=D3A279EE1BABABA71DB01DC35EBA879D
+PT=8CBC45BA28F9DE0BFE192FC4EA88B678
+CT=B4696871EE3A9D035BC32308DA5A5DA7
+
+I=393
+KEY=B557440CEEB6E4EF54F6CD1B222246AC82F9CCDE3A5BEA3B41D8DC94F0BAF9C1
+IV=B4696871EE3A9D035BC32308DA5A5DA7
+PT=1AA091217B2A230B4BE9F2E8E80663A9
+CT=C5047AFD7884E0124928229AA6E72F67
+
+I=394
+KEY=BF64C071FAAD2C48CB269C03563FA06147FDB62342DF0A2908F0FE0E565DD6A6
+IV=C5047AFD7884E0124928229AA6E72F67
+PT=0A33847D141BC8A79FD05118741DE6CD
+CT=240D684E6BAD3FD4E41D58DB871E93CD
+
+I=395
+KEY=F6945509258A1584398F5438DFD679DB63F0DE6D297235FDECEDA6D5D143456B
+IV=240D684E6BAD3FD4E41D58DB871E93CD
+PT=49F09578DF2739CCF2A9C83B89E9D9BA
+CT=F66917F0C3C67774F9263062F918DDD5
+
+I=396
+KEY=A8E48107D59287ABBA374E7CE5BC28E89599C99DEAB4428915CB96B7285B98BE
+IV=F66917F0C3C67774F9263062F918DDD5
+PT=5E70D40EF018922F83B81A443A6A5133
+CT=85C42456F11D0191BC4B4DD4EA0406EE
+
+I=397
+KEY=E4F367569F4F9114AFE937A0190C9738105DEDCB1BA94318A980DB63C25F9E50
+IV=85C42456F11D0191BC4B4DD4EA0406EE
+PT=4C17E6514ADD16BF15DE79DCFCB0BFD0
+CT=D48B6C87A25C71113947569411C2186A
+
+I=398
+KEY=987ED2D586DA9AB08C584BBEA0478953C4D6814CB9F5320990C78DF7D39D863A
+IV=D48B6C87A25C71113947569411C2186A
+PT=7C8DB58319950BA423B17C1EB94B1E6B
+CT=AB6957C2F3D360593E9096F3A392A701
+
+I=399
+KEY=3DF2BF13B7FF97CA13567A890E11C9796FBFD68E4A265250AE571B04700F213B
+IV=AB6957C2F3D360593E9096F3A392A701
+PT=A58C6DC631250D7A9F0E3137AE56402A
+CT=C0FEFFF07506A0B4CD7B8B0CF25D3664
+
+===========
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/test/ecb_d_m.txt b/mechglue/src/lib/crypto/aes/test/ecb_d_m.txt
new file mode 100644
index 000000000..d99a69af3
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/ecb_d_m.txt
@@ -0,0 +1,6024 @@
+
+=========================
+
+FILENAME:  "ecb_d_m.txt"
+
+Electronic Codebook (ECB) Mode - DECRYPTION
+Monte Carlo Test
+
+Algorithm Name: Rijndael
+Principal Submitter: Joan Daemen
+
+=========================
+
+KEYSIZE=128
+
+I=0
+KEY=00000000000000000000000000000000
+CT=00000000000000000000000000000000
+PT=44416AC2D1F53C583303917E6BE9EBE0
+
+I=1
+KEY=44416AC2D1F53C583303917E6BE9EBE0
+CT=44416AC2D1F53C583303917E6BE9EBE0
+PT=E3FD51123B48A2E2AB1DB29894202222
+
+I=2
+KEY=A7BC3BD0EABD9EBA981E23E6FFC9C9C2
+CT=E3FD51123B48A2E2AB1DB29894202222
+PT=877B88A77AEF04F05546539E17259F53
+
+I=3
+KEY=20C7B37790529A4ACD587078E8EC5691
+CT=877B88A77AEF04F05546539E17259F53
+PT=C7A71C1B46261602EB1EE48FDA8155A4
+
+I=4
+KEY=E760AF6CD6748C48264694F7326D0335
+CT=C7A71C1B46261602EB1EE48FDA8155A4
+PT=6B6AC8E00FAF7E045ECCFC426A137221
+
+I=5
+KEY=8C0A678CD9DBF24C788A68B5587E7114
+CT=6B6AC8E00FAF7E045ECCFC426A137221
+PT=3F252821FA79AFC3F1798B343AAD41EE
+
+I=6
+KEY=B32F4FAD23A25D8F89F3E38162D330FA
+CT=3F252821FA79AFC3F1798B343AAD41EE
+PT=0B55C691E1F97205D137FF34478E5BC9
+
+I=7
+KEY=B87A893CC25B2F8A58C41CB5255D6B33
+CT=0B55C691E1F97205D137FF34478E5BC9
+PT=F6CCC1CC18A3199D6427EDCA0BB2DF90
+
+I=8
+KEY=4EB648F0DAF836173CE3F17F2EEFB4A3
+CT=F6CCC1CC18A3199D6427EDCA0BB2DF90
+PT=0CDD7D9734B1515C73DDA60EFF28CD89
+
+I=9
+KEY=426B3567EE49674B4F3E5771D1C7792A
+CT=0CDD7D9734B1515C73DDA60EFF28CD89
+PT=3E813131EDD440D9054799CEA508FF6F
+
+I=10
+KEY=7CEA0456039D27924A79CEBF74CF8645
+CT=3E813131EDD440D9054799CEA508FF6F
+PT=8C6859BD0B6E078FAA6B686297653232
+
+I=11
+KEY=F0825DEB08F3201DE012A6DDE3AAB477
+CT=8C6859BD0B6E078FAA6B686297653232
+PT=C966A4106C1DCE062D1346EB5E5133BB
+
+I=12
+KEY=39E4F9FB64EEEE1BCD01E036BDFB87CC
+CT=C966A4106C1DCE062D1346EB5E5133BB
+PT=4F4AE38B53FD7800F0E9F5C214E16F2A
+
+I=13
+KEY=76AE1A703713961B3DE815F4A91AE8E6
+CT=4F4AE38B53FD7800F0E9F5C214E16F2A
+PT=C73A033491DC0B6A77FEA2FBCC9D305E
+
+I=14
+KEY=B1941944A6CF9D714A16B70F6587D8B8
+CT=C73A033491DC0B6A77FEA2FBCC9D305E
+PT=C928C2A05BB44816EFBE6B13E94BC70E
+
+I=15
+KEY=78BCDBE4FD7BD567A5A8DC1C8CCC1FB6
+CT=C928C2A05BB44816EFBE6B13E94BC70E
+PT=A7C1593E7B4BAEE5256D4081337E7CAF
+
+I=16
+KEY=DF7D82DA86307B8280C59C9DBFB26319
+CT=A7C1593E7B4BAEE5256D4081337E7CAF
+PT=7ECD305AC27AEBFA2B8F85F9AC312638
+
+I=17
+KEY=A1B0B280444A9078AB4A196413834521
+CT=7ECD305AC27AEBFA2B8F85F9AC312638
+PT=A24D1403A58B94798F5F3565ABFD3B44
+
+I=18
+KEY=03FDA683E1C1040124152C01B87E7E65
+CT=A24D1403A58B94798F5F3565ABFD3B44
+PT=5B6E097B3B0E21DCC9CE9970701C7BD5
+
+I=19
+KEY=5893AFF8DACF25DDEDDBB571C86205B0
+CT=5B6E097B3B0E21DCC9CE9970701C7BD5
+PT=4E21CEA52B3111AC8F6B204A1F5E65E2
+
+I=20
+KEY=16B2615DF1FE347162B0953BD73C6052
+CT=4E21CEA52B3111AC8F6B204A1F5E65E2
+PT=806DDC5C37ADEEBB6FCE4730939D7A99
+
+I=21
+KEY=96DFBD01C653DACA0D7ED20B44A11ACB
+CT=806DDC5C37ADEEBB6FCE4730939D7A99
+PT=3462F7C6D3E071A0D3ACE7FD79149776
+
+I=22
+KEY=A2BD4AC715B3AB6ADED235F63DB58DBD
+CT=3462F7C6D3E071A0D3ACE7FD79149776
+PT=AF0FFF307B72284E794C8A64C30299D2
+
+I=23
+KEY=0DB2B5F76EC18324A79EBF92FEB7146F
+CT=AF0FFF307B72284E794C8A64C30299D2
+PT=E482B613FBCF9C4422D85E3160B1FB0F
+
+I=24
+KEY=E93003E4950E1F608546E1A39E06EF60
+CT=E482B613FBCF9C4422D85E3160B1FB0F
+PT=FADC8EF9C95540AD69897DECAB2D50D5
+
+I=25
+KEY=13EC8D1D5C5B5FCDECCF9C4F352BBFB5
+CT=FADC8EF9C95540AD69897DECAB2D50D5
+PT=2A765E237FB5230D792D455596A17118
+
+I=26
+KEY=399AD33E23EE7CC095E2D91AA38ACEAD
+CT=2A765E237FB5230D792D455596A17118
+PT=0887DA8012C7F95BD6ADB18D1ED3C2DB
+
+I=27
+KEY=311D09BE3129859B434F6897BD590C76
+CT=0887DA8012C7F95BD6ADB18D1ED3C2DB
+PT=3BB831A7B6FAC3649176471012FAD1C1
+
+I=28
+KEY=0AA5381987D346FFD2392F87AFA3DDB7
+CT=3BB831A7B6FAC3649176471012FAD1C1
+PT=E4F8629AB3489A0945B8B7188B953DE5
+
+I=29
+KEY=EE5D5A83349BDCF69781989F2436E052
+CT=E4F8629AB3489A0945B8B7188B953DE5
+PT=1D4B0B5B321EB711939AB481239E2541
+
+I=30
+KEY=F31651D806856BE7041B2C1E07A8C513
+CT=1D4B0B5B321EB711939AB481239E2541
+PT=71A368D5A33665D6FF9F33FECAFC6884
+
+I=31
+KEY=82B5390DA5B30E31FB841FE0CD54AD97
+CT=71A368D5A33665D6FF9F33FECAFC6884
+PT=8ACF418080075BA23B05A52552773B84
+
+I=32
+KEY=087A788D25B45593C081BAC59F239613
+CT=8ACF418080075BA23B05A52552773B84
+PT=E0E6058735F4FE765E882521D769FB41
+
+I=33
+KEY=E89C7D0A1040ABE59E099FE4484A6D52
+CT=E0E6058735F4FE765E882521D769FB41
+PT=70DCE91F818DF2CDC4269F1B4EA0A465
+
+I=34
+KEY=9840941591CD59285A2F00FF06EAC937
+CT=70DCE91F818DF2CDC4269F1B4EA0A465
+PT=E2F809D6DD77D72EF6DB5A82C42BF1CF
+
+I=35
+KEY=7AB89DC34CBA8E06ACF45A7DC2C138F8
+CT=E2F809D6DD77D72EF6DB5A82C42BF1CF
+PT=0741D11DDD877957E753ECF8DB91C72B
+
+I=36
+KEY=7DF94CDE913DF7514BA7B6851950FFD3
+CT=0741D11DDD877957E753ECF8DB91C72B
+PT=03E411012CA3B5B3CC163677D4B52456
+
+I=37
+KEY=7E1D5DDFBD9E42E287B180F2CDE5DB85
+CT=03E411012CA3B5B3CC163677D4B52456
+PT=0270D90790EF8347ACFB87EB2FEC2710
+
+I=38
+KEY=7C6D84D82D71C1A52B4A0719E209FC95
+CT=0270D90790EF8347ACFB87EB2FEC2710
+PT=3AE40270512374AF4022638E0A7A6D8E
+
+I=39
+KEY=468986A87C52B50A6B686497E873911B
+CT=3AE40270512374AF4022638E0A7A6D8E
+PT=8008D87E928A980FECA08CAF1EC91DDA
+
+I=40
+KEY=C6815ED6EED82D0587C8E838F6BA8CC1
+CT=8008D87E928A980FECA08CAF1EC91DDA
+PT=1D479A54832FF1A81D30008EFDF16A34
+
+I=41
+KEY=DBC6C4826DF7DCAD9AF8E8B60B4BE6F5
+CT=1D479A54832FF1A81D30008EFDF16A34
+PT=9E731FECD9A767BDA0C84B4C4D552BD3
+
+I=42
+KEY=45B5DB6EB450BB103A30A3FA461ECD26
+CT=9E731FECD9A767BDA0C84B4C4D552BD3
+PT=C2211A6B16CD27C6C73A5C3C1A0132AC
+
+I=43
+KEY=8794C105A29D9CD6FD0AFFC65C1FFF8A
+CT=C2211A6B16CD27C6C73A5C3C1A0132AC
+PT=7E523DD6F25706F971F020F88FFA0CF7
+
+I=44
+KEY=F9C6FCD350CA9A2F8CFADF3ED3E5F37D
+CT=7E523DD6F25706F971F020F88FFA0CF7
+PT=0EDC01C6C1A8DA6A7C9EEE3587CB098E
+
+I=45
+KEY=F71AFD1591624045F064310B542EFAF3
+CT=0EDC01C6C1A8DA6A7C9EEE3587CB098E
+PT=EE479106871DA872632794633B1ACF0E
+
+I=46
+KEY=195D6C13167FE8379343A5686F3435FD
+CT=EE479106871DA872632794633B1ACF0E
+PT=7EC1A4578D911F336184DACCCA92D943
+
+I=47
+KEY=679CC8449BEEF704F2C77FA4A5A6ECBE
+CT=7EC1A4578D911F336184DACCCA92D943
+PT=53715F25AE02513F181E3DECBB007803
+
+I=48
+KEY=34ED976135ECA63BEAD942481EA694BD
+CT=53715F25AE02513F181E3DECBB007803
+PT=304D5764B5206F8204A69D1BED11FA62
+
+I=49
+KEY=04A0C00580CCC9B9EE7FDF53F3B76EDF
+CT=304D5764B5206F8204A69D1BED11FA62
+PT=5A7590ADEF208BFD808499A2BFE9B011
+
+I=50
+KEY=5ED550A86FEC42446EFB46F14C5EDECE
+CT=5A7590ADEF208BFD808499A2BFE9B011
+PT=2502C0F68A721A93ECE8D7B6C2097BA4
+
+I=51
+KEY=7BD7905EE59E58D7821391478E57A56A
+CT=2502C0F68A721A93ECE8D7B6C2097BA4
+PT=1C814E26A6464086D606C7B4C6DFD85B
+
+I=52
+KEY=6756DE7843D81851541556F348887D31
+CT=1C814E26A6464086D606C7B4C6DFD85B
+PT=9D55D6EA99BA391190068205DD9AE69C
+
+I=53
+KEY=FA030892DA622140C413D4F695129BAD
+CT=9D55D6EA99BA391190068205DD9AE69C
+PT=9D1212D0BD8C26422EEFF4DDB16B2EF3
+
+I=54
+KEY=67111A4267EE0702EAFC202B2479B55E
+CT=9D1212D0BD8C26422EEFF4DDB16B2EF3
+PT=54DF71E70141E1712449CDC1AC7D07F6
+
+I=55
+KEY=33CE6BA566AFE673CEB5EDEA8804B2A8
+CT=54DF71E70141E1712449CDC1AC7D07F6
+PT=AF3DE6F3510978928C129CFC19FB29B4
+
+I=56
+KEY=9CF38D5637A69EE142A7711691FF9B1C
+CT=AF3DE6F3510978928C129CFC19FB29B4
+PT=830DB7014774C7DF870C8456BC0162AB
+
+I=57
+KEY=1FFE3A5770D2593EC5ABF5402DFEF9B7
+CT=830DB7014774C7DF870C8456BC0162AB
+PT=6606C0A36A18BEFF33485F95B82C30E7
+
+I=58
+KEY=79F8FAF41ACAE7C1F6E3AAD595D2C950
+CT=6606C0A36A18BEFF33485F95B82C30E7
+PT=4B1E64672B89056DF693E73B419E786E
+
+I=59
+KEY=32E69E933143E2AC00704DEED44CB13E
+CT=4B1E64672B89056DF693E73B419E786E
+PT=1877DEEAFF10A5A3F5E9A811BF7595BA
+
+I=60
+KEY=2A914079CE53470FF599E5FF6B392484
+CT=1877DEEAFF10A5A3F5E9A811BF7595BA
+PT=A11A48215BF59CC53BC8A009DCA3973D
+
+I=61
+KEY=8B8B085895A6DBCACE5145F6B79AB3B9
+CT=A11A48215BF59CC53BC8A009DCA3973D
+PT=E80535676DE8898A3624B8127EC21024
+
+I=62
+KEY=638E3D3FF84E5240F875FDE4C958A39D
+CT=E80535676DE8898A3624B8127EC21024
+PT=E2977A804EC9A8B03C85234AD3A95B52
+
+I=63
+KEY=811947BFB687FAF0C4F0DEAE1AF1F8CF
+CT=E2977A804EC9A8B03C85234AD3A95B52
+PT=D776D8BF13F736483862328571C06C61
+
+I=64
+KEY=566F9F00A570CCB8FC92EC2B6B3194AE
+CT=D776D8BF13F736483862328571C06C61
+PT=3AF7969F3247A0914037209556997164
+
+I=65
+KEY=6C98099F97376C29BCA5CCBE3DA8E5CA
+CT=3AF7969F3247A0914037209556997164
+PT=4F87DDC715CEE3A9D67645AD920DF74A
+
+I=66
+KEY=231FD45882F98F806AD38913AFA51280
+CT=4F87DDC715CEE3A9D67645AD920DF74A
+PT=9E88CA52E6B0C160E52B23F36882DBA1
+
+I=67
+KEY=BD971E0A64494EE08FF8AAE0C727C921
+CT=9E88CA52E6B0C160E52B23F36882DBA1
+PT=CAD26E5881D9D4E52C7595C773E0FDAB
+
+I=68
+KEY=77457052E5909A05A38D3F27B4C7348A
+CT=CAD26E5881D9D4E52C7595C773E0FDAB
+PT=C2D0B3D713CFCA5ABB7B9DED14429F37
+
+I=69
+KEY=B595C385F65F505F18F6A2CAA085ABBD
+CT=C2D0B3D713CFCA5ABB7B9DED14429F37
+PT=DD7AADA7524A4878F7C598C4CBCD9CAB
+
+I=70
+KEY=68EF6E22A4151827EF333A0E6B483716
+CT=DD7AADA7524A4878F7C598C4CBCD9CAB
+PT=A0F33B1FCC3F4A4B0982F0823C4ED3C9
+
+I=71
+KEY=C81C553D682A526CE6B1CA8C5706E4DF
+CT=A0F33B1FCC3F4A4B0982F0823C4ED3C9
+PT=B22BB23CD68E8779A8C0FC9A350CB756
+
+I=72
+KEY=7A37E701BEA4D5154E713616620A5389
+CT=B22BB23CD68E8779A8C0FC9A350CB756
+PT=EA4D96AC54BD8387AD36AC8C855A9D44
+
+I=73
+KEY=907A71ADEA195692E3479A9AE750CECD
+CT=EA4D96AC54BD8387AD36AC8C855A9D44
+PT=A3B90CFDE355723BC94999784534FA74
+
+I=74
+KEY=33C37D50094C24A92A0E03E2A26434B9
+CT=A3B90CFDE355723BC94999784534FA74
+PT=55636C86A64383768CB948FF57B29322
+
+I=75
+KEY=66A011D6AF0FA7DFA6B74B1DF5D6A79B
+CT=55636C86A64383768CB948FF57B29322
+PT=B29CCDFD8E7BE50892F0D77DD969F97E
+
+I=76
+KEY=D43CDC2B217442D734479C602CBF5EE5
+CT=B29CCDFD8E7BE50892F0D77DD969F97E
+PT=9CF0432822EABDF489B57EDD9CEF7FEA
+
+I=77
+KEY=48CC9F03039EFF23BDF2E2BDB050210F
+CT=9CF0432822EABDF489B57EDD9CEF7FEA
+PT=AA753B7D38E807D691005899385DC6DA
+
+I=78
+KEY=E2B9A47E3B76F8F52CF2BA24880DE7D5
+CT=AA753B7D38E807D691005899385DC6DA
+PT=E4F0681527FA7AD3D1E7C78C03FB79FA
+
+I=79
+KEY=0649CC6B1C8C8226FD157DA88BF69E2F
+CT=E4F0681527FA7AD3D1E7C78C03FB79FA
+PT=7923AF8E50F378B9C97D2F162348025B
+
+I=80
+KEY=7F6A63E54C7FFA9F346852BEA8BE9C74
+CT=7923AF8E50F378B9C97D2F162348025B
+PT=3BEFAB920CA31A6B8B87E11DF97B42DE
+
+I=81
+KEY=4485C87740DCE0F4BFEFB3A351C5DEAA
+CT=3BEFAB920CA31A6B8B87E11DF97B42DE
+PT=4661D6B8004611976A21C69804D102C0
+
+I=82
+KEY=02E41ECF409AF163D5CE753B5514DC6A
+CT=4661D6B8004611976A21C69804D102C0
+PT=B861DF2279F2AEE4FCFD7D322AD0BE2B
+
+I=83
+KEY=BA85C1ED39685F87293308097FC46241
+CT=B861DF2279F2AEE4FCFD7D322AD0BE2B
+PT=1785745618A541F9454443FFB494F2E9
+
+I=84
+KEY=AD00B5BB21CD1E7E6C774BF6CB5090A8
+CT=1785745618A541F9454443FFB494F2E9
+PT=AA7507A80B4CCF33E8B4F09E2D7004F6
+
+I=85
+KEY=0775B2132A81D14D84C3BB68E620945E
+CT=AA7507A80B4CCF33E8B4F09E2D7004F6
+PT=433412B8F10F81A557AC461823097FC7
+
+I=86
+KEY=4441A0ABDB8E50E8D36FFD70C529EB99
+CT=433412B8F10F81A557AC461823097FC7
+PT=EC3206BDB3765876B74952C411D40373
+
+I=87
+KEY=A873A61668F8089E6426AFB4D4FDE8EA
+CT=EC3206BDB3765876B74952C411D40373
+PT=F7F994027D328FA3D70C9DEABD3BE733
+
+I=88
+KEY=5F8A321415CA873DB32A325E69C60FD9
+CT=F7F994027D328FA3D70C9DEABD3BE733
+PT=E2A8419BF86A2408ED8D0274A5CE0E10
+
+I=89
+KEY=BD22738FEDA0A3355EA7302ACC0801C9
+CT=E2A8419BF86A2408ED8D0274A5CE0E10
+PT=80FB8CD5243C89D77F503B2F16979F90
+
+I=90
+KEY=3DD9FF5AC99C2AE221F70B05DA9F9E59
+CT=80FB8CD5243C89D77F503B2F16979F90
+PT=F7773137F233AE2609C2C9AC36F58224
+
+I=91
+KEY=CAAECE6D3BAF84C42835C2A9EC6A1C7D
+CT=F7773137F233AE2609C2C9AC36F58224
+PT=F3D0A1DADA4A009E8E4C0EF717469BCD
+
+I=92
+KEY=397E6FB7E1E5845AA679CC5EFB2C87B0
+CT=F3D0A1DADA4A009E8E4C0EF717469BCD
+PT=0AC0FF22EB653A26A3F1F0CFE3808609
+
+I=93
+KEY=33BE90950A80BE7C05883C9118AC01B9
+CT=0AC0FF22EB653A26A3F1F0CFE3808609
+PT=28FF865CE11720BB1B56EF49D7D1840D
+
+I=94
+KEY=1B4116C9EB979EC71EDED3D8CF7D85B4
+CT=28FF865CE11720BB1B56EF49D7D1840D
+PT=001FAF58E22F5E8ED6BCC7FD581D7C2F
+
+I=95
+KEY=1B5EB99109B8C049C86214259760F99B
+CT=001FAF58E22F5E8ED6BCC7FD581D7C2F
+PT=32B41303A58AB49CB4CB2322B77383B3
+
+I=96
+KEY=29EAAA92AC3274D57CA9370720137A28
+CT=32B41303A58AB49CB4CB2322B77383B3
+PT=9C52020FCDE0306C8E19CDF68FEFDF50
+
+I=97
+KEY=B5B8A89D61D244B9F2B0FAF1AFFCA578
+CT=9C52020FCDE0306C8E19CDF68FEFDF50
+PT=2E3452997687D12E3A8C59B9178B09E2
+
+I=98
+KEY=9B8CFA0417559597C83CA348B877AC9A
+CT=2E3452997687D12E3A8C59B9178B09E2
+PT=872CF16DBB7CD6EA8EBB91A60BDE0C6F
+
+I=99
+KEY=1CA00B69AC29437D468732EEB3A9A0F5
+CT=872CF16DBB7CD6EA8EBB91A60BDE0C6F
+PT=7862C78E3B209535E6C6BE92F5EDF42B
+
+I=100
+KEY=64C2CCE79709D648A0418C7C464454DE
+CT=7862C78E3B209535E6C6BE92F5EDF42B
+PT=9185D8487C1D2DB679A52FDA2FE5FFCD
+
+I=101
+KEY=F54714AFEB14FBFED9E4A3A669A1AB13
+CT=9185D8487C1D2DB679A52FDA2FE5FFCD
+PT=77C3AF8C81CDB1CDEF5C0429CF3E5DA4
+
+I=102
+KEY=8284BB236AD94A3336B8A78FA69FF6B7
+CT=77C3AF8C81CDB1CDEF5C0429CF3E5DA4
+PT=6F36C74290EA6332E98CD23D08AEF7F9
+
+I=103
+KEY=EDB27C61FA332901DF3475B2AE31014E
+CT=6F36C74290EA6332E98CD23D08AEF7F9
+PT=4A7831538FA1D32E3F8631BEFD99AA73
+
+I=104
+KEY=A7CA4D327592FA2FE0B2440C53A8AB3D
+CT=4A7831538FA1D32E3F8631BEFD99AA73
+PT=5D2B599D9AF9054A99C25577C9286C9E
+
+I=105
+KEY=FAE114AFEF6BFF657970117B9A80C7A3
+CT=5D2B599D9AF9054A99C25577C9286C9E
+PT=65E4088200BCC01FCEE39C6E42082FD8
+
+I=106
+KEY=9F051C2DEFD73F7AB7938D15D888E87B
+CT=65E4088200BCC01FCEE39C6E42082FD8
+PT=4588E0D3AABBEFE611B9576391B903E9
+
+I=107
+KEY=DA8DFCFE456CD09CA62ADA764931EB92
+CT=4588E0D3AABBEFE611B9576391B903E9
+PT=A55622F833FF271DD8A8F01CF5828FCF
+
+I=108
+KEY=7FDBDE067693F7817E822A6ABCB3645D
+CT=A55622F833FF271DD8A8F01CF5828FCF
+PT=8C954010C870B2DB7FA44E1DEBFE6DE8
+
+I=109
+KEY=F34E9E16BEE3455A01266477574D09B5
+CT=8C954010C870B2DB7FA44E1DEBFE6DE8
+PT=58B7BD00ED18FC81E618807DE65305B8
+
+I=110
+KEY=ABF9231653FBB9DBE73EE40AB11E0C0D
+CT=58B7BD00ED18FC81E618807DE65305B8
+PT=EF82E5F4879039F2A1A4CC2F2044BD14
+
+I=111
+KEY=447BC6E2D46B8029469A2825915AB119
+CT=EF82E5F4879039F2A1A4CC2F2044BD14
+PT=2B6C12307F14FD50B41D8F972B19AC76
+
+I=112
+KEY=6F17D4D2AB7F7D79F287A7B2BA431D6F
+CT=2B6C12307F14FD50B41D8F972B19AC76
+PT=C9B6D042CE76892D17F70D4EE00A0D79
+
+I=113
+KEY=A6A104906509F454E570AAFC5A491016
+CT=C9B6D042CE76892D17F70D4EE00A0D79
+PT=1B08F9293BBFC44DDCF2C1D26A9DD00B
+
+I=114
+KEY=BDA9FDB95EB6301939826B2E30D4C01D
+CT=1B08F9293BBFC44DDCF2C1D26A9DD00B
+PT=4FD353B247048FAAA728E10C691C70CA
+
+I=115
+KEY=F27AAE0B19B2BFB39EAA8A2259C8B0D7
+CT=4FD353B247048FAAA728E10C691C70CA
+PT=0BBB6FDBC62C428B85111BC7C93AE994
+
+I=116
+KEY=F9C1C1D0DF9EFD381BBB91E590F25943
+CT=0BBB6FDBC62C428B85111BC7C93AE994
+PT=9C1A213A5772DE6C15CE7406F84BED03
+
+I=117
+KEY=65DBE0EA88EC23540E75E5E368B9B440
+CT=9C1A213A5772DE6C15CE7406F84BED03
+PT=AB3DE06BBDB213D64F735CA990DC373C
+
+I=118
+KEY=CEE60081355E30824106B94AF865837C
+CT=AB3DE06BBDB213D64F735CA990DC373C
+PT=6C004A1A114E90C7903AA4A0120A2B10
+
+I=119
+KEY=A2E64A9B2410A045D13C1DEAEA6FA86C
+CT=6C004A1A114E90C7903AA4A0120A2B10
+PT=6405A033C294E72119A8955712548121
+
+I=120
+KEY=C6E3EAA8E6844764C89488BDF83B294D
+CT=6405A033C294E72119A8955712548121
+PT=AE8A3BAC7279B1BC152A5AD8EBAC3EAD
+
+I=121
+KEY=6869D10494FDF6D8DDBED265139717E0
+CT=AE8A3BAC7279B1BC152A5AD8EBAC3EAD
+PT=4ADDA9999D2BE20D8925F39699563294
+
+I=122
+KEY=22B4789D09D614D5549B21F38AC12574
+CT=4ADDA9999D2BE20D8925F39699563294
+PT=BC5CA33CB2A1A580EB92946C77A63467
+
+I=123
+KEY=9EE8DBA1BB77B155BF09B59FFD671113
+CT=BC5CA33CB2A1A580EB92946C77A63467
+PT=F7ABEAD301264A3E59EABA0B9606DC92
+
+I=124
+KEY=69433172BA51FB6BE6E30F946B61CD81
+CT=F7ABEAD301264A3E59EABA0B9606DC92
+PT=2566114A10BE9BF19E0910486DAB6BE5
+
+I=125
+KEY=4C252038AAEF609A78EA1FDC06CAA664
+CT=2566114A10BE9BF19E0910486DAB6BE5
+PT=AF72E1B179660A1B833D9D4FC8473B6B
+
+I=126
+KEY=E357C189D3896A81FBD78293CE8D9D0F
+CT=AF72E1B179660A1B833D9D4FC8473B6B
+PT=DFF968B761D8E154B74C9D568C12008E
+
+I=127
+KEY=3CAEA93EB2518BD54C9B1FC5429F9D81
+CT=DFF968B761D8E154B74C9D568C12008E
+PT=42DF098BCB57D0D25269E29C9BC99DE6
+
+I=128
+KEY=7E71A0B579065B071EF2FD59D9560067
+CT=42DF098BCB57D0D25269E29C9BC99DE6
+PT=66C34CAAEFC2009B985D1E622FC61AB4
+
+I=129
+KEY=18B2EC1F96C45B9C86AFE33BF6901AD3
+CT=66C34CAAEFC2009B985D1E622FC61AB4
+PT=150C1BF943982C5EA1A6839D94F23288
+
+I=130
+KEY=0DBEF7E6D55C77C2270960A66262285B
+CT=150C1BF943982C5EA1A6839D94F23288
+PT=048BFBB28879206964C5F3B41264011A
+
+I=131
+KEY=09350C545D2557AB43CC931270062941
+CT=048BFBB28879206964C5F3B41264011A
+PT=54D2DC53B87EC949F0FA0E134EE26D50
+
+I=132
+KEY=5DE7D007E55B9EE2B3369D013EE44411
+CT=54D2DC53B87EC949F0FA0E134EE26D50
+PT=1BA46AFE1AE87C4F0254BF02DF3B6D37
+
+I=133
+KEY=4643BAF9FFB3E2ADB1622203E1DF2926
+CT=1BA46AFE1AE87C4F0254BF02DF3B6D37
+PT=7733E74E743C9E997AC2ED36B2E89CE8
+
+I=134
+KEY=31705DB78B8F7C34CBA0CF355337B5CE
+CT=7733E74E743C9E997AC2ED36B2E89CE8
+PT=670AEA160FAC67ABCECA140EB8195EB5
+
+I=135
+KEY=567AB7A184231B9F056ADB3BEB2EEB7B
+CT=670AEA160FAC67ABCECA140EB8195EB5
+PT=7CFD74D510AC894FF5B698280386F4FF
+
+I=136
+KEY=2A87C374948F92D0F0DC4313E8A81F84
+CT=7CFD74D510AC894FF5B698280386F4FF
+PT=10D03F32C0694E9FFF598E101998105E
+
+I=137
+KEY=3A57FC4654E6DC4F0F85CD03F1300FDA
+CT=10D03F32C0694E9FFF598E101998105E
+PT=351D6E8D1C26F36973356F6235B8ABAD
+
+I=138
+KEY=0F4A92CB48C02F267CB0A261C488A477
+CT=351D6E8D1C26F36973356F6235B8ABAD
+PT=0DDDA7AA09FBD986C0B9EA2B018FAE4F
+
+I=139
+KEY=02973561413BF6A0BC09484AC5070A38
+CT=0DDDA7AA09FBD986C0B9EA2B018FAE4F
+PT=31C5B68B7A08D1B7320FAB052CC3B0D1
+
+I=140
+KEY=335283EA3B3327178E06E34FE9C4BAE9
+CT=31C5B68B7A08D1B7320FAB052CC3B0D1
+PT=501B8D9EE91468522029020A39484DB5
+
+I=141
+KEY=63490E74D2274F45AE2FE145D08CF75C
+CT=501B8D9EE91468522029020A39484DB5
+PT=2714FBA566DFD4909B8ABF29B1D5A8E8
+
+I=142
+KEY=445DF5D1B4F89BD535A55E6C61595FB4
+CT=2714FBA566DFD4909B8ABF29B1D5A8E8
+PT=94485381E5088D67BC1335C89FA5C2B8
+
+I=143
+KEY=D015A65051F016B289B66BA4FEFC9D0C
+CT=94485381E5088D67BC1335C89FA5C2B8
+PT=BE5BEE26D6686A0EB5838C237FEF79B7
+
+I=144
+KEY=6E4E487687987CBC3C35E7878113E4BB
+CT=BE5BEE26D6686A0EB5838C237FEF79B7
+PT=417F73D46CFBE3C5C9AD513BCBC6D185
+
+I=145
+KEY=2F313BA2EB639F79F598B6BC4AD5353E
+CT=417F73D46CFBE3C5C9AD513BCBC6D185
+PT=AE3B07350B3BE7D4F9F6FE2F95622449
+
+I=146
+KEY=810A3C97E05878AD0C6E4893DFB71177
+CT=AE3B07350B3BE7D4F9F6FE2F95622449
+PT=7BD4231225A7B665953AB034E24A7C7A
+
+I=147
+KEY=FADE1F85C5FFCEC89954F8A73DFD6D0D
+CT=7BD4231225A7B665953AB034E24A7C7A
+PT=3C1FBE8F3CEB1438B4A64E59FAF291CF
+
+I=148
+KEY=C6C1A10AF914DAF02DF2B6FEC70FFCC2
+CT=3C1FBE8F3CEB1438B4A64E59FAF291CF
+PT=ACFF7F1E71AA952CF8ADB24FEE18A7BB
+
+I=149
+KEY=6A3EDE1488BE4FDCD55F04B129175B79
+CT=ACFF7F1E71AA952CF8ADB24FEE18A7BB
+PT=3C3A6D3FD73B36317417106A92E2B43E
+
+I=150
+KEY=5604B32B5F8579EDA14814DBBBF5EF47
+CT=3C3A6D3FD73B36317417106A92E2B43E
+PT=F34F8C719A4A74DD8F4FA4CBC520827A
+
+I=151
+KEY=A54B3F5AC5CF0D302E07B0107ED56D3D
+CT=F34F8C719A4A74DD8F4FA4CBC520827A
+PT=6A5D56FB6C7EBA15112AF8A093F3E1E1
+
+I=152
+KEY=CF1669A1A9B1B7253F2D48B0ED268CDC
+CT=6A5D56FB6C7EBA15112AF8A093F3E1E1
+PT=8BF39EE3B8ED0F6A6EA92319A81B10E6
+
+I=153
+KEY=44E5F742115CB84F51846BA9453D9C3A
+CT=8BF39EE3B8ED0F6A6EA92319A81B10E6
+PT=2BC796D320C444BBBAD466D686F460F6
+
+I=154
+KEY=6F2261913198FCF4EB500D7FC3C9FCCC
+CT=2BC796D320C444BBBAD466D686F460F6
+PT=2CF595F424ED50B1A146E387B128CBA3
+
+I=155
+KEY=43D7F4651575AC454A16EEF872E1376F
+CT=2CF595F424ED50B1A146E387B128CBA3
+PT=56F2E856045BAE66EA003A6C39205344
+
+I=156
+KEY=15251C33112E0223A016D4944BC1642B
+CT=56F2E856045BAE66EA003A6C39205344
+PT=31C83401BD83424BA6E94C0D6D453D9A
+
+I=157
+KEY=24ED2832ACAD406806FF9899268459B1
+CT=31C83401BD83424BA6E94C0D6D453D9A
+PT=A687F05992CCB57CDE61AFF8878913ED
+
+I=158
+KEY=826AD86B3E61F514D89E3761A10D4A5C
+CT=A687F05992CCB57CDE61AFF8878913ED
+PT=16E771193C2473502F415C27FB101D94
+
+I=159
+KEY=948DA97202458644F7DF6B465A1D57C8
+CT=16E771193C2473502F415C27FB101D94
+PT=C69CDBA29C9EDC3407C1C73A756A0B6E
+
+I=160
+KEY=521172D09EDB5A70F01EAC7C2F775CA6
+CT=C69CDBA29C9EDC3407C1C73A756A0B6E
+PT=566D82281F48E3217F3852115CF2E944
+
+I=161
+KEY=047CF0F88193B9518F26FE6D7385B5E2
+CT=566D82281F48E3217F3852115CF2E944
+PT=B3FEBC8F8F0F0B652C4358BCC9BF54DF
+
+I=162
+KEY=B7824C770E9CB234A365A6D1BA3AE13D
+CT=B3FEBC8F8F0F0B652C4358BCC9BF54DF
+PT=BBB84877094B3EB86203D17C92CF5168
+
+I=163
+KEY=0C3A040007D78C8CC16677AD28F5B055
+CT=BBB84877094B3EB86203D17C92CF5168
+PT=2C45E5A3F8C564862DA4D8AD428D3E67
+
+I=164
+KEY=207FE1A3FF12E80AECC2AF006A788E32
+CT=2C45E5A3F8C564862DA4D8AD428D3E67
+PT=10ADC2AF56600D95AD8BB579EF5170C9
+
+I=165
+KEY=30D2230CA972E59F41491A798529FEFB
+CT=10ADC2AF56600D95AD8BB579EF5170C9
+PT=1854BB8AC568F3599153BE1AC60BA78D
+
+I=166
+KEY=288698866C1A16C6D01AA46343225976
+CT=1854BB8AC568F3599153BE1AC60BA78D
+PT=E641765C80D8812A1A0F4606C639642E
+
+I=167
+KEY=CEC7EEDAECC297ECCA15E265851B3D58
+CT=E641765C80D8812A1A0F4606C639642E
+PT=317AC70CEAA87AE66A15C22BD5E534E5
+
+I=168
+KEY=FFBD29D6066AED0AA000204E50FE09BD
+CT=317AC70CEAA87AE66A15C22BD5E534E5
+PT=BFFB8D7B3D9F54727944ABC3F6474362
+
+I=169
+KEY=4046A4AD3BF5B978D9448B8DA6B94ADF
+CT=BFFB8D7B3D9F54727944ABC3F6474362
+PT=060765D1D9D289B862DA274CFDB4D7A0
+
+I=170
+KEY=4641C17CE22730C0BB9EACC15B0D9D7F
+CT=060765D1D9D289B862DA274CFDB4D7A0
+PT=FBAFA4C1D6CEF2A45E9E084311FDF858
+
+I=171
+KEY=BDEE65BD34E9C264E500A4824AF06527
+CT=FBAFA4C1D6CEF2A45E9E084311FDF858
+PT=F7F36BFDA77362B470B0B074241C58E9
+
+I=172
+KEY=4A1D0E40939AA0D095B014F66EEC3DCE
+CT=F7F36BFDA77362B470B0B074241C58E9
+PT=2FC236EDCD573A6DCFBA7930E9CF4698
+
+I=173
+KEY=65DF38AD5ECD9ABD5A0A6DC687237B56
+CT=2FC236EDCD573A6DCFBA7930E9CF4698
+PT=949A9994DC976595BFACA5F31116A165
+
+I=174
+KEY=F145A139825AFF28E5A6C8359635DA33
+CT=949A9994DC976595BFACA5F31116A165
+PT=19373CA9D519BF83EAA4C17E1EE8225C
+
+I=175
+KEY=E8729D90574340AB0F02094B88DDF86F
+CT=19373CA9D519BF83EAA4C17E1EE8225C
+PT=685C783918997A7572B0A09315F1F2DB
+
+I=176
+KEY=802EE5A94FDA3ADE7DB2A9D89D2C0AB4
+CT=685C783918997A7572B0A09315F1F2DB
+PT=FC0CB1792EADB7E8DECB021A435DE1E7
+
+I=177
+KEY=7C2254D061778D36A379ABC2DE71EB53
+CT=FC0CB1792EADB7E8DECB021A435DE1E7
+PT=797C5E5B4F3B38E7C72FF7AAAB270E86
+
+I=178
+KEY=055E0A8B2E4CB5D164565C687556E5D5
+CT=797C5E5B4F3B38E7C72FF7AAAB270E86
+PT=A5AB675262EA186F777681647B6AA1F9
+
+I=179
+KEY=A0F56DD94CA6ADBE1320DD0C0E3C442C
+CT=A5AB675262EA186F777681647B6AA1F9
+PT=08CDF6AF55BBB247D0DE1A69CD041A78
+
+I=180
+KEY=A8389B76191D1FF9C3FEC765C3385E54
+CT=08CDF6AF55BBB247D0DE1A69CD041A78
+PT=DED1F3C30AB5EC3455C7B6A756E5FF03
+
+I=181
+KEY=76E968B513A8F3CD963971C295DDA157
+CT=DED1F3C30AB5EC3455C7B6A756E5FF03
+PT=C759A17B354D668D1BA5541D16241D9F
+
+I=182
+KEY=B1B0C9CE26E595408D9C25DF83F9BCC8
+CT=C759A17B354D668D1BA5541D16241D9F
+PT=97E011FE7B327B8292270D4CD18BD9AC
+
+I=183
+KEY=2650D8305DD7EEC21FBB289352726564
+CT=97E011FE7B327B8292270D4CD18BD9AC
+PT=9F004E4282F790C06681F16262EF78CF
+
+I=184
+KEY=B9509672DF207E02793AD9F1309D1DAB
+CT=9F004E4282F790C06681F16262EF78CF
+PT=6B34AA95EFD874915DAE275CE34A04B9
+
+I=185
+KEY=D2643CE730F80A932494FEADD3D71912
+CT=6B34AA95EFD874915DAE275CE34A04B9
+PT=96966D118C50B67849F93B109492B5EB
+
+I=186
+KEY=44F251F6BCA8BCEB6D6DC5BD4745ACF9
+CT=96966D118C50B67849F93B109492B5EB
+PT=2CA6F85E4F29BE884392A0FEDD08D5A7
+
+I=187
+KEY=6854A9A8F38102632EFF65439A4D795E
+CT=2CA6F85E4F29BE884392A0FEDD08D5A7
+PT=21B71D4F23DDC002CAAFB7426009BD27
+
+I=188
+KEY=49E3B4E7D05CC261E450D201FA44C479
+CT=21B71D4F23DDC002CAAFB7426009BD27
+PT=BF059F1945E9E51B22B308849757B475
+
+I=189
+KEY=F6E62BFE95B5277AC6E3DA856D13700C
+CT=BF059F1945E9E51B22B308849757B475
+PT=434F4E756A3178472E12B80A1C2ED83E
+
+I=190
+KEY=B5A9658BFF845F3DE8F1628F713DA832
+CT=434F4E756A3178472E12B80A1C2ED83E
+PT=37DB2B0D5967700CDE348FB60661A6D4
+
+I=191
+KEY=82724E86A6E32F3136C5ED39775C0EE6
+CT=37DB2B0D5967700CDE348FB60661A6D4
+PT=D31C5130F8F217AC0014B5F37B9BB86B
+
+I=192
+KEY=516E1FB65E11389D36D158CA0CC7B68D
+CT=D31C5130F8F217AC0014B5F37B9BB86B
+PT=3B8CD15967907F9C617697EBEF395B16
+
+I=193
+KEY=6AE2CEEF3981470157A7CF21E3FEED9B
+CT=3B8CD15967907F9C617697EBEF395B16
+PT=AF17B5E5236BF46576379CD4E5AF8A34
+
+I=194
+KEY=C5F57B0A1AEAB364219053F5065167AF
+CT=AF17B5E5236BF46576379CD4E5AF8A34
+PT=88286D6FB237181EC239C1D70C0D6675
+
+I=195
+KEY=4DDD1665A8DDAB7AE3A992220A5C01DA
+CT=88286D6FB237181EC239C1D70C0D6675
+PT=8A5207BB1283343B3692045183451A7D
+
+I=196
+KEY=C78F11DEBA5E9F41D53B967389191BA7
+CT=8A5207BB1283343B3692045183451A7D
+PT=53C12FAC4B0185AA0CE067FC67EC5B9C
+
+I=197
+KEY=944E3E72F15F1AEBD9DBF18FEEF5403B
+CT=53C12FAC4B0185AA0CE067FC67EC5B9C
+PT=BBA2BB9B1CA48D2E97E0C39E500EB9C0
+
+I=198
+KEY=2FEC85E9EDFB97C54E3B3211BEFBF9FB
+CT=BBA2BB9B1CA48D2E97E0C39E500EB9C0
+PT=8BA2341064B7B5184CD7E7A40FA0358E
+
+I=199
+KEY=A44EB1F9894C22DD02ECD5B5B15BCC75
+CT=8BA2341064B7B5184CD7E7A40FA0358E
+PT=97121EEEA68CC6200FBC0B311849E625
+
+I=200
+KEY=335CAF172FC0E4FD0D50DE84A9122A50
+CT=97121EEEA68CC6200FBC0B311849E625
+PT=027FA370A9412B342043A15F19294961
+
+I=201
+KEY=31230C678681CFC92D137FDBB03B6331
+CT=027FA370A9412B342043A15F19294961
+PT=72CFBE6BA03AB28A53A6727717D1199A
+
+I=202
+KEY=43ECB20C26BB7D437EB50DACA7EA7AAB
+CT=72CFBE6BA03AB28A53A6727717D1199A
+PT=7A15B1B4B4ED35F9C208500FE7C4C1C7
+
+I=203
+KEY=39F903B8925648BABCBD5DA3402EBB6C
+CT=7A15B1B4B4ED35F9C208500FE7C4C1C7
+PT=AF46496D09254FAB5F381E93EEB4FBB0
+
+I=204
+KEY=96BF4AD59B730711E3854330AE9A40DC
+CT=AF46496D09254FAB5F381E93EEB4FBB0
+PT=ADA064E0F4324E8B0C062F6E33C7D016
+
+I=205
+KEY=3B1F2E356F41499AEF836C5E9D5D90CA
+CT=ADA064E0F4324E8B0C062F6E33C7D016
+PT=7723A61733BD5BBFAB8C559ED379B8B5
+
+I=206
+KEY=4C3C88225CFC1225440F39C04E24287F
+CT=7723A61733BD5BBFAB8C559ED379B8B5
+PT=5D210E8F35DD863316E89FADA70E8392
+
+I=207
+KEY=111D86AD6921941652E7A66DE92AABED
+CT=5D210E8F35DD863316E89FADA70E8392
+PT=92B1D20E7D87787950990052DE2ABA4F
+
+I=208
+KEY=83AC54A314A6EC6F027EA63F370011A2
+CT=92B1D20E7D87787950990052DE2ABA4F
+PT=178E494D23AA6AC13AC180727C47FD2A
+
+I=209
+KEY=94221DEE370C86AE38BF264D4B47EC88
+CT=178E494D23AA6AC13AC180727C47FD2A
+PT=CB9C10817C059D5BE4F123576FF459C6
+
+I=210
+KEY=5FBE0D6F4B091BF5DC4E051A24B3B54E
+CT=CB9C10817C059D5BE4F123576FF459C6
+PT=4934C56CC7BAF0A8DEBB62CFB2B0DEBF
+
+I=211
+KEY=168AC8038CB3EB5D02F567D596036BF1
+CT=4934C56CC7BAF0A8DEBB62CFB2B0DEBF
+PT=F6F2A4B90B357D88401702C968D9EC02
+
+I=212
+KEY=E0786CBA878696D542E2651CFEDA87F3
+CT=F6F2A4B90B357D88401702C968D9EC02
+PT=06A35CAD7B36751BEE345C33112EB6D1
+
+I=213
+KEY=E6DB3017FCB0E3CEACD6392FEFF43122
+CT=06A35CAD7B36751BEE345C33112EB6D1
+PT=3244CDE10DF48795DA702CD8C2F4CABD
+
+I=214
+KEY=D49FFDF6F144645B76A615F72D00FB9F
+CT=3244CDE10DF48795DA702CD8C2F4CABD
+PT=47C06F5BEA8C3503512E0E200966C546
+
+I=215
+KEY=935F92AD1BC8515827881BD724663ED9
+CT=47C06F5BEA8C3503512E0E200966C546
+PT=68A077D25CBEA7F76B88D8C6A414D0CE
+
+I=216
+KEY=FBFFE57F4776F6AF4C00C3118072EE17
+CT=68A077D25CBEA7F76B88D8C6A414D0CE
+PT=DDF110C2C79B46C5132CCEF654280D7E
+
+I=217
+KEY=260EF5BD80EDB06A5F2C0DE7D45AE369
+CT=DDF110C2C79B46C5132CCEF654280D7E
+PT=0AB610A0082813076D052011C12DC924
+
+I=218
+KEY=2CB8E51D88C5A36D32292DF615772A4D
+CT=0AB610A0082813076D052011C12DC924
+PT=8C42F49EDAE1BD6B631E74B68B1B8444
+
+I=219
+KEY=A0FA118352241E06513759409E6CAE09
+CT=8C42F49EDAE1BD6B631E74B68B1B8444
+PT=B5A5B6E50B3A066D16DF883F353019FE
+
+I=220
+KEY=155FA766591E186B47E8D17FAB5CB7F7
+CT=B5A5B6E50B3A066D16DF883F353019FE
+PT=70CFA25AFC9919937E2FC90900F0B398
+
+I=221
+KEY=6590053CA58701F839C71876ABAC046F
+CT=70CFA25AFC9919937E2FC90900F0B398
+PT=B927A5911AE33DEAB619DAFEE22CD0DF
+
+I=222
+KEY=DCB7A0ADBF643C128FDEC2884980D4B0
+CT=B927A5911AE33DEAB619DAFEE22CD0DF
+PT=10C548438C5B976EDD624129B2102D7A
+
+I=223
+KEY=CC72E8EE333FAB7C52BC83A1FB90F9CA
+CT=10C548438C5B976EDD624129B2102D7A
+PT=4549E45DA2F8FE82972DC7DF3548CAFF
+
+I=224
+KEY=893B0CB391C755FEC591447ECED83335
+CT=4549E45DA2F8FE82972DC7DF3548CAFF
+PT=2B85505E64089FEB6B5763011E778C96
+
+I=225
+KEY=A2BE5CEDF5CFCA15AEC6277FD0AFBFA3
+CT=2B85505E64089FEB6B5763011E778C96
+PT=4B157930F9A6EBE3D9D6AC9FADDEB35C
+
+I=226
+KEY=E9AB25DD0C6921F677108BE07D710CFF
+CT=4B157930F9A6EBE3D9D6AC9FADDEB35C
+PT=12341C0FE9EB6757BFFCC4BC1A8F2585
+
+I=227
+KEY=FB9F39D2E58246A1C8EC4F5C67FE297A
+CT=12341C0FE9EB6757BFFCC4BC1A8F2585
+PT=5422D62D794B02FC04BE01198EE23ACE
+
+I=228
+KEY=AFBDEFFF9CC9445DCC524E45E91C13B4
+CT=5422D62D794B02FC04BE01198EE23ACE
+PT=42D43022FD6DB571BCB2FDE653C9068C
+
+I=229
+KEY=ED69DFDD61A4F12C70E0B3A3BAD51538
+CT=42D43022FD6DB571BCB2FDE653C9068C
+PT=80BD3AAED5D519B75D22BF060EF1DFC6
+
+I=230
+KEY=6DD4E573B471E89B2DC20CA5B424CAFE
+CT=80BD3AAED5D519B75D22BF060EF1DFC6
+PT=B72973F9016A348CDDCCFFC2DD291B5A
+
+I=231
+KEY=DAFD968AB51BDC17F00EF367690DD1A4
+CT=B72973F9016A348CDDCCFFC2DD291B5A
+PT=5692E61C86A7B2C043ABBED712390361
+
+I=232
+KEY=8C6F709633BC6ED7B3A54DB07B34D2C5
+CT=5692E61C86A7B2C043ABBED712390361
+PT=75138737269AA27855C2CFD2DCEDEFC4
+
+I=233
+KEY=F97CF7A11526CCAFE6678262A7D93D01
+CT=75138737269AA27855C2CFD2DCEDEFC4
+PT=A022AA28CECC4BB5EB28BA5B7828AB6E
+
+I=234
+KEY=595E5D89DBEA871A0D4F3839DFF1966F
+CT=A022AA28CECC4BB5EB28BA5B7828AB6E
+PT=17B0BF87EE02AA44705B1B1B4DF7D3F4
+
+I=235
+KEY=4EEEE20E35E82D5E7D1423229206459B
+CT=17B0BF87EE02AA44705B1B1B4DF7D3F4
+PT=095A5A041C43DCFEB5D0DF3E7659344A
+
+I=236
+KEY=47B4B80A29ABF1A0C8C4FC1CE45F71D1
+CT=095A5A041C43DCFEB5D0DF3E7659344A
+PT=9DCE0D1C572509F3367EE952B89044E5
+
+I=237
+KEY=DA7AB5167E8EF853FEBA154E5CCF3534
+CT=9DCE0D1C572509F3367EE952B89044E5
+PT=E6075BCC82399A91E52034EA2F197058
+
+I=238
+KEY=3C7DEEDAFCB762C21B9A21A473D6456C
+CT=E6075BCC82399A91E52034EA2F197058
+PT=431D243CEE96B424B0FA4FEC5E707036
+
+I=239
+KEY=7F60CAE61221D6E6AB606E482DA6355A
+CT=431D243CEE96B424B0FA4FEC5E707036
+PT=5EF70106A2EA454CA9405A8AA1B54EF0
+
+I=240
+KEY=2197CBE0B0CB93AA022034C28C137BAA
+CT=5EF70106A2EA454CA9405A8AA1B54EF0
+PT=09B003CB7E2ADDD587A2ABCDD03D234F
+
+I=241
+KEY=2827C82BCEE14E7F85829F0F5C2E58E5
+CT=09B003CB7E2ADDD587A2ABCDD03D234F
+PT=3647FAC6EF758113DC768E7737098DE9
+
+I=242
+KEY=1E6032ED2194CF6C59F411786B27D50C
+CT=3647FAC6EF758113DC768E7737098DE9
+PT=C043BD96A88492C85431B72C708C3C60
+
+I=243
+KEY=DE238F7B89105DA40DC5A6541BABE96C
+CT=C043BD96A88492C85431B72C708C3C60
+PT=299A25142A6B5D334158D359DD9CD574
+
+I=244
+KEY=F7B9AA6FA37B00974C9D750DC6373C18
+CT=299A25142A6B5D334158D359DD9CD574
+PT=21E56C2202C8D6F81EDC63A8A1EA4B6A
+
+I=245
+KEY=D65CC64DA1B3D66F524116A567DD7772
+CT=21E56C2202C8D6F81EDC63A8A1EA4B6A
+PT=FD3565957E3845065B7AEF27A900FDD5
+
+I=246
+KEY=2B69A3D8DF8B9369093BF982CEDD8AA7
+CT=FD3565957E3845065B7AEF27A900FDD5
+PT=A4DB9120D1ED0419342AFC2CBF114647
+
+I=247
+KEY=8FB232F80E6697703D1105AE71CCCCE0
+CT=A4DB9120D1ED0419342AFC2CBF114647
+PT=27FDDEA1E746BD217CFB4CD7A511BACE
+
+I=248
+KEY=A84FEC59E9202A5141EA4979D4DD762E
+CT=27FDDEA1E746BD217CFB4CD7A511BACE
+PT=6A9189FD46E47B22F151A213D023442B
+
+I=249
+KEY=C2DE65A4AFC45173B0BBEB6A04FE3205
+CT=6A9189FD46E47B22F151A213D023442B
+PT=1C729701404C76D5D7A156C39CF52542
+
+I=250
+KEY=DEACF2A5EF8827A6671ABDA9980B1747
+CT=1C729701404C76D5D7A156C39CF52542
+PT=6F97CB4564E0783DFE962DCB13FEDF72
+
+I=251
+KEY=B13B39E08B685F9B998C90628BF5C835
+CT=6F97CB4564E0783DFE962DCB13FEDF72
+PT=F818140A280299B182CDA37CBE9B27AB
+
+I=252
+KEY=49232DEAA36AC62A1B41331E356EEF9E
+CT=F818140A280299B182CDA37CBE9B27AB
+PT=20E9F2BE7017C2945005FD8A420A5B7D
+
+I=253
+KEY=69CADF54D37D04BE4B44CE947764B4E3
+CT=20E9F2BE7017C2945005FD8A420A5B7D
+PT=60BB97C634161EF6A36056193B6EDDB0
+
+I=254
+KEY=09714892E76B1A48E824988D4C0A6953
+CT=60BB97C634161EF6A36056193B6EDDB0
+PT=E4B9777B7390EF430A93FF7DD0B68CD4
+
+I=255
+KEY=EDC83FE994FBF50BE2B767F09CBCE587
+CT=E4B9777B7390EF430A93FF7DD0B68CD4
+PT=E5E3BD960CF15BBDB8A6C08711A884CF
+
+I=256
+KEY=082B827F980AAEB65A11A7778D146148
+CT=E5E3BD960CF15BBDB8A6C08711A884CF
+PT=71A6AEFD0181DCE69A116585044C7F66
+
+I=257
+KEY=798D2C82998B7250C000C2F289581E2E
+CT=71A6AEFD0181DCE69A116585044C7F66
+PT=8E9C1CFFDB8972617D74DA0E9ED065D1
+
+I=258
+KEY=F711307D42020031BD7418FC17887BFF
+CT=8E9C1CFFDB8972617D74DA0E9ED065D1
+PT=CE7882AB901A199910FC463A4D1D626A
+
+I=259
+KEY=3969B2D6D21819A8AD885EC65A951995
+CT=CE7882AB901A199910FC463A4D1D626A
+PT=2334546032E850D0029CB1AD6AFCEA7A
+
+I=260
+KEY=1A5DE6B6E0F04978AF14EF6B3069F3EF
+CT=2334546032E850D0029CB1AD6AFCEA7A
+PT=88B4CF0D4AB7BD00BE98DA1626063A69
+
+I=261
+KEY=92E929BBAA47F478118C357D166FC986
+CT=88B4CF0D4AB7BD00BE98DA1626063A69
+PT=5A7FF831F28E5EC4A11DA524E2323925
+
+I=262
+KEY=C896D18A58C9AABCB0919059F45DF0A3
+CT=5A7FF831F28E5EC4A11DA524E2323925
+PT=DF000551EF9BBD914969BD1B353BDC8C
+
+I=263
+KEY=1796D4DBB752172DF9F82D42C1662C2F
+CT=DF000551EF9BBD914969BD1B353BDC8C
+PT=1EECBC47697208193C354E28D23E8CE9
+
+I=264
+KEY=097A689CDE201F34C5CD636A1358A0C6
+CT=1EECBC47697208193C354E28D23E8CE9
+PT=DF85CD4B3F821A7411F9F5D1FDF9DB85
+
+I=265
+KEY=D6FFA5D7E1A20540D43496BBEEA17B43
+CT=DF85CD4B3F821A7411F9F5D1FDF9DB85
+PT=038E765F1910D8C0C1251254605218F2
+
+I=266
+KEY=D571D388F8B2DD80151184EF8EF363B1
+CT=038E765F1910D8C0C1251254605218F2
+PT=FBA8FE850294EEAEE75F56C974BF7DE4
+
+I=267
+KEY=2ED92D0DFA26332EF24ED226FA4C1E55
+CT=FBA8FE850294EEAEE75F56C974BF7DE4
+PT=47F9D6F7A3E2A1BFA360EA1BA8B0450E
+
+I=268
+KEY=6920FBFA59C49291512E383D52FC5B5B
+CT=47F9D6F7A3E2A1BFA360EA1BA8B0450E
+PT=FD6F4A4825DE5E776BFD569223CB5A2C
+
+I=269
+KEY=944FB1B27C1ACCE63AD36EAF71370177
+CT=FD6F4A4825DE5E776BFD569223CB5A2C
+PT=10430ED7EE0FDB8FBC348F8E08286622
+
+I=270
+KEY=840CBF659215176986E7E121791F6755
+CT=10430ED7EE0FDB8FBC348F8E08286622
+PT=4B75D5C573185303B01EB649884758B1
+
+I=271
+KEY=CF796AA0E10D446A36F95768F1583FE4
+CT=4B75D5C573185303B01EB649884758B1
+PT=85CCA4271A941517D55D05B4F29527C3
+
+I=272
+KEY=4AB5CE87FB99517DE3A452DC03CD1827
+CT=85CCA4271A941517D55D05B4F29527C3
+PT=615EA2D44C52D639B6AD05D621B4A1A6
+
+I=273
+KEY=2BEB6C53B7CB87445509570A2279B981
+CT=615EA2D44C52D639B6AD05D621B4A1A6
+PT=1DFD1E93D34ABFE45BA6BF6BD3FBF30E
+
+I=274
+KEY=361672C0648138A00EAFE861F1824A8F
+CT=1DFD1E93D34ABFE45BA6BF6BD3FBF30E
+PT=B65C3F09FFFF752DEE2F8F2D441A51CA
+
+I=275
+KEY=804A4DC99B7E4D8DE080674CB5981B45
+CT=B65C3F09FFFF752DEE2F8F2D441A51CA
+PT=3B36D6FD4F7ACAD4681FF4398AC7AFB3
+
+I=276
+KEY=BB7C9B34D4048759889F93753F5FB4F6
+CT=3B36D6FD4F7ACAD4681FF4398AC7AFB3
+PT=F3CDEFABE450D887CD585C280BB22367
+
+I=277
+KEY=48B1749F30545FDE45C7CF5D34ED9791
+CT=F3CDEFABE450D887CD585C280BB22367
+PT=ECC49251BAD79981CA1B1F683A843531
+
+I=278
+KEY=A475E6CE8A83C65F8FDCD0350E69A2A0
+CT=ECC49251BAD79981CA1B1F683A843531
+PT=8BE43F0A30663108513A0E5F49F9152C
+
+I=279
+KEY=2F91D9C4BAE5F757DEE6DE6A4790B78C
+CT=8BE43F0A30663108513A0E5F49F9152C
+PT=DB3D559FCEBE0FAF3B218161BA6B3F07
+
+I=280
+KEY=F4AC8C5B745BF8F8E5C75F0BFDFB888B
+CT=DB3D559FCEBE0FAF3B218161BA6B3F07
+PT=8F0C3AE11B03433C07CABD26BF47A430
+
+I=281
+KEY=7BA0B6BA6F58BBC4E20DE22D42BC2CBB
+CT=8F0C3AE11B03433C07CABD26BF47A430
+PT=73578DC3464CE3EE0314B206E1E9504C
+
+I=282
+KEY=08F73B792914582AE119502BA3557CF7
+CT=73578DC3464CE3EE0314B206E1E9504C
+PT=60DA2C12B296804C608348A54EE1C60D
+
+I=283
+KEY=682D176B9B82D866819A188EEDB4BAFA
+CT=60DA2C12B296804C608348A54EE1C60D
+PT=A960934724BDC61E5429E59856FC1902
+
+I=284
+KEY=C14D842CBF3F1E78D5B3FD16BB48A3F8
+CT=A960934724BDC61E5429E59856FC1902
+PT=6B7E71535C6B7B09BDF19AF79CD58C95
+
+I=285
+KEY=AA33F57FE3546571684267E1279D2F6D
+CT=6B7E71535C6B7B09BDF19AF79CD58C95
+PT=B95E0126EF320F1E6F288366DB7F2773
+
+I=286
+KEY=136DF4590C666A6F076AE487FCE2081E
+CT=B95E0126EF320F1E6F288366DB7F2773
+PT=6403B99D6FE0F85128FDD1F05B81AA6E
+
+I=287
+KEY=776E4DC46386923E2F973577A763A270
+CT=6403B99D6FE0F85128FDD1F05B81AA6E
+PT=9EBA25F2D6CE5817F4317F3AFE6421E7
+
+I=288
+KEY=E9D46836B548CA29DBA64A4D59078397
+CT=9EBA25F2D6CE5817F4317F3AFE6421E7
+PT=5E77AAE8A3C5EEAF4732BB310DAC3771
+
+I=289
+KEY=B7A3C2DE168D24869C94F17C54ABB4E6
+CT=5E77AAE8A3C5EEAF4732BB310DAC3771
+PT=5FD00675371300B60C30EFCEE0171080
+
+I=290
+KEY=E873C4AB219E243090A41EB2B4BCA466
+CT=5FD00675371300B60C30EFCEE0171080
+PT=482D701DBCE3AE108F65836C12A41C2C
+
+I=291
+KEY=A05EB4B69D7D8A201FC19DDEA618B84A
+CT=482D701DBCE3AE108F65836C12A41C2C
+PT=2966D81642542925891D8F7409051E4A
+
+I=292
+KEY=89386CA0DF29A30596DC12AAAF1DA600
+CT=2966D81642542925891D8F7409051E4A
+PT=2FD6F3DB9DD1DEDED9F32D1806AE69D6
+
+I=293
+KEY=A6EE9F7B42F87DDB4F2F3FB2A9B3CFD6
+CT=2FD6F3DB9DD1DEDED9F32D1806AE69D6
+PT=9B59277165B792790E29ADB53ADE60DB
+
+I=294
+KEY=3DB7B80A274FEFA241069207936DAF0D
+CT=9B59277165B792790E29ADB53ADE60DB
+PT=A4873C5246044200B56C25FFADAB15D6
+
+I=295
+KEY=99308458614BADA2F46AB7F83EC6BADB
+CT=A4873C5246044200B56C25FFADAB15D6
+PT=9E2BBBD65649EB2A0CD974AD32BF382F
+
+I=296
+KEY=071B3F8E37024688F8B3C3550C7982F4
+CT=9E2BBBD65649EB2A0CD974AD32BF382F
+PT=F83F4408675892DADA4833A43F22FFC8
+
+I=297
+KEY=FF247B86505AD45222FBF0F1335B7D3C
+CT=F83F4408675892DADA4833A43F22FFC8
+PT=19C337CCBF8D06DC68D9A16DB294EF44
+
+I=298
+KEY=E6E74C4AEFD7D28E4A22519C81CF9278
+CT=19C337CCBF8D06DC68D9A16DB294EF44
+PT=433578E0901A4F4B134E6DCF68249FC7
+
+I=299
+KEY=A5D234AA7FCD9DC5596C3C53E9EB0DBF
+CT=433578E0901A4F4B134E6DCF68249FC7
+PT=7F317CB0B3279C894B8A08289797FFF1
+
+I=300
+KEY=DAE3481ACCEA014C12E6347B7E7CF24E
+CT=7F317CB0B3279C894B8A08289797FFF1
+PT=AFFB4CA21A2A36FD24BB18C5AED17789
+
+I=301
+KEY=751804B8D6C037B1365D2CBED0AD85C7
+CT=AFFB4CA21A2A36FD24BB18C5AED17789
+PT=394DA5EC353A68B844D1BC24A468DA5C
+
+I=302
+KEY=4C55A154E3FA5F09728C909A74C55F9B
+CT=394DA5EC353A68B844D1BC24A468DA5C
+PT=C649C174B98A06351F26C117D14FF290
+
+I=303
+KEY=8A1C60205A70593C6DAA518DA58AAD0B
+CT=C649C174B98A06351F26C117D14FF290
+PT=2E122AA7C90B57304A80C19480627DD7
+
+I=304
+KEY=A40E4A87937B0E0C272A901925E8D0DC
+CT=2E122AA7C90B57304A80C19480627DD7
+PT=9841ADE6A65834CE89959EFE8F059ED6
+
+I=305
+KEY=3C4FE76135233AC2AEBF0EE7AAED4E0A
+CT=9841ADE6A65834CE89959EFE8F059ED6
+PT=6B70D74762A4BEFBD15B9EC6835CB69B
+
+I=306
+KEY=573F3026578784397FE4902129B1F891
+CT=6B70D74762A4BEFBD15B9EC6835CB69B
+PT=2E8B5DEF53E2294C0C953A9B8BD9399D
+
+I=307
+KEY=79B46DC90465AD757371AABAA268C10C
+CT=2E8B5DEF53E2294C0C953A9B8BD9399D
+PT=D32D00F78BA00F6CEA792598B89779E4
+
+I=308
+KEY=AA996D3E8FC5A21999088F221AFFB8E8
+CT=D32D00F78BA00F6CEA792598B89779E4
+PT=7059DCC6CB8D295B95F2978F25927B31
+
+I=309
+KEY=DAC0B1F844488B420CFA18AD3F6DC3D9
+CT=7059DCC6CB8D295B95F2978F25927B31
+PT=833A1AFA7DC4CAF54F5B36981A98D7E3
+
+I=310
+KEY=59FAAB02398C41B743A12E3525F5143A
+CT=833A1AFA7DC4CAF54F5B36981A98D7E3
+PT=4CC5A526400B493AAA28909A2F4932BF
+
+I=311
+KEY=153F0E247987088DE989BEAF0ABC2685
+CT=4CC5A526400B493AAA28909A2F4932BF
+PT=D7134DEE2967104D161876A0802B3727
+
+I=312
+KEY=C22C43CA50E018C0FF91C80F8A9711A2
+CT=D7134DEE2967104D161876A0802B3727
+PT=C45DB7BC52D7A0D53399B91EFB686D32
+
+I=313
+KEY=0671F4760237B815CC08711171FF7C90
+CT=C45DB7BC52D7A0D53399B91EFB686D32
+PT=2F49EA2A8D7F44909BCF41C3640FD0AB
+
+I=314
+KEY=29381E5C8F48FC8557C730D215F0AC3B
+CT=2F49EA2A8D7F44909BCF41C3640FD0AB
+PT=6D416059758F4AC555A05D83E9CFC4DE
+
+I=315
+KEY=44797E05FAC7B64002676D51FC3F68E5
+CT=6D416059758F4AC555A05D83E9CFC4DE
+PT=2721015DDF85EC87ED8480A87705CD37
+
+I=316
+KEY=63587F5825425AC7EFE3EDF98B3AA5D2
+CT=2721015DDF85EC87ED8480A87705CD37
+PT=3B045F5DD5ADC6E5D341E2E6A5B919D3
+
+I=317
+KEY=585C2005F0EF9C223CA20F1F2E83BC01
+CT=3B045F5DD5ADC6E5D341E2E6A5B919D3
+PT=85DA9719FF16899B343BE56FDF9F86BF
+
+I=318
+KEY=DD86B71C0FF915B90899EA70F11C3ABE
+CT=85DA9719FF16899B343BE56FDF9F86BF
+PT=67FD32AC2783C381E77AE0BB8ACEECCD
+
+I=319
+KEY=BA7B85B0287AD638EFE30ACB7BD2D673
+CT=67FD32AC2783C381E77AE0BB8ACEECCD
+PT=D8BEC715849E6A2A164F0139B8EC038E
+
+I=320
+KEY=62C542A5ACE4BC12F9AC0BF2C33ED5FD
+CT=D8BEC715849E6A2A164F0139B8EC038E
+PT=6ECA9375A207148E36203C8BD885A520
+
+I=321
+KEY=0C0FD1D00EE3A89CCF8C37791BBB70DD
+CT=6ECA9375A207148E36203C8BD885A520
+PT=A96877A8369B7086EF76D8281C066068
+
+I=322
+KEY=A567A6783878D81A20FAEF5107BD10B5
+CT=A96877A8369B7086EF76D8281C066068
+PT=2D6DDF2C136F5ACDC12D33D52ECD6397
+
+I=323
+KEY=880A79542B1782D7E1D7DC8429707322
+CT=2D6DDF2C136F5ACDC12D33D52ECD6397
+PT=E2F3EFF780EEDAD7B820CF57F946AB21
+
+I=324
+KEY=6AF996A3ABF9580059F713D3D036D803
+CT=E2F3EFF780EEDAD7B820CF57F946AB21
+PT=D083829AB624DC46BF55F15C2ACA2CDC
+
+I=325
+KEY=BA7A14391DDD8446E6A2E28FFAFCF4DF
+CT=D083829AB624DC46BF55F15C2ACA2CDC
+PT=637A1328711A701F011B0D66953A11FC
+
+I=326
+KEY=D90007116CC7F459E7B9EFE96FC6E523
+CT=637A1328711A701F011B0D66953A11FC
+PT=9230F9E8C4AA7D697641B4E800AECE8B
+
+I=327
+KEY=4B30FEF9A86D893091F85B016F682BA8
+CT=9230F9E8C4AA7D697641B4E800AECE8B
+PT=CABC2F3EBCB87AEF4550060FB6F95C7D
+
+I=328
+KEY=818CD1C714D5F3DFD4A85D0ED99177D5
+CT=CABC2F3EBCB87AEF4550060FB6F95C7D
+PT=25C93DA609BEDFD48D88B7E005EA9D4D
+
+I=329
+KEY=A445EC611D6B2C0B5920EAEEDC7BEA98
+CT=25C93DA609BEDFD48D88B7E005EA9D4D
+PT=E445C1B43DC6AA0D47C766675676CA29
+
+I=330
+KEY=40002DD520AD86061EE78C898A0D20B1
+CT=E445C1B43DC6AA0D47C766675676CA29
+PT=3F8A99E9D556F0CE0B0F3B4FE89A7C15
+
+I=331
+KEY=7F8AB43CF5FB76C815E8B7C662975CA4
+CT=3F8A99E9D556F0CE0B0F3B4FE89A7C15
+PT=BE04197CADBDBC917AB288D85C554D4A
+
+I=332
+KEY=C18EAD405846CA596F5A3F1E3EC211EE
+CT=BE04197CADBDBC917AB288D85C554D4A
+PT=2CF8FE59EED67AF15BD6C09C8DA37882
+
+I=333
+KEY=ED765319B690B0A8348CFF82B361696C
+CT=2CF8FE59EED67AF15BD6C09C8DA37882
+PT=FF8CBF98D0B15198ACDC53D7247511C5
+
+I=334
+KEY=12FAEC816621E1309850AC55971478A9
+CT=FF8CBF98D0B15198ACDC53D7247511C5
+PT=27794678855BAE2BDE7EB75487813E28
+
+I=335
+KEY=3583AAF9E37A4F1B462E1B0110954681
+CT=27794678855BAE2BDE7EB75487813E28
+PT=5681B2CECDE71663A864D0288607D86B
+
+I=336
+KEY=630218372E9D5978EE4ACB2996929EEA
+CT=5681B2CECDE71663A864D0288607D86B
+PT=8936EB6E65F2CD2B3AFD1310B5B2D6C8
+
+I=337
+KEY=EA34F3594B6F9453D4B7D83923204822
+CT=8936EB6E65F2CD2B3AFD1310B5B2D6C8
+PT=16045490148187B05CC46B80099A4530
+
+I=338
+KEY=FC30A7C95FEE13E38873B3B92ABA0D12
+CT=16045490148187B05CC46B80099A4530
+PT=FE909FFB1D490B028867288FE682EEE9
+
+I=339
+KEY=02A0383242A718E100149B36CC38E3FB
+CT=FE909FFB1D490B028867288FE682EEE9
+PT=7B3E5C0017089A7842866ABA6364FFEA
+
+I=340
+KEY=799E643255AF82994292F18CAF5C1C11
+CT=7B3E5C0017089A7842866ABA6364FFEA
+PT=CC263F129618975F204AE499F115C69B
+
+I=341
+KEY=B5B85B20C3B715C662D815155E49DA8A
+CT=CC263F129618975F204AE499F115C69B
+PT=997ACE7EABF6EBF9CC7BBCC2670CF1A0
+
+I=342
+KEY=2CC2955E6841FE3FAEA3A9D739452B2A
+CT=997ACE7EABF6EBF9CC7BBCC2670CF1A0
+PT=88D4A74B19278ED442068D0954DFA8B2
+
+I=343
+KEY=A4163215716670EBECA524DE6D9A8398
+CT=88D4A74B19278ED442068D0954DFA8B2
+PT=F1CC6407AB254178DEFEF983112D6AC5
+
+I=344
+KEY=55DA5612DA433193325BDD5D7CB7E95D
+CT=F1CC6407AB254178DEFEF983112D6AC5
+PT=689A0E429CDAF1BD1197C160BF962544
+
+I=345
+KEY=3D4058504699C02E23CC1C3DC321CC19
+CT=689A0E429CDAF1BD1197C160BF962544
+PT=54CF618196D978C0460CF8051DF5BE18
+
+I=346
+KEY=698F39D1D040B8EE65C0E438DED47201
+CT=54CF618196D978C0460CF8051DF5BE18
+PT=4AA0EF106F23B43C3DD371C66404C602
+
+I=347
+KEY=232FD6C1BF630CD2581395FEBAD0B403
+CT=4AA0EF106F23B43C3DD371C66404C602
+PT=A5185CAE1718143FC6CC329D9F233E17
+
+I=348
+KEY=86378A6FA87B18ED9EDFA76325F38A14
+CT=A5185CAE1718143FC6CC329D9F233E17
+PT=A2A7E8855D25A0C475961E9B7ED7BE35
+
+I=349
+KEY=249062EAF55EB829EB49B9F85B243421
+CT=A2A7E8855D25A0C475961E9B7ED7BE35
+PT=E0B7536B335FB98F197F762B3B97CECE
+
+I=350
+KEY=C4273181C60101A6F236CFD360B3FAEF
+CT=E0B7536B335FB98F197F762B3B97CECE
+PT=C45C38164083871528D8B3BA7423BFEA
+
+I=351
+KEY=007B0997868286B3DAEE7C6914904505
+CT=C45C38164083871528D8B3BA7423BFEA
+PT=017AEBDEF43CF9664C582356A4A0C374
+
+I=352
+KEY=0101E24972BE7FD596B65F3FB0308671
+CT=017AEBDEF43CF9664C582356A4A0C374
+PT=BBB48EA21B5EDCCF5346A7B4E6796BED
+
+I=353
+KEY=BAB56CEB69E0A31AC5F0F88B5649ED9C
+CT=BBB48EA21B5EDCCF5346A7B4E6796BED
+PT=3A53DFCB6067F9E98653136A44A4B537
+
+I=354
+KEY=80E6B32009875AF343A3EBE112ED58AB
+CT=3A53DFCB6067F9E98653136A44A4B537
+PT=951BA0E2272E46FC8CC3990E002EEFF0
+
+I=355
+KEY=15FD13C22EA91C0FCF6072EF12C3B75B
+CT=951BA0E2272E46FC8CC3990E002EEFF0
+PT=249202E40BC5892B9CEE96279E69432A
+
+I=356
+KEY=316F1126256C9524538EE4C88CAAF471
+CT=249202E40BC5892B9CEE96279E69432A
+PT=B90CE5BF126163B37F75032A88AFD615
+
+I=357
+KEY=8863F499370DF6972CFBE7E204052264
+CT=B90CE5BF126163B37F75032A88AFD615
+PT=E0BDD9E1FF493D82777BD7FB4035D309
+
+I=358
+KEY=68DE2D78C844CB155B8030194430F16D
+CT=E0BDD9E1FF493D82777BD7FB4035D309
+PT=0A3A5E377CDB2D1F6CB09E200494F578
+
+I=359
+KEY=62E4734FB49FE60A3730AE3940A40415
+CT=0A3A5E377CDB2D1F6CB09E200494F578
+PT=483DF6E2936389D1FC09921497AF8AE7
+
+I=360
+KEY=2AD985AD27FC6FDBCB393C2DD70B8EF2
+CT=483DF6E2936389D1FC09921497AF8AE7
+PT=7A90B7B1E493109323A54AD285090EC6
+
+I=361
+KEY=5049321CC36F7F48E89C76FF52028034
+CT=7A90B7B1E493109323A54AD285090EC6
+PT=B6471BF36A24B5B0CAC19BDD4C83DC50
+
+I=362
+KEY=E60E29EFA94BCAF8225DED221E815C64
+CT=B6471BF36A24B5B0CAC19BDD4C83DC50
+PT=EFBDC6ECADCE6AA5DBD302E7A0647700
+
+I=363
+KEY=09B3EF030485A05DF98EEFC5BEE52B64
+CT=EFBDC6ECADCE6AA5DBD302E7A0647700
+PT=783A89B88CC875F743B645BA1449CEE7
+
+I=364
+KEY=718966BB884DD5AABA38AA7FAAACE583
+CT=783A89B88CC875F743B645BA1449CEE7
+PT=EAD61D2577852D4EA276F3699EFB2BDC
+
+I=365
+KEY=9B5F7B9EFFC8F8E4184E59163457CE5F
+CT=EAD61D2577852D4EA276F3699EFB2BDC
+PT=9E804D8814AF4FC67BA931D1C72774C7
+
+I=366
+KEY=05DF3616EB67B72263E768C7F370BA98
+CT=9E804D8814AF4FC67BA931D1C72774C7
+PT=7C383CC27D8C2B117AC72088EB334FD9
+
+I=367
+KEY=79E70AD496EB9C331920484F1843F541
+CT=7C383CC27D8C2B117AC72088EB334FD9
+PT=9D4BE61ECECB2E60EC621A6320C0E844
+
+I=368
+KEY=E4ACECCA5820B253F542522C38831D05
+CT=9D4BE61ECECB2E60EC621A6320C0E844
+PT=227992ADFC526D9AA99BA629E7523198
+
+I=369
+KEY=C6D57E67A472DFC95CD9F405DFD12C9D
+CT=227992ADFC526D9AA99BA629E7523198
+PT=93A265FB7650BE75CBDD8732F65F09A5
+
+I=370
+KEY=55771B9CD22261BC97047337298E2538
+CT=93A265FB7650BE75CBDD8732F65F09A5
+PT=5AB3354B8D28F041C5A7FDAB828996BC
+
+I=371
+KEY=0FC42ED75F0A91FD52A38E9CAB07B384
+CT=5AB3354B8D28F041C5A7FDAB828996BC
+PT=BA5C6566701BD3791C2DA51CDC5AB6DD
+
+I=372
+KEY=B5984BB12F1142844E8E2B80775D0559
+CT=BA5C6566701BD3791C2DA51CDC5AB6DD
+PT=2C96CE0653EFB1113C6E822DD4AE6200
+
+I=373
+KEY=990E85B77CFEF39572E0A9ADA3F36759
+CT=2C96CE0653EFB1113C6E822DD4AE6200
+PT=1065F5519472C78BADAB79EC00BBCABA
+
+I=374
+KEY=896B70E6E88C341EDF4BD041A348ADE3
+CT=1065F5519472C78BADAB79EC00BBCABA
+PT=049AA7D4B4C1A59C1A16E3E5D8B46515
+
+I=375
+KEY=8DF1D7325C4D9182C55D33A47BFCC8F6
+CT=049AA7D4B4C1A59C1A16E3E5D8B46515
+PT=C8F1C4179DD8FCD6942D07AF7392F481
+
+I=376
+KEY=45001325C1956D545170340B086E3C77
+CT=C8F1C4179DD8FCD6942D07AF7392F481
+PT=9C9AE90AFE18822197EA47FE2F48813F
+
+I=377
+KEY=D99AFA2F3F8DEF75C69A73F52726BD48
+CT=9C9AE90AFE18822197EA47FE2F48813F
+PT=DFBABE8688391CC868CDE134DDFFE1F0
+
+I=378
+KEY=062044A9B7B4F3BDAE5792C1FAD95CB8
+CT=DFBABE8688391CC868CDE134DDFFE1F0
+PT=72BE585F98DA4DC03998B5820D5230A9
+
+I=379
+KEY=749E1CF62F6EBE7D97CF2743F78B6C11
+CT=72BE585F98DA4DC03998B5820D5230A9
+PT=BCF3D47B888599A27AD63D6EFD8FB86F
+
+I=380
+KEY=C86DC88DA7EB27DFED191A2D0A04D47E
+CT=BCF3D47B888599A27AD63D6EFD8FB86F
+PT=62F7A2AD05BB46CB81B9601129100455
+
+I=381
+KEY=AA9A6A20A25061146CA07A3C2314D02B
+CT=62F7A2AD05BB46CB81B9601129100455
+PT=FA4D3B82232D19BE14A57422012C7751
+
+I=382
+KEY=50D751A2817D78AA78050E1E2238A77A
+CT=FA4D3B82232D19BE14A57422012C7751
+PT=40953AAA3D6C1BBE375A1E275754C98C
+
+I=383
+KEY=10426B08BC1163144F5F1039756C6EF6
+CT=40953AAA3D6C1BBE375A1E275754C98C
+PT=CE9123C6A5A66AF788A8515721D646A0
+
+I=384
+KEY=DED348CE19B709E3C7F7416E54BA2856
+CT=CE9123C6A5A66AF788A8515721D646A0
+PT=E45F3483E343F5C3C0AC77E955369AB3
+
+I=385
+KEY=3A8C7C4DFAF4FC20075B3687018CB2E5
+CT=E45F3483E343F5C3C0AC77E955369AB3
+PT=6E7CE5F4BE070EC870691CDD494A767E
+
+I=386
+KEY=54F099B944F3F2E877322A5A48C6C49B
+CT=6E7CE5F4BE070EC870691CDD494A767E
+PT=2BB1EE551920A632E90EB9E462280365
+
+I=387
+KEY=7F4177EC5DD354DA9E3C93BE2AEEC7FE
+CT=2BB1EE551920A632E90EB9E462280365
+PT=692E0FA8B1C39CB96A11E21EA1B3365E
+
+I=388
+KEY=166F7844EC10C863F42D71A08B5DF1A0
+CT=692E0FA8B1C39CB96A11E21EA1B3365E
+PT=345C0DE98A9F472B6BCBE241BB346590
+
+I=389
+KEY=223375AD668F8F489FE693E130699430
+CT=345C0DE98A9F472B6BCBE241BB346590
+PT=D9D9313DC80FB90608614ECCC962207F
+
+I=390
+KEY=FBEA4490AE80364E9787DD2DF90BB44F
+CT=D9D9313DC80FB90608614ECCC962207F
+PT=7AEE31C488D1DD54B9AD8EE3AEFE546C
+
+I=391
+KEY=810475542651EB1A2E2A53CE57F5E023
+CT=7AEE31C488D1DD54B9AD8EE3AEFE546C
+PT=9CF27E1202080D9F3A9B5E02290204EA
+
+I=392
+KEY=1DF60B462459E68514B10DCC7EF7E4C9
+CT=9CF27E1202080D9F3A9B5E02290204EA
+PT=670085C6D3B95C6017DB9163B9D2D565
+
+I=393
+KEY=7AF68E80F7E0BAE5036A9CAFC72531AC
+CT=670085C6D3B95C6017DB9163B9D2D565
+PT=2A36E88DF74BA4B24283FEE52DDE5AA4
+
+I=394
+KEY=50C0660D00AB1E5741E9624AEAFB6B08
+CT=2A36E88DF74BA4B24283FEE52DDE5AA4
+PT=81B75B31F130467F4A1FA6CA4A329E5E
+
+I=395
+KEY=D1773D3CF19B58280BF6C480A0C9F556
+CT=81B75B31F130467F4A1FA6CA4A329E5E
+PT=D0A0347102BD11F9E2BD8E8A72D53ADC
+
+I=396
+KEY=01D7094DF32649D1E94B4A0AD21CCF8A
+CT=D0A0347102BD11F9E2BD8E8A72D53ADC
+PT=97F0187509608DF1D9B27AB5D005E505
+
+I=397
+KEY=96271138FA46C42030F930BF02192A8F
+CT=97F0187509608DF1D9B27AB5D005E505
+PT=E60139E36ECD7B24C7C98772C92A1E87
+
+I=398
+KEY=702628DB948BBF04F730B7CDCB333408
+CT=E60139E36ECD7B24C7C98772C92A1E87
+PT=7E92E19E07A469E7D49D3D07EF719157
+
+I=399
+KEY=0EB4C945932FD6E323AD8ACA2442A55F
+CT=7E92E19E07A469E7D49D3D07EF719157
+PT=F5BF8B37136F2E1F6BEC6F572021E3BA
+
+=========================
+
+KEYSIZE=192
+
+I=0
+KEY=000000000000000000000000000000000000000000000000
+CT=00000000000000000000000000000000
+PT=48E31E9E256718F29229319C19F15BA4
+
+I=1
+KEY=9643D8334A63DF4D48E31E9E256718F29229319C19F15BA4
+CT=48E31E9E256718F29229319C19F15BA4
+PT=CC01684BE9B29ED01EA7923E7D2380AA
+
+I=2
+KEY=EF334C87288C43DE84E276D5CCD586228C8EA3A264D2DB0E
+CT=CC01684BE9B29ED01EA7923E7D2380AA
+PT=8726B4E66D6B8FBAA22D42981A5A40CC
+
+I=3
+KEY=0891A045BB044B9D03C4C233A1BE09982EA3E13A7E889BC2
+CT=8726B4E66D6B8FBAA22D42981A5A40CC
+PT=83B9A21A0710FDB9C603797613772ED6
+
+I=4
+KEY=A5233519DE914717807D6029A6AEF421E8A0984C6DFFB514
+CT=83B9A21A0710FDB9C603797613772ED6
+PT=F15479A2B2C250F7E5C11D333D867CBD
+
+I=5
+KEY=A1CB19726DB4C2C77129198B146CA4D60D61857F5079C9A9
+CT=F15479A2B2C250F7E5C11D333D867CBD
+PT=C1AF401BD4E62D8BA15BEC3690F2FB25
+
+I=6
+KEY=04B03C15DB8324B3B0865990C08A895DAC3A6949C08B328C
+CT=C1AF401BD4E62D8BA15BEC3690F2FB25
+PT=01E01E3B10470286035EBD7502EF11A0
+
+I=7
+KEY=A1CB0164AB1E88EDB16647ABD0CD8BDBAF64D43CC264232C
+CT=01E01E3B10470286035EBD7502EF11A0
+PT=A681127825B718411291106AB416779A
+
+I=8
+KEY=27BFD9CB824C525617E755D3F57A939ABDF5C456767254B6
+CT=A681127825B718411291106AB416779A
+PT=5C2EBA728589A9CAA15E28E7D8E59AA0
+
+I=9
+KEY=B308E0DCE108194C4BC9EFA170F33A501CABECB1AE97CE16
+CT=5C2EBA728589A9CAA15E28E7D8E59AA0
+PT=E738305279BE636648B6D5FFA3E97E4A
+
+I=10
+KEY=FE787701EE66664BACF1DFF3094D5936541D394E0D7EB05C
+CT=E738305279BE636648B6D5FFA3E97E4A
+PT=5AF7D4C9439C7412FD7236E7685659DF
+
+I=11
+KEY=DD93D742AFA0B19CF6060B3A4AD12D24A96F0FA96528E983
+CT=5AF7D4C9439C7412FD7236E7685659DF
+PT=30D0681D4060E24D1427D1AAC498DB1B
+
+I=12
+KEY=D5D19C2FEA9DC94BC6D663270AB1CF69BD48DE03A1B03298
+CT=30D0681D4060E24D1427D1AAC498DB1B
+PT=FC9B6752064B1CCE75EBFBE91AF8F2CD
+
+I=13
+KEY=EB0954ECE44620833A4D04750CFAD3A7C8A325EABB48C055
+CT=FC9B6752064B1CCE75EBFBE91AF8F2CD
+PT=61E6AE6E035BCC3C94EF00101216904A
+
+I=14
+KEY=E6E5AB38545B6DF75BABAA1B0FA11F9B5C4C25FAA95E501F
+CT=61E6AE6E035BCC3C94EF00101216904A
+PT=BF738A4E55F036126CC9B56DED530B8C
+
+I=15
+KEY=E8C670F71E5B62B6E4D820555A51298930859097440D5B93
+CT=BF738A4E55F036126CC9B56DED530B8C
+PT=6B9CD4C227FC30C14FD881B838D9F8F5
+
+I=16
+KEY=23FF647DD75770418F44F4977DAD19487F5D112F7CD4A366
+CT=6B9CD4C227FC30C14FD881B838D9F8F5
+PT=6173EF2B5C9B569A1BD4B62C7C913844
+
+I=17
+KEY=DB94124B11CC03D9EE371BBC21364FD26489A70300459B22
+CT=6173EF2B5C9B569A1BD4B62C7C913844
+PT=709EF90F853E55123A917FB258E900F9
+
+I=18
+KEY=4821CA96B50ACA049EA9E2B3A4081AC05E18D8B158AC9BDB
+CT=709EF90F853E55123A917FB258E900F9
+PT=5D73D99E47B1DB28E0ED9B9D1C212CFA
+
+I=19
+KEY=FA47C5BF5E688F8BC3DA3B2DE3B9C1E8BEF5432C448DB721
+CT=5D73D99E47B1DB28E0ED9B9D1C212CFA
+PT=32016FFCB2AA5EA6EA0C808F60613CA2
+
+I=20
+KEY=C66A73E0D1261C2CF1DB54D151139F4E54F9C3A324EC8B83
+CT=32016FFCB2AA5EA6EA0C808F60613CA2
+PT=CAA3704F7FD76EBACB1D2A266A0899FF
+
+I=21
+KEY=FAE8E04094E572A33B78249E2EC4F1F49FE4E9854EE4127C
+CT=CAA3704F7FD76EBACB1D2A266A0899FF
+PT=E32DBD027A1A36B2EC8D0A98C9293E7E
+
+I=22
+KEY=8F2FBF9E40182950D855999C54DEC7467369E31D87CD2C02
+CT=E32DBD027A1A36B2EC8D0A98C9293E7E
+PT=1C117311882C0D5159A9DFD5C3C68D95
+
+I=23
+KEY=F6FB8F6DFAA034BFC444EA8DDCF2CA172AC03CC8440BA197
+CT=1C117311882C0D5159A9DFD5C3C68D95
+PT=5E379C2471DB04582CD861E6F8A419D7
+
+I=24
+KEY=699DCA67F4EF50C49A7376A9AD29CE4F06185D2EBCAFB840
+CT=5E379C2471DB04582CD861E6F8A419D7
+PT=5932A84C6ACBD8452EE9AC47CE4B6BD8
+
+I=25
+KEY=F568B4F126486CE4C341DEE5C7E2160A28F1F16972E4D398
+CT=5932A84C6ACBD8452EE9AC47CE4B6BD8
+PT=00634EED1D18C84AE0A8198CF791DE81
+
+I=26
+KEY=C49E5E8D366B6FE7C3229008DAFADE40C859E8E585750D19
+CT=00634EED1D18C84AE0A8198CF791DE81
+PT=E10C93B1C466FFF0B6EB6DB50AF271EC
+
+I=27
+KEY=22B07DB9ED443A9D222E03B91E9C21B07EB285508F877CF5
+CT=E10C93B1C466FFF0B6EB6DB50AF271EC
+PT=58A0C680F565E63A7E41C6EAC50A3B01
+
+I=28
+KEY=2BDF4CCE2B4CAFDD7A8EC539EBF9C78A00F343BA4A8D47F4
+CT=58A0C680F565E63A7E41C6EAC50A3B01
+PT=92921B2AA7FC6367199A4C42FAE0E2A4
+
+I=29
+KEY=E2BE29F6905D41C5E81CDE134C05A4ED19690FF8B06DA550
+CT=92921B2AA7FC6367199A4C42FAE0E2A4
+PT=B6EC2A692D2657E5506F2C3BA1912799
+
+I=30
+KEY=E43634FD3DB719C75EF0F47A6123F308490623C311FC82C9
+CT=B6EC2A692D2657E5506F2C3BA1912799
+PT=23ECD0813B1A7090CF9BE874D6B0846C
+
+I=31
+KEY=ACA2F21EF46E30B57D1C24FB5A398398869DCBB7C74C06A5
+CT=23ECD0813B1A7090CF9BE874D6B0846C
+PT=04BD52F4C1AB8DF4816A6E11F8B54452
+
+I=32
+KEY=0130B37AFE24D66079A1760F9B920E6C07F7A5A63FF942F7
+CT=04BD52F4C1AB8DF4816A6E11F8B54452
+PT=DFA0074DEFEDB44D0D96AD6020D1A37D
+
+I=33
+KEY=00AC6BF5E3AD20FFA6017142747FBA210A6108C61F28E18A
+CT=DFA0074DEFEDB44D0D96AD6020D1A37D
+PT=5AB15057E05F73FAAF12C0EC26D3F02F
+
+I=34
+KEY=E3A70EBF3D9167AAFCB021159420C9DBA573C82A39FB11A5
+CT=5AB15057E05F73FAAF12C0EC26D3F02F
+PT=6ECC2F23AB7854E97F215C52EF1E62E0
+
+I=35
+KEY=CBCD9116DC78FA64927C0E363F589D32DA529478D6E57345
+CT=6ECC2F23AB7854E97F215C52EF1E62E0
+PT=930B3EBDE0989049056022E83FC9EF1E
+
+I=36
+KEY=FBB5E5462DE715180177308BDFC00D7BDF32B690E92C9C5B
+CT=930B3EBDE0989049056022E83FC9EF1E
+PT=1EE4ABB9ACD70B93A83BCD8751F858DE
+
+I=37
+KEY=E5D2B1ACD8BE6DF21F939B32731706E877097B17B8D4C485
+CT=1EE4ABB9ACD70B93A83BCD8751F858DE
+PT=FCAC610EA0D309C6D36EED5A4BC04036
+
+I=38
+KEY=54DD0B6CB083BDE8E33FFA3CD3C40F2EA467964DF31484B3
+CT=FCAC610EA0D309C6D36EED5A4BC04036
+PT=161D5EE8F50A3F69A11ADFEAF1A2A2AA
+
+I=39
+KEY=28309F7EB99AAEE1F522A4D426CE3047057D49A702B62619
+CT=161D5EE8F50A3F69A11ADFEAF1A2A2AA
+PT=D9D365B061D2F3BF9DF94181837621B4
+
+I=40
+KEY=E55ECDDFAE95A2C92CF1C164471CC3F89884082681C007AD
+CT=D9D365B061D2F3BF9DF94181837621B4
+PT=938647A6AAD455D89A6DFEFE60D62331
+
+I=41
+KEY=C9CEE1C9D89DF76ABF7786C2EDC8962002E9F6D8E116249C
+CT=938647A6AAD455D89A6DFEFE60D62331
+PT=06A002DDC7DC4F22F9B1D5734C312AAA
+
+I=42
+KEY=B26709109B66C916B9D7841F2A14D902FB5823ABAD270E36
+CT=06A002DDC7DC4F22F9B1D5734C312AAA
+PT=BB45E9BE2237E3288F56EDD0D9AD6734
+
+I=43
+KEY=2FAD2FF32E10680502926DA108233A2A740ECE7B748A6902
+CT=BB45E9BE2237E3288F56EDD0D9AD6734
+PT=CF5A1338F5FA7ED4C77F6EA3836F079A
+
+I=44
+KEY=63D3D62540C790D1CDC87E99FDD944FEB371A0D8F7E56E98
+CT=CF5A1338F5FA7ED4C77F6EA3836F079A
+PT=32F2D628117ADB46383FC101B58E95A6
+
+I=45
+KEY=0DF38CE71CF26A19FF3AA8B1ECA39FB88B4E61D9426BFB3E
+CT=32F2D628117ADB46383FC101B58E95A6
+PT=3A3CCEA99D43887AC64498AB4EFC87DD
+
+I=46
+KEY=7EEEB78A0C9BAA9FC506661871E017C24D0AF9720C977CE3
+CT=3A3CCEA99D43887AC64498AB4EFC87DD
+PT=787DC1C632C4AA77D42324338C510146
+
+I=47
+KEY=4DF02EE427AE29A1BD7BA7DE4324BDB59929DD4180C67DA5
+CT=787DC1C632C4AA77D42324338C510146
+PT=BB0635A471D26B80E5E387E4F14A1626
+
+I=48
+KEY=D6983F5E8BE728D9067D927A32F6D6357CCA5AA5718C6B83
+CT=BB0635A471D26B80E5E387E4F14A1626
+PT=14A9AA3EE6343C2D57E0F2ED7A05DC0D
+
+I=49
+KEY=BD84A7CD471613B512D43844D4C2EA182B2AA8480B89B78E
+CT=14A9AA3EE6343C2D57E0F2ED7A05DC0D
+PT=25E254AD6C33908BC07B3DEC4052F549
+
+I=50
+KEY=E54A2146242AADFB37366CE9B8F17A93EB5195A44BDB42C7
+CT=25E254AD6C33908BC07B3DEC4052F549
+PT=10E09F426E6F33CD21DF1EB748A46088
+
+I=51
+KEY=0517B745BCE24E0527D6F3ABD69E495ECA8E8B13037F224F
+CT=10E09F426E6F33CD21DF1EB748A46088
+PT=B65D2FFE83F9469AA2B1ABC559EAAB87
+
+I=52
+KEY=8297790C75E8931C918BDC5555670FC4683F20D65A9589C8
+CT=B65D2FFE83F9469AA2B1ABC559EAAB87
+PT=E743F6441CCF9703FF4B8E3F4921ACDF
+
+I=53
+KEY=7EC47C0C5663CD4C76C82A1149A898C79774AEE913B42517
+CT=E743F6441CCF9703FF4B8E3F4921ACDF
+PT=BECC5CF2F2C62A9E7D3CF979A9E96F94
+
+I=54
+KEY=FBB1F10529FABEB3C80476E3BB6EB259EA485790BA5D4A83
+CT=BECC5CF2F2C62A9E7D3CF979A9E96F94
+PT=3718199958EAA473B980B95F9C76E03F
+
+I=55
+KEY=EE4113D30720269DFF1C6F7AE384162A53C8EECF262BAABC
+CT=3718199958EAA473B980B95F9C76E03F
+PT=D15525B8BBB6D209E0BB3B6F5ACB2556
+
+I=56
+KEY=488286944DC6B0842E494AC25832C423B373D5A07CE08FEA
+CT=D15525B8BBB6D209E0BB3B6F5ACB2556
+PT=0270AF07DDA52DF7CA7B0EE7DF098A80
+
+I=57
+KEY=A32A880A84E7EDB82C39E5C58597E9D47908DB47A3E9056A
+CT=0270AF07DDA52DF7CA7B0EE7DF098A80
+PT=2D380F99A182CD14CFFEF5E88B93B416
+
+I=58
+KEY=DBD0FD5053BC52C60101EA5C241524C0B6F62EAF287AB17C
+CT=2D380F99A182CD14CFFEF5E88B93B416
+PT=47FE8C67DCBC616E4C984D323EA4A45B
+
+I=59
+KEY=D79F78A4726F5FCA46FF663BF8A945AEFA6E639D16DE1527
+CT=47FE8C67DCBC616E4C984D323EA4A45B
+PT=FA595C69C3286771FB8C921DFBBFFC2E
+
+I=60
+KEY=0C88AAD46F951FB6BCA63A523B8122DF01E2F180ED61E909
+CT=FA595C69C3286771FB8C921DFBBFFC2E
+PT=8FA64C511FCE6FC987B327D12EBDADAD
+
+I=61
+KEY=762EEA21D382067E33007603244F4D168651D651C3DC44A4
+CT=8FA64C511FCE6FC987B327D12EBDADAD
+PT=8F52C709508408B40C241FD38E515E76
+
+I=62
+KEY=EA05788C20FB364EBC52B10A74CB45A28A75C9824D8D1AD2
+CT=8F52C709508408B40C241FD38E515E76
+PT=7CFD332B306684AC92279CE06F1287D8
+
+I=63
+KEY=D4B2582B094D874DC0AF822144ADC10E18525562229F9D0A
+CT=7CFD332B306684AC92279CE06F1287D8
+PT=0DA14F6619665E0128044355481BD658
+
+I=64
+KEY=C080E7033FDF1BCFCD0ECD475DCB9F0F305616376A844B52
+CT=0DA14F6619665E0128044355481BD658
+PT=FEDEBE73AA4047AF27E86A8B9E8E2ED7
+
+I=65
+KEY=C5BA9667999CF2D633D07334F78BD8A017BE7CBCF40A6585
+CT=FEDEBE73AA4047AF27E86A8B9E8E2ED7
+PT=12CD6896129E376AAB9C0E980F3B7CD2
+
+I=66
+KEY=65FF092A539C4600211D1BA2E515EFCABC227224FB311957
+CT=12CD6896129E376AAB9C0E980F3B7CD2
+PT=04E7939B352F7B5C38B7EC5784EC78C2
+
+I=67
+KEY=F98E7062F9EBE61C25FA8839D03A949684959E737FDD6195
+CT=04E7939B352F7B5C38B7EC5784EC78C2
+PT=0184996278A57E36E608E95616C46964
+
+I=68
+KEY=306FBEFB3BF4E241247E115BA89FEAA0629D7725691908F1
+CT=0184996278A57E36E608E95616C46964
+PT=92179E392E05C8B96A0CFAC36109B09E
+
+I=69
+KEY=EE641F5DB58F9057B6698F62869A221908918DE60810B86F
+CT=92179E392E05C8B96A0CFAC36109B09E
+PT=7F197B01172C809635198E6B156D13BC
+
+I=70
+KEY=EADB8B255F98FD9DC970F46391B6A28F3D88038D1D7DABD3
+CT=7F197B01172C809635198E6B156D13BC
+PT=46F6DD79AD079DCFBC451B24ECDDA4FA
+
+I=71
+KEY=47225D75FE68FFA08F86291A3CB13F4081CD18A9F1A00F29
+CT=46F6DD79AD079DCFBC451B24ECDDA4FA
+PT=B5DAA09E3545F92FF44176187A1F9179
+
+I=72
+KEY=7CDECC21E72E54F43A5C898409F4C66F758C6EB18BBF9E50
+CT=B5DAA09E3545F92FF44176187A1F9179
+PT=F51A35F3DD410132EEC9E9F22A6F6FAB
+
+I=73
+KEY=75D1AAFDBFE72C94CF46BC77D4B5C75D9B458743A1D0F1FB
+CT=F51A35F3DD410132EEC9E9F22A6F6FAB
+PT=D1CC6D95B58793C342CF14AF250D5E40
+
+I=74
+KEY=41874C54BD58757A1E8AD1E26132549ED98A93EC84DDAFBB
+CT=D1CC6D95B58793C342CF14AF250D5E40
+PT=A1FAB3B352A887A829357528FED4B80E
+
+I=75
+KEY=1D94704F4A51A5CABF706251339AD336F0BFE6C47A0917B5
+CT=A1FAB3B352A887A829357528FED4B80E
+PT=CBC6473B3AA4DE2D64EED554CA241EAC
+
+I=76
+KEY=A41B52E0AE7E568074B6256A093E0D1B94513390B02D0919
+CT=CBC6473B3AA4DE2D64EED554CA241EAC
+PT=19DC6E89D71DCE5DCECD1A6F85C3FBD6
+
+I=77
+KEY=85F21BCD70691F596D6A4BE3DE23C3465A9C29FF35EEF2CF
+CT=19DC6E89D71DCE5DCECD1A6F85C3FBD6
+PT=EC6974E51B21F26A100E66183C68FD15
+
+I=78
+KEY=CAD0B254A88B669681033F06C502312C4A924FE709860FDA
+CT=EC6974E51B21F26A100E66183C68FD15
+PT=A16B6F78009B6E30CB758E87AD4D8034
+
+I=79
+KEY=8AC49B19582BFCF32068507EC5995F1C81E7C160A4CB8FEE
+CT=A16B6F78009B6E30CB758E87AD4D8034
+PT=CB5C20AAFA898193BC34FF3EE460B313
+
+I=80
+KEY=988F8D4F3A66AC99EB3470D43F10DE8F3DD33E5E40AB3CFD
+CT=CB5C20AAFA898193BC34FF3EE460B313
+PT=397F92C8E69E0916E30DC6889779799E
+
+I=81
+KEY=DE2D26C6130E006ED24BE21CD98ED799DEDEF8D6D7D24563
+CT=397F92C8E69E0916E30DC6889779799E
+PT=9A9CBD9380E2187855CAE5A73D58480F
+
+I=82
+KEY=BF6BE6D55C04977348D75F8F596CCFE18B141D71EA8A0D6C
+CT=9A9CBD9380E2187855CAE5A73D58480F
+PT=B67B360EE0FF297D3662F5B7CDB82CB9
+
+I=83
+KEY=6582BCA895FA1221FEAC6981B993E69CBD76E8C6273221D5
+CT=B67B360EE0FF297D3662F5B7CDB82CB9
+PT=2D146ED9236082D2D71810969A1AB1FB
+
+I=84
+KEY=6AC68BB8BBC7F520D3B807589AF3644E6A6EF850BD28902E
+CT=2D146ED9236082D2D71810969A1AB1FB
+PT=4B9F55652C40B6DA963A98D875ADACE4
+
+I=85
+KEY=180DAB1B14A92DB29827523DB6B3D294FC546088C8853CCA
+CT=4B9F55652C40B6DA963A98D875ADACE4
+PT=FC0A8A3D511F5FAFF0A3DD13B49E5A13
+
+I=86
+KEY=7ABD7440D5EE5FE2642DD800E7AC8D3B0CF7BD9B7C1B66D9
+CT=FC0A8A3D511F5FAFF0A3DD13B49E5A13
+PT=4231C02AD3231C3EB7AEB9135B95AC4B
+
+I=87
+KEY=54ACAE182B5FDACF261C182A348F9105BB590488278ECA92
+CT=4231C02AD3231C3EB7AEB9135B95AC4B
+PT=4C3A949ACCCBB55F9415C81B1413FD9D
+
+I=88
+KEY=015706F99E81CC026A268CB0F844245A2F4CCC93339D370F
+CT=4C3A949ACCCBB55F9415C81B1413FD9D
+PT=E9B1CEAF77B64A88CC3E020B16E1BF7E
+
+I=89
+KEY=929BD0A1CC6450E78397421F8FF26ED2E372CE98257C8871
+CT=E9B1CEAF77B64A88CC3E020B16E1BF7E
+PT=98FFEA0827068CB0B508CA520D8B43F7
+
+I=90
+KEY=9B81EC47D8442D311B68A817A8F4E262567A04CA28F7CB86
+CT=98FFEA0827068CB0B508CA520D8B43F7
+PT=BEDA572C3CA3FEF97F7071DA35414EA1
+
+I=91
+KEY=93B211B869CBECCBA5B2FF3B94571C9B290A75101DB68527
+CT=BEDA572C3CA3FEF97F7071DA35414EA1
+PT=35E8CB8302748C8623A09980909FB516
+
+I=92
+KEY=BC5320E4025EB960905A34B89623901D0AAAEC908D293031
+CT=35E8CB8302748C8623A09980909FB516
+PT=E136148B2FA5AF5CD3F8BC3883566CB8
+
+I=93
+KEY=C4EC937F948D0B5A716C2033B9863F41D95250A80E7F5C89
+CT=E136148B2FA5AF5CD3F8BC3883566CB8
+PT=B7CE40E3E3D30191CDF4AB5BE98F347A
+
+I=94
+KEY=6D381856C149D9DCC6A260D05A553ED014A6FBF3E7F068F3
+CT=B7CE40E3E3D30191CDF4AB5BE98F347A
+PT=A821E934DAAE37FF3136E769DAC315FB
+
+I=95
+KEY=A3679C5957C656DE6E8389E480FB092F25901C9A3D337D08
+CT=A821E934DAAE37FF3136E769DAC315FB
+PT=4227B96A0CC6CA1C21BCF8B1ADB3BDE1
+
+I=96
+KEY=BE7112453B1DF3EC2CA4308E8C3DC333042CE42B9080C0E9
+CT=4227B96A0CC6CA1C21BCF8B1ADB3BDE1
+PT=EE36BBFDDF19165F9E64AE79B4CF06A9
+
+I=97
+KEY=AEA4A2D5CD0A2FC7C2928B735324D56C9A484A52244FC640
+CT=EE36BBFDDF19165F9E64AE79B4CF06A9
+PT=C3DFE088C6767BC939F492C1FA9604CD
+
+I=98
+KEY=A16FC5F22F03984F014D6BFB9552AEA5A3BCD893DED9C28D
+CT=C3DFE088C6767BC939F492C1FA9604CD
+PT=DB1202E468119D977868F6E294E3CC3A
+
+I=99
+KEY=A4E0565DD419BDD1DA5F691FFD433332DBD42E714A3A0EB7
+CT=DB1202E468119D977868F6E294E3CC3A
+PT=6F2F682BA4F95EB8C5B883C7660B2653
+
+I=100
+KEY=3CAEE44D0E85058EB570013459BA6D8A1E6CADB62C3128E4
+CT=6F2F682BA4F95EB8C5B883C7660B2653
+PT=1036B4AA6C897D36DFE6658A953E5075
+
+I=101
+KEY=4E883A500CA89963A546B59E353310BCC18AC83CB90F7891
+CT=1036B4AA6C897D36DFE6658A953E5075
+PT=04FCB3A81E5319A16CCF212719906229
+
+I=102
+KEY=ADED5A405C5C095AA1BA06362B60091DAD45E91BA09F1AB8
+CT=04FCB3A81E5319A16CCF212719906229
+PT=CD79BAC069BB58605D43005B927816E5
+
+I=103
+KEY=5499B441405D16B06CC3BCF642DB517DF006E94032E70C5D
+CT=CD79BAC069BB58605D43005B927816E5
+PT=DB5B3C625D1F66CF28A86CC100472398
+
+I=104
+KEY=D31221246382CA8EB79880941FC437B2D8AE858132A02FC5
+CT=DB5B3C625D1F66CF28A86CC100472398
+PT=D8732A2C16EC6AE202371AF03A6F91E8
+
+I=105
+KEY=CDF928E97051F08B6FEBAAB809285D50DA999F7108CFBE2D
+CT=D8732A2C16EC6AE202371AF03A6F91E8
+PT=F0A1A353A8AB9A893F621F0BEA3B4F01
+
+I=106
+KEY=10CC2EED0ECBD1E69F4A09EBA183C7D9E5FB807AE2F4F12C
+CT=F0A1A353A8AB9A893F621F0BEA3B4F01
+PT=27E4451BD15E43F301E138713DC12E78
+
+I=107
+KEY=03C4F5E1FD3D34D1B8AE4CF070DD842AE41AB80BDF35DF54
+CT=27E4451BD15E43F301E138713DC12E78
+PT=C7FA931DA414CB37A9BDB6F128E082EE
+
+I=108
+KEY=CC5D7D36D085E3257F54DFEDD4C94F1D4DA70EFAF7D55DBA
+CT=C7FA931DA414CB37A9BDB6F128E082EE
+PT=A6777D51A0A1C94DD74A18795341015F
+
+I=109
+KEY=9F4EE4750FF3F53AD923A2BC746886509AED1683A4945CE5
+CT=A6777D51A0A1C94DD74A18795341015F
+PT=32A4D930A5597E02D7076E399D18D895
+
+I=110
+KEY=8525417BB6D8095BEB877B8CD131F8524DEA78BA398C8470
+CT=32A4D930A5597E02D7076E399D18D895
+PT=1B78FCF274EEB1E597998EE4EFFF9F8B
+
+I=111
+KEY=54EFA98071F1EF62F0FF877EA5DF49B7DA73F65ED6731BFB
+CT=1B78FCF274EEB1E597998EE4EFFF9F8B
+PT=2997FEE2823CC84DA14E8439449F5C7C
+
+I=112
+KEY=2505931CE4D41D16D968799C27E381FA7B3D726792EC4787
+CT=2997FEE2823CC84DA14E8439449F5C7C
+PT=810534A9E8DB2808FEE681B13C04411D
+
+I=113
+KEY=C2DF863BEB4F27AB586D4D35CF38A9F285DBF3D6AEE8069A
+CT=810534A9E8DB2808FEE681B13C04411D
+PT=BE2380994365F1D7FC8278E86C8B497D
+
+I=114
+KEY=036C0C95D0C26B66E64ECDAC8C5D582579598B3EC2634FE7
+CT=BE2380994365F1D7FC8278E86C8B497D
+PT=EFEC3977D5A21DC4AC786E786CA3ECE9
+
+I=115
+KEY=BD05AD63A0A9F1B509A2F4DB59FF45E1D521E546AEC0A30E
+CT=EFEC3977D5A21DC4AC786E786CA3ECE9
+PT=22A7280D8231895EA4F0B6A39AC583C3
+
+I=116
+KEY=A16DFA00981597B42B05DCD6DBCECCBF71D153E5340520CD
+CT=22A7280D8231895EA4F0B6A39AC583C3
+PT=0CC61E91B3CBCD0E190D52059E27647A
+
+I=117
+KEY=ABC1AD453235832727C3C247680501B168DC01E0AA2244B7
+CT=0CC61E91B3CBCD0E190D52059E27647A
+PT=5CE91F77F7C8F0AB1BBA802D2FFF0E9B
+
+I=118
+KEY=64D40ACA0F526EC67B2ADD309FCDF11A736681CD85DD4A2C
+CT=5CE91F77F7C8F0AB1BBA802D2FFF0E9B
+PT=255459BE5A27E08942A049F6EC44582E
+
+I=119
+KEY=8BB5C7D8B2B177855E7E848EC5EA119331C6C83B69991202
+CT=255459BE5A27E08942A049F6EC44582E
+PT=28E2E20115C3665D9D88CB74681301EA
+
+I=120
+KEY=4E30FCC4C182F471769C668FD02977CEAC4E034F018A13E8
+CT=28E2E20115C3665D9D88CB74681301EA
+PT=2E96E6BBCD999F4B1507C7EC9E4B8430
+
+I=121
+KEY=906B361E9D72E107580A80341DB0E885B949C4A39FC197D8
+CT=2E96E6BBCD999F4B1507C7EC9E4B8430
+PT=03DED0A95164E5FA215E9C49C433E95B
+
+I=122
+KEY=F656F5D9D973C02C5BD4509D4CD40D7F981758EA5BF27E83
+CT=03DED0A95164E5FA215E9C49C433E95B
+PT=AD9C16D2567B73FCA4866FE16CF09CDA
+
+I=123
+KEY=8811A4ACDF37A140F648464F1AAF7E833C91370B3702E259
+CT=AD9C16D2567B73FCA4866FE16CF09CDA
+PT=68539BFF0F8CC23A0A3267796A11B75C
+
+I=124
+KEY=E5AF2E8CDBAD01589E1BDDB01523BCB936A350725D135505
+CT=68539BFF0F8CC23A0A3267796A11B75C
+PT=B15F623E5A7D73452A419EB04AFCF72E
+
+I=125
+KEY=C9E743CAD731A62E2F44BF8E4F5ECFFC1CE2CEC217EFA22B
+CT=B15F623E5A7D73452A419EB04AFCF72E
+PT=520142AFDA69E9CFA98D8DD59CCB12BC
+
+I=126
+KEY=6CF6C656FFBB77807D45FD2195372633B56F43178B24B097
+CT=520142AFDA69E9CFA98D8DD59CCB12BC
+PT=7EC2A8430F23A5E183E0032DAB5232C5
+
+I=127
+KEY=772CEE9F934D57D4038755629A1483D2368F403A20768252
+CT=7EC2A8430F23A5E183E0032DAB5232C5
+PT=E5E3A5D968B1FF774B55CCA06BE3BD65
+
+I=128
+KEY=9A4DAB93F3C74EBBE664F0BBF2A57CA57DDA8C9A4B953F37
+CT=E5E3A5D968B1FF774B55CCA06BE3BD65
+PT=9608643D0A34DA28372A7E7E34427E1B
+
+I=129
+KEY=EF0F60BCBA3374E0706C9486F891A68D4AF0F2E47FD7412C
+CT=9608643D0A34DA28372A7E7E34427E1B
+PT=B22BD410584F29610801B18EDAB1BD19
+
+I=130
+KEY=DE013A6C3440AFF3C2474096A0DE8FEC42F1436AA566FC35
+CT=B22BD410584F29610801B18EDAB1BD19
+PT=ADEC4519F1A7AD74BCCECABEDCF20D73
+
+I=131
+KEY=2B5B547A934A5A376FAB058F51792298FE3F89D47994F146
+CT=ADEC4519F1A7AD74BCCECABEDCF20D73
+PT=E04D4FF54191BEEEF5B295A32DA2ADE5
+
+I=132
+KEY=BF356F2FFC2C538F8FE64A7A10E89C760B8D1C7754365CA3
+CT=E04D4FF54191BEEEF5B295A32DA2ADE5
+PT=3F9531EDD5072F7A9F2A62ECC2CCE50A
+
+I=133
+KEY=7CEBD7310CC4791AB0737B97C5EFB30C94A77E9B96FAB9A9
+CT=3F9531EDD5072F7A9F2A62ECC2CCE50A
+PT=C3DC95781FAE7BB6C02BD08B3617DDF1
+
+I=134
+KEY=192741D2AB9C887673AFEEEFDA41C8BA548CAE10A0ED6458
+CT=C3DC95781FAE7BB6C02BD08B3617DDF1
+PT=F69B837F168B9A9E637E7357B65F2B60
+
+I=135
+KEY=38552740A79FB5BF85346D90CCCA522437F2DD4716B24F38
+CT=F69B837F168B9A9E637E7357B65F2B60
+PT=40DCDF58E7EFDD62C114A83F8AC898BB
+
+I=136
+KEY=A0AED2C07C2168B6C5E8B2C82B258F46F6E675789C7AD783
+CT=40DCDF58E7EFDD62C114A83F8AC898BB
+PT=27F78F3BD8E04A8646EBF364155A71ED
+
+I=137
+KEY=2B4FAEBF17993E12E21F3DF3F3C5C5C0B00D861C8920A66E
+CT=27F78F3BD8E04A8646EBF364155A71ED
+PT=F305DFC8EAD44E786F59B0551C7104F5
+
+I=138
+KEY=96819F6E9738209F111AE23B19118BB8DF5436499551A29B
+CT=F305DFC8EAD44E786F59B0551C7104F5
+PT=2E47F833BE7C06ED1E42AC11366F4BEF
+
+I=139
+KEY=AAEA16BAC3E84DD73F5D1A08A76D8D55C1169A58A33EE974
+CT=2E47F833BE7C06ED1E42AC11366F4BEF
+PT=A9D3A511C3D76779B607AAB2556823AD
+
+I=140
+KEY=F66BA47C56AC5A36968EBF1964BAEA2C771130EAF656CAD9
+CT=A9D3A511C3D76779B607AAB2556823AD
+PT=153A7CC2387C05289F759C85076CDD88
+
+I=141
+KEY=1D892BCCFAF3DA1083B4C3DB5CC6EF04E864AC6FF13A1751
+CT=153A7CC2387C05289F759C85076CDD88
+PT=76B6089030D914F0F4C6078193207A7D
+
+I=142
+KEY=DAEBAF980095A397F502CB4B6C1FFBF41CA2ABEE621A6D2C
+CT=76B6089030D914F0F4C6078193207A7D
+PT=EB71D127848BA397451D45801830461E
+
+I=143
+KEY=85F86FADA92076AB1E731A6CE894586359BFEE6E7A2A2B32
+CT=EB71D127848BA397451D45801830461E
+PT=B79D9BE1B2DB808B412413C203C710DF
+
+I=144
+KEY=BEADDA5CE1E7F3D4A9EE818D5A4FD8E8189BFDAC79ED3BED
+CT=B79D9BE1B2DB808B412413C203C710DF
+PT=E6423467C3CA69D94C944FA2A97BB61F
+
+I=145
+KEY=D4664C8DCFA8304D4FACB5EA9985B131540FB20ED0968DF2
+CT=E6423467C3CA69D94C944FA2A97BB61F
+PT=18EFF53B7D62A9D9ED8AB9ABE67FC110
+
+I=146
+KEY=9CCF1EEAF55FEA5A574340D1E4E718E8B9850BA536E94CE2
+CT=18EFF53B7D62A9D9ED8AB9ABE67FC110
+PT=8E6A4AC577153D806ED71A07319CAB67
+
+I=147
+KEY=7D840184CB9D3A05D9290A1493F22568D75211A20775E785
+CT=8E6A4AC577153D806ED71A07319CAB67
+PT=B7B23D8E7D344F39B3EA0D67CCF37377
+
+I=148
+KEY=D72F35B6DD825B656E9B379AEEC66A5164B81CC5CB8694F2
+CT=B7B23D8E7D344F39B3EA0D67CCF37377
+PT=3385AD0503AF68BFBFBEAA89B1C87736
+
+I=149
+KEY=48335F06D7C27C955D1E9A9FED6902EEDB06B64C7A4EE3C4
+CT=3385AD0503AF68BFBFBEAA89B1C87736
+PT=9FC40A6B984BEEC182AB650B05CEF38C
+
+I=150
+KEY=A66149286535FD6EC2DA90F47522EC2F59ADD3477F801048
+CT=9FC40A6B984BEEC182AB650B05CEF38C
+PT=4CEC52C9DE143486DFC9D098637DFBB5
+
+I=151
+KEY=7EA78450FAEEF8BF8E36C23DAB36D8A9866403DF1CFDEBFD
+CT=4CEC52C9DE143486DFC9D098637DFBB5
+PT=EB8E40333ACD18EFB04DC0A857DDCD7A
+
+I=152
+KEY=197DDF842BAEF36E65B8820E91FBC0463629C3774B202687
+CT=EB8E40333ACD18EFB04DC0A857DDCD7A
+PT=F1AFF04058F819B0F191398C8022130F
+
+I=153
+KEY=D68841CF848B0F619417724EC903D9F6C7B8FAFBCB023588
+CT=F1AFF04058F819B0F191398C8022130F
+PT=6DF4A95D8D602C0E53F5A5C350D3EB64
+
+I=154
+KEY=6DFA0F7B01A2F011F9E3DB134463F5F8944D5F389BD1DEEC
+CT=6DF4A95D8D602C0E53F5A5C350D3EB64
+PT=057D8F9BE9260BB3A0382CD2EF7D1FCA
+
+I=155
+KEY=88227C4AD1CBC8F0FC9E5488AD45FE4B347573EA74ACC126
+CT=057D8F9BE9260BB3A0382CD2EF7D1FCA
+PT=D4EDACCB9B7B35F2A0690E22C91E25AE
+
+I=156
+KEY=848B8E3213D366B22873F843363ECBB9941C7DC8BDB2E488
+CT=D4EDACCB9B7B35F2A0690E22C91E25AE
+PT=A2F61B5BDD9F580B26C329B878BAFA3C
+
+I=157
+KEY=FA3A476D1C6E33FD8A85E318EBA193B2B2DF5470C5081EB4
+CT=A2F61B5BDD9F580B26C329B878BAFA3C
+PT=5A0616880CD40B72B58CF268EC8F934B
+
+I=158
+KEY=C9F77D58F58D5FEDD083F590E77598C00753A61829878DFF
+CT=5A0616880CD40B72B58CF268EC8F934B
+PT=0E42047D7EDE2A5FBB37767A69A45B9B
+
+I=159
+KEY=00A523C700FBB663DEC1F1ED99ABB29FBC64D0624023D664
+CT=0E42047D7EDE2A5FBB37767A69A45B9B
+PT=2AFA823A10BB436A7B00816C80A52711
+
+I=160
+KEY=660275323A59E807F43B73D78910F1F5C764510EC086F175
+CT=2AFA823A10BB436A7B00816C80A52711
+PT=B2406F3F9160E25DF7C9AA81AF6EB449
+
+I=161
+KEY=47A4FCDB97D4A383467B1CE8187013A830ADFB8F6FE8453C
+CT=B2406F3F9160E25DF7C9AA81AF6EB449
+PT=B1E01D2A401495F8DDAEAB7B04BEB23D
+
+I=162
+KEY=2BDD5B54D4EB236AF79B01C258648650ED0350F46B56F701
+CT=B1E01D2A401495F8DDAEAB7B04BEB23D
+PT=390572A9ECE28A0E0BBDC729DBE5F79A
+
+I=163
+KEY=328202460B65D004CE9E736BB4860C5EE6BE97DDB0B3009B
+CT=390572A9ECE28A0E0BBDC729DBE5F79A
+PT=5D41665811702124C597DB4E3BD950E1
+
+I=164
+KEY=94457C0A759DF4E993DF1533A5F62D7A23294C938B6A507A
+CT=5D41665811702124C597DB4E3BD950E1
+PT=689EB1CB1586D127696E8725DEE49E58
+
+I=165
+KEY=4E0226CA850DDC79FB41A4F8B070FC5D4A47CBB6558ECE22
+CT=689EB1CB1586D127696E8725DEE49E58
+PT=A2D9DF62AC8BF8A93E7A954416864052
+
+I=166
+KEY=659C817A1C10A24D59987B9A1CFB04F4743D5EF243088E70
+CT=A2D9DF62AC8BF8A93E7A954416864052
+PT=507835696F1920BD4A05797563DF5769
+
+I=167
+KEY=92192D9175187FB409E04EF373E224493E38278720D7D919
+CT=507835696F1920BD4A05797563DF5769
+PT=2070413F5103482B6C83129304E5AC87
+
+I=168
+KEY=6959063FBA59CCEC29900FCC22E16C6252BB35142432759E
+CT=2070413F5103482B6C83129304E5AC87
+PT=BF7FD1E21B41B1F1C2625C1097F1BCB8
+
+I=169
+KEY=5722993710D811B196EFDE2E39A0DD9390D96904B3C3C926
+CT=BF7FD1E21B41B1F1C2625C1097F1BCB8
+PT=6E2236654F2999545F50FA9CF63F9F2E
+
+I=170
+KEY=038FA98E7A226A9FF8CDE84B768944C7CF89939845FC5608
+CT=6E2236654F2999545F50FA9CF63F9F2E
+PT=3F370291CEDCB115C8EE409A8EEB46D6
+
+I=171
+KEY=CACF0199725D5466C7FAEADAB855F5D20767D302CB1710DE
+CT=3F370291CEDCB115C8EE409A8EEB46D6
+PT=84023DB96D373EC8315AE78A3B7E82FB
+
+I=172
+KEY=7B40321CB11520D143F8D763D562CB1A363D3488F0699225
+CT=84023DB96D373EC8315AE78A3B7E82FB
+PT=C35064D82A3016FE2C2E2CC0627E7B5C
+
+I=173
+KEY=F045CFEC2A6BC7E580A8B3BBFF52DDE41A1318489217E979
+CT=C35064D82A3016FE2C2E2CC0627E7B5C
+PT=D78DFFE87C0F95856C31A07BADA23084
+
+I=174
+KEY=86B3CA5F50CEF6C557254C53835D48617622B8333FB5D9FD
+CT=D78DFFE87C0F95856C31A07BADA23084
+PT=5B5B5D3CA5C6E5CF18F3E4EE802BE82B
+
+I=175
+KEY=E6D99DC0C58655B70C7E116F269BADAE6ED15CDDBF9E31D6
+CT=5B5B5D3CA5C6E5CF18F3E4EE802BE82B
+PT=DB65A82F6EB7A410A367165900E85117
+
+I=176
+KEY=B8F770CFBE47D070D71BB940482C09BECDB64A84BF7660C1
+CT=DB65A82F6EB7A410A367165900E85117
+PT=FE8BE8484D925043102238FF63FDAC57
+
+I=177
+KEY=FF09ADB06FE587192990510805BE59FDDD94727BDC8BCC96
+CT=FE8BE8484D925043102238FF63FDAC57
+PT=AC36E01A7AD482A8D89703D2A6528720
+
+I=178
+KEY=B5C937A4019CDAD185A6B1127F6ADB55050371A97AD94BB6
+CT=AC36E01A7AD482A8D89703D2A6528720
+PT=9F3698CE06C6497C89B58CA723F7ECAA
+
+I=179
+KEY=F60CAF8FB99B63B21A9029DC79AC92298CB6FD0E592EA71C
+CT=9F3698CE06C6497C89B58CA723F7ECAA
+PT=FB8CE2E1D332FE4557B6C5CF1676F2FB
+
+I=180
+KEY=B7CF2BABD58B5FDCE11CCB3DAA9E6C6CDB0038C14F5855E7
+CT=FB8CE2E1D332FE4557B6C5CF1676F2FB
+PT=A2631F612698318AD454E9DB10319DA6
+
+I=181
+KEY=FD99B4137CAFC47F437FD45C8C065DE60F54D11A5F69C841
+CT=A2631F612698318AD454E9DB10319DA6
+PT=FCA42B332B5974EE6DFA54B54EC89AC7
+
+I=182
+KEY=271CEEF189AD367DBFDBFF6FA75F290862AE85AF11A15286
+CT=FCA42B332B5974EE6DFA54B54EC89AC7
+PT=A70DBBDFCE54B8648C3FC4A8A58CCDF8
+
+I=183
+KEY=7B78F7ECC9B28EC718D644B0690B916CEE914107B42D9F7E
+CT=A70DBBDFCE54B8648C3FC4A8A58CCDF8
+PT=C90CE914F9310F9C3EE065DD95281A51
+
+I=184
+KEY=762F521ADF6C5F24D1DAADA4903A9EF0D07124DA2105852F
+CT=C90CE914F9310F9C3EE065DD95281A51
+PT=63E8430CE22F531E4A4D4583533F6FC4
+
+I=185
+KEY=A88A493EB3C28C49B232EEA87215CDEE9A3C6159723AEAEB
+CT=63E8430CE22F531E4A4D4583533F6FC4
+PT=E7562DC647910A052F4AFBF165A68A3A
+
+I=186
+KEY=1C97343A60EE05035564C36E3584C7EBB5769AA8179C60D1
+CT=E7562DC647910A052F4AFBF165A68A3A
+PT=3E070B3F65FD01B49849513B556DB199
+
+I=187
+KEY=C5110692100A332E6B63C8515079C65F2D3FCB9342F1D148
+CT=3E070B3F65FD01B49849513B556DB199
+PT=3DE5A45B2CAA4FAFAC3032F89F15195D
+
+I=188
+KEY=D94D8CAA9EBD67F056866C0A7CD389F0810FF96BDDE4C815
+CT=3DE5A45B2CAA4FAFAC3032F89F15195D
+PT=A36A163E8806B1E053EBE439B0D1302F
+
+I=189
+KEY=1C1D7A3E9358048CF5EC7A34F4D53810D2E41D526D35F83A
+CT=A36A163E8806B1E053EBE439B0D1302F
+PT=67CA4B988CCABA4E4DBEE6C387562762
+
+I=190
+KEY=9182E40D14973087922631AC781F825E9F5AFB91EA63DF58
+CT=67CA4B988CCABA4E4DBEE6C387562762
+PT=9F404F0E1A9FE5A988CE6E4A54FE9E23
+
+I=191
+KEY=7D89ECFC0DCFFE0A0D667EA2628067F7179495DBBE9D417B
+CT=9F404F0E1A9FE5A988CE6E4A54FE9E23
+PT=D71EFD794457C71614E4266C77193444
+
+I=192
+KEY=AC7A11D29CDA0FB6DA7883DB26D7A0E10370B3B7C984753F
+CT=D71EFD794457C71614E4266C77193444
+PT=185DBF418A6834CD118B16EAF381F3CB
+
+I=193
+KEY=1029D5FA3D38927EC2253C9AACBF942C12FBA55D3A0586F4
+CT=185DBF418A6834CD118B16EAF381F3CB
+PT=737A502DEE68DDFA3FEECD42ACE124EA
+
+I=194
+KEY=F261B484C642750CB15F6CB742D749D62D15681F96E4A21E
+CT=737A502DEE68DDFA3FEECD42ACE124EA
+PT=FD11B0F356455913E892928B5B16946B
+
+I=195
+KEY=BCCFAF05FF47A5EC4C4EDC44149210C5C587FA94CDF23675
+CT=FD11B0F356455913E892928B5B16946B
+PT=4B06F6D6D149BAF25D4C76E46EFF8571
+
+I=196
+KEY=1000A15983B73D6807482A92C5DBAA3798CB8C70A30DB304
+CT=4B06F6D6D149BAF25D4C76E46EFF8571
+PT=450713DA24492403C48CB16D2F39744E
+
+I=197
+KEY=306F097E64B634AC424F3948E1928E345C473D1D8C34C74A
+CT=450713DA24492403C48CB16D2F39744E
+PT=998CA5E3C80B66EB11EAD376FA358A92
+
+I=198
+KEY=13965208C3EF77E1DBC39CAB2999E8DF4DADEE6B76014DD8
+CT=998CA5E3C80B66EB11EAD376FA358A92
+PT=F54A34F6F0833CA808D60A8F75BB0585
+
+I=199
+KEY=1A6DC3FDD0D1F97C2E89A85DD91AD477457BE4E403BA485D
+CT=F54A34F6F0833CA808D60A8F75BB0585
+PT=8760D5CBD1DA48807BAEAF7F781680F2
+
+I=200
+KEY=228897B4E2F16967A9E97D9608C09CF73ED54B9B7BACC8AF
+CT=8760D5CBD1DA48807BAEAF7F781680F2
+PT=EF57DF7161E1BC0F7B466A50C576691A
+
+I=201
+KEY=D0E8190E72A305C946BEA2E7692120F8459321CBBEDAA1B5
+CT=EF57DF7161E1BC0F7B466A50C576691A
+PT=E01ECA338A93EA38E43B2F364314C121
+
+I=202
+KEY=087F0486B80659F0A6A068D4E3B2CAC0A1A80EFDFDCE6094
+CT=E01ECA338A93EA38E43B2F364314C121
+PT=A7683273638D02272FF6A311BB94256F
+
+I=203
+KEY=1D807E4730DDA3EB01C85AA7803FC8E78E5EADEC465A45FB
+CT=A7683273638D02272FF6A311BB94256F
+PT=1BCC3DF6B07BD2615C13E381F5F877C3
+
+I=204
+KEY=D4D4F2780D52D7521A04675130441A86D24D4E6DB3A23238
+CT=1BCC3DF6B07BD2615C13E381F5F877C3
+PT=D1B3B793D1377E82A2DE5D46E53791FB
+
+I=205
+KEY=86D08D85652DB662CBB7D0C2E17364047093132B5695A3C3
+CT=D1B3B793D1377E82A2DE5D46E53791FB
+PT=9AC7AF9B82621E18E4FF613EAA609F46
+
+I=206
+KEY=C03996907AC99A7A51707F5963117A1C946C7215FCF53C85
+CT=9AC7AF9B82621E18E4FF613EAA609F46
+PT=57F3FA35A42C29F33DEC4671140264A4
+
+I=207
+KEY=F8CA52D95C587EF80683856CC73D53EFA9803464E8F75821
+CT=57F3FA35A42C29F33DEC4671140264A4
+PT=A887ED8BF6C19F5012F317A4FCF3D7BF
+
+I=208
+KEY=DE99CC8F9756C1DCAE0468E731FCCCBFBB7323C014048F9E
+CT=A887ED8BF6C19F5012F317A4FCF3D7BF
+PT=A29C8D764BCF211C789158A9B8EB330C
+
+I=209
+KEY=9228DB1B61E0D8670C98E5917A33EDA3C3E27B69ACEFBC92
+CT=A29C8D764BCF211C789158A9B8EB330C
+PT=EB6AFD9B36315DB322EC8C4243043F50
+
+I=210
+KEY=24AFE14097C2A217E7F2180A4C02B010E10EF72BEFEB83C2
+CT=EB6AFD9B36315DB322EC8C4243043F50
+PT=05C8AC90CCD00E2A3809C68C11D6D65A
+
+I=211
+KEY=32810943F9313BD0E23AB49A80D2BE3AD90731A7FE3D5598
+CT=05C8AC90CCD00E2A3809C68C11D6D65A
+PT=E39991B58C52154166AD09367B04C67A
+
+I=212
+KEY=FBEC72A177254EA501A3252F0C80AB7BBFAA3891853993E2
+CT=E39991B58C52154166AD09367B04C67A
+PT=CBC8974F72F77A1821FC69B29FE2DB60
+
+I=213
+KEY=C706D206DE538439CA6BB2607E77D1639E5651231ADB4882
+CT=CBC8974F72F77A1821FC69B29FE2DB60
+PT=1D08F4E2B8DFED1032B6CA5211B3E34C
+
+I=214
+KEY=9A7EB0A4F8E67F87D7634682C6A83C73ACE09B710B68ABCE
+CT=1D08F4E2B8DFED1032B6CA5211B3E34C
+PT=1888CEC22449EFF96BDC2C7A242BBBDC
+
+I=215
+KEY=70CA2CAD6A50D22BCFEB8840E2E1D38AC73CB70B2F431012
+CT=1888CEC22449EFF96BDC2C7A242BBBDC
+PT=032E6155677B6A72D7F94C7A9A9AA53F
+
+I=216
+KEY=B16697FEA247CDB9CCC5E915859AB9F810C5FB71B5D9B52D
+CT=032E6155677B6A72D7F94C7A9A9AA53F
+PT=9B43BBD1C0CEBF7593E9BC0ABB626E96
+
+I=217
+KEY=7A3E844BEB897A63578652C44554068D832C477B0EBBDBBB
+CT=9B43BBD1C0CEBF7593E9BC0ABB626E96
+PT=8D661E03C61C28D5786EBCEBE0D5B63D
+
+I=218
+KEY=E7A1B96EFC4D5FB5DAE04CC783482E58FB42FB90EE6E6D86
+CT=8D661E03C61C28D5786EBCEBE0D5B63D
+PT=F61D5DCBF8F2F3F0EAB387149790E079
+
+I=219
+KEY=0EDA761C06FBA0A02CFD110C7BBADDA811F17C8479FE8DFF
+CT=F61D5DCBF8F2F3F0EAB387149790E079
+PT=1F03E0957B6892533BBEAB06EB35AD4F
+
+I=220
+KEY=E242AD5B7141916133FEF19900D24FFB2A4FD78292CB20B0
+CT=1F03E0957B6892533BBEAB06EB35AD4F
+PT=BB9E7343035F88764B229D506E7ADC7B
+
+I=221
+KEY=D901A6CF874A6A77886082DA038DC78D616D4AD2FCB1FCCB
+CT=BB9E7343035F88764B229D506E7ADC7B
+PT=3934EBF7AD2243C0D09734E30B41C0E4
+
+I=222
+KEY=0F488E86E7D92F29B154692DAEAF844DB1FA7E31F7F03C2F
+CT=3934EBF7AD2243C0D09734E30B41C0E4
+PT=B9CE1A1A9595E7235F5B10FBA29ACCD2
+
+I=223
+KEY=A7E2CF991692247A089A73373B3A636EEEA16ECA556AF0FD
+CT=B9CE1A1A9595E7235F5B10FBA29ACCD2
+PT=624EBA65EE9E3E1BDF8C5AA7E1283A65
+
+I=224
+KEY=1DE03E09395E56CE6AD4C952D5A45D75312D346DB442CA98
+CT=624EBA65EE9E3E1BDF8C5AA7E1283A65
+PT=375132E5F47DA19E80CC8652BE5A3692
+
+I=225
+KEY=51B6813629EFE53C5D85FBB721D9FCEBB1E1B23F0A18FC0A
+CT=375132E5F47DA19E80CC8652BE5A3692
+PT=8165A4126FE75EFC6AFF7BFD732F94A6
+
+I=226
+KEY=8DD50DFF93624339DCE05FA54E3EA217DB1EC9C2793768AC
+CT=8165A4126FE75EFC6AFF7BFD732F94A6
+PT=35012FABD289E6B7FB07946591D18F0D
+
+I=227
+KEY=C7A4F75CB74C7F3DE9E1700E9CB744A020195DA7E8E6E7A1
+CT=35012FABD289E6B7FB07946591D18F0D
+PT=C26F37D700677ED72F4FC2C8F6AEADE2
+
+I=228
+KEY=198B572CD0E711352B8E47D99CD03A770F569F6F1E484A43
+CT=C26F37D700677ED72F4FC2C8F6AEADE2
+PT=CB29ECE41596736B72AED2460AEEFBA2
+
+I=229
+KEY=0A1FB41CA720E357E0A7AB3D8946491C7DF84D2914A6B1E1
+CT=CB29ECE41596736B72AED2460AEEFBA2
+PT=7F7BD6FAF9C37D5522A3BF480CCEBF20
+
+I=230
+KEY=7E383601899DEA729FDC7DC7708534495F5BF26118680EC1
+CT=7F7BD6FAF9C37D5522A3BF480CCEBF20
+PT=C501E371005DF57E0037F41A744D026F
+
+I=231
+KEY=13ACF410865B41E15ADD9EB670D8C1375F6C067B6C250CAE
+CT=C501E371005DF57E0037F41A744D026F
+PT=624EF8749580108CDC7A020179F81D0F
+
+I=232
+KEY=75F025072AA2406F389366C2E558D1BB8316047A15DD11A1
+CT=624EF8749580108CDC7A020179F81D0F
+PT=40D72550603522C67180DE6EC3D30139
+
+I=233
+KEY=C5ED76F88EA65C3D78444392856DF37DF296DA14D60E1098
+CT=40D72550603522C67180DE6EC3D30139
+PT=96C6F647AFB90F804431F9E2F1780F29
+
+I=234
+KEY=E827DFF88D0B1A43EE82B5D52AD4FCFDB6A723F627761FB1
+CT=96C6F647AFB90F804431F9E2F1780F29
+PT=CCB934A501DDAD11E994938A214EB189
+
+I=235
+KEY=F0777D1BFF12EE42223B81702B0951EC5F33B07C0638AE38
+CT=CCB934A501DDAD11E994938A214EB189
+PT=07825F2D35E761C76893B697E30E4D08
+
+I=236
+KEY=6912B59C06C90D3725B9DE5D1EEE302B37A006EBE536E330
+CT=07825F2D35E761C76893B697E30E4D08
+PT=1F674E97F88EB1DA1DD24C0AB4321258
+
+I=237
+KEY=AE24933526FAE5F83ADE90CAE66081F12A724AE15104F168
+CT=1F674E97F88EB1DA1DD24C0AB4321258
+PT=B6DE499EBE0B3C30F1DAC8E40FE9F10C
+
+I=238
+KEY=F348F88852CF356C8C00D954586BBDC1DBA882055EED0064
+CT=B6DE499EBE0B3C30F1DAC8E40FE9F10C
+PT=105E31DBDE33764B098862AF6D0B6CD2
+
+I=239
+KEY=83B06CC00A17D3149C5EE88F8658CB8AD220E0AA33E66CB6
+CT=105E31DBDE33764B098862AF6D0B6CD2
+PT=697D6537677B20C188246FBF4997C7CB
+
+I=240
+KEY=A5381A9C91D61A01F5238DB8E123EB4B5A048F157A71AB7D
+CT=697D6537677B20C188246FBF4997C7CB
+PT=4FBFB0EFBA92C1E0189E2C3097AA35BA
+
+I=241
+KEY=FDF831A7D1345AFEBA9C3D575BB12AAB429AA325EDDB9EC7
+CT=4FBFB0EFBA92C1E0189E2C3097AA35BA
+PT=600288531DCEB99B69A7890CE804FA9F
+
+I=242
+KEY=A10ED54E7B2B2B2BDA9EB504467F93302B3D2A2905DF6458
+CT=600288531DCEB99B69A7890CE804FA9F
+PT=EE94D4376D9332C8DCD05C695EDB124F
+
+I=243
+KEY=2F69F01250D7745F340A61332BECA1F8F7ED76405B047617
+CT=EE94D4376D9332C8DCD05C695EDB124F
+PT=7EDC3182C36DC5A172B170A919524888
+
+I=244
+KEY=FCD5F8FAB347624E4AD650B1E8816459855C06E942563E9F
+CT=7EDC3182C36DC5A172B170A919524888
+PT=95FA03C96DFCB9ABCFF23B5ABFBABCDE
+
+I=245
+KEY=A9307E62197A747EDF2C5378857DDDF24AAE3DB3FDEC8241
+CT=95FA03C96DFCB9ABCFF23B5ABFBABCDE
+PT=6CE2C6CFC61667965C20B0BE11B55DDE
+
+I=246
+KEY=DA3B03896DDFDE08B3CE95B7436BBA64168E8D0DEC59DF9F
+CT=6CE2C6CFC61667965C20B0BE11B55DDE
+PT=3DBDFBE63A6FAE7572C778108A62A27C
+
+I=247
+KEY=7D766BAD6E536CE38E736E51790414116449F51D663B7DE3
+CT=3DBDFBE63A6FAE7572C778108A62A27C
+PT=1C197D3449FED6ED6924E14B43A17BF0
+
+I=248
+KEY=36F69C30B0272CAB926A136530FAC2FC0D6D1456259A0613
+CT=1C197D3449FED6ED6924E14B43A17BF0
+PT=0B0CCC6F508C18168284F7976AD81BEE
+
+I=249
+KEY=632661C312B2EB5D9966DF0A6076DAEA8FE9E3C14F421DFD
+CT=0B0CCC6F508C18168284F7976AD81BEE
+PT=F437B8FD92CE37D8D74550C5BE29BF99
+
+I=250
+KEY=5FB1BDFC29EFE2DA6D5167F7F2B8ED3258ACB304F16BA264
+CT=F437B8FD92CE37D8D74550C5BE29BF99
+PT=78F6E6F6480A04F5632EA112170F928C
+
+I=251
+KEY=2B24C5188F4A2E7B15A78101BAB2E9C73B821216E66430E8
+CT=78F6E6F6480A04F5632EA112170F928C
+PT=2FD38831EE4D09DD8DB9A84B5825B528
+
+I=252
+KEY=F816FB720A08828C3A74093054FFE01AB63BBA5DBE4185C0
+CT=2FD38831EE4D09DD8DB9A84B5825B528
+PT=ED307697B51CFAD7052A3A7B3A564990
+
+I=253
+KEY=776B08F4778FAB96D7447FA7E1E31ACDB31180268417CC50
+CT=ED307697B51CFAD7052A3A7B3A564990
+PT=DB9952A98F0D4B045C624EFA5619CAF9
+
+I=254
+KEY=C7A944C9BA2D5F740CDD2D0E6EEE51C9EF73CEDCD20E06A9
+CT=DB9952A98F0D4B045C624EFA5619CAF9
+PT=DADA40BF0E367AF50874BB2628251AA3
+
+I=255
+KEY=69B8688D9C1ECD95D6076DB160D82B3CE70775FAFA2B1C0A
+CT=DADA40BF0E367AF50874BB2628251AA3
+PT=35DFA85D3F2D7F47DD7865EA0BC73A5C
+
+I=256
+KEY=7E6C7E90EDE36F44E3D8C5EC5FF5547B3A7F1010F1EC2656
+CT=35DFA85D3F2D7F47DD7865EA0BC73A5C
+PT=EE0231F994C2DB6C7C04746170F03E54
+
+I=257
+KEY=0E56C8FD184AB5D40DDAF415CB378F17467B6471811C1802
+CT=EE0231F994C2DB6C7C04746170F03E54
+PT=D9F314FEAD11122CE8F532ED0C0B129C
+
+I=258
+KEY=267BC5325796002BD429E0EB66269D3BAE8E569C8D170A9E
+CT=D9F314FEAD11122CE8F532ED0C0B129C
+PT=74A32BDFF53A59F09AAFB328977E05B1
+
+I=259
+KEY=889B6087CAAD1B43A08ACB34931CC4CB3421E5B41A690F2F
+CT=74A32BDFF53A59F09AAFB328977E05B1
+PT=D4CCC3077C15EE470D5EFCF815A48410
+
+I=260
+KEY=F9AE78D077E3F98574460833EF092A8C397F194C0FCD8B3F
+CT=D4CCC3077C15EE470D5EFCF815A48410
+PT=29284B0E7776DFB8BB536B3C16399D62
+
+I=261
+KEY=71BBCD4B1F4B04265D6E433D987FF534822C727019F4165D
+CT=29284B0E7776DFB8BB536B3C16399D62
+PT=202326CEAD57A5C13592FFBFFD5BF508
+
+I=262
+KEY=F6F461C7931CF0317D4D65F3352850F5B7BE8DCFE4AFE355
+CT=202326CEAD57A5C13592FFBFFD5BF508
+PT=B9AFAD0658E1A4A1EECAA25B2863AD53
+
+I=263
+KEY=BC0D82D3B7909D54C4E2C8F56DC9F45459742F94CCCC4E06
+CT=B9AFAD0658E1A4A1EECAA25B2863AD53
+PT=DE7AC7F7381DD34F3148911F306F4161
+
+I=264
+KEY=339FFE2E01AB1D621A980F0255D4271B683CBE8BFCA30F67
+CT=DE7AC7F7381DD34F3148911F306F4161
+PT=F197DE9FED1EA08F6C17E631BF5449FE
+
+I=265
+KEY=EC908F9A4F266644EB0FD19DB8CA8794042B58BA43F74699
+CT=F197DE9FED1EA08F6C17E631BF5449FE
+PT=7E1416C06ED3F56782DB5CB536B9B56E
+
+I=266
+KEY=CFE36CCCC94F8A5B951BC75DD61972F386F0040F754EF3F7
+CT=7E1416C06ED3F56782DB5CB536B9B56E
+PT=BE1FE1F7B4CFF55D15BBCB6D9313729D
+
+I=267
+KEY=90690906407FB8AC2B0426AA62D687AE934BCF62E65D816A
+CT=BE1FE1F7B4CFF55D15BBCB6D9313729D
+PT=50E6818C06583D3D1C99C4A127D118CF
+
+I=268
+KEY=5D2A712578EC47217BE2A726648EBA938FD20BC3C18C99A5
+CT=50E6818C06583D3D1C99C4A127D118CF
+PT=E1BFD3ED18E9A6D7BF383D590DA23B59
+
+I=269
+KEY=3CA141EE57D7E0FC9A5D74CB7C671C4430EA369ACC2EA2FC
+CT=E1BFD3ED18E9A6D7BF383D590DA23B59
+PT=03961127347C141C01F5276CB9BB31F7
+
+I=270
+KEY=65E9B8AE22DC52A599CB65EC481B0858311F11F67595930B
+CT=03961127347C141C01F5276CB9BB31F7
+PT=E9A8336DC0B530A86988B2DE74EDFFA1
+
+I=271
+KEY=870A30E0F3B836FA7063568188AE38F05897A32801786CAA
+CT=E9A8336DC0B530A86988B2DE74EDFFA1
+PT=B5FA5E388CFFFE2BA33436CC39A73972
+
+I=272
+KEY=4B81E55C765F570CC59908B90451C6DBFBA395E438DF55D8
+CT=B5FA5E388CFFFE2BA33436CC39A73972
+PT=CEF4896BBC86F1E02312479C40D96DAE
+
+I=273
+KEY=0FAB0DCFB6E3E7940B6D81D2B8D7373BD8B1D27878063876
+CT=CEF4896BBC86F1E02312479C40D96DAE
+PT=F195F5321FCAA68B0B0CBA83978A8084
+
+I=274
+KEY=F860076D3847A80BFAF874E0A71D91B0D3BD68FBEF8CB8F2
+CT=F195F5321FCAA68B0B0CBA83978A8084
+PT=861575205386223EBC6B48B22C35A2A6
+
+I=275
+KEY=B2DB77DC3E18C3A77CED01C0F49BB38E6FD62049C3B91A54
+CT=861575205386223EBC6B48B22C35A2A6
+PT=DC074F3D41C62DA9D609A982DEB9E074
+
+I=276
+KEY=E632B0C6EE68910EA0EA4EFDB55D9E27B9DF89CB1D00FA20
+CT=DC074F3D41C62DA9D609A982DEB9E074
+PT=6933F4F193B028A22B913453B0B4C9A2
+
+I=277
+KEY=88AA3FEE5FDFA336C9D9BA0C26EDB685924EBD98ADB43382
+CT=6933F4F193B028A22B913453B0B4C9A2
+PT=56811E665DDFBEA07A7C2C762F0D5C73
+
+I=278
+KEY=2A0A1FE31ADFC64F9F58A46A7B320825E83291EE82B96FF1
+CT=56811E665DDFBEA07A7C2C762F0D5C73
+PT=CFF92E47C8C973ADA7B57D9FE320B356
+
+I=279
+KEY=7958F9D10B6DC91050A18A2DB3FB7B884F87EC716199DCA7
+CT=CFF92E47C8C973ADA7B57D9FE320B356
+PT=A55A4F827552761580DC27E0712051B1
+
+I=280
+KEY=ADDB73FE13D439CAF5FBC5AFC6A90D9DCF5BCB9110B98D16
+CT=A55A4F827552761580DC27E0712051B1
+PT=734B095C3C54FCDE26C33659C82CACCB
+
+I=281
+KEY=E979AF9C739F60AE86B0CCF3FAFDF143E998FDC8D89521DD
+CT=734B095C3C54FCDE26C33659C82CACCB
+PT=122A4F2ADE6C69364943658517A56587
+
+I=282
+KEY=E05BDC75E94EB2A8949A83D924919875A0DB984DCF30445A
+CT=122A4F2ADE6C69364943658517A56587
+PT=C6EF3170C5EF69B479AC6653E8B7E979
+
+I=283
+KEY=67AF0BE0DE572F595275B2A9E17EF1C1D977FE1E2787AD23
+CT=C6EF3170C5EF69B479AC6653E8B7E979
+PT=51113FF8A1000A5449F24E8E5363FB72
+
+I=284
+KEY=7C8DCBB512AE775603648D51407EFB959085B09074E45651
+CT=51113FF8A1000A5449F24E8E5363FB72
+PT=B9341E24A41C9D9CE56D6E4F17A7A311
+
+I=285
+KEY=EEBE49DAF88030F5BA509375E462660975E8DEDF6343F540
+CT=B9341E24A41C9D9CE56D6E4F17A7A311
+PT=26A135C466B061791DE40A40E9366FC6
+
+I=286
+KEY=A06A0B9127769EF79CF1A6B182D20770680CD49F8A759A86
+CT=26A135C466B061791DE40A40E9366FC6
+PT=AE832B68C147CF8A70A8E5CCC3FF05F2
+
+I=287
+KEY=CD394B7808099B2832728DD94395C8FA18A43153498A9F74
+CT=AE832B68C147CF8A70A8E5CCC3FF05F2
+PT=72747F478E3AE57C6C7D6D4E5C4FCE71
+
+I=288
+KEY=80D4A1BD538D11434006F29ECDAF2D8674D95C1D15C55105
+CT=72747F478E3AE57C6C7D6D4E5C4FCE71
+PT=21539022400BEE401E8FE7E9F0F7AAC3
+
+I=289
+KEY=C8BCB868E11B46E3615562BC8DA4C3C66A56BBF4E532FBC6
+CT=21539022400BEE401E8FE7E9F0F7AAC3
+PT=44149C7C375F07B7169C8A9A14133C8C
+
+I=290
+KEY=DFC35DD4FAD95C2A2541FEC0BAFBC4717CCA316EF121C74A
+CT=44149C7C375F07B7169C8A9A14133C8C
+PT=2A7FA9D2EACC0C5444510E7D69EB3FD6
+
+I=291
+KEY=73B0B53EE6D591140F3E57125037C825389B3F1398CAF89C
+CT=2A7FA9D2EACC0C5444510E7D69EB3FD6
+PT=9949145B8C88D03BBA46FEBE9856B732
+
+I=292
+KEY=7BFBD6A0A317DEE996774349DCBF181E82DDC1AD009C4FAE
+CT=9949145B8C88D03BBA46FEBE9856B732
+PT=714E072347ECDEA4F8EB2B02746FBC66
+
+I=293
+KEY=CA326A1D191B2BC6E739446A9B53C6BA7A36EAAF74F3F3C8
+CT=714E072347ECDEA4F8EB2B02746FBC66
+PT=CCF2295814759A5004E8C3E2B97C4958
+
+I=294
+KEY=428400F7196D32C62BCB6D328F265CEA7EDE294DCD8FBA90
+CT=CCF2295814759A5004E8C3E2B97C4958
+PT=12108AB0753EAAE007DEFF2EBA8A3EF0
+
+I=295
+KEY=3E38F6FA3F49742339DBE782FA18F60A7900D66377058460
+CT=12108AB0753EAAE007DEFF2EBA8A3EF0
+PT=0109AC127FB55B91BC922EDFF3C43819
+
+I=296
+KEY=07C585ABD1C227D638D24B9085ADAD9BC592F8BC84C1BC79
+CT=0109AC127FB55B91BC922EDFF3C43819
+PT=33FF03F6966E81EE28889CFA0B9BA8B9
+
+I=297
+KEY=FB823872148252C20B2D486613C32C75ED1A64468F5A14C0
+CT=33FF03F6966E81EE28889CFA0B9BA8B9
+PT=D8468C180BAC0F6D703611DDAD951014
+
+I=298
+KEY=F81900EAD21ECE3BD36BC47E186F23189D2C759B22CF04D4
+CT=D8468C180BAC0F6D703611DDAD951014
+PT=07994906A8377D64F2D32DB4BB170EF1
+
+I=299
+KEY=2ADC8C0244307531D4F28D78B0585E7C6FFF582F99D80A25
+CT=07994906A8377D64F2D32DB4BB170EF1
+PT=48382015F82AA7EC8944C40275595CEF
+
+I=300
+KEY=2E917F5C5BAB80939CCAAD6D4872F990E6BB9C2DEC8156CA
+CT=48382015F82AA7EC8944C40275595CEF
+PT=D4EEE0A1A56118EB8F6AE16FE16F70ED
+
+I=301
+KEY=126D396B29E0252248244DCCED13E17B69D17D420DEE2627
+CT=D4EEE0A1A56118EB8F6AE16FE16F70ED
+PT=358E5FAE4A4ED6B1058E32942AE030DB
+
+I=302
+KEY=D390A60684F5C9147DAA1262A75D37CA6C5F4FD6270E16FC
+CT=358E5FAE4A4ED6B1058E32942AE030DB
+PT=B9730D311EA8312DAC34F444A4560DDC
+
+I=303
+KEY=0B2A03E62FCD9B06C4D91F53B9F506E7C06BBB9283581B20
+CT=B9730D311EA8312DAC34F444A4560DDC
+PT=D64F286B32B4058A51B73844BCA93DDA
+
+I=304
+KEY=5858183C5713BBD6129637388B41036D91DC83D63FF126FA
+CT=D64F286B32B4058A51B73844BCA93DDA
+PT=78425B7FE64D972C642ED17369ED8844
+
+I=305
+KEY=C555D9DC23D3A1846AD46C476D0C9441F5F252A5561CAEBE
+CT=78425B7FE64D972C642ED17369ED8844
+PT=2DE9202F4CD7F67C7B7F94CF7F3B9B5A
+
+I=306
+KEY=7BA871DA6E336CFA473D4C6821DB623D8E8DC66A292735E4
+CT=2DE9202F4CD7F67C7B7F94CF7F3B9B5A
+PT=A30322EC9A51266B50153995BCEBC846
+
+I=307
+KEY=55BF35687EBA169AE43E6E84BB8A4456DE98FFFF95CCFDA2
+CT=A30322EC9A51266B50153995BCEBC846
+PT=14754B0469683F36E4791FD9B8B1C585
+
+I=308
+KEY=0404CAE90360F118F04B2580D2E27B603AE1E0262D7D3827
+CT=14754B0469683F36E4791FD9B8B1C585
+PT=E8592DC147A1DC4F48D43E365B9D63FF
+
+I=309
+KEY=109E16AA717A4EF4181208419543A72F7235DE1076E05BD8
+CT=E8592DC147A1DC4F48D43E365B9D63FF
+PT=47A3BF0743562C7D412563C94C2CD717
+
+I=310
+KEY=0A8DC7647F8C06D15FB1B746D6158B523310BDD93ACC8CCF
+CT=47A3BF0743562C7D412563C94C2CD717
+PT=63F8C6A062937471364050815D856793
+
+I=311
+KEY=CC9B8854C13F73623C4971E6B486FF230550ED586749EB5C
+CT=63F8C6A062937471364050815D856793
+PT=E70443AF44BF549607251A86CD83A4D3
+
+I=312
+KEY=2D067D896DF1E749DB4D3249F039ABB50275F7DEAACA4F8F
+CT=E70443AF44BF549607251A86CD83A4D3
+PT=ACEF2AE95CA660AEE513BF48BCF7D125
+
+I=313
+KEY=DEC45DD3C0DAD30A77A218A0AC9FCB1BE7664896163D9EAA
+CT=ACEF2AE95CA660AEE513BF48BCF7D125
+PT=859E9E4001245A50ED76055539672F1A
+
+I=314
+KEY=6F208E93D9C89CE8F23C86E0ADBB914B0A104DC32F5AB1B0
+CT=859E9E4001245A50ED76055539672F1A
+PT=42B059061FE4C86C7AC2B7C8B62820C2
+
+I=315
+KEY=86EC7CE558994E8EB08CDFE6B25F592770D2FA0B99729172
+CT=42B059061FE4C86C7AC2B7C8B62820C2
+PT=01C6296F1532450F182D6A3FC8249DD7
+
+I=316
+KEY=C74B31CEC9B31130B14AF689A76D1C2868FF903451560CA5
+CT=01C6296F1532450F182D6A3FC8249DD7
+PT=14334054946821E3FE8D72D1EF402EE1
+
+I=317
+KEY=AC636B2AD3699560A579B6DD33053DCB9672E2E5BE162244
+CT=14334054946821E3FE8D72D1EF402EE1
+PT=F09B2FE9A8F17CD847532D4979D2A8C4
+
+I=318
+KEY=6F956E3680FC783155E299349BF44113D121CFACC7C48A80
+CT=F09B2FE9A8F17CD847532D4979D2A8C4
+PT=4C97BD8822E63C7A2EE0E444563AF1C8
+
+I=319
+KEY=C69B2FB718C41B1A197524BCB9127D69FFC12BE891FE7B48
+CT=4C97BD8822E63C7A2EE0E444563AF1C8
+PT=344E85BE2C8B36430C8058B310062171
+
+I=320
+KEY=BFFA143B8A18CACF2D3BA10295994B2AF341735B81F85A39
+CT=344E85BE2C8B36430C8058B310062171
+PT=FF3F882CB22D13A8631DCA6DD702D0E0
+
+I=321
+KEY=22F58A0FC077AB5FD204292E27B45882905CB93656FA8AD9
+CT=FF3F882CB22D13A8631DCA6DD702D0E0
+PT=866B2E52CF71505973D9D6642C8178BB
+
+I=322
+KEY=DC8CE7A9130F3662546F077CE8C508DBE3856F527A7BF262
+CT=866B2E52CF71505973D9D6642C8178BB
+PT=4802741ADF67A3811A8AEC7008D8827E
+
+I=323
+KEY=743B09AA8FD3C6A01C6D736637A2AB5AF90F832272A3701C
+CT=4802741ADF67A3811A8AEC7008D8827E
+PT=FD3701579815D02BE878C74ABB98C59B
+
+I=324
+KEY=865B3EC9EFBE27D0E15A7231AFB77B7111774468C93BB587
+CT=FD3701579815D02BE878C74ABB98C59B
+PT=99BCA8250D54F3A9A72054AF5578F842
+
+I=325
+KEY=041C037E08923FFF78E6DA14A2E388D8B65710C79C434DC5
+CT=99BCA8250D54F3A9A72054AF5578F842
+PT=F0DA5C0E446547356D5027BA346A831C
+
+I=326
+KEY=FBABCE025CF5FF3D883C861AE686CFEDDB07377DA829CED9
+CT=F0DA5C0E446547356D5027BA346A831C
+PT=EED0140AF408652DD879E3289536C389
+
+I=327
+KEY=3F12399A3E5C0F9566EC9210128EAAC0037ED4553D1F0D50
+CT=EED0140AF408652DD879E3289536C389
+PT=FDC7299A95BDB941A299478B7B409EF8
+
+I=328
+KEY=D541517B701036E39B2BBB8A87331381A1E793DE465F93A8
+CT=FDC7299A95BDB941A299478B7B409EF8
+PT=5BE5AEC30578CD03BA7B17E8B16AAFBF
+
+I=329
+KEY=6657840FF425DD8AC0CE1549824BDE821B9C8436F7353C17
+CT=5BE5AEC30578CD03BA7B17E8B16AAFBF
+PT=3C7A9745F48DA61CF7875A449E24C735
+
+I=330
+KEY=52D29BBD64550DFBFCB4820C76C6789EEC1BDE726911FB22
+CT=3C7A9745F48DA61CF7875A449E24C735
+PT=69516DE0343F3552830D28CE8B9A282C
+
+I=331
+KEY=3699B16BB0349B9195E5EFEC42F94DCC6F16F6BCE28BD30E
+CT=69516DE0343F3552830D28CE8B9A282C
+PT=EB09EE300286690EA65A30526A43B86B
+
+I=332
+KEY=60E79B9E7C41814E7EEC01DC407F24C2C94CC6EE88C86B65
+CT=EB09EE300286690EA65A30526A43B86B
+PT=A235384FE517A5F455BBE6B850C05E33
+
+I=333
+KEY=11F650282BBCB584DCD93993A56881369CF72056D8083556
+CT=A235384FE517A5F455BBE6B850C05E33
+PT=41E297350390E91EC00FF875B3CA60BA
+
+I=334
+KEY=11B449F7EE983AB89D3BAEA6A6F868285CF8D8236BC255EC
+CT=41E297350390E91EC00FF875B3CA60BA
+PT=5FB9F6408D54401A9A76288AE3A04944
+
+I=335
+KEY=54CBA9A5782ED91FC28258E62BAC2832C68EF0A988621CA8
+CT=5FB9F6408D54401A9A76288AE3A04944
+PT=7C9CD2510E96FF37BF75E57E84098535
+
+I=336
+KEY=871169F28E704C95BE1E8AB7253AD70579FB15D70C6B999D
+CT=7C9CD2510E96FF37BF75E57E84098535
+PT=8E041B8C74A84D747B02714452B34F11
+
+I=337
+KEY=7F44ED6AA755957A301A913B51929A7102F964935ED8D68C
+CT=8E041B8C74A84D747B02714452B34F11
+PT=3698639F56657A40D52B9B8015448C2A
+
+I=338
+KEY=EEAF09001996BA6E0682F2A407F7E031D7D2FF134B9C5AA6
+CT=3698639F56657A40D52B9B8015448C2A
+PT=79FB5E4A065D29E1CA3E15897B60032F
+
+I=339
+KEY=D21CCA06254A64C97F79ACEE01AAC9D01DECEA9A30FC5989
+CT=79FB5E4A065D29E1CA3E15897B60032F
+PT=C582F5F8D9D2E9323C769B2B1AE369BD
+
+I=340
+KEY=29D2F84E4568BA6FBAFB5916D87820E2219A71B12A1F3034
+CT=C582F5F8D9D2E9323C769B2B1AE369BD
+PT=916405DC8F2AD50548997D87BCCADBFB
+
+I=341
+KEY=43AC4D54A8A0222F2B9F5CCA5752F5E769030C3696D5EBCF
+CT=916405DC8F2AD50548997D87BCCADBFB
+PT=0E9FF0E147A47056EC6B09837C9E0E62
+
+I=342
+KEY=9AF110B8274794772500AC2B10F685B1856805B5EA4BE5AD
+CT=0E9FF0E147A47056EC6B09837C9E0E62
+PT=3B6E3CAAC358427980E66E3D30D39E4F
+
+I=343
+KEY=49F910E7957BC95C1E6E9081D3AEC7C8058E6B88DA987BE2
+CT=3B6E3CAAC358427980E66E3D30D39E4F
+PT=25CBE5AB4C6785C0F2847CF89F2635AB
+
+I=344
+KEY=64D90092DD97AC3C3BA5752A9FC94208F70A177045BE4E49
+CT=25CBE5AB4C6785C0F2847CF89F2635AB
+PT=3D9200D39461D8B2CE7874DA20BFD9DA
+
+I=345
+KEY=C7A8403AFB011673063775F90BA89ABA397263AA65019793
+CT=3D9200D39461D8B2CE7874DA20BFD9DA
+PT=E61E7E06A1E1F656AE8F8C29C96E5A16
+
+I=346
+KEY=071AF635AF7A9602E0290BFFAA496CEC97FDEF83AC6FCD85
+CT=E61E7E06A1E1F656AE8F8C29C96E5A16
+PT=7488BB35F06E94F31A744D1EA95E71D0
+
+I=347
+KEY=A4B5ECB7047E08D694A1B0CA5A27F81F8D89A29D0531BC55
+CT=7488BB35F06E94F31A744D1EA95E71D0
+PT=3912DC00C0AB79C473CA2CC8F69262F0
+
+I=348
+KEY=BD4478B38A0E9347ADB36CCA9A8C81DBFE438E55F3A3DEA5
+CT=3912DC00C0AB79C473CA2CC8F69262F0
+PT=C4B546F134A016DADA8E7C478B1E7D45
+
+I=349
+KEY=F7B6F476517483AD69062A3BAE2C970124CDF21278BDA3E0
+CT=C4B546F134A016DADA8E7C478B1E7D45
+PT=298524C5D468EBFA97DEFEC7B80EE752
+
+I=350
+KEY=8E0C5244F7417C2440830EFE7A447CFBB3130CD5C0B344B2
+CT=298524C5D468EBFA97DEFEC7B80EE752
+PT=B27EFB90BA3A27A1077C6742D5B68396
+
+I=351
+KEY=C6E8F264FA0C9A9AF2FDF56EC07E5B5AB46F6B971505C724
+CT=B27EFB90BA3A27A1077C6742D5B68396
+PT=D02C27A94DD3B772B338C7462379B009
+
+I=352
+KEY=AD694D243DCC6B7B22D1D2C78DADEC280757ACD1367C772D
+CT=D02C27A94DD3B772B338C7462379B009
+PT=1CED06084E67BA4BAD3C331F4074B9FF
+
+I=353
+KEY=68AEF48D86D395583E3CD4CFC3CA5663AA6B9FCE7608CED2
+CT=1CED06084E67BA4BAD3C331F4074B9FF
+PT=C0D7811FE8630B3E7C3A60DA9042A6B2
+
+I=354
+KEY=670A8D40573F598AFEEB55D02BA95D5DD651FF14E64A6860
+CT=C0D7811FE8630B3E7C3A60DA9042A6B2
+PT=45F92C84CE2AEC6E7953C8AAC5901D0F
+
+I=355
+KEY=D44FD97B0D59C923BB127954E583B133AF0237BE23DA756F
+CT=45F92C84CE2AEC6E7953C8AAC5901D0F
+PT=23A4863C994EFE93E7CE1C89FE14143D
+
+I=356
+KEY=4E08C6A539C74A6598B6FF687CCD4FA048CC2B37DDCE6152
+CT=23A4863C994EFE93E7CE1C89FE14143D
+PT=85EB5F46988211E3077FDBE38F1EBE6B
+
+I=357
+KEY=21B17D5E461224B31D5DA02EE44F5E434FB3F0D452D0DF39
+CT=85EB5F46988211E3077FDBE38F1EBE6B
+PT=59CF6CCC81A8BC17A52D7550B40C7514
+
+I=358
+KEY=6CC595309F161F3E4492CCE265E7E254EA9E8584E6DCAA2D
+CT=59CF6CCC81A8BC17A52D7550B40C7514
+PT=13DF4C2AA74A4B9123B3A57FE94F85BE
+
+I=359
+KEY=77B90151B41B1B7D574D80C8C2ADA9C5C92D20FB0F932F93
+CT=13DF4C2AA74A4B9123B3A57FE94F85BE
+PT=6DEDE53AD5DC2A87744DA0EA561977A3
+
+I=360
+KEY=8E1683C57C1817C23AA065F217718342BD608011598A5830
+CT=6DEDE53AD5DC2A87744DA0EA561977A3
+PT=F9D912AAB5ED1ACBD0475411DF98F49C
+
+I=361
+KEY=E9FDD94AE4B4FABAC3797758A29C99896D27D4008612ACAC
+CT=F9D912AAB5ED1ACBD0475411DF98F49C
+PT=853C907D9FD35B61D2ABBE5C1A89DB4B
+
+I=362
+KEY=BCC524DF4D452AE14645E7253D4FC2E8BF8C6A5C9C9B77E7
+CT=853C907D9FD35B61D2ABBE5C1A89DB4B
+PT=874C4BC1993FBA12136443B57F9523BE
+
+I=363
+KEY=9F5EFA7196589240C109ACE4A47078FAACE829E9E30E5459
+CT=874C4BC1993FBA12136443B57F9523BE
+PT=E6B6E9133DD0EC2844EF3CC0C2F9E4AC
+
+I=364
+KEY=2F0731DB4FA3024127BF45F799A094D2E807152921F7B0F5
+CT=E6B6E9133DD0EC2844EF3CC0C2F9E4AC
+PT=20B41EE01134041DF8D11BB7F86928EA
+
+I=365
+KEY=7E44D240F06AAA5E070B5B17889490CF10D60E9ED99E981F
+CT=20B41EE01134041DF8D11BB7F86928EA
+PT=BF6B03096DCDC052B1325CC34BF6E56C
+
+I=366
+KEY=D8D3E3D538C8CA34B860581EE559509DA1E4525D92687D73
+CT=BF6B03096DCDC052B1325CC34BF6E56C
+PT=5ED3E40FB5C34DD1F370C3AD72C7C24D
+
+I=367
+KEY=F3DF20767CDA5E0CE6B3BC11509A1D4C529491F0E0AFBF3E
+CT=5ED3E40FB5C34DD1F370C3AD72C7C24D
+PT=3EA6BCE2317C5D696DF8240C481B34DD
+
+I=368
+KEY=484932A15D75173FD81500F361E640253F6CB5FCA8B48BE3
+CT=3EA6BCE2317C5D696DF8240C481B34DD
+PT=41D6E077746FE1A9307E1107631A5D2C
+
+I=369
+KEY=EF960956685DE1CE99C3E0841589A18C0F12A4FBCBAED6CF
+CT=41D6E077746FE1A9307E1107631A5D2C
+PT=D0C6DDEF0A623686BA303C278D445964
+
+I=370
+KEY=82477D8D682C1D4849053D6B1FEB970AB52298DC46EA8FAB
+CT=D0C6DDEF0A623686BA303C278D445964
+PT=EEFFA6025D6CAFBF9DC18E5B1B99A6ED
+
+I=371
+KEY=15D8DCF80A26856AA7FA9B69428738B528E316875D732946
+CT=EEFFA6025D6CAFBF9DC18E5B1B99A6ED
+PT=38E222ABAA07CDAE9CC02FAC84EC0FC1
+
+I=372
+KEY=556151278277D7579F18B9C2E880F51BB423392BD99F2687
+CT=38E222ABAA07CDAE9CC02FAC84EC0FC1
+PT=B00C719E6A320E4385794EB7F23C0D80
+
+I=373
+KEY=777F91003E4410572F14C85C82B2FB58315A779C2BA32B07
+CT=B00C719E6A320E4385794EB7F23C0D80
+PT=0E667CA932023D2EFD8DDBDED5A43D78
+
+I=374
+KEY=130507FC817F14432172B4F5B0B0C676CCD7AC42FE07167F
+CT=0E667CA932023D2EFD8DDBDED5A43D78
+PT=6B15DA892F0B5916F31BB74FC7D03F9A
+
+I=375
+KEY=D045A84BBF62DE2E4A676E7C9FBB9F603FCC1B0D39D729E5
+CT=6B15DA892F0B5916F31BB74FC7D03F9A
+PT=EBEF6DC298D63BF6E6E46F833B217033
+
+I=376
+KEY=7742FB68CDF60735A18803BE076DA496D928748E02F659D6
+CT=EBEF6DC298D63BF6E6E46F833B217033
+PT=48DC6F65F193AFCCE559EA6F04FBD79A
+
+I=377
+KEY=5CE32BC22C77B664E9546CDBF6FE0B5A3C719EE1060D8E4C
+CT=48DC6F65F193AFCCE559EA6F04FBD79A
+PT=D0596880F92716C51E41519C640AEFDA
+
+I=378
+KEY=2DA6B73C5131E24C390D045B0FD91D9F2230CF7D62076196
+CT=D0596880F92716C51E41519C640AEFDA
+PT=ABB7C3E499086F53C4DB97640168943B
+
+I=379
+KEY=E41C1A826978491892BAC7BF96D172CCE6EB5819636FF5AD
+CT=ABB7C3E499086F53C4DB97640168943B
+PT=0CC58B3D0370317E1025E1AF97962646
+
+I=380
+KEY=501012EE411DCDC59E7F4C8295A143B2F6CEB9B6F4F9D3EB
+CT=0CC58B3D0370317E1025E1AF97962646
+PT=28920AED2B644C4346FC146903887244
+
+I=381
+KEY=97B7E8C1147A5062B6ED466FBEC50FF1B032ADDFF771A1AF
+CT=28920AED2B644C4346FC146903887244
+PT=E7A28DA5EC871DAF8C2D196C7ED8977F
+
+I=382
+KEY=988B9928402BCD63514FCBCA5242125E3C1FB4B389A936D0
+CT=E7A28DA5EC871DAF8C2D196C7ED8977F
+PT=013876A92413AED2E360A241FE021B25
+
+I=383
+KEY=3432357430ACC9135077BD637651BC8CDF7F16F277AB2DF5
+CT=013876A92413AED2E360A241FE021B25
+PT=10F1A56A8CFDA1D5044D5D0E53F6A773
+
+I=384
+KEY=CE94F859CD3E85F440861809FAAC1D59DB324BFC245D8A86
+CT=10F1A56A8CFDA1D5044D5D0E53F6A773
+PT=941C717EE6642DD474719F099AEEB1EB
+
+I=385
+KEY=A1BFA52EA232FDF0D49A69771CC8308DAF43D4F5BEB33B6D
+CT=941C717EE6642DD474719F099AEEB1EB
+PT=F31B47230ABC94977E14E1080528C1C9
+
+I=386
+KEY=37B36A8E7A3B4F2A27812E541674A41AD15735FDBB9BFAA4
+CT=F31B47230ABC94977E14E1080528C1C9
+PT=A91264221890CA93541B662F64A11C62
+
+I=387
+KEY=04F603F98A9D1AC78E934A760EE46E89854C53D2DF3AE6C6
+CT=A91264221890CA93541B662F64A11C62
+PT=05F5171B639825EC67A37B3671F2F884
+
+I=388
+KEY=A294EBBBD53D18DD8B665D6D6D7C4B65E2EF28E4AEC81E42
+CT=05F5171B639825EC67A37B3671F2F884
+PT=B6FE84EB2987DE956953DEBA6FD2E029
+
+I=389
+KEY=E0E38A82F60E8EED3D98D98644FB95F08BBCF65EC11AFE6B
+CT=B6FE84EB2987DE956953DEBA6FD2E029
+PT=2741338CF00FBC70C4B1C67C97E85B97
+
+I=390
+KEY=2193D386143F6D761AD9EA0AB4F429804F0D302256F2A5FC
+CT=2741338CF00FBC70C4B1C67C97E85B97
+PT=E56C7C453E2E13028AD812F9CDB78E2F
+
+I=391
+KEY=05AD3BC4F1B29F17FFB5964F8ADA3A82C5D522DB9B452BD3
+CT=E56C7C453E2E13028AD812F9CDB78E2F
+PT=9A9B49AC0691F1576D515E935F042229
+
+I=392
+KEY=1588C005075F4674652EDFE38C4BCBD5A8847C48C44109FA
+CT=9A9B49AC0691F1576D515E935F042229
+PT=143E5F64AD38373D3B54FA24CC7C0AF5
+
+I=393
+KEY=731083CCCB22E7CF711080872173FCE893D0866C083D030F
+CT=143E5F64AD38373D3B54FA24CC7C0AF5
+PT=61F6AF426601588CB7C525255EC1A06D
+
+I=394
+KEY=DACEE3906B98DFC110E62FC54772A4642415A34956FCA362
+CT=61F6AF426601588CB7C525255EC1A06D
+PT=DB5DC1C3B3413F653D72F8744C2DD881
+
+I=395
+KEY=D9ACA0F56DCA4FC0CBBBEE06F4339B0119675B3D1AD17BE3
+CT=DB5DC1C3B3413F653D72F8744C2DD881
+PT=4E9D548DA49E992AD3123F53558909C9
+
+I=396
+KEY=12C2FE0C57D21C208526BA8B50AD022BCA75646E4F58722A
+CT=4E9D548DA49E992AD3123F53558909C9
+PT=EB2E835192E64ABC30C3F2662B703C47
+
+I=397
+KEY=7A43322D6174BA786E0839DAC24B4897FAB6960864284E6D
+CT=EB2E835192E64ABC30C3F2662B703C47
+PT=CD0690863F63F2B263D4C11190A7985B
+
+I=398
+KEY=EBC6D71978D39185A30EA95CFD28BA2599625719F48FD636
+CT=CD0690863F63F2B263D4C11190A7985B
+PT=C044E800B65CA78559D0642C370C7D3E
+
+I=399
+KEY=A1B6CE2EEC5FC386634A415C4B741DA0C0B23335C383AB08
+CT=C044E800B65CA78559D0642C370C7D3E
+PT=F1A81B68F6E5A6271A8CB24E7D9491EF
+
+=========================
+
+KEYSIZE=256
+
+I=0
+KEY=0000000000000000000000000000000000000000000000000000000000000000
+CT=00000000000000000000000000000000
+PT=058CCFFDBBCB382D1F6F56585D8A4ADE
+
+I=1
+KEY=85C6B2BB2300148F945AEBF1F021CF79058CCFFDBBCB382D1F6F56585D8A4ADE
+CT=058CCFFDBBCB382D1F6F56585D8A4ADE
+PT=15173A0EB65F5CC05E704EFE61D9E346
+
+I=2
+KEY=2447EC44111548FBB670B98F182D5DEE109BF5F30D9464ED411F18A63C53A998
+CT=15173A0EB65F5CC05E704EFE61D9E346
+PT=85F083ACC676D91EDD1ABFB43935237A
+
+I=3
+KEY=85D3E1D750CAA89BEE274AA7C32C2207956B765FCBE2BDF39C05A71205668AE2
+CT=85F083ACC676D91EDD1ABFB43935237A
+PT=42C8F0ABC58E0BEAC32911D2DD9FA8C8
+
+I=4
+KEY=CE86B24954745B2BAAF27010202EE7FAD7A386F40E6CB6195F2CB6C0D8F9222A
+CT=42C8F0ABC58E0BEAC32911D2DD9FA8C8
+PT=5E44123D2CA07981B073BB2749F557D6
+
+I=5
+KEY=CD7BCBBA4555A0D034FD7B528A1D042C89E794C922CCCF98EF5F0DE7910C75FC
+CT=5E44123D2CA07981B073BB2749F557D6
+PT=8B649458EA90F4F7E13467E509B7F164
+
+I=6
+KEY=EF28DFAED7794B1C7B892F3C98FCDC9602830091C85C3B6F0E6B6A0298BB8498
+CT=8B649458EA90F4F7E13467E509B7F164
+PT=F240D1F579DA2CA8839F7072DF52EBA3
+
+I=7
+KEY=C66605EC92F96B49F08CBC6276A0DC68F0C3D164B18617C78DF41A7047E96F3B
+CT=F240D1F579DA2CA8839F7072DF52EBA3
+PT=B05297490A394B4A1736DE7F8DC12969
+
+I=8
+KEY=347403B6E6344E1525B8D2BD4DCA343F4091462DBBBF5C8D9AC2C40FCA284652
+CT=B05297490A394B4A1736DE7F8DC12969
+PT=8BA49D44B98E67501235CE1C2F26BB28
+
+I=9
+KEY=B932CD0C70488602C56F92A0DA57BE27CB35DB6902313BDD88F70A13E50EFD7A
+CT=8BA49D44B98E67501235CE1C2F26BB28
+PT=86CE4E4D040C49F2717407157454162E
+
+I=10
+KEY=28F8B6B4AB2B0B81F3676F6E422D438C4DFB9524063D722FF9830D06915AEB54
+CT=86CE4E4D040C49F2717407157454162E
+PT=4E9CA7FB0FF9F38FC821CA91052483F9
+
+I=11
+KEY=5CD19F4D3C5B58602B101E15B39F51E4036732DF09C481A031A2C797947E68AD
+CT=4E9CA7FB0FF9F38FC821CA91052483F9
+PT=55E49ED59245C1850CB0C17C1CEEA05E
+
+I=12
+KEY=E822BB0D1F25F3DCA6FE0CB1A8AF39F15683AC0A9B8140253D1206EB8890C8F3
+CT=55E49ED59245C1850CB0C17C1CEEA05E
+PT=F7F0BFA319AC289C9F64E6FCDD531B44
+
+I=13
+KEY=8B64FF354C6E303F14EA34C9F667FEC9A17313A9822D68B9A276E01755C3D3B7
+CT=F7F0BFA319AC289C9F64E6FCDD531B44
+PT=6ACB8A177226AE47E2170F77D2FE4923
+
+I=14
+KEY=1A9D440EBAC3F3625E229B66C5D9249CCBB899BEF00BC6FE4061EF60873D9A94
+CT=6ACB8A177226AE47E2170F77D2FE4923
+PT=BAA9BB819332A87D6004164927EAC699
+
+I=15
+KEY=97F92B9AD44A3182FF10E07747C560B37111223F63396E832065F929A0D75C0D
+CT=BAA9BB819332A87D6004164927EAC699
+PT=EB84793E2D68632900B0517392EC4B94
+
+I=16
+KEY=2AEEBA2AC59870A7B4274B80FE74D55A9A955B014E510DAA20D5A85A323B1799
+CT=EB84793E2D68632900B0517392EC4B94
+PT=6C662FBE2B22394CC1D45453772C72BA
+
+I=17
+KEY=EEA4B3C4F96C42E3B7DF5A3870C85B69F6F374BF657334E6E101FC0945176523
+CT=6C662FBE2B22394CC1D45453772C72BA
+PT=70D2BBC1FA7D49848D94112DA93A3C3C
+
+I=18
+KEY=F930D1529C654F31549809C6CD5CC4608621CF7E9F0E7D626C95ED24EC2D591F
+CT=70D2BBC1FA7D49848D94112DA93A3C3C
+PT=1AFF91E67039133946638E4E505310C2
+
+I=19
+KEY=5D0F461C1A5FF7BA5C93F0CED9DD49FF9CDE5E98EF376E5B2AF6636ABC7E49DD
+CT=1AFF91E67039133946638E4E505310C2
+PT=8E4358B22DE7BCDC8B8409E6250633BF
+
+I=20
+KEY=AA4B475845EB19F601856A40AB517594129D062AC2D0D287A1726A8C99787A62
+CT=8E4358B22DE7BCDC8B8409E6250633BF
+PT=2A79FE5A222C9503954346D6C15AC679
+
+I=21
+KEY=9703F4DD85A3BE85343FFD15950A266B38E4F870E0FC478434312C5A5822BC1B
+CT=2A79FE5A222C9503954346D6C15AC679
+PT=0FF812C5B863282C294D7069F830EE86
+
+I=22
+KEY=3DD1B2ACBC6568851E767D20D82AD324371CEAB5589F6FA81D7C5C33A012529D
+CT=0FF812C5B863282C294D7069F830EE86
+PT=D449218625DE49D2B9514E032CA096E7
+
+I=23
+KEY=95CC16235D3DFF4F7DB2116D2B380F39E355CB337D41267AA42D12308CB2C47A
+CT=D449218625DE49D2B9514E032CA096E7
+PT=F951EAC3BC78DB0AE13FDC33048D2D81
+
+I=24
+KEY=A6F55AFBDA7EA939F6F2A28530C416781A0421F0C139FD704512CE03883FE9FB
+CT=F951EAC3BC78DB0AE13FDC33048D2D81
+PT=7D5A03A955F6403F918AC915AC22B797
+
+I=25
+KEY=7C5D39885F4C0F4FCF672321B711C5B7675E225994CFBD4FD4980716241D5E6C
+CT=7D5A03A955F6403F918AC915AC22B797
+PT=CA2E1C274073AD2A3AE35C60ECA52A58
+
+I=26
+KEY=4E7B914B84BFA1A2D7BD409AFADD2EDCAD703E7ED4BC1065EE7B5B76C8B87434
+CT=CA2E1C274073AD2A3AE35C60ECA52A58
+PT=C5048FA0148CED10A06E107269DA9C95
+
+I=27
+KEY=F62D8C4822C5F89D51E3C68695D91CA66874B1DEC030FD754E154B04A162E8A1
+CT=C5048FA0148CED10A06E107269DA9C95
+PT=CB9B457A7A24577DA71AC335F0572DAB
+
+I=28
+KEY=C37AAD7CB20087F4B98390C59D3ECFB2A3EFF4A4BA14AA08E90F88315135C50A
+CT=CB9B457A7A24577DA71AC335F0572DAB
+PT=FA60BFF170DD30C29DF1807C1612CD67
+
+I=29
+KEY=1A2C6858B37D0341BF8796FB72D00B72598F4B55CAC99ACA74FE084D4727086D
+CT=FA60BFF170DD30C29DF1807C1612CD67
+PT=E2FACFB5DF4E69C911838FCC546D0C8E
+
+I=30
+KEY=039B73E3A8DCF3C678FBC246AAECDAECBB7584E01587F303657D8781134A04E3
+CT=E2FACFB5DF4E69C911838FCC546D0C8E
+PT=749AB2B9176AFDB8B6714DF44BBF2B58
+
+I=31
+KEY=773D90EA7ECA29DFD9141A42EB2BBC64CFEF365902ED0EBBD30CCA7558F52FBB
+CT=749AB2B9176AFDB8B6714DF44BBF2B58
+PT=0285E58D09A8D33FB196FD16A8DF37C0
+
+I=32
+KEY=598262B046B44784D977F6BE2553C6ACCD6AD3D40B45DD84629A3763F02A187B
+CT=0285E58D09A8D33FB196FD16A8DF37C0
+PT=1C952C46AE829D8805031A44F9D85521
+
+I=33
+KEY=AFAE657D3220CD1E6199A49754525F4AD1FFFF92A5C7400C67992D2709F24D5A
+CT=1C952C46AE829D8805031A44F9D85521
+PT=EED0A47E63FF354B4D9C53F7FD75D720
+
+I=34
+KEY=A61F583BCFD120B8CABE1E4C616F4FC73F2F5BECC63875472A057ED0F4879A7A
+CT=EED0A47E63FF354B4D9C53F7FD75D720
+PT=10C1F0F7C32AD36F03AEA8DCE6AAE7BC
+
+I=35
+KEY=FB76D4B83A7F50482A92F5A92CB60F522FEEAB1B0512A62829ABD60C122D7DC6
+CT=10C1F0F7C32AD36F03AEA8DCE6AAE7BC
+PT=372488DF6543180F1F2AE15E5B0C8785
+
+I=36
+KEY=35EAC2BA73F55570CB727220C027FE6218CA23C46051BE27368137524921FA43
+CT=372488DF6543180F1F2AE15E5B0C8785
+PT=3DE420FF3699D68DB69966F57D09045A
+
+I=37
+KEY=48B6E08B9FD9B5C130E1829CD4540D9C252E033B56C868AA801851A73428FE19
+CT=3DE420FF3699D68DB69966F57D09045A
+PT=7858F396DC520131C789CB8F8C919CCD
+
+I=38
+KEY=DB39C13F29241FF29C5BEB839705AD5B5D76F0AD8A9A699B47919A28B8B962D4
+CT=7858F396DC520131C789CB8F8C919CCD
+PT=07BE8BBF9FCD7D04888E61935DD7222F
+
+I=39
+KEY=A5F9B675531AB58C1FFC316C9359EA335AC87B121557149FCF1FFBBBE56E40FB
+CT=07BE8BBF9FCD7D04888E61935DD7222F
+PT=EDD619B7C12E2AF6BDAA953B2E7871EF
+
+I=40
+KEY=A02D1F14A64BBC67DD7EE9EAB3FB0EADB71E62A5D4793E6972B56E80CB163114
+CT=EDD619B7C12E2AF6BDAA953B2E7871EF
+PT=C748CDB645F1A1E44A63FAF00B2C3A45
+
+I=41
+KEY=177D7A6843B5ABBEB212E68734A7A05C7056AF1391889F8D38D69470C03A0B51
+CT=C748CDB645F1A1E44A63FAF00B2C3A45
+PT=BD3ED4C8CD7DBF4299AC63FE119D291E
+
+I=42
+KEY=BD9BDC6BD09DEED3E75C918BE55E5332CD687BDB5CF520CFA17AF78ED1A7224F
+CT=BD3ED4C8CD7DBF4299AC63FE119D291E
+PT=A16B82F958441E90A965427C854EECBB
+
+I=43
+KEY=E6325C33EC76F8EDE02707A3AE82F1096C03F92204B13E5F081FB5F254E9CEF4
+CT=A16B82F958441E90A965427C854EECBB
+PT=E04E642689D1AB78E7CDE26D0563901C
+
+I=44
+KEY=B8543DB3071AB9F0802D4106FBDA59648C4D9D048D609527EFD2579F518A5EE8
+CT=E04E642689D1AB78E7CDE26D0563901C
+PT=08E59C72C13C030DA3C50300861EA097
+
+I=45
+KEY=ECDD43A6B225DB325BFFE5462B66E97884A801764C5C962A4C17549FD794FE7F
+CT=08E59C72C13C030DA3C50300861EA097
+PT=C224B2EFEE07AAC33F1F6EB1295D9A50
+
+I=46
+KEY=741D627C8B47BED4497C71FDC9854912468CB399A25B3CE973083A2EFEC9642F
+CT=C224B2EFEE07AAC33F1F6EB1295D9A50
+PT=1653CE734D27B44369D4FE582E7A885F
+
+I=47
+KEY=A47BDC62B1D80815AC6BF04481C5601F50DF7DEAEF7C88AA1ADCC476D0B3EC70
+CT=1653CE734D27B44369D4FE582E7A885F
+PT=CADC89828B6147FAEC581DDCFF3C0960
+
+I=48
+KEY=CB91E738F51C111DAC2E0A3BF7B076A39A03F468641DCF50F684D9AA2F8FE510
+CT=CADC89828B6147FAEC581DDCFF3C0960
+PT=49402F0F4AFA2518D57C5D1CFCECC0F2
+
+I=49
+KEY=BDA1FFAEE7B93EDFCA4374871A149550D343DB672EE7EA4823F884B6D36325E2
+CT=49402F0F4AFA2518D57C5D1CFCECC0F2
+PT=EBFF53AB449DE5A53EDC6E595AA47B10
+
+I=50
+KEY=18D865B8E8C779268D3876C22AF479FB38BC88CC6A7A0FED1D24EAEF89C75EF2
+CT=EBFF53AB449DE5A53EDC6E595AA47B10
+PT=30073458509F9AC9DA21B2DF566AB3BE
+
+I=51
+KEY=967E2580238300563A34A6E70D84B4FF08BBBC943AE59524C7055830DFADED4C
+CT=30073458509F9AC9DA21B2DF566AB3BE
+PT=5AB9F90CC2A7603A68E2ACA95A2DE55D
+
+I=52
+KEY=A469A4E2F0B3847F3B52886FAD7DBAF652024598F842F51EAFE7F49985800811
+CT=5AB9F90CC2A7603A68E2ACA95A2DE55D
+PT=F22A13F395B6064172CA9DC572C26B2E
+
+I=53
+KEY=9EA4946ED73FF8BB8700C18967C01968A028566B6DF4F35FDD2D695CF742633F
+CT=F22A13F395B6064172CA9DC572C26B2E
+PT=26E44B9F3DEBA8EE3531DDFA42F1DC14
+
+I=54
+KEY=3D25EEEACEF18702FD3896283CFF8A8386CC1DF4501F5BB1E81CB4A6B5B3BF2B
+CT=26E44B9F3DEBA8EE3531DDFA42F1DC14
+PT=32D9F05174FFF34594E952B7ADE09737
+
+I=55
+KEY=8BF2A692F6A35980C0CF02FF4650871BB415EDA524E0A8F47CF5E6111853281C
+CT=32D9F05174FFF34594E952B7ADE09737
+PT=7BEF027DEB1FF22774CE8A8A101DD41B
+
+I=56
+KEY=C90BF0E1A8B615B4C8BD318260BB80AECFFAEFD8CFFF5AD3083B6C9B084EFC07
+CT=7BEF027DEB1FF22774CE8A8A101DD41B
+PT=CF6B2444DFBBFE5B6A1CA99F2D13DE9A
+
+I=57
+KEY=C2A4C82B4AAEE0A22315026C6FE396900091CB9C1044A4886227C504255D229D
+CT=CF6B2444DFBBFE5B6A1CA99F2D13DE9A
+PT=14AD8C7B0F0460A3F48D5CD2CFFB385C
+
+I=58
+KEY=BF76E610192E2AEF42FF8F487CDDC318143C47E71F40C42B96AA99D6EAA61AC1
+CT=14AD8C7B0F0460A3F48D5CD2CFFB385C
+PT=A5A850FC44A09C5985CE9661AF84F186
+
+I=59
+KEY=1E42AEC368C600F18CBFA305EB559946B194171B5BE0587213640FB74522EB47
+CT=A5A850FC44A09C5985CE9661AF84F186
+PT=E2895D416951FDA66B695ABFA313F89D
+
+I=60
+KEY=4E9BC121E32849DAA501BEA4E534D9C2531D4A5A32B1A5D4780D5508E63113DA
+CT=E2895D416951FDA66B695ABFA313F89D
+PT=91E93AAECC5FB253F7463F101B2A4132
+
+I=61
+KEY=ACC045A67F680F14D3F8DA454C922071C2F470F4FEEE17878F4B6A18FD1B52E8
+CT=91E93AAECC5FB253F7463F101B2A4132
+PT=F0F339022B4001E72F3BCC1A140603AD
+
+I=62
+KEY=4B47D2639B4A04D3C87D35DB4E63E563320749F6D5AE1660A070A602E91D5145
+CT=F0F339022B4001E72F3BCC1A140603AD
+PT=DBECAFF90EDD4555A5D9A23817520D51
+
+I=63
+KEY=C73B1C617BE90F2710DFF2C3AC60E0F9E9EBE60FDB73533505A9043AFE4F5C14
+CT=DBECAFF90EDD4555A5D9A23817520D51
+PT=73315A63A8889095AFED497AEFE657B4
+
+I=64
+KEY=7F368758F7B303DE356481ED8EBFA46F9ADABC6C73FBC3A0AA444D4011A90BA0
+CT=73315A63A8889095AFED497AEFE657B4
+PT=3AB7E2F81D24D857308A1FC785559333
+
+I=65
+KEY=6D7EF76412498AB3C70AA3006CC87188A06D5E946EDF1BF79ACE528794FC9893
+CT=3AB7E2F81D24D857308A1FC785559333
+PT=7EAA2814E372F674AB0B6E0E428D1AF4
+
+I=66
+KEY=D626AD50A7B86153BF9215A6A8F7E908DEC776808DADED8331C53C89D6718267
+CT=7EAA2814E372F674AB0B6E0E428D1AF4
+PT=ADD212A59AC9EF6A55AEAC22D35A1BFE
+
+I=67
+KEY=4B9C7ED9AC7835C87DAB8BEF3ED6878B73156425176402E9646B90AB052B9999
+CT=ADD212A59AC9EF6A55AEAC22D35A1BFE
+PT=203ECD34AE1BB2F23BC673DBD74FA07B
+
+I=68
+KEY=E34FBDEF9D81B464DD1138093F132051532BA911B97FB01B5FADE370D26439E2
+CT=203ECD34AE1BB2F23BC673DBD74FA07B
+PT=0A18AFD5EEBBD338299897EA1F01324C
+
+I=69
+KEY=77BD51D39775121C22343FFC66D40F0B593306C457C463237635749ACD650BAE
+CT=0A18AFD5EEBBD338299897EA1F01324C
+PT=2892A6AE9517642A0977942360FB8104
+
+I=70
+KEY=2761BF5478726AF184C86B45AE331A7E71A1A06AC2D307097F42E0B9AD9E8AAA
+CT=2892A6AE9517642A0977942360FB8104
+PT=8A4CD7685B9A1E663C3130C34BC418B9
+
+I=71
+KEY=DD168B81E90D806FF468BE5E551F3344FBED77029949196F4373D07AE65A9213
+CT=8A4CD7685B9A1E663C3130C34BC418B9
+PT=C7C0A15A1A22363B378D5DD27A69D4C2
+
+I=72
+KEY=3442C07C0E98F523F9278D934F424BD83C2DD658836B2F5474FE8DA89C3346D1
+CT=C7C0A15A1A22363B378D5DD27A69D4C2
+PT=55A8EF8CAE213FE3FD6AA77E7415400A
+
+I=73
+KEY=291BD1577921B2947BC470C19727F0BD698539D42D4A10B789942AD6E82606DB
+CT=55A8EF8CAE213FE3FD6AA77E7415400A
+PT=0B07BEB71461356645936996AC45EB87
+
+I=74
+KEY=46475B4C21F0F4895FEFCC67632DBCDC62828763392B25D1CC0743404463ED5C
+CT=0B07BEB71461356645936996AC45EB87
+PT=6DFA5978F740C18CEE6F70FF50008BFD
+
+I=75
+KEY=CF89BDDE5D363B3C44DB6FED2DAB47AA0F78DE1BCE6BE45D226833BF146366A1
+CT=6DFA5978F740C18CEE6F70FF50008BFD
+PT=6F58747F0336A2C4D2A397511E06D703
+
+I=76
+KEY=85F7D4A4503F7C3D52998384F8B29BEF6020AA64CD5D4699F0CBA4EE0A65B1A2
+CT=6F58747F0336A2C4D2A397511E06D703
+PT=32AC7B1B8FFA7D411F46C129EEFFAF13
+
+I=77
+KEY=CDE87D2DFB6198CFC737D93433419757528CD17F42A73BD8EF8D65C7E49A1EB1
+CT=32AC7B1B8FFA7D411F46C129EEFFAF13
+PT=CF5D039714814E72ECE7B9D5D1B27D11
+
+I=78
+KEY=BCB9F75F11496AABFE2633E393B59B449DD1D2E8562675AA036ADC12352863A0
+CT=CF5D039714814E72ECE7B9D5D1B27D11
+PT=3455F997002A1818967E2679A07C1D56
+
+I=79
+KEY=99E143B3524E724A009533AEC659E15BA9842B7F560C6DB29514FA6B95547EF6
+CT=3455F997002A1818967E2679A07C1D56
+PT=1F2113D44E290F1379A3CEC6D57D6279
+
+I=80
+KEY=90086C83794D6878FF2CE748ECA6EDF4B6A538AB182562A1ECB734AD40291C8F
+CT=1F2113D44E290F1379A3CEC6D57D6279
+PT=88866DB676AA3B21954AFDE0A0F33007
+
+I=81
+KEY=FA254EB868F6CD5965346ACAE326BD2A3E23551D6E8F598079FDC94DE0DA2C88
+CT=88866DB676AA3B21954AFDE0A0F33007
+PT=A1665AD0252764E2691E65FEFB609CDA
+
+I=82
+KEY=92032C92FEEB0A5CD5D71AAF1BF5F47D9F450FCD4BA83D6210E3ACB31BBAB052
+CT=A1665AD0252764E2691E65FEFB609CDA
+PT=988CE348430A206546379A8C684C00F1
+
+I=83
+KEY=CF32144187F7B98256B5B4204DFABC8807C9EC8508A21D0756D4363F73F6B0A3
+CT=988CE348430A206546379A8C684C00F1
+PT=60289F0B6A9ADD08BF8924AA6D7F4D12
+
+I=84
+KEY=A7BD244360E3C325F3EA315C86959DD867E1738E6238C00FE95D12951E89FDB1
+CT=60289F0B6A9ADD08BF8924AA6D7F4D12
+PT=FA3EA122499D7E083D81F147D9D68B09
+
+I=85
+KEY=86213610EDC35A883A3364E8D529C6459DDFD2AC2BA5BE07D4DCE3D2C75F76B8
+CT=FA3EA122499D7E083D81F147D9D68B09
+PT=8E0B2452EF0515FC554A0AADF107714D
+
+I=86
+KEY=92CC3AE4A2A68CD93634075E902C66CB13D4F6FEC4A0ABFB8196E97F365807F5
+CT=8E0B2452EF0515FC554A0AADF107714D
+PT=463CEAE83A50BA54280E792AB6B29B94
+
+I=87
+KEY=6D86FA00DBB949A29D4A6166F1EF531E55E81C16FEF011AFA998905580EA9C61
+CT=463CEAE83A50BA54280E792AB6B29B94
+PT=416CA710B874E50CC98DF842B3435AD1
+
+I=88
+KEY=C9400C98A04F5041BE1C6090A866F7DA1484BB064684F4A36015681733A9C6B0
+CT=416CA710B874E50CC98DF842B3435AD1
+PT=3BA8BB5C572C0404E4B8199528825904
+
+I=89
+KEY=ED5043E9699B37844033E8BD170588342F2C005A11A8F0A784AD71821B2B9FB4
+CT=3BA8BB5C572C0404E4B8199528825904
+PT=1D2812DE70AA2D59894DA4DA7FE906FC
+
+I=90
+KEY=1964C6C301EEEF60B34E8E35175CAF8D320412846102DDFE0DE0D55864C29948
+CT=1D2812DE70AA2D59894DA4DA7FE906FC
+PT=2735CAAFE653442FFC2E878AE2829998
+
+I=91
+KEY=567B1E0737D0F72F82EB3A47D17209191531D82B875199D1F1CE52D2864000D0
+CT=2735CAAFE653442FFC2E878AE2829998
+PT=07B5FA4835E5DFC67E02F490A497145D
+
+I=92
+KEY=89AAD6DCA6A8973580D02768EBC8372412842263B2B446178FCCA64222D7148D
+CT=07B5FA4835E5DFC67E02F490A497145D
+PT=A31272EC8623213B015811FAE12330CE
+
+I=93
+KEY=4B4AB47A0DBA39907D8E919767E69518B196508F3497672C8E94B7B8C3F42443
+CT=A31272EC8623213B015811FAE12330CE
+PT=9132AB51C9738A62CABDE4977947E0BF
+
+I=94
+KEY=BEC71999AEE5517C243B65830D30DEBB20A4FBDEFDE4ED4E4429532FBAB3C4FC
+CT=9132AB51C9738A62CABDE4977947E0BF
+PT=689375EA83B61894631E6EFA2D509531
+
+I=95
+KEY=77CE2C97A458300D7C95C6871CEB56D648378E347E52F5DA27373DD597E351CD
+CT=689375EA83B61894631E6EFA2D509531
+PT=AAA5C6C5917DFC103383DE6C79EB2BA6
+
+I=96
+KEY=0AD691774612F7EFA41FE39B8B3A2D14E29248F1EF2F09CA14B4E3B9EE087A6B
+CT=AAA5C6C5917DFC103383DE6C79EB2BA6
+PT=29D9945BDB3770ED2A41D2760D0DC51D
+
+I=97
+KEY=4E1D42ADC4CEF6BAE3A5B9E08F7ACD65CB4BDCAA341879273EF531CFE305BF76
+CT=29D9945BDB3770ED2A41D2760D0DC51D
+PT=2F9B3C4E1FDCDC8F7D5DFBEA342284F2
+
+I=98
+KEY=2D76A3E35C075DB14E40A59F46E07A81E4D0E0E42BC4A5A843A8CA25D7273B84
+CT=2F9B3C4E1FDCDC8F7D5DFBEA342284F2
+PT=ED4CFCF1C8D226EBACCC8FF11B1C81B8
+
+I=99
+KEY=E7364D0D17D723A69C0BA956778BD0E9099C1C15E3168343EF6445D4CC3BBA3C
+CT=ED4CFCF1C8D226EBACCC8FF11B1C81B8
+PT=2F9B5E1392B767E8497F849D00E98193
+
+I=100
+KEY=709380C7012CB4272A69F6D4936B163E2607420671A1E4ABA61BC149CCD23BAF
+CT=2F9B5E1392B767E8497F849D00E98193
+PT=3BE783A4A38EFB44150AA7A08E1888F6
+
+I=101
+KEY=98FF27B8AB7B91F690231E24608076EF1DE0C1A2D22F1FEFB31166E942CAB359
+CT=3BE783A4A38EFB44150AA7A08E1888F6
+PT=F35AED9C83E53D2EADDE507345096218
+
+I=102
+KEY=24F9D2FF633EE9AAED7321CFCF4D1D20EEBA2C3E51CA22C11ECF369A07C3D141
+CT=F35AED9C83E53D2EADDE507345096218
+PT=A22BF93FD521A6E59C196022FF252DC2
+
+I=103
+KEY=70E491840BC5C42A878655E18E9AAAA74C91D50184EB842482D656B8F8E6FC83
+CT=A22BF93FD521A6E59C196022FF252DC2
+PT=11E67B52F8CD97D63268485EB546E1FE
+
+I=104
+KEY=098FF2D6DE55FF5C66D5AD7D5949643A5D77AE537C2613F2B0BE1EE64DA01D7D
+CT=11E67B52F8CD97D63268485EB546E1FE
+PT=1E67AF3F7E7FDEFB868696E96F718ACC
+
+I=105
+KEY=B89EA7CBAE57B8AD39F23B22A8F651A44310016C0259CD093638880F22D197B1
+CT=1E67AF3F7E7FDEFB868696E96F718ACC
+PT=332B0045710B2DD6EC3D619051580C7F
+
+I=106
+KEY=39F71BC56EBFA91088499DC41A0C5B5B703B01297352E0DFDA05E99F73899BCE
+CT=332B0045710B2DD6EC3D619051580C7F
+PT=86F3D75D18F7AB31C6C52C19B0C35023
+
+I=107
+KEY=417147DB03FDA0B26BEED7FE8A9487D5F6C8D6746BA54BEE1CC0C586C34ACBED
+CT=86F3D75D18F7AB31C6C52C19B0C35023
+PT=452E6C2DA8B93A1E282F1A86AECB9F15
+
+I=108
+KEY=C4336C26C20AD7811578044800A51E8EB3E6BA59C31C71F034EFDF006D8154F8
+CT=452E6C2DA8B93A1E282F1A86AECB9F15
+PT=637F010BAC28AC108331F4E26B262D3A
+
+I=109
+KEY=D0369C75D40EEF29CF7588FB87EE2ED2D099BB526F34DDE0B7DE2BE206A779C2
+CT=637F010BAC28AC108331F4E26B262D3A
+PT=3F3DCA8B4C2DDFD556880A17FB575E7B
+
+I=110
+KEY=4DE25218630A678C287EC42F93985D22EFA471D923190235E15621F5FDF027B9
+CT=3F3DCA8B4C2DDFD556880A17FB575E7B
+PT=3DA8C1D40B51A8BC6E728D7A1E6B3B2E
+
+I=111
+KEY=C0526C3096805B532433C0248E153A00D20CB00D2848AA898F24AC8FE39B1C97
+CT=3DA8C1D40B51A8BC6E728D7A1E6B3B2E
+PT=449B050578191E4C156F7040EF27D5EC
+
+I=112
+KEY=6A1B7384328BAA25B6A857FB12A90FD49697B5085051B4C59A4BDCCF0CBCC97B
+CT=449B050578191E4C156F7040EF27D5EC
+PT=D58ACA128F936803BDD5EC1E6DECAB04
+
+I=113
+KEY=44B7F3EB0EF0EF4325353D30F35C4D71431D7F1ADFC2DCC6279E30D16150627F
+CT=D58ACA128F936803BDD5EC1E6DECAB04
+PT=77F1011F968AD46338CA68D5DF37959E
+
+I=114
+KEY=E1E6BBD70AEAC4D65159422B3DFE82DF34EC7E05494808A51F545804BE67F7E1
+CT=77F1011F968AD46338CA68D5DF37959E
+PT=FC692161766A29C9E6A86C353E2F3FE5
+
+I=115
+KEY=5C33A88179175BB12593D6574245A6A6C8855F643F22216CF9FC34318048C804
+CT=FC692161766A29C9E6A86C353E2F3FE5
+PT=F5FD2F77BC4908F470142417048C6233
+
+I=116
+KEY=E6A3CDD47570AEC4FC3B3453F78F253F3D787013836B299889E8102684C4AA37
+CT=F5FD2F77BC4908F470142417048C6233
+PT=FBDC2774D7E426CBD8B62ABD0E0EAA6F
+
+I=117
+KEY=4F5B3EDC53366D4C74D94663E17CBDB6C6A45767548F0F53515E3A9B8ACA0058
+CT=FBDC2774D7E426CBD8B62ABD0E0EAA6F
+PT=796D978C9D724C1C9445EC5BD272CEB0
+
+I=118
+KEY=9119AD19E78100B3D04BED87FF5C22B5BFC9C0EBC9FD434FC51BD6C058B8CEE8
+CT=796D978C9D724C1C9445EC5BD272CEB0
+PT=15ECF7D3F516D3CBA0307959287A5BAB
+
+I=119
+KEY=600B4D7604FF2650611C453A50D02275AA2537383CEB9084652BAF9970C29543
+CT=15ECF7D3F516D3CBA0307959287A5BAB
+PT=DA67996084E9C74C143310FC3CF207DD
+
+I=120
+KEY=3B8E0B73BBF745BB360EA50E7DA9B3297042AE58B80257C87118BF654C30929E
+CT=DA67996084E9C74C143310FC3CF207DD
+PT=6E9BC50580D45D54FEEC74830C0D9516
+
+I=121
+KEY=231592D0CE761359AE2E85CC4E4156A01ED96B5D38D60A9C8FF4CBE6403D0788
+CT=6E9BC50580D45D54FEEC74830C0D9516
+PT=A4B0F6A50C72C5EE755FA5595334DF2E
+
+I=122
+KEY=7ABD82D278910B909B0D6219EF5E0D98BA699DF834A4CF72FAAB6EBF1309D8A6
+CT=A4B0F6A50C72C5EE755FA5595334DF2E
+PT=24CDAEEB54A1EB7E2D4A0BEE526EA6E0
+
+I=123
+KEY=5C8F7B23850BD287F011E257D691F8979EA433136005240CD7E1655141677E46
+CT=24CDAEEB54A1EB7E2D4A0BEE526EA6E0
+PT=84F24CDC0AA63CEA2DDE8F94C8776765
+
+I=124
+KEY=DF8EEE46309021F6E7D7D41908B6CABE1A567FCF6AA318E6FA3FEAC589101923
+CT=84F24CDC0AA63CEA2DDE8F94C8776765
+PT=EEA20542DEDB0B99A2144942FFEAC820
+
+I=125
+KEY=8634A663D618B3BB54F44A5849170ACDF4F47A8DB478137F582BA38776FAD103
+CT=EEA20542DEDB0B99A2144942FFEAC820
+PT=CDD91737753BE9F672A60DD722202127
+
+I=126
+KEY=E41913E97F21A4E6A948ABEB45279E0D392D6DBAC143FA892A8DAE5054DAF024
+CT=CDD91737753BE9F672A60DD722202127
+PT=E6E2F7846E06BB90F19B21521DD4D238
+
+I=127
+KEY=1E63624B5EADBE7D42255F208CC7D348DFCF9A3EAF454119DB168F02490E221C
+CT=E6E2F7846E06BB90F19B21521DD4D238
+PT=0110CA2647D43C8BD012976113EFB860
+
+I=128
+KEY=8476329019AA4D0D91C71E0DFFF47906DEDF5018E8917D920B0418635AE19A7C
+CT=0110CA2647D43C8BD012976113EFB860
+PT=CC9AACC98876387D09565F1A20D329AF
+
+I=129
+KEY=DB1C0803BC1AD91C5621FA8C54AA83EF1245FCD160E745EF025247797A32B3D3
+CT=CC9AACC98876387D09565F1A20D329AF
+PT=55AB296D67DEEBA179AD8093C1952CC2
+
+I=130
+KEY=5C0887FF7C888D7800C43BC9E88D9B3B47EED5BC0739AE4E7BFFC7EABBA79F11
+CT=55AB296D67DEEBA179AD8093C1952CC2
+PT=27016691505182706848CD5D7A2C5CAB
+
+I=131
+KEY=0FFBE12ADFA17F3BF26622C20311D38960EFB32D57682C3E13B70AB7C18BC3BA
+CT=27016691505182706848CD5D7A2C5CAB
+PT=5E6C9FAF480FFE51D7687ADE203D5367
+
+I=132
+KEY=C4C12330BC21062618E2E83EC3755DAC3E832C821F67D26FC4DF7069E1B690DD
+CT=5E6C9FAF480FFE51D7687ADE203D5367
+PT=082FF20DC6AFBA3888348E5724F5C526
+
+I=133
+KEY=3F6BF56A0136C1058924FCD831A65EBC36ACDE8FD9C868574CEBFE3EC54355FB
+CT=082FF20DC6AFBA3888348E5724F5C526
+PT=67AE68CDDA349A067339F28FA216A188
+
+I=134
+KEY=4AB9E8E9B5BB84353006AB43065C6B8F5102B64203FCF2513FD20CB16755F473
+CT=67AE68CDDA349A067339F28FA216A188
+PT=3316F37F97D679B78A537A0E107923AB
+
+I=135
+KEY=E04DE045508423D735B20168C7974CC26214453D942A8BE6B58176BF772CD7D8
+CT=3316F37F97D679B78A537A0E107923AB
+PT=00AEB331686999C5F5FB1E7C6CCF1072
+
+I=136
+KEY=D4D19E570760468E9703F0E49C4AC9F262BAF60CFC431223407A68C31BE3C7AA
+CT=00AEB331686999C5F5FB1E7C6CCF1072
+PT=29A5DB93D2AE9B1ED9714213EAD9AA1C
+
+I=137
+KEY=6D6789354D2CC3EFA9ABFC466F21A6E24B1F2D9F2EED893D990B2AD0F13A6DB6
+CT=29A5DB93D2AE9B1ED9714213EAD9AA1C
+PT=E98426CB0F858A084EB66311188D9200
+
+I=138
+KEY=06ED66801B81943BF1640AAE222A23C7A29B0B5421680335D7BD49C1E9B7FFB6
+CT=E98426CB0F858A084EB66311188D9200
+PT=21527326577425261F2D40268C428E29
+
+I=139
+KEY=2232758279A806C21870C85273C12FA883C97872761C2613C89009E765F5719F
+CT=21527326577425261F2D40268C428E29
+PT=CC9393A43B8A8194C0EC29F989E597A6
+
+I=140
+KEY=E7E22C2A6E6D4A1BFE7B706047094AF44F5AEBD64D96A787087C201EEC10E639
+CT=CC9393A43B8A8194C0EC29F989E597A6
+PT=714846062B262A823B24164900DF91AD
+
+I=141
+KEY=89A78F64BCAEE02CAC92928134C2567C3E12ADD066B08D0533583657ECCF7794
+CT=714846062B262A823B24164900DF91AD
+PT=1D0AC79D1E9BB36A6A6A8E49538C08FF
+
+I=142
+KEY=4F6E8D81296C95FAA0FE6F2D324A392223186A4D782B3E6F5932B81EBF437F6B
+CT=1D0AC79D1E9BB36A6A6A8E49538C08FF
+PT=403D8B10E0AB31493589AFFA8E8B1BEE
+
+I=143
+KEY=24E398291CF018E4666728F4F635F74D6325E15D98800F266CBB17E431C86485
+CT=403D8B10E0AB31493589AFFA8E8B1BEE
+PT=9E0516EDA401DAAF6AC013841C0D63C8
+
+I=144
+KEY=F80CF8AF1FA463D2ED7C7F59C1B239B0FD20F7B03C81D589067B04602DC5074D
+CT=9E0516EDA401DAAF6AC013841C0D63C8
+PT=74B2B200922B21AA20A0C5860CFB7E4D
+
+I=145
+KEY=577A5456424E1A76C3E113EB82CCDF34899245B0AEAAF42326DBC1E6213E7900
+CT=74B2B200922B21AA20A0C5860CFB7E4D
+PT=25AFF27E13888A638CDA2673D7F16AFD
+
+I=146
+KEY=7C623BBD4777E6EF9BC058DF5BA27BEAAC3DB7CEBD227E40AA01E795F6CF13FD
+CT=25AFF27E13888A638CDA2673D7F16AFD
+PT=A54F400AB9C52913D7302BA36BF217DD
+
+I=147
+KEY=A8B33E433720C4B925C4F0315DDB73B00972F7C404E757537D31CC369D3D0420
+CT=A54F400AB9C52913D7302BA36BF217DD
+PT=48A263A07112AA95EA1414CE03545790
+
+I=148
+KEY=DA864B91AED3E2FAC25782F4A50C13C841D0946475F5FDC69725D8F89E6953B0
+CT=48A263A07112AA95EA1414CE03545790
+PT=541547E924522E59C1721D130B64D92F
+
+I=149
+KEY=EEB5FF6F9C435510E12934F5E806553E15C5D38D51A7D39F5657C5EB950D8A9F
+CT=541547E924522E59C1721D130B64D92F
+PT=5830544939EB4607145538388840248B
+
+I=150
+KEY=24E609AD29E4C601189CB2FE119767884DF587C4684C95984202FDD31D4DAE14
+CT=5830544939EB4607145538388840248B
+PT=CBE1F82FD3318448AA36ADB5967EF865
+
+I=151
+KEY=5A7EBB76C38C2E5F038612A06E84BB2C86147FEBBB7D11D0E83450668B335671
+CT=CBE1F82FD3318448AA36ADB5967EF865
+PT=3B104547D2D620879E3CB2B5774C0FB4
+
+I=152
+KEY=827EFCB7BC862C2466B8C79FC297AD3DBD043AAC69AB31577608E2D3FC7F59C5
+CT=3B104547D2D620879E3CB2B5774C0FB4
+PT=B667F7544FE49A07611A160E3312F69A
+
+I=153
+KEY=9BC6C18805144F98CAEA7B252B3EE2930B63CDF8264FAB501712F4DDCF6DAF5F
+CT=B667F7544FE49A07611A160E3312F69A
+PT=C3E928FDEB5D7DDF7CF32C4DBCFE32F3
+
+I=154
+KEY=2BC00DF6D26F9A968C3BFF47AE761718C88AE505CD12D68F6BE1D89073939DAC
+CT=C3E928FDEB5D7DDF7CF32C4DBCFE32F3
+PT=72A9CF7AA2EDAF1907D77D10A02A45DE
+
+I=155
+KEY=15A0EE054E2D5E7EDCF3FC766860ACCDBA232A7F6FFF79966C36A580D3B9D872
+CT=72A9CF7AA2EDAF1907D77D10A02A45DE
+PT=97ABFAAD506940F88FDC8F55AD7EA919
+
+I=156
+KEY=C56C11F3A96852119C16751963C24CD42D88D0D23F96396EE3EA2AD57EC7716B
+CT=97ABFAAD506940F88FDC8F55AD7EA919
+PT=DD55A02B1EB01EB091CA6337D0BEB5BD
+
+I=157
+KEY=8634CC7B3416FCE337AAFA39791D1545F0DD70F9212627DE722049E2AE79C4D6
+CT=DD55A02B1EB01EB091CA6337D0BEB5BD
+PT=C5EB3DF5A328B267F3895CECD4A828AF
+
+I=158
+KEY=DDC1361E1432CCAC3551E2478A321A0035364D0C820E95B981A9150E7AD1EC79
+CT=C5EB3DF5A328B267F3895CECD4A828AF
+PT=49952DACD97FD5583A7D9C4FF515EC17
+
+I=159
+KEY=52658EEC2A7441D866CFA15944BB12857CA360A05B7140E1BBD489418FC4006E
+CT=49952DACD97FD5583A7D9C4FF515EC17
+PT=4971EEEF871E935AC470BD770802B04B
+
+I=160
+KEY=05FC7A181B1935EA8DCEC961B0DFC14B35D28E4FDC6FD3BB7FA4343687C6B025
+CT=4971EEEF871E935AC470BD770802B04B
+PT=3DB5E9165C24EC3790DC3E53E5E5D2DE
+
+I=161
+KEY=8D2793B7BDCF80338AA39C86008361BC08676759804B3F8CEF780A65622362FB
+CT=3DB5E9165C24EC3790DC3E53E5E5D2DE
+PT=1FDB5D4FBB59F082B3B617C8A23734F1
+
+I=162
+KEY=37BE37961B77866869826907BB9E9C1717BC3A163B12CF0E5CCE1DADC014560A
+CT=1FDB5D4FBB59F082B3B617C8A23734F1
+PT=8C59775AD3FF7C337B22C8E785321E25
+
+I=163
+KEY=F3184EA1C8FFE3D436BEE076AA999B659BE54D4CE8EDB33D27ECD54A4526482F
+CT=8C59775AD3FF7C337B22C8E785321E25
+PT=0CB834FCC0CFDAECAF4AFC5A2E38DF23
+
+I=164
+KEY=CACF50D99B066EB84CBFAEEC9B0D6769975D79B0282269D188A629106B1E970C
+CT=0CB834FCC0CFDAECAF4AFC5A2E38DF23
+PT=229EB7B6A97D91921BCD8C95A0D7C17B
+
+I=165
+KEY=3FA80E4FB785B9FC3B058CC62D289958B5C3CE06815FF843936BA585CBC95677
+CT=229EB7B6A97D91921BCD8C95A0D7C17B
+PT=0D7692C281DD4FF35D9B1620E1385C34
+
+I=166
+KEY=CE2A3A893C96A4F1AA81AD52EBCC3C23B8B55CC40082B7B0CEF0B3A52AF10A43
+CT=0D7692C281DD4FF35D9B1620E1385C34
+PT=D3C5FE594F5C8C5A359235448EB20146
+
+I=167
+KEY=FC8642DB8CB42D1B1251CB7FE6AFF90D6B70A29D4FDE3BEAFB6286E1A4430B05
+CT=D3C5FE594F5C8C5A359235448EB20146
+PT=8C0F88460C700D96847249807B84223F
+
+I=168
+KEY=2A9C9FD184A5B2418FD415A228A5C0AFE77F2ADB43AE367C7F10CF61DFC7293A
+CT=8C0F88460C700D96847249807B84223F
+PT=5A4237A5C2DABDCDA6389D5FC66032F6
+
+I=169
+KEY=FDB533163E989D2FA32CCA5D3CC5D376BD3D1D7E81748BB1D928523E19A71BCC
+CT=5A4237A5C2DABDCDA6389D5FC66032F6
+PT=BF8AAC6B1536CCCCECCC9D6BE970EB3E
+
+I=170
+KEY=3C4B3CF0FD0C4292B2497175D4400F8902B7B1159442477D35E4CF55F0D7F0F2
+CT=BF8AAC6B1536CCCCECCC9D6BE970EB3E
+PT=97CE58407FD26D63C86765CB05EA6277
+
+I=171
+KEY=367862F3E2C5520EA2269392B6139E9C9579E955EB902A1EFD83AA9EF53D9285
+CT=97CE58407FD26D63C86765CB05EA6277
+PT=B411687B044B624077A92D8C130697B9
+
+I=172
+KEY=0300AF491DAF6C607417FB1FD9B1EC612168812EEFDB485E8A2A8712E63B053C
+CT=B411687B044B624077A92D8C130697B9
+PT=D22E92A5132EA85F4FB25EE19C248008
+
+I=173
+KEY=7C92EF49A7D27E97F1884299B635F0ADF346138BFCF5E001C598D9F37A1F8534
+CT=D22E92A5132EA85F4FB25EE19C248008
+PT=FD6817CD680A2A8CE93E4B4F9CAA72AA
+
+I=174
+KEY=80EABB1D8C9B5F769FCAC87ED8D0C9CA0E2E044694FFCA8D2CA692BCE6B5F79E
+CT=FD6817CD680A2A8CE93E4B4F9CAA72AA
+PT=8DDD9B3B9278D2DE3453EA6769E1C39C
+
+I=175
+KEY=FB345E2D7BBBED527259FAEAEA79C05D83F39F7D0687185318F578DB8F543402
+CT=8DDD9B3B9278D2DE3453EA6769E1C39C
+PT=AE69F5CD8D342E74113E979ACE3539F2
+
+I=176
+KEY=7D93DC33FF2266770291160CD317C65E2D9A6AB08BB3362709CBEF4141610DF0
+CT=AE69F5CD8D342E74113E979ACE3539F2
+PT=30E19A4E84997172486DAE4FB4C41E58
+
+I=177
+KEY=82362FF3E9C1AD93474CF4CABD354E7E1D7BF0FE0F2A475541A6410EF5A513A8
+CT=30E19A4E84997172486DAE4FB4C41E58
+PT=75B3D07617EB189512DC5161908940C1
+
+I=178
+KEY=8EFD0FCB3855CCC16BD919FBD17596C768C8208818C15FC0537A106F652C5369
+CT=75B3D07617EB189512DC5161908940C1
+PT=FD13E89107FAFA44998721AD726C620F
+
+I=179
+KEY=2299D22282C798107F489637DCD479C395DBC8191F3BA584CAFD31C217403166
+CT=FD13E89107FAFA44998721AD726C620F
+PT=C1B0210C0387864717BD7D02063B6A69
+
+I=180
+KEY=75E05597A2BBDF23E5BD172C83548C9B546BE9151CBC23C3DD404CC0117B5B0F
+CT=C1B0210C0387864717BD7D02063B6A69
+PT=0E442B38E9024CCA5DC43A7B8D5F6FCF
+
+I=181
+KEY=4DBC8DCB8C25B5F4AD374BA3064216555A2FC22DF5BE6F09808476BB9C2434C0
+CT=0E442B38E9024CCA5DC43A7B8D5F6FCF
+PT=8FD213EC19D62FD2C19E6C91B97E56A0
+
+I=182
+KEY=E393BAD07E955EBC1446B847DE5A891ED5FDD1C1EC6840DB411A1A2A255A6260
+CT=8FD213EC19D62FD2C19E6C91B97E56A0
+PT=F52ADFD33A68EE198F33708E676D0CE9
+
+I=183
+KEY=3F33A76F87DB0388C2D66C7F2EFAA1B820D70E12D600AEC2CE296AA442376E89
+CT=F52ADFD33A68EE198F33708E676D0CE9
+PT=7649EB4283505EEEE1BE16DB6677B3F5
+
+I=184
+KEY=04BC65DE70C9E01EEEDA5A507C218C8D569EE5505550F02C2F977C7F2440DD7C
+CT=7649EB4283505EEEE1BE16DB6677B3F5
+PT=6FB1C4AD8A5B8A606621A8BF4277F3DC
+
+I=185
+KEY=8A6EF9710F4AE10EB60C8D25A8F67C50392F21FDDF0B7A4C49B6D4C066372EA0
+CT=6FB1C4AD8A5B8A606621A8BF4277F3DC
+PT=22C2CF9572D708F688291056E2F8E120
+
+I=186
+KEY=ED6D084D5F8AA4F201F9C20EA26A90E81BEDEE68ADDC72BAC19FC49684CFCF80
+CT=22C2CF9572D708F688291056E2F8E120
+PT=28AC7257911ECEB549D910BFA0905AE5
+
+I=187
+KEY=BA2735927D6A76B952C08A219FBB572233419C3F3CC2BC0F8846D429245F9565
+CT=28AC7257911ECEB549D910BFA0905AE5
+PT=2A1F3842DF988CDA0C6415450A657DB2
+
+I=188
+KEY=53BCC06CCCBC31A5BEE2CE88E6EAEFAC195EA47DE35A30D58422C16C2E3AE8D7
+CT=2A1F3842DF988CDA0C6415450A657DB2
+PT=6055EB3A24DE4D87C6BA5073A5BAC919
+
+I=189
+KEY=DF88C3CEC31C7B88D8AC0C7AAA2CED99790B4F47C7847D524298911F8B8021CE
+CT=6055EB3A24DE4D87C6BA5073A5BAC919
+PT=CC051CCD37068B41935FD14538DFEF82
+
+I=190
+KEY=265B351B93FF456D5A1EAADD2BEA1296B50E538AF082F613D1C7405AB35FCE4C
+CT=CC051CCD37068B41935FD14538DFEF82
+PT=225B63F455DD72EC87CF6FD5DF0FDAF3
+
+I=191
+KEY=BAC4C541E0A693CF8A3892A82F67CD959755307EA55F84FF56082F8F6C5014BF
+CT=225B63F455DD72EC87CF6FD5DF0FDAF3
+PT=64027F6B72F0A11628F66D5C502658E8
+
+I=192
+KEY=E8F68EF4909A128F331DFEFAE8560EBCF3574F15D7AF25E97EFE42D33C764C57
+CT=64027F6B72F0A11628F66D5C502658E8
+PT=529AAF9163EDA1BC39E66D2556BE938B
+
+I=193
+KEY=1951B1A50BED04096C17E816D4EC6225A1CDE084B442845547182FF66AC8DFDC
+CT=529AAF9163EDA1BC39E66D2556BE938B
+PT=F93E85D98EB9BDDD7D3844421235FBAB
+
+I=194
+KEY=D39AF070909FBC0E3226E28041B0286158F3655D3AFB39883A206BB478FD2477
+CT=F93E85D98EB9BDDD7D3844421235FBAB
+PT=16B6B3CC08003BA36C9E84B1EE9CD7CC
+
+I=195
+KEY=B705C6CCD010B980E386B8690C83E96C4E45D69132FB022B56BEEF059661F3BB
+CT=16B6B3CC08003BA36C9E84B1EE9CD7CC
+PT=301AFE66055149FA5775A9CE19F1FF63
+
+I=196
+KEY=B3C813D4FCBD31ED95E7E71CEC15153E7E5F28F737AA4BD101CB46CB8F900CD8
+CT=301AFE66055149FA5775A9CE19F1FF63
+PT=1090E68F7C8400861589E304A5B815CD
+
+I=197
+KEY=0EBC30ADB6946B6415C0309D636C79F46ECFCE784B2E4B571442A5CF2A281915
+CT=1090E68F7C8400861589E304A5B815CD
+PT=2778F0C712804C0B8D085B196A4D73C4
+
+I=198
+KEY=9C5815C6705B39DEECB8BDDDC9329A0D49B73EBF59AE075C994AFED640656AD1
+CT=2778F0C712804C0B8D085B196A4D73C4
+PT=14FECB137DC9C38A04D92B60A177A61D
+
+I=199
+KEY=9D83B41F8F415B5F3B2C08682383471B5D49F5AC2467C4D69D93D5B6E112CCCC
+CT=14FECB137DC9C38A04D92B60A177A61D
+PT=0EF1321EA52EAA7624E3F2EFD0C886AF
+
+I=200
+KEY=2960CEE0AF043ED1A549BA223F6C1CF153B8C7B281496EA0B970275931DA4A63
+CT=0EF1321EA52EAA7624E3F2EFD0C886AF
+PT=AFA8B2129577EC178B59D42D1B92D313
+
+I=201
+KEY=51E0DECF48A151021C70EC3EE3CE9008FC1075A0143E82B73229F3742A489970
+CT=AFA8B2129577EC178B59D42D1B92D313
+PT=3351631344E6EF86712327D3C05EBDEB
+
+I=202
+KEY=5F34A789B0B1185BA7D1BB3EF2677060CF4116B350D86D31430AD4A7EA16249B
+CT=3351631344E6EF86712327D3C05EBDEB
+PT=C299D0556B0D15014627CADBCCC3DC33
+
+I=203
+KEY=FC3E420F84F4C75802DCF68ABF0030E70DD8C6E63BD57830052D1E7C26D5F8A8
+CT=C299D0556B0D15014627CADBCCC3DC33
+PT=CEB83A2B9DD76B649BAAE48A8B772A5C
+
+I=204
+KEY=C04448AD77DBF33F22A2346C7A40F813C360FCCDA60213549E87FAF6ADA2D2F4
+CT=CEB83A2B9DD76B649BAAE48A8B772A5C
+PT=A8C6AEC94E82BC68AC8E29A8CB9504F6
+
+I=205
+KEY=3FA863ECC4AFA141DD7349C44F94FEE16BA65204E880AF3C3209D35E6637D602
+CT=A8C6AEC94E82BC68AC8E29A8CB9504F6
+PT=1EDED55C8D3309F828C17AF072C79D7A
+
+I=206
+KEY=8893E5FB27191AE09E4AB5F062289F117578875865B3A6C41AC8A9AE14F04B78
+CT=1EDED55C8D3309F828C17AF072C79D7A
+PT=FD2AC22891FB294EB0AD2BADFE759C29
+
+I=207
+KEY=90BA1205BB7927E86F9895855648D3EB88524570F4488F8AAA658203EA85D751
+CT=FD2AC22891FB294EB0AD2BADFE759C29
+PT=2FE6AE59ACD516EE1567A7A1C43FDE2A
+
+I=208
+KEY=278FD88834EA67564F301785C4045D6FA7B4EB29589D9964BF0225A22EBA097B
+CT=2FE6AE59ACD516EE1567A7A1C43FDE2A
+PT=35BEC13F159F61C7EF4C860AD3B41A75
+
+I=209
+KEY=E9D2F23C213D02724737A5E907BFBDF0920A2A164D02F8A3504EA3A8FD0E130E
+CT=35BEC13F159F61C7EF4C860AD3B41A75
+PT=650D65D6ED716DA515EAAF1A7447C3FB
+
+I=210
+KEY=4A0A997634E2D9305795FC90291F6FD9F7074FC0A073950645A40CB28949D0F5
+CT=650D65D6ED716DA515EAAF1A7447C3FB
+PT=7AFE0D2F234A6CDEDD7103DA09147285
+
+I=211
+KEY=BD671DD81F8FCD9D472564589AA13F5D8DF942EF8339F9D898D50F68805DA270
+CT=7AFE0D2F234A6CDEDD7103DA09147285
+PT=40627620B17313AF42EA7DD6CFD900F9
+
+I=212
+KEY=5668F777C46BF78DC664E72186626BF5CD9B34CF324AEA77DA3F72BE4F84A289
+CT=40627620B17313AF42EA7DD6CFD900F9
+PT=0C62985837C8C6FB468BD6E3928F8497
+
+I=213
+KEY=B82B5D4C3DEF62CFAE064CFDB5D904EFC1F9AC9705822C8C9CB4A45DDD0B261E
+CT=0C62985837C8C6FB468BD6E3928F8497
+PT=A1FFF4635AAF2AD8AE6EA8C70858EF3B
+
+I=214
+KEY=6A179EF63528EFA2B12DBA23D1EC8D21600658F45F2D065432DA0C9AD553C925
+CT=A1FFF4635AAF2AD8AE6EA8C70858EF3B
+PT=403F8E2D050E2976487BBEDD6466357E
+
+I=215
+KEY=6857720AC4DDCFFE8A96B455C973901A2039D6D95A232F227AA1B247B135FC5B
+CT=403F8E2D050E2976487BBEDD6466357E
+PT=2DD7EB8476988C850E8D95DC598FC61A
+
+I=216
+KEY=5B938E230BFE9056471E7C83A6ED03930DEE3D5D2CBBA3A7742C279BE8BA3A41
+CT=2DD7EB8476988C850E8D95DC598FC61A
+PT=676B96F400AE18138B302FD3D70D490E
+
+I=217
+KEY=4CE7ECA340DEC23715C53343EB9162DA6A85ABA92C15BBB4FF1C08483FB7734F
+CT=676B96F400AE18138B302FD3D70D490E
+PT=620AAA14B94BF6B60A83129085BCF02B
+
+I=218
+KEY=1024ECE618D140CAE8B9DFC8EB1DE137088F01BD955E4D02F59F1AD8BA0B8364
+CT=620AAA14B94BF6B60A83129085BCF02B
+PT=B701A38325DC282045C6F914394B9F70
+
+I=219
+KEY=6B8C6DA855E1E72E4A6AC44601B24D60BF8EA23EB0826522B059E3CC83401C14
+CT=B701A38325DC282045C6F914394B9F70
+PT=808D0B334B775C59F8C34A3524CB4126
+
+I=220
+KEY=C50A625A89465321DACCB9EB40DEF57D3F03A90DFBF5397B489AA9F9A78B5D32
+CT=808D0B334B775C59F8C34A3524CB4126
+PT=4E29C921CC295F6A3082C1BC02ACDA70
+
+I=221
+KEY=973341A4E3DB315FA97C7EEDF493EA71712A602C37DC661178186845A5278742
+CT=4E29C921CC295F6A3082C1BC02ACDA70
+PT=77BC204E50EFCA2AEBDC16D3F3C3D739
+
+I=222
+KEY=639EB8FB16B34B55550705FDCFF7C8CC069640626733AC3B93C47E9656E4507B
+CT=77BC204E50EFCA2AEBDC16D3F3C3D739
+PT=A677A7B55AA03EB0587EE00123D047F3
+
+I=223
+KEY=610A9602B725E4D87AB2904E91050D90A0E1E7D73D93928BCBBA9E9775341788
+CT=A677A7B55AA03EB0587EE00123D047F3
+PT=09AF5421548AC11466370484F8C556DE
+
+I=224
+KEY=314A6E0BD202458489059738917B6678A94EB3F66919539FAD8D9A138DF14156
+CT=09AF5421548AC11466370484F8C556DE
+PT=B6CDD2336AB8735EE7A9946A1FE7EE0C
+
+I=225
+KEY=73658C0F88490F7C3B9F2B7B39551BBF1F8361C503A120C14A240E799216AF5A
+CT=B6CDD2336AB8735EE7A9946A1FE7EE0C
+PT=B5A2F3B47E4AC87BC06612587253930E
+
+I=226
+KEY=968794DEC3E866DE4F999C860E9851E9AA2192717DEBE8BA8A421C21E0453C54
+CT=B5A2F3B47E4AC87BC06612587253930E
+PT=09C9C38BB3348147EB284FFA24D87244
+
+I=227
+KEY=205605E66A4BE2CF61E13243E104FED9A3E851FACEDF69FD616A53DBC49D4E10
+CT=09C9C38BB3348147EB284FFA24D87244
+PT=9D1EDCA2674E5A30416DF7CC2938DC63
+
+I=228
+KEY=9CA7508C83DB6E56EFF3489F2BD30C573EF68D58A99133CD2007A417EDA59273
+CT=9D1EDCA2674E5A30416DF7CC2938DC63
+PT=E8A2282B47DAB6A666A4607BBC857FC6
+
+I=229
+KEY=0F98884E85FEB533CFC281C2F4437915D654A573EE4B856B46A3C46C5120EDB5
+CT=E8A2282B47DAB6A666A4607BBC857FC6
+PT=B6675D2263DC1C1E0F04A9A9BC666D2D
+
+I=230
+KEY=3F3ED6DC6E08DF2515D08273832429286033F8518D97997549A76DC5ED468098
+CT=B6675D2263DC1C1E0F04A9A9BC666D2D
+PT=D6FF2642FD84C80674EAF8674242248D
+
+I=231
+KEY=67910C06B57CD52767674B70F59337D8B6CCDE13701351733D4D95A2AF04A415
+CT=D6FF2642FD84C80674EAF8674242248D
+PT=47D4419A669253C39A0CC96C7CD612C0
+
+I=232
+KEY=43EE254E414DB89044EE2F703B340F6AF1189F89168102B0A7415CCED3D2B6D5
+CT=47D4419A669253C39A0CC96C7CD612C0
+PT=B2B3FD7A1D4B0695B3499430F2E44CEA
+
+I=233
+KEY=89C9881E6D6CEFF00DDFC5618655FA4543AB62F30BCA04251408C8FE2136FA3F
+CT=B2B3FD7A1D4B0695B3499430F2E44CEA
+PT=4AAD0AE20AFF0675CF78992DFD2B685C
+
+I=234
+KEY=2C24846D047677F89EF73B917962D0FA0906681101350250DB7051D3DC1D9263
+CT=4AAD0AE20AFF0675CF78992DFD2B685C
+PT=C90343412CFE70201CE22D9AD2222788
+
+I=235
+KEY=770637F8F8F32915BF7630919D0726AEC0052B502DCB7270C7927C490E3FB5EB
+CT=C90343412CFE70201CE22D9AD2222788
+PT=923FE89134FAF362802C5A2EBF399D2C
+
+I=236
+KEY=426891CF6B068FAC7FFB5A04874AEC78523AC3C11931811247BE2667B10628C7
+CT=923FE89134FAF362802C5A2EBF399D2C
+PT=9C08F05026196BA3550A2496049B720B
+
+I=237
+KEY=B66BCCA5EFAF3F448BDD52DC48F2B904CE3233913F28EAB112B402F1B59D5ACC
+CT=9C08F05026196BA3550A2496049B720B
+PT=7B487FD67D0C2D987C3DEFD335C2EF17
+
+I=238
+KEY=079CCBC13FCFB0D032293FDFEC563F86B57A4C474224C7296E89ED22805FB5DB
+CT=7B487FD67D0C2D987C3DEFD335C2EF17
+PT=CEC12158856704CE8ABF0CA6C6F3006B
+
+I=239
+KEY=998AFEF458902CA632D60843A88D36637BBB6D1FC743C3E7E436E18446ACB5B0
+CT=CEC12158856704CE8ABF0CA6C6F3006B
+PT=DA19C7C7283ADD9C5145ABBA53F1E7E1
+
+I=240
+KEY=95EDAF196289EE6D24AA752DF489DEFCA1A2AAD8EF791E7BB5734A3E155D5251
+CT=DA19C7C7283ADD9C5145ABBA53F1E7E1
+PT=F043A57E686C1FE7DACB858F0C3E6857
+
+I=241
+KEY=3050D2C04C0860414427BF5B19792D7651E10FA68715019C6FB8CFB119633A06
+CT=F043A57E686C1FE7DACB858F0C3E6857
+PT=2FB7B264BB4B3FAFA01A6BB93CC2958D
+
+I=242
+KEY=26186DD7BE83659550BA3B52D99975037E56BDC23C5E3E33CFA2A40825A1AF8B
+CT=2FB7B264BB4B3FAFA01A6BB93CC2958D
+PT=D46BBD3ABD958DA722F3591578C30F5E
+
+I=243
+KEY=DE1D625B9C840580FDDE57EDE82419D1AA3D00F881CBB394ED51FD1D5D62A0D5
+CT=D46BBD3ABD958DA722F3591578C30F5E
+PT=3D69379AB60535902C38AB5E121DD035
+
+I=244
+KEY=FF9396CB65FFB9D47EF4E0253FD98BBA9754376237CE8604C16956434F7F70E0
+CT=3D69379AB60535902C38AB5E121DD035
+PT=A5767F4E6C8482290BC7B76D23EEF145
+
+I=245
+KEY=B98B5F1CA9752B1B07514B72C3D585F23222482C5B4A042DCAAEE12E6C9181A5
+CT=A5767F4E6C8482290BC7B76D23EEF145
+PT=9388736A82C99337C49BB4F32437B1DA
+
+I=246
+KEY=5F130919FB4ED29397E4781550B1D444A1AA3B46D983971A0E3555DD48A6307F
+CT=9388736A82C99337C49BB4F32437B1DA
+PT=915C6C5181E797DADC289F8FFF60CD19
+
+I=247
+KEY=D3F202F140D38545C8A04EC2D0993E2B30F65717586400C0D21DCA52B7C6FD66
+CT=915C6C5181E797DADC289F8FFF60CD19
+PT=A61167CDBE95ABFAD9C1A58BDA90F0D4
+
+I=248
+KEY=FBFA83B249C3B13C83E8FC111611391296E730DAE6F1AB3A0BDC6FD96D560DB2
+CT=A61167CDBE95ABFAD9C1A58BDA90F0D4
+PT=9AF2B4CF00B037976D0F5CAC4201885D
+
+I=249
+KEY=CC24CC54D0889912C7AD2473EBA8BBB30C158415E6419CAD66D333752F5785EF
+CT=9AF2B4CF00B037976D0F5CAC4201885D
+PT=A9B74046119B6699FD5EFD1E476BEE64
+
+I=250
+KEY=F520F18D9FACA98E5F57226127FA9B6BA5A2C453F7DAFA349B8DCE6B683C6B8B
+CT=A9B74046119B6699FD5EFD1E476BEE64
+PT=CD7EAA1EF3B91B69FD3E54FCC5A802E9
+
+I=251
+KEY=9BFD59A9F78FB1BE6F13B701D7EB0F6268DC6E4D0463E15D66B39A97AD946962
+CT=CD7EAA1EF3B91B69FD3E54FCC5A802E9
+PT=FD7095C419E2722425E6D4CA1A393D8C
+
+I=252
+KEY=C1C39AC5158C8CDBE82CF37D00B7896995ACFB891D81937943554E5DB7AD54EE
+CT=FD7095C419E2722425E6D4CA1A393D8C
+PT=9963CE47EB0322135C5D20B923FC341A
+
+I=253
+KEY=C9E26AE18D08643029C92F11BD3E8AA40CCF35CEF682B16A1F086EE4945160F4
+CT=9963CE47EB0322135C5D20B923FC341A
+PT=11589A1BDD037FABABBB9BF5AAC859A7
+
+I=254
+KEY=2183FF3C1EB1DF48DB8FA5F87F279F891D97AFD52B81CEC1B4B3F5113E993953
+CT=11589A1BDD037FABABBB9BF5AAC859A7
+PT=B6CEE1CD709BE6E055041FC2E1A87539
+
+I=255
+KEY=738690954B4B92CE2367567B3A960E8DAB594E185B1A2821E1B7EAD3DF314C6A
+CT=B6CEE1CD709BE6E055041FC2E1A87539
+PT=D776658F01CCEC460FA7145C6C6CBD42
+
+I=256
+KEY=71AB2DBD9923F08E516D8DF0CF57CC227C2F2B975AD6C467EE10FE8FB35DF128
+CT=D776658F01CCEC460FA7145C6C6CBD42
+PT=0C6D2578060A0A1024230D838AA45234
+
+I=257
+KEY=1C0E18C83D74E46DDF65BFC3335CFF0D70420EEF5CDCCE77CA33F30C39F9A31C
+CT=0C6D2578060A0A1024230D838AA45234
+PT=BFD55D67EF4883200FDAEEA5D44F0302
+
+I=258
+KEY=7DA814BD80D8CBBEE778E030682E7F34CF975388B3944D57C5E91DA9EDB6A01E
+CT=BFD55D67EF4883200FDAEEA5D44F0302
+PT=E821629542650FAFEF08D94AC889078A
+
+I=259
+KEY=10490CD6F16D915CE9891C69E10884D827B6311DF1F142F82AE1C4E3253FA794
+CT=E821629542650FAFEF08D94AC889078A
+PT=F2F81CD9CBD3E932686B6195A97EE13A
+
+I=260
+KEY=F0114F7C7101931F6A4595A6C3D2F34AD54E2DC43A22ABCA428AA5768C4146AE
+CT=F2F81CD9CBD3E932686B6195A97EE13A
+PT=C90348C14450EE3D9BFA30377D4B2440
+
+I=261
+KEY=C5802B19BA4921D3750A590F02658F621C4D65057E7245F7D9709541F10A62EE
+CT=C90348C14450EE3D9BFA30377D4B2440
+PT=619E907C4E7FD3A723E34B8D3880D71B
+
+I=262
+KEY=236500CE70AC49E98907DC4EDAE41CCA7DD3F579300D9650FA93DECCC98AB5F5
+CT=619E907C4E7FD3A723E34B8D3880D71B
+PT=932A17E8FDA853F6DB1C9271EC4FBF56
+
+I=263
+KEY=7BB7D14473E7E2D70F3C8C90D4B1035CEEF9E291CDA5C5A6218F4CBD25C50AA3
+CT=932A17E8FDA853F6DB1C9271EC4FBF56
+PT=549CB80C490E592E18ACC04FAA933489
+
+I=264
+KEY=415AD8391B32F6E61A861B4C8A4BBC6DBA655A9D84AB9C8839238CF28F563E2A
+CT=549CB80C490E592E18ACC04FAA933489
+PT=BF6337BEDE116D5A60B06DA8B270159C
+
+I=265
+KEY=058F24C125EB3E94B54BB6F1F099501C05066D235ABAF1D25993E15A3D262BB6
+CT=BF6337BEDE116D5A60B06DA8B270159C
+PT=CBD3D52496E6DF0DBD065BD924C5001F
+
+I=266
+KEY=B85B96EC639098C392FD33D11A49251ECED5B807CC5C2EDFE495BA8319E32BA9
+CT=CBD3D52496E6DF0DBD065BD924C5001F
+PT=AF8879C67DF265E118096478FBA003AD
+
+I=267
+KEY=526BF9DCAF4A4DFD05FAD0EA3B58131D615DC1C1B1AE4B3EFC9CDEFBE2432804
+CT=AF8879C67DF265E118096478FBA003AD
+PT=C627176029E2D22A51F5630B129A1095
+
+I=268
+KEY=553316781F120EE83A2D083D97D19F99A77AD6A1984C9914AD69BDF0F0D93891
+CT=C627176029E2D22A51F5630B129A1095
+PT=F46AC5870C65636D6C200312F2A15BE6
+
+I=269
+KEY=E9A37578C1402447D6CC1161F126D5C7531013269429FA79C149BEE202786377
+CT=F46AC5870C65636D6C200312F2A15BE6
+PT=4FBBFF3856FC0DEC7EE18585FFA4AC16
+
+I=270
+KEY=78521B42D0FBE8EA8BB6D44D66AE476D1CABEC1EC2D5F795BFA83B67FDDCCF61
+CT=4FBBFF3856FC0DEC7EE18585FFA4AC16
+PT=8711DAE7DD9B3F6D9FAD03669C1C8F5E
+
+I=271
+KEY=851C9A078620280FBCDDFB4FD3745C749BBA36F91F4EC8F82005380161C0403F
+CT=8711DAE7DD9B3F6D9FAD03669C1C8F5E
+PT=050E884136E09368DEFBC43F6B3182CC
+
+I=272
+KEY=50CCAA51D781B7090285D907E68B1F7A9EB4BEB829AE5B90FEFEFC3E0AF1C2F3
+CT=050E884136E09368DEFBC43F6B3182CC
+PT=CEC37197CEE3E0D797F441CC0541B851
+
+I=273
+KEY=DAB5ECB43982EAE8412102E2B7BC7CEA5077CF2FE74DBB47690ABDF20FB07AA2
+CT=CEC37197CEE3E0D797F441CC0541B851
+PT=197ECC091E5620DCA63BA2E6CFBC9F43
+
+I=274
+KEY=57974D1C4BBF761C9E09B8DAD3E510DF49090326F91B9B9BCF311F14C00CE5E1
+CT=197ECC091E5620DCA63BA2E6CFBC9F43
+PT=F2E836DEE9668E81D74A3C0F03CF3C10
+
+I=275
+KEY=E37677110C5A9A59EC06E0968BF5D14EBBE135F8107D151A187B231BC3C3D9F1
+CT=F2E836DEE9668E81D74A3C0F03CF3C10
+PT=DD581BB9F4A7BEC66CAC7916871F55C8
+
+I=276
+KEY=2CD760C245E62EA5B477BDA094B3AD5166B92E41E4DAABDC74D75A0D44DC8C39
+CT=DD581BB9F4A7BEC66CAC7916871F55C8
+PT=7B05D43A3BE733E0DE6E2CE494141B46
+
+I=277
+KEY=DE35BF6BC48E8B8E6A30DB886C9D75DD1DBCFA7BDF3D983CAAB976E9D0C8977F
+CT=7B05D43A3BE733E0DE6E2CE494141B46
+PT=1D561DCAA42E92568DD6ACD583FF7BCE
+
+I=278
+KEY=8AD7FCADA5D092DD5D221532EED3FD1000EAE7B17B130A6A276FDA3C5337ECB1
+CT=1D561DCAA42E92568DD6ACD583FF7BCE
+PT=1E9AB09A76FD91CC33B85390BDE631F8
+
+I=279
+KEY=534EEF6B1450693335980E00CD3CDE361E70572B0DEE9BA614D789ACEED1DD49
+CT=1E9AB09A76FD91CC33B85390BDE631F8
+PT=CBD0E3A07952EAC118A81B76D09276FD
+
+I=280
+KEY=8A39C2221622785E4DA9B14DAAE6ADF3D5A0B48B74BC71670C7F92DA3E43ABB4
+CT=CBD0E3A07952EAC118A81B76D09276FD
+PT=AC20057B857E6C34F7E68A5765573538
+
+I=281
+KEY=50887AD2D325CBC04B5FD69518318BAD7980B1F0F1C21D53FB99188D5B149E8C
+CT=AC20057B857E6C34F7E68A5765573538
+PT=DDFFD26BA5B33AEA36A0A6D75EAA047C
+
+I=282
+KEY=9613965C1776C5BAEA3CEE6154AABC9FA47F639B547127B9CD39BE5A05BE9AF0
+CT=DDFFD26BA5B33AEA36A0A6D75EAA047C
+PT=F0883B6DD3CA0515CB9F1ABA646CCB69
+
+I=283
+KEY=E7F6DB8A94597956CEE07447F9BB5CA454F758F687BB22AC06A6A4E061D25199
+CT=F0883B6DD3CA0515CB9F1ABA646CCB69
+PT=F4E27CA9E27B3E81B981298738C01FDA
+
+I=284
+KEY=0CB665943D6E6E32886A94C070366FB2A015245F65C01C2DBF278D6759124E43
+CT=F4E27CA9E27B3E81B981298738C01FDA
+PT=B03B2EB7A1E13E1A17C51FF5684E2A72
+
+I=285
+KEY=1EA698290E4B1D41B0CC4F3B9A9398FF102E0AE8C4212237A8E29292315C6431
+CT=B03B2EB7A1E13E1A17C51FF5684E2A72
+PT=BE133CCCE406C1C0BC1707115B5B0C84
+
+I=286
+KEY=BA38F49FA3D4A74ED41F8DA958A953C7AE3D36242027E3F714F595836A0768B5
+CT=BE133CCCE406C1C0BC1707115B5B0C84
+PT=A15B1C9BCF319AEF262E366C142A0DCF
+
+I=287
+KEY=935F2CEECBBCF3465DB9B0DB927AF4310F662ABFEF16791832DBA3EF7E2D657A
+CT=A15B1C9BCF319AEF262E366C142A0DCF
+PT=7A8DA23874D28EB75261D87D57451EAE
+
+I=288
+KEY=B8E67B884E3E229EBB516065499F790275EB88879BC4F7AF60BA7B9229687BD4
+CT=7A8DA23874D28EB75261D87D57451EAE
+PT=9331C989A7E291FD94BA4C945A79126E
+
+I=289
+KEY=CFB51BE6CDA499D66E7B36CAAC220FB7E6DA410E3C266652F4003706731169BA
+CT=9331C989A7E291FD94BA4C945A79126E
+PT=70A2F921A8BB0548D91A114478308448
+
+I=290
+KEY=19821B21FED0C1659AF4E16F49F63B699678B82F949D631A2D1A26420B21EDF2
+CT=70A2F921A8BB0548D91A114478308448
+PT=8ED8FC98045BA0EF9C15E9565EECE5BB
+
+I=291
+KEY=27DA5E31E794D670BDB701F361B8977018A044B790C6C3F5B10FCF1455CD0849
+CT=8ED8FC98045BA0EF9C15E9565EECE5BB
+PT=F6621989AFC0427E3E84039B6C6C2E75
+
+I=292
+KEY=64E8F7C4292DF7D0B01BED3FAE08DA4FEEC25D3E3F06818B8F8BCC8F39A1263C
+CT=F6621989AFC0427E3E84039B6C6C2E75
+PT=68F4804D1E8D383FAF4E76F80FB8F92B
+
+I=293
+KEY=EE626AFFE4997C11CAE2714FF96D84B18636DD73218BB9B420C5BA773619DF17
+CT=68F4804D1E8D383FAF4E76F80FB8F92B
+PT=2D61F123E2479D56AE5C327A57F6A28B
+
+I=294
+KEY=EA24B2DB953084C818B0E6F34BA1584DAB572C50C3CC24E28E99880D61EF7D9C
+CT=2D61F123E2479D56AE5C327A57F6A28B
+PT=C6CD16E7A122D105EE398E6C7F15B4EF
+
+I=295
+KEY=F209D1ADE0869F674F6FEDCD3DB7D2EB6D9A3AB762EEF5E760A006611EFAC973
+CT=C6CD16E7A122D105EE398E6C7F15B4EF
+PT=EDD6BBA5787DA2BF6A1ADF297DB98281
+
+I=296
+KEY=302BEB9AA2ACB3594D7E50859C187294804C81121A9357580ABAD94863434BF2
+CT=EDD6BBA5787DA2BF6A1ADF297DB98281
+PT=4A51E54F4F81469A06F6001F2F32F4AC
+
+I=297
+KEY=3270FC87B4DC04FDD3F20C01407BE123CA1D645D551211C20C4CD9574C71BF5E
+CT=4A51E54F4F81469A06F6001F2F32F4AC
+PT=F7A2303EA59907BCC32AA4FC5A6DE448
+
+I=298
+KEY=C85326465BF46A442BC1E544F9041C4A3DBF5463F08B167ECF667DAB161C5B16
+CT=F7A2303EA59907BCC32AA4FC5A6DE448
+PT=2274E43F9F8A7081DF74D5225EC28AD8
+
+I=299
+KEY=A54E889A4D9FFBF993C53A9DD3B951391FCBB05C6F0166FF1012A88948DED1CE
+CT=2274E43F9F8A7081DF74D5225EC28AD8
+PT=0C8358EC431313223B59126BDBB36571
+
+I=300
+KEY=FA14699C20CFFE7DB68786E6117F95851348E8B02C1275DD2B4BBAE2936DB4BF
+CT=0C8358EC431313223B59126BDBB36571
+PT=03237A81EEA2EAFBB5AC0B3E635CC1AC
+
+I=301
+KEY=B3744022A5397A735A4271261A2C96DF106B9231C2B09F269EE7B1DCF0317513
+CT=03237A81EEA2EAFBB5AC0B3E635CC1AC
+PT=409EBF7DF31FD9557118B1B5CAB5EBE3
+
+I=302
+KEY=8C7A22A934DCBC5E084E472DBAE4848350F52D4C31AF4673EFFF00693A849EF0
+CT=409EBF7DF31FD9557118B1B5CAB5EBE3
+PT=6CF5C9CF4A62C668B6481F7A12EE43DB
+
+I=303
+KEY=DB0497ED308C95BC9703265174B654D23C00E4837BCD801B59B71F13286ADD2B
+CT=6CF5C9CF4A62C668B6481F7A12EE43DB
+PT=D8A84E93CFF3EB9DC891333BDA5F3560
+
+I=304
+KEY=7A88D30D4CC9AB8EFA76139B68F0028AE4A8AA10B43E6B8691262C28F235E84B
+CT=D8A84E93CFF3EB9DC891333BDA5F3560
+PT=009E0C2454E321326336CC56D0660F91
+
+I=305
+KEY=55A78B8839B395B552630641648DFCE5E436A634E0DD4AB4F210E07E2253E7DA
+CT=009E0C2454E321326336CC56D0660F91
+PT=EBC89334F29560D9B9AEAE2F1D9DC65B
+
+I=306
+KEY=B41A907C82EDE32C6C1FD0DFED0A232D0FFE350012482A6D4BBE4E513FCE2181
+CT=EBC89334F29560D9B9AEAE2F1D9DC65B
+PT=4DA63E94EBB4DA255800C9B25068E47E
+
+I=307
+KEY=3E428E8A77067008EFDE7BD6174B05B742580B94F9FCF04813BE87E36FA6C5FF
+CT=4DA63E94EBB4DA255800C9B25068E47E
+PT=6833E2CEFA8CF4B5B4607FA49D7B658D
+
+I=308
+KEY=39D17AE8C7232386F8339427E4A79AAC2A6BE95A037004FDA7DEF847F2DDA072
+CT=6833E2CEFA8CF4B5B4607FA49D7B658D
+PT=41D882B653BEFEEEB9AE354F5ABCC058
+
+I=309
+KEY=E8D52C97FA4149312A45D3EFE0A326086BB36BEC50CEFA131E70CD08A861602A
+CT=41D882B653BEFEEEB9AE354F5ABCC058
+PT=D54A329BCF56B703BE0F02EE3AACB933
+
+I=310
+KEY=D36FAED6CF436A491111890449BC3C66BEF959779F984D10A07FCFE692CDD919
+CT=D54A329BCF56B703BE0F02EE3AACB933
+PT=5FAAEB95E0F9D0C3C43BF725DADC9595
+
+I=311
+KEY=9D7BCBB15816A0A941BBB787D2EEA155E153B2E27F619DD3644438C348114C8C
+CT=5FAAEB95E0F9D0C3C43BF725DADC9595
+PT=BC699D5E82FD43B45A7B925E8C1A2F3C
+
+I=312
+KEY=F2EB78917ECAC2E77C19B892E846AE715D3A2FBCFD9CDE673E3FAA9DC40B63B0
+CT=BC699D5E82FD43B45A7B925E8C1A2F3C
+PT=773D115B40F0E9EF780B2D10846FA684
+
+I=313
+KEY=B10B9F0CECA554749EC178F3C63547DD2A073EE7BD6C37884634878D4064C534
+CT=773D115B40F0E9EF780B2D10846FA684
+PT=50095809CC96520EB8E3A66F499EE147
+
+I=314
+KEY=E86E52AEB04DE0D3DC85A91E9B10D2677A0E66EE71FA6586FED721E209FA2473
+CT=50095809CC96520EB8E3A66F499EE147
+PT=6994CF8BA4C731CA33DAFE33D2A0BF94
+
+I=315
+KEY=44C3C8A2F0F931926AC73F3E5351B114139AA965D53D544CCD0DDFD1DB5A9BE7
+CT=6994CF8BA4C731CA33DAFE33D2A0BF94
+PT=981902A8FD71DF8B67D52E6FC2813B90
+
+I=316
+KEY=2D309D3D2603EC7E7B4EA626E9BDECFE8B83ABCD284C8BC7AAD8F1BE19DBA077
+CT=981902A8FD71DF8B67D52E6FC2813B90
+PT=35FA9A93AE142F562E62771991752B78
+
+I=317
+KEY=E80939BCB4DB83768EBAD3CF2DD3F270BE79315E8658A49184BA86A788AE8B0F
+CT=35FA9A93AE142F562E62771991752B78
+PT=A3651DBF8585004F0729AF4CA615C674
+
+I=318
+KEY=BF1A4C57D4434FA59A2E45DB589AA16F1D1C2CE103DDA4DE839329EB2EBB4D7B
+CT=A3651DBF8585004F0729AF4CA615C674
+PT=AF31F082CACEB768627B93A4D3E5349A
+
+I=319
+KEY=6EB47730BACAAB2207A3D12B0652B0CDB22DDC63C91313B6E1E8BA4FFD5E79E1
+CT=AF31F082CACEB768627B93A4D3E5349A
+PT=57B75D2B640F45DB2D4A1F71F08545A5
+
+I=320
+KEY=3EB0F3D31E648E260FE9F6FA8812ADD1E59A8148AD1C566DCCA2A53E0DDB3C44
+CT=57B75D2B640F45DB2D4A1F71F08545A5
+PT=A812DA38D7B82DF310366FA62FFD11E6
+
+I=321
+KEY=0409A87F024E710C27E456CA170B60184D885B707AA47B9EDC94CA9822262DA2
+CT=A812DA38D7B82DF310366FA62FFD11E6
+PT=447F235914368F2BECD5FF98D1A34205
+
+I=322
+KEY=7DE3A1E7234BF755908324E13DF413EB09F778296E92F4B530413500F3856FA7
+CT=447F235914368F2BECD5FF98D1A34205
+PT=5205860E4562B5CD6748EF89BF2791E9
+
+I=323
+KEY=12EE9519335A2D827649D4EB047EB5255BF2FE272BF041785709DA894CA2FE4E
+CT=5205860E4562B5CD6748EF89BF2791E9
+PT=30C0229AFDFF59E24426ACAD8D4AEFDB
+
+I=324
+KEY=78FF32A055D51E0A9D6E77D838AE72AD6B32DCBDD60F189A132F7624C1E81195
+CT=30C0229AFDFF59E24426ACAD8D4AEFDB
+PT=FF467C6E0F82F5D2F9487DDBDB43EFB3
+
+I=325
+KEY=6E49FA4CDEFC70619F739B488DD434969474A0D3D98DED48EA670BFF1AABFE26
+CT=FF467C6E0F82F5D2F9487DDBDB43EFB3
+PT=7E375B3D13871B09CA4D3357AC5EBB0E
+
+I=326
+KEY=90791666C996FF15EED1E20BAFB6B4B3EA43FBEECA0AF641202A38A8B6F54528
+CT=7E375B3D13871B09CA4D3357AC5EBB0E
+PT=E64A319F6FBD96BD799760C4077F9713
+
+I=327
+KEY=7F0D0CAB938585CF65726A6CB01DE8B00C09CA71A5B760FC59BD586CB18AD23B
+CT=E64A319F6FBD96BD799760C4077F9713
+PT=1487C8488C675BD46FAF2EEC0BC7AE7E
+
+I=328
+KEY=7B429E6D59D4D65E16ED325F49E93D9C188E023929D03B2836127680BA4D7C45
+CT=1487C8488C675BD46FAF2EEC0BC7AE7E
+PT=1F103E64A4F5239C9157E70487C50941
+
+I=329
+KEY=AF20B02C3C5BD4E33E34359B86BBF2CF079E3C5D8D2518B4A74591843D887504
+CT=1F103E64A4F5239C9157E70487C50941
+PT=24C8481DD1A2245735597A18A2433E41
+
+I=330
+KEY=E4F3CE6AFF9926837BAAB04C311F72A7235674405C873CE3921CEB9C9FCB4B45
+CT=24C8481DD1A2245735597A18A2433E41
+PT=3D9E715A686DE9AF8EE37AF54F82AA8A
+
+I=331
+KEY=A9BACBEC55AA453A83FF82CFDDB7F2F91EC8051A34EAD54C1CFF9169D049E1CF
+CT=3D9E715A686DE9AF8EE37AF54F82AA8A
+PT=B330735D9AB5B96501CDAF61A8EAD19F
+
+I=332
+KEY=5826BE9127DB557D401AF4DE6343F8AFADF87647AE5F6C291D323E0878A33050
+CT=B330735D9AB5B96501CDAF61A8EAD19F
+PT=61AE40475EA11DBCC364F5377673CE37
+
+I=333
+KEY=A8F0146E46A5391D0663380DF9F1FD6FCC563600F0FE7195DE56CB3F0ED0FE67
+CT=61AE40475EA11DBCC364F5377673CE37
+PT=525C1ED538B23D7CFA4A43114CF35BD4
+
+I=334
+KEY=20F90A51E7A0BB9B88AE1DD28C8B484A9E0A28D5C84C4CE9241C882E4223A5B3
+CT=525C1ED538B23D7CFA4A43114CF35BD4
+PT=C2957E002E35236D455F53006495E4B7
+
+I=335
+KEY=A71CC695B7AEB0D5148FA622536669385C9F56D5E6796F846143DB2E26B64104
+CT=C2957E002E35236D455F53006495E4B7
+PT=76F9C97A4B414E5DE532082BB12F5362
+
+I=336
+KEY=617CF5726F26BD9A3B52FC0D902A97AD2A669FAFAD3821D98471D30597991266
+CT=76F9C97A4B414E5DE532082BB12F5362
+PT=F4D9E814D4C61B2FB1D7CDCCBAF14AA1
+
+I=337
+KEY=D4DBBCC269A61933E4D63C3BDA5F522EDEBF77BB79FE3AF635A61EC92D6858C7
+CT=F4D9E814D4C61B2FB1D7CDCCBAF14AA1
+PT=6B51AF38B42F226D62474A97BD001FFF
+
+I=338
+KEY=512FAF06A5885D032A885EC030AF3C18B5EED883CDD1189B57E1545E90684738
+CT=6B51AF38B42F226D62474A97BD001FFF
+PT=868C58D6B805CF8F9EB04A8BA123371A
+
+I=339
+KEY=BDD2CB78E9B554FC7FEEEC05D02309F23362805575D4D714C9511ED5314B7022
+CT=868C58D6B805CF8F9EB04A8BA123371A
+PT=1752558A1F90975140CA41F68BE5333F
+
+I=340
+KEY=15CC46826BFD5B45ABAE9B0B2756D39C2430D5DF6A444045899B5F23BAAE431D
+CT=1752558A1F90975140CA41F68BE5333F
+PT=68801EAB4042E7390E64AA53C38C1D15
+
+I=341
+KEY=DF5FB425C5B25E15EA717736D8ABE6644CB0CB742A06A77C87FFF57079225E08
+CT=68801EAB4042E7390E64AA53C38C1D15
+PT=02FE87211909D8954EC90EF53100F26D
+
+I=342
+KEY=CD73FCED5EBA6038DD8B8A000111BEF94E4E4C55330F7FE9C936FB854822AC65
+CT=02FE87211909D8954EC90EF53100F26D
+PT=3A51FAFD22A2CC95B532023A37BBF0FE
+
+I=343
+KEY=EF890ED47D9F1581CC98C88F3BF7F88D741FB6A811ADB37C7C04F9BF7F995C9B
+CT=3A51FAFD22A2CC95B532023A37BBF0FE
+PT=D233A6BBC315BA5F4630AE7F99F77116
+
+I=344
+KEY=AA9CA1A7DFA24E1936E49D34054F7749A62C1013D2B809233A3457C0E66E2D8D
+CT=D233A6BBC315BA5F4630AE7F99F77116
+PT=E6B9619D7B0E1DF6CFE79FD51533406B
+
+I=345
+KEY=ADC4161B346687F98D4CB5B661662A8A4095718EA9B614D5F5D3C815F35D6DE6
+CT=E6B9619D7B0E1DF6CFE79FD51533406B
+PT=A746D31BCB29F7512E3F6E5EFD14FDAD
+
+I=346
+KEY=9C1CA3776C9ED13D220453C8AEFA0ECDE7D3A295629FE384DBECA64B0E49904B
+CT=A746D31BCB29F7512E3F6E5EFD14FDAD
+PT=B2489A51878848EC37E6782FB2110122
+
+I=347
+KEY=B64A5B45ABFDEC3EF8164FCEAE89919E559B38C4E517AB68EC0ADE64BC589169
+CT=B2489A51878848EC37E6782FB2110122
+PT=EF77F9367A063FDB874C9FC96983EAD1
+
+I=348
+KEY=AEFFDEE2501961FEEB985134E2B651EDBAECC1F29F1194B36B4641ADD5DB7BB8
+CT=EF77F9367A063FDB874C9FC96983EAD1
+PT=4ECFF4DA51BB2BE1EF8E85C4BBE51C69
+
+I=349
+KEY=6B28BA96CEB25B3862F413A2CBED4889F4233528CEAABF5284C8C4696E3E67D1
+CT=4ECFF4DA51BB2BE1EF8E85C4BBE51C69
+PT=0CAEAF484505A1AF13BB0ADCC665F91C
+
+I=350
+KEY=2062889724A47DD541F1F0A3FC8C5952F88D9A608BAF1EFD9773CEB5A85B9ECD
+CT=0CAEAF484505A1AF13BB0ADCC665F91C
+PT=6C75CA469CACCCE29CAE88202E02727C
+
+I=351
+KEY=C2115A8A6EE164B944A8C8128EBAB8E694F850261703D21F0BDD46958659ECB1
+CT=6C75CA469CACCCE29CAE88202E02727C
+PT=567060CEFF3AEDDE8AB5823450E35967
+
+I=352
+KEY=C3D2704E15936C6916073E234D0012CCC28830E8E8393FC18168C4A1D6BAB5D6
+CT=567060CEFF3AEDDE8AB5823450E35967
+PT=E04F927E409060080EC530D5C344CA24
+
+I=353
+KEY=49173A9FB3283181B71264E3FB5591FA22C7A296A8A95FC98FADF47415FE7FF2
+CT=E04F927E409060080EC530D5C344CA24
+PT=4D473408396C17D4BA3DBB63B46E7727
+
+I=354
+KEY=8BF3DDDC9217496E29F46E61233D62B66F80969E91C5481D35904F17A19008D5
+CT=4D473408396C17D4BA3DBB63B46E7727
+PT=BB6779933AC9E435C637CDA146A04284
+
+I=355
+KEY=6ACA3C31248BFBB5BB9FD54C4B31BC21D4E7EF0DAB0CAC28F3A782B6E7304A51
+CT=BB6779933AC9E435C637CDA146A04284
+PT=5C2129A55114540ED68591C60E45D6CF
+
+I=356
+KEY=1A270DAD402DC752332671216A6C3BFF88C6C6A8FA18F82625221370E9759C9E
+CT=5C2129A55114540ED68591C60E45D6CF
+PT=57790B87F69BF1C007E563A82987EEAE
+
+I=357
+KEY=6E39E75268AC2C51ABE11CE3CE16CAF3DFBFCD2F0C8309E622C770D8C0F27230
+CT=57790B87F69BF1C007E563A82987EEAE
+PT=58790B192C8B90B76F34990E28A6689A
+
+I=358
+KEY=2367A67114D722A79F9434B5A418BEEB87C6C636200899514DF3E9D6E8541AAA
+CT=58790B192C8B90B76F34990E28A6689A
+PT=599CA8B58EFE301A87CE72540CCB4067
+
+I=359
+KEY=A4CE195518F7E36D7E0D5C9666802411DE5A6E83AEF6A94BCA3D9B82E49F5ACD
+CT=599CA8B58EFE301A87CE72540CCB4067
+PT=4483131C7E03089F898166A5B3E85E3A
+
+I=360
+KEY=73C5204211D3648DAAF5FE071186C0E99AD97D9FD0F5A1D443BCFD27577704F7
+CT=4483131C7E03089F898166A5B3E85E3A
+PT=DBF64C5A0897B343BAF7047A6C564D02
+
+I=361
+KEY=1A3831AFF223BB2FE79C8EF8845E553C412F31C5D8621297F94BF95D3B2149F5
+CT=DBF64C5A0897B343BAF7047A6C564D02
+PT=B24420DA45E3620B619978CB09F1860C
+
+I=362
+KEY=31EF243EF87C32148751F8F299151042F36B111F9D81709C98D2819632D0CFF9
+CT=B24420DA45E3620B619978CB09F1860C
+PT=12B466EF6AE6F28AF78AC184DB8B3C83
+
+I=363
+KEY=9E935E6F5D76BEE2E639F2880C8352EEE1DF77F0F76782166F584012E95BF37A
+CT=12B466EF6AE6F28AF78AC184DB8B3C83
+PT=518E89A35CF55D591DE8BB924D8F96E7
+
+I=364
+KEY=C6398957838B02B5948A95DCBFBF2813B051FE53AB92DF4F72B0FB80A4D4659D
+CT=518E89A35CF55D591DE8BB924D8F96E7
+PT=1FDF7FE52BD46EF54F1F7A6242B04BD8
+
+I=365
+KEY=5764E84D9000518C185717581E0D70E5AF8E81B68046B1BA3DAF81E2E6642E45
+CT=1FDF7FE52BD46EF54F1F7A6242B04BD8
+PT=2C68E67C37B50056E80DC09B9ED84AA8
+
+I=366
+KEY=5F8CB51BF30B954B4AC09620B0A20FCA83E667CAB7F3B1ECD5A2417978BC64ED
+CT=2C68E67C37B50056E80DC09B9ED84AA8
+PT=14CC2D821B03BE21355A779B9066BE41
+
+I=367
+KEY=50B32E6D62EE3B8CE2DD5797BA70D8D2972A4A48ACF00FCDE0F836E2E8DADAAC
+CT=14CC2D821B03BE21355A779B9066BE41
+PT=BB09D339888C27294E73326E64AC3B21
+
+I=368
+KEY=E1B2199CAF1C3FA78E973ACF5C3AC8702C239971247C28E4AE8B048C8C76E18D
+CT=BB09D339888C27294E73326E64AC3B21
+PT=BCFBD8255802CC8233AEA86E49089328
+
+I=369
+KEY=3403D2498A4562E73734D065E9B44AD890D841547C7EE4669D25ACE2C57E72A5
+CT=BCFBD8255802CC8233AEA86E49089328
+PT=5A919AC72F12DB1FAB8E4876FBA8842B
+
+I=370
+KEY=B979FA15F93E5ACA1F6E452C9053751BCA49DB93536C3F7936ABE4943ED6F68E
+CT=5A919AC72F12DB1FAB8E4876FBA8842B
+PT=BDB03BD29FD3828AF1AE8C729F37F88A
+
+I=371
+KEY=A8CDF9FE3C0227A9107C700C404AE39777F9E041CCBFBDF3C70568E6A1E10E04
+CT=BDB03BD29FD3828AF1AE8C729F37F88A
+PT=0AAC43CE316476F3A532D44B4DFBF4B8
+
+I=372
+KEY=B4D497FBD5DE2CA68FF60C701E208A257D55A38FFDDBCB006237BCADEC1AFABC
+CT=0AAC43CE316476F3A532D44B4DFBF4B8
+PT=853A5EE7CB3C4BB3F0120BB2CFFB4436
+
+I=373
+KEY=A019DCC09A4CAAA3772BF4C54C8828E9F86FFD6836E780B39225B71F23E1BE8A
+CT=853A5EE7CB3C4BB3F0120BB2CFFB4436
+PT=B525599C918446AF4EA9F6965F3971EA
+
+I=374
+KEY=238BF8B851B0864F9BEC8E242B7795D14D4AA4F4A763C61CDC8C41897CD8CF60
+CT=B525599C918446AF4EA9F6965F3971EA
+PT=A8377EC293D41F74A0A2DB66BA7D3D2F
+
+I=375
+KEY=AF9E313988F294AE6A8155BC76F2514BE57DDA3634B7D9687C2E9AEFC6A5F24F
+CT=A8377EC293D41F74A0A2DB66BA7D3D2F
+PT=301BD4D318101A02166EBC23DED9C12D
+
+I=376
+KEY=3B6186F7ACE8E9B022DDE0ECF5D808D3D5660EE52CA7C36A6A4026CC187C3362
+CT=301BD4D318101A02166EBC23DED9C12D
+PT=05BD0686BE53B94FB1B42AE407BE081C
+
+I=377
+KEY=EADED20A0F405D9E3AAE404FB074162ED0DB086392F47A25DBF40C281FC23B7E
+CT=05BD0686BE53B94FB1B42AE407BE081C
+PT=7A3AF681F2043806EDB761F65D9A6C3A
+
+I=378
+KEY=AA6F474F5F5FF513FC992E4232061B75AAE1FEE260F0422336436DDE42585744
+CT=7A3AF681F2043806EDB761F65D9A6C3A
+PT=3C297DE35CCF4E6E0A800B9A3EE37C95
+
+I=379
+KEY=68BFE30863F135A09B81BE2800CBBC3796C883013C3F0C4D3CC366447CBB2BD1
+CT=3C297DE35CCF4E6E0A800B9A3EE37C95
+PT=5F8AAC15C74CC7EA87A1AC185103A9D7
+
+I=380
+KEY=9093DEBE66D714180BEB8FE51C4807ADC9422F14FB73CBA7BB62CA5C2DB88206
+CT=5F8AAC15C74CC7EA87A1AC185103A9D7
+PT=083AF3AF30961FD5A077F5564D55E9E9
+
+I=381
+KEY=A1E1049159A94DF638092C90F7707CD7C178DCBBCBE5D4721B153F0A60ED6BEF
+CT=083AF3AF30961FD5A077F5564D55E9E9
+PT=89BEFF6AB40B18ECD9413446E848253A
+
+I=382
+KEY=7C506732A8863DB1BF61EFC710F22D2348C623D17FEECC9EC2540B4C88A54ED5
+CT=89BEFF6AB40B18ECD9413446E848253A
+PT=095B2C04636C9C5BF9735BCA21211EAA
+
+I=383
+KEY=7283413612863BA1E1B5AE93DF1318F5419D0FD51C8250C53B275086A984507F
+CT=095B2C04636C9C5BF9735BCA21211EAA
+PT=E95DB3DB1E3A478C8A31212B28E0E7BC
+
+I=384
+KEY=BE861CED86D725162D938727D7AEFC1BA8C0BC0E02B81749B11671AD8164B7C3
+CT=E95DB3DB1E3A478C8A31212B28E0E7BC
+PT=9927F1D7EF0631500E1DF058932BF320
+
+I=385
+KEY=45AA89CBCE192CEEC22BF5F33DDE0E8D31E74DD9EDBE2619BF0B81F5124F44E3
+CT=9927F1D7EF0631500E1DF058932BF320
+PT=4B1147179F2AF27E5C9DBB7F01CC56A8
+
+I=386
+KEY=B08A08DABC52884E9EBB310236815BFE7AF60ACE7294D467E3963A8A1383124B
+CT=4B1147179F2AF27E5C9DBB7F01CC56A8
+PT=E9752A7D47734DACAC6E74A1A3EC4956
+
+I=387
+KEY=34B4424CE75A4A1BCE9E6C825F5F0DC1938320B335E799CB4FF84E2BB06F5B1D
+CT=E9752A7D47734DACAC6E74A1A3EC4956
+PT=AB2D652BCEE42804C5155980DA02CECC
+
+I=388
+KEY=F9954BB1A793565A79AA2B9DF408A34A38AE4598FB03B1CF8AED17AB6A6D95D1
+CT=AB2D652BCEE42804C5155980DA02CECC
+PT=3C6651362E89F6C6B28C04CA22F110EC
+
+I=389
+KEY=9548931715FB259E318020E30D68165604C814AED58A470938611361489C853D
+CT=3C6651362E89F6C6B28C04CA22F110EC
+PT=15598364698838475AB96F95CFCF3342
+
+I=390
+KEY=1CDB0706417BBE66B559237109353221119197CABC027F4E62D87CF48753B67F
+CT=15598364698838475AB96F95CFCF3342
+PT=D8B3BB941893206E1CA6654B81F403E4
+
+I=391
+KEY=8C4AD897B595252B0987673F45EE73F2C9222C5EA4915F207E7E19BF06A7B59B
+CT=D8B3BB941893206E1CA6654B81F403E4
+PT=ECE471CC2FF45C26C7143C41702F90D2
+
+I=392
+KEY=A6D3DF3279B7405256C0D22DA240524125C65D928B650306B96A25FE76882549
+CT=ECE471CC2FF45C26C7143C41702F90D2
+PT=AB387AE5A5FC892C311D97C22467940D
+
+I=393
+KEY=36F250F7C3906C7E0020055422CDB8B28EFE27772E998A2A8877B23C52EFB144
+CT=AB387AE5A5FC892C311D97C22467940D
+PT=FF48C2C77D5F52DF27C4060DF7F895D7
+
+I=394
+KEY=4FF045275860B943EDE02C802F34B71B71B6E5B053C6D8F5AFB3B431A5172493
+CT=FF48C2C77D5F52DF27C4060DF7F895D7
+PT=221BC444E2A6A7F8DE9DA16AB01EB2AC
+
+I=395
+KEY=E15B4E0E242FBABF1D47E9DBE6D0660253AD21F4B1607F0D712E155B1509963F
+CT=221BC444E2A6A7F8DE9DA16AB01EB2AC
+PT=DE252D19973ABD9F182049D39455784B
+
+I=396
+KEY=401023A611A3133C895A3684AB3E7C9D8D880CED265AC292690E5C88815CEE74
+CT=DE252D19973ABD9F182049D39455784B
+PT=843163BD101982EE948039915C8F60D8
+
+I=397
+KEY=B9DDF52C271F143E523532E45E6F368D09B96F503643407CFD8E6519DDD38EAC
+CT=843163BD101982EE948039915C8F60D8
+PT=6FD9D36B751854C3417F29E8F3B654D9
+
+I=398
+KEY=AC7F45F8630CE02525F9F4941B4E13206660BC3B435B14BFBCF14CF12E65DA75
+CT=6FD9D36B751854C3417F29E8F3B654D9
+PT=E1268BA8A1473DEDE6CA64DDF2C8B805
+
+I=399
+KEY=DE11FF0A429E1CD3DE016DAC294F771187463793E21C29525A3B282CDCAD6270
+CT=E1268BA8A1473DEDE6CA64DDF2C8B805
+PT=4DE0C6DF7CB1697284604D60271BC59A
+
+===========
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/test/ecb_e_m.txt b/mechglue/src/lib/crypto/aes/test/ecb_e_m.txt
new file mode 100644
index 000000000..40a95e7ca
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/ecb_e_m.txt
@@ -0,0 +1,6024 @@
+
+=========================
+
+FILENAME:  "ecb_e_m.txt"
+
+Electronic Codebook (ECB) Mode - ENCRYPTION
+Monte Carlo Test
+
+Algorithm Name: Rijndael
+Principal Submitter: Joan Daemen
+
+=========================
+
+KEYSIZE=128
+
+I=0
+KEY=00000000000000000000000000000000
+PT=00000000000000000000000000000000
+CT=C34C052CC0DA8D73451AFE5F03BE297F
+
+I=1
+KEY=C34C052CC0DA8D73451AFE5F03BE297F
+PT=C34C052CC0DA8D73451AFE5F03BE297F
+CT=0AC15A9AFBB24D54AD99E987208272E2
+
+I=2
+KEY=C98D5FB63B68C027E88317D8233C5B9D
+PT=0AC15A9AFBB24D54AD99E987208272E2
+CT=A3D43BFFA65D0E80092F67A314857870
+
+I=3
+KEY=6A5964499D35CEA7E1AC707B37B923ED
+PT=A3D43BFFA65D0E80092F67A314857870
+CT=355F697E8B868B65B25A04E18D782AFA
+
+I=4
+KEY=5F060D3716B345C253F6749ABAC10917
+PT=355F697E8B868B65B25A04E18D782AFA
+CT=ACC863637868E3E068D2FD6E3508454A
+
+I=5
+KEY=F3CE6E546EDBA6223B2489F48FC94C5D
+PT=ACC863637868E3E068D2FD6E3508454A
+CT=665F9F12A824F3D52A1C71D6210D5470
+
+I=6
+KEY=9591F146C6FF55F71138F822AEC4182D
+PT=665F9F12A824F3D52A1C71D6210D5470
+CT=9B27361DBC8E5618E8E98036F5AD40B0
+
+I=7
+KEY=0EB6C75B7A7103EFF9D178145B69589D
+PT=9B27361DBC8E5618E8E98036F5AD40B0
+CT=21D9BD7EBA0163A293F2D56C316CBD36
+
+I=8
+KEY=2F6F7A25C070604D6A23AD786A05E5AB
+PT=21D9BD7EBA0163A293F2D56C316CBD36
+CT=3E8037A9988E28FF81F2A7154ACD91BE
+
+I=9
+KEY=11EF4D8C58FE48B2EBD10A6D20C87415
+PT=3E8037A9988E28FF81F2A7154ACD91BE
+CT=014EE14F1AA8C0D4A47A72F197F4DCB0
+
+I=10
+KEY=10A1ACC3425688664FAB789CB73CA8A5
+PT=014EE14F1AA8C0D4A47A72F197F4DCB0
+CT=0B542083DBC03A96AA00C1A5AE58C9F1
+
+I=11
+KEY=1BF58C409996B2F0E5ABB93919646154
+PT=0B542083DBC03A96AA00C1A5AE58C9F1
+CT=7340B59E1E3BB9211CE167F2DEBDB090
+
+I=12
+KEY=68B539DE87AD0BD1F94ADECBC7D9D1C4
+PT=7340B59E1E3BB9211CE167F2DEBDB090
+CT=67E05F75135BA834CBCDCFF068541BBE
+
+I=13
+KEY=0F5566AB94F6A3E53287113BAF8DCA7A
+PT=67E05F75135BA834CBCDCFF068541BBE
+CT=8BD5553105C3507B0A07FDB351B25B4F
+
+I=14
+KEY=8480339A9135F39E3880EC88FE3F9135
+PT=8BD5553105C3507B0A07FDB351B25B4F
+CT=649F061F95C0A79BD3066EFFE5B27CAB
+
+I=15
+KEY=E01F358504F55405EB8682771B8DED9E
+PT=649F061F95C0A79BD3066EFFE5B27CAB
+CT=697F4EB0603340E90FE91C27B6D9CEAA
+
+I=16
+KEY=89607B3564C614ECE46F9E50AD542334
+PT=697F4EB0603340E90FE91C27B6D9CEAA
+CT=A8CBBA624FA28A7F8637324E1E20CB9C
+
+I=17
+KEY=21ABC1572B649E936258AC1EB374E8A8
+PT=A8CBBA624FA28A7F8637324E1E20CB9C
+CT=73B852132DE715872A40EB25B1133C00
+
+I=18
+KEY=5213934406838B144818473B0267D4A8
+PT=73B852132DE715872A40EB25B1133C00
+CT=1328A1C2F386BB3E4D4BE0942B8249A2
+
+I=19
+KEY=413B3286F505302A0553A7AF29E59D0A
+PT=1328A1C2F386BB3E4D4BE0942B8249A2
+CT=06F72DEA0067F543AA8C342CC9191745
+
+I=20
+KEY=47CC1F6CF562C569AFDF9383E0FC8A4F
+PT=06F72DEA0067F543AA8C342CC9191745
+CT=110B6011B60C94382C2321BFCAA62A1C
+
+I=21
+KEY=56C77F7D436E515183FCB23C2A5AA053
+PT=110B6011B60C94382C2321BFCAA62A1C
+CT=80C90EF6794361DFA400EFE922F45A59
+
+I=22
+KEY=D60E718B3A2D308E27FC5DD508AEFA0A
+PT=80C90EF6794361DFA400EFE922F45A59
+CT=F8DF0AC62EE229245DB1F300F2E5B143
+
+I=23
+KEY=2ED17B4D14CF19AA7A4DAED5FA4B4B49
+PT=F8DF0AC62EE229245DB1F300F2E5B143
+CT=45390146539E773B502E84A0C29AD5B0
+
+I=24
+KEY=6BE87A0B47516E912A632A7538D19EF9
+PT=45390146539E773B502E84A0C29AD5B0
+CT=B07721757865838BDFC2329998B5174F
+
+I=25
+KEY=DB9F5B7E3F34ED1AF5A118ECA06489B6
+PT=B07721757865838BDFC2329998B5174F
+CT=B83F3B7A9FFBA35DF1D6661A0F8AD0F4
+
+I=26
+KEY=63A06004A0CF4E4704777EF6AFEE5942
+PT=B83F3B7A9FFBA35DF1D6661A0F8AD0F4
+CT=7098C99B1B245DE623B78F1B07D08EBE
+
+I=27
+KEY=1338A99FBBEB13A127C0F1EDA83ED7FC
+PT=7098C99B1B245DE623B78F1B07D08EBE
+CT=58A095EF9268B923920238486D0B13E1
+
+I=28
+KEY=4B983C702983AA82B5C2C9A5C535C41D
+PT=58A095EF9268B923920238486D0B13E1
+CT=97DD8052CE0D87715075A42942C120ED
+
+I=29
+KEY=DC45BC22E78E2DF3E5B76D8C87F4E4F0
+PT=97DD8052CE0D87715075A42942C120ED
+CT=F480B5A67DAFCB9524DC21453AF66FAF
+
+I=30
+KEY=28C509849A21E666C16B4CC9BD028B5F
+PT=F480B5A67DAFCB9524DC21453AF66FAF
+CT=71CE64CE8C98367F2F12E6851AC70FF3
+
+I=31
+KEY=590B6D4A16B9D019EE79AA4CA7C584AC
+PT=71CE64CE8C98367F2F12E6851AC70FF3
+CT=81C3AA693CC1C647399701DA17D5FDD5
+
+I=32
+KEY=D8C8C7232A78165ED7EEAB96B0107979
+PT=81C3AA693CC1C647399701DA17D5FDD5
+CT=5BB93103F6DDF0415592EE2217704D41
+
+I=33
+KEY=8371F620DCA5E61F827C45B4A7603438
+PT=5BB93103F6DDF0415592EE2217704D41
+CT=87B8B17FF9079829AB5C47E055FFCEE3
+
+I=34
+KEY=04C9475F25A27E3629200254F29FFADB
+PT=87B8B17FF9079829AB5C47E055FFCEE3
+CT=615FE7D34154F42D6CE9D647904295E0
+
+I=35
+KEY=6596A08C64F68A1B45C9D41362DD6F3B
+PT=615FE7D34154F42D6CE9D647904295E0
+CT=A60C213CDF9B54DF9041948F98585CE2
+
+I=36
+KEY=C39A81B0BB6DDEC4D588409CFA8533D9
+PT=A60C213CDF9B54DF9041948F98585CE2
+CT=FB126C61071EB9167B6FF28E5244E624
+
+I=37
+KEY=3888EDD1BC7367D2AEE7B212A8C1D5FD
+PT=FB126C61071EB9167B6FF28E5244E624
+CT=8A79CE45F030B91B53D1591D10FF1B02
+
+I=38
+KEY=B2F123944C43DEC9FD36EB0FB83ECEFF
+PT=8A79CE45F030B91B53D1591D10FF1B02
+CT=BE20190BAE15162F43E93F67A580192B
+
+I=39
+KEY=0CD13A9FE256C8E6BEDFD4681DBED7D4
+PT=BE20190BAE15162F43E93F67A580192B
+CT=0107D3E3511F91545D02B498A9E3C318
+
+I=40
+KEY=0DD6E97CB34959B2E3DD60F0B45D14CC
+PT=0107D3E3511F91545D02B498A9E3C318
+CT=2A832A1205D6B5FCF1B20126EE59DD9D
+
+I=41
+KEY=2755C36EB69FEC4E126F61D65A04C951
+PT=2A832A1205D6B5FCF1B20126EE59DD9D
+CT=F362782F550DCBFC49CEF15C3A0ABA7A
+
+I=42
+KEY=D437BB41E39227B25BA1908A600E732B
+PT=F362782F550DCBFC49CEF15C3A0ABA7A
+CT=51A8A0C6434A3BE8C939B6DDD56EAA53
+
+I=43
+KEY=859F1B87A0D81C5A92982657B560D978
+PT=51A8A0C6434A3BE8C939B6DDD56EAA53
+CT=89D3F1086F3D96C18A76C61F25A52221
+
+I=44
+KEY=0C4CEA8FCFE58A9B18EEE04890C5FB59
+PT=89D3F1086F3D96C18A76C61F25A52221
+CT=A5F7E0A5FA70DDB718EF970F50EB7B86
+
+I=45
+KEY=A9BB0A2A3595572C00017747C02E80DF
+PT=A5F7E0A5FA70DDB718EF970F50EB7B86
+CT=7BB64305538E71AFBF993B5BD23D5523
+
+I=46
+KEY=D20D492F661B2683BF984C1C1213D5FC
+PT=7BB64305538E71AFBF993B5BD23D5523
+CT=E6BF8F5338568603EC668C6D15331FA5
+
+I=47
+KEY=34B2C67C5E4DA08053FEC0710720CA59
+PT=E6BF8F5338568603EC668C6D15331FA5
+CT=27644649FCDF52085CDB20E3DEE1E2F6
+
+I=48
+KEY=13D68035A292F2880F25E092D9C128AF
+PT=27644649FCDF52085CDB20E3DEE1E2F6
+CT=7629AACAED7F49938373C83410AD1744
+
+I=49
+KEY=65FF2AFF4FEDBB1B8C5628A6C96C3FEB
+PT=7629AACAED7F49938373C83410AD1744
+CT=D440FC6E9A65819934FAF8641C05A17C
+
+I=50
+KEY=B1BFD691D5883A82B8ACD0C2D5699E97
+PT=D440FC6E9A65819934FAF8641C05A17C
+CT=FBEE29FEFD725E1852B58502D3076C46
+
+I=51
+KEY=4A51FF6F28FA649AEA1955C0066EF2D1
+PT=FBEE29FEFD725E1852B58502D3076C46
+CT=E345A47A6C89BE4350CDD8C9D319529D
+
+I=52
+KEY=A9145B154473DAD9BAD48D09D577A04C
+PT=E345A47A6C89BE4350CDD8C9D319529D
+CT=1C6A7CBAF21E483B6025DB6DA573C5C6
+
+I=53
+KEY=B57E27AFB66D92E2DAF156647004658A
+PT=1C6A7CBAF21E483B6025DB6DA573C5C6
+CT=2B05F4D8EB50D851A013798753B65A1F
+
+I=54
+KEY=9E7BD3775D3D4AB37AE22FE323B23F95
+PT=2B05F4D8EB50D851A013798753B65A1F
+CT=CEFE04978228A0DBCCE9EE42B21DD34A
+
+I=55
+KEY=5085D7E0DF15EA68B60BC1A191AFECDF
+PT=CEFE04978228A0DBCCE9EE42B21DD34A
+CT=7B41DF8CD85B61EA800536648DBDA2AE
+
+I=56
+KEY=2BC4086C074E8B82360EF7C51C124E71
+PT=7B41DF8CD85B61EA800536648DBDA2AE
+CT=08688872151D18CD19E2FC14B9E4C962
+
+I=57
+KEY=23AC801E1253934F2FEC0BD1A5F68713
+PT=08688872151D18CD19E2FC14B9E4C962
+CT=F08C88BE5E748C4D82D2E7D7813A33AF
+
+I=58
+KEY=D32008A04C271F02AD3EEC0624CCB4BC
+PT=F08C88BE5E748C4D82D2E7D7813A33AF
+CT=319B7D38AB1AC3AEA0A0490C341F4F20
+
+I=59
+KEY=E2BB7598E73DDCAC0D9EA50A10D3FB9C
+PT=319B7D38AB1AC3AEA0A0490C341F4F20
+CT=EE70748772E8D88B2717D78F31F0EA86
+
+I=60
+KEY=0CCB011F95D504272A8972852123111A
+PT=EE70748772E8D88B2717D78F31F0EA86
+CT=A3A5DC791EA1BBB9D7A2B292572DFD5C
+
+I=61
+KEY=AF6EDD668B74BF9EFD2BC017760EEC46
+PT=A3A5DC791EA1BBB9D7A2B292572DFD5C
+CT=255692B06B3A18498BCAF99F7B3EE374
+
+I=62
+KEY=8A384FD6E04EA7D776E139880D300F32
+PT=255692B06B3A18498BCAF99F7B3EE374
+CT=500E492232891293875F50279B5DC5C3
+
+I=63
+KEY=DA3606F4D2C7B544F1BE69AF966DCAF1
+PT=500E492232891293875F50279B5DC5C3
+CT=57C3FCCE9B5BA3BC19BBF7BB9B37A9AC
+
+I=64
+KEY=8DF5FA3A499C16F8E8059E140D5A635D
+PT=57C3FCCE9B5BA3BC19BBF7BB9B37A9AC
+CT=BF06FDFDB687C8B24FB0E2A6D6D37EA5
+
+I=65
+KEY=32F307C7FF1BDE4AA7B57CB2DB891DF8
+PT=BF06FDFDB687C8B24FB0E2A6D6D37EA5
+CT=6D459ED545CF3C6FF2746411CD9B3E31
+
+I=66
+KEY=5FB69912BAD4E22555C118A3161223C9
+PT=6D459ED545CF3C6FF2746411CD9B3E31
+CT=C74E0704A9D9EC2D90F75B34FC95CD32
+
+I=67
+KEY=98F89E16130D0E08C5364397EA87EEFB
+PT=C74E0704A9D9EC2D90F75B34FC95CD32
+CT=0453D4FBC2D7F8E0AD0AD90F98D1EC5C
+
+I=68
+KEY=9CAB4AEDD1DAF6E8683C9A98725602A7
+PT=0453D4FBC2D7F8E0AD0AD90F98D1EC5C
+CT=5BBA052D6C39DC1E9553B7646CB7344B
+
+I=69
+KEY=C7114FC0BDE32AF6FD6F2DFC1EE136EC
+PT=5BBA052D6C39DC1E9553B7646CB7344B
+CT=9870FFE04984426501ECB55FFBB363CB
+
+I=70
+KEY=5F61B020F4676893FC8398A3E5525527
+PT=9870FFE04984426501ECB55FFBB363CB
+CT=1363D65F7C943FC4512E41A717D3704D
+
+I=71
+KEY=4C02667F88F35757ADADD904F281256A
+PT=1363D65F7C943FC4512E41A717D3704D
+CT=664762AED6BC5FB74A646A928837FC83
+
+I=72
+KEY=2A4504D15E4F08E0E7C9B3967AB6D9E9
+PT=664762AED6BC5FB74A646A928837FC83
+CT=655CB6BAB4B0532273689E4DC9234C42
+
+I=73
+KEY=4F19B26BEAFF5BC294A12DDBB39595AB
+PT=655CB6BAB4B0532273689E4DC9234C42
+CT=E8AAE0E0B9D2BE6259AEBC478DC90FD9
+
+I=74
+KEY=A7B3528B532DE5A0CD0F919C3E5C9A72
+PT=E8AAE0E0B9D2BE6259AEBC478DC90FD9
+CT=FECACAF43DD920FA3078256C6A587741
+
+I=75
+KEY=5979987F6EF4C55AFD77B4F05404ED33
+PT=FECACAF43DD920FA3078256C6A587741
+CT=11F3F56529B8B172D87A4C86BB90F3B6
+
+I=76
+KEY=488A6D1A474C7428250DF876EF941E85
+PT=11F3F56529B8B172D87A4C86BB90F3B6
+CT=B44340D44F1ABA37CB09FE57FC771A9E
+
+I=77
+KEY=FCC92DCE0856CE1FEE04062113E3041B
+PT=B44340D44F1ABA37CB09FE57FC771A9E
+CT=C49F12B88C34A0D696FE283B01D5710C
+
+I=78
+KEY=38563F7684626EC978FA2E1A12367517
+PT=C49F12B88C34A0D696FE283B01D5710C
+CT=58D6D2D36C14DDBDA7604AB740918D76
+
+I=79
+KEY=6080EDA5E876B374DF9A64AD52A7F861
+PT=58D6D2D36C14DDBDA7604AB740918D76
+CT=21F735F77B0EAD7551CE06900A568EB3
+
+I=80
+KEY=4177D85293781E018E54623D58F176D2
+PT=21F735F77B0EAD7551CE06900A568EB3
+CT=FE2E9BDB393BF6D1BBF108B8AC3B6818
+
+I=81
+KEY=BF594389AA43E8D035A56A85F4CA1ECA
+PT=FE2E9BDB393BF6D1BBF108B8AC3B6818
+CT=FECFCD3722C6C8E6608258341220E739
+
+I=82
+KEY=41968EBE88852036552732B1E6EAF9F3
+PT=FECFCD3722C6C8E6608258341220E739
+CT=10A8BB234C9D9A22DEC7887E931F85BD
+
+I=83
+KEY=513E359DC418BA148BE0BACF75F57C4E
+PT=10A8BB234C9D9A22DEC7887E931F85BD
+CT=767EB7DBA70BC7094DF7A5BDD233EB5C
+
+I=84
+KEY=2740824663137D1DC6171F72A7C69712
+PT=767EB7DBA70BC7094DF7A5BDD233EB5C
+CT=FCD7184F3F4DB7CA182225B9A358209D
+
+I=85
+KEY=DB979A095C5ECAD7DE353ACB049EB78F
+PT=FCD7184F3F4DB7CA182225B9A358209D
+CT=A5CD025AEBF0380EAC66EF034806179F
+
+I=86
+KEY=7E5A9853B7AEF2D97253D5C84C98A010
+PT=A5CD025AEBF0380EAC66EF034806179F
+CT=FE46F4A72C7031FE8D900152CD20B95F
+
+I=87
+KEY=801C6CF49BDEC327FFC3D49A81B8194F
+PT=FE46F4A72C7031FE8D900152CD20B95F
+CT=CF1ACB502A4B608C61364891E34F93A0
+
+I=88
+KEY=4F06A7A4B195A3AB9EF59C0B62F78AEF
+PT=CF1ACB502A4B608C61364891E34F93A0
+CT=95AB1367FF6C03DE87FFA282A3E52200
+
+I=89
+KEY=DAADB4C34EF9A075190A3E89C112A8EF
+PT=95AB1367FF6C03DE87FFA282A3E52200
+CT=762B6393252B347F55AF3E4CA16F2FC9
+
+I=90
+KEY=AC86D7506BD2940A4CA500C5607D8726
+PT=762B6393252B347F55AF3E4CA16F2FC9
+CT=A63491A22E23AD921ADAB9CC0DA20521
+
+I=91
+KEY=0AB246F245F13998567FB9096DDF8207
+PT=A63491A22E23AD921ADAB9CC0DA20521
+CT=C0852A5E7CEEAFB5FA87C440B598BFD6
+
+I=92
+KEY=CA376CAC391F962DACF87D49D8473DD1
+PT=C0852A5E7CEEAFB5FA87C440B598BFD6
+CT=485747C528B08033169E991E98E4CBB5
+
+I=93
+KEY=82602B6911AF161EBA66E45740A3F664
+PT=485747C528B08033169E991E98E4CBB5
+CT=415B95B222161A8C9ED20CF99C26848C
+
+I=94
+KEY=C33BBEDB33B90C9224B4E8AEDC8572E8
+PT=415B95B222161A8C9ED20CF99C26848C
+CT=7E673E6348C38CD40C9B11F4C9F3E3A0
+
+I=95
+KEY=BD5C80B87B7A8046282FF95A15769148
+PT=7E673E6348C38CD40C9B11F4C9F3E3A0
+CT=B88508E55279AFF0D848C38DBEC76B2C
+
+I=96
+KEY=05D9885D29032FB6F0673AD7ABB1FA64
+PT=B88508E55279AFF0D848C38DBEC76B2C
+CT=3902B5DC34E815BA50A53DB9C8FFAA92
+
+I=97
+KEY=3CDB3D811DEB3A0CA0C2076E634E50F6
+PT=3902B5DC34E815BA50A53DB9C8FFAA92
+CT=FEF57F51360547EA6B88085B8656A1D0
+
+I=98
+KEY=C22E42D02BEE7DE6CB4A0F35E518F126
+PT=FEF57F51360547EA6B88085B8656A1D0
+CT=94D052E1F097106A5B714ADD0EF79E64
+
+I=99
+KEY=56FE1031DB796D8C903B45E8EBEF6F42
+PT=94D052E1F097106A5B714ADD0EF79E64
+CT=7FD3EF411360E5270F63A8BACCCC74C0
+
+I=100
+KEY=292DFF70C81988AB9F58ED5227231B82
+PT=7FD3EF411360E5270F63A8BACCCC74C0
+CT=F572692DE6EFBC2309B947D1A75BE009
+
+I=101
+KEY=DC5F965D2EF6348896E1AA838078FB8B
+PT=F572692DE6EFBC2309B947D1A75BE009
+CT=BFD3233C513448C283C05311B8085B5C
+
+I=102
+KEY=638CB5617FC27C4A1521F9923870A0D7
+PT=BFD3233C513448C283C05311B8085B5C
+CT=078739F570071AA1A96A1F00F31E05FD
+
+I=103
+KEY=640B8C940FC566EBBC4BE692CB6EA52A
+PT=078739F570071AA1A96A1F00F31E05FD
+CT=947CA236277CDD0AC13C194B99E8CF16
+
+I=104
+KEY=F0772EA228B9BBE17D77FFD952866A3C
+PT=947CA236277CDD0AC13C194B99E8CF16
+CT=34DE5F2D355BC4ACE54AD0CB8C008CB8
+
+I=105
+KEY=C4A9718F1DE27F4D983D2F12DE86E684
+PT=34DE5F2D355BC4ACE54AD0CB8C008CB8
+CT=E5729CBD84C89B914F35412F902A2CA3
+
+I=106
+KEY=21DBED32992AE4DCD7086E3D4EACCA27
+PT=E5729CBD84C89B914F35412F902A2CA3
+CT=EB326D6ABAFC93EADBEC9B05CE4AAF0C
+
+I=107
+KEY=CAE9805823D677360CE4F53880E6652B
+PT=EB326D6ABAFC93EADBEC9B05CE4AAF0C
+CT=9F088089F8D8E8E28A9A2A1FF50F2ED3
+
+I=108
+KEY=55E100D1DB0E9FD4867EDF2775E94BF8
+PT=9F088089F8D8E8E28A9A2A1FF50F2ED3
+CT=C8D2BF3D6ADB57F478656D4808142160
+
+I=109
+KEY=9D33BFECB1D5C820FE1BB26F7DFD6A98
+PT=C8D2BF3D6ADB57F478656D4808142160
+CT=062016811215B9DBDD3C794A15FBEBBA
+
+I=110
+KEY=9B13A96DA3C071FB2327CB2568068122
+PT=062016811215B9DBDD3C794A15FBEBBA
+CT=71F9F04E9AED1C302E5ED2AD36B5C7F5
+
+I=111
+KEY=EAEA5923392D6DCB0D7919885EB346D7
+PT=71F9F04E9AED1C302E5ED2AD36B5C7F5
+CT=253982568F6C3FDFDE173E46B614989C
+
+I=112
+KEY=CFD3DB75B6415214D36E27CEE8A7DE4B
+PT=253982568F6C3FDFDE173E46B614989C
+CT=6D51D51276A6FA9C933E4D4496D0455E
+
+I=113
+KEY=A2820E67C0E7A88840506A8A7E779B15
+PT=6D51D51276A6FA9C933E4D4496D0455E
+CT=B9A6924F773CE826BBBC6DDBFA4E146A
+
+I=114
+KEY=1B249C28B7DB40AEFBEC075184398F7F
+PT=B9A6924F773CE826BBBC6DDBFA4E146A
+CT=474943C523162BC81186779A07144BC6
+
+I=115
+KEY=5C6DDFED94CD6B66EA6A70CB832DC4B9
+PT=474943C523162BC81186779A07144BC6
+CT=20128A092B99B4BC212B1107C3BA1DF9
+
+I=116
+KEY=7C7F55E4BF54DFDACB4161CC4097D940
+PT=20128A092B99B4BC212B1107C3BA1DF9
+CT=90330B8FB5A50E958250A953EF5145C7
+
+I=117
+KEY=EC4C5E6B0AF1D14F4911C89FAFC69C87
+PT=90330B8FB5A50E958250A953EF5145C7
+CT=C1B788D0EB2C8C7B9E020CC2BEACD595
+
+I=118
+KEY=2DFBD6BBE1DD5D34D713C45D116A4912
+PT=C1B788D0EB2C8C7B9E020CC2BEACD595
+CT=EF87960DABBE82F6CFA8045CE4A9EED0
+
+I=119
+KEY=C27C40B64A63DFC218BBC001F5C3A7C2
+PT=EF87960DABBE82F6CFA8045CE4A9EED0
+CT=405C8408D5027DF90CBE3159701D161A
+
+I=120
+KEY=8220C4BE9F61A23B1405F15885DEB1D8
+PT=405C8408D5027DF90CBE3159701D161A
+CT=FCAB7F88E85D6573A98D23D684A5A5F3
+
+I=121
+KEY=7E8BBB36773CC748BD88D28E017B142B
+PT=FCAB7F88E85D6573A98D23D684A5A5F3
+CT=191E6F1EECBF5149F4D49446E97D8820
+
+I=122
+KEY=6795D4289B839601495C46C8E8069C0B
+PT=191E6F1EECBF5149F4D49446E97D8820
+CT=C77128F53D48594194EFBA67E46C6B23
+
+I=123
+KEY=A0E4FCDDA6CBCF40DDB3FCAF0C6AF728
+PT=C77128F53D48594194EFBA67E46C6B23
+CT=DFB898170571450CC5E2244AE4D3AF43
+
+I=124
+KEY=7F5C64CAA3BA8A4C1851D8E5E8B9586B
+PT=DFB898170571450CC5E2244AE4D3AF43
+CT=3BD1633B5053609A3B42CC098F9F5D87
+
+I=125
+KEY=448D07F1F3E9EAD6231314EC672605EC
+PT=3BD1633B5053609A3B42CC098F9F5D87
+CT=AC15B23F205AEB10470F853BA18361E0
+
+I=126
+KEY=E898B5CED3B301C6641C91D7C6A5640C
+PT=AC15B23F205AEB10470F853BA18361E0
+CT=2DA73BA6E01B1ADFBEEAFA2E37942078
+
+I=127
+KEY=C53F8E6833A81B19DAF66BF9F1314474
+PT=2DA73BA6E01B1ADFBEEAFA2E37942078
+CT=C5B3D7089173958B32340B88D35B738B
+
+I=128
+KEY=008C5960A2DB8E92E8C26071226A37FF
+PT=C5B3D7089173958B32340B88D35B738B
+CT=8318BAA96569F3ADCD30C08D54494392
+
+I=129
+KEY=8394E3C9C7B27D3F25F2A0FC7623746D
+PT=8318BAA96569F3ADCD30C08D54494392
+CT=4F6F2A06A1A344B261084563BCCC5A5A
+
+I=130
+KEY=CCFBC9CF6611398D44FAE59FCAEF2E37
+PT=4F6F2A06A1A344B261084563BCCC5A5A
+CT=07EC18166362BF049A48D146A63FF378
+
+I=131
+KEY=CB17D1D905738689DEB234D96CD0DD4F
+PT=07EC18166362BF049A48D146A63FF378
+CT=81CB17ABAC28A3ED135442454C212646
+
+I=132
+KEY=4ADCC672A95B2564CDE6769C20F1FB09
+PT=81CB17ABAC28A3ED135442454C212646
+CT=C1CBDE45E27B9B1198CE93A51E38D9C5
+
+I=133
+KEY=8B1718374B20BE755528E5393EC922CC
+PT=C1CBDE45E27B9B1198CE93A51E38D9C5
+CT=8E4EB89DDFEE065784556FA0B426954A
+
+I=134
+KEY=0559A0AA94CEB822D17D8A998AEFB786
+PT=8E4EB89DDFEE065784556FA0B426954A
+CT=6A966414CC6FE52F957E9DE7012EC4BD
+
+I=135
+KEY=6FCFC4BE58A15D0D4403177E8BC1733B
+PT=6A966414CC6FE52F957E9DE7012EC4BD
+CT=7C88474D963BFDFE61F052F51D1796EF
+
+I=136
+KEY=134783F3CE9AA0F325F3458B96D6E5D4
+PT=7C88474D963BFDFE61F052F51D1796EF
+CT=6269F5DA04B09D442DDCB46001573AE9
+
+I=137
+KEY=712E7629CA2A3DB7082FF1EB9781DF3D
+PT=6269F5DA04B09D442DDCB46001573AE9
+CT=FBD2965ACE0B360A12EF39873A8F3805
+
+I=138
+KEY=8AFCE07304210BBD1AC0C86CAD0EE738
+PT=FBD2965ACE0B360A12EF39873A8F3805
+CT=5B46EF12C9BE55DCD5571D82E5BC6FF1
+
+I=139
+KEY=D1BA0F61CD9F5E61CF97D5EE48B288C9
+PT=5B46EF12C9BE55DCD5571D82E5BC6FF1
+CT=403DEFDB60876F3161CF02F319F5EA9A
+
+I=140
+KEY=9187E0BAAD183150AE58D71D51476253
+PT=403DEFDB60876F3161CF02F319F5EA9A
+CT=70FD321C583C1B54ED6AD3A79721E84A
+
+I=141
+KEY=E17AD2A6F5242A04433204BAC6668A19
+PT=70FD321C583C1B54ED6AD3A79721E84A
+CT=32AE26E948D563782532AC711BFAB644
+
+I=142
+KEY=D3D4F44FBDF1497C6600A8CBDD9C3C5D
+PT=32AE26E948D563782532AC711BFAB644
+CT=ECF948F5EBB98E4C7286046E0F7AF127
+
+I=143
+KEY=3F2DBCBA5648C7301486ACA5D2E6CD7A
+PT=ECF948F5EBB98E4C7286046E0F7AF127
+CT=818F87EFA0B5E4098E737AD44DB537BA
+
+I=144
+KEY=BEA23B55F6FD23399AF5D6719F53FAC0
+PT=818F87EFA0B5E4098E737AD44DB537BA
+CT=029F170737413F1BFBE02C292D506E44
+
+I=145
+KEY=BC3D2C52C1BC1C226115FA58B2039484
+PT=029F170737413F1BFBE02C292D506E44
+CT=77A7C520912761121373E35FD3B5AF0F
+
+I=146
+KEY=CB9AE972509B7D307266190761B63B8B
+PT=77A7C520912761121373E35FD3B5AF0F
+CT=D407B965C368E1F77195ED446BEEBA73
+
+I=147
+KEY=1F9D501793F39CC703F3F4430A5881F8
+PT=D407B965C368E1F77195ED446BEEBA73
+CT=D1F304E0B3614A4840F128AA364BA6A3
+
+I=148
+KEY=CE6E54F72092D68F4302DCE93C13275B
+PT=D1F304E0B3614A4840F128AA364BA6A3
+CT=69B748543EE72474D0CC301BDBD50A6C
+
+I=149
+KEY=A7D91CA31E75F2FB93CEECF2E7C62D37
+PT=69B748543EE72474D0CC301BDBD50A6C
+CT=BA471D91DBC6D27EBA7B510E67830C3F
+
+I=150
+KEY=1D9E0132C5B3208529B5BDFC80452108
+PT=BA471D91DBC6D27EBA7B510E67830C3F
+CT=7C0CF396D078E01A741613B1E1D7A9CB
+
+I=151
+KEY=6192F2A415CBC09F5DA3AE4D619288C3
+PT=7C0CF396D078E01A741613B1E1D7A9CB
+CT=6F670A289398F49C75ACBBE9EAC2ABFC
+
+I=152
+KEY=0EF5F88C86533403280F15A48B50233F
+PT=6F670A289398F49C75ACBBE9EAC2ABFC
+CT=C392EF479528BF1B02296E6C894E4FDD
+
+I=153
+KEY=CD6717CB137B8B182A267BC8021E6CE2
+PT=C392EF479528BF1B02296E6C894E4FDD
+CT=C4226C8C98D5F137A4C6A239E04B0FB3
+
+I=154
+KEY=09457B478BAE7A2F8EE0D9F1E2556351
+PT=C4226C8C98D5F137A4C6A239E04B0FB3
+CT=2382714FC945AD4A1E03858B63973B9E
+
+I=155
+KEY=2AC70A0842EBD76590E35C7A81C258CF
+PT=2382714FC945AD4A1E03858B63973B9E
+CT=E41F350AC9320A8A23E27C0349978168
+
+I=156
+KEY=CED83F028BD9DDEFB3012079C855D9A7
+PT=E41F350AC9320A8A23E27C0349978168
+CT=7E9137997CB7676F3D0141797C6F31A8
+
+I=157
+KEY=B049089BF76EBA808E006100B43AE80F
+PT=7E9137997CB7676F3D0141797C6F31A8
+CT=4BF7EBC15369A757981EE4A0B7F55706
+
+I=158
+KEY=FBBEE35AA4071DD7161E85A003CFBF09
+PT=4BF7EBC15369A757981EE4A0B7F55706
+CT=EC677E86A8D2A5935D33D6471A58A781
+
+I=159
+KEY=17D99DDC0CD5B8444B2D53E719971888
+PT=EC677E86A8D2A5935D33D6471A58A781
+CT=F31066D48884BC9B37F218FCF385344B
+
+I=160
+KEY=E4C9FB08845104DF7CDF4B1BEA122CC3
+PT=F31066D48884BC9B37F218FCF385344B
+CT=51CFEA4E482A7B7BCF4D31DA5CED4370
+
+I=161
+KEY=B5061146CC7B7FA4B3927AC1B6FF6FB3
+PT=51CFEA4E482A7B7BCF4D31DA5CED4370
+CT=89F3CD1590669A16F8460991BFD3CF5C
+
+I=162
+KEY=3CF5DC535C1DE5B24BD47350092CA0EF
+PT=89F3CD1590669A16F8460991BFD3CF5C
+CT=9930DA8E5DBC1F6C87B0B41BD386E2E0
+
+I=163
+KEY=A5C506DD01A1FADECC64C74BDAAA420F
+PT=9930DA8E5DBC1F6C87B0B41BD386E2E0
+CT=41A8CB583E5B9D2BA7CDA3763B6529C0
+
+I=164
+KEY=E46DCD853FFA67F56BA9643DE1CF6BCF
+PT=41A8CB583E5B9D2BA7CDA3763B6529C0
+CT=53479DCFB0C69624B42B9C272B0A1A85
+
+I=165
+KEY=B72A504A8F3CF1D1DF82F81ACAC5714A
+PT=53479DCFB0C69624B42B9C272B0A1A85
+CT=E72F27AE86E913EF55309120358BAD35
+
+I=166
+KEY=500577E409D5E23E8AB2693AFF4EDC7F
+PT=E72F27AE86E913EF55309120358BAD35
+CT=9B1EF901BACC70819DBC627C7CDC8CD9
+
+I=167
+KEY=CB1B8EE5B31992BF170E0B46839250A6
+PT=9B1EF901BACC70819DBC627C7CDC8CD9
+CT=9546C7B789345E4C32EE84BCE8E78C7E
+
+I=168
+KEY=5E5D49523A2DCCF325E08FFA6B75DCD8
+PT=9546C7B789345E4C32EE84BCE8E78C7E
+CT=33700B93E03CE8202BAC7E64E3255108
+
+I=169
+KEY=6D2D42C1DA1124D30E4CF19E88508DD0
+PT=33700B93E03CE8202BAC7E64E3255108
+CT=44246615BCA5C0A8DCB7E63729398F0A
+
+I=170
+KEY=290924D466B4E47BD2FB17A9A16902DA
+PT=44246615BCA5C0A8DCB7E63729398F0A
+CT=3215FC55FEE5A30BFA11F8EBBC912652
+
+I=171
+KEY=1B1CD8819851477028EAEF421DF82488
+PT=3215FC55FEE5A30BFA11F8EBBC912652
+CT=796C9136407BC4F484B253DAEB206912
+
+I=172
+KEY=627049B7D82A8384AC58BC98F6D84D9A
+PT=796C9136407BC4F484B253DAEB206912
+CT=B18977B404F0671C10AA979389408CCA
+
+I=173
+KEY=D3F93E03DCDAE498BCF22B0B7F98C150
+PT=B18977B404F0671C10AA979389408CCA
+CT=B2592621EE947D4ED9AD4295E0675F93
+
+I=174
+KEY=61A01822324E99D6655F699E9FFF9EC3
+PT=B2592621EE947D4ED9AD4295E0675F93
+CT=62D3B7E28765DA8F83EBE19C97293C0A
+
+I=175
+KEY=0373AFC0B52B4359E6B4880208D6A2C9
+PT=62D3B7E28765DA8F83EBE19C97293C0A
+CT=F417D650D6B7631542CFF8F95FC81C9B
+
+I=176
+KEY=F7647990639C204CA47B70FB571EBE52
+PT=F417D650D6B7631542CFF8F95FC81C9B
+CT=700A5DE153D6B438FFF7BA902DEC32FF
+
+I=177
+KEY=876E2471304A94745B8CCA6B7AF28CAD
+PT=700A5DE153D6B438FFF7BA902DEC32FF
+CT=67DC08A48F1EC7E32121B8693BB23621
+
+I=178
+KEY=E0B22CD5BF5453977AAD72024140BA8C
+PT=67DC08A48F1EC7E32121B8693BB23621
+CT=90038BB156A7F7992E260E9CBFAC0D82
+
+I=179
+KEY=70B1A764E9F3A40E548B7C9EFEECB70E
+PT=90038BB156A7F7992E260E9CBFAC0D82
+CT=C6BB1407C2D037BF238BEC772BA95352
+
+I=180
+KEY=B60AB3632B2393B1770090E9D545E45C
+PT=C6BB1407C2D037BF238BEC772BA95352
+CT=8C3D249574FF74F84053977219D69F5E
+
+I=181
+KEY=3A3797F65FDCE7493753079BCC937B02
+PT=8C3D249574FF74F84053977219D69F5E
+CT=131F7FC5A1528AD5DCB167AFAA8BFD47
+
+I=182
+KEY=2928E833FE8E6D9CEBE2603466188645
+PT=131F7FC5A1528AD5DCB167AFAA8BFD47
+CT=6E68AE6FDF2C10B42B85486D3EFBCEB9
+
+I=183
+KEY=4740465C21A27D28C067285958E348FC
+PT=6E68AE6FDF2C10B42B85486D3EFBCEB9
+CT=26808ABFA3967D742D64A26CADF8DD70
+
+I=184
+KEY=61C0CCE38234005CED038A35F51B958C
+PT=26808ABFA3967D742D64A26CADF8DD70
+CT=8BBCBA5E4C219D000A2F6B701CDA09C3
+
+I=185
+KEY=EA7C76BDCE159D5CE72CE145E9C19C4F
+PT=8BBCBA5E4C219D000A2F6B701CDA09C3
+CT=5D707BB328BEFF51C8C1D984C1608AA0
+
+I=186
+KEY=B70C0D0EE6AB620D2FED38C128A116EF
+PT=5D707BB328BEFF51C8C1D984C1608AA0
+CT=8D0A485482B914FC282C2DA9F7147D0C
+
+I=187
+KEY=3A06455A641276F107C11568DFB56BE3
+PT=8D0A485482B914FC282C2DA9F7147D0C
+CT=C5678BC12445627CBAA94177F070F736
+
+I=188
+KEY=FF61CE9B4057148DBD68541F2FC59CD5
+PT=C5678BC12445627CBAA94177F070F736
+CT=EB9B50846E92C20CD6EDBA7A3A260684
+
+I=189
+KEY=14FA9E1F2EC5D6816B85EE6515E39A51
+PT=EB9B50846E92C20CD6EDBA7A3A260684
+CT=E2178B471A3F72A271013C4CBE41FA1C
+
+I=190
+KEY=F6ED155834FAA4231A84D229ABA2604D
+PT=E2178B471A3F72A271013C4CBE41FA1C
+CT=C10C8084A17D90339E5ED8C638B902A4
+
+I=191
+KEY=37E195DC9587341084DA0AEF931B62E9
+PT=C10C8084A17D90339E5ED8C638B902A4
+CT=03C839CCF269548279F30A1F45C30556
+
+I=192
+KEY=3429AC1067EE6092FD2900F0D6D867BF
+PT=03C839CCF269548279F30A1F45C30556
+CT=1C5DC5C94B5C7E332D4122A0A4FACD96
+
+I=193
+KEY=287469D92CB21EA1D06822507222AA29
+PT=1C5DC5C94B5C7E332D4122A0A4FACD96
+CT=E7292B7D15E9311F242FACFAFC0B0B81
+
+I=194
+KEY=CF5D42A4395B2FBEF4478EAA8E29A1A8
+PT=E7292B7D15E9311F242FACFAFC0B0B81
+CT=EA6DF86EEE09613104DB81B97B949AEC
+
+I=195
+KEY=2530BACAD7524E8FF09C0F13F5BD3B44
+PT=EA6DF86EEE09613104DB81B97B949AEC
+CT=8FBCCDEBA43FE3FFDE4C3C279BDD4A27
+
+I=196
+KEY=AA8C7721736DAD702ED033346E607163
+PT=8FBCCDEBA43FE3FFDE4C3C279BDD4A27
+CT=985971BE962C63B0F50D1004963E9BED
+
+I=197
+KEY=32D5069FE541CEC0DBDD2330F85EEA8E
+PT=985971BE962C63B0F50D1004963E9BED
+CT=F2CC0FF4B6D2F88766F1B8BE370FE463
+
+I=198
+KEY=C019096B53933647BD2C9B8ECF510EED
+PT=F2CC0FF4B6D2F88766F1B8BE370FE463
+CT=FE33F823B7B97FC017B35B6E22415D3E
+
+I=199
+KEY=3E2AF148E42A4987AA9FC0E0ED1053D3
+PT=FE33F823B7B97FC017B35B6E22415D3E
+CT=465D804A6053EC2580B59F0CD645C060
+
+I=200
+KEY=787771028479A5A22A2A5FEC3B5593B3
+PT=465D804A6053EC2580B59F0CD645C060
+CT=DE05AD28693E3D471B8F39BAD1803C0E
+
+I=201
+KEY=A672DC2AED4798E531A56656EAD5AFBD
+PT=DE05AD28693E3D471B8F39BAD1803C0E
+CT=61EB397D55A2FC3D78974C8A10200AC6
+
+I=202
+KEY=C799E557B8E564D849322ADCFAF5A57B
+PT=61EB397D55A2FC3D78974C8A10200AC6
+CT=BD95D742D81AD795AA4E10FB41F54294
+
+I=203
+KEY=7A0C321560FFB34DE37C3A27BB00E7EF
+PT=BD95D742D81AD795AA4E10FB41F54294
+CT=F43A1E8C6E057E68414D23DA6932DE2C
+
+I=204
+KEY=8E362C990EFACD25A23119FDD23239C3
+PT=F43A1E8C6E057E68414D23DA6932DE2C
+CT=8EBB208032245988E851148B34B92F0E
+
+I=205
+KEY=008D0C193CDE94AD4A600D76E68B16CD
+PT=8EBB208032245988E851148B34B92F0E
+CT=2F18B4B14A360E06C50C89A4E6FE6C17
+
+I=206
+KEY=2F95B8A876E89AAB8F6C84D200757ADA
+PT=2F18B4B14A360E06C50C89A4E6FE6C17
+CT=681E131FA7EA5EBE10B59D3F16009582
+
+I=207
+KEY=478BABB7D102C4159FD919ED1675EF58
+PT=681E131FA7EA5EBE10B59D3F16009582
+CT=376FA31CC9D18E756E96715D61403C5D
+
+I=208
+KEY=70E408AB18D34A60F14F68B07735D305
+PT=376FA31CC9D18E756E96715D61403C5D
+CT=519E87E4A1AC61C376842F028D1BD75F
+
+I=209
+KEY=217A8F4FB97F2BA387CB47B2FA2E045A
+PT=519E87E4A1AC61C376842F028D1BD75F
+CT=BFAED9E9964967342808C6C332E02204
+
+I=210
+KEY=9ED456A62F364C97AFC38171C8CE265E
+PT=BFAED9E9964967342808C6C332E02204
+CT=5A9F55C61A03D6A3196FFD6879CBCA02
+
+I=211
+KEY=C44B036035359A34B6AC7C19B105EC5C
+PT=5A9F55C61A03D6A3196FFD6879CBCA02
+CT=0FD872478223CDE765A62036EDD6F42F
+
+I=212
+KEY=CB937127B71657D3D30A5C2F5CD31873
+PT=0FD872478223CDE765A62036EDD6F42F
+CT=965ED2AF7D26CDA8A8B7E7B2F1ADA768
+
+I=213
+KEY=5DCDA388CA309A7B7BBDBB9DAD7EBF1B
+PT=965ED2AF7D26CDA8A8B7E7B2F1ADA768
+CT=05599B8D42D92457605A69200C6DC0AA
+
+I=214
+KEY=5894380588E9BE2C1BE7D2BDA1137FB1
+PT=05599B8D42D92457605A69200C6DC0AA
+CT=3436A49EE590788F625A6FB44BF72FA3
+
+I=215
+KEY=6CA29C9B6D79C6A379BDBD09EAE45012
+PT=3436A49EE590788F625A6FB44BF72FA3
+CT=DB181195EFF35E307167BADA138A837A
+
+I=216
+KEY=B7BA8D0E828A989308DA07D3F96ED368
+PT=DB181195EFF35E307167BADA138A837A
+CT=45E06B534233447E3CB696C1DD179477
+
+I=217
+KEY=F25AE65DC0B9DCED346C91122479471F
+PT=45E06B534233447E3CB696C1DD179477
+CT=D2EDC4E2B4EDD671D984E8AA5BABAAD7
+
+I=218
+KEY=20B722BF74540A9CEDE879B87FD2EDC8
+PT=D2EDC4E2B4EDD671D984E8AA5BABAAD7
+CT=DB92F4E9F2DD6A61E20A79CFC82CD061
+
+I=219
+KEY=FB25D656868960FD0FE20077B7FE3DA9
+PT=DB92F4E9F2DD6A61E20A79CFC82CD061
+CT=79383629DF124FD94A1C36BECB711747
+
+I=220
+KEY=821DE07F599B2F2445FE36C97C8F2AEE
+PT=79383629DF124FD94A1C36BECB711747
+CT=3F3F592FB3DB51CF08B70E6F2174AB43
+
+I=221
+KEY=BD22B950EA407EEB4D4938A65DFB81AD
+PT=3F3F592FB3DB51CF08B70E6F2174AB43
+CT=D34FDA2917E9697118502CB7A6CAE07C
+
+I=222
+KEY=6E6D6379FDA9179A55191411FB3161D1
+PT=D34FDA2917E9697118502CB7A6CAE07C
+CT=24D2C38E5C52A404DBE0D8BB6DA44AEE
+
+I=223
+KEY=4ABFA0F7A1FBB39E8EF9CCAA96952B3F
+PT=24D2C38E5C52A404DBE0D8BB6DA44AEE
+CT=2ED6A7503B3547C04E0B7B709218CD4A
+
+I=224
+KEY=646907A79ACEF45EC0F2B7DA048DE675
+PT=2ED6A7503B3547C04E0B7B709218CD4A
+CT=4F11BE7A8B5D1A04AB82F60000BC7B50
+
+I=225
+KEY=2B78B9DD1193EE5A6B7041DA04319D25
+PT=4F11BE7A8B5D1A04AB82F60000BC7B50
+CT=B98B51B76B262CB9ED157567A05770AF
+
+I=226
+KEY=92F3E86A7AB5C2E3866534BDA466ED8A
+PT=B98B51B76B262CB9ED157567A05770AF
+CT=D6CA5483F89D5AA01DBCFEBE30C26F5E
+
+I=227
+KEY=4439BCE9822898439BD9CA0394A482D4
+PT=D6CA5483F89D5AA01DBCFEBE30C26F5E
+CT=7706922EBA53937E287084C8FDFEB33F
+
+I=228
+KEY=333F2EC7387B0B3DB3A94ECB695A31EB
+PT=7706922EBA53937E287084C8FDFEB33F
+CT=0F2DA3B8BFCB1046CA94EC9322320BF9
+
+I=229
+KEY=3C128D7F87B01B7B793DA2584B683A12
+PT=0F2DA3B8BFCB1046CA94EC9322320BF9
+CT=29CAD5CDC5A2834A5D533335FED2EA81
+
+I=230
+KEY=15D858B242129831246E916DB5BAD093
+PT=29CAD5CDC5A2834A5D533335FED2EA81
+CT=A48A2D319552BF02E84E4662E75884DB
+
+I=231
+KEY=B1527583D7402733CC20D70F52E25448
+PT=A48A2D319552BF02E84E4662E75884DB
+CT=334560ECD22BB9F660BC4FFAB13891C9
+
+I=232
+KEY=8217156F056B9EC5AC9C98F5E3DAC581
+PT=334560ECD22BB9F660BC4FFAB13891C9
+CT=DAAEB8436205DFB6688D9DE0A21A6B9D
+
+I=233
+KEY=58B9AD2C676E4173C411051541C0AE1C
+PT=DAAEB8436205DFB6688D9DE0A21A6B9D
+CT=E38798615C2158872704125A7CFC6540
+
+I=234
+KEY=BB3E354D3B4F19F4E315174F3D3CCB5C
+PT=E38798615C2158872704125A7CFC6540
+CT=BACB9EA5499A093F6595E8D1D5CF7E50
+
+I=235
+KEY=01F5ABE872D510CB8680FF9EE8F3B50C
+PT=BACB9EA5499A093F6595E8D1D5CF7E50
+CT=813B0D4AC4C2B8371A1A132927D24F62
+
+I=236
+KEY=80CEA6A2B617A8FC9C9AECB7CF21FA6E
+PT=813B0D4AC4C2B8371A1A132927D24F62
+CT=D1AD1AE650B377520EE19370D9E968A9
+
+I=237
+KEY=5163BC44E6A4DFAE927B7FC716C892C7
+PT=D1AD1AE650B377520EE19370D9E968A9
+CT=3CEC25102A51A5A4C26E7391590D54ED
+
+I=238
+KEY=6D8F9954CCF57A0A50150C564FC5C62A
+PT=3CEC25102A51A5A4C26E7391590D54ED
+CT=505FD54017E89E9FAA6376E399F2FF09
+
+I=239
+KEY=3DD04C14DB1DE495FA767AB5D6373923
+PT=505FD54017E89E9FAA6376E399F2FF09
+CT=1B45550B4E3AB908A2CC72FFFB38701A
+
+I=240
+KEY=2695191F95275D9D58BA084A2D0F4939
+PT=1B45550B4E3AB908A2CC72FFFB38701A
+CT=E2469D9D2F91E3AA88DC7970C94E7237
+
+I=241
+KEY=C4D38482BAB6BE37D066713AE4413B0E
+PT=E2469D9D2F91E3AA88DC7970C94E7237
+CT=9352C72F2B5093D1AF52BA959963F59B
+
+I=242
+KEY=578143AD91E62DE67F34CBAF7D22CE95
+PT=9352C72F2B5093D1AF52BA959963F59B
+CT=F26DE32F035B270BA42075574056564E
+
+I=243
+KEY=A5ECA08292BD0AEDDB14BEF83D7498DB
+PT=F26DE32F035B270BA42075574056564E
+CT=6AC08B3D91FC31A34B3A81F7C300587E
+
+I=244
+KEY=CF2C2BBF03413B4E902E3F0FFE74C0A5
+PT=6AC08B3D91FC31A34B3A81F7C300587E
+CT=E5E6455304C3B5E2349E2372D6E4B0B8
+
+I=245
+KEY=2ACA6EEC07828EACA4B01C7D2890701D
+PT=E5E6455304C3B5E2349E2372D6E4B0B8
+CT=90524F27C63CCA1E4CA9674381786C30
+
+I=246
+KEY=BA9821CBC1BE44B2E8197B3EA9E81C2D
+PT=90524F27C63CCA1E4CA9674381786C30
+CT=44625D68290415039E2C6C05B4954896
+
+I=247
+KEY=FEFA7CA3E8BA51B17635173B1D7D54BB
+PT=44625D68290415039E2C6C05B4954896
+CT=EC401B0D3780FDB4A3952706B07F6CEF
+
+I=248
+KEY=12BA67AEDF3AAC05D5A0303DAD023854
+PT=EC401B0D3780FDB4A3952706B07F6CEF
+CT=DCEDC88021F6FD1C61C08DAABF0E73BA
+
+I=249
+KEY=CE57AF2EFECC5119B460BD97120C4BEE
+PT=DCEDC88021F6FD1C61C08DAABF0E73BA
+CT=C15C85D8161B97DD61EB8B514CDCFFD5
+
+I=250
+KEY=0F0B2AF6E8D7C6C4D58B36C65ED0B43B
+PT=C15C85D8161B97DD61EB8B514CDCFFD5
+CT=B68B65E041C84433DEA4D9E15E9F98AB
+
+I=251
+KEY=B9804F16A91F82F70B2FEF27004F2C90
+PT=B68B65E041C84433DEA4D9E15E9F98AB
+CT=8122505A5B6F8D985A8D9D7E9E2FF4F3
+
+I=252
+KEY=38A21F4CF2700F6F51A272599E60D863
+PT=8122505A5B6F8D985A8D9D7E9E2FF4F3
+CT=8F72F8FFA71D24C900D2BBE8784B9C48
+
+I=253
+KEY=B7D0E7B3556D2BA65170C9B1E62B442B
+PT=8F72F8FFA71D24C900D2BBE8784B9C48
+CT=1D541D794774264680CF3689365CD845
+
+I=254
+KEY=AA84FACA12190DE0D1BFFF38D0779C6E
+PT=1D541D794774264680CF3689365CD845
+CT=CBAE9336C5C1F038176B5123CC205BF7
+
+I=255
+KEY=612A69FCD7D8FDD8C6D4AE1B1C57C799
+PT=CBAE9336C5C1F038176B5123CC205BF7
+CT=C4CE2DC1BAE3028392BD8A005A360F56
+
+I=256
+KEY=A5E4443D6D3BFF5B5469241B4661C8CF
+PT=C4CE2DC1BAE3028392BD8A005A360F56
+CT=549B7075DE975B759A6DAE7D761CDC01
+
+I=257
+KEY=F17F3448B3ACA42ECE048A66307D14CE
+PT=549B7075DE975B759A6DAE7D761CDC01
+CT=2338FFEEE2A391B2DAFD1EBB0ECF19E3
+
+I=258
+KEY=D247CBA6510F359C14F994DD3EB20D2D
+PT=2338FFEEE2A391B2DAFD1EBB0ECF19E3
+CT=B27705C512C6849DE6012A490F834F36
+
+I=259
+KEY=6030CE6343C9B101F2F8BE943131421B
+PT=B27705C512C6849DE6012A490F834F36
+CT=33A239E0426921192F8C89C6FBCDD23C
+
+I=260
+KEY=5392F78301A09018DD743752CAFC9027
+PT=33A239E0426921192F8C89C6FBCDD23C
+CT=90CCBE46338C7E9FB25409F82BF81234
+
+I=261
+KEY=C35E49C5322CEE876F203EAAE1048213
+PT=90CCBE46338C7E9FB25409F82BF81234
+CT=873D1CAF1F2C2A56BEE419FE8A01489F
+
+I=262
+KEY=4463556A2D00C4D1D1C427546B05CA8C
+PT=873D1CAF1F2C2A56BEE419FE8A01489F
+CT=1E9ED35EB85ADD9AB88B6D85299FD8E7
+
+I=263
+KEY=5AFD8634955A194B694F4AD1429A126B
+PT=1E9ED35EB85ADD9AB88B6D85299FD8E7
+CT=36871F8BD629B27EEDE04E086FC539C4
+
+I=264
+KEY=6C7A99BF4373AB3584AF04D92D5F2BAF
+PT=36871F8BD629B27EEDE04E086FC539C4
+CT=10D10983F98D799235E8142BD67C1FD2
+
+I=265
+KEY=7CAB903CBAFED2A7B14710F2FB23347D
+PT=10D10983F98D799235E8142BD67C1FD2
+CT=193CEDEEE0410DE79F1B2FC077B14199
+
+I=266
+KEY=65977DD25ABFDF402E5C3F328C9275E4
+PT=193CEDEEE0410DE79F1B2FC077B14199
+CT=1EC99AD6EEF155B6B5F61452D2E73A7D
+
+I=267
+KEY=7B5EE704B44E8AF69BAA2B605E754F99
+PT=1EC99AD6EEF155B6B5F61452D2E73A7D
+CT=92DA7D1858210C87B32C6FEA1CC6A0E6
+
+I=268
+KEY=E9849A1CEC6F86712886448A42B3EF7F
+PT=92DA7D1858210C87B32C6FEA1CC6A0E6
+CT=A06C4ACCA35DE95CFAD365349969271D
+
+I=269
+KEY=49E8D0D04F326F2DD25521BEDBDAC862
+PT=A06C4ACCA35DE95CFAD365349969271D
+CT=4B892CB63A35A3DED0F43BA4309CBB2E
+
+I=270
+KEY=0261FC667507CCF302A11A1AEB46734C
+PT=4B892CB63A35A3DED0F43BA4309CBB2E
+CT=E05F73446706A68A5099088279B58064
+
+I=271
+KEY=E23E8F2212016A795238129892F3F328
+PT=E05F73446706A68A5099088279B58064
+CT=542D8314299AF433EC549EBFFCF2B3D9
+
+I=272
+KEY=B6130C363B9B9E4ABE6C8C276E0140F1
+PT=542D8314299AF433EC549EBFFCF2B3D9
+CT=4935A91590E8A70D9F75489F6D5B70E7
+
+I=273
+KEY=FF26A523AB7339472119C4B8035A3016
+PT=4935A91590E8A70D9F75489F6D5B70E7
+CT=C3A4940C6EC7D0E2F11C3CF60AB2C31D
+
+I=274
+KEY=3C82312FC5B4E9A5D005F84E09E8F30B
+PT=C3A4940C6EC7D0E2F11C3CF60AB2C31D
+CT=F109AC488D917B5FC28BA28C9720A46F
+
+I=275
+KEY=CD8B9D67482592FA128E5AC29EC85764
+PT=F109AC488D917B5FC28BA28C9720A46F
+CT=65234934641FA21D8C3A3804D09208F3
+
+I=276
+KEY=A8A8D4532C3A30E79EB462C64E5A5F97
+PT=65234934641FA21D8C3A3804D09208F3
+CT=DE015A71CB9C9A3B11C2C9B744B6B5ED
+
+I=277
+KEY=76A98E22E7A6AADC8F76AB710AECEA7A
+PT=DE015A71CB9C9A3B11C2C9B744B6B5ED
+CT=973D0C12D7826B45CC7824EF09D82BAB
+
+I=278
+KEY=E19482303024C199430E8F9E0334C1D1
+PT=973D0C12D7826B45CC7824EF09D82BAB
+CT=EBD2D23B9D08F63385A0D21FF76FAC33
+
+I=279
+KEY=0A46500BAD2C37AAC6AE5D81F45B6DE2
+PT=EBD2D23B9D08F63385A0D21FF76FAC33
+CT=A7A460A555E4C4E53457AE00FC0D9BA8
+
+I=280
+KEY=ADE230AEF8C8F34FF2F9F3810856F64A
+PT=A7A460A555E4C4E53457AE00FC0D9BA8
+CT=56F0329103B5238E03C781E2AB0E7A2D
+
+I=281
+KEY=FB12023FFB7DD0C1F13E7263A3588C67
+PT=56F0329103B5238E03C781E2AB0E7A2D
+CT=0D5710472E980CF439109BAC3EAB19A8
+
+I=282
+KEY=F6451278D5E5DC35C82EE9CF9DF395CF
+PT=0D5710472E980CF439109BAC3EAB19A8
+CT=063CB786AD88ECADC4EAC8FE39A84286
+
+I=283
+KEY=F079A5FE786D30980CC42131A45BD749
+PT=063CB786AD88ECADC4EAC8FE39A84286
+CT=825BD1E57F0E16D744C2A69233C8654B
+
+I=284
+KEY=7222741B0763264F480687A39793B202
+PT=825BD1E57F0E16D744C2A69233C8654B
+CT=8EA54322F26DC051F831A5CBBD07A73C
+
+I=285
+KEY=FC873739F50EE61EB03722682A94153E
+PT=8EA54322F26DC051F831A5CBBD07A73C
+CT=803F3194726F4D5C5BD80D12D1284F0A
+
+I=286
+KEY=7CB806AD8761AB42EBEF2F7AFBBC5A34
+PT=803F3194726F4D5C5BD80D12D1284F0A
+CT=5A1D90E682989AB1A84F01422CE69F82
+
+I=287
+KEY=26A5964B05F931F343A02E38D75AC5B6
+PT=5A1D90E682989AB1A84F01422CE69F82
+CT=3F5AFCD41950EEFBC3D7CEF744F0C060
+
+I=288
+KEY=19FF6A9F1CA9DF088077E0CF93AA05D6
+PT=3F5AFCD41950EEFBC3D7CEF744F0C060
+CT=2EE3691BD58D7645DA91CD4943F10157
+
+I=289
+KEY=371C0384C924A94D5AE62D86D05B0481
+PT=2EE3691BD58D7645DA91CD4943F10157
+CT=BEF4B188364E87A9E49855CC68C02A50
+
+I=290
+KEY=89E8B20CFF6A2EE4BE7E784AB89B2ED1
+PT=BEF4B188364E87A9E49855CC68C02A50
+CT=2263387A7A52AB73704774D07EA5AA69
+
+I=291
+KEY=AB8B8A7685388597CE390C9AC63E84B8
+PT=2263387A7A52AB73704774D07EA5AA69
+CT=84E68DA3E9D999016D0B734DAE8C128B
+
+I=292
+KEY=2F6D07D56CE11C96A3327FD768B29633
+PT=84E68DA3E9D999016D0B734DAE8C128B
+CT=978F5F49D7BA1189F16FC0635231DF5F
+
+I=293
+KEY=B8E2589CBB5B0D1F525DBFB43A83496C
+PT=978F5F49D7BA1189F16FC0635231DF5F
+CT=FE59B2F2BDE0AB5E1700A1771EDF8663
+
+I=294
+KEY=46BBEA6E06BBA641455D1EC3245CCF0F
+PT=FE59B2F2BDE0AB5E1700A1771EDF8663
+CT=A94B982DC50C338E25ABFB4113F904A8
+
+I=295
+KEY=EFF07243C3B795CF60F6E58237A5CBA7
+PT=A94B982DC50C338E25ABFB4113F904A8
+CT=79A5BB282D8247192AC9F8A3DB431EA1
+
+I=296
+KEY=9655C96BEE35D2D64A3F1D21ECE6D506
+PT=79A5BB282D8247192AC9F8A3DB431EA1
+CT=FC339DA0D4593CD79D407CD6F1E1E7ED
+
+I=297
+KEY=6A6654CB3A6CEE01D77F61F71D0732EB
+PT=FC339DA0D4593CD79D407CD6F1E1E7ED
+CT=08EAB51652B85C6E9BC07B718E57E144
+
+I=298
+KEY=628CE1DD68D4B26F4CBF1A869350D3AF
+PT=08EAB51652B85C6E9BC07B718E57E144
+CT=9EA63934609F947AAA926443D0D5BEFA
+
+I=299
+KEY=FC2AD8E9084B2615E62D7EC543856D55
+PT=9EA63934609F947AAA926443D0D5BEFA
+CT=7FE121C45E158FF1F527BAFDDBEAE223
+
+I=300
+KEY=83CBF92D565EA9E4130AC438986F8F76
+PT=7FE121C45E158FF1F527BAFDDBEAE223
+CT=B1B70D5AD08BE5DCB8126D8700F25969
+
+I=301
+KEY=327CF47786D54C38AB18A9BF989DD61F
+PT=B1B70D5AD08BE5DCB8126D8700F25969
+CT=389812FA2D4A6419380A2AC8961CCDA6
+
+I=302
+KEY=0AE4E68DAB9F2821931283770E811BB9
+PT=389812FA2D4A6419380A2AC8961CCDA6
+CT=CEF20323EE53A2BA576F4DF86A7AC078
+
+I=303
+KEY=C416E5AE45CC8A9BC47DCE8F64FBDBC1
+PT=CEF20323EE53A2BA576F4DF86A7AC078
+CT=A65611BF1901C940B883D746F1694278
+
+I=304
+KEY=6240F4115CCD43DB7CFE19C9959299B9
+PT=A65611BF1901C940B883D746F1694278
+CT=7E43C2A99D11C656351B96CECD400E75
+
+I=305
+KEY=1C0336B8C1DC858D49E58F0758D297CC
+PT=7E43C2A99D11C656351B96CECD400E75
+CT=7DE74D06851AD329C60DD1934C34CBE4
+
+I=306
+KEY=61E47BBE44C656A48FE85E9414E65C28
+PT=7DE74D06851AD329C60DD1934C34CBE4
+CT=A99B66FE5825C895DCC6BE718AB8BE34
+
+I=307
+KEY=C87F1D401CE39E31532EE0E59E5EE21C
+PT=A99B66FE5825C895DCC6BE718AB8BE34
+CT=4752E30DDA44BA393EF197270C111AB7
+
+I=308
+KEY=8F2DFE4DC6A724086DDF77C2924FF8AB
+PT=4752E30DDA44BA393EF197270C111AB7
+CT=5A3FC324D12AC30FE5BBE87FC4B655F0
+
+I=309
+KEY=D5123D69178DE70788649FBD56F9AD5B
+PT=5A3FC324D12AC30FE5BBE87FC4B655F0
+CT=79061587E9D9FEEF52F753AE9BCDC4B1
+
+I=310
+KEY=AC1428EEFE5419E8DA93CC13CD3469EA
+PT=79061587E9D9FEEF52F753AE9BCDC4B1
+CT=86C32E69874EAA0D103581199AFA813A
+
+I=311
+KEY=2AD70687791AB3E5CAA64D0A57CEE8D0
+PT=86C32E69874EAA0D103581199AFA813A
+CT=82A924A5928570E29D18DE200F8558DD
+
+I=312
+KEY=A87E2222EB9FC30757BE932A584BB00D
+PT=82A924A5928570E29D18DE200F8558DD
+CT=2D3E0ECCC1FEA93736BD205A5217D830
+
+I=313
+KEY=85402CEE2A616A306103B3700A5C683D
+PT=2D3E0ECCC1FEA93736BD205A5217D830
+CT=52FA0FCF771191A4A4C4E48C7B11DC1F
+
+I=314
+KEY=D7BA23215D70FB94C5C757FC714DB422
+PT=52FA0FCF771191A4A4C4E48C7B11DC1F
+CT=C2A47519AACA187B97C884D20ED1D825
+
+I=315
+KEY=151E5638F7BAE3EF520FD32E7F9C6C07
+PT=C2A47519AACA187B97C884D20ED1D825
+CT=66F1D0799F3C473978C189F745695293
+
+I=316
+KEY=73EF86416886A4D62ACE5AD93AF53E94
+PT=66F1D0799F3C473978C189F745695293
+CT=803361A1428EAC3E134B0726E5CF0754
+
+I=317
+KEY=F3DCE7E02A0808E839855DFFDF3A39C0
+PT=803361A1428EAC3E134B0726E5CF0754
+CT=2CC85CEDEE03D7AB279D766D3F2BADF4
+
+I=318
+KEY=DF14BB0DC40BDF431E182B92E0119434
+PT=2CC85CEDEE03D7AB279D766D3F2BADF4
+CT=706626C1CE6731DD4DBA263C4D7EAB67
+
+I=319
+KEY=AF729DCC0A6CEE9E53A20DAEAD6F3F53
+PT=706626C1CE6731DD4DBA263C4D7EAB67
+CT=BD7A59659E3774B85465C91740017628
+
+I=320
+KEY=1208C4A9945B9A2607C7C4B9ED6E497B
+PT=BD7A59659E3774B85465C91740017628
+CT=F1778330059467556D08223682EC32AA
+
+I=321
+KEY=E37F479991CFFD736ACFE68F6F827BD1
+PT=F1778330059467556D08223682EC32AA
+CT=7B3C6979DCEE500E3FBB2CF4E17B0A3B
+
+I=322
+KEY=98432EE04D21AD7D5574CA7B8EF971EA
+PT=7B3C6979DCEE500E3FBB2CF4E17B0A3B
+CT=AFEBC6E81B90C3D82ECE26D788AB2412
+
+I=323
+KEY=37A8E80856B16EA57BBAECAC065255F8
+PT=AFEBC6E81B90C3D82ECE26D788AB2412
+CT=E4087042AB32B9C43128AADACB4F7FA6
+
+I=324
+KEY=D3A0984AFD83D7614A924676CD1D2A5E
+PT=E4087042AB32B9C43128AADACB4F7FA6
+CT=07E1230BC456A3DCE7DF8A4EF7265BC8
+
+I=325
+KEY=D441BB4139D574BDAD4DCC383A3B7196
+PT=07E1230BC456A3DCE7DF8A4EF7265BC8
+CT=88F0C30172B9A0EA8CD657CE6847AC94
+
+I=326
+KEY=5CB178404B6CD457219B9BF6527CDD02
+PT=88F0C30172B9A0EA8CD657CE6847AC94
+CT=710FE26B2DAB5A12D147D6446732B272
+
+I=327
+KEY=2DBE9A2B66C78E45F0DC4DB2354E6F70
+PT=710FE26B2DAB5A12D147D6446732B272
+CT=9C30630A9ADF9B4EBF099452AB75D14A
+
+I=328
+KEY=B18EF921FC18150B4FD5D9E09E3BBE3A
+PT=9C30630A9ADF9B4EBF099452AB75D14A
+CT=77526DA4D9AE9FD4347AAC10EA4728AA
+
+I=329
+KEY=C6DC948525B68ADF7BAF75F0747C9690
+PT=77526DA4D9AE9FD4347AAC10EA4728AA
+CT=A9EDBD1A190BC67AC91D27BB7F5A1BD1
+
+I=330
+KEY=6F31299F3CBD4CA5B2B2524B0B268D41
+PT=A9EDBD1A190BC67AC91D27BB7F5A1BD1
+CT=B8700A2BAEABCB0C67251C26F82ACEF7
+
+I=331
+KEY=D74123B4921687A9D5974E6DF30C43B6
+PT=B8700A2BAEABCB0C67251C26F82ACEF7
+CT=FF5F30BA14A8C49276B040B00864BE29
+
+I=332
+KEY=281E130E86BE433BA3270EDDFB68FD9F
+PT=FF5F30BA14A8C49276B040B00864BE29
+CT=B448E87BE1E1A41FF94353F6018929C8
+
+I=333
+KEY=9C56FB75675FE7245A645D2BFAE1D457
+PT=B448E87BE1E1A41FF94353F6018929C8
+CT=9F59D422CB9265C17732E0B16DEF352A
+
+I=334
+KEY=030F2F57ACCD82E52D56BD9A970EE17D
+PT=9F59D422CB9265C17732E0B16DEF352A
+CT=06FD7DB54E62FAC3C511F4DE5C1E93B9
+
+I=335
+KEY=05F252E2E2AF7826E8474944CB1072C4
+PT=06FD7DB54E62FAC3C511F4DE5C1E93B9
+CT=0DDA3E4AD600F8D3EA6B06AE465DF3BC
+
+I=336
+KEY=08286CA834AF80F5022C4FEA8D4D8178
+PT=0DDA3E4AD600F8D3EA6B06AE465DF3BC
+CT=17305FA95D26FB72995165DA8A07FCDF
+
+I=337
+KEY=1F18330169897B879B7D2A30074A7DA7
+PT=17305FA95D26FB72995165DA8A07FCDF
+CT=12B56FEBEE2773A2258FC6E0F9115728
+
+I=338
+KEY=0DAD5CEA87AE0825BEF2ECD0FE5B2A8F
+PT=12B56FEBEE2773A2258FC6E0F9115728
+CT=36440D1A561E8F77B89DF6EA3D8EC7F5
+
+I=339
+KEY=3BE951F0D1B08752066F1A3AC3D5ED7A
+PT=36440D1A561E8F77B89DF6EA3D8EC7F5
+CT=752C4D620413C0F4A313CF37EB34CFDD
+
+I=340
+KEY=4EC51C92D5A347A6A57CD50D28E122A7
+PT=752C4D620413C0F4A313CF37EB34CFDD
+CT=B2A282D0B6A9EB8B7B7C962675AEC843
+
+I=341
+KEY=FC679E42630AAC2DDE00432B5D4FEAE4
+PT=B2A282D0B6A9EB8B7B7C962675AEC843
+CT=D0C3D785B5507C1460DDC44B123ED5FE
+
+I=342
+KEY=2CA449C7D65AD039BEDD87604F713F1A
+PT=D0C3D785B5507C1460DDC44B123ED5FE
+CT=4DAE52B77F8001CBAB8D1949E73DD578
+
+I=343
+KEY=610A1B70A9DAD1F215509E29A84CEA62
+PT=4DAE52B77F8001CBAB8D1949E73DD578
+CT=29AA82197E8158D88FFFE5BEAFC0C967
+
+I=344
+KEY=48A09969D75B892A9AAF7B97078C2305
+PT=29AA82197E8158D88FFFE5BEAFC0C967
+CT=58C665AA97945F7D3AA23BE8B8DDA20D
+
+I=345
+KEY=1066FCC340CFD657A00D407FBF518108
+PT=58C665AA97945F7D3AA23BE8B8DDA20D
+CT=5A104A7093DB3308EB4009829B5E26B1
+
+I=346
+KEY=4A76B6B3D314E55F4B4D49FD240FA7B9
+PT=5A104A7093DB3308EB4009829B5E26B1
+CT=8C8EA0BEE4640F6BB6D906A7A6EA3810
+
+I=347
+KEY=C6F8160D3770EA34FD944F5A82E59FA9
+PT=8C8EA0BEE4640F6BB6D906A7A6EA3810
+CT=1517ED0B6D4EC3B85479AB28DF48BFDB
+
+I=348
+KEY=D3EFFB065A3E298CA9EDE4725DAD2072
+PT=1517ED0B6D4EC3B85479AB28DF48BFDB
+CT=9546CCBB8094E65E464C38E0809552E3
+
+I=349
+KEY=46A937BDDAAACFD2EFA1DC92DD387291
+PT=9546CCBB8094E65E464C38E0809552E3
+CT=7D5AD8DEDB92F80D2B28C3458843AE84
+
+I=350
+KEY=3BF3EF63013837DFC4891FD7557BDC15
+PT=7D5AD8DEDB92F80D2B28C3458843AE84
+CT=E62676E27ED61D0FD7DFE170E0938361
+
+I=351
+KEY=DDD599817FEE2AD01356FEA7B5E85F74
+PT=E62676E27ED61D0FD7DFE170E0938361
+CT=DA9865198B9463681C66FB96C2C1DAA5
+
+I=352
+KEY=074DFC98F47A49B80F300531772985D1
+PT=DA9865198B9463681C66FB96C2C1DAA5
+CT=62CD9DAA9487F34AF168E6E20A0684CF
+
+I=353
+KEY=6580613260FDBAF2FE58E3D37D2F011E
+PT=62CD9DAA9487F34AF168E6E20A0684CF
+CT=10BA978FDABA586691946145BE246D3C
+
+I=354
+KEY=753AF6BDBA47E2946FCC8296C30B6C22
+PT=10BA978FDABA586691946145BE246D3C
+CT=13443CF524213B08776D7F5169B79C0F
+
+I=355
+KEY=667ECA489E66D99C18A1FDC7AABCF02D
+PT=13443CF524213B08776D7F5169B79C0F
+CT=6507336876ED4F6DB3E35D6CF5A89A2B
+
+I=356
+KEY=0379F920E88B96F1AB42A0AB5F146A06
+PT=6507336876ED4F6DB3E35D6CF5A89A2B
+CT=B84902B5CBBC6DB8111CA45BC5F99991
+
+I=357
+KEY=BB30FB952337FB49BA5E04F09AEDF397
+PT=B84902B5CBBC6DB8111CA45BC5F99991
+CT=20973140A999B8AD9982B9B706F7C32E
+
+I=358
+KEY=9BA7CAD58AAE43E423DCBD479C1A30B9
+PT=20973140A999B8AD9982B9B706F7C32E
+CT=EE7FF1177C5E080AA03854A2A819565E
+
+I=359
+KEY=75D83BC2F6F04BEE83E4E9E5340366E7
+PT=EE7FF1177C5E080AA03854A2A819565E
+CT=7A4F74EC2181269AC17D0E48A4DA2A88
+
+I=360
+KEY=0F974F2ED7716D744299E7AD90D94C6F
+PT=7A4F74EC2181269AC17D0E48A4DA2A88
+CT=5B7A7751F0FD91E203A14CE518838DD7
+
+I=361
+KEY=54ED387F278CFC964138AB48885AC1B8
+PT=5B7A7751F0FD91E203A14CE518838DD7
+CT=71319FDDBACB038354A37A41F1910F94
+
+I=362
+KEY=25DCA7A29D47FF15159BD10979CBCE2C
+PT=71319FDDBACB038354A37A41F1910F94
+CT=81AC58FD503FC3AA78199168AE2C9085
+
+I=363
+KEY=A470FF5FCD783CBF6D824061D7E75EA9
+PT=81AC58FD503FC3AA78199168AE2C9085
+CT=1F668F512038142C1155B950B0B040EC
+
+I=364
+KEY=BB16700EED4028937CD7F93167571E45
+PT=1F668F512038142C1155B950B0B040EC
+CT=6B27D7791E9B14A5AC3D9582DBDBD929
+
+I=365
+KEY=D031A777F3DB3C36D0EA6CB3BC8CC76C
+PT=6B27D7791E9B14A5AC3D9582DBDBD929
+CT=9B7151FDC4E135EE93DAB2D9EB74D59C
+
+I=366
+KEY=4B40F68A373A09D84330DE6A57F812F0
+PT=9B7151FDC4E135EE93DAB2D9EB74D59C
+CT=1F199945BCFA624B1AD3DCBBD95291B2
+
+I=367
+KEY=54596FCF8BC06B9359E302D18EAA8342
+PT=1F199945BCFA624B1AD3DCBBD95291B2
+CT=E2C82FA8FE98F26283A6E0B75D0A58C6
+
+I=368
+KEY=B6914067755899F1DA45E266D3A0DB84
+PT=E2C82FA8FE98F26283A6E0B75D0A58C6
+CT=5A240FFB99C3594C273B51CACF01B28B
+
+I=369
+KEY=ECB54F9CEC9BC0BDFD7EB3AC1CA1690F
+PT=5A240FFB99C3594C273B51CACF01B28B
+CT=D01847391534848FB102CA85C97749B1
+
+I=370
+KEY=3CAD08A5F9AF44324C7C7929D5D620BE
+PT=D01847391534848FB102CA85C97749B1
+CT=DC5CF60EBDF4A8DDDDF997E7ACA67515
+
+I=371
+KEY=E0F1FEAB445BECEF9185EECE797055AB
+PT=DC5CF60EBDF4A8DDDDF997E7ACA67515
+CT=749E3815FE305B307D9F4DB6A7E4658C
+
+I=372
+KEY=946FC6BEBA6BB7DFEC1AA378DE943027
+PT=749E3815FE305B307D9F4DB6A7E4658C
+CT=8152C1E676A4FC8B0CD093FEB4B51615
+
+I=373
+KEY=153D0758CCCF4B54E0CA30866A212632
+PT=8152C1E676A4FC8B0CD093FEB4B51615
+CT=0847044668710F6E5C93DD248AC921BA
+
+I=374
+KEY=1D7A031EA4BE443ABC59EDA2E0E80788
+PT=0847044668710F6E5C93DD248AC921BA
+CT=1D6C3EFB413A59AB40F34CEFBFF25C17
+
+I=375
+KEY=00163DE5E5841D91FCAAA14D5F1A5B9F
+PT=1D6C3EFB413A59AB40F34CEFBFF25C17
+CT=5D7C206A79D61868FFE7AA28044996D3
+
+I=376
+KEY=5D6A1D8F9C5205F9034D0B655B53CD4C
+PT=5D7C206A79D61868FFE7AA28044996D3
+CT=78B4DE3B84D5D1010245CA3077A41BAC
+
+I=377
+KEY=25DEC3B41887D4F80108C1552CF7D6E0
+PT=78B4DE3B84D5D1010245CA3077A41BAC
+CT=9E003AACEDECDBB077BDE832465F40C7
+
+I=378
+KEY=BBDEF918F56B0F4876B529676AA89627
+PT=9E003AACEDECDBB077BDE832465F40C7
+CT=EEFF9E6C73E6DC5432AA446385AA1499
+
+I=379
+KEY=55216774868DD31C441F6D04EF0282BE
+PT=EEFF9E6C73E6DC5432AA446385AA1499
+CT=03252A19E37D9F040C56E4D712982798
+
+I=380
+KEY=56044D6D65F04C18484989D3FD9AA526
+PT=03252A19E37D9F040C56E4D712982798
+CT=CF59A752BA0E14BE23AFD09437B39C65
+
+I=381
+KEY=995DEA3FDFFE58A66BE65947CA293943
+PT=CF59A752BA0E14BE23AFD09437B39C65
+CT=8B08FB7974A77167DFB234F57C8DFFE1
+
+I=382
+KEY=12551146AB5929C1B4546DB2B6A4C6A2
+PT=8B08FB7974A77167DFB234F57C8DFFE1
+CT=DD2A93C1106CFDAE4A1684EE02C82FE2
+
+I=383
+KEY=CF7F8287BB35D46FFE42E95CB46CE940
+PT=DD2A93C1106CFDAE4A1684EE02C82FE2
+CT=38696128584F60636354E9F802590391
+
+I=384
+KEY=F716E3AFE37AB40C9D1600A4B635EAD1
+PT=38696128584F60636354E9F802590391
+CT=7E552E3AD28729F642D590E3C289D598
+
+I=385
+KEY=8943CD9531FD9DFADFC3904774BC3F49
+PT=7E552E3AD28729F642D590E3C289D598
+CT=17A40392AA00D7B5A6E9F59007E60C22
+
+I=386
+KEY=9EE7CE079BFD4A4F792A65D7735A336B
+PT=17A40392AA00D7B5A6E9F59007E60C22
+CT=A048D6755C2AD24DD8833DDCEB145BA6
+
+I=387
+KEY=3EAF1872C7D79802A1A9580B984E68CD
+PT=A048D6755C2AD24DD8833DDCEB145BA6
+CT=2F1CCE852396986EC4B2852E5F684CD2
+
+I=388
+KEY=11B3D6F7E441006C651BDD25C726241F
+PT=2F1CCE852396986EC4B2852E5F684CD2
+CT=2C28BD1E98DA63B95C0C81202BBCFE39
+
+I=389
+KEY=3D9B6BE97C9B63D539175C05EC9ADA26
+PT=2C28BD1E98DA63B95C0C81202BBCFE39
+CT=6AE097A8E685B58BA2309B59D6A9EB2B
+
+I=390
+KEY=577BFC419A1ED65E9B27C75C3A33310D
+PT=6AE097A8E685B58BA2309B59D6A9EB2B
+CT=6EFC01751753999843A9BB6749097E0C
+
+I=391
+KEY=3987FD348D4D4FC6D88E7C3B733A4F01
+PT=6EFC01751753999843A9BB6749097E0C
+CT=6B6B75F78016052E4F89C73EA826D2F2
+
+I=392
+KEY=52EC88C30D5B4AE89707BB05DB1C9DF3
+PT=6B6B75F78016052E4F89C73EA826D2F2
+CT=1E9890E8F0AABCBFB8C4EDAEA0F563EF
+
+I=393
+KEY=4C74182BFDF1F6572FC356AB7BE9FE1C
+PT=1E9890E8F0AABCBFB8C4EDAEA0F563EF
+CT=143ED9FE6FD7DFB822C31DE8A3E868A9
+
+I=394
+KEY=584AC1D5922629EF0D004B43D80196B5
+PT=143ED9FE6FD7DFB822C31DE8A3E868A9
+CT=9C2834AA5C95F2874DC6B267C0469E14
+
+I=395
+KEY=C462F57FCEB3DB6840C6F924184708A1
+PT=9C2834AA5C95F2874DC6B267C0469E14
+CT=0720377F673352693EE2EF76D4FCFB0F
+
+I=396
+KEY=C342C200A98089017E241652CCBBF3AE
+PT=0720377F673352693EE2EF76D4FCFB0F
+CT=E83ED303F4B0ABF675C7BBC470B924FE
+
+I=397
+KEY=2B7C11035D3022F70BE3AD96BC02D750
+PT=E83ED303F4B0ABF675C7BBC470B924FE
+CT=D87ADD68CBCAEA46DFFF99AE3723BC94
+
+I=398
+KEY=F306CC6B96FAC8B1D41C34388B216BC4
+PT=D87ADD68CBCAEA46DFFF99AE3723BC94
+CT=2C290AE7C65B6E5BBAA32DE577DBA343
+
+I=399
+KEY=DF2FC68C50A1A6EA6EBF19DDFCFAC887
+PT=2C290AE7C65B6E5BBAA32DE577DBA343
+CT=A04377ABE259B0D0B5BA2D40A501971B
+
+=========================
+
+KEYSIZE=192
+
+I=0
+KEY=000000000000000000000000000000000000000000000000
+PT=00000000000000000000000000000000
+CT=F3F6752AE8D7831138F041560631B114
+
+I=1
+KEY=AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114
+PT=F3F6752AE8D7831138F041560631B114
+CT=77BA00ED5412DFF27C8ED91F3C376172
+
+I=2
+KEY=A92B07597B52873C844C75C7BCC55CE3447E98493A06D066
+PT=77BA00ED5412DFF27C8ED91F3C376172
+CT=2D92DE893574463412BD7D121A94952F
+
+I=3
+KEY=5FD632DA76165EDBA9DEAB4E89B11AD756C3E55B20924549
+PT=2D92DE893574463412BD7D121A94952F
+CT=96650F835912F5E748422727802C6CE1
+
+I=4
+KEY=984A4BEC5D3474103FBBA4CDD0A3EF301E81C27CA0BE29A8
+PT=96650F835912F5E748422727802C6CE1
+CT=5FCCD4B5F125ADC5B85A56DB32283732
+
+I=5
+KEY=6B7EDEEAC755885F60777078218642F5A6DB94A792961E9A
+PT=5FCCD4B5F125ADC5B85A56DB32283732
+CT=EA5B1DAE2E4F9FD254A2CC28E128EB9B
+
+I=6
+KEY=CA5585D8C9727F208A2C6DD60FC9DD27F279588F73BEF501
+PT=EA5B1DAE2E4F9FD254A2CC28E128EB9B
+CT=BB87C0FF5DB4B2A593B93398407F823A
+
+I=7
+KEY=BADA7C0D4A0CDD4631ABAD29527D6F8261C06B1733C1773B
+PT=BB87C0FF5DB4B2A593B93398407F823A
+CT=D5AF7D56281F86E3E079BE6B9465DBB4
+
+I=8
+KEY=FF98AB620A203FFCE404D07F7A62E96181B9D57CA7A4AC8F
+PT=D5AF7D56281F86E3E079BE6B9465DBB4
+CT=511331CCA62B067CAC47475800EE33CD
+
+I=9
+KEY=1186A7F46656EA07B517E1B3DC49EF1D2DFE9224A74A9F42
+PT=511331CCA62B067CAC47475800EE33CD
+CT=64ACDC3579D7871644DD585C582AF3A2
+
+I=10
+KEY=313ADFF9712EABE4D1BB3D86A59E680B6923CA78FF606CE0
+PT=64ACDC3579D7871644DD585C582AF3A2
+CT=EA3C45FB8A6E548DAB14BAE07966246C
+
+I=11
+KEY=DDABAC02BE6C40493B87787D2FF03C86C23770988606488C
+PT=EA3C45FB8A6E548DAB14BAE07966246C
+CT=6BC276C465C9ADBE900049A5B58D2DCB
+
+I=12
+KEY=9A9F7E267C2BFCD150450EB94A3991385237393D338B6547
+PT=6BC276C465C9ADBE900049A5B58D2DCB
+CT=E2F0FFA8D6DF327CA0FB80A325B21931
+
+I=13
+KEY=80246B9FB6224226B2B5F1119CE6A344F2CCB99E16397C76
+PT=E2F0FFA8D6DF327CA0FB80A325B21931
+CT=ACEE4C9B8A00A7760DD9CD2F6C6DFA8C
+
+I=14
+KEY=60CDC3E8265B71E81E5BBD8A16E60432FF1574B17A5486FA
+PT=ACEE4C9B8A00A7760DD9CD2F6C6DFA8C
+CT=9579E43690FD2800FED810F7442D366B
+
+I=15
+KEY=9DEC584DB87D63F48B2259BC861B2C3201CD64463E79B091
+PT=9579E43690FD2800FED810F7442D366B
+CT=72D4D064851A050D415FC94E3FBB6A1C
+
+I=16
+KEY=BBC1ED636907611EF9F689D80301293F4092AD0801C2DA8D
+PT=72D4D064851A050D415FC94E3FBB6A1C
+CT=0CCC3B9B35CE3584D7B78C14905BEE55
+
+I=17
+KEY=AE398529289F7994F53AB24336CF1CBB9725211C919934D8
+PT=0CCC3B9B35CE3584D7B78C14905BEE55
+CT=66B6A61BF7BCC6392B8FEC12152E5363
+
+I=18
+KEY=4617E60BD8AF29D5938C1458C173DA82BCAACD0E84B767BB
+PT=66B6A61BF7BCC6392B8FEC12152E5363
+CT=6C2247EA3BC566A84A30BF0B30AB4EEC
+
+I=19
+KEY=6B762D1391AA17CBFFAE53B2FAB6BC2AF69A7205B41C2957
+PT=6C2247EA3BC566A84A30BF0B30AB4EEC
+CT=C16FBCDFAE34E839BA449D697452550D
+
+I=20
+KEY=374499A8C09A60DA3EC1EF6D548254134CDEEF6CC04E7C5A
+PT=C16FBCDFAE34E839BA449D697452550D
+CT=C8B704B4AFE68AF5C91A810F2873F13F
+
+I=21
+KEY=09DCC638DD59F37CF676EBD9FB64DEE685C46E63E83D8D65
+PT=C8B704B4AFE68AF5C91A810F2873F13F
+CT=FC9C31036B26234ED1CBA46E0BE944EE
+
+I=22
+KEY=CE2CEB8869D7EC160AEADADA9042FDA8540FCA0DE3D4C98B
+PT=FC9C31036B26234ED1CBA46E0BE944EE
+CT=DCF13203AD179CD008779F189EBC78F0
+
+I=23
+KEY=505FBECF6B0B083CD61BE8D93D5561785C7855157D68B17B
+PT=DCF13203AD179CD008779F189EBC78F0
+CT=24AEB937E259D44D352FF39C1A8A79E0
+
+I=24
+KEY=1D1649FDB7484DD2F2B551EEDF0CB5356957A68967E2C89B
+PT=24AEB937E259D44D352FF39C1A8A79E0
+CT=19016D033872CB7694A712A84DBC43F2
+
+I=25
+KEY=9BE41771C0F74BDEEBB43CEDE77E7E43FDF0B4212A5E8B69
+PT=19016D033872CB7694A712A84DBC43F2
+CT=0536107FEA26AB6A4FE2667EF7FCF16A
+
+I=26
+KEY=FF3619AED9A1F724EE822C920D58D529B212D25FDDA27A03
+PT=0536107FEA26AB6A4FE2667EF7FCF16A
+CT=5D35213390FCA53AD422DC2ED4BF674D
+
+I=27
+KEY=59D2F5AF4BB6F28BB3B70DA19DA4701366300E71091D1D4E
+PT=5D35213390FCA53AD422DC2ED4BF674D
+CT=04A6F9B1AE64AD03659C4E375A690852
+
+I=28
+KEY=C8384D35CAF0074EB711F41033C0DD1003AC40465374151C
+PT=04A6F9B1AE64AD03659C4E375A690852
+CT=18AB347EFC2F8F93655E16732BB509DE
+
+I=29
+KEY=910CE58F963B684EAFBAC06ECFEF528366F2563578C11CC2
+PT=18AB347EFC2F8F93655E16732BB509DE
+CT=F6037C06C71793BD14A4FC89A05D918F
+
+I=30
+KEY=5D1EF94FBA1E098459B9BC6808F8C13E7256AABCD89C8D4D
+PT=F6037C06C71793BD14A4FC89A05D918F
+CT=75094DD9B2FDDAC96B49CAB676057288
+
+I=31
+KEY=61FDA8DA3EF8949C2CB0F1B1BA051BF7191F600AAE99FFC5
+PT=75094DD9B2FDDAC96B49CAB676057288
+CT=346F9F9E70C05B53DCDAF736FE59749D
+
+I=32
+KEY=5C383CCC2DCAE66A18DF6E2FCAC540A4C5C5973C50C08B58
+PT=346F9F9E70C05B53DCDAF736FE59749D
+CT=1DB82CC8EF5B736AAEFD1F1B9CE5B67D
+
+I=33
+KEY=1EC7FDBB8AE4FF05056742E7259E33CE6B388827CC253D25
+PT=1DB82CC8EF5B736AAEFD1F1B9CE5B67D
+CT=31B5E80D946AE577268973AF865151EB
+
+I=34
+KEY=FFE21FDAB07E755034D2AAEAB1F4D6B94DB1FB884A746CCE
+PT=31B5E80D946AE577268973AF865151EB
+CT=9FD63EB3EC6A15FC149A4F058EDA7080
+
+I=35
+KEY=7EC4053A63B2353BAB0494595D9EC345592BB48DC4AE1C4E
+PT=9FD63EB3EC6A15FC149A4F058EDA7080
+CT=41730A9E9D197435AC36902C57B16588
+
+I=36
+KEY=FB6D2FAFD47FE8D1EA779EC7C087B770F51D24A1931F79C6
+PT=41730A9E9D197435AC36902C57B16588
+CT=08AD282171F0772F85C0A43E8BACEC74
+
+I=37
+KEY=9531B1BBE0863D44E2DAB6E6B177C05F70DD809F18B395B2
+PT=08AD282171F0772F85C0A43E8BACEC74
+CT=8561E508FA237E4170CECD3A8352CFA4
+
+I=38
+KEY=0AB0CF2D1CA2957A67BB53EE4B54BE1E00134DA59BE15A16
+PT=8561E508FA237E4170CECD3A8352CFA4
+CT=4470EFA3C3172EBF64A064F59AE364A9
+
+I=39
+KEY=291FD5C38E400CFA23CBBC4D884390A164B3295001023EBF
+PT=4470EFA3C3172EBF64A064F59AE364A9
+CT=FCC5636DFE9E45CB7761DD14A1CF4773
+
+I=40
+KEY=114E4DEF0447E1D5DF0EDF2076DDD56A13D2F444A0CD79CC
+PT=FCC5636DFE9E45CB7761DD14A1CF4773
+CT=2130BA8736D4933678C3B536AEDBC500
+
+I=41
+KEY=0C19F74860652278FE3E65A74009465C6B1141720E16BCCC
+PT=2130BA8736D4933678C3B536AEDBC500
+CT=1725EECBA8F9A542E9956168390C82C2
+
+I=42
+KEY=EF9E7E57576D8A3EE91B8B6CE8F0E31E8284201A371A3E0E
+PT=1725EECBA8F9A542E9956168390C82C2
+CT=60912D3EEDC962D68A29AED73DDAA24D
+
+I=43
+KEY=CE6464925302B9F4898AA652053981C808AD8ECD0AC09C43
+PT=60912D3EEDC962D68A29AED73DDAA24D
+CT=43A8B490BBC75DC8D2D2F060C8672E9E
+
+I=44
+KEY=8657F15C75C74469CA2212C2BEFEDC00DA7F7EADC2A7B2DD
+PT=43A8B490BBC75DC8D2D2F060C8672E9E
+CT=67D856AF692A4BA7DEC7C8C14A37BD50
+
+I=45
+KEY=2D566517DCC2D4EBADFA446DD7D497A704B8B66C88900F8D
+PT=67D856AF692A4BA7DEC7C8C14A37BD50
+CT=293C5A05F31E863C6CA26DB8018751CA
+
+I=46
+KEY=826DFA3FD5229B9B84C61E6824CA119B681ADBD489175E47
+PT=293C5A05F31E863C6CA26DB8018751CA
+CT=9421BF2E7727F49C252D644B952C76C4
+
+I=47
+KEY=A5A13E0D1C01D7CF10E7A14653EDE5074D37BF9F1C3B2883
+PT=9421BF2E7727F49C252D644B952C76C4
+CT=CEE8F6FCF7CAF1C5EA9F746C10BD405B
+
+I=48
+KEY=923D8EE015266BA8DE0F57BAA42714C2A7A8CBF30C8668D8
+PT=CEE8F6FCF7CAF1C5EA9F746C10BD405B
+CT=403220B81E6E0837ACCEDA5ACB3730BE
+
+I=49
+KEY=B41FA03C1181401A9E3D7702BA491CF50B6611A9C7B15866
+PT=403220B81E6E0837ACCEDA5ACB3730BE
+CT=8C5D05679F78F853CF83CB8E5BBEBA44
+
+I=50
+KEY=00B6D7172075472F126072652531E4A6C4E5DA279C0FE222
+PT=8C5D05679F78F853CF83CB8E5BBEBA44
+CT=6F9C74C0BB40608AAD1A1202FCAF62EB
+
+I=51
+KEY=BEB1F890B29E8EFE7DFC06A59E71842C69FFC82560A080C9
+PT=6F9C74C0BB40608AAD1A1202FCAF62EB
+CT=B812DB4E295951BB04B1636A9CE91DDB
+
+I=52
+KEY=9455ABC4AC495686C5EEDDEBB728D5976D4EAB4FFC499D12
+PT=B812DB4E295951BB04B1636A9CE91DDB
+CT=B164574EAECAD5A06FFB4F3E6C607D61
+
+I=53
+KEY=1E9CCB2A3541F810748A8AA519E2003702B5E4719029E073
+PT=B164574EAECAD5A06FFB4F3E6C607D61
+CT=1433D23C1500EDBA0EFFD03D96E18F20
+
+I=54
+KEY=F4817B9409F1F1D160B958990CE2ED8D0C4A344C06C86F53
+PT=1433D23C1500EDBA0EFFD03D96E18F20
+CT=B81C889B6FAF5DA800AEBA561992853B
+
+I=55
+KEY=49F7CD1535080039D8A5D002634DB0250CE48E1A1F5AEA68
+PT=B81C889B6FAF5DA800AEBA561992853B
+CT=5B558B7C5916CF14FA5BC9266CFE875F
+
+I=56
+KEY=FCD5479474EA721783F05B7E3A5B7F31F6BF473C73A46D37
+PT=5B558B7C5916CF14FA5BC9266CFE875F
+CT=49BE310D74A9980E9A78B0A8BB3BA1AB
+
+I=57
+KEY=6A68208CC7D6782ECA4E6A734EF2E73F6CC7F794C89FCC9C
+PT=49BE310D74A9980E9A78B0A8BB3BA1AB
+CT=7BD5BABAD7F1EEAA56E17BF9B6678DC8
+
+I=58
+KEY=38DE1A69C03EF9C1B19BD0C9990309953A268C6D7EF84154
+PT=7BD5BABAD7F1EEAA56E17BF9B6678DC8
+CT=62448A767C344E7E7CDB02112F475EFE
+
+I=59
+KEY=02634EC657B436A8D3DF5ABFE53747EB46FD8E7C51BF1FAA
+PT=62448A767C344E7E7CDB02112F475EFE
+CT=F490A20D8B5C53E34C4CF5B7B72A4591
+
+I=60
+KEY=DCDAAB8CBD526850274FF8B26E6B14080AB17BCBE6955A3B
+PT=F490A20D8B5C53E34C4CF5B7B72A4591
+CT=ACFFD7CD5C01B183AB92DBB62DC088F6
+
+I=61
+KEY=51EB6B7172C22A248BB02F7F326AA58BA123A07DCB55D2CD
+PT=ACFFD7CD5C01B183AB92DBB62DC088F6
+CT=0BEDDFA8E7A1AC84E3E164A59D599BAB
+
+I=62
+KEY=4796B5FA7B22626B805DF0D7D5CB090F42C2C4D8560C4966
+PT=0BEDDFA8E7A1AC84E3E164A59D599BAB
+CT=9CC82E2B6B96254345C1FDBAD667275E
+
+I=63
+KEY=D8E112F9657BD2BF1C95DEFCBE5D2C4C07033962806B6E38
+PT=9CC82E2B6B96254345C1FDBAD667275E
+CT=75926F4D3503411CD3C059DA4FFABD62
+
+I=64
+KEY=A19B892107C4F8F86907B1B18B5E6D50D4C360B8CF91D35A
+PT=75926F4D3503411CD3C059DA4FFABD62
+CT=1073561CF6BA28EC57F4B7E5073D27FA
+
+I=65
+KEY=AEFE35F52D8D54A27974E7AD7DE445BC8337D75DC8ACF4A0
+PT=1073561CF6BA28EC57F4B7E5073D27FA
+CT=83E161BA51E6F3A4588C94F7A24BA81F
+
+I=66
+KEY=5E41A6382F88A350FA9586172C02B618DBBB43AA6AE75CBF
+PT=83E161BA51E6F3A4588C94F7A24BA81F
+CT=BD693B4C49378F17322D175932B87111
+
+I=67
+KEY=A2D760EE839234F147FCBD5B6535390FE99654F3585F2DAE
+PT=BD693B4C49378F17322D175932B87111
+CT=101A83CF8487BEDD2C93180BB5024EC9
+
+I=68
+KEY=0F463C72AF8E4B5357E63E94E1B287D2C5054CF8ED5D6367
+PT=101A83CF8487BEDD2C93180BB5024EC9
+CT=757949BE62D3328D09E2F45DF2AD095A
+
+I=69
+KEY=C3C0A16686A5D66B229F772A8361B55FCCE7B8A51FF06A3D
+PT=757949BE62D3328D09E2F45DF2AD095A
+CT=63EBBF9E15BECEC1A0885BECB3D06BF8
+
+I=70
+KEY=3A0B55738CF3B3E94174C8B496DF7B9E6C6FE349AC2001C5
+PT=63EBBF9E15BECEC1A0885BECB3D06BF8
+CT=E176B5C7AFCE06E8ED0C63A4CF7E3034
+
+I=71
+KEY=450F848D964934DAA0027D7339117D76816380ED635E31F1
+PT=E176B5C7AFCE06E8ED0C63A4CF7E3034
+CT=97B91F0A898E5B3A77A0883140D477BC
+
+I=72
+KEY=F3AF781D6EA3529237BB6279B09F264CF6C308DC238A464D
+PT=97B91F0A898E5B3A77A0883140D477BC
+CT=346AD1C470309DFE6CB08DCC24E17470
+
+I=73
+KEY=4E43AB584BF1F8C603D1B3BDC0AFBBB29A738510076B323D
+PT=346AD1C470309DFE6CB08DCC24E17470
+CT=F8B462FB7D758B3AF2CDF7D9244B738F
+
+I=74
+KEY=5A1F023E8F0987B4FB65D146BDDA308868BE72C9232041B2
+PT=F8B462FB7D758B3AF2CDF7D9244B738F
+CT=B44D090FD0B7F762146FF6301C6DBF54
+
+I=75
+KEY=FFC4BB75031165DA4F28D8496D6DC7EA7CD184F93F4DFEE6
+PT=B44D090FD0B7F762146FF6301C6DBF54
+CT=15CB042313710F2CD1C3409B5F3AF419
+
+I=76
+KEY=8107240E1FB855765AE3DC6A7E1CC8C6AD12C46260770AFF
+PT=15CB042313710F2CD1C3409B5F3AF419
+CT=0AB01B03F415A58D52CF7A1E40856275
+
+I=77
+KEY=4493743ADE27D1D85053C7698A096D4BFFDDBE7C20F2688A
+PT=0AB01B03F415A58D52CF7A1E40856275
+CT=05BE037C28719B4C4EEBEA329FAC63D5
+
+I=78
+KEY=F582EC062155016255EDC415A278F607B136544EBF5E0B5F
+PT=05BE037C28719B4C4EEBEA329FAC63D5
+CT=74C3C4F42B3F575C6B8D5BAD9AF0191F
+
+I=79
+KEY=8FAF8EEAA5E2D76B212E00E18947A15BDABB0FE325AE1240
+PT=74C3C4F42B3F575C6B8D5BAD9AF0191F
+CT=92CB4A3DF34E6711FB56391F26D949AD
+
+I=80
+KEY=1CAD393CC06BC104B3E54ADC7A09C64A21ED36FC03775BED
+PT=92CB4A3DF34E6711FB56391F26D949AD
+CT=3754BB3D8C3D7370EDBA842CDF17D5C0
+
+I=81
+KEY=E3AB53BB36BDFBBB84B1F1E1F634B53ACC57B2D0DC608E2D
+PT=3754BB3D8C3D7370EDBA842CDF17D5C0
+CT=94EAC7FD54D228619791BCCBF9F633F4
+
+I=82
+KEY=480B1D923E853259105B361CA2E69D5B5BC60E1B2596BDD9
+PT=94EAC7FD54D228619791BCCBF9F633F4
+CT=CAB29222355968E9CF492D5BF08B0999
+
+I=83
+KEY=D8F6791107FB3D26DAE9A43E97BFF5B2948F2340D51DB440
+PT=CAB29222355968E9CF492D5BF08B0999
+CT=00837C78B88005288DB39452F1EB8F13
+
+I=84
+KEY=6521B6B771FE24B2DA6AD8462F3FF09A193CB71224F63B53
+PT=00837C78B88005288DB39452F1EB8F13
+CT=2082F77D48A63E223A79217CD4516854
+
+I=85
+KEY=9D9F3198682E2476FAE82F3B6799CEB82345966EF0A75307
+PT=2082F77D48A63E223A79217CD4516854
+CT=C5074D4B3F455346B078DAFBC1327AB6
+
+I=86
+KEY=61832291235DC7C33FEF627058DC9DFE933D4C95319529B1
+PT=C5074D4B3F455346B078DAFBC1327AB6
+CT=72EE56572A2B7CEC53FC4E4FC0293D63
+
+I=87
+KEY=5C2877854338D45D4D01342772F7E112C0C102DAF1BC14D2
+PT=72EE56572A2B7CEC53FC4E4FC0293D63
+CT=7350039161DF9E8E45B360E6139E4226
+
+I=88
+KEY=A8225CF65297BA953E5137B613287F9C8572623CE22256F4
+PT=7350039161DF9E8E45B360E6139E4226
+CT=4339288215BE1BB87E31AF8FB35DEDC1
+
+I=89
+KEY=51649B52A8458F4B7D681F3406966424FB43CDB3517FBB35
+PT=4339288215BE1BB87E31AF8FB35DEDC1
+CT=4D7AB61CC2C930CBB0DF43EEE92EBA1F
+
+I=90
+KEY=750E4E7E9183E2FF3012A928C45F54EF4B9C8E5DB851012A
+PT=4D7AB61CC2C930CBB0DF43EEE92EBA1F
+CT=1090FE663EA77DC2EC30E8F89E662918
+
+I=91
+KEY=B65FBDF702246E442082574EFAF8292DA7AC66A526372832
+PT=1090FE663EA77DC2EC30E8F89E662918
+CT=14307A2CC40BDFB0413DF10F961337CA
+
+I=92
+KEY=7BEC3480AA0A44FF34B22D623EF3F69DE69197AAB0241FF8
+PT=14307A2CC40BDFB0413DF10F961337CA
+CT=8F378E272D82DE8E63EC418912EF8642
+
+I=93
+KEY=63921E8700657D6ABB85A34513712813857DD623A2CB99BA
+PT=8F378E272D82DE8E63EC418912EF8642
+CT=3947DDC00E3C4D958E508DF58AB4982A
+
+I=94
+KEY=754B2E8355FABCAF82C27E851D4D65860B2D5BD6287F0190
+PT=3947DDC00E3C4D958E508DF58AB4982A
+CT=492DB375B3CC640DD8FEDBAF2C943535
+
+I=95
+KEY=E8F8C2450F8597B3CBEFCDF0AE81018BD3D3807904EB34A5
+PT=492DB375B3CC640DD8FEDBAF2C943535
+CT=D74BD4118D448B674935B80E4B1BFB93
+
+I=96
+KEY=34A2C5B010AE479A1CA419E123C58AEC9AE638774FF0CF36
+PT=D74BD4118D448B674935B80E4B1BFB93
+CT=E9742B41295BC3ED3AA66E80E8718665
+
+I=97
+KEY=0E11D08AA9EC81A4F5D032A00A9E4901A04056F7A7814953
+PT=E9742B41295BC3ED3AA66E80E8718665
+CT=5FB17BFE146B410F90EC922B1385D0E4
+
+I=98
+KEY=B15779E61FD27B02AA61495E1EF5080E30ACC4DCB40499B7
+PT=5FB17BFE146B410F90EC922B1385D0E4
+CT=1B0CCF643F19DDBC0E3ED0EEAE83ACC1
+
+I=99
+KEY=861B580225193DD5B16D863A21ECD5B23E9214321A873576
+PT=1B0CCF643F19DDBC0E3ED0EEAE83ACC1
+CT=B3A7D434E30DC0CDEE4D17BBC27B855E
+
+I=100
+KEY=B6DF2A8726C31D6E02CA520EC2E1157FD0DF0389D8FCB028
+PT=B3A7D434E30DC0CDEE4D17BBC27B855E
+CT=57DE2345D91E26A2AB7CA88AEA23A84F
+
+I=101
+KEY=6976D3780B5F01E25514714B1BFF33DD7BA3AB0332DF1867
+PT=57DE2345D91E26A2AB7CA88AEA23A84F
+CT=7B03541D239B569FEE7ABD8980F1BD05
+
+I=102
+KEY=734CAC477A2727542E1725563864654295D9168AB22EA562
+PT=7B03541D239B569FEE7ABD8980F1BD05
+CT=5CB7E72B2E6CFF8C18AEB026FE40C2FA
+
+I=103
+KEY=B59171BEBC7BFB8672A0C27D16089ACE8D77A6AC4C6E6798
+PT=5CB7E72B2E6CFF8C18AEB026FE40C2FA
+CT=50B9186306DA92FE785D6EB9223E43A9
+
+I=104
+KEY=E460BA8A2F82DBB72219DA1E10D20830F52AC8156E502431
+PT=50B9186306DA92FE785D6EB9223E43A9
+CT=B3D8CE8B04B99CF2F82571E1588C358B
+
+I=105
+KEY=CE7C790CD4B34C4791C11495146B94C20D0FB9F436DC11BA
+PT=B3D8CE8B04B99CF2F82571E1588C358B
+CT=9845F0A5681A40A6DC3D9BCA639FE786
+
+I=106
+KEY=699FE59B482743180984E4307C71D464D132223E5543F63C
+PT=9845F0A5681A40A6DC3D9BCA639FE786
+CT=C7EBF5CEAAD5652563A8550020EC7070
+
+I=107
+KEY=FEBE2836F5099F53CE6F11FED6A4B141B29A773E75AF864C
+PT=C7EBF5CEAAD5652563A8550020EC7070
+CT=DE94A376634FE9856A84E2EE6EED86E8
+
+I=108
+KEY=22BCFFB0740FC30510FBB288B5EB58C4D81E95D01B4200A4
+PT=DE94A376634FE9856A84E2EE6EED86E8
+CT=64B9917E23328A4FE1F8FDB8AE43E7F3
+
+I=109
+KEY=E8491AFDF41F0DFB744223F696D9D28B39E66868B501E757
+PT=64B9917E23328A4FE1F8FDB8AE43E7F3
+CT=2C59820184ABC99E82A7F51D4E3A86A8
+
+I=110
+KEY=3BE5F390D72ABE6A581BA1F712721B15BB419D75FB3B61FF
+PT=2C59820184ABC99E82A7F51D4E3A86A8
+CT=387ACD0BAD539773287C209A0876581F
+
+I=111
+KEY=B7388762F772C83560616CFCBF218C66933DBDEFF34D39E0
+PT=387ACD0BAD539773287C209A0876581F
+CT=F12D3E1F21AFB9CACAB541EFB7334438
+
+I=112
+KEY=FBD600191276FA5C914C52E39E8E35AC5988FC00447E7DD8
+PT=F12D3E1F21AFB9CACAB541EFB7334438
+CT=68D2FA1BB635D9D35E4BF440335CBD80
+
+I=113
+KEY=1E2B19106450AA2FF99EA8F828BBEC7F07C308407722C058
+PT=68D2FA1BB635D9D35E4BF440335CBD80
+CT=4532507D5E0227054CB36CBD3C489D53
+
+I=114
+KEY=C0B60F65BAD77DA4BCACF88576B9CB7A4B7064FD4B6A5D0B
+PT=4532507D5E0227054CB36CBD3C489D53
+CT=6DB8FD7DE7924B7E92CF27BC0AD11D16
+
+I=115
+KEY=451836B53318CC33D11405F8912B8004D9BF434141BB401D
+PT=6DB8FD7DE7924B7E92CF27BC0AD11D16
+CT=A3D5F6A8D4372B66F8D3DD9FF945DECA
+
+I=116
+KEY=0E57235F9B527C5172C1F350451CAB62216C9EDEB8FE9ED7
+PT=A3D5F6A8D4372B66F8D3DD9FF945DECA
+CT=BEDFF233AD31EEB9943EEBF52F66AABF
+
+I=117
+KEY=BB7E1C438E5F36A3CC1E0163E82D45DBB552752B97983468
+PT=BEDFF233AD31EEB9943EEBF52F66AABF
+CT=4531EDEC06570582755199A0C4745EA5
+
+I=118
+KEY=DE70EC87811AFD32892FEC8FEE7A4059C003EC8B53EC6ACD
+PT=4531EDEC06570582755199A0C4745EA5
+CT=F3189383C202A472CE238571D187F8EB
+
+I=119
+KEY=CA2AE67397E9238A7A377F0C2C78E42B0E2069FA826B9226
+PT=F3189383C202A472CE238571D187F8EB
+CT=B48952CBAC43D0114985A9035DFF0382
+
+I=120
+KEY=335EF040D622E95BCEBE2DC7803B343A47A5C0F9DF9491A4
+PT=B48952CBAC43D0114985A9035DFF0382
+CT=9B71302FDFBC47DF6276AB73D4D0D8B3
+
+I=121
+KEY=683CC10DFBC6C09C55CF1DE85F8773E525D36B8A0B444917
+PT=9B71302FDFBC47DF6276AB73D4D0D8B3
+CT=69EED4A0C5428005199DF12B338393E2
+
+I=122
+KEY=B86C9A2F1A978E123C21C9489AC5F3E03C4E9AA138C7DAF5
+PT=69EED4A0C5428005199DF12B338393E2
+CT=D0C2ACA653E6D7D80D32F445B0DD2347
+
+I=123
+KEY=EF7E3DCDF05FFA86ECE365EEC9232438317C6EE4881AF9B2
+PT=D0C2ACA653E6D7D80D32F445B0DD2347
+CT=F373D4DBD7ADAFEF582621EC8C7CD2A2
+
+I=124
+KEY=B8059C7A6BA2273E1F90B1351E8E8BD7695A4F0804662B10
+PT=F373D4DBD7ADAFEF582621EC8C7CD2A2
+CT=0AD37AFC8C929513F9BDB976E69C7CF3
+
+I=125
+KEY=F5C9ECCBB672D46F1543CBC9921C1EC490E7F67EE2FA57E3
+PT=0AD37AFC8C929513F9BDB976E69C7CF3
+CT=E80B118DFB34F11DB344B6AE34EDEBC8
+
+I=126
+KEY=AA67DC18543A7A88FD48DA446928EFD923A340D0D617BC2B
+PT=E80B118DFB34F11DB344B6AE34EDEBC8
+CT=628D5C42DDEBA9AE4983F51D339366B4
+
+I=127
+KEY=BF0C30A039C0FEE89FC58606B4C346776A20B5CDE584DA9F
+PT=628D5C42DDEBA9AE4983F51D339366B4
+CT=1BE2A5A8CCA8E065557F6982AF3E056F
+
+I=128
+KEY=A219F6B8E2FF1AA3842723AE786BA6123F5FDC4F4ABADFF0
+PT=1BE2A5A8CCA8E065557F6982AF3E056F
+CT=5E1187D78AEB34780F07905A84D2EBBA
+
+I=129
+KEY=851DDD078D4B7802DA36A479F280926A30584C15CE68344A
+PT=5E1187D78AEB34780F07905A84D2EBBA
+CT=31EE3AC2EC79D14EBCA71E760326CD74
+
+I=130
+KEY=E6741084FEDEEFFEEBD89EBB1EF943248CFF5263CD4EF93E
+PT=31EE3AC2EC79D14EBCA71E760326CD74
+CT=298E3A00F280BBF8364CF8D6D44CF54E
+
+I=131
+KEY=8A41136FE9DB1FB5C256A4BBEC79F8DCBAB3AAB519020C70
+PT=298E3A00F280BBF8364CF8D6D44CF54E
+CT=39B7A0416C1F9B19C7B99A1F6A70258C
+
+I=132
+KEY=E1F1B622EB8BC9B1FBE104FA806663C57D0A30AA737229FC
+PT=39B7A0416C1F9B19C7B99A1F6A70258C
+CT=B1655FA9AB2C4956E2C56F7A6C421BE5
+
+I=133
+KEY=0EE0B7E1AF7093694A845B532B4A2A939FCF5FD01F303219
+PT=B1655FA9AB2C4956E2C56F7A6C421BE5
+CT=1AD9CBB1A28F7A2A6CBC7EC98EF483FC
+
+I=134
+KEY=180A2BD07F77D34E505D90E289C550B9F373211991C4B1E5
+PT=1AD9CBB1A28F7A2A6CBC7EC98EF483FC
+CT=6363BE57D6D587EE3ABA9FE81F3D3A10
+
+I=135
+KEY=848B7408CAACF02E333E2EB55F10D757C9C9BEF18EF98BF5
+PT=6363BE57D6D587EE3ABA9FE81F3D3A10
+CT=05618580D7915AA7398EF4DB7D1F1DE3
+
+I=136
+KEY=E581D7B4F84F2860365FAB3588818DF0F0474A2AF3E69616
+PT=05618580D7915AA7398EF4DB7D1F1DE3
+CT=F8D0118087404FD729F96CA6551338AD
+
+I=137
+KEY=6C81D6873EFFF763CE8FBAB50FC1C227D9BE268CA6F5AEBB
+PT=F8D0118087404FD729F96CA6551338AD
+CT=784913B38D32A7395D73AF1378A0DC56
+
+I=138
+KEY=D971137D872F606EB6C6A90682F3651E84CD899FDE5572ED
+PT=784913B38D32A7395D73AF1378A0DC56
+CT=D07C418BD183457B6683AE99C457FC0B
+
+I=139
+KEY=196BBA79E35EEC7966BAE88D53702065E24E27061A028EE6
+PT=D07C418BD183457B6683AE99C457FC0B
+CT=5595D16DF7668779825BC135D1408013
+
+I=140
+KEY=6F140EC274635FA2332F39E0A416A71C6015E633CB420EF5
+PT=5595D16DF7668779825BC135D1408013
+CT=1AB9F5075E063403FEFD976044C89C95
+
+I=141
+KEY=926F3A2AA0BD8C952996CCE7FA10931F9EE871538F8A9260
+PT=1AB9F5075E063403FEFD976044C89C95
+CT=6DF413E53FCEDA296D7ABA796179D600
+
+I=142
+KEY=740F74BF0E0C38154462DF02C5DE4936F392CB2AEEF34460
+PT=6DF413E53FCEDA296D7ABA796179D600
+CT=0D0F499B0D51948A9CCBC4B6531A05F7
+
+I=143
+KEY=2500C9B63042B24B496D9699C88FDDBC6F590F9CBDE94197
+PT=0D0F499B0D51948A9CCBC4B6531A05F7
+CT=85833A1072B6A0ED932D4D89D53A785A
+
+I=144
+KEY=FCB377C07622271FCCEEAC89BA397D51FC74421568D339CD
+PT=85833A1072B6A0ED932D4D89D53A785A
+CT=545EDE1A4B737F1E51CBDAE311E91D5C
+
+I=145
+KEY=BB108ABE391C394E98B07293F14A024FADBF98F6793A2491
+PT=545EDE1A4B737F1E51CBDAE311E91D5C
+CT=DA8CC635CF1450685DDAAA5A56BC3BD9
+
+I=146
+KEY=34F8623EC93A6C2A423CB4A63E5E5227F06532AC2F861F48
+PT=DA8CC635CF1450685DDAAA5A56BC3BD9
+CT=FE73162BF90B52DEE7D0EA9D73F8444D
+
+I=147
+KEY=5E3CB25583365D5EBC4FA28DC75500F917B5D8315C7E5B05
+PT=FE73162BF90B52DEE7D0EA9D73F8444D
+CT=BC75D12F66C232E1979D0F6C3E1ED8F1
+
+I=148
+KEY=EABE655116470AE1003A73A2A19732188028D75D626083F4
+PT=BC75D12F66C232E1979D0F6C3E1ED8F1
+CT=661A3FA0530BF47C266D609FE01DAF48
+
+I=149
+KEY=97A1B8E97CF217C366204C02F29CC664A645B7C2827D2CBC
+PT=661A3FA0530BF47C266D609FE01DAF48
+CT=791144514CF8E4CC15BC6ADE3291F9CD
+
+I=150
+KEY=5189DC6F535B5A091F310853BE6422A8B3F9DD1CB0ECD571
+PT=791144514CF8E4CC15BC6ADE3291F9CD
+CT=4369FDB3626F399A6526C476373A52D4
+
+I=151
+KEY=21CD36EDB27428AB5C58F5E0DC0B1B32D6DF196A87D687A5
+PT=4369FDB3626F399A6526C476373A52D4
+CT=4C8869494C044703CFDD09F83B2208AA
+
+I=152
+KEY=85C08C7D4667AE3710D09CA9900F5C3119021092BCF48F0F
+PT=4C8869494C044703CFDD09F83B2208AA
+CT=06BC45BDB38A7028CB2D189E9E0C3046
+
+I=153
+KEY=807182BD7E1F29BE166CD91423852C19D22F080C22F8BF49
+PT=06BC45BDB38A7028CB2D189E9E0C3046
+CT=74AFD5F37F8F0712710585FB8DB22FF8
+
+I=154
+KEY=1AF15D0DE00CEF3F62C30CE75C0A2B0BA32A8DF7AF4A90B1
+PT=74AFD5F37F8F0712710585FB8DB22FF8
+CT=B1A4EE894A12794E0C1A286DDBC01CFD
+
+I=155
+KEY=E0732BA619DCF2F5D367E26E16185245AF30A59A748A8C4C
+PT=B1A4EE894A12794E0C1A286DDBC01CFD
+CT=0EA90279135DFFC7F58DB959F9E8BFE1
+
+I=156
+KEY=AE8779E669BFF77EDDCEE0170545AD825ABD1CC38D6233AD
+PT=0EA90279135DFFC7F58DB959F9E8BFE1
+CT=3717C67E520D87778350E62525C01730
+
+I=157
+KEY=79D13142BE9066A2EAD9266957482AF5D9EDFAE6A8A2249D
+PT=3717C67E520D87778350E62525C01730
+CT=A8F96DA7AE81EF8810A317AB4C9B82A9
+
+I=158
+KEY=597D70828E56003942204BCEF9C9C57DC94EED4DE439A634
+PT=A8F96DA7AE81EF8810A317AB4C9B82A9
+CT=8C373A065986BAC9E345475F5D83FBCF
+
+I=159
+KEY=96C8CF3884D5DA18CE1771C8A04F7FB42A0BAA12B9BA5DFB
+PT=8C373A065986BAC9E345475F5D83FBCF
+CT=8E4D562CBEDC360EFB25B857DD4C4FF2
+
+I=160
+KEY=5A0A29B58F17F9F9405A27E41E9349BAD12E124564F61209
+PT=8E4D562CBEDC360EFB25B857DD4C4FF2
+CT=192CCD79E3B4C8F5617D1F55B789B7A3
+
+I=161
+KEY=29A4692EDE3EAABE5976EA9DFD27814FB0530D10D37FA5AA
+PT=192CCD79E3B4C8F5617D1F55B789B7A3
+CT=8A5F181E1748C98121D1C22204591B23
+
+I=162
+KEY=5E5CA30210E78677D329F283EA6F48CE9182CF32D726BE89
+PT=8A5F181E1748C98121D1C22204591B23
+CT=14512A4997094A0536594E63ACC5EF4A
+
+I=163
+KEY=7DA5F9C99B68DFB0C778D8CA7D6602CBA7DB81517BE351C3
+PT=14512A4997094A0536594E63ACC5EF4A
+CT=F91BA751D5E2ADC074FC6CC14476DE67
+
+I=164
+KEY=658144C57CCFDAD83E637F9BA884AF0BD327ED903F958FA4
+PT=F91BA751D5E2ADC074FC6CC14476DE67
+CT=5F7FED22BABA25D48C95C4E2CAEDB3F4
+
+I=165
+KEY=13C5D7A44396F6FD611C92B9123E8ADF5FB22972F5783C50
+PT=5F7FED22BABA25D48C95C4E2CAEDB3F4
+CT=0FCFB3CB93B2E7FDF7E156486929BD17
+
+I=166
+KEY=99DBAC1D5D268DB06ED32172818C6D22A8537F3A9C518147
+PT=0FCFB3CB93B2E7FDF7E156486929BD17
+CT=3E16265A02271FF68AE6310A6BFDEE60
+
+I=167
+KEY=A8876A49E2F1CC5250C5072883AB72D422B54E30F7AC6F27
+PT=3E16265A02271FF68AE6310A6BFDEE60
+CT=1657BF722B57D083D8864B6447317E05
+
+I=168
+KEY=0A615A71BC2BE3E94692B85AA8FCA257FA330554B09D1122
+PT=1657BF722B57D083D8864B6447317E05
+CT=018B742E941E27C547451B9E41F245F5
+
+I=169
+KEY=6AE11571E3D54C4B4719CC743CE28592BD761ECAF16F54D7
+PT=018B742E941E27C547451B9E41F245F5
+CT=8C5BB61774502B6A9C44BEE8D6C44A63
+
+I=170
+KEY=DCE75079013F0865CB427A6348B2AEF82132A02227AB1EB4
+PT=8C5BB61774502B6A9C44BEE8D6C44A63
+CT=361D3B51C751298194CB1AA32C0A86EE
+
+I=171
+KEY=E73232D50D457866FD5F41328FE38779B5F9BA810BA1985A
+PT=361D3B51C751298194CB1AA32C0A86EE
+CT=7B734F34DD4F332CBE5CFC7659C390BF
+
+I=172
+KEY=BEEF9073227655EB862C0E0652ACB4550BA546F7526208E5
+PT=7B734F34DD4F332CBE5CFC7659C390BF
+CT=63CCC9CE5DADA5B5AC68870E6C675943
+
+I=173
+KEY=1E9078C198526C1DE5E0C7C80F0111E0A7CDC1F93E0551A6
+PT=63CCC9CE5DADA5B5AC68870E6C675943
+CT=7BBC6F7B62807CBE1C93CADB5E6CAE0A
+
+I=174
+KEY=AD26AC70784FF1B99E5CA8B36D816D5EBB5E0B226069FFAC
+PT=7BBC6F7B62807CBE1C93CADB5E6CAE0A
+CT=E95B0C766EF9049163D3A249E196DDB8
+
+I=175
+KEY=E17835A277F1D1EE7707A4C5037869CFD88DA96B81FF2214
+PT=E95B0C766EF9049163D3A249E196DDB8
+CT=968263CBCDB4582FC9CDFD0C9FD0B4F0
+
+I=176
+KEY=22F9EB31E67C62DBE185C70ECECC31E0114054671E2F96E4
+PT=968263CBCDB4582FC9CDFD0C9FD0B4F0
+CT=9F573A339DFA07B844E4034718A4FE88
+
+I=177
+KEY=0FEC8766966A42DA7ED2FD3D5336365855A45720068B686C
+PT=9F573A339DFA07B844E4034718A4FE88
+CT=A0809BA3A742C0EB1BDA613B7472F56A
+
+I=178
+KEY=98E655519C9A8A95DE52669EF474F6B34E7E361B72F99D06
+PT=A0809BA3A742C0EB1BDA613B7472F56A
+CT=9BF1D85440818035FA6AC36E5A5F00A7
+
+I=179
+KEY=A8D37BE0EB386F8045A3BECAB4F57686B414F57528A69DA1
+PT=9BF1D85440818035FA6AC36E5A5F00A7
+CT=924E309AC04A655C50980360914E9830
+
+I=180
+KEY=7D89F156EA181E92D7ED8E5074BF13DAE48CF615B9E80591
+PT=924E309AC04A655C50980360914E9830
+CT=427819CDAE419A046D4586FF5A784A1C
+
+I=181
+KEY=B028A265666F69629595979DDAFE89DE89C970EAE3904F8D
+PT=427819CDAE419A046D4586FF5A784A1C
+CT=D8B51EEC0A6A6D17F1E476C922AD8548
+
+I=182
+KEY=DF20B45B990C5E734D208971D094E4C9782D0623C13DCAC5
+PT=D8B51EEC0A6A6D17F1E476C922AD8548
+CT=7823F1BBA96105168195CDAC34AB5315
+
+I=183
+KEY=AF4C64F7E4AA6DE2350378CA79F5E1DFF9B8CB8FF59699D0
+PT=7823F1BBA96105168195CDAC34AB5315
+CT=85DD0256BC29EAA867DB77C1A049574D
+
+I=184
+KEY=4047F74604E37A00B0DE7A9CC5DC0B779E63BC4E55DFCE9D
+PT=85DD0256BC29EAA867DB77C1A049574D
+CT=64C1880D34408CB1A92BBA354941D5B6
+
+I=185
+KEY=9C3BF36E47110C08D41FF291F19C87C63748067B1C9E1B2B
+PT=64C1880D34408CB1A92BBA354941D5B6
+CT=25B80866FE3198C775F64C412E734348
+
+I=186
+KEY=FAE7368F99242159F1A7FAF70FAD1F0142BE4A3A32ED5863
+PT=25B80866FE3198C775F64C412E734348
+CT=8D3D7E9A195363C96334C48120BC343A
+
+I=187
+KEY=5F48BD86A9C4DC897C9A846D16FE7CC8218A8EBB12516C59
+PT=8D3D7E9A195363C96334C48120BC343A
+CT=E886EEA0F2D556D693DC94FFC588D1F4
+
+I=188
+KEY=B7406993C120EA20941C6ACDE42B2A1EB2561A44D7D9BDAD
+PT=E886EEA0F2D556D693DC94FFC588D1F4
+CT=76CB89CBB935D422DED9784D4548A84F
+
+I=189
+KEY=4DB740C3FA55F4ABE2D7E3065D1EFE3C6C8F6209929115E2
+PT=76CB89CBB935D422DED9784D4548A84F
+CT=93D7AC7B18A1196D5C166203C44A43D3
+
+I=190
+KEY=353A0293DEFB648071004F7D45BFE7513099000A56DB5631
+PT=93D7AC7B18A1196D5C166203C44A43D3
+CT=8982BD77485524EE9E49769591E922CE
+
+I=191
+KEY=F6FC1F7E838CD8A7F882F20A0DEAC3BFAED0769FC73274FF
+PT=8982BD77485524EE9E49769591E922CE
+CT=89012A1E3F7669C76C5F5F4987108662
+
+I=192
+KEY=A1AA84E01EBC3E837183D814329CAA78C28F29D64022F29D
+PT=89012A1E3F7669C76C5F5F4987108662
+CT=139E37ADA17990054AF8EF5B717E884B
+
+I=193
+KEY=C631229E9871F2AC621DEFB993E53A7D8877C68D315C7AD6
+PT=139E37ADA17990054AF8EF5B717E884B
+CT=CEC8F9C90B2E393BDA4602C2A83F953C
+
+I=194
+KEY=824604723CD82F95ACD5167098CB03465231C44F9963EFEA
+PT=CEC8F9C90B2E393BDA4602C2A83F953C
+CT=2A2E1344AE4C6BA40568E170BF67FD74
+
+I=195
+KEY=2B17489FA71F683B86FB0534368768E25759253F2604129E
+PT=2A2E1344AE4C6BA40568E170BF67FD74
+CT=7402AC6982DBB0BED678746E4523556C
+
+I=196
+KEY=DA9C0CF5A89D3D94F2F9A95DB45CD85C81215151632747F2
+PT=7402AC6982DBB0BED678746E4523556C
+CT=36A36B5B55F950F00B9F3E31156BFD65
+
+I=197
+KEY=543619886B56830BC45AC206E1A588AC8ABE6F60764CBA97
+PT=36A36B5B55F950F00B9F3E31156BFD65
+CT=D7B36A117E824A49A5944C37BEE27F06
+
+I=198
+KEY=9494630598E7618213E9A8179F27C2E52F2A2357C8AEC591
+PT=D7B36A117E824A49A5944C37BEE27F06
+CT=2D60BC0BC950EEE7E36D50E971CF68D0
+
+I=199
+KEY=B0328218DF523A0C3E89141C56772C02CC4773BEB961AD41
+PT=2D60BC0BC950EEE7E36D50E971CF68D0
+CT=49A4643E535F45A1ABDEF41ABABBE268
+
+I=200
+KEY=5E3FD7ACD8EF334D772D7022052869A3679987A403DA4F29
+PT=49A4643E535F45A1ABDEF41ABABBE268
+CT=D5EEB5CC40AF8612708BAABE85685E4C
+
+I=201
+KEY=A232D0267D606002A2C3C5EE4587EFB117122D1A86B21165
+PT=D5EEB5CC40AF8612708BAABE85685E4C
+CT=3F5B875DE202C5441165FE5C5CA2D258
+
+I=202
+KEY=844ED6FAFA342BFE9D9842B3A7852AF50677D346DA10C33D
+PT=3F5B875DE202C5441165FE5C5CA2D258
+CT=9B5F0210E0EC623C6ACF1C0BC06EBF51
+
+I=203
+KEY=109F8CEC689E0F5306C740A3476948C96CB8CF4D1A7E7C6C
+PT=9B5F0210E0EC623C6ACF1C0BC06EBF51
+CT=E57015FAB0006446E544704DB6629059
+
+I=204
+KEY=D9ABCBAC4B271B04E3B75559F7692C8F89FCBF00AC1CEC35
+PT=E57015FAB0006446E544704DB6629059
+CT=85F0DF6B1ED933E87F6A9F609D516346
+
+I=205
+KEY=09915869AE1F57F766478A32E9B01F67F6962060314D8F73
+PT=85F0DF6B1ED933E87F6A9F609D516346
+CT=471B931539C155478A1D4B9BA50DCE43
+
+I=206
+KEY=BFB70AA6C4F05C1D215C1927D0714A207C8B6BFB94404130
+PT=471B931539C155478A1D4B9BA50DCE43
+CT=9AC55C1CC77E7B59CC9204898A38CEA7
+
+I=207
+KEY=660972D79B056F14BB99453B170F3179B0196F721E788F97
+PT=9AC55C1CC77E7B59CC9204898A38CEA7
+CT=19B00FEB13145F9F356173B42184D516
+
+I=208
+KEY=F09576EB17FB1A07A2294AD0041B6EE685781CC63FFC5A81
+PT=19B00FEB13145F9F356173B42184D516
+CT=5F1379E25F6DD8653B73F58E738D6243
+
+I=209
+KEY=8D170BBC5E3662BEFD3A33325B76B683BE0BE9484C7138C2
+PT=5F1379E25F6DD8653B73F58E738D6243
+CT=AEF55C09E7AD76CC9BA7B83874A0A86B
+
+I=210
+KEY=1A7BD2572D3CDB8C53CF6F3BBCDBC04F25AC517038D190A9
+PT=AEF55C09E7AD76CC9BA7B83874A0A86B
+CT=6BEF52E6D86DC15D2A03B5CB3EBAB130
+
+I=211
+KEY=B4BC0603F59BE3D038203DDD64B601120FAFE4BB066B2199
+PT=6BEF52E6D86DC15D2A03B5CB3EBAB130
+CT=FDC093FFED096B7812E77E23AD9C7C71
+
+I=212
+KEY=C00A0DDA74D55250C5E0AE2289BF6A6A1D489A98ABF75DE8
+PT=FDC093FFED096B7812E77E23AD9C7C71
+CT=072625CB0C022827E195DE8AB4FE7E0C
+
+I=213
+KEY=6534CBAB46880CE0C2C68BE985BD424DFCDD44121F0923E4
+PT=072625CB0C022827E195DE8AB4FE7E0C
+CT=11AA47C5557437AEE8A8BE31A849A047
+
+I=214
+KEY=C204AFE794D81224D36CCC2CD0C975E31475FA23B74083A3
+PT=11AA47C5557437AEE8A8BE31A849A047
+CT=4C91B3031567DFFC22829CBC3C419B6D
+
+I=215
+KEY=01A4820CC4D281B99FFD7F2FC5AEAA1F36F7669F8B0118CE
+PT=4C91B3031567DFFC22829CBC3C419B6D
+CT=54C0F95B0179CB753917A2592F58BD77
+
+I=216
+KEY=B5C1DD77446C8FD1CB3D8674C4D7616A0FE0C4C6A459A5B9
+PT=54C0F95B0179CB753917A2592F58BD77
+CT=A2A19A98250E432131F9EF4AE473677F
+
+I=217
+KEY=9FDC1167AC2D1A51699C1CECE1D9224B3E192B8C402AC2C6
+PT=A2A19A98250E432131F9EF4AE473677F
+CT=9B5780CA9669A92688F54887E303F2D3
+
+I=218
+KEY=C734A73F4A32D311F2CB9C2677B08B6DB6EC630BA3293015
+PT=9B5780CA9669A92688F54887E303F2D3
+CT=F1750745D1E74E41A07B99482ECABAAA
+
+I=219
+KEY=1612B86730F487EF03BE9B63A657C52C1697FA438DE38ABF
+PT=F1750745D1E74E41A07B99482ECABAAA
+CT=30F510DBDDAEC6FC0D2504C11DF23CFA
+
+I=220
+KEY=D52E3B50F72B085D334B8BB87BF903D01BB2FE829011B645
+PT=30F510DBDDAEC6FC0D2504C11DF23CFA
+CT=64998C3018185D722477A2DBFB84ABB8
+
+I=221
+KEY=7F9F2A23D320792E57D2078863E15EA23FC55C596B951DFD
+PT=64998C3018185D722477A2DBFB84ABB8
+CT=9293A4FF9ED5D57D81BB8A63381BF66A
+
+I=222
+KEY=B529B6E7080E0AE4C541A377FD348BDFBE7ED63A538EEB97
+PT=9293A4FF9ED5D57D81BB8A63381BF66A
+CT=A389ABCF609B41F28CC3188B2C126915
+
+I=223
+KEY=A5C4C3A89459F79566C808B89DAFCA2D32BDCEB17F9C8282
+PT=A389ABCF609B41F28CC3188B2C126915
+CT=5F4BC60608A3DF788631EBB66763E7DF
+
+I=224
+KEY=F59456291C6CF0C83983CEBE950C1555B48C250718FF655D
+PT=5F4BC60608A3DF788631EBB66763E7DF
+CT=EFDE2113118EDFD5A15D4DFA1C1E79B4
+
+I=225
+KEY=9A4CD87E44EA7DEED65DEFAD8482CA8015D168FD04E11CE9
+PT=EFDE2113118EDFD5A15D4DFA1C1E79B4
+CT=2526BA56DA8A9F9A5799A9D2BE96AEBA
+
+I=226
+KEY=A19D5DFAEC1C9B9DF37B55FB5E08551A4248C12FBA77B253
+PT=2526BA56DA8A9F9A5799A9D2BE96AEBA
+CT=83F237712EF89A7B1E84D69DEFC9B9B9
+
+I=227
+KEY=C48B0103470544867089628A70F0CF615CCC17B255BE0BEA
+PT=83F237712EF89A7B1E84D69DEFC9B9B9
+CT=13B7E26895FEEFE2356306D8D822DDD3
+
+I=228
+KEY=B366B0FE6BB3DB17633E80E2E50E208369AF116A8D9CD639
+PT=13B7E26895FEEFE2356306D8D822DDD3
+CT=BF8C47559B230A3311543BEAA90D4DA1
+
+I=229
+KEY=BE5A735484B72645DCB2C7B77E2D2AB078FB2A8024919B98
+PT=BF8C47559B230A3311543BEAA90D4DA1
+CT=D3C9AFCED64F46AC74FFF73302DE10EB
+
+I=230
+KEY=1DFD852FE9F131840F7B6879A8626C1C0C04DDB3264F8B73
+PT=D3C9AFCED64F46AC74FFF73302DE10EB
+CT=004386EABD8F3C60971D34B5A5F220F8
+
+I=231
+KEY=BB9831D80259A5A40F38EE9315ED507C9B19E90683BDAB8B
+PT=004386EABD8F3C60971D34B5A5F220F8
+CT=119A244F6A3ED1947A764CFE96568213
+
+I=232
+KEY=93B0F09E78E610741EA2CADC7FD381E8E16FA5F815EB2998
+PT=119A244F6A3ED1947A764CFE96568213
+CT=4C8D061BD62737E674DDCACEFC37DA11
+
+I=233
+KEY=43E5036A09590404522FCCC7A9F4B60E95B26F36E9DCF389
+PT=4C8D061BD62737E674DDCACEFC37DA11
+CT=7B5EFE44536B5AB9CF75A457BB8C2417
+
+I=234
+KEY=869CF7BF36FBB5D829713283FA9FECB75AC7CB615250D79E
+PT=7B5EFE44536B5AB9CF75A457BB8C2417
+CT=25771915A1C0F8149634963E1C91BD26
+
+I=235
+KEY=C9BD373897A760E30C062B965B5F14A3CCF35D5F4EC16AB8
+PT=25771915A1C0F8149634963E1C91BD26
+CT=8BB2BC7E7BAAEA1AAF7A9E285BEEB8F1
+
+I=236
+KEY=D2EE543EACA1592687B497E820F5FEB96389C377152FD249
+PT=8BB2BC7E7BAAEA1AAF7A9E285BEEB8F1
+CT=05556B6AB68D2DABCDB32FB724D44F57
+
+I=237
+KEY=9583438F7194754F82E1FC829678D312AE3AECC031FB9D1E
+PT=05556B6AB68D2DABCDB32FB724D44F57
+CT=A4CE8197B0EAE6AD57D5A0630D0CABD0
+
+I=238
+KEY=A5B96A3EFB2EF0C7262F7D15269235BFF9EF4CA33CF736CE
+PT=A4CE8197B0EAE6AD57D5A0630D0CABD0
+CT=8E40F09865AA8EA114EA7F36E11815C3
+
+I=239
+KEY=8E7A04E47969F5DBA86F8D8D4338BB1EED053395DDEF230D
+PT=8E40F09865AA8EA114EA7F36E11815C3
+CT=194A76947319ED92D96D292684C29B5A
+
+I=240
+KEY=E52197304B446A01B125FB193021568C34681AB3592DB857
+PT=194A76947319ED92D96D292684C29B5A
+CT=93526BBB6405BDEA68AC01F1C807EBF7
+
+I=241
+KEY=DA4552EC2C076DC3227790A25424EB665CC41B42912A53A0
+PT=93526BBB6405BDEA68AC01F1C807EBF7
+CT=59860971F900B739B36CB97D35B082D1
+
+I=242
+KEY=E7329ED9491CA8227BF199D3AD245C5FEFA8A23FA49AD171
+PT=59860971F900B739B36CB97D35B082D1
+CT=92F430D5B1F35B469ECDDFDCB2A110F5
+
+I=243
+KEY=1ADC19560D9AEF09E905A9061CD7071971657DE3163BC184
+PT=92F430D5B1F35B469ECDDFDCB2A110F5
+CT=F81D2505FD9A569A71502B23894DA535
+
+I=244
+KEY=6ED932F2BEBD486911188C03E14D5183003556C09F7664B1
+PT=F81D2505FD9A569A71502B23894DA535
+CT=93BACD72A0E761D34E8603FC44F6BA5E
+
+I=245
+KEY=F0A52339F0C68F5782A2417141AA30504EB3553CDB80DEEF
+PT=93BACD72A0E761D34E8603FC44F6BA5E
+CT=631DB808708B5EBB54A2DE6B62519235
+
+I=246
+KEY=0B262E7EA7109C03E1BFF97931216EEB1A118B57B9D14CDA
+PT=631DB808708B5EBB54A2DE6B62519235
+CT=C402023DA5F2F230FEEACE1C5F8B5390
+
+I=247
+KEY=1E7EB042CA0EA74F25BDFB4494D39CDBE4FB454BE65A1F4A
+PT=C402023DA5F2F230FEEACE1C5F8B5390
+CT=CAD88E79E0AB4A3B324F6D3ABBEA211C
+
+I=248
+KEY=215E3E970705BE3DEF65753D7478D6E0D6B428715DB03E56
+PT=CAD88E79E0AB4A3B324F6D3ABBEA211C
+CT=1B2303C4FEB78105B5BF35BC1C5C2FF9
+
+I=249
+KEY=512CE443B55593D9F44676F98ACF57E5630B1DCD41EC11AF
+PT=1B2303C4FEB78105B5BF35BC1C5C2FF9
+CT=06CAE1EED611AF829C83216697F8AEFA
+
+I=250
+KEY=533251960972B2BFF28C97175CDEF867FF883CABD614BF55
+PT=06CAE1EED611AF829C83216697F8AEFA
+CT=170194A7E4E85B0A339BF86460E5ABC6
+
+I=251
+KEY=B484A158FBC3D31FE58D03B0B836A36DCC13C4CFB6F11493
+PT=170194A7E4E85B0A339BF86460E5ABC6
+CT=AF7014D972F55B0CD759CAFBC0D9483B
+
+I=252
+KEY=C470759A6962C1934AFD1769CAC3F8611B4A0E3476285CA8
+PT=AF7014D972F55B0CD759CAFBC0D9483B
+CT=E8BD547419DADD980682B701CCEF3C7E
+
+I=253
+KEY=D27A5BF9DD3B6F61A240431DD31925F91DC8B935BAC760D6
+PT=E8BD547419DADD980682B701CCEF3C7E
+CT=E8F9CFAA891A471EBBC5806F03E0E18A
+
+I=254
+KEY=041C2FF776BAF2334AB98CB75A0362E7A60D395AB927815C
+PT=E8F9CFAA891A471EBBC5806F03E0E18A
+CT=F90F888C03CEBFC9A807DF2100488B24
+
+I=255
+KEY=9BB4307835C91BA4B3B6043B59CDDD2E0E0AE67BB96F0A78
+PT=F90F888C03CEBFC9A807DF2100488B24
+CT=7874C642B44810334C2CF572DA0DEF68
+
+I=256
+KEY=56E742B84F293B68CBC2C279ED85CD1D422613096362E510
+PT=7874C642B44810334C2CF572DA0DEF68
+CT=064513BBD5E667B651B93502E86B6C43
+
+I=257
+KEY=66E28C26E01570FCCD87D1C23863AAAB139F260B8B098953
+PT=064513BBD5E667B651B93502E86B6C43
+CT=D461A03D7D8669BBC32430D00D437E59
+
+I=258
+KEY=5674831937969B7619E671FF45E5C310D0BB16DB864AF70A
+PT=D461A03D7D8669BBC32430D00D437E59
+CT=0A07F858DBD1909FF970C95ED7287FB3
+
+I=259
+KEY=D45BCD0FF3E14A7013E189A79E34538F29CBDF85516288B9
+PT=0A07F858DBD1909FF970C95ED7287FB3
+CT=C2E45D29C1DF02CB4D768682ADD73E6B
+
+I=260
+KEY=40F81EBEF03AAAABD105D48E5FEB514464BD5907FCB5B6D2
+PT=C2E45D29C1DF02CB4D768682ADD73E6B
+CT=01E21E496061DAC195F24F6D1CF22B8A
+
+I=261
+KEY=99C8875EE8221C3FD0E7CAC73F8A8B85F14F166AE0479D58
+PT=01E21E496061DAC195F24F6D1CF22B8A
+CT=71D1C35E1126F6907CDB5414B8C97E84
+
+I=262
+KEY=F1582613B3466D7FA13609992EAC7D158D94427E588EE3DC
+PT=71D1C35E1126F6907CDB5414B8C97E84
+CT=8B7BBAF63C993D4BBB098A22D00C5608
+
+I=263
+KEY=4679A2F69656CFD32A4DB36F1235405E369DC85C8882B5D4
+PT=8B7BBAF63C993D4BBB098A22D00C5608
+CT=651B19F5C1B67FC52151E7C5F1246485
+
+I=264
+KEY=A404FC3490DFC7244F56AA9AD3833F9B17CC2F9979A6D151
+PT=651B19F5C1B67FC52151E7C5F1246485
+CT=158F0AE36B5585868DFB998520318FEB
+
+I=265
+KEY=F7DCCA4394981F2D5AD9A079B8D6BA1D9A37B61C59975EBA
+PT=158F0AE36B5585868DFB998520318FEB
+CT=B62EC94231405F3FB0D160FBFF2DE27E
+
+I=266
+KEY=1F38711C9B6BD060ECF7693B8996E5222AE6D6E7A6BABCC4
+PT=B62EC94231405F3FB0D160FBFF2DE27E
+CT=464AFFA35373CEE71523FF0AFBFB1F51
+
+I=267
+KEY=6B846AAC0C448654AABD9698DAE52BC53FC529ED5D41A395
+PT=464AFFA35373CEE71523FF0AFBFB1F51
+CT=C729EA9A05D5482491CE31DBBC03CE24
+
+I=268
+KEY=BD539A9B4001B6876D947C02DF3063E1AE0B1836E1426DB1
+PT=C729EA9A05D5482491CE31DBBC03CE24
+CT=C755C048ADAD22A628B077163097415F
+
+I=269
+KEY=18B524EEF606589DAAC1BC4A729D414786BB6F20D1D52CEE
+PT=C755C048ADAD22A628B077163097415F
+CT=2DADB8F8FC76D8C997627449E44D14B2
+
+I=270
+KEY=3C2C6A047706E3DD876C04B28EEB998E11D91B693598385C
+PT=2DADB8F8FC76D8C997627449E44D14B2
+CT=2D7109526C2F1B5D08DD356B163498D7
+
+I=271
+KEY=40593D776B6C5920AA1D0DE0E2C482D319042E0223ACA08B
+PT=2D7109526C2F1B5D08DD356B163498D7
+CT=D9C1D988ABD5C892B2E5BA7BF4F584D3
+
+I=272
+KEY=72B53E4711B3DE9873DCD46849114A41ABE19479D7592458
+PT=D9C1D988ABD5C892B2E5BA7BF4F584D3
+CT=0A32E78440A8AE4A3FF74B20A3F5F7DE
+
+I=273
+KEY=C0BEF126899B305B79EE33EC09B9E40B9416DF5974ACD386
+PT=0A32E78440A8AE4A3FF74B20A3F5F7DE
+CT=E7AA36688851D8E4E08E9EFE6987C571
+
+I=274
+KEY=D16257EFEE63CC399E44058481E83CEF749841A71D2B16F7
+PT=E7AA36688851D8E4E08E9EFE6987C571
+CT=0E3E2E99FFA84F8A69CAA897017DD09C
+
+I=275
+KEY=3509E5A7A66648B9907A2B1D7E4073651D52E9301C56C66B
+PT=0E3E2E99FFA84F8A69CAA897017DD09C
+CT=96766B7F6E78537994466BDC62607C85
+
+I=276
+KEY=46BC3EB6FA22C8AC060C40621038201C891482EC7E36BAEE
+PT=96766B7F6E78537994466BDC62607C85
+CT=AA42980BBABA21DACE6D9FCD28A5B0BA
+
+I=277
+KEY=26FC66C5E5C6E585AC4ED869AA8201C647791D2156930A54
+PT=AA42980BBABA21DACE6D9FCD28A5B0BA
+CT=EC057F10222EC91403E1B6CEFCE3556A
+
+I=278
+KEY=91FBDF7B24B0FEB4404BA77988ACC8D24498ABEFAA705F3E
+PT=EC057F10222EC91403E1B6CEFCE3556A
+CT=E6E91EC6B977C3547D08F717F6702E80
+
+I=279
+KEY=5BD8360BB35CE209A6A2B9BF31DB0B8639905CF85C0071BE
+PT=E6E91EC6B977C3547D08F717F6702E80
+CT=DF9BE6A5A61CC4B66C76447202CBFADA
+
+I=280
+KEY=E58D0EFAB72342BD79395F1A97C7CF3055E6188A5ECB8B64
+PT=DF9BE6A5A61CC4B66C76447202CBFADA
+CT=8466FA526E1038CC14A2EC6D85FC4EDF
+
+I=281
+KEY=7EB51DD43B05BB26FD5FA548F9D7F7FC4144F4E7DB37C5BB
+PT=8466FA526E1038CC14A2EC6D85FC4EDF
+CT=5C5A965E386B16D50F3487D54C04AA6B
+
+I=282
+KEY=8F4BEBA429FE57C4A1053316C1BCE1294E70733297336FD0
+PT=5C5A965E386B16D50F3487D54C04AA6B
+CT=BCD57B57FAA6E3F81660113345CD24F9
+
+I=283
+KEY=4A5DA421D27E62821DD048413B1A02D158106201D2FE4B29
+PT=BCD57B57FAA6E3F81660113345CD24F9
+CT=7450D38B3A6D8C4987EE3F7F71C68FFC
+
+I=284
+KEY=77934AE2BB39BC4469809BCA01778E98DFFE5D7EA338C4D5
+PT=7450D38B3A6D8C4987EE3F7F71C68FFC
+CT=A6D1D5A31BAB1CE9F027376539B2AAE2
+
+I=285
+KEY=2C6FD4455E96F2F6CF514E691ADC92712FD96A1B9A8A6E37
+PT=A6D1D5A31BAB1CE9F027376539B2AAE2
+CT=10894E2E6275D172259D4C23332508B9
+
+I=286
+KEY=2608AB9AA8CED631DFD8004778A943030A442638A9AF668E
+PT=10894E2E6275D172259D4C23332508B9
+CT=53C2AB8E42B4EF7FF659D3FB251453C7
+
+I=287
+KEY=68840BD9639AC3128C1AABC93A1DAC7CFC1DF5C38CBB3549
+PT=53C2AB8E42B4EF7FF659D3FB251453C7
+CT=3A9C38D026561B83B0F3E7B566C66CD2
+
+I=288
+KEY=EFCDF07C0E70D051B68693191C4BB7FF4CEE1276EA7D599B
+PT=3A9C38D026561B83B0F3E7B566C66CD2
+CT=B9F7E495B96BE7C0307D8F7A53200193
+
+I=289
+KEY=87DFC62793B45EF60F71778CA520503F7C939D0CB95D5808
+PT=B9F7E495B96BE7C0307D8F7A53200193
+CT=2425FE8AAA7ED06A5FFEC11D7B289891
+
+I=290
+KEY=5FD78DA64A9F50142B5489060F5E8055236D5C11C275C099
+PT=2425FE8AAA7ED06A5FFEC11D7B289891
+CT=93BC83BCF69DBB256C27AF250FDEFAEB
+
+I=291
+KEY=81C88579E065FD16B8E80ABAF9C33B704F4AF334CDAB3A72
+PT=93BC83BCF69DBB256C27AF250FDEFAEB
+CT=A1AF953D4BD1A474B1173D4686EBB8CF
+
+I=292
+KEY=DEE7FFE9A3814D2B19479F87B2129F04FE5DCE724B4082BD
+PT=A1AF953D4BD1A474B1173D4686EBB8CF
+CT=00AAC1CD74952011A03714A6BB091653
+
+I=293
+KEY=8331CC8136829F1E19ED5E4AC687BF155E6ADAD4F04994EE
+PT=00AAC1CD74952011A03714A6BB091653
+CT=00B92CBFFC3589CEB3ECAA7D221C3F0B
+
+I=294
+KEY=FF862EBFECC11E93195472F53AB236DBED8670A9D255ABE5
+PT=00B92CBFFC3589CEB3ECAA7D221C3F0B
+CT=2E07858E94AD300A35448EFA848A767A
+
+I=295
+KEY=18B8678C5497708E3753F77BAE1F06D1D8C2FE5356DFDD9F
+PT=2E07858E94AD300A35448EFA848A767A
+CT=B02F0C98F3B7BB7807F35F6DFD925238
+
+I=296
+KEY=C90D1E18331CA38F877CFBE35DA8BDA9DF31A13EAB4D8FA7
+PT=B02F0C98F3B7BB7807F35F6DFD925238
+CT=EAACC8624146D29129ED8B904E89F04A
+
+I=297
+KEY=A08AD721EE869F2E6DD033811CEE6F38F6DC2AAEE5C47FED
+PT=EAACC8624146D29129ED8B904E89F04A
+CT=8949A5A4289B65A32C5116E8A4B55A50
+
+I=298
+KEY=CED3055CB1AC48CAE499962534750A9BDA8D3C46417125BD
+PT=8949A5A4289B65A32C5116E8A4B55A50
+CT=B632C5FD8EB9676B5504A8BA13E63E2D
+
+I=299
+KEY=AD1DA883EFFC2F3052AB53D8BACC6DF08F8994FC52971B90
+PT=B632C5FD8EB9676B5504A8BA13E63E2D
+CT=EF28A1297C07A575686B3429AC9B62D1
+
+I=300
+KEY=007F57339EC932CCBD83F2F1C6CBC885E7E2A0D5FE0C7941
+PT=EF28A1297C07A575686B3429AC9B62D1
+CT=C99F15E4000944120D1C3DD283D99BFF
+
+I=301
+KEY=3688FDD4FD7822F2741CE715C6C28C97EAFE9D077DD5E2BE
+PT=C99F15E4000944120D1C3DD283D99BFF
+CT=0AC0219E2BD43F9F19F3A0997FCB9FCD
+
+I=302
+KEY=AB54BF259C6F5CEE7EDCC68BED16B308F30D3D9E021E7D73
+PT=0AC0219E2BD43F9F19F3A0997FCB9FCD
+CT=E27242BC80823BDC09C33C1BDB2EA3BE
+
+I=303
+KEY=9C88F101B483F8399CAE84376D9488D4FACE0185D930DECD
+PT=E27242BC80823BDC09C33C1BDB2EA3BE
+CT=7ABF9BD872F54E12FB7F0B11A6D10472
+
+I=304
+KEY=971A26707E5B8BC2E6111FEF1F61C6C601B10A947FE1DABF
+PT=7ABF9BD872F54E12FB7F0B11A6D10472
+CT=336653E5166F1B4146DBEAED74D72BB7
+
+I=305
+KEY=1FFD085658F88F24D5774C0A090EDD87476AE0790B36F108
+PT=336653E5166F1B4146DBEAED74D72BB7
+CT=4849136D0509CE6C404E5685FBEEE9B8
+
+I=306
+KEY=411DF55702805FE69D3E5F670C0713EB0724B6FCF0D818B0
+PT=4849136D0509CE6C404E5685FBEEE9B8
+CT=6CF8DCFD53E2ED214A449398D8BF0F6C
+
+I=307
+KEY=504BFF39E24E870FF1C6839A5FE5FECA4D602564286717DC
+PT=6CF8DCFD53E2ED214A449398D8BF0F6C
+CT=9C8326B89B3054A46ECA3BB76BC2F292
+
+I=308
+KEY=E4F4B55125D2D1056D45A522C4D5AA6E23AA1ED343A5E54E
+PT=9C8326B89B3054A46ECA3BB76BC2F292
+CT=C85479C9E038BA5495F67D6E8B2BEB64
+
+I=309
+KEY=F2E9B605207E0FD4A511DCEB24ED103AB65C63BDC88E0E2A
+PT=C85479C9E038BA5495F67D6E8B2BEB64
+CT=145607ACFFA06C08AB958DCB7BC0BDBC
+
+I=310
+KEY=CC0D3F478519145BB147DB47DB4D7C321DC9EE76B34EB396
+PT=145607ACFFA06C08AB958DCB7BC0BDBC
+CT=ED7EE0DA132D9964BE5E7B2581C3C270
+
+I=311
+KEY=EB3AFCDD9AAB59705C393B9DC860E556A3979553328D71E6
+PT=ED7EE0DA132D9964BE5E7B2581C3C270
+CT=6B576FD09F34ED38774AA383BB88B385
+
+I=312
+KEY=866ECC1B3691532D376E544D5754086ED4DD36D08905C263
+PT=6B576FD09F34ED38774AA383BB88B385
+CT=E540518151453A18C29BE22B5DE84D5B
+
+I=313
+KEY=2B3BF12A0A10E6F9D22E05CC061132761646D4FBD4ED8F38
+PT=E540518151453A18C29BE22B5DE84D5B
+CT=7865DE74099D486ECB584BE7890F3078
+
+I=314
+KEY=3C6EA741634001E0AA4BDBB80F8C7A18DD1E9F1C5DE2BF40
+PT=7865DE74099D486ECB584BE7890F3078
+CT=5226B72FA16653187980D265EB6C7C6D
+
+I=315
+KEY=A32E19E0F06CB649F86D6C97AEEA2900A49E4D79B68EC32D
+PT=5226B72FA16653187980D265EB6C7C6D
+CT=CA0D39D92B042BECABF7A14115B3A307
+
+I=316
+KEY=E48451707115D4A03260554E85EE02EC0F69EC38A33D602A
+PT=CA0D39D92B042BECABF7A14115B3A307
+CT=EC1658D60F1D94EF514FA8EDADAB3C1D
+
+I=317
+KEY=89A589616229672BDE760D988AF396035E2644D50E965C37
+PT=EC1658D60F1D94EF514FA8EDADAB3C1D
+CT=F278CD13BF2C6A1F2D9A9F0C1113205D
+
+I=318
+KEY=6013E84EFD076E402C0EC08B35DFFC1C73BCDBD91F857C6A
+PT=F278CD13BF2C6A1F2D9A9F0C1113205D
+CT=0B1A35F604DDB043BCD0573DC0850AF0
+
+I=319
+KEY=68BCE1DC00C592E22714F57D31024C5FCF6C8CE4DF00769A
+PT=0B1A35F604DDB043BCD0573DC0850AF0
+CT=EAC4FE6F8A04871AC434322CB06308E3
+
+I=320
+KEY=1BE682363F216340CDD00B12BB06CB450B58BEC86F637E79
+PT=EAC4FE6F8A04871AC434322CB06308E3
+CT=64B6BA31C6B15BE040DC2C0A07FFE60F
+
+I=321
+KEY=2082C6C0D49B4DECA966B1237DB790A54B8492C2689C9876
+PT=64B6BA31C6B15BE040DC2C0A07FFE60F
+CT=5ECDC37FEA4176145C6A308F91659D43
+
+I=322
+KEY=23668EEA68987F8CF7AB725C97F6E6B117EEA24DF9F90535
+PT=5ECDC37FEA4176145C6A308F91659D43
+CT=BB25C81945A062A7D53531593D9910F6
+
+I=323
+KEY=10B544566773DD5F4C8EBA45D2568416C2DB9314C46015C3
+PT=BB25C81945A062A7D53531593D9910F6
+CT=48D98FFFC4E378D42CFC785B53DFC38D
+
+I=324
+KEY=7F96DD27E1C0B7B7045735BA16B5FCC2EE27EB4F97BFD64E
+PT=48D98FFFC4E378D42CFC785B53DFC38D
+CT=7DCE20BAE8345CB68103461B4AFA9F09
+
+I=325
+KEY=A73354FC47570B2679991500FE81A0746F24AD54DD454947
+PT=7DCE20BAE8345CB68103461B4AFA9F09
+CT=099B315B4DD55CAB5D02163154DA521C
+
+I=326
+KEY=92A57B873A1D292F7002245BB354FCDF3226BB65899F1B5B
+PT=099B315B4DD55CAB5D02163154DA521C
+CT=37207C17099989D3EA0D13DBD6DF7FEF
+
+I=327
+KEY=7048AF52E1763E8E4722584CBACD750CD82BA8BE5F4064B4
+PT=37207C17099989D3EA0D13DBD6DF7FEF
+CT=7CE37081A6751A1518F03B70FBC1479D
+
+I=328
+KEY=24E37AF6A4BC72403BC128CD1CB86F19C0DB93CEA4812329
+PT=7CE37081A6751A1518F03B70FBC1479D
+CT=201BBD8456F70ED0BB4E19A7AE36F1A6
+
+I=329
+KEY=17E541A643CB8EE01BDA95494A4F61C97B958A690AB7D28F
+PT=201BBD8456F70ED0BB4E19A7AE36F1A6
+CT=3384168E4F022049B0E3AD6899B71DC9
+
+I=330
+KEY=31D5A160B61690A0285E83C7054D4180CB7627019300CF46
+PT=3384168E4F022049B0E3AD6899B71DC9
+CT=C83AA6AE617CB17E2977D394EBC4AD19
+
+I=331
+KEY=6EBA775B83D704AAE06425696431F0FEE201F49578C4625F
+PT=C83AA6AE617CB17E2977D394EBC4AD19
+CT=8AC467890AF8E729C7A86A471ADEB378
+
+I=332
+KEY=C1237F715488582E6AA042E06EC917D725A99ED2621AD127
+PT=8AC467890AF8E729C7A86A471ADEB378
+CT=B89CE4F733A9D67C8E504BC4BC2F7664
+
+I=333
+KEY=0A9E4BDAD3E856F1D23CA6175D60C1ABABF9D516DE35A743
+PT=B89CE4F733A9D67C8E504BC4BC2F7664
+CT=47B421469B794A5188255ACE84D89721
+
+I=334
+KEY=4BE367B885F7AF9195888751C6198BFA23DC8FD85AED3062
+PT=47B421469B794A5188255ACE84D89721
+CT=B6B09DBF9E62C60951368C9C8B63A860
+
+I=335
+KEY=CDFB62995E4C5D4E23381AEE587B4DF372EA0344D18E9802
+PT=B6B09DBF9E62C60951368C9C8B63A860
+CT=68933B4BD0BC23EB3178347DFE68E7F6
+
+I=336
+KEY=8887EBF40DE51F064BAB21A588C76E18439237392FE67FF4
+PT=68933B4BD0BC23EB3178347DFE68E7F6
+CT=C6F16CDDF00C982A927609B559B0BCBD
+
+I=337
+KEY=221D949B8CA9F4C48D5A4D7878CBF632D1E43E8C7656C349
+PT=C6F16CDDF00C982A927609B559B0BCBD
+CT=CBEE831F7623E3214E72AF57706525C7
+
+I=338
+KEY=3D35666DACEFF3C846B4CE670EE815139F9691DB0633E68E
+PT=CBEE831F7623E3214E72AF57706525C7
+CT=DFE0297AE9B69F0AD69D6189C1447333
+
+I=339
+KEY=43370C9C958216DC9954E71DE75E8A19490BF052C77795BD
+PT=DFE0297AE9B69F0AD69D6189C1447333
+CT=59C3B4D6055B9F73064B715CD5213C99
+
+I=340
+KEY=DF43233D68EE5C4AC09753CBE205156A4F40810E1256A924
+PT=59C3B4D6055B9F73064B715CD5213C99
+CT=5373F13BB16B3653FCC138FC9A9E8A47
+
+I=341
+KEY=472E0A65B06B4F4693E4A2F0536E2339B381B9F288C82363
+PT=5373F13BB16B3653FCC138FC9A9E8A47
+CT=9C7514B7FEDF2DC26B0C2C1954745077
+
+I=342
+KEY=1409E4DF955583A00F91B647ADB10EFBD88D95EBDCBC7314
+PT=9C7514B7FEDF2DC26B0C2C1954745077
+CT=2480D7C35D6B0207D84A9CEFA1C2CFDC
+
+I=343
+KEY=458552CAB6B1A8AC2B116184F0DA0CFC00C709047D7EBCC8
+PT=2480D7C35D6B0207D84A9CEFA1C2CFDC
+CT=46DE3E51F1355FA76652C8DA3642409B
+
+I=344
+KEY=2065D6F033E1EE2E6DCF5FD501EF535B6695C1DE4B3CFC53
+PT=46DE3E51F1355FA76652C8DA3642409B
+CT=13F328173D057A64DA3917468528DB4F
+
+I=345
+KEY=6D30053E2C95BC5A7E3C77C23CEA293FBCACD698CE14271C
+PT=13F328173D057A64DA3917468528DB4F
+CT=33D71B6CD0A68B685C89C9F2D70FDFCE
+
+I=346
+KEY=59D69C2D25BFB6A34DEB6CAEEC4CA257E0251F6A191BF8D2
+PT=33D71B6CD0A68B685C89C9F2D70FDFCE
+CT=8E9F57B5E945CD7DFC2B9FCD5AF96DFB
+
+I=347
+KEY=F41ABD021E5C144EC3743B1B05096F2A1C0E80A743E29529
+PT=8E9F57B5E945CD7DFC2B9FCD5AF96DFB
+CT=71295B41B9E5872E1BD4D5C3C4C62D71
+
+I=348
+KEY=41C1194732CD4654B25D605ABCECE80407DA55648724B858
+PT=71295B41B9E5872E1BD4D5C3C4C62D71
+CT=E704FBBAA917788CE906A54B2A56A232
+
+I=349
+KEY=AF58932371569CE655599BE015FB9088EEDCF02FAD721A6A
+PT=E704FBBAA917788CE906A54B2A56A232
+CT=8DBA56CF3E019B8EA80CCB772551CA5B
+
+I=350
+KEY=B1E68A05A144F4FAD8E3CD2F2BFA0B0646D03B588823D031
+PT=8DBA56CF3E019B8EA80CCB772551CA5B
+CT=18F8A23F785AFEFC4ECD527AC6DBE609
+
+I=351
+KEY=456D39FF40B1622BC01B6F1053A0F5FA081D69224EF83638
+PT=18F8A23F785AFEFC4ECD527AC6DBE609
+CT=073F93A707D6B9A82E99990CB13BD00E
+
+I=352
+KEY=1FF446993B6927C6C724FCB754764C522684F02EFFC3E636
+PT=073F93A707D6B9A82E99990CB13BD00E
+CT=76723E1239356EDC37FB5E1EAFDF4678
+
+I=353
+KEY=0DED89E36C3B06B9B156C2A56D43228E117FAE30501CA04E
+PT=76723E1239356EDC37FB5E1EAFDF4678
+CT=1B57D35B4E2484D3945B82D59114A531
+
+I=354
+KEY=E433448EB970D64FAA0111FE2367A65D85242CE5C108057F
+PT=1B57D35B4E2484D3945B82D59114A531
+CT=4466DCB75F6B83885EE32D9FD533A902
+
+I=355
+KEY=3751EC4737F029E3EE67CD497C0C25D5DBC7017A143BAC7D
+PT=4466DCB75F6B83885EE32D9FD533A902
+CT=A8B62B9FCAA9331A3282899DB475AADE
+
+I=356
+KEY=6C1042FACD259CC346D1E6D6B6A516CFE94588E7A04E06A3
+PT=A8B62B9FCAA9331A3282899DB475AADE
+CT=DFE1CB42B29F119E44F37F60A8C2BD7C
+
+I=357
+KEY=640D2DB3E708999A99302D94043A0751ADB6F787088CBBDF
+PT=DFE1CB42B29F119E44F37F60A8C2BD7C
+CT=891B211EE1BEA05AD7BA478FDFEBC507
+
+I=358
+KEY=C434FF9BD02BDF6C102B0C8AE584A70B7A0CB008D7677ED8
+PT=891B211EE1BEA05AD7BA478FDFEBC507
+CT=16ABB92A1E0F433250C551F84AE177CF
+
+I=359
+KEY=22A76DAFC8A7748E0680B5A0FB8BE4392AC9E1F09D860917
+PT=16ABB92A1E0F433250C551F84AE177CF
+CT=1A2F4BF6ED0CADB7FA3FC52F3C6AF191
+
+I=360
+KEY=5DDEDF839CF5C0D11CAFFE561687498ED0F624DFA1ECF886
+PT=1A2F4BF6ED0CADB7FA3FC52F3C6AF191
+CT=16AE687EE38FB85C0F70E20F5585F750
+
+I=361
+KEY=13D0157C6A30C26C0A019628F508F1D2DF86C6D0F4690FD6
+PT=16AE687EE38FB85C0F70E20F5585F750
+CT=6CD2D70F641B2A7814014177C4880107
+
+I=362
+KEY=6DBFF188E61696C966D341279113DBAACB8787A730E10ED1
+PT=6CD2D70F641B2A7814014177C4880107
+CT=8CAD28041AE53AA64CE0173DBD9046C2
+
+I=363
+KEY=44A13B269C44F018EA7E69238BF6E10C8767909A8D714813
+PT=8CAD28041AE53AA64CE0173DBD9046C2
+CT=FC8D4274BA1EF15CC39E750DD1848F7B
+
+I=364
+KEY=B7A8311B81A3B82C16F32B5731E8105044F9E5975CF5C768
+PT=FC8D4274BA1EF15CC39E750DD1848F7B
+CT=01CBDAEAADE486CF655401D8F7F7E84E
+
+I=365
+KEY=A3AC668823C917DE1738F1BD9C0C969F21ADE44FAB022F26
+PT=01CBDAEAADE486CF655401D8F7F7E84E
+CT=494C3219700E06EE9C4DCB61EF932FDF
+
+I=366
+KEY=05CC07DC3CBB1A4B5E74C3A4EC029071BDE02F2E449100F9
+PT=494C3219700E06EE9C4DCB61EF932FDF
+CT=BB0E7D5CD93B1839DF5CAED7996F9560
+
+I=367
+KEY=8768468EFC3CE954E57ABEF83539884862BC81F9DDFE9599
+PT=BB0E7D5CD93B1839DF5CAED7996F9560
+CT=CC1F9A504A67C24621ED127C63AE2A36
+
+I=368
+KEY=470E251F98662CEC296524A87F5E4A0E43519385BE50BFAF
+PT=CC1F9A504A67C24621ED127C63AE2A36
+CT=A48D3751956B71F925680073B35BC0A3
+
+I=369
+KEY=533C67C061CE6B9E8DE813F9EA353BF7663993F60D0B7F0C
+PT=A48D3751956B71F925680073B35BC0A3
+CT=80143AC021E94718146EBC7808A9DDD8
+
+I=370
+KEY=0303563B9274349D0DFC2939CBDC7CEF72572F8E05A2A2D4
+PT=80143AC021E94718146EBC7808A9DDD8
+CT=B90AC6ADEE1B60228096D022EE5C681B
+
+I=371
+KEY=1E7D3A52CC112BDCB4F6EF9425C71CCDF2C1FFACEBFECACF
+PT=B90AC6ADEE1B60228096D022EE5C681B
+CT=CB8553B21250642107E824E8FB27CAEA
+
+I=372
+KEY=750A36009059323E7F73BC26379778ECF529DB4410D90025
+PT=CB8553B21250642107E824E8FB27CAEA
+CT=9C86DA9646FCFEA7E778A5498F50E01E
+
+I=373
+KEY=6876C614C460B02CE3F566B0716B864B12517E0D9F89E03B
+PT=9C86DA9646FCFEA7E778A5498F50E01E
+CT=1481357AD5690762FD6F3809F1E5F219
+
+I=374
+KEY=7CE6B00F6B651FAEF77453CAA4028129EF3E46046E6C1222
+PT=1481357AD5690762FD6F3809F1E5F219
+CT=39B64998D4370E0CB47C1DC23EDCDD03
+
+I=375
+KEY=C3F72A84EF6F4A0CCEC21A5270358F255B425BC650B0CF21
+PT=39B64998D4370E0CB47C1DC23EDCDD03
+CT=EB1BA96272D7BB044A3381439BA4CD5B
+
+I=376
+KEY=C670185A26E7DA4A25D9B33002E234211171DA85CB14027A
+PT=EB1BA96272D7BB044A3381439BA4CD5B
+CT=F87EC3D7F55DA25790718E461BA2E194
+
+I=377
+KEY=72ECF820AC459D8DDDA770E7F7BF9676810054C3D0B6E3EE
+PT=F87EC3D7F55DA25790718E461BA2E194
+CT=AD7EA1621AD7FBA975D6BB0AB9AED116
+
+I=378
+KEY=CE4ECAD1C7D17D1170D9D185ED686DDFF4D6EFC9691832F8
+PT=AD7EA1621AD7FBA975D6BB0AB9AED116
+CT=473B6484F6EAE1FC837A2710AE8D462F
+
+I=379
+KEY=3273752C9A8682F237E2B5011B828C2377ACC8D9C79574D7
+PT=473B6484F6EAE1FC837A2710AE8D462F
+CT=0E3634529E49692762F4D80333738045
+
+I=380
+KEY=8C2CFBB98A4E5E3839D4815385CBE504155810DAF4E6F492
+PT=0E3634529E49692762F4D80333738045
+CT=F8EFEBD78C115CC620F25AB66038F2A0
+
+I=381
+KEY=0416DBCAFA0850D8C13B6A8409DAB9C235AA4A6C94DE0632
+PT=F8EFEBD78C115CC620F25AB66038F2A0
+CT=B4442C38E3B8E87D8AAE2C17A5571CE9
+
+I=382
+KEY=7A7815A748696E99757F46BCEA6251BFBF04667B31891ADB
+PT=B4442C38E3B8E87D8AAE2C17A5571CE9
+CT=576A20E194015AB069D769FCA7D842FC
+
+I=383
+KEY=3848903CD019B4572215665D7E630B0FD6D30F8796515827
+PT=576A20E194015AB069D769FCA7D842FC
+CT=E253D9FB4075B021DF452B3AD51204D6
+
+I=384
+KEY=3E468D281DF03284C046BFA63E16BB2E099624BD43435CF1
+PT=E253D9FB4075B021DF452B3AD51204D6
+CT=D9454AE62207E70A34F13B0063498A8F
+
+I=385
+KEY=860E4E60B132A8851903F5401C115C243D671FBD200AD67E
+PT=D9454AE62207E70A34F13B0063498A8F
+CT=A21F7DA8A298670D631F677D23504757
+
+I=386
+KEY=27B82EDF5FFD15DDBB1C88E8BE893B295E7878C0035A9129
+PT=A21F7DA8A298670D631F677D23504757
+CT=1D239EFBABD09A029FE11C59A385C909
+
+I=387
+KEY=631BCB74800FD13AA63F16131559A12BC1996499A0DF5820
+PT=1D239EFBABD09A029FE11C59A385C909
+CT=C87EB2AB019AFA608BE99CE77717B333
+
+I=388
+KEY=EE1326871289985E6E41A4B814C35B4B4A70F87ED7C8EB13
+PT=C87EB2AB019AFA608BE99CE77717B333
+CT=528DBF70307431E33815D1AA44C30FA8
+
+I=389
+KEY=F1D72A84C2FE044F3CCC1BC824B76AA8726529D4930BE4BB
+PT=528DBF70307431E33815D1AA44C30FA8
+CT=6C8014B427ED6331A5C174CF2846B70A
+
+I=390
+KEY=A1610602C8DD2836504C0F7C035A0999D7A45D1BBB4D53B1
+PT=6C8014B427ED6331A5C174CF2846B70A
+CT=3DF4C4BE003A13030E73026F7027ADB1
+
+I=391
+KEY=B2418E725A1435DD6DB8CBC203601A9AD9D75F74CB6AFE00
+PT=3DF4C4BE003A13030E73026F7027ADB1
+CT=39C50365300DCC5B47F827054879C642
+
+I=392
+KEY=761AF29E74671706547DC8A7336DD6C19E2F787183133842
+PT=39C50365300DCC5B47F827054879C642
+CT=847F488B3CEC2E1E4E1C6B9F37E4F631
+
+I=393
+KEY=C912116E7B47169AD002802C0F81F8DFD03313EEB4F7CE73
+PT=847F488B3CEC2E1E4E1C6B9F37E4F631
+CT=9A581179C883C5E057CC560A3DF6CD34
+
+I=394
+KEY=B08B1226353C6BD34A5A9155C7023D3F87FF45E489010347
+PT=9A581179C883C5E057CC560A3DF6CD34
+CT=799B437C3EF3663EFBD6F186EDFDF21A
+
+I=395
+KEY=1ECAE821E161A2C833C1D229F9F15B017C29B46264FCF15D
+PT=799B437C3EF3663EFBD6F186EDFDF21A
+CT=138A858B14FE28D9A47C76BB3FAE9AA1
+
+I=396
+KEY=3AD2B951E451EEA8204B57A2ED0F73D8D855C2D95B526BFC
+PT=138A858B14FE28D9A47C76BB3FAE9AA1
+CT=5E35BC76C5AC8765A6C396DFE5689579
+
+I=397
+KEY=791E5F91477E986E7E7EEBD428A3F4BD7E965406BE3AFE85
+PT=5E35BC76C5AC8765A6C396DFE5689579
+CT=53F8361BF47A82EF27492322BA6F57AD
+
+I=398
+KEY=194A170B3D4FA6E62D86DDCFDCD9765259DF77240455A928
+PT=53F8361BF47A82EF27492322BA6F57AD
+CT=FF626D77AE144C11480610EC1ABB5028
+
+I=399
+KEY=C9DC82F000187721D2E4B0B872CD3A4311D967C81EEEF900
+PT=FF626D77AE144C11480610EC1ABB5028
+CT=4E46F8C5092B29E29A971A0CD1F610FB
+
+=========================
+
+KEYSIZE=256
+
+I=0
+KEY=0000000000000000000000000000000000000000000000000000000000000000
+PT=00000000000000000000000000000000
+CT=8B79EECC93A0EE5DFF30B4EA21636DA4
+
+I=1
+KEY=AD3965683E6FA98B5F38AC26653679288B79EECC93A0EE5DFF30B4EA21636DA4
+PT=8B79EECC93A0EE5DFF30B4EA21636DA4
+CT=C737317FE0846F132B23C8C2A672CE22
+
+I=2
+KEY=28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386
+PT=C737317FE0846F132B23C8C2A672CE22
+CT=E58B82BFBA53C0040DC610C642121168
+
+I=3
+KEY=0721E93EACF9DC6C870D8133376B7C0DA9C55D0CC977414AD9D56CEEC503B2EE
+PT=E58B82BFBA53C0040DC610C642121168
+CT=10B296ABB40504995DB71DDA0B7E26FB
+
+I=4
+KEY=0ECE1E210ADA32EBC497AD50F516602EB977CBA77D7245D384627134CE7D9415
+PT=10B296ABB40504995DB71DDA0B7E26FB
+CT=B7198D8E88BAA25234C18517E99BB70D
+
+I=5
+KEY=D31313ACD90A9BB7D6596DEAB752003F0E6E4629F5C8E781B0A3F42327E62318
+PT=B7198D8E88BAA25234C18517E99BB70D
+CT=6125097DB5738C64513E125872EA436C
+
+I=6
+KEY=488B6A78D9AA23FEA7289E250928BDE36F4B4F5440BB6BE5E19DE67B550C6074
+PT=6125097DB5738C64513E125872EA436C
+CT=07FF2ED24B522F1E31D46E94BE5C505B
+
+I=7
+KEY=03DDD56B142AD3B0E4FFD2BAC6568E5468B461860BE944FBD04988EFEB50302F
+PT=07FF2ED24B522F1E31D46E94BE5C505B
+CT=EB3C1E3328F840B110E934B0129F2F23
+
+I=8
+KEY=20F9D92C65B2F00183464197B23BE5AF83887FB52311044AC0A0BC5FF9CF1F0C
+PT=EB3C1E3328F840B110E934B0129F2F23
+CT=107CB7B403DC3F6F09EC30EC1718D183
+
+I=9
+KEY=79CF0BCF8EFE3DE82E27778923D1AA1993F4C80120CD3B25C94C8CB3EED7CE8F
+PT=107CB7B403DC3F6F09EC30EC1718D183
+CT=CE9DB77B1FAE0CFEC5341FA5AF4CDE8A
+
+I=10
+KEY=F50ADABA26525BFA7BF6EEF2402450785D697F7A3F6337DB0C789316419B1005
+PT=CE9DB77B1FAE0CFEC5341FA5AF4CDE8A
+CT=157B5946862DA3E9A1A83E45857E207D
+
+I=11
+KEY=3B6947995411D0AE50645129D13BACC04812263CB94E9432ADD0AD53C4E53078
+PT=157B5946862DA3E9A1A83E45857E207D
+CT=4AE3583491DF78918CAB3AC241286855
+
+I=12
+KEY=AAD12F02F5E5681D16236B668EF2C46702F17E082891ECA3217B979185CD582D
+PT=4AE3583491DF78918CAB3AC241286855
+CT=05400C32DC84F1AB486A9BADB1415B50
+
+I=13
+KEY=EA02EB82D4B2112DD3BD64C1C908CEC307B1723AF4151D0869110C3C348C037D
+PT=05400C32DC84F1AB486A9BADB1415B50
+CT=E4C0781A2EA68D142504739731EF396E
+
+I=14
+KEY=D51A1846DFEB738F0AF138F74C968DCCE3710A20DAB3901C4C157FAB05633A13
+PT=E4C0781A2EA68D142504739731EF396E
+CT=44CC8A9C84E6AD66BD24F1EE1F925EC3
+
+I=15
+KEY=B6401DFC35AF21E53CD254431CC639E9A7BD80BC5E553D7AF1318E451AF164D0
+PT=44CC8A9C84E6AD66BD24F1EE1F925EC3
+CT=20AF5FDDF65856D1A60ADC03567AE163
+
+I=16
+KEY=D1D2E8B5644910077B3EDB245F029C0D8712DF61A80D6BAB573B52464C8B85B3
+PT=20AF5FDDF65856D1A60ADC03567AE163
+CT=CEB74DD6FBEAFDCEE54930D58AF22ACA
+
+I=17
+KEY=9F932DC2AB83FA5153E7081E7360ABB449A592B753E79665B2726293C679AF79
+PT=CEB74DD6FBEAFDCEE54930D58AF22ACA
+CT=72FB3F7BBBDBA9C036C94531A32E937D
+
+I=18
+KEY=06AABCA83922297791C9D07AEB639BDD3B5EADCCE83C3FA584BB27A265573C04
+PT=72FB3F7BBBDBA9C036C94531A32E937D
+CT=299B26D5D6DFA2C20824D8A84E98A244
+
+I=19
+KEY=6124BC71768DE5E9C14D37915D90F1AE12C58B193EE39D678C9FFF0A2BCF9E40
+PT=299B26D5D6DFA2C20824D8A84E98A244
+CT=0A35C0D4170BDE0258D79B668C7C98F4
+
+I=20
+KEY=282B067BD441670E11E576F26C4EA67D18F04BCD29E84365D448646CA7B306B4
+PT=0A35C0D4170BDE0258D79B668C7C98F4
+CT=F4E3E981FFC8B50FC9146B85A22E71D4
+
+I=21
+KEY=2864E2A3986F99C55EC21C225E3498ECEC13A24CD620F66A1D5C0FE9059D7760
+PT=F4E3E981FFC8B50FC9146B85A22E71D4
+CT=130ACF4CEAFE3277DF057D4D170582ED
+
+I=22
+KEY=600FD4DFD03132B0DB7B2432DBE027C2FF196D003CDEC41DC25972A41298F58D
+PT=130ACF4CEAFE3277DF057D4D170582ED
+CT=50001D54F2EA5EAA3BE2206F3845D9A9
+
+I=23
+KEY=C1CBE3A1679D6C1913EABE3400993100AF197054CE349AB7F9BB52CB2ADD2C24
+PT=50001D54F2EA5EAA3BE2206F3845D9A9
+CT=69F3EE4B230B2DB2492FE0E36B949154
+
+I=24
+KEY=7C6C63E14606A0B09254A531CACB45A0C6EA9E1FED3FB705B094B2284149BD70
+PT=69F3EE4B230B2DB2492FE0E36B949154
+CT=CEEE40F3D2FD9A5521F44AD3AB55198D
+
+I=25
+KEY=22BB6E21BCA0450240DB117B028837AF0804DEEC3FC22D509160F8FBEA1CA4FD
+PT=CEEE40F3D2FD9A5521F44AD3AB55198D
+CT=1FA1F1AE7BF2A8C66A6ED6D5F276846B
+
+I=26
+KEY=7364D9AE40CBB0CCA6640B7E542DBA2617A52F4244308596FB0E2E2E186A2096
+PT=1FA1F1AE7BF2A8C66A6ED6D5F276846B
+CT=6D5BD8391C73507D57B902AB3D58D228
+
+I=27
+KEY=A2D8BF7602FCD22755ADA9979B2DD33B7AFEF77B5843D5EBACB72C852532F2BE
+PT=6D5BD8391C73507D57B902AB3D58D228
+CT=15ACD05539318363F275C857FBC5D86C
+
+I=28
+KEY=3AD56A33CE89D8D3510C4152DEE734126F52272E617256885EC2E4D2DEF72AD2
+PT=15ACD05539318363F275C857FBC5D86C
+CT=B54F8D944301A899A2A88440FE8AB631
+
+I=29
+KEY=13ED08137C66C2000D3FE9E167387864DA1DAABA2273FE11FC6A6092207D9CE3
+PT=B54F8D944301A899A2A88440FE8AB631
+CT=23B4BF936BF383325F0DAF0548E32851
+
+I=30
+KEY=3C2C53CCDB4721F44B6C057BF758361AF9A9152949807D23A367CF97689EB4B2
+PT=23B4BF936BF383325F0DAF0548E32851
+CT=8B4984C6F39C7FD543B4A8629EAC6740
+
+I=31
+KEY=95E744B66044529E2DC2B06BF84FF3D672E091EFBA1C02F6E0D367F5F632D3F2
+PT=8B4984C6F39C7FD543B4A8629EAC6740
+CT=108834058381578E8AA7988E03942230
+
+I=32
+KEY=E7715B09238876A93F9858D9548CBEA56268A5EA399D55786A74FF7BF5A6F1C2
+PT=108834058381578E8AA7988E03942230
+CT=EE3974A2ECEA5A1E6FC09535323BFF29
+
+I=33
+KEY=08F25145082684F576933E4DF5C63DFE8C51D148D5770F6605B46A4EC79D0EEB
+PT=EE3974A2ECEA5A1E6FC09535323BFF29
+CT=1AC80F42E3529BCA587D4EA828BD3631
+
+I=34
+KEY=93D63C9069B415595934FA66C76A9CD09699DE0A362594AC5DC924E6EF2038DA
+PT=1AC80F42E3529BCA587D4EA828BD3631
+CT=E196DF1E8A0DE844EBD3FD84B307EEB6
+
+I=35
+KEY=0F5E4A3907A7BC56AAC2CB6F6871674C770F0114BC287CE8B61AD9625C27D66C
+PT=E196DF1E8A0DE844EBD3FD84B307EEB6
+CT=917AC29C88967EE5C792E72B046A4399
+
+I=36
+KEY=B935C42A3A93D1E45E94CBE1E232A135E675C38834BE020D71883E49584D95F5
+PT=917AC29C88967EE5C792E72B046A4399
+CT=9CE3D545895005F3EC432699F17FFDA2
+
+I=37
+KEY=CC3C0DCF9E6E91BE48B7F7AE251D1CB37A9616CDBDEE07FE9DCB18D0A9326857
+PT=9CE3D545895005F3EC432699F17FFDA2
+CT=089F0D41397E27B04D3268834ADF932C
+
+I=38
+KEY=29AB63D0AB0E237BA75D250BC67E362472091B8C8490204ED0F97053E3EDFB7B
+PT=089F0D41397E27B04D3268834ADF932C
+CT=9C364B0CC209389C00824505226B8989
+
+I=39
+KEY=7FB99ABACCC92D9C8B17CC0066F02F39EE3F5080469918D2D07B3556C18672F2
+PT=9C364B0CC209389C00824505226B8989
+CT=767FB14493BE17A29839FBF115B9B38B
+
+I=40
+KEY=DB08EEBD184AEEB002302A3C41E5595B9840E1C4D5270F704842CEA7D43FC179
+PT=767FB14493BE17A29839FBF115B9B38B
+CT=CBEC5B7FB05D673C19EBF0F4B647CDB5
+
+I=41
+KEY=F7C517C27F319857F1D9DA5D29B6B76353ACBABB657A684C51A93E5362780CCC
+PT=CBEC5B7FB05D673C19EBF0F4B647CDB5
+CT=9721CB9555EF079ADD547D8DE09CC0C7
+
+I=42
+KEY=47D5164E15743853C8B0E55ED3A965D6C48D712E30956FD68CFD43DE82E4CC0B
+PT=9721CB9555EF079ADD547D8DE09CC0C7
+CT=5B16109122E874A08A2A48D5B5753256
+
+I=43
+KEY=152E7EF1B0FAD417DA84B4FA0AB560DB9F9B61BF127D1B7606D70B0B3791FE5D
+PT=5B16109122E874A08A2A48D5B5753256
+CT=198A9B7C41C225334176614A16F1D7CB
+
+I=44
+KEY=81BB271A9F0CE56E452C9FBE4CF09FF88611FAC353BF3E4547A16A4121602996
+PT=198A9B7C41C225334176614A16F1D7CB
+CT=56E255DB999AFA713020C4E987F4433B
+
+I=45
+KEY=A654ABA71B351BCBFD1CB03B5F88CE1AD0F3AF18CA25C4347781AEA8A6946AAD
+PT=56E255DB999AFA713020C4E987F4433B
+CT=7BF8470233D197839D4FC1B365E79C8D
+
+I=46
+KEY=C700B39660C3C72E15E278B2D22DD528AB0BE81AF9F453B7EACE6F1BC373F620
+PT=7BF8470233D197839D4FC1B365E79C8D
+CT=D7CDF94CBBE5E7EF7E47E4CE9BD5E073
+
+I=47
+KEY=C49B1589810F1915998C8C79CA2382D87CC611564211B45894898BD558A61653
+PT=D7CDF94CBBE5E7EF7E47E4CE9BD5E073
+CT=A5617B71AF28E732A0B69BFA3B90F291
+
+I=48
+KEY=D37A9390FD2C8D4D01704352BAFC2EE2D9A76A27ED39536A343F102F6336E4C2
+PT=A5617B71AF28E732A0B69BFA3B90F291
+CT=156D08F6A2AC3F7202DBEE15D53C8BCD
+
+I=49
+KEY=E4E2958608635DF83B8E39FD503356D5CCCA62D14F956C1836E4FE3AB60A6F0F
+PT=156D08F6A2AC3F7202DBEE15D53C8BCD
+CT=1790CB4B9B4E01F4CA3AAB588A3B7A51
+
+I=50
+KEY=B0F77AF53FB1FAF66A421093111DC925DB5AA99AD4DB6DECFCDE55623C31155E
+PT=1790CB4B9B4E01F4CA3AAB588A3B7A51
+CT=5E2DC515FE9BAE8F16188DC052C63A80
+
+I=51
+KEY=487CA8ECBA3E2CAF61A16285005F01F685776C8F2A40C363EAC6D8A26EF72FDE
+PT=5E2DC515FE9BAE8F16188DC052C63A80
+CT=A625E46D2DA293F536D25C9207090AA5
+
+I=52
+KEY=410909F6119DDA628537B825D24E8DF9235288E207E25096DC14843069FE257B
+PT=A625E46D2DA293F536D25C9207090AA5
+CT=FEFCF38ABD12EAAD37F3AE73BC4B4A8C
+
+I=53
+KEY=F1027D98B61D2F383BCF60A83D317D03DDAE7B68BAF0BA3BEBE72A43D5B56FF7
+PT=FEFCF38ABD12EAAD37F3AE73BC4B4A8C
+CT=76D8221C2AAD44D226C769875A93CDA8
+
+I=54
+KEY=DDA104019F122286887545C85F6B09B1AB765974905DFEE9CD2043C48F26A25F
+PT=76D8221C2AAD44D226C769875A93CDA8
+CT=DE7FBEB010089D7EE0A1BD18F3461AEE
+
+I=55
+KEY=46CE686778BA955831B63F2ACFE397747509E7C4805563972D81FEDC7C60B8B1
+PT=DE7FBEB010089D7EE0A1BD18F3461AEE
+CT=A8B0824BD1FC52D92AFA0B4B23ABDEBD
+
+I=56
+KEY=EF1408D365E549B808DADADE3D4CBCDADDB9658F51A9314E077BF5975FCB660C
+PT=A8B0824BD1FC52D92AFA0B4B23ABDEBD
+CT=93AC85EE8DE4091894F0E1800A0DF443
+
+I=57
+KEY=8E8FC86B7F82A57799FE32DD1C748C8D4E15E061DC4D3856938B141755C6924F
+PT=93AC85EE8DE4091894F0E1800A0DF443
+CT=0FAE963D9B74341316D7EA8862D0766F
+
+I=58
+KEY=D3900458ABB1ACCE0707A49565D27C4C41BB765C47390C45855CFE9F3716E420
+PT=0FAE963D9B74341316D7EA8862D0766F
+CT=37930DFBC771510D0BBDCBFAB2A5852F
+
+I=59
+KEY=C55EE2F5633DE3E7EF3710C6C143AA7076287BA780485D488EE1356585B3610F
+PT=37930DFBC771510D0BBDCBFAB2A5852F
+CT=9C3B82D06CB9378F6CBBF6325B456A8B
+
+I=60
+KEY=AA16073435B24614EB1E9AE81FD921F0EA13F977ECF16AC7E25AC357DEF60B84
+PT=9C3B82D06CB9378F6CBBF6325B456A8B
+CT=2DB135F2599323714B4D0E66562FAF48
+
+I=61
+KEY=033F102BFB13F9F84A4E9FC0C6F52AC8C7A2CC85B56249B6A917CD3188D9A4CC
+PT=2DB135F2599323714B4D0E66562FAF48
+CT=130D64DC60EE70F07F6A68F26A9B5E19
+
+I=62
+KEY=60D36FD89196DB13031E829B54615707D4AFA859D58C3946D67DA5C3E242FAD5
+PT=130D64DC60EE70F07F6A68F26A9B5E19
+CT=E4E5C4A1E2A0DC99EEC583E311824371
+
+I=63
+KEY=532BC273D1843EB5CC1DE01D28684454304A6CF8372CE5DF38B82620F3C0B9A4
+PT=E4E5C4A1E2A0DC99EEC583E311824371
+CT=72CCE240749A6BFD0A93CDCBE2589B41
+
+I=64
+KEY=DAE91111E43D9DF4A0F44C27A6B1AB0842868EB843B68E22322BEBEB119822E5
+PT=72CCE240749A6BFD0A93CDCBE2589B41
+CT=300F85629B48F47444D2AA51EBAAD16C
+
+I=65
+KEY=5C7C95B43BEA70F20A5C490F9A9F716372890BDAD8FE7A5676F941BAFA32F389
+PT=300F85629B48F47444D2AA51EBAAD16C
+CT=89278608A583E1243704B39AB9C0F30C
+
+I=66
+KEY=5B64FDB468399A031D5745325331C2E8FBAE8DD27D7D9B7241FDF22043F20085
+PT=89278608A583E1243704B39AB9C0F30C
+CT=71B74D5FAA4558A59F3BC91AA564579A
+
+I=67
+KEY=0166230CCF036B4B22C63D36F71C3CF58A19C08DD738C3D7DEC63B3AE696571F
+PT=71B74D5FAA4558A59F3BC91AA564579A
+CT=7B433C70951E4BD140FF7A0CBF367429
+
+I=68
+KEY=D7A12389D7DD5DE963841B344315ADF9F15AFCFD422688069E39413659A02336
+PT=7B433C70951E4BD140FF7A0CBF367429
+CT=B0BE67EBCD672549AF03D323AF026FFF
+
+I=69
+KEY=A3EC2E92C58FE150F708C6FAEB1F459E41E49B168F41AD4F313A9215F6A24CC9
+PT=B0BE67EBCD672549AF03D323AF026FFF
+CT=99A829A7C5C7CD6A44C7EABA9A5421C7
+
+I=70
+KEY=CC3F7485BF8460CB1EA0AA3C20553644D84CB2B14A86602575FD78AF6CF66D0E
+PT=99A829A7C5C7CD6A44C7EABA9A5421C7
+CT=76E1A70AF79F89CFE68EAF15DC0E9BC5
+
+I=71
+KEY=17DC64F06B3A2941A21AE58E2FFAB363AEAD15BBBD19E9EA9373D7BAB0F8F6CB
+PT=76E1A70AF79F89CFE68EAF15DC0E9BC5
+CT=DB0805B5DCC1CA2CA7489C8E1237E7A2
+
+I=72
+KEY=DC7128E894C9DA167D0ACED5888F846275A5100E61D823C6343B4B34A2CF1169
+PT=DB0805B5DCC1CA2CA7489C8E1237E7A2
+CT=935D409B87A85A2CFCC09DE3D2A9A294
+
+I=73
+KEY=8073895C9316D299F4F32C602F2F2616E6F85095E67079EAC8FBD6D77066B3FD
+PT=935D409B87A85A2CFCC09DE3D2A9A294
+CT=F22B73EFF24249CBCB31BDC7C126B735
+
+I=74
+KEY=99E16793433652800ABAD7000638560914D3237A1432302103CA6B10B14004C8
+PT=F22B73EFF24249CBCB31BDC7C126B735
+CT=A16A380AE9B3F2B0AE39BB0E24BF7C0A
+
+I=75
+KEY=8F77C5E97DA567CC447B52F45175BC74B5B91B70FD81C291ADF3D01E95FF78C2
+PT=A16A380AE9B3F2B0AE39BB0E24BF7C0A
+CT=9CF088DE60AE87687481C9F217E86A7C
+
+I=76
+KEY=DA1B3C2C424D2BC6A1C7A3D18D41C3F5294993AE9D2F45F9D97219EC821712BE
+PT=9CF088DE60AE87687481C9F217E86A7C
+CT=1C8B68951E65E32E77F1A31571351C1B
+
+I=77
+KEY=3D64F3D4BF8F585917273805AA43DCD735C2FB3B834AA6D7AE83BAF9F3220EA5
+PT=1C8B68951E65E32E77F1A31571351C1B
+CT=4AD3F3B0C15D810F0EA0FF62C6B2D0FE
+
+I=78
+KEY=51D61FB1B31EB55C7AA2D918E7BE32A97F11088B421727D8A023459B3590DE5B
+PT=4AD3F3B0C15D810F0EA0FF62C6B2D0FE
+CT=0DFCF7CA661572E050C522AE554A4BF8
+
+I=79
+KEY=B93510F7689FB9856194CF629EF63AAA72EDFF4124025538F0E6673560DA95A3
+PT=0DFCF7CA661572E050C522AE554A4BF8
+CT=7C185A5A68675DAC7A16C8DDE4B8CF8B
+
+I=80
+KEY=8496679D7598A1B91D2F221CF958F90B0EF5A51B4C6508948AF0AFE884625A28
+PT=7C185A5A68675DAC7A16C8DDE4B8CF8B
+CT=88FDDDA7BC2B09E48598A94474C64DC7
+
+I=81
+KEY=F27BCC0F919566675B129C526A4DC796860878BCF04E01700F6806ACF0A417EF
+PT=88FDDDA7BC2B09E48598A94474C64DC7
+CT=35C5C98C9C774D0BE9EFFB55C90B2F9C
+
+I=82
+KEY=05F12B58DBF5602D31CFD0EB10313502B3CDB1306C394C7BE687FDF939AF3873
+PT=35C5C98C9C774D0BE9EFFB55C90B2F9C
+CT=C3374B5C81646AC881F0F924C22A723B
+
+I=83
+KEY=FD05BE617555BC8184C2F46911C46B9E70FAFA6CED5D26B3677704DDFB854A48
+PT=C3374B5C81646AC881F0F924C22A723B
+CT=0CE756792AF27525A088700DB66D4399
+
+I=84
+KEY=3831345DFA5ADDF7CE8B5F76B5E1EBDE7C1DAC15C7AF5396C7FF74D04DE809D1
+PT=0CE756792AF27525A088700DB66D4399
+CT=401CD076E03C108A7FD79651407923E9
+
+I=85
+KEY=B101FDD95C23BE560262D355E09FC39B3C017C632793431CB828E2810D912A38
+PT=401CD076E03C108A7FD79651407923E9
+CT=88614E46C416E5164F2A63CDA9DD7B89
+
+I=86
+KEY=0B53859962A79D216E395830E36F8D45B4603225E385A60AF702814CA44C51B1
+PT=88614E46C416E5164F2A63CDA9DD7B89
+CT=7411856C8F14A2E5F6C5F1830302A66F
+
+I=87
+KEY=FE07E3B8961C2A1B3E34A50F8CFA1A45C071B7496C9104EF01C770CFA74EF7DE
+PT=7411856C8F14A2E5F6C5F1830302A66F
+CT=B0A815E93EBAC7A68F8BB420C8A5692D
+
+I=88
+KEY=9F2E0D3DB033B1929009D6C4C460B24F70D9A2A0522BC3498E4CC4EF6FEB9EF3
+PT=B0A815E93EBAC7A68F8BB420C8A5692D
+CT=AA6D27BB26275F5CB3EC3D6A8AFB80BF
+
+I=89
+KEY=5E903EF160161E1CA79A26D28FE32175DAB4851B740C9C153DA0F985E5101E4C
+PT=AA6D27BB26275F5CB3EC3D6A8AFB80BF
+CT=EAF7941A7E5D3907B6F52C1106EED2CE
+
+I=90
+KEY=60284EF35A9246CC32002028E4969309304311010A51A5128B55D594E3FECC82
+PT=EAF7941A7E5D3907B6F52C1106EED2CE
+CT=1178DD3DBDB1810E360E6FE09AA0D75C
+
+I=91
+KEY=300CB519F3203AD4589749651BD99AC7213BCC3CB7E0241CBD5BBA74795E1BDE
+PT=1178DD3DBDB1810E360E6FE09AA0D75C
+CT=584B48263DE541E93B29C6E570D4A6F4
+
+I=92
+KEY=2F79EA55D0E3EAF1D0DBD364A7D64E2A7970841A8A0565F586727C91098ABD2A
+PT=584B48263DE541E93B29C6E570D4A6F4
+CT=7B2EC27F2F1BC24EAD4FC0AA0519685C
+
+I=93
+KEY=8B46F59BF2C4B226523C203E8FD3936D025E4665A51EA7BB2B3DBC3B0C93D576
+PT=7B2EC27F2F1BC24EAD4FC0AA0519685C
+CT=13404D003576493EBB36C07C6D16A1B6
+
+I=94
+KEY=C7E75C30B0CE770A0075E3EBEB244811111E0B659068EE85900B7C47618574C0
+PT=13404D003576493EBB36C07C6D16A1B6
+CT=A083421A139DF68C8F863B337F3408BE
+
+I=95
+KEY=A957F876769BE9005DCEE4B7514FAC62B19D497F83F518091F8D47741EB17C7E
+PT=A083421A139DF68C8F863B337F3408BE
+CT=BF86650C9ECBD6C14B420FBE6B6E488B
+
+I=96
+KEY=FD4DE7532652D17C5ACCEA759C52A95C0E1B2C731D3ECEC854CF48CA75DF34F5
+PT=BF86650C9ECBD6C14B420FBE6B6E488B
+CT=75CEFAE872574AB6F26B0CAF6F08D858
+
+I=97
+KEY=54DBCDC0A57363DE6B3A032607E968C27BD5D69B6F69847EA6A444651AD7ECAD
+PT=75CEFAE872574AB6F26B0CAF6F08D858
+CT=8A3F9C96598883E9D3760C8A8FE406C6
+
+I=98
+KEY=AC10312E365401908F2C8AE371CB8C90F1EA4A0D36E1079775D248EF9533EA6B
+PT=8A3F9C96598883E9D3760C8A8FE406C6
+CT=B8B372C0CC6D164F340DF26B8F832DF8
+
+I=99
+KEY=64265CF02043C966C01DF5255F8D2867495938CDFA8C11D841DFBA841AB0C793
+PT=B8B372C0CC6D164F340DF26B8F832DF8
+CT=A7F6267A6F0CEB0EF7D07959EE065760
+
+I=100
+KEY=CF6B88FB273B247B8D64B5A323EF5760EEAF1EB79580FAD6B60FC3DDF4B690F3
+PT=A7F6267A6F0CEB0EF7D07959EE065760
+CT=AD96ADAC9B786AB78B1B46D9E026C935
+
+I=101
+KEY=4C8EEA35A90CB46AF32235997D2ADBBE4339B31B0EF890613D148504149059C6
+PT=AD96ADAC9B786AB78B1B46D9E026C935
+CT=FC7BAC9A5F64571AABF4B0A451C8D88D
+
+I=102
+KEY=0DD6D30191FABEC371CF0BA223BECF19BF421F81519CC77B96E035A04558814B
+PT=FC7BAC9A5F64571AABF4B0A451C8D88D
+CT=2B56E363834F27090FAC8061507A4787
+
+I=103
+KEY=2E69324E634312611C33F695A137AFE49414FCE2D2D3E072994CB5C11522C6CC
+PT=2B56E363834F27090FAC8061507A4787
+CT=FD37886E30CEFA28F8E8A5662A9EC5DC
+
+I=104
+KEY=8AFAC0C1507472CCB28B37CA88B7139D6923748CE21D1A5A61A410A73FBC0310
+PT=FD37886E30CEFA28F8E8A5662A9EC5DC
+CT=F7F36142C000D5162F789C392971FCE7
+
+I=105
+KEY=7DC5DA2A80219692F9F26C5934826DF29ED015CE221DCF4C4EDC8C9E16CDFFF7
+PT=F7F36142C000D5162F789C392971FCE7
+CT=D560607A0F0BE8320F2CEE56B155163F
+
+I=106
+KEY=3CC9AE3E3EB90B511C6D8CD74419D6944BB075B42D16277E41F062C8A798E9C8
+PT=D560607A0F0BE8320F2CEE56B155163F
+CT=708133FEB47A226A616900D46FA85037
+
+I=107
+KEY=8B84B7F96F9B3184D5B6402ECAE344CB3B31464A996C05142099621CC830B9FF
+PT=708133FEB47A226A616900D46FA85037
+CT=1B2ED9348FC7A4E4AD8BFCE2A148D1AD
+
+I=108
+KEY=655CB7606D17582441247D23E222ECCF201F9F7E16ABA1F08D129EFE69786852
+PT=1B2ED9348FC7A4E4AD8BFCE2A148D1AD
+CT=B2B726C8605A6F5CBA97F04E85A1F985
+
+I=109
+KEY=E0BA77DAAD3E3502AB9A6CEBEC654D0492A8B9B676F1CEAC37856EB0ECD991D7
+PT=B2B726C8605A6F5CBA97F04E85A1F985
+CT=CD7F53BB4AEB364A1D8630E0B5C4A6A2
+
+I=110
+KEY=1470D5E493B0E8212F02D4419C46A8CD5FD7EA0D3C1AF8E62A035E50591D3775
+PT=CD7F53BB4AEB364A1D8630E0B5C4A6A2
+CT=57271A960FE2170BA3F1987E694BBD16
+
+I=111
+KEY=415408E88421573F93FDBE25DD4B90C208F0F09B33F8EFED89F2C62E30568A63
+PT=57271A960FE2170BA3F1987E694BBD16
+CT=E9D47C3E926475FFDB783624C3ADB17B
+
+I=112
+KEY=40B3017DC81EEE4BF652AE8BB8CEED1DE1248CA5A19C9A12528AF00AF3FB3B18
+PT=E9D47C3E926475FFDB783624C3ADB17B
+CT=D78F96812BB55723E04BE8818C262485
+
+I=113
+KEY=9EABE9B3608ACE61684BAD3F3FED5C9736AB1A248A29CD31B2C1188B7FDD1F9D
+PT=D78F96812BB55723E04BE8818C262485
+CT=E2092227E1A3D2E525942090DA0A3F3E
+
+I=114
+KEY=B095E4F38E060016EBC4C42D3A4EFBD6D4A238036B8A1FD49755381BA5D720A3
+PT=E2092227E1A3D2E525942090DA0A3F3E
+CT=95E9EE1F56A65FF85B752FC300F525AE
+
+I=115
+KEY=9B2841F44291552EA04DE13E4E78011B414BD61C3D2C402CCC2017D8A522050D
+PT=95E9EE1F56A65FF85B752FC300F525AE
+CT=32D8465F2E11A04F8984FEE8E710CD25
+
+I=116
+KEY=67D8B10D0DDB61932E610EB077F0D85F73939043133DE06345A4E9304232C828
+PT=32D8465F2E11A04F8984FEE8E710CD25
+CT=2D9803ECFB95B2591FE56B3CBB4307F2
+
+I=117
+KEY=B0C80A38EDE23A549EF08E5DC3CEA2F25E0B93AFE8A8523A5A41820CF971CFDA
+PT=2D9803ECFB95B2591FE56B3CBB4307F2
+CT=4B19F9BCAFD471BF9014ADA19891E4E6
+
+I=118
+KEY=85C6DF29F9AEBA6087E3746BA5CF6C1515126A13477C2385CA552FAD61E02B3C
+PT=4B19F9BCAFD471BF9014ADA19891E4E6
+CT=53159BC4FBD06FD03ABAC028A536C4A0
+
+I=119
+KEY=2D42BE0B33D92ECC40DF48CF0AE0CB764607F1D7BCAC4C55F0EFEF85C4D6EF9C
+PT=53159BC4FBD06FD03ABAC028A536C4A0
+CT=BCDB1347ACD50D0084D588D4540420E3
+
+I=120
+KEY=338A4DC6E729E6FCF71095BB4E6F52FEFADCE29010794155743A675190D2CF7F
+PT=BCDB1347ACD50D0084D588D4540420E3
+CT=E12DC82E79554E1202DA471C3221A554
+
+I=121
+KEY=47597486437CBCD33FC195C56FF972BB1BF12ABE692C0F4776E0204DA2F36A2B
+PT=E12DC82E79554E1202DA471C3221A554
+CT=23A43E9D6F7C5A6C842233CCEC120EB9
+
+I=122
+KEY=CEE8CF713EBF0C609E3429E5183014BB385514230650552BF2C213814EE16492
+PT=23A43E9D6F7C5A6C842233CCEC120EB9
+CT=9F3F4349BF98D3CC00DB167F0FFDC7AB
+
+I=123
+KEY=C9B3A1CAFA0D4F0DA942C17FFB75E333A76A576AB9C886E7F21905FE411CA339
+PT=9F3F4349BF98D3CC00DB167F0FFDC7AB
+CT=C4D8B8EBEF311C11FE2404220EA65E99
+
+I=124
+KEY=8360E6F464B61C4BAE31D3A72422128463B2EF8156F99AF60C3D01DC4FBAFDA0
+PT=C4D8B8EBEF311C11FE2404220EA65E99
+CT=47E3318C721E6C094763F0A18042911D
+
+I=125
+KEY=926B00B9767D0CAD5331CD6F0343C4A92451DE0D24E7F6FF4B5EF17DCFF86CBD
+PT=47E3318C721E6C094763F0A18042911D
+CT=D709FA9A1415B0FAC71B4CF52504791F
+
+I=126
+KEY=3F4349126EF6A51FD196742CB461D01EF358249730F246058C45BD88EAFC15A2
+PT=D709FA9A1415B0FAC71B4CF52504791F
+CT=7937DD067DDB85F200A492E5824DA23C
+
+I=127
+KEY=4420ADF6906CFBF8421524E88517327C8A6FF9914D29C3F78CE12F6D68B1B79E
+PT=7937DD067DDB85F200A492E5824DA23C
+CT=B68617F1372847206BA088D7100334A4
+
+I=128
+KEY=125BEB5234B89A376ABBB2185F24BDDE3CE9EE607A0184D7E741A7BA78B2833A
+PT=B68617F1372847206BA088D7100334A4
+CT=390938BA9F2264484DE63D8003C15369
+
+I=129
+KEY=A457831AB172D88111E87C3955D0C0F205E0D6DAE523E09FAAA79A3A7B73D053
+PT=390938BA9F2264484DE63D8003C15369
+CT=A69ED32FD728337A5C25FBC2230DC788
+
+I=130
+KEY=CC7ED4183BFAE0FA0F9DD348B8E194F2A37E05F5320BD3E5F68261F8587E17DB
+PT=A69ED32FD728337A5C25FBC2230DC788
+CT=EDB9D6099202FE4AE51EEC725478FB47
+
+I=131
+KEY=686AB4F5C19296AED306ADEA4FD52D1A4EC7D3FCA0092DAF139C8D8A0C06EC9C
+PT=EDB9D6099202FE4AE51EEC725478FB47
+CT=61059EA3BF0C953762CB37E50ED7081F
+
+I=132
+KEY=8115329FADEBA92AB2827BD7701A01442FC24D5F1F05B8987157BA6F02D1E483
+PT=61059EA3BF0C953762CB37E50ED7081F
+CT=A683E36EF7CCDABDBCA683C2D6560D25
+
+I=133
+KEY=49254E8904EED2766A6A1A615B63B97C8941AE31E8C96225CDF139ADD487E9A6
+PT=A683E36EF7CCDABDBCA683C2D6560D25
+CT=8EF424771561BFEC0058C7CAA5876EF6
+
+I=134
+KEY=259194CE8701581012F5592B61BCA99507B58A46FDA8DDC9CDA9FE6771008750
+PT=8EF424771561BFEC0058C7CAA5876EF6
+CT=79AC024A7BA5FFE143D40D34F2E587A6
+
+I=135
+KEY=CA0427FE28C77D0CA25D6851CCFE58C47E19880C860D22288E7DF35383E500F6
+PT=79AC024A7BA5FFE143D40D34F2E587A6
+CT=2258AB9F0E254CE21EB9B7F6EA690671
+
+I=136
+KEY=DA9A4B566C9F670DF850F891A5274CC95C41239388286ECA90C444A5698C0687
+PT=2258AB9F0E254CE21EB9B7F6EA690671
+CT=55ACB73E8A45BF964BD040C799724DAD
+
+I=137
+KEY=9F177A6A6B524C75DB5CC0DBB6AD733209ED94AD026DD15CDB140462F0FE4B2A
+PT=55ACB73E8A45BF964BD040C799724DAD
+CT=3E904B15F2E5DDC934DABC25259CB3CF
+
+I=138
+KEY=2AD96F6874C1BA6A82C5EE80A9A2E8E5377DDFB8F0880C95EFCEB847D562F8E5
+PT=3E904B15F2E5DDC934DABC25259CB3CF
+CT=3ACFF8D5B701A5BD1355DDA705D269CB
+
+I=139
+KEY=ADD59DF57CC01DE988C6D81E65B1D00E0DB2276D4789A928FC9B65E0D0B0912E
+PT=3ACFF8D5B701A5BD1355DDA705D269CB
+CT=3EF4AC14CC954FB4A9A808C7C00A2F1F
+
+I=140
+KEY=D3EBE43C4E9C96B37133F6AF8910A25F33468B798B1CE69C55336D2710BABE31
+PT=3EF4AC14CC954FB4A9A808C7C00A2F1F
+CT=61C50D5C736AEDCF03C06FC310CC19D9
+
+I=141
+KEY=FA45F434377F2E217C4A5B7A7526CC1952838625F8760B5356F302E40076A7E8
+PT=61C50D5C736AEDCF03C06FC310CC19D9
+CT=2BF543C6548ED0344262640AD95F95C9
+
+I=142
+KEY=71EAD73C81ED5AE731D19B0B2B42F0E87976C5E3ACF8DB67149166EED9293221
+PT=2BF543C6548ED0344262640AD95F95C9
+CT=F8C1DBDD20317FEB1625634A451931B5
+
+I=143
+KEY=3FD0019D000111D4300D2CEF39F53C0D81B71E3E8CC9A48C02B405A49C300394
+PT=F8C1DBDD20317FEB1625634A451931B5
+CT=DEDB54735B8B90C8EEC66EAECFB13ED6
+
+I=144
+KEY=070976B2D3AA1E737BC24A8A794A21BE5F6C4A4DD7423444EC726B0A53813D42
+PT=DEDB54735B8B90C8EEC66EAECFB13ED6
+CT=75941A1ADA444115961E058E2D6C6396
+
+I=145
+KEY=81AC2B7F073D0D06BA8A43D3381D3A3F2AF850570D0675517A6C6E847EED5ED4
+PT=75941A1ADA444115961E058E2D6C6396
+CT=7C66BE2B0354A6549E10489AF7A83424
+
+I=146
+KEY=37BDD1946BB9B5616115F015E9162F5B569EEE7C0E52D305E47C261E89456AF0
+PT=7C66BE2B0354A6549E10489AF7A83424
+CT=F589769555BDEFD0B29E6A65313BD2E1
+
+I=147
+KEY=CF27BD543BB4EED052B808D1EE350D35A31798E95BEF3CD556E24C7BB87EB811
+PT=F589769555BDEFD0B29E6A65313BD2E1
+CT=9B3215F70FBCC5ED9CC0D6D7E1E56F11
+
+I=148
+KEY=43321308251C33234CCD9ED19E5E74AF38258D1E5453F938CA229AAC599BD700
+PT=9B3215F70FBCC5ED9CC0D6D7E1E56F11
+CT=705CCB60E0A6E997578DCC804D49D265
+
+I=149
+KEY=F2152160EAD144776BA6BDED0AC49CD24879467EB4F510AF9DAF562C14D20565
+PT=705CCB60E0A6E997578DCC804D49D265
+CT=3DA4CEC68D47E55ECF21A1C5CDAFE4E6
+
+I=150
+KEY=593B7EDAE946A5269EF33D088D1B297675DD88B839B2F5F1528EF7E9D97DE183
+PT=3DA4CEC68D47E55ECF21A1C5CDAFE4E6
+CT=32299EDBED49B66271107CA1822F179E
+
+I=151
+KEY=852E4554AD1459CE81DBA17D18DA96C447F41663D4FB4393239E8B485B52F61D
+PT=32299EDBED49B66271107CA1822F179E
+CT=45856FD2080FA9BBFA0857BCF7381823
+
+I=152
+KEY=1D8F910508F9C08DB4DE4D5C465310F4027179B1DCF4EA28D996DCF4AC6AEE3E
+PT=45856FD2080FA9BBFA0857BCF7381823
+CT=6A8C18595AF5D1E46F9F168C31566BAF
+
+I=153
+KEY=1A42C028C1ABA740D95A47ABD7B4F40D68FD61E886013BCCB609CA789D3C8591
+PT=6A8C18595AF5D1E46F9F168C31566BAF
+CT=71A41A6B6BF9FB906B0617DCB76B4BA5
+
+I=154
+KEY=3C408CB08BCAF34B2BCE6EF787A96D5219597B83EDF8C05CDD0FDDA42A57CE34
+PT=71A41A6B6BF9FB906B0617DCB76B4BA5
+CT=9105B8FC516E0B19AEDD003979F8C298
+
+I=155
+KEY=804516E36B1B5E046B15CBE1D3F26EE9885CC37FBC96CB4573D2DD9D53AF0CAC
+PT=9105B8FC516E0B19AEDD003979F8C298
+CT=27ACD01CC0403AD6DB45C7DF3E515EDE
+
+I=156
+KEY=CD8199690660BD4DBA38CE522D1A12CEAFF013637CD6F193A8971A426DFE5272
+PT=27ACD01CC0403AD6DB45C7DF3E515EDE
+CT=86E2A23AC567C5F05F15A318E38360A7
+
+I=157
+KEY=0AD8BB3D5B2A538DF0BDD50EB74CC1BA2912B159B9B13463F782B95A8E7D32D5
+PT=86E2A23AC567C5F05F15A318E38360A7
+CT=CB03EDA81BF211B5FE03D4A0879E9EDD
+
+I=158
+KEY=081040B60AE9E733243F4C39013EEDB5E2115CF1A24325D609816DFA09E3AC08
+PT=CB03EDA81BF211B5FE03D4A0879E9EDD
+CT=6F1AD4AD727348DD593459E0D7661813
+
+I=159
+KEY=A51E29D20BB0963DF854C898299E114A8D0B885CD0306D0B50B5341ADE85B41B
+PT=6F1AD4AD727348DD593459E0D7661813
+CT=236B421E3103D4C17297D3F5C8BA1D17
+
+I=160
+KEY=49D4EB9964431F42F0FC6494A47A50CCAE60CA42E133B9CA2222E7EF163FA90C
+PT=236B421E3103D4C17297D3F5C8BA1D17
+CT=118AE5A5597E8DB200B26DBE11AC4BC8
+
+I=161
+KEY=0F3F7298BE444450A0A07A4B73897720BFEA2FE7B84D347822908A510793E2C4
+PT=118AE5A5597E8DB200B26DBE11AC4BC8
+CT=DF02587F25CC4C59E6AECE98BCAACCB8
+
+I=162
+KEY=7E30984A4C0B18D2F791858B83FC960960E877989D817821C43E44C9BB392E7C
+PT=DF02587F25CC4C59E6AECE98BCAACCB8
+CT=3DA0F35FDAEF499ADBF602939FC748D4
+
+I=163
+KEY=360A7168E056892E5BF0127EA3B58CAF5D4884C7476E31BB1FC8465A24FE66A8
+PT=3DA0F35FDAEF499ADBF602939FC748D4
+CT=FE462F878CEEDDDAA00855B85A81A14B
+
+I=164
+KEY=A75B3537E0EB98FC0F41C9E1306F6667A30EAB40CB80EC61BFC013E27E7FC7E3
+PT=FE462F878CEEDDDAA00855B85A81A14B
+CT=47EA8AC561D7A9F99F64F41A9AD46E5C
+
+I=165
+KEY=219E71FC6D23A5103DE4DA9C5EDFA0AEE4E42185AA57459820A4E7F8E4ABA9BF
+PT=47EA8AC561D7A9F99F64F41A9AD46E5C
+CT=650FAE7F29A098D787F60CC3C0D77580
+
+I=166
+KEY=038A888C6EA4E9502A15110832AE0DF081EB8FFA83F7DD4FA752EB3B247CDC3F
+PT=650FAE7F29A098D787F60CC3C0D77580
+CT=0334BF8CA2835C71F2A283736D54E933
+
+I=167
+KEY=714967419F9129B9649A13A9DA3291A582DF30762174813E55F068484928350C
+PT=0334BF8CA2835C71F2A283736D54E933
+CT=1B3A09B325F3D833A3C83D941832B204
+
+I=168
+KEY=BCDB12EAF8D3C95F821C0DD324FD36BB99E539C50487590DF63855DC511A8708
+PT=1B3A09B325F3D833A3C83D941832B204
+CT=CF980ED2619858290881314B7F0B9516
+
+I=169
+KEY=B8FA32AE829E8AF3EF543A407E2D61BA567D3717651F0124FEB964972E11121E
+PT=CF980ED2619858290881314B7F0B9516
+CT=98FF5ADA0739122DBBD241847D4A318D
+
+I=170
+KEY=D62592634F0ABD21AC98887A88845E2ECE826DCD62261309456B2513535B2393
+PT=98FF5ADA0739122DBBD241847D4A318D
+CT=1824306B9F54BE4CE3F94F037B4B8569
+
+I=171
+KEY=77005AE2FA1AD6D77D36566B9E988345D6A65DA6FD72AD45A6926A102810A6FA
+PT=1824306B9F54BE4CE3F94F037B4B8569
+CT=25BA57B9035625DD268492282535960C
+
+I=172
+KEY=BE766696DC4458442056D89C96CAFDF0F31C0A1FFE2488988016F8380D2530F6
+PT=25BA57B9035625DD268492282535960C
+CT=26AEAD4ED08CA78CE2A3358F36DA0E3F
+
+I=173
+KEY=1E1D3EBC714EE191EDB2A02B64EF2C23D5B2A7512EA82F1462B5CDB73BFF3EC9
+PT=26AEAD4ED08CA78CE2A3358F36DA0E3F
+CT=10AB48E0CB1D72D82794E35DBDEF88F6
+
+I=174
+KEY=D3EAD2DA40B4C94B506A0ED75210023BC519EFB1E5B55DCC45212EEA8610B63F
+PT=10AB48E0CB1D72D82794E35DBDEF88F6
+CT=878BCAC367294B227533E1451F654960
+
+I=175
+KEY=87D0B5D4A1314054EC37B67B4245BA8C42922572829C16EE3012CFAF9975FF5F
+PT=878BCAC367294B227533E1451F654960
+CT=98CC3311EC8E8B75944503734DEAC00D
+
+I=176
+KEY=EF3FA3235BB42B1326DE67088C68E2BDDA5E16636E129D9BA457CCDCD49F3F52
+PT=98CC3311EC8E8B75944503734DEAC00D
+CT=DAF5FB711E259B498918871933A2E1FD
+
+I=177
+KEY=2EBBBB1B070658DD43299478725AA88F00ABED12703706D22D4F4BC5E73DDEAF
+PT=DAF5FB711E259B498918871933A2E1FD
+CT=AACC545DEE8FF1F5C7A91A2EE3D25C1B
+
+I=178
+KEY=E15D1FC214F23FF93886D219B4DFCD45AA67B94F9EB8F727EAE651EB04EF82B4
+PT=AACC545DEE8FF1F5C7A91A2EE3D25C1B
+CT=B844B67FBFD12E2712CCB66EBB4F7691
+
+I=179
+KEY=CC3335B792121DE55FA04A4D6FEE57B012230F302169D900F82AE785BFA0F425
+PT=B844B67FBFD12E2712CCB66EBB4F7691
+CT=3E00C548BAEE6150FAA5B67986331FD5
+
+I=180
+KEY=18DB585F810069C584251CA1E04A58382C23CA789B87B850028F51FC3993EBF0
+PT=3E00C548BAEE6150FAA5B67986331FD5
+CT=EB23DEEA8449E8FA0D828C12B98437AE
+
+I=181
+KEY=DFE08CA44B0BC4F51C43BE3631E20735C70014921FCE50AA0F0DDDEE8017DC5E
+PT=EB23DEEA8449E8FA0D828C12B98437AE
+CT=35BBE35CFC1D8FC40BC52F20D3FB35D5
+
+I=182
+KEY=0F7DCC456D50A31AC9351794BFE6DD57F2BBF7CEE3D3DF6E04C8F2CE53ECE98B
+PT=35BBE35CFC1D8FC40BC52F20D3FB35D5
+CT=DFFE7AEEAAF4762C7EB52453B1F61AD8
+
+I=183
+KEY=D34FDEB3F04FB4563BC0FD204E8D459F2D458D204927A9427A7DD69DE21AF353
+PT=DFFE7AEEAAF4762C7EB52453B1F61AD8
+CT=C648DAF9EBFB4BC6166B15BF067E107F
+
+I=184
+KEY=5E90B747C9976A3F5050B0C51F116A81EB0D57D9A2DCE2846C16C322E464E32C
+PT=C648DAF9EBFB4BC6166B15BF067E107F
+CT=057258D07CAEE57807C396FAE651855A
+
+I=185
+KEY=52D3686BC0CD56B9DFF3A69F5073F30AEE7F0F09DE7207FC6BD555D802356676
+PT=057258D07CAEE57807C396FAE651855A
+CT=B1109BE49E6E0F4C4190D8E0D717E8D0
+
+I=186
+KEY=39C89286B658E006FBF97BAB1C4874025F6F94ED401C08B02A458D38D5228EA6
+PT=B1109BE49E6E0F4C4190D8E0D717E8D0
+CT=4DDE60FEEE40402058C988092603AB53
+
+I=187
+KEY=562C9A004CBF05A4CA97994D48C0874C12B1F413AE5C4890728C0531F32125F5
+PT=4DDE60FEEE40402058C988092603AB53
+CT=3B18CBF83791E93D661EB269CFEAB1BE
+
+I=188
+KEY=F95206C4D3862E01A4DFE3676A2F297C29A93FEB99CDA1AD1492B7583CCB944B
+PT=3B18CBF83791E93D661EB269CFEAB1BE
+CT=0A3204DEE28B65E849136960949E4E5E
+
+I=189
+KEY=FEFDBE4294E46E22074E77B6BB7F964B239B3B357B46C4455D81DE38A855DA15
+PT=0A3204DEE28B65E849136960949E4E5E
+CT=6C47ECB8B1478F0BBEDEF3A05A439776
+
+I=190
+KEY=05858C957F861410187DD8CC2EE48E364FDCD78DCA014B4EE35F2D98F2164D63
+PT=6C47ECB8B1478F0BBEDEF3A05A439776
+CT=881188C2834B0496CB97F15F7A5C332A
+
+I=191
+KEY=A51CABC6D50BF9043E95CE2BC511D26DC7CD5F4F494A4FD828C8DCC7884A7E49
+PT=881188C2834B0496CB97F15F7A5C332A
+CT=1FAE86251E2F615E3BFCAC545013CD12
+
+I=192
+KEY=4EE1F6812CC35A16AA63F1CB39669ED7D863D96A57652E8613347093D859B35B
+PT=1FAE86251E2F615E3BFCAC545013CD12
+CT=6017C6764080CB6D2BAC24C0F1BFF8F5
+
+I=193
+KEY=F4F31D57DD72E6BF842D3834372AA60CB8741F1C17E5E5EB3898545329E64BAE
+PT=6017C6764080CB6D2BAC24C0F1BFF8F5
+CT=10C8548253FB2BCD5D6F87CB28FAE7E7
+
+I=194
+KEY=9DBB357DC99A95C240E750F1970C5C65A8BC4B9E441ECE2665F7D398011CAC49
+PT=10C8548253FB2BCD5D6F87CB28FAE7E7
+CT=20E253845A3DD51FFC16141FDAA20749
+
+I=195
+KEY=A814CD8766E0BFFBD8530589D6202BE0885E181A1E231B3999E1C787DBBEAB00
+PT=20E253845A3DD51FFC16141FDAA20749
+CT=9383323218D891F9DCE7578FCD6A54A5
+
+I=196
+KEY=C516C26E23E38C2B87346F759D8AEF881BDD2A2806FB8AC04506900816D4FFA5
+PT=9383323218D891F9DCE7578FCD6A54A5
+CT=9CFF8002D46EAFAAC7B035A788A37CF5
+
+I=197
+KEY=9301F8120939D0E70C97F614F61F18648722AA2AD295256A82B6A5AF9E778350
+PT=9CFF8002D46EAFAAC7B035A788A37CF5
+CT=90C9F34994D5DA86406C7E82EDDD1009
+
+I=198
+KEY=82B163831972D2CEF8F1780AA6B0707A17EB59634640FFECC2DADB2D73AA9359
+PT=90C9F34994D5DA86406C7E82EDDD1009
+CT=C8B5021EE84635EB7E7D0F5DBE967FD0
+
+I=199
+KEY=F99FF8714EE5D822E0E25C499D7C96ACDF5E5B7DAE06CA07BCA7D470CD3CEC89
+PT=C8B5021EE84635EB7E7D0F5DBE967FD0
+CT=15CCB3C950764E24CA714707034DF9A7
+
+I=200
+KEY=3529E6B83266BD558B7F33FC00AE4904CA92E8B4FE70842376D69377CE71152E
+PT=15CCB3C950764E24CA714707034DF9A7
+CT=5FDA0EF6A2172D5DAA8E842F061A2E44
+
+I=201
+KEY=2D77F95D8B556740CD9E2CC546CA45C99548E6425C67A97EDC581758C86B3B6A
+PT=5FDA0EF6A2172D5DAA8E842F061A2E44
+CT=808781D0D10B3A02333E0A53E159287F
+
+I=202
+KEY=79298FD5F3C4B6378403CFAD05C3C96E15CF67928D6C937CEF661D0B29321315
+PT=808781D0D10B3A02333E0A53E159287F
+CT=CC760400725FCFD37E757D99C6361B93
+
+I=203
+KEY=69535F335F6AEBF452407F3F1C203410D9B96392FF335CAF91136092EF040886
+PT=CC760400725FCFD37E757D99C6361B93
+CT=247D3A6BB4C883C142C4000B085C3B79
+
+I=204
+KEY=1A4F8FD7BD8DBCFB3677C708CDDDC7C4FDC459F94BFBDF6ED3D76099E75833FF
+PT=247D3A6BB4C883C142C4000B085C3B79
+CT=47E4C802C61E6A1706BAE95AF75CA70D
+
+I=205
+KEY=A573989455A11CAD1E8642CD774806B1BA2091FB8DE5B579D56D89C3100494F2
+PT=47E4C802C61E6A1706BAE95AF75CA70D
+CT=4297101350A5CE6C435FAD2725C22E46
+
+I=206
+KEY=8D52414DD5600AA0CACD5AD399FD1B37F8B781E8DD407B15963224E435C6BAB4
+PT=4297101350A5CE6C435FAD2725C22E46
+CT=BEC56BF1F3B6BE60C0F4CB7AE77BF0F5
+
+I=207
+KEY=49D4DF2FB3B561817F2BA6599B66C9244672EA192EF6C57556C6EF9ED2BD4A41
+PT=BEC56BF1F3B6BE60C0F4CB7AE77BF0F5
+CT=5B590F24D329BB6ED981938A4CDB9907
+
+I=208
+KEY=68BD5721E2A51A184CDBAC3A035670701D2BE53DFDDF7E1B8F477C149E66D346
+PT=5B590F24D329BB6ED981938A4CDB9907
+CT=A8A15DBB79BB9B1131EF39C1E3FCFC9C
+
+I=209
+KEY=2CC71F1B9BE892100E8A340E61D0A128B58AB8868464E50ABEA845D57D9A2FDA
+PT=A8A15DBB79BB9B1131EF39C1E3FCFC9C
+CT=E8CBAB9E98D2866E779512AAC2FA2EA0
+
+I=210
+KEY=EEF45CE1BB444A6BA5A029363FB9D4DB5D4113181CB66364C93D577FBF60017A
+PT=E8CBAB9E98D2866E779512AAC2FA2EA0
+CT=7E4896F0A48A25FFE950B74B96F5F40E
+
+I=211
+KEY=151FE809785C11F8F19F31EA0246B416230985E8B83C469B206DE0342995F574
+PT=7E4896F0A48A25FFE950B74B96F5F40E
+CT=E1C642B54B89822E73A695C851BC8EBE
+
+I=212
+KEY=14FE470CD366C580F124EA924B918BF5C2CFC75DF3B5C4B553CB75FC78297BCA
+PT=E1C642B54B89822E73A695C851BC8EBE
+CT=5FA2C6A2303ED7219984F30B78BE6B96
+
+I=213
+KEY=92E61F4C495462354EF612492557D6AB9D6D01FFC38B1394CA4F86F70097105C
+PT=5FA2C6A2303ED7219984F30B78BE6B96
+CT=3791959FBF178682A711623C2F91616C
+
+I=214
+KEY=6C0B6F23AC7526204C451A8ADE54D404AAFC94607C9C95166D5EE4CB2F067130
+PT=3791959FBF178682A711623C2F91616C
+CT=E14FCACD5FD26FC2710776EE82317ABC
+
+I=215
+KEY=0DAE926E4172586817730DB9FDF2CE0B4BB35EAD234EFAD41C599225AD370B8C
+PT=E14FCACD5FD26FC2710776EE82317ABC
+CT=E576499EAF5365E7FE3B4961D9C74419
+
+I=216
+KEY=DCD553F2977BD114B61F724ABC6AFE8EAEC517338C1D9F33E262DB4474F04F95
+PT=E576499EAF5365E7FE3B4961D9C74419
+CT=38567558119E72929F2932E6C289095E
+
+I=217
+KEY=6333DA8D5B655B5B5AABBCAF0B010BE89693626B9D83EDA17D4BE9A2B67946CB
+PT=38567558119E72929F2932E6C289095E
+CT=D20AD648F558E5507CC5C905E92CC268
+
+I=218
+KEY=F9010180B464FBB8AD7C9D5E41B1E09A4499B42368DB08F1018E20A75F5584A3
+PT=D20AD648F558E5507CC5C905E92CC268
+CT=00C719F3757DDD2D2E64C3F2666FB2CB
+
+I=219
+KEY=8CE68ED02B4FFD9720B3D16FAE92D164445EADD01DA6D5DC2FEAE355393A3668
+PT=00C719F3757DDD2D2E64C3F2666FB2CB
+CT=AEEAB9F50456CA3233A964219D2E7816
+
+I=220
+KEY=57E26BA4DBD3549051B0D9436EB38D4FEAB4142519F01FEE1C438774A4144E7E
+PT=AEEAB9F50456CA3233A964219D2E7816
+CT=3F02C97E127FD697AFD58BC66941F654
+
+I=221
+KEY=4D0BC4A8796407C939797EF19D0CE7E3D5B6DD5B0B8FC979B3960CB2CD55B82A
+PT=3F02C97E127FD697AFD58BC66941F654
+CT=BC4C0DDBCF0003B7814EEF1ABD22B6A8
+
+I=222
+KEY=9C1FD1789544D2F3FF84574A216767CD69FAD080C48FCACE32D8E3A870770E82
+PT=BC4C0DDBCF0003B7814EEF1ABD22B6A8
+CT=D125D8C2920ADD3EA00103DC695A0D9D
+
+I=223
+KEY=ADBE97F99DBE61213892D9849B81B3FBB8DF0842568517F092D9E074192D031F
+PT=D125D8C2920ADD3EA00103DC695A0D9D
+CT=C0C57598639BA69E13C82E3AF24777C5
+
+I=224
+KEY=A14DC5CF6CD0BD9AC9499317C509CCB4781A7DDA351EB16E8111CE4EEB6A74DA
+PT=C0C57598639BA69E13C82E3AF24777C5
+CT=81E3B8F6A691BC30AA66AD70F0358881
+
+I=225
+KEY=0EC479D8681AC8CA455D64A4BB34C86DF9F9C52C938F0D5E2B77633E1B5FFC5B
+PT=81E3B8F6A691BC30AA66AD70F0358881
+CT=3CD03908D4ABA4B9885BCB1AC89D16C3
+
+I=226
+KEY=E74102D814426E659732B303E6D44DB7C529FC244724A9E7A32CA824D3C2EA98
+PT=3CD03908D4ABA4B9885BCB1AC89D16C3
+CT=61662DD8EE676E17AE5CF2BABDC54A67
+
+I=227
+KEY=EE4034F1A2EF16D7D848BB005CDA5E99A44FD1FCA943C7F00D705A9E6E07A0FF
+PT=61662DD8EE676E17AE5CF2BABDC54A67
+CT=4E637432B0FF54FD665A902725B977EB
+
+I=228
+KEY=45E8F2DF7FC6E49FB0AF3B73788A1065EA2CA5CE19BC930D6B2ACAB94BBED714
+PT=4E637432B0FF54FD665A902725B977EB
+CT=E53D1440407503B66530EEEEBBC9182B
+
+I=229
+KEY=0BEBC981186DEF84C01688CA16A061E00F11B18E59C990BB0E1A2457F077CF3F
+PT=E53D1440407503B66530EEEEBBC9182B
+CT=12134ADF5BB16D867B4EE9CE87EBE36D
+
+I=230
+KEY=6FADFDB92B0F888514730F17A37A81B61D02FB510278FD3D7554CD99779C2C52
+PT=12134ADF5BB16D867B4EE9CE87EBE36D
+CT=310EACEF26A3EB5E4511437145DC30F9
+
+I=231
+KEY=A565724F25EE29346543964864A0FFAA2C0C57BE24DB166330458EE832401CAB
+PT=310EACEF26A3EB5E4511437145DC30F9
+CT=6848E5A618419EC6BACD9CD40BB42083
+
+I=232
+KEY=1FAEBFE13AC7545DC742ED60241BC2E84444B2183C9A88A58A88123C39F43C28
+PT=6848E5A618419EC6BACD9CD40BB42083
+CT=C64DA25E7CB1A004E31CD37F9D4E1112
+
+I=233
+KEY=A8EE2725373C48BAD9C0009C53C298A982091046402B28A16994C143A4BA2D3A
+PT=C64DA25E7CB1A004E31CD37F9D4E1112
+CT=D02E6AE8FDD0C5813669080AA7B82527
+
+I=234
+KEY=0770874A41ED1396940D75E6A5A09F5352277AAEBDFBED205FFDC9490302081D
+PT=D02E6AE8FDD0C5813669080AA7B82527
+CT=5DDFBC75FE48D88E7D6F307E4A008BC7
+
+I=235
+KEY=D7D098F85AB45E754629D2AB7DA2226C0FF8C6DB43B335AE2292F937490283DA
+PT=5DDFBC75FE48D88E7D6F307E4A008BC7
+CT=E216C9AC28239E97237930079739ECE0
+
+I=236
+KEY=5D6FAFF37EE7400691E504578251ECB1EDEE0F776B90AB3901EBC930DE3B6F3A
+PT=E216C9AC28239E97237930079739ECE0
+CT=8D126659360D03548879000642E78029
+
+I=237
+KEY=D75C5C64D94D0BC8566F568278B502D560FC692E5D9DA86D8992C9369CDCEF13
+PT=8D126659360D03548879000642E78029
+CT=9EA4C85D0F07AD618A2EBEBBE50D72B6
+
+I=238
+KEY=D42BD9CDCD8BDA71E64817A2755C97C0FE58A173529A050C03BC778D79D19DA5
+PT=9EA4C85D0F07AD618A2EBEBBE50D72B6
+CT=1F525901AF1D94BA6CA3C7244E2CD885
+
+I=239
+KEY=32DD1758D2EFC602EE85C58A66D0B080E10AF872FD8791B66F1FB0A937FD4520
+PT=1F525901AF1D94BA6CA3C7244E2CD885
+CT=E131C071BFA21FCE21D18DB87B522903
+
+I=240
+KEY=BEC98C02D74E088458A668D0B6DDCF13003B380342258E784ECE3D114CAF6C23
+PT=E131C071BFA21FCE21D18DB87B522903
+CT=51F1B72C99C869BF73A6637D3A2E2278
+
+I=241
+KEY=D368F7BE25A6A0C9AD2004E764F43A3551CA8F2FDBEDE7C73D685E6C76814E5B
+PT=51F1B72C99C869BF73A6637D3A2E2278
+CT=0965CDD7A134672036F0C69774CFD380
+
+I=242
+KEY=E5A7E12124540DBB4147A55C276A35B958AF42F87AD980E70B9898FB024E9DDB
+PT=0965CDD7A134672036F0C69774CFD380
+CT=52ECEB721073FBF3D1BD5808351BEC5E
+
+I=243
+KEY=7D9702E2C8906805A580D5D85B03BBC60A43A98A6AAA7B14DA25C0F337557185
+PT=52ECEB721073FBF3D1BD5808351BEC5E
+CT=493CE4E2B090DA3A2354C9DA7DB44D39
+
+I=244
+KEY=8EFA5EC96F3AEF51AB38F4CCD969E5D5437F4D68DA3AA12EF97109294AE13CBC
+PT=493CE4E2B090DA3A2354C9DA7DB44D39
+CT=DA64246FF65969995F9A4E8AE7C805CF
+
+I=245
+KEY=19C97957444E9931293047A647D7A19A991B69072C63C8B7A6EB47A3AD293973
+PT=DA64246FF65969995F9A4E8AE7C805CF
+CT=CF85EBD76908CD8F8D3177E53DA3AD5E
+
+I=246
+KEY=7BDB3ED45BD78C131611FD9D54B8E9D2569E82D0456B05382BDA3046908A942D
+PT=CF85EBD76908CD8F8D3177E53DA3AD5E
+CT=45E1FDEFC98E62A841BD1D8D8236CEEF
+
+I=247
+KEY=19961521A42D96238D44F651E7E7D463137F7F3F8CE567906A672DCB12BC5AC2
+PT=45E1FDEFC98E62A841BD1D8D8236CEEF
+CT=E056EF7B711A9CBDED8878EF74AF1671
+
+I=248
+KEY=343360636E697E607319D4DCBC12B543F3299044FDFFFB2D87EF552466134CB3
+PT=E056EF7B711A9CBDED8878EF74AF1671
+CT=E4EFF77C6C3273393BE4814A16C3DF4A
+
+I=249
+KEY=B63D4D3D099F8E68F6A041D2EB1B1C1417C6673891CD8814BC0BD46E70D093F9
+PT=E4EFF77C6C3273393BE4814A16C3DF4A
+CT=EC562E353DF8BA76699B01A6ACC8AD52
+
+I=250
+KEY=EF500379EDE772968F1499F07B0B09CFFB90490DAC353262D590D5C8DC183EAB
+PT=EC562E353DF8BA76699B01A6ACC8AD52
+CT=4473050ADC687112AACB86AA73CB6C6D
+
+I=251
+KEY=EA5CD4EDD99E64018AD3104026F0F528BFE34C07705D43707F5B5362AFD352C6
+PT=4473050ADC687112AACB86AA73CB6C6D
+CT=6561A82EE86E4F18DF6965312F0C0984
+
+I=252
+KEY=2ABF9529FC88D85FF68CF6D72B9A9CB5DA82E42998330C68A032365380DF5B42
+PT=6561A82EE86E4F18DF6965312F0C0984
+CT=47590CE1C90F3AC2C68B272B4A667F61
+
+I=253
+KEY=A485B647790DBFF76F16C42A39F5F5559DDBE8C8513C36AA66B91178CAB92423
+PT=47590CE1C90F3AC2C68B272B4A667F61
+CT=4ED731A36BCB2672A810633E432D8922
+
+I=254
+KEY=F0D0E858B597595A06458FF6C2259127D30CD96B3AF710D8CEA972468994AD01
+PT=4ED731A36BCB2672A810633E432D8922
+CT=4AC2F0D5F52762F77DB5D9EF53B76642
+
+I=255
+KEY=EDDE80556ECA4CC51EFB33E23C43C04399CE29BECFD0722FB31CABA9DA23CB43
+PT=4AC2F0D5F52762F77DB5D9EF53B76642
+CT=A574FBE71E359A57D57A24A388FDF6EE
+
+I=256
+KEY=3C7C248C9FCE1D060D5B0664C0FF3F6B3CBAD259D1E5E87866668F0A52DE3DAD
+PT=A574FBE71E359A57D57A24A388FDF6EE
+CT=CCC3A011108469A7987F336C209BB84E
+
+I=257
+KEY=D43727570A809BE0D9EB78760FE4CDA9F0797248C16181DFFE19BC66724585E3
+PT=CCC3A011108469A7987F336C209BB84E
+CT=686357D3013977390164834D4E5324DC
+
+I=258
+KEY=2F060E361977E544B98779AB55886D57981A259BC058F6E6FF7D3F2B3C16A13F
+PT=686357D3013977390164834D4E5324DC
+CT=DDDAD6FBDBF7C7BE7EBF3F036009A270
+
+I=259
+KEY=A3630C05DC65905D37AFDB315B2AA4D945C0F3601BAF315881C200285C1F034F
+PT=DDDAD6FBDBF7C7BE7EBF3F036009A270
+CT=237124FEDF28B4201B6D1584B93D5F7C
+
+I=260
+KEY=3E6ADAAEF53A36294CDEA0D94BE742C166B1D79EC48785789AAF15ACE5225C33
+PT=237124FEDF28B4201B6D1584B93D5F7C
+CT=D1A9DDFB5662934AAD98B2861E50A871
+
+I=261
+KEY=234615019E03C466AEA186112C4EB523B7180A6592E516323737A72AFB72F442
+PT=D1A9DDFB5662934AAD98B2861E50A871
+CT=CA18344F4C7A0F068398CA8137C056DD
+
+I=262
+KEY=22ED93581611798050E94CC70F6090BF7D003E2ADE9F1934B4AF6DABCCB2A29F
+PT=CA18344F4C7A0F068398CA8137C056DD
+CT=91FA4D62D10E852D9EDA42FAC8C34557
+
+I=263
+KEY=A5981D9A37D6D3D948391D1D462B6DCFECFA73480F919C192A752F510471E7C8
+PT=91FA4D62D10E852D9EDA42FAC8C34557
+CT=B956221510135066B2B2552C4CB37642
+
+I=264
+KEY=BF2E4397D0E93DFFA38D69B30F33835B55AC515D1F82CC7F98C77A7D48C2918A
+PT=B956221510135066B2B2552C4CB37642
+CT=300CFCEAFED28E622CD08222D3A3B0B0
+
+I=265
+KEY=55432143B807A628001F8D062CE0157265A0ADB7E150421DB417F85F9B61213A
+PT=300CFCEAFED28E622CD08222D3A3B0B0
+CT=26681BCFDC630A21A684C60EF6A23747
+
+I=266
+KEY=2966A6CB3BA9028583813B91FD72748D43C8B6783D33483C12933E516DC3167D
+PT=26681BCFDC630A21A684C60EF6A23747
+CT=8EDD4B1B458D16841AD4525C01A8397E
+
+I=267
+KEY=1A22288AC28060F8E4B20C2AE0C82AEACD15FD6378BE5EB808476C0D6C6B2F03
+PT=8EDD4B1B458D16841AD4525C01A8397E
+CT=BFDE412A7CAF0326AD1727996056A61C
+
+I=268
+KEY=C882E880508E92FF709E9BD4A555B30A72CBBC4904115D9EA5504B940C3D891F
+PT=BFDE412A7CAF0326AD1727996056A61C
+CT=88C039A0B395C5D08848C64DFC150C57
+
+I=269
+KEY=298B3829EE60112C926E1FD583C9A2DEFA0B85E9B784984E2D188DD9F0288548
+PT=88C039A0B395C5D08848C64DFC150C57
+CT=ACDF23F2CB73FD8D3D814A79E3C94126
+
+I=270
+KEY=2F2A3D0DDB2DBA8B8E3FF8A9DE765FE356D4A61B7CF765C31099C7A013E1C46E
+PT=ACDF23F2CB73FD8D3D814A79E3C94126
+CT=A8BE26FE8780972650D5F384B744AC44
+
+I=271
+KEY=F8CC20E8296CD38F1EF8BB2777EE1200FE6A80E5FB77F2E5404C3424A4A5682A
+PT=A8BE26FE8780972650D5F384B744AC44
+CT=B5557CC20F64FCC576A6EC7BE324CE43
+
+I=272
+KEY=678B5341F1BC13DB366B36D59ADADC7C4B3FFC27F4130E2036EAD85F4781A669
+PT=B5557CC20F64FCC576A6EC7BE324CE43
+CT=B59281EFF9C8D19E5D9C053CBE1F2F33
+
+I=273
+KEY=E4701C9009693E38C455CE186A4B87DFFEAD7DC80DDBDFBE6B76DD63F99E895A
+PT=B59281EFF9C8D19E5D9C053CBE1F2F33
+CT=7E8B1D4BFF81C5B9AA1FCA81DF8DE64F
+
+I=274
+KEY=C1F886CBCBF2BD920A0E68F30FCB8FCE80266083F25A1A07C16917E226136F15
+PT=7E8B1D4BFF81C5B9AA1FCA81DF8DE64F
+CT=20841B35C77A109B528A1135E17D36EE
+
+I=275
+KEY=F05D61A9441B3C741D9D7489F2EE4A5EA0A27BB635200A9C93E306D7C76E59FB
+PT=20841B35C77A109B528A1135E17D36EE
+CT=C3195DC001FA1AD7C253DD3FE4A4BC7D
+
+I=276
+KEY=0C8E70943252DD5DC9819A9FDB375B3F63BB267634DA104B51B0DBE823CAE586
+PT=C3195DC001FA1AD7C253DD3FE4A4BC7D
+CT=7E06BD1B3440DB4CA73AF1A05B33AD3F
+
+I=277
+KEY=84F1B5CF1AD11205E98ECD317AD670A11DBD9B6D009ACB07F68A2A4878F948B9
+PT=7E06BD1B3440DB4CA73AF1A05B33AD3F
+CT=6224DBD71C1DC35A5C62777D2EA32C3E
+
+I=278
+KEY=E3465353AED687EF62CD1DA8D7DA3EEB7F9940BA1C87085DAAE85D35565A6487
+PT=6224DBD71C1DC35A5C62777D2EA32C3E
+CT=1E4E51CD7BA1F7467AC69755F8894EF4
+
+I=279
+KEY=31F715D1FFA116F58AB70E4A3EEF6E9561D711776726FF1BD02ECA60AED32A73
+PT=1E4E51CD7BA1F7467AC69755F8894EF4
+CT=4AB8AFEACB2A1B1AE9E74D647266E234
+
+I=280
+KEY=487B6847CA14B04D429C81278332273F2B6FBE9DAC0CE40139C98704DCB5C847
+PT=4AB8AFEACB2A1B1AE9E74D647266E234
+CT=64C0BBA15382C142BBEE84B86B7D0BA0
+
+I=281
+KEY=D1C9CA26B21945011B044EA6E29C9AD54FAF053CFF8E2543822703BCB7C8C3E7
+PT=64C0BBA15382C142BBEE84B86B7D0BA0
+CT=F82292AF614648EC6C1E9A1027167410
+
+I=282
+KEY=3F585C00E187BE1B0C9E09781C9548A8B78D97939EC86DAFEE3999AC90DEB7F7
+PT=F82292AF614648EC6C1E9A1027167410
+CT=31C38ED5F207B412A14A51632D8805CE
+
+I=283
+KEY=340B8C115BAFF387400CD8F0EE8F8F6F864E19466CCFD9BD4F73C8CFBD56B239
+PT=31C38ED5F207B412A14A51632D8805CE
+CT=3FC4CC8F4245BBBC5939A0C0A24A14DE
+
+I=284
+KEY=EA8EACF07402225D6C5181A8802DA515B98AD5C92E8A6201164A680F1F1CA6E7
+PT=3FC4CC8F4245BBBC5939A0C0A24A14DE
+CT=23A98FA41D6C3D4CD9CFB9737A6D7872
+
+I=285
+KEY=56EF7B73BF04F5F463E4D0EA0F6FC4DA9A235A6D33E65F4DCF85D17C6571DE95
+PT=23A98FA41D6C3D4CD9CFB9737A6D7872
+CT=82CC2D376B2772B7B988BEA17EFBB3D2
+
+I=286
+KEY=C425E380DA91C34B73CE922C59B13C8818EF775A58C12DFA760D6FDD1B8A6D47
+PT=82CC2D376B2772B7B988BEA17EFBB3D2
+CT=5330F6218D528A32B24085EA496A05A9
+
+I=287
+KEY=EA66C7FF9FCD2F9E76BCC5C6387E133E4BDF817BD593A7C8C44DEA3752E068EE
+PT=5330F6218D528A32B24085EA496A05A9
+CT=7C1E082C2C89C90AD91AE81DF73F1F5F
+
+I=288
+KEY=C89CF336490832FB54BB536813AEE6EA37C18957F91A6EC21D57022AA5DF77B1
+PT=7C1E082C2C89C90AD91AE81DF73F1F5F
+CT=2AB33673B654E2C49D6736D65A5F45C8
+
+I=289
+KEY=7CC5409A9AE1F997774C3FEB74A6E9061D72BF244F4E8C06803034FCFF803279
+PT=2AB33673B654E2C49D6736D65A5F45C8
+CT=21BA6CADDCA5E0BE779D1A2651794C81
+
+I=290
+KEY=E5E1873FDEE9DC066AF79C0E6027D0703CC8D38993EB6CB8F7AD2EDAAEF97EF8
+PT=21BA6CADDCA5E0BE779D1A2651794C81
+CT=8E2AF8BA54CF04812AE786C180FCFCA8
+
+I=291
+KEY=844AA67914DE1C11677B5526D5B12765B2E22B33C7246839DD4AA81B2E058250
+PT=8E2AF8BA54CF04812AE786C180FCFCA8
+CT=E48A7CD35CA33B1D919B8A83ADF4C6BE
+
+I=292
+KEY=FE3248768ACB0AF9DBD639AF7B7EB944566857E09B8753244CD1229883F144EE
+PT=E48A7CD35CA33B1D919B8A83ADF4C6BE
+CT=C377A76CF43C27784CC54079744413D1
+
+I=293
+KEY=709E7BC30A7DE8FADC071B3D04338FCA951FF08C6FBB745C001462E1F7B5573F
+PT=C377A76CF43C27784CC54079744413D1
+CT=01D8083A9EA403A4754EF82CA29CDD5B
+
+I=294
+KEY=448B1AEC2F68D202679183D85C4A6D2194C7F8B6F11F77F8755A9ACD55298A64
+PT=01D8083A9EA403A4754EF82CA29CDD5B
+CT=46ADC32EFF2C3EFF40B468E845EFC2E4
+
+I=295
+KEY=529401616FA6193014D6A10BEF1A816FD26A3B980E33490735EEF22510C64880
+PT=46ADC32EFF2C3EFF40B468E845EFC2E4
+CT=FCC6594B1BBF40E28BE798ABC00163F1
+
+I=296
+KEY=15A5E8BAF02EF91390AB7D35742CC5C12EAC62D3158C09E5BE096A8ED0C72B71
+PT=FCC6594B1BBF40E28BE798ABC00163F1
+CT=28D35B6E1140738ED1DF20FE11003B1E
+
+I=297
+KEY=589C04ECDF2B884807919A2018A93080067F39BD04CC7A6B6FD64A70C1C7106F
+PT=28D35B6E1140738ED1DF20FE11003B1E
+CT=3354C7962E19FB043FD4CD7B2C99E195
+
+I=298
+KEY=A6987BEB541098C7173475B34568F36B352BFE2B2AD5816F5002870BED5EF1FA
+PT=3354C7962E19FB043FD4CD7B2C99E195
+CT=EB76F282C9F10F507FACFCDEEC8BBBB8
+
+I=299
+KEY=3732B395057761A8A2624F52354668CFDE5D0CA9E3248E3F2FAE7BD501D54A42
+PT=EB76F282C9F10F507FACFCDEEC8BBBB8
+CT=77A4DAE8406992C5018D6B0310195E0C
+
+I=300
+KEY=E24C9F98F43E840AE04ED4928133F65AA9F9D641A34D1CFA2E2310D611CC144E
+PT=77A4DAE8406992C5018D6B0310195E0C
+CT=655DEC1062EDB50B8B31A66071E236A2
+
+I=301
+KEY=8BA207CA6E2B720810E66CCAB597E8DACCA43A51C1A0A9F1A512B6B6602E22EC
+PT=655DEC1062EDB50B8B31A66071E236A2
+CT=28A22A069D8FF3DE359860B0A5B6FD1F
+
+I=302
+KEY=22C629C84758D553AFE4876AA739A1F0E40610575C2F5A2F908AD606C598DFF3
+PT=28A22A069D8FF3DE359860B0A5B6FD1F
+CT=95DD88B4AFD0680E221C70422ADFFCD1
+
+I=303
+KEY=F86A3C799AAB6884220196BF07E1643D71DB98E3F3FF3221B296A644EF472322
+PT=95DD88B4AFD0680E221C70422ADFFCD1
+CT=323475C634FD6845BAA9F371F29DC363
+
+I=304
+KEY=83412E9600B279F76C93F171C469AD1943EFED25C7025A64083F55351DDAE041
+PT=323475C634FD6845BAA9F371F29DC363
+CT=61276AD535F9E73FCFB53DBF2D5D1F62
+
+I=305
+KEY=01AD15137C4A572322660716B6B4EDCD22C887F0F2FBBD5BC78A688A3087FF23
+PT=61276AD535F9E73FCFB53DBF2D5D1F62
+CT=105ECB04A5CA32FC93987569A7CB46D7
+
+I=306
+KEY=1CC639BA56CA0DF23E64BB3395C08BB332964CF457318FA754121DE3974CB9F4
+PT=105ECB04A5CA32FC93987569A7CB46D7
+CT=831DBB3F4BBD4343B94D54AA2B3E0620
+
+I=307
+KEY=25ABCF5B8DB1A7CCB1FA49936E0AB3C8B18BF7CB1C8CCCE4ED5F4949BC72BFD4
+PT=831DBB3F4BBD4343B94D54AA2B3E0620
+CT=40B9D9C6201E639DC9A04E500BCD7F61
+
+I=308
+KEY=75B34E0F371C4527732F22CF35AD923BF1322E0D3C92AF7924FF0719B7BFC0B5
+PT=40B9D9C6201E639DC9A04E500BCD7F61
+CT=A159BB0C751148C14D561E0407A9F6DB
+
+I=309
+KEY=1EB6E3491B431B7EFFCCC965C9041274506B95014983E7B869A9191DB016366E
+PT=A159BB0C751148C14D561E0407A9F6DB
+CT=2012E67815334AC48E5309DD129E0476
+
+I=310
+KEY=F0BDAFB216613A6FB3819D08B17EFDC1707973795CB0AD7CE7FA10C0A2883218
+PT=2012E67815334AC48E5309DD129E0476
+CT=53E415BC0C9013F83B77298395FC9FEF
+
+I=311
+KEY=9C5A3B9C862E07159AB06D5B7FB585C5239D66C55020BE84DC8D39433774ADF7
+PT=53E415BC0C9013F83B77298395FC9FEF
+CT=2B1EEAA13373494A2A56C15FD5ECA103
+
+I=312
+KEY=9764AC349B8222394160F4896BA6761808838C646353F7CEF6DBF81CE2980CF4
+PT=2B1EEAA13373494A2A56C15FD5ECA103
+CT=2A00E873782853DC842427A03C30A81A
+
+I=313
+KEY=42A1614569C4DE66D6336BC082B3B9DD228364171B7BA41272FFDFBCDEA8A4EE
+PT=2A00E873782853DC842427A03C30A81A
+CT=5FEB74E489C4C8121A15C2BCF51046A5
+
+I=314
+KEY=CED80BE0859A5863CFE41F0F2CE9F65B7D6810F392BF6C0068EA1D002BB8E24B
+PT=5FEB74E489C4C8121A15C2BCF51046A5
+CT=948214D5DB68997C37A48927AA97B89A
+
+I=315
+KEY=178DAF533EBB695D5E57401E5345C3E8E9EA042649D7F57C5F4E9427812F5AD1
+PT=948214D5DB68997C37A48927AA97B89A
+CT=AB8F3BB9917E4D1C8F1F2EDDB7070530
+
+I=316
+KEY=66F4B8B5A0BD877514FDB4CD2DD04D8C42653F9FD8A9B860D051BAFA36285FE1
+PT=AB8F3BB9917E4D1C8F1F2EDDB7070530
+CT=CB5FB11C6DB1AB6BC189F0F3FB47A2A5
+
+I=317
+KEY=9753278CFCEE8B059ECF573A2E0D65D6893A8E83B518130B11D84A09CD6FFD44
+PT=CB5FB11C6DB1AB6BC189F0F3FB47A2A5
+CT=F0CE65E6C5C263182E6C253F26460A1B
+
+I=318
+KEY=121A860A5B53C56E536DE56566F31E2079F4EB6570DA70133FB46F36EB29F75F
+PT=F0CE65E6C5C263182E6C253F26460A1B
+CT=9AA17B0F532814CA74FF0A046F377C48
+
+I=319
+KEY=88F5E58E9522495BF7B68430946F7C0FE355906A23F264D94B4B6532841E8B17
+PT=9AA17B0F532814CA74FF0A046F377C48
+CT=52CAAEF16E55858487AEDBDBA822002D
+
+I=320
+KEY=D9A3D3547F215D44D80C6A5D3548D4D2B19F3E9B4DA7E15DCCE5BEE92C3C8B3A
+PT=52CAAEF16E55858487AEDBDBA822002D
+CT=2599545FD15C7F59A6F02CDCB95E6589
+
+I=321
+KEY=6ACE86543B0F981C2D0FCB1408A42C3294066AC49CFB9E046A1592359562EEB3
+PT=2599545FD15C7F59A6F02CDCB95E6589
+CT=DC7A68313CE3E1963D31E5149CDBE22A
+
+I=322
+KEY=E9D6D08194DAFBB7B491124515118FA6487C02F5A0187F925724772109B90C99
+PT=DC7A68313CE3E1963D31E5149CDBE22A
+CT=333B588A7354CB3229E43780AFE4738D
+
+I=323
+KEY=762FC93CEED1EE9C6EF702A4E3BBABD67B475A7FD34CB4A07EC040A1A65D7F14
+PT=333B588A7354CB3229E43780AFE4738D
+CT=41727DC0D18725AFD2EF8FF51EAE1C2C
+
+I=324
+KEY=FF4EC1DF818E820424CFE5D09EE2E5423A3527BF02CB910FAC2FCF54B8F36338
+PT=41727DC0D18725AFD2EF8FF51EAE1C2C
+CT=A7236B16D9937C84F37BF9D79D0251F9
+
+I=325
+KEY=59BDAB706DEA2EC52AE05A2E4382A4169D164CA9DB58ED8B5F54368325F132C1
+PT=A7236B16D9937C84F37BF9D79D0251F9
+CT=B81D30EFDB86688F1DCA616EC771B9FD
+
+I=326
+KEY=4C008516CD614B6588A526FFE33C055B250B7C4600DE8504429E57EDE2808B3C
+PT=B81D30EFDB86688F1DCA616EC771B9FD
+CT=A5AD142C8F078ABF419B7CF5C86C9F83
+
+I=327
+KEY=DB65698F99E4A27019ABE194A89E9BC680A6686A8FD90FBB03052B182AEC14BF
+PT=A5AD142C8F078ABF419B7CF5C86C9F83
+CT=861B59E3B61A5D02F0D70DFF40EF7FF2
+
+I=328
+KEY=0790C16C53A7826B4B309DDF99B5239006BD318939C352B9F3D226E76A036B4D
+PT=861B59E3B61A5D02F0D70DFF40EF7FF2
+CT=B0F4C2C4D0D282BE3128AD78D34B1FA6
+
+I=329
+KEY=AFE168F089E676A806DD191003777E6DB649F34DE911D007C2FA8B9FB94874EB
+PT=B0F4C2C4D0D282BE3128AD78D34B1FA6
+CT=9DFCF5727851ADE8C37A9AA3AA77B20D
+
+I=330
+KEY=F261CDF199D9EF436C1A08EB9755A2112BB5063F91407DEF0180113C133FC6E6
+PT=9DFCF5727851ADE8C37A9AA3AA77B20D
+CT=9268DBA972B72C9DEF15CF9B8041F23B
+
+I=331
+KEY=E0D6DCF3BA840720688456A43E849C5CB9DDDD96E3F75172EE95DEA7937E34DD
+PT=9268DBA972B72C9DEF15CF9B8041F23B
+CT=D45A8B321CB6D8F28167C857BC2900BF
+
+I=332
+KEY=B77CF3A880C2E9E66D0C98A4D88555F46D8756A4FF4189806FF216F02F573462
+PT=D45A8B321CB6D8F28167C857BC2900BF
+CT=0124FE2D8BCB81E1286A18D2BABEA919
+
+I=333
+KEY=7729E55EFA6B249E0207E06AAF6F09206CA3A889748A086147980E2295E99D7B
+PT=0124FE2D8BCB81E1286A18D2BABEA919
+CT=A1BB0D975A50BE8BD8C2973D4BA7BF42
+
+I=334
+KEY=102384784C54539084BC7181AA95F184CD18A51E2EDAB6EA9F5A991FDE4E2239
+PT=A1BB0D975A50BE8BD8C2973D4BA7BF42
+CT=15302D5DBFD8E407EADDE9896B42CB13
+
+I=335
+KEY=9FF48EF1068BFC07DA38F7790D7418D2D8288843910252ED75877096B50CE92A
+PT=15302D5DBFD8E407EADDE9896B42CB13
+CT=90D93B8F802CFAD3F6E682DD704B5F43
+
+I=336
+KEY=84477EB9007ECDF8D1C4A6A976C76AB848F1B3CC112EA83E8361F24BC547B669
+PT=90D93B8F802CFAD3F6E682DD704B5F43
+CT=2DD7E0B91C5DDF0FD118F4CDD836A212
+
+I=337
+KEY=F1CE87DE930567CE29DF313D8778358D652653750D737731527906861D71147B
+PT=2DD7E0B91C5DDF0FD118F4CDD836A212
+CT=AC9D307EFF44703D6FDA621FFF8D077C
+
+I=338
+KEY=22D31C8F64CFB23620A70E7CD4A486D3C9BB630BF237070C3DA36499E2FC1307
+PT=AC9D307EFF44703D6FDA621FFF8D077C
+CT=CC6772DE3B27CB1DB3E5A804843EB6FF
+
+I=339
+KEY=FC9057D2D2D28BFAC4D5E3654717188205DC11D5C910CC118E46CC9D66C2A5F8
+PT=CC6772DE3B27CB1DB3E5A804843EB6FF
+CT=BDB021550FE0744090EAFEEBCF422061
+
+I=340
+KEY=1EA032190E7E4CC45D2E1E138429658AB86C3080C6F0B8511EAC3276A9808599
+PT=BDB021550FE0744090EAFEEBCF422061
+CT=C6E21F9A1305C3969F2D70C11D58A1A7
+
+I=341
+KEY=B633EDA212B952785755700FBDC91CA57E8E2F1AD5F57BC7818142B7B4D8243E
+PT=C6E21F9A1305C3969F2D70C11D58A1A7
+CT=01BC936B7063CA9D28DB1FFCCB9C2048
+
+I=342
+KEY=94A06984520AB40D74568F0D5286AEE37F32BC71A596B15AA95A5D4B7F440476
+PT=01BC936B7063CA9D28DB1FFCCB9C2048
+CT=88279D100DFA68CEBD9949F19C3333F4
+
+I=343
+KEY=96A3BD621155F71A9EFB8E35F95238ACF7152161A86CD99414C314BAE3773782
+PT=88279D100DFA68CEBD9949F19C3333F4
+CT=41574A686596D4741BF5DE52B5183260
+
+I=344
+KEY=185312E4301E5AADC373CEB3EBA66FB7B6426B09CDFA0DE00F36CAE8566F05E2
+PT=41574A686596D4741BF5DE52B5183260
+CT=BD9F5087C32A66A4797C7EE87355FF4A
+
+I=345
+KEY=BC5D60D256DCA48E88E52F05C349431A0BDD3B8E0ED06B44764AB400253AFAA8
+PT=BD9F5087C32A66A4797C7EE87355FF4A
+CT=A88BC3FAF87D6C1D3F98A2884EF1D4DA
+
+I=346
+KEY=1485A9209167A6FA2ECD2CE6AA03DBA5A356F874F6AD075949D216886BCB2E72
+PT=A88BC3FAF87D6C1D3F98A2884EF1D4DA
+CT=E514E6E34A050EB917F2382EDF92353A
+
+I=347
+KEY=2B62B0E29763FF09F53A2006B990E97746421E97BCA809E05E202EA6B4591B48
+PT=E514E6E34A050EB917F2382EDF92353A
+CT=142EEBE72E0F56ABE5D67FCC28F957F6
+
+I=348
+KEY=FC13067E362B7C9C39AA73B85F32011C526CF57092A75F4BBBF6516A9CA04CBE
+PT=142EEBE72E0F56ABE5D67FCC28F957F6
+CT=24FDB7A03FE8A9288BFAA5AC2527D015
+
+I=349
+KEY=8AC3B473244989EA74025FE98269BC17769142D0AD4FF663300CF4C6B9879CAB
+PT=24FDB7A03FE8A9288BFAA5AC2527D015
+CT=649095ABA5F4006B7B89D20F10A37AE9
+
+I=350
+KEY=FD0F4205DBFF0160203898EF02E9088E1201D77B08BBF6084B8526C9A924E642
+PT=649095ABA5F4006B7B89D20F10A37AE9
+CT=F5428E8BDDDC31FC8EF67BC7DB3201D3
+
+I=351
+KEY=701AF95194FB0918BC2CA79AFD507336E74359F0D567C7F4C5735D0E7216E791
+PT=F5428E8BDDDC31FC8EF67BC7DB3201D3
+CT=A56B2014A4929373DC1F6FD5C0AC138C
+
+I=352
+KEY=633D0E72722E6443D4E219086D221939422879E471F55487196C32DBB2BAF41D
+PT=A56B2014A4929373DC1F6FD5C0AC138C
+CT=F35F9CD43144B358843A48B4D1C41882
+
+I=353
+KEY=DCA79BA0184EC0A22A875E5057CA967AB177E53040B1E7DF9D567A6F637EEC9F
+PT=F35F9CD43144B358843A48B4D1C41882
+CT=A572C1F98330A1C1FA91DFD5A5B76AB9
+
+I=354
+KEY=A3D0FE4C3C1A1CE19CF66CF80135553D140524C9C381461E67C7A5BAC6C98626
+PT=A572C1F98330A1C1FA91DFD5A5B76AB9
+CT=23C56E065427F0409504053DD8A994CD
+
+I=355
+KEY=175C8D4085802768D20875CDBE6EFE2437C04ACF97A6B65EF2C3A0871E6012EB
+PT=23C56E065427F0409504053DD8A994CD
+CT=7E666724C1CAC0A582325381E9C98D73
+
+I=356
+KEY=800EE65CA3DE8643371DA10FB0605AB649A62DEB566C76FB70F1F306F7A99F98
+PT=7E666724C1CAC0A582325381E9C98D73
+CT=B6C18D730A074196884CADF151CAC890
+
+I=357
+KEY=F526E578E8978822944644B146154425FF67A0985C6B376DF8BD5EF7A6635708
+PT=B6C18D730A074196884CADF151CAC890
+CT=0068BB370419CD39748559C2DE206817
+
+I=358
+KEY=7D144850BE03306F41A642442890EA20FF0F1BAF5872FA548C38073578433F1F
+PT=0068BB370419CD39748559C2DE206817
+CT=56852D240F01729C4EAD0B1FFC3EDA1F
+
+I=359
+KEY=33B2189E3774B1A066BE522C07550F88A98A368B577388C8C2950C2A847DE500
+PT=56852D240F01729C4EAD0B1FFC3EDA1F
+CT=458633A84E1F5737E9668A37388CF3C2
+
+I=360
+KEY=CF53C76250347B0CC5CAC660D52199B1EC0C0523196CDFFF2BF3861DBCF116C2
+PT=458633A84E1F5737E9668A37388CF3C2
+CT=F96E181E03350F27106C8D24403A49DD
+
+I=361
+KEY=618676C1702531077565060B5DA0570B15621D3D1A59D0D83B9F0B39FCCB5F1F
+PT=F96E181E03350F27106C8D24403A49DD
+CT=B515584E252F703A4EB55E81EDA58E30
+
+I=362
+KEY=D2C8CF9645CD741F67263845150FE649A07745733F76A0E2752A55B8116ED12F
+PT=B515584E252F703A4EB55E81EDA58E30
+CT=54E7D10C236785AFE0A93B3971D6F237
+
+I=363
+KEY=D0847F41C7940023491C2F83D02F8271F490947F1C11254D95836E8160B82318
+PT=54E7D10C236785AFE0A93B3971D6F237
+CT=937DFDE10E96030A0A8823EA3EF31B98
+
+I=364
+KEY=17502FC3077EFD420D2268CE0FF26F4667ED699E128726479F0B4D6B5E4B3880
+PT=937DFDE10E96030A0A8823EA3EF31B98
+CT=93FDF0392A3391C74DBE4229792C9630
+
+I=365
+KEY=4D6AA08A6C7EB7CA9CBE7AF4500C229EF41099A738B4B780D2B50F422767AEB0
+PT=93FDF0392A3391C74DBE4229792C9630
+CT=B9F80E1476658E6CE7FADBA215298958
+
+I=366
+KEY=D8820A50934290C146AFE477D9D4A0224DE897B34ED139EC354FD4E0324E27E8
+PT=B9F80E1476658E6CE7FADBA215298958
+CT=87ACDCD1F1332B9961CC5E18F9009A39
+
+I=367
+KEY=50E8959452DD52247A6F21A0C7BEDEB8CA444B62BFE2127554838AF8CB4EBDD1
+PT=87ACDCD1F1332B9961CC5E18F9009A39
+CT=3DD6249971FEC0FB4432236078D98D53
+
+I=368
+KEY=7A1973C5B90748596A54C709D1598DA5F7926FFBCE1CD28E10B1A998B3973082
+PT=3DD6249971FEC0FB4432236078D98D53
+CT=D540F8BDE3442D17E88B524D00618309
+
+I=369
+KEY=F9C08719A452CA931A62C5BD8F1D669D22D297462D58FF99F83AFBD5B3F6B38B
+PT=D540F8BDE3442D17E88B524D00618309
+CT=7BB18B2DA9ED188BCE3B18C02C9B3F3B
+
+I=370
+KEY=5EBA35F7E58381DBE29EC4A1D9B5B9AD59631C6B84B5E7123601E3159F6D8CB0
+PT=7BB18B2DA9ED188BCE3B18C02C9B3F3B
+CT=9A7380BAA169495B0FC29BB002D70E48
+
+I=371
+KEY=E442442FE32FA6BDA63AF0A6AC5D5AB2C3109CD125DCAE4939C378A59DBA82F8
+PT=9A7380BAA169495B0FC29BB002D70E48
+CT=88F3FE65298F7498A788E4196F13FC80
+
+I=372
+KEY=39079A8713E148703212A6F7FFD1B04D4BE362B40C53DAD19E4B9CBCF2A97E78
+PT=88F3FE65298F7498A788E4196F13FC80
+CT=A5E6361FBA6418CD9B2F50992B50A557
+
+I=373
+KEY=A99A33F38B36E3EE4DEE59F8A4282A84EE0554ABB637C21C0564CC25D9F9DB2F
+PT=A5E6361FBA6418CD9B2F50992B50A557
+CT=B1430F431ACC1C498FABF2D33B63CC67
+
+I=374
+KEY=BC09FAC540F44949F3B8EDFE2444CA725F465BE8ACFBDE558ACF3EF6E29A1748
+PT=B1430F431ACC1C498FABF2D33B63CC67
+CT=A90D76642D8D7899DD4A85EB92C89382
+
+I=375
+KEY=D26C1D07B51073C609030DC782FFAE93F64B2D8C8176A6CC5785BB1D705284CA
+PT=A90D76642D8D7899DD4A85EB92C89382
+CT=57522F39211100EF248D4A34E35CE4CE
+
+I=376
+KEY=2D7ADCD18F615F814B8D8B07CE48B4A1A11902B5A067A6237308F129930E6004
+PT=57522F39211100EF248D4A34E35CE4CE
+CT=87AED1E0C9F067C5F3F6D3D3BBCDE872
+
+I=377
+KEY=CA206C3442FAEFF3CB1292C675F52C2426B7D3556997C1E680FE22FA28C38876
+PT=87AED1E0C9F067C5F3F6D3D3BBCDE872
+CT=05798F53DFAE4A78D7BEEC24BE775B55
+
+I=378
+KEY=6ECC5BC346B18446D77FFBC44CCB0B1823CE5C06B6398B9E5740CEDE96B4D323
+PT=05798F53DFAE4A78D7BEEC24BE775B55
+CT=7677CE104395FFA15B51F81DAFBCAB1A
+
+I=379
+KEY=2E52C8E239CF1E959AB831307034FEF755B99216F5AC743F0C1136C339087839
+PT=7677CE104395FFA15B51F81DAFBCAB1A
+CT=760DE53561246F944B3E6279B39373F1
+
+I=380
+KEY=79B65B7D435E2134A1AB9A1CC1F08A8423B4772394881BAB472F54BA8A9B0BC8
+PT=760DE53561246F944B3E6279B39373F1
+CT=5B61CC978A9C808767C272432765EC0B
+
+I=381
+KEY=9EF57B89E7B8127348A9EF05E93DCC8D78D5BBB41E149B2C20ED26F9ADFEE7C3
+PT=5B61CC978A9C808767C272432765EC0B
+CT=902CDF3BD5E869E9CCFF8F2A454E1D42
+
+I=382
+KEY=15BB7B6BC685E4865BFA134C59CFC9C5E8F9648FCBFCF2C5EC12A9D3E8B0FA81
+PT=902CDF3BD5E869E9CCFF8F2A454E1D42
+CT=38264937B9372C316478BDF7AE578900
+
+I=383
+KEY=735D93C1DDD54986ACC6C2B0DFCC5E8AD0DF2DB872CBDEF4886A142446E77381
+PT=38264937B9372C316478BDF7AE578900
+CT=3BFE31D3E909E6EC3112F88DB8FFCA45
+
+I=384
+KEY=675B0E7FC5BCC3AF319B1D55C1F62CCAEB211C6B9BC23818B978ECA9FE18B9C4
+PT=3BFE31D3E909E6EC3112F88DB8FFCA45
+CT=2BFD5F6532BC1D2A8DA34481F9228B84
+
+I=385
+KEY=0AB242F9783E75D04E98733E63458F53C0DC430EA97E253234DBA828073A3240
+PT=2BFD5F6532BC1D2A8DA34481F9228B84
+CT=161481003108BAEFCC02BFD335C6A89F
+
+I=386
+KEY=58457CB82A24222839CF20D837F168A8D6C8C20E98769FDDF8D917FB32FC9ADF
+PT=161481003108BAEFCC02BFD335C6A89F
+CT=8A50E98A1165C1B6137231E519EC137B
+
+I=387
+KEY=C2C52CEA5654AAC9BD60FA04068094EF5C982B8489135E6BEBAB261E2B1089A4
+PT=8A50E98A1165C1B6137231E519EC137B
+CT=24ACAA0F045F5A6765D3B468550585B5
+
+I=388
+KEY=816757A434D81AA348E0B2F4FC44F4387834818B8D4C040C8E7892767E150C11
+PT=24ACAA0F045F5A6765D3B468550585B5
+CT=9993F9CBDAD9CA98C74CCBDB3E079F50
+
+I=389
+KEY=647A9F1E43B08FD15EFC17342EB8970AE1A778405795CE94493459AD40129341
+PT=9993F9CBDAD9CA98C74CCBDB3E079F50
+CT=F676785AEF58297C28035E8E065829FF
+
+I=390
+KEY=4BB8B5020862EA9228B663DEDB39336717D1001AB8CDE7E861370723464ABABE
+PT=F676785AEF58297C28035E8E065829FF
+CT=ED16C74BD4252F7B72AA37D11E198508
+
+I=391
+KEY=5392AAED87CE40891A69F4690A8743FBFAC7C7516CE8C893139D30F258533FB6
+PT=ED16C74BD4252F7B72AA37D11E198508
+CT=3BE7B6A9E197598146E98B7A501A2226
+
+I=392
+KEY=9D8BABE9C12E6BA3A18EB23A92205456C12071F88D7F91125574BB8808491D90
+PT=3BE7B6A9E197598146E98B7A501A2226
+CT=CC1163A3D9AF3307ED740591AB66BD81
+
+I=393
+KEY=231B451E506AC98FF993A3C7AD9C37F70D31125B54D0A215B800BE19A32FA011
+PT=CC1163A3D9AF3307ED740591AB66BD81
+CT=43FB8B2B44C740956111DA816616771D
+
+I=394
+KEY=1699C517EE1713D02C6EA0957E4A00CE4ECA99701017E280D9116498C539D70C
+PT=43FB8B2B44C740956111DA816616771D
+CT=A511AEA01DB8E7E16E7C53931625BEC3
+
+I=395
+KEY=2624CE7970CC5DAFAC73C881FDD5F6EBEBDB37D00DAF0561B76D370BD31C69CF
+PT=A511AEA01DB8E7E16E7C53931625BEC3
+CT=82EF6D2A1FF1DBCDF39DC04BE523229F
+
+I=396
+KEY=60C9931E19ED0D095F8DF75AEA56689769345AFA125EDEAC44F0F740363F4B50
+PT=82EF6D2A1FF1DBCDF39DC04BE523229F
+CT=A595C8AAAAAD80DD4F40693FF2D89A19
+
+I=397
+KEY=D461E3605B0AD0E87F5A078ECFE25934CCA19250B8F35E710BB09E7FC4E7D149
+PT=A595C8AAAAAD80DD4F40693FF2D89A19
+CT=57B18DFEAD129795C3BB8D6C06764729
+
+I=398
+KEY=0BE3FC6C21764F1C15782D52D92919A09B101FAE15E1C9E4C80B1313C2919660
+PT=57B18DFEAD129795C3BB8D6C06764729
+CT=6F8606BBA6CC03A5D0A64FE21E277B60
+
+I=399
+KEY=982D617A0F737342E99123A5A573D266F4961915B32DCA4118AD5CF1DCB6ED00
+PT=6F8606BBA6CC03A5D0A64FE21E277B60
+CT=1F6763DF807A7E70960D4CD3118E601A
+
+===========
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/test/ecb_iv.readme b/mechglue/src/lib/crypto/aes/test/ecb_iv.readme
new file mode 100644
index 000000000..c37215768
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/ecb_iv.readme
@@ -0,0 +1,19 @@
+Description of the Intermediate Value Known Answer Test
+--------------------------------------------------------
+
+The test encrypts one plaintext with a variable number of rounds.
+In ECB encryption mode, the output PTi is the output after the 
+initial key addition and i rounds (a round ends with a key
+addition). 
+
+As explained in the documentation, in ECB decryption mode 
+there are several definitions of a `round' possible. In order
+to make visual inspection more intuitive, we output the
+intermediate values that correspond with the output of the
+encryption mode. 
+These values might actually not occur in a practical decryption,
+especially in an optimised implementation, where various operations
+of different rounds are interchanged.
+
+This explains also why the Java and the C code output different
+files for this test.
diff --git a/mechglue/src/lib/crypto/aes/test/ecb_iv.txt b/mechglue/src/lib/crypto/aes/test/ecb_iv.txt
new file mode 100644
index 000000000..3f6608e4e
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/ecb_iv.txt
@@ -0,0 +1,123 @@
+
+=========================
+
+FILENAME:  "ecb_iv.txt"
+
+Electronic Codebook (ECB) Mode
+Intermediate Value Known Answer Tests
+
+Algorithm Name: Rijndael
+Principal Submitter: Joan Daemen
+
+==========
+
+KEYSIZE=128
+KEY=000102030405060708090A0B0C0D0E0F
+
+Intermediate Ciphertext Values (Encryption)
+
+PT=000102030405060708090A0B0C0D0E0F
+CT1=B5C9179EB1CC1199B9C51B92B5C8159D
+CT2=2B65F6374C427C5B2FE3A9256896755B
+CT3=D1015FCBB4EF65679688462076B9D6AD
+CT4=8E17064A2A35A183729FE59FF3A591F1
+CT5=D7557DD55999DB3259E2183D558DCDD2
+CT6=73A96A5D7799A5F3111D2B63684B1F7F
+CT7=1B6B853069EEFC749AFEFD7B57A04CD1
+CT8=107EEADFB6F77933B5457A6F08F046B2
+CT9=8EC166481A677AA96A14FF6ECE88C010
+CT=0A940BB5416EF045F1C39458C653EA5A
+
+Intermediate Ciphertext Values (Decryption)
+
+CT=0A940BB5416EF045F1C39458C653EA5A
+PT1=8EC166481A677AA96A14FF6ECE88C010
+PT2=107EEADFB6F77933B5457A6F08F046B2
+PT3=1B6B853069EEFC749AFEFD7B57A04CD1
+PT4=73A96A5D7799A5F3111D2B63684B1F7F
+PT5=D7557DD55999DB3259E2183D558DCDD2
+PT6=8E17064A2A35A183729FE59FF3A591F1
+PT7=D1015FCBB4EF65679688462076B9D6AD
+PT8=2B65F6374C427C5B2FE3A9256896755B
+PT9=B5C9179EB1CC1199B9C51B92B5C8159D
+PT=000102030405060708090A0B0C0D0E0F
+
+==========
+
+KEYSIZE=192
+KEY=000102030405060708090A0B0C0D0E0F1011121314151617
+
+Intermediate Ciphertext Values (Encryption)
+
+PT=000102030405060708090A0B0C0D0E0F
+CT1=73727170777675743B25919A3F20979D
+CT2=C673B27A311EC2EB64AD47FF53B233D7
+CT3=0B5CC6BA34C807E6496D79B46826A1E8
+CT4=005B53A5B660E280307883487E4D1A4D
+CT5=88A105F0DDD45F3674DBC3DE1A211B03
+CT6=EB5CD8B5FD8A3F33F03A70FB5C620C06
+CT7=909913B09BD2CC5A70B6C647931F0A1F
+CT8=6EB6CA10E395AFD646B02C5E9E745A9F
+CT9=2CFD2FC41AF82B8DFB80E9BD1C989ECE
+CT10=31C5D5E27EAF073E5C21ADAAEAA969D4
+CT11=1DB94956A7268B0DE963D27E55868580
+CT=0060BFFE46834BB8DA5CF9A61FF220AE
+
+Intermediate Ciphertext Values (Decryption)
+
+CT=0060BFFE46834BB8DA5CF9A61FF220AE
+PT1=1DB94956A7268B0DE963D27E55868580
+PT2=31C5D5E27EAF073E5C21ADAAEAA969D4
+PT3=2CFD2FC41AF82B8DFB80E9BD1C989ECE
+PT4=6EB6CA10E395AFD646B02C5E9E745A9F
+PT5=909913B09BD2CC5A70B6C647931F0A1F
+PT6=EB5CD8B5FD8A3F33F03A70FB5C620C06
+PT7=88A105F0DDD45F3674DBC3DE1A211B03
+PT8=005B53A5B660E280307883487E4D1A4D
+PT9=0B5CC6BA34C807E6496D79B46826A1E8
+PT10=C673B27A311EC2EB64AD47FF53B233D7
+PT11=73727170777675743B25919A3F20979D
+PT=000102030405060708090A0B0C0D0E0F
+
+==========
+
+KEYSIZE=256
+KEY=000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
+
+Intermediate Ciphertext Values (Encryption)
+
+PT=000102030405060708090A0B0C0D0E0F
+CT1=73727170777675747B7A79787F7E7D7C
+CT2=4E5D32BB8B67FD1BD4CFEC9FFB20AC4F
+CT3=96A212E486341549C4AAF7C843F0277A
+CT4=0F45F284CDD0CB16E3EA81ECC891A4E1
+CT5=E59BFC458A89063E0137BBE6DB63A058
+CT6=1D958D960EA3143383C17D5CD87BA327
+CT7=43843EF40D9219481935B77A586DB5DE
+CT8=5AA5ABADBC40230CBA6124E9FAEEEFB5
+CT9=DAD61937BDFD582927F14C990C5FC761
+CT10=E8A48C5DEE5C0792AB6DFFF5B038529D
+CT11=4B71E5A8BFB4E9A5312A18119E68E829
+CT12=DCBA75CEE6589DDC0D289A172E8415B5
+CT13=8A0E856B2074C1093104131D0628BFE8
+CT=5A6E045708FB7196F02E553D02C3A692
+
+Intermediate Ciphertext Values (Decryption)
+
+CT=5A6E045708FB7196F02E553D02C3A692
+PT1=8A0E856B2074C1093104131D0628BFE8
+PT2=DCBA75CEE6589DDC0D289A172E8415B5
+PT3=4B71E5A8BFB4E9A5312A18119E68E829
+PT4=E8A48C5DEE5C0792AB6DFFF5B038529D
+PT5=DAD61937BDFD582927F14C990C5FC761
+PT6=5AA5ABADBC40230CBA6124E9FAEEEFB5
+PT7=43843EF40D9219481935B77A586DB5DE
+PT8=1D958D960EA3143383C17D5CD87BA327
+PT9=E59BFC458A89063E0137BBE6DB63A058
+PT10=0F45F284CDD0CB16E3EA81ECC891A4E1
+PT11=96A212E486341549C4AAF7C843F0277A
+PT12=4E5D32BB8B67FD1BD4CFEC9FFB20AC4F
+PT13=73727170777675747B7A79787F7E7D7C
+PT=000102030405060708090A0B0C0D0E0F
+
+==========
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/test/ecb_tbl.txt b/mechglue/src/lib/crypto/aes/test/ecb_tbl.txt
new file mode 100644
index 000000000..f1eef5300
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/ecb_tbl.txt
@@ -0,0 +1,1955 @@
+/* Description of what tables are tested:
+   The provided implementations each use a different set of tables
+    - Java implementation: uses no tables
+    - reference C implementation: uses Logtable, Alogtable, S, Si, rcon
+    - fast C implementation: uses Logtable, Alogtable,  rcon
+        and additionally, T1, T2, T3, T4, T5, T6, T7, T8
+        and (for the inverse key schedule only) U1, U2, U3, U4.
+   All these tables are tested.
+
+=========================
+
+FILENAME:  "ecb_tbl.txt"
+
+Electronic Codebook (ECB) Mode
+Tables Known Answer Tests
+
+Algorithm Name: Rijndael
+Principal Submitter: Joan Daemen
+
+==========
+
+KEYSIZE=128
+
+
+I=1
+KEY=00010203050607080A0B0C0D0F101112
+PT=506812A45F08C889B97F5980038B8359
+CT=D8F532538289EF7D06B506A4FD5BE9C9
+
+I=2
+KEY=14151617191A1B1C1E1F202123242526
+PT=5C6D71CA30DE8B8B00549984D2EC7D4B
+CT=59AB30F4D4EE6E4FF9907EF65B1FB68C
+
+I=3
+KEY=28292A2B2D2E2F30323334353738393A
+PT=53F3F4C64F8616E4E7C56199F48F21F6
+CT=BF1ED2FCB2AF3FD41443B56D85025CB1
+
+I=4
+KEY=3C3D3E3F41424344464748494B4C4D4E
+PT=A1EB65A3487165FB0F1C27FF9959F703
+CT=7316632D5C32233EDCB0780560EAE8B2
+
+I=5
+KEY=50515253555657585A5B5C5D5F606162
+PT=3553ECF0B1739558B08E350A98A39BFA
+CT=408C073E3E2538072B72625E68B8364B
+
+I=6
+KEY=64656667696A6B6C6E6F707173747576
+PT=67429969490B9711AE2B01DC497AFDE8
+CT=E1F94DFA776597BEACA262F2F6366FEA
+
+I=7
+KEY=78797A7B7D7E7F80828384858788898A
+PT=93385C1F2AEC8BED192F5A8E161DD508
+CT=F29E986C6A1C27D7B29FFD7EE92B75F1
+
+I=8
+KEY=8C8D8E8F91929394969798999B9C9D9E
+PT=B5BF946BE19BEB8DB3983B5F4C6E8DDB
+CT=131C886A57F8C2E713ABA6955E2B55B5
+
+I=9
+KEY=A0A1A2A3A5A6A7A8AAABACADAFB0B1B2
+PT=41321EE10E21BD907227C4450FF42324
+CT=D2AB7662DF9B8C740210E5EEB61C199D
+
+I=10
+KEY=B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6
+PT=00A82F59C91C8486D12C0A80124F6089
+CT=14C10554B2859C484CAB5869BBE7C470
+
+I=11
+KEY=C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA
+PT=7CE0FD076754691B4BBD9FAF8A1372FE
+CT=DB4D498F0A49CF55445D502C1F9AB3B5
+
+I=12
+KEY=DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE
+PT=23605A8243D07764541BC5AD355B3129
+CT=6D96FEF7D66590A77A77BB2056667F7F
+
+I=13
+KEY=F0F1F2F3F5F6F7F8FAFBFCFDFE010002
+PT=12A8CFA23EA764FD876232B4E842BC44
+CT=316FB68EDBA736C53E78477BF913725C
+
+I=14
+KEY=04050607090A0B0C0E0F101113141516
+PT=BCAF32415E8308B3723E5FDD853CCC80
+CT=6936F2B93AF8397FD3A771FC011C8C37
+
+I=15
+KEY=2C2D2E2F31323334363738393B3C3D3E
+PT=89AFAE685D801AD747ACE91FC49ADDE0
+CT=F3F92F7A9C59179C1FCC2C2BA0B082CD
+
+I=16
+KEY=40414243454647484A4B4C4D4F505152
+PT=F521D07B484357C4A69E76124A634216
+CT=6A95EA659EE3889158E7A9152FF04EBC
+
+I=17
+KEY=54555657595A5B5C5E5F606163646566
+PT=3E23B3BC065BCC152407E23896D77783
+CT=1959338344E945670678A5D432C90B93
+
+I=18
+KEY=68696A6B6D6E6F70727374757778797A
+PT=79F0FBA002BE1744670E7E99290D8F52
+CT=E49BDDD2369B83EE66E6C75A1161B394
+
+I=19
+KEY=7C7D7E7F81828384868788898B8C8D8E
+PT=DA23FE9D5BD63E1D72E3DAFBE21A6C2A
+CT=D3388F19057FF704B70784164A74867D
+
+I=20
+KEY=A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6
+PT=E3F5698BA90B6A022EFD7DB2C7E6C823
+CT=23AA03E2D5E4CD24F3217E596480D1E1
+
+I=21
+KEY=E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2
+PT=BDC2691D4F1B73D2700679C3BCBF9C6E
+CT=C84113D68B666AB2A50A8BDB222E91B9
+
+I=22
+KEY=08090A0B0D0E0F10121314151718191A
+PT=BA74E02093217EE1BA1B42BD5624349A
+CT=AC02403981CD4340B507963DB65CB7B6
+
+I=23
+KEY=6C6D6E6F71727374767778797B7C7D7E
+PT=B5C593B5851C57FBF8B3F57715E8F680
+CT=8D1299236223359474011F6BF5088414
+
+I=24
+KEY=80818283858687888A8B8C8D8F909192
+PT=3DA9BD9CEC072381788F9387C3BBF4EE
+CT=5A1D6AB8605505F7977E55B9A54D9B90
+
+I=25
+KEY=94959697999A9B9C9E9FA0A1A3A4A5A6
+PT=4197F3051121702AB65D316B3C637374
+CT=72E9C2D519CF555E4208805AABE3B258
+
+I=26
+KEY=A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA
+PT=9F46C62EC4F6EE3F6E8C62554BC48AB7
+CT=A8F3E81C4A23A39EF4D745DFFE026E80
+
+I=27
+KEY=BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE
+PT=0220673FE9E699A4EBC8E0DBEB6979C8
+CT=546F646449D31458F9EB4EF5483AEE6C
+
+I=28
+KEY=D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2
+PT=B2B99171337DED9BC8C2C23FF6F18867
+CT=4DBE4BC84AC797C0EE4EFB7F1A07401C
+
+I=29
+KEY=E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6
+PT=A7FACF4E301E984E5EFEEFD645B23505
+CT=25E10BFB411BBD4D625AC8795C8CA3B3
+
+I=30
+KEY=F8F9FAFBFDFEFE00020304050708090A
+PT=F7C762E4A9819160FD7ACFB6C4EEDCDD
+CT=315637405054EC803614E43DEF177579
+
+I=31
+KEY=0C0D0E0F11121314161718191B1C1D1E
+PT=9B64FC21EA08709F4915436FAA70F1BE
+CT=60C5BC8A1410247295C6386C59E572A8
+
+I=32
+KEY=20212223252627282A2B2C2D2F303132
+PT=52AF2C3DE07EE6777F55A4ABFC100B3F
+CT=01366FC8CA52DFE055D6A00A76471BA6
+
+I=33
+KEY=34353637393A3B3C3E3F404143444546
+PT=2FCA001224386C57AA3F968CBE2C816F
+CT=ECC46595516EC612449C3F581E7D42FF
+
+I=34
+KEY=48494A4B4D4E4F50525354555758595A
+PT=4149C73658A4A9C564342755EE2C132F
+CT=6B7FFE4C602A154B06EE9C7DAB5331C9
+
+I=35
+KEY=5C5D5E5F61626364666768696B6C6D6E
+PT=AF60005A00A1772F7C07A48A923C23D2
+CT=7DA234C14039A240DD02DD0FBF84EB67
+
+I=36
+KEY=70717273757677787A7B7C7D7F808182
+PT=6FCCBC28363759914B6F0280AFAF20C6
+CT=C7DC217D9E3604FFE7E91F080ECD5A3A
+
+I=37
+KEY=84858687898A8B8C8E8F909193949596
+PT=7D82A43DDF4FEFA2FC5947499884D386
+CT=37785901863F5C81260EA41E7580CDA5
+
+I=38
+KEY=98999A9B9D9E9FA0A2A3A4A5A7A8A9AA
+PT=5D5A990EAAB9093AFE4CE254DFA49EF9
+CT=A07B9338E92ED105E6AD720FCCCE9FE4
+
+I=39
+KEY=ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE
+PT=4CD1E2FD3F4434B553AAE453F0ED1A02
+CT=AE0FB9722418CC21A7DA816BBC61322C
+
+I=40
+KEY=C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2
+PT=5A2C9A9641D4299125FA1B9363104B5E
+CT=C826A193080FF91FFB21F71D3373C877
+
+I=41
+KEY=D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6
+PT=B517FE34C0FA217D341740BFD4FE8DD4
+CT=1181B11B0E494E8D8B0AA6B1D5AC2C48
+
+I=42
+KEY=E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FA
+PT=014BAF2278A69D331D5180103643E99A
+CT=6743C3D1519AB4F2CD9A78AB09A511BD
+
+I=43
+KEY=FCFDFEFF01020304060708090B0C0D0E
+PT=B529BD8164F20D0AA443D4932116841C
+CT=DC55C076D52BACDF2EEFD952946A439D
+
+I=44
+KEY=10111213151617181A1B1C1D1F202122
+PT=2E596DCBB2F33D4216A1176D5BD1E456
+CT=711B17B590FFC72B5C8E342B601E8003
+
+I=45
+KEY=24252627292A2B2C2E2F303133343536
+PT=7274A1EA2B7EE2424E9A0E4673689143
+CT=19983BB0950783A537E1339F4AA21C75
+
+I=46
+KEY=38393A3B3D3E3F40424344454748494A
+PT=AE20020BD4F13E9D90140BEE3B5D26AF
+CT=3BA7762E15554169C0F4FA39164C410C
+
+I=47
+KEY=4C4D4E4F51525354565758595B5C5D5E
+PT=BAAC065DA7AC26E855E79C8849D75A02
+CT=A0564C41245AFCA7AF8AA2E0E588EA89
+
+I=48
+KEY=60616263656667686A6B6C6D6F707172
+PT=7C917D8D1D45FAB9E2540E28832540CC
+CT=5E36A42A2E099F54AE85ECD92E2381ED
+
+I=49
+KEY=74757677797A7B7C7E7F808183848586
+PT=BDE6F89E16DAADB0E847A2A614566A91
+CT=770036F878CD0F6CA2268172F106F2FE
+
+I=50
+KEY=88898A8B8D8E8F90929394959798999A
+PT=C9DE163725F1F5BE44EBB1DB51D07FBC
+CT=7E4E03908B716116443CCF7C94E7C259
+
+I=51
+KEY=9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE
+PT=3AF57A58F0C07DFFA669572B521E2B92
+CT=482735A48C30613A242DD494C7F9185D
+
+I=52
+KEY=B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2
+PT=3D5EBAC306DDE4604F1B4FBBBFCDAE55
+CT=B4C0F6C9D4D7079ADDF9369FC081061D
+
+I=53
+KEY=C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6
+PT=C2DFA91BCEB76A1183C995020AC0B556
+CT=D5810FE0509AC53EDCD74F89962E6270
+
+I=54
+KEY=D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EA
+PT=C70F54305885E9A0746D01EC56C8596B
+CT=03F17A16B3F91848269ECDD38EBB2165
+
+I=55
+KEY=ECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE
+PT=C4F81B610E98012CE000182050C0C2B2
+CT=DA1248C3180348BAD4A93B4D9856C9DF
+
+I=56
+KEY=00010203050607080A0B0C0D0F101112
+PT=EAAB86B1D02A95D7404EFF67489F97D4
+CT=3D10D7B63F3452C06CDF6CCE18BE0C2C
+
+I=57
+KEY=14151617191A1B1C1E1F202123242526
+PT=7C55BDB40B88870B52BEC3738DE82886
+CT=4AB823E7477DFDDC0E6789018FCB6258
+
+I=58
+KEY=28292A2B2D2E2F30323334353738393A
+PT=BA6EAA88371FF0A3BD875E3F2A975CE0
+CT=E6478BA56A77E70CFDAA5C843ABDE30E
+
+I=59
+KEY=3C3D3E3F41424344464748494B4C4D4E
+PT=08059130C4C24BD30CF0575E4E0373DC
+CT=1673064895FBEAF7F09C5429FF75772D
+
+I=60
+KEY=50515253555657585A5B5C5D5F606162
+PT=9A8EAB004EF53093DFCF96F57E7EDA82
+CT=4488033AE9F2EFD0CA9383BFCA1A94E9
+
+I=61
+KEY=64656667696A6B6C6E6F707173747576
+PT=0745B589E2400C25F117B1D796C28129
+CT=978F3B8C8F9D6F46626CAC3C0BCB9217
+
+I=62
+KEY=78797A7B7D7E7F80828384858788898A
+PT=2F1777781216CEC3F044F134B1B92BBE
+CT=E08C8A7E582E15E5527F1D9E2EECB236
+
+I=63
+KEY=8C8D8E8F91929394969798999B9C9D9E
+PT=353A779FFC541B3A3805D90CE17580FC
+CT=CEC155B76AC5FFDA4CF4F9CA91E49A7A
+
+I=64
+KEY=A0A1A2A3A5A6A7A8AAABACADAFB0B1B2
+PT=1A1EAE4415CEFCF08C4AC1C8F68BEA8F
+CT=D5AC7165763225DD2A38CDC6862C29AD
+
+I=65
+KEY=B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6
+PT=E6E7E4E5B0B3B2B5D4D5AAAB16111013
+CT=03680FE19F7CE7275452020BE70E8204
+
+I=66
+KEY=C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA
+PT=F8F9FAFBFBF8F9E677767170EFE0E1E2
+CT=461DF740C9781C388E94BB861CEB54F6
+
+I=67
+KEY=DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE
+PT=63626160A1A2A3A445444B4A75727370
+CT=451BD60367F96483042742219786A074
+
+I=68
+KEY=F0F1F2F3F5F6F7F8FAFBFCFDFE010002
+PT=717073720605040B2D2C2B2A05FAFBF9
+CT=E4DFA42671A02E57EF173B85C0EA9F2B
+
+I=69
+KEY=04050607090A0B0C0E0F101113141516
+PT=78797A7BEAE9E8EF3736292891969794
+CT=ED11B89E76274282227D854700A78B9E
+
+I=70
+KEY=18191A1B1D1E1F20222324252728292A
+PT=838281803231300FDDDCDBDAA0AFAEAD
+CT=433946EAA51EA47AF33895F2B90B3B75
+
+I=71
+KEY=2C2D2E2F31323334363738393B3C3D3E
+PT=18191A1BBFBCBDBA75747B7A7F78797A
+CT=6BC6D616A5D7D0284A5910AB35022528
+
+I=72
+KEY=40414243454647484A4B4C4D4F505152
+PT=848586879B989996A3A2A5A4849B9A99
+CT=D2A920ECFE919D354B5F49EAE9719C98
+
+I=73
+KEY=54555657595A5B5C5E5F606163646566
+PT=0001020322212027CACBF4F551565754
+CT=3A061B17F6A92885EFBD0676985B373D
+
+I=74
+KEY=68696A6B6D6E6F70727374757778797A
+PT=CECFCCCDAFACADB2515057564A454447
+CT=FADEEC16E33EA2F4688499D157E20D8F
+
+I=75
+KEY=7C7D7E7F81828384868788898B8C8D8E
+PT=92939091CDCECFC813121D1C80878685
+CT=5CDEFEDE59601AA3C3CDA36FA6B1FA13
+
+I=76
+KEY=90919293959697989A9B9C9D9FA0A1A2
+PT=D2D3D0D16F6C6D6259585F5ED1EEEFEC
+CT=9574B00039844D92EBBA7EE8719265F8
+
+I=77
+KEY=A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6
+PT=ACADAEAF878485820F0E1110D5D2D3D0
+CT=9A9CF33758671787E5006928188643FA
+
+I=78
+KEY=B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CA
+PT=9091929364676619E6E7E0E1757A7B78
+CT=2CDDD634C846BA66BB46CBFEA4A674F9
+
+I=79
+KEY=CCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE
+PT=BABBB8B98A89888F74757A7B92959497
+CT=D28BAE029393C3E7E26E9FAFBBB4B98F
+
+I=80
+KEY=E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2
+PT=8D8C8F8E6E6D6C633B3A3D3CCAD5D4D7
+CT=EC27529B1BEE0A9AB6A0D73EBC82E9B7
+
+I=81
+KEY=F4F5F6F7F9FAFBFCFEFE010103040506
+PT=86878485010203040808F7F767606162
+CT=3CB25C09472AFF6EE7E2B47CCD7CCB17
+
+I=82
+KEY=08090A0B0D0E0F10121314151718191A
+PT=8E8F8C8D656667788A8B8C8D010E0F0C
+CT=DEE33103A7283370D725E44CA38F8FE5
+
+I=83
+KEY=1C1D1E1F21222324262728292B2C2D2E
+PT=C8C9CACB858687807A7B7475E7E0E1E2
+CT=27F9BCD1AAC64BFFC11E7815702C1A69
+
+I=84
+KEY=30313233353637383A3B3C3D3F404142
+PT=6D6C6F6E5053525D8C8D8A8BADD2D3D0
+CT=5DF534FFAD4ED0749A9988E9849D0021
+
+I=85
+KEY=44454647494A4B4C4E4F505153545556
+PT=28292A2B393A3B3C0607181903040506
+CT=A48BEE75DB04FB60CA2B80F752A8421B
+
+I=86
+KEY=58595A5B5D5E5F60626364656768696A
+PT=A5A4A7A6B0B3B28DDBDADDDCBDB2B3B0
+CT=024C8CF70BC86EE5CE03678CB7AF45F9
+
+I=87
+KEY=6C6D6E6F71727374767778797B7C7D7E
+PT=323330316467666130313E3F2C2B2A29
+CT=3C19AC0F8A3A3862CE577831301E166B
+
+I=88
+KEY=80818283858687888A8B8C8D8F909192
+PT=27262524080B0A05171611100B141516
+CT=C5E355B796A57421D59CA6BE82E73BCA
+
+I=89
+KEY=94959697999A9B9C9E9FA0A1A3A4A5A6
+PT=040506074142434435340B0AA3A4A5A6
+CT=D94033276417ABFB05A69D15B6E386E2
+
+I=90
+KEY=A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA
+PT=242526271112130C61606766BDB2B3B0
+CT=24B36559EA3A9B9B958FE6DA3E5B8D85
+
+I=91
+KEY=BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE
+PT=4B4A4948252627209E9F9091CEC9C8CB
+CT=20FD4FEAA0E8BF0CCE7861D74EF4CB72
+
+I=92
+KEY=D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2
+PT=68696A6B6665646B9F9E9998D9E6E7E4
+CT=350E20D5174277B9EC314C501570A11D
+
+I=93
+KEY=E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6
+PT=34353637C5C6C7C0F0F1EEEF7C7B7A79
+CT=87A29D61B7C604D238FE73045A7EFD57
+
+I=94
+KEY=F8F9FAFBFDFEFE00020304050708090A
+PT=32333031C2C1C13F0D0C0B0A050A0B08
+CT=2C3164C1CC7D0064816BDC0FAA362C52
+
+I=95
+KEY=0C0D0E0F11121314161718191B1C1D1E
+PT=CDCCCFCEBEBDBCBBABAAA5A4181F1E1D
+CT=195FE5E8A05A2ED594F6E4400EEE10B3
+
+I=96
+KEY=20212223252627282A2B2C2D2F303132
+PT=212023223635343BA0A1A6A7445B5A59
+CT=E4663DF19B9A21A5A284C2BD7F905025
+
+I=97
+KEY=34353637393A3B3C3E3F404143444546
+PT=0E0F0C0DA8ABAAAD2F2E515002050407
+CT=21B88714CFB4E2A933BD281A2C4743FD
+
+I=98
+KEY=48494A4B4D4E4F50525354555758595A
+PT=070605042A2928378E8F8889BDB2B3B0
+CT=CBFC3980D704FD0FC54378AB84E17870
+
+I=99
+KEY=5C5D5E5F61626364666768696B6C6D6E
+PT=CBCAC9C893909196A9A8A7A6A5A2A3A0
+CT=BC5144BAA48BDEB8B63E22E03DA418EF
+
+I=100
+KEY=70717273757677787A7B7C7D7F808182
+PT=80818283C1C2C3CC9C9D9A9B0CF3F2F1
+CT=5A1DBAEF1EE2984B8395DA3BDFFA3CCC
+
+I=101
+KEY=84858687898A8B8C8E8F909193949596
+PT=1213101125262720FAFBE4E5B1B6B7B4
+CT=F0B11CD0729DFCC80CEC903D97159574
+
+I=102
+KEY=98999A9B9D9E9FA0A2A3A4A5A7A8A9AA
+PT=7F7E7D7C3033320D97969190222D2C2F
+CT=9F95314ACFDDC6D1914B7F19A9CC8209
+
+I=103
+KEY=ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE
+PT=4E4F4C4D484B4A4D81808F8E53545556
+CT=595736F6F0F70914A94E9E007F022519
+
+I=104
+KEY=C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2
+PT=DCDDDEDFB0B3B2BD15141312A1BEBFBC
+CT=1F19F57892CAE586FCDFB4C694DEB183
+
+I=105
+KEY=D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6
+PT=93929190282B2A2DC4C5FAFB92959497
+CT=540700EE1F6F3DAB0B3EDDF6CAEE1EF5
+
+I=106
+KEY=E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FA
+PT=F5F4F7F6C4C7C6D9373631307E717073
+CT=14A342A91019A331687A2254E6626CA2
+
+I=107
+KEY=FCFDFEFF01020304060708090B0C0D0E
+PT=93929190B6B5B4B364656A6B05020300
+CT=7B25F3C3B2EEA18D743EF283140F29FF
+
+I=108
+KEY=10111213151617181A1B1C1D1F202122
+PT=BABBB8B90D0E0F00A4A5A2A3043B3A39
+CT=46C2587D66E5E6FA7F7CA6411AD28047
+
+I=109
+KEY=24252627292A2B2C2E2F303133343536
+PT=D8D9DADB7F7C7D7A10110E0F787F7E7D
+CT=09470E72229D954ED5EE73886DFEEBA9
+
+I=110
+KEY=38393A3B3D3E3F40424344454748494A
+PT=FEFFFCFDEFECED923B3A3D3C6768696A
+CT=D77C03DE92D4D0D79EF8D4824EF365EB
+
+I=111
+KEY=4C4D4E4F51525354565758595B5C5D5E
+PT=D6D7D4D58A89888F96979899A5A2A3A0
+CT=1D190219F290E0F1715D152D41A23593
+
+I=112
+KEY=60616263656667686A6B6C6D6F707172
+PT=18191A1BA8ABAAA5303136379B848586
+CT=A2CD332CE3A0818769616292E87F757B
+
+I=113
+KEY=74757677797A7B7C7E7F808183848586
+PT=6B6A6968A4A7A6A1D6D72829B0B7B6B5
+CT=D54AFA6CE60FBF9341A3690E21385102
+
+I=114
+KEY=88898A8B8D8E8F90929394959798999A
+PT=000102038A89889755545352A6A9A8AB
+CT=06E5C364DED628A3F5E05E613E356F46
+
+I=115
+KEY=9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE
+PT=2D2C2F2EB3B0B1B6B6B7B8B9F2F5F4F7
+CT=EAE63C0E62556DAC85D221099896355A
+
+I=116
+KEY=B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2
+PT=979695943536373856575051E09F9E9D
+CT=1FED060E2C6FC93EE764403A889985A2
+
+I=117
+KEY=C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6
+PT=A4A5A6A7989B9A9DB1B0AFAE7A7D7C7F
+CT=C25235C1A30FDEC1C7CB5C5737B2A588
+
+I=118
+KEY=D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EA
+PT=C1C0C3C2686B6A55A8A9AEAFEAE5E4E7
+CT=796DBEF95147D4D30873AD8B7B92EFC0
+
+I=119
+KEY=ECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE
+PT=C1C0C3C2141716118C8D828364636261
+CT=CBCF0FB34D98D0BD5C22CE37211A46BF
+
+I=120
+KEY=00010203050607080A0B0C0D0F101112
+PT=93929190CCCFCEC196979091E0FFFEFD
+CT=94B44DA6466126CAFA7C7FD09063FC24
+
+I=121
+KEY=14151617191A1B1C1E1F202123242526
+PT=B4B5B6B7F9FAFBFC25241B1A6E69686B
+CT=D78C5B5EBF9B4DBDA6AE506C5074C8FE
+
+I=122
+KEY=28292A2B2D2E2F30323334353738393A
+PT=868784850704051AC7C6C1C08788898A
+CT=6C27444C27204B043812CF8CF95F9769
+
+I=123
+KEY=3C3D3E3F41424344464748494B4C4D4E
+PT=F4F5F6F7AAA9A8AFFDFCF3F277707172
+CT=BE94524EE5A2AA50BBA8B75F4C0AEBCF
+
+I=124
+KEY=50515253555657585A5B5C5D5F606162
+PT=D3D2D1D00605040BC3C2C5C43E010003
+CT=A0AEAAE91BA9F31F51AEB3588CF3A39E
+
+I=125
+KEY=64656667696A6B6C6E6F707173747576
+PT=73727170424140476A6B74750D0A0B08
+CT=275297779C28266EF9FE4C6A13C08488
+
+I=126
+KEY=78797A7B7D7E7F80828384858788898A
+PT=C2C3C0C10A0908F754555253A1AEAFAC
+CT=86523D92BB8672CB01CF4A77FD725882
+
+I=127
+KEY=8C8D8E8F91929394969798999B9C9D9E
+PT=6D6C6F6EF8FBFAFD82838C8DF8FFFEFD
+CT=4B8327640E9F33322A04DD96FCBF9A36
+
+I=128
+KEY=A0A1A2A3A5A6A7A8AAABACADAFB0B1B2
+PT=F5F4F7F684878689A6A7A0A1D2CDCCCF
+CT=CE52AF650D088CA559425223F4D32694
+
+==========
+
+KEYSIZE=192
+
+
+I=1
+KEY=00010203050607080A0B0C0D0F10111214151617191A1B1C
+PT=2D33EEF2C0430A8A9EBF45E809C40BB6
+CT=DFF4945E0336DF4C1C56BC700EFF837F
+
+I=2
+KEY=1E1F20212324252628292A2B2D2E2F30323334353738393A
+PT=6AA375D1FA155A61FB72353E0A5A8756
+CT=B6FDDEF4752765E347D5D2DC196D1252
+
+I=3
+KEY=3C3D3E3F41424344464748494B4C4D4E5051525355565758
+PT=BC3736518B9490DCB8ED60EB26758ED4
+CT=D23684E3D963B3AFCF1A114ACA90CBD6
+
+I=4
+KEY=5A5B5C5D5F60616264656667696A6B6C6E6F707173747576
+PT=AA214402B46CFFB9F761EC11263A311E
+CT=3A7AC027753E2A18C2CEAB9E17C11FD0
+
+I=5
+KEY=78797A7B7D7E7F80828384858788898A8C8D8E8F91929394
+PT=02AEA86E572EEAB66B2C3AF5E9A46FD6
+CT=8F6786BD007528BA26603C1601CDD0D8
+
+I=6
+KEY=969798999B9C9D9EA0A1A2A3A5A6A7A8AAABACADAFB0B1B2
+PT=E2AEF6ACC33B965C4FA1F91C75FF6F36
+CT=D17D073B01E71502E28B47AB551168B3
+
+I=7
+KEY=B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6C8C9CACBCDCECFD0
+PT=0659DF46427162B9434865DD9499F91D
+CT=A469DA517119FAB95876F41D06D40FFA
+
+I=8
+KEY=D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE
+PT=49A44239C748FEB456F59C276A5658DF
+CT=6091AA3B695C11F5C0B6AD26D3D862FF
+
+I=9
+KEY=F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C
+PT=66208F6E9D04525BDEDB2733B6A6BE37
+CT=70F9E67F9F8DF1294131662DC6E69364
+
+I=10
+KEY=0E0F10111314151618191A1B1D1E1F20222324252728292A
+PT=3393F8DFC729C97F5480B950BC9666B0
+CT=D154DCAFAD8B207FA5CBC95E9996B559
+
+I=11
+KEY=2C2D2E2F31323334363738393B3C3D3E4041424345464748
+PT=606834C8CE063F3234CF1145325DBD71
+CT=4934D541E8B46FA339C805A7AEB9E5DA
+
+I=12
+KEY=4A4B4C4D4F50515254555657595A5B5C5E5F606163646566
+PT=FEC1C04F529BBD17D8CECFCC4718B17F
+CT=62564C738F3EFE186E1A127A0C4D3C61
+
+I=13
+KEY=68696A6B6D6E6F70727374757778797A7C7D7E7F81828384
+PT=32DF99B431ED5DC5ACF8CAF6DC6CE475
+CT=07805AA043986EB23693E23BEF8F3438
+
+I=14
+KEY=868788898B8C8D8E90919293959697989A9B9C9D9FA0A1A2
+PT=7FDC2B746F3F665296943B83710D1F82
+CT=DF0B4931038BADE848DEE3B4B85AA44B
+
+I=15
+KEY=A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6B8B9BABBBDBEBFC0
+PT=8FBA1510A3C5B87E2EAA3F7A91455CA2
+CT=592D5FDED76582E4143C65099309477C
+
+I=16
+KEY=C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE
+PT=2C9B468B1C2EED92578D41B0716B223B
+CT=C9B8D6545580D3DFBCDD09B954ED4E92
+
+I=17
+KEY=E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFC
+PT=0A2BBF0EFC6BC0034F8A03433FCA1B1A
+CT=5DCCD5D6EB7C1B42ACB008201DF707A0
+
+I=18
+KEY=FEFE01010304050608090A0B0D0E0F10121314151718191A
+PT=25260E1F31F4104D387222E70632504B
+CT=A2A91682FFEB6ED1D34340946829E6F9
+
+I=19
+KEY=1C1D1E1F21222324262728292B2C2D2E3031323335363738
+PT=C527D25A49F08A5228D338642AE65137
+CT=E45D185B797000348D9267960A68435D
+
+I=20
+KEY=3A3B3C3D3F40414244454647494A4B4C4E4F505153545556
+PT=3B49FC081432F5890D0E3D87E884A69E
+CT=45E060DAE5901CDA8089E10D4F4C246B
+
+I=21
+KEY=58595A5B5D5E5F60626364656768696A6C6D6E6F71727374
+PT=D173F9ED1E57597E166931DF2754A083
+CT=F6951AFACC0079A369C71FDCFF45DF50
+
+I=22
+KEY=767778797B7C7D7E80818283858687888A8B8C8D8F909192
+PT=8C2B7CAFA5AFE7F13562DAEAE1ADEDE0
+CT=9E95E00F351D5B3AC3D0E22E626DDAD6
+
+I=23
+KEY=94959697999A9B9C9E9FA0A1A3A4A5A6A8A9AAABADAEAFB0
+PT=AAF4EC8C1A815AEB826CAB741339532C
+CT=9CB566FF26D92DAD083B51FDC18C173C
+
+I=24
+KEY=D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBEC
+PT=40BE8C5D9108E663F38F1A2395279ECF
+CT=C9C82766176A9B228EB9A974A010B4FB
+
+I=25
+KEY=2A2B2C2D2F30313234353637393A3B3C3E3F404143444546
+PT=0C8AD9BC32D43E04716753AA4CFBE351
+CT=D8E26AA02945881D5137F1C1E1386E88
+
+I=26
+KEY=48494A4B4D4E4F50525354555758595A5C5D5E5F61626364
+PT=1407B1D5F87D63357C8DC7EBBAEBBFEE
+CT=C0E024CCD68FF5FFA4D139C355A77C55
+
+I=27
+KEY=84858687898A8B8C8E8F90919394959698999A9B9D9E9FA0
+PT=E62734D1AE3378C4549E939E6F123416
+CT=0B18B3D16F491619DA338640DF391D43
+
+I=28
+KEY=A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE
+PT=5A752CFF2A176DB1A1DE77F2D2CDEE41
+CT=DBE09AC8F66027BF20CB6E434F252EFC
+
+I=29
+KEY=C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDC
+PT=A9C8C3A4EABEDC80C64730DDD018CD88
+CT=6D04E5E43C5B9CBE05FEB9606B6480FE
+
+I=30
+KEY=1A1B1C1D1F20212224252627292A2B2C2E2F303133343536
+PT=EE9B3DBBDB86180072130834D305999A
+CT=DD1D6553B96BE526D9FEE0FBD7176866
+
+I=31
+KEY=38393A3B3D3E3F40424344454748494A4C4D4E4F51525354
+PT=A7FA8C3586B8EBDE7568EAD6F634A879
+CT=0260CA7E3F979FD015B0DD4690E16D2A
+
+I=32
+KEY=929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE
+PT=37E0F4A87F127D45AC936FE7AD88C10A
+CT=9893734DE10EDCC8A67C3B110B8B8CC6
+
+I=33
+KEY=464748494B4C4D4E50515253555657585A5B5C5D5F606162
+PT=3F77D8B5D92BAC148E4E46F697A535C5
+CT=93B30B750516B2D18808D710C2EE84EF
+
+I=34
+KEY=828384858788898A8C8D8E8F91929394969798999B9C9D9E
+PT=D25EBB686C40F7E2C4DA1014936571CA
+CT=16F65FA47BE3CB5E6DFE7C6C37016C0E
+
+I=35
+KEY=A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBC
+PT=4F1C769D1E5B0552C7ECA84DEA26A549
+CT=F3847210D5391E2360608E5ACB560581
+
+I=36
+KEY=BEBFC0C1C3C4C5C6C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA
+PT=8548E2F882D7584D0FAFC54372B6633A
+CT=8754462CD223366D0753913E6AF2643D
+
+I=37
+KEY=DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEEF0F1F2F3F5F6F7F8
+PT=87D7A336CB476F177CD2A51AF2A62CDF
+CT=1EA20617468D1B806A1FD58145462017
+
+I=38
+KEY=FAFBFCFDFE01000204050607090A0B0C0E0F101113141516
+PT=03B1FEAC668C4E485C1065DFC22B44EE
+CT=3B155D927355D737C6BE9DDA60136E2E
+
+I=39
+KEY=18191A1B1D1E1F20222324252728292A2C2D2E2F31323334
+PT=BDA15E66819FA72D653A6866AA287962
+CT=26144F7B66DAA91B6333DBD3850502B3
+
+I=40
+KEY=363738393B3C3D3E40414243454647484A4B4C4D4F505152
+PT=4D0C7A0D2505B80BF8B62CEB12467F0A
+CT=E4F9A4AB52CED8134C649BF319EBCC90
+
+I=41
+KEY=54555657595A5B5C5E5F60616364656668696A6B6D6E6F70
+PT=626D34C9429B37211330986466B94E5F
+CT=B9DDD29AC6128A6CAB121E34A4C62B36
+
+I=42
+KEY=727374757778797A7C7D7E7F81828384868788898B8C8D8E
+PT=333C3E6BF00656B088A17E5FF0E7F60A
+CT=6FCDDAD898F2CE4EFF51294F5EAAF5C9
+
+I=43
+KEY=90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABAC
+PT=687ED0CDC0D2A2BC8C466D05EF9D2891
+CT=C9A6FE2BF4028080BEA6F7FC417BD7E3
+
+I=44
+KEY=AEAFB0B1B3B4B5B6B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CA
+PT=487830E78CC56C1693E64B2A6660C7B6
+CT=6A2026846D8609D60F298A9C0673127F
+
+I=45
+KEY=CCCDCECFD1D2D3D4D6D7D8D9DBDCDDDEE0E1E2E3E5E6E7E8
+PT=7A48D6B7B52B29392AA2072A32B66160
+CT=2CB25C005E26EFEA44336C4C97A4240B
+
+I=46
+KEY=EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506
+PT=907320E64C8C5314D10F8D7A11C8618D
+CT=496967AB8680DDD73D09A0E4C7DCC8AA
+
+I=47
+KEY=08090A0B0D0E0F10121314151718191A1C1D1E1F21222324
+PT=B561F2CA2D6E65A4A98341F3ED9FF533
+CT=D5AF94DE93487D1F3A8C577CB84A66A4
+
+I=48
+KEY=262728292B2C2D2E30313233353637383A3B3C3D3F404142
+PT=DF769380D212792D026F049E2E3E48EF
+CT=84BDAC569CAE2828705F267CC8376E90
+
+I=49
+KEY=44454647494A4B4C4E4F50515354555658595A5B5D5E5F60
+PT=79F374BC445BDABF8FCCB8843D6054C6
+CT=F7401DDA5AD5AB712B7EB5D10C6F99B6
+
+I=50
+KEY=626364656768696A6C6D6E6F71727374767778797B7C7D7E
+PT=4E02F1242FA56B05C68DBAE8FE44C9D6
+CT=1C9D54318539EBD4C3B5B7E37BF119F0
+
+I=51
+KEY=80818283858687888A8B8C8D8F90919294959697999A9B9C
+PT=CF73C93CBFF57AC635A6F4AD2A4A1545
+CT=ACA572D65FB2764CFFD4A6ECA090EA0D
+
+I=52
+KEY=9E9FA0A1A3A4A5A6A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA
+PT=9923548E2875750725B886566784C625
+CT=36D9C627B8C2A886A10CCB36EAE3DFBB
+
+I=53
+KEY=BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCED0D1D2D3D5D6D7D8
+PT=4888336B723A022C9545320F836A4207
+CT=010EDBF5981E143A81D646E597A4A568
+
+I=54
+KEY=DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6
+PT=F84D9A5561B0608B1160DEE000C41BA8
+CT=8DB44D538DC20CC2F40F3067FD298E60
+
+I=55
+KEY=F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314
+PT=C23192A0418E30A19B45AE3E3625BF22
+CT=930EB53BC71E6AC4B82972BDCD5AAFB3
+
+I=56
+KEY=161718191B1C1D1E20212223252627282A2B2C2D2F303132
+PT=B84E0690B28B0025381AD82A15E501A7
+CT=6C42A81EDCBC9517CCD89C30C95597B4
+
+I=57
+KEY=34353637393A3B3C3E3F40414344454648494A4B4D4E4F50
+PT=ACEF5E5C108876C4F06269F865B8F0B0
+CT=DA389847AD06DF19D76EE119C71E1DD3
+
+I=58
+KEY=525354555758595A5C5D5E5F61626364666768696B6C6D6E
+PT=0F1B3603E0F5DDEA4548246153A5E064
+CT=E018FDAE13D3118F9A5D1A647A3F0462
+
+I=59
+KEY=70717273757677787A7B7C7D7F80818284858687898A8B8C
+PT=FBB63893450D42B58C6D88CD3C1809E3
+CT=2AA65DB36264239D3846180FABDFAD20
+
+I=60
+KEY=8E8F90919394959698999A9B9D9E9FA0A2A3A4A5A7A8A9AA
+PT=4BEF736DF150259DAE0C91354E8A5F92
+CT=1472163E9A4F780F1CEB44B07ECF4FDB
+
+I=61
+KEY=ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBEC0C1C2C3C5C6C7C8
+PT=7D2D46242056EF13D3C3FC93C128F4C7
+CT=C8273FDC8F3A9F72E91097614B62397C
+
+I=62
+KEY=CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6
+PT=E9C1BA2DF415657A256EDB33934680FD
+CT=66C8427DCD733AAF7B3470CB7D976E3F
+
+I=63
+KEY=E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304
+PT=E23EE277B0AA0A1DFB81F7527C3514F1
+CT=146131CB17F1424D4F8DA91E6F80C1D0
+
+I=64
+KEY=060708090B0C0D0E10111213151617181A1B1C1D1F202122
+PT=3E7445B0B63CAAF75E4A911E12106B4C
+CT=2610D0AD83659081AE085266A88770DC
+
+I=65
+KEY=24252627292A2B2C2E2F30313334353638393A3B3D3E3F40
+PT=767774752023222544455A5BE6E1E0E3
+CT=38A2B5A974B0575C5D733917FB0D4570
+
+I=66
+KEY=424344454748494A4C4D4E4F51525354565758595B5C5D5E
+PT=72737475717E7F7CE9E8EBEA696A6B6C
+CT=E21D401EBC60DE20D6C486E4F39A588B
+
+I=67
+KEY=60616263656667686A6B6C6D6F70717274757677797A7B7C
+PT=DFDEDDDC25262728C9C8CFCEF1EEEFEC
+CT=E51D5F88C670B079C0CA1F0C2C4405A2
+
+I=68
+KEY=7E7F80818384858688898A8B8D8E8F90929394959798999A
+PT=FFFE0100707776755F5E5D5C7675746B
+CT=246A94788A642FB3D1B823C8762380C8
+
+I=69
+KEY=9C9D9E9FA1A2A3A4A6A7A8A9ABACADAEB0B1B2B3B5B6B7B8
+PT=E0E1E2E3424140479F9E9190292E2F2C
+CT=B80C391C5C41A4C3B30C68E0E3D7550F
+
+I=70
+KEY=BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6
+PT=2120272690EFEEED3B3A39384E4D4C4B
+CT=B77C4754FC64EB9A1154A9AF0BB1F21C
+
+I=71
+KEY=D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4
+PT=ECEDEEEF5350516EA1A0A7A6A3ACADAE
+CT=FB554DE520D159A06BF219FC7F34A02F
+
+I=72
+KEY=F6F7F8F9FBFCFDFE00010203050607080A0B0C0D0F101112
+PT=32333C3D25222320E9E8EBEACECDCCC3
+CT=A89FBA152D76B4927BEED160DDB76C57
+
+I=73
+KEY=14151617191A1B1C1E1F20212324252628292A2B2D2E2F30
+PT=40414243626160678A8BB4B511161714
+CT=5676EAB4A98D2E8473B3F3D46424247C
+
+I=74
+KEY=323334353738393A3C3D3E3F41424344464748494B4C4D4E
+PT=94959293F5FAFBF81F1E1D1C7C7F7E79
+CT=4E8F068BD7EDE52A639036EC86C33568
+
+I=75
+KEY=50515253555657585A5B5C5D5F60616264656667696A6B6C
+PT=BEBFBCBD191A1B14CFCEC9C8546B6A69
+CT=F0193C4D7AFF1791EE4C07EB4A1824FC
+
+I=76
+KEY=6E6F70717374757678797A7B7D7E7F80828384858788898A
+PT=2C2D3233898E8F8CBBBAB9B8333031CE
+CT=AC8686EECA9BA761AFE82D67B928C33F
+
+I=77
+KEY=8C8D8E8F91929394969798999B9C9D9EA0A1A2A3A5A6A7A8
+PT=84858687BFBCBDBA37363938FDFAFBF8
+CT=5FAF8573E33B145B6A369CD3606AB2C9
+
+I=78
+KEY=AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6
+PT=828384857669686B909192930B08090E
+CT=31587E9944AB1C16B844ECAD0DF2E7DA
+
+I=79
+KEY=C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4
+PT=BEBFBCBD9695948B707176779E919093
+CT=D017FECD91148ABA37F6F3068AA67D8A
+
+I=80
+KEY=E6E7E8E9EBECEDEEF0F1F2F3F5F6F7F8FAFBFCFDFE010002
+PT=8B8A85846067666521202322D0D3D2DD
+CT=788EF2F021A73CBA2794B616078A8500
+
+I=81
+KEY=04050607090A0B0C0E0F10111314151618191A1B1D1E1F20
+PT=76777475F1F2F3F4F8F9E6E777707172
+CT=5D1EF20DCED6BCBC12131AC7C54788AA
+
+I=82
+KEY=222324252728292A2C2D2E2F31323334363738393B3C3D3E
+PT=A4A5A2A34F404142B4B5B6B727242522
+CT=B3C8CF961FAF9EA05FDDE6D1E4D8F663
+
+I=83
+KEY=40414243454647484A4B4C4D4F50515254555657595A5B5C
+PT=94959697E1E2E3EC16171011839C9D9E
+CT=143075C70605861C7FAC6526199E459F
+
+I=84
+KEY=5E5F60616364656668696A6B6D6E6F70727374757778797A
+PT=03023D3C06010003DEDFDCDDFFFCFDE2
+CT=A5AE12EADE9A87268D898BFC8FC0252A
+
+I=85
+KEY=7C7D7E7F81828384868788898B8C8D8E9091929395969798
+PT=10111213F1F2F3F4CECFC0C1DBDCDDDE
+CT=0924F7CF2E877A4819F5244A360DCEA9
+
+I=86
+KEY=9A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6
+PT=67666160724D4C4F1D1C1F1E73707176
+CT=3D9E9635AFCC3E291CC7AB3F27D1C99A
+
+I=87
+KEY=B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4
+PT=E6E7E4E5A8ABAAD584858283909F9E9D
+CT=9D80FEEBF87510E2B8FB98BB54FD788C
+
+I=88
+KEY=D6D7D8D9DBDCDDDEE0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2
+PT=71707F7E565150537D7C7F7E6162636C
+CT=5F9D1A082A1A37985F174002ECA01309
+
+I=89
+KEY=F4F5F6F7F9FAFBFCFEFE01010304050608090A0B0D0E0F10
+PT=64656667212223245555AAAA03040506
+CT=A390EBB1D1403930184A44B4876646E4
+
+I=90
+KEY=121314151718191A1C1D1E1F21222324262728292B2C2D2E
+PT=9E9F9899ABA4A5A6CFCECDCC2B28292E
+CT=700FE918981C3195BB6C4BCB46B74E29
+
+I=91
+KEY=30313233353637383A3B3C3D3F40414244454647494A4B4C
+PT=C7C6C5C4D1D2D3DC626364653A454447
+CT=907984406F7BF2D17FB1EB15B673D747
+
+I=92
+KEY=4E4F50515354555658595A5B5D5E5F60626364656768696A
+PT=F6F7E8E9E0E7E6E51D1C1F1E5B585966
+CT=C32A956DCFC875C2AC7C7CC8B8CC26E1
+
+I=93
+KEY=6C6D6E6F71727374767778797B7C7D7E8081828385868788
+PT=BCBDBEBF5D5E5F5868696667F4F3F2F1
+CT=02646E2EBFA9B820CF8424E9B9B6EB51
+
+I=94
+KEY=8A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6
+PT=40414647B0AFAEAD9B9A99989B98999E
+CT=621FDA3A5BBD54C6D3C685816BD4EAD8
+
+I=95
+KEY=A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4
+PT=69686B6A0201001F0F0E0908B4BBBAB9
+CT=D4E216040426DFAF18B152469BC5AC2F
+
+I=96
+KEY=C6C7C8C9CBCCCDCED0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2
+PT=C7C6C9C8D8DFDEDD5A5B5859BEBDBCB3
+CT=9D0635B9D33B6CDBD71F5D246EA17CC8
+
+I=97
+KEY=E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6F8F9FAFBFDFEFE00
+PT=DEDFDCDD787B7A7DFFFEE1E0B2B5B4B7
+CT=10ABAD1BD9BAE5448808765583A2CC1A
+
+I=98
+KEY=020304050708090A0C0D0E0F11121314161718191B1C1D1E
+PT=4D4C4B4A606F6E6DD0D1D2D3FBF8F9FE
+CT=6891889E16544E355FF65A793C39C9A8
+
+I=99
+KEY=20212223252627282A2B2C2D2F30313234353637393A3B3C
+PT=B7B6B5B4D7D4D5DAE5E4E3E2E1FEFFFC
+CT=CC735582E68072C163CD9DDF46B91279
+
+I=100
+KEY=3E3F40414344454648494A4B4D4E4F50525354555758595A
+PT=CECFB0B1F7F0F1F2AEAFACAD3E3D3C23
+CT=C5C68B9AEEB7F878DF578EFA562F9574
+
+I=101
+KEY=5C5D5E5F61626364666768696B6C6D6E7071727375767778
+PT=CACBC8C9CDCECFC812131C1D494E4F4C
+CT=5F4764395A667A47D73452955D0D2CE8
+
+I=102
+KEY=7A7B7C7D7F80818284858687898A8B8C8E8F909193949596
+PT=9D9C9B9AD22D2C2FB1B0B3B20C0F0E09
+CT=701448331F66106CEFDDF1EB8267C357
+
+I=103
+KEY=98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4
+PT=7A7B787964676659959493924F404142
+CT=CB3EE56D2E14B4E1941666F13379D657
+
+I=104
+KEY=B6B7B8B9BBBCBDBEC0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2
+PT=AAABA4A5CEC9C8CB1F1E1D1CABA8A9A6
+CT=9FE16EFD18AB6E1981191851FEDB0764
+
+I=105
+KEY=D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6E8E9EAEBEDEEEFF0
+PT=93929190282B2A2DC4C5FAFB92959497
+CT=3DC9BA24E1B223589B147ADCEB4C8E48
+
+I=106
+KEY=F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E
+PT=EFEEE9E8DED1D0D339383B3A888B8A8D
+CT=1C333032682E7D4DE5E5AFC05C3E483C
+
+I=107
+KEY=10111213151617181A1B1C1D1F20212224252627292A2B2C
+PT=7F7E7D7CA2A1A0AF78797E7F112E2F2C
+CT=D593CC99A95AFEF7E92038E05A59D00A
+
+I=108
+KEY=2E2F30313334353638393A3B3D3E3F40424344454748494A
+PT=84859A9B2B2C2D2E868784852625245B
+CT=51E7F96F53B4353923452C222134E1EC
+
+I=109
+KEY=4C4D4E4F51525354565758595B5C5D5E6061626365666768
+PT=B0B1B2B3070405026869666710171615
+CT=4075B357A1A2B473400C3B25F32F81A4
+
+I=110
+KEY=6A6B6C6D6F70717274757677797A7B7C7E7F808183848586
+PT=ACADAAABBDA2A3A00D0C0F0E595A5B5C
+CT=302E341A3EBCD74F0D55F61714570284
+
+I=111
+KEY=88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4
+PT=121310115655544B5253545569666764
+CT=57ABDD8231280DA01C5042B78CF76522
+
+I=112
+KEY=A6A7A8A9ABACADAEB0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2
+PT=DEDFD0D166616063EAEBE8E94142434C
+CT=17F9EA7EEA17AC1ADF0E190FEF799E92
+
+I=113
+KEY=C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6D8D9DADBDDDEDFE0
+PT=DBDAD9D81417161166677879E0E7E6E5
+CT=2E1BDD563DD87EE5C338DD6D098D0A7A
+
+I=114
+KEY=E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE
+PT=6A6B6C6DE0EFEEED2B2A2928C0C3C2C5
+CT=EB869996E6F8BFB2BFDD9E0C4504DBB2
+
+I=115
+KEY=00010203050607080A0B0C0D0F10111214151617191A1B1C
+PT=B1B0B3B21714151A1A1B1C1D5649484B
+CT=C2E01549E9DECF317468B3E018C61BA8
+
+I=116
+KEY=1E1F20212324252628292A2B2D2E2F30323334353738393A
+PT=39380706A3A4A5A6C4C5C6C77271706F
+CT=8DA875D033C01DD463B244A1770F4A22
+
+I=117
+KEY=3C3D3E3F41424344464748494B4C4D4E5051525355565758
+PT=5C5D5E5F1013121539383736E2E5E4E7
+CT=8BA0DCF3A186844F026D022F8839D696
+
+I=118
+KEY=5A5B5C5D5F60616264656667696A6B6C6E6F707173747576
+PT=43424544EAD5D4D72E2F2C2D64676661
+CT=E9691FF9A6CC6970E51670A0FD5B88C1
+
+I=119
+KEY=78797A7B7D7E7F80828384858788898A8C8D8E8F91929394
+PT=55545756989B9A65F8F9FEFF18171615
+CT=F2BAEC06FAEED30F88EE63BA081A6E5B
+
+I=120
+KEY=969798999B9C9D9EA0A1A2A3A5A6A7A8AAABACADAFB0B1B2
+PT=05040B0A525554573C3D3E3F4A494847
+CT=9C39D4C459AE5753394D6094ADC21E78
+
+I=121
+KEY=B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6C8C9CACBCDCECFD0
+PT=14151617595A5B5C8584FBFA8E89888B
+CT=6345B532A11904502EA43BA99C6BD2B2
+
+I=122
+KEY=D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE
+PT=7C7D7A7BFDF2F3F029282B2A51525354
+CT=5FFAE3061A95172E4070CEDCE1E428C8
+
+I=123
+KEY=F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C
+PT=38393A3B1E1D1C1341404746C23D3C3E
+CT=0A4566BE4CDF9ADCE5DEC865B5AB34CD
+
+I=124
+KEY=0E0F10111314151618191A1B1D1E1F20222324252728292A
+PT=8D8C939240474645818083827C7F7E41
+CT=CA17FCCE79B7404F2559B22928F126FB
+
+I=125
+KEY=2C2D2E2F31323334363738393B3C3D3E4041424345464748
+PT=3B3A39381A19181F32333C3D45424340
+CT=97CA39B849ED73A6470A97C821D82F58
+
+I=126
+KEY=4A4B4C4D4F50515254555657595A5B5C5E5F606163646566
+PT=F0F1F6F738272625828380817F7C7D7A
+CT=8198CB06BC684C6D3E9B7989428DCF7A
+
+I=127
+KEY=68696A6B6D6E6F70727374757778797A7C7D7E7F81828384
+PT=89888B8A0407061966676061141B1A19
+CT=F53C464C705EE0F28D9A4C59374928BD
+
+I=128
+KEY=868788898B8C8D8E90919293959697989A9B9C9D9FA0A1A2
+PT=D3D2DDDCAAADACAF9C9D9E9FE8EBEAE5
+CT=9ADB3D4CCA559BB98C3E2ED73DBF1154
+
+==========
+
+KEYSIZE=256
+
+
+I=1
+KEY=00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526
+PT=834EADFCCAC7E1B30664B1ABA44815AB
+CT=1946DABF6A03A2A2C3D0B05080AED6FC
+
+I=2
+KEY=28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E
+PT=D9DC4DBA3021B05D67C0518F72B62BF1
+CT=5ED301D747D3CC715445EBDEC62F2FB4
+
+I=3
+KEY=50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576
+PT=A291D86301A4A739F7392173AA3C604C
+CT=6585C8F43D13A6BEAB6419FC5935B9D0
+
+I=4
+KEY=78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E
+PT=4264B2696498DE4DF79788A9F83E9390
+CT=2A5B56A596680FCC0E05F5E0F151ECAE
+
+I=5
+KEY=A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6
+PT=EE9932B3721804D5A83EF5949245B6F6
+CT=F5D6FF414FD2C6181494D20C37F2B8C4
+
+I=6
+KEY=C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE
+PT=E6248F55C5FDCBCA9CBBB01C88A2EA77
+CT=85399C01F59FFFB5204F19F8482F00B8
+
+I=7
+KEY=F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516
+PT=B8358E41B9DFF65FD461D55A99266247
+CT=92097B4C88A041DDF98144BC8D22E8E7
+
+I=8
+KEY=18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E
+PT=F0E2D72260AF58E21E015AB3A4C0D906
+CT=89BD5B73B356AB412AEF9F76CEA2D65C
+
+I=9
+KEY=40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566
+PT=475B8B823CE8893DB3C44A9F2A379FF7
+CT=2536969093C55FF9454692F2FAC2F530
+
+I=10
+KEY=68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E
+PT=688F5281945812862F5F3076CF80412F
+CT=07FC76A872843F3F6E0081EE9396D637
+
+I=11
+KEY=90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6
+PT=08D1D2BC750AF553365D35E75AFACEAA
+CT=E38BA8EC2AA741358DCC93E8F141C491
+
+I=12
+KEY=B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE
+PT=8707121F47CC3EFCECA5F9A8474950A1
+CT=D028EE23E4A89075D0B03E868D7D3A42
+
+I=13
+KEY=E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506
+PT=E51AA0B135DBA566939C3B6359A980C5
+CT=8CD9423DFC459E547155C5D1D522E540
+
+I=14
+KEY=08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E
+PT=069A007FC76A459F98BAF917FEDF9521
+CT=080E9517EB1677719ACF728086040AE3
+
+I=15
+KEY=30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556
+PT=726165C1723FBCF6C026D7D00B091027
+CT=7C1700211A3991FC0ECDED0AB3E576B0
+
+I=16
+KEY=58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E
+PT=D7C544DE91D55CFCDE1F84CA382200CE
+CT=DABCBCC855839251DB51E224FBE87435
+
+I=17
+KEY=80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6
+PT=FED3C9A161B9B5B2BD611B41DC9DA357
+CT=68D56FAD0406947A4DD27A7448C10F1D
+
+I=18
+KEY=A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE
+PT=4F634CDC6551043409F30B635832CF82
+CT=DA9A11479844D1FFEE24BBF3719A9925
+
+I=19
+KEY=D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6
+PT=109CE98DB0DFB36734D9F3394711B4E6
+CT=5E4BA572F8D23E738DA9B05BA24B8D81
+
+I=20
+KEY=70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596
+PT=4EA6DFABA2D8A02FFDFFA89835987242
+CT=A115A2065D667E3F0B883837A6E903F8
+
+I=21
+KEY=98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE
+PT=5AE094F54AF58E6E3CDBF976DAC6D9EF
+CT=3E9E90DC33EAC2437D86AD30B137E66E
+
+I=22
+KEY=C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6
+PT=764D8E8E0F29926DBE5122E66354FDBE
+CT=01CE82D8FBCDAE824CB3C48E495C3692
+
+I=23
+KEY=E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E
+PT=3F0418F888CDF29A982BF6B75410D6A9
+CT=0C9CFF163CE936FAAF083CFD3DEA3117
+
+I=24
+KEY=10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536
+PT=E4A3E7CB12CDD56AA4A75197A9530220
+CT=5131BA9BD48F2BBA85560680DF504B52
+
+I=25
+KEY=38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E
+PT=211677684AAC1EC1A160F44C4EBF3F26
+CT=9DC503BBF09823AEC8A977A5AD26CCB2
+
+I=26
+KEY=60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586
+PT=D21E439FF749AC8F18D6D4B105E03895
+CT=9A6DB0C0862E506A9E397225884041D7
+
+I=27
+KEY=88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE
+PT=D9F6FF44646C4725BD4C0103FF5552A7
+CT=430BF9570804185E1AB6365FC6A6860C
+
+I=28
+KEY=B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6
+PT=0B1256C2A00B976250CFC5B0C37ED382
+CT=3525EBC02F4886E6A5A3762813E8CE8A
+
+I=29
+KEY=D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE
+PT=B056447FFC6DC4523A36CC2E972A3A79
+CT=07FA265C763779CCE224C7BAD671027B
+
+I=30
+KEY=00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526
+PT=5E25CA78F0DE55802524D38DA3FE4456
+CT=E8B72B4E8BE243438C9FFF1F0E205872
+
+I=31
+KEY=28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E
+PT=A5BCF4728FA5EAAD8567C0DC24675F83
+CT=109D4F999A0E11ACE1F05E6B22CBCB50
+
+I=32
+KEY=50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576
+PT=814E59F97ED84646B78B2CA022E9CA43
+CT=45A5E8D4C3ED58403FF08D68A0CC4029
+
+I=33
+KEY=78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E
+PT=15478BEEC58F4775C7A7F5D4395514D7
+CT=196865964DB3D417B6BD4D586BCB7634
+
+I=34
+KEY=A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6
+PT=253548FFCA461C67C8CBC78CD59F4756
+CT=60436AD45AC7D30D99195F815D98D2AE
+
+I=35
+KEY=C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE
+PT=FD7AD8D73B9B0F8CC41600640F503D65
+CT=BB07A23F0B61014B197620C185E2CD75
+
+I=36
+KEY=F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516
+PT=06199DE52C6CBF8AF954CD65830BCD56
+CT=5BC0B2850129C854423AFF0751FE343B
+
+I=37
+KEY=18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E
+PT=F17C4FFE48E44C61BD891E257E725794
+CT=7541A78F96738E6417D2A24BD2BECA40
+
+I=38
+KEY=40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566
+PT=9A5B4A402A3E8A59BE6BF5CD8154F029
+CT=B0A303054412882E464591F1546C5B9E
+
+I=39
+KEY=68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E
+PT=79BD40B91A7E07DC939D441782AE6B17
+CT=778C06D8A355EEEE214FCEA14B4E0EEF
+
+I=40
+KEY=90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6
+PT=D8CEAAF8976E5FBE1012D8C84F323799
+CT=09614206D15CBACE63227D06DB6BEEBB
+
+I=41
+KEY=B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE
+PT=3316E2751E2E388B083DA23DD6AC3FBE
+CT=41B97FB20E427A9FDBBB358D9262255D
+
+I=42
+KEY=E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506
+PT=8B7CFBE37DE7DCA793521819242C5816
+CT=C1940F703D845F957652C2D64ABD7ADF
+
+I=43
+KEY=08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E
+PT=F23F033C0EEBF8EC55752662FD58CE68
+CT=D2D44FCDAE5332343366DB297EFCF21B
+
+I=44
+KEY=30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556
+PT=59EB34F6C8BDBACC5FC6AD73A59A1301
+CT=EA8196B79DBE167B6AA9896E287EED2B
+
+I=45
+KEY=58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E
+PT=DCDE8B6BD5CF7CC22D9505E3CE81261A
+CT=D6B0B0C4BA6C7DBE5ED467A1E3F06C2D
+
+I=46
+KEY=80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6
+PT=E33CF7E524FED781E7042FF9F4B35DC7
+CT=EC51EB295250C22C2FB01816FB72BCAE
+
+I=47
+KEY=A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE
+PT=27963C8FACDF73062867D164DF6D064C
+CT=ADED6630A07CE9C7408A155D3BD0D36F
+
+I=48
+KEY=D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6
+PT=77B1CE386B551B995F2F2A1DA994EEF8
+CT=697C9245B9937F32F5D1C82319F0363A
+
+I=49
+KEY=F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E
+PT=F083388B013679EFCF0BB9B15D52AE5C
+CT=AAD5AD50C6262AAEC30541A1B7B5B19C
+
+I=50
+KEY=20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546
+PT=C5009E0DAB55DB0ABDB636F2600290C8
+CT=7D34B893855341EC625BD6875AC18C0D
+
+I=51
+KEY=48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E
+PT=7804881E26CD532D8514D3683F00F1B9
+CT=7EF05105440F83862F5D780E88F02B41
+
+I=52
+KEY=70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596
+PT=46CDDCD73D1EB53E675CA012870A92A3
+CT=C377C06403382061AF2C9C93A8E70DF6
+
+I=53
+KEY=98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE
+PT=A9FB44062BB07FE130A8E8299EACB1AB
+CT=1DBDB3FFDC052DACC83318853ABC6DE5
+
+I=54
+KEY=C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6
+PT=2B6FF8D7A5CC3A28A22D5A6F221AF26B
+CT=69A6EAB00432517D0BF483C91C0963C7
+
+I=55
+KEY=E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E
+PT=1A9527C29B8ADD4B0E3E656DBB2AF8B4
+CT=0797F41DC217C80446E1D514BD6AB197
+
+I=56
+KEY=10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536
+PT=7F99CF2C75244DF015EB4B0C1050AEAE
+CT=9DFD76575902A637C01343C58E011A03
+
+I=57
+KEY=38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E
+PT=E84FF85B0D9454071909C1381646C4ED
+CT=ACF4328AE78F34B9FA9B459747CC2658
+
+I=58
+KEY=60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586
+PT=89AFD40F99521280D5399B12404F6DB4
+CT=B0479AEA12BAC4FE2384CF98995150C6
+
+I=59
+KEY=88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE
+PT=A09EF32DBC5119A35AB7FA38656F0329
+CT=9DD52789EFE3FFB99F33B3DA5030109A
+
+I=60
+KEY=B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6
+PT=61773457F068C376C7829B93E696E716
+CT=ABBB755E4621EF8F1214C19F649FB9FD
+
+I=61
+KEY=D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE
+PT=A34F0CAE726CCE41DD498747D891B967
+CT=DA27FB8174357BCE2BED0E7354F380F9
+
+I=62
+KEY=00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526
+PT=856F59496C7388EE2D2B1A27B7697847
+CT=C59A0663F0993838F6E5856593BDC5EF
+
+I=63
+KEY=28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E
+PT=CB090C593EF7720BD95908FB93B49DF4
+CT=ED60B264B5213E831607A99C0CE5E57E
+
+I=64
+KEY=50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576
+PT=A0AC75CD2F1923D460FC4D457AD95BAF
+CT=E50548746846F3EB77B8C520640884ED
+
+I=65
+KEY=78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E
+PT=2A2B282974777689E8E9EEEF525D5C5F
+CT=28282CC7D21D6A2923641E52D188EF0C
+
+I=66
+KEY=A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6
+PT=909192939390919E0F0E09089788898A
+CT=0DFA5B02ABB18E5A815305216D6D4F8E
+
+I=67
+KEY=C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE
+PT=777675748D8E8F907170777649464744
+CT=7359635C0EECEFE31D673395FB46FB99
+
+I=68
+KEY=F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516
+PT=717073720605040B2D2C2B2A05FAFBF9
+CT=73C679F7D5AEF2745C9737BB4C47FB36
+
+I=69
+KEY=18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E
+PT=64656667FEFDFCC31B1A1D1CA5AAABA8
+CT=B192BD472A4D2EAFB786E97458967626
+
+I=70
+KEY=40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566
+PT=DBDAD9D86A696867B5B4B3B2C8D7D6D5
+CT=0EC327F6C8A2B147598CA3FDE61DC6A4
+
+I=71
+KEY=68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E
+PT=5C5D5E5FE3E0E1FE31303736333C3D3E
+CT=FC418EB3C41B859B38D4B6F646629729
+
+I=72
+KEY=90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6
+PT=545556574B48494673727574546B6A69
+CT=30249E5AC282B1C981EA64B609F3A154
+
+I=73
+KEY=B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE
+PT=ECEDEEEFC6C5C4BB56575051F5FAFBF8
+CT=5E6E08646D12150776BB43C2D78A9703
+
+I=74
+KEY=E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506
+PT=464744452724252AC9C8CFCED2CDCCCF
+CT=FAEB3D5DE652CD3447DCEB343F30394A
+
+I=75
+KEY=08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E
+PT=E6E7E4E54142435C878681801C131211
+CT=A8E88706823F6993EF80D05C1C7B2CF0
+
+I=76
+KEY=30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556
+PT=72737071CFCCCDC2F9F8FFFE710E0F0C
+CT=8CED86677E6E00A1A1B15968F2D3CCE6
+
+I=77
+KEY=58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E
+PT=505152537370714EC3C2C5C4010E0F0C
+CT=9FC7C23858BE03BDEBB84E90DB6786A9
+
+I=78
+KEY=80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6
+PT=A8A9AAAB5C5F5E51AEAFA8A93D222320
+CT=B4FBD65B33F70D8CF7F1111AC4649C36
+
+I=79
+KEY=A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE
+PT=DEDFDCDDF6F5F4EB10111617FEF1F0F3
+CT=C5C32D5ED03C4B53CC8C1BD0EF0DBBF6
+
+I=80
+KEY=D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6
+PT=BDBCBFBE5E5D5C530B0A0D0CFAC5C4C7
+CT=D1A7F03B773E5C212464B63709C6A891
+
+I=81
+KEY=F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E
+PT=8A8B8889050606F8F4F5F2F3636C6D6E
+CT=6B7161D8745947AC6950438EA138D028
+
+I=82
+KEY=20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546
+PT=A6A7A4A54D4E4F40B2B3B4B539262724
+CT=FD47A9F7E366EE7A09BC508B00460661
+
+I=83
+KEY=48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E
+PT=9C9D9E9FE9EAEBF40E0F08099B949596
+CT=00D40B003DC3A0D9310B659B98C7E416
+
+I=84
+KEY=70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596
+PT=2D2C2F2E1013121DCCCDCACBED121310
+CT=EEA4C79DCC8E2BDA691F20AC48BE0717
+
+I=85
+KEY=98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE
+PT=F4F5F6F7EDEEEFD0EAEBECEDF7F8F9FA
+CT=E78F43B11C204403E5751F89D05A2509
+
+I=86
+KEY=C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6
+PT=3D3C3F3E282B2A2573727574150A0B08
+CT=D0F0E3D1F1244BB979931E38DD1786EF
+
+I=87
+KEY=E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E
+PT=B6B7B4B5F8FBFAE5B4B5B2B3A0AFAEAD
+CT=042E639DC4E1E4DDE7B75B749EA6F765
+
+I=88
+KEY=10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536
+PT=B7B6B5B4989B9A95878681809BA4A5A6
+CT=BC032FDD0EFE29503A980A7D07AB46A8
+
+I=89
+KEY=38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E
+PT=A8A9AAABE5E6E798E9E8EFEE4748494A
+CT=0C93AC949C0DA6446EFFB86183B6C910
+
+I=90
+KEY=60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586
+PT=ECEDEEEFD9DADBD4B9B8BFBE657A7B78
+CT=E0D343E14DA75C917B4A5CEC4810D7C2
+
+I=91
+KEY=88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE
+PT=7F7E7D7C696A6B74CACBCCCD929D9C9F
+CT=0EAFB821748408279B937B626792E619
+
+I=92
+KEY=B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6
+PT=08090A0B0605040BFFFEF9F8B9C6C7C4
+CT=FA1AC6E02D23B106A1FEF18B274A553F
+
+I=93
+KEY=D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE
+PT=08090A0BF1F2F3CCFCFDFAFB68676665
+CT=0DADFE019CD12368075507DF33C1A1E9
+
+I=94
+KEY=00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526
+PT=CACBC8C93A393837050403020D121310
+CT=3A0879B414465D9FFBAF86B33A63A1B9
+
+I=95
+KEY=28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E
+PT=E9E8EBEA8281809F8F8E8988343B3A39
+CT=62199FADC76D0BE1805D3BA0B7D914BF
+
+I=96
+KEY=50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576
+PT=515053524645444BD0D1D6D7340B0A09
+CT=1B06D6C5D333E742730130CF78E719B4
+
+I=97
+KEY=78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E
+PT=42434041ECEFEE1193929594C6C9C8CB
+CT=F1F848824C32E9DCDCBF21580F069329
+
+I=98
+KEY=A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6
+PT=EFEEEDECC2C1C0CF76777071455A5B58
+CT=1A09050CBD684F784D8E965E0782F28A
+
+I=99
+KEY=C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE
+PT=5F5E5D5C3F3C3D221D1C1B1A19161714
+CT=79C2969E7DED2BA7D088F3F320692360
+
+I=100
+KEY=F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516
+PT=000102034142434C1C1D1A1B8D727371
+CT=091A658A2F7444C16ACCB669450C7B63
+
+I=101
+KEY=18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E
+PT=8E8F8C8DB1B2B38C56575051050A0B08
+CT=97C1E3A72CCA65FA977D5ED0E8A7BBFC
+
+I=102
+KEY=40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566
+PT=A7A6A5A4E8EBEAE57F7E7978CAD5D4D7
+CT=70C430C6DB9A17828937305A2DF91A2A
+
+I=103
+KEY=68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E
+PT=8A8B888994979689454443429F909192
+CT=629553457FBE2479098571C7C903FDE8
+
+I=104
+KEY=90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6
+PT=8C8D8E8FE0E3E2ED45444342F1CECFCC
+CT=A25B25A61F612669E7D91265C7D476BA
+
+I=105
+KEY=B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE
+PT=FFFEFDFC4C4F4E31D8D9DEDFB6B9B8BB
+CT=EB7E4E49B8AE0F024570DDA293254FED
+
+I=106
+KEY=E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506
+PT=FDFCFFFECCCFCEC12F2E29286679787B
+CT=38FE15D61CCA84516E924ADCE5014F67
+
+I=107
+KEY=08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E
+PT=67666564BAB9B8A77071767719161714
+CT=3AD208492249108C9F3EBEB167AD0583
+
+I=108
+KEY=30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556
+PT=9A9B98992D2E2F2084858283245B5A59
+CT=299BA9F9BF5AB05C3580FC26EDD1ED12
+
+I=109
+KEY=58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E
+PT=A4A5A6A70B0809365C5D5A5B2C232221
+CT=19DC705B857A60FB07717B2EA5717781
+
+I=110
+KEY=80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6
+PT=464744455754555AF3F2F5F4AFB0B1B2
+CT=FFC8AEB885B5EFCAD06B6DBEBF92E76B
+
+I=111
+KEY=A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE
+PT=323330317675746B7273747549464744
+CT=F58900C5E0B385253FF2546250A0142B
+
+I=112
+KEY=D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6
+PT=A8A9AAAB181B1A15808186872B141516
+CT=2EE67B56280BC462429CEE6E3370CBC1
+
+I=113
+KEY=F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E
+PT=E7E6E5E4202323DDAAABACAD343B3A39
+CT=20DB650A9C8E9A84AB4D25F7EDC8F03F
+
+I=114
+KEY=20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546
+PT=A8A9AAAB2221202FEDECEBEA1E010003
+CT=3C36DA169525CF818843805F25B78AE5
+
+I=115
+KEY=48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E
+PT=F9F8FBFA5F5C5D42424344450E010003
+CT=9A781D960DB9E45E37779042FEA51922
+
+I=116
+KEY=70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596
+PT=57565554F5F6F7F89697909120DFDEDD
+CT=6560395EC269C672A3C288226EFDBA77
+
+I=117
+KEY=98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE
+PT=F8F9FAFBCCCFCEF1DDDCDBDA0E010003
+CT=8C772B7A189AC544453D5916EBB27B9A
+
+I=118
+KEY=C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6
+PT=D9D8DBDA7073727D80818687C2DDDCDF
+CT=77CA5468CC48E843D05F78EED9D6578F
+
+I=119
+KEY=E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E
+PT=C5C4C7C6080B0A1588898E8F68676665
+CT=72CDCC71DC82C60D4429C9E2D8195BAA
+
+I=120
+KEY=10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536
+PT=83828180DCDFDED186878081F0CFCECD
+CT=8080D68CE60E94B40B5B8B69EEB35AFA
+
+I=121
+KEY=38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E
+PT=98999A9BDDDEDFA079787F7E0A050407
+CT=44222D3CDE299C04369D58AC0EBA1E8E
+
+I=122
+KEY=60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586
+PT=CECFCCCD4F4C4D429F9E9998DFC0C1C2
+CT=9B8721B0A8DFC691C5BC5885DBFCB27A
+
+I=123
+KEY=88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE
+PT=404142436665647B29282F2EABA4A5A6
+CT=0DC015CE9A3A3414B5E62EC643384183
+
+I=124
+KEY=B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6
+PT=33323130E6E5E4EB23222524DEA1A0A3
+CT=705715448A8DA412025CE38345C2A148
+
+I=125
+KEY=D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE
+PT=CFCECDCCF6F5F4CBE6E7E0E199969794
+CT=C32B5B0B6FBAE165266C569F4B6ECF0B
+
+I=126
+KEY=00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526
+PT=BABBB8B97271707FDCDDDADB29363734
+CT=4DCA6C75192A01DDCA9476AF2A521E87
+
+I=127
+KEY=28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E
+PT=C9C8CBCA4447465926272021545B5A59
+CT=058691E627ECBC36AC07B6DB423BD698
+
+I=128
+KEY=50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576
+PT=050407067477767956575051221D1C1F
+CT=7444527095838FE080FC2BCDD30847EB
+
+==========
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/test/ecb_vk.txt b/mechglue/src/lib/crypto/aes/test/ecb_vk.txt
new file mode 100644
index 000000000..5dfd60089
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/ecb_vk.txt
@@ -0,0 +1,2334 @@
+
+=========================
+
+FILENAME:  "ecb_vk.txt"
+
+Electronic Codebook (ECB) Mode
+Variable Key Known Answer Tests
+
+Algorithm Name: Rijndael
+Principal Submitter: Joan Daemen
+
+==========
+
+KEYSIZE=128
+
+PT=00000000000000000000000000000000
+
+I=1
+KEY=80000000000000000000000000000000
+CT=0EDD33D3C621E546455BD8BA1418BEC8
+
+I=2
+KEY=40000000000000000000000000000000
+CT=C0CC0C5DA5BD63ACD44A80774FAD5222
+
+I=3
+KEY=20000000000000000000000000000000
+CT=2F0B4B71BC77851B9CA56D42EB8FF080
+
+I=4
+KEY=10000000000000000000000000000000
+CT=6B1E2FFFE8A114009D8FE22F6DB5F876
+
+I=5
+KEY=08000000000000000000000000000000
+CT=9AA042C315F94CBB97B62202F83358F5
+
+I=6
+KEY=04000000000000000000000000000000
+CT=DBE01DE67E346A800C4C4B4880311DE4
+
+I=7
+KEY=02000000000000000000000000000000
+CT=C117D2238D53836ACD92DDCDB85D6A21
+
+I=8
+KEY=01000000000000000000000000000000
+CT=DC0ED85DF9611ABB7249CDD168C5467E
+
+I=9
+KEY=00800000000000000000000000000000
+CT=807D678FFF1F56FA92DE3381904842F2
+
+I=10
+KEY=00400000000000000000000000000000
+CT=0E53B3FCAD8E4B130EF73AEB957FB402
+
+I=11
+KEY=00200000000000000000000000000000
+CT=969FFD3B7C35439417E7BDE923035D65
+
+I=12
+KEY=00100000000000000000000000000000
+CT=A99B512C19CA56070491166A1503BF15
+
+I=13
+KEY=00080000000000000000000000000000
+CT=6E9985252126EE344D26AE369D2327E3
+
+I=14
+KEY=00040000000000000000000000000000
+CT=B85F4809F904C275491FCDCD1610387E
+
+I=15
+KEY=00020000000000000000000000000000
+CT=ED365B8D7D20C1F5D53FB94DD211DF7B
+
+I=16
+KEY=00010000000000000000000000000000
+CT=B3A575E86A8DB4A7135D604C43304896
+
+I=17
+KEY=00008000000000000000000000000000
+CT=89704BCB8E69F846259EB0ACCBC7F8A2
+
+I=18
+KEY=00004000000000000000000000000000
+CT=C56EE7C92197861F10D7A92B90882055
+
+I=19
+KEY=00002000000000000000000000000000
+CT=92F296F6846E0EAF9422A5A24A08B069
+
+I=20
+KEY=00001000000000000000000000000000
+CT=E67E32BB8F11DEB8699318BEE9E91A60
+
+I=21
+KEY=00000800000000000000000000000000
+CT=B08EEF85EAF626DD91B65C4C3A97D92B
+
+I=22
+KEY=00000400000000000000000000000000
+CT=661083A6ADDCE79BB4E0859AB5538013
+
+I=23
+KEY=00000200000000000000000000000000
+CT=55DFE2941E0EB10AFC0B333BD34DE1FE
+
+I=24
+KEY=00000100000000000000000000000000
+CT=6BFE5945E715C9662609770F8846087A
+
+I=25
+KEY=00000080000000000000000000000000
+CT=79848E9C30C2F8CDA8B325F7FED2B139
+
+I=26
+KEY=00000040000000000000000000000000
+CT=7A713A53B99FEF34AC04DEEF80965BD0
+
+I=27
+KEY=00000020000000000000000000000000
+CT=18144A2B46620D32C3C32CE52D49257F
+
+I=28
+KEY=00000010000000000000000000000000
+CT=872E827C70887C80749F7B8BB1847C7E
+
+I=29
+KEY=00000008000000000000000000000000
+CT=6B86C6A4FE6A60C59B1A3102F8DE49F3
+
+I=30
+KEY=00000004000000000000000000000000
+CT=9848BB3DFDF6F532F094679A4C231A20
+
+I=31
+KEY=00000002000000000000000000000000
+CT=925AD528E852E329B2091CD3F1C2BCEE
+
+I=32
+KEY=00000001000000000000000000000000
+CT=80DF436544B0DD596722E46792A40CD8
+
+I=33
+KEY=00000000800000000000000000000000
+CT=525DAF18F93E83E1E74BBBDDE4263BBA
+
+I=34
+KEY=00000000400000000000000000000000
+CT=F65C9D2EE485D24701FFA3313B9D5BE6
+
+I=35
+KEY=00000000200000000000000000000000
+CT=E4FC8D8BCA06425BDF94AFA40FCC14BA
+
+I=36
+KEY=00000000100000000000000000000000
+CT=A53F0A5CA1E4E6440BB975FF320DE6F8
+
+I=37
+KEY=00000000080000000000000000000000
+CT=D55313B9394080462E87E02899B553F0
+
+I=38
+KEY=00000000040000000000000000000000
+CT=34A71D761F71BCD344384C7F97D27906
+
+I=39
+KEY=00000000020000000000000000000000
+CT=233F3D819599612EBC89580245C996A8
+
+I=40
+KEY=00000000010000000000000000000000
+CT=B4F1374E5268DBCB676E447529E53F89
+
+I=41
+KEY=00000000008000000000000000000000
+CT=0816BD27861D2BA891D1044E39951E96
+
+I=42
+KEY=00000000004000000000000000000000
+CT=F3BE9EA3F10C73CA64FDE5DB13A951D1
+
+I=43
+KEY=00000000002000000000000000000000
+CT=2448086A8106FBD03048DDF857D3F1C8
+
+I=44
+KEY=00000000001000000000000000000000
+CT=670756E65BEC8B68F03D77CDCDCE7B91
+
+I=45
+KEY=00000000000800000000000000000000
+CT=EF968CF0D36FD6C6EFFD225F6FB44CA9
+
+I=46
+KEY=00000000000400000000000000000000
+CT=2E8767157922E3826DDCEC1B0CC1E105
+
+I=47
+KEY=00000000000200000000000000000000
+CT=78CE7EEC670E45A967BAB17E26A1AD36
+
+I=48
+KEY=00000000000100000000000000000000
+CT=3C5CEE825655F098F6E81A2F417DA3FB
+
+I=49
+KEY=00000000000080000000000000000000
+CT=67BFDB431DCE1292200BC6F5207ADB12
+
+I=50
+KEY=00000000000040000000000000000000
+CT=7540FD38E447C0779228548747843A6F
+
+I=51
+KEY=00000000000020000000000000000000
+CT=B85E513301F8A936EA9EC8A21A85B5E6
+
+I=52
+KEY=00000000000010000000000000000000
+CT=04C67DBF16C11427D507A455DE2C9BC5
+
+I=53
+KEY=00000000000008000000000000000000
+CT=03F75EB8959E55079CFFB4FF149A37B6
+
+I=54
+KEY=00000000000004000000000000000000
+CT=74550287F666C63BB9BC7838433434B0
+
+I=55
+KEY=00000000000002000000000000000000
+CT=7D537200195EBC3AEFD1EAAB1C385221
+
+I=56
+KEY=00000000000001000000000000000000
+CT=CE24E4D40C68A82B535CBD3C8E21652A
+
+I=57
+KEY=00000000000000800000000000000000
+CT=AB20072405AA8FC40265C6F1F3DC8BC0
+
+I=58
+KEY=00000000000000400000000000000000
+CT=6CFD2CF688F566B093F67B9B3839E80A
+
+I=59
+KEY=00000000000000200000000000000000
+CT=BD95977E6B7239D407A012C5544BF584
+
+I=60
+KEY=00000000000000100000000000000000
+CT=DF9C0130AC77E7C72C997F587B46DBE0
+
+I=61
+KEY=00000000000000080000000000000000
+CT=E7F1B82CADC53A648798945B34EFEFF2
+
+I=62
+KEY=00000000000000040000000000000000
+CT=932C6DBF69255CF13EDCDB72233ACEA3
+
+I=63
+KEY=00000000000000020000000000000000
+CT=5C76002BC7206560EFE550C80B8F12CC
+
+I=64
+KEY=00000000000000010000000000000000
+CT=F6B7BDD1CAEEBAB574683893C4475484
+
+I=65
+KEY=00000000000000008000000000000000
+CT=A920E37CC6DC6B31DA8C0169569F5034
+
+I=66
+KEY=00000000000000004000000000000000
+CT=919380ECD9C778BC513148B0C28D65FD
+
+I=67
+KEY=00000000000000002000000000000000
+CT=EE67308DD3F2D9E6C2170755E5784BE1
+
+I=68
+KEY=00000000000000001000000000000000
+CT=3CC73E53B85609023A05E149B223AE09
+
+I=69
+KEY=00000000000000000800000000000000
+CT=983E8AF7CF05EBB28D71EB841C9406E6
+
+I=70
+KEY=00000000000000000400000000000000
+CT=0F3099B2D31FA5299EE5BF43193287FC
+
+I=71
+KEY=00000000000000000200000000000000
+CT=B763D84F38C27FE6931DCEB6715D4DB6
+
+I=72
+KEY=00000000000000000100000000000000
+CT=5AE3C9B0E3CC29C0C61565CD01F8A248
+
+I=73
+KEY=00000000000000000080000000000000
+CT=F58083572CD90981958565D48D2DEE25
+
+I=74
+KEY=00000000000000000040000000000000
+CT=7E6255EEF8F70C0EF10337AAB1CCCEF8
+
+I=75
+KEY=00000000000000000020000000000000
+CT=AAD4BAC34DB22821841CE2F631961902
+
+I=76
+KEY=00000000000000000010000000000000
+CT=D7431C0409BB1441BA9C6858DC7D4E81
+
+I=77
+KEY=00000000000000000008000000000000
+CT=EF9298C65E339F6E801A59C626456993
+
+I=78
+KEY=00000000000000000004000000000000
+CT=53FE29F68FF541ABC3F0EF3350B72F7E
+
+I=79
+KEY=00000000000000000002000000000000
+CT=F6BBA5C10DB02529E2C2DA3FB582CC14
+
+I=80
+KEY=00000000000000000001000000000000
+CT=E4239AA37FC531A386DAD1126FC0E9CD
+
+I=81
+KEY=00000000000000000000800000000000
+CT=8F7758F857D15BBE7BFD0E416404C365
+
+I=82
+KEY=00000000000000000000400000000000
+CT=D273EB57C687BCD1B4EA7218A509E7B8
+
+I=83
+KEY=00000000000000000000200000000000
+CT=65D64F8D76E8B3423FA25C4EB58A210A
+
+I=84
+KEY=00000000000000000000100000000000
+CT=623D802B4EC450D66A16625702FCDBE0
+
+I=85
+KEY=00000000000000000000080000000000
+CT=7496460CB28E5791BAEAF9B68FB00022
+
+I=86
+KEY=00000000000000000000040000000000
+CT=34EA600F18BB0694B41681A49D510C1D
+
+I=87
+KEY=00000000000000000000020000000000
+CT=5F8FF0D47D5766D29B5D6E8F46423BD8
+
+I=88
+KEY=00000000000000000000010000000000
+CT=225F9286C5928BF09F84D3F93F541959
+
+I=89
+KEY=00000000000000000000008000000000
+CT=B21E90D25DF383416A5F072CEBEB1FFB
+
+I=90
+KEY=00000000000000000000004000000000
+CT=4AEFCDA089318125453EB9E8EB5E492E
+
+I=91
+KEY=00000000000000000000002000000000
+CT=4D3E75C6CD40EC4869BC85158591ADB8
+
+I=92
+KEY=00000000000000000000001000000000
+CT=63A8B904405436A1B99D7751866771B7
+
+I=93
+KEY=00000000000000000000000800000000
+CT=64F0DAAE47529199792EAE172BA53293
+
+I=94
+KEY=00000000000000000000000400000000
+CT=C3EEF84BEA18225D515A8C852A9047EE
+
+I=95
+KEY=00000000000000000000000200000000
+CT=A44AC422B47D47B81AF73B3E9AC9596E
+
+I=96
+KEY=00000000000000000000000100000000
+CT=D16E04A8FBC435094F8D53ADF25F5084
+
+I=97
+KEY=00000000000000000000000080000000
+CT=EF13DC34BAB03E124EEAD8B6BF44B532
+
+I=98
+KEY=00000000000000000000000040000000
+CT=D94799075C24DCC067AF0D392049250D
+
+I=99
+KEY=00000000000000000000000020000000
+CT=14F431771EDDCE4764C21A2254B5E3C8
+
+I=100
+KEY=00000000000000000000000010000000
+CT=7039329F36F2ED682B02991F28D64679
+
+I=101
+KEY=00000000000000000000000008000000
+CT=124EE24EDE5551639DB8B8B941F6141D
+
+I=102
+KEY=00000000000000000000000004000000
+CT=C2852879A34D5184E478EC918B993FEE
+
+I=103
+KEY=00000000000000000000000002000000
+CT=86A806A3525B93E432053C9AB5ABBEDF
+
+I=104
+KEY=00000000000000000000000001000000
+CT=C1609BF5A4F07E37C17A36366EC23ECC
+
+I=105
+KEY=00000000000000000000000000800000
+CT=7E81E7CB92159A51FFCEA331B1E8EA53
+
+I=106
+KEY=00000000000000000000000000400000
+CT=37A7BE002856C5A59A6E03EAFCE7729A
+
+I=107
+KEY=00000000000000000000000000200000
+CT=BDF98A5A4F91E890C9A1D1E5FAAB138F
+
+I=108
+KEY=00000000000000000000000000100000
+CT=4E96ACB66E051F2BC739CC3D3E34A26B
+
+I=109
+KEY=00000000000000000000000000080000
+CT=EE996CDD120EB86E21ECFA49E8E1FCF1
+
+I=110
+KEY=00000000000000000000000000040000
+CT=61B9E6B579DBF6070C351A1440DD85FF
+
+I=111
+KEY=00000000000000000000000000020000
+CT=AC369E484316440B40DFC83AA96E28E7
+
+I=112
+KEY=00000000000000000000000000010000
+CT=0A2D16DE985C76D45C579C1159413BBE
+
+I=113
+KEY=00000000000000000000000000008000
+CT=DA3FDC38DA1D374FA4802CDA1A1C6B0F
+
+I=114
+KEY=00000000000000000000000000004000
+CT=B842523D4C41C2211AFE43A5800ADCE3
+
+I=115
+KEY=00000000000000000000000000002000
+CT=9E2CDA90D8E992DBA6C73D8229567192
+
+I=116
+KEY=00000000000000000000000000001000
+CT=D49583B781D9E20F5BE101415957FC49
+
+I=117
+KEY=00000000000000000000000000000800
+CT=EF09DA5C12B376E458B9B8670032498E
+
+I=118
+KEY=00000000000000000000000000000400
+CT=A96BE0463DA774461A5E1D5A9DD1AC10
+
+I=119
+KEY=00000000000000000000000000000200
+CT=32CEE3341060790D2D4B1362EF397090
+
+I=120
+KEY=00000000000000000000000000000100
+CT=21CEA416A3D3359D2C4D58FB6A035F06
+
+I=121
+KEY=00000000000000000000000000000080
+CT=172AEAB3D507678ECAF455C12587ADB7
+
+I=122
+KEY=00000000000000000000000000000040
+CT=B6F897941EF8EBFF9FE80A567EF38478
+
+I=123
+KEY=00000000000000000000000000000020
+CT=A9723259D94A7DC662FB0C782CA3F1DD
+
+I=124
+KEY=00000000000000000000000000000010
+CT=2F91C984B9A4839F30001B9F430493B4
+
+I=125
+KEY=00000000000000000000000000000008
+CT=0472406345A610B048CB99EE0EF3FA0F
+
+I=126
+KEY=00000000000000000000000000000004
+CT=F5F39086646F8C05ED16EFA4B617957C
+
+I=127
+KEY=00000000000000000000000000000002
+CT=26D50F485A30408D5AF47A5736292450
+
+I=128
+KEY=00000000000000000000000000000001
+CT=0545AAD56DA2A97C3663D1432A3D1C84
+
+==========
+
+KEYSIZE=192
+
+PT=00000000000000000000000000000000
+
+I=1
+KEY=800000000000000000000000000000000000000000000000
+CT=DE885DC87F5A92594082D02CC1E1B42C
+
+I=2
+KEY=400000000000000000000000000000000000000000000000
+CT=C749194F94673F9DD2AA1932849630C1
+
+I=3
+KEY=200000000000000000000000000000000000000000000000
+CT=0CEF643313912934D310297B90F56ECC
+
+I=4
+KEY=100000000000000000000000000000000000000000000000
+CT=C4495D39D4A553B225FBA02A7B1B87E1
+
+I=5
+KEY=080000000000000000000000000000000000000000000000
+CT=636D10B1A0BCAB541D680A7970ADC830
+
+I=6
+KEY=040000000000000000000000000000000000000000000000
+CT=07CF045786BD6AFCC147D99E45A901A7
+
+I=7
+KEY=020000000000000000000000000000000000000000000000
+CT=6A8E3F425A7599348F95398448827976
+
+I=8
+KEY=010000000000000000000000000000000000000000000000
+CT=5518276836148A00D91089A20D8BFF57
+
+I=9
+KEY=008000000000000000000000000000000000000000000000
+CT=F267E07B5E87E3BC20B969C61D4FCB06
+
+I=10
+KEY=004000000000000000000000000000000000000000000000
+CT=5A1CDE69571D401BFCD20DEBADA2212C
+
+I=11
+KEY=002000000000000000000000000000000000000000000000
+CT=70A9057263254701D12ADD7D74CD509E
+
+I=12
+KEY=001000000000000000000000000000000000000000000000
+CT=35713A7E108031279388A33A0FE2E190
+
+I=13
+KEY=000800000000000000000000000000000000000000000000
+CT=E74EDE82B1254714F0C7B4B243108655
+
+I=14
+KEY=000400000000000000000000000000000000000000000000
+CT=39272E3100FAA37B55B862320D1B3EB3
+
+I=15
+KEY=000200000000000000000000000000000000000000000000
+CT=6D6E24C659FC5AEF712F77BCA19C9DD0
+
+I=16
+KEY=000100000000000000000000000000000000000000000000
+CT=76D18212F972370D3CC2C6C372C6CF2F
+
+I=17
+KEY=000080000000000000000000000000000000000000000000
+CT=B21A1F0BAE39E55C7594ED570A7783EA
+
+I=18
+KEY=000040000000000000000000000000000000000000000000
+CT=77DE202111895AC48DD1C974B358B458
+
+I=19
+KEY=000020000000000000000000000000000000000000000000
+CT=67810B311969012AAF7B504FFAF39FD1
+
+I=20
+KEY=000010000000000000000000000000000000000000000000
+CT=C22EA2344D3E9417A6BA07843E713AEA
+
+I=21
+KEY=000008000000000000000000000000000000000000000000
+CT=C79CAF4B97BEE0BD0630AB354539D653
+
+I=22
+KEY=000004000000000000000000000000000000000000000000
+CT=135FD1AF761D9AE23DF4AA6B86760DB4
+
+I=23
+KEY=000002000000000000000000000000000000000000000000
+CT=D4659D0B06ACD4D56AB8D11A16FD83B9
+
+I=24
+KEY=000001000000000000000000000000000000000000000000
+CT=F7D270028FC188E4E4F35A4AAA25D4D4
+
+I=25
+KEY=000000800000000000000000000000000000000000000000
+CT=345CAE5A8C9620A9913D5473985852FF
+
+I=26
+KEY=000000400000000000000000000000000000000000000000
+CT=4E8980ADDE60B0E42C0B287FEA41E729
+
+I=27
+KEY=000000200000000000000000000000000000000000000000
+CT=F11B6D74E1F15155633DC39743C1A527
+
+I=28
+KEY=000000100000000000000000000000000000000000000000
+CT=9C87916C0180064F9D3179C6F5DD8C35
+
+I=29
+KEY=000000080000000000000000000000000000000000000000
+CT=71AB186BCAEA518E461D4F7FAD230E6A
+
+I=30
+KEY=000000040000000000000000000000000000000000000000
+CT=C4A31BBC3DAAF742F9141C2A5001A49C
+
+I=31
+KEY=000000020000000000000000000000000000000000000000
+CT=E7C47B7B1D40F182A8928C8A55671D07
+
+I=32
+KEY=000000010000000000000000000000000000000000000000
+CT=8E17F294B28FA373C6249538868A7EEF
+
+I=33
+KEY=000000008000000000000000000000000000000000000000
+CT=754404096A5CBC08AF09491BE249141A
+
+I=34
+KEY=000000004000000000000000000000000000000000000000
+CT=101CB56E55F05D86369B6D1069204F0A
+
+I=35
+KEY=000000002000000000000000000000000000000000000000
+CT=73F19BB6604205C6EE227B9759791E41
+
+I=36
+KEY=000000001000000000000000000000000000000000000000
+CT=6270C0028F0D136C37A56B2CB64D24D6
+
+I=37
+KEY=000000000800000000000000000000000000000000000000
+CT=A3BF7C2C38D1114A087ECF212E694346
+
+I=38
+KEY=000000000400000000000000000000000000000000000000
+CT=49CABFF2CEF7D9F95F5EFB1F7A1A7DDE
+
+I=39
+KEY=000000000200000000000000000000000000000000000000
+CT=EC7F8A47CC59B849469255AD49F62752
+
+I=40
+KEY=000000000100000000000000000000000000000000000000
+CT=68FAE55A13EFAF9B07B3552A8A0DC9D1
+
+I=41
+KEY=000000000080000000000000000000000000000000000000
+CT=211E6B19C69FAEF481F64F24099CDA65
+
+I=42
+KEY=000000000040000000000000000000000000000000000000
+CT=DBB918C75BC5732416F79FB0C8EE4C5C
+
+I=43
+KEY=000000000020000000000000000000000000000000000000
+CT=98D494E5D963A6C8B92536D3EC35E3FD
+
+I=44
+KEY=000000000010000000000000000000000000000000000000
+CT=C9A873404D403D6F074190851D67781A
+
+I=45
+KEY=000000000008000000000000000000000000000000000000
+CT=073AEF4A7C77D921928CB0DD9D27CAE7
+
+I=46
+KEY=000000000004000000000000000000000000000000000000
+CT=89BDE25CEE36FDE769A10E52298CF90F
+
+I=47
+KEY=000000000002000000000000000000000000000000000000
+CT=26D0842D37EAD38557C65E0A5E5F122E
+
+I=48
+KEY=000000000001000000000000000000000000000000000000
+CT=F8294BA375AF46B3F22905BBAFFAB107
+
+I=49
+KEY=000000000000800000000000000000000000000000000000
+CT=2AD63EB4D0D43813B979CF72B35BDB94
+
+I=50
+KEY=000000000000400000000000000000000000000000000000
+CT=7710C171EE0F4EFA39BE4C995180181D
+
+I=51
+KEY=000000000000200000000000000000000000000000000000
+CT=C0CB2B40DBA7BE8C0698FAE1E4B80FF8
+
+I=52
+KEY=000000000000100000000000000000000000000000000000
+CT=97970E505194622FD955CA1B80B784E9
+
+I=53
+KEY=000000000000080000000000000000000000000000000000
+CT=7CB1824B29F850900DF2CAD9CF04C1CF
+
+I=54
+KEY=000000000000040000000000000000000000000000000000
+CT=FDF4F036BB988E42F2F62DE63FE19A64
+
+I=55
+KEY=000000000000020000000000000000000000000000000000
+CT=08908CFE2C82606B2C15DF61B75CF3E2
+
+I=56
+KEY=000000000000010000000000000000000000000000000000
+CT=B3AA689EF2D07FF365ACB9ADBA2AF07A
+
+I=57
+KEY=000000000000008000000000000000000000000000000000
+CT=F2672CD8EAA3B98776660D0263656F5C
+
+I=58
+KEY=000000000000004000000000000000000000000000000000
+CT=5BDEAC00E986687B9E1D94A0DA7BF452
+
+I=59
+KEY=000000000000002000000000000000000000000000000000
+CT=E6D57BD66EA1627363EE0C4B711B0B21
+
+I=60
+KEY=000000000000001000000000000000000000000000000000
+CT=03730DD6ACB4AD9996A63BE7765EC06F
+
+I=61
+KEY=000000000000000800000000000000000000000000000000
+CT=A470E361AA5437B2BE8586D2F78DE582
+
+I=62
+KEY=000000000000000400000000000000000000000000000000
+CT=7567FEEFA559911FD479670246B484E3
+
+I=63
+KEY=000000000000000200000000000000000000000000000000
+CT=29829DEA15A4E7A4C049045E7B106E29
+
+I=64
+KEY=000000000000000100000000000000000000000000000000
+CT=A407834C3D89D48A2CB7A152208FA4ED
+
+I=65
+KEY=000000000000000080000000000000000000000000000000
+CT=68F948053F78FEF0D8F9FE7EF3A89819
+
+I=66
+KEY=000000000000000040000000000000000000000000000000
+CT=B605174CAB13AD8FE3B20DA3AE7B0234
+
+I=67
+KEY=000000000000000020000000000000000000000000000000
+CT=CCAB8F0AEBFF032893996D383CBFDBFA
+
+I=68
+KEY=000000000000000010000000000000000000000000000000
+CT=AF14BB8428C9730B7DC17B6C1CBEBCC8
+
+I=69
+KEY=000000000000000008000000000000000000000000000000
+CT=5A41A21332040877EB7B89E8E80D19FE
+
+I=70
+KEY=000000000000000004000000000000000000000000000000
+CT=AC1BA52EFCDDE368B1596F2F0AD893A0
+
+I=71
+KEY=000000000000000002000000000000000000000000000000
+CT=41B890E31B9045E6ECDC1BC3F2DB9BCC
+
+I=72
+KEY=000000000000000001000000000000000000000000000000
+CT=4D54A549728E55B19A23660424A0F146
+
+I=73
+KEY=000000000000000000800000000000000000000000000000
+CT=A917581F41C47C7DDCFFD5285E2D6A61
+
+I=74
+KEY=000000000000000000400000000000000000000000000000
+CT=604DF24BA6099B93A7405A524D764FCB
+
+I=75
+KEY=000000000000000000200000000000000000000000000000
+CT=78D9D156F28B190E232D1B7AE7FC730A
+
+I=76
+KEY=000000000000000000100000000000000000000000000000
+CT=5A12C39E442CD7F27B3CD77F5D029582
+
+I=77
+KEY=000000000000000000080000000000000000000000000000
+CT=FF2BF2F47CF7B0F28EE25AF95DBF790D
+
+I=78
+KEY=000000000000000000040000000000000000000000000000
+CT=1863BB7D193BDA39DF090659EB8AE48B
+
+I=79
+KEY=000000000000000000020000000000000000000000000000
+CT=38178F2FB4CFCF31E87E1ABCDC023EB5
+
+I=80
+KEY=000000000000000000010000000000000000000000000000
+CT=F5B13DC690CC0D541C6BA533023DC8C9
+
+I=81
+KEY=000000000000000000008000000000000000000000000000
+CT=48EC05238D7375D126DC9D08884D4827
+
+I=82
+KEY=000000000000000000004000000000000000000000000000
+CT=ACD0D81139691B310B92A6E377BACC87
+
+I=83
+KEY=000000000000000000002000000000000000000000000000
+CT=9A4AA43578B55CE9CC178F0D2E162C79
+
+I=84
+KEY=000000000000000000001000000000000000000000000000
+CT=08AD94BC737DB3C87D49B9E01B720D81
+
+I=85
+KEY=000000000000000000000800000000000000000000000000
+CT=3BCFB2D5D210E8332900C5991D551A2A
+
+I=86
+KEY=000000000000000000000400000000000000000000000000
+CT=C5F0C6B9397ACB29635CE1A0DA2D8D96
+
+I=87
+KEY=000000000000000000000200000000000000000000000000
+CT=844A29EFC693E2FA9900F87FBF5DCD5F
+
+I=88
+KEY=000000000000000000000100000000000000000000000000
+CT=5126A1C41051FEA158BE41200E1EA59D
+
+I=89
+KEY=000000000000000000000080000000000000000000000000
+CT=302123CA7B4F46D667FFFB0EB6AA7703
+
+I=90
+KEY=000000000000000000000040000000000000000000000000
+CT=A9D16BCE7DB5C024277709EE2A88D91A
+
+I=91
+KEY=000000000000000000000020000000000000000000000000
+CT=F013C5EC123A26CFC34B598C992A996B
+
+I=92
+KEY=000000000000000000000010000000000000000000000000
+CT=E38A825CD971A1D2E56FB1DBA248F2A8
+
+I=93
+KEY=000000000000000000000008000000000000000000000000
+CT=6E701773C0311E0BD4C5A097406D22B3
+
+I=94
+KEY=000000000000000000000004000000000000000000000000
+CT=754262CEF0C64BE4C3E67C35ABE439F7
+
+I=95
+KEY=000000000000000000000002000000000000000000000000
+CT=C9C2D4C47DF7D55CFA0EE5F1FE5070F4
+
+I=96
+KEY=000000000000000000000001000000000000000000000000
+CT=6AB4BEA85B172573D8BD2D5F4329F13D
+
+I=97
+KEY=000000000000000000000000800000000000000000000000
+CT=11F03EF28E2CC9AE5165C587F7396C8C
+
+I=98
+KEY=000000000000000000000000400000000000000000000000
+CT=0682F2EB1A68BAC7949922C630DD27FA
+
+I=99
+KEY=000000000000000000000000200000000000000000000000
+CT=ABB0FEC0413D659AFE8E3DCF6BA873BB
+
+I=100
+KEY=000000000000000000000000100000000000000000000000
+CT=FE86A32E19F805D6569B2EFADD9C92AA
+
+I=101
+KEY=000000000000000000000000080000000000000000000000
+CT=E434E472275D1837D3D717F2EECC88C3
+
+I=102
+KEY=000000000000000000000000040000000000000000000000
+CT=74E57DCD12A21D26EF8ADAFA5E60469A
+
+I=103
+KEY=000000000000000000000000020000000000000000000000
+CT=C275429D6DAD45DDD423FA63C816A9C1
+
+I=104
+KEY=000000000000000000000000010000000000000000000000
+CT=7F6EC1A9AE729E86F7744AED4B8F4F07
+
+I=105
+KEY=000000000000000000000000008000000000000000000000
+CT=48B5A71AB9292BD4F9E608EF102636B2
+
+I=106
+KEY=000000000000000000000000004000000000000000000000
+CT=076FB95D5F536C78CBED3181BCCF3CF1
+
+I=107
+KEY=000000000000000000000000002000000000000000000000
+CT=BFA76BEA1E684FD3BF9256119EE0BC0F
+
+I=108
+KEY=000000000000000000000000001000000000000000000000
+CT=7D395923D56577F3FF8670998F8C4A71
+
+I=109
+KEY=000000000000000000000000000800000000000000000000
+CT=BA02C986E529AC18A882C34BA389625F
+
+I=110
+KEY=000000000000000000000000000400000000000000000000
+CT=3DFCF2D882AFE75D3A191193013A84B5
+
+I=111
+KEY=000000000000000000000000000200000000000000000000
+CT=FAD1FDE1D0241784B63080D2C74D236C
+
+I=112
+KEY=000000000000000000000000000100000000000000000000
+CT=7D6C80D39E41F007A14FB9CD2B2C15CD
+
+I=113
+KEY=000000000000000000000000000080000000000000000000
+CT=7975F401FC10637BB33EA2DB058FF6EC
+
+I=114
+KEY=000000000000000000000000000040000000000000000000
+CT=657983865C55A818F02B7FCD52ED7E99
+
+I=115
+KEY=000000000000000000000000000020000000000000000000
+CT=B32BEB1776F9827FF4C3AC9997E84B20
+
+I=116
+KEY=000000000000000000000000000010000000000000000000
+CT=2AE2C7C374F0A41E3D46DBC3E66BB59F
+
+I=117
+KEY=000000000000000000000000000008000000000000000000
+CT=4D835E4ABDD4BDC6B88316A6E931A07F
+
+I=118
+KEY=000000000000000000000000000004000000000000000000
+CT=E07EFABFF1C353F7384EBB87B435A3F3
+
+I=119
+KEY=000000000000000000000000000002000000000000000000
+CT=ED3088DC3FAF89AD87B4356FF1BB09C2
+
+I=120
+KEY=000000000000000000000000000001000000000000000000
+CT=4324D01140C156FC898C2E32BA03FB05
+
+I=121
+KEY=000000000000000000000000000000800000000000000000
+CT=BE15D016FACB5BAFBC24FA9289132166
+
+I=122
+KEY=000000000000000000000000000000400000000000000000
+CT=AC9B7048EDB1ACF4D97A5B0B3F50884B
+
+I=123
+KEY=000000000000000000000000000000200000000000000000
+CT=448BECE1F86C7845DFA9A4BB2A016FB3
+
+I=124
+KEY=000000000000000000000000000000100000000000000000
+CT=10DD445E87686EB46EA9B1ABC49257F0
+
+I=125
+KEY=000000000000000000000000000000080000000000000000
+CT=B7FCCF7659FA756D4B7303EEA6C07458
+
+I=126
+KEY=000000000000000000000000000000040000000000000000
+CT=289117115CA3513BAA7640B1004872C2
+
+I=127
+KEY=000000000000000000000000000000020000000000000000
+CT=57CB42F7EE7186051F50B93FFA7B35BF
+
+I=128
+KEY=000000000000000000000000000000010000000000000000
+CT=F2741BFBFB81663B9136802FB9C3126A
+
+I=129
+KEY=000000000000000000000000000000008000000000000000
+CT=E32DDDC5C7398C096E3BD535B31DB5CE
+
+I=130
+KEY=000000000000000000000000000000004000000000000000
+CT=81D3C204E608AF9CC713EAEBCB72433F
+
+I=131
+KEY=000000000000000000000000000000002000000000000000
+CT=D4DEEF4BFC36AAA579496E6935F8F98E
+
+I=132
+KEY=000000000000000000000000000000001000000000000000
+CT=C356DB082B97802B038571C392C5C8F6
+
+I=133
+KEY=000000000000000000000000000000000800000000000000
+CT=A3919ECD4861845F2527B77F06AC6A4E
+
+I=134
+KEY=000000000000000000000000000000000400000000000000
+CT=A53858E17A2F802A20E40D44494FFDA0
+
+I=135
+KEY=000000000000000000000000000000000200000000000000
+CT=5D989E122B78C758921EDBEEB827F0C0
+
+I=136
+KEY=000000000000000000000000000000000100000000000000
+CT=4B1C0C8F9E7830CC3C4BE7BD226FA8DE
+
+I=137
+KEY=000000000000000000000000000000000080000000000000
+CT=82C40C5FD897FBCA7B899C70713573A1
+
+I=138
+KEY=000000000000000000000000000000000040000000000000
+CT=ED13EE2D45E00F75CCDB51EA8E3E36AD
+
+I=139
+KEY=000000000000000000000000000000000020000000000000
+CT=F121799EEFE8432423176A3CCF6462BB
+
+I=140
+KEY=000000000000000000000000000000000010000000000000
+CT=4FA0C06F07997E98271DD86F7B355C50
+
+I=141
+KEY=000000000000000000000000000000000008000000000000
+CT=849EB364B4E81D058649DC5B1BF029B9
+
+I=142
+KEY=000000000000000000000000000000000004000000000000
+CT=F48F9E0DE8DE7AD944A207809335D9B1
+
+I=143
+KEY=000000000000000000000000000000000002000000000000
+CT=E59E9205B5A81A4FD26DFCF308966022
+
+I=144
+KEY=000000000000000000000000000000000001000000000000
+CT=3A91A1BE14AAE9ED700BDF9D70018804
+
+I=145
+KEY=000000000000000000000000000000000000800000000000
+CT=8ABAD78DCB79A48D79070E7DA89664EC
+
+I=146
+KEY=000000000000000000000000000000000000400000000000
+CT=B68377D98AAE6044938A7457F6C649D9
+
+I=147
+KEY=000000000000000000000000000000000000200000000000
+CT=E4E1275C42F5F1B63D662C099D6CE33D
+
+I=148
+KEY=000000000000000000000000000000000000100000000000
+CT=7DEF32A34C6BE668F17DA1BB193B06EF
+
+I=149
+KEY=000000000000000000000000000000000000080000000000
+CT=78B6000CC3D30CB3A74B68D0EDBD2B53
+
+I=150
+KEY=000000000000000000000000000000000000040000000000
+CT=0A47531DE88DD8AE5C23EAE4F7D1F2D5
+
+I=151
+KEY=000000000000000000000000000000000000020000000000
+CT=667B24E8000CF68231EC484581D922E5
+
+I=152
+KEY=000000000000000000000000000000000000010000000000
+CT=39DAA5EBD4AACAE130E9C33236C52024
+
+I=153
+KEY=000000000000000000000000000000000000008000000000
+CT=E3C88760B3CB21360668A63E55BB45D1
+
+I=154
+KEY=000000000000000000000000000000000000004000000000
+CT=F131EE903C1CDB49D416866FD5D8DE51
+
+I=155
+KEY=000000000000000000000000000000000000002000000000
+CT=7A1916135B0447CF4033FC13047A583A
+
+I=156
+KEY=000000000000000000000000000000000000001000000000
+CT=F7D55FB27991143DCDFA90DDF0424FCB
+
+I=157
+KEY=000000000000000000000000000000000000000800000000
+CT=EA93E7D1CA1111DBD8F7EC111A848C0C
+
+I=158
+KEY=000000000000000000000000000000000000000400000000
+CT=2A689E39DFD3CBCBE221326E95888779
+
+I=159
+KEY=000000000000000000000000000000000000000200000000
+CT=C1CE399CA762318AC2C40D1928B4C57D
+
+I=160
+KEY=000000000000000000000000000000000000000100000000
+CT=D43FB6F2B2879C8BFAF0092DA2CA63ED
+
+I=161
+KEY=000000000000000000000000000000000000000080000000
+CT=224563E617158DF97650AF5D130E78A5
+
+I=162
+KEY=000000000000000000000000000000000000000040000000
+CT=6562FDF6833B7C4F7484AE6EBCC243DD
+
+I=163
+KEY=000000000000000000000000000000000000000020000000
+CT=93D58BA7BED22615D661D002885A7457
+
+I=164
+KEY=000000000000000000000000000000000000000010000000
+CT=9A0EF559003AD9E52D3E09ED3C1D3320
+
+I=165
+KEY=000000000000000000000000000000000000000008000000
+CT=96BAF5A7DC6F3DD27EB4C717A85D261C
+
+I=166
+KEY=000000000000000000000000000000000000000004000000
+CT=B8762E06884900E8452293190E19CCDB
+
+I=167
+KEY=000000000000000000000000000000000000000002000000
+CT=785416A22BD63CBABF4B1789355197D3
+
+I=168
+KEY=000000000000000000000000000000000000000001000000
+CT=A0D20CE1489BAA69A3612DCE90F7ABF6
+
+I=169
+KEY=000000000000000000000000000000000000000000800000
+CT=700244E93DC94230CC607FFBA0E48F32
+
+I=170
+KEY=000000000000000000000000000000000000000000400000
+CT=85329E476829F872A2B4A7E59F91FF2D
+
+I=171
+KEY=000000000000000000000000000000000000000000200000
+CT=E4219B4935D988DB719B8B8B2B53D247
+
+I=172
+KEY=000000000000000000000000000000000000000000100000
+CT=6ACDD04FD13D4DB4409FE8DD13FD737B
+
+I=173
+KEY=000000000000000000000000000000000000000000080000
+CT=9EB7A670AB59E15BE582378701C1EC14
+
+I=174
+KEY=000000000000000000000000000000000000000000040000
+CT=29DF2D6935FE657763BC7A9F22D3D492
+
+I=175
+KEY=000000000000000000000000000000000000000000020000
+CT=99303359D4A13AFDBE6C784028CE533A
+
+I=176
+KEY=000000000000000000000000000000000000000000010000
+CT=FF5C70A6334545F33B9DBF7BEA0417CA
+
+I=177
+KEY=000000000000000000000000000000000000000000008000
+CT=289F58A17E4C50EDA4269EFB3DF55815
+
+I=178
+KEY=000000000000000000000000000000000000000000004000
+CT=EA35DCB416E9E1C2861D1682F062B5EB
+
+I=179
+KEY=000000000000000000000000000000000000000000002000
+CT=3A47BF354BE775383C50B0C0A83E3A58
+
+I=180
+KEY=000000000000000000000000000000000000000000001000
+CT=BF6C1DC069FB95D05D43B01D8206D66B
+
+I=181
+KEY=000000000000000000000000000000000000000000000800
+CT=046D1D580D5898DA6595F32FD1F0C33D
+
+I=182
+KEY=000000000000000000000000000000000000000000000400
+CT=5F57803B7B82A110F7E9855D6A546082
+
+I=183
+KEY=000000000000000000000000000000000000000000000200
+CT=25336ECF34E7BE97862CDFF715FF05A8
+
+I=184
+KEY=000000000000000000000000000000000000000000000100
+CT=ACBAA2A943D8078022D693890E8C4FEF
+
+I=185
+KEY=000000000000000000000000000000000000000000000080
+CT=3947597879F6B58E4E2F0DF825A83A38
+
+I=186
+KEY=000000000000000000000000000000000000000000000040
+CT=4EB8CC3335496130655BF3CA570A4FC0
+
+I=187
+KEY=000000000000000000000000000000000000000000000020
+CT=BBDA7769AD1FDA425E18332D97868824
+
+I=188
+KEY=000000000000000000000000000000000000000000000010
+CT=5E7532D22DDB0829A29C868198397154
+
+I=189
+KEY=000000000000000000000000000000000000000000000008
+CT=E66DA67B630AB7AE3E682855E1A1698E
+
+I=190
+KEY=000000000000000000000000000000000000000000000004
+CT=4D93800F671B48559A64D1EA030A590A
+
+I=191
+KEY=000000000000000000000000000000000000000000000002
+CT=F33159FCC7D9AE30C062CD3B322AC764
+
+I=192
+KEY=000000000000000000000000000000000000000000000001
+CT=8BAE4EFB70D33A9792EEA9BE70889D72
+
+==========
+
+KEYSIZE=256
+
+PT=00000000000000000000000000000000
+
+I=1
+KEY=8000000000000000000000000000000000000000000000000000000000000000
+CT=E35A6DCB19B201A01EBCFA8AA22B5759
+
+I=2
+KEY=4000000000000000000000000000000000000000000000000000000000000000
+CT=5075C2405B76F22F553488CAE47CE90B
+
+I=3
+KEY=2000000000000000000000000000000000000000000000000000000000000000
+CT=49DF95D844A0145A7DE01C91793302D3
+
+I=4
+KEY=1000000000000000000000000000000000000000000000000000000000000000
+CT=E7396D778E940B8418A86120E5F421FE
+
+I=5
+KEY=0800000000000000000000000000000000000000000000000000000000000000
+CT=05F535C36FCEDE4657BE37F4087DB1EF
+
+I=6
+KEY=0400000000000000000000000000000000000000000000000000000000000000
+CT=D0C1DDDD10DA777C68AB36AF51F2C204
+
+I=7
+KEY=0200000000000000000000000000000000000000000000000000000000000000
+CT=1C55FB811B5C6464C4E5DE1535A75514
+
+I=8
+KEY=0100000000000000000000000000000000000000000000000000000000000000
+CT=52917F3AE957D5230D3A2AF57C7B5A71
+
+I=9
+KEY=0080000000000000000000000000000000000000000000000000000000000000
+CT=C6E3D5501752DD5E9AEF086D6B45D705
+
+I=10
+KEY=0040000000000000000000000000000000000000000000000000000000000000
+CT=A24A9C7AF1D9B1E17E1C9A3E711B3FA7
+
+I=11
+KEY=0020000000000000000000000000000000000000000000000000000000000000
+CT=B881ECA724A6D43DBC6B96F6F59A0D20
+
+I=12
+KEY=0010000000000000000000000000000000000000000000000000000000000000
+CT=EC524D9A24DFFF2A9639879B83B8E137
+
+I=13
+KEY=0008000000000000000000000000000000000000000000000000000000000000
+CT=34C4F345F5466215A037F443635D6F75
+
+I=14
+KEY=0004000000000000000000000000000000000000000000000000000000000000
+CT=5BA5055BEDB8895F672E29F2EB5A355D
+
+I=15
+KEY=0002000000000000000000000000000000000000000000000000000000000000
+CT=B3F692AA3A435259EBBEF9B51AD1E08D
+
+I=16
+KEY=0001000000000000000000000000000000000000000000000000000000000000
+CT=414FEB4376F2C64A5D2FBB2ED531BA7D
+
+I=17
+KEY=0000800000000000000000000000000000000000000000000000000000000000
+CT=A20D519E3BCA3303F07E81719F61605E
+
+I=18
+KEY=0000400000000000000000000000000000000000000000000000000000000000
+CT=A08D10E520AF811F45BD60A2DC0DC4B1
+
+I=19
+KEY=0000200000000000000000000000000000000000000000000000000000000000
+CT=B06893A8C563C430E6F3858826EFBBE4
+
+I=20
+KEY=0000100000000000000000000000000000000000000000000000000000000000
+CT=0FFEE26AE2D3929C6BD9C6BEDFF84409
+
+I=21
+KEY=0000080000000000000000000000000000000000000000000000000000000000
+CT=4D0F5E906ED77801FC0EF53EDC5F9E2B
+
+I=22
+KEY=0000040000000000000000000000000000000000000000000000000000000000
+CT=8B6EC00119AD8B026DCE56EA7DEFE930
+
+I=23
+KEY=0000020000000000000000000000000000000000000000000000000000000000
+CT=69026591D43363EE9D83B5007F0B484E
+
+I=24
+KEY=0000010000000000000000000000000000000000000000000000000000000000
+CT=27135D86950C6A2F86872706279A4761
+
+I=25
+KEY=0000008000000000000000000000000000000000000000000000000000000000
+CT=35E6DB8723F281DA410C3AC8535ED77C
+
+I=26
+KEY=0000004000000000000000000000000000000000000000000000000000000000
+CT=57427CF214B8C28E4BBF487CCB8D0E09
+
+I=27
+KEY=0000002000000000000000000000000000000000000000000000000000000000
+CT=6DF01BF56E5131AC87F96E99CAB86367
+
+I=28
+KEY=0000001000000000000000000000000000000000000000000000000000000000
+CT=3856C5B55790B768BBF7D43031579BCF
+
+I=29
+KEY=0000000800000000000000000000000000000000000000000000000000000000
+CT=1E6ED8FB7C15BC4D2F63BA7037ED44D0
+
+I=30
+KEY=0000000400000000000000000000000000000000000000000000000000000000
+CT=E1B2ED6CD8D93D455534E401156D4BCF
+
+I=31
+KEY=0000000200000000000000000000000000000000000000000000000000000000
+CT=EFBCCA5BDFDAD10E875F02336212CE36
+
+I=32
+KEY=0000000100000000000000000000000000000000000000000000000000000000
+CT=0B777F02FD18DCE2646DCFE868DFAFAD
+
+I=33
+KEY=0000000080000000000000000000000000000000000000000000000000000000
+CT=C8A104B5693D1B14F5BF1F10100BF508
+
+I=34
+KEY=0000000040000000000000000000000000000000000000000000000000000000
+CT=4CCE6615244AFCB38408FECE219962EA
+
+I=35
+KEY=0000000020000000000000000000000000000000000000000000000000000000
+CT=F99E7845D3A255B394C9C050CBA258B1
+
+I=36
+KEY=0000000010000000000000000000000000000000000000000000000000000000
+CT=B4AFBB787F9BCFB7B55FDF447F611295
+
+I=37
+KEY=0000000008000000000000000000000000000000000000000000000000000000
+CT=AE1C426A697FAF2808B7EF6ADDB5C020
+
+I=38
+KEY=0000000004000000000000000000000000000000000000000000000000000000
+CT=7572F92811A85B9BDD38DEAD9945BCAE
+
+I=39
+KEY=0000000002000000000000000000000000000000000000000000000000000000
+CT=71BC7AA46E43FB95A181527D9F6A360F
+
+I=40
+KEY=0000000001000000000000000000000000000000000000000000000000000000
+CT=5542EF2923066F1EC8F546DD0D8E7CA8
+
+I=41
+KEY=0000000000800000000000000000000000000000000000000000000000000000
+CT=6B92317C7D623790B748FDD7EFC42422
+
+I=42
+KEY=0000000000400000000000000000000000000000000000000000000000000000
+CT=0FE7C097E899C71EF045360F8D6C25CF
+
+I=43
+KEY=0000000000200000000000000000000000000000000000000000000000000000
+CT=4ECE7EE107D0264D04693151C25B9DF6
+
+I=44
+KEY=0000000000100000000000000000000000000000000000000000000000000000
+CT=FD6AE687CBFCA9E301045888D3BB9605
+
+I=45
+KEY=0000000000080000000000000000000000000000000000000000000000000000
+CT=476B579C8556C7254424902CC1D6D36E
+
+I=46
+KEY=0000000000040000000000000000000000000000000000000000000000000000
+CT=4133CBCDFDD6B8860A1FC18665D6D71B
+
+I=47
+KEY=0000000000020000000000000000000000000000000000000000000000000000
+CT=3B36EC2664798C108B816812C65DFDC7
+
+I=48
+KEY=0000000000010000000000000000000000000000000000000000000000000000
+CT=364E20A234FEA385D48DC5A09C9E70CF
+
+I=49
+KEY=0000000000008000000000000000000000000000000000000000000000000000
+CT=4A4BA25969DE3F5EE5642C71AAD0EFD1
+
+I=50
+KEY=0000000000004000000000000000000000000000000000000000000000000000
+CT=E42CBAAE43297F67A76C1C501BB79E36
+
+I=51
+KEY=0000000000002000000000000000000000000000000000000000000000000000
+CT=23CEDEDA4C15B4C037E8C61492217937
+
+I=52
+KEY=0000000000001000000000000000000000000000000000000000000000000000
+CT=A1719147A1F4A1A1180BD16E8593DCDE
+
+I=53
+KEY=0000000000000800000000000000000000000000000000000000000000000000
+CT=AB82337E9FB0EC60D1F25A1D0014192C
+
+I=54
+KEY=0000000000000400000000000000000000000000000000000000000000000000
+CT=74BF2D8FC5A8388DF1A3A4D7D33FC164
+
+I=55
+KEY=0000000000000200000000000000000000000000000000000000000000000000
+CT=D5B493317E6FBC6FFFD664B3C491368A
+
+I=56
+KEY=0000000000000100000000000000000000000000000000000000000000000000
+CT=BA767381586DA56A2A8D503D5F7ADA0B
+
+I=57
+KEY=0000000000000080000000000000000000000000000000000000000000000000
+CT=E8E6BC57DFE9CCADB0DECABF4E5CF91F
+
+I=58
+KEY=0000000000000040000000000000000000000000000000000000000000000000
+CT=3C8E5A5CDC9CEED90815D1F84BB2998C
+
+I=59
+KEY=0000000000000020000000000000000000000000000000000000000000000000
+CT=283843020BA38F056001B2FD585F7CC9
+
+I=60
+KEY=0000000000000010000000000000000000000000000000000000000000000000
+CT=D8ADC7426F623ECE8741A70621D28870
+
+I=61
+KEY=0000000000000008000000000000000000000000000000000000000000000000
+CT=D7C5C215592D06F00E6A80DA69A28EA9
+
+I=62
+KEY=0000000000000004000000000000000000000000000000000000000000000000
+CT=52CF6FA433C3C870CAC70190358F7F16
+
+I=63
+KEY=0000000000000002000000000000000000000000000000000000000000000000
+CT=F63D442A584DA71786ADEC9F3346DF75
+
+I=64
+KEY=0000000000000001000000000000000000000000000000000000000000000000
+CT=549078F4B0CA7079B45F9A5ADAFAFD99
+
+I=65
+KEY=0000000000000000800000000000000000000000000000000000000000000000
+CT=F2A5986EE4E9984BE2BAFB79EA8152FA
+
+I=66
+KEY=0000000000000000400000000000000000000000000000000000000000000000
+CT=8A74535017B4DB2776668A1FAE64384C
+
+I=67
+KEY=0000000000000000200000000000000000000000000000000000000000000000
+CT=E613342F57A97FD95DC088711A5D0ECD
+
+I=68
+KEY=0000000000000000100000000000000000000000000000000000000000000000
+CT=3FFAEBF6B22CF1DC82AE17CD48175B01
+
+I=69
+KEY=0000000000000000080000000000000000000000000000000000000000000000
+CT=BAFD52EFA15C248CCBF9757735E6B1CE
+
+I=70
+KEY=0000000000000000040000000000000000000000000000000000000000000000
+CT=7AF94BC018D9DDD4539D2DD1C6F4000F
+
+I=71
+KEY=0000000000000000020000000000000000000000000000000000000000000000
+CT=FE177AD61CA0FDB281086FBA8FE76803
+
+I=72
+KEY=0000000000000000010000000000000000000000000000000000000000000000
+CT=74DBEA15E2E9285BAD163D7D534251B6
+
+I=73
+KEY=0000000000000000008000000000000000000000000000000000000000000000
+CT=23DD21331B3A92F200FE56FF050FFE74
+
+I=74
+KEY=0000000000000000004000000000000000000000000000000000000000000000
+CT=A69C5AA34AB20A858CAFA766EACED6D8
+
+I=75
+KEY=0000000000000000002000000000000000000000000000000000000000000000
+CT=3F72BB4DF2A4F941A4A09CB78F04B97A
+
+I=76
+KEY=0000000000000000001000000000000000000000000000000000000000000000
+CT=72CC43577E1FD5FD14622D24D97FCDCC
+
+I=77
+KEY=0000000000000000000800000000000000000000000000000000000000000000
+CT=D83AF8EBE93E0B6B99CAFADE224937D1
+
+I=78
+KEY=0000000000000000000400000000000000000000000000000000000000000000
+CT=44042329128D56CAA8D084C8BD769D1E
+
+I=79
+KEY=0000000000000000000200000000000000000000000000000000000000000000
+CT=14102D72290DE4F2C430ADD1ED64BA1D
+
+I=80
+KEY=0000000000000000000100000000000000000000000000000000000000000000
+CT=449124097B1ECD0AE7065206DF06F03C
+
+I=81
+KEY=0000000000000000000080000000000000000000000000000000000000000000
+CT=D060A99F8CC153A42E11E5F97BD7584A
+
+I=82
+KEY=0000000000000000000040000000000000000000000000000000000000000000
+CT=65605B3EA9261488D53E48602ADEA299
+
+I=83
+KEY=0000000000000000000020000000000000000000000000000000000000000000
+CT=C5E5CAD7A208DE8EA6BE049EFE5C7346
+
+I=84
+KEY=0000000000000000000010000000000000000000000000000000000000000000
+CT=4C280C46D2181646048DD5BC0C0831A5
+
+I=85
+KEY=0000000000000000000008000000000000000000000000000000000000000000
+CT=5DD65CF37F2A0929559AABAFDA08E730
+
+I=86
+KEY=0000000000000000000004000000000000000000000000000000000000000000
+CT=31F2335CAAF264172F69A693225E6D22
+
+I=87
+KEY=0000000000000000000002000000000000000000000000000000000000000000
+CT=3E28B35F99A72662590DA96426DD377F
+
+I=88
+KEY=0000000000000000000001000000000000000000000000000000000000000000
+CT=570F40F5D7B20441486578ED344343BE
+
+I=89
+KEY=0000000000000000000000800000000000000000000000000000000000000000
+CT=C54308AD1C9E3B19F8B7417873045A8C
+
+I=90
+KEY=0000000000000000000000400000000000000000000000000000000000000000
+CT=CBF335E39CE13ADE2B696179E8FD0CE1
+
+I=91
+KEY=0000000000000000000000200000000000000000000000000000000000000000
+CT=9C2FBF422355D8293083D51F4A3C18A9
+
+I=92
+KEY=0000000000000000000000100000000000000000000000000000000000000000
+CT=5ED8B5A31ECEFAB16C9AA6986DA67BCE
+
+I=93
+KEY=0000000000000000000000080000000000000000000000000000000000000000
+CT=627815DCFC814ABC75900041B1DD7B59
+
+I=94
+KEY=0000000000000000000000040000000000000000000000000000000000000000
+CT=9EF3E82A50A59F166260494F7A7F2CC3
+
+I=95
+KEY=0000000000000000000000020000000000000000000000000000000000000000
+CT=878CD0D8D920888B5935D6C351128737
+
+I=96
+KEY=0000000000000000000000010000000000000000000000000000000000000000
+CT=E44429474D6FC3084EB2A6B8B46AF754
+
+I=97
+KEY=0000000000000000000000008000000000000000000000000000000000000000
+CT=EBAACF9641D54E1FB18D0A2BE4F19BE5
+
+I=98
+KEY=0000000000000000000000004000000000000000000000000000000000000000
+CT=13B3BF497CEE780E123C7E193DEA3A01
+
+I=99
+KEY=0000000000000000000000002000000000000000000000000000000000000000
+CT=6E8F381DE00A41161F0DF03B4155BFD4
+
+I=100
+KEY=0000000000000000000000001000000000000000000000000000000000000000
+CT=35E4F29BBA2BAE01144910783C3FEF49
+
+I=101
+KEY=0000000000000000000000000800000000000000000000000000000000000000
+CT=55B17BD66788CEAC366398A31F289FFB
+
+I=102
+KEY=0000000000000000000000000400000000000000000000000000000000000000
+CT=11341F56C0D6D1008D28741DAA7679CE
+
+I=103
+KEY=0000000000000000000000000200000000000000000000000000000000000000
+CT=4DF7253DF421D83358BDBE924745D98C
+
+I=104
+KEY=0000000000000000000000000100000000000000000000000000000000000000
+CT=BAE2EE651116D93EDC8E83B5F3347BE1
+
+I=105
+KEY=0000000000000000000000000080000000000000000000000000000000000000
+CT=F9721ABD06709157183AF3965A659D9D
+
+I=106
+KEY=0000000000000000000000000040000000000000000000000000000000000000
+CT=19A1C252A613FE2860A4AE6D75CE6FA3
+
+I=107
+KEY=0000000000000000000000000020000000000000000000000000000000000000
+CT=B5DDB2F5D9752C949FBDE3FFF5556C6E
+
+I=108
+KEY=0000000000000000000000000010000000000000000000000000000000000000
+CT=81B044FCFFC78ECCFCD171AAD0405C66
+
+I=109
+KEY=0000000000000000000000000008000000000000000000000000000000000000
+CT=C640566D3C06020EB2C42F1D62E56A9B
+
+I=110
+KEY=0000000000000000000000000004000000000000000000000000000000000000
+CT=EA6C4BCF425291679FDFFD26A424FBCC
+
+I=111
+KEY=0000000000000000000000000002000000000000000000000000000000000000
+CT=57F6901465D9440D9F15EE2CBA5A4090
+
+I=112
+KEY=0000000000000000000000000001000000000000000000000000000000000000
+CT=FBCFA74CADC7406260F63D96C8AAB6B1
+
+I=113
+KEY=0000000000000000000000000000800000000000000000000000000000000000
+CT=DFF4F096CEA211D4BBDACA033D0EC7D1
+
+I=114
+KEY=0000000000000000000000000000400000000000000000000000000000000000
+CT=1EE5190D551F0F42F675227A381296A9
+
+I=115
+KEY=0000000000000000000000000000200000000000000000000000000000000000
+CT=F98E1905012E580F097623C10B93054F
+
+I=116
+KEY=0000000000000000000000000000100000000000000000000000000000000000
+CT=E7D43743D21DD3C9F168C86856558B9A
+
+I=117
+KEY=0000000000000000000000000000080000000000000000000000000000000000
+CT=632A9DDA730DAB67593C5D08D8AC1059
+
+I=118
+KEY=0000000000000000000000000000040000000000000000000000000000000000
+CT=E084317000715B9057BC9DE9F3AB6124
+
+I=119
+KEY=0000000000000000000000000000020000000000000000000000000000000000
+CT=61F9EF33A0BB4E666C2ED99101919FAB
+
+I=120
+KEY=0000000000000000000000000000010000000000000000000000000000000000
+CT=6DC1D68A11834657D46703C22578D59A
+
+I=121
+KEY=0000000000000000000000000000008000000000000000000000000000000000
+CT=53AC1548863D3D16F1D4DC7242E05F2C
+
+I=122
+KEY=0000000000000000000000000000004000000000000000000000000000000000
+CT=E82CD587A408306AD78CEAE0916B9F8C
+
+I=123
+KEY=0000000000000000000000000000002000000000000000000000000000000000
+CT=0FD2D40EA6AD17A3A767F0A8600D6295
+
+I=124
+KEY=0000000000000000000000000000001000000000000000000000000000000000
+CT=AD84CC8255ADB39DFCA23F92761AE7E9
+
+I=125
+KEY=0000000000000000000000000000000800000000000000000000000000000000
+CT=F4F20CF7D51BEE7DA024A2B11A7ECA0B
+
+I=126
+KEY=0000000000000000000000000000000400000000000000000000000000000000
+CT=5057691B85D9CE93A193214DB0A016B6
+
+I=127
+KEY=0000000000000000000000000000000200000000000000000000000000000000
+CT=0F58C960876390BDEF4BB6BE95CAA1EE
+
+I=128
+KEY=0000000000000000000000000000000100000000000000000000000000000000
+CT=9A3E66EEBC21BC0BD9430B341EF465FA
+
+I=129
+KEY=0000000000000000000000000000000080000000000000000000000000000000
+CT=20415035F34B8BCBCB28ABF07F78F0D4
+
+I=130
+KEY=0000000000000000000000000000000040000000000000000000000000000000
+CT=AC89FC7BA10479EBF10DE65BCEF89B3C
+
+I=131
+KEY=0000000000000000000000000000000020000000000000000000000000000000
+CT=068FA75A30BE443171AF3F6FEB1A20D2
+
+I=132
+KEY=0000000000000000000000000000000010000000000000000000000000000000
+CT=50E02F213246C525A8C27700CA34B502
+
+I=133
+KEY=0000000000000000000000000000000008000000000000000000000000000000
+CT=227DA47D5A0906DB3AB042BB0A695FB6
+
+I=134
+KEY=0000000000000000000000000000000004000000000000000000000000000000
+CT=8663AC30ED12514F1DE46777F4514BFC
+
+I=135
+KEY=0000000000000000000000000000000002000000000000000000000000000000
+CT=A987D4BC12E1DE9F4B6DF43567C34A8B
+
+I=136
+KEY=0000000000000000000000000000000001000000000000000000000000000000
+CT=6D5A0370F599ACA605F63B04E5143D0C
+
+I=137
+KEY=0000000000000000000000000000000000800000000000000000000000000000
+CT=9809266E378B07B7AFDB3BAA97B7E442
+
+I=138
+KEY=0000000000000000000000000000000000400000000000000000000000000000
+CT=8F753252B30CCCACE12D9A301F4D5090
+
+I=139
+KEY=0000000000000000000000000000000000200000000000000000000000000000
+CT=032465F6C0CE34D41962F561692A1AFF
+
+I=140
+KEY=0000000000000000000000000000000000100000000000000000000000000000
+CT=C50E9AD5BEB8F3B00821DD47FF8AC093
+
+I=141
+KEY=0000000000000000000000000000000000080000000000000000000000000000
+CT=9C6FEA3D46268D54A6829B2AD25BB276
+
+I=142
+KEY=0000000000000000000000000000000000040000000000000000000000000000
+CT=0FD8575E87706F561343D7B3A41E044A
+
+I=143
+KEY=0000000000000000000000000000000000020000000000000000000000000000
+CT=BEE9BEB3739540D88CBCE77925F0A114
+
+I=144
+KEY=0000000000000000000000000000000000010000000000000000000000000000
+CT=D24EAEE7FFFBAC3D6F26C2DCE0DCDE28
+
+I=145
+KEY=0000000000000000000000000000000000008000000000000000000000000000
+CT=47771A90398FF0F7FA821C2F8F5E1398
+
+I=146
+KEY=0000000000000000000000000000000000004000000000000000000000000000
+CT=4639741B6F84B135AD118C8249B64ED0
+
+I=147
+KEY=0000000000000000000000000000000000002000000000000000000000000000
+CT=8EE5505EC85567697A3306F250A27720
+
+I=148
+KEY=0000000000000000000000000000000000001000000000000000000000000000
+CT=7C8A19AC1AEFBC5E0119D91A5F05D4C2
+
+I=149
+KEY=0000000000000000000000000000000000000800000000000000000000000000
+CT=5141B9B672E54773B672E3A6C424887B
+
+I=150
+KEY=0000000000000000000000000000000000000400000000000000000000000000
+CT=B5A2D3CD206653C6402F34FB0AE3613D
+
+I=151
+KEY=0000000000000000000000000000000000000200000000000000000000000000
+CT=0F5BD9408738231D114B0A82753279A3
+
+I=152
+KEY=0000000000000000000000000000000000000100000000000000000000000000
+CT=FEF033FF4268EA487FC74C5E43A45338
+
+I=153
+KEY=0000000000000000000000000000000000000080000000000000000000000000
+CT=A3EDC09DCD529B113910D904AD855581
+
+I=154
+KEY=0000000000000000000000000000000000000040000000000000000000000000
+CT=AB8FBB6F27A0AC7C55B59FDD36B72F1C
+
+I=155
+KEY=0000000000000000000000000000000000000020000000000000000000000000
+CT=EEA44D5ED4D769CC930CD83D8999EC46
+
+I=156
+KEY=0000000000000000000000000000000000000010000000000000000000000000
+CT=6972276803AE9AA7C6F431AB10979C34
+
+I=157
+KEY=0000000000000000000000000000000000000008000000000000000000000000
+CT=86DEAA9F39244101818178474D7DBDE9
+
+I=158
+KEY=0000000000000000000000000000000000000004000000000000000000000000
+CT=88C6B466EA361D662D8D08CBF181F4FE
+
+I=159
+KEY=0000000000000000000000000000000000000002000000000000000000000000
+CT=91AB2C6B7C63FF59F7CBEEBF91B20B95
+
+I=160
+KEY=0000000000000000000000000000000000000001000000000000000000000000
+CT=2DFE6C146AD5B3D8C3C1718F13B48E01
+
+I=161
+KEY=0000000000000000000000000000000000000000800000000000000000000000
+CT=C7CFF1623451711391A302EEC3584AAA
+
+I=162
+KEY=0000000000000000000000000000000000000000400000000000000000000000
+CT=089FE845CC05011686C66019D18BE050
+
+I=163
+KEY=0000000000000000000000000000000000000000200000000000000000000000
+CT=08C8410B9B427211A67124B0DCCEAD48
+
+I=164
+KEY=0000000000000000000000000000000000000000100000000000000000000000
+CT=8D91592F5566085254784606334D7629
+
+I=165
+KEY=0000000000000000000000000000000000000000080000000000000000000000
+CT=3298FEAAF2E1201D6299FF8846639C97
+
+I=166
+KEY=0000000000000000000000000000000000000000040000000000000000000000
+CT=C497CB9F0BDFE0EFC8C2F3F90760AA72
+
+I=167
+KEY=0000000000000000000000000000000000000000020000000000000000000000
+CT=2788AFD046E0309CBE4424690DA2AB89
+
+I=168
+KEY=0000000000000000000000000000000000000000010000000000000000000000
+CT=E9891707F25EF29FEE372890D4258982
+
+I=169
+KEY=0000000000000000000000000000000000000000008000000000000000000000
+CT=DB041D94A23D45D4D4DCED5A030CAF61
+
+I=170
+KEY=0000000000000000000000000000000000000000004000000000000000000000
+CT=FFAFDBF0ECB18DF9EA02C27077448E6D
+
+I=171
+KEY=0000000000000000000000000000000000000000002000000000000000000000
+CT=2DAAA42A7D0A1D3B0E4761D99CF2150A
+
+I=172
+KEY=0000000000000000000000000000000000000000001000000000000000000000
+CT=3B7A54CB7CF30ABE263DD6ED5BFE8D63
+
+I=173
+KEY=0000000000000000000000000000000000000000000800000000000000000000
+CT=EEFA090174C590C448A55D43648F534A
+
+I=174
+KEY=0000000000000000000000000000000000000000000400000000000000000000
+CT=9E15798731ED42F43EA2740A691DA872
+
+I=175
+KEY=0000000000000000000000000000000000000000000200000000000000000000
+CT=31FBD661540A5DEAAD1017CFD3909EC8
+
+I=176
+KEY=0000000000000000000000000000000000000000000100000000000000000000
+CT=CDA9AE05F224140E28CB951721B44D6A
+
+I=177
+KEY=0000000000000000000000000000000000000000000080000000000000000000
+CT=0C5BC512C60A1EAC3434EFB1A8FBB182
+
+I=178
+KEY=0000000000000000000000000000000000000000000040000000000000000000
+CT=AA863610DEEEEB62D045E87EA30B59B5
+
+I=179
+KEY=0000000000000000000000000000000000000000000020000000000000000000
+CT=6AC2448DE568D279C7EEBE1DF403920C
+
+I=180
+KEY=0000000000000000000000000000000000000000000010000000000000000000
+CT=E2011E3D292B26888AE801215FD0CB40
+
+I=181
+KEY=0000000000000000000000000000000000000000000008000000000000000000
+CT=E06F3E15EE3A61672D1C99BADE5B9DBE
+
+I=182
+KEY=0000000000000000000000000000000000000000000004000000000000000000
+CT=BB7027F0548CF6712CEB4C7A4B28E178
+
+I=183
+KEY=0000000000000000000000000000000000000000000002000000000000000000
+CT=061EC21FB70FADBDF87C3BD2AE23825B
+
+I=184
+KEY=0000000000000000000000000000000000000000000001000000000000000000
+CT=4C21F26FE94ABBAC381352375314C3EB
+
+I=185
+KEY=0000000000000000000000000000000000000000000000800000000000000000
+CT=F7CEE6DD99909C2B569EEDA61ED8942E
+
+I=186
+KEY=0000000000000000000000000000000000000000000000400000000000000000
+CT=CE98C4A876C65E4CCB261EBB1D9DF7F5
+
+I=187
+KEY=0000000000000000000000000000000000000000000000200000000000000000
+CT=A5491881CF833C3604ABC08044F402AC
+
+I=188
+KEY=0000000000000000000000000000000000000000000000100000000000000000
+CT=A1BA16E64CCCB3087D57A768507B0BFC
+
+I=189
+KEY=0000000000000000000000000000000000000000000000080000000000000000
+CT=D55951E202D2949EBD3BE43120C738BF
+
+I=190
+KEY=0000000000000000000000000000000000000000000000040000000000000000
+CT=EBB8E43069E69F450EFEC65DCD52B7FD
+
+I=191
+KEY=0000000000000000000000000000000000000000000000020000000000000000
+CT=2B292135663B4AA5ABFE9423D57E7EE9
+
+I=192
+KEY=0000000000000000000000000000000000000000000000010000000000000000
+CT=E91BF974B3BE3AD966249D8655292A85
+
+I=193
+KEY=0000000000000000000000000000000000000000000000008000000000000000
+CT=384365998EAA9562236CC58F6ADF9610
+
+I=194
+KEY=0000000000000000000000000000000000000000000000004000000000000000
+CT=C2E997012AA3D4D8D359C9A947CBE69F
+
+I=195
+KEY=0000000000000000000000000000000000000000000000002000000000000000
+CT=F49421204148BA213BE87E2D5C22B0BF
+
+I=196
+KEY=0000000000000000000000000000000000000000000000001000000000000000
+CT=82ED0ED9953AA92E4DF30929CA65C00F
+
+I=197
+KEY=0000000000000000000000000000000000000000000000000800000000000000
+CT=291EB1D11653C8479437C74A977F5106
+
+I=198
+KEY=0000000000000000000000000000000000000000000000000400000000000000
+CT=BCB997B1939B8983ABD550D6025683E3
+
+I=199
+KEY=0000000000000000000000000000000000000000000000000200000000000000
+CT=1FBA2592C6F489775CAADA71F9B983E9
+
+I=200
+KEY=0000000000000000000000000000000000000000000000000100000000000000
+CT=969F66F217AF1A3DB9E41C1B29039824
+
+I=201
+KEY=0000000000000000000000000000000000000000000000000080000000000000
+CT=A54BB7D6B17E423AC0A7744C19073CB8
+
+I=202
+KEY=0000000000000000000000000000000000000000000000000040000000000000
+CT=B0AC6E6578D1021F47DCF9748A32EAD5
+
+I=203
+KEY=0000000000000000000000000000000000000000000000000020000000000000
+CT=B87B361C3B7B194C77A4358D4669153E
+
+I=204
+KEY=0000000000000000000000000000000000000000000000000010000000000000
+CT=46A133847F96EAA8282A799DC8899D58
+
+I=205
+KEY=0000000000000000000000000000000000000000000000000008000000000000
+CT=2265EC3A9F2D5C9547A091CC8CFB18EA
+
+I=206
+KEY=0000000000000000000000000000000000000000000000000004000000000000
+CT=54CBF3A6FC4FE56D426117AA1FFD1DDE
+
+I=207
+KEY=0000000000000000000000000000000000000000000000000002000000000000
+CT=5312877CCEAB6CFB0905394A370A8003
+
+I=208
+KEY=0000000000000000000000000000000000000000000000000001000000000000
+CT=7190BD6EC613FE38B84ECFE28F702FE4
+
+I=209
+KEY=0000000000000000000000000000000000000000000000000000800000000000
+CT=D1FA5B9CA89A43B04C05F0EF29EF68CD
+
+I=210
+KEY=0000000000000000000000000000000000000000000000000000400000000000
+CT=808285751548ED934FD1056D2D9AE8BA
+
+I=211
+KEY=0000000000000000000000000000000000000000000000000000200000000000
+CT=2758DEF3E7B95A9AE89777BE64D5A6CF
+
+I=212
+KEY=0000000000000000000000000000000000000000000000000000100000000000
+CT=07D81F87DB3E0ACC82B01E08FB22F3C1
+
+I=213
+KEY=0000000000000000000000000000000000000000000000000000080000000000
+CT=8DA250E5553D650711A75EE1CB4FD1C7
+
+I=214
+KEY=0000000000000000000000000000000000000000000000000000040000000000
+CT=A93D946BD0E87F32719DF5F158CEE669
+
+I=215
+KEY=0000000000000000000000000000000000000000000000000000020000000000
+CT=03945236EC2A4D4EAF30B8ABEB54330D
+
+I=216
+KEY=0000000000000000000000000000000000000000000000000000010000000000
+CT=11CC35301F24B79DDE31AEA2D1354F88
+
+I=217
+KEY=0000000000000000000000000000000000000000000000000000008000000000
+CT=E73715B3E8D9A290F44AE6FFBF247E5D
+
+I=218
+KEY=0000000000000000000000000000000000000000000000000000004000000000
+CT=7345E07732B71CB158BBF64CCA5C5B96
+
+I=219
+KEY=0000000000000000000000000000000000000000000000000000002000000000
+CT=6E128F296D24705A1924FD9B70C4ED04
+
+I=220
+KEY=0000000000000000000000000000000000000000000000000000001000000000
+CT=95A789776F036783FBD330947083F54F
+
+I=221
+KEY=0000000000000000000000000000000000000000000000000000000800000000
+CT=360DEC2533EA4AA2E3E54FD3DE2906EB
+
+I=222
+KEY=0000000000000000000000000000000000000000000000000000000400000000
+CT=E68EFD7FECF4D601EA22727BD764965B
+
+I=223
+KEY=0000000000000000000000000000000000000000000000000000000200000000
+CT=9065C64A8BFF44AC33EDBB611CF83D7B
+
+I=224
+KEY=0000000000000000000000000000000000000000000000000000000100000000
+CT=8F33C8DF2A7A51CE8090E8F123BC3723
+
+I=225
+KEY=0000000000000000000000000000000000000000000000000000000080000000
+CT=807F391FFBA8291BA625623210F99018
+
+I=226
+KEY=0000000000000000000000000000000000000000000000000000000040000000
+CT=5E8B3F3A701522CE5CAA761C929D6292
+
+I=227
+KEY=0000000000000000000000000000000000000000000000000000000020000000
+CT=3BA404DC38735A78289E3809E8364835
+
+I=228
+KEY=0000000000000000000000000000000000000000000000000000000010000000
+CT=D23BEDBAD229F8305DC425B6B759DCC9
+
+I=229
+KEY=0000000000000000000000000000000000000000000000000000000008000000
+CT=44880F21CF5913040AE376AEE2A10AD8
+
+I=230
+KEY=0000000000000000000000000000000000000000000000000000000004000000
+CT=9BC98E29D057C0E828C3B5CCE69256C1
+
+I=231
+KEY=0000000000000000000000000000000000000000000000000000000002000000
+CT=B293CC7A975DA141A68279368057CC41
+
+I=232
+KEY=0000000000000000000000000000000000000000000000000000000001000000
+CT=8D60FB87ACD91385B313BE5F1D7BD30F
+
+I=233
+KEY=0000000000000000000000000000000000000000000000000000000000800000
+CT=2C8E56132D70291B303C48FDF75543CD
+
+I=234
+KEY=0000000000000000000000000000000000000000000000000000000000400000
+CT=D1F80035B826791F6CE4E59B7DB1BB0D
+
+I=235
+KEY=0000000000000000000000000000000000000000000000000000000000200000
+CT=42CE6224FC36469339A133DD08173BD4
+
+I=236
+KEY=0000000000000000000000000000000000000000000000000000000000100000
+CT=61817155EA41BCBA2AF7F06AE7CBF585
+
+I=237
+KEY=0000000000000000000000000000000000000000000000000000000000080000
+CT=D1923A9866068D2EF5FB77D57C3315B6
+
+I=238
+KEY=0000000000000000000000000000000000000000000000000000000000040000
+CT=B37CBDB5D719F49691CA968EF2E84140
+
+I=239
+KEY=0000000000000000000000000000000000000000000000000000000000020000
+CT=EC974E653A055D7F8F22171030F68E1D
+
+I=240
+KEY=0000000000000000000000000000000000000000000000000000000000010000
+CT=DDE5D3B9AAD9C32213BB3675A822499C
+
+I=241
+KEY=0000000000000000000000000000000000000000000000000000000000008000
+CT=D3B6E9216EA1AE57EB1C628A3C38AB78
+
+I=242
+KEY=0000000000000000000000000000000000000000000000000000000000004000
+CT=82C99ECC69472B7E96324B042AE8B87A
+
+I=243
+KEY=0000000000000000000000000000000000000000000000000000000000002000
+CT=97144DC5338C43600F84439C0AA0D147
+
+I=244
+KEY=0000000000000000000000000000000000000000000000000000000000001000
+CT=400AC4A0BBADA1DB2121EB144C7E5209
+
+I=245
+KEY=0000000000000000000000000000000000000000000000000000000000000800
+CT=EFD9D550EB419ED278F4885A490AB54C
+
+I=246
+KEY=0000000000000000000000000000000000000000000000000000000000000400
+CT=2AB7816E149B7C0404C88A8857793670
+
+I=247
+KEY=0000000000000000000000000000000000000000000000000000000000000200
+CT=5B591DFF9E8DEE15BAD24C025DBCA481
+
+I=248
+KEY=0000000000000000000000000000000000000000000000000000000000000100
+CT=0C06633E30721C3749F49AD8CBF2B754
+
+I=249
+KEY=0000000000000000000000000000000000000000000000000000000000000080
+CT=96D6D31A41B5123B2035FD91A921D4CA
+
+I=250
+KEY=0000000000000000000000000000000000000000000000000000000000000040
+CT=E7F6C34D86668BC2805CA7793C5E86AD
+
+I=251
+KEY=0000000000000000000000000000000000000000000000000000000000000020
+CT=F46DFF5FF500D6879C4D3E45CF0CF0F3
+
+I=252
+KEY=0000000000000000000000000000000000000000000000000000000000000010
+CT=60D842D9C61DA7495C116197B7CECBBE
+
+I=253
+KEY=0000000000000000000000000000000000000000000000000000000000000008
+CT=D45B24EDB673353EBDF248B8FA06B67A
+
+I=254
+KEY=0000000000000000000000000000000000000000000000000000000000000004
+CT=119EAEBCC165D0BD02C0D35DC82EF992
+
+I=255
+KEY=0000000000000000000000000000000000000000000000000000000000000002
+CT=E673143680414ADA301D0ED34626B9FE
+
+I=256
+KEY=0000000000000000000000000000000000000000000000000000000000000001
+CT=6B6CFE160A6263631B292F879EEFF926
+
+==========
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/test/ecb_vt.txt b/mechglue/src/lib/crypto/aes/test/ecb_vt.txt
new file mode 100644
index 000000000..6dea60fc4
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/test/ecb_vt.txt
@@ -0,0 +1,1566 @@
+
+=========================
+
+FILENAME:  "ecb_vt.txt"
+
+Electronic Codebook (ECB) Mode
+Variable Text Known Answer Tests
+
+Algorithm Name: Rijndael
+Principal Submitter: Joan Daemen
+
+==========
+
+KEYSIZE=128
+
+KEY=00000000000000000000000000000000
+
+I=1
+PT=80000000000000000000000000000000
+CT=3AD78E726C1EC02B7EBFE92B23D9EC34
+
+I=2
+PT=40000000000000000000000000000000
+CT=45BC707D29E8204D88DFBA2F0B0CAD9B
+
+I=3
+PT=20000000000000000000000000000000
+CT=161556838018F52805CDBD6202002E3F
+
+I=4
+PT=10000000000000000000000000000000
+CT=F5569B3AB6A6D11EFDE1BF0A64C6854A
+
+I=5
+PT=08000000000000000000000000000000
+CT=64E82B50E501FBD7DD4116921159B83E
+
+I=6
+PT=04000000000000000000000000000000
+CT=BAAC12FB613A7DE11450375C74034041
+
+I=7
+PT=02000000000000000000000000000000
+CT=BCF176A7EAAD8085EBACEA362462A281
+
+I=8
+PT=01000000000000000000000000000000
+CT=47711816E91D6FF059BBBF2BF58E0FD3
+
+I=9
+PT=00800000000000000000000000000000
+CT=B970DFBE40698AF1638FE38BD3DF3B2F
+
+I=10
+PT=00400000000000000000000000000000
+CT=F95B59A44F391E14CF20B74BDC32FCFF
+
+I=11
+PT=00200000000000000000000000000000
+CT=720F74AE04A2A435B9A7256E49378F5B
+
+I=12
+PT=00100000000000000000000000000000
+CT=2A0445F61D36BFA7E277070730CF76DA
+
+I=13
+PT=00080000000000000000000000000000
+CT=8D0536B997AEFEC1D94011BAB6699A03
+
+I=14
+PT=00040000000000000000000000000000
+CT=674F002E19F6ED47EFF319E51FAD4498
+
+I=15
+PT=00020000000000000000000000000000
+CT=292C02C5CB9163C80AC0F6CF1DD8E92D
+
+I=16
+PT=00010000000000000000000000000000
+CT=FA321CF18EF5FE727DD82A5C1E945141
+
+I=17
+PT=00008000000000000000000000000000
+CT=A5A7AFE1034C39CCCEBE3C584BC0BE05
+
+I=18
+PT=00004000000000000000000000000000
+CT=4FF5A52E697E77D081205DBDB21CEA39
+
+I=19
+PT=00002000000000000000000000000000
+CT=209E88DC94C9003000CE0769AF7B7166
+
+I=20
+PT=00001000000000000000000000000000
+CT=5DEE41AF864CB4B650E5F51551824D38
+
+I=21
+PT=00000800000000000000000000000000
+CT=A79A63FA7E4503AE6D6E09F5F9053030
+
+I=22
+PT=00000400000000000000000000000000
+CT=A48316749FAE7FAC7002031A6AFD8BA7
+
+I=23
+PT=00000200000000000000000000000000
+CT=D6EEE8A7357A0E1D64262CA9C337AC42
+
+I=24
+PT=00000100000000000000000000000000
+CT=B013CA8A62A858053E9FB667ED39829E
+
+I=25
+PT=00000080000000000000000000000000
+CT=DF6EA9E4538A45A52D5C1A43C88F4B55
+
+I=26
+PT=00000040000000000000000000000000
+CT=7D03BA451371591D3FD5547D9165C73B
+
+I=27
+PT=00000020000000000000000000000000
+CT=0E0426281A6277E186499D365D5F49FF
+
+I=28
+PT=00000010000000000000000000000000
+CT=DBC02169DD2059E6CC4C57C1FEDF5AB4
+
+I=29
+PT=00000008000000000000000000000000
+CT=826590E05D167DA6F00DCC75E22788EB
+
+I=30
+PT=00000004000000000000000000000000
+CT=34A73F21A04421D9786335FAAB49423A
+
+I=31
+PT=00000002000000000000000000000000
+CT=ED347D0E0128EE1A7392A1D36AB78AA9
+
+I=32
+PT=00000001000000000000000000000000
+CT=EE944B2FE6E9FC888042608DA9615F75
+
+I=33
+PT=00000000800000000000000000000000
+CT=9E7C85A909EF7218BA7947CFB4718F46
+
+I=34
+PT=00000000400000000000000000000000
+CT=811AE07A0B2B1F816587FA73699AE77D
+
+I=35
+PT=00000000200000000000000000000000
+CT=68466FBF43C2FE13D4B18F7EC5EA745F
+
+I=36
+PT=00000000100000000000000000000000
+CT=D20B015C7191B219780956E6101F9354
+
+I=37
+PT=00000000080000000000000000000000
+CT=5939D5C1BBF54EE1B3E326D757BDDE25
+
+I=38
+PT=00000000040000000000000000000000
+CT=B1FDAFE9A0240E8FFEA19CE94B5105D3
+
+I=39
+PT=00000000020000000000000000000000
+CT=D62962ECE02CDD68C06BDFEFB2F9495B
+
+I=40
+PT=00000000010000000000000000000000
+CT=B3BB2DE6F3C26587BA8BAC4F7AD9499A
+
+I=41
+PT=00000000008000000000000000000000
+CT=E0B1072D6D9FF703D6FBEF77852B0A6B
+
+I=42
+PT=00000000004000000000000000000000
+CT=D8DD51C907F478DE0228E83E61FD1758
+
+I=43
+PT=00000000002000000000000000000000
+CT=A42DFFE6E7C1671C06A25236FDD10017
+
+I=44
+PT=00000000001000000000000000000000
+CT=25ACF141550BFAB9EF451B6C6A5B2163
+
+I=45
+PT=00000000000800000000000000000000
+CT=4DA7FCA3949B16E821DBC84F19581018
+
+I=46
+PT=00000000000400000000000000000000
+CT=7D49B6347CBCC8919C7FA96A37A7A215
+
+I=47
+PT=00000000000200000000000000000000
+CT=900024B29A08C6721B95BA3B753DDB4D
+
+I=48
+PT=00000000000100000000000000000000
+CT=6D2182FB283B6934D90BA7848CAB5E66
+
+I=49
+PT=00000000000080000000000000000000
+CT=F73EF01B448D23A4D90DE8B2F9666E7A
+
+I=50
+PT=00000000000040000000000000000000
+CT=4AD9CDA2418643E9A3D926AF5E6B0412
+
+I=51
+PT=00000000000020000000000000000000
+CT=7CAEC8E7E5953997D545B033201C8C5B
+
+I=52
+PT=00000000000010000000000000000000
+CT=3C43CA1F6B6864503E27B48D88230CF5
+
+I=53
+PT=00000000000008000000000000000000
+CT=44F779B93108FE9FEEC880D79BA74488
+
+I=54
+PT=00000000000004000000000000000000
+CT=9E50E8D9CFD3A682A78E527C9072A1CF
+
+I=55
+PT=00000000000002000000000000000000
+CT=68D000CBC838BBE3C505D6F814C01F28
+
+I=56
+PT=00000000000001000000000000000000
+CT=2CB2A9FEC1ACD1D9B0FA05205E304F57
+
+I=57
+PT=00000000000000800000000000000000
+CT=01EB2806606E46444520A5CC6180CD4B
+
+I=58
+PT=00000000000000400000000000000000
+CT=DAA9B25168CC702326F217F1A0C0B162
+
+I=59
+PT=00000000000000200000000000000000
+CT=3E07E648975D9578D03555B1755807ED
+
+I=60
+PT=00000000000000100000000000000000
+CT=0B45F52E802C8B8DE09579425B80B711
+
+I=61
+PT=00000000000000080000000000000000
+CT=659595DA0B68F6DF0DD6CA77202986E1
+
+I=62
+PT=00000000000000040000000000000000
+CT=05FF42873893536E58C8FA98A45C73C4
+
+I=63
+PT=00000000000000020000000000000000
+CT=B5B03421DE8BBFFC4EADEC767339A9BD
+
+I=64
+PT=00000000000000010000000000000000
+CT=788BCD111ECF73D4E78D2E21BEF55460
+
+I=65
+PT=00000000000000008000000000000000
+CT=909CD9EC6790359F982DC6F2393D5315
+
+I=66
+PT=00000000000000004000000000000000
+CT=332950F361535FF24EFAC8C76293F12C
+
+I=67
+PT=00000000000000002000000000000000
+CT=A68CCD4E330FFDA9D576DA436DB53D75
+
+I=68
+PT=00000000000000001000000000000000
+CT=27C8A1CCFDB0B015D1ED5B3E77143791
+
+I=69
+PT=00000000000000000800000000000000
+CT=D76A4B95887A77DF610DD3E1D3B20325
+
+I=70
+PT=00000000000000000400000000000000
+CT=C068AB0DE71C66DAE83C361EF4B2D989
+
+I=71
+PT=00000000000000000200000000000000
+CT=C2120BCD49EDA9A288B3B4BE79AC8158
+
+I=72
+PT=00000000000000000100000000000000
+CT=0C546F62BF2773CD0F564FCECA7BA688
+
+I=73
+PT=00000000000000000080000000000000
+CT=18F3462BEDE4920213CCB66DAB1640AA
+
+I=74
+PT=00000000000000000040000000000000
+CT=FE42F245EDD0E24B216AEBD8B392D690
+
+I=75
+PT=00000000000000000020000000000000
+CT=3D3EEBC8D3D1558A194C2D00C337FF2B
+
+I=76
+PT=00000000000000000010000000000000
+CT=29AAEDF043E785DB42836F79BE6CBA28
+
+I=77
+PT=00000000000000000008000000000000
+CT=215F90C6744E2944358E78619159A611
+
+I=78
+PT=00000000000000000004000000000000
+CT=8606B1AA9E1D548E5442B06551E2C6DC
+
+I=79
+PT=00000000000000000002000000000000
+CT=987BB4B8740EC0EDE7FEA97DF033B5B1
+
+I=80
+PT=00000000000000000001000000000000
+CT=C0A3500DA5B0AE07D2F450930BEEDF1B
+
+I=81
+PT=00000000000000000000800000000000
+CT=525FDF8312FE8F32C781481A8DAAAE37
+
+I=82
+PT=00000000000000000000400000000000
+CT=BFD2C56AE5FB9C9DE33A6944572A6487
+
+I=83
+PT=00000000000000000000200000000000
+CT=7975A57A425CDF5AA1FA929101F650B0
+
+I=84
+PT=00000000000000000000100000000000
+CT=BF174BC49609A8709B2CD8366DAA79FE
+
+I=85
+PT=00000000000000000000080000000000
+CT=06C50C43222F56C874B1704E9F44BF7D
+
+I=86
+PT=00000000000000000000040000000000
+CT=0CEC48CD34043EA29CA3B8ED5278721E
+
+I=87
+PT=00000000000000000000020000000000
+CT=9548EA34A1560197B304D0ACB8A1698D
+
+I=88
+PT=00000000000000000000010000000000
+CT=22F9E9B1BD73B6B5B7D3062C986272F3
+
+I=89
+PT=00000000000000000000008000000000
+CT=FEE8E934BD0873295059002230E298D4
+
+I=90
+PT=00000000000000000000004000000000
+CT=1B08E2E3EB820D139CB4ABBDBE81D00D
+
+I=91
+PT=00000000000000000000002000000000
+CT=0021177681E4D90CEAF69DCED0145125
+
+I=92
+PT=00000000000000000000001000000000
+CT=4A8E314452CA8A8A3619FC54BC423643
+
+I=93
+PT=00000000000000000000000800000000
+CT=65047474F7222C94C6965425FF1BFD0A
+
+I=94
+PT=00000000000000000000000400000000
+CT=E123F551A9C4A8489622B16F961A9AA4
+
+I=95
+PT=00000000000000000000000200000000
+CT=EF05530948B80915028BB2B6FE429380
+
+I=96
+PT=00000000000000000000000100000000
+CT=72535B7FE0F0F777CEDCD55CD77E2DDF
+
+I=97
+PT=00000000000000000000000080000000
+CT=3423D8EFC31FA2F4C365C77D8F3B5C63
+
+I=98
+PT=00000000000000000000000040000000
+CT=DE0E51C264663F3C5DBC59580A98D8E4
+
+I=99
+PT=00000000000000000000000020000000
+CT=B2D9391166680947AB09264156719679
+
+I=100
+PT=00000000000000000000000010000000
+CT=10DB79F23B06D263835C424AF749ADB7
+
+I=101
+PT=00000000000000000000000008000000
+CT=DDF72D27E6B01EC107EA3E005B59563B
+
+I=102
+PT=00000000000000000000000004000000
+CT=8266B57485A5954A4236751DE07F6694
+
+I=103
+PT=00000000000000000000000002000000
+CT=669A501E1F1ADE6E5523DE01D6DBC987
+
+I=104
+PT=00000000000000000000000001000000
+CT=C20C48F2989725D461D1DB589DC0896E
+
+I=105
+PT=00000000000000000000000000800000
+CT=DE35158E7810ED1191825D2AA98FA97D
+
+I=106
+PT=00000000000000000000000000400000
+CT=4FE294F2C0F34D0671B693A237EBDDC8
+
+I=107
+PT=00000000000000000000000000200000
+CT=087AE74B10CCBFDF6739FEB9559C01A4
+
+I=108
+PT=00000000000000000000000000100000
+CT=5DC278970B7DEF77A5536C77AB59C207
+
+I=109
+PT=00000000000000000000000000080000
+CT=7607F078C77085184EAA9B060C1FBFFF
+
+I=110
+PT=00000000000000000000000000040000
+CT=9DB841531BCBE7998DAD19993FB3CC00
+
+I=111
+PT=00000000000000000000000000020000
+CT=D6A089B654854A94560BAE13298835B8
+
+I=112
+PT=00000000000000000000000000010000
+CT=E1E223C4CF90CC5D195B370D65114622
+
+I=113
+PT=00000000000000000000000000008000
+CT=1CBED73C50D053BDAD372CEEE54836A1
+
+I=114
+PT=00000000000000000000000000004000
+CT=D309E69376D257ADF2BFDA152B26555F
+
+I=115
+PT=00000000000000000000000000002000
+CT=740F7649117F0DEE6EAA7789A9994C36
+
+I=116
+PT=00000000000000000000000000001000
+CT=76AE64417C297184D668C5FD908B3CE5
+
+I=117
+PT=00000000000000000000000000000800
+CT=6095FEA4AA8035591F1787A819C48787
+
+I=118
+PT=00000000000000000000000000000400
+CT=D1FF4E7ACD1C79967FEBAB0F7465D450
+
+I=119
+PT=00000000000000000000000000000200
+CT=5F5AD3C42B9489557BB63BF49ECF5F8A
+
+I=120
+PT=00000000000000000000000000000100
+CT=FB56CC09B680B1D07C5A52149E29F07C
+
+I=121
+PT=00000000000000000000000000000080
+CT=FF49B8DF4A97CBE03833E66197620DAD
+
+I=122
+PT=00000000000000000000000000000040
+CT=5E070ADE533D2E090ED0F5BE13BC0983
+
+I=123
+PT=00000000000000000000000000000020
+CT=3AB4FB1D2B7BA376590A2C241D1F508D
+
+I=124
+PT=00000000000000000000000000000010
+CT=58B2431BC0BEDE02550F40238969EC78
+
+I=125
+PT=00000000000000000000000000000008
+CT=0253786E126504F0DAB90C48A30321DE
+
+I=126
+PT=00000000000000000000000000000004
+CT=200211214E7394DA2089B6ACD093ABE0
+
+I=127
+PT=00000000000000000000000000000002
+CT=0388DACE60B6A392F328C2B971B2FE78
+
+I=128
+PT=00000000000000000000000000000001
+CT=58E2FCCEFA7E3061367F1D57A4E7455A
+
+==========
+
+KEYSIZE=192
+
+KEY=000000000000000000000000000000000000000000000000
+
+I=1
+PT=80000000000000000000000000000000
+CT=6CD02513E8D4DC986B4AFE087A60BD0C
+
+I=2
+PT=40000000000000000000000000000000
+CT=423D2772A0CA56DAABB48D2129062987
+
+I=3
+PT=20000000000000000000000000000000
+CT=1021F2A8DA70EB2219DC16804445FF98
+
+I=4
+PT=10000000000000000000000000000000
+CT=C636E35B402577F96974D8804295EBB8
+
+I=5
+PT=08000000000000000000000000000000
+CT=1566D2E57E8393C19E29F892EA28A9A7
+
+I=6
+PT=04000000000000000000000000000000
+CT=883C878FED70B36CC09D040F9619DD19
+
+I=7
+PT=02000000000000000000000000000000
+CT=06734593A974965790E715594FC34AA9
+
+I=8
+PT=01000000000000000000000000000000
+CT=F19B389948D9A45534E5BD36C984134A
+
+I=9
+PT=00800000000000000000000000000000
+CT=D8410DFC14FA6D175EC968EA8CAC514C
+
+I=10
+PT=00400000000000000000000000000000
+CT=7E6C6EBB4029A177CF7B2FDD9AC6BB7A
+
+I=11
+PT=00200000000000000000000000000000
+CT=4B51DD4850DC0A6C3A46D924003D2C27
+
+I=12
+PT=00100000000000000000000000000000
+CT=2E510A9D917B15BE32A192B12A668F23
+
+I=13
+PT=00080000000000000000000000000000
+CT=88F6F79962B0FB77FEA8E7C632D3108E
+
+I=14
+PT=00040000000000000000000000000000
+CT=A3A35AB1D88DAF07B52794A0F065383A
+
+I=15
+PT=00020000000000000000000000000000
+CT=DC6CC878433E2B3BB193049A4ECBFC53
+
+I=16
+PT=00010000000000000000000000000000
+CT=EFCD3763EB7B1A415938248A9A5B4FD5
+
+I=17
+PT=00008000000000000000000000000000
+CT=AB7E9FB9A66DBE5BB44854F07D9015EE
+
+I=18
+PT=00004000000000000000000000000000
+CT=8B8E9D3365F8F6743ECF7E33E99255A4
+
+I=19
+PT=00002000000000000000000000000000
+CT=54D37B4F176FF3D8F6AFC866066D8572
+
+I=20
+PT=00001000000000000000000000000000
+CT=E83310889480FBF3C00342E3126D0D02
+
+I=21
+PT=00000800000000000000000000000000
+CT=D321AB2511F92F098174AA2DE6E85DA2
+
+I=22
+PT=00000400000000000000000000000000
+CT=D8E3F40B1112D5149D58C481DFA9983F
+
+I=23
+PT=00000200000000000000000000000000
+CT=2454C4E0806639DDF19854D6C68054AD
+
+I=24
+PT=00000100000000000000000000000000
+CT=A5506D410F7CA32F3955DD79D9D09418
+
+I=25
+PT=00000080000000000000000000000000
+CT=7908EE40677699568A7DC1AA317C7E4E
+
+I=26
+PT=00000040000000000000000000000000
+CT=B4B7B29DD43B2F5CF765E25192273982
+
+I=27
+PT=00000020000000000000000000000000
+CT=92AFE9668159BEFFE2A86F8503260164
+
+I=28
+PT=00000010000000000000000000000000
+CT=5C36A232FBA6D187A84657AD4028B18F
+
+I=29
+PT=00000008000000000000000000000000
+CT=A2E994DFAB3A798DF8F54F6DA87E58E2
+
+I=30
+PT=00000004000000000000000000000000
+CT=6CDAB10A72ADF77D71D0765BAAE95631
+
+I=31
+PT=00000002000000000000000000000000
+CT=9FE3C801BCAAF7BB800F2E6BF3278E21
+
+I=32
+PT=00000001000000000000000000000000
+CT=B459D90D9A6C392E5493BC91CF5A0863
+
+I=33
+PT=00000000800000000000000000000000
+CT=0518A9FA5007F6787E0FB4E5AC27D758
+
+I=34
+PT=00000000400000000000000000000000
+CT=BED9795415D28599700ED7952384A963
+
+I=35
+PT=00000000200000000000000000000000
+CT=F0140421173D60251EF6CAB0229B1B50
+
+I=36
+PT=00000000100000000000000000000000
+CT=460EB4652B3F6779EA28CB11B37529ED
+
+I=37
+PT=00000000080000000000000000000000
+CT=C4283D351C960A6AC13CD19CCF03AE38
+
+I=38
+PT=00000000040000000000000000000000
+CT=6815A10047B2C834A798EBDCC6786C75
+
+I=39
+PT=00000000020000000000000000000000
+CT=99BA19F0CDD5990D0386B32CE56C9C4C
+
+I=40
+PT=00000000010000000000000000000000
+CT=DE76F62C61E07915162DA13E79679DEC
+
+I=41
+PT=00000000008000000000000000000000
+CT=DD0325D6854803D06D1D2277D5FB8D67
+
+I=42
+PT=00000000004000000000000000000000
+CT=580B71A41DE37D6FAC83CCB0B3BB1C97
+
+I=43
+PT=00000000002000000000000000000000
+CT=E9B1AB470A1B02EF0FF5E6754A092C96
+
+I=44
+PT=00000000001000000000000000000000
+CT=8590620F5AF5993B7410282F4126BC1F
+
+I=45
+PT=00000000000800000000000000000000
+CT=8D4914D2F1B22B2E268E66E532D29D7C
+
+I=46
+PT=00000000000400000000000000000000
+CT=FD826CE48E62C5E30867044B86BA4B56
+
+I=47
+PT=00000000000200000000000000000000
+CT=100E7B831C9F35FA1271F5F1316C6FCF
+
+I=48
+PT=00000000000100000000000000000000
+CT=0A2DD0C17F68B996AA96C007003D0B31
+
+I=49
+PT=00000000000080000000000000000000
+CT=C95F68C57E06B0A2E1F623C83C5D80BF
+
+I=50
+PT=00000000000040000000000000000000
+CT=571CAFC92C7C8A5EC54C0741E186905C
+
+I=51
+PT=00000000000020000000000000000000
+CT=22514353E95312C112255E1EED0B2DF6
+
+I=52
+PT=00000000000010000000000000000000
+CT=791A8BF462BD17580BD9152C6D11C6C5
+
+I=53
+PT=00000000000008000000000000000000
+CT=5882A0178D548F84A165DB809C60DC28
+
+I=54
+PT=00000000000004000000000000000000
+CT=3CE4A90EED4458CA6039E42DDADB71C3
+
+I=55
+PT=00000000000002000000000000000000
+CT=D3CBAB261207A16BE2751E77044FD7C9
+
+I=56
+PT=00000000000001000000000000000000
+CT=24E32B698A7B32217093628B01F424AB
+
+I=57
+PT=00000000000000800000000000000000
+CT=9F6AFC0AF27CF565110C77E3C24F4F5B
+
+I=58
+PT=00000000000000400000000000000000
+CT=E088AA5CDA20EF267BB039B00C72C45B
+
+I=59
+PT=00000000000000200000000000000000
+CT=5CF1018B7E0BA1775601C2E279900360
+
+I=60
+PT=00000000000000100000000000000000
+CT=3B1A7388B89FB9416AD8753CF5AF35D2
+
+I=61
+PT=00000000000000080000000000000000
+CT=137FA4ED00AFCD9F5D8BC0D14BD5837A
+
+I=62
+PT=00000000000000040000000000000000
+CT=806F5C9B663559BB56F234881E4A3E60
+
+I=63
+PT=00000000000000020000000000000000
+CT=8069A449152292DF2DE8642992C632B6
+
+I=64
+PT=00000000000000010000000000000000
+CT=37C6CF2A1ABD1B1F1922B46C7B4A280D
+
+I=65
+PT=00000000000000008000000000000000
+CT=7A2835260E5A0AA2B5DC301800EC8438
+
+I=66
+PT=00000000000000004000000000000000
+CT=EE81FAF2F9058213FFCACF281CB8509E
+
+I=67
+PT=00000000000000002000000000000000
+CT=57F22D93C37129BA331FDBA38E005A1E
+
+I=68
+PT=00000000000000001000000000000000
+CT=EC798782E87B7D9F780CC3C3A46519B5
+
+I=69
+PT=00000000000000000800000000000000
+CT=43EA28497F5D40E3A4744FA2EDAA42DE
+
+I=70
+PT=00000000000000000400000000000000
+CT=91F004E7DEBF41B3414DD8C5C317372C
+
+I=71
+PT=00000000000000000200000000000000
+CT=C249EAE54E7B4DF43B938C1B4CC28314
+
+I=72
+PT=00000000000000000100000000000000
+CT=32C289D7EEFB99D2F17AD7B7D45FE1EC
+
+I=73
+PT=00000000000000000080000000000000
+CT=A675FB2E8DDBF810CEF01CF2B728CD2B
+
+I=74
+PT=00000000000000000040000000000000
+CT=A418AAAB6E6921CC731AA8A349386080
+
+I=75
+PT=00000000000000000020000000000000
+CT=2E2B0F44863E67D9B0215C4ABD60417F
+
+I=76
+PT=00000000000000000010000000000000
+CT=F0AF7CB19E911D481F6426DAEFDD2240
+
+I=77
+PT=00000000000000000008000000000000
+CT=CB1304DAAA2DF6878F56AC2E0F887E04
+
+I=78
+PT=00000000000000000004000000000000
+CT=B1B70A7E6A0CD1916D9B78BEA19084AE
+
+I=79
+PT=00000000000000000002000000000000
+CT=0CDE9F9BE646A5FCE3436B794A9CFC65
+
+I=80
+PT=00000000000000000001000000000000
+CT=68C7946D476A0A36674B36AFD7E5DF33
+
+I=81
+PT=00000000000000000000800000000000
+CT=48770159A07DD8DFFF06C80105F8D57C
+
+I=82
+PT=00000000000000000000400000000000
+CT=665E62801B3260E3C45BD3BE34DFDEBE
+
+I=83
+PT=00000000000000000000200000000000
+CT=4159C1F686BFBE5B0E50BDB0DA532B69
+
+I=84
+PT=00000000000000000000100000000000
+CT=6333100A5A4AD917DC2D4E78A04869A3
+
+I=85
+PT=00000000000000000000080000000000
+CT=866A4519AB1D199F25886B89D0539ACC
+
+I=86
+PT=00000000000000000000040000000000
+CT=EC0CFD37E4CBC7E8BE385283F7AEA75A
+
+I=87
+PT=00000000000000000000020000000000
+CT=CA2F383AACCA0810AA13F3E710621422
+
+I=88
+PT=00000000000000000000010000000000
+CT=1D0EEF6870444F950937831EC0A55D98
+
+I=89
+PT=00000000000000000000008000000000
+CT=37839B35ED6801E7670496D479A95017
+
+I=90
+PT=00000000000000000000004000000000
+CT=02317C8C7098C4F94AB867AC7A49DD8D
+
+I=91
+PT=00000000000000000000002000000000
+CT=FFB4CB4E3F7F8BF3367EBD43236518B4
+
+I=92
+PT=00000000000000000000001000000000
+CT=36BEDEF1E4AA3E4A40A305741713FCBF
+
+I=93
+PT=00000000000000000000000800000000
+CT=B2DFE3C4870269C1E3FEEC39161540D9
+
+I=94
+PT=00000000000000000000000400000000
+CT=147EF2518AD45DA0026056ECBF6A3DFA
+
+I=95
+PT=00000000000000000000000200000000
+CT=027A75E4DE635790E47ACE90D7928804
+
+I=96
+PT=00000000000000000000000100000000
+CT=C4CF3CCB59BF87D0AFBD629F48CFBB7B
+
+I=97
+PT=00000000000000000000000080000000
+CT=35165C93F564C97E1C32EF97E8151A87
+
+I=98
+PT=00000000000000000000000040000000
+CT=449DE37F7D5A1BBD628ABBE7E061701D
+
+I=99
+PT=00000000000000000000000020000000
+CT=B1D45EAF218F1799B149BAD677FE129F
+
+I=100
+PT=00000000000000000000000010000000
+CT=BE08AC6DB6BD0583AA9D2ABC71C73DCD
+
+I=101
+PT=00000000000000000000000008000000
+CT=BCC835BD3DF1A79E4C7C145B899A5C25
+
+I=102
+PT=00000000000000000000000004000000
+CT=3D311EA611FF5AF371301C58A8E9912D
+
+I=103
+PT=00000000000000000000000002000000
+CT=A5A1BEA594ACC7CA80F09EA5ADDB5C71
+
+I=104
+PT=00000000000000000000000001000000
+CT=0F09492429FE7222D6CD8190D9F2FFBF
+
+I=105
+PT=00000000000000000000000000800000
+CT=816D2220A16B8AAEE71364FD43636C6F
+
+I=106
+PT=00000000000000000000000000400000
+CT=D7E8702408419ED73191B107EAF75A0B
+
+I=107
+PT=00000000000000000000000000200000
+CT=9B170EFB1E235B433C78E276BEA082F0
+
+I=108
+PT=00000000000000000000000000100000
+CT=03BBECC5598AE974430F29395522F096
+
+I=109
+PT=00000000000000000000000000080000
+CT=DB53517766C0E8CF42059607CBA89380
+
+I=110
+PT=00000000000000000000000000040000
+CT=2E2AF4B7931F0AEFFAC5471148A5BB97
+
+I=111
+PT=00000000000000000000000000020000
+CT=C872C0408266403B984F635FF5683DE4
+
+I=112
+PT=00000000000000000000000000010000
+CT=15DCF750B0E3A68AD1F4EFD07E8967B4
+
+I=113
+PT=00000000000000000000000000008000
+CT=B41092048E9E6A749F6FD8CE515A23A3
+
+I=114
+PT=00000000000000000000000000004000
+CT=4DA9267D62507994312BD5C99ADDE730
+
+I=115
+PT=00000000000000000000000000002000
+CT=9E2FCA6D1D626E9C6A924EBF7DBF618A
+
+I=116
+PT=00000000000000000000000000001000
+CT=E092E8D7EF2C2465AEFB2493C3063590
+
+I=117
+PT=00000000000000000000000000000800
+CT=1C0E58DA37D1068378A88DBE2EDE4E10
+
+I=118
+PT=00000000000000000000000000000400
+CT=19063F854232B8509A6A3A6D46809959
+
+I=119
+PT=00000000000000000000000000000200
+CT=447FB09E54EFA285F7530F25C4EA0022
+
+I=120
+PT=00000000000000000000000000000100
+CT=F6ABE86321BE40E1FBFDAFED37CC1D9B
+
+I=121
+PT=00000000000000000000000000000080
+CT=4E8506CD006666341D6CF51F98B41F35
+
+I=122
+PT=00000000000000000000000000000040
+CT=53995DE0009CA18BECAFB8307C54C14C
+
+I=123
+PT=00000000000000000000000000000020
+CT=2006BF99F4C58B6CC2627856593FAEEA
+
+I=124
+PT=00000000000000000000000000000010
+CT=2DA697D2737CB30B744A4644FA1CBC6E
+
+I=125
+PT=00000000000000000000000000000008
+CT=47A22ACDB60C3A986A8F76ECD0EA3433
+
+I=126
+PT=00000000000000000000000000000004
+CT=FDAA17C2CDE20268FE36E164EA532151
+
+I=127
+PT=00000000000000000000000000000002
+CT=98E7247C07F0FE411C267E4384B0F600
+
+I=128
+PT=00000000000000000000000000000001
+CT=CD33B28AC773F74BA00ED1F312572435
+
+==========
+
+KEYSIZE=256
+
+KEY=0000000000000000000000000000000000000000000000000000000000000000
+
+I=1
+PT=80000000000000000000000000000000
+CT=DDC6BF790C15760D8D9AEB6F9A75FD4E
+
+I=2
+PT=40000000000000000000000000000000
+CT=C7098C217C334D0C9BDF37EA13B0822C
+
+I=3
+PT=20000000000000000000000000000000
+CT=60F0FB0D4C56A8D4EEFEC5264204042D
+
+I=4
+PT=10000000000000000000000000000000
+CT=73376FBBF654D0686E0E84001477106B
+
+I=5
+PT=08000000000000000000000000000000
+CT=2F443B52BA5F0C6EA0602C7C4FD259B6
+
+I=6
+PT=04000000000000000000000000000000
+CT=75D11B0E3A68C4223D88DBF017977DD7
+
+I=7
+PT=02000000000000000000000000000000
+CT=779B38D15BFFB63D8D609D551A5CC98E
+
+I=8
+PT=01000000000000000000000000000000
+CT=5275F3D86B4FB8684593133EBFA53CD3
+
+I=9
+PT=00800000000000000000000000000000
+CT=1CEF2074B336CEC62F12DEA2F6AB1481
+
+I=10
+PT=00400000000000000000000000000000
+CT=1AEF5ABBAD9D7160874578DCD8BAE172
+
+I=11
+PT=00200000000000000000000000000000
+CT=46C525DB17E72F26BF03216846B6F609
+
+I=12
+PT=00100000000000000000000000000000
+CT=E24411F941BBE08788781E3EC52CBAA4
+
+I=13
+PT=00080000000000000000000000000000
+CT=83A3DEDD1DD27018F6A6477E40527581
+
+I=14
+PT=00040000000000000000000000000000
+CT=B68F8A2CDBAB0C923C67FC8F0F1087DE
+
+I=15
+PT=00020000000000000000000000000000
+CT=649944A70C32BF87A7409E7AE128FDE8
+
+I=16
+PT=00010000000000000000000000000000
+CT=2846526D67387539C89314DE9E0C2D02
+
+I=17
+PT=00008000000000000000000000000000
+CT=A9A0B8402E53C70DD1688054BA58DDFD
+
+I=18
+PT=00004000000000000000000000000000
+CT=4A72E6E1B79C83AC4BE3EBA5699EED48
+
+I=19
+PT=00002000000000000000000000000000
+CT=B0E36B867BA4FF2B77D0614B0E364E4C
+
+I=20
+PT=00001000000000000000000000000000
+CT=49B57DE141F6418E3090F24DDD4014B6
+
+I=21
+PT=00000800000000000000000000000000
+CT=A6C0D5B9797258E1987AC5F6CD20146D
+
+I=22
+PT=00000400000000000000000000000000
+CT=426CF4BDCAA369175965D26E7C71EEA2
+
+I=23
+PT=00000200000000000000000000000000
+CT=E27F484CE54BC99BC1A52BDA3B518A26
+
+I=24
+PT=00000100000000000000000000000000
+CT=D16D186284C7E6EE64B8104E0EF20BA5
+
+I=25
+PT=00000080000000000000000000000000
+CT=6431F8538AD54E1E044A9F71F8EF556B
+
+I=26
+PT=00000040000000000000000000000000
+CT=ECD57CEB451D27EB96C55B2042257E8E
+
+I=27
+PT=00000020000000000000000000000000
+CT=4F0F188DC911B1954AFBC734C9F68872
+
+I=28
+PT=00000010000000000000000000000000
+CT=B54DEF0337626B65614E81EDFDE620F3
+
+I=29
+PT=00000008000000000000000000000000
+CT=6655D8074CAE0B90B0D3A3FE72D4D9DB
+
+I=30
+PT=00000004000000000000000000000000
+CT=C6B74B6B9EB4FC0C9A237DB1B616D09A
+
+I=31
+PT=00000002000000000000000000000000
+CT=D7B5D076EA56EC2B20791D7AD51CCF8F
+
+I=32
+PT=00000001000000000000000000000000
+CT=FE160C224BF003CE3BDDC90CB52ED22C
+
+I=33
+PT=00000000800000000000000000000000
+CT=5E00DA9BA94B5EC0D258D8A8002E0F6A
+
+I=34
+PT=00000000400000000000000000000000
+CT=09AC6DCFF4DACFF1651E2BA212A292A3
+
+I=35
+PT=00000000200000000000000000000000
+CT=B283617E318D99AF83A05D9810BA89F7
+
+I=36
+PT=00000000100000000000000000000000
+CT=0B5F70CCB40B0EF2538AE9B4A9770B35
+
+I=37
+PT=00000000080000000000000000000000
+CT=43282BF180248FB517839B37F4DDAAE4
+
+I=38
+PT=00000000040000000000000000000000
+CT=DDBD534C8B2E6D30A268F88C55AD765B
+
+I=39
+PT=00000000020000000000000000000000
+CT=A41A164E50EC2D9F175E752B755E0B5C
+
+I=40
+PT=00000000010000000000000000000000
+CT=37BFF99FF2F7AA97779E4ADF6F13FB10
+
+I=41
+PT=00000000008000000000000000000000
+CT=9BA4F7BD298152903A683C4CEC669216
+
+I=42
+PT=00000000004000000000000000000000
+CT=5FB750C7CE10DE7B4504248914D0DA06
+
+I=43
+PT=00000000002000000000000000000000
+CT=3E748BFA108E086F51D56EC74A9E0FB9
+
+I=44
+PT=00000000001000000000000000000000
+CT=31D4E56B99F5B73C1B8437DF332AFB98
+
+I=45
+PT=00000000000800000000000000000000
+CT=9DC6717B84FC55D266E7B1D9B5C52A5F
+
+I=46
+PT=00000000000400000000000000000000
+CT=8EF8BA007F23C0A50FC120E07041BCCD
+
+I=47
+PT=00000000000200000000000000000000
+CT=C58F38E1839FC1918A12B8C9E88C66B6
+
+I=48
+PT=00000000000100000000000000000000
+CT=B695D72A3FCF508C4050E12E40061C2D
+
+I=49
+PT=00000000000080000000000000000000
+CT=5D2736AD478A50583BC8C11BEFF16D7A
+
+I=50
+PT=00000000000040000000000000000000
+CT=DF0EACA8F17847AD41F9578F14C7B56B
+
+I=51
+PT=00000000000020000000000000000000
+CT=E5AA14AD48AD0A3C47CC35D5F8020E51
+
+I=52
+PT=00000000000010000000000000000000
+CT=11BE6C8F58EBD8CEF1A53F591A68E8CE
+
+I=53
+PT=00000000000008000000000000000000
+CT=ECFE7BAFCBF42C1FEE015488770B3053
+
+I=54
+PT=00000000000004000000000000000000
+CT=E552649F8D8EC4A1E1CD6DF50B6E6777
+
+I=55
+PT=00000000000002000000000000000000
+CT=521C0629DE93B9119CDB1DDC5809DDEA
+
+I=56
+PT=00000000000001000000000000000000
+CT=CB38A62A0BAB1784156BA038CBA99BF6
+
+I=57
+PT=00000000000000800000000000000000
+CT=76CCEE8AAACD394DE1EEF3DDA10CB54B
+
+I=58
+PT=00000000000000400000000000000000
+CT=6AFF910FA1D5673140E2DB59B8416049
+
+I=59
+PT=00000000000000200000000000000000
+CT=064A12C0EF73FB386801BF4F35F3120D
+
+I=60
+PT=00000000000000100000000000000000
+CT=2240E374929D5B1BB8FF0FFDDDF640EC
+
+I=61
+PT=00000000000000080000000000000000
+CT=D4BA15C904C7692185DE85C02052E180
+
+I=62
+PT=00000000000000040000000000000000
+CT=1714A315AB0166728A44CD91D4AE9018
+
+I=63
+PT=00000000000000020000000000000000
+CT=6C970BDD9F0E222722EA31A1D12DD0AD
+
+I=64
+PT=00000000000000010000000000000000
+CT=F5956EDF02BD36A401BBB6CE77C3D3FB
+
+I=65
+PT=00000000000000008000000000000000
+CT=0CA11F122CCD7C259DC597EED3DF9BC4
+
+I=66
+PT=00000000000000004000000000000000
+CT=50109AB4912AD2560B206F331B62EB6C
+
+I=67
+PT=00000000000000002000000000000000
+CT=DBE7C91A4175614889A2D4BEFD64845E
+
+I=68
+PT=00000000000000001000000000000000
+CT=0D3322853A571A6B46B79C0228E0DD25
+
+I=69
+PT=00000000000000000800000000000000
+CT=96E4EE0BB9A11C6FB8522F285BADDEB6
+
+I=70
+PT=00000000000000000400000000000000
+CT=96705C52D2CFCE82E630C93477C79C49
+
+I=71
+PT=00000000000000000200000000000000
+CT=C50130AED6A126149D71F3888C83C232
+
+I=72
+PT=00000000000000000100000000000000
+CT=4816EFE3DEB380566EBA0C17BF582090
+
+I=73
+PT=00000000000000000080000000000000
+CT=0390857B4C8C98E4CF7A2B6F3394C507
+
+I=74
+PT=00000000000000000040000000000000
+CT=422E73A02025EBE8B8B5D6E0FA24FCB2
+
+I=75
+PT=00000000000000000020000000000000
+CT=3271AA7F4BF1D7C38050A43076D4FF76
+
+I=76
+PT=00000000000000000010000000000000
+CT=D2074946F0D37B8975607BFC2E70234C
+
+I=77
+PT=00000000000000000008000000000000
+CT=1A509194C1270AB92E5A42D3A9F8D98B
+
+I=78
+PT=00000000000000000004000000000000
+CT=512438946360CCC4A5C6D73F6EED7130
+
+I=79
+PT=00000000000000000002000000000000
+CT=98CFCDEC46EBEA1A286B3004F2746A0D
+
+I=80
+PT=00000000000000000001000000000000
+CT=A1CF369949677A3AF3D58E3EABF2741B
+
+I=81
+PT=00000000000000000000800000000000
+CT=D84C2E1A0E4A52166FA8FF6889D1E5E2
+
+I=82
+PT=00000000000000000000400000000000
+CT=4AD91CCEEF60119B5078FD162D2735DE
+
+I=83
+PT=00000000000000000000200000000000
+CT=2860793D818E97AAFF1D339D7702438D
+
+I=84
+PT=00000000000000000000100000000000
+CT=6F9068BE73364AE250D89D78A6C9CE6F
+
+I=85
+PT=00000000000000000000080000000000
+CT=024FC3FEF4883FEB1A8DD005305FECCE
+
+I=86
+PT=00000000000000000000040000000000
+CT=08A61FE0816D75EA15EB3C9FB9CCDED6
+
+I=87
+PT=00000000000000000000020000000000
+CT=449C86DFA13F260175CE39797686FFA4
+
+I=88
+PT=00000000000000000000010000000000
+CT=4FFFFC29A59858E1133F2BFB1A8A4817
+
+I=89
+PT=00000000000000000000008000000000
+CT=19425D1F6480B25096561295697DC2B7
+
+I=90
+PT=00000000000000000000004000000000
+CT=31974727ECDD2C77C3A428FC3A8CB3FC
+
+I=91
+PT=00000000000000000000002000000000
+CT=A57CD704B3C95E744D08DF443458F2F5
+
+I=92
+PT=00000000000000000000001000000000
+CT=486D8C193DB1ED73ACB17990442FC40B
+
+I=93
+PT=00000000000000000000000800000000
+CT=5E4DBF4E83AB3BC055B9FCC7A6B3A763
+
+I=94
+PT=00000000000000000000000400000000
+CT=ACF2E0A693FBBCBA4D41B861E0D89E37
+
+I=95
+PT=00000000000000000000000200000000
+CT=32A7CB2AE066A51D2B78FC4B4CFCB608
+
+I=96
+PT=00000000000000000000000100000000
+CT=677D494DBB73CAF55C1990158DA12F14
+
+I=97
+PT=00000000000000000000000080000000
+CT=082A0D2367512ADF0D75A151BFBE0A17
+
+I=98
+PT=00000000000000000000000040000000
+CT=5E5BB7337923C482CE8CBA249E6A8C7D
+
+I=99
+PT=00000000000000000000000020000000
+CT=D3001BA7C7026EE3E5003179530AFCFC
+
+I=100
+PT=00000000000000000000000010000000
+CT=46EC44F8931E629FE8FD8961312EDDE1
+
+I=101
+PT=00000000000000000000000008000000
+CT=C5F8ECD79C7B30E81D17E32079969310
+
+I=102
+PT=00000000000000000000000004000000
+CT=5B8AD6919E24CAEBCC55401AEE0C9802
+
+I=103
+PT=00000000000000000000000002000000
+CT=C2302B7E701B5CC7F8B29E3516DBBFA6
+
+I=104
+PT=00000000000000000000000001000000
+CT=A1D04D6A76F9F7A94D49FAA64A87F244
+
+I=105
+PT=00000000000000000000000000800000
+CT=7FB6F92D35B5CB6C631600EDB9E860BA
+
+I=106
+PT=00000000000000000000000000400000
+CT=B2EF7078BCFACE07AEEC3F9B48830EB3
+
+I=107
+PT=00000000000000000000000000200000
+CT=F475A7493D24C7036E53390374C378B3
+
+I=108
+PT=00000000000000000000000000100000
+CT=B36802AC987377A37BD8EADC97C57D60
+
+I=109
+PT=00000000000000000000000000080000
+CT=ADDCD3D19689C4DDC738CE5F69DC9505
+
+I=110
+PT=00000000000000000000000000040000
+CT=0DAF8CA22884915403C0F0BB1F4BD74F
+
+I=111
+PT=00000000000000000000000000020000
+CT=4AF36BAE2660503B3248E4685059FD05
+
+I=112
+PT=00000000000000000000000000010000
+CT=7D5631814DD8E917D97A0D514C743971
+
+I=113
+PT=00000000000000000000000000008000
+CT=BC3352500FC0CBB9DB5B5F6B491C1BE8
+
+I=114
+PT=00000000000000000000000000004000
+CT=6A4A30BA87E87AF65C90AEB7AFEDC76B
+
+I=115
+PT=00000000000000000000000000002000
+CT=77E6125897668AC8E73E8C79A6FF8336
+
+I=116
+PT=00000000000000000000000000001000
+CT=3FA9D39104EBB323C7AAAA248960DD1E
+
+I=117
+PT=00000000000000000000000000000800
+CT=FAD75AD76AB10ADC49036B250E229D39
+
+I=118
+PT=00000000000000000000000000000400
+CT=2FACAA5FE35B228A16AC74088D702EC4
+
+I=119
+PT=00000000000000000000000000000200
+CT=88B6CBCFDFEF8AD91720A1BB69A1F33E
+
+I=120
+PT=00000000000000000000000000000100
+CT=C7E9D250998632D444356242EF04058D
+
+I=121
+PT=00000000000000000000000000000080
+CT=B14DAD8D3D9153F46C0D3A1AD63C7A05
+
+I=122
+PT=00000000000000000000000000000040
+CT=60ABA678A506608D0845966D29B5F790
+
+I=123
+PT=00000000000000000000000000000020
+CT=482DC43F2388EF25D24144E144BD834E
+
+I=124
+PT=00000000000000000000000000000010
+CT=1490A05A7CEE43BDE98B56E309DC0126
+
+I=125
+PT=00000000000000000000000000000008
+CT=ABFA77CD6E85DA245FB0BDC5E52CFC29
+
+I=126
+PT=00000000000000000000000000000004
+CT=DD4AB1284D4AE17B41E85924470C36F7
+
+I=127
+PT=00000000000000000000000000000002
+CT=CEA7403D4D606B6E074EC5D3BAF39D18
+
+I=128
+PT=00000000000000000000000000000001
+CT=530F8AFBC74536B9A963B4F1C4CB738B
+
+==========
\ No newline at end of file
diff --git a/mechglue/src/lib/crypto/aes/test/katmct.pdf b/mechglue/src/lib/crypto/aes/test/katmct.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..b494fb53716f92bdc6ca762cd5689493eb0bdc56
GIT binary patch
literal 100812
zcmc%PRZv{P*C={)f@g3ixH~i00Kwhe0}SqNfdn1gU4y&3ySux4(BKJ#<mUT-=bSpX
zPTi{WcHdU7y>@rke%Slhy_-%|Qksp6otqL9jqc!Zb`cZpUnD@uN$F%}i-{&Ago(zX
zXyIt(ZcWL>`7f*fuPtq3?{48r$)TvPBWVG3GPn45hlmI!nwz_;g{cE3S^zLIU_N}w
zlARO<Fqn|nX2}giK?@PJ?h_-3B8xtNv+jx^AR3~UHnDCpVJE_X4f02*juH}LNGG=2
zY>6^b6DwQtBoytrgR-Uv5Pi}`75GSJ9=K84PQ19Y3p5Jzr$kNph>?&su;(TysnV6D
z2mKXKweW^w)YXbW&ip`hOAR7L*$9`UXaJ2%bjv3OqUf6>z4r87b;=B^<zV8}CMiCZ
z_dG9{7$xpi#H?BcdwD@pOlfSqB;%!EV<1oo<|j~eX3ZOpW~G7MwBROitn8UsT#En>
z6PGHa8Y<ZL1j^Jl5ZfmzaS>tCs(%j{vsf5FL%m-VDB3dR#VVk!=wBJ~0b&jZ!G|BY
z^6%(hOSq(w9J�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
F{|1h!T}%J~

literal 0
HcmV?d00001

diff --git a/mechglue/src/lib/crypto/aes/uitypes.h b/mechglue/src/lib/crypto/aes/uitypes.h
new file mode 100644
index 000000000..02dd3b072
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/uitypes.h
@@ -0,0 +1,81 @@
+/*
+ -------------------------------------------------------------------------
+ Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary 
+ form is allowed (with or without changes) provided that:
+
+   1. distributions of this source code include the above copyright 
+      notice, this list of conditions and the following disclaimer;
+
+   2. distributions in binary form include the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other associated materials;
+
+   3. the copyright holder's name is not used to endorse products 
+      built using this software without specific written permission. 
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explcit or implied warranties
+ in respect of any properties, including, but not limited to, correctness 
+ and fitness for purpose.
+ -------------------------------------------------------------------------
+ Issue Date: 01/02/2002
+
+ This file contains code to obtain or set the definitions for fixed length 
+ unsigned integer types.
+*/
+
+#ifndef _UITYPES_H
+#define _UITYPES_H
+
+#if defined(__GNU_LIBRARY__)
+#define HAS_INTTYPES_H
+#elif !defined(_MSC_VER)
+#include <limits.h>
+#if ULONG_MAX > 0xFFFFFFFFUL
+  #define MODEL_64
+#else
+  #define MODEL_32
+#endif
+#endif
+
+#if defined HAS_INTTYPES_H || defined HAVE_INTTYPES_H
+#include <inttypes.h>
+#define s_u32     u
+#define s_u64   ull
+#elif defined MODEL_32
+typedef unsigned char            uint8_t;
+typedef unsigned short int      uint16_t;
+typedef unsigned int            uint32_t;
+typedef unsigned long long int  uint64_t;
+#define s_u32     u
+#define s_u64   ull
+#elif defined MODEL_64
+typedef unsigned char            uint8_t;
+typedef unsigned short int      uint16_t;
+typedef unsigned int            uint32_t;
+typedef unsigned long int       uint64_t;
+#define s_u32     u
+#define s_u64    ul
+#elif defined(_MSC_VER)
+typedef unsigned  __int8         uint8_t;
+typedef unsigned __int16        uint16_t;
+typedef unsigned __int32        uint32_t;
+typedef unsigned __int64        uint64_t;
+#define s_u32    ui32
+#define s_u64    ui64
+#else
+#error You need to define fixed length types in uitypes.h
+#endif
+
+#define sfx_lo(x,y) x##y
+#define sfx_hi(x,y) sfx_lo(x,y)
+#define x_32(p)     sfx_hi(0x##p,s_u32)
+#define x_64(p)     sfx_hi(0x##p,s_u64)
+
+#endif
diff --git a/mechglue/src/lib/crypto/aes/vb.txt b/mechglue/src/lib/crypto/aes/vb.txt
new file mode 100644
index 000000000..dab133c2c
--- /dev/null
+++ b/mechglue/src/lib/crypto/aes/vb.txt
@@ -0,0 +1,87 @@
+
+Private Const BlkLenMax = 32        ' maximum block length in bytes
+Private Const KeyLenMax = 32        ' maximum block length in bytes
+Private Const KeySchLenMax = 128    ' maximum key schedule length in bytes
+Private BlkLen As Integer           ' actual block length
+Private KeyLen As Integer           ' actual key length
+
+Private Type AESctx     ' Type to hold the AES context data
+  Ekey(0 To KeySchLenMax - 1) As Long
+  Nrnd As Long
+  Ncol As Long
+End Type
+
+Private Type KeyBlk     ' Type to hold user key data
+ K(0 To KeyLenMax - 1) As Byte
+End Type
+
+Private Type IoBlk      ' Type to hold cipher input and output blocks
+ IO(0 To BlkLenMax - 1) As Byte
+End Type
+
+Rem Change "d:\dll_pth" in the following lines to the directory path where the AES DLL is located
+Private Declare Function AesBlkLen Lib "d:\dll_path\aes.dll" Alias "_aes_blk_len@8" (ByVal N As Long, C As AESctx) As Integer
+Private Declare Function AesEncKey Lib "d:\dll_path\aes.dll" Alias "_aes_enc_key@12" (K As KeyBlk, ByVal N As Long, C As AESctx) As Integer
+Private Declare Function AesDecKey Lib "d:\dll_path\aes.dll" Alias "_aes_dec_key@12" (K As KeyBlk, ByVal N As Long, C As AESctx) As Integer
+Private Declare Function AesEncBlk Lib "d:\dll_path\aes.dll" Alias "_aes_enc_blk@12" (Ib As IoBlk, Ob As IoBlk, C As AESctx) As Integer
+Private Declare Function AesDecBlk Lib "d:\dll_path\aes.dll" Alias "_aes_dec_blk@12" (Ib As IoBlk, Ob As IoBlk, C As AESctx) As Integer
+
+Private Sub Hex(X As Byte)  ' Output a byte in hexadecimal format
+Dim H As Byte
+H = Int(X / 16)
+If H < 10 Then
+    Debug.Print Chr(48 + H);
+Else
+    Debug.Print Chr(87 + H);
+End If
+H = Int(X Mod 16)
+If H < 10 Then
+    Debug.Print Chr(48 + H);
+Else
+    Debug.Print Chr(87 + H);
+End If
+End Sub
+
+Private Sub OutKey(S As String, B As KeyBlk)    ' Display a key value
+Debug.Print: Debug.Print S;
+For i = 0 To KeyLen - 1
+   Hex B.K(i)
+Next i
+End Sub
+
+Private Sub OutBlock(S As String, B As IoBlk)   ' Display an input/output block
+Debug.Print: Debug.Print S;
+For i = 0 To BlkLen - 1
+   Hex B.IO(i)
+Next i
+End Sub
+
+Rem The following Main routine should output the following in the immediate window:
+Rem Key =            00000000000000000000000000000000
+Rem Input =          00000000000000000000000000000000
+Rem Encrypted Text = 66e94bd4ef8a2c3b884cfa59ca342b2e
+Rem Decrypted Text = 00000000000000000000000000000000
+
+Sub Main()
+Dim Key As KeyBlk   ' These variables are automatically
+Dim Ib As IoBlk, Ob As IoBlk, Rb As IoBlk
+Dim Cx As AESctx    ' initialised to zero values in VBA
+Dim RetVal As Integer
+
+BlkLen = 16: KeyLen = 16
+
+Rem RetVal = AesBlkLen(BlkLen, Cx)          ' include if the cipher block size is variable
+
+OutKey "Key =            ", Key
+OutBlock "Input =          ", Ib
+
+RetVal = AesEncKey(Key, KeyLen, Cx)     ' set an all zero encryption key
+RetVal = AesEncBlk(Ib, Ob, Cx)          ' encrypt Ib to Ob
+OutBlock "Encrypted Text = ", Ob
+
+RetVal = AesDecKey(Key, KeyLen, Cx)     ' set an all zero decryption key
+RetVal = AesDecBlk(Ob, Rb, Cx)          ' decrypt Ob to Rb
+OutBlock "Decrypted Text = ", Rb
+Debug.Print
+
+End Sub
diff --git a/mechglue/src/lib/crypto/arcfour/ChangeLog b/mechglue/src/lib/crypto/arcfour/ChangeLog
new file mode 100644
index 000000000..1eaac886c
--- /dev/null
+++ b/mechglue/src/lib/crypto/arcfour/ChangeLog
@@ -0,0 +1,115 @@
+2005-10-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour_s2k.c (asctouni): Counter should be size_t, like len.
+
+2005-07-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour_s2k.c: Renamed from string_to_key.c.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Updated accordingly.
+
+2004-09-21  Sam Hartman  <hartmans@mit.edu>
+
+	* string_to_key.c (krb5int_arcfour_string_to_key): Free the copy
+	of the password, thanks to Derrick Schommer 
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour.c: Use ANSI C style function definitions.
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour.c (l40): Now const.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour.c (krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
+	krb5_arcfour_decrypt): Use new numeric fields for block/hash/key
+	sizes instead of calling functions.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour.c (krb5int_arcfour_string_to_key): Renamed from
+	krb5_... and added new s2k-params argument, which must be null.
+	* arcfour.h: Updated.
+
+2003-02-03  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour.c (krb5_arcfour_encrypt_length): l40, the 40-bit
+	constant should be static 
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-05-13  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour.c: Microsoft indicates that they have changed some key
+	usage numbers to be closer to the Kerberos spec; reflect those
+	changes.  This is OK because currently no one actually sends any
+	authorization data in that space.
+2002-02-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour.h, arcfour.c, string_to_key.c: Use const instead of
+	krb5_const.
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* string_to_key.c (krb5_arcfour_string_to_key): Use size_t instead
+	of int for local variable.
+	(asctouni): Length argument now size_t instead of int.
+
+2001-11-07  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour.c (krb5_arcfour_encrypt): Set output length
+	(ms_translate_usage): Be consistent with latest mail from Microsoft
+
+2001-11-06  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour-int.h: Structure for arcfour cipher state
+	
+2001-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* string_to_key.c (krb5_arcfour_string_to_key): Cleanup variables
+	defined but not used.
+
+2001-10-25  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour.c: GSSAPI usage translations
+
+2001-10-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* arcfour.h: Declare krb5int_enc_arcfour extern so that multiple
+	copies are not generated (etypes.c, and arcfour.c).
+
+2001-10-22  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour-int.h: Make krb5int_arcfour_translate_usage non-static so the hash can use it
+	
+
+2001-10-19  Sam Hartman  <hartmans@mit.edu>
+
+	* string_to_key.c (krb5_arcfour_string_to_key): Ignore salt
+	(krb5_arcfour_string_to_key): Use memset not bzero
+
+	* arcfour.c (krb5_arcfour_decrypt): Return error if salt cannot be allocated
+	(krb5_arcfour_encrypt): Only memset bits of key to known value on export-grade crypto
+
+2001-10-18  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour.c (arcfour_translate_usage): Attempt to implement based
+	on draft-brezak-win2k-krb-rc4-hmac-03.  Several usages remain unclear.
+	Make 40-bit string not unsigned to avoid warning
+	(krb5_arcfour_encrypt krb5_arcfour_decrypt):  cast to avoid pointer warnings
+
diff --git a/mechglue/src/lib/crypto/arcfour/Makefile.in b/mechglue/src/lib/crypto/arcfour/Makefile.in
new file mode 100644
index 000000000..949f52f76
--- /dev/null
+++ b/mechglue/src/lib/crypto/arcfour/Makefile.in
@@ -0,0 +1,58 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/arcfour
+mydir=arcfour
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../md4
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=arcfour
+##DOS##OBJFILE=..\$(OUTPRE)arcfour.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS=\
+	arcfour.o	\
+	arcfour_s2k.o
+
+OBJS=\
+	$(OUTPRE)arcfour.$(OBJEXT)	\
+	$(OUTPRE)arcfour_s2k.$(OBJEXT)
+
+SRCS=\
+	$(srcdir)/arcfour.c	\
+	$(srcdir)/arcfour_s2k.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+arcfour.so arcfour.po $(OUTPRE)arcfour.$(OBJEXT): arcfour.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  arcfour-int.h arcfour.h
+arcfour_s2k.so arcfour_s2k.po $(OUTPRE)arcfour_s2k.$(OBJEXT): \
+  arcfour_s2k.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../md4/rsa-md4.h arcfour-int.h arcfour.h
diff --git a/mechglue/src/lib/crypto/arcfour/arcfour-int.h b/mechglue/src/lib/crypto/arcfour/arcfour-int.h
new file mode 100644
index 000000000..398fe57a1
--- /dev/null
+++ b/mechglue/src/lib/crypto/arcfour/arcfour-int.h
@@ -0,0 +1,31 @@
+/*
+
+ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95).
+This cipher is widely believed and has been tested to be equivalent
+with the RC4 cipher from RSA Data Security, Inc.  (RC4 is a trademark
+of RSA Data Security)
+
+*/
+#ifndef ARCFOUR_INT_H
+#define ARCFOUR_INT_H
+
+#include "arcfour.h"
+
+#define CONFOUNDERLENGTH 8
+
+typedef struct
+{
+   unsigned int x;
+   unsigned int y;
+   unsigned char state[256];
+} ArcfourContext;
+
+typedef struct {
+  int initialized;
+  ArcfourContext ctx;
+} ArcFourCipherState;
+
+krb5_keyusage krb5int_arcfour_translate_usage(krb5_keyusage usage);
+
+
+#endif /* ARCFOUR_INT_H */
diff --git a/mechglue/src/lib/crypto/arcfour/arcfour.c b/mechglue/src/lib/crypto/arcfour/arcfour.c
new file mode 100644
index 000000000..3481fadcb
--- /dev/null
+++ b/mechglue/src/lib/crypto/arcfour/arcfour.c
@@ -0,0 +1,318 @@
+/*
+
+ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95).
+This cipher is widely believed and has been tested to be equivalent
+with the RC4 cipher from RSA Data Security, Inc.  (RC4 is a trademark
+of RSA Data Security)
+
+*/
+#include "k5-int.h"
+#include "arcfour-int.h"
+static const char *const l40 = "fortybits";
+
+void
+krb5_arcfour_encrypt_length(const struct krb5_enc_provider *enc,
+			    const struct krb5_hash_provider *hash,
+			    size_t inputlen, size_t *length)
+{
+  size_t blocksize, hashsize;
+
+  blocksize = enc->block_size;
+  hashsize = hash->hashsize;
+
+  /* checksum + (confounder + inputlen, in even blocksize) */
+  *length = hashsize + krb5_roundup(8 + inputlen, blocksize);
+}
+
+ krb5_keyusage
+ krb5int_arcfour_translate_usage(krb5_keyusage usage)
+{
+  switch (usage) {
+  case 1:			/* AS-REQ PA-ENC-TIMESTAMP padata timestamp,  */
+    return 1;
+  case 2:			/* ticket from kdc */
+    return 2;
+  case 3:			/* as-rep encrypted part */
+    return 8;
+  case 4:			/* tgs-req authz data */
+    return 4;
+  case 5:			/* tgs-req authz data in subkey */
+    return 5;
+  case 6:			/* tgs-req authenticator cksum */
+    return 6;			
+case 7:				/* tgs-req authenticator */
+  return 7;
+    case 8:
+    return 8;
+  case 9:			/* tgs-rep encrypted with subkey */
+    return 8;
+  case 10:			/* ap-rep authentication cksum */
+    return 10;			/* xxx  Microsoft never uses this*/
+  case 11:			/* app-req authenticator */
+    return 11;
+  case 12:			/* app-rep encrypted part */
+    return 12;
+  case 23: /* sign wrap token*/
+    return 13;
+  default:
+      return usage;
+}
+}
+
+krb5_error_code
+krb5_arcfour_encrypt(const struct krb5_enc_provider *enc,
+		     const struct krb5_hash_provider *hash,
+		     const krb5_keyblock *key, krb5_keyusage usage,
+		     const krb5_data *ivec, const krb5_data *input,
+		     krb5_data *output)
+{
+  krb5_keyblock k1, k2, k3;
+  krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder;
+  krb5_keyusage ms_usage;
+  size_t keylength, keybytes, blocksize, hashsize;
+  krb5_error_code ret;
+
+  blocksize = enc->block_size;
+  keybytes = enc->keybytes;
+  keylength = enc->keylength;
+  hashsize = hash->hashsize;
+  
+  d1.length=keybytes;
+  d1.data=malloc(d1.length);
+  if (d1.data == NULL)
+    return (ENOMEM);
+  memcpy(&k1, key, sizeof (krb5_keyblock));
+  k1.length=d1.length;
+  k1.contents= (void *) d1.data;
+
+  d2.length=keybytes;
+  d2.data=malloc(d2.length);
+  if (d2.data == NULL) {
+    free(d1.data);
+    return (ENOMEM);
+  }
+  memcpy(&k2, key, sizeof (krb5_keyblock));
+  k2.length=d2.length;
+  k2.contents=(void *) d2.data;
+
+  d3.length=keybytes;
+  d3.data=malloc(d3.length);
+  if (d3.data == NULL) {
+    free(d1.data);
+    free(d2.data);
+    return (ENOMEM);
+  }
+  memcpy(&k3, key, sizeof (krb5_keyblock));
+  k3.length=d3.length;
+  k3.contents= (void *) d3.data;
+  
+  salt.length=14;
+  salt.data=malloc(salt.length);
+  if (salt.data == NULL) {
+    free(d1.data);
+    free(d2.data);
+    free(d3.data);
+    return (ENOMEM);
+  }
+
+  /* is "input" already blocksize aligned?  if it is, then we need this
+     step, otherwise we do not */
+  plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
+  plaintext.data=malloc(plaintext.length);
+  if (plaintext.data == NULL) {
+    free(d1.data);
+    free(d2.data);
+    free(d3.data);
+    free(salt.data);
+    return(ENOMEM);
+  }
+
+  /* setup convienient pointers into the allocated data */
+  checksum.length=hashsize;
+  checksum.data=output->data;
+  ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
+  ciphertext.data=output->data+hashsize;
+  confounder.length=CONFOUNDERLENGTH;
+  confounder.data=plaintext.data;
+  output->length = plaintext.length+hashsize;
+  
+  /* begin the encryption, computer K1 */
+  ms_usage=krb5int_arcfour_translate_usage(usage);
+  if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+    strncpy(salt.data, l40, salt.length);
+    salt.data[10]=ms_usage & 0xff;
+    salt.data[11]=(ms_usage >> 8) & 0xff;
+    salt.data[12]=(ms_usage >> 16) & 0xff;
+    salt.data[13]=(ms_usage >> 24) & 0xff;
+  } else {
+    salt.length=4;
+    salt.data[0]=ms_usage & 0xff;
+    salt.data[1]=(ms_usage >> 8) & 0xff;
+    salt.data[2]=(ms_usage >> 16) & 0xff;
+    salt.data[3]=(ms_usage >> 24) & 0xff;
+  }
+  krb5_hmac(hash, key, 1, &salt, &d1);
+
+  memcpy(k2.contents, k1.contents, k2.length);
+
+  if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP)
+    memset(k1.contents+7, 0xab, 9);
+
+  ret=krb5_c_random_make_octets(/* XXX */ 0, &confounder);
+  memcpy(plaintext.data+confounder.length, input->data, input->length);
+  if (ret)
+    goto cleanup;
+
+  krb5_hmac(hash, &k2, 1, &plaintext, &checksum);
+
+  krb5_hmac(hash, &k1, 1, &checksum, &d3);
+
+  ret=(*(enc->encrypt))(&k3, ivec, &plaintext, &ciphertext);
+    
+ cleanup:
+  memset(d1.data, 0, d1.length);
+  memset(d2.data, 0, d2.length);
+  memset(d3.data, 0, d3.length);
+  memset(salt.data, 0, salt.length);
+  memset(plaintext.data, 0, plaintext.length);
+
+  free(d1.data);
+  free(d2.data);
+  free(d3.data);
+  free(salt.data);
+  free(plaintext.data);
+  return (ret);
+}
+
+/* This is the arcfour-hmac decryption routine */
+krb5_error_code
+krb5_arcfour_decrypt(const struct krb5_enc_provider *enc,
+		     const struct krb5_hash_provider *hash,
+		     const krb5_keyblock *key, krb5_keyusage usage,
+		     const krb5_data *ivec, const krb5_data *input,
+		     krb5_data *output)
+{
+  krb5_keyblock k1,k2,k3;
+  krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum;
+  krb5_keyusage ms_usage;
+  size_t keybytes, keylength, hashsize, blocksize;
+  krb5_error_code ret;
+
+  blocksize = enc->block_size;
+  keybytes = enc->keybytes;
+  keylength = enc->keylength;
+  hashsize = hash->hashsize;
+
+  d1.length=keybytes;
+  d1.data=malloc(d1.length);
+  if (d1.data == NULL)
+    return (ENOMEM);
+  memcpy(&k1, key, sizeof (krb5_keyblock));
+  k1.length=d1.length;
+  k1.contents= (void *) d1.data;
+  
+  d2.length=keybytes;
+  d2.data=malloc(d2.length);
+  if (d2.data == NULL) {
+    free(d1.data);
+    return (ENOMEM);
+  }
+  memcpy(&k2, key, sizeof(krb5_keyblock));
+  k2.length=d2.length;
+  k2.contents= (void *) d2.data;
+
+  d3.length=keybytes;
+  d3.data=malloc(d3.length);
+  if  (d3.data == NULL) {
+    free(d1.data);
+    free(d2.data);
+    return (ENOMEM);
+  }
+  memcpy(&k3, key, sizeof(krb5_keyblock));
+  k3.length=d3.length;
+  k3.contents= (void *) d3.data;
+
+  salt.length=14;
+  salt.data=malloc(salt.length);
+  if(salt.data==NULL) {
+    free(d1.data);
+    free(d2.data);
+    free(d3.data);
+    return (ENOMEM);
+  }
+
+  ciphertext.length=input->length-hashsize;
+  ciphertext.data=input->data+hashsize;
+  plaintext.length=ciphertext.length;
+  plaintext.data=malloc(plaintext.length);
+  if (plaintext.data == NULL) {
+    free(d1.data);
+    free(d2.data);
+    free(d3.data);
+    free(salt.data);
+    return (ENOMEM);
+  }
+
+  checksum.length=hashsize;
+  checksum.data=input->data;
+
+  /* compute the salt */
+  ms_usage=krb5int_arcfour_translate_usage(usage);
+  if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+    strncpy(salt.data, l40, salt.length);
+    salt.data[10]=ms_usage & 0xff;
+    salt.data[11]=(ms_usage>>8) & 0xff;
+    salt.data[12]=(ms_usage>>16) & 0xff;
+    salt.data[13]=(ms_usage>>24) & 0xff;
+  } else {
+    salt.length=4;
+    salt.data[0]=ms_usage & 0xff;
+    salt.data[1]=(ms_usage>>8) & 0xff;
+    salt.data[2]=(ms_usage>>16) & 0xff;
+    salt.data[3]=(ms_usage>>24) & 0xff;
+  }
+  ret=krb5_hmac(hash, key, 1, &salt, &d1);
+  if (ret)
+    goto cleanup;
+
+  memcpy(k2.contents, k1.contents, k2.length);
+
+  if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
+    memset(k1.contents+7, 0xab, 9);
+  
+  ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
+  if (ret)
+    goto cleanup;
+
+  ret=(*(enc->decrypt))(&k3, ivec, &ciphertext, &plaintext);
+  if (ret)
+    goto cleanup;
+
+  ret=krb5_hmac(hash, &k2, 1, &plaintext, &d1);
+  if (ret)
+    goto cleanup;
+
+  if (memcmp(checksum.data, d1.data, hashsize) != 0) {
+    ret=KRB5KRB_AP_ERR_BAD_INTEGRITY;
+    goto cleanup;
+  }
+
+  memcpy(output->data, plaintext.data+CONFOUNDERLENGTH,
+	 (plaintext.length-CONFOUNDERLENGTH));
+  output->length=plaintext.length-CONFOUNDERLENGTH;
+
+ cleanup:
+  memset(d1.data, 0, d1.length);
+  memset(d2.data, 0, d2.length);
+  memset(d3.data, 0, d2.length);
+  memset(salt.data, 0, salt.length);
+  memset(plaintext.data, 0, plaintext.length);
+
+  free(d1.data);
+  free(d2.data);
+  free(d3.data);
+  free(salt.data);
+  free(plaintext.data);
+  return (ret);
+}
+
diff --git a/mechglue/src/lib/crypto/arcfour/arcfour.h b/mechglue/src/lib/crypto/arcfour/arcfour.h
new file mode 100644
index 000000000..c6e435334
--- /dev/null
+++ b/mechglue/src/lib/crypto/arcfour/arcfour.h
@@ -0,0 +1,36 @@
+#ifndef ARCFOUR_H
+#define ARCFOUR_H
+
+extern void
+krb5_arcfour_encrypt_length(const struct krb5_enc_provider *,
+			const struct krb5_hash_provider *,
+			size_t,
+			size_t *);
+
+extern 
+krb5_error_code krb5_arcfour_encrypt(const struct krb5_enc_provider *,
+			const struct krb5_hash_provider *,
+			const krb5_keyblock *,
+			krb5_keyusage,
+			const krb5_data *,
+     			const krb5_data *,
+			krb5_data *);
+
+extern 
+krb5_error_code krb5_arcfour_decrypt(const struct krb5_enc_provider *,
+			const struct krb5_hash_provider *,
+			const krb5_keyblock *,
+			krb5_keyusage,
+			const krb5_data *,
+			const krb5_data *,
+			krb5_data *);
+
+extern krb5_error_code krb5int_arcfour_string_to_key(
+     const struct krb5_enc_provider *,
+     const krb5_data *,
+     const krb5_data *,
+     const krb5_data *,
+     krb5_keyblock *);
+
+extern const struct krb5_enc_provider krb5int_enc_arcfour;
+#endif /* ARCFOUR_H */
diff --git a/mechglue/src/lib/crypto/arcfour/arcfour_s2k.c b/mechglue/src/lib/crypto/arcfour/arcfour_s2k.c
new file mode 100644
index 000000000..efa92bfb1
--- /dev/null
+++ b/mechglue/src/lib/crypto/arcfour/arcfour_s2k.c
@@ -0,0 +1,70 @@
+#include "k5-int.h"
+#include "rsa-md4.h"
+#include "arcfour-int.h"
+
+static void asctouni(unsigned char *unicode, unsigned char *ascii, size_t len)
+{
+	size_t counter;
+	for (counter=0;counter<len;counter++) {
+		unicode[2*counter]=ascii[counter];
+		unicode[2*counter + 1]=0x00;
+	}
+}
+
+krb5_error_code
+krb5int_arcfour_string_to_key(const struct krb5_enc_provider *enc,
+			      const krb5_data *string, const krb5_data *salt,
+			      const krb5_data *params, krb5_keyblock *key)
+{
+  size_t len,slen;
+  unsigned char *copystr;
+  krb5_MD4_CTX md4_context;
+
+  if (params != NULL)
+      return KRB5_ERR_BAD_S2K_PARAMS;
+  
+  if (key->length != 16)
+    return (KRB5_BAD_MSIZE);
+
+  /* We ignore salt per the Microsoft spec*/
+
+  /* compute the space needed for the new string.
+     Since the password must be stored in unicode, we need to increase
+     that number by 2x.
+
+     This should be re-evauated in the future, it makes the assumption that
+     thes user's password is in ascii.
+  */
+  slen = ((string->length)>128)?128:string->length;
+  len=(slen)*2;
+
+  copystr = malloc(len);
+  if (copystr == NULL)
+    return ENOMEM;
+
+  /* make the string.  start by creating the unicode version of the password*/
+  asctouni(copystr, string->data, slen );
+
+  /* the actual MD4 hash of the data */
+  krb5_MD4Init(&md4_context);
+  krb5_MD4Update(&md4_context, (unsigned char *)copystr, len);
+  krb5_MD4Final(&md4_context);
+  memcpy(key->contents, md4_context.digest, 16);
+
+#if 0  
+  /* test the string_to_key function */
+  printf("Hash=");
+  {
+    int counter;
+    for(counter=0;counter<16;counter++)
+      printf("%02x", md4_context.digest[counter]);
+    printf("\n");
+  }
+#endif /* 0 */
+
+  /* Zero out the data behind us */
+  memset (copystr, 0, len);
+  memset(&md4_context, 0, sizeof(md4_context));
+  free(copystr);
+  return 0;
+}
diff --git a/mechglue/src/lib/crypto/block_size.c b/mechglue/src/lib/crypto/block_size.c
new file mode 100644
index 000000000..e4c11e869
--- /dev/null
+++ b/mechglue/src/lib/crypto/block_size.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_block_size(krb5_context context, krb5_enctype enctype,
+		  size_t *blocksize)
+{
+    int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    *blocksize = krb5_enctypes_list[i].enc->block_size;
+
+    return(0);
+}
diff --git a/mechglue/src/lib/crypto/checksum_length.c b/mechglue/src/lib/crypto/checksum_length.c
new file mode 100644
index 000000000..16177be09
--- /dev/null
+++ b/mechglue/src/lib/crypto/checksum_length.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_checksum_length(krb5_context context, krb5_cksumtype cksumtype,
+		       size_t *length)
+{
+    int i;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if (krb5_cksumtypes_list[i].ctype == cksumtype)
+	    break;
+    }
+
+    if (i == krb5_cksumtypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    if (krb5_cksumtypes_list[i].keyhash)
+	*length = krb5_cksumtypes_list[i].keyhash->hashsize;
+    else if (krb5_cksumtypes_list[i].trunc_size)
+	*length = krb5_cksumtypes_list[i].trunc_size;
+    else
+	*length = krb5_cksumtypes_list[i].hash->hashsize;
+
+    return(0);
+}
+	
diff --git a/mechglue/src/lib/crypto/cksumtype_to_string.c b/mechglue/src/lib/crypto/cksumtype_to_string.c
new file mode 100644
index 000000000..b0ac516e2
--- /dev/null
+++ b/mechglue/src/lib/crypto/cksumtype_to_string.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_cksumtype_to_string(krb5_cksumtype cksumtype, char *buffer, size_t buflen)
+{
+    int i;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if (krb5_cksumtypes_list[i].ctype == cksumtype) {
+	    if ((strlen(krb5_cksumtypes_list[i].out_string)+1) > buflen)
+		return(ENOMEM);
+
+	    strcpy(buffer, krb5_cksumtypes_list[i].out_string);
+	    return(0);
+	}
+    }
+
+    return(EINVAL);
+}
diff --git a/mechglue/src/lib/crypto/cksumtypes.c b/mechglue/src/lib/crypto/cksumtypes.c
new file mode 100644
index 000000000..ae7ed5f87
--- /dev/null
+++ b/mechglue/src/lib/crypto/cksumtypes.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "hash_provider.h"
+#include "keyhash_provider.h"
+#include "cksumtypes.h"
+
+const struct krb5_cksumtypes krb5_cksumtypes_list[] = {
+    { CKSUMTYPE_CRC32, KRB5_CKSUMFLAG_NOT_COLL_PROOF,
+      "crc32", "CRC-32",
+      0, NULL,
+      &krb5int_hash_crc32 },
+
+    { CKSUMTYPE_RSA_MD4, 0,
+      "md4", "RSA-MD4",
+      0, NULL,
+      &krb5int_hash_md4 },
+    { CKSUMTYPE_RSA_MD4_DES, 0,
+      "md4-des", "RSA-MD4 with DES cbc mode",
+      ENCTYPE_DES_CBC_CRC, &krb5int_keyhash_md4des,
+      NULL },
+
+    { CKSUMTYPE_DESCBC, 0,
+      "des-cbc", "DES cbc mode",
+      ENCTYPE_DES_CBC_CRC, &krb5int_keyhash_descbc,
+      NULL },
+
+    { CKSUMTYPE_RSA_MD5, 0,
+      "md5", "RSA-MD5",
+      0, NULL,
+      &krb5int_hash_md5 },
+    { CKSUMTYPE_RSA_MD5_DES, 0,
+      "md5-des", "RSA-MD5 with DES cbc mode",
+      ENCTYPE_DES_CBC_CRC, &krb5int_keyhash_md5des,
+      NULL },
+
+    { CKSUMTYPE_NIST_SHA, 0,
+      "sha", "NIST-SHA",
+      0, NULL,
+      &krb5int_hash_sha1 },
+
+    { CKSUMTYPE_HMAC_SHA1_DES3, KRB5_CKSUMFLAG_DERIVE,
+      "hmac-sha1-des3", "HMAC-SHA1 DES3 key",
+      0, NULL,
+      &krb5int_hash_sha1 },
+    { CKSUMTYPE_HMAC_SHA1_DES3, KRB5_CKSUMFLAG_DERIVE,
+      "hmac-sha1-des3-kd", "HMAC-SHA1 DES3 key", /* alias */
+      0, NULL,
+      &krb5int_hash_sha1 },
+    { CKSUMTYPE_HMAC_MD5_ARCFOUR, 0,
+      "hmac-md5-rc4", "Microsoft HMAC MD5 (RC4 key)", 
+      ENCTYPE_ARCFOUR_HMAC, &krb5int_keyhash_hmac_md5,
+      NULL },
+    { CKSUMTYPE_HMAC_MD5_ARCFOUR, 0,
+      "hmac-md5-enc", "Microsoft HMAC MD5 (RC4 key)",  /*Heimdal alias*/
+      ENCTYPE_ARCFOUR_HMAC, &krb5int_keyhash_hmac_md5,
+      NULL },
+    { CKSUMTYPE_HMAC_MD5_ARCFOUR, 0,
+      "hmac-md5-earcfour", "Microsoft HMAC MD5 (RC4 key)",  /* alias*/
+      ENCTYPE_ARCFOUR_HMAC, &krb5int_keyhash_hmac_md5,
+      NULL },
+
+    { CKSUMTYPE_HMAC_SHA1_96_AES128, KRB5_CKSUMFLAG_DERIVE,
+      "hmac-sha1-96-aes128", "HMAC-SHA1 AES128 key",
+      0, NULL, 
+      &krb5int_hash_sha1, 12 },
+    { CKSUMTYPE_HMAC_SHA1_96_AES256, KRB5_CKSUMFLAG_DERIVE,
+      "hmac-sha1-96-aes256", "HMAC-SHA1 AES256 key",
+      0, NULL, 
+      &krb5int_hash_sha1, 12 },
+};
+
+const int krb5_cksumtypes_length =
+sizeof(krb5_cksumtypes_list)/sizeof(struct krb5_cksumtypes);
diff --git a/mechglue/src/lib/crypto/cksumtypes.h b/mechglue/src/lib/crypto/cksumtypes.h
new file mode 100644
index 000000000..dae70c8f2
--- /dev/null
+++ b/mechglue/src/lib/crypto/cksumtypes.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_cksumtypes krb5_cksumtypes_list[];
+extern const int krb5_cksumtypes_length;
diff --git a/mechglue/src/lib/crypto/coll_proof_cksum.c b/mechglue/src/lib/crypto/coll_proof_cksum.c
new file mode 100644
index 000000000..5c3ea48d3
--- /dev/null
+++ b/mechglue/src/lib/crypto/coll_proof_cksum.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_boolean KRB5_CALLCONV
+krb5_c_is_coll_proof_cksum(krb5_cksumtype ctype)
+{
+    int i;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if (krb5_cksumtypes_list[i].ctype == ctype)
+	    return((krb5_cksumtypes_list[i].flags &
+		    KRB5_CKSUMFLAG_NOT_COLL_PROOF)?0:1);
+    }
+
+    /* ick, but it's better than coredumping, which is what the
+       old code would have done */
+    return(0);
+}
+
+krb5_boolean KRB5_CALLCONV
+is_coll_proof_cksum(krb5_cksumtype ctype)
+{
+    return krb5_c_is_coll_proof_cksum (ctype);
+}
diff --git a/mechglue/src/lib/crypto/combine_keys.c b/mechglue/src/lib/crypto/combine_keys.c
new file mode 100644
index 000000000..3d9765164
--- /dev/null
+++ b/mechglue/src/lib/crypto/combine_keys.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2002 Naval Research Laboratory (NRL/CCS)
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the software,
+ * derivative works or modified versions, and any portions thereof.
+ * 
+ * NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
+ * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Key combination function.
+ *
+ * If Key1 and Key2 are two keys to be combined, the algorithm to combine
+ * them is as follows.
+ *
+ * Definitions:
+ *
+ * k-truncate is defined as truncating to the key size the input.
+ *
+ * DR is defined as the generate "random" data from a key
+ * (defined in crypto draft)
+ *
+ * DK is defined as the key derivation function (krb5_derive_key())
+ *
+ * (note: | means "concatenate")
+ *
+ * Combine key algorithm:
+ *
+ * R1 = DR(Key1, n-fold(Key2)) [ Output is length of Key1 ]
+ * R2 = DR(Key2, n-fold(Key1)) [ Output is length of Key2 ]
+ *
+ * rnd = n-fold(R1 | R2) [ Note: output size of nfold must be appropriately
+ *			   sized for random-to-key function ]
+ * tkey = random-to-key(rnd)
+ * Combine-Key(Key1, Key2) = DK(tkey, CombineConstant)
+ *
+ * CombineConstant is defined as the byte string:
+ *
+ * { 0x63 0x6f 0x6d 0x62 0x69 0x6e 0x65 }, which corresponds to the
+ * ASCII encoding of the string "combine"
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include "dk.h"
+
+static krb5_error_code dr
+(const struct krb5_enc_provider *enc, const krb5_keyblock *inkey,
+		unsigned char *outdata, const krb5_data *in_constant);
+
+/*
+ * We only support this combine_keys algorithm for des and 3des keys.
+ * Everything else should use the PRF defined in the crypto framework.
+ * We don't implement that yet.
+ */
+
+static krb5_boolean  enctype_ok (krb5_enctype e) 
+{
+    switch (e) {
+    case ENCTYPE_DES_CBC_CRC:
+    case ENCTYPE_DES_CBC_MD4:
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES3_CBC_SHA1:
+	return 1;
+    default:
+	return 0;
+    }
+}
+
+krb5_error_code krb5int_c_combine_keys
+(krb5_context context, krb5_keyblock *key1, krb5_keyblock *key2, krb5_keyblock *outkey)
+{
+    unsigned char *r1, *r2, *combined, *rnd, *output;
+    size_t keybytes, keylength;
+    const struct krb5_enc_provider *enc;
+    krb5_data input, randbits;
+    krb5_keyblock tkey;
+    krb5_error_code ret;
+    int i, myalloc = 0;
+    if (!(enctype_ok(key1->enctype)&&enctype_ok(key2->enctype)))
+	return (KRB5_CRYPTO_INTERNAL);
+    
+
+    if (key1->length != key2->length || key1->enctype != key2->enctype)
+	return (KRB5_CRYPTO_INTERNAL);
+
+    /*
+     * Find our encryption algorithm
+     */
+
+    for (i = 0; i < krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == key1->enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return (KRB5_BAD_ENCTYPE);
+
+    enc = krb5_enctypes_list[i].enc;
+
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    /*
+     * Allocate and set up buffers
+     */
+
+    if ((r1 = (unsigned char *) malloc(keybytes)) == NULL)
+	return (ENOMEM);
+
+    if ((r2 = (unsigned char *) malloc(keybytes)) == NULL) {
+	free(r1);
+	return (ENOMEM);
+    }
+
+    if ((rnd = (unsigned char *) malloc(keybytes)) == NULL) {
+	free(r1);
+	free(r2);
+	return (ENOMEM);
+    }
+
+    if ((combined = (unsigned char *) malloc(keybytes * 2)) == NULL) {
+	free(r1);
+	free(r2);
+	free(rnd);
+	return (ENOMEM);
+    }
+
+    if ((output = (unsigned char *) malloc(keylength)) == NULL) {
+	free(r1);
+	free(r2);
+	free(rnd);
+	free(combined);
+	return (ENOMEM);
+    }
+
+    /*
+     * Get R1 and R2 (by running the input keys through the DR algorithm.
+     * Note this is most of derive-key, but not all.
+     */
+
+    input.length = key2->length;
+    input.data = (char *) key2->contents;
+    if ((ret = dr(enc, key1, r1, &input)))
+	goto cleanup;
+
+#if 0
+    {
+	int i;
+	printf("R1 =");
+	for (i = 0; i < keybytes; i++)
+	    printf(" %02x", (unsigned char) r1[i]);
+	printf("\n");
+    }
+#endif
+
+    input.length = key1->length;
+    input.data = (char *) key1->contents;
+    if ((ret = dr(enc, key2, r2, &input)))
+	goto cleanup;
+
+#if 0
+    {
+	int i;
+	printf("R2 =");
+	for (i = 0; i < keybytes; i++)
+	    printf(" %02x", (unsigned char) r2[i]);
+	printf("\n");
+    }
+#endif
+
+    /*
+     * Concatenate the two keys together, and then run them through
+     * n-fold to reduce them to a length appropriate for the random-to-key
+     * operation.  Note here that krb5_nfold() takes sizes in bits, hence
+     * the multiply by 8.
+     */
+
+    memcpy(combined, r1, keybytes);
+    memcpy(combined + keybytes, r2, keybytes);
+
+    krb5_nfold((keybytes * 2) * 8, combined, keybytes * 8, rnd);
+
+#if 0
+    {
+	int i;
+	printf("rnd =");
+	for (i = 0; i < keybytes; i++)
+	    printf(" %02x", (unsigned char) rnd[i]);
+	printf("\n");
+    }
+#endif
+
+    /*
+     * Run the "random" bits through random-to-key to produce a encryption
+     * key.
+     */
+
+    randbits.length = keybytes;
+    randbits.data = (char *) rnd;
+    tkey.length = keylength;
+    tkey.contents = output;
+
+    if ((ret = (*(enc->make_key))(&randbits, &tkey)))
+	goto cleanup;
+
+#if 0
+    {
+	int i;
+	printf("tkey =");
+	for (i = 0; i < tkey.length; i++)
+	    printf(" %02x", (unsigned char) tkey.contents[i]);
+	printf("\n");
+    }
+#endif
+
+    /*
+     * Run through derive-key one more time to produce the final key.
+     * Note that the input to derive-key is the ASCII string "combine".
+     */
+
+    input.length = 7; /* Note; change this if string length changes */
+    input.data = "combine";
+
+    /*
+     * Just FYI: _if_ we have space here in the key, then simply use it
+     * without modification.  But if the key is blank (no allocated storage)
+     * then allocate some memory for it.  This allows programs to use one of
+     * the existing keys as the output key, _or_ pass in a blank keyblock
+     * for us to allocate.  It's easier for us to allocate it since we already
+     * know the crypto library internals
+     */
+
+    if (outkey->length == 0 || outkey->contents == NULL) {
+	outkey->contents = (krb5_octet *) malloc(keylength);
+	if (!outkey->contents) {
+	    ret = ENOMEM;
+	    goto cleanup;
+	}
+	outkey->length = keylength;
+	outkey->enctype = key1->enctype;
+	myalloc = 1;
+    }
+
+    if ((ret = krb5_derive_key(enc, &tkey, outkey, &input))) {
+	if (myalloc) {
+	    free(outkey->contents);
+	    outkey->contents = NULL;
+	}
+	goto cleanup;
+    }
+
+#if 0
+    {
+	int i;
+	printf("output =");
+	for (i = 0; i < outkey->length; i++)
+	    printf(" %02x", (unsigned char) outkey->contents[i]);
+	printf("\n");
+    }
+#endif
+
+    ret = 0;
+
+cleanup:
+    memset(r1, 0, keybytes);
+    memset(r2, 0, keybytes);
+    memset(rnd, 0, keybytes);
+    memset(combined, 0, keybytes * 2);
+    memset(output, 0, keylength);
+
+    free(r1);
+    free(r2);
+    free(rnd);
+    free(combined);
+    free(output);
+
+    return (ret);
+}
+
+/*
+ * Our DR function; mostly taken from derive.c
+ */
+
+static krb5_error_code dr
+(const struct krb5_enc_provider *enc, const krb5_keyblock *inkey, unsigned char *out, const krb5_data *in_constant)
+{
+    size_t blocksize, keybytes, keylength, n;
+    unsigned char *inblockdata, *outblockdata;
+    krb5_data inblock, outblock;
+
+    blocksize = enc->block_size;
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    /* allocate and set up buffers */
+
+    if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL)
+	return(ENOMEM);
+
+    if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) {
+	free(inblockdata);
+	return(ENOMEM);
+    }
+
+    inblock.data = (char *) inblockdata;
+    inblock.length = blocksize;
+
+    outblock.data = (char *) outblockdata;
+    outblock.length = blocksize;
+
+    /* initialize the input block */
+
+    if (in_constant->length == inblock.length) {
+	memcpy(inblock.data, in_constant->data, inblock.length);
+    } else {
+	krb5_nfold(in_constant->length*8, (unsigned char *) in_constant->data,
+		   inblock.length*8, (unsigned char *) inblock.data);
+    }
+
+    /* loop encrypting the blocks until enough key bytes are generated */
+
+    n = 0;
+    while (n < keybytes) {
+	(*(enc->encrypt))(inkey, 0, &inblock, &outblock);
+
+	if ((keybytes - n) <= outblock.length) {
+	    memcpy(out+n, outblock.data, (keybytes - n));
+	    break;
+	}
+
+	memcpy(out+n, outblock.data, outblock.length);
+	memcpy(inblock.data, outblock.data, outblock.length);
+	n += outblock.length;
+    }
+
+    /* clean memory, free resources and exit */
+
+    memset(inblockdata, 0, blocksize);
+    memset(outblockdata, 0, blocksize);
+
+    free(outblockdata);
+    free(inblockdata);
+
+    return(0);
+}
+
diff --git a/mechglue/src/lib/crypto/configure.in b/mechglue/src/lib/crypto/configure.in
new file mode 100644
index 000000000..d663bf73b
--- /dev/null
+++ b/mechglue/src/lib/crypto/configure.in
@@ -0,0 +1,11 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+
+AC_CHECK_HEADERS(memory.h unistd.h endian.h machine/endian.h)
+
+KRB5_RUN_FLAGS
+KRB5_BUILD_PROGRAM
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+
+V5_AC_OUTPUT_MAKEFILE(. crc32 des dk enc_provider hash_provider keyhash_provider md4 md5 old raw sha1 arcfour yarrow aes)
diff --git a/mechglue/src/lib/crypto/crc32/.Sanitize b/mechglue/src/lib/crypto/crc32/.Sanitize
new file mode 100644
index 000000000..056f83445
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/.Sanitize
@@ -0,0 +1,40 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+crc-32.h
+crc-test
+crc.c
+crctest.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/crypto/crc32/CRC.pm b/mechglue/src/lib/crypto/crc32/CRC.pm
new file mode 100644
index 000000000..ee2ab2ae8
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/CRC.pm
@@ -0,0 +1,156 @@
+# Copyright 2002 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+
+package CRC;
+
+# CRC: implement a CRC using the Poly package (yes this is slow)
+#
+# message M(x) = m_0 * x^0 + m_1 * x^1 + ... + m_(k-1) * x^(k-1)
+# generator P(x) = p_0 * x^0 + p_1 * x^1 + ... + p_n * x^n
+# remainder R(x) = r_0 * x^0 + r_1 * x^1 + ... + r_(n-1) * x^(n-1)
+#
+# R(x) = (x^n * M(x)) % P(x)
+#
+# Note that if F(x) = x^n * M(x) + R(x), then F(x) = 0 mod P(x) .
+#
+# In MIT Kerberos 5, R(x) is taken as the CRC, as opposed to what
+# ISO 3309 does.
+#
+# ISO 3309 adds a precomplement and a postcomplement.
+#
+# The ISO 3309 postcomplement is of the form
+#
+# A(x) = x^0 + x^1 + ... + x^(n-1) .
+#
+# The ISO 3309 precomplement is of the form
+#
+# B(x) = x^k * A(x) .
+#
+# The ISO 3309 FCS is then
+#
+# (x^n * M(x)) % P(x) + B(x) % P(x) + A(x) ,
+#
+# which is equivalent to
+#
+# (x^n * M(x) + B(x)) % P(x) + A(x) .
+#
+# In ISO 3309, the transmitted frame is
+#
+# F'(x) = x^n * M(x) + R(x) + R'(x) + A(x) ,
+#
+# where
+#
+# R'(x) = B(x) % P(x) .
+#
+# Note that this means that if a new remainder is computed over the
+# frame F'(x) (treating F'(x) as the new M(x)), it will be equal to a
+# constant.
+#
+# F'(x) = 0 + R'(x) + A(x) mod P(x) ,
+#
+# then
+#
+# (F'(x) + x^k * A(x)) * x^n
+#
+# = ((R'(x) + A(x)) + x^k * A(x)) * x^n mod P(x)
+#
+# = (x^k * A(x) + A(x) + x^k * A(x)) * x^n mod P(x)
+#
+# = (0 + A(x)) * x^n mod P(x)
+#
+# Note that (A(x) * x^n) % P(x) is a constant, and that this result
+# depends on B(x) being x^k * A(x).
+
+use Carp;
+use Poly;
+
+sub new {
+    my $self = shift;
+    my $class = ref($self) || $self;
+    my %args = @_;
+    $self = {bitsendian => "little"};
+    bless $self, $class;
+    $self->setpoly($args{"Poly"}) if exists $args{"Poly"};
+    $self->bitsendian($args{"bitsendian"})
+	if exists $args{"bitsendian"};
+    $self->{precomp} = $args{precomp} if exists $args{precomp};
+    $self->{postcomp} = $args{postcomp} if exists $args{postcomp};
+    return $self;
+}
+
+sub setpoly {
+    my $self = shift;
+    my($arg) = @_;
+    croak "need a polynomial" if !$arg->isa("Poly");
+    $self->{Poly} = $arg;
+    return $self;
+}
+
+sub crc {
+    my $self = shift;
+    my $msg = Poly->new(@_);
+    my($order, $r, $precomp);
+    $order = $self->{Poly}->order;
+    # B(x) = x^k * precomp
+    $precomp = $self->{precomp} ?
+	$self->{precomp} * Poly->powers2poly(scalar(@_)) : Poly->new;
+    # R(x) = (x^n * M(x)) % P(x)
+    $r = ($msg * Poly->powers2poly($order)) % $self->{Poly};
+    # B(x) % P(x)
+    $r += $precomp % $self->{Poly};
+    $r += $self->{postcomp} if exists $self->{postcomp};
+    return $r;
+}
+
+# endianness of bits of each octet
+#
+# Note that the message is always treated as being sent in big-endian
+# octet order.
+#
+# Usually, the message will be treated as bits being little-endian,
+# since that is the common case for serial implementations that
+# present data in octets; e.g., most UARTs shift octets onto the line
+# in little-endian order, and protocols such as ISO 3309, V.42,
+# etc. treat individual octets as being sent LSB-first.
+
+sub bitsendian {
+    my $self = shift;
+    my($arg) = @_;
+    croak "bad bit endianness" if $arg !~ /big|little/;
+    $self->{bitsendian} = $arg;
+    return $self;
+}
+
+sub crcstring {
+    my $self = shift;
+    my($arg) = @_;
+    my($packstr, @m);
+    {
+	$packstr = "B*", last if $self->{bitsendian} =~ /big/;
+	$packstr = "b*", last if $self->{bitsendian} =~ /little/;
+	croak "bad bit endianness";
+    };
+    @m = split //, unpack $packstr, $arg;
+    return $self->crc(@m);
+}
+
+1;
diff --git a/mechglue/src/lib/crypto/crc32/ChangeLog b/mechglue/src/lib/crypto/crc32/ChangeLog
new file mode 100644
index 000000000..a61fb7966
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/ChangeLog
@@ -0,0 +1,254 @@
+2005-12-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_crc): Build against support library.
+	(check-unix): Use $(RUN_SETUP).
+
+2005-05-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_crc.c (main): Don't run timing test for now.
+
+2005-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* crc-32.h (mit_crc32): Remove gratuitous "const" in argument
+	declaration.
+
+2004-03-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_crc.c (timetest): Free 'block' before returning.
+	(verify): Fix minor type error in call to gethexstr.
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* crc32.c: Use ANSI C style function definitions.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* t_crc.c: Declare local functions static. 
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-19  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (clean-unix): Remove t_crc.o and t_crc.
+
+2002-01-07  Tom Yu  <tlyu@mit.edu>
+
+	* crc.pl: New file; perl script to do generate some test vectors
+	and CRC tables.
+
+	* CRC.pm: New file; perl module to implement CRCs in terms of
+	polynomial arithmetic (verrrry slooow).
+
+	* Poly.pm: New file; perl module to do polynomial arithmetic in
+	the field of integers mod 2.
+
+	* t_crc.c: New file; do some sanity checks (and timing checks,
+	more useful when building shift-4 as well).
+
+	* Makefile.in (check-unix): Add rules for building, running
+	t_crc.
+
+	* crc32.c (mit_crc32_shift4): Add new function, usually not
+	compiled, for shift-4 implementation of CRC32.
+
+	* crc-32.h: Add (conditionalized) prototype for the shift-4
+	function; remove checksum_entry (it's no longer used).
+
+	* crctest.c: Removed.
+
+	* crc-test: Removed.
+
+	* crc.c: Removed.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* crc.c: Make prototypes unconditional.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* crc.c: Don't declare pointers FAR any more.
+
+2001-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* crc-32.h: Stop using PROTOTYPE macro.
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* crc-32.h, crc.c, crc32.c: Use const instead of krb5_const.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:15:59 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Sun Jul 19 12:00:00 1998  Marc Horowitz <marc@mit.edu>
+
+	* *.c: replace the crypto layer.
+
+Wed Feb 18 16:05:45 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.  Fix up usage of $(C).
+
+Fri Feb 13 15:20:54 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (thisconfigdir), configure.in: Point the
+ 		configuration directory at our parent, and remove our
+		local configure.in
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sat Feb 22 18:46:38 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Move list file construction to win-post.in
+
+Thu Jan 30 21:30:32 1997  Richard Basch  <basch@lehman.com>
+
+	* crc.c: Declare the functions to take const pointers, where possible.
+
+Thu Nov 21 00:58:04 EST 1996    Richard Basch   <basch@lehman.com>
+
+	* Makefile.in: Win32 build
+
+Sun Dec 29 21:53:25 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to use new library building procedure.
+
+Tue May 14 19:33:27 1996  Richard Basch  <basch@lehman.com>
+
+	* crc.c: ensure the cksum content length is sufficient
+
+	* crctest.c: set the cksum length field.
+
+Sat Mar 30 22:54:12 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS): Removed crctest.c from the SRCS list, since
+		it's only a test program and it confuses the Macintosh build.
+
+Fri Oct  6 21:59:30 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (CFLAGS): Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:48:23 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 13 10:28:47 1995 Keith Vetter (keithv@fusion.com)
+
+	* crc.c: put function prototype back in.
+
+Fri Jul 7 16:10:52 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* crc.c - Use CRC32_CKSUM_LENGTH where appropriate.  Add checksum
+		verifier procedure.
+
+Wed Jun 21 10:51:33 1995    <tytso@rsx-11.mit.edu>
+
+	* crc.c: Change PROTOTYPE -> KRB5_PROTOTYPE
+
+Fri Jun  9 19:18:36 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu May 25 22:15:49 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for shared libraries.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+        * *.h added FAR to pointers visible at to the world.
+
+Thu Mar 16 21:14:15 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (crctest, crctest.exe):  Replace crctest-unix and
+	crctest-windows with versions that work for Mac too.
+	(check):  Build and run crctest$(EXEEXT).  This runs on MPW now.
+
+Tue Mar 14 17:20:47 1995 Keith Vetter (keithv@fusion.com)
+
+	* crc.c: removed method for pulling in a data structure (windows),
+           and turned an int into a size_t for corrected 'signed'ness.
+
+Fri Mar 3 19:01:59 1995 Keith Vetter (keithv@fusion.com)
+
+	* crc.c: added a method to pull in a data structure 
+           from outside a dll.
+
+Thu Mar 2 17:48:08 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed LIBNAME for the PC
+        * crc.c, crctest.c: added cast on the assignment of bits of
+           a long into characters.
+
+Mon Feb 20 15:37:10 1995 Keith Vetter (keithv@fusion.com)
+
+	* crc.c: changed API to INTERFACE
+
+Fri Feb 20 11:08:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* crc.c: added function prototype and removed a function
+	   pointer cast.
+
+Mon Feb 6 19:24:13 1995 Keith Vetter (keithv@fusion.com)
+
+        * Makefile.in: made to work under Windows
+           - added windows only make preamble 
+           - moved the all target after the objects it depends on
+           - used $(OBJEXT) and $(EXEEXT) where needed
+           - split crctest into unix rules and windows rules
+           - changed file separatars into macros where needed
+        * crctest.c: changed int to long to work on 16 bit machines
+        * crc.c: added Windows calling convention to the function
+           and casted the assignment of the function.
+
+
+Wed Jan 25 20:01:33 1995  John Gilmore  (gnu at toad.com)
+
+	* crc-32.h:  New file, moved from include/krb5/crc-32.h.
+	* crc.c, crctest.c:  Replace <.../...> includes with "..."s.
+
+Wed Oct 19 12:27:16 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+    	* Makefile.in: Don't use LDFLAGS, but CCFLAGS since CCFLAGS is
+		configurable.
+
+Wed Oct 12 02:24:04 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Run crctest on a "make check".  Clean up the
+		crctest program on a "make clean".
+
+Tue Oct  4 14:53:54 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* crc.c: Added placeholder for magic number
+
diff --git a/mechglue/src/lib/crypto/crc32/Makefile.in b/mechglue/src/lib/crypto/crc32/Makefile.in
new file mode 100644
index 000000000..bf56c76e0
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/Makefile.in
@@ -0,0 +1,52 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/crc32
+mydir=crc32
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=crc32
+##DOS##OBJFILE=..\$(OUTPRE)crc32.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= crc32.o
+
+OBJS= $(OUTPRE)crc32.$(OBJEXT) 
+
+SRCS= $(srcdir)/crc32.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+	$(RM) t_crc.o t_crc
+
+check-unix:: t_crc
+	$(RUN_SETUP) ./t_crc
+
+t_crc: t_crc.o crc32.o $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_crc.o crc32.o $(SUPPORT_LIB)
+
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+crc32.so crc32.po $(OUTPRE)crc32.$(OBJEXT): crc32.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  crc-32.h
diff --git a/mechglue/src/lib/crypto/crc32/Poly.pm b/mechglue/src/lib/crypto/crc32/Poly.pm
new file mode 100644
index 000000000..cad0f77b5
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/Poly.pm
@@ -0,0 +1,182 @@
+# Copyright 2002 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+
+package Poly;
+
+# Poly: implements some basic operations on polynomials in the field
+# of integers (mod 2).
+#
+# The rep is an array of coefficients, highest order term first.
+#
+# This is rather slow at the moment.
+
+use overload
+    '+' => \&add,
+    '-' => \&add,
+    '*' => \&mul,
+    '%' => sub {$_[2] ? mod($_[1], $_[0]) : mod($_[0], $_[1])},
+    '/' => sub { $_[2] ? scalar(div($_[1], $_[0]))
+		     : scalar(div($_[0], $_[1])) },
+    '<=>' => sub {$_[2] ? pcmp($_[1], $_[0]) : pcmp($_[0], $_[1])},
+    '""' => \&str
+;
+
+use Carp;
+
+# doesn't do much beyond normalize and bless
+sub new {
+    my $this = shift;
+    my $class = ref($this) || $this;
+    my(@x) = @_;
+    return bless [norm(@x)], $class;
+}
+
+# stringified P(x)
+sub pretty {
+    my(@x) = @{+shift};
+    my $n = @x;
+    local $_;
+    return "0" if !@x;
+    return join " + ", map {$n--; $_ ? ("x^$n") : ()} @x;
+}
+
+sub print {
+    my $self = shift;
+    print $self->pretty, "\n";
+}
+
+# This assumes normalization.
+sub order {
+    my $self = shift;
+    return $#{$self};
+}
+
+sub str {
+    return overload::StrVal($_[0]);
+}
+
+# strip leading zero coefficients
+sub norm {
+    my(@x) = @_;
+    shift @x while @x && !$x[0];
+    return @x;
+}
+
+# multiply $self by the single term of power $n
+sub multerm {
+    my($self, $n) = @_;
+    return $self->new(@$self, (0) x $n);
+}
+
+# This is really an order comparison; different polys of same order
+# compare equal.  It also assumes prior normalization.
+sub pcmp {
+    my @x = @{+shift};
+    my @y = @{+shift};
+    return @x <=> @y;
+}
+
+# convenience constructor; takes list of non-zero terms
+sub powers2poly
+{
+    my $self = shift;
+    my $poly = $self->new;
+    my $n;
+    foreach $n (@_) {
+	$poly += $one->multerm($n);
+    }
+    return $poly;
+}
+
+sub add {
+    my $self = shift;
+    my @x = @$self;
+    my @y = @{+shift};
+    my @r;
+    unshift @r, (pop @x || 0) ^ (pop @y || 0)
+	while @x || @y;
+    return $self->new(@r);
+}
+
+sub mul {
+    my($self) = shift;
+    my @y = @{+shift};
+    my $r = $self->new;
+    my $power = 0;
+    while (@y) {
+	$r += $self->multerm($power) if pop @y;
+	$power++;
+    }
+    return $r;
+}
+
+sub oldmod {
+    my($self, $div) = @_;
+    my @num = @$self;
+    my @div = @$div;
+    my $r = $self->new(splice @num, 0, @div);
+    do {
+	push @$r, shift @num while @num && $r < $div;
+	$r += $div if $r >= $div;
+    } while @num;
+    return $r;
+}
+
+sub div {
+    my($self, $div) = @_;
+    my $q = $self->new;
+    my $r = $self->new(@$self);
+    my $one = $self->new(1);
+    my ($tp, $power);
+    croak "divide by zero" if !@$div;
+    while ($div <= $r) {
+	$power = 0;
+	$power++ while ($tp = $div->multerm($power)) < $r;
+	$q += $one->multerm($power);
+	$r -= $tp;
+    }
+    return wantarray ? ($q, $r) : $q;
+}
+
+sub mod {
+    (&div)[1];
+}
+
+# bits and octets both big-endian
+sub hex {
+    my @x = @{+shift};
+    my $minwidth = shift || 32;
+    unshift @x, 0 while @x % 8 || @x < $minwidth;
+    return unpack "H*", pack "B*", join "", @x;
+}
+
+# bit-reversal of above
+sub revhex {
+    my @x = @{+shift};
+    my $minwidth = shift || 32;
+    unshift @x, 0 while @x % 8 || @x < $minwidth;
+    return unpack "H*", pack "B*", join "", reverse @x;
+}
+
+$one = Poly->new(1);
+
+1;
diff --git a/mechglue/src/lib/crypto/crc32/crc-32.h b/mechglue/src/lib/crypto/crc32/crc-32.h
new file mode 100644
index 000000000..10facaa58
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/crc-32.h
@@ -0,0 +1,71 @@
+/*
+ * include/krb5/crc-32.h
+ *
+ * Copyright 1989,1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Definitions for the CRC-32 checksum
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+#ifndef KRB5_CRC32__
+#define KRB5_CRC32__
+
+#define CRC32_CKSUM_LENGTH	4
+
+void
+mit_crc32 (const krb5_pointer in, size_t in_length, unsigned long *c);
+
+#ifdef CRC32_SHIFT4
+void mit_crc32_shift4(const krb5_pointer /* in */,
+		      const size_t /* in_length */,
+		      unsigned long * /* cksum */);
+#endif
+
+#endif /* KRB5_CRC32__ */
diff --git a/mechglue/src/lib/crypto/crc32/crc.pl b/mechglue/src/lib/crypto/crc32/crc.pl
new file mode 100644
index 000000000..b21b6b15d
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/crc.pl
@@ -0,0 +1,111 @@
+# Copyright 2002 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+
+use CRC;
+
+print "*** crudely testing polynomial functions ***\n";
+
+$x = Poly->new(1,1,1,1);
+$y = Poly->new(1,1);
+print "x = @{[$x->pretty]}\ny = @{[$y->pretty]}\n";
+$q = $x / $y;
+$r = $x % $y;
+print $x->pretty, " = (", $y->pretty , ") * (", $q->pretty,
+    ") + ", $r->pretty, "\n";
+$q = $y / $x;
+$r = $y % $x;
+print "y / x = @{[$q->pretty]}\ny % x = @{[$r->pretty]}\n";
+
+# ISO 3309 32-bit FCS polynomial
+$fcs32 = Poly->powers2poly(32,26,23,22,16,12,11,10,8,7,5,4,2,1,0);
+print "fcs32 = ", $fcs32->pretty, "\n";
+
+$crc = CRC->new(Poly => $fcs32, bitsendian => "little");
+
+print "\n";
+
+print "*** little endian, no complementation ***\n";
+for ($i = 0; $i < 256; $i++) {
+    $r = $crc->crcstring(pack "C", $i);
+    printf ("%02x: ", $i) if !($i % 8);
+    print ($r->revhex, ($i % 8 == 7) ? "\n" : " ");
+}
+
+print "\n";
+
+print "*** little endian, 4 bits, no complementation ***\n";
+for ($i = 0; $i < 16; $i++) {
+    @m = (split //, unpack "b*", pack "C", $i)[0..3];
+    $r = $crc->crc(@m);
+    printf ("%02x: ", $i) if !($i % 8);
+    print ($r->revhex, ($i % 8 == 7) ? "\n" : " ");
+}
+
+print "\n";
+
+print "*** test vectors for t_crc.c, little endian ***\n";
+for ($i = 1; $i <= 4; $i *=2) {
+    for ($j = 0; $j < $i * 8; $j++) {
+	@m = split //, unpack "b*", pack "V", 1 << $j;
+	splice @m, $i * 8;
+	$r = $crc->crc(@m);
+	$m = unpack "H*", pack "b*", join("", @m);
+	print "{HEX, \"$m\", 0x", $r->revhex, "},\n";
+    }
+}
+@m = ("foo", "test0123456789",
+      "MASSACHVSETTS INSTITVTE OF TECHNOLOGY");
+foreach $m (@m) {
+    $r = $crc->crcstring($m);
+    print "{STR, \"$m\", 0x", $r->revhex, "},\n";
+}
+__END__
+
+print "*** big endian, no complementation ***\n";
+for ($i = 0; $i < 256; $i++) {
+    $r = $crc->crcstring(pack "C", $i);
+    printf ("%02x: ", $i) if !($i % 8);
+    print ($r->hex, ($i % 8 == 7) ? "\n" : " ");
+}
+
+# all ones polynomial of order 31
+$ones = Poly->new((1) x 32);
+
+print "*** big endian, ISO-3309 style\n";
+$crc = CRC->new(Poly => $fcs32,
+		bitsendian => "little",
+		precomp => $ones,
+		postcomp => $ones);
+for ($i = 0; $i < 256; $i++) {
+    $r = $crc->crcstring(pack "C", $i);
+    print ($r->hex, ($i % 8 == 7) ? "\n" : " ");
+}
+
+for ($i = 0; $i < 0; $i++) {
+    $x = Poly->new((1) x 32, (0) x $i);
+    $y = Poly->new((1) x 32);
+    $f = ($x % $fcs32) + $y;
+    $r = (($f + $x) * Poly->powers2poly(32)) % $fcs32;
+    @out = @$r;
+    unshift @out, 0 while @out < 32;
+    print @out, "\n";
+}
diff --git a/mechglue/src/lib/crypto/crc32/crc32.c b/mechglue/src/lib/crypto/crc32/crc32.c
new file mode 100644
index 000000000..ef65476d9
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/crc32.c
@@ -0,0 +1,192 @@
+/*
+ * lib/crypto/crc32/crc.c
+ *
+ * Copyright 1990, 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * CRC-32/AUTODIN-II routines
+ */
+
+#include "k5-int.h"
+#include "crc-32.h"
+
+/* This table and block of comments are taken from code labeled: */
+/*
+ * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+
+/* First, the polynomial itself and its table of feedback terms.  The  */
+/* polynomial is                                                       */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in  */
+/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
+/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
+/* the MSB being 1.                                                    */
+
+/* Note that the usual hardware shift register implementation, which   */
+/* is what we're using (we're merely optimizing it by doing eight-bit  */
+/* chunks at a time) shifts bits into the lowest-order term.  In our   */
+/* implementation, that means shifting towards the right.  Why do we   */
+/* do it this way?  Because the calculated CRC must be transmitted in  */
+/* order from highest-order term to lowest-order term.  UARTs transmit */
+/* characters in order from LSB to MSB.  By storing the CRC this way,  */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part.  Reception works similarly.                  */
+
+/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
+/*                                                                     */
+/*  1. The table can be generated at runtime if desired; code to do so */
+/*     is shown later.  It might not be obvious, but the feedback      */
+/*     terms simply represent the results of eight shift/xor opera-    */
+/*     tions for all combinations of data and CRC register values.     */
+/*                                                                     */
+/*  2. The CRC accumulation logic is the same for all CRC polynomials, */
+/*     be they sixteen or thirty-two bits wide.  You simply choose the */
+/*     appropriate table.  Alternatively, because the table can be     */
+/*     generated at runtime, you can start by generating the table for */
+/*     the polynomial in question and use exactly the same "updcrc",   */
+/*     if your application needn't simultaneously handle two CRC       */
+/*     polynomials.  (Note, however, that XMODEM is strange.)          */
+/*                                                                     */
+/*  3. For 16-bit CRCs, the table entries need be only 16 bits wide;   */
+/*     of course, 32-bit entries work OK if the high 16 bits are zero. */
+/*                                                                     */
+/*  4. The values must be right-shifted by eight bits by the "updcrc"  */
+/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
+/*     hardware you could probably optimize the shift in assembler by  */
+/*     using byte-swap instructions.                                   */
+
+static u_long const crc_table[256] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+    0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+    0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+    0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+    0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+    0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+    0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+    0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+    0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+    0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+    0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+    0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+    0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+    0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+    0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+    0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+    0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+    };
+
+void
+mit_crc32(krb5_pointer in, size_t in_length, unsigned long *cksum)
+{
+    register u_char *data;
+    register u_long c = 0;
+    register int idx;
+    size_t i;
+
+    data = (u_char *)in;
+    for (i = 0; i < in_length; i++) {
+	idx = (int) (data[i] ^ c);
+	idx &= 0xff;
+	c >>= 8;
+	c ^= crc_table[idx];
+    }
+
+    *cksum = c;
+}
+
+#ifdef CRC32_SHIFT4
+static unsigned long const tbl4[16] = {
+    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+    0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+    0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+    0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+};
+
+void
+mit_crc32_shift4(krb5_pointer in, size_t in_length, unsigned long *cksum)
+{
+    register unsigned char *data, b;
+    register unsigned long c = 0;
+    size_t i;
+
+    data = (u_char *)in;
+    for (i = 0; i < in_length; i++) {
+	b = data[i];
+	c = (c >> 4) ^ tbl4[(b ^ c) & 0x0f];
+	b >>= 4;
+	c = (c >> 4) ^ tbl4[(b ^ c) & 0x0f];
+    }
+    *cksum = c;
+}
+#endif
diff --git a/mechglue/src/lib/crypto/crc32/t_crc.c b/mechglue/src/lib/crypto/crc32/t_crc.c
new file mode 100644
index 000000000..e8a353a0b
--- /dev/null
+++ b/mechglue/src/lib/crypto/crc32/t_crc.c
@@ -0,0 +1,213 @@
+/*
+ * lib/crypto/crc32/t_crc.c
+ *
+ * Copyright 2002,2005 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Sanity checks for CRC32.
+ */
+#include <sys/times.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "k5-int.h"
+#include "crc-32.h"
+
+#define HEX 1
+#define STR 2
+struct crc_trial {
+    int		type;
+    char	*data;
+    unsigned long	sum;
+};
+
+struct crc_trial trials[] = {
+    {HEX, "01", 0x77073096},
+    {HEX, "02", 0xee0e612c},
+    {HEX, "04", 0x076dc419},
+    {HEX, "08", 0x0edb8832},
+    {HEX, "10", 0x1db71064},
+    {HEX, "20", 0x3b6e20c8},
+    {HEX, "40", 0x76dc4190},
+    {HEX, "80", 0xedb88320},
+    {HEX, "0100", 0x191b3141},
+    {HEX, "0200", 0x32366282},
+    {HEX, "0400", 0x646cc504},
+    {HEX, "0800", 0xc8d98a08},
+    {HEX, "1000", 0x4ac21251},
+    {HEX, "2000", 0x958424a2},
+    {HEX, "4000", 0xf0794f05},
+    {HEX, "8000", 0x3b83984b},
+    {HEX, "0001", 0x77073096},
+    {HEX, "0002", 0xee0e612c},
+    {HEX, "0004", 0x076dc419},
+    {HEX, "0008", 0x0edb8832},
+    {HEX, "0010", 0x1db71064},
+    {HEX, "0020", 0x3b6e20c8},
+    {HEX, "0040", 0x76dc4190},
+    {HEX, "0080", 0xedb88320},
+    {HEX, "01000000", 0xb8bc6765},
+    {HEX, "02000000", 0xaa09c88b},
+    {HEX, "04000000", 0x8f629757},
+    {HEX, "08000000", 0xc5b428ef},
+    {HEX, "10000000", 0x5019579f},
+    {HEX, "20000000", 0xa032af3e},
+    {HEX, "40000000", 0x9b14583d},
+    {HEX, "80000000", 0xed59b63b},
+    {HEX, "00010000", 0x01c26a37},
+    {HEX, "00020000", 0x0384d46e},
+    {HEX, "00040000", 0x0709a8dc},
+    {HEX, "00080000", 0x0e1351b8},
+    {HEX, "00100000", 0x1c26a370},
+    {HEX, "00200000", 0x384d46e0},
+    {HEX, "00400000", 0x709a8dc0},
+    {HEX, "00800000", 0xe1351b80},
+    {HEX, "00000100", 0x191b3141},
+    {HEX, "00000200", 0x32366282},
+    {HEX, "00000400", 0x646cc504},
+    {HEX, "00000800", 0xc8d98a08},
+    {HEX, "00001000", 0x4ac21251},
+    {HEX, "00002000", 0x958424a2},
+    {HEX, "00004000", 0xf0794f05},
+    {HEX, "00008000", 0x3b83984b},
+    {HEX, "00000001", 0x77073096},
+    {HEX, "00000002", 0xee0e612c},
+    {HEX, "00000004", 0x076dc419},
+    {HEX, "00000008", 0x0edb8832},
+    {HEX, "00000010", 0x1db71064},
+    {HEX, "00000020", 0x3b6e20c8},
+    {HEX, "00000040", 0x76dc4190},
+    {HEX, "00000080", 0xedb88320},
+    {STR, "foo", 0x7332bc33},
+    {STR, "test0123456789", 0xb83e88d6},
+    {STR, "MASSACHVSETTS INSTITVTE OF TECHNOLOGY", 0xe34180f7}
+};
+
+#define NTRIALS (sizeof(trials) / sizeof(trials[0]))
+
+static void
+timetest(unsigned int nblk, unsigned int blksiz)
+{
+    char *block;
+    int i;
+    struct tms before, after;
+    unsigned long cksum;
+
+    block = malloc(blksiz * nblk);
+    if (block == NULL)
+	exit(1);
+    for (i = 0; i < blksiz * nblk; i++)
+	block[i] = i % 256;
+    times(&before);
+    for (i = 0; i < nblk; i++) {
+	mit_crc32(block + i * blksiz, blksiz, &cksum);
+    }
+
+    times(&after);
+    printf("shift-8 implementation, %d blocks of %d bytes:\n",
+	   nblk, blksiz);
+    printf("\tu=%ld s=%ld cu=%ld cs=%ld\n",
+	   (long)(after.tms_utime - before.tms_utime),
+	   (long)(after.tms_stime - before.tms_stime),
+	   (long)(after.tms_cutime - before.tms_cutime),
+	   (long)(after.tms_cstime - before.tms_cstime));
+
+#ifdef CRC32_SHIFT4
+    times(&before);
+    for (i = 0; i < nblk; i++) {
+	mit_crc32_shift4(block + i * blksiz, blksiz, &cksum);
+    }
+    times(&after);
+    printf("shift-4 implementation, %d blocks of %d bytes:\n",
+	   nblk, blksiz);
+    printf("\tu=%ld s=%ld cu=%ld cs=%ld\n",
+	   (long)(after.tms_utime - before.tms_utime),
+	   (long)(after.tms_stime - before.tms_stime),
+	   (long)(after.tms_cutime - before.tms_cutime),
+	   (long)(after.tms_cstime - before.tms_cstime));
+#endif
+    free(block);
+}
+
+static void gethexstr(char *data, size_t *outlen, unsigned char *outbuf,
+		      size_t buflen)
+{
+    size_t inlen;
+    char *cp, buf[3];
+    long n;
+
+    inlen = strlen(data);
+    *outlen = 0;
+    for (cp = data; cp - data < inlen; cp += 2) {
+	strncpy(buf, cp, 2);
+	buf[2] = '\0';
+	n = strtol(buf, NULL, 16);
+	outbuf[(*outlen)++] = n;
+	if (*outlen > buflen)
+	    break;
+    }
+}
+
+static void
+verify(void)
+{
+    int i;
+    struct crc_trial trial;
+    unsigned char buf[4];
+    size_t len;
+    unsigned long cksum;
+    char *typestr;
+
+    for (i = 0; i < NTRIALS; i++) {
+	trial = trials[i];
+	switch (trial.type) {
+	case STR:
+	    len = strlen(trial.data);
+	    typestr = "STR";
+	    mit_crc32(trial.data, len, &cksum);
+	    break;
+	case HEX:
+	    typestr = "HEX";
+	    gethexstr(trial.data, &len, buf, 4);
+	    mit_crc32(buf, len, &cksum);
+	    break;
+	default:
+	    typestr = "BOGUS";
+	    fprintf(stderr, "bad trial type %d\n", trial.type);
+	    exit(1);
+	}
+	printf("%s: %s \"%s\" = 0x%08lx\n",
+	       (trial.sum == cksum) ? "OK" : "***BAD***",
+	       typestr, trial.data, cksum);
+    }
+}
+
+int
+main(void)
+{
+#if 0
+    timetest(64*1024, 1024);
+#endif
+    verify();
+    exit(0);
+}
diff --git a/mechglue/src/lib/crypto/crypto_libinit.c b/mechglue/src/lib/crypto/crypto_libinit.c
new file mode 100644
index 000000000..91bf8ac22
--- /dev/null
+++ b/mechglue/src/lib/crypto/crypto_libinit.c
@@ -0,0 +1,33 @@
+#include <assert.h>
+#include "k5-int.h"
+
+MAKE_INIT_FUNCTION(cryptoint_initialize_library);
+MAKE_FINI_FUNCTION(cryptoint_cleanup_library);
+
+extern int krb5int_prng_init(void);
+extern void krb5int_prng_cleanup (void);
+
+/*
+ * Initialize the crypto library.
+ */
+
+int cryptoint_initialize_library (void)
+{
+    return krb5int_prng_init();
+}
+
+int krb5int_crypto_init(void)
+{
+    return CALL_INIT_FUNCTION(cryptoint_initialize_library);
+}
+
+/*
+ * Clean up the crypto library state
+ */
+
+void cryptoint_cleanup_library (void)
+{
+    if (!INITIALIZER_RAN(cryptoint_initialize_library))
+	return;
+    krb5int_prng_cleanup ();
+}
diff --git a/mechglue/src/lib/crypto/decrypt.c b/mechglue/src/lib/crypto/decrypt.c
new file mode 100644
index 000000000..c252eb7c2
--- /dev/null
+++ b/mechglue/src/lib/crypto/decrypt.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_decrypt(krb5_context context, const krb5_keyblock *key,
+	       krb5_keyusage usage, const krb5_data *ivec,
+	       const krb5_enc_data *input, krb5_data *output)
+{
+    int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == key->enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    if ((input->enctype != ENCTYPE_UNKNOWN) &&
+	(krb5_enctypes_list[i].etype != input->enctype))
+	return(KRB5_BAD_ENCTYPE);
+
+    return((*(krb5_enctypes_list[i].decrypt))
+	   (krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
+	    key, usage, ivec, &input->ciphertext, output));
+}
diff --git a/mechglue/src/lib/crypto/default_state.c b/mechglue/src/lib/crypto/default_state.c
new file mode 100644
index 000000000..33a189f26
--- /dev/null
+++ b/mechglue/src/lib/crypto/default_state.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2001 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Section 6 (Encryption) of the Kerberos revisions document defines
+ * cipher states to be used to chain encryptions and decryptions
+ * together.  Examples of cipher states include initialization vectors
+ * for CBC encription.  Most Kerberos encryption systems can share
+ * code for initializing and freeing cipher states.  This file
+ * contains that default code.
+ */
+
+#include "k5-int.h"
+
+krb5_error_code krb5int_des_init_state
+(const krb5_keyblock *key, krb5_keyusage usage, krb5_data *new_state )
+{
+  new_state->length = 8;
+  new_state->data = (void *) malloc(8);
+  if (new_state->data) {
+    memset (new_state->data, 0, new_state->length);
+    /* We need to copy in the key for des-cbc-cr--ick, but that's how it works*/
+    if (key->enctype == ENCTYPE_DES_CBC_CRC) {
+      memcpy (new_state->data, key->contents, new_state->length);
+  }
+  } else {
+    return ENOMEM;
+  }
+  return 0;
+}
+
+krb5_error_code krb5int_default_free_state
+(krb5_data *state)
+{
+  if (state->data) {
+    free (state->data);
+    state-> data = NULL;
+    state->length = 0;
+  }
+  return 0;
+}
+
+    
+  
diff --git a/mechglue/src/lib/crypto/des/.Sanitize b/mechglue/src/lib/crypto/des/.Sanitize
new file mode 100644
index 000000000..dbf87fb59
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/.Sanitize
@@ -0,0 +1,71 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+FUNCTIONS
+Makefile.in
+afsstring2key.c
+cbc_cksum.c
+configure
+configure.in
+d3_cbc.c
+d3_ecb.c
+d3_kysched.c
+d3_procky.c
+d3_str2ky.c
+des.h
+des_int.h
+destest.c
+doc
+f_README
+f_cbc.c
+f_cksum.c
+f_ecb.c
+f_parity.c
+f_pcbc.c
+f_sched.c
+f_tables.c
+f_tables.h
+fin_rndkey.c
+finish_key.c
+init_rkey.c
+key_sched.c
+keytest.data
+process_ky.c
+random_key.c
+string2key.c
+t_random.c
+t_verify.c
+u_nfold.c
+u_rn_key.c
+weak_key.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/crypto/des/ChangeLog b/mechglue/src/lib/crypto/des/ChangeLog
new file mode 100644
index 000000000..5aee62fc2
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/ChangeLog
@@ -0,0 +1,765 @@
+2006-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (destest$(EXEEXT)): Include support library.
+
+2005-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* destest.c (main): Force testing of unaligned access to input,
+	output, and key blocks.
+
+2005-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* f_tables.h: Include k5-platform.h.
+	(GET_HALF_BLOCK): Use load_32_be.
+	(PUT_HALF_BLOCK): Use store_32_be.
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* d3_cbc.c (krb5int_des3_cbc_encrypt, krb5int_des3_cbc_decrypt):
+	Don't declare left and right variables as registers.
+	* f_cksum.c (mit_des_cbc_cksum): Likewise.
+	* f_cbc.c (krb5int_des_cbc_encrypt, krb5int_des_cbc_decrypt):
+	Likewise.
+	(krb5int_des_cbc_encrypt): For full blocks, use GET_HALF_BLOCK to
+	read and then xor, instead of processing each byte individually.
+	(krb5int_des_do_encrypt_2, krb5int_des_do_decrypt_2)
+	[CONFIG_SMALL]: New functions, wrapping large macros with the DES
+	inner loops.
+	* f_tables.h (DES_DO_ENCRYPT_1, DES_DO_DECRYPT_1): Renamed from
+	non-_1 names.
+	(krb5int_des_do_encrypt_2, krb5int_des_do_decrypt_2): Declare if
+	CONFIG_SMALL is defined.
+	(DES_DO_ENCRYPT, DES_DO_DECRYPT): Expand to _1 macros or _2
+	function calls depending on whether CONFIG_SMALL is defined.
+
+2004-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (verify, t_afss2k): Link test programs against
+	thread support library.
+
+2004-04-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* string2key.c: Replaced with a new implementation.
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* afsstring2key.c, d3_cbc.c, d3_kysched.c, f_cbc.c, f_cksum.c,
+	f_parity.c, f_sched.c, key_sched.c, string2key.c, weak_key.c: Use
+	ANSI C style function definitions.
+
+2004-02-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* f_tables.h (DES_DO_ENCRYPT, DES_DO_DECRYPT): Allocate temporary
+	variable locally instead of taking the extra argument.
+	* d3_cbc.c (krb5int_des3_cbc_encrypt): Don't pass the extra
+	argument, and delete the automatic variable.
+	(krb5int_des3_cbc_decrypt): Likewise.
+	* f_cbc.c (krb5int_des_cbc_encrypt, krb5int_des_cbc_decrypt):
+	Likewise.
+	* f_cksum.c (mit_des_cbc_cksum): Likewise.
+
+	* afsstring2key.c (krb5_afs_encrypt): Drop EDFLAG as an argument,
+	make it local instead, since we always pass 0.
+	(afs_crypt): Call changed.
+	(krb5_afs_crypt_setkey, krb5_afs_encrypt): Use memcpy.
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* f_cbc.c (mit_des_zeroblock): Define, as a single cblock, not the
+	array of 8 that was used elsewhere.
+	* des_int.h (mit_des_zeroblock): Declare, and use a macro to stick
+	a krb5int prefix on it.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* f_cbc.c (krb5int_des_cbc_decrypt): Move declarations that were
+	after statements after flattening blocks is previous change.
+	* d3_cbc.c (krb5int_des3_cbc_decrypt): Likewise.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* f_cbc.c (krb5int_des_cbc_encrypt, krb5int_des_cbc_decrypt): New
+	functions broken out from mit_des_cbc_encrypt.
+	(mit_des_cbc_encrypt): Call them.
+	* d3_cbc.c (krb5int_des3_cbc_encrypt, krb5int_des3_cbc_decrypt):
+	New functions broken out from mit_des3_cbc_encrypt.
+	(mit_des3_cbc_encrypt): Call them.
+	* des_int.h (krb5int_des_cbc_encrypt, krb5int_des_cbc_decrypt,
+	krb5int_des3_cbc_encrypt, krb5int_des3_cbc_decrypt): Declare.
+	(mit_des_cbc_encrypt, mit_des3_cbc_encrypt): New macros.
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+
+    * des_int.h: Added prototype for mit_afs_crypt which is used by
+    the deprecated KfM des_crypt function. 
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* des_int.h (krb5_raw_des_cst_entry, krb5_des_crc_cst_entry,
+	krb5_des_md5_cst_entry, krb5_des3_sha_cst_entry,
+	krb5_des3_raw_cst_entry, krb5_des_cbc_cksumtable_entry): Delete
+	unused declarations.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* t_verify.c: Signed vs. unsigned cleanups. Remove unsused variables.
+
+2002-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* string2key.c (mit_des_string_to_key_int): If PRINT_TEST_VECTORS
+	is defined, print some of the intermediate results.
+
+2002-09-26  Tom Yu  <tlyu@mit.edu>
+
+	* afsstring2key.c (krb5_afs_crypt): Leak this function out as as
+	mit_afs_crypt to allow for des_crypt and des_fcrypt
+	implementations for the KfM merge.
+
+	* des_int.h: Change DES_INT32 strategy to include kerberosIV/des.h
+	with a magic macro defined for skipping krb4-specific stuff.  Make
+	renaming of make_key_sched explicit, to avoid conflict with
+	kerberosIV/des.h.
+
+	* f_sched.c, key_sched.c, d3_kysched.c: Make renaming of
+	make_key_sched explicit.
+
+	* f_cksum.c (mit_des_cbc_cksum): Return only the rightmost 32
+	bits; this should optimize out on any platform where longs are
+	exactly 32 bits wide.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-16  Tom Yu  <tlyu@mit.edu>
+
+	* string2key.c: Work around possible bug with AFS salts;
+	[krb5-clients/1146] from <Wolfgang.Friebel@cern.ch>.
+
+2002-06-07  Miro Jurisic  <meeroh@mit.edu>
+
+	* des_int.h: use "" includes for k5-int.h
+	[pullup from 1-2-2-branch]
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* afsstring2key.c, d3_cbc.c, des_int.h, f_cbc.c, f_cksum.c,
+	string2key.c: Don't explicitly declare pointers FAR any more.
+
+2001-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* string2key.c (mit_des_string_to_key_int): Undo last change.
+
+2001-06-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* destest.c (value): Now signed int, since some entries are
+	negative.
+	(convert): Do bounds checking on character values used as indices
+	into value array.
+
+	* string2key.c (mit_des_string_to_key_int): Now static.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_verify.c: Get rid of global variables i,j.
+
+2001-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* string2key.c (mit_des_string_to_key_int): Construct a krb5_data
+	object with proper length for the AFS case (indicated by a -1 salt
+	length on input).
+
+2001-06-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* destest.c: main returns int instead of void.  Add "const" to
+	casts in calls to mit_des_cbc_encrypt().
+
+	* t_verify.c (main): Add parenthesis aroud assignment in conditional. 
+
+2001-05-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* f_cbc.c (mit_des_cbc_encrypt): Do not use a variable named "encrypt".
+	* d3_cbc.c (mit_des3_cbc_encrypt): Likewise.
+
+	* des_int.h (mit_des_cbc_encrypt, mit_des3_ecb_encrypt,
+	mit_des3_cbc_encrypt): Don't use "encrypt" as argument name.
+
+2001-04-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* f_tables.h: Do not define const to nothing on platforms that
+	fail to define __STDC__ - let autoconf do this if necessary.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_afss2k.c (do_it): Add cast to keep compiler quiet.
+
+	* f_cksum.c (mit_des_cbc_cksum): Use const for input, key
+	schedule, and initial vector.  Get rid of casts when possible.
+	* f_cbc.c (mit_des_cbc_encrypt): Likewise.
+	* f_sched.c (make_key_sched): Likewise.
+	* d3_cbc.c (mit_des3_cbc_encrypt): Likewise.
+	* d3_kysched.c (mit_des3_key_sched): Don't create new variables to
+	point to components of key and schedule, just index into the
+	argument variables.
+	* des_int.h (mit_des_cbc_cksum, mit_des_cbc_encrypt,
+	mit_des3_cbc_encrypt): Update decls.
+	(mit_des_string_to_key_int): New decl.
+
+	* weak_key.c (mit_des_is_weak_key): Get rid of some unneeded
+	casts.
+
+	* des_int.h (make_key_sched): Define a macro to rename with
+	mit_des_ prefix.
+
+	* des_int.h (des_cblock, des_key_schedule): Duplicate definitions
+	here and in kerberosIV/des.h, using macro
+	KRB5INT_DES_TYPES_DEFINED to avoid duplication.
+	(mit_des_cblock, mit_des_key_schedule): Define in terms of the
+	other types for now.
+	(PROTOTYPE): Don't define.
+
+	* afsstring2key.c, des_int.h, destest.c: Don't use PROTOTYPE macro.
+
+2001-01-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_afss2k.c: Extend test cases to cover situation where krb5_data
+	refers to strings that are not nul-terminated.  Reorder functions
+	to avoid inlining, to keep debugging easier.
+	* afsstring2key.c (mit_afs_string_to_key): Don't depend on
+	nul-termination of input strings.
+
+2001-01-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* afsstring2key.c (mit_afs_string_to_key): Allocate and pass
+	buffer for afs_crypt.  Don't use static storage for key schedule.
+	(IP, FP, PC1_C, PC1_D, shifts, PC2_C, PC2_D, E, e, P, S): Now
+	const.
+	(C, D, KS, L, R, tempL, f, preS): Static variables deleted.
+	(afs_crypt): Allocate them here, and pass pointers to other
+	routines.
+	(krb5_afs_crypt_setkey, krb5_afs_encrypt): Add extra arguments or
+	local variables for additional state, instead of static
+	variables.
+
+	* t_afss2k.c: New file.
+	* Makefile.in (t_afss2k): New target.
+	(TAFSS2KOBJS): New variable.
+	(check-unix): Run t_afss2k.
+	(clean): Get rid of t_afss2k binaries.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* des_int.h: Change prototypes for mit_des_cbc_encrypt(),
+	mit_des_cbc_cksum(), and mit_des3_cbc_encrypt() to take unsigned
+	long lengths.
+
+	* d3_cbc.c (mit_des3_cbc_encrypt): Length argument now takes an
+	unsigned long.
+
+	* f_cbc.c (mit_des_cbc_encrypt): Length argument now takes an
+	unsigned long.
+
+	* f_cksum.c (mit_des_cbc_cksum): Length argument now takes an
+	unsigned long.
+
+	* string2key.c: Unsigned/signed int cleanup. Test for a
+	salt-length of SALT_TYPE_AFS_LENGTH or -1 (for backwards
+	compatibilty) for use of mit_afs_string_to_key().
+
+2000-06-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* afsstring2key.c: Initialization of S[8][64] - each 64 elements 
+	enclosed in brackets. 
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* afsstring2key.c: "register x" -> "register int x".
+
+2000-02-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_verify.c: Add "const" to casts in calls to mit_des_cbc_encrypt().
+
+	* destest.c: Declare zeroblock as krb5_octet * instead of char * as
+	argument to mit_des_cbc_encrypt.
+	
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* f_sched.c (PC2_C, PC2_D): Put braces around sub-arrays.
+	* f_tables.c (des_SP_table): Ditto.
+
+	* weak_key.c (weak): Now const.
+	(mit_des_is_weak_key): Adjust pointer type accordingly.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:16:18 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Sun Jul 19 12:00:00 1998  Marc Horowitz <marc@mit.edu>
+
+	* *.c: replace the crypto layer.
+
+Wed Feb 18 16:06:23 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 15:20:54 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (thisconfigdir), configure.in: Point the
+ 		configuration directory at our parent, and remove our
+		local configure.in
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Dec 25 20:57:53 1997  Tom Yu  <chaoself@mit.edu>
+
+	* init_rkey.c (mit_des_init_random_key): Punt the struct; use
+	explicit variables instead because we're no longer doing a
+	memcpy.  In addition, fill p_state->sequence.data a byte at a
+	time. [krb5-libs/492]
+
+Mon Oct 27 01:06:34 1997  Tom Yu  <tlyu@mit.edu>
+
+	* d3_cbc.c, des.h, des_int.h, f_cbc.c, f_cksum.c, f_ecb.c,
+	f_pcbc.c, f_sched.c, f_tables.c, f_tables.h: Change KRB_INT32 to
+	DES_INT32 to avoid temptation to misuse.
+
+	* d3_cbc.c, d3_ecb.c, f_cbc.c, f_cksum.c, f_ecb.c, f_parity.c,
+ 	f_pcbc.c, f_sched.c, f_tables.c: Don't include des.h; it's broken
+ 	in ways.  Use only des_int.h instead.
+
+Tue Oct 21 13:22:23 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (RUN_SETUP): Set KRB5_CONFIG.
+
+Tue Oct 14 15:35:53 1997  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* des_int.h: Use better logic to find an appropriate type for
+ 	KRB_INT32; also don't assume that a key schedule element is
+	exactly 64 bits wide... use instead 2 * KRB_INT32, since that is
+	what the code uses internally.
+
+	* des.h: Use better logic to find an appropriate type for
+ 	KRB_INT32.
+
+Mon Oct  6 11:32:51 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* destest.c (main): Initialize context to 0 so it will not be
+	        treated as unset by purify.
+
+	* t_verify.c (main): Use krb5_free_context to release memory in use.
+
+
+Sat Feb 22 18:50:35 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Fri Feb  7 07:12:52 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in (all-unix, all-mac): Create shared directory
+		before trying to build the object files
+
+Thu Jan 30 21:43:19 1997  Richard Basch  <basch@lehman.com>
+
+	* cbc_cksum.c
+		Change functions to take const args where possible
+
+Thu Nov 21 00:58:04 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: Win32 build
+
+Sat Feb  8 18:49:39 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Sun Dec 29 21:53:49 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to use new library building procedure.
+
+Sat Jun 15 03:51:19 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean): Add space before \
+
+Wed Jun 12 00:08:31 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* des_int.h: Add missing prototypes; needed to make Win-32
+		compiler happy.
+
+	* f_tables.h: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS
+
+Tue May 21 19:30:10 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (check-unix): In building destest and verify, make
+ 	sure we include enough object modules to deal with systems that do
+ 	early binding in shared libs, so we porperly overide
+ 	mit_des_is_weak_key
+
+	* Makefile.in (check-unix): Use $(RUN_SETUP) so shared lib paths
+ 	are happy.
+
+Sat May 18 02:02:59 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* u_nfold.c (mit_des_n_fold): Fix memory leak.  Free tempbuf
+		before returning.
+
+Tue May 14 18:59:38 1996  Richard Basch  <basch@lehman.com>
+
+	* des_int.h: the cs_entry routines in cbc_cksum.c are now static.
+
+	* Makefile.in: removed cs_entry.c
+
+	* cbc_cksum.c:
+		caller is responsible for allocating cksum->contents
+		  and indicate the allocated amount in cksum->length.
+		the cs_entry routines are now static and the cs_entry
+		  structure is now in this file to enforce proper use.
+
+Fri May 10 01:46:25 1996  Richard Basch  <basch@lehman.com>
+
+	* d3_str2ky.c d3_procky.c des_int.h init_rkey.c:
+	Replace des3-md5 with des3-sha
+
+Thu May  2 18:29:01 1996  Richard Basch  <basch@lehman.com>
+
+	* d3_rndky.c new_rn_key.c: Removed (obsolete).
+
+	* u_rn_key.c: New file
+		Support routines to set the seed/sequence number of the
+		random stream.
+
+	* Makefile.in: new/removed file changes
+
+	* des_int.h: Changed prototypes for all the random routines.
+
+	* fin_rndkey.c: rewrote mit_des_finish_random_key to use the new
+		random state structure and to accept an eblock as arg 1.
+
+	* init_rkey.c: rewritten to be a common DES, 3-DES random stream
+		initialization routine.  it uses the eblock to determine
+		the random key type to generate.
+		
+	* random_key.c: rewritten to be a common DES, 3-DES random stream
+		generator, using the former DES algorithm (encrypting an
+		incrementing sequence number with a unique key schedule)
+		[3-DES uses DES3-CBC-CRC to increment a 192 bit sequence
+		number, instead of being only as secure as DES.]
+
+Wed Apr 17 19:25:01 1996  Marc Horowitz  <marc@mit.edu>
+
+	* cbc_cksum.c (mit_des_cbc_checksum): don't allocate the checksum
+	contents.  The caller is supposed to do this.
+
+Wed Apr 10 17:46:40 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS,OBJS): Added afsstring2key.c to the list of
+		files to be compiled.
+
+Sat Mar 30 22:56:48 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS): Took the list of sources and object files in
+		FSRCS, FOBJS, D3OBJS, and D3SRCS, and inlined them into
+		the OBJS and SRCS list.  This is necessary so that the
+		files are correctly picked up for the Macintosh build.
+
+Thu Mar 28 10:49:31 1996  Richard Basch  <basch@lehman.com>
+
+	* init_rkey.c, d3_str2ky.c, d3_procky.c: Support ENCTYPE_DES3_CBC_RAW
+
+	* des_int.h: Support CKSUMTYPE_DES3_CBC_MD5
+
+Wed Mar 20 22:33:40 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* u_nfold.c (mit_des_n_fold): 
+	* d3_str2ky.c (mit_des3_string_to_key): Fix Windows lint flames.
+
+Mon Mar 11 11:03:23 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* new_rn_key.c (mit_des_generate_random_block): Add const keywrod
+		to cast for suncc warning.
+
+Thu Feb 22 20:32:08 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* t_random.c: New file which just tests the random number generator.
+
+	* new_rn_key.c (mit_des_set_random_generator_seed): Add fix so
+		that we do something even if the input key is not a valid
+		DES key.
+
+Wed Jan 10 22:28:23 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* des_int.h: Fix return type for mit_des3_string_to_key().
+
+Tue Nov 28 11:24:26 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* f_ecb.c, des_int.h (mit_des_ecb_encrypt): Add const declaration
+		to input cblock.
+
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * string2key.c : Remove krb5_enctype from krb5_string_to_key() args.
+	* string2key.c, des_int.h : Remove krb5_enctype from 
+		mit_des_string_to_key() args.
+
+Tue Oct 31 22:06:52 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* finish_key.c (mit_des_finish_key): Make mit_des_finish_key()
+		safe to call even if there is no key that needs to be
+		freed.
+
+Fri Oct  6 21:59:55 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Thu Sep 28 16:00:00 1995  John Rivlin  <jrivlin@fusion.com>
+
+	* Makefile.in: Renamed verify.c to t_verify.c to avoid conflict with 
+		lib/gssapi/krb5/verify.c on the Mac.
+
+Mon Sep 25 16:48:36 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Fri Sep 22 23:32:58 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* des_int.h: Define PROTOTYPE if it is not defined elsewhere.
+
+Tue Sep 12 18:50:50 1995   John Rivlin (jrivlin@fusion.com)
+
+	* f_pcbc.c: Added include of des_int.h which seemed to
+		get lost so that mit_des_xxx get defined.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * des_int.h, destest.c, init_rkey.c, random_key.c, string2key.c 
+	* verify.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * destest.c, random_key.c, string2key.c, verify.c : Remove krb5_enctype
+		references, and replace with krb5_keytype where appropriate.
+	* init_rkey.c (mit_des_init_random_key()), 
+	* string2key.c (mit_des_string_to_key()) : Allow for any DES keytype.
+
+
+Tue Aug 29 13:29:19 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* process_key.c, finish_key.c - Set and use priv_size in the krb5_
+		encrypt_block.
+
+Thu Aug 24 18:08:42 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+        * f_cksum.c: Change code to match prototypes. 
+
+	* f_cbc.c, f_ecb, f_parity, f_pcbc: Change des_cblock to
+		mit_des_cblock and  des_key_schedule to
+		mit_des_key_schedule. Also include des_int.h.
+
+	* destest.c: Change des_cblock to mit_des_cblock and add local
+		prototypes. 
+
+	* cs_entry.c: Remove prototypes for mit_des_cbc_cksum and
+		mit_des_cbc_cksum. Now in des_int.h.
+
+	* cbc_cksum.c, string2key.c:	Remove casts in call to
+		mit_des_cbc_cksum 
+
+	* des_int.h: Add prototype for mit_des_cbc_verf_cksum. Change 
+		return code for mit_des_cbc_cksum to match source.
+
+	* des.h: Remove unused structures and defines.
+
+Thu Jul 27 15:18:37 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* des_int.h - Inline the old contents of include/krb5/mit-des.h.  This
+		is now the only place that it's needed.  Also update the
+		prototype for mit_des_ecb_encrypt.
+	* destest.c, f_sched.c, fin_rndkey.c, finish_key.c - Include des_int.h
+	* destest.c, new_rn_key.c, verify.c - Cast to the correct type for
+		mit_des_ecb_encrypt.
+
+
+Fri Jul 7 16:12:29 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* cbc_cksum.c - Add checksum verifier procedure.
+	* cs_entry.c - Add entry for checksum verifier.
+
+Thu Jul  6 17:16:17 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* new_rn_key.c (mit_des_init_random_number_generator): don't call
+		us_timeofday with context arg; also update for new
+		function names (krb5_crypto_*).
+
+Fri Jun  9 19:18:29 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu May 25 22:16:02 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for shared libraries.
+
+Fri May 12 02:46:13 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* key_sched.c (mit_des_key_sched): *always* fill in the schedule,
+	regardless of the key failing other tests, as a defense against
+	telnet-style bugs.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+        * *.h added FAR to pointers visible at to the world.
+        * f_tables.h: __STDC__ condition also checks _WINDOWS
+
+Tue Mar 28 15:09:43 1995  John Gilmore  (gnu at toad.com)
+
+	Bring in portability fixes from Cygnus K4 release.
+
+	* f_cbc.c, f_cksum.c, f_pcbc.c:  Replace individual casts with
+	simpler solution.
+	* f_tables.h:  Insert debugging code, and circumvention for MPW
+	compiler bug.
+	* key_sched.c:  Remove ancient (microvax??!) comments, and dup 
+	prototype.
+	* verify.c:  Small hack for MS-Windows scrolling.  Fix spelling.
+	"register x" -> "register int x".
+
+Thu Mar 16 21:16:24 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Remove, conflicts with pre.in.
+	(clean):  Insert FIXME.
+	(verify$(EXEEXT), destest$(EXEEXT)):  Make them work on Mac.
+	(check-mac):  Add, identical to Unix.
+	(clean):  Use $(EXEEXT).
+	* des_int.h (mit_des_cbc_cksum):  Fix prototype from void to long,
+	to match the actual function.
+
+Tue Mar 14 17:28:35 1995 Keith Vetter (keithv@fusion.com)
+
+	* f_cbc.c, f_cksum.c, f_pcbc.c: added casts so that chars get promoted
+           to longs instead of ints when doing 32 bit bit manipulations.
+
+Thu Mar 2 17:50:39 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed LIBNAME for the PC.
+        * f_tables.h. f_cbc.c: added cast on the assignment of bits of
+           a long into characters.
+        * string2k.c: promoted an int into a long.
+
+Thu Mar  2 18:09:28 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:30:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 00:18:38 1995  John Gilmore  (gnu at toad.com)
+
+	* des_int.h:  Avoid <krb5/...> includes.
+
+Mon Feb 20 16:10:29 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work under windows PC
+        * cbc_cksu.c cs_entry.c finish_k.c fin_rndk.c f_cbc.c f_cksum.c 
+          f_ecb.c f_parity.c f_pcbc.c f_sched.c init_rke.c key_sche.c 
+          new_rn_k.c process_.c random_k.c string2k.c weak_key.c: added
+          windows INTERFACE keyword.
+        * string2key.c: needed long -> int casts for memset and malloc
+
+Wed Feb  8 13:59:05 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* des.h: Add KRB5_INT32 definitions for non-32 int platforms.
+
+Fri Feb  3 06:33:22 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* des_int.h: Remove unused cruft from the file.
+
+	* verify.c: Fix typo; "%02 X" --> "%02X"
+
+Wed Jan 25 20:04:39 1995  John Gilmore  (gnu at toad.com)
+
+	* cbc_cksum.c, cs_entry.c, des.h, destest.c, f_sched.c,
+	fin_rndkey.c, finish_key.c, init_rkey.c, key_sched.c,
+	new_rn_key.c, process_ky.c, random_key.c, string2key.c, verify.c,
+	weak_key.c: Replace <.../...> includes with "..."s.
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+        * Removed all narrow types and references to wide.h and narrow.h
+
+Fri Nov 18 16:20:10 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* destest.c (main): Add magic numbers to keyblock structure.
+
+Tue Nov  8 17:57:47 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* des_int.h:
+	  random_key.c (mit_des_random_key):
+	  string2key.c (mit_des_string_to_key): Change
+		internal calling signature to pass in the encryption
+		block, so that the encryption type in the keyblock
+		structure can be properly initialized.
+
+Thu Nov  3 18:31:55 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* Makefile.in: stop building f_pcbc.c, since it belongs in
+	libdes425, but leave it here for reference.
+
+Fri Oct 14 00:33:17 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* des_int.h, f_cbc.c, verify.c: Fix function declarations to
+		(slightly) better match the conventions used by the krb5
+		source tree.
+
+	* cs_entry.c: Remove declarations of the cryptosystem specific
+		structures to raw-des.c and des-crc.c in the parent
+		directory.  They're strictly speaking not DES specific.
+
+	* Makefile.in: Remove file krb_glue.c; we don't use it any more.
+
+Thu Oct  6 12:49:29 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Make sure the "make check" programs get cleaned up
+		on a "make clean".
+
+	* verify.c (main): Take out check that assures that long is 4
+		bytes.  The DES implementation shouldn't be depending on
+		this, and if it is, then that's what the verify program
+		should be discovering, yes?
+
+Thu Jun 23 01:09:33 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* cs_entry.c: oops typo in that last one
+
+	* grrr.... ETYPE_DES_CBC_CRC really should be ETYPE_RAW_DES_CBC,
+	although something like ETYPE_DES_CBC_RAW or ETYPE_DES_CBC_NONE
+	would probably work better (following the convention
+	ETYPE_{system}_{mode}_{integrity})
+
diff --git a/mechglue/src/lib/crypto/des/ISSUES b/mechglue/src/lib/crypto/des/ISSUES
new file mode 100644
index 000000000..412f94aa7
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/ISSUES
@@ -0,0 +1,13 @@
+Issues to be addressed for src/lib/crypto/des: -*- text -*-
+
+
+"const" could be used in more places
+
+
+Array types are used in calling interfaces.  Under ANSI C, a value of
+type "arraytype *" cannot be assigned to a variable of type "const
+arraytype *", so we get compilation warnings.
+
+Possible fix: Rewrite internal interfaces to not use arrays this way.
+Provide external routines compatible with old API, but not using
+const?
diff --git a/mechglue/src/lib/crypto/des/Makefile.in b/mechglue/src/lib/crypto/des/Makefile.in
new file mode 100644
index 000000000..acd4af603
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/Makefile.in
@@ -0,0 +1,176 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/des
+mydir=des
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=des
+##DOS##OBJFILE=..\$(OUTPRE)des.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS=\
+	afsstring2key.o	\
+	d3_cbc.o	\
+	d3_kysched.o	\
+	f_cbc.o 	\
+	f_cksum.o	\
+	f_parity.o 	\
+	f_sched.o 	\
+	f_tables.o	\
+	key_sched.o	\
+	string2key.o	\
+	weak_key.o
+
+OBJS=	$(OUTPRE)afsstring2key.$(OBJEXT)	\
+	$(OUTPRE)d3_cbc.$(OBJEXT)	\
+	$(OUTPRE)d3_kysched.$(OBJEXT)	\
+	$(OUTPRE)f_cbc.$(OBJEXT) 	\
+	$(OUTPRE)f_cksum.$(OBJEXT)	\
+	$(OUTPRE)f_parity.$(OBJEXT) 	\
+	$(OUTPRE)f_sched.$(OBJEXT) 	\
+	$(OUTPRE)f_tables.$(OBJEXT)	\
+	$(OUTPRE)key_sched.$(OBJEXT)	\
+	$(OUTPRE)string2key.$(OBJEXT)	\
+	$(OUTPRE)weak_key.$(OBJEXT)
+
+SRCS=	$(srcdir)/afsstring2key.c	\
+	$(srcdir)/d3_cbc.c	\
+	$(srcdir)/d3_kysched.c	\
+	$(srcdir)/f_cbc.c	\
+	$(srcdir)/f_cksum.c	\
+	$(srcdir)/f_parity.c	\
+	$(srcdir)/f_sched.c	\
+	$(srcdir)/f_tables.c	\
+	$(srcdir)/key_sched.c	\
+	$(srcdir)/weak_key.c	\
+	$(srcdir)/string2key.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+TOBJS = $(OUTPRE)key_sched.$(OBJEXT) $(OUTPRE)f_sched.$(OBJEXT) $(OUTPRE)f_cbc.$(OBJEXT) \
+	$(OUTPRE)f_tables.$(OBJEXT) $(OUTPRE)f_cksum.$(OBJEXT)
+
+verify$(EXEEXT): t_verify.$(OBJEXT) $(TOBJS) f_parity.$(OBJEXT) \
+	$(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_verify.$(OBJEXT) $(TOBJS) f_parity.$(OBJEXT) \
+		-lcom_err $(SUPPORT_LIB)
+
+destest$(EXEEXT): destest.$(OBJEXT) $(TOBJS) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ destest.$(OBJEXT) $(TOBJS) $(SUPPORT_LIB)
+
+TAFSS2KOBJS =								\
+	t_afss2k.$(OBJEXT) $(TOBJS)					\
+	afsstring2key.$(OBJEXT) f_parity.$(OBJEXT) weak_key.$(OBJEXT)
+
+t_afss2k$(EXEEXT): $(TAFSS2KOBJS) $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ $(TAFSS2KOBJS) -lcom_err $(SUPPORT_LIB)
+
+check-unix:: verify destest t_afss2k
+	$(RUN_SETUP) ./verify -z
+	$(RUN_SETUP) ./verify -m
+	$(RUN_SETUP) ./verify
+	$(RUN_SETUP) ./destest < $(srcdir)/keytest.data
+	$(RUN_SETUP) ./t_afss2k
+
+check-windows::
+
+clean:: 
+	$(RM) destest$(EXEEXT) verify$(EXEEXT) destest.$(OBJEXT) \
+	t_verify.$(OBJEXT) t_afss2k.$(OBJEXT) t_afss2k$(EXEEXT)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+afsstring2key.so afsstring2key.po $(OUTPRE)afsstring2key.$(OBJEXT): \
+  afsstring2key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  des_int.h $(SRCTOP)/include/kerberosIV/des.h
+d3_cbc.so d3_cbc.po $(OUTPRE)d3_cbc.$(OBJEXT): d3_cbc.c \
+  des_int.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/kerberosIV/des.h f_tables.h
+d3_kysched.so d3_kysched.po $(OUTPRE)d3_kysched.$(OBJEXT): \
+  d3_kysched.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  des_int.h $(SRCTOP)/include/kerberosIV/des.h
+f_cbc.so f_cbc.po $(OUTPRE)f_cbc.$(OBJEXT): f_cbc.c \
+  des_int.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/kerberosIV/des.h f_tables.h
+f_cksum.so f_cksum.po $(OUTPRE)f_cksum.$(OBJEXT): f_cksum.c \
+  des_int.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/kerberosIV/des.h f_tables.h
+f_parity.so f_parity.po $(OUTPRE)f_parity.$(OBJEXT): \
+  f_parity.c des_int.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/kerberosIV/des.h
+f_sched.so f_sched.po $(OUTPRE)f_sched.$(OBJEXT): f_sched.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  des_int.h $(SRCTOP)/include/kerberosIV/des.h
+f_tables.so f_tables.po $(OUTPRE)f_tables.$(OBJEXT): \
+  f_tables.c des_int.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/kerberosIV/des.h f_tables.h
+key_sched.so key_sched.po $(OUTPRE)key_sched.$(OBJEXT): \
+  key_sched.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  des_int.h $(SRCTOP)/include/kerberosIV/des.h
+weak_key.so weak_key.po $(OUTPRE)weak_key.$(OBJEXT): \
+  weak_key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  des_int.h $(SRCTOP)/include/kerberosIV/des.h
+string2key.so string2key.po $(OUTPRE)string2key.$(OBJEXT): \
+  string2key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  des_int.h $(SRCTOP)/include/kerberosIV/des.h
diff --git a/mechglue/src/lib/crypto/des/afsstring2key.c b/mechglue/src/lib/crypto/des/afsstring2key.c
new file mode 100644
index 000000000..97ec2d8a1
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/afsstring2key.c
@@ -0,0 +1,570 @@
+/*
+ * lib/crypto/des/string2key.c
+ *
+ * based on lib/crypto/des/string2key.c from MIT V5 
+ * and on lib/des/afs_string_to_key.c from UMD.
+ * constructed by Mark Eichin, Cygnus Support, 1995.
+ * made thread-safe by Ken Raeburn, MIT, 2001.
+ */
+
+/*
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include <ctype.h>
+
+#define afs_crypt mit_afs_crypt
+char *afs_crypt (const char *, const char *, char *);
+
+#undef min
+#define min(a,b) ((a)>(b)?(b):(a))
+
+krb5_error_code
+mit_afs_string_to_key (krb5_keyblock *keyblock, const krb5_data *data,
+		       const krb5_data *salt)
+{
+  /* totally different approach from MIT string2key. */
+  /* much of the work has already been done by the only caller 
+     which is mit_des_string_to_key; in particular, *keyblock is already 
+     set up. */
+  
+    char *realm = salt->data;
+    unsigned int i, j;
+    krb5_octet *key = keyblock->contents;
+
+    if (data->length <= 8) {
+      /* One block only.  Run afs_crypt and use the first eight
+	 returned bytes after the copy of the (fixed) salt.
+
+	 Since the returned bytes are alphanumeric, the output is
+	 limited to 2**48 possibilities; for each byte, only 64
+	 possible values can be used.  */
+      unsigned char password[9]; /* trailing nul for crypt() */
+      char afs_crypt_buf[16];
+
+      memset (password, 0, sizeof (password));
+      memcpy (password, realm, min (salt->length, 8));
+      for (i=0; i<8; i++)
+	if (isupper(password[i]))
+	  password[i] = tolower(password[i]);
+      for (i=0; i<data->length; i++)
+	password[i] ^= data->data[i];
+      for (i=0; i<8; i++)
+	if (password[i] == '\0')
+	  password[i] = 'X';
+      password[8] = '\0';
+      /* Out-of-bounds salt characters are equivalent to a salt string
+	 of "p1".  */
+      strncpy((char *) key,
+	      (char *) afs_crypt((char *) password, "#~", afs_crypt_buf) + 2,
+	      8);
+      for (i=0; i<8; i++)
+	key[i] <<= 1;
+      /* now fix up key parity again */
+      mit_des_fixup_key_parity(key);
+      /* clean & free the input string */
+      memset(password, 0, (size_t) sizeof(password));
+    } else {
+      /* Multiple blocks.  Do a CBC checksum, twice, and use the
+	 result as the new key.  */
+      mit_des_cblock ikey, tkey;
+      mit_des_key_schedule key_sked;
+      unsigned int pw_len = salt->length+data->length;
+      unsigned char *password = malloc(pw_len+1);
+      if (!password) return ENOMEM;
+
+      /* Some bound checks from the original code are elided here as
+	 the malloc above makes sure we have enough storage. */
+      memcpy (password, data->data, data->length);
+      for (i=data->length, j = 0; j < salt->length; i++, j++) {
+	password[i] = realm[j];
+	if (isupper(password[i]))
+	  password[i] = tolower(password[i]);
+      }
+	
+      memcpy (ikey, "kerberos", sizeof(ikey));
+      memcpy (tkey, ikey, sizeof(tkey));
+      mit_des_fixup_key_parity (tkey);
+      (void) mit_des_key_sched (tkey, key_sked);
+      (void) mit_des_cbc_cksum (password, tkey, i, key_sked, ikey);
+
+      memcpy (ikey, tkey, sizeof(ikey));
+      mit_des_fixup_key_parity (tkey);
+      (void) mit_des_key_sched (tkey, key_sked);
+      (void) mit_des_cbc_cksum (password, key, i, key_sked, ikey);
+	
+      /* erase key_sked */
+      memset((char *)key_sked, 0,sizeof(key_sked));
+
+      /* now fix up key parity again */
+      mit_des_fixup_key_parity(key);
+      
+      /* clean & free the input string */
+      memset(password, 0, (size_t) pw_len);
+      krb5_xfree(password);
+    }
+#if 0
+    /* must free here because it was copied for this special case */
+    krb5_xfree(salt->data);
+#endif
+    return 0;
+}
+
+
+/* Portions of this code:
+   Copyright 1989 by the Massachusetts Institute of Technology
+   */
+ 
+/*
+ * Copyright (c) 1990 Regents of The University of Michigan.
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appears in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * The University of Michigan not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. This software is supplied as
+ * is without expressed or implied warranties of any kind.
+ *
+ *	ITD Research Systems
+ *	University of Michigan
+ *	535 W. William Street
+ *	Ann Arbor, Michigan
+ *	+1-313-936-2652
+ *	netatalk@terminator.cc.umich.edu
+ */
+
+static void krb5_afs_crypt_setkey (char*, char*, char(*)[48]);
+static void krb5_afs_encrypt (char*,char*,char (*)[48]);
+
+/*
+ * Initial permutation,
+ */
+static const char	IP[] = {
+	58,50,42,34,26,18,10, 2,
+	60,52,44,36,28,20,12, 4,
+	62,54,46,38,30,22,14, 6,
+	64,56,48,40,32,24,16, 8,
+	57,49,41,33,25,17, 9, 1,
+	59,51,43,35,27,19,11, 3,
+	61,53,45,37,29,21,13, 5,
+	63,55,47,39,31,23,15, 7,
+};
+ 
+/*
+ * Final permutation, FP = IP^(-1)
+ */
+static const char	FP[] = {
+	40, 8,48,16,56,24,64,32,
+	39, 7,47,15,55,23,63,31,
+	38, 6,46,14,54,22,62,30,
+	37, 5,45,13,53,21,61,29,
+	36, 4,44,12,52,20,60,28,
+	35, 3,43,11,51,19,59,27,
+	34, 2,42,10,50,18,58,26,
+	33, 1,41, 9,49,17,57,25,
+};
+ 
+/*
+ * Permuted-choice 1 from the key bits to yield C and D.
+ * Note that bits 8,16... are left out: They are intended for a parity check.
+ */
+static const char	PC1_C[] = {
+	57,49,41,33,25,17, 9,
+	 1,58,50,42,34,26,18,
+	10, 2,59,51,43,35,27,
+	19,11, 3,60,52,44,36,
+};
+ 
+static const char	PC1_D[] = {
+	63,55,47,39,31,23,15,
+	 7,62,54,46,38,30,22,
+	14, 6,61,53,45,37,29,
+	21,13, 5,28,20,12, 4,
+};
+ 
+/*
+ * Sequence of shifts used for the key schedule.
+ */
+static const char	shifts[] = {
+	1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,
+};
+ 
+/*
+ * Permuted-choice 2, to pick out the bits from
+ * the CD array that generate the key schedule.
+ */
+static const char	PC2_C[] = {
+	14,17,11,24, 1, 5,
+	 3,28,15, 6,21,10,
+	23,19,12, 4,26, 8,
+	16, 7,27,20,13, 2,
+};
+ 
+static const char	PC2_D[] = {
+	41,52,31,37,47,55,
+	30,40,51,45,33,48,
+	44,49,39,56,34,53,
+	46,42,50,36,29,32,
+};
+ 
+/*
+ * The E bit-selection table.
+ */
+static const char	e[] = {
+	32, 1, 2, 3, 4, 5,
+	 4, 5, 6, 7, 8, 9,
+	 8, 9,10,11,12,13,
+	12,13,14,15,16,17,
+	16,17,18,19,20,21,
+	20,21,22,23,24,25,
+	24,25,26,27,28,29,
+	28,29,30,31,32, 1,
+};
+ 
+/*
+ * P is a permutation on the selected combination
+ * of the current L and key.
+ */
+static const char	P[] = {
+	16, 7,20,21,
+	29,12,28,17,
+	 1,15,23,26,
+	 5,18,31,10,
+	 2, 8,24,14,
+	32,27, 3, 9,
+	19,13,30, 6,
+	22,11, 4,25,
+};
+ 
+/*
+ * The 8 selection functions.
+ * For some reason, they give a 0-origin
+ * index, unlike everything else.
+ */
+static const char	S[8][64] = {
+	{14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
+	  0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
+	  4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
+	 15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13},
+ 
+	{15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
+	  3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
+	  0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
+	 13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9},
+ 
+	{10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
+	 13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
+	 13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
+	  1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12},
+ 
+	{ 7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
+	 13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
+	 10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
+	  3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14},
+ 
+	{ 2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
+	 14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
+	  4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
+	 11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3},
+ 
+	{12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
+	 10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8,
+	  9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
+	  4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13},
+ 
+	{ 4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
+	 13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6,
+	  1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
+	  6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12},
+ 
+	{13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
+	  1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
+	  7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
+	  2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11},
+};
+ 
+ 
+char *afs_crypt(const char *pw, const char *salt,
+		/* must be at least 16 bytes */
+		char *iobuf)
+{
+	int i, j, c;
+	int temp;
+	char block[66];
+	char E[48];
+	/*
+	 * The key schedule.
+	 * Generated from the key.
+	 */
+	char KS[16][48];
+ 
+	for(i=0; i<66; i++)
+		block[i] = 0;
+	for(i=0; (c= *pw) && i<64; pw++){
+		for(j=0; j<7; j++, i++)
+			block[i] = (c>>(6-j)) & 01;
+		i++;
+	}
+	
+	krb5_afs_crypt_setkey(block, E, KS);
+
+	for(i=0; i<66; i++)
+		block[i] = 0;
+
+	for(i=0;i<2;i++){
+		c = *salt++;
+		iobuf[i] = c;
+		if(c>'Z') c -= 6;
+		if(c>'9') c -= 7;
+		c -= '.';
+		for(j=0;j<6;j++){
+			if((c>>j) & 01){
+				temp = E[6*i+j];
+				E[6*i+j] = E[6*i+j+24];
+				E[6*i+j+24] = temp;
+				}
+			}
+		}
+	
+	for(i=0; i<25; i++)
+		krb5_afs_encrypt(block,E,KS);
+	
+	for(i=0; i<11; i++){
+		c = 0;
+		for(j=0; j<6; j++){
+			c <<= 1;
+			c |= block[6*i+j];
+			}
+		c += '.';
+		if(c>'9') c += 7;
+		if(c>'Z') c += 6;
+		iobuf[i+2] = c;
+	}
+	iobuf[i+2] = 0;
+	if(iobuf[1]==0)
+		iobuf[1] = iobuf[0];
+	return(iobuf);
+}
+
+/*
+ * Set up the key schedule from the key.
+ */
+ 
+static void krb5_afs_crypt_setkey(char *key, char *E, char (*KS)[48])
+{
+	register int i, j, k;
+	int t;
+	/*
+	 * The C and D arrays used to calculate the key schedule.
+	 */
+	char C[28], D[28];
+ 
+	/*
+	 * First, generate C and D by permuting
+	 * the key.  The low order bit of each
+	 * 8-bit char is not used, so C and D are only 28
+	 * bits apiece.
+	 */
+	for (i=0; i<28; i++) {
+		C[i] = key[PC1_C[i]-1];
+		D[i] = key[PC1_D[i]-1];
+	}
+	/*
+	 * To generate Ki, rotate C and D according
+	 * to schedule and pick up a permutation
+	 * using PC2.
+	 */
+	for (i=0; i<16; i++) {
+		/*
+		 * rotate.
+		 */
+		for (k=0; k<shifts[i]; k++) {
+			t = C[0];
+			for (j=0; j<28-1; j++)
+				C[j] = C[j+1];
+			C[27] = t;
+			t = D[0];
+			for (j=0; j<28-1; j++)
+				D[j] = D[j+1];
+			D[27] = t;
+		}
+		/*
+		 * get Ki. Note C and D are concatenated.
+		 */
+		for (j=0; j<24; j++) {
+			KS[i][j] = C[PC2_C[j]-1];
+			KS[i][j+24] = D[PC2_D[j]-28-1];
+		}
+	}
+ 
+#if 0
+	for(i=0;i<48;i++) {
+		E[i] = e[i];
+	}
+#else
+	memcpy(E, e, 48);
+#endif
+}
+ 
+/*
+ * The payoff: encrypt a block.
+ */
+ 
+static void krb5_afs_encrypt(char *block, char *E, char (*KS)[48])
+{
+	const long edflag = 0;
+	int i, ii;
+	int t, j, k;
+	char tempL[32];
+	char f[32];
+	/*
+	 * The current block, divided into 2 halves.
+	 */
+	char L[64];
+	char *const R = &L[32];
+	/*
+	 * The combination of the key and the input, before selection.
+	 */
+	char preS[48];
+
+	/*
+	 * First, permute the bits in the input
+	 */
+	for (j=0; j<64; j++)
+		L[j] = block[IP[j]-1];
+	/*
+	 * Perform an encryption operation 16 times.
+	 */
+	for (ii=0; ii<16; ii++) {
+		/*
+		 * Set direction
+		 */
+		if (edflag)
+			i = 15-ii;
+		else
+			i = ii;
+		/*
+		 * Save the R array,
+		 * which will be the new L.
+		 */
+#if 0
+		for (j=0; j<32; j++)
+			tempL[j] = R[j];
+#else
+		memcpy(tempL, R, 32);
+#endif
+		/*
+		 * Expand R to 48 bits using the E selector;
+		 * exclusive-or with the current key bits.
+		 */
+		for (j=0; j<48; j++)
+			preS[j] = R[E[j]-1] ^ KS[i][j];
+		/*
+		 * The pre-select bits are now considered
+		 * in 8 groups of 6 bits each.
+		 * The 8 selection functions map these
+		 * 6-bit quantities into 4-bit quantities
+		 * and the results permuted
+		 * to make an f(R, K).
+		 * The indexing into the selection functions
+		 * is peculiar; it could be simplified by
+		 * rewriting the tables.
+		 */
+		for (j=0; j<8; j++) {
+			t = 6*j;
+			k = S[j][(preS[t+0]<<5)+
+				(preS[t+1]<<3)+
+				(preS[t+2]<<2)+
+				(preS[t+3]<<1)+
+				(preS[t+4]<<0)+
+				(preS[t+5]<<4)];
+			t = 4*j;
+				f[t+0] = (k>>3)&01;
+				f[t+1] = (k>>2)&01;
+				f[t+2] = (k>>1)&01;
+				f[t+3] = (k>>0)&01;
+		}
+		/*
+		 * The new R is L ^ f(R, K).
+		 * The f here has to be permuted first, though.
+		 */
+		for (j=0; j<32; j++)
+			R[j] = L[j] ^ f[P[j]-1];
+		/*
+		 * Finally, the new L (the original R)
+		 * is copied back.
+		 */
+#if 0
+		for (j=0; j<32; j++)
+			L[j] = tempL[j];
+#else
+		memcpy(L, tempL, 32);
+#endif
+	}
+	/*
+	 * The output L and R are reversed.
+	 */
+	for (j=0; j<32; j++) {
+		t = L[j];
+		L[j] = R[j];
+		R[j] = t;
+	}
+	/*
+	 * The final output
+	 * gets the inverse permutation of the very original.
+	 */
+	for (j=0; j<64; j++)
+		block[j] = L[FP[j]-1];
+}
diff --git a/mechglue/src/lib/crypto/des/d3_cbc.c b/mechglue/src/lib/crypto/des/d3_cbc.c
new file mode 100644
index 000000000..37c32c76f
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/d3_cbc.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright 1995 by Richard P. Basch.  All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "des_int.h"
+#include "f_tables.h"
+
+/*
+ * Triple-DES CBC encryption mode.
+ */
+
+#undef mit_des3_cbc_encrypt
+int
+mit_des3_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
+		     unsigned long length, const mit_des_key_schedule ks1,
+		     const mit_des_key_schedule ks2,
+		     const mit_des_key_schedule ks3,
+		     const mit_des_cblock ivec, int enc)
+{
+    if (enc)
+	krb5int_des3_cbc_encrypt(in, out, length, ks1, ks2, ks3, ivec);
+    else
+	krb5int_des3_cbc_decrypt(in, out, length, ks1, ks2, ks3, ivec);
+    return 0;
+}
+
+void
+krb5int_des3_cbc_encrypt(const mit_des_cblock *in,
+			 mit_des_cblock *out,
+			 unsigned long length,
+			 const mit_des_key_schedule ks1,
+			 const mit_des_key_schedule ks2,
+			 const mit_des_key_schedule ks3,
+			 const mit_des_cblock ivec)
+{
+    unsigned DES_INT32 left, right;
+    const unsigned DES_INT32 *kp1, *kp2, *kp3;
+    const unsigned char *ip;
+    unsigned char *op;
+
+    /*
+     * Get key pointer here.  This won't need to be reinitialized
+     */
+    kp1 = (const unsigned DES_INT32 *)ks1;
+    kp2 = (const unsigned DES_INT32 *)ks2;
+    kp3 = (const unsigned DES_INT32 *)ks3;
+
+    /*
+     * Initialize left and right with the contents of the initial
+     * vector.
+     */
+    ip = ivec;
+    GET_HALF_BLOCK(left, ip);
+    GET_HALF_BLOCK(right, ip);
+
+    /*
+     * Suitably initialized, now work the length down 8 bytes
+     * at a time.
+     */
+    ip = *in;
+    op = *out;
+    while (length > 0) {
+	/*
+	 * Get more input, xor it in.  If the length is
+	 * greater than or equal to 8 this is straight
+	 * forward.  Otherwise we have to fart around.
+	 */
+	if (length >= 8) {
+	    left  ^= ((*ip++) & FF_UINT32) << 24;
+	    left  ^= ((*ip++) & FF_UINT32) << 16;
+	    left  ^= ((*ip++) & FF_UINT32) <<  8;
+	    left  ^=  (*ip++) & FF_UINT32;
+	    right ^= ((*ip++) & FF_UINT32) << 24;
+	    right ^= ((*ip++) & FF_UINT32) << 16;
+	    right ^= ((*ip++) & FF_UINT32) <<  8;
+	    right ^=  (*ip++) & FF_UINT32;
+	    length -= 8;
+	} else {
+	    /*
+	     * Oh, shoot.  We need to pad the
+	     * end with zeroes.  Work backwards
+	     * to do this.
+	     */
+	    ip += (int) length;
+	    switch(length) {
+	    case 7:	right ^= (*(--ip) & FF_UINT32) <<  8;
+	    case 6:	right ^= (*(--ip) & FF_UINT32) << 16;
+	    case 5:	right ^= (*(--ip) & FF_UINT32) << 24;
+	    case 4:	left  ^=  *(--ip) & FF_UINT32;
+	    case 3:	left  ^= (*(--ip) & FF_UINT32) <<  8;
+	    case 2:	left  ^= (*(--ip) & FF_UINT32) << 16;
+	    case 1:	left  ^= (*(--ip) & FF_UINT32) << 24;
+
+	    }
+	    length = 0;
+	}
+
+	/*
+	 * Encrypt what we have
+	 */
+	DES_DO_ENCRYPT(left, right, kp1);
+	DES_DO_DECRYPT(left, right, kp2);
+	DES_DO_ENCRYPT(left, right, kp3);
+
+	/*
+	 * Copy the results out
+	 */
+	PUT_HALF_BLOCK(left, op);
+	PUT_HALF_BLOCK(right, op);
+    }
+}
+
+void
+krb5int_des3_cbc_decrypt(const mit_des_cblock *in,
+			 mit_des_cblock *out,
+			 unsigned long length,
+			 const mit_des_key_schedule ks1,
+			 const mit_des_key_schedule ks2,
+			 const mit_des_key_schedule ks3,
+			 const mit_des_cblock ivec)
+{
+    unsigned DES_INT32 left, right;
+    const unsigned DES_INT32 *kp1, *kp2, *kp3;
+    const unsigned char *ip;
+    unsigned char *op;
+    unsigned DES_INT32 ocipherl, ocipherr;
+    unsigned DES_INT32 cipherl, cipherr;
+
+    /*
+     * Get key pointer here.  This won't need to be reinitialized
+     */
+    kp1 = (const unsigned DES_INT32 *)ks1;
+    kp2 = (const unsigned DES_INT32 *)ks2;
+    kp3 = (const unsigned DES_INT32 *)ks3;
+
+    /*
+     * Decrypting is harder than encrypting because of
+     * the necessity of remembering a lot more things.
+     * Should think about this a little more...
+     */
+
+    if (length <= 0)
+	return;
+
+    /*
+     * Prime the old cipher with ivec.
+     */
+    ip = ivec;
+    GET_HALF_BLOCK(ocipherl, ip);
+    GET_HALF_BLOCK(ocipherr, ip);
+
+    /*
+     * Now do this in earnest until we run out of length.
+     */
+    ip = *in;
+    op = *out;
+    for (;;) {		/* check done inside loop */
+	/*
+	 * Read a block from the input into left and
+	 * right.  Save this cipher block for later.
+	 */
+	GET_HALF_BLOCK(left, ip);
+	GET_HALF_BLOCK(right, ip);
+	cipherl = left;
+	cipherr = right;
+
+	/*
+	 * Decrypt this.
+	 */
+	DES_DO_DECRYPT(left, right, kp3);
+	DES_DO_ENCRYPT(left, right, kp2);
+	DES_DO_DECRYPT(left, right, kp1);
+
+	/*
+	 * Xor with the old cipher to get plain
+	 * text.  Output 8 or less bytes of this.
+	 */
+	left ^= ocipherl;
+	right ^= ocipherr;
+	if (length > 8) {
+	    length -= 8;
+	    PUT_HALF_BLOCK(left, op);
+	    PUT_HALF_BLOCK(right, op);
+	    /*
+	     * Save current cipher block here
+	     */
+	    ocipherl = cipherl;
+	    ocipherr = cipherr;
+	} else {
+	    /*
+	     * Trouble here.  Start at end of output,
+	     * work backwards.
+	     */
+	    op += (int) length;
+	    switch(length) {
+	    case 8: *(--op) = (unsigned char) (right & 0xff);
+	    case 7: *(--op) = (unsigned char) ((right >> 8) & 0xff);
+	    case 6: *(--op) = (unsigned char) ((right >> 16) & 0xff);
+	    case 5: *(--op) = (unsigned char) ((right >> 24) & 0xff);
+	    case 4: *(--op) = (unsigned char) (left & 0xff);
+	    case 3: *(--op) = (unsigned char) ((left >> 8) & 0xff);
+	    case 2: *(--op) = (unsigned char) ((left >> 16) & 0xff);
+	    case 1: *(--op) = (unsigned char) ((left >> 24) & 0xff);
+	    }
+	    break;		/* we're done */
+	}
+    }
+}
diff --git a/mechglue/src/lib/crypto/des/d3_kysched.c b/mechglue/src/lib/crypto/des/d3_kysched.c
new file mode 100644
index 000000000..f18cc2419
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/d3_kysched.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1995 by Richard P. Basch.  All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+int
+mit_des3_key_sched(mit_des3_cblock k, mit_des3_key_schedule schedule)
+{
+    mit_des_make_key_sched(k[0],schedule[0]);
+    mit_des_make_key_sched(k[1],schedule[1]);
+    mit_des_make_key_sched(k[2],schedule[2]);
+
+    if (!mit_des_check_key_parity(k[0]))	/* bad parity --> return -1 */
+	return(-1);
+    if (mit_des_is_weak_key(k[0]))
+	return(-2);
+
+    if (!mit_des_check_key_parity(k[1]))
+	return(-1);
+    if (mit_des_is_weak_key(k[1]))
+	return(-2);
+
+    if (!mit_des_check_key_parity(k[2]))
+	return(-1);
+    if (mit_des_is_weak_key(k[2]))
+	return(-2);
+
+    /* if key was good, return 0 */
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/des/des_int.h b/mechglue/src/lib/crypto/des/des_int.h
new file mode 100644
index 000000000..c330a935a
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/des_int.h
@@ -0,0 +1,305 @@
+/*
+ * lib/crypto/des/des_int.h
+ *
+ * Copyright 1987, 1988, 1990, 2002 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Private include file for the Data Encryption Standard library.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* only do the whole thing once	 */
+#ifndef DES_INTERNAL_DEFS
+#define DES_INTERNAL_DEFS
+
+#include "k5-int.h"
+/*
+ * Begin "mit-des.h"
+ */
+#ifndef KRB5_MIT_DES__
+#define KRB5_MIT_DES__
+
+#define KRB5INT_CRYPTO_DES_INT	/* skip krb4-specific DES stuff */
+#include "kerberosIV/des.h"	/* for des_key_schedule, etc. */
+#undef KRB5INT_CRYPTO_DES_INT	/* don't screw other inclusions of des.h */
+
+typedef des_cblock mit_des_cblock;
+typedef des_key_schedule mit_des_key_schedule;
+
+/* Triple-DES structures */
+typedef mit_des_cblock		mit_des3_cblock[3];
+typedef mit_des_key_schedule	mit_des3_key_schedule[3];
+
+#define MIT_DES_ENCRYPT	1
+#define MIT_DES_DECRYPT	0
+
+typedef struct mit_des_ran_key_seed {
+    krb5_encrypt_block eblock;
+    krb5_data sequence;
+} mit_des_random_state;
+
+/* the first byte of the key is already in the keyblock */
+
+#define MIT_DES_BLOCK_LENGTH 		(8*sizeof(krb5_octet))
+#define	MIT_DES_CBC_CRC_PAD_MINIMUM	CRC32_CKSUM_LENGTH
+/* This used to be 8*sizeof(krb5_octet) */
+#define MIT_DES_KEYSIZE		 	8
+
+#define MIT_DES_CBC_CKSUM_LENGTH	(4*sizeof(krb5_octet))
+
+/*
+ * Check if k5-int.h has been included before us.  If so, then check to see
+ * that our view of the DES key size is the same as k5-int.h's.
+ */
+#ifdef	KRB5_MIT_DES_KEYSIZE
+#if	MIT_DES_KEYSIZE != KRB5_MIT_DES_KEYSIZE
+error(MIT_DES_KEYSIZE does not equal KRB5_MIT_DES_KEYSIZE)
+#endif	/* MIT_DES_KEYSIZE != KRB5_MIT_DES_KEYSIZE */
+#endif	/* KRB5_MIT_DES_KEYSIZE */
+#endif /* KRB5_MIT_DES__ */
+/*
+ * End "mit-des.h"
+ */
+
+/* afsstring2key.c */
+extern krb5_error_code mit_afs_string_to_key
+	(krb5_keyblock *keyblock,
+		   const krb5_data *data,
+		   const krb5_data *salt);
+extern char *mit_afs_crypt
+    (const char *pw, const char *salt, char *iobuf);
+
+/* f_cksum.c */
+extern unsigned long mit_des_cbc_cksum
+    (const krb5_octet *, krb5_octet *, unsigned long ,
+     const mit_des_key_schedule, const krb5_octet *);
+
+/* f_ecb.c */
+extern int mit_des_ecb_encrypt
+    (const mit_des_cblock *, mit_des_cblock *, mit_des_key_schedule , int );
+
+/* f_cbc.c */
+extern int mit_des_cbc_encrypt (const mit_des_cblock *in,
+				mit_des_cblock *out,
+				unsigned long length,
+				const mit_des_key_schedule schedule,
+				const mit_des_cblock ivec, int enc);
+    
+#define mit_des_zeroblock krb5int_c_mit_des_zeroblock
+extern const mit_des_cblock mit_des_zeroblock;
+
+/* fin_rndkey.c */
+extern krb5_error_code mit_des_finish_random_key
+    ( const krb5_encrypt_block *,
+		krb5_pointer *);
+
+/* finish_key.c */
+extern krb5_error_code mit_des_finish_key
+    ( krb5_encrypt_block *);
+
+/* init_rkey.c */
+extern krb5_error_code mit_des_init_random_key
+    ( const krb5_encrypt_block *,
+		const krb5_keyblock *,
+		krb5_pointer *);
+
+/* key_parity.c */
+extern void mit_des_fixup_key_parity (mit_des_cblock );
+extern int mit_des_check_key_parity (mit_des_cblock );
+
+/* key_sched.c */
+extern int mit_des_key_sched
+    (mit_des_cblock , mit_des_key_schedule );
+
+/* process_ky.c */
+extern krb5_error_code mit_des_process_key
+    ( krb5_encrypt_block *,  const krb5_keyblock *);
+
+/* random_key.c */
+extern krb5_error_code mit_des_random_key
+    ( const krb5_encrypt_block *, krb5_pointer ,
+                krb5_keyblock **);
+
+/* string2key.c */
+extern krb5_error_code mit_des_string_to_key
+    ( const krb5_encrypt_block *, 
+	       krb5_keyblock *, const krb5_data *, const krb5_data *);
+extern krb5_error_code mit_des_string_to_key_int
+	(krb5_keyblock *, const krb5_data *, const krb5_data *);
+
+/* weak_key.c */
+extern int mit_des_is_weak_key (mit_des_cblock );
+
+/* cmb_keys.c */
+krb5_error_code mit_des_combine_subkeys
+    (const krb5_keyblock *, const krb5_keyblock *,
+	       krb5_keyblock **);
+
+/* f_pcbc.c */
+int mit_des_pcbc_encrypt ();
+
+/* f_sched.c */
+int mit_des_make_key_sched(mit_des_cblock, mit_des_key_schedule);
+
+
+/* misc.c */
+extern void swap_bits (char *);
+extern unsigned long long_swap_bits (unsigned long );
+extern unsigned long swap_six_bits_to_ansi (unsigned long );
+extern unsigned long swap_four_bits_to_ansi (unsigned long );
+extern unsigned long swap_bit_pos_1 (unsigned long );
+extern unsigned long swap_bit_pos_0 (unsigned long );
+extern unsigned long swap_bit_pos_0_to_ansi (unsigned long );
+extern unsigned long rev_swap_bit_pos_0 (unsigned long );
+extern unsigned long swap_byte_bits (unsigned long );
+extern unsigned long swap_long_bytes_bit_number (unsigned long );
+#ifdef FILE
+/* XXX depends on FILE being a #define! */
+extern void test_set (FILE *, const char *, int, const char *, int);
+#endif
+
+/* d3_ecb.c */
+extern int mit_des3_ecb_encrypt
+	(const mit_des_cblock *in,
+		   mit_des_cblock *out,
+		   mit_des_key_schedule sched1,
+		   mit_des_key_schedule sched2,
+		   mit_des_key_schedule sched3,
+		   int enc);
+
+/* d3_cbc.c */
+extern int mit_des3_cbc_encrypt
+	(const mit_des_cblock *in,
+	 mit_des_cblock *out,
+	 unsigned long length,
+	 const mit_des_key_schedule ks1,
+	 const mit_des_key_schedule ks2,
+	 const mit_des_key_schedule ks3,
+	 const mit_des_cblock ivec,
+	 int enc);
+
+void
+krb5int_des3_cbc_encrypt(const mit_des_cblock *in,
+			 mit_des_cblock *out,
+			 unsigned long length,
+			 const mit_des_key_schedule ks1,
+			 const mit_des_key_schedule ks2,
+			 const mit_des_key_schedule ks3,
+			 const mit_des_cblock ivec);
+void
+krb5int_des3_cbc_decrypt(const mit_des_cblock *in,
+			 mit_des_cblock *out,
+			 unsigned long length,
+			 const mit_des_key_schedule ks1,
+			 const mit_des_key_schedule ks2,
+			 const mit_des_key_schedule ks3,
+			 const mit_des_cblock ivec);
+
+
+#define mit_des3_cbc_encrypt(in,out,length,ks1,ks2,ks3,ivec,enc) \
+    ((enc ? krb5int_des3_cbc_encrypt : krb5int_des3_cbc_decrypt) \
+     (in, out, length, ks1, ks2, ks3, ivec), 0)
+
+void
+krb5int_des_cbc_encrypt(const mit_des_cblock *in,
+			mit_des_cblock *out,
+			unsigned long length,
+			const mit_des_key_schedule schedule,
+			const mit_des_cblock ivec);
+void
+krb5int_des_cbc_decrypt(const mit_des_cblock *in,
+			mit_des_cblock *out,
+			unsigned long length,
+			const mit_des_key_schedule schedule,
+			const mit_des_cblock ivec);
+
+#define mit_des_cbc_encrypt(in,out,length,schedule,ivec,enc) \
+    ((enc ? krb5int_des_cbc_encrypt : krb5int_des_cbc_decrypt) \
+     (in, out, length, schedule, ivec), 0)
+
+
+/* d3_procky.c */
+extern krb5_error_code mit_des3_process_key
+	(krb5_encrypt_block * eblock,
+		   const krb5_keyblock * keyblock);
+
+/* d3_kysched.c */
+extern int mit_des3_key_sched
+	(mit_des3_cblock key,
+		   mit_des3_key_schedule schedule);
+
+/* d3_str2ky.c */
+extern krb5_error_code mit_des3_string_to_key
+	(const krb5_encrypt_block * eblock,
+		   krb5_keyblock * keyblock,
+		   const krb5_data * data,
+		   const krb5_data * salt);
+
+/* u_nfold.c */
+extern krb5_error_code mit_des_n_fold
+	(const krb5_octet * input,
+		   const size_t in_len,
+		   krb5_octet * output,
+		   const size_t out_len);
+
+/* u_rn_key.c */
+extern int mit_des_is_weak_keyblock
+	(krb5_keyblock *keyblock);
+
+extern void mit_des_fixup_keyblock_parity
+	(krb5_keyblock *keyblock);
+
+extern krb5_error_code mit_des_set_random_generator_seed
+	(const krb5_data * seed,
+		   krb5_pointer random_state);
+
+extern krb5_error_code mit_des_set_random_sequence_number
+	(const krb5_data * sequence,
+		   krb5_pointer random_state);
+
+#endif	/*DES_INTERNAL_DEFS*/
diff --git a/mechglue/src/lib/crypto/des/destest.c b/mechglue/src/lib/crypto/des/destest.c
new file mode 100644
index 000000000..2582cc3d3
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/destest.c
@@ -0,0 +1,247 @@
+/*
+ * lib/crypto/des/destest.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Test a DES implementation against known inputs & outputs
+ */
+
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "des_int.h"
+#include "com_err.h"
+
+#include <stdio.h>
+
+void convert (char *, unsigned char []);
+
+void des_cblock_print_file (mit_des_cblock, FILE *);
+
+krb5_octet zeroblock[8] = {0,0,0,0,0,0,0,0};
+
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    char block1[17], block2[17], block3[17];
+#if 0
+    mit_des_cblock key, input, output, output2;
+#else
+    /* Force tests of unaligned accesses.  */
+    union { unsigned char c[8*4+3]; long l; } u;
+    unsigned char *ioblocks = u.c;
+    unsigned char *input = ioblocks+1;
+    unsigned char *output = ioblocks+10;
+    unsigned char *output2 = ioblocks+19;
+    unsigned char *key = ioblocks+27;
+#endif
+    mit_des_key_schedule sched;
+    int num = 0;
+    int retval;
+
+    int error = 0;
+
+    while (scanf("%16s %16s %16s", block1, block2, block3) == 3) {
+	convert(block1, key);
+	convert(block2, input);
+	convert(block3, output);
+
+	retval = mit_des_key_sched(key, sched);
+	if (retval) {
+            fprintf(stderr, "des test: can't process key");
+            exit(1);
+        }
+	mit_des_cbc_encrypt((const mit_des_cblock *) input, output2, 8,
+			    sched, zeroblock, 1);
+
+	if (memcmp((char *)output2, (char *)output, 8)) {
+	    fprintf(stderr, 
+		    "DES ENCRYPT ERROR, key %s, text %s, real cipher %s, computed cyphertext %02X%02X%02X%02X%02X%02X%02X%02X\n",
+		    block1, block2, block3,
+		    output2[0],output2[1],output2[2],output2[3],
+		    output2[4],output2[5],output2[6],output2[7]);
+	    error++;
+	}
+
+	/*
+	 * Now try decrypting....
+	 */
+	mit_des_cbc_encrypt((const mit_des_cblock *) output, output2, 8,
+			    sched, zeroblock, 0);
+
+	if (memcmp((char *)output2, (char *)input, 8)) {
+	    fprintf(stderr, 
+		    "DES DECRYPT ERROR, key %s, text %s, real cipher %s, computed cleartext %02X%02X%02X%02X%02X%02X%02X%02X\n",
+		    block1, block2, block3,
+		    output2[0],output2[1],output2[2],output2[3],
+		    output2[4],output2[5],output2[6],output2[7]);
+	    error++;
+	}
+
+	num++;
+    }
+
+    if (error) 
+	printf("destest: failed to pass the test\n");
+    else
+	printf("destest: %d tests passed successfully\n", num);
+
+    exit( (error > 256 && error % 256) ? 1 : error);
+}
+
+int value[128] = {
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+0, 1, 2, 3, 4, 5, 6, 7,
+8, 9, -1, -1, -1, -1, -1, -1,
+-1, 10, 11, 12, 13, 14, 15, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+-1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+void
+convert(text, cblock)
+    char *text;
+    unsigned char cblock[];
+{
+    register int i;
+    for (i = 0; i < 8; i++) {
+	if (text[i*2] < 0 || text[i*2] >= 128)
+	    abort ();
+	if (value[(int) text[i*2]] == -1 || value[(int) text[i*2+1]] == -1) {
+	    printf("Bad value byte %d in %s\n", i, text);
+	    exit(1);
+	}
+	cblock[i] = 16*value[(int) text[i*2]] + value[(int) text[i*2+1]];
+    }
+    return;
+}
+
+/*
+ * Fake out the DES library, for the purposes of testing.
+ */
+
+#include "des_int.h"
+
+int
+mit_des_is_weak_key(key)
+    mit_des_cblock key;
+{
+    return 0;				/* fake it out for testing */
+}
+
+void
+des_cblock_print_file(x, fp)
+    mit_des_cblock x;
+    FILE *fp;
+{
+    unsigned char *y = (unsigned char *) x;
+    register int i = 0;
+    fprintf(fp," 0x { ");
+
+    while (i++ < 8) {
+        fprintf(fp,"%x",*y++);
+        if (i < 8)
+            fprintf(fp,", ");
+    }
+    fprintf(fp," }");
+}
+
+
+#define smask(step) ((1<<step)-1)
+#define pstep(x,step) (((x)&smask(step))^(((x)>>step)&smask(step)))
+#define parity_char(x) pstep(pstep(pstep((x),4),2),1)
+
+/*
+ * des_check_key_parity: returns true iff key has the correct des parity.
+ *                       See des_fix_key_parity for the definition of
+ *                       correct des parity.
+ */
+int
+mit_des_check_key_parity(key)
+     register mit_des_cblock key;
+{
+    int i;
+    
+    for (i=0; i<sizeof(mit_des_cblock); i++) {
+	if ((key[i] & 1) == parity_char(0xfe&key[i])) {
+	    printf("warning: bad parity key:");
+	    des_cblock_print_file(key, stdout); 
+	    putchar('\n');
+	      
+	    return 1;
+	}
+    }
+
+    return(1);
+}
+
+void
+mit_des_fixup_key_parity(key)
+     register mit_des_cblock key;
+{
+    int i;
+    for (i=0; i<sizeof(mit_des_cblock); i++) 
+      {
+	key[i] &= 0xfe;
+	key[i] |= 1^parity_char(key[i]);
+      }
+  
+    return;
+}
diff --git a/mechglue/src/lib/crypto/des/doc/.Sanitize b/mechglue/src/lib/crypto/des/doc/.Sanitize
new file mode 100644
index 000000000..ea2692428
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/doc/.Sanitize
@@ -0,0 +1,32 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+libdes.doc
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/crypto/des/doc/libdes.doc b/mechglue/src/lib/crypto/des/doc/libdes.doc
new file mode 100644
index 000000000..70f9f336a
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/doc/libdes.doc
@@ -0,0 +1,208 @@
+
+	How to use the Kerberos encryption library.
+
+			Revised		10/15/85	spm
+
+1)	The following include file is needed:
+	
+	/projects/auth/include/des.h	(VAX)
+	---------------					(PC8086)
+
+2)	The encryption library that should be linked to is:
+	
+	/projects/auth/lib/libdes.a		(VAX)
+|	/projects/auth/ibm/lib/libdes.a	(PC8086 cross-compilation environment)
+
+3)	For each key that may be simultaneously active,
+	allocate (either compile or malloc) a "Key_schedule" struct, 
+	defined in "des.h"
+
+4)	Create key schedules, as needed, prior to using the encryption
+	routines, via "des_set_key()".
+
+5)  Setup the input and output areas.  Make sure to note the restrictions
+	on lengths being multiples of eight bytes.
+
+6)	Invoke the encryption/decryption routines, "ecb_encrypt()"
+	 or "cbc_encrypt()"
+
+7)	To generate a cryptographic checksum, use "cbc_cksum()"
+/*	----------------------------------------------------------------	*/
+	
+	Routine Interfaces--
+
+/*	-----------------------------------------------------------------	*/
+
+int
+	des_set_key(k,schedule)
+		C_Block			*k;
+		Key_schedule	schedule;
+
+	Calculates a key schedule from (all) eight bytes of the input key, and
+	puts it into the indicated "Key_schedule" struct;
+
+	Make sure to pass valid eight bytes, no padding or other processing
+	it done.
+
+	The key schedule is then used in subsequent encryption/decryption
+	operations.  Many key schedules may be created and cached for later
+	use.
+
+	The user is responsible to clear keys and schedules no longer needed
+	to prevent their disclosure.
+
+|	Checks the parity of the key provided, to make sure it is odd per
+|	FIPS spec.  Returns 0 value for key ok, 1 for key_parity error.
+
+/*	----------------------------------------------------------------	*/
+	
+int
+	ecb_encrypt(input,output,schedule,encrypt)
+		C_Block			*input;		/* ptr to eight byte input value */
+		C_Block			*output;	/* ptr to eight byte output value */
+		int				encrypt;	/* 0 ==> decrypt, else encrypt */
+		Key_schedule	schedule;	/* addr of key schedule */
+
+This is the low level routine that encrypts or decrypts a single 8-byte
+block in electronic code book mode.  Always transforms the input
+data into the output data.
+
+If encrypt is non-zero, the input (cleartext) is encrypted into the
+output (ciphertext) using the specified key_schedule, pre-set via "des_set_key".
+
+If encrypt is zero, the input (now ciphertext) is decrypted into
+the output (now cleartext).
+
+Input and output may be the same space.
+
+Does not return any meaningful value.  Void is not used for compatibility
+with other compilers.
+
+/*	--------------------------------------------------------------	*/
+
+int	
+	cbc_encrypt(input,output,length,schedule,ivec,encrypt)
+
+		C_Block			*input;		/* ptr to input data */
+		C_Block			*output;	/* ptr to output data */
+		int				length;		/* desired length, in bytes */
+		Key_schedule	schedule;		/* addr of precomputed schedule */
+		C_Block			*ivec;		/* pointer to 8 byte initialization
+									 * vector
+									 */
+		int				encrypt		/* 0 ==> decrypt; else encrypt*/
+
+
+	If encrypt is non-zero, the routine cipher-block-chain encrypts
+	the INPUT (cleartext) into the OUTPUT (ciphertext) using the provided
+	key schedule and initialization vector.  If the length is not an integral
+	multiple of eight bytes, the last block is copied to a temp and zero 
+	filled (highest addresses).  The output is ALWAYS an integral multiple
+	of eight bytes.
+
+	If encrypt is zero, the routine cipher-block chain decrypts the INPUT
+	(ciphertext) into the OUTPUT (cleartext) using the provided key schedule
+	and	initialization vector.	Decryption ALWAYS operates on integral
+	multiples of 8 bytes, so will round the length provided up to the
+	appropriate	multiple. Consequently,	it will always produce the rounded-up
+	number of bytes of output cleartext. The application must determine if
+	the output cleartext was zero-padded due to cleartext lengths not integral
+	multiples of 8.
+
+	No errors or meaningful value are returned.  Void is not used for
+	compatibility with other compilers.
+
+
+/* cbc checksum (MAC) only routine  ---------------------------------------- */
+int	
+	cbc_cksum(input,output,length,schedule,ivec)
+
+	C_Block		 	*input;		/* >= length bytes of inputtext	 */
+	C_Block		 	*output;	/* >= length bytes of outputtext */
+	int				length;		/* in bytes						*/
+	Key_schedule	schedule;	/* precomputed key schedule	   */
+	C_Block			*ivec;		/* 8 bytes of ivec			   */
+
+
+	Produces a cryptographic checksum, 8 bytes, by cipher-block-chain
+	encrypting the input, discarding the ciphertext output, and only retaining
+	the last ciphertext 8-byte block.  Uses the provided key schedule and ivec.
+	The input is effectively zero-padded to an integral multiple of
+	eight bytes, though the original input is not modified.
+
+	No meaningful value is returned.  Void is not used for compatibility
+	with other compilers.
+
+
+/*	random_key ----------------------------------------*/
+int
+	random_key(key)
+
+	C_Block	*key;
+
+	The start for the random number generated is set from the current time
+	in microseconds, then the random number generator is invoked
+	to create an eight byte output key (not a schedule).  The key
+	generated is set to odd parity per FIPS spec.
+
+	The caller must	supply space for the output key, pointed to 
+	by "*key", then after getting a new key, call the des_set_key() 
+	routine when needed.
+
+	No meaningfull value is returned.  Void is not used for compatibility
+	with other compilers.
+
+
+/* string_to_key --------------------------------------------*/
+
+int
+	string_to_key(str,key)
+	register char		*str;
+	register C_Block	*key;
+
+	This routines converts an arbitrary length, null terminated string
+	to an 8 byte DES key, with each byte parity set to odd, per FIPS spec.
+
+	The algorithm is as follows:
+
+|	Take the first 8 bytes and remove the parity (leaving 56 bits).
+|	Do the same for the second 8 bytes, and the third, etc.  Do this for
+|	as many sets of 8 bytes as necessary, filling in the remainder of the
+|	last set with nulls.  Fold the second set back on the first (i.e. bit
+|	0 over bit 55, and bit 55 over bit 0).  Fold the third over the second
+|	(bit 0 of the third set is now over bit 0 of the first set).  Repeat
+|	until you have done this to all sets.  Xor the folded sets.  Break the
+|	result into 8 7 bit bytes, and generate odd parity for each byte.  You
+|	now have 64 bits.  Note that DES takes a 64 bit key, and uses only the
+|	non parity bits.
+
+
+/* read_password -------------------------------------------*/
+
+read_password(k,prompt,verify)
+	C_Block	*k;
+	char *prompt;
+	int	verify;
+
+This routine issues the supplied prompt, turns off echo, if possible, and
+reads an input string.  If verify is non-zero, it does it again, for use
+in applications such as changing a password. If verify is non-zero, both
+versions are compared, and the input is requested repeatedly until they
+match.  Then, the input string is mapped into a valid DES key, internally
+using the string_to_key routine.  The newly created key is copied to the
+area pointed to by parameter "k".  
+
+No meaningful value is returned.  If an error occurs trying to manipulate
+the terminal echo, the routine forces the process to exit.
+
+/* get_line ------------------------*/
+long get_line(p,max)
+	char	*p;
+	long	max;
+
+Reads input characters from standard input until either a newline appears or
+else the max length is reached.  The characters read are stuffed into
+the string pointed to, which will always be null terminated.  The newline
+is not inserted in the string.  The max parameter includes the byte needed
+for the null terminator, so allocate and pass one more than the maximum
+string length desired.
diff --git a/mechglue/src/lib/crypto/des/f_cbc.c b/mechglue/src/lib/crypto/des/f_cbc.c
new file mode 100644
index 000000000..24996e489
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/f_cbc.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 1990 Dennis Ferguson.  All rights reserved.
+ *
+ * Commercial use is permitted only if products which are derived from
+ * or include this software are made available for purchase and/or use
+ * in Canada.  Otherwise, redistribution and use in source and binary
+ * forms are permitted.
+ */
+
+/*
+ * des_cbc_encrypt.c - an implementation of the DES cipher function in cbc mode
+ */
+#include "des_int.h"
+#include "f_tables.h"
+
+/*
+ * des_cbc_encrypt - {en,de}crypt a stream in CBC mode
+ */
+
+/*
+ * This routine performs DES cipher-block-chaining operation, either
+ * encrypting from cleartext to ciphertext, if encrypt != 0 or
+ * decrypting from ciphertext to cleartext, if encrypt == 0.
+ *
+ * The key schedule is passed as an arg, as well as the cleartext or
+ * ciphertext.  The cleartext and ciphertext should be in host order.
+ *
+ * NOTE-- the output is ALWAYS an multiple of 8 bytes long.  If not
+ * enough space was provided, your program will get trashed.
+ *
+ * For encryption, the cleartext string is null padded, at the end, to
+ * an integral multiple of eight bytes.
+ *
+ * For decryption, the ciphertext will be used in integral multiples
+ * of 8 bytes, but only the first "length" bytes returned into the
+ * cleartext.
+ */
+
+const mit_des_cblock mit_des_zeroblock /* = all zero */;
+
+#undef mit_des_cbc_encrypt
+int
+mit_des_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
+		    unsigned long length, const mit_des_key_schedule schedule,
+		    const mit_des_cblock ivec, int enc)
+{
+    /*
+     * Deal with encryption and decryption separately.
+     */
+    if (enc)
+	krb5int_des_cbc_encrypt(in, out, length, schedule, ivec);
+    else
+	krb5int_des_cbc_decrypt(in, out, length, schedule, ivec);
+    return 0;
+}
+
+void
+krb5int_des_cbc_encrypt(const mit_des_cblock *in,
+			mit_des_cblock *out,
+			unsigned long length,
+			const mit_des_key_schedule schedule,
+			const mit_des_cblock ivec)
+{
+	unsigned DES_INT32 left, right;
+	const unsigned DES_INT32 *kp;
+	const unsigned char *ip;
+	unsigned char *op;
+
+	/*
+	 * Get key pointer here.  This won't need to be reinitialized
+	 */
+	kp = (const unsigned DES_INT32 *)schedule;
+
+	/*
+	 * Initialize left and right with the contents of the initial
+	 * vector.
+	 */
+	ip = ivec;
+	GET_HALF_BLOCK(left, ip);
+	GET_HALF_BLOCK(right, ip);
+
+	/*
+	 * Suitably initialized, now work the length down 8 bytes
+	 * at a time.
+	 */
+	ip = *in;
+	op = *out;
+	while (length > 0) {
+		/*
+		 * Get more input, xor it in.  If the length is
+		 * greater than or equal to 8 this is straight
+		 * forward.  Otherwise we have to fart around.
+		 */
+		if (length >= 8) {
+			unsigned DES_INT32 temp;
+			GET_HALF_BLOCK(temp, ip);
+			left  ^= temp;
+			GET_HALF_BLOCK(temp, ip);
+			right ^= temp;
+			length -= 8;
+		} else {
+			/*
+			 * Oh, shoot.  We need to pad the
+			 * end with zeroes.  Work backwards
+			 * to do this.
+			 */
+			ip += (int) length;
+			switch(length) {
+			case 7:
+				right ^= (*(--ip) & FF_UINT32) <<  8;
+			case 6:
+				right ^= (*(--ip) & FF_UINT32) << 16;
+			case 5:
+				right ^= (*(--ip) & FF_UINT32) << 24;
+			case 4:
+				left  ^=  *(--ip) & FF_UINT32;
+			case 3:
+				left  ^= (*(--ip) & FF_UINT32) <<  8;
+			case 2:
+				left  ^= (*(--ip) & FF_UINT32) << 16;
+			case 1:
+				left  ^= (*(--ip) & FF_UINT32) << 24;
+				break;
+			}
+			length = 0;
+		}
+
+		/*
+		 * Encrypt what we have
+		 */
+		DES_DO_ENCRYPT(left, right, kp);
+
+		/*
+		 * Copy the results out
+		 */
+		PUT_HALF_BLOCK(left, op);
+		PUT_HALF_BLOCK(right, op);
+	}
+}
+
+void
+krb5int_des_cbc_decrypt(const mit_des_cblock *in,
+			mit_des_cblock *out,
+			unsigned long length,
+			const mit_des_key_schedule schedule,
+			const mit_des_cblock ivec)
+{
+	unsigned DES_INT32 left, right;
+	const unsigned DES_INT32 *kp;
+	const unsigned char *ip;
+	unsigned char *op;
+	unsigned DES_INT32 ocipherl, ocipherr;
+	unsigned DES_INT32 cipherl, cipherr;
+
+	/*
+	 * Get key pointer here.  This won't need to be reinitialized
+	 */
+	kp = (const unsigned DES_INT32 *)schedule;
+
+	/*
+	 * Decrypting is harder than encrypting because of
+	 * the necessity of remembering a lot more things.
+	 * Should think about this a little more...
+	 */
+
+	if (length <= 0)
+		return;
+
+	/*
+	 * Prime the old cipher with ivec.
+	 */
+	ip = ivec;
+	GET_HALF_BLOCK(ocipherl, ip);
+	GET_HALF_BLOCK(ocipherr, ip);
+
+	/*
+	 * Now do this in earnest until we run out of length.
+	 */
+	ip = *in;
+	op = *out;
+	for (;;) {		/* check done inside loop */
+		/*
+		 * Read a block from the input into left and
+		 * right.  Save this cipher block for later.
+		 */
+		GET_HALF_BLOCK(left, ip);
+		GET_HALF_BLOCK(right, ip);
+		cipherl = left;
+		cipherr = right;
+
+		/*
+		 * Decrypt this.
+		 */
+		DES_DO_DECRYPT(left, right, kp);
+
+		/*
+		 * Xor with the old cipher to get plain
+		 * text.  Output 8 or less bytes of this.
+		 */
+		left ^= ocipherl;
+		right ^= ocipherr;
+		if (length > 8) {
+			length -= 8;
+			PUT_HALF_BLOCK(left, op);
+			PUT_HALF_BLOCK(right, op);
+			/*
+			 * Save current cipher block here
+			 */
+			ocipherl = cipherl;
+			ocipherr = cipherr;
+		} else {
+			/*
+			 * Trouble here.  Start at end of output,
+			 * work backwards.
+			 */
+			op += (int) length;
+			switch(length) {
+			case 8:
+				*(--op) = (unsigned char) (right & 0xff);
+			case 7:
+				*(--op) = (unsigned char) ((right >> 8) & 0xff);
+			case 6:
+				*(--op) = (unsigned char) ((right >> 16) & 0xff);
+			case 5:
+				*(--op) = (unsigned char) ((right >> 24) & 0xff);
+			case 4:
+				*(--op) = (unsigned char) (left & 0xff);
+			case 3:
+				*(--op) = (unsigned char) ((left >> 8) & 0xff);
+			case 2:
+				*(--op) = (unsigned char) ((left >> 16) & 0xff);
+			case 1:
+				*(--op) = (unsigned char) ((left >> 24) & 0xff);
+				break;
+			}
+			break;		/* we're done */
+		}
+	}
+}
+
+#ifdef CONFIG_SMALL
+void krb5int_des_do_encrypt_2 (unsigned DES_INT32 *left,
+			       unsigned DES_INT32 *right,
+			       const unsigned DES_INT32 *kp)
+{
+    DES_DO_ENCRYPT_1 (*left, *right, kp);
+}
+
+void krb5int_des_do_decrypt_2 (unsigned DES_INT32 *left,
+			       unsigned DES_INT32 *right,
+			       const unsigned DES_INT32 *kp)
+{
+    DES_DO_DECRYPT_1 (*left, *right, kp);
+}
+#endif
diff --git a/mechglue/src/lib/crypto/des/f_cksum.c b/mechglue/src/lib/crypto/des/f_cksum.c
new file mode 100644
index 000000000..1b9e9a02b
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/f_cksum.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1990 Dennis Ferguson.  All rights reserved.
+ *
+ * Commercial use is permitted only if products which are derived from
+ * or include this software are made available for purchase and/or use
+ * in Canada.  Otherwise, redistribution and use in source and binary
+ * forms are permitted.
+ */
+
+/*
+ * des_cbc_cksum.c - compute an 8 byte checksum using DES in CBC mode
+ */
+#include "des_int.h"
+#include "f_tables.h"
+
+/*
+ * This routine performs DES cipher-block-chaining checksum operation,
+ * a.k.a.  Message Authentication Code.  It ALWAYS encrypts from input
+ * to a single 64 bit output MAC checksum.
+ *
+ * The key schedule is passed as an arg, as well as the cleartext or
+ * ciphertext. The cleartext and ciphertext should be in host order.
+ *
+ * NOTE-- the output is ALWAYS 8 bytes long.  If not enough space was
+ * provided, your program will get trashed.
+ *
+ * The input is null padded, at the end (highest addr), to an integral
+ * multiple of eight bytes.
+ */
+
+unsigned long
+mit_des_cbc_cksum(const krb5_octet *in, krb5_octet *out,
+		  unsigned long length, const mit_des_key_schedule schedule,
+		  const krb5_octet *ivec)
+{
+	unsigned DES_INT32 left, right;
+	const unsigned DES_INT32 *kp;
+	const unsigned char *ip;
+	unsigned char *op;
+	register DES_INT32 len;
+
+	/*
+	 * Initialize left and right with the contents of the initial
+	 * vector.
+	 */
+	ip = ivec;
+	GET_HALF_BLOCK(left, ip);
+	GET_HALF_BLOCK(right, ip);
+
+	/*
+	 * Suitably initialized, now work the length down 8 bytes
+	 * at a time.
+	 */
+	ip = in;
+	len = length;
+	while (len > 0) {
+		/*
+		 * Get more input, xor it in.  If the length is
+		 * greater than or equal to 8 this is straight
+		 * forward.  Otherwise we have to fart around.
+		 */
+		if (len >= 8) {
+			left  ^= ((*ip++) & FF_UINT32) << 24;
+			left  ^= ((*ip++) & FF_UINT32) << 16;
+			left  ^= ((*ip++) & FF_UINT32) <<  8;
+			left  ^=  (*ip++) & FF_UINT32;
+			right ^= ((*ip++) & FF_UINT32) << 24;
+			right ^= ((*ip++) & FF_UINT32) << 16;
+			right ^= ((*ip++) & FF_UINT32) <<  8;
+			right ^=  (*ip++) & FF_UINT32;
+			len -= 8;
+		} else {
+			/*
+			 * Oh, shoot.  We need to pad the
+			 * end with zeroes.  Work backwards
+			 * to do this.
+			 */
+			ip += (int) len;
+			switch(len) {
+			case 7:
+				right ^= (*(--ip) & FF_UINT32) <<  8;
+			case 6:
+				right ^= (*(--ip) & FF_UINT32) << 16;
+			case 5:
+				right ^= (*(--ip) & FF_UINT32) << 24;
+			case 4:
+				left  ^=  *(--ip) & FF_UINT32;
+			case 3:
+				left  ^= (*(--ip) & FF_UINT32) <<  8;
+			case 2:
+				left  ^= (*(--ip) & FF_UINT32) << 16;
+			case 1:
+				left  ^= (*(--ip) & FF_UINT32) << 24;
+				break;
+			}
+			len = 0;
+		}
+
+		/*
+		 * Encrypt what we have
+		 */
+		kp = (const unsigned DES_INT32 *)schedule;
+		DES_DO_ENCRYPT(left, right, kp);
+	}
+
+	/*
+	 * Done.  Left and right have the checksum.  Put it into
+	 * the output.
+	 */
+	op = out;
+	PUT_HALF_BLOCK(left, op);
+	PUT_HALF_BLOCK(right, op);
+
+	/*
+	 * Return right.  I'll bet the MIT code returns this
+	 * inconsistantly (with the low order byte of the checksum
+	 * not always in the low order byte of the DES_INT32).  We won't.
+	 */
+	return right & 0xFFFFFFFFUL;
+}
diff --git a/mechglue/src/lib/crypto/des/f_parity.c b/mechglue/src/lib/crypto/des/f_parity.c
new file mode 100644
index 000000000..26cf6039b
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/f_parity.c
@@ -0,0 +1,56 @@
+/*
+ * These routines check and fix parity of encryption keys for the DES
+ * algorithm.
+ *
+ * They are a replacement for routines in key_parity.c, that don't require
+ * the table building that they do.
+ *
+ * Mark Eichin -- Cygnus Support
+ */
+
+
+#include "des_int.h"
+
+/*
+ * des_fixup_key_parity: Forces odd parity per byte; parity is bits
+ *                       8,16,...64 in des order, implies 0, 8, 16, ...
+ *                       vax order.
+ */
+#define smask(step) ((1<<step)-1)
+#define pstep(x,step) (((x)&smask(step))^(((x)>>step)&smask(step)))
+#define parity_char(x) pstep(pstep(pstep((x),4),2),1)
+
+void
+mit_des_fixup_key_parity(mit_des_cblock key)
+{
+    int i;
+    for (i=0; i<sizeof(mit_des_cblock); i++) 
+      {
+	key[i] &= 0xfe;
+	key[i] |= 1^parity_char(key[i]);
+      }
+  
+    return;
+}
+
+/*
+ * des_check_key_parity: returns true iff key has the correct des parity.
+ *                       See des_fix_key_parity for the definition of
+ *                       correct des parity.
+ */
+int
+mit_des_check_key_parity(mit_des_cblock key)
+{
+    int i;
+    
+    for (i=0; i<sizeof(mit_des_cblock); i++) 
+      {
+	if((key[i] & 1) == parity_char(0xfe&key[i])) 
+	  {
+	    return 0;
+	  }
+      }
+
+    return(1);
+}
+
diff --git a/mechglue/src/lib/crypto/des/f_sched.c b/mechglue/src/lib/crypto/des/f_sched.c
new file mode 100644
index 000000000..99d1dc313
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/f_sched.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 1990 Dennis Ferguson.  All rights reserved.
+ *
+ * Commercial use is permitted only if products which are derived from
+ * or include this software are made available for purchase and/or use
+ * in Canada.  Otherwise, redistribution and use in source and binary
+ * forms are permitted.
+ */
+
+/*
+ * des_make_sched.c - permute a DES key, returning the resulting key schedule
+ */
+#include "k5-int.h"
+#include "des_int.h"
+
+/*
+ * Permuted choice 1 tables.  These are used to extract bits
+ * from the left and right parts of the key to form Ci and Di.
+ * The code that uses these tables knows which bits from which
+ * part of each key are used to form Ci and Di.
+ */
+static const unsigned DES_INT32 PC1_CL[8] = {
+	0x00000000, 0x00000010, 0x00001000, 0x00001010,
+	0x00100000, 0x00100010, 0x00101000, 0x00101010
+};
+
+static const unsigned DES_INT32 PC1_DL[16] = {
+	0x00000000, 0x00100000, 0x00001000, 0x00101000,
+	0x00000010, 0x00100010, 0x00001010, 0x00101010,
+	0x00000001, 0x00100001, 0x00001001, 0x00101001,
+	0x00000011, 0x00100011, 0x00001011, 0x00101011
+};
+
+static const unsigned DES_INT32 PC1_CR[16] = {
+	0x00000000, 0x00000001, 0x00000100, 0x00000101,
+	0x00010000, 0x00010001, 0x00010100, 0x00010101,
+	0x01000000, 0x01000001, 0x01000100, 0x01000101,
+	0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+
+static const unsigned DES_INT32 PC1_DR[8] = {
+	0x00000000, 0x01000000, 0x00010000, 0x01010000,
+	0x00000100, 0x01000100, 0x00010100, 0x01010100
+};
+
+
+/*
+ * At the start of some iterations of the key schedule we do
+ * a circular left shift by one place, while for others we do a shift by
+ * two places.  This has bits set for the iterations where we do 2 bit
+ * shifts, starting at the low order bit.
+ */
+#define	TWO_BIT_SHIFTS	0x7efc
+
+/*
+ * Permuted choice 2 tables.  The first actually produces the low order
+ * 24 bits of the subkey Ki from the 28 bit value of Ci.  The second produces
+ * the high order 24 bits from Di.  The tables are indexed by six bit
+ * segments of Ci and Di respectively.  The code is handcrafted to compute
+ * the appropriate 6 bit chunks.
+ *
+ * Note that for ease of computation, the 24 bit values are produced with
+ * six bits going into each byte.  Note also that the table has been byte
+ * rearranged to produce keys which match the order we will apply them
+ * in in the des code.
+ */
+static const unsigned DES_INT32 PC2_C[4][64] = {
+  {
+	0x00000000, 0x00000004, 0x00010000, 0x00010004,
+	0x00000400, 0x00000404, 0x00010400, 0x00010404,
+	0x00000020, 0x00000024, 0x00010020, 0x00010024,
+	0x00000420, 0x00000424, 0x00010420, 0x00010424,
+	0x01000000, 0x01000004, 0x01010000, 0x01010004,
+	0x01000400, 0x01000404, 0x01010400, 0x01010404,
+	0x01000020, 0x01000024, 0x01010020, 0x01010024,
+	0x01000420, 0x01000424, 0x01010420, 0x01010424,
+	0x00020000, 0x00020004, 0x00030000, 0x00030004,
+	0x00020400, 0x00020404, 0x00030400, 0x00030404,
+	0x00020020, 0x00020024, 0x00030020, 0x00030024,
+	0x00020420, 0x00020424, 0x00030420, 0x00030424,
+	0x01020000, 0x01020004, 0x01030000, 0x01030004,
+	0x01020400, 0x01020404, 0x01030400, 0x01030404,
+	0x01020020, 0x01020024, 0x01030020, 0x01030024,
+	0x01020420, 0x01020424, 0x01030420, 0x01030424,
+  },
+  {
+	0x00000000, 0x02000000, 0x00000800, 0x02000800,
+	0x00080000, 0x02080000, 0x00080800, 0x02080800,
+	0x00000001, 0x02000001, 0x00000801, 0x02000801,
+	0x00080001, 0x02080001, 0x00080801, 0x02080801,
+	0x00000100, 0x02000100, 0x00000900, 0x02000900,
+	0x00080100, 0x02080100, 0x00080900, 0x02080900,
+	0x00000101, 0x02000101, 0x00000901, 0x02000901,
+	0x00080101, 0x02080101, 0x00080901, 0x02080901,
+	0x10000000, 0x12000000, 0x10000800, 0x12000800,
+	0x10080000, 0x12080000, 0x10080800, 0x12080800,
+	0x10000001, 0x12000001, 0x10000801, 0x12000801,
+	0x10080001, 0x12080001, 0x10080801, 0x12080801,
+	0x10000100, 0x12000100, 0x10000900, 0x12000900,
+	0x10080100, 0x12080100, 0x10080900, 0x12080900,
+	0x10000101, 0x12000101, 0x10000901, 0x12000901,
+	0x10080101, 0x12080101, 0x10080901, 0x12080901,
+  },
+  {
+	0x00000000, 0x00040000, 0x00002000, 0x00042000,
+	0x00100000, 0x00140000, 0x00102000, 0x00142000,
+	0x20000000, 0x20040000, 0x20002000, 0x20042000,
+	0x20100000, 0x20140000, 0x20102000, 0x20142000,
+	0x00000008, 0x00040008, 0x00002008, 0x00042008,
+	0x00100008, 0x00140008, 0x00102008, 0x00142008,
+	0x20000008, 0x20040008, 0x20002008, 0x20042008,
+	0x20100008, 0x20140008, 0x20102008, 0x20142008,
+	0x00200000, 0x00240000, 0x00202000, 0x00242000,
+	0x00300000, 0x00340000, 0x00302000, 0x00342000,
+	0x20200000, 0x20240000, 0x20202000, 0x20242000,
+	0x20300000, 0x20340000, 0x20302000, 0x20342000,
+	0x00200008, 0x00240008, 0x00202008, 0x00242008,
+	0x00300008, 0x00340008, 0x00302008, 0x00342008,
+	0x20200008, 0x20240008, 0x20202008, 0x20242008,
+	0x20300008, 0x20340008, 0x20302008, 0x20342008,
+  },
+  {
+	0x00000000, 0x00000010, 0x08000000, 0x08000010,
+	0x00000200, 0x00000210, 0x08000200, 0x08000210,
+	0x00000002, 0x00000012, 0x08000002, 0x08000012,
+	0x00000202, 0x00000212, 0x08000202, 0x08000212,
+	0x04000000, 0x04000010, 0x0c000000, 0x0c000010,
+	0x04000200, 0x04000210, 0x0c000200, 0x0c000210,
+	0x04000002, 0x04000012, 0x0c000002, 0x0c000012,
+	0x04000202, 0x04000212, 0x0c000202, 0x0c000212,
+	0x00001000, 0x00001010, 0x08001000, 0x08001010,
+	0x00001200, 0x00001210, 0x08001200, 0x08001210,
+	0x00001002, 0x00001012, 0x08001002, 0x08001012,
+	0x00001202, 0x00001212, 0x08001202, 0x08001212,
+	0x04001000, 0x04001010, 0x0c001000, 0x0c001010,
+	0x04001200, 0x04001210, 0x0c001200, 0x0c001210,
+	0x04001002, 0x04001012, 0x0c001002, 0x0c001012,
+	0x04001202, 0x04001212, 0x0c001202, 0x0c001212
+  },
+};
+
+static const unsigned DES_INT32 PC2_D[4][64] = {
+  {
+	0x00000000, 0x02000000, 0x00020000, 0x02020000,
+	0x00000100, 0x02000100, 0x00020100, 0x02020100,
+	0x00000008, 0x02000008, 0x00020008, 0x02020008,
+	0x00000108, 0x02000108, 0x00020108, 0x02020108,
+	0x00200000, 0x02200000, 0x00220000, 0x02220000,
+	0x00200100, 0x02200100, 0x00220100, 0x02220100,
+	0x00200008, 0x02200008, 0x00220008, 0x02220008,
+	0x00200108, 0x02200108, 0x00220108, 0x02220108,
+	0x00000200, 0x02000200, 0x00020200, 0x02020200,
+	0x00000300, 0x02000300, 0x00020300, 0x02020300,
+	0x00000208, 0x02000208, 0x00020208, 0x02020208,
+	0x00000308, 0x02000308, 0x00020308, 0x02020308,
+	0x00200200, 0x02200200, 0x00220200, 0x02220200,
+	0x00200300, 0x02200300, 0x00220300, 0x02220300,
+	0x00200208, 0x02200208, 0x00220208, 0x02220208,
+	0x00200308, 0x02200308, 0x00220308, 0x02220308,
+  },
+  {
+	0x00000000, 0x00001000, 0x00000020, 0x00001020,
+	0x00100000, 0x00101000, 0x00100020, 0x00101020,
+	0x08000000, 0x08001000, 0x08000020, 0x08001020,
+	0x08100000, 0x08101000, 0x08100020, 0x08101020,
+	0x00000004, 0x00001004, 0x00000024, 0x00001024,
+	0x00100004, 0x00101004, 0x00100024, 0x00101024,
+	0x08000004, 0x08001004, 0x08000024, 0x08001024,
+	0x08100004, 0x08101004, 0x08100024, 0x08101024,
+	0x00000400, 0x00001400, 0x00000420, 0x00001420,
+	0x00100400, 0x00101400, 0x00100420, 0x00101420,
+	0x08000400, 0x08001400, 0x08000420, 0x08001420,
+	0x08100400, 0x08101400, 0x08100420, 0x08101420,
+	0x00000404, 0x00001404, 0x00000424, 0x00001424,
+	0x00100404, 0x00101404, 0x00100424, 0x00101424,
+	0x08000404, 0x08001404, 0x08000424, 0x08001424,
+	0x08100404, 0x08101404, 0x08100424, 0x08101424,
+  },
+  {
+	0x00000000, 0x10000000, 0x00010000, 0x10010000,
+	0x00000002, 0x10000002, 0x00010002, 0x10010002,
+	0x00002000, 0x10002000, 0x00012000, 0x10012000,
+	0x00002002, 0x10002002, 0x00012002, 0x10012002,
+	0x00040000, 0x10040000, 0x00050000, 0x10050000,
+	0x00040002, 0x10040002, 0x00050002, 0x10050002,
+	0x00042000, 0x10042000, 0x00052000, 0x10052000,
+	0x00042002, 0x10042002, 0x00052002, 0x10052002,
+	0x20000000, 0x30000000, 0x20010000, 0x30010000,
+	0x20000002, 0x30000002, 0x20010002, 0x30010002,
+	0x20002000, 0x30002000, 0x20012000, 0x30012000,
+	0x20002002, 0x30002002, 0x20012002, 0x30012002,
+	0x20040000, 0x30040000, 0x20050000, 0x30050000,
+	0x20040002, 0x30040002, 0x20050002, 0x30050002,
+	0x20042000, 0x30042000, 0x20052000, 0x30052000,
+	0x20042002, 0x30042002, 0x20052002, 0x30052002,
+  },
+  {
+	0x00000000, 0x04000000, 0x00000001, 0x04000001,
+	0x01000000, 0x05000000, 0x01000001, 0x05000001,
+	0x00000010, 0x04000010, 0x00000011, 0x04000011,
+	0x01000010, 0x05000010, 0x01000011, 0x05000011,
+	0x00080000, 0x04080000, 0x00080001, 0x04080001,
+	0x01080000, 0x05080000, 0x01080001, 0x05080001,
+	0x00080010, 0x04080010, 0x00080011, 0x04080011,
+	0x01080010, 0x05080010, 0x01080011, 0x05080011,
+	0x00000800, 0x04000800, 0x00000801, 0x04000801,
+	0x01000800, 0x05000800, 0x01000801, 0x05000801,
+	0x00000810, 0x04000810, 0x00000811, 0x04000811,
+	0x01000810, 0x05000810, 0x01000811, 0x05000811,
+	0x00080800, 0x04080800, 0x00080801, 0x04080801,
+	0x01080800, 0x05080800, 0x01080801, 0x05080801,
+	0x00080810, 0x04080810, 0x00080811, 0x04080811,
+	0x01080810, 0x05080810, 0x01080811, 0x05080811
+  },
+};
+
+
+
+/*
+ * Permute the key to give us our key schedule.
+ */
+int
+mit_des_make_key_sched(mit_des_cblock key, mit_des_key_schedule schedule)
+{
+	register unsigned DES_INT32 c, d;
+
+	{
+		/*
+		 * Need a pointer for the keys and a temporary DES_INT32
+		 */
+		const unsigned char *k;
+		register unsigned DES_INT32 tmp;
+
+		/*
+		 * Fetch the key into something we can work with
+		 */
+		k = key;
+
+		/*
+		 * The first permutted choice gives us the 28 bits for C0 and
+		 * 28 for D0.  C0 gets 12 bits from the left key and 16 from
+		 * the right, while D0 gets 16 from the left and 12 from the
+		 * right.  The code knows which bits go where.
+		 */
+		tmp = ((unsigned DES_INT32)(*(k)++)) << 24;
+		tmp |= ((unsigned DES_INT32)(*(k)++)) << 16;
+		tmp |= ((unsigned DES_INT32)(*(k)++)) << 8;
+		tmp |= (unsigned DES_INT32)(*(k)++);		/* left part of key */
+		c =  PC1_CL[(tmp >> 29) & 0x7]
+		  | (PC1_CL[(tmp >> 21) & 0x7] << 1)
+		  | (PC1_CL[(tmp >> 13) & 0x7] << 2)
+		  | (PC1_CL[(tmp >>  5) & 0x7] << 3);
+		d =  PC1_DL[(tmp >> 25) & 0xf]
+		  | (PC1_DL[(tmp >> 17) & 0xf] << 1)
+		  | (PC1_DL[(tmp >>  9) & 0xf] << 2)
+		  | (PC1_DL[(tmp >>  1) & 0xf] << 3);
+
+		tmp = ((unsigned DES_INT32)(*(k)++)) << 24;
+		tmp |= ((unsigned DES_INT32)(*(k)++)) << 16;
+		tmp |= ((unsigned DES_INT32)(*(k)++)) << 8;
+		tmp |= (unsigned DES_INT32)(*(k)++);		/* right part of key */
+		c |= PC1_CR[(tmp >> 28) & 0xf]
+		  | (PC1_CR[(tmp >> 20) & 0xf] << 1)
+		  | (PC1_CR[(tmp >> 12) & 0xf] << 2)
+		  | (PC1_CR[(tmp >>  4) & 0xf] << 3);
+		d |= PC1_DR[(tmp >> 25) & 0x7]
+		  | (PC1_DR[(tmp >> 17) & 0x7] << 1)
+		  | (PC1_DR[(tmp >>  9) & 0x7] << 2)
+		  | (PC1_DR[(tmp >>  1) & 0x7] << 3);
+	}
+
+	{
+		/*
+		 * Need several temporaries in here
+		 */
+		register unsigned DES_INT32 ltmp, rtmp;
+		register unsigned DES_INT32 *k;
+		register int two_bit_shifts;
+		register int i;
+		/*
+		 * Now iterate to compute the key schedule.  Note that we
+		 * record the entire set of subkeys in 6 bit chunks since
+		 * they are used that way.  At 6 bits/char, we need
+		 * 48/6 char's/subkey * 16 subkeys/encryption == 128 bytes.
+		 * The schedule must be this big.
+		 */
+		k = (unsigned DES_INT32 *)schedule;
+		two_bit_shifts = TWO_BIT_SHIFTS;
+		for (i = 16; i > 0; i--) {
+			/*
+			 * Do the rotation.  One bit and two bit rotations
+			 * are done separately.  Note C and D are 28 bits.
+			 */
+			if (two_bit_shifts & 0x1) {
+				c = ((c << 2) & 0xffffffc) | (c >> 26);
+				d = ((d << 2) & 0xffffffc) | (d >> 26);
+			} else {
+				c = ((c << 1) & 0xffffffe) | (c >> 27);
+				d = ((d << 1) & 0xffffffe) | (d >> 27);
+			}
+			two_bit_shifts >>= 1;
+
+			/*
+			 * Apply permutted choice 2 to C to get the first
+			 * 24 bits worth of keys.  Note that bits 9, 18, 22
+			 * and 25 (using DES numbering) in C are unused.  The
+			 * shift-mask stuff is done to delete these bits from
+			 * the indices, since this cuts the table size in half.
+			 *
+			 * The table is torqued, by the way.  If the standard
+			 * byte order for this (high to low order) is 1234,
+			 * the table actually gives us 4132.
+			 */
+			ltmp = PC2_C[0][((c >> 22) & 0x3f)]
+			     | PC2_C[1][((c >> 15) & 0xf) | ((c >> 16) & 0x30)]
+			     | PC2_C[2][((c >>  4) & 0x3) | ((c >>  9) & 0x3c)]
+			     | PC2_C[3][((c      ) & 0x7) | ((c >>  4) & 0x38)];
+			/*
+			 * Apply permutted choice 2 to D to get the other half.
+			 * Here, bits 7, 10, 15 and 26 go unused.  The sqeezing
+			 * actually turns out to be cheaper here.
+			 *
+			 * This table is similarly torqued.  If the standard
+			 * byte order is 5678, the table has the bytes permuted
+			 * to give us 7685.
+			 */
+			rtmp = PC2_D[0][((d >> 22) & 0x3f)]
+			     | PC2_D[1][((d >> 14) & 0xf) | ((d >> 15) & 0x30)]
+			     | PC2_D[2][((d >>  7) & 0x3f)]
+			     | PC2_D[3][((d      ) & 0x3) | ((d >>  1) & 0x3c)];
+			
+			/*
+			 * Make up two words of the key schedule, with a
+			 * byte order which is convenient for the DES
+			 * inner loop.  The high order (first) word will
+			 * hold bytes 7135 (high to low order) while the
+			 * second holds bytes 4682.
+			 */
+			*k++ = (ltmp & 0x00ffff00) | (rtmp & 0xff0000ff);
+			*k++ = (ltmp & 0xff0000ff) | (rtmp & 0x00ffff00);
+		}
+	}
+	return (0);
+}
diff --git a/mechglue/src/lib/crypto/des/f_tables.c b/mechglue/src/lib/crypto/des/f_tables.c
new file mode 100644
index 000000000..f84ade538
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/f_tables.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 1990 Dennis Ferguson.  All rights reserved.
+ *
+ * Commercial use is permitted only if products which are derived from
+ * or include this software are made available for purchase and/or use
+ * in Canada.  Otherwise, redistribution and use in source and binary
+ * forms are permitted.
+ */
+
+/*
+ * des_tables.c - precomputed tables used for the DES cipher function
+ */
+
+/*
+ * Include the header file so something will complain if the
+ * declarations get out of sync
+ */
+#include "des_int.h"
+#include "f_tables.h"
+
+/*
+ * These tables may be declared const if you want.  Many compilers
+ * don't support this, though.
+ */
+
+/*
+ * The DES algorithm which uses these is intended to be fairly speedy
+ * at the expense of some memory.  All the standard hacks are used.
+ * The S boxes and the P permutation are precomputed into one table.
+ * The E box never actually appears explicitly since it is easy to apply
+ * this algorithmically as needed.  The initial permutation and final
+ * (inverse initial) permutation are computed from tables designed to
+ * permute one byte at a time.  This should run pretty fast on machines
+ * with 32 bit words and bit field/multiple bit shift instructions which
+ * are fast.
+ */
+
+/*
+ * The initial permutation array.  This is used to compute both the
+ * left and the right halves of the initial permutation using bytes
+ * from words made from the following operations:
+ *
+ * ((left & 0x55555555) << 1) | (right & 0x55555555)  for left half
+ * (left & 0xaaaaaaaa) | ((right & 0xaaaaaaaa) >> 1)  for right half
+ *
+ * The scheme is that we index into the table using each byte.  The
+ * result from the high order byte is or'd with the result from the
+ * next byte shifted left once is or'd with the result from the next
+ * byte shifted left twice if or'd with the result from the low order
+ * byte shifted left by three.  Clear?
+ */
+
+const unsigned DES_INT32 des_IP_table[256] = {
+	0x00000000, 0x00000010, 0x00000001, 0x00000011,
+	0x00001000, 0x00001010, 0x00001001, 0x00001011,
+	0x00000100, 0x00000110, 0x00000101, 0x00000111,
+	0x00001100, 0x00001110, 0x00001101, 0x00001111,
+	0x00100000, 0x00100010, 0x00100001, 0x00100011,
+	0x00101000, 0x00101010, 0x00101001, 0x00101011,
+	0x00100100, 0x00100110, 0x00100101, 0x00100111,
+	0x00101100, 0x00101110, 0x00101101, 0x00101111,
+	0x00010000, 0x00010010, 0x00010001, 0x00010011,
+	0x00011000, 0x00011010, 0x00011001, 0x00011011,
+	0x00010100, 0x00010110, 0x00010101, 0x00010111,
+	0x00011100, 0x00011110, 0x00011101, 0x00011111,
+	0x00110000, 0x00110010, 0x00110001, 0x00110011,
+	0x00111000, 0x00111010, 0x00111001, 0x00111011,
+	0x00110100, 0x00110110, 0x00110101, 0x00110111,
+	0x00111100, 0x00111110, 0x00111101, 0x00111111,
+	0x10000000, 0x10000010, 0x10000001, 0x10000011,
+	0x10001000, 0x10001010, 0x10001001, 0x10001011,
+	0x10000100, 0x10000110, 0x10000101, 0x10000111,
+	0x10001100, 0x10001110, 0x10001101, 0x10001111,
+	0x10100000, 0x10100010, 0x10100001, 0x10100011,
+	0x10101000, 0x10101010, 0x10101001, 0x10101011,
+	0x10100100, 0x10100110, 0x10100101, 0x10100111,
+	0x10101100, 0x10101110, 0x10101101, 0x10101111,
+	0x10010000, 0x10010010, 0x10010001, 0x10010011,
+	0x10011000, 0x10011010, 0x10011001, 0x10011011,
+	0x10010100, 0x10010110, 0x10010101, 0x10010111,
+	0x10011100, 0x10011110, 0x10011101, 0x10011111,
+	0x10110000, 0x10110010, 0x10110001, 0x10110011,
+	0x10111000, 0x10111010, 0x10111001, 0x10111011,
+	0x10110100, 0x10110110, 0x10110101, 0x10110111,
+	0x10111100, 0x10111110, 0x10111101, 0x10111111,
+	0x01000000, 0x01000010, 0x01000001, 0x01000011,
+	0x01001000, 0x01001010, 0x01001001, 0x01001011,
+	0x01000100, 0x01000110, 0x01000101, 0x01000111,
+	0x01001100, 0x01001110, 0x01001101, 0x01001111,
+	0x01100000, 0x01100010, 0x01100001, 0x01100011,
+	0x01101000, 0x01101010, 0x01101001, 0x01101011,
+	0x01100100, 0x01100110, 0x01100101, 0x01100111,
+	0x01101100, 0x01101110, 0x01101101, 0x01101111,
+	0x01010000, 0x01010010, 0x01010001, 0x01010011,
+	0x01011000, 0x01011010, 0x01011001, 0x01011011,
+	0x01010100, 0x01010110, 0x01010101, 0x01010111,
+	0x01011100, 0x01011110, 0x01011101, 0x01011111,
+	0x01110000, 0x01110010, 0x01110001, 0x01110011,
+	0x01111000, 0x01111010, 0x01111001, 0x01111011,
+	0x01110100, 0x01110110, 0x01110101, 0x01110111,
+	0x01111100, 0x01111110, 0x01111101, 0x01111111,
+	0x11000000, 0x11000010, 0x11000001, 0x11000011,
+	0x11001000, 0x11001010, 0x11001001, 0x11001011,
+	0x11000100, 0x11000110, 0x11000101, 0x11000111,
+	0x11001100, 0x11001110, 0x11001101, 0x11001111,
+	0x11100000, 0x11100010, 0x11100001, 0x11100011,
+	0x11101000, 0x11101010, 0x11101001, 0x11101011,
+	0x11100100, 0x11100110, 0x11100101, 0x11100111,
+	0x11101100, 0x11101110, 0x11101101, 0x11101111,
+	0x11010000, 0x11010010, 0x11010001, 0x11010011,
+	0x11011000, 0x11011010, 0x11011001, 0x11011011,
+	0x11010100, 0x11010110, 0x11010101, 0x11010111,
+	0x11011100, 0x11011110, 0x11011101, 0x11011111,
+	0x11110000, 0x11110010, 0x11110001, 0x11110011,
+	0x11111000, 0x11111010, 0x11111001, 0x11111011,
+	0x11110100, 0x11110110, 0x11110101, 0x11110111,
+	0x11111100, 0x11111110, 0x11111101, 0x11111111
+};
+
+/*
+ * The final permutation array.  Like the IP array, used
+ * to compute both the left and right results from the bytes
+ * of words computed from:
+ *
+ * ((left & 0x0f0f0f0f) << 4) | (right & 0x0f0f0f0f)  for left result
+ * (left & 0xf0f0f0f0) | ((right & 0xf0f0f0f0) >> 4)  for right result
+ *
+ * The result from the high order byte is shifted left 6 bits and
+ * or'd with the result from the next byte shifted left 4 bits, which
+ * is or'd with the result from the next byte shifted left 2 bits,
+ * which is or'd with the result from the low byte.
+ */
+const unsigned DES_INT32 des_FP_table[256] = {
+	0x00000000, 0x02000000, 0x00020000, 0x02020000,
+	0x00000200, 0x02000200, 0x00020200, 0x02020200,
+	0x00000002, 0x02000002, 0x00020002, 0x02020002,
+	0x00000202, 0x02000202, 0x00020202, 0x02020202,
+	0x01000000, 0x03000000, 0x01020000, 0x03020000,
+	0x01000200, 0x03000200, 0x01020200, 0x03020200,
+	0x01000002, 0x03000002, 0x01020002, 0x03020002,
+	0x01000202, 0x03000202, 0x01020202, 0x03020202,
+	0x00010000, 0x02010000, 0x00030000, 0x02030000,
+	0x00010200, 0x02010200, 0x00030200, 0x02030200,
+	0x00010002, 0x02010002, 0x00030002, 0x02030002,
+	0x00010202, 0x02010202, 0x00030202, 0x02030202,
+	0x01010000, 0x03010000, 0x01030000, 0x03030000,
+	0x01010200, 0x03010200, 0x01030200, 0x03030200,
+	0x01010002, 0x03010002, 0x01030002, 0x03030002,
+	0x01010202, 0x03010202, 0x01030202, 0x03030202,
+	0x00000100, 0x02000100, 0x00020100, 0x02020100,
+	0x00000300, 0x02000300, 0x00020300, 0x02020300,
+	0x00000102, 0x02000102, 0x00020102, 0x02020102,
+	0x00000302, 0x02000302, 0x00020302, 0x02020302,
+	0x01000100, 0x03000100, 0x01020100, 0x03020100,
+	0x01000300, 0x03000300, 0x01020300, 0x03020300,
+	0x01000102, 0x03000102, 0x01020102, 0x03020102,
+	0x01000302, 0x03000302, 0x01020302, 0x03020302,
+	0x00010100, 0x02010100, 0x00030100, 0x02030100,
+	0x00010300, 0x02010300, 0x00030300, 0x02030300,
+	0x00010102, 0x02010102, 0x00030102, 0x02030102,
+	0x00010302, 0x02010302, 0x00030302, 0x02030302,
+	0x01010100, 0x03010100, 0x01030100, 0x03030100,
+	0x01010300, 0x03010300, 0x01030300, 0x03030300,
+	0x01010102, 0x03010102, 0x01030102, 0x03030102,
+	0x01010302, 0x03010302, 0x01030302, 0x03030302,
+	0x00000001, 0x02000001, 0x00020001, 0x02020001,
+	0x00000201, 0x02000201, 0x00020201, 0x02020201,
+	0x00000003, 0x02000003, 0x00020003, 0x02020003,
+	0x00000203, 0x02000203, 0x00020203, 0x02020203,
+	0x01000001, 0x03000001, 0x01020001, 0x03020001,
+	0x01000201, 0x03000201, 0x01020201, 0x03020201,
+	0x01000003, 0x03000003, 0x01020003, 0x03020003,
+	0x01000203, 0x03000203, 0x01020203, 0x03020203,
+	0x00010001, 0x02010001, 0x00030001, 0x02030001,
+	0x00010201, 0x02010201, 0x00030201, 0x02030201,
+	0x00010003, 0x02010003, 0x00030003, 0x02030003,
+	0x00010203, 0x02010203, 0x00030203, 0x02030203,
+	0x01010001, 0x03010001, 0x01030001, 0x03030001,
+	0x01010201, 0x03010201, 0x01030201, 0x03030201,
+	0x01010003, 0x03010003, 0x01030003, 0x03030003,
+	0x01010203, 0x03010203, 0x01030203, 0x03030203,
+	0x00000101, 0x02000101, 0x00020101, 0x02020101,
+	0x00000301, 0x02000301, 0x00020301, 0x02020301,
+	0x00000103, 0x02000103, 0x00020103, 0x02020103,
+	0x00000303, 0x02000303, 0x00020303, 0x02020303,
+	0x01000101, 0x03000101, 0x01020101, 0x03020101,
+	0x01000301, 0x03000301, 0x01020301, 0x03020301,
+	0x01000103, 0x03000103, 0x01020103, 0x03020103,
+	0x01000303, 0x03000303, 0x01020303, 0x03020303,
+	0x00010101, 0x02010101, 0x00030101, 0x02030101,
+	0x00010301, 0x02010301, 0x00030301, 0x02030301,
+	0x00010103, 0x02010103, 0x00030103, 0x02030103,
+	0x00010303, 0x02010303, 0x00030303, 0x02030303,
+	0x01010101, 0x03010101, 0x01030101, 0x03030101,
+	0x01010301, 0x03010301, 0x01030301, 0x03030301,
+	0x01010103, 0x03010103, 0x01030103, 0x03030103,
+	0x01010303, 0x03010303, 0x01030303, 0x03030303
+};
+
+
+/*
+ * The SP table is actually the S boxes and the P permutation
+ * table combined.  This table is actually reordered from the
+ * spec, to match the order of key application we follow.
+ */
+const unsigned DES_INT32 des_SP_table[8][64] = {
+  {
+	0x00100000, 0x02100001, 0x02000401, 0x00000000,	/* 7 */
+	0x00000400, 0x02000401, 0x00100401, 0x02100400,
+	0x02100401, 0x00100000, 0x00000000, 0x02000001,
+	0x00000001, 0x02000000, 0x02100001, 0x00000401,
+	0x02000400, 0x00100401, 0x00100001, 0x02000400,
+	0x02000001, 0x02100000, 0x02100400, 0x00100001,
+	0x02100000, 0x00000400, 0x00000401, 0x02100401,
+	0x00100400, 0x00000001, 0x02000000, 0x00100400,
+	0x02000000, 0x00100400, 0x00100000, 0x02000401,
+	0x02000401, 0x02100001, 0x02100001, 0x00000001,
+	0x00100001, 0x02000000, 0x02000400, 0x00100000,
+	0x02100400, 0x00000401, 0x00100401, 0x02100400,
+	0x00000401, 0x02000001, 0x02100401, 0x02100000,
+	0x00100400, 0x00000000, 0x00000001, 0x02100401,
+	0x00000000, 0x00100401, 0x02100000, 0x00000400,
+	0x02000001, 0x02000400, 0x00000400, 0x00100001,
+  },
+  {
+	0x00808200, 0x00000000, 0x00008000, 0x00808202,	/* 1 */
+	0x00808002, 0x00008202, 0x00000002, 0x00008000,
+	0x00000200, 0x00808200, 0x00808202, 0x00000200,
+	0x00800202, 0x00808002, 0x00800000, 0x00000002,
+	0x00000202, 0x00800200, 0x00800200, 0x00008200,
+	0x00008200, 0x00808000, 0x00808000, 0x00800202,
+	0x00008002, 0x00800002, 0x00800002, 0x00008002,
+	0x00000000, 0x00000202, 0x00008202, 0x00800000,
+	0x00008000, 0x00808202, 0x00000002, 0x00808000,
+	0x00808200, 0x00800000, 0x00800000, 0x00000200,
+	0x00808002, 0x00008000, 0x00008200, 0x00800002,
+	0x00000200, 0x00000002, 0x00800202, 0x00008202,
+	0x00808202, 0x00008002, 0x00808000, 0x00800202,
+	0x00800002, 0x00000202, 0x00008202, 0x00808200,
+	0x00000202, 0x00800200, 0x00800200, 0x00000000,
+	0x00008002, 0x00008200, 0x00000000, 0x00808002,
+  },
+  {
+	0x00000104, 0x04010100, 0x00000000, 0x04010004,	/* 3 */
+	0x04000100, 0x00000000, 0x00010104, 0x04000100,
+	0x00010004, 0x04000004, 0x04000004, 0x00010000,
+	0x04010104, 0x00010004, 0x04010000, 0x00000104,
+	0x04000000, 0x00000004, 0x04010100, 0x00000100,
+	0x00010100, 0x04010000, 0x04010004, 0x00010104,
+	0x04000104, 0x00010100, 0x00010000, 0x04000104,
+	0x00000004, 0x04010104, 0x00000100, 0x04000000,
+	0x04010100, 0x04000000, 0x00010004, 0x00000104,
+	0x00010000, 0x04010100, 0x04000100, 0x00000000,
+	0x00000100, 0x00010004, 0x04010104, 0x04000100,
+	0x04000004, 0x00000100, 0x00000000, 0x04010004,
+	0x04000104, 0x00010000, 0x04000000, 0x04010104,
+	0x00000004, 0x00010104, 0x00010100, 0x04000004,
+	0x04010000, 0x04000104, 0x00000104, 0x04010000,
+	0x00010104, 0x00000004, 0x04010004, 0x00010100,
+  },
+  {
+	0x00000080, 0x01040080, 0x01040000, 0x21000080,	/* 5 */
+	0x00040000, 0x00000080, 0x20000000, 0x01040000,
+	0x20040080, 0x00040000, 0x01000080, 0x20040080,
+	0x21000080, 0x21040000, 0x00040080, 0x20000000,
+	0x01000000, 0x20040000, 0x20040000, 0x00000000,
+	0x20000080, 0x21040080, 0x21040080, 0x01000080,
+	0x21040000, 0x20000080, 0x00000000, 0x21000000,
+	0x01040080, 0x01000000, 0x21000000, 0x00040080,
+	0x00040000, 0x21000080, 0x00000080, 0x01000000,
+	0x20000000, 0x01040000, 0x21000080, 0x20040080,
+	0x01000080, 0x20000000, 0x21040000, 0x01040080,
+	0x20040080, 0x00000080, 0x01000000, 0x21040000,
+	0x21040080, 0x00040080, 0x21000000, 0x21040080,
+	0x01040000, 0x00000000, 0x20040000, 0x21000000,
+	0x00040080, 0x01000080, 0x20000080, 0x00040000,
+	0x00000000, 0x20040000, 0x01040080, 0x20000080,
+  },
+  {
+	0x80401000, 0x80001040, 0x80001040, 0x00000040,	/* 4 */
+	0x00401040, 0x80400040, 0x80400000, 0x80001000,
+	0x00000000, 0x00401000, 0x00401000, 0x80401040,
+	0x80000040, 0x00000000, 0x00400040, 0x80400000,
+	0x80000000, 0x00001000, 0x00400000, 0x80401000,
+	0x00000040, 0x00400000, 0x80001000, 0x00001040,
+	0x80400040, 0x80000000, 0x00001040, 0x00400040,
+	0x00001000, 0x00401040, 0x80401040, 0x80000040,
+	0x00400040, 0x80400000, 0x00401000, 0x80401040,
+	0x80000040, 0x00000000, 0x00000000, 0x00401000,
+	0x00001040, 0x00400040, 0x80400040, 0x80000000,
+	0x80401000, 0x80001040, 0x80001040, 0x00000040,
+	0x80401040, 0x80000040, 0x80000000, 0x00001000,
+	0x80400000, 0x80001000, 0x00401040, 0x80400040,
+	0x80001000, 0x00001040, 0x00400000, 0x80401000,
+	0x00000040, 0x00400000, 0x00001000, 0x00401040,
+  },
+  {
+	0x10000008, 0x10200000, 0x00002000, 0x10202008,	/* 6 */
+	0x10200000, 0x00000008, 0x10202008, 0x00200000,
+	0x10002000, 0x00202008, 0x00200000, 0x10000008,
+	0x00200008, 0x10002000, 0x10000000, 0x00002008,
+	0x00000000, 0x00200008, 0x10002008, 0x00002000,
+	0x00202000, 0x10002008, 0x00000008, 0x10200008,
+	0x10200008, 0x00000000, 0x00202008, 0x10202000,
+	0x00002008, 0x00202000, 0x10202000, 0x10000000,
+	0x10002000, 0x00000008, 0x10200008, 0x00202000,
+	0x10202008, 0x00200000, 0x00002008, 0x10000008,
+	0x00200000, 0x10002000, 0x10000000, 0x00002008,
+	0x10000008, 0x10202008, 0x00202000, 0x10200000,
+	0x00202008, 0x10202000, 0x00000000, 0x10200008,
+	0x00000008, 0x00002000, 0x10200000, 0x00202008,
+	0x00002000, 0x00200008, 0x10002008, 0x00000000,
+	0x10202000, 0x10000000, 0x00200008, 0x10002008,
+  },
+  {
+	0x08000820, 0x00000800, 0x00020000, 0x08020820,	/* 8 */
+	0x08000000, 0x08000820, 0x00000020, 0x08000000,
+	0x00020020, 0x08020000, 0x08020820, 0x00020800,
+	0x08020800, 0x00020820, 0x00000800, 0x00000020,
+	0x08020000, 0x08000020, 0x08000800, 0x00000820,
+	0x00020800, 0x00020020, 0x08020020, 0x08020800,
+	0x00000820, 0x00000000, 0x00000000, 0x08020020,
+	0x08000020, 0x08000800, 0x00020820, 0x00020000,
+	0x00020820, 0x00020000, 0x08020800, 0x00000800,
+	0x00000020, 0x08020020, 0x00000800, 0x00020820,
+	0x08000800, 0x00000020, 0x08000020, 0x08020000,
+	0x08020020, 0x08000000, 0x00020000, 0x08000820,
+	0x00000000, 0x08020820, 0x00020020, 0x08000020,
+	0x08020000, 0x08000800, 0x08000820, 0x00000000,
+	0x08020820, 0x00020800, 0x00020800, 0x00000820,
+	0x00000820, 0x00020020, 0x08000000, 0x08020800,
+  },
+  {
+	0x40084010, 0x40004000, 0x00004000, 0x00084010,	/* 2 */
+	0x00080000, 0x00000010, 0x40080010, 0x40004010,
+	0x40000010, 0x40084010, 0x40084000, 0x40000000,
+	0x40004000, 0x00080000, 0x00000010, 0x40080010,
+	0x00084000, 0x00080010, 0x40004010, 0x00000000,
+	0x40000000, 0x00004000, 0x00084010, 0x40080000,
+	0x00080010, 0x40000010, 0x00000000, 0x00084000,
+	0x00004010, 0x40084000, 0x40080000, 0x00004010,
+	0x00000000, 0x00084010, 0x40080010, 0x00080000,
+	0x40004010, 0x40080000, 0x40084000, 0x00004000,
+	0x40080000, 0x40004000, 0x00000010, 0x40084010,
+	0x00084010, 0x00000010, 0x00004000, 0x40000000,
+	0x00004010, 0x40084000, 0x00080000, 0x40000010,
+	0x00080010, 0x40004010, 0x40000010, 0x00080010,
+	0x00084000, 0x00000000, 0x40004000, 0x00004010,
+	0x40000000, 0x40080010, 0x40084010, 0x00084000
+  },
+};
diff --git a/mechglue/src/lib/crypto/des/f_tables.h b/mechglue/src/lib/crypto/des/f_tables.h
new file mode 100644
index 000000000..65181157a
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/f_tables.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 1990 Dennis Ferguson.  All rights reserved.
+ *
+ * Commercial use is permitted only if products which are derived from
+ * or include this software are made available for purchase and/or use
+ * in Canada.  Otherwise, redistribution and use in source and binary
+ * forms are permitted.
+ */
+
+/*
+ * des_tables.h - declarations to import the DES tables, used internally
+ *		  by some of the library routines.
+ */
+#ifndef	__DES_TABLES_H__
+#define	__DES_TABLES_H__	/* nothing */
+
+#include "k5-platform.h"
+/*
+ * These may be declared const if you wish.  Be sure to change the
+ * declarations in des_tables.c as well.
+ */
+extern const unsigned DES_INT32 des_IP_table[256];
+extern const unsigned DES_INT32 des_FP_table[256];
+extern const unsigned DES_INT32 des_SP_table[8][64];
+
+/*
+ * Use standard shortforms to reference these to save typing
+ */
+#define	IP	des_IP_table
+#define	FP	des_FP_table
+#define	SP	des_SP_table
+
+#ifdef DEBUG
+#define	DEB(foofraw)	printf foofraw
+#else
+#define	DEB(foofraw)	/* nothing */
+#endif
+
+/*
+ * Code to do a DES round using the tables.  Note that the E expansion
+ * is easy to compute algorithmically, especially if done out-of-order.
+ * Take a look at its form and compare it to everything involving temp
+ * below.  Since SP[0-7] don't have any bits in common set it is okay
+ * to do the successive xor's.
+ *
+ * Note too that the SP table has been reordered to match the order of
+ * the keys (if the original order of SP was 12345678, the reordered
+ * table is 71354682).  This is unnecessary, but was done since some
+ * compilers seem to like you going through the matrix from beginning
+ * to end.
+ *
+ * There is a difference in the best way to do this depending on whether
+ * one is encrypting or decrypting.  If encrypting we move forward through
+ * the keys and hence should move forward through the table.  If decrypting
+ * we go back.  Part of the need for this comes from trying to emulate
+ * existing software which generates a single key schedule and uses it
+ * both for encrypting and decrypting.  Generating separate encryption
+ * and decryption key schedules would allow one to use the same code
+ * for both.
+ *
+ * left, right and temp should be unsigned DES_INT32 values.  left and right
+ * should be the high and low order parts of the cipher block at the
+ * current stage of processing (this makes sense if you read the spec).
+ * kp should be an unsigned DES_INT32 pointer which points at the current
+ * set of subkeys in the key schedule.  It is advanced to the next set
+ * (i.e. by 8 bytes) when this is done.
+ *
+ * This occurs in the innermost loop of the DES function.  The four
+ * variables should really be in registers.
+ *
+ * When using this, the inner loop of the DES function might look like:
+ *
+ *	for (i = 0; i < 8; i++) {
+ *		DES_SP_{EN,DE}CRYPT_ROUND(left, right, temp, kp);
+ *		DES_SP_{EN,DE}CRYPT_ROUND(right, left, temp, kp);
+ *	}
+ *
+ * Note the trick above.  You are supposed to do 16 rounds, swapping
+ * left and right at the end of each round.  By doing two rounds at
+ * a time and swapping left and right in the code we can avoid the
+ * swaps altogether.
+ */
+#define	DES_SP_ENCRYPT_ROUND(left, right, temp, kp) \
+	(temp) = (((right) >> 11) | ((right) << 21)) ^ *(kp)++; \
+	(left) ^= SP[0][((temp) >> 24) & 0x3f] \
+		| SP[1][((temp) >> 16) & 0x3f] \
+		| SP[2][((temp) >>  8) & 0x3f] \
+		| SP[3][((temp)      ) & 0x3f]; \
+	(temp) = (((right) >> 23) | ((right) << 9)) ^ *(kp)++; \
+	(left) ^= SP[4][((temp) >> 24) & 0x3f] \
+		| SP[5][((temp) >> 16) & 0x3f] \
+		| SP[6][((temp) >>  8) & 0x3f] \
+		| SP[7][((temp)      ) & 0x3f]
+
+#define	DES_SP_DECRYPT_ROUND(left, right, temp, kp) \
+	(temp) = (((right) >> 23) | ((right) << 9)) ^ *(--(kp)); \
+	(left) ^= SP[7][((temp)      ) & 0x3f] \
+		| SP[6][((temp) >>  8) & 0x3f] \
+		| SP[5][((temp) >> 16) & 0x3f] \
+		| SP[4][((temp) >> 24) & 0x3f]; \
+	(temp) = (((right) >> 11) | ((right) << 21)) ^ *(--(kp)); \
+	(left) ^= SP[3][((temp)      ) & 0x3f] \
+		| SP[2][((temp) >>  8) & 0x3f] \
+		| SP[1][((temp) >> 16) & 0x3f] \
+		| SP[0][((temp) >> 24) & 0x3f]
+
+/*
+ * Macros to help deal with the initial permutation table.  Note
+ * the IP table only deals with 32 bits at a time, allowing us to
+ * collect the bits we need to deal with each half into an unsigned
+ * DES_INT32.  By carefully selecting how the bits are ordered we also
+ * take advantages of symmetries in the table so that we can use a
+ * single table to compute the permutation of all bytes.  This sounds
+ * complicated, but if you go through the process of designing the
+ * table you'll find the symmetries fall right out.
+ *
+ * The follow macros compute the set of bits used to index the
+ * table for produce the left and right permuted result.
+ *
+ * The inserted cast to unsigned DES_INT32 circumvents a bug in
+ * the Macintosh MPW 3.2 C compiler which loses the unsignedness and
+ * propagates the high-order bit in the shift.
+ */
+#define	DES_IP_LEFT_BITS(left, right) \
+	((((left) & 0x55555555) << 1) | ((right) & 0x55555555))
+#define	DES_IP_RIGHT_BITS(left, right) \
+	(((left) & 0xaaaaaaaa) | \
+		( ( (unsigned DES_INT32) ((right) & 0xaaaaaaaa) ) >> 1))
+
+/*
+ * The following macro does an in-place initial permutation given
+ * the current left and right parts of the block and a single
+ * temporary.  Use this more as a guide for rolling your own, though.
+ * The best way to do the IP depends on the form of the data you
+ * are dealing with.  If you use this, though, try to make left,
+ * right and temp register unsigned DES_INT32s.
+ */
+#define	DES_INITIAL_PERM(left, right, temp) \
+	(temp) = DES_IP_RIGHT_BITS((left), (right)); \
+	(right) = DES_IP_LEFT_BITS((left), (right)); \
+	(left) = IP[((right) >> 24) & 0xff] \
+	       | (IP[((right) >> 16) & 0xff] << 1) \
+	       | (IP[((right) >>  8) & 0xff] << 2) \
+	       | (IP[(right) & 0xff] << 3); \
+	(right) = IP[((temp) >> 24) & 0xff] \
+		| (IP[((temp) >> 16) & 0xff] << 1) \
+		| (IP[((temp) >>  8) & 0xff] << 2) \
+		| (IP[(temp) & 0xff] << 3)
+
+/*
+ * Now the final permutation stuff.  The same comments apply to
+ * this as to the initial permutation, except that we use different
+ * bits and shifts.
+ *
+ * The inserted cast to unsigned DES_INT32 circumvents a bug in
+ * the Macintosh MPW 3.2 C compiler which loses the unsignedness and
+ * propagates the high-order bit in the shift.
+ */
+#define DES_FP_LEFT_BITS(left, right) \
+	((((left) & 0x0f0f0f0f) << 4) | ((right) & 0x0f0f0f0f))
+#define	DES_FP_RIGHT_BITS(left, right) \
+	(((left) & 0xf0f0f0f0) | \
+		( ( (unsigned DES_INT32) ((right) & 0xf0f0f0f0) ) >> 4))
+
+
+/*
+ * Here is a sample final permutation.  Note that there is a trick
+ * here.  DES requires swapping the left and right parts after the
+ * last cipher round but before the final permutation.  We do this
+ * swapping internally, which is why left and right are confused
+ * at the beginning.
+ */
+#define DES_FINAL_PERM(left, right, temp) \
+	(temp) = DES_FP_RIGHT_BITS((right), (left)); \
+	(right) = DES_FP_LEFT_BITS((right), (left)); \
+	(left) = (FP[((right) >> 24) & 0xff] << 6) \
+	       | (FP[((right) >> 16) & 0xff] << 4) \
+	       | (FP[((right) >>  8) & 0xff] << 2) \
+	       |  FP[(right) & 0xff]; \
+	(right) = (FP[((temp) >> 24) & 0xff] << 6) \
+		| (FP[((temp) >> 16) & 0xff] << 4) \
+		| (FP[((temp) >>  8) & 0xff] << 2) \
+		|  FP[temp & 0xff]
+
+
+/*
+ * Finally, as a sample of how all this might be held together, the
+ * following two macros do in-place encryptions and decryptions.  left
+ * and right are two unsigned DES_INT32 variables which at the beginning
+ * are expected to hold the clear (encrypted) block in host byte order
+ * (left the high order four bytes, right the low order).  At the end
+ * they will contain the encrypted (clear) block.  temp is an unsigned DES_INT32
+ * used as a temporary.  kp is an unsigned DES_INT32 pointer pointing at
+ * the start of the key schedule.  All these should be in registers.
+ *
+ * You can probably do better than these by rewriting for particular
+ * situations.  These aren't bad, though.
+ *
+ * The DEB macros enable debugging when this code breaks (typically
+ * when a buggy compiler breaks it), by printing the intermediate values
+ * at each stage of the encryption, so that by comparing the output to
+ * a known good machine, the location of the first error can be found.
+ */
+#define	DES_DO_ENCRYPT_1(left, right, kp) \
+	do { \
+		register int i; \
+		register unsigned DES_INT32 temp1; \
+		DEB (("do_encrypt %8lX %8lX \n", left, right)); \
+		DES_INITIAL_PERM((left), (right), (temp1)); \
+		DEB (("  after IP %8lX %8lX\n", left, right)); \
+		for (i = 0; i < 8; i++) { \
+			DES_SP_ENCRYPT_ROUND((left), (right), (temp1), (kp)); \
+			DEB (("  round %2d %8lX %8lX \n", i*2, left, right)); \
+			DES_SP_ENCRYPT_ROUND((right), (left), (temp1), (kp)); \
+			DEB (("  round %2d %8lX %8lX \n", 1+i*2, left, right)); \
+		} \
+		DES_FINAL_PERM((left), (right), (temp1)); \
+		(kp) -= (2 * 16); \
+		DEB (("  after FP %8lX %8lX \n", left, right)); \
+	} while (0)
+
+#define	DES_DO_DECRYPT_1(left, right, kp) \
+	do { \
+		register int i; \
+		register unsigned DES_INT32 temp2; \
+		DES_INITIAL_PERM((left), (right), (temp2)); \
+		(kp) += (2 * 16); \
+		for (i = 0; i < 8; i++) { \
+			DES_SP_DECRYPT_ROUND((left), (right), (temp2), (kp)); \
+			DES_SP_DECRYPT_ROUND((right), (left), (temp2), (kp)); \
+		} \
+		DES_FINAL_PERM((left), (right), (temp2)); \
+	} while (0)
+
+#ifdef CONFIG_SMALL
+extern void krb5int_des_do_encrypt_2(unsigned DES_INT32 *l,
+				     unsigned DES_INT32 *r,
+				     const unsigned DES_INT32 *k);
+extern void krb5int_des_do_decrypt_2(unsigned DES_INT32 *l,
+				     unsigned DES_INT32 *r,
+				     const unsigned DES_INT32 *k);
+#define DES_DO_ENCRYPT(L,R,K) krb5int_des_do_encrypt_2(&(L), &(R), (K))
+#define DES_DO_DECRYPT(L,R,K) krb5int_des_do_decrypt_2(&(L), &(R), (K))
+#else
+#define DES_DO_ENCRYPT DES_DO_ENCRYPT_1
+#define DES_DO_DECRYPT DES_DO_DECRYPT_1
+#endif
+
+/*
+ * These are handy dandy utility thingies for straightening out bytes.
+ * Included here because they're used a couple of places.
+ */
+#define	GET_HALF_BLOCK(lr, ip)	((lr) = load_32_be(ip), (ip) += 4)
+#define PUT_HALF_BLOCK(lr, op)	(store_32_be(lr, op), (op) += 4)
+
+/* Shorthand that we'll need in several places, for creating values that
+   really can hold 32 bits regardless of the prevailing int size.  */
+#define FF_UINT32	((unsigned DES_INT32) 0xFF)
+
+#endif	/* __DES_TABLES_H__ */
diff --git a/mechglue/src/lib/crypto/des/key_sched.c b/mechglue/src/lib/crypto/des/key_sched.c
new file mode 100644
index 000000000..26449a94c
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/key_sched.c
@@ -0,0 +1,61 @@
+/*
+ * lib/crypto/des/key_sched.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 1990 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This routine computes the DES key schedule given a key.  The
+ * permutations and shifts have been done at compile time, resulting
+ * in a direct one-step mapping from the input key to the key
+ * schedule.
+ *
+ * Also checks parity and weak keys.
+ *
+ * Watch out for the subscripts -- most effectively start at 1 instead
+ * of at zero.  Maybe some bugs in that area.
+ *
+ * In case the user wants to cache the computed key schedule, it is
+ * passed as an arg.  Also implies that caller has explicit control
+ * over zeroing both the key schedule and the key.
+ *
+ * Originally written 6/85 by Steve Miller, MIT Project Athena.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+int
+mit_des_key_sched(mit_des_cblock k, mit_des_key_schedule schedule)
+{
+    mit_des_make_key_sched(k,schedule);
+
+    if (!mit_des_check_key_parity(k))	/* bad parity --> return -1 */
+	return(-1);
+
+    if (mit_des_is_weak_key(k))
+	return(-2);
+
+    /* if key was good, return 0 */
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/des/keytest.data b/mechglue/src/lib/crypto/des/keytest.data
new file mode 100644
index 000000000..7ff34eedc
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/keytest.data
@@ -0,0 +1,171 @@
+0101010101010101 95F8A5E5DD31D900 8000000000000000
+0101010101010101 DD7F121CA5015619 4000000000000000
+0101010101010101 2E8653104F3834EA 2000000000000000
+0101010101010101 4BD388FF6CD81D4F 1000000000000000
+0101010101010101 20B9E767B2FB1456 0800000000000000
+0101010101010101 55579380D77138EF 0400000000000000
+0101010101010101 6CC5DEFAAF04512F 0200000000000000
+0101010101010101 0D9F279BA5D87260 0100000000000000
+0101010101010101 D9031B0271BD5A0A 0080000000000000
+0101010101010101 424250B37C3DD951 0040000000000000
+0101010101010101 B8061B7ECD9A21E5 0020000000000000
+0101010101010101 F15D0F286B65BD28 0010000000000000
+0101010101010101 ADD0CC8D6E5DEBA1 0008000000000000
+0101010101010101 E6D5F82752AD63D1 0004000000000000
+0101010101010101 ECBFE3BD3F591A5E 0002000000000000
+0101010101010101 F356834379D165CD 0001000000000000
+0101010101010101 2B9F982F20037FA9 0000800000000000
+0101010101010101 889DE068A16F0BE6 0000400000000000
+0101010101010101 E19E275D846A1298 0000200000000000
+0101010101010101 329A8ED523D71AEC 0000100000000000
+0101010101010101 E7FCE22557D23C97 0000080000000000
+0101010101010101 12A9F5817FF2D65D 0000040000000000
+0101010101010101 A484C3AD38DC9C19 0000020000000000
+0101010101010101 FBE00A8A1EF8AD72 0000010000000000
+0101010101010101 750D079407521363 0000008000000000
+0101010101010101 64FEED9C724C2FAF 0000004000000000
+0101010101010101 F02B263B328E2B60 0000002000000000
+0101010101010101 9D64555A9A10B852 0000001000000000
+0101010101010101 D106FF0BED5255D7 0000000800000000
+0101010101010101 E1652C6B138C64A5 0000000400000000
+0101010101010101 E428581186EC8F46 0000000200000000
+0101010101010101 AEB5F5EDE22D1A36 0000000100000000
+0101010101010101 E943D7568AEC0C5C 0000000080000000
+0101010101010101 DF98C8276F54B04B 0000000040000000
+0101010101010101 B160E4680F6C696F 0000000020000000
+0101010101010101 FA0752B07D9C4AB8 0000000010000000
+0101010101010101 CA3A2B036DBC8502 0000000008000000
+0101010101010101 5E0905517BB59BCF 0000000004000000
+0101010101010101 814EEB3B91D90726 0000000002000000
+0101010101010101 4D49DB1532919C9F 0000000001000000
+0101010101010101 25EB5FC3F8CF0621 0000000000800000
+0101010101010101 AB6A20C0620D1C6F 0000000000400000
+0101010101010101 79E90DBC98F92CCA 0000000000200000
+0101010101010101 866ECEDD8072BB0E 0000000000100000
+0101010101010101 8B54536F2F3E64A8 0000000000080000
+0101010101010101 EA51D3975595B86B 0000000000040000
+0101010101010101 CAFFC6AC4542DE31 0000000000020000
+0101010101010101 8DD45A2DDF90796C 0000000000010000
+0101010101010101 1029D55E880EC2D0 0000000000008000
+0101010101010101 5D86CB23639DBEA9 0000000000004000
+0101010101010101 1D1CA853AE7C0C5F 0000000000002000
+0101010101010101 CE332329248F3228 0000000000001000
+0101010101010101 8405D1ABE24FB942 0000000000000800
+0101010101010101 E643D78090CA4207 0000000000000400
+0101010101010101 48221B9937748A23 0000000000000200
+0101010101010101 DD7C0BBD61FAFD54 0000000000000100
+0101010101010101 2FBC291A570DB5C4 0000000000000080
+0101010101010101 E07C30D7E4E26E12 0000000000000040
+0101010101010101 0953E2258E8E90A1 0000000000000020
+0101010101010101 5B711BC4CEEBF2EE 0000000000000010
+0101010101010101 CC083F1E6D9E85F6 0000000000000008
+0101010101010101 D2FD8867D50D2DFE 0000000000000004
+0101010101010101 06E7EA22CE92708F 0000000000000002
+0101010101010101 166B40B44ABA4BD6 0000000000000001
+8001010101010101 0000000000000000 95A8D72813DAA94D
+4001010101010101 0000000000000000 0EEC1487DD8C26D5
+2001010101010101 0000000000000000 7AD16FFB79C45926
+1001010101010101 0000000000000000 D3746294CA6A6CF3
+0801010101010101 0000000000000000 809F5F873C1FD761
+0401010101010101 0000000000000000 C02FAFFEC989D1FC
+0201010101010101 0000000000000000 4615AA1D33E72F10
+0180010101010101 0000000000000000 2055123350C00858
+0140010101010101 0000000000000000 DF3B99D6577397C8
+0120010101010101 0000000000000000 31FE17369B5288C9
+0110010101010101 0000000000000000 DFDD3CC64DAE1642
+0108010101010101 0000000000000000 178C83CE2B399D94
+0104010101010101 0000000000000000 50F636324A9B7F80
+0102010101010101 0000000000000000 A8468EE3BC18F06D
+0101800101010101 0000000000000000 A2DC9E92FD3CDE92
+0101400101010101 0000000000000000 CAC09F797D031287
+0101200101010101 0000000000000000 90BA680B22AEB525
+0101100101010101 0000000000000000 CE7A24F350E280B6
+0101080101010101 0000000000000000 882BFF0AA01A0B87
+0101040101010101 0000000000000000 25610288924511C2
+0101020101010101 0000000000000000 C71516C29C75D170
+0101018001010101 0000000000000000 5199C29A52C9F059
+0101014001010101 0000000000000000 C22F0A294A71F29F
+0101012001010101 0000000000000000 EE371483714C02EA
+0101011001010101 0000000000000000 A81FBD448F9E522F
+0101010801010101 0000000000000000 4F644C92E192DFED
+0101010401010101 0000000000000000 1AFA9A66A6DF92AE
+0101010201010101 0000000000000000 B3C1CC715CB879D8
+0101010180010101 0000000000000000 19D032E64AB0BD8B
+0101010140010101 0000000000000000 3CFAA7A7DC8720DC
+0101010120010101 0000000000000000 B7265F7F447AC6F3
+0101010110010101 0000000000000000 9DB73B3C0D163F54
+0101010108010101 0000000000000000 8181B65BABF4A975
+0101010104010101 0000000000000000 93C9B64042EAA240
+0101010102010101 0000000000000000 5570530829705592
+0101010101800101 0000000000000000 8638809E878787A0
+0101010101400101 0000000000000000 41B9A79AF79AC208
+0101010101200101 0000000000000000 7A9BE42F2009A892
+0101010101100101 0000000000000000 29038D56BA6D2745
+0101010101080101 0000000000000000 5495C6ABF1E5DF51
+0101010101040101 0000000000000000 AE13DBD561488933
+0101010101020101 0000000000000000 024D1FFA8904E389
+0101010101018001 0000000000000000 D1399712F99BF02E
+0101010101014001 0000000000000000 14C1D7C1CFFEC79E
+0101010101012001 0000000000000000 1DE5279DAE3BED6F
+0101010101011001 0000000000000000 E941A33F85501303
+0101010101010801 0000000000000000 DA99DBBC9A03F379
+0101010101010401 0000000000000000 B7FC92F91D8E92E9
+0101010101010201 0000000000000000 AE8E5CAA3CA04E85
+0101010101010180 0000000000000000 9CC62DF43B6EED74
+0101010101010140 0000000000000000 D863DBB5C59A91A0
+0101010101010120 0000000000000000 A1AB2190545B91D7
+0101010101010110 0000000000000000 0875041E64C570F7
+0101010101010108 0000000000000000 5A594528BEBEF1CC
+0101010101010104 0000000000000000 FCDB3291DE21F0C0
+0101010101010102 0000000000000000 869EFD7F9F265A09
+1046913489980131 0000000000000000 88D55E54F54C97B4
+1007103489988020 0000000000000000 0C0CC00C83EA48FD
+10071034C8980120 0000000000000000 83BC8EF3A6570183
+1046103489988020 0000000000000000 DF725DCAD94EA2E9
+1086911519190101 0000000000000000 E652B53B550BE8B0
+1086911519580101 0000000000000000 AF527120C485CBB0
+5107B01519580101 0000000000000000 0F04CE393DB926D5
+1007B01519190101 0000000000000000 C9F00FFC74079067
+3107915498080101 0000000000000000 7CFD82A593252B4E
+3107919498080101 0000000000000000 CB49A2F9E91363E3
+10079115B9080140 0000000000000000 00B588BE70D23F56
+3107911598080140 0000000000000000 406A9A6AB43399AE
+1007D01589980101 0000000000000000 6CB773611DCA9ADA
+9107911589980101 0000000000000000 67FD21C17DBB5D70
+9107D01589190101 0000000000000000 9592CB4110430787
+1007D01598980120 0000000000000000 A6B7FF68A318DDD3
+1007940498190101 0000000000000000 4D102196C914CA16
+0107910491190401 0000000000000000 2DFA9F4573594965
+0107910491190101 0000000000000000 B46604816C0E0774
+0107940491190401 0000000000000000 6E7E6221A4F34E87
+19079210981A0101 0000000000000000 AA85E74643233199
+1007911998190801 0000000000000000 2E5A19DB4D1962D6
+10079119981A0801 0000000000000000 23A866A809D30894
+1007921098190101 0000000000000000 D812D961F017D320
+100791159819010B 0000000000000000 055605816E58608F
+1004801598190101 0000000000000000 ABD88E8B1B7716F1
+1004801598190102 0000000000000000 537AC95BE69DA1E1
+1004801598190108 0000000000000000 AED0F6AE3C25CDD8
+1002911598100104 0000000000000000 B3E35A5EE53E7B8D
+1002911598190104 0000000000000000 61C79C71921A2EF8
+1002911598100201 0000000000000000 E2F5728F0995013C
+1002911698100101 0000000000000000 1AEAC39A61F0A464
+7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B
+0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271
+07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A
+3849674C2602319E 51454B582DDF440A 7178876E01F19B2A
+04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095
+0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B
+0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09
+43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A
+07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F
+04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088
+37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77
+1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A
+584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56
+025816164629B007 480D39006EE762F2 A1F9915541020B56
+49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556
+4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC
+49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A
+018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41
+1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793
diff --git a/mechglue/src/lib/crypto/des/string2key.c b/mechglue/src/lib/crypto/des/string2key.c
new file mode 100644
index 000000000..4fe9e4799
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/string2key.c
@@ -0,0 +1,261 @@
+/*
+ * lib/crypto/des/des_s2k.c
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Compute encryption key from salt and pass phrase.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+krb5_error_code
+mit_des_string_to_key_int (krb5_keyblock *key,
+			   const krb5_data *pw, const krb5_data *salt)
+{
+    union {
+	/* 8 "forward" bytes, 8 "reverse" bytes */
+	unsigned char uc[16];
+	krb5_ui_4 ui[4];
+	mit_des_cblock cb;
+    } temp;
+    int i;
+    krb5_ui_4 x, y, z;
+    unsigned char *p;
+    des_key_schedule sched;
+    char *copy;
+    size_t copylen;
+
+    /* As long as the architecture is big-endian or little-endian, it
+       doesn't matter which it is.  Think of it as reversing the
+       bytes, and also reversing the bits within each byte.  But this
+       current algorithm is dependent on having four 8-bit char values
+       exactly overlay a 32-bit integral type.  */
+    if (sizeof(temp.uc) != sizeof(temp.ui)
+	|| (unsigned char)~0 != 0xFF
+	|| (krb5_ui_4)~(krb5_ui_4)0 != 0xFFFFFFFF
+	|| (temp.uc[0] = 1, temp.uc[1] = 2, temp.uc[2] = 3, temp.uc[3] = 4,
+	    !(temp.ui[0] == 0x01020304
+	      || temp.ui[0] == 0x04030201)))
+	abort();
+#define FETCH4(VAR, IDX)	VAR = temp.ui[IDX/4]
+#define PUT4(VAR, IDX)		temp.ui[IDX/4] = VAR
+
+    if (salt
+	&& (salt->length == SALT_TYPE_AFS_LENGTH
+	    /* XXX  Yuck!  Aren't we done with this yet?  */
+	    || salt->length == (unsigned) -1)) {
+	krb5_data afssalt;
+	char *at;
+
+	afssalt.data = salt->data;
+	at = strchr(afssalt.data, '@');
+	if (at) {
+	    *at = 0;
+	    afssalt.length = at - afssalt.data;
+	} else
+	    afssalt.length = strlen(afssalt.data);
+	return mit_afs_string_to_key(key, pw, &afssalt);
+    }
+
+    copylen = pw->length + (salt ? salt->length : 0);
+    /* Don't need NUL termination, at this point we're treating it as
+       a byte array, not a string.  */
+    copy = malloc(copylen);
+    if (copy == NULL)
+	return errno;
+    memcpy(copy, pw->data, pw->length);
+    if (salt)
+	memcpy(copy + pw->length, salt->data, salt->length);
+
+    memset(&temp, 0, sizeof(temp));
+    p = temp.uc;
+    /* Handle the fan-fold xor operation by splitting the data into
+       forward and reverse sections, and combine them later, rather
+       than having to do the reversal over and over again.  */
+    for (i = 0; i < copylen; i++) {
+	*p++ ^= copy[i];
+	if (p == temp.uc+16) {
+	    p = temp.uc;
+#ifdef PRINT_TEST_VECTORS
+	    {
+		int j;
+		printf("after %d input bytes:\nforward block:\t", i+1);
+		for (j = 0; j < 8; j++)
+		    printf(" %02x", temp.uc[j] & 0xff);
+		printf("\nreverse block:\t");
+		for (j = 8; j < 16; j++)
+		    printf(" %02x", temp.uc[j] & 0xff);
+		printf("\n");
+	    }
+#endif
+	}
+    }
+
+#ifdef PRINT_TEST_VECTORS
+    if (p != temp.uc) {
+	int j;
+	printf("at end, after %d input bytes:\nforward block:\t", i);
+	for (j = 0; j < 8; j++)
+	    printf(" %02x", temp.uc[j] & 0xff);
+	printf("\nreverse block:\t");
+	for (j = 8; j < 16; j++)
+	    printf(" %02x", temp.uc[j] & 0xff);
+	printf("\n");
+    }
+#endif
+#if 0
+    /* Algorithm described in Dr. Dobbs Journal 1983, reported in "bit
+       twiddling hacks" web page collected by Sean Eron Anderson; see
+       http://graphics.stanford.edu/~seander/bithacks.html for
+       details.
+
+       Avoids loops, uses 7*lg(N)=35 ops instead of 4*N=128 for the
+       obvious mask, ior, shift, shift sequence of each 32-bit
+       quantity.
+
+       If we could rely on 64-bit math, another 7 ops would save us
+       from having to do double the work.  */
+#define REVERSE_STEP(VAR, SHIFT, MASK)			\
+    VAR = ((VAR >> SHIFT) & MASK) | ((VAR << SHIFT) & (0xFFFFFFFFUL & ~MASK))
+#define REVERSE(VAR)						\
+    REVERSE_STEP (VAR, 1, 0x55555555UL); /* swap odd/even bits */	\
+    REVERSE_STEP (VAR, 2, 0x33333333UL); /* swap bitpairs */		\
+    REVERSE_STEP (VAR, 4, 0x0F0F0F0FUL); /* swap nibbles, etc */	\
+    REVERSE_STEP (VAR, 8, 0x00FF00FFUL);				\
+    REVERSE_STEP (VAR, 16, 0x0000FFFFUL);
+#else /* shorter */
+#define REVERSE(VAR)				\
+    {						\
+	krb5_ui_4 old = VAR, temp1 = 0;		\
+	int j;					\
+	for (j = 0; j < 32; j++) {		\
+	    temp1 = (temp1 << 1) | (old & 1);	\
+	    old >>= 1;				\
+	}					\
+	VAR = temp1;				\
+    }
+#endif
+
+    FETCH4 (x, 8);
+    FETCH4 (y, 12);
+    /* Ignore high bits of each input byte.  */
+    x &= 0x7F7F7F7F;
+    y &= 0x7F7F7F7F;
+    /* Reverse the bit strings -- after this, y is "before" x.  */
+    REVERSE (x);
+    REVERSE (y);
+#ifdef PRINT_TEST_VECTORS
+    {
+	int j;
+	union { unsigned char uc[4]; krb5_ui_4 ui; } t2;
+	printf("after reversal, reversed block:\n\t\t");
+	t2.ui = y;
+	for (j = 0; j < 4; j++)
+	    printf(" %02x", t2.uc[j] & 0xff);
+	t2.ui = x;
+	for (j = 0; j < 4; j++)
+	    printf(" %02x", t2.uc[j] & 0xff);
+	printf("\n");
+    }
+#endif
+    /* Ignored bits are now at the bottom of each byte, where we'll
+       put the parity bits.  Good.  */
+    FETCH4 (z, 0);
+    z &= 0x7F7F7F7F;
+    /* Ignored bits for z are at the top of each byte; fix that.  */
+    z <<= 1;
+    /* Finish the fan-fold xor for these four bytes.  */
+    z ^= y;
+    PUT4 (z, 0);
+    /* Now do the second four bytes.  */
+    FETCH4 (z, 4);
+    z &= 0x7F7F7F7F;
+    /* Ignored bits for z are at the top of each byte; fix that.  */
+    z <<= 1;
+    /* Finish the fan-fold xor for these four bytes.  */
+    z ^= x;
+    PUT4 (z, 4);
+
+#ifdef PRINT_TEST_VECTORS
+    {
+	int j;
+	printf("after reversal, combined block:\n\t\t");
+	for (j = 0; j < 8; j++)
+	    printf(" %02x", temp.uc[j] & 0xff);
+	printf("\n");
+    }
+#endif
+
+#define FIXUP(K)					\
+    (mit_des_fixup_key_parity(K),			\
+     mit_des_is_weak_key(K) ? (K[7] ^= 0xF0) : 0)
+
+    /* Now temp.cb is the temporary key, with invalid parity.  */
+    FIXUP(temp.cb);
+
+#ifdef PRINT_TEST_VECTORS
+    {
+	int j;
+	printf("after fixing parity and weak keys:\n\t\t");
+	for (j = 0; j < 8; j++)
+	    printf(" %02x", temp.uc[j] & 0xff);
+	printf("\n");
+    }
+#endif
+
+    mit_des_key_sched(temp.cb, sched);
+    mit_des_cbc_cksum(copy, temp.cb, copylen, sched, temp.cb);
+
+    memset(copy, 0, copylen);
+    free(copy);
+
+#ifdef PRINT_TEST_VECTORS
+    {
+	int j;
+	printf("cbc checksum:\n\t\t");
+	for (j = 0; j < 8; j++)
+	    printf(" %02x", temp.uc[j] & 0xff);
+	printf("\n");
+    }
+#endif
+
+    memset(sched, 0, sizeof(sched));
+    FIXUP (temp.cb);
+
+#ifdef PRINT_TEST_VECTORS
+    {
+	int j;
+	printf("after fixing parity and weak keys:\n\t\t");
+	for (j = 0; j < 8; j++)
+	    printf(" %02x", temp.uc[j] & 0xff);
+	printf("\n");
+    }
+#endif
+
+    memcpy(key->contents, temp.cb, 8);
+    memset(&temp, 0, sizeof(temp));
+
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/des/t_afss2k.c b/mechglue/src/lib/crypto/des/t_afss2k.c
new file mode 100644
index 000000000..a6d0aa58d
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/t_afss2k.c
@@ -0,0 +1,136 @@
+#include "des_int.h"
+
+static const char *me;
+
+struct test_case {
+	char *saltstr;
+	int saltlen;
+	unsigned char keys[12][8];
+};
+
+struct test_case test_cases[] = {
+	{
+		"Sodium Chloride", -1,
+		{
+			{ 0xa4, 0xd0, 0xd0, 0x9b, 0x86, 0x92, 0xb0, 0xc2, },
+			{ 0xf1, 0xf2, 0x9e, 0xab, 0xd0, 0xef, 0xdf, 0x73, },
+			{ 0xd6, 0x85, 0x61, 0xc4, 0xf2, 0x94, 0xf4, 0xa1, },
+			{ 0xd0, 0xe3, 0xa7, 0x83, 0x94, 0x61, 0xe0, 0xd0, },
+			{ 0xd5, 0x62, 0xcd, 0x94, 0x61, 0xcb, 0x97, 0xdf, },
+			{ 0x9e, 0xa2, 0xa2, 0xec, 0xa8, 0x8c, 0x6b, 0x8f, },
+			{ 0xe3, 0x91, 0x6d, 0xd3, 0x85, 0xf1, 0x67, 0xc4, },
+			{ 0xf4, 0xc4, 0x73, 0xc8, 0x8a, 0xe9, 0x94, 0x6d, },
+			{ 0xa1, 0x9e, 0xb3, 0xad, 0x6b, 0xe3, 0xab, 0xd9, },
+			{ 0xad, 0xa1, 0xce, 0x10, 0x37, 0x83, 0xa7, 0x8c, },
+			{ 0xd3, 0x01, 0xd0, 0xf7, 0x3e, 0x7a, 0x49, 0x0b, },
+			{ 0xb6, 0x2a, 0x4a, 0xec, 0x9d, 0x4c, 0x68, 0xdf, },
+		}
+	},
+	{
+		"NaCl", 4,
+		{
+			{ 0x61, 0xef, 0xe6, 0x83, 0xe5, 0x8a, 0x6b, 0x98 },
+			{ 0x68, 0xcd, 0x68, 0xad, 0xc4, 0x86, 0xcd, 0xe5 },
+			{ 0x83, 0xa1, 0xc8, 0x86, 0x8f, 0x67, 0xd0, 0x62 },
+			{ 0x9e, 0xc7, 0x8f, 0xa4, 0xa4, 0xb3, 0xe0, 0xd5 },
+			{ 0xd9, 0x92, 0x86, 0x8f, 0x9d, 0x8c, 0x85, 0xe6 },
+			{ 0xda, 0xf2, 0x92, 0x83, 0xf4, 0x9b, 0xa7, 0xad },
+			{ 0x91, 0xcd, 0xad, 0xef, 0x86, 0xdf, 0xd3, 0xa2 },
+			{ 0x73, 0xd3, 0x67, 0x68, 0x8f, 0x6e, 0xe3, 0x73 },
+			{ 0xc4, 0x61, 0x85, 0x9d, 0xad, 0xf4, 0xdc, 0xb0 },
+			{ 0xe9, 0x02, 0x83, 0x16, 0x2c, 0xec, 0xe0, 0x08 },
+			{ 0x61, 0xc8, 0x26, 0x29, 0xd9, 0x73, 0x6e, 0xb6 },
+			{ 0x8c, 0xa8, 0x9e, 0xc4, 0xa8, 0xdc, 0x31, 0x73 },
+		}
+	},
+	{
+		/* This one intentionally supplies a length shorter
+		   than the string.  The point of this is to ensure
+		   that s[len] is not zero, so that anything actually
+		   relying on that value (i.e., reading out of bounds)
+		   should generate incorrect results.  */
+		"NaCl2", 4,
+		{
+			{ 0x61, 0xef, 0xe6, 0x83, 0xe5, 0x8a, 0x6b, 0x98 },
+			{ 0x68, 0xcd, 0x68, 0xad, 0xc4, 0x86, 0xcd, 0xe5 },
+			{ 0x83, 0xa1, 0xc8, 0x86, 0x8f, 0x67, 0xd0, 0x62 },
+			{ 0x9e, 0xc7, 0x8f, 0xa4, 0xa4, 0xb3, 0xe0, 0xd5 },
+			{ 0xd9, 0x92, 0x86, 0x8f, 0x9d, 0x8c, 0x85, 0xe6 },
+			{ 0xda, 0xf2, 0x92, 0x83, 0xf4, 0x9b, 0xa7, 0xad },
+			{ 0x91, 0xcd, 0xad, 0xef, 0x86, 0xdf, 0xd3, 0xa2 },
+			{ 0x73, 0xd3, 0x67, 0x68, 0x8f, 0x6e, 0xe3, 0x73 },
+			{ 0xc4, 0x61, 0x85, 0x9d, 0xad, 0xf4, 0xdc, 0xb0 },
+			{ 0xe9, 0x02, 0x83, 0x16, 0x2c, 0xec, 0xe0, 0x08 },
+			{ 0x61, 0xc8, 0x26, 0x29, 0xd9, 0x73, 0x6e, 0xb6 },
+			{ 0x8c, 0xa8, 0x9e, 0xc4, 0xa8, 0xdc, 0x31, 0x73 },
+		}
+	},
+};
+
+static void do_it (struct test_case *tcase);
+
+int
+main (int argc, char *argv[])
+{
+	int i;
+
+	me = argv[0];
+	for (i = 0; i < sizeof (test_cases) / sizeof (struct test_case); i++)
+		do_it (&test_cases[i]);
+	return 0;
+}
+
+static void
+do_it (struct test_case *tcase)
+{
+	unsigned char keydata[8];
+	krb5_data salt, passwd;
+	krb5_keyblock key;
+	krb5_error_code err;
+	int i;
+	unsigned char longpass[2048];
+
+	key.contents = keydata;
+	key.length = sizeof (keydata);
+
+	salt.data = tcase->saltstr;
+	if (tcase->saltlen == -1)
+		salt.length = strlen (tcase->saltstr);
+	else
+		salt.length = tcase->saltlen;
+
+	/*
+	 * Try passwords with lengths equal to, greater than, and less
+	 * than 8 characters, since the AFS s2k algorithm does
+	 * interesting stuff depending on the length.
+	 */
+	passwd.data = "My Password";
+	for (i = 0; i < 12; i++) {
+		passwd.length = i;
+		err = mit_afs_string_to_key (&key, &passwd, &salt);
+		if (err != 0) {
+			com_err (me, err, "");
+			exit (1);
+		}
+		if (memcmp (tcase->keys[i], keydata, 8) != 0)
+			abort ();
+	}
+
+	/* Run another pass to make sure the characters after the
+	   password in the buffer aren't influencing the output.  The
+	   password is *not* required to be null-terminated.  */
+	memset (longpass, '!', sizeof (longpass));
+	longpass[sizeof (longpass)-1] = '\0';
+	memcpy (longpass, "My Password", strlen ("My Password"));
+	passwd.data = (char *) longpass;
+	for (i = 0; i < 12; i++) {
+		passwd.length = i;
+		err = mit_afs_string_to_key (&key, &passwd, &salt);
+		if (err != 0) {
+			com_err (me, err, "");
+			exit (1);
+		}
+		if (memcmp (tcase->keys[i], keydata, 8) != 0)
+			abort ();
+	}
+}
diff --git a/mechglue/src/lib/crypto/des/t_verify.c b/mechglue/src/lib/crypto/des/t_verify.c
new file mode 100644
index 000000000..a6ad07cb8
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/t_verify.c
@@ -0,0 +1,418 @@
+/*
+ * lib/crypto/des/verify.c
+ *
+ * Copyright 1988, 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Program to test the correctness of the DES library
+ * implementation.
+ *
+ * exit returns	 0 ==> success
+ * 		-1 ==> error
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include <stdio.h>
+#include "com_err.h"
+
+static void do_encrypt(unsigned char *, unsigned char *);
+static void do_decrypt(unsigned char *, unsigned char *);
+
+char *progname;
+int nflag = 2;
+int vflag;
+int mflag;
+int zflag;
+int pid;
+int mit_des_debug;
+
+unsigned char cipher_text[64];
+unsigned char clear_text[64] = "Now is the time for all " ;
+unsigned char clear_text2[64] = "7654321 Now is the time for ";
+unsigned char clear_text3[64] = {2,0,0,0, 1,0,0,0};
+unsigned char output[64];
+unsigned char zero_text[8] = {0x0,0,0,0,0,0,0,0};
+unsigned char msb_text[8] = {0x0,0,0,0, 0,0,0,0x40}; /* to ANSI MSB */
+unsigned char *input;
+
+/* 0x0123456789abcdef */
+unsigned char default_key[8] = {
+    0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef
+};
+unsigned char key2[8] = { 0x08,0x19,0x2a,0x3b,0x4c,0x5d,0x6e,0x7f };
+unsigned char key3[8] = { 0x80,1,1,1,1,1,1,1 };
+mit_des_cblock s_key;
+unsigned char default_ivec[8] = {
+    0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef
+};
+unsigned char *ivec;
+unsigned char zero_key[8] = {1,1,1,1,1,1,1,1}; /* just parity bits */
+
+unsigned char cipher1[8] = {
+    0x25,0xdd,0xac,0x3e,0x96,0x17,0x64,0x67
+};
+unsigned char cipher2[8] = {
+    0x3f,0xa4,0x0e,0x8a,0x98,0x4d,0x48,0x15
+};
+unsigned char cipher3[64] = {
+    0xe5,0xc7,0xcd,0xde,0x87,0x2b,0xf2,0x7c,
+    0x43,0xe9,0x34,0x00,0x8c,0x38,0x9c,0x0f,
+    0x68,0x37,0x88,0x49,0x9a,0x7c,0x05,0xf6
+};
+unsigned char checksum[8] = {
+    0x58,0xd2,0xe7,0x7e,0x86,0x06,0x27,0x33
+};
+
+unsigned char zresult[8] = {
+    0x8c, 0xa6, 0x4d, 0xe9, 0xc1, 0xb1, 0x23, 0xa7
+};
+
+unsigned char mresult[8] = {
+    0xa3, 0x80, 0xe0, 0x2a, 0x6b, 0xe5, 0x46, 0x96
+};
+
+    
+/*
+ * Can also add :
+ * plaintext = 0, key = 0, cipher = 0x8ca64de9c1b123a7 (or is it a 1?)
+ */
+
+mit_des_key_schedule sched;
+
+int
+main(argc,argv)
+    int argc;
+    char *argv[];
+{
+    /* Local Declarations */
+    size_t  in_length;
+    int  retval;
+    int i, j;
+
+#ifdef WINDOWS
+    /* Set screen window buffer to infinite size -- MS default is tiny.  */
+    _wsetscreenbuf (fileno (stdout), _WINBUFINF);
+#endif
+    progname=argv[0];		/* salt away invoking program */
+
+    while (--argc > 0 && (*++argv)[0] == '-')
+	for (i=1; argv[0][i] != '\0'; i++) {
+	    switch (argv[0][i]) {
+
+		/* debug flag */
+	    case 'd':
+		mit_des_debug=3;
+		continue;
+
+	    case 'z':
+		zflag = 1;
+		continue;
+
+	    case 'm':
+		mflag = 1;
+		continue;
+
+	    default:
+		printf("%s: illegal flag \"%c\" ",
+		       progname,argv[0][i]);
+		exit(1);
+	    }
+	};
+
+    if (argc) {
+	fprintf(stderr, "Usage: %s [-dmz]\n", progname);
+	exit(1);
+    }
+
+    /* do some initialisation */
+
+    /* use known input and key */
+
+    /* ECB zero text zero key */
+    if (zflag) {
+	input = zero_text;
+	mit_des_key_sched(zero_key, sched);
+	printf("plaintext = key = 0, cipher = 0x8ca64de9c1b123a7\n");
+	do_encrypt(input,cipher_text);
+	printf("\tcipher  = (low to high bytes)\n\t\t");
+	for (j = 0; j<=7; j++)
+	    printf("%02x ",cipher_text[j]);
+	printf("\n");
+	do_decrypt(output,cipher_text);
+	if ( memcmp((char *)cipher_text, (char *)zresult, 8) ) {
+	    printf("verify: error in zero key test\n");
+	    exit(-1);
+	}
+
+	exit(0);
+    }
+
+    if (mflag) {
+	input = msb_text;
+	mit_des_key_sched(key3, sched);
+	printf("plaintext = 0x00 00 00 00 00 00 00 40, ");
+	printf("key = 0x80 01 01 01 01 01 01 01\n");
+	printf("	cipher = 0xa380e02a6be54696\n");
+	do_encrypt(input,cipher_text);
+	printf("\tcipher  = (low to high bytes)\n\t\t");
+	for (j = 0; j<=7; j++) {
+	    printf("%02x ",cipher_text[j]);
+	}
+	printf("\n");
+	do_decrypt(output,cipher_text);
+	if ( memcmp((char *)cipher_text, (char *)mresult, 8) ) {
+	    printf("verify: error in msb test\n");
+	    exit(-1);
+	}
+	exit(0);
+    }
+
+    /* ECB mode Davies and Price */
+    {
+	input = zero_text;
+	mit_des_key_sched(key2, sched);
+	printf("Examples per FIPS publication 81, keys ivs and cipher\n");
+	printf("in hex.  These are the correct answers, see below for\n");
+	printf("the actual answers.\n\n");
+	printf("Examples per Davies and Price.\n\n");
+	printf("EXAMPLE ECB\tkey = 08192a3b4c5d6e7f\n");
+	printf("\tclear = 0\n");
+	printf("\tcipher = 25 dd ac 3e 96 17 64 67\n");
+	printf("ACTUAL ECB\n");
+	printf("\tclear \"%s\"\n", input);
+	do_encrypt(input,cipher_text);
+	printf("\tcipher  = (low to high bytes)\n\t\t");
+	for (j = 0; j<=7; j++)
+	    printf("%02x ",cipher_text[j]);
+	printf("\n\n");
+	do_decrypt(output,cipher_text);
+	if ( memcmp((char *)cipher_text, (char *)cipher1, 8) ) {
+	    printf("verify: error in ECB encryption\n");
+	    exit(-1);
+	}
+	else 
+	    printf("verify: ECB encryption is correct\n\n");
+    }
+
+    /* ECB mode */
+    {
+	mit_des_key_sched(default_key, sched);
+	input = clear_text;
+	ivec = default_ivec;
+	printf("EXAMPLE ECB\tkey = 0123456789abcdef\n");
+	printf("\tclear = \"Now is the time for all \"\n");
+	printf("\tcipher = 3f a4 0e 8a 98 4d 48 15 ...\n");
+	printf("ACTUAL ECB\n\tclear \"%s\"",input);
+	do_encrypt(input,cipher_text);
+	printf("\n\tcipher	= (low to high bytes)\n\t\t");
+	for (j = 0; j<=7; j++) {
+	    printf("%02x ",cipher_text[j]);
+	}
+	printf("\n\n");
+	do_decrypt(output,cipher_text);
+	if ( memcmp((char *)cipher_text, (char *)cipher2, 8) ) {
+	    printf("verify: error in ECB encryption\n");
+	    exit(-1);
+	}
+	else 
+	    printf("verify: ECB encryption is correct\n\n");
+    }
+
+    /* CBC mode */
+    printf("EXAMPLE CBC\tkey = 0123456789abcdef");
+    printf("\tiv = 1234567890abcdef\n");
+    printf("\tclear = \"Now is the time for all \"\n");
+    printf("\tcipher =\te5 c7 cd de 87 2b f2 7c\n");
+    printf("\t\t\t43 e9 34 00 8c 38 9c 0f\n");
+    printf("\t\t\t68 37 88 49 9a 7c 05 f6\n");
+
+    printf("ACTUAL CBC\n\tclear \"%s\"\n",input);
+    in_length =  strlen((char *)input);
+    if ((retval = mit_des_cbc_encrypt((const mit_des_cblock *) input,
+				      (mit_des_cblock *) cipher_text,
+				      (size_t) in_length, 
+				      sched,
+				      ivec,
+				      MIT_DES_ENCRYPT))) {
+	com_err("des verify", retval, "can't encrypt");
+	exit(-1);
+    }
+    printf("\tciphertext = (low to high bytes)\n");
+    for (i = 0; i <= 2; i++) {
+	printf("\t\t");
+	for (j = 0; j <= 7; j++) {
+	    printf("%02x ",cipher_text[i*8+j]);
+	}
+	printf("\n");
+    }
+    if ((retval = mit_des_cbc_encrypt((const mit_des_cblock *) cipher_text,
+				      (mit_des_cblock *) clear_text,
+				      (size_t) in_length, 
+				      sched,
+				      ivec,
+				      MIT_DES_DECRYPT))) {
+	com_err("des verify", retval, "can't decrypt");
+	exit(-1);
+    }
+    printf("\tdecrypted clear_text = \"%s\"\n",clear_text);
+
+    if ( memcmp((char *)cipher_text, (char *)cipher3, in_length) ) {
+	printf("verify: error in CBC encryption\n");
+	exit(-1);
+    }
+    else 
+	printf("verify: CBC encryption is correct\n\n");
+
+    printf("EXAMPLE CBC checksum");
+    printf("\tkey =  0123456789abcdef\tiv =  1234567890abcdef\n");
+    printf("\tclear =\t\t\"7654321 Now is the time for \"\n");
+    printf("\tchecksum\t58 d2 e7 7e 86 06 27 33, ");
+    printf("or some part thereof\n");
+    input = clear_text2;
+    mit_des_cbc_cksum(input,cipher_text, strlen((char *)input),
+		      sched,ivec);
+    printf("ACTUAL CBC checksum\n");
+    printf("\t\tencrypted cksum = (low to high bytes)\n\t\t");
+    for (j = 0; j<=7; j++)
+	printf("%02x ",cipher_text[j]);
+    printf("\n\n");
+    if ( memcmp((char *)cipher_text, (char *)checksum, 8) ) {
+	printf("verify: error in CBC cheksum\n");
+	exit(-1);
+    }
+    else 
+	printf("verify: CBC checksum is correct\n\n");
+
+    exit(0);
+}
+
+#if 0
+void
+flip(array)
+    char *array;
+{
+    register int old,new,i,j;
+    /* flips the bit order within each byte from 0 lsb to 0 msb */
+    for (i = 0; i<=7; i++) {
+	old = *array;
+	new = 0;
+	for (j = 0; j<=7; j++) {
+	    if (old & 01)
+		new = new | 01;
+	    if (j < 7) {
+		old = old >> 1;
+		new = new << 1;
+	    }
+	}
+	*array = new;
+	array++;
+    }
+}
+#endif
+
+static void
+do_encrypt(in,out)
+    unsigned char *in;
+    unsigned char *out;
+{
+    int i, j;
+    for (i =1; i<=nflag; i++) {
+	mit_des_cbc_encrypt((const mit_des_cblock *)in,
+			    (mit_des_cblock *)out,
+			    8,
+			    sched,
+			    zero_text,
+			    MIT_DES_ENCRYPT);
+	if (mit_des_debug) {
+	    printf("\nclear %s\n",in);
+	    for (j = 0; j<=7; j++)
+		printf("%02X ",in[j] & 0xff);
+	    printf("\tcipher ");
+	    for (j = 0; j<=7; j++)
+		printf("%02X ",out[j] & 0xff);
+	}
+    }
+}
+
+static void
+do_decrypt(in,out)
+    unsigned char *out;
+    unsigned char *in;
+    /* try to invert it */
+{
+    int i, j;
+    for (i =1; i<=nflag; i++) {
+	mit_des_cbc_encrypt((const mit_des_cblock *)out,
+			    (mit_des_cblock *)in,
+			    8,
+			    sched,
+			    zero_text,
+			    MIT_DES_DECRYPT);
+	if (mit_des_debug) {
+	    printf("clear %s\n",in);
+	    for (j = 0; j<=7; j++)
+		printf("%02X ",in[j] & 0xff);
+	    printf("\tcipher ");
+	    for (j = 0; j<=7; j++)
+		printf("%02X ",out[j] & 0xff);
+	}
+    }
+}
+
+/*
+ * Fake out the DES library, for the purposes of testing.
+ */
+
+int
+mit_des_is_weak_key(key)
+    mit_des_cblock key;
+{
+    return 0;				/* fake it out for testing */
+}
diff --git a/mechglue/src/lib/crypto/des/weak_key.c b/mechglue/src/lib/crypto/des/weak_key.c
new file mode 100644
index 000000000..005b16387
--- /dev/null
+++ b/mechglue/src/lib/crypto/des/weak_key.c
@@ -0,0 +1,85 @@
+/*
+ * lib/crypto/des/weak_key.c
+ *
+ * Copyright 1989,1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Under U.S. law, this software may not be exported outside the US
+ * without license from the U.S. Commerce department.
+ *
+ * These routines form the library interface to the DES facilities.
+ *
+ * Originally written 8/85 by Steve Miller, MIT Project Athena.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+/*
+ * The following are the weak DES keys:
+ */
+static const mit_des_cblock weak[16] = {
+    /* weak keys */
+    {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
+    {0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe},
+    {0x1f,0x1f,0x1f,0x1f,0x0e,0x0e,0x0e,0x0e},
+    {0xe0,0xe0,0xe0,0xe0,0xf1,0xf1,0xf1,0xf1},
+
+    /* semi-weak */
+    {0x01,0xfe,0x01,0xfe,0x01,0xfe,0x01,0xfe},
+    {0xfe,0x01,0xfe,0x01,0xfe,0x01,0xfe,0x01},
+
+    {0x1f,0xe0,0x1f,0xe0,0x0e,0xf1,0x0e,0xf1},
+    {0xe0,0x1f,0xe0,0x1f,0xf1,0x0e,0xf1,0x0e},
+
+    {0x01,0xe0,0x01,0xe0,0x01,0xf1,0x01,0xf1},
+    {0xe0,0x01,0xe0,0x01,0xf1,0x01,0xf1,0x01},
+
+    {0x1f,0xfe,0x1f,0xfe,0x0e,0xfe,0x0e,0xfe},
+    {0xfe,0x1f,0xfe,0x1f,0xfe,0x0e,0xfe,0x0e},
+
+    {0x01,0x1f,0x01,0x1f,0x01,0x0e,0x01,0x0e},
+    {0x1f,0x01,0x1f,0x01,0x0e,0x01,0x0e,0x01},
+
+    {0xe0,0xfe,0xe0,0xfe,0xf1,0xfe,0xf1,0xfe},
+    {0xfe,0xe0,0xfe,0xe0,0xfe,0xf1,0xfe,0xf1}
+};
+
+/*
+ * mit_des_is_weak_key: returns true iff key is a [semi-]weak des key.
+ *
+ * Requires: key has correct odd parity.
+ */
+int
+mit_des_is_weak_key(mit_des_cblock key)
+{
+    int i;
+    const mit_des_cblock *weak_p = weak;
+
+    for (i = 0; i < (sizeof(weak)/sizeof(mit_des_cblock)); i++) {
+	if (!memcmp(weak_p++,key,sizeof(mit_des_cblock)))
+	    return 1;
+    }
+
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/dk/ChangeLog b/mechglue/src/lib/crypto/dk/ChangeLog
new file mode 100644
index 000000000..5e9886700
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/ChangeLog
@@ -0,0 +1,181 @@
+2005-05-19  Sam Hartman  <hartmans@mit.edu>
+
+	* dk_prf.c (krb5int_dk_prf):  Use k5crypto versions of keyblock memory management
+
+2004-12-09  Sam Hartman  <hartmans@mit.edu>
+
+	* dk.h: Add krb5_dk_prf
+
+	* Makefile.in (SRCS): Add dk_prf.c
+
+	* dk_prf.c (krb5int_dk_prf): New function
+
+2004-03-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* derive.c (krb5_random2key): Don't compile.
+
+	* dk.h (krb5_derive_random): Declare.
+
+2004-02-24  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* dk.h: As below.
+
+	* checksum.c dk_decrypt.c dk_encrypt.c: Remove ENCTYPE_LOCAL_DES3_HMAC_SHA1
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* checksum.c, derive.c, dk_decrypt.c, dk_encrypt.c: Use ANSI C
+	style function definitions.
+
+2004-02-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* dk_decrypt.c (krb5_dk_decrypt_maybe_trunc_hmac): New argument
+	IVEC_MODE.  If clear, same old behavior.  If set, copy out next
+	to last block for CTS.
+	(krb5_dk_decrypt, krb5int_aes_dk_decrypt): Pass extra argument.
+	* dk_encrypt.c (krb5int_aes_dk_encrypt): For IV, copy out next to
+	last block for CTS.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* checksum.c (krb5_dk_make_checksum, krb5_marc_dk_make_checksum):
+	Use new numeric fields for key/bolck sizes instead of calling
+	functions.
+	* derive.c (krb5_derive_key, krb5_derive_random): Likewise.
+	* dk_decrypt.c (krb5_dk_decrypt_maybe_trunc_hmac,
+	krb5_marc_dk_decrypt): Likewise.
+	* dk_encrypt.c (krb5_dk_encrypt_length, krb5_dk_encrypt,
+	krb5int_aes_encrypt_length, trunc_hmac, krb5int_aes_dk_encrypt,
+	krb5_marc_dk_encrypt_length, krb5_mark_dk_encrypt): Likewise.
+	* stringtokey.c (krb5int_dk_string_to_key): Likewise.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-04-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* dk_encrypt.c (krb5int_aes_dk_encrypt): Set output length
+	properly.
+
+2003-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* dk_decrypt.c (krb5_dk_decrypt_maybe_trunc_hmac): Renamed from
+	krb5_dk_decrypt, made static, added extra HMACSIZE argument to
+	indicate size of HMAC.  Cast byte values to char to silence
+	compiler warning.
+	(krb5_dk_decrypt): Call it.
+	(krb5int_aes_dk_decrypt): New function.
+	* dk_encrypt.c (krb5_dk_encrypt): Cast byte values to char to
+	silence compiler warning.
+	(krb5int_aes_encrypt_length, trunc_hmac, krb5int_aes_dk_encrypt):
+	New functions.
+	* dk.h (krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt,
+	krb5int_aes_dk_decrypt): Declare.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* stringtokey.c (krb5int_dk_string_to_key): Renamed from
+	krb5_... and added s2k-params argument.
+	* dk.h: Updated.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* dk.h: Make prototypes unconditional.
+
+2001-06-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* derive.c: Include etypes.h.
+	(krb5_derive_random, krb5_random2key): New functions.
+
+	* checksum.c (krb5_dk_make_checksum): Cast 0x99 to char explicitly
+	to silence warnings.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* checksum.c (krb5_dk_make_checksum): Add casts when mixing
+	pointers with different target signedness.
+	* dk_decrypt.c (krb5_dk_decrypt): Likewise.
+	* stringtokey.c (krb5_dk_string_to_key): Likewise.
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* checksum.c, derive.c, dk.h, dk_decrypt.c, dk_encrypt.c,
+	stringtokey.c: Use const instead of krb5_const.
+
+2001-01-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* stringtokey.c (kerberos): Now const.
+	(krb5_dk_string_to_key): Cast it to non-const.
+
+2000-06-03  Tom Yu  <tlyu@mit.edu>
+
+	* dk_encrypt.c (krb5_dk_encrypt, krb5_marc_dk_encrypt): Chain
+	ivecs.
+	
+	* dk_decrypt.c (krb5_dk_decrypt, krb5_marc_dk_decrypt): Chain
+	ivecs.
+
+2000-04-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* derive.c (krb5_derive_key): If memory allocation fails, release
+	other allocated blocks before returning, instead of trying to
+	release them after returning.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* checksum.c (krb5_dk_make_checksum): enc_providers are now
+	const.  Modify if(a=b) assignment/test constructs to silence gcc
+	warnings.
+	* dk_decrypt.c (krb5_dk_decrypt, krb5_marc_dk_decrypt): Ditto.
+	* dk_encrypt.c (krb5_dk_encrypt, krb5_marc_dk_encrypt): Ditto.
+	* stringtokey.c (krb5_dk_string_to_key): Ditto.  Include dk.h.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-06-28  Tom Yu  <tlyu@mit.edu>
+
+	* dk_encrypt.c (krb5_marc_dk_encrypt): Call
+	krb5_marc_dk_encrypt_length() instead of krb5_dk_encrypt_length()
+	to prevent blocksize errors.
+
+Mon May 10 15:16:34 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Tue Jan  5 00:09:13 1999  Tom Yu  <tlyu@mit.edu>
+
+	* dk.h: Add prototypes for krb5_marc_dk_*.
+
+	* dk_encrypt.c (krb5_marc_dk_encrypt): Add compat for 32-bit
+	length coded ciphertext.
+
+	* dk_decrypt.c (krb5_marc_dk_decrypt): Add compat for 32-bit
+	length coded ciphertext.
+
+	* checksum.c: Add compat for 32-bit length included checksum.
+	Note that nothing uses this at the moment, and probably
+	shouldn't.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
diff --git a/mechglue/src/lib/crypto/dk/Makefile.in b/mechglue/src/lib/crypto/dk/Makefile.in
new file mode 100644
index 000000000..84027362d
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/Makefile.in
@@ -0,0 +1,97 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/dk
+mydir=dk
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=dk
+##DOS##OBJFILE=..\$(OUTPRE)dk.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS=\
+	checksum.o	\
+	dk_decrypt.o	\
+	dk_encrypt.o	\
+	derive.o	\
+	dk_prf.o  \
+	stringtokey.o
+
+OBJS=\
+	$(OUTPRE)checksum.$(OBJEXT)	\
+	$(OUTPRE)dk_decrypt.$(OBJEXT)	\
+	$(OUTPRE)dk_encrypt.$(OBJEXT)	\
+	$(OUTPRE)derive.$(OBJEXT)	\
+	$(OUTPRE)dk_prf.$(OBJEXT) \
+	$(OUTPRE)stringtokey.$(OBJEXT)
+
+SRCS=\
+	$(srcdir)/checksum.c	\
+	$(srcdir)/dk_decrypt.c	\
+	$(srcdir)/dk_encrypt.c	\
+	$(srcdir)/dk_prf.c \
+	$(srcdir)/derive.c	\
+	$(srcdir)/stringtokey.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+checksum.so checksum.po $(OUTPRE)checksum.$(OBJEXT): \
+  checksum.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../etypes.h dk.h
+dk_decrypt.so dk_decrypt.po $(OUTPRE)dk_decrypt.$(OBJEXT): \
+  dk_decrypt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  dk.h
+dk_encrypt.so dk_encrypt.po $(OUTPRE)dk_encrypt.$(OBJEXT): \
+  dk_encrypt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  dk.h
+dk_prf.so dk_prf.po $(OUTPRE)dk_prf.$(OBJEXT): dk_prf.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  dk.h
+derive.so derive.po $(OUTPRE)derive.$(OBJEXT): derive.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  dk.h
+stringtokey.so stringtokey.po $(OUTPRE)stringtokey.$(OBJEXT): \
+  stringtokey.c dk.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
diff --git a/mechglue/src/lib/crypto/dk/checksum.c b/mechglue/src/lib/crypto/dk/checksum.c
new file mode 100644
index 000000000..2f30cb740
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/checksum.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include "dk.h"
+
+#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
+
+krb5_error_code
+krb5_dk_make_checksum(const struct krb5_hash_provider *hash,
+		      const krb5_keyblock *key, krb5_keyusage usage,
+		      const krb5_data *input, krb5_data *output)
+{
+    int i;
+    const struct krb5_enc_provider *enc;
+    size_t blocksize, keybytes, keylength;
+    krb5_error_code ret;
+    unsigned char constantdata[K5CLENGTH];
+    krb5_data datain;
+    unsigned char *kcdata;
+    krb5_keyblock kc;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == key->enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    enc = krb5_enctypes_list[i].enc;
+
+    /* allocate and set to-be-derived keys */
+
+    blocksize = enc->block_size;
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    /* key->length will be tested in enc->encrypt
+       output->length will be tested in krb5_hmac */
+
+    if ((kcdata = (unsigned char *) malloc(keylength)) == NULL)
+	return(ENOMEM);
+
+    kc.contents = kcdata;
+    kc.length = keylength;
+
+    /* derive the key */
+ 
+    datain.data = (char *) constantdata;
+    datain.length = K5CLENGTH;
+
+    datain.data[0] = (usage>>24)&0xff;
+    datain.data[1] = (usage>>16)&0xff;
+    datain.data[2] = (usage>>8)&0xff;
+    datain.data[3] = usage&0xff;
+
+    datain.data[4] = (char) 0x99;
+
+    if ((ret = krb5_derive_key(enc, key, &kc, &datain)) != 0)
+	goto cleanup;
+
+    /* hash the data */
+
+    datain = *input;
+
+    if ((ret = krb5_hmac(hash, &kc, 1, &datain, output)) != 0)
+	memset(output->data, 0, output->length);
+
+    /* ret is set correctly by the prior call */
+
+cleanup:
+    memset(kcdata, 0, keylength);
+
+    free(kcdata);
+
+    return(ret);
+}
+
diff --git a/mechglue/src/lib/crypto/dk/derive.c b/mechglue/src/lib/crypto/dk/derive.c
new file mode 100644
index 000000000..81dac4b57
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/derive.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "dk.h"
+
+krb5_error_code
+krb5_derive_key(const struct krb5_enc_provider *enc,
+		const krb5_keyblock *inkey, krb5_keyblock *outkey,
+		const krb5_data *in_constant)
+{
+    size_t blocksize, keybytes, keylength, n;
+    unsigned char *inblockdata, *outblockdata, *rawkey;
+    krb5_data inblock, outblock;
+
+    blocksize = enc->block_size;
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    if ((inkey->length != keylength) ||
+	(outkey->length != keylength))
+	return(KRB5_CRYPTO_INTERNAL);
+
+    /* allocate and set up buffers */
+
+    if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL)
+	return(ENOMEM);
+
+    if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) {
+	free(inblockdata);
+	return(ENOMEM);
+    }
+
+    if ((rawkey = (unsigned char *) malloc(keybytes)) == NULL) {
+	free(outblockdata);
+	free(inblockdata);
+	return(ENOMEM);
+    }
+
+    inblock.data = inblockdata;
+    inblock.length = blocksize;
+
+    outblock.data = outblockdata;
+    outblock.length = blocksize;
+
+    /* initialize the input block */
+
+    if (in_constant->length == inblock.length) {
+	memcpy(inblock.data, in_constant->data, inblock.length);
+    } else {
+	krb5_nfold(in_constant->length*8, in_constant->data,
+		   inblock.length*8, inblock.data);
+    }
+
+    /* loop encrypting the blocks until enough key bytes are generated */
+
+    n = 0;
+    while (n < keybytes) {
+	(*(enc->encrypt))(inkey, 0, &inblock, &outblock);
+
+	if ((keybytes - n) <= outblock.length) {
+	    memcpy(rawkey+n, outblock.data, (keybytes - n));
+	    break;
+	}
+
+	memcpy(rawkey+n, outblock.data, outblock.length);
+	memcpy(inblock.data, outblock.data, outblock.length);
+	n += outblock.length;
+    }
+
+    /* postprocess the key */
+
+    inblock.data = rawkey;
+    inblock.length = keybytes;
+
+    (*(enc->make_key))(&inblock, outkey);
+
+    /* clean memory, free resources and exit */
+
+    memset(inblockdata, 0, blocksize);
+    memset(outblockdata, 0, blocksize);
+    memset(rawkey, 0, keybytes);
+
+    free(rawkey);
+    free(outblockdata);
+    free(inblockdata);
+
+    return(0);
+}
+
+
+krb5_error_code
+krb5_derive_random(const struct krb5_enc_provider *enc,
+		   const krb5_keyblock *inkey, krb5_data *outrnd,
+		   const krb5_data *in_constant)
+{
+    size_t blocksize, keybytes, keylength, n;
+    unsigned char *inblockdata, *outblockdata, *rawkey;
+    krb5_data inblock, outblock;
+
+    blocksize = enc->block_size;
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    if ((inkey->length != keylength) ||
+	(outrnd->length != keybytes))
+	return(KRB5_CRYPTO_INTERNAL);
+
+    /* allocate and set up buffers */
+
+    if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL)
+	return(ENOMEM);
+
+    if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) {
+	free(inblockdata);
+	return(ENOMEM);
+    }
+
+    if ((rawkey = (unsigned char *) malloc(keybytes)) == NULL) {
+	free(outblockdata);
+	free(inblockdata);
+	return(ENOMEM);
+    }
+
+    inblock.data = inblockdata;
+    inblock.length = blocksize;
+
+    outblock.data = outblockdata;
+    outblock.length = blocksize;
+
+    /* initialize the input block */
+
+    if (in_constant->length == inblock.length) {
+	memcpy(inblock.data, in_constant->data, inblock.length);
+    } else {
+	krb5_nfold(in_constant->length*8, in_constant->data,
+		   inblock.length*8, inblock.data);
+    }
+
+    /* loop encrypting the blocks until enough key bytes are generated */
+
+    n = 0;
+    while (n < keybytes) {
+	(*(enc->encrypt))(inkey, 0, &inblock, &outblock);
+
+	if ((keybytes - n) <= outblock.length) {
+	    memcpy(rawkey+n, outblock.data, (keybytes - n));
+	    break;
+	}
+
+	memcpy(rawkey+n, outblock.data, outblock.length);
+	memcpy(inblock.data, outblock.data, outblock.length);
+	n += outblock.length;
+    }
+
+    /* postprocess the key */
+
+    memcpy (outrnd->data, rawkey, keybytes);
+
+    /* clean memory, free resources and exit */
+
+    memset(inblockdata, 0, blocksize);
+    memset(outblockdata, 0, blocksize);
+    memset(rawkey, 0, keybytes);
+
+    free(rawkey);
+    free(outblockdata);
+    free(inblockdata);
+
+    return(0);
+}
+
+#if 0
+#include "etypes.h"
+void
+krb5_random2key (krb5_enctype enctype, krb5_data *inblock,
+		 krb5_keyblock *outkey)
+{
+    int i;
+    const struct krb5_enc_provider *enc;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	abort ();
+
+    enc = krb5_enctypes_list[i].enc;
+
+    enc->make_key (inblock, outkey);
+}
+#endif
diff --git a/mechglue/src/lib/crypto/dk/dk.h b/mechglue/src/lib/crypto/dk/dk.h
new file mode 100644
index 000000000..47bda6ebf
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/dk.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+void krb5_dk_encrypt_length
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		size_t input, size_t *length);
+
+krb5_error_code krb5_dk_encrypt
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec,
+		const krb5_data *input, krb5_data *output);
+
+void krb5int_aes_encrypt_length
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		size_t input, size_t *length);
+
+krb5_error_code krb5int_aes_dk_encrypt
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec,
+		const krb5_data *input, krb5_data *output);
+
+krb5_error_code krb5_dk_decrypt
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec, const krb5_data *input,
+		krb5_data *arg_output);
+
+krb5_error_code krb5int_aes_dk_decrypt
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec, const krb5_data *input,
+		krb5_data *arg_output);
+
+krb5_error_code krb5int_dk_string_to_key
+(const struct krb5_enc_provider *enc, 
+		const krb5_data *string, const krb5_data *salt,
+		const krb5_data *params, krb5_keyblock *key);
+
+krb5_error_code 
+krb5int_dk_prf(const struct krb5_enc_provider *enc,
+	       const struct krb5_hash_provider *hash,
+	       const krb5_keyblock *key, const krb5_data *in, krb5_data *out);
+
+krb5_error_code krb5_derive_key
+(const struct krb5_enc_provider *enc,
+		const krb5_keyblock *inkey,
+		krb5_keyblock *outkey, const krb5_data *in_constant);
+
+krb5_error_code krb5_dk_make_checksum
+(const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *input, krb5_data *output);
+
+krb5_error_code
+krb5_derive_random(const struct krb5_enc_provider *enc,
+		   const krb5_keyblock *inkey, krb5_data *outrnd,
+		   const krb5_data *in_constant);
diff --git a/mechglue/src/lib/crypto/dk/dk_decrypt.c b/mechglue/src/lib/crypto/dk/dk_decrypt.c
new file mode 100644
index 000000000..c4397382a
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/dk_decrypt.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "dk.h"
+
+#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
+
+static krb5_error_code
+krb5_dk_decrypt_maybe_trunc_hmac(const struct krb5_enc_provider *enc,
+				 const struct krb5_hash_provider *hash,
+				 const krb5_keyblock *key,
+				 krb5_keyusage usage,
+				 const krb5_data *ivec,
+				 const krb5_data *input,
+				 krb5_data *output,
+				 size_t hmacsize,
+				 int ivec_mode);
+
+krb5_error_code
+krb5_dk_decrypt(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec, const krb5_data *input,
+		krb5_data *output)
+{
+    return krb5_dk_decrypt_maybe_trunc_hmac(enc, hash, key, usage,
+					    ivec, input, output, 0, 0);
+}
+
+krb5_error_code
+krb5int_aes_dk_decrypt(const struct krb5_enc_provider *enc,
+		       const struct krb5_hash_provider *hash,
+		       const krb5_keyblock *key, krb5_keyusage usage,
+		       const krb5_data *ivec, const krb5_data *input,
+		       krb5_data *output)
+{
+    return krb5_dk_decrypt_maybe_trunc_hmac(enc, hash, key, usage,
+					    ivec, input, output, 96 / 8, 1);
+}
+
+static krb5_error_code
+krb5_dk_decrypt_maybe_trunc_hmac(const struct krb5_enc_provider *enc,
+				 const struct krb5_hash_provider *hash,
+				 const krb5_keyblock *key, krb5_keyusage usage,
+				 const krb5_data *ivec, const krb5_data *input,
+				 krb5_data *output, size_t hmacsize,
+				 int ivec_mode)
+{
+    krb5_error_code ret;
+    size_t hashsize, blocksize, keybytes, keylength, enclen, plainlen;
+    unsigned char *plaindata, *kedata, *kidata, *cksum, *cn;
+    krb5_keyblock ke, ki;
+    krb5_data d1, d2;
+    unsigned char constantdata[K5CLENGTH];
+
+    /* allocate and set up ciphertext and to-be-derived keys */
+
+    hashsize = hash->hashsize;
+    blocksize = enc->block_size;
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    if (hmacsize == 0)
+	hmacsize = hashsize;
+    else if (hmacsize > hashsize)
+	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
+
+    enclen = input->length - hmacsize;
+
+    if ((kedata = (unsigned char *) malloc(keylength)) == NULL)
+	return(ENOMEM);
+    if ((kidata = (unsigned char *) malloc(keylength)) == NULL) {
+	free(kedata);
+	return(ENOMEM);
+    }
+    if ((plaindata = (unsigned char *) malloc(enclen)) == NULL) {
+	free(kidata);
+	free(kedata);
+	return(ENOMEM);
+    }
+    if ((cksum = (unsigned char *) malloc(hashsize)) == NULL) {
+	free(plaindata);
+	free(kidata);
+	free(kedata);
+	return(ENOMEM);
+    }
+
+    ke.contents = kedata;
+    ke.length = keylength;
+    ki.contents = kidata;
+    ki.length = keylength;
+
+    /* derive the keys */
+
+    d1.data = (char *) constantdata;
+    d1.length = K5CLENGTH;
+
+    d1.data[0] = (usage>>24)&0xff;
+    d1.data[1] = (usage>>16)&0xff;
+    d1.data[2] = (usage>>8)&0xff;
+    d1.data[3] = usage&0xff;
+
+    d1.data[4] = (char) 0xAA;
+
+    if ((ret = krb5_derive_key(enc, key, &ke, &d1)) != 0)
+	goto cleanup;
+
+    d1.data[4] = 0x55;
+
+    if ((ret = krb5_derive_key(enc, key, &ki, &d1)) != 0)
+	goto cleanup;
+
+    /* decrypt the ciphertext */
+
+    d1.length = enclen;
+    d1.data = input->data;
+
+    d2.length = enclen;
+    d2.data = (char *) plaindata;
+
+    if ((ret = ((*(enc->decrypt))(&ke, ivec, &d1, &d2))) != 0)
+	goto cleanup;
+
+    if (ivec != NULL && ivec->length == blocksize) {
+	if (ivec_mode == 0)
+	    cn = (unsigned char *) d1.data + d1.length - blocksize;
+	else if (ivec_mode == 1) {
+	    int nblocks = (d1.length + blocksize - 1) / blocksize;
+	    cn = d1.data + blocksize * (nblocks - 2);
+	} else
+	    abort();
+    } else
+	cn = NULL;
+
+    /* verify the hash */
+
+    d1.length = hashsize;
+    d1.data = (char *) cksum;
+
+    if ((ret = krb5_hmac(hash, &ki, 1, &d2, &d1)) != 0)
+	goto cleanup;
+
+    if (memcmp(cksum, input->data+enclen, hmacsize) != 0) {
+	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+	goto cleanup;
+    }
+
+    /* because this encoding isn't self-describing wrt length, the
+       best we can do here is to compute the length minus the
+       confounder. */
+
+    plainlen = enclen - blocksize;
+
+    if (output->length < plainlen)
+	return(KRB5_BAD_MSIZE);
+
+    output->length = plainlen;
+
+    memcpy(output->data, d2.data+blocksize, output->length);
+
+    if (cn != NULL)
+	memcpy(ivec->data, cn, blocksize);
+
+    ret = 0;
+
+cleanup:
+    memset(kedata, 0, keylength);
+    memset(kidata, 0, keylength);
+    memset(plaindata, 0, enclen);
+    memset(cksum, 0, hashsize);
+
+    free(cksum);
+    free(plaindata);
+    free(kidata);
+    free(kedata);
+
+    return(ret);
+}
+
diff --git a/mechglue/src/lib/crypto/dk/dk_encrypt.c b/mechglue/src/lib/crypto/dk/dk_encrypt.c
new file mode 100644
index 000000000..2431e61c8
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/dk_encrypt.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "dk.h"
+
+#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
+
+/* the spec says that the confounder size and padding are specific to
+   the encryption algorithm.  This code (dk_encrypt_length and
+   dk_encrypt) assume the confounder is always the blocksize, and the
+   padding is always zero bytes up to the blocksize.  If these
+   assumptions ever fails, the keytype table should be extended to
+   include these bits of info. */
+
+void
+krb5_dk_encrypt_length(const struct krb5_enc_provider *enc,
+		       const struct krb5_hash_provider *hash,
+		       size_t inputlen, size_t *length)
+{
+    size_t blocksize, hashsize;
+
+    blocksize = enc->block_size;
+    hashsize = hash->hashsize;
+    *length = krb5_roundup(blocksize+inputlen, blocksize) + hashsize;
+}
+
+krb5_error_code
+krb5_dk_encrypt(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec, const krb5_data *input,
+		krb5_data *output)
+{
+    size_t blocksize, keybytes, keylength, plainlen, enclen;
+    krb5_error_code ret;
+    unsigned char constantdata[K5CLENGTH];
+    krb5_data d1, d2;
+    unsigned char *plaintext, *kedata, *kidata, *cn;
+    krb5_keyblock ke, ki;
+
+    /* allocate and set up plaintext and to-be-derived keys */
+
+    blocksize = enc->block_size;
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+    plainlen = krb5_roundup(blocksize+input->length, blocksize);
+
+    krb5_dk_encrypt_length(enc, hash, input->length, &enclen);
+
+    /* key->length, ivec will be tested in enc->encrypt */
+
+    if (output->length < enclen)
+	return(KRB5_BAD_MSIZE);
+
+    if ((kedata = (unsigned char *) malloc(keylength)) == NULL)
+	return(ENOMEM);
+    if ((kidata = (unsigned char *) malloc(keylength)) == NULL) {
+	free(kedata);
+	return(ENOMEM);
+    }
+    if ((plaintext = (unsigned char *) malloc(plainlen)) == NULL) {
+	free(kidata);
+	free(kedata);
+	return(ENOMEM);
+    }
+
+    ke.contents = kedata;
+    ke.length = keylength;
+    ki.contents = kidata;
+    ki.length = keylength;
+
+    /* derive the keys */
+
+    d1.data = constantdata;
+    d1.length = K5CLENGTH;
+
+    d1.data[0] = (usage>>24)&0xff;
+    d1.data[1] = (usage>>16)&0xff;
+    d1.data[2] = (usage>>8)&0xff;
+    d1.data[3] = usage&0xff;
+
+    d1.data[4] = (char) 0xAA;
+
+    if ((ret = krb5_derive_key(enc, key, &ke, &d1)))
+	goto cleanup;
+
+    d1.data[4] = 0x55;
+
+    if ((ret = krb5_derive_key(enc, key, &ki, &d1)))
+	goto cleanup;
+
+    /* put together the plaintext */
+
+    d1.length = blocksize;
+    d1.data = plaintext;
+
+    if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &d1)))
+	goto cleanup;
+
+    memcpy(plaintext+blocksize, input->data, input->length);
+
+    memset(plaintext+blocksize+input->length, 0,
+	   plainlen - (blocksize+input->length));
+
+    /* encrypt the plaintext */
+
+    d1.length = plainlen;
+    d1.data = plaintext;
+
+    d2.length = plainlen;
+    d2.data = output->data;
+
+    if ((ret = ((*(enc->encrypt))(&ke, ivec, &d1, &d2))))
+	goto cleanup;
+
+    if (ivec != NULL && ivec->length == blocksize)
+	cn = d2.data + d2.length - blocksize;
+    else
+	cn = NULL;
+
+    /* hash the plaintext */
+
+    d2.length = enclen - plainlen;
+    d2.data = output->data+plainlen;
+
+    output->length = enclen;
+
+    if ((ret = krb5_hmac(hash, &ki, 1, &d1, &d2))) {
+	memset(d2.data, 0, d2.length);
+	goto cleanup;
+    }
+
+    /* update ivec */
+    if (cn != NULL)
+	memcpy(ivec->data, cn, blocksize);
+
+    /* ret is set correctly by the prior call */
+
+cleanup:
+    memset(kedata, 0, keylength);
+    memset(kidata, 0, keylength);
+    memset(plaintext, 0, plainlen);
+
+    free(plaintext);
+    free(kidata);
+    free(kedata);
+
+    return(ret);
+}
+
+/* Not necessarily "AES", per se, but "a CBC+CTS mode block cipher
+   with a 96-bit truncated HMAC".  */
+void
+krb5int_aes_encrypt_length(const struct krb5_enc_provider *enc,
+			   const struct krb5_hash_provider *hash,
+			   size_t inputlen, size_t *length)
+{
+    size_t blocksize, hashsize;
+
+    blocksize = enc->block_size;
+    hashsize = 96 / 8;
+
+    /* No roundup, since CTS requires no padding once we've hit the
+       block size.  */
+    *length = blocksize+inputlen + hashsize;
+}
+
+static krb5_error_code
+trunc_hmac (const struct krb5_hash_provider *hash,
+	    const krb5_keyblock *ki, int num,
+	    const krb5_data *input, const krb5_data *output)
+{
+    size_t hashsize;
+    krb5_data tmp;
+    krb5_error_code ret;
+
+    hashsize = hash->hashsize;
+    if (hashsize < output->length)
+	return KRB5_CRYPTO_INTERNAL;
+    tmp.length = hashsize;
+    tmp.data = malloc(hashsize);
+    if (tmp.data == NULL)
+	return errno;
+    ret = krb5_hmac(hash, ki, num, input, &tmp);
+    if (ret == 0)
+	memcpy(output->data, tmp.data, output->length);
+    memset(tmp.data, 0, hashsize);
+    free(tmp.data);
+    return ret;
+}
+
+krb5_error_code
+krb5int_aes_dk_encrypt(const struct krb5_enc_provider *enc,
+		       const struct krb5_hash_provider *hash,
+		       const krb5_keyblock *key, krb5_keyusage usage,
+		       const krb5_data *ivec, const krb5_data *input,
+		       krb5_data *output)
+{
+    size_t blocksize, keybytes, keylength, plainlen, enclen;
+    krb5_error_code ret;
+    unsigned char constantdata[K5CLENGTH];
+    krb5_data d1, d2;
+    unsigned char *plaintext, *kedata, *kidata, *cn;
+    krb5_keyblock ke, ki;
+
+    /* allocate and set up plaintext and to-be-derived keys */
+
+    blocksize = enc->block_size;
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+    plainlen = blocksize+input->length;
+
+    krb5int_aes_encrypt_length(enc, hash, input->length, &enclen);
+
+    /* key->length, ivec will be tested in enc->encrypt */
+
+    if (output->length < enclen)
+	return(KRB5_BAD_MSIZE);
+
+    if ((kedata = (unsigned char *) malloc(keylength)) == NULL)
+	return(ENOMEM);
+    if ((kidata = (unsigned char *) malloc(keylength)) == NULL) {
+	free(kedata);
+	return(ENOMEM);
+    }
+    if ((plaintext = (unsigned char *) malloc(plainlen)) == NULL) {
+	free(kidata);
+	free(kedata);
+	return(ENOMEM);
+    }
+
+    ke.contents = kedata;
+    ke.length = keylength;
+    ki.contents = kidata;
+    ki.length = keylength;
+
+    /* derive the keys */
+
+    d1.data = constantdata;
+    d1.length = K5CLENGTH;
+
+    d1.data[0] = (usage>>24)&0xff;
+    d1.data[1] = (usage>>16)&0xff;
+    d1.data[2] = (usage>>8)&0xff;
+    d1.data[3] = usage&0xff;
+
+    d1.data[4] = (char) 0xAA;
+
+    if ((ret = krb5_derive_key(enc, key, &ke, &d1)))
+	goto cleanup;
+
+    d1.data[4] = 0x55;
+
+    if ((ret = krb5_derive_key(enc, key, &ki, &d1)))
+	goto cleanup;
+
+    /* put together the plaintext */
+
+    d1.length = blocksize;
+    d1.data = plaintext;
+
+    if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &d1)))
+	goto cleanup;
+
+    memcpy(plaintext+blocksize, input->data, input->length);
+
+    /* Ciphertext stealing; there should be no more.  */
+    if (plainlen != blocksize + input->length)
+	abort();
+
+    /* encrypt the plaintext */
+
+    d1.length = plainlen;
+    d1.data = plaintext;
+
+    d2.length = plainlen;
+    d2.data = output->data;
+
+    if ((ret = ((*(enc->encrypt))(&ke, ivec, &d1, &d2))))
+	goto cleanup;
+
+    if (ivec != NULL && ivec->length == blocksize) {
+	int nblocks = (d2.length + blocksize - 1) / blocksize;
+	cn = d2.data + blocksize * (nblocks - 2);
+    } else
+	cn = NULL;
+
+    /* hash the plaintext */
+
+    d2.length = enclen - plainlen;
+    d2.data = output->data+plainlen;
+    if (d2.length != 96 / 8)
+	abort();
+
+    if ((ret = trunc_hmac(hash, &ki, 1, &d1, &d2))) {
+	memset(d2.data, 0, d2.length);
+	goto cleanup;
+    }
+
+    output->length = enclen;
+
+    /* update ivec */
+    if (cn != NULL) {
+	memcpy(ivec->data, cn, blocksize);
+#if 0
+	{
+	    int i;
+	    printf("\n%s: output:", __func__);
+	    for (i = 0; i < output->length; i++) {
+		if (i % 16 == 0)
+		    printf("\n%s: ", __func__);
+		printf(" %02x", i[(unsigned char *)output->data]);
+	    }
+	    printf("\n%s: outputIV:", __func__);
+	    for (i = 0; i < ivec->length; i++) {
+		if (i % 16 == 0)
+		    printf("\n%s: ", __func__);
+		printf(" %02x", i[(unsigned char *)ivec->data]);
+	    }
+	    printf("\n");  fflush(stdout);
+	}
+#endif
+    }
+
+    /* ret is set correctly by the prior call */
+
+cleanup:
+    memset(kedata, 0, keylength);
+    memset(kidata, 0, keylength);
+    memset(plaintext, 0, plainlen);
+
+    free(plaintext);
+    free(kidata);
+    free(kedata);
+
+    return(ret);
+}
+
diff --git a/mechglue/src/lib/crypto/dk/dk_prf.c b/mechglue/src/lib/crypto/dk/dk_prf.c
new file mode 100644
index 000000000..ec64caf16
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/dk_prf.c
@@ -0,0 +1,64 @@
+/*
+ * lib/crypto/dk/prf.c
+ *
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * 
+ *
+ * This file contains an implementation of the RFC 3961 PRF for
+ *simplified profile enctypes.
+ */
+
+#include "k5-int.h"
+#include "dk.h"
+
+krb5_error_code
+krb5int_dk_prf (const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key,
+		const krb5_data *in, krb5_data *out)
+{
+  krb5_data tmp;
+  krb5_data prfconst;
+  krb5_keyblock *kp = NULL;
+  krb5_error_code ret = 0;
+  
+  prfconst.data = (char *) "prf";
+  prfconst.length = 3;
+  tmp.length = hash->hashsize;
+  tmp.data = malloc(hash->hashsize);
+  if (tmp.data == NULL)
+    return ENOMEM;
+  hash->hash(1, in, &tmp);
+  tmp.length = (tmp.length/enc->block_size)*enc->block_size; /*truncate to block size*/
+  ret = krb5int_c_init_keyblock(0, key->enctype,
+			   key->length, &kp);
+    if (ret == 0)
+      ret = krb5_derive_key(enc, key, kp, &prfconst);
+  if (ret == 0)
+    ret = enc->encrypt(kp, NULL, &tmp, out);
+      if (kp)
+	krb5int_c_free_keyblock(0, kp);
+  free (tmp.data);
+  return ret;
+}
diff --git a/mechglue/src/lib/crypto/dk/stringtokey.c b/mechglue/src/lib/crypto/dk/stringtokey.c
new file mode 100644
index 000000000..0e54b849f
--- /dev/null
+++ b/mechglue/src/lib/crypto/dk/stringtokey.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "dk.h"
+
+static const unsigned char kerberos[] = "kerberos";
+#define kerberos_len (sizeof(kerberos)-1)
+
+krb5_error_code
+krb5int_dk_string_to_key(const struct krb5_enc_provider *enc,
+			 const krb5_data *string, const krb5_data *salt,
+			 const krb5_data *parms, krb5_keyblock *key)
+{
+    krb5_error_code ret;
+    size_t keybytes, keylength, concatlen;
+    unsigned char *concat, *foldstring, *foldkeydata;
+    krb5_data indata;
+    krb5_keyblock foldkey;
+
+    /* key->length is checked by krb5_derive_key */
+
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    concatlen = string->length+(salt?salt->length:0);
+
+    if ((concat = (unsigned char *) malloc(concatlen)) == NULL)
+	return(ENOMEM);
+    if ((foldstring = (unsigned char *) malloc(keybytes)) == NULL) {
+	free(concat);
+	return(ENOMEM);
+    }
+    if ((foldkeydata = (unsigned char *) malloc(keylength)) == NULL) {
+	free(foldstring);
+	free(concat);
+	return(ENOMEM);
+    }
+
+    /* construct input string ( = string + salt), fold it, make_key it */
+
+    memcpy(concat, string->data, string->length);
+    if (salt)
+	memcpy(concat+string->length, salt->data, salt->length);
+
+    krb5_nfold(concatlen*8, concat, keybytes*8, foldstring);
+
+    indata.length = keybytes;
+    indata.data = (char *) foldstring;
+    foldkey.length = keylength;
+    foldkey.contents = foldkeydata;
+
+    (*(enc->make_key))(&indata, &foldkey);
+
+    /* now derive the key from this one */
+
+    indata.length = kerberos_len;
+    indata.data = (char *) kerberos;
+
+    if ((ret = krb5_derive_key(enc, &foldkey, key, &indata)))
+	memset(key->contents, 0, key->length);
+
+    /* ret is set correctly by the prior call */
+
+    memset(concat, 0, concatlen);
+    memset(foldstring, 0, keybytes);
+    memset(foldkeydata, 0, keylength);
+
+    free(foldkeydata);
+    free(foldstring);
+    free(concat);
+
+    return(ret);
+}
diff --git a/mechglue/src/lib/crypto/enc_provider/ChangeLog b/mechglue/src/lib/crypto/enc_provider/ChangeLog
new file mode 100644
index 000000000..cd6256953
--- /dev/null
+++ b/mechglue/src/lib/crypto/enc_provider/ChangeLog
@@ -0,0 +1,149 @@
+2005-07-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc4.c: Renamed from arcfour.c.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Updated accordingly.
+
+2004-05-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* aes.c (krb5int_aes_encrypt): Signed/unsigned warning fix. 
+
+2004-02-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes.c (krb5int_aes_encrypt, krb5int_aes_decrypt): Copy out value
+	for new IV.
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour.c (arcfour_weakkey1, arcfour_weakkey2,
+	arcfour_weakkeys): Now const.
+
+	* des.c (mit_des_zeroblock): Don't define here.
+	* des3.c (mit_des_zeroblock): Don't define here.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes.c (aes_block_size, aes128_keysize, aes256_keysize):
+	Deleted.
+	(krb5int_enc_aes128, krb5int_enc_aes256): Updated.
+	* arcfour.c (k5_arcfour_blocksize, k5_arcfour_keysize): Deleted.
+	(krb5int_enc_arcfour): Updated.
+	* des.c (k5_des_block_size, k5_des_keysize): Deleted.
+	(krb5int_enc_des): Updated.
+	* des3.c (k5_des3_block_size, k5_des3_keysize): Deleted.
+	(krb5int_enc_des3): Updated.
+
+	* des3.c (validate_and_schedule): Split out from old
+	k5_des3_docrypt.
+	(k5_des3_encrypt, k5_des3_decrypt): Call it, and
+	krb5int_des3_cbc_encrypt or _decrypt, instead of
+	k5_des3_docrypt.  Zap key schedules before returning.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes.c (enc): Replaced function with a macro.
+	(dec): New macro.
+	(krb5int_aes_encrypt): Use enc and dec.  Delete unused variable
+	OFFSET.
+	(krb5int_aes_decrypt): Renamed from k5_aes_dencrypt, implemented
+	decryption, made non-static.
+	(krb5int_enc_aes128, krb5int_enc_aes256): Use new name for
+	krb5int_aes_decrypt.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes.c (krb5int_aes_init_state): Implement.
+	* enc_provider.h (krb5int_enc_aes128, krb5int_enc_aes256):
+	Declare.
+
+2003-02-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* aes.c: New file.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Include it.
+	(LOCALINCLUDE): Add aes source dir.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-02-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* arcfour.c: Use const instead of krb5_const.
+
+2001-11-06  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour.c (k5_arcfour_docrypt): Treat state as an
+	ArcFourCipherState structure; manipulate and initialize as appropriate.
+	(k5_arcfour_init_state): new function
+
+	* arcfour.c des.c des3.c:  Add state functions
+
+2001-10-23  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour.c (endif /* gcc inlines*/): handle inlines in an ansi-compatible manner
+
+	* enc_provider.h: New encryption provider: rc4
+
+2001-10-19  Sam Hartman  <hartmans@mit.edu>
+
+	* arcfour.c: Move prototype for static functions here  rather than in a header file.
+
+2001-05-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* des.c (k5_des_docrypt): Do not use a variable named "encrypt"
+	* des3.c (k5_des3_docrypt): Likewise.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.c (k5_des_docrypt): Add casts when mixing pointer types with
+	different target signedness.
+	* des3.c (k5_des3_docrypt): Likewise.
+
+2001-03-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.c, des3.c, enc_provider.h: Use krb5int_ prefix for internal
+	"provider" structures.
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.c, des3.c: Use const instead of krb5_const.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* des.c, des3.c: Remove unused variables.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.c (mit_des_zeroblock): Now const, and using C default
+	initialization.
+	(krb5_enc_des): Now const.
+	* des3.c (mit_des_zeroblock, krb5_enc_des3): Similar.
+	* enc_provider.h (krb5_enc_des, krb5_enc_des3): Update decls.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:16:54 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
diff --git a/mechglue/src/lib/crypto/enc_provider/Makefile.in b/mechglue/src/lib/crypto/enc_provider/Makefile.in
new file mode 100644
index 000000000..149423c0a
--- /dev/null
+++ b/mechglue/src/lib/crypto/enc_provider/Makefile.in
@@ -0,0 +1,74 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/enc_provider
+mydir=enc_provider
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/../des -I$(srcdir)/../arcfour -I$(srcdir)/../aes
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=enc_provider
+##DOS##OBJFILE=..\$(OUTPRE)enc_prov.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= des.o des3.o rc4.o aes.o
+
+OBJS= \
+	$(OUTPRE)des.$(OBJEXT) \
+	$(OUTPRE)des3.$(OBJEXT) \
+	$(OUTPRE)aes.$(OBJEXT) \
+	$(OUTPRE)rc4.$(OBJEXT)
+
+SRCS= \
+	$(srcdir)/des.c \
+	$(srcdir)/des3.c \
+	$(srcdir)/aes.c \
+	$(srcdir)/rc4.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+des.so des.po $(OUTPRE)des.$(OBJEXT): des.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../des/des_int.h \
+  $(SRCTOP)/include/kerberosIV/des.h enc_provider.h
+des3.so des3.po $(OUTPRE)des3.$(OBJEXT): des3.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../des/des_int.h \
+  $(SRCTOP)/include/kerberosIV/des.h
+aes.so aes.po $(OUTPRE)aes.$(OBJEXT): aes.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h enc_provider.h $(srcdir)/../aes/aes.h \
+  $(srcdir)/../aes/uitypes.h
+rc4.so rc4.po $(OUTPRE)rc4.$(OBJEXT): rc4.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../arcfour/arcfour-int.h \
+  $(srcdir)/../arcfour/arcfour.h enc_provider.h
diff --git a/mechglue/src/lib/crypto/enc_provider/aes.c b/mechglue/src/lib/crypto/enc_provider/aes.c
new file mode 100644
index 000000000..45019692d
--- /dev/null
+++ b/mechglue/src/lib/crypto/enc_provider/aes.c
@@ -0,0 +1,208 @@
+#include "k5-int.h"
+#include "enc_provider.h"
+#include "aes.h"
+
+#if 0
+aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]);
+aes_rval aes_enc_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+aes_rval aes_enc_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+aes_rval aes_dec_key(const unsigned char in_key[], unsigned int klen, aes_ctx cx[1]);
+aes_rval aes_dec_blk(const unsigned char in_blk[], unsigned char out_blk[], const aes_ctx cx[1]);
+#endif
+
+#define CHECK_SIZES 0
+
+#if 0
+static void printd (const char *descr, krb5_data *d) {
+    int i, j;
+    const int r = 16;
+
+    printf("%s:", descr);
+
+    for (i = 0; i < d->length; i += r) {
+	printf("\n  %04x: ", i);
+	for (j = i; j < i + r && j < d->length; j++)
+	    printf(" %02x", 0xff & d->data[j]);
+#ifdef SHOW_TEXT
+	for (; j < i + r; j++)
+	    printf("   ");
+	printf("   ");
+	for (j = i; j < i + r && j < d->length; j++) {
+	    int c = 0xff & d->data[j];
+	    printf("%c", isprint(c) ? c : '.');
+	}
+#endif
+    }
+    printf("\n");
+}
+#endif
+
+#define enc(OUT, IN, CTX) (aes_enc_blk((IN),(OUT),(CTX)) == aes_good ? (void) 0 : abort())
+#define dec(OUT, IN, CTX) (aes_dec_blk((IN),(OUT),(CTX)) == aes_good ? (void) 0 : abort())
+
+static void xorblock(char *out, const char *in)
+{
+    int z;
+    for (z = 0; z < BLOCK_SIZE; z++)
+	out[z] ^= in[z];
+}
+
+krb5_error_code
+krb5int_aes_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+		    const krb5_data *input, krb5_data *output)
+{
+    aes_ctx ctx;
+    unsigned char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+    int nblocks = 0, blockno;
+
+/*    CHECK_SIZES; */
+
+    if (aes_enc_key(key->contents, key->length, &ctx) != aes_good)
+	abort();
+
+    if (ivec)
+	memcpy(tmp, ivec->data, BLOCK_SIZE);
+    else
+	memset(tmp, 0, BLOCK_SIZE);
+
+    nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+    if (nblocks == 1) {
+	/* XXX Used for DK function.  */
+	enc(output->data, input->data, &ctx);
+    } else {
+	unsigned int nleft;
+
+	for (blockno = 0; blockno < nblocks - 2; blockno++) {
+	    xorblock(tmp, input->data + blockno * BLOCK_SIZE);
+	    enc(tmp2, tmp, &ctx);
+	    memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+
+	    /* Set up for next block.  */
+	    memcpy(tmp, tmp2, BLOCK_SIZE);
+	}
+	/* Do final CTS step for last two blocks (the second of which
+	   may or may not be incomplete).  */
+	xorblock(tmp, input->data + (nblocks - 2) * BLOCK_SIZE);
+	enc(tmp2, tmp, &ctx);
+	nleft = input->length - (nblocks - 1) * BLOCK_SIZE;
+	memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2, nleft);
+	memcpy(tmp, tmp2, BLOCK_SIZE);
+
+	memset(tmp3, 0, sizeof(tmp3));
+	memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE, nleft);
+	xorblock(tmp, tmp3);
+	enc(tmp2, tmp, &ctx);
+	memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+	if (ivec)
+	    memcpy(ivec->data, tmp2, BLOCK_SIZE);
+    }
+
+    return 0;
+}
+
+krb5_error_code
+krb5int_aes_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+		    const krb5_data *input, krb5_data *output)
+{
+    aes_ctx ctx;
+    unsigned char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+    int nblocks = 0, blockno;
+
+    CHECK_SIZES;
+
+    if (aes_dec_key(key->contents, key->length, &ctx) != aes_good)
+	abort();
+
+    if (ivec)
+	memcpy(tmp, ivec->data, BLOCK_SIZE);
+    else
+	memset(tmp, 0, BLOCK_SIZE);
+
+    nblocks = (input->length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+    if (nblocks == 1) {
+	if (input->length < BLOCK_SIZE)
+	    abort();
+	dec(output->data, input->data, &ctx);
+    } else {
+
+	for (blockno = 0; blockno < nblocks - 2; blockno++) {
+	    dec(tmp2, input->data + blockno * BLOCK_SIZE, &ctx);
+	    xorblock(tmp2, tmp);
+	    memcpy(output->data + blockno * BLOCK_SIZE, tmp2, BLOCK_SIZE);
+	    memcpy(tmp, input->data + blockno * BLOCK_SIZE, BLOCK_SIZE);
+	}
+	/* Do last two blocks, the second of which (next-to-last block
+	   of plaintext) may be incomplete.  */
+	dec(tmp2, input->data + (nblocks - 2) * BLOCK_SIZE, &ctx);
+	/* Set tmp3 to last ciphertext block, padded.  */
+	memset(tmp3, 0, sizeof(tmp3));
+	memcpy(tmp3, input->data + (nblocks - 1) * BLOCK_SIZE,
+	       input->length - (nblocks - 1) * BLOCK_SIZE);
+	/* Set tmp2 to last (possibly partial) plaintext block, and
+	   save it.  */
+	xorblock(tmp2, tmp3);
+	memcpy(output->data + (nblocks - 1) * BLOCK_SIZE, tmp2,
+	       input->length - (nblocks - 1) * BLOCK_SIZE);
+	/* Maybe keep the trailing part, and copy in the last
+	   ciphertext block.  */
+	memcpy(tmp2, tmp3, input->length - (nblocks - 1) * BLOCK_SIZE);
+	/* Decrypt, to get next to last plaintext block xor previous
+	   ciphertext.  */
+	dec(tmp3, tmp2, &ctx);
+	xorblock(tmp3, tmp);
+	memcpy(output->data + (nblocks - 2) * BLOCK_SIZE, tmp3, BLOCK_SIZE);
+	if (ivec)
+	    memcpy(ivec->data, input->data + (nblocks - 2) * BLOCK_SIZE,
+		   BLOCK_SIZE);
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+k5_aes_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    if (key->length != 16 && key->length != 32)
+	return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != key->length)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+
+    memcpy(key->contents, randombits->data, randombits->length);
+    return(0);
+}
+
+static krb5_error_code
+krb5int_aes_init_state (const krb5_keyblock *key, krb5_keyusage usage,
+			krb5_data *state)
+{
+    state->length = 16;
+    state->data = (void *) malloc(16);
+    if (state->data == NULL)
+	return ENOMEM;
+    memset(state->data, 0, state->length);
+    return 0;
+}
+
+const struct krb5_enc_provider krb5int_enc_aes128 = {
+    16,
+    16, 16,
+    krb5int_aes_encrypt,
+    krb5int_aes_decrypt,
+    k5_aes_make_key,
+    krb5int_aes_init_state,
+    krb5int_default_free_state
+};
+
+const struct krb5_enc_provider krb5int_enc_aes256 = {
+    16,
+    32, 32,
+    krb5int_aes_encrypt,
+    krb5int_aes_decrypt,
+    k5_aes_make_key,
+    krb5int_aes_init_state,
+    krb5int_default_free_state
+};
diff --git a/mechglue/src/lib/crypto/enc_provider/des.c b/mechglue/src/lib/crypto/enc_provider/des.c
new file mode 100644
index 000000000..561e980f8
--- /dev/null
+++ b/mechglue/src/lib/crypto/enc_provider/des.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include "enc_provider.h"
+
+static krb5_error_code
+k5_des_docrypt(const krb5_keyblock *key, const krb5_data *ivec,
+	       const krb5_data *input, krb5_data *output, int enc)
+{
+    mit_des_key_schedule schedule;
+
+    /* key->enctype was checked by the caller */
+
+    if (key->length != 8)
+	return(KRB5_BAD_KEYSIZE);
+    if ((input->length%8) != 0)
+	return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+	return(KRB5_BAD_MSIZE);
+    if (input->length != output->length)
+	return(KRB5_BAD_MSIZE);
+
+    switch (mit_des_key_sched(key->contents, schedule)) {
+    case -1:
+	return(KRB5DES_BAD_KEYPAR);
+    case -2:
+	return(KRB5DES_WEAK_KEY);
+    }
+
+    /* this has a return value, but the code always returns zero */
+
+    mit_des_cbc_encrypt((krb5_pointer) input->data,
+			(krb5_pointer) output->data, input->length,
+			schedule,
+			(ivec
+			 ? (unsigned char *) ivec->data
+			 : (unsigned char *) mit_des_zeroblock),
+			enc);
+
+    memset(schedule, 0, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+	       const krb5_data *input, krb5_data *output)
+{
+    return(k5_des_docrypt(key, ivec, input, output, 1));
+}
+
+static krb5_error_code
+k5_des_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+	       const krb5_data *input, krb5_data *output)
+{
+    return(k5_des_docrypt(key, ivec, input, output, 0));
+}
+
+static krb5_error_code
+k5_des_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    if (key->length != 8)
+	return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != 7)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+    key->length = 8;
+
+    /* take the seven bytes, move them around into the top 7 bits of the
+       8 key bytes, then compute the parity bits */
+
+    memcpy(key->contents, randombits->data, randombits->length);
+    key->contents[7] = (((key->contents[0]&1)<<1) | ((key->contents[1]&1)<<2) |
+			((key->contents[2]&1)<<3) | ((key->contents[3]&1)<<4) |
+			((key->contents[4]&1)<<5) | ((key->contents[5]&1)<<6) |
+			((key->contents[6]&1)<<7));
+
+    mit_des_fixup_key_parity(key->contents);
+
+    return(0);
+}
+
+const struct krb5_enc_provider krb5int_enc_des = {
+    8,
+    7, 8,
+    k5_des_encrypt,
+    k5_des_decrypt,
+    k5_des_make_key,
+    krb5int_des_init_state,
+    krb5int_default_free_state
+};
diff --git a/mechglue/src/lib/crypto/enc_provider/des3.c b/mechglue/src/lib/crypto/enc_provider/des3.c
new file mode 100644
index 000000000..f844747c8
--- /dev/null
+++ b/mechglue/src/lib/crypto/enc_provider/des3.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+
+static krb5_error_code
+validate_and_schedule(const krb5_keyblock *key, const krb5_data *ivec,
+		      const krb5_data *input, const krb5_data *output,
+		      mit_des3_key_schedule *schedule)
+{
+    /* key->enctype was checked by the caller */
+
+    if (key->length != 24)
+	return(KRB5_BAD_KEYSIZE);
+    if ((input->length%8) != 0)
+	return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+	return(KRB5_BAD_MSIZE);
+    if (input->length != output->length)
+	return(KRB5_BAD_MSIZE);
+
+    switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+			       *schedule)) {
+    case -1:
+	return(KRB5DES_BAD_KEYPAR);
+    case -2:
+	return(KRB5DES_WEAK_KEY);
+    }
+    return 0;
+}
+
+static krb5_error_code
+k5_des3_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
+		const krb5_data *input, krb5_data *output)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule(key, ivec, input, output, &schedule);
+    if (err)
+	return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_encrypt((krb5_pointer) input->data,
+			     (krb5_pointer) output->data, input->length,
+			     schedule[0], schedule[1], schedule[2],
+			     ivec?(unsigned char *) ivec->data:(unsigned char *)mit_des_zeroblock);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des3_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
+		const krb5_data *input, krb5_data *output)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule(key, ivec, input, output, &schedule);
+    if (err)
+	return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_decrypt((krb5_pointer) input->data,
+			     (krb5_pointer) output->data, input->length,
+			     schedule[0], schedule[1], schedule[2],
+			     ivec?(unsigned char *) ivec->data:(unsigned char *)mit_des_zeroblock);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des3_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    int i;
+
+    if (key->length != 24)
+	return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != 21)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+    key->length = 24;
+
+    /* take the seven bytes, move them around into the top 7 bits of the
+       8 key bytes, then compute the parity bits.  Do this three times. */
+
+    for (i=0; i<3; i++) {
+	memcpy(key->contents+i*8, randombits->data+i*7, 7);
+	key->contents[i*8+7] = (((key->contents[i*8]&1)<<1) |
+				((key->contents[i*8+1]&1)<<2) |
+				((key->contents[i*8+2]&1)<<3) |
+				((key->contents[i*8+3]&1)<<4) |
+				((key->contents[i*8+4]&1)<<5) |
+				((key->contents[i*8+5]&1)<<6) |
+				((key->contents[i*8+6]&1)<<7));
+
+	mit_des_fixup_key_parity(key->contents+i*8);
+    }
+
+    return(0);
+}
+
+const struct krb5_enc_provider krb5int_enc_des3 = {
+    8,
+    21, 24,
+    k5_des3_encrypt,
+    k5_des3_decrypt,
+    k5_des3_make_key,
+    krb5int_des_init_state,
+    krb5int_default_free_state
+};
diff --git a/mechglue/src/lib/crypto/enc_provider/enc_provider.h b/mechglue/src/lib/crypto/enc_provider/enc_provider.h
new file mode 100644
index 000000000..5754d1a2d
--- /dev/null
+++ b/mechglue/src/lib/crypto/enc_provider/enc_provider.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_enc_provider krb5int_enc_des;
+extern const struct krb5_enc_provider krb5int_enc_des3;
+extern const struct krb5_enc_provider krb5int_enc_arcfour;
+extern const struct krb5_enc_provider krb5int_enc_aes128;
+extern const struct krb5_enc_provider krb5int_enc_aes256;
diff --git a/mechglue/src/lib/crypto/enc_provider/rc4.c b/mechglue/src/lib/crypto/enc_provider/rc4.c
new file mode 100644
index 000000000..685f89a89
--- /dev/null
+++ b/mechglue/src/lib/crypto/enc_provider/rc4.c
@@ -0,0 +1,216 @@
+/* arcfour.c 
+ *
+ * Copyright (c) 2000 by Computer Science Laboratory,
+ *                       Rensselaer Polytechnic Institute
+ *
+ * #include STD_DISCLAIMER
+ */
+
+#include "k5-int.h"
+#include "arcfour-int.h"
+#include "enc_provider.h"
+/* gets the next byte from the PRNG */
+#if ((__GNUC__ >= 2) )
+static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *);
+#else
+static unsigned int k5_arcfour_byte(ArcfourContext *);
+#endif /* gcc inlines*/
+
+/* Initializes the context and sets the key. */
+static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key, 
+		  unsigned int keylen);
+
+/* Encrypts/decrypts data. */
+static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest, 
+		     const unsigned char *src, unsigned int len);
+
+/* Interface layer to kerb5 crypto layer */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *, const krb5_data *,
+		   const krb5_data *, krb5_data *);
+
+/* from a random bitstrem, construct a key */
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *, krb5_keyblock *);
+
+static const unsigned char arcfour_weakkey1[] = {0x00, 0x00, 0xfd};
+static const unsigned char arcfour_weakkey2[] = {0x03, 0xfd, 0xfc};
+static const krb5_data arcfour_weakkeys[] = {
+    {KV5M_DATA, sizeof (arcfour_weakkey1),
+     (char * ) arcfour_weakkey1},
+    {KV5M_DATA, sizeof (arcfour_weakkey2),
+     (char * ) arcfour_weakkey2},
+    {KV5M_DATA, 0, 0}
+};
+
+/*xxx we really should check for c9x here and use inline on 
+ * more than just gcc. */
+#if ((__GNUC__ >= 2) )
+static __inline__ unsigned int k5_arcfour_byte(ArcfourContext * ctx)
+#else
+static unsigned int k5_arcfour_byte(ArcfourContext * ctx)
+#endif /* gcc inlines*/
+{
+  unsigned int x;
+  unsigned int y;
+  unsigned int sx, sy;
+  unsigned char *state;
+
+  state = ctx->state;
+  x = (ctx->x + 1) & 0xff;
+  sx = state[x];
+  y = (sx + ctx->y) & 0xff;
+  sy = state[y];
+  ctx->x = x;
+  ctx->y = y;
+  state[y] = sx;
+  state[x] = sy;
+  return state[(sx + sy) & 0xff];
+}
+
+static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest, 
+		     const unsigned char *src, unsigned int len)
+{
+  unsigned int i;
+  for (i = 0; i < len; i++)
+    dest[i] = src[i] ^ k5_arcfour_byte(ctx);
+}
+
+
+static krb5_error_code
+k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key, 
+		  unsigned int key_len)
+{
+  unsigned int t, u;
+  unsigned int keyindex;
+  unsigned int stateindex;
+  unsigned char* state;
+  unsigned int counter;
+
+  if (key_len != 16)
+    return KRB5_BAD_MSIZE;     /*this is probably not the correct error code
+				 to return */
+  for(counter=0;arcfour_weakkeys[counter].length >0; counter++)
+    if (memcmp(key, arcfour_weakkeys[counter].data,
+	       arcfour_weakkeys[counter].length) == 0)
+      return KRB5DES_WEAK_KEY; /* most certainly not the correct error */
+
+  state = &ctx->state[0];
+  ctx->x = 0;
+  ctx->y = 0;
+  for (counter = 0; counter < 256; counter++)
+    state[counter] = counter;
+  keyindex = 0;
+  stateindex = 0;
+  for (counter = 0; counter < 256; counter++)
+    {
+      t = state[counter];
+      stateindex = (stateindex + key[keyindex] + t) & 0xff;
+      u = state[stateindex];
+      state[stateindex] = t;
+      state[counter] = u;
+      if (++keyindex >= key_len)
+	keyindex = 0;
+    }
+  return 0;
+}
+
+
+/* The workhorse of the arcfour system, this impliments the cipher */
+static krb5_error_code
+k5_arcfour_docrypt(const krb5_keyblock *key, const krb5_data *state,
+	       const krb5_data *input, krb5_data *output)
+{
+  ArcfourContext *arcfour_ctx;
+  ArcFourCipherState *cipher_state;
+  int ret;
+
+  if (key->length != 16)
+    return(KRB5_BAD_KEYSIZE);
+  if (state && (state->length != sizeof (ArcFourCipherState)))
+    return(KRB5_BAD_MSIZE);
+  if (input->length != output->length)
+    return(KRB5_BAD_MSIZE);
+
+  if (state) {
+    cipher_state = (ArcFourCipherState *) state->data;
+    arcfour_ctx=&cipher_state->ctx;
+    if (cipher_state->initialized == 0) {
+      if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) {
+	return ret;
+      }
+      cipher_state->initialized = 1;
+    }
+    k5_arcfour_crypt(arcfour_ctx, (unsigned char *) output->data, (const unsigned char *) input->data, input->length);
+  }
+  else {
+    arcfour_ctx=malloc(sizeof (ArcfourContext));
+    if (arcfour_ctx == NULL)
+      return ENOMEM;
+    if ((ret=k5_arcfour_init(arcfour_ctx, key->contents, key->length))) {
+      free(arcfour_ctx);
+      return (ret);
+    }
+    k5_arcfour_crypt(arcfour_ctx, (unsigned char * ) output->data,
+		     (const unsigned char * ) input->data, input->length);
+    memset(arcfour_ctx, 0, sizeof (ArcfourContext));
+    free(arcfour_ctx);
+  }
+  
+  return 0;
+}
+
+static krb5_error_code
+k5_arcfour_make_key(const krb5_data *randombits, krb5_keyblock *key)
+{
+    if (key->length != 16)
+	return(KRB5_BAD_KEYSIZE);
+    if (randombits->length != 16)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    key->magic = KV5M_KEYBLOCK;
+    key->length = 16;
+
+    memcpy(key->contents, randombits->data, randombits->length);
+
+    return(0);
+}
+
+static krb5_error_code
+k5_arcfour_init_state (const krb5_keyblock *key,
+		       krb5_keyusage keyusage, krb5_data *new_state)
+{
+  /* Note that we can't actually set up the state here  because the key
+   * will change  between now and when encrypt is called
+   * because  it is data dependent.  Yeah, this has strange
+   * properties. --SDH
+   */
+  new_state->length = sizeof (ArcFourCipherState);
+  new_state->data = malloc (new_state->length);
+  if (new_state->data) {
+    memset (new_state->data, 0 , new_state->length);
+    /* That will set initialized to zero*/
+  }else {
+    return (ENOMEM);
+  }
+  return 0;
+}
+
+/* Since the arcfour cipher is identical going forwards and backwards, 
+   we just call "docrypt" directly
+*/
+const struct krb5_enc_provider krb5int_enc_arcfour = {
+    /* This seems to work... although I am not sure what the
+       implications are in other places in the kerberos library */
+    1,
+    /* Keysize is arbitrary in arcfour, but the constraints of the
+       system, and to attempt to work with the MSFT system forces us
+       to 16byte/128bit.  Since there is no parity in the key, the
+       byte and length are the same.  */
+    16, 16,
+    k5_arcfour_docrypt,
+    k5_arcfour_docrypt,
+    k5_arcfour_make_key,
+    k5_arcfour_init_state, /*xxx not implemented yet*/
+    krb5int_default_free_state
+};
diff --git a/mechglue/src/lib/crypto/encrypt.c b/mechglue/src/lib/crypto/encrypt.c
new file mode 100644
index 000000000..c215dc429
--- /dev/null
+++ b/mechglue/src/lib/crypto/encrypt.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_encrypt(krb5_context context, const krb5_keyblock *key,
+	       krb5_keyusage usage, const krb5_data *ivec,
+	       const krb5_data *input, krb5_enc_data *output)
+{
+    int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == key->enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    output->magic = KV5M_ENC_DATA;
+    output->kvno = 0;
+    output->enctype = key->enctype;
+
+    return((*(krb5_enctypes_list[i].encrypt))
+	   (krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
+	    key, usage, ivec, input, &output->ciphertext));
+}
diff --git a/mechglue/src/lib/crypto/encrypt_length.c b/mechglue/src/lib/crypto/encrypt_length.c
new file mode 100644
index 000000000..71c25e735
--- /dev/null
+++ b/mechglue/src/lib/crypto/encrypt_length.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_encrypt_length(krb5_context context, krb5_enctype enctype,
+		      size_t inputlen, size_t *length)
+{
+    int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    (*(krb5_enctypes_list[i].encrypt_len))
+	(krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
+	 inputlen, length);
+
+    return(0);
+}
diff --git a/mechglue/src/lib/crypto/enctype_compare.c b/mechglue/src/lib/crypto/enctype_compare.c
new file mode 100644
index 000000000..55e827764
--- /dev/null
+++ b/mechglue/src/lib/crypto/enctype_compare.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_enctype_compare(krb5_context context, krb5_enctype e1, krb5_enctype e2,
+		       krb5_boolean *similar)
+{
+    int i, j;
+
+    for (i=0; i<krb5_enctypes_length; i++) 
+	if (krb5_enctypes_list[i].etype == e1)
+	    break;
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    for (j=0; j<krb5_enctypes_length; j++) 
+	if (krb5_enctypes_list[j].etype == e2)
+	    break;
+
+    if (j == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    *similar = 
+	((krb5_enctypes_list[i].enc == krb5_enctypes_list[j].enc) &&
+	 (krb5_enctypes_list[i].str2key == krb5_enctypes_list[j].str2key));
+
+    return(0);
+}
diff --git a/mechglue/src/lib/crypto/enctype_to_string.c b/mechglue/src/lib/crypto/enctype_to_string.c
new file mode 100644
index 000000000..f77dbff1c
--- /dev/null
+++ b/mechglue/src/lib/crypto/enctype_to_string.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_enctype_to_string(krb5_enctype enctype, char *buffer, size_t buflen)
+{
+    int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == enctype) {
+	    if ((strlen(krb5_enctypes_list[i].out_string)+1) > buflen)
+		return(ENOMEM);
+
+	    strcpy(buffer, krb5_enctypes_list[i].out_string);
+	    return(0);
+	}
+    }
+
+    return(EINVAL);
+}
diff --git a/mechglue/src/lib/crypto/etypes.c b/mechglue/src/lib/crypto/etypes.c
new file mode 100644
index 000000000..4273e2826
--- /dev/null
+++ b/mechglue/src/lib/crypto/etypes.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "enc_provider.h"
+#include "hash_provider.h"
+#include "etypes.h"
+#include "old.h"
+#include "raw.h"
+#include "dk.h"
+#include "arcfour.h"
+#include "aes_s2k.h"
+
+/* these will be linear searched.  if they ever get big, a binary
+   search or hash table would be better, which means these would need
+   to be sorted.  An array would be more efficient, but that assumes
+   that the keytypes are all near each other.  I'd rather not make
+   that assumption. */
+
+const struct krb5_keytypes krb5_enctypes_list[] = {
+    { ENCTYPE_DES_CBC_CRC,
+      "des-cbc-crc", "DES cbc mode with CRC-32",
+      &krb5int_enc_des, &krb5int_hash_crc32,
+      8,
+      krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
+      krb5int_des_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_RSA_MD5 },
+    { ENCTYPE_DES_CBC_MD4,
+      "des-cbc-md4", "DES cbc mode with RSA-MD4",
+      &krb5int_enc_des, &krb5int_hash_md4,
+      8,
+      krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
+      krb5int_des_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_RSA_MD4 },
+    { ENCTYPE_DES_CBC_MD5,
+      "des-cbc-md5", "DES cbc mode with RSA-MD5",
+      &krb5int_enc_des, &krb5int_hash_md5,
+      8,
+      krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
+      krb5int_des_string_to_key,
+      NULL, /*PRF*/
+CKSUMTYPE_RSA_MD5 },
+    { ENCTYPE_DES_CBC_MD5,
+      "des", "DES cbc mode with RSA-MD5", /* alias */
+      &krb5int_enc_des, &krb5int_hash_md5,
+      8,
+      krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
+      krb5int_des_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_RSA_MD5 },
+
+    { ENCTYPE_DES_CBC_RAW,
+      "des-cbc-raw", "DES cbc mode raw",
+      &krb5int_enc_des, NULL,
+      8,
+      krb5_raw_encrypt_length, krb5_raw_encrypt, krb5_raw_decrypt,
+      krb5int_des_string_to_key,
+      NULL, /*PRF*/
+      0 },
+    { ENCTYPE_DES3_CBC_RAW,
+      "des3-cbc-raw", "Triple DES cbc mode raw",
+      &krb5int_enc_des3, NULL,
+      8,
+      krb5_raw_encrypt_length, krb5_raw_encrypt, krb5_raw_decrypt,
+      krb5int_dk_string_to_key,
+      NULL, /*PRF*/
+      0 },
+
+    { ENCTYPE_DES3_CBC_SHA1,
+      "des3-cbc-sha1", "Triple DES cbc mode with HMAC/sha1",
+      &krb5int_enc_des3, &krb5int_hash_sha1,
+      8,
+      krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
+      krb5int_dk_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_SHA1_DES3 },
+    { ENCTYPE_DES3_CBC_SHA1,	/* alias */
+      "des3-hmac-sha1", "Triple DES cbc mode with HMAC/sha1",
+      &krb5int_enc_des3, &krb5int_hash_sha1,
+      8,
+      krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
+      krb5int_dk_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_SHA1_DES3 },
+    { ENCTYPE_DES3_CBC_SHA1,	/* alias */
+      "des3-cbc-sha1-kd", "Triple DES cbc mode with HMAC/sha1",
+      &krb5int_enc_des3, &krb5int_hash_sha1,
+      8,
+      krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
+      krb5int_dk_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_SHA1_DES3 },
+
+    { ENCTYPE_DES_HMAC_SHA1,
+      "des-hmac-sha1", "DES with HMAC/sha1",
+      &krb5int_enc_des, &krb5int_hash_sha1,
+      8,
+      krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
+      krb5int_dk_string_to_key,
+      NULL, /*PRF*/
+      0 },
+    { ENCTYPE_ARCFOUR_HMAC, 
+      "arcfour-hmac","ArcFour with HMAC/md5", &krb5int_enc_arcfour,
+      &krb5int_hash_md5,
+      0,
+krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
+      krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+    { ENCTYPE_ARCFOUR_HMAC,  /* alias */
+      "rc4-hmac", "ArcFour with HMAC/md5", &krb5int_enc_arcfour,
+      &krb5int_hash_md5,
+      0,
+      krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
+      krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+    { ENCTYPE_ARCFOUR_HMAC,  /* alias */
+      "arcfour-hmac-md5", "ArcFour with HMAC/md5", &krb5int_enc_arcfour,
+      &krb5int_hash_md5,
+      0,
+      krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
+      krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+    { ENCTYPE_ARCFOUR_HMAC_EXP, 
+      "arcfour-hmac-exp", "Exportable ArcFour with HMAC/md5",
+      &krb5int_enc_arcfour,
+      &krb5int_hash_md5,
+      0,
+      krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
+      krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+    { ENCTYPE_ARCFOUR_HMAC_EXP, /* alias */
+      "rc4-hmac-exp", "Exportable ArcFour with HMAC/md5",
+      &krb5int_enc_arcfour,
+      &krb5int_hash_md5,
+      0,
+      krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
+      krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+    { ENCTYPE_ARCFOUR_HMAC_EXP, /* alias */
+      "arcfour-hmac-md5-exp", "Exportable ArcFour with HMAC/md5",
+      &krb5int_enc_arcfour,
+      &krb5int_hash_md5,
+      0,
+      krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
+      krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
+      NULL, /*PRF*/
+      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+
+    { ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+      "aes128-cts-hmac-sha1-96", "AES-128 CTS mode with 96-bit SHA-1 HMAC",
+      &krb5int_enc_aes128, &krb5int_hash_sha1,
+      16,
+      krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
+      krb5int_aes_string_to_key,
+      krb5int_dk_prf,
+      CKSUMTYPE_HMAC_SHA1_96_AES128 },
+    { ENCTYPE_AES128_CTS_HMAC_SHA1_96, /* alias */
+      "aes128-cts", "AES-128 CTS mode with 96-bit SHA-1 HMAC",
+      &krb5int_enc_aes128, &krb5int_hash_sha1,
+      16,
+      krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
+      krb5int_aes_string_to_key,
+      krb5int_dk_prf,
+      CKSUMTYPE_HMAC_SHA1_96_AES128 },
+    { ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+      "aes256-cts-hmac-sha1-96", "AES-256 CTS mode with 96-bit SHA-1 HMAC",
+      &krb5int_enc_aes256, &krb5int_hash_sha1,
+      16,
+      krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
+      krb5int_aes_string_to_key,
+      krb5int_dk_prf,
+      CKSUMTYPE_HMAC_SHA1_96_AES256 },
+    { ENCTYPE_AES256_CTS_HMAC_SHA1_96, /* alias */
+      "aes256-cts", "AES-256 CTS mode with 96-bit SHA-1 HMAC",
+      &krb5int_enc_aes256, &krb5int_hash_sha1,
+      16,
+      krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
+      krb5int_aes_string_to_key,
+      krb5int_dk_prf,
+      CKSUMTYPE_HMAC_SHA1_96_AES256 },
+};
+
+const int krb5_enctypes_length =
+sizeof(krb5_enctypes_list)/sizeof(struct krb5_keytypes);
diff --git a/mechglue/src/lib/crypto/etypes.h b/mechglue/src/lib/crypto/etypes.h
new file mode 100644
index 000000000..ca94e56ff
--- /dev/null
+++ b/mechglue/src/lib/crypto/etypes.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_keytypes krb5_enctypes_list[];
+extern const int krb5_enctypes_length;
diff --git a/mechglue/src/lib/crypto/hash_provider/ChangeLog b/mechglue/src/lib/crypto/hash_provider/ChangeLog
new file mode 100644
index 000000000..d1fa65733
--- /dev/null
+++ b/mechglue/src/lib/crypto/hash_provider/ChangeLog
@@ -0,0 +1,73 @@
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* hash_crc32.c (k5_crc32_hash_size, k5_crc32_block_size):
+	Deleted.
+	(krb5int_hash_crc32): Updated.
+	* hash_md4.c (k5_md4_hash_size, k5_md4_block_size): Deleted.
+	(krb5int_hash_md4): Updated.
+	* hash_md5.c (k5_md5_hash_size, k5_md5_block_size): Deleted.
+	(krb5int_hash_md5): Updated.
+	* hash_sha1.c (k5_sha1_hash_size, k5_sha1_block_size): Deleted.
+	(krb5int_hash_sha1): Updated.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* hash_md4.c (k5_md4_hash): Cast argument to krb5_MD4Update.
+	* hash_md5.c (k5_md5_hash): Cast argument to krb5_MD5Update.
+
+2001-03-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* hash_crc32.c, hash_md4.c, hash_md5.c, hash_provider.h,
+	hash_sha1.c: Use krb5int_ prefix for internal "provider"
+	structures.
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* hash_crc32.c, hash_md4.c, hash_md5.c, hash_sha1.c: Use const
+	instead of krb5_const.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* hash_sha1.c (k5_sha1_hash): Cast length field in shsUpdate call
+	to int.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* hash_crc32.c (krb5_hash_crc32): Now const.
+	* hash_md4.c (krb5_hash_md4): Now const.
+	* hash_md5.c (krb5_hash_md5): Now const.
+	* hash_sha1.c (krb5_hash_sha1): Now const.
+	* hash_provider.h: Updated decls.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:19:03 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
diff --git a/mechglue/src/lib/crypto/hash_provider/Makefile.in b/mechglue/src/lib/crypto/hash_provider/Makefile.in
new file mode 100644
index 000000000..673489857
--- /dev/null
+++ b/mechglue/src/lib/crypto/hash_provider/Makefile.in
@@ -0,0 +1,69 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/hash_provider
+mydir=hash_provider
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/../crc32 -I$(srcdir)/../md4 \
+	-I$(srcdir)/../md5 -I$(srcdir)/../sha1
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=hash_provider
+##DOS##OBJFILE=..\$(OUTPRE)hash_pro.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= hash_crc32.o hash_md4.o hash_md5.o hash_sha1.o
+
+OBJS= $(OUTPRE)hash_crc32.$(OBJEXT) $(OUTPRE)hash_md4.$(OBJEXT) \
+	$(OUTPRE)hash_md5.$(OBJEXT) $(OUTPRE)hash_sha1.$(OBJEXT)
+
+SRCS= $(srcdir)/hash_crc32.c $(srcdir)/hash_md4.c \
+	$(srcdir)/hash_md5.c $(srcdir)/hash_sha1.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+hash_crc32.so hash_crc32.po $(OUTPRE)hash_crc32.$(OBJEXT): \
+  hash_crc32.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../crc32/crc-32.h hash_provider.h
+hash_md4.so hash_md4.po $(OUTPRE)hash_md4.$(OBJEXT): \
+  hash_md4.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../md4/rsa-md4.h hash_provider.h
+hash_md5.so hash_md5.po $(OUTPRE)hash_md5.$(OBJEXT): \
+  hash_md5.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../md5/rsa-md5.h hash_provider.h
+hash_sha1.so hash_sha1.po $(OUTPRE)hash_sha1.$(OBJEXT): \
+  hash_sha1.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../sha1/shs.h hash_provider.h
diff --git a/mechglue/src/lib/crypto/hash_provider/hash_crc32.c b/mechglue/src/lib/crypto/hash_provider/hash_crc32.c
new file mode 100644
index 000000000..b48b3b363
--- /dev/null
+++ b/mechglue/src/lib/crypto/hash_provider/hash_crc32.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "crc-32.h"
+#include "hash_provider.h"
+
+static krb5_error_code
+k5_crc32_hash(unsigned int icount, const krb5_data *input,
+	      krb5_data *output)
+{
+    unsigned long c, cn;
+    int i;
+    
+    if (output->length != CRC32_CKSUM_LENGTH)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    c = 0;
+    for (i=0; i<icount; i++) {
+	mit_crc32(input[i].data, input[i].length, &cn);
+	c ^= cn;
+    }
+
+    output->data[0] = c&0xff;
+    output->data[1] = (c>>8)&0xff;
+    output->data[2] = (c>>16)&0xff;
+    output->data[3] = (c>>24)&0xff;
+
+    return(0);
+}
+
+const struct krb5_hash_provider krb5int_hash_crc32 = {
+    CRC32_CKSUM_LENGTH,
+    1,
+    k5_crc32_hash
+};
diff --git a/mechglue/src/lib/crypto/hash_provider/hash_md4.c b/mechglue/src/lib/crypto/hash_provider/hash_md4.c
new file mode 100644
index 000000000..97487923b
--- /dev/null
+++ b/mechglue/src/lib/crypto/hash_provider/hash_md4.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "rsa-md4.h"
+#include "hash_provider.h"
+
+static krb5_error_code
+k5_md4_hash(unsigned int icount, const krb5_data *input,
+	    krb5_data *output)
+{
+    krb5_MD4_CTX ctx;
+    int i;
+
+    if (output->length != RSA_MD4_CKSUM_LENGTH)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    krb5_MD4Init(&ctx);
+    for (i=0; i<icount; i++)
+	krb5_MD4Update(&ctx, (unsigned char *) input[i].data, input[i].length);
+    krb5_MD4Final(&ctx);
+
+    memcpy(output->data, ctx.digest, RSA_MD4_CKSUM_LENGTH);
+
+    return(0);
+}
+
+const struct krb5_hash_provider krb5int_hash_md4 = {
+    RSA_MD4_CKSUM_LENGTH,
+    64,
+    k5_md4_hash
+};
diff --git a/mechglue/src/lib/crypto/hash_provider/hash_md5.c b/mechglue/src/lib/crypto/hash_provider/hash_md5.c
new file mode 100644
index 000000000..408729337
--- /dev/null
+++ b/mechglue/src/lib/crypto/hash_provider/hash_md5.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "rsa-md5.h"
+#include "hash_provider.h"
+
+static krb5_error_code
+k5_md5_hash(unsigned int icount, const krb5_data *input,
+	    krb5_data *output)
+{
+    krb5_MD5_CTX ctx;
+    int i;
+
+    if (output->length != RSA_MD5_CKSUM_LENGTH)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    krb5_MD5Init(&ctx);
+    for (i=0; i<icount; i++)
+	krb5_MD5Update(&ctx, (unsigned char *) input[i].data, input[i].length);
+    krb5_MD5Final(&ctx);
+
+    memcpy(output->data, ctx.digest, RSA_MD5_CKSUM_LENGTH);
+
+    return(0);
+}
+
+const struct krb5_hash_provider krb5int_hash_md5 = {
+    RSA_MD5_CKSUM_LENGTH,
+    64,
+    k5_md5_hash
+};
diff --git a/mechglue/src/lib/crypto/hash_provider/hash_provider.h b/mechglue/src/lib/crypto/hash_provider/hash_provider.h
new file mode 100644
index 000000000..4fa46097d
--- /dev/null
+++ b/mechglue/src/lib/crypto/hash_provider/hash_provider.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_hash_provider krb5int_hash_crc32;
+extern const struct krb5_hash_provider krb5int_hash_md4;
+extern const struct krb5_hash_provider krb5int_hash_md5;
+extern const struct krb5_hash_provider krb5int_hash_sha1;
diff --git a/mechglue/src/lib/crypto/hash_provider/hash_sha1.c b/mechglue/src/lib/crypto/hash_provider/hash_sha1.c
new file mode 100644
index 000000000..2ee56ad21
--- /dev/null
+++ b/mechglue/src/lib/crypto/hash_provider/hash_sha1.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "shs.h"
+#include "hash_provider.h"
+
+static krb5_error_code
+k5_sha1_hash(unsigned int icount, const krb5_data *input,
+	     krb5_data *output)
+{
+    SHS_INFO ctx;
+    int i;
+
+    if (output->length != SHS_DIGESTSIZE)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    shsInit(&ctx);
+    for (i=0; i<icount; i++)
+	shsUpdate(&ctx, (unsigned char *) input[i].data, (int) input[i].length);
+    shsFinal(&ctx);
+
+    for (i=0; i<(sizeof(ctx.digest)/sizeof(ctx.digest[0])); i++) {
+	output->data[i*4] = (ctx.digest[i]>>24)&0xff;
+	output->data[i*4+1] = (ctx.digest[i]>>16)&0xff;
+	output->data[i*4+2] = (ctx.digest[i]>>8)&0xff;
+	output->data[i*4+3] = ctx.digest[i]&0xff;
+    }
+
+    return(0);
+}
+
+const struct krb5_hash_provider krb5int_hash_sha1 = {
+    SHS_DIGESTSIZE,
+    SHS_DATASIZE,
+    k5_sha1_hash
+};
diff --git a/mechglue/src/lib/crypto/hmac.c b/mechglue/src/lib/crypto/hmac.c
new file mode 100644
index 000000000..cc46374c5
--- /dev/null
+++ b/mechglue/src/lib/crypto/hmac.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+/*
+ * the HMAC transform looks like:
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ *
+ * where H is a cryptographic hash
+ * K is an n byte key
+ * ipad is the byte 0x36 repeated blocksize times
+ * opad is the byte 0x5c repeated blocksize times
+ * and text is the data being protected
+ */
+
+krb5_error_code
+krb5_hmac(const struct krb5_hash_provider *hash, const krb5_keyblock *key,
+	  unsigned int icount, const krb5_data *input, krb5_data *output)
+{
+    size_t hashsize, blocksize;
+    unsigned char *xorkey, *ihash;
+    int i;
+    krb5_data *hashin, hashout;
+    krb5_error_code ret;
+
+    hashsize = hash->hashsize;
+    blocksize = hash->blocksize;
+
+    if (key->length > blocksize)
+	return(KRB5_CRYPTO_INTERNAL);
+    if (output->length < hashsize)
+	return(KRB5_BAD_MSIZE);
+    /* if this isn't > 0, then there won't be enough space in this
+       array to compute the outer hash */
+    if (icount == 0)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    /* allocate space for the xor key, hash input vector, and inner hash */
+
+    if ((xorkey = (unsigned char *) malloc(blocksize)) == NULL)
+	return(ENOMEM);
+    if ((ihash = (unsigned char *) malloc(hashsize)) == NULL) {
+	free(xorkey);
+	return(ENOMEM);
+    }
+    if ((hashin = (krb5_data *)malloc(sizeof(krb5_data)*(icount+1))) == NULL) {
+	free(ihash);
+	free(xorkey);
+	return(ENOMEM);
+    }
+
+    /* create the inner padded key */
+
+    memset(xorkey, 0x36, blocksize);
+
+    for (i=0; i<key->length; i++)
+	xorkey[i] ^= key->contents[i];
+
+    /* compute the inner hash */
+
+    for (i=0; i<icount; i++) {
+	hashin[0].length = blocksize;
+	hashin[0].data = (char *) xorkey;
+	hashin[i+1] = input[i];
+    }
+
+    hashout.length = hashsize;
+    hashout.data = (char *) ihash;
+
+    if ((ret = ((*(hash->hash))(icount+1, hashin, &hashout))))
+	goto cleanup;
+
+    /* create the outer padded key */
+
+    memset(xorkey, 0x5c, blocksize);
+
+    for (i=0; i<key->length; i++)
+	xorkey[i] ^= key->contents[i];
+
+    /* compute the outer hash */
+
+    hashin[0].length = blocksize;
+    hashin[0].data = (char *) xorkey;
+    hashin[1] = hashout;
+
+    output->length = hashsize;
+
+    if ((ret = ((*(hash->hash))(2, hashin, output))))
+	memset(output->data, 0, output->length);
+
+    /* ret is set correctly by the prior call */
+
+cleanup:
+    memset(xorkey, 0, blocksize);
+    memset(ihash, 0, hashsize);
+
+    free(hashin);
+    free(ihash);
+    free(xorkey);
+
+    return(ret);
+}
diff --git a/mechglue/src/lib/crypto/keyblocks.c b/mechglue/src/lib/crypto/keyblocks.c
new file mode 100644
index 000000000..626443c83
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyblocks.c
@@ -0,0 +1,79 @@
+/*
+ * lib/crypto/keyblocks.c
+ *
+ * Copyright (C) 2002, 2005 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * 
+ *
+ * krb5_init_keyblock- a function to set up 
+ *  an empty keyblock
+ */
+
+
+#include "k5-int.h"
+#include <assert.h>
+
+krb5_error_code   krb5int_c_init_keyblock
+	(krb5_context context, krb5_enctype enctype,
+	 size_t length, krb5_keyblock **out)
+{
+    krb5_keyblock *kb;
+    kb = malloc (sizeof(krb5_keyblock));
+    assert (out);
+    *out = NULL;
+    if (!kb) {
+	return ENOMEM;
+    }
+    kb->magic = KV5M_KEYBLOCK;
+    kb->enctype = enctype;
+    kb->length = length;
+    if(length) {
+	kb->contents = malloc (length);
+	if(!kb->contents) {
+	    free (kb);
+	    return ENOMEM;
+	}
+    } else {
+	kb->contents = NULL;
+    }
+    *out = kb;
+    return 0;
+}
+
+
+void 
+krb5int_c_free_keyblock(krb5_context context, register krb5_keyblock *val)
+{
+    krb5int_c_free_keyblock_contents(context, val);
+    krb5_xfree(val);
+}
+
+void 
+krb5int_c_free_keyblock_contents(krb5_context context, register krb5_keyblock *key)
+{
+     if (key->contents) {
+       krb5int_zap_data (key->contents, key->length);
+	  krb5_xfree(key->contents);
+	  key->contents = 0;
+     }
+}
diff --git a/mechglue/src/lib/crypto/keyed_checksum_types.c b/mechglue/src/lib/crypto/keyed_checksum_types.c
new file mode 100644
index 000000000..0e46466f2
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyed_checksum_types.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include "cksumtypes.h"
+
+static int etype_match(krb5_enctype e1, krb5_enctype e2)
+{
+    int i1, i2;
+
+    for (i1=0; i1<krb5_enctypes_length; i1++) 
+	if (krb5_enctypes_list[i1].etype == e1)
+	    break;
+
+    for (i2=0; i2<krb5_enctypes_length; i2++) 
+	if (krb5_enctypes_list[i2].etype == e2)
+	    break;
+
+    return((i1 < krb5_enctypes_length) &&
+	   (i2 < krb5_enctypes_length) &&
+	   (krb5_enctypes_list[i1].enc == krb5_enctypes_list[i2].enc));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_keyed_checksum_types(krb5_context context, krb5_enctype enctype,
+			    unsigned int *count, krb5_cksumtype **cksumtypes)
+{
+    unsigned int i, c;
+
+    c = 0;
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if ((krb5_cksumtypes_list[i].keyhash &&
+	     etype_match(krb5_cksumtypes_list[i].keyed_etype, enctype)) ||
+	    (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE)) {
+	    c++;
+	}
+    }
+
+    *count = c;
+
+    if ((*cksumtypes = (krb5_cksumtype *) malloc(c*sizeof(krb5_cksumtype)))
+	== NULL)
+	return(ENOMEM);
+
+    c = 0;
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if ((krb5_cksumtypes_list[i].keyhash &&
+	     etype_match(krb5_cksumtypes_list[i].keyed_etype, enctype)) ||
+	    (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE)) {
+	    (*cksumtypes)[c] = krb5_cksumtypes_list[i].ctype;
+	    c++;
+	}
+    }
+
+    return(0);
+}
+
+void KRB5_CALLCONV
+krb5_free_cksumtypes(krb5_context context, krb5_cksumtype *val)
+{
+    if (val)
+	krb5_xfree(val);
+    return;
+}
+
diff --git a/mechglue/src/lib/crypto/keyed_cksum.c b/mechglue/src/lib/crypto/keyed_cksum.c
new file mode 100644
index 000000000..4d50c2c4a
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyed_cksum.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_boolean KRB5_CALLCONV
+krb5_c_is_keyed_cksum(krb5_cksumtype ctype)
+{
+    int i;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if (krb5_cksumtypes_list[i].ctype == ctype) {
+	    if (krb5_cksumtypes_list[i].keyhash ||
+		(krb5_cksumtypes_list[i].flags &
+		 KRB5_CKSUMFLAG_DERIVE))
+		return(1);
+	    else
+		return(0);
+	}
+    }
+
+    /* ick, but it's better than coredumping, which is what the
+       old code would have done */
+    return 0;   /* error case */
+}
+
+krb5_boolean KRB5_CALLCONV
+is_keyed_cksum(krb5_cksumtype ctype)
+{
+    return krb5_c_is_keyed_cksum (ctype);
+}
diff --git a/mechglue/src/lib/crypto/keyhash_provider/ChangeLog b/mechglue/src/lib/crypto/keyhash_provider/ChangeLog
new file mode 100644
index 000000000..6f442b1f3
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyhash_provider/ChangeLog
@@ -0,0 +1,148 @@
+2004-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_cksum4, t_cksum5): Link test programs against
+	thread support library.
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* descbc.c (mit_des_zeroblock): Don't define here.
+	* k5_md4des.c (mit_des_zeroblock): Don't define here.
+	* k5_md5des.c (mit_des_zeroblock): Don't define here.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* descbc.c (k5_descbc_hash_size): Deleted.
+	(krb5int_keyhash_descbc): Updated.
+	* hmac_md5.c (k5_hmac_md5_hash_size): Deleted.
+	(krb5int_keyhash_hmac_md5): Updated.
+	* k5_md4des.c (k5_md4des_hash_size): Deleted.
+	(krb5int_keyhash_md4des): Updated.
+	* k5_md5des.c (k5_md5des_hash_size): Deleted.
+	(krb5int_keyhash_md5des): Updated.
+	* t_cksum.c (main): Use the hashsize field instead of calling a
+	function.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* t_cksum.c: Cleanup (potential) variable used before set warning.
+
+2002-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_cksum4, t_cksum5): Include com_err library when
+	linking.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-12-14  Ezra Peisach  <epeisach@mit.edu>
+
+	* hmac_md5.c (k5_hmac_md5_hash): Test if malloc returns NULL and
+	not the argument to malloc.
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_cksum.c (main): Free memory leak in tests.
+
+2001-10-28  Jeff Altman <jaltman@columbia.edu>
+
+        * Makefile.in - added dependency info for hmac_md5.c
+          Fixed typo $(OUTP)hmac_md5.c -> $(OUTPRE)hmac_md5.c which prevented
+          builds on Windows.
+
+2001-10-23  Sam Hartman  <hartmans@mit.edu>
+
+	* t_cksum.c (main): Include usage argument to verify
+
+	* k5_md5des.c (k5_md5des_verify): Add usage
+
+	* k5_md4des.c (k5_md4des_verify): Add usage
+
+2001-10-22  Sam Hartman  <hartmans@mit.edu>
+
+	* keyhash_provider.h hmac_md5.c:  Implement Microsoft hmac-md5 keyhash provider
+
+	* t_cksum.c (main):  Include key usage in hash call.
+
+	* k5_md5des.c (k5_md5des_hash): add usage
+
+	* k5_md4des.c (k5_md4des_hash):  add key usage
+
+	* descbc.c (k5_descbc_hash):  Add key usage
+
+2001-05-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5_md4des.c (k5_md4des_verify): Get rid of local variable that
+	is assigned to, without side effects, but never used.
+	* k5_md5des.c (k5_md5des_verify): Likewise.
+
+2001-03-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* descbc.c, k5_md4des.c, k5_md5des.c, keyhash_provider.h,
+	t_cksum.c: Use krb5int_ prefix for internal "provider"
+	structures.
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* descbc.c, k5_md4des.c, k5_md5des.c: Use const instead of
+	krb5_const.
+
+2000-09-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* descbc.c, k5_md4des.c, k5_md5des.c, t_cksum.c: Cleanup unsigned
+	vs. signed warnings.
+
+	* Makefile.in (t_cksum5, t_cksum4): Executables do not need to
+	link with the krb5 library.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* descbc.c (k5_descbc_hash): Get rid of unused variable.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* descbc.c (mit_des_zeroblock): Now const, and using C default
+	initializer.
+	(krb5_keyhash_descbc): Now const.
+	* k5_md4des.c (mit_des_zeroblock): Now const, and using C default
+	initializer.
+	(k5_md4des_hash): Change if(a=b) constructs to silence gcc
+	warnings.
+	(k5_md4des_verify): Delete unused variable.
+	(krb5_keyhash_md4des): Now const.
+	* k5_md5des.c (mit_des_zeroblock): Now const, and using C default
+	initializer.
+	(k5_md5des_hash): Change if(a=b) constructs to silence gcc
+	warnings.
+	(k5_md5des_verify): Delete unused variable.
+	(krb5_keyhash_md5des): Now const.
+	* keyhash_provider.h: Updated krb5_keyhash_* decls.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:19:24 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
diff --git a/mechglue/src/lib/crypto/keyhash_provider/Makefile.in b/mechglue/src/lib/crypto/keyhash_provider/Makefile.in
new file mode 100644
index 000000000..820206206
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyhash_provider/Makefile.in
@@ -0,0 +1,93 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/keyhash_provider
+mydir=keyhash_provider
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/../des -I$(srcdir)/../md4 \
+	-I$(srcdir)/../md5 -I$(srcdir)/../arcfour \
+	-I$(srcdir)/../hash_provider
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=keyhash_provider
+##DOS##OBJFILE=..\$(OUTPRE)kh_pro.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= descbc.o k5_md4des.o k5_md5des.o hmac_md5.o
+
+OBJS= $(OUTPRE)descbc.$(OBJEXT) $(OUTPRE)k5_md4des.$(OBJEXT) $(OUTPRE)k5_md5des.$(OBJEXT) $(OUTPRE)hmac_md5.$(OBJEXT)
+
+SRCS= $(srcdir)/descbc.c $(srcdir)/k5_md4des.c $(srcdir)/k5_md5des.c $(srcdir)/hmac_md5.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+t_cksum4.o: $(srcdir)/t_cksum.c
+	$(CC) -DMD=4 $(ALL_CFLAGS) -o t_cksum4.o -c $(srcdir)/t_cksum.c
+
+t_cksum5.o: $(srcdir)/t_cksum.c
+	$(CC) -DMD=5 $(ALL_CFLAGS) -o t_cksum5.o -c $(srcdir)/t_cksum.c
+
+t_cksum4: t_cksum4.o $(CRYTPO_DEPLIB)
+	$(CC_LINK) -o t_cksum4 t_cksum4.o $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(LIBS)
+
+t_cksum5: t_cksum5.o $(CRYPTO_DEPLIB)
+	$(CC_LINK) -o t_cksum5 t_cksum5.o $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(LIBS)
+
+check-unix:: t_cksum4 t_cksum5
+	$(RUN_SETUP) $(C)t_cksum4 "this is a test"
+	$(RUN_SETUP) $(C)t_cksum5 "this is a test"
+
+clean-unix::
+	$(RM) t_cksum4 t_cksum4.o
+	$(RM) t_cksum5 t_cksum5.o
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+descbc.so descbc.po $(OUTPRE)descbc.$(OBJEXT): descbc.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../des/des_int.h $(SRCTOP)/include/kerberosIV/des.h \
+  keyhash_provider.h
+k5_md4des.so k5_md4des.po $(OUTPRE)k5_md4des.$(OBJEXT): \
+  k5_md4des.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../des/des_int.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(srcdir)/../md4/rsa-md4.h keyhash_provider.h
+k5_md5des.so k5_md5des.po $(OUTPRE)k5_md5des.$(OBJEXT): \
+  k5_md5des.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../des/des_int.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(srcdir)/../md5/rsa-md5.h keyhash_provider.h
+hmac_md5.so hmac_md5.po $(OUTPRE)hmac_md5.$(OBJEXT): \
+  hmac_md5.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  keyhash_provider.h $(srcdir)/../arcfour/arcfour-int.h \
+  $(srcdir)/../arcfour/arcfour.h $(srcdir)/../md5/rsa-md5.h \
+  $(srcdir)/../hash_provider/hash_provider.h
diff --git a/mechglue/src/lib/crypto/keyhash_provider/descbc.c b/mechglue/src/lib/crypto/keyhash_provider/descbc.c
new file mode 100644
index 000000000..fcccbfa7c
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyhash_provider/descbc.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include "keyhash_provider.h"
+
+static krb5_error_code
+k5_descbc_hash(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec,
+	       const krb5_data *input, krb5_data *output)
+{
+    mit_des_key_schedule schedule;
+
+    if (key->length != 8)
+	return(KRB5_BAD_KEYSIZE);
+    if ((input->length%8) != 0)
+	return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+	return(KRB5_CRYPTO_INTERNAL);
+    if (output->length != 8)
+	return(KRB5_CRYPTO_INTERNAL);
+
+    switch (mit_des_key_sched(key->contents, schedule)) {
+    case -1:
+	return(KRB5DES_BAD_KEYPAR);
+    case -2:
+	return(KRB5DES_WEAK_KEY);
+    }
+
+    /* this has a return value, but it's useless to us */
+
+    mit_des_cbc_cksum((unsigned char *) input->data, 
+		      (unsigned char *) output->data, input->length,
+		      schedule, 
+		      ivec? (unsigned char *)ivec->data: 
+		            (unsigned char *)mit_des_zeroblock);
+
+    memset(schedule, 0, sizeof(schedule));
+
+    return(0);
+}
+
+const struct krb5_keyhash_provider krb5int_keyhash_descbc = {
+    8,
+    k5_descbc_hash,
+    NULL
+};
diff --git a/mechglue/src/lib/crypto/keyhash_provider/hmac_md5.c b/mechglue/src/lib/crypto/keyhash_provider/hmac_md5.c
new file mode 100644
index 000000000..a2472a832
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyhash_provider/hmac_md5.c
@@ -0,0 +1,96 @@
+/*
+ * lib/crypto/keyhash_provider/hmac_md5.c
+ *
+(I don't know)
+.
+ * Copyright2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+* Implementation of the Microsoft hmac-md5 checksum type.
+* Implemented based on draft-brezak-win2k-krb-rc4-hmac-03
+ */
+
+#include "k5-int.h"
+#include "keyhash_provider.h"
+#include "arcfour-int.h"
+#include "rsa-md5.h"
+#include "hash_provider.h"
+
+static  krb5_error_code
+k5_hmac_md5_hash (const krb5_keyblock *key, krb5_keyusage usage,
+		  const krb5_data *iv,
+		  const krb5_data *input, krb5_data *output)
+{
+  krb5_keyusage ms_usage;
+  krb5_error_code ret;
+  krb5_keyblock ks;
+  krb5_data ds, ks_constant, md5tmp;
+  krb5_MD5_CTX ctx;
+  char t[4];
+  
+
+  ds.length = key->length;
+  ks.length = key->length;
+  ds.data = malloc(ds.length);
+  if (ds.data == NULL)
+    return ENOMEM;
+  ks.contents = (void *) ds.data;
+
+  ks_constant.data = "signaturekey";
+  ks_constant.length = strlen(ks_constant.data)+1; /* Including null*/
+
+  ret = krb5_hmac( &krb5int_hash_md5, key, 1,
+		   &ks_constant, &ds);
+  if (ret)
+    goto cleanup;
+
+  krb5_MD5Init (&ctx);
+  ms_usage = krb5int_arcfour_translate_usage (usage);
+  t[0] = (ms_usage) & 0xff;
+  t[1] = (ms_usage>>8) & 0xff;
+  t[2] = (ms_usage >>16) & 0xff;
+  t[3] = (ms_usage>>24) & 0XFF;
+  krb5_MD5Update (&ctx, (unsigned char * ) &t, 4);
+  krb5_MD5Update (&ctx, (unsigned char *) input-> data,
+		  (unsigned int) input->length );
+  krb5_MD5Final(&ctx);
+  md5tmp.data = (void *) ctx.digest;
+  md5tmp.length = 16;
+  ret = krb5_hmac ( &krb5int_hash_md5, &ks, 1, &md5tmp,
+		    output);
+
+    cleanup:
+  memset(&ctx, 0, sizeof(ctx));
+  memset (ks.contents, 0, ks.length);
+  free (ks.contents);
+  return ret;
+}
+
+		 
+
+const struct krb5_keyhash_provider krb5int_keyhash_hmac_md5 = {
+  16,
+  k5_hmac_md5_hash,
+  NULL /*checksum  again*/
+};
+
diff --git a/mechglue/src/lib/crypto/keyhash_provider/k5_md4des.c b/mechglue/src/lib/crypto/keyhash_provider/k5_md4des.c
new file mode 100644
index 000000000..8e9623901
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyhash_provider/k5_md4des.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include "rsa-md4.h"
+#include "keyhash_provider.h"
+
+#define CONFLENGTH 8
+
+/* Force acceptance of krb5-beta5 md4des checksum for now. */
+#define KRB5_MD4DES_BETA5_COMPAT
+
+/* des-cbc(xorkey, conf | rsa-md4(conf | data)) */
+
+/* this could be done in terms of the md4 and des providers, but
+   that's less efficient, and there's no need for this to be generic */
+
+static krb5_error_code
+k5_md4des_hash(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec,
+	       const krb5_data *input, krb5_data *output)
+{
+    krb5_error_code ret;
+    krb5_data data;
+    krb5_MD4_CTX ctx;
+    unsigned char conf[CONFLENGTH];
+    unsigned char xorkey[8];
+    int i;
+    mit_des_key_schedule schedule;
+
+    if (key->length != 8)
+	return(KRB5_BAD_KEYSIZE);
+    if (ivec)
+	return(KRB5_CRYPTO_INTERNAL);
+    if (output->length != (CONFLENGTH+RSA_MD4_CKSUM_LENGTH))
+	return(KRB5_CRYPTO_INTERNAL);
+
+    /* create the confouder */
+
+    data.length = CONFLENGTH;
+    data.data = (char *) conf;
+    if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &data)))
+	return(ret);
+
+    /* create and schedule the encryption key */
+
+    memcpy(xorkey, key->contents, sizeof(xorkey));
+    for (i=0; i<sizeof(xorkey); i++)
+	xorkey[i] ^= 0xf0;
+    
+    switch (ret = mit_des_key_sched(xorkey, schedule)) {
+    case -1:
+	return(KRB5DES_BAD_KEYPAR);
+    case -2:
+	return(KRB5DES_WEAK_KEY);
+    }
+
+    /* hash the confounder, then the input data */
+
+    krb5_MD4Init(&ctx);
+    krb5_MD4Update(&ctx, conf, CONFLENGTH);
+    krb5_MD4Update(&ctx, (unsigned char *) input->data,
+		   (unsigned int) input->length);
+    krb5_MD4Final(&ctx);
+
+    /* construct the buffer to be encrypted */
+
+    memcpy(output->data, conf, CONFLENGTH);
+    memcpy(output->data+CONFLENGTH, ctx.digest, RSA_MD4_CKSUM_LENGTH);
+
+    /* encrypt it, in place.  this has a return value, but it's
+       always zero.  */
+
+    mit_des_cbc_encrypt((krb5_pointer) output->data,
+			(krb5_pointer) output->data, output->length,
+			schedule, (unsigned char *) mit_des_zeroblock, 1);
+
+    return(0);
+}
+
+static krb5_error_code
+k5_md4des_verify(const krb5_keyblock *key, krb5_keyusage usage,
+		 const krb5_data *ivec,
+		 const krb5_data *input, const krb5_data *hash,
+		 krb5_boolean *valid)
+{
+    krb5_MD4_CTX ctx;
+    unsigned char plaintext[CONFLENGTH+RSA_MD4_CKSUM_LENGTH];
+    unsigned char xorkey[8];
+    int i;
+    mit_des_key_schedule schedule;
+    int compathash = 0;
+
+    if (key->length != 8)
+	return(KRB5_BAD_KEYSIZE);
+    if (ivec)
+	return(KRB5_CRYPTO_INTERNAL);
+    if (hash->length != (CONFLENGTH+RSA_MD4_CKSUM_LENGTH)) {
+#ifdef KRB5_MD4DES_BETA5_COMPAT
+	if (hash->length != RSA_MD4_CKSUM_LENGTH)
+	    return(KRB5_CRYPTO_INTERNAL);
+	else
+	    compathash = 1;
+#else
+	return(KRB5_CRYPTO_INTERNAL);
+#endif
+	return(KRB5_CRYPTO_INTERNAL);
+    }
+
+    /* create and schedule the encryption key */
+
+    memcpy(xorkey, key->contents, sizeof(xorkey));
+    if (!compathash) {
+	for (i=0; i<sizeof(xorkey); i++)
+	    xorkey[i] ^= 0xf0;
+    }
+    
+    switch (mit_des_key_sched(xorkey, schedule)) {
+    case -1:
+	return(KRB5DES_BAD_KEYPAR);
+    case -2:
+	return(KRB5DES_WEAK_KEY);
+    }
+
+    /* decrypt it.  this has a return value, but it's always zero.  */
+
+    if (!compathash) {
+	mit_des_cbc_encrypt((krb5_pointer) hash->data,
+			    (krb5_pointer) plaintext, hash->length,
+			    schedule, (unsigned char *) mit_des_zeroblock, 0);
+    } else {
+	mit_des_cbc_encrypt((krb5_pointer) hash->data,
+			    (krb5_pointer) plaintext, hash->length,
+			    schedule, xorkey, 0);
+    }
+
+    /* hash the confounder, then the input data */
+
+    krb5_MD4Init(&ctx);
+    if (!compathash) {
+	krb5_MD4Update(&ctx, plaintext, CONFLENGTH);
+    }
+    krb5_MD4Update(&ctx, (unsigned char *) input->data, 
+		   (unsigned int) input->length);
+    krb5_MD4Final(&ctx);
+
+    /* compare the decrypted hash to the computed one */
+
+    if (!compathash) {
+	*valid =
+	    (memcmp(plaintext+CONFLENGTH, ctx.digest, RSA_MD4_CKSUM_LENGTH)
+	     == 0);
+    } else {
+	*valid =
+	    (memcmp(plaintext, ctx.digest, RSA_MD4_CKSUM_LENGTH) == 0);
+    }
+
+    memset(plaintext, 0, sizeof(plaintext));
+
+    return(0);
+}
+
+const struct krb5_keyhash_provider krb5int_keyhash_md4des = {
+    CONFLENGTH+RSA_MD4_CKSUM_LENGTH,
+    k5_md4des_hash,
+    k5_md4des_verify
+};
diff --git a/mechglue/src/lib/crypto/keyhash_provider/k5_md5des.c b/mechglue/src/lib/crypto/keyhash_provider/k5_md5des.c
new file mode 100644
index 000000000..4f7b89812
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyhash_provider/k5_md5des.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "des_int.h"
+#include "rsa-md5.h"
+#include "keyhash_provider.h"
+
+#define CONFLENGTH 8
+
+/* Force acceptance of krb5-beta5 md5des checksum for now. */
+#define KRB5_MD5DES_BETA5_COMPAT
+
+/* des-cbc(xorkey, conf | rsa-md5(conf | data)) */
+
+/* this could be done in terms of the md5 and des providers, but
+   that's less efficient, and there's no need for this to be generic */
+
+static krb5_error_code
+k5_md5des_hash(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec,
+	       const krb5_data *input, krb5_data *output)
+{
+    krb5_error_code ret;
+    krb5_data data;
+    krb5_MD5_CTX ctx;
+    unsigned char conf[CONFLENGTH];
+    unsigned char xorkey[8];
+    int i;
+    mit_des_key_schedule schedule;
+
+    if (key->length != 8)
+	return(KRB5_BAD_KEYSIZE);
+    if (ivec)
+	return(KRB5_CRYPTO_INTERNAL);
+    if (output->length != (CONFLENGTH+RSA_MD5_CKSUM_LENGTH))
+	return(KRB5_CRYPTO_INTERNAL);
+
+    /* create the confouder */
+
+    data.length = CONFLENGTH;
+    data.data = (char *) conf;
+    if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &data)))
+	return(ret);
+
+    /* create and schedule the encryption key */
+
+    memcpy(xorkey, key->contents, sizeof(xorkey));
+    for (i=0; i<sizeof(xorkey); i++)
+	xorkey[i] ^= 0xf0;
+    
+    switch (ret = mit_des_key_sched(xorkey, schedule)) {
+    case -1:
+	return(KRB5DES_BAD_KEYPAR);
+    case -2:
+	return(KRB5DES_WEAK_KEY);
+    }
+
+    /* hash the confounder, then the input data */
+
+    krb5_MD5Init(&ctx);
+    krb5_MD5Update(&ctx, conf, CONFLENGTH);
+    krb5_MD5Update(&ctx, (unsigned char *) input->data, 
+		   (unsigned int) input->length);
+    krb5_MD5Final(&ctx);
+
+    /* construct the buffer to be encrypted */
+
+    memcpy(output->data, conf, CONFLENGTH);
+    memcpy(output->data+CONFLENGTH, ctx.digest, RSA_MD5_CKSUM_LENGTH);
+
+    /* encrypt it, in place.  this has a return value, but it's
+       always zero.  */
+
+    mit_des_cbc_encrypt((krb5_pointer) output->data,
+			(krb5_pointer) output->data, output->length,
+			schedule, (unsigned char *) mit_des_zeroblock, 1);
+
+    return(0);
+}
+
+static krb5_error_code
+k5_md5des_verify(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec,
+		 const krb5_data *input, const krb5_data *hash,
+		 krb5_boolean *valid)
+{
+    krb5_MD5_CTX ctx;
+    unsigned char plaintext[CONFLENGTH+RSA_MD5_CKSUM_LENGTH];
+    unsigned char xorkey[8];
+    int i;
+    mit_des_key_schedule schedule;
+    int compathash = 0;
+
+    if (key->length != 8)
+	return(KRB5_BAD_KEYSIZE);
+    if (ivec)
+	return(KRB5_CRYPTO_INTERNAL);
+    if (hash->length != (CONFLENGTH+RSA_MD5_CKSUM_LENGTH)) {
+#ifdef KRB5_MD5DES_BETA5_COMPAT
+	if (hash->length != RSA_MD5_CKSUM_LENGTH)
+	    return(KRB5_CRYPTO_INTERNAL);
+	else
+	    compathash = 1;
+#else
+	return(KRB5_CRYPTO_INTERNAL);
+#endif
+    }
+
+    /* create and schedule the encryption key */
+
+    memcpy(xorkey, key->contents, sizeof(xorkey));
+    if (!compathash) {
+	for (i=0; i<sizeof(xorkey); i++)
+	    xorkey[i] ^= 0xf0;
+    }
+    
+    switch (mit_des_key_sched(xorkey, schedule)) {
+    case -1:
+	return(KRB5DES_BAD_KEYPAR);
+    case -2:
+	return(KRB5DES_WEAK_KEY);
+    }
+
+    /* decrypt it.  this has a return value, but it's always zero.  */
+
+    if (!compathash) {
+	mit_des_cbc_encrypt((krb5_pointer) hash->data,
+			    (krb5_pointer) plaintext, hash->length,
+			    schedule, (unsigned char *) mit_des_zeroblock, 0);
+    } else {
+	mit_des_cbc_encrypt((krb5_pointer) hash->data,
+			    (krb5_pointer) plaintext, hash->length,
+			    schedule, xorkey, 0);
+    }
+
+    /* hash the confounder, then the input data */
+
+    krb5_MD5Init(&ctx);
+    if (!compathash) {
+	krb5_MD5Update(&ctx, plaintext, CONFLENGTH);
+    }
+    krb5_MD5Update(&ctx, (unsigned char *) input->data, 
+		   (unsigned) input->length);
+    krb5_MD5Final(&ctx);
+
+    /* compare the decrypted hash to the computed one */
+
+    if (!compathash) {
+	*valid =
+	    (memcmp(plaintext+CONFLENGTH, ctx.digest, RSA_MD5_CKSUM_LENGTH)
+	     == 0);
+    } else {
+	*valid = 
+	    (memcmp(plaintext, ctx.digest, RSA_MD5_CKSUM_LENGTH) == 0);
+    }
+    memset(plaintext, 0, sizeof(plaintext));
+
+    return(0);
+}
+
+const struct krb5_keyhash_provider krb5int_keyhash_md5des = {
+    CONFLENGTH+RSA_MD5_CKSUM_LENGTH,
+    k5_md5des_hash,
+    k5_md5des_verify
+};
diff --git a/mechglue/src/lib/crypto/keyhash_provider/keyhash_provider.h b/mechglue/src/lib/crypto/keyhash_provider/keyhash_provider.h
new file mode 100644
index 000000000..6a96faf8f
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyhash_provider/keyhash_provider.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+extern const struct krb5_keyhash_provider krb5int_keyhash_descbc;
+extern const struct krb5_keyhash_provider krb5int_keyhash_md4des;
+extern const struct krb5_keyhash_provider krb5int_keyhash_md5des;
+extern const struct krb5_keyhash_provider krb5int_keyhash_hmac_md5;
diff --git a/mechglue/src/lib/crypto/keyhash_provider/t_cksum.c b/mechglue/src/lib/crypto/keyhash_provider/t_cksum.c
new file mode 100644
index 000000000..98187f7f1
--- /dev/null
+++ b/mechglue/src/lib/crypto/keyhash_provider/t_cksum.c
@@ -0,0 +1,139 @@
+/*
+ * lib/crypto/md5/t_cksum.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * t_cksum.c - Test checksum and checksum compatability for rsa-md[4,5]-des
+ */
+
+#include "k5-int.h"
+
+#define MD5_K5BETA_COMPAT
+#define MD4_K5BETA_COMPAT
+
+#if	MD == 4
+extern struct krb5_keyhash_provider krb5int_keyhash_md4des;
+#define khp krb5int_keyhash_md4des
+#endif
+
+#if	MD == 5
+extern struct krb5_keyhash_provider krb5int_keyhash_md5des;
+#define khp krb5int_keyhash_md5des
+#endif
+
+static void
+print_checksum(text, number, message, checksum)
+     char	*text;
+     int	number;
+     char	*message;
+     krb5_data	*checksum;
+{
+  int i;
+
+  printf("%s MD%d checksum(\"%s\") = ", text, number, message);
+  for (i=0; i<checksum->length; i++)
+    printf("%02x", (unsigned char) checksum->data[i]);
+  printf("\n");
+}
+
+/*
+ * Test the checksum verification of Old Style (tm) and correct RSA-MD[4,5]-DES
+ * checksums.
+ */
+
+krb5_octet testkey[8] = { 0x45, 0x01, 0x49, 0x61, 0x58, 0x19, 0x1a, 0x3d };
+
+int
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+  int 			msgindex;
+  krb5_boolean		valid;
+  size_t		length;
+  krb5_keyblock		keyblock;
+  krb5_error_code	kret=0;
+  krb5_data		plaintext, newstyle_checksum;
+
+  /* this is a terrible seed, but that's ok for the test. */
+
+  plaintext.length = 8;
+  plaintext.data = (char *) testkey;
+
+  krb5_c_random_seed(/* XXX */ 0, &plaintext);
+
+  keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+  keyblock.length = sizeof(testkey);
+  keyblock.contents = testkey;
+
+  length = khp.hashsize;
+
+  newstyle_checksum.length = length;
+
+  if (!(newstyle_checksum.data = (char *)
+	malloc((unsigned) newstyle_checksum.length))) {
+    printf("cannot get memory for new style checksum\n");
+    return(ENOMEM);
+  }
+  for (msgindex = 1; msgindex < argc; msgindex++) {
+    plaintext.length = strlen(argv[msgindex]);
+    plaintext.data = argv[msgindex];
+
+    if ((kret = (*(khp.hash))(&keyblock, 0, 0, &plaintext, &newstyle_checksum))) {
+      printf("krb5_calculate_checksum choked with %d\n", kret);
+      break;
+    }
+    print_checksum("correct", MD, argv[msgindex], &newstyle_checksum);
+
+    if ((kret = (*(khp.verify))(&keyblock, 0, 0, &plaintext, &newstyle_checksum,
+				&valid))) {
+      printf("verify on new checksum choked with %d\n", kret);
+      break;
+    }
+    if (!valid) {
+      printf("verify on new checksum failed\n");
+      break;
+    }
+    printf("Verify succeeded for \"%s\"\n", argv[msgindex]);
+
+    newstyle_checksum.data[0]++;
+    if ((kret = (*(khp.verify))(&keyblock, 0, 0, &plaintext, &newstyle_checksum,
+				&valid))) {
+      printf("verify on new checksum choked with %d\n", kret);
+      break;
+    }
+    if (valid) {
+      printf("verify on new checksum succeeded, but shouldn't have\n");
+      break;
+    }
+    printf("Verify of bad checksum OK for \"%s\"\n", argv[msgindex]);
+    kret = 0;
+  }
+  free(newstyle_checksum.data);
+  if (!kret)
+    printf("%d tests passed successfully for MD%d checksum\n", argc-1, MD);
+  return(kret);
+}
diff --git a/mechglue/src/lib/crypto/libk5crypto.exports b/mechglue/src/lib/crypto/libk5crypto.exports
new file mode 100644
index 000000000..b06f2e427
--- /dev/null
+++ b/mechglue/src/lib/crypto/libk5crypto.exports
@@ -0,0 +1,156 @@
+des_FP_table
+des_IP_table
+des_SP_table
+is_coll_proof_cksum
+is_keyed_cksum
+krb5_MD4Final
+krb5_MD4Init
+krb5_MD4Update
+krb5_MD5Final
+krb5_MD5Init
+krb5_MD5Update
+krb5_arcfour_decrypt
+krb5_arcfour_encrypt
+krb5_arcfour_encrypt_length
+krb5_c_block_size
+krb5_c_checksum_length
+krb5_c_decrypt
+krb5_c_encrypt
+krb5_c_encrypt_length
+krb5_c_enctype_compare
+krb5_c_free_state
+krb5_c_init_state
+krb5_c_is_coll_proof_cksum
+krb5_c_is_keyed_cksum
+krb5_c_keyed_checksum_types
+krb5_c_make_checksum
+krb5_c_make_random_key
+krb5_c_prf
+krb5_c_prf_length
+krb5_c_random_add_entropy
+krb5_c_random_make_octets
+krb5_c_random_os_entropy
+krb5_c_random_seed
+krb5_c_string_to_key
+krb5_c_string_to_key_with_params
+krb5_c_valid_cksumtype
+krb5_c_valid_enctype
+krb5_c_verify_checksum
+krb5_calculate_checksum
+krb5_checksum_size
+krb5_cksumtype_to_string
+krb5_cksumtypes_length
+krb5_cksumtypes_list
+krb5_decrypt
+krb5_decrypt_data
+krb5_derive_key
+krb5_derive_random
+krb5_dk_decrypt
+krb5_dk_encrypt
+krb5_dk_encrypt_length
+krb5_dk_make_checksum
+krb5_eblock_enctype
+krb5_encrypt
+krb5_encrypt_data
+krb5_encrypt_size
+krb5_enctype_to_string
+krb5_enctypes_length
+krb5_enctypes_list
+krb5_finish_key
+krb5_finish_random_key
+krb5_free_cksumtypes
+krb5_hmac
+krb5_init_random_key
+krb5_nfold
+krb5_old_decrypt
+krb5_old_encrypt
+krb5_old_encrypt_length
+krb5_process_key
+krb5_random_confounder
+krb5_random_key
+krb5_raw_decrypt
+krb5_raw_encrypt
+krb5_raw_encrypt_length
+krb5_string_to_cksumtype
+krb5_string_to_enctype
+krb5_string_to_key
+krb5_use_enctype
+krb5_verify_checksum
+krb5int_aes_dec_blk
+krb5int_aes_dec_key
+krb5int_aes_decrypt
+krb5int_aes_dk_decrypt
+krb5int_aes_dk_encrypt
+krb5int_aes_enc_blk
+krb5int_aes_enc_key
+krb5int_aes_encrypt
+krb5int_aes_encrypt_length
+krb5int_aes_string_to_key
+krb5int_arcfour_string_to_key
+krb5int_arcfour_translate_usage
+krb5int_c_combine_keys
+krb5int_c_mandatory_cksumtype
+krb5int_c_free_keyblock
+krb5int_c_free_keyblock_contents
+krb5int_c_init_keyblock
+krb5int_c_mit_des_zeroblock
+krb5int_default_free_state
+krb5int_des3_cbc_decrypt
+krb5int_des3_cbc_encrypt
+krb5int_des_cbc_decrypt
+krb5int_des_cbc_encrypt
+krb5int_des_init_state
+krb5int_des_string_to_key
+krb5int_dk_string_to_key
+krb5int_enc_aes128
+krb5int_enc_aes256
+krb5int_enc_arcfour
+krb5int_enc_des
+krb5int_enc_des3
+krb5int_fl_tab
+krb5int_ft_tab
+krb5int_hash_crc32
+krb5int_hash_md4
+krb5int_hash_md5
+krb5int_hash_sha1
+krb5int_il_tab
+krb5int_im_tab
+krb5int_it_tab
+krb5int_keyhash_descbc
+krb5int_keyhash_hmac_md5
+krb5int_keyhash_md4des
+krb5int_keyhash_md5des
+krb5int_pbkdf2_hmac_sha1
+krb5int_prng_cleanup
+krb5int_rcon_tab
+krb5int_yarrow_cipher_encrypt_block
+krb5int_yarrow_cipher_init
+krb5int_yarrow_final
+krb5int_yarrow_gate
+krb5int_yarrow_init
+krb5int_yarrow_input
+krb5int_yarrow_new_source
+krb5int_yarrow_output
+krb5int_yarrow_register_source_estimator
+krb5int_yarrow_reseed
+krb5int_yarrow_status
+krb5int_yarrow_str_error
+krb5int_yarrow_stretch
+mit_afs_crypt
+mit_afs_string_to_key
+mit_crc32
+mit_des3_cbc_encrypt
+mit_des3_key_sched
+mit_des_cbc_cksum
+mit_des_cbc_encrypt
+mit_des_check_key_parity
+mit_des_fixup_key_parity
+mit_des_is_weak_key
+mit_des_key_sched
+mit_des_make_key_sched
+mit_des_string_to_key_int
+shsFinal
+shsInit
+shsUpdate
+valid_cksumtype
+valid_enctype
diff --git a/mechglue/src/lib/crypto/make_checksum.c b/mechglue/src/lib/crypto/make_checksum.c
new file mode 100644
index 000000000..4a2f00072
--- /dev/null
+++ b/mechglue/src/lib/crypto/make_checksum.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+#include "etypes.h"
+#include "dk.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_make_checksum(krb5_context context, krb5_cksumtype cksumtype,
+		     const krb5_keyblock *key, krb5_keyusage usage,
+		     const krb5_data *input, krb5_checksum *cksum)
+{
+    int i, e1, e2;
+    krb5_data data;
+    krb5_error_code ret;
+    size_t cksumlen;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if (krb5_cksumtypes_list[i].ctype == cksumtype)
+	    break;
+    }
+
+    if (i == krb5_cksumtypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    if (krb5_cksumtypes_list[i].keyhash)
+	cksumlen = krb5_cksumtypes_list[i].keyhash->hashsize;
+    else
+	cksumlen = krb5_cksumtypes_list[i].hash->hashsize;
+
+    cksum->length = cksumlen;
+
+    if ((cksum->contents = (krb5_octet *) malloc(cksum->length)) == NULL)
+	return(ENOMEM);
+
+    data.length = cksum->length;
+    data.data = (char *) cksum->contents;
+
+    if (krb5_cksumtypes_list[i].keyhash) {
+	/* check if key is compatible */
+
+	if (krb5_cksumtypes_list[i].keyed_etype) {
+	    for (e1=0; e1<krb5_enctypes_length; e1++) 
+		if (krb5_enctypes_list[e1].etype ==
+		    krb5_cksumtypes_list[i].keyed_etype)
+		    break;
+
+	    for (e2=0; e2<krb5_enctypes_length; e2++) 
+		if (krb5_enctypes_list[e2].etype == key->enctype)
+		    break;
+
+	    if ((e1 == krb5_enctypes_length) ||
+		(e2 == krb5_enctypes_length) ||
+		(krb5_enctypes_list[e1].enc != krb5_enctypes_list[e2].enc)) {
+		ret = KRB5_BAD_ENCTYPE;
+		goto cleanup;
+	    }
+	}
+
+	ret = (*(krb5_cksumtypes_list[i].keyhash->hash))(key, usage, 0, input, &data);
+    } else if (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE) {
+	ret = krb5_dk_make_checksum(krb5_cksumtypes_list[i].hash,
+				    key, usage, input, &data);
+    } else {
+	/* no key is used */
+
+	ret = (*(krb5_cksumtypes_list[i].hash->hash))(1, input, &data);
+    }
+
+    if (!ret) {
+	cksum->magic = KV5M_CHECKSUM;
+	cksum->checksum_type = cksumtype;
+	if (krb5_cksumtypes_list[i].trunc_size) {
+	    krb5_octet *trunc;
+	    cksum->length = krb5_cksumtypes_list[i].trunc_size;
+	    trunc = (krb5_octet *) realloc(cksum->contents, cksum->length);
+	    if (trunc)
+		cksum->contents = trunc;
+	}
+    }
+
+cleanup:
+    if (ret) {
+	memset(cksum->contents, 0, cksum->length);
+	free(cksum->contents);
+	cksum->contents = NULL;
+    }
+
+    return(ret);
+}
diff --git a/mechglue/src/lib/crypto/make_random_key.c b/mechglue/src/lib/crypto/make_random_key.c
new file mode 100644
index 000000000..0ae321dca
--- /dev/null
+++ b/mechglue/src/lib/crypto/make_random_key.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_make_random_key(krb5_context context, krb5_enctype enctype,
+		       krb5_keyblock *random_key)
+{
+    int i;
+    krb5_error_code ret;
+    const struct krb5_enc_provider *enc;
+    size_t keybytes, keylength;
+    krb5_data random_data;
+    unsigned char *bytes;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    enc = krb5_enctypes_list[i].enc;
+
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    if ((bytes = (unsigned char *) malloc(keybytes)) == NULL)
+	return(ENOMEM);
+    if ((random_key->contents = (krb5_octet *) malloc(keylength)) == NULL) {
+	free(bytes);
+	return(ENOMEM);
+    }
+
+    random_data.data = (char *) bytes;
+    random_data.length = keybytes;
+
+    if ((ret = krb5_c_random_make_octets(context, &random_data)))
+	goto cleanup;
+
+    random_key->magic = KV5M_KEYBLOCK;
+    random_key->enctype = enctype;
+    random_key->length = keylength;
+
+    ret = ((*(enc->make_key))(&random_data, random_key));
+
+cleanup:
+    memset(bytes, 0, keybytes);
+    free(bytes);
+
+    if (ret) {
+	memset(random_key->contents, 0, keylength);
+	free(random_key->contents);
+    }
+
+    return(ret);
+}
diff --git a/mechglue/src/lib/crypto/mandatory_sumtype.c b/mechglue/src/lib/crypto/mandatory_sumtype.c
new file mode 100644
index 000000000..f9322ff3f
--- /dev/null
+++ b/mechglue/src/lib/crypto/mandatory_sumtype.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2003 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code
+krb5int_c_mandatory_cksumtype (krb5_context ctx, krb5_enctype etype,
+			       krb5_cksumtype *cksumtype)
+{
+    int i;
+
+    for (i = 0; i < krb5_enctypes_length; i++)
+	if (krb5_enctypes_list[i].etype == etype) {
+	    *cksumtype = krb5_enctypes_list[i].required_ctype;
+	    return 0;
+	}
+
+    return KRB5_BAD_ENCTYPE;
+}
diff --git a/mechglue/src/lib/crypto/md4/.Sanitize b/mechglue/src/lib/crypto/md4/.Sanitize
new file mode 100644
index 000000000..d2e49c102
--- /dev/null
+++ b/mechglue/src/lib/crypto/md4/.Sanitize
@@ -0,0 +1,42 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+Makefile.in
+configure
+configure.in
+md4.c
+md4crypto.c
+md4driver.c
+md4glue.c
+rsa-md4.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/crypto/md4/ChangeLog b/mechglue/src/lib/crypto/md4/ChangeLog
new file mode 100644
index 000000000..5537d8570
--- /dev/null
+++ b/mechglue/src/lib/crypto/md4/ChangeLog
@@ -0,0 +1,311 @@
+2006-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_mddriver): Include support library.  Use
+	CC_LINK.
+
+2005-05-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* md4.c (Transform) [CONFIG_SMALL]: Roll loops for each round.
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* md4.c: Use ANSI C style function definitions.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* rsa-md4.h (rsa_md4_cksumtable_entry,
+	rsa_md4_des_cksumtable_entry): Delete unused declarations.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* md4.c, rsa-md4.h: Don't explicitly declare pointers FAR any
+	more.
+
+2001-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* md4.c (GG, HH, krb5_MD4Init): Use UL suffix on numbers, don't
+	bother with UL macro.
+	(UL): Macro deleted.
+	(Transform): Always declare with prototype.
+
+	* rsa-md4.h: Always use prototypes.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* md4.c (PADDING): Now const.
+	(krb5_MD4Update): Argument inBuf now points to const.
+	(ROTATE_LEFT): Change (a&b|c) construct to silence gcc warning.
+	* rsa-md4.h (krb5_MD4Update): Update decl.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:19:48 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Nov  6 10:29:34 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Fix for make check to work out of source tree.
+
+Sun Jul 19 12:00:00 1998  Marc Horowitz <marc@mit.edu>
+
+	* *.c: replace the crypto layer.
+
+Tue Mar  3 08:39:47 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (t_cksum): Do not depend on libkrb5.a, use 
+	KRB5_BASE_DEPLIBS.
+
+Wed Feb 18 16:06:57 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 15:20:54 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (thisconfigdir), configure.in: Point the
+ 		configuration directory at our parent, and remove our
+		local configure.in
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Oct 28 16:36:15 1997  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* md4.c: Fix to deal with types longer than 32 bits.
+
+Sat Feb 22 18:53:00 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Thu Feb  6 12:46:49 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (t_cksum): Link with libkrb5.a.
+
+Thu Jan 30 21:42:03 1997  Richard Basch  <basch@lehman.com>
+
+	* md4crypto.c md4glue.c:
+		Change functions to take const args where possible
+
+Thu Nov 21 00:58:04 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: Win32 build
+
+Sun Dec 29 21:54:09 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to use new library building procedure.
+
+Wed Jun 12 00:10:42 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* md4.c
+	* rsa-md4.h: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS
+	
+
+Thu May 23 19:24:33 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (RUN_SETUP):  use KRB5_RUN_FLAGS
+
+Tue May 21 22:33:12 1996  Richard Basch  <basch@lehman.com>
+
+	* md4crypto.c: Incorrrect size arguments were being passed causing
+	decrypt integrity failures with the "fixed" md4 algorithm.  The old
+	path was also fixed to better reflect the appropriate size variables
+	even though the two in use were identical (if someone copied the
+	code to make a new crypto system, they may spend a long time
+	debugging because of the misuse of variables).
+	[Tracked down by epeisach; audited by basch.]
+
+Mon May 20 17:16:47 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* md4crypto.c, md4crypto.h: Change use of RSA_MD4_DES_CKSUM_LENGTH
+ 		to use OLD_RSA_MD4_DES_CKSUM_LENGTH and
+ 		NEW_RSA_MD4_DES_CKSUM_LENGTH, as appropriate.
+
+Sat May 18 01:49:33 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* md4crypto.c: Define MD4_K5BETA_COMPAT and MD4_K5BETA_COMP_DEF so
+ 		that we continue doing things the wrong (broken) way.  All
+ 		hail backwards compatibility....  The code now generates
+ 		the old checksum, but it will verify both the old and the
+ 		correct checksum formats.
+
+		Also fixed two bugs in the "correct" MD4_CRYPTO
+		implementation; use a zero initialization vector, and
+		calculate the confounder at the beginning of the message,
+		not at the end.  
+
+Tue May 14 19:31:58 1996  Richard Basch  <basch@lehman.com>
+
+	* md4crypto.c md4glue.c:
+		ensure the cksum content length is sufficient
+
+Fri Apr 12 21:38:33 1996  Richard Basch  <basch@lehman.com>
+
+	* md4driver.c md4glue.c md4.c rsa-md4.h md4crypto.c:
+	Renamed the functions to be preceded with krb5_
+
+Fri Oct  6 22:00:15 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:48:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 13 10:30:58 1995 Keith Vetter (keithv@fusion.com)
+
+	* md4crypt.c: put function prototype back in, fixed signed/unsigned
+		mismatch and removed unused variables.
+	* md4glue.c: put function prototypes back in.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * md4crypto.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * md4crypto.c : Replace KEYTYPE_DES_CBC_MD4 for KEYTYPE_DES.
+
+Thu Jul 27 15:22:17 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* rsa-md4.h - Don't include k5-config.h.  No longer present or needed.
+
+
+Fri Jul 7 16:13:28 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add t_cksum under unix only.
+	* configure.in - Define MD4_K5BETA_COMPAT to select compatability for
+		md4crypto.c.
+	* md4crypto.c - Correct implementation of RSA-MD4-DES checksums.  Add
+		ability to understand previous implementation and ability to
+		generate these checksums when forced to.
+		- Also add verification procedure for these checksums.
+	* md4glue.c - Add verifier procedure.
+	* rsa-md4.h - Add RSA_MD4_DES_CONFOUND_LENGTH, the length of the
+		RSA-MD4-DES confounder per RFC1510.
+
+
+Tue Jun 27 15:53:02 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* md4.c(Transform) - Add 'register' to scratch variable names.  Helps
+		out compiler so that DEC native compilers can now optimize
+		this module within our lifetimes.
+
+Thu Jun 22 16:13:29 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* md4.c: reverse sense of KRB5_PROVIDE_PROTOTYPES
+
+Wed Jun 21 10:52:07 1995    <tytso@rsx-11.mit.edu>
+
+	* md4crypto.c, md4glue.c: Change PROTOTYPE -> KRB5_PROTOTYPE
+
+Fri Jun  9 19:18:17 1995    <tytso@rsx-11.mit.edu>
+
+	* md4crypto.c: Fix -Wall nits
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu May 25 22:16:14 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for shared libraries.
+
+Thu Apr 20 11:39:15 1995    <tytso@rsx-11.mit.edu>
+
+	* rsa-md4.h: removed unneeded #include of wordsize.h
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+        * *.h added FAR to pointers visible at to the world.
+        * rsa-md4.h: __STDC__ condition also checks _WINDOWS
+
+Thu Mar 16 21:19:55 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (CFLAGS):  Tweak for Unix->MPW converter.
+	(LDFLAGS):  Remove, conflicts with pre.in.
+	(all):  Remove all-$(WHAT) stuff, generalize for all platforms.
+	(t_mddriver):  Remove t_mddriver-$(WHAT) stuff, ditto.
+	(check):  Use $(EXEEXT).
+
+Tue Mar 14 17:24:57 1995 Keith Vetter (keithv@fusion.com)
+
+	* md4crypto.c: removed method for DLL data since everything's
+           going into one DLL.
+
+Fri Mar 3 19:01:59 1995 Keith Vetter (keithv@fusion.com)
+
+	* md4crypto.c: added a method to pull in a data structure 
+           from outside a dll.
+
+Thu Mar 2 17:53:35 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed LIBNAME for the PC
+
+Tue Feb 28 00:19:06 1995  John Gilmore  (gnu at toad.com)
+
+	* rsa-md4.h:  Avoid <krb5/...> includes.
+
+Mon Feb 20 15:54:1 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work for the PC
+        * md4.c, md4crypt.c md4glue.c: added windows INTERFACE keyword
+        * rsa-md4.h: added windows INTERFACE to prototypes
+
+Thu Feb  2 03:00:41 1995  John Gilmore  <gnu@cygnus.com>
+
+	* Makefile.in (CFLAGS):  Handle $(srcdir) properly in -I options.
+
+Wed Jan 25 20:08:47 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (CFLAGS):  Add -I../des to pull in DES header file.
+	* 
+rsa-md4.h:  New include file, moved from include/krb5, since
+	it's only used locally.
+	* md4.c, md4crypto.c, md4driver.c, md4glue.c:  Replace <.../...>
+	includes with "..."s.
+
+Thu Oct 13 17:48:21 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Add support for the MDx test driver t_mddriver.
+		Run t_mddriver on a "make check", to make sure we have a
+		valid MD4 implementation.
+
+	* md4.c (UL): Add the UL macro to control how unsigned long
+		constants are compiled.  If we have an ANSI C environment,
+		use the UL suffix to keep the compiler from warning about
+		numbers that would overflow a signed long.
+
+Tue Oct  4 14:54:19 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* md4crypto.c:
+	* md4glue.c: Added placeholder for magic number.
+
diff --git a/mechglue/src/lib/crypto/md4/ISSUES b/mechglue/src/lib/crypto/md4/ISSUES
new file mode 100644
index 000000000..1103bd87b
--- /dev/null
+++ b/mechglue/src/lib/crypto/md4/ISSUES
@@ -0,0 +1,3 @@
+Issues to be addressed for src/lib/crypto/md4: -*- text -*-
+
+Assumes int is >= 32 bits.
diff --git a/mechglue/src/lib/crypto/md4/Makefile.in b/mechglue/src/lib/crypto/md4/Makefile.in
new file mode 100644
index 000000000..4dd977e3c
--- /dev/null
+++ b/mechglue/src/lib/crypto/md4/Makefile.in
@@ -0,0 +1,68 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/md4
+mydir=md4
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=md4
+##DOS##OBJFILE=..\$(OUTPRE)md4.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= md4.o
+
+OBJS= $(OUTPRE)md4.$(OBJEXT) 
+
+SRCS= $(srcdir)/md4.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+t_mddriver.c: $(srcdir)/../md5/t_mddriver.c
+	$(CP) $(srcdir)/../md5/t_mddriver.c t_mddriver.c
+
+t_mddriver.o: t_mddriver.c
+	$(CC) -DMD=4 $(ALL_CFLAGS) -c  t_mddriver.c
+
+t_mddriver: t_mddriver.o md4.o $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o t_mddriver t_mddriver.o md4.o $(SUPPORT_LIB)
+
+$(OUTPRE)t_mddriver.obj: t_mddriver.c
+	$(CC) -DMD=4 $(ALL_CFLAGS) -Fo$@ -c $**
+
+$(OUTPRE)t_mddriver.exe: $(OUTPRE)t_mddriver.obj $(OUTPRE)md4.obj
+	link -out:$@ $**
+
+check-unix:: t_mddriver
+	$(RUN_SETUP) $(C)t_mddriver -x
+
+check-windows:: $(OUTPRE)t_mddriver.exe
+	$(OUTPRE)$(C)t_mddriver.exe -x
+
+clean:: 
+	$(RM) $(OUTPRE)t_mddriver$(EXEEXT) $(OUTPRE)t_mddriver.$(OBJEXT) t_mddriver.c
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+md4.so md4.po $(OUTPRE)md4.$(OBJEXT): md4.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h rsa-md4.h
diff --git a/mechglue/src/lib/crypto/md4/md4.c b/mechglue/src/lib/crypto/md4/md4.c
new file mode 100644
index 000000000..5e95d359f
--- /dev/null
+++ b/mechglue/src/lib/crypto/md4/md4.c
@@ -0,0 +1,257 @@
+/*
+ *	lib/crypto/md4/md4.c
+ */
+
+/*
+ **********************************************************************
+ ** md4.c                                                            **
+ ** RSA Data Security, Inc. MD4 Message Digest Algorithm             **
+ ** Created: 2/17/90 RLR                                             **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version                  **
+ **********************************************************************
+ */
+
+/*
+ **********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ **                                                                  **
+ ** License to copy and use this software is granted provided that   **
+ ** it is identified as the "RSA Data Security, Inc. MD4 Message     **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function.                                       **
+ **                                                                  **
+ ** License is also granted to make and use derivative works         **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD4 Message Digest Algorithm" in all         **
+ ** material mentioning or referencing the derived work.             **
+ **                                                                  **
+ ** RSA Data Security, Inc. makes no representations concerning      **
+ ** either the merchantability of this software or the suitability   **
+ ** of this software for any particular purpose.  It is provided "as **
+ ** is" without express or implied warranty of any kind.             **
+ **                                                                  **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software.                                   **
+ **********************************************************************
+ */
+
+#include "k5-int.h"
+#include "rsa-md4.h"
+
+/* forward declaration */
+static void Transform (krb5_ui_4 *, krb5_ui_4 *);
+
+static const unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) ((((x) << (n)) & 0xffffffff) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are MD4 transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) \
+  {(a) += F ((b), (c), (d)) + (x); \
+   (a) &= 0xffffffff; \
+   (a) = ROTATE_LEFT ((a), (s));}
+#define GG(a, b, c, d, x, s) \
+  {(a) += G ((b), (c), (d)) + (x) + 013240474631UL; \
+   (a) &= 0xffffffff; \
+   (a) = ROTATE_LEFT ((a), (s));}
+#define HH(a, b, c, d, x, s) \
+  {(a) += H ((b), (c), (d)) + (x) + 015666365641UL; \
+   (a) &= 0xffffffff; \
+   (a) = ROTATE_LEFT ((a), (s));}
+
+void
+krb5_MD4Init (krb5_MD4_CTX *mdContext)
+{
+  mdContext->i[0] = mdContext->i[1] = (krb5_ui_4)0;
+
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = 0x67452301UL;
+  mdContext->buf[1] = 0xefcdab89UL;
+  mdContext->buf[2] = 0x98badcfeUL;
+  mdContext->buf[3] = 0x10325476UL;
+}
+
+void
+krb5_MD4Update (krb5_MD4_CTX *mdContext, const unsigned char *inBuf, unsigned int inLen)
+{
+  krb5_ui_4 in[16];
+  int mdi;
+  unsigned int i, ii;
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((krb5_ui_4)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((krb5_ui_4)inLen << 3);
+  mdContext->i[1] += ((krb5_ui_4)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((krb5_ui_4)mdContext->in[ii+3]) << 24) |
+                (((krb5_ui_4)mdContext->in[ii+2]) << 16) |
+                (((krb5_ui_4)mdContext->in[ii+1]) << 8) |
+                ((krb5_ui_4)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+void
+krb5_MD4Final (krb5_MD4_CTX *mdContext)
+{
+  krb5_ui_4 in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  krb5_MD4Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((krb5_ui_4)mdContext->in[ii+3]) << 24) |
+            (((krb5_ui_4)mdContext->in[ii+2]) << 16) |
+            (((krb5_ui_4)mdContext->in[ii+1]) << 8) |
+            ((krb5_ui_4)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
+
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+}
+
+/* Basic MD4 step. Transform buf based on in.
+ */
+static void Transform (krb5_ui_4 *buf, krb5_ui_4 *in)
+{
+  register krb5_ui_4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+#ifdef CONFIG_SMALL
+  int i;
+#define ROTATE { krb5_ui_4 temp; temp = d, d = c, c = b, b = a, a = temp; }
+  for (i = 0; i < 16; i++) {
+      static const unsigned char round1consts[] = { 3, 7, 11, 19, };
+      FF (a, b, c, d, in[i], round1consts[i%4]); ROTATE;
+  }
+  for (i = 0; i < 16; i++) {
+      static const unsigned char round2indices[] = {
+	  0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15
+      };
+      static const unsigned char round2consts[] = { 3, 5, 9, 13 };
+      GG (a, b, c, d, in[round2indices[i]], round2consts[i%4]); ROTATE;
+  }
+  for (i = 0; i < 16; i++) {
+      static const unsigned char round3indices[] = {
+	  0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
+      };
+      static const unsigned char round3consts[] = { 3, 9, 11, 15 };
+      HH (a, b, c, d, in[round3indices[i]], round3consts[i%4]); ROTATE;
+  }
+#else
+  /* Round 1 */
+  FF (a, b, c, d, in[ 0],  3);
+  FF (d, a, b, c, in[ 1],  7);
+  FF (c, d, a, b, in[ 2], 11);
+  FF (b, c, d, a, in[ 3], 19);
+  FF (a, b, c, d, in[ 4],  3);
+  FF (d, a, b, c, in[ 5],  7);
+  FF (c, d, a, b, in[ 6], 11);
+  FF (b, c, d, a, in[ 7], 19);
+  FF (a, b, c, d, in[ 8],  3);
+  FF (d, a, b, c, in[ 9],  7);
+  FF (c, d, a, b, in[10], 11);
+  FF (b, c, d, a, in[11], 19);
+  FF (a, b, c, d, in[12],  3);
+  FF (d, a, b, c, in[13],  7);
+  FF (c, d, a, b, in[14], 11);
+  FF (b, c, d, a, in[15], 19);
+
+  /* Round 2 */
+  GG (a, b, c, d, in[ 0],  3);
+  GG (d, a, b, c, in[ 4],  5);
+  GG (c, d, a, b, in[ 8],  9);
+  GG (b, c, d, a, in[12], 13);
+  GG (a, b, c, d, in[ 1],  3);
+  GG (d, a, b, c, in[ 5],  5);
+  GG (c, d, a, b, in[ 9],  9);
+  GG (b, c, d, a, in[13], 13);
+  GG (a, b, c, d, in[ 2],  3);
+  GG (d, a, b, c, in[ 6],  5);
+  GG (c, d, a, b, in[10],  9);
+  GG (b, c, d, a, in[14], 13);
+  GG (a, b, c, d, in[ 3],  3);
+  GG (d, a, b, c, in[ 7],  5);
+  GG (c, d, a, b, in[11],  9);
+  GG (b, c, d, a, in[15], 13);
+
+  /* Round 3 */
+  HH (a, b, c, d, in[ 0],  3);
+  HH (d, a, b, c, in[ 8],  9);
+  HH (c, d, a, b, in[ 4], 11);
+  HH (b, c, d, a, in[12], 15);
+  HH (a, b, c, d, in[ 2],  3);
+  HH (d, a, b, c, in[10],  9);
+  HH (c, d, a, b, in[ 6], 11);
+  HH (b, c, d, a, in[14], 15);
+  HH (a, b, c, d, in[ 1],  3);
+  HH (d, a, b, c, in[ 9],  9);
+  HH (c, d, a, b, in[ 5], 11);
+  HH (b, c, d, a, in[13], 15);
+  HH (a, b, c, d, in[ 3],  3);
+  HH (d, a, b, c, in[11],  9);
+  HH (c, d, a, b, in[ 7], 11);
+  HH (b, c, d, a, in[15], 15);
+#endif
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+/*
+ **********************************************************************
+ ** End of md4.c                                                     **
+ ******************************* (cut) ********************************
+ */
diff --git a/mechglue/src/lib/crypto/md4/rsa-md4.h b/mechglue/src/lib/crypto/md4/rsa-md4.h
new file mode 100644
index 000000000..d4e6f6b79
--- /dev/null
+++ b/mechglue/src/lib/crypto/md4/rsa-md4.h
@@ -0,0 +1,94 @@
+/*
+ * lib/crypto/md4/rsa-md4.h
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * RSA MD4 header file, with Kerberos/STDC additions.
+ */
+
+#ifndef __KRB5_RSA_MD4_H__
+#define __KRB5_RSA_MD4_H__
+
+#ifdef unicos61
+#include <sys/types.h>
+#endif /* unicos61 */
+
+/* 16 u_char's in the digest */
+#define RSA_MD4_CKSUM_LENGTH	16
+/* des blocksize is 8, so this works nicely... */
+#define OLD_RSA_MD4_DES_CKSUM_LENGTH	16
+#define NEW_RSA_MD4_DES_CKSUM_LENGTH	24
+#define	RSA_MD4_DES_CONFOUND_LENGTH	8
+
+/*
+ **********************************************************************
+ ** md4.h -- Header file for implementation of MD4                   **
+ ** RSA Data Security, Inc. MD4 Message Digest Algorithm             **
+ ** Created: 2/17/90 RLR                                             **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version              **
+ **********************************************************************
+ */
+
+/*
+ **********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ **                                                                  **
+ ** License to copy and use this software is granted provided that   **
+ ** it is identified as the "RSA Data Security, Inc. MD4 Message     **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function.                                       **
+ **                                                                  **
+ ** License is also granted to make and use derivative works         **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD4 Message Digest Algorithm" in all         **
+ ** material mentioning or referencing the derived work.             **
+ **                                                                  **
+ ** RSA Data Security, Inc. makes no representations concerning      **
+ ** either the merchantability of this software or the suitability   **
+ ** of this software for any particular purpose.  It is provided "as **
+ ** is" without express or implied warranty of any kind.             **
+ **                                                                  **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software.                                   **
+ **********************************************************************
+ */
+
+/* Data structure for MD4 (Message Digest) computation */
+typedef struct {
+  krb5_ui_4 i[2];			/* number of _bits_ handled mod 2^64 */
+  krb5_ui_4 buf[4];			/* scratch buffer */
+  unsigned char in[64];			/* input buffer */
+  unsigned char digest[16];		/* actual digest after MD4Final call */
+} krb5_MD4_CTX;
+
+extern void krb5_MD4Init(krb5_MD4_CTX *);
+extern void krb5_MD4Update(krb5_MD4_CTX *, const unsigned char *, unsigned int);
+extern void krb5_MD4Final(krb5_MD4_CTX *);
+
+/*
+ **********************************************************************
+ ** End of md4.h                                                     **
+ ******************************* (cut) ********************************
+ */
+#endif /* __KRB5_RSA_MD4_H__ */
diff --git a/mechglue/src/lib/crypto/md5/.Sanitize b/mechglue/src/lib/crypto/md5/.Sanitize
new file mode 100644
index 000000000..b8f8a6431
--- /dev/null
+++ b/mechglue/src/lib/crypto/md5/.Sanitize
@@ -0,0 +1,42 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+md5.c
+md5crypto.c
+md5glue.c
+rsa-md5.h
+t_cksum.c
+t_mddriver.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/crypto/md5/ChangeLog b/mechglue/src/lib/crypto/md5/ChangeLog
new file mode 100644
index 000000000..bd9a81712
--- /dev/null
+++ b/mechglue/src/lib/crypto/md5/ChangeLog
@@ -0,0 +1,319 @@
+2006-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_mddriver): Include support library.  Use
+	CC_LINK.
+
+2005-05-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* md5.c (Transform) [CONFIG_SMALL]: Roll loops for each round.
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* md5.c: Use ANSI C style function definitions.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* rsa-md5.h (rsa_md5_cksumtable_entry,
+	rsa_md5_des_cksumtable_entry): Delete unused declarations.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_mddriver.c: Make prototypes unconditional.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* md5.c, rsa-md5.h: Don't explicitly declare pointers FAR any
+	more.
+
+2001-06-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_mddriver.c: Cleanup assignments in conditionals w/o parentheses.
+	Add parenthesis abount structure initializers.
+
+2001-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* rsa-md5.h: Always use prototypes.
+
+	* md5.c: Use UL suffix instead of UL macro.
+	(UL): Macro deleted.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* md5.c (PADDING): Now const.
+	(krb5_MD5Update): Argument inBuf now points to const.
+	(ROTATE_LEFT): Change (a&b|c) construct to silence gcc warning.
+	* rsa-md5.h (krb5_MD5Update): Update decl.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:20:16 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Sun Jul 19 12:00:00 1998  Marc Horowitz <marc@mit.edu>
+
+	* *.c: replace the crypto layer.
+
+Tue Mar  3 08:42:10 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (t_cksum): Do not depend on libkrb5.a, use 
+	KRB5_BASE_DEPLIBS.
+
+Wed Feb 18 16:07:46 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 15:20:54 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (thisconfigdir), configure.in: Point the
+ 		configuration directory at our parent, and remove our
+		local configure.in
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Oct 28 16:36:30 1997  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* md5.c: Fix to deal with types longer than 32 bits.
+
+Sat Feb 22 18:54:09 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Thu Feb  6 12:48:41 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (t_cksum): Link with libkrb5.a as well.
+
+Thu Jan 30 21:42:50 1997  Richard Basch  <basch@lehman.com>
+
+	* md5crypto.c md5glue.c:
+		Change functions to take const args where possible
+
+Thu Nov 21 00:58:04 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: Win32 build
+
+Sun Dec 29 21:54:24 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to use new library building procedure.
+
+Wed Jun 12 00:11:34 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* rsa-md5.h:
+	* md5.c: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS
+
+Tue May 21 20:29:03 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (check-unix): Use KRB5_RUN_FLAGS 
+
+Mon May 20 17:19:00 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* md5crypto.c, md5crypto.h: Change use of RSA_MD5_DES_CKSUM_LENGTH
+ 		to use OLD_RSA_MD5_DES_CKSUM_LENGTH and
+ 		NEW_RSA_MD5_DES_CKSUM_LENGTH, as appropriate.
+
+	* t_cksum.c (main): Use proper header file constants to get the
+ 		correct checksum length for the MD4 and MD5 old-style and
+ 		new-style checksum functions.
+
+Sat May 18 01:49:33 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* md5crypto.c: Define MD5_K5BETA_COMPAT and MD5_K5BETA_COMP_DEF so
+ 		that we continue doing things the wrong (broken) way.  All
+ 		hail backwards compatibility....  The code now generates
+ 		the old checksum, but it will verify both the old and the
+ 		correct checksum formats.
+
+		Also fixed two bugs in the "correct" MD5_CRYPTO
+		implementation; use a zero initialization vector, and
+		calculate the confounder at the beginning of the message,
+		not at the end.  
+
+Tue May 14 19:32:51 1996  Richard Basch  <basch@lehman.com>
+
+	* md5crypto.c md5glue.c:
+		ensure the cksum content length is sufficient.
+
+	* t_cksum.c: initialize cksum.length
+
+Fri May 10 01:19:18 1996  Richard Basch  <basch@lehman.com>
+
+	* md5crypto.c: des3-md5 is being replaced with des3-sha
+
+Fri Apr 12 21:27:35 1996  Richard Basch  <basch@lehman.com>
+
+	* rsa-md5.h md5crypto.c md5glue.c md5.c t_cksum.c t_mddriver.c:
+	Renamed the global functions to be krb5_<name>
+
+Thu Mar 28 09:50:58 1996  Richard Basch  <basch@lehman.com>
+
+	* md5crypto.c: Added support for CKSUMTYPE_RSA_MD5_DES3
+
+Sat Jan 27 00:56:38 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* t_cksum.c (main): use proper old-style definition.
+
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * t_cksum.c : Remove krb5_enctype from krb5_string_to_key() args.
+
+Fri Oct  6 22:00:32 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:49:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 13 10:30:58 1995 Keith Vetter (keithv@fusion.com)
+
+	* md5crypt.c: put function prototype back in, fixed signed/unsigned
+		mismatch and removed unused variables.
+	* md5glue.c: put function prototypes back in.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * md5crypto.c, t_cksum.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * md5crypto.c : Replace KEYTYPE_DES_CBC_MD5 for KEYTYPE_DES.
+
+	* t_cksum.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate.
+
+Thu Aug 24 18:40:48 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Thu Jul 27 15:22:42 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* rsa-md5.h - Add this file, relocated from include/krb5.
+
+
+Fri Jul 7 16:20:07 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add t_cksum under unix only.
+	* configure.in - Define MD5_K5BETA_COMPAT to select compatability for
+		md5crypto.c.
+	* md5crypto.c - Correct implementation of RSA-MD5-DES checksums.  Add
+		ability to understand previous implementation and ability to
+		generate these checksums when forced to.
+		- Also add verification procedure for these checksums.
+	* md5glue.c - Add verifier procedure.
+	* t_cksum.c - New checksum verifier test.
+
+Wed Jun 21 10:52:20 1995    <tytso@rsx-11.mit.edu>
+
+	* md5crypto.c, md5glue.c: Change PROTOTYPE -> KRB5_PROTOTYPE
+
+Fri Jun  9 19:18:24 1995    <tytso@rsx-11.mit.edu>
+
+	* md5crypto.c: Fix -Wall nits
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu May 25 22:16:26 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for shared libraries.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+        * *.h added FAR to pointers visible at to the world.
+
+Thu Mar 16 21:23:03 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Remove, conflicts with pre.in.
+	(all):  Remove all-$(WHAT) stuff.
+	(t_mddriver):  Make it build on Mac.
+	(check):  Use $(EXEEXT).
+
+Tue Mar 14 17:24:57 1995 Keith Vetter (keithv@fusion.com)
+
+	* md5crypto.c: removed method for DLL data since everything's
+           going into one DLL.
+
+Fri Mar 3 19:01:59 1995 Keith Vetter (keithv@fusion.com)
+
+	* md5crypto.c: added a method to pull in a data structure 
+           from outside a dll.
+
+Thu Mar 2 17:54:26 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed LIBNAME for the PC
+
+Tue Feb 28 00:20:15 1995  John Gilmore  (gnu at toad.com)
+
+	* md5.c, md5crypto.c, md5glue.c, t_mddriver.c:  Avoid <krb5/...>
+	includes.
+
+Mon Feb 20 15:54:1 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work for the PC
+        * md5.c, md5crypt.c md5glue.c: added windows INTERFACE keyword
+
+Thu Feb  2 03:01:28 1995  John Gilmore  <gnu@cygnus.com>
+
+	* Makefile.in (CFLAGS):  Handle $(srcdir) properly in -I options.
+
+Wed Jan 25 20:11:30 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (CFLAGS):  Use -I../des to pull in include file.
+	* md5.c, md5crypto.c, md5glue.c, t_mddriver.c:  Replace <.../...>
+	includes with "..."s.
+
+Fri Oct 14 00:22:19 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* t_mddriver.c (MDString, MDTestSuite): Cast char pointer to the
+		expected unsigned char pointer, since that's what MDUpdate
+		requires. 
+
+Thu Oct 13 17:50:19 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Add support for the MDx test driver t_mddriver.
+		Run t_mddriver on a "make check", to make sure we have a
+		valid MD5 implementation.
+
+	* md5.c (UL): Add the UL macro to control how unsigned long
+		constants are compiled.  If we have an ANSI C environment,
+		use the UL suffix to keep the compiler from warning about
+		numbers that would overflow a signed long.
+
+Tue Oct  4 14:55:10 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* md5crypto.c:
+	* md5glue.c: Added placeholder for magic number.
+
+
diff --git a/mechglue/src/lib/crypto/md5/ISSUES b/mechglue/src/lib/crypto/md5/ISSUES
new file mode 100644
index 000000000..481e52914
--- /dev/null
+++ b/mechglue/src/lib/crypto/md5/ISSUES
@@ -0,0 +1,3 @@
+Issues to be addressed for src/lib/crypto/md5: -*- text -*-
+
+Assumes int is >= 32 bits.
diff --git a/mechglue/src/lib/crypto/md5/Makefile.in b/mechglue/src/lib/crypto/md5/Makefile.in
new file mode 100644
index 000000000..35f14fafc
--- /dev/null
+++ b/mechglue/src/lib/crypto/md5/Makefile.in
@@ -0,0 +1,58 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/md5
+mydir=md5
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=md5
+##DOS##OBJFILE=..\$(OUTPRE)md5.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= md5.o
+
+OBJS= $(OUTPRE)md5.$(OBJEXT) 
+
+SRCS= $(srcdir)/md5.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+t_mddriver: t_mddriver.o md5.o $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o t_mddriver t_mddriver.o md5.o $(SUPPORT_LIB)
+
+$(OUTPRE)t_mddriver.exe: $(OUTPRE)t_mddriver.obj $(OUTPRE)md5.obj
+	link -out:$@ $**
+
+check-unix:: t_mddriver
+	$(RUN_SETUP) $(C)t_mddriver -x
+
+check-windows:: $(OUTPRE)t_mddriver.exe
+	$(OUTPRE)$(C)t_mddriver.exe -x
+
+clean:: 
+	$(RM) $(OUTPRE)t_mddriver$(EXEEXT) $(OUTPRE)t_mddriver.$(OBJEXT)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+md5.so md5.po $(OUTPRE)md5.$(OBJEXT): md5.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h rsa-md5.h
diff --git a/mechglue/src/lib/crypto/md5/md5.c b/mechglue/src/lib/crypto/md5/md5.c
new file mode 100644
index 000000000..4b56755a8
--- /dev/null
+++ b/mechglue/src/lib/crypto/md5/md5.c
@@ -0,0 +1,355 @@
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines                         **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ * Modified by John Carr, MIT, to use Kerberos 5 typedefs.
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#include "k5-int.h"
+#include "rsa-md5.h"
+
+/*
+ ***********************************************************************
+ **  Message-digest routines:                                         **
+ **  To form the message digest for a message M                       **
+ **    (1) Initialize a context buffer mdContext using krb5_MD5Init   **
+ **    (2) Call krb5_MD5Update on mdContext and M                     **
+ **    (3) Call krb5_MD5Final on mdContext                            **
+ **  The message digest is now in mdContext->digest[0...15]           **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform (krb5_ui_4 *buf, krb5_ui_4 *in);
+
+static const unsigned char PADDING[64] = {
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) ((((x) << (n)) & 0xffffffff) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+  {(a) += F ((b), (c), (d)) + (x) + (krb5_ui_4)(ac); \
+   (a) &= 0xffffffff; \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+   (a) &= 0xffffffff; \
+  }
+#define GG(a, b, c, d, x, s, ac) \
+  {(a) += G ((b), (c), (d)) + (x) + (krb5_ui_4)(ac); \
+   (a) &= 0xffffffff; \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+   (a) &= 0xffffffff; \
+  }
+#define HH(a, b, c, d, x, s, ac) \
+  {(a) += H ((b), (c), (d)) + (x) + (krb5_ui_4)(ac); \
+   (a) &= 0xffffffff; \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+   (a) &= 0xffffffff; \
+  }
+#define II(a, b, c, d, x, s, ac) \
+  {(a) += I ((b), (c), (d)) + (x) + (krb5_ui_4)(ac); \
+   (a) &= 0xffffffff; \
+   (a) = ROTATE_LEFT ((a), (s)); \
+   (a) += (b); \
+   (a) &= 0xffffffff; \
+  }
+
+/* The routine krb5_MD5Init initializes the message-digest context
+   mdContext. All fields are set to zero.
+ */
+void 
+krb5_MD5Init (krb5_MD5_CTX *mdContext)
+{
+  mdContext->i[0] = mdContext->i[1] = (krb5_ui_4)0;
+
+  /* Load magic initialization constants.
+   */
+  mdContext->buf[0] = 0x67452301UL;
+  mdContext->buf[1] = 0xefcdab89UL;
+  mdContext->buf[2] = 0x98badcfeUL;
+  mdContext->buf[3] = 0x10325476UL;
+}
+
+/* The routine krb5_MD5Update updates the message-digest context to
+   account for the presence of each of the characters inBuf[0..inLen-1]
+   in the message whose digest is being computed.
+ */
+void
+krb5_MD5Update (krb5_MD5_CTX *mdContext, const unsigned char *inBuf, unsigned int inLen)
+{
+  krb5_ui_4 in[16];
+  int mdi;
+  unsigned int i, ii;
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* update number of bits */
+  if ((mdContext->i[0] + ((krb5_ui_4)inLen << 3)) < mdContext->i[0])
+    mdContext->i[1]++;
+  mdContext->i[0] += ((krb5_ui_4)inLen << 3);
+  mdContext->i[1] += ((krb5_ui_4)inLen >> 29);
+
+  while (inLen--) {
+    /* add new character to buffer, increment mdi */
+    mdContext->in[mdi++] = *inBuf++;
+
+    /* transform if necessary */
+    if (mdi == 0x40) {
+      for (i = 0, ii = 0; i < 16; i++, ii += 4)
+        in[i] = (((krb5_ui_4)mdContext->in[ii+3]) << 24) |
+                (((krb5_ui_4)mdContext->in[ii+2]) << 16) |
+                (((krb5_ui_4)mdContext->in[ii+1]) << 8) |
+                ((krb5_ui_4)mdContext->in[ii]);
+      Transform (mdContext->buf, in);
+      mdi = 0;
+    }
+  }
+}
+
+/* The routine krb5_MD5Final terminates the message-digest computation and
+   ends with the desired message digest in mdContext->digest[0...15].
+ */
+void
+krb5_MD5Final (krb5_MD5_CTX *mdContext)
+{
+  krb5_ui_4 in[16];
+  int mdi;
+  unsigned int i, ii;
+  unsigned int padLen;
+
+  /* save number of bits */
+  in[14] = mdContext->i[0];
+  in[15] = mdContext->i[1];
+
+  /* compute number of bytes mod 64 */
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+  /* pad out to 56 mod 64 */
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+  krb5_MD5Update (mdContext, PADDING, padLen);
+
+  /* append length in bits and transform */
+  for (i = 0, ii = 0; i < 14; i++, ii += 4)
+    in[i] = (((krb5_ui_4)mdContext->in[ii+3]) << 24) |
+            (((krb5_ui_4)mdContext->in[ii+2]) << 16) |
+            (((krb5_ui_4)mdContext->in[ii+1]) << 8) |
+            ((krb5_ui_4)mdContext->in[ii]);
+  Transform (mdContext->buf, in);
+
+  /* store buffer in digest */
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+    mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+    mdContext->digest[ii+1] =
+      (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+    mdContext->digest[ii+2] =
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+    mdContext->digest[ii+3] =
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+  }
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (krb5_ui_4 *buf, krb5_ui_4 *in)
+{
+  register krb5_ui_4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+#ifdef CONFIG_SMALL
+
+  int i;
+#define ROTATE { krb5_ui_4 temp; temp = d, d = c, c = b, b = a, a = temp; }
+  for (i = 0; i < 16; i++) {
+      const unsigned char round1s[] = { 7, 12, 17, 22 };
+      const krb5_ui_4 round1consts[] = {
+	  3614090360UL,	  3905402710UL,	   606105819UL,	  3250441966UL,
+	  4118548399UL,	  1200080426UL,	  2821735955UL,	  4249261313UL,
+	  1770035416UL,	  2336552879UL,	  4294925233UL,	  2304563134UL,
+	  1804603682UL,	  4254626195UL,	  2792965006UL,	  1236535329UL,
+      };
+      FF (a, b, c, d, in[i], round1s[i%4], round1consts[i]);
+      ROTATE;
+  }
+  for (i = 0; i < 16; i++) {
+      const unsigned char round2s[] = { 5, 9, 14, 20 };
+      const krb5_ui_4 round2consts[] = {
+	  4129170786UL,	  3225465664UL,	   643717713UL,	  3921069994UL,
+	  3593408605UL,	    38016083UL,	  3634488961UL,	  3889429448UL,
+	   568446438UL,	  3275163606UL,	  4107603335UL,	  1163531501UL,
+	  2850285829UL,	  4243563512UL,	  1735328473UL,	  2368359562UL,
+      };
+      int r2index = (1 + i * 5) % 16;
+      GG (a, b, c, d, in[r2index], round2s[i%4], round2consts[i]);
+      ROTATE;
+  }
+  for (i = 0; i < 16; i++) {
+      static const unsigned char round3s[] = { 4, 11, 16, 23 };
+      static const krb5_ui_4 round3consts[] = {
+	  4294588738UL,	  2272392833UL,	  1839030562UL,	  4259657740UL,
+	  2763975236UL,	  1272893353UL,	  4139469664UL,	  3200236656UL,
+	   681279174UL,	  3936430074UL,	  3572445317UL,	    76029189UL,
+	  3654602809UL,	  3873151461UL,	   530742520UL,	  3299628645UL,
+      };
+      int r3index = (5 + i * 3) % 16;
+      HH (a, b, c, d, in[r3index], round3s[i%4], round3consts[i]);
+      ROTATE;
+  }
+  for (i = 0; i < 16; i++) {
+      static const unsigned char round4s[] = { 6, 10, 15, 21 };
+      static const krb5_ui_4 round4consts[] = {
+	  4096336452UL,	  1126891415UL,	  2878612391UL,	  4237533241UL,
+	  1700485571UL,	  2399980690UL,	  4293915773UL,	  2240044497UL,
+	  1873313359UL,	  4264355552UL,	  2734768916UL,	  1309151649UL,
+	  4149444226UL,	  3174756917UL,	   718787259UL,	  3951481745UL,
+      };
+      int r4index = (7 * i) % 16;
+      II (a, b, c, d, in[r4index], round4s[i%4], round4consts[i]);
+      ROTATE;
+  }
+
+#else
+
+  /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+  FF ( a, b, c, d, in[ 0], S11, 3614090360UL); /* 1 */
+  FF ( d, a, b, c, in[ 1], S12, 3905402710UL); /* 2 */
+  FF ( c, d, a, b, in[ 2], S13,  606105819UL); /* 3 */
+  FF ( b, c, d, a, in[ 3], S14, 3250441966UL); /* 4 */
+  FF ( a, b, c, d, in[ 4], S11, 4118548399UL); /* 5 */
+  FF ( d, a, b, c, in[ 5], S12, 1200080426UL); /* 6 */
+  FF ( c, d, a, b, in[ 6], S13, 2821735955UL); /* 7 */
+  FF ( b, c, d, a, in[ 7], S14, 4249261313UL); /* 8 */
+  FF ( a, b, c, d, in[ 8], S11, 1770035416UL); /* 9 */
+  FF ( d, a, b, c, in[ 9], S12, 2336552879UL); /* 10 */
+  FF ( c, d, a, b, in[10], S13, 4294925233UL); /* 11 */
+  FF ( b, c, d, a, in[11], S14, 2304563134UL); /* 12 */
+  FF ( a, b, c, d, in[12], S11, 1804603682UL); /* 13 */
+  FF ( d, a, b, c, in[13], S12, 4254626195UL); /* 14 */
+  FF ( c, d, a, b, in[14], S13, 2792965006UL); /* 15 */
+  FF ( b, c, d, a, in[15], S14, 1236535329UL); /* 16 */
+
+  /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+  GG ( a, b, c, d, in[ 1], S21, 4129170786UL); /* 17 */
+  GG ( d, a, b, c, in[ 6], S22, 3225465664UL); /* 18 */
+  GG ( c, d, a, b, in[11], S23,  643717713UL); /* 19 */
+  GG ( b, c, d, a, in[ 0], S24, 3921069994UL); /* 20 */
+  GG ( a, b, c, d, in[ 5], S21, 3593408605UL); /* 21 */
+  GG ( d, a, b, c, in[10], S22,   38016083UL); /* 22 */
+  GG ( c, d, a, b, in[15], S23, 3634488961UL); /* 23 */
+  GG ( b, c, d, a, in[ 4], S24, 3889429448UL); /* 24 */
+  GG ( a, b, c, d, in[ 9], S21,  568446438UL); /* 25 */
+  GG ( d, a, b, c, in[14], S22, 3275163606UL); /* 26 */
+  GG ( c, d, a, b, in[ 3], S23, 4107603335UL); /* 27 */
+  GG ( b, c, d, a, in[ 8], S24, 1163531501UL); /* 28 */
+  GG ( a, b, c, d, in[13], S21, 2850285829UL); /* 29 */
+  GG ( d, a, b, c, in[ 2], S22, 4243563512UL); /* 30 */
+  GG ( c, d, a, b, in[ 7], S23, 1735328473UL); /* 31 */
+  GG ( b, c, d, a, in[12], S24, 2368359562UL); /* 32 */
+
+  /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+  HH ( a, b, c, d, in[ 5], S31, 4294588738UL); /* 33 */
+  HH ( d, a, b, c, in[ 8], S32, 2272392833UL); /* 34 */
+  HH ( c, d, a, b, in[11], S33, 1839030562UL); /* 35 */
+  HH ( b, c, d, a, in[14], S34, 4259657740UL); /* 36 */
+  HH ( a, b, c, d, in[ 1], S31, 2763975236UL); /* 37 */
+  HH ( d, a, b, c, in[ 4], S32, 1272893353UL); /* 38 */
+  HH ( c, d, a, b, in[ 7], S33, 4139469664UL); /* 39 */
+  HH ( b, c, d, a, in[10], S34, 3200236656UL); /* 40 */
+  HH ( a, b, c, d, in[13], S31,  681279174UL); /* 41 */
+  HH ( d, a, b, c, in[ 0], S32, 3936430074UL); /* 42 */
+  HH ( c, d, a, b, in[ 3], S33, 3572445317UL); /* 43 */
+  HH ( b, c, d, a, in[ 6], S34,   76029189UL); /* 44 */
+  HH ( a, b, c, d, in[ 9], S31, 3654602809UL); /* 45 */
+  HH ( d, a, b, c, in[12], S32, 3873151461UL); /* 46 */
+  HH ( c, d, a, b, in[15], S33,  530742520UL); /* 47 */
+  HH ( b, c, d, a, in[ 2], S34, 3299628645UL); /* 48 */
+
+  /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+  II ( a, b, c, d, in[ 0], S41, 4096336452UL); /* 49 */
+  II ( d, a, b, c, in[ 7], S42, 1126891415UL); /* 50 */
+  II ( c, d, a, b, in[14], S43, 2878612391UL); /* 51 */
+  II ( b, c, d, a, in[ 5], S44, 4237533241UL); /* 52 */
+  II ( a, b, c, d, in[12], S41, 1700485571UL); /* 53 */
+  II ( d, a, b, c, in[ 3], S42, 2399980690UL); /* 54 */
+  II ( c, d, a, b, in[10], S43, 4293915773UL); /* 55 */
+  II ( b, c, d, a, in[ 1], S44, 2240044497UL); /* 56 */
+  II ( a, b, c, d, in[ 8], S41, 1873313359UL); /* 57 */
+  II ( d, a, b, c, in[15], S42, 4264355552UL); /* 58 */
+  II ( c, d, a, b, in[ 6], S43, 2734768916UL); /* 59 */
+  II ( b, c, d, a, in[13], S44, 1309151649UL); /* 60 */
+  II ( a, b, c, d, in[ 4], S41, 4149444226UL); /* 61 */
+  II ( d, a, b, c, in[11], S42, 3174756917UL); /* 62 */
+  II ( c, d, a, b, in[ 2], S43,  718787259UL); /* 63 */
+  II ( b, c, d, a, in[ 9], S44, 3951481745UL); /* 64 */
+
+#endif /* small? */
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
diff --git a/mechglue/src/lib/crypto/md5/rsa-md5.h b/mechglue/src/lib/crypto/md5/rsa-md5.h
new file mode 100644
index 000000000..846b23856
--- /dev/null
+++ b/mechglue/src/lib/crypto/md5/rsa-md5.h
@@ -0,0 +1,60 @@
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5                    **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **
+ ** Created: 2/17/90 RLR                                              **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **
+ ** Revised (for MD5): RLR 4/27/91                                    **
+ **   -- G modified to have y&~z instead of y&z                       **
+ **   -- FF, GG, HH modified to add in last register done             **
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **
+ **   -- distinct additive constant for each step                     **
+ **   -- round 4 added, working mod 7                                 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **
+ **                                                                   **
+ ** License to copy and use this software is granted provided that    **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **
+ ** Digest Algorithm" in all material mentioning or referencing this  **
+ ** software or this function.                                        **
+ **                                                                   **
+ ** License is also granted to make and use derivative works          **
+ ** provided that such works are identified as "derived from the RSA  **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **
+ ** material mentioning or referencing the derived work.              **
+ **                                                                   **
+ ** RSA Data Security, Inc. makes no representations concerning       **
+ ** either the merchantability of this software or the suitability    **
+ ** of this software for any particular purpose.  It is provided "as  **
+ ** is" without express or implied warranty of any kind.              **
+ **                                                                   **
+ ** These notices must be retained in any copies of any part of this  **
+ ** documentation and/or software.                                    **
+ ***********************************************************************
+ */
+
+#ifndef	KRB5_RSA_MD5__
+#define	KRB5_RSA_MD5__
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+  krb5_ui_4 i[2];			/* number of _bits_ handled mod 2^64 */
+  krb5_ui_4 buf[4];			/* scratch buffer */
+  unsigned char in[64];			/* input buffer */
+  unsigned char digest[16];		/* actual digest after MD5Final call */
+} krb5_MD5_CTX;
+
+extern void krb5_MD5Init(krb5_MD5_CTX *);
+extern void krb5_MD5Update(krb5_MD5_CTX *,const unsigned char *,unsigned int);
+extern void krb5_MD5Final(krb5_MD5_CTX *);
+
+#define	RSA_MD5_CKSUM_LENGTH		16
+#define	OLD_RSA_MD5_DES_CKSUM_LENGTH	16
+#define	NEW_RSA_MD5_DES_CKSUM_LENGTH	24
+#define	RSA_MD5_DES_CONFOUND_LENGTH	8
+
+#endif /* KRB5_RSA_MD5__ */
diff --git a/mechglue/src/lib/crypto/md5/t_cksum.c b/mechglue/src/lib/crypto/md5/t_cksum.c
new file mode 100644
index 000000000..17ecd51d7
--- /dev/null
+++ b/mechglue/src/lib/crypto/md5/t_cksum.c
@@ -0,0 +1,206 @@
+/*
+ * lib/crypto/md5/t_cksum.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * t_cksum.c - Test checksum and checksum compatability for rsa-md[4,5]-des
+ */
+
+#ifndef	MD
+#define	MD	5
+#endif	/* MD */
+
+#include "k5-int.h"
+#if	MD == 4
+#include "rsa-md4.h"
+#endif	/* MD == 4 */
+#if	MD == 5
+#include "rsa-md5.h"
+#endif	/* MD == 5 */
+#include "des_int.h"
+
+#define MD5_K5BETA_COMPAT
+#define MD4_K5BETA_COMPAT
+
+#if	MD == 4
+#define	CONFOUNDER_LENGTH	RSA_MD4_DES_CONFOUND_LENGTH
+#define	NEW_CHECKSUM_LENGTH	NEW_RSA_MD4_DES_CKSUM_LENGTH
+#define	OLD_CHECKSUM_LENGTH	OLD_RSA_MD4_DES_CKSUM_LENGTH
+#define	CHECKSUM_TYPE		CKSUMTYPE_RSA_MD4_DES
+#ifdef	MD4_K5BETA_COMPAT
+#define	K5BETA_COMPAT	1
+#else	/* MD4_K5BETA_COMPAT */
+#undef	K5BETA_COMPAT
+#endif	/* MD4_K5BETA_COMPAT */
+#define	CKSUM_FUNCTION		krb5_md4_crypto_sum_func
+#define	COMPAT_FUNCTION		krb5_md4_crypto_compat_sum_func
+#define	VERIFY_FUNCTION		krb5_md4_crypto_verify_func
+#endif	/* MD == 4 */
+
+#if	MD == 5
+#define	CONFOUNDER_LENGTH	RSA_MD5_DES_CONFOUND_LENGTH
+#define	NEW_CHECKSUM_LENGTH	NEW_RSA_MD5_DES_CKSUM_LENGTH
+#define	OLD_CHECKSUM_LENGTH	OLD_RSA_MD5_DES_CKSUM_LENGTH
+#define	CHECKSUM_TYPE		CKSUMTYPE_RSA_MD5_DES
+#ifdef	MD5_K5BETA_COMPAT
+#define	K5BETA_COMPAT	1
+#else	/* MD5_K5BETA_COMPAT */
+#undef	K5BETA_COMPAT
+#endif	/* MD5_K5BETA_COMPAT */
+#define	CKSUM_FUNCTION		krb5_md5_crypto_sum_func
+#define	COMPAT_FUNCTION		krb5_md5_crypto_compat_sum_func
+#define	VERIFY_FUNCTION		krb5_md5_crypto_verify_func
+#endif	/* MD == 5 */
+
+static void
+print_checksum(text, number, message, checksum)
+     char	*text;
+     int	number;
+     char	*message;
+     krb5_checksum	*checksum;
+{
+  int i;
+
+  printf("%s MD%d checksum(\"%s\") = ", text, number, message);
+  for (i=0; i<checksum->length; i++)
+    printf("%02x", checksum->contents[i]);
+  printf("\n");
+}
+
+/*
+ * Test the checksum verification of Old Style (tm) and correct RSA-MD[4,5]-DES
+ * checksums.
+ */
+int
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+  int 			msgindex;
+  krb5_context		kcontext;
+  krb5_encrypt_block	encblock;
+  krb5_keyblock		keyblock;
+  krb5_error_code	kret;
+  krb5_checksum		oldstyle_checksum;
+  krb5_checksum		newstyle_checksum;
+  krb5_data		pwdata;
+  char			*pwd;
+
+  pwd = "test password";
+  pwdata.length = strlen(pwd);
+  pwdata.data = pwd;
+  krb5_use_enctype(kcontext, &encblock, DEFAULT_KDC_ENCTYPE);
+  if ((kret = mit_des_string_to_key(&encblock, &keyblock, &pwdata, NULL))) {
+    printf("mit_des_string_to_key choked with %d\n", kret);
+    return(kret);
+  }
+  if ((kret = mit_des_process_key(&encblock, &keyblock))) {
+    printf("mit_des_process_key choked with %d\n", kret);
+    return(kret);
+  }
+
+  oldstyle_checksum.length = OLD_CHECKSUM_LENGTH;
+  if (!(oldstyle_checksum.contents = (krb5_octet *) malloc(OLD_CHECKSUM_LENGTH))) {
+    printf("cannot get memory for old style checksum\n");
+    return(ENOMEM);
+  }
+  newstyle_checksum.length = NEW_CHECKSUM_LENGTH;
+  if (!(newstyle_checksum.contents = (krb5_octet *)
+	malloc(NEW_CHECKSUM_LENGTH))) {
+    printf("cannot get memory for new style checksum\n");
+    return(ENOMEM);
+  }
+  for (msgindex = 1; msgindex < argc; msgindex++) {
+    if ((kret = CKSUM_FUNCTION(argv[msgindex],
+			       strlen(argv[msgindex]),
+			       (krb5_pointer) keyblock.contents,
+			       keyblock.length,
+			       &newstyle_checksum))) {
+      printf("krb5_calculate_checksum choked with %d\n", kret);
+      break;
+    }
+    print_checksum("correct", MD, argv[msgindex], &newstyle_checksum);
+#ifdef	K5BETA_COMPAT
+    if ((kret = COMPAT_FUNCTION(argv[msgindex],
+				strlen(argv[msgindex]),
+				(krb5_pointer) keyblock.contents,
+				keyblock.length,
+				&oldstyle_checksum))) {
+      printf("old style calculate_checksum choked with %d\n", kret);
+      break;
+    }
+    print_checksum("old", MD, argv[msgindex], &oldstyle_checksum);
+#endif	/* K5BETA_COMPAT */
+    if ((kret = VERIFY_FUNCTION(&newstyle_checksum,
+				argv[msgindex],
+				strlen(argv[msgindex]),
+				(krb5_pointer) keyblock.contents,
+				keyblock.length))) {
+      printf("verify on new checksum choked with %d\n", kret);
+      break;
+    }
+    printf("Verify succeeded for \"%s\"\n", argv[msgindex]);
+#ifdef	K5BETA_COMPAT
+    if ((kret = VERIFY_FUNCTION(&oldstyle_checksum,
+				argv[msgindex],
+				strlen(argv[msgindex]),
+				(krb5_pointer) keyblock.contents,
+				keyblock.length))) {
+      printf("verify on old checksum choked with %d\n", kret);
+      break;
+    }
+    printf("Compatible checksum verify succeeded for \"%s\"\n",
+	   argv[msgindex]);
+#endif	/* K5BETA_COMPAT */
+    newstyle_checksum.contents[0]++;
+    if (!(kret = VERIFY_FUNCTION(&newstyle_checksum,
+				 argv[msgindex],
+				 strlen(argv[msgindex]),
+				 (krb5_pointer) keyblock.contents,
+				 keyblock.length))) {
+      printf("verify on new checksum should have choked\n");
+      break;
+    }
+    printf("Verify of bad checksum OK for \"%s\"\n", argv[msgindex]);
+#ifdef	K5BETA_COMPAT
+    oldstyle_checksum.contents[0]++;
+    if (!(kret = VERIFY_FUNCTION(&oldstyle_checksum,
+				 argv[msgindex],
+				 strlen(argv[msgindex]),
+				 (krb5_pointer) keyblock.contents,
+				 keyblock.length))) {
+      printf("verify on old checksum should have choked\n");
+      break;
+    }
+    printf("Compatible checksum verify of altered checksum OK for \"%s\"\n",
+	   argv[msgindex]);
+#endif	/* K5BETA_COMPAT */
+    kret = 0;
+  }
+  if (!kret)
+    printf("%d tests passed successfully for MD%d checksum\n", argc-1, MD);
+  return(kret);
+}
diff --git a/mechglue/src/lib/crypto/md5/t_mddriver.c b/mechglue/src/lib/crypto/md5/t_mddriver.c
new file mode 100644
index 000000000..d894aaaec
--- /dev/null
+++ b/mechglue/src/lib/crypto/md5/t_mddriver.c
@@ -0,0 +1,323 @@
+/* MDDRIVER.C - test driver for MD2, MD4 and MD5
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+rights reserved.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* The following makes MD default to MD5 if it has not already been
+  defined with C compiler flags.
+ */
+#ifndef MD
+#define MD 5
+#endif
+
+#include "k5-int.h"
+
+#if MD == 2
+#include "md2.h"
+#endif
+#if MD == 4
+#include "rsa-md4.h"
+#endif
+#if MD == 5
+#include "rsa-md5.h"
+#endif
+
+/* Length of test block, number of test blocks.
+ */
+#define TEST_BLOCK_LEN 1000
+#define TEST_BLOCK_COUNT 1000
+
+static void MDString (char *);
+static void MDTimeTrial (void);
+static void MDTestSuite (void);
+static void MDFile (char *);
+static void MDFilter (void);
+static void MDPrint (unsigned char [16]);
+
+struct md_test_entry {
+    char *string;
+    unsigned char digest[16];
+};
+
+#if MD == 2
+#define MD_CTX krb5_MD2_CTX
+#define MDInit krb5_MD2Init
+#define MDUpdate krb5_MD2Update
+#define MDFinal krb5_MD2Final
+#endif
+
+#if MD == 4
+#define MD_CTX krb5_MD4_CTX
+#define MDInit krb5_MD4Init
+#define MDUpdate krb5_MD4Update
+#define MDFinal krb5_MD4Final
+
+#define HAVE_TEST_SUITE
+/* Test suite from RFC 1320 */
+
+struct md_test_entry md_test_suite[] = {
+    { "",
+	  {0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
+	   0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0 }},
+    { "a",
+	  {0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46,
+	   0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24 }},
+    { "abc",
+	  {0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52,
+	   0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d }},
+    { "message digest",
+	  {0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8,
+	   0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b }},
+    { "abcdefghijklmnopqrstuvwxyz",
+	  {0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd,
+	   0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9 }},
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+	  {0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35,
+	  0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4 }},
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	  {0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19,
+	   0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36 }},
+    {0, {0}}
+};
+
+#endif
+
+#if MD == 5
+#define MD_CTX krb5_MD5_CTX
+#define MDInit krb5_MD5Init
+#define MDUpdate krb5_MD5Update
+#define MDFinal krb5_MD5Final
+
+#define HAVE_TEST_SUITE
+/* Test suite from RFC 1321 */
+
+struct md_test_entry md_test_suite[] = {
+    { "",
+	  {0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+	   0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e }},
+    { "a",
+	  {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+	   0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 }},
+    { "abc",
+	  {0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+	   0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 }},
+    { "message digest",
+	  {0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
+	   0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 }},
+    { "abcdefghijklmnopqrstuvwxyz",
+	  {0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
+	   0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b }},
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 
+	  {0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
+	   0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f }},
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	  {0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
+	   0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a }},
+    { 0, {0} }
+};
+	
+#endif
+
+/* Main driver.
+
+Arguments (may be any combination):
+  -sstring - digests string
+  -t       - runs time trial
+  -x       - runs test script
+  filename - digests file
+  (none)   - digests standard input
+ */
+int main (argc, argv)
+int argc;
+char *argv[];
+{
+  int i;
+
+  if (argc > 1)
+ for (i = 1; i < argc; i++)
+   if (argv[i][0] == '-' && argv[i][1] == 's')
+     MDString (argv[i] + 2);
+   else if (strcmp (argv[i], "-t") == 0)
+     MDTimeTrial ();
+   else if (strcmp (argv[i], "-x") == 0)
+     MDTestSuite ();
+   else
+     MDFile (argv[i]);
+  else
+ MDFilter ();
+
+  return (0);
+}
+
+/* Digests a string and prints the result.
+ */
+static void MDString (string)
+char *string;
+{
+  MD_CTX context;
+  unsigned int len = strlen (string);
+
+  MDInit (&context);
+  MDUpdate (&context, (unsigned char *) string, len);
+  MDFinal (&context);
+
+  printf ("MD%d (\"%s\") = ", MD, string);
+  MDPrint (context.digest);
+  printf ("\n");
+}
+
+/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte
+  blocks.
+ */
+static void MDTimeTrial ()
+{
+  MD_CTX context;
+  time_t endTime, startTime;
+  unsigned char block[TEST_BLOCK_LEN];
+  unsigned int i;
+  
+  printf("MD%d time trial. Digesting %d %d-byte blocks ...", MD,
+  TEST_BLOCK_LEN, TEST_BLOCK_COUNT);
+
+  /* Initialize block */
+  for (i = 0; i < TEST_BLOCK_LEN; i++)
+ block[i] = (unsigned char)(i & 0xff);
+
+  /* Start timer */
+  time (&startTime);
+
+  /* Digest blocks */
+  MDInit (&context);
+  for (i = 0; i < TEST_BLOCK_COUNT; i++)
+      MDUpdate (&context, block, TEST_BLOCK_LEN);
+  MDFinal (&context);
+
+  /* Stop timer */
+  time (&endTime);
+
+  printf (" done\n");
+  printf ("Digest = ");
+  MDPrint (context.digest);
+  printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));
+  printf
+ ("Speed = %ld bytes/second\n",
+  (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));
+}
+
+/* Digests a reference suite of strings and prints the results.
+ */
+static void MDTestSuite ()
+{
+#ifdef HAVE_TEST_SUITE
+    MD_CTX context;
+    struct md_test_entry *entry;
+    int	i, num_tests = 0, num_failed = 0;
+    
+    printf ("MD%d test suite:\n\n", MD);
+    for (entry = md_test_suite; entry->string; entry++) {
+	unsigned int len = strlen (entry->string);
+
+	MDInit (&context);
+	MDUpdate (&context, (unsigned char *) entry->string, len);
+	MDFinal (&context);
+
+	printf ("MD%d (\"%s\") = ", MD, entry->string);
+	MDPrint (context.digest);
+	printf ("\n");
+	for (i=0; i < 16; i++) {
+	    if (context.digest[i] != entry->digest[i]) {
+		printf("\tIncorrect MD%d digest!  Should have been:\n\t\t ",
+		       MD);
+		MDPrint(entry->digest);
+		printf("\n");
+		num_failed++;
+	    }
+	}
+	num_tests++;
+    }
+    if (num_failed) {
+	printf("%d out of %d tests failed for MD%d!!!\n", num_failed,
+	       num_tests, MD);
+	exit(1);
+    } else {
+	printf ("%d tests passed successfully for MD%d.\n", num_tests, MD);
+	exit(0);
+    }
+#else
+  
+    printf ("MD%d test suite:\n", MD);
+    MDString ("");
+    MDString ("a");
+    MDString ("abc");
+    MDString ("message digest");
+    MDString ("abcdefghijklmnopqrstuvwxyz");
+    MDString
+	("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+    MDString
+	("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+#endif
+}
+
+/* Digests a file and prints the result. */
+
+static void MDFile (filename)
+    char *filename;
+{
+    FILE *file;
+    MD_CTX context;
+    int len;
+    unsigned char buffer[1024];
+
+    if ((file = fopen (filename, "rb")) == NULL)
+	printf ("%s can't be opened\n", filename);
+    else {
+	MDInit (&context);
+	while ((len = fread (buffer, 1, 1024, file)) != 0)
+	    MDUpdate (&context, buffer, len);
+	MDFinal (&context);
+
+	fclose (file);
+
+	printf ("MD%d (%s) = ", MD, filename);
+	MDPrint (context.digest);
+	printf ("\n");
+    }
+}
+
+/* Digests the standard input and prints the result.
+ */
+static void MDFilter ()
+{
+  MD_CTX context;
+  int len;
+  unsigned char buffer[16];
+
+  MDInit (&context);
+  while ((len = fread (buffer, 1, 16, stdin)) != 0)
+    MDUpdate (&context, buffer, len);
+  MDFinal (&context);
+
+  MDPrint (context.digest);
+  printf ("\n");
+}
+
+/* Prints a message digest in hexadecimal.
+ */
+static void MDPrint (digest)
+unsigned char digest[16];
+{
+  unsigned int i;
+
+  for (i = 0; i < 16; i++)
+ printf ("%02x", digest[i]);
+}
diff --git a/mechglue/src/lib/crypto/nfold.c b/mechglue/src/lib/crypto/nfold.c
new file mode 100644
index 000000000..1f1902d1c
--- /dev/null
+++ b/mechglue/src/lib/crypto/nfold.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/*
+n-fold(k-bits):
+  l = lcm(n,k)
+  r = l/k
+  s = k-bits | k-bits rot 13 | k-bits rot 13*2 | ... | k-bits rot 13*(r-1)
+  compute the 1's complement sum:
+	n-fold = s[0..n-1]+s[n..2n-1]+s[2n..3n-1]+..+s[(k-1)*n..k*n-1]
+*/
+
+/* representation: msb first, assume n and k are multiples of 8, and
+   that k>=16.  this is the case of all the cryptosystems which are
+   likely to be used.  this function can be replaced if that
+   assumption ever fails.  */
+
+/* input length is in bits */
+
+void
+krb5_nfold(unsigned int inbits, const unsigned char *in, unsigned int outbits,
+	   unsigned char *out)
+{
+    int a,b,c,lcm;
+    int byte, i, msbit;
+
+    /* the code below is more readable if I make these bytes
+       instead of bits */
+
+    inbits >>= 3;
+    outbits >>= 3;
+
+    /* first compute lcm(n,k) */
+
+    a = outbits;
+    b = inbits;
+
+    while(b != 0) {
+	c = b;
+	b = a%b;
+	a = c;
+    }
+
+    lcm = outbits*inbits/a;
+
+    /* now do the real work */
+
+    memset(out, 0, outbits);
+    byte = 0;
+
+    /* this will end up cycling through k lcm(k,n)/k times, which
+       is correct */
+    for (i=lcm-1; i>=0; i--) {
+	/* compute the msbit in k which gets added into this byte */
+	msbit = (/* first, start with the msbit in the first, unrotated
+		    byte */
+		 ((inbits<<3)-1)
+		 /* then, for each byte, shift to the right for each
+		    repetition */
+		 +(((inbits<<3)+13)*(i/inbits))
+		 /* last, pick out the correct byte within that
+		    shifted repetition */
+		 +((inbits-(i%inbits))<<3)
+		 )%(inbits<<3);
+
+	/* pull out the byte value itself */
+	byte += (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
+		  (in[((inbits)-(msbit>>3))%inbits]))
+		 >>((msbit&7)+1))&0xff;
+
+	/* do the addition */
+	byte += out[i%outbits];
+	out[i%outbits] = byte&0xff;
+
+#if 0
+	printf("msbit[%d] = %d\tbyte = %02x\tsum = %03x\n", i, msbit,
+	       (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
+		 (in[((inbits)-(msbit>>3))%inbits]))
+		>>((msbit&7)+1))&0xff, byte);
+#endif
+
+	/* keep around the carry bit, if any */
+	byte >>= 8;
+
+#if 0
+	printf("carry=%d\n", byte);
+#endif
+    }
+
+    /* if there's a carry bit left over, add it back in */
+    if (byte) {
+	for (i=outbits-1; i>=0; i--) {
+	    /* do the addition */
+	    byte += out[i];
+	    out[i] = byte&0xff;
+
+	    /* keep around the carry bit, if any */
+	    byte >>= 8;
+	}
+    }
+}
+
diff --git a/mechglue/src/lib/crypto/old/ChangeLog b/mechglue/src/lib/crypto/old/ChangeLog
new file mode 100644
index 000000000..34d257f6c
--- /dev/null
+++ b/mechglue/src/lib/crypto/old/ChangeLog
@@ -0,0 +1,122 @@
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* des_stringtokey.c: Use ANSI C style function definitions.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* old_decrypt.c (krb5_old_decrypt): Use block_size and hashsize
+	fields instead of calling functions.
+	* old_encrypt.c (krb5_old_encrypt_length, krb5_old_encrypt):
+	Likewise.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-05-23  Sam Hartman  <hartmans@mit.edu>
+
+	* des_stringtokey.c (krb5int_des_string_to_key): If param has  one
+	byte, treat it as a type.   Type 0 is normal, type 1 is AFS
+	string2key. 
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* des_stringtokey.c (krb5int_des_string_to_key): Renamed from
+	krb5_... and added s2k-params argument which must be null.
+	* old.h: Updated.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* des_stringtokey.c, old.h: Make prototypes unconditional.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* des_stringtokey.c: Don't explicitly declare pointers FAR any
+	more.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* old_decrypt.c (krb5_old_decrypt): Fix casts.
+	* old_encrypt.c (krb5_old_encrypt): Likewise.
+
+2001-03-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (STLIBOBJS): Undo last change.
+
+2001-03-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* old_decrypt.c (memmove): Delete macro definition.
+	(krb5_old_decrypt): Define with prototype form.
+	* old_encrypt.c (krb5_old_encrypt_length, krb5_old_encrypt):
+	Define with prototype form.
+
+	* Makefile.in (STLIBOBJS): Nothing uses des_stringtokey.o, drop
+	it.
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* des_stringtokey.c, old.h, old_decrypt.c, old_encrypt.c: Use
+	const instead of krb5_const.
+
+2000-06-03  Tom Yu  <tlyu@mit.edu>
+
+	* old_encrypt.c (krb5_old_encrypt): Chain ivecs.
+
+	* old_decrypt.c (krb5_old_decrypt): Chain ivecs.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* des_stringtokey.c (mit_des_string_to_key_int): Declare.
+	* old_decrypt.c (krb5_old_decrypt): Delete unused variable.
+	Change if(a=b) constructs to silence gcc warning.
+	* old_encrypt.c (krb5_old_encrypt): Change if(a=b) constructs to
+	silence gcc warning.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* old_decrypt.c (memmove) [HAVE_BCOPY && !HAVE_MEMMOVE]: Define to
+	use bcopy.  Should work unless any system has no memmove *and*
+	bcopy isn't safe with overlaps.
+
+Mon May 10 15:20:32 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Wed Dec 16 16:14:02 1998  Tom Yu  <tlyu@mit.edu>
+
+	* old_decrypt.c (krb5_old_decrypt): Initialize the ivec to the key
+ 	if we're using DES_CBC_CRC, for backwards compatibility.  We
+ 	weren't noticing this before because it only trashes the first
+ 	block, which is the confounder, which we weren't actually
+ 	verifying because checksum was unconditionally succeeding prior to
+ 	the other patch.
+
+Thu Dec 10 22:16:14 1998  Tom Yu  <tlyu@mit.edu>
+
+	* old_decrypt.c (krb5_old_decrypt): Actually compare the
+	calculated checksum against the provided checksum.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
diff --git a/mechglue/src/lib/crypto/old/Makefile.in b/mechglue/src/lib/crypto/old/Makefile.in
new file mode 100644
index 000000000..b467fc593
--- /dev/null
+++ b/mechglue/src/lib/crypto/old/Makefile.in
@@ -0,0 +1,60 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/old
+mydir=old
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/../des
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=old
+##DOS##OBJFILE=..\$(OUTPRE)old.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= old_decrypt.o old_encrypt.o des_stringtokey.o
+
+OBJS= $(OUTPRE)des_stringtokey.$(OBJEXT) $(OUTPRE)old_decrypt.$(OBJEXT) $(OUTPRE)old_encrypt.$(OBJEXT)
+
+SRCS= $(srcdir)/des_stringtokey.c $(srcdir)/old_decrypt.c \
+	$(srcdir)/old_encrypt.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+des_stringtokey.so des_stringtokey.po $(OUTPRE)des_stringtokey.$(OBJEXT): \
+  des_stringtokey.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  old.h $(srcdir)/../des/des_int.h $(SRCTOP)/include/kerberosIV/des.h
+old_decrypt.so old_decrypt.po $(OUTPRE)old_decrypt.$(OBJEXT): \
+  old_decrypt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  old.h
+old_encrypt.so old_encrypt.po $(OUTPRE)old_encrypt.$(OBJEXT): \
+  old_encrypt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  old.h
diff --git a/mechglue/src/lib/crypto/old/des_stringtokey.c b/mechglue/src/lib/crypto/old/des_stringtokey.c
new file mode 100644
index 000000000..2bacb4ef9
--- /dev/null
+++ b/mechglue/src/lib/crypto/old/des_stringtokey.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "old.h"
+#include <des_int.h>
+
+/* XXX */
+extern krb5_error_code mit_des_string_to_key_int
+(krb5_keyblock * keyblock,
+		 const krb5_data * data,
+		 const krb5_data * salt);
+
+krb5_error_code
+krb5int_des_string_to_key(const struct krb5_enc_provider *enc,
+			  const krb5_data *string,
+			  const krb5_data *salt, const krb5_data *parm,
+			  krb5_keyblock *key)
+{
+    int type;
+    if (parm ) {
+	if (parm->length != 1)
+	    return KRB5_ERR_BAD_S2K_PARAMS;
+	type = parm->data[0];
+    }
+    else type = 0;
+    switch(type) {
+    case 0:
+    return(mit_des_string_to_key_int(key, string, salt));
+    case 1:
+	return mit_afs_string_to_key(key, string, salt);
+    default:
+	return KRB5_ERR_BAD_S2K_PARAMS;
+    }
+}
diff --git a/mechglue/src/lib/crypto/old/old.h b/mechglue/src/lib/crypto/old/old.h
new file mode 100644
index 000000000..94ee6421e
--- /dev/null
+++ b/mechglue/src/lib/crypto/old/old.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+void krb5_old_encrypt_length
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		size_t input, size_t *length);
+
+krb5_error_code krb5_old_encrypt
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec, const krb5_data *input,
+		krb5_data *output);
+
+krb5_error_code krb5_old_decrypt
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec, const krb5_data *input,
+		krb5_data *arg_output);
+
+krb5_error_code krb5int_des_string_to_key
+(const struct krb5_enc_provider *enc,
+		const krb5_data *string, const krb5_data *salt,
+		const krb5_data *params,
+		krb5_keyblock *key);
diff --git a/mechglue/src/lib/crypto/old/old_decrypt.c b/mechglue/src/lib/crypto/old/old_decrypt.c
new file mode 100644
index 000000000..cfbbd7272
--- /dev/null
+++ b/mechglue/src/lib/crypto/old/old_decrypt.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "old.h"
+
+krb5_error_code
+krb5_old_decrypt(const struct krb5_enc_provider *enc,
+		 const struct krb5_hash_provider *hash,
+		 const krb5_keyblock *key,
+		 krb5_keyusage usage,
+		 const krb5_data *ivec,
+		 const krb5_data *input,
+		 krb5_data *arg_output)
+{
+    krb5_error_code ret;
+    size_t blocksize, hashsize, plainsize;
+    unsigned char *cksumdata, *cn;
+    krb5_data output, cksum, crcivec;
+    int alloced;
+
+    blocksize = enc->block_size;
+    hashsize = hash->hashsize;
+
+    plainsize = input->length - blocksize - hashsize;
+
+    if (arg_output->length < plainsize)
+	return(KRB5_BAD_MSIZE);
+
+    /* if there's enough space to work in the app buffer, use it,
+       otherwise allocate our own */
+
+    if ((cksumdata = (unsigned char *) malloc(hashsize)) == NULL)
+	return(ENOMEM);
+
+    if (arg_output->length < input->length) {
+	output.length = input->length;
+
+	if ((output.data = (char *) malloc(output.length)) == NULL) {
+	    free(cksumdata);
+	    return(ENOMEM);
+	}
+
+	alloced = 1;
+    } else {
+	output.length = input->length;
+
+	output.data = arg_output->data;
+
+	alloced = 0;
+    }
+
+    /* decrypt it */
+
+    /* save last ciphertext block in case we decrypt in place */
+    if (ivec != NULL && ivec->length == blocksize) {
+	cn = malloc(blocksize);
+	if (cn == NULL) {
+	    ret = ENOMEM;
+	    goto cleanup;
+	}
+	memcpy(cn, input->data + input->length - blocksize, blocksize);
+    } else
+	cn = NULL;
+
+    /* XXX this is gross, but I don't have much choice */
+    if ((key->enctype == ENCTYPE_DES_CBC_CRC) && (ivec == 0)) {
+	crcivec.length = key->length;
+	crcivec.data = (char *) key->contents;
+	ivec = &crcivec;
+    }
+
+    if ((ret = ((*(enc->decrypt))(key, ivec, input, &output))))
+	goto cleanup;
+
+    /* verify the checksum */
+
+    memcpy(cksumdata, output.data+blocksize, hashsize);
+    memset(output.data+blocksize, 0, hashsize);
+
+    cksum.length = hashsize;
+    cksum.data = output.data+blocksize;
+
+    if ((ret = ((*(hash->hash))(1, &output, &cksum))))
+	goto cleanup;
+
+    if (memcmp(cksum.data, cksumdata, cksum.length) != 0) {
+	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+	goto cleanup;
+    }
+
+    /* copy the plaintext around */
+
+    if (alloced) {
+	memcpy(arg_output->data, output.data+blocksize+hashsize,
+	       plainsize);
+    } else {
+	memmove(arg_output->data, arg_output->data+blocksize+hashsize,
+		plainsize);
+    }
+    arg_output->length = plainsize;
+
+    /* update ivec */
+    if (cn != NULL)
+	memcpy(ivec->data, cn, blocksize);
+
+    ret = 0;
+
+cleanup:
+    if (alloced) {
+	memset(output.data, 0, output.length);
+	free(output.data);
+    }
+
+    if (cn != NULL)
+	free(cn);
+    memset(cksumdata, 0, hashsize);
+    free(cksumdata);
+    return(ret);
+}
diff --git a/mechglue/src/lib/crypto/old/old_encrypt.c b/mechglue/src/lib/crypto/old/old_encrypt.c
new file mode 100644
index 000000000..98bd109e0
--- /dev/null
+++ b/mechglue/src/lib/crypto/old/old_encrypt.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "old.h"
+
+void
+krb5_old_encrypt_length(const struct krb5_enc_provider *enc,
+			const struct krb5_hash_provider *hash,
+			size_t inputlen,
+			size_t *length)
+{
+    size_t blocksize, hashsize;
+
+    blocksize = enc->block_size;
+    hashsize = hash->hashsize;
+
+    *length = krb5_roundup(blocksize+hashsize+inputlen, blocksize);
+}
+
+krb5_error_code
+krb5_old_encrypt(const struct krb5_enc_provider *enc,
+		 const struct krb5_hash_provider *hash,
+		 const krb5_keyblock *key,
+		 krb5_keyusage usage,
+		 const krb5_data *ivec,
+		 const krb5_data *input,
+		 krb5_data *output)
+{
+    krb5_error_code ret;
+    size_t blocksize, hashsize, enclen;
+    krb5_data datain, crcivec;
+    int real_ivec;
+
+    blocksize = enc->block_size;
+    hashsize = hash->hashsize;
+
+    krb5_old_encrypt_length(enc, hash, input->length, &enclen);
+
+    if (output->length < enclen)
+	return(KRB5_BAD_MSIZE);
+
+    output->length = enclen;
+
+    /* fill in confounded, padded, plaintext buffer with zero checksum */
+
+    memset(output->data, 0, output->length);
+
+    datain.length = blocksize;
+    datain.data = output->data;
+
+    if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &datain)))
+	return(ret);
+    memcpy(output->data+blocksize+hashsize, input->data, input->length);
+
+    /* compute the checksum */
+
+    datain.length = hashsize;
+    datain.data = output->data+blocksize;
+
+    if ((ret = ((*(hash->hash))(1, output, &datain))))
+	goto cleanup;
+
+    /* encrypt it */
+
+    /* XXX this is gross, but I don't have much choice */
+    if ((key->enctype == ENCTYPE_DES_CBC_CRC) && (ivec == 0)) {
+	crcivec.length = key->length;
+	crcivec.data = (char *) key->contents;
+	ivec = &crcivec;
+	real_ivec = 0;
+    } else
+	real_ivec = 1;
+
+    if ((ret = ((*(enc->encrypt))(key, ivec, output, output))))
+	goto cleanup;
+
+    /* update ivec */
+    if (real_ivec && ivec != NULL && ivec->length == blocksize)
+	memcpy(ivec->data, output->data + output->length - blocksize,
+	       blocksize);
+cleanup:
+    if (ret)
+	memset(output->data, 0, output->length);
+
+    return(ret);
+}
diff --git a/mechglue/src/lib/crypto/old_api_glue.c b/mechglue/src/lib/crypto/old_api_glue.c
new file mode 100644
index 000000000..fda16909a
--- /dev/null
+++ b/mechglue/src/lib/crypto/old_api_glue.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_encrypt(krb5_context context, krb5_const_pointer inptr,
+	     krb5_pointer outptr, size_t size, krb5_encrypt_block *eblock,
+	     krb5_pointer ivec)
+{
+    krb5_data inputd, ivecd;
+    krb5_enc_data outputd;
+    size_t blocksize, outlen;
+    krb5_error_code ret;
+
+    if (ivec) {
+	if ((ret = krb5_c_block_size(context, eblock->key->enctype, &blocksize)))
+	    return(ret);
+
+	ivecd.length = blocksize;
+	ivecd.data = ivec;
+    }
+
+    /* size is the length of the input cleartext data */
+    inputd.length = size;
+    inputd.data = inptr;
+
+    /* The size of the output buffer isn't part of the old api.  Not too
+       safe.  So, we assume here that it's big enough. */
+    if ((ret = krb5_c_encrypt_length(context, eblock->key->enctype, size,
+				     &outlen)))
+	return(ret);
+
+    outputd.ciphertext.length = outlen;
+    outputd.ciphertext.data = outptr;
+
+    return(krb5_c_encrypt(context, eblock->key, 0, ivec?&ivecd:0,
+			  &inputd, &outputd));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_decrypt(krb5_context context, krb5_const_pointer inptr,
+	     krb5_pointer outptr, size_t size, krb5_encrypt_block *eblock,
+	     krb5_pointer ivec)
+{
+    krb5_enc_data inputd;
+    krb5_data outputd, ivecd;
+    size_t blocksize;
+    krb5_error_code ret;
+
+    if (ivec) {
+	if ((ret = krb5_c_block_size(context, eblock->key->enctype, &blocksize)))
+	    return(ret);
+
+	ivecd.length = blocksize;
+	ivecd.data = ivec;
+    }
+
+    /* size is the length of the input ciphertext data */
+    inputd.enctype = eblock->key->enctype;
+    inputd.ciphertext.length = size;
+    inputd.ciphertext.data = inptr;
+
+    /* we don't really know how big this is, but the code tends to assume
+       that the output buffer size should be the same as the input
+       buffer size */
+    outputd.length = size;
+    outputd.data = outptr;
+
+    return(krb5_c_decrypt(context, eblock->key, 0, ivec?&ivecd:0,
+			  &inputd, &outputd));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_process_key(krb5_context context, krb5_encrypt_block *eblock,
+		 const krb5_keyblock *key)
+{
+    eblock->key = (krb5_keyblock *) key;
+
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_finish_key(krb5_context context, krb5_encrypt_block *eblock)
+{
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_string_to_key(krb5_context context, const krb5_encrypt_block *eblock,
+		   krb5_keyblock *keyblock, const krb5_data *data,
+		   const krb5_data *salt)
+{
+    return(krb5_c_string_to_key(context, eblock->crypto_entry, data, salt,
+				keyblock));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_init_random_key(krb5_context context, const krb5_encrypt_block *eblock,
+		     const krb5_keyblock *keyblock, krb5_pointer *ptr)
+{
+    krb5_data data;
+
+    data.length = keyblock->length;
+    data.data = (char *) keyblock->contents;
+
+    return(krb5_c_random_seed(context, &data));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_finish_random_key(krb5_context context, const krb5_encrypt_block *eblock,
+		       krb5_pointer *ptr)
+{
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_random_key(krb5_context context, const krb5_encrypt_block *eblock,
+		krb5_pointer ptr, krb5_keyblock **keyblock)
+{
+    krb5_keyblock *key;
+    krb5_error_code ret;
+
+    if ((key = (krb5_keyblock *) malloc(sizeof(krb5_keyblock))) == NULL)
+	return(ENOMEM);
+
+    if ((ret = krb5_c_make_random_key(context, eblock->crypto_entry, key)))
+	free(key);
+
+    *keyblock = key;
+
+    return(ret);
+}
+
+krb5_enctype KRB5_CALLCONV
+krb5_eblock_enctype(krb5_context context, const krb5_encrypt_block *eblock)
+{
+    return(eblock->crypto_entry);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_use_enctype(krb5_context context, krb5_encrypt_block *eblock,
+		 krb5_enctype enctype)
+{
+    eblock->crypto_entry = enctype;
+
+    return(0);
+}
+
+size_t KRB5_CALLCONV
+krb5_encrypt_size(size_t length, krb5_enctype crypto)
+{
+    size_t ret;
+
+    if (krb5_c_encrypt_length(/* XXX */ 0, crypto, length, &ret))
+	return(-1); /* XXX */
+
+    return(ret);
+}
+
+size_t KRB5_CALLCONV
+krb5_checksum_size(krb5_context context, krb5_cksumtype ctype)
+{
+    size_t ret;
+
+    if (krb5_c_checksum_length(context, ctype, &ret))
+	return(-1); /* XXX */
+
+    return(ret);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_calculate_checksum(krb5_context context, krb5_cksumtype ctype,
+			krb5_const_pointer in, size_t in_length,
+			krb5_const_pointer seed, size_t seed_length,
+			krb5_checksum *outcksum)
+{
+    krb5_data input;
+    krb5_keyblock key;
+    krb5_error_code ret;
+    krb5_checksum cksum;
+
+    input.data = in;
+    input.length = in_length;
+
+    key.length = seed_length;
+    key.contents = seed;
+
+    if ((ret = krb5_c_make_checksum(context, ctype, &key, 0, &input, &cksum)))
+	return(ret);
+
+    if (outcksum->length < cksum.length) {
+	memset(cksum.contents, 0, cksum.length);
+	free(cksum.contents);
+	return(KRB5_BAD_MSIZE);
+    }
+
+    outcksum->magic = cksum.magic;
+    outcksum->checksum_type = cksum.checksum_type;
+    memcpy(outcksum->contents, cksum.contents, cksum.length);
+    outcksum->length = cksum.length;
+
+    free(cksum.contents);
+    
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
+		     const krb5_checksum *cksum, krb5_const_pointer in,
+		     size_t in_length, krb5_const_pointer seed,
+		     size_t seed_length)
+{
+    krb5_data input;
+    krb5_keyblock key;
+    krb5_error_code ret;
+    krb5_boolean valid;
+
+    input.data = in;
+    input.length = in_length;
+
+    key.length = seed_length;
+    key.contents = seed;
+
+    if ((ret = krb5_c_verify_checksum(context, &key, 0, &input, cksum,
+				      &valid)))
+	return(ret);
+
+    if (!valid)
+	return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
+
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_random_confounder(size_t size, krb5_pointer ptr)
+{
+    krb5_data random_data;
+
+    random_data.length = size;
+    random_data.data = ptr;
+
+    return(krb5_c_random_make_octets(/* XXX */ 0, &random_data));
+}
+
+krb5_error_code krb5_encrypt_data(krb5_context context, krb5_keyblock *key,
+				  krb5_pointer ivec, krb5_data *data,
+				  krb5_enc_data *enc_data)
+{
+    krb5_error_code ret;
+    size_t enclen, blocksize;
+    krb5_data ivecd;
+
+    if ((ret = krb5_c_encrypt_length(context, key->enctype, data->length,
+				     &enclen)))
+	return(ret);
+
+    if (ivec) {
+	if ((ret = krb5_c_block_size(context, key->enctype, &blocksize)))
+	    return(ret);
+
+	ivecd.length = blocksize;
+	ivecd.data = ivec;
+    }
+
+    enc_data->magic = KV5M_ENC_DATA;
+    enc_data->kvno = 0;
+    enc_data->enctype = key->enctype;
+    enc_data->ciphertext.length = enclen;
+    if ((enc_data->ciphertext.data = malloc(enclen)) == NULL)
+	return(ENOMEM);
+
+    if ((ret = krb5_c_encrypt(context, key, 0, ivec?&ivecd:0, data, enc_data)))
+	free(enc_data->ciphertext.data);
+
+    return(ret);
+}
+
+krb5_error_code krb5_decrypt_data(krb5_context context, krb5_keyblock *key,
+				  krb5_pointer ivec, krb5_enc_data *enc_data,
+				  krb5_data *data)
+{
+    krb5_error_code ret;
+    krb5_data ivecd;
+    size_t blocksize;
+
+    if (ivec) {
+	if ((ret = krb5_c_block_size(context, key->enctype, &blocksize)))
+	    return(ret);
+
+	ivecd.length = blocksize;
+	ivecd.data = ivec;
+    }
+
+    data->length = enc_data->ciphertext.length;
+    if ((data->data = (char *) malloc(data->length)) == NULL)
+	return(ENOMEM);
+
+    if ((ret = krb5_c_decrypt(context, key, 0, ivec?&ivecd:0, enc_data, data)))
+	free(data->data);
+
+    return(0);
+}
diff --git a/mechglue/src/lib/crypto/pbkdf2.c b/mechglue/src/lib/crypto/pbkdf2.c
new file mode 100644
index 000000000..ff446dbde
--- /dev/null
+++ b/mechglue/src/lib/crypto/pbkdf2.c
@@ -0,0 +1,268 @@
+/*
+ * lib/crypto/pbkdf2.c
+ *
+ * Copyright 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Implementation of PBKDF2 from RFC 2898.
+ * Not currently used; likely to be used when we get around to AES support.
+ */
+
+#include <ctype.h>
+#include "k5-int.h"
+#include "hash_provider.h"
+
+/* Not exported, for now.  */
+static krb5_error_code
+krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
+				       krb5_data *),
+		size_t hlen, const krb5_data *pass, const krb5_data *salt,
+		unsigned long count, const krb5_data *output);
+
+static int debug_hmac = 0;
+
+static void printd (const char *descr, krb5_data *d) {
+    int i, j;
+    const int r = 16;
+
+    printf("%s:", descr);
+
+    for (i = 0; i < d->length; i += r) {
+	printf("\n  %04x: ", i);
+	for (j = i; j < i + r && j < d->length; j++)
+	    printf(" %02x", 0xff & d->data[j]);
+	for (; j < i + r; j++)
+	    printf("   ");
+	printf("   ");
+	for (j = i; j < i + r && j < d->length; j++) {
+	    int c = 0xff & d->data[j];
+	    printf("%c", isprint(c) ? c : '.');
+	}
+    }
+    printf("\n");
+}
+static void printk(const char *descr, krb5_keyblock *k) {
+    krb5_data d;
+    d.data = (char *) k->contents;
+    d.length = k->length;
+    printd(descr, &d);
+}
+
+static krb5_error_code
+F(char *output, char *u_tmp1, char *u_tmp2,
+  krb5_error_code (*prf)(krb5_keyblock *, krb5_data *, krb5_data *),
+  size_t hlen,
+  const krb5_data *pass, const krb5_data *salt,
+  unsigned long count, int i)
+{
+    unsigned char ibytes[4];
+    size_t tlen;
+    int j, k;
+    krb5_keyblock pdata;
+    krb5_data sdata;
+    krb5_data out;
+    krb5_error_code err;
+
+    pdata.contents = pass->data;
+    pdata.length = pass->length;
+
+#if 0
+    printf("F(i=%d, count=%lu, pass=%d:%s)\n", i, count,
+	   pass->length, pass->data);
+    printk("F password", &pdata);
+#endif
+
+    /* Compute U_1.  */
+    ibytes[3] = i & 0xff;
+    ibytes[2] = (i >> 8) & 0xff;
+    ibytes[1] = (i >> 16) & 0xff;
+    ibytes[0] = (i >> 24) & 0xff;
+
+    tlen = salt->length;
+    memcpy(u_tmp2, salt->data, tlen);
+    memcpy(u_tmp2 + tlen, ibytes, 4);
+    tlen += 4;
+    sdata.data = u_tmp2;
+    sdata.length = tlen;
+
+#if 0
+    printd("initial salt", &sdata);
+#endif
+
+    out.data = u_tmp1;
+    out.length = hlen;
+
+#if 0
+    printf("F: computing hmac #1 (U_1) with %s\n", pdata.contents);
+#endif
+    err = (*prf)(&pdata, &sdata, &out);
+    if (err)
+	return err;
+#if 0
+    printd("F: prf return value", &out);
+#endif
+    memcpy(output, u_tmp1, hlen);
+
+    /* Compute U_2, .. U_c.  */
+    sdata.length = hlen;
+    for (j = 2; j <= count; j++) {
+#if 0
+	printf("F: computing hmac #%d (U_%d)\n", j, j);
+#endif
+	memcpy(u_tmp2, u_tmp1, hlen);
+	err = (*prf)(&pdata, &sdata, &out);
+	if (err)
+	    return err;
+#if 0
+	printd("F: prf return value", &out);
+#endif
+	/* And xor them together.  */
+	for (k = 0; k < hlen; k++)
+	    output[k] ^= u_tmp1[k];
+#if 0
+	printf("F: xor result:\n");
+	for (k = 0; k < hlen; k++)
+	    printf(" %02x", 0xff & output[k]);
+	printf("\n");
+#endif
+    }
+    return 0;
+}
+
+static krb5_error_code
+krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
+				       krb5_data *),
+		size_t hlen,
+		const krb5_data *pass, const krb5_data *salt,
+		unsigned long count, const krb5_data *output)
+{
+    int l, r, i;
+    char *utmp1, *utmp2;
+    char utmp3[20];		/* XXX length shouldn't be hardcoded! */
+
+    if (output->length == 0 || hlen == 0)
+	abort();
+    /* Step 1 & 2.  */
+    if (output->length / hlen > 0xffffffff)
+	abort();
+    /* Step 2.  */
+    l = (output->length + hlen - 1) / hlen;
+    r = output->length - (l - 1) * hlen;
+
+    utmp1 = /*output + dklen; */ malloc(hlen);
+    if (utmp1 == NULL)
+	return errno;
+    utmp2 = /*utmp1 + hlen; */ malloc(salt->length + 4 + hlen);
+    if (utmp2 == NULL) {
+	free(utmp1);
+	return errno;
+    }
+
+    /* Step 3.  */
+    for (i = 1; i <= l; i++) {
+#if 0
+	int j;
+#endif
+	krb5_error_code err;
+	char *out;
+
+	if (i == l)
+	    out = utmp3;
+	else
+	    out = output->data + (i-1) * hlen;
+	err = F(out, utmp1, utmp2, prf, hlen, pass, salt, count, i);
+	if (err) {
+	    free(utmp1);
+	    free(utmp2);
+	    return err;
+	}
+	if (i == l)
+	    memcpy(output->data + (i-1) * hlen, utmp3,
+		   output->length - (i-1) * hlen);
+
+#if 0
+	printf("after F(%d), @%p:\n", i, output->data);
+	for (j = (i-1) * hlen; j < i * hlen; j++)
+	    printf(" %02x", 0xff & output->data[j]);
+	printf ("\n");
+#endif
+    }
+    free(utmp1);
+    free(utmp2);
+    return 0;
+}
+
+static krb5_error_code hmac1(const struct krb5_hash_provider *h,
+			     krb5_keyblock *key, krb5_data *in, krb5_data *out)
+{
+    char tmp[40];
+    size_t blocksize, hashsize;
+    krb5_error_code err;
+    krb5_keyblock k;
+
+    k = *key;
+    key = &k;
+    if (debug_hmac)
+	printk(" test key", key);
+    blocksize = h->blocksize;
+    hashsize = h->hashsize;
+    if (hashsize > sizeof(tmp))
+	abort();
+    if (key->length > blocksize) {
+	krb5_data d, d2;
+	d.data = (char *) key->contents;
+	d.length = key->length;
+	d2.data = tmp;
+	d2.length = hashsize;
+	err = h->hash (1, &d, &d2);
+	if (err)
+	    return err;
+	key->length = d2.length;
+	key->contents = (krb5_octet *) d2.data;
+	if (debug_hmac)
+	    printk(" pre-hashed key", key);
+    }
+    if (debug_hmac)
+	printd(" hmac input", in);
+    err = krb5_hmac(h, key, 1, in, out);
+    if (err == 0 && debug_hmac)
+	printd(" hmac output", out);
+    return err;
+}
+
+static krb5_error_code
+foo(krb5_keyblock *pass, krb5_data *salt, krb5_data *out)
+{
+    krb5_error_code err;
+
+    memset(out->data, 0, out->length);
+    err = hmac1 (&krb5int_hash_sha1, pass, salt, out);
+    return err;
+}
+
+krb5_error_code
+krb5int_pbkdf2_hmac_sha1 (const krb5_data *out, unsigned long count,
+			  const krb5_data *pass, const krb5_data *salt)
+{
+    return krb5int_pbkdf2 (foo, 20, pass, salt, count, out);
+}
diff --git a/mechglue/src/lib/crypto/prf.c b/mechglue/src/lib/crypto/prf.c
new file mode 100644
index 000000000..f52564db4
--- /dev/null
+++ b/mechglue/src/lib/crypto/prf.c
@@ -0,0 +1,87 @@
+/*
+ * lib/crypto/prf.c
+ *
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * 
+ *
+ * This contains the implementation of krb5_c_prf, which  will find
+ *the enctype-specific PRF and then generate pseudo-random data.  This
+ *function yields krb5_c_prf_length bytes of output.
+ */
+
+
+#include "k5-int.h"
+#include "etypes.h"
+
+#include <assert.h>
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_prf_length(krb5_context context, krb5_enctype enctype,
+		  size_t *len)
+{
+    int i;
+    assert (len);
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    *len = krb5_enctypes_list[i].prf_length;
+    return 0;
+    
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_prf(krb5_context context, const krb5_keyblock *key,
+krb5_data *input, krb5_data *output)
+{
+    int i;
+    size_t len;
+    assert(input && output);
+    assert (output->data);
+
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == key->enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    output->magic = KV5M_DATA;
+    if (!krb5_enctypes_list[i].prf)
+	return (KRB5_CRYPTO_INTERNAL);
+    krb5_c_prf_length (context, key->enctype, &len);
+    if( len != output->length)
+	return (KRB5_CRYPTO_INTERNAL);
+            return((*(krb5_enctypes_list[i].prf))
+	   (krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
+	    key,  input, output));
+}
+
diff --git a/mechglue/src/lib/crypto/prng.c b/mechglue/src/lib/crypto/prng.c
new file mode 100644
index 000000000..54a68e067
--- /dev/null
+++ b/mechglue/src/lib/crypto/prng.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2001, 2002, 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "enc_provider.h"
+#include <assert.h>
+#include "k5-thread.h"
+
+#include "yarrow.h"
+static Yarrow_CTX y_ctx;
+static int init_error;
+#define yarrow_lock krb5int_yarrow_lock
+k5_mutex_t yarrow_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+/* Helper function to estimate entropy based on sample length
+ * and where it comes from.
+ */
+
+static size_t
+entropy_estimate (unsigned int randsource, size_t length)
+{
+  switch (randsource) {
+  case KRB5_C_RANDSOURCE_OLDAPI:
+    return (4*length);
+  case KRB5_C_RANDSOURCE_OSRAND:
+    return (8*length);
+  case KRB5_C_RANDSOURCE_TRUSTEDPARTY:
+    return (4*length);
+  case KRB5_C_RANDSOURCE_TIMING:return (2);
+  case KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL:
+    return (0);
+  default:
+    abort();
+  }
+return (0);
+}
+
+int krb5int_prng_init(void)
+{
+    unsigned i;
+    int yerr;
+
+    yerr = k5_mutex_finish_init(&yarrow_lock);
+    if (yerr)
+	return yerr;
+
+    yerr = krb5int_yarrow_init (&y_ctx, NULL);
+    if ((yerr != YARROW_OK) && (yerr != YARROW_NOT_SEEDED))
+	return KRB5_CRYPTO_INTERNAL;
+
+    for (i=0; i < KRB5_C_RANDSOURCE_MAX; i++ ) {
+	unsigned source_id;
+	if (krb5int_yarrow_new_source (&y_ctx, &source_id) != YARROW_OK )
+	    return KRB5_CRYPTO_INTERNAL;
+	assert (source_id == i);
+    }
+
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_random_add_entropy (krb5_context context, unsigned int randsource,
+			   const krb5_data *data)
+{
+  int yerr;
+
+  /* Make sure the mutex got initialized.  */
+  yerr = krb5int_crypto_init();
+  if (yerr)
+      return yerr;
+  /* Now, finally, feed in the data.  */
+  yerr = krb5int_yarrow_input (&y_ctx, randsource,
+			       data->data, data->length,
+			       entropy_estimate (randsource, data->length));
+  if (yerr != YARROW_OK)
+      return (KRB5_CRYPTO_INTERNAL);
+  return (0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_random_seed (krb5_context context, krb5_data *data)
+{
+    return krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_OLDAPI, data);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_random_make_octets(krb5_context context, krb5_data *data)
+{
+    int yerr;
+    yerr = krb5int_yarrow_output (&y_ctx, data->data, data->length);
+    if (yerr == YARROW_NOT_SEEDED) {
+      yerr = krb5int_yarrow_reseed (&y_ctx, YARROW_SLOW_POOL);
+      if (yerr == YARROW_OK)
+	yerr = krb5int_yarrow_output (&y_ctx, data->data, data->length);
+    }
+    if ( yerr != YARROW_OK)
+      return (KRB5_CRYPTO_INTERNAL);
+    return(0);
+}
+
+void krb5int_prng_cleanup (void)
+{
+    krb5int_yarrow_final (&y_ctx);
+    k5_mutex_destroy(&yarrow_lock);
+}
+
+
+/*
+ * Routines to get entropy from the OS.  For UNIX we try /dev/urandom
+ * and /dev/random.  Currently we don't do anything for Windows.
+ */
+#if defined(_WIN32)
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_random_os_entropy (krb5_context context, int strong, int *success)
+{
+  if (success)
+    *success  = 0;
+  return 0;
+}
+
+#else /*Windows*/
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+/*
+ * Helper function to read entropy from  a random device.  Takes the
+ * name of a device, opens it, makes sure it is a device and if so,
+ * reads entropy.  Returns  a boolean indicating whether entropy was
+ * read.
+ */
+
+static int
+read_entropy_from_device (krb5_context context, const char *device)
+{
+  krb5_data data;
+  struct stat sb;
+  int fd;
+  unsigned char buf[YARROW_SLOW_THRESH/8];
+  int left;
+  fd = open (device, O_RDONLY);
+  if (fd == -1)
+    return 0;
+  if (fstat (fd, &sb) == -1)
+    return 0;
+  if (S_ISREG(sb.st_mode)) {
+    close(fd);
+    return 0;
+  }
+  for (left = sizeof (buf); left > 0;) {
+    ssize_t count;
+    count = read (fd, &buf, (unsigned) left);
+    if (count <= 0) {
+      close(fd);
+      return 0;
+    }
+    left -= count;
+  }
+  close (fd);
+  data.length = sizeof (buf);
+  data.data = ( char * ) buf;
+  if ( krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_OSRAND, 
+				  &data) != 0) {
+    return 0;
+  }
+  return 1;
+}
+    
+krb5_error_code KRB5_CALLCONV
+krb5_c_random_os_entropy (krb5_context context,
+			  int strong, int *success)
+{
+  int unused;
+  int *oursuccess = success?success:&unused;
+  *oursuccess = 0;
+  /* If we are getting strong data then try that first.  We aare
+     guaranteed to cause a reseed of some kind if strong is true and
+     we have both /dev/random and /dev/urandom.  We want the strong
+     data included in the reseed so we get it first.*/
+  if (strong) {
+    if (read_entropy_from_device (context, "/dev/random"))
+      *oursuccess = 1;
+  }
+  if (read_entropy_from_device (context, "/dev/urandom"))
+    *oursuccess = 1;
+  return 0;
+}
+
+#endif /*Windows or pre-OSX Mac*/
diff --git a/mechglue/src/lib/crypto/raw/ChangeLog b/mechglue/src/lib/crypto/raw/ChangeLog
new file mode 100644
index 000000000..937242118
--- /dev/null
+++ b/mechglue/src/lib/crypto/raw/ChangeLog
@@ -0,0 +1,51 @@
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* raw_decrypt.c, raw_encrypt.c: Use ANSI C style function
+	definitions.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* raw_encrypt.c (krb5_raw_encrypt_length): Use block_size field
+	instead of calling a function.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* raw.h: Make prototypes unconditional.
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* raw.h, raw_decrypt.c, raw_encrypt.c: Use const instead of
+	krb5_const.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:20:51 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
diff --git a/mechglue/src/lib/crypto/raw/Makefile.in b/mechglue/src/lib/crypto/raw/Makefile.in
new file mode 100644
index 000000000..c3d2166c9
--- /dev/null
+++ b/mechglue/src/lib/crypto/raw/Makefile.in
@@ -0,0 +1,51 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/raw
+mydir=raw
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=raw
+##DOS##OBJFILE=..\$(OUTPRE)raw.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= raw_decrypt.o raw_encrypt.o
+
+OBJS= $(OUTPRE)raw_decrypt.$(OBJEXT) $(OUTPRE)raw_encrypt.$(OBJEXT)
+
+SRCS= $(srcdir)/raw_decrypt.c $(srcdir)/raw_encrypt.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+raw_decrypt.so raw_decrypt.po $(OUTPRE)raw_decrypt.$(OBJEXT): \
+  raw_decrypt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  raw.h
+raw_encrypt.so raw_encrypt.po $(OUTPRE)raw_encrypt.$(OBJEXT): \
+  raw_encrypt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  raw.h
diff --git a/mechglue/src/lib/crypto/raw/raw.h b/mechglue/src/lib/crypto/raw/raw.h
new file mode 100644
index 000000000..d3f7dd835
--- /dev/null
+++ b/mechglue/src/lib/crypto/raw/raw.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+void krb5_raw_encrypt_length
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		size_t input, size_t *length);
+
+krb5_error_code krb5_raw_encrypt
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec, const krb5_data *input,
+		krb5_data *output);
+
+krb5_error_code krb5_raw_decrypt
+(const struct krb5_enc_provider *enc,
+		const struct krb5_hash_provider *hash,
+		const krb5_keyblock *key, krb5_keyusage usage,
+		const krb5_data *ivec, const krb5_data *input,
+		krb5_data *arg_output);
diff --git a/mechglue/src/lib/crypto/raw/raw_decrypt.c b/mechglue/src/lib/crypto/raw/raw_decrypt.c
new file mode 100644
index 000000000..767da1f9f
--- /dev/null
+++ b/mechglue/src/lib/crypto/raw/raw_decrypt.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "raw.h"
+
+krb5_error_code
+krb5_raw_decrypt(const struct krb5_enc_provider *enc,
+		 const struct krb5_hash_provider *hash,
+		 const krb5_keyblock *key, krb5_keyusage usage,
+		 const krb5_data *ivec, const krb5_data *input,
+		 krb5_data *output)
+{
+    return((*(enc->decrypt))(key, ivec, input, output));
+}
diff --git a/mechglue/src/lib/crypto/raw/raw_encrypt.c b/mechglue/src/lib/crypto/raw/raw_encrypt.c
new file mode 100644
index 000000000..68b819c01
--- /dev/null
+++ b/mechglue/src/lib/crypto/raw/raw_encrypt.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "raw.h"
+
+void
+krb5_raw_encrypt_length(const struct krb5_enc_provider *enc,
+			const struct krb5_hash_provider *hash,
+			size_t inputlen, size_t *length)
+{
+    size_t blocksize;
+
+    blocksize = enc->block_size;
+
+    *length = krb5_roundup(inputlen, blocksize);
+}
+
+krb5_error_code
+krb5_raw_encrypt(const struct krb5_enc_provider *enc,
+		 const struct krb5_hash_provider *hash,
+		 const krb5_keyblock *key, krb5_keyusage usage,
+		 const krb5_data *ivec, const krb5_data *input,
+		 krb5_data *output)
+{
+    return((*(enc->encrypt))(key, ivec, input, output));
+}
diff --git a/mechglue/src/lib/crypto/sha1/ChangeLog b/mechglue/src/lib/crypto/sha1/ChangeLog
new file mode 100644
index 000000000..e02427682
--- /dev/null
+++ b/mechglue/src/lib/crypto/sha1/ChangeLog
@@ -0,0 +1,98 @@
+2006-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_shs, t_shs3): Include support library.  Use
+	CC_LINK.
+
+2005-05-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* shs.c (SHSTransform) [CONFIG_SMALL]: Roll loops for each round.
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* shs.c: Use ANSI C style function definitions.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* shs.h (nist_sha_cksumtable_entry, hmac_sha_cksumtable_entry):
+	Delete unused declarations.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* t_shs3.c: Signed/unsigned cleanup. Provide function prototypes. 
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-07  Miro Jurisic  <meeroh@mit.edu>
+
+	* shs.h: use "" include for k5-int.h
+	[pullup from 1-2-2-branch]
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* shs.c, shs.h (shsUpdate): Declare second argument as const.
+
+2001-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_shs3.c: New test file from Marcus Watts.
+	(longReverse): Resurrected function long since deleted from
+	shs.c.
+	* Makefile.in (check-unix, check-windows): Use t_shs3 test.
+	(clean): Delete it.
+
+	* shs.c (SHSTransform): Make input data pointer point to const.
+	(SHSUpdate): Bugfixes suggested by Marcus Watts, to fix buffer
+	overruns, bugs with small or odd block sizes.
+
+2001-07-05  Danilo Almeida  <dalmeida@mit.edu>
+
+	* shs.h, shs.c, t_shs.c: Fix sha1 on Windows by renaming LONG to
+	SHS_LONG to avoid problem with LONG being signed on Windows.
+	Rename BYTE to SHS_BYTE to avoid any name colisions with Windows
+	(where BYTE and LONG are types defined in the Platform SDK).
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_shs.c: Cast arguments to match printf format. Declare main as
+	returning int. Comment out unused variables.
+
+2001-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* shs.h: Stop using KRB5_PROTOTYPE.
+
+2000-01-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* shs.c (ROTL): Change (a&b|c) construct to make meaning clear,
+	and silence gcc warning.
+	(longReverse): Delete unused function.
+	(shsFinal): Delete unused variable.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:21:10 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
diff --git a/mechglue/src/lib/crypto/sha1/ISSUES b/mechglue/src/lib/crypto/sha1/ISSUES
new file mode 100644
index 000000000..8b7e8a2a1
--- /dev/null
+++ b/mechglue/src/lib/crypto/sha1/ISSUES
@@ -0,0 +1,7 @@
+Issues to be addressed for src/lib/crypto/sha1: -*- text -*-
+
+Assumes int (look for "count") is >= 32 bits.
+
+Changing the types of internal variables is easy, but shsUpdate takes
+an int parameter; changing that could change the ABI on some
+platforms.
diff --git a/mechglue/src/lib/crypto/sha1/Makefile.in b/mechglue/src/lib/crypto/sha1/Makefile.in
new file mode 100644
index 000000000..d2e0b87d1
--- /dev/null
+++ b/mechglue/src/lib/crypto/sha1/Makefile.in
@@ -0,0 +1,63 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/sha1
+mydir=sha1
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=sha1
+##DOS##OBJFILE=..\$(OUTPRE)sha1.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS= shs.o
+
+OBJS= $(OUTPRE)shs.$(OBJEXT) 
+
+SRCS= $(srcdir)/shs.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+t_shs: t_shs.o shs.o $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o t_shs t_shs.o shs.o $(SUPPORT_LIB)
+
+$(OUTPRE)t_shs.exe: $(OUTPRE)t_shs.obj $(OUTPRE)shs.obj
+	link -out:$@ $**
+
+check-unix:: t_shs t_shs3
+	$(C)t_shs -x
+	$(C)t_shs3
+
+check-windows:: $(OUTPRE)t_shs.exe $(OUTPRE)t_shs3.exe
+	$(OUTPRE)$(C)t_shs.exe -x
+	$(OUTPRE)$(C)t_shs3.exe
+
+clean:: 
+	$(RM) t_shs$(EXEEXT) t_shs.$(OBJEXT) t_shs3$(EXEEXT) t_shs3.$(OBJEXT)
+
+clean-unix:: clean-libobjs
+
+t_shs3: t_shs3.o shs.o $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o t_shs3 t_shs3.o shs.o $(SUPPORT_LIB)
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+shs.so shs.po $(OUTPRE)shs.$(OBJEXT): shs.c shs.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h
diff --git a/mechglue/src/lib/crypto/sha1/shs.c b/mechglue/src/lib/crypto/sha1/shs.c
new file mode 100644
index 000000000..a6d3c9f8b
--- /dev/null
+++ b/mechglue/src/lib/crypto/sha1/shs.c
@@ -0,0 +1,386 @@
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <string.h>
+#include "shs.h"
+
+/* The SHS f()-functions.  The f1 and f3 functions can be optimized to
+   save one boolean operation each - thanks to Rich Schroeppel,
+   rcs@cs.arizona.edu for discovering this */
+
+#define f1(x,y,z)   ( z ^ ( x & ( y ^ z ) ) )           /* Rounds  0-19 */
+#define f2(x,y,z)   ( x ^ y ^ z )                       /* Rounds 20-39 */
+#define f3(x,y,z)   ( ( x & y ) | ( z & ( x | y ) ) )   /* Rounds 40-59 */
+#define f4(x,y,z)   ( x ^ y ^ z )                       /* Rounds 60-79 */
+
+/* The SHS Mysterious Constants */
+
+#define K1  0x5A827999L                                 /* Rounds  0-19 */
+#define K2  0x6ED9EBA1L                                 /* Rounds 20-39 */
+#define K3  0x8F1BBCDCL                                 /* Rounds 40-59 */
+#define K4  0xCA62C1D6L                                 /* Rounds 60-79 */
+
+/* SHS initial values */
+
+#define h0init  0x67452301L
+#define h1init  0xEFCDAB89L
+#define h2init  0x98BADCFEL
+#define h3init  0x10325476L
+#define h4init  0xC3D2E1F0L
+
+/* Note that it may be necessary to add parentheses to these macros if they
+   are to be called with expressions as arguments */
+
+/* 32-bit rotate left - kludged with shifts */
+
+#define ROTL(n,X)  ((((X) << (n)) & 0xffffffff) | ((X) >> (32 - n)))
+
+/* The initial expanding function.  The hash function is defined over an
+   80-word expanded input array W, where the first 16 are copies of the input
+   data, and the remaining 64 are defined by
+
+        W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ]
+
+   This implementation generates these values on the fly in a circular
+   buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
+   optimization.
+
+   The updated SHS changes the expanding function by adding a rotate of 1
+   bit.  Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor
+   for this information */
+
+#ifdef NEW_SHS
+#define expand(W,i) ( W[ i & 15 ] = ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
+                                                 W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] )))
+#else
+#define expand(W,i) ( W[ i & 15 ] ^= W[ (i - 14) & 15 ] ^ \
+		      W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] )
+#endif /* NEW_SHS */
+
+/* The prototype SHS sub-round.  The fundamental sub-round is:
+
+        a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data;
+        b' = a;
+        c' = ROTL( 30, b );
+        d' = c;
+        e' = d;
+
+   but this is implemented by unrolling the loop 5 times and renaming the
+   variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration.
+   This code is then replicated 20 times for each of the 4 functions, using
+   the next 20 values from the W[] array each time */
+
+#define subRound(a, b, c, d, e, f, k, data) \
+    ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, \
+      e &= 0xffffffff, b = ROTL( 30, b ) )
+
+/* Initialize the SHS values */
+
+void shsInit(SHS_INFO *shsInfo)
+{
+    /* Set the h-vars to their initial values */
+    shsInfo->digest[ 0 ] = h0init;
+    shsInfo->digest[ 1 ] = h1init;
+    shsInfo->digest[ 2 ] = h2init;
+    shsInfo->digest[ 3 ] = h3init;
+    shsInfo->digest[ 4 ] = h4init;
+
+    /* Initialise bit count */
+    shsInfo->countLo = shsInfo->countHi = 0;
+}
+
+/* Perform the SHS transformation.  Note that this code, like MD5, seems to
+   break some optimizing compilers due to the complexity of the expressions
+   and the size of the basic block.  It may be necessary to split it into
+   sections, e.g. based on the four subrounds
+
+   Note that this corrupts the shsInfo->data area */
+
+static void SHSTransform (SHS_LONG *digest, const SHS_LONG *data);
+
+static
+void SHSTransform(SHS_LONG *digest, const SHS_LONG *data)
+{
+    SHS_LONG A, B, C, D, E;     /* Local vars */
+    SHS_LONG eData[ 16 ];       /* Expanded data */
+
+    /* Set up first buffer and local data buffer */
+    A = digest[ 0 ];
+    B = digest[ 1 ];
+    C = digest[ 2 ];
+    D = digest[ 3 ];
+    E = digest[ 4 ];
+    memcpy(eData, data, sizeof (eData));
+
+#ifdef CONFIG_SMALL
+
+    {
+	int i;
+	SHS_LONG temp;
+	for (i = 0; i < 20; i++) {
+	    SHS_LONG x = (i < 16) ? eData[i] : expand(eData, i);
+	    subRound(A, B, C, D, E, f1, K1, x);
+	    temp = E, E = D, D = C, C = B, B = A, A = temp;
+	}
+	for (i = 20; i < 40; i++) {
+	    subRound(A, B, C, D, E, f2, K2, expand(eData, i));
+	    temp = E, E = D, D = C, C = B, B = A, A = temp;
+	}
+	for (i = 40; i < 60; i++) {
+	    subRound(A, B, C, D, E, f3, K3, expand(eData, i));
+	    temp = E, E = D, D = C, C = B, B = A, A = temp;
+	}
+	for (i = 60; i < 80; i++) {
+	    subRound(A, B, C, D, E, f4, K4, expand(eData, i));
+	    temp = E, E = D, D = C, C = B, B = A, A = temp;
+	}
+    }
+
+#else
+
+    /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
+    subRound( A, B, C, D, E, f1, K1, eData[  0 ] );
+    subRound( E, A, B, C, D, f1, K1, eData[  1 ] );
+    subRound( D, E, A, B, C, f1, K1, eData[  2 ] );
+    subRound( C, D, E, A, B, f1, K1, eData[  3 ] );
+    subRound( B, C, D, E, A, f1, K1, eData[  4 ] );
+    subRound( A, B, C, D, E, f1, K1, eData[  5 ] );
+    subRound( E, A, B, C, D, f1, K1, eData[  6 ] );
+    subRound( D, E, A, B, C, f1, K1, eData[  7 ] );
+    subRound( C, D, E, A, B, f1, K1, eData[  8 ] );
+    subRound( B, C, D, E, A, f1, K1, eData[  9 ] );
+    subRound( A, B, C, D, E, f1, K1, eData[ 10 ] );
+    subRound( E, A, B, C, D, f1, K1, eData[ 11 ] );
+    subRound( D, E, A, B, C, f1, K1, eData[ 12 ] );
+    subRound( C, D, E, A, B, f1, K1, eData[ 13 ] );
+    subRound( B, C, D, E, A, f1, K1, eData[ 14 ] );
+    subRound( A, B, C, D, E, f1, K1, eData[ 15 ] );
+    subRound( E, A, B, C, D, f1, K1, expand( eData, 16 ) );
+    subRound( D, E, A, B, C, f1, K1, expand( eData, 17 ) );
+    subRound( C, D, E, A, B, f1, K1, expand( eData, 18 ) );
+    subRound( B, C, D, E, A, f1, K1, expand( eData, 19 ) );
+
+    subRound( A, B, C, D, E, f2, K2, expand( eData, 20 ) );
+    subRound( E, A, B, C, D, f2, K2, expand( eData, 21 ) );
+    subRound( D, E, A, B, C, f2, K2, expand( eData, 22 ) );
+    subRound( C, D, E, A, B, f2, K2, expand( eData, 23 ) );
+    subRound( B, C, D, E, A, f2, K2, expand( eData, 24 ) );
+    subRound( A, B, C, D, E, f2, K2, expand( eData, 25 ) );
+    subRound( E, A, B, C, D, f2, K2, expand( eData, 26 ) );
+    subRound( D, E, A, B, C, f2, K2, expand( eData, 27 ) );
+    subRound( C, D, E, A, B, f2, K2, expand( eData, 28 ) );
+    subRound( B, C, D, E, A, f2, K2, expand( eData, 29 ) );
+    subRound( A, B, C, D, E, f2, K2, expand( eData, 30 ) );
+    subRound( E, A, B, C, D, f2, K2, expand( eData, 31 ) );
+    subRound( D, E, A, B, C, f2, K2, expand( eData, 32 ) );
+    subRound( C, D, E, A, B, f2, K2, expand( eData, 33 ) );
+    subRound( B, C, D, E, A, f2, K2, expand( eData, 34 ) );
+    subRound( A, B, C, D, E, f2, K2, expand( eData, 35 ) );
+    subRound( E, A, B, C, D, f2, K2, expand( eData, 36 ) );
+    subRound( D, E, A, B, C, f2, K2, expand( eData, 37 ) );
+    subRound( C, D, E, A, B, f2, K2, expand( eData, 38 ) );
+    subRound( B, C, D, E, A, f2, K2, expand( eData, 39 ) );
+
+    subRound( A, B, C, D, E, f3, K3, expand( eData, 40 ) );
+    subRound( E, A, B, C, D, f3, K3, expand( eData, 41 ) );
+    subRound( D, E, A, B, C, f3, K3, expand( eData, 42 ) );
+    subRound( C, D, E, A, B, f3, K3, expand( eData, 43 ) );
+    subRound( B, C, D, E, A, f3, K3, expand( eData, 44 ) );
+    subRound( A, B, C, D, E, f3, K3, expand( eData, 45 ) );
+    subRound( E, A, B, C, D, f3, K3, expand( eData, 46 ) );
+    subRound( D, E, A, B, C, f3, K3, expand( eData, 47 ) );
+    subRound( C, D, E, A, B, f3, K3, expand( eData, 48 ) );
+    subRound( B, C, D, E, A, f3, K3, expand( eData, 49 ) );
+    subRound( A, B, C, D, E, f3, K3, expand( eData, 50 ) );
+    subRound( E, A, B, C, D, f3, K3, expand( eData, 51 ) );
+    subRound( D, E, A, B, C, f3, K3, expand( eData, 52 ) );
+    subRound( C, D, E, A, B, f3, K3, expand( eData, 53 ) );
+    subRound( B, C, D, E, A, f3, K3, expand( eData, 54 ) );
+    subRound( A, B, C, D, E, f3, K3, expand( eData, 55 ) );
+    subRound( E, A, B, C, D, f3, K3, expand( eData, 56 ) );
+    subRound( D, E, A, B, C, f3, K3, expand( eData, 57 ) );
+    subRound( C, D, E, A, B, f3, K3, expand( eData, 58 ) );
+    subRound( B, C, D, E, A, f3, K3, expand( eData, 59 ) );
+
+    subRound( A, B, C, D, E, f4, K4, expand( eData, 60 ) );
+    subRound( E, A, B, C, D, f4, K4, expand( eData, 61 ) );
+    subRound( D, E, A, B, C, f4, K4, expand( eData, 62 ) );
+    subRound( C, D, E, A, B, f4, K4, expand( eData, 63 ) );
+    subRound( B, C, D, E, A, f4, K4, expand( eData, 64 ) );
+    subRound( A, B, C, D, E, f4, K4, expand( eData, 65 ) );
+    subRound( E, A, B, C, D, f4, K4, expand( eData, 66 ) );
+    subRound( D, E, A, B, C, f4, K4, expand( eData, 67 ) );
+    subRound( C, D, E, A, B, f4, K4, expand( eData, 68 ) );
+    subRound( B, C, D, E, A, f4, K4, expand( eData, 69 ) );
+    subRound( A, B, C, D, E, f4, K4, expand( eData, 70 ) );
+    subRound( E, A, B, C, D, f4, K4, expand( eData, 71 ) );
+    subRound( D, E, A, B, C, f4, K4, expand( eData, 72 ) );
+    subRound( C, D, E, A, B, f4, K4, expand( eData, 73 ) );
+    subRound( B, C, D, E, A, f4, K4, expand( eData, 74 ) );
+    subRound( A, B, C, D, E, f4, K4, expand( eData, 75 ) );
+    subRound( E, A, B, C, D, f4, K4, expand( eData, 76 ) );
+    subRound( D, E, A, B, C, f4, K4, expand( eData, 77 ) );
+    subRound( C, D, E, A, B, f4, K4, expand( eData, 78 ) );
+    subRound( B, C, D, E, A, f4, K4, expand( eData, 79 ) );
+
+#endif
+
+    /* Build message digest */
+    digest[ 0 ] += A;
+    digest[ 0 ] &= 0xffffffff;
+    digest[ 1 ] += B;
+    digest[ 1 ] &= 0xffffffff;
+    digest[ 2 ] += C;
+    digest[ 2 ] &= 0xffffffff;
+    digest[ 3 ] += D;
+    digest[ 3 ] &= 0xffffffff;
+    digest[ 4 ] += E;
+    digest[ 4 ] &= 0xffffffff;
+}
+
+/* Update SHS for a block of data */
+
+void shsUpdate(SHS_INFO *shsInfo, const SHS_BYTE *buffer, int count)
+{
+    SHS_LONG tmp;
+    int dataCount, canfill;
+    SHS_LONG *lp;
+
+    /* Update bitcount */
+    tmp = shsInfo->countLo;
+    shsInfo->countLo = tmp + (((SHS_LONG) count) << 3 );
+    if ((shsInfo->countLo &= 0xffffffff) < tmp)
+        shsInfo->countHi++;	/* Carry from low to high */
+    shsInfo->countHi += count >> 29;
+
+    /* Get count of bytes already in data */
+    dataCount = (int) (tmp >> 3) & 0x3F;
+
+    /* Handle any leading odd-sized chunks */
+    if (dataCount) {
+	lp = shsInfo->data + dataCount / 4;
+	dataCount = SHS_DATASIZE - dataCount;
+	canfill = (count >= dataCount);
+
+	if (dataCount % 4) {
+	    /* Fill out a full 32 bit word first if needed -- this
+	       is not very efficient (computed shift amount),
+	       but it shouldn't happen often. */
+	    while (dataCount % 4 && count > 0) {
+		*lp |= (SHS_LONG) *buffer++ << ((--dataCount % 4) * 8);
+		count--;
+	    }
+	    lp++;
+	}
+	while (lp < shsInfo->data + 16) {
+	    if (count < 4) {
+		*lp = 0;
+		switch (count % 4) {
+		case 3:
+		    *lp |= (SHS_LONG) buffer[2] << 8;
+		case 2:
+		    *lp |= (SHS_LONG) buffer[1] << 16;
+		case 1:
+		    *lp |= (SHS_LONG) buffer[0] << 24;
+		}
+		count = 0;
+		break;		/* out of while loop */
+	    }
+	    *lp = (SHS_LONG) *buffer++ << 24;
+	    *lp |= (SHS_LONG) *buffer++ << 16;
+	    *lp |= (SHS_LONG) *buffer++ << 8;
+	    *lp++ |= (SHS_LONG) *buffer++;
+	    count -= 4;
+	}
+	if (canfill) {
+	    SHSTransform(shsInfo->digest, shsInfo->data);
+	}
+    }
+
+    /* Process data in SHS_DATASIZE chunks */
+    while (count >= SHS_DATASIZE) {
+	lp = shsInfo->data;
+	while (lp < shsInfo->data + 16) {
+	    *lp = ((SHS_LONG) *buffer++) << 24;
+	    *lp |= ((SHS_LONG) *buffer++) << 16;
+	    *lp |= ((SHS_LONG) *buffer++) << 8;
+	    *lp++ |= (SHS_LONG) *buffer++;
+	}
+	SHSTransform(shsInfo->digest, shsInfo->data);
+	count -= SHS_DATASIZE;
+    }
+
+    if (count > 0) {
+	lp = shsInfo->data;
+	while (count > 4) {
+	    *lp = ((SHS_LONG) *buffer++) << 24;
+	    *lp |= ((SHS_LONG) *buffer++) << 16;
+	    *lp |= ((SHS_LONG) *buffer++) << 8;
+	    *lp++ |= (SHS_LONG) *buffer++;
+	    count -= 4;
+	}
+	*lp = 0;
+	switch (count % 4) {
+	case 0:
+	    *lp |= ((SHS_LONG) buffer[3]);
+	case 3:
+	    *lp |= ((SHS_LONG) buffer[2]) << 8;
+	case 2:
+	    *lp |= ((SHS_LONG) buffer[1]) << 16;
+	case 1:
+	    *lp |= ((SHS_LONG) buffer[0]) << 24;
+	}
+    }
+}
+
+/* Final wrapup - pad to SHS_DATASIZE-byte boundary with the bit pattern
+   1 0* (64-bit count of bits processed, MSB-first) */
+
+void shsFinal(SHS_INFO *shsInfo)
+{
+    int count;
+    SHS_LONG *lp;
+
+    /* Compute number of bytes mod 64 */
+    count = (int) shsInfo->countLo;
+    count = (count >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    lp = shsInfo->data + count / 4;
+    switch (count % 4) {
+    case 3:
+	*lp++ |= (SHS_LONG) 0x80;
+	break;
+    case 2:
+	*lp++ |= (SHS_LONG) 0x80 << 8;
+	break;
+    case 1:
+	*lp++ |= (SHS_LONG) 0x80 << 16;
+	break;
+    case 0:
+	*lp++ = (SHS_LONG) 0x80 << 24;
+    }
+
+    /* at this point, lp can point *past* shsInfo->data.  If it points
+       there, just Transform and reset.  If it points to the last
+       element, set that to zero.  This pads out to 64 bytes if not
+       enough room for length words */
+
+    if (lp == shsInfo->data + 15)
+	*lp++ = 0;
+
+    if (lp == shsInfo->data + 16) {
+	SHSTransform(shsInfo->digest, shsInfo->data);
+	lp = shsInfo->data;
+    }
+
+    /* Pad out to 56 bytes */
+    while (lp < shsInfo->data + 14)
+	*lp++ = 0;
+
+    /* Append length in bits and transform */
+    *lp++ = shsInfo->countHi;
+    *lp++ = shsInfo->countLo;
+    SHSTransform(shsInfo->digest, shsInfo->data);
+}
diff --git a/mechglue/src/lib/crypto/sha1/shs.h b/mechglue/src/lib/crypto/sha1/shs.h
new file mode 100644
index 000000000..96422c468
--- /dev/null
+++ b/mechglue/src/lib/crypto/sha1/shs.h
@@ -0,0 +1,45 @@
+#ifndef _SHS_DEFINED
+
+#include "k5-int.h"
+
+#define _SHS_DEFINED
+
+/* Some useful types */
+
+typedef krb5_octet	SHS_BYTE;
+typedef krb5_ui_4	SHS_LONG;
+
+/* Define the following to use the updated SHS implementation */
+#define NEW_SHS         /**/
+
+/* The SHS block size and message digest sizes, in bytes */
+
+#define SHS_DATASIZE    64
+#define SHS_DIGESTSIZE  20
+
+/* The structure for storing SHS info */
+
+typedef struct {
+               SHS_LONG digest[ 5 ];            /* Message digest */
+               SHS_LONG countLo, countHi;       /* 64-bit bit count */
+               SHS_LONG data[ 16 ];             /* SHS data buffer */
+               } SHS_INFO;
+
+/* Message digest functions (shs.c) */
+void shsInit(SHS_INFO *shsInfo);
+void shsUpdate(SHS_INFO *shsInfo, const SHS_BYTE *buffer, int count);
+void shsFinal(SHS_INFO *shsInfo);
+
+
+/* Keyed Message digest functions (hmac_sha.c) */
+krb5_error_code hmac_sha(krb5_octet *text,
+			int text_len,
+			krb5_octet *key,
+			int key_len,
+			krb5_octet *digest);
+
+
+#define NIST_SHA_CKSUM_LENGTH		SHS_DIGESTSIZE
+#define HMAC_SHA_CKSUM_LENGTH		SHS_DIGESTSIZE
+
+#endif /* _SHS_DEFINED */
diff --git a/mechglue/src/lib/crypto/sha1/t_shs.c b/mechglue/src/lib/crypto/sha1/t_shs.c
new file mode 100644
index 000000000..adcb0927a
--- /dev/null
+++ b/mechglue/src/lib/crypto/sha1/t_shs.c
@@ -0,0 +1,135 @@
+/****************************************************************************
+*                                                                           *
+*                               SHS Test Code                               *
+*                                                                           *
+****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "shs.h"
+
+/* Test the SHS implementation */
+
+#ifdef NEW_SHS
+
+static SHS_LONG shsTestResults[][ 5 ] = {
+    { 0xA9993E36L, 0x4706816AL, 0xBA3E2571L, 0x7850C26CL, 0x9CD0D89DL, },
+    { 0x84983E44L, 0x1C3BD26EL, 0xBAAE4AA1L, 0xF95129E5L, 0xE54670F1L, },
+    { 0x34AA973CL, 0xD4C4DAA4L, 0xF61EEB2BL, 0xDBAD2731L, 0x6534016FL, }
+    };
+
+#else
+
+static SHS_LONG shsTestResults[][ 5 ] = {
+    { 0x0164B8A9L, 0x14CD2A5EL, 0x74C4F7FFL, 0x082C4D97L, 0xF1EDF880L },
+    { 0xD2516EE1L, 0xACFA5BAFL, 0x33DFC1C4L, 0x71E43844L, 0x9EF134C8L },
+    { 0x3232AFFAL, 0x48628A26L, 0x653B5AAAL, 0x44541FD9L, 0x0D690603L }
+    };
+#endif /* NEW_SHS */
+
+static int compareSHSresults(shsInfo, shsTestLevel)
+SHS_INFO *shsInfo;
+int shsTestLevel;
+{
+    int i, fail = 0;
+
+    /* Compare the returned digest and required values */
+    for( i = 0; i < 5; i++ )
+        if( shsInfo->digest[ i ] != shsTestResults[ shsTestLevel ][ i ] )
+	    fail = 1;
+    if (fail) {
+	printf("\nExpected: ");
+	for (i = 0; i < 5; i++) {
+	    printf("%8.8lx ", (unsigned long) shsTestResults[shsTestLevel][i]);
+	}
+	printf("\nGot:      ");
+	for (i = 0; i < 5; i++) {
+	    printf("%8.8lx ", (unsigned long) shsInfo->digest[i]);
+	}
+	printf("\n");
+	return( -1 );
+    }
+    return( 0 );
+}
+
+int
+main()
+{
+    SHS_INFO shsInfo;
+    unsigned int i;
+#if 0
+    time_t secondCount;
+    SHS_BYTE data[ 200 ];
+#endif
+
+    /* Make sure we've got the endianness set right.  If the machine is
+       big-endian (up to 64 bits) the following value will be signed,
+       otherwise it will be unsigned.  Unfortunately we can't test for odd
+       things like middle-endianness without knowing the size of the data
+       types */
+
+    /* Test SHS against values given in SHS standards document */
+    printf( "Running SHS test 1 ... " );
+    shsInit( &shsInfo );
+    shsUpdate( &shsInfo, ( SHS_BYTE * ) "abc", 3 );
+    shsFinal( &shsInfo );
+    if( compareSHSresults( &shsInfo, 0 ) == -1 )
+        {
+        putchar( '\n' );
+        puts( "SHS test 1 failed" );
+        exit( -1 );
+        }
+#ifdef NEW_SHS
+    puts( "passed, result= A9993E364706816ABA3E25717850C26C9CD0D89D" );
+#else
+    puts( "passed, result= 0164B8A914CD2A5E74C4F7FF082C4D97F1EDF880" );
+#endif /* NEW_SHS */
+
+    printf( "Running SHS test 2 ... " );
+    shsInit( &shsInfo );
+    shsUpdate( &shsInfo, ( SHS_BYTE * ) "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56 );
+    shsFinal( &shsInfo );
+    if( compareSHSresults( &shsInfo, 1 ) == -1 )
+        {
+        putchar( '\n' );
+        puts( "SHS test 2 failed" );
+        exit( -1 );
+        }
+#ifdef NEW_SHS
+    puts( "passed, result= 84983E441C3BD26EBAAE4AA1F95129E5E54670F1" );
+#else
+    puts( "passed, result= D2516EE1ACFA5BAF33DFC1C471E438449EF134C8" );
+#endif /* NEW_SHS */
+
+    printf( "Running SHS test 3 ... " );
+    shsInit( &shsInfo );
+    for( i = 0; i < 15625; i++ )
+        shsUpdate( &shsInfo, ( SHS_BYTE * ) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 64 );
+    shsFinal( &shsInfo );
+    if( compareSHSresults( &shsInfo, 2 ) == -1 )
+        {
+        putchar( '\n' );
+        puts( "SHS test 3 failed" );
+        exit( -1 );
+        }
+#ifdef NEW_SHS
+    puts( "passed, result= 34AA973CD4C4DAA4F61EEB2BDBAD27316534016F" );
+#else
+    puts( "passed, result= 3232AFFA48628A26653B5AAA44541FD90D690603" );
+#endif /* NEW_SHS */
+
+#if 0
+    printf( "\nTesting speed for 100MB data... " );
+    shsInit( &shsInfo );
+    secondCount = time( NULL );
+    for( i = 0; i < 500000U; i++ )
+        shsUpdate( &shsInfo, data, 200 );
+    secondCount = time( NULL ) - secondCount;
+    printf( "done.  Time = %ld seconds, %ld kbytes/second.\n", \
+            secondCount, 100500L / secondCount );
+#endif
+
+    puts( "\nAll SHS tests passed" );
+    exit( 0 );
+}
diff --git a/mechglue/src/lib/crypto/sha1/t_shs3.c b/mechglue/src/lib/crypto/sha1/t_shs3.c
new file mode 100644
index 000000000..cefec45eb
--- /dev/null
+++ b/mechglue/src/lib/crypto/sha1/t_shs3.c
@@ -0,0 +1,592 @@
+/* test shs code */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "shs.h"
+
+static void process(void);
+static void test1(void);
+static void test2(void);
+static void test3(void);
+static void test4(void);
+static void test5(void);
+static void test6(void);
+static void test7(void);
+
+/* When run on a little-endian CPU we need to perform byte reversal on an
+   array of longwords.  It is possible to make the code endianness-
+   independant by fiddling around with data at the byte level, but this
+   makes for very slow code, so we rely on the user to sort out endianness
+   at compile time */
+
+static void longReverse( SHS_LONG *buffer, int byteCount )
+{
+    SHS_LONG value;
+    static int init = 0;
+    char *cp;
+
+    switch (init) {
+    case 0:
+	init=1;
+	cp = (char *) &init;
+	if (*cp == 1) {
+	    init=2;
+	    break;
+	}
+	init=1;
+	/* fall through - MSB */
+    case 1:
+	return;
+    }
+
+    byteCount /= sizeof( SHS_LONG );
+    while( byteCount-- ) {
+        value = *buffer;
+        value = ( ( value & 0xFF00FF00L ) >> 8  ) | 
+                ( ( value & 0x00FF00FFL ) << 8 );
+        *buffer++ = ( value << 16 ) | ( value >> 16 );
+    }
+}
+
+int rc;
+int mode;
+int Dflag;
+
+int
+main(argc,argv)
+	char **argv;
+{
+	char *argp;
+
+	while (--argc > 0) if (*(argp = *++argv)=='-')
+	while (*++argp) switch(*argp)
+	{
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+		if (mode) goto Usage;
+		mode = *argp;
+		break;
+	case 'D':
+		if (argc <= 1) goto Usage;
+		--argc;
+		Dflag = atoi(*++argv);
+		break;
+	case '-':
+		break;
+	default:
+		fprintf (stderr,"Bad switch char <%c>\n", *argp);
+	Usage:
+		fprintf(stderr, "Usage: t_shs [-1234567] [-D #]\n");
+		exit(1);
+	}
+	else goto Usage;
+
+	process();
+	exit(rc);
+}
+
+static void process(void)
+{
+	switch(mode)
+	{
+	case '1':
+		test1();
+		break;
+	case '2':
+		test2();
+		break;
+	case '3':
+		test3();
+		break;
+	case '4':
+		test4();
+		break;
+	case '5':
+		test5();
+		break;
+	case '6':
+		test6();
+		break;
+	case '7':
+		test7();
+		break;
+	default:
+		test1();
+		test2();
+		test3();
+		test4();
+		test5();
+		test6();
+		test7();
+	}
+}
+
+#ifndef shsDigest
+static unsigned char *
+shsDigest(si)
+	SHS_INFO *si;
+{
+	longReverse(si->digest, SHS_DIGESTSIZE);
+	return (unsigned char*) si->digest;
+}
+#endif
+
+unsigned char results1[SHS_DIGESTSIZE] = {
+0xa9,0x99,0x3e,0x36,0x47,0x06,0x81,0x6a,0xba,0x3e,
+0x25,0x71,0x78,0x50,0xc2,0x6c,0x9c,0xd0,0xd8,0x9d};
+
+static void test1(void)
+{
+	SHS_INFO si[1];
+	unsigned char digest[SHS_DIGESTSIZE];
+	int failed;
+	int i;
+
+	printf("Running SHS test 1 ...\n");
+	shsInit(si);
+	shsUpdate(si, (SHS_BYTE *) "abc", 3);
+	shsFinal(si);
+	memcpy(digest, shsDigest(si), SHS_DIGESTSIZE);
+	if ((failed = memcmp(digest, results1, SHS_DIGESTSIZE)) != 0)
+	{
+		fprintf(stderr,"SHS test 1 failed!\n");
+		rc = 1;
+	}
+	printf ("%s, results = ", failed ? "Failed" : "Passed");
+	for (i = 0; i < SHS_DIGESTSIZE; ++i)
+		printf("%02x",digest[i]);
+	if (failed)
+	{
+		printf ("\n, expected ");
+		for (i = 0; i < SHS_DIGESTSIZE; ++i)
+			printf("%02x",results1[i]);
+	}
+	printf("\n");
+}
+
+unsigned char results2[SHS_DIGESTSIZE] = {
+0x84,0x98,0x3e,0x44,0x1c,0x3b,0xd2,0x6e,0xba,0xae,
+0x4a,0xa1,0xf9,0x51,0x29,0xe5,0xe5,0x46,0x70,0xf1};
+
+static void test2(void)
+{
+	SHS_INFO si[1];
+	unsigned char digest[SHS_DIGESTSIZE];
+	int failed;
+	int i;
+
+	printf("Running SHS test 2 ...\n");
+	shsInit(si);
+	shsUpdate(si,
+	(SHS_BYTE *) "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		56);
+	shsFinal(si);
+	memcpy(digest, shsDigest(si), SHS_DIGESTSIZE);
+	if ((failed = memcmp(digest, results2, SHS_DIGESTSIZE)) != 0)
+	{
+		fprintf(stderr,"SHS test 2 failed!\n");
+		rc = 1;
+	}
+	printf ("%s, results = ", failed ? "Failed" : "Passed");
+	for (i = 0; i < SHS_DIGESTSIZE; ++i)
+		printf("%02x",digest[i]);
+	if (failed)
+	{
+		printf ("\n, expected ");
+		for (i = 0; i < SHS_DIGESTSIZE; ++i)
+			printf("%02x",results2[i]);
+	}
+	printf("\n");
+}
+
+unsigned char results3[SHS_DIGESTSIZE] = {
+0x34,0xaa,0x97,0x3c,0xd4,0xc4,0xda,0xa4,0xf6,0x1e,
+0xeb,0x2b,0xdb,0xad,0x27,0x31,0x65,0x34,0x01,0x6f};
+
+static void test3(void)
+{
+	SHS_INFO si[1];
+	unsigned char digest[SHS_DIGESTSIZE];
+	int failed;
+	int i;
+
+	printf("Running SHS test 3 ...\n");
+	shsInit(si);
+	for (i = 0; i < 15625; ++i)
+		shsUpdate(si,
+(SHS_BYTE *) "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+			64);
+	shsFinal(si);
+	memcpy(digest, shsDigest(si), SHS_DIGESTSIZE);
+	if ((failed = memcmp(digest, results3, SHS_DIGESTSIZE)) != 0)
+	{
+		fprintf(stderr,"SHS test 3 failed!\n");
+		rc = 1;
+	}
+	printf ("%s, results = ", failed ? "Failed" : "Passed");
+	for (i = 0; i < SHS_DIGESTSIZE; ++i)
+		printf("%02x",digest[i]);
+	if (failed)
+	{
+		printf ("\n, expected ");
+		for (i = 0; i < SHS_DIGESTSIZE; ++i)
+			printf("%02x",results3[i]);
+	}
+	printf("\n");
+}
+
+unsigned char randdata[] = {
+0xfe,0x28,0x79,0x25,0xf5,0x03,0xf9,0x1c,0xcd,0x70,0x7b,0xb0,0x42,0x02,0xb8,0x2f,
+0xf3,0x63,0xa2,0x79,0x8e,0x9b,0x33,0xd7,0x2b,0xc4,0xb4,0xd2,0xcb,0x61,0xec,0xbb,
+0x94,0xe1,0x8f,0x53,0x80,0x55,0xd9,0x90,0xb2,0x03,0x58,0xfa,0xa6,0xe5,0x18,0x57,
+0x68,0x04,0x24,0x98,0x41,0x7e,0x84,0xeb,0xc1,0x39,0xbc,0x1d,0xf7,0x4e,0x92,0x72,
+0x1a,0x5b,0xb6,0x99,0x43,0xa5,0x0a,0x45,0x73,0x55,0xfd,0x57,0x83,0x45,0x36,0x5c,
+0xfd,0x39,0x08,0x6e,0xe2,0x01,0x9a,0x8c,0x4e,0x39,0xd2,0x0d,0x5f,0x0e,0x35,0x15,
+0xb9,0xac,0x5f,0xa1,0x8a,0xe6,0xdd,0x6e,0x68,0x9d,0xf6,0x29,0x95,0xf6,0x7d,0x7b,
+0xd9,0x5e,0xf4,0x67,0x25,0xbd,0xee,0xed,0x53,0x60,0xb0,0x47,0xdf,0xef,0xf4,0x41,
+0xbd,0x45,0xcf,0x5c,0x93,0x41,0x87,0x97,0x82,0x39,0x20,0x66,0xb4,0xda,0xcb,0x66,
+0x93,0x02,0x2e,0x7f,0x94,0x4c,0xc7,0x3b,0x2c,0xcf,0xf6,0x99,0x6f,0x13,0xf1,0xc5,
+0x28,0x2b,0xa6,0x6c,0x39,0x26,0x7f,0x76,0x24,0x4a,0x6e,0x01,0x40,0x63,0xf8,0x00,
+0x06,0x23,0x5a,0xaa,0xa6,0x2f,0xd1,0x37,0xc7,0xcc,0x76,0xe9,0x54,0x1e,0x57,0x73,
+0xf5,0x33,0xaa,0x96,0xbe,0x35,0xcd,0x1d,0xd5,0x7d,0xac,0x50,0xd5,0xf8,0x47,0x2d,
+0xd6,0x93,0x5f,0x6e,0x38,0xd3,0xac,0xd0,0x7e,0xad,0x9e,0xf8,0x87,0x95,0x63,0x15,
+0x65,0xa3,0xd4,0xb3,0x9a,0x6c,0xac,0xcd,0x2a,0x54,0x83,0x13,0xc4,0xb4,0x94,0xfa,
+0x76,0x87,0xc5,0x8b,0x4a,0x10,0x92,0x05,0xd1,0x0e,0x97,0xfd,0xc8,0xfb,0xc5,0xdc,
+0x21,0x4c,0xc8,0x77,0x5c,0xed,0x32,0x22,0x77,0xc1,0x38,0x30,0xd7,0x8e,0x2a,0x70,
+0x72,0x67,0x13,0xe4,0xb7,0x18,0xd4,0x76,0xdd,0x32,0x12,0xf4,0x5d,0xc9,0xec,0xc1,
+0x2c,0x8a,0xfe,0x08,0x6c,0xea,0xf6,0xab,0x5a,0x0e,0x8e,0x81,0x1d,0xc8,0x5a,0x4b,
+0xed,0xb9,0x7f,0x4b,0x67,0xe3,0x65,0x46,0xc9,0xf2,0xab,0x37,0x0a,0x98,0x67,0x5b,
+0xb1,0x3b,0x02,0x91,0x38,0x71,0xea,0x62,0x88,0xae,0xb6,0xdb,0xfc,0x55,0x79,0x33,
+0x69,0x95,0x51,0xb6,0xe1,0x3b,0xab,0x22,0x68,0x54,0xf9,0x89,0x9c,0x94,0xe0,0xe3,
+0xd3,0x48,0x5c,0xe9,0x78,0x5b,0xb3,0x4b,0xba,0xd8,0x48,0xd8,0xaf,0x91,0x4e,0x23,
+0x38,0x23,0x23,0x6c,0xdf,0x2e,0xf0,0xff,0xac,0x1d,0x2d,0x27,0x10,0x45,0xa3,0x2d,
+0x8b,0x00,0xcd,0xe2,0xfc,0xb7,0xdb,0x52,0x13,0xb7,0x66,0x79,0xd9,0xd8,0x29,0x0e,
+0x32,0xbd,0x52,0x6b,0x75,0x71,0x08,0x83,0x1b,0x67,0x28,0x93,0x97,0x97,0x32,0xff,
+0x8b,0xd3,0x98,0xa3,0xce,0x2b,0x88,0x37,0x1c,0xcc,0xa0,0xd1,0x19,0x9b,0xe6,0x11,
+0xfc,0xc0,0x3c,0x4e,0xe1,0x35,0x49,0x29,0x19,0xcf,0x1d,0xe1,0x60,0x74,0xc0,0xe9,
+0xf7,0xb4,0x99,0xa0,0x23,0x50,0x51,0x78,0xcf,0xc0,0xe5,0xc2,0x1c,0x16,0xd2,0x24,
+0x5a,0x63,0x54,0x83,0xaa,0x74,0x3d,0x41,0x0d,0x52,0xee,0xfe,0x0f,0x4d,0x13,0xe1,
+0x27,0x00,0xc4,0xf3,0x2b,0x55,0xe0,0x9c,0x81,0xe0,0xfc,0xc2,0x13,0xd4,0x39,0x09
+};
+
+unsigned char results4[SHS_DIGESTSIZE] = {
+0x13,0x62,0xfc,0x87,0x68,0x33,0xd5,0x1d,0x2f,0x0c,
+0x73,0xe3,0xfb,0x87,0x6a,0x6b,0xc3,0x25,0x54,0xfc};
+
+static void test4(void)
+{
+	SHS_INFO si[1];
+	unsigned char digest[SHS_DIGESTSIZE];
+	int failed;
+	int i;
+
+	printf("Running SHS test 4 ...\n");
+	shsInit(si);
+	shsUpdate(si, randdata, 19);
+	shsFinal(si);
+	memcpy(digest, shsDigest(si), SHS_DIGESTSIZE);
+	if ((failed = memcmp(digest, results4, SHS_DIGESTSIZE)) != 0)
+	{
+		fprintf(stderr,"SHS test 4 failed!\n");
+		rc = 1;
+	}
+	printf ("%s, results = ", failed ? "Failed" : "Passed");
+	for (i = 0; i < SHS_DIGESTSIZE; ++i)
+		printf("%02x",digest[i]);
+	if (failed)
+	{
+		printf ("\n, expected ");
+		for (i = 0; i < SHS_DIGESTSIZE; ++i)
+			printf("%02x",results4[i]);
+	}
+	printf("\n");
+}
+
+unsigned char results5[SHS_DIGESTSIZE] = {
+0x19,0x4d,0xf6,0xeb,0x8e,0x02,0x6d,0x37,0x58,0x64,
+0xe5,0x95,0x19,0x2a,0xdd,0x1c,0xc4,0x3c,0x24,0x86};
+
+static void test5(void)
+{
+	SHS_INFO si[1];
+	unsigned char digest[SHS_DIGESTSIZE];
+	int failed;
+	int i;
+
+	printf("Running SHS test 5 ...\n");
+	shsInit(si);
+	shsUpdate(si, randdata, 19);
+	shsUpdate(si, randdata+32, 15);
+	shsFinal(si);
+	memcpy(digest, shsDigest(si), SHS_DIGESTSIZE);
+	if ((failed = memcmp(digest, results5, SHS_DIGESTSIZE)) != 0)
+	{
+		fprintf(stderr,"SHS test 5 failed!\n");
+		rc = 1;
+	}
+	printf ("%s, results = ", failed ? "Failed" : "Passed");
+	for (i = 0; i < SHS_DIGESTSIZE; ++i)
+		printf("%02x",digest[i]);
+	if (failed)
+	{
+		printf ("\n, expected ");
+		for (i = 0; i < SHS_DIGESTSIZE; ++i)
+			printf("%02x",results5[i]);
+	}
+	printf("\n");
+}
+
+unsigned char results6[SHS_DIGESTSIZE] = {
+0x4e,0x16,0x57,0x9d,0x4b,0x48,0xa9,0x1c,0x88,0x72,
+0x83,0xdb,0x88,0xd1,0xea,0x3a,0x45,0xdf,0xa1,0x10};
+
+static void test6(void)
+{
+	struct {
+		long pad1;
+		SHS_INFO si1;
+		long pad2;
+		SHS_INFO si2;
+		long pad3;
+	} sdata;
+	unsigned char digest[SHS_DIGESTSIZE];
+	int failed;
+	int i, j;
+
+	printf("Running SHS test 6 ...\n");
+	sdata.pad1 = 0x12345678;
+	sdata.pad2 = 0x87654321;
+	sdata.pad3 = 0x78563412;
+	shsInit((&sdata.si2));
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #20 %#lx\n",
+sdata.pad2);
+sdata.pad2 = 0x87654321;
+}
+if (sdata.pad3 != 0x78563412) {
+printf ("Overrun #21 %#lx\n",
+sdata.pad3);
+sdata.pad3 = 0x78563412;
+}
+	for (i = 0; i < 400; ++i)
+	{
+		shsInit(&sdata.si1);
+if (sdata.pad1 != 0x12345678) {
+printf ("Overrun #22 %#lx at %d\n",
+sdata.pad1, i);
+sdata.pad1 = 0x12345678;
+}
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #23 %#lx at %d\n",
+sdata.pad2, i);
+sdata.pad2 = 0x87654321;
+}
+		shsUpdate(&sdata.si1, (randdata+sizeof(randdata))-i, i);
+if (sdata.pad1 != 0x12345678) {
+printf ("Overrun #24 %#lx at %d\n",
+sdata.pad1, i);
+sdata.pad1 = 0x12345678;
+}
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #25 %#lx at %d\n",
+sdata.pad2, i);
+sdata.pad2 = 0x87654321;
+}
+		shsFinal(&sdata.si1);
+if (sdata.pad1 != 0x12345678) {
+printf ("Overrun #26 %#lx at %d\n",
+sdata.pad1, i);
+sdata.pad1 = 0x12345678;
+}
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #27 %#lx at %d\n",
+sdata.pad2, i);
+sdata.pad2 = 0x87654321;
+}
+		memcpy(digest, shsDigest(&sdata.si1), SHS_DIGESTSIZE);
+		if (Dflag & 1)
+		{
+			printf ("%d: ", i);
+			for (j = 0; j < SHS_DIGESTSIZE; ++j)
+				printf("%02x",digest[j]);
+			printf("\n");
+		}
+		shsUpdate((&sdata.si2), digest, SHS_DIGESTSIZE);
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #28 %#lx at %d\n",
+sdata.pad2, i);
+sdata.pad2 = 0x87654321;
+}
+if (sdata.pad3 != 0x78563412) {
+printf ("Overrun #29 %#lx at %d\n",
+sdata.pad3, i);
+sdata.pad3 = 0x78563412;
+}
+		if (Dflag & 2)
+			printf ("%d: %08lx%08lx%08lx%08lx%08lx\n",
+				i,
+				(unsigned long) sdata.si2.digest[0],
+				(unsigned long) sdata.si2.digest[1],
+				(unsigned long) sdata.si2.digest[2],
+				(unsigned long) sdata.si2.digest[3],
+				(unsigned long) sdata.si2.digest[4]);
+	}
+	shsFinal((&sdata.si2));
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #30 %#lx\n",
+sdata.pad2);
+sdata.pad2 = 0x87654321;
+}
+if (sdata.pad3 != 0x78563412) {
+printf ("Overrun #31 %#lx\n",
+sdata.pad3);
+sdata.pad3 = 0x78563412;
+}
+	memcpy(digest, shsDigest((&sdata.si2)), SHS_DIGESTSIZE);
+	if ((failed = memcmp(digest, results6, SHS_DIGESTSIZE)) != 0)
+	{
+		fprintf(stderr,"SHS test 6 failed!\n");
+		rc = 1;
+	}
+	printf ("%s, results = ", failed ? "Failed" : "Passed");
+	for (i = 0; i < SHS_DIGESTSIZE; ++i)
+		printf("%02x",digest[i]);
+	if (failed)
+	{
+		printf ("\n, expected ");
+		for (i = 0; i < SHS_DIGESTSIZE; ++i)
+			printf("%02x",results6[i]);
+	}
+	printf("\n");
+}
+
+unsigned char results7[SHS_DIGESTSIZE] = {
+0x89,0x41,0x65,0xce,0x76,0xc1,0xd1,0xd1,0xc3,0x6f,
+0xab,0x92,0x79,0x30,0x01,0x71,0x63,0x1f,0x74,0xfe};
+
+int jfsize[] = {0,1,31,32,
+	33,55,56,63,
+	64,65,71,72,
+	73,95,96,97,
+	119,120,123,127};
+int kfsize[] = {0,1,31,32,33,55,56,63};
+
+static void test7(void)
+{
+	struct {
+		long pad1;
+		SHS_INFO si1;
+		long pad2;
+		SHS_INFO si2;
+		long pad3;
+	} sdata;
+	unsigned char digest[SHS_DIGESTSIZE];
+	int failed;
+	int i, j, k, l;
+
+	printf("Running SHS test 7 ...\n");
+	sdata.pad1 = 0x12345678;
+	sdata.pad2 = 0x87654321;
+	sdata.pad3 = 0x78563412;
+	shsInit((&sdata.si2));
+	for (i = 1; i <= 128; ++i)
+	for (j = 0; j < 20; ++j)
+	for (k = 0; k < 8; ++k)
+	{
+		shsInit(&sdata.si1);
+		shsUpdate(&sdata.si1, (randdata+80+j), i);
+if (sdata.pad1 != 0x12345678) {
+printf ("Overrun #1 %#lx at %d,%d,%d\n",
+sdata.pad1, i,j,k);
+sdata.pad1 = 0x12345678;
+}
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #2 %#lx at %d,%d,%d\n",
+sdata.pad2, i,j,k);
+sdata.pad2 = 0x87654321;
+}
+		shsUpdate(&sdata.si1, randdata+i, jfsize[j]);
+if (sdata.pad1 != 0x12345678) {
+printf ("Overrun #3 %#lx at %d,%d,%d\n",
+sdata.pad1, i,j,k);
+sdata.pad1 = 0x12345678;
+}
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #4 %#lx at %d,%d,%d\n",
+sdata.pad2, i,j,k);
+sdata.pad2 = 0x87654321;
+}
+		if (k) shsUpdate(&sdata.si1, randdata+(i^j), kfsize[k]);
+if (sdata.pad1 != 0x12345678) {
+printf ("Overrun #5 %#lx at %d,%d,%d\n",
+sdata.pad1, i,j,k);
+sdata.pad1 = 0x12345678;
+}
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #6 %#lx at %d,%d,%d\n",
+sdata.pad2, i,j,k);
+sdata.pad2 = 0x87654321;
+}
+		shsFinal(&sdata.si1);
+if (sdata.pad1 != 0x12345678) {
+printf ("Overrun #7 %#lx at %d,%d,%d\n",
+sdata.pad1, i,j,k);
+sdata.pad1 = 0x12345678;
+}
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #8 %#lx at %d,%d,%d\n",
+sdata.pad2, i,j,k);
+sdata.pad2 = 0x87654321;
+}
+		memcpy(digest, shsDigest(&sdata.si1), SHS_DIGESTSIZE);
+		if (Dflag & 1)
+		{
+			printf ("%d,%d,%d: ", i, j, k);
+			for (l = 0; l < SHS_DIGESTSIZE; ++l)
+				printf("%02x",digest[l]);
+			printf("\n");
+		}
+		shsUpdate((&sdata.si2), digest, SHS_DIGESTSIZE);
+if (sdata.pad2 != 0x87654321) {
+printf ("Overrun #9 %#lx at %d,%d,%d\n",
+sdata.pad2, i,j,k);
+sdata.pad2 = 0x87654321;
+}
+if (sdata.pad3 != 0x78563412) {
+printf ("Overrun #10 %#lx at %d,%d,%d\n",
+sdata.pad3, i,j,k);
+sdata.pad3 = 0x78563412;
+}
+		if (Dflag & 2)
+			printf ("%d,%d,%d: %08lx%08lx%08lx%08lx%08lx\n",
+				i,j,k,
+				(unsigned long) sdata.si2.digest[0],
+				(unsigned long) sdata.si2.digest[1],
+				(unsigned long) sdata.si2.digest[2],
+				(unsigned long) sdata.si2.digest[3],
+				(unsigned long) sdata.si2.digest[4]);
+	}
+	shsFinal((&sdata.si2));
+	memcpy(digest, shsDigest((&sdata.si2)), SHS_DIGESTSIZE);
+	if ((failed = memcmp(digest, results7, SHS_DIGESTSIZE)) != 0)
+	{
+		fprintf(stderr,"SHS test 7 failed!\n");
+		rc = 1;
+	}
+	printf ("%s, results = ", failed ? "Failed" : "Passed");
+	for (i = 0; i < SHS_DIGESTSIZE; ++i)
+		printf("%02x",digest[i]);
+	if (failed)
+	{
+		printf ("\n, expected ");
+		for (i = 0; i < SHS_DIGESTSIZE; ++i)
+			printf("%02x",results7[i]);
+	}
+	printf("\n");
+}
diff --git a/mechglue/src/lib/crypto/state.c b/mechglue/src/lib/crypto/state.c
new file mode 100644
index 000000000..f69746c81
--- /dev/null
+++ b/mechglue/src/lib/crypto/state.c
@@ -0,0 +1,72 @@
+/*
+ * lib/crypto/state.c
+ *
+ * Copyright (C) 2001 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+
+ * 
+ * 
+ *
+ *  * Section 6 (Encryption) of the Kerberos revisions document defines
+ * cipher states to be used to chain encryptions and decryptions
+ * together.  Examples of cipher states include initialization vectors
+ * for CBC encription.    This file contains implementations of
+ * krb5_c_init_state and krb5_c_free_state used by clients of the
+ * Kerberos crypto library.
+ */
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_init_state (krb5_context context, const krb5_keyblock *key,
+		   krb5_keyusage keyusage, krb5_data *new_state)
+{
+      int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == key->enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    return (*(krb5_enctypes_list[i].enc->init_state))
+      (key, keyusage, new_state);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_free_state (krb5_context context, const krb5_keyblock *key,
+		   krb5_data *state)
+{
+      int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == key->enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    return     (*(krb5_enctypes_list[i].enc->free_state))
+      (state);
+}
diff --git a/mechglue/src/lib/crypto/string_to_cksumtype.c b/mechglue/src/lib/crypto/string_to_cksumtype.c
new file mode 100644
index 000000000..710f26160
--- /dev/null
+++ b/mechglue/src/lib/crypto/string_to_cksumtype.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_string_to_cksumtype(char *string, krb5_cksumtype *cksumtypep)
+{
+    int i;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if (strcasecmp(krb5_cksumtypes_list[i].in_string, string) == 0) {
+	    *cksumtypep = krb5_cksumtypes_list[i].ctype;
+	    return(0);
+	}
+    }
+
+    return(EINVAL);
+}
diff --git a/mechglue/src/lib/crypto/string_to_enctype.c b/mechglue/src/lib/crypto/string_to_enctype.c
new file mode 100644
index 000000000..9d3245bf0
--- /dev/null
+++ b/mechglue/src/lib/crypto/string_to_enctype.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_string_to_enctype(char *string, krb5_enctype *enctypep)
+{
+    int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (strcasecmp(krb5_enctypes_list[i].in_string, string) == 0) {
+	    *enctypep = krb5_enctypes_list[i].etype;
+	    return(0);
+	}
+    }
+
+    return(EINVAL);
+}
diff --git a/mechglue/src/lib/crypto/string_to_key.c b/mechglue/src/lib/crypto/string_to_key.c
new file mode 100644
index 000000000..03165ab25
--- /dev/null
+++ b/mechglue/src/lib/crypto/string_to_key.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_string_to_key_with_params(krb5_context context,
+				 krb5_enctype enctype,
+				 const krb5_data *string,
+				 const krb5_data *salt,
+				 const krb5_data *params,
+				 krb5_keyblock *key);
+
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_string_to_key(krb5_context context, krb5_enctype enctype,
+		     const krb5_data *string, const krb5_data *salt,
+		     krb5_keyblock *key)
+{
+    return krb5_c_string_to_key_with_params(context, enctype, string, salt,
+					    NULL, key);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_string_to_key_with_params(krb5_context context, krb5_enctype enctype,
+				 const krb5_data *string,
+				 const krb5_data *salt,
+				 const krb5_data *params, krb5_keyblock *key)
+{
+    int i;
+    krb5_error_code ret;
+    const struct krb5_enc_provider *enc;
+    size_t keybytes, keylength;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == enctype)
+	    break;
+    }
+
+    if (i == krb5_enctypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    enc = krb5_enctypes_list[i].enc;
+/* xxx AFS string2key function is indicated by a special length  in
+ * the salt in much of the code.  However only the DES enctypes can
+ * deal with this.  Using s2kparams would be a much better solution.*/
+    if (salt && salt->length == SALT_TYPE_AFS_LENGTH) {
+	switch (enctype) {
+	case ENCTYPE_DES_CBC_CRC:
+	case ENCTYPE_DES_CBC_MD4:
+	case ENCTYPE_DES_CBC_MD5:
+	    break;
+	default:
+	    return (KRB5_CRYPTO_INTERNAL);
+	}
+    }
+
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    if ((key->contents = (krb5_octet *) malloc(keylength)) == NULL)
+	return(ENOMEM);
+
+    key->magic = KV5M_KEYBLOCK;
+    key->enctype = enctype;
+    key->length = keylength;
+
+    ret = (*krb5_enctypes_list[i].str2key)(enc, string, salt, params, key);
+    if (ret) {
+	memset(key->contents, 0, keylength);
+	free(key->contents);
+    }
+
+    return(ret);
+}
diff --git a/mechglue/src/lib/crypto/t_cts.c b/mechglue/src/lib/crypto/t_cts.c
new file mode 100644
index 000000000..5066a26df
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_cts.c
@@ -0,0 +1,177 @@
+/*
+ * lib/crypto/vectors.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Test vectors for crypto code, matching data submitted for inclusion
+ * with RFC1510bis.
+ *
+ * N.B.: Doesn't compile -- this file uses some routines internal to our
+ * crypto library which are declared "static" and thus aren't accessible
+ * without modifying the other sources.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "hash_provider.h"
+
+#define ASIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
+
+const char *whoami;
+
+static void printhex (size_t len, const char *p)
+{
+    while (len--)
+	printf ("%02x", 0xff & *p++);
+}
+
+static void printstringhex (const char *p) { printhex (strlen (p), p); }
+
+static void printdata (krb5_data *d) { printhex (d->length, d->data); }
+
+static void printkey (krb5_keyblock *k) { printhex (k->length, k->contents); }
+
+
+#define JURISIC "Juri\305\241i\304\207" /* hi Miro */
+#define ESZETT "\303\237"
+#define GCLEF  "\360\235\204\236" /* outside BMP, woo hoo!  */
+
+static void
+keyToData (krb5_keyblock *k, krb5_data *d)
+{
+    d->length = k->length;
+    d->data = k->contents;
+}
+
+void check_error (int r, int line) {
+    if (r != 0) {
+	fprintf (stderr, "%s:%d: %s\n", __FILE__, line,
+		 error_message (r));
+	exit (1);
+    }
+}
+#define CHECK check_error(r, __LINE__)
+
+extern struct krb5_enc_provider krb5int_enc_des3;
+struct krb5_enc_provider *enc = &krb5int_enc_des3;
+extern struct krb5_enc_provider krb5int_enc_aes128, krb5int_enc_aes256;
+
+static void printd (const char *descr, krb5_data *d) {
+    int i, j;
+    const int r = 16;
+
+    printf("%s:", descr);
+
+    for (i = 0; i < d->length; i += r) {
+	printf("\n  %04x: ", i);
+	for (j = i; j < i + r && j < d->length; j++)
+	    printf(" %02x", 0xff & d->data[j]);
+#ifdef SHOW_TEXT
+	for (; j < i + r; j++)
+	    printf("   ");
+	printf("   ");
+	for (j = i; j < i + r && j < d->length; j++) {
+	    int c = 0xff & d->data[j];
+	    printf("%c", isprint(c) ? c : '.');
+	}
+#endif
+    }
+    printf("\n");
+}
+static void printk(const char *descr, krb5_keyblock *k) {
+    krb5_data d;
+    d.data = k->contents;
+    d.length = k->length;
+    printd(descr, &d);
+}
+
+static void test_cts()
+{
+    static const char input[4*16] =
+	"I would like the General Gau's Chicken, please, and wonton soup.";
+    static const unsigned char aeskey[16] = "chicken teriyaki";
+    static const int lengths[] = { 17, 31, 32, 47, 48, 64 };
+    extern krb5_error_code krb5int_aes_encrypt(const krb5_keyblock *,
+					       const krb5_data *,
+					       const krb5_data *,
+					       krb5_data *);
+
+    int i;
+    char outbuf[64], encivbuf[16], decivbuf[16], outbuf2[64];
+    krb5_data in, out, enciv, deciv, out2;
+    krb5_keyblock key;
+    krb5_error_code err;
+
+    in.data = input;
+    out.data = outbuf;
+    out2.data = outbuf2;
+    enciv.length = deciv.length = 16;
+    enciv.data = encivbuf;
+    deciv.data = decivbuf;
+    key.contents = aeskey;
+    key.length = 16;
+
+    memset(enciv.data, 0, 16);
+    printk("AES 128-bit key", &key);
+    for (i = 0; i < sizeof(lengths)/sizeof(lengths[0]); i++) {
+    memset(enciv.data, 0, 16);
+    memset(deciv.data, 0, 16);
+
+	printf("\n");
+	in.length = out.length = lengths[i];
+	printd("IV", &enciv);
+	err = krb5int_aes_encrypt(&key, &enciv, &in, &out);
+	if (err) {
+	    printf("error %ld from krb5int_aes_encrypt\n", (long)err);
+	    exit(1);
+	}
+	printd("Input", &in);
+	printd("Output", &out);
+	printd("Next IV", &enciv);
+	out2.length = out.length;
+	err = krb5int_aes_decrypt(&key, &deciv, &out, &out2);
+	if (err) {
+	    printf("error %ld from krb5int_aes_decrypt\n", (long)err);
+	    exit(1);
+	}
+	if (out2.length != in.length
+	    || memcmp(in.data, out2.data, in.length)) {
+	    printd("Decryption result DOESN'T MATCH", &out2);
+	    exit(1);
+	}
+	if (memcmp(enciv.data, deciv.data, 16)) {
+	    printd("Decryption IV result DOESN'T MATCH", &deciv);
+	    exit(1);
+	}
+    }
+}
+
+int main (int argc, char **argv)
+{
+    whoami = argv[0];
+    test_cts();
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/t_encrypt.c b/mechglue/src/lib/crypto/t_encrypt.c
new file mode 100644
index 000000000..eb2378b5e
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_encrypt.c
@@ -0,0 +1,153 @@
+/*
+main * lib/crypto/t_encrypt.c
+ *
+ * Copyright2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * <<< Description >>>
+ */
+/* 
+ * Some black-box tests of crypto systems.  Make sure that we can decrypt things we encrypt, etc.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include <stdio.h>
+
+/* What enctypes should we test?*/
+krb5_enctype interesting_enctypes[] = {
+  ENCTYPE_DES_CBC_CRC,
+  ENCTYPE_DES_CBC_MD4,
+  ENCTYPE_DES_CBC_MD5,
+  ENCTYPE_DES3_CBC_SHA1,
+  ENCTYPE_ARCFOUR_HMAC,
+  ENCTYPE_ARCFOUR_HMAC_EXP,
+  ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+  ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+  0
+};
+
+#define test(msg, exp) \
+printf ("%s: . . . ", msg); \
+retval = (exp);\
+if( retval) { \
+  printf( "Failed: %s\n", error_message(retval)); \
+  abort(); \
+} else printf ("OK\n");
+  
+static int compare_results(krb5_data *d1, krb5_data *d2)
+{
+    if (d1->length != d2->length) {
+	/* Decryption can leave a little trailing cruft.
+	   For the current cryptosystems, this can be up to 7 bytes.  */
+	if (d1->length + 8 <= d2->length)
+	    return EINVAL;
+	if (d1->length > d2->length)
+	    return EINVAL;
+    }
+    if (memcmp(d1->data, d2->data, d1->length)) {
+	return EINVAL;
+    }
+    return 0;
+}
+
+int
+main ()
+{
+  krb5_context context = 0;
+  krb5_data  in, in2, out, out2, check, check2, state;
+  int i;
+  size_t len;
+  krb5_enc_data enc_out, enc_out2;
+  krb5_error_code retval;
+  krb5_keyblock *key;
+
+  in.data = "This is a test.\n";
+  in.length = strlen (in.data);
+  in2.data = "This is another test.\n";
+  in2.length = strlen (in2.data);
+
+  test ("Seeding random number generator",
+	krb5_c_random_seed (context, &in));
+  out.data = malloc(2048);
+  out2.data = malloc(2048);
+  check.data = malloc(2048);
+  check2.data = malloc(2048);
+  if (out.data == NULL || out2.data == NULL
+      || check.data == NULL || check2.data == NULL)
+      abort();
+  out.length = 2048;
+  out2.length = 2048;
+  check.length = 2048;
+  check2.length = 2048;
+  for (i = 0; interesting_enctypes[i]; i++) {
+    krb5_enctype enctype = interesting_enctypes [i];
+    printf ("Testing enctype %d\n", enctype);
+    test ("Initializing a keyblock",
+	  krb5_init_keyblock (context, enctype, 0, &key));
+    test ("Generating random key",
+	  krb5_c_make_random_key (context, enctype, key));
+    enc_out.ciphertext = out;
+    enc_out2.ciphertext = out2;
+    /* We use an intermediate `len' because size_t may be different size 
+       than `int' */
+    krb5_c_encrypt_length (context, key->enctype, in.length, &len);
+    enc_out.ciphertext.length = len;
+    test ("Encrypting",
+	  krb5_c_encrypt (context, key, 7, 0, &in, &enc_out));
+    test ("Decrypting",
+	  krb5_c_decrypt (context, key, 7, 0, &enc_out, &check));
+    test ("Comparing", compare_results (&in, &check));
+    enc_out.ciphertext.length = out.length;
+    check.length = 2048;
+    test ("init_state",
+	  krb5_c_init_state (context, key, 7, &state));
+    test ("Encrypting with state",
+	  krb5_c_encrypt (context, key, 7, &state, &in, &enc_out));
+    test ("Encrypting again with state",
+	  krb5_c_encrypt (context, key, 7, &state, &in2, &enc_out2));
+    test ("free_state",
+	  krb5_c_free_state (context, key, &state));
+    test ("init_state",
+	  krb5_c_init_state (context, key, 7, &state));
+    test ("Decrypting with state",
+	  krb5_c_decrypt (context, key, 7, &state, &enc_out, &check));
+    test ("Decrypting again with state",
+	  krb5_c_decrypt (context, key, 7, &state, &enc_out2, &check2));
+    test ("free_state",
+	  krb5_c_free_state (context, key, &state));
+    test ("Comparing",
+	  compare_results (&in, &check));
+    test ("Comparing",
+	  compare_results (&in2, &check2));
+    krb5_free_keyblock (context, key);
+  }
+
+  free(out.data);
+  free(out2.data);
+  free(check.data);
+  free(check2.data);
+  return 0;
+}
+
+	
diff --git a/mechglue/src/lib/crypto/t_hmac.c b/mechglue/src/lib/crypto/t_hmac.c
new file mode 100644
index 000000000..000e64b85
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_hmac.c
@@ -0,0 +1,271 @@
+/*
+ * lib/crypto/t_hmac.c
+ *
+ * Copyright 2001,2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Test vectors for HMAC-MD5 and HMAC-SHA1 (placeholder only).
+ * Tests taken from RFC 2202.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "hash_provider.h"
+
+#define ASIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
+
+const char *whoami;
+
+static void keyToData (krb5_keyblock *k, krb5_data *d) {
+    d->length = k->length;
+    d->data = (char *) k->contents;
+}
+
+#if 0
+static void check_error (int r, int line) {
+    if (r != 0) {
+	fprintf (stderr, "%s:%d: %s\n", __FILE__, line,
+		 error_message (r));
+	exit (1);
+    }
+}
+#define CHECK check_error(r, __LINE__)
+#endif
+
+static void printd (const char *descr, krb5_data *d) {
+    int i, j;
+    const int r = 16;
+
+    printf("%s (%d bytes):", descr, d->length);
+
+    for (i = 0; i < d->length; i += r) {
+	printf("\n  %04x: ", i);
+	for (j = i; j < i + r && j < d->length; j++)
+	    printf(" %02x", 0xff & d->data[j]);
+	for (; j < i + r; j++)
+	    printf("   ");
+	printf("   ");
+	for (j = i; j < i + r && j < d->length; j++) {
+	    int c = 0xff & d->data[j];
+	    printf("%c", isprint(c) ? c : '.');
+	}
+    }
+    printf("\n");
+}
+static void printk(const char *descr, krb5_keyblock *k) {
+    krb5_data d;
+    keyToData(k,&d);
+    printd(descr, &d);
+}
+
+
+
+struct hmac_test {
+    int key_len;
+    unsigned char key[180];
+    int data_len;
+    unsigned char data[80];
+    const char *hexdigest;
+};
+
+static krb5_error_code hmac1(const struct krb5_hash_provider *h, 
+			     krb5_keyblock *key,
+			     krb5_data *in, krb5_data *out)
+{
+    char tmp[40];
+    size_t blocksize, hashsize;
+    krb5_error_code err;
+
+    printk(" test key", key);
+    blocksize = h->blocksize;
+    hashsize = h->hashsize;
+    if (hashsize > sizeof(tmp))
+	abort();
+    if (key->length > blocksize) {
+	krb5_data d, d2;
+	d.data = (char *) key->contents;
+	d.length = key->length;
+	d2.data = tmp;
+	d2.length = hashsize;
+	err = h->hash (1, &d, &d2);
+	if (err) {
+	    com_err(whoami, err, "hashing key before calling hmac");
+	    exit(1);
+	}
+	key->length = d2.length;
+	key->contents = (krb5_octet *) d2.data;
+	printk(" pre-hashed key", key);
+    }
+    printd(" hmac input", in);
+    err = krb5_hmac(h, key, 1, in, out);
+    if (err == 0)
+	printd(" hmac output", out);
+    return err;
+}
+
+static void test_hmac()
+{
+    krb5_keyblock key;
+    krb5_data in, out;
+    char outbuf[20];
+    char stroutbuf[80];
+    krb5_error_code err;
+    int i, j;
+    int lose = 0;
+
+    /* RFC 2202 test vector.  */
+    static const struct hmac_test md5tests[] = {
+	{
+	    16, {
+		0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb,
+		0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb,
+	    },
+	    8, "Hi There",
+	    "0x9294727a3638bb1c13f48ef8158bfc9d"
+	},
+
+	{
+	    4, "Jefe",
+	    28, "what do ya want for nothing?",
+	    "0x750c783e6ab0b503eaa86e310a5db738"
+	},
+
+	{
+	    16, {
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+	    },
+	    50, {
+		0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+	    },
+	    "0x56be34521d144c88dbb8c733f0e8b3f6"
+	},
+
+	{
+	    25, {
+		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+		0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+		0x15, 0x16, 0x17, 0x18, 0x19
+	    },
+	    50, {
+		0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+	    },
+	    "0x697eaf0aca3a3aea3a75164746ffaa79"
+	},
+
+	{
+	    16, {
+		0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+		0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+	    },
+	    20, "Test With Truncation",
+	    "0x56461ef2342edc00f9bab995690efd4c"
+	},
+
+	{
+	    80, {
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	    },
+	    54, "Test Using Larger Than Block-Size Key - Hash Key First",
+	    "0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"
+	},
+
+	{
+	    80, {
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+	    },
+	    73, 
+	    "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+	    "0x6f630fad67cda0ee1fb1f562db3aa53e"
+	},
+    };
+
+    for (i = 0; i < sizeof(md5tests)/sizeof(md5tests[0]); i++) {
+	key.contents = md5tests[i].key;
+	key.length = md5tests[i].key_len;
+	in.data = md5tests[i].data;
+	in.length = md5tests[i].data_len;
+
+	out.data = outbuf;
+	out.length = 20;
+	printf("\nTest #%d:\n", i+1);
+	err = hmac1(&krb5int_hash_md5, &key, &in, &out);
+	if (err) {
+	    com_err(whoami, err, "computing hmac");
+	    exit(1);
+	}
+
+	if (sizeof(stroutbuf) - 3 < 2 * out.length)
+	    abort();
+	strcpy(stroutbuf, "0x");
+	for (j = 0; j < out.length; j++)
+	    sprintf(stroutbuf + strlen(stroutbuf), "%02x", 0xff & outbuf[j]);
+	if (strcmp(stroutbuf, md5tests[i].hexdigest)) {
+	    printf("*** CHECK FAILED!\n"
+		   "\tReturned: %s.\n"
+		   "\tExpected: %s.\n", stroutbuf, md5tests[i].hexdigest);
+	    lose++;
+	} else
+	    printf("Matches expected result.\n");
+    }
+
+    /* Do again with SHA-1 tests....  */
+
+    if (lose) {
+	printf("%d failures; exiting.\n", lose);
+	exit(1);
+    }
+}
+
+
+int main (int argc, char **argv)
+{
+    whoami = argv[0];
+    test_hmac();
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/t_nfold.c b/mechglue/src/lib/crypto/t_nfold.c
new file mode 100644
index 000000000..6be0a0934
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_nfold.c
@@ -0,0 +1,165 @@
+/*
+ * lib/crypto/t_nfold.c
+ *
+ * Copyright 1988, 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Program to test the correctness of nfold implementation.
+ *
+ * exit returns	 0 ==> success
+ * 		-1 ==> error
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "k5-int.h"
+
+#define ASIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
+
+static void printhex (size_t len, const unsigned char *p)
+{
+    while (len--)
+	printf ("%02x", 0xff & *p++);
+}
+
+static void printstringhex (const unsigned char *p) {
+    printhex (strlen ((const char *) p), p);
+}
+
+static void rfc_tests ()
+{
+    int i;
+    struct {
+	char *input;
+	unsigned int n;
+	unsigned char exp[192/8];
+    } tests[] = {
+	{ "012345", 64,
+	  { 0xbe,0x07,0x26,0x31,0x27,0x6b,0x19,0x55, }
+	},
+	{ "password", 56,
+	  { 0x78,0xa0,0x7b,0x6c,0xaf,0x85,0xfa, }
+	},
+	{ "Rough Consensus, and Running Code", 64,
+	  { 0xbb,0x6e,0xd3,0x08,0x70,0xb7,0xf0,0xe0, }
+	},
+	{ "password", 168,
+	  { 0x59,0xe4,0xa8,0xca,0x7c,0x03,0x85,0xc3,
+	    0xc3,0x7b,0x3f,0x6d,0x20,0x00,0x24,0x7c,
+	    0xb6,0xe6,0xbd,0x5b,0x3e, }
+	},
+	{ "MASSACHVSETTS INSTITVTE OF TECHNOLOGY", 192,
+	  { 0xdb,0x3b,0x0d,0x8f,0x0b,0x06,0x1e,0x60,
+	    0x32,0x82,0xb3,0x08,0xa5,0x08,0x41,0x22,
+	    0x9a,0xd7,0x98,0xfa,0xb9,0x54,0x0c,0x1b, }
+	},
+    };
+    unsigned char outbuf[192/8];
+
+    printf ("RFC tests:\n");
+    for (i = 0; i < ASIZE (tests); i++) {
+	unsigned char *p = (unsigned char *) tests[i].input;
+	assert (tests[i].n / 8 <= sizeof (outbuf));
+	krb5_nfold (8 * strlen ((char *) p), p, tests[i].n, outbuf);
+	printf ("%d-fold(\"%s\") =\n", tests[i].n, p);
+	printf ("%d-fold(", tests[i].n);
+	printstringhex (p);
+	printf (") =\n\t");
+	printhex (tests[i].n / 8, outbuf);
+	printf ("\n\n");
+	if (memcmp (outbuf, tests[i].exp, tests[i].n/8) != 0) {
+	    printf ("wrong value! expected:\n\t");
+	    printhex (tests[i].n / 8, tests[i].exp);
+	    exit (1);
+	}
+    }
+}
+
+static void fold_kerberos(unsigned int nbytes)
+{
+    unsigned char cipher_text[300];
+    int j;
+
+    if (nbytes > 300)
+	abort();
+
+    printf("%d-fold(\"kerberos\") =\n\t", nbytes*8);
+    krb5_nfold(64, (unsigned char *) "kerberos", 8*nbytes, cipher_text);
+    for (j=0; j<nbytes; j++)
+	printf("%s%02x", (j&3) ? "" : " ", cipher_text[j]);
+    printf("\n");
+}
+
+unsigned char *nfold_in[] = {
+    (unsigned char *) "basch",
+    (unsigned char *) "eichin",
+    (unsigned char *) "sommerfeld",
+    (unsigned char *) "MASSACHVSETTS INSTITVTE OF TECHNOLOGY" };
+
+unsigned char nfold_192[4][24] = {
+    { 0x1a, 0xab, 0x6b, 0x42, 0x96, 0x4b, 0x98, 0xb2, 0x1f, 0x8c, 0xde, 0x2d,
+      0x24, 0x48, 0xba, 0x34, 0x55, 0xd7, 0x86, 0x2c, 0x97, 0x31, 0x64, 0x3f },
+    { 0x65, 0x69, 0x63, 0x68, 0x69, 0x6e, 0x4b, 0x73, 0x2b, 0x4b, 0x1b, 0x43,
+      0xda, 0x1a, 0x5b, 0x99, 0x5a, 0x58, 0xd2, 0xc6, 0xd0, 0xd2, 0xdc, 0xca },
+    { 0x2f, 0x7a, 0x98, 0x55, 0x7c, 0x6e, 0xe4, 0xab, 0xad, 0xf4, 0xe7, 0x11,
+      0x92, 0xdd, 0x44, 0x2b, 0xd4, 0xff, 0x53, 0x25, 0xa5, 0xde, 0xf7, 0x5c },
+    { 0xdb, 0x3b, 0x0d, 0x8f, 0x0b, 0x06, 0x1e, 0x60, 0x32, 0x82, 0xb3, 0x08,
+      0xa5, 0x08, 0x41, 0x22, 0x9a, 0xd7, 0x98, 0xfa, 0xb9, 0x54, 0x0c, 0x1b }
+};
+
+int
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+    unsigned char cipher_text[64];
+    int i, j;
+
+    printf("N-fold\n");
+    for (i=0; i<sizeof(nfold_in)/sizeof(char *); i++) {
+	printf("\tInput:\t\"%.*s\"\n", (int) strlen((char *) nfold_in[i]), 
+	       nfold_in[i]);
+	printf("\t192-Fold:\t");
+	krb5_nfold(strlen((char *) nfold_in[i])*8, nfold_in[i], 24*8, 
+		   cipher_text);
+	for (j=0; j<24; j++)
+	    printf("%s%02x", (j&3) ? "" : " ", cipher_text[j]);
+	printf("\n");
+	if (memcmp(cipher_text, nfold_192[i], 24)) {
+	    printf("verify: error in n-fold\n");
+	    exit(-1);
+	};
+    }
+    rfc_tests ();
+
+    printf("verify: N-fold is correct\n\n");
+
+    fold_kerberos(8);
+    fold_kerberos(16);
+    fold_kerberos(21);
+    fold_kerberos(32);
+
+    exit(0);
+}
diff --git a/mechglue/src/lib/crypto/t_pkcs5.c b/mechglue/src/lib/crypto/t_pkcs5.c
new file mode 100644
index 000000000..fa1f43dea
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_pkcs5.c
@@ -0,0 +1,105 @@
+/*
+ * lib/crypto/t_pkcs5.c
+ *
+ * Copyright 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Test vectors for PBKDF2 (from PKCS #5v2), based on RFC 3211.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "k5-int.h"
+
+static void printhex (size_t len, const char *p)
+{
+    while (len--)
+	printf (" %02X", 0xff & *p++);
+}
+
+static void printdata (krb5_data *d) {
+    printhex (d->length, d->data);
+}
+
+static void test_pbkdf2_rfc3211()
+{
+    char x[100];
+    krb5_error_code err;
+    krb5_data d, pass, salt;
+    int i;
+
+    /* RFC 3211 test cases.  */
+    static const struct {
+	const char *pass;
+	const char *salt;
+	unsigned int count;
+	size_t len;
+	const unsigned char expected[24];
+    } t[] = {
+	{ "password", "\x12\x34\x56\x78\x78\x56\x34\x12", 5, 8,
+	  { 0xD1, 0xDA, 0xA7, 0x86, 0x15, 0xF2, 0x87, 0xE6 } },
+	{ "All n-entities must communicate with other "
+	  "n-entities via n-1 entiteeheehees",
+	  "\x12\x34\x56\x78\x78\x56\x34\x12", 500, 24,
+	  { 0x6A, 0x89, 0x70, 0xBF, 0x68, 0xC9, 0x2C, 0xAE,
+	    0xA8, 0x4A, 0x8D, 0xF2, 0x85, 0x10, 0x85, 0x86,
+	    0x07, 0x12, 0x63, 0x80, 0xCC, 0x47, 0xAB, 0x2D } },
+    };
+
+    d.data = x;
+    printf("RFC 3211 test of PBKDF#2\n");
+
+    for (i = 0; i < sizeof(t)/sizeof(t[0]); i++) {
+
+	printf("pkbdf2(iter_count=%d, dklen=%d (%d bytes), salt=12 34 56 78 78 56 34 12,\n"
+	       "       pass=%s):\n  ->",
+	       t[i].count, t[i].len * 8, t[i].len, t[i].pass);
+
+	d.length = t[i].len;
+	pass.data = t[i].pass;
+	pass.length = strlen(pass.data);
+	salt.data = t[i].salt;
+	salt.length = strlen(salt.data);
+	err = krb5int_pbkdf2_hmac_sha1 (&d, t[i].count, &pass, &salt);
+	if (err) {
+	    printf("error in computing pbkdf2: %s\n", error_message(err));
+	    exit(1);
+	}
+	printdata(&d);
+	if (!memcmp(x, t[i].expected, t[i].len))
+	    printf("\nTest passed.\n\n");
+	else {
+	    printf("\n*** CHECK FAILED!\n");
+	    exit(1);
+	}
+    }
+}
+
+int main ()
+{
+    test_pbkdf2_rfc3211();
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/t_prf.c b/mechglue/src/lib/crypto/t_prf.c
new file mode 100644
index 000000000..f11784b3d
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_prf.c
@@ -0,0 +1,89 @@
+/*
+ * lib/crypto/t_prf.c
+ *
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * This file contains tests for the PRF  code in Kerberos.  IT reads
+ *an input file, and writes an output file.  It is assumed that the
+ *output file will be diffed against expected output  to see whether
+ *regression tests pass.  The input file is a very primitive format.
+ *It  includes an enctype and  to be string2keyed   followed by a number of bytes of input
+ *length, followed by  that many bytes of input.  The program outputs
+ *krb5_c_prf of that input and key  as a hex string.
+ */
+
+#include "k5-int.h"
+#include <assert.h>
+
+int main () {
+  krb5_error_code ret;
+  krb5_data input, output;
+  krb5_keyblock *key = NULL;
+  unsigned int in_length;
+  unsigned int i;
+  while (1) {
+      krb5_enctype enctype;
+      char s[1025];
+
+      if (scanf( "%d", &enctype) == EOF)
+	  break;
+      if (scanf("%1024s", &s[0]) == EOF)
+	  break;
+      assert (krb5_init_keyblock(0, enctype, 0, &key) == 0);
+      input.data = &s[0];
+      input.length = strlen(s);
+      assert(krb5_c_string_to_key (0, enctype, &input, &input, key) == 0);
+    
+      if (scanf("%u", &in_length) == EOF)
+	  break;
+
+      if (in_length ) {
+	  unsigned int lc;
+	  assert ((input.data = malloc(in_length)) != NULL);
+	  for (lc = in_length; lc > 0; lc--) {
+	      scanf ("%2x",  &i);
+	      input.data[in_length-lc] = (unsigned) (i&0xff);
+	  }
+	  input.length = in_length;
+	  assert (krb5_c_prf_length(0, enctype, &i) == 0);
+	  assert (output.data = malloc(i));
+	  output.length = i;
+	  assert (krb5_c_prf(0, key, &input, &output) == 0);
+      
+	  free (input.data);
+	  input.data = NULL;
+      }
+      for (; i > 0; i--) {
+	  printf ("%02x",
+		  (unsigned int) ((unsigned char ) output.data[output.length-i]));
+      }
+      printf ("\n");
+
+      free (output.data);
+      output.data = NULL;
+      krb5_free_keyblock(0, key);
+      key = NULL;
+  }
+
+  return (0);
+}
diff --git a/mechglue/src/lib/crypto/t_prng.c b/mechglue/src/lib/crypto/t_prng.c
new file mode 100644
index 000000000..49c0aec74
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_prng.c
@@ -0,0 +1,87 @@
+/*
+ * lib/crypto/t_prng.c
+ *
+ * Copyright (C) 2001 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * This file contains tests for the PRNG code in Kerberos.  IT reads
+ *an input file, and writes an output file.  It is assumed that the
+ *output file will be diffed against expected output  to see whether
+ *regression tests pass.  The input file is very primitive format.  It
+ *is composed of alternating seeds and outputs.   The first  line in
+ *the file is an integer source Id from the krb5_c_randsource enum in
+ *krb5.h.  Then an integer seed length is be
+ *read.  Then that many bytes (encoded in hex) is read; whitspace or
+ *newlines may be inserted between bytes.  Then after the seed data is
+ *a  integer describing how many bytes of output should be written.
+ *Then another source ID and seed length is read.  If the seed length
+ *is 0, the source id is ignored and the seed is not seeded.
+ */
+
+#include "k5-int.h"
+#include <assert.h>
+
+int main () {
+  krb5_error_code ret;
+  krb5_data input, output;
+  unsigned int source_id, seed_length;
+  unsigned int i;
+  while (1) {
+        /* Read source*/
+    if (scanf ("%u", &source_id ) == EOF )
+      break;
+        /* Read seed length*/
+    if (scanf ("%u", &seed_length) == EOF)
+      break;
+    if (seed_length ) {
+      unsigned int lc;
+      assert ((input.data = malloc(seed_length)) != NULL);
+      for (lc = seed_length; lc > 0; lc--) {
+	scanf ("%2x",  &i);
+	input.data[seed_length-lc] = (unsigned) (i&0xff);
+      }
+      input.length = seed_length;
+      assert (krb5_c_random_add_entropy (0, source_id, &input) == 0);
+      free (input.data);
+      input.data = NULL;
+    }
+    if (scanf ("%u", &i) == EOF)
+      break;
+    if (i) {
+      assert ((output.data = malloc (i)) != NULL);
+      output.length = i;
+      ret = krb5_c_random_make_octets (0, &output);
+      if (ret)
+	printf ("failed\n");
+      else {
+	for (; i > 0; i--) {
+	  printf ("%02x",
+		  (unsigned int) ((unsigned char ) output.data[output.length-i]));
+	}
+	printf ("\n");
+      }
+      free (output.data);
+      output.data = NULL;
+    }
+  }
+  return (0);
+}
diff --git a/mechglue/src/lib/crypto/t_prng.comments b/mechglue/src/lib/crypto/t_prng.comments
new file mode 100644
index 000000000..1666b7060
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_prng.comments
@@ -0,0 +1,14 @@
+Things this test tries to do:
+*adding data
+* getting random data
+* adding more data but not enough for reseed
+*getting more random data
+*adding enough to trigger a reseed
+*getting more random data
+* getting random data without a reseed inbetween
+* getting enough data to trigger a gate
+
+
+If you adjust the blocksize or the seeding parameters then this test
+should be adjusted.
+
diff --git a/mechglue/src/lib/crypto/t_prng.expected b/mechglue/src/lib/crypto/t_prng.expected
new file mode 100644
index 000000000..f7f165051
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_prng.expected
@@ -0,0 +1,4 @@
+d2f8fbd707a8ece5cb11a02f
+eb4cb6e06236ea1c0529f7acbfca8d78cb85bb1d
+a244005ae870604342b0386025874ec4306c1dd483c118621b
+63e6408afdf9fd225839a7afcc6da6ae494fb4f82bd21ea06bb17ca0848bdae8cea671f545aac52699951caba960c536024b4102f47d61d61fd7b17582a4cf50ba7d215062558f71483249e079689893f3bf25def7f45f9e852281269904d401d6719e3115f6410088c6c5171e878494362684d2116633bb9ea8d9ed5faec73cb076c44d5d639bc2c8ae3de54f0e1e092d5ea439e607e9cd73053bbdf40723f5b48f298fdeeef845e22e06f2f6362fc67fba366e638a7988999d456dcc3d53b23388d685620a7c446d28cd94b13049761b64779db5412e78ac4bab2aacf103fd1b9ceb7213d43710d6a46fd4223fa20e0a68d3e16a82cbadea650ba815dc9ee99b4eb8e2acdac866a05d90ab9de3246db0560fb4b36633bb642c3ea9bf358937dda743f9cef1148791c2cac58995b8eb8fdb1c0cce1686e04ebef5ae7aae36691faafbe8920d3c013f125b687eb019faefa70fc750c52e2e2e33f426824bf1da31268a9bb8d9501f2290375755f8bf77b46639346b4011b78ce9d81105c7791ec5991a2f1eab037488b604df1a21c5c4e36a7c76dca5884d36e30fe8d30d0e7d93fab72062219390655eace2b434b0e2cd21ec9c5a8aa13e783afadcdf386fc43b960c518acb38d7e3da2f67695c1c1c25c4f251b40f4c2e42e89f6f642c32e66159f6ce24aa910fb5d95e3a899a4de5efcf570996e1a662d14362b65d00524df79cd56be93bd572526e4dfd1cf9f7586bc021105cf5456b28c1f45a6d354d000a113e15f64aa0b5253830c07afc8fa47b58dbba8bbae1645b2093035f2387036229dec6f7141b444b8bb7d0382a742bd5c746ba2d7af3af1cadb2dd90bda87d5daed2d2eebd243c7b2d06955d0cc7fe1061d4cfa3b061aaeb97084d9f9a7ec9dbe9e642f4f090d57b5ea1bd8b393f00896d3dc7089e1fc4c2fed7336c2a8c6d119a682c6cc4ae1ccedd30292f2c5570bf4d6287ce8e20b8b34e7fc38e87273f588cd33b8c913defaee5f6bf8fdeda72531c845a6f97a84d5e9b9a6497d4c48614dee7693df35faedc008fded852be8d4bffd475476336e54ed48a827b99d3f0e39019a40d43aef5ae522ec6e280f6a8e7d2713f3c3188bed2476a84af5a5afefa0fa178ed07de0e073693e8790f8bbd0cf9183e48f140b556e723565c382cf7a4c186748189a14e603e4ac70e2b80c266334231207721d16d834a973b48cfec584620624686603cfd66d55dbf8dd8eccd99d85f041c624ec3a7bec314af95d2313afd43cc5cc19249cf85b7ab0b5a4530b597341e7477b249fef1a07eb0d8fa790e9bce752e8b2f7086e98ab44751e0a1b37f29682ce67c0de7a2fd036f26ed719fc343bbf49432aec651d884c99c24d5943c747f7ec3b48d4c2236a8cb6151794daeda073774cc88ff121fdd423b81ef2f34c8f281ca2e5366faee87ff7a623484f2937cc0680ed76ead32b43cb6c67a21f8089b435f38a404d267397c6435cfac16591a3573d9e92f8c4a8028719c22662b903ddb16e08ea7bb2d6b8938c06bdddb4d174c7f2c5d812ed3a34ba8859a1ae841b3b9d5522372018c9aa55b048df826f05a087f185808cb66899f320783a1c4aa2dcd5f2665405ba7e5726e122b67559a39da30956e49fe7711d1b2506e159c5ea42ce0a1ad497220ee3b3e5ebcb73db975bd08e8be56e5f4533b8295b10d4b0fef466de6540f8fe10530c9716d83a12f5ffbba5b4dbc50ed89388d04e7a15d3d9d251041ed5303efa2525bc62a5aeb821f7838676811784584534be8a7fc667f09c3fe1bbf7d0aad29324f562086ecb8326829413867
diff --git a/mechglue/src/lib/crypto/t_prng.reseedtest b/mechglue/src/lib/crypto/t_prng.reseedtest
new file mode 100644
index 000000000..5eee0c064
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_prng.reseedtest
@@ -0,0 +1,31 @@
+1
+160
+ cb 12 70 40 ee fb 76 2e 32 0d f1 0c a7 a9 36 f8
+ c8 f3 35 4e 0f 51 18 cd 25 0f 48 5b e4 97 aa 4f
+ be 7e 93 af dd 15 29 fc 24 4f 0b 9a 9b 1d ad 7f
+ 32 c8 a6 96 d4 34 aa 83 d2 d7 33 b0 2f aa ba f6
+ cf 8c 78 ad 8a 52 e1 48 e4 7c a7 c5 57 49 31 ea
+ db b7 9b 6b ab 13 f3 12 a5 ec 67 db 1e 83 73 be
+ ca 59 fc ed 29 8c f3 ef ca fd 81 55 fa 91 3b 31
+ da 24 d2 8b c1 a5 c1 3a 9c 50 a6 3c a1 60 31 0f
+ 62 c7 88 9b 1a e9 9f 3c 0f 04 d0 35 11 45 f0 8b
+ 84 a2 26 85 67 f1 e6 2b 34 6b ab 9b 3f c1 a1 0e
+0
+1
+40
+ f4 fc ab 98 45 a0 41 e4 4d 65 9c eb c2 c9 74 a4
+ 55 df 6c 78 78 bc db ae e7 63 b8 a7 33 3b d7 50
+ f6 33 c4 a0 1d 14 45 04
+0
+0
+40
+ 16 80 1d 78 39 4b 3a 27 80 87 08 6c a9 37 59 74
+ 60 f8 fc 37 10 4a 8a c4 d6 3e 6a 41 1a e1 5f 69
+ 92 12 5a e1 3b 86 f1 5d
+0
+0
+40
+ a3 c8 78 4a a0 4d ce 3c 2a 8e 34 bf f7 06 dc d7
+ 92 13 bd 74 45 72 40 b6 1c d6 55 28 47 1e f4 70
+ 74 e4 94 d7 17 a6 7e 3b
+20
diff --git a/mechglue/src/lib/crypto/t_prng.reseedtest-comments b/mechglue/src/lib/crypto/t_prng.reseedtest-comments
new file mode 100644
index 000000000..e50e09602
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_prng.reseedtest-comments
@@ -0,0 +1,21 @@
+The reseedtest is intended to allow confirmation that if sufficient
+entropy is provided then the PRNG will reseed (well initially seed)
+itself before the first random data is requested.  This test is not
+useful to run in an automated manner because the point is to look at
+internal function call order.
+
+To test this, set a break point at krb5int_yarrow_reseed and
+krb5_c_random_make_octets and run the test.  The reseed function
+should be called with a pool of 1 (YARROW_SLOW_POOL) before
+krb5_c_random_make_octets is called.
+
+A slow reseed should require two sources to reach sufficient entropy.
+Sources  start out sending entropy to fast pool then alternate with
+slow pool.  So this test does the following:
+* Seed source 1
+* Seed source 1 (this time to slow pool)
+* Seed source 0
+* Seed source 0 (to slow pool triggering reseed)
+* Output some random data
+
+
diff --git a/mechglue/src/lib/crypto/t_prng.reseedtest-expected b/mechglue/src/lib/crypto/t_prng.reseedtest-expected
new file mode 100644
index 000000000..d7b50801e
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_prng.reseedtest-expected
@@ -0,0 +1 @@
+fd543f42aded9bd725c9b05682cd0f504c1b33d1
diff --git a/mechglue/src/lib/crypto/t_prng.seed b/mechglue/src/lib/crypto/t_prng.seed
new file mode 100644
index 000000000..79f4f6458
--- /dev/null
+++ b/mechglue/src/lib/crypto/t_prng.seed
@@ -0,0 +1,25 @@
+2
+20
+ c9 72 2b e4 90 e1 fa 4b da d4 2f 43 0d dd d9 91
+ 39 d0 23 c4
+0
+1
+24
+ 87 1c 4f d4 4a 8b b8 cf 54 4e eb 9b 1f bb 7a 8e
+ 9a 7d 8d 62
+ ca 41 18 00
+12
+0
+0
+20
+1
+24
+ 28 d4 bd d4 81 85 ca 70 d5 f0 e4 a4 f3 45 80 01
+ 6a 34 79 69 0e e0 cd 21
+25
+2
+40
+ de 7c f0 c5 6a 37 0b 34 f4 0c 3a 19 31 eb 66 f1
+ ae 5f c6 a3 64 3f 2e a9 76 e1 87 93 df b6 94 86
+ bd 96 57 3f 31 e6 88 8c
+1290
diff --git a/mechglue/src/lib/crypto/valid_cksumtype.c b/mechglue/src/lib/crypto/valid_cksumtype.c
new file mode 100644
index 000000000..bc34c0b95
--- /dev/null
+++ b/mechglue/src/lib/crypto/valid_cksumtype.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_boolean KRB5_CALLCONV
+krb5_c_valid_cksumtype(krb5_cksumtype ctype)
+{
+    int i;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if (krb5_cksumtypes_list[i].ctype == ctype)
+	    return(1);
+    }
+
+    return(0);
+}
+
+krb5_boolean KRB5_CALLCONV
+valid_cksumtype(krb5_cksumtype ctype)
+{
+    return krb5_c_valid_cksumtype (ctype);
+}
diff --git a/mechglue/src/lib/crypto/valid_enctype.c b/mechglue/src/lib/crypto/valid_enctype.c
new file mode 100644
index 000000000..f36023084
--- /dev/null
+++ b/mechglue/src/lib/crypto/valid_enctype.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_boolean KRB5_CALLCONV
+krb5_c_valid_enctype(krb5_enctype etype)
+{
+    int i;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+	if (krb5_enctypes_list[i].etype == etype)
+	    return(1);
+    }
+
+    return(0);
+}
+
+krb5_boolean KRB5_CALLCONV
+valid_enctype(krb5_enctype etype)
+{
+    return krb5_c_valid_enctype (etype);
+}
diff --git a/mechglue/src/lib/crypto/vectors.c b/mechglue/src/lib/crypto/vectors.c
new file mode 100644
index 000000000..27b6206c9
--- /dev/null
+++ b/mechglue/src/lib/crypto/vectors.c
@@ -0,0 +1,457 @@
+/*
+ * lib/crypto/vectors.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Test vectors for crypto code, matching data submitted for inclusion
+ * with RFC1510bis.
+ *
+ * N.B.: Doesn't compile -- this file uses some routines internal to our
+ * crypto library which are declared "static" and thus aren't accessible
+ * without modifying the other sources.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "hash_provider.h"
+
+#define ASIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
+
+const char *whoami;
+
+static void printhex (size_t len, const char *p)
+{
+    while (len--)
+	printf ("%02x", 0xff & *p++);
+}
+
+static void printstringhex (const char *p) { printhex (strlen (p), p); }
+
+static void printdata (krb5_data *d) { printhex (d->length, d->data); }
+
+static void printkey (krb5_keyblock *k) { printhex (k->length, k->contents); }
+
+static void test_nfold ()
+{
+    int i;
+    static const struct {
+	char *input;
+	int n;
+    } tests[] = {
+	{ "012345", 64, },
+	{ "password", 56, },
+	{ "Rough Consensus, and Running Code", 64, },
+	{ "password", 168, },
+	{ "MASSACHVSETTS INSTITVTE OF TECHNOLOGY", 192 },
+	{ "Q", 168 },
+	{ "ba", 168 },
+    };
+    unsigned char outbuf[192/8];
+
+    for (i = 0; i < ASIZE (tests); i++) {
+	char *p = tests[i].input;
+	assert (tests[i].n / 8 <= sizeof (outbuf));
+	printf ("%d-fold(\"%s\") =\n", tests[i].n, p);
+	printf ("%d-fold(", tests[i].n);
+	printstringhex (p);
+	printf (") =\n\t");
+	krb5_nfold (8 * strlen (p), p, tests[i].n, outbuf);
+	printhex (tests[i].n / 8U, outbuf);
+	printf ("\n\n");
+    }
+}
+
+#define JURISIC "Juri\305\241i\304\207" /* hi Miro */
+#define ESZETT "\303\237"
+#define GCLEF  "\360\235\204\236" /* outside BMP, woo hoo!  */
+
+/* Some weak keys:
+    {0x1f,0x1f,0x1f,0x1f,0x0e,0x0e,0x0e,0x0e},
+    {0xe0,0xe0,0xe0,0xe0,0xf1,0xf1,0xf1,0xf1},
+   so try to generate them. */
+
+static void
+test_mit_des_s2k ()
+{
+    static const struct {
+	const char *pass;
+	const char *salt;
+    } pairs[] = {
+	{ "password", "ATHENA.MIT.EDUraeburn" },
+	{ "potatoe", "WHITEHOUSE.GOVdanny" },
+	{ "penny", "EXAMPLE.COMbuckaroo", },
+	{ GCLEF, "EXAMPLE.COMpianist" },
+	{ ESZETT, "ATHENA.MIT.EDU" JURISIC },
+	/* These two trigger weak-key fixups.  */
+	{ "11119999", "AAAAAAAA" },
+	{ "NNNN6666", "FFFFAAAA" },
+    };
+    int i;
+
+    for (i = 0; i < ASIZE (pairs); i++) {
+	const char *p = pairs[i].pass;
+	const char *s = pairs[i].salt;
+	krb5_data pd;
+	krb5_data sd;
+	unsigned char key_contents[60];
+	krb5_keyblock key;
+	krb5_error_code r;
+	char buf[80];
+
+	key.contents = key_contents;
+
+	pd.length = strlen (p);
+	pd.data = (char *) p;
+	sd.length = strlen (s);
+	sd.data = (char *) s;
+
+	assert (strlen (s) + 4 < sizeof (buf));
+	sprintf (buf, "\"%s\"", s);
+	printf (  "salt:     %-25s", buf);
+	printhex (strlen(s), s);
+	sprintf (buf, "\"%s\"", p);
+	printf ("\npassword: %-25s", buf);
+	printhex (strlen(p), p);
+	printf ("\n");
+	r = krb5int_des_string_to_key (0, &pd, &sd, 0, &key);
+	printf (  "DES key:  %-25s", "");
+	printhex (key.length, key.contents);
+	printf ("\n\n");
+    }
+}
+
+static void
+test_s2k (krb5_enctype enctype)
+{
+    static const struct {
+	const char *pass;
+	const char *salt;
+    } pairs[] = {
+	{ "password", "ATHENA.MIT.EDUraeburn" },
+	{ "potatoe", "WHITEHOUSE.GOVdanny" },
+	{ "penny", "EXAMPLE.COMbuckaroo", },
+	{ ESZETT, "ATHENA.MIT.EDU" JURISIC },
+	{ GCLEF, "EXAMPLE.COMpianist" },
+    };
+    int i;
+
+    for (i = 0; i < ASIZE (pairs); i++) {
+	const char *p = pairs[i].pass;
+	const char *s = pairs[i].salt;
+	krb5_data pd, sd;
+	unsigned char key_contents[60];
+	krb5_keyblock key;
+	krb5_error_code r;
+	char buf[80];
+
+	pd.length = strlen (p);
+	pd.data = (char *) p;
+	sd.length = strlen (s);
+	sd.data = (char *) s;
+	key.contents = key_contents;
+
+	assert (strlen (s) + 4 < sizeof (buf));
+	sprintf (buf, "\"%s\"", s);
+	printf (  "salt:\t%s\n\t", buf);
+	printhex (strlen(s), s);
+	sprintf (buf, "\"%s\"", p);
+	printf ("\npasswd:\t%s\n\t", buf);
+	printhex (strlen(p), p);
+	printf ("\n");
+	r = krb5_c_string_to_key (0, enctype, &pd, &sd, &key);
+	printf (  "key:\t");
+	printhex (key.length, key.contents);
+	printf ("\n\n");
+    }
+}
+
+static void test_des3_s2k () { test_s2k (ENCTYPE_DES3_CBC_SHA1); }
+
+static void
+keyToData (krb5_keyblock *k, krb5_data *d)
+{
+    d->length = k->length;
+    d->data = k->contents;
+}
+
+void check_error (int r, int line) {
+    if (r != 0) {
+	fprintf (stderr, "%s:%d: %s\n", __FILE__, line,
+		 error_message (r));
+	exit (1);
+    }
+}
+#define CHECK check_error(r, __LINE__)
+
+extern struct krb5_enc_provider krb5int_enc_des3;
+struct krb5_enc_provider *enc = &krb5int_enc_des3;
+extern struct krb5_enc_provider krb5int_enc_aes128, krb5int_enc_aes256;
+
+void DK (krb5_keyblock *out, krb5_keyblock *in, const krb5_data *usage) {
+    krb5_error_code r;
+    r = krb5_derive_key (enc, in, out, usage);
+    CHECK;
+}
+
+void DR (krb5_data *out, krb5_keyblock *in, const krb5_data *usage) {
+    krb5_error_code r;
+    r = krb5_derive_random (enc, in, out, usage);
+    CHECK;
+}
+
+#define KEYBYTES  21
+#define KEYLENGTH 24
+
+void test_dr_dk ()
+{
+    static const struct {
+	unsigned char keydata[KEYLENGTH];
+	int usage_len;
+	unsigned char usage[8];
+    } derive_tests[] = {
+	{
+	    {
+		0xdc, 0xe0, 0x6b, 0x1f, 0x64, 0xc8, 0x57, 0xa1,
+		0x1c, 0x3d, 0xb5, 0x7c, 0x51, 0x89, 0x9b, 0x2c,
+		0xc1, 0x79, 0x10, 0x08, 0xce, 0x97, 0x3b, 0x92,
+	    },
+	    5, { 0x00, 0x00, 0x00, 0x01, 0x55 },
+	},
+	{
+	    {
+		0x5e, 0x13, 0xd3, 0x1c, 0x70, 0xef, 0x76, 0x57,
+		0x46, 0x57, 0x85, 0x31, 0xcb, 0x51, 0xc1, 0x5b,
+		0xf1, 0x1c, 0xa8, 0x2c, 0x97, 0xce, 0xe9, 0xf2,
+	    },
+	    5, { 0x00, 0x00, 0x00, 0x01, 0xaa },
+	},
+	{
+	    {
+		0x98, 0xe6, 0xfd, 0x8a, 0x04, 0xa4, 0xb6, 0x85,
+		0x9b, 0x75, 0xa1, 0x76, 0x54, 0x0b, 0x97, 0x52,
+		0xba, 0xd3, 0xec, 0xd6, 0x10, 0xa2, 0x52, 0xbc,
+	    },
+	    5, { 0x00, 0x00, 0x00, 0x01, 0x55 },
+	},
+	{
+	    {
+		0x62, 0x2a, 0xec, 0x25, 0xa2, 0xfe, 0x2c, 0xad,
+		0x70, 0x94, 0x68, 0x0b, 0x7c, 0x64, 0x94, 0x02,
+		0x80, 0x08, 0x4c, 0x1a, 0x7c, 0xec, 0x92, 0xb5,
+	    },
+	    5, { 0x00, 0x00, 0x00, 0x01, 0xaa },
+	},
+	{
+	    {
+		0xd3, 0xf8, 0x29, 0x8c, 0xcb, 0x16, 0x64, 0x38,
+		0xdc, 0xb9, 0xb9, 0x3e, 0xe5, 0xa7, 0x62, 0x92,
+		0x86, 0xa4, 0x91, 0xf8, 0x38, 0xf8, 0x02, 0xfb,
+	     },
+	    8, { 'k', 'e', 'r', 'b', 'e', 'r', 'o', 's' },
+	},
+	{
+	    {
+		0xb5, 0x5e, 0x98, 0x34, 0x67, 0xe5, 0x51, 0xb3,
+		0xe5, 0xd0, 0xe5, 0xb6, 0xc8, 0x0d, 0x45, 0x76,
+		0x94, 0x23, 0xa8, 0x73, 0xdc, 0x62, 0xb3, 0x0e,
+	    },
+	    7, { 'c', 'o', 'm', 'b', 'i', 'n', 'e', },
+	},
+	{
+	    {
+		0xc1, 0x08, 0x16, 0x49, 0xad, 0xa7, 0x43, 0x62,
+		0xe6, 0xa1, 0x45, 0x9d, 0x01, 0xdf, 0xd3, 0x0d,
+		0x67, 0xc2, 0x23, 0x4c, 0x94, 0x07, 0x04, 0xda,
+	    },
+	    5, { 0x00, 0x00, 0x00, 0x01, 0x55 },
+	},
+	{
+	    {
+		0x5d, 0x15, 0x4a, 0xf2, 0x38, 0xf4, 0x67, 0x13,
+		0x15, 0x57, 0x19, 0xd5, 0x5e, 0x2f, 0x1f, 0x79,
+		0x0d, 0xd6, 0x61, 0xf2, 0x79, 0xa7, 0x91, 0x7c,
+	    },
+	    5, { 0x00, 0x00, 0x00, 0x01, 0xaa },
+	},
+	{
+	    {
+		0x79, 0x85, 0x62, 0xe0, 0x49, 0x85, 0x2f, 0x57,
+		0xdc, 0x8c, 0x34, 0x3b, 0xa1, 0x7f, 0x2c, 0xa1,
+		0xd9, 0x73, 0x94, 0xef, 0xc8, 0xad, 0xc4, 0x43,
+	    },
+	    5, { 0x00, 0x00, 0x00, 0x01, 0x55 },
+	},
+	{
+	    {
+		0x26, 0xdc, 0xe3, 0x34, 0xb5, 0x45, 0x29, 0x2f,
+		0x2f, 0xea, 0xb9, 0xa8, 0x70, 0x1a, 0x89, 0xa4,
+		0xb9, 0x9e, 0xb9, 0x94, 0x2c, 0xec, 0xd0, 0x16,
+	    },
+	    5, { 0x00, 0x00, 0x00, 0x01, 0xaa },
+	},
+    };
+    int i;
+
+    for (i = 0; i < ASIZE(derive_tests); i++) {
+#define D (derive_tests[i])
+	krb5_keyblock key;
+	krb5_data usage;
+
+	unsigned char drData[KEYBYTES];
+	krb5_data dr;
+	unsigned char dkData[KEYLENGTH];
+	krb5_keyblock dk;
+
+	key.length = KEYLENGTH, key.contents = D.keydata;
+	usage.length = D.usage_len, usage.data = D.usage;
+	dr.length = KEYBYTES, dr.data = drData;
+	dk.length = KEYLENGTH, dk.contents = dkData;
+
+	printf ("key:\t"); printkey (&key); printf ("\n");
+	printf ("usage:\t"); printdata (&usage); printf ("\n");
+	DR (&dr, &key, &usage);
+	printf ("DR:\t"); printdata (&dr); printf ("\n");
+	DK (&dk, &key, &usage);
+	printf ("DK:\t"); printkey (&dk); printf ("\n\n");
+    }
+}
+
+
+static void printd (const char *descr, krb5_data *d) {
+    int i, j;
+    const int r = 16;
+
+    printf("%s:", descr);
+
+    for (i = 0; i < d->length; i += r) {
+	printf("\n  %04x: ", i);
+	for (j = i; j < i + r && j < d->length; j++)
+	    printf(" %02x", 0xff & d->data[j]);
+	for (; j < i + r; j++)
+	    printf("   ");
+	printf("   ");
+	for (j = i; j < i + r && j < d->length; j++) {
+	    int c = 0xff & d->data[j];
+	    printf("%c", isprint(c) ? c : '.');
+	}
+    }
+    printf("\n");
+}
+static void printk(const char *descr, krb5_keyblock *k) {
+    krb5_data d;
+    d.data = k->contents;
+    d.length = k->length;
+    printd(descr, &d);
+}
+
+
+static void
+test_pbkdf2()
+{
+    static struct {
+	int count;
+	char *pass;
+	char *salt;
+    } test[] = {
+	{ 1, "password", "ATHENA.MIT.EDUraeburn" },
+	{ 2, "password", "ATHENA.MIT.EDUraeburn" },
+	{ 1200, "password", "ATHENA.MIT.EDUraeburn" },
+	{ 5, "password", "\x12\x34\x56\x78\x78\x56\x34\x12" },
+	{ 1200,
+	  "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+	  "pass phrase equals block size" },
+	{ 1200,
+	  "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+	  "pass phrase exceeds block size" },
+	{ 50, "\xf0\x9d\x84\x9e", "EXAMPLE.COMpianist" },
+    };
+    unsigned char x[100];
+    unsigned char x2[100];
+    int j;
+    krb5_error_code err;
+    krb5_data d;
+    krb5_keyblock k, dk;
+    krb5_data usage, pass, salt;
+
+    d.data = x;
+    dk.contents = x2;
+
+    usage.data = "kerberos";
+    usage.length = 8;
+
+    for (j = 0; j < sizeof(test)/sizeof(test[0]); j++) {
+	printf("pkbdf2(count=%d, pass=\"%s\", salt=",
+	       test[j].count, test[j].pass);
+	if (isprint(test[j].salt[0]))
+	    printf("\"%s\")\n", test[j].salt);
+	else {
+	    char *s = test[j].salt;
+	    printf("0x");
+	    while (*s)
+		printf("%02X", 0xff & *s++);
+	    printf(")\n");
+	}
+
+	d.length = 16;
+	pass.data = test[j].pass;
+	pass.length = strlen(pass.data);
+	salt.data = test[j].salt;
+	salt.length = strlen(salt.data);
+	err = krb5int_pbkdf2_hmac_sha1 (&d, test[j].count, &pass, &salt);
+	printd("128-bit PBKDF2 output", &d);
+	enc = &krb5int_enc_aes128;
+	k.contents = d.data;
+	k.length = d.length;
+	dk.length = d.length;
+	DK (&dk, &k, &usage);
+	printk("128-bit AES key",&dk);
+
+	d.length = 32;
+	err = krb5int_pbkdf2_hmac_sha1 (&d, test[j].count, &pass, &salt);
+	printd("256-bit PBKDF2 output", &d);
+	enc = &krb5int_enc_aes256;
+	k.contents = d.data;
+	k.length = d.length;
+	dk.length = d.length;
+	DK (&dk, &k, &usage);
+	printk("256-bit AES key", &dk);
+
+	printf("\n");
+    }
+}
+
+int main (int argc, char **argv)
+{
+    whoami = argv[0];
+    test_nfold ();
+#if 0
+    test_mit_des_s2k ();
+    test_des3_s2k ();
+    test_dr_dk ();
+#endif
+    test_pbkdf2();
+    return 0;
+}
diff --git a/mechglue/src/lib/crypto/verify_checksum.c b/mechglue/src/lib/crypto/verify_checksum.c
new file mode 100644
index 000000000..30c9c07c0
--- /dev/null
+++ b/mechglue/src/lib/crypto/verify_checksum.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_verify_checksum(krb5_context context, const krb5_keyblock *key,
+		       krb5_keyusage usage, const krb5_data *data,
+		       const krb5_checksum *cksum, krb5_boolean *valid)
+{
+    int i;
+    size_t hashsize;
+    krb5_error_code ret;
+    krb5_data indata;
+    krb5_checksum computed;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+	if (krb5_cksumtypes_list[i].ctype == cksum->checksum_type)
+	    break;
+    }
+
+    if (i == krb5_cksumtypes_length)
+	return(KRB5_BAD_ENCTYPE);
+
+    /* if there's actually a verify function, call it */
+
+    indata.length = cksum->length;
+    indata.data = (char *) cksum->contents;
+
+    if (krb5_cksumtypes_list[i].keyhash &&
+	krb5_cksumtypes_list[i].keyhash->verify)
+	return((*(krb5_cksumtypes_list[i].keyhash->verify))(key, usage, 0, data,
+							    &indata, valid));
+
+    /* otherwise, make the checksum again, and compare */
+
+    if ((ret = krb5_c_checksum_length(context, cksum->checksum_type, &hashsize)))
+	return(ret);
+
+    if (cksum->length != hashsize)
+	return(KRB5_BAD_MSIZE);
+
+    computed.length = hashsize;
+
+    if ((ret = krb5_c_make_checksum(context, cksum->checksum_type, key, usage,
+				   data, &computed))) {
+	free(computed.contents);
+	return(ret);
+    }
+
+    *valid = (memcmp(computed.contents, cksum->contents, hashsize) == 0);
+
+    free(computed.contents);
+
+    return(0);
+}
diff --git a/mechglue/src/lib/crypto/yarrow/ASSUMPTIONS b/mechglue/src/lib/crypto/yarrow/ASSUMPTIONS
new file mode 100644
index 000000000..3e3c99c49
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/ASSUMPTIONS
@@ -0,0 +1,101 @@
+Assumptions
+===========
+
+The Yarrow design, described in "Yarrow-160: Notes on the Design and
+Analysis of the Yarrow Cryptographic Pseudonumber Generator" by John
+Kelsey, Bruce Schneier and Niels Ferguson of Counterpane Systems
+(available from http://www.counterpane.com/yarrow.html), left out some
+implementation details and has some ambiguities in the protocol.  ZKS
+has to made some assumptions and taken some decisions in its
+implementation of Yarrow. In the text, `we' represents ZKS.
+
+Here is the list of those assumptions: 
+
+1) To simplify the code and speed up running time, we limit the number
+of different sources to 20. This should be enough for most
+applications. This can be changed by redefining YARROW_MAX_SOURCE in
+yarrow.h.
+
+2) The Yarrow paper (in section 5.3) state that Pt is either
+implementation dependent or dynamically adjusted. We chose to fix the
+slow pool's Pt to 100 and the fast pool's Pt to 10. This can be
+changed by redefining YARROW_FAST_PT and YARROW_SLOW_PT in yarrow.c.
+
+3) Initialization when there is no saved state is not discussed in the
+Yarrow paper.  We have defined that CPRNG is becomes seeded after a
+slow reseed.  During initialization, a slow reseed is triggered by
+YARROW_K_OF_N_INIT_THRESH sources reaching the slow threshold
+YARROW_SLOW_INIT_THRESH.  During initialization, fast reseeds are
+triggered when a source reaches the fast threshold
+YARROW_FAST_INIT_THRESH.  After reseed the behavior of the pools is
+controlled by YARROW_K_OF_N_THRESH, YARROW_SLOW_THRESH and
+YARROW_FAST_THRESH.  
+
+Our default values for YARROW_K_OF_N_INIT_THRESH,
+YARROW_SLOW_INIT_THRESH and YARROW_FAST_INIT_THRESH are the same as
+YARROW_K_OF_N_THRESH, YARROW_SLOW_THRESH and YARROW_FAST_THRESH
+respectively.  Note this means that a Yarrow_Poll call by itself can
+never put us in an initialized state, as it only works on one pool,
+and the default YARROW_K_OF_N_INIT_THRESH value is 2.
+
+4) We define a function Yarrow_Poll which can gather entropy.  The
+user must allocate a source_id, and call Yarrow_Poll manually.
+Yarrow_Poll just adds samples from the machines state to the source
+given as an argument.
+
+5) Prior to initialization, Yarrow_Output will fail.
+
+6) The actions to take on state load are not described in the yarrow
+paper, all it says is that 2k bytes should be written (and by
+implication read back in somehow).  We read in the 2k bytes, hash
+them into the fast pool, and then do a forced fast reseed, and an
+immediate state save.
+
+7) In step 2 of the reseed process, we must hash the value i. The
+representation of this integer will affect the hash value. In our
+code, i is a 64-bit unsigned value. We update the hash context using
+the 64 bit big endian representation of i.
+
+8) Yarrow outputs random bits in blocks. If the calling function
+requests less bits than available, then the unused bits are kept
+in memory until the next call. In case of a reseed, we chose to 
+discard those leftover bits.
+
+9) The samples from one source must alternate between the two pools.
+As a default, we initialize the first pool to send the sample too to
+be the fast pool. This initialization is done only when a source is
+added, not when we reseed from one.
+
+10) The Yarrow paper states that the maximum number of outputs between
+reseeding is limited to min(2^n,2^(k/3)*Pg), but does not explain
+what is to happen when this limit is reached. It could be the case
+that we reach the limit but there is not enough entropy in the pools 
+to reseed. In our code, the Yarrow_Output_Block will do a forced
+fast reseed. 
+
+11) In the Yarrow paper, the limit on the number of outputs between
+reseeding is expressed in number of outputs:
+
+#oututs <= min(2^n, 2^(k/3).Pg)
+
+but we redefine it in terms of gates by dividing the numbers by Pg,
+the number of outputs per gate, and counting the number of gates
+instead.  This makes an overflow a little less likely.
+
+We don't use a bignum library, so in event of overflow, the limit in
+number of gates before reseed (y->gates_limit) is reduced down to
+2^64-1 (or 2^32-1 if 64 bit ints aren't available on the platform).
+
+12) The Yarrow paper describes that the cipher block C should be 
+incremented as part of the output function.  We treat the bytes
+of C as a big endian number to do the increment.
+
+13) Triple-DES key size.  The yarrow paper uses the letter k to
+represent the keysize in bits.  Due to the parity bits, the size of k
+is 192 bits.  However the effective key size is actually 168 bits, as
+the value of k is used in security limits, k must be 168 bits.  The
+paper uses k (eg set K to the next k output bits), so we have to do
+the parity padding function, to copy bits 0-6 to 0-7, 7-13 to 8-15
+etc.  The macro DES_Init performs the function of doing a DES key
+schedule from a packed key (no parity bits), internally doing the
+parity padding.  Other ciphers are simpler as there is no parity.
diff --git a/mechglue/src/lib/crypto/yarrow/ChangeLog b/mechglue/src/lib/crypto/yarrow/ChangeLog
new file mode 100644
index 000000000..30eae99ed
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/ChangeLog
@@ -0,0 +1,150 @@
+2005-05-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* ytypes.h: Include autoconf.h.  Include sys/types.h only if it
+	exists.
+
+2005-04-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* yarrow.c: Delete old macintosh support.
+	(yarrow_input_maybe_locking): Do the optional locking, and verify
+	that the mutex is locked, before doing anything else.
+	(yarrow_reseed_locked): Verify that the global mutex is locked
+	before doing anything else.
+
+2005-01-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* yarrow.c (yarrow_reseed_locked): Renamed from
+	krb5int_yarrow_reseed and made static.
+	(Yarrow_detect_fork, yarrow_input_maybe_locking,
+	krb5int_yarrow_output_Block): Call it.
+	(krb5int_yarrow_reseed): New function, grabs lock and calls the
+	old version.
+	(krb5int_yarrow_final): Hold the lock until after clearing the
+	Yarrow context data.
+
+2005-01-13  Ezra Peisach  <epeisach@mit.edu>
+
+	* yarrow.c: Declare yarrow_gate_locked static before first use.
+
+2004-11-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* yarrow.c (yarrow_input_maybe_locking): Renamed from
+	yarrow_input_maybe_locking, made static.  New argument indicates
+	whether or not to do locking.
+	(krb5int_yarrow_input): New wrapper function.
+	(yarrow_input_locked): New wrapper function.
+	(Yarrow_detect_fork): Call yarrow_input_locked.
+
+2004-11-15  Sam Hartman  <hartmans@mit.edu>
+
+	* ycipher.h: Use AES256 not 3des
+
+2004-11-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* yarrow.c (krb5int_yarrow_input, krb5int_yarrow_final): Don't
+	check for forking here.
+	(yarrow_output_locked): Split out from krb5int_yarrow_output,
+	without locking.
+	(krb5int_yarrow_output): Do locking and call yarrow_output_locked.
+	(yarrow_gate_locked): New function; uses yarrow_output_locked.
+	(krb5int_yarrow_output_Block): Use yarrow_gate_locked.
+
+2004-10-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* ylock.h: Include k5-thread.h.
+	(krb5int_yarrow_lock): Declare.
+	(LOCK, UNLOCK): Define as macros using the k5_mutex_ macros.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* yarrow.c (yarrow_str_error): Now const.
+
+2004-05-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* yarrow.c (krb5int_yarrow_final): Call
+	krb5int_yarrow_cipher_final before zeroing out reference to
+	memory.
+
+	* ycipher.[ch] (krb5int_yarrow_cipher_final): Free CIPHER_CTX memory
+	allocated by krb5int_yarrpw_cipher_init().
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* ycipher.c (krb5int_yarrow_cipher_init): Use keybytes and
+	keylength fields instead of calling a function.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* yarrow.c: Use the canonical _WIN32 instead of WIN32 to test for
+	Win32.  Include port-sockets.h on Win32 (now that using
+	WIN32_LEAN_AND_MEAN).
+
+2002-01-14  Sam Hartman  <hartmans@mit.edu>
+
+	* yarrow.c (krb5int_yarrow_reseed): The MS word of  the integer
+	counter going into v_i will always be zero; don't try
+	right-shifting by 32. 
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* yarrow.c (krb5int_yarrow_stretch): Delare local variable unsigned. 
+	(krb5int_yarrow_init): Zero cipher context on init.
+
+	* yhash.h (HASH_Final): Use a variable other than out (shadow in
+	yarrow.c)
+
+2001-11-21  Sam Hartman  <hartmans@mit.edu>
+
+	* yarrow.c (Yarrow_detect_fork): Reseed the number generator including the fork rather than throwing away state.
+
+2001-11-19  Sam Hartman  <hartmans@mit.edu>
+
+	* yhash.h: Work around sha1 implementation using host byte order
+
+2001-11-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Fix typo OUTP -> OUTPRE.
+
+2001-11-14  Sam Hartman  <hartmans@mit.edu>
+
+	* ycipher.c (krb5int_yarrow_cipher_init):  Use free not free_keyblock_contents
+
+2001-11-09  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in: New file
+
+	* yhash.h :  Use krb5 shaa1
+
+	* yarrow.c (Yarrow_Reseed):  For all calls to cipher_init, use TRY
+	block and  use function rather than macros 
+	(Yarrow_Reseed):  call encrypt block function not macro
+
+	* ycipher.h: Make the the interface use functions not macros; convert for krb5 ciphers
+
+2001-11-08  Sam Hartman  <hartmans@mit.edu>
+
+	* ylock.h (lock UNLOCK):  Turn into no-ops
+
+	* yarrow.h: Don't use #error
+	(YARROW_DLL): Don't actually ever export or import from win32 dlls as Yarrow is not a public part of krb5 API
+	(yarrow_poll): Drop from the API
+	Remove MAc-specific memset and  memcpy
+
+	* ytypes.h yarrow.c: Align with krb5 int types
+
diff --git a/mechglue/src/lib/crypto/yarrow/LICENSE b/mechglue/src/lib/crypto/yarrow/LICENSE
new file mode 100644
index 000000000..c85475d7e
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/LICENSE
@@ -0,0 +1,21 @@
+Copyright 2000 by Zero-Knowledge Systems, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Zero-Knowledge Systems,
+Inc. not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.  Zero-Knowledge Systems, Inc. makes no representations
+about the suitability of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+
+ZERO-KNOWLEDGE SYSTEMS, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL ZERO-KNOWLEDGE SYSTEMS, INC. BE LIABLE FOR
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
diff --git a/mechglue/src/lib/crypto/yarrow/Makefile.in b/mechglue/src/lib/crypto/yarrow/Makefile.in
new file mode 100644
index 000000000..ad9cf762f
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/Makefile.in
@@ -0,0 +1,59 @@
+thisconfigdir=./..
+myfulldir=lib/crypto/yarrow
+mydir=yarrow
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../sha1 -I$(srcdir)/../enc_provider
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=yarrow
+##DOS##OBJFILE=..\$(OUTPRE)yarrow.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+
+STLIBOBJS=\
+	yarrow.o \
+	ycipher.o
+OBJS=\
+	$(OUTPRE)yarrow.$(OBJEXT) \
+	$(OUTPRE)ycipher.$(OBJEXT)
+
+SRCS=\
+	$(srcdir)/yarrow.c \
+	$(srcdir)/ycipher.c 
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+includes:: depend
+
+depend:: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+yarrow.so yarrow.po $(OUTPRE)yarrow.$(OBJEXT): yarrow.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  yarrow.h ytypes.h yhash.h $(srcdir)/../sha1/shs.h ycipher.h \
+  ylock.h ystate.h yexcep.h
+ycipher.so ycipher.po $(OUTPRE)ycipher.$(OBJEXT): ycipher.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  yarrow.h ytypes.h yhash.h $(srcdir)/../sha1/shs.h ycipher.h \
+  $(srcdir)/../enc_provider/enc_provider.h
diff --git a/mechglue/src/lib/crypto/yarrow/README b/mechglue/src/lib/crypto/yarrow/README
new file mode 100644
index 000000000..3dd4b801a
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/README
@@ -0,0 +1,94 @@
+Yarrow - Secure Pseudo-Random Number Generator
+==============================================
+
+This is an implementation of the cryptographic pseudo-random number
+generator Yarrow.  You are encouraged to use, modify, and incorporate
+this code.  Please see the accompanying LICENSE file for more details.
+
+
+Yarrow can be used with OpenSSL 0.9.5a (http://www.openssl.org) and
+other cryptographic libraries.
+
+The Yarrow design is described in "Yarrow-160: Notes on the Design and
+Analysis of the Yarrow Cryptographic Pseudorandom Number Generator" by
+John Kelsey, Bruce Schneier and Niels Ferguson of Counterpane Systems,
+available from http://www.counterpane.com/yarrow.html
+
+The Yarrow function calls are described in the yarrow(3) manpage.
+
+Installation
+============
+
+By default, Yarrow is built with OpenSSL. If the OpenSSL headers are
+not installed in the standard directory /usr/local/ssl/include,
+set the path in the Makefile.
+
+If it is possible that an application using Yarrow will fork(), Yarrow
+must be compiled with -DYARROW_DETECT_FORK (then the child process
+will have to seed Yarrow again), or the Yarrow_CTX must be allocated
+in shared memory.
+
+If compiled with -DYARROW_SAVE_STATE, Yarrow will use a seed file
+specified in the Yarrow_Init call.
+
+When the settings in the Makefile are correct, run "make".
+
+
+Yarrow with OpenSSL:
+-------------------
+
+The macros YARROW_CIPHER_3DES (default), YARROW_CIPHER_BLOWFISH and
+YARROW_CIPHER_IDEA for ciphers and YARROW_HASH_SHA1 (default) and
+YARROW_HASH_MD5 for hash functions are available to select algorithms
+from OpenSSL.
+
+CRYPTO_set_locking_callback() is required in multithreaded applications.
+
+
+Yarrow with other cryptographic libraries:
+-----------------------------------------
+
+The Yarrow implementation uses a symmetric cipher, a cryptographic
+hash function and a mutex. By default, Yarrow calls OpenSSL. For use
+with other cryptographic libraries, the following types and macros
+should be defined:
+
+Symmetric cipher - ycipher.h:
+
+  typedef struct { ... } CIPHER_CTX;
+
+  #define CIPHER_BLOCK_SIZE ...
+  #define CIPHER_KEY_SIZE ...
+
+  void CIPHER_Init(CIPHER_CTX *ctx, void *key);
+  void CIPHER_Encrypt_Block(CIPHER_CTX *ctx, void *in, void *out);
+
+Hash function - yhash.h:
+
+  typedef struct { ... } HASH_CTX;
+
+  #define HASH_DIGEST_SIZE ...
+  #define HASH_STATE_SIZE ...
+
+  void HASH_Init(HASH_CTX *ctx);
+  void HASH_Update(HASH_CTX *ctx, const void *data, unsigned long size);
+  void HASH_Final(HASH_CTX *ctx, unsigned char *md);
+
+Mutex - ylock.h:
+
+  int LOCK(void);
+  int UNLOCK(void);
+
+Learn More:
+----------
+
+It is Zero-Knowledge's hope that third party developers of yarrow will
+collaborate to derive test vectors for yarrow.  In an effort to further
+this discussion, we have created a mailing list for developers and
+interested parties.  To subscribe, send an email to
+"yarrow-request@zeroknowledge.com" with "subscribe" in the body of the
+message.
+
+For more information, or if you have questions or comments regarding open
+source at Zero-Knowledge Systems, please visit
+http://opensource.zeroknowledge.com
diff --git a/mechglue/src/lib/crypto/yarrow/TODO b/mechglue/src/lib/crypto/yarrow/TODO
new file mode 100644
index 000000000..bd133ecfd
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/TODO
@@ -0,0 +1,9 @@
+open issues:
+
+* when should the initial seed be considered complete?
+* poll system ressources for randomness on startup?
+* how frequently should the PRNG state be saved?
+* how to react to fork()?
+* what should the seed file contain, how should it be processed?
+* test fork() hack
+* test openSSL locks in multi-threaded environment
diff --git a/mechglue/src/lib/crypto/yarrow/yarrow.c b/mechglue/src/lib/crypto/yarrow/yarrow.c
new file mode 100644
index 000000000..b52057daa
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/yarrow.c
@@ -0,0 +1,955 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+
+/*
+ * Yarrow - Cryptographic Pseudo-Random Number Generator
+ * Copyright (c) 2000 Zero-Knowledge Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Zero-Knowledge Systems,
+ * Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Zero-Knowledge Systems, Inc. makes no representations
+ * about the suitability of this software for any purpose.  It is
+ * provided "as is" without express or implied warranty.
+ * 
+ * See the accompanying LICENSE file for more information.
+ */
+
+#include "k5-int.h"
+
+#include <string.h>
+#include <limits.h>
+#ifdef _WIN32
+#include "port-sockets.h"
+#else
+#   include <unistd.h>
+#   include <netinet/in.h>
+#endif
+#if !defined(YARROW_NO_MATHLIB)
+#include <math.h>
+#endif
+
+#define YARROW_IMPL
+#include "yarrow.h"
+#include "yhash.h"
+#include "ycipher.h"
+#include "ylock.h"
+#include "ystate.h"
+#include "yexcep.h"
+
+#if defined( YARROW_DEBUG ) || defined( YARROW_TRACE )
+#   include <stdio.h>
+#endif
+
+#if defined( YARROW_TRACE )
+extern int yarrow_verbose;
+#define TRACE( x ) do { if (yarrow_verbose) { x } } while (0)
+#else
+#define TRACE( x ) 
+#endif
+
+#if defined(macintosh)
+#   define make_big_endian32(x) (x)
+#else
+#   define make_big_endian32(x) htonl(x)
+#endif
+
+#if defined( YARROW_DEBUG )
+static void hex_print(FILE* f, const char* var, void* data, size_t size);
+#endif
+
+static void block_increment( void* block, const int sz );
+#if defined( YARROW_SAVE_STATE )
+static int Yarrow_Load_State( Yarrow_CTX *y );
+static int Yarrow_Save_State( Yarrow_CTX *y );
+#endif
+
+static int yarrow_gate_locked(Yarrow_CTX* y);
+
+static const byte zero_block[CIPHER_BLOCK_SIZE] = { 0, };
+
+static const char* const yarrow_str_error[] = {
+    "ok",
+    "failed",
+    "failed: uninitialized",
+    "failed: already initialized",
+    "failed: no driver",
+    "failed: can't open driver",
+    "failed: invalid source id",
+    "failed: no more source ids available",
+    "failed: invalid argument",
+    "failed: insufficient privileges",
+    "failed: out of memory",
+    "failed: resource exhausted",
+    "failed: not enough entropy to generate output",
+    "failed: locking error",
+    "failed: no state to load",
+    "failed: state load or save failed",
+    "failed: not implemented"
+};
+
+/* calculate limits after initialization */
+
+static void krb5int_yarrow_init_Limits(Yarrow_CTX* y)
+{
+    double tmp1, tmp2, limit;
+    /* max number of gates between reseeds -> exceed this, do forced reseed */
+
+    /* #oututs <= min(2^n, 2^(k/3).Pg) */
+
+    /* => #gates <= min(2^n/Pg, 2^(k/3)) */
+
+    tmp1 = POW_CIPHER_BLOCK_SIZE / y->Pg;
+    tmp2 = POW_CIPHER_KEY_SIZE;
+    limit = min(tmp1, tmp2);
+    if (limit < COUNTER_MAX)
+    {
+	y->gates_limit = limit;
+    }
+    else
+    {
+	y->gates_limit = COUNTER_MAX;
+    }
+}
+
+static int yarrow_reseed_locked( Yarrow_CTX* y, int pool );
+
+/* if the program was forked, the child must not operate on the same
+   PRNG state */
+#ifdef YARROW_DETECT_FORK
+
+static int
+yarrow_input_locked( Yarrow_CTX* y, unsigned source_id,
+		     const void *sample,
+		     size_t size, size_t entropy_bits );
+
+static int Yarrow_detect_fork(Yarrow_CTX *y)
+{
+    pid_t newpid;
+    EXCEP_DECL;
+
+    /* this does not work for multi-threaded apps if threads have different
+     * pids */
+       newpid = getpid();
+    if ( y->pid != newpid )
+    {
+	/* we input the pid twice, so it will get into the fast pool at least once
+	 * Then we reseed.  This doesn't really increase entropy, but does make the
+	 * streams distinct assuming we already have good entropy*/
+	y->pid = newpid;
+	TRY (yarrow_input_locked (y, 0, &newpid,
+				  sizeof (newpid), 0));
+	TRY (yarrow_input_locked (y, 0, &newpid,
+				  sizeof (newpid), 0));
+	TRY (yarrow_reseed_locked (y, YARROW_FAST_POOL));
+    }
+
+ CATCH:
+    EXCEP_RET;
+}
+
+#else
+
+#define Yarrow_detect_fork(x) (YARROW_OK)
+
+#endif
+
+static void Yarrow_Make_Seeded( Yarrow_CTX* y )
+{
+    TRACE( printf( "SEEDED," ); );
+    y->seeded = 1;
+
+    /* now we are seeded switch to _THRESH values */
+
+    y->slow_thresh = YARROW_SLOW_THRESH;
+    y->fast_thresh = YARROW_FAST_THRESH;
+    y->slow_k_of_n_thresh = YARROW_K_OF_N_THRESH;
+}
+
+YARROW_DLL
+int krb5int_yarrow_init(Yarrow_CTX* y, const char *filename)
+{
+    EXCEP_DECL;
+    int locked = 0;
+
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+    TRY( LOCK() );
+    locked = 1;
+
+    y->seeded = 0;
+    y->saved = 0;
+
+#if defined( YARROW_DETECT_FORK )
+    y->pid = getpid();
+#endif
+
+    y->entropyfile = filename;
+    y->num_sources = 0;
+    mem_zero(y->C, sizeof(y->C));
+    HASH_Init(&y->pool[YARROW_FAST_POOL]);
+    HASH_Init(&y->pool[YARROW_SLOW_POOL]);
+
+    mem_zero(y->K, sizeof(y->K));
+
+    mem_zero(&y->cipher, sizeof(y->cipher));
+
+    TRY (krb5int_yarrow_cipher_init(&y->cipher, y->K));
+    y->out_left = 0;
+    y->out_count = 0;
+    y->gate_count = 0;
+    y->Pg = YARROW_OUTPUTS_PER_GATE;
+    y->Pt[YARROW_FAST_POOL] = YARROW_FAST_PT;
+    y->Pt[YARROW_SLOW_POOL] = YARROW_SLOW_PT;
+    y->slow_k_of_n = 0;
+
+    /* start with INIT_THRESH values, after seeded, switch to THRESH values */
+
+    y->slow_thresh = YARROW_SLOW_INIT_THRESH;
+    y->fast_thresh = YARROW_FAST_INIT_THRESH;
+    y->slow_k_of_n_thresh = YARROW_K_OF_N_INIT_THRESH;
+
+    krb5int_yarrow_init_Limits(y);
+
+#if defined( YARROW_SAVE_STATE )
+    if ( y->entropyfile != NULL )
+    {
+	int ret = Yarrow_Load_State( y );
+	if ( ret != YARROW_OK && ret != YARROW_NO_STATE )
+	{
+	    THROW( ret );
+	}
+
+	/*  if load suceeded then write new state back immediately
+	 */
+
+	/*  Also check that it's not already saved, because the reseed in
+	 *  Yarrow_Load_State may trigger a save
+	 */
+
+	if ( ret == YARROW_OK && !y->saved )
+	{
+	    TRY( Yarrow_Save_State( y ) );
+	}
+    }
+#endif
+
+    if ( !y->seeded )
+    {
+	THROW( YARROW_NOT_SEEDED );
+    }
+
+ CATCH:
+    if ( locked ) { TRY( UNLOCK() ); }
+    EXCEP_RET;
+}
+
+static
+int yarrow_input_maybe_locking( Yarrow_CTX* y, unsigned source_id, 
+				const void* sample, 
+				size_t size, size_t entropy_bits,
+				int do_lock )
+{
+    EXCEP_DECL;
+    int ret;
+    int locked = 0;
+    Source* source;
+    size_t new_entropy;
+    size_t estimate;
+  
+    if (do_lock) {
+	    TRY( LOCK() );
+	    locked = 1;
+    }
+    k5_assert_locked(&krb5int_yarrow_lock);
+
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+
+    if (source_id >= y->num_sources) { THROW( YARROW_BAD_SOURCE ); }
+  
+    source = &y->source[source_id];
+
+    if(source->pool != YARROW_FAST_POOL && source->pool != YARROW_SLOW_POOL)
+    {
+	THROW( YARROW_BAD_SOURCE );
+    }
+
+    /* hash in the sample */
+
+    HASH_Update(&y->pool[source->pool], (const void*)sample, size);
+  
+    /* only update entropy estimate if pool is not full */
+
+    if ( (source->pool == YARROW_FAST_POOL && 
+	  source->entropy[source->pool] < y->fast_thresh) ||
+	 (source->pool == YARROW_SLOW_POOL &&
+	  source->entropy[source->pool] < y->slow_thresh) )
+    {
+	new_entropy = min(entropy_bits, size * 8 * YARROW_ENTROPY_MULTIPLIER);
+	if (source->estimator)
+	{
+	    estimate = source->estimator(sample, size);
+	    new_entropy = min(new_entropy, estimate);
+	}
+	source->entropy[source->pool] += new_entropy;
+	if ( source->entropy[source->pool] > YARROW_POOL_SIZE )
+	{
+	    source->entropy[source->pool] = YARROW_POOL_SIZE;
+	}
+
+	if (source->pool == YARROW_FAST_POOL)
+	{
+	    if (source->entropy[YARROW_FAST_POOL] >= y->fast_thresh)
+	    {
+		ret = yarrow_reseed_locked(y, YARROW_FAST_POOL);
+		if ( ret != YARROW_OK && ret != YARROW_NOT_SEEDED )
+		{
+		    THROW( ret );
+		}
+	    }
+	}
+	else
+	{
+	    if (!source->reached_slow_thresh && 
+		source->entropy[YARROW_SLOW_POOL] >= y->slow_thresh)
+	    {
+		source->reached_slow_thresh = 1;
+		y->slow_k_of_n++;
+		if (y->slow_k_of_n >= y->slow_k_of_n_thresh)
+		{
+		    y->slow_k_of_n = 0;
+		    ret = yarrow_reseed_locked(y, YARROW_SLOW_POOL);
+		    if ( ret != YARROW_OK && ret != YARROW_NOT_SEEDED )
+		    {
+			THROW( ret );
+		    }
+		}
+	    }
+	}
+    }
+  
+    /* put samples in alternate pools */
+
+    source->pool = (source->pool + 1) % 2;
+  
+ CATCH:
+    if ( locked ) { TRY( UNLOCK() ); }
+    EXCEP_RET;
+}
+
+YARROW_DLL
+int krb5int_yarrow_input( Yarrow_CTX* y, unsigned source_id, 
+		  const void* sample, 
+		  size_t size, size_t entropy_bits )
+{
+    return yarrow_input_maybe_locking(y, source_id, sample, size,
+				      entropy_bits, 1);
+}
+
+static int
+yarrow_input_locked( Yarrow_CTX* y, unsigned source_id,
+		     const void *sample,
+		     size_t size, size_t entropy_bits )
+{
+    return yarrow_input_maybe_locking(y, source_id, sample, size,
+				      entropy_bits, 0);
+}
+
+YARROW_DLL
+int krb5int_yarrow_new_source(Yarrow_CTX* y, unsigned* source_id)
+{
+    EXCEP_DECL;
+    int locked = 0;
+    Source* source;
+
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+
+    TRY( LOCK() );
+    locked = 1;
+
+    if (y->num_sources + 1 > YARROW_MAX_SOURCES)
+    {
+	THROW( YARROW_TOO_MANY_SOURCES );
+    }
+
+    *source_id = y->num_sources;
+
+    source = &y->source[*source_id];
+
+    source->pool = YARROW_FAST_POOL;
+    source->entropy[YARROW_FAST_POOL] = 0;
+    source->entropy[YARROW_SLOW_POOL] = 0;
+    source->reached_slow_thresh = 0;
+    source->estimator = 0;
+
+    y->num_sources++;
+CATCH:
+    if ( locked ) { TRY( UNLOCK() ); }
+    EXCEP_RET;
+}
+
+int krb5int_yarrow_register_source_estimator(Yarrow_CTX* y, unsigned source_id, 
+                                     estimator_fn* fptr)
+{
+    EXCEP_DECL;
+    Source* source;
+
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+    if (source_id >= y->num_sources) { THROW( YARROW_BAD_SOURCE ); }
+
+    source = &y->source[source_id];
+
+    source->estimator = fptr;
+  
+ CATCH:
+    EXCEP_RET;
+}
+
+static int krb5int_yarrow_output_Block( Yarrow_CTX* y, void* out )
+{
+    EXCEP_DECL;
+
+    if (!y || !out) { THROW( YARROW_BAD_ARG ); }
+
+    TRACE( printf( "OUT," ); );
+
+    /* perform a gate function after Pg outputs */
+
+    y->out_count++;
+    if (y->out_count >= y->Pg)
+    {
+	y->out_count = 0;
+	TRY( yarrow_gate_locked( y ) );
+
+	/* require new seed after reaching gates_limit */
+
+	y->gate_count++;
+	if ( y->gate_count >= y->gates_limit )
+	{
+	    y->gate_count = 0;
+	    
+	    /* not defined whether to do slow or fast reseed */ 
+	    
+	    TRACE( printf( "OUTPUT LIMIT REACHED," ); );
+
+	    TRY( yarrow_reseed_locked( y, YARROW_SLOW_POOL ) );
+	}
+    }
+  
+    /* C <- (C + 1) mod 2^n */
+
+    block_increment( y->C, CIPHER_BLOCK_SIZE );
+
+    /* R <- E_k(C) */
+
+    TRY ( krb5int_yarrow_cipher_encrypt_block ( &y->cipher, y->C, out ));
+
+#if defined(YARROW_DEBUG)
+    printf("===\n");
+    hex_print( stdout, "output: C", y->C, CIPHER_BLOCK_SIZE );
+    hex_print( stdout, "output: K", y->K, CIPHER_KEY_SIZE );
+    hex_print( stdout, "output: O", out, CIPHER_BLOCK_SIZE );
+#endif
+ CATCH:
+    EXCEP_RET;
+}
+
+YARROW_DLL
+int krb5int_yarrow_status( Yarrow_CTX* y, int *num_sources, unsigned *source_id,
+		   size_t *entropy_bits, size_t *entropy_max )
+{
+    EXCEP_DECL;
+    int num = y->slow_k_of_n_thresh;
+    int source = -1;
+    int emax = y->slow_thresh;
+    size_t entropy = 0;
+    unsigned i;
+
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+    TRY( Yarrow_detect_fork( y ) );
+
+    if (num_sources) { *num_sources = num; }
+    if (source_id) { *source_id = -1; }
+    if (entropy_bits) { *entropy_bits = 0; }
+    if (entropy_max) { *entropy_max = emax; }
+
+    if (y->seeded)
+    {
+	if (num_sources) { *num_sources = 0; }
+	if (entropy_bits) { *entropy_bits = emax; }
+	THROW( YARROW_OK );
+    }
+
+    for (i = 0; i < y->num_sources; i++)
+    {
+	if (y->source[i].entropy[YARROW_SLOW_POOL] >= y->slow_thresh)
+	{
+	    num--;
+	}
+	else if (y->source[i].entropy[YARROW_SLOW_POOL] > entropy)
+	{
+	    source = i;
+	    entropy = y->source[i].entropy[YARROW_SLOW_POOL];
+	}
+    }
+
+    if (num_sources) { *num_sources = num; }
+    if (source_id) { *source_id = source; }
+    if (entropy_bits) { *entropy_bits = entropy; }
+    THROW( YARROW_NOT_SEEDED );
+
+ CATCH:
+    EXCEP_RET;
+}
+
+static int yarrow_output_locked(Yarrow_CTX*, void*, size_t);
+
+YARROW_DLL
+int krb5int_yarrow_output( Yarrow_CTX* y, void* out, size_t size )
+{
+    EXCEP_DECL;
+    TRY( LOCK() );
+    TRY( yarrow_output_locked(y, out, size));
+CATCH:
+    UNLOCK();
+    EXCEP_RET;
+}
+
+static
+int yarrow_output_locked( Yarrow_CTX* y, void* out, size_t size )
+{
+    EXCEP_DECL;
+    size_t left;
+    char* outp;
+    size_t use;
+
+    if (!y || !out) { THROW( YARROW_BAD_ARG ); }
+    TRY( Yarrow_detect_fork( y ) );
+
+    if (!y->seeded) { THROW( YARROW_NOT_SEEDED ); }
+
+    left = size;
+    outp = out;
+
+    if (y->out_left > 0)
+    {
+	use = min(left, y->out_left);
+	mem_copy(outp, y->out + CIPHER_BLOCK_SIZE - y->out_left, use);
+	left -= use;
+	y->out_left -= use;
+	outp += use;
+    }
+
+    for ( ; 
+	  left >= CIPHER_BLOCK_SIZE;
+	  left -= CIPHER_BLOCK_SIZE, outp += CIPHER_BLOCK_SIZE)
+    {
+	TRY( krb5int_yarrow_output_Block(y, outp) );
+    }
+
+    if (left > 0)
+    {
+	TRY( krb5int_yarrow_output_Block(y, y->out) );
+	mem_copy(outp, y->out, left);
+	y->out_left = CIPHER_BLOCK_SIZE - left;
+    }
+
+ CATCH:
+    EXCEP_RET;
+}
+
+static int yarrow_gate_locked(Yarrow_CTX* y)
+{
+    EXCEP_DECL;
+    byte new_K[CIPHER_KEY_SIZE];
+
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+  
+    TRACE( printf( "GATE[" ); );
+
+    /* K <- Next k bits of PRNG output */
+
+    TRY( yarrow_output_locked(y, new_K, CIPHER_KEY_SIZE) );
+    mem_copy(y->K, new_K, CIPHER_KEY_SIZE);
+
+    /* need to resetup the key schedule as the key has changed */
+
+    TRY (krb5int_yarrow_cipher_init(&y->cipher, y->K));
+
+ CATCH:
+    TRACE( printf( "]," ); );
+    mem_zero(new_K, sizeof(new_K));
+    EXCEP_RET;
+}
+
+int krb5int_yarrow_gate(Yarrow_CTX* y)
+{
+    EXCEP_DECL;
+    byte new_K[CIPHER_KEY_SIZE];
+
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+  
+    TRACE( printf( "GATE[" ); );
+
+    /* K <- Next k bits of PRNG output */
+
+    TRY( krb5int_yarrow_output(y, new_K, CIPHER_KEY_SIZE) );
+    mem_copy(y->K, new_K, CIPHER_KEY_SIZE);
+
+    /* need to resetup the key schedule as the key has changed */
+
+    TRY (krb5int_yarrow_cipher_init(&y->cipher, y->K));
+
+ CATCH:
+    TRACE( printf( "]," ); );
+    mem_zero(new_K, sizeof(new_K));
+    EXCEP_RET;
+}
+
+#if defined( YARROW_SAVE_STATE )
+static int Yarrow_Load_State( Yarrow_CTX *y )
+{
+    EXCEP_DECL;
+    Yarrow_STATE state;
+    
+    if ( !y ) { THROW( YARROW_BAD_ARG ); }
+
+    if ( y->entropyfile )
+    {
+	TRY( STATE_Load(y->entropyfile, &state) );
+	TRACE( printf( "LOAD STATE," ); );
+
+#if defined( YARROW_DEBUG )
+	hex_print( stderr, "state.load", state.seed, sizeof(state.seed));
+#endif
+    
+	/* what to do here is not defined by the Yarrow paper */
+	/* this is a place holder until we get some clarification */
+    
+	HASH_Update( &y->pool[YARROW_FAST_POOL], 
+		     state.seed, sizeof(state.seed) );
+
+	Yarrow_Make_Seeded( y );
+
+	TRY( krb5int_yarrow_reseed(y, YARROW_FAST_POOL) );
+    }
+ CATCH:
+    mem_zero(state.seed, sizeof(state.seed));
+    EXCEP_RET;
+}
+
+static int Yarrow_Save_State( Yarrow_CTX *y )
+{
+    EXCEP_DECL;
+    Yarrow_STATE state;
+    
+    if ( !y ) { THROW( YARROW_BAD_ARG ); }
+
+    if ( y->entropyfile && y->seeded ) 
+    {
+	TRACE( printf( "SAVE STATE[" ); );
+	TRY( krb5int_yarrow_output( y, state.seed, sizeof(state.seed) ) );
+	TRY( STATE_Save(y->entropyfile, &state) );
+    }
+    y->saved = 1;
+# if defined(YARROW_DEBUG)
+    hex_print(stdout, "state.save", state.seed, sizeof(state.seed));
+# endif
+
+ CATCH:
+    TRACE( printf( "]," ); );
+    mem_zero(state.seed, sizeof(state.seed));
+    EXCEP_RET;
+}
+
+#endif
+
+static int yarrow_reseed_locked(Yarrow_CTX* y, int pool)
+{
+    EXCEP_DECL;
+    HASH_CTX* fast_pool;
+    HASH_CTX* slow_pool;
+    byte digest[HASH_DIGEST_SIZE];
+    HASH_CTX hash;
+    byte v_0[HASH_DIGEST_SIZE];
+    byte v_i[HASH_DIGEST_SIZE];
+    krb5_ui_4 big_endian_int32;
+    COUNTER i;
+
+    k5_assert_locked(&krb5int_yarrow_lock);
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+    fast_pool = &y->pool[YARROW_FAST_POOL];
+    slow_pool = &y->pool[YARROW_SLOW_POOL];
+    if( pool != YARROW_FAST_POOL && pool != YARROW_SLOW_POOL )
+    {
+	THROW( YARROW_BAD_ARG );
+    }
+  
+    TRACE( printf( "%s RESEED,", 
+		   pool == YARROW_SLOW_POOL ? "SLOW" : "FAST" ); );
+
+    if (pool == YARROW_SLOW_POOL)
+    {
+	/* SLOW RESEED */
+
+	/* feed hash of slow pool into the fast pool */
+
+
+	HASH_Final(slow_pool, digest);
+
+	/*  Each pool contains the running hash of all inputs fed into it
+	 *  since it was last used to carry out a reseed -- this implies
+	 *  that the pool must be reinitialized after a reseed
+	 */
+
+	HASH_Init(slow_pool);    /* reinitialize slow pool */
+	HASH_Update(fast_pool, digest, sizeof(digest));
+
+	if (y->seeded == 0)
+	{
+	    Yarrow_Make_Seeded( y );
+	}
+    }
+
+    /* step 1. v_0 <- hash of all inputs into fast pool */
+
+    HASH_Final(fast_pool, &v_0);
+    HASH_Init(fast_pool);    /* reinitialize fast pool */ 
+
+    /* v_i <- v_0 */
+
+    mem_copy( v_i, v_0, sizeof(v_0) );
+
+    /* step 2. v_i = h(v_{i-1}|v_0|i) for i = 1,..,Pt */
+
+    /* note: this code has to work for Pt = 0 also */
+
+    for ( i = 0; i < y->Pt[pool]; i++ )
+    {
+	HASH_Init(&hash);
+	HASH_Update(&hash, v_i, sizeof(v_i));
+	HASH_Update(&hash, v_0, sizeof(v_0));
+	big_endian_int32 = make_big_endian32(0); /* MS word */
+	HASH_Update(&hash, &big_endian_int32, sizeof(krb5_ui_4));
+	big_endian_int32 = make_big_endian32(i & 0xFFFFFFFF); /* LS word */
+	HASH_Update(&hash, &big_endian_int32, sizeof(krb5_ui_4));
+	HASH_Final(&hash, &v_i);
+    }
+
+    /* step3. K = h'(h(v_Pt|K)) */
+
+    /* t = h(v_Pt|K) */
+
+    HASH_Init(&hash);
+    HASH_Update(&hash, v_i, sizeof(v_i));
+    HASH_Update(&hash, y->K, sizeof(y->K));
+    HASH_Final(&hash, v_i);
+
+#if defined(YARROW_DEBUG)
+    hex_print(stdout, "old K", y->K, sizeof(y->K));
+#endif
+    /* K <- h'(t) */
+
+    TRY( krb5int_yarrow_stretch(v_i, HASH_DIGEST_SIZE, y->K, CIPHER_KEY_SIZE) );
+
+    /* need to resetup the key schedule as the key has changed */
+
+    TRY(krb5int_yarrow_cipher_init(&y->cipher, y->K));
+
+#if defined(YARROW_DEBUG)
+    hex_print(stdout, "new K", y->K, sizeof(y->K));
+#endif
+
+    /* step 4. C <- E_k(0) */
+
+#if defined(YARROW_DEBUG)
+    hex_print(stdout, "old C", y->C, sizeof(y->C));
+#endif
+    TRY (krb5int_yarrow_cipher_encrypt_block (&y->cipher, zero_block, y->C));
+#if defined(YARROW_DEBUG)
+    hex_print(stdout, "new C", y->C, sizeof(y->C));
+#endif
+
+    /* discard part output from previous key */
+  
+    y->out_left = 0;
+
+    /*   step 5. Reset all entropy estimate accumulators of the entropy
+     *   accumulator to zero
+     */
+
+    for (i = 0; i < y->num_sources; i++)
+    {
+	y->source[i].entropy[pool] = 0;
+	if (pool == YARROW_SLOW_POOL)
+	{
+    /*   if this is a slow reseed, reset the fast pool entropy
+     *   accumulator also
+     */
+	    y->source[i].entropy[YARROW_FAST_POOL] = 0;
+	    y->source[i].reached_slow_thresh = 0;
+	}
+    }
+
+    /*  step 7. If a seed file is in use, the next 2k bits of output
+     *  are written to the seed file
+     */
+
+#if defined( YARROW_SAVE_STATE )
+    if ( y->seeded && y->entropyfile )
+    {
+	TRY( Yarrow_Save_State( y ) );
+    }
+#endif
+
+ CATCH:
+    /*   step 6. Wipe the memory of all intermediate values
+     *
+     */
+
+    mem_zero( digest, sizeof(digest) );
+    mem_zero( &hash, sizeof(hash) );
+    mem_zero( v_0, sizeof(v_0) );
+    mem_zero( v_i, sizeof(v_i) );
+
+    EXCEP_RET;
+}
+int krb5int_yarrow_reseed(Yarrow_CTX* y, int pool)
+{
+	int r;
+	LOCK();
+	r = yarrow_reseed_locked(y, pool);
+	UNLOCK();
+	return r;
+}
+
+int krb5int_yarrow_stretch(const byte* m, size_t size, byte* out, size_t out_size)
+{
+    EXCEP_DECL;
+    const byte* s_i;
+    byte* outp;
+    int left;
+    unsigned int use;
+    HASH_CTX hash, save;
+    byte digest[HASH_DIGEST_SIZE];
+  
+    if (m == NULL || size == 0 || out == NULL || out_size == 0)
+    {
+	THROW( YARROW_BAD_ARG );
+    }
+  
+    /* 
+     *   s_0 = m
+     *   s_1 = h(s_0 | ... | s_{i-1})
+     *
+     *   h'(m, k) = first k bits of (s_0 | s_1 | ...)
+     *
+     */
+
+    outp = out;
+    left = out_size;
+  
+    use = min(out_size, size);
+    mem_copy(outp, m, use);    /* get k bits or as many as available */
+
+    s_i = (const byte*)m;            /* pointer to s0 = m */
+    outp += use;
+    left -= use;
+
+    HASH_Init(&hash);
+    for ( ;
+	  left > 0;
+	  left -= HASH_DIGEST_SIZE)
+    {
+	HASH_Update(&hash, s_i, use);
+    
+	/* have to save hash state to one side as HASH_final changes state */
+
+	mem_copy(&save, &hash, sizeof(hash));
+	HASH_Final(&hash, digest);
+
+	use = min(HASH_DIGEST_SIZE, left);
+	mem_copy(outp, digest, use);
+
+	/* put state back for next time */
+
+	mem_copy(&hash, &save, sizeof(hash));
+
+	s_i = outp;            /* retain pointer to s_i */
+	outp += use;
+    }
+  
+ CATCH:
+    mem_zero(&hash, sizeof(hash));
+    mem_zero(digest, sizeof(digest));
+
+    EXCEP_RET;
+}
+
+static void block_increment(void* block, const int sz)
+{
+    byte* b = block;
+    int i;
+  
+    for (i = sz-1; (++b[i]) == 0 && i > 0; i--)
+    {
+	; /* nothing */
+    }
+}
+
+YARROW_DLL
+int krb5int_yarrow_final(Yarrow_CTX* y)
+{
+    EXCEP_DECL;
+    int locked = 0;
+
+    if (!y) { THROW( YARROW_BAD_ARG ); }
+    TRY( LOCK() );
+    locked = 1;
+
+#if defined( YARROW_SAVE_STATE )
+    if ( y->seeded && y->entropyfile )
+    {
+	TRY( Yarrow_Save_State( y ) );
+    }
+#endif
+
+ CATCH:
+    krb5int_yarrow_cipher_final(&y->cipher);
+    mem_zero( y, sizeof(Yarrow_CTX) );
+    if ( locked ) { TRY( UNLOCK() ); }
+    EXCEP_RET;
+}
+
+YARROW_DLL
+const char* krb5int_yarrow_str_error( int err )
+{
+    err = 1-err;
+    if ( err < 0 || err >= sizeof( yarrow_str_error ) / sizeof( char* ) )
+    {
+	err = 1-YARROW_FAIL;
+    } 
+    return yarrow_str_error[ err ];
+}
+
+#if defined(YARROW_DEBUG)
+static void hex_print(FILE* f, const char* var, void* data, size_t size)
+{
+    const char* conv = "0123456789abcdef";
+    size_t i;
+    char* p = (char*) data;
+    char c, d;
+
+    fprintf(f, var);
+    fprintf(f, " = ");
+    for (i = 0; i < size; i++)
+    {
+	c = conv[(p[i] >> 4) & 0xf];
+	d = conv[p[i] & 0xf];
+	fprintf(f, "%c%c", c, d);
+    }
+    fprintf(f, "\n");
+}
+#endif
diff --git a/mechglue/src/lib/crypto/yarrow/yarrow.h b/mechglue/src/lib/crypto/yarrow/yarrow.h
new file mode 100644
index 000000000..7e1fe1442
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/yarrow.h
@@ -0,0 +1,186 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+
+#ifndef YARROW_H
+#define YARROW_H
+
+#ifdef HAVE_UNISTD_H
+#define YARROW_DETECT_FORK
+#include <unistd.h>
+#endif
+#define YARROW_NO_MATHLIB
+
+#include "ytypes.h"
+#include "yhash.h"
+#include "ycipher.h"
+
+/* These error codes are returned by the functions below. */
+
+#define YARROW_OK                1  /* All is well */
+#define YARROW_FAIL              0  /* generic failure */
+#define YARROW_NOT_INIT         -1  /* YarrowInit hasn't been called */
+#define YARROW_ALREADY_INIT     -2  /* YarrowInit has already been called */
+#define YARROW_NO_DRIVER        -3  /* driver doesn't exist */
+#define YARROW_CANT_OPEN        -4  /* can't open driver */
+#define YARROW_BAD_SOURCE       -5  /* invalid source id */
+#define YARROW_TOO_MANY_SOURCES -6  /* can't create any more source ids */
+#define YARROW_BAD_ARG          -7  /* invalid argument */
+#define YARROW_ACCESS           -8  /* insufficient privileges */
+#define YARROW_NOMEM            -9  /* out of memory */
+#define YARROW_NORSRC          -10  /* a resource is exhausted */
+#define YARROW_NOT_SEEDED      -11  /* not enough entropy to generate output */
+#define YARROW_LOCKING         -12  /* locking error */
+#define YARROW_NO_STATE        -13  /* there is no state to load */
+#define YARROW_STATE_ERROR     -14  /* error with state load or save */
+#define YARROW_NOT_IMPL        -15  /* not implemented */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Yarrow implementation and configuration parameters */
+
+/* pool identification */
+#define YARROW_FAST_POOL 0
+#define YARROW_SLOW_POOL 1
+
+#define YARROW_MAX_SOURCES 20
+#define YARROW_ENTROPY_MULTIPLIER 0.5
+
+#define YARROW_POOL_SIZE (HASH_DIGEST_SIZE*8)
+
+#define YARROW_OUTPUTS_PER_GATE 10   /* Pg */
+#define YARROW_FAST_PT 10
+#define YARROW_SLOW_PT 100
+
+/* thresholds to use once seeded */
+
+#define YARROW_FAST_THRESH 100
+#define YARROW_SLOW_THRESH 160
+#define YARROW_K_OF_N_THRESH 2
+
+/* The Yarrow paper does not specify when the initial seed should be
+   considered complete. Use the same conditions as a slow reseed */
+
+#define YARROW_FAST_INIT_THRESH YARROW_FAST_THRESH
+#define YARROW_SLOW_INIT_THRESH YARROW_SLOW_THRESH
+#define YARROW_K_OF_N_INIT_THRESH YARROW_K_OF_N_THRESH
+
+/* sanity checks */
+
+#if YARROW_FAST_THRESH > YARROW_POOL_SIZE
+error "can't have higher YARROW_FAST_THRESH than pool size"
+#endif
+
+#if YARROW_SLOW_THRESH > YARROW_POOL_SIZE
+error "can't have higher YARROW_SLOW_THRESH than pool size"
+#endif
+
+#if YARROW_FAST_INIT_THRESH > YARROW_POOL_SIZE
+error "can't have higher YARROW_FAST_INIT_THRESH than pool size"
+#endif
+
+#if YARROW_SLOW_INIT_THRESH > YARROW_POOL_SIZE
+error "can't have higher YARROW_SLOW_INIT_THRESH than pool size"
+#endif
+
+typedef size_t estimator_fn(const void* sample, size_t size);
+
+typedef struct
+{
+    int pool;
+    size_t entropy[2];
+    int reached_slow_thresh;
+    estimator_fn* estimator;
+} Source;
+
+typedef struct
+{
+    /* state */
+    int seeded;
+    int saved;
+#if defined( YARROW_DETECT_FORK )
+    int pid;
+#endif
+    Source source[YARROW_MAX_SOURCES];
+    unsigned num_sources;
+    HASH_CTX pool[2];
+    byte out[CIPHER_BLOCK_SIZE];
+    unsigned out_left;
+    COUNTER out_count;
+    COUNTER gate_count;
+    COUNTER gates_limit;
+    byte C[CIPHER_BLOCK_SIZE];
+    CIPHER_CTX cipher;
+    byte K[CIPHER_KEY_SIZE];
+
+    const char *entropyfile;
+
+    /* parameters */
+    COUNTER Pt[2];
+    COUNTER Pg;
+    int slow_k_of_n;
+
+    /* current thresholds */
+    int slow_thresh;
+    int fast_thresh;
+    int slow_k_of_n_thresh;
+} Yarrow_CTX;
+
+#   define YARROW_DLL
+
+
+YARROW_DLL
+int krb5int_yarrow_init( Yarrow_CTX* y, const char *filename );
+
+
+YARROW_DLL
+int krb5int_yarrow_input( Yarrow_CTX* y, unsigned source_id,
+		  const void* sample, 
+		  size_t size, size_t entropy_bits );
+
+YARROW_DLL
+int krb5int_yarrow_status( Yarrow_CTX* y, int *num_sources, unsigned *source_id,
+		   size_t *entropy_bits, size_t *entropy_max );
+
+YARROW_DLL
+int krb5int_yarrow_output( Yarrow_CTX* y, void* out, size_t size );
+
+YARROW_DLL
+int krb5int_yarrow_new_source( Yarrow_CTX* y, unsigned* source_id );
+
+YARROW_DLL
+int krb5int_yarrow_register_source_estimator( Yarrow_CTX* y, unsigned source_id, 
+				      estimator_fn* fptr );
+
+YARROW_DLL
+int krb5int_yarrow_stretch( const byte* m, size_t size, byte* out, size_t out_size );
+
+YARROW_DLL
+int krb5int_yarrow_reseed( Yarrow_CTX* y, int pool );
+
+YARROW_DLL
+int krb5int_yarrow_gate( Yarrow_CTX* y );
+
+YARROW_DLL
+int krb5int_yarrow_final( Yarrow_CTX* y );
+
+YARROW_DLL
+const char* krb5int_yarrow_str_error( int );
+
+
+#   define mem_zero(p, n)       memset((p), 0, (n))
+#   define mem_copy(d, s, n)    memcpy((d), (s), (n))
+
+
+#if !defined(WIN32)
+#   define min(x, y) ((x) < (y) ? (x) : (y))
+#   define max(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* YARROW_H */
diff --git a/mechglue/src/lib/crypto/yarrow/yarrow.man b/mechglue/src/lib/crypto/yarrow/yarrow.man
new file mode 100644
index 000000000..a65b4e05c
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/yarrow.man
@@ -0,0 +1,315 @@
+.rn '' }`
+''' $RCSfile$$Revision$$Date$
+'''
+''' $Log$
+''' Revision 1.1  2001/11/08 21:51:57  hartmans
+''' Add Yarrow from http://www.zeroknowledge.com/.
+'''
+''' This is version 0.1 of their Yarrow implementation.  I have flattened the distribution,
+''' copying files in the src directory directly into this directory.
+'''
+''' Revision 1.1.2.1  2000/08/13 21:11:24  adamb
+''' added some more assumptions
+''' included yarrow.man derived from yarrow.pod with pod2man
+'''
+'''
+.de Sh
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp
+.if t .sp .5v
+.if n .sp
+..
+.de Ip
+.br
+.ie \\n(.$>=3 .ne \\$3
+.el .ne 3
+.IP "\\$1" \\$2
+..
+.de Vb
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve
+.ft R
+
+.fi
+..
+'''
+'''
+'''     Set up \*(-- to give an unbreakable dash;
+'''     string Tr holds user defined translation string.
+'''     Bell System Logo is used as a dummy character.
+'''
+.tr \(*W-|\(bv\*(Tr
+.ie n \{\
+.ds -- \(*W-
+.ds PI pi
+.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+.ds L" ""
+.ds R" ""
+'''   \*(M", \*(S", \*(N" and \*(T" are the equivalent of
+'''   \*(L" and \*(R", except that they are used on ".xx" lines,
+'''   such as .IP and .SH, which do another additional levels of
+'''   double-quote interpretation
+.ds M" """
+.ds S" """
+.ds N" """""
+.ds T" """""
+.ds L' '
+.ds R' '
+.ds M' '
+.ds S' '
+.ds N' '
+.ds T' '
+'br\}
+.el\{\
+.ds -- \(em\|
+.tr \*(Tr
+.ds L" ``
+.ds R" ''
+.ds M" ``
+.ds S" ''
+.ds N" ``
+.ds T" ''
+.ds L' `
+.ds R' '
+.ds M' `
+.ds S' '
+.ds N' `
+.ds T' '
+.ds PI \(*p
+'br\}
+.\"	If the F register is turned on, we'll generate
+.\"	index entries out stderr for the following things:
+.\"		TH	Title 
+.\"		SH	Header
+.\"		Sh	Subsection 
+.\"		Ip	Item
+.\"		X<>	Xref  (embedded
+.\"	Of course, you have to process the output yourself
+.\"	in some meaninful fashion.
+.if \nF \{
+.de IX
+.tm Index:\\$1\t\\n%\t"\\$2"
+..
+.nr % 0
+.rr F
+.\}
+.TH YARROW 1 "perl 5.005, patch 03" "13/Aug/2000" "User Contributed Perl Documentation"
+.UC
+.if n .hy 0
+.if n .na
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.de CQ          \" put $1 in typewriter font
+.ft CW
+'if n "\c
+'if t \\&\\$1\c
+'if n \\&\\$1\c
+'if n \&"
+\\&\\$2 \\$3 \\$4 \\$5 \\$6 \\$7
+'.ft R
+..
+.\" @(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2
+.	\" AM - accent mark definitions
+.bd B 3
+.	\" fudge factors for nroff and troff
+.if n \{\
+.	ds #H 0
+.	ds #V .8m
+.	ds #F .3m
+.	ds #[ \f1
+.	ds #] \fP
+.\}
+.if t \{\
+.	ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.	ds #V .6m
+.	ds #F 0
+.	ds #[ \&
+.	ds #] \&
+.\}
+.	\" simple accents for nroff and troff
+.if n \{\
+.	ds ' \&
+.	ds ` \&
+.	ds ^ \&
+.	ds , \&
+.	ds ~ ~
+.	ds ? ?
+.	ds ! !
+.	ds /
+.	ds q
+.\}
+.if t \{\
+.	ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.	ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.	ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.	ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.	ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.	ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10'
+.	ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m'
+.	ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.	ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10'
+.\}
+.	\" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*(#]
+.ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u'
+.ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u'
+.ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#]
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.ds oe o\h'-(\w'o'u*4/10)'e
+.ds Oe O\h'-(\w'O'u*4/10)'E
+.	\" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.	\" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.	ds : e
+.	ds 8 ss
+.	ds v \h'-1'\o'\(aa\(ga'
+.	ds _ \h'-1'^
+.	ds . \h'-1'.
+.	ds 3 3
+.	ds o a
+.	ds d- d\h'-1'\(ga
+.	ds D- D\h'-1'\(hy
+.	ds th \o'bp'
+.	ds Th \o'LP'
+.	ds ae ae
+.	ds Ae AE
+.	ds oe oe
+.	ds Oe OE
+.\}
+.rm #[ #] #H #V #F C
+.SH "NAME"
+Yarrow_Init, Yarrow_Poll, Yarrow_Input, Yarrow_Status, Yarrow_Output, Yarrow_New_Source, Yarrow_Register_Source_Estimator, Yarrow Final \- cryptographic pseudo-random number generator
+.SH "SYNOPSIS"
+int \fIYarrow_Init\fR\|(Yarrow_CTX *y, const char *filename);
+.PP
+int \fIYarrow_New_Source\fR\|(Yarrow_CTX* y, unsigned* source_id);
+.PP
+int \fIYarrow_Poll\fR\|(Yarrow_CTX *y, unsigned source_id)
+.PP
+int \fIYarrow_Input\fR\|( Yarrow_CTX* y, unsigned source_id,
+       const void* sample, size_t size,
+       size_t entropy_bits);
+.PP
+int \fIYarrow_Status\fR\|(Yarrow_CTX* y, int *num_sources,
+       unsigned *source_id, size_t *entropy_bits,
+       size_t *entropy_max);
+.PP
+int \fIYarrow_Output\fR\|(Yarrow_CTX* y, void* out, size_t size);
+.PP
+int \fIYarrow_Register_Source_Estimator\fR\|(Yarrow_CTX* y,
+       unsigned source_id,
+       size_t (*estimator)(const void* sample,
+                           size_t size));
+.PP
+int \fIYarrow_Final\fR\|(Yarrow_CTX* y);
+.SH "DESCRIPTION"
+\fIYarrow_Init()\fR initializes a \fBYarrow_CTX\fR structure. \fBfilename\fR can
+be NULL, or the path to a seed file that Yarrow will use to store the
+PRNG state for use in later sessions.  Returns \fBYARROW_OK\fR if the
+PRNG is seeded on exit, or \fBYARROW_NOT_SEEDED\fR if the PRNG is not yet
+seeded.
+.PP
+\fIYarrow_New_Source()\fR associates entropy sources such as keyboard input,
+mouse movements and other unpredictable events with a
+\fBYarrow_CTX\fR. The function assigns a unique number to the new source,
+and places it in \fBsource_id\fR.
+.PP
+\fIYarrow_Poll()\fR gathers entropy from the state of the machine and adds
+it to the source \fBsource_id\fR.  The source has to be allocated by the
+user with Yarrow_New_Source.  Returns \fBYARROW_OK\fR if the PRNG is
+seeded on exit, or \fBYARROW_NOT_SEEDED\fR if the PRNG is not yet seeded.
+.PP
+\fIYarrow_Input()\fR is used to add randomness from the source \fBsource_id\fR
+to the PRNG. It reads \fBsize\fR bytes at the address \fBsample\fR. An
+estimate of the entropy in bits contained in the sample must be
+specified as \fBentropy_bits\fR.
+.PP
+\fIYarrow_Status()\fR returns \fBYARROW_OK\fR if the PRNG has enough entropy to
+produce output, and \fBYARROW_NOT_SEEDED\fR if calls to \fIYarrow_Output()\fR
+would fail.
+.PP
+If num_sources is not NULL, the number of entropy sources that still
+need to be seeded is returned in \fB*num_sources\fR.
+.PP
+If source_id is not NULL, the entropy source that is closest to its
+threshold is returned in \fB*source_id\fR.  \fB*source_id\fR is set to \-1 if
+no sources have either reached their threshold or not collected any
+entropy yet.
+.PP
+If not NULL, \fB*entropy_bits\fR is set to the current number of bits for
+the source \fB*source_id\fR, and \fB*entropy_max\fR to the threshold.
+.PP
+\fIYarrow_Output()\fR generates \fBsize\fR bytes of cryptographically strong
+pseudo-random output and places them at \fBout\fR. The return value must
+always be checked. If an error occurs, the PRNG may produce
+predictable data or no output at all.
+.PP
+\fIYarrow_Register_Source_Estimator()\fR registers an entropy estimator
+for \fBsource_id\fR. An entropy estimator is a function that tries to
+estimate the entropy in a sample and returns the entropy in bits
+in order to detect abnormal situations in which the samples have a very
+low entropy.
+.PP
+\fIYarrow_Final()\fR writes the PRNG state to the seed file and erases it
+from memory.
+.SH "RETURN VALUES"
+All functions return \fBYARROW_OK\fR on success. Error conditions are reported
+as follows:
+.PP
+.Vb 16
+\& YARROW_FAIL              generic failure
+\& YARROW_NOT_INIT          YarrowInit() hasn't been called
+\& YARROW_ALREADY_INIT      YarrowInit() has already been called
+\& YARROW_NO_DRIVER         driver doesn't exist
+\& YARROW_CANT_OPEN         can't open driver
+\& YARROW_BAD_SOURCE        invalid source id
+\& YARROW_TOO_MANY_SOURCES  can't create any more source IDs
+\& YARROW_BAD_ARG           invalid argument
+\& YARROW_ACCESS            insufficient privileges
+\& YARROW_NOMEM             out of memory
+\& YARROW_NORSRC            a resource (apart from memory) is exhausted
+\& YARROW_NOT_SEEDED        not enough entropy to generate output
+\& YARROW_LOCKING           locking error
+\& YARROW_NO_STATE          there is no state to load 
+\& YARROW_STATE_ERROR       error with state load or save
+\& YARROW_NOT_IMPL          not implemented
+.Ve
+.SH "AUTHORS"
+Yarrow was designed by John Kelsey, Bruce Schneier and Niels Ferguson
+of Counterpane Systems. This implementation is (C) 2000 by
+Zero-Knowledge Systems Inc.
+
+.rn }` ''
+.IX Title "YARROW 1"
+.IX Name "Yarrow_Init, Yarrow_Poll, Yarrow_Input, Yarrow_Status, Yarrow_Output, Yarrow_New_Source, Yarrow_Register_Source_Estimator, Yarrow Final - cryptographic pseudo-random number generator"
+
+.IX Header "NAME"
+
+.IX Header "SYNOPSIS"
+
+.IX Header "DESCRIPTION"
+
+.IX Header "RETURN VALUES"
+
+.IX Header "AUTHORS"
+
diff --git a/mechglue/src/lib/crypto/yarrow/yarrow.pod b/mechglue/src/lib/crypto/yarrow/yarrow.pod
new file mode 100644
index 000000000..7892ebbe6
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/yarrow.pod
@@ -0,0 +1,112 @@
+=pod
+
+=head1 NAME
+
+Yarrow_Init, Yarrow_Poll, Yarrow_Input, Yarrow_Status, Yarrow_Output, Yarrow_New_Source, Yarrow_Register_Source_Estimator, Yarrow Final - cryptographic pseudo-random number generator
+
+=head1 SYNOPSIS
+
+int Yarrow_Init(Yarrow_CTX *y, const char *filename);
+
+int Yarrow_New_Source(Yarrow_CTX* y, unsigned* source_id);
+
+int Yarrow_Poll(Yarrow_CTX *y, unsigned source_id)
+
+int Yarrow_Input( Yarrow_CTX* y, unsigned source_id,
+       const void* sample, size_t size,
+       size_t entropy_bits);
+
+int Yarrow_Status(Yarrow_CTX* y, int *num_sources,
+       unsigned *source_id, size_t *entropy_bits,
+       size_t *entropy_max);
+
+int Yarrow_Output(Yarrow_CTX* y, void* out, size_t size);
+
+int Yarrow_Register_Source_Estimator(Yarrow_CTX* y,
+       unsigned source_id,
+       size_t (*estimator)(const void* sample,
+                           size_t size));
+
+int Yarrow_Final(Yarrow_CTX* y);
+
+=head1 DESCRIPTION
+
+Yarrow_Init() initializes a B<Yarrow_CTX> structure. B<filename> can
+be NULL, or the path to a seed file that Yarrow will use to store the
+PRNG state for use in later sessions.  Returns B<YARROW_OK> if the
+PRNG is seeded on exit, or B<YARROW_NOT_SEEDED> if the PRNG is not yet
+seeded.
+
+Yarrow_New_Source() associates entropy sources such as keyboard input,
+mouse movements and other unpredictable events with a
+B<Yarrow_CTX>. The function assigns a unique number to the new source,
+and places it in B<source_id>.
+
+Yarrow_Poll() gathers entropy from the state of the machine and adds
+it to the source B<source_id>.  The source has to be allocated by the
+user with Yarrow_New_Source.  Returns B<YARROW_OK> if the PRNG is
+seeded on exit, or B<YARROW_NOT_SEEDED> if the PRNG is not yet seeded.
+
+Yarrow_Input() is used to add randomness from the source B<source_id>
+to the PRNG. It reads B<size> bytes at the address B<sample>. An
+estimate of the entropy in bits contained in the sample must be
+specified as B<entropy_bits>.
+
+Yarrow_Status() returns B<YARROW_OK> if the PRNG has enough entropy to
+produce output, and B<YARROW_NOT_SEEDED> if calls to Yarrow_Output()
+would fail.
+
+If num_sources is not NULL, the number of entropy sources that still
+need to be seeded is returned in B<*num_sources>.
+
+If source_id is not NULL, the entropy source that is closest to its
+threshold is returned in B<*source_id>.  B<*source_id> is set to -1 if
+no sources have either reached their threshold or not collected any
+entropy yet.
+
+If not NULL, B<*entropy_bits> is set to the current number of bits for
+the source B<*source_id>, and B<*entropy_max> to the threshold.
+
+Yarrow_Output() generates B<size> bytes of cryptographically strong
+pseudo-random output and places them at B<out>. The return value must
+always be checked. If an error occurs, the PRNG may produce
+predictable data or no output at all.
+
+Yarrow_Register_Source_Estimator() registers an entropy estimator
+for B<source_id>. An entropy estimator is a function that tries to
+estimate the entropy in a sample and returns the entropy in bits
+in order to detect abnormal situations in which the samples have a very
+low entropy.
+
+Yarrow_Final() writes the PRNG state to the seed file and erases it
+from memory.
+
+=head1 RETURN VALUES
+
+All functions return B<YARROW_OK> on success. Error conditions are reported
+as follows:
+
+ YARROW_FAIL              generic failure
+ YARROW_NOT_INIT          YarrowInit() hasn't been called
+ YARROW_ALREADY_INIT      YarrowInit() has already been called
+ YARROW_NO_DRIVER         driver doesn't exist
+ YARROW_CANT_OPEN         can't open driver
+ YARROW_BAD_SOURCE        invalid source id
+ YARROW_TOO_MANY_SOURCES  can't create any more source IDs
+ YARROW_BAD_ARG           invalid argument
+ YARROW_ACCESS            insufficient privileges
+ YARROW_NOMEM             out of memory
+ YARROW_NORSRC            a resource (apart from memory) is exhausted
+ YARROW_NOT_SEEDED        not enough entropy to generate output
+ YARROW_LOCKING           locking error
+ YARROW_NO_STATE          there is no state to load 
+ YARROW_STATE_ERROR       error with state load or save
+ YARROW_NOT_IMPL          not implemented
+
+=head1 AUTHORS
+
+Yarrow was designed by John Kelsey, Bruce Schneier and Niels Ferguson
+of Counterpane Systems. This implementation is (C) 2000 by
+Zero-Knowledge Systems Inc.
+
+=cut
diff --git a/mechglue/src/lib/crypto/yarrow/ycipher.c b/mechglue/src/lib/crypto/yarrow/ycipher.c
new file mode 100644
index 000000000..01d105ffe
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/ycipher.c
@@ -0,0 +1,96 @@
+/*
+ * lib/crypto/yarrow/ycipher.c
+ *
+ * Copyright (C) 2001 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * 
+ *
+ *  Routines  to implement krb5 cipher operations.
+ */
+#include "k5-int.h"
+#include "yarrow.h"
+#include "ycipher.h"
+#include "enc_provider.h"
+#include "assert.h"
+
+int
+krb5int_yarrow_cipher_init
+(CIPHER_CTX *ctx,
+ unsigned const char * key)
+{
+  size_t keybytes, keylength;
+  const struct krb5_enc_provider *enc = &yarrow_enc_provider;
+  krb5_error_code ret;
+  krb5_data randombits;
+  keybytes = enc->keybytes;
+  keylength = enc->keylength;
+  assert (keybytes == CIPHER_KEY_SIZE);
+  if (ctx->key.contents) {
+    memset (ctx->key.contents, 0, ctx->key.length);
+    free (ctx->key.contents);
+  }
+  ctx->key.contents = (void *) malloc  (keylength);
+  ctx->key.length = keylength;
+  if (ctx->key.contents == NULL)
+    return (YARROW_NOMEM);
+  randombits.data = (char *) key;
+  randombits.length = keybytes;
+  ret = enc->make_key (&randombits, &ctx->key);
+  if (ret) {
+    memset (ctx->key.contents, 0, ctx->key.length);
+    free(ctx->key.contents);
+    ctx->key.contents = NULL;
+    return (YARROW_FAIL);
+  }
+  return (YARROW_OK);
+}
+
+int krb5int_yarrow_cipher_encrypt_block
+(CIPHER_CTX *ctx, const unsigned char *in,
+ unsigned char *out)
+{
+  krb5_error_code ret;
+  krb5_data ind, outd;
+  const struct krb5_enc_provider *enc = &yarrow_enc_provider;
+  ind.data = (char *) in;
+  ind.length = CIPHER_BLOCK_SIZE;
+  outd.data = out;
+  outd.length = CIPHER_BLOCK_SIZE;
+  ret = enc->encrypt (&ctx->key, 0, &ind, &outd);
+  if (ret)
+    return YARROW_FAIL;
+  return YARROW_OK;
+}
+
+void
+krb5int_yarrow_cipher_final
+(CIPHER_CTX *ctx)
+
+{
+ if (ctx->key.contents) {
+    memset (ctx->key.contents, 0, ctx->key.length);
+    free (ctx->key.contents);
+  }
+  ctx->key.contents = 0;
+  ctx->key.length = 0;
+}
diff --git a/mechglue/src/lib/crypto/yarrow/ycipher.h b/mechglue/src/lib/crypto/yarrow/ycipher.h
new file mode 100644
index 000000000..96999c0db
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/ycipher.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+
+#ifndef YCIPHER_H
+#define YCIPHER_H
+
+/* block cipher interface */
+
+typedef struct 
+{
+    krb5_keyblock key;
+} CIPHER_CTX;
+
+/* We need to choose a cipher. To do this, choose an enc_provider.
+ * Be sure to update the block size and key size constants below;
+ * they are here because static data structures are sized based on
+ * them so they must be known at compile time./  Thus we cannot
+ * call the enc_provider function to get the info.
+ */
+
+#define yarrow_enc_provider krb5int_enc_aes256
+
+#define CIPHER_BLOCK_SIZE 16
+#define CIPHER_KEY_SIZE 32
+
+#if defined( YARROW_NO_MATHLIB )
+/* see macros at end for functions evaluated */
+#define POW_CIPHER_KEY_SIZE    115792089237316195423570985008687907853269984665640564039457584007913129639936.0
+#define POW_CIPHER_BLOCK_SIZE  340282366920938463463374607431768211456.0
+#endif
+
+
+int krb5int_yarrow_cipher_init (CIPHER_CTX *ctx, unsigned const char *key);
+int krb5int_yarrow_cipher_encrypt_block
+(CIPHER_CTX *ctx,  const unsigned char *in, unsigned char *out);
+void krb5int_yarrow_cipher_final (CIPHER_CTX *ctx);
+
+#if !defined( YARROW_NO_MATHLIB )
+#define POW_CIPHER_KEY_SIZE pow(2.0, CIPHER_KEY_SIZE * 8 / 3.0)
+#define POW_CIPHER_BLOCK_SIZE pow(2.0, CIPHER_BLOCK_SIZE * 8)
+#endif
+
+#endif /* YCIPHER_H */
diff --git a/mechglue/src/lib/crypto/yarrow/yexcep.h b/mechglue/src/lib/crypto/yarrow/yexcep.h
new file mode 100644
index 000000000..d27de2d5e
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/yexcep.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+
+#ifndef YEXCEP_H
+#define YEXCEP_H
+
+/*   yes, macros with gotos in them, but in the interests of
+ *   avoiding repetition of code, and having less error prone
+ *   error handling
+ *
+ *   EXCEP_DECL - declares the return value and local state variables
+ *                needed by the exception macros
+ *
+ *   THROW( x ) - set return value to x and goto function cleanup
+ *                section (CATCH: block).  In the catch block, THROW
+ *                does not goto catch label to avoid loops, and instead
+ *                falls through to the next statement.
+ *
+ *   EXCEP_OK   - success return value (=1)
+ *
+ *   EXCEP_FAIL - failure return value (=0), other user exceptions are 
+ *                given negative values (<0)
+ *
+ *   TRY( x )   - if code returns value <= 0 TRY sets return value to 
+ *                that value and goes to function cleanup section 
+ *                (CATCH: block).  In the catch block, TRY does not goto
+ *                the catch label to avoid loops, and instead
+ *                falls through to the next statement.  The
+ *                return value is set to the first non success value
+ *                returned by a TRY, unless this is overridden by a THROW.
+ *
+ *   CATCH:     - start of catch block, also switches behavior of 
+ *                TRY and THROW to not goto CATCH: inside the catch
+ *                block to avoid loops
+ *
+ *   EXCEP_RET  - return the current return value from the function
+ *                equivlanet to return (EXCEPTION)
+ *
+ *   EXCEPTION  - current return value, is set to EXCEP_OK by EXCEP_DECL
+ *
+ *   EXCEP_BOOL - convert current return value to EXCEP_OK, or EXCEP_FAIL
+ *                (EXCEP_FAIL is anything other than EXCEP_OK)
+ *
+ */
+
+/* example usage */
+
+/*
+ * 
+ * #define EXCEP_OK_COMMENT 2
+ * #define EXCEP_NULL_PTR -1
+ * #define EXCEP_OUT_OF_MEM -2
+ * 
+ * int bar( char *c )
+ * {
+ *     EXCEP_DECL;
+ * 
+ *     if ( !c ) { THROW( EXCEP_NULL_PTR ); }
+ *     if ( *c == '\0' ) { THROW( EXCEP_FAIL ); );
+ *     if ( *c == '#' ) { SET( EXCEP_COMMENT ); }
+ *  CATCH:
+ *     EXCEP_RET;
+ * }
+ * 
+ * int foo( char *c )
+ * {
+ *     EXCEP_DECL;
+ *     int *p = NULL;
+ * 
+ *     if ( !c ) { THROW( EXCEP_NULL_PTR ); }
+ *     TRY( bar( c ) );
+ *     if ( RETURN == EXCEP_COMMENT ) { print( "comment\n" ); }
+ *     p = strdup( c );
+ *     if ( !p ) { THROW( EXCEP_OUT_OF_MEM ); }
+ * 
+ *  CATCH:
+ *     if ( p ) { TRY( bar( p ) ); free( p ); }
+ *     THROW( EXCEP_BOOL );
+ *     if ( EXCEPTION == EXCEP_OK ) { printf( "success\n" ); }
+ *     EXCEP_RET;
+ * }
+ * 
+ */
+
+#define EXCEP_FAIL 0
+#define EXCEP_OK 1
+#define EXCEP_DECL int _thr = 0, _ret2 = 0, _ret = _ret2+EXCEP_OK
+
+#define THROW( x ) \
+    do { \
+        _ret = (x); \
+        if( !_thr ) { goto _catch; } \
+    } while ( 0 )
+
+#define TRY( x ) \
+    do { \
+        _ret2 = (x); \
+        if ( _ret > 0 && _ret2 <= 0 ) { THROW( _ret2 ); } \
+    } while ( 0 )
+
+#define SET( x ) (_ret = (x))
+#define EXCEP_RET return( _ret )
+#define EXCEPTION _ret
+#define RETURN _ret2
+#define CATCH _catch: _thr = 1; if ( 0 ) { goto _foo; } _foo
+#define EXCEP_BOOL ( _ret > 0 ? EXCEP_OK : EXCEP_FAIL )
+
+#endif
diff --git a/mechglue/src/lib/crypto/yarrow/yhash.h b/mechglue/src/lib/crypto/yarrow/yhash.h
new file mode 100644
index 000000000..aaa739fe1
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/yhash.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+
+#ifndef YHASH_H
+#define YHASH_H
+
+/* hash function interface */
+
+/* default to SHA1 for yarrow 160 */
+
+#include "shs.h"
+
+
+
+#define HASH_CTX SHS_INFO
+#define HASH_Init(x) shsInit(x)
+#define HASH_Update(x, buf, sz) shsUpdate(x, (const void*)buf, sz)
+#define HASH_Final(x, tdigest)  do { \
+  int loopvar; \
+  unsigned char *out2 = (void *)(tdigest); \
+  HASH_CTX  *ctx = (x); \
+  shsFinal(ctx); \
+for (loopvar=0; loopvar<(sizeof(ctx->digest)/sizeof(ctx->digest[0])); loopvar++) { \
+  out2[loopvar*4] = (ctx->digest[loopvar]>>24)&0xff; \
+  out2[loopvar*4+1] = (ctx->digest[loopvar]>>16)&0xff; \
+  out2[loopvar*4+2] = (ctx->digest[loopvar]>>8)&0xff; \
+  out2[loopvar*4+3] = ctx->digest[loopvar]&0xff; \
+} \
+  } while(0)
+
+
+#define HASH_DIGEST_SIZE SHS_DIGESTSIZE
+
+#endif /* YHASH_H */
diff --git a/mechglue/src/lib/crypto/yarrow/ylock.h b/mechglue/src/lib/crypto/yarrow/ylock.h
new file mode 100644
index 000000000..9c032dc61
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/ylock.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+
+#ifndef YLOCK_H
+#define YLOCK_H
+
+#include "yarrow.h"
+
+/* these functions should return:
+ *
+ *        YARROW_OK on success
+ *    and YARROW_LOCKING on failure
+ */
+
+#if 0
+static int LOCK( void ) {  return (YARROW_OK); }
+static int UNLOCK( void ) {  return (YARROW_OK); }
+#else
+#include "k5-thread.h"
+extern k5_mutex_t krb5int_yarrow_lock;
+#define LOCK()	(k5_mutex_lock(&krb5int_yarrow_lock) ? YARROW_LOCKING : YARROW_OK)
+#define UNLOCK() (k5_mutex_unlock(&krb5int_yarrow_lock) ? YARROW_LOCKING : YARROW_OK)
+#endif
+
+#endif /* YLOCK_H */
diff --git a/mechglue/src/lib/crypto/yarrow/ystate.h b/mechglue/src/lib/crypto/yarrow/ystate.h
new file mode 100644
index 000000000..2886ca338
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/ystate.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+
+#ifndef YSTATE_H
+#define YSTATE_H
+
+#ifdef YARROW_SAVE_STATE
+
+#include "ycipher.h"
+#include "ytypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Yarrow_STATE {
+    byte seed[CIPHER_KEY_SIZE * 2];    /* 2k bits saved to seed file */
+} Yarrow_STATE;
+
+int STATE_Save( const char *filename, const struct Yarrow_STATE* state );
+int STATE_Load( const char *filename, struct Yarrow_STATE* state );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* YARROW_SAVE_STATE */
+
+#endif /* YSTATE_H */
diff --git a/mechglue/src/lib/crypto/yarrow/ytest.c b/mechglue/src/lib/crypto/yarrow/ytest.c
new file mode 100644
index 000000000..aa1f6941f
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/ytest.c
@@ -0,0 +1,389 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+/*
+ * Yarrow - Cryptographic Pseudo-Random Number Generator
+ * Copyright (c) 2000 Zero-Knowledge Systems, Inc.
+ *
+ * See the accompanying LICENSE file for license information.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "yarrow.h"
+#include "yexcep.h"
+
+void hex_print( FILE* f, const char* var, void* data, size_t size );
+void dump_yarrow_state( FILE* f, Yarrow_CTX* y );
+
+#define YARROW_SEED_FILE "seed"
+
+static void print_yarrow_status( Yarrow_CTX *y )
+{
+    int sid, pool;
+    Source* source;
+
+    for ( pool = 0; pool < 2; pool++ )
+    {
+	printf( " %s: ", pool == YARROW_SLOW_POOL ? "slow" : "fast" );
+	for ( sid = 0; sid < y->num_sources; sid++ )
+	{
+	    source = &y->source[ sid ];
+	    printf( "#%d=%d/%d, ", sid, source->entropy[pool], 
+		    pool == YARROW_SLOW_POOL ? 
+		    y->slow_thresh : y->fast_thresh );
+	}
+    }
+    printf( "\n" );
+}
+
+int yarrow_verbose = 0;
+#define VERBOSE( x ) if ( yarrow_verbose ) { x }
+
+int Instrumented_krb5int_yarrow_input( Yarrow_CTX* y, int sid, void* sample,
+			       size_t size, int entropy )
+{
+    int ret;
+
+    VERBOSE( printf( "krb5int_yarrow_input( #%d, %d bits, %s ) = [", sid, entropy, 
+		     y->source[sid].pool == 
+		     YARROW_SLOW_POOL ? "slow" : "fast" ); );
+    ret = krb5int_yarrow_input( y, sid, sample, size, entropy );
+
+    VERBOSE( printf( "%s]\n", krb5int_yarrow_str_error( ret ) ); );
+    VERBOSE( print_yarrow_status( y ); );
+    return (ret);
+}
+
+typedef int (*test_fn)( void );
+
+int test_1( void );
+int test_2( void );
+int test_3( void );
+int test_4( void );
+
+test_fn test_func[] =
+{
+    test_1, test_2, test_3, test_4
+};
+
+#define num_tests ( sizeof(test_func) / sizeof(test_fn) )
+
+int do_test( int t )
+{
+    EXCEP_DECL;
+    int ret;
+
+    printf( "doing test %d ... ", t ); fflush( stdout );
+    ret = test_func[ t-1 ]();
+    VERBOSE( printf( "\ndone test %d ", t ); );
+    printf( "[%s]\n", krb5int_yarrow_str_error( ret ) ); fflush( stdout );
+    THROW( ret );
+
+ CATCH:
+    THROW( EXCEP_BOOL );
+    EXCEP_RET;
+}
+
+int main( int argc, char* argv[] )
+{
+    EXCEP_DECL;
+    int test = 0;
+    char** argvp;
+    char* arg;
+    char* conv_ok = NULL;
+    int ok = YARROW_OK;
+    int done_some_tests = 0;
+    int i;
+    int ret;
+
+#if defined(__MWERKS__) && defined(macintosh)
+    argc = ccommand(&argv);
+#endif
+    
+    for ( argvp = argv+1, i = 1; i < argc; i++, argvp++ )
+    {
+	arg = *argvp;
+	if ( arg[0] == '-' ) 
+	{
+	    switch ( arg[1] )
+	    {
+	    case 'v': yarrow_verbose = 1; continue; 
+	    default: fprintf( stderr, "usage: test [-v] [[test] ... ]\n" );
+		THROW( YARROW_FAIL );
+	    }
+	}
+	conv_ok = NULL;
+	test = strtoul( arg, &conv_ok, 10 );
+	if ( !conv_ok || test < 1 || test > num_tests )
+	{
+	    fprintf( stderr, "usage: test [-v] [[test] ... ]\n" );
+	    THROW( YARROW_FAIL );
+	}
+	else
+	{
+	    ret = do_test( test );
+	    if ( ok ) { ok = ret; }
+	    done_some_tests = 1;
+	}
+    }
+
+    if ( !done_some_tests )
+    {
+	for ( i = 1; i <= num_tests; i++ )
+	{
+	    ret = do_test( i );
+	    if ( ok ) { ok = ret; }
+	}
+    }
+    THROW( ok );
+
+ CATCH:
+    switch (EXCEPTION)
+    {
+    case YARROW_OK:
+	exit (EXIT_SUCCESS);
+    default:
+	exit (EXIT_FAILURE);
+    }
+}
+
+int test_1( void )
+{
+    EXCEP_DECL;
+
+#if defined(YARROW_HASH_SHA1)
+    VERBOSE( printf( "\nsha1 test\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+#elif defined(YARROW_MD5)
+    VERBOSE( printf( "\nmd5 test\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+#else
+    VERBOSE( printf( "\nunknown hash function\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+#endif
+ CATCH:
+    EXCEP_RET;
+}
+
+int test_2( void )
+{
+    EXCEP_DECL;
+
+#if defined(YARROW_CIPHER_3DES)
+    VERBOSE( printf( "\n3des test\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+#elif defined(YARROW_CIPHER_BLOWFISH)
+    VERBOSE( printf( "\nblowfish test\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+#elif defined(YARROW_CIPHER_IDEA)
+    VERBOSE( printf( "\nidea test\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+#else
+    VERBOSE( printf( "\nunknown encryption function\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+#endif
+ CATCH:
+    EXCEP_RET;
+}
+
+int test_3( void )
+{
+    EXCEP_DECL;
+
+#if !defined(YARROW_CIPHER_3DES) || !defined(YARROW_HASH_SHA1)
+    VERBOSE( printf( "\nnot Yarrow-SHA1-3DES (aka Yarrow-160)\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+#endif
+
+    VERBOSE( printf( "\nkrb5int_yarrow_stretch\n\n" ); );
+    THROW( YARROW_NOT_IMPL );
+    
+ CATCH:
+    EXCEP_RET;
+}
+
+int test_4( void )
+{
+    EXCEP_DECL;
+    Yarrow_CTX yarrow;
+    int initialized = 0;
+    unsigned user, mouse, keyboard;
+    int i, ret;
+    byte user_sample[ 20 ];
+    byte mouse_sample[ 4 ];
+    byte keyboard_sample[ 2 ];
+    byte random[ 30 ];
+    byte junk[ 48 ];
+
+    memset( user_sample,     3, sizeof( user_sample ) );
+    memset( mouse_sample,    1, sizeof( mouse_sample ) );
+    memset( keyboard_sample, 2, sizeof( keyboard_sample ) );
+
+    VERBOSE( printf( "\nGeneral workout test\n\n" ); )
+
+    VERBOSE( printf( "krb5int_yarrow_init() = [" ); );
+    ret = krb5int_yarrow_init( &yarrow, YARROW_SEED_FILE );
+    VERBOSE( printf( "%s]\n", krb5int_yarrow_str_error( ret ) ); );
+
+    if ( ret != YARROW_OK && ret != YARROW_NOT_SEEDED ) { THROW( ret ); }
+    initialized = 1;
+
+#if defined( YARROW_DEBUG )
+    dump_yarrow_state( stdout, &yarrow );
+#endif
+
+    ret = krb5int_yarrow_new_source( &yarrow, &user );
+    VERBOSE( printf( "krb5int_yarrow_new_source() = [%s]\n",
+		     krb5int_yarrow_str_error( ret ) ); );
+    if ( ret != YARROW_OK ) { THROW( ret ); }
+  
+    VERBOSE( printf( "Yarrow_Poll( #%d ) = [", user ); );
+    ret = Yarrow_Poll( &yarrow, user );
+    VERBOSE( printf( "%s]\n", krb5int_yarrow_str_error( ret ) ); );
+
+    ret = krb5int_yarrow_new_source( &yarrow, &mouse );
+    VERBOSE( printf( "krb5int_yarrow_new_source() = [%s]\n", 
+		     krb5int_yarrow_str_error( ret ) ); );
+    if ( ret != YARROW_OK ) { THROW( ret ); }
+
+    ret = krb5int_yarrow_new_source( &yarrow, &keyboard );
+    VERBOSE( printf( "krb5int_yarrow_new_source() = [%s]\n", 
+		     krb5int_yarrow_str_error( ret ) ); );
+    if ( ret != YARROW_OK ) { THROW( ret ); }
+
+/*  prematurely try to draw output, to check failure when no
+ *  seed file, or state saving turned off
+ */
+
+    VERBOSE( printf( "krb5int_yarrow_output( %d ) = [", sizeof( random ) ); );
+    ret = krb5int_yarrow_output( &yarrow, random, sizeof( random ) );
+    VERBOSE( printf( "%s]\n", krb5int_yarrow_str_error( ret ) ); );
+
+/*   do it twice so that we some slow samples 
+ *   (first sample goes to fast pool, and then samples alternate)
+ */
+
+    for ( i = 0; i < 2; i++ )
+    {
+	TRY( Instrumented_krb5int_yarrow_input( &yarrow, mouse, mouse_sample, 
+					sizeof( mouse_sample ), 2 ) );
+	
+	TRY( Instrumented_krb5int_yarrow_input( &yarrow, keyboard, keyboard_sample, 
+					sizeof( keyboard_sample ), 2 ) );
+
+	TRY( Instrumented_krb5int_yarrow_input( &yarrow, user, user_sample, 
+					sizeof( user_sample ), 2 ) );
+    }
+	
+#if defined( YARROW_DEBUG )
+    dump_yarrow_state( stdout, &yarrow );
+#endif
+
+    VERBOSE( printf( "\nInduce user source (#%d) to reach "
+		     "slow threshold\n\n", user ); );
+
+    /* induce fast reseed */
+
+    for ( i = 0; i < 7; i++ )
+    {
+	TRY( Instrumented_krb5int_yarrow_input( &yarrow, user, user_sample, 
+					sizeof( user_sample ), 
+					sizeof( user_sample ) * 3 ) );
+    }
+
+    VERBOSE( printf( "\nInduce mouse source (#%d) to reach "
+		     "slow threshold reseed\n\n", mouse ); );
+
+    /* induce slow reseed, by triggering a second source to reach it's
+       threshold */
+
+    for ( i = 0; i < 40; i++ )
+    {
+	TRY( Instrumented_krb5int_yarrow_input( &yarrow, mouse, mouse_sample, 
+					sizeof( mouse_sample ), 
+					sizeof( mouse_sample )*2 ) );
+    }
+
+    VERBOSE( printf( "\nProduce some output\n\n" ); );
+
+    for ( i = 0; i < 30; i++ )
+    {
+	VERBOSE( printf( "krb5int_yarrow_output( %d ) = [", sizeof( junk ) ); );
+	ret = krb5int_yarrow_output( &yarrow, junk, sizeof( junk ) );
+	VERBOSE( printf( "%s]\n", krb5int_yarrow_str_error( ret ) ); );
+	if ( ret != YARROW_OK ) { THROW( ret );	}
+    }
+
+    memset( junk, 0, sizeof( junk ) );
+
+    VERBOSE( printf( "\nTrigger some fast and slow reseeds\n\n" ); );
+
+    for ( i = 0; i < 30; i++ )
+    {
+	/* odd input to a different source so there are some slow reseeds */
+
+	if ( i % 16 == 0 )
+	{
+	    TRY( Instrumented_krb5int_yarrow_input( &yarrow, mouse, junk, 
+					    sizeof( junk ), 
+					    sizeof( junk ) * 3 ) );
+	}
+	else
+	{
+	    TRY( Instrumented_krb5int_yarrow_input( &yarrow, user, junk, 
+					    sizeof( junk ), 
+					    sizeof( junk ) * 3 ) );
+	}
+    }
+
+    VERBOSE( printf( "\nPrint some random output\n\n" ); );
+    
+    VERBOSE( printf( "krb5int_yarrow_output( %d ) = [", sizeof( random ) ); );
+    ret = krb5int_yarrow_output( &yarrow, random, sizeof( random ) );
+    VERBOSE( printf( "%s]\n", krb5int_yarrow_str_error( ret ) ); );
+    if ( ret != YARROW_OK )
+    {
+	THROW( ret );
+    }
+    else
+    {
+	VERBOSE( hex_print( stdout, "random", random, sizeof( random ) ); );
+    }
+
+    VERBOSE( printf( "\nClose down Yarrow\n\n" ); );
+
+ CATCH:
+    if ( initialized )
+    {
+	VERBOSE( printf( "krb5int_yarrow_final() = [" ); );
+	ret = krb5int_yarrow_final( &yarrow );
+	VERBOSE( printf( "%s]\n", krb5int_yarrow_str_error( ret ) ); );
+	THROW( ret );
+    }
+    EXCEP_RET;
+}
+
+void hex_print( FILE* f, const char* var, void* data, size_t size )
+{
+    const char* conv = "0123456789abcdef";
+    size_t i;
+    char* p = (char*) data;
+    char c, d;
+    
+    fprintf( f, var );
+    fprintf( f, " = " );
+    for ( i = 0; i < size; i++ )
+    {
+	c = conv[ (p[ i ] >> 4) & 0xf ];
+	d = conv[ p[ i ] & 0xf ];
+	fprintf( f, "%c%c", c, d );
+    }
+    fprintf( f, "\n" );
+}
+
+void dump_yarrow_state( FILE* f, Yarrow_CTX* y )
+{
+    fprintf( f, "===Yarrow State===\n" );
+    hex_print( f, "C", y->C, sizeof( y->C ) );
+    hex_print( f, "K", y->K, sizeof( y->K ) );
+}
diff --git a/mechglue/src/lib/crypto/yarrow/ytypes.h b/mechglue/src/lib/crypto/yarrow/ytypes.h
new file mode 100644
index 000000000..b7a30c76d
--- /dev/null
+++ b/mechglue/src/lib/crypto/yarrow/ytypes.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C; c-file-style: "bsd" -*- */
+
+#ifndef YTYPES_H
+#define YTYPES_H
+
+#include <limits.h>
+#include <stddef.h>
+#include "krb5/autoconf.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#define byte unsigned char 
+
+#define uint8 unsigned char
+#define int8 signed char
+
+
+#if defined(uint64)
+#   define COUNTER uint64
+#else
+#   define COUNTER krb5_ui_4
+#endif
+
+#define COUNTER_MAX ((COUNTER)0 - 1)
+
+#endif /* YTYPES_H */
diff --git a/mechglue/src/lib/des425/.Sanitize b/mechglue/src/lib/des425/.Sanitize
new file mode 100644
index 000000000..4db4c7032
--- /dev/null
+++ b/mechglue/src/lib/des425/.Sanitize
@@ -0,0 +1,54 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+cksum.c
+configure
+configure.in
+des.c
+des.h
+enc_dec.c
+k4_glue.c
+key_parity.c
+key_sched.c
+new_rnd_key.c
+pcbc_encrypt.c
+quad_cksum.c
+random_key.c
+read_passwd.c
+str_to_key.c
+string2key.c
+unix_time.c
+util.c
+verify.c
+weak_key.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/des425/ChangeLog b/mechglue/src/lib/des425/ChangeLog
new file mode 100644
index 000000000..0667b6f08
--- /dev/null
+++ b/mechglue/src/lib/des425/ChangeLog
@@ -0,0 +1,583 @@
+2006-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_quad): Include support library.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac): Target deleted.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libdes425.exports: New file.
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* pcbc_encrypt.c (des_pcbc_encrypt): Don't pass a temporary
+	variable to DES_DO_ENCRYPT and _DECRYPT.  Drop the temporary
+	variable.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.c (mit_des_cbc_encrypt): Undef before use.
+	* enc_dec.c (mit_des_cbc_encrypt): Likewise.
+	* mac_des_glue.c (mit_des3_cbc_encrypt): Likewise.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* quad_cksum.c, t_pcbc.c, t_quad.c, verify.c: Don't declare errno
+	or errmsg.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+
+    * mac_des_glue.c, des.c, enc_dec.c, key_sched.c, str_to_key.c: 
+    Move KfM des functions into their own file.  They are all 
+    deprecated on KfM and shouldn't even get built on stock krb5 builds.
+    
+    * read_passwd.c:  Added warning comment that des_read_pw_string 
+    is an exported function on KfM, so we should not change its ABI.
+
+2003-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* str_to_key.c (afs_string_to_key): Move out from under
+	TARGET_OS_MAC conditional.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_INSTALL, or check
+	for #pragma weak.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2002-10-10  Sam Hartman  <hartmans@mit.edu>
+
+	* read_passwd.c : Implement in terms of krb5_prompter_posix
+
+2002-09-26  Tom Yu  <tlyu@mit.edu>
+
+	* cksum.c (des_cbc_cksum): Update API for KfM merge.
+
+	* des.c (des_ecb_encrypt): Update API for KfM merge.
+	(des_3ecb_encrypt): New (emulated) function from KfM.
+
+	* enc_dec.c (des_cbc_encrypt): Update API for KfM merge.
+	(des_3cbc_encrypt): New (emulated) function from KfM.
+
+	* key_sched.c (make_key_sched): New (emulated) function for KfM.
+
+	* new_rnd_key.c (des_generate_random_block) 
+	(des_set_random_generator_seed, des_set_sequence_number):
+	New (emulated) functions from KfM.
+
+	* read_passwd.c (des_rd_pwstr_2prompt): Renamed from
+	des_read_pw_string; also now only returns -1, errno, or 0.
+	(des_read_pw_string): New (emulated) function from KfM.
+	(des_read_password): Update API for KfM merge.
+
+	* str_to_key.c (des_string_to_key): Update call to des_cbc_cksum.
+	(afs_string_to_key): New (emulated) function from KfM.
+	(des_crypt, des_fcrypt, des_set_key): New (emulated) functions
+	from KfM, presumed to be internal but exported by KfM anyway.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* read_passwd.c, unix_time.c: Drop _MSDOS support.
+
+	* quad_cksum.c: Don't explicitly declare pointers FAR any more.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.c, key_sched.c, new_rnd_key.c, des_pcbc_encrypt.c,
+	quad_cksum.c, str_to_key.c: Don't use KRB5_DLLIMP.
+
+2001-07-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* read_passwd.c: Create local variable that takes the "int"
+	bufsize and makes it unsigned for use in malloc, strcmp, etc.
+
+2001-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* des.c (des_ecb_encrypt): Put "static" before "const" for local
+	variable "iv".
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* verify.c (do_decrypt, do_encrypt): Cast argument to
+ 	des_ecb_encrypt to unsigned long *.
+
+2001-05-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* des.c (des_ecb_encrypt): Do not use a variable named "encrypt".
+	* enc_dec.c (des_cbc_encrypt): Likewise.
+	* pcbc_encrypt.c (des_pcbc_encrypt): Likewise.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't use HAS_ANSI_VOLATILE.
+
+2001-04-12  Danilo Almeida  <dalmeida@mit.edu>
+
+	* cksum.c (des_cbc_cksum): Gee, a consistent calling convntion.
+	What a concept!
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* cksum.c (des_cbc_cksum): Arguments IN, KEY, and IV now const.
+	* des.c (des_ecb_encrypt): Change type of arg "schedule" to
+	const des_key_schedule and drop register decl.  Make local
+	variable "iv" const.
+	* enc_dec.c (des_cbc_encrypt): Arguments KEY and IV now const.
+	* pcbc_encrypt.c (des_pcbc_encrypt): Argument SCHEDULE now const.
+	Drop some unnecessary casts.
+	* quad_cksum.c (vaxtohl, vaxtohs): Cast to pointer to const.
+	(des_quad_cksum): Argument IN now points to const.
+	* str_to_key.c (des_string_to_key): String argument now const.
+	Delete local declaration of des_cbc_cksum.  Delete or fix some
+	casts.
+	* t_pcbc.c (main): Pass address of ivec to des_pcbc_encrypt.
+	* util.c (des_cblock_print_file): Delete unnecessary cast.
+
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Delete references to
+	k4_glue.c etc.
+	(clean): Remove t_quad and t_pcbc object files and test programs.
+	* k4_glue.c: Deleted.
+
+2001-04-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_pcbc.c: New file.
+	* Makefile.in (t_pcbc): New target.
+	(check-unix): Depend on and run t_pcbc.
+
+	* pcbc_encrypt.c (des_pcbc_encrypt): Initialize plainl and plainr
+	to keep compiler happy.
+
+	* des.h: Deleted to avoid confusion with the other des.h in the
+	tree.  All files changed to include des_int.h and
+	(the other) des.h instead.
+	* new_rnd_key.c (des_init_random_number_generator): Cast seed data
+	pointer to keep compiler happy.
+	* read_passwd.c (intr_routine, des_read_pw_string): Add
+	prototypes.
+	(des_read_password): Fix call sequence for des_string_to_key.
+	* str_to_key.c (des_string_to_key): Remove static storage in favor
+	of automatic storage.  Fix call sequence to des_key_sched.  Delete
+	no-op while loop.
+	* t_quad.c (main): Fix call sequence for des_quad_cksum.
+	* verify.c (des_string_to_key, des_key_sched, des_ecb_encrypt,
+	des_cbc_encrypt): Removed declarations.
+	(do_encrypt, do_decrypt): Prototype.  Make args point to unsigned
+	char, and return types void.
+	(main): Declare return type.  Make automatic var in_length be
+	unsigned long; discard some casts, but cast it when passing to
+	memcmp.  Remove extra arg passed to des_cbc_cksum.
+	(flip): Delete unused function.
+
+	* quad_cksum.c (des_quad_cksum): Add comments.  Force 32-bit
+	arithmetic just to be careful.
+
+2001-04-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_quad.c: New file.
+	* Makefile.in (t_quad): New target.
+	(check-unix): Depend on and run t_quad.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* cksum.c (des_cbc_cksum): Length is unsigned long.
+
+	* enc_dec.c (des_cbc_encrypt): Length is unsigned long. 
+
+Thu Jun 29 17:11:17 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* random_key.c (des_random_key): Add parentheses around assignment
+ 	used as truth value.
+
+2000-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* read_passwd.c (des_read_pw_string): Make ointrfunc volatile.
+	Fix volatile decl for readin_string.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:21:30 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Thu Nov 12 17:20:25 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Restore des.c
+
+	* des.c: Restore des_ecb_encrypt and make it use the cbc
+	interface.
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* random_key.c, new_rnd_key.c: make the v4 compat random key code
+	use the krb5 crypto interface, instead of the des implementation
+	internals.
+
+Wed Apr 15 18:03:43 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS):
+	(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
+
+Tue Mar  3 08:59:03 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add KRB5_BUILD_PROGRAM
+
+	* Makefile.in (verify): Use CC_LINK and proper Makefile variables
+        for library dependencies.
+
+Wed Feb 18 16:10:05 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trialing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jan 23 22:19:39 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Add AC_PROG_INSTALL since it's need by the install
+		rules.
+
+Tue Nov 18 18:57:07 1997  Tom Yu  <tlyu@mit.edu>
+
+	* quad_cksum.c (des_quad_cksum): Reorder parameters to match the
+	prototype in include/kerberosIV/des.h.
+
+	* pcbc_encrypt.c: Fix up parameters to use a des_cblock* as the
+	ivec to match the prototype in include/kerberosIV/des.h.
+
+	* Makefile.in: Garbage collect some old library build system
+	stuff.
+
+Mon Oct 27 01:14:16 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pcbc_encrypt.c, quad_cksum.c: Punt duplicates of definitions;
+ 	use local des.h only, as that appears to be safe.  Also, replace
+	uses of KRB_INT32 with DES_INT32 to remove temptation to misuse.
+
+	* des.h: Don't include k5-int.h any longer, as des_int.h already
+	gets it.
+
+Tue Oct 14 15:40:46 1997  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in (LIBMAJOR): Bump major version due to possible
+ 	change in type sizes.
+
+Sat Feb 22 18:55:52 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Sat Feb 22 01:07:34 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* read_passwd.c: Don't base definitions on unix being defined.
+
+
+Fri Feb 21 19:11:33 1997  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Depend on -lcrypto
+
+Sun Feb 16 23:29:09 1997  Richard Basch  <basch@lehman.com>
+
+	* pcbc_encrypt.c: Export des_pcbc_encrypt (win16/win32)
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+	* des.c, des.h, key_sched.c, new_rnd_key.c, pcbc_encrypt.c,
+	read_passwd.c, unix_time.c:
+		DLL export various functions (mostly for wintel)
+
+Wed Jan  8 01:31:22 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean-unix, install-unix): Properly install and clean.
+
+Mon Jan  6 07:47:56 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in, Makefile.in: Update to new library building procedure.
+
+Mon Nov 18 20:39:02 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Set shared library version to 1.0. [krb5-libs/201]
+
+Wed Aug  7 12:50:36 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* new_rnd_key.c (des_set_sequence_number): Change cast to
+		krb5_octet to char *. 
+
+	* des.c (des_ecb_encrypt): Add const keyword in cast to make
+		suncc happy.   
+
+Tue May 21 20:42:16 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (check-unix): Use KRB5_RUN_FLAGS
+
+Mon May 13 15:24:18 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (SHLIB_LIBS): For shared library, add dependency on
+		libkrb5.so 
+
+	* configure.in (CRYPTO_SH_VERS): Pass krb5 shared library version
+		to Makefile.
+
+Sat May 11 17:36:26 EDT 1996  Richard Basch  <basch@lehman.com>
+
+	* new_rnd_key.c: Use sizeof(mit_des_cblock) instead of sizeof(key)
+	so that we copy the full DES key instead of only 4 bytes.
+
+Thu May  2 18:44:02 1996  Richard Basch  <basch@lehman.com>
+
+	* random_key.c new_rnd_key.c:
+	Use the rewritten random number routines of libcrypto
+
+Fri Oct  6 22:01:18 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Oct  2 11:07:24 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in (V5_MAKE_SHARED_LIB): Change rule to install
+		version 0.1 of the library. Pass the libcrypto version
+		number to Makefile
+
+	* Makefile.in (CRYPTO_VER): Get the proper libcrypto version number
+
+Fri Sep 29 01:28:11 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* pcbc_encrypt.c: #include autoconf.h instead of osconf.h, because
+		that's the file we really care about.
+
+Mon Sep 25 16:51:10 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * string2key.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Thu Aug 24 18:51:53 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Thu Jul 27 15:23:26 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Check for the sizes of short, int and long.
+	* des.c - Cast mit_des_ecb_encrypt arguments correctly.
+	* pcbc_encrypt.c - Remove inclusion of k5-config.h.
+	* verify.c - Fix compiler grumbles.
+
+
+Fri Jul 7 16:22:13 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS, it's set by configure.
+
+Wed Jun 28 17:09:34 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* read_passwd.c, configure.in: use HAS_ANSI_VOLATILE instead.
+
+Tue Jun 27 23:17:11 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* read_passwd.c: only use volatile if __STDC__ is 1.
+
+Tue Jun 27 15:51:10 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* util.c - Make #endif ansi-compliant.
+	* read_passwd.c - Add signal name parameter to signal handler to
+		conform to prototype.
+
+Mon Jun 26 14:39:18 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* Makefile.in (LDFLAGS): Removed bogus -g.  It breaks on shared
+        links when you're actually calling ld not cc.
+
+Fri Jun 23 18:16:09 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: fix Sam's typo so libdes425.a gets symlinked
+		properly.
+
+Fri Jun 23 12:45:43 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* configure.in: New static library targets.
+
+	* Makefile.in : Add new static library target handling.
+
+Fri Jun 16 17:00:04 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* k4_glue.c - Add this module with the "req_act_vno" symbol definition
+		so that we can use old versions of K4.
+	* configure.in - Check for #pragma weak.
+	* Makefile.in - Add k4_glue.c, Add K4 to include list.
+
+Fri Jun 16 11:15:11 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add install target for shared library.
+
+
+Thu Jun 15 18:00:45 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change "./DONE" target to "DONE" since we have a rule
+		for how to build it.  Also add definitions for shared library
+		building rules.
+	* configure.in - Create symlinks for archive and shared library when
+		we build them.
+
+Wed Jun 14 07:37:26 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (libdes425.a): Don't copy library up a level. Let
+		above Makefile symlink to it.
+
+Fri Jun  9 19:18:59 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Jun  8 23:24:20 1995    <tytso@rsx-11.mit.edu>
+
+	* read_passwd.c (des_read_pw_string): Don't depend on
+		krb5_read_password(); this created a circular dependency
+		in the libraries.  This code is now duplicated in
+		des_read_pw_string.
+
+	* util.c (des_cblock_print_file): Fix -Wall nit.
+
+Mon Jun  5 21:02:37 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* quad_cksum: Convert longs to KRB_INT32 for 64 bit platforms.
+
+Fri May 26 21:43:52 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* util.c: Added new function, des_cblock_print_file(), which is
+		referenced by libkrb4.a.  (Even though it's never used,
+		some OS's demand that all of the references in a
+		shared library have to be resolved.)
+
+Mon May  1 11:29:37 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* read_passwd.c: (des_read_pw_string): Call to krb5_read_password
+		wants a pointer to the length of the buffer.
+
+Fri Apr 28 13:35:25 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* read_passwd.c (des_read_pw_string): Add des_read_pw_string,
+		since it's used by the V4 login.c code.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+
+Wed Mar 22 11:21:38 1995 Keith Vetter (keithv@fusion.com)
+
+	* read_passwd.c: changed return value to krb5_error_code
+        * des.h: same as above
+        * unix_time.c: didn't work on the PC. Copied PC time code from 
+           krb5\os\ustime.c.
+
+Mon Mar 20 21:14:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in, unix_time.c(unix_time_gmt_unixsec): Added function
+		needed for des425 to work with the Cygnus krb.a.
+
+Wed Mar 15 13:44:23 1995 Keith Vetter (keithv@fusion.com)
+
+	* des.h: now includes des_int.h for proper prototypes.
+	* enc_dec.c: cast the types of the input/output buffers in calling
+           the encrypt routine.
+	* key_sched.c: removed prototype of a non-existent routine.
+	* new_rnd_key.c: removed prototypes in the file and instead include
+           header file with the real prototypes.
+	* random_key.c: code, as it was, could never have worked. Adding 
+           prototypes revealed that it was passing KEY with the wrong level
+           of indirection.
+        
+Tue Mar 7 19:57:28 1995 Keith Vetter (keithv@fusion.com)
+
+	* pcbc_enc.c: added casts on the long->char assignments.
+        * str_to_key.c: converted int->long to match types.
+
+
+Wed Mar  8 17:13:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (clean): Dete verify.o on a "make clean".
+
+Wed Mar  1 17:57:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* verify.c: Remove declaration of exit().
+
+Tue Feb 28 01:30:11 1995  John Gilmore  (gnu at toad.com)
+
+	* cksum.c, des.c, des.h, enc_dec.c, pcbc_encrypt.c, quad_cksum.c,
+	read_passwd.c, string2key.c, weak_key.c:  Avoid <krb5/...> includes.
+
+Tue Feb 21 17:42:44 1995 Keith Vetter (keithv@fusion.com)
+
+        * Makefile.in: made to work on the PC
+	* *.c, des.h: added windows INTERFACE keyword
+        * read_passwd.c: renamed a static variable to avoid compiler error
+        * quad_cksum.c: errno extern declaration removed on the PC
+
+Fri Feb  3 17:23:45 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* pcbc_encrypt.c: Add SIZEOF_FOO checks to properly define
+		  KRB_INT32
+
+Wed Jan 18 15:12:18 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* read_passwd.c (des_read_password): Declare global_context and
+		initialize it if necessary.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Thu Nov  3 18:29:10 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* pcbc_encrypt.c: moved from f_pcbc.c in lib/crypto/des, and
+	inlined proper des.h to avoid confusion in names.
+	* Makefile.in: add -I to CFLAGS to get f_tables.h from
+	lib/crypto/des as well.
+
+Wed Oct 26 14:23:36 1994    (tytso@rsx-11)
+
+	* Makefile.in (check): 
+	* verify.c (main): Add verification checks to the test suite.
+
+Wed Oct 19 12:16:13 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR) completely
+
+Mon Oct  3 22:48:14 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR)
+
+Thu Aug  4 03:40:55 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: oops look for install program
+
+	* Makefile.in: make install fixes
+
diff --git a/mechglue/src/lib/des425/ISSUES b/mechglue/src/lib/des425/ISSUES
new file mode 100644
index 000000000..ec5ce0087
--- /dev/null
+++ b/mechglue/src/lib/des425/ISSUES
@@ -0,0 +1,28 @@
+-*- text -*-
+
+* unix_time.c also exists in ../krb4, and they're different; both
+  should probably call into the krb5 support anyways to avoid
+  duplicating code.
+
+* namespace intrusions
+
+* Check include/kerberosIV/des.h and see if all the prototyped
+  functions really are necessary to retain; if not, delete some of
+  these source files.
+
+* Much of this code requires that DES_INT32 be *exactly* 32 bits, and
+  4 bytes.
+
+* Array types are used in function call signatures, which is unclean.
+  It makes trying to add "const" qualifications in the right places
+  really, um, interesting.  But we're probably stuck with them.
+
+* quad_cksum is totally broken.  I have no idea whether the author
+  actually believed it implemented the documented algorithm, but I'm
+  certain it doesn't.  The only question is, is it still reasonably
+  secure, when the plaintext and checksum are visible to an attacker
+  as in the mk_safe message?
+
+* des_read_password and des_read_pw_string are not thread-safe.  Also,
+  they should be calling into the k5crypto library instead of
+  duplicating functionality.
diff --git a/mechglue/src/lib/des425/Makefile.in b/mechglue/src/lib/des425/Makefile.in
new file mode 100644
index 000000000..0257f7029
--- /dev/null
+++ b/mechglue/src/lib/des425/Makefile.in
@@ -0,0 +1,216 @@
+thisconfigdir=.
+myfulldir=lib/des425
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/../crypto/des -I$(srcdir)/../../include/kerberosIV
+
+##DOS##BUILDTOP = ..\..
+##DOS##LIBNAME=$(OUTPRE)des425.lib
+##DOS##OBJFILE=$(OUTPRE)des425.lst
+##DOS##OBJFILEDEP=$(OUTPRE)des425.lst
+##DOS##OBJFILELIST=@$(OUTPRE)des425.lst
+
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP=@KRB5_RUN_ENV@
+
+LIBBASE=des425
+LIBMAJOR=3
+LIBMINOR=0
+RELDIR=des425
+# Depends on libk5crypto and libkrb5
+SHLIB_EXPDEPS = \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(TOPLIBD)/libkrb5$(SHLIBEXT)
+SHLIB_EXPLIBS=-lkrb5 -lcom_err -lk5crypto
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+STOBJLISTS=OBJS.ST
+STLIBOBJS=cksum.o	\
+	des.o		\
+	enc_dec.o	\
+	key_parity.o	\
+	key_sched.o	\
+	new_rnd_key.o	\
+	pcbc_encrypt.o	\
+	quad_cksum.o	\
+	random_key.o	\
+	read_passwd.o  \
+	str_to_key.o	\
+	unix_time.o     \
+	util.o		\
+	weak_key.o
+
+
+OBJS=	$(OUTPRE)cksum.$(OBJEXT)	\
+	$(OUTPRE)des.$(OBJEXT)		\
+	$(OUTPRE)enc_dec.$(OBJEXT)	\
+	$(OUTPRE)key_parity.$(OBJEXT)	\
+	$(OUTPRE)key_sched.$(OBJEXT)	\
+	$(OUTPRE)new_rnd_key.$(OBJEXT)	\
+	$(OUTPRE)pcbc_encrypt.$(OBJEXT)	\
+	$(OUTPRE)quad_cksum.$(OBJEXT)	\
+	$(OUTPRE)random_key.$(OBJEXT)	\
+	$(OUTPRE)read_passwd.$(OBJEXT)	\
+	$(OUTPRE)str_to_key.$(OBJEXT)	\
+	$(OUTPRE)unix_time.$(OBJEXT)	\
+	$(OUTPRE)util.$(OBJEXT)		\
+	$(OUTPRE)weak_key.$(OBJEXT)
+
+SRCS=	$(srcdir)/cksum.c	\
+	$(srcdir)/des.c		\
+	$(srcdir)/enc_dec.c	\
+	$(srcdir)/key_parity.c	\
+	$(srcdir)/key_sched.c	\
+	$(srcdir)/new_rnd_key.c	\
+	$(srcdir)/pcbc_encrypt.c	\
+	$(srcdir)/quad_cksum.c	\
+	$(srcdir)/random_key.c	\
+	$(srcdir)/read_passwd.c \
+	$(srcdir)/str_to_key.c	\
+	$(srcdir)/unix_time.c   \
+	$(srcdir)/util.c	\
+	$(srcdir)/weak_key.c
+
+all-unix:: all-liblinks
+
+##DOS##LIBOBJS = $(OBJS)
+
+shared:
+	mkdir shared
+
+verify: verify.o $(DES425_DEPLIB) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $@ verify.o $(DES425_LIB) $(KRB5_BASE_LIBS)
+
+t_quad: t_quad.o quad_cksum.o $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o $@ t_quad.o quad_cksum.o $(SUPPORT_LIB)
+
+t_pcbc: t_pcbc.o pcbc_encrypt.o key_sched.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $@ t_pcbc.o pcbc_encrypt.o key_sched.o $(KRB5_BASE_LIBS)
+
+check-unix:: verify t_quad t_pcbc
+	$(RUN_SETUP) ./verify -z
+	$(RUN_SETUP) ./verify -m
+	$(RUN_SETUP) ./verify
+	$(RUN_SETUP) ./t_quad
+	$(RUN_SETUP) ./t_pcbc
+
+check-windows::
+
+clean:: 
+	$(RM) $(OUTPRE)verify$(EXEEXT) $(OUTPRE)verify.$(OBJEXT) \
+		$(OUTPRE)t_quad$(EXEEXT) $(OUTPRE)t_quad.$(OBJEXT) \
+		$(OUTPRE)t_pcbc$(EXEEXT) $(OUTPRE)t_pcbc.$(OBJEXT)
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+install-unix:: install-libs
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+cksum.so cksum.po $(OUTPRE)cksum.$(OBJEXT): cksum.c \
+  $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+des.so des.po $(OUTPRE)des.$(OBJEXT): des.c $(srcdir)/../crypto/des/des_int.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/kerberosIV/des.h
+enc_dec.so enc_dec.po $(OUTPRE)enc_dec.$(OBJEXT): enc_dec.c \
+  $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+key_parity.so key_parity.po $(OUTPRE)key_parity.$(OBJEXT): \
+  key_parity.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+key_sched.so key_sched.po $(OUTPRE)key_sched.$(OBJEXT): \
+  key_sched.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+new_rnd_key.so new_rnd_key.po $(OUTPRE)new_rnd_key.$(OBJEXT): \
+  new_rnd_key.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+pcbc_encrypt.so pcbc_encrypt.po $(OUTPRE)pcbc_encrypt.$(OBJEXT): \
+  pcbc_encrypt.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(srcdir)/../crypto/des/f_tables.h
+quad_cksum.so quad_cksum.po $(OUTPRE)quad_cksum.$(OBJEXT): \
+  quad_cksum.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+random_key.so random_key.po $(OUTPRE)random_key.$(OBJEXT): \
+  random_key.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+read_passwd.so read_passwd.po $(OUTPRE)read_passwd.$(OBJEXT): \
+  read_passwd.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+str_to_key.so str_to_key.po $(OUTPRE)str_to_key.$(OBJEXT): \
+  str_to_key.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
+unix_time.so unix_time.po $(OUTPRE)unix_time.$(OBJEXT): \
+  unix_time.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+util.so util.po $(OUTPRE)util.$(OBJEXT): util.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../crypto/des/des_int.h \
+  $(SRCTOP)/include/kerberosIV/des.h
+weak_key.so weak_key.po $(OUTPRE)weak_key.$(OBJEXT): \
+  weak_key.c $(srcdir)/../crypto/des/des_int.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/kerberosIV/des.h
diff --git a/mechglue/src/lib/des425/cksum.c b/mechglue/src/lib/des425/cksum.c
new file mode 100644
index 000000000..33b5322ac
--- /dev/null
+++ b/mechglue/src/lib/des425/cksum.c
@@ -0,0 +1,68 @@
+/*
+ * lib/des425/cksum.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 1990 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * These routines perform encryption and decryption using the DES
+ * private key algorithm, or else a subset of it-- fewer inner loops.
+ * (AUTH_DES_ITER defaults to 16, may be less.)
+ *
+ * Under U.S. law, this software may not be exported outside the US
+ * without license from the U.S. Commerce department.
+ * 
+ * These routines form the library interface to the DES facilities.
+ *
+ *	spm	8/85	MIT project athena
+ */
+
+#include "des_int.h"
+#include "des.h"
+
+/*
+ * This routine performs DES cipher-block-chaining checksum operation,
+ * a.k.a.  Message Authentication Code.  It ALWAYS encrypts from input
+ * to a single 64 bit output MAC checksum.
+ *
+ * The key schedule is passed as an arg, as well as the cleartext or
+ * ciphertext. The cleartext and ciphertext should be in host order.
+ *
+ * NOTE-- the output is ALWAYS 8 bytes long.  If not enough space was
+ * provided, your program will get trashed.
+ *
+ * The input is null padded, at the end (highest addr), to an integral
+ * multiple of eight bytes.
+ */
+
+unsigned long KRB5_CALLCONV
+des_cbc_cksum(in,out,length,key,iv)
+    const des_cblock  *in;		/* >= length bytes of inputtext */
+    des_cblock  *out;			/* >= length bytes of outputtext */
+    register unsigned long length;	/* in bytes */
+    const mit_des_key_schedule key;	/* precomputed key schedule */
+    const des_cblock  *iv;		/* 8 bytes of ivec */
+{
+    return mit_des_cbc_cksum((const krb5_octet *)in, (krb5_octet *)out,
+			     length, key, (krb5_octet *)iv);
+}
diff --git a/mechglue/src/lib/des425/configure.in b/mechglue/src/lib/des425/configure.in
new file mode 100644
index 000000000..6d6c47b37
--- /dev/null
+++ b/mechglue/src/lib/des425/configure.in
@@ -0,0 +1,12 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+dnl
+KRB5_RUN_FLAGS
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+KRB5_BUILD_PROGRAM
+dnl
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/lib/des425/des.c b/mechglue/src/lib/des425/des.c
new file mode 100644
index 000000000..745b4bed5
--- /dev/null
+++ b/mechglue/src/lib/des425/des.c
@@ -0,0 +1,44 @@
+/*
+ * lib/des425/des.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 1990 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "des_int.h"
+#include "des.h"
+#undef mit_des_cbc_encrypt
+
+int KRB5_CALLCONV
+des_ecb_encrypt(clear, cipher, schedule, enc)
+    des_cblock *clear;
+    des_cblock *cipher;
+    const mit_des_key_schedule schedule;
+    int enc;		/* 0 ==> decrypt, else encrypt */
+{
+    static const des_cblock iv;
+
+    return (mit_des_cbc_encrypt((const des_cblock *)clear, cipher,
+				8, schedule, iv, enc));
+}
diff --git a/mechglue/src/lib/des425/enc_dec.c b/mechglue/src/lib/des425/enc_dec.c
new file mode 100644
index 000000000..b75a63e20
--- /dev/null
+++ b/mechglue/src/lib/des425/enc_dec.c
@@ -0,0 +1,47 @@
+/*
+ * lib/des425/enc_dec.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 1990 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+#include "des_int.h"
+#include "des.h"
+#undef mit_des_cbc_encrypt
+
+int
+des_cbc_encrypt(in,out,length,key,iv,enc)
+    des_cblock   *in;	/* >= length bytes of input text */
+    des_cblock  *out;		/* >= length bytes of output text */
+    register unsigned long length;	/* in bytes */
+    const mit_des_key_schedule key;		/* precomputed key schedule */
+    const des_cblock *iv;		/* 8 bytes of ivec */
+    int enc;		/* 0 ==> decrypt, else encrypt */
+{
+	return (mit_des_cbc_encrypt((const des_cblock *) in,
+				    out, length, key,
+				    (const unsigned char *)iv, /* YUCK! */
+				    enc));
+}
diff --git a/mechglue/src/lib/des425/key_parity.c b/mechglue/src/lib/des425/key_parity.c
new file mode 100644
index 000000000..96e13e2f4
--- /dev/null
+++ b/mechglue/src/lib/des425/key_parity.c
@@ -0,0 +1,52 @@
+/*
+ * lib/des425/key_parity.c
+ *
+ * Copyright 1989, 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "des_int.h"
+#include "des.h"
+
+/*
+ * des_fixup_key_parity: Forces odd parity per byte; parity is bits
+ *                       8,16,...64 in des order, implies 0, 8, 16, ...
+ *                       vax order.
+ */
+void
+des_fixup_key_parity(key)
+     register mit_des_cblock key;
+{
+	mit_des_fixup_key_parity(key);
+}
+
+/*
+ * des_check_key_parity: returns true iff key has the correct des parity.
+ */
+int
+des_check_key_parity(key)
+     register mit_des_cblock key;
+{
+	return(mit_des_check_key_parity(key));
+}
+
diff --git a/mechglue/src/lib/des425/key_sched.c b/mechglue/src/lib/des425/key_sched.c
new file mode 100644
index 000000000..70f61ce5e
--- /dev/null
+++ b/mechglue/src/lib/des425/key_sched.c
@@ -0,0 +1,40 @@
+/*
+ * lib/des425/key_sched.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 1990 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+
+#include <stdio.h>
+#include "des_int.h"
+#include "des.h"
+
+int KRB5_CALLCONV
+des_key_sched(k,schedule)
+    des_cblock k;
+    des_key_schedule schedule;
+{
+    return (mit_des_key_sched(k, schedule));
+}
diff --git a/mechglue/src/lib/des425/libdes425.exports b/mechglue/src/lib/des425/libdes425.exports
new file mode 100644
index 000000000..5753a6e96
--- /dev/null
+++ b/mechglue/src/lib/des425/libdes425.exports
@@ -0,0 +1,18 @@
+afs_string_to_key
+des_cbc_cksum
+des_cbc_encrypt
+des_cblock_print_file
+des_check_key_parity
+des_ecb_encrypt
+des_fixup_key_parity
+des_init_random_number_generator
+des_is_weak_key
+des_key_sched
+des_new_random_key
+des_pcbc_encrypt
+des_quad_cksum
+des_random_key
+des_read_password
+des_read_pw_string
+des_string_to_key
+unix_time_gmt_unixsec
diff --git a/mechglue/src/lib/des425/mac_des_glue.c b/mechglue/src/lib/des425/mac_des_glue.c
new file mode 100644
index 000000000..b7f3a6af8
--- /dev/null
+++ b/mechglue/src/lib/des425/mac_des_glue.c
@@ -0,0 +1,104 @@
+#include "des_int.h"
+#include "des.h"
+#undef mit_des3_cbc_encrypt
+
+/* These functions are exported on KfM for ABI compatibility with
+ * older versions of the library.  They have been pulled from the headers
+ * in the hope that someday we can remove them.
+ * 
+ * Do not change the ABIs of any of these functions!
+ */
+
+//int des_read_pw_string(char *, int, char *, int);
+char *des_crypt(const char *, const char *);
+char *des_fcrypt(const char *, const char *, char *);
+
+int make_key_sched(des_cblock *, des_key_schedule);
+int des_set_key(des_cblock *, des_key_schedule);
+
+void des_3cbc_encrypt(des_cblock *, des_cblock *, long, 
+                      des_key_schedule, des_key_schedule, des_key_schedule, 
+                      des_cblock *, int);
+void des_3ecb_encrypt(des_cblock *, des_cblock *, 
+                      des_key_schedule, des_key_schedule, des_key_schedule, 
+                      int);
+
+void des_generate_random_block(des_cblock);
+void des_set_random_generator_seed(des_cblock);
+void des_set_sequence_number(des_cblock);
+
+#pragma mark -
+
+/* Why was this exported on KfM?  Who knows... */
+int des_debug = 0;
+
+char *des_crypt(const char *str, const char *salt)
+{
+    char afs_buf[16];
+
+    return des_fcrypt(str, salt, afs_buf);
+}
+
+
+char *des_fcrypt(const char *str, const char *salt, char *buf)
+{
+    return mit_afs_crypt(str, salt, buf);
+}
+
+
+int make_key_sched(des_cblock *k, des_key_schedule schedule)
+{
+    return mit_des_key_sched((unsigned char *)k, schedule); /* YUCK! */
+}
+
+
+int des_set_key(des_cblock *key, des_key_schedule schedule)
+{
+    return make_key_sched(key, schedule);
+}
+
+
+void des_3cbc_encrypt(des_cblock *in, des_cblock *out, long length,
+                      des_key_schedule ks1, des_key_schedule ks2, des_key_schedule ks3, 
+                      des_cblock *iv, int enc)
+{
+    mit_des3_cbc_encrypt((const des_cblock *)in, out, (unsigned long)length,
+			 ks1, ks2, ks3,
+			 (const unsigned char *)iv, /* YUCK! */
+			 enc);
+}
+
+
+void des_3ecb_encrypt(des_cblock *clear, des_cblock *cipher,
+                      des_key_schedule ks1, des_key_schedule ks2, des_key_schedule ks3, 
+                      int enc)
+{
+    static const des_cblock iv;
+
+    mit_des3_cbc_encrypt((const des_cblock *)clear, cipher, 8, ks1, ks2, ks3, iv, enc);
+}
+
+
+void des_generate_random_block(des_cblock block)
+{
+    krb5_data data;
+
+    data.length = sizeof(des_cblock);
+    data.data = (char *)block;
+    
+    /* This function can return an error, however we must ignore it. */
+    /* The worst that happens is that the resulting block is non-random */
+    krb5_c_random_make_octets(/* XXX */ 0, &data);
+}
+
+
+void des_set_random_generator_seed(des_cblock block)
+{
+    des_init_random_number_generator(block); /* XXX */
+}
+
+
+void des_set_sequence_number(des_cblock block)
+{
+    des_init_random_number_generator(block); /* XXX */
+}
diff --git a/mechglue/src/lib/des425/new_rnd_key.c b/mechglue/src/lib/des425/new_rnd_key.c
new file mode 100644
index 000000000..126ddf500
--- /dev/null
+++ b/mechglue/src/lib/des425/new_rnd_key.c
@@ -0,0 +1,96 @@
+/*
+ * lib/des425/new_rnd_key.c
+ *
+ * Copyright 1988,1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "des_int.h"
+#include "des.h"
+#include "k5-int.h"
+
+void
+des_init_random_number_generator(key)
+    mit_des_cblock key;
+{
+    krb5_data seed;
+
+    seed.length = sizeof(key);
+    seed.data = (char *) key;
+
+    if (krb5_c_random_seed(/* XXX */ 0, &seed))
+	/* XXX */ abort();
+}
+
+/*
+ * des_new_random_key: create a random des key
+ *
+ * Requires: des_set_random_number_generater_seed must be at called least
+ *           once before this routine is called.
+ *
+ * Notes: the returned key has correct parity and is guarenteed not
+ *        to be a weak des key.  Des_generate_random_block is used to
+ *        provide the random bits.
+ */
+int KRB5_CALLCONV
+des_new_random_key(key)
+    mit_des_cblock key;
+{
+    krb5_keyblock keyblock;
+    krb5_error_code kret;
+
+    kret = krb5_c_make_random_key(/* XXX */ 0, ENCTYPE_DES_CBC_CRC, &keyblock);
+    if (kret) return kret;
+    
+    memcpy(key, keyblock.contents, sizeof(mit_des_cblock));
+    krb5_free_keyblock_contents(/* XXX */ 0, &keyblock);
+
+    return 0;
+}
diff --git a/mechglue/src/lib/des425/pcbc_encrypt.c b/mechglue/src/lib/des425/pcbc_encrypt.c
new file mode 100644
index 000000000..70d7b6b84
--- /dev/null
+++ b/mechglue/src/lib/des425/pcbc_encrypt.c
@@ -0,0 +1,218 @@
+/*
+ * lib/des425/pcbc_encrypt.c
+ */
+
+/*
+ * Copyright (c) 1990 Dennis Ferguson.  All rights reserved.
+ *
+ * Commercial use is permitted only if products which are derived from
+ * or include this software are made available for purchase and/or use
+ * in Canada.  Otherwise, redistribution and use in source and binary
+ * forms are permitted.
+ */
+
+/*
+ * des_pcbc_encrypt.c - encrypt a string of characters in error propagation mode
+ */
+
+#include "des_int.h"
+#include "des.h"
+#include <f_tables.h>
+
+/*
+ * des_pcbc_encrypt - {en,de}crypt a stream in PCBC mode
+ */
+int KRB5_CALLCONV
+des_pcbc_encrypt(in, out, length, schedule, ivec, enc)
+	des_cblock *in;
+	des_cblock *out;
+	long length;
+	const des_key_schedule schedule;
+	des_cblock *ivec;
+	int enc;
+{
+	register unsigned DES_INT32 left, right;
+	const unsigned DES_INT32 *kp;
+	const unsigned char *ip;
+	unsigned char *op;
+
+	/*
+	 * Copy the key pointer, just once
+	 */
+	kp = (const unsigned DES_INT32 *)schedule;
+
+	/*
+	 * Deal with encryption and decryption separately.
+	 */
+	if (enc) {
+		/* Initialization isn't really needed here, but gcc
+		   complains because it doesn't understand that the
+		   only case where these can be used uninitialized is
+		   to compute values that'll in turn be ignored
+		   because we won't go around the loop again.  */
+		register unsigned DES_INT32 plainl = 42;
+		register unsigned DES_INT32 plainr = 17;
+
+		/*
+		 * Initialize left and right with the contents of the initial
+		 * vector.
+		 */
+		ip = *ivec;
+		GET_HALF_BLOCK(left, ip);
+		GET_HALF_BLOCK(right, ip);
+
+		/*
+		 * Suitably initialized, now work the length down 8 bytes
+		 * at a time.
+		 */
+		ip = *in;
+		op = *out;
+		while (length > 0) {
+			/*
+			 * Get block of input.  If the length is
+			 * greater than 8 this is straight
+			 * forward.  Otherwise we have to fart around.
+			 */
+			if (length > 8) {
+				GET_HALF_BLOCK(plainl, ip);
+				GET_HALF_BLOCK(plainr, ip);
+				left ^= plainl;
+				right ^= plainr;
+				length -= 8;
+			} else {
+				/*
+				 * Oh, shoot.  We need to pad the
+				 * end with zeroes.  Work backwards
+				 * to do this.  We know this is the
+				 * last block, though, so we don't have
+				 * to save the plain text.
+				 */
+				ip += (int) length;
+				switch(length) {
+				case 8:
+					right ^= *(--ip) & 0xff;
+				case 7:
+					right ^= (*(--ip) & 0xff) << 8;
+				case 6:
+					right ^= (*(--ip) & 0xff) << 16;
+				case 5:
+					right ^= (*(--ip) & 0xff) << 24;
+				case 4:
+					left ^= *(--ip) & 0xff;
+				case 3:
+					left ^= (*(--ip) & 0xff) << 8;
+				case 2:
+					left ^= (*(--ip) & 0xff) << 16;
+				case 1:
+					left ^= (*(--ip) & 0xff) << 24;
+					break;
+				}
+				length = 0;
+			}
+
+			/*
+			 * Encrypt what we have
+			 */
+			DES_DO_ENCRYPT(left, right, kp);
+
+			/*
+			 * Copy the results out
+			 */
+			PUT_HALF_BLOCK(left, op);
+			PUT_HALF_BLOCK(right, op);
+
+			/*
+			 * Xor with the old plain text
+			 */
+			left ^= plainl;
+			right ^= plainr;
+		}
+	} else {
+		/*
+		 * Decrypting is harder than encrypting because of
+		 * the necessity of remembering a lot more things.
+		 * Should think about this a little more...
+		 */
+		unsigned DES_INT32 ocipherl, ocipherr;
+		unsigned DES_INT32 cipherl, cipherr;
+
+		if (length <= 0)
+			return 0;
+
+		/*
+		 * Prime the old cipher with ivec.
+		 */
+		ip = *ivec;
+		GET_HALF_BLOCK(ocipherl, ip);
+		GET_HALF_BLOCK(ocipherr, ip);
+
+		/*
+		 * Now do this in earnest until we run out of length.
+		 */
+		ip = *in;
+		op = *out;
+		for (;;) {		/* check done inside loop */
+			/*
+			 * Read a block from the input into left and
+			 * right.  Save this cipher block for later.
+			 */
+			GET_HALF_BLOCK(left, ip);
+			GET_HALF_BLOCK(right, ip);
+			cipherl = left;
+			cipherr = right;
+
+			/*
+			 * Decrypt this.
+			 */
+			DES_DO_DECRYPT(left, right, kp);
+
+			/*
+			 * Xor with the old cipher to get plain
+			 * text.  Output 8 or less bytes of this.
+			 */
+			left ^= ocipherl;
+			right ^= ocipherr;
+			if (length > 8) {
+				length -= 8;
+				PUT_HALF_BLOCK(left, op);
+				PUT_HALF_BLOCK(right, op);
+				/*
+				 * Save current cipher block here
+				 */
+				ocipherl = cipherl ^ left;
+				ocipherr = cipherr ^ right;
+			} else {
+				/*
+				 * Trouble here.  Start at end of output,
+				 * work backwards.
+				 */
+				op += (int) length;
+				switch(length) {
+				case 8:
+					*(--op) = (unsigned char) (right & 0xff);
+				case 7:
+					*(--op) = (unsigned char) ((right >> 8) & 0xff);
+				case 6:
+					*(--op) = (unsigned char) ((right >> 16) & 0xff);
+				case 5:
+					*(--op) = (unsigned char) ((right >> 24) & 0xff);
+				case 4:
+					*(--op) = (unsigned char) (left & 0xff);
+				case 3:
+					*(--op) = (unsigned char) ((left >> 8) & 0xff);
+				case 2:
+					*(--op) = (unsigned char) ((left >> 16) & 0xff);
+				case 1:
+					*(--op) = (unsigned char) ((left >> 24) & 0xff);
+					break;
+				}
+				break;		/* we're done */
+			}
+		}
+	}
+
+	/*
+	 * Done, return nothing.
+	 */
+	return 0;
+}
diff --git a/mechglue/src/lib/des425/quad_cksum.c b/mechglue/src/lib/des425/quad_cksum.c
new file mode 100644
index 000000000..2a7b78cfd
--- /dev/null
+++ b/mechglue/src/lib/des425/quad_cksum.c
@@ -0,0 +1,200 @@
+/*
+ * lib/des425/quad_cksum.c
+ *
+ * Copyright 1985, 1986, 1987, 1988,1990 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * This routine does not implement:
+ *
+ *
+ * Quadratic Congruential Manipulation Dectection Code
+ *
+ * ref: "Message Authentication"
+ *		R.R. Jueneman, S. M. Matyas, C.H. Meyer
+ *		IEEE Communications Magazine,
+ *		Sept 1985 Vol 23 No 9 p 29-40
+ *
+ * This routine, part of the Athena DES library built for the Kerberos
+ * authentication system, calculates a manipulation detection code for
+ * a message.  It is a much faster alternative to the DES-checksum
+ * method. No guarantees are offered for its security.
+ *
+ * Implementation for 4.2bsd
+ * by S.P. Miller	Project Athena/MIT
+ */
+
+/*
+ * Algorithm (per paper):
+ *		define:
+ *		message to be composed of n m-bit blocks X1,...,Xn
+ *		optional secret seed S in block X1
+ *		MDC in block Xn+1
+ *		prime modulus N
+ *		accumulator Z
+ *		initial (secret) value of accumulator C
+ *		N, C, and S are known at both ends
+ *		C and , optionally, S, are hidden from the end users
+ *		then
+ *			(read array references as subscripts over time)
+ *			Z[0] = c;
+ *			for i = 1...n
+ *				Z[i] = (Z[i+1] + X[i])**2 modulo N
+ *			X[n+1] = Z[n] = MDC
+ *
+ *		Then pick
+ *			N = 2**31 -1
+ *			m = 16
+ *			iterate 4 times over plaintext, also use Zn
+ *			from iteration j as seed for iteration j+1,
+ *			total MDC is then a 128 bit array of the four
+ *			Zn;
+ *
+ *			return the last Zn and optionally, all
+ *			four as output args.
+ *
+ * Modifications:
+ *	To inhibit brute force searches of the seed space, this
+ *	implementation is modified to have
+ *	Z	= 64 bit accumulator
+ *	C	= 64 bit C seed
+ *	N	= 2**63 - 1
+ *  S	= S seed is not implemented here
+ *	arithmetic is not quite real double integer precision, since we
+ *	cant get at the carry or high order results from multiply,
+ *	but nontheless is 64 bit arithmetic.
+ */
+/*
+ * This code purports to implement the above algorithm, but fails.
+ *
+ * First of all, there was an implicit mod 2**32 being done on the
+ * machines where this was developed because of their word sizes, and
+ * for compabitility this has to be done on machines with 64-bit
+ * words, so we make it explicit.
+ *
+ * Second, in the squaring operation, I really doubt the carry-over
+ * from the low 31-bit half of the accumulator is being done right,
+ * and using a modulus of 0x7fffffff on the low half of the
+ * accumulator seems completely wrong.  And I challenge anyone to
+ * explain where the number 83653421 comes from.
+ *
+ * --Ken Raeburn  2001-04-06
+ */
+
+
+/* System include files */
+#include <stdio.h>
+#include <errno.h>
+
+#include "des_int.h"
+#include "des.h"
+
+/* Definitions for byte swapping */
+
+/* vax byte order is LSB first. This is not performance critical, and
+   is far more readable this way. */
+#define four_bytes_vax_to_nets(x) ((((((x[3]<<8)|x[2])<<8)|x[1])<<8)|x[0])
+#define vaxtohl(x) four_bytes_vax_to_nets(((const unsigned char *)(x)))
+#define two_bytes_vax_to_nets(x) ((x[1]<<8)|x[0])
+#define vaxtohs(x) two_bytes_vax_to_nets(((const unsigned char *)(x)))
+
+/* Externals */
+extern int des_debug;
+
+/*** Routines ***************************************************** */
+
+unsigned long KRB5_CALLCONV
+des_quad_cksum(in,out,length,out_count,c_seed)
+    const unsigned char *in;	/* input block */
+    unsigned DES_INT32 *out;	/* optional longer output */
+    long length;			/* original length in bytes */
+    int out_count;			/* number of iterations */
+    mit_des_cblock *c_seed;		/* secret seed, 8 bytes */
+{
+
+    /*
+     * this routine both returns the low order of the final (last in
+     * time) 32bits of the checksum, and if "out" is not a null
+     * pointer, a longer version, up to entire 32 bytes of the
+     * checksum is written unto the address pointed to.
+     */
+
+    register unsigned DES_INT32 z;
+    register unsigned DES_INT32 z2;
+    register unsigned DES_INT32 x;
+    register unsigned DES_INT32 x2;
+    const unsigned char *p;
+    register DES_INT32 len;
+    register int i;
+
+    /* use all 8 bytes of seed */
+
+    z = vaxtohl(c_seed);
+    z2 = vaxtohl((const char *)c_seed+4);
+    if (out == NULL)
+	out_count = 1;		/* default */
+
+    /* This is repeated n times!! */
+    for (i = 1; i <=4 && i<= out_count; i++) {
+	len = length;
+	p = in;
+	while (len) {
+	    /*
+	     * X = Z + Input ... sort of.  Carry out from low half
+	     * isn't done, so we're using all 32 bits of x now.
+	     */
+	    if (len > 1) {
+		x = (z + vaxtohs(p));
+		p += 2;
+		len -= 2;
+	    }
+	    else {
+		x = (z + *(const unsigned char *)p++);
+		len = 0;
+	    }
+	    x2 = z2;
+	    /*
+	     * I think this is supposed to be a squaring operation.
+	     * What it really is, I haven't figured out yet.
+	     *
+	     * Explicit mod 2**32 is for backwards compatibility.  Why
+	     * mod 0x7fffffff and not 0x80000000 on the low half of
+	     * the (supposed) accumulator?  And where does the number
+	     * 83653421 come from??
+	     */
+	    z  = (((x * x) + (x2 * x2)) & 0xffffffff) % 0x7fffffff;
+	    z2 = ((x * (x2+83653421)) & 0xffffffff) % 0x7fffffff; /* modulo */
+#ifdef DEBUG
+	    if (des_debug & 8)
+		printf("%d %d\n",z,z2);
+#endif
+	}
+
+	if (out != NULL) {
+	    *out++ = z;
+	    *out++ = z2;
+	}
+    }
+    /* return final z value as 32 bit version of checksum */
+    return z;
+}
diff --git a/mechglue/src/lib/des425/random_key.c b/mechglue/src/lib/des425/random_key.c
new file mode 100644
index 000000000..f367fc817
--- /dev/null
+++ b/mechglue/src/lib/des425/random_key.c
@@ -0,0 +1,74 @@
+/*
+ * lib/des425/random_key.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "des_int.h"
+#include "des.h"
+
+/* random_key */
+int
+des_random_key(key)
+    mit_des_cblock *key;
+{
+    krb5_keyblock	keyblock;
+    krb5_error_code	kret;
+
+    if ((kret = krb5_c_make_random_key(/* XXX */ 0, ENCTYPE_DES_CBC_CRC,
+				      &keyblock)))
+	return(kret);
+
+    memcpy(key, keyblock.contents, sizeof(mit_des_cblock));
+
+    return(0);
+}
+
diff --git a/mechglue/src/lib/des425/read_passwd.c b/mechglue/src/lib/des425/read_passwd.c
new file mode 100644
index 000000000..e1b4c713c
--- /dev/null
+++ b/mechglue/src/lib/des425/read_passwd.c
@@ -0,0 +1,129 @@
+/*
+ * lib/des425/read_passwd.c
+ *
+ * Copyright 1985,1986,1987,1988,1991 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This routine prints the supplied string to standard
+ * output as a prompt, and reads a password string without
+ * echoing.
+ */
+
+#if !defined(_WIN32)
+
+#include "des_int.h"
+#include "des.h"
+#include <stdio.h>
+#include <errno.h>
+#include <krb5.h>
+/* This is re-declared here because des.h might not declare it. */
+int KRB5_CALLCONV des_read_pw_string(char *, int, char *, int);
+static int des_rd_pwstr_2prompt(char *, int, char *, char *);
+
+
+/*** Routines ****************************************************** */
+static int
+des_rd_pwstr_2prompt(return_pwd, bufsize_in, prompt, prompt2)
+    char *return_pwd;
+    int bufsize_in;
+    char *prompt;
+    char *prompt2;
+{
+    krb5_data reply_data;      
+    krb5_prompt k5prompt;
+    krb5_error_code retval;
+    reply_data.length = bufsize_in;
+    reply_data.data = return_pwd;
+    k5prompt.prompt = prompt;
+    k5prompt.hidden = 1;
+    k5prompt.reply = &reply_data;
+    retval =  krb5_prompter_posix(NULL,
+				  NULL, NULL, NULL, 1, &k5prompt);
+
+    if ((retval==0) && prompt2) {
+	krb5_data verify_data;
+	verify_data.data = malloc(bufsize_in);
+	verify_data.length = bufsize_in;
+	k5prompt.prompt = prompt2;
+	k5prompt.reply = &verify_data;
+	if (!verify_data.data)
+	    return ENOMEM;
+	retval = krb5_prompter_posix(NULL,
+				     NULL,NULL, NULL, 1, &k5prompt);
+	if (retval) {
+	    free(verify_data.data);
+	} else {
+	    /* compare */
+	    if (strncmp(return_pwd, (char *)verify_data.data, bufsize_in)) {
+		retval = KRB5_LIBOS_BADPWDMATCH;
+		free(verify_data.data);
+	    }
+	}
+    }
+    return retval;
+}
+
+
+int KRB5_CALLCONV
+des_read_password(k,prompt,verify)
+    mit_des_cblock *k;
+    char *prompt;
+    int	verify;
+{
+    int ok;
+    char key_string[BUFSIZ];
+
+    ok = des_read_pw_string(key_string, sizeof(key_string), prompt, verify);
+    if (ok == 0)
+	des_string_to_key(key_string, *k);
+
+    memset(key_string, 0, sizeof (key_string));
+    return ok;
+}
+
+/* Note: this function is exported on KfM.  Do not change its ABI. */
+int KRB5_CALLCONV
+des_read_pw_string(s, max, prompt, verify)
+    char *s;
+    int max;
+    char *prompt;
+    int	verify;
+{
+    int ok;
+    char prompt2[BUFSIZ];
+
+    if (verify) {
+	strcpy(prompt2, "Verifying, please re-enter ");
+	strncat(prompt2, prompt, sizeof(prompt2)-(strlen(prompt2)+1));
+	prompt2[sizeof(prompt2)-1] = '\0';
+    }
+    ok = des_rd_pwstr_2prompt(s, max, prompt, verify ? prompt2 : 0);
+    return ok;
+}
+
+#else /* !unix */
+/*
+ * These are all just dummy functions to make the rest of the library happy...
+ */
+#endif /* _WINDOWS */
diff --git a/mechglue/src/lib/des425/str_to_key.c b/mechglue/src/lib/des425/str_to_key.c
new file mode 100644
index 000000000..4ddcaed4a
--- /dev/null
+++ b/mechglue/src/lib/des425/str_to_key.c
@@ -0,0 +1,168 @@
+/*
+ * lib/des425/str_to_key.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 1989,1990 by the Massachusetts Institute
+ * of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * These routines perform encryption and decryption using the DES
+ * private key algorithm, or else a subset of it-- fewer inner loops.
+ * (AUTH_DES_ITER defaults to 16, may be less.)
+ *
+ * Under U.S. law, this software may not be exported outside the US
+ * without license from the U.S. Commerce department.
+ *
+ * The key schedule is passed as an arg, as well as the cleartext or
+ * ciphertext.  The cleartext and ciphertext should be in host order.
+ *
+ * These routines form the library interface to the DES facilities.
+ *
+ *	spm	8/85	MIT project athena
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include "des_int.h"
+#include "des.h"
+
+extern int mit_des_debug;
+
+/*
+ * Convert an arbitrary length string to a DES key.
+ */
+
+/*
+ * For krb5, a change was made to this algorithm: When each key is
+ * generated, after fixing parity, a check for weak and semi-weak keys
+ * is done.  If the key is weak or semi-weak, we XOR the last byte
+ * with 0xF0.  (In the case of the intermediate key, the weakness is
+ * probably irrelevant, but there it is.)  The odds that this will
+ * generate a different key for a random input string are pretty low,
+ * but non-zero.  So we need this different function for krb4 to use.
+ */
+int KRB5_CALLCONV
+des_string_to_key(str,key)
+    const char *str;
+    register mit_des_cblock key;
+{
+    const char *in_str;
+    register unsigned temp;
+    register int j;
+    unsigned long i, length;
+    unsigned char *k_p;
+    int forward;
+    register char *p_char;
+    char k_char[64];
+    mit_des_key_schedule key_sked;
+
+    in_str = str;
+    forward = 1;
+    p_char = k_char;
+    length = strlen(str);
+
+    /* init key array for bits */
+    memset(k_char, 0,sizeof(k_char));
+
+#ifdef DEBUG
+    if (mit_des_debug)
+	fprintf(stdout,
+		"\n\ninput str length = %ld  string = %s\nstring = 0x ",
+		length,str);
+#endif
+
+    /* get next 8 bytes, strip parity, xor */
+    for (i = 1; i <= length; i++) {
+	/* get next input key byte */
+	temp = (unsigned int) *str++;
+#ifdef DEBUG
+	if (mit_des_debug)
+	    fprintf(stdout,"%02x ",temp & 0xff);
+#endif
+	/* loop through bits within byte, ignore parity */
+	for (j = 0; j <= 6; j++) {
+	    if (forward)
+		*p_char++ ^= (int) temp & 01;
+	    else
+		*--p_char ^= (int) temp & 01;
+	    temp = temp >> 1;
+	}
+
+	/* check and flip direction */
+	if ((i%8) == 0)
+	    forward = !forward;
+    }
+
+    /* now stuff into the key des_cblock, and force odd parity */
+    p_char = k_char;
+    k_p = (unsigned char *) key;
+
+    for (i = 0; i <= 7; i++) {
+	temp = 0;
+	for (j = 0; j <= 6; j++)
+	    temp |= *p_char++ << (1+j);
+	*k_p++ = (unsigned char) temp;
+    }
+
+    /* fix key parity */
+    des_fixup_key_parity(key);
+
+    /* Now one-way encrypt it with the folded key */
+    (void) des_key_sched(key, key_sked);
+    (void) des_cbc_cksum((const des_cblock *)in_str, (des_cblock *)key,
+			 length, key_sked, (const des_cblock *)key);
+    /* erase key_sked */
+    memset(key_sked, 0,sizeof(key_sked));
+
+    /* now fix up key parity again */
+    des_fixup_key_parity(key);
+
+#ifdef DEBUG
+    if (mit_des_debug)
+	fprintf(stdout,
+		"\nResulting string_to_key = 0x%x 0x%x\n",
+		*((unsigned long *) key),
+		*((unsigned long *) key+1));
+#endif /* DEBUG */
+    return 0;			/* Really should be returning void, */
+				/* but the original spec was for it to */
+				/* return an int, and ANSI compilers */
+				/* can do dumb things sometimes */
+}
+
+void afs_string_to_key(char *str, char *cell, des_cblock key)
+{
+    krb5_data str_data;
+    krb5_data cell_data;
+    krb5_keyblock keyblock;
+
+    str_data.data = str;
+    str_data.length = strlen(str);
+    cell_data.data = cell;
+    cell_data.length = strlen(cell);
+    keyblock.enctype = ENCTYPE_DES_CBC_CRC;
+    keyblock.length = sizeof(des_cblock);
+    keyblock.contents = key;
+
+    mit_afs_string_to_key(&keyblock, &str_data, &cell_data);
+}
diff --git a/mechglue/src/lib/des425/string2key.c b/mechglue/src/lib/des425/string2key.c
new file mode 100644
index 000000000..8756787a1
--- /dev/null
+++ b/mechglue/src/lib/des425/string2key.c
@@ -0,0 +1,174 @@
+/* THIS FILE DOES NOT GET COMPILED.  AUDIT BEFORE USE.  */
+/*
+ * lib/des425/string2key.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Wrapper for the V4 libdes for use with kerberos V5.
+ */
+
+
+#include "des.h"
+#include "des_int.h"
+
+#ifdef DEBUG
+#include <stdio.h>
+extern int des_debug;
+#endif
+
+/*
+	converts the string pointed to by "data" into an encryption key
+	of type "enctype".  *keyblock is filled in with the key info;
+	in particular, keyblock->contents is to be set to allocated storage.
+	It is the responsibility of the caller to release this storage
+	when the generated key no longer needed.
+
+	The routine may use "princ" to seed or alter the conversion
+	algorithm.
+
+	If the particular function called does not know how to make a
+	key of type "enctype", an error may be returned.
+
+	returns: errors
+ */
+
+krb5_error_code mit_des_string_to_key (enctype, keyblock, data, princ)
+    const krb5_enctype enctype;
+    krb5_keyblock * keyblock;
+    const krb5_data * data;
+    krb5_const_principal princ;
+{
+    char copystr[512];
+
+    register char *str = copystr;
+    register krb5_octet *key;
+
+    register unsigned temp,i;
+    register int j;
+    register long length;
+    unsigned char *k_p;
+    int forward;
+    register char *p_char;
+    char k_char[64];
+    mit_des_key_schedule key_sked;
+
+#define min(A, B) ((A) < (B) ? (A): (B))
+
+    if ( enctype != ENCTYPE_DES )
+	return (KRB5_PROG_ENCTYPE_NOSUPP);
+
+    if ( !(keyblock->contents = (krb5_octet *)malloc(sizeof(mit_des_cblock))) )
+	return(ENOMEM);
+
+#define cleanup() {memset(keyblock->contents, 0, sizeof(mit_des_cblock));\
+		       krb5_xfree(keyblock->contents);}
+
+    keyblock->enctype = ENCTYPE_DES;
+    keyblock->length = sizeof(mit_des_cblock);
+    key = keyblock->contents;
+
+    memset(copystr, 0, sizeof(copystr));
+    j = min(data->length, 511);
+    (void) strncpy(copystr, data->data, j);
+    if ( princ != 0 )
+	for (i=0; princ[i] != 0 && j < 511; i++) {
+	    (void) strncpy(copystr+j, princ[i]->data, 
+			   min(princ[i]->length, 511-j));
+	    j += min(princ[i]->length, 511-j);
+	}
+
+    /* convert copystr to des key */
+    forward = 1;
+    p_char = k_char;
+    length = strlen(str);
+
+    /* init key array for bits */
+    memset(k_char,0,sizeof(k_char));
+
+#ifdef DEBUG
+    if (mit_des_debug)
+	fprintf(stdout,
+		"\n\ninput str length = %d  string = %s\nstring = 0x ",
+		length,str);
+#endif
+
+    /* get next 8 bytes, strip parity, xor */
+    for (i = 1; i <= length; i++) {
+	/* get next input key byte */
+	temp = (unsigned int) *str++;
+#ifdef DEBUG
+	if (mit_des_debug)
+	    fprintf(stdout,"%02x ",temp & 0xff);
+#endif
+	/* loop through bits within byte, ignore parity */
+	for (j = 0; j <= 6; j++) {
+	    if (forward)
+		*p_char++ ^= (int) temp & 01;
+	    else
+		*--p_char ^= (int) temp & 01;
+	    temp = temp >> 1;
+	}
+
+	/* check and flip direction */
+	if ((i%8) == 0)
+	    forward = !forward;
+    }
+
+    /* now stuff into the key mit_des_cblock, and force odd parity */
+    p_char = k_char;
+    k_p = (unsigned char *) key;
+
+    for (i = 0; i <= 7; i++) {
+	temp = 0;
+	for (j = 0; j <= 6; j++)
+	    temp |= *p_char++ << (1+j);
+	*k_p++ = (unsigned char) temp;
+    }
+
+    /* fix key parity */
+    mit_des_fixup_key_parity(key);
+
+    /* Now one-way encrypt it with the folded key */
+    (void) mit_des_key_sched(key, key_sked);
+    (void) mit_des_cbc_cksum((krb5_octet *)copystr, key, length, key_sked, key);
+    /* erase key_sked */
+    memset((char *)key_sked, 0, sizeof(key_sked));
+
+    /* now fix up key parity again */
+    mit_des_fixup_key_parity(key);
+
+#ifdef DEBUG
+    if (mit_des_debug)
+	fprintf(stdout,
+		"\nResulting string_to_key = 0x%x 0x%x\n",
+		*((unsigned long *) key),
+		*((unsigned long *) key+1));
+#endif
+    
+    return 0;
+}
+
+
+
+
diff --git a/mechglue/src/lib/des425/t_pcbc.c b/mechglue/src/lib/des425/t_pcbc.c
new file mode 100644
index 000000000..2932148b7
--- /dev/null
+++ b/mechglue/src/lib/des425/t_pcbc.c
@@ -0,0 +1,123 @@
+/*
+ * lib/des425/t_quad.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include "des_int.h"
+#include "des.h"
+
+char *progname;
+int des_debug;
+
+/* These test values were constructed by experimentation, because I
+   couldn't be bothered to look up the spec for the encryption mode
+   and see if any test vector is defined.  But really, the thing we
+   need to test is that the operation we use doesn't changed.  Like
+   with quad_cksum, compatibility is more important than strict
+   adherence to the spec, if we have to choose.  In any case, if you
+   have a useful test vector, send it in....  */
+struct {
+    unsigned char text[32];
+    des_cblock out[4];
+} tests[] = {
+    {
+	"Now is the time for all ",
+	{
+	    {  0x7f, 0x81, 0x65, 0x41, 0x21, 0xdb, 0xd4, 0xcf, },
+	    {  0xf8, 0xaa, 0x09, 0x90, 0xeb, 0xc7, 0x60, 0x2b, },
+	    {  0x45, 0x3e, 0x4e, 0x65, 0x83, 0x6c, 0xf1, 0x98, },
+	    {  0x4c, 0xfc, 0x69, 0x72, 0x23, 0xdb, 0x48, 0x78, }
+	}
+    }, {
+	"7654321 Now is the time for ",
+	{
+	    {  0xcc, 0xd1, 0x73, 0xff, 0xab, 0x20, 0x39, 0xf4, },
+	    {  0x6d, 0xec, 0xb4, 0x70, 0xa0, 0xe5, 0x6b, 0x15, },
+	    {  0xae, 0xa6, 0xbf, 0x61, 0xed, 0x7d, 0x9c, 0x9f, },
+	    {  0xf7, 0x17, 0x46, 0x3b, 0x8a, 0xb3, 0xcc, 0x88, }
+	}
+    }, {
+	"hi",
+        { {  0x76, 0x61, 0x0e, 0x8b, 0x23, 0xa4, 0x5f, 0x34, } }
+    },
+};
+
+/* 0x0123456789abcdef */
+unsigned char default_key[8] = {
+    0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef
+};
+des_cblock ivec = {
+    0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10
+};
+
+int
+main(argc,argv)
+    int argc;
+    char *argv[];
+{
+    int i;
+    int fail=0;
+    des_cblock out[32/8];
+    des_cblock out2[32/8];
+    des_key_schedule sked;
+
+    progname=argv[0];		/* salt away invoking program */
+
+    /* use known input and key */
+
+    for (i = 0; i < 3; i++) {
+	int wrong = 0, j, jmax;
+	des_key_sched (default_key, sked);
+	/* This could lose on alignment... */
+	des_pcbc_encrypt ((des_cblock *)&tests[i].text, out,
+			  strlen(tests[i].text) + 1, sked, &ivec, 1);
+	printf ("pcbc_encrypt(\"%s\") = {", tests[i].text);
+	jmax = (strlen (tests[i].text) + 8) & ~7U;
+	for (j = 0; j < jmax; j++) {
+	    if (j % 8 == 0)
+		printf ("\n\t");
+	    printf (" 0x%02x,", out[j/8][j%8]);
+	    if (out[j/8][j%8] != tests[i].out[j/8][j%8])
+		wrong = 1;
+	}
+	printf ("\n}\n");
+
+	/* reverse it */
+	des_pcbc_encrypt (out, out2, jmax, sked, &ivec, 0);
+	if (strcmp ((char *)out2, tests[i].text)) {
+	    printf ("decrypt failed\n");
+	    wrong = 1;
+	} else
+	    printf ("decrypt worked\n");
+
+	if (wrong) {
+	    printf ("wrong result!\n");
+	    fail = 1;
+	}
+    }
+    return fail;
+}
diff --git a/mechglue/src/lib/des425/t_quad.c b/mechglue/src/lib/des425/t_quad.c
new file mode 100644
index 000000000..b9299fd20
--- /dev/null
+++ b/mechglue/src/lib/des425/t_quad.c
@@ -0,0 +1,101 @@
+/*
+ * lib/des425/t_quad.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include "des_int.h"
+#include "des.h"
+
+extern unsigned long quad_cksum();
+char *progname;
+int des_debug;
+unsigned DES_INT32 out[8];
+struct {
+    unsigned char text[64];
+    unsigned DES_INT32 out[8];
+} tests[] = {
+    {
+	"Now is the time for all ",
+	{
+	    0x6c6240c5, 0x77db9b1c, 0x7991d316, 0x4e688989,
+	    0x27a0ae6a, 0x13be2da4, 0x4a2fdfc6, 0x7dfc494c,
+	}
+    }, {
+	"7654321 Now is the time for ",
+	{
+	    0x36839db5, 0x4d7be717, 0x15b0f5b6, 0x2304ff9c,
+	    0x75472d26, 0x6a5f833c, 0x7399a4ee, 0x1170fdfb,
+	}
+    }, {
+	{2,0,0,0, 1,0,0,0},
+	{
+	    0x7c81f205, 0x63d38e38, 0x314ece44, 0x05d3a4f8,
+	    0x6e10db76, 0x3eda7685, 0x2e841332, 0x1bdc7fd3,
+	}
+    },
+};
+
+/* 0x0123456789abcdef */
+unsigned char default_key[8] = {
+    0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef
+};
+
+int
+main(argc,argv)
+    int argc;
+    char *argv[];
+{
+    int i;
+    int fail=0;
+
+    progname=argv[0];		/* salt away invoking program */
+
+    /* use known input and key */
+
+    for (i = 0; i < 3; i++) {
+	int wrong = 0, j;
+	des_quad_cksum (tests[i].text, out, 64L, 4,
+			(mit_des_cblock *) &default_key);
+	if (tests[i].text[0] == 2)
+	    printf ("quad_cksum(<binary blob 1>) = {");
+	else
+	    printf ("quad_cksum(\"%s\"...zero fill...) = {", tests[i].text);
+	for (j = 0; j < 8; j++) {
+	    if (j == 0 || j == 4)
+		printf ("\n\t");
+	    printf (" 0x%lx,", (unsigned long) out[j]);
+	    if (out[j] != tests[i].out[j])
+		wrong = 1;
+	}
+	printf ("\n}\n");
+	if (wrong) {
+	    printf ("wrong result!\n");
+	    fail = 1;
+	}
+    }
+    return fail;
+}
diff --git a/mechglue/src/lib/des425/unix_time.c b/mechglue/src/lib/des425/unix_time.c
new file mode 100644
index 000000000..53ce03b68
--- /dev/null
+++ b/mechglue/src/lib/des425/unix_time.c
@@ -0,0 +1,46 @@
+/*
+ * unix_time.c
+ * 
+ * Glue code for pasting Kerberos into the Unix environment.
+ *
+ * Originally written by John Gilmore, Cygnus Support, May '94.
+ * Public Domain.
+ *
+ * Required for use by the Cygnus krb.a.
+ */
+
+
+#include "k5-int.h"
+
+#if !defined(_WIN32)
+#include <sys/time.h>
+
+krb5_ui_4
+unix_time_gmt_unixsec (usecptr)
+     krb5_ui_4	*usecptr;
+{
+	struct timeval	now;
+
+	(void) gettimeofday (&now, (struct timezone *)0);
+	if (usecptr)
+		*usecptr = now.tv_usec;
+	return now.tv_sec;
+}
+
+#endif /* !_WIN32 */
+
+#ifdef _WIN32
+#include <time.h>
+
+krb5_ui_4
+unix_time_gmt_unixsec (usecptr)
+    krb5_ui_4 *usecptr;
+{
+    time_t gmt;
+
+    time(&gmt);
+    if (usecptr)
+	*usecptr = gmt;
+    return gmt;
+}
+#endif /* _WIN32 */
diff --git a/mechglue/src/lib/des425/util.c b/mechglue/src/lib/des425/util.c
new file mode 100644
index 000000000..2c5ef9216
--- /dev/null
+++ b/mechglue/src/lib/des425/util.c
@@ -0,0 +1,33 @@
+/*
+ * lib/des425/util.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Miscellaneous debug printing utilities
+ */
+
+#include <stdio.h>
+
+/* Application include files */
+#include "k5-int.h"
+#include "des_int.h"
+#include "des.h"
+
+void des_cblock_print_file(x, fp)
+    des_cblock *x;
+    FILE *fp;
+{
+    unsigned char *y = *x;
+    register int i = 0;
+    fprintf(fp," 0x { ");
+
+    while (i++ < 8) {
+	fprintf(fp,"%x",*y++);
+	if (i < 8)
+	    fprintf(fp,", ");
+    }
+    fprintf(fp," }");
+}
diff --git a/mechglue/src/lib/des425/verify.c b/mechglue/src/lib/des425/verify.c
new file mode 100644
index 000000000..653730a2f
--- /dev/null
+++ b/mechglue/src/lib/des425/verify.c
@@ -0,0 +1,317 @@
+/*
+ * lib/des425/verify.c
+ *
+ * Copyright 1988,1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Program to test the correctness of the DES library
+ * implementation.
+ *
+ * exit returns	 0 ==> success
+ * 		-1 ==> error
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include "des_int.h"
+#include "des.h"
+
+char *progname;
+int nflag = 2;
+int vflag;
+int mflag;
+int zflag;
+int pid;
+int des_debug;
+des_key_schedule KS;
+unsigned char cipher_text[64];
+unsigned char clear_text[64] = "Now is the time for all " ;
+unsigned char clear_text2[64] = "7654321 Now is the time for ";
+unsigned char clear_text3[64] = {2,0,0,0, 1,0,0,0};
+unsigned char output[64];
+unsigned char zero_text[8] = {0x0,0,0,0,0,0,0,0};
+unsigned char msb_text[8] = {0x0,0,0,0, 0,0,0,0x40}; /* to ANSI MSB */
+unsigned char *input;
+
+/* 0x0123456789abcdef */
+unsigned char default_key[8] = {
+    0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef
+};
+unsigned char key2[8] = { 0x08,0x19,0x2a,0x3b,0x4c,0x5d,0x6e,0x7f };
+unsigned char key3[8] = { 0x80,1,1,1,1,1,1,1 };
+des_cblock s_key;
+unsigned char default_ivec[8] = {
+    0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef
+};
+unsigned char *ivec;
+unsigned char zero_key[8] = {1,1,1,1,1,1,1,1}; /* just parity bits */
+int i,j;
+
+unsigned char cipher1[8] = {
+    0x25,0xdd,0xac,0x3e,0x96,0x17,0x64,0x67
+};
+unsigned char cipher2[8] = {
+    0x3f,0xa4,0x0e,0x8a,0x98,0x4d,0x48,0x15
+};
+unsigned char cipher3[64] = {
+    0xe5,0xc7,0xcd,0xde,0x87,0x2b,0xf2,0x7c,
+    0x43,0xe9,0x34,0x00,0x8c,0x38,0x9c,0x0f,
+    0x68,0x37,0x88,0x49,0x9a,0x7c,0x05,0xf6
+};
+unsigned char checksum[8] = {
+    0x58,0xd2,0xe7,0x7e,0x86,0x06,0x27,0x33
+};
+
+unsigned char zresult[8] = {
+    0x8c, 0xa6, 0x4d, 0xe9, 0xc1, 0xb1, 0x23, 0xa7
+};
+
+unsigned char mresult[8] = {
+    0xa3, 0x80, 0xe0, 0x2a, 0x6b, 0xe5, 0x46, 0x96
+};
+
+   
+/*
+ * Can also add :
+ * plaintext = 0, key = 0, cipher = 0x8ca64de9c1b123a7 (or is it a 1?)
+ */
+
+void do_encrypt (unsigned char *, unsigned char *);
+void do_decrypt (unsigned char *, unsigned char *);
+
+int
+main(argc,argv)
+    int argc;
+    char *argv[];
+{
+    /* Local Declarations */
+    unsigned long in_length;
+
+    progname=argv[0];		/* salt away invoking program */
+
+    while (--argc > 0 && (*++argv)[0] == '-')
+	for (i=1; argv[0][i] != '\0'; i++) {
+	    switch (argv[0][i]) {
+
+		/* debug flag */
+	    case 'd':
+		des_debug=3;
+		continue;
+
+	    case 'z':
+		zflag = 1;
+		continue;
+
+	    case 'm':
+		mflag = 1;
+		continue;
+
+	    default:
+		printf("%s: illegal flag \"%c\" ",
+		       progname,argv[0][i]);
+		exit(1);
+	    }
+	};
+
+    if (argc) {
+	fprintf(stderr, "Usage: %s [-dmz]\n", progname);
+	exit(1);
+    }
+
+    /* use known input and key */
+
+    /* ECB zero text zero key */
+    if (zflag) {
+	input = zero_text;
+	des_key_sched(zero_key,KS);
+	printf("plaintext = key = 0, cipher = 0x8ca64de9c1b123a7\n");
+	do_encrypt(input,cipher_text);
+	printf("\tcipher  = (low to high bytes)\n\t\t");
+	for (j = 0; j<=7; j++)
+	    printf("%02x ",cipher_text[j]);
+	printf("\n");
+	do_decrypt(output,cipher_text);
+	if ( memcmp((char *)cipher_text, (char *)zresult, 8) ) {
+	    printf("verify: error in zero key test\n");
+	    exit(-1);
+	}
+	exit(0);
+    }
+
+    if (mflag) {
+	input = msb_text;
+	des_key_sched(key3,KS);
+	printf("plaintext = 0x00 00 00 00 00 00 00 40, ");
+	printf("key = 0, cipher = 0x??\n");
+	do_encrypt(input,cipher_text);
+	printf("\tcipher  = (low to high bytes)\n\t\t");
+	for (j = 0; j<=7; j++) {
+	    printf("%02x ",cipher_text[j]);
+	}
+	printf("\n");
+	do_decrypt(output,cipher_text);
+	if ( memcmp((char *)cipher_text, (char *)mresult, 8) ) {
+	    printf("verify: error in msb test\n");
+	    exit(-1);
+	}
+	exit(0);
+    }
+
+    /* ECB mode Davies and Price */
+    {
+	input = zero_text;
+	des_key_sched(key2,KS);
+	printf("Examples per FIPS publication 81, keys ivs and cipher\n");
+	printf("in hex.  These are the correct answers, see below for\n");
+	printf("the actual answers.\n\n");
+	printf("Examples per Davies and Price.\n\n");
+	printf("EXAMPLE ECB\tkey = 08192a3b4c5d6e7f\n");
+	printf("\tclear = 0\n");
+	printf("\tcipher = 25 dd ac 3e 96 17 64 67\n");
+	printf("ACTUAL ECB\n");
+	printf("\tclear \"%s\"\n", input);
+	do_encrypt(input,cipher_text);
+	printf("\tcipher  = (low to high bytes)\n\t\t");
+	for (j = 0; j<=7; j++)
+	    printf("%02x ",cipher_text[j]);
+	printf("\n\n");
+	do_decrypt(output,cipher_text);
+	if ( memcmp((char *)cipher_text, (char *)cipher1, 8) ) {
+	    printf("verify: error in ECB encryption\n");
+	    exit(-1);
+	}
+	else 
+	    printf("verify: ECB encription is correct\n\n");
+    }
+
+    /* ECB mode */
+    {
+	des_key_sched(default_key,KS);
+	input = clear_text;
+	ivec = default_ivec;
+	printf("EXAMPLE ECB\tkey = 0123456789abcdef\n");
+	printf("\tclear = \"Now is the time for all \"\n");
+	printf("\tcipher = 3f a4 0e 8a 98 4d 48 15 ...\n");
+	printf("ACTUAL ECB\n\tclear \"%s\"",input);
+	do_encrypt(input,cipher_text);
+	printf("\n\tcipher	= (low to high bytes)\n\t\t");
+	for (j = 0; j<=7; j++) {
+	    printf("%02x ",cipher_text[j]);
+	}
+	printf("\n\n");
+	do_decrypt(output,cipher_text);
+	if ( memcmp((char *)cipher_text, (char *)cipher2, 8) ) {
+	    printf("verify: error in ECB encryption\n");
+	    exit(-1);
+	}
+	else 
+	    printf("verify: ECB encription is correct\n\n");
+    }
+
+    /* CBC mode */
+    printf("EXAMPLE CBC\tkey = 0123456789abcdef");
+    printf("\tiv = 1234567890abcdef\n");
+    printf("\tclear = \"Now is the time for all \"\n");
+    printf("\tcipher =\te5 c7 cd de 87 2b f2 7c\n");
+    printf("\t\t\t43 e9 34 00 8c 38 9c 0f\n");
+    printf("\t\t\t68 37 88 49 9a 7c 05 f6\n");
+
+    printf("ACTUAL CBC\n\tclear \"%s\"\n",input);
+    in_length = strlen((char *) input);
+    des_cbc_encrypt(input,cipher_text, in_length,KS,ivec,1);
+    printf("\tciphertext = (low to high bytes)\n");
+    for (i = 0; i <= 7; i++) {
+	printf("\t\t");
+	for (j = 0; j <= 7; j++) {
+	    printf("%02x ",cipher_text[i*8+j]);
+	}
+	printf("\n");
+    }
+    des_cbc_encrypt(cipher_text,clear_text,in_length,KS,ivec,0);
+    printf("\tdecrypted clear_text = \"%s\"\n",clear_text);
+
+    if ( memcmp(cipher_text, cipher3, (size_t) in_length) ) {
+	printf("verify: error in CBC encryption\n");
+	exit(-1);
+    }
+    else 
+	printf("verify: CBC encription is correct\n\n");
+
+    printf("EXAMPLE CBC checksum");
+    printf("\tkey =  0123456789abcdef\tiv =  1234567890abcdef\n");
+    printf("\tclear =\t\t\"7654321 Now is the time for \"\n");
+    printf("\tchecksum\t58 d2 e7 7e 86 06 27 33, ");
+    printf("or some part thereof\n");
+    input = clear_text2;
+    des_cbc_cksum(input,cipher_text,(long) strlen((char *) input),KS,ivec);
+    printf("ACTUAL CBC checksum\n");
+    printf("\t\tencrypted cksum = (low to high bytes)\n\t\t");
+    for (j = 0; j<=7; j++)
+	printf("%02x ",cipher_text[j]);
+    printf("\n\n");
+    if ( memcmp((char *)cipher_text, (char *)checksum, 8) ) {
+	printf("verify: error in CBC cheksum\n");
+	exit(-1);
+    }
+    else 
+	printf("verify: CBC checksum is correct\n\n");
+    exit(0);
+}
+
+void
+do_encrypt(in,out)
+    unsigned char *in;
+    unsigned char *out;
+{
+    for (i =1; i<=nflag; i++) {
+	des_ecb_encrypt((unsigned long *) in, (unsigned long *)out, KS, 1);
+	if (des_debug) {
+	    printf("\nclear %s\n",in);
+	    for (j = 0; j<=7; j++)
+		printf("%02X ",in[j] & 0xff);
+	    printf("\tcipher ");
+	    for (j = 0; j<=7; j++)
+		printf("%02X ",out[j] & 0xff);
+	}
+    }
+}
+
+void
+do_decrypt(in,out)
+    unsigned char *out;
+    unsigned char *in;
+    /* try to invert it */
+{
+    for (i =1; i<=nflag; i++) {
+	des_ecb_encrypt((unsigned long *) out, (unsigned long *)in,KS,0);
+	if (des_debug) {
+	    printf("clear %s\n",in);
+	    for (j = 0; j<=7; j++)
+		printf("%02X ",in[j] & 0xff);
+	    printf("\tcipher ");
+	    for (j = 0; j<=7; j++)
+		printf("%02X ",out[j] & 0xff);
+	}
+    }
+}
diff --git a/mechglue/src/lib/des425/weak_key.c b/mechglue/src/lib/des425/weak_key.c
new file mode 100644
index 000000000..f4ef6fbc5
--- /dev/null
+++ b/mechglue/src/lib/des425/weak_key.c
@@ -0,0 +1,41 @@
+/*
+ * lib/des425/weak_key.c
+ *
+ * Copyright 1989,1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "des_int.h"
+#include "des.h"
+
+/*
+ * mit_des_is_weak_key: returns true iff key is a [semi-]weak des key.
+ *
+ * Requires: key has correct odd parity.
+ */
+int
+des_is_weak_key(key)
+     mit_des_cblock key;
+{
+	return (mit_des_is_weak_key(key));
+}
diff --git a/mechglue/src/lib/glue4.c b/mechglue/src/lib/glue4.c
new file mode 100644
index 000000000..bf9bbd8a0
--- /dev/null
+++ b/mechglue/src/lib/glue4.c
@@ -0,0 +1,19 @@
+#include "krb5.h"
+
+krb5_data string_list[3] = {
+{11, "FOO.MIT.EDU"},
+{6, "jtkohl"},
+};
+
+krb5_data *princ[] = {&string_list[0], &string_list[1], 0};
+
+krb5_data string_list2[3] = {
+{11, "FOO.MIT.EDU"},
+{4, "rcmd"},
+{13, "lycus.mit.edu"},
+};
+
+krb5_data *princ2[] = {&string_list2[0], &string_list2[1], &string_list2[2], 0};
+				   
+krb5_last_req_entry lrentries[] = { {32000, 1}, {0, 3}, {10, 2} };
+krb5_last_req_entry *lrfoo1[] = {&lrentries[0], &lrentries[1], &lrentries[2], 0};
diff --git a/mechglue/src/lib/gssapi/.Sanitize b/mechglue/src/lib/gssapi/.Sanitize
new file mode 100644
index 000000000..ca985a84c
--- /dev/null
+++ b/mechglue/src/lib/gssapi/.Sanitize
@@ -0,0 +1,42 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+Makefile.original
+README_SAMPLE_APP
+configure
+configure.in
+generic
+krb5
+mechglue
+sample
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/gssapi/ChangeLog b/mechglue/src/lib/gssapi/ChangeLog
new file mode 100644
index 000000000..61ec844c9
--- /dev/null
+++ b/mechglue/src/lib/gssapi/ChangeLog
@@ -0,0 +1,416 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-04-07  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Use awk to work around Makefile quoting problems.
+
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBINITFUNC, LIBFINIFUNC): Define.
+
+	* gss_libinit.c (gssint_lib_init, gssint_lib_fini)
+	[SHOW_INITFINI_FUNCS]: Print tracing messages.
+
+2005-02-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for xom.h.  Set include_xom to a C include
+	directive or comment, and substitute it in the Makefiles.
+
+2005-01-17  Jeffrey Altman <jaltman@mit.edu>
+
+        * gss_libinit.c: implement cleanup of mutexes, static vars, etc for Windows
+
+2004-07-29  Sam Hartman  <hartmans@mit.edu>
+
+	* libgssapi_krb5.exports: Add lucid context routines and gss_krb5_set_allowable_enctypes
+
+2004-07-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): Use _DEPLIB variables.
+	(SHLIB_EXPLIBS): Add $(SUPPORT_LIB).
+
+	* gss_libinit.c (gssint_lib_init): Initialize new keytab-name
+	mutex, and register two new key values.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (OBJFILELIST, OBJFILEDEP) [DOS]: Depend on locally
+	built objects too.
+	(OBJFILE, LIBOBJS) [DOS]: Define.
+	($(BUILDTOP)/include/gssapi/gssapi.h generic/gssapi.h
+	krb5/gssapi_err_krb5.h generic/gssapi_err_generic.h
+	krb5/gssapi_krb5.h) [DOS]: Disable dependencies on Windows.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Don't set.
+
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Add $(LIBS).
+
+2004-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (krb5/gssapi_krb5.h): Depend on recursion rule.
+
+2004-06-08  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: If stdint.h exists, include in gssapi_krb5.h
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss_libinit.c (gssint_lib_init): Initialize error tables here.
+	(gssint_initialize_library): Don't do it directly here.  Make sure
+	gssint_lib_init has been called, and return the status.
+	(gssint_lib_fini): Remove error tables here.
+	(gssint_cleanup_library): Function deleted.
+	(initialized): Variable deleted.
+
+2004-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* libgssapi_krb5.exports: Remove et_*, generic_*, gssint_*,
+	initialize_*, kg_* symbols.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss_libinit.c: Include k5-platform.h.
+	(gssint_lib_init, gssint_lib_fini): New init/fini functions.
+	Create and clean up the mutex in kg_vdb.
+	(gssint_initialize_library): Verify the library initializer has
+	run successfully.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libgssapi_krb5.exports: New file.
+
+2003-07-17  Tom Yu  <tlyu@mit.edu>
+
+	* gss_libinit.c (gssint_initialize_library): Don't call
+	kg_release_defcred(); it doesn't exist any more.
+
+2003-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(BUILDTOP)/include/gssapi/gssapi.h,
+	generic/gssapi.h, generic/gssapi_err_generic.h,
+	krb5/gssapi_err_krb5.h): Comment out old rules and dependencies;
+	depend on all-recurse and supply a no-op rule.
+
+2003-03-07  Alexandra Ellwood  <lxs@mit.edu>
+
+    * gss_libinit.c: Changed USE_HARDCODED_FALLBACK_ERROR_TABLES macro 
+    to !USE_BUNDLE_ERROR_STRINGS so Darwin based builds get com_err
+    style error tables.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+
+    * gss_libinit.c: Removed Mac header goober.
+    Fixed USE_HARDCODED_FALLBACK_ERROR_TABLES macro used by KfM.
+
+    * gss_libinit.h: do not use the same multiple include
+    protection macro as krb5_libinit.h.  Changed to GSSAPI_LIBINIT_H.
+
+2003-02-11  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in ($(BUILDTOP)/include/gssapi/gssapi.h): Add
+	dependencies and cause to invoke a differently-named target in
+	subdirectory.
+	(generic/gssapi.h): Make separate rule.
+	(generic/gssapi_err_generic.h, krb5/gssapi_err_krb5.h): New rules
+	to generate these files in subdirectories as needed.
+
+2003-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in ($(BUILDTOP)/include/gssapi/gssapi.h generic/gssapi.h): 
+	Don't depend on all-recurse, as it causes spurious rebuilds of
+	these header files.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_ARCHIVE,
+	AC_PROG_ARCHIVE_ADD, AC_PROG_INSTALL, AC_PROG_RANLIB.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.original: Deleted.
+
+2002-09-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(BUILDTOP)/include/gssapi/gssapi.h,
+	generic/gssapi.h): Depend on all-recurse.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SUBDIROBJLISTS): New variable.
+
+2002-07-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* gss_libinit.c (gssint_cleanup_library): Remove variable set but
+	not used.
+
+2002-07-14  Alexandra Ellwood <lxs@mit.edu>
+
+	* gss_libinit.c: Conditionalized error table loading for Mac OS X.
+	Error tables should always be loaded on other platforms.
+
+	* gss_libinit.c: updated for Mac OS X header paths and added
+	include of gssapiP_krb5.h to get function prototypes.
+
+	[pullups from 1-2-2-branch]
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Use $(srcdir) not $(subdir).
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* gss_libinit.c: Include gssapiP_krb5.h for kg_release_defcred()
+ 	prototype.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_TYPE_SIZE_T instead of AC_SIZE_T.
+
+2000-06-03  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in(LIBMINOR): Bump library version.
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* configure.in: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+Tue Feb 22 10:23:19 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean-unix): Add clean-libobjs.
+
+2000-01-24  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (STLIBOBJS): Properly add gss_libinit.o to permit
+	compiling.
+
+	* configure.in: Add libobj to Makefile frags.
+
+	* gss_libinit.c: Add terminating newline.  Use 0 and 1 instead of
+	false and true.
+
+Fri Jan 21 22:47:00 2000  Miro Jurisic  <meeroh@mit.edu>
+
+	* Makefile.in: added gss_libinit.[co]
+	* gss_libinit.[ch]: new files, contain library initialization
+		and cleanup code
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+Mon May 10 15:21:50 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1999-02-19  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (DLL_FILE_DEF): Tell the Makefile template that we
+		are building object files for the GSSAPI DLL.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+	* configure.in: Use K5_AC_OUTPUT instead of K5_OUTPUT_FILES.
+
+Wed Apr 15 18:04:18 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): 
+	(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
+
+Wed Feb 18 16:10:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Thu Feb 12 16:17:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented out AC_OUTPUT to force autoreconf to
+	rebuild the configure script.
+
+Mon Feb  2 16:47:05 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* configure.in: Create the makefiles for all of the subdirectories
+		and move all of the configure.in tests from the
+		subdirectories into this configure.in.
+	
+Wed Jan 21 19:12:42 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (LIBMINOR): Bump minor version due to internal
+	structure change.
+
+Sat Feb 22 01:21:06 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): s/so/$(SHLIBEXT)
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+Tue Jan 14 20:07:50 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Mon Nov 18 20:39:41 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Set shared library version to 1.0. [krb5-libs/201]
+
+Tue Jul 23 22:50:22 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Remove mechglue from the list of
+		Macintosh subdirectories.
+
+Thu Jun  6 00:04:38 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Don't pass $(LIBCMD) on the command
+		line.  It's set in the windows.in prologue for all Makefiles anyway.
+
+Mon May 20 11:00:45 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* Makefile.in (libgssapi.$(STEXT)): deal with new improved
+		libupdate
+
+Mon May  6 21:33:25 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean-unix): Remove libgssapi_krb5.stamp.
+
+Wed Apr 17 21:48:15 1996  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in, configure.in: Nothing in mechglue is used anymore,
+ 	for now.
+
+Tue Feb 27 22:10:48 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (all-windows, clean-windows): Add mechglue to the
+		list of directories which are recursively handled for
+		Windows.
+
+Wed Feb  7 00:23:18 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Fri Jan 26 01:55:14 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Fix path to library from lib
+
+Wed Jan 24 21:28:04 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Remove LinkFileDir line for libgssapi as the
+        shared lib stuff does that.
+
+Tue Jan 23 12:12:49 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (SHLIB_LIBS): Add lines for shared library building
+		depending on libkrb5, crypto, and com_err.
+
+Tue Jan 23 04:06:36 1996    <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Add support for building the gssapi library as a
+		shared library.
+
+Tue Jan 23 03:32:25 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Add the mechglue directory as a subdir
+
+	* Makefile.in (libgssapi_krb5.a): Include the object files in the
+		mechglue directory as well.
+
+Fri Oct  6 22:02:48 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:52:41 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 13 11:11:38 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: Put back in all:: all-$(WHAT) rule--PC needs it.
+
+Thu Jun 15 18:02:16 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit "all" rule at head of file, it causes
+		platform specific target to get done first.
+	* configure.in - Create symlinks for archive and shared library when
+		we build them.  Also, put explicit "all" rule at end of file
+		so that we do the subdirectory rules first.
+
+Fri Jun  9 18:55:01 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Mon May 22 10:04:26 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in	- Add SUBDIRS for install target.
+
+Tue May  2 21:42:32 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: nuke spurious whitespace in blank line
+
+Wed Apr 26 14:39:18 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: passed wrong macro on the recursive makes.
+
+Tue Mar 21 19:08:51 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed the name of the library the PC
+           builds, and added xxx-mac targets to mimic xxx-unix.
+
+Wed Mar 15 20:23:17 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: cleaned up for the PC
+
+Mon Feb 20 21:38:20 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work on the PC
+
+Fri Nov 18 00:17:29 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: move WITH_CCOPTS.
+
+Wed Oct 19 12:16:44 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR) completely
+
+Mon Oct  3 22:48:54 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR)
+
+Thu Aug  4 03:41:21 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: look for install program
+
+	* Makefile.in: make install fixes
+
diff --git a/mechglue/src/lib/gssapi/Makefile.in b/mechglue/src/lib/gssapi/Makefile.in
new file mode 100644
index 000000000..2f7ed757a
--- /dev/null
+++ b/mechglue/src/lib/gssapi/Makefile.in
@@ -0,0 +1,135 @@
+thisconfigdir=.
+myfulldir=lib/gssapi
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCAL_SUBDIRS= generic mechglue krb5
+
+##DOSLIBNAME=$(OUTPRE)gssapi.lib
+##DOSOBJFILELIST=@$(OUTPRE)generic.lst @$(OUTPRE)krb5.lst @$(OUTPRE)gssapi.lst
+##DOSOBJFILEDEP=$(OUTPRE)generic.lst $(OUTPRE)krb5.lst $(OUTPRE)gssapi.lst
+
+##DOSOBJFILE=$(OUTPRE)gssapi.lst
+##DOSLIBOBJS=$(OBJS)
+
+##DOS##DLL_EXP_TYPE=GSS
+
+LOCALINCLUDES = -Igeneric -I$(srcdir)/generic -Ikrb5 -I$(srcdir)/krb5 -I$(srcdir)/mechglue
+STLIBOBJS=\
+	gss_libinit.o
+
+OBJS=\
+	$(OUTPRE)gss_libinit.$(OBJEXT)
+
+SRCS=\
+	$(srcdir)/gss_libinit.c
+
+LIBBASE=gssapi_krb5
+LIBMAJOR=2
+LIBMINOR=2
+LIBINITFUNC=gssint_lib_init
+LIBFINIFUNC=gssint_lib_fini
+STOBJLISTS=OBJS.ST generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST
+SUBDIROBJLISTS=generic/OBJS.ST mechglue/OBJS.ST krb5/OBJS.ST
+SHLIB_EXPDEPS=\
+	$(KRB5_DEPLIB) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB) $(COM_ERR_DEPLIB)
+SHLIB_EXPLIBS=-lkrb5 -lk5crypto -lcom_err $(SUPPORT_LIB) $(LIBS)
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+RELDIR=gssapi
+
+all-unix:: all-liblinks
+
+install-unix:: install-libs
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+clean-windows::
+	$(RM) gssapi.lib gssapi.bak
+
+all-windows::
+	cd generic
+	@echo Making in gssapi\generic
+	$(MAKE) -$(MFLAGS)
+	cd ..\krb5
+	@echo Making in gssapi\krb5
+	$(MAKE) -$(MFLAGS)
+#	cd ..\mechglue
+#	@echo Making in gssapi\mechglue
+#	$(MAKE) -$(MFLAGS)
+	cd ..
+
+clean-windows::
+	cd generic
+	@echo Making clean in gssapi\generic
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\krb5
+	@echo Making clean in gssapi\krb5
+	$(MAKE) -$(MFLAGS) clean
+#	cd ..\mechglue
+#	@echo Making clean in gssapi\mechglue
+#	$(MAKE) -$(MFLAGS) clean
+	cd ..
+	@echo Making clean in gssapi
+
+# These rules are an attempt to handle several different problems:
+#
+# Certain files in subdirectories must be made current by the
+# recursion step before we can build files in this directory that
+# depend on them.  Existing but out-of-date versions must not be used.
+#
+# In a parallel make, nothing should be built more than once.  This
+# effect can be exaggerated for testing by sticking "sleep 5" into the
+# rules for generating the files in subdirectories.  For example, in
+# between testing for a directory and creating it -- do you then get
+# mkdir complaining that the directory exists?  Adding the sleep
+# command may also exaggerate the build-with-outdated-headers problem,
+# by causing the timestamp on the newly generated header to be several
+# seconds newer than object files built with its old version, even on
+# fast machines where the UNIX filesystem's one-second granularity
+# would mask the problem.
+#
+# We must not cause these files to always be considered newly updated
+# when it comes time to build the object files in this directory.
+# Otherwise, we wind up recompiling some files every time we run make.
+
+# This set of rules fails the parallel make case; it can build
+# gssapi-include and all-recurse at the same time, and both will
+# create include/gssapi and gssapi.h.
+#$(BUILDTOP)/include/gssapi/gssapi.h: generic/gssapi.h
+#	(cd generic && $(MAKE) gssapi-include)
+#generic/gssapi.h: generic/gssapi.hin
+#	(cd generic && $(MAKE) gssapi.h)
+#generic/gssapi_err_generic.h: generic/gssapi_err_generic.et
+#	(cd generic && $(MAKE) gssapi_err_generic.h)
+#krb5/gssapi_err_krb5.h: krb5/gssapi_err_krb5.et
+#	(cd krb5 && $(MAKE) gssapi_err_krb5.h)
+
+# This version, without the no-op command to run, reportedly caused
+# repeated rebuilds in certain cases.  With the no-op command, it
+# appears to be properly serializing the subdir processing and local
+# compiles... so far.
+##DOS##!if 0
+$(BUILDTOP)/include/gssapi/gssapi.h generic/gssapi.h krb5/gssapi_err_krb5.h generic/gssapi_err_generic.h krb5/gssapi_krb5.h: all-recurse
+	: $@ updated by recursion rule
+##DOS##!endif
+
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+gss_libinit.so gss_libinit.po $(OUTPRE)gss_libinit.$(OBJEXT): \
+  gss_libinit.c generic/gssapi_err_generic.h $(COM_ERR_DEPS) \
+  krb5/gssapi_err_krb5.h $(srcdir)/krb5/gssapiP_krb5.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/generic/gssapiP_generic.h $(srcdir)/generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h krb5/gssapi_krb5.h \
+  gss_libinit.h generic/gssapi.h
diff --git a/mechglue/src/lib/gssapi/README_SAMPLE_APP b/mechglue/src/lib/gssapi/README_SAMPLE_APP
new file mode 100644
index 000000000..c26bb09ad
--- /dev/null
+++ b/mechglue/src/lib/gssapi/README_SAMPLE_APP
@@ -0,0 +1,4 @@
+A sample GSS-API client and server application can be found in the
+directory ./appl/gss-sample in this distribution.  Read the file
+./appl/gss-sample/README for information on how it works and how to
+build it.
diff --git a/mechglue/src/lib/gssapi/configure.in b/mechglue/src/lib/gssapi/configure.in
new file mode 100644
index 000000000..8c9786843
--- /dev/null
+++ b/mechglue/src/lib/gssapi/configure.in
@@ -0,0 +1,19 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+AC_PROG_AWK
+AC_CHECK_HEADERS(stdlib.h sys/types.h limits.h memory.h)
+AC_TYPE_SIZE_T
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_HEADER(stdint.h,[
+	include_stdint='awk '\''END{printf("%cinclude <stdint.h>\n", 35);}'\'' < /dev/null'],
+	include_stdint='echo "/* no stdint.h */"')
+AC_SUBST(include_stdint)
+AC_CHECK_HEADER(xom.h,[
+	include_xom='awk '\''END{printf("%cinclude <xom.h>\n", 35);}'\'' < /dev/null'], [
+	include_xom='echo "/* no xom.h */"'])
+AC_SUBST(include_xom)
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+V5_AC_OUTPUT_MAKEFILE(. generic krb5 mechglue)
diff --git a/mechglue/src/lib/gssapi/generic/.Sanitize b/mechglue/src/lib/gssapi/generic/.Sanitize
new file mode 100644
index 000000000..86e5a9d20
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/.Sanitize
@@ -0,0 +1,53 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+Makefile.original
+configure
+configure.in
+disp_com_err_status.c
+disp_major_status.c
+gssapi.h
+gssapiP_generic.h
+gssapi_err_generic.et
+gssapi_generic.h
+util_buffer.c
+util_canonhost.c
+util_dup.c
+util_localhost.c
+util_oid.c
+util_ordering.c
+util_set.c
+util_token.c
+util_validate.c
+utl_nohash_validate.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/gssapi/generic/ChangeLog b/mechglue/src/lib/gssapi/generic/ChangeLog
new file mode 100644
index 000000000..901410c17
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/ChangeLog
@@ -0,0 +1,907 @@
+2005-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* rel_buffer.c (generic_gss_release_buffer): Free buffer even if
+	length is zero.  This avoids memory leaks in some cases.
+
+2005-04-07  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (gssapi.h): Use awk hack to work around quoting
+	problem.
+
+2005-02-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (gssapi.h): Change SIZEOF symbols to start with GSS_
+	when extracting from autoconf.h.  Don't look for HAVE_ or USE_
+	symbols.  Add ${include_xom} to the prologue.
+	(include_xom): New variable.
+	* gssapi.hin: Always include stddef.h unconditionally.  Don't
+	conditionally include xom.h here.
+	(GSS_SIZEOF_INT, GSS_SIZEOF_LONG, GSS_SIZEOF_SHORT): Don't
+	define, except on Windows.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi.hin: Don't test macintosh or __MWERKS__.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* util_validate.c (g_save): Call gssint_initialize_library.
+
+2004-06-08  Sam Hartman  <hartmans@mit.edu>
+
+	* util_validate.c utl_nohash_validate.c gssapiP_generic.h:
+	Support for lucid context validation 
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* disp_com_err_status.c (init_et): Variable deleted.
+	(g_display_com_err_status): Don't call initialize_ggss_error_table
+	conditionally; instead, always call gssint_initialize_library.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapiP_generic.h (G_SET_INIT): Use the new mutex partial
+	initializer now.
+
+2004-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapiP_generic.h (struct _g_set_elt, g_set_elt): Renamed from
+	non-_elt versions.
+	* util_set.c, util_validate.c: Uses updated.
+
+	* gssapiP_generic.h (g_set): New struct type.
+	(G_SET_INIT): New macro.
+	* util_validate.c (g_save, g_validate, g_delete): Change first
+	argument to take a g_set * rather than void **; use the address of
+	the void pointer from the structure.
+	(g_save_name, g_save_cred_id, g_save_ctx_id, g_validate_name,
+	g_validate_cred_id, g_validate_ctx_id, g_delete_name,
+	g_delete_cred_id, g_delete_ctx_id): Updated first argument type.
+	* gssapiP_generic.h: Declarations updated.
+
+	* gssapiP_generic.h: Include k5-thread.h.
+	(g_set): Add a mutex.
+	(G_SET_INIT): Initialize it.
+	* util_validate.c (g_save, g_validate, g_delete): Lock the mutex
+	while working on the set.  (BDB version untested.)
+
+2004-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* util_ordering.c (g_queue_externalize, g_queue_internalize):
+	Check for sufficient buffer space.
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi_generic.c (const_oids): Renamed from oids, and now const.
+	(oids): New macro, casts const_oids to non-const pointer for use
+	in initializers.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapiP_generic.h: Include k5-platform.h.
+	(gssint_uint64): New typedef.
+	(g_order_init, g_order_check): Update decls.
+	* util_ordering.c (struct _queue): Change sequence number fields
+	to gssint_uint64.  Add mask field.
+	(queue_insert): Change sequence number to gssint_uint64.
+	(g_order_init): Change sequence numbers to gssint_uint64.  Add
+	"wide_nums" argument; initialize the queue mask field based on
+	it; all callers changed.  Store a -1 as the first element.
+	(g_order_check): Store and check elements as offsets from
+	firstnum.  Mask to 32 bits if desired.
+	* util_token.c (g_verify_token_header): Add new argument
+	indicating whether the pseudo-ASN.1 wrapper is required; all
+	callers changed.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-05-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(EHDRDIR)$(S)timestamp): New target, used for
+	ensuring $(EHDRDIR) exists.
+	(clean-unix): Delete the dummy file.
+	($(EHDRDIR)$(S)gssapi.h): Depend on it, instead of creating the
+	directory here.
+	($(EHDRDIR)$(S)gssapi_generic.h): Likewise.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+
+    * disp_com_err_status.c, gssapi_generic.h:  
+    Removed Mac header goober.
+    
+    * gssapiP_generic.h, gssapi.hin: Removed macintosh check because 
+    we don't build on OS 9 anymore.
+    
+    * gssapi.hin: Removed enumsalwaysint because there are no typed
+    enums in this header.  Removed duplicate CFM-68K magic.  
+
+2003-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove stamp rules.  Explicitly creates header
+	directory if needed.
+	(gssapi.h): Tweak to avoid race conditions.
+
+2003-02-11  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (gssapi-include): New rules to avoid coding
+	dependence on relative pathnames in parent Makefile.in.
+
+2003-02-11  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Another attempt... turns our that the "copy"
+	command on Windows preserves modtimes, so spurious rebuilds were
+	happening even with the stamp file, since the target in $(EHDRDIR)
+	is always out of date with respect to the stamp file.
+
+2003-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fix $(EHDRDIR) creation to avoid spurious
+	rebuilds.
+
+2003-02-09  Ezra Peisach  <epeisach@bu,edu>
+
+	* gssapiP_generic.h, util_token.c (g_token_size): Return unsigned
+	int instead of int.
+
+2003-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(EHDRDIR)$(S)gssapi.h): Depend on create-ehdrdir,
+	to make sure the directory is created before installation of the
+	file.
+	($(EHDRDIR)$(S)gssapi_generic.h): Likewise.
+	(create-ehdrdir): New target on UNIX.  Renamed from $(EHDRDIR) on
+	Windows and changed to check for an existing directory.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.original: Deleted.
+
+2002-12-05  Sam Hartman  <hartmans@mit.edu>
+
+	* util_token.c (g_verify_token_header g_make_token_header):
+	Accept -1 to mean  that no token type is expected; the token type
+	is purely an RFC 1964 artifact and is not used in other mechanisms
+	such as SPNEGO.
+
+2002-11-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* gssapiP_generic.h, util_token.c: Change g_make_token_header and
+	g_verfy_token_header to take an unsigned length in.
+
+2002-10-07  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in : Add install-headers- support
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(EHDRDIR)/gssapi.h, $(EHDRDIR)/gssapi_generic.h):
+	Quote target of copies.  Reverted.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* gssapiP_generic.h, util_token.c (g_verify_token_header): Make
+	length argument a pointer to an unsigned int.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS, OBJS, STLIBOBJS): Don't build util_dup.c.
+	* util_set.c (g_set_destroy): Don't compile this unused function.
+
+2002-07-12  Alexandra Ellwood <lxs@mit.edu>
+
+	* gssapi_generic.h: allow inclusion by C++
+
+	* gssapi.hin: Conditionalized pragmas for Metrowerks
+
+	* gssapi.hin: Added check for CFM compiles.  Removed dependency on
+	PRAGMA_* macros.  Moved check struct alignment check before struct
+	declarations.
+
+	* disp_com_err_status.c, gssapi.hin, gssapi_generic.h: 
+	Updated Mac OS X headers to new framework layout
+
+	* gssapi_generic.h: Fixed check for Mac OS X includes.
+
+	[pullups from 1-2-2-branch]
+
+2002-07-12  Miro Jurisic  <meeroh@mit.edu>
+
+	* gssapiP_generic.h: use "" include for krb5.h
+	[pullup from 1-2-2-branch]
+
+2001-10-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapiP_generic.h (g_*): For every g_ function declared here,
+	first define the name as a macro using a gssint_ prefix to avoid
+	conflicting with glib function names.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi.hin, gssapiP_generic.h: Make prototypes unconditional.
+	* gssapi.hin (PROTOTYPE): Don't define.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	Windows still requires DLL specs for variables.
+	* gssapi.hin (GSS_DLLIMP): Define, as before (from win-mac.h) for
+	Windows, empty otherwise.
+	(GSS_C_NT_USER_NAME, GSS_C_NT_MACHINE_UID_NAME,
+	GSS_C_NT_STRING_UID_NAME, GSS_C_NT_HOSTBASED_SERVICE_X,
+	GSS_C_NT_HOSTBASED_SERVICE, GSS_C_NT_ANONYMOUS,
+	GSS_C_NT_EXPORT_NAME): Use GSS_DLLIMP.
+	(KRB5_EXPORTVAR): Don't define.
+
+	* gssapi_generic.h (gss_nt_user_name, gss_nt_machine_uid_name,
+	gss_nt_string_uid_name, gss_nt_service_name): Use GSS_DLLIMP.
+	* gssapi_generic.c (gss_nt_user_name, gss_nt_machine_uid_name,
+	gss_nt_string_uid_name, gss_nt_service_name, GSS_C_NT_USER_NAME,
+	GSS_C_NT_MACHINE_UID_NAME, GSS_C_NT_STRING_UID_NAME,
+	GSS_C_NT_HOSTBASED_SERVICE_X, GSS_C_NT_HOSTBASED_SERVICE,
+	GSS_C_NT_ANONYMOUS, GSS_C_NT_EXPORT_NAME): Use GSS_DLLIMP.
+
+	* gssapi.hin: Drop FAR, NEAR, _MSDOS support.
+	* gssapiP_generic.h: Drop _MSDOS support.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi.hin, gssapi_generic.c, gssapi_generic.h: Don't use
+	GSS_DLLIMP.
+
+2001-06-25  Tom Yu  <tlyu@mit.edu>
+
+	* gssapi.hin, gssapi_generic.h, gssapi_generic.c:
+	added oids from rfc 2744.  Kept old oids for compatibility.
+	[pullup of lxs's changes]
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* util_validate.c (g_save): Cleanup extraneous variable from last
+ 	change.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* util_validate.c (g_validate, g_save, g_delete): If HAVE_BSD_TYPE
+	is not defined, declare static functions as taking a void *type for
+	passing to g_set_entry_add.
+
+2001-05-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* disp_major_status.c (display_unknown): Remove unused variable. 
+
+	* util_token.c (g_make_token_header): Remove incorrect cast of
+	length argument to memcpy.
+
+	* oid_ops.c (generic_gss_str_to_oid): Cast argument of isxxx()
+	functions to int - avoids gcc warning when these are implemented
+	as macros indexing an array.
+
+2001-05-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* disp_major_status.c (display_unknown): Declare as static. Remove
+	non-useful code.
+
+2001-04-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unixmac): Target deleted.
+
+2001-03-10  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* oid_ops.c: Avoid the use of a variable named index.
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* gssapiP_generic.h (g_OID_equal): Instead of casting argument to
+	memcmp as int, cast to unsigned int to match prototype.
+
+2000-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS, OBJS, STLIBOBJS): Remove util_canonhost.
+	* gssapiP_generic (g_canonicalize_host, g_local_host_name): Delete
+	declarations.
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* util_token.c: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Wed May 19 13:23:16 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Improve rule to create gssapi include dir under
+		windows.
+
+Wed May 19 11:39:05 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Fix windows cleanup to ignore any errors while
+		removing gssapi include dir.
+
+Mon May 10 15:22:12 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Thu Mar 25 22:41:30 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* disp_major_status.c (display_unknown): Fix the length of the
+ 	 	buffer to be the size of the returned string, instead of
+ 	 	something bigger than the returned string.
+
+1999-02-19  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (DLL_FILE_DEF): Tell the Makefile template that we
+		are building object files for the GSSAPI DLL.
+
+	* gssapi.hin, gssapi_generic.c: Change use of KRB5_DLLIMP to be
+		GSS_DLLIMP.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* gssapi.hin: define GSS_S_DUPLICATE_ELEMENT, GSS_S_NAME_NOT_MN,
+	and GSS_S_GAP_TOKEN as per gss v2 c bindings
+
+1998-06-08  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* oid_ops.c (generic_gss_release_oid): Recognize our own "self"
+		oids so that we don't free static oid's.  (exported_name
+		and nt_service_name_v2).
+
+Sun May 24 22:01:29 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* util_buffer.c (g_make_string_buffer): Don't include the trailing
+		NULL of the string in the gss buffer's length.
+
+1998-05-18  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* util_ordering.c (g_order_free): 
+	* rel_oid_set.c (generic_gss_release_oid_set): 
+	* disp_major_status.c: General lint cleanup.
+
+	* util_oid.c (g_copy_OID_set): Copy the OID set with entirely
+		dynamic memory (don't alias the contents of the OID set).
+
+Wed Apr  1 16:33:27 1998  Tom Yu  <tlyu@mit.edu>
+
+	* disp_major_status.c (g_display_major_status): Fix a typo in
+	previous.
+
+1998-03-31  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* disp_major_status.c (display_unknown): Change to not return
+		GSS_S_CONTINUE_NEEDED, per the standard C bindings
+		specification.
+
+Wed Feb 18 16:11:15 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jun 27 08:44:54 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* gssapi.hin: Add definition of GSS_C_NO_NAME (per
+		draft-ietf-cbind-04.txt)
+
+Wed Nov 19 11:01:27 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean-unix): Remove EXPORTED_BUILT_HEADERS as well.
+
+Sun Aug 17 14:31:26 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* util_token.c (g_verify_token_header): Change local char *
+	 	variable to unsigned char * to match usage.
+
+Tue Jul 29 22:54:40 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssapi_generic.c: Add support for the new OID value for
+		host-based service name.
+
+Tue Jul  8 12:46:17 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* util_ordering.c: Include string.h for prototypes.
+
+Fri Mar 28 03:43:58 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssapi_generic.c, gssapi_generic.h: Added definition for the
+		generic gsspi OID type "gss_nt_exported_name".
+
+Thu Mar 27 15:36:32 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* gssapi.hin: Add the GSS_C_PROT_READY_FLAG and GSS_C_TRANS_FLAG
+		Add prototypes for the V2 functions gss_export_name(),
+		gss_duplicate_name(), and gss_canonicalize_name().
+
+Tue Mar 18 13:52:29 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* gssapi.hin: Add 'extern "C"' for C++ compatibility; also check
+		for __cplusplus since some C++ compilers don't set
+ 		__STDC__
+
+Mon Mar 17 14:42:33 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssapi.hin: Fix header file so that winmac.h is #included when
+		compiling on the Macintosh.
+
+Sat Feb 22 18:57:56 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Sun Feb  9 11:41:08 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fix includes generation for unix after
+	libhack_branch merge.
+
+Thu Feb  6 11:11:17 1997  Ezra Peisach  (epeisach@mit.edu)
+
+	* configure.in: Remove the CopyHeader and CopySrcHeader rules as
+		they are handled in Makefile.in
+
+	* Makefile.in: Create include/gssapi on unix. Make clean removes
+		built gssapi.h
+
+Wed Feb  5 23:28:47 1997  Richard Basch  <basch@lehman.com>
+
+	* gssapi.hin: Make sure KRB5_EXPORTVAR is defined.
+
+Tue Feb  4 15:55:11 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Only override the object build of the error table
+		under Unix
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+	* gssapi.hin, gssapi_generic.c, gssapi_generic.h:
+	DLL export all public gssapi functions; move windows/mac stuff to
+	win-mac.h
+
+Tue Jan 14 20:16:46 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Wed Nov 20 13:59:58 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (install): Install gssapi.h from the build tree.
+
+Tue Nov 19 16:43:16 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (gssapi.h): grep USE_.*_H out from autoconf.h as
+	well (some stuff was depending on USE_STRING_H).
+
+Mon Nov 18 12:38:34 1996  Tom Yu  <tlyu@mit.edu>
+
+	*gssapi.h: Renamed to gssapi.hin.
+
+	* gssapi.hin: Remove #ifdef USE_AUTOCONF_H; we're grepping symbols
+	directly from autoconf.h now.
+
+	* configure.in: Change CopySrcHeader to CopyHeader, as gssapi.h is
+	now generated in the build tree.
+
+	* Makefile.in: Add rules to generate gssapi.h from gssapi.hin,
+	similar to how krb5.h is generated from krb5.hin.  Remove
+	-DUSE_AUTOCONF_H from $(CFLAGS)
+
+Tue Nov  5 18:47:44 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (HDRS): Changes so that $(OBJS) will not get
+	recompiled gratuitously if someone touches the include directory.
+
+	* configure.in: Revert previous change re: CopySrcHeader.
+
+Tue Oct 29 10:20:58 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Use $(S) instead of / for productions which could
+		be used on both DOS and Unix systems.
+
+Mon Oct 21 16:16:26 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* util_ordering.c (g_queue_internalize, g_queue_externalize):
+ 		Fixed typo so that the remaining length field is set
+ 		correctly.
+
+Sat Oct 19 00:39:25 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* util_ordering.c (g_queue_externalize, g_queue_internalize,
+	 	g_queue_size):  New routines which allow the serailizing
+	 	routines to access the seqstate structure.
+
+Thu Oct 10 15:03:38 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Remove calls to CopySrcHeader.
+
+	* Makefile.in: More fixups; punt usage of CopySrcHeader and use
+ 	explicit dependencies instead, thus avoiding abuse of double-colon
+ 	rules.
+
+Wed Oct  9 14:12:27 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-unix): Fix up last change; depending on a phony
+	target causes everything all of $(OBJS) to get remade always.
+
+	* Makefile.in (all-unix): Fix up various rules that have
+	"includes" as dependencies in order to allow for makes that don't
+	do left-to-right ordering of dependencies.
+
+Wed Aug 28 17:44:06 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* utl_nohash_validate.c: 
+	* util_canonhost.c:
+	* util_validate.c: Only include sys/types.h if present.
+
+	* configure.in: Add check for limits.h and sys/types.h
+
+Fri Aug  2 13:37:10 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gssapiP_generic.h: If not on a Mac or under Dos, and stdlib.h
+		exists, include it.
+
+	* configure.in: Check for stdlib.h
+
+Thu Jul 25 00:03:01 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* util_ordering.c (g_order_check): 
+	* util_ordering.c (g_order_init): Changed return code to be an int
+		32, since we return a com_err error code.  Change the type
+		of the sequence number to be an uint32.
+
+	* gssapi.h: Define gss_int32 -- needed for error code returns.
+
+	* Makefile.in (EHDRDIR): Use $(S) instead of /, so that EHDRDIR is
+		valid under windows.  Fix how the header file is copied in
+		under Windows.
+
+	* gssapiP_generic.h: Include gssapi_generic.h instead of gssapi.h,
+		so that we get the definitions of the nametype oids.
+
+Wed Jul 24 18:48:43 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* oid_ops.c (generic_gss_release_oid): Re-enable function.
+
+	* util_token.c (g_verify_token_header): Changed return code to be
+		an int 32, since we return a com_err error code.
+
+	* rel_buffer.c (generic_gss_release_buffer): 
+	* rel_oid_set.c (generic_gss_release_oid_set): Remove INTERFACE
+ 		keyworded; not needed (and causes problems) since we're
+ 		not exporting this function to the DLL.
+
+Tue Jul 23 16:44:50 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* util_validate.c: Only include <sys/file.h> if building with BSD_DB.
+
+	* gssapiP_generic.h: Must include k5-int.h on Windows and
+		Macintosh builds.
+
+	* Makefile.in (SRCS): Renamed release_buffer.c to rel_buffer.c,
+		and release_oid_set.c to rel_oid_set.c.  Marc broke the
+		DOS 8.3 renaming which Gilmore had done to conform with
+		DOS's filesystem constraints.
+
+Fri Jun 21 18:02:51 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* gssapi.h: Fix Win-16 build #defines for KRB5_CALLCONV and
+	 	KRB5_DLLIMP.
+
+Thu Jun 13 22:11:08 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to ET_RULES
+
+Wed Jun 12 00:48:32 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Update special rule for gssapi_err_generic.obj
+		so that it uses the right Win-32 library command.
+
+Wed Jun 12 00:46:41 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* gssapi.h: Change INTERFACE to be KRB5_CALLCONV, which is where
+		the calling convention is defined.  Add KRB5_DLLIMP
+		which is where the DLL import/export should be put for
+		Win32.  (Win16 is just different.)  The correct way to
+		declare a function which will be used in a DLL is now:
+		KRB5_DLLIMP func_return_t KRB5_CALLCONV func(long)
+
+		Change function delcarations to use the new
+		convention.  Actually, it doesn't hurt to use the old
+		convention as long as func_return_t doesn't contain a
+		'*'.  But in the long run we should be exterminating
+		all uses of INTERFACE in favor of KRB5_CALLCONV and
+		KRB5_DLLIMP.
+
+Sun Apr 21 03:07:02 1996  Marc Horowitz  <marc@mit.edu>
+
+	* gssapi_generic.c, release_buffer.c, release_oid_set.c: added
+ 	files which should have been added before, but either I or commit
+ 	was confused.
+
+Wed Apr 17 20:59:23 1996  Marc Horowitz  <marc@mit.edu>
+
+	* oid_ops.c: moved from mechglue
+	
+	* util_canonhost.c (g_canonicalize_host): cast the return value of
+ 	malloc()
+
+	* gssapiP_generic.h: Added prototypes for oid_ops.c
+
+	* gssapi.h: Make the types of OM_uint32 constants portable,
+	fix some minor compile-time nits
+
+	* Makefile.in: change the list of files which need to be built
+
+Tue Apr  2 15:31:25 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS): Inlined list of source files for SRCS and
+		OBJS (for Macintosh build).
+
+Thu Feb 29 19:39:23 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* util_token.c (der_length_size, der_write_size): Fix to work on
+		16-bit platforms (we don't allow greater than 64k tokens
+		on these platforms).
+
+Tue Feb 27 17:49:54 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapi.h (size_t): Make sure size_t and uid_t are defined under
+	        MS-DOS.
+
+Sat Feb 24 21:30:53 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapi.h (GSS_S_DUPLICATE_ELEMENT): New error code function.
+		XXX Need to square number assigment with official C-binds
+		draft once it is issued.
+
+Wed Jan 24 20:48:15 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* gssapi.h: Added definition of NPROTOTYPE to dtrt with Ultrix,
+		etc.  Also added special case for Ultrix (limited
+		prototype support).
+
+Tue Jan 23 03:28:41 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapiP_generic.h: Removed prototypes of functions that have
+		been moved to the mechglue layer.
+
+	* Makefile.in: Removed gssapi_generic.c, oid_ops.c, rel_buffer.c,
+		and rel_oid_set.c --- these functions are now done in the
+		mechglue layer.  
+
+Wed Jan 10 21:31:42 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (gssapi_err_generic.$(OBJEXT)): Added ##DOS
+		statements after gssapi_err_generic.$(OBJECT) to get it
+		added to library on Windows.  (Patch from Doug Engert).
+
+	* gssapi.h: Remove #if statement that used sizeof(xxx), since that
+		won't work for most C compilers/C preprocessors!
+
+Thu Jan  4 21:33:38 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapiP_generic.h (TWRITE_INT16, TREAD_INT16): Added new macros
+		to read and write two byte integers from the wire.
+
+	* gssapiP_generic.h: Don't include <sys/types.h> since it's
+		already included by gssapi.h.
+
+	* gssapi.h: Add a #ifndef _MACINTOSH around include of <sys/types.h>
+
+Fri Nov 17 22:21:58 1995    <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, ChangeLog: Add support to compile shared libraries.
+
+	* gssapi.h: Include sys/types.h, since that's where POSIX says
+		size_t is defined.
+
+Fri Oct  6 22:01:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Fri Sep 29 02:02:35 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapi.h: For MS-DOS, use the brute force method of defining the
+		size of variables; we should really get an autoconf file
+		for MS-DOS.
+
+Mon Sep 28 12:00:00 1995  John Rivlin <jrivlin@fusion.com>
+	
+	* gssapi_generic.h: Modified to use build in compiler symbols rather
+		than relying on _MACINTOSH so the projects can include the file
+		without using our headers.
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Mon Sep 25 16:53:00 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 13 10:36:32 1995 Keith Vetter (keithv@fusion.com)
+
+	* oid_ops.c: signed/unsigned mismatch, removed unused variables.
+	* util_oid.c: changed int to a size_t.
+
+Wed Sep  6 12:00:00 1995  James Mattly  <mattly@fusion.com>
+	* gssapiP_generic.h:  changed a path bearing include for MACINTOSH
+	* gssapi_generic.h:  changed a path bearing include for MACINTOSH
+	* util_cannonhost.h:  changed a path bearing include for MACINTOSH
+	* utl_nohash_validate.h:  changed a path bearing include for MACINTOSH,
+		also we don't have limits.h
+
+
+Thu Aug 31 11:43:59 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gssapi.h - Update to V2 API.  Also use autoconf.h if USE_AUTOCONF_H
+		is defined, otherwise resort to brute force.  Remove const_
+		gss_OID, as it's not defined in the API.
+	* gssapiP_generic.h - Add new V2 dispatch prototypes.  Update
+		arguments to be compatible with V2 API.
+	* disp_major_status.c - Describe new failure codes.  Update argument.
+	* gssapi_generic.c - Replace const_gss_OID.
+	* rel_oid_set.c - Free individual OID data also.
+	* util_token.c - Replace const_gss_OID.
+	* oid_ops.c - New V2 OID set manipulation routines.
+	* Makefile.in, .Sanitize - Add oid_ops.c.
+
+
+Tue Aug 29 13:30:29 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gssapi.h - Add prototypes for gss_{im,ex}port_sec_context.
+
+
+Thu Jul 27 15:25:08 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gssapiP_generic.h - Include k5-int.h instead of k5-config.h and
+		conditionally k5-sockets.h.
+
+
+Fri Jul 7 16:22:49 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS, it's set by configure.
+
+Fri Jun  9 19:25:47 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed May 24 06:52:41 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gssapiP_generic.h: Include k5-sockets.h now that k5-config.h
+		does not include netdb.h.
+
+Mon May 22 10:08:13 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in	- Install EXPORTED_HEADERS in gssapi subdirectory of
+			  KRB5_INCDIR.
+	* configure.in	- Find KRB5ROOT and install program.
+
+Sat Apr 29 15:29:15 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gssapi.h: Only define PROTOTYPE if it is not deined at all.
+
+Fri Apr 21 10:57:44 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* gssapi.h: If !stdc and !windows, define PROTOTYPE properly.
+
+Thu Apr 20 14:23:14 1995 Keith Vetter (keithv@fusion.com)
+
+	* gssapi.h: fixed up the "windows specific hackery".
+
+Thu Apr 20 11:41:04 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Add checking for SIZEOF_SHORT, SIZEOF_INT, and
+		SIZEOF_LONG, so we don't need to depend on getting this
+		information from include/krb5/autoconf.h
+
+	* gssapi.h: Removed dependence on krb5 include files.
+
+	* gssapiP_generic.h: We need to include k5-config in order to get
+		Windows specific hackery.  Somewhat of a wart, but this is
+		a gssapi internal header file, so the rest of the world
+		doesn't have to see this.
+
+	* util_token.c: Define VALID_INT, instead of relying on this being
+		defined by krb5.h.
+
+Thu Apr 13 16:27:56 1995 Keith Vetter (keithv@fusion.com)
+
+	* gssapi_e.c: __STDC__ conditional also checks the _WINDOWS define.
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+        * *.h added FAR to pointers visible at to the world.
+
+Tue Mar 28 18:28:03 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (unixmac):  Add to build header files.
+
+Fri Mar 24 18:02:15 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* util_canonhost.c: Don't include sys/socket.h and netdb.h, since
+		they are included by k5-config.h
+
+Tue Mar 21 19:09:34 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed the name of the library the PC
+           builds, and added xxx-mac targets to mimic xxx-unix.
+
+Tue Mar 7 20:14:53 1995 Keith Vetter (keithv@fusion.com)
+
+	* disp_maj.c: added casts on int->long assignments.
+        * util_can.c: made to work with PC winsockets.
+        * util_dup.c: added system include for prototype info.
+        * util_tok.c: int/long problems.
+        * gssapip_.h: added casts on int->char assignments.
+
+Tue Feb 28 00:25:58 1995  John Gilmore  (gnu at toad.com)
+
+	* gssapi.h:  Avoid <krb5/...> includes.
+	* disp_com_err_status.c:  Use "com_err.h" not <com_err.h>.
+
+Mon Feb 20 18:50:33 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work on the PC
+        * Added windows INTERFACE keyword
+          disp_com.c disp_maj.c rel_buff.c rel_oid_.c
+          util_buf.c util_can.c util_dup.c util_oid.c
+          util_tok.c util_val.c utl_noha.c
+        * gssapiP_generic.h: 
+          added INTERFACE keyword
+          removed inclusion
+        * util_tok.c: had to coerce long to int on TWRITE_STR.
+        * gssapi.h: made typedef for OM_uint32 machine independent and
+          added INTERFACE to prototypes.
+
+Mon Feb 20 12:00:00 1994  Keith Vetter (keithv@fusion.com)
+
+	More DOS 8.3 renames--for files created by make
+	* gssapi_generic_err.et   => gssapi_err_generic.et
+				  => gssapi_err_generic.h
+				  => gssapi_err_generic.c
+	* gssapiP_generic.h was changed to match
+	* Makefile.in was changed to match
+
+Fri Feb  3 00:18:11 1995  John Gilmore  <gnu@cygnus.com>
+
+	Rename files for DOS 8.3 uniqueness:
+	* display_com_err_status.c => disp_com_err_status.c
+	* display_major_status.c   => disp_major_status.c
+	* release_buffer.c         => rel_buffer.c
+	* release_oid_set.c        => rel_oid_set.c
+	* util_val_nohash.c        => utl_nohash_validate.c
+	* Makefile.in was changed to match.
+
+Sat Aug 20 01:34:46 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* gss_generic.c (gss_OID_desc): Fix OID's!
+
+Thu Jul 14 03:29:25 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: remove spurious mkdir
+
+Tue Jun 21 01:17:35 1994  Mark W. Eichin  (eichin at mit.edu)
+
+	* configure.in: add AC_SIZE_T.
+
diff --git a/mechglue/src/lib/gssapi/generic/Makefile.in b/mechglue/src/lib/gssapi/generic/Makefile.in
new file mode 100644
index 000000000..d80163a08
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/Makefile.in
@@ -0,0 +1,208 @@
+thisconfigdir=./..
+myfulldir=lib/gssapi/generic
+mydir=generic
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir)
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=generic
+##DOS##OBJFILE=..\$(OUTPRE)generic.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+ETSRCS= gssapi_err_generic.c
+ETOBJS= $(OUTPRE)gssapi_err_generic.$(OBJEXT)
+ETHDRS= gssapi_err_generic.h
+
+EHDRDIR= $(BUILDTOP)$(S)include$(S)gssapi
+
+HDRS=	$(EHDRDIR)$(S)gssapi.h \
+	$(EHDRDIR)$(S)gssapi_generic.h
+
+MK_EHDRDIR=if test -d $(EHDRDIR); then :; else (set -x; mkdir $(EHDRDIR)); fi
+##DOS##MK_EHDRDIR=rem
+
+gssapi-include: $(EHDRDIR)$(S)gssapi.h
+
+$(EHDRDIR)$(S)gssapi.h: $(EHDRDIR)$(S)timestamp gssapi.h
+	$(CP) gssapi.h $@
+$(EHDRDIR)$(S)gssapi_generic.h: $(EHDRDIR)$(S)timestamp $(srcdir)$(S)gssapi_generic.h
+	$(CP) $(srcdir)$(S)gssapi_generic.h $@
+
+$(EHDRDIR)$(S)timestamp:
+	$(MK_EHDRDIR)
+	echo timestamp > $(EHDRDIR)$(S)timestamp
+
+$(OUTPRE)gssapi_err_generic.$(OBJEXT): gssapi_err_generic.c
+gssapi_err_generic.h: gssapi_err_generic.et
+gssapi_err_generic.c: gssapi_err_generic.et
+
+include_xom=@include_xom@
+##DOS##include_xom=
+gssapi.h: gssapi.hin
+	@echo "Creating gssapi.h" ; \
+	h=gss$$$$; $(RM) $$h; \
+	(echo "/* This is the gssapi.h prologue. */"; \
+	echo "/* It contains some choice pieces of autoconf.h */"; \
+	sed -n "/SIZEOF/s//GSS_&/p" < $(BUILDTOP)/include/krb5/autoconf.h; \
+	$(include_xom); \
+	echo "/* End of gssapi.h prologue. */"; \
+	cat $(srcdir)/gssapi.hin )> $$h && \
+	(set -x; $(MV) $$h $@) ; e=$$?; $(RM) $$h; exit $$e
+
+#if HasHashLibrary
+# UTIL_VALIDATE_SRC= $(srcdir)/util_validate.c
+# UTIL_VALIDATE_OBJ= util_validate.$(OBJEXT)
+#else
+#UTIL_VALIDATE_SRC= $(srcdir)/utl_nohash_validate.c
+#UTIL_VALIDATE_OBJ= utl_nohash_validate.$(OBJEXT)
+#endif
+
+SRCS = \
+	$(srcdir)/disp_com_err_status.c \
+	$(srcdir)/disp_major_status.c \
+	$(srcdir)/gssapi_generic.c \
+	$(srcdir)/rel_buffer.c \
+	$(srcdir)/rel_oid_set.c \
+	$(srcdir)/util_buffer.c \
+	$(srcdir)/util_oid.c \
+	$(srcdir)/util_ordering.c \
+	$(srcdir)/util_set.c \
+	$(srcdir)/util_token.c \
+	$(srcdir)/util_validate.c \
+	gssapi_err_generic.c
+
+OBJS = \
+	$(OUTPRE)disp_com_err_status.$(OBJEXT) \
+	$(OUTPRE)disp_major_status.$(OBJEXT) \
+	$(OUTPRE)gssapi_generic.$(OBJEXT) \
+	$(OUTPRE)rel_buffer.$(OBJEXT) \
+	$(OUTPRE)rel_oid_set.$(OBJEXT) \
+	$(OUTPRE)util_buffer.$(OBJEXT) \
+	$(OUTPRE)util_oid.$(OBJEXT) \
+	$(OUTPRE)util_ordering.$(OBJEXT) \
+	$(OUTPRE)util_set.$(OBJEXT) \
+	$(OUTPRE)util_token.$(OBJEXT) \
+	$(OUTPRE)util_validate.$(OBJEXT) \
+	$(OUTPRE)gssapi_err_generic.$(OBJEXT)
+
+STLIBOBJS = \
+	disp_com_err_status.o \
+	disp_major_status.o \
+	gssapi_generic.o \
+	rel_buffer.o \
+	rel_oid_set.o \
+	util_buffer.o \
+	util_oid.o \
+	util_ordering.o \
+	util_set.o \
+	util_token.o \
+	util_validate.o \
+	gssapi_err_generic.o
+
+EXPORTED_HEADERS= gssapi_generic.h
+EXPORTED_BUILT_HEADERS= gssapi.h
+
+$(OBJS): $(EXPORTED_HEADERS) $(ETHDRS)
+
+all-unix:: $(EXPORTED_HEADERS) $(ETHDRS) $(HDRS)
+all-unix:: all-libobjs
+
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-windows:: win-create-ehdrdir
+all-windows:: $(HDRS)
+
+win-create-ehdrdir:
+	if not exist $(EHDRDIR)\nul mkdir $(EHDRDIR)
+
+clean-unix:: clean-libobjs
+	$(RM) $(ETHDRS) $(ETSRCS) $(HDRS) $(EXPORTED_BUILT_HEADERS) \
+		$(EHDRDIR)$(S)timestamp
+
+clean-windows::
+	$(RM) $(HDRS)
+	-if exist $(EHDRDIR)\nul rmdir $(EHDRDIR)
+
+# Krb5InstallHeaders($(EXPORTED_HEADERS), $(KRB5_INCDIR)/krb5)
+install-headers-unix install:: gssapi.h
+	@set -x; for f in $(EXPORTED_HEADERS) ; \
+	do $(INSTALL_DATA) $(srcdir)/$$f	\
+		$(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
+	done
+	@set -x; for f in $(EXPORTED_BUILT_HEADERS) ; \
+	do $(INSTALL_DATA) $$f	\
+		$(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
+	done
+
+depend:: $(ETSRCS)
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+disp_com_err_status.so disp_com_err_status.po $(OUTPRE)disp_com_err_status.$(OBJEXT): \
+  disp_com_err_status.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+disp_major_status.so disp_major_status.po $(OUTPRE)disp_major_status.$(OBJEXT): \
+  disp_major_status.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+gssapi_generic.so gssapi_generic.po $(OUTPRE)gssapi_generic.$(OBJEXT): \
+  gssapi_generic.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+oid_ops.so oid_ops.po $(OUTPRE)oid_ops.$(OBJEXT): oid_ops.c \
+  gssapiP_generic.h $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5/autoconf.h \
+  gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  gssapi_err_generic.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+rel_buffer.so rel_buffer.po $(OUTPRE)rel_buffer.$(OBJEXT): \
+  rel_buffer.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+rel_oid_set.so rel_oid_set.po $(OUTPRE)rel_oid_set.$(OBJEXT): \
+  rel_oid_set.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+util_buffer.so util_buffer.po $(OUTPRE)util_buffer.$(OBJEXT): \
+  util_buffer.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+util_oid.so util_oid.po $(OUTPRE)util_oid.$(OBJEXT): \
+  util_oid.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+util_ordering.so util_ordering.po $(OUTPRE)util_ordering.$(OBJEXT): \
+  util_ordering.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+util_set.so util_set.po $(OUTPRE)util_set.$(OBJEXT): \
+  util_set.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+util_token.so util_token.po $(OUTPRE)util_token.$(OBJEXT): \
+  util_token.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+util_validate.so util_validate.po $(OUTPRE)util_validate.$(OBJEXT): \
+  util_validate.c gssapiP_generic.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gssapi_err_generic.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-platform.h
+gssapi_err_generic.so gssapi_err_generic.po $(OUTPRE)gssapi_err_generic.$(OBJEXT): \
+  gssapi_err_generic.c $(COM_ERR_DEPS)
diff --git a/mechglue/src/lib/gssapi/generic/disp_com_err_status.c b/mechglue/src/lib/gssapi/generic/disp_com_err_status.c
new file mode 100644
index 000000000..24511dfe5
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/disp_com_err_status.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_generic.h"
+#include "com_err.h"
+
+/* XXXX internationalization!! */
+
+/**/
+
+static const char * const no_error = "No error";
+
+/**/
+
+/* if status_type == GSS_C_GSS_CODE, return up to three error messages,
+     for routine errors, call error, and status, in that order.
+     message_context == 0 : print the routine error
+     message_context == 1 : print the calling error
+     message_context > 2  : print supplementary info bit (message_context-2)
+   if status_type == GSS_C_MECH_CODE, return the output from error_message()
+   */
+
+OM_uint32
+g_display_com_err_status(minor_status, status_value, status_string)
+     OM_uint32 *minor_status;
+     OM_uint32 status_value;
+     gss_buffer_t status_string;
+{
+   status_string->length = 0;
+   status_string->value = NULL;
+
+   (void) gssint_initialize_library();
+
+   if (! g_make_string_buffer(((status_value == 0)?no_error:
+			       error_message(status_value)),
+			      status_string)) {
+      *minor_status = ENOMEM;
+      return(GSS_S_FAILURE);
+   }
+   *minor_status = 0;
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/generic/disp_major_status.c b/mechglue/src/lib/gssapi/generic/disp_major_status.c
new file mode 100644
index 000000000..218370d14
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/disp_major_status.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_generic.h"
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * $Id$
+ */
+
+/* This code has knowledge of the min and max errors of each type
+   within the gssapi major status */
+
+#define GSS_ERROR_STR(value, array, select, min, max, num) \
+   (((select(value) < (min)) || (select(value) > (max))) ? NULL : \
+    (array)[num(value)])
+
+/**/
+
+static const char * const calling_error_string[] = {
+   NULL,
+   "A required input parameter could not be read",
+   "A required input parameter could not be written",
+   "A parameter was malformed",
+};
+ 
+static const char * const calling_error = "calling error";
+
+#define GSS_CALLING_ERROR_STR(x) \
+   GSS_ERROR_STR((x), calling_error_string, GSS_CALLING_ERROR, \
+		 GSS_S_CALL_INACCESSIBLE_READ, GSS_S_CALL_BAD_STRUCTURE, \
+		 GSS_CALLING_ERROR_FIELD)
+
+/**/
+
+static const char * const routine_error_string[] = {
+   NULL,
+   "An unsupported mechanism was requested",
+   "An invalid name was supplied",
+   "A supplied name was of an unsupported type",
+   "Incorrect channel bindings were supplied",
+   "An invalid status code was supplied",
+   "A token had an invalid signature",
+   "No credentials were supplied",
+   "No context has been established",
+   "A token was invalid",
+   "A credential was invalid",
+   "The referenced credentials have expired",
+   "The context has expired",
+   "Miscellaneous failure",
+   "The quality-of-protection requested could not be provided",
+   "The operation is forbidden by the local security policy",
+   "The operation or option is not available",
+};   
+
+static const char * const routine_error = "routine error";
+
+#define GSS_ROUTINE_ERROR_STR(x) \
+   GSS_ERROR_STR((x), routine_error_string, GSS_ROUTINE_ERROR, \
+		 GSS_S_BAD_MECH, GSS_S_FAILURE, \
+		 GSS_ROUTINE_ERROR_FIELD)
+
+/**/
+
+/* this becomes overly gross after about 4 strings */
+
+static const char * const sinfo_string[] = {
+   "The routine must be called again to complete its function",
+   "The token was a duplicate of an earlier token",
+   "The token's validity period has expired",
+   "A later token has already been processed",
+};
+
+static const char * const sinfo_code = "supplementary info code";
+
+#define LSBGET(x) ((((x)^((x)-1))+1)>>1)
+#define LSBMASK(n) ((1<<(n))^((1<<(n))-1))
+
+#define GSS_SINFO_STR(x) \
+   ((((1<<(x)) < GSS_S_CONTINUE_NEEDED) || ((1<<(x)) > GSS_S_UNSEQ_TOKEN)) ? \
+    /**/NULL:sinfo_string[(x)])
+
+/**/
+
+static const char * const no_error = "No error";
+static const char * const unknown_error = "Unknown %s (field = %d)";
+
+/**/
+
+static int 
+display_unknown(kind, value, buffer)
+     const char *kind;
+     OM_uint32 value;
+     gss_buffer_t buffer;
+{
+   char *str;
+
+   if ((str =
+	(char *) xmalloc(strlen(unknown_error)+strlen(kind)+7)) == NULL)
+      return(0);
+
+   sprintf(str, unknown_error, kind, value);
+
+   buffer->length = strlen(str);
+   buffer->value = str;
+
+   return(1);
+}
+
+/* code should be set to the calling error field */
+
+static OM_uint32 display_calling(minor_status, code, status_string)
+     OM_uint32 *minor_status;
+     OM_uint32 code;
+     gss_buffer_t status_string;
+{
+   const char *str;
+
+   if ((str = GSS_CALLING_ERROR_STR(code))) {
+      if (! g_make_string_buffer(str, status_string)) {
+	 *minor_status = ENOMEM;
+	 return(GSS_S_FAILURE);
+      }
+   } else {
+      if (! display_unknown(calling_error, GSS_CALLING_ERROR_FIELD(code),
+			    status_string)) {
+	 *minor_status = ENOMEM;
+	 return(GSS_S_FAILURE);
+      }
+   }
+   *minor_status = 0;
+   return(GSS_S_COMPLETE);
+}
+
+/* code should be set to the routine error field */
+
+static OM_uint32 display_routine(minor_status, code, status_string)
+     OM_uint32 *minor_status;
+     OM_uint32 code;
+     gss_buffer_t status_string;
+{
+   const char *str;
+
+   if ((str = GSS_ROUTINE_ERROR_STR(code))) {
+      if (! g_make_string_buffer(str, status_string)) {
+	 *minor_status = ENOMEM;
+	 return(GSS_S_FAILURE);
+      }
+   } else {
+      if (! display_unknown(routine_error, GSS_ROUTINE_ERROR_FIELD(code),
+			    status_string)) {
+	 *minor_status = ENOMEM;
+	 return(GSS_S_FAILURE);
+      }
+   }
+   *minor_status = 0;
+   return(GSS_S_COMPLETE);
+}
+
+/* code should be set to the bit offset (log_2) of a supplementary info bit */
+
+static OM_uint32 display_bit(minor_status, code, status_string)
+     OM_uint32 *minor_status;
+     OM_uint32 code;
+     gss_buffer_t status_string;
+{
+   const char *str;
+
+   if ((str = GSS_SINFO_STR(code))) {
+      if (! g_make_string_buffer(str, status_string)) {
+	 *minor_status = ENOMEM;
+	 return(GSS_S_FAILURE);
+      }
+   } else {
+      if (! display_unknown(sinfo_code, 1<<code, status_string)) {
+	 *minor_status = ENOMEM;
+	 return(GSS_S_FAILURE);
+      }
+   }
+   *minor_status = 0;
+   return(GSS_S_COMPLETE);
+}
+
+/**/
+
+/* return error messages, for routine errors, call error, and status,
+   in that order.
+     message_context == 0 : print the routine error
+     message_context == 1 : print the calling error
+     message_context > 2  : print supplementary info bit (message_context-2)
+     */
+
+OM_uint32 g_display_major_status(minor_status, status_value, 
+				 message_context, status_string)
+     OM_uint32 *minor_status;
+     OM_uint32 status_value;
+     OM_uint32 *message_context;
+     gss_buffer_t status_string;
+{
+   OM_uint32 ret, tmp;
+   int bit;
+
+   /*** deal with no error at all specially */
+
+   if (status_value == 0) {
+      if (! g_make_string_buffer(no_error, status_string)) {
+	 *minor_status = ENOMEM;
+	 return(GSS_S_FAILURE);
+      }
+      *message_context = 0;
+      *minor_status = 0;
+      return(GSS_S_COMPLETE);
+   }
+
+   /*** do routine error */
+
+   if (*message_context == 0) {
+      if ((tmp = GSS_ROUTINE_ERROR(status_value))) {
+	 status_value -= tmp;
+	 if ((ret = display_routine(minor_status, tmp, status_string)))
+	    return(ret);
+	 *minor_status = 0;
+	 if (status_value) {
+	    (*message_context)++;
+	    return(GSS_S_COMPLETE);
+	 } else {
+	    *message_context = 0;
+	    return(GSS_S_COMPLETE);
+	 }
+      } else {
+	 (*message_context)++;
+      }
+   } else {
+      status_value -= GSS_ROUTINE_ERROR(status_value);
+   }
+
+   /*** do calling error */
+
+   if (*message_context == 1) {
+      if ((tmp = GSS_CALLING_ERROR(status_value))) {
+	 status_value -= tmp;
+	 if ((ret = display_calling(minor_status, tmp, status_string)))
+	    return(ret);
+	 *minor_status = 0;
+	 if (status_value) {
+	    (*message_context)++;
+	    return(GSS_S_COMPLETE);
+	 } else {
+	    *message_context = 0;
+	    return(GSS_S_COMPLETE);
+	 }
+      } else {
+	 (*message_context)++;
+      }
+   } else {
+      status_value -= GSS_CALLING_ERROR(status_value);
+   }
+
+   /*** do sinfo bits (*message_context == 2 + number of bits done) */
+
+   tmp = GSS_SUPPLEMENTARY_INFO_FIELD(status_value);
+   /* mask off the bits which have been done */
+   if (*message_context > 2) {
+      tmp &= ~LSBMASK(*message_context-3);
+      status_value &= ~LSBMASK(*message_context-3);
+   }
+
+   if (!tmp) {
+      /* bogon input - there should be something left */
+      *minor_status = (OM_uint32) G_BAD_MSG_CTX;
+      return(GSS_S_FAILURE);
+   }
+
+   /* compute the bit offset */
+   /*SUPPRESS 570*/
+   for (bit=0; (((OM_uint32) 1)<<bit) != LSBGET(tmp); bit++) ;
+
+   /* print it */
+   if ((ret = display_bit(minor_status, bit, status_string)))
+      return(ret);
+
+   /* compute the new status_value/message_context */
+   status_value -= ((OM_uint32) 1)<<bit;
+
+   if (status_value) {
+      *message_context = bit+3;
+      return(GSS_S_COMPLETE);
+   } else {
+      *message_context = 0;
+      return(GSS_S_COMPLETE);
+   }
+}
diff --git a/mechglue/src/lib/gssapi/generic/gssapi.hin b/mechglue/src/lib/gssapi/generic/gssapi.hin
new file mode 100644
index 000000000..d3b93548e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/gssapi.hin
@@ -0,0 +1,796 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GSSAPI_H_
+#define _GSSAPI_H_
+
+/*
+ * Determine platform-dependent configuration.
+ */
+
+#if defined(__MACH__) && defined(__APPLE__)
+#	include <TargetConditionals.h>
+#	if TARGET_RT_MAC_CFM
+#		error "Use KfM 4.0 SDK headers for CFM compilation."
+#	endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if TARGET_OS_MAC
+#	pragma options align=mac68k
+#endif
+
+#if defined(_MSDOS) || defined(_WIN32)
+#include <win-mac.h>
+#define GSS_SIZEOF_SHORT SIZEOF_SHORT
+#define GSS_SIZEOF_LONG  SIZEOF_LONG
+#define GSS_SIZEOF_INT   SIZEOF_INT
+#endif
+
+#ifndef KRB5_CALLCONV
+#define KRB5_CALLCONV
+#define KRB5_CALLCONV_C
+#endif
+
+/*
+ * First, include stddef.h to get size_t defined.
+ */
+#include <stddef.h>
+
+/*
+ * POSIX says that sys/types.h is where size_t is defined.
+ */
+#include <sys/types.h>
+
+/*
+ * $Id$
+ */
+
+/*
+ * First, define the three platform-dependent pointer types.
+ */
+
+typedef void * gss_name_t;
+typedef void * gss_cred_id_t;
+typedef void * gss_ctx_id_t;
+
+/*
+ * The following type must be defined as the smallest natural unsigned integer
+ * supported by the platform that has at least 32 bits of precision.
+ */
+#if (GSS_SIZEOF_SHORT == 4)
+typedef unsigned short gss_uint32;
+typedef short gss_int32;
+#elif (GSS_SIZEOF_INT == 4)
+typedef unsigned int gss_uint32;
+typedef int gss_int32;
+#elif (GSS_SIZEOF_LONG == 4)
+typedef unsigned long gss_uint32;
+typedef long gss_int32;
+#endif
+
+#ifdef	OM_STRING
+/*
+ * We have included the xom.h header file.  Use the definition for
+ * OM_object identifier.
+ */
+typedef OM_object_identifier	gss_OID_desc, *gss_OID;
+#else	/* OM_STRING */
+/*
+ * We can't use X/Open definitions, so roll our own.
+ */
+typedef gss_uint32	OM_uint32;
+
+typedef struct gss_OID_desc_struct {
+      OM_uint32 length;
+      void *elements;
+} gss_OID_desc, *gss_OID;
+#endif	/* OM_STRING */
+
+typedef struct gss_OID_set_desc_struct  {
+      size_t  count;
+      gss_OID elements;
+} gss_OID_set_desc, *gss_OID_set;
+
+typedef struct gss_buffer_desc_struct {
+      size_t length;
+      void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+typedef struct gss_channel_bindings_struct {
+      OM_uint32 initiator_addrtype;
+      gss_buffer_desc initiator_address;
+      OM_uint32 acceptor_addrtype;
+      gss_buffer_desc acceptor_address;
+      gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+/*
+ * For now, define a QOP-type as an OM_uint32 (pending resolution of ongoing
+ * discussions).
+ */
+typedef	OM_uint32	gss_qop_t;
+typedef	int		gss_cred_usage_t;
+
+/*
+ * Flag bits for context-level services.
+ */
+#define GSS_C_DELEG_FLAG 1
+#define GSS_C_MUTUAL_FLAG 2
+#define GSS_C_REPLAY_FLAG 4
+#define GSS_C_SEQUENCE_FLAG 8
+#define GSS_C_CONF_FLAG 16
+#define GSS_C_INTEG_FLAG 32
+#define	GSS_C_ANON_FLAG 64
+#define GSS_C_PROT_READY_FLAG 128
+#define GSS_C_TRANS_FLAG 256
+
+/*
+ * Credential usage options
+ */
+#define GSS_C_BOTH 0
+#define GSS_C_INITIATE 1
+#define GSS_C_ACCEPT 2
+
+/*
+ * Status code types for gss_display_status
+ */
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+/*
+ * The constant definitions for channel-bindings address families
+ */
+#define GSS_C_AF_UNSPEC     0
+#define GSS_C_AF_LOCAL      1
+#define GSS_C_AF_INET       2
+#define GSS_C_AF_IMPLINK    3
+#define GSS_C_AF_PUP        4
+#define GSS_C_AF_CHAOS      5
+#define GSS_C_AF_NS         6
+#define GSS_C_AF_NBS        7
+#define GSS_C_AF_ECMA       8
+#define GSS_C_AF_DATAKIT    9
+#define GSS_C_AF_CCITT      10
+#define GSS_C_AF_SNA        11
+#define GSS_C_AF_DECnet     12
+#define GSS_C_AF_DLI        13
+#define GSS_C_AF_LAT        14
+#define GSS_C_AF_HYLINK     15
+#define GSS_C_AF_APPLETALK  16
+#define GSS_C_AF_BSC        17
+#define GSS_C_AF_DSS        18
+#define GSS_C_AF_OSI        19
+#define GSS_C_AF_X25        21
+
+#define GSS_C_AF_NULLADDR   255
+
+/*
+ * Various Null values.
+ */
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+/*
+ * Some alternate names for a couple of the above values.  These are defined
+ * for V1 compatibility.
+ */
+#define	GSS_C_NULL_OID		GSS_C_NO_OID
+#define	GSS_C_NULL_OID_SET	GSS_C_NO_OID_SET
+
+/*
+ * Define the default Quality of Protection for per-message services.  Note
+ * that an implementation that offers multiple levels of QOP may either reserve
+ * a value (for example zero, as assumed here) to mean "default protection", or
+ * alternatively may simply equate GSS_C_QOP_DEFAULT to a specific explicit
+ * QOP value.  However a value of 0 should always be interpreted by a GSSAPI
+ * implementation as a request for the default protection level.
+ */
+#define GSS_C_QOP_DEFAULT 0
+
+/*
+ * Expiration time of 2^32-1 seconds means infinite lifetime for a
+ * credential or security context
+ */
+#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful)
+
+
+/* Major status codes */
+
+#define GSS_S_COMPLETE 0
+
+/*
+ * Some "helper" definitions to make the status code macros obvious.
+ */
+#define GSS_C_CALLING_ERROR_OFFSET 24
+#define GSS_C_ROUTINE_ERROR_OFFSET 16
+#define GSS_C_SUPPLEMENTARY_OFFSET 0
+#define GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul)
+#define GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul)
+#define GSS_C_SUPPLEMENTARY_MASK ((OM_uint32) 0177777ul)
+
+/*
+ * The macros that test status codes for error conditions.  Note that the
+ * GSS_ERROR() macro has changed slightly from the V1 GSSAPI so that it now
+ * evaluates its argument only once.
+ */
+#define GSS_CALLING_ERROR(x) \
+  ((x) & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
+#define GSS_ROUTINE_ERROR(x) \
+  ((x) & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
+#define GSS_SUPPLEMENTARY_INFO(x) \
+  ((x) & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
+#define GSS_ERROR(x) \
+  ((x) & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
+	  (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
+
+/*
+ * Now the actual status code definitions
+ */
+
+/*
+ * Calling errors:
+ */
+#define GSS_S_CALL_INACCESSIBLE_READ \
+                             (((OM_uint32) 1ul) << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_INACCESSIBLE_WRITE \
+                             (((OM_uint32) 2ul) << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_BAD_STRUCTURE \
+                             (((OM_uint32) 3ul) << GSS_C_CALLING_ERROR_OFFSET)
+
+/*
+ * Routine errors:
+ */
+#define GSS_S_BAD_MECH (((OM_uint32) 1ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAME (((OM_uint32) 2ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAMETYPE (((OM_uint32) 3ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_BINDINGS (((OM_uint32) 4ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_STATUS (((OM_uint32) 5ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_SIG (((OM_uint32) 6ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CRED (((OM_uint32) 7ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CONTEXT (((OM_uint32) 8ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_TOKEN (((OM_uint32) 9ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_CREDENTIAL \
+     (((OM_uint32) 10ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CREDENTIALS_EXPIRED \
+     (((OM_uint32) 11ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CONTEXT_EXPIRED \
+     (((OM_uint32) 12ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_FAILURE (((OM_uint32) 13ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_QOP (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAUTHORIZED (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAVAILABLE (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DUPLICATE_ELEMENT \
+     (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NAME_NOT_MN \
+     (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+
+/*
+ * Supplementary info bits:
+ */
+#define GSS_S_CONTINUE_NEEDED (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
+#define GSS_S_DUPLICATE_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
+#define GSS_S_OLD_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
+#define GSS_S_UNSEQ_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
+#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
+
+
+/*
+ * Finally, function prototypes for the GSSAPI routines.
+ */
+
+#if defined (_WIN32) && defined (_MSC_VER)
+# ifdef GSS_DLL_FILE
+#  define GSS_DLLIMP __declspec(dllexport)
+# else
+#  define GSS_DLLIMP __declspec(dllimport)
+# endif
+#else
+# define GSS_DLLIMP
+#endif
+
+/* Reserved static storage for GSS_oids.  Comments are quotes from RFC 2744.
+ *
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) user_name(1)}.  The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_USER_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_MACHINE_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_STRING_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)).  The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc.  This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x04"}, corresponding to an
+ * object-identifier value of {iso(1) member-body(2)
+ * Unites States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}.  The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ * corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}.  The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_ANONYMOUS;
+
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ * corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}.  The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+GSS_DLLIMP extern gss_OID GSS_C_NT_EXPORT_NAME;
+
+/* Function Prototypes */
+
+OM_uint32 KRB5_CALLCONV gss_acquire_cred
+(OM_uint32 *,		/* minor_status */
+            gss_name_t,			/* desired_name */
+            OM_uint32,			/* time_req */
+            gss_OID_set,		/* desired_mechs */
+            gss_cred_usage_t,		/* cred_usage */
+            gss_cred_id_t *,	/* output_cred_handle */
+            gss_OID_set *,		/* actual_mechs */
+            OM_uint32 *		/* time_rec */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_release_cred
+(OM_uint32 *,		/* minor_status */
+            gss_cred_id_t *		/* cred_handle */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_init_sec_context
+(OM_uint32 *,		/* minor_status */
+            gss_cred_id_t,		/* claimant_cred_handle */
+            gss_ctx_id_t *,		/* context_handle */
+            gss_name_t,			/* target_name */
+            gss_OID,			/* mech_type (used to be const) */
+            OM_uint32,			/* req_flags */
+            OM_uint32,			/* time_req */
+            gss_channel_bindings_t,	/* input_chan_bindings */
+            gss_buffer_t,		/* input_token */
+            gss_OID *,		/* actual_mech_type */
+            gss_buffer_t,		/* output_token */
+            OM_uint32 *,		/* ret_flags */
+            OM_uint32 *		/* time_rec */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_accept_sec_context
+(OM_uint32 *,		/* minor_status */
+            gss_ctx_id_t *,		/* context_handle */
+            gss_cred_id_t,		/* acceptor_cred_handle */
+            gss_buffer_t,		/* input_token_buffer */
+            gss_channel_bindings_t,	/* input_chan_bindings */
+            gss_name_t *,		/* src_name */
+            gss_OID *,		/* mech_type */
+            gss_buffer_t,		/* output_token */
+            OM_uint32 *,		/* ret_flags */
+            OM_uint32 *,		/* time_rec */
+            gss_cred_id_t *		/* delegated_cred_handle */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_process_context_token
+(OM_uint32 *,		/* minor_status */
+            gss_ctx_id_t,		/* context_handle */
+            gss_buffer_t		/* token_buffer */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_delete_sec_context
+(OM_uint32 *,		/* minor_status */
+            gss_ctx_id_t *,		/* context_handle */
+            gss_buffer_t		/* output_token */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_context_time
+(OM_uint32 *,		/* minor_status */
+            gss_ctx_id_t,		/* context_handle */
+            OM_uint32 *		/* time_rec */
+           );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_get_mic
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_qop_t,			/* qop_req */
+	    gss_buffer_t,		/* message_buffer */
+	    gss_buffer_t		/* message_token */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_verify_mic
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_buffer_t,		/* message_buffer */
+	    gss_buffer_t,		/* message_token */
+	    gss_qop_t *			/* qop_state */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_wrap
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    int,			/* conf_req_flag */
+	    gss_qop_t,			/* qop_req */
+	    gss_buffer_t,		/* input_message_buffer */
+	    int *,			/* conf_state */
+	    gss_buffer_t		/* output_message_buffer */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_unwrap
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_buffer_t,		/* input_message_buffer */
+	    gss_buffer_t,		/* output_message_buffer */
+	    int *,			/* conf_state */
+	    gss_qop_t *		/* qop_state */
+	   );
+
+OM_uint32 KRB5_CALLCONV gss_display_status
+(OM_uint32 *,		/* minor_status */
+            OM_uint32,			/* status_value */
+            int,			/* status_type */
+            gss_OID,			/* mech_type (used to be const) */
+            OM_uint32 *,		/* message_context */
+            gss_buffer_t		/* status_string */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_indicate_mechs
+(OM_uint32 *,		/* minor_status */
+            gss_OID_set *		/* mech_set */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_compare_name
+(OM_uint32 *,		/* minor_status */
+            gss_name_t,			/* name1 */
+            gss_name_t,			/* name2 */
+            int *			/* name_equal */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_display_name
+(OM_uint32 *,		/* minor_status */
+            gss_name_t,			/* input_name */
+            gss_buffer_t,		/* output_name_buffer */
+            gss_OID *		/* output_name_type */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_import_name
+(OM_uint32 *,		/* minor_status */
+            gss_buffer_t,		/* input_name_buffer */
+            gss_OID,			/* input_name_type(used to be const) */
+            gss_name_t *		/* output_name */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_release_name
+(OM_uint32 *,		/* minor_status */
+            gss_name_t *		/* input_name */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_release_buffer
+(OM_uint32 *,		/* minor_status */
+            gss_buffer_t		/* buffer */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_release_oid_set
+(OM_uint32 *,		/* minor_status */
+            gss_OID_set * 		/* set */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_inquire_cred
+(OM_uint32 *,		/* minor_status */
+            gss_cred_id_t,		/* cred_handle */
+            gss_name_t *,		/* name */
+            OM_uint32 *,		/* lifetime */
+            gss_cred_usage_t *,	/* cred_usage */
+            gss_OID_set *		/* mechanisms */
+           );
+
+/* Last argument new for V2 */
+OM_uint32 KRB5_CALLCONV gss_inquire_context
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_name_t *,		/* src_name */
+	    gss_name_t *,		/* targ_name */
+	    OM_uint32 *,		/* lifetime_rec */
+	    gss_OID *,		/* mech_type */
+	    OM_uint32 *,		/* ctx_flags */
+	    int *,           	/* locally_initiated */
+	    int *			/* open */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_wrap_size_limit
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    int,			/* conf_req_flag */
+	    gss_qop_t,			/* qop_req */
+	    OM_uint32,			/* req_output_size */
+	    OM_uint32 *			/* max_input_size */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_import_name_object
+(OM_uint32 *,		/* minor_status */
+	    void *,			/* input_name */
+	    gss_OID,			/* input_name_type */
+	    gss_name_t *		/* output_name */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_export_name_object
+(OM_uint32 *,		/* minor_status */
+	    gss_name_t,			/* input_name */
+	    gss_OID,			/* desired_name_type */
+	    void **		/* output_name */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_add_cred
+(OM_uint32 *,		/* minor_status */
+	    gss_cred_id_t,		/* input_cred_handle */
+	    gss_name_t,			/* desired_name */
+	    gss_OID,			/* desired_mech */
+	    gss_cred_usage_t,		/* cred_usage */
+	    OM_uint32,			/* initiator_time_req */
+	    OM_uint32,			/* acceptor_time_req */
+	    gss_cred_id_t *,	/* output_cred_handle */
+	    gss_OID_set *,		/* actual_mechs */
+	    OM_uint32 *,		/* initiator_time_rec */
+	    OM_uint32 *		/* acceptor_time_rec */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_inquire_cred_by_mech
+(OM_uint32 *,		/* minor_status */
+	    gss_cred_id_t,		/* cred_handle */
+	    gss_OID,			/* mech_type */
+	    gss_name_t *,		/* name */
+	    OM_uint32 *,		/* initiator_lifetime */
+	    OM_uint32 *,		/* acceptor_lifetime */
+	    gss_cred_usage_t * 	/* cred_usage */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_export_sec_context
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t *,		/* context_handle */
+	    gss_buffer_t		/* interprocess_token */
+	    );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_import_sec_context
+(OM_uint32 *,		/* minor_status */
+	    gss_buffer_t,		/* interprocess_token */
+	    gss_ctx_id_t *		/* context_handle */
+	    );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_release_oid
+(OM_uint32 *,		/* minor_status */
+	    gss_OID *		/* oid */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_create_empty_oid_set
+(OM_uint32 *,		/* minor_status */
+	    gss_OID_set *		/* oid_set */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_add_oid_set_member
+(OM_uint32 *,		/* minor_status */
+	    gss_OID,			/* member_oid */
+	    gss_OID_set *		/* oid_set */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_test_oid_set_member
+(OM_uint32 *,		/* minor_status */
+	    gss_OID,			/* member */
+	    gss_OID_set,		/* set */
+	    int *			/* present */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_str_to_oid
+(OM_uint32 *,		/* minor_status */
+	    gss_buffer_t,		/* oid_str */
+	    gss_OID *		/* oid */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_oid_to_str
+(OM_uint32 *,		/* minor_status */
+	    gss_OID,			/* oid */
+	    gss_buffer_t		/* oid_str */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_inquire_names_for_mech
+(OM_uint32 *,		/* minor_status */
+	    gss_OID,			/* mechanism */
+	    gss_OID_set *		/* name_types */
+	   );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_inquire_mechs_for_name(
+    OM_uint32 *,		/* minor_status */
+    const gss_name_t,		/* input_name */
+    gss_OID_set *		/* mech_types */
+);
+
+/*
+ * The following routines are obsolete variants of gss_get_mic, gss_wrap,
+ * gss_verify_mic and gss_unwrap.  They should be provided by GSSAPI V2
+ * implementations for backwards compatibility with V1 applications.  Distinct
+ * entrypoints (as opposed to #defines) should be provided, to allow GSSAPI
+ * V1 applications to link against GSSAPI V2 implementations.
+ */
+OM_uint32 KRB5_CALLCONV gss_sign
+(OM_uint32 *,    /* minor_status */
+            gss_ctx_id_t,     	/* context_handle */
+            int,              	/* qop_req */
+            gss_buffer_t,     	/* message_buffer */
+            gss_buffer_t      	/* message_token */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_verify
+(OM_uint32 *,    /* minor_status */
+            gss_ctx_id_t,     	/* context_handle */
+            gss_buffer_t,     	/* message_buffer */
+            gss_buffer_t,     	/* token_buffer */
+            int *           /* qop_state */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_seal
+(OM_uint32 *,    /* minor_status */
+            gss_ctx_id_t,     	/* context_handle */
+            int,              	/* conf_req_flag */
+            int,              	/* qop_req */
+            gss_buffer_t,     	/* input_message_buffer */
+            int *,          /* conf_state */
+            gss_buffer_t      	/* output_message_buffer */
+           );
+
+OM_uint32 KRB5_CALLCONV gss_unseal
+(OM_uint32 *,    /* minor_status */
+            gss_ctx_id_t,     	/* context_handle */
+            gss_buffer_t,     	/* input_message_buffer */
+            gss_buffer_t,     	/* output_message_buffer */
+            int *,          /* conf_state */
+            int *           /* qop_state */
+           );
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_export_name
+(OM_uint32  *,		/* minor_status */
+		 const gss_name_t,	/* input_name */
+		 gss_buffer_t		/* exported_name */
+	);
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_duplicate_name
+(OM_uint32  *,		/* minor_status */
+		 const gss_name_t,	/* input_name */
+		 gss_name_t *		/* dest_name */
+	);
+
+/* New for V2 */
+OM_uint32 KRB5_CALLCONV gss_canonicalize_name
+(OM_uint32  *,		/* minor_status */
+		 const gss_name_t,	/* input_name */
+		 const gss_OID,		/* mech_type */
+		 gss_name_t *		/* output_name */
+	);
+
+#if TARGET_OS_MAC
+#  pragma options align=reset
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/* XXXX these are not part of the GSSAPI C bindings!  (but should be) */
+
+#define GSS_CALLING_ERROR_FIELD(x) \
+   (((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK)
+#define GSS_ROUTINE_ERROR_FIELD(x) \
+   (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK)
+#define GSS_SUPPLEMENTARY_INFO_FIELD(x) \
+   (((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK)
+
+/* XXXX This is a necessary evil until the spec is fixed */
+#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE
+
+#endif /* _GSSAPI_H_ */
diff --git a/mechglue/src/lib/gssapi/generic/gssapiP_generic.h b/mechglue/src/lib/gssapi/generic/gssapiP_generic.h
new file mode 100644
index 000000000..0af65df1b
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/gssapiP_generic.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GSSAPIP_GENERIC_H_
+#define _GSSAPIP_GENERIC_H_
+
+/*
+ * $Id$
+ */
+
+#if defined(_WIN32)
+#include "k5-int.h"
+#else
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#endif
+
+#include "k5-thread.h"
+
+#include "gssapi_generic.h"
+
+#include "gssapi_err_generic.h"
+#include <errno.h>
+
+#include "k5-platform.h"
+typedef UINT64_TYPE gssint_uint64;
+
+/** helper macros **/
+
+#define g_OID_equal(o1,o2) \
+   (((o1)->length == (o2)->length) && \
+    (memcmp((o1)->elements,(o2)->elements,(unsigned int) (o1)->length) == 0))
+
+/* this code knows that an int on the wire is 32 bits.  The type of
+   num should be at least this big, or the extra shifts may do weird
+   things */
+
+#define TWRITE_INT(ptr, num, bigend) \
+   (ptr)[0] = (char) ((bigend)?((num)>>24):((num)&0xff)); \
+   (ptr)[1] = (char) ((bigend)?(((num)>>16)&0xff):(((num)>>8)&0xff)); \
+   (ptr)[2] = (char) ((bigend)?(((num)>>8)&0xff):(((num)>>16)&0xff)); \
+   (ptr)[3] = (char) ((bigend)?((num)&0xff):((num)>>24)); \
+   (ptr) += 4;
+
+#define TWRITE_INT16(ptr, num, bigend) \
+   (ptr)[0] = (char) ((bigend)?((num)>>24):((num)&0xff)); \
+   (ptr)[1] = (char) ((bigend)?(((num)>>16)&0xff):(((num)>>8)&0xff)); \
+   (ptr) += 2;
+
+#define TREAD_INT(ptr, num, bigend) \
+   (num) = (((ptr)[0]<<((bigend)?24: 0)) | \
+            ((ptr)[1]<<((bigend)?16: 8)) | \
+            ((ptr)[2]<<((bigend)? 8:16)) | \
+            ((ptr)[3]<<((bigend)? 0:24))); \
+   (ptr) += 4;
+
+#define TREAD_INT16(ptr, num, bigend) \
+   (num) = (((ptr)[0]<<((bigend)?24: 0)) | \
+            ((ptr)[1]<<((bigend)?16: 8))); \
+   (ptr) += 2;
+
+#define TWRITE_STR(ptr, str, len) \
+   memcpy((ptr), (char *) (str), (len)); \
+   (ptr) += (len);
+
+#define TREAD_STR(ptr, str, len) \
+   (str) = (ptr); \
+   (ptr) += (len);
+
+#define TWRITE_BUF(ptr, buf, bigend) \
+   TWRITE_INT((ptr), (buf).length, (bigend)); \
+   TWRITE_STR((ptr), (buf).value, (buf).length);
+
+/** malloc wrappers; these may actually do something later */
+
+#define xmalloc(n) malloc(n)
+#define xrealloc(p,n) realloc(p,n)
+#ifdef xfree
+#undef xfree
+#endif
+#define xfree(p) free(p)
+
+/** helper functions **/
+
+/* hide names from applications, especially glib applications */
+#define	g_set_init		gssint_g_set_init
+#define	g_set_destroy		gssint_g_set_destroy
+#define	g_set_entry_add		gssint_g_set_entry_add
+#define	g_set_entry_delete	gssint_g_set_entry_delete
+#define	g_set_entry_get		gssint_g_set_entry_get
+#define	g_save_name		gssint_g_save_name
+#define	g_save_cred_id		gssint_g_save_cred_id
+#define	g_save_ctx_id		gssint_g_save_ctx_id
+#define	g_save_lucidctx_id	gssint_g_save_lucidctx_id
+#define	g_validate_name		gssint_g_validate_name
+#define	g_validate_cred_id	gssint_g_validate_cred_id
+#define	g_validate_ctx_id	gssint_g_validate_ctx_id
+#define	g_validate_lucidctx_id	gssint_g_validate_lucidctx_id
+#define	g_delete_name		gssint_g_delete_name
+#define	g_delete_cred_id	gssint_g_delete_cred_id
+#define	g_delete_ctx_id		gssint_g_delete_ctx_id
+#define	g_delete_lucidctx_id	gssint_g_delete_lucidctx_id
+#define	g_make_string_buffer	gssint_g_make_string_buffer
+#define	g_copy_OID_set		gssint_g_copy_OID_set
+#define	g_token_size		gssint_g_token_size
+#define	g_make_token_header	gssint_g_make_token_header
+#define	g_verify_token_header	gssint_g_verify_token_header
+#define	g_display_major_status	gssint_g_display_major_status
+#define	g_display_com_err_status gssint_g_display_com_err_status
+#define	g_order_init		gssint_g_order_init
+#define	g_order_check		gssint_g_order_check
+#define	g_order_free		gssint_g_order_free
+#define	g_queue_size		gssint_g_queue_size
+#define	g_queue_externalize	gssint_g_queue_externalize
+#define	g_queue_internalize	gssint_g_queue_internalize
+#define	g_canonicalize_host	gssint_g_canonicalize_host
+#define	g_local_host_name	gssint_g_local_host_name
+#define	g_strdup		gssint_g_strdup
+
+typedef struct _g_set_elt *g_set_elt;
+typedef struct {
+    k5_mutex_t mutex;
+    void *data;
+} g_set;
+#define G_SET_INIT { K5_MUTEX_PARTIAL_INITIALIZER, 0 }
+
+int g_set_init (g_set_elt *s);
+int g_set_destroy (g_set_elt *s);
+int g_set_entry_add (g_set_elt *s, void *key, void *value);
+int g_set_entry_delete (g_set_elt *s, void *key);
+int g_set_entry_get (g_set_elt *s, void *key, void **value);
+
+int g_save_name (g_set *vdb, gss_name_t *name);
+int g_save_cred_id (g_set *vdb, gss_cred_id_t *cred);
+int g_save_ctx_id (g_set *vdb, gss_ctx_id_t *ctx);
+int g_save_lucidctx_id (g_set *vdb, void *lctx);
+
+int g_validate_name (g_set *vdb, gss_name_t *name);
+int g_validate_cred_id (g_set *vdb, gss_cred_id_t *cred);
+int g_validate_ctx_id (g_set *vdb, gss_ctx_id_t *ctx);
+int g_validate_lucidctx_id (g_set *vdb, void *lctx);
+
+int g_delete_name (g_set *vdb, gss_name_t *name);
+int g_delete_cred_id (g_set *vdb, gss_cred_id_t *cred);
+int g_delete_ctx_id (g_set *vdb, gss_ctx_id_t *ctx);
+int g_delete_lucidctx_id (g_set *vdb, void *lctx);
+
+int g_make_string_buffer (const char *str, gss_buffer_t buffer);
+
+int g_copy_OID_set (const gss_OID_set_desc * const in, gss_OID_set *out);
+
+unsigned int g_token_size (gss_OID mech, unsigned int body_size);
+
+void g_make_token_header (gss_OID mech, unsigned int body_size,
+			  unsigned char **buf, int tok_type);
+
+gss_int32 g_verify_token_header (gss_OID mech, unsigned int *body_size,
+				 unsigned char **buf, int tok_type, 
+				 unsigned int toksize_in,
+				 int wrapper_required);
+
+OM_uint32 g_display_major_status (OM_uint32 *minor_status,
+				 OM_uint32 status_value,
+				 OM_uint32 *message_context,
+				 gss_buffer_t status_string);
+
+OM_uint32 g_display_com_err_status (OM_uint32 *minor_status,
+				   OM_uint32 status_value,
+				   gss_buffer_t status_string);
+
+gss_int32 g_order_init (void **queue, gssint_uint64 seqnum,
+				  int do_replay, int do_sequence, int wide);
+
+gss_int32 g_order_check (void **queue, gssint_uint64 seqnum);
+
+void g_order_free (void **queue);
+
+gss_uint32 g_queue_size(void *vqueue, size_t *sizep);
+gss_uint32 g_queue_externalize(void *vqueue, unsigned char **buf,
+			       size_t *lenremain);
+gss_uint32 g_queue_internalize(void **vqueue, unsigned char **buf,
+			       size_t *lenremain);
+
+char *g_strdup (char *str);
+
+/** declarations of internal name mechanism functions **/
+
+OM_uint32 generic_gss_release_buffer
+(OM_uint32*,       /* minor_status */
+            gss_buffer_t      /* buffer */
+           );
+
+OM_uint32 generic_gss_release_oid_set
+(OM_uint32*,       /* minor_status */
+            gss_OID_set*      /* set */
+           );
+
+OM_uint32 generic_gss_release_oid
+(OM_uint32*,       /* minor_status */
+            gss_OID*         /* set */
+           );
+
+OM_uint32 generic_gss_copy_oid
+(OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* oid */
+	    gss_OID *		/* new_oid */
+	    );
+
+OM_uint32 generic_gss_create_empty_oid_set
+(OM_uint32 *,	/* minor_status */
+	    gss_OID_set *	/* oid_set */
+	   );
+
+OM_uint32 generic_gss_add_oid_set_member
+(OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* member_oid */
+	    gss_OID_set *	/* oid_set */
+	   );
+
+OM_uint32 generic_gss_test_oid_set_member
+(OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* member */
+	    gss_OID_set,	/* set */
+	    int *		/* present */
+	   );
+
+OM_uint32 generic_gss_oid_to_str
+(OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* oid */
+	    gss_buffer_t	/* oid_str */
+	   );
+
+OM_uint32 generic_gss_str_to_oid
+(OM_uint32 *,	/* minor_status */
+	    gss_buffer_t,	/* oid_str */
+	    gss_OID *		/* oid */
+	   );
+
+#endif /* _GSSAPIP_GENERIC_H_ */
diff --git a/mechglue/src/lib/gssapi/generic/gssapi_err_generic.et b/mechglue/src/lib/gssapi/generic/gssapi_err_generic.et
new file mode 100644
index 000000000..3e976e3db
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/gssapi_err_generic.et
@@ -0,0 +1,49 @@
+# 
+# Copyright 1993 by OpenVision Technologies, Inc.
+# 
+# Permission to use, copy, modify, distribute, and sell this software
+# and its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appears in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of OpenVision not be used
+# in advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. OpenVision makes no
+# representations about the suitability of this software for any
+# purpose.  It is provided "as is" without express or implied warranty.
+# 
+# OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+# 
+
+#
+# $Id$
+#
+
+error_table ggss
+
+error_code G_BAD_SERVICE_NAME, "No @ in SERVICE-NAME name string"
+error_code G_BAD_STRING_UID, "STRING-UID-NAME contains nondigits"
+error_code G_NOUSER, "UID does not resolve to username"
+error_code G_VALIDATE_FAILED, "Validation error"
+error_code G_BUFFER_ALLOC, "Couldn't allocate gss_buffer_t data"
+error_code G_BAD_MSG_CTX, "Message context invalid"
+error_code G_WRONG_SIZE, "Buffer is the wrong size"
+error_code G_BAD_USAGE, "Credential usage type is unknown"
+error_code G_UNKNOWN_QOP, "Unknown quality of protection specified"
+error_code G_NO_HOSTNAME, "Local host name could not be determined"
+error_code G_BAD_HOSTNAME, "Hostname in SERVICE-NAME string could not be canonicalized"
+error_code G_WRONG_MECH, "Mechanism is incorrect"
+error_code G_BAD_TOK_HEADER, "Token header is malformed or corrupt"
+error_code G_BAD_DIRECTION, "Packet was replayed in wrong direction"
+error_code G_TOK_TRUNC, "Token is missing data"
+error_code G_REFLECT, "Token was reflected"
+error_code G_WRONG_TOKID, "Received token ID does not match expected token ID"
+error_code G_CRED_USAGE_MISMATCH, "The given credential's usage does not match the requested usage"
+error_code G_STORE_ACCEPTOR_CRED_NOSUPP, "Storing of acceptor credentials is not supported by the mechanism"
+error_code G_STORE_NON_DEFAULT_CRED_NOSUPP, "Storing of non-default credentials is not supported by the mechanism"
+end
diff --git a/mechglue/src/lib/gssapi/generic/gssapi_generic.c b/mechglue/src/lib/gssapi/generic/gssapi_generic.c
new file mode 100644
index 000000000..db92abb96
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/gssapi_generic.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_generic.h"
+
+/*
+ * See krb5/gssapi_krb5.c for a description of the algorithm for
+ * encoding an object identifier.
+ */
+
+/* Reserved static storage for GSS_oids.  Comments are quotes from RFC 2744. */
+
+#define oids ((gss_OID_desc *)const_oids)
+static const gss_OID_desc const_oids[] = {
+    /*
+     * The implementation must reserve static storage for a
+	 * gss_OID_desc object containing the value */
+    {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"},
+    /* corresponding to an object-identifier value of
+	 * {iso(1) member-body(2) United States(840) mit(113554)
+	 * infosys(1) gssapi(2) generic(1) user_name(1)}.  The constant
+	 * GSS_C_NT_USER_NAME should be initialized to point
+	 * to that gss_OID_desc.
+	 */                                
+    
+    /*
+	 * The implementation must reserve static storage for a
+	 * gss_OID_desc object containing the value */
+    {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"},
+    /* corresponding to an object-identifier value of
+	 * {iso(1) member-body(2) United States(840) mit(113554)
+	 * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+	 * The constant GSS_C_NT_MACHINE_UID_NAME should be
+	 * initialized to point to that gss_OID_desc.
+	 */
+     
+    /*
+    * The implementation must reserve static storage for a
+    * gss_OID_desc object containing the value */
+    {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03"},
+    /* corresponding to an object-identifier value of
+    * {iso(1) member-body(2) United States(840) mit(113554)
+    * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+    * The constant GSS_C_NT_STRING_UID_NAME should be
+    * initialized to point to that gss_OID_desc.
+    */
+    
+    /*
+     * The implementation must reserve static storage for a
+     * gss_OID_desc object containing the value */
+    {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+    /* corresponding to an object-identifier value of
+     * {iso(1) org(3) dod(6) internet(1) security(5)
+     * nametypes(6) gss-host-based-services(2)).  The constant
+     * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+     * to that gss_OID_desc.  This is a deprecated OID value, and
+     * implementations wishing to support hostbased-service names
+     * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+     * defined below, to identify such names;
+     * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+     * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+     * parameter, but should not be emitted by GSS-API
+     * implementations
+     */
+    
+    /*
+     * The implementation must reserve static storage for a
+     * gss_OID_desc object containing the value */
+    {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"}, 
+    /* corresponding to an object-identifier value of 
+     * {iso(1) member-body(2) Unites States(840) mit(113554) 
+     * infosys(1) gssapi(2) generic(1) service_name(4)}.  
+     * The constant GSS_C_NT_HOSTBASED_SERVICE should be 
+     * initialized to point to that gss_OID_desc.
+     */
+
+    /*
+     * The implementation must reserve static storage for a
+     * gss_OID_desc object containing the value */
+    {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+    /* corresponding to an object identifier value of
+     * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+     * 6(nametypes), 3(gss-anonymous-name)}.  The constant
+     * and GSS_C_NT_ANONYMOUS should be initialized to point
+     * to that gss_OID_desc.
+     */
+    
+    /*
+     * The implementation must reserve static storage for a
+     * gss_OID_desc object containing the value */
+    {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+    /* corresponding to an object-identifier value of
+     * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+     * 6(nametypes), 4(gss-api-exported-name)}.  The constant
+     * GSS_C_NT_EXPORT_NAME should be initialized to point
+     * to that gss_OID_desc.
+     */
+};
+
+/* Here are the constants which point to the static structure above.
+ *
+ * Constants of the form GSS_C_NT_* are specified by rfc 2744.
+ *
+ * Constants of the form gss_nt_* are the original MIT krb5 names 
+ * found in gssapi_generic.h.  They are provided for compatibility. */ 
+
+GSS_DLLIMP gss_OID GSS_C_NT_USER_NAME           = oids+0;
+GSS_DLLIMP gss_OID gss_nt_user_name             = oids+0;
+
+GSS_DLLIMP gss_OID GSS_C_NT_MACHINE_UID_NAME    = oids+1;
+GSS_DLLIMP gss_OID gss_nt_machine_uid_name      = oids+1;
+
+GSS_DLLIMP gss_OID GSS_C_NT_STRING_UID_NAME     = oids+2;
+GSS_DLLIMP gss_OID gss_nt_string_uid_name       = oids+2;
+
+GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE_X = oids+3;
+gss_OID gss_nt_service_name_v2       = oids+3;
+
+GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE   = oids+4;
+GSS_DLLIMP gss_OID gss_nt_service_name          = oids+4;
+
+GSS_DLLIMP gss_OID GSS_C_NT_ANONYMOUS           = oids+5;
+
+GSS_DLLIMP gss_OID GSS_C_NT_EXPORT_NAME         = oids+6;
+gss_OID gss_nt_exported_name         = oids+6;
diff --git a/mechglue/src/lib/gssapi/generic/gssapi_generic.h b/mechglue/src/lib/gssapi/generic/gssapi_generic.h
new file mode 100644
index 000000000..bf3c2af59
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/gssapi_generic.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GSSAPI_GENERIC_H_
+#define _GSSAPI_GENERIC_H_
+
+/*
+ * $Id$
+ */
+
+#include <gssapi/gssapi.h>
+
+#if defined(__cplusplus) && !defined(GSSAPIGENERIC_BEGIN_DECLS)
+#define GSSAPIGENERIC_BEGIN_DECLS	extern "C" {
+#define GSSAPIGENERIC_END_DECLS	}
+#else
+#define GSSAPIGENERIC_BEGIN_DECLS
+#define GSSAPIGENERIC_END_DECLS
+#endif
+
+GSSAPIGENERIC_BEGIN_DECLS
+
+/* Deprecated MIT krb5 oid names provided for compatibility.
+ * The correct oids (GSS_C_NT_USER_NAME, etc) from rfc 2744 
+ * are defined in gssapi.h. */
+
+GSS_DLLIMP extern gss_OID gss_nt_user_name;
+GSS_DLLIMP extern gss_OID gss_nt_machine_uid_name;
+GSS_DLLIMP extern gss_OID gss_nt_string_uid_name;
+extern gss_OID gss_nt_service_name_v2;
+GSS_DLLIMP extern gss_OID gss_nt_service_name;
+extern gss_OID gss_nt_exported_name;
+
+GSSAPIGENERIC_END_DECLS
+
+#endif /* _GSSAPI_GENERIC_H_ */
diff --git a/mechglue/src/lib/gssapi/generic/oid_ops.c b/mechglue/src/lib/gssapi/generic/oid_ops.c
new file mode 100644
index 000000000..a73589879
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/oid_ops.c
@@ -0,0 +1,388 @@
+/*
+ * lib/gssapi/generic/oid_ops.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
+ */
+
+#include "gssapiP_generic.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+OM_uint32
+generic_gss_release_oid(minor_status, oid)
+    OM_uint32	*minor_status;
+    gss_OID	*oid;
+{
+    *minor_status = 0;
+
+    if (*oid == GSS_C_NO_OID)
+	return(GSS_S_COMPLETE);
+
+    /*
+     * The V2 API says the following!
+     *
+     * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
+     * and will silently ignore attempts to free these OIDs; for other OIDs
+     * it will call the C free() routine for both the OID data and the
+     * descriptor.  This allows applications to freely mix their own heap-
+     * allocated OID values with OIDs returned by GSS-API.
+     */
+    if ((*oid != gss_nt_user_name) &&
+	(*oid != gss_nt_machine_uid_name) &&
+	(*oid != gss_nt_string_uid_name) &&
+	(*oid != gss_nt_service_name) &&
+	(*oid != gss_nt_exported_name) &&
+	(*oid != gss_nt_service_name_v2)) {
+	free((*oid)->elements);
+	free(*oid);
+    }
+    *oid = GSS_C_NO_OID;
+    return(GSS_S_COMPLETE);
+}
+
+OM_uint32
+generic_gss_copy_oid(minor_status, oid, new_oid)
+	OM_uint32	*minor_status;
+	gss_OID		oid, *new_oid;
+{
+	gss_OID		p;
+
+	p = (gss_OID) malloc(sizeof(gss_OID_desc));
+	if (!p) {
+		*minor_status = ENOMEM;
+		return GSS_S_FAILURE;
+	}
+	p->length = oid->length;
+	p->elements = malloc(p->length);
+	if (!p->elements) {
+		free(p);
+		*minor_status = ENOMEM;
+		return GSS_S_FAILURE;
+	}
+	memcpy(p->elements, oid->elements, p->length);
+	*new_oid = p;
+	return(GSS_S_COMPLETE);
+}
+
+
+OM_uint32
+generic_gss_create_empty_oid_set(minor_status, oid_set)
+    OM_uint32	*minor_status;
+    gss_OID_set	*oid_set;
+{
+    if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) {
+	memset(*oid_set, 0, sizeof(gss_OID_set_desc));
+	*minor_status = 0;
+	return(GSS_S_COMPLETE);
+    }
+    else {
+	*minor_status = ENOMEM;
+	return(GSS_S_FAILURE);
+    }
+}
+
+OM_uint32
+generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
+    OM_uint32	*minor_status;
+    gss_OID	member_oid;
+    gss_OID_set	*oid_set;
+{
+    gss_OID	elist;
+    gss_OID	lastel;
+
+    elist = (*oid_set)->elements;
+    /* Get an enlarged copy of the array */
+    if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
+						  sizeof(gss_OID_desc)))) {
+	/* Copy in the old junk */
+	if (elist)
+	    memcpy((*oid_set)->elements,
+		   elist,
+		   ((*oid_set)->count * sizeof(gss_OID_desc)));
+
+	/* Duplicate the input element */
+	lastel = &(*oid_set)->elements[(*oid_set)->count];
+	if ((lastel->elements =
+	     (void *) malloc((size_t) member_oid->length))) {
+	    /* Success - copy elements */
+	    memcpy(lastel->elements, member_oid->elements,
+		   (size_t) member_oid->length);
+	    /* Set length */
+	    lastel->length = member_oid->length;
+
+	    /* Update count */
+	    (*oid_set)->count++;
+	    if (elist)
+		free(elist);
+	    *minor_status = 0;
+	    return(GSS_S_COMPLETE);
+	}
+	else
+	    free((*oid_set)->elements);
+    }
+    /* Failure - restore old contents of list */
+    (*oid_set)->elements = elist;
+    *minor_status = ENOMEM;
+    return(GSS_S_FAILURE);
+}
+
+OM_uint32
+generic_gss_test_oid_set_member(minor_status, member, set, present)
+    OM_uint32	*minor_status;
+    gss_OID	member;
+    gss_OID_set	set;
+    int		*present;
+{
+    size_t	i;
+    int		result;
+
+    result = 0;
+    for (i=0; i<set->count; i++) {
+	if ((set->elements[i].length == member->length) &&
+	    !memcmp(set->elements[i].elements,
+		    member->elements,
+		    (size_t) member->length)) {
+	    result = 1;
+	    break;
+	}
+    }
+    *present = result;
+    *minor_status = 0;
+    return(GSS_S_COMPLETE);
+}
+
+/*
+ * OID<->string routines.  These are uuuuugly.
+ */
+OM_uint32
+generic_gss_oid_to_str(minor_status, oid, oid_str)
+    OM_uint32		*minor_status;
+    gss_OID		oid;
+    gss_buffer_t	oid_str;
+{
+    char		numstr[128];
+    unsigned long	number;
+    int			numshift;
+    size_t		string_length;
+    size_t		i;
+    unsigned char	*cp;
+    char		*bp;
+
+    /* Decoded according to krb5/gssapi_krb5.c */
+
+    /* First determine the size of the string */
+    string_length = 0;
+    number = 0;
+    numshift = 0;
+    cp = (unsigned char *) oid->elements;
+    number = (unsigned long) cp[0];
+    sprintf(numstr, "%ld ", number/40);
+    string_length += strlen(numstr);
+    sprintf(numstr, "%ld ", number%40);
+    string_length += strlen(numstr);
+    for (i=1; i<oid->length; i++) {
+	if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) {
+	    number = (number << 7) | (cp[i] & 0x7f);
+	    numshift += 7;
+	}
+	else {
+	    *minor_status = EINVAL;
+	    return(GSS_S_FAILURE);
+	}
+	if ((cp[i] & 0x80) == 0) {
+	    sprintf(numstr, "%ld ", number);
+	    string_length += strlen(numstr);
+	    number = 0;
+	    numshift = 0;
+	}
+    }
+    /*
+     * If we get here, we've calculated the length of "n n n ... n ".  Add 4
+     * here for "{ " and "}\0".
+     */
+    string_length += 4;
+    if ((bp = (char *) malloc(string_length))) {
+	strcpy(bp, "{ ");
+	number = (unsigned long) cp[0];
+	sprintf(numstr, "%ld ", number/40);
+	strcat(bp, numstr);
+	sprintf(numstr, "%ld ", number%40);
+	strcat(bp, numstr);
+	number = 0;
+	cp = (unsigned char *) oid->elements;
+	for (i=1; i<oid->length; i++) {
+	    number = (number << 7) | (cp[i] & 0x7f);
+	    if ((cp[i] & 0x80) == 0) {
+		sprintf(numstr, "%ld ", number);
+		strcat(bp, numstr);
+		number = 0;
+	    }
+	}
+	strcat(bp, "}");
+	oid_str->length = strlen(bp)+1;
+	oid_str->value = (void *) bp;
+	*minor_status = 0;
+	return(GSS_S_COMPLETE);
+    }
+    *minor_status = ENOMEM;
+    return(GSS_S_FAILURE);
+}
+
+OM_uint32
+generic_gss_str_to_oid(minor_status, oid_str, oid)
+    OM_uint32		*minor_status;
+    gss_buffer_t	oid_str;
+    gss_OID		*oid;
+{
+    char	*cp, *bp, *startp;
+    int		brace;
+    long	numbuf;
+    long	onumbuf;
+    OM_uint32	nbytes;
+    int		idx;
+    unsigned char *op;
+
+    brace = 0;
+    bp = (char *) oid_str->value;
+    cp = bp;
+    /* Skip over leading space */
+    while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
+	bp++;
+    if (*bp == '{') {
+	brace = 1;
+	bp++;
+    }
+    while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
+	bp++;
+    startp = bp;
+    nbytes = 0;
+
+    /*
+     * The first two numbers are chewed up by the first octet.
+     */
+    if (sscanf(bp, "%ld", &numbuf) != 1) {
+	*minor_status = EINVAL;
+	return(GSS_S_FAILURE);
+    }
+    while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
+	bp++;
+    while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
+	bp++;
+    if (sscanf(bp, "%ld", &numbuf) != 1) {
+	*minor_status = EINVAL;
+	return(GSS_S_FAILURE);
+    }
+    while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
+	bp++;
+    while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
+	bp++;
+    nbytes++;
+    while (isdigit((int) *bp)) {
+	if (sscanf(bp, "%ld", &numbuf) != 1) {
+	    *minor_status = EINVAL;
+	    return(GSS_S_FAILURE);
+	}
+	while (numbuf) {
+	    nbytes++;
+	    numbuf >>= 7;
+	}
+	while ((bp < &cp[oid_str->length]) && isdigit((int) *bp))
+	    bp++;
+	while ((bp < &cp[oid_str->length]) && isspace((int) *bp))
+	    bp++;
+    }
+    if (brace && (*bp != '}')) {
+	*minor_status = EINVAL;
+	return(GSS_S_FAILURE);
+    }
+
+    /*
+     * Phew!  We've come this far, so the syntax is good.
+     */
+    if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
+	if (((*oid)->elements = (void *) malloc((size_t) nbytes))) {
+	    (*oid)->length = nbytes;
+	    op = (unsigned char *) (*oid)->elements;
+	    bp = startp;
+	    sscanf(bp, "%ld", &numbuf);
+	    while (isdigit((int) *bp))
+		bp++;
+	    while (isspace((int) *bp))
+		bp++;
+	    onumbuf = 40*numbuf;
+	    sscanf(bp, "%ld", &numbuf);
+	    onumbuf += numbuf;
+	    *op = (unsigned char) onumbuf;
+	    op++;
+	    while (isdigit((int) *bp))
+		bp++;
+	    while (isspace((int) *bp))
+		bp++;
+	    while (isdigit((int) *bp)) {
+		sscanf(bp, "%ld", &numbuf);
+		nbytes = 0;
+		/* Have to fill in the bytes msb-first */
+		onumbuf = numbuf;
+		while (numbuf) {
+		    nbytes++;
+		    numbuf >>= 7;
+		}
+		numbuf = onumbuf;
+		op += nbytes;
+		idx = -1;
+		while (numbuf) {
+		    op[idx] = (unsigned char) numbuf & 0x7f;
+		    if (idx != -1)
+			op[idx] |= 0x80;
+		    idx--;
+		    numbuf >>= 7;
+		}
+		while (isdigit((int) *bp))
+		    bp++;
+		while (isspace((int) *bp))
+		    bp++;
+	    }
+	    *minor_status = 0;
+	    return(GSS_S_COMPLETE);
+	}
+	else {
+	    free(*oid);
+	    *oid = GSS_C_NO_OID;
+	}
+    }
+    *minor_status = ENOMEM;
+    return(GSS_S_FAILURE);
+}
+
diff --git a/mechglue/src/lib/gssapi/generic/rel_buffer.c b/mechglue/src/lib/gssapi/generic/rel_buffer.c
new file mode 100644
index 000000000..555888184
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/rel_buffer.c
@@ -0,0 +1,57 @@
+/* #ident  "@(#)g_rel_buffer.c 1.2     96/02/06 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_release_buffer
+ */
+
+#include "gssapiP_generic.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32
+generic_gss_release_buffer (minor_status,
+			    buffer)
+     OM_uint32 *		minor_status;
+     gss_buffer_t		buffer;
+{
+    if (minor_status)
+	*minor_status = 0;
+
+    /* if buffer is NULL, return */
+
+    if (buffer == GSS_C_NO_BUFFER)
+	return(GSS_S_COMPLETE);
+
+    if (buffer->value) {
+	free(buffer->value);
+	buffer->length = 0;
+	buffer->value = NULL;
+    }
+
+    return (GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/generic/rel_oid_set.c b/mechglue/src/lib/gssapi/generic/rel_oid_set.c
new file mode 100644
index 000000000..bd7f3cb2c
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/rel_oid_set.c
@@ -0,0 +1,61 @@
+/* #ident  "@(#)gss_release_oid_set.c 1.12     95/08/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_release_oid_set
+ */
+
+#include "gssapiP_generic.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32
+generic_gss_release_oid_set (minor_status,
+			     set)
+     OM_uint32 *		minor_status;
+     gss_OID_set *		set;
+{
+    size_t i;
+    if (minor_status)
+	*minor_status = 0;
+
+    if (set == NULL)
+	return(GSS_S_COMPLETE);
+
+    if (*set == GSS_C_NULL_OID_SET)
+	return(GSS_S_COMPLETE);
+
+    for (i=0; i<(*set)->count; i++)
+	free((*set)->elements[i].elements);
+
+    free((*set)->elements);
+    free(*set);
+
+    *set = GSS_C_NULL_OID_SET;
+    
+    return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/generic/util_buffer.c b/mechglue/src/lib/gssapi/generic/util_buffer.c
new file mode 100644
index 000000000..77cb2eb2f
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/util_buffer.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_generic.h"
+#include <string.h>
+
+/* return nonzero on success, 0 on failure
+   make sure that buffer is consistent (release'able) when this
+   function exits, no matter what the exit value */
+
+int g_make_string_buffer(str, buffer)
+     const char *str;
+     gss_buffer_t buffer;
+{
+   buffer->length = strlen(str);
+
+   if ((buffer->value = (void *) xmalloc(buffer->length + 1)) == NULL) {
+      buffer->length = 0;
+      return(0);
+   }
+
+   strcpy(buffer->value, str);
+
+   return(1);
+}
diff --git a/mechglue/src/lib/gssapi/generic/util_canonhost.c b/mechglue/src/lib/gssapi/generic/util_canonhost.c
new file mode 100644
index 000000000..829311db9
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/util_canonhost.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+/* This file could be OS specific */
+
+#include "gssapiP_generic.h"
+
+#include "port-sockets.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <ctype.h>
+#include <string.h>
+
+char *
+g_canonicalize_host(hostname)
+     char *hostname;
+{
+   struct hostent *hent;
+   char *haddr;
+   char *canon, *str;
+
+   if ((hent = gethostbyname(hostname)) == NULL)
+      return(NULL);
+
+   if (! (haddr = (char *) xmalloc(hent->h_length))) {
+	return(NULL);
+   }
+
+   memcpy(haddr, hent->h_addr_list[0], hent->h_length);
+
+   if (! (hent = gethostbyaddr(haddr, hent->h_length, hent->h_addrtype))) {
+	return(NULL);
+   }
+
+   xfree(haddr);
+
+   if ((canon = (char *) xmalloc(strlen(hent->h_name)+1)) == NULL)
+      return(NULL);
+
+   strcpy(canon, hent->h_name);
+
+   for (str = canon; *str; str++)
+      if (isupper(*str)) *str = tolower(*str);
+
+   return(canon);
+}
diff --git a/mechglue/src/lib/gssapi/generic/util_localhost.c b/mechglue/src/lib/gssapi/generic/util_localhost.c
new file mode 100644
index 000000000..13856e320
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/util_localhost.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+/* This file could be OS specific */
+
+#include <sys/param.h>
+
+#include "gssapiP_generic.h"
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+char *g_local_host_name()
+{
+     char buf[MAXHOSTNAMELEN+1], *ptr;
+
+     if (gethostname(buf, sizeof(buf)) < 0)
+	  return 0;
+
+     buf[sizeof(buf)-1] = '\0';
+
+     if (! (ptr = xmalloc(strlen(buf) + 1)))
+	  return 0;
+
+     return strcpy(ptr, buf);
+}
diff --git a/mechglue/src/lib/gssapi/generic/util_oid.c b/mechglue/src/lib/gssapi/generic/util_oid.c
new file mode 100644
index 000000000..60b1e157e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/util_oid.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_generic.h"
+#include "string.h"
+
+/*
+ * $Id$
+ */
+
+int
+g_copy_OID_set(in, out)
+     const gss_OID_set_desc * const in;
+     gss_OID_set *out;
+{
+   gss_OID_set copy;
+   gss_OID     new_oid;
+   size_t      i;
+   size_t      len;
+
+   *out = NULL;
+
+   if ((copy =
+	(gss_OID_set_desc *) xmalloc(sizeof(gss_OID_set_desc))) == NULL)
+      return(0);
+
+   copy->count = in->count;
+   len = sizeof(gss_OID_desc) * copy->count;
+
+   if ((copy->elements = 
+	(gss_OID_desc *) xmalloc( len )) == NULL) {
+      xfree(copy);
+      return(0);
+   }
+
+   memset( copy->elements, 0, len );
+   
+   for (i=0; i<in->count; i++) {
+      len = in->elements[i].length;
+      new_oid = &(copy->elements[i]);
+      new_oid->elements = xmalloc( len );
+      if ( new_oid->elements == NULL ) {
+         while( i>0 ) {
+            i--;
+            new_oid = &(copy->elements[i]);
+            if ( new_oid->elements!=NULL )
+               xfree( new_oid->elements );
+         }
+         xfree( copy->elements );
+         xfree( copy );
+         return( 0 );
+      }
+      memcpy( new_oid->elements, in->elements[i].elements, len );
+      new_oid->length = len;
+   }
+
+   *out = copy;
+   return(1);
+}
diff --git a/mechglue/src/lib/gssapi/generic/util_ordering.c b/mechglue/src/lib/gssapi/generic/util_ordering.c
new file mode 100644
index 000000000..f7cf66678
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/util_ordering.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+/*
+ * functions to check sequence numbers for replay and sequencing
+ */
+
+#include "gssapiP_generic.h"
+#include <string.h>
+
+#define QUEUE_LENGTH 20
+
+typedef struct _queue {
+   int do_replay;
+   int do_sequence;
+   int start;
+   int length;
+   gssint_uint64 firstnum;
+   /* Stored as deltas from firstnum.  This way, the high bit won't
+      overflow unless we've actually gone through 2**n messages, or
+      gotten something *way* out of sequence.  */
+   gssint_uint64 elem[QUEUE_LENGTH];
+   /* All ones for 64-bit sequence numbers; 32 ones for 32-bit
+      sequence numbers.  */
+   gssint_uint64 mask;
+} queue;
+
+/* rep invariant:
+ *  - the queue is a circular queue.  The first element (q->elem[q->start])
+ * is the oldest.  The last element is the newest.
+ */
+
+#define QSIZE(q) (sizeof((q)->elem)/sizeof((q)->elem[0]))
+#define QELEM(q,i) ((q)->elem[(i)%QSIZE(q)])
+
+static void
+queue_insert(queue *q, int after, gssint_uint64 seqnum)
+{
+   /* insert.  this is not the fastest way, but it's easy, and it's
+      optimized for insert at end, which is the common case */
+   int i;
+
+   /* common case: at end, after == q->start+q->length-1 */
+
+   /* move all the elements (after,last] up one slot */
+
+   for (i=q->start+q->length-1; i>after; i--)
+      QELEM(q,i+1) = QELEM(q,i);
+
+   /* fill in slot after+1 */
+
+   QELEM(q,after+1) = seqnum;
+
+   /* Either increase the length by one, or move the starting point up
+      one (deleting the first element, which got bashed above), as
+      appropriate. */
+
+   if (q->length == QSIZE(q)) {
+      q->start++;
+      if (q->start == QSIZE(q))
+	 q->start = 0;
+   } else {
+      q->length++;
+   }
+}
+
+gss_int32
+g_order_init(void **vqueue, gssint_uint64 seqnum,
+	     int do_replay, int do_sequence, int wide_nums)
+{
+   queue *q;
+
+   if ((q = (queue *) malloc(sizeof(queue))) == NULL)
+      return(ENOMEM);
+
+   q->do_replay = do_replay;
+   q->do_sequence = do_sequence;
+   q->mask = wide_nums ? ~(gssint_uint64)0 : 0xffffffffUL;
+
+   q->start = 0;
+   q->length = 1;
+   q->firstnum = seqnum;
+   q->elem[q->start] = ((gssint_uint64)0 - 1) & q->mask;
+
+   *vqueue = (void *) q;
+   return(0);
+}
+
+gss_int32
+g_order_check(void **vqueue, gssint_uint64 seqnum)
+{
+   queue *q;
+   int i;
+   gssint_uint64 expected;
+
+   q = (queue *) (*vqueue);
+
+   if (!q->do_replay && !q->do_sequence)
+      return(GSS_S_COMPLETE);
+
+   /* All checks are done relative to the initial sequence number, to
+      avoid (or at least put off) the pain of wrapping.  */
+   seqnum -= q->firstnum;
+   /* If we're only doing 32-bit values, adjust for that again.
+
+      Note that this will probably be the wrong thing to if we get
+      2**32 messages sent with 32-bit sequence numbers.  */
+   seqnum &= q->mask;
+
+   /* rule 1: expected sequence number */
+
+   expected = (QELEM(q,q->start+q->length-1)+1) & q->mask;
+   if (seqnum == expected) { 
+      queue_insert(q, q->start+q->length-1, seqnum);
+      return(GSS_S_COMPLETE);
+   }
+
+   /* rule 2: > expected sequence number */
+
+   if ((seqnum > expected)) {
+      queue_insert(q, q->start+q->length-1, seqnum);
+      if (q->do_replay && !q->do_sequence)
+	 return(GSS_S_COMPLETE);
+      else
+	 return(GSS_S_GAP_TOKEN);
+   }
+
+   /* rule 3: seqnum < seqnum(first) */
+
+   if ((seqnum < QELEM(q,q->start)) &&
+       /* Is top bit of whatever width we're using set?
+
+	  We used to check for greater than or equal to firstnum, but
+	  (1) we've since switched to compute values relative to
+	  firstnum, so the lowest we can have is 0, and (2) the effect
+	  of the original scheme was highly dependent on whether
+	  firstnum was close to either side of 0.  (Consider
+	  firstnum==0xFFFFFFFE and we miss three packets; the next
+	  packet is *new* but would look old.)
+
+          This check should give us 2**31 or 2**63 messages "new", and
+          just as many "old".  That's not quite right either.  */
+       (seqnum & (1 + (q->mask >> 1)))
+       ) {
+      if (q->do_replay && !q->do_sequence)
+	 return(GSS_S_OLD_TOKEN);
+      else
+	 return(GSS_S_UNSEQ_TOKEN);
+   }
+
+   /* rule 4+5: seqnum in [seqnum(first),seqnum(last)]  */
+
+   else {
+      if (seqnum == QELEM(q,q->start+q->length-1))
+	 return(GSS_S_DUPLICATE_TOKEN);
+
+      for (i=q->start; i<q->start+q->length-1; i++) {
+	 if (seqnum == QELEM(q,i))
+	    return(GSS_S_DUPLICATE_TOKEN);
+	 if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) {
+	    queue_insert(q, i, seqnum);
+	    if (q->do_replay && !q->do_sequence)
+	       return(GSS_S_COMPLETE);
+	    else
+	       return(GSS_S_UNSEQ_TOKEN);
+	 }
+      }
+   }
+
+   /* this should never happen */
+   return(GSS_S_FAILURE);
+}
+
+void
+g_order_free(void **vqueue)
+{
+   queue *q;
+   
+   q = (queue *) (*vqueue);
+
+   free(q);
+
+   *vqueue = NULL;
+}
+
+/*
+ * These support functions are for the serialization routines
+ */
+gss_uint32
+g_queue_size(void *vqueue, size_t *sizep)
+{
+    *sizep += sizeof(queue);
+    return 0;
+}
+
+gss_uint32
+g_queue_externalize(void *vqueue, unsigned char **buf, size_t *lenremain)
+{
+    if (*lenremain < sizeof(queue))
+	return ENOMEM;
+    memcpy(*buf, vqueue, sizeof(queue));
+    *buf += sizeof(queue);
+    *lenremain -= sizeof(queue);
+    
+    return 0;
+}
+
+gss_uint32
+g_queue_internalize(void **vqueue, unsigned char **buf, size_t *lenremain)
+{
+    void *q;
+
+    if (*lenremain < sizeof(queue))
+	return EINVAL;
+    if ((q = malloc(sizeof(queue))) == 0)
+	return ENOMEM;
+    memcpy(q, *buf, sizeof(queue));
+    *buf += sizeof(queue);
+    *lenremain -= sizeof(queue);
+    *vqueue = q;
+    return 0;
+}
diff --git a/mechglue/src/lib/gssapi/generic/util_set.c b/mechglue/src/lib/gssapi/generic/util_set.c
new file mode 100644
index 000000000..fea810852
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/util_set.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 1995 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_generic.h"
+
+struct _g_set_elt {
+   void *key;
+   void *value;
+   struct _g_set_elt *next;
+};
+
+int g_set_init(g_set_elt *s)
+{
+   *s = NULL;
+
+   return(0);
+}
+
+#if 0
+int g_set_destroy(g_set_elt *s)
+{
+   g_set next;
+
+   while (*s) {
+      next = (*s)->next;
+      free(*s);
+      *s = next;
+   }
+
+   return(0);
+}
+#endif
+
+int g_set_entry_add(g_set_elt *s, void *key, void *value)
+{
+   g_set_elt first;
+
+   if ((first = (struct _g_set_elt *) malloc(sizeof(struct _g_set_elt))) == NULL)
+      return(ENOMEM);
+
+   first->key = key;
+   first->value = value;
+   first->next = *s;
+
+   *s = first;
+
+   return(0);
+}
+
+int g_set_entry_delete(g_set_elt *s, void *key)
+{
+   g_set_elt *p;
+
+   for (p=s; *p; p = &((*p)->next)) {
+      if ((*p)->key == key) {
+	 g_set_elt next = (*p)->next;
+	 free(*p);
+	 *p = next;
+
+	 return(0);
+      }
+   }
+
+   return(-1);
+}
+
+int g_set_entry_get(g_set_elt *s, void *key, void **value)
+{
+   g_set_elt p;
+
+   for (p = *s; p; p = p->next) {
+      if (p->key == key) {
+	 *value = p->value;
+
+	 return(0);
+      }
+   }
+
+   *value = NULL;
+
+   return(-1);
+}
diff --git a/mechglue/src/lib/gssapi/generic/util_token.c b/mechglue/src/lib/gssapi/generic/util_token.c
new file mode 100644
index 000000000..97a788c09
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/util_token.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_generic.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/*
+ * $Id$
+ */
+
+/* XXXX this code currently makes the assumption that a mech oid will
+   never be longer than 127 bytes.  This assumption is not inherent in
+   the interfaces, so the code can be fixed if the OSI namespace
+   balloons unexpectedly. */
+
+/* Each token looks like this:
+
+0x60				tag for APPLICATION 0, SEQUENCE
+					(constructed, definite-length)
+	<length>		possible multiple bytes, need to parse/generate
+	0x06			tag for OBJECT IDENTIFIER
+		<moid_length>	compile-time constant string (assume 1 byte)
+		<moid_bytes>	compile-time constant string
+	<inner_bytes>		the ANY containing the application token
+					bytes 0,1 are the token type
+					bytes 2,n are the token data
+
+Note that the token type field is a feature of RFC 1964 mechanisms and
+is not used by other GSSAPI mechanisms.  As such, a token type of -1
+is interpreted to mean that no token type should be expected or
+generated. 
+
+For the purposes of this abstraction, the token "header" consists of
+the sequence tag and length octets, the mech OID DER encoding, and the
+first two inner bytes, which indicate the token type.  The token
+"body" consists of everything else.
+
+*/
+
+static unsigned int der_length_size(length)
+     int length;
+{
+   if (length < (1<<7))
+      return(1);
+   else if (length < (1<<8))
+      return(2);
+#if (SIZEOF_INT == 2)
+   else
+       return(3);
+#else
+   else if (length < (1<<16))
+      return(3);
+   else if (length < (1<<24))
+      return(4);
+   else
+      return(5);
+#endif
+}
+
+static void der_write_length(buf, length)
+     unsigned char **buf;
+     int length;
+{
+   if (length < (1<<7)) {
+      *(*buf)++ = (unsigned char) length;
+   } else {
+      *(*buf)++ = (unsigned char) (der_length_size(length)+127);
+#if (SIZEOF_INT > 2)
+      if (length >= (1<<24))
+	 *(*buf)++ = (unsigned char) (length>>24);
+      if (length >= (1<<16))
+	 *(*buf)++ = (unsigned char) ((length>>16)&0xff);
+#endif
+      if (length >= (1<<8))
+	 *(*buf)++ = (unsigned char) ((length>>8)&0xff);
+      *(*buf)++ = (unsigned char) (length&0xff);
+   }
+}
+
+/* returns decoded length, or < 0 on failure.  Advances buf and
+   decrements bufsize */
+
+static int der_read_length(buf, bufsize)
+     unsigned char **buf;
+     int *bufsize;
+{
+   unsigned char sf;
+   int ret;
+
+   if (*bufsize < 1)
+      return(-1);
+   sf = *(*buf)++;
+   (*bufsize)--;
+   if (sf & 0x80) {
+      if ((sf &= 0x7f) > ((*bufsize)-1))
+	 return(-1);
+      if (sf > SIZEOF_INT)
+	  return (-1);
+      ret = 0;
+      for (; sf; sf--) {
+	 ret = (ret<<8) + (*(*buf)++);
+	 (*bufsize)--;
+      }
+   } else {
+      ret = sf;
+   }
+
+   return(ret);
+}
+
+/* returns the length of a token, given the mech oid and the body size */
+
+unsigned int g_token_size(mech, body_size)
+     gss_OID mech;
+     unsigned int body_size;
+{
+   /* set body_size to sequence contents size */
+   body_size += 4 + (int) mech->length;         /* NEED overflow check */
+   return(1 + der_length_size(body_size) + body_size);
+}
+
+/* fills in a buffer with the token header.  The buffer is assumed to
+   be the right size.  buf is advanced past the token header */
+
+void g_make_token_header(mech, body_size, buf, tok_type)
+     gss_OID mech;
+     unsigned int body_size;
+     unsigned char **buf;
+     int tok_type;
+{
+   *(*buf)++ = 0x60;
+   der_write_length(buf, (tok_type == -1) ?2:4 + mech->length + body_size);
+   *(*buf)++ = 0x06;
+   *(*buf)++ = (unsigned char) mech->length;
+   TWRITE_STR(*buf, mech->elements, mech->length);
+   if (tok_type != -1) {
+       *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
+       *(*buf)++ = (unsigned char) (tok_type&0xff);
+   }
+}
+
+/*
+ * Given a buffer containing a token, reads and verifies the token,
+ * leaving buf advanced past the token header, and setting body_size
+ * to the number of remaining bytes.  Returns 0 on success,
+ * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
+ * mechanism in the token does not match the mech argument.  buf and
+ * *body_size are left unmodified on error.
+ */
+
+gss_int32 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize_in,
+				wrapper_required)
+     gss_OID mech;
+     unsigned int *body_size;
+     unsigned char **buf_in;
+     int tok_type;
+     unsigned int toksize_in;
+     int wrapper_required;
+{
+   unsigned char *buf = *buf_in;
+   int seqsize;
+   gss_OID_desc toid;
+   int toksize = toksize_in;
+
+   if ((toksize-=1) < 0)
+      return(G_BAD_TOK_HEADER);
+   if (*buf++ != 0x60) {
+       if (wrapper_required)
+	   return(G_BAD_TOK_HEADER);
+       buf--;
+       toksize++;
+       goto skip_wrapper;
+   }
+
+   if ((seqsize = der_read_length(&buf, &toksize)) < 0)
+      return(G_BAD_TOK_HEADER);
+
+   if (seqsize != toksize)
+      return(G_BAD_TOK_HEADER);
+
+   if ((toksize-=1) < 0)
+      return(G_BAD_TOK_HEADER);
+   if (*buf++ != 0x06)
+      return(G_BAD_TOK_HEADER);
+ 
+   if ((toksize-=1) < 0)
+      return(G_BAD_TOK_HEADER);
+   toid.length = *buf++;
+
+   if ((toksize-=toid.length) < 0)
+      return(G_BAD_TOK_HEADER);
+   toid.elements = buf;
+   buf+=toid.length;
+
+   if (! g_OID_equal(&toid, mech)) 
+       return  G_WRONG_MECH;
+skip_wrapper:
+   if (tok_type != -1) {
+       if ((toksize-=2) < 0)
+	   return(G_BAD_TOK_HEADER);
+
+       if ((*buf++ != ((tok_type>>8)&0xff)) ||
+	   (*buf++ != (tok_type&0xff)))
+	   return(G_WRONG_TOKID);
+   }
+   *buf_in = buf;
+   *body_size = toksize;
+
+   return 0;
+}
diff --git a/mechglue/src/lib/gssapi/generic/util_validate.c b/mechglue/src/lib/gssapi/generic/util_validate.c
new file mode 100644
index 000000000..fedbab158
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/util_validate.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+/*
+ * functions to validate name, credential, and context handles
+ */
+
+#include "gssapiP_generic.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <fcntl.h>
+#include <limits.h>
+
+#ifdef HAVE_BSD_DB
+#include <sys/file.h>
+#include <db.h>
+
+static const int one = 1;
+static const DBT dbtone = { (void *) &one, sizeof(one) };
+
+typedef struct _vkey {
+   int type;
+   void *ptr;
+} vkey;
+#endif
+
+#define V_NAME		1
+#define V_CRED_ID	2
+#define V_CTX_ID	3
+#define V_LCTX_ID	4
+
+/* All these functions return 0 on failure, and non-zero on success */
+
+static int g_save(db, type, ptr)
+     g_set *db;
+#ifdef HAVE_BSD_DB
+     int type;
+#else
+     void *type;
+#endif
+     void *ptr;
+{
+   int ret;
+#ifdef HAVE_BSD_DB
+   DB **vdb;
+   vkey vk;
+   DBT key;
+
+   ret = gssint_initialize_library();
+   if (ret)
+       return 0;
+   ret = k5_mutex_lock(&db->mutex);
+   if (ret)
+       return 0;
+
+   vdb = (DB **) &db->data;
+
+   if (!*vdb)
+      *vdb = dbopen(NULL, O_CREAT|O_RDWR, O_CREAT|O_RDWR, DB_HASH, NULL);
+
+   vk.type = type;
+   vk.ptr = ptr;
+
+   key.data = &vk;
+   key.size = sizeof(vk);
+
+   ret = ((*((*vdb)->put))(*vdb, &key, &dbtone, 0) == 0);
+   k5_mutex_unlock(&db->mutex);
+   return ret;
+#else
+   g_set_elt *gs;
+
+   ret = gssint_initialize_library();
+   if (ret)
+       return 0;
+   ret = k5_mutex_lock(&db->mutex);
+   if (ret)
+       return 0;
+
+   gs = (g_set_elt *) &db->data;
+
+   if (!*gs)
+      if (g_set_init(gs)) {
+	 k5_mutex_unlock(&db->mutex);
+	 return(0);
+      }
+
+   ret = (g_set_entry_add(gs, ptr, type) == 0);
+   k5_mutex_unlock(&db->mutex);
+   return ret;
+#endif
+}
+
+static int g_validate(db, type, ptr)
+     g_set *db;
+#ifdef HAVE_BSD_DB
+     int type;
+#else
+     void *type;
+#endif
+     void *ptr;
+{
+   int ret;
+#ifdef HAVE_BSD_DB
+   DB **vdb;
+   vkey vk;
+   DBT key, value;
+
+   ret = k5_mutex_lock(&db->mutex);
+   if (ret)
+       return 0;
+
+   vdb = (DB **) &db->data;
+   if (!*vdb) {
+      k5_mutex_unlock(&db->mutex);
+      return(0);
+   }
+
+   vk.type = type;
+   vk.ptr = ptr;
+
+   key.data = &vk;
+   key.size = sizeof(vk);
+
+   if ((*((*vdb)->get))(*vdb, &key, &value, 0)) {
+      k5_mutex_unlock(&db->mutex);
+      return(0);
+   }
+
+   k5_mutex_unlock(&db->mutex);
+   return((value.size == sizeof(one)) &&
+	  (*((int *) value.data) == one));
+#else
+   g_set_elt *gs;
+   void *value;
+
+   ret = k5_mutex_lock(&db->mutex);
+   if (ret)
+       return 0;
+
+   gs = (g_set_elt *) &db->data;
+   if (!*gs) {
+      k5_mutex_unlock(&db->mutex);
+      return(0);
+   }
+
+   if (g_set_entry_get(gs, ptr, (void **) &value)) {
+      k5_mutex_unlock(&db->mutex);
+      return(0);
+   }
+   k5_mutex_unlock(&db->mutex);
+   return(value == type);
+#endif
+}
+
+static int g_delete(db, type, ptr)
+     g_set *db;
+#ifdef HAVE_BSD_DB
+     int type;
+#else
+     void *type;
+#endif
+     void *ptr;
+{
+   int ret;
+#ifdef HAVE_BSD_DB
+   DB **vdb;
+   vkey vk;
+   DBT key;
+
+   ret = k5_mutex_lock(&db->mutex);
+   if (ret)
+       return 0;
+
+   vdb = (DB **) &db->data;
+   if (!*vdb) {
+      k5_mutex_unlock(&db->mutex);
+      return(0);
+   }
+
+   vk.type = type;
+   vk.ptr = ptr;
+
+   key.data = &vk;
+   key.size = sizeof(vk);
+
+   ret = ((*((*vdb)->del))(*vdb, &key, 0) == 0);
+   k5_mutex_unlock(&db->mutex);
+   return ret;
+#else
+   g_set_elt *gs;
+
+   ret = k5_mutex_lock(&db->mutex);
+   if (ret)
+       return 0;
+
+   gs = (g_set_elt *) &db->data;
+   if (!*gs) {
+      k5_mutex_unlock(&db->mutex);
+      return(0);
+   }
+
+   if (g_set_entry_delete(gs, ptr)) {
+      k5_mutex_unlock(&db->mutex);
+      return(0);
+   }
+   k5_mutex_unlock(&db->mutex);
+   return(1);
+#endif
+}
+
+/* functions for each type */
+
+/* save */
+
+int g_save_name(vdb, name)
+     g_set *vdb;
+     gss_name_t *name;
+{
+   return(g_save(vdb, V_NAME, (void *) name));
+}
+int g_save_cred_id(vdb, cred)
+     g_set *vdb;
+     gss_cred_id_t *cred;
+{
+   return(g_save(vdb, V_CRED_ID, (void *) cred));
+}
+int g_save_ctx_id(vdb, ctx)
+     g_set *vdb;
+     gss_ctx_id_t *ctx;
+{
+   return(g_save(vdb, V_CTX_ID, (void *) ctx));
+}
+int g_save_lucidctx_id(vdb, lctx)
+     g_set *vdb;
+     void *lctx;
+{
+   return(g_save(vdb, V_LCTX_ID, (void *) lctx));
+}
+
+
+/* validate */
+
+int g_validate_name(vdb, name)
+     g_set *vdb;
+     gss_name_t *name;
+{
+   return(g_validate(vdb, V_NAME, (void *) name));
+}
+int g_validate_cred_id(vdb, cred)
+     g_set *vdb;
+     gss_cred_id_t *cred;
+{
+   return(g_validate(vdb, V_CRED_ID, (void *) cred));
+}
+int g_validate_ctx_id(vdb, ctx)
+     g_set *vdb;
+     gss_ctx_id_t *ctx;
+{
+   return(g_validate(vdb, V_CTX_ID, (void *) ctx));
+}
+int g_validate_lucidctx_id(vdb, lctx)
+     g_set *vdb;
+     void *lctx;
+{
+   return(g_validate(vdb, V_LCTX_ID, (void *) lctx));
+}
+
+/* delete */
+
+int g_delete_name(vdb, name)
+     g_set *vdb;
+     gss_name_t *name;
+{
+   return(g_delete(vdb, V_NAME, (void *) name));
+}
+int g_delete_cred_id(vdb, cred)
+     g_set *vdb;
+     gss_cred_id_t *cred;
+{
+   return(g_delete(vdb, V_CRED_ID, (void *) cred));
+}
+int g_delete_ctx_id(vdb, ctx)
+     g_set *vdb;
+     gss_ctx_id_t *ctx;
+{
+   return(g_delete(vdb, V_CTX_ID, (void *) ctx));
+}
+int g_delete_lucidctx_id(vdb, lctx)
+     g_set *vdb;
+     void *lctx;
+{
+   return(g_delete(vdb, V_LCTX_ID, (void *) lctx));
+}
+
diff --git a/mechglue/src/lib/gssapi/generic/utl_nohash_validate.c b/mechglue/src/lib/gssapi/generic/utl_nohash_validate.c
new file mode 100644
index 000000000..da20b71d6
--- /dev/null
+++ b/mechglue/src/lib/gssapi/generic/utl_nohash_validate.c
@@ -0,0 +1,121 @@
+/*
+ *  Copyright 1990,1994 by the Massachusetts Institute of Technology.
+ *  All Rights Reserved.
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+/*
+ * stub functions for those without the hash library.
+ */
+
+#include "gssapiP_generic.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+/* functions for each type */
+
+/* save */
+
+int g_save_name(vdb, name)
+     void **vdb;
+     gss_name_t *name;
+{
+	return 1;
+}
+int g_save_cred_id(vdb, cred)
+     void **vdb;
+     gss_cred_id_t *cred;
+{
+	return 1;
+}
+int g_save_ctx_id(vdb, ctx)
+     void **vdb;
+     gss_ctx_id_t *ctx;
+{
+	return 1;
+}
+int g_save_lucidctx_id(vdb, lctx)
+     void **vdb;
+     void *lctx;
+{
+	return 1;
+}
+
+/* validate */
+
+int g_validate_name(vdb, name)
+     void **vdb;
+     gss_name_t *name;
+{
+	return 1;
+}
+int g_validate_cred_id(vdb, cred)
+     void **vdb;
+     gss_cred_id_t *cred;
+{
+	return 1;
+}
+int g_validate_ctx_id(vdb, ctx)
+     void **vdb;
+     gss_ctx_id_t *ctx;
+{
+	return 1;
+}
+int g_validate_lucidctx_id(vdb, lctx)
+     void **vdb;
+     void *lctx;
+{
+	return 1;
+}
+
+/* delete */
+
+int g_delete_name(vdb, name)
+     void **vdb;
+     gss_name_t *name;
+{
+	return 1;
+}
+int g_delete_cred_id(vdb, cred)
+     void **vdb;
+     gss_cred_id_t *cred;
+{
+	return 1;
+}
+int g_delete_ctx_id(vdb, ctx)
+     void **vdb;
+     gss_ctx_id_t *ctx;
+{
+	return 1;
+}
+int g_delete_lucidctx_id(vdb, lctx)
+     void **vdb;
+     void *lctx;
+{
+	return 1;
+}
+
diff --git a/mechglue/src/lib/gssapi/gss_libinit.c b/mechglue/src/lib/gssapi/gss_libinit.c
new file mode 100644
index 000000000..1d9a2397a
--- /dev/null
+++ b/mechglue/src/lib/gssapi/gss_libinit.c
@@ -0,0 +1,71 @@
+#include <assert.h>
+
+#include "gssapi_err_generic.h"
+#include "gssapi_err_krb5.h"
+#include "gssapiP_krb5.h"
+
+#include "gss_libinit.h"
+#include "k5-platform.h"
+
+#include "mglueP.h"
+
+/*
+ * Initialize the GSSAPI library.
+ */
+
+MAKE_INIT_FUNCTION(gssint_lib_init);
+MAKE_FINI_FUNCTION(gssint_lib_fini);
+
+int gssint_lib_init(void)
+{
+    int err;
+
+#ifdef SHOW_INITFINI_FUNCS
+    printf("gssint_lib_init\n");
+#endif
+
+#if !USE_BUNDLE_ERROR_STRINGS
+    add_error_table(&et_k5g_error_table);
+    add_error_table(&et_ggss_error_table);
+#endif
+    err = gssint_mechglue_init();
+    if (err)
+	return err;
+    err = k5_mutex_finish_init(&gssint_krb5_keytab_lock);
+    if (err)
+	return err;
+    err = k5_key_register(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, free);
+    if (err)
+	return err;
+    err = k5_key_register(K5_KEY_GSS_KRB5_CCACHE_NAME, free);
+    if (err)
+	return err;
+    return k5_mutex_finish_init(&kg_vdb.mutex);
+}
+
+void gssint_lib_fini(void)
+{
+    if (!INITIALIZER_RAN(gssint_lib_init) || PROGRAM_EXITING()) {
+#ifdef SHOW_INITFINI_FUNCS
+	printf("gssint_lib_fini: skipping\n");
+#endif
+	return;
+    }
+#ifdef SHOW_INITFINI_FUNCS
+    printf("gssint_lib_fini\n");
+#endif
+#if !USE_BUNDLE_ERROR_STRINGS
+    remove_error_table(&et_k5g_error_table);
+    remove_error_table(&et_ggss_error_table);
+#endif
+    k5_key_delete(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
+    k5_key_delete(K5_KEY_GSS_KRB5_CCACHE_NAME);
+    k5_mutex_destroy(&kg_vdb.mutex);
+    k5_mutex_destroy(&gssint_krb5_keytab_lock);
+    gssint_mechglue_fini();
+}
+
+OM_uint32 gssint_initialize_library (void)
+{
+    return CALL_INIT_FUNCTION(gssint_lib_init);
+}
diff --git a/mechglue/src/lib/gssapi/gss_libinit.h b/mechglue/src/lib/gssapi/gss_libinit.h
new file mode 100644
index 000000000..5a3660426
--- /dev/null
+++ b/mechglue/src/lib/gssapi/gss_libinit.h
@@ -0,0 +1,9 @@
+#ifndef GSSAPI_LIBINIT_H
+#define GSSAPI_LIBINIT_H
+
+#include "gssapi.h"
+
+OM_uint32 gssint_initialize_library (void);
+void gssint_cleanup_library (void);
+
+#endif /* GSSAPI_LIBINIT_H */
diff --git a/mechglue/src/lib/gssapi/krb5/.Sanitize b/mechglue/src/lib/gssapi/krb5/.Sanitize
new file mode 100644
index 000000000..d82c290cd
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/.Sanitize
@@ -0,0 +1,74 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+Makefile.original
+accept_sec_context.c
+acquire_cred.c
+compare_name.c
+configure
+configure.in
+context_time.c
+delete_sec_context.c
+disp_name.c
+disp_status.c
+export_sec_context.c
+get_tkt_flags.c
+gssapiP_krb5.h
+gssapi_err_krb5.et
+gssapi_krb5.c
+gssapi_krb5.h
+import_name.c
+import_sec_context.c
+indicate_mechs.c
+init_sec_context.c
+inq_context.c
+inq_cred.c
+inq_names.c
+k5mech.c
+k5seal.c
+k5unseal.c
+pname_to_uid.c
+process_context_token.c
+rel_cred.c
+rel_name.c
+rel_oid.c
+seal.c
+ser_sctx.c
+sign.c
+unseal.c
+util_cksum.c
+util_crypt.c
+util_seed.c
+util_seqnum.c
+verify.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/gssapi/krb5/3des.txt b/mechglue/src/lib/gssapi/krb5/3des.txt
new file mode 100644
index 000000000..64ca1ac49
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/3des.txt
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Kerberos Working Group                                        K. Raeburn
+Category: Informational                                              MIT
+Document: draft-raeburn-krb-gssapi-krb5-3des-01.txt    November 24, 2000
+
+
+         Triple-DES Support for the Kerberos 5 GSSAPI Mechanism
+
+Status of this Memo
+
+   This document is an Internet-Draft and is in full conformance with
+   all provisions of Section 10 of RFC2026 [1]. Internet-Drafts are
+   working documents of the Internet Engineering Task Force (IETF), its
+   areas, and its working groups. Note that other groups may also
+   distribute working documents as Internet-Drafts. Internet-Drafts are
+   draft documents valid for a maximum of six months and may be updated,
+   replaced, or obsoleted by other documents at any time. It is
+   inappropriate to use Internet-Drafts as reference material or to cite
+   them other than as "work in progress."
+
+   The list of current Internet-Drafts can be accessed at
+   http://www.ietf.org/ietf/1id-abstracts.txt
+
+   The list of Internet-Draft Shadow Directories can be accessed at
+   http://www.ietf.org/shadow.html.
+
+1. Abstract
+
+   The GSSAPI Kerberos 5 mechanism definition [GSSAPI-KRB5] specifically
+   enumerates encryption and checksum types, independently of how such
+   schemes may be used in Kerberos.  In the long run, a new Kerberos-
+   based mechanism, which does not require separately enumerating for
+   the GSSAPI mechanism each of the various encryption types defined by
+   Kerberos, is probably a better approach.  Various people have
+   expressed interest in designing one, but the work has not yet been
+   completed.
+
+   The MIT Kerberos 5 release version 1.2 includes support for triple-
+   DES with key derivation [KrbRev].  Recent work by the EFF [EFF] has
+   demonstrated the vulnerability of single-DES mechanisms to brute-
+   force attacks by sufficiently motivated and well-funded parties.  So,
+   in the interest of providing increased security in the near term, MIT
+   is adding support for triple-DES to the existing mechanism
+   implementation we ship, as an interim measure.
+
+
+
+
+
+
+
+
+Raeburn                                                         [Page 1]
+
+INTERNET DRAFT       Triple-DES for GSSAPI Kerberos        November 2000
+
+
+2. New Algorithm Identifiers
+
+   One new sealing algorithm is defined, for use in Wrap tokens.
+
+
+   +--------------------------------------------------------------------+
+   |          name                                octet values          |
+   +--------------------------------------------------------------------+
+   |         DES3-KD                                 02 00              |
+   +--------------------------------------------------------------------+
+
+   This algorithm uses triple-DES with key derivation, with a usage
+   value KG_USAGE_SEAL.  (Unlike the EncryptedData definition in
+   [KrbRev], no integrity protection is needed, so this is "raw" triple-
+   DES, with no checksum attached to the encrypted data.)  Padding is
+   still to 8-byte multiples, and the IV for encrypting application data
+   is zero.
+
+   One new signing algorithm is defined, for use in MIC, Wrap, and
+   Delete tokens.
+
+
+   +--------------------------------------------------------------------+
+   |             name                               octet values        |
+   +--------------------------------------------------------------------+
+   |       HMAC SHA1 DES3-KD                           04 00            |
+   +--------------------------------------------------------------------+
+
+   This algorithm generates an HMAC using SHA-1 and a derived DES3 key
+   with usage KG_USAGE_SIGN, as described in [KrbRev].
+
+   [N.B.: The current [KrbRev] description refers to expired I-Ds from
+   Marc Horowitz.  The text in [KrbRev] may be inadequate to produce an
+   interoperable implementation.]
+
+   The checksum size for this algorithm is 20 octets.  See section 4.3
+   below for the use of checksum lengths of other than eight bytes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Raeburn                                                         [Page 2]
+
+INTERNET DRAFT       Triple-DES for GSSAPI Kerberos        November 2000
+
+
+3. Key Derivation
+
+   For purposes of key derivation, we add three new usage values to the
+   list defined in [KrbRev]; one for signing messages, one for sealing
+   messages, and one for encrypting sequence numbers:
+
+
+   +--------------------------------------------------------------------+
+   |             name                                    value          |
+   +--------------------------------------------------------------------+
+   |         KG_USAGE_SEAL                                22            |
+   |         KG_USAGE_SIGN                                23            |
+   |         KG_USAGE_SEQ                                 24            |
+   +--------------------------------------------------------------------+
+
+4. Adjustments to Previous Definitions
+
+4.1. Quality of Protection
+
+   The GSSAPI specification [GSSAPI] says that a zero QOP value
+   indicates the "default".  The original specification for the Kerberos
+   5 mechanism says that a zero QOP value (or a QOP value with the
+   appropriate bits clear) means DES encryption.
+
+   Rather than forcing the use of plain DES when the application doesn't
+   use mechanism-specific QOP values, we redefine the explicit DES QOP
+   value as a non-zero value, and define a triple-DES value as well.
+   Then a zero value continues to imply the default, which would be
+   triple-DES protection when given a triple-DES session key.
+
+   Our values are:
+
+   +--------------------------------------------------------------------+
+   |             name                  value      meaning               |
+   +--------------------------------------------------------------------+
+   | GSS_KRB5_INTEG_C_QOP_HMAC_SHA1    0x0004     SHA-1 HMAC, using     |
+   |                                              key derivation        |
+   |                                                                    |
+   |    GSS_KRB5_CONF_C_QOP_DES        0x0100     plain DES encryption  |
+   |                                                                    |
+   |  GSS_KRB5_CONF_C_QOP_DES3_KD      0x0200     triple-DES with key   |
+   |                                              derivation            |
+   +--------------------------------------------------------------------+
+
+   Rather than attempt to specify a generic mechanism for deriving a key
+   of one type given a key of another type, and evaluate the security
+   implications of using a short key to generate a longer key to satisfy
+   the requested quality of protection, our implementation will simply
+
+
+
+Raeburn                                                         [Page 3]
+
+INTERNET DRAFT       Triple-DES for GSSAPI Kerberos        November 2000
+
+
+   return an error if the nonzero QOP value specified does not
+   correspond to the session key type.
+
+4.2. MIC Sequence Number Encryption
+
+   The sequence numbers are encrypted in the context key (as defined in
+   [GSSAPI-KRB5] -- this will be either the Kerberos session key or
+   asubkey provided by the context initiator), using whatever encryption
+   system is designated by the type of that context key.  The IV is
+   formed from the first N bytes of the SGN_CKSUM field, where N is the
+   number of bytes needed for the IV.  (With all algorithms described
+   here and in [GSSAPI-KRB5], the checksum is at least as large as the
+   IV.)
+
+4.3. Message Layout
+
+   Both MIC and Wrap tokens, as defined in [GSSAPI-KRB5], contain an
+   checksum field SGN_CKSUM.  In [GSSAPI-KRB5], this field was specified
+   as being 8 bytes long.  We now change this size to be "defined by the
+   checksum algorithm", and retroactively amend the descriptions of all
+   the checksum algorithms described in [GSSAPI-KRB5] to explicitly
+   specify 8-byte output.  Application data continues to immediately
+   follow the checksum field in the Wrap token.
+
+   The revised message descriptions are thus:
+
+   MIC token:
+
+   Byte #             Name                Description
+   ----------------------------------------------------------------------
+    0..1              TOK_ID              Identification field.
+    2..3              SGN_ALG             Integrity algorithm indicator.
+    4..7              Filler              Contains ff ff ff ff
+    8..15             SND_SEQ             Sequence number field.
+   16..s+15           SGN_CKSUM           Checksum of "to-be-signed
+                                          data", calculated according to
+                                          algorithm specified in SGN_ALG
+                                          field.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Raeburn                                                         [Page 4]
+
+INTERNET DRAFT       Triple-DES for GSSAPI Kerberos        November 2000
+
+
+   Wrap token:
+
+   Byte #           Name             Description
+   ----------------------------------------------------------------------
+    0..1            TOK_ID           Identification field.  Tokens
+                                     emitted by GSS_Wrap() contain the
+                                     hex value 02 01 in this field.
+    2..3            SGN_ALG          Checksum algorithm indicator.
+    4..5            SEAL_ALG         Sealing algorithm indicator.
+    6..7            Filler           Contains ff ff
+    8..15           SND_SEQ          Encrypted sequence number field.
+   16..s+15         SGN_CKSUM        Checksum of plaintext padded data,
+                                     calculated according to algorithm
+                                     specified in SGN_ALG field.
+   s+16..last       Data             encrypted or plaintext padded data
+
+
+   Where "s" indicates the size of the checksum.
+
+   As indicated above in section 2, we define the HMAC SHA1 DES3-KD
+   checksum algorithm to produce a 20-byte output, so encrypted data
+   begins at byte 36.
+
+5. Backwards Compatibility Considerations
+
+   The context initiator should request of the KDC credentials using
+   session-key cryptosystem types supported by that implementation; if
+   the only types returned by the KDC are not supported by the mechanism
+   implementation, it should indicate a failure.  This may seem obvious,
+   but early implementations of both Kerberos and the GSSAPI Kerberos
+   mechanism supported only DES keys, so the cryptosystem compatibility
+   question was easy to overlook.
+
+   Under the current mechanism, no negotiation of algorithm types
+   occurs, so server-side (acceptor) implementations cannot request that
+   clients not use algorithm types not understood by the server.
+   However, administration of the server's Kerberos data (e.g., the
+   service key) has to be done in communication with the KDC, and it is
+   from the KDC that the client will request credentials.  The KDC could
+   therefore be tasked with limiting session keys for a given service to
+   types actually supported by the Kerberos and GSSAPI software on the
+   server.
+
+   This does have a drawback for cases where a service principal name is
+   used both for GSSAPI-based and non-GSSAPI-based communication (most
+   notably the "host" service key), if the GSSAPI implementation does
+   not understand triple-DES but the Kerberos implementation does.  It
+   means that triple-DES session keys cannot be issued for that service
+
+
+
+Raeburn                                                         [Page 5]
+
+INTERNET DRAFT       Triple-DES for GSSAPI Kerberos        November 2000
+
+
+   principal, which keeps the protection of non-GSSAPI services weaker
+   than necessary.
+
+   It would also be possible to have clients attempt to get single-DES
+   session keys before trying to get triple-DES session keys, and have
+   the KDC refuse to issue the single-DES keys only for the most
+   critical of services, for which single-DES protection is considered
+   inadequate.  However, that would eliminate the possibility of
+   connecting with the more secure cryptosystem to any service that can
+   be accessed with the weaker cryptosystem.
+
+   For MIT's 1.2 release, we chose to go with the former approach,
+   putting the burden on the KDC administration and gaining the best
+   protection possible for GSSAPI services, possibly at the cost of
+   weaker protection of non-GSSAPI Kerberos services running earlier
+   versions of the software.
+
+6. Security Considerations
+
+   Various tradeoffs arise regarding the mixing of new and old software,
+   or GSSAPI-based and non-GSSAPI Kerberos authentication.  They are
+   discussed in section 5.
+
+7. References
+
+   [EFF] Electronic Frontier Foundation, "Cracking DES: Secrets of
+   Encryption Research, Wiretap Politics, and Chip Design", O'Reilly &
+   Associates, Inc., May, 1998.
+
+   [GSSAPI] Linn, J., "Generic Security Service Application Program
+   Interface Version 2, Update 1", RFC 2743, January, 2000.
+
+   [GSSAPI-KRB5] Linn, J., "The Kerberos Version 5 GSS-API Mechanism",
+   RFC 1964, June, 1996.
+
+   [KrbRev] Neuman, C., Kohl, J., Ts'o, T., "The Kerberos Network
+   Authentication Service (V5)", draft-ietf-cat-kerberos-
+   revisions-06.txt, July 4, 2000.
+
+8. Author's Address
+
+   Kenneth Raeburn Massachusetts Institute of Technology 77
+   Massachusetts Avenue Cambridge, MA 02139
+
+9. Full Copyright Statement
+
+   Copyright (C) The Internet Society (2000).  All Rights Reserved.
+
+
+
+
+Raeburn                                                         [Page 6]
+
+INTERNET DRAFT       Triple-DES for GSSAPI Kerberos        November 2000
+
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
+
+10. Document Change History
+
+>From -00 to -01:
+
+   Converted master to GNU troff and tbl, rewriting tables in the
+   process.
+
+   Specify informational category only.  Modify some text to emphasize
+   that this document intends to describe MIT's extensions.
+
+   Point out that while EncryptedData for 3des-kd includes a checksum,
+   DES3-KD GSS encryption does not.
+
+   Shorten backwards-compatibility descriptions a little.
+
+   Submit to Kerberos working group rather than CAT.
+
+
+
+
+
+
+
+
+
+
+
+Raeburn                                                         [Page 7]
+
diff --git a/mechglue/src/lib/gssapi/krb5/ChangeLog b/mechglue/src/lib/gssapi/krb5/ChangeLog
new file mode 100644
index 000000000..0e6c3a471
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/ChangeLog
@@ -0,0 +1,2284 @@
+2005-11-14  Jeffrey Altman <jaltman@mit.edu>
+
+	* gssapi_krb5.hin: include k5-int.h instead of krb5.h
+
+2005-10-20  Alexandra Ellwood <lxs@mit.edu>, Jeffrey Altman <jaltman@mit.edu>
+	
+	* acquire_cred.c (acquire_init_cred):
+	  If a specific principal has been requested, attempt to acquire
+          tickets and set the ccache name in the context to the ccache
+          containing the tickets if obtained. (KFM/KFW)  
+
+2005-10-20  Jeffrey Altman <jaltman@mit.edu>
+
+	* gssapi_krb5.hin: add missing GSS_DLLIMP to exported symbols
+
+2005-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* import_name.c (krb5_gss_import_name): Add missing free of tmp in
+	an error case to fix a memory leak.
+
+	* inq_cred.c (krb5_gss_inquire_cred): Memory leak fixes: call
+	krb5_gss_release_cred() with address of cred, not cred; add
+	missing call to krb5_gss_release_cred() in an error case.
+
+	* duplicate_name.c (krb5_gss_duplicate_name):
+	* export_name.c (krb5_gss_export_name): Fix gsstest nit by
+	clearing minor_status if no errors.
+
+	* inq_cred.c (krb5_gss_inquire_cred): Initialize ret_name to
+	NULL.  Only call kg_save_name() if ret_name is actually non-NULL.
+	Return GSS_C_NO_NAME for now if no principal name in the cred.
+	Reported by Christoph Weizen.
+
+2005-08-11  Tom Yu  <tlyu@mit.edu>
+
+	* import_name.c: Include stdio.h regardless of presence of
+	getpwuid_r(), to ensure definition of BUFSIZ.  Reported by
+	Vladimir Terziev.
+
+2005-04-07  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (gssapi_krb5.h): Use awk hack to work around quoting
+	problem.
+
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* import_name.c (krb5_gss_import_name): Use k5_getpwuid_r.
+
+2005-01-13 Jeffrey Altman <jaltman@mit.edu>
+
+        * init_sec_context.c, acquire_cred.c: fix calls to 
+          krb5_gss_release_cred() to pass in the correct type.
+          This fixes a mutex leak.
+
+2004-08-27  Tom Yu  <tlyu@mit.edu>
+
+	* init_sec_context.c (make_ap_req_v1): Free checksum data
+	allocated by make_gss_checksum() to avoid leak.
+
+	* k5sealv3.c (gss_krb5int_unseal_token_v3): Free plain.data after
+	checksum is verified, to avoid leak.
+
+2004-08-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* acquire_cred.c (krb5_gss_acquire_cred): Call
+	gssint_initialize_library.  Return correct error code on mutex
+	initialization failure.
+
+2004-07-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi_krb5.c (kg_ccache_name): Variable deleted.
+	(kg_sync_ccache_name, kg_get_ccache_name, kg_set_ccache_name): Get
+	and set thread-specific values instead.
+
+2004-07-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapiP_krb5.h (struct _krb5_gss_cred_id_rec): Add a mutex.
+	(krb5_gss_validate_cred_1): Declare.
+	* accept_sec_context.c (rd_and_store_for_creds): Initialize mutex.
+	* acquire_cred.c (krb5_gss_acquire_cred): Initialize mutex.
+	* add_cred.c (krb5_gss_add_cred): Create the krb5 context
+	earlier.  Call krb5_gss_validate_cred_1.  Make sure the mutex is
+	locked.
+	* copy_ccache.c (gss_krb5_copy_ccache): Lock the mutex in the
+	source credential.
+	* init_sec_context.c (get_credentials, new_connection): Check that
+	the mutex is locked.
+	(mutual_auth): Delete unused credential argument.
+	(krb5_gss_init_sec_context): Lock the mutex.
+	* inq_cred.c (krb5_gss_inquire_cred): Lock the mutex.
+	* rel_cred.c (krb5_gss_release_cred): Destroy the mutex.
+	* set_allowable_enctypes.c (gss_krb5_set_allowable_enctypes): Lock
+	the mutex.
+	* val_cred.c (krb5_gss_validate_cred_1): New function, most of old
+	krb5_gss_validate_cred but requires that the krb5 context be
+	supplied, and returns with the credential mutex still locked if
+	successful, so the caller needn't re-lock it.
+	(krb5_gss_validate_cred): Use it.
+
+	* set_ccache.c (gss_krb5_ccache_name): Don't make a copy of the
+	string returned by kg_get_ccache_name.  Simplify some calls using
+	a temporary error code variable.
+
+	* gssapi_krb5.c (kg_get_ccache_name): Make a copy of the default
+	ccache name, because calling krb5_free_context will destroy it.
+	Make the copy always, not just in the local-context case.  Check
+	for errors in making the copy.
+
+2004-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi_krb5.c (kg_sync_ccache_name): Add context argument
+	instead of calling kg_get_context.
+	(kg_get_ccache_name): Use a locally created krb5 context instead
+	of calling kg_get_context.
+	(kg_get_context): Deleted.
+	* acquire_cred.c (acquire_init_cred): Pass current context.
+	(krb5_gss_acquire_cred): Use a locally created krb5 context
+	instead of calling kg_get_context.
+	* add_cred.c (krb5_gss_add_cred): Call kg_sync_ccache_name.
+	* init_sec_context.c (krb5_gss_init_sec_context): Likewise.
+	* gssapiP_krb5.h (kg_sync_ccache_name): Update prototype.
+	(kg_get_context): Delete declaration.
+
+2004-07-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* acquire_cred.c: Include gss_libinit.h.
+	(gssint_krb5_keytab_lock): New mutex.
+	(krb5_gss_register_acceptor_identity, acquire_accept_cred): Lock
+	the mutex while manipulating krb5_gss_keytab.
+	* gssapiP_krb5.h (gssint_krb5_keytab_lock): Declare.
+
+	* set_ccache.c (gss_krb5_ccache_name): Check thread-specific data
+	for the saved "old" name to free.  Save the new old name in
+	thread-specific data.
+
+2004-07-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): Add $(srcdir)/.. to the list.
+
+2004-07-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* disp_status.c: Include gss_libinit.h.
+	(init_et): Variable deleted.
+	(krb5_gss_display_status): Don't use init_et; instead, call
+	gssint_initialize_library.
+
+2004-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* import_name.c [HAVE_GETPWUID_R]: Include stdio.h.
+	(krb5_gss_import_name) [HAVE_GETPWUID_R]: Use getpwuid_r instead
+	of getpwuid, for thread safety.
+
+2004-06-17  Tom Yu  <tlyu@mit.edu>
+
+	* ser_sctx.c (kg_ctx_size, kg_ctx_externalize):
+	(kg_ctx_internalize): Adjust for new field cred_rcache.
+
+2004-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Only null
+	out the auth_context's rcache if it was provided by acceptor
+	creds; this prevents a leak.
+
+	* delete_sec_context.c (krb5_gss_delete_sec_context): Only null
+	out the auth_context's rcache if it was provided by acceptor
+	creds; this prevents a leak.
+
+	* gssapiP_krb5.h (krb5_gss_ctx_id_rec): Add cred_rcache to track
+	whether acceptor creds provided an rcache.
+
+2004-06-14  Tom Yu  <tlyu@mit.edu>
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Fix pointer
+	assignment when retrieving k5_context from existing
+	context_handle.
+
+2004-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (gssapi_krb5.h): Add Windows version of generation
+	rule.
+
+2004-06-09  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (install-headers-unix install): install
+	gssapi_krb5.h from build directory not source directory 
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): If the
+	server provides channel bindings, these channel bindings must be
+	matched.  Thus clients can only provide null channel bindings if
+	the server provides no channel bindings. 
+
+2004-06-08  Sam Hartman  <hartmans@mit.edu>
+
+	* set_allowable_enctypes.c lucid_context.c:  new file
+
+	* gssapi_krb5.hin: Made file autogenerated; support  gss_uint64 type
+
+	* Makefile.in (gssapi_krb5.h): Include code to pull in stdint.h if available.
+
+	* gssapi_krb5.h: Add declarations for lucid_context support
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi_krb5.c (kg_get_ccache_name): Don't test err while it's
+	still known to be 0.
+	(kg_set_ccache_name): Likewise.  Return after an error rather
+	than continuing.
+
+	* krb5_gss_glue.c (gss_import_name): Call
+	gssint_initialize_library and check the return status.
+
+2004-04-13  Jeffrey Altman <jaltman@mit.edu>
+ 
+    * k5unseal.c: gss_krb5int_unseal_token_v3() takes a pointer to 
+      krb5_context
+    * import_sec_context.c: krb5_gss_ser_init() contains a function
+      pointer table.  this table must use pointers to functions of
+      type KRB5_CALLCONV.
+
+2004-03-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* rel_cred.c (krb5_gss_release_cred): Create and destroy a local
+	krb5 context.
+	* rel_name.c (krb5_gss_release_name): Likewise.
+	* val_cred.c (krb5_gss_validate_cred): Likewise.
+
+2004-03-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* add_cred.c (krb5_gss_add_cred): Create and destroy a local krb5
+	context.
+	* compare_name.c (krb5_gss_compare_name): Likewise.
+	* copy_ccache.c (gss_krb5_copy_ccache): Likewise.
+	* disp_name.c (krb5_gss_display_name): Likewise.
+	* duplicate_name.c (krb5_gss_duplicate_name): Likewise.
+	* inq_cred.c (krb5_gss_inquire_cred): Likewise.
+	* export_name.c (krb5_gss_export_name): Likewise.
+	* import_name.c (krb5_gss_import_name): Likewise.
+
+	* context_time.c (krb5_gss_context_time): Use the krb5 context in
+	the GSS security context.
+
+2004-03-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5seal.c (kg_seal): Extract the krb5 context from the security
+	context instead of requiring it be passed in as an argument.
+	* k5unseal.c (kg_unseal): Likewise.
+	* gssapiP_krb5.h (kg_seal, kg_unseal): Declarations updated.
+	* delete_sec_context.c, process_context_token.c, seal.c, sign.c,
+	unseal.c, verify.c: Callers changed.
+	* inq_context.c (krb5_gss_inquire_context): Use krb5 context
+	contained in security context instead of calling kg_get_context.
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Likewise.
+
+	* import_sec_context.c (krb5_gss_ser_init): New function.
+	(krb5_gss_import_sec_context): Create a krb5 context locally to
+	use for the import.
+	* export_sec_context.c (krb5_gss_export_sec_context): Use the
+	krb5 context in the security context.
+	* gssapiP_krb5.h (krb5_gss_ser_init): Declare.
+	* gssapi_krb5.c (kg_get_context): Don't call krb5 serialization
+	initialization code here.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Free the
+	new krb5 context in an error case not caught before.
+
+2004-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapiP_krb5.h (struct _krb5_gss_ctx_id_rec): Add a krb5
+	context object.
+	* init_sec_context.c (krb5_gss_init_sec_context): Create a new
+	krb5 context, and store it in the security context if
+	successful.  If there's already a security context, use the krb5
+	context in it.
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Create a
+	new krb5 context, and store it in the security context if
+	successful.
+	* delete_sec_context.c (krb5_gss_delete_sec_context): If the
+	security context has a krb5 context, free it.
+
+	* gssapi_krb5.c (kg_vdb): Change type to g_set and initialize.
+	* gssapiP_krb5.h (kg_vdb): Declaration updated.
+
+	* gssapiP_krb5.h (struct _krb5_gss_ctx_id_rec): Delete fields
+	init_token and testing_unknown_tokid.
+	* init_sec_context.c (new_connection): Drop support (already
+	inside "#if 0") for them.
+	(krb5_gss_init_sec_context): Drop support for
+	testing_unknown_tokid.
+	(mutual_auth): Don't let major_status be used uninitialized.
+
+2004-03-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* gssapiP_krb5.h: Add prototype for gss_krb5int_unseal_token_v3.
+
+2004-03-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* disp_status.c (krb5_gss_display_status): Don't call
+	kg_get_context; delete local krb5_context variable.
+	* inq_cred.c (krb5_gss_inquire_cred_by_mech): Likewise.
+	* inq_names.c (krb5_gss_inquire_names_for_mech): Likewise.
+
+2004-02-26  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Don't clear
+	the DO_TIME flag until after rd_req is called so a replay cache is
+	set up  even in the no_credential case. 
+
+2004-02-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Fix calculation
+	for confidential CFX tokens.
+
+2004-02-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* ser_sctx.c (kg_oid_externalize): Check for errors.
+	(kg_oid_internalize): Check for errors.  Free allocated storage on
+	error.
+	(kg_queue_externalize): Check for errors.
+	(kg_queue_internalize): Check for errors.  Free allocated storage
+	on error.
+	(kg_ctx_size): Update for new context data.
+	(kg_ctx_externalize): Update for new context data.  Check for
+	error storing trailer.
+	(kg_ctx_internalize): Update for new context data.  Check for
+	errors in a few more cases.
+
+2004-02-05  Jeffrey Altman <jaltman@mit.edu>
+
+    * gssapiP_krb5.h:  remove KG_IMPLFLAGS macro
+
+    * init_sec_context.c (init_sec_context): Expand KG_IMPLFLAGS
+      macro with previous macro definition
+
+    * accept_sec_context.c (accept_sec_context): Replace KG_IMPLFLAGS
+      macro with new definition.  As per 1964 the INTEG and CONF flags
+      are supposed to indicate the availability of the services in 
+      the client.  By applying the previous definition of KG_IMPLFLAGS
+      the INTEG and CONF flags are always on.  This can be a problem
+      because some clients such as Microsoft's Kerberos SSPI allow
+      CONF and INTEG to be used independently.  By forcing the flags
+      on, we would end up with inconsist state with the client.
+
+2004-01-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_sec_context.c (make_gss_checksum) [CFX_EXERCISE]: Don't
+	crash on null pointer in debugging code.
+	(new_connection): Disable CFX_EXERCISE unknown-token-id case
+	detection.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context)
+	[CFX_EXERCISE]: Log to /tmp/gsslog whether delegation or extra
+	option bytes were present.
+
+2004-01-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_sec_context.c: Include auth_con.h if CFX_EXERCISE is
+	defined.
+	(make_gss_checksum) [CFX_EXERCISE]: If the key enctype is aes256,
+	insert some stuff after the delegation slot.
+	(new_connection) [CFX_EXERCISE]: Don't send messages with bogus
+	token ids.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Don't
+	discard the delegation flag; only look for a delegation if the
+	flag is set, and only look for delegation, not other options.
+	Ignore any other data there.
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* util_crypt.c (kg_encrypt, kg_decrypt): Input pointer now points
+	to const.
+	* gssapiP_krb5.h: Declarations updated.
+	* util_seed.c (zeros): Now const.
+
+2003-12-19  Tom Yu  <tlyu@mit.edu>
+
+	* init_sec_context.c: Include k5-int.h for accessor.
+
+2003-12-18  Jeffrey Altman <jaltman@mit.edu>
+
+   * accept_sec_context.c, init_sec_context.c, ser_sctx.c:
+     Implement use of krb5int_accessor() for krb5int_c_mandatory_cksumtype,
+     krb5_ser_pack_int64, and krb5_ser_unpack_int64
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+	    Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* k5sealv3.c: New file, implements Wrap and MIC tokens for CFX
+	extensions.
+	* gssapiP_krb5.h (struct _krb5_gss_ctx_id_rec): Added acceptor
+	subkey, 64-bit sequence numbers, checksum type, and hooks for
+	sending a bogus initial token for CFX testing.  Changed some flags
+	into bitfields.
+	(gss_krb5int_make_seal_token_v3): Declare.
+	* Makefile.in (SRCS, OBJS, STLIBOBJS): Build it.
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Add CFX
+	support.  For G_WRONG_TOKID, send back an error token with
+	AP_ERR_MSG_TYPE code and return a CONTINUE_NEEDED indication.
+	Initialize new fields in context.
+	* delete_sec_context.c (krb5_gss_delete_sec_context): Free
+	acceptor subkey field.
+	* init_sec_context.c (get_credentials): Drop enctypes argument;
+	callers changed.
+	(get_requested_enctypes): Deleted.
+	(setup_enc): Combine some common sections.  Do CFX initialization
+	for newer enctypes.
+	(new_connection) [CFX_EXERCISE]: If doing CFX, send a bogus
+	token.  Delete the enctype list manipulation.
+	(mutual_auth): If CFX, save acceptor's subkey.
+	* k5seal.c (make_seal_token_v1): Sequence number is now 64 bits.
+	(kg_seal): Call out to _v3 code for CFX.
+	* k5unseal.c (kg_unseal): For CFX, adjust token id numbers and
+	call out to _v3 code.
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Implement CFX
+	support.
+
+	* gssapiP_krb5.h (struct _krb5_gss_ctx_id_rec): Deleted fields
+	ctypes and nctypes.
+	* delete_sec_context.c, init_sec_context.c, ser_sctx.c: Removed
+	references.
+
+2003-12-11  Alexandra Ellwood <lxs@mit.edu>
+
+	* acquire_cred.c, gssapi_krb5.c, gssapiP_krb5.h, set_ccache.c:
+        Added kg_sync_ccache_name(), kg_get_ccache_name, and 
+        kg_set_ccache_name() and rewrote gss_krb5_ccache_name() and
+        added a call to kg_sync_ccache_name() to acquire_init_cred()
+        to fix a bug where on systems with multiple ccaches that GSSAPI
+        gets stuck on the ccache that was default when it launched.
+
+2003-07-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* acquire_cred.c (krb5_gss_register_acceptor_identity): Allocate
+	enough memory to include the null at the end of the keytab char *.
+
+2003-07-17  Tom Yu  <tlyu@mit.edu>
+
+	* gssapiP_krb5.h: Delete kg_release_defcred(); it's no longer
+	used.
+
+	* gssapi_krb5.c: Delete defcred; it's no longer cached.
+	(kg_get_defcred): Don't cache.
+	(kg_release_defcred): Delete; it's no longer used.
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Break into more
+	manageable pieces.  Clean up a few error condition memory leaks
+	previously obscured by the sheer size of this function.
+	(setup_enc): New function; used to be part of
+	krb5_gss_init_sec_context() responsible for setting up enctypes,
+	keyblocks, related nastiness.
+	(get_requested_enctypes): New function; used to be part of
+	krb5_gss_init_sec_context() responsible for pruning the krb5
+	library's default enctype list to the limited set of enctypes
+	usable with GSSAPI.
+	(new_connection): New function; used to be part of
+	krb5_gss_init_sec_context() responsible for initial gss_ctx setup
+	and creating the AP-REQ.
+	(mutual_auth): New function; used to be part of
+	krb5_gss_init_sec_context() responsible for reading the AP-REP if
+	mutual auth was requested.
+
+	* inq_cred.c (krb5_gss_inquire_cred): Rearrange due to removal of
+	kg_release_defcred(), particularly to explicitly release the
+	defcred once it's obtained.
+
+	* rel_cred.c (krb5_gss_release_cred): Remove call to
+	kg_release_defcred(), and always succeed in releasing the null
+	credential.
+
+	* set_ccache.c (gss_krb5_ccache_name): Remove call to
+	kg_release_defcred().
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-07-14  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Call
+	TREAD_STR with correct arguments.  Patch from Emily Ratliff.
+
+2003-07-10  Tom Yu  <tlyu@mit.edu>
+
+	* acquire_cred.c (acquire_init_cred): Close the ccache if
+	krb5_cc_set_flags() fails, as krb5int_cc_default succeeds even if
+	the file is not there, but krb5_cc_set_flags will fail in turning
+	off OPENCLOSE mode if the file can't be opened.  Thanks to Kent Wu.
+
+2003-06-13  Tom Yu  <tlyu@mit.edu>
+
+	* init_sec_context.c (make_ap_req_v1): Free checksum_data if
+	needed, to avoid leaking memory.  Found by Kent Wu.
+	(krb5_gss_init_sec_context): Free default_enctypes to avoid
+	leaking returned value from krb5_get_tgs_ktypes.
+
+	* k5unseal.c (kg_unseal_v1): Explicitly set token.value to NULL if
+	token.length == 0, to avoid spurious uninitialized memory
+	references when calling memcpy() with a zero length.
+
+2003-05-13  Tom Yu  <tlyu@mit.edu>
+
+	* gssapi_krb5.h: Remove check for GSS_RFC_COMPLIANT_OIDS.
+
+2003-05-09  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Rename
+	remote_subkey -> recv_subkey.
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Rename
+	local_subkey -> send_subkey.
+
+2003-03-14  Sam Hartman  <hartmans@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Set
+	prot_ready here
+
+	* init_sec_context.c (krb5_gss_init_sec_context):  Set prot_ready
+	after context established
+
+	* gssapiP_krb5.h (KG_IMPLFLAGS): Don't claim prot_ready until the
+	context is established  because we don't currently support it.  
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+
+    * disp_status.c, gssapi_krb5.h, gssapiP_krb5.h: 
+    Removed Mac header goober.
+
+2003-03-05  Tom Yu  <tlyu@mit.edu>
+
+	* acquire_cred.c (krb5_gss_register_acceptor_identity): New
+	function.  Allows global override of default keytab for
+	gss_acquire_cred() purposes.
+	(acquire_accept_cred): Implement override.
+
+	* gssapi_krb5.h: Add krb5_gss_register_acceptor_identity.
+
+2003-03-04  Sam Hartman  <hartmans@mit.edu>
+
+	* accept_sec_context.c (rd_and_store_for_creds): Do not expect sequence number in incoming krb_cred message.
+
+2003-03-02  Sam Hartman  <hartmans@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Deal with
+	creds without rcache available.  They will be slower.
+
+	* add_cred.c (krb5_gss_add_cred): Deal with princ being null
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Populate
+	ctx->here from ticket->server instead of cred->princ.  If
+	cred->princ exists it will be the same, but the previous change
+	may make it null
+
+	* inq_cred.c (krb5_gss_inquire_cred): Allow for null princ
+	component of credentials
+
+	* acquire_cred.c: When acquiring acceptor credentials, allow
+	GSS_C_NO_NAME to mean that we accept any credential.  In this case
+	we do not look to see if the principal is found in the keytab and
+	we leave princ null in the context.  This means you get
+	GSS_C_NO_NAME out from inquire_cred.   If cred->princ is null
+	don't set up a rcache
+
+2003-03-01  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Don't
+	validate verifier_cred_handle if GSS_C_NO_CREDENTIAL is passed in.
+
+2003-02-25  Tom Yu  <tlyu@mit.edu>
+
+	* set_ccache.c (gss_krb5_ccache_name): Don't return a pointer to
+	freed memory.
+
+2003-02-24  Tom Yu  <tlyu@mit.edu>
+
+	* gssapi_krb5.c (kg_get_defcred): Revert previous; it's probably
+	not appropriate for inquire_cred() to cause new credentials to be
+	fetched.
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Explicitly
+	release default cred in the NO_CREDENTIAL case, so it is always
+	refreshed.
+
+2003-02-21  Tom Yu  <tlyu@mit.edu>
+
+	* gssapi_krb5.c (kg_get_defcred): Check for invalid or expired
+	defcred if it exists, and call acquire_cred() again if necessary.
+
+2003-02-13  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in ($(GSSAPI_KRB5_HDR)): Use $(S) to avoid problems on
+	windows.
+
+2003-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (includes): Delete gssapi_krb5.h rule.
+	($(GSSAPI_KRB5_HDR)): Add command to create header directory if
+	needed.
+	(all-unix): Add $(GSSAPI_KRB_HDR).
+
+2003-02-09  Ezra Peisach  <epeisach@bu.edu>
+
+	* init_sec_context.c (make_ap_req_v1): Unsigned/signed cleanup.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-07  Sam Hartman  <hartmans@mit.edu>
+
+	* init_sec_context.c (make_gss_checksum): New function to
+	construct the checksum in the authenticator, used directly  or
+	indirectly depending on whether krb5_cred is encrypted.
+	(make_ap_req_v1): use it
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.original: Deleted.
+
+2002-11-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Use unsigned
+	lengths for arguments to g_token_size and g_make_token_header.
+
+	* export_name.c (krb5_gss_export_name): Change local length
+	variable to unsigned.
+
+	* k5unseal.c (kg_unseal_v1): Seqnum variable changed from
+	krb5_int32 to krb5_ui_4.
+
+	* k5seal.c (make_seal_token_v1): Change seqnum argument to
+	krb5_ui_4 from krb5_int32 to match krb5_gss_ctx_id_rec struct.
+
+	* gssapiP_krb5.h, util_crypt.c, util_seqnum.c: kg_make_seq_num(),
+	kg_get_seq_num() changed to use krb5_ui_4 for sequence
+	numbers. kg_encrypt(), kg_decrypt() length argument now unsigned.
+
+2002-10-07  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in :  Add install-headers support
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(GSSAPI_KRB5_HDR)): Quote target of copy.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* k5unseal.c (kg_unseal): Pass unsigned int * instead of int *
+	length return argument to g_verify_token_header.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Pass
+	OM_uint32 * instead of krb5_error_code * to krb5_gss_release_cred.
+
+2002-07-14  Alexandra Ellwood <lxs@mit.edu>
+
+	* gssapi_krb5.h: Added #include of gssapi.h and gssapi_generic.h
+	for the Mac because we can't assume people will include them and
+	get the OID macro and the old names on the Mac.
+
+	* disp_status.c: Updated Mac OS X header paths.
+
+	* gssapiP_krb5.h: Updated Mac OS X header paths and added
+	prototype on Mac.
+
+	* gssapi_krb5.h: Updated Mac OS X headers to new framework layout
+
+	[pullups from 1-2-2-branch]
+
+2002-07-14  Miro Jurisic  <meeroh@mit.edu>
+
+	* gssapi_krb5.h, gssapi_krb5.c: Added oids from rfc 1964 using the
+	suggested names.
+	[pullup from 1-2-2-branch]
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* accept_sec_context.c (rd_and_store_for_creds): Remove
+	registration of memory ccache type.  Don't declare krb5_mcc_ops.
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Instead of
+	asking for the enctypes supported by the GSS code, use that set as
+	a filter on the default enctypes and use the resulting list.
+	(make_ap_req_v2): Delete unused function.
+
+	* k5mech.c, pname_to_uid.c, util_ctxsetup.c: Deleted.
+	* Makefile.in (SRCS, OBJS, STLIBOBJS): Don't compile
+	util_ctxsetup.c.
+	* rel_oid.c (krb5_gss_internal_release_oid): Now static.
+	* util_crypt.c (kg_encrypt_size): Function deleted.
+	* gssapiP_krb5.h (struct kg2_option, kg2_parse_token,
+	kg2_intersect_ctypes, krb5_gss_internal_release_oid,
+	kg_encrypt_size): Declarations deleted.
+
+2002-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi_krb5.c (gss_mech_krb5_v2, gss_mech_set_krb5_v2,
+	gss_mech_set_krb5_v1v2): Delete variables.
+	* gssapi_krb5.h (gss_mech_krb5_v2, gss_mech_set_krb5_v2,
+	gss_mech_set_krb5_v1v2): Delete declarations.
+	* add_cred.c (krb5_gss_add_cred): Delete uses of them.
+	* canon_name.c (krb5_gss_canonicalize_name): Ditto.
+	* disp_status.c (krb5_gss_display_status): Ditto.
+	* indicate_mechs.c (krb5_gss_indicate_mechs): Ditto.
+	* inq_cred.c (krb5_gss_inquire_cred_by_mech): Ditto.
+	* inq_names.c (krb5_gss_inquire_names_for_mech): Ditto.
+	* rel_oid.c (krb5_gss_internal_release_oid): Ditto.
+
+	* accept_sec_context.c (rd_and_store_for_creds): Extra parens
+	around assignments to quiet gcc.
+	(krb5_gss_accept_sec_context): Fix some type mismatches between
+	OM_uint32 and krb5_error_code.
+	* k5unseal.c (kg_unseal_v1): Move a variable declaration and
+	assignment to fix gcc "possibly uninitialized" warning.
+	* init_sec_context.c (get_credentials): Delete unused variable.
+
+2002-03-03  Sam Hartman  <hartmans@mit.edu>
+
+	* accept_sec_context.c (rd_and_store_for_creds): Patch from Steven
+	Michaud <smch@midway.uchicago.edu>  to accept encrypted or
+	unencrypted credentials.  This is important because Heimdal (and
+	sometimes Microsoft) send encrypted credentials.
+
+2001-11-18  Sam Hartman  <hartmans@mit.edu>
+
+	* init_sec_context.c (get_credentials): Override
+	default_tgs_enctypes rather than looping over credentials.  Avoids
+	hits on the KDC.
+
+2001-10-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5unseal.c: Fix whitespace in copyright message.
+
+	* k5seal.c (make_seal_token_v1): Cleanup code for mic
+	tokens. Essentially revert code to Sam's 10/25 code, with one
+	correction - allocation of data_ptr - use msglen and not tmsglen.
+	Additionally, do not rely on malloc(0) being non-NULL. 
+	
+2001-10-27  Sam Hartman  <hartmans@mit.edu>
+
+	* k5seal.c (make_seal_token_v1): Use usage 15 only for mic tokens,
+	not for seal tokens without encryption
+
+2001-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5seal.c (make_seal_token_v1): Correct errors in code pertaining
+	to case when signing message only. Fixes buffer overflows as found
+	by gssapi dejagnu testsuite.
+
+2001-10-25  Sam Hartman  <hartmans@mit.edu>
+
+	* k5unseal.c (kg_unseal_v1): same here.
+
+	* k5seal.c (make_seal_token_v1): Factor out usage type we claim
+	for signatures so we can do something different for  hmac-md5.
+	Microsoft uses a different usage number for  mic tokens and wrap  tokens.
+
+	* k5unseal.c (kg_unseal_v1):  Add arcfour checksum and decrypt support
+
+	* util_seqnum.c (kg_get_seq_num): support arcfour_hmac
+
+	* k5unseal.c (kg_unseal_v1): Get the sequence number before
+	decrypting the token so we can use it to decrypt arcfour 
+
+	* gssapiP_krb5.h util_crypt.c:  New function kg_arcfour_docrypt
+
+	* util_seqnum.c (kg_make_seq_num): Add rc4 support
+
+	* k5seal.c (make_seal_token_v1): Simplify logic significantly.
+	Don't worry so much about only allocating memory we use; allocate
+	a full token all the time  and only decide not to copy in data at
+	the last moment.  This significantly simplifies the control flow,
+	giving better testing coverage and allowing better reasoning about
+	the code. Add arcfour-hmac support
+
+	* util_crypt.c (kg_confounder_size): Special case arcfour to return 8
+
+2001-10-24  Sam Hartman  <hartmans@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Support rc4 enctype
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Support rc4 enctype
+
+	* gssapiP_krb5.h: Remove claim we don't support Microsoft sign alg
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapiP_krb5.h, gssapi_krb5.h, k5mech.c: Make prototypes
+	unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* accept_sec_context.c, gssapiP_krb5.h, import_sec_context.c,
+	krb5_gss_glue.c: Don't explicitly declare pointers FAR any more.
+
+	* pname_to_uid.c: Drop _MSDOS support.
+
+2001-10-04  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Ignore
+	unrecognized options properly. [krb5-libs/738]
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* copy_ccache.c, get_tkt_flags.c, gssapi_krb5.h, krb5_gss_glue.c,
+	set_ccache.c: Don't use GSS_DLLIMP.
+
+2001-10-01  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (rd_and_store_for_creds): Handle error
+	returns from krb5_rd_cred more sanely.
+
+2001-07-27  Danilo Almeida  <dalmeida@mit.edu>
+
+	* gssapi_krb5.h: Unmark gss_mech_krb5 variable as an import.
+
+2001-07-27  Danilo Almeida  <dalmeida@mit.edu>
+
+	* gssapi_krb5.h: Mark gss_mech_krb5 variable as an import.
+
+2001-07-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* import_sec_context.c (krb5_gss_import_sec_context): Get rid of
+	variable set but never used.
+	* ser_sctx.c (kg_queue_internalize): Ditto
+	
+2001-07-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* ser_sctx.c: Declare kg_oid_size and kg_queue_size static.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Do not
+	shadow local variable ptr.
+
+2001-06-22  Danilo Almeida  <dalmeida@mit.edu>
+
+	* util_crypt.c (kg_encrypt, kg_decrypt): Use free() instead of
+	krb5_free_data_contents().
+
+	* util_cksum.c (kg_checksum_channel_bindings): Make sure that
+	returned memory is allocated with xmalloc() so that caller can use
+	xfree() on it.
+
+	* k5unseal.c (kg_unseal_v1):  Use krb5_free_data_contents()
+	instead of xfree().
+
+	* k5seal.c (make_seal_token_v1): Use krb5_free_data_contents()
+	instead of xfree().
+
+	* init_sec_context.c (make_ap_req_v1): Use xfree() instead of
+	free() to be consistent with xmalloc() usage.  Use
+	krb5_free_data_contents() instead of xfree().
+
+	* disp_name.c (krb5_gss_display_name): Use
+	krb5_free_unparsed_name() instead of xfree().
+
+	* add_cred.c (krb5_gss_add_cred): Use xfree() instead of free() to
+	be consistent with xmalloc() usage.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Remove
+	variables that were effectively unused.  Use
+	krb5_free_data_contents() instead of xfree() where appropriate.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* acquire_cred.c (acquire_init_cred): Include "k5-int.h" for
+	krb5int-cc_default() prototype.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* accept_sec_context.c acquire_cred.c import_sec_context.c
+	init_sec_context.c inq_cred.c: Cast const gss_OID to gss_OID for
+	gssapi functions which are not speced with const in the RFC.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* ser_sctx.c (kg_oid_internalize): Do away with local variable
+	that was set but never used.
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Cleanup
+ 	assignments in conditionals.
+	* k5seal.c (make_seal_token_v1): Likewise.
+
+2001-05-14  Ezra Peisach  <epeisach@mit.edu>
+
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Get rid of unused
+	variable.
+
+	* util_ctxsetup.c (kg2_parse_token): Fix erroneous assignment in
+	conditional. (code not used in current tree). 
+
+	* util_seed.c, util_seqnum.c, util_crypt.c, util_cksum.c: Cleanup
+	up assignments in conditionals.
+
+	* ser_sctx.c (kg_queue_internalize): Get rid of unused variable.
+
+	* gssapiP_krb5.h: Renable prototype for krb5_gss_release_oid() as
+	code is back (since 1996).
+
+	* k5unseal.c (kg_unseal_v1): Declare internal function static.
+
+	* init_sec_context.c (make_ap_req_v2): Comment out non-referenced
+	function.
+
+	* gssapi_krb5.c: Include k5-int.h for krb5_ser_* prototypes.
+
+2001-04-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* util_crypt.c (kg_make_confounder): Change variable random to
+ 	lrandom to prevent shadowing of global function.
+
+2000-12-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* k5seal.c (make_seal_token_v1): Use ANSI-style definition,
+	instead of K&R plus prototype.  Don't use too-big numbers even as
+	placeholders.
+
+	* accept_sec_context.c (rd_and_store_for_creds): After creating an
+	auth context, set flags to require sequence numbers.
+	(krb5_gss_accept_sec_context): Likewise.
+	* init_sec_context.c (krb5_gss_init_sec_context): Likewise.
+
+2000-10-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): If an error
+	occurs after the auth_context is established, but before the
+	krb5_gss_ctx_id_rec is established, release our pointer to the
+	replay cache and invoke krb5_auth_con_free(). (krb5-libs/855)
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* add_cred.c (krb5_gss_add_cred): krb5_cc_get_type() and
+	krb5_cc_get_name() return const char *. Cleanup assigments in
+	conditionals warnings.
+
+Fri Sep 22 12:05:31 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): When
+ 	GCC_S_NO_CHANNEL_BINDINGS is set by the server, skip over the
+ 	bindings sent from the client. RFC-1964 indicates that the
+ 	client's channel bindings are always sent in checksum field and
+ 	need to be accounted for, evn if the server does not care.
+
+2000-09-01  Jeffrey Altman <jaltman@columbia.edu>
+
+        * accept_sec_context.c: krb5_gss_accept_sec_context()
+        It has been determined by Martin Rex that Windows 2000 is incapable
+        of supporting channel bindings.   This caused us to examine the
+        various RFCs affecting FTP GSSAPI to determine whether or not
+        channel bindings were a MUST for implementation of the FTP GSSAPI
+        protocol.  It was determined that the channel binding facility as
+        described in RFC2743 is optional.  Therefore, we cannot assume
+        that all clients or servers will support it.  The code was updated
+        to allow GSS_C_NO_CHANNEL_BINDINGS when specified by either the
+        client or server to indicate that channel bindings will not be
+        used.
+
+2000-06-27  Tom Yu  <tlyu@mit.edu>
+
+	* init_sec_context.c (get_credentials): Add initial iteration of
+	krb5_get_credentials in order to differentiate between an actual
+	missing credential and merely a bad match based on enctype.  This
+	was causing problems with kadmin.
+
+2000-06-09  Tom Yu  <tlyu@mit.edu>
+	    Ken Raeburn  <raeburn@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Remove
+	explicit check of mech OID against credential.
+
+	* util_crypt.c (kg_encrypt): Copy ivec, since c_encrypt() now
+	updates ivecs.
+	(kg_decrypt): Copy ivec, since c_decrypt() now updates ivecs.
+
+	* init_sec_context.c (get_credentials): Don't check each enctype
+	against a list from the krb5 library; instead, just try to use it,
+	and go on to the next if the error code indicates we can't use it.
+
+	* gssapiP_krb5.h (enum qop): New type, derived from spec but
+	currently not used.
+	* util_crypt.c (kg_encrypt, kg_decrypt): Added key derivation
+	usage value as an argument.  Prototypes and callers updated; all
+	callers use KG_USAGE_SEAL, except KG_USAGE_SEQ when encrypting
+	sequence numbers.
+	* 3des.txt: New file.
+
+	* gssapiP_krb5.h (struct _krb5_gss_ctx_id_rec): Delete field
+	gsskrb5_version.
+	(struct _krb5_gss_cred_id_rec): Delete field rfcv2_mech.
+	* accept_sec_context.c, acquire_cred.c, add_cred.c, inq_cred.c,
+	k5seal.c, k5unseal.c, ser_ctx.c:
+	Delete krb5-mech2 support.
+
+	* init_sec_context.c (get_credentials): Enctype argument is now a
+	pointer to a list of enctypes.  Explicitly try each in order until
+	success or an error other than cryptosystem not being supported.
+	(krb5_gss_init_sec_context): Pass list of cryptosystems, starting
+	with 3DES.
+
+	* gssapiP_krb5.h (enum sgn_alg, enum seal_alg): New types,
+	giving symbolic names for values from RFC 1964, a Microsoft win2k
+	I-D, and our proposed 3des-sha1 values.
+	(KG_USAGE_SEAL, KG_USAGE_SIGN, KG_USAGE_SEQ): New macros.
+
+	* accept_sec_context.c (rd_req_keyproc): Already-disabled routine
+	deleted.
+	(krb5_gss_accept_sec_context): Use sgn_alg and seal_alg symbolic
+	names.  Add a case for des3-hmac-sha1.
+	* k5seal.c (make_seal_token_v1): Likewise.  Do key derivation for
+	checksums.
+	* k5unseal.c (kg_unseal_v1): Likewise.
+	* util_crypt.c (kg_encrypt, kg_decrypt): Do key derivation for
+	encryption.
+
+	* util_crypt.c (zeros): Unused variable deleted.
+
+	* wrap_size_limit.c: Remove mech2 support.  Add MIT copyright.
+
+2000-06-09  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* add_cred.c (krb5_gss_add_cred): Don't overflow buffers "ktboth"
+	or "ccboth".
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* accept_sec_context.c, gssapiP_krb5.h, init_sec_context.c,
+	k5unseal.c, util_cksum.c, util_crypt.c, util_seed.c: Check for
+	existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-5-19	Alexandra Ellwood <lxs@mit.edu>
+
+	* acquire_cred.c: Changed to use krb5int_cc_default.  This function 
+	supports the Kerberos Login Library and pops up a dialog if the cache does 
+	not contain valid tickets.  This is used to automatically get a tgt before
+	obtaining service tickets.  Note that this should be an internal function
+	because callers don't expect krb5_cc_default to pop up a dialog!
+	(We found this out the hard way :-)
+
+2000-04-08  Tom Yu  <tlyu@mit.edu>
+
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Fix up
+	wrap_size_limit() to deal with integrity wrap tokens properly.
+	The rfc1964 mech always pads and confounds regardless of whether
+	confidentiality is requested.
+
+2000-01-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Default to
+	des-cbc-crc.
+
+1999-10-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Get rid of
+	unused variables 'err' and 'enctype'.
+
+	* k5seal.c (make_integ_token_v2): Set 'code' when malloc fails.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Wed May 19 13:21:55 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Improve rule to create gssapi include dir under
+		windows.
+
+Wed May 19 11:40:52 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add windows build rules for putting header files in
+		include dir.
+
+Mon May 10 15:22:27 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Fri Apr 30 12:27:14 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* set_ccache.c (gss_krb5_ccache_name): Add call to free the
+		default credential changing the ccache name.
+
+Thu Apr 29 18:02:00 1999  Miro Jurisic  <meeroh@mit.edu>
+
+	* gssapi_krb5.h: Remove gssapi_generic.h includes because
+		this header file is public interface and gssapi_generic.h
+		isn't and shouldn't be included by clients.
+
+Fri Apr 23 00:31:17 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Fix wrap_size
+		limit so that it correctly calculates its results, and
+		underestimates the correct size instead of overestimating
+		it, and not returning zero all the time.  (Which it used
+		to do after the March 25 fix.)
+
+Sat Apr 17 01:23:57 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssapi_krb5.h, copy_ccache.c, get_tkt_flags.c, set_ccache.c:
+ 		Make the krb5 extension functions exportable in a Windows
+ 		DLL.
+
+Fri Mar 26 22:17:20 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* acquire_cred.c (krb5_gss_acquire_cred): Don't use strcmp to
+ 		compare against principal components (they aren't null
+ 		terminated!)
+
+Thu Mar 25 22:43:54 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssapi_krb5.c: Rearrange OID's so that the V1V2 mechanism set
+		returns all three mechanism ID's recognized by this
+		implementation, with the RFC1964 OID first (and thus
+		preferred). 
+
+	* import_sec_context.c (krb5_gss_convert_static_mech_oid): Make
+		the old convert_static_oid() function globally accessible
+		with a namespace compliant name, since init_sec_context()
+		needs to be able to use this function.
+
+	* indicate_mechs.c (krb5_gss_indicate_mechs): Return the v1v2
+		mechanism set OID, since we should return all the
+		mechanisms that we support.
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Make
+ 		ctx->mech_used use a static OID, since it is returned by
+ 		gss_inquire_context which must return a static OID.
+
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Fix bug where we
+		would overestimate the size of the allowable input message
+		by one byte, because we weren't passing the right estimate
+		of the wrapped data to g_token_size().
+
+1999-03-14  Miro Jurisic  <meeroh@mit.edu>
+
+	* gssapi_krb5.h: added extern "C" for C++ friendliness
+
+1999-03-14  Miro Jurisic  <meeroh@mit.edu>
+
+	* set_ccache.c (gss_krb5_ccache_name): Now compiles
+
+1999-03-11  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* set_ccache.c (gss_krb5_ccache_name): Added new Krb5 specific
+		interface to set the default credentials cache name.
+
+1999-02-19  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (DLL_FILE_DEF): Tell the Makefile template that we
+		are building object files for the GSSAPI DLL.
+
+	* krb5_gss_glue.c: Change use of KRB5_DLLIMP to be GSS_DLLIMP.
+
+Mon Dec 21 19:50:04 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Eliminate
+ 		double free of ap_req.data, and initialize ctypes to be
+ 		NULL to avoid freeing a pointer to stack garbage when
+ 		doing a V1 mechanism accept_sec_contxt.
+
+	* init_sec_context.c: Re-arrange program logic to simplify and
+		factor out code; fix gss_init_sec_context() so that if the
+		default OID is passed to the init_sec_context, it will use
+		the V1 mechanism if a single DES enctype is used.   Error
+		handling was revamped to make it simpler and cleaner, and
+		to assure that we don't have memory leaks on error returns.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Nov  6 09:19:23 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* k5unseal.c (kg2_unwrap_integ): Handle case of malloc(0)
+	returning NULL.
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in, accept_sec_context.c, acquire_cred.c, canon_name.c,
+	delete_sec_context.c, disp_status.c, gssapiP_krb5.h,
+	gssapi_err_krb5.et, gssapi_krb5.c, gssapi_krb5.h,
+	init_sec_context.c, inq_cred.c, inq_names.c, k5seal.c, k5unseal.c,
+	rel_oid.c, ser_sctx.c, util_cksum.c, util_crypt.c, util_seed.c,
+	util_seqnum.c, wrap_size_limit.c: convert to new crypto api.
+	Implement new krb5 v2 gssapi mechanism.
+
+	* add_cred.c, util_ctxsetup.c: New files needed to implement the
+	krb5 v2 mech.
+
+Mon Sep 21 00:32:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Free authdat
+	even on success to avoid a memory leak.
+
+	* util_cksum.c (kg_checksum_channel_bindings): Fix memory leak by
+ 	not allocating cksum->contents unless we have to return a
+ 	zero-filled one.
+
+	* k5unseal.c (kg_unseal_v1): Fix memorly leak by not allocating
+	md5cksum.contents.
+
+	* k5seal.c (make_seal_token_v1): Fix memory leak by not allocating
+	md5cksum.contents.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Only free
+	ap_req.data if it was allocated by kg2_parse_token(), otherwise we
+	lose very badly trying to free the middle of a potentially
+	malloc()'ed block, possibly coredumping.
+
+Thu Sep  3 19:35:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Fix typo;
+	bash the enctype in ctx->subkey->enctype rather than just
+	"enctype", which nothing checks.
+
+Fri Jul 24 21:13:53 1998  Tom Yu  <tlyu@mit.edu>
+
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Fix to round down
+	by 8 even if the req_output_size-ohlen is a multiple of 8, since
+	the wrap token is always padded regardless of whether it's a
+	mutiple of 8 bytes.
+
+1998-06-08  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* k5unseal.c (kg_unseal):  Clean up lint warnings.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Don't return
+		an error token if we can't provide the server name to the
+		KRB5 error structure (because cred isn't initialized).
+
+	* gssapi_krb5.c, gssapi_krb5.h: Export the oid of static
+		arrays as krb5_gss_oid_array since it's needed by
+		gss_import_sec_context.
+
+	* import_sec_context.c: Fix up the OID of the mechanism in the
+		imported security context so that we use the static
+		OID if at all possible.  This is needed since
+		gss_inquire_context() must return a static OID.
+
+Sun May 24 21:57:03 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* import_name.c (krb5_gss_import_name): Fix typo which caused
+ 		import_name to incorrectly import names produced by
+ 		gss_export_name().
+
+1998-05-24  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* copy_ccache.c (gss_krb5_copy_ccache): Fix bugs in copy_ccache.c,
+		which never compiled cleanly (since it wasn't added to the
+		Makefile correctly originally).
+
+	* k5seal.c (make_seal_token): Clean up -Wall flames
+
+1998-05-18  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inq_cred.c (krb5_gss_inquire_cred): 
+	* inq_context.c (krb5_gss_inquire_context): 
+	* import_name.c (krb5_gss_import_name): 
+	* export_name.c (krb5_gss_export_name): 
+	* disp_name.c (krb5_gss_display_name): 
+	* context_time.c (krb5_gss_context_time): 
+	* acquire_cred.c (krb5_gss_acquire_cred): Clean up -Wall flames.
+
+	* indicate_mechs.c (krb5_gss_indicate_mechs): Return a dynamic OID
+		set.
+
+Fri Feb 27 18:41:08 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* export_name.c (krb5_gss_export_name): Fix bug in
+ 	 	gss_export_name.  The 2nd length field in the ASN.1 was 2
+ 	 	bytes bigger than it should have been.
+
+Wed Feb 18 16:12:14 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 13:23:18 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Don't
+		restrict mechanisms when accepting contexts.  (Allow
+		either pre-RFC or RFC-based mechanisms)
+
+Thu Feb 12 16:38:14 1998  Tom Yu  <tlyu@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Add lots of
+	explicit assignments to major_status to ensure that we actually
+	return an error when we mean to.  This was previously preventing
+	gssrpc authentication with the old ovsec_kadm interface from
+	working because the gssrpc server side functions were failing to
+	loop over a set of supplied credentials.
+
+	* init_sec_context.c: KLUDGE!! Add global variable
+	krb5_gss_dbg_client_expcreds to allow the client library to send
+	expired credentials for testing and debugging purposes.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 28 16:57:05 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in, Makefile.in: Remove use of CopySrcHeader from
+		configure.in and move functionality to Makefile.in
+
+Thu Feb  5 22:39:44 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* wrap_size_limit.c (krb5_gss_wrap_size_limit): Fix bug where if
+		the output header size is greater than the maximum
+		requested output size, return 0 rather than a very large
+		unsigned number.  :-)
+
+Fri Jan 30 23:07:40 1998  Tom Yu  <tlyu@mit.edu>
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Actually
+	initialize now before calling make_ap_req.
+
+Thu Jan 29 20:08:02 1998  Dan Winship  <danw@mit.edu>
+
+	* accept_sec_context.c (rd_and_store_for_creds): Don't mess with
+	krb5_cc_default--use a new mem-based ccache.
+
+	* Makefile.in: 
+	* gssapi_krb5.h: 
+	* copy_ccache.c (gss_krb5_copy_ccache): Routine to copy a
+	gss_cred_id_t (such as a forwarded creds) into an existing
+	krb5_ccache.
+
+Fri Jun 27 08:37:11 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Will now
+ 		obtain default credentials if no credentials are given.
+
+Wed Dec  3 02:16:18 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_sec_context.c (make_ap_req): Enforce a stricter requirement
+		on the ticket expiration time of the credentials, since
+		accept_sec_context doesn't use the timeskew fudge for
+		checking ticket expirations.
+		(krb5_gss_init_sec_context): Return GSS_S_NO_CRED when
+		appropriate. 
+
+Wed Jan 21 19:14:09 1998  Tom Yu  <tlyu@mit.edu>
+
+	* gssapiP_krb5.h: Add rcache member to the creds
+	structure. [krb5-libs/370]
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Actually set
+	an rcache in auth context from the one saved in the creds
+	structure. [krb5-libs/370]
+
+	* acquire_cred.c (acquire_accept_cred): Set up an rcache for use
+	later. [krb5-libs/370]
+
+	* delete_sec_context.c (krb5_gss_delete_sec_context): Don't delete
+	the rcache when freeing the auth_context. [krb5-libs/370]
+
+	* rel_cred.c (krb5_gss_release_cred): Properly close the
+	rcache. [krb5-libs/370]
+
+Mon Dec 29 10:30:43 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (OBJS): Changed val_cred.$(OBJECT) to
+	        val_cred.$(OBJEXT) for windows building.
+
+Sun Dec  7 10:42:32 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* val_cred.c (krb5_gss_validate_cred): Free principal extracted
+		from credential cache when finished.
+
+Sat Nov 15 20:14:05 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context), 
+	  init_sec_context.c (krb5_gss_init_sec_context),
+	  inq_cred.c (krb5_gss_inquire_cred): Call krb5_gss_validate_cred
+	  	to make sure the credential handle is still valid.
+
+	* val_cred.c (krb5_gss_validate_cred): New file which validates
+		the credential to make sure it is valid, including
+		checking to make sure the credentials cache still points
+		at the same krb5 principal as it did before.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Return
+ 		GSS_S_FAILURE if a non-NULL context handle is passed to
+ 		it.
+
+Thu Sep 18 17:55:09 1997  Tom Yu  <tlyu@mit.edu>
+
+	* acquire_cred.c: Replace USE_STRING_H with something more sane.
+
+	* import_name.c: Replace USE_STRING_H with something more sane.
+
+Tue Jul 29 22:56:04 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* inq_names.c (krb5_gss_inquire_names_for_mech): Add the 
+ 		the new OID value for the host-based service name and 
+ 		the exported name OID to the list of OID's supported by
+		this mechanism.
+	
+	* import_name.c (krb5_gss_import_name): Add support for the new
+		OID value for the host-based service name.
+
+Mon Jul 21 20:32:14 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Initialize
+		ctx before referenced in failure cases.
+
+Tue Jul 15 22:05:21 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Always copy the
+		mechtype so that delete_sec_context() can safely release
+		the OID without smashing memory passed in by the application.
+
+Mon Jun 30 14:05:51 1997  Kevin L Mitchell  <klmitch@mit.edu>
+
+	* accept_sec_context.c: added code to return a valid delegated
+		credential handle if credentials were delegated.  The
+		GSS_C_DELEG_FLAG from the client is ignored, and the
+		option is only set if the client actually delegated
+		credentials.
+
+Fri Jun  6 15:26:27 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Reorganized
+ 		error handling code to be more compact (and correct!).  If
+ 		an error occurs while we are doing mutual authentication,
+ 		send an KRB_ERROR message back to the client, so that it
+ 		knows what is going on.  (This is specified by RFC 1964;
+ 		we just weren't implementing this previously.)
+           
+	* delete_sec_context.c (krb5_gss_delete_sec_context): Check to
+ 		make sure pointers in the context are non-zero before
+ 		freeing them.
+
+	* init_sec_context.c (krb5_gss_init_sec_context): If the server
+		sends a KRB_ERROR message, decode it and return an
+		appropriate minor status error code.
+
+Mon Mar 31 21:22:19 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5_gss_glue.c: Add GSSAPI V2 calls to the glue layer.
+
+Fri Mar 28 03:52:14 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* import_name.c (krb5_gss_import_name): Add support for importing
+		the exported name call
+
+	* export_name.c (krb5_gss_export_name): Fix export_name emit the token
+		exactly as specified by RFC 2078.
+
+Thu Mar 27 15:52:04 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Add canon_name.c, duplicate_name.c, export_name.c
+		to the GSSAPI library.
+	
+	* canon_name.c (krb5_gss_canonicalize_name): New GSSAPI V2 function
+
+	* duplicate_name.c (krb5_gss_duplicate_name): New GSSAPI V2 function
+
+	* export_name.c (krb5_gss_export_name): New GSSAPI V2 function
+
+	* gssapiP_krb5.h (KG_IMPLFLAGS): Add support for
+		GSS_C_PROT_STATE_READY and GSS_C_TRANS_FLAG
+
+Tue Mar 25 01:00:55 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_sec_context.c (krb5_gss_init_sec_context): A zero-length
+		token should be treated like a GSS_C_NO_BUFFER during the
+		initial context establishment.  [krb5-libs/352]
+
+Sat Feb 22 18:59:42 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Wed Feb  5 20:27:50 1997  Richard Basch  <basch@lehman.com>
+
+	* util_crypt.c: Include k5-int.h as we need to dereference
+		the _cryptosystem_entry element of the krb5_encrypt_block.
+
+	* acquire_cred.c (acquire_accept_cred): Removed unused local variable
+
+Tue Feb  4 15:56:01 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Only override the object build of the error table
+		under Unix
+
+Tue Jan 14 20:20:10 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Wed Dec  4 13:06:13 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* acquire_cred.c (acquire_accept_cred): use krb5_kt_get_entry
+ 	instead of scanning through keytab to find matching principal
+ 	[krb5-libs/210]
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+	* gssapiP_krb5.h krb5_gss_glue.c:
+	DLL export all public GSSAPI interfaces; adjusted some other
+	declarations accordingly (KRB5_CALLCONV, FAR keywords added)
+
+Wed Nov 20 19:55:29 1996  Marc Horowitz  <marc@cygnus.com>
+
+	* init_sec_context.c (make_ap_rep, krb5_gss_init_sec_context),
+ 	accept_sec_context.c (krb5_gss_accept_sec_context): fix up use of
+ 	gss flags.  under some circumstances, the context would not have
+ 	checked for replay or sequencing, even if those features were
+	requested.
+
+	* init_sec_context.c (make_ap_req), (krb5_gss_init_sec_context):
+ 	If delegation is requested, but forwarding the credentials fails,
+	instead of aborting the context setup, just don't forward
+	credentials.
+
+	* gssapiP_krb5.h (krb5_gss_ctx_id_t), ser_sctx.c
+ 	(kg_ctx_externalize, kg_ctx_internalize), init_sec_context.c
+ 	(krb5_gss_init_sec_context), get_tkt_flags.c
+ 	(gss_krb5_get_tkt_flags), accept_sec_context.c
+ 	(krb5_gss_accept_sec_context): rename ctx->flags to
+ 	ctx->krb_flags, to disambiguate it from ctx->gss_flags
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): If the subkey
+	isn't present in the authenticator, then use the session key
+	instead.
+
+Sat Oct 19 00:38:22 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ser_sctx.c (kg_oid_externalize, kg_oid_internalize,
+ 		kg_oid_size): Add a GSSAPI OID magic number to the
+ 		externalized OID, so that if the OID is skipped, (it is
+ 		optional), the serialization code can resyncronize if
+ 		necessary.
+		(kg_queue_internalize, kg_queue_externalize,
+ 		kg_queue_size): New functions to externalize the gssapi
+ 		queue.
+		(kg_ctx_size, kg_ctx_exteranlize, kg_ctx_import): Changed
+ 		to include the mech_used field and to include the auth
+ 		context.
+
+	* gssapi_krb5.c (kg_get_context): Add calls to correctly
+ 		initialize the serializers needed by import and export sec
+ 		context.
+
+	* delete_sec_context.c (krb5_gss_delete_sec_context): Remember to
+		release the mech_used OID if necessary!
+
+Wed Oct 16 17:53:17 1996  Marc Horowitz  <marc@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): return an
+ 	error if the ticket endtime is in the past.  also, cleaned up
+ 	some error cleanup code.
+
+Thu Oct 10 13:50:49 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* acquire_cred.c (krb5_gss_acquire_cred): Don't let the "timeleft"
+ 		returned by krb5_gss_acquire_cred be negative!
+
+Wed Oct  9 18:02:43 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssapi_krb5.c: Definition of gss_nt_krb5_name was incorrect;
+		someone was being a bonehead.
+
+Wed Aug 28 17:45:55 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* util_cksum.c (kg_checksum_channel_bindings): Fix stupid bug;
+		don't free buf before it's allocated!
+
+Thu Aug 15 20:52:37 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* init_sec_context.c (make_ap_req): Require des-cbc-crc for now;
+        DES3 support is broken.
+
+Fri Aug  2 13:40:16 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* acquire_cred.c (krb5_gss_acquire_cred): Add const to local
+		variable which is pointing to const data.
+
+Fri Jul 26 16:58:31 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in (OBJS): Remove trailing backslash on a comment; it
+		was keeping HDRS from getting set.
+
+Fri Jul 26 00:40:43 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* configure.in: Add AC_PROG_INSTALL, since it's needed for a "make
+		install"
+
+Thu Jul 25 20:21:33 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in: remove trailing backslash from comment under SRCS
+		because it was causing line that set OBJS variable to
+		become part of a comment
+
+Thu Jul 25 02:08:17 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Fixed error
+ 		checking so that if you pass a bad mechanism type, it
+ 		*will* get flagged as an error.
+
+Wed Jul 24 22:54:37 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* acquire_cred.c (krb5_gss_acquire_cred): Initialize variable
+		before use if GSS_C_NULL_OID_SET.
+
+Wed Jul 24 19:40:55 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* rel_oid.c (krb5_gss_release_oid): 
+	* krb5_gss_glue.c(gss_release_oid): Re-enable function
+
+	* ser_sctx.c (kg_oid_externalize): Add proper return code
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): 
+	* init_sec_context.c (krb5_gss_init_sec_context): Test (gss_flags &
+		XXXX) against 0 so that we pass a int value to
+		g_order_init.  Needed since int is 16 bits for Win16 build.
+
+Tue Jul 23 22:35:53 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Fix broken Windows commands to copy
+		gssapi_krb5.h to include/gssapi.
+
+	* gssapiP_krb5.h: Must include k5-int.h on Windows and Macintosh
+		builds. 
+
+Thu Jul 18 19:48:48 1996  Marc Horowitz  <marc@mit.edu>
+
+	* init_sec_context.c (krb5_gss_init_sec_context),
+ 	accept_sec_context.c (krb5_gss_accept_sec_context): ifdef'd out
+ 	reference to 3des.
+
+Fri Jul  5 15:27:29 1996  Marc Horowitz  <marc@mit.edu>
+
+	* gssapi_krb5.h: Add declarations for _old mech set, and _both
+ 	mech set
+
+Thu Jun 20 23:15:57 1996  Marc Horowitz  <marc@mit.edu>
+
+	* ser_sctx.c (kg_oid_size, kg_ctx_size): pull the oid-related code
+ 	out of kg_ctx_size into kg_oid_size.
+	
+	* k5unseal.c (kg_unseal), k5seal.c (make_seal_token): == cannot be
+ 	used to compare oid's.  The g_OID_equal macro must be used.
+
+	* init_sec_context.c (make_ap_req, krb5_gss_init_sec_context): -
+ 	gss_init_sec_context should use the mech set in the credential.
+  	If the default mech is requested, but the old mech oid was
+ 	explicitly passed to gss_acquire_cred, then the context should be
+ 	the old mech, otherwise, the new mech.  If a mech was requested
+ 	explicitly, then the code should insure that the credential is
+ 	compatible.
+
+	* acquire_cred.c (krb5_gss_acquire_cred), gssapiP_krb5.h (struct
+ 	_krb5_gss_cred_it_rec), gssapi_krb5.c (gss_mech_set_krb5*),
+ 	inq_cred.c (krb5_gss_inquire_cred): gss_acquire_cred needs to be
+ 	able to deal with both mech oid's.  It should return in
+ 	actual_mechs the intersection of the set passed in and the
+ 	{old,new} mechs, or if the default was requested, it should return
+ 	both mech oid's.  This state should be stored in the credential
+ 	handle, and regurgitated by gss_inquire_cred.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): make sure
+ 	that the oid in the token is compatible with the mechanisms
+ 	specified by the credential.
+
+Thu Jun 13 22:11:30 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to ET_RULES
+
+Wed Jun 12 00:48:32 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Update special rule for gssapi_err_krb5.obj so that
+		it uses the right Win-32 library command.
+
+	* pname_to_uid.c: Add #ifdef _WIN32 in places where we had #ifdef
+	 	_MSDOS
+
+Fri Jun  7 14:52:56 1996  Kevin L Mitchell  <klmitch@mit.edu>
+
+	* accept_sec_context.c, init_sec_context.c, inq_context.c,
+ 		gssapiP_krb5.h: changed `mutual' element of struct
+		_krb5_gss_ctx_id_rec into more general `gss_flags' and
+		updated functions that process it
+
+Tue May 14 19:09:49 1996  Richard Basch  <basch@lehman.com>
+
+	* k5seal.c k5unseal.c util_cksum.c:
+		setup krb5_checksum "contents" and "length" field prior to
+		calling krb5_calculate_checksum().
+
+Tue May 14 04:42:11 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_sec_context.c (make_ap_req): Change call to
+ 		krb5_auth_con_setcksumtype to use
+ 		krb5_auth_con_set_req_cksumtype by default instead.
+
+Sun May 12 00:54:35 1996  Marc Horowitz  <marc@mit.edu>
+
+	* util_crypt.c (kg_encrypt): It used to be that krb5_encrypt could
+ 	be used to encrypt in place.  That's broken now.  This would need
+ 	to be fixed in several places in the crypto layer, and it's not
+ 	clear what the right thing is, so it's worked around here in the
+ 	interests of portability and reliablility, at the expense of a
+ 	malloc/memcpy/free.
+
+	* Makefile.in, configure.in: gssapi_krb5.h should be installed
+ 	inside the tree.  This is really only half the work, as it should
+ 	be installed outside of the tree, too.
+
+Sat Apr 20 00:02:51 1996  Marc Horowitz  <marc@mit.edu>
+
+	* accept_sec_context.c, export_sec_context.c, gssapiP_krb5.h,
+ 	import_sec_context.c, init_sec_context.c, k5seal.c, k5unseal.c,
+ 	ser_sctx.c, wrap_size_limit.c: Implemented triple-des changes
+ 	based on Richard's patches.
+
+Wed Apr 17 21:08:59 1996  Marc Horowitz  <marc@mit.edu>
+
+	* accept_sec_context.c (krb5_gss_set_backward_mode): removed
+
+	* krb5_gss_glue.c, wrap_size_limit.c: added
+	
+	* import_sec_context.c: intern the newly created context id so
+ 	that the validation functions will accept it.
+	
+	* Makefile.in (CFLAGS): Don't need md5 header files anymore.
+  	(OBJS, SRCS): Change the list of files to build.
+
+	* export_sec_context.c, import_sec_context.c, gssapiP_krb5.h,
+ 	ser_sctx.c: don't use the serialization abstraction, since it
+ 	doesn't add anything, and is internal to kerberos.  Instead, make
+ 	the {de,}serialization functions internal gssapi functions, and
+ 	call those directly.
+
+	* accept_sec_context.c, acquire_cred.c, context_time.c,
+ 	delete_sec_context.c, disp_name.c, disp_status.c,
+ 	export_sec_context.c, gssapi_krb5.c (kg_get_context),
+ 	import_name.c, import_sec_context.c, indicate_mechs.c,
+ 	init_sec_context.c, inq_context.c, inq_cred.c, inq_names.c,
+ 	process_context_token.c, rel_cred.c, rel_name.c, seal.c, sign.c,
+ 	unseal.c, verify.c:
+ 	Don't pass in the context from the caller.  Instead, call
+ 	kg_get_context() to find out the kerberos library context.  Also,
+ 	random minor compile-time fixes.
+
+	* accept_sec_context.c, gssapi_krb5.c (kg_get_defcred),
+ 	gssapiP_krb5.h, init_sec_context.c, k5seal.c, k5unseal.c,
+ 	util_cksum.c (kg_checksum_channel_bindings), util_seqnum.c
+ 	(kg_make_seq_num, kg_get_seq_num), util_seed.c (kg_make_seed),
+ 	util_crypt.c (kg_encrypt, kg_decrypt): 
+	pass the context to the kg_* functions which need it instead of
+ 	determining it directly.
+
+Fri Apr 12 21:47:46 1996  Richard Basch  <basch@lehman.com>
+
+        * k5seal.c k5unseal.c:
+        Renamed MD5 routines to be preceded with krb5_
+
+Thu Apr 11 18:53:09 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* acquire_cred.c (acquire_init_cred): Return GSS_S_CRED_UNAVAIL on
+		if krb5_cc_set_flags() returns an error, since that's the
+		call that will return an error if the credentials files
+		doesn't exist.
+
+Wed Apr  3 16:10:24 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* init_sec_context.c (krb5_gss_init_sec_context): If make_ap_req()
+		returns KRB5APP_TKT_EXPIRED, then return
+		GSS_S_CREDENTIALS_EXPIRED as the major return code.
+
+Tue Apr  2 15:20:24 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS): Inlined list of source files for SRCS and
+		OBJS (for Macintosh build).
+
+	* k5mech.c: Added Macintosh #ifdef so that the #include path is
+		right for the Macintosh.
+
+Wed Mar 20 20:25:53 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rel_oid.c (krb5_gss_release_oid): Don't compile this procedure,
+		since it's not used.  The mechanism glue layer uses the
+		krb5_gss_internal_relase_oid() function.
+
+	* pname_to_uid.c: Comment out #ident line.  This causes the
+		Macintosh C compiler indigestion.  Remove #include of
+		gssapi/gssapi.h, since that gets included by
+		gssapiP_generic.h.
+
+Fri Mar  8 21:36:29 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* util_cksum.c (kg_checksum_channel_bindings): Change sizeof(long)
+		to sizeof(krb5_int32).
+
+Sat Mar  2 02:22:30 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5mech.c (krb5_gss_get_context): Initialize the serializers
+		here, instead of in export and import security context.
+		This will speed things up a little.
+
+	* export_sec_context.c (krb5_gss_export_sec_context): 
+	* import_sec_context.c (krb5_gss_import_sec_context): Don't create
+		a serialization context just for importing/exporting
+		credentials.  Use the passed-in gssapi context.  This
+		speeds things up significantly.  Assume the serializers
+		are initialized in krb5_gss_get_context.
+
+Tue Feb 27 17:53:22 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Remove dead
+		code which used geteuid().
+
+	* Makefile.in (gssapi_err_krb5.$(OBJEXT)): Add Windows production
+		to add file to library.
+
+	* pname_to_uid.c: Don't try to compile pname_to_uid.c for MS-DOS
+		or Macintosh.
+
+Mon Feb 26 18:08:57 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* k5mech.c : do not declare kg_context static as it is declared in
+	        another file, and declared extern in a header.
+
+Sat Feb 24 00:06:37 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* k5mech.c (krb5_gss_initialize): No longer need to call
+		name-type/mechanism registration function.  This is now
+		done for us by the generic intialization function.
+		Add support for new V2 call gss_wrap_size_limit.
+
+Sat Feb 24 11:45:05 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* import_sec_context.c (krb5_gss_import_sec_context): Do not
+		shadow parameter ctx.
+
+	* inq_context.c (krb5_gss_inquire_context): Do not shadow
+		parameter ctx.
+
+	* rel_oid.c (krb5_gss_internal_release_oid): Change to match prototype.
+
+	* process_context_token.c (krb5_gss_process_context_token): Change
+		to match prototype.
+
+Sat Feb 24 00:06:37 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapiP_krb5.h: Changed most krb5 gssapi functions to take a
+		void * as their first argument, instead of a krb5_context.
+		Makes for a cleaner interface to the mechanism glue layer.
+
+	* k5mech.c (krb5_gss_initialize): Call name-type/mechanism
+	        registration function so that mechanism glue layer knows
+		whether or not a name needs to be lazy evaluated or not.
+
+Tue Feb  6 23:55:45 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* pname_to_uid.c (krb5_pname_to_uid): Instead of using specialized
+		code to derive the username from a kerberos principal, use
+		krb5_aname_to_lname().  Added extra argument for the
+		context structure.
+
+Fri Jan 26 03:09:32 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* init_sec_context.c (make_ap_req): Make sure we get a DES session key.
+
+Wed Jan 24 20:46:37 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* pname_to_uid.c (krb5_pname_to_uid): Changed def'n of
+		krb5principalname to static so K&R compilers won't lose on
+		automatic aggregate initialization.
+
+Wed Jan 24 13:21:37 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* import_name.c (krb5_gss_import_name): Don't assume that the
+		input_name_buffer is null terminated, when it contains a
+		string.  Fix gcc warnings.
+
+Tue Jan 23 13:01:42 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Check for stdlib.h
+
+	* pname_to_uid.c: Include string.h and stdlib.h.
+
+	* init_sec_context.c (make_ap_req): Handle gcc warning.
+
+Tue Jan 23 04:05:23 1996    <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Add support for building GSSAPI as a shared
+	        library.
+
+Tue Jan 23 03:25:02 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rel_oid.c (krb5_gss_internal_release_oid): Add the new interface
+		for the mechglue layer.
+
+	* inq_cred.c (krb5_gss_inquire_cred): Call gss_release_oid_set()
+		instead of generic_gss_release_oid_set().
+
+	* gssapiP_krb5.h: Added prototype for krb5_gss_internal_release_oid 
+
+	* Makefile.in (CCSRCS): Removed the file krb5_gss_glue.c and added
+		the file k5mech.c and pname_to_uid.c
+
+Tue Jan  9 22:11:25 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapiP_krb5.h (KRB5_GSS_FOR_CREDS_OPTION): New constant added
+		for delegation (forwarding) of credentials.
+
+	* init_sec_context.c (make_ap_req): Add support for sending
+		delegated credentials.  Misc lint cleanups.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Add support
+		for accepting delegated credentials.  Misc lint cleanups.
+
+Fri Dec  1 17:27:33 1995    <tytso@rsts-11.mit.edu>
+
+	* configure.in: Add rule for building shared object files.
+
+Fri Dec  1 17:11:43 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapiP_krb5.h (KG_TOK_WRAP_MSG): Changed token ID for
+		KG_TOK_WRAP_MSG to match KG_TOK_SEAL_MSG both should be
+		0x0201.
+
+	* krb5_gss_glue.c (gss_inquire_names_for_mech): Added new context
+		argument to the call of krb5_gss_inquire_names_for_mech().
+
+	* inq_names.c (krb5_gss_inquire_names_for_mech): Added new context
+		argument to the arg list.
+
+Thu Nov 16 17:04:00 1995    <tytso@rsts-11.mit.edu>
+
+	* gssapiP_krb5.h (KG_TOK_MIC_MSG, KG_TOK_WRAP_MSG, KG_DEL_CTX):
+	        Fixed token type numbers so they conform with the protocol
+		spec.  Paul Park didn't realize that he wasn't allowed to
+		change these willy-nilly...
+
+Wed Oct 25 15:38:00 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* init_sec_context.c (make_ap_req): Change the input type of
+		do_mutual to be OM_int32 instead of an int, to prevent
+		lossage under windows, since the passed in type size is a
+		OM_int32.
+
+Fri Oct  6 22:02:24 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:52:49 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Sun Sep 24 10:39:13 1995  John Rivlin (jrivlin@fusion.com)
+	* gssapiP_krb5.h: Fixed kb_seal_size prototype
+
+Wed Sep 13 10:39:13 1995 Keith Vetter (keithv@fusion.com)
+
+	* acquire_.c: changed int to size_t.
+	* gssapip_.h: added prototype for kg_seal_size.
+	* k5seal.c: 16/32 bit mismatch and removed unused variables.
+	* seal.c: 16/32 bit mismatch.
+	* sign.c: 16/32 bit mismatch.
+	* ser_sctx.c: added prototypes for all functions since they get 
+		assigned into a structure that has been prototyped.
+
+Sat Sep 16 03:18:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gssapiP_krb5.h: Remove context and cred from the gssapi security
+		context, as they aren't needed.  kg_seal and kg_unseal now
+		take a krb5_context argument.
+
+	* ser_sctx.c (kg_ctx_size, kg_ctx_externalize,
+		kg_ctx_internalize): No longer serialize the context and
+		cred fields of the gssapi security context.
+
+	* krb5_gss_glue.c: Don't rely on the context field of the gssapi
+		security context.  Use kg_context instead.
+
+	* verify.c (krb5_gss_verify, krb5_gss_verify_mic): 
+	* unseal.c (krb5_gss_unwrap, krb5_gss_unseal): 
+	* sign.c (krb5_gss_sign, krb5_gss_get_mic): 
+	* seal.c (krb5_gss_seal, krb5_gss_wrap): 
+	* process_context_token.c (krb5_gss_process_context_token): 
+	* k5unseal.c (kg_unseal):
+	* k5seal.c (kg_seal_size): Add a krb5_context argument to this
+		function, so we don't have to depend on the context field
+		in the gssapi security context.
+
+	* init_sec_context.c (krb5_gss_init_sec_context): Don't initialize
+		the context and cred fields in the gssapi security
+		context.  Copy ctx->subkey to ctx->seq.key, so they are
+		separately allocated.
+
+	* gssapi_krb5.c (kg_get_context): When initialize kg_context, call
+		krb5_init_ets() so that the error tables are initialized.
+
+	* export_sec_context.c (krb5_gss_export_sec_context): Don't depend
+		on the context field from the gssapi security context.
+		Free ctx->seq.key.
+
+	* delete_sec_context.c (krb5_gss_delete_sec_context): kg_seal()
+		now takes a krb5_context argument.  Free ctx->seq.key.
+
+	* acquire_cred.c (krb5_gss_acquire_cred): Clear the gssapi
+		credential before setting it, to prevent purify from
+		complaining.
+
+	* accept_sec_context.c (krb5_gss_accept_sec_context): Remove
+		context and cred from the gssapi security context.  Make
+		sure the ticket is freed after we're done with it.
+
+Fri Sep 15 22:12:49 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* import_sec_context.c (krb5_gss_import_sec_context): Don't bash
+		the input interprocess_token.  Otherwise, it can't be
+		freed.  Don't depend on the context field in the gss
+		security context.
+
+Tue Sep 12 19:07:52 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* export_sec_context.c (krb5_gss_export_sec_context): Free the
+		auth context when freeing the GSSAPI context structure.
+
+	* delete_sec_context.c (krb5_gss_delete_sec_context): Free the
+		auth context when freeing the GSSAPI context structure.
+
+Tue Sep 12 13:05:51 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* k5seal.c, k5unseal.c, accept_sec_context.c: Undo MACINTOSH
+		change for paths. The old ones were correct.
+
+Wed Sep  6 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* gssapi_krb5.h:  changed a path bearing include for MACINTOSH
+
+	* accept_sec_context.c:  changed a path bearing include for MACINTOSH
+
+	* k5seal.c:  changed a path bearing include for MACINTOSH
+
+	* k5unseal.c:  changed a path bearing include for MACINTOSH
+	
+Sat Sep  9 00:16:34 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_gss_glue.c (gss_delete_sec_context): Add extra indirection
+		so that we actually fetch the context correctly.
+		(gss_accept_sec_context): Remove unused code.
+
+Wed Sep  6 16:12:28 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* init_sec_context.c (make_ap_req): Initialize mk_req_flags to
+		zero so that when we OR in flags, the result is
+		well-defined. 
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * accept_sec_context.c, init_sec_context.c, util.c : 
+		s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * accept_sec_context.c, init_sec_context.c, util_seed.c : 
+		Remove krb5_enctype references, and replace with 
+		krb5_keytype where appropriate.
+
+Thu Aug 31 11:50:34 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gssapiP_krb5.h - Add new V2 dispatch prototypes.  Update arguments
+		to be compatible with V2 API.  Add tokens for V2 integrity
+		and confidentiality services.
+	* k5seal.c - Add support for V2 tokens and add kg_seal_size() to
+		support gss_wrap_size_limit().
+	* k5unseal.c - Add support for V2 tokens.
+	* accept_sec_context,disp_status,gssapi_krb5,init_sec_context,
+		inq_context,rel_name.c - Update arguments to V2.
+	* acquire_cred,import_name,inq_cred,krb5_gss_glue,seal,sign,unseal,
+		verify.c - Update arguments to V2 and add new V2 functions.
+	* rel_oid.c, inq_names.c - New V2 modules.
+	* Makefile.in, .Sanitize - Add rel_oid.c and inq_names.c
+
+Tue Aug 29 22:38:54 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* init_sec_context.c (krb5_gss_init_sec_context):  Remove
+		duplicated cleanup code. 
+
+Tue Aug 29 17:48:40 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* {accept,init}_sec_context.c - Zero out the newly allocated context
+		because garbage in the uninitialized context messes up the
+		serializers.
+
+
+Tue Aug 29 13:31:46 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in, .Sanitize, {im,ex}port_sec_context.c, ser_sctx.c - Add
+		new modules to support {im,ex}port of GSSAPI context.
+	* krb5_gss_glue.c - Add krb5_gss_{im,ex}port_sec_context() wrapper
+		routines.
+	* gssapiP_krb5.h - Add prototypes for krb5_gss_{im,ex}port_sec_context
+		and kg_ser_context_init.
+	* gssapi_err_krb5.et - Add magic numbers for GSSAPI data structures.
+
+Mon Aug  7 19:08:52 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* inq_cred.c (krb5_gss_inquire_cred): Use
+		generic_gss_release_oid_set() instead of gss_release_oid_set()
+		so that the krb5-specific mechanism can be linked in
+		without pulling in krb5_gss_glue.c
+
+Thu Jul 27 15:26:27 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add -I$(srcdir)/../../crypto/md5 to get rsa-md5.h.
+	* accept_sec_context.c - Include "rsa-md5.h" instead of <krb5/...>.
+	* gssapiP_krb5.h - Replace k5-specific includes with k5-int.h
+	* k5[un]seal.c - Include "rsa-md5.h" instead of <krb5/...>.
+
+
+Fri Jul 7 16:23:17 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS, it's set by configure.
+
+Sat Jun 10 23:04:52 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* accept_sec_context.c, gssapiP_krb5.h, init_sec_context.c:
+		krb5_auth_context redefinitions
+
+Fri Jun  9 19:25:55 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed Jun  7 10:05:16 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gssapiP_krb5.h: Include time.h (or sys/time.h) for struct tm
+		structure which is now in the los-proto.h file.
+
+Mon May 22 10:10:41 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in	- Add null install target.
+	* inq_cred.c	- Don't mark credentials as expired if the expiration
+			  time is indefinite.
+
+Mon May 01 15:56:32 1995  Chris Provenzano (proven@mit.edu)
+
+	* init_sec_context.c (krb5_gss_init_sec_context()) :
+		The krb5_mk_rep() routine must always encode the data in
+		the keyblock of the ticket, not the subkey.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+        * *.h added FAR to pointers visible at to the world.
+        * gssapi_e.c: __STDC__ conditional also checks the _WINDOWS define.
+
+Thu Mar 30 16:00:30 1995 Keith Vetter (keithv@fusion.com)
+
+	* accept_sec_context.c: fixed wrong level of indirection on a 
+           parameter to getauthenticator.
+
+Mon Mar 27 07:56:26 1995 Chris Provenzano (proven@mit.edu)
+
+        * accept_sec_context.c: Use new calling convention for krb5_rd_req()
+		and krb5_mk_rep().
+
+Thu Mar 16 19:54:33 1995 Keith Vetter (keithv@fusion.com)
+
+	* init_sec_context.c: fixed signed/unsigned mismatch and
+           added a prototype which will later be removed.
+        * import_name.c: fixed for the PC--made conditional the
+           code dependent upon passwords.
+	* Makefile.in: changed the name of the library the PC
+	   builds, and added xxx-mac targets to mimic xxx-unix.
+
+Fri Mar 10 09:44:29 1995 Chris Provenzano (proven@mit.edu)
+
+	* init_sec_context.c (krb5_gss_init_sec_context())
+		Use new calling convention for krb5_mk_req_ext() and
+		krb5_rd_rep().
+
+	* gssapiP_krb5.h Added a krb5_auth_context pointer to the
+		krb5_gss_ctx_id_rec structure to store the auth_context
+		between multiple calls to krb5_gss_init_sec_context().
+
+Tue Mar 7 20:48:03 1995 Keith Vetter (keithv@fusion.com)
+
+	* accept_s.c, acqire_s.c, compare_.c, context_.c, delete_s.c,
+          disp_nam.c, disp_sta.c, get_tkt_.c, init_sec.c, inq_cont.c, 
+          inq_cred.c, k5seal.c, k5unseal.c, process_.c, rel_cred.c, 
+          rel_name.c, util_cks.c, util_cry.c: added casts on signed ->
+            unsigned assignments.
+        * util_seq.c: added casts on bit extraction code.
+        * gssapip_.h: pulls in los-proto.h for prototypes.
+
+Tue Feb 28 00:27:44 1995  John Gilmore  (gnu at toad.com)
+
+	* gssapi_krb5.h, gssapiP_krb5.h: Avoid <krb5/...> includes.
+	* disp_status.c:  Avoid <com_err.h>, use "com_err.h".
+
+Mon Feb 20 19:53:9 1995 Keith Vetter (keithv@fusion.com)
+
+	* accept_s.c: needed temp to avoid sign/unsigned mismatch on the PC.
+	* init_sec.c: needed temp to avoid sign/unsigned mismatch on the PC.
+        * gssapiP_krb5.h k5seal.c, k5unseal.c: removed netinet/in.h include.
+        * util_seq.c: changed int to 32bit int
+        * gssapiP_krb5.h, gssapi_krb5.h, *.c: added windows INTERFACE keyword
+
+Mon Feb 20 12:00:00 1995  keith Vetter (keithv@fusion.com)
+
+	Rename files for DOS 8.3 uniqueness--files created by Make
+	* gssapi_krb5_err.et => gssapi_err_krb5.et
+			     => gssapi_err_krb5.h
+			     => gssapi_err_krb5.c
+	* gssapiP_krb5.h changed to match
+	* Makefile.in changed to match
+
+Tue Feb 14 15:01:36 1995 Chris Provenzano (proven@mit.edu)
+
+    * init_sec_context.c (make_ap_req()) Use new API for 
+        krb5_mk_req_extended() and cleanup internal processing.
+
+Fri Feb  3 00:34:55 1995  John Gilmore  <gnu@cygnus.com>
+
+	Rename files for DOS 8.3 uniqueness:
+	* display_name.c    => disp_name.c
+	* display_status.c  => disp_status.c
+	* inquire_context.c => inq_context.c
+	* inquire_cred.c    => inq_cred.c
+	* release_cred.c    => rel_cred.c
+	* release_name.c    => rel_name.c
+	* Makefile.in changed to match.
+
+Fri Jan 27 14:41:12 1995  Chris Provenzano (proven@mit.edu)
+
+        * accept_sec_context.c (rd_req_keyproc() added krb5_keytype arg.
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+        * Removed all narrow types and references to wide.h and narrow.h
+
+Sun Jan 22 18:26:32 1995  John Gilmore  (gnu at toad.com)
+
+	* acquire_cred.c (acquire_accept_cred):  Add context arg when
+	calling krb5_sname_to_principal.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Mon Jan  9 19:27:55 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* display_name.c (krb5_gss_display_name): gss_display_name()
+		should return a name type OID, not a mechanism OID.
+
+Tue Oct  4 16:40:45 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* accept_security_context.c (rd_req_keyproc): Add widen.h and
+		narrow.h to widen argument types of keyproc.
+
+Tue Sep 27 23:30:14 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* accept_security_context.c (krb5_gss_accept_sec_context):
+		  krb5_rc_dfl_close now frees the rcache structure, so
+		  this routine shouldn't.
+
+Wed Aug 17 15:47:26 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* gssapi_krb5.c: Fixed OID for the krb5 mechanism.  (Transcription
+	error.) 
+
+
+
+
+	
diff --git a/mechglue/src/lib/gssapi/krb5/Makefile.in b/mechglue/src/lib/gssapi/krb5/Makefile.in
new file mode 100644
index 000000000..a410d55f2
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/Makefile.in
@@ -0,0 +1,642 @@
+thisconfigdir=./..
+myfulldir=lib/gssapi/krb5
+mydir=krb5
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic -I../mechglue -I$(srcdir)/../mechglue
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=krb5
+##DOS##OBJFILE = ..\$(OUTPRE)krb5.lst
+
+##DOS##DLL_EXP_TYPE=GSS
+
+include_stdint=@include_stdint@
+##DOS##include_stdint=
+ETSRCS= gssapi_err_krb5.c
+ETOBJS= $(OUTPRE)gssapi_err_krb5.$(OBJEXT)
+ETHDRS= gssapi_err_krb5.h
+
+$(OUTPRE)gssapi_err_krb5.$(OBJEXT): gssapi_err_krb5.c
+gssapi_err_krb5.h: gssapi_err_krb5.et
+gssapi_err_krb5.c: gssapi_err_krb5.et
+
+SRCS = \
+	$(srcdir)/accept_sec_context.c \
+	$(srcdir)/acquire_cred.c \
+	$(srcdir)/add_cred.c \
+	$(srcdir)/canon_name.c \
+	$(srcdir)/compare_name.c \
+	$(srcdir)/context_time.c \
+	$(srcdir)/copy_ccache.c \
+	$(srcdir)/delete_sec_context.c \
+	$(srcdir)/disp_name.c \
+	$(srcdir)/disp_status.c \
+	$(srcdir)/duplicate_name.c \
+	$(srcdir)/export_name.c \
+	$(srcdir)/export_sec_context.c \
+	$(srcdir)/get_tkt_flags.c \
+	$(srcdir)/gssapi_krb5.c \
+	$(srcdir)/import_name.c \
+	$(srcdir)/import_sec_context.c \
+	$(srcdir)/indicate_mechs.c \
+	$(srcdir)/init_sec_context.c \
+	$(srcdir)/inq_context.c \
+	$(srcdir)/inq_cred.c \
+	$(srcdir)/inq_names.c \
+	$(srcdir)/k5seal.c \
+	$(srcdir)/k5sealv3.c \
+	$(srcdir)/k5unseal.c \
+	$(srcdir)/krb5_gss_glue.c \
+	$(srcdir)/lucid_context.c \
+	$(srcdir)/process_context_token.c \
+	$(srcdir)/rel_cred.c \
+	$(srcdir)/rel_oid.c \
+	$(srcdir)/rel_name.c \
+	$(srcdir)/seal.c \
+	$(srcdir)/set_allowable_enctypes.c \
+	$(srcdir)/ser_sctx.c \
+	$(srcdir)/set_ccache.c \
+	$(srcdir)/sign.c \
+	$(srcdir)/unseal.c \
+	$(srcdir)/util_cksum.c \
+	$(srcdir)/util_crypt.c \
+	$(srcdir)/util_seed.c \
+	$(srcdir)/util_seqnum.c \
+	$(srcdir)/val_cred.c \
+	$(srcdir)/verify.c \
+	$(srcdir)/wrap_size_limit.c \
+	gssapi_err_krb5.c
+
+#	$(srcdir)/pname_to_uid.c \
+#	$(srcdir)/k5mech.c
+
+OBJS = \
+	$(OUTPRE)accept_sec_context.$(OBJEXT) \
+	$(OUTPRE)acquire_cred.$(OBJEXT) \
+	$(OUTPRE)add_cred.$(OBJEXT) \
+	$(OUTPRE)canon_name.$(OBJEXT) \
+	$(OUTPRE)compare_name.$(OBJEXT) \
+	$(OUTPRE)context_time.$(OBJEXT) \
+	$(OUTPRE)copy_ccache.$(OBJEXT) \
+	$(OUTPRE)delete_sec_context.$(OBJEXT) \
+	$(OUTPRE)disp_name.$(OBJEXT) \
+	$(OUTPRE)disp_status.$(OBJEXT) \
+	$(OUTPRE)duplicate_name.$(OBJEXT) \
+	$(OUTPRE)export_name.$(OBJEXT) \
+	$(OUTPRE)export_sec_context.$(OBJEXT) \
+	$(OUTPRE)get_tkt_flags.$(OBJEXT) \
+	$(OUTPRE)gssapi_krb5.$(OBJEXT) \
+	$(OUTPRE)import_name.$(OBJEXT) \
+	$(OUTPRE)import_sec_context.$(OBJEXT) \
+	$(OUTPRE)indicate_mechs.$(OBJEXT) \
+	$(OUTPRE)init_sec_context.$(OBJEXT) \
+	$(OUTPRE)inq_context.$(OBJEXT) \
+	$(OUTPRE)inq_cred.$(OBJEXT) \
+	$(OUTPRE)inq_names.$(OBJEXT) \
+	$(OUTPRE)k5seal.$(OBJEXT) \
+	$(OUTPRE)k5sealv3.$(OBJEXT) \
+	$(OUTPRE)k5unseal.$(OBJEXT) \
+	$(OUTPRE)krb5_gss_glue.$(OBJEXT) \
+	$(OUTPRE)lucid_context.$(OBJEXT) \
+	$(OUTPRE)process_context_token.$(OBJEXT) \
+	$(OUTPRE)rel_cred.$(OBJEXT) \
+	$(OUTPRE)rel_oid.$(OBJEXT) \
+	$(OUTPRE)rel_name.$(OBJEXT) \
+	$(OUTPRE)seal.$(OBJEXT) \
+	$(OUTPRE)set_allowable_enctypes.$(OBJEXT) \
+	$(OUTPRE)ser_sctx.$(OBJEXT) \
+	$(OUTPRE)set_ccache.$(OBJEXT) \
+	$(OUTPRE)sign.$(OBJEXT) \
+	$(OUTPRE)unseal.$(OBJEXT) \
+	$(OUTPRE)util_cksum.$(OBJEXT) \
+	$(OUTPRE)util_crypt.$(OBJEXT) \
+	$(OUTPRE)util_seed.$(OBJEXT) \
+	$(OUTPRE)util_seqnum.$(OBJEXT) \
+	$(OUTPRE)val_cred.$(OBJEXT) \
+	$(OUTPRE)verify.$(OBJEXT) \
+	$(OUTPRE)wrap_size_limit.$(OBJEXT) \
+	$(OUTPRE)gssapi_err_krb5.$(OBJEXT)
+
+#	k5mech.$(OBJEXT) \
+#	pname_to_uid.$(OBJEXT)
+
+STLIBOBJS = \
+	accept_sec_context.o \
+	acquire_cred.o \
+	add_cred.o \
+	canon_name.o \
+	compare_name.o \
+	context_time.o \
+	copy_ccache.o \
+	delete_sec_context.o \
+	disp_name.o \
+	disp_status.o \
+	duplicate_name.o \
+	export_name.o \
+	export_sec_context.o \
+	get_tkt_flags.o \
+	gssapi_krb5.o \
+	import_name.o \
+	import_sec_context.o \
+	indicate_mechs.o \
+	init_sec_context.o \
+	inq_context.o \
+	inq_cred.o \
+	inq_names.o \
+	k5seal.o \
+	k5sealv3.o \
+	k5unseal.o \
+	krb5_gss_glue.o \
+	lucid_context.o \
+	process_context_token.o \
+	rel_cred.o \
+	rel_oid.o \
+	rel_name.o \
+	seal.o \
+	set_allowable_enctypes.o \
+	ser_sctx.o \
+	set_ccache.o \
+	sign.o \
+	unseal.o \
+	util_cksum.o \
+	util_crypt.o \
+	util_seed.o \
+	util_seqnum.o \
+	val_cred.o \
+	verify.o \
+	wrap_size_limit.o \
+	gssapi_err_krb5.o
+
+#	k5mech.o \
+#	pname_to_uid.o
+
+HDRS= $(ETHDRS)
+
+EHDRDIR=$(BUILDTOP)$(S)include$(S)gssapi
+EXPORTED_HEADERS= gssapi_krb5.h
+
+##DOS##LIBOBJS = $(OBJS)
+
+GSSAPI_KRB5_HDR=$(EHDRDIR)$(S)gssapi_krb5.h
+
+all-windows:: $(EHDRDIR) $(GSSAPI_KRB5_HDR) $(SRCS) $(HDRS)
+
+##DOS##$(EHDRDIR):
+##DOS##	mkdir $(EHDRDIR)
+
+MK_EHDRDIR=if test -d $(EHDRDIR); then :; else (set -x; mkdir $(EHDRDIR)); fi
+##DOS##MK_EHDRDIR=rem
+
+$(GSSAPI_KRB5_HDR): gssapi_krb5.h
+	@$(MK_EHDRDIR)
+	$(CP) gssapi_krb5.h "$@"
+
+all-unix:: $(SRCS) $(HDRS) $(GSSAPI_KRB5_HDR) includes
+all-unix:: all-libobjs
+
+clean-unix::
+	$(RM) $(BUILDTOP)/include/gssapi/gssapi_krb5.h
+	-$(RM) gssapi_krb5.h
+
+clean-unix:: clean-libobjs
+	$(RM) $(ETHDRS) $(ETSRCS)
+
+clean-windows::
+	$(RM) $(EHDRDIR)\gssapi_krb5.h
+	-if exist $(EHDRDIR)\nul rmdir $(EHDRDIR)
+
+##DOS##!if 0
+gssapi_krb5.h: gssapi_krb5.hin
+	@echo "Creating gssapi.h" ; \
+	h=gss$$$$; $(RM) $$h; \
+	(echo "/* This is the gssapi_krb5.h prologue. */"; \
+	$(include_stdint) ; \
+	echo "/* End of gssapi_krb5.h prologue. */"; \
+	cat $(srcdir)/gssapi_krb5.hin )> $$h && \
+	(set -x; $(MV) $$h $@) ; e=$$?; $(RM) $$h; exit $$e
+##DOS##!endif
+##DOS### No prologue needed for Windows, the support is
+##DOS### in gssapi_krb5.hin already.
+##DOS##gssapi_krb5.h: gssapi_krb5.hin
+##DOS##	$(CP) gssapi_krb5.hin gssapi_krb5.h
+
+install-headers-unix install::
+	@set -x; for f in $(EXPORTED_HEADERS) ; \
+	do $(INSTALL_DATA) $$f	\
+		$(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \
+	done
+
+depend:: $(ETSRCS)
+
+includes::  gssapi_krb5.h
+
+install::
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+accept_sec_context.so accept_sec_context.po $(OUTPRE)accept_sec_context.$(OBJEXT): \
+  accept_sec_context.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  gssapiP_krb5.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+acquire_cred.so acquire_cred.po $(OUTPRE)acquire_cred.$(OBJEXT): \
+  acquire_cred.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../gss_libinit.h ../generic/gssapi.h gssapiP_krb5.h \
+  $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h ../generic/gssapi_err_generic.h \
+  gssapi_krb5.h gssapi_err_krb5.h
+add_cred.so add_cred.po $(OUTPRE)add_cred.$(OBJEXT): \
+  add_cred.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+canon_name.so canon_name.po $(OUTPRE)canon_name.$(OBJEXT): \
+  canon_name.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+compare_name.so compare_name.po $(OUTPRE)compare_name.$(OBJEXT): \
+  compare_name.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+context_time.so context_time.po $(OUTPRE)context_time.$(OBJEXT): \
+  context_time.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+copy_ccache.so copy_ccache.po $(OUTPRE)copy_ccache.$(OBJEXT): \
+  copy_ccache.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+delete_sec_context.so delete_sec_context.po $(OUTPRE)delete_sec_context.$(OBJEXT): \
+  delete_sec_context.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+disp_name.so disp_name.po $(OUTPRE)disp_name.$(OBJEXT): \
+  disp_name.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+disp_status.so disp_status.po $(OUTPRE)disp_status.$(OBJEXT): \
+  disp_status.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h \
+  $(srcdir)/../gss_libinit.h ../generic/gssapi.h
+duplicate_name.so duplicate_name.po $(OUTPRE)duplicate_name.$(OBJEXT): \
+  duplicate_name.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+export_name.so export_name.po $(OUTPRE)export_name.$(OBJEXT): \
+  export_name.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+export_sec_context.so export_sec_context.po $(OUTPRE)export_sec_context.$(OBJEXT): \
+  export_sec_context.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+get_tkt_flags.so get_tkt_flags.po $(OUTPRE)get_tkt_flags.$(OBJEXT): \
+  get_tkt_flags.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+gssapi_krb5.so gssapi_krb5.po $(OUTPRE)gssapi_krb5.$(OBJEXT): \
+  gssapi_krb5.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  gssapiP_krb5.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+import_name.so import_name.po $(OUTPRE)import_name.$(OBJEXT): \
+  import_name.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+import_sec_context.so import_sec_context.po $(OUTPRE)import_sec_context.$(OBJEXT): \
+  import_sec_context.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+indicate_mechs.so indicate_mechs.po $(OUTPRE)indicate_mechs.$(OBJEXT): \
+  indicate_mechs.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+init_sec_context.so init_sec_context.po $(OUTPRE)init_sec_context.$(OBJEXT): \
+  init_sec_context.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  gssapiP_krb5.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+inq_context.so inq_context.po $(OUTPRE)inq_context.$(OBJEXT): \
+  inq_context.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+inq_cred.so inq_cred.po $(OUTPRE)inq_cred.$(OBJEXT): \
+  inq_cred.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+inq_names.so inq_names.po $(OUTPRE)inq_names.$(OBJEXT): \
+  inq_names.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+k5seal.so k5seal.po $(OUTPRE)k5seal.$(OBJEXT): k5seal.c \
+  gssapiP_krb5.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h ../generic/gssapi_err_generic.h \
+  gssapi_krb5.h gssapi_err_krb5.h
+k5sealv3.so k5sealv3.po $(OUTPRE)k5sealv3.$(OBJEXT): \
+  k5sealv3.c $(SRCTOP)/include/k5-platform.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  gssapiP_krb5.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+k5unseal.so k5unseal.po $(OUTPRE)k5unseal.$(OBJEXT): \
+  k5unseal.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+krb5_gss_glue.so krb5_gss_glue.po $(OUTPRE)krb5_gss_glue.$(OBJEXT): \
+  krb5_gss_glue.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+lucid_context.so lucid_context.po $(OUTPRE)lucid_context.$(OBJEXT): \
+  lucid_context.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+process_context_token.so process_context_token.po $(OUTPRE)process_context_token.$(OBJEXT): \
+  process_context_token.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+rel_cred.so rel_cred.po $(OUTPRE)rel_cred.$(OBJEXT): \
+  rel_cred.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+rel_oid.so rel_oid.po $(OUTPRE)rel_oid.$(OBJEXT): rel_oid.c \
+  gssapiP_krb5.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h ../generic/gssapi_err_generic.h \
+  gssapi_krb5.h gssapi_err_krb5.h
+rel_name.so rel_name.po $(OUTPRE)rel_name.$(OBJEXT): \
+  rel_name.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+seal.so seal.po $(OUTPRE)seal.$(OBJEXT): seal.c gssapiP_krb5.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h ../generic/gssapi_err_generic.h \
+  gssapi_krb5.h gssapi_err_krb5.h
+set_allowable_enctypes.so set_allowable_enctypes.po \
+  $(OUTPRE)set_allowable_enctypes.$(OBJEXT): set_allowable_enctypes.c \
+  gssapiP_krb5.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h ../generic/gssapi_err_generic.h \
+  gssapi_krb5.h gssapi_err_krb5.h
+ser_sctx.so ser_sctx.po $(OUTPRE)ser_sctx.$(OBJEXT): \
+  ser_sctx.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  gssapiP_krb5.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+set_ccache.so set_ccache.po $(OUTPRE)set_ccache.$(OBJEXT): \
+  set_ccache.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+sign.so sign.po $(OUTPRE)sign.$(OBJEXT): sign.c gssapiP_krb5.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h ../generic/gssapi_err_generic.h \
+  gssapi_krb5.h gssapi_err_krb5.h
+unseal.so unseal.po $(OUTPRE)unseal.$(OBJEXT): unseal.c \
+  gssapiP_krb5.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h ../generic/gssapi_err_generic.h \
+  gssapi_krb5.h gssapi_err_krb5.h
+util_cksum.so util_cksum.po $(OUTPRE)util_cksum.$(OBJEXT): \
+  util_cksum.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+util_crypt.so util_crypt.po $(OUTPRE)util_crypt.$(OBJEXT): \
+  util_crypt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  gssapiP_krb5.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+util_seed.so util_seed.po $(OUTPRE)util_seed.$(OBJEXT): \
+  util_seed.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+util_seqnum.so util_seqnum.po $(OUTPRE)util_seqnum.$(OBJEXT): \
+  util_seqnum.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+val_cred.so val_cred.po $(OUTPRE)val_cred.$(OBJEXT): \
+  val_cred.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+verify.so verify.po $(OUTPRE)verify.$(OBJEXT): verify.c \
+  gssapiP_krb5.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(srcdir)/../generic/gssapiP_generic.h $(srcdir)/../generic/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h ../generic/gssapi_err_generic.h \
+  gssapi_krb5.h gssapi_err_krb5.h
+wrap_size_limit.so wrap_size_limit.po $(OUTPRE)wrap_size_limit.$(OBJEXT): \
+  wrap_size_limit.c gssapiP_krb5.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(srcdir)/../generic/gssapiP_generic.h \
+  $(srcdir)/../generic/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  ../generic/gssapi_err_generic.h gssapi_krb5.h gssapi_err_krb5.h
+gssapi_err_krb5.so gssapi_err_krb5.po $(OUTPRE)gssapi_err_krb5.$(OBJEXT): \
+  gssapi_err_krb5.c $(COM_ERR_DEPS)
diff --git a/mechglue/src/lib/gssapi/krb5/accept_sec_context.c b/mechglue/src/lib/gssapi/krb5/accept_sec_context.c
new file mode 100644
index 000000000..219d9da06
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/accept_sec_context.c
@@ -0,0 +1,995 @@
+/*
+ * Copyright 2000, 2004  by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+#ifdef CFX_EXERCISE
+#define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
+#else
+#define CFX_ACCEPTOR_SUBKEY 1
+#endif
+
+/* Decode, decrypt and store the forwarded creds in the local ccache. */
+static krb5_error_code
+rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
+    krb5_context context;
+    krb5_auth_context auth_context;
+    krb5_data *inbuf;
+    krb5_gss_cred_id_t *out_cred;
+{
+    krb5_creds ** creds = NULL;
+    krb5_error_code retval;
+    krb5_ccache ccache = NULL;
+    krb5_gss_cred_id_t cred = NULL;
+    krb5_auth_context new_auth_ctx = NULL;
+	krb5_int32 flags_org;
+
+	if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
+		return retval;
+	krb5_auth_con_setflags(context, auth_context,
+			       0);
+
+	/*
+	 * By the time krb5_rd_cred is called here (after krb5_rd_req has been
+	 * called in krb5_gss_accept_sec_context), the "keyblock" field of
+	 * auth_context contains a pointer to the session key, and the
+	 * "recv_subkey" field might contain a session subkey.  Either of
+	 * these (the "recv_subkey" if it isn't NULL, otherwise the
+	 * "keyblock") might have been used to encrypt the encrypted part of
+	 * the KRB_CRED message that contains the forwarded credentials.  (The
+	 * Java Crypto and Security Implementation from the DSTC in Australia
+	 * always uses the session key.  But apparently it never negotiates a
+	 * subkey, so this code works fine against a JCSI client.)  Up to the
+	 * present, though, GSSAPI clients linked against the MIT code (which
+	 * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
+	 * all -- at this level.  So if the first call to krb5_rd_cred fails,
+	 * we should call it a second time with another auth context freshly
+	 * created by krb5_auth_con_init.  All of its keyblock fields will be
+	 * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
+	 * unencrypted.  (The MIT code doesn't actually send the KRB_CRED
+	 * message in the clear -- the "authenticator" whose "checksum" ends up
+	 * containing the KRB_CRED message does get encrypted.)
+	 */
+	if (krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) {
+		if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
+			goto cleanup;
+		krb5_auth_con_setflags(context, new_auth_ctx, 0);
+		if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
+					   &creds, NULL)))
+			goto cleanup;
+		}
+
+    /* Lots of kludging going on here... Some day the ccache interface
+       will be rewritten though */
+
+    if ((retval = krb5_cc_resolve(context, "MEMORY:GSSAPI", &ccache)))
+        goto cleanup;
+
+    if ((retval = krb5_cc_gen_new(context, &ccache)))
+        goto cleanup;
+    
+    if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
+	goto cleanup;
+
+    if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
+	goto cleanup;
+
+    /* generate a delegated credential handle */
+    if (out_cred) {
+	/* allocate memory for a cred_t... */
+	if (!(cred =
+	      (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
+	    retval = ENOMEM; /* out of memory? */
+	    goto cleanup;
+	}
+
+	/* zero it out... */
+	memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
+
+	retval = k5_mutex_init(&cred->lock);
+	if (retval) {
+	    xfree(cred);
+	    cred = NULL;
+	    goto cleanup;
+	}
+
+	/* copy the client principle into it... */
+	if ((retval =
+	     krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
+	    k5_mutex_destroy(&cred->lock);
+	    retval = ENOMEM; /* out of memory? */
+	    xfree(cred); /* clean up memory on failure */
+	    cred = NULL;
+	    goto cleanup;
+	}
+
+	cred->usage = GSS_C_INITIATE; /* we can't accept with this */
+	/* cred->princ already set */
+	cred->prerfc_mech = 1; /* this cred will work with all three mechs */
+	cred->rfc_mech = 1;
+	cred->keytab = NULL; /* no keytab associated with this... */
+	cred->ccache = ccache; /* but there is a credential cache */
+	cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
+    }
+
+    /* If there were errors, there might have been a memory leak
+       if (!cred)
+       if ((retval = krb5_cc_close(context, ccache)))
+       goto cleanup;
+    */
+cleanup:
+    if (creds)
+	krb5_free_tgt_creds(context, creds);
+
+    if (!cred && ccache)
+	(void)krb5_cc_close(context, ccache);
+
+    if (out_cred)
+	*out_cred = cred; /* return credential */
+
+    if (new_auth_ctx)
+	krb5_auth_con_free(context, new_auth_ctx);
+
+    krb5_auth_con_setflags(context, auth_context, flags_org);
+
+    return retval;
+}
+
+OM_uint32
+krb5_gss_accept_sec_context(minor_status, context_handle, 
+			    verifier_cred_handle, input_token,
+			    input_chan_bindings, src_name, mech_type,
+			    output_token, ret_flags, time_rec,
+			    delegated_cred_handle)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t *context_handle;
+     gss_cred_id_t verifier_cred_handle;
+     gss_buffer_t input_token;
+     gss_channel_bindings_t input_chan_bindings;
+     gss_name_t *src_name;
+     gss_OID *mech_type;
+     gss_buffer_t output_token;
+     OM_uint32 *ret_flags;
+     OM_uint32 *time_rec;
+     gss_cred_id_t *delegated_cred_handle;
+{
+   krb5_context context;
+   unsigned char *ptr, *ptr2;
+   char *sptr;
+   long tmp;
+   size_t md5len;
+   int bigend;
+   krb5_gss_cred_id_t cred = 0;
+   krb5_data ap_rep, ap_req;
+   int i;
+   krb5_error_code code;
+   krb5_address addr, *paddr;
+   krb5_authenticator *authdat = 0;
+   krb5_checksum reqcksum;
+   krb5_principal name = NULL;
+   krb5_ui_4 gss_flags = 0;
+   int decode_req_message = 0;
+   krb5_gss_ctx_id_rec *ctx = 0;
+   krb5_timestamp now;
+   gss_buffer_desc token;
+   krb5_auth_context auth_context = NULL;
+   krb5_ticket * ticket = NULL;
+   int option_id;
+   krb5_data option;
+   const gss_OID_desc *mech_used = NULL;
+   OM_uint32 major_status = GSS_S_FAILURE;
+   krb5_error krb_error_data;
+   krb5_data scratch;
+   gss_cred_id_t cred_handle = NULL;
+   krb5_gss_cred_id_t deleg_cred = NULL;
+   krb5int_access kaccess;
+   int cred_rcache = 0;
+
+   code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+   if (code) {
+       *minor_status = code;
+       return(GSS_S_FAILURE);
+   }
+
+   code = krb5_init_context(&context);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   /* set up returns to be freeable */
+
+   if (src_name)
+      *src_name = (gss_name_t) NULL;
+   output_token->length = 0;
+   output_token->value = NULL;
+   token.value = 0;
+   reqcksum.contents = 0;
+   ap_req.data = 0;
+   ap_rep.data = 0;
+   
+   if (mech_type)
+      *mech_type = GSS_C_NULL_OID;
+   /* return a bogus cred handle */
+   if (delegated_cred_handle)
+      *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+   /*
+    * Context handle must be unspecified.  Actually, it must be
+    * non-established, but currently, accept_sec_context never returns
+    * a non-established context handle.
+    */
+   /*SUPPRESS 29*/
+   if (*context_handle != GSS_C_NO_CONTEXT) {
+      *minor_status = 0;
+      krb5_free_context(context);
+      return(GSS_S_FAILURE);
+   }
+
+   /* handle default cred handle */
+   if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
+       major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
+					    GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
+					    GSS_C_ACCEPT, &cred_handle,
+					    NULL, NULL);
+       if (major_status != GSS_S_COMPLETE) {
+	   code = *minor_status;
+	   goto fail;
+       }
+   } else {
+       major_status = krb5_gss_validate_cred(minor_status,
+					     verifier_cred_handle);
+       if (GSS_ERROR(major_status)) {
+	   code = *minor_status;
+	   goto fail;
+       }
+       cred_handle = verifier_cred_handle;
+   }
+
+   cred = (krb5_gss_cred_id_t) cred_handle;
+
+   /* make sure the supplied credentials are valid for accept */
+
+   if ((cred->usage != GSS_C_ACCEPT) &&
+       (cred->usage != GSS_C_BOTH)) {
+       code = 0;
+       major_status = GSS_S_NO_CRED;
+       goto fail;
+   }
+
+   /* verify the token's integrity, and leave the token in ap_req.
+      figure out which mech oid was used, and save it */
+
+   ptr = (unsigned char *) input_token->value;
+
+   if (!(code = g_verify_token_header((gss_OID) gss_mech_krb5,
+				      &(ap_req.length),
+				      &ptr, KG_TOK_CTX_AP_REQ,
+				      input_token->length, 1))) {
+       mech_used = gss_mech_krb5;
+   } else if ((code == G_WRONG_MECH) &&
+	      !(code = g_verify_token_header((gss_OID) gss_mech_krb5_old,
+					     &(ap_req.length), 
+					     &ptr, KG_TOK_CTX_AP_REQ,
+					     input_token->length, 1))) {
+       /*
+	* Previous versions of this library used the old mech_id
+	* and some broken behavior (wrong IV on checksum
+	* encryption).  We support the old mech_id for
+	* compatibility, and use it to decide when to use the
+	* old behavior.
+	*/
+       mech_used = gss_mech_krb5_old;
+   } else if (code == G_WRONG_TOKID) {
+       major_status = GSS_S_CONTINUE_NEEDED;
+       code = KRB5KRB_AP_ERR_MSG_TYPE;
+       mech_used = gss_mech_krb5;
+       goto fail;
+   } else {
+       major_status = GSS_S_DEFECTIVE_TOKEN;
+       goto fail;
+   }
+
+   sptr = (char *) ptr;
+   TREAD_STR(sptr, ap_req.data, ap_req.length);
+   decode_req_message = 1;
+
+   /* construct the sender_addr */
+
+   if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
+       (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
+       /* XXX is this right? */
+       addr.addrtype = ADDRTYPE_INET;
+       addr.length = input_chan_bindings->initiator_address.length;
+       addr.contents = input_chan_bindings->initiator_address.value;
+
+       paddr = &addr;
+   } else {
+       paddr = NULL;
+   }
+
+   /* decode the AP_REQ message */
+
+   /* decode the message */
+
+   if ((code = krb5_auth_con_init(context, &auth_context))) {
+       major_status = GSS_S_FAILURE;
+       goto fail;
+   }
+   if (cred->rcache) {
+       cred_rcache = 1;
+       if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+   }
+   if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
+       major_status = GSS_S_FAILURE;
+       goto fail;
+   }
+
+   if ((code = krb5_rd_req(context, &auth_context, &ap_req, cred->princ,
+			   cred->keytab, NULL, &ticket))) {
+       major_status = GSS_S_FAILURE;
+       goto fail;
+   }
+   krb5_auth_con_setflags(context, auth_context,
+			  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+   krb5_auth_con_getauthenticator(context, auth_context, &authdat);
+
+#if 0
+   /* make sure the necessary parts of the authdat are present */
+
+   if ((authdat->authenticator->subkey == NULL) ||
+       (authdat->ticket->enc_part2 == NULL)) {
+	   code = KG_NO_SUBKEY;
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+   }
+#endif
+
+   {
+       /* gss krb5 v1 */
+
+       /* stash this now, for later. */
+       code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
+       if (code) {
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+
+       /* verify that the checksum is correct */
+
+       /*
+	 The checksum may be either exactly 24 bytes, in which case
+	 no options are specified, or greater than 24 bytes, in which case
+	 one or more options are specified. Currently, the only valid
+	 option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
+       */
+
+       if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
+	   (authdat->checksum->length < 24)) {
+	   code = 0;
+	   major_status = GSS_S_BAD_BINDINGS;
+	   goto fail;
+       }
+
+       /*
+	 "Be liberal in what you accept, and
+	 conservative in what you send"
+	 -- rfc1123
+
+	 This code will let this acceptor interoperate with an initiator
+	 using little-endian or big-endian integer encoding.
+       */
+
+       ptr = (unsigned char *) authdat->checksum->contents;
+       bigend = 0;
+
+       TREAD_INT(ptr, tmp, bigend);
+
+       if (tmp != md5len) {
+	   ptr = (unsigned char *) authdat->checksum->contents;
+	   bigend = 1;
+
+	   TREAD_INT(ptr, tmp, bigend);
+
+	   if (tmp != md5len) {
+	       code = KG_BAD_LENGTH;
+	       major_status = GSS_S_FAILURE;
+	       goto fail;
+	   }
+       }
+
+       /* at this point, bigend is set according to the initiator's
+	  byte order */
+
+
+       /* 
+          The following section of code attempts to implement the
+          optional channel binding facility as described in RFC2743.
+
+          Since this facility is optional channel binding may or may
+          not have been provided by either the client or the server.
+
+          If the server has specified input_chan_bindings equal to
+          GSS_C_NO_CHANNEL_BINDINGS then we skip the check.  If
+          the server does provide channel bindings then we compute
+          a checksum and compare against those provided by the
+          client.         */
+
+       if ((code = kg_checksum_channel_bindings(context, 
+						input_chan_bindings,
+						&reqcksum, bigend))) {
+	 major_status = GSS_S_BAD_BINDINGS;
+	 goto fail;
+       }
+
+       /* Always read the clients bindings - eventhough we might ignore them */
+       TREAD_STR(ptr, ptr2, reqcksum.length);
+
+       if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
+           if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
+               xfree(reqcksum.contents);
+               reqcksum.contents = 0;
+	       code = 0;
+	       major_status = GSS_S_BAD_BINDINGS;
+                   goto fail;
+           }
+           
+       }
+
+       xfree(reqcksum.contents);
+       reqcksum.contents = 0;
+
+       TREAD_INT(ptr, gss_flags, bigend);
+#if 0
+       gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag; if
+					  there's a delegation, we'll set
+					  it below */
+#endif
+       decode_req_message = 0;
+
+       /* if the checksum length > 24, there are options to process */
+
+       if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
+
+	   i = authdat->checksum->length - 24;
+
+	   if (i >= 4) {
+
+	       TREAD_INT16(ptr, option_id, bigend);
+
+	       TREAD_INT16(ptr, option.length, bigend);
+
+	       i -= 4;
+
+	       if (i < option.length || option.length < 0) {
+		   code = KG_BAD_LENGTH;
+		   major_status = GSS_S_FAILURE;
+		   goto fail;
+	       }
+
+	       /* have to use ptr2, since option.data is wrong type and
+		  macro uses ptr as both lvalue and rvalue */
+
+	       TREAD_STR(ptr, ptr2, option.length);
+	       option.data = (char *) ptr2;
+
+	       i -= option.length;
+
+	       if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
+		   major_status = GSS_S_FAILURE;
+		   goto fail;
+	       }
+
+		   /* store the delegated credential */
+
+		   code = rd_and_store_for_creds(context, auth_context, &option,
+						 (delegated_cred_handle) ?
+						 &deleg_cred : NULL);
+		   if (code) {
+		       major_status = GSS_S_FAILURE;
+		       goto fail;
+		   }
+
+	   } /* if i >= 4 */
+	   /* ignore any additional trailing data, for now */
+#ifdef CFX_EXERCISE
+	   {
+	       FILE *f = fopen("/tmp/gsslog", "a");
+	       if (f) {
+		   fprintf(f,
+			   "initial context token with delegation, %d extra bytes\n",
+			   i);
+		   fclose(f);
+	       }
+	   }
+#endif
+       } else {
+#ifdef CFX_EXERCISE
+	   {
+	       FILE *f = fopen("/tmp/gsslog", "a");
+	       if (f) {
+		   if (gss_flags & GSS_C_DELEG_FLAG)
+		       fprintf(f,
+			       "initial context token, delegation flag but too small\n");
+		   else
+		       /* no deleg flag, length might still be too big */
+		       fprintf(f,
+			       "initial context token, %d extra bytes\n",
+			       authdat->checksum->length - 24);
+		   fclose(f);
+	       }
+	   }
+#endif
+       }
+   }
+
+   /* create the ctx struct and start filling it in */
+
+   if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
+       == NULL) {
+       code = ENOMEM;
+       major_status = GSS_S_FAILURE;
+       goto fail;
+   }
+
+   memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+   ctx->mech_used = (gss_OID) mech_used;
+   ctx->auth_context = auth_context;
+   ctx->initiate = 0;
+   ctx->gss_flags = (GSS_C_TRANS_FLAG |
+                    ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
+                            GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+                            GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
+   ctx->seed_init = 0;
+   ctx->big_endian = bigend;
+   ctx->cred_rcache = cred_rcache;
+
+   /* Intern the ctx pointer so that delete_sec_context works */
+   if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
+       xfree(ctx);
+       ctx = 0;
+
+       code = G_VALIDATE_FAILED;
+       major_status = GSS_S_FAILURE;
+       goto fail;
+   }
+
+   if ((code = krb5_copy_principal(context, ticket->server, &ctx->here))) {
+       major_status = GSS_S_FAILURE;
+       goto fail;
+   }
+
+   if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) {
+       major_status = GSS_S_FAILURE;
+       goto fail;
+   }
+
+   if ((code = krb5_auth_con_getrecvsubkey(context, auth_context,
+					   &ctx->subkey))) { 
+       major_status = GSS_S_FAILURE;      
+       goto fail;
+   }
+
+   /* use the session key if the subkey isn't present */
+
+   if (ctx->subkey == NULL) {
+       if ((code = krb5_auth_con_getkey(context, auth_context,
+					&ctx->subkey))) {
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+   }
+
+   if (ctx->subkey == NULL) {
+       /* this isn't a very good error, but it's not clear to me this
+	  can actually happen */
+       major_status = GSS_S_FAILURE;
+       code = KRB5KDC_ERR_NULL_KEY;
+       goto fail;
+   }
+
+   ctx->proto = 0;
+   switch(ctx->subkey->enctype) {
+   case ENCTYPE_DES_CBC_MD5:
+   case ENCTYPE_DES_CBC_CRC:
+       ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
+       ctx->signalg = SGN_ALG_DES_MAC_MD5;
+       ctx->cksum_size = 8;
+       ctx->sealalg = SEAL_ALG_DES;
+
+       /* fill in the encryption descriptors */
+
+       if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+
+       for (i=0; i<ctx->enc->length; i++)
+	   /*SUPPRESS 113*/
+	   ctx->enc->contents[i] ^= 0xf0;
+
+       goto copy_subkey_to_seq;
+
+   case ENCTYPE_DES3_CBC_SHA1:
+       ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
+       ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
+       ctx->cksum_size = 20;
+       ctx->sealalg = SEAL_ALG_DES3KD;
+
+       /* fill in the encryption descriptors */
+   copy_subkey:
+       if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+   copy_subkey_to_seq:
+       if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+       break;
+
+   case ENCTYPE_ARCFOUR_HMAC:
+       ctx->signalg = SGN_ALG_HMAC_MD5 ;
+       ctx->cksum_size = 8;
+       ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
+       goto copy_subkey;
+
+   default:
+       ctx->signalg = -1;
+       ctx->sealalg = -1;
+       ctx->proto = 1;
+       code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
+					    &ctx->cksumtype);
+       if (code)
+	   goto fail;
+       code = krb5_c_checksum_length(context, ctx->cksumtype,
+				     &ctx->cksum_size);
+       if (code)
+	   goto fail;
+       ctx->have_acceptor_subkey = 0;
+       goto copy_subkey;
+   }
+
+   ctx->endtime = ticket->enc_part2->times.endtime;
+   ctx->krb_flags = ticket->enc_part2->flags;
+
+   krb5_free_ticket(context, ticket); /* Done with ticket */
+
+   {
+       krb5_ui_4 seq_temp;
+       krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
+       ctx->seq_recv = seq_temp;
+   }
+
+   if ((code = krb5_timeofday(context, &now))) {
+       major_status = GSS_S_FAILURE;
+       goto fail;
+   }
+
+   if (ctx->endtime < now) {
+       code = 0;
+       major_status = GSS_S_CREDENTIALS_EXPIRED;
+       goto fail;
+   }
+
+   g_order_init(&(ctx->seqstate), ctx->seq_recv,
+		(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
+		(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
+
+   /* at this point, the entire context structure is filled in, 
+      so it can be released.  */
+
+   /* generate an AP_REP if necessary */
+
+   if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
+       unsigned char * ptr3;
+       krb5_ui_4 seq_temp;
+       int cfx_generate_subkey;
+
+       if (ctx->proto == 1)
+	   cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
+       else
+	   cfx_generate_subkey = 0;
+
+       if (cfx_generate_subkey) {
+	   krb5_int32 acflags;
+	   code = krb5_auth_con_getflags(context, auth_context, &acflags);
+	   if (code == 0) {
+	       acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
+	       code = krb5_auth_con_setflags(context, auth_context, acflags);
+	   }
+	   if (code) {
+	       major_status = GSS_S_FAILURE;
+	       goto fail;
+	   }
+       }
+
+       if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+
+       krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
+       ctx->seq_send = seq_temp & 0xffffffffL;
+
+       if (cfx_generate_subkey) {
+	   /* Get the new acceptor subkey.  With the code above, there
+	      should always be one if we make it to this point.  */
+	   code = krb5_auth_con_getsendsubkey(context, auth_context,
+					      &ctx->acceptor_subkey);
+	   if (code != 0) {
+	       major_status = GSS_S_FAILURE;
+	       goto fail;
+	   }
+	   code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
+						ctx->acceptor_subkey->enctype,
+						&ctx->acceptor_subkey_cksumtype);
+	   if (code) {
+	       major_status = GSS_S_FAILURE;
+	       goto fail;
+	   }
+	   ctx->have_acceptor_subkey = 1;
+       }
+
+       /* the reply token hasn't been sent yet, but that's ok. */
+       ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
+       ctx->established = 1;
+
+       token.length = g_token_size((gss_OID) mech_used, ap_rep.length);
+
+       if ((token.value = (unsigned char *) xmalloc(token.length))
+	   == NULL) {
+	   major_status = GSS_S_FAILURE;
+	   code = ENOMEM;
+	   goto fail;
+       }
+       ptr3 = token.value;
+       g_make_token_header((gss_OID) mech_used, ap_rep.length,
+			   &ptr3, KG_TOK_CTX_AP_REP);
+
+       TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
+
+       ctx->established = 1;
+
+   } else {
+       token.length = 0;
+       token.value = NULL;
+       ctx->seq_send = ctx->seq_recv;
+
+       ctx->established = 1;
+   }
+
+   /* set the return arguments */
+
+   if (src_name) {
+       if ((code = krb5_copy_principal(context, ctx->there, &name))) {
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+       /* intern the src_name */
+       if (! kg_save_name((gss_name_t) name)) {
+	   code = G_VALIDATE_FAILED;
+	   major_status = GSS_S_FAILURE;
+	   goto fail;
+       }
+   }
+
+   if (mech_type)
+      *mech_type = (gss_OID) mech_used;
+
+   if (time_rec)
+      *time_rec = ctx->endtime - now;
+
+   if (ret_flags)
+      *ret_flags = ctx->gss_flags;
+
+   *context_handle = ctx;
+   *output_token = token;
+
+   if (src_name)
+      *src_name = (gss_name_t) name;
+
+   if (delegated_cred_handle && deleg_cred) {
+       if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
+	   major_status = GSS_S_FAILURE;
+	   code = G_VALIDATE_FAILED;
+	   goto fail;
+       }
+
+       *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
+   }
+
+   /* finally! */
+
+   *minor_status = 0;
+   major_status = GSS_S_COMPLETE;
+
+ fail:
+   if (authdat)
+       krb5_free_authenticator(context, authdat);
+   /* The ctx structure has the handle of the auth_context */
+   if (auth_context && !ctx) {
+       if (cred_rcache)
+	   (void)krb5_auth_con_setrcache(context, auth_context, NULL);
+
+       krb5_auth_con_free(context, auth_context);
+   }
+   if (reqcksum.contents)
+       xfree(reqcksum.contents);
+   if (ap_rep.data)
+       krb5_free_data_contents(context, &ap_rep);
+
+   if (!GSS_ERROR(major_status) && major_status != GSS_S_CONTINUE_NEEDED) {
+       ctx->k5_context = context;
+       return(major_status);
+   }
+
+   /* from here on is the real "fail" code */
+
+   if (ctx)
+       (void) krb5_gss_delete_sec_context(minor_status, 
+					  (gss_ctx_id_t *) &ctx, NULL);
+   if (deleg_cred) { /* free memory associated with the deleg credential */
+       if (deleg_cred->ccache)
+	   (void)krb5_cc_close(context, deleg_cred->ccache);
+       if (deleg_cred->princ)
+	   krb5_free_principal(context, deleg_cred->princ);
+       xfree(deleg_cred);
+   }
+   if (token.value)
+       xfree(token.value);
+   if (name) {
+       (void) kg_delete_name((gss_name_t) name);
+       krb5_free_principal(context, name);
+   }
+
+   *minor_status = code;
+
+   /*
+    * If decode_req_message is set, then we need to decode the ap_req
+    * message to determine whether or not to send a response token.
+    * We need to do this because for some errors we won't be able to
+    * decode the authenticator to read out the gss_flags field.
+    */
+   if (decode_req_message) {
+       krb5_ap_req 	* request;
+	   
+       if (decode_krb5_ap_req(&ap_req, &request)) {
+	   krb5_free_context(context);
+	   return (major_status);
+       }
+       if (request->ap_options & AP_OPTS_MUTUAL_REQUIRED)
+	   gss_flags |= GSS_C_MUTUAL_FLAG;
+       krb5_free_ap_req(context, request);
+   }
+
+   if (cred
+       && ((gss_flags & GSS_C_MUTUAL_FLAG)
+	   || (major_status == GSS_S_CONTINUE_NEEDED))) {
+       unsigned int tmsglen;
+       int toktype;
+
+       /*
+	* The client is expecting a response, so we can send an
+	* error token back
+	*/
+       memset(&krb_error_data, 0, sizeof(krb_error_data));
+
+       code -= ERROR_TABLE_BASE_krb5;
+       if (code < 0 || code > 128)
+	   code = 60 /* KRB_ERR_GENERIC */;
+
+       krb_error_data.error = code;
+       (void) krb5_us_timeofday(context, &krb_error_data.stime,
+				&krb_error_data.susec);
+       krb_error_data.server = cred->princ;
+
+       code = krb5_mk_error(context, &krb_error_data, &scratch);
+       if (code) {
+	   krb5_free_context(context);
+	   return (major_status);
+       }
+
+       tmsglen = scratch.length;
+       toktype = KG_TOK_CTX_ERROR;
+
+       token.length = g_token_size((gss_OID) mech_used, tmsglen);
+       token.value = (unsigned char *) xmalloc(token.length);
+       if (!token.value) {
+	   krb5_free_context(context);
+	   return (major_status);
+       }
+
+       ptr = token.value;
+       g_make_token_header((gss_OID) mech_used, tmsglen, &ptr, toktype);
+
+       TWRITE_STR(ptr, scratch.data, scratch.length);
+       krb5_free_data_contents(context, &scratch);
+
+       *output_token = token;
+   }
+   if (!verifier_cred_handle && cred_handle) {
+	   krb5_gss_release_cred(minor_status, cred_handle);
+   }
+   krb5_free_context(context);
+   return (major_status);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/acquire_cred.c b/mechglue/src/lib/gssapi/krb5/acquire_cred.c
new file mode 100644
index 000000000..c293b2783
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/acquire_cred.c
@@ -0,0 +1,652 @@
+/*
+ * Copyright 2000 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "gss_libinit.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#if defined(USE_LOGIN_LIBRARY)
+#include <Kerberos/KerberosLoginPrivate.h>
+#elif defined(USE_LEASH)
+static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL;
+static HANDLE hLeashDLL = INVALID_HANDLE_VALUE;
+#endif
+
+k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+static char *krb5_gss_keytab = NULL;
+
+/* Heimdal calls this gsskrb5_register_acceptor_identity. */
+OM_uint32 KRB5_CALLCONV
+krb5_gss_register_acceptor_identity(const char *keytab)
+{
+    size_t	len;
+    char *new, *old;
+    int err;
+
+    err = gssint_initialize_library();
+    if (err != 0)
+	return GSS_S_FAILURE;
+
+    if (keytab == NULL)
+	return GSS_S_FAILURE;
+
+    len = strlen(keytab);
+    new = malloc(len + 1);
+    if (new == NULL)
+	return GSS_S_FAILURE;
+    strcpy(new, keytab);
+
+    err = k5_mutex_lock(&gssint_krb5_keytab_lock);
+    if (err) {
+	free(new);
+	return GSS_S_FAILURE;
+    }
+    old = krb5_gss_keytab;
+    krb5_gss_keytab = new;
+    k5_mutex_unlock(&gssint_krb5_keytab_lock);
+    if (old != NULL)
+	free(old);
+    return GSS_S_COMPLETE;
+}
+
+/* get credentials corresponding to a key in the krb5 keytab.
+   If the default name is requested, return the name in output_princ.
+     If output_princ is non-NULL, the caller will use or free it, regardless
+     of the return value.
+   If successful, set the keytab-specific fields in cred
+   */
+
+static OM_uint32 
+acquire_accept_cred(context, minor_status, desired_name, output_princ, cred)
+     krb5_context context;
+     OM_uint32 *minor_status;
+     gss_name_t desired_name;
+     krb5_principal *output_princ;
+     krb5_gss_cred_id_rec *cred;
+{
+   krb5_error_code code;
+   krb5_principal princ;
+   krb5_keytab kt;
+   krb5_keytab_entry entry;
+
+   *output_princ = NULL;
+   cred->keytab = NULL;
+
+   /* open the default keytab */
+
+   code = gssint_initialize_library();
+   if (code != 0) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+   code = k5_mutex_lock(&gssint_krb5_keytab_lock);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+   if (krb5_gss_keytab != NULL) {
+      code = krb5_kt_resolve(context, krb5_gss_keytab, &kt);
+      k5_mutex_unlock(&gssint_krb5_keytab_lock);
+   } else {
+      k5_mutex_unlock(&gssint_krb5_keytab_lock);
+      code = krb5_kt_default(context, &kt);
+   }
+
+   if (code) {
+      *minor_status = code;
+      return(GSS_S_CRED_UNAVAIL);
+   }
+
+   if (desired_name != GSS_C_NO_NAME) {
+      princ = (krb5_principal) desired_name;
+      if ((code = krb5_kt_get_entry(context, kt, princ, 0, 0, &entry))) {
+	 (void) krb5_kt_close(context, kt);
+	 if (code == KRB5_KT_NOTFOUND)
+	    *minor_status = KG_KEYTAB_NOMATCH;
+	 else
+	    *minor_status = code;
+	 return(GSS_S_CRED_UNAVAIL);
+      }
+      krb5_kt_free_entry(context, &entry);
+
+      /* Open the replay cache for this principal. */
+      if ((code = krb5_get_server_rcache(context,
+					 krb5_princ_component(context, princ, 0),
+					 &cred->rcache))) {
+	 *minor_status = code;
+	 return(GSS_S_FAILURE);
+      }
+
+   }
+
+/* hooray.  we made it */
+
+   cred->keytab = kt;
+
+   return(GSS_S_COMPLETE);
+}
+
+/* get credentials corresponding to the default credential cache.
+   If the default name is requested, return the name in output_princ.
+     If output_princ is non-NULL, the caller will use or free it, regardless
+     of the return value.
+   If successful, set the ccache-specific fields in cred.
+   */
+
+static OM_uint32 
+acquire_init_cred(context, minor_status, desired_name, output_princ, cred)
+     krb5_context context;
+     OM_uint32 *minor_status;
+     gss_name_t desired_name;
+     krb5_principal *output_princ;
+     krb5_gss_cred_id_rec *cred;
+{
+   krb5_error_code code;
+   krb5_ccache ccache;
+   krb5_principal princ, tmp_princ;
+   krb5_flags flags;
+   krb5_cc_cursor cur;
+   krb5_creds creds;
+   int got_endtime;
+
+   cred->ccache = NULL;
+
+   /* load the GSS ccache name into the kg_context */
+   
+   if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
+       return(GSS_S_FAILURE);
+
+#if defined(USE_LOGIN_LIBRARY) || defined(USE_LEASH)
+   if (desired_name != NULL) {
+#if defined(USE_LOGIN_LIBRARY)
+       char *ccache_name = NULL;
+       KLPrincipal kl_desired_princ = NULL;
+       
+       if ((code = __KLCreatePrincipalFromKerberos5Principal ((krb5_principal) desired_name,
+                                                              &kl_desired_princ))) {
+           *minor_status = code;
+           return(GSS_S_CRED_UNAVAIL);
+       }
+       
+       if ((code = KLAcquireInitialTickets (kl_desired_princ, NULL, NULL, &ccache_name))) {
+           KLDisposePrincipal (kl_desired_princ);
+           *minor_status = code;
+           return(GSS_S_CRED_UNAVAIL);
+       }
+       
+       if ((code = krb5_cc_resolve (context, ccache_name, &ccache))) {
+           KLDisposeString (ccache_name);
+           KLDisposePrincipal (kl_desired_princ);
+           *minor_status = code;
+           return(GSS_S_CRED_UNAVAIL);
+       }
+   
+       if (kl_desired_princ != NULL) { KLDisposePrincipal (kl_desired_princ); }
+       if (ccache_name      != NULL) { KLDisposeString (ccache_name); }
+#elif defined(USE_LEASH)
+       if ( hLeashDLL == INVALID_HANDLE_VALUE ) {
+	   hLeashDLL = LoadLibrary("leashw32.dll");
+	   if ( hLeashDLL != INVALID_HANDLE_VALUE ) {
+	       (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
+		   GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
+	   }
+       }
+    
+       if ( pLeash_AcquireInitialTicketsIfNeeded ) {
+	   char ccname[256]="";
+	   pLeash_AcquireInitialTicketsIfNeeded(context, (krb5_principal) desired_name, ccname, sizeof(ccname));
+	   if (!ccname[0]) {
+	       *minor_status = KRB5_CC_NOTFOUND;
+	       return(GSS_S_CRED_UNAVAIL);
+	   }
+
+	   if ((code = krb5_cc_resolve (context, ccname, &ccache))) {
+	       *minor_status = code;
+	       return(GSS_S_CRED_UNAVAIL);
+	   }
+       }
+#endif /* USE_LEASH */
+   } else
+#endif /* USE_LOGIN_LIBRARY || USE_LEASH */
+   {
+       /* open the default credential cache */
+   
+       if ((code = krb5int_cc_default(context, &ccache))) {
+	   *minor_status = code;
+	   return(GSS_S_CRED_UNAVAIL);
+       }
+   }
+
+   /* turn off OPENCLOSE mode while extensive frobbing is going on */
+
+   flags = 0;		/* turns off OPENCLOSE mode */
+   if ((code = krb5_cc_set_flags(context, ccache, flags))) {
+      (void)krb5_cc_close(context, ccache);
+      *minor_status = code;
+      return(GSS_S_CRED_UNAVAIL);
+   }
+
+   /* get out the principal name and see if it matches */
+
+   if ((code = krb5_cc_get_principal(context, ccache, &princ))) {
+      (void)krb5_cc_close(context, ccache);
+      *minor_status = code;
+      return(GSS_S_FAILURE);
+   }
+
+   if (desired_name != (gss_name_t) NULL) {
+      if (! krb5_principal_compare(context, princ, (krb5_principal) desired_name)) {
+	 (void)krb5_free_principal(context, princ);
+	 (void)krb5_cc_close(context, ccache);
+	 *minor_status = KG_CCACHE_NOMATCH;
+	 return(GSS_S_CRED_UNAVAIL);
+      }
+      (void)krb5_free_principal(context, princ);
+      princ = (krb5_principal) desired_name;
+   } else {
+      *output_princ = princ;
+   }
+
+   /* iterate over the ccache, find the tgt */
+
+   if ((code = krb5_cc_start_seq_get(context, ccache, &cur))) {
+      (void)krb5_cc_close(context, ccache);
+      *minor_status = code;
+      return(GSS_S_FAILURE);
+   }
+
+   /* this is hairy.  If there's a tgt for the principal's local realm
+      in here, that's what we want for the expire time.  But if
+      there's not, then we want to use the first key.  */
+
+   got_endtime = 0;
+
+   code = krb5_build_principal_ext(context, &tmp_princ,
+				   krb5_princ_realm(context, princ)->length,
+				   krb5_princ_realm(context, princ)->data,
+				   6, "krbtgt",
+				   krb5_princ_realm(context, princ)->length,
+				   krb5_princ_realm(context, princ)->data,
+				   0);
+   if (code) {
+      (void)krb5_cc_close(context, ccache);
+      *minor_status = code;
+      return(GSS_S_FAILURE);
+   }
+   while (!(code = krb5_cc_next_cred(context, ccache, &cur, &creds))) {
+      if (krb5_principal_compare(context, tmp_princ, creds.server)) {
+	 cred->tgt_expire = creds.times.endtime;
+	 got_endtime = 1;
+	 *minor_status = 0;
+	 code = 0;
+	 krb5_free_cred_contents(context, &creds);
+	 break;
+      }
+      if (got_endtime == 0) {
+	 cred->tgt_expire = creds.times.endtime;
+	 got_endtime = 1;
+      }
+      krb5_free_cred_contents(context, &creds);
+   }
+   krb5_free_principal(context, tmp_princ);
+
+   if (code && code != KRB5_CC_END) {
+      /* this means some error occurred reading the ccache */
+      (void)krb5_cc_end_seq_get(context, ccache, &cur);
+      (void)krb5_cc_close(context, ccache);
+      *minor_status = code;
+      return(GSS_S_FAILURE);
+   } else if (! got_endtime) {
+      /* this means the ccache was entirely empty */
+      (void)krb5_cc_end_seq_get(context, ccache, &cur);
+      (void)krb5_cc_close(context, ccache);
+      *minor_status = KG_EMPTY_CCACHE;
+      return(GSS_S_FAILURE);
+   } else {
+      /* this means that we found an endtime to use. */
+      if ((code = krb5_cc_end_seq_get(context, ccache, &cur))) {
+	 (void)krb5_cc_close(context, ccache);
+	 *minor_status = code;
+	 return(GSS_S_FAILURE);
+      }
+      flags = KRB5_TC_OPENCLOSE;	/* turns on OPENCLOSE mode */
+      if ((code = krb5_cc_set_flags(context, ccache, flags))) {
+	 (void)krb5_cc_close(context, ccache);
+	 *minor_status = code;
+	 return(GSS_S_FAILURE);
+      }
+   }
+
+   /* the credentials match and are valid */
+
+   cred->ccache = ccache;
+   /* minor_status is set while we are iterating over the ccache */
+   return(GSS_S_COMPLETE);
+}
+   
+/*ARGSUSED*/
+OM_uint32
+krb5_gss_acquire_cred(minor_status, desired_name, time_req,
+		      desired_mechs, cred_usage, output_cred_handle,
+		      actual_mechs, time_rec)
+     OM_uint32 *minor_status;
+     gss_name_t desired_name;
+     OM_uint32 time_req;
+     gss_OID_set desired_mechs;
+     gss_cred_usage_t cred_usage;
+     gss_cred_id_t *output_cred_handle;
+     gss_OID_set *actual_mechs;
+     OM_uint32 *time_rec;
+{
+   krb5_context context;
+   size_t i;
+   krb5_gss_cred_id_t cred;
+   gss_OID_set ret_mechs;
+   int req_old, req_new;
+   OM_uint32 ret;
+   krb5_error_code code;
+
+   code = gssint_initialize_library();
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   code = krb5_init_context(&context);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   /* make sure all outputs are valid */
+
+   *output_cred_handle = NULL;
+   if (actual_mechs)
+      *actual_mechs = NULL;
+   if (time_rec)
+      *time_rec = 0;
+
+   /* validate the name */
+
+   /*SUPPRESS 29*/
+   if ((desired_name != (gss_name_t) NULL) &&
+       (! kg_validate_name(desired_name))) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      krb5_free_context(context);
+      return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+   }
+
+   /* verify that the requested mechanism set is the default, or
+      contains krb5 */
+
+   if (desired_mechs == GSS_C_NULL_OID_SET) {
+      req_old = 1;
+      req_new = 1;
+   } else {
+      req_old = 0;
+      req_new = 0;
+
+      for (i=0; i<desired_mechs->count; i++) {
+	 if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i])))
+	    req_old++;
+	 if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i])))
+	    req_new++;
+      }
+
+      if (!req_old && !req_new) {
+	 *minor_status = 0;
+	 krb5_free_context(context);
+	 return(GSS_S_BAD_MECH);
+      }
+   }
+
+   /* create the gss cred structure */
+
+   if ((cred =
+	(krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) == NULL) {
+      *minor_status = ENOMEM;
+      krb5_free_context(context);
+      return(GSS_S_FAILURE);
+   }
+   memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
+
+   cred->usage = cred_usage;
+   cred->princ = NULL;
+   cred->prerfc_mech = req_old;
+   cred->rfc_mech = req_new;
+
+   cred->keytab = NULL;
+   cred->ccache = NULL;
+
+   code = k5_mutex_init(&cred->lock);
+   if (code) {
+       *minor_status = code;
+       krb5_free_context(context);
+       return GSS_S_FAILURE;
+   }
+   /* Note that we don't need to lock this GSSAPI credential record
+      here, because no other thread can gain access to it until we
+      return it.  */
+
+   if ((cred_usage != GSS_C_INITIATE) &&
+       (cred_usage != GSS_C_ACCEPT) &&
+       (cred_usage != GSS_C_BOTH)) {
+      k5_mutex_destroy(&cred->lock);
+      xfree(cred);
+      *minor_status = (OM_uint32) G_BAD_USAGE;
+      krb5_free_context(context);
+      return(GSS_S_FAILURE);
+   }
+
+   /* if requested, acquire credentials for accepting */
+   /* this will fill in cred->princ if the desired_name is not specified */
+
+   if ((cred_usage == GSS_C_ACCEPT) ||
+       (cred_usage == GSS_C_BOTH))
+      if ((ret = acquire_accept_cred(context, minor_status, desired_name,
+				     &(cred->princ), cred))
+	  != GSS_S_COMPLETE) {
+	 if (cred->princ)
+	    krb5_free_principal(context, cred->princ);
+         k5_mutex_destroy(&cred->lock);
+         xfree(cred);
+	 /* minor_status set by acquire_accept_cred() */
+	 krb5_free_context(context);
+	 return(ret);
+      }
+
+   /* if requested, acquire credentials for initiation */
+   /* this will fill in cred->princ if it wasn't set above, and
+      the desired_name is not specified */
+
+   if ((cred_usage == GSS_C_INITIATE) ||
+       (cred_usage == GSS_C_BOTH))
+      if ((ret =
+	   acquire_init_cred(context, minor_status,
+			     cred->princ?(gss_name_t)cred->princ:desired_name,
+			     &(cred->princ), cred))
+	  != GSS_S_COMPLETE) {
+	 if (cred->keytab)
+	    krb5_kt_close(context, cred->keytab);
+	 if (cred->princ)
+	    krb5_free_principal(context, cred->princ);
+         k5_mutex_destroy(&cred->lock);
+         xfree(cred);
+	 /* minor_status set by acquire_init_cred() */
+	 krb5_free_context(context);
+	 return(ret);
+      }
+
+   /* if the princ wasn't filled in already, fill it in now */
+
+   if (!cred->princ && (desired_name != GSS_C_NO_CREDENTIAL))
+      if ((code = krb5_copy_principal(context, (krb5_principal) desired_name,
+				      &(cred->princ)))) {
+	 if (cred->ccache)
+	    (void)krb5_cc_close(context, cred->ccache);
+	 if (cred->keytab)
+	    (void)krb5_kt_close(context, cred->keytab);
+         k5_mutex_destroy(&cred->lock);
+         xfree(cred);
+	 *minor_status = code;
+	 krb5_free_context(context);
+	 return(GSS_S_FAILURE);
+      }
+
+   /*** at this point, the cred structure has been completely created */
+
+   /* compute time_rec */
+
+   if (cred_usage == GSS_C_ACCEPT) {
+      if (time_rec)
+	 *time_rec = GSS_C_INDEFINITE;
+   } else {
+      krb5_timestamp now;
+
+      if ((code = krb5_timeofday(context, &now))) {
+	 if (cred->ccache)
+	    (void)krb5_cc_close(context, cred->ccache);
+	 if (cred->keytab)
+	    (void)krb5_kt_close(context, cred->keytab);
+	 if (cred->princ)
+	    krb5_free_principal(context, cred->princ);
+         k5_mutex_destroy(&cred->lock);
+         xfree(cred);
+	 *minor_status = code;
+	 krb5_free_context(context);
+	 return(GSS_S_FAILURE);
+      }
+
+      if (time_rec)
+	 *time_rec = (cred->tgt_expire > now) ? (cred->tgt_expire - now) : 0;
+   }
+
+   /* create mechs */
+
+   if (actual_mechs) {
+       if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
+							    &ret_mechs)) ||
+	   (cred->prerfc_mech &&
+	    GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+							   (gss_OID) gss_mech_krb5_old,
+							   &ret_mechs))) ||
+	   (cred->rfc_mech &&
+	    GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+							   (gss_OID) gss_mech_krb5,
+							   &ret_mechs)))) {
+	   if (cred->ccache)
+	       (void)krb5_cc_close(context, cred->ccache);
+	   if (cred->keytab)
+	       (void)krb5_kt_close(context, cred->keytab);
+	   if (cred->princ)
+	       krb5_free_principal(context, cred->princ);
+           k5_mutex_destroy(&cred->lock);
+	   xfree(cred);
+	   /* *minor_status set above */
+	   krb5_free_context(context);
+	   return(ret);
+       }
+   }
+
+   /* intern the credential handle */
+
+   if (! kg_save_cred_id((gss_cred_id_t) cred)) {
+      free(ret_mechs->elements);
+      free(ret_mechs);
+      if (cred->ccache)
+	 (void)krb5_cc_close(context, cred->ccache);
+      if (cred->keytab)
+	 (void)krb5_kt_close(context, cred->keytab);
+      if (cred->princ)
+	 krb5_free_principal(context, cred->princ);
+      k5_mutex_destroy(&cred->lock);
+      xfree(cred);
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      krb5_free_context(context);
+      return(GSS_S_FAILURE);
+   }
+
+   /* return success */
+
+   *minor_status = 0;
+   *output_cred_handle = (gss_cred_id_t) cred;
+   if (actual_mechs)
+      *actual_mechs = ret_mechs;
+
+   krb5_free_context(context);
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/add_cred.c b/mechglue/src/lib/gssapi/krb5/add_cred.c
new file mode 100644
index 000000000..6cb6605d9
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/add_cred.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2000 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * $Id$
+ */
+
+/* V2 interface */
+OM_uint32
+krb5_gss_add_cred(minor_status, input_cred_handle,
+		  desired_name, desired_mech, cred_usage,
+		  initiator_time_req, acceptor_time_req,
+		  output_cred_handle, actual_mechs, 
+		  initiator_time_rec, acceptor_time_rec)
+    OM_uint32		*minor_status;
+    gss_cred_id_t	input_cred_handle;
+    gss_name_t		desired_name;
+    gss_OID		desired_mech;
+    gss_cred_usage_t	cred_usage;
+    OM_uint32		initiator_time_req;
+    OM_uint32		acceptor_time_req;
+    gss_cred_id_t	*output_cred_handle;
+    gss_OID_set		*actual_mechs;
+    OM_uint32		*initiator_time_rec;
+    OM_uint32		*acceptor_time_rec;
+{
+    krb5_context	context;
+    OM_uint32		major_status, lifetime;
+    krb5_gss_cred_id_t	cred;
+    krb5_error_code	code;
+
+    /* this is pretty simple, since there's not really any difference
+       between the underlying mechanisms.  The main hair is in copying
+       a mechanism if requested. */
+
+    /* check if the desired_mech is bogus */
+
+    if (!g_OID_equal(desired_mech, gss_mech_krb5) &&
+	!g_OID_equal(desired_mech, gss_mech_krb5_old)) {
+	*minor_status = 0;
+	return(GSS_S_BAD_MECH);
+    }
+
+    /* check if the desired_mech is bogus */
+
+    if ((cred_usage != GSS_C_INITIATE) &&
+	(cred_usage != GSS_C_ACCEPT) &&
+	(cred_usage != GSS_C_BOTH)) {
+	*minor_status = (OM_uint32) G_BAD_USAGE;
+	return(GSS_S_FAILURE);
+    }
+
+    /* since the default credential includes all the mechanisms,
+       return an error for that case. */
+
+    /*SUPPRESS 29*/
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+	*minor_status = 0;
+	return(GSS_S_DUPLICATE_ELEMENT);
+    }
+
+    code = krb5_init_context(&context);
+    if (code) {
+	*minor_status = code;
+	return GSS_S_FAILURE;
+    }
+
+    major_status = krb5_gss_validate_cred_1(minor_status, input_cred_handle,
+					    context);
+    if (GSS_ERROR(major_status)) {
+	krb5_free_context(context);
+	return major_status;
+    }
+
+    cred = (krb5_gss_cred_id_t) input_cred_handle;
+    k5_mutex_assert_locked(&cred->lock);
+
+    /* check if the cred_usage is equal or "less" than the passed-in cred
+       if copying */
+
+    if (!((cred->usage == cred_usage) ||
+	  ((cred->usage == GSS_C_BOTH) &&
+	   (output_cred_handle != NULL)))) {
+      *minor_status = (OM_uint32) G_BAD_USAGE;
+      krb5_free_context(context);
+      return(GSS_S_FAILURE);
+    }
+
+    /* check that desired_mech isn't already in the credential */
+
+    if ((g_OID_equal(desired_mech, gss_mech_krb5_old) && cred->prerfc_mech) ||
+	(g_OID_equal(desired_mech, gss_mech_krb5) && cred->rfc_mech)) {
+	*minor_status = 0;
+	krb5_free_context(context);
+	return(GSS_S_DUPLICATE_ELEMENT);
+    }
+
+    if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) {
+	krb5_free_context(context);
+	return GSS_S_FAILURE;
+    }
+
+    /* verify the desired_name */
+
+    /*SUPPRESS 29*/
+    if ((desired_name != (gss_name_t) NULL) &&
+	(! kg_validate_name(desired_name))) {
+	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	krb5_free_context(context);
+	return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+    }
+
+    /* make sure the desired_name is the same as the existing one */
+
+    if (desired_name &&
+	!krb5_principal_compare(context, (krb5_principal) desired_name,
+				cred->princ)) {
+	*minor_status = 0;
+	krb5_free_context(context);
+	return(GSS_S_BAD_NAME);
+    }
+
+    /* copy the cred if necessary */
+
+    if (output_cred_handle) {
+	/* make a copy */
+	krb5_gss_cred_id_t new_cred;
+	char *kttype, ktboth[1024];
+	const char *cctype, *ccname;
+	char ccboth[1024];
+
+	if ((new_cred =
+	     (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))
+	    == NULL) {
+	    *minor_status = ENOMEM;
+	    krb5_free_context(context);
+	    return(GSS_S_FAILURE);
+	}
+	memset(new_cred, 0, sizeof(krb5_gss_cred_id_rec));
+	
+	new_cred->usage = cred_usage;
+	new_cred->prerfc_mech = cred->prerfc_mech;
+	new_cred->rfc_mech = cred->rfc_mech;
+	new_cred->tgt_expire = cred->tgt_expire;
+
+	if (cred->princ)
+	    code = krb5_copy_principal(context, cred->princ, &new_cred->princ);
+	if (code) {
+	    xfree(new_cred);
+
+	    *minor_status = code;
+	    krb5_free_context(context);
+	    return(GSS_S_FAILURE);
+	}
+	    
+	if (cred->keytab) {
+	    kttype = krb5_kt_get_type(context, cred->keytab);
+	    if ((strlen(kttype)+2) > sizeof(ktboth)) {
+		if (new_cred->princ)
+		    krb5_free_principal(context, new_cred->princ);
+		xfree(new_cred);
+
+		*minor_status = ENOMEM;
+		krb5_free_context(context);
+		return(GSS_S_FAILURE);
+	    }
+
+	    strncpy(ktboth, kttype, sizeof(ktboth) - 1);
+	    ktboth[sizeof(ktboth) - 1] = '\0';
+	    strncat(ktboth, ":", sizeof(ktboth) - 1 - strlen(ktboth));
+
+	    code = krb5_kt_get_name(context, cred->keytab, 
+				    ktboth+strlen(ktboth),
+				    sizeof(ktboth)-strlen(ktboth));
+	    if (code) {
+		if(new_cred->princ)
+		    krb5_free_principal(context, new_cred->princ);
+		xfree(new_cred);
+
+		*minor_status = code;
+		krb5_free_context(context);
+		return(GSS_S_FAILURE);
+	    }
+
+	    code = krb5_kt_resolve(context, ktboth, &new_cred->keytab);
+	    if (code) {
+		if (new_cred->princ)
+		krb5_free_principal(context, new_cred->princ);
+		xfree(new_cred);
+
+		*minor_status = code;
+		krb5_free_context(context);
+		return(GSS_S_FAILURE);
+	    }
+	} else {
+	    new_cred->keytab = NULL;
+	}
+		
+	if (cred->rcache) {
+	    /* Open the replay cache for this principal. */
+	    if ((code = krb5_get_server_rcache(context,
+					       krb5_princ_component(context, cred->princ, 0),
+					       &new_cred->rcache))) {
+		if (new_cred->keytab)
+		    krb5_kt_close(context, new_cred->keytab);
+		if (new_cred->princ)
+		    krb5_free_principal(context, new_cred->princ);
+		xfree(new_cred);
+
+		krb5_free_context(context);
+		*minor_status = code;
+		return(GSS_S_FAILURE);
+	    }
+	} else {
+	    new_cred->rcache = NULL;
+	}
+
+	if (cred->ccache) {
+	    cctype = krb5_cc_get_type(context, cred->ccache);
+	    ccname = krb5_cc_get_name(context, cred->ccache);
+
+	    if ((strlen(cctype)+strlen(ccname)+2) > sizeof(ccboth)) {
+		if (new_cred->rcache)
+		    krb5_rc_close(context, new_cred->rcache);
+		if (new_cred->keytab)
+		    krb5_kt_close(context, new_cred->keytab);
+		if (new_cred->princ)
+		krb5_free_principal(context, new_cred->princ);
+		xfree(new_cred);
+
+		krb5_free_context(context);
+		*minor_status = ENOMEM;
+		return(GSS_S_FAILURE);
+	    }
+
+	    strncpy(ccboth, cctype, sizeof(ccboth) - 1);
+	    ccboth[sizeof(ccboth) - 1] = '\0';
+	    strncat(ccboth, ":", sizeof(ccboth) - 1 - strlen(ccboth));
+	    strncat(ccboth, ccname, sizeof(ccboth) - 1 - strlen(ccboth));
+
+	    code = krb5_cc_resolve(context, ccboth, &new_cred->ccache);
+	    if (code) {
+		if (new_cred->rcache)
+		    krb5_rc_close(context, new_cred->rcache);
+		if (new_cred->keytab)
+		    krb5_kt_close(context, new_cred->keytab);
+		if (new_cred->princ)
+		    krb5_free_principal(context, new_cred->princ);
+		xfree(new_cred);
+		krb5_free_context(context);
+
+		*minor_status = code;
+		return(GSS_S_FAILURE);
+	    }
+	} else {
+	    new_cred->ccache = NULL;
+	}
+
+	/* intern the credential handle */
+
+	if (! kg_save_cred_id((gss_cred_id_t) new_cred)) {
+	    if (new_cred->ccache)
+		krb5_cc_close(context, new_cred->ccache);
+	    if (new_cred->rcache)
+		krb5_rc_close(context, new_cred->rcache);
+	    if (new_cred->keytab)
+		krb5_kt_close(context, new_cred->keytab);
+	    if (new_cred->princ)
+	    krb5_free_principal(context, new_cred->princ);
+	    xfree(new_cred);
+	    krb5_free_context(context);
+
+	    *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	    return(GSS_S_FAILURE);
+	}
+
+	/* modify new_cred */
+
+	cred = new_cred;
+    }
+		
+    /* set the flag for the new mechanism */
+
+    if (g_OID_equal(desired_mech, gss_mech_krb5_old))
+	cred->prerfc_mech = 1;
+    else if (g_OID_equal(desired_mech, gss_mech_krb5))
+	cred->rfc_mech = 1;
+
+    /* set the outputs */
+
+    if (GSS_ERROR(major_status = krb5_gss_inquire_cred(minor_status, cred,
+						       NULL, &lifetime,
+						       NULL, actual_mechs))) {
+	OM_uint32 dummy;
+	
+	if (output_cred_handle)
+	    (void) krb5_gss_release_cred(&dummy, (gss_cred_id_t *) &cred);
+	krb5_free_context(context);
+
+	return(major_status);
+    }
+
+    if (initiator_time_rec)
+	*initiator_time_rec = lifetime;
+    if (acceptor_time_rec)
+	*acceptor_time_rec = lifetime;
+
+    if (output_cred_handle)
+	*output_cred_handle = cred;
+
+    krb5_free_context(context);
+    *minor_status = 0;
+    return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/canon_name.c b/mechglue/src/lib/gssapi/krb5/canon_name.c
new file mode 100644
index 000000000..aed67c352
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/canon_name.c
@@ -0,0 +1,44 @@
+/*
+ * lib/gssapi/krb5/canon_name.c
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "gssapiP_krb5.h"
+
+/* This is trivial since we're a single mechanism implementation */
+
+OM_uint32 krb5_gss_canonicalize_name(OM_uint32  *minor_status,
+				     const gss_name_t input_name,
+				     const gss_OID mech_type,
+				     gss_name_t *output_name)
+{
+    if (!g_OID_equal(gss_mech_krb5, mech_type) &&
+	!g_OID_equal(gss_mech_krb5_old, mech_type)) {
+	*minor_status = 0;
+	return(GSS_S_BAD_MECH);
+    }
+
+    return(gss_duplicate_name(minor_status, input_name, output_name));
+}
diff --git a/mechglue/src/lib/gssapi/krb5/compare_name.c b/mechglue/src/lib/gssapi/krb5/compare_name.c
new file mode 100644
index 000000000..12201bf00
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/compare_name.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_compare_name(minor_status, name1, name2, name_equal)
+     OM_uint32 *minor_status;
+     gss_name_t name1;
+     gss_name_t name2;
+     int *name_equal;
+{ 
+   krb5_context context;
+   krb5_error_code code;
+
+   if (! kg_validate_name(name1)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+   }
+
+   if (! kg_validate_name(name2)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+   }
+
+   code = krb5_init_context(&context);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   *minor_status = 0;
+   *name_equal = krb5_principal_compare(context, (krb5_principal) name1,
+					(krb5_principal) name2);
+   krb5_free_context(context);
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/context_time.c b/mechglue/src/lib/gssapi/krb5/context_time.c
new file mode 100644
index 000000000..8b7930ffd
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/context_time.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+krb5_gss_context_time(minor_status, context_handle, time_rec)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     OM_uint32 *time_rec;
+{
+   krb5_error_code code;
+   krb5_gss_ctx_id_rec *ctx;
+   krb5_timestamp now;
+   krb5_deltat lifetime;
+
+   /* validate the context handle */
+   if (! kg_validate_ctx_id(context_handle)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+   if (! ctx->established) {
+      *minor_status = KG_CTX_INCOMPLETE;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   if ((code = krb5_timeofday(ctx->k5_context, &now))) {
+      *minor_status = code;
+      return(GSS_S_FAILURE);
+   }
+
+   if ((lifetime = ctx->endtime - now) <= 0) {
+      *time_rec = 0;
+      *minor_status = 0;
+      return(GSS_S_CONTEXT_EXPIRED);
+   } else {
+      *time_rec = lifetime;
+      *minor_status = 0;
+      return(GSS_S_COMPLETE);
+   }
+}
diff --git a/mechglue/src/lib/gssapi/krb5/copy_ccache.c b/mechglue/src/lib/gssapi/krb5/copy_ccache.c
new file mode 100644
index 000000000..38f109054
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/copy_ccache.c
@@ -0,0 +1,59 @@
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV 
+gss_krb5int_copy_ccache(minor_status, cred_handle, out_ccache)
+     OM_uint32 *minor_status;
+     gss_cred_id_t cred_handle;
+     krb5_ccache out_ccache;
+{
+   OM_uint32 stat;
+   krb5_gss_cred_id_t k5creds;
+   krb5_cc_cursor cursor;
+   krb5_creds creds;
+   krb5_error_code code;
+   krb5_context context;
+
+   /* validate the cred handle */
+   stat = krb5_gss_validate_cred(minor_status, cred_handle);
+   if (stat)
+       return(stat);
+   
+   k5creds = (krb5_gss_cred_id_t) cred_handle;
+   code = k5_mutex_lock(&k5creds->lock);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+   if (k5creds->usage == GSS_C_ACCEPT) {
+       k5_mutex_unlock(&k5creds->lock);
+       *minor_status = (OM_uint32) G_BAD_USAGE;
+       return(GSS_S_FAILURE);
+   }
+
+   code = krb5_init_context(&context);
+   if (code) {
+       k5_mutex_unlock(&k5creds->lock);
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   code = krb5_cc_start_seq_get(context, k5creds->ccache, &cursor);
+   if (code) {
+       k5_mutex_unlock(&k5creds->lock);
+       *minor_status = code;
+       krb5_free_context(context);
+       return(GSS_S_FAILURE);
+   }
+   while (!code && !krb5_cc_next_cred(context, k5creds->ccache, &cursor, &creds)) 
+       code = krb5_cc_store_cred(context, out_ccache, &creds);
+   krb5_cc_end_seq_get(context, k5creds->ccache, &cursor);
+   k5_mutex_unlock(&k5creds->lock);
+   krb5_free_context(context);
+   if (code) {
+       *minor_status = code;
+       return(GSS_S_FAILURE);
+   } else {
+       *minor_status = 0;
+       return(GSS_S_COMPLETE);
+   }
+}
diff --git a/mechglue/src/lib/gssapi/krb5/delete_sec_context.c b/mechglue/src/lib/gssapi/krb5/delete_sec_context.c
new file mode 100644
index 000000000..be91cd078
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/delete_sec_context.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+krb5_gss_delete_sec_context(minor_status, context_handle, output_token)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t *context_handle;
+     gss_buffer_t output_token;
+{
+   krb5_context context;
+   krb5_gss_ctx_id_rec *ctx;
+
+   if (output_token) {
+      output_token->length = 0;
+      output_token->value = NULL;
+   }
+
+   /*SUPPRESS 29*/
+   if (*context_handle == GSS_C_NO_CONTEXT) {
+      *minor_status = 0;
+      return(GSS_S_COMPLETE);
+   }
+
+   /*SUPPRESS 29*/
+   /* validate the context handle */
+   if (! kg_validate_ctx_id(*context_handle)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   ctx = (gss_ctx_id_t) *context_handle;
+   context = ctx->k5_context;
+
+   /* construct a delete context token if necessary */
+
+   if (output_token) {
+      OM_uint32 major;
+      gss_buffer_desc empty;
+      empty.length = 0; empty.value = NULL;
+
+      if ((major = kg_seal(minor_status, *context_handle, 0,
+			   GSS_C_QOP_DEFAULT,
+			   &empty, NULL, output_token, KG_TOK_DEL_CTX)))
+	 return(major);
+   }
+
+   /* invalidate the context handle */
+
+   (void)kg_delete_ctx_id(*context_handle);
+
+   /* free all the context state */
+
+   if (ctx->seqstate)
+      g_order_free(&(ctx->seqstate));
+
+   if (ctx->enc)
+      krb5_free_keyblock(context, ctx->enc);
+
+   if (ctx->seq)
+      krb5_free_keyblock(context, ctx->seq);
+
+   if (ctx->here)
+      krb5_free_principal(context, ctx->here);
+   if (ctx->there)
+      krb5_free_principal(context, ctx->there);
+   if (ctx->subkey)
+      krb5_free_keyblock(context, ctx->subkey);
+   if (ctx->acceptor_subkey)
+       krb5_free_keyblock(context, ctx->acceptor_subkey);
+
+   if (ctx->auth_context) {
+       if (ctx->cred_rcache)
+	   (void)krb5_auth_con_setrcache(context, ctx->auth_context, NULL);
+
+       krb5_auth_con_free(context, ctx->auth_context);
+   }
+
+   if (ctx->mech_used)
+       gss_release_oid(minor_status, &ctx->mech_used);
+   
+   if (ctx->k5_context)
+       krb5_free_context(ctx->k5_context);
+
+   /* Zero out context */
+   memset(ctx, 0, sizeof(*ctx));
+   xfree(ctx);
+
+   /* zero the handle itself */
+
+   *context_handle = GSS_C_NO_CONTEXT;
+
+   *minor_status = 0;
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/disp_name.c b/mechglue/src/lib/gssapi/krb5/disp_name.c
new file mode 100644
index 000000000..419f350b5
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/disp_name.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_display_name(minor_status, input_name, output_name_buffer, 
+		      output_name_type)
+     OM_uint32 *minor_status;
+     gss_name_t input_name;
+     gss_buffer_t output_name_buffer;
+     gss_OID *output_name_type;
+{
+   krb5_context context;
+   krb5_error_code code;
+   char *str;
+
+   code = krb5_init_context(&context);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   output_name_buffer->length = 0;
+   output_name_buffer->value = NULL;
+
+   if (! kg_validate_name(input_name)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      krb5_free_context(context);
+      return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+   }
+
+   if ((code = krb5_unparse_name(context,
+				 (krb5_principal) input_name, &str))) {
+      *minor_status = code;
+      krb5_free_context(context);
+      return(GSS_S_FAILURE);
+   }
+
+   if (! g_make_string_buffer(str, output_name_buffer)) {
+      krb5_free_unparsed_name(context, str);
+      krb5_free_context(context);
+
+      *minor_status = (OM_uint32) G_BUFFER_ALLOC;
+      return(GSS_S_FAILURE);
+   }
+
+   krb5_free_unparsed_name(context, str);
+   krb5_free_context(context);
+
+   *minor_status = 0;
+   if (output_name_type)
+      *output_name_type = (gss_OID) gss_nt_krb5_name;
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/disp_status.c b/mechglue/src/lib/gssapi/krb5/disp_status.c
new file mode 100644
index 000000000..1988d50c6
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/disp_status.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+#include "gss_libinit.h"
+#include "com_err.h"
+
+/* XXXX internationalization!! */
+
+/**/
+
+OM_uint32
+krb5_gss_display_status(minor_status, status_value, status_type,
+			mech_type, message_context, status_string)
+     OM_uint32 *minor_status;
+     OM_uint32 status_value;
+     int status_type;
+     gss_OID mech_type;
+     OM_uint32 *message_context;
+     gss_buffer_t status_string;
+{
+   status_string->length = 0;
+   status_string->value = NULL;
+
+   if ((mech_type != GSS_C_NULL_OID) &&
+       !g_OID_equal(gss_mech_krb5, mech_type) &&
+       !g_OID_equal(gss_mech_krb5_old, mech_type)) {
+       *minor_status = 0;
+       return(GSS_S_BAD_MECH);
+    }
+
+   if (status_type == GSS_C_GSS_CODE) {
+      return(g_display_major_status(minor_status, status_value,
+				    message_context, status_string));
+   } else if (status_type == GSS_C_MECH_CODE) {
+      (void) gssint_initialize_library();
+
+      if (*message_context) {
+	 *minor_status = (OM_uint32) G_BAD_MSG_CTX;
+	 return(GSS_S_FAILURE);
+      }
+
+      return(g_display_com_err_status(minor_status, status_value,
+				      status_string));
+   } else {
+      *minor_status = 0;
+      return(GSS_S_BAD_STATUS);
+   }
+}
diff --git a/mechglue/src/lib/gssapi/krb5/duplicate_name.c b/mechglue/src/lib/gssapi/krb5/duplicate_name.c
new file mode 100644
index 000000000..ffb762952
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/duplicate_name.c
@@ -0,0 +1,79 @@
+/*
+ * lib/gssapi/krb5/duplicate_name.c
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 krb5_gss_duplicate_name(OM_uint32  *minor_status,
+				  const gss_name_t input_name,
+				  gss_name_t *dest_name)
+{
+	krb5_context context;
+	krb5_error_code code;
+	krb5_principal princ, outprinc;
+
+	if (minor_status)
+	    *minor_status = 0;
+
+	code = krb5_init_context(&context);
+	if (code) {
+	    if (minor_status)
+		*minor_status = code;
+	    return GSS_S_FAILURE;
+	}
+
+	if (! kg_validate_name(input_name)) {
+		if (minor_status)
+			*minor_status = (OM_uint32) G_VALIDATE_FAILED;
+		krb5_free_context(context);
+		return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+	}
+
+	princ = input_name;
+	if ((code = krb5_copy_principal(context, princ, &outprinc))) {
+		*minor_status = code;
+		krb5_free_context(context);
+		return(GSS_S_FAILURE);
+	}
+
+	if (! kg_save_name((gss_name_t) outprinc)) {
+		krb5_free_principal(context, outprinc);
+		krb5_free_context(context);
+		*minor_status = (OM_uint32) G_VALIDATE_FAILED;
+		return(GSS_S_FAILURE);
+	}
+	
+	krb5_free_context(context);
+	*dest_name = (gss_name_t) outprinc;
+	return(GSS_S_COMPLETE);
+	
+}
+
+
+
+
+
+
diff --git a/mechglue/src/lib/gssapi/krb5/export_name.c b/mechglue/src/lib/gssapi/krb5/export_name.c
new file mode 100644
index 000000000..7605d4342
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/export_name.c
@@ -0,0 +1,96 @@
+/*
+ * lib/gssapi/krb5/export_name.c
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 krb5_gss_export_name(OM_uint32  *minor_status,
+			       const gss_name_t input_name,
+			       gss_buffer_t exported_name)
+{
+	krb5_context context;
+	krb5_error_code code;
+	size_t length;
+	char *str, *cp;
+
+	if (minor_status)
+		*minor_status = 0;
+
+	code = krb5_init_context(&context);
+	if (code) {
+	    if (minor_status)
+		*minor_status = code;
+	    return GSS_S_FAILURE;
+	}
+
+	exported_name->length = 0;
+	exported_name->value = NULL;
+	
+	if (! kg_validate_name(input_name)) {
+		if (minor_status)
+			*minor_status = (OM_uint32) G_VALIDATE_FAILED;
+		krb5_free_context(context);
+		return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+	}
+
+	if ((code = krb5_unparse_name(context, (krb5_principal) input_name, 
+				      &str))) {
+		if (minor_status)
+			*minor_status = code;
+		krb5_free_context(context);
+		return(GSS_S_FAILURE);
+	}
+
+	krb5_free_context(context);
+	length = strlen(str);
+	exported_name->length = 10 + length + gss_mech_krb5->length;
+	exported_name->value = malloc(exported_name->length);
+	if (!exported_name->value) {
+		free(str);
+		if (minor_status)
+			*minor_status = ENOMEM;
+		return(GSS_S_FAILURE);
+	}
+	cp = exported_name->value;
+
+	/* Note: we assume the OID will be less than 128 bytes... */
+	*cp++ = 0x04; *cp++ = 0x01;
+	*cp++ = (gss_mech_krb5->length+2) >> 8;
+	*cp++ = (gss_mech_krb5->length+2) & 0xFF;
+	*cp++ = 0x06;
+	*cp++ = (gss_mech_krb5->length) & 0xFF;
+	memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length);
+	cp += gss_mech_krb5->length;
+	*cp++ = length >> 24;
+	*cp++ = length >> 16;
+	*cp++ = length >> 8;
+	*cp++ = length & 0xFF;
+	memcpy(cp, str, length);
+
+	free(str);
+
+	return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/export_sec_context.c b/mechglue/src/lib/gssapi/krb5/export_sec_context.c
new file mode 100644
index 000000000..fb57b882a
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/export_sec_context.c
@@ -0,0 +1,102 @@
+/*
+ * lib/gssapi/krb5/export_sec_context.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * export_sec_context.c	- Externalize the security context.
+ */
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_export_sec_context(minor_status, context_handle, interprocess_token)
+    OM_uint32		*minor_status;
+    gss_ctx_id_t	*context_handle;
+    gss_buffer_t	interprocess_token;
+{
+    krb5_context	context;
+    krb5_error_code	kret;
+    OM_uint32		retval;
+    size_t		bufsize, blen;
+    krb5_gss_ctx_id_t	ctx;
+    krb5_octet		*obuffer, *obp;
+
+    /* Assume a tragic failure */
+    obuffer = (krb5_octet *) NULL;
+    retval = GSS_S_FAILURE;
+    *minor_status = 0;
+
+    if (!kg_validate_ctx_id(*context_handle)) {
+	    kret = (OM_uint32) G_VALIDATE_FAILED;
+	    retval = GSS_S_NO_CONTEXT;
+	    goto error_out;
+    }
+
+    ctx = (krb5_gss_ctx_id_t) *context_handle;
+    context = ctx->k5_context;
+    kret = krb5_gss_ser_init(context);
+    if (kret)
+	goto error_out;
+
+    /* Determine size needed for externalization of context */
+    bufsize = 0;
+    if ((kret = kg_ctx_size(context, (krb5_pointer) ctx,
+			    &bufsize)))
+	    goto error_out;
+
+    /* Allocate the buffer */
+    if ((obuffer = (krb5_octet *) xmalloc(bufsize)) == NULL) {
+	    kret = ENOMEM;
+	    goto error_out;
+    }
+
+    obp = obuffer;
+    blen = bufsize;
+    /* Externalize the context */
+    if ((kret = kg_ctx_externalize(context,
+				   (krb5_pointer) ctx, &obp, &blen)))
+	    goto error_out;
+
+    /* Success!  Return the buffer */
+    interprocess_token->length = bufsize - blen;
+    interprocess_token->value = obuffer;
+    *minor_status = 0;
+    retval = GSS_S_COMPLETE;
+
+    /* Now, clean up the context state */
+    (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+    *context_handle = GSS_C_NO_CONTEXT;
+
+    return (GSS_S_COMPLETE);
+
+error_out:
+    if (obuffer && bufsize) {
+	    memset(obuffer, 0, bufsize);
+	    xfree(obuffer);
+    }
+    if (*minor_status == 0) 
+	    *minor_status = (OM_uint32) kret;
+    return(retval);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/get_tkt_flags.c b/mechglue/src/lib/gssapi/krb5/get_tkt_flags.c
new file mode 100644
index 000000000..19841a086
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/get_tkt_flags.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32 KRB5_CALLCONV 
+gss_krb5int_get_tkt_flags(minor_status, context_handle, ticket_flags)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     krb5_flags *ticket_flags;
+{
+   krb5_gss_ctx_id_rec *ctx;
+
+   /* validate the context handle */
+   if (! kg_validate_ctx_id(context_handle)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+   if (! ctx->established) {
+      *minor_status = KG_CTX_INCOMPLETE;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   if (ticket_flags)
+      *ticket_flags = ctx->krb_flags;
+
+   *minor_status = 0;
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/gssapiP_krb5.h b/mechglue/src/lib/gssapi/krb5/gssapiP_krb5.h
new file mode 100644
index 000000000..c942c1868
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -0,0 +1,664 @@
+/*
+ * Copyright 2000 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GSSAPIP_KRB5_H_
+#define _GSSAPIP_KRB5_H_
+
+#include <k5-int.h>
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* work around sunos braindamage */
+#ifdef major
+#undef major
+#endif
+#ifdef minor
+#undef minor
+#endif
+
+#include "gssapiP_generic.h"
+
+/* The include of gssapi_krb5.h will dtrt with the above #defines in
+ * effect.
+ */
+#include "gssapi_krb5.h"
+#include "gssapi_err_krb5.h"
+
+/* for debugging */
+#undef CFX_EXERCISE
+
+/** constants **/
+
+#define GSS_MECH_KRB5_OID_LENGTH 9
+#define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002"
+
+#define CKSUMTYPE_KG_CB		0x8003
+
+#define KG_TOK_CTX_AP_REQ	0x0100
+#define KG_TOK_CTX_AP_REP	0x0200
+#define KG_TOK_CTX_ERROR	0x0300
+#define KG_TOK_SIGN_MSG		0x0101
+#define KG_TOK_SEAL_MSG		0x0201
+#define	KG_TOK_MIC_MSG		0x0101
+#define	KG_TOK_WRAP_MSG		0x0201
+#define KG_TOK_DEL_CTX		0x0102
+
+#define KG2_TOK_INITIAL		0x0101
+#define KG2_TOK_RESPONSE	0x0202
+#define KG2_TOK_MIC		0x0303
+#define KG2_TOK_WRAP_INTEG	0x0404
+#define KG2_TOK_WRAP_PRIV	0x0505
+
+#define KRB5_GSS_FOR_CREDS_OPTION 1
+
+#define KG2_RESP_FLAG_ERROR		0x0001
+#define KG2_RESP_FLAG_DELEG_OK		0x0002
+
+/* These are to be stored in little-endian order, i.e., des-mac is
+   stored as 02 00.  */
+enum sgn_alg {
+  SGN_ALG_DES_MAC_MD5           = 0x0000,
+  SGN_ALG_MD2_5                 = 0x0001,
+  SGN_ALG_DES_MAC               = 0x0002,
+  SGN_ALG_3			= 0x0003, /* not published */
+  SGN_ALG_HMAC_MD5              = 0x0011, /* microsoft w2k;  */
+  SGN_ALG_HMAC_SHA1_DES3_KD     = 0x0004
+};
+enum seal_alg {
+  SEAL_ALG_NONE            = 0xffff,
+  SEAL_ALG_DES             = 0x0000,
+  SEAL_ALG_1		   = 0x0001, /* not published */
+  SEAL_ALG_MICROSOFT_RC4   = 0x0010, /* microsoft w2k;  */
+  SEAL_ALG_DES3KD          = 0x0002
+};
+
+/* for 3DES */
+#define KG_USAGE_SEAL 22
+#define KG_USAGE_SIGN 23
+#define KG_USAGE_SEQ  24
+
+/* for draft-ietf-krb-wg-gssapi-cfx-01 */
+#define KG_USAGE_ACCEPTOR_SEAL	22
+#define KG_USAGE_ACCEPTOR_SIGN	23
+#define KG_USAGE_INITIATOR_SEAL	24
+#define KG_USAGE_INITIATOR_SIGN	25
+
+enum qop {
+  GSS_KRB5_INTEG_C_QOP_MD5       = 0x0001, /* *partial* MD5 = "MD2.5" */
+  GSS_KRB5_INTEG_C_QOP_DES_MD5   = 0x0002,
+  GSS_KRB5_INTEG_C_QOP_DES_MAC   = 0x0003,
+  GSS_KRB5_INTEG_C_QOP_HMAC_SHA1 = 0x0004,
+  GSS_KRB5_INTEG_C_QOP_MASK      = 0x00ff,
+  GSS_KRB5_CONF_C_QOP_DES        = 0x0100,
+  GSS_KRB5_CONF_C_QOP_DES3_KD    = 0x0200,
+  GSS_KRB5_CONF_C_QOP_MASK       = 0xff00
+};
+
+/** internal types **/
+
+typedef krb5_principal krb5_gss_name_t;
+
+typedef struct _krb5_gss_cred_id_rec {
+   /* protect against simultaneous accesses */
+   k5_mutex_t lock;
+
+   /* name/type of credential */
+   gss_cred_usage_t usage;
+   krb5_principal princ;	/* this is not interned as a gss_name_t */
+   int prerfc_mech;
+   int rfc_mech;
+
+   /* keytab (accept) data */
+   krb5_keytab keytab;
+   krb5_rcache rcache;
+
+   /* ccache (init) data */
+   krb5_ccache ccache;
+   krb5_timestamp tgt_expire;
+   krb5_enctype *req_enctypes;	/* limit negotiated enctypes to this list */
+} krb5_gss_cred_id_rec, *krb5_gss_cred_id_t; 
+
+typedef struct _krb5_gss_ctx_id_rec {
+   unsigned int initiate : 1;	/* nonzero if initiating, zero if accepting */
+   unsigned int established : 1;
+   unsigned int big_endian : 1;
+   unsigned int have_acceptor_subkey : 1;
+   unsigned int seed_init : 1;	/* XXX tested but never actually set */
+   OM_uint32 gss_flags;
+   unsigned char seed[16];
+   krb5_principal here;
+   krb5_principal there;
+   krb5_keyblock *subkey;
+   int signalg;
+   size_t cksum_size;
+   int sealalg;
+   krb5_keyblock *enc;
+   krb5_keyblock *seq;
+   krb5_timestamp endtime;
+   krb5_flags krb_flags;
+   /* XXX these used to be signed.  the old spec is inspecific, and
+      the new spec specifies unsigned.  I don't believe that the change
+      affects the wire encoding. */
+   gssint_uint64 seq_send;
+   gssint_uint64 seq_recv;
+   void *seqstate;
+   krb5_context k5_context;
+   krb5_auth_context auth_context;
+   gss_OID_desc *mech_used;
+    /* Protocol spec revision
+       0 => RFC 1964 with 3DES and RC4 enhancements
+       1 => draft-ietf-krb-wg-gssapi-cfx-01
+       No others defined so far.  */
+   int proto;
+   krb5_cksumtype cksumtype;	/* for "main" subkey */
+   krb5_keyblock *acceptor_subkey; /* CFX only */
+   krb5_cksumtype acceptor_subkey_cksumtype;
+   int cred_rcache;		/* did we get rcache from creds? */
+} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
+
+extern g_set kg_vdb;
+
+extern k5_mutex_t gssint_krb5_keytab_lock;
+
+/* helper macros */
+
+#define kg_save_name(name)		g_save_name(&kg_vdb,name)
+#define kg_save_cred_id(cred)		g_save_cred_id(&kg_vdb,cred)
+#define kg_save_ctx_id(ctx)		g_save_ctx_id(&kg_vdb,ctx)
+#define kg_save_lucidctx_id(lctx)	g_save_lucidctx_id(&kg_vdb,lctx)
+
+#define kg_validate_name(name)		g_validate_name(&kg_vdb,name)
+#define kg_validate_cred_id(cred)	g_validate_cred_id(&kg_vdb,cred)
+#define kg_validate_ctx_id(ctx)		g_validate_ctx_id(&kg_vdb,ctx)
+#define kg_validate_lucidctx_id(lctx)	g_validate_lucidctx_id(&kg_vdb,lctx)
+
+#define kg_delete_name(name)		g_delete_name(&kg_vdb,name)
+#define kg_delete_cred_id(cred)		g_delete_cred_id(&kg_vdb,cred)
+#define kg_delete_ctx_id(ctx)		g_delete_ctx_id(&kg_vdb,ctx)
+#define kg_delete_lucidctx_id(lctx)	g_delete_lucidctx_id(&kg_vdb,lctx)
+
+/** helper functions **/
+
+OM_uint32 kg_get_defcred 
+	(OM_uint32 *minor_status, 
+		   gss_cred_id_t *cred);
+
+krb5_error_code kg_checksum_channel_bindings
+         (krb5_context context, gss_channel_bindings_t cb,
+					     krb5_checksum *cksum,
+					     int bigend);
+
+krb5_error_code kg_make_seq_num (krb5_context context,
+					   krb5_keyblock *key,
+            int direction, krb5_ui_4 seqnum, unsigned char *cksum,
+				unsigned char *buf);
+
+krb5_error_code kg_get_seq_num (krb5_context context,
+					  krb5_keyblock *key,
+            unsigned char *cksum, unsigned char *buf, int *direction,
+					  krb5_ui_4 *seqnum);
+
+krb5_error_code kg_make_seed (krb5_context context,
+					krb5_keyblock *key,
+					unsigned char *seed);
+
+int kg_confounder_size (krb5_context context, krb5_keyblock *key);
+
+krb5_error_code kg_make_confounder (krb5_context context, 
+	    krb5_keyblock *key, unsigned char *buf);
+
+krb5_error_code kg_encrypt (krb5_context context, 
+				      krb5_keyblock *key, int usage,
+				      krb5_pointer iv,
+				      krb5_const_pointer in,
+				      krb5_pointer out,
+				      unsigned int length);
+krb5_error_code
+kg_arcfour_docrypt (const krb5_keyblock *longterm_key , int ms_usage,
+		    const unsigned char *kd_data, size_t kd_data_len,
+		    const unsigned char *input_buf, size_t input_len,
+		    unsigned char *output_buf);
+
+krb5_error_code kg_decrypt (krb5_context context,
+				      krb5_keyblock *key,  int usage,
+				      krb5_pointer iv,
+				      krb5_const_pointer in,
+				      krb5_pointer out,
+				      unsigned int length);
+
+OM_uint32 kg_seal (OM_uint32 *minor_status,
+		  gss_ctx_id_t context_handle,
+		  int conf_req_flag,
+		  int qop_req,
+		  gss_buffer_t input_message_buffer,
+		  int *conf_state,
+		  gss_buffer_t output_message_buffer,
+		  int toktype);
+
+OM_uint32 kg_unseal (OM_uint32 *minor_status,
+		    gss_ctx_id_t context_handle,
+		    gss_buffer_t input_token_buffer,
+		    gss_buffer_t message_buffer,
+		    int *conf_state,
+		    int *qop_state,
+		    int toktype);
+
+OM_uint32 kg_seal_size (OM_uint32 *minor_status,
+				  gss_ctx_id_t context_handle,
+				  int conf_req_flag,
+				  gss_qop_t qop_req,
+				  OM_uint32 output_size,
+				  OM_uint32 *input_size);
+
+krb5_error_code kg_ctx_size (krb5_context kcontext,
+				       krb5_pointer arg,
+				       size_t *sizep);
+
+krb5_error_code kg_ctx_externalize (krb5_context kcontext,
+					      krb5_pointer arg,
+					      krb5_octet **buffer,
+					      size_t *lenremain);
+
+krb5_error_code kg_ctx_internalize (krb5_context kcontext,
+					      krb5_pointer *argp,
+					      krb5_octet **buffer,
+					      size_t *lenremain);
+
+OM_uint32 kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status);
+
+OM_uint32 kg_get_ccache_name (OM_uint32 *minor_status, 
+                              const char **out_name);
+
+OM_uint32 kg_set_ccache_name (OM_uint32 *minor_status, 
+                              const char *name);
+
+/** declarations of internal name mechanism functions **/
+
+OM_uint32 krb5_gss_acquire_cred
+(OM_uint32*,       /* minor_status */
+            gss_name_t,       /* desired_name */
+            OM_uint32,        /* time_req */
+            gss_OID_set,      /* desired_mechs */
+            gss_cred_usage_t, /* cred_usage */
+            gss_cred_id_t*,   /* output_cred_handle */
+            gss_OID_set*,     /* actual_mechs */
+            OM_uint32*        /* time_rec */
+           );
+
+OM_uint32 krb5_gss_release_cred
+(OM_uint32*,       /* minor_status */
+            gss_cred_id_t*    /* cred_handle */
+           );
+
+OM_uint32 krb5_gss_init_sec_context
+(OM_uint32*,       /* minor_status */
+            gss_cred_id_t,    /* claimant_cred_handle */
+            gss_ctx_id_t*,    /* context_handle */
+            gss_name_t,       /* target_name */
+            gss_OID,          /* mech_type */
+            OM_uint32,        /* req_flags */
+            OM_uint32,        /* time_req */
+            gss_channel_bindings_t,
+                              /* input_chan_bindings */
+            gss_buffer_t,     /* input_token */
+            gss_OID*,         /* actual_mech_type */
+            gss_buffer_t,     /* output_token */
+            OM_uint32*,       /* ret_flags */
+            OM_uint32*        /* time_rec */
+           );
+
+OM_uint32 krb5_gss_accept_sec_context
+(OM_uint32*,       /* minor_status */
+            gss_ctx_id_t*,    /* context_handle */
+            gss_cred_id_t,    /* verifier_cred_handle */
+            gss_buffer_t,     /* input_token_buffer */
+            gss_channel_bindings_t,
+                              /* input_chan_bindings */
+            gss_name_t*,      /* src_name */
+            gss_OID*,         /* mech_type */
+            gss_buffer_t,     /* output_token */
+            OM_uint32*,       /* ret_flags */
+            OM_uint32*,       /* time_rec */
+            gss_cred_id_t*    /* delegated_cred_handle */
+           );
+
+OM_uint32 krb5_gss_process_context_token
+(OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            gss_buffer_t      /* token_buffer */
+           );
+
+OM_uint32 krb5_gss_delete_sec_context
+(OM_uint32*,       /* minor_status */
+            gss_ctx_id_t*,    /* context_handle */
+            gss_buffer_t      /* output_token */
+           );
+
+OM_uint32 krb5_gss_context_time
+(OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            OM_uint32*        /* time_rec */
+           );
+
+OM_uint32 krb5_gss_sign
+(OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            int,              /* qop_req */
+            gss_buffer_t,     /* message_buffer */
+            gss_buffer_t      /* message_token */
+           );
+
+OM_uint32 krb5_gss_verify
+(OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            gss_buffer_t,     /* message_buffer */
+            gss_buffer_t,     /* token_buffer */
+            int*              /* qop_state */
+           );
+
+OM_uint32 krb5_gss_seal
+(OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            int,              /* conf_req_flag */
+            int,              /* qop_req */
+            gss_buffer_t,     /* input_message_buffer */
+            int*,             /* conf_state */
+            gss_buffer_t      /* output_message_buffer */
+           );
+
+OM_uint32 krb5_gss_unseal
+(OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            gss_buffer_t,     /* input_message_buffer */
+            gss_buffer_t,     /* output_message_buffer */
+            int*,             /* conf_state */
+            int*              /* qop_state */
+           );
+
+OM_uint32 krb5_gss_display_status
+(OM_uint32*,       /* minor_status */
+            OM_uint32,        /* status_value */
+            int,              /* status_type */
+            gss_OID,          /* mech_type */
+            OM_uint32*,       /* message_context */
+            gss_buffer_t      /* status_string */
+           );
+
+OM_uint32 krb5_gss_indicate_mechs
+(OM_uint32*,       /* minor_status */
+            gss_OID_set*      /* mech_set */
+           );
+
+OM_uint32 krb5_gss_compare_name
+(OM_uint32*,       /* minor_status */
+            gss_name_t,       /* name1 */
+            gss_name_t,       /* name2 */
+            int*              /* name_equal */
+           );
+
+OM_uint32 krb5_gss_display_name
+(OM_uint32*,      /* minor_status */
+            gss_name_t,      /* input_name */
+            gss_buffer_t,    /* output_name_buffer */
+            gss_OID*         /* output_name_type */
+           );
+
+OM_uint32 krb5_gss_import_name
+(OM_uint32*,       /* minor_status */
+            gss_buffer_t,     /* input_name_buffer */
+            gss_OID,          /* input_name_type */
+            gss_name_t*       /* output_name */
+           );
+
+OM_uint32 krb5_gss_release_name
+(OM_uint32*,       /* minor_status */
+            gss_name_t*       /* input_name */
+           );
+
+OM_uint32 krb5_gss_inquire_cred
+(OM_uint32 *,      /* minor_status */
+            gss_cred_id_t,    /* cred_handle */
+            gss_name_t *,     /* name */
+            OM_uint32 *,      /* lifetime */
+            gss_cred_usage_t*,/* cred_usage */
+            gss_OID_set *     /* mechanisms */
+           );
+
+OM_uint32 krb5_gss_inquire_context
+(OM_uint32*,       /* minor_status */
+	    gss_ctx_id_t,     /* context_handle */
+	    gss_name_t*,      /* initiator_name */
+	    gss_name_t*,      /* acceptor_name */
+	    OM_uint32*,       /* lifetime_rec */
+	    gss_OID*,         /* mech_type */
+	    OM_uint32*,       /* ret_flags */
+	    int*,             /* locally_initiated */
+	    int*              /* open */
+	   );
+
+/* New V2 entry points */
+OM_uint32 krb5_gss_get_mic
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_qop_t,			/* qop_req */
+	    gss_buffer_t,		/* message_buffer */
+	    gss_buffer_t		/* message_token */
+	   );
+
+OM_uint32 krb5_gss_verify_mic
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_buffer_t,		/* message_buffer */
+	    gss_buffer_t,		/* message_token */
+	    gss_qop_t *			/* qop_state */
+	   );
+
+OM_uint32 krb5_gss_wrap
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    int,			/* conf_req_flag */
+	    gss_qop_t,			/* qop_req */
+	    gss_buffer_t,		/* input_message_buffer */
+	    int *,			/* conf_state */
+	    gss_buffer_t		/* output_message_buffer */
+	   );
+
+OM_uint32 krb5_gss_unwrap
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_buffer_t,		/* input_message_buffer */
+	    gss_buffer_t,		/* output_message_buffer */
+	    int *,			/* conf_state */
+	    gss_qop_t *			/* qop_state */
+	   );
+
+OM_uint32 krb5_gss_wrap_size_limit
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    int,			/* conf_req_flag */
+	    gss_qop_t,			/* qop_req */
+	    OM_uint32,			/* req_output_size */
+	    OM_uint32 *			/* max_input_size */
+	   );
+
+OM_uint32 krb5_gss_import_name_object
+(OM_uint32 *,		/* minor_status */
+	    void *,			/* input_name */
+	    gss_OID,			/* input_name_type */
+	    gss_name_t *		/* output_name */
+	   );
+
+OM_uint32 krb5_gss_export_name_object
+(OM_uint32 *,		/* minor_status */
+	    gss_name_t,			/* input_name */
+	    gss_OID,			/* desired_name_type */
+	    void * *			/* output_name */
+	   );
+
+OM_uint32 krb5_gss_add_cred
+(OM_uint32 *,		/* minor_status */
+	    gss_cred_id_t,		/* input_cred_handle */
+	    gss_name_t,			/* desired_name */
+	    gss_OID,			/* desired_mech */
+	    gss_cred_usage_t,		/* cred_usage */
+	    OM_uint32,			/* initiator_time_req */
+	    OM_uint32,			/* acceptor_time_req */
+	    gss_cred_id_t *,		/* output_cred_handle */
+	    gss_OID_set *,		/* actual_mechs */
+	    OM_uint32 *,		/* initiator_time_rec */
+	    OM_uint32 *			/* acceptor_time_rec */
+	   );
+
+OM_uint32 krb5_gss_inquire_cred_by_mech
+(OM_uint32  *,		/* minor_status */
+	    gss_cred_id_t,		/* cred_handle */
+	    gss_OID,			/* mech_type */
+	    gss_name_t *,		/* name */
+	    OM_uint32 *,		/* initiator_lifetime */
+	    OM_uint32 *,		/* acceptor_lifetime */
+	    gss_cred_usage_t * 		/* cred_usage */
+	   );
+
+OM_uint32 krb5_gss_export_sec_context
+(OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t *,		/* context_handle */
+	    gss_buffer_t		/* interprocess_token */
+	    );
+
+OM_uint32 krb5_gss_import_sec_context
+(OM_uint32 *,		/* minor_status */
+	    gss_buffer_t,		/* interprocess_token */
+	    gss_ctx_id_t *		/* context_handle */
+	    );
+
+krb5_error_code krb5_gss_ser_init(krb5_context);
+
+OM_uint32 krb5_gss_release_oid
+(OM_uint32 *,		/* minor_status */
+	    gss_OID *			/* oid */
+	   );
+
+OM_uint32 krb5_gss_inquire_names_for_mech
+(OM_uint32 *,		/* minor_status */
+	    gss_OID,			/* mechanism */
+	    gss_OID_set *		/* name_types */
+	   );
+
+OM_uint32 krb5_gss_canonicalize_name
+(OM_uint32  *,		/* minor_status */
+	    const gss_name_t,		/* input_name */
+	    const gss_OID,		/* mech_type */
+	    gss_name_t *		/* output_name */
+	 );
+	
+OM_uint32 krb5_gss_export_name
+(OM_uint32  *,		/* minor_status */
+	    const gss_name_t,		/* input_name */
+	    gss_buffer_t		/* exported_name */
+	 );
+
+OM_uint32 krb5_gss_duplicate_name
+(OM_uint32  *,		/* minor_status */
+	    const gss_name_t,		/* input_name */
+	    gss_name_t *		/* dest_name */
+	 );
+
+OM_uint32 krb5_gss_validate_cred
+(OM_uint32 *,		/* minor_status */
+	    gss_cred_id_t		/* cred */
+         );
+
+OM_uint32
+krb5_gss_validate_cred_1(OM_uint32 * /* minor_status */,
+			 gss_cred_id_t /* cred_handle */,
+			 krb5_context /* context */);
+
+gss_OID krb5_gss_convert_static_mech_oid(gss_OID oid);
+	
+krb5_error_code gss_krb5int_make_seal_token_v3(krb5_context,
+					       krb5_gss_ctx_id_rec *,
+					       const gss_buffer_desc *,
+					       gss_buffer_t,
+					       int, int);
+
+OM_uint32 gss_krb5int_unseal_token_v3(krb5_context *contextptr,
+				      OM_uint32 *minor_status,
+				      krb5_gss_ctx_id_rec *ctx,
+				      unsigned char *ptr, int bodysize,
+				      gss_buffer_t message_buffer,
+				      int *conf_state, int *qop_state, 
+				      int toktype);
+
+/*
+ * These take unglued krb5-mech-specific contexts.
+ */
+
+OM_uint32 KRB5_CALLCONV gss_krb5int_get_tkt_flags 
+	(OM_uint32 *minor_status,
+		   gss_ctx_id_t context_handle,
+		   krb5_flags *ticket_flags);
+
+OM_uint32 KRB5_CALLCONV gss_krb5int_copy_ccache
+	(OM_uint32 *minor_status,
+		   gss_cred_id_t cred_handle,
+		   krb5_ccache out_ccache);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status, 
+				   gss_cred_id_t cred,
+				   OM_uint32 num_ktypes,
+				   krb5_enctype *ktypes);
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_export_lucid_sec_context(OM_uint32 *minor_status,
+				     gss_ctx_id_t *context_handle,
+				     OM_uint32 version,
+				     void **kctx);
+
+
+#endif /* _GSSAPIP_KRB5_H_ */
diff --git a/mechglue/src/lib/gssapi/krb5/gssapi_err_krb5.et b/mechglue/src/lib/gssapi/krb5/gssapi_err_krb5.et
new file mode 100644
index 000000000..c2a705c84
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/gssapi_err_krb5.et
@@ -0,0 +1,40 @@
+# 
+# Copyright 1993 by OpenVision Technologies, Inc.
+# 
+# Permission to use, copy, modify, distribute, and sell this software
+# and its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appears in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of OpenVision not be used
+# in advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. OpenVision makes no
+# representations about the suitability of this software for any
+# purpose.  It is provided "as is" without express or implied warranty.
+# 
+# OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+# 
+
+error_table k5g
+
+error_code KG_CCACHE_NOMATCH, "Principal in credential cache does not match desired name"
+error_code KG_KEYTAB_NOMATCH, "No principal in keytab matches desired name"
+error_code KG_TGT_MISSING, "Credential cache has no TGT"
+error_code KG_NO_SUBKEY, "Authenticator has no subkey"
+error_code KG_CONTEXT_ESTABLISHED, "Context is already fully established"
+error_code KG_BAD_SIGN_TYPE, "Unknown signature type in token"
+error_code KG_BAD_LENGTH, "Invalid field length in token"
+error_code KG_CTX_INCOMPLETE, "Attempt to use incomplete security context"
+error_code KG_CONTEXT, "Bad magic number for krb5_gss_ctx_id_t"
+error_code KG_CRED, "Bad magic number for krb5_gss_cred_id_t"
+error_code KG_ENC_DESC, "Bad magic number for krb5_gss_enc_desc"
+error_code KG_BAD_SEQ, "Sequence number in token is corrupt"
+error_code KG_EMPTY_CCACHE, "Credential cache is empty"
+error_code KG_NO_CTYPES, "Acceptor and Initiator share no checksum types"
+error_code KG_LUCID_VERSION, "Requested lucid context version not supported"
+end
diff --git a/mechglue/src/lib/gssapi/krb5/gssapi_krb5.c b/mechglue/src/lib/gssapi/krb5/gssapi_krb5.c
new file mode 100644
index 000000000..feb8499b2
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * $Id$
+ */
+
+
+/* For declaration of krb5_ser_context_init */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+/** exported constants defined in gssapi_krb5{,_nx}.h **/
+
+/* these are bogus, but will compile */
+
+/*
+ * The OID of the draft krb5 mechanism, assigned by IETF, is:
+ * 	iso(1) org(3) dod(5) internet(1) security(5)
+ *	kerberosv5(2) = 1.3.5.1.5.2
+ * The OID of the krb5_name type is:
+ * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * 	krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1
+ * The OID of the krb5_principal type is:
+ * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * 	krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2
+ * The OID of the proposed standard krb5 mechanism is:
+ * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * 	krb5(2) = 1.2.840.113554.1.2.2
+ * The OID of the proposed standard krb5 v2 mechanism is:
+ * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * 	krb5v2(3) = 1.2.840.113554.1.2.3
+ *	
+ */
+
+/*
+ * Encoding rules: The first two values are encoded in one byte as 40
+ * * value1 + value2.  Subsequent values are encoded base 128, most
+ * significant digit first, with the high bit (\200) set on all octets
+ * except the last in each value's encoding.
+ */
+
+const gss_OID_desc krb5_gss_oid_array[] = {
+   /* this is the official, rfc-specified OID */
+   {GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID},
+   /* this is the unofficial, wrong OID */
+   {5, "\053\005\001\005\002"},
+   /* this is the v2 assigned OID */
+   {9, "\052\206\110\206\367\022\001\002\003"},
+   /* these two are name type OID's */
+
+    /* 2.1.1. Kerberos Principal Name Form:  (rfc 1964)
+     * This name form shall be represented by the Object Identifier {iso(1)
+     * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+     * krb5(2) krb5_name(1)}.  The recommended symbolic name for this type
+     * is "GSS_KRB5_NT_PRINCIPAL_NAME". */
+   {10, "\052\206\110\206\367\022\001\002\002\001"},
+
+   /* gss_nt_krb5_principal.  Object identifier for a krb5_principal. Do not use. */
+   {10, "\052\206\110\206\367\022\001\002\002\002"},
+   { 0, 0 }
+};
+
+const gss_OID_desc * const gss_mech_krb5              = krb5_gss_oid_array+0;
+const gss_OID_desc * const gss_mech_krb5_old          = krb5_gss_oid_array+1;
+const gss_OID_desc * const gss_nt_krb5_name           = krb5_gss_oid_array+3;
+const gss_OID_desc * const gss_nt_krb5_principal      = krb5_gss_oid_array+4;
+const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME = krb5_gss_oid_array+3;
+
+static const gss_OID_set_desc oidsets[] = {
+   {1, (gss_OID) krb5_gss_oid_array+0},
+   {1, (gss_OID) krb5_gss_oid_array+1},
+   {2, (gss_OID) krb5_gss_oid_array+0},
+   {1, (gss_OID) krb5_gss_oid_array+2},
+   {3, (gss_OID) krb5_gss_oid_array+0},
+};
+
+const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+0;
+const gss_OID_set_desc * const gss_mech_set_krb5_old = oidsets+1;
+const gss_OID_set_desc * const gss_mech_set_krb5_both = oidsets+2;
+
+g_set kg_vdb = G_SET_INIT;
+
+/** default credential support */
+
+/*
+ * init_sec_context() will explicitly re-acquire default credentials,
+ * so handling the expiration/invalidation condition here isn't needed.
+ */
+OM_uint32
+kg_get_defcred(minor_status, cred)
+     OM_uint32 *minor_status;
+     gss_cred_id_t *cred;
+{
+    OM_uint32 major;
+    
+    if ((major = krb5_gss_acquire_cred(minor_status, 
+				      (gss_name_t) NULL, GSS_C_INDEFINITE, 
+				      GSS_C_NULL_OID_SET, GSS_C_INITIATE, 
+				      cred, NULL, NULL)) && GSS_ERROR(major)) {
+      return(major);
+   }
+   *minor_status = 0;
+   return(GSS_S_COMPLETE);
+}
+
+OM_uint32
+kg_sync_ccache_name (krb5_context context, OM_uint32 *minor_status)
+{
+    OM_uint32 err = 0;
+    
+    /* 
+     * Sync up the context ccache name with the GSSAPI ccache name.
+     * If kg_ccache_name is NULL -- normal unless someone has called 
+     * gss_krb5_ccache_name() -- then the system default ccache will 
+     * be picked up and used by resetting the context default ccache.
+     * This is needed for platforms which support multiple ccaches.
+     */
+    
+    if (!err) {
+        /* if NULL, resets the context default ccache */
+        err = krb5_cc_set_default_name(context,
+				       (char *) k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME));
+    }
+    
+    *minor_status = err;
+    return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+OM_uint32
+kg_get_ccache_name (OM_uint32 *minor_status, const char **out_name)
+{
+    const char *name = NULL;
+    OM_uint32 err = 0;
+    char *kg_ccache_name;
+
+    kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
+    
+    if (kg_ccache_name != NULL) {
+	name = strdup(kg_ccache_name);
+	if (name == NULL)
+	    err = errno;
+    } else {
+	krb5_context context = NULL;
+
+	/* Reset the context default ccache (see text above), and then
+	   retrieve it.  */
+	err = krb5_init_context(&context);
+	if (!err)
+	    err = krb5_cc_set_default_name (context, NULL);
+	if (!err) {
+	    name = krb5_cc_default_name(context);
+	    if (name) {
+		name = strdup(name);
+		if (name == NULL)
+		    err = errno;
+	    }
+	}
+	if (context)
+	    krb5_free_context(context);
+    }
+
+    if (!err) {
+        if (out_name) {
+            *out_name = name;
+        }
+    }
+    
+    *minor_status = err;
+    return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+
+OM_uint32
+kg_set_ccache_name (OM_uint32 *minor_status, const char *name)
+{
+    char *new_name = NULL;
+    char *swap = NULL;
+    char *kg_ccache_name;
+    krb5_error_code kerr;
+
+    if (name) {
+	new_name = malloc(strlen(name) + 1);
+	if (new_name == NULL) {
+	    *minor_status = ENOMEM;
+	    return GSS_S_FAILURE;
+	}
+	strcpy(new_name, name);
+    }
+
+    kg_ccache_name = k5_getspecific(K5_KEY_GSS_KRB5_CCACHE_NAME);
+    swap = kg_ccache_name;
+    kg_ccache_name = new_name;
+    new_name = swap;
+    kerr = k5_setspecific(K5_KEY_GSS_KRB5_CCACHE_NAME, kg_ccache_name);
+    if (kerr != 0) {
+	/* Can't store, so free up the storage.  */
+	free(kg_ccache_name);
+	/* ??? free(new_name); */
+	*minor_status = kerr;
+	return GSS_S_FAILURE;
+    }
+
+    free (new_name);
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
diff --git a/mechglue/src/lib/gssapi/krb5/gssapi_krb5.hin b/mechglue/src/lib/gssapi/krb5/gssapi_krb5.hin
new file mode 100644
index 000000000..20002478e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/gssapi_krb5.hin
@@ -0,0 +1,271 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _GSSAPI_KRB5_H_
+#define _GSSAPI_KRB5_H_
+
+#include <gssapi/gssapi.h>
+#include <krb5.h>
+
+/* C++ friendlyness */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Reserved static storage for GSS_oids.  See rfc 1964 for more details. */
+
+/* 2.1.1. Kerberos Principal Name Form: */
+GSS_DLLIMP extern const gss_OID_desc * const GSS_KRB5_NT_PRINCIPAL_NAME;
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5_name(1)}.  The recommended symbolic name for this type
+ * is "GSS_KRB5_NT_PRINCIPAL_NAME". */
+
+/* 2.1.2. Host-Based Service Name Form */
+#define GSS_KRB5_NT_HOSTBASED_SERVICE_NAME GSS_C_NT_HOSTBASED_SERVICE
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}.  The previously recommended symbolic
+ * name for this type is "GSS_KRB5_NT_HOSTBASED_SERVICE_NAME".  The
+ * currently preferred symbolic name for this type is
+ * "GSS_C_NT_HOSTBASED_SERVICE". */
+
+/* 2.2.1. User Name Form */
+#define GSS_KRB5_NT_USER_NAME GSS_C_NT_USER_NAME    
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) user_name(1)}.  The recommended symbolic name for this
+ * type is "GSS_KRB5_NT_USER_NAME". */
+
+/* 2.2.2. Machine UID Form */
+#define GSS_KRB5_NT_MACHINE_UID_NAME GSS_C_NT_MACHINE_UID_NAME
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) machine_uid_name(2)}.  The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_MACHINE_UID_NAME". */
+
+/* 2.2.3. String UID Form */
+#define GSS_KRB5_NT_STRING_UID_NAME GSS_C_NT_STRING_UID_NAME
+/* This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) string_uid_name(3)}.  The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_STRING_UID_NAME". */ 
+
+GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5;
+GSS_DLLIMP extern const gss_OID_desc * const gss_mech_krb5_old;
+GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5;
+GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_old;
+GSS_DLLIMP extern const gss_OID_set_desc * const gss_mech_set_krb5_both;
+
+GSS_DLLIMP extern const gss_OID_desc * const gss_nt_krb5_name;
+GSS_DLLIMP extern const gss_OID_desc * const gss_nt_krb5_principal;
+
+GSS_DLLIMP extern const gss_OID_desc krb5_gss_oid_array[];
+
+#define gss_krb5_nt_general_name	gss_nt_krb5_name
+#define gss_krb5_nt_principal		gss_nt_krb5_principal
+#define gss_krb5_nt_service_name	gss_nt_service_name
+#define gss_krb5_nt_user_name		gss_nt_user_name
+#define gss_krb5_nt_machine_uid_name	gss_nt_machine_uid_name
+#define gss_krb5_nt_string_uid_name	gss_nt_string_uid_name
+
+
+#if defined(_WIN32)
+typedef  unsigned __int64 gss_uint64;
+#else /*windows*/
+#include <inttypes.h>
+typedef  uint64_t gss_uint64;
+#endif
+
+
+typedef struct gss_krb5_lucid_key {
+	OM_uint32	type;		/* key encryption type */
+	OM_uint32	length;		/* length of key data */
+	void *		data;		/* actual key data */
+} gss_krb5_lucid_key_t;
+
+typedef struct gss_krb5_rfc1964_keydata {
+	OM_uint32	sign_alg;	/* signing algorthm */
+	OM_uint32	seal_alg;	/* seal/encrypt algorthm */
+	gss_krb5_lucid_key_t	ctx_key;
+					/* Context key
+					   (Kerberos session key or subkey) */
+} gss_krb5_rfc1964_keydata_t;
+
+typedef struct gss_krb5_cfx_keydata {
+	OM_uint32		have_acceptor_subkey;
+					/* 1 if there is an acceptor_subkey
+					   present, 0 otherwise */
+	gss_krb5_lucid_key_t	ctx_key;
+					/* Context key
+					   (Kerberos session key or subkey) */
+	gss_krb5_lucid_key_t	acceptor_subkey;
+					/* acceptor-asserted subkey or
+					   0's if no acceptor subkey */
+} gss_krb5_cfx_keydata_t;
+
+typedef struct gss_krb5_lucid_context_v1 {
+	OM_uint32	version;	/* Structure version number (1)
+					   MUST be at beginning of struct! */
+	OM_uint32	initiate;	/* Are we the initiator? */
+	OM_uint32	endtime;	/* expiration time of context */
+	gss_uint64	send_seq;	/* sender sequence number */
+	gss_uint64	recv_seq;	/* receive sequence number */
+	OM_uint32	protocol;	/* 0: rfc1964,
+					   1: draft-ietf-krb-wg-gssapi-cfx-07 */
+	/*
+	 * if (protocol == 0) rfc1964_kd should be used
+	 * and cfx_kd contents are invalid and should be zero
+	 * if (protocol == 1) cfx_kd should be used
+	 * and rfc1964_kd contents are invalid and should be zero
+	 */
+	gss_krb5_rfc1964_keydata_t rfc1964_kd;
+	gss_krb5_cfx_keydata_t	   cfx_kd;
+} gss_krb5_lucid_context_v1_t;
+
+/*
+ * Mask for determining the returned structure version.
+ * See example below for usage.
+ */
+typedef struct gss_krb5_lucid_context_version {
+	OM_uint32	version;	/* Structure version number */
+} gss_krb5_lucid_context_version_t;
+
+
+
+
+/* Alias for Heimdal compat. */
+#define gsskrb5_register_acceptor_identity krb5_gss_register_acceptor_identity
+
+OM_uint32 KRB5_CALLCONV krb5_gss_register_acceptor_identity(const char *);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_get_tkt_flags 
+	(OM_uint32 *minor_status,
+		   gss_ctx_id_t context_handle,
+		   krb5_flags *ticket_flags);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_copy_ccache
+	(OM_uint32 *minor_status,
+		   gss_cred_id_t cred_handle,
+		   krb5_ccache out_ccache);
+
+OM_uint32 KRB5_CALLCONV gss_krb5_ccache_name
+	(OM_uint32 *minor_status, const char *name,
+		   const char **out_name);
+
+/*
+ * gss_krb5_set_allowable_enctypes
+ *
+ * This function may be called by a context initiator after calling
+ * gss_acquire_cred(), but before calling gss_init_sec_context(),
+ * to restrict the set of enctypes which will be negotiated during
+ * context establishment to those in the provided array.
+ *
+ * 'cred' must be a valid credential handle obtained via
+ * gss_acquire_cred().  It may not be GSS_C_NO_CREDENTIAL.
+ * gss_acquire_cred() may have been called to get a handle to
+ * the default credential.
+ *
+ * The purpose of this function is to limit the keys that may
+ * be exported via gss_krb5_export_lucid_sec_context(); thus it
+ * should limit the enctypes of all keys that will be needed
+ * after the security context has been established.
+ * (i.e. context establishment may use a session key with a
+ * stronger enctype than in the provided array, however a
+ * subkey must be established within the enctype limits
+ * established by this function.)
+ *
+ */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 
+				gss_cred_id_t cred,
+				OM_uint32 num_ktypes,
+				krb5_enctype *ktypes);
+
+/*
+ * Returns a non-opaque (lucid) version of the internal context
+ * information.  
+ *
+ * Note that context_handle must not be used again by the caller
+ * after this call.  The GSS implementation is free to release any
+ * resources associated with the original context.  It is up to the
+ * GSS implementation whether it returns pointers to existing data,
+ * or copies of the data.  The caller should treat the returned
+ * lucid context as read-only.
+ * 
+ * The caller must call gss_krb5_free_lucid_context() to free
+ * the context and allocated resources when it is finished with it.
+ *
+ * 'version' is an integer indicating the highest version of lucid
+ * context understood by the caller.  The highest version
+ * understood by both the caller and the GSS implementation must
+ * be returned.  The caller can determine which version of the
+ * structure was actually returned by examining the version field
+ * of the returned structure.  gss_krb5_lucid_context_version_t
+ * may be used as a mask to examine the returned structure version.
+ *
+ * If there are no common versions, an error should be returned.
+ * (XXX Need error definition(s))
+ *
+ * For example:
+ *	void *return_ctx;
+ *	gss_krb5_lucid_context_v1_t *ctx;
+ *	OM_uint32 min_stat, maj_stat;
+ *	OM_uint32 vers;
+ *	gss_ctx_id_t *ctx_handle;
+ *
+ *	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
+ *			ctx_handle, 1, &return_ctx);
+ *	// Verify success 
+ *
+ *	vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version;
+ *	switch (vers) {
+ *	case 1:
+ *		ctx = (gss_krb5_lucid_context_v1_t *) return_ctx;
+ *		break;
+ *	default:
+ *		// Error, unknown version returned
+ *		break;
+ *	}
+ *
+ */
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
+				  gss_ctx_id_t *context_handle,
+				  OM_uint32 version,
+				  void **kctx);
+
+/*
+ * Frees the allocated storage associated with an
+ * exported struct gss_krb5_lucid_context.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status,
+				void *kctx);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _GSSAPI_KRB5_H_ */
diff --git a/mechglue/src/lib/gssapi/krb5/import_name.c b/mechglue/src/lib/gssapi/krb5/import_name.c
new file mode 100644
index 000000000..75cad9e2f
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/import_name.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+#ifndef NO_PASSWORD
+#include <pwd.h>
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * errors:
+ * GSS_S_BAD_NAMETYPE	if the type is bogus
+ * GSS_S_BAD_NAME	if the type is good but the name is bogus
+ * GSS_S_FAILURE	if memory allocation fails
+ */
+
+OM_uint32
+krb5_gss_import_name(minor_status, input_name_buffer, 
+		     input_name_type, output_name)
+     OM_uint32 *minor_status;
+     gss_buffer_t input_name_buffer;
+     gss_OID input_name_type;
+     gss_name_t *output_name;
+{
+   krb5_context context;
+   krb5_principal princ;
+   krb5_error_code code;
+   char *stringrep, *tmp, *tmp2, *cp;
+   OM_uint32	length;
+#ifndef NO_PASSWORD
+   struct passwd *pw;
+#endif
+
+   code = krb5_init_context(&context);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   /* set up default returns */
+
+   *output_name = NULL;
+   *minor_status = 0;
+
+   /* Go find the appropriate string rep to pass into parse_name */
+
+   if ((input_name_type != GSS_C_NULL_OID) &&
+       (g_OID_equal(input_name_type, gss_nt_service_name) ||
+	g_OID_equal(input_name_type, gss_nt_service_name_v2))) {
+      char *service, *host;
+
+      if ((tmp =
+	   (char *) xmalloc(input_name_buffer->length + 1)) == NULL) {
+	 *minor_status = ENOMEM;
+	 krb5_free_context(context);
+	 return(GSS_S_FAILURE);
+      }
+
+      memcpy(tmp, input_name_buffer->value, input_name_buffer->length);
+      tmp[input_name_buffer->length] = 0;
+
+      service = tmp;
+      if ((host = strchr(tmp, '@'))) {
+	 *host = '\0';
+	 host++;
+      }
+
+      code = krb5_sname_to_principal(context, host, service, KRB5_NT_SRV_HST,
+				     &princ);
+
+      xfree(tmp);
+   } else if ((input_name_type != GSS_C_NULL_OID) &&
+	      (g_OID_equal(input_name_type, gss_nt_krb5_principal))) {
+      krb5_principal input;
+
+      if (input_name_buffer->length != sizeof(krb5_principal)) {
+	 *minor_status = (OM_uint32) G_WRONG_SIZE;
+	 krb5_free_context(context);
+	 return(GSS_S_BAD_NAME);
+      }
+
+      input = *((krb5_principal *) input_name_buffer->value);
+
+      if ((code = krb5_copy_principal(context, input, &princ))) {
+	 *minor_status = code;
+	 krb5_free_context(context);
+	 return(GSS_S_FAILURE);
+      }
+   } else {
+#ifndef NO_PASSWORD
+      uid_t uid;
+      struct passwd pwx;
+      char pwbuf[BUFSIZ];
+#endif
+
+      stringrep = NULL;
+
+      if ((tmp =
+	   (char *) xmalloc(input_name_buffer->length + 1)) == NULL) {
+	 *minor_status = ENOMEM;
+	 krb5_free_context(context);
+	 return(GSS_S_FAILURE);
+      }
+      tmp2 = 0;
+
+      memcpy(tmp, input_name_buffer->value, input_name_buffer->length);
+      tmp[input_name_buffer->length] = 0;
+
+      if ((input_name_type == GSS_C_NULL_OID) ||
+	  g_OID_equal(input_name_type, gss_nt_krb5_name) ||
+	  g_OID_equal(input_name_type, gss_nt_user_name)) {
+	 stringrep = (char *) tmp;
+#ifndef NO_PASSWORD
+      } else if (g_OID_equal(input_name_type, gss_nt_machine_uid_name)) {
+	 uid = *(uid_t *) input_name_buffer->value;
+      do_getpwuid:
+	 if (k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) == 0)
+	     stringrep = pw->pw_name;
+	 else
+	    *minor_status = (OM_uint32) G_NOUSER;
+      } else if (g_OID_equal(input_name_type, gss_nt_string_uid_name)) {
+	 uid = atoi(tmp);
+	 goto do_getpwuid;
+#endif
+      } else if (g_OID_equal(input_name_type, gss_nt_exported_name)) {
+	 cp = tmp;
+	 if (*cp++ != 0x04)
+		 goto fail_name;
+	 if (*cp++ != 0x01)
+		 goto fail_name;
+	 if (*cp++ != 0x00)
+		 goto fail_name;
+	 length = *cp++;
+	 if (length != gss_mech_krb5->length+2)
+		 goto fail_name;
+	 if (*cp++ != 0x06)
+		 goto fail_name;
+	 length = *cp++;
+	 if (length != gss_mech_krb5->length)
+		 goto fail_name;
+	 if (memcmp(cp, gss_mech_krb5->elements, length) != 0)
+		 goto fail_name;
+	 cp += length;
+	 length = *cp++;
+	 length = (length << 8) | *cp++;
+	 length = (length << 8) | *cp++;
+	 length = (length << 8) | *cp++;
+	 tmp2 = malloc(length+1);
+	 if (tmp2 == NULL) {
+		 xfree(tmp);
+		 *minor_status = ENOMEM;
+		 krb5_free_context(context);
+		 return GSS_S_FAILURE;
+	 }
+	 strncpy(tmp2, cp, length);
+	 tmp2[length] = 0;
+	 
+	 stringrep = tmp2;
+     } else {
+	 xfree(tmp);
+	 krb5_free_context(context);
+	 return(GSS_S_BAD_NAMETYPE);
+      }
+
+      /* at this point, stringrep is set, or if not, *minor_status is. */
+
+      if (stringrep)
+	 code = krb5_parse_name(context, (char *) stringrep, &princ);
+      else {
+      fail_name:
+	 xfree(tmp);
+	 if (tmp2)
+		 xfree(tmp2);
+	 krb5_free_context(context);
+	 return(GSS_S_BAD_NAME);
+      }
+      
+      if (tmp2)
+	      xfree(tmp2);
+      xfree(tmp);
+   }
+
+   /* at this point, a krb5 function has been called to set princ.  code
+      contains the return status */
+
+   if (code) {
+      *minor_status = (OM_uint32) code;
+      krb5_free_context(context);
+      return(GSS_S_BAD_NAME);
+   }
+
+   /* save the name in the validation database */
+
+   if (! kg_save_name((gss_name_t) princ)) {
+      krb5_free_principal(context, princ);
+      krb5_free_context(context);
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_FAILURE);
+   }
+
+   krb5_free_context(context);
+
+   /* return it */
+
+   *output_name = (gss_name_t) princ;
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/import_sec_context.c b/mechglue/src/lib/gssapi/krb5/import_sec_context.c
new file mode 100644
index 000000000..84072f549
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/import_sec_context.c
@@ -0,0 +1,126 @@
+/*
+ * lib/gssapi/krb5/import_sec_context.c
+ *
+ * Copyright 1995,2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * import_sec_context.c	- Internalize the security context.
+ */
+#include "gssapiP_krb5.h"
+/* for serialization initialization functions */
+#include "k5-int.h"
+
+/*
+ * Fix up the OID of the mechanism so that uses the static version of
+ * the OID if possible.
+ */
+gss_OID krb5_gss_convert_static_mech_oid(oid)
+     gss_OID	oid;
+{
+	const gss_OID_desc 	*p;
+	OM_uint32		minor_status;
+	
+	for (p = krb5_gss_oid_array; p->length; p++) {
+		if ((oid->length == p->length) &&
+		    (memcmp(oid->elements, p->elements, p->length) == 0)) {
+			gss_release_oid(&minor_status, &oid);
+			return (gss_OID) p;
+		}
+	}
+	return oid;
+}
+
+krb5_error_code
+krb5_gss_ser_init (krb5_context context)
+{
+    krb5_error_code code;
+    static krb5_error_code (KRB5_CALLCONV *const fns[])(krb5_context) = {
+	krb5_ser_context_init, krb5_ser_auth_context_init,
+	krb5_ser_ccache_init, krb5_ser_rcache_init, krb5_ser_keytab_init,
+    };
+    int i;
+
+    for (i = 0; i < sizeof(fns)/sizeof(fns[0]); i++)
+	if ((code = (fns[i])(context)) != 0)
+	    return code;
+    return 0;
+}
+
+OM_uint32
+krb5_gss_import_sec_context(minor_status, interprocess_token, context_handle)
+    OM_uint32		*minor_status;
+    gss_buffer_t	interprocess_token;
+    gss_ctx_id_t	*context_handle;
+{
+    krb5_context	context;
+    krb5_error_code	kret = 0;
+    size_t		blen;
+    krb5_gss_ctx_id_t	ctx;
+    krb5_octet		*ibp;
+
+    /* This is a bit screwy.  We create a krb5 context because we need
+       one when calling the serialization code.  However, one of the
+       objects we're unpacking is a krb5 context, so when we finish,
+       we can throw this one away.  */
+    kret = krb5_init_context(&context);
+    if (kret) {
+	*minor_status = kret;
+	return GSS_S_FAILURE;
+    }
+    kret = krb5_gss_ser_init(context);
+    if (kret) {
+	krb5_free_context(context);
+	*minor_status = kret;
+	return GSS_S_FAILURE;
+    }
+
+    /* Assume a tragic failure */
+    ctx = (krb5_gss_ctx_id_t) NULL;
+    *minor_status = 0;
+
+    /* Internalize the context */
+    ibp = (krb5_octet *) interprocess_token->value;
+    blen = (size_t) interprocess_token->length;
+    kret = kg_ctx_internalize(context, (krb5_pointer *) &ctx, &ibp, &blen);
+    krb5_free_context(context);
+    if (kret) {
+       *minor_status = (OM_uint32) kret;
+       return(GSS_S_FAILURE);
+    }
+
+    /* intern the context handle */
+    if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
+       (void)krb5_gss_delete_sec_context(minor_status, 
+					 (gss_ctx_id_t *) &ctx, NULL);
+       *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+       return(GSS_S_FAILURE);
+    }
+    ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
+    
+    *context_handle = (gss_ctx_id_t) ctx;
+
+    *minor_status = 0;
+    return (GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/indicate_mechs.c b/mechglue/src/lib/gssapi/krb5/indicate_mechs.c
new file mode 100644
index 000000000..48baf1a0e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/indicate_mechs.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_indicate_mechs(minor_status, mech_set)
+     OM_uint32 *minor_status;
+     gss_OID_set *mech_set;
+{
+   *minor_status = 0;
+
+   if (! g_copy_OID_set(gss_mech_set_krb5_both, mech_set)) {
+         *mech_set     = GSS_C_NO_OID_SET;
+         *minor_status = ENOMEM;
+         return(GSS_S_FAILURE);
+   }
+
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/init_sec_context.c b/mechglue/src/lib/gssapi/krb5/init_sec_context.c
new file mode 100644
index 000000000..4f4055932
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/init_sec_context.c
@@ -0,0 +1,968 @@
+/*
+ * Copyright 2000,2002, 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdlib.h>
+#include <assert.h>
+
+/*
+ * $Id$
+ */
+
+/* XXX This is for debugging only!!!  Should become a real bitfield
+   at some point */
+int krb5_gss_dbg_client_expcreds = 0;
+
+/*
+ * Common code which fetches the correct krb5 credentials from the
+ * ccache.
+ */
+static krb5_error_code get_credentials(context, cred, server, now,
+				       endtime, out_creds)
+    krb5_context context;
+    krb5_gss_cred_id_t cred;
+    krb5_principal server;
+    krb5_timestamp now;
+    krb5_timestamp endtime;
+    krb5_creds **out_creds;
+{
+    krb5_error_code	code;
+    krb5_creds 		in_creds;
+
+    k5_mutex_assert_locked(&cred->lock);
+    memset((char *) &in_creds, 0, sizeof(krb5_creds));
+
+    if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client)))
+	goto cleanup;
+    if ((code = krb5_copy_principal(context, server, &in_creds.server)))
+	goto cleanup;
+    in_creds.times.endtime = endtime;
+
+    in_creds.keyblock.enctype = 0;
+
+    code = krb5_get_credentials(context, 0, cred->ccache,
+				&in_creds, out_creds);
+    if (code)
+	goto cleanup;
+
+    /*
+     * Enforce a stricter limit (without timeskew forgiveness at the
+     * boundaries) because accept_sec_context code is also similarly
+     * non-forgiving.
+     */
+    if (!krb5_gss_dbg_client_expcreds && *out_creds != NULL &&
+	(*out_creds)->times.endtime < now) {
+	code = KRB5KRB_AP_ERR_TKT_EXPIRED;
+	goto cleanup;
+    }
+    
+cleanup:
+    if (in_creds.client)
+	    krb5_free_principal(context, in_creds.client);
+    if (in_creds.server)
+	    krb5_free_principal(context, in_creds.server);
+    return code;
+}
+struct gss_checksum_data {
+    krb5_gss_ctx_id_rec *ctx;
+    krb5_gss_cred_id_t cred;
+    krb5_checksum md5;
+    krb5_data checksum_data;
+};
+
+#ifdef CFX_EXERCISE
+#include "../../krb5/krb/auth_con.h"
+#endif
+static krb5_error_code KRB5_CALLCONV
+make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
+		   void *cksum_data, krb5_data **out)
+{
+    krb5_error_code code;
+    krb5_int32 con_flags;
+    unsigned char *ptr;
+    struct gss_checksum_data *data = cksum_data;
+    krb5_data credmsg;
+    int junk;
+
+    data->checksum_data.data = 0;
+    credmsg.data = 0;
+    /* build the checksum field */
+
+    if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
+	/* first get KRB_CRED message, so we know its length */
+
+	/* clear the time check flag that was set in krb5_auth_con_init() */
+	krb5_auth_con_getflags(context, auth_context, &con_flags);
+	krb5_auth_con_setflags(context, auth_context,
+			       con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
+
+	code = krb5_fwd_tgt_creds(context, auth_context, 0,
+				  data->cred->princ, data->ctx->there,
+				  data->cred->ccache, 1,
+				  &credmsg);
+
+	/* turn KRB5_AUTH_CONTEXT_DO_TIME back on */
+	krb5_auth_con_setflags(context, auth_context, con_flags);
+
+	if (code) {
+	    /* don't fail here; just don't accept/do the delegation
+               request */
+	    data->ctx->gss_flags &= ~GSS_C_DELEG_FLAG;
+
+	    data->checksum_data.length = 24;
+	} else {
+	    if (credmsg.length+28 > KRB5_INT16_MAX) {
+		krb5_free_data_contents(context, &credmsg);
+		return(KRB5KRB_ERR_FIELD_TOOLONG);
+	    }
+
+	    data->checksum_data.length = 28+credmsg.length;
+	}
+    } else {
+	data->checksum_data.length = 24;
+    }
+#ifdef CFX_EXERCISE
+    if (data->ctx->auth_context->keyblock != NULL
+	&& data->ctx->auth_context->keyblock->enctype == 18) {
+	srand(time(0) ^ getpid());
+	/* Our ftp client code stupidly assumes a base64-encoded
+	   version of the token will fit in 10K, so don't make this
+	   too big.  */
+	junk = rand() & 0xff;
+    } else
+	junk = 0;
+#else
+    junk = 0;
+#endif
+
+    data->checksum_data.length += junk;
+
+    /* now allocate a buffer to hold the checksum data and
+       (maybe) KRB_CRED msg */
+
+    if ((data->checksum_data.data =
+	 (char *) xmalloc(data->checksum_data.length)) == NULL) {
+	if (credmsg.data)
+	    krb5_free_data_contents(context, &credmsg);
+	return(ENOMEM);
+    }
+
+    ptr = data->checksum_data.data;
+
+    TWRITE_INT(ptr, data->md5.length, 0);
+    TWRITE_STR(ptr, (unsigned char *) data->md5.contents, data->md5.length);
+    TWRITE_INT(ptr, data->ctx->gss_flags, 0);
+
+    /* done with this, free it */
+    xfree(data->md5.contents);
+
+    if (credmsg.data) {
+	TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
+	TWRITE_INT16(ptr, credmsg.length, 0);
+	TWRITE_STR(ptr, (unsigned char *) credmsg.data, credmsg.length);
+
+	/* free credmsg data */
+	krb5_free_data_contents(context, &credmsg);
+    }
+    if (junk)
+	memset(ptr, 'i', junk);
+    *out = &data->checksum_data;
+    return 0;
+}
+    
+static krb5_error_code
+make_ap_req_v1(context, ctx, cred, k_cred, chan_bindings, mech_type, token)
+    krb5_context context;
+    krb5_gss_ctx_id_rec *ctx;
+    krb5_gss_cred_id_t cred;
+    krb5_creds *k_cred;
+    gss_channel_bindings_t chan_bindings;
+    gss_OID mech_type;
+    gss_buffer_t token;
+{
+    krb5_flags mk_req_flags = 0;
+    krb5_error_code code;
+    struct gss_checksum_data cksum_struct;
+    krb5_checksum md5;
+    krb5_data ap_req;
+    krb5_data *checksum_data = NULL;
+    unsigned char *ptr;
+    unsigned char *t;
+    unsigned int tlen;
+
+    k5_mutex_assert_locked(&cred->lock);
+    ap_req.data = 0;
+
+    /* compute the hash of the channel bindings */
+
+    if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5, 0)))
+        return(code);
+
+    krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
+				    CKSUMTYPE_KG_CB);
+    cksum_struct.md5 = md5;
+    cksum_struct.ctx = ctx;
+    cksum_struct.cred = cred;
+    cksum_struct.checksum_data.data = NULL;
+    switch (k_cred->keyblock.enctype) {
+    case ENCTYPE_DES_CBC_CRC:
+    case ENCTYPE_DES_CBC_MD4:
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES3_CBC_SHA1:
+      code = make_gss_checksum(context, ctx->auth_context, &cksum_struct,
+				 &checksum_data);
+	    if (code)
+		goto cleanup;
+	break;
+    default:
+	krb5_auth_con_set_checksum_func(context, ctx->auth_context,
+					make_gss_checksum, &cksum_struct);
+	    break;
+    }
+
+
+    /* call mk_req.  subkey and ap_req need to be used or destroyed */
+
+    mk_req_flags = AP_OPTS_USE_SUBKEY;
+
+    if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
+	mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED;
+
+    code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
+				checksum_data, k_cred, &ap_req);
+    krb5_free_data_contents(context, &cksum_struct.checksum_data);
+    if (code)
+	goto cleanup;
+
+   /* store the interesting stuff from creds and authent */
+   ctx->endtime = k_cred->times.endtime;
+   ctx->krb_flags = k_cred->ticket_flags;
+
+   /* build up the token */
+
+   /* allocate space for the token */
+   tlen = g_token_size((gss_OID) mech_type, ap_req.length);
+
+   if ((t = (unsigned char *) xmalloc(tlen)) == NULL) {
+      code = ENOMEM;
+      goto cleanup;
+   }
+
+   /* fill in the buffer */
+
+   ptr = t;
+
+   g_make_token_header((gss_OID) mech_type, ap_req.length,
+		       &ptr, KG_TOK_CTX_AP_REQ);
+
+   TWRITE_STR(ptr, (unsigned char *) ap_req.data, ap_req.length);
+
+   /* pass it back */
+
+   token->length = tlen;
+   token->value = (void *) t;
+
+   code = 0;
+    
+ cleanup:
+   if (checksum_data && checksum_data->data)
+       krb5_free_data_contents(context, checksum_data);
+   if (ap_req.data)
+       krb5_free_data_contents(context, &ap_req);
+
+   return (code);
+}
+
+/*
+ * setup_enc
+ *
+ * Fill in the encryption descriptors.  Called after AP-REQ is made.
+ */
+static OM_uint32
+setup_enc(
+   OM_uint32 *minor_status,
+   krb5_gss_ctx_id_rec *ctx,
+   krb5_context context)
+{
+   krb5_error_code code;
+   int i;
+   krb5int_access kaccess;
+
+   code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+   if (code)
+       goto fail;
+
+   ctx->have_acceptor_subkey = 0;
+   ctx->proto = 0;
+   ctx->cksumtype = 0;
+   switch(ctx->subkey->enctype) {
+   case ENCTYPE_DES_CBC_MD5:
+   case ENCTYPE_DES_CBC_MD4:
+   case ENCTYPE_DES_CBC_CRC:
+      ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
+      ctx->signalg = SGN_ALG_DES_MAC_MD5;
+      ctx->cksum_size = 8;
+      ctx->sealalg = SEAL_ALG_DES;
+
+      /* The encryption key is the session key XOR
+	 0xf0f0f0f0f0f0f0f0.  */
+      if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc)))
+	 goto fail;
+
+      for (i=0; i<ctx->enc->length; i++)
+	 ctx->enc->contents[i] ^= 0xf0;
+
+      goto copy_subkey_to_seq;
+
+   case ENCTYPE_DES3_CBC_SHA1:
+       /* MIT extension */
+      ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
+      ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
+      ctx->cksum_size = 20;
+      ctx->sealalg = SEAL_ALG_DES3KD;
+
+   copy_subkey:
+      code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc);
+      if (code)
+	 goto fail;
+   copy_subkey_to_seq:
+      code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq);
+      if (code) {
+	 krb5_free_keyblock (context, ctx->enc);
+	 goto fail;
+      }
+      break;
+
+   case ENCTYPE_ARCFOUR_HMAC:
+       /* Microsoft extension */
+      ctx->signalg = SGN_ALG_HMAC_MD5 ;
+      ctx->cksum_size = 8;
+      ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
+
+      goto copy_subkey;
+
+   default:
+       /* Fill some fields we shouldn't be using on this path
+	  with garbage.  */
+       ctx->signalg = -10;
+       ctx->sealalg = -10;
+
+       ctx->proto = 1;
+       code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
+					    &ctx->cksumtype);
+       if (code)
+	   goto fail;
+       code = krb5_c_checksum_length(context, ctx->cksumtype,
+				     &ctx->cksum_size);
+       if (code)
+	   goto fail;
+       goto copy_subkey;
+   }
+fail:
+   *minor_status = code;
+   return GSS_S_FAILURE;
+}
+
+/*
+ * new_connection
+ *
+ * Do the grunt work of setting up a new context.
+ */
+static OM_uint32
+new_connection(
+   OM_uint32 *minor_status,
+   krb5_gss_cred_id_t cred,
+   gss_ctx_id_t *context_handle,
+   gss_name_t target_name,
+   gss_OID mech_type,
+   OM_uint32 req_flags,
+   OM_uint32 time_req,
+   gss_channel_bindings_t input_chan_bindings,
+   gss_buffer_t input_token,
+   gss_OID *actual_mech_type,
+   gss_buffer_t output_token,
+   OM_uint32 *ret_flags,
+   OM_uint32 *time_rec,
+   krb5_context context,
+   int default_mech)
+{
+   OM_uint32 major_status;
+   krb5_error_code code;
+   krb5_creds *k_cred;
+   krb5_gss_ctx_id_rec *ctx, *ctx_free;
+   krb5_timestamp now;
+   gss_buffer_desc token;
+
+   k5_mutex_assert_locked(&cred->lock);
+   major_status = GSS_S_FAILURE;
+   token.length = 0;
+   token.value = NULL;
+
+   /* make sure the cred is usable for init */
+
+   if ((cred->usage != GSS_C_INITIATE) &&
+       (cred->usage != GSS_C_BOTH)) {
+      *minor_status = 0;
+      return(GSS_S_NO_CRED);
+   }
+
+   /* complain if the input token is non-null */
+
+   if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
+       *minor_status = 0;
+       return(GSS_S_DEFECTIVE_TOKEN);
+   }
+
+   /* create the ctx */
+
+   if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
+       == NULL) {
+      *minor_status = ENOMEM;
+      return(GSS_S_FAILURE);
+   }
+
+   /* fill in the ctx */
+   memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+   ctx_free = ctx;
+   if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
+      goto fail;
+   krb5_auth_con_setflags(context, ctx->auth_context,
+			  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+   /* limit the encryption types negotiated (if requested) */
+   if (cred->req_enctypes) {
+	if ((code = krb5_set_default_tgs_enctypes(context,
+						  cred->req_enctypes))) {
+	    goto fail;
+	}
+   }
+
+   ctx->initiate = 1;
+   ctx->gss_flags = (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
+                     GSS_C_TRANS_FLAG | 
+                     ((req_flags) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
+                                     GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
+   ctx->seed_init = 0;
+   ctx->big_endian = 0;  /* all initiators do little-endian, as per spec */
+   ctx->seqstate = 0;
+
+   if ((code = krb5_timeofday(context, &now)))
+      goto fail;
+
+   if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
+      ctx->endtime = 0;
+   } else {
+      ctx->endtime = now + time_req;
+   }
+
+   if ((code = krb5_copy_principal(context, cred->princ, &ctx->here)))
+      goto fail;
+      
+   if ((code = krb5_copy_principal(context, (krb5_principal) target_name,
+				   &ctx->there)))
+      goto fail;
+
+   code = get_credentials(context, cred, ctx->there, now,
+			  ctx->endtime, &k_cred);
+   if (code)
+      goto fail;
+
+   if (default_mech) {
+      mech_type = (gss_OID) gss_mech_krb5;
+   }
+
+   if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used)
+       != GSS_S_COMPLETE) {
+      code = *minor_status;
+      goto fail;
+   }
+   /*
+    * Now try to make it static if at all possible....
+    */
+   ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
+
+   {
+      /* gsskrb5 v1 */
+      krb5_ui_4 seq_temp;
+      if ((code = make_ap_req_v1(context, ctx,
+				 cred, k_cred, input_chan_bindings, 
+				 mech_type, &token))) {
+	 if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
+	     (code == KG_EMPTY_CCACHE))
+	    major_status = GSS_S_NO_CRED;
+	 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
+	    major_status = GSS_S_CREDENTIALS_EXPIRED;
+	 goto fail;
+      }
+
+      krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &seq_temp);
+      ctx->seq_send = seq_temp;
+      krb5_auth_con_getsendsubkey(context, ctx->auth_context,
+				  &ctx->subkey);
+   }
+
+   major_status = setup_enc(minor_status, ctx, context);
+
+   if (k_cred) {
+      krb5_free_creds(context, k_cred);
+      k_cred = 0;
+   }
+      
+   /* at this point, the context is constructed and valid,
+      hence, releaseable */
+
+   /* intern the context handle */
+
+   if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
+      code = G_VALIDATE_FAILED;
+      goto fail;
+   }
+   *context_handle = (gss_ctx_id_t) ctx;
+   ctx_free = 0;
+
+   /* compute time_rec */
+   if (time_rec) {
+      if ((code = krb5_timeofday(context, &now)))
+	 goto fail;
+      *time_rec = ctx->endtime - now;
+   }
+
+   /* set the other returns */
+   *output_token = token;
+
+   if (ret_flags)
+      *ret_flags = ctx->gss_flags;
+
+   if (actual_mech_type)
+      *actual_mech_type = mech_type;
+
+   /* return successfully */
+
+   *minor_status = 0;
+   if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
+      ctx->established = 0;
+      return(GSS_S_CONTINUE_NEEDED);
+   } else {
+      ctx->seq_recv = ctx->seq_send;
+      g_order_init(&(ctx->seqstate), ctx->seq_recv,
+		   (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, 
+		   (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
+      ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
+      ctx->established = 1;
+      return(GSS_S_COMPLETE);
+   }
+
+fail:
+   if (ctx_free) {
+       if (ctx_free->auth_context)
+	   krb5_auth_con_free(context, ctx_free->auth_context);
+       if (ctx_free->here)
+	   krb5_free_principal(context, ctx_free->here);
+       if (ctx_free->there)
+	   krb5_free_principal(context, ctx_free->there);
+       if (ctx_free->subkey)
+	   krb5_free_keyblock(context, ctx_free->subkey);
+       xfree(ctx_free);
+   } else
+	(void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+
+   *minor_status = code;
+   return (major_status);
+}
+
+/*
+ * mutual_auth
+ *
+ * Handle the reply from the acceptor, if we're doing mutual auth.
+ */
+static OM_uint32
+mutual_auth(
+   OM_uint32 *minor_status,
+   gss_ctx_id_t *context_handle,
+   gss_name_t target_name,
+   gss_OID mech_type,
+   OM_uint32 req_flags,
+   OM_uint32 time_req,
+   gss_channel_bindings_t input_chan_bindings,
+   gss_buffer_t input_token,
+   gss_OID *actual_mech_type,
+   gss_buffer_t output_token,
+   OM_uint32 *ret_flags,
+   OM_uint32 *time_rec,
+   krb5_context context)
+{
+   OM_uint32 major_status;
+   unsigned char *ptr;
+   char *sptr;
+   krb5_data ap_rep;
+   krb5_ap_rep_enc_part *ap_rep_data;
+   krb5_timestamp now;
+   krb5_gss_ctx_id_rec *ctx;
+   krb5_error *krb_error;
+   krb5_error_code code;
+   krb5int_access kaccess;
+
+   major_status = GSS_S_FAILURE;
+
+   code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+   if (code)
+       goto fail;
+
+   /* validate the context handle */
+   /*SUPPRESS 29*/
+   if (! kg_validate_ctx_id(*context_handle)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   ctx = (gss_ctx_id_t) *context_handle;
+
+   /* make sure the context is non-established, and that certain
+      arguments are unchanged */
+
+   if ((ctx->established) ||
+       ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
+      code = KG_CONTEXT_ESTABLISHED;
+      goto fail;
+   }
+
+   if (! krb5_principal_compare(context, ctx->there, 
+				(krb5_principal) target_name)) {
+      (void)krb5_gss_delete_sec_context(minor_status, 
+					context_handle, NULL);
+      code = 0;
+      major_status = GSS_S_BAD_NAME;
+      goto fail;
+   }
+
+   /* verify the token and leave the AP_REP message in ap_rep */
+
+   if (input_token == GSS_C_NO_BUFFER) {
+      (void)krb5_gss_delete_sec_context(minor_status, 
+					context_handle, NULL);
+      code = 0;
+      major_status = GSS_S_DEFECTIVE_TOKEN;
+      goto fail;
+   }
+
+   ptr = (unsigned char *) input_token->value;
+
+   if (g_verify_token_header((gss_OID) ctx->mech_used,
+			     &(ap_rep.length),
+			     &ptr, KG_TOK_CTX_AP_REP,
+			     input_token->length, 1)) {
+      if (g_verify_token_header((gss_OID) ctx->mech_used,
+				&(ap_rep.length),
+				&ptr, KG_TOK_CTX_ERROR,
+				input_token->length, 1) == 0) {
+
+	 /* Handle a KRB_ERROR message from the server */
+
+	 sptr = (char *) ptr;           /* PC compiler bug */
+	 TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+		      
+	 code = krb5_rd_error(context, &ap_rep, &krb_error);
+	 if (code)
+	    goto fail;
+	 if (krb_error->error)
+	    code = krb_error->error + ERROR_TABLE_BASE_krb5;
+	 else
+	    code = 0;
+	 krb5_free_error(context, krb_error);
+	 goto fail;
+      } else {
+	 *minor_status = 0;
+	 return(GSS_S_DEFECTIVE_TOKEN);
+      }
+   }
+
+   sptr = (char *) ptr;                      /* PC compiler bug */
+   TREAD_STR(sptr, ap_rep.data, ap_rep.length);
+
+   /* decode the ap_rep */
+   if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
+			   &ap_rep_data))) {
+      /*
+       * XXX A hack for backwards compatiblity.
+       * To be removed in 1999 -- proven 
+       */
+      krb5_auth_con_setuseruserkey(context, ctx->auth_context,
+				   ctx->subkey);
+      if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
+		       &ap_rep_data)))
+	 goto fail;
+   }
+
+   /* store away the sequence number */
+   ctx->seq_recv = ap_rep_data->seq_number;
+   g_order_init(&(ctx->seqstate), ctx->seq_recv,
+		(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
+		(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0, ctx->proto);
+
+   if (ctx->proto == 1 && ap_rep_data->subkey) {
+       /* Keep acceptor's subkey.  */
+       ctx->have_acceptor_subkey = 1;
+       code = krb5_copy_keyblock(context, ap_rep_data->subkey,
+				 &ctx->acceptor_subkey);
+       if (code)
+	   goto fail;
+       code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
+					    ctx->acceptor_subkey->enctype,
+					    &ctx->acceptor_subkey_cksumtype);
+       if (code)
+	   goto fail;
+   }
+
+   /* free the ap_rep_data */
+   krb5_free_ap_rep_enc_part(context, ap_rep_data);
+
+   /* set established */
+   ctx->established = 1;
+
+   /* set returns */
+
+   if (time_rec) {
+      if ((code = krb5_timeofday(context, &now)))
+	 goto fail;
+      *time_rec = ctx->endtime - now;
+   }
+
+   if (ret_flags)
+      *ret_flags = ctx->gss_flags;
+
+   if (actual_mech_type)
+      *actual_mech_type = mech_type;
+
+   /* success */
+
+   *minor_status = 0;
+   return GSS_S_COMPLETE;
+
+fail:
+   (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+
+   *minor_status = code;
+   return (major_status);
+}
+
+OM_uint32
+krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
+			  context_handle, target_name, mech_type,
+			  req_flags, time_req, input_chan_bindings,
+			  input_token, actual_mech_type, output_token,
+			  ret_flags, time_rec)
+    OM_uint32 *minor_status;
+    gss_cred_id_t claimant_cred_handle;
+    gss_ctx_id_t *context_handle;
+    gss_name_t target_name;
+    gss_OID mech_type;
+    OM_uint32 req_flags;
+    OM_uint32 time_req;
+    gss_channel_bindings_t input_chan_bindings;
+    gss_buffer_t input_token;
+    gss_OID *actual_mech_type;
+    gss_buffer_t output_token;
+    OM_uint32 *ret_flags;
+    OM_uint32 *time_rec;
+{
+   krb5_context context;
+   krb5_gss_cred_id_t cred;
+   int err;
+   krb5_error_code kerr;
+   int default_mech = 0;
+   OM_uint32 major_status;
+   OM_uint32 tmp_min_stat;
+
+   if (*context_handle == GSS_C_NO_CONTEXT) {
+       kerr = krb5_init_context(&context);
+       if (kerr) {
+	   *minor_status = kerr;
+	   return GSS_S_FAILURE;
+       }
+       if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
+	   return GSS_S_FAILURE;
+   } else {
+       context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
+   }
+
+   /* set up return values so they can be "freed" successfully */
+
+   major_status = GSS_S_FAILURE; /* Default major code */
+   output_token->length = 0;
+   output_token->value = NULL;
+   if (actual_mech_type)
+      *actual_mech_type = NULL;
+
+   /* verify that the target_name is valid and usable */
+
+   if (! kg_validate_name(target_name)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      if (*context_handle == GSS_C_NO_CONTEXT)
+	  krb5_free_context(context);
+      return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+   }
+
+   /* verify the credential, or use the default */
+   /*SUPPRESS 29*/
+   if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
+      major_status = kg_get_defcred(minor_status, &cred);
+      if (major_status && GSS_ERROR(major_status)) {
+	 if (*context_handle == GSS_C_NO_CONTEXT)
+	    krb5_free_context(context);
+	 return(major_status);
+      }
+   } else {
+      major_status = krb5_gss_validate_cred(minor_status, claimant_cred_handle);
+      if (GSS_ERROR(major_status)) {
+	  if (*context_handle == GSS_C_NO_CONTEXT)
+	      krb5_free_context(context);
+	  return(major_status);
+      }
+      cred = (krb5_gss_cred_id_t) claimant_cred_handle;
+   }
+   kerr = k5_mutex_lock(&cred->lock);
+   if (kerr) {
+       krb5_free_context(context);
+       *minor_status = kerr;
+       return GSS_S_FAILURE;
+   }
+
+   /* verify the mech_type */
+
+   err = 0;
+   if (mech_type == GSS_C_NULL_OID) {
+       default_mech = 1;
+       if (cred->rfc_mech) {
+	   mech_type = (gss_OID) gss_mech_krb5;
+       } else if (cred->prerfc_mech) {
+	   mech_type = (gss_OID) gss_mech_krb5_old;
+       } else {
+	   err = 1;
+       }
+   } else if (g_OID_equal(mech_type, gss_mech_krb5)) {
+       if (!cred->rfc_mech)
+	   err = 1;
+   } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
+       if (!cred->prerfc_mech)
+	   err = 1;
+   } else {
+       err = 1;
+   }
+   
+   if (err) {
+      k5_mutex_unlock(&cred->lock);
+      if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
+	 krb5_gss_release_cred(minor_status, (gss_cred_id_t)&cred);
+      *minor_status = 0;
+      if (*context_handle == GSS_C_NO_CONTEXT)
+	 krb5_free_context(context);
+      return(GSS_S_BAD_MECH);
+   }
+
+   /* is this a new connection or not? */
+
+   /*SUPPRESS 29*/
+   if (*context_handle == GSS_C_NO_CONTEXT) {
+      major_status = new_connection(minor_status, cred, context_handle,
+				    target_name, mech_type, req_flags,
+				    time_req, input_chan_bindings,
+				    input_token, actual_mech_type,
+				    output_token, ret_flags, time_rec,
+				    context, default_mech);
+      k5_mutex_unlock(&cred->lock);
+      if (*context_handle == GSS_C_NO_CONTEXT)
+	  krb5_free_context(context);
+      else
+	  ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context;
+   } else {
+      /* mutual_auth doesn't care about the credentials */
+      k5_mutex_unlock(&cred->lock);
+      major_status = mutual_auth(minor_status, context_handle,
+				 target_name, mech_type, req_flags,
+				 time_req, input_chan_bindings,
+				 input_token, actual_mech_type,
+				 output_token, ret_flags, time_rec,
+				 context);
+      /* If context_handle is now NO_CONTEXT, mutual_auth called
+	 delete_sec_context, which would've zapped the krb5 context
+	 too.  */
+   }
+
+   if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
+      krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t)&cred);
+
+   return(major_status);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/inq_context.c b/mechglue/src/lib/gssapi/krb5/inq_context.c
new file mode 100644
index 000000000..0954ddc5d
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/inq_context.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_inquire_context(minor_status, context_handle, initiator_name, 
+			 acceptor_name, lifetime_rec, mech_type, ret_flags,
+			 locally_initiated, open)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     gss_name_t *initiator_name;
+     gss_name_t *acceptor_name;
+     OM_uint32 *lifetime_rec;
+     gss_OID *mech_type;
+     OM_uint32 *ret_flags;
+     int *locally_initiated;
+     int *open;
+{
+   krb5_context context;
+   krb5_error_code code;
+   krb5_gss_ctx_id_rec *ctx;
+   krb5_principal init, accept;
+   krb5_timestamp now;
+   krb5_deltat lifetime;
+
+   if (initiator_name)
+      *initiator_name = (gss_name_t) NULL;
+   if (acceptor_name)
+      *acceptor_name = (gss_name_t) NULL;
+
+   /* validate the context handle */
+   if (! kg_validate_ctx_id(context_handle)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+   if (! ctx->established) {
+      *minor_status = KG_CTX_INCOMPLETE;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   init = NULL;
+   accept = NULL;
+   context = ctx->k5_context;
+
+   if ((code = krb5_timeofday(context, &now))) {
+      *minor_status = code;
+      return(GSS_S_FAILURE);
+   }
+
+   if ((lifetime = ctx->endtime - now) < 0)
+      lifetime = 0;
+
+   if (initiator_name) {
+      if ((code = krb5_copy_principal(context, 
+				      ctx->initiate?ctx->here:ctx->there,
+				      &init))) {
+	 *minor_status = code;
+	 return(GSS_S_FAILURE);
+      }
+      if (! kg_save_name((gss_name_t) init)) {
+	 krb5_free_principal(context, init);
+	 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	 return(GSS_S_FAILURE);
+      }
+   }
+
+   if (acceptor_name) {
+      if ((code = krb5_copy_principal(context, 
+				      ctx->initiate?ctx->there:ctx->here,
+				      &accept))) {
+	 if (init) krb5_free_principal(context, init);
+	 *minor_status = code;
+	 return(GSS_S_FAILURE);
+      }
+      if (! kg_save_name((gss_name_t) accept)) {
+	 krb5_free_principal(context, accept);
+	 if (init) {
+	    kg_delete_name((gss_name_t) accept);
+	    krb5_free_principal(context, init);
+	 }
+	 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	 return(GSS_S_FAILURE);
+      }
+   }
+
+   if (initiator_name)
+      *initiator_name = (gss_name_t) init;
+
+   if (acceptor_name)
+      *acceptor_name = (gss_name_t) accept;
+
+   if (lifetime_rec)
+      *lifetime_rec = lifetime;
+
+   if (mech_type)
+      *mech_type = (gss_OID) ctx->mech_used;
+
+   if (ret_flags)
+      *ret_flags = ctx->gss_flags;
+
+   if (locally_initiated)
+      *locally_initiated = ctx->initiate;
+
+   if (open)
+      *open = ctx->established;
+
+   *minor_status = 0;
+   return((lifetime == 0)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/inq_cred.c b/mechglue/src/lib/gssapi/krb5/inq_cred.c
new file mode 100644
index 000000000..780e79870
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/inq_cred.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2000 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret,
+		      cred_usage, mechanisms)
+     OM_uint32 *minor_status;
+     gss_cred_id_t cred_handle;
+     gss_name_t *name;
+     OM_uint32 *lifetime_ret;
+     gss_cred_usage_t *cred_usage;
+     gss_OID_set *mechanisms;
+{
+   krb5_context context;
+   krb5_gss_cred_id_t cred;
+   krb5_error_code code;
+   krb5_timestamp now;
+   krb5_deltat lifetime;
+   krb5_principal ret_name;
+   gss_OID_set mechs;
+   OM_uint32 ret;
+
+   ret = GSS_S_FAILURE;
+   ret_name = NULL;
+
+   code = krb5_init_context(&context);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   if (name) *name = NULL;
+   if (mechanisms) *mechanisms = NULL;
+
+   /* check for default credential */
+   /*SUPPRESS 29*/
+   if (cred_handle == GSS_C_NO_CREDENTIAL) {
+      OM_uint32 major;
+
+      if ((major = kg_get_defcred(minor_status, (gss_cred_id_t)&cred)) &&
+	  GSS_ERROR(major)) {
+	 krb5_free_context(context);
+	 return(major);
+      }
+   } else {
+      OM_uint32 major;
+	   
+      major = krb5_gss_validate_cred(minor_status, cred_handle);
+      if (GSS_ERROR(major)) {
+	  krb5_free_context(context);
+	  return(major);
+      }
+      cred = (krb5_gss_cred_id_t) cred_handle;
+   }
+
+   if ((code = krb5_timeofday(context, &now))) {
+      *minor_status = code;
+      ret = GSS_S_FAILURE;
+      goto fail;
+   }
+
+   code = k5_mutex_lock(&cred->lock);
+   if (code != 0) {
+       *minor_status = code;
+       ret = GSS_S_FAILURE;
+       goto fail;
+   }
+   if (cred->tgt_expire > 0) {
+       if ((lifetime = cred->tgt_expire - now) < 0)
+	   lifetime = 0;
+   }
+   else
+       lifetime = GSS_C_INDEFINITE;
+
+   if (name) {
+      if (cred->princ &&
+	  (code = krb5_copy_principal(context, cred->princ, &ret_name))) {
+	 k5_mutex_unlock(&cred->lock);
+	 *minor_status = code;
+	 ret = GSS_S_FAILURE;
+	 goto fail;
+      }
+   }
+
+   if (mechanisms) {
+       if (GSS_ERROR(ret = generic_gss_create_empty_oid_set(minor_status,
+							    &mechs)) ||
+	   (cred->prerfc_mech &&
+	    GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+							   (gss_OID) gss_mech_krb5_old,
+							   &mechs))) ||
+	   (cred->rfc_mech &&
+	    GSS_ERROR(ret = generic_gss_add_oid_set_member(minor_status,
+							   (gss_OID) gss_mech_krb5,
+							   &mechs)))) {
+	   k5_mutex_unlock(&cred->lock);
+	   if (ret_name)
+	       krb5_free_principal(context, ret_name);
+	   /* *minor_status set above */
+	   goto fail;
+       }
+   }
+
+   if (name) {
+      if (ret_name != NULL && ! kg_save_name((gss_name_t) ret_name)) {
+	 k5_mutex_unlock(&cred->lock);
+	 if (cred_handle == GSS_C_NO_CREDENTIAL)
+	     krb5_gss_release_cred(minor_status, (gss_cred_id_t)&cred);
+
+	 (void) gss_release_oid_set(minor_status, &mechs);
+	 krb5_free_principal(context, ret_name);
+	 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	 krb5_free_context(context);
+	 return(GSS_S_FAILURE);
+      }
+      if (ret_name != NULL)
+	  *name = (gss_name_t) ret_name;
+      else
+	  *name = GSS_C_NO_NAME;
+   }
+
+   if (lifetime_ret)
+      *lifetime_ret = lifetime;
+
+   if (cred_usage)
+      *cred_usage = cred->usage;
+   k5_mutex_unlock(&cred->lock);
+
+   if (mechanisms)
+      *mechanisms = mechs;
+
+   if (cred_handle == GSS_C_NO_CREDENTIAL)
+       krb5_gss_release_cred(minor_status, (gss_cred_id_t)&cred);
+
+   krb5_free_context(context);
+   *minor_status = 0;
+   return((lifetime == 0)?GSS_S_CREDENTIALS_EXPIRED:GSS_S_COMPLETE);
+fail:
+   if (cred_handle == GSS_C_NO_CREDENTIAL) {
+       OM_uint32 tmp_min_stat;
+
+       krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t)&cred);
+   }
+   krb5_free_context(context);
+   return ret;
+}
+
+/* V2 interface */
+OM_uint32
+krb5_gss_inquire_cred_by_mech(minor_status, cred_handle,
+			      mech_type, name, initiator_lifetime,
+			      acceptor_lifetime, cred_usage)
+    OM_uint32		*minor_status;
+    gss_cred_id_t	cred_handle;
+    gss_OID		mech_type;
+    gss_name_t		*name;
+    OM_uint32		*initiator_lifetime;
+    OM_uint32		*acceptor_lifetime;
+    gss_cred_usage_t *cred_usage;
+{
+    krb5_gss_cred_id_t	cred;
+    OM_uint32		lifetime;
+    OM_uint32		mstat;
+
+    /*
+     * We only know how to handle our own creds.
+     */
+    if ((mech_type != GSS_C_NULL_OID) &&
+	!g_OID_equal(gss_mech_krb5_old, mech_type) &&
+	!g_OID_equal(gss_mech_krb5, mech_type)) {
+	*minor_status = 0;
+	return(GSS_S_NO_CRED);
+    }
+
+    cred = (krb5_gss_cred_id_t) cred_handle;
+    mstat = krb5_gss_inquire_cred(minor_status,
+				  cred_handle,
+				  name,
+				  &lifetime,
+				  cred_usage,
+				  (gss_OID_set *) NULL);
+    if (mstat == GSS_S_COMPLETE) {
+	if (cred &&
+	    ((cred->usage == GSS_C_INITIATE) ||
+	     (cred->usage == GSS_C_BOTH)) &&
+	    initiator_lifetime)
+	    *initiator_lifetime = lifetime;
+	if (cred &&
+	    ((cred->usage == GSS_C_ACCEPT) ||
+	     (cred->usage == GSS_C_BOTH)) &&
+	    acceptor_lifetime)
+	    *acceptor_lifetime = lifetime;
+    }
+    return(mstat);
+}
+
diff --git a/mechglue/src/lib/gssapi/krb5/inq_names.c b/mechglue/src/lib/gssapi/krb5/inq_names.c
new file mode 100644
index 000000000..430132d74
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/inq_names.c
@@ -0,0 +1,99 @@
+/*
+ * lib/gssapi/krb5/inq_names.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * inq_names.c - Return set of nametypes supported by the KRB5 mechanism.
+ */
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_inquire_names_for_mech(minor_status, mechanism, name_types)
+    OM_uint32	*minor_status;
+    gss_OID	mechanism;
+    gss_OID_set	*name_types;
+{
+    OM_uint32	major, minor;
+
+    /*
+     * We only know how to handle our own mechanism.
+     */
+    if ((mechanism != GSS_C_NULL_OID) &&
+	!g_OID_equal(gss_mech_krb5, mechanism) &&
+	!g_OID_equal(gss_mech_krb5_old, mechanism)) {
+	*minor_status = 0;
+	return(GSS_S_BAD_MECH);
+    }
+
+    /* We're okay.  Create an empty OID set */
+    major = gss_create_empty_oid_set(minor_status, name_types);
+    if (major == GSS_S_COMPLETE) {
+	/* Now add our members. */
+	if (
+	    ((major = gss_add_oid_set_member(minor_status,
+					     (gss_OID) gss_nt_user_name,
+					     name_types)
+	      ) == GSS_S_COMPLETE) &&
+	    ((major = gss_add_oid_set_member(minor_status,
+					     (gss_OID) gss_nt_machine_uid_name,
+					     name_types)
+	      ) == GSS_S_COMPLETE) &&
+	    ((major = gss_add_oid_set_member(minor_status,
+					     (gss_OID) gss_nt_string_uid_name,
+					     name_types)
+	      ) == GSS_S_COMPLETE) &&
+	    ((major = gss_add_oid_set_member(minor_status,
+					     (gss_OID) gss_nt_service_name,
+					     name_types)
+	      ) == GSS_S_COMPLETE) &&
+	    ((major = gss_add_oid_set_member(minor_status,
+					     (gss_OID) gss_nt_service_name_v2,
+					     name_types)
+	      ) == GSS_S_COMPLETE) &&
+	    ((major = gss_add_oid_set_member(minor_status,
+					     (gss_OID) gss_nt_exported_name,
+					     name_types)
+	      ) == GSS_S_COMPLETE) &&
+	    ((major = gss_add_oid_set_member(minor_status,
+					     (gss_OID) gss_nt_krb5_name,
+					     name_types)
+	      ) == GSS_S_COMPLETE)
+	    ) {
+	    major = gss_add_oid_set_member(minor_status,
+					   (gss_OID) gss_nt_krb5_principal,
+					   name_types);
+	}
+
+	/*
+	 * If we choked, then release the set, but don't overwrite the minor
+	 * status with the release call.
+	 */
+	if (major != GSS_S_COMPLETE)
+	    (void) gss_release_oid_set(&minor,
+				       name_types);
+    }
+    return(major);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/k5seal.c b/mechglue/src/lib/gssapi/krb5/k5seal.c
new file mode 100644
index 000000000..30dbcab64
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/k5seal.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+#include <assert.h>
+
+static krb5_error_code
+make_seal_token_v1 (krb5_context context,
+		    krb5_keyblock *enc,
+		    krb5_keyblock *seq,
+		    gssint_uint64 *seqnum,
+		    int direction,
+		    gss_buffer_t text,
+		    gss_buffer_t token,
+		    int signalg,
+		    int cksum_size,
+		    int sealalg,
+		    int encrypt,
+		    int toktype,
+		    int bigend,
+		    gss_OID oid)
+{
+    krb5_error_code code;
+    size_t sumlen;
+    char *data_ptr;
+    krb5_data plaind;
+    krb5_checksum md5cksum;
+    krb5_checksum cksum;
+				/* msglen contains the message length
+				 * we are signing/encrypting.  tmsglen
+				 * contains the length of the message
+				 * we plan to write out to the token.
+				 * tlen is the length of the token
+				 * including header. */
+    unsigned  conflen=0, tmsglen, tlen, msglen;
+    unsigned char *t, *ptr;
+    unsigned char *plain;
+    unsigned char pad;
+    krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+
+    assert((!encrypt) || (toktype == KG_TOK_SEAL_MSG));
+    /* create the token buffer */
+    /* Do we need confounder? */
+    if (encrypt || (!bigend && (toktype == KG_TOK_SEAL_MSG)))
+      conflen = kg_confounder_size(context, enc);
+    else conflen = 0;
+
+    if (toktype == KG_TOK_SEAL_MSG) {
+      switch (sealalg) {
+      case SEAL_ALG_MICROSOFT_RC4:
+	msglen = conflen + text->length+1;
+	pad = 1;
+	break;
+      default:
+	/* XXX knows that des block size is 8 */
+	msglen = (conflen+text->length+8)&(~7);
+	      pad = 8-(text->length%8);
+      }
+      tmsglen = msglen;
+    } else {
+      tmsglen = 0;
+      msglen = text->length;
+      pad = 0;
+    }
+    tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);
+
+    if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
+      return(ENOMEM);
+
+    /*** fill in the token */
+
+    ptr = t;
+    g_make_token_header((gss_OID) oid, 14+cksum_size+tmsglen, &ptr, toktype);
+
+    /* 0..1 SIGN_ALG */
+    ptr[0] = signalg & 0xff;
+    ptr[1] = (signalg >> 8) & 0xff;
+
+    /* 2..3 SEAL_ALG or Filler */
+    if ((toktype == KG_TOK_SEAL_MSG) && encrypt) {
+      ptr[2] = sealalg & 0xff;
+      ptr[3] = (sealalg >> 8) & 0xff;
+    } else {
+      /* No seal */
+      ptr[2] = 0xff;
+      ptr[3] = 0xff;
+    }
+
+    /* 4..5 Filler */
+    ptr[4] = 0xff;
+    ptr[5] = 0xff;
+
+    /* pad the plaintext, encrypt if needed, and stick it in the token */
+
+    /* initialize the the cksum */
+    switch (signalg) {
+    case SGN_ALG_DES_MAC_MD5:
+    case SGN_ALG_MD2_5:
+      md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+      break;
+    case SGN_ALG_HMAC_SHA1_DES3_KD:
+      md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+      break;
+    case SGN_ALG_HMAC_MD5:
+      md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+      if (toktype != KG_TOK_SEAL_MSG)
+	sign_usage = 15;
+      break;
+    default:
+    case SGN_ALG_DES_MAC:
+      abort ();
+    }
+
+    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
+    if (code)
+      return(code);
+    md5cksum.length = sumlen;
+
+
+    if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
+      xfree(t);
+      return(ENOMEM);
+    }
+
+    if (conflen) {
+      if ((code = kg_make_confounder(context, enc, plain))) {
+	xfree(plain);
+	xfree(t);
+	return(code);
+      }
+    }
+
+    memcpy(plain+conflen, text->value, text->length);
+    if (pad) memset(plain+conflen+text->length, pad, pad);
+
+    /* compute the checksum */
+
+    /* 8 = head of token body as specified by mech spec */
+    if (! (data_ptr =
+	   (char *) xmalloc(8 + (bigend ? text->length : msglen)))) {
+      xfree(plain);
+      xfree(t);
+      return(ENOMEM);
+    }
+    (void) memcpy(data_ptr, ptr-2, 8);
+    if (bigend)
+      (void) memcpy(data_ptr+8, text->value, text->length);
+    else
+      (void) memcpy(data_ptr+8, plain, msglen);
+    plaind.length = 8 + (bigend ? text->length : msglen);
+    plaind.data = data_ptr;
+    code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq,
+				sign_usage, &plaind, &md5cksum);
+    xfree(data_ptr);
+
+    if (code) {
+      xfree(plain);
+      xfree(t);
+      return(code);
+    }
+    switch(signalg) {
+    case SGN_ALG_DES_MAC_MD5:
+    case 3:
+
+      if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL,
+			     (g_OID_equal(oid, gss_mech_krb5_old) ?
+			      seq->contents : NULL),
+			     md5cksum.contents, md5cksum.contents, 16))) {
+	krb5_free_checksum_contents(context, &md5cksum);
+	xfree (plain);
+	xfree(t);
+	return code;
+      }
+
+      cksum.length = cksum_size;
+      cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+      memcpy(ptr+14, cksum.contents, cksum.length);
+      break;
+
+    case SGN_ALG_HMAC_SHA1_DES3_KD:
+      /*
+       * Using key derivation, the call to krb5_c_make_checksum
+       * already dealt with encrypting.
+       */
+      if (md5cksum.length != cksum_size)
+	abort ();
+      memcpy (ptr+14, md5cksum.contents, md5cksum.length);
+      break;
+    case SGN_ALG_HMAC_MD5:
+      memcpy (ptr+14, md5cksum.contents, cksum_size);
+      break;
+    }
+
+    krb5_free_checksum_contents(context, &md5cksum);
+
+    /* create the seq_num */
+
+    if ((code = kg_make_seq_num(context, seq, direction?0:0xff, *seqnum,
+				ptr+14, ptr+6))) {
+      xfree (plain);
+      xfree(t);
+      return(code);
+    }
+
+    if (encrypt) {
+      switch(sealalg) {
+      case SEAL_ALG_MICROSOFT_RC4:
+	{
+	  unsigned char bigend_seqnum[4];
+	  krb5_keyblock *enc_key;
+	  int i;
+	  bigend_seqnum[0] = (*seqnum>>24) & 0xff;
+	  bigend_seqnum[1] = (*seqnum>>16) & 0xff;
+	  bigend_seqnum[2] = (*seqnum>>8) & 0xff;
+	  bigend_seqnum[3] = *seqnum & 0xff;
+	  code = krb5_copy_keyblock (context, enc, &enc_key);
+	  if (code)
+	    {
+	      xfree(plain);
+	      xfree(t);
+	      return(code);
+	    }	      
+	  assert (enc_key->length == 16);
+	  for (i = 0; i <= 15; i++)
+	    ((char *) enc_key->contents)[i] ^=0xf0;
+	  code = kg_arcfour_docrypt (enc_key, 0,
+				     bigend_seqnum, 4, 
+				     plain, tmsglen,
+				     ptr+14+cksum_size);
+	  krb5_free_keyblock (context, enc_key);
+	  if (code)
+	    {
+	      xfree(plain);
+	      xfree(t);
+	      return(code);
+	    }
+	}
+	break;
+      default:
+	    if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
+				   (krb5_pointer) plain,
+				   (krb5_pointer) (ptr+cksum_size+14),
+				   tmsglen))) {
+	      xfree(plain);
+	      xfree(t);
+	      return(code);
+	    }
+      }
+    }else {
+      if (tmsglen)
+	memcpy(ptr+14+cksum_size, plain, tmsglen);
+    }
+	    xfree(plain);
+
+
+    /* that's it.  return the token */
+
+    (*seqnum)++;
+    *seqnum &= 0xffffffffL;
+
+    token->length = tlen;
+    token->value = (void *) t;
+
+    return(0);
+}
+
+/* if signonly is true, ignore conf_req, conf_state,
+   and do not encode the ENC_TYPE, MSG_LENGTH, or MSG_TEXT fields */
+
+OM_uint32
+kg_seal(minor_status, context_handle, conf_req_flag, qop_req,
+	input_message_buffer, conf_state, output_message_buffer, toktype)
+    OM_uint32 *minor_status;
+    gss_ctx_id_t context_handle;
+    int conf_req_flag;
+    int qop_req;
+    gss_buffer_t input_message_buffer;
+    int *conf_state;
+    gss_buffer_t output_message_buffer;
+    int toktype;
+{
+    krb5_gss_ctx_id_rec *ctx;
+    krb5_error_code code;
+    krb5_timestamp now;
+    krb5_context context;
+
+    output_message_buffer->length = 0;
+    output_message_buffer->value = NULL;
+
+    /* Only default qop or matching established cryptosystem is allowed.
+
+       There are NO EXTENSIONS to this set for AES and friends!  The
+       new spec says "just use 0".  The old spec plus extensions would
+       actually allow for certain non-zero values.  Fix this to handle
+       them later.  */
+    if (qop_req != 0) {
+	*minor_status = (OM_uint32) G_UNKNOWN_QOP;
+	return GSS_S_FAILURE;
+    }
+
+    /* validate the context handle */
+    if (! kg_validate_ctx_id(context_handle)) {
+	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	return(GSS_S_NO_CONTEXT);
+    }
+
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+    if (! ctx->established) {
+	*minor_status = KG_CTX_INCOMPLETE;
+	return(GSS_S_NO_CONTEXT);
+    }
+
+    context = ctx->k5_context;
+    if ((code = krb5_timeofday(context, &now))) {
+	*minor_status = code;
+	return(GSS_S_FAILURE);
+    }
+
+    switch (ctx->proto)
+    {
+    case 0:
+	code = make_seal_token_v1(context, ctx->enc, ctx->seq,
+				  &ctx->seq_send, ctx->initiate,
+				  input_message_buffer, output_message_buffer,
+				  ctx->signalg, ctx->cksum_size, ctx->sealalg,
+				  conf_req_flag, toktype, ctx->big_endian,
+				  ctx->mech_used);
+	break;
+    case 1:
+	code = gss_krb5int_make_seal_token_v3(context, ctx,
+					      input_message_buffer,
+					      output_message_buffer,
+					      conf_req_flag, toktype);
+	break;
+    default:
+	code = G_UNKNOWN_QOP;	/* XXX */
+	break;
+    }
+
+    if (code) {
+	*minor_status = code;
+	return(GSS_S_FAILURE);
+    }
+
+    if (conf_state)
+	*conf_state = conf_req_flag;
+
+    *minor_status = 0;
+    return((ctx->endtime < now)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/k5sealv3.c b/mechglue/src/lib/gssapi/krb5/k5sealv3.c
new file mode 100644
index 000000000..9fa1bf755
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/k5sealv3.c
@@ -0,0 +1,502 @@
+/*
+ * lib/gssapi/krb5/k5sealv3.c
+ *
+ * Copyright 2003,2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+/* draft-ietf-krb-wg-gssapi-cfx-05 */
+
+#include <assert.h>
+#include "k5-platform.h" 	/* for 64-bit support */
+#include "k5-int.h"		/* for zap() */
+#include "gssapiP_krb5.h"
+#include <stdarg.h>
+
+static int
+rotate_left (void *ptr, size_t bufsiz, size_t rc)
+{
+    /* Optimize for receiving.  After some debugging is done, the MIT
+       implementation won't do any rotates on sending, and while
+       debugging, they'll be randomly chosen.
+
+       Return 1 for success, 0 for failure (ENOMEM).  */
+    void *tbuf;
+
+    if (bufsiz == 0)
+	return 1;
+    rc = rc % bufsiz;
+    if (rc == 0)
+	return 1;
+
+    tbuf = malloc(rc);
+    if (tbuf == 0)
+	return 0;
+    memcpy(tbuf, ptr, rc);
+    memmove(ptr, (char *)ptr + rc, bufsiz - rc);
+    memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
+    free(tbuf);
+    return 1;
+}
+
+static const gss_buffer_desc empty_message = { 0, 0 };
+
+#define FLAG_SENDER_IS_ACCEPTOR	0x01
+#define FLAG_WRAP_CONFIDENTIAL	0x02
+#define FLAG_ACCEPTOR_SUBKEY	0x04
+
+krb5_error_code
+gss_krb5int_make_seal_token_v3 (krb5_context context,
+				krb5_gss_ctx_id_rec *ctx,
+				const gss_buffer_desc * message,
+				gss_buffer_t token,
+				int conf_req_flag, int toktype)
+{
+    size_t bufsize = 16;
+    unsigned char *outbuf = 0;
+    krb5_error_code err;
+    int key_usage;
+    unsigned char acceptor_flag;
+    const gss_buffer_desc *message2 = message;
+    size_t rrc, ec;
+    unsigned short tok_id;
+    krb5_checksum sum;
+    krb5_keyblock *key;
+
+    assert(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
+    assert(ctx->big_endian == 0);
+
+    acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
+    key_usage = (toktype == KG_TOK_WRAP_MSG
+		 ? (ctx->initiate
+		    ? KG_USAGE_INITIATOR_SEAL
+		    : KG_USAGE_ACCEPTOR_SEAL)
+		 : (ctx->initiate
+		    ? KG_USAGE_INITIATOR_SIGN
+		    : KG_USAGE_ACCEPTOR_SIGN));
+    if (ctx->have_acceptor_subkey) {
+	key = ctx->acceptor_subkey;
+    } else {
+	key = ctx->enc;
+    }
+
+#ifdef CFX_EXERCISE
+    {
+	static int initialized = 0;
+	if (!initialized) {
+	    srand(time(0));
+	    initialized = 1;
+	}
+    }
+#endif
+
+    if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
+	krb5_data plain;
+	krb5_enc_data cipher;
+	size_t ec_max;
+
+	/* 300: Adds some slop.  */
+	if (SIZE_MAX - 300 < message->length)
+	    return ENOMEM;
+	ec_max = SIZE_MAX - message->length - 300;
+	if (ec_max > 0xffff)
+	    ec_max = 0xffff;
+#ifdef CFX_EXERCISE
+	/* For testing only.  For performance, always set ec = 0.  */
+	ec = ec_max & rand();
+#else
+	ec = 0;
+#endif
+	plain.length = message->length + 16 + ec;
+	plain.data = malloc(message->length + 16 + ec);
+	if (plain.data == NULL)
+	    return ENOMEM;
+
+	/* Get size of ciphertext.  */
+	bufsize = 16 + krb5_encrypt_size (plain.length, ctx->enc->enctype);
+	/* Allocate space for header plus encrypted data.  */
+	outbuf = malloc(bufsize);
+	if (outbuf == NULL) {
+	    free(plain.data);
+	    return ENOMEM;
+	}
+
+	/* TOK_ID */
+	store_16_be(0x0504, outbuf);
+	/* flags */
+	outbuf[2] = (acceptor_flag
+		     | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
+		     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+	/* filler */
+	outbuf[3] = 0xff;
+	/* EC */
+	store_16_be(ec, outbuf+4);
+	/* RRC */
+	store_16_be(0, outbuf+6);
+	store_64_be(ctx->seq_send, outbuf+8);
+
+	memcpy(plain.data, message->value, message->length);
+	memset(plain.data + message->length, 'x', ec);
+	memcpy(plain.data + message->length + ec, outbuf, 16);
+
+	cipher.ciphertext.data = outbuf + 16;
+	cipher.ciphertext.length = bufsize - 16;
+	cipher.enctype = key->enctype;
+	err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher);
+	zap(plain.data, plain.length);
+	free(plain.data);
+	plain.data = 0;
+	if (err)
+	    goto error;
+
+	/* Now that we know we're returning a valid token....  */
+	ctx->seq_send++;
+
+#ifdef CFX_EXERCISE
+	rrc = rand() & 0xffff;
+	if (rotate_left(outbuf+16, bufsize-16,
+			(bufsize-16) - (rrc % (bufsize - 16))))
+	    store_16_be(rrc, outbuf+6);
+	/* If the rotate fails, don't worry about it.  */
+#endif
+    } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
+	krb5_data plain;
+
+	/* Here, message is the application-supplied data; message2 is
+	   what goes into the output token.  They may be the same, or
+	   message2 may be empty (for MIC).  */
+
+	tok_id = 0x0504;
+
+    wrap_with_checksum:
+	plain.length = message->length + 16;
+	plain.data = malloc(message->length + 16);
+	if (plain.data == NULL)
+	    return ENOMEM;
+
+	if (ctx->cksum_size > 0xffff)
+	    abort();
+
+	bufsize = 16 + message2->length + ctx->cksum_size;
+	outbuf = malloc(bufsize);
+	if (outbuf == NULL) {
+	    free(plain.data);
+	    plain.data = 0;
+	    err = ENOMEM;
+	    goto error;
+	}
+
+	/* TOK_ID */
+	store_16_be(tok_id, outbuf);
+	/* flags */
+	outbuf[2] = (acceptor_flag
+		     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
+	/* filler */
+	outbuf[3] = 0xff;
+	if (toktype == KG_TOK_WRAP_MSG) {
+	    /* Use 0 for checksum calculation, substitute
+	       checksum length later.  */
+	    /* EC */
+	    store_16_be(0, outbuf+4);
+	    /* RRC */
+	    store_16_be(0, outbuf+6);
+	} else {
+	    /* MIC and DEL store 0xFF in EC and RRC.  */
+	    store_16_be(0xffff, outbuf+4);
+	    store_16_be(0xffff, outbuf+6);
+	}
+	store_64_be(ctx->seq_send, outbuf+8);
+
+	memcpy(plain.data, message->value, message->length);
+	memcpy(plain.data + message->length, outbuf, 16);
+
+	/* Fill in the output token -- data contents, if any, and
+	   space for the checksum.  */
+	if (message2->length)
+	    memcpy(outbuf + 16, message2->value, message2->length);
+
+	sum.contents = outbuf + 16 + message2->length;
+	sum.length = ctx->cksum_size;
+
+	err = krb5_c_make_checksum(context, ctx->cksumtype, key,
+				   key_usage, &plain, &sum);
+	zap(plain.data, plain.length);
+	free(plain.data);
+	plain.data = 0;
+	if (err) {
+	    zap(outbuf,bufsize);
+	    free(outbuf);
+	    goto error;
+	}
+	if (sum.length != ctx->cksum_size)
+	    abort();
+	memcpy(outbuf + 16 + message2->length, sum.contents, ctx->cksum_size);
+	krb5_free_checksum_contents(context, &sum);
+	sum.contents = 0;
+	/* Now that we know we're actually generating the token...  */
+	ctx->seq_send++;
+
+	if (toktype == KG_TOK_WRAP_MSG) {
+#ifdef CFX_EXERCISE
+	    rrc = rand() & 0xffff;
+	    /* If the rotate fails, don't worry about it.  */
+	    if (rotate_left(outbuf+16, bufsize-16,
+			    (bufsize-16) - (rrc % (bufsize - 16))))
+		store_16_be(rrc, outbuf+6);
+#endif
+	    /* Fix up EC field.  */
+	    store_16_be(ctx->cksum_size, outbuf+4);
+	} else {
+	    store_16_be(0xffff, outbuf+6);
+	}
+    } else if (toktype == KG_TOK_MIC_MSG) {
+	tok_id = 0x0404;
+	message2 = &empty_message;
+	goto wrap_with_checksum;
+    } else if (toktype == KG_TOK_DEL_CTX) {
+	tok_id = 0x0405;
+	message = message2 = &empty_message;
+	goto wrap_with_checksum;
+    } else
+	abort();
+
+    token->value = outbuf;
+    token->length = bufsize;
+    return 0;
+
+error:
+    free(outbuf);
+    token->value = NULL;
+    token->length = 0;
+    return err;
+}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+   conf_state is only valid if SEAL. */
+
+OM_uint32
+gss_krb5int_unseal_token_v3(krb5_context *contextptr,
+			    OM_uint32 *minor_status,
+			    krb5_gss_ctx_id_rec *ctx,
+			    unsigned char *ptr, int bodysize,
+			    gss_buffer_t message_buffer,
+			    int *conf_state, int *qop_state, int toktype)
+{
+    krb5_context context = *contextptr;
+    krb5_data plain;
+    gssint_uint64 seqnum;
+    size_t ec, rrc;
+    int key_usage;
+    unsigned char acceptor_flag;
+    krb5_checksum sum;
+    krb5_error_code err;
+    krb5_boolean valid;
+    krb5_keyblock *key;
+
+    assert(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
+    assert(ctx->big_endian == 0);
+    assert(ctx->proto == 1);
+
+    if (qop_state)
+	*qop_state = GSS_C_QOP_DEFAULT;
+
+    acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
+    key_usage = (toktype == KG_TOK_WRAP_MSG
+		 ? (!ctx->initiate
+		    ? KG_USAGE_INITIATOR_SEAL
+		    : KG_USAGE_ACCEPTOR_SEAL)
+		 : (!ctx->initiate
+		    ? KG_USAGE_INITIATOR_SIGN
+		    : KG_USAGE_ACCEPTOR_SIGN));
+
+    /* Oops.  I wrote this code assuming ptr would be at the start of
+       the token header.  */
+    ptr -= 2;
+    bodysize += 2;
+
+    if (bodysize < 16) {
+    defective:
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+    if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
+	*minor_status = G_BAD_DIRECTION;
+	return GSS_S_BAD_SIG;
+    }
+
+    /* Two things to note here.
+
+       First, we can't really enforce the use of the acceptor's subkey,
+       if we're the acceptor; the initiator may have sent messages
+       before getting the subkey.  We could probably enforce it if
+       we're the initiator.
+
+       Second, if someone tweaks the code to not set the flag telling
+       the krb5 library to generate a new subkey in the AP-REP
+       message, the MIT library may include a subkey anyways --
+       namely, a copy of the AP-REQ subkey, if it was provided.  So
+       the initiator may think we wanted a subkey, and set the flag,
+       even though we weren't trying to set the subkey.  The "other"
+       key, the one not asserted by the acceptor, will have the same
+       value in that case, though, so we can just ignore the flag.  */
+    if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
+	key = ctx->acceptor_subkey;
+    } else {
+	key = ctx->enc;
+    }
+
+    if (toktype == KG_TOK_WRAP_MSG) {
+	if (load_16_be(ptr) != 0x0504)
+	    goto defective;
+	if (ptr[3] != 0xff)
+	    goto defective;
+	ec = load_16_be(ptr+4);
+	rrc = load_16_be(ptr+6);
+	seqnum = load_64_be(ptr+8);
+	if (!rotate_left(ptr+16, bodysize-16, rrc)) {
+	no_mem:
+	    *minor_status = ENOMEM;
+	    return GSS_S_FAILURE;
+	}
+	if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
+	    /* confidentiality */
+	    krb5_enc_data cipher;
+	    unsigned char *althdr;
+
+	    if (conf_state)
+		*conf_state = 1;
+	    /* Do we have no decrypt_size function?
+
+	       For all current cryptosystems, the ciphertext size will
+	       be larger than the plaintext size.  */
+	    cipher.enctype = key->enctype;
+	    cipher.ciphertext.length = bodysize - 16;
+	    cipher.ciphertext.data = ptr + 16;
+	    plain.length = bodysize - 16;
+	    plain.data = malloc(plain.length);
+	    if (plain.data == NULL)
+		goto no_mem;
+	    err = krb5_c_decrypt(context, key, key_usage, 0,
+				 &cipher, &plain);
+	    if (err) {
+		free(plain.data);
+		goto error;
+	    }
+	    /* Don't use bodysize here!  Use the fact that
+	       cipher.ciphertext.length has been adjusted to the
+	       correct length.  */
+	    althdr = plain.data + plain.length - 16;
+	    if (load_16_be(althdr) != 0x0504
+		|| althdr[2] != ptr[2]
+		|| althdr[3] != ptr[3]
+		|| memcmp(althdr+8, ptr+8, 8))
+		goto defective;
+	    message_buffer->value = plain.data;
+	    message_buffer->length = plain.length - ec - 16;
+	} else {
+	    /* no confidentiality */
+	    if (conf_state)
+		*conf_state = 0;
+	    if (ec + 16 < ec)
+		/* overflow check */
+		goto defective;
+	    if (ec + 16 > bodysize)
+		goto defective;
+	    /* We have: header | msg | cksum.
+	       We need cksum(msg | header).
+	       Rotate the first two.  */
+	    store_16_be(0, ptr+4);
+	    store_16_be(0, ptr+6);
+	    plain.length = bodysize-ec;
+	    plain.data = ptr;
+	    if (!rotate_left(ptr, bodysize-ec, 16))
+		goto no_mem;
+	    sum.length = ec;
+	    if (sum.length != ctx->cksum_size) {
+		*minor_status = 0;
+		return GSS_S_BAD_SIG;
+	    }
+	    sum.contents = ptr+bodysize-ec;
+	    sum.checksum_type = ctx->cksumtype;
+	    err = krb5_c_verify_checksum(context, key, key_usage,
+					 &plain, &sum, &valid);
+	    if (err)
+		goto error;
+	    if (!valid) {
+		*minor_status = 0;
+		return GSS_S_BAD_SIG;
+	    }
+	    message_buffer->length = plain.length - 16;
+	    message_buffer->value = malloc(message_buffer->length);
+	    if (message_buffer->value == NULL)
+		goto no_mem;
+	    memcpy(message_buffer->value, plain.data, message_buffer->length);
+	}
+	err = g_order_check(&ctx->seqstate, seqnum);
+	*minor_status = 0;
+	return err;
+    } else if (toktype == KG_TOK_MIC_MSG) {
+	/* wrap token, no confidentiality */
+	if (load_16_be(ptr) != 0x0404)
+	    goto defective;
+    verify_mic_1:
+	if (ptr[3] != 0xff)
+	    goto defective;
+	if (load_32_be(ptr+4) != 0xffffffffL)
+	    goto defective;
+	seqnum = load_64_be(ptr+8);
+	plain.length = message_buffer->length + 16;
+	plain.data = malloc(plain.length);
+	if (plain.data == NULL)
+	    goto no_mem;
+	if (message_buffer->length)
+	    memcpy(plain.data, message_buffer->value, message_buffer->length);
+	memcpy(plain.data + message_buffer->length, ptr, 16);
+	sum.length = bodysize - 16;
+	sum.contents = ptr + 16;
+	sum.checksum_type = ctx->cksumtype;
+	err = krb5_c_verify_checksum(context, key, key_usage,
+				     &plain, &sum, &valid);
+	free(plain.data);
+	plain.data = NULL;
+	if (err) {
+	error:
+	    *minor_status = err;
+	    return GSS_S_BAD_SIG; /* XXX */
+	}
+	if (!valid) {
+	    *minor_status = 0;
+	    return GSS_S_BAD_SIG;
+	}
+	err = g_order_check(&ctx->seqstate, seqnum);
+	*minor_status = 0;
+	return err;
+    } else if (toktype == KG_TOK_DEL_CTX) {
+	if (load_16_be(ptr) != 0x0405)
+	    goto defective;
+	message_buffer = &empty_message;
+	goto verify_mic_1;
+    } else {
+	goto defective;
+    }
+}
diff --git a/mechglue/src/lib/gssapi/krb5/k5unseal.c b/mechglue/src/lib/gssapi/krb5/k5unseal.c
new file mode 100644
index 000000000..5bb44fd52
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/k5unseal.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <assert.h>
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+   conf_state is only valid if SEAL. */
+
+static OM_uint32
+kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer,
+	     conf_state, qop_state, toktype)
+    krb5_context context;
+    OM_uint32 *minor_status;
+    krb5_gss_ctx_id_rec *ctx;
+    unsigned char *ptr;
+    int bodysize;
+    gss_buffer_t message_buffer;
+    int *conf_state;
+    int *qop_state;
+    int toktype;
+{
+    krb5_error_code code;
+    int conflen = 0;
+    int signalg;
+    int sealalg;
+    gss_buffer_desc token;
+    krb5_checksum cksum;
+    krb5_checksum md5cksum;
+    krb5_data plaind;
+    char *data_ptr;
+    krb5_timestamp now;
+    unsigned char *plain;
+    int cksum_len = 0;
+    int plainlen;
+    int direction;
+    krb5_ui_4 seqnum;
+    OM_uint32 retval;
+    size_t sumlen;
+    krb5_keyusage sign_usage = KG_USAGE_SIGN;
+
+    if (toktype == KG_TOK_SEAL_MSG) {
+	message_buffer->length = 0;
+	message_buffer->value = NULL;
+    }
+
+    /* get the sign and seal algorithms */
+
+    signalg = ptr[0] + (ptr[1]<<8);
+    sealalg = ptr[2] + (ptr[3]<<8);
+
+    /* Sanity checks */
+
+    if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) {
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if ((toktype != KG_TOK_SEAL_MSG) &&
+	(sealalg != 0xffff)) {
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    /* in the current spec, there is only one valid seal algorithm per
+       key type, so a simple comparison is ok */
+
+    if ((toktype == KG_TOK_SEAL_MSG) &&
+	!((sealalg == 0xffff) ||
+	  (sealalg == ctx->sealalg))) {
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    /* there are several mappings of seal algorithms to sign algorithms,
+       but few enough that we can try them all. */
+
+    if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
+	(ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
+	(ctx->sealalg == SEAL_ALG_DES3KD &&
+	 signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
+	(ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
+	signalg != SGN_ALG_HMAC_MD5)) {
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    switch (signalg) {
+    case SGN_ALG_DES_MAC_MD5:
+    case SGN_ALG_MD2_5:
+    case SGN_ALG_HMAC_MD5:
+	cksum_len = 8;
+	if (toktype != KG_TOK_SEAL_MSG)
+	  sign_usage = 15;
+	    break;
+    case SGN_ALG_3:
+	cksum_len = 16;
+	break;
+    case SGN_ALG_HMAC_SHA1_DES3_KD:
+	cksum_len = 20;
+	break;
+    default:
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    /* get the token parameters */
+
+    if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction,
+			       &seqnum))) {
+	*minor_status = code;
+	return(GSS_S_BAD_SIG);
+    }
+
+    /* decode the message, if SEAL */
+
+    if (toktype == KG_TOK_SEAL_MSG) {
+	int tmsglen = bodysize-(14+cksum_len);
+	if (sealalg != 0xffff) {
+	    if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) {
+		*minor_status = ENOMEM;
+		return(GSS_S_FAILURE);
+	    }
+	    if (ctx->enc->enctype == ENCTYPE_ARCFOUR_HMAC) {
+	      unsigned char bigend_seqnum[4];
+	      krb5_keyblock *enc_key;
+	      int i;
+	      bigend_seqnum[0] = (seqnum>>24) & 0xff;
+	      bigend_seqnum[1] = (seqnum>>16) & 0xff;
+	      bigend_seqnum[2] = (seqnum>>8) & 0xff;
+	      bigend_seqnum[3] = seqnum & 0xff;
+	      code = krb5_copy_keyblock (context, ctx->enc, &enc_key);
+	      if (code)
+		{
+		  xfree(plain);
+		  *minor_status = code;
+		  return(GSS_S_FAILURE);
+		}
+
+	      assert (enc_key->length == 16);
+	      for (i = 0; i <= 15; i++)
+		((char *) enc_key->contents)[i] ^=0xf0;
+	      code = kg_arcfour_docrypt (enc_key, 0,
+					 &bigend_seqnum[0], 4, 
+					 ptr+14+cksum_len, tmsglen,
+					 plain);
+	      krb5_free_keyblock (context, enc_key);
+	    } else {
+	      code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL,
+				ptr+14+cksum_len, plain, tmsglen);
+		}
+	    if (code) {
+	      		xfree(plain);
+		*minor_status = code;
+		return(GSS_S_FAILURE);
+	    }
+	} else {
+	    plain = ptr+14+cksum_len;
+	}
+
+	plainlen = tmsglen;
+
+	if ((sealalg == 0xffff) && ctx->big_endian) {
+	    token.length = tmsglen;
+	} else {
+	    conflen = kg_confounder_size(context, ctx->enc);
+	    token.length = tmsglen - conflen - plain[tmsglen-1];
+	}
+
+	if (token.length) {
+	    if ((token.value = (void *) xmalloc(token.length)) == NULL) {
+		if (sealalg != 0xffff)
+		    xfree(plain);
+		*minor_status = ENOMEM;
+		return(GSS_S_FAILURE);
+	    }
+	    memcpy(token.value, plain+conflen, token.length);
+	} else {
+	    token.value = NULL;
+	}
+    } else if (toktype == KG_TOK_SIGN_MSG) {
+	token = *message_buffer;
+	plain = token.value;
+	plainlen = token.length;
+    } else {
+	token.length = 0;
+	token.value = NULL;
+	plain = token.value;
+	plainlen = token.length;
+    }
+
+    /* compute the checksum of the message */
+
+    /* initialize the the cksum */
+    switch (signalg) {
+    case SGN_ALG_DES_MAC_MD5:
+    case SGN_ALG_MD2_5:
+    case SGN_ALG_DES_MAC:
+    case SGN_ALG_3:
+	md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+	break;
+    case SGN_ALG_HMAC_MD5:
+      md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+      break;
+    case SGN_ALG_HMAC_SHA1_DES3_KD:
+	md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
+	break;
+    default:
+	abort ();
+    }
+
+    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
+    if (code)
+	return(code);
+    md5cksum.length = sumlen;
+
+    switch (signalg) {
+    case SGN_ALG_DES_MAC_MD5:
+    case SGN_ALG_3:
+	/* compute the checksum of the message */
+
+	/* 8 = bytes of token body to be checksummed according to spec */
+
+	if (! (data_ptr = (void *)
+	       xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
+	    if (sealalg != 0xffff)
+		xfree(plain);
+	    if (toktype == KG_TOK_SEAL_MSG)
+		xfree(token.value);
+	    *minor_status = ENOMEM;
+	    return(GSS_S_FAILURE);
+	}
+
+	(void) memcpy(data_ptr, ptr-2, 8);
+
+	if (ctx->big_endian)
+	    (void) memcpy(data_ptr+8, token.value, token.length);
+	else
+	    (void) memcpy(data_ptr+8, plain, plainlen);
+
+	plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
+	plaind.data = data_ptr;
+	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
+				    ctx->seq, sign_usage,
+				    &plaind, &md5cksum);
+	xfree(data_ptr);
+
+	if (code) {
+	    if (toktype == KG_TOK_SEAL_MSG)
+		xfree(token.value);
+	    *minor_status = code;
+	    return(GSS_S_FAILURE);
+	}
+
+	if ((code = kg_encrypt(context, ctx->seq, KG_USAGE_SEAL,
+			       (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
+				ctx->seq->contents : NULL),
+			       md5cksum.contents, md5cksum.contents, 16))) {
+	    krb5_free_checksum_contents(context, &md5cksum);
+	    if (toktype == KG_TOK_SEAL_MSG)
+		xfree(token.value);
+	    *minor_status = code;
+	    return GSS_S_FAILURE;
+	}
+
+	if (signalg == 0)
+	    cksum.length = 8;
+	else
+	    cksum.length = 16;
+	cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+	code = memcmp(cksum.contents, ptr+14, cksum.length);
+	break;
+
+    case SGN_ALG_MD2_5:
+	if (!ctx->seed_init &&
+	    (code = kg_make_seed(context, ctx->subkey, ctx->seed))) {
+	    krb5_free_checksum_contents(context, &md5cksum);
+	    if (sealalg != 0xffff)
+		xfree(plain);
+	    if (toktype == KG_TOK_SEAL_MSG)
+		xfree(token.value);
+	    *minor_status = code;
+	    return GSS_S_FAILURE;
+	}
+
+	if (! (data_ptr = (void *)
+	       xmalloc(sizeof(ctx->seed) + 8 +
+		       (ctx->big_endian ? token.length : plainlen)))) {
+	    krb5_free_checksum_contents(context, &md5cksum);
+	    if (sealalg == 0)
+		xfree(plain);
+	    if (toktype == KG_TOK_SEAL_MSG)
+		xfree(token.value);
+	    *minor_status = ENOMEM;
+	    return(GSS_S_FAILURE);
+	}
+	(void) memcpy(data_ptr, ptr-2, 8);
+	(void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed));
+	if (ctx->big_endian)
+	    (void) memcpy(data_ptr+8+sizeof(ctx->seed),
+			  token.value, token.length);
+	else
+	    (void) memcpy(data_ptr+8+sizeof(ctx->seed),
+			  plain, plainlen);
+	plaind.length = 8 + sizeof(ctx->seed) +
+	    (ctx->big_endian ? token.length : plainlen);
+	plaind.data = data_ptr;
+	krb5_free_checksum_contents(context, &md5cksum);
+	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
+				    ctx->seq, sign_usage,
+				    &plaind, &md5cksum);
+	xfree(data_ptr);
+
+	if (code) {
+	    if (sealalg == 0)
+		xfree(plain);
+	    if (toktype == KG_TOK_SEAL_MSG)
+		xfree(token.value);
+	    *minor_status = code;
+	    return(GSS_S_FAILURE);
+	}
+
+	code = memcmp(md5cksum.contents, ptr+14, 8);
+	/* Falls through to defective-token??  */
+
+    default:
+	*minor_status = 0;
+	return(GSS_S_DEFECTIVE_TOKEN);
+
+    case SGN_ALG_HMAC_SHA1_DES3_KD:
+    case SGN_ALG_HMAC_MD5:
+	/* compute the checksum of the message */
+
+	/* 8 = bytes of token body to be checksummed according to spec */
+
+	if (! (data_ptr = (void *)
+	       xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) {
+	    if (sealalg != 0xffff)
+		xfree(plain);
+	    if (toktype == KG_TOK_SEAL_MSG)
+		xfree(token.value);
+	    *minor_status = ENOMEM;
+	    return(GSS_S_FAILURE);
+	}
+
+	(void) memcpy(data_ptr, ptr-2, 8);
+
+	if (ctx->big_endian)
+	    (void) memcpy(data_ptr+8, token.value, token.length);
+	else
+	    (void) memcpy(data_ptr+8, plain, plainlen);
+
+	plaind.length = 8 + (ctx->big_endian ? token.length : plainlen);
+	plaind.data = data_ptr;
+	code = krb5_c_make_checksum(context, md5cksum.checksum_type,
+				    ctx->seq, sign_usage,
+				    &plaind, &md5cksum);
+	xfree(data_ptr);
+
+	if (code) {
+	    if (toktype == KG_TOK_SEAL_MSG)
+		xfree(token.value);
+	    *minor_status = code;
+	    return(GSS_S_FAILURE);
+	}
+
+	code = memcmp(md5cksum.contents, ptr+14, cksum_len);
+	break;
+    }
+
+    krb5_free_checksum_contents(context, &md5cksum);
+    if (sealalg != 0xffff)
+	xfree(plain);
+
+    /* compare the computed checksum against the transmitted checksum */
+
+    if (code) {
+	if (toktype == KG_TOK_SEAL_MSG)
+	    xfree(token.value);
+	*minor_status = 0;
+	return(GSS_S_BAD_SIG);
+    }
+
+
+    /* it got through unscathed.  Make sure the context is unexpired */
+
+    if (toktype == KG_TOK_SEAL_MSG)
+	*message_buffer = token;
+
+    if (conf_state)
+	*conf_state = (sealalg != 0xffff);
+
+    if (qop_state)
+	*qop_state = GSS_C_QOP_DEFAULT;
+
+    if ((code = krb5_timeofday(context, &now))) {
+	*minor_status = code;
+	return(GSS_S_FAILURE);
+    }
+
+    if (now > ctx->endtime) {
+	*minor_status = 0;
+	return(GSS_S_CONTEXT_EXPIRED);
+    }
+
+    /* do sequencing checks */
+
+    if ((ctx->initiate && direction != 0xff) ||
+	(!ctx->initiate && direction != 0)) {
+	if (toktype == KG_TOK_SEAL_MSG)
+	    xfree(token.value);
+	*minor_status = G_BAD_DIRECTION;
+	return(GSS_S_BAD_SIG);
+    }
+
+    retval = g_order_check(&(ctx->seqstate), seqnum);
+
+    /* success or ordering violation */
+
+    *minor_status = 0;
+    return(retval);
+}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+   conf_state is only valid if SEAL. */
+
+OM_uint32
+kg_unseal(minor_status, context_handle, input_token_buffer,
+	  message_buffer, conf_state, qop_state, toktype)
+    OM_uint32 *minor_status;
+    gss_ctx_id_t context_handle;
+    gss_buffer_t input_token_buffer;
+    gss_buffer_t message_buffer;
+    int *conf_state;
+    int *qop_state;
+    int toktype;
+{
+    krb5_gss_ctx_id_rec *ctx;
+    unsigned char *ptr;
+    unsigned int bodysize;
+    int err;
+    int toktype2;
+
+    /* validate the context handle */
+    if (! kg_validate_ctx_id(context_handle)) {
+	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	return(GSS_S_NO_CONTEXT);
+    }
+
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+    if (! ctx->established) {
+	*minor_status = KG_CTX_INCOMPLETE;
+	return(GSS_S_NO_CONTEXT);
+    }
+
+    /* parse the token, leave the data in message_buffer, setting conf_state */
+
+    /* verify the header */
+
+    ptr = (unsigned char *) input_token_buffer->value;
+
+    if (ctx->proto)
+	switch (toktype) {
+	case KG_TOK_SIGN_MSG:
+	    toktype2 = 0x0404;
+	    break;
+	case KG_TOK_SEAL_MSG:
+	    toktype2 = 0x0504;
+	    break;
+	case KG_TOK_DEL_CTX:
+	    toktype2 = 0x0405;
+	    break;
+	default:
+	    toktype2 = toktype;
+	    break;
+	}
+    else
+	toktype2 = toktype;
+    err = g_verify_token_header((gss_OID) ctx->mech_used,
+				&bodysize, &ptr, toktype2,
+				input_token_buffer->length,
+				!ctx->proto);
+    if (err) {
+	*minor_status = err;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (ctx->proto == 0)
+	return kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
+			    message_buffer, conf_state, qop_state,
+			    toktype);
+    else
+	return gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
+					   ptr, bodysize, message_buffer,
+					   conf_state, qop_state, toktype);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/krb5_gss_glue.c b/mechglue/src/lib/gssapi/krb5/krb5_gss_glue.c
new file mode 100644
index 000000000..e4a9618ba
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/krb5_gss_glue.c
@@ -0,0 +1,1057 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "gssapiP_krb5.h"
+#include "mglueP.h"
+
+/** mechglue wrappers **/
+
+static OM_uint32 k5glue_acquire_cred
+(void *, OM_uint32*,       /* minor_status */
+            gss_name_t,       /* desired_name */
+            OM_uint32,        /* time_req */
+            gss_OID_set,      /* desired_mechs */
+            gss_cred_usage_t, /* cred_usage */
+            gss_cred_id_t*,   /* output_cred_handle */
+            gss_OID_set*,     /* actual_mechs */
+            OM_uint32*        /* time_rec */
+           );
+
+static OM_uint32 k5glue_release_cred
+(void *, OM_uint32*,       /* minor_status */
+            gss_cred_id_t*    /* cred_handle */
+           );
+
+static OM_uint32 k5glue_init_sec_context
+(void *, OM_uint32*,       /* minor_status */
+            gss_cred_id_t,    /* claimant_cred_handle */
+            gss_ctx_id_t*,    /* context_handle */
+            gss_name_t,       /* target_name */
+            gss_OID,          /* mech_type */
+            OM_uint32,        /* req_flags */
+            OM_uint32,        /* time_req */
+            gss_channel_bindings_t,
+                              /* input_chan_bindings */
+            gss_buffer_t,     /* input_token */
+            gss_OID*,         /* actual_mech_type */
+            gss_buffer_t,     /* output_token */
+            OM_uint32*,       /* ret_flags */
+            OM_uint32*        /* time_rec */
+           );
+
+static OM_uint32 k5glue_accept_sec_context
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t*,    /* context_handle */
+            gss_cred_id_t,    /* verifier_cred_handle */
+            gss_buffer_t,     /* input_token_buffer */
+            gss_channel_bindings_t,
+                              /* input_chan_bindings */
+            gss_name_t*,      /* src_name */
+            gss_OID*,         /* mech_type */
+            gss_buffer_t,     /* output_token */
+            OM_uint32*,       /* ret_flags */
+            OM_uint32*,       /* time_rec */
+            gss_cred_id_t*    /* delegated_cred_handle */
+           );
+
+static OM_uint32 k5glue_process_context_token
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            gss_buffer_t      /* token_buffer */
+           );
+
+static OM_uint32 k5glue_delete_sec_context
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t*,    /* context_handle */
+            gss_buffer_t      /* output_token */
+           );
+
+static OM_uint32 k5glue_context_time
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            OM_uint32*        /* time_rec */
+           );
+
+static OM_uint32 k5glue_sign
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            int,              /* qop_req */
+            gss_buffer_t,     /* message_buffer */
+            gss_buffer_t      /* message_token */
+           );
+
+static OM_uint32 k5glue_verify
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            gss_buffer_t,     /* message_buffer */
+            gss_buffer_t,     /* token_buffer */
+            int*              /* qop_state */
+           );
+
+static OM_uint32 k5glue_seal
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            int,              /* conf_req_flag */
+            int,              /* qop_req */
+            gss_buffer_t,     /* input_message_buffer */
+            int*,             /* conf_state */
+            gss_buffer_t      /* output_message_buffer */
+           );
+
+static OM_uint32 k5glue_unseal
+(void *, OM_uint32*,       /* minor_status */
+            gss_ctx_id_t,     /* context_handle */
+            gss_buffer_t,     /* input_message_buffer */
+            gss_buffer_t,     /* output_message_buffer */
+            int*,             /* conf_state */
+            int*              /* qop_state */
+           );
+
+static OM_uint32 k5glue_display_status
+(void *, OM_uint32*,       /* minor_status */
+            OM_uint32,        /* status_value */
+            int,              /* status_type */
+            gss_OID,          /* mech_type */
+            OM_uint32*,       /* message_context */
+            gss_buffer_t      /* status_string */
+           );
+
+static OM_uint32 k5glue_indicate_mechs
+(void *, OM_uint32*,       /* minor_status */
+            gss_OID_set*      /* mech_set */
+           );
+
+static OM_uint32 k5glue_compare_name
+(void *, OM_uint32*,       /* minor_status */
+            gss_name_t,       /* name1 */
+            gss_name_t,       /* name2 */
+            int*              /* name_equal */
+           );
+
+static OM_uint32 k5glue_display_name
+(void *, OM_uint32*,      /* minor_status */
+            gss_name_t,      /* input_name */
+            gss_buffer_t,    /* output_name_buffer */
+            gss_OID*         /* output_name_type */
+           );
+
+static OM_uint32 k5glue_import_name
+(void *, OM_uint32*,       /* minor_status */
+            gss_buffer_t,     /* input_name_buffer */
+            gss_OID,          /* input_name_type */
+            gss_name_t*       /* output_name */
+           );
+
+static OM_uint32 k5glue_release_name
+(void *, OM_uint32*,       /* minor_status */
+            gss_name_t*       /* input_name */
+           );
+
+static OM_uint32 k5glue_inquire_cred
+(void *, OM_uint32 *,      /* minor_status */
+            gss_cred_id_t,    /* cred_handle */
+            gss_name_t *,     /* name */
+            OM_uint32 *,      /* lifetime */
+            gss_cred_usage_t*,/* cred_usage */
+            gss_OID_set *     /* mechanisms */
+           );
+
+static OM_uint32 k5glue_inquire_context
+(void *, OM_uint32*,       /* minor_status */
+	    gss_ctx_id_t,     /* context_handle */
+	    gss_name_t*,      /* initiator_name */
+	    gss_name_t*,      /* acceptor_name */
+	    OM_uint32*,       /* lifetime_rec */
+	    gss_OID*,         /* mech_type */
+	    OM_uint32*,       /* ret_flags */
+	    int*,             /* locally_initiated */
+	    int*              /* open */
+	   );
+
+#if 0
+/* New V2 entry points */
+static OM_uint32 k5glue_get_mic
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_qop_t,			/* qop_req */
+	    gss_buffer_t,		/* message_buffer */
+	    gss_buffer_t		/* message_token */
+	   );
+
+static OM_uint32 k5glue_verify_mic
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_buffer_t,		/* message_buffer */
+	    gss_buffer_t,		/* message_token */
+	    gss_qop_t *			/* qop_state */
+	   );
+
+static OM_uint32 k5glue_wrap
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    int,			/* conf_req_flag */
+	    gss_qop_t,			/* qop_req */
+	    gss_buffer_t,		/* input_message_buffer */
+	    int *,			/* conf_state */
+	    gss_buffer_t		/* output_message_buffer */
+	   );
+
+static OM_uint32 k5glue_unwrap
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_buffer_t,		/* input_message_buffer */
+	    gss_buffer_t,		/* output_message_buffer */
+	    int *,			/* conf_state */
+	    gss_qop_t *			/* qop_state */
+	   );
+#endif
+
+static OM_uint32 k5glue_wrap_size_limit
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    int,			/* conf_req_flag */
+	    gss_qop_t,			/* qop_req */
+	    OM_uint32,			/* req_output_size */
+	    OM_uint32 *			/* max_input_size */
+	   );
+
+#if 0
+static OM_uint32 k5glue_import_name_object
+(void *, OM_uint32 *,		/* minor_status */
+	    void *,			/* input_name */
+	    gss_OID,			/* input_name_type */
+	    gss_name_t *		/* output_name */
+	   );
+
+static OM_uint32 k5glue_export_name_object
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_name_t,			/* input_name */
+	    gss_OID,			/* desired_name_type */
+	    void * *			/* output_name */
+	   );
+#endif
+
+static OM_uint32 k5glue_add_cred
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_cred_id_t,		/* input_cred_handle */
+	    gss_name_t,			/* desired_name */
+	    gss_OID,			/* desired_mech */
+	    gss_cred_usage_t,		/* cred_usage */
+	    OM_uint32,			/* initiator_time_req */
+	    OM_uint32,			/* acceptor_time_req */
+	    gss_cred_id_t *,		/* output_cred_handle */
+	    gss_OID_set *,		/* actual_mechs */
+	    OM_uint32 *,		/* initiator_time_rec */
+	    OM_uint32 *			/* acceptor_time_rec */
+	   );
+
+static OM_uint32 k5glue_inquire_cred_by_mech
+(void *, OM_uint32  *,		/* minor_status */
+	    gss_cred_id_t,		/* cred_handle */
+	    gss_OID,			/* mech_type */
+	    gss_name_t *,		/* name */
+	    OM_uint32 *,		/* initiator_lifetime */
+	    OM_uint32 *,		/* acceptor_lifetime */
+	    gss_cred_usage_t * 		/* cred_usage */
+	   );
+
+static OM_uint32 k5glue_export_sec_context
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t *,		/* context_handle */
+	    gss_buffer_t		/* interprocess_token */
+	    );
+
+static OM_uint32 k5glue_import_sec_context
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_buffer_t,		/* interprocess_token */
+	    gss_ctx_id_t *		/* context_handle */
+	    );
+
+krb5_error_code k5glue_ser_init(krb5_context);
+
+static OM_uint32 k5glue_release_oid
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_OID *			/* oid */
+	   );
+
+static OM_uint32 k5glue_inquire_names_for_mech
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_OID,			/* mechanism */
+	    gss_OID_set *		/* name_types */
+	   );
+
+#if 0
+static OM_uint32 k5glue_canonicalize_name
+(void *, OM_uint32  *,		/* minor_status */
+	    const gss_name_t,		/* input_name */
+	    const gss_OID,		/* mech_type */
+	    gss_name_t *		/* output_name */
+	 );
+#endif
+
+static OM_uint32 k5glue_export_name
+(void *, OM_uint32  *,		/* minor_status */
+	    const gss_name_t,		/* input_name */
+	    gss_buffer_t		/* exported_name */
+	 );
+
+#if 0
+static OM_uint32 k5glue_duplicate_name
+(void *, OM_uint32  *,		/* minor_status */
+	    const gss_name_t,		/* input_name */
+	    gss_name_t *		/* dest_name */
+	 );
+#endif
+
+#if 0
+static OM_uint32 k5glue_validate_cred
+(void *, OM_uint32 *,		/* minor_status */
+	    gss_cred_id_t		/* cred */
+         );
+#endif
+
+struct gss_config krb5_mechanism = {
+    { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+    NULL,
+    k5glue_acquire_cred,
+    k5glue_release_cred,
+    k5glue_init_sec_context,
+    k5glue_accept_sec_context,
+    k5glue_process_context_token,
+    k5glue_delete_sec_context,
+    k5glue_context_time,
+    k5glue_sign,
+    k5glue_verify,
+    k5glue_seal,
+    k5glue_unseal,
+    k5glue_display_status,
+    k5glue_indicate_mechs,
+    k5glue_compare_name,
+    k5glue_display_name,
+    k5glue_import_name,
+    k5glue_release_name,
+    k5glue_inquire_cred,
+    k5glue_add_cred,
+    k5glue_export_sec_context,
+    k5glue_import_sec_context,
+    k5glue_inquire_cred_by_mech,
+    k5glue_inquire_names_for_mech,
+    k5glue_inquire_context,
+    k5glue_release_oid,
+    k5glue_wrap_size_limit,
+    NULL,			/* pname_to_uid */
+    NULL,			/* userok */
+    k5glue_export_name,
+    NULL			/* store_cred */
+};
+
+#ifdef KRB5_MECH_MODULE
+gss_mechanism
+gss_mech_initialize(const gss_OID oid)
+{
+    if (oid == NULL ||
+	!g_OID_equal(oid, &krb5_mechanism.mech_type)) {
+	return NULL;
+    }
+    return &krb5_mechanism;
+}
+#endif
+
+static OM_uint32
+k5glue_accept_sec_context(ctx, minor_status, context_handle, verifier_cred_handle,
+		       input_token, input_chan_bindings, src_name, mech_type, 
+		       output_token, ret_flags, time_rec, delegated_cred_handle)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t *context_handle;
+     gss_cred_id_t verifier_cred_handle;
+     gss_buffer_t input_token;
+     gss_channel_bindings_t input_chan_bindings;
+     gss_name_t *src_name;
+     gss_OID *mech_type;
+     gss_buffer_t output_token;
+     OM_uint32 *ret_flags;
+     OM_uint32 *time_rec;
+     gss_cred_id_t *delegated_cred_handle;
+{
+   return(krb5_gss_accept_sec_context(minor_status,
+				      context_handle,
+				      verifier_cred_handle,
+				      input_token,
+				      input_chan_bindings,
+				      src_name,
+				      mech_type,
+				      output_token,
+				      ret_flags,
+				      time_rec,
+				      delegated_cred_handle));
+}
+
+static OM_uint32
+k5glue_acquire_cred(ctx, minor_status, desired_name, time_req, desired_mechs,
+		 cred_usage, output_cred_handle, actual_mechs, time_rec)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_name_t desired_name;
+     OM_uint32 time_req;
+     gss_OID_set desired_mechs;
+     gss_cred_usage_t cred_usage;
+     gss_cred_id_t *output_cred_handle;
+     gss_OID_set *actual_mechs;
+     OM_uint32 *time_rec;
+{
+   return(krb5_gss_acquire_cred(minor_status,
+				desired_name,
+				time_req,
+				desired_mechs,
+				cred_usage,
+				output_cred_handle,
+				actual_mechs,
+				time_rec));
+}
+
+/* V2 */
+static OM_uint32
+k5glue_add_cred(ctx, minor_status, input_cred_handle, desired_name, desired_mech,
+	     cred_usage, initiator_time_req, acceptor_time_req,
+	     output_cred_handle, actual_mechs, initiator_time_rec,
+	     acceptor_time_rec)
+    void *ctx;
+    OM_uint32		 *minor_status;
+    gss_cred_id_t	input_cred_handle;
+    gss_name_t		desired_name;
+    gss_OID		desired_mech;
+    gss_cred_usage_t	cred_usage;
+    OM_uint32		initiator_time_req;
+    OM_uint32		acceptor_time_req;
+    gss_cred_id_t	 *output_cred_handle;
+    gss_OID_set		 *actual_mechs;
+    OM_uint32		 *initiator_time_rec;
+    OM_uint32		 *acceptor_time_rec;
+{
+    return(krb5_gss_add_cred(minor_status, input_cred_handle, desired_name,
+			     desired_mech, cred_usage, initiator_time_req,
+			     acceptor_time_req, output_cred_handle,
+			     actual_mechs, initiator_time_rec,
+			     acceptor_time_rec));
+}
+
+#if 0
+/* V2 */
+static OM_uint32
+k5glue_add_oid_set_member(ctx, minor_status, member_oid, oid_set)
+    void *ctx;
+    OM_uint32	 *minor_status;
+    gss_OID	member_oid;
+    gss_OID_set	 *oid_set;
+{
+    return(generic_gss_add_oid_set_member(minor_status, member_oid, oid_set));
+}
+#endif
+
+static OM_uint32
+k5glue_compare_name(ctx, minor_status, name1, name2, name_equal)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_name_t name1;
+     gss_name_t name2;
+     int *name_equal;
+{
+   return(krb5_gss_compare_name(minor_status, name1,
+				name2, name_equal));
+}
+
+static OM_uint32
+k5glue_context_time(ctx, minor_status, context_handle, time_rec)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     OM_uint32 *time_rec;
+{
+   return(krb5_gss_context_time(minor_status, context_handle,
+				time_rec));
+}
+
+#if 0
+/* V2 */
+static OM_uint32
+k5glue_create_empty_oid_set(ctx, minor_status, oid_set)
+    void *ctx;
+    OM_uint32	 *minor_status;
+    gss_OID_set	 *oid_set;
+{
+    return(generic_gss_create_empty_oid_set(minor_status, oid_set));
+}
+#endif
+
+static OM_uint32
+k5glue_delete_sec_context(ctx, minor_status, context_handle, output_token)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t *context_handle;
+     gss_buffer_t output_token;
+{
+   return(krb5_gss_delete_sec_context(minor_status,
+				      context_handle, output_token));
+}
+
+static OM_uint32
+k5glue_display_name(ctx, minor_status, input_name, output_name_buffer, output_name_type)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_name_t input_name;
+     gss_buffer_t output_name_buffer;
+     gss_OID *output_name_type;
+{
+   return(krb5_gss_display_name(minor_status, input_name,
+				output_name_buffer, output_name_type));
+}
+
+static OM_uint32
+k5glue_display_status(ctx, minor_status, status_value, status_type,
+		   mech_type, message_context, status_string)
+    void *ctx;
+     OM_uint32 *minor_status;
+     OM_uint32 status_value;
+     int status_type;
+     gss_OID mech_type;
+     OM_uint32 *message_context;
+     gss_buffer_t status_string;
+{
+   return(krb5_gss_display_status(minor_status, status_value,
+				  status_type, mech_type, message_context,
+				  status_string));
+}
+
+/* V2 */
+static OM_uint32
+k5glue_export_sec_context(ctx, minor_status, context_handle, interprocess_token)
+    void *ctx;
+     OM_uint32		 *minor_status;
+     gss_ctx_id_t	 *context_handle;
+     gss_buffer_t	interprocess_token;
+{
+   return(krb5_gss_export_sec_context(minor_status,
+				      context_handle,
+				      interprocess_token));
+}
+
+#if 0
+/* V2 */
+static OM_uint32
+k5glue_get_mic(ctx, minor_status, context_handle, qop_req,
+	    message_buffer, message_token)
+    void *ctx;
+     OM_uint32		 *minor_status;
+     gss_ctx_id_t	context_handle;
+     gss_qop_t		qop_req;
+     gss_buffer_t	message_buffer;
+     gss_buffer_t	message_token;
+{
+    return(krb5_gss_get_mic(minor_status, context_handle,
+			    qop_req, message_buffer, message_token));
+}
+#endif
+
+static OM_uint32
+k5glue_import_name(ctx, minor_status, input_name_buffer, input_name_type, output_name)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_buffer_t input_name_buffer;
+     gss_OID input_name_type;
+     gss_name_t *output_name;
+{
+#if 0
+    OM_uint32 err;
+    err = gssint_initialize_library();
+    if (err) {
+	*minor_status = err;
+	return GSS_S_FAILURE;
+    }
+#endif
+    return(krb5_gss_import_name(minor_status, input_name_buffer,
+				input_name_type, output_name));
+}
+
+/* V2 */
+static OM_uint32
+k5glue_import_sec_context(ctx, minor_status, interprocess_token, context_handle)
+    void *ctx;
+     OM_uint32		 *minor_status;
+     gss_buffer_t	interprocess_token;
+     gss_ctx_id_t	 *context_handle;
+{
+   return(krb5_gss_import_sec_context(minor_status,
+				      interprocess_token,
+				      context_handle));
+}
+
+static OM_uint32
+k5glue_indicate_mechs(ctx, minor_status, mech_set)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_OID_set *mech_set;
+{
+   return(krb5_gss_indicate_mechs(minor_status, mech_set));
+}
+
+static OM_uint32
+k5glue_init_sec_context(ctx, minor_status, claimant_cred_handle, context_handle,
+		     target_name, mech_type, req_flags, time_req,
+		     input_chan_bindings, input_token, actual_mech_type,
+		     output_token, ret_flags, time_rec)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_cred_id_t claimant_cred_handle;
+     gss_ctx_id_t *context_handle;
+     gss_name_t target_name;
+     gss_OID mech_type;
+     OM_uint32 req_flags;
+     OM_uint32 time_req;
+     gss_channel_bindings_t input_chan_bindings;
+     gss_buffer_t input_token;
+     gss_OID *actual_mech_type;
+     gss_buffer_t output_token;
+     OM_uint32 *ret_flags;
+     OM_uint32 *time_rec;
+{
+   return(krb5_gss_init_sec_context(minor_status,
+				    claimant_cred_handle, context_handle,
+				    target_name, mech_type, req_flags,
+				    time_req, input_chan_bindings, input_token,
+				    actual_mech_type, output_token, ret_flags,
+				    time_rec));
+}
+
+static OM_uint32
+k5glue_inquire_context(ctx, minor_status, context_handle, initiator_name, acceptor_name,
+		    lifetime_rec, mech_type, ret_flags,
+		    locally_initiated, open)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     gss_name_t *initiator_name;
+     gss_name_t *acceptor_name;
+     OM_uint32 *lifetime_rec;
+     gss_OID *mech_type;
+     OM_uint32 *ret_flags;
+     int *locally_initiated;
+     int *open;
+{
+   return(krb5_gss_inquire_context(minor_status, context_handle,
+				   initiator_name, acceptor_name, lifetime_rec,
+				   mech_type, ret_flags, locally_initiated,
+				   open));
+}
+
+static OM_uint32
+k5glue_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
+		 cred_usage, mechanisms)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_cred_id_t cred_handle;
+     gss_name_t *name;
+     OM_uint32 *lifetime_ret;
+     gss_cred_usage_t *cred_usage;
+     gss_OID_set *mechanisms;
+{
+   return(krb5_gss_inquire_cred(minor_status, cred_handle,
+				name, lifetime_ret, cred_usage, mechanisms));
+}
+
+/* V2 */
+static OM_uint32
+k5glue_inquire_cred_by_mech(ctx, minor_status, cred_handle, mech_type, name,
+			 initiator_lifetime, acceptor_lifetime, cred_usage)
+    void *ctx;
+     OM_uint32		 *minor_status;
+     gss_cred_id_t	cred_handle;
+     gss_OID		mech_type;
+     gss_name_t		 *name;
+     OM_uint32		 *initiator_lifetime;
+     OM_uint32		 *acceptor_lifetime;
+     gss_cred_usage_t	 *cred_usage;
+{
+   return(krb5_gss_inquire_cred_by_mech(minor_status, cred_handle,
+					mech_type, name, initiator_lifetime,
+					acceptor_lifetime, cred_usage));
+}
+
+/* V2 */
+static OM_uint32
+k5glue_inquire_names_for_mech(ctx, minor_status, mechanism, name_types)
+    void *ctx;
+    OM_uint32	 *minor_status;
+    gss_OID	mechanism;
+    gss_OID_set	 *name_types;
+{
+    return(krb5_gss_inquire_names_for_mech(minor_status,
+					   mechanism,
+					   name_types));
+}
+
+#if 0
+/* V2 */
+static OM_uint32
+k5glue_oid_to_str(ctx, minor_status, oid, oid_str)
+    void *ctx;
+    OM_uint32		 *minor_status;
+    gss_OID		oid;
+    gss_buffer_t	oid_str;
+{
+    return(generic_gss_oid_to_str(minor_status, oid, oid_str));
+}
+#endif
+
+static OM_uint32
+k5glue_process_context_token(ctx, minor_status, context_handle, token_buffer)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     gss_buffer_t token_buffer;
+{
+   return(krb5_gss_process_context_token(minor_status,
+					 context_handle, token_buffer));
+}
+
+static OM_uint32
+k5glue_release_cred(ctx, minor_status, cred_handle)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_cred_id_t *cred_handle;
+{
+   return(krb5_gss_release_cred(minor_status, cred_handle));
+}
+
+static OM_uint32
+k5glue_release_name(ctx, minor_status, input_name)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_name_t *input_name;
+{
+   return(krb5_gss_release_name(minor_status, input_name));
+}
+
+#if 0
+static OM_uint32
+k5glue_release_buffer(ctx, minor_status, buffer)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_buffer_t buffer;
+{
+   return(generic_gss_release_buffer(minor_status,
+				     buffer));
+}
+#endif
+
+/* V2 */
+static OM_uint32
+k5glue_release_oid(ctx, minor_status, oid)
+    void *ctx;
+     OM_uint32	 *minor_status;
+     gss_OID	 *oid;
+{
+    return(krb5_gss_release_oid(minor_status, oid));
+}
+
+#if 0
+static OM_uint32
+k5glue_release_oid_set(ctx, minor_status, set)
+    void *ctx;
+     OM_uint32 * minor_status;
+     gss_OID_set *set;
+{
+   return(generic_gss_release_oid_set(minor_status, set));
+}
+#endif
+
+/* V1 only */
+static OM_uint32
+k5glue_seal(ctx, minor_status, context_handle, conf_req_flag, qop_req,
+	 input_message_buffer, conf_state, output_message_buffer)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     int conf_req_flag;
+     int qop_req;
+     gss_buffer_t input_message_buffer;
+     int *conf_state;
+     gss_buffer_t output_message_buffer;
+{
+   return(krb5_gss_seal(minor_status, context_handle,
+			conf_req_flag, qop_req, input_message_buffer,
+			conf_state, output_message_buffer));
+}
+
+static OM_uint32
+k5glue_sign(ctx, minor_status, context_handle,
+	      qop_req, message_buffer, 
+	      message_token)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     int qop_req;
+     gss_buffer_t message_buffer;
+     gss_buffer_t message_token;
+{
+   return(krb5_gss_sign(minor_status, context_handle,
+			qop_req, message_buffer, message_token));
+}
+
+#if 0
+/* V2 */
+static OM_uint32
+k5glue_verify_mic(ctx, minor_status, context_handle,
+	       message_buffer, token_buffer, qop_state)
+    void *ctx;
+     OM_uint32		 *minor_status;
+     gss_ctx_id_t	context_handle;
+     gss_buffer_t	message_buffer;
+     gss_buffer_t	token_buffer;
+     gss_qop_t		 *qop_state;
+{
+    return(krb5_gss_verify_mic(minor_status, context_handle,
+			       message_buffer, token_buffer, qop_state));
+}
+
+/* V2 */
+static OM_uint32
+k5glue_wrap(ctx, minor_status, context_handle, conf_req_flag, qop_req,
+	 input_message_buffer, conf_state, output_message_buffer)
+    void *ctx;
+    OM_uint32		 *minor_status;
+    gss_ctx_id_t	context_handle;
+    int			conf_req_flag;
+    gss_qop_t		qop_req;
+    gss_buffer_t	input_message_buffer;
+    int			 *conf_state;
+    gss_buffer_t	output_message_buffer;
+{
+    return(krb5_gss_wrap(minor_status, context_handle, conf_req_flag, qop_req,
+			 input_message_buffer, conf_state,
+			 output_message_buffer));
+}
+
+/* V2 */
+static OM_uint32
+k5glue_str_to_oid(ctx, minor_status, oid_str, oid)
+    void *ctx;
+    OM_uint32		 *minor_status;
+    gss_buffer_t	oid_str;
+    gss_OID		 *oid;
+{
+    return(generic_gss_str_to_oid(minor_status, oid_str, oid));
+}
+
+/* V2 */
+static OM_uint32
+k5glue_test_oid_set_member(ctx, minor_status, member, set, present)
+    void *ctx;
+    OM_uint32	 *minor_status;
+    gss_OID	member;
+    gss_OID_set	set;
+    int		 *present;
+{
+    return(generic_gss_test_oid_set_member(minor_status, member, set,
+					   present));
+}
+#endif
+
+/* V1 only */
+static OM_uint32
+k5glue_unseal(ctx, minor_status, context_handle, input_message_buffer,
+	   output_message_buffer, conf_state, qop_state)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     gss_buffer_t input_message_buffer;
+     gss_buffer_t output_message_buffer;
+     int *conf_state;
+     int *qop_state;
+{
+   return(krb5_gss_unseal(minor_status, context_handle,
+			  input_message_buffer, output_message_buffer,
+			  conf_state, qop_state));
+}
+
+#if 0
+/* V2 */
+static OM_uint32
+k5glue_unwrap(ctx, minor_status, context_handle, input_message_buffer, 
+	   output_message_buffer, conf_state, qop_state)
+    void *ctx;
+    OM_uint32		 *minor_status;
+    gss_ctx_id_t	context_handle;
+    gss_buffer_t	input_message_buffer;
+    gss_buffer_t	output_message_buffer;
+    int			 *conf_state;
+    gss_qop_t		 *qop_state;
+{
+    return(krb5_gss_unwrap(minor_status, context_handle, input_message_buffer,
+			   output_message_buffer, conf_state, qop_state));
+}
+#endif
+
+/* V1 only */
+static OM_uint32
+k5glue_verify(ctx, minor_status, context_handle, message_buffer,
+	   token_buffer, qop_state)
+    void *ctx;
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     gss_buffer_t message_buffer;
+     gss_buffer_t token_buffer;
+     int *qop_state;
+{
+   return(krb5_gss_verify(minor_status,
+			  context_handle,
+			  message_buffer,
+			  token_buffer,
+			  qop_state));
+}
+
+/* V2 interface */
+static OM_uint32
+k5glue_wrap_size_limit(ctx, minor_status, context_handle, conf_req_flag,
+		    qop_req, req_output_size, max_input_size)
+    void *ctx;
+    OM_uint32		 *minor_status;
+    gss_ctx_id_t	context_handle;
+    int			conf_req_flag;
+    gss_qop_t		qop_req;
+    OM_uint32		req_output_size;
+    OM_uint32		 *max_input_size;
+{
+   return(krb5_gss_wrap_size_limit(minor_status, context_handle,
+				   conf_req_flag, qop_req,
+				   req_output_size, max_input_size));
+}
+
+#if 0
+/* V2 interface */
+static OM_uint32
+k5glue_canonicalize_name(ctx, minor_status, input_name, mech_type, output_name)
+    void *ctx;
+	OM_uint32  *minor_status;
+	const gss_name_t input_name;
+	const gss_OID mech_type;
+	gss_name_t *output_name;
+{
+	return krb5_gss_canonicalize_name(minor_status, input_name,
+					  mech_type, output_name);
+}
+#endif
+
+/* V2 interface */
+static OM_uint32
+k5glue_export_name(ctx, minor_status, input_name, exported_name)
+    void *ctx;
+	OM_uint32  *minor_status;
+	const gss_name_t input_name;
+	gss_buffer_t exported_name;
+{
+	return krb5_gss_export_name(minor_status, input_name, exported_name);
+}
+
+#if 0
+/* V2 interface */
+static OM_uint32
+k5glue_duplicate_name(ctx, minor_status, input_name, dest_name)
+    void *ctx;
+	OM_uint32  *minor_status;
+	const gss_name_t input_name;
+	gss_name_t *dest_name;
+{
+	return krb5_gss_duplicate_name(minor_status, input_name, dest_name);
+}
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_get_tkt_flags(
+    OM_uint32 *minor_status,
+    gss_ctx_id_t context_handle,
+    krb5_flags *ticket_flags)
+{
+    gss_union_ctx_id_t uctx;
+
+    uctx = (gss_union_ctx_id_t)context_handle;
+    if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type))
+	return GSS_S_BAD_MECH;
+    return gss_krb5int_get_tkt_flags(minor_status, uctx->internal_ctx_id,
+				     ticket_flags);
+}
+
+OM_uint32 KRB5_CALLCONV 
+gss_krb5_copy_ccache(
+    OM_uint32 *minor_status,
+    gss_cred_id_t cred_handle,
+    krb5_ccache out_ccache)
+{
+    gss_union_cred_t ucred;
+    gss_cred_id_t mcred;
+
+    ucred = (gss_union_cred_t)cred_handle;
+    mcred = __gss_get_mechanism_cred(ucred, &krb5_mechanism.mech_type);
+    if (mcred == NULL)
+	return GSS_S_DEFECTIVE_CREDENTIAL;
+    return gss_krb5int_copy_ccache(minor_status, mcred, out_ccache);
+}
+
+/* XXX need to delete mechglue ctx too */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_export_lucid_sec_context(
+    OM_uint32 *minor_status,
+    gss_ctx_id_t *context_handle,
+    OM_uint32 version,
+    void **kctx)
+{
+    gss_union_ctx_id_t uctx;
+
+    uctx = (gss_union_ctx_id_t)*context_handle;
+    if (!g_OID_equal(uctx->mech_type, &krb5_mechanism.mech_type))
+	return GSS_S_BAD_MECH;
+    return gss_krb5int_export_lucid_sec_context(minor_status,
+						&uctx->internal_ctx_id,
+						version, kctx);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5_set_allowable_enctypes(
+    OM_uint32 *minor_status, 
+    gss_cred_id_t cred,
+    OM_uint32 num_ktypes,
+    krb5_enctype *ktypes)
+{
+    gss_union_cred_t ucred;
+    gss_cred_id_t mcred;
+
+    ucred = (gss_union_cred_t)cred;
+    mcred = __gss_get_mechanism_cred(ucred, &krb5_mechanism.mech_type);
+    if (mcred == NULL)
+	return GSS_S_DEFECTIVE_CREDENTIAL;
+    return gss_krb5int_set_allowable_enctypes(minor_status, mcred,
+					      num_ktypes, ktypes);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/lucid_context.c b/mechglue/src/lib/gssapi/krb5/lucid_context.c
new file mode 100644
index 000000000..a1679a93d
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/lucid_context.c
@@ -0,0 +1,309 @@
+/*
+ * lib/gssapi/krb5/lucid_context.c
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * lucid_context.c  -  Externalize a "lucid" security
+ * context from a krb5_gss_ctx_id_rec structure.
+ */
+#include "gssapiP_krb5.h"
+#include "gssapi_krb5.h"
+
+/*
+ * Local routine prototypes
+ */
+static void
+free_external_lucid_ctx_v1(
+    gss_krb5_lucid_context_v1_t *ctx);
+
+static void
+free_lucid_key_data(
+    gss_krb5_lucid_key_t *key);
+
+static krb5_error_code
+copy_keyblock_to_lucid_key(
+    krb5_keyblock *k5key,
+    gss_krb5_lucid_key_t *lkey);
+
+static krb5_error_code
+make_external_lucid_ctx_v1(
+    krb5_gss_ctx_id_rec * gctx,
+    unsigned int version,
+    void **out_ptr);
+
+
+/*
+ * Exported routines
+ */
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_export_lucid_sec_context(
+    OM_uint32		*minor_status,
+    gss_ctx_id_t	*context_handle,
+    OM_uint32		version,
+    void		**kctx)
+{
+    krb5_error_code	kret = 0;
+    OM_uint32		retval;
+    krb5_gss_ctx_id_t	ctx;
+    void		*lctx = NULL;
+
+    /* Assume failure */
+    retval = GSS_S_FAILURE;
+    *minor_status = 0;
+
+    if (kctx)
+	*kctx = NULL;
+    else {
+	kret = EINVAL;
+    	goto error_out;
+    }
+
+    if (!kg_validate_ctx_id(*context_handle)) {
+	    kret = (OM_uint32) G_VALIDATE_FAILED;
+	    retval = GSS_S_NO_CONTEXT;
+	    goto error_out;
+    }
+
+    ctx = (krb5_gss_ctx_id_t) *context_handle;
+    if (kret)
+	goto error_out;
+
+    /* Externalize a structure of the right version */
+    switch (version) {
+    case 1:
+	kret = make_external_lucid_ctx_v1((krb5_pointer)ctx,
+					      version, &lctx);
+        break;
+    default:
+	kret = (OM_uint32) KG_LUCID_VERSION;
+	break;
+    }
+
+    if (kret)
+	goto error_out;
+
+    /* Success!  Record the context and return the buffer */
+    if (! kg_save_lucidctx_id((void *)lctx)) {
+	kret = G_VALIDATE_FAILED;
+	goto error_out;
+    }
+
+    *kctx = lctx;
+    *minor_status = 0;
+    retval = GSS_S_COMPLETE;
+
+    /* Clean up the context state (it is an error for
+     * someone to attempt to use this context again)
+     */
+    (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
+    *context_handle = GSS_C_NO_CONTEXT;
+
+    return (retval);
+
+error_out:
+    if (*minor_status == 0) 
+	    *minor_status = (OM_uint32) kret;
+    return(retval);
+}
+
+/*
+ * Frees the storage associated with an
+ * exported lucid context structure.
+ */
+OM_uint32 KRB5_CALLCONV
+gss_krb5_free_lucid_sec_context(
+    OM_uint32 *minor_status,
+    void *kctx)
+{
+    OM_uint32		retval;
+    krb5_error_code	kret = 0;
+    int			version;
+
+    /* Assume failure */
+    retval = GSS_S_FAILURE;
+    *minor_status = 0;
+
+    if (!kctx) {
+	kret = EINVAL;
+	goto error_out;
+    }
+
+    /* Verify pointer is valid lucid context */
+    if (! kg_validate_lucidctx_id(kctx)) {
+	kret = G_VALIDATE_FAILED;
+	goto error_out;
+    }
+
+    /* Determine version and call correct free routine */
+    version = ((gss_krb5_lucid_context_version_t *)kctx)->version;
+    switch (version) {
+    case 1:
+	free_external_lucid_ctx_v1((gss_krb5_lucid_context_v1_t*) kctx);
+	break;
+    default:
+	kret = EINVAL;
+	break;
+    }
+
+    if (kret)
+	goto error_out;
+
+    /* Success! */
+    (void)kg_delete_lucidctx_id(kctx);
+    *minor_status = 0;
+    retval = GSS_S_COMPLETE;
+
+    return (retval);
+
+error_out:
+    if (*minor_status == 0) 
+	    *minor_status = (OM_uint32) kret;
+    return(retval);
+}
+
+/*
+ * Local routines
+ */
+
+static krb5_error_code
+make_external_lucid_ctx_v1(
+    krb5_gss_ctx_id_rec * gctx,
+    unsigned int version,
+    void **out_ptr)
+{
+    gss_krb5_lucid_context_v1_t *lctx = NULL;
+    unsigned int bufsize = sizeof(gss_krb5_lucid_context_v1_t);
+    krb5_error_code retval;
+
+    /* Allocate the structure */
+    if ((lctx = xmalloc(bufsize)) == NULL) {
+    	retval = ENOMEM;
+	goto error_out;
+    }
+
+    memset(lctx, 0, bufsize);
+
+    lctx->version = 1;
+    lctx->initiate = gctx->initiate ? 1 : 0;
+    lctx->endtime = gctx->endtime;
+    lctx->send_seq = gctx->seq_send;
+    lctx->recv_seq = gctx->seq_recv;
+    lctx->protocol = gctx->proto;
+    /* gctx->proto == 0 ==> rfc1964-style key information
+       gctx->proto == 1 ==> cfx-style (draft-ietf-krb-wg-gssapi-cfx-07) keys */
+    if (gctx->proto == 0) {
+	lctx->rfc1964_kd.sign_alg = gctx->signalg;
+	lctx->rfc1964_kd.seal_alg = gctx->sealalg;
+	/* Copy key */
+	if ((retval = copy_keyblock_to_lucid_key(gctx->subkey,
+	    				&lctx->rfc1964_kd.ctx_key)))
+	    goto error_out;
+    }
+    else if (gctx->proto == 1) {
+	/* Copy keys */
+	/* (subkey is always present, either a copy of the kerberos
+	   session key or a subkey) */
+	if ((retval = copy_keyblock_to_lucid_key(gctx->subkey,
+	    				&lctx->cfx_kd.ctx_key)))
+	    goto error_out;
+	if (gctx->have_acceptor_subkey) {
+	    if ((retval = copy_keyblock_to_lucid_key(gctx->enc,
+	    				&lctx->cfx_kd.acceptor_subkey)))
+		goto error_out;
+	    lctx->cfx_kd.have_acceptor_subkey = 1;
+	}
+    }
+    else {
+	return EINVAL;	/* XXX better error code? */
+    }
+
+    /* Success! */
+    *out_ptr = lctx;
+    return 0;
+
+error_out:
+    if (lctx) {
+	free_external_lucid_ctx_v1(lctx);
+    }
+    return retval;
+
+}
+
+/* Copy the contents of a krb5_keyblock to a gss_krb5_lucid_key_t structure */
+static krb5_error_code
+copy_keyblock_to_lucid_key(
+    krb5_keyblock *k5key,
+    gss_krb5_lucid_key_t *lkey)
+{
+    if (!k5key || !k5key->contents || k5key->length == 0)
+	return EINVAL;
+
+    memset(lkey, 0, sizeof(gss_krb5_lucid_key_t));
+
+    /* Allocate storage for the key data */
+    if ((lkey->data = xmalloc(k5key->length)) == NULL) {
+	return ENOMEM;
+    }
+    memcpy(lkey->data, k5key->contents, k5key->length);
+    lkey->length = k5key->length;
+    lkey->type = k5key->enctype;
+
+    return 0;
+}
+
+
+/* Free any storage associated with a gss_krb5_lucid_key_t structure */
+static void
+free_lucid_key_data(
+    gss_krb5_lucid_key_t *key)
+{
+    if (key) {
+	if (key->data && key->length) {
+	    memset(key->data, 0, key->length);
+	    xfree(key->data);
+	    memset(key, 0, sizeof(gss_krb5_lucid_key_t));
+	}
+    }
+}
+/* Free any storage associated with a gss_krb5_lucid_context_v1 structure */
+static void
+free_external_lucid_ctx_v1(
+    gss_krb5_lucid_context_v1_t *ctx)
+{
+    if (ctx) {
+	if (ctx->protocol == 0) {
+	    free_lucid_key_data(&ctx->rfc1964_kd.ctx_key);
+	}
+	if (ctx->protocol == 1) {
+	    free_lucid_key_data(&ctx->cfx_kd.ctx_key);
+	    if (ctx->cfx_kd.have_acceptor_subkey)
+		free_lucid_key_data(&ctx->cfx_kd.acceptor_subkey);
+	}
+	xfree(ctx);
+	ctx = NULL;
+    }
+}
diff --git a/mechglue/src/lib/gssapi/krb5/process_context_token.c b/mechglue/src/lib/gssapi/krb5/process_context_token.c
new file mode 100644
index 000000000..f1bf5c537
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/process_context_token.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+krb5_gss_process_context_token(minor_status, context_handle, 
+			       token_buffer)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     gss_buffer_t token_buffer;
+{
+   krb5_gss_ctx_id_rec *ctx;
+   OM_uint32 majerr;
+
+   /* validate the context handle */
+   if (! kg_validate_ctx_id(context_handle)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   ctx = (krb5_gss_ctx_id_rec *) context_handle;
+
+   if (! ctx->established) {
+      *minor_status = KG_CTX_INCOMPLETE;
+      return(GSS_S_NO_CONTEXT);
+   }
+
+   /* "unseal" the token */
+
+   if (GSS_ERROR(majerr = kg_unseal(minor_status, ctx, token_buffer,
+				    GSS_C_NO_BUFFER, NULL, NULL,
+				    KG_TOK_DEL_CTX)))
+      return(majerr);
+
+   /* that's it.  delete the context */
+
+   return(krb5_gss_delete_sec_context(minor_status, &context_handle,
+				      GSS_C_NO_BUFFER));
+}
diff --git a/mechglue/src/lib/gssapi/krb5/rel_cred.c b/mechglue/src/lib/gssapi/krb5/rel_cred.c
new file mode 100644
index 000000000..ed88abb43
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/rel_cred.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32 
+krb5_gss_release_cred(minor_status, cred_handle)
+     OM_uint32 *minor_status;
+     gss_cred_id_t *cred_handle;
+{
+   krb5_context context;
+   krb5_gss_cred_id_t cred;
+   krb5_error_code code1, code2, code3;
+
+   code1 = krb5_init_context(&context);
+   if (code1) {
+       *minor_status = code1;
+       return GSS_S_FAILURE;
+   }
+
+   if (*cred_handle == GSS_C_NO_CREDENTIAL) {
+      *minor_status = 0;
+      krb5_free_context(context);
+      return(GSS_S_COMPLETE);
+   }
+
+   if (! kg_delete_cred_id(*cred_handle)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      krb5_free_context(context);
+      return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_NO_CRED);
+   }
+
+   cred = *cred_handle;
+
+   k5_mutex_destroy(&cred->lock);
+   /* ignore error destroying mutex */
+
+   if (cred->ccache)
+      code1 = krb5_cc_close(context, cred->ccache);
+   else
+      code1 = 0;
+
+   if (cred->keytab)
+      code2 = krb5_kt_close(context, cred->keytab);
+   else
+      code2 = 0;
+
+   if (cred->rcache)
+      code3 = krb5_rc_close(context, cred->rcache);
+   else
+      code3 = 0;
+   if (cred->princ)
+      krb5_free_principal(context, cred->princ);
+   xfree(cred);
+   krb5_free_context(context);
+
+   *cred_handle = NULL;
+
+   *minor_status = 0;
+   if (code1)
+      *minor_status = code1;
+   if (code2)
+      *minor_status = code2;
+   if (code3)
+      *minor_status = code3;
+
+   return(*minor_status?GSS_S_FAILURE:GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/rel_name.c b/mechglue/src/lib/gssapi/krb5/rel_name.c
new file mode 100644
index 000000000..961ccb29c
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/rel_name.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+krb5_gss_release_name(minor_status, input_name)
+     OM_uint32 *minor_status;
+     gss_name_t *input_name;
+{
+   krb5_context context;
+   krb5_error_code code;
+
+   code = krb5_init_context(&context);
+   if (code) {
+       *minor_status = code;
+       return GSS_S_FAILURE;
+   }
+
+   if (! kg_validate_name(*input_name)) {
+      *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+      krb5_free_context(context);
+      return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+   }
+
+   (void)kg_delete_name(*input_name);
+
+   krb5_free_principal(context, (krb5_principal) *input_name);
+   krb5_free_context(context);
+
+   *input_name = (gss_name_t) NULL;
+
+   *minor_status = 0;
+   return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/rel_oid.c b/mechglue/src/lib/gssapi/krb5/rel_oid.c
new file mode 100644
index 000000000..01921c02f
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/rel_oid.c
@@ -0,0 +1,85 @@
+/*
+ * lib/gssapi/krb5/rel_oid.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * rel_oid.c - Release an OID.
+ */
+#include "gssapiP_krb5.h"
+
+static OM_uint32 krb5_gss_internal_release_oid (OM_uint32 *, /* minor_status */
+						gss_OID * /* oid */
+    );
+
+OM_uint32
+krb5_gss_release_oid(minor_status, oid)
+    OM_uint32	*minor_status;
+    gss_OID	*oid;
+{
+    /*
+     * The V2 API says the following!
+     *
+     * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
+     * and will silently ignore attempts to free these OIDs; for other OIDs
+     * it will call the C free() routine for both the OID data and the
+     * descriptor.  This allows applications to freely mix their own heap-
+     * allocated OID values with OIDs returned by GSS-API.
+     */
+    if (krb5_gss_internal_release_oid(minor_status, oid) != GSS_S_COMPLETE) {
+	/* Pawn it off on the generic routine */
+	return(generic_gss_release_oid(minor_status, oid));
+    }
+    else {
+	*oid = GSS_C_NO_OID;
+	*minor_status = 0;
+	return(GSS_S_COMPLETE);
+    }
+}
+
+static OM_uint32
+krb5_gss_internal_release_oid(minor_status, oid)
+    OM_uint32	*minor_status;
+    gss_OID	*oid;
+{
+    /*
+     * This function only knows how to release internal OIDs. It will
+     * return GSS_S_CONTINUE_NEEDED for any OIDs it does not recognize.
+     */
+   
+    if ((*oid != gss_mech_krb5) &&
+	(*oid != gss_mech_krb5_old) &&
+	(*oid != gss_nt_krb5_name) &&
+	(*oid != gss_nt_krb5_principal)) {
+	/* We don't know about this OID */
+	return(GSS_S_CONTINUE_NEEDED);
+    }
+    else {
+	*oid = GSS_C_NO_OID;
+	*minor_status = 0;
+	return(GSS_S_COMPLETE);
+    }
+}
+
diff --git a/mechglue/src/lib/gssapi/krb5/seal.c b/mechglue/src/lib/gssapi/krb5/seal.c
new file mode 100644
index 000000000..63d3dabe0
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/seal.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+krb5_gss_seal(minor_status, context_handle, conf_req_flag,
+	      qop_req, input_message_buffer, conf_state,
+	      output_message_buffer)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     int conf_req_flag;
+     int qop_req;
+     gss_buffer_t input_message_buffer;
+     int *conf_state;
+     gss_buffer_t output_message_buffer;
+{
+   return(kg_seal(minor_status, context_handle, conf_req_flag,
+		  qop_req, input_message_buffer, conf_state,
+		  output_message_buffer, KG_TOK_SEAL_MSG));
+}
+
+/* V2 interface */
+OM_uint32
+krb5_gss_wrap(minor_status, context_handle, conf_req_flag,
+	      qop_req, input_message_buffer, conf_state,
+	      output_message_buffer)
+    OM_uint32		*minor_status;
+    gss_ctx_id_t	context_handle;
+    int			conf_req_flag;
+    gss_qop_t		qop_req;
+    gss_buffer_t	input_message_buffer;
+    int			*conf_state;
+    gss_buffer_t	output_message_buffer;
+{
+    return(kg_seal(minor_status, context_handle, conf_req_flag,
+		   (int) qop_req, input_message_buffer, conf_state,
+		   output_message_buffer, KG_TOK_WRAP_MSG));
+}
+
diff --git a/mechglue/src/lib/gssapi/krb5/ser_sctx.c b/mechglue/src/lib/gssapi/krb5/ser_sctx.c
new file mode 100644
index 000000000..00ea78254
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/ser_sctx.c
@@ -0,0 +1,676 @@
+/*
+ * lib/gssapi/krb5/ser_sctx.c
+ *
+ * Copyright 1995, 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_sctx.c - Handle [de]serialization of GSSAPI security context.
+ */
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+
+/*
+ * This module contains routines to [de]serialize 
+ *	krb5_gss_enc_desc and krb5_gss_ctx_id_t.
+ * XXX This whole serialization abstraction is unnecessary in a
+ * non-messaging environment, which krb5 is.  Someday, this should
+ * all get redone without the extra level of indirection. I've done
+ * some of this work here, since adding new serializers is an internal
+ * krb5 interface, and I won't use those.  There is some more
+ * deobfuscation (no longer anonymizing pointers, mostly) which could
+ * still be done. --marc
+ */
+
+static krb5_error_code
+kg_oid_externalize(kcontext, arg, buffer, lenremain)
+    krb5_context	kcontext;
+    krb5_pointer	arg;
+    krb5_octet		**buffer;
+    size_t		*lenremain;
+{
+     gss_OID oid = (gss_OID) arg;
+     krb5_error_code err;
+     
+     err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
+     if (err)
+	 return err;
+     err = krb5_ser_pack_int32((krb5_int32) oid->length,
+			       buffer, lenremain);
+     if (err)
+	 return err;
+     err = krb5_ser_pack_bytes((krb5_octet *) oid->elements,
+			       oid->length, buffer, lenremain);
+     if (err)
+	 return err;
+     err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain);
+     return err;
+}
+
+static krb5_error_code
+kg_oid_internalize(kcontext, argp, buffer, lenremain)
+    krb5_context	kcontext;
+    krb5_pointer	*argp;
+    krb5_octet		**buffer;
+    size_t		*lenremain;
+{
+     gss_OID oid;
+     krb5_int32 ibuf;
+     krb5_octet		*bp;
+     size_t		remain;
+
+     bp = *buffer;
+     remain = *lenremain;
+
+     /* Read in and check our magic number */
+     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	return (EINVAL);
+
+     if (ibuf != KV5M_GSS_OID)
+	 return (EINVAL);
+
+     oid = (gss_OID) malloc(sizeof(gss_OID_desc));
+     if (oid == NULL)
+	  return ENOMEM;
+     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+	 free(oid);
+	 return EINVAL;
+     }
+     oid->length = ibuf;
+     oid->elements = malloc(ibuf);
+     if (oid->elements == 0) {
+	     free(oid);
+	     return ENOMEM;
+     }
+     if (krb5_ser_unpack_bytes((krb5_octet *) oid->elements,
+			       oid->length, &bp, &remain)) {
+	 free(oid->elements);
+	 free(oid);
+	 return EINVAL;
+     }
+     
+     /* Read in and check our trailing magic number */
+     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+	 free(oid->elements);
+	 free(oid);
+	 return (EINVAL);
+     }
+
+     if (ibuf != KV5M_GSS_OID) {
+	 free(oid->elements);
+	 free(oid);
+	 return (EINVAL);
+     }
+
+     *buffer = bp;
+     *lenremain = remain;
+     *argp = (krb5_pointer) oid;
+     return 0;
+}
+
+static krb5_error_code
+kg_oid_size(kcontext, arg, sizep)
+    krb5_context	kcontext;
+    krb5_pointer	arg;
+    size_t		*sizep;
+{
+   krb5_error_code kret;
+   gss_OID oid;
+   size_t required;
+
+   kret = EINVAL;
+   if ((oid = (gss_OID) arg)) {
+      required = 2*sizeof(krb5_int32); /* For the header and trailer */
+      required += sizeof(krb5_int32);
+      required += oid->length;
+
+      kret = 0;
+
+      *sizep += required;
+   }
+
+   return(kret);
+}
+
+static krb5_error_code
+kg_queue_externalize(kcontext, arg, buffer, lenremain)
+    krb5_context	kcontext;
+    krb5_pointer	arg;
+    krb5_octet		**buffer;
+    size_t		*lenremain;
+{
+    krb5_error_code err;
+    err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
+    if (err == 0)
+	err = g_queue_externalize(arg, buffer, lenremain);
+    if (err == 0)
+	err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain);
+    return err;
+}
+
+static krb5_error_code
+kg_queue_internalize(kcontext, argp, buffer, lenremain)
+    krb5_context	kcontext;
+    krb5_pointer	*argp;
+    krb5_octet		**buffer;
+    size_t		*lenremain;
+{
+     krb5_int32 ibuf;
+     krb5_octet		*bp;
+     size_t		remain;
+     krb5_error_code	err;
+
+     bp = *buffer;
+     remain = *lenremain;
+
+     /* Read in and check our magic number */
+     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	return (EINVAL);
+
+     if (ibuf != KV5M_GSS_QUEUE)
+	 return (EINVAL);
+
+     err = g_queue_internalize(argp, &bp, &remain);
+     if (err)
+	  return err;
+
+     /* Read in and check our trailing magic number */
+     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) {
+	 g_order_free(argp);
+	 return (EINVAL);
+     }
+
+     if (ibuf != KV5M_GSS_QUEUE) {
+	 g_order_free(argp);
+	 return (EINVAL);
+     }
+
+     *buffer = bp;
+     *lenremain = remain;
+     return 0;
+}
+
+static krb5_error_code
+kg_queue_size(kcontext, arg, sizep)
+    krb5_context	kcontext;
+    krb5_pointer	arg;
+    size_t		*sizep;
+{
+   krb5_error_code kret;
+   size_t required;
+
+   kret = EINVAL;
+   if (arg) {
+      required = 2*sizeof(krb5_int32); /* For the header and trailer */
+      g_queue_size(arg, &required);
+
+      kret = 0;
+      *sizep += required;
+   }
+   return(kret);
+}
+
+/*
+ * Determine the size required for this krb5_gss_ctx_id_rec.
+ */
+krb5_error_code
+kg_ctx_size(kcontext, arg, sizep)
+    krb5_context	kcontext;
+    krb5_pointer	arg;
+    size_t		*sizep;
+{
+    krb5_error_code	kret;
+    krb5_gss_ctx_id_rec	*ctx;
+    size_t		required;
+
+    /*
+     * krb5_gss_ctx_id_rec requires:
+     *	krb5_int32	for KG_CONTEXT
+     *	krb5_int32	for initiate.
+     *	krb5_int32	for established.
+     *	krb5_int32	for big_endian.
+     *	krb5_int32	for have_acceptor_subkey.
+     *	krb5_int32	for seed_init.
+     *	krb5_int32	for gss_flags.
+     *	sizeof(seed)	for seed
+     *	...		for here
+     *	...		for there
+     *	...		for subkey
+     *  krb5_int32	for signalg.
+     *  krb5_int32	for cksum_size.
+     *  krb5_int32	for sealalg.
+     *	...		for enc
+     *	...		for seq
+     *	krb5_int32	for endtime.
+     *	krb5_int32	for flags.
+     *	krb5_int64	for seq_send.
+     *	krb5_int64	for seq_recv.
+     *	...		for seqstate
+     *	...		for auth_context
+     *	...		for mech_used
+     *	krb5_int32	for proto
+     *	krb5_int32	for cksumtype
+     *	...		for acceptor_subkey
+     *	krb5_int32	for acceptor_key_cksumtype
+     *	krb5_int32	for cred_rcache
+     *	krb5_int32	for trailer.
+     */
+    kret = EINVAL;
+    if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
+	required = 17*sizeof(krb5_int32);
+	required += 2*sizeof(krb5_int64);
+	required += sizeof(ctx->seed);
+
+	kret = 0;
+	if (!kret && ctx->here)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_PRINCIPAL,
+				    (krb5_pointer) ctx->here,
+				    &required);
+
+	if (!kret && ctx->there)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_PRINCIPAL,
+				    (krb5_pointer) ctx->there,
+				    &required);
+
+	if (!kret && ctx->subkey)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) ctx->subkey,
+				    &required);
+
+	if (!kret && ctx->enc)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) ctx->enc,
+				    &required);
+
+	if (!kret && ctx->seq)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) ctx->seq,
+				    &required);
+
+	if (!kret)
+	    kret = kg_oid_size(kcontext,
+			       (krb5_pointer) ctx->mech_used,
+			       &required);
+
+	if (!kret && ctx->seqstate)
+	    kret = kg_queue_size(kcontext, ctx->seqstate, &required);
+
+	if (!kret)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_CONTEXT,
+				    (krb5_pointer) ctx->k5_context,
+				    &required);
+	if (!kret)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_AUTH_CONTEXT,
+				    (krb5_pointer) ctx->auth_context,
+				    &required);
+	if (!kret && ctx->acceptor_subkey)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) ctx->acceptor_subkey,
+				    &required);
+	if (!kret)
+	    *sizep += required;
+    }
+    return(kret);
+}
+
+/*
+ * Externalize this krb5_gss_ctx_id_ret.
+ */
+krb5_error_code
+kg_ctx_externalize(kcontext, arg, buffer, lenremain)
+    krb5_context	kcontext;
+    krb5_pointer	arg;
+    krb5_octet		**buffer;
+    size_t		*lenremain;
+{
+    krb5_error_code	kret;
+    krb5_gss_ctx_id_rec	*ctx;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+    krb5int_access kaccess;
+
+    kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+    if (kret) 
+        return(kret);
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((ctx = (krb5_gss_ctx_id_rec *) arg)) {
+	kret = ENOMEM;
+	if (!kg_ctx_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
+
+	    /* Now static data */
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->initiate,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->established,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->big_endian,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->have_acceptor_subkey,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->seed_init,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->gss_flags,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed,
+				       sizeof(ctx->seed),
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->signalg,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->endtime,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags,
+				       &bp, &remain);
+	    (void) (*kaccess.krb5_ser_pack_int64)((krb5_int64) ctx->seq_send,
+				       &bp, &remain);
+	    (void) (*kaccess.krb5_ser_pack_int64)((krb5_int64) ctx->seq_recv,
+				       &bp, &remain);
+
+	    /* Now dynamic data */
+	    kret = 0;
+
+	    if (!kret && ctx->mech_used)
+		 kret = kg_oid_externalize(kcontext, ctx->mech_used,
+					   &bp, &remain); 
+	    
+	    if (!kret && ctx->here)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_PRINCIPAL,
+					       (krb5_pointer) ctx->here,
+					       &bp, &remain);
+
+	    if (!kret && ctx->there)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_PRINCIPAL,
+					       (krb5_pointer) ctx->there,
+					       &bp, &remain);
+
+	    if (!kret && ctx->subkey)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer) ctx->subkey,
+					       &bp, &remain);
+
+	    if (!kret && ctx->enc)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer) ctx->enc,
+					       &bp, &remain);
+
+	    if (!kret && ctx->seq)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer) ctx->seq,
+					       &bp, &remain);
+
+	    if (!kret && ctx->seqstate)
+		kret = kg_queue_externalize(kcontext,
+					    ctx->seqstate, &bp, &remain);
+
+	    if (!kret)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_CONTEXT,
+					       (krb5_pointer) ctx->k5_context,
+					       &bp, &remain);
+
+	    if (!kret)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_AUTH_CONTEXT,
+					       (krb5_pointer) ctx->auth_context,
+					       &bp, &remain);
+
+	    if (!kret)
+		kret = krb5_ser_pack_int32((krb5_int32) ctx->proto,
+					   &bp, &remain);
+	    if (!kret)
+		kret = krb5_ser_pack_int32((krb5_int32) ctx->cksumtype,
+					   &bp, &remain);
+	    if (!kret && ctx->acceptor_subkey)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer) ctx->acceptor_subkey,
+					       &bp, &remain);
+	    if (!kret)
+		kret = krb5_ser_pack_int32((krb5_int32) ctx->acceptor_subkey_cksumtype,
+					   &bp, &remain);
+
+	    if (!kret)
+		kret = krb5_ser_pack_int32((krb5_int32) ctx->cred_rcache,
+					   &bp, &remain);
+	    /* trailer */
+	    if (!kret)
+		kret = krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain);
+	    if (!kret) {
+		*buffer = bp;
+		*lenremain = remain;
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Internalize this krb5_gss_ctx_id_t.
+ */
+krb5_error_code
+kg_ctx_internalize(kcontext, argp, buffer, lenremain)
+    krb5_context	kcontext;
+    krb5_pointer	*argp;
+    krb5_octet		**buffer;
+    size_t		*lenremain;
+{
+    krb5_error_code	kret;
+    krb5_gss_ctx_id_rec	*ctx;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    krb5int_access kaccess;
+
+    kret = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+    if (kret)
+        return(kret);
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KG_CONTEXT) {
+	kret = ENOMEM;
+
+	/* Get a context */
+	if ((remain >= (17*sizeof(krb5_int32)
+			+ 2*sizeof(krb5_int64)
+			+ sizeof(ctx->seed))) &&
+	    (ctx = (krb5_gss_ctx_id_rec *)
+	     xmalloc(sizeof(krb5_gss_ctx_id_rec)))) {
+	    memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+
+	    ctx->k5_context = kcontext;
+
+	    /* Get static data */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->initiate = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->established = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->big_endian = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->have_acceptor_subkey = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->seed_init = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->gss_flags = (int) ibuf;
+	    (void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed,
+					 sizeof(ctx->seed),
+					 &bp, &remain);
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->signalg = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->cksum_size = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->sealalg = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->endtime = (krb5_timestamp) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->krb_flags = (krb5_flags) ibuf;
+	    (void) (*kaccess.krb5_ser_unpack_int64)(&ctx->seq_send, &bp, &remain);
+	    kret = (*kaccess.krb5_ser_unpack_int64)(&ctx->seq_recv, &bp, &remain);
+	    if (kret) {
+		free(ctx);
+		return kret;
+	    }
+
+	    if ((kret = kg_oid_internalize(kcontext, &ctx->mech_used, &bp,
+					   &remain))) {
+		 if (kret == EINVAL)
+		      kret = 0;
+	    }
+	    /* Now get substructure data */
+	    if ((kret = krb5_internalize_opaque(kcontext,
+						KV5M_PRINCIPAL,
+						(krb5_pointer *) &ctx->here,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+	    if (!kret &&
+		(kret = krb5_internalize_opaque(kcontext,
+						KV5M_PRINCIPAL,
+						(krb5_pointer *) &ctx->there,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+	    if (!kret &&
+		(kret = krb5_internalize_opaque(kcontext,
+						KV5M_KEYBLOCK,
+						(krb5_pointer *) &ctx->subkey,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+	    if (!kret &&
+		(kret = krb5_internalize_opaque(kcontext,
+						KV5M_KEYBLOCK,
+						(krb5_pointer *) &ctx->enc,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+	    if (!kret &&
+		(kret = krb5_internalize_opaque(kcontext,
+						KV5M_KEYBLOCK,
+						(krb5_pointer *) &ctx->seq,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+
+	    if (!kret) {
+		kret = kg_queue_internalize(kcontext, &ctx->seqstate,
+					    &bp, &remain);
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+		
+	    if (!kret)
+		kret = krb5_internalize_opaque(kcontext,
+					       KV5M_CONTEXT,
+					       (krb5_pointer *) &ctx->k5_context,
+					       &bp, &remain);
+
+	    if (!kret)
+		kret = krb5_internalize_opaque(kcontext,
+					       KV5M_AUTH_CONTEXT,
+				       (krb5_pointer *) &ctx->auth_context,
+					       &bp, &remain);
+
+	    if (!kret)
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->proto = ibuf;
+	    if (!kret)
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->cksumtype = ibuf;
+	    if (!kret &&
+		(kret = krb5_internalize_opaque(kcontext,
+						KV5M_KEYBLOCK,
+						(krb5_pointer *) &ctx->acceptor_subkey,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+	    if (!kret)
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->cred_rcache = ibuf;
+	    if (!kret)
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->acceptor_subkey_cksumtype = ibuf;
+
+	    /* Get trailer */
+	    if (!kret)
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    if (!kret && ibuf != KG_CONTEXT)
+		kret = EINVAL;
+
+	    if (!kret) {
+		*buffer = bp;
+		*lenremain = remain;
+		*argp = (krb5_pointer) ctx;
+	    } else {
+		if (ctx->seq)
+		    krb5_free_keyblock(kcontext, ctx->seq);
+		if (ctx->enc)
+		    krb5_free_keyblock(kcontext, ctx->enc);
+		if (ctx->subkey)
+		    krb5_free_keyblock(kcontext, ctx->subkey);
+		if (ctx->there)
+		    krb5_free_principal(kcontext, ctx->there);
+		if (ctx->here)
+		    krb5_free_principal(kcontext, ctx->here);
+		xfree(ctx);
+	    }
+	}
+    }
+    return(kret);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/set_allowable_enctypes.c b/mechglue/src/lib/gssapi/krb5/set_allowable_enctypes.c
new file mode 100644
index 000000000..1ce6c4b9e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/set_allowable_enctypes.c
@@ -0,0 +1,131 @@
+/*
+ * lib/gssapi/krb5/set_allowable_enctypes.c
+ *
+ * Copyright 2004  by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * krb5_gss_set_allowable_enctypes()
+ */
+
+/*
+ * gss_krb5_set_allowable_enctypes
+ *
+ * This function may be called by a context initiator after calling
+ * gss_acquire_cred(), but before calling gss_init_sec_context(),
+ * to restrict the set of enctypes which will be negotiated during
+ * context establishment to those in the provided array.
+ *
+ * 'cred_handle' must be a valid credential handle obtained via
+ * gss_acquire_cred().  It may not be GSS_C_NO_CREDENTIAL.
+ * gss_acquire_cred() may be called with GSS_C_NO_CREDENTIAL
+ * to get a handle to the default credential.
+ *
+ * The purpose of this function is to limit the keys that may
+ * be exported via gss_krb5_export_lucid_sec_context(); thus it
+ * should limit the enctypes of all keys that will be needed
+ * after the security context has been established.
+ * (i.e. context establishment may use a session key with a
+ * stronger enctype than in the provided array, however a
+ * subkey must be established within the enctype limits
+ * established by this function.)
+ *
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "gssapi_krb5.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_krb5int_set_allowable_enctypes(OM_uint32 *minor_status, 
+				   gss_cred_id_t cred_handle,
+				   OM_uint32 num_ktypes,
+				   krb5_enctype *ktypes)
+{
+    int i;
+    krb5_enctype * new_ktypes;
+    OM_uint32 major_status;
+    krb5_gss_cred_id_t cred;
+    krb5_error_code kerr = 0;
+    OM_uint32 temp_status;
+
+    /* Assume a failure */
+    *minor_status = 0;
+    major_status = GSS_S_FAILURE;
+
+    /* verify and valildate cred handle */
+    if (cred_handle == GSS_C_NO_CREDENTIAL) {
+	kerr = KRB5_NOCREDS_SUPPLIED;
+	goto error_out;
+    }
+    major_status = krb5_gss_validate_cred(&temp_status, cred_handle);
+    if (GSS_ERROR(major_status)) {
+	kerr = temp_status;
+	goto error_out;
+    }
+    cred = (krb5_gss_cred_id_t) cred_handle;
+
+    if (ktypes) {
+	for (i = 0; i < num_ktypes && ktypes[i]; i++) {
+	    if (!krb5_c_valid_enctype(ktypes[i])) {
+		kerr = KRB5_PROG_ETYPE_NOSUPP;
+		goto error_out;
+	    }
+	}
+    } else {
+	kerr = k5_mutex_lock(&cred->lock);
+	if (kerr)
+	    goto error_out;
+	if (cred->req_enctypes)
+	    free(cred->req_enctypes);
+	cred->req_enctypes = NULL;
+	k5_mutex_unlock(&cred->lock);
+	return GSS_S_COMPLETE;
+    }
+
+    /* Copy the requested ktypes into the cred structure */
+    if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * (i + 1)))) {
+	memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
+	new_ktypes[i] = 0;	/* "null-terminate" the list */
+    }
+    else {
+	kerr = ENOMEM;
+	goto error_out;
+    }
+    kerr = k5_mutex_lock(&cred->lock);
+    if (kerr)
+	goto error_out;
+    if (cred->req_enctypes)
+	free(cred->req_enctypes);
+    cred->req_enctypes = new_ktypes;
+    k5_mutex_unlock(&cred->lock);
+
+    /* Success! */
+    return GSS_S_COMPLETE;
+
+error_out:
+    *minor_status = kerr;
+    return(major_status);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/set_ccache.c b/mechglue/src/lib/gssapi/krb5/set_ccache.c
new file mode 100644
index 000000000..810c7a050
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/set_ccache.c
@@ -0,0 +1,91 @@
+/*
+ * lib/gssapi/krb5/set_ccache.c
+ *
+ * Copyright 1999, 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Set ccache name used by gssapi, and optionally obtain old ccache
+ * name.  Caller should not free returned name.
+ */
+
+#include <string.h>
+#include "gssapiP_krb5.h"
+
+OM_uint32 KRB5_CALLCONV 
+gss_krb5_ccache_name(minor_status, name, out_name)
+	OM_uint32 *minor_status;
+	const char *name;
+	const char **out_name;
+{
+    char *old_name = NULL;
+    OM_uint32 err = 0;
+    OM_uint32 minor = 0;
+    char *gss_out_name;
+
+    err = gssint_initialize_library();
+    if (err) {
+	*minor_status = err;
+	return GSS_S_FAILURE;
+    }
+
+    gss_out_name = k5_getspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME);
+
+    if (out_name) {
+        const char *tmp_name = NULL;
+
+        if (!err) {
+            kg_get_ccache_name (&err, &tmp_name);
+        }
+        if (!err) {
+            old_name = gss_out_name;
+            gss_out_name = tmp_name;
+        }            
+    }
+    /* If out_name was NULL, we keep the same gss_out_name value, and
+       don't free up any storage (leave old_name NULL).  */
+
+    if (!err)
+        kg_set_ccache_name (&err, name);
+
+    minor = k5_setspecific(K5_KEY_GSS_KRB5_SET_CCACHE_OLD_NAME, gss_out_name);
+    if (minor) {
+	/* Um.  Now what?  */
+	if (err == 0) {
+	    err = minor;
+	}
+	free(gss_out_name);
+	gss_out_name = NULL;
+    }
+
+    if (!err) {
+        if (out_name) {
+            *out_name = gss_out_name;
+        }
+    }
+    
+    if (old_name != NULL) {
+        free (old_name);
+    }
+    
+    *minor_status = err;
+    return (*minor_status == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
diff --git a/mechglue/src/lib/gssapi/krb5/sign.c b/mechglue/src/lib/gssapi/krb5/sign.c
new file mode 100644
index 000000000..2d192c9bb
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/sign.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+krb5_gss_sign(minor_status, context_handle,
+	      qop_req, message_buffer, 
+	      message_token)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     int qop_req;
+     gss_buffer_t message_buffer;
+     gss_buffer_t message_token;
+{
+   return(kg_seal(minor_status, context_handle, 0,
+		  qop_req, message_buffer, NULL,
+		  message_token, KG_TOK_SIGN_MSG));
+}
+
+/* V2 interface */
+OM_uint32
+krb5_gss_get_mic(minor_status, context_handle, qop_req,
+		 message_buffer, message_token)
+    OM_uint32		*minor_status;
+    gss_ctx_id_t	context_handle;
+    gss_qop_t		qop_req;
+    gss_buffer_t	message_buffer;
+    gss_buffer_t	message_token;
+{
+    return(kg_seal(minor_status, context_handle, 0,
+		   (int) qop_req, message_buffer, NULL,
+		   message_token, KG_TOK_MIC_MSG));
+}
diff --git a/mechglue/src/lib/gssapi/krb5/unseal.c b/mechglue/src/lib/gssapi/krb5/unseal.c
new file mode 100644
index 000000000..71dc11048
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/unseal.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+krb5_gss_unseal(minor_status, context_handle,
+		input_message_buffer, output_message_buffer,
+		conf_state, qop_state)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     gss_buffer_t input_message_buffer;
+     gss_buffer_t output_message_buffer;
+     int *conf_state;
+     int *qop_state;
+{
+   return(kg_unseal(minor_status, context_handle,
+		    input_message_buffer, output_message_buffer,
+		    conf_state, qop_state, KG_TOK_SEAL_MSG));
+}
+
+/* V2 interface */
+OM_uint32
+krb5_gss_unwrap(minor_status, context_handle,
+		input_message_buffer, output_message_buffer,
+		conf_state, qop_state)
+    OM_uint32		*minor_status;
+    gss_ctx_id_t	context_handle;
+    gss_buffer_t	input_message_buffer;
+    gss_buffer_t	output_message_buffer;
+    int			*conf_state;
+    gss_qop_t		*qop_state;
+{
+    OM_uint32		rstat;
+    int			qstate;
+
+    rstat = kg_unseal(minor_status, context_handle,
+		      input_message_buffer, output_message_buffer,
+		      conf_state, &qstate, KG_TOK_WRAP_MSG);
+    if (!rstat && qop_state)
+	*qop_state = (gss_qop_t) qstate;
+    return(rstat);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/util_cksum.c b/mechglue/src/lib/gssapi/krb5/util_cksum.c
new file mode 100644
index 000000000..235d74947
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/util_cksum.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* Checksumming the channel bindings always uses plain MD5.  */
+krb5_error_code
+kg_checksum_channel_bindings(context, cb, cksum, bigend)
+     krb5_context context;
+     gss_channel_bindings_t cb;
+     krb5_checksum *cksum;
+     int bigend;
+{
+   size_t len;
+   char *buf = 0;
+   char *ptr;
+   size_t sumlen;
+   krb5_data plaind;
+   krb5_error_code code;
+   void *temp;
+
+   /* initialize the the cksum */
+   code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &sumlen);
+   if (code)
+       return(code);
+
+   cksum->checksum_type = CKSUMTYPE_RSA_MD5;
+   cksum->length = sumlen;
+ 
+   /* generate a buffer full of zeros if no cb specified */
+
+   if (cb == GSS_C_NO_CHANNEL_BINDINGS) {
+       if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) {
+	   return(ENOMEM);
+       }
+       memset(cksum->contents, '\0', cksum->length);
+       return(0);
+   }
+
+   /* create the buffer to checksum into */
+
+   len = (sizeof(krb5_int32)*5+
+	  cb->initiator_address.length+
+	  cb->acceptor_address.length+
+	  cb->application_data.length);
+
+   if ((buf = (char *) xmalloc(len)) == NULL)
+      return(ENOMEM);
+
+   /* helper macros.  This code currently depends on a long being 32
+      bits, and htonl dtrt. */
+
+   ptr = buf;
+
+   TWRITE_INT(ptr, cb->initiator_addrtype, bigend);
+   TWRITE_BUF(ptr, cb->initiator_address, bigend);
+   TWRITE_INT(ptr, cb->acceptor_addrtype, bigend);
+   TWRITE_BUF(ptr, cb->acceptor_address, bigend);
+   TWRITE_BUF(ptr, cb->application_data, bigend);
+
+   /* checksum the data */
+
+   plaind.length = len;
+   plaind.data = buf;
+
+   code = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, 0, 0,
+			       &plaind, cksum);
+   if (code)
+       goto cleanup;
+
+   if ((temp = xmalloc(cksum->length)) == NULL) {
+       krb5_free_checksum_contents(context, cksum);
+       code = ENOMEM;
+       goto cleanup;
+   }
+
+   memcpy(temp, cksum->contents, cksum->length);
+   krb5_free_checksum_contents(context, cksum);
+   cksum->contents = (krb5_octet *)temp;
+
+   /* success */
+ cleanup:
+   if (buf)
+       xfree(buf);
+   return code;
+}
diff --git a/mechglue/src/lib/gssapi/krb5/util_crypt.c b/mechglue/src/lib/gssapi/krb5/util_crypt.c
new file mode 100644
index 000000000..dad4b023d
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/util_crypt.c
@@ -0,0 +1,240 @@
+/*
+  * Copyright2001 by the Massachusetts Institute of Technology.
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+int
+kg_confounder_size(context, key)
+     krb5_context context;
+     krb5_keyblock *key;
+{
+   krb5_error_code code;
+   size_t blocksize;
+   /* We special case rc4*/
+   if (key->enctype == ENCTYPE_ARCFOUR_HMAC)
+     return 8;
+   code = krb5_c_block_size(context, key->enctype, &blocksize);
+   if (code)
+      return(-1); /* XXX */
+
+   return(blocksize);
+}
+
+krb5_error_code
+kg_make_confounder(context, key, buf)
+     krb5_context context;
+     krb5_keyblock *key;
+     unsigned char *buf;
+{
+   krb5_error_code code;
+   size_t blocksize;
+   krb5_data lrandom;
+
+   code = krb5_c_block_size(context, key->enctype, &blocksize);
+   if (code)
+       return(code);
+
+   lrandom.length = blocksize;
+   lrandom.data = buf;
+
+   return(krb5_c_random_make_octets(context, &lrandom));
+}
+
+krb5_error_code
+kg_encrypt(context, key, usage, iv, in, out, length)
+     krb5_context context;
+     krb5_keyblock *key;
+     int usage;
+     krb5_pointer iv;
+     krb5_const_pointer in;
+     krb5_pointer out;
+     unsigned int length;
+{
+   krb5_error_code code;
+   size_t blocksize;
+   krb5_data ivd, *pivd, inputd;
+   krb5_enc_data outputd;
+
+   if (iv) {
+       code = krb5_c_block_size(context, key->enctype, &blocksize);
+       if (code)
+	   return(code);
+
+       ivd.length = blocksize;
+       ivd.data = malloc(ivd.length);
+       if (ivd.data == NULL)
+	   return ENOMEM;
+       memcpy(ivd.data, iv, ivd.length);
+       pivd = &ivd;
+   } else {
+       pivd = NULL;
+   }
+
+   inputd.length = length;
+   inputd.data = in;
+
+   outputd.ciphertext.length = length;
+   outputd.ciphertext.data = out;
+
+   code = krb5_c_encrypt(context, key, usage, pivd, &inputd, &outputd);
+   if (pivd != NULL)
+       free(pivd->data);
+   return code;
+}
+
+/* length is the length of the cleartext. */
+
+krb5_error_code
+kg_decrypt(context, key, usage, iv, in, out, length)
+     krb5_context context;
+     krb5_keyblock *key;
+     int usage;
+     krb5_pointer iv;
+     krb5_const_pointer in;
+     krb5_pointer out;
+     unsigned int length;
+{
+   krb5_error_code code;
+   size_t blocksize;
+   krb5_data ivd, *pivd, outputd;
+   krb5_enc_data inputd;
+
+   if (iv) {
+       code = krb5_c_block_size(context, key->enctype, &blocksize);
+       if (code)
+	   return(code);
+
+       ivd.length = blocksize;
+       ivd.data = malloc(ivd.length);
+       if (ivd.data == NULL)
+	   return ENOMEM;
+       memcpy(ivd.data, iv, ivd.length);
+       pivd = &ivd;
+   } else {
+       pivd = NULL;
+   }
+
+   inputd.enctype = ENCTYPE_UNKNOWN;
+   inputd.ciphertext.length = length;
+   inputd.ciphertext.data = in;
+
+   outputd.length = length;
+   outputd.data = out;
+
+   code = krb5_c_decrypt(context, key, usage, pivd, &inputd, &outputd);
+   if (pivd != NULL)
+       free(pivd->data);
+   return code;
+}
+
+krb5_error_code
+kg_arcfour_docrypt (const krb5_keyblock *longterm_key , int ms_usage,
+		    const unsigned char *kd_data, size_t kd_data_len,
+		    const unsigned char *input_buf, size_t input_len,
+		    unsigned char *output_buf)
+{
+  krb5_error_code code;
+  krb5_data input, output;
+  krb5int_access kaccess;
+  krb5_keyblock seq_enc_key, usage_key;
+  unsigned char t[4];
+
+  usage_key.length = longterm_key->length;
+  usage_key.contents = malloc(usage_key.length);
+  if (usage_key.contents == NULL)
+    return (ENOMEM);
+  seq_enc_key.length = longterm_key->length;
+  seq_enc_key.contents = malloc(seq_enc_key.length);
+  if (seq_enc_key.contents == NULL) {
+    free ((void *) usage_key.contents);
+    return (ENOMEM);
+  }
+  code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
+  if (code)
+    goto cleanup_arcfour;
+
+  t[0] = ms_usage &0xff;
+  t[1] = (ms_usage>>8) & 0xff;
+  t[2] = (ms_usage>>16) & 0xff;
+  t[3] = (ms_usage>>24) & 0xff;
+  input.data = (void *) &t;
+  input.length = 4;
+  output.data = (void *) usage_key.contents;
+  output.length = usage_key.length;
+  code = (*kaccess.krb5_hmac) (kaccess.md5_hash_provider,
+			       longterm_key, 1, &input, &output);
+  if (code)
+    goto cleanup_arcfour;
+	  
+  input.data = ( void *) kd_data;
+  input.length = kd_data_len;
+  output.data = (void *) seq_enc_key.contents;
+  code = (*kaccess.krb5_hmac) (kaccess.md5_hash_provider,
+			       &usage_key, 1, &input, &output);
+  if (code)
+    goto cleanup_arcfour;
+  input.data = ( void * ) input_buf;
+  input.length = input_len;
+  output.data = (void * ) output_buf;
+  output.length = input_len;
+  code =  ((*kaccess.arcfour_enc_provider->encrypt)(
+						    &seq_enc_key, 0, 
+						    &input, &output));
+ cleanup_arcfour:
+  memset ((void *) seq_enc_key.contents, 0, seq_enc_key.length);
+  memset ((void *) usage_key.contents, 0, usage_key.length);
+  free ((void *) usage_key.contents);
+  free ((void *) seq_enc_key.contents);
+  return (code);
+}
+		    
diff --git a/mechglue/src/lib/gssapi/krb5/util_seed.c b/mechglue/src/lib/gssapi/krb5/util_seed.c
new file mode 100644
index 000000000..9d39e4937
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/util_seed.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+static const unsigned char zeros[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
+
+krb5_error_code
+kg_make_seed(context, key, seed)
+     krb5_context context;
+     krb5_keyblock *key;
+     unsigned char *seed;
+{
+   krb5_error_code code;
+   krb5_keyblock *tmpkey;
+   int i;
+
+   code = krb5_copy_keyblock(context, key, &tmpkey);
+   if (code)
+      return(code);
+
+   /* reverse the key bytes, as per spec */
+
+   for (i=0; i<tmpkey->length; i++)
+      tmpkey->contents[i] = key->contents[key->length - 1 - i];
+
+   code = kg_encrypt(context, tmpkey, KG_USAGE_SEAL, NULL, zeros, seed, 16);
+
+   krb5_free_keyblock(context, tmpkey);
+
+   return(code);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/util_seqnum.c b/mechglue/src/lib/gssapi/krb5/util_seqnum.c
new file mode 100644
index 000000000..ec7da5567
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/util_seqnum.c
@@ -0,0 +1,105 @@
+/*
+  * Copyright2001 by the Massachusetts Institute of Technology.
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+#include "k5-int.h"
+
+/*
+ * $Id$
+ */
+
+krb5_error_code
+kg_make_seq_num(context, key, direction, seqnum, cksum, buf)
+     krb5_context context;
+     krb5_keyblock *key;
+     int direction;
+     krb5_ui_4 seqnum;
+     unsigned char *cksum;
+     unsigned char *buf;
+{
+   unsigned char plain[8];
+
+   plain[4] = direction;
+   plain[5] = direction;
+   plain[6] = direction;
+   plain[7] = direction;
+   if (key->enctype == ENCTYPE_ARCFOUR_HMAC ) {
+     /* Yes, Microsoft used big-endian sequence number.*/
+     plain[0] = (seqnum>>24) & 0xff;
+     plain[1] = (seqnum>>16) & 0xff;
+     plain[2] = (seqnum>>8) & 0xff;
+     plain[3] = seqnum & 0xff;
+     return kg_arcfour_docrypt (key, 0, 
+				cksum, 8,
+				&plain[0], 8,
+				buf);
+     
+   }
+     
+   plain[0] = (unsigned char) (seqnum&0xff);
+   plain[1] = (unsigned char) ((seqnum>>8)&0xff);
+   plain[2] = (unsigned char) ((seqnum>>16)&0xff);
+   plain[3] = (unsigned char) ((seqnum>>24)&0xff);
+
+   return(kg_encrypt(context, key, KG_USAGE_SEQ, cksum, plain, buf, 8));
+}
+
+krb5_error_code kg_get_seq_num(context, key, cksum, buf, direction, seqnum)
+     krb5_context context;
+     krb5_keyblock *key;
+     unsigned char *cksum;
+     unsigned char *buf;
+     int *direction;
+     krb5_ui_4 *seqnum;
+{
+   krb5_error_code code;
+   unsigned char plain[8];
+
+   if (key->enctype == ENCTYPE_ARCFOUR_HMAC) {
+     code = kg_arcfour_docrypt (key, 0,
+				cksum, 8,
+				buf, 8,
+				plain);
+   } else {
+     code = kg_decrypt(context, key, KG_USAGE_SEQ, cksum, buf, plain, 8);
+   }
+   if (code)
+      return(code);
+
+   if ((plain[4] != plain[5]) ||
+       (plain[4] != plain[6]) ||
+       (plain[4] != plain[7]))
+      return((krb5_error_code) KG_BAD_SEQ);
+
+   *direction = plain[4];
+   if (key->enctype == ENCTYPE_ARCFOUR_HMAC) {
+     *seqnum = (plain[3]|(plain[2]<<8) | (plain[1]<<16)| (plain[0]<<24));
+   } else {
+     *seqnum = ((plain[0]) |
+	      (plain[1]<<8) |
+	      (plain[2]<<16) |
+	      (plain[3]<<24));
+   }
+
+   return(0);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/val_cred.c b/mechglue/src/lib/gssapi/krb5/val_cred.c
new file mode 100644
index 000000000..1fdb3c298
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/val_cred.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright 1997 by Massachusetts Institute of Technology
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * Check to see whether or not a GSSAPI krb5 credential is valid.  If
+ * it is not, return an error.
+ */
+
+OM_uint32
+krb5_gss_validate_cred_1(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
+			 krb5_context context)
+{
+    krb5_gss_cred_id_t cred;
+    krb5_error_code code;
+    krb5_principal princ;
+
+    if (!kg_validate_cred_id(cred_handle)) {
+	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_DEFECTIVE_CREDENTIAL);
+    }
+
+    cred = (krb5_gss_cred_id_t) cred_handle;
+
+    code = k5_mutex_lock(&cred->lock);
+    if (code) {
+	*minor_status = code;
+	return GSS_S_FAILURE;
+    }
+
+    if (cred->ccache) {
+	if ((code = krb5_cc_get_principal(context, cred->ccache, &princ))) {
+	    k5_mutex_unlock(&cred->lock);
+	    *minor_status = code;
+	    return(GSS_S_DEFECTIVE_CREDENTIAL);
+	}
+	if (!krb5_principal_compare(context, princ, cred->princ)) {
+	    k5_mutex_unlock(&cred->lock);
+	    *minor_status = KG_CCACHE_NOMATCH;
+	    return(GSS_S_DEFECTIVE_CREDENTIAL);
+	}
+	(void)krb5_free_principal(context, princ);
+    }
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+krb5_gss_validate_cred(minor_status, cred_handle)
+     OM_uint32 *minor_status;
+     gss_cred_id_t cred_handle;
+{
+    krb5_context context;
+    krb5_error_code code;
+    OM_uint32 maj;
+
+    code = krb5_init_context(&context);
+    if (code) {
+	*minor_status = code;
+	return GSS_S_FAILURE;
+    }
+
+    maj = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
+    if (maj == 0) {
+	krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t) cred_handle;
+	k5_mutex_assert_locked(&cred->lock);
+	k5_mutex_unlock(&cred->lock);
+    }
+    krb5_free_context(context);
+    return maj;
+}
+
+		
+
+
diff --git a/mechglue/src/lib/gssapi/krb5/verify.c b/mechglue/src/lib/gssapi/krb5/verify.c
new file mode 100644
index 000000000..833697b19
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/verify.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/*
+ * $Id$
+ */
+
+OM_uint32
+krb5_gss_verify(minor_status, context_handle,
+		message_buffer, token_buffer,
+		qop_state)
+     OM_uint32 *minor_status;
+     gss_ctx_id_t context_handle;
+     gss_buffer_t message_buffer;
+     gss_buffer_t token_buffer;
+     int *qop_state;
+{
+     return(kg_unseal(minor_status, context_handle,
+		      token_buffer, message_buffer,
+		      NULL, qop_state, KG_TOK_SIGN_MSG));
+}
+
+/* V2 interface */
+OM_uint32
+krb5_gss_verify_mic(minor_status, context_handle,
+		    message_buffer, token_buffer,
+		    qop_state)
+    OM_uint32		*minor_status;
+    gss_ctx_id_t	context_handle;
+    gss_buffer_t	message_buffer;
+    gss_buffer_t	token_buffer;
+    gss_qop_t		*qop_state;
+{
+    OM_uint32		rstat;
+    int			qstate;
+
+    rstat = kg_unseal(minor_status, context_handle,
+		      token_buffer, message_buffer,
+		      NULL, &qstate, KG_TOK_MIC_MSG);
+    if (!rstat && qop_state)
+	*qop_state = (gss_qop_t) qstate;
+    return(rstat);
+}
diff --git a/mechglue/src/lib/gssapi/krb5/wrap_size_limit.c b/mechglue/src/lib/gssapi/krb5/wrap_size_limit.c
new file mode 100644
index 000000000..460070637
--- /dev/null
+++ b/mechglue/src/lib/gssapi/krb5/wrap_size_limit.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2000 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+
+/* V2 interface */
+OM_uint32
+krb5_gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
+			 qop_req, req_output_size, max_input_size)
+    OM_uint32		*minor_status;
+    gss_ctx_id_t	context_handle;
+    int			conf_req_flag;
+    gss_qop_t		qop_req;
+    OM_uint32		req_output_size;
+    OM_uint32		*max_input_size;
+{
+    krb5_gss_ctx_id_rec	*ctx;
+    OM_uint32		data_size, conflen;
+    OM_uint32		ohlen;
+    int			overhead;
+
+    /* only default qop is allowed */
+    if (qop_req != GSS_C_QOP_DEFAULT) {
+	*minor_status = (OM_uint32) G_UNKNOWN_QOP;
+	return(GSS_S_FAILURE);
+    }
+    
+    /* validate the context handle */
+    if (! kg_validate_ctx_id(context_handle)) {
+	*minor_status = (OM_uint32) G_VALIDATE_FAILED;
+	return(GSS_S_NO_CONTEXT);
+    }
+    
+    ctx = (krb5_gss_ctx_id_rec *) context_handle;
+    if (! ctx->established) {
+	*minor_status = KG_CTX_INCOMPLETE;
+	return(GSS_S_NO_CONTEXT);
+    }
+
+    if (ctx->proto == 1) {
+	/* No pseudo-ASN.1 wrapper overhead, so no sequence length and
+	   OID.  */
+	OM_uint32 sz = req_output_size;
+	/* Token header: 16 octets.  */
+	if (conf_req_flag) {
+	    while (sz > 0 && krb5_encrypt_size(sz, ctx->enc->enctype) + 16 > req_output_size)
+		sz--;
+	    /* Allow for encrypted copy of header.  */
+	    if (sz > 16)
+		sz -= 16;
+	    else
+		sz = 0;
+#ifdef CFX_EXERCISE
+	    /* Allow for EC padding.  In the MIT implementation, only
+	       added while testing.  */
+	    if (sz > 65535)
+		sz -= 65535;
+	    else
+		sz = 0;
+#endif
+	} else {
+	    /* Allow for token header and checksum.  */
+	    if (sz < 16 + ctx->cksum_size)
+		sz = 0;
+	    else
+		sz -= (16 + ctx->cksum_size);
+	}
+
+	*max_input_size = sz;
+	*minor_status = 0;
+	return GSS_S_COMPLETE;
+    }
+
+    /* Calculate the token size and subtract that from the output size */
+    overhead = 7 + ctx->mech_used->length;
+    data_size = req_output_size;
+    conflen = kg_confounder_size(ctx->k5_context, ctx->enc);
+    data_size = (conflen + data_size + 8) & (~(OM_uint32)7);
+    ohlen = g_token_size((gss_OID) ctx->mech_used,
+			 (unsigned int) (data_size + ctx->cksum_size + 14))
+      - req_output_size;
+
+    if (ohlen+overhead < req_output_size)
+      /*
+       * Cannot have trailer length that will cause us to pad over our
+       * length.
+       */
+      *max_input_size = (req_output_size - ohlen - overhead) & (~(OM_uint32)7);
+    else
+      *max_input_size = 0;
+
+    *minor_status = 0;
+    return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/libgssapi_krb5.exports b/mechglue/src/lib/gssapi/libgssapi_krb5.exports
new file mode 100644
index 000000000..46a52d168
--- /dev/null
+++ b/mechglue/src/lib/gssapi/libgssapi_krb5.exports
@@ -0,0 +1,108 @@
+GSS_C_NT_ANONYMOUS
+GSS_C_NT_EXPORT_NAME
+GSS_C_NT_HOSTBASED_SERVICE
+GSS_C_NT_HOSTBASED_SERVICE_X
+GSS_C_NT_MACHINE_UID_NAME
+GSS_C_NT_STRING_UID_NAME
+GSS_C_NT_USER_NAME
+GSS_KRB5_NT_PRINCIPAL_NAME
+gss_accept_sec_context
+gss_acquire_cred
+gss_add_cred
+gss_add_oid_set_member
+gss_canonicalize_name
+gss_compare_name
+gss_context_time
+gss_create_empty_oid_set
+gss_delete_sec_context
+gss_display_name
+gss_display_status
+gss_duplicate_name
+gss_export_name
+gss_export_sec_context
+gss_get_mic
+gss_import_name
+gss_import_sec_context
+gss_indicate_mechs
+gss_init_sec_context
+gss_inquire_context
+gss_inquire_cred
+gss_inquire_cred_by_mech
+gss_inquire_names_for_mech
+gss_krb5_ccache_name
+gss_krb5_copy_ccache
+gss_krb5_export_lucid_sec_context
+gss_krb5_get_tkt_flags
+gss_krb5_free_lucid_sec_context
+gss_krb5_set_allowable_enctypes
+gss_krb5int_make_seal_token_v3
+gss_krb5int_unseal_token_v3
+gss_mech_krb5
+gss_mech_krb5_old
+gss_mech_set_krb5
+gss_mech_set_krb5_both
+gss_mech_set_krb5_old
+gss_nt_exported_name
+gss_nt_krb5_name
+gss_nt_krb5_principal
+gss_nt_machine_uid_name
+gss_nt_service_name
+gss_nt_service_name_v2
+gss_nt_string_uid_name
+gss_nt_user_name
+gss_oid_to_str
+gss_process_context_token
+gss_release_buffer
+gss_release_cred
+gss_release_name
+gss_release_oid
+gss_release_oid_set
+gss_seal
+gss_sign
+gss_str_to_oid
+gss_test_oid_set_member
+gss_unseal
+gss_unwrap
+gss_verify
+gss_verify_mic
+gss_wrap
+gss_wrap_size_limit
+krb5_gss_accept_sec_context
+krb5_gss_acquire_cred
+krb5_gss_add_cred
+krb5_gss_canonicalize_name
+krb5_gss_compare_name
+krb5_gss_context_time
+krb5_gss_convert_static_mech_oid
+krb5_gss_dbg_client_expcreds
+krb5_gss_delete_sec_context
+krb5_gss_display_name
+krb5_gss_display_status
+krb5_gss_duplicate_name
+krb5_gss_export_name
+krb5_gss_export_sec_context
+krb5_gss_get_mic
+krb5_gss_import_name
+krb5_gss_import_sec_context
+krb5_gss_indicate_mechs
+krb5_gss_init_sec_context
+krb5_gss_inquire_context
+krb5_gss_inquire_cred
+krb5_gss_inquire_cred_by_mech
+krb5_gss_inquire_names_for_mech
+krb5_gss_oid_array
+krb5_gss_process_context_token
+krb5_gss_register_acceptor_identity
+krb5_gss_release_cred
+krb5_gss_release_name
+krb5_gss_release_oid
+krb5_gss_seal
+krb5_gss_ser_init
+krb5_gss_sign
+krb5_gss_unseal
+krb5_gss_unwrap
+krb5_gss_validate_cred
+krb5_gss_verify
+krb5_gss_verify_mic
+krb5_gss_wrap
+krb5_gss_wrap_size_limit
diff --git a/mechglue/src/lib/gssapi/mechglue/.Sanitize b/mechglue/src/lib/gssapi/mechglue/.Sanitize
new file mode 100644
index 000000000..6e21578df
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/.Sanitize
@@ -0,0 +1,71 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+g_accept_sec_context.c
+g_acquire_cred.c
+g_compare_name.c
+g_context_time.c
+g_delete_sec_context.c
+g_dsp_name.c
+g_dsp_status.c
+g_exp_sec_context.c
+g_glue.c
+g_imp_name.c
+g_imp_sec_context.c
+g_indicate_mechs.c
+g_init_sec_context.c
+g_initialize.c
+g_inq_context.c
+g_inq_cred.c
+g_inq_names.c
+g_mechname.c
+g_oid_ops.c
+g_process_context.c
+g_rel_buffer.c
+g_rel_cred.c
+g_rel_name.c
+g_rel_oid_set.c
+g_seal.c
+g_sign.c
+g_unseal.c
+g_verify.c
+gen_oids.c
+gssd_pname_to_uid.c
+mech.conf
+mechglue.h
+mglueP.h
+oid_ops.c
+
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/gssapi/mechglue/ChangeLog b/mechglue/src/lib/gssapi/mechglue/ChangeLog
new file mode 100644
index 000000000..9c7ec1894
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/ChangeLog
@@ -0,0 +1,372 @@
+2004-09-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Delete @SHARED_RULE@ line.
+	(thisconfigdir): Fix.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* g_initialize.c, oid_ops.c: Don't test macintosh.
+	* mechglue.h: Don't test __MWERKS__, applec, THINK_C.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac, clean-mac): Targets deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* mechglue.h: Make prototypes unconditional.
+	* mglueP.h: Make all prototypes unconditional.
+	(NPROTOTYPE): Macro deleted.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* g_initialize.c, mglueP.h: Drop _MSDOS support.
+
+	* g_init_sec_context.c: Don't declare pointers FAR any more.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* g_acquire_cred.c, g_oid_ops.c: Don't use GSS_DLLIMP.
+
+2001-04-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unixmac): Target deleted.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:22:42 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1999-02-19  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (DLL_FILE_DEF): Tell the Makefile template that we
+		are building object files for the GSSAPI DLL.
+
+	* g_acquire_cred.c, g_oid_ops.c: Change use of KRB5_DLLIMP to be
+		GSS_DLLIMP.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Wed Feb 18 16:12:43 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trialing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Feb  5 10:37:00 1996  Richard Basch  <basch@lehman.com>
+
+	* g_accept_sec_context.c g_acquire_cred.c g_compare_name.c
+	  g_context_time.c g_delete_sec_context.c g_dsp_name.c
+	  g_dsp_status.c g_exp_sec_context.c g_imp_name.c
+	  g_imp_sec_context.c g_indicate_mechs.c g_init_sec_context.c
+	  g_inq_context.c g_inq_cred.c g_inq_names.c g_process_context.c
+	  g_rel_buffer.c g_rel_cred.c g_rel_name.c g_rel_oid_set.c
+	  g_seal.c g_sign.c g_unseal.c g_verify.c
+		Changed INTERFACE keyword to KRB5_CALLCONV
+
+Mon Nov 18 20:43:54 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Shared library version number to 1.0. [krb5-libs/201]
+
+Wed Jun 12 00:50:32 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Remove include of config/windows.in; that's done
+		automatically by wconfig.
+
+	* g_acquire_cred.c, g_oid_ops.c: Change to use new convention of
+		KRB5_CALLCONV and KRB5_DLLIMP instead of INTERFACE
+
+Wed May 22 07:48:21 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (libgssapi.$(STEXT)): Remove unnecessary install rule for libgssapi.a.
+
+Mon May 20 23:56:46 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in: Don't make libgssapi.a on AIX.  It is handled incorrectly becaus all symbols are not resolved, and it isn't useful as a non-shared library.
+	
+
+Fri May  3 16:43:43 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* g_inq_cred.c (gss_inquire_cred): Add code to support appropriate
+		behavior when the input credentials is NULL (i.e., the
+		default credential).  We use the default credential for
+		the "default mechanism", which is the first mechanism
+		registered with the library.
+
+Thu Apr 11 20:11:00 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* g_acquire_cred.c (gss_add_cred): Fixed code to correctly handle
+		errors reported from the mechanism layer.
+
+Wed Mar 27 00:05:37 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* mglueP.h: Don't include <sys/types.h> mechglue.h will take care
+		of this by including gssapi.h, which will include
+		sys/types.h if necessary.
+
+Thu Mar 21 00:12:07 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* g_imp_sec_context.c (gss_import_sec_context):
+	* g_exp_sec_context.c (gss_export_sec_context): Fix 16bit vs 32bit
+		lint flame.
+
+Wed Mar 20 20:20:38 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* g_glue.c: 
+	* g_initialize.c: Add include of string.h, as it is needed.
+
+	* g_acquire_cred.c: 
+	* g_inq_cred.c: Add include of time.h
+
+	* g_rel_oid_set.c (gss_release_oid_set): Removed unused variable.
+
+	* mechglue.h: Don't include <sys/types.h>; it's included if
+		necessary in gssapi/gssapi.h.  On a Macintosh, #include
+		gssapi.h instead of gssapi/gssapi.h.
+
+	* g_accept_sec_context.c, g_acquire_cred.c, g_compare_name.c,
+	g_context_time.c, g_delete_sec_context.c, g_dsp_name.c,
+	g_dsp_status.c, g_exp_sec_context.c, g_glue.c, g_imp_name.c,
+	g_imp_sec_context.c, g_indicate_mechs.c, g_init_sec_context.c,
+	g_initialize.c, g_inq_context.c, g_inq_cred.c, g_inq_names.c,
+	g_process_context.c, g_rel_buffer.c, g_rel_cred.c, g_rel_name.c,
+	g_rel_oid_set.c, g_seal.c, g_sign.c, g_unseal.c, g_verify.c,
+	gssd_pname_to_uid.c, mechglue.h, mglueP.h: Comment out #ident
+		line.  This causes the Macintosh C compiler indigestion.
+
+Tue Mar 12 23:28:57 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* mechglue.h (gssd_pname_to_uid, gss_initialize): Use PROTOTYPE
+	macro in declarations.
+
+Sun Mar  3 12:49:25 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* g_imp_sec_context.c, g_exp_sec_context.c: Include string.h
+
+Thu Feb 29 11:32:16 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* g_glue.c (__gss_get_mech_type): Fix code to properly parse token
+		headers.  It was working only by serendipity....
+
+	* g_accept_sec_context.c (gss_accept_sec_context): Add error
+		checking and memory cleanup.  Make gss_accept_sec_context
+		work for mechanisms that use multiple token roundtrips.
+
+Wed Feb 28 20:33:47 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* mglueP.h: For MS-DOS, add #include of malloc.h
+
+	* g_acquire_cred.c (gss_acquire_cred): Fix so that the call works
+		when desired_name is NULL (meaning use the default
+		credentials).
+
+	* g_imp_sec_context.c (gss_import_sec_context): 
+	* g_exp_sec_context.c (gss_export_sec_context): Fix to 
+		import/export the framing security context (so that this
+		call actually works!).
+
+Tue Feb 27 18:44:51 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* g_initialize.c (gss_initialize): Don't fprintf to stderr on
+		Macintoshes and Windows.
+
+	* g_inq_context.c: Add INTERFACE keyword for Windows.
+
+	* oid_ops.c: Protect include of unistd.h with HAVE_UNISTD_H
+
+Sun Feb 25 15:39:08 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* g_acquire_cred.c, g_delete_sec_context.c, g_dsp_name.c,
+	g_dsp_status.c, g_exp_sec_context.c, g_glue.c, g_imp_name.c,
+	g_imp_sec_context.c, g_indicate_mechs.c, g_init_sec_context.c,
+	g_inq_cred.c, g_rel_buffer.c, g_rel_cred.c, g_rel_name.c,
+	g_rel_oid_set.c: include stdio.h to actually get NULL.
+
+Sat Feb 24 16:19:30 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in, g_inquire_cred.c, g_inquire_names.c,
+		g_inquire_context.c: Renamed files to g_inq_cred.c,
+		g_inq_names.c, and g_inq_context.c, respectively.
+
+	* g_acquire_cred.c (gss_add_cred): New GSSAPI V2 function.
+
+	* g_inquire_cred.c (gss_inquire_cred_by_mech): New GSSAPI V2
+		function. 
+
+	* g_init_sec_context.c (gss_init_sec_context): Make sure we
+		convert the union credential into a mechanism specific
+		credential.
+
+	* g_glue.c (__gss_get_mechanism_cred): New function for returning
+		the mechanism-specific credential from a union credential.
+
+	* g_inquire_names.c (gss_inquire_names_for_mech): 
+	* g_oid_ops.c (gss_str_to_oid, gss_oid_to_str, 
+		gss_test_oid_set_member, gss_add_oid_set_member,
+		gss_create_empty_oid_set, gss_release_oid): 
+	* g_imp_sec_context.c (gss_import_sec_context): 
+	* g_exp_sec_context.c (gss_export_sec_context):
+	* g_inquire_cred.c (gss_inquire_cred): 
+	* g_rel_oid_set.c (gss_release_oid_set): 
+	* g_rel_buffer.c (gss_release_buffer): 
+	* g_rel_name.c (gss_release_name): 
+	* g_imp_name.c (gss_import_name): 
+	* g_dsp_name.c (gss_display_name): 
+	* g_compare_name.c (gss_compare_name):
+	* g_indicate_mechs.c (gss_indicate_mechs):
+	* g_dsp_status.c (gss_display_status): 
+	* g_unseal.c (gss_unseal, gss_unwrap): 
+	* g_seal.c (gss_seal, gss_wrap):
+	* g_verify.c (gss_verify, gss_verify_mic): 
+	* g_sign.c (gss_sign, gss_get_mic):
+	* g_context_time.c (gss_context_time): 
+	* g_delete_sec_context.c (gss_delete_sec_context): 
+	* g_process_context.c (gss_process_context): 
+	* g_accept_sec_context.c (gss_accept_sec_context): 
+	* g_init_sec_context.c (gss_init_sec_context): 
+	* g_rel_cred.c (gss_release_cred): 
+	* g_acquire_cred.c (gss_acquire_cred): Added INTERFACE keyword for
+		Windows.
+
+	* mglueP.h:
+	* g_seal.c: Add support for new V2 call gss_wrap_size_limit()
+
+	* g_mechname.c (gss_add_mech_name_type): Only mark a name-type as
+		being non-mechanism-specific if the mechanism doesn't
+		match the type currently associated with the name-type.
+
+	* g_init_sec_context.c (gss_init_security_context): If we are
+		using a mechanism-specific name, use the
+		mechanism-specific name directly, instead of calling
+		__gss_internal_import() on the external form of the name.
+		If the mechanism_type is unspecified, use the type of the
+		mechanism-specific name.  If the mechanism_type is
+		specified, it must match the type of the supplied name.
+
+	* g_acquire_cred.c (gss_acquire_cred): If we are acquiring
+		credentials for a mechanism-specific name, use the name
+		directly, instead of doing an __gss_internal_import() on
+		the name.  Also, if the desired_mechanisms oid is NULL,
+		default to using the mechanism-type of the
+		mechanism-specific name.
+
+	* g_compare_name.c (gss_compare_name): Add logic for comparing
+		mechanism-specific names.
+
+	* g_accept_sec_context.c (gss_accept_sec_context): Use
+		__gss_convert_name_to_union_name() to take the gss_name_t
+		returned by the mechanism accept_sec_context(), and
+		convert it into a mechanism-specific union name.
+
+	* g_inquire_context.c (gss_inquire_context):  Removed local static
+		function convert_name_to_union_name(), and changed
+		references to it use the generalized
+		__gss_convert_name_to_union_name() call.
+
+	* g_glue.c (__gss_convert_name_to_union_name): New function which
+		takes gss_name_t returned by a particular mechanism, and
+		converts it into a gss_union_name.
+
+	* g_rel_oid_set.c (gss_release_oid_set): Manually free the oids in
+		an OID set, since the containing structure is allocated as
+		an array.
+
+Sat Feb 24 12:21:03 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* mglueP.h (gss_config): Change int fields to OM_uint32 to match
+		arguments to procedure calls in gss_init_sec_context,
+		gss_accept_sec_context, and gss_display_status.
+
+Sat Feb 24 00:00:27 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* g_imp_name.c (gss_import_name): If the user passes in a
+		name-type which is mechanism specific, then import it
+		immediately; don't lazy evaluate it.
+
+	* g_mechname.c (gss_add_mech_name_type): New file for maintaining
+		a registry of name-types which are mechanism specific.
+
+	* g_dsp_name.c (gss_display_name): If there is a mechanism
+		specific name, use it when displaying the name.
+
+	* oid_ops.c (generic_gss_copy_oid): New function used to copy an
+		OID object.
+
+Fri Feb 23 18:27:20 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* g_rel_name.c (gss_release_name): Release the OID in the
+		mechanism name, as it is now allocated.  Release the
+		mechanism-specific name if it is present.
+
+	* g_imp_name.c (gss_import_name):  Copy the input OID, so we don't
+		have to worry about memory allocation problems later.
+		Initialize mech_type and mech_name in the union name to be
+		zero.  (for now)
+
+	* oid_ops.c (generic_gss_copy_oid): Added new function to copy OIDs.
+
+Thu Feb 22 21:48:44 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* mglueP.h: Add space for the mechanism name in gss_union_name.
+
+Sat Feb 10 18:38:43 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* g_glue.c: grab stdlib.h to get NULL
+
+Fri Feb  9 09:04:50 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* g_inquire_context.c: Include stdlib.h if present
+
+Wed Feb  7 14:16:01 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* g_initialize.c: Need to include stdio.h, errno.h all the time.
+
+Tue Feb  6 23:59:49 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* g_initialize.c (gss_initialize): Added code to try to
+		dynamically read in the GSSAPI mechanim library using
+		dlopen().
+
+Wed Jan 24 20:49:13 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* g_compare_name.c, g_delete_sec_context.c, g_dsp_status.c,
+	g_exp_sec_context.c, g_imp_sec_context.c, g_rel_buffer.c,
+	g_rel_cred.c, g_rel_name.c, g_rel_oid_set.c, get_mechanism.c,
+	get_mtype.c: Include stdlib.h and string.h as needed
+
+	* mglueP.h: Add many invocations of NPROTOTYPE and PROTOTYPE to
+		prevent breakage.
+
+Tue Jan 23 11:52:24 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* add_mechanism.c, g_inquire_cred.c, g_imp_name.c,
+	  g_dsp_name.c, g_indicate_mechs.c, g_accept_sec_context.c,
+	  g_init_sec_context.c, g_acquire_cred.c: Include stdlib.h, string.h
+
+	* configure.in: Check for stdlib.h
+
+	* Makefile.in (SRCS): Remove extraneous line with only a tab.
+		(SHLIB_LDFLAGS): Declare that krb5_gss_initialize is to be
+		unresolved. 
+
+
diff --git a/mechglue/src/lib/gssapi/mechglue/Makefile.in b/mechglue/src/lib/gssapi/mechglue/Makefile.in
new file mode 100644
index 000000000..f7988b7e7
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/Makefile.in
@@ -0,0 +1,102 @@
+thisconfigdir=./..
+myfulldir=lib/gssapi/mechglue
+mydir=mechglue
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I. -I$(srcdir) -I$(srcdir)/.. -I../generic -I$(srcdir)/../generic
+
+##DOSBUILDTOP = ..\..\..
+##DOSLIBNAME=..\$(OUTPRE)gssapi.$(LIBEXT)
+
+##DOS##DLL_EXP_TYPE=GSS
+
+SRCS = \
+	$(srcdir)/g_accept_sec_context.c \
+	$(srcdir)/g_acquire_cred.c \
+	$(srcdir)/g_canon_name.c \
+	$(srcdir)/g_compare_name.c \
+	$(srcdir)/g_context_time.c \
+	$(srcdir)/g_delete_sec_context.c \
+	$(srcdir)/g_dsp_name.c \
+	$(srcdir)/g_dsp_status.c \
+	$(srcdir)/g_dup_name.c \
+	$(srcdir)/g_exp_sec_context.c \
+	$(srcdir)/g_export_name.c \
+	$(srcdir)/g_glue.c \
+	$(srcdir)/g_imp_name.c \
+	$(srcdir)/g_imp_sec_context.c \
+	$(srcdir)/g_init_sec_context.c \
+	$(srcdir)/g_initialize.c \
+	$(srcdir)/g_inq_context.c \
+	$(srcdir)/g_inq_cred.c \
+	$(srcdir)/g_inq_names.c \
+	$(srcdir)/g_mechname.c \
+	$(srcdir)/g_oid_ops.c \
+	$(srcdir)/g_process_context.c \
+	$(srcdir)/g_rel_buffer.c \
+	$(srcdir)/g_rel_cred.c \
+	$(srcdir)/g_rel_name.c \
+	$(srcdir)/g_rel_oid_set.c \
+	$(srcdir)/g_seal.c \
+	$(srcdir)/g_sign.c \
+	$(srcdir)/g_store_cred.c \
+	$(srcdir)/g_unseal.c \
+	$(srcdir)/g_userok.c \
+	$(srcdir)/g_utils.c \
+	$(srcdir)/g_verify.c \
+	$(srcdir)/gssd_pname_to_uid.c \
+	$(srcdir)/oid_ops.c
+
+STLIBOBJS = \
+	g_accept_sec_context.o \
+	g_acquire_cred.o \
+	g_canon_name.o \
+	g_compare_name.o \
+	g_context_time.o \
+	g_delete_sec_context.o \
+	g_dsp_name.o \
+	g_dsp_status.o \
+	g_dup_name.o \
+	g_exp_sec_context.o \
+	g_export_name.o \
+	g_glue.o \
+	g_imp_name.o \
+	g_imp_sec_context.o \
+	g_init_sec_context.o \
+	g_initialize.o \
+	g_inq_context.o \
+	g_inq_cred.o \
+	g_inq_names.o \
+	g_mechname.o \
+	g_oid_ops.o \
+	g_process_context.o \
+	g_rel_buffer.o \
+	g_rel_cred.o \
+	g_rel_name.o \
+	g_rel_oid_set.o \
+	g_seal.o \
+	g_sign.o \
+	g_store_cred.o \
+	g_unseal.o \
+	g_userok.o \
+	g_utils.o \
+	g_verify.o \
+	gssd_pname_to_uid.o \
+	oid_ops.o
+
+EHDRDIR= $(BUILDTOP)$(S)include$(S)gssapi
+EXPORTED_HEADERS = mechglue.h
+
+all-unix:: all-libobjs
+
+clean-unix:: clean-libobjs
+
+# Krb5InstallHeaders($(EXPORTED_HEADERS), $(KRB5_INCDIR)/krb5)
+install::
+	@set -x; for f in $(EXPORTED_HEADERS) ; \
+	do $(INSTALL_DATA) $(srcdir)$(S)$$f     \
+		$(DESTDIR)$(KRB5_INCDIR)$(S)gssapi$(S)$$f ; \
+	done
+
+includes::
+
+# @libobj_frag@
diff --git a/mechglue/src/lib/gssapi/mechglue/g_accept_sec_context.c b/mechglue/src/lib/gssapi/mechglue/g_accept_sec_context.c
new file mode 100644
index 000000000..b2a21e6de
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_accept_sec_context.c
@@ -0,0 +1,312 @@
+/* #pragma ident	"@(#)g_accept_sec_context.c	1.19	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_accept_sec_context
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_accept_sec_context (minor_status,
+                        context_handle,
+                        verifier_cred_handle,
+                        input_token_buffer,
+                        input_chan_bindings,
+                        src_name,
+                        mech_type,
+                        output_token,
+                        ret_flags,
+                        time_rec,
+                        d_cred)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t *		context_handle;
+gss_cred_id_t		verifier_cred_handle;
+gss_buffer_t		input_token_buffer;
+gss_channel_bindings_t	input_chan_bindings;
+gss_name_t *		src_name;
+gss_OID *		mech_type;
+gss_buffer_t		output_token;
+OM_uint32 *		ret_flags;
+OM_uint32 *		time_rec;
+gss_cred_id_t *		d_cred;
+
+{
+    OM_uint32		status, temp_status, temp_minor_status;
+    gss_union_ctx_id_t	union_ctx_id;
+    gss_union_cred_t	union_cred;
+    gss_cred_id_t	input_cred_handle = GSS_C_NO_CREDENTIAL;
+    gss_cred_id_t	tmp_d_cred = GSS_C_NO_CREDENTIAL;
+    gss_name_t		internal_name = GSS_C_NO_NAME;
+    gss_name_t		tmp_src_name = GSS_C_NO_NAME;
+    gss_OID_desc	token_mech_type_desc;
+    gss_OID		token_mech_type = &token_mech_type_desc;
+    gss_mechanism	mech;
+    
+    /* check parameters first */
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+ 
+    if (context_handle == NULL || output_token == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+ 
+    /* clear optional fields */
+    output_token->value = NULL;
+    output_token->length = 0;
+    if (src_name)
+	*src_name = NULL;
+
+    if (mech_type)
+	*mech_type = NULL;
+
+    if (d_cred)
+	*d_cred = NULL;
+    /*
+     * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
+     * descriptor to hold the mech type information as well as the
+     * underlying mechanism context handle. Otherwise, cast the
+     * value of *context_handle to the union context variable.
+     */
+    
+    if(*context_handle == GSS_C_NO_CONTEXT) {
+	
+	if (GSS_EMPTY_BUFFER(input_token_buffer))
+	    return (GSS_S_CALL_INACCESSIBLE_READ);
+
+	/* Get the token mech type */
+	status = __gss_get_mech_type(token_mech_type, input_token_buffer);
+	if (status)
+	    return status;
+
+	status = GSS_S_FAILURE;
+	union_ctx_id = (gss_union_ctx_id_t)
+	    malloc(sizeof(gss_union_ctx_id_desc));
+	if (!union_ctx_id)
+	    return (GSS_S_FAILURE);
+
+	union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
+	status = generic_gss_copy_oid(&temp_minor_status,
+				      token_mech_type,
+				      &union_ctx_id->mech_type);
+	if (status != GSS_S_COMPLETE) {
+	    free(union_ctx_id);
+	    return (status);
+	}
+
+	/* set the new context handle to caller's data */
+	*context_handle = (gss_ctx_id_t)union_ctx_id;
+    } else {
+	union_ctx_id = (gss_union_ctx_id_t)*context_handle;
+	token_mech_type = union_ctx_id->mech_type;
+    }
+    
+    /* 
+     * get the appropriate cred handle from the union cred struct.
+     * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
+     * use the default credential.
+     */
+    union_cred = (gss_union_cred_t) verifier_cred_handle;
+    input_cred_handle = __gss_get_mechanism_cred(union_cred, token_mech_type);
+    
+    /*
+     * now select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    mech = __gss_get_mechanism (token_mech_type);
+    if (mech && mech->gss_accept_sec_context) {
+
+	    status = mech->gss_accept_sec_context(
+						  mech->context,
+						  minor_status,
+						  &union_ctx_id->internal_ctx_id,
+						  input_cred_handle,
+						  input_token_buffer,
+						  input_chan_bindings,
+						  &internal_name,
+						  mech_type,
+						  output_token,
+						  ret_flags,
+						  time_rec,
+					d_cred ? &tmp_d_cred : NULL);
+
+	    /* If there's more work to do, keep going... */
+	    if (status == GSS_S_CONTINUE_NEEDED)
+		return GSS_S_CONTINUE_NEEDED;
+	    
+	    /* if the call failed, return with failure */
+	    if (status != GSS_S_COMPLETE)
+		goto error_out;
+
+	    /*
+	     * if src_name is non-NULL,
+	     * convert internal_name into a union name equivalent
+	     * First call the mechanism specific display_name()
+	     * then call gss_import_name() to create
+	     * the union name struct cast to src_name
+	     */
+	    if (internal_name != NULL) {
+		temp_status = __gss_convert_name_to_union_name(
+		       &temp_minor_status, mech,
+		       internal_name, &tmp_src_name);
+		if (temp_status != GSS_S_COMPLETE) {
+		    *minor_status = temp_minor_status;
+		    if (output_token->length)
+			(void) gss_release_buffer(&temp_minor_status,
+						  output_token);
+		    if (internal_name != GSS_C_NO_NAME)
+			mech->gss_release_name(
+			    mech->context,
+			    &temp_minor_status,
+			    &internal_name);
+		    return (temp_status);
+		}
+		if (src_name != NULL) {
+		    *src_name = tmp_src_name;
+		}
+	    } else if (src_name != NULL) {
+		*src_name = GSS_C_NO_NAME;
+	    }
+
+	    /* Ensure we're returning correct creds format */
+	    if ((ret_flags && GSS_C_DELEG_FLAG) &&
+		tmp_d_cred != GSS_C_NO_CREDENTIAL) {
+		gss_union_cred_t d_u_cred = NULL;
+
+		d_u_cred = malloc(sizeof (gss_union_cred_desc));
+		if (d_u_cred == NULL) {
+		    status = GSS_S_FAILURE;
+		    goto error_out;
+		}
+		(void) memset(d_u_cred, 0,
+			      sizeof (gss_union_cred_desc));
+
+		d_u_cred->count = 1;
+
+		status = generic_gss_copy_oid(&temp_minor_status,
+					      token_mech_type,
+					      &d_u_cred->mechs_array);
+
+		if (status != GSS_S_COMPLETE) {
+		    free(d_u_cred);
+		    goto error_out;
+		}
+
+		d_u_cred->cred_array = malloc(sizeof (gss_cred_id_t));
+		if (d_u_cred->cred_array != NULL) {
+		    d_u_cred->cred_array[0] = tmp_d_cred;
+		} else {
+		    free(d_u_cred);
+		    status = GSS_S_FAILURE;
+		    goto error_out;
+		}
+
+		if (status != GSS_S_COMPLETE) {
+		    free(d_u_cred->cred_array);
+		    free(d_u_cred);
+		    goto error_out;
+		}
+
+		internal_name = GSS_C_NO_NAME;
+
+		d_u_cred->auxinfo.creation_time = time(0);
+		d_u_cred->auxinfo.time_rec = 0;
+
+		if (mech->gss_inquire_cred) {
+		    status = mech->gss_inquire_cred(mech->context,
+						    minor_status,
+						    tmp_d_cred,
+						    &internal_name,
+						    &d_u_cred->auxinfo.time_rec,
+						    &d_u_cred->auxinfo.cred_usage,
+						    NULL);
+		}
+
+		if (internal_name != NULL) {
+		    temp_status = __gss_convert_name_to_union_name(
+			&temp_minor_status, mech,
+			internal_name, &tmp_src_name);
+		    if (temp_status != GSS_S_COMPLETE) {
+			*minor_status = temp_minor_status;
+			if (output_token->length)
+			    (void) gss_release_buffer(
+				&temp_minor_status,
+				output_token);
+			free(d_u_cred->cred_array);
+			free(d_u_cred);
+			return (temp_status);
+		    }
+		}
+
+		if (tmp_src_name != NULL) {
+		    status = gss_display_name(
+			&temp_minor_status,
+			tmp_src_name,
+			&d_u_cred->auxinfo.name,
+			&d_u_cred->auxinfo.name_type);
+		}
+
+		*d_cred = (gss_cred_id_t)d_u_cred;
+	    }
+
+	    if (src_name == NULL && tmp_src_name != NULL)
+		(void) gss_release_name(&temp_minor_status,
+					&tmp_src_name);
+	    return	(status);
+    } else {
+
+	status = GSS_S_BAD_MECH;
+    }
+    
+error_out:
+    if (union_ctx_id) {
+	if (union_ctx_id->mech_type) {
+	    if (union_ctx_id->mech_type->elements)
+		free(union_ctx_id->mech_type->elements);
+	    free(union_ctx_id->mech_type);
+	    *context_handle = GSS_C_NO_CONTEXT;
+	}
+	free(union_ctx_id);
+    }
+
+    if (output_token->length)
+	(void) gss_release_buffer(&temp_minor_status, output_token);
+
+    if (src_name)
+	*src_name = GSS_C_NO_NAME;
+
+    if (tmp_src_name != GSS_C_NO_NAME)
+	(void) gss_release_buffer(&temp_minor_status,
+				  (gss_buffer_t)tmp_src_name);
+
+    return (status);
+}
+
diff --git a/mechglue/src/lib/gssapi/mechglue/g_acquire_cred.c b/mechglue/src/lib/gssapi/mechglue/g_acquire_cred.c
new file mode 100644
index 000000000..c0bfd3f5a
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_acquire_cred.c
@@ -0,0 +1,437 @@
+/* #pragma ident	"@(#)g_acquire_cred.c	1.22	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_acquire_cred
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static gss_OID_set
+create_actual_mechs(mechs_array, count)
+    const gss_OID	mechs_array;
+    int count;
+{
+    gss_OID_set 	actual_mechs;
+    int			i;
+    OM_uint32		minor;
+
+    actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
+    if (!actual_mechs)
+	return NULL;
+
+    actual_mechs->elements = (gss_OID)
+	malloc(sizeof (gss_OID_desc) * count);
+    if (!actual_mechs->elements) {
+	free(actual_mechs);
+	return NULL;
+    }
+    
+    actual_mechs->count = 0;
+
+    for (i = 0; i < count; i++) {
+	actual_mechs->elements[i].elements = (void *)
+	    malloc(mechs_array[i].length);
+	if (actual_mechs->elements[i].elements == NULL) {
+	    (void) gss_release_oid_set(&minor, &actual_mechs);
+	    return (NULL);
+	}
+	g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
+	actual_mechs->count++;
+    }
+
+    return actual_mechs;
+}
+
+
+OM_uint32 KRB5_CALLCONV
+gss_acquire_cred(minor_status,
+                 desired_name,
+                 time_req,
+                 desired_mechs,
+		 cred_usage,
+                 output_cred_handle,
+                 actual_mechs,
+                 time_rec)
+
+OM_uint32 *		minor_status;
+gss_name_t		desired_name;
+OM_uint32		time_req;
+gss_OID_set		desired_mechs;
+int			cred_usage;
+gss_cred_id_t *		output_cred_handle;
+gss_OID_set *		actual_mechs;
+OM_uint32 *		time_rec;
+
+{
+    OM_uint32 major = GSS_S_FAILURE;
+    OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
+    gss_OID_set_desc default_OID_set;
+    gss_OID_set mechs;
+    gss_OID_desc default_OID;
+    gss_mechanism mech;
+    int i;
+    gss_union_cred_t creds;
+
+    /* start by checking parameters */
+    if (!minor_status)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+    
+    if (!output_cred_handle)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+    *output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+    /* Set output parameters to NULL for now */
+    if (actual_mechs)
+	*actual_mechs = GSS_C_NULL_OID_SET;
+
+    if (time_rec)
+	*time_rec = 0;
+
+    /*
+     * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
+     * appropriate default.  We use the first mechanism in the
+     * mechansim list as the default. This set is created with
+     * statics thus needs not be freed
+     */
+    if(desired_mechs == GSS_C_NULL_OID_SET) {
+	mech = __gss_get_mechanism(NULL);
+	if (mech == NULL)
+	    return (GSS_S_BAD_MECH);
+	
+	mechs = &default_OID_set;
+	default_OID_set.count = 1;
+	default_OID_set.elements = &default_OID;
+	default_OID.length = mech->mech_type.length;
+	default_OID.elements = mech->mech_type.elements;
+    } else
+	mechs = desired_mechs;
+
+    if (mechs->count == 0)
+	return (GSS_S_BAD_MECH);
+
+    /* allocate the output credential structure */
+    creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
+    if (creds == NULL)
+	return (GSS_S_FAILURE);
+
+    /* initialize to 0s */
+    (void) memset(creds, 0, sizeof (gss_union_cred_desc));
+
+    /* for each requested mech attempt to obtain a credential */
+    for (i = 0; i < mechs->count; i++) {
+	major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
+			     desired_name,
+			     &mechs->elements[i],
+			     cred_usage, time_req, time_req, NULL,
+			     NULL, &initTimeOut, &acceptTimeOut);
+	if (major == GSS_S_COMPLETE) {
+	    /* update the credential's time */
+	    if (cred_usage == GSS_C_ACCEPT) {
+		if (outTime > acceptTimeOut)
+		    outTime = acceptTimeOut;
+	    } else if (cred_usage == GSS_C_INITIATE) {
+		if (outTime > initTimeOut)
+		    outTime = initTimeOut;
+	    } else {
+		/*
+		 * time_rec is the lesser of the
+		 * init/accept times
+		 */
+		if (initTimeOut > acceptTimeOut)
+		    outTime = (outTime > acceptTimeOut) ?
+			acceptTimeOut : outTime;
+		else
+		    outTime = (outTime > initTimeOut) ?
+			initTimeOut : outTime;
+	    }
+	}
+    } /* for */
+
+    /* ensure that we have at least one credential element */
+    if (creds->count < 1) {
+	free(creds);
+	return (major);
+    }
+
+    /*
+     * fill in output parameters
+     * setup the actual mechs output parameter
+     */
+    if (actual_mechs != NULL) {
+	if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
+						 creds->count)) == NULL) {
+	    (void) gss_release_cred(minor_status,
+				    (gss_cred_id_t *)&creds);
+	    *minor_status = 0;
+	    return (GSS_S_FAILURE);
+	}
+    }
+
+    if (time_rec)
+	*time_rec = outTime;
+
+
+    *output_cred_handle = (gss_cred_id_t)creds;
+    return (GSS_S_COMPLETE);
+}
+
+/* V2 KRB5_CALLCONV */
+OM_uint32 KRB5_CALLCONV
+gss_add_cred(minor_status, input_cred_handle,
+		  desired_name, desired_mech, cred_usage,
+		  initiator_time_req, acceptor_time_req,
+		  output_cred_handle, actual_mechs, 
+		  initiator_time_rec, acceptor_time_rec)
+    OM_uint32		*minor_status;
+    gss_cred_id_t	input_cred_handle;
+    gss_name_t		desired_name;
+    gss_OID		desired_mech;
+    gss_cred_usage_t	cred_usage;
+    OM_uint32		initiator_time_req;
+    OM_uint32		acceptor_time_req;
+    gss_cred_id_t	*output_cred_handle;
+    gss_OID_set		*actual_mechs;
+    OM_uint32		*initiator_time_rec;
+    OM_uint32		*acceptor_time_rec;
+{
+    OM_uint32		status, temp_minor_status;
+    OM_uint32		time_req, time_rec;
+    gss_union_name_t	union_name;
+    gss_union_cred_t	new_union_cred, union_cred;
+    gss_name_t		internal_name = GSS_C_NO_NAME;
+    gss_name_t		allocated_name = GSS_C_NO_NAME;
+    gss_mechanism	mech;
+    gss_cred_id_t	cred = NULL;
+    gss_OID		new_mechs_array = NULL;
+    gss_cred_id_t *	new_cred_array = NULL;
+
+    /* check input parameters */
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
+	output_cred_handle == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
+
+    if (output_cred_handle)
+	*output_cred_handle = GSS_C_NO_CREDENTIAL;
+
+    if (actual_mechs)
+	*actual_mechs = NULL;
+
+    if (acceptor_time_rec)
+	*acceptor_time_rec = 0;
+
+    if (initiator_time_rec)
+	*initiator_time_rec = 0;
+
+    mech = __gss_get_mechanism(desired_mech);
+    if (!mech)
+	return GSS_S_BAD_MECH;
+    else if (!mech->gss_acquire_cred)
+	return (GSS_S_UNAVAILABLE);
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+	union_cred = malloc(sizeof (gss_union_cred_desc));
+	if (union_cred == NULL)
+	    return (GSS_S_FAILURE);
+
+	(void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
+
+	/* for default credentials we will use GSS_C_NO_NAME */
+	internal_name = GSS_C_NO_NAME;
+    } else {
+	union_cred = (gss_union_cred_t)input_cred_handle;
+	if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
+	    GSS_C_NO_CREDENTIAL)
+	    return (GSS_S_DUPLICATE_ELEMENT);
+
+	/* may need to create a mechanism specific name */
+	if (desired_name) {
+	    union_name = (gss_union_name_t)desired_name;
+	    if (union_name->mech_type &&
+		g_OID_equal(union_name->mech_type,
+			    &mech->mech_type))
+		internal_name = union_name->mech_name;
+	    else {
+		if (__gss_import_internal_name(minor_status,
+					       &mech->mech_type, union_name,
+					       &allocated_name) != GSS_S_COMPLETE)
+		    return (GSS_S_BAD_NAME);
+		internal_name = allocated_name;
+	    }
+	}
+    }
+
+
+    if (cred_usage == GSS_C_ACCEPT)
+	time_req = acceptor_time_req;
+    else if (cred_usage == GSS_C_INITIATE)
+	time_req = initiator_time_req;
+    else if (cred_usage == GSS_C_BOTH)
+	time_req = (acceptor_time_req > initiator_time_req) ?
+	    acceptor_time_req : initiator_time_req;
+
+    status = mech->gss_acquire_cred(mech->context, minor_status,
+				    internal_name, time_req,
+				    GSS_C_NULL_OID_SET, cred_usage,
+				    &cred, NULL, &time_rec);
+
+    if (status != GSS_S_COMPLETE)
+	goto errout;
+
+    /* may need to set credential auxinfo strucutre */
+    if (union_cred->auxinfo.creation_time == 0) {
+	union_cred->auxinfo.creation_time = time(NULL);
+	union_cred->auxinfo.time_rec = time_rec;
+	union_cred->auxinfo.cred_usage = cred_usage;
+
+	/*
+	 * we must set the name; if name is not supplied
+	 * we must do inquire cred to get it
+	 */
+	if (internal_name == NULL) {
+	    if (mech->gss_inquire_cred == NULL ||
+		((status = mech->gss_inquire_cred(
+		      mech->context,
+		      &temp_minor_status, cred,
+		      &allocated_name, NULL, NULL,
+		      NULL)) != GSS_S_COMPLETE))
+		goto errout;
+	    internal_name = allocated_name;
+	}
+
+	if ((status = mech->gss_display_name(mech->context,
+					     &temp_minor_status, internal_name,
+					     &union_cred->auxinfo.name,
+					     &union_cred->auxinfo.name_type)) !=
+	    GSS_S_COMPLETE)
+	    goto errout;
+    }
+
+    /* now add the new credential elements */
+    new_mechs_array = (gss_OID)
+	malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
+
+    new_cred_array = (gss_cred_id_t *)
+	malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
+
+    if (!new_mechs_array || !new_cred_array) {
+	status = GSS_S_FAILURE;
+	goto errout;
+    }
+
+    if (acceptor_time_rec)
+	if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
+	    *acceptor_time_rec = time_rec;
+    if (initiator_time_rec)
+	if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
+	    *initiator_time_rec = time_rec;
+
+    /*
+     * OK, expand the mechanism array and the credential array
+     */
+    (void) memcpy(new_mechs_array, union_cred->mechs_array,
+		  sizeof (gss_OID_desc) * union_cred->count);
+    (void) memcpy(new_cred_array, union_cred->cred_array,
+		  sizeof (gss_cred_id_t) * union_cred->count);
+
+    new_cred_array[union_cred->count] = cred;
+    if ((new_mechs_array[union_cred->count].elements =
+	 malloc(mech->mech_type.length)) == NULL)
+	goto errout;
+
+    g_OID_copy(&new_mechs_array[union_cred->count],
+	       &mech->mech_type);
+
+    if (actual_mechs) {
+	*actual_mechs = create_actual_mechs(new_mechs_array,
+					    union_cred->count + 1);
+	if (*actual_mechs == NULL) {
+	    free(new_mechs_array[union_cred->count].elements);
+	    goto errout;
+	}
+    }
+
+    if (output_cred_handle == NULL) {
+	free(union_cred->mechs_array);
+	free(union_cred->cred_array);
+	new_union_cred = union_cred;
+    } else {
+	new_union_cred = malloc(sizeof (gss_union_cred_desc));
+	if (new_union_cred == NULL) {
+	    free(new_mechs_array[union_cred->count].elements);
+	    goto errout;
+	}
+	*new_union_cred = *union_cred;
+	*output_cred_handle = (gss_cred_id_t)new_union_cred;
+    }
+
+    new_union_cred->mechs_array = new_mechs_array;
+    new_union_cred->cred_array = new_cred_array;
+    new_union_cred->count++;
+
+    /* We're done with the internal name. Free it if we allocated it. */
+
+    if (allocated_name)
+	(void) __gss_release_internal_name(&temp_minor_status,
+					   &mech->mech_type,
+					   &allocated_name);
+
+    return (GSS_S_COMPLETE);
+
+errout:
+    if (new_mechs_array)
+	free(new_mechs_array);
+    if (new_cred_array)
+	free(new_cred_array);
+
+    if (cred != NULL && mech->gss_release_cred)
+	mech->gss_release_cred(mech->context,
+			       &temp_minor_status, &cred);
+
+    if (allocated_name)
+	(void) __gss_release_internal_name(&temp_minor_status,
+					   &mech->mech_type,
+					   &allocated_name);
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
+	if (union_cred->auxinfo.name.value)
+	    free(union_cred->auxinfo.name.value);
+	free(union_cred);
+    }
+
+    return (status);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_canon_name.c b/mechglue/src/lib/gssapi/mechglue/g_canon_name.c
new file mode 100644
index 000000000..c786d4d04
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_canon_name.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident	"@(#)g_canon_name.c	1.15	04/02/23 SMI" */
+
+/*
+ * routine gss_canonicalize_name
+ *
+ * This routine is used to produce a mechanism specific
+ * representation of name that has been previously
+ * imported with gss_import_name.  The routine uses the mechanism
+ * specific implementation of gss_import_name to implement this
+ * function.
+ *
+ * We allow a NULL output_name, in which case we modify the
+ * input_name to include the mechanism specific name.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32
+gss_canonicalize_name(minor_status,
+				input_name,
+				mech_type,
+				output_name)
+OM_uint32 *minor_status;
+const gss_name_t input_name;
+const gss_OID mech_type;
+gss_name_t *output_name;
+{
+	gss_union_name_t in_union, out_union = NULL, dest_union = NULL;
+	OM_uint32 major_status = GSS_S_FAILURE;
+
+	if (minor_status == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	*minor_status = 0;
+
+	if (output_name)
+		*output_name = 0;
+
+	/* check the input parameters */
+	if (input_name == NULL || mech_type == GSS_C_NULL_OID)
+		return (GSS_S_CALL_INACCESSIBLE_READ);
+
+	in_union = (gss_union_name_t)input_name;
+	/*
+	 * If the caller wants to reuse the name, and the name has already
+	 * been converted, then there is nothing for us to do.
+	 */
+	if (!output_name && in_union->mech_type &&
+		g_OID_equal(in_union->mech_type, mech_type))
+		return (GSS_S_COMPLETE);
+
+	/* ok, then we need to do something - start by creating data struct */
+	if (output_name) {
+		out_union =
+			(gss_union_name_t)malloc(sizeof (gss_union_name_desc));
+		if (!out_union)
+			goto allocation_failure;
+
+		out_union->mech_type = 0;
+		out_union->mech_name = 0;
+		out_union->name_type = 0;
+		out_union->external_name = 0;
+
+		/* Allocate the buffer for the user specified representation */
+		if (__gss_create_copy_buffer(in_union->external_name,
+				&out_union->external_name, 1))
+			goto allocation_failure;
+
+		if (in_union->name_type != GSS_C_NULL_OID) {
+			if ((major_status = generic_gss_copy_oid(minor_status,
+				in_union->name_type, &out_union->name_type)))
+			goto allocation_failure;
+		}
+
+	}
+
+	/*
+	 * might need to delete any old mechanism names if we are
+	 * reusing the buffer.
+	 */
+	if (!output_name) {
+		if (in_union->mech_type) {
+			(void) __gss_release_internal_name(minor_status,
+							in_union->mech_type,
+							&in_union->mech_name);
+			(void) gss_release_oid(minor_status,
+					    &in_union->mech_type);
+			in_union->mech_type = 0;
+		}
+		dest_union = in_union;
+	} else
+		dest_union = out_union;
+
+	/* now let's create the new mech name */
+	if (major_status = generic_gss_copy_oid(minor_status, mech_type,
+						&dest_union->mech_type))
+		goto allocation_failure;
+
+	if (major_status =
+		__gss_import_internal_name(minor_status, mech_type,
+						dest_union,
+						&dest_union->mech_name))
+		goto allocation_failure;
+
+	if (output_name)
+		*output_name = (gss_name_t)dest_union;
+
+	return (GSS_S_COMPLETE);
+
+allocation_failure:
+	/* do not delete the src name external name format */
+	if (output_name) {
+		if (out_union->external_name) {
+			if (out_union->external_name->value)
+				free(out_union->external_name->value);
+			free(out_union->external_name);
+		}
+		if (out_union->name_type)
+			(void) gss_release_oid(minor_status,
+					    &out_union->name_type);
+
+		dest_union = out_union;
+	} else
+		dest_union = in_union;
+
+	/*
+	 * delete the partially created mech specific name
+	 * applies for both src and dest which ever is being used for output
+	 */
+
+	if (dest_union->mech_name) {
+		(void) __gss_release_internal_name(minor_status,
+						dest_union->mech_type,
+						&dest_union->mech_name);
+	}
+
+	if (dest_union->mech_type)
+		(void) gss_release_oid(minor_status, &dest_union->mech_type);
+
+
+	if (output_name)
+		free(out_union);
+
+	return (major_status);
+} /**********  gss_canonicalize_name ********/
diff --git a/mechglue/src/lib/gssapi/mechglue/g_compare_name.c b/mechglue/src/lib/gssapi/mechglue/g_compare_name.c
new file mode 100644
index 000000000..9cd50d9de
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_compare_name.c
@@ -0,0 +1,177 @@
+/* #pragma ident	"@(#)g_compare_name.c	1.16	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_compare_name
+ *
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_compare_name (minor_status,
+                  name1,
+                  name2,
+                  name_equal)
+
+OM_uint32 *		minor_status;
+gss_name_t		name1;
+gss_name_t		name2;
+int *			name_equal;
+
+{
+    OM_uint32		major_status, temp_minor;
+    gss_union_name_t	union_name1, union_name2;
+    gss_mechanism	mech;
+    gss_name_t		internal_name;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (name1 == 0 || name2 == 0)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (name_equal == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    union_name1 = (gss_union_name_t) name1;
+    union_name2 = (gss_union_name_t) name2;
+    /*
+     * Try our hardest to make union_name1 be the mechanism-specific
+     * name.  (Of course we can't if both names aren't
+     * mechanism-specific.)
+     */
+    if (union_name1->mech_type == 0) {
+	union_name1 = (gss_union_name_t) name2;
+	union_name2 = (gss_union_name_t) name1;
+    }
+    /*
+     * If union_name1 is mechanism specific, then fetch its mechanism
+     * information.
+     */
+    if (union_name1->mech_type) {
+	mech = __gss_get_mechanism (union_name1->mech_type);
+	if (!mech)
+	    return (GSS_S_BAD_MECH);
+	if (!mech->gss_compare_name)
+			return (GSS_S_UNAVAILABLE);
+    }
+	
+    *name_equal = 0;		/* Default to *not* equal.... */
+
+    /*
+     * First case... both names are mechanism-specific
+     */
+    if (union_name1->mech_type && union_name2->mech_type) {
+	if (!g_OID_equal(union_name1->mech_type, union_name2->mech_type))
+	    return (GSS_S_COMPLETE);
+	if ((union_name1->mech_name == 0) || (union_name2->mech_name == 0))
+	    /* should never happen */
+	    return (GSS_S_BAD_NAME);
+	return (mech->gss_compare_name(mech->context, minor_status,
+				       union_name1->mech_name,
+				       union_name2->mech_name, name_equal));
+	
+    }
+
+    /*
+     * Second case... both names are NOT mechanism specific.
+     * 
+     * All we do here is make sure the two name_types are equal and then
+     * that the external_names are equal. Note the we do not take care
+     * of the case where two different external names map to the same
+     * internal name. We cannot determine this, since we as yet do not
+     * know what mechanism to use for calling the underlying
+     * gss_import_name().
+     */
+    if (!union_name1->mech_type && !union_name2->mech_type) {
+		/*
+		 * Second case, first sub-case... one name has null
+		 * name_type, the other doesn't.
+		 *
+		 * Not knowing a mech_type we can't import the name with
+		 * null name_type so we can't compare.
+		 */
+		if ((union_name1->name_type == GSS_C_NULL_OID &&
+		    union_name2->name_type != GSS_C_NULL_OID) ||
+		    (union_name1->name_type != GSS_C_NULL_OID &&
+		    union_name2->name_type == GSS_C_NULL_OID))
+			return (GSS_S_COMPLETE);
+		/*
+		 * Second case, second sub-case... both names have
+		 * name_types, but they are different.
+		 */
+		if ((union_name1->name_type != GSS_C_NULL_OID &&
+		    union_name2->name_type != GSS_C_NULL_OID) &&
+		    !g_OID_equal(union_name1->name_type,
+					union_name2->name_type))
+	    return (GSS_S_COMPLETE);
+		/*
+		 * Second case, third sub-case... both names have equal
+		 * name_types (and both have no mech_types) so we just
+		 * compare the external_names.
+		 */
+	if ((union_name1->external_name->length !=
+	     union_name2->external_name->length) ||
+	    (memcmp(union_name1->external_name->value,
+		    union_name2->external_name->value,
+		    union_name1->external_name->length) != 0))
+	    return (GSS_S_COMPLETE);
+	*name_equal = 1;
+	return (GSS_S_COMPLETE);
+    }
+
+    /*
+     * Final case... one name is mechanism specific, the other isn't.
+     * 
+     * We attempt to convert the general name to the mechanism type of
+     * the mechanism-specific name, and then do the compare.  If we
+     * can't import the general name, then we return that the name is
+     * _NOT_ equal.
+     */
+    if (union_name2->mech_type) {
+	/* We make union_name1 the mechanism specific name. */
+	union_name1 = (gss_union_name_t) name2;
+	union_name2 = (gss_union_name_t) name1;
+    }
+    major_status = __gss_import_internal_name(minor_status,
+					      union_name1->mech_type,
+					      union_name2,
+					      &internal_name);
+    if (major_status != GSS_S_COMPLETE)
+	return (GSS_S_COMPLETE); /* return complete, but not equal */
+
+    major_status = mech->gss_compare_name(mech->context, minor_status,
+					  union_name1->mech_name,
+					  internal_name, name_equal);
+    __gss_release_internal_name(&temp_minor, union_name1->mech_type,
+				&internal_name);
+    return (major_status);
+    
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_context_time.c b/mechglue/src/lib/gssapi/mechglue/g_context_time.c
new file mode 100644
index 000000000..82262a06e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_context_time.c
@@ -0,0 +1,78 @@
+/* #pragma ident	"@(#)g_context_time.c	1.12	98/01/22 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routines for gss_context_time
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_context_time (minor_status,
+                  context_handle,
+                  time_rec)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+OM_uint32 *		time_rec;
+
+{
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (time_rec == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+    
+    if (mech) {
+
+	if (mech->gss_context_time)
+	    status = mech->gss_context_time(
+					    mech->context,
+					    minor_status,
+					    ctx->internal_ctx_id,
+					    time_rec);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return(status);
+    }
+    
+    return (GSS_S_BAD_MECH);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_delete_sec_context.c b/mechglue/src/lib/gssapi/mechglue/g_delete_sec_context.c
new file mode 100644
index 000000000..9678bd083
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_delete_sec_context.c
@@ -0,0 +1,90 @@
+/* #pragma ident	"@(#)g_delete_sec_context.c	1.11	97/11/09 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_delete_sec_context
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32 KRB5_CALLCONV 
+gss_delete_sec_context (minor_status,
+                        context_handle,
+                        output_token)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t *		context_handle;
+gss_buffer_t		output_token;
+
+{
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if (output_token != GSS_C_NO_BUFFER) {
+	output_token->length = 0;
+	output_token->value = NULL;
+    }
+
+    /* if the context_handle is Null, return NO_CONTEXT error */
+    if(context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    ctx = (gss_union_ctx_id_t) *context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+    
+    if (mech) {
+
+	if (mech->gss_delete_sec_context)
+	    status = mech->gss_delete_sec_context(
+						  mech->context,
+						  minor_status,
+						  &ctx->internal_ctx_id,
+						  output_token);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	/* now free up the space for the union context structure */
+	free(ctx->mech_type->elements);
+	free(ctx->mech_type);
+	free(*context_handle);
+	*context_handle = NULL;
+
+	return(status);
+    }
+
+    return (GSS_S_BAD_MECH);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_dsp_name.c b/mechglue/src/lib/gssapi/mechglue/g_dsp_name.c
new file mode 100644
index 000000000..f90c87669
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_dsp_name.c
@@ -0,0 +1,108 @@
+/* #pragma ident	"@(#)g_dsp_name.c	1.13	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_display_name()
+ *
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_display_name (minor_status,
+                  input_name,
+                  output_name_buffer,
+                  output_name_type)
+
+OM_uint32 *		minor_status;
+gss_name_t		input_name;
+gss_buffer_t		output_name_buffer;
+gss_OID *		output_name_type;
+
+{
+    OM_uint32		major_status;
+    gss_union_name_t	union_name;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (input_name == 0)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (output_name_buffer == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    if (output_name_type)
+	*output_name_type = NULL;
+
+    union_name = (gss_union_name_t) input_name;
+
+    if (union_name->mech_type) {
+	/*
+	 * OK, we have a mechanism-specific name; let's use it!
+	 */
+	return (__gss_display_internal_name(minor_status,
+					    union_name->mech_type,
+					    union_name->mech_name,
+					    output_name_buffer,
+					    output_name_type));
+    }
+    
+    /*
+     * copy the value of the external_name component of the union
+     * name into the output_name_buffer and point the output_name_type
+     * to the name_type component of union_name
+     */
+    if (output_name_type != NULL &&
+	union_name->name_type != GSS_C_NULL_OID) {
+	major_status = generic_gss_copy_oid(minor_status,
+					    union_name->name_type,
+					    output_name_type);
+	if (major_status != GSS_S_COMPLETE)
+	    return (major_status);
+    }
+
+    if ((output_name_buffer->value =
+	 malloc(union_name->external_name->length + 1)) == NULL) {
+	if (output_name_type && *output_name_type != GSS_C_NULL_OID) {
+	    (void) generic_gss_release_oid(minor_status,
+					   output_name_type);
+	    *output_name_type = NULL;
+	}
+	return (GSS_S_FAILURE);
+    }
+    output_name_buffer->length = union_name->external_name->length;
+    (void) memcpy(output_name_buffer->value,
+		  union_name->external_name->value,
+		  union_name->external_name->length);
+    ((char *)output_name_buffer->value)[output_name_buffer->length] = '\0';
+
+    return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_dsp_status.c b/mechglue/src/lib/gssapi/mechglue/g_dsp_status.c
new file mode 100644
index 000000000..51d552e56
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_dsp_status.c
@@ -0,0 +1,325 @@
+/* #pragma ident	"@(#)g_dsp_status.c	1.17	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine gss_display_status
+ *
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* local function */
+static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t);
+
+OM_uint32 KRB5_CALLCONV
+gss_display_status (minor_status,
+                    status_value,
+                    status_type,
+                    req_mech_type,
+                    message_context,
+                    status_string)
+
+OM_uint32 *		minor_status;
+OM_uint32		status_value;
+int			status_type;
+gss_OID			req_mech_type;
+OM_uint32 *		message_context;
+gss_buffer_t		status_string;
+
+{
+    gss_OID		mech_type = (gss_OID) req_mech_type;
+    gss_mechanism	mech;
+
+    /* check the input parameters */
+    if (!minor_status)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *minor_status = 0;
+
+    if (!message_context || status_string == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    status_string->length = 0;
+    status_string->value = NULL;
+
+    /* we handle major status codes, and the mechs do the minor */
+    if (status_type == GSS_C_GSS_CODE)
+	return (displayMajor(status_value, message_context,
+			     status_string));
+
+    /*
+     * must be the minor status - let mechs do the work
+     * select the appropriate underlying mechanism routine and
+     * call it.
+     */
+
+    mech = __gss_get_mechanism (mech_type);
+
+    if (mech && mech->gss_display_status) {
+	if (mech_type == GSS_C_NULL_OID)
+	    mech_type = &mech->mech_type;
+
+	return (mech->gss_display_status(mech->context, minor_status,
+					 status_value, status_type, mech_type,
+					 message_context, status_string));
+    }
+
+    if (!mech)
+	return (GSS_S_BAD_MECH);
+
+    return (GSS_S_UNAVAILABLE);
+}
+
+/*
+ * function to map the major error codes
+ * it uses case statements so that the strings could be wrapped by gettext
+ * msgCtxt is interpreted as:
+ *	0 - first call
+ *	1 - routine error
+ *	>= 2 - the supplementary error code bit shifted by 1
+ */
+static OM_uint32
+displayMajor(status, msgCtxt, outStr)
+OM_uint32 status;
+OM_uint32 *msgCtxt;
+gss_buffer_t outStr;
+{
+	OM_uint32 oneVal, mask = 0x1, currErr;
+	char *errStr = NULL;
+	int i, haveErr = 0;
+
+	/* take care of the success value first */
+	if (status == GSS_S_COMPLETE)
+		errStr = "The routine completed successfully";
+	else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
+		switch (oneVal) {
+		case GSS_S_CALL_INACCESSIBLE_READ:
+			errStr = "A required input parameter"
+				" could not be read";
+			break;
+
+		case GSS_S_CALL_INACCESSIBLE_WRITE:
+			errStr = "A required output parameter"
+				" could not be written";
+			break;
+
+		case GSS_S_CALL_BAD_STRUCTURE:
+			errStr = "A parameter was malformed";
+			break;
+
+		default:
+			errStr = "An invalid status code was supplied";
+			break;
+		}
+
+		/* we now need to determine new value of msgCtxt */
+		if (GSS_ROUTINE_ERROR(status))
+			*msgCtxt = 1;
+		else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
+			*msgCtxt = (OM_uint32)(oneVal << 1);
+		else
+			*msgCtxt = 0;
+
+	} else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
+		(oneVal = GSS_ROUTINE_ERROR(status))) {
+		switch (oneVal) {
+		case GSS_S_BAD_MECH:
+			errStr = "An unsupported mechanism"
+				" was requested";
+			break;
+
+		case GSS_S_BAD_NAME:
+			errStr = "An invalid name was supplied";
+			break;
+
+		case GSS_S_BAD_NAMETYPE:
+			errStr = "A supplied name was of an"
+				" unsupported type";
+			break;
+
+		case GSS_S_BAD_BINDINGS:
+			errStr = "Incorrect channel bindings"
+				" were supplied";
+			break;
+
+		case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
+			errStr = "A token had an invalid Message"
+				" Integrity Check (MIC)";
+			break;
+
+		case GSS_S_NO_CRED:
+			errStr = "No credentials were supplied, or the"
+				" credentials were unavailable or"
+				" inaccessible";
+			break;
+
+		case GSS_S_NO_CONTEXT:
+			errStr = "No context has been established";
+			break;
+
+		case GSS_S_DEFECTIVE_TOKEN:
+			errStr = "Invalid token was supplied";
+			break;
+
+		case GSS_S_DEFECTIVE_CREDENTIAL:
+			errStr = "Invalid credential was supplied";
+			break;
+
+		case GSS_S_CREDENTIALS_EXPIRED:
+			errStr = "The referenced credential has"
+				" expired";
+			break;
+
+		case GSS_S_CONTEXT_EXPIRED:
+			errStr = "The referenced context has expired";
+			break;
+
+		case GSS_S_FAILURE:
+			errStr = "Unspecified GSS failure.  Minor code"
+				" may provide more information";
+			break;
+
+		case GSS_S_BAD_QOP:
+			errStr = "The quality-of-protection (QOP) "
+				"requested could not be provided";
+			break;
+
+		case GSS_S_UNAUTHORIZED:
+			errStr = "The operation is forbidden by local"
+				" security policy";
+			break;
+
+		case GSS_S_UNAVAILABLE:
+			errStr = "The operation or option is not"
+				" available or unsupported";
+			break;
+
+		case GSS_S_DUPLICATE_ELEMENT:
+			errStr = "The requested credential element"
+				" already exists";
+			break;
+
+		case GSS_S_NAME_NOT_MN:
+			errStr = "The provided name was not mechanism"
+				" specific (MN)";
+			break;
+
+		case GSS_S_BAD_STATUS:
+		default:
+			errStr = "An invalid status code was supplied";
+		}
+
+		/* we must determine if the caller should call us again */
+		if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
+			*msgCtxt = (OM_uint32)(oneVal << 1);
+		else
+			*msgCtxt = 0;
+
+	} else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
+		(oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
+		/*
+		 * if msgCtxt is not 0, then it should encode
+		 * the supplementary error code we should be printing
+		 */
+		if (*msgCtxt >= 2)
+			oneVal = (OM_uint32) (*msgCtxt) >> 1;
+		else
+			oneVal = GSS_SUPPLEMENTARY_INFO(status);
+
+		/* we display the errors LSB first */
+		for (i = 0; i < 16; i++) {
+			if (oneVal & mask) {
+				haveErr = 1;
+				break;
+			}
+			mask <<= 1;
+		}
+
+		/* isolate the bit or if not found set to illegal value */
+		if (haveErr)
+			currErr = oneVal & mask;
+		else
+			currErr = 1 << 17; /* illegal value */
+
+		switch (currErr) {
+		case GSS_S_CONTINUE_NEEDED:
+			errStr = "The routine must be called again to"
+				" complete its function";
+			break;
+
+		case GSS_S_DUPLICATE_TOKEN:
+			errStr = "The token was a duplicate of an"
+				" earlier token";
+			break;
+
+		case GSS_S_OLD_TOKEN:
+			errStr = "The token's validity period"
+				" has expired";
+			break;
+
+		case GSS_S_UNSEQ_TOKEN:
+			errStr = "A later token has already been"
+				" processed";
+			break;
+
+		case GSS_S_GAP_TOKEN:
+			errStr = "An expected per-message token was"
+				" not received";
+			break;
+
+		default:
+			errStr = "An invalid status code was supplied";
+		}
+
+		/*
+		 * we must check if there is any other supplementary errors
+		 * if found, then turn off current bit, and store next value
+		 * in msgCtxt shifted by 1 bit
+		 */
+		if (!haveErr)
+			*msgCtxt = 0;
+		else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
+			*msgCtxt = (OM_uint32)
+				((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
+		else
+			*msgCtxt = 0;
+	}
+
+	if (errStr == NULL)
+		errStr = "An invalid status code was supplied";
+
+	/* now copy the status code and return to caller */
+	outStr->length = strlen(errStr);
+	outStr->value = malloc((size_t)outStr->length+1);
+	if (outStr->value == NULL) {
+		outStr->length = 0;
+		return (GSS_S_FAILURE);
+	}
+
+	(void) strcpy((char *)outStr->value, errStr);
+	return (GSS_S_COMPLETE);
+} /* displayMajor */
diff --git a/mechglue/src/lib/gssapi/mechglue/g_dup_name.c b/mechglue/src/lib/gssapi/mechglue/g_dup_name.c
new file mode 100644
index 000000000..d8508202c
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_dup_name.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident	"@(#)g_dup_name.c	1.14	04/02/23 SMI" */
+
+/*
+ *  routine gss_duplicate_name
+ *
+ * This routine does not rely on mechanism implementation of this
+ * name, but instead uses mechanism specific gss_import_name routine.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32
+gss_duplicate_name(minor_status,
+		src_name,
+		dest_name)
+OM_uint32 *minor_status;
+const gss_name_t src_name;
+gss_name_t *dest_name;
+{
+		gss_union_name_t src_union, dest_union;
+		OM_uint32 major_status = GSS_S_FAILURE;
+
+
+	if (!minor_status)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	*minor_status = 0;
+
+	/* if output_name is NULL, simply return */
+	if (dest_name == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_BAD_NAME);
+
+	*dest_name = 0;
+
+	if (src_name == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_READ);
+
+	src_union = (gss_union_name_t)src_name;
+
+	/*
+	 * First create the union name struct that will hold the external
+	 * name and the name type.
+	 */
+	dest_union = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
+	if (!dest_union)
+		goto allocation_failure;
+
+	dest_union->mech_type = 0;
+	dest_union->mech_name = 0;
+	dest_union->name_type = 0;
+	dest_union->external_name = 0;
+
+	/* Now copy the external representaion */
+	if (__gss_create_copy_buffer(src_union->external_name,
+				&dest_union->external_name, 0))
+		goto allocation_failure;
+
+	if (src_union->name_type != GSS_C_NULL_OID) {
+		major_status = generic_gss_copy_oid(minor_status,
+						src_union->name_type,
+						&dest_union->name_type);
+		if (major_status != GSS_S_COMPLETE)
+			goto allocation_failure;
+	}
+
+	/*
+	 * See if source name is mechanim specific, if so then need to import it
+	 */
+	if (src_union->mech_type) {
+		major_status = generic_gss_copy_oid(minor_status,
+							src_union->mech_type,
+							&dest_union->mech_type);
+		if (major_status != GSS_S_COMPLETE)
+			goto allocation_failure;
+
+		major_status = __gss_import_internal_name(minor_status,
+							dest_union->mech_type,
+							dest_union,
+							&dest_union->mech_name);
+		if (major_status != GSS_S_COMPLETE)
+			goto allocation_failure;
+	}
+
+
+	*dest_name = (gss_name_t)dest_union;
+	return (GSS_S_COMPLETE);
+
+allocation_failure:
+	if (dest_union) {
+		if (dest_union->external_name) {
+			if (dest_union->external_name->value)
+				free(dest_union->external_name->value);
+				free(dest_union->external_name);
+		}
+		if (dest_union->name_type)
+			(void) generic_gss_release_oid(minor_status,
+							&dest_union->name_type);
+		if (dest_union->mech_name)
+			(void) __gss_release_internal_name(minor_status,
+						dest_union->mech_type,
+						&dest_union->mech_name);
+		if (dest_union->mech_type)
+			(void) generic_gss_release_oid(minor_status,
+							&dest_union->mech_type);
+		free(dest_union);
+	}
+	return (major_status);
+} /*	gss_duplicate_name	*/
diff --git a/mechglue/src/lib/gssapi/mechglue/g_exp_sec_context.c b/mechglue/src/lib/gssapi/mechglue/g_exp_sec_context.c
new file mode 100644
index 000000000..a9a244366
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_exp_sec_context.c
@@ -0,0 +1,108 @@
+/* #pragma ident	"@(#)g_exp_sec_context.c	1.14	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_export_sec_context
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_export_sec_context(minor_status,
+                       context_handle,
+                       interprocess_token)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t *		context_handle;
+gss_buffer_t		interprocess_token;
+
+{
+    OM_uint32		status;
+    OM_uint32 		length;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+    gss_buffer_desc	token;
+    char		*buf;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (interprocess_token == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    ctx = (gss_union_ctx_id_t) *context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+    if (!mech)
+	return GSS_S_BAD_MECH;
+    if (!mech->gss_export_sec_context)
+	return (GSS_S_UNAVAILABLE);
+    
+    status = mech->gss_export_sec_context(mech->context, minor_status,
+					  &ctx->internal_ctx_id, &token);
+    if (status != GSS_S_COMPLETE)
+	return (status);
+
+    length = token.length + 4 + ctx->mech_type->length;
+    interprocess_token->length = length;
+    interprocess_token->value = malloc(length);
+    if (interprocess_token->value == 0) {
+	(void) gss_release_buffer(minor_status, &token);
+	return (GSS_S_FAILURE);
+    }
+    buf = interprocess_token->value;
+    length = ctx->mech_type->length;
+    buf[3] = (unsigned char) (length & 0xFF);
+    length >>= 8;
+    buf[2] = (unsigned char) (length & 0xFF);
+    length >>= 8;
+    buf[1] = (unsigned char) (length & 0xFF);
+    length >>= 8;
+    buf[0] = (unsigned char) (length & 0xFF);
+    memcpy(buf+4, ctx->mech_type->elements, (size_t) ctx->mech_type->length);
+    memcpy(buf+4+ctx->mech_type->length, token.value, token.length);
+
+    (void) gss_release_buffer(minor_status, &token);
+
+    free(ctx->mech_type->elements);
+    free(ctx->mech_type);
+    free(ctx);
+    *context_handle = 0;
+    
+    return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_export_name.c b/mechglue/src/lib/gssapi/mechglue/g_export_name.c
new file mode 100644
index 000000000..6b5780c2a
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_export_name.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1996,1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* #pragma ident	"@(#)g_export_name.c	1.11	00/07/17 SMI" */
+
+/*
+ * glue routine gss_export_name
+ *
+ * Will either call the mechanism defined gss_export_name, or if one is
+ * not defined will call a generic_gss_export_name routine.
+ */
+
+#include <mglueP.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+OM_uint32
+gss_export_name(minor_status,
+			input_name,
+			exported_name)
+OM_uint32 *		minor_status;
+const gss_name_t	input_name;
+gss_buffer_t		exported_name;
+{
+	gss_union_name_t		union_name;
+
+
+	if (minor_status)
+		*minor_status = 0;
+
+	/* check out parameter */
+	if (!exported_name)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	exported_name->value = NULL;
+	exported_name->length = 0;
+
+	/* check input parameter */
+	if (!input_name)
+		return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+	union_name = (gss_union_name_t)input_name;
+
+	/* the name must be in mechanism specific format */
+	if (!union_name->mech_type)
+		return (GSS_S_NAME_NOT_MN);
+
+	return __gss_export_internal_name(minor_status, union_name->mech_type,
+					union_name->mech_name, exported_name);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_glue.c b/mechglue/src/lib/gssapi/mechglue/g_glue.c
new file mode 100644
index 000000000..d807ff070
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_glue.c
@@ -0,0 +1,584 @@
+/* #pragma ident	"@(#)g_glue.c	1.25	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#define	MSO_BIT (8*(sizeof (int) - 1))  /* Most significant octet bit */
+
+extern gss_mechanism *__gss_mechs_array;
+
+/*
+ * This file contains the support routines for the glue layer.
+ */
+
+/*
+ * get_der_length: Givin a pointer to a buffer that contains a DER encoded
+ * length, decode the length updating the buffer to point to the character
+ * after the DER encoding. The parameter bytes will point to the number of
+ * bytes that made up the DER encoding of the length originally pointed to
+ * by the buffer. Note we return -1 on error.
+ */
+int
+get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
+{
+    /* p points to the beginning of the buffer */
+    unsigned char *p = *buf;
+    int length, new_length;
+    int octets;
+
+    if (buf_len < 1)
+	return (-1);
+
+    /* We should have at least one byte */
+    *bytes = 1;
+
+    /*
+     * If the High order bit is not set then the length is just the value
+     * of *p.
+     */
+    if (*p < 128) {
+	*buf = p+1;	/* Advance the buffer */
+	return (*p);		/* return the length */
+    }
+
+    /*
+     * if the High order bit is set, then the low order bits represent
+     * the number of bytes that contain the DER encoding of the length.
+     */
+
+    octets = *p++ & 0x7f;
+    *bytes += octets;
+
+    /* See if the supplied buffer contains enough bytes for the length. */
+    if (octets > buf_len - 1)
+	return (-1);
+
+    /*
+     * Calculate a multibyte length. The length is encoded as an
+     * unsigned integer base 256.
+     */
+    for (length = 0; octets; octets--) {
+	new_length = (length << 8) + *p++;
+	if (new_length < length)  /* overflow */
+	    return (-1);
+	length = new_length;
+    }
+
+    *buf = p; /* Advance the buffer */
+
+    return (length);
+}
+
+/*
+ * der_length_size: Return the number of bytes to encode a given length.
+ */
+unsigned int
+der_length_size(unsigned int len)
+{
+    int i;
+
+    if (len < 128)
+	return (1);
+
+    for (i = 0; len; i++) {
+	len >>= 8;
+    }
+
+    return (i+1);
+}
+
+/*
+ * put_der_length: Encode the supplied length into the buffer pointed to
+ * by buf. max_length represents the maximum length of the buffer pointed
+ * to by buff. We will advance buf to point to the character after the newly
+ * DER encoded length. We return 0 on success or -l it the length cannot
+ * be encoded in max_len characters.
+ */
+int
+put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len)
+{
+    unsigned char *s = *buf, *p;
+    unsigned int buf_len = 0;
+    int i, first;
+
+    /* Oops */
+    if (buf == 0 || max_len < 1)
+	return (-1);
+
+    /* Single byte is the length */
+    if (length < 128) {
+	*s++ = length;
+	*buf = s;
+	return (0);
+    }
+
+    /* First byte contains the number of octets */
+    p = s + 1;
+
+    /* Running total of the DER encoding length */
+    buf_len = 0;
+
+    /*
+     * Encode MSB first. We do the encoding by setting a shift
+     * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
+     * by the factor. We then encode the resulting low order byte.
+     * We subtract 8 from the shift factor and repeat to ecnode the next
+     * byte. We stop when the shift factor is zero or we've run out of
+     * buffer to encode into.
+     */
+    first = 0;
+    for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
+	unsigned int v;
+	v = (length >> i) & 0xff;
+	if ((v) || first) {
+	    buf_len += 1;
+	    *p++ = v;
+	    first = 1;
+	}
+    }
+    if (i >= 0)			/* buffer overflow */
+	return (-1);
+
+    /*
+     * We go back now and set the first byte to be the length with
+     * the high order bit set.
+     */
+    *s = buf_len | 0x80;
+    *buf = p;
+
+    return (0);
+}
+
+
+/*
+ *  glue routine for get_mech_type
+ *
+ */
+
+OM_uint32 __gss_get_mech_type(OID, token)
+    gss_OID		OID;
+    gss_buffer_t	token;
+{
+    unsigned char * buffer_ptr;
+    int length;
+    
+    /*
+     * This routine reads the prefix of "token" in order to determine
+     * its mechanism type. It assumes the encoding suggested in
+     * Appendix B of RFC 1508. This format starts out as follows :
+     *
+     * tag for APPLICATION 0, Sequence[constructed, definite length]
+     * length of remainder of token
+     * tag of OBJECT IDENTIFIER
+     * length of mechanism OID
+     * encoding of mechanism OID
+     * <the rest of the token>
+     *
+     * Numerically, this looks like :
+     *
+     * 0x60
+     * <length> - could be multiple bytes
+     * 0x06
+     * <length> - assume only one byte, hence OID length < 127
+     * <mech OID bytes>
+     *
+     * The routine fills in the OID value and returns an error as necessary.
+     */
+    
+	if (OID == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	if ((token == NULL) || (token->value == NULL))
+	return (GSS_S_DEFECTIVE_TOKEN);
+    
+    /* Skip past the APP/Sequnce byte and the token length */
+    
+    buffer_ptr = (unsigned char *) token->value;
+
+    if (*(buffer_ptr++) != 0x60)
+	return (GSS_S_DEFECTIVE_TOKEN);
+    length = *buffer_ptr++;
+
+	/* check if token length is null */
+	if (length == 0)
+	    return (GSS_S_DEFECTIVE_TOKEN);
+
+    if (length & 0x80) {
+	if ((length & 0x7f) > 4)
+	    return (GSS_S_DEFECTIVE_TOKEN);
+	buffer_ptr += length & 0x7f;
+    }
+    
+    if (*(buffer_ptr++) != 0x06)
+	return (GSS_S_DEFECTIVE_TOKEN);
+    
+    OID->length = (OM_uint32) *(buffer_ptr++);
+    OID->elements = (void *) buffer_ptr;
+    return (GSS_S_COMPLETE);
+}
+
+
+/*
+ *  Internal routines to get and release an internal mechanism name
+ */
+
+#include "mglueP.h"
+
+OM_uint32 __gss_import_internal_name (minor_status, mech_type, union_name, 
+				internal_name)
+OM_uint32	*minor_status;
+gss_OID		mech_type;
+gss_union_name_t	union_name;
+gss_name_t	*internal_name;
+{
+    OM_uint32		status;
+    gss_mechanism	mech;
+
+    mech = __gss_get_mechanism (mech_type);
+    if (mech) {
+	if (mech->gss_import_name)
+	    status = mech->gss_import_name (
+					    mech->context,
+					    minor_status,
+					    union_name->external_name,
+					    union_name->name_type,
+					    internal_name);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return (status);
+    }
+
+    return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 __gss_export_internal_name(minor_status, mech_type,
+				     internal_name, name_buf)
+    OM_uint32		*minor_status;
+    const gss_OID		mech_type;
+    const gss_name_t	internal_name;
+    gss_buffer_t		name_buf;
+{
+    OM_uint32 status;
+    gss_mechanism mech;
+    gss_buffer_desc dispName;
+    gss_OID nameOid;
+    unsigned char *buf = NULL;
+    const unsigned char tokId[] = "\x04\x01";
+    const unsigned int tokIdLen = 2;
+    const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
+    int mechOidDERLen = 0;
+    int mechOidLen = 0;
+
+    mech = __gss_get_mechanism(mech_type);
+    if (!mech)
+	return (GSS_S_BAD_MECH);
+
+    if (mech->gss_export_name)
+	return (mech->gss_export_name(mech->context,
+				      minor_status,
+				      internal_name,
+				      name_buf));
+
+    /*
+     * if we are here it is because the mechanism does not provide
+     * a gss_export_name so we will use our implementation.  We
+     * do required that the mechanism define a gss_display_name.
+     */
+    if (!mech->gss_display_name)
+	return (GSS_S_UNAVAILABLE);
+
+    /*
+     * NOTE: RFC2743 (section 3.2) governs the format of the outer
+     *	 wrapper of exported names; the mechanisms' specs govern
+     *	 the format of the inner portion of the exported name
+     *	 and, for some (e.g., RFC1964, the Kerberos V mech), a
+     *	 generic default as implemented here will do.
+     *
+     * The outer wrapper of an exported MN is: 2-octet tok Id
+     * (0x0401) + 2-octet network-byte order mech OID length + mech
+     * oid (in DER format, including DER tag and DER length) +
+     * 4-octet network-byte order length of inner portion + inner
+     * portion.
+     *
+     * For the Kerberos V mechanism the inner portion of an exported
+     * MN is the display name string and ignores the name type OID
+     * altogether.  And we hope this will be so for any future
+     * mechanisms also, so that factoring name export/import out of
+     * the mech and into libgss pays off.
+     */
+    if ((status = mech->gss_display_name(mech->context,
+					 minor_status,
+					 internal_name,
+					 &dispName,
+					 &nameOid))
+	!= GSS_S_COMPLETE)
+	return (status);
+
+    /* determine the size of the buffer needed */
+    mechOidDERLen = der_length_size(mech_type->length);
+    name_buf->length = tokIdLen + mechOidLenLen +
+	mechOidTagLen + mechOidDERLen +
+	mech_type->length +
+	nameLenLen + dispName.length;
+    if ((name_buf->value = (void*)malloc(name_buf->length)) ==
+	(void*)NULL) {
+	name_buf->length = 0;
+	(void) gss_release_buffer(&status, &dispName);
+	return (GSS_S_FAILURE);
+    }
+
+    /* now create the name ..... */
+    buf = (unsigned char *)name_buf->value;
+    (void) memset(name_buf->value, 0, name_buf->length);
+    (void) memcpy(buf, tokId, tokIdLen);
+    buf += tokIdLen;
+
+    /* spec allows only 2 bytes for the mech oid length */
+    mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
+    *buf++ = (mechOidLen & 0xFF00) >> 8;
+    *buf++ = (mechOidLen & 0x00FF);
+
+    /*
+     * DER Encoding of mech OID contains OID Tag (0x06), length and
+     * mech OID value
+     */
+    *buf++ = 0x06;
+    if (put_der_length(mech_type->length, &buf,
+		       (name_buf->length - tokIdLen -2)) != 0) {
+	name_buf->length = 0;
+	free(name_buf->value);
+	(void) gss_release_buffer(&status, &dispName);
+	return (GSS_S_FAILURE);
+    }
+
+    (void) memcpy(buf, mech_type->elements, mech_type->length);
+    buf += mech_type->length;
+
+    /* spec designates the next 4 bytes for the name length */
+    *buf++ = (dispName.length & 0xFF000000) >> 24;
+    *buf++ = (dispName.length & 0x00FF0000) >> 16;
+    *buf++ = (dispName.length & 0x0000FF00) >> 8;
+    *buf++ = (dispName.length & 0X000000FF);
+
+    /* for the final ingredient - add the name from gss_display_name */
+    (void) memcpy(buf, dispName.value, dispName.length);
+
+    /* release the buffer obtained from gss_display_name */
+    (void) gss_release_buffer(minor_status, &dispName);
+    return (GSS_S_COMPLETE);
+} /*  __gss_export_internal_name */
+
+OM_uint32 __gss_display_internal_name (minor_status, mech_type, internal_name, 
+				 external_name, name_type)
+OM_uint32	*minor_status;
+gss_OID		mech_type;
+gss_name_t	internal_name;
+gss_buffer_t	external_name;
+gss_OID		*name_type;
+{
+    OM_uint32		status;
+    gss_mechanism	mech;
+
+    mech = __gss_get_mechanism (mech_type);
+    if (mech) {
+	if (mech->gss_display_name)
+	    status = mech->gss_display_name (
+					     mech->context,
+					     minor_status,
+					     internal_name,
+					     external_name,
+					     name_type);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return (status);
+    }
+
+    return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 __gss_release_internal_name (minor_status, mech_type, internal_name)
+OM_uint32	*minor_status;
+gss_OID		mech_type;
+gss_name_t	*internal_name;
+{
+    OM_uint32		status;
+    gss_mechanism	mech;
+
+    mech = __gss_get_mechanism (mech_type);
+    if (mech) {
+	if (mech->gss_release_name)
+	    status = mech->gss_release_name (
+					     mech->context,
+					     minor_status,
+					     internal_name);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return (status);
+    }
+
+    return (GSS_S_BAD_MECH);
+}
+
+
+/*
+ * This function converts an internal gssapi name to a union gssapi
+ * name.  Note that internal_name should be considered "consumed" by
+ * this call, whether or not we return an error.
+ */
+OM_uint32 __gss_convert_name_to_union_name(minor_status, mech,
+					   internal_name, external_name)
+    OM_uint32 *minor_status;
+    gss_mechanism	mech;
+    gss_name_t	internal_name;
+    gss_name_t	*external_name;
+{
+    OM_uint32 major_status,tmp;
+    gss_union_name_t union_name;
+
+    union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
+    if (!union_name) {
+	    goto allocation_failure;
+    }
+    union_name->mech_type = 0;
+    union_name->mech_name = internal_name;
+    union_name->name_type = 0;
+    union_name->external_name = 0;
+
+    major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
+					&union_name->mech_type);
+    if (major_status != GSS_S_COMPLETE)
+	goto allocation_failure;
+
+    union_name->external_name =
+	(gss_buffer_t) malloc(sizeof(gss_buffer_desc));
+    if (!union_name->external_name) {
+	    goto allocation_failure;
+    }
+	
+    major_status = mech->gss_display_name(mech->context, minor_status,
+					  internal_name,
+					  union_name->external_name,
+					  &union_name->name_type);
+    if (major_status != GSS_S_COMPLETE)
+	goto allocation_failure;
+
+    *external_name =  union_name;
+    return (GSS_S_COMPLETE);
+
+allocation_failure:
+    if (union_name) {
+	if (union_name->external_name) {
+	    if (union_name->external_name->value)
+		free(union_name->external_name->value);
+	    free(union_name->external_name);
+	}
+	if (union_name->name_type)
+	    gss_release_oid(&tmp, &union_name->name_type);
+	if (union_name->mech_type)
+	    gss_release_oid(&tmp, &union_name->mech_type);
+	free(union_name);
+    }
+    /*
+     * do as the top comment says - since we are now owners of
+     * internal_name, we must clean it up
+     */
+    if (internal_name)
+	(void) __gss_release_internal_name(&tmp, &mech->mech_type,
+					   &internal_name);
+    return (major_status);
+}
+
+/*
+ * Glue routine for returning the mechanism-specific credential from a
+ * external union credential.
+ */
+gss_cred_id_t
+__gss_get_mechanism_cred(union_cred, mech_type)
+    gss_union_cred_t	union_cred;
+    gss_OID		mech_type;
+{
+    int		i;
+    
+    if (union_cred == GSS_C_NO_CREDENTIAL)
+	return GSS_C_NO_CREDENTIAL;
+    
+    for (i=0; i < union_cred->count; i++) {
+	if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
+	    return union_cred->cred_array[i];
+    }
+    return GSS_C_NO_CREDENTIAL;
+}
+
+/*
+ * Routine to create and copy the gss_buffer_desc structure.
+ * Both space for the structure and the data is allocated.
+ */
+OM_uint32
+__gss_create_copy_buffer(srcBuf, destBuf, addNullChar)
+    const gss_buffer_t	srcBuf;
+    gss_buffer_t 		*destBuf;
+    int			addNullChar;
+{
+    gss_buffer_t aBuf;
+    unsigned int len;
+
+    if (destBuf == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *destBuf = 0;
+
+    aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
+    if (!aBuf)
+	return (GSS_S_FAILURE);
+
+    if (addNullChar)
+	len = srcBuf->length + 1;
+    else
+	len = srcBuf->length;
+
+    if (!(aBuf->value = (void*)malloc(len))) {
+	free(aBuf);
+	return (GSS_S_FAILURE);
+    }
+
+
+    (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
+    aBuf->length = srcBuf->length;
+    *destBuf = aBuf;
+
+    /* optionally add a NULL character */
+    if (addNullChar)
+	((char *)aBuf->value)[aBuf->length] = '\0';
+
+    return (GSS_S_COMPLETE);
+} /* ****** __gss_create_copy_buffer  ****** */
diff --git a/mechglue/src/lib/gssapi/mechglue/g_imp_name.c b/mechglue/src/lib/gssapi/mechglue/g_imp_name.c
new file mode 100644
index 000000000..e68b3e24e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_imp_name.c
@@ -0,0 +1,328 @@
+/* #pragma ident	"@(#)g_imp_name.c	1.26	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine gss_import_name
+ *
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+/* local function to import GSS_C_EXPORT_NAME names */
+static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t);
+
+OM_uint32 KRB5_CALLCONV
+gss_import_name(minor_status,
+                input_name_buffer,
+                input_name_type,
+                output_name)
+
+OM_uint32 *		minor_status;
+gss_buffer_t		input_name_buffer;
+gss_OID			input_name_type;
+gss_name_t *		output_name;
+
+{
+    gss_union_name_t	union_name;
+    OM_uint32		tmp, major_status = GSS_S_FAILURE;
+
+    /* check output parameters */
+    if (!minor_status)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *minor_status = 0;
+
+    if (GSS_EMPTY_BUFFER(input_name_buffer))
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (output_name == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *output_name = 0;
+
+    if (input_name_buffer == GSS_C_NO_BUFFER)
+	return (GSS_S_BAD_NAME);
+
+    /*
+     * First create the union name struct that will hold the external
+     * name and the name type.
+     */
+    union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
+    if (!union_name)
+	return (GSS_S_FAILURE);
+
+    union_name->mech_type = 0;
+    union_name->mech_name = 0;
+    union_name->name_type = 0;
+    union_name->external_name = 0;
+
+    /*
+     * All we do here is record the external name and name_type.
+     * When the name is actually used, the underlying gss_import_name()
+     * is called for the appropriate mechanism.  The exception to this
+     * rule is when the name of GSS_C_NT_EXPORT_NAME type.  If that is
+     * the case, then we make it MN in this call.
+     */
+    major_status = __gss_create_copy_buffer(input_name_buffer,
+					    &union_name->external_name, 0);
+    if (major_status != GSS_S_COMPLETE) {
+	free(union_name);
+	return (major_status);
+    }
+
+    if (input_name_type != GSS_C_NULL_OID) {
+	major_status = generic_gss_copy_oid(minor_status,
+					    input_name_type,
+					    &union_name->name_type);
+	if (major_status != GSS_S_COMPLETE)
+	    goto allocation_failure;
+    }
+
+    /*
+     * In MIT Distribution the mechanism is determined from the nametype;
+     * This is not a good idea - first mechanism that supports a given
+     * name type is picked up; later on the caller can request a
+     * different mechanism. So we don't determine the mechanism here. Now
+     * the user level and kernel level import_name routine looks similar
+     * except the kernel routine makes a copy of the nametype structure. We
+     * do however make this an MN for names of GSS_C_NT_EXPORT_NAME type.
+     */
+    if (input_name_type != GSS_C_NULL_OID &&
+	g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
+	major_status = importExportName(minor_status, union_name);
+	if (major_status != GSS_S_COMPLETE)
+	    goto allocation_failure;
+    }
+
+    *output_name = (gss_name_t)union_name;
+    return (GSS_S_COMPLETE);
+
+allocation_failure:
+    if (union_name) {
+	if (union_name->external_name) {
+	    if (union_name->external_name->value)
+		free(union_name->external_name->value);
+	    free(union_name->external_name);
+	}
+	if (union_name->name_type)
+	    generic_gss_release_oid(&tmp, &union_name->name_type);
+	if (union_name->mech_name)
+	    __gss_release_internal_name(minor_status, union_name->mech_type,
+					&union_name->mech_name);
+	if (union_name->mech_type)
+	    generic_gss_release_oid(&tmp, &union_name->mech_type);
+	free(union_name);
+    }
+    return (major_status);
+}
+
+/*
+ * GSS export name constants
+ */
+static const char *expNameTokId = "\x04\x01";
+static const unsigned int expNameTokIdLen = 2;
+static const unsigned int mechOidLenLen = 2;
+static const unsigned int nameTypeLenLen = 2;
+
+static OM_uint32
+importExportName(minor, unionName)
+    OM_uint32 *minor;
+    gss_union_name_t unionName;
+{
+    gss_OID_desc mechOid;
+    gss_buffer_desc expName;
+    unsigned char *buf;
+    gss_mechanism mech;
+    OM_uint32 major, mechOidLen, nameLen, curLength;
+    unsigned int bytes;
+
+    expName.value = unionName->external_name->value;
+    expName.length = unionName->external_name->length;
+
+    curLength = expNameTokIdLen + mechOidLenLen;
+    if (expName.length < curLength)
+	return (GSS_S_DEFECTIVE_TOKEN);
+
+    buf = (unsigned char *)expName.value;
+    if (memcmp(expNameTokId, buf, expNameTokIdLen) != 0)
+	return (GSS_S_DEFECTIVE_TOKEN);
+
+    buf += expNameTokIdLen;
+
+    /* extract the mechanism oid length */
+    mechOidLen = (*buf++ << 8);
+    mechOidLen |= (*buf++);
+    curLength += mechOidLen;
+    if (expName.length < curLength)
+	return (GSS_S_DEFECTIVE_TOKEN);
+    /*
+     * The mechOid itself is encoded in DER format, OID Tag (0x06)
+     * length and the value of mech_OID
+     */
+    if (*buf++ != 0x06)
+	return (GSS_S_DEFECTIVE_TOKEN);
+
+    /*
+     * mechoid Length is encoded twice; once in 2 bytes as
+     * explained in RFC2743 (under mechanism independent exported
+     * name object format) and once using DER encoding
+     *
+     * We verify both lengths.
+     */
+
+    mechOid.length = get_der_length(&buf,
+				    (expName.length - curLength), &bytes);
+    mechOid.elements = (void *)buf;
+
+    /*
+     * 'bytes' is the length of the DER length, '1' is for the DER
+     * tag for OID
+     */
+    if ((bytes + mechOid.length + 1) != mechOidLen)
+	return (GSS_S_DEFECTIVE_TOKEN);
+
+    buf += mechOid.length;
+    if ((mech = __gss_get_mechanism(&mechOid)) == NULL)
+	return (GSS_S_BAD_MECH);
+
+    if (mech->gss_import_name == NULL)
+	return (GSS_S_UNAVAILABLE);
+
+    /*
+     * we must now determine if we should unwrap the name ourselves
+     * or make the mechanism do it - we should only unwrap it
+     * if we create it; so if mech->gss_export_name == NULL, we must
+     * have created it.
+     */
+    if (mech->gss_export_name) {
+	if ((major = mech->gss_import_name(mech->context, minor,
+					   &expName, (gss_OID)GSS_C_NT_EXPORT_NAME,
+					   &unionName->mech_name)) != GSS_S_COMPLETE ||
+	    (major = generic_gss_copy_oid(minor, &mechOid,
+					  &unionName->mech_type)) !=
+	    GSS_S_COMPLETE) {
+	    return (major);
+	}
+	return (major);
+    }
+    /*
+     * we must have exported the name - so we now need to reconstruct it
+     * and call the mechanism to create it
+     *
+     * WARNING:	Older versions of __gss_export_internal_name() did
+     *		not export names correctly, but now it does.  In
+     *		order to stay compatible with existing exported
+     *		names we must support names exported the broken
+     *		way.
+     *
+     * Specifically, __gss_export_internal_name() used to include
+     * the name type OID in the encoding of the exported MN.
+     * Additionally, the Kerberos V mech used to make display names
+     * that included a null terminator which was counted in the
+     * display name gss_buffer_desc.
+     */
+    curLength += 4;		/* 4 bytes for name len */
+    if (expName.length < curLength)
+	return (GSS_S_DEFECTIVE_TOKEN);
+
+    /* next 4 bytes in the name are the name length */
+    nameLen = (*buf++) << 24;
+    nameLen |= (*buf++ << 16);
+    nameLen |= (*buf++ << 8);
+    nameLen |= (*buf++);
+
+    /*
+     * we use < here because bad code in rpcsec_gss rounds up exported
+     * name token lengths and pads with nulls, otherwise != would be
+     * appropriate
+     */
+    curLength += nameLen;   /* this is the total length */
+    if (expName.length < curLength)
+	return (GSS_S_DEFECTIVE_TOKEN);
+
+    /*
+     * We detect broken exported names here: they always start with
+     * a two-octet network-byte order OID length, which is always
+     * less than 256 bytes, so the first octet of the length is
+     * always '\0', which is not allowed in GSS-API display names
+     * (or never occurs in them anyways).  Of course, the OID
+     * shouldn't be there, but it is.  After the OID (sans DER tag
+     * and length) there's the name itself, though null-terminated;
+     * this null terminator should also not be there, but it is.
+     */
+    if (nameLen > 0 && *buf == '\0') {
+	OM_uint32 nameTypeLen;
+	/* next two bytes are the name oid */
+	if (nameLen < nameTypeLenLen)
+	    return (GSS_S_DEFECTIVE_TOKEN);
+
+	nameLen -= nameTypeLenLen;
+
+	nameTypeLen = (*buf++) << 8;
+	nameTypeLen |= (*buf++);
+
+	if (nameLen < nameTypeLen)
+	    return (GSS_S_DEFECTIVE_TOKEN);
+
+	buf += nameTypeLen;
+	nameLen -= nameTypeLen;
+
+	/*
+	 * adjust for expected null terminator that should
+	 * really not be there
+	 */
+	if (nameLen > 0 && *(buf + nameLen - 1) == '\0')
+	    nameLen--;
+    }
+
+    /*
+     * Can a name be null?  Let the mech decide.
+     *
+     * NOTE: We use GSS_C_NULL_OID as the name type when importing
+     *	 the unwrapped name.  Presumably the exported name had,
+     *	 prior to being exported been obtained in such a way
+     *	 that it has been properly perpared ("canonicalized," in
+     *	 GSS-API terms) accroding to some name type; we cannot
+     *	 tell what that name type was now, but the name should
+     *	 need no further preparation other than the lowest
+     *	 common denominator afforded by the mech to names
+     *	 imported with GSS_C_NULL_OID.  For the Kerberos V mech
+     *	 this means doing less busywork too (particularly once
+     *	 IDN is thrown in with Kerberos V extensions).
+     */
+    expName.length = nameLen;
+    expName.value = nameLen ? (void *)buf : NULL;
+    major = mech->gss_import_name(mech->context, minor, &expName,
+				  GSS_C_NULL_OID, &unionName->mech_name);
+    if (major != GSS_S_COMPLETE)
+	return (major);
+
+    return (generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type));
+} /* importExportName */
diff --git a/mechglue/src/lib/gssapi/mechglue/g_imp_sec_context.c b/mechglue/src/lib/gssapi/mechglue/g_imp_sec_context.c
new file mode 100644
index 000000000..fd3a3af43
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_imp_sec_context.c
@@ -0,0 +1,135 @@
+/* #pragma ident	"@(#)g_imp_sec_context.c	1.18	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine gss_export_sec_context
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_import_sec_context(minor_status,
+                       interprocess_token,
+                       context_handle)
+
+OM_uint32 *		minor_status;
+gss_buffer_t		interprocess_token;
+gss_ctx_id_t *		context_handle;
+
+{
+    OM_uint32		length = 0;
+    OM_uint32		status;
+    char		*p;
+    gss_union_ctx_id_t	ctx;
+    gss_buffer_desc	token;
+    gss_mechanism	mech;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+    
+    if (context_handle == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
+    *context_handle = GSS_C_NO_CONTEXT;
+
+    if (GSS_EMPTY_BUFFER(interprocess_token))
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_DEFECTIVE_TOKEN);
+
+    status = GSS_S_FAILURE;
+
+    ctx = (gss_union_ctx_id_t) malloc(sizeof(gss_union_ctx_id_desc));
+    if (!ctx)
+	return (GSS_S_FAILURE);
+
+    ctx->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc));
+    if (!ctx->mech_type) {
+	free(ctx);
+	return (GSS_S_FAILURE);
+    }
+
+    if (interprocess_token->length >= sizeof (OM_uint32)) {
+	p = interprocess_token->value;
+	length = (OM_uint32)*p++;
+	length = (OM_uint32)(length << 8) + *p++;
+	length = (OM_uint32)(length << 8) + *p++;
+	length = (OM_uint32)(length << 8) + *p++;
+    }
+
+    if (length == 0 ||
+	length > (interprocess_token->length - sizeof (OM_uint32))) {
+	free(ctx);
+	return (GSS_S_CALL_BAD_STRUCTURE | GSS_S_DEFECTIVE_TOKEN);
+    }
+
+    ctx->mech_type->length = length;
+    ctx->mech_type->elements = malloc(length);
+    if (!ctx->mech_type->elements) {
+	goto error_out;
+    }
+    memcpy(ctx->mech_type->elements, p, length);
+    p += length;
+
+    token.length = interprocess_token->length - sizeof (OM_uint32) - length;
+    token.value = p;
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    mech = __gss_get_mechanism (ctx->mech_type);
+    if (!mech) {
+	status = GSS_S_BAD_MECH;
+	goto error_out;
+    }
+    if (!mech->gss_import_sec_context) {
+	status = GSS_S_UNAVAILABLE;
+	goto error_out;
+    }
+    
+    status = mech->gss_import_sec_context(mech->context, minor_status,
+					  &token, &ctx->internal_ctx_id);
+
+    if (status == GSS_S_COMPLETE) {
+	*context_handle = ctx;
+	return (GSS_S_COMPLETE);
+    }
+    
+error_out:
+    if (ctx) {
+	if (ctx->mech_type) {
+	    if (ctx->mech_type->elements)
+		free(ctx->mech_type->elements);
+	    free(ctx->mech_type);
+	}
+	free(ctx);
+    }
+    return status;
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_indicate_mechs.c b/mechglue/src/lib/gssapi/mechglue/g_indicate_mechs.c
new file mode 100644
index 000000000..334f7c1b9
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_indicate_mechs.c
@@ -0,0 +1,90 @@
+/* #ident  "@(#)gss_indicate_mechs.c 1.13     95/08/04 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_indicate_mechs
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+extern gss_mechanism *__gss_mechs_array;
+
+static gss_OID_set_desc	supported_mechs_desc; 
+static gss_OID_set supported_mechs = NULL;
+
+OM_uint32 KRB5_CALLCONV
+gss_indicate_mechs (minor_status,
+                    mech_set)
+
+OM_uint32 *		minor_status;
+gss_OID_set *		mech_set;
+
+{
+    int i;
+    
+    gss_initialize();
+
+    if (minor_status)
+	*minor_status = 0;
+
+    /*
+     * If we have already computed the mechanisms supported, return
+     * a pointer to it. Otherwise, compute them and return the pointer.
+     */
+    
+    if(supported_mechs == NULL) {
+
+	supported_mechs = &supported_mechs_desc;
+	supported_mechs->count = 0;
+
+	/* Build the mech_set from the OIDs in mechs_array. */
+
+	for(i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) 
+	    supported_mechs->count++;
+
+	supported_mechs->elements =
+	    (void *) malloc(supported_mechs->count *
+			    sizeof(gss_OID_desc));
+
+	for(i=0; i < supported_mechs->count; i++) {
+	    supported_mechs->elements[i].length =
+		__gss_mechs_array[i]->mech_type.length;
+	    supported_mechs->elements[i].elements = (void *)
+		malloc(__gss_mechs_array[i]->mech_type.length);
+	    memcpy(supported_mechs->elements[i].elements,
+		   __gss_mechs_array[i]->mech_type.elements,
+		   __gss_mechs_array[i]->mech_type.length);
+	}
+    }
+    
+    if(mech_set != NULL)
+	*mech_set = supported_mechs;
+    
+    return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_init_sec_context.c b/mechglue/src/lib/gssapi/mechglue/g_init_sec_context.c
new file mode 100644
index 000000000..78e0553d8
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_init_sec_context.c
@@ -0,0 +1,212 @@
+/* #pragma ident	"@(#)g_init_sec_context.c	1.20	03/10/24 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_init_sec_context
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_init_sec_context (minor_status,
+                      claimant_cred_handle,
+                      context_handle,
+                      target_name,
+                      req_mech_type,
+                      req_flags,
+                      time_req,
+                      input_chan_bindings,
+                      input_token,
+                      actual_mech_type,
+                      output_token,
+                      ret_flags,
+                      time_rec)
+
+OM_uint32 *		minor_status;
+gss_cred_id_t		claimant_cred_handle;
+gss_ctx_id_t *		context_handle;
+gss_name_t		target_name;
+gss_OID			req_mech_type;
+OM_uint32		req_flags;
+OM_uint32		time_req;
+gss_channel_bindings_t	input_chan_bindings;
+gss_buffer_t		input_token;
+gss_OID *		actual_mech_type;
+gss_buffer_t		output_token;
+OM_uint32 *		ret_flags;
+OM_uint32 *		time_rec;
+
+{
+    OM_uint32		status, temp_minor_status;
+    gss_union_name_t	union_name;
+    gss_union_cred_t	union_cred;
+    gss_name_t		internal_name;
+    gss_union_ctx_id_t	union_ctx_id;
+    gss_OID		mech_type = (gss_OID) req_mech_type;
+    gss_mechanism	mech;
+    gss_cred_id_t	input_cred_handle;
+
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    /* clear output values */
+    if (actual_mech_type)
+	*actual_mech_type = NULL;
+
+    if (context_handle == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT);
+
+    union_name = (gss_union_name_t) target_name;
+
+    if (target_name == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (output_token == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    output_token->value = NULL;
+    output_token->length = 0;
+
+
+    if (req_mech_type)
+	mech_type = (gss_OID)req_mech_type;
+
+    union_name = (gss_union_name_t)target_name;
+    
+    /*
+     * obtain the gss mechanism information for the requested
+     * mechanism.  If mech_type is NULL, set it to the resultant
+     * mechanism
+     */
+    mech = __gss_get_mechanism (mech_type);
+    if (mech == NULL)
+	return (GSS_S_BAD_MECH);
+
+    if (mech->gss_init_sec_context == NULL)
+	return (GSS_S_UNAVAILABLE);
+
+    if (mech_type == GSS_C_NULL_OID)
+	mech_type = &mech->mech_type;
+
+    /*
+     * If target_name is mechanism_specific, then it must match the
+     * mech_type that we're about to use.  Otherwise, do an import on
+     * the external_name form of the target name.
+     */
+    if (union_name->mech_type &&
+	g_OID_equal(union_name->mech_type, mech_type)) {
+	internal_name = union_name->mech_name;
+    } else {
+	if ((status = __gss_import_internal_name(minor_status, mech_type,
+						 union_name,
+						 &internal_name)) != GSS_S_COMPLETE)
+	    return (status);
+    }
+
+    /*
+     * if context_handle is GSS_C_NO_CONTEXT, allocate a union context
+     * descriptor to hold the mech type information as well as the
+     * underlying mechanism context handle. Otherwise, cast the
+     * value of *context_handle to the union context variable.
+     */
+    
+    if(*context_handle == GSS_C_NO_CONTEXT) {
+	status = GSS_S_FAILURE;
+	union_ctx_id = (gss_union_ctx_id_t)
+	    malloc(sizeof(gss_union_ctx_id_desc));
+	if (union_ctx_id == NULL)
+	    goto end;
+
+	union_ctx_id->mech_type = (gss_OID)
+	    malloc(sizeof(gss_OID_desc));
+
+	if (generic_gss_copy_oid(&temp_minor_status, mech_type,
+				 &union_ctx_id->mech_type) != GSS_S_COMPLETE) {
+	    free(union_ctx_id);
+	    goto end;
+	}
+
+	/* copy the supplied context handle */
+	union_ctx_id->internal_ctx_id = *context_handle;
+    } else
+	union_ctx_id = *context_handle;
+    
+    /* 
+     * get the appropriate cred handle from the union cred struct.
+     * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
+     * use the default credential.
+     */
+    union_cred = (gss_union_cred_t) claimant_cred_handle;
+    input_cred_handle = __gss_get_mechanism_cred(union_cred, mech_type);
+    
+    /*
+     * now call the approprate underlying mechanism routine 
+     */
+    
+    status = mech->gss_init_sec_context(
+	mech->context,
+	minor_status,
+	input_cred_handle,
+	&union_ctx_id->internal_ctx_id,
+	internal_name,
+	mech_type,
+	req_flags,
+	time_req,
+	input_chan_bindings,
+	input_token,
+	actual_mech_type,
+	output_token,
+	ret_flags,
+	time_rec);
+
+    if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
+	/*
+	 * the spec says (the preferred) method is to delete all
+	 * context info on the first call to init, and on all
+	 * subsequent calls make the caller responsible for
+	 * calling gss_delete_sec_context
+	 */
+	if (*context_handle == GSS_C_NO_CONTEXT) {
+	    free(union_ctx_id->mech_type->elements);
+	    free(union_ctx_id->mech_type);
+	    free(union_ctx_id);
+	}
+    } else if (*context_handle == GSS_C_NO_CONTEXT)
+	*context_handle = (gss_ctx_id_t)union_ctx_id;
+
+end:
+    if (union_name->mech_name == NULL ||
+	union_name->mech_name != internal_name) {
+	(void) __gss_release_internal_name(&temp_minor_status,
+					   mech_type, &internal_name);
+    }
+
+    return(status);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_initialize.c b/mechglue/src/lib/gssapi/mechglue/g_initialize.c
new file mode 100644
index 000000000..41bbb78ac
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_initialize.c
@@ -0,0 +1,985 @@
+/* #pragma ident	"@(#)g_initialize.c	1.36	05/02/02 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This function will initialize the gssapi mechglue library
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <dlfcn.h>
+
+#define	MECH_CONF "/etc/gss/mech"
+
+#define	MECH_LIB_PREFIX1	"/usr/lib/"
+
+#define	MECH_LIB_PREFIX2	""
+
+#define	MECH_LIB_DIR		"gss/"
+
+#define	MECH_LIB_PREFIX	MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 MECH_LIB_DIR
+
+#define MECH_SYM "gss_mech_initialize"
+
+#define	M_DEFAULT	"default"
+
+#include <sys/stat.h>
+
+#include "k5-thread.h"
+
+extern gss_mechanism krb5_gss_initialize();
+
+static int _gss_initialized = 0;
+
+static struct gss_config null_mech = {
+  {0,NULL}};
+
+gss_mechanism *__gss_mechs_array = NULL;
+
+/* Local functions */
+static gss_mech_info searchMechList(const gss_OID);
+static void loadConfigFile(const char *);
+static void updateMechList(void);
+
+static void init_hardcoded(void);
+
+/*
+ * list of mechanism libraries and their entry points.
+ * the list also maintains state of the mech libraries (loaded or not).
+ */
+static gss_mech_info g_mechList = NULL;
+static gss_mech_info g_mechListTail = NULL;
+static k5_mutex_t g_mechListLock = K5_MUTEX_PARTIAL_INITIALIZER;
+static time_t g_confFileModTime = (time_t)0;
+
+int
+gssint_mechglue_init(void)
+{
+	return k5_mutex_finish_init(&g_mechListLock);
+}
+
+void
+gssint_mechglue_fini(void)
+{
+	k5_mutex_destroy(&g_mechListLock);
+}
+
+
+/*
+ * function used to reclaim the memory used by a gss_OID structure.
+ * This routine requires direct access to the mechList.
+ */
+OM_uint32
+gss_release_oid(minor_status, oid)
+OM_uint32 *minor_status;
+gss_OID *oid;
+{
+	OM_uint32 major;
+	gss_mech_info aMech = g_mechList;
+
+	if (minor_status == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	*minor_status = 0;
+
+	while (aMech != NULL) {
+
+		/*
+		 * look through the loaded mechanism libraries for
+		 * gss_internal_release_oid until one returns success.
+		 * gss_internal_release_oid will only return success when
+		 * the OID was recognized as an internal mechanism OID. if no
+		 * mechanisms recognize the OID, then call the generic version.
+		 */
+
+		/*
+		 * we can walk the mechanism list without a mutex, because we
+		 * are only looking at fields which once read will never change.
+		 * Mechanism entries are always added to the end, and as
+		 * complete entries.
+		 */
+		if (aMech->mech && aMech->mech->gss_internal_release_oid) {
+			major = aMech->mech->gss_internal_release_oid(
+					aMech->mech->context,
+					minor_status, oid);
+			if (major == GSS_S_COMPLETE)
+				return (GSS_S_COMPLETE);
+		}
+		aMech = aMech->next;
+	} /* while */
+
+	return (generic_gss_release_oid(minor_status, oid));
+} /* gss_release_oid */
+
+
+/*
+ * this function will return an oid set indicating available mechanisms.
+ * The set returned is based on configuration file entries and
+ * NOT on the loaded mechanisms.  This function does not check if any
+ * of these can actually be loaded.
+ * This routine needs direct access to the mechanism list.
+ * To avoid reading the configuration file each call, we will save a
+ * a mech oid set, and only update it once the file has changed.
+ */
+static time_t g_mechSetTime = (time_t)0;
+static gss_OID_set_desc g_mechSet = { 0, NULL };
+static k5_mutex_t g_mechSetLock;
+
+
+OM_uint32
+gss_indicate_mechs(minorStatus, mechSet)
+OM_uint32 *minorStatus;
+gss_OID_set *mechSet;
+{
+	gss_mech_info mList;
+	char *fileName;
+	struct stat fileInfo;
+	int count, i, j;
+	gss_OID curItem;
+
+	if (!minorStatus)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	*minorStatus = 0;
+
+
+	/* check output parameter */
+	if (mechSet == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	fileName = MECH_CONF;
+
+	/*
+	 * If we have already computed the mechanisms supported and if it
+	 * is still valid; make a copy and return to caller,
+	 * otherwise build it first.
+	 */
+	if ((stat(fileName, &fileInfo) == 0 &&
+		fileInfo.st_mtime > g_mechSetTime)) {
+		/*
+		 * lock the mutex since we will be updating
+		 * the mechList structure
+		 * we need to keep the lock while we build the mechanism list
+		 * since we are accessing parts of the mechList which could be
+		 * modified.
+		 */
+		(void) k5_mutex_lock(&g_mechListLock);
+
+		/*
+		 * this checks for the case when we need to re-construct the
+		 * g_mechSet structure, but the mechanism list is upto date
+		 * (because it has been read by someone calling
+		 * __gss_get_mechanism)
+		 */
+		if (fileInfo.st_mtime > g_confFileModTime)
+		{
+			g_confFileModTime = fileInfo.st_mtime;
+			loadConfigFile(fileName);
+		}
+
+		/*
+		 * we need to lock the mech set so that no one else will
+		 * try to read it as we are re-creating it
+		 */
+		(void) k5_mutex_lock(&g_mechSetLock);
+
+		/* if the oid list already exists we must free it first */
+		if (g_mechSet.count != 0) {
+			for (i = 0; i < g_mechSet.count; i++)
+				free(g_mechSet.elements[i].elements);
+			free(g_mechSet.elements);
+			g_mechSet.elements = NULL;
+			g_mechSet.count = 0;
+		}
+
+		/* determine how many elements to have in the list */
+		mList = g_mechList;
+		count = 0;
+		while (mList != NULL) {
+			count++;
+			mList = mList->next;
+		}
+
+		/* this should always be true, but.... */
+		if (count > 0) {
+			g_mechSet.elements =
+				(gss_OID) calloc(count, sizeof (gss_OID_desc));
+			if (g_mechSet.elements == NULL) {
+				(void) k5_mutex_unlock(&g_mechSetLock);
+				(void) k5_mutex_unlock(&g_mechListLock);
+				return (GSS_S_FAILURE);
+			}
+
+			(void) memset(g_mechSet.elements, 0,
+				count * sizeof (gss_OID_desc));
+
+			/* now copy each oid element */
+			g_mechSet.count = count;
+			count = 0;
+			mList = g_mechList;
+			while (mList != NULL) {
+				curItem = &(g_mechSet.elements[count]);
+				curItem->elements = (void*)
+					malloc(mList->mech_type->length);
+				if (curItem->elements == NULL) {
+					/*
+					 * this is nasty - we must delete the
+					 * part of the array already copied
+					 */
+					for (i = 0; i < count; i++) {
+						free(g_mechSet.elements[i].
+							elements);
+					}
+					free(g_mechSet.elements);
+					g_mechSet.count = 0;
+					g_mechSet.elements = NULL;
+					(void) k5_mutex_unlock(&g_mechSetLock);
+					(void) k5_mutex_unlock(&g_mechListLock);
+					return (GSS_S_FAILURE);
+				}
+				g_OID_copy(curItem, mList->mech_type);
+				count++;
+				mList = mList->next;
+			}
+		}
+
+		g_mechSetTime = fileInfo.st_mtime;
+		(void) k5_mutex_unlock(&g_mechSetLock);
+		(void) k5_mutex_unlock(&g_mechListLock);
+	} /* if g_mechSet is out of date or not initialized */
+
+	/*
+	 * the mech set is created and it is up to date
+	 * so just copy it to caller
+	 */
+	if ((*mechSet =
+		(gss_OID_set) malloc(sizeof (gss_OID_set_desc))) == NULL)
+	{
+		return (GSS_S_FAILURE);
+	}
+
+	/*
+	 * need to lock the g_mechSet in case someone tries to update it while
+	 * I'm copying it.
+	 */
+	(void) k5_mutex_lock(&g_mechSetLock);
+
+	/* allocate space for the oid structures */
+	if (((*mechSet)->elements =
+		(void*) calloc(g_mechSet.count, sizeof (gss_OID_desc)))
+		== NULL)
+	{
+		(void) k5_mutex_unlock(&g_mechSetLock);
+		free(*mechSet);
+		*mechSet = NULL;
+		return (GSS_S_FAILURE);
+	}
+
+	/* now copy the oid structures */
+	(void) memcpy((*mechSet)->elements, g_mechSet.elements,
+		g_mechSet.count * sizeof (gss_OID_desc));
+
+	(*mechSet)->count = g_mechSet.count;
+
+	/* still need to copy each of the oid elements arrays */
+	for (i = 0; i < (*mechSet)->count; i++) {
+		curItem = &((*mechSet)->elements[i]);
+		curItem->elements =
+			(void *) malloc(g_mechSet.elements[i].length);
+		if (curItem->elements == NULL) {
+			(void) k5_mutex_unlock(&g_mechSetLock);
+			/*
+			 * must still free the allocated elements for
+			 * each allocated gss_OID_desc
+			 */
+			for (j = 0; j < i; j++) {
+				free((*mechSet)->elements[j].elements);
+			}
+			free((*mechSet)->elements);
+			free(mechSet);
+			*mechSet = NULL;
+			return (GSS_S_FAILURE);
+		}
+		g_OID_copy(curItem, &g_mechSet.elements[i]);
+	}
+	(void) k5_mutex_unlock(&g_mechSetLock);
+	return (GSS_S_COMPLETE);
+} /* gss_indicate_mechs */
+
+/*
+ * this function has been added for use by modules that need to
+ * know what (if any) optional parameters are supplied in the
+ * config file (MECH_CONF).
+ * It will return the option string for a specified mechanism.
+ * caller is responsible for freeing the memory
+ */
+char *
+__gss_get_modOptions(oid)
+const gss_OID oid;
+{
+	gss_mech_info aMech;
+	char *modOptions = NULL;
+
+	/* make sure we have fresh data */
+	(void) k5_mutex_lock(&g_mechListLock);
+	updateMechList();
+	(void) k5_mutex_unlock(&g_mechListLock);
+
+	/* searching the list does not require a lock */
+	if ((aMech = searchMechList(oid)) == NULL ||
+		aMech->optionStr == NULL) {
+		return (NULL);
+	}
+
+	/*
+	 * need to obtain a lock on this structure in case someone else
+	 * will try to update it during the copy
+	 */
+	(void) k5_mutex_lock(&g_mechListLock);
+	if (aMech->optionStr)
+		modOptions = strdup(aMech->optionStr);
+	(void) k5_mutex_unlock(&g_mechListLock);
+
+	return (modOptions);
+} /* __gss_get_modOptions */
+
+/*
+ * given a mechanism string return the mechanism oid
+ */
+OM_uint32
+__gss_mech_to_oid(const char *mechStr, gss_OID* oid)
+{
+	gss_mech_info aMech;
+
+	if (oid == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	*oid = GSS_C_NULL_OID;
+
+	if ((mechStr == NULL) || (strlen(mechStr) == 0) ||
+		(strcasecmp(mechStr, M_DEFAULT) == 0))
+		return (GSS_S_COMPLETE);
+
+	/* ensure we have fresh data */
+	(void) k5_mutex_lock(&g_mechListLock);
+	updateMechList();
+	(void) k5_mutex_unlock(&g_mechListLock);
+
+	aMech = g_mechList;
+
+	/* no lock required - only looking at fields that are not updated */
+	while (aMech != NULL) {
+		if ((aMech->mechNameStr) &&
+			strcmp(aMech->mechNameStr, mechStr) == 0) {
+			*oid = aMech->mech_type;
+			return (GSS_S_COMPLETE);
+		}
+		aMech = aMech->next;
+	}
+	return (GSS_S_FAILURE);
+} /* __gss_mech_to_oid */
+
+
+/*
+ * Given the mechanism oid, return the readable mechanism name
+ * associated with that oid from the mech config file
+ * (/etc/gss/mech).
+ */
+const char *
+__gss_oid_to_mech(const gss_OID oid)
+{
+	gss_mech_info aMech;
+
+	if (oid == GSS_C_NULL_OID)
+		return (M_DEFAULT);
+
+	/* ensure we have fresh data */
+	(void) k5_mutex_lock(&g_mechListLock);
+	updateMechList();
+	(void) k5_mutex_unlock(&g_mechListLock);
+
+	if ((aMech = searchMechList(oid)) == NULL)
+		return (NULL);
+
+	return (aMech->mechNameStr);
+} /* __gss_oid_to_mech */
+
+
+/*
+ * return a list of mechanism strings supported
+ * upon return the array is terminated with a NULL entry
+ */
+OM_uint32
+__gss_get_mechanisms(char *mechArray[], int arrayLen)
+{
+	gss_mech_info aMech;
+	int i;
+
+	if (gssint_initialize_library())
+		return GSS_S_FAILURE;
+	if (mechArray == NULL || arrayLen < 1)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	/* ensure we have fresh data */
+	(void) k5_mutex_lock(&g_mechListLock);
+	updateMechList();
+	(void) k5_mutex_unlock(&g_mechListLock);
+
+	aMech = g_mechList;
+
+	/* no lock required - only looking at fields that are not updated */
+	for (i = 1; i < arrayLen; i++) {
+		if (aMech != NULL) {
+			*mechArray = aMech->mechNameStr;
+			mechArray++;
+			aMech = aMech->next;
+		} else
+			break;
+	}
+	*mechArray = NULL;
+	return (GSS_S_COMPLETE);
+} /* gss_get_mechanisms */
+
+
+/*
+ * determines if the mechList needs to be updated from file
+ * and performs the update.
+ * this functions must be called with a lock of g_mechListLock
+ */
+static void
+updateMechList(void)
+{
+	char *fileName;
+	struct stat fileInfo;
+
+	init_hardcoded();
+	fileName = MECH_CONF;
+
+	/* check if mechList needs updating */
+	if (stat(fileName, &fileInfo) == 0 &&
+		(fileInfo.st_mtime > g_confFileModTime)) {
+		loadConfigFile(fileName);
+		g_confFileModTime = fileInfo.st_mtime;
+	}
+} /* updateMechList */
+
+
+static void
+init_hardcoded(void)
+{
+	extern struct gss_config krb5_mechanism;
+	gss_mech_info cf;
+
+	if (g_mechList != NULL)
+		return;
+	cf = malloc(sizeof(*cf));
+	if (cf == NULL)
+		return;
+	memset(cf, 0, sizeof(*cf));
+	cf->uLibName = strdup("<hardcoded internal>");
+	cf->mechNameStr = "kerberos_v5";
+	cf->mech_type = &krb5_mechanism.mech_type;
+	cf->mech = &krb5_mechanism;
+	cf->next = NULL;
+	g_mechList = cf;
+}
+
+
+/*
+ * given the mechanism type, return the mechanism structure
+ * containing the mechanism library entry points.
+ * will return NULL if mech type is not found
+ * This function will also trigger the loading of the mechanism
+ * module if it has not been already loaded.
+ */
+gss_mechanism
+__gss_get_mechanism(oid)
+const gss_OID oid;
+{
+	gss_mech_info aMech;
+	gss_mechanism (*sym)(const gss_OID);
+	void *dl;
+
+	if (gssint_initialize_library())
+		return GSS_S_FAILURE;
+
+	/* check if the mechanism is already loaded */
+	if ((aMech = searchMechList(oid)) != NULL && aMech->mech) {
+		return (aMech->mech);
+	}
+
+	/*
+	 * might need to re-read the configuration file before loading
+	 * the mechanism to ensure we have the latest info.
+	 */
+	(void) k5_mutex_lock(&g_mechListLock);
+	updateMechList();
+
+	aMech = searchMechList(oid);
+
+	/* is the mechanism present in the list ? */
+	if (aMech == NULL) {
+		(void) k5_mutex_unlock(&g_mechListLock);
+		return ((gss_mechanism)NULL);
+	}
+
+	/* has another thread loaded the mech */
+	if (aMech->mech) {
+		(void) k5_mutex_unlock(&g_mechListLock);
+		return (aMech->mech);
+	}
+
+	/* we found the mechanism, but it is not loaded */
+	if ((dl = dlopen(aMech->uLibName, RTLD_NOW)) == NULL) {
+#if 0
+		(void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+				aMech->uLibName, dlerror());
+#endif
+		(void) k5_mutex_unlock(&g_mechListLock);
+		return ((gss_mechanism)NULL);
+	}
+
+	if ((sym = (gss_mechanism (*)(const gss_OID))dlsym(dl, MECH_SYM))
+			== NULL) {
+		(void) dlclose(dl);
+#if 0
+		(void) syslog(LOG_INFO, "unable to initialize mechanism"
+				" library [%s]\n", aMech->uLibName);
+#endif
+		(void) k5_mutex_unlock(&g_mechListLock);
+		return ((gss_mechanism)NULL);
+	}
+
+	/* Call the symbol to get the mechanism table */
+	aMech->mech = (*sym)(aMech->mech_type);
+
+	if (aMech->mech == NULL) {
+		(void) dlclose(dl);
+#if 0
+		(void) syslog(LOG_INFO, "unable to initialize mechanism"
+				" library [%s]\n", aMech->uLibName);
+#endif
+		(void) k5_mutex_unlock(&g_mechListLock);
+		return ((gss_mechanism)NULL);
+	}
+
+	aMech->dl_handle = dl;
+
+	(void) k5_mutex_unlock(&g_mechListLock);
+	return (aMech->mech);
+} /* __gss_get_mechanism */
+
+gss_mechanism_ext
+__gss_get_mechanism_ext(oid)
+const gss_OID oid;
+{
+	gss_mech_info aMech;
+	gss_mechanism_ext mech_ext;
+
+	/* check if the mechanism is already loaded */
+	if ((aMech = searchMechList(oid)) != NULL && aMech->mech_ext != NULL)
+		return (aMech->mech_ext);
+
+	if (__gss_get_mechanism(oid) == NULL)
+		return (NULL);
+
+	if (aMech->dl_handle == NULL)
+		return (NULL);
+
+	/* Load the gss_config_ext struct for this mech */
+
+	mech_ext = (gss_mechanism_ext)malloc(sizeof (struct gss_config_ext));
+
+	if (mech_ext == NULL)
+		return (NULL);
+
+	/*
+	 * dlsym() the mech's 'method' functions for the extended APIs
+	 *
+	 * NOTE:  Until the void *context argument is removed from the
+	 * SPI method functions' signatures it will be necessary to have
+	 * different function pointer typedefs and function names for
+	 * the SPI methods than for the API.  When this argument is
+	 * removed it will be possible to rename gss_*_sfct to gss_*_fct
+	 * and and gssspi_* to gss_*.
+	 */
+	mech_ext->gss_acquire_cred_with_password =
+		(gss_acquire_cred_with_password_sfct)dlsym(aMech->dl_handle,
+			"gssspi_acquire_cred_with_password");
+
+	/* Set aMech->mech_ext */
+	(void) k5_mutex_lock(&g_mechListLock);
+
+	if (aMech->mech_ext == NULL)
+		aMech->mech_ext = mech_ext;
+	else
+		free(mech_ext);	/* we raced and lost; don't leak */
+
+	(void) k5_mutex_unlock(&g_mechListLock);
+
+	return (aMech->mech_ext);
+
+} /* __gss_get_mechanism_ext */
+
+
+/*
+ * this routine is used for searching the list of mechanism data.
+ * it needs not be mutex protected because we only add new structures
+ * from the end and they are fully initialized before being added.
+ */
+static gss_mech_info searchMechList(oid)
+const gss_OID oid;
+{
+	gss_mech_info aMech = g_mechList;
+
+	/* if oid is null -> then get default which is the first in the list */
+	if (oid == GSS_C_NULL_OID)
+		return (aMech);
+
+	while (aMech != NULL) {
+		if (g_OID_equal(aMech->mech_type, oid))
+			return (aMech);
+		aMech = aMech->next;
+	}
+
+	/* none found */
+	return ((gss_mech_info) NULL);
+} /* searchMechList */
+
+
+/*
+ * loads the configuration file
+ * this is called while having a mutex lock on the mechanism list
+ * entries for libraries that have been loaded can't be modified
+ * mechNameStr and mech_type fields are not updated during updates
+ */
+static void loadConfigFile(fileName)
+const char *fileName;
+{
+	char buffer[BUFSIZ], *oidStr, *oid, *sharedLib, *kernMod, *endp;
+	char *modOptions;
+	char sharedPath[sizeof (MECH_LIB_PREFIX) + BUFSIZ];
+	char *tmpStr;
+	FILE *confFile;
+	gss_OID mechOid;
+	gss_mech_info aMech, tmp;
+	OM_uint32 minor;
+	gss_buffer_desc oidBuf;
+
+	if ((confFile = fopen(fileName, "r")) == NULL) {
+		return;
+	}
+
+	(void) memset(buffer, 0, sizeof (buffer));
+	while (fgets(buffer, BUFSIZ, confFile) != NULL) {
+
+		/* ignore lines beginning with # */
+		if (*buffer == '#')
+			continue;
+
+		/*
+		 * find the first white-space character after
+		 * the mechanism name
+		 */
+		oidStr = buffer;
+		for (oid = buffer; *oid && !isspace(*oid); oid++);
+
+		/* Now find the first non-white-space character */
+		if (*oid) {
+			*oid = '\0';
+			oid++;
+			while (*oid && isspace(*oid))
+				oid++;
+		}
+
+		/*
+		 * If that's all, then this is a corrupt entry. Skip it.
+		 */
+		if (! *oid)
+			continue;
+
+		/* Find the end of the oid and make sure it is NULL-ended */
+		for (endp = oid; *endp && !isspace(*endp); endp++)
+			;
+
+		if (*endp) {
+			*endp = '\0';
+		}
+
+		/*
+		 * check if an entry for this oid already exists
+		 * if it does, and the library is already loaded then
+		 * we can't modify it, so skip it
+		 */
+		oidBuf.value = (void *)oid;
+		oidBuf.length = strlen(oid);
+		if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
+			!= GSS_S_COMPLETE) {
+#if 0
+			(void) syslog(LOG_INFO, "invalid mechanism oid"
+					" [%s] in configuration file", oid);
+#endif
+			continue;
+		}
+
+		aMech = searchMechList(mechOid);
+		if (aMech && aMech->mech) {
+			free(mechOid->elements);
+			free(mechOid);
+			continue;
+		}
+
+		/* Find the start of the shared lib name */
+		for (sharedLib = endp+1; *sharedLib && isspace(*sharedLib);
+			sharedLib++)
+			;
+
+		/*
+		 * If that's all, then this is a corrupt entry. Skip it.
+		 */
+		if (! *sharedLib) {
+			free(mechOid->elements);
+			free(mechOid);
+			continue;
+		}
+
+		/*
+		 * Find the end of the shared lib name and make sure it is
+		 *  NULL-terminated.
+		 */
+		for (endp = sharedLib; *endp && !isspace(*endp); endp++)
+			;
+
+		if (*endp) {
+			*endp = '\0';
+		}
+
+		/* Find the start of the optional kernel module lib name */
+		for (kernMod = endp+1; *kernMod && isspace(*kernMod);
+			kernMod++)
+			;
+
+		/*
+		 * If this item starts with a bracket "[", then
+		 * it is not a kernel module, but is a list of
+		 * options for the user module to parse later.
+		 */
+		if (*kernMod && *kernMod != '[') {
+			/*
+			 * Find the end of the shared lib name and make sure
+			 * it is NULL-terminated.
+			 */
+			for (endp = kernMod; *endp && !isspace(*endp); endp++)
+				;
+
+			if (*endp) {
+				*endp = '\0';
+			}
+		} else
+			kernMod = NULL;
+
+		/* Find the start of the optional module options list */
+		for (modOptions = endp+1; *modOptions && isspace(*modOptions);
+			modOptions++);
+
+		if (*modOptions == '[')  {
+			/* move past the opening bracket */
+			for (modOptions = modOptions+1;
+			    *modOptions && isspace(*modOptions);
+			    modOptions++);
+
+			/* Find the closing bracket */
+			for (endp = modOptions;
+				*endp && *endp != ']'; endp++);
+
+			if (endp)
+				*endp = '\0';
+
+		} else {
+			modOptions = NULL;
+		}
+
+		(void) strcpy(sharedPath, MECH_LIB_PREFIX);
+		(void) strcat(sharedPath, sharedLib);
+
+		/*
+		 * are we creating a new mechanism entry or
+		 * just modifying existing (non loaded) mechanism entry
+		 */
+		if (aMech) {
+			/*
+			 * delete any old values and set new
+			 * mechNameStr and mech_type are not modified
+			 */
+			if (aMech->kmodName) {
+				free(aMech->kmodName);
+				aMech->kmodName = NULL;
+			}
+
+			if (aMech->optionStr) {
+				free(aMech->optionStr);
+				aMech->optionStr = NULL;
+			}
+
+			if ((tmpStr = strdup(sharedPath)) != NULL) {
+				if (aMech->uLibName)
+					free(aMech->uLibName);
+				aMech->uLibName = tmpStr;
+			}
+
+			if (kernMod) /* this is an optional parameter */
+				aMech->kmodName = strdup(kernMod);
+
+			if (modOptions) /* optional module options */
+				aMech->optionStr = strdup(modOptions);
+
+			/* the oid is already set */
+			free(mechOid->elements);
+			free(mechOid);
+			continue;
+		}
+
+		/* adding a new entry */
+		aMech = malloc(sizeof (struct gss_mech_config));
+		if (aMech == NULL) {
+			free(mechOid->elements);
+			free(mechOid);
+			continue;
+		}
+		(void) memset(aMech, 0, sizeof (struct gss_mech_config));
+		aMech->mech_type = mechOid;
+		aMech->uLibName = strdup(sharedPath);
+		aMech->mechNameStr = strdup(oidStr);
+
+		/* check if any memory allocations failed - bad news */
+		if (aMech->uLibName == NULL || aMech->mechNameStr == NULL) {
+			if (aMech->uLibName)
+				free(aMech->uLibName);
+			if (aMech->mechNameStr)
+				free(aMech->mechNameStr);
+			free(mechOid->elements);
+			free(mechOid);
+			free(aMech);
+			continue;
+		}
+		if (kernMod)	/* this is an optional parameter */
+			aMech->kmodName = strdup(kernMod);
+
+		if (modOptions)
+			aMech->optionStr = strdup(modOptions);
+		/*
+		 * add the new entry to the end of the list - make sure
+		 * that only complete entries are added because other
+		 * threads might currently be searching the list.
+		 */
+		tmp = g_mechListTail;
+		g_mechListTail = aMech;
+
+		if (tmp != NULL)
+			tmp->next = aMech;
+
+		if (g_mechList == NULL)
+			g_mechList = aMech;
+	} /* while */
+	(void) fclose(confFile);
+} /* loadConfigFile */
+
+
+#ifdef USE_SOLARIS_SHARED_LIBRARIES
+/* 
+ * read the configuration file to find out what mechanisms to
+ * load, load them, and then load the mechanism defitions in
+ * and add the mechanisms
+ */
+static void solaris_initialize ()
+{
+    char buffer[BUFSIZ], *filename, *symname, *endp;
+    FILE *conffile;
+    void *dl;
+    gss_mechanism (*sym)(void), mech;
+
+    if ((filename = getenv("GSSAPI_MECH_CONF")) == NULL)
+	filename = MECH_CONF;
+
+    if ((conffile = fopen(filename, "r")) == NULL)
+	return;
+
+    while (fgets (buffer, BUFSIZ, conffile) != NULL) {
+	/* ignore lines beginning with # */
+	if (*buffer == '#')
+	    continue;
+
+	/* find the first white-space character after the filename */
+	for (symname = buffer; *symname && !isspace(*symname); symname++);
+
+	/* Now find the first non-white-space character */
+	if (*symname) {
+	    *symname = '\0';
+	    symname++;
+	    while (*symname && isspace(*symname))
+		symname++;
+	}
+
+	if (! *symname)
+	    symname = MECH_SYM;
+	else {
+	  /* Find the end of the symname and make sure it is NULL-terminated */
+	  for (endp = symname; *endp && !isspace(*endp); endp++);
+	  if (*endp)
+	    *endp = '\0';
+	}
+
+	if ((dl = dlopen(buffer, RTLD_NOW)) == NULL) {
+		/* for debugging only */
+		fprintf(stderr,"can't open %s: %s\n",buffer, dlerror());
+		continue;
+	}
+
+	if ((sym = (gss_mechanism (*)(void))dlsym(dl, symname)) == NULL) {
+	    dlclose(dl);
+	    continue;
+	}
+
+	/* Call the symbol to get the mechanism table */
+	mech = sym();
+
+	/* And add the mechanism (or close the shared library) */
+	if (mech)
+	    add_mechanism (mech, 1);
+	else
+	    dlclose(dl);
+
+    } /* while */
+
+    return;
+}
+#endif /* USE_SOLARIS_SHARED_LIBRARIES */
diff --git a/mechglue/src/lib/gssapi/mechglue/g_inq_context.c b/mechglue/src/lib/gssapi/mechglue/g_inq_context.c
new file mode 100644
index 000000000..ec1ace62b
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_inq_context.c
@@ -0,0 +1,144 @@
+/* #pragma ident	"@(#)g_inquire_context.c	1.15	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_inquire_context
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/* Last argument new for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_context(
+	    minor_status,
+	    context_handle,
+	    src_name,
+	    targ_name,
+	    lifetime_rec,
+	    mech_type,
+	    ctx_flags,
+	    locally_initiated,
+	    open)
+
+OM_uint32 *	minor_status;
+gss_ctx_id_t	context_handle;
+gss_name_t *	src_name;
+gss_name_t *	targ_name;
+OM_uint32 *	lifetime_rec;
+gss_OID *	mech_type;
+OM_uint32 *	ctx_flags;
+int *           locally_initiated;
+int *		open;
+
+
+{
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+    OM_uint32		status, temp_minor;
+    gss_name_t localTargName = NULL, localSourceName = NULL;
+    
+    if (!minor_status)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *minor_status = 0;
+    
+    /* if the context_handle is Null, return NO_CONTEXT error */
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    /* set all output value to NULL */
+    if (src_name)
+	*src_name = NULL;
+
+    if (targ_name)
+	*targ_name = NULL;
+
+    if (mech_type)
+	*mech_type = NULL;
+    
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+    
+    if (!mech || !mech->gss_inquire_context || !mech->gss_display_name ||
+	!mech->gss_release_name) {
+	return (GSS_S_UNAVAILABLE);
+    }
+
+    status = mech->gss_inquire_context(
+			mech->context,
+			minor_status,
+			ctx->internal_ctx_id,
+			(src_name ? &localSourceName : NULL),
+			(targ_name ? &localTargName : NULL),
+			lifetime_rec,
+			NULL,
+			ctx_flags,
+			locally_initiated,
+			open);
+
+    if (status != GSS_S_COMPLETE) {
+	return status;
+    }
+
+    /* need to convert names */
+
+    if (src_name) {
+	    status = __gss_convert_name_to_union_name(minor_status, mech,
+						      localSourceName, src_name);
+
+	    if (status != GSS_S_COMPLETE) {
+		if (localTargName)
+		    mech->gss_release_name(mech->context,
+					   &temp_minor, &localTargName);
+		return (status);
+	    }
+
+    }
+
+    if (targ_name) {
+	    status = __gss_convert_name_to_union_name(minor_status, mech,
+						      localTargName, targ_name);
+
+	    if (status != GSS_S_COMPLETE) {
+		if (src_name)
+		    (void) gss_release_name(&temp_minor, src_name);
+
+		return (status);
+	    }
+    }
+
+    /* spec says mech type must point to static storage */
+    if (mech_type)
+	*mech_type = &mech->mech_type;
+    return(GSS_S_COMPLETE);
+}
+
diff --git a/mechglue/src/lib/gssapi/mechglue/g_inq_cred.c b/mechglue/src/lib/gssapi/mechglue/g_inq_cred.c
new file mode 100644
index 000000000..812fd9dab
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_inq_cred.c
@@ -0,0 +1,255 @@
+/* #pragma ident	"@(#)g_inquire_cred.c	1.16	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_inquire_cred
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_cred(minor_status,
+                 cred_handle,
+                 name,
+                 lifetime,
+		 cred_usage,
+                 mechanisms)
+
+OM_uint32 *		minor_status;
+gss_cred_id_t 		cred_handle;
+gss_name_t *		name;
+OM_uint32 *		lifetime;
+int *			cred_usage;
+gss_OID_set *		mechanisms;
+
+{
+    OM_uint32		status, elapsed_time, temp_minor_status;
+    gss_union_cred_t	union_cred;
+    gss_mechanism	mech;
+    gss_name_t		internal_name;
+    int			i;
+    
+    /* check parms and set to defaults */
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (name)
+	*name = NULL;
+
+    if (mechanisms)
+	*mechanisms = NULL;
+
+    if (cred_handle == GSS_C_NO_CREDENTIAL) {
+	/*
+	 * No credential was supplied. This means we can't get a mechanism
+	 * pointer to call the mechanism specific gss_inquire_cred.
+	 * So, call get_mechanism with an arguement of GSS_C_NULL_OID.
+	 * get_mechanism will return the first mechanism in the mech
+	 * array, which becomes the default mechanism.
+	 */
+
+	if ((mech = __gss_get_mechanism(GSS_C_NULL_OID)) == NULL)
+	    return (GSS_S_DEFECTIVE_CREDENTIAL);
+
+	if (!mech->gss_inquire_cred)
+	    return (GSS_S_UNAVAILABLE);
+	
+	status = mech->gss_inquire_cred(mech->context, minor_status,
+					GSS_C_NO_CREDENTIAL,
+					name ? &internal_name : NULL,
+					lifetime, cred_usage, mechanisms);
+
+	if (status != GSS_S_COMPLETE)
+	    return(status);
+
+	if (name) {
+	    /*
+	     * Convert internal_name into a union_name equivalent.
+	     */
+	    status = __gss_convert_name_to_union_name(&temp_minor_status,
+						      mech, internal_name,
+						      name);
+	    if (status != GSS_S_COMPLETE) {
+		*minor_status = temp_minor_status;
+		if (mechanisms && *mechanisms) {
+		    (void) gss_release_oid_set(
+			&temp_minor_status,
+			mechanisms);
+		}
+		return (status);
+	    }
+	}
+	return(GSS_S_COMPLETE);
+    } 
+	
+    /* get the cred_handle cast as a union_credentials structure */
+	
+    union_cred = (gss_union_cred_t) cred_handle;
+    
+    /*
+     * get the information out of the union_cred structure that was
+     * placed there during gss_acquire_cred.
+     */
+    
+    if(cred_usage != NULL)
+	*cred_usage = union_cred->auxinfo.cred_usage;
+    
+    if(lifetime != NULL) {
+	elapsed_time = time(0) - union_cred->auxinfo.creation_time;
+	*lifetime = union_cred->auxinfo.time_rec < elapsed_time ? 0 :
+	union_cred->auxinfo.time_rec - elapsed_time;
+    }
+    
+    /*
+     * if name is non_null,
+     * call gss_import_name(), giving it the printable name held within
+     * union_cred in order to get an internal name to pass back to the
+     * caller. If this call fails, return failure to our caller.
+     */
+    
+    if(name != NULL) {
+	if ((gss_import_name(&temp_minor_status,
+			     &union_cred->auxinfo.name,
+			     union_cred->auxinfo.name_type,
+			     name) != GSS_S_COMPLETE) ||
+	    (gss_canonicalize_name(minor_status, *name,
+				   &union_cred->mechs_array[0],
+				   NULL) != GSS_S_COMPLETE)) {
+	    status = GSS_S_DEFECTIVE_CREDENTIAL;
+	    goto error;
+	}
+    }
+
+    /*
+     * copy the mechanism set in union_cred into an OID set and return in
+     * the mechanisms parameter.
+     */
+    
+    if(mechanisms != NULL) {
+	status = GSS_S_FAILURE;
+	*mechanisms = (gss_OID_set) malloc(sizeof(gss_OID_set_desc));
+	if (*mechanisms == NULL)
+	    goto error;
+
+	(*mechanisms)->count = 0;
+	(*mechanisms)->elements =
+	    (gss_OID) malloc(sizeof(gss_OID_desc) *
+			     union_cred->count);
+
+	if ((*mechanisms)->elements == NULL) {
+	    free(*mechanisms);
+	    *mechanisms = NULL;
+	    goto error;
+	}
+
+	for(i=0; i < union_cred->count; i++) {
+	    (*mechanisms)->elements[i].elements = (void *)
+		malloc(union_cred->mechs_array[i].length);
+	    if ((*mechanisms)->elements[i].elements == NULL)
+		goto error;
+	    g_OID_copy(&(*mechanisms)->elements[i],
+		       &union_cred->mechs_array[i]);
+	    (*mechanisms)->count++;
+	}
+    }
+    
+    return(GSS_S_COMPLETE);
+
+error:
+    /*
+     * cleanup any allocated memory - we can just call
+     * gss_release_oid_set, because the set is constructed so that
+     * count always references the currently copied number of
+     * elements.
+     */
+    if (mechanisms && *mechanisms != NULL)
+	(void) gss_release_oid_set(&temp_minor_status, mechanisms);
+
+    if (name && *name != NULL)
+	(void) gss_release_name(&temp_minor_status, name);
+
+    return (status);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name,
+			 initiator_lifetime, acceptor_lifetime, cred_usage)
+    OM_uint32		*minor_status;
+    gss_cred_id_t	cred_handle;
+    gss_OID		mech_type;
+    gss_name_t		*name;
+    OM_uint32		*initiator_lifetime;
+    OM_uint32		*acceptor_lifetime;
+    gss_cred_usage_t *cred_usage;
+{
+    gss_union_cred_t	union_cred;
+    gss_cred_id_t	mech_cred;
+    gss_mechanism	mech;
+    OM_uint32		status, temp_minor_status;
+    gss_name_t		internal_name;
+
+
+    mech = __gss_get_mechanism (mech_type);
+    if (!mech)
+	return (GSS_S_BAD_MECH);
+    if (!mech->gss_inquire_cred_by_mech)
+	return (GSS_S_BAD_BINDINGS);
+     
+    union_cred = (gss_union_cred_t) cred_handle;
+    mech_cred = __gss_get_mechanism_cred(union_cred, mech_type);
+    if (mech_cred == NULL)
+	return (GSS_S_DEFECTIVE_CREDENTIAL);
+
+    status = mech->gss_inquire_cred_by_mech(mech->context, minor_status,
+					    mech_cred, mech_type,
+					    name ? &internal_name : NULL,
+					    initiator_lifetime,
+					    acceptor_lifetime, cred_usage);
+	
+    if (status != GSS_S_COMPLETE)
+	return (status);
+
+    if (name) {
+	/*
+	 * Convert internal_name into a union_name equivalent.
+	 */
+	status = __gss_convert_name_to_union_name(
+	    &temp_minor_status, mech,
+	    internal_name, name);
+	if (status != GSS_S_COMPLETE) {
+	    *minor_status = temp_minor_status;
+	    return (status);
+	}
+    }
+
+    return (GSS_S_COMPLETE);
+}
+
diff --git a/mechglue/src/lib/gssapi/mechglue/g_inq_names.c b/mechglue/src/lib/gssapi/mechglue/g_inq_names.c
new file mode 100644
index 000000000..b1592bd44
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_inq_names.c
@@ -0,0 +1,157 @@
+/* #pragma ident	"@(#)g_inquire_names.c	1.16	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_inquire_context
+ */
+
+#include "mglueP.h"
+
+#define	MAX_MECH_OID_PAIRS 32
+
+/* Last argument new for V2 */
+OM_uint32 KRB5_CALLCONV
+gss_inquire_names_for_mech(minor_status, mechanism, name_types)
+
+OM_uint32 *	minor_status;
+gss_OID 	mechanism;
+gss_OID_set *	name_types;
+
+{
+    OM_uint32		status;
+    gss_mechanism	mech;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (name_types == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    mech = __gss_get_mechanism (mechanism);
+    
+    if (mech) {
+
+	if (mech->gss_inquire_names_for_mech)
+	    status = mech->gss_inquire_names_for_mech(
+				mech->context,
+				minor_status,
+				mechanism,
+				name_types);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return(status);
+    }
+    
+    return (GSS_S_BAD_MECH);
+}
+OM_uint32
+gss_inquire_mechs_for_name(minor_status, input_name, mech_set)
+
+    OM_uint32 *		minor_status;
+    const gss_name_t	input_name;
+    gss_OID_set *		mech_set;
+
+{
+    OM_uint32		status;
+    static char		*mech_list[MAX_MECH_OID_PAIRS+1];
+    gss_OID_set		mech_name_types;
+    int			present;
+    char 			*mechanism;
+    gss_OID 		mechOid;
+    gss_OID 		name_type;
+    gss_buffer_desc		name_buffer;
+    int			i;
+
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (input_name == NULL)
+	return (GSS_S_BAD_NAME);
+
+    status = gss_create_empty_oid_set(minor_status, mech_set);
+    if (status != GSS_S_COMPLETE)
+	return (status);
+    *mech_list = NULL;
+    status = __gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
+    if (status != GSS_S_COMPLETE)
+	return (status);
+    for (i = 0; i < MAX_MECH_OID_PAIRS && mech_list[i] != NULL; i++) {
+	mechanism = mech_list[i];
+	if (__gss_mech_to_oid(mechanism, &mechOid) == GSS_S_COMPLETE) {
+	    status = gss_inquire_names_for_mech(
+		minor_status,
+		mechOid,
+		&mech_name_types);
+	    if (status == GSS_S_COMPLETE) {
+		status = gss_display_name(minor_status,
+					  input_name,
+					  &name_buffer,
+					  &name_type);
+
+		(void) gss_release_buffer(NULL, &name_buffer);
+
+		if (status == GSS_S_COMPLETE && name_type) {
+		    status = gss_test_oid_set_member(
+			minor_status,
+			name_type,
+			mech_name_types,
+			&present);
+		    if (status == GSS_S_COMPLETE &&
+			present) {
+			status = gss_add_oid_set_member(
+			    minor_status,
+			    mechOid,
+			    mech_set);
+			if (status != GSS_S_COMPLETE) {
+			    (void) gss_release_oid_set(
+				minor_status,
+				&mech_name_types);
+			    (void) gss_release_oid_set(
+				minor_status,
+				mech_set);
+			    return (status);
+			}
+		    }
+		}
+		(void) gss_release_oid_set(
+		    minor_status,
+		    &mech_name_types);
+	    }
+	} else {
+	    (void) gss_release_oid_set(
+		minor_status,
+		mech_set);
+	    return (GSS_S_FAILURE);
+	}
+    }
+    return (GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_mechname.c b/mechglue/src/lib/gssapi/mechglue/g_mechname.c
new file mode 100644
index 000000000..0607c38f1
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_mechname.c
@@ -0,0 +1,112 @@
+/*
+ * g_mechname.c --- registry of mechanism-specific name types
+ *
+ * This file contains a registry of mechanism-specific name types.  It
+ * is used to determine which name types not should be lazy evaluated,
+ * but rather evaluated on the spot.
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static gss_mech_spec_name name_list = NULL;
+
+/*
+ * generic searching helper function.
+ */
+static gss_mech_spec_name search_mech_spec(name_type)
+    gss_OID name_type;
+{
+    gss_mech_spec_name p;
+
+    for (p = name_list; p; p = p->next) {
+	if (g_OID_equal(name_type, p->name_type))
+	    return p;
+    }
+    return NULL;
+}
+
+/*
+ * Given a name_type, if it is specific to a mechanism, return the
+ * mechanism OID.  Otherwise, return NULL.
+ */
+gss_OID gss_find_mechanism_from_name_type(name_type)
+    gss_OID name_type;
+{
+    gss_mech_spec_name p;
+
+    p = search_mech_spec(name_type);
+    if (!p)
+	return NULL;
+    return p->mech;
+}
+
+/*
+ * This function adds a (name_type, mechanism) pair to the
+ * mechanism-specific name type registry.  If an entry for the
+ * name_type already exists, then zero out the mechanism entry.
+ * Otherwise, enter the pair into the registry.
+ */
+OM_uint32
+gss_add_mech_name_type(minor_status, name_type, mech)
+    OM_uint32	*minor_status;
+    gss_OID	name_type;
+    gss_OID	mech;
+{
+    OM_uint32	major_status, tmp;
+    gss_mech_spec_name p;
+
+    p = search_mech_spec(name_type);
+    if (p) {
+	/*
+	 * We found an entry for this name type; mark it as not being
+	 * a mechanism-specific name type.
+	 */
+	if (p->mech) {
+	    if (!g_OID_equal(mech, p->mech)) {
+		generic_gss_release_oid(minor_status, &p->mech);
+		p->mech = 0;
+	    }
+	}
+	return GSS_S_COMPLETE;
+    }
+    p = malloc(sizeof(gss_mech_spec_name_desc));
+    if (!p) {
+	*minor_status = ENOMEM;
+	goto allocation_failure;
+    }
+    p->name_type = 0;
+    p->mech = 0;
+    
+    major_status = generic_gss_copy_oid(minor_status, name_type,
+					&p->name_type);
+    if (major_status)
+	goto allocation_failure;
+    major_status = generic_gss_copy_oid(minor_status, mech,
+					&p->mech);
+    if (major_status)
+	goto allocation_failure;
+
+    p->next = name_list;
+    p->prev = 0;
+    name_list = p;
+
+    return GSS_S_COMPLETE;
+    
+allocation_failure:
+    if (p) {
+	if (p->mech)
+	    generic_gss_release_oid(&tmp, &p->mech);
+	if (p->name_type)
+	    generic_gss_release_oid(&tmp, &p->name_type);
+	free(p);
+    }
+    return GSS_S_FAILURE;
+}
+
diff --git a/mechglue/src/lib/gssapi/mechglue/g_oid_ops.c b/mechglue/src/lib/gssapi/mechglue/g_oid_ops.c
new file mode 100644
index 000000000..a036d8763
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_oid_ops.c
@@ -0,0 +1,88 @@
+/* #pragma ident	"@(#)g_oid_ops.c	1.11	98/01/22 SMI" */
+/*
+ * lib/gssapi/mechglue/g_oid_ops.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
+ */
+
+#include "mglueP.h"
+/* should include to get protos #include "../generic/gssapiP_generic.h" */
+
+extern gss_mechanism *__gss_mechs_array;
+
+/*
+ * gss_release_oid has been moved to g_initialize, becasue it requires access
+ * to the mechanism list.  All functions requiring direct access to the
+ * mechanism list are now in g_initialize.c
+ */
+
+OM_uint32 KRB5_CALLCONV
+gss_create_empty_oid_set(minor_status, oid_set)
+    OM_uint32	*minor_status;
+    gss_OID_set	*oid_set;
+{
+	return generic_gss_create_empty_oid_set(minor_status, oid_set);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_add_oid_set_member(minor_status, member_oid, oid_set)
+    OM_uint32	*minor_status;
+    gss_OID	member_oid;
+    gss_OID_set	*oid_set;
+{
+     return generic_gss_add_oid_set_member(minor_status, member_oid, oid_set);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_test_oid_set_member(minor_status, member, set, present)
+    OM_uint32	*minor_status;
+    gss_OID	member;
+    gss_OID_set	set;
+    int		*present;
+{
+    return generic_gss_test_oid_set_member(minor_status, member, set, present);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_oid_to_str(minor_status, oid, oid_str)
+    OM_uint32		*minor_status;
+    gss_OID		oid;
+    gss_buffer_t	oid_str;
+{
+    return generic_gss_oid_to_str(minor_status, oid, oid_str);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_str_to_oid(minor_status, oid_str, oid)
+    OM_uint32		*minor_status;
+    gss_buffer_t	oid_str;
+    gss_OID		*oid;
+{
+    return generic_gss_str_to_oid(minor_status, oid_str, oid);
+}
+
diff --git a/mechglue/src/lib/gssapi/mechglue/g_process_context.c b/mechglue/src/lib/gssapi/mechglue/g_process_context.c
new file mode 100644
index 000000000..83687df3e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_process_context.c
@@ -0,0 +1,78 @@
+/* #pragma ident	"@(#)g_process_context.c	1.12	98/01/22 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine gss_process_context
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_process_context_token (minor_status,
+                           context_handle,
+                           token_buffer)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+gss_buffer_t		token_buffer;
+
+{
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (GSS_EMPTY_BUFFER(token_buffer))
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+
+    if (mech) {
+
+	if (mech->gss_process_context_token)
+	    status = mech->gss_process_context_token(
+						    mech->context,
+						    minor_status,
+						    ctx->internal_ctx_id,
+						    token_buffer);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return(status);
+    }
+    
+    return (GSS_S_BAD_MECH);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_rel_buffer.c b/mechglue/src/lib/gssapi/mechglue/g_rel_buffer.c
new file mode 100644
index 000000000..6f8367a1d
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_rel_buffer.c
@@ -0,0 +1,58 @@
+/* #ident  "@(#)g_rel_buffer.c 1.2     96/02/06 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_release_buffer
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_release_buffer (minor_status,
+		    buffer)
+
+OM_uint32 *		minor_status;
+gss_buffer_t		buffer;
+{
+    if (minor_status)
+	*minor_status = 0;
+
+    /* if buffer is NULL, return */
+
+    if(buffer == GSS_C_NO_BUFFER)
+	return(GSS_S_COMPLETE);
+
+    if ((buffer->length) &&
+	(buffer->value)) {
+	    free(buffer->value);
+	    buffer->length = 0;
+	    buffer->value = NULL;
+    }
+
+    return (GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_rel_cred.c b/mechglue/src/lib/gssapi/mechglue/g_rel_cred.c
new file mode 100644
index 000000000..e289f591c
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_rel_cred.c
@@ -0,0 +1,98 @@
+/* #pragma ident	"@(#)g_rel_cred.c	1.14	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_release_cred
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_release_cred(minor_status,
+                 cred_handle)
+
+OM_uint32 *		minor_status;
+gss_cred_id_t *		cred_handle;
+
+{
+    OM_uint32		status, temp_status;
+    int			j;
+    gss_union_cred_t	union_cred;
+    gss_mechanism	mech;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *minor_status = 0;
+
+    if (cred_handle == NULL)
+	return (GSS_S_NO_CRED | GSS_S_CALL_INACCESSIBLE_READ);
+    
+    /*
+     * Loop through the union_cred struct, selecting the approprate 
+     * underlying mechanism routine and calling it. At the end,
+     * release all of the storage taken by the union_cred struct.
+     */
+    
+    union_cred = (gss_union_cred_t) *cred_handle;
+    *cred_handle = NULL;
+
+    if (union_cred == (gss_union_cred_t)GSS_C_NO_CREDENTIAL)
+	return (GSS_S_COMPLETE);
+
+    status = GSS_S_COMPLETE;
+    
+    for(j=0; j < union_cred->count; j++) {
+
+	mech = __gss_get_mechanism (&union_cred->mechs_array[j]);
+
+	if (union_cred->mechs_array[j].elements)
+		free(union_cred->mechs_array[j].elements);
+	if (mech) {
+	    if (mech->gss_release_cred) {
+		temp_status = mech->gss_release_cred
+		    (mech->context,
+		     minor_status,
+		     &union_cred->cred_array[j]);
+
+	    if (temp_status != GSS_S_COMPLETE)
+		status = GSS_S_NO_CRED;
+
+	    } else
+		status = GSS_S_UNAVAILABLE;
+	} else
+	    status = GSS_S_DEFECTIVE_CREDENTIAL;
+    }
+
+    gss_release_buffer(minor_status, &union_cred->auxinfo.name);
+    free(union_cred->cred_array);
+    free(union_cred->mechs_array);
+    free(union_cred);
+    
+    return(status);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_rel_name.c b/mechglue/src/lib/gssapi/mechglue/g_rel_name.c
new file mode 100644
index 000000000..ffa678c26
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_rel_name.c
@@ -0,0 +1,81 @@
+/* #pragma ident	"@(#)g_rel_name.c	1.11	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_release_name
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+OM_uint32 KRB5_CALLCONV
+gss_release_name (minor_status,
+		  input_name)
+
+OM_uint32 *		minor_status;
+gss_name_t *		input_name;
+
+{
+    gss_union_name_t	union_name;
+    
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+    
+    /* if input_name is NULL, return error */
+    if (input_name == 0)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
+
+    if (*input_name == GSS_C_NO_NAME)
+	return GSS_S_COMPLETE;
+
+    /*
+     * free up the space for the external_name and then
+     * free the union_name descriptor
+     */
+    
+    union_name = (gss_union_name_t) *input_name;
+    *input_name = 0;
+    *minor_status = 0;
+
+    if (union_name->name_type)
+	    gss_release_oid(minor_status, &union_name->name_type);
+    
+    free(union_name->external_name->value);
+    free(union_name->external_name);
+
+    if (union_name->mech_type) {
+	    __gss_release_internal_name(minor_status, union_name->mech_type,
+					&union_name->mech_name);
+	    gss_release_oid(minor_status, &union_name->mech_type);
+    }
+
+    free(union_name);
+
+    return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_rel_oid_set.c b/mechglue/src/lib/gssapi/mechglue/g_rel_oid_set.c
new file mode 100644
index 000000000..f712a891a
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_rel_oid_set.c
@@ -0,0 +1,63 @@
+/* #pragma ident	"@(#)g_rel_oid_set.c	1.12	97/11/11 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_release_oid_set
+ */
+
+#include "mglueP.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+OM_uint32 KRB5_CALLCONV
+gss_release_oid_set (minor_status,
+		     set)
+
+OM_uint32 *		minor_status;
+gss_OID_set *		set;
+{
+    OM_uint32 index;
+    gss_OID oid;
+    if (minor_status)
+	*minor_status = 0;
+
+    if (set ==NULL)
+	return GSS_S_COMPLETE;
+
+    if (*set == GSS_C_NULL_OID_SET)
+	return(GSS_S_COMPLETE);
+
+    for (index=0; index<(*set)->count; index++) {
+      oid = &(*set)->elements[index];
+      free(oid->elements);
+    }
+    free((*set)->elements);
+    free(*set);
+
+    *set = GSS_C_NULL_OID_SET;
+    
+    return(GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_seal.c b/mechglue/src/lib/gssapi/mechglue/g_seal.c
new file mode 100644
index 000000000..c68a6b031
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_seal.c
@@ -0,0 +1,163 @@
+/* #pragma ident	"@(#)g_seal.c	1.19	98/04/21 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_seal
+ */
+
+#include "mglueP.h"
+
+OM_uint32
+gss_seal (minor_status,
+          context_handle,
+          conf_req_flag,
+          qop_req,
+          input_message_buffer,
+          conf_state,
+          output_message_buffer)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+int			conf_req_flag;
+int			qop_req;
+gss_buffer_t		input_message_buffer;
+int *			conf_state;
+gss_buffer_t		output_message_buffer;
+{
+ /* EXPORT DELETE START */
+
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (input_message_buffer == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (output_message_buffer == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+    
+    if (mech) {
+	if (mech->gss_seal)
+	    status = mech->gss_seal(
+				    mech->context,
+				    minor_status,
+				    ctx->internal_ctx_id,
+				    conf_req_flag,
+				    qop_req,
+				    input_message_buffer,
+				    conf_state,
+				    output_message_buffer);
+	else
+	    status = GSS_S_UNAVAILABLE;
+	
+	return(status);
+    }
+ /* EXPORT DELETE END */
+ 
+    return (GSS_S_BAD_MECH);
+}
+
+OM_uint32
+gss_wrap (minor_status,
+          context_handle,
+          conf_req_flag,
+          qop_req,
+          input_message_buffer,
+          conf_state,
+          output_message_buffer)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+int			conf_req_flag;
+gss_qop_t		qop_req;
+gss_buffer_t		input_message_buffer;
+int *			conf_state;
+gss_buffer_t		output_message_buffer;
+
+{
+    return gss_seal(minor_status, (gss_ctx_id_t)context_handle,
+		    conf_req_flag, (int) qop_req,
+		    (gss_buffer_t)input_message_buffer, conf_state,
+		    output_message_buffer);
+}
+
+/*
+ * New for V2
+ */
+OM_uint32
+gss_wrap_size_limit(minor_status, context_handle, conf_req_flag,
+		    qop_req, req_output_size, max_input_size)
+    OM_uint32		*minor_status;
+    gss_ctx_id_t	context_handle;
+    int			conf_req_flag;
+    gss_qop_t		qop_req;
+    OM_uint32		req_output_size;
+    OM_uint32		*max_input_size;
+{
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+    
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (max_input_size == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+    
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+
+    if (!mech)
+	return (GSS_S_BAD_MECH);
+
+    if (!mech->gss_wrap_size_limit)
+	return (GSS_S_UNAVAILABLE);
+    
+    return (mech->gss_wrap_size_limit(mech->context, minor_status,
+				      ctx->internal_ctx_id, conf_req_flag, qop_req,
+				      req_output_size, max_input_size));
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_sign.c b/mechglue/src/lib/gssapi/mechglue/g_sign.c
new file mode 100644
index 000000000..f1f883f52
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_sign.c
@@ -0,0 +1,107 @@
+/* #pragma ident	"@(#)g_sign.c	1.14	98/04/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine gss_sign
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_sign (minor_status,
+          context_handle,
+          qop_req,
+          message_buffer,
+          msg_token)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+int			qop_req;
+gss_buffer_t		message_buffer;
+gss_buffer_t		msg_token;
+
+{
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (message_buffer == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (msg_token == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    msg_token->value = NULL;
+    msg_token->length = 0;
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+
+    if (mech) {
+	if (mech->gss_sign)
+	    status = mech->gss_sign(
+				    mech->context,
+				    minor_status,
+				    ctx->internal_ctx_id,
+				    qop_req,
+				    message_buffer,
+				    msg_token);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return(status);
+    }
+
+    return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_get_mic (minor_status,
+          context_handle,
+          qop_req,
+          message_buffer,
+          msg_token)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+gss_qop_t		qop_req;
+gss_buffer_t		message_buffer;
+gss_buffer_t		msg_token;
+
+{
+	return (gss_sign(minor_status, context_handle, (int) qop_req,
+			 message_buffer, msg_token));
+}
+
diff --git a/mechglue/src/lib/gssapi/mechglue/g_store_cred.c b/mechglue/src/lib/gssapi/mechglue/g_store_cred.c
new file mode 100644
index 000000000..7ccbfcd7e
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_store_cred.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident	"@(#)g_store_cred.c	1.2	04/04/05 SMI" */
+
+/*
+ *  glue routine for gss_store_cred
+ */
+
+#include <mglueP.h>
+
+OM_uint32 gss_store_cred(minor_status,
+			input_cred_handle,
+			cred_usage,
+			desired_mech,
+			overwrite_cred,
+			default_cred,
+			elements_stored,
+			cred_usage_stored)
+
+OM_uint32		*minor_status;
+const gss_cred_id_t	 input_cred_handle;
+gss_cred_usage_t	 cred_usage;
+const gss_OID		 desired_mech;
+OM_uint32		 overwrite_cred;
+OM_uint32		 default_cred;
+gss_OID_set		*elements_stored;
+gss_cred_usage_t	*cred_usage_stored;
+
+{
+	OM_uint32		major_status = GSS_S_FAILURE;
+	gss_union_cred_t	union_cred;
+	gss_cred_id_t		mech_cred;
+	gss_mechanism		mech;
+	gss_OID			dmech;
+	int			i;
+
+	/* Start by checking parameters */
+	if (minor_status == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE|GSS_S_NO_CRED);
+	*minor_status = 0;
+
+	if (input_cred_handle == GSS_C_NO_CREDENTIAL)
+		return (GSS_S_CALL_INACCESSIBLE_READ);
+
+	if (elements_stored != NULL)
+		*elements_stored = GSS_C_NULL_OID_SET;
+
+	if (cred_usage_stored != NULL)
+		*cred_usage_stored = GSS_C_BOTH; /* there's no GSS_C_NEITHER */
+
+	union_cred = (gss_union_cred_t)input_cred_handle;
+
+	/* desired_mech != GSS_C_NULL_OID -> store one element */
+	if (desired_mech != GSS_C_NULL_OID) {
+		mech = __gss_get_mechanism(desired_mech);
+		if (mech == NULL)
+			return (GSS_S_BAD_MECH);
+
+		if (mech->gss_store_cred == NULL)
+			return (major_status);
+
+		mech_cred = __gss_get_mechanism_cred(union_cred, desired_mech);
+		if (mech_cred == GSS_C_NO_CREDENTIAL)
+			return (GSS_S_NO_CRED);
+
+		return (mech->gss_store_cred(mech->context,
+						minor_status,
+						(gss_cred_id_t)mech_cred,
+						cred_usage,
+						desired_mech,
+						overwrite_cred,
+						default_cred,
+						elements_stored,
+						cred_usage_stored));
+	}
+
+	/* desired_mech == GSS_C_NULL_OID -> store all elements */
+
+	*minor_status = 0;
+
+	for (i = 0; i < union_cred->count; i++) {
+		/* Get mech and cred element */
+		dmech = &union_cred->mechs_array[i];
+		mech = __gss_get_mechanism(dmech);
+		if (mech == NULL)
+			continue;
+
+		if (mech->gss_store_cred == NULL)
+			continue;
+
+		mech_cred = __gss_get_mechanism_cred(union_cred, dmech);
+		if (mech_cred == GSS_C_NO_CREDENTIAL)
+			continue; /* can't happen, but safe to ignore */
+
+		major_status = mech->gss_store_cred(mech->context,
+						minor_status,
+						(gss_cred_id_t)mech_cred,
+						cred_usage,
+						dmech,
+						overwrite_cred,
+						default_cred,
+						NULL,
+						cred_usage_stored);
+		if (major_status != GSS_S_COMPLETE)
+			continue;
+
+		/* Succeeded for at least one mech */
+
+		if (elements_stored == NULL)
+			continue;
+
+		if (*elements_stored == GSS_C_NULL_OID_SET) {
+			major_status = gss_create_empty_oid_set(minor_status,
+						elements_stored);
+
+			if (GSS_ERROR(major_status))
+				return (major_status);
+		}
+
+		major_status = gss_add_oid_set_member(minor_status, dmech,
+			elements_stored);
+
+		/* The caller should clean up elements_stored */
+		if (GSS_ERROR(major_status))
+			return (major_status);
+	}
+
+	/*
+	 * Success with some mechs may mask failure with others, but
+	 * that's what elements_stored is for.
+	 */
+	return (major_status);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_unseal.c b/mechglue/src/lib/gssapi/mechglue/g_unseal.c
new file mode 100644
index 000000000..8e975827f
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_unseal.c
@@ -0,0 +1,116 @@
+/* #pragma ident	"@(#)g_unseal.c	1.13	98/01/22 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine gss_unseal
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_unseal (minor_status,
+            context_handle,
+            input_message_buffer,
+            output_message_buffer,
+            conf_state,
+            qop_state)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+gss_buffer_t		input_message_buffer;
+gss_buffer_t		output_message_buffer;
+int *			conf_state;
+int *			qop_state;
+
+{
+/* EXPORT DELETE START */
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if (GSS_EMPTY_BUFFER(input_message_buffer))
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (output_message_buffer == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    output_message_buffer->length = 0;
+    output_message_buffer->value = NULL;
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+
+    if (mech) {
+	if (mech->gss_unseal) 
+	    status = mech->gss_unseal(
+				      mech->context,
+				      minor_status,
+				      ctx->internal_ctx_id,
+				      input_message_buffer,
+				      output_message_buffer,
+				      conf_state,
+				      qop_state);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return(status);
+    }
+
+/* EXPORT DELETE END */
+
+    return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_unwrap (minor_status,
+            context_handle,
+            input_message_buffer,
+            output_message_buffer,
+            conf_state,
+            qop_state)
+
+OM_uint32 *		minor_status;
+const gss_ctx_id_t	context_handle;
+const gss_buffer_t	input_message_buffer;
+gss_buffer_t		output_message_buffer;
+int *			conf_state;
+gss_qop_t *		qop_state;
+
+{
+    return (gss_unseal(minor_status, (gss_ctx_id_t)context_handle,
+		       (gss_buffer_t)input_message_buffer,
+		       output_message_buffer, conf_state, (int *) qop_state));
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_userok.c b/mechglue/src/lib/gssapi/mechglue/g_userok.c
new file mode 100644
index 000000000..eaf376ea8
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_userok.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident	"@(#)g_userok.c	1.1	04/03/25 SMI" */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <deflt.h>
+#include <mglueP.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
+
+
+static OM_uint32
+compare_names(OM_uint32 *minor,
+	    const gss_OID mech_type,
+	    const gss_name_t name,
+	    const char *user,
+	    int *user_ok)
+{
+
+	OM_uint32 status, tmpMinor;
+	gss_name_t imported_name;
+	gss_name_t canon_name;
+	gss_buffer_desc gss_user;
+	int match = 0;
+
+	*user_ok = 0;
+
+	gss_user.value = (void *)user;
+	if (!gss_user.value || !name || !mech_type)
+		return (GSS_S_BAD_NAME);
+	gss_user.length = strlen(gss_user.value);
+
+	status = gss_import_name(minor,
+				&gss_user,
+				GSS_C_NT_USER_NAME,
+				&imported_name);
+	if (status != GSS_S_COMPLETE) {
+		goto out;
+	}
+
+	status = gss_canonicalize_name(minor,
+				    imported_name,
+				    mech_type,
+				    &canon_name);
+	if (status != GSS_S_COMPLETE) {
+		(void) gss_release_name(&tmpMinor, &imported_name);
+		goto out;
+	}
+
+	status = gss_compare_name(minor,
+				canon_name,
+				name,
+				&match);
+	(void) gss_release_name(&tmpMinor, &canon_name);
+	(void) gss_release_name(&tmpMinor, &imported_name);
+	if (status == GSS_S_COMPLETE) {
+		if (match)
+			*user_ok = 1; /* remote user is a-ok */
+	}
+
+out:
+	return (status);
+}
+
+
+OM_uint32
+__gss_userok(OM_uint32 *minor,
+	    const gss_name_t name,
+	    const char *user,
+	    int *user_ok)
+
+{
+	gss_mechanism mech;
+	gss_union_name_t intName;
+	gss_name_t mechName = NULL;
+	OM_uint32 major;
+
+	if (minor == NULL || user_ok == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	if (name == NULL || user == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_READ);
+
+	*user_ok = 0;
+	*minor = GSS_S_COMPLETE;
+
+	intName = (gss_union_name_t)name;
+
+	mech = __gss_get_mechanism(intName->mech_type);
+	if (mech == NULL)
+		return (GSS_S_UNAVAILABLE);
+
+	/* may need to import the name if this is not MN */
+	if (intName->mech_type == NULL) {
+		return (GSS_S_FAILURE);
+	} else
+		mechName = intName->mech_name;
+
+	if (mech->__gss_userok)
+		major = mech->__gss_userok(mech->context,  minor, mechName,
+				user, user_ok);
+	else
+		major = compare_names(minor, intName->mech_type,
+				    name, user, user_ok);
+
+	return (major);
+} /* gss_userok */
diff --git a/mechglue/src/lib/gssapi/mechglue/g_utils.c b/mechglue/src/lib/gssapi/mechglue/g_utils.c
new file mode 100644
index 000000000..875e159f7
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_utils.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* #pragma ident	"@(#)g_utils.c	1.8	04/02/23 SMI" */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <ctype.h>
+#include <errno.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
+#include <synch.h>
+
+#define	Q_DEFAULT		"default"
+#define	BUFLEN			256
+
+static int qop_num_pair_cnt;
+static const char    QOP_NUM_FILE[] = "/etc/gss/qop";
+static qop_num	qop_num_pairs[MAX_QOP_NUM_PAIRS+1];
+static mutex_t qopfile_lock = DEFAULTMUTEX;
+
+static OM_uint32 __gss_read_qop_file(void);
+
+/*
+ * This routine fetches qop and num from "/etc/gss/qop".
+ * There is a memory leak associated with rereading this file,
+ * because we can't free the qop_num_pairs array when we reread
+ * the file (some callers may have been given these pointers).
+ * In general, this memory leak should be a small one, because
+ * we don't expect the qop file to be changed and reread often.
+ */
+static OM_uint32
+__gss_read_qop_file(void)
+{
+	char 	buf[BUFLEN];	/* one line from the file */
+	char	*name, *next;
+	char	*qopname, *num_str;
+	char 	*line;
+	FILE 	*fp;
+	static int last = 0;
+	struct stat stbuf;
+	OM_uint32 major = GSS_S_COMPLETE;
+
+	(void) mutex_lock(&qopfile_lock);
+	if (stat(QOP_NUM_FILE, &stbuf) != 0 || stbuf.st_mtime < last) {
+		if (!qop_num_pairs[0].qop) {
+			major = GSS_S_FAILURE;
+		}
+		goto done;
+	}
+	last = stbuf.st_mtime;
+
+	fp = fopen(QOP_NUM_FILE, "r");
+	if (fp == (FILE *)0) {
+		major = GSS_S_FAILURE;
+		goto done;
+	}
+
+	/*
+	 * For each line in the file parse it appropriately.
+	 * File format : qopname	num(int)
+	 * Note that we silently ignore corrupt entries.
+	 */
+	qop_num_pair_cnt = 0;
+	while (!feof(fp)) {
+		line = fgets(buf, BUFLEN, fp);
+		if (line == NULL)
+			break;
+
+		/* Skip comments and blank lines */
+		if ((*line == '#') || (*line == '\n'))
+			continue;
+
+		/* Skip trailing comments */
+		next = strchr(line, '#');
+		if (next)
+			*next = '\0';
+
+		name = &(buf[0]);
+		while (isspace(*name))
+			name++;
+		if (*name == '\0')	/* blank line */
+			continue;
+
+		qopname = name;	/* will contain qop name */
+		while (!isspace(*qopname))
+			qopname++;
+		if (*qopname == '\0') {
+			continue;
+		}
+		next = qopname+1;
+		*qopname = '\0';	/* null terminate qopname */
+		qop_num_pairs[qop_num_pair_cnt].qop = strdup(name);
+		if (qop_num_pairs[qop_num_pair_cnt].qop == NULL)
+			continue;
+
+		name = next;
+		while (isspace(*name))
+			name++;
+		if (*name == '\0') { 	/* end of line, no num */
+			free(qop_num_pairs[qop_num_pair_cnt].qop);
+			continue;
+		}
+		num_str = name;	/* will contain num (n) */
+		while (!isspace(*num_str))
+			num_str++;
+		next = num_str+1;
+		*num_str++ = '\0';	/* null terminate num_str */
+
+		qop_num_pairs[qop_num_pair_cnt].num = (OM_uint32)atoi(name);
+		name = next;
+		while (isspace(*name))
+			name++;
+		if (*name == '\0') { 	/* end of line, no mechanism */
+			free(qop_num_pairs[qop_num_pair_cnt].qop);
+			continue;
+		}
+		num_str = name;	/* will contain mech */
+		while (!isspace(*num_str))
+			num_str++;
+		*num_str = '\0';
+
+		qop_num_pairs[qop_num_pair_cnt].mech = strdup(name);
+		if (qop_num_pairs[qop_num_pair_cnt].mech == NULL) {
+			free(qop_num_pairs[qop_num_pair_cnt].qop);
+			continue;
+		}
+
+		if (qop_num_pair_cnt++ >= MAX_QOP_NUM_PAIRS)
+			break;
+	}
+	(void) fclose(fp);
+done:
+	(void) mutex_unlock(&qopfile_lock);
+	return (major);
+}
+
+OM_uint32
+__gss_qop_to_num(
+	char		*qop,
+	char		*mech,
+	OM_uint32	*num
+)
+{
+	int i;
+	OM_uint32 major = GSS_S_FAILURE;
+
+	if (!num)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+	if (qop == NULL || strlen(qop) == 0 ||
+			strcasecmp(qop, Q_DEFAULT) == 0) {
+		*num = GSS_C_QOP_DEFAULT;
+		return (GSS_S_COMPLETE);
+	}
+
+	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
+		return (major);
+
+	for (i = 0; i < qop_num_pair_cnt; i++) {
+		if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
+		    (strcasecmp(qop, qop_num_pairs[i].qop) == 0)) {
+			*num = qop_num_pairs[i].num;
+			return (GSS_S_COMPLETE);
+		}
+	}
+
+	return (GSS_S_FAILURE);
+}
+
+OM_uint32
+__gss_num_to_qop(
+	char		*mech,
+	OM_uint32	num,
+	char		**qop
+)
+{
+	int i;
+	OM_uint32 major;
+
+	if (!qop)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+	*qop = NULL;
+
+	if (num == GSS_C_QOP_DEFAULT) {
+		*qop = Q_DEFAULT;
+		return (GSS_S_COMPLETE);
+	}
+
+	if (mech == NULL)
+		return (GSS_S_CALL_INACCESSIBLE_READ);
+
+	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
+		return (major);
+
+	for (i = 0; i < qop_num_pair_cnt; i++) {
+		if ((strcasecmp(mech, qop_num_pairs[i].mech) == 0) &&
+		    (num == qop_num_pairs[i].num)) {
+			*qop = qop_num_pairs[i].qop;
+			return (GSS_S_COMPLETE);
+		}
+	}
+	return (GSS_S_FAILURE);
+}
+
+/*
+ * For a given mechanism pass back qop information about it in a buffer
+ * of size MAX_QOPS_PER_MECH+1.
+ */
+OM_uint32
+__gss_get_mech_info(
+	char		*mech,
+	char		**qops
+)
+{
+	int i, cnt = 0;
+	OM_uint32 major = GSS_S_COMPLETE;
+
+	if (!qops)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+	*qops = NULL;
+
+	if (!mech)
+		return (GSS_S_CALL_INACCESSIBLE_READ);
+
+	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
+		return (major);
+
+	for (i = 0; i < qop_num_pair_cnt; i++) {
+		if (strcmp(mech, qop_num_pairs[i].mech) == 0) {
+		    if (cnt >= MAX_QOPS_PER_MECH) {
+			return (GSS_S_FAILURE);
+		    }
+		    qops[cnt++] = qop_num_pairs[i].qop;
+		}
+	}
+	qops[cnt] = NULL;
+	return (GSS_S_COMPLETE);
+}
+
+/*
+ * Copy the qop values and names for the mechanism back in a qop_num
+ * buffer of size MAX_QOPS_PER_MECH provided by the caller.
+ */
+OM_uint32
+__gss_mech_qops(
+	char *mech,
+	qop_num *mechqops,
+	int *numqop
+)
+{
+	int i;
+	OM_uint32 major;
+	int cnt = 0;
+
+	if (!mechqops || !numqop)
+		return (GSS_S_CALL_INACCESSIBLE_WRITE);
+	*numqop = 0;
+
+	if (!mech)
+		return (GSS_S_CALL_INACCESSIBLE_READ);
+
+	if ((major = __gss_read_qop_file()) != GSS_S_COMPLETE)
+		return (major);
+
+	for (i = 0; i < qop_num_pair_cnt; i++) {
+	    if (strcasecmp(mech, qop_num_pairs[i].mech) == 0) {
+		if (cnt >= MAX_QOPS_PER_MECH) {
+			return (GSS_S_FAILURE);
+		}
+		mechqops[cnt++] = qop_num_pairs[i];
+	    }
+	}
+	*numqop = cnt;
+	return (GSS_S_COMPLETE);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/g_verify.c b/mechglue/src/lib/gssapi/mechglue/g_verify.c
new file mode 100644
index 000000000..4f2415566
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/g_verify.c
@@ -0,0 +1,102 @@
+/* #pragma ident	"@(#)g_verify.c	1.13	98/04/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routine for gss_verify
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_verify (minor_status,
+            context_handle,
+            message_buffer,
+            token_buffer,
+            qop_state)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+gss_buffer_t		message_buffer;
+gss_buffer_t		token_buffer;
+int *			qop_state;
+
+{
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+
+
+    if (minor_status == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+    *minor_status = 0;
+
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
+
+    if ((message_buffer == NULL) || GSS_EMPTY_BUFFER(token_buffer))
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = __gss_get_mechanism (ctx->mech_type);
+
+    if (mech) {
+	if (mech->gss_verify)
+	    status = mech->gss_verify(
+				      mech->context,
+				      minor_status,
+				      ctx->internal_ctx_id,
+				      message_buffer,
+				      token_buffer,
+				      qop_state);
+	else
+	    status = GSS_S_UNAVAILABLE;
+
+	return(status);
+    }
+
+    return (GSS_S_BAD_MECH);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_verify_mic (minor_status,
+            context_handle,
+            message_buffer,
+            token_buffer,
+            qop_state)
+
+OM_uint32 *		minor_status;
+gss_ctx_id_t		context_handle;
+gss_buffer_t		message_buffer;
+gss_buffer_t		token_buffer;
+gss_qop_t *		qop_state;
+
+{
+	return (gss_verify(minor_status, context_handle,
+			   message_buffer, token_buffer, (int *) qop_state));
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/gen_oids.c b/mechglue/src/lib/gssapi/mechglue/gen_oids.c
new file mode 100644
index 000000000..cd3c1a835
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/gen_oids.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "mglueP.h"
+
+/*
+ * See krb5/gssapi_krb5.c for a description of the algorithm for
+ * encoding an object identifier.
+ */
+
+/*
+ * The OID of user_name is:
+ * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * 	generic(1) user_name(1) = 1.2.840.113554.1.2.1.1
+ * machine_uid_name:
+ * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * 	generic(1) machine_uid_name(2) = 1.2.840.113554.1.2.1.2
+ * string_uid_name:
+ * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * 	generic(1) string_uid_name(3) = 1.2.840.113554.1.2.1.3
+ * service_name:
+ * 	iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2)
+ * 	generic(1) service_name(4) = 1.2.840.113554.1.2.1.4
+ */
+
+static const gss_OID_desc oids[] = {
+   {10, "\052\206\110\206\367\022\001\002\001\001"},
+   {10, "\052\206\110\206\367\022\001\002\001\002"},
+   {10, "\052\206\110\206\367\022\001\002\001\003"},
+   {10, "\052\206\110\206\367\022\001\002\001\004"},
+};
+
+const gss_OID_desc * const gss_nt_user_name = oids+0;
+const gss_OID_desc * const gss_nt_machine_uid_name = oids+1;
+const gss_OID_desc * const gss_nt_string_uid_name = oids+2;
+const gss_OID_desc * const gss_nt_service_name = oids+3;
diff --git a/mechglue/src/lib/gssapi/mechglue/gssd_pname_to_uid.c b/mechglue/src/lib/gssapi/mechglue/gssd_pname_to_uid.c
new file mode 100644
index 000000000..036ae904f
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/gssd_pname_to_uid.c
@@ -0,0 +1,65 @@
+/* #pragma ident	"@(#)gssd_pname_to_uid.c	1.18	04/02/23 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ *  glue routines that test the mech id either passed in to
+ *  gss_init_sec_contex() or gss_accept_sec_context() or within the glue
+ *  routine supported version of the security context and then call
+ *  the appropriate underlying mechanism library procedure. 
+ *
+ */
+
+#include "mglueP.h"
+
+int gssd_pname_to_uid(pname, name_type, mech_type, uid)
+
+char * pname;
+gss_OID name_type;
+gss_OID mech_type;
+uid_t * uid;
+{
+    int status;
+    gss_mechanism	mech;
+
+    /*
+     * find the appropriate mechanism specific pname_to_uid procedure and
+     * call it.
+     */
+
+    mech = __gss_get_mechanism (mech_type);
+
+    if (mech) {
+	if (mech_type == GSS_C_NULL_OID)
+	    mech_type = &mech->mech_type;
+
+	if (mech->pname_to_uid)
+		status = mech->pname_to_uid(mech->context,
+					pname, name_type, mech_type, uid);
+	else
+	    status = GSS_S_BAD_MECH;
+    } else
+	status = GSS_S_BAD_MECH;
+
+    return(status);
+}
diff --git a/mechglue/src/lib/gssapi/mechglue/mech.conf b/mechglue/src/lib/gssapi/mechglue/mech.conf
new file mode 100644
index 000000000..5257a01a2
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/mech.conf
@@ -0,0 +1,7 @@
+#
+#
+# GSSAPI Mechanism Definitions
+#
+# library				function
+/opt/SUNWgss/lib/mech_krb5.so	krb5_gss_initialize
+#mech_krb5.so			krb5_gss_initialize
diff --git a/mechglue/src/lib/gssapi/mechglue/mechglue.h b/mechglue/src/lib/gssapi/mechglue/mechglue.h
new file mode 100644
index 000000000..691b30a96
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/mechglue.h
@@ -0,0 +1,41 @@
+/* #ident  "@(#)mechglue.h 1.13     95/08/07 SMI" */
+
+/*
+ * Copyright 1996 by Sun Microsystems, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Sun Microsystems not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Sun Microsystems makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This header contains the mechglue definitions.
+ */
+
+#ifndef _GSS_MECHGLUE_H
+#define _GSS_MECHGLUE_H
+
+#include <gssapi/gssapi.h>
+
+/********************************************************/
+/* GSSAPI Extension functions -- these functions aren't */
+/* in the GSSAPI, but they are provided in this library */
+
+int gssd_pname_to_uid (char *, gss_OID, gss_OID, uid_t *);
+void gss_initialize (void);
+
+#endif /* _GSS_MECHGLUE_H */
diff --git a/mechglue/src/lib/gssapi/mechglue/mglueP.h b/mechglue/src/lib/gssapi/mechglue/mglueP.h
new file mode 100644
index 000000000..20f5ea655
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/mglueP.h
@@ -0,0 +1,565 @@
+/* #ident  "@(#)mglueP.h 1.2     96/01/18 SMI" */
+
+/*
+ * This header contains the private mechglue definitions.
+ *
+ * Copyright (c) 1995, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _GSS_MECHGLUEP_H
+#define _GSS_MECHGLUEP_H
+
+#include "mechglue.h"
+
+#define	g_OID_equal(o1, o2) \
+	(((o1)->length == (o2)->length) && \
+	(memcmp((o1)->elements, (o2)->elements, (o1)->length) == 0))
+
+#define	g_OID_copy(o1, o2)					\
+do {								\
+	memcpy((o1)->elements, (o2)->elements, (o2)->length);	\
+	(o1)->length = (o2)->length;				\
+} while (0)
+
+#define	GSS_EMPTY_BUFFER(buf)	((buf) == NULL ||\
+	(buf)->value == NULL || (buf)->length == 0)
+
+/*
+ * Array of context IDs typed by mechanism OID
+ */
+typedef struct gss_union_ctx_id_t {
+	gss_OID			mech_type;
+	gss_ctx_id_t		internal_ctx_id;
+} gss_union_ctx_id_desc, *gss_union_ctx_id_t;
+
+/*
+ * Generic GSSAPI names.  A name can either be a generic name, or a
+ * mechanism specific name....
+ */
+typedef struct gss_union_name_t {
+	gss_OID			name_type;
+	gss_buffer_t		external_name;
+	/*
+	 * These last two fields are only filled in for mechanism
+	 * names.
+	 */
+	gss_OID			mech_type;
+	gss_name_t		mech_name;
+} gss_union_name_desc, *gss_union_name_t;
+
+/*
+ * Structure for holding list of mechanism-specific name types
+ */
+typedef struct gss_mech_spec_name_t {
+    gss_OID	name_type;
+    gss_OID	mech;
+    struct gss_mech_spec_name_t	*next, *prev;
+} gss_mech_spec_name_desc, *gss_mech_spec_name;
+
+/*
+ * Credential auxiliary info, used in the credential structure
+ */
+typedef struct gss_union_cred_auxinfo {
+	gss_buffer_desc		name;
+	gss_OID			name_type;
+	OM_uint32		creation_time;
+	OM_uint32		time_rec;
+	int			cred_usage;
+} gss_union_cred_auxinfo;
+
+/*
+ * Set of Credentials typed on mechanism OID
+ */
+typedef struct gss_union_cred_t {
+	int			count;
+	gss_OID			mechs_array;
+	gss_cred_id_t		*cred_array;
+	gss_union_cred_auxinfo	auxinfo;
+} gss_union_cred_desc, *gss_union_cred_t;
+ 
+typedef	OM_uint32	    (*gss_acquire_cred_with_password_sfct)(
+		    void *,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    const gss_name_t,	/* desired_name */
+		    const gss_buffer_t, /* password */
+		    OM_uint32,		/* time_req */
+		    const gss_OID_set,	/* desired_mechs */
+		    int,		/* cred_usage */
+		    gss_cred_id_t *,	/* output_cred_handle */
+		    gss_OID_set *,	/* actual_mechs */
+		    OM_uint32 *		/* time_rec */
+	/* */);
+
+/********************************************************/
+/* The Mechanism Dispatch Table -- a mechanism needs to */
+/* define one of these and provide a function to return */
+/* it to initialize the GSSAPI library                  */
+
+/*
+ * This is the definition of the mechs_array struct, which is used to
+ * define the mechs array table. This table is used to indirectly
+ * access mechanism specific versions of the gssapi routines through
+ * the routines in the glue module (gssd_mech_glue.c)
+ *
+ * This contants all of the functions defined in gssapi.h except for
+ * gss_release_buffer() and gss_release_oid_set(), which I am
+ * assuming, for now, to be equal across mechanisms.  
+ */
+ 
+typedef struct gss_config {
+    gss_OID_desc    mech_type;
+    void *	    context;
+    OM_uint32       (*gss_acquire_cred)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_name_t,		/* desired_name */
+		    OM_uint32,		/* time_req */
+		    gss_OID_set,	/* desired_mechs */
+		    int,		/* cred_usage */
+		    gss_cred_id_t*,	/* output_cred_handle */
+		    gss_OID_set*,	/* actual_mechs */
+		    OM_uint32*		/* time_rec */
+		    );
+    OM_uint32       (*gss_release_cred)
+	(
+		    void*,		/* context */		       
+		    OM_uint32*,		/* minor_status */
+		    gss_cred_id_t*	/* cred_handle */
+		    );
+    OM_uint32       (*gss_init_sec_context)
+	(
+		    void*,			/* context */
+		    OM_uint32*,			/* minor_status */
+		    gss_cred_id_t,		/* claimant_cred_handle */
+		    gss_ctx_id_t*,		/* context_handle */
+		    gss_name_t,			/* target_name */
+		    gss_OID,			/* mech_type */
+		    OM_uint32,			/* req_flags */
+		    OM_uint32,			/* time_req */
+		    gss_channel_bindings_t,	/* input_chan_bindings */
+		    gss_buffer_t,		/* input_token */
+		    gss_OID*,			/* actual_mech_type */
+		    gss_buffer_t,		/* output_token */
+		    OM_uint32*,			/* ret_flags */
+		    OM_uint32*			/* time_rec */
+		    );
+    OM_uint32       (*gss_accept_sec_context)
+	(
+		    void*,			/* context */
+		    OM_uint32*,			/* minor_status */
+		    gss_ctx_id_t*,		/* context_handle */
+		    gss_cred_id_t,		/* verifier_cred_handle */
+		    gss_buffer_t,		/* input_token_buffer */
+		    gss_channel_bindings_t,	/* input_chan_bindings */
+		    gss_name_t*,		/* src_name */
+		    gss_OID*,			/* mech_type */
+		    gss_buffer_t,		/* output_token */
+		    OM_uint32*,			/* ret_flags */
+		    OM_uint32*,			/* time_rec */
+		    gss_cred_id_t*		/* delegated_cred_handle */
+		    );
+    OM_uint32       (*gss_process_context_token)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_ctx_id_t,	/* context_handle */
+		    gss_buffer_t	/* token_buffer */
+		    );
+    OM_uint32       (*gss_delete_sec_context)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_ctx_id_t*,	/* context_handle */
+		    gss_buffer_t	/* output_token */
+		    );
+    OM_uint32       (*gss_context_time)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_ctx_id_t,	/* context_handle */
+		    OM_uint32*		/* time_rec */
+		    );
+    OM_uint32       (*gss_sign)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_ctx_id_t,	/* context_handle */
+		    int,		/* qop_req */
+		    gss_buffer_t,	/* message_buffer */
+		    gss_buffer_t	/* message_token */
+		    );
+    OM_uint32       (*gss_verify)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_ctx_id_t,	/* context_handle */
+		    gss_buffer_t,	/* message_buffer */
+		    gss_buffer_t,	/* token_buffer */
+		    int*		/* qop_state */
+		    );
+    OM_uint32       (*gss_seal)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_ctx_id_t,	/* context_handle */
+		    int,		/* conf_req_flag */
+		    int,		/* qop_req */
+		    gss_buffer_t,	/* input_message_buffer */
+		    int*,		/* conf_state */
+		    gss_buffer_t	/* output_message_buffer */
+		    );
+    OM_uint32       (*gss_unseal)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_ctx_id_t,	/* context_handle */
+		    gss_buffer_t,	/* input_message_buffer */
+		    gss_buffer_t,	/* output_message_buffer */
+		    int*,		/* conf_state */
+		    int*		/* qop_state */
+		    );
+    OM_uint32       (*gss_display_status)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    OM_uint32,		/* status_value */
+		    int,		/* status_type */
+		    gss_OID,		/* mech_type */
+		    OM_uint32*,		/* message_context */
+		    gss_buffer_t	/* status_string */
+		    );
+    OM_uint32       (*gss_indicate_mechs)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_OID_set*	/* mech_set */
+		    );
+    OM_uint32       (*gss_compare_name)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_name_t,		/* name1 */
+		    gss_name_t,		/* name2 */
+		    int*		/* name_equal */
+		    );
+    OM_uint32       (*gss_display_name)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_name_t,		/* input_name */
+		    gss_buffer_t,	/* output_name_buffer */
+		    gss_OID*		/* output_name_type */
+		    );
+    OM_uint32       (*gss_import_name)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_buffer_t,	/* input_name_buffer */
+		    gss_OID,		/* input_name_type */
+		    gss_name_t*		/* output_name */
+		    );
+    OM_uint32       (*gss_release_name)
+	(
+		    void*,		/* context */
+		    OM_uint32*,		/* minor_status */
+		    gss_name_t*		/* input_name */
+		    );
+    OM_uint32       (*gss_inquire_cred)
+	(
+		    void*,			/* context */
+		    OM_uint32 *,		/* minor_status */
+		    gss_cred_id_t,		/* cred_handle */
+		    gss_name_t *,		/* name */
+		    OM_uint32 *,		/* lifetime */
+		    int *,			/* cred_usage */
+		    gss_OID_set *		/* mechanisms */
+		    );
+    OM_uint32	    (*gss_add_cred)
+	(
+		    void*,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    gss_cred_id_t,	/* input_cred_handle */
+		    gss_name_t,		/* desired_name */
+		    gss_OID,		/* desired_mech */
+		    gss_cred_usage_t,	/* cred_usage */
+		    OM_uint32,		/* initiator_time_req */
+		    OM_uint32,		/* acceptor_time_req */
+		    gss_cred_id_t *,	/* output_cred_handle */
+		    gss_OID_set *,	/* actual_mechs */
+		    OM_uint32 *,	/* initiator_time_rec */
+		    OM_uint32 *		/* acceptor_time_rec */
+		    );
+    OM_uint32	    (*gss_export_sec_context)
+	(
+		    void*,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    gss_ctx_id_t *,	/* context_handle */
+		    gss_buffer_t	/* interprocess_token */
+		    );
+    OM_uint32	    (*gss_import_sec_context)
+	(
+		    void *,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    gss_buffer_t,	/* interprocess_token */
+		    gss_ctx_id_t *	/* context_handle */
+		    );
+    OM_uint32 	    (*gss_inquire_cred_by_mech)
+	(
+		    void *,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    gss_cred_id_t,	/* cred_handle */
+		    gss_OID,		/* mech_type */
+		    gss_name_t *,	/* name */
+		    OM_uint32 *,	/* initiator_lifetime */
+		    OM_uint32 *,	/* acceptor_lifetime */
+		    gss_cred_usage_t *	/* cred_usage */
+		    );
+    OM_uint32	    (*gss_inquire_names_for_mech)
+	(
+		    void *,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    gss_OID,		/* mechanism */
+		    gss_OID_set *	/* name_types */
+		    );
+    OM_uint32	(*gss_inquire_context)
+	(
+		    void *,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    gss_ctx_id_t,	/* context_handle */
+		    gss_name_t *,	/* src_name */
+		    gss_name_t *,	/* targ_name */
+		    OM_uint32 *,	/* lifetime_rec */
+		    gss_OID *,		/* mech_type */
+		    OM_uint32 *,	/* ctx_flags */
+		    int *,           	/* locally_initiated */
+		    int *		/* open */
+		    );
+    OM_uint32	    (*gss_internal_release_oid)
+	(
+		    void *,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    gss_OID *		/* OID */
+	 );
+    OM_uint32	     (*gss_wrap_size_limit)
+	(
+		    void *,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    gss_ctx_id_t,	/* context_handle */
+		    int,		/* conf_req_flag */
+		    gss_qop_t,		/* qop_req */
+		    OM_uint32,		/* req_output_size */
+		    OM_uint32 *		/* max_input_size */
+	 );
+    int		     (*pname_to_uid)
+	(
+		    void *,		/* context */
+		    char *,		/* pname */
+		    gss_OID,		/* name type */
+		    gss_OID,		/* mech type */
+		    uid_t *		/* uid */
+		    );
+	OM_uint32		(*__gss_userok)
+	(
+		    void *,		/* context */
+		    OM_uint32 *,	/* minor_status */
+		    const gss_name_t,	/* pname */
+		    const char *,	/* local user */
+		    int *		/* user ok? */
+	/* */);
+	OM_uint32		(*gss_export_name)
+	(
+		void *,			/* context */
+		OM_uint32 *,		/* minor_status */
+		const gss_name_t,	/* input_name */
+		gss_buffer_t		/* exported_name */
+	/* */);
+	OM_uint32	(*gss_store_cred)
+	(
+		void *,			/* context */
+		OM_uint32 *,		/* minor_status */
+		const gss_cred_id_t,	/* input_cred */
+		gss_cred_usage_t,	/* cred_usage */
+		const gss_OID,		/* desired_mech */
+		OM_uint32,		/* overwrite_cred */
+		OM_uint32,		/* default_cred */
+		gss_OID_set *,		/* elements_stored */
+		gss_cred_usage_t *	/* cred_usage_stored */
+	/* */);
+} *gss_mechanism;
+
+/* This structure MUST NOT be used by any code outside libgss */
+typedef struct gss_config_ext {
+	gss_acquire_cred_with_password_sfct	gss_acquire_cred_with_password;
+} *gss_mechanism_ext;
+
+/*
+ * In the user space we use a wrapper structure to encompass the
+ * mechanism entry points.  The wrapper contain the mechanism
+ * entry points and other data which is only relevant to the gss-api
+ * layer.  In the kernel we use only the gss_config strucutre because
+ * the kernal does not cantain any of the extra gss-api specific data.
+ */
+typedef struct gss_mech_config {
+	char *kmodName;			/* kernel module name */
+	char *uLibName;			/* user library name */
+	char *mechNameStr;		/* mechanism string name */
+	char *optionStr;		/* optional mech parameters */
+	void *dl_handle;		/* RTLD object handle for the mech */
+	gss_OID mech_type;		/* mechanism oid */
+	gss_mechanism mech;		/* mechanism initialization struct */
+	gss_mechanism_ext mech_ext;	/* extensions */
+	struct gss_mech_config *next;	/* next element in the list */
+} *gss_mech_info;
+
+/********************************************************/
+/* Internal mechglue routines */
+
+int gssint_mechglue_init(void);
+void gssint_mechglue_fini(void);
+
+gss_mechanism __gss_get_mechanism (gss_OID);
+gss_mechanism_ext __gss_get_mechanism_ext(const gss_OID);
+OM_uint32 __gss_get_mech_type (gss_OID, gss_buffer_t);
+char *__gss_get_kmodName(const gss_OID);
+char *__gss_get_modOptions(const gss_OID);
+OM_uint32 __gss_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t,
+				      gss_name_t *);
+OM_uint32 __gss_export_internal_name(OM_uint32 *, const gss_OID,
+	const gss_name_t, gss_buffer_t);
+OM_uint32 __gss_display_internal_name (OM_uint32 *, gss_OID, gss_name_t,
+				       gss_buffer_t, gss_OID *);
+OM_uint32 __gss_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *);
+
+OM_uint32 __gss_convert_name_to_union_name
+	  (OM_uint32 *,		/* minor_status */
+	   gss_mechanism,	/* mech */
+	   gss_name_t,		/* internal_name */
+	   gss_name_t *		/* external_name */
+	   );
+gss_cred_id_t __gss_get_mechanism_cred
+	  (gss_union_cred_t,	/* union_cred */
+	   gss_OID		/* mech_type */
+	   );
+
+OM_uint32 __gss_create_copy_buffer(
+	const gss_buffer_t,	/* src buffer */
+	gss_buffer_t *,		/* destination buffer */
+	int			/* NULL terminate buffer ? */
+);
+
+OM_uint32 generic_gss_release_oid
+	   (OM_uint32 *,	/* minor_status */
+	    gss_OID *		/* oid */
+	   );
+
+OM_uint32 generic_gss_copy_oid
+	   (OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* oid */
+	    gss_OID *		/* new_oid */
+	    );
+
+OM_uint32 generic_gss_create_empty_oid_set
+	   (OM_uint32 *,	/* minor_status */
+	    gss_OID_set *	/* oid_set */
+	   );
+
+OM_uint32 generic_gss_add_oid_set_member
+	   (OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* member_oid */
+	    gss_OID_set *	/* oid_set */
+	   );
+
+OM_uint32 generic_gss_test_oid_set_member
+	   (OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* member */
+	    gss_OID_set,	/* set */
+	    int *		/* present */
+	   );
+
+OM_uint32 generic_gss_oid_to_str
+ (OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* oid */
+	    gss_buffer_t	/* oid_str */
+	   );
+
+OM_uint32 generic_gss_str_to_oid
+	   (OM_uint32 *,	/* minor_status */
+	    gss_buffer_t,	/* oid_str */
+	    gss_OID *		/* oid */
+	   );
+
+OM_uint32 gss_copy_oid_set(
+	OM_uint32 *,			/* minor_status */
+	const gss_OID_set_desc *,	/* oid set */
+	gss_OID_set *			/* new oid set */
+);
+
+gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */
+
+OM_uint32 gss_add_mech_name_type
+	   (OM_uint32 *,	/* minor_status */
+	    gss_OID,		/* name_type */
+	    gss_OID		/* mech */
+	       );
+
+/*
+ * Sun extensions to GSS-API v2
+ */
+
+OM_uint32
+__gss_mech_to_oid(
+	const char *mech,		/* mechanism string name */
+	gss_OID *oid			/* mechanism oid */
+);
+
+const char *
+__gss_oid_to_mech(
+	const gss_OID oid		/* mechanism oid */
+);
+
+OM_uint32
+__gss_get_mechanisms(
+	char *mechArray[],		/* array to populate with mechs */
+	int arrayLen			/* length of passed in array */
+);
+
+OM_uint32
+__gss_userok(
+	OM_uint32 *,		/* minor */
+	const gss_name_t,	/* name */
+	const char *,		/* user */
+	int *			/* user_ok */
+);
+
+OM_uint32
+gss_store_cred(
+	OM_uint32 *,		/* minor_status */
+	const gss_cred_id_t,	/* input_cred_handle */
+	gss_cred_usage_t,	/* cred_usage */
+	const gss_OID,		/* desired_mech */
+	OM_uint32,		/* overwrite_cred */
+	OM_uint32,		/* default_cred */
+	gss_OID_set *,		/* elements_stored */
+	gss_cred_usage_t *	/* cred_usage_stored */
+);
+
+int
+get_der_length(
+	unsigned char **,	/* buf */
+	unsigned int,		/* buf_len */
+	unsigned int *		/* bytes */
+);
+
+unsigned int
+der_length_size(unsigned int /* len */);
+
+int
+put_der_length(
+	unsigned int,		/* length */
+	unsigned char **,	/* buf */
+	unsigned int		/* max_len */
+);
+
+#endif /* _GSS_MECHGLUEP_H */
diff --git a/mechglue/src/lib/gssapi/mechglue/oid_ops.c b/mechglue/src/lib/gssapi/mechglue/oid_ops.c
new file mode 100644
index 000000000..e13e6a4f5
--- /dev/null
+++ b/mechglue/src/lib/gssapi/mechglue/oid_ops.c
@@ -0,0 +1,502 @@
+/* #pragma ident	"@(#)oid_ops.c	1.19	04/02/23 SMI" */
+/*
+ * lib/gssapi/generic/oid_ops.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
+ */
+
+#include "mglueP.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <gssapi/gssapi_generic.h>
+#include <errno.h>
+#include <ctype.h>
+
+OM_uint32
+generic_gss_release_oid(minor_status, oid)
+    OM_uint32	*minor_status;
+    gss_OID	*oid;
+{
+    if (minor_status)
+	*minor_status = 0;
+
+    if (*oid == GSS_C_NO_OID)
+	return(GSS_S_COMPLETE);
+
+    /*
+     * The V2 API says the following!
+     *
+     * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
+     * and will silently ignore attempts to free these OIDs; for other OIDs
+     * it will call the C free() routine for both the OID data and the
+     * descriptor.  This allows applications to freely mix their own heap-
+     * allocated OID values with OIDs returned by GSS-API.
+     */
+
+    /*
+     * We use the official OID definitions instead of the unofficial OID
+     * defintions. But we continue to support the unofficial OID
+     * gss_nt_service_name just in case if some gss applications use
+     * the old OID.
+     */
+
+    if ((*oid != GSS_C_NT_USER_NAME) &&
+	(*oid != GSS_C_NT_MACHINE_UID_NAME) &&
+	(*oid != GSS_C_NT_STRING_UID_NAME) &&
+	(*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
+	(*oid != GSS_C_NT_ANONYMOUS) &&
+	(*oid != GSS_C_NT_EXPORT_NAME) &&
+	(*oid != gss_nt_service_name)) {
+	free((*oid)->elements);
+	free(*oid);
+    }
+    *oid = GSS_C_NO_OID;
+    return(GSS_S_COMPLETE);
+}
+
+OM_uint32
+generic_gss_copy_oid(minor_status, oid, new_oid)
+	OM_uint32	*minor_status;
+	gss_OID		oid, *new_oid;
+{
+	gss_OID		p;
+
+	*minor_status = 0;
+
+	p = (gss_OID) malloc(sizeof(gss_OID_desc));
+	if (!p) {
+		*minor_status = ENOMEM;
+		return GSS_S_FAILURE;
+	}
+	p->length = oid->length;
+	p->elements = malloc(p->length);
+	if (!p->elements) {
+		free(p);
+		return GSS_S_FAILURE;
+	}
+	memcpy(p->elements, oid->elements, p->length);
+	*new_oid = p;
+	return(GSS_S_COMPLETE);
+}
+
+
+OM_uint32
+generic_gss_create_empty_oid_set(minor_status, oid_set)
+    OM_uint32	*minor_status;
+    gss_OID_set	*oid_set;
+{
+    *minor_status = 0;
+
+    if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) {
+	memset(*oid_set, 0, sizeof(gss_OID_set_desc));
+	return(GSS_S_COMPLETE);
+    }
+    else {
+	*minor_status = ENOMEM;
+	return(GSS_S_FAILURE);
+    }
+}
+
+OM_uint32
+generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
+    OM_uint32	*minor_status;
+    gss_OID	member_oid;
+    gss_OID_set	*oid_set;
+{
+    gss_OID	elist;
+    gss_OID	lastel;
+
+    *minor_status = 0;
+
+    if (member_oid == NULL || member_oid->length == 0 ||
+	member_oid->elements == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    elist = (*oid_set)->elements;
+    /* Get an enlarged copy of the array */
+    if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
+						  sizeof(gss_OID_desc)))) {
+	/* Copy in the old junk */
+	if (elist)
+	    memcpy((*oid_set)->elements,
+		   elist,
+		   ((*oid_set)->count * sizeof(gss_OID_desc)));
+
+	/* Duplicate the input element */
+	lastel = &(*oid_set)->elements[(*oid_set)->count];
+	if ((lastel->elements =
+	     (void *) malloc((size_t) member_oid->length))) {
+	    /* Success - copy elements */
+	    memcpy(lastel->elements, member_oid->elements,
+		   (size_t) member_oid->length);
+	    /* Set length */
+	    lastel->length = member_oid->length;
+
+	    /* Update count */
+	    (*oid_set)->count++;
+	    if (elist)
+		free(elist);
+	    *minor_status = 0;
+	    return(GSS_S_COMPLETE);
+	}
+	else
+	    free((*oid_set)->elements);
+    }
+    /* Failure - restore old contents of list */
+    (*oid_set)->elements = elist;
+    *minor_status = ENOMEM;
+    return(GSS_S_FAILURE);
+}
+
+OM_uint32
+generic_gss_test_oid_set_member(minor_status, member, set, present)
+    OM_uint32	*minor_status;
+    gss_OID	member;
+    gss_OID_set	set;
+    int		*present;
+{
+    OM_uint32	i;
+    int		result;
+
+    *minor_status = 0;
+
+    if (member == NULL || set == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (present == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    result = 0;
+    for (i=0; i<set->count; i++) {
+	if ((set->elements[i].length == member->length) &&
+	    !memcmp(set->elements[i].elements,
+		    member->elements,
+		    (size_t) member->length)) {
+	    result = 1;
+	    break;
+	}
+    }
+    *present = result;
+    return(GSS_S_COMPLETE);
+}
+
+/*
+ * OID<->string routines.  These are uuuuugly.
+ */
+OM_uint32
+generic_gss_oid_to_str(minor_status, oid, oid_str)
+    OM_uint32		*minor_status;
+    gss_OID		oid;
+    gss_buffer_t	oid_str;
+{
+    char		numstr[128];
+    OM_uint32		number;
+    int			numshift;
+    OM_uint32 string_length;
+    OM_uint32 i;
+    unsigned char	*cp;
+    char		*bp;
+
+    *minor_status = 0;
+
+    if (oid == NULL || oid->length == 0 || oid->elements == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (oid_str == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    /* Decoded according to krb5/gssapi_krb5.c */
+
+    /* First determine the size of the string */
+    string_length = 0;
+    number = 0;
+    numshift = 0;
+    cp = (unsigned char *) oid->elements;
+    number = (unsigned long) cp[0];
+    sprintf(numstr, "%ld ", number/40);
+    string_length += strlen(numstr);
+    sprintf(numstr, "%ld ", number%40);
+    string_length += strlen(numstr);
+    for (i=1; i<oid->length; i++) {
+	if ((OM_uint32) (numshift+7) < (sizeof (OM_uint32)*8)) {/* XXX */
+	    number = (number << 7) | (cp[i] & 0x7f);
+	    numshift += 7;
+	}
+	else {
+	    return(GSS_S_FAILURE);
+	}
+	if ((cp[i] & 0x80) == 0) {
+	    sprintf(numstr, "%ld ", number);
+	    string_length += strlen(numstr);
+	    number = 0;
+	    numshift = 0;
+	}
+    }
+    /*
+     * If we get here, we've calculated the length of "n n n ... n ".  Add 4
+     * here for "{ " and "}\0".
+     */
+    string_length += 4;
+    if ((bp = (char *) malloc(string_length))) {
+	strcpy(bp, "{ ");
+	number = (OM_uint32) cp[0];
+	sprintf(numstr, "%ld ", number/40);
+	strcat(bp, numstr);
+	sprintf(numstr, "%ld ", number%40);
+	strcat(bp, numstr);
+	number = 0;
+	cp = (unsigned char *) oid->elements;
+	for (i=1; i<oid->length; i++) {
+	    number = (number << 7) | (cp[i] & 0x7f);
+	    if ((cp[i] & 0x80) == 0) {
+		sprintf(numstr, "%ld ", number);
+		strcat(bp, numstr);
+		number = 0;
+	    }
+	}
+	strcat(bp, "}");
+	oid_str->length = strlen(bp)+1;
+	oid_str->value = (void *) bp;
+	return(GSS_S_COMPLETE);
+    }
+    *minor_status = ENOMEM;
+    return(GSS_S_FAILURE);
+}
+
+OM_uint32
+generic_gss_str_to_oid(minor_status, oid_str, oid)
+    OM_uint32		*minor_status;
+    gss_buffer_t	oid_str;
+    gss_OID		*oid;
+{
+    char	*cp, *bp, *startp;
+    int		brace;
+    long	numbuf;
+    long	onumbuf;
+    OM_uint32	nbytes;
+    int		index;
+    unsigned char *op;
+
+    *minor_status = 0;
+
+    if (GSS_EMPTY_BUFFER(oid_str))
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (oid == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    brace = 0;
+    bp = (char *) oid_str->value;
+    cp = bp;
+    /* Skip over leading space */
+    while ((bp < &cp[oid_str->length]) && isspace(*bp))
+	bp++;
+    if (*bp == '{') {
+	brace = 1;
+	bp++;
+    }
+    while ((bp < &cp[oid_str->length]) && isspace(*bp))
+	bp++;
+    startp = bp;
+    nbytes = 0;
+
+    /*
+     * The first two numbers are chewed up by the first octet.
+     */
+    if (sscanf(bp, "%ld", &numbuf) != 1) {
+	*minor_status = EINVAL;
+	return(GSS_S_FAILURE);
+    }
+    while ((bp < &cp[oid_str->length]) && isdigit(*bp))
+	bp++;
+    while ((bp < &cp[oid_str->length]) && isspace(*bp))
+	bp++;
+    if (sscanf(bp, "%ld", &numbuf) != 1) {
+	*minor_status = EINVAL;
+	return(GSS_S_FAILURE);
+    }
+    while ((bp < &cp[oid_str->length]) && isdigit(*bp))
+	bp++;
+    while ((bp < &cp[oid_str->length]) &&
+	   (isspace(*bp) || *bp == '.'))
+	bp++;
+    nbytes++;
+    while (isdigit(*bp)) {
+	if (sscanf(bp, "%d", &numbuf) != 1) {
+	    return(GSS_S_FAILURE);
+	}
+	while (numbuf) {
+	    nbytes++;
+	    numbuf >>= 7;
+	}
+	while ((bp < &cp[oid_str->length]) && isdigit(*bp))
+	    bp++;
+	while ((bp < &cp[oid_str->length]) &&
+	       (isspace(*bp) || *bp == '.'))
+	    bp++;
+    }
+    if (brace && (*bp != '}')) {
+	return(GSS_S_FAILURE);
+    }
+
+    /*
+     * Phew!  We've come this far, so the syntax is good.
+     */
+    if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
+	if (((*oid)->elements = (void *) malloc(nbytes))) {
+	    (*oid)->length = nbytes;
+	    op = (unsigned char *) (*oid)->elements;
+	    bp = startp;
+	    (void) sscanf(bp, "%d", &numbuf);
+	    while (isdigit(*bp))
+		bp++;
+	    while (isspace(*bp) || *bp == '.')
+		bp++;
+	    onumbuf = 40*numbuf;
+	    (void) sscanf(bp, "%d", &numbuf);
+	    onumbuf += numbuf;
+	    *op = (unsigned char) onumbuf;
+	    op++;
+	    while (isdigit(*bp))
+		bp++;
+	    while (isspace(*bp) || *bp == '.')
+		bp++;
+	    while (isdigit(*bp)) {
+		(void) sscanf(bp, "%d", &numbuf);
+		nbytes = 0;
+		/* Have to fill in the bytes msb-first */
+		onumbuf = numbuf;
+		while (numbuf) {
+		    nbytes++;
+		    numbuf >>= 7;
+		}
+		numbuf = onumbuf;
+		op += nbytes;
+		index = -1;
+		while (numbuf) {
+		    op[index] = (unsigned char) numbuf & 0x7f;
+		    if (index != -1)
+			op[index] |= 0x80;
+		    index--;
+		    numbuf >>= 7;
+		}
+		while (isdigit(*bp))
+		    bp++;
+		while (isspace(*bp) || *bp == '.')
+		    bp++;
+	    }
+	    return(GSS_S_COMPLETE);
+	}
+	else {
+	    free(*oid);
+	    *oid = GSS_C_NO_OID;
+	}
+    }
+    return(GSS_S_FAILURE);
+}
+
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+OM_uint32
+gss_copy_oid_set(
+    OM_uint32 *minor_status,
+    const gss_OID_set_desc * const oidset,
+    gss_OID_set *new_oidset
+    )
+{
+    gss_OID_set_desc *copy;
+    OM_uint32 minor = 0;
+    OM_uint32 major = GSS_S_COMPLETE;
+    OM_uint32 index;
+
+    if (minor_status)
+	*minor_status = 0;
+
+    if (oidset == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_READ);
+
+    if (new_oidset == NULL)
+	return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+    *new_oidset = NULL;
+
+    if ((copy = (gss_OID_set_desc *) calloc(1, sizeof (*copy))) == NULL) {
+	major = GSS_S_FAILURE;
+	goto done;
+    }
+
+    if ((copy->elements = (gss_OID_desc *)
+	 calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
+	major = GSS_S_FAILURE;
+	goto done;
+    }
+    copy->count = oidset->count;
+
+    for (index = 0; index < copy->count; index++) {
+	gss_OID_desc *out = ©->elements[index];
+	gss_OID_desc *in = &oidset->elements[index];
+
+	if ((out->elements = (void *) malloc(in->length)) == NULL) {
+	    major = GSS_S_FAILURE;
+	    goto done;
+	}
+	(void) memcpy(out->elements, in->elements, in->length);
+	out->length = in->length;
+    }
+
+    *new_oidset = copy;
+done:
+    if (major != GSS_S_COMPLETE) {
+	(void) gss_release_oid_set(&minor, ©);
+    }
+
+    return (major);
+}
diff --git a/mechglue/src/lib/gssapi32.def b/mechglue/src/lib/gssapi32.def
new file mode 100644
index 000000000..51b7d481b
--- /dev/null
+++ b/mechglue/src/lib/gssapi32.def
@@ -0,0 +1,96 @@
+;----------------------------------------------------
+;   GSSAPI32.DEF - GSSAPI32.DLL module definition file
+;----------------------------------------------------
+
+;LIBRARY		GSSAPI32
+DESCRIPTION	'Base Generic Security Service API'
+HEAPSIZE	8192
+
+EXPORTS
+	gss_acquire_cred
+	gss_release_cred
+	gss_init_sec_context
+	gss_accept_sec_context
+	gss_process_context_token
+	gss_delete_sec_context
+	gss_context_time
+	gss_sign
+	gss_verify
+	gss_seal
+	gss_unseal
+	gss_display_status
+	gss_indicate_mechs
+	gss_compare_name
+	gss_display_name
+	gss_import_name
+	gss_release_name
+	gss_release_buffer
+	gss_release_oid_set
+	gss_inquire_cred
+;
+; GSS-API v2  additional credential calls
+;
+	gss_add_cred
+	gss_inquire_cred_by_mech
+;
+; GSS-API v2  additional context-level calls
+;
+	gss_inquire_context
+	gss_wrap_size_limit
+	gss_export_sec_context
+	gss_import_sec_context
+;
+; GSS-API v2  additional calls for OID and OID_set operations
+;
+	gss_release_oid
+	gss_create_empty_oid_set
+	gss_add_oid_set_member
+	gss_test_oid_set_member
+	gss_oid_to_str
+	gss_str_to_oid
+;
+; GSS-API v2  renamed message protection calls
+;
+	gss_wrap
+	gss_unwrap
+	gss_get_mic
+	gss_verify_mic
+;
+; GSS-API v2  future extensions
+;
+	gss_inquire_names_for_mech
+;	gss_inquire_mechs_for_name
+	gss_canonicalize_name
+	gss_export_name
+	gss_duplicate_name
+;
+; Krb5 specific function extensions
+;
+	gss_krb5_get_tkt_flags 
+	gss_krb5_copy_ccache
+	gss_krb5_ccache_name
+        gss_krb5_set_allowable_enctypes
+        gss_krb5_export_lucid_sec_context
+        gss_krb5_free_lucid_sec_context
+;
+; GSS-API variables
+;
+        gss_nt_krb5_name               DATA
+        gss_nt_krb5_principal          DATA
+	gss_nt_user_name	       DATA
+	gss_nt_machine_uid_name	       DATA
+	gss_nt_string_uid_name	       DATA
+	gss_nt_service_name	       DATA
+        GSS_C_NT_USER_NAME             DATA
+        GSS_C_NT_MACHINE_UID_NAME      DATA
+        GSS_C_NT_STRING_UID_NAME       DATA
+        GSS_C_NT_HOSTBASED_SERVICE     DATA
+        GSS_C_NT_HOSTBASED_SERVICE_X   DATA
+        GSS_C_NT_ANONYMOUS             DATA
+        GSS_C_NT_EXPORT_NAME           DATA
+        krb5_gss_oid_array             DATA
+        gss_mech_krb5                  DATA
+        gss_mech_krb5_old              DATA
+        gss_mech_set_krb5              DATA
+        gss_mech_set_krb5_old          DATA
+        gss_mech_set_krb5_both         DATA
diff --git a/mechglue/src/lib/kadm5/ChangeLog b/mechglue/src/lib/kadm5/ChangeLog
new file mode 100644
index 000000000..15bdaca53
--- /dev/null
+++ b/mechglue/src/lib/kadm5/ChangeLog
@@ -0,0 +1,734 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* admin.h: Include kdb.h instead of k5-int.h.
+	* kadm_rpc_xdr.c, server_internal.h: Include errno.h instead of
+	k5-int.h.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+	* kadm_rpc.h: Remove krb5_ui_4 casts on RPC defined numbers.
+	Remove argument names from RPC proc declarations.  Reorder
+	declarations, change whitespace.  Renamed all RPC functions from
+	_1 to _2 to match current program version number.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	Novell merge.
+	* Makefile.in (adb_err.*): Targets deleted.
+	(SRCS, OBJS, clean, STLIBOBJS, BUILD_HDRS): Delete references to
+	adb_err.*.
+	(HDRS, SRC_HDRS): Delete references to adb.h.
+	* adb_err.et: Moved to lib/kdb.
+	* admin.h: Don't include kadm5/adb_err.h.
+	(krb5_key_salt_tuple): Delete typedef and struct definition.
+	(kadm5_init, kadm5_init_with_password, kadm5_init_with_skey,
+	kadm5_init_with_creds, ovsec_kadm_init,
+	ovsec_kadm_init_with_password, ovsec_kadm_init_with_skey): Add new
+	char** argument for arbitrary db args.
+	* admin_xdr.h: Include server_internal.h.
+	(xdr_krb5_key_data, xdr_osa_pw_hist_ent): Declare.
+	* kadm_err.et (KADM5_XDR_FAILURE): New error code.
+	* kadm_rpc.h (struct generic_ret, struct gprincs_ret, struct
+	chrand_ret, struct gprinc_ret, struct gpol_ret, struct gpols_ret,
+	struct getprivs_ret): Add new field for error-string return.
+	* kadm_rpc_xdr.c (xdr_generic_ret, xdr_gprincs_ret,
+	xdr_chrand_ret, xdr_gprinc_ret, xdr_gpol_ret, xdr_gpols_ret,
+	xdr_getprivs_ret): Encode/decode new field.
+	* ovsec_glue.c (ovsec_kadm_init_with_password,
+	ovsec_kadm_init_with_skey, ovsec_kadm_init): Pass through new
+	argument to kadm5_init_* routines.
+	* server_internal.h: Don't include adb.h.
+	(kadm5_server_handle_rec): Delete policy_db field, add db_args
+	field.
+	(OSA_ADB_PRINC_VERSION_1, osa_pw_hist_ent, osa_pw_hist_t,
+	osa_princ_ent_rec, osa_princ_ent_t, xdr_osa_princ_ent_rec,
+	osa_free_princ_ent): Duplicate definitions and declarations from
+	adb.h.
+	(kdb_iter_entry): Add match_entry argument.
+
+2005-04-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't invoke AC_CANONICAL_HOST explicitly,
+	CONFIG_RULES already does it.
+
+2004-08-20  Tom Yu  <tlyu@mit.edu>
+
+	* admin.h (KADM5_CONFIG_NO_AUTH): New flag.
+
+2004-06-25  Tom Yu  <tlyu@mit.edu>
+
+	* adb.h:
+	* kadm_rpc_xdr.c: rpc_u_int32 -> uint32_t
+
+2004-06-24  Tom Yu  <tlyu@mit.edu>
+
+	* alt_prof.c (kadm5_get_admin_service_name): Fix call to
+	kadm5_get_config_params().
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (clean-mac): Target deleted.
+
+2004-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* admin.h (kadm5_get_admin_service_name): Prototype for new function.
+	(KADM5_CONFIG_OLD_AUTH_GSSAPI): New flag to force old AUTH_GSSAPI
+	flavor.
+
+	* alt_prof.c (kadm5_get_admin_service_name): New function.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Invoke PRIOCNTL_HACK.
+
+2003-06-03  Tom Yu  <tlyu@mit.edu>
+
+	* alt_prof.c (krb5_read_realm_params): Don't bother reading in
+	realm_keysalts or realm_num_keysalts, as they're no longer used.
+
+2003-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): Change default max_life to
+	one day.
+
+2003-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): Remove aes256 from the
+	default supported enctypes list for now.
+
+2003-05-04  Sam Hartman  <hartmans@mit.edu>
+
+	* chpass_util_strings.et: Replace reference to ovpasswd with kpasswd
+
+2003-04-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): Add aes256 to the default
+	supported enctypes list.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_ARCHIVE,
+	AC_PROG_ARCHIVE_ADD, AC_PROG_RANLIB, AC_PROG_INSTALL.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-prerecurse): Change double colons to single
+	colons.
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* chpass_util_strings.et: Remove trailing colons, as new
+	implementation of krb5_read_password() appends it.
+
+2002-10-08  Tom Yu  <tlyu@mit.edu>
+
+	* adb.h (struct _osa_adb_db_ent_t): Add opencnt, which keeps track
+	of how many times an open was attempted on the adb.
+
+	* admin.h: Add kadm5_lock and kadm5_unlock.
+
+2002-09-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* admin.h (struct __krb5_realm_params): New field
+	realm_kdc_tcp_ports.
+	* alt_prof.c (krb5_read_realm_params): Fill it in by looking up
+	"kdc_tcp_ports" in the config file.
+	(krb5_free_realm_params): Free the storage.
+
+	* logger.c (klog_com_err_proc, krb5_klog_init, krb5_klog_close,
+	severity2string, klog_vsyslog, krb5_klog_syslog,
+	krb5_klog_reopen): Always define functions in prototype style.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(HDRS)): Depend on "includes".
+
+2002-07-31  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_err.et: Add KADM5_MISSING_KRB5_CONF_PARAMS, indicating a
+	problem with krb5.conf.  This prevents confusing users who look
+	for kdc.conf trouble rather than krb5.conf trouble, which is what
+	they should be looking at on a kadm5 client.
+
+2002-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_admhst.c: Deleted.
+
+2001-11-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* alt_prof.c (krb5_aprof_get_boolean): Return krb5_boolean *
+	instead of int *.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* logger.c (krb5_klog_init): Initialize savec to keep compiler
+	happy.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* logger.c: Drop _MSDOS support.
+
+2001-09-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* admin.h (krb5_realm_params): Add fields realm_reject_bad_transit
+	and realm_reject_bad_transit_valid; delete field realm_filler.
+	* alt_prof.c (string_to_boolean, krb5_aprof_get_boolean): New
+	functions.
+	(krb5_read_realm_params): Parse "reject_bad_transit" value as
+	boolean and save it.
+
+2001-07-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* kadm_rpc_xdr.c: Add xdr_krb5_ui_2. 
+	(xdr_krb5_tl_data): Change local variable from int to unsigned int. 
+
+	* admin_xdr.h: Add prototype for xdr_krb5_ui_2. 
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* logger.c (severity2string): Declare as returning const char *.
+	(klog_com_err_proc): Do not discard const status of format string.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* server_internal.h: Add prototype for krb5_copy_key_data_contents.
+
+2001-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* str_conv.c (krb5_string_to_keysalts): When parsing string, allow
+	for extra separator characters (like spaces) between keysalts.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* admin_internal.h (_KADM5_CHECK_HANDLE): Change code to ecode in
+	blocked statement to prevent shadowing.
+
+2001-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* logger.c (krb5_klog_init) [HAVE_SYSLOG]: Loop over an array of
+	syslog facility names rather than open-coding each check.  Add
+	"authpriv" and "ftp" names.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* server_internal.h: Add prototype for kdb_iter_entry().
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* alt_prof.c (krb5_read_realm_params): Cast argument to isspace()
+	to int.
+	* logger.c (krb5_klog_init): Likewise.
+
+2001-06-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* logger.c (klog_vsyslog): If krb5_klog_init() is not called, do
+	not pass a NULL pointer to vsprintf for a %s format. Also, if
+	syslog() exists on the system, fallback to using this so the
+	message is not dropped on the floor.
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* logger.c (krb5_klog_init): Cleanup assignments in
+	conditionals. Ensure that if hostname is MAXHOSTNAMELEN, buffer is
+	\0 terminated.
+
+	* str_conv.c (krb5_string_to_keysalts, krb5_keysalt_iterate):
+	Clean up assignments in conditionals.
+
+	* admin.h: Move kadm5_free_name_list() to version 1 api as it is
+ 	present in the ovsec_glue layer.
+
+2001-03-10  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* str_conv.c: Include adm_proto.h for missing prototypes.
+
+Sun Feb 18 16:26:33 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* server_internal.h: Add prototype for
+        krb5_free_key_data_contents() which really should be in libkdb.
+
+	* kadm_rpc_xdr.c: Include krb5/admin_xdr.h for prototypes.
+
+	* kadm_rpc.h: Add prototypes for client and server stub
+        functions. Server functions renamed to have _svc appended. 
+
+	* alt_prof.c: Clean up warnings. Do not shadow index() with local
+        variable.
+
+	* admin_xdr.h: Add prototypes for xdr_nulltype(), xdr_krb5_ui_4(),
+        xdr_krb5_int16(), xdr_krb5_key_data_nocontents(),
+        xdr_krb5_key_salt_tuple(), xdr_krb5_tl_data(),
+        xdr_kadm5_principal_ent_rec_v1(), xdr_cprinc3_arg(),
+        xdr_generic_ret(0, xdr_chpass3_arg(), xdr_setv4key_arg(),
+        xdr_setkey_arg(), xdr_setkey3_arg(), xdr_chrand3_arg(),
+        xdr_gprincs_arg(), xdr_grpincs_ret(), xdr_gpols_arg(),
+        xdr_gpols_ret(), xdr_getprivs_ret(), xdr_krb5_salttype().
+
+	* admin_internal.h: Add prototype for _kadm5_check_handle().
+
+	* admin.h: Add prototypes for kadm5_free_config_params(),
+        kadm5_decrypt_key(), ovsec_kadm_free_name_list().
+
+	* adb.h: Add prototypes for xdr_osa_pw_hist_ent(),
+        xdr_krb5_key_data(), osa_adb_rename_db(),
+        osa_adb_rename_policy_db().
+
+2001-01-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* str_conv.c (krb5_keysalt_iterate): Always use the prototype for
+	function-pointer argument ITERATOR.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* admin.h (KADM5_PW_FIRST_PROMPT): Get rid of casts from
+	error_message to char * - leave them as const char *.
+	(kadm5_chpass_principal_util): Argument msg_len is unsigned int.
+
+	* admin_internal.h (_kadm5_chpass_principal_util): msg_len is
+	unsigned int.
+
+	* chpass_util.c (_kadm5_chpass_principal_util): Change msg_len to
+	unsigned int. Arhument to krb5_read_password is unsigned int. 
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* admin.h: Add kadm5_free_name_list prototype.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* adb.h: Add btinfo.
+
+	* configure.in: Remove AIX_DB_LIB kludge as we're now building
+	libdb reasonably.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* alt_prof.c (krb5_aprof_init): profile_init takes a
+	profile_filespec_t as argument instad of char **.
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): Include des3 in supported
+	enctypes by default.
+
+	* ovsec_glue.c (ovsec_kadm_chpass_principal_util): Use 1024 for
+	hard-coded length, to match existing callers.
+
+2000-06-23  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* admin.h: Add a length parameter to kadm5_chpass_principal_util().
+	* admin_internal.h: Add a length parameter to
+	_kadm5_chpass_principal_util().
+	* chpass_util.c (_kadm5_chpass_principal_util): Add a length parameter,
+	and use it to avoid overflowing "msg_ret".
+	* ovsec_glue.c (ovsec_kadm_chpass_principal_util): Adjust for new
+	parameter in kadm5_chpass_principal_util().
+
+	* logger.c (klog_com_err_proc): Don't overflow buffer "outbuf".
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* configure.in, chpass_util.c, server_internal.h: Check for
+	existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-02-26  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc_xdr.c (xdr_cprinc3_arg): Don't XDR the nonexistent
+	keepold flag.
+
+	* kadm_rpc.h: Remove keepold flag from cprinc3_arg.
+
+	* admin.h: Remove keepold flag from create_principal_3, which was
+	kinda ridiculous.
+
+2000-02-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (includes): Extract basename of header file to be
+	installed, since Digital UNIX 4.0 native make substitutes the
+	VPATH-derived pathname here.
+
+2000-02-21  Bear Giles  <bgiles@coyotesong.com>
+
+	* alt_prof.c (krb5_read_realm_params): Permit realm supported
+	enctypes to be unspecified, letting the KDC produce defaults.
+	Don't look up enctypes at all if an error is to be returned.
+
+2000-02-18  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc_xdr.c (xdr_chpass3_arg): 
+	(xdr_chrand3_arg): Fix up calls to xdr_array.
+
+2000-02-13  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc_xdr.c: Add xdr functions for new kadm rpc functions.
+
+	* kadm_rpc.h: Add arg structs, prototypes, constants for new kadm
+	rpc functions.
+
+	* kadm_err.et: Add error code KADM5_SETKEY3_ETYPE_MISMATCH.
+
+	* admin.h: Add prototype for setkey_principal_3.
+
+1999-12-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* logger.c (klog_vsyslog): Convert pid_t to long for printing.
+
+1999-11-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): Fix bug in direction of
+	test while walking through whitespace.  Thanks to Matt Crawford.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* logger.c (lspec_parse_err_1, lspec_parse_err_2, log_file_err,
+	log_device_err, log_ufo_string, log_emerg_string,
+	log_alert_string, log_crit_string, log_err_string,
+	log_warning_string, log_notice_string, log_info_string,
+	log_debug_string): Replace char arrays with macros.
+	(klog_com_err_proc, klog_vsyslog): When calling syslog, supply %s
+	format string.
+
+1999-09-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* logger.c (DEVICE_PRINT, klog_com_err_proc, klog_vsyslog): Use
+	proper format strings to fprintf, instead of net-supplied data.
+	Fold in writes of following end-of-line sequences when
+	appropriate.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Dec  4 23:12:43 1998  Tom Yu  <tlyu@mit.edu>
+
+	* admin.h: Add prototypes for create_principal_3,
+	chpass_principal_3, and randkey_principal_3.
+
+Thu Aug 13 17:21:06 1998  Tom Yu  <tlyu@mit.edu>
+
+	* alt_prof.c (krb5_read_realm_params): Fix to check
+	"supported_enctypes" if "kdc_supported_enctypes" isn't there.
+
+Wed Aug 12 20:19:08 1998  Tom Yu  <tlyu@mit.edu>
+
+	* alt_prof.c (krb5_read_realm_params): Use
+	"kdc_supported_enctypes" instead of "supported_enctypes" so that
+	the KDC and the kadmind will use different enctype lists.
+
+Wed Jul  8 04:48:50 1998  Geoffrey J. King  <gjking@mit.edu>
+
+	* logger.c: Add the function krb5_klog_reopen() which closes
+	        and reopens the log files.
+
+Mon Apr  6 19:40:05 1998  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in (includes): Don't call mkdir unless the directory
+ 	exists.
+
+Fri Feb 27 22:30:41 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Move tests from all of kadm5's subdirectories into
+		this configure.in, and make it generate makefiles for all
+		of the subdirectories.
+
+	* Makefile.in: Add a LOCAL_SUBDIRS macro for all subdirectories in
+		the kadm5 library.
+
+Wed Feb 25 15:00:10 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* alt_prof.c (krb5_free_realm_params): Free realm_acl_file portion
+	of structure. 
+
+Wed Feb 18 16:13:56 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 21:33:27 1998  Tom Yu  <tlyu@mit.edu>
+
+	* admin.h:
+	* kadm_rpc.h:
+	* kadm_rpc_xdr.c: Update header locations.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 28 16:32:36 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in, Makefile.in: Remove the CopySrcHeader and
+		CopyHeader macros from configure.in and substitute
+		equivalent functionality in Makefile.in
+
+Tue Jan 20 23:06:36 1998  Tom Yu  <tlyu@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): Add support for Cygnus chpw.
+
+	* admin.h: Add support for Cygnus chpw.
+
+Mon Oct 13 10:48:24 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): When KADM5_CONFIG_ENCTYPES
+           is set on the input parameters, allocate a new copy of the
+           key_salts for the output parameters.
+	(kadm5_free_config_params): Free the admin_server and admin_lockfile
+	   names. 
+
+Tue Oct  7 07:48:12 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* logger.c: Include ctype.h for isspace definition.
+
+Tue Jul  1 02:31:07 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_rpc.h, kadm_rpc_xdr.c: Add support for setv4key.
+
+Sun Jun 29 14:52:04 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kadm_err.et: Add support for kadm5_setv4key_principal.
+
+	* admin.h: Add prototype for kadm5_setv4key_principal.
+
+Wed May 28 13:34:17 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* admin.h: add prototype for kadm5_setkey_principal
+
+	* misc_free.c (kadm5_free_key_data): add kadm5_free_data
+	
+Mon Mar 31 17:41:11 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadm_err.et, kadm_rpc.h, kadm_rpc_xdr.c: add support for
+ 	setkey_principal
+
+Thu Jan 16 19:01:00 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-prerecurse): Update to use double-colon rules.
+
+Wed Jan 15 20:43:01 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new libarary build procedure.
+
+Mon Nov 11 17:01:40 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadm_rpc_xdr.c: fix memory leak handling key_data and tl_data
+
+Wed Nov  6 10:20:36 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kadm_err.et: New error codes for KADM5_MISSING_CONF_PARAMS and 
+		KADM5_BAD_SERVER_NAME.
+
+Mon Nov  4 21:16:01 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* alt_prof.c (krb5_aprof_init): If the user specifies the config
+		file using a configuration file, it must exist.
+		Otherwise, krb5_aprof_init will return an error.
+		(kadm5_get_config_params): If aprof_init returns an error,
+		it should return an error as well.
+
+Wed Nov  6 17:45:43 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadm_rpc_xdr.c (xdr_krb5_principal): handle a NULL principal
+ 	pointer (this can happen when get_principal is passed a mask
+ 	without KADM5_PRINCIPAL in it, and will cause a beta 7 kadmind to
+ 	coredump)
+
+Fri Nov  1 13:16:16 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadm_err.et: update for new tl_data semantics [krb5-admin/140]
+
+Fri Oct 25 23:47:26 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in, Makefile.in: Tweaks to prevent unecessary
+	rebuilding.
+
+Mon Oct 21 21:23:44 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fixes for new directory recursion method; also
+	fixes for inclusion sequencing.
+
+Mon Oct 21 16:29:11 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* server_internal.h (ALL_PRINC_MASK): add KADM5_TL_DATA and
+ 	KADM5_KEY_DATA to ALL_PRINC_MASK [krb5-admin/20]
+
+Fri Oct 18 15:44:14 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kadm_rpc_xdr.c, misc_free.c, server_internal.h: include stdlib.h
+ 	instead of malloc.h [krb5-admin/35]
+
+Tue Oct 15 18:01:51 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* logger.c (krb5_klog_init): remember to call openlog() when
+ 	defaulting to syslog because nothing else was specified
+	(klog_vsyslog): enable VERBOSE_LOGS so we get the process name and
+ 	pid [krb5-kdc/63]
+
+Thu Sep 26 17:45:18 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* alt_prof.c: don't allow admin_dbname or admin_lockfile to be
+ 	independetly configured
+
+Fri Sep 20 16:52:07 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* configure.in: add unit-test directory
+
+Wed Sep 18 12:35:16 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): set max_life default to 10
+ 	hours, instead of 0
+
+Tue Sep 17 15:09:28 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* server_internal.h (ALL_PRINC_MASK): Add MAX_RLIFE to
+ 	ALL_PRINC_MASK.
+
+Tue Sep 10 01:47:39 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* alt_prof.c (krb5_aprof_init): use profile_init_path on fname,
+	not profile_init.
+
+Wed Aug 28 16:11:50 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* alt_prof.c (kadm5_get_config_params): fix default semantics to
+ 	agree with api-funcspec.tex
+
+Mon Aug 26 17:02:55 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* admin.h: KRB5_TL_KADM5_E_DATA moved to kdb.h
+
+Fri Aug  2 13:19:29 1996  Barry Jaspan  <bjaspan@DUN-DUN-NOODLES>
+
+	* alt_prof.c (kadm5_get_config_params): alloc enough bytes for
+        adbname
+
+	* kadm_rpc_xdr.c (xdr_krb5_kvno): assign tmp before xdr'ing it to
+        avoid a spurious purify error
+
+Thu Jul 25 12:04:32 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* admin_internal.h (_KADM5_CHECK_HANDLE): Add parenthesis around
+		assignment used as truth value to reduce gcc -Wall flames.
+
+	* misc_free.c (kadm5_free_name_list, krb5_free_key_data_contents: 
+		Add KADM5_OK return value upon success.
+
+
+Wed Jul 24 18:18:39 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in, configure.in: fix shared lib lossage by
+		rearrangement of subdirectories
+
+Tue Jul 23 16:49:56 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in: delete extraneous trailing backslash from GENSRCS
+		and GENOBJS
+
+Mon Jul 22 04:17:23 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in (LIBS): add -lgen to LIBS whenever compile is
+ 	found.  Solaris requires it.
+
+	* chpass_util.c (_kadm5_chpass_principal_util): the calls to
+ 	kadm5_free_{princicpal,policy}_ent used server_handle instead of
+ 	lhandle, which caused problems in the api versioning code.
+
+Thu Jul 18 19:50:39 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: removed ET_RULES, replaced with AC_PROG_AWK
+
+Mon Jul 15 16:52:44 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* client_init.c (_kadm5_init_any): use krb5_get_in_tkt_keytab
+ 	instead of changing krb5_defkeyname
+
+Mon Jul 15 16:36:02 1996  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in (CLNTOBJS), AC_REPLACE_FUNCS: check for setenv, and
+ 	link against setenv.o if it's needed.
+
+Fri Jul 12 15:06:48 1996  Marc Horowitz  <marc@mit.edu>
+
+	* svr_iters.c (glob_to_regexp:append_realm): the semantics and
+ 	code were somewhat confused.  they are now fixed.
+
+	* logger.c (HAVE_*): turn all the "#if HAVE_*" into
+	"#ifdef HAVE_*"
+
+	* configure.in (AC_CHECK_FUNCS): check for the functions which
+ 	logger.c checks for.
+
+	* svr_principal.c (kadm5_get_principal): due to the the api
+ 	versioning, it is possible for this function to be called with a
+ 	three argument prototype.  in this case, do not modify mask,
+ 	because this will clobber the stack on some platforms.
+
+	* client_principal.c (kadm5_create_principal): be more careful
+ 	about what sorts of things are referenced, passed down, and passed
+ 	back if the caller is api v1.
+
+Wed Jul 10 01:29:34 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in: added autoconf support
+
+Tue Jul  9 17:38:43 1996  Marc Horowitz  <marc@mit.edu>
+
+	* svr_iters.c (*_REGEXPS): rework the conditionals to operate
+ 	as functions of function symbols tested by configure.
+	* client_init.c (setenv, unsetenv declarations): make them the
+ 	same as the stdlib declarations, if they're going to be here at
+ 	all.
+	* Makefile.in: reworked to support building both libraries.  this
+ 	required a bunch of changes, including some coordinating ones in
+ 	aclocal.m4
+	
+Tue Jul  9 16:26:26 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_principal.c (kadm5_decrypt_key): add kadm5_decrypt_key
+
+Mon Jul  8 16:55:22 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_iters.c (kadm5_get_either): append local ream to globs with
+ 	no realm
+
+	* alt_prof.c: fix dbname, admin_dbname, and admin_lockfile to
+ 	derive from each other as in spec
+
+	* adb_policy.c: add create_db/destroy_db
+
+	* adb_openclose.c: add create_db/destroy_db, fix handling of
+ 	permanent locks, handle multiple lock files via static linked list
+
+	* adb.h: update create_db/destroy_db to make params instead of
+ 	explicit values
+
+	* Makefile.ov (TOP): Use ../../kadmin, not kadmin.ov
+	
+
diff --git a/mechglue/src/lib/kadm5/Makefile.in b/mechglue/src/lib/kadm5/Makefile.in
new file mode 100644
index 000000000..7f0b239c7
--- /dev/null
+++ b/mechglue/src/lib/kadm5/Makefile.in
@@ -0,0 +1,187 @@
+thisconfigdir=.
+myfulldir=lib/kadm5
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCAL_SUBDIRS = clnt srv unit-test
+
+##DOSBUILDTOP = ..\..
+
+kadm_err.$(OBJEXT): kadm_err.c
+chpass_util_strings.$(OBJEXT): chpass_util_strings.c
+
+kadm_err.c kadm_err.h: $(srcdir)/kadm_err.et
+chpass_util_strings.c chpass_util_strings.h: $(srcdir)/chpass_util_strings.et
+
+clean::
+	$(RM) kadm_err.c kadm_err.h kadm_err.o
+	$(RM) chpass_util_strings.c chpass_util_strings.h chpass_util_strings.o
+
+SRCS =	kadm_err.c \
+	chpass_util_strings.c \
+	$(srcdir)/ovsec_glue.c \
+	$(srcdir)/misc_free.c \
+	$(srcdir)/kadm_rpc_xdr.c \
+	$(srcdir)/chpass_util.c \
+	$(srcdir)/alt_prof.c \
+	$(srcdir)/str_conv.c \
+	$(srcdir)/logger.c
+
+OBJS =	kadm_err.$(OBJEXT) \
+	chpass_util_strings.$(OBJEXT) \
+	ovsec_glue.$(OBJEXT) \
+	misc_free.$(OBJEXT) \
+	kadm_rpc_xdr.$(OBJEXT) \
+	chpass_util.$(OBJEXT) \
+	alt_prof.$(OBJEXT) \
+	str_conv.$(OBJEXT) \
+	logger.$(OBJEXT)
+
+STLIBOBJS = \
+	kadm_err.o \
+	chpass_util_strings.o \
+	ovsec_glue.o \
+	misc_free.o \
+	kadm_rpc_xdr.o \
+	chpass_util.o \
+	alt_prof.o \
+	str_conv.o \
+	logger.o
+
+HDRDIR=$(BUILDTOP)/include/kadm5
+HDRS =	$(HDRDIR)/admin.h \
+	$(HDRDIR)/admin_internal.h \
+	$(HDRDIR)/admin_xdr.h \
+	$(HDRDIR)/kadm_rpc.h \
+	$(HDRDIR)/server_internal.h \
+	$(HDRDIR)/chpass_util_strings.h \
+	$(HDRDIR)/kadm_err.h
+
+BUILD_HDRS = chpass_util_strings.h kadm_err.h
+SRC_HDRS = admin.h admin_internal.h admin_xdr.h kadm_rpc.h \
+		server_internal.h 
+
+$(HDRS): includes
+
+includes:: $(SRC_HDRS) $(BUILD_HDRS)
+	if [ -d $(HDRDIR) ]; then :; else mkdir -p $(HDRDIR); fi
+	for i in $(SRC_HDRS) ; do \
+		i=`basename $$i`; \
+		if cmp $(srcdir)/$$i $(HDRDIR)/$$i >/dev/null 2>&1; then :; \
+		else \
+			(set -x; $(RM) $(HDRDIR)/$$i; \
+			 $(CP) $(srcdir)/$$i $(HDRDIR)/$$i) ; \
+		fi ; \
+	done
+	for i in $(BUILD_HDRS) ; do \
+		i=`basename $$i`; \
+		if cmp $$i $(HDRDIR)/$$i >/dev/null 2>&1; then :; \
+		else \
+			(set -x; $(RM) $(HDRDIR)/$$i; \
+			 $(CP) $$i $(HDRDIR)/$$i) ; \
+		fi ; \
+	done
+
+clean-unix::
+	$(RM) $(HDRS)
+
+all-prerecurse: includes
+all-prerecurse: all-libobjs
+
+all-windows:: $(OBJS)
+
+check-windows::
+
+clean-unix:: clean-libobjs
+
+clean-windows::
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+kadm_err.so kadm_err.po $(OUTPRE)kadm_err.$(OBJEXT): \
+  kadm_err.c $(COM_ERR_DEPS)
+chpass_util_strings.so chpass_util_strings.po $(OUTPRE)chpass_util_strings.$(OBJEXT): \
+  chpass_util_strings.c $(COM_ERR_DEPS)
+ovsec_glue.so ovsec_glue.po $(OUTPRE)ovsec_glue.$(OBJEXT): \
+  ovsec_glue.c $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h
+misc_free.so misc_free.po $(OUTPRE)misc_free.$(OBJEXT): \
+  misc_free.c $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h server_internal.h \
+  admin_internal.h
+kadm_rpc_xdr.so kadm_rpc_xdr.po $(OUTPRE)kadm_rpc_xdr.$(OBJEXT): \
+  kadm_rpc_xdr.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/kadm5/admin.h \
+  $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_rpc.h \
+  $(BUILDTOP)/include/kadm5/admin_xdr.h $(BUILDTOP)/include/kadm5/server_internal.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h
+chpass_util.so chpass_util.po $(OUTPRE)chpass_util.$(OBJEXT): \
+  chpass_util.c $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h admin_internal.h
+alt_prof.so alt_prof.po $(OUTPRE)alt_prof.$(OBJEXT): \
+  alt_prof.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(SRCTOP)/include/krb5/adm_proto.h
+str_conv.so str_conv.po $(OUTPRE)str_conv.$(OBJEXT): \
+  str_conv.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  admin_internal.h $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(SRCTOP)/include/krb5/adm_proto.h
+logger.so logger.po $(OUTPRE)logger.$(OBJEXT): logger.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/krb5/adm_proto.h $(SRCTOP)/include/syslog.h
diff --git a/mechglue/src/lib/kadm5/adb.h b/mechglue/src/lib/kadm5/adb.h
new file mode 100644
index 000000000..8b53b5501
--- /dev/null
+++ b/mechglue/src/lib/kadm5/adb.h
@@ -0,0 +1,149 @@
+/*
+ * Data Types for policy and principal information that
+ * exists in the respective databases.
+ *
+ * $Header$
+ *
+ * This file was originally created with rpcgen.
+ * It has been hacked up since then.
+ */
+
+#ifndef __ADB_H__
+#define __ADB_H__
+#include <sys/types.h>
+#include <gssrpc/types.h>
+#include "k5-int.h"
+#include <krb5/kdb.h>
+#include <db.h>
+#include <kadm5/admin.h>
+#include <kadm5/adb_err.h>
+#include <com_err.h>
+
+typedef	long		osa_adb_ret_t;
+
+#define OSA_ADB_POLICY_DB_MAGIC	0x12345A00
+#define OSA_ADB_PRINC_DB_MAGIC	0x12345B00
+
+#define OSA_ADB_SHARED		0x7001
+#define OSA_ADB_EXCLUSIVE	0x7002
+#define OSA_ADB_PERMANENT	0x7003
+
+#define OSA_ADB_PRINC_VERSION_MASK	0x12345C00
+#define OSA_ADB_PRINC_VERSION_1		0x12345C01
+#define OSA_ADB_POLICY_VERSION_MASK	0x12345D00
+#define OSA_ADB_POLICY_VERSION_1	0x12345D01
+
+typedef struct _osa_adb_db_lock_ent_t {
+     FILE	*lockfile;
+     char	*filename;
+     int	refcnt, lockmode, lockcnt;
+     krb5_context context;
+} osa_adb_lock_ent, *osa_adb_lock_t;
+
+typedef struct _osa_adb_db_ent_t {
+     int	magic;
+     DB		*db;
+     HASHINFO	info;
+     BTREEINFO	btinfo;
+     char	*filename;
+     osa_adb_lock_t lock;
+     int	opencnt;
+} osa_adb_db_ent, *osa_adb_db_t, *osa_adb_princ_t, *osa_adb_policy_t;
+
+/* an osa_pw_hist_ent stores all the key_datas for a single password */
+typedef struct _osa_pw_hist_t {
+     int n_key_data;
+     krb5_key_data *key_data;
+} osa_pw_hist_ent, *osa_pw_hist_t;
+
+typedef struct _osa_princ_ent_t {
+    int				version;
+    char			*policy;
+    long			aux_attributes;
+    unsigned int		old_key_len;
+    unsigned int		old_key_next;
+    krb5_kvno			admin_history_kvno;
+    osa_pw_hist_ent		*old_keys;
+} osa_princ_ent_rec, *osa_princ_ent_t;
+
+typedef struct _osa_policy_ent_t {
+    int		version;
+    char	*name;
+    uint32_t	pw_min_life;
+    uint32_t	pw_max_life;
+    uint32_t	pw_min_length;
+    uint32_t	pw_min_classes;
+    uint32_t	pw_history_num;
+    uint32_t	policy_refcnt;
+} osa_policy_ent_rec, *osa_policy_ent_t;
+
+typedef	void	(*osa_adb_iter_princ_func) (void *, osa_princ_ent_t);
+typedef	void	(*osa_adb_iter_policy_func) (void *, osa_policy_ent_t);
+  
+
+/*
+ * Return Code (the rest are in adb_err.h)
+ */
+ 
+#define OSA_ADB_OK		0
+
+/*
+ * xdr functions
+ */
+bool_t		xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp);
+bool_t		xdr_osa_policy_ent_rec(XDR *xdrs, osa_policy_ent_t objp);
+bool_t		xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp);
+bool_t          xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp);
+
+/*
+ * Functions
+ */
+
+osa_adb_ret_t	osa_adb_create_db(char *filename, char *lockfile, int magic);
+osa_adb_ret_t	osa_adb_destroy_db(char *filename, char *lockfile, int magic);
+osa_adb_ret_t   osa_adb_rename_db(char *filefrom, char *lockfrom,
+				  char *fileto, char *lockto, int magic);
+osa_adb_ret_t   osa_adb_rename_policy_db(kadm5_config_params *fromparams,
+					 kadm5_config_params *toparams);
+osa_adb_ret_t	osa_adb_init_db(osa_adb_db_t *dbp, char *filename,
+				char *lockfile, int magic);
+osa_adb_ret_t	osa_adb_fini_db(osa_adb_db_t db, int magic);
+osa_adb_ret_t	osa_adb_get_lock(osa_adb_db_t db, int mode);
+osa_adb_ret_t	osa_adb_release_lock(osa_adb_db_t db);
+osa_adb_ret_t	osa_adb_open_and_lock(osa_adb_princ_t db, int locktype);
+osa_adb_ret_t	osa_adb_close_and_unlock(osa_adb_princ_t db);
+
+osa_adb_ret_t	osa_adb_create_policy_db(kadm5_config_params *params);
+osa_adb_ret_t	osa_adb_destroy_policy_db(kadm5_config_params *params);
+osa_adb_ret_t	osa_adb_open_princ(osa_adb_princ_t *db, char *filename);
+osa_adb_ret_t	osa_adb_open_policy(osa_adb_policy_t *db,
+				    kadm5_config_params *rparams);
+osa_adb_ret_t	osa_adb_close_princ(osa_adb_princ_t db);
+osa_adb_ret_t	osa_adb_close_policy(osa_adb_policy_t db);
+osa_adb_ret_t	osa_adb_create_princ(osa_adb_princ_t db,
+				 osa_princ_ent_t entry);
+osa_adb_ret_t	osa_adb_create_policy(osa_adb_policy_t db,
+				      osa_policy_ent_t entry);
+osa_adb_ret_t	osa_adb_destroy_princ(osa_adb_princ_t db,
+				      kadm5_princ_t name);
+osa_adb_ret_t	osa_adb_destroy_policy(osa_adb_policy_t db,
+				       kadm5_policy_t name);
+osa_adb_ret_t	osa_adb_get_princ(osa_adb_princ_t db,
+				  kadm5_princ_t name,
+				  osa_princ_ent_t *entry);
+osa_adb_ret_t	osa_adb_get_policy(osa_adb_policy_t db,
+				   kadm5_policy_t name,
+				   osa_policy_ent_t *entry);
+osa_adb_ret_t	osa_adb_put_princ(osa_adb_princ_t db,
+				  osa_princ_ent_t entry);
+osa_adb_ret_t	osa_adb_put_policy(osa_adb_policy_t db,
+				   osa_policy_ent_t entry);
+osa_adb_ret_t	osa_adb_iter_policy(osa_adb_policy_t db,
+				    osa_adb_iter_policy_func func,
+				    void * data);
+osa_adb_ret_t	osa_adb_iter_princ(osa_adb_princ_t db,
+				       osa_adb_iter_princ_func func,
+				       void *data);
+void		osa_free_policy_ent(osa_policy_ent_t val);
+void		osa_free_princ_ent(osa_princ_ent_t val);
+#endif /* __ADB_H__ */
diff --git a/mechglue/src/lib/kadm5/admin.h b/mechglue/src/lib/kadm5/admin.h
new file mode 100644
index 000000000..3ce01c7f3
--- /dev/null
+++ b/mechglue/src/lib/kadm5/admin.h
@@ -0,0 +1,734 @@
+/*
+ * lib/kadm5/admin.h
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#ifndef __KADM5_ADMIN_H__
+#define __KADM5_ADMIN_H__
+
+#if !defined(USE_KADM5_API_VERSION)
+#define USE_KADM5_API_VERSION 2
+#endif
+     
+#include	<sys/types.h>
+#include	<gssrpc/rpc.h>
+#include	<krb5.h>
+#include	<kdb.h>
+#include	<com_err.h>
+#include	<kadm5/kadm_err.h>
+#include	<kadm5/chpass_util_strings.h>
+
+#define KADM5_ADMIN_SERVICE	"kadmin/admin"
+#define KADM5_CHANGEPW_SERVICE	"kadmin/changepw"
+#define KADM5_HIST_PRINCIPAL	"kadmin/history"
+
+typedef krb5_principal	kadm5_princ_t;
+typedef	char		*kadm5_policy_t;
+typedef long		kadm5_ret_t;
+
+#define KADM5_PW_FIRST_PROMPT \
+	(error_message(CHPASS_UTIL_NEW_PASSWORD_PROMPT))
+#define KADM5_PW_SECOND_PROMPT \
+	(error_message(CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT))
+
+/*
+ * Successful return code
+ */
+#define KADM5_OK	0
+
+/*
+ * Field masks
+ */
+
+/* kadm5_principal_ent_t */
+#define KADM5_PRINCIPAL		0x000001
+#define KADM5_PRINC_EXPIRE_TIME	0x000002
+#define KADM5_PW_EXPIRATION	0x000004
+#define KADM5_LAST_PWD_CHANGE	0x000008
+#define KADM5_ATTRIBUTES	0x000010
+#define KADM5_MAX_LIFE		0x000020
+#define KADM5_MOD_TIME		0x000040
+#define KADM5_MOD_NAME		0x000080
+#define KADM5_KVNO		0x000100
+#define KADM5_MKVNO		0x000200
+#define KADM5_AUX_ATTRIBUTES	0x000400
+#define KADM5_POLICY		0x000800
+#define KADM5_POLICY_CLR	0x001000
+/* version 2 masks */
+#define KADM5_MAX_RLIFE		0x002000
+#define KADM5_LAST_SUCCESS	0x004000
+#define KADM5_LAST_FAILED	0x008000
+#define KADM5_FAIL_AUTH_COUNT	0x010000
+#define KADM5_KEY_DATA		0x020000
+#define KADM5_TL_DATA		0x040000
+/* all but KEY_DATA and TL_DATA */
+#define KADM5_PRINCIPAL_NORMAL_MASK 0x01ffff
+
+/* kadm5_policy_ent_t */
+#define KADM5_PW_MAX_LIFE	0x004000
+#define KADM5_PW_MIN_LIFE	0x008000
+#define KADM5_PW_MIN_LENGTH	0x010000
+#define KADM5_PW_MIN_CLASSES	0x020000
+#define KADM5_PW_HISTORY_NUM	0x040000
+#define KADM5_REF_COUNT		0x080000
+
+/* kadm5_config_params */
+#define KADM5_CONFIG_REALM		0x000001
+#define KADM5_CONFIG_DBNAME		0x000002
+#define KADM5_CONFIG_MKEY_NAME		0x000004
+#define KADM5_CONFIG_MAX_LIFE		0x000008
+#define KADM5_CONFIG_MAX_RLIFE		0x000010
+#define KADM5_CONFIG_EXPIRATION		0x000020
+#define KADM5_CONFIG_FLAGS		0x000040
+#define KADM5_CONFIG_ADMIN_KEYTAB	0x000080
+#define KADM5_CONFIG_STASH_FILE		0x000100
+#define KADM5_CONFIG_ENCTYPE		0x000200
+#define KADM5_CONFIG_ADBNAME		0x000400
+#define KADM5_CONFIG_ADB_LOCKFILE	0x000800
+#define KADM5_CONFIG_PROFILE		0x001000
+#define KADM5_CONFIG_ACL_FILE		0x002000
+#define KADM5_CONFIG_KADMIND_PORT	0x004000
+#define KADM5_CONFIG_ENCTYPES		0x008000
+#define KADM5_CONFIG_ADMIN_SERVER	0x010000
+#define KADM5_CONFIG_DICT_FILE		0x020000
+#define KADM5_CONFIG_MKEY_FROM_KBD	0x040000
+#define KADM5_CONFIG_KPASSWD_PORT	0x080000
+#define KADM5_CONFIG_OLD_AUTH_GSSAPI	0x100000
+#define KADM5_CONFIG_NO_AUTH		0x200000
+#define KADM5_CONFIG_AUTH_NOFALLBACK	0x400000
+
+/*
+ * permission bits
+ */
+#define KADM5_PRIV_GET		0x01
+#define KADM5_PRIV_ADD		0x02
+#define KADM5_PRIV_MODIFY	0x04
+#define KADM5_PRIV_DELETE	0x08
+
+/*
+ * API versioning constants
+ */
+#define KADM5_MASK_BITS		0xffffff00
+
+#define KADM5_STRUCT_VERSION_MASK	0x12345600
+#define KADM5_STRUCT_VERSION_1	(KADM5_STRUCT_VERSION_MASK|0x01)
+#define KADM5_STRUCT_VERSION	KADM5_STRUCT_VERSION_1
+
+#define KADM5_API_VERSION_MASK	0x12345700
+#define KADM5_API_VERSION_1	(KADM5_API_VERSION_MASK|0x01)
+#define KADM5_API_VERSION_2	(KADM5_API_VERSION_MASK|0x02)
+
+typedef struct _kadm5_principal_ent_t_v2 {
+	krb5_principal	principal;
+	krb5_timestamp	princ_expire_time;
+	krb5_timestamp	last_pwd_change;
+	krb5_timestamp	pw_expiration;
+	krb5_deltat	max_life;
+	krb5_principal	mod_name;
+	krb5_timestamp	mod_date;
+	krb5_flags	attributes;
+	krb5_kvno	kvno;
+	krb5_kvno	mkvno;
+	char		*policy;
+	long		aux_attributes;
+
+	/* version 2 fields */
+	krb5_deltat max_renewable_life;
+        krb5_timestamp last_success;
+        krb5_timestamp last_failed;
+        krb5_kvno fail_auth_count;
+	krb5_int16 n_key_data;
+	krb5_int16 n_tl_data;
+        krb5_tl_data *tl_data;
+	krb5_key_data *key_data;
+} kadm5_principal_ent_rec_v2, *kadm5_principal_ent_t_v2;
+
+typedef struct _kadm5_principal_ent_t_v1 {
+	krb5_principal	principal;
+	krb5_timestamp	princ_expire_time;
+	krb5_timestamp	last_pwd_change;
+	krb5_timestamp	pw_expiration;
+	krb5_deltat	max_life;
+	krb5_principal	mod_name;
+	krb5_timestamp	mod_date;
+	krb5_flags	attributes;
+	krb5_kvno	kvno;
+	krb5_kvno	mkvno;
+	char		*policy;
+	long		aux_attributes;
+} kadm5_principal_ent_rec_v1, *kadm5_principal_ent_t_v1;
+
+#if USE_KADM5_API_VERSION == 1
+typedef struct _kadm5_principal_ent_t_v1
+     kadm5_principal_ent_rec, *kadm5_principal_ent_t;
+#else
+typedef struct _kadm5_principal_ent_t_v2
+     kadm5_principal_ent_rec, *kadm5_principal_ent_t;
+#endif
+
+typedef struct _kadm5_policy_ent_t {
+	char		*policy;
+	long		pw_min_life;
+	long		pw_max_life;
+	long		pw_min_length;
+	long		pw_min_classes;
+	long		pw_history_num;
+	long		policy_refcnt;
+} kadm5_policy_ent_rec, *kadm5_policy_ent_t;
+
+/*
+ * Data structure returned by kadm5_get_config_params()
+ */
+typedef struct _kadm5_config_params {
+     long		mask;
+     char *		realm;
+     char *		profile;
+     int		kadmind_port;
+     int		kpasswd_port;
+
+     char *		admin_server;
+
+     char *		dbname;
+     char *		admin_dbname;
+     char *		admin_lockfile;
+     char *		admin_keytab;
+     char *		acl_file;
+     char *		dict_file;
+
+     int		mkey_from_kbd;
+     char *		stash_file;
+     char *		mkey_name;
+     krb5_enctype	enctype;
+     krb5_deltat	max_life;
+     krb5_deltat	max_rlife;
+     krb5_timestamp	expiration;
+     krb5_flags		flags;
+     krb5_key_salt_tuple *keysalts;
+     krb5_int32		num_keysalts;
+} kadm5_config_params;
+
+/***********************************************************************
+ * This is the old krb5_realm_read_params, which I mutated into
+ * kadm5_get_config_params but which old code (kdb5_* and krb5kdc)
+ * still uses.
+ ***********************************************************************/
+
+/*
+ * Data structure returned by krb5_read_realm_params()
+ */
+typedef struct __krb5_realm_params {
+    char *		realm_profile;
+    char *		realm_dbname;
+    char *		realm_mkey_name;
+    char *		realm_stash_file;
+    char *		realm_kdc_ports;
+    char *		realm_kdc_tcp_ports;
+    char *		realm_acl_file;
+    krb5_int32		realm_kadmind_port;
+    krb5_enctype	realm_enctype;
+    krb5_deltat		realm_max_life;
+    krb5_deltat		realm_max_rlife;
+    krb5_timestamp	realm_expiration;
+    krb5_flags		realm_flags;
+    krb5_key_salt_tuple	*realm_keysalts;
+    unsigned int	realm_reject_bad_transit:1;
+    unsigned int	realm_kadmind_port_valid:1;
+    unsigned int	realm_enctype_valid:1;
+    unsigned int	realm_max_life_valid:1;
+    unsigned int	realm_max_rlife_valid:1;
+    unsigned int	realm_expiration_valid:1;
+    unsigned int	realm_flags_valid:1;
+    unsigned int	realm_reject_bad_transit_valid:1;
+    krb5_int32		realm_num_keysalts;
+} krb5_realm_params;
+
+/*
+ * functions
+ */
+
+#if USE_KADM5_API_VERSION > 1
+krb5_error_code kadm5_get_config_params(krb5_context context,
+					char *kdcprofile, char *kdcenv,
+					kadm5_config_params *params_in,
+					kadm5_config_params *params_out);
+
+krb5_error_code kadm5_free_config_params(krb5_context context, 
+					 kadm5_config_params *params);
+
+krb5_error_code kadm5_free_realm_params(krb5_context kcontext,
+					kadm5_config_params *params);
+
+krb5_error_code kadm5_get_admin_service_name(krb5_context, char *,
+					     char *, size_t);
+#endif
+
+kadm5_ret_t    kadm5_init(char *client_name, char *pass,
+			  char *service_name,
+#if USE_KADM5_API_VERSION == 1
+			  char *realm,
+#else
+			  kadm5_config_params *params,
+#endif
+			  krb5_ui_4 struct_version,
+			  krb5_ui_4 api_version,
+			  char **db_args,
+			  void **server_handle);
+kadm5_ret_t    kadm5_init_with_password(char *client_name,
+					char *pass, 
+					char *service_name,
+#if USE_KADM5_API_VERSION == 1
+					char *realm,
+#else
+					kadm5_config_params *params,
+#endif
+					krb5_ui_4 struct_version,
+					krb5_ui_4 api_version,
+					char **db_args,
+					void **server_handle);
+kadm5_ret_t    kadm5_init_with_skey(char *client_name,
+				    char *keytab,
+				    char *service_name,
+#if USE_KADM5_API_VERSION == 1
+				    char *realm,
+#else
+				    kadm5_config_params *params,
+#endif
+				    krb5_ui_4 struct_version,
+				    krb5_ui_4 api_version,
+				    char **db_args,
+				    void **server_handle);
+#if USE_KADM5_API_VERSION > 1
+kadm5_ret_t    kadm5_init_with_creds(char *client_name,
+				     krb5_ccache cc,
+				     char *service_name,
+				     kadm5_config_params *params,
+				     krb5_ui_4 struct_version,
+				     krb5_ui_4 api_version,
+				     char **db_args,
+				     void **server_handle);
+#endif
+kadm5_ret_t    kadm5_lock(void *server_handle);
+kadm5_ret_t    kadm5_unlock(void *server_handle);
+kadm5_ret_t    kadm5_flush(void *server_handle);
+kadm5_ret_t    kadm5_destroy(void *server_handle);
+kadm5_ret_t    kadm5_create_principal(void *server_handle,
+				      kadm5_principal_ent_t ent,
+				      long mask, char *pass);
+kadm5_ret_t    kadm5_create_principal_3(void *server_handle,
+					kadm5_principal_ent_t ent,
+					long mask,
+					int n_ks_tuple,
+					krb5_key_salt_tuple *ks_tuple,
+					char *pass);
+kadm5_ret_t    kadm5_delete_principal(void *server_handle,
+				      krb5_principal principal);
+kadm5_ret_t    kadm5_modify_principal(void *server_handle,
+				      kadm5_principal_ent_t ent,
+				      long mask);
+kadm5_ret_t    kadm5_rename_principal(void *server_handle,
+				      krb5_principal,krb5_principal);
+#if USE_KADM5_API_VERSION == 1
+kadm5_ret_t    kadm5_get_principal(void *server_handle,
+				   krb5_principal principal,
+				   kadm5_principal_ent_t *ent);
+#else
+kadm5_ret_t    kadm5_get_principal(void *server_handle,
+				   krb5_principal principal,
+				   kadm5_principal_ent_t ent,
+				   long mask);
+#endif
+kadm5_ret_t    kadm5_chpass_principal(void *server_handle,
+				      krb5_principal principal,
+				      char *pass);
+kadm5_ret_t    kadm5_chpass_principal_3(void *server_handle,
+					krb5_principal principal,
+					krb5_boolean keepold,
+					int n_ks_tuple,
+					krb5_key_salt_tuple *ks_tuple,
+					char *pass);
+#if USE_KADM5_API_VERSION == 1
+kadm5_ret_t    kadm5_randkey_principal(void *server_handle,
+				       krb5_principal principal,
+				       krb5_keyblock **keyblock);
+#else
+kadm5_ret_t    kadm5_randkey_principal(void *server_handle,
+				       krb5_principal principal,
+				       krb5_keyblock **keyblocks,
+				       int *n_keys);
+kadm5_ret_t    kadm5_randkey_principal_3(void *server_handle,
+					 krb5_principal principal,
+					 krb5_boolean keepold,
+					 int n_ks_tuple,
+					 krb5_key_salt_tuple *ks_tuple,
+					 krb5_keyblock **keyblocks,
+					 int *n_keys);
+#endif
+kadm5_ret_t    kadm5_setv4key_principal(void *server_handle,
+					krb5_principal principal,
+					krb5_keyblock *keyblock);
+
+kadm5_ret_t    kadm5_setkey_principal(void *server_handle,
+				      krb5_principal principal,
+				      krb5_keyblock *keyblocks,
+				      int n_keys);
+
+kadm5_ret_t    kadm5_setkey_principal_3(void *server_handle,
+					krb5_principal principal,
+					krb5_boolean keepold,
+					int n_ks_tuple,
+					krb5_key_salt_tuple *ks_tuple,
+					krb5_keyblock *keyblocks,
+					int n_keys);
+
+kadm5_ret_t    kadm5_decrypt_key(void *server_handle,
+				 kadm5_principal_ent_t entry, krb5_int32
+				 ktype, krb5_int32 stype, krb5_int32
+				 kvno, krb5_keyblock *keyblock,
+				 krb5_keysalt *keysalt, int *kvnop);
+
+kadm5_ret_t    kadm5_create_policy(void *server_handle,
+				   kadm5_policy_ent_t ent,
+				   long mask);
+/*
+ * kadm5_create_policy_internal is not part of the supported,
+ * exposed API.  It is available only in the server library, and you
+ * shouldn't use it unless you know why it's there and how it's
+ * different from kadm5_create_policy.
+ */
+kadm5_ret_t    kadm5_create_policy_internal(void *server_handle,
+					    kadm5_policy_ent_t
+					    entry, long mask);
+kadm5_ret_t    kadm5_delete_policy(void *server_handle,
+				   kadm5_policy_t policy);
+kadm5_ret_t    kadm5_modify_policy(void *server_handle,
+				   kadm5_policy_ent_t ent,
+				   long mask);
+/*
+ * kadm5_modify_policy_internal is not part of the supported,
+ * exposed API.  It is available only in the server library, and you
+ * shouldn't use it unless you know why it's there and how it's
+ * different from kadm5_modify_policy.
+ */
+kadm5_ret_t    kadm5_modify_policy_internal(void *server_handle,
+					    kadm5_policy_ent_t
+					    entry, long mask);
+#if USE_KADM5_API_VERSION == 1
+kadm5_ret_t    kadm5_get_policy(void *server_handle,
+				kadm5_policy_t policy,
+				kadm5_policy_ent_t *ent);
+#else
+kadm5_ret_t    kadm5_get_policy(void *server_handle,
+				kadm5_policy_t policy,
+				kadm5_policy_ent_t ent);
+#endif
+kadm5_ret_t    kadm5_get_privs(void *server_handle,
+			       long *privs);
+
+kadm5_ret_t    kadm5_chpass_principal_util(void *server_handle,
+					   krb5_principal princ,
+					   char *new_pw, 
+					   char **ret_pw,
+					   char *msg_ret,
+					   unsigned int msg_len);
+
+kadm5_ret_t    kadm5_free_principal_ent(void *server_handle,
+					kadm5_principal_ent_t
+					ent);
+kadm5_ret_t    kadm5_free_policy_ent(void *server_handle,
+				     kadm5_policy_ent_t ent);
+
+kadm5_ret_t    kadm5_get_principals(void *server_handle,
+				    char *exp, char ***princs,
+				    int *count);
+
+kadm5_ret_t    kadm5_get_policies(void *server_handle,
+				  char *exp, char ***pols,
+				  int *count);
+
+#if USE_KADM5_API_VERSION > 1
+kadm5_ret_t    kadm5_free_key_data(void *server_handle,
+				   krb5_int16 *n_key_data,
+				   krb5_key_data *key_data);
+#endif
+
+kadm5_ret_t    kadm5_free_name_list(void *server_handle, char **names, 
+				    int count);
+
+#if USE_KADM5_API_VERSION == 1
+/*
+ * OVSEC_KADM_API_VERSION_1 should be, if possible, compile-time
+ * compatible with KADM5_API_VERSION_2.  Basically, this means we have
+ * to continue to provide all the old ovsec_kadm function and symbol
+ * names.
+ */
+
+#define OVSEC_KADM_ACLFILE		"/krb5/ovsec_adm.acl"
+#define	OVSEC_KADM_WORDFILE		"/krb5/ovsec_adm.dict"
+
+#define OVSEC_KADM_ADMIN_SERVICE	"ovsec_adm/admin"
+#define OVSEC_KADM_CHANGEPW_SERVICE	"ovsec_adm/changepw"
+#define OVSEC_KADM_HIST_PRINCIPAL	"ovsec_adm/history"
+
+typedef krb5_principal	ovsec_kadm_princ_t;
+typedef krb5_keyblock	ovsec_kadm_keyblock;
+typedef	char		*ovsec_kadm_policy_t;
+typedef long		ovsec_kadm_ret_t;
+
+enum	ovsec_kadm_salttype { OVSEC_KADM_SALT_V4, OVSEC_KADM_SALT_NORMAL };
+enum	ovsec_kadm_saltmod  { OVSEC_KADM_MOD_KEEP, OVSEC_KADM_MOD_V4, OVSEC_KADM_MOD_NORMAL };
+
+#define OVSEC_KADM_PW_FIRST_PROMPT \
+	((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_PROMPT))
+#define OVSEC_KADM_PW_SECOND_PROMPT \
+	((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT))
+
+/*
+ * Successful return code
+ */
+#define OVSEC_KADM_OK	0
+ 
+/*
+ * Create/Modify masks
+ */
+/* principal */
+#define OVSEC_KADM_PRINCIPAL		0x000001
+#define OVSEC_KADM_PRINC_EXPIRE_TIME	0x000002
+#define OVSEC_KADM_PW_EXPIRATION	0x000004
+#define OVSEC_KADM_LAST_PWD_CHANGE	0x000008
+#define OVSEC_KADM_ATTRIBUTES		0x000010
+#define OVSEC_KADM_MAX_LIFE		0x000020
+#define OVSEC_KADM_MOD_TIME		0x000040
+#define OVSEC_KADM_MOD_NAME		0x000080
+#define OVSEC_KADM_KVNO			0x000100
+#define OVSEC_KADM_MKVNO		0x000200
+#define OVSEC_KADM_AUX_ATTRIBUTES	0x000400
+#define OVSEC_KADM_POLICY		0x000800
+#define OVSEC_KADM_POLICY_CLR		0x001000
+/* policy */
+#define OVSEC_KADM_PW_MAX_LIFE		0x004000
+#define OVSEC_KADM_PW_MIN_LIFE		0x008000
+#define OVSEC_KADM_PW_MIN_LENGTH	0x010000
+#define OVSEC_KADM_PW_MIN_CLASSES	0x020000
+#define OVSEC_KADM_PW_HISTORY_NUM	0x040000
+#define OVSEC_KADM_REF_COUNT		0x080000
+
+/*
+ * permission bits
+ */
+#define OVSEC_KADM_PRIV_GET	0x01
+#define OVSEC_KADM_PRIV_ADD	0x02
+#define OVSEC_KADM_PRIV_MODIFY	0x04
+#define OVSEC_KADM_PRIV_DELETE	0x08
+
+/*
+ * API versioning constants
+ */
+#define OVSEC_KADM_MASK_BITS		0xffffff00
+
+#define OVSEC_KADM_STRUCT_VERSION_MASK	0x12345600
+#define OVSEC_KADM_STRUCT_VERSION_1	(OVSEC_KADM_STRUCT_VERSION_MASK|0x01)
+#define OVSEC_KADM_STRUCT_VERSION	OVSEC_KADM_STRUCT_VERSION_1
+
+#define OVSEC_KADM_API_VERSION_MASK	0x12345700
+#define OVSEC_KADM_API_VERSION_1	(OVSEC_KADM_API_VERSION_MASK|0x01)
+
+
+typedef struct _ovsec_kadm_principal_ent_t {
+	krb5_principal	principal;
+	krb5_timestamp	princ_expire_time;
+	krb5_timestamp	last_pwd_change;
+	krb5_timestamp	pw_expiration;
+	krb5_deltat	max_life;
+	krb5_principal	mod_name;
+	krb5_timestamp	mod_date;
+	krb5_flags	attributes;
+	krb5_kvno	kvno;
+	krb5_kvno	mkvno;
+	char		*policy;
+	long		aux_attributes;
+} ovsec_kadm_principal_ent_rec, *ovsec_kadm_principal_ent_t;
+
+typedef struct _ovsec_kadm_policy_ent_t {
+	char		*policy;
+	long		pw_min_life;
+	long		pw_max_life;
+	long		pw_min_length;
+	long		pw_min_classes;
+	long		pw_history_num;
+	long		policy_refcnt;
+} ovsec_kadm_policy_ent_rec, *ovsec_kadm_policy_ent_t;
+
+/*
+ * functions
+ */
+ovsec_kadm_ret_t    ovsec_kadm_init(char *client_name, char *pass,
+				    char *service_name, char *realm,
+				    krb5_ui_4 struct_version,
+				    krb5_ui_4 api_version,
+				    char **db_args,
+				    void **server_handle);
+ovsec_kadm_ret_t    ovsec_kadm_init_with_password(char *client_name,
+						  char *pass, 
+						  char *service_name,
+						  char *realm, 
+						  krb5_ui_4 struct_version,
+						  krb5_ui_4 api_version,
+						  char ** db_args,
+						  void **server_handle);
+ovsec_kadm_ret_t    ovsec_kadm_init_with_skey(char *client_name,
+					      char *keytab,
+					      char *service_name,
+					      char *realm,
+					      krb5_ui_4 struct_version,
+					      krb5_ui_4 api_version,
+					      char **db_args,
+					      void **server_handle);
+ovsec_kadm_ret_t    ovsec_kadm_flush(void *server_handle);
+ovsec_kadm_ret_t    ovsec_kadm_destroy(void *server_handle);
+ovsec_kadm_ret_t    ovsec_kadm_create_principal(void *server_handle,
+						ovsec_kadm_principal_ent_t ent,
+						long mask, char *pass);
+ovsec_kadm_ret_t    ovsec_kadm_delete_principal(void *server_handle,
+						krb5_principal principal);
+ovsec_kadm_ret_t    ovsec_kadm_modify_principal(void *server_handle,
+						ovsec_kadm_principal_ent_t ent,
+						long mask);
+ovsec_kadm_ret_t    ovsec_kadm_rename_principal(void *server_handle,
+						krb5_principal,krb5_principal);
+ovsec_kadm_ret_t    ovsec_kadm_get_principal(void *server_handle,
+					     krb5_principal principal,
+					     ovsec_kadm_principal_ent_t *ent);
+ovsec_kadm_ret_t    ovsec_kadm_chpass_principal(void *server_handle,
+						krb5_principal principal,
+						char *pass);
+ovsec_kadm_ret_t    ovsec_kadm_randkey_principal(void *server_handle,
+						 krb5_principal principal,
+						 krb5_keyblock **keyblock);
+ovsec_kadm_ret_t    ovsec_kadm_create_policy(void *server_handle,
+					     ovsec_kadm_policy_ent_t ent,
+					     long mask);
+/*
+ * ovsec_kadm_create_policy_internal is not part of the supported,
+ * exposed API.  It is available only in the server library, and you
+ * shouldn't use it unless you know why it's there and how it's
+ * different from ovsec_kadm_create_policy.
+ */
+ovsec_kadm_ret_t    ovsec_kadm_create_policy_internal(void *server_handle,
+						      ovsec_kadm_policy_ent_t
+						      entry, long mask);
+ovsec_kadm_ret_t    ovsec_kadm_delete_policy(void *server_handle,
+					     ovsec_kadm_policy_t policy);
+ovsec_kadm_ret_t    ovsec_kadm_modify_policy(void *server_handle,
+					     ovsec_kadm_policy_ent_t ent,
+					     long mask);
+/*
+ * ovsec_kadm_modify_policy_internal is not part of the supported,
+ * exposed API.  It is available only in the server library, and you
+ * shouldn't use it unless you know why it's there and how it's
+ * different from ovsec_kadm_modify_policy.
+ */
+ovsec_kadm_ret_t    ovsec_kadm_modify_policy_internal(void *server_handle,
+						      ovsec_kadm_policy_ent_t
+						      entry, long mask);
+ovsec_kadm_ret_t    ovsec_kadm_get_policy(void *server_handle,
+					  ovsec_kadm_policy_t policy,
+					  ovsec_kadm_policy_ent_t *ent);
+ovsec_kadm_ret_t    ovsec_kadm_get_privs(void *server_handle,
+					 long *privs);
+
+ovsec_kadm_ret_t    ovsec_kadm_chpass_principal_util(void *server_handle,
+						     krb5_principal princ,
+						     char *new_pw, 
+						     char **ret_pw,
+						     char *msg_ret);
+
+ovsec_kadm_ret_t    ovsec_kadm_free_principal_ent(void *server_handle,
+						  ovsec_kadm_principal_ent_t
+						  ent);
+ovsec_kadm_ret_t    ovsec_kadm_free_policy_ent(void *server_handle,
+					       ovsec_kadm_policy_ent_t ent);
+
+ovsec_kadm_ret_t ovsec_kadm_free_name_list(void *server_handle,
+					   char **names, int count);
+
+ovsec_kadm_ret_t    ovsec_kadm_get_principals(void *server_handle,
+					      char *exp, char ***princs,
+					      int *count);
+
+ovsec_kadm_ret_t    ovsec_kadm_get_policies(void *server_handle,
+					    char *exp, char ***pols,
+					    int *count);
+
+#define OVSEC_KADM_FAILURE KADM5_FAILURE
+#define OVSEC_KADM_AUTH_GET KADM5_AUTH_GET
+#define OVSEC_KADM_AUTH_ADD KADM5_AUTH_ADD
+#define OVSEC_KADM_AUTH_MODIFY KADM5_AUTH_MODIFY
+#define OVSEC_KADM_AUTH_DELETE KADM5_AUTH_DELETE
+#define OVSEC_KADM_AUTH_INSUFFICIENT KADM5_AUTH_INSUFFICIENT
+#define OVSEC_KADM_BAD_DB KADM5_BAD_DB
+#define OVSEC_KADM_DUP KADM5_DUP
+#define OVSEC_KADM_RPC_ERROR KADM5_RPC_ERROR
+#define OVSEC_KADM_NO_SRV KADM5_NO_SRV
+#define OVSEC_KADM_BAD_HIST_KEY KADM5_BAD_HIST_KEY
+#define OVSEC_KADM_NOT_INIT KADM5_NOT_INIT
+#define OVSEC_KADM_UNK_PRINC KADM5_UNK_PRINC
+#define OVSEC_KADM_UNK_POLICY KADM5_UNK_POLICY
+#define OVSEC_KADM_BAD_MASK KADM5_BAD_MASK
+#define OVSEC_KADM_BAD_CLASS KADM5_BAD_CLASS
+#define OVSEC_KADM_BAD_LENGTH KADM5_BAD_LENGTH
+#define OVSEC_KADM_BAD_POLICY KADM5_BAD_POLICY
+#define OVSEC_KADM_BAD_PRINCIPAL KADM5_BAD_PRINCIPAL
+#define OVSEC_KADM_BAD_AUX_ATTR KADM5_BAD_AUX_ATTR
+#define OVSEC_KADM_BAD_HISTORY KADM5_BAD_HISTORY
+#define OVSEC_KADM_BAD_MIN_PASS_LIFE KADM5_BAD_MIN_PASS_LIFE
+#define OVSEC_KADM_PASS_Q_TOOSHORT KADM5_PASS_Q_TOOSHORT
+#define OVSEC_KADM_PASS_Q_CLASS KADM5_PASS_Q_CLASS
+#define OVSEC_KADM_PASS_Q_DICT KADM5_PASS_Q_DICT
+#define OVSEC_KADM_PASS_REUSE KADM5_PASS_REUSE
+#define OVSEC_KADM_PASS_TOOSOON KADM5_PASS_TOOSOON
+#define OVSEC_KADM_POLICY_REF KADM5_POLICY_REF
+#define OVSEC_KADM_INIT KADM5_INIT
+#define OVSEC_KADM_BAD_PASSWORD KADM5_BAD_PASSWORD
+#define OVSEC_KADM_PROTECT_PRINCIPAL KADM5_PROTECT_PRINCIPAL
+#define OVSEC_KADM_BAD_SERVER_HANDLE KADM5_BAD_SERVER_HANDLE
+#define OVSEC_KADM_BAD_STRUCT_VERSION KADM5_BAD_STRUCT_VERSION
+#define OVSEC_KADM_OLD_STRUCT_VERSION KADM5_OLD_STRUCT_VERSION
+#define OVSEC_KADM_NEW_STRUCT_VERSION KADM5_NEW_STRUCT_VERSION
+#define OVSEC_KADM_BAD_API_VERSION KADM5_BAD_API_VERSION
+#define OVSEC_KADM_OLD_LIB_API_VERSION KADM5_OLD_LIB_API_VERSION
+#define OVSEC_KADM_OLD_SERVER_API_VERSION KADM5_OLD_SERVER_API_VERSION
+#define OVSEC_KADM_NEW_LIB_API_VERSION KADM5_NEW_LIB_API_VERSION
+#define OVSEC_KADM_NEW_SERVER_API_VERSION KADM5_NEW_SERVER_API_VERSION
+#define OVSEC_KADM_SECURE_PRINC_MISSING KADM5_SECURE_PRINC_MISSING
+#define OVSEC_KADM_NO_RENAME_SALT KADM5_NO_RENAME_SALT
+
+#endif /* USE_KADM5_API_VERSION == 1 */
+
+#endif /* __KADM5_ADMIN_H__ */
diff --git a/mechglue/src/lib/kadm5/admin_internal.h b/mechglue/src/lib/kadm5/admin_internal.h
new file mode 100644
index 000000000..6a9d31b0c
--- /dev/null
+++ b/mechglue/src/lib/kadm5/admin_internal.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ */
+
+#ifndef __KADM5_ADMIN_INTERNAL_H__
+#define __KADM5_ADMIN_INTERNAL_H__
+
+#include <kadm5/admin.h>
+
+#define KADM5_SERVER_HANDLE_MAGIC	0x12345800
+
+#define GENERIC_CHECK_HANDLE(handle, old_api_version, new_api_version) \
+{ \
+	kadm5_server_handle_t srvr = \
+	     (kadm5_server_handle_t) handle; \
+ \
+	if (! srvr) \
+		return KADM5_BAD_SERVER_HANDLE; \
+	if (srvr->magic_number != KADM5_SERVER_HANDLE_MAGIC) \
+		return KADM5_BAD_SERVER_HANDLE; \
+	if ((srvr->struct_version & KADM5_MASK_BITS) != \
+	    KADM5_STRUCT_VERSION_MASK) \
+		return KADM5_BAD_STRUCT_VERSION; \
+	if (srvr->struct_version < KADM5_STRUCT_VERSION_1) \
+		return KADM5_OLD_STRUCT_VERSION; \
+	if (srvr->struct_version > KADM5_STRUCT_VERSION_1) \
+		return KADM5_NEW_STRUCT_VERSION; \
+	if ((srvr->api_version & KADM5_MASK_BITS) != \
+	    KADM5_API_VERSION_MASK) \
+		return KADM5_BAD_API_VERSION; \
+	if (srvr->api_version < KADM5_API_VERSION_1) \
+		return old_api_version; \
+	if (srvr->api_version > KADM5_API_VERSION_2) \
+		return new_api_version; \
+}
+
+/*
+ * _KADM5_CHECK_HANDLE calls the function _kadm5_check_handle and
+ * returns any non-zero error code that function returns.
+ * _kadm5_check_handle, in client_handle.c and server_handle.c, exists
+ * in both the server- and client- side libraries.  In each library,
+ * it calls CHECK_HANDLE, which is defined by the appropriate
+ * _internal.h header file to call GENERIC_CHECK_HANDLE as well as
+ * CLIENT_CHECK_HANDLE and SERVER_CHECK_HANDLE.
+ *
+ * _KADM5_CHECK_HANDLE should be used by a function that needs to
+ * check the handle but wants to be the same code in both the client
+ * and server library; it makes a function call to the right handle
+ * checker.  Code that only exists in one library can call the
+ * CHECK_HANDLE macro, which inlines the test instead of making
+ * another function call.
+ *
+ * Got that?
+ */
+#define _KADM5_CHECK_HANDLE(handle) \
+{ int ecode; if ((ecode = _kadm5_check_handle((void *)handle))) return ecode;}
+
+int         _kadm5_check_handle(void *handle);
+kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle,
+					 void *lhandle,
+					 krb5_principal princ,
+					 char *new_pw, 
+					 char **ret_pw,
+					 char *msg_ret,
+					 unsigned int msg_len);
+
+/* this is needed by the alt_prof code I stole.  The functions
+   maybe shouldn't be named krb5_*, but they are. */
+
+krb5_error_code
+krb5_string_to_keysalts(char *string, const char *tupleseps,
+			const char *ksaltseps, krb5_boolean dups,
+			krb5_key_salt_tuple **ksaltp, krb5_int32 *nksaltp);
+
+krb5_error_code
+krb5_string_to_flags(char* string, const char* positive, const char* negative,
+		     krb5_flags *flagsp);
+
+#endif /* __KADM5_ADMIN_INTERNAL_H__ */
diff --git a/mechglue/src/lib/kadm5/admin_xdr.h b/mechglue/src/lib/kadm5/admin_xdr.h
new file mode 100644
index 000000000..05d1a7ea6
--- /dev/null
+++ b/mechglue/src/lib/kadm5/admin_xdr.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ * 
+ */
+
+#include    <kadm5/admin.h>
+#include    "kadm_rpc.h"
+#include    "server_internal.h"
+
+bool_t      xdr_ui_4(XDR *xdrs, krb5_ui_4 *objp);
+bool_t	    xdr_nullstring(XDR *xdrs, char **objp);
+bool_t      xdr_nulltype(XDR *xdrs, void **objp, xdrproc_t proc);
+bool_t	    xdr_krb5_timestamp(XDR *xdrs, krb5_timestamp *objp);
+bool_t	    xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp);
+bool_t	    xdr_krb5_deltat(XDR *xdrs, krb5_deltat *objp);
+bool_t	    xdr_krb5_flags(XDR *xdrs, krb5_flags *objp);
+bool_t      xdr_krb5_ui_4(XDR *xdrs, krb5_ui_4 *objp);
+bool_t      xdr_krb5_int16(XDR *xdrs, krb5_int16 *objp);
+bool_t      xdr_krb5_ui_2(XDR *xdrs, krb5_ui_2 *objp);
+bool_t      xdr_krb5_key_data_nocontents(XDR *xdrs, krb5_key_data *objp);
+bool_t      xdr_krb5_key_salt_tuple(XDR *xdrs, krb5_key_salt_tuple *objp);
+bool_t      xdr_krb5_tl_data(XDR *xdrs, krb5_tl_data **tl_data_head);
+bool_t	    xdr_kadm5_ret_t(XDR *xdrs, kadm5_ret_t *objp);
+bool_t      xdr_kadm5_principal_ent_rec_v1(XDR *xdrs, kadm5_principal_ent_rec *objp);
+bool_t	    xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp);
+bool_t	    xdr_kadm5_policy_ent_rec(XDR *xdrs, kadm5_policy_ent_rec *objp);
+bool_t	    xdr_kadm5_policy_ent_t(XDR *xdrs, kadm5_policy_ent_t *objp);
+bool_t	    xdr_kadm5_principal_ent_t(XDR *xdrs, kadm5_principal_ent_t *objp);
+bool_t	    xdr_cprinc_arg(XDR *xdrs, cprinc_arg *objp);
+bool_t      xdr_cprinc3_arg(XDR *xdrs, cprinc3_arg *objp);
+bool_t      xdr_generic_ret(XDR *xdrs, generic_ret *objp);
+bool_t	    xdr_dprinc_arg(XDR *xdrs, dprinc_arg *objp);
+bool_t	    xdr_mprinc_arg(XDR *xdrs, mprinc_arg *objp);
+bool_t	    xdr_rprinc_arg(XDR *xdrs, rprinc_arg *objp);
+bool_t	    xdr_chpass_arg(XDR *xdrs, chpass_arg *objp);
+bool_t      xdr_chpass3_arg(XDR *xdrs, chpass3_arg *objp);
+bool_t      xdr_setv4key_arg(XDR *xdrs, setv4key_arg *objp);
+bool_t      xdr_setkey_arg(XDR *xdrs, setkey_arg *objp);
+bool_t      xdr_setkey3_arg(XDR *xdrs, setkey3_arg *objp);
+bool_t	    xdr_chrand_arg(XDR *xdrs, chrand_arg *objp);
+bool_t      xdr_chrand3_arg(XDR *xdrs, chrand3_arg *objp);
+bool_t	    xdr_chrand_ret(XDR *xdrs, chrand_ret *objp);
+bool_t	    xdr_gprinc_arg(XDR *xdrs, gprinc_arg *objp);
+bool_t      xdr_gprinc_ret(XDR *xdrs, gprinc_ret *objp);
+bool_t	    xdr_gprincs_arg(XDR *xdrs, gprincs_arg *objp);
+bool_t      xdr_gprincs_ret(XDR *xdrs, gprincs_ret *objp);
+bool_t	    xdr_cpol_arg(XDR *xdrs, cpol_arg *objp);
+bool_t	    xdr_dpol_arg(XDR *xdrs, dpol_arg *objp);
+bool_t	    xdr_mpol_arg(XDR *xdrs, mpol_arg *objp);
+bool_t	    xdr_gpol_arg(XDR *xdrs, gpol_arg *objp);
+bool_t	    xdr_gpol_ret(XDR *xdrs, gpol_ret *objp);
+bool_t      xdr_gpols_arg(XDR *xdrs, gpols_arg *objp);
+bool_t      xdr_gpols_ret(XDR *xdrs, gpols_ret *objp);
+bool_t      xdr_getprivs_ret(XDR *xdrs, getprivs_ret *objp);
+bool_t	    xdr_krb5_principal(XDR *xdrs, krb5_principal *objp);
+bool_t	    xdr_krb5_octet(XDR *xdrs, krb5_octet *objp);
+bool_t	    xdr_krb5_int32(XDR *xdrs, krb5_int32 *objp);
+bool_t	    xdr_krb5_enctype(XDR *xdrs, krb5_enctype *objp);
+bool_t      xdr_krb5_salttype(XDR *xdrs, krb5_int32 *objp);
+bool_t	    xdr_krb5_keyblock(XDR *xdrs, krb5_keyblock *objp);
+bool_t      xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp);
+bool_t      xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp);
diff --git a/mechglue/src/lib/kadm5/alt_prof.c b/mechglue/src/lib/kadm5/alt_prof.c
new file mode 100644
index 000000000..bb87f8881
--- /dev/null
+++ b/mechglue/src/lib/kadm5/alt_prof.c
@@ -0,0 +1,1026 @@
+/*
+ * lib/kadm/alt_prof.c
+ *
+ * Copyright 1995,2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * alt_prof.c - Implement alternate profile file handling.
+ */
+#include "k5-int.h"
+#include <kadm5/admin.h>
+#include "adm_proto.h"
+#include <stdio.h>
+#include <ctype.h>
+
+static krb5_key_salt_tuple *copy_key_salt_tuple(ksalt, len)
+krb5_key_salt_tuple *ksalt;
+krb5_int32 len;
+{
+    krb5_key_salt_tuple *knew;    
+
+    if((knew = (krb5_key_salt_tuple *)
+		malloc((len ) * sizeof(krb5_key_salt_tuple)))) {
+         memcpy(knew, ksalt, len * sizeof(krb5_key_salt_tuple));
+	 return knew;
+    }
+    return 0;
+}
+
+/*
+ * krb5_aprof_init()	- Initialize alternate profile context.
+ *
+ * Parameters:
+ *	fname		- default file name of the profile.
+ *	envname		- environment variable name which can override fname.
+ *	acontextp	- Pointer to opaque context for alternate profile.
+ *
+ * Returns:
+ *	error codes from profile_init()
+ */
+krb5_error_code
+krb5_aprof_init(fname, envname, acontextp)
+    char		*fname;
+    char		*envname;
+    krb5_pointer	*acontextp;
+{
+    krb5_error_code	kret;
+    const_profile_filespec_t 	namelist[2];
+    profile_t		profile;
+    
+    namelist[1] = (profile_filespec_t) NULL;
+    profile = (profile_t) NULL;
+    if (envname) {
+	if ((namelist[0] = getenv(envname))) {
+	    kret = profile_init(namelist, &profile);
+	    if (kret)
+		return kret;
+	    *acontextp = (krb5_pointer) profile;
+	    return 0;
+	}
+    }
+    profile = (profile_t) NULL;
+    if (fname) {
+	kret = profile_init_path(fname, &profile);
+	if (kret == ENOENT) {
+	    profile = 0;
+	} else if (kret)
+	    return kret;
+	*acontextp = (krb5_pointer) profile;
+	return 0;
+    }
+    return 0;
+}
+
+/*
+ * krb5_aprof_getvals()	- Get values from alternate profile.
+ *
+ * Parameters:
+ *	acontext	- opaque context for alternate profile.
+ *	hierarchy	- hierarchy of value to retrieve.
+ *	retdata		- Returned data values.
+ *
+ * Returns:
+ * 	error codes from profile_get_values()
+ */
+krb5_error_code
+krb5_aprof_getvals(acontext, hierarchy, retdata)
+    krb5_pointer	acontext;
+    const char		**hierarchy;
+    char		***retdata;
+{
+    return(profile_get_values((profile_t) acontext,
+			      hierarchy,
+			      retdata));
+}
+
+/*
+ * krb5_aprof_get_boolean()
+ *
+ * Parameters:
+ *	acontext	- opaque context for alternate profile
+ *	hierarchy	- hierarchy of value to retrieve
+ *	retdata		- Returned data value
+ * Returns:
+ *	error codes
+ */
+
+static krb5_error_code
+string_to_boolean (const char *string, krb5_boolean *out)
+{
+    static const char *const yes[] = { "y", "yes", "true", "t", "1", "on" };
+    static const char *const no[] = { "n", "no", "false", "f", "nil", "0", "off" };
+    int i;
+
+    for (i = 0; i < sizeof(yes)/sizeof(yes[0]); i++)
+	if (!strcasecmp(string, yes[i])) {
+	    *out = 1;
+	    return 0;
+	}
+    for (i = 0; i < sizeof(no)/sizeof(no[0]); i++)
+	if (!strcasecmp(string, no[i])) {
+	    *out = 0;
+	    return 0;
+	}
+    return PROF_BAD_BOOLEAN;
+}
+
+krb5_error_code
+krb5_aprof_get_boolean(krb5_pointer acontext, const char **hierarchy,
+		       int uselast, krb5_boolean *retdata)
+{
+    krb5_error_code kret;
+    char **values;
+    char *valp;
+    int idx;
+    krb5_boolean val;
+
+    kret = krb5_aprof_getvals (acontext, hierarchy, &values);
+    if (kret)
+	return kret;
+    idx = 0;
+    if (uselast) {
+	while (values[idx])
+	    idx++;
+	idx--;
+    }
+    valp = values[idx];
+    kret = string_to_boolean (valp, &val);
+    if (kret)
+	return kret;
+    *retdata = val;
+    return 0;
+}
+
+/*
+ * krb5_aprof_get_deltat()	- Get a delta time value from the alternate
+ *				  profile.
+ *
+ * Parameters:
+ *	acontext		- opaque context for alternate profile.
+ *	hierarchy		- hierarchy of value to retrieve.
+ *	uselast			- if true, use last value, otherwise use
+ *				  first value found.
+ *	deltatp			- returned delta time value.
+ *
+ * Returns:
+ * 	error codes from profile_get_values()
+ *	error codes from krb5_string_to_deltat()
+ */
+krb5_error_code
+krb5_aprof_get_deltat(acontext, hierarchy, uselast, deltatp)
+    krb5_pointer	acontext;
+    const char		**hierarchy;
+    krb5_boolean	uselast;
+    krb5_deltat		*deltatp;
+{
+    krb5_error_code	kret;
+    char		**values;
+    char		*valp;
+    int			idx;
+
+    if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+	idx = 0;
+	if (uselast) {
+	    for (idx=0; values[idx]; idx++);
+	    idx--;
+	}
+	valp = values[idx];
+	kret = krb5_string_to_deltat(valp, deltatp);
+
+	/* Free the string storage */
+	for (idx=0; values[idx]; idx++)
+	    krb5_xfree(values[idx]);
+	krb5_xfree(values);
+    }
+    return(kret);
+}
+
+/*
+ * krb5_aprof_get_string()	- Get a string value from the alternate
+ *				  profile.
+ *
+ * Parameters:
+ *	acontext		- opaque context for alternate profile.
+ *	hierarchy		- hierarchy of value to retrieve.
+ *	uselast			- if true, use last value, otherwise use
+ *				  first value found.
+ *	stringp			- returned string value.
+ *
+ * Returns:
+ * 	error codes from profile_get_values()
+ */
+krb5_error_code
+krb5_aprof_get_string(acontext, hierarchy, uselast, stringp)
+    krb5_pointer	acontext;
+    const char		**hierarchy;
+    krb5_boolean	uselast;
+    char		**stringp;
+{
+    krb5_error_code	kret;
+    char		**values;
+    int			idx, i;
+
+    if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+	idx = 0;
+	if (uselast) {
+	    for (idx=0; values[idx]; idx++);
+	    idx--;
+	}
+
+	*stringp = values[idx];
+
+	/* Free the string storage */
+	for (i=0; values[i]; i++)
+	    if (i != idx)
+		krb5_xfree(values[i]);
+	krb5_xfree(values);
+    }
+    return(kret);
+}
+
+/*
+ * krb5_aprof_get_int32()	- Get a 32-bit integer value from the alternate
+ *				  profile.
+ *
+ * Parameters:
+ *	acontext		- opaque context for alternate profile.
+ *	hierarchy		- hierarchy of value to retrieve.
+ *	uselast			- if true, use last value, otherwise use
+ *				  first value found.
+ *	intp			- returned 32-bit integer value.
+ *
+ * Returns:
+ * 	error codes from profile_get_values()
+ *	EINVAL			- value is not an integer
+ */
+krb5_error_code
+krb5_aprof_get_int32(acontext, hierarchy, uselast, intp)
+    krb5_pointer	acontext;
+    const char		**hierarchy;
+    krb5_boolean	uselast;
+    krb5_int32		*intp;
+{
+    krb5_error_code	kret;
+    char		**values;
+    int			idx;
+
+    if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
+	idx = 0;
+	if (uselast) {
+	    for (idx=0; values[idx]; idx++);
+	    idx--;
+	}
+
+	if (sscanf(values[idx], "%d", intp) != 1)
+	    kret = EINVAL;
+
+	/* Free the string storage */
+	for (idx=0; values[idx]; idx++)
+	    krb5_xfree(values[idx]);
+	krb5_xfree(values);
+    }
+    return(kret);
+}
+
+/*
+ * krb5_aprof_finish()	- Finish alternate profile context.
+ *
+ * Parameter:
+ *	acontext	- opaque context for alternate profile.
+ *
+ * Returns:
+ *	0 on success, something else on failure.
+ */
+krb5_error_code
+krb5_aprof_finish(acontext)
+    krb5_pointer	acontext;
+{
+    profile_release(acontext);
+    return(0);
+}
+
+/*
+ * Function: kadm5_get_config_params
+ *
+ * Purpose: Merge configuration parameters provided by the caller with
+ * values specified in configuration files and with default values.
+ *
+ * Arguments:
+ *
+ *	context		(r) krb5_context to use
+ *	profile		(r) profile file to use
+ *	envname		(r) envname that contains a profile name to
+ *			override profile
+ *	params_in	(r) params structure containing user-supplied
+ *			values, or NULL
+ *	params_out	(w) params structure to be filled in
+ *
+ * Effects:
+ *
+ * The fields and mask of params_out are filled in with values
+ * obtained from params_in, the specified profile, and default
+ * values.  Only and all fields specified in params_out->mask are
+ * set.  The context of params_out must be freed with
+ * kadm5_free_config_params.
+ *
+ * params_in and params_out may be the same pointer.  However, all pointers
+ * in params_in for which the mask is set will be re-assigned to newly copied
+ * versions, overwriting the old pointer value.
+ */
+krb5_error_code kadm5_get_config_params(context, kdcprofile, kdcenv,
+					params_in, params_out)
+   krb5_context		context;
+   char			*kdcprofile;
+   char			*kdcenv;
+   kadm5_config_params	*params_in, *params_out;
+{
+    char		*filename;
+    char		*envname;
+    char		*lrealm;
+    krb5_pointer	aprofile = 0;
+    const char		*hierarchy[4];
+    char		*svalue;
+    krb5_int32		ivalue;
+    krb5_deltat		dtvalue;
+    kadm5_config_params params, empty_params;
+
+    krb5_error_code	kret = 0;
+
+    memset((char *) ¶ms, 0, sizeof(params));
+    memset((char *) &empty_params, 0, sizeof(empty_params));
+
+    if (params_in == NULL) params_in = &empty_params;
+
+    if (params_in->mask & KADM5_CONFIG_REALM) {
+	 lrealm = params.realm = strdup(params_in->realm);
+	 if (params.realm)
+	      params.mask |= KADM5_CONFIG_REALM;
+    } else {
+	 kret = krb5_get_default_realm(context, &lrealm);
+	 if (kret)
+	      goto cleanup;
+	 params.realm = lrealm;
+	 params.mask |= KADM5_CONFIG_REALM;
+    }
+    if (params_in->mask & KADM5_CONFIG_PROFILE) {
+	 filename = params.profile = strdup(params_in->profile);
+	 if (params.profile)
+	      params.mask |= KADM5_CONFIG_PROFILE;
+	 envname = NULL;
+    } else {
+	 /*
+	  * XXX These defaults should to work on both client and
+	  * server.  kadm5_get_config_params can be implemented as a
+	  * wrapper function in each library that provides correct
+	  * defaults for NULL values.
+	  */
+	 filename = (kdcprofile) ? kdcprofile : DEFAULT_KDC_PROFILE;
+	 envname = (kdcenv) ? kdcenv : KDC_PROFILE_ENV;
+	 if (context->profile_secure == TRUE) envname = 0;
+    }
+
+    kret = krb5_aprof_init(filename, envname, &aprofile);
+    if (kret)
+	    goto cleanup;
+    
+    /* Initialize realm parameters */
+    hierarchy[0] = "realms";
+    hierarchy[1] = lrealm;
+    hierarchy[3] = (char *) NULL;
+
+    /* Get the value for the admin server */
+    hierarchy[2] = "admin_server";
+    if (params_in->mask & KADM5_CONFIG_ADMIN_SERVER) {
+	 params.admin_server = strdup(params_in->admin_server);
+	 if (params.admin_server)
+	      params.mask |= KADM5_CONFIG_ADMIN_SERVER;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 params.admin_server = svalue;
+	 params.mask |= KADM5_CONFIG_ADMIN_SERVER;
+    }
+    if (params.mask & KADM5_CONFIG_ADMIN_SERVER) {
+	 char *p;
+	 p = strchr(params.admin_server, ':');
+	 if (p) {
+	      params.kadmind_port = atoi(p+1);
+	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
+	      *p = '\0';
+	 }
+    }
+
+    /* Get the value for the database */
+    hierarchy[2] = "database_name";
+    if (params_in->mask & KADM5_CONFIG_DBNAME) {
+	 params.dbname = strdup(params_in->dbname);
+	 if (params.dbname)
+	      params.mask |= KADM5_CONFIG_DBNAME;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 params.dbname = svalue;
+	 params.mask |= KADM5_CONFIG_DBNAME;
+    } else {
+	 params.dbname = strdup(DEFAULT_KDB_FILE);
+	 if (params.dbname) 
+	      params.mask |= KADM5_CONFIG_DBNAME;
+    }
+
+    /*
+     * admin database name and lockfile are now always derived from dbname
+     */
+    if (params.mask & KADM5_CONFIG_DBNAME) {
+	 params.admin_dbname = (char *) malloc(strlen(params.dbname) + 7);
+	 if (params.admin_dbname) {
+	      sprintf(params.admin_dbname, "%s.kadm5", params.dbname);
+	      params.mask |= KADM5_CONFIG_ADBNAME;
+	 }
+    }
+
+    if (params.mask & KADM5_CONFIG_ADBNAME) {
+	 params.admin_lockfile = (char *) malloc(strlen(params.admin_dbname)
+						 + 6);
+	 if (params.admin_lockfile) {
+	      sprintf(params.admin_lockfile, "%s.lock", params.admin_dbname);
+	      params.mask |= KADM5_CONFIG_ADB_LOCKFILE;
+	 }
+    }
+    
+    /* Get the value for the admin (policy) database lock file*/
+    hierarchy[2] = "admin_keytab";
+    if (params_in->mask & KADM5_CONFIG_ADMIN_KEYTAB) {
+	 params.admin_keytab = strdup(params_in->admin_keytab);
+	 if (params.admin_keytab)
+	      params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
+	 params.admin_keytab = svalue;
+    } else if ((params.admin_keytab = (char *) getenv("KRB5_KTNAME"))) {
+	 params.admin_keytab = strdup(params.admin_keytab);
+	 if (params.admin_keytab)
+	      params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
+    } else {
+	 params.admin_keytab = strdup(DEFAULT_KADM5_KEYTAB);
+	 if (params.admin_keytab)
+	      params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
+    }
+    
+    /* Get the name of the acl file */
+    hierarchy[2] = "acl_file";
+    if (params_in->mask & KADM5_CONFIG_ACL_FILE) {
+	 params.acl_file = strdup(params_in->acl_file);
+	 if (params.acl_file)
+	      params.mask |= KADM5_CONFIG_ACL_FILE;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 params.mask |= KADM5_CONFIG_ACL_FILE;
+	 params.acl_file = svalue;
+    } else {
+	 params.acl_file = strdup(DEFAULT_KADM5_ACL_FILE);
+	 if (params.acl_file)
+	      params.mask |= KADM5_CONFIG_ACL_FILE;
+    }
+    
+    /* Get the name of the dict file */
+    hierarchy[2] = "dict_file";
+    if (params_in->mask & KADM5_CONFIG_DICT_FILE) {
+	 params.dict_file = strdup(params_in->dict_file);
+	 if (params.dict_file)
+	      params.mask |= KADM5_CONFIG_DICT_FILE;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 params.mask |= KADM5_CONFIG_DICT_FILE;
+	 params.dict_file = svalue;
+    }
+	    
+    /* Get the value for the kadmind port */
+    if (! (params.mask & KADM5_CONFIG_KADMIND_PORT)) {
+	 hierarchy[2] = "kadmind_port";
+	 if (params_in->mask & KADM5_CONFIG_KADMIND_PORT) {
+	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
+	      params.kadmind_port = params_in->kadmind_port;
+	 } else if (aprofile &&
+		    !krb5_aprof_get_int32(aprofile, hierarchy, TRUE,
+					  &ivalue)) { 
+	      params.kadmind_port = ivalue;
+	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
+	 } else {
+	      params.kadmind_port = DEFAULT_KADM5_PORT;
+	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
+	 }
+    }
+    
+    /* Get the value for the kpasswd port */
+    if (! (params.mask & KADM5_CONFIG_KPASSWD_PORT)) {
+	hierarchy[2] = "kpasswd_port";
+	if (params_in->mask & KADM5_CONFIG_KPASSWD_PORT) {
+	    params.mask |= KADM5_CONFIG_KPASSWD_PORT;
+	    params.kpasswd_port = params_in->kpasswd_port;
+	} else if (aprofile &&
+		   !krb5_aprof_get_int32(aprofile, hierarchy, TRUE,
+					 &ivalue)) { 
+	    params.kpasswd_port = ivalue;
+	    params.mask |= KADM5_CONFIG_KPASSWD_PORT;
+	} else {
+	    params.kpasswd_port = DEFAULT_KPASSWD_PORT;
+	    params.mask |= KADM5_CONFIG_KPASSWD_PORT;
+	}
+    }
+    
+    /* Get the value for the master key name */
+	 hierarchy[2] = "master_key_name";
+    if (params_in->mask & KADM5_CONFIG_MKEY_NAME) {
+	 params.mkey_name = strdup(params_in->mkey_name);
+	 if (params.mkey_name)
+	      params.mask |= KADM5_CONFIG_MKEY_NAME;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 params.mask |= KADM5_CONFIG_MKEY_NAME;
+	 params.mkey_name = svalue;
+    }
+    
+    /* Get the value for the master key type */
+    hierarchy[2] = "master_key_type";
+    if (params_in->mask & KADM5_CONFIG_ENCTYPE) {
+	 params.mask |= KADM5_CONFIG_ENCTYPE;
+	 params.enctype = params_in->enctype;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 if (!krb5_string_to_enctype(svalue, ¶ms.enctype)) {
+	      params.mask |= KADM5_CONFIG_ENCTYPE;
+	      krb5_xfree(svalue);
+	 }
+    } else {
+	 params.mask |= KADM5_CONFIG_ENCTYPE;
+	 params.enctype = DEFAULT_KDC_ENCTYPE;
+    }
+    
+    /* Get the value for mkey_from_kbd */
+    if (params_in->mask & KADM5_CONFIG_MKEY_FROM_KBD) {
+	 params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+	 params.mkey_from_kbd = params_in->mkey_from_kbd;
+    }
+    
+    /* Get the value for the stashfile */
+    hierarchy[2] = "key_stash_file";
+    if (params_in->mask & KADM5_CONFIG_STASH_FILE) {
+	 params.stash_file = strdup(params_in->stash_file);
+	 if (params.stash_file)
+	      params.mask |= KADM5_CONFIG_STASH_FILE;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 params.mask |= KADM5_CONFIG_STASH_FILE;
+	 params.stash_file = svalue;
+    }
+    
+    /* Get the value for maximum ticket lifetime. */
+    hierarchy[2] = "max_life";
+    if (params_in->mask & KADM5_CONFIG_MAX_LIFE) {
+	 params.mask |= KADM5_CONFIG_MAX_LIFE;
+	 params.max_life = params_in->max_life;
+    } else if (aprofile &&
+	       !krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
+	 params.max_life = dtvalue;
+	 params.mask |= KADM5_CONFIG_MAX_LIFE;
+    } else {
+	 params.max_life = 24 * 60 * 60; /* 1 day */
+	 params.mask |= KADM5_CONFIG_MAX_LIFE;
+    }	 
+	    
+    /* Get the value for maximum renewable ticket lifetime. */
+    hierarchy[2] = "max_renewable_life";
+    if (params_in->mask & KADM5_CONFIG_MAX_RLIFE) {
+	 params.mask |= KADM5_CONFIG_MAX_RLIFE;
+	 params.max_rlife = params_in->max_rlife;
+    } else if (aprofile &&
+	       !krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
+	 params.max_rlife = dtvalue;
+	 params.mask |= KADM5_CONFIG_MAX_RLIFE;
+    } else {
+	 params.max_rlife = 0;
+	 params.mask |= KADM5_CONFIG_MAX_RLIFE;
+    }
+	    
+    /* Get the value for the default principal expiration */
+    hierarchy[2] = "default_principal_expiration";
+    if (params_in->mask & KADM5_CONFIG_EXPIRATION) {
+	 params.mask |= KADM5_CONFIG_EXPIRATION;
+	 params.expiration = params_in->expiration;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 if (!krb5_string_to_timestamp(svalue, ¶ms.expiration)) {
+	      params.mask |= KADM5_CONFIG_EXPIRATION;
+	      krb5_xfree(svalue);
+	 }
+    } else {
+	 params.mask |= KADM5_CONFIG_EXPIRATION;
+	 params.expiration = 0;
+    }
+    
+    /* Get the value for the default principal flags */
+    hierarchy[2] = "default_principal_flags";
+    if (params_in->mask & KADM5_CONFIG_FLAGS) {
+	 params.mask |= KADM5_CONFIG_FLAGS;
+	 params.flags = params_in->flags;
+    } else if (aprofile &&
+	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	 char *sp, *ep, *tp;
+	 
+	 sp = svalue;
+	 params.flags = 0;
+	 while (sp) {
+	      if ((ep = strchr(sp, (int) ',')) ||
+		  (ep = strchr(sp, (int) ' ')) ||
+		  (ep = strchr(sp, (int) '\t'))) {
+		   /* Fill in trailing whitespace of sp */
+		   tp = ep - 1;
+		   while (isspace((int) *tp) && (tp > sp)) {
+			*tp = '\0';
+			tp--;
+		   }
+		   *ep = '\0';
+		   ep++;
+		   /* Skip over trailing whitespace of ep */
+		   while (isspace((int) *ep) && (*ep)) ep++;
+	      }
+	      /* Convert this flag */
+	      if (krb5_string_to_flags(sp,
+				       "+",
+				       "-",
+				       ¶ms.flags))
+		   break;
+	      sp = ep;
+	 }
+	 if (!sp)
+	      params.mask |= KADM5_CONFIG_FLAGS;
+	 krb5_xfree(svalue);
+    } else {
+	 params.mask |= KADM5_CONFIG_FLAGS;
+	 params.flags = KRB5_KDB_DEF_FLAGS;
+    }
+
+    /* Get the value for the supported enctype/salttype matrix */
+    hierarchy[2] = "supported_enctypes";
+    if (params_in->mask & KADM5_CONFIG_ENCTYPES) {
+         /* The following scenario is when the input keysalts are !NULL */
+         if(params_in->keysalts) {
+	       params.keysalts = copy_key_salt_tuple(params_in->keysalts, 
+						     params_in->num_keysalts);
+	       if(params.keysalts) {
+		 params.mask |= KADM5_CONFIG_ENCTYPES;
+		 params.num_keysalts = params_in->num_keysalts;
+	       }
+	 } else {
+		 params.mask |= KADM5_CONFIG_ENCTYPES;
+		 params.keysalts = 0;
+		 params.num_keysalts = params_in->num_keysalts;
+	 }
+    } else {
+	 svalue = NULL;
+	 if (aprofile)
+	      krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue);
+	 if (svalue == NULL)
+	     svalue = strdup("des3-hmac-sha1:normal des-cbc-crc:normal");
+
+	 params.keysalts = NULL;
+	 params.num_keysalts = 0;
+	 krb5_string_to_keysalts(svalue,
+				 ", \t",/* Tuple separators	*/
+				 ":.-",	/* Key/salt separators	*/
+				 0,	/* No duplicates	*/
+				 ¶ms.keysalts,
+				 ¶ms.num_keysalts);
+	 if (params.num_keysalts)
+	      params.mask |= KADM5_CONFIG_ENCTYPES;
+
+	 if (svalue)
+	      krb5_xfree(svalue);
+    }
+    
+    *params_out = params;
+    
+cleanup:
+    if (aprofile)
+	krb5_aprof_finish(aprofile);
+    if (kret) {
+	 kadm5_free_config_params(context, ¶ms);
+	 params_out->mask = 0;
+    }
+    return(kret);
+}
+/*
+ * kadm5_free_config_params()	- Free data allocated by above.
+ */
+krb5_error_code
+kadm5_free_config_params(context, params)
+    krb5_context	context;
+    kadm5_config_params	*params;
+{
+    if (params) {
+	if (params->profile)
+	    krb5_xfree(params->profile);
+	if (params->dbname)
+	    krb5_xfree(params->dbname);
+	if (params->mkey_name)
+	    krb5_xfree(params->mkey_name);
+	if (params->stash_file)
+	    krb5_xfree(params->stash_file);
+	if (params->keysalts)
+	    krb5_xfree(params->keysalts);
+	if (params->admin_server)
+	     free(params->admin_server);
+	if (params->admin_keytab)
+	     free(params->admin_keytab);
+	if (params->dict_file)
+	     free(params->dict_file);
+	if (params->acl_file)
+	     free(params->acl_file);
+	if (params->realm)
+	     free(params->realm);
+	if (params->admin_dbname)
+	     free(params->admin_dbname);
+	if (params->admin_lockfile)
+	     free(params->admin_lockfile);
+
+    }
+    return(0);
+}
+
+krb5_error_code
+kadm5_get_admin_service_name(krb5_context ctx,
+			     char *realm_in,
+			     char *admin_name,
+			     size_t maxlen)
+{
+    krb5_error_code ret;
+    kadm5_config_params params_in, params_out;
+    struct hostent *hp;
+
+    memset(¶ms_in, 0, sizeof(params_in));
+    memset(¶ms_out, 0, sizeof(params_out));
+
+    params_in.mask |= KADM5_CONFIG_REALM;
+    params_in.realm = realm_in;
+    ret = kadm5_get_config_params(ctx, DEFAULT_PROFILE_PATH,
+				  "KRB5_CONFIG", ¶ms_in, ¶ms_out);
+    if (ret)
+	return ret;
+
+    if (!(params_out.mask & KADM5_CONFIG_ADMIN_SERVER)) {
+	ret = KADM5_MISSING_KRB5_CONF_PARAMS;
+	goto err_params;
+    }
+
+    hp = gethostbyname(params_out.admin_server);
+    if (hp == NULL) {
+	ret = errno;
+	goto err_params;
+    }
+    if (strlen(hp->h_name) + sizeof("kadmin/") > maxlen) {
+	ret = ENOMEM;
+	goto err_params;
+    }
+    sprintf(admin_name, "kadmin/%s", hp->h_name);
+
+err_params:
+    kadm5_free_config_params(ctx, ¶ms_out);
+    return ret;
+}
+
+/***********************************************************************
+ * This is the old krb5_realm_read_params, which I mutated into
+ * kadm5_get_config_params but which old code (kdb5_* and krb5kdc)
+ * still uses.
+ ***********************************************************************/
+
+/*
+ * krb5_read_realm_params()	- Read per-realm parameters from KDC
+ *				  alternate profile.
+ */
+krb5_error_code
+krb5_read_realm_params(kcontext, realm, kdcprofile, kdcenv, rparamp)
+    krb5_context	kcontext;
+    char		*realm;
+    char		*kdcprofile;
+    char		*kdcenv;
+    krb5_realm_params	**rparamp;
+{
+    char		*filename;
+    char		*envname;
+    char		*lrealm;
+    krb5_pointer	aprofile = 0;
+    krb5_realm_params	*rparams;
+    const char		*hierarchy[4];
+    char		*svalue;
+    krb5_int32		ivalue;
+    krb5_boolean	bvalue;
+    krb5_deltat		dtvalue;
+
+    krb5_error_code	kret;
+
+    filename = (kdcprofile) ? kdcprofile : DEFAULT_KDC_PROFILE;
+    envname = (kdcenv) ? kdcenv : KDC_PROFILE_ENV;
+
+    if (kcontext->profile_secure == TRUE) envname = 0;
+
+    rparams = (krb5_realm_params *) NULL;
+    if (realm)
+	lrealm = strdup(realm);
+    else {
+	kret = krb5_get_default_realm(kcontext, &lrealm);
+	if (kret)
+	    goto cleanup;
+    }
+
+    kret = krb5_aprof_init(filename, envname, &aprofile);
+    if (kret)
+	goto cleanup;
+    
+    rparams = (krb5_realm_params *) malloc(sizeof(krb5_realm_params));
+    if (rparams == 0) {
+	kret = ENOMEM;
+	goto cleanup;
+    }
+
+    /* Initialize realm parameters */
+    memset((char *) rparams, 0, sizeof(krb5_realm_params));
+
+    /* Get the value for the database */
+    hierarchy[0] = "realms";
+    hierarchy[1] = lrealm;
+    hierarchy[2] = "database_name";
+    hierarchy[3] = (char *) NULL;
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+	rparams->realm_dbname = svalue;
+	
+    /* Get the value for the KDC port list */
+    hierarchy[2] = "kdc_ports";
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+	rparams->realm_kdc_ports = svalue;
+    hierarchy[2] = "kdc_tcp_ports";
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+	rparams->realm_kdc_tcp_ports = svalue;
+
+    /* Get the name of the acl file */
+    hierarchy[2] = "acl_file";
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+	rparams->realm_acl_file = svalue;
+	    
+    /* Get the value for the kadmind port */
+    hierarchy[2] = "kadmind_port";
+    if (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) {
+	rparams->realm_kadmind_port = ivalue;
+	rparams->realm_kadmind_port_valid = 1;
+    }
+	    
+    /* Get the value for the master key name */
+    hierarchy[2] = "master_key_name";
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+	rparams->realm_mkey_name = svalue;
+	    
+    /* Get the value for the master key type */
+    hierarchy[2] = "master_key_type";
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	if (!krb5_string_to_enctype(svalue, &rparams->realm_enctype))
+	    rparams->realm_enctype_valid = 1;
+	krb5_xfree(svalue);
+    }
+	    
+    /* Get the value for the stashfile */
+    hierarchy[2] = "key_stash_file";
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
+	rparams->realm_stash_file = svalue;
+	    
+    /* Get the value for maximum ticket lifetime. */
+    hierarchy[2] = "max_life";
+    if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
+	rparams->realm_max_life = dtvalue;
+	rparams->realm_max_life_valid = 1;
+    }
+	    
+    /* Get the value for maximum renewable ticket lifetime. */
+    hierarchy[2] = "max_renewable_life";
+    if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
+	rparams->realm_max_rlife = dtvalue;
+	rparams->realm_max_rlife_valid = 1;
+    }
+	    
+    /* Get the value for the default principal expiration */
+    hierarchy[2] = "default_principal_expiration";
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	if (!krb5_string_to_timestamp(svalue,
+				      &rparams->realm_expiration))
+	    rparams->realm_expiration_valid = 1;
+	krb5_xfree(svalue);
+    }
+
+    hierarchy[2] = "reject_bad_transit";
+    if (!krb5_aprof_get_boolean(aprofile, hierarchy, TRUE, &bvalue)) {
+	rparams->realm_reject_bad_transit = bvalue;
+	rparams->realm_reject_bad_transit_valid = 1;
+    }
+
+    /* Get the value for the default principal flags */
+    hierarchy[2] = "default_principal_flags";
+    if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
+	char *sp, *ep, *tp;
+
+	sp = svalue;
+	rparams->realm_flags = 0;
+	while (sp) {
+	    if ((ep = strchr(sp, (int) ',')) ||
+		(ep = strchr(sp, (int) ' ')) ||
+		(ep = strchr(sp, (int) '\t'))) {
+		/* Fill in trailing whitespace of sp */
+		tp = ep - 1;
+		while (isspace((int) *tp) && (tp < sp)) {
+		    *tp = '\0';
+		    tp--;
+		}
+		*ep = '\0';
+		ep++;
+		/* Skip over trailing whitespace of ep */
+		while (isspace((int) *ep) && (*ep)) ep++;
+	    }
+	    /* Convert this flag */
+	    if (krb5_string_to_flags(sp,
+				     "+",
+				     "-",
+				     &rparams->realm_flags))
+		break;
+	    sp = ep;
+	}
+	if (!sp)
+	    rparams->realm_flags_valid = 1;
+	krb5_xfree(svalue);
+    }
+
+    rparams->realm_keysalts = NULL;
+    rparams->realm_num_keysalts = 0;
+
+cleanup:
+    if (aprofile)
+	krb5_aprof_finish(aprofile);
+    if (lrealm)
+	free(lrealm);
+    if (kret) {
+	if (rparams)
+	    krb5_free_realm_params(kcontext, rparams);
+	rparams = 0;
+    }
+    *rparamp = rparams;
+    return(kret);
+}
+
+/*
+ * krb5_free_realm_params()	- Free data allocated by above.
+ */
+krb5_error_code
+krb5_free_realm_params(kcontext, rparams)
+    krb5_context	kcontext;
+    krb5_realm_params	*rparams;
+{
+    if (rparams) {
+	if (rparams->realm_profile)
+	    krb5_xfree(rparams->realm_profile);
+	if (rparams->realm_dbname)
+	    krb5_xfree(rparams->realm_dbname);
+	if (rparams->realm_mkey_name)
+	    krb5_xfree(rparams->realm_mkey_name);
+	if (rparams->realm_stash_file)
+	    krb5_xfree(rparams->realm_stash_file);
+	if (rparams->realm_keysalts)
+	    krb5_xfree(rparams->realm_keysalts);
+	if (rparams->realm_kdc_ports)
+	    krb5_xfree(rparams->realm_kdc_ports);
+	if (rparams->realm_kdc_tcp_ports)
+	    krb5_xfree(rparams->realm_kdc_tcp_ports);
+	if (rparams->realm_acl_file)
+	    krb5_xfree(rparams->realm_acl_file);
+	krb5_xfree(rparams);
+    }
+    return(0);
+}
+
diff --git a/mechglue/src/lib/kadm5/chpass_util.c b/mechglue/src/lib/kadm5/chpass_util.c
new file mode 100644
index 000000000..a3c42bfe1
--- /dev/null
+++ b/mechglue/src/lib/kadm5/chpass_util.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ */
+
+
+#include <stdio.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <time.h>
+
+#include <kadm5/admin.h>
+#include "admin_internal.h"
+
+#include <krb5.h>
+
+#define string_text error_message
+
+/*
+ * Function: kadm5_chpass_principal_util
+ *
+ * Purpose: Wrapper around chpass_principal. We can read new pw, change pw and return useful messages
+ *
+ * Arguments:
+ *
+ *      princ          (input) a krb5b_principal structure for the 
+ *                     principal whose password we should change.
+ *
+ *      new_password   (input) NULL or a null terminated string with the 
+ *                     the principal's desired new password.  If new_password
+ *                     is NULL then this routine will read a new password.
+ *    
+ *	pw_ret		(output) if non-NULL, points to a static buffer
+ *			containing the new password (if password is prompted
+ *			internally), or to the new_password argument (if
+ *			that is non-NULL).  If the former, then the buffer
+ *			is only valid until the next call to the function,
+ *			and the caller should be sure to zero it when
+ *			it is no longer needed.
+ *
+ *      msg_ret         (output) a useful message is copied here.
+ *
+ *      <return value>  exit status of 0 for success, else the com err code 
+ *                      for the last significant routine called.
+ *      
+ * Requires:
+ *      
+ *      A msg_ret should point to a buffer large enough for the messasge.
+ *
+ * Effects:
+ *      
+ * Modifies:
+ *
+ *
+ */
+
+kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle,
+					 void *lhandle,
+					 krb5_principal princ,
+					 char *new_pw, 
+					 char **ret_pw,
+					 char *msg_ret,
+					 unsigned int msg_len)
+{
+  int code, code2;
+  unsigned int pwsize;
+  static char buffer[255];
+  char *new_password;
+  kadm5_principal_ent_rec princ_ent;
+  kadm5_policy_ent_rec policy_ent;
+
+  _KADM5_CHECK_HANDLE(server_handle);
+
+  if (ret_pw)
+    *ret_pw = NULL;
+
+  if (new_pw != NULL) {
+    new_password = new_pw;
+  } else { /* read the password */
+    krb5_context context;
+
+    if ((code = (int) krb5_init_context(&context)) == 0) {
+      pwsize = sizeof(buffer);
+      code = krb5_read_password(context, KADM5_PW_FIRST_PROMPT,
+				KADM5_PW_SECOND_PROMPT,
+				buffer, &pwsize);
+      krb5_free_context(context);
+    }
+
+    if (code == 0) 
+      new_password = buffer;
+    else {
+#ifdef ZEROPASSWD    
+      memset(buffer, 0, sizeof(buffer));
+#endif      
+      if (code == KRB5_LIBOS_BADPWDMATCH) {
+	strncpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH),
+		msg_len - 1);
+	msg_ret[msg_len - 1] = '\0';
+	return(code);
+      } else {
+        strncpy(msg_ret, error_message(code), msg_len - 1);
+        strncat(msg_ret, " ", msg_len - 1);
+        strncat(msg_ret, string_text(CHPASS_UTIL_WHILE_READING_PASSWORD),
+		msg_len - 1);
+        strncat(msg_ret, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED),
+		msg_len - 1);
+	msg_ret[msg_len - 1] = '\0';
+	return(code);
+      }
+    }
+    if (pwsize == 0) {
+#ifdef ZEROPASSWD    
+      memset(buffer, 0, sizeof(buffer));
+#endif      
+      strncpy(msg_ret, string_text(CHPASS_UTIL_NO_PASSWORD_READ), msg_len - 1);
+      msg_ret[msg_len - 1] = '\0';
+      return(KRB5_LIBOS_CANTREADPWD); /* could do better */
+    }
+  }
+
+  if (ret_pw)
+    *ret_pw = new_password;
+
+  code = kadm5_chpass_principal(server_handle, princ, new_password);
+
+#ifdef ZEROPASSWD
+  if (!ret_pw)
+    memset(buffer, 0, sizeof(buffer)); /* in case we read a new password */
+#endif    
+
+  if (code == KADM5_OK) {
+    strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_CHANGED), msg_len - 1);
+    msg_ret[msg_len - 1] = '\0';
+    return(0);
+  }
+
+  if ((code != KADM5_PASS_Q_TOOSHORT) && 
+      (code != KADM5_PASS_REUSE) &&(code != KADM5_PASS_Q_CLASS) && 
+      (code != KADM5_PASS_Q_DICT) && (code != KADM5_PASS_TOOSOON)) {
+    /* Can't get more info for other errors */
+    sprintf(buffer, "%s %s", error_message(code), 
+	    string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE));
+    sprintf(msg_ret, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), 
+	    buffer);
+    return(code);
+  }
+
+  /* Ok, we have a password quality error. Return a good message */
+
+  if (code == KADM5_PASS_REUSE) {
+    strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_REUSE), msg_len - 1);
+    msg_ret[msg_len - 1] = '\0';
+    return(code);
+  }
+
+  if (code == KADM5_PASS_Q_DICT) {
+    strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_IN_DICTIONARY),
+	    msg_len - 1);
+    msg_ret[msg_len - 1] = '\0';
+    return(code);
+  }
+  
+  /* Look up policy for the remaining messages */
+
+  code2 = kadm5_get_principal (lhandle, princ, &princ_ent,
+			       KADM5_PRINCIPAL_NORMAL_MASK);
+  if (code2 != 0) {
+    strncpy(msg_ret, error_message(code2), msg_len - 1);
+    strncat(msg_ret, " ", msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, string_text(CHPASS_UTIL_GET_PRINC_INFO), msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, "\n", msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, error_message(code), msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, " ", msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE),
+	    msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, "\n\n", msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED),
+	    msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, "\n", msg_len - 1 - strlen(msg_ret));
+    msg_ret[msg_len - 1] = '\0';
+    return(code);
+  }
+  
+  if ((princ_ent.aux_attributes & KADM5_POLICY) == 0) {
+    strncpy(msg_ret, error_message(code), msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, " ", msg_len - 1 - strlen(msg_ret));
+    strncpy(msg_ret, string_text(CHPASS_UTIL_NO_POLICY_YET_Q_ERROR),
+	    msg_len - 1 - strlen(msg_ret));
+    strncat(msg_ret, "\n\n", msg_len - 1 - strlen(msg_ret));
+    strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED),
+	    msg_len - 1 - strlen(msg_ret));
+    msg_ret[msg_len - 1] = '\0';
+
+    (void) kadm5_free_principal_ent(lhandle, &princ_ent);
+    return(code);
+  }
+
+  code2 = kadm5_get_policy(lhandle, princ_ent.policy,
+			   &policy_ent);
+  if (code2 != 0) {
+    sprintf(msg_ret, "%s %s\n%s %s\n\n%s\n ", error_message(code2), 
+	    string_text(CHPASS_UTIL_GET_POLICY_INFO),
+	    error_message(code),
+	    string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE),
+	    string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
+    (void) kadm5_free_principal_ent(lhandle, &princ_ent);
+    return(code);
+  }
+  
+  if (code == KADM5_PASS_Q_TOOSHORT) {
+    sprintf(msg_ret, string_text(CHPASS_UTIL_PASSWORD_TOO_SHORT), 
+	    policy_ent.pw_min_length);
+    (void) kadm5_free_principal_ent(lhandle, &princ_ent);
+    (void) kadm5_free_policy_ent(lhandle, &policy_ent);
+    return(code);
+  }
+
+/* Can't get more info for other errors */
+
+  if (code == KADM5_PASS_Q_CLASS) {
+    sprintf(msg_ret, string_text(CHPASS_UTIL_TOO_FEW_CLASSES), 
+	    policy_ent.pw_min_classes);
+    (void) kadm5_free_principal_ent(lhandle, &princ_ent);
+    (void) kadm5_free_policy_ent(lhandle, &policy_ent);
+    return(code);
+  }
+
+  if (code == KADM5_PASS_TOOSOON) {
+    time_t until;
+    char *time_string, *ptr;
+
+    until = princ_ent.last_pwd_change + policy_ent.pw_min_life;
+
+    time_string = ctime(&until);
+    if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
+      *ptr = '\0';
+
+    sprintf(msg_ret, string_text(CHPASS_UTIL_PASSWORD_TOO_SOON), 
+	    time_string);
+    (void) kadm5_free_principal_ent(lhandle, &princ_ent);
+    (void) kadm5_free_policy_ent(lhandle, &policy_ent);
+    return(code);
+  }
+
+  /* We should never get here, but just in case ... */
+  sprintf(buffer, "%s %s", error_message(code), 
+	  string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE));
+  sprintf(msg_ret, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), 
+	  buffer);
+  (void) kadm5_free_principal_ent(lhandle, &princ_ent);
+  (void) kadm5_free_policy_ent(lhandle, &policy_ent);
+  return(code);
+}
diff --git a/mechglue/src/lib/kadm5/chpass_util_strings.et b/mechglue/src/lib/kadm5/chpass_util_strings.et
new file mode 100644
index 000000000..c65010ae1
--- /dev/null
+++ b/mechglue/src/lib/kadm5/chpass_util_strings.et
@@ -0,0 +1,58 @@
+# this is really a string table for ovsec_kadm_chpass_principal_util
+
+error_table ovku
+
+error_code CHPASS_UTIL_GET_POLICY_INFO, "while getting policy info."
+error_code CHPASS_UTIL_GET_PRINC_INFO, "while getting principal info."
+error_code CHPASS_UTIL_NEW_PASSWORD_MISMATCH, 
+	"New passwords do not match - password not changed.\n"
+
+error_code CHPASS_UTIL_NEW_PASSWORD_PROMPT, "New password"
+error_code CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT, "New password (again)"
+error_code CHPASS_UTIL_NO_PASSWORD_READ, "You must type a password. Passwords must be at least one character long.\n"
+error_code CHPASS_UTIL_NO_POLICY_YET_Q_ERROR, 
+"yet no policy set!  Contact your system security administrator."
+
+error_code CHPASS_UTIL_PASSWORD_CHANGED, "Password changed.\n"
+
+error_code CHPASS_UTIL_PASSWORD_IN_DICTIONARY,
+"New password was found in a dictionary of possible passwords and\n\
+therefore may be easily guessed. Please choose another password.\n\
+See the kpasswd man page for help in choosing a good password."
+
+error_code CHPASS_UTIL_PASSWORD_NOT_CHANGED, "Password not changed."
+
+error_code CHPASS_UTIL_PASSWORD_TOO_SHORT, 
+"New password is too short.\n\
+Please choose a password which is at least %d characters long."
+#	/*  <pw-min-len> */
+
+error_code CHPASS_UTIL_TOO_FEW_CLASSES, 
+"New password does not have enough character classes.\n\
+The character classes are:\n\
+	- lower-case letters,\n\
+	- upper-case letters,\n\
+	- digits,\n\
+	- punctuation, and\n\
+	- all other characters (e.g., control characters).\n\
+Please choose a password with at least %d character classes."
+# /* <min-classes> */
+
+
+error_code CHPASS_UTIL_PASSWORD_TOO_SOON,
+"Password cannot be changed because it was changed too recently.\n\
+Please wait until %s before you change it.\n\
+If you need to change your password before then, contact your system\n\
+security administrator."
+# /* <ctime(last-pw-change+pw-min-life)> */
+
+error_code CHPASS_UTIL_PASSWORD_REUSE, 
+"New password was used previously. Please choose a different password."
+
+error_code CHPASS_UTIL_WHILE_TRYING_TO_CHANGE, 
+"while trying to change password."
+
+error_code CHPASS_UTIL_WHILE_READING_PASSWORD, "while reading new password."
+
+end
+
diff --git a/mechglue/src/lib/kadm5/clnt/ChangeLog b/mechglue/src/lib/kadm5/clnt/ChangeLog
new file mode 100644
index 000000000..424272772
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/ChangeLog
@@ -0,0 +1,357 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* client_principal.c, clnt_policy.c: Include errno.h.
+	* client_init.c: Include k5-int.h before krb5.h.
+	* err_handle.h: Include com_err.h and krb5.h instead of k5-int.h.
+
+2005-10-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkadm5clnt.exports: Don't export internal error-table
+	symbols.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkadm5clnt.exports: Delete RPC functions, and references to
+	adb error table.
+	* client_init.c, client_principal.c, client_rpc.c, clnt_policy.c,
+	clnt_privs.c: Renamed all RPC functions from _1 to _2 to match
+	current program version number.
+
+2005-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* err_handle.c (krb5_err_key): Variable deleted.
+	(init_err_handling, krb5_set_err, krb5_get_err_string,
+	krb5_clr_error): Use k5_ macros for thread-specific data instead
+	of pthread versions.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	Novell merge.
+	* err_handle.c: New file.
+	* err_handle.h: New file.
+	* Makefile.in (SRCS, OBJS, STLIBOBJS, err_handle.o): Build
+	err_handle.c.
+	* client_init.c (_kadm5_init_any): Accept new db_args argument,
+	but ignore it.  Don't call initialize_adb_error_table.
+	(kadm5_init_with_creds, kadm5_init_with_password, kadm5_init,
+	kadm5_init_with_skey): Accept new db_args argument and pass it
+	through to _kadm5_init_any.
+	* client_principal.c: Include err_handle.h.
+	(kadm5_get_principal, kadm5_get_principals,
+	kadm5_randkey_principal_3, kadm5_randkey_principal): If an error
+	was returned from the server, pass it and the error string to
+	krb5_set_err.
+	* clnt_policy.c: Include err_handle.h.
+	(kadm5_create_policy, kadm5_delete_policy, kadm5_modify_policy,
+	kadm5_get_policy, kadm5_get_policies): If an error was returned
+	from the server, pass it and the error string to krb5_set_err.
+	* clnt_privs.c: Include err_handle.h.
+	(kadm5_get_privs): If an error was returned from the server, pass
+	it and the error string to krb5_set_err.
+
+2005-02-11  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c (kadm5_get_init_creds, kadm5_gic_iter) 
+	(kadm5_setup_gss, kadm5_rpc_auth): New functions, containing parts
+	of _kadm5_init_any.
+	(_kadm5_init_any): Bits broken out into helper functions.
+	(kadm5_get_init_creds): Fall back from kadmin/fqdn to kadmin/admin
+	if NULL service name passed in.
+	(kadm5_rpc_auth): Fall back from RPCSEC_GSS to AUTH_GSSAPI.
+
+2004-10-25  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c (_kadm5_init_any): Pass req_flags and cred to
+	auth_gss_create().
+
+2004-08-20  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c (_kadm5_init_any): Remove INIT_TEST ifdefs.  Use
+	KADM5_CONFIG_NO_AUTH to request no auth (for testing).
+
+2004-06-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkadm5clnt.exports: Export kadm5_get_admin_service_name.
+
+2004-06-24  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c (_kadm5_init_any)[DEBUG]: Print error from
+	clnttcp_create().
+	(_kadm5_init_any): Use kadm5_get_admin_service_name() if null
+	pointer passed in for service_name.
+
+2004-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* client_principal.c (eret): Add some debugging messages for some
+	RPC errors.
+
+	* client_init.c (_kadm5_init_any): Add support for RPCSEC_GSS.
+	Default to using AUTH_GSSAPI for ovsec.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkadm5clnt.exports: New file.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* client_init.c (enctypes): Variable deleted.
+	(_kadm5_init_any): Pass a null pointer instead of enctypes.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2002-10-08  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (LIBMINOR): Bump.
+
+	* client_init.c (kadm5_lock, kadm5_unlock): Add stubs that error
+	out, since these are not supported on the client side.
+
+2002-09-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* client_init.c (_kadm5_init_any): If creating a new ccache, put
+	it in memory instead of on disk.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-31  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c (_kadm5_init_any): Use
+	KADM5_MISSING_KRB5_CONF_PARAMS in order to be less confusing to
+	someone running kadmin rather than kadmin.local.
+
+2002-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS, SHLIB_EXPLIBS): Drop references to
+	libdyn.
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBMAJOR): Bump to avoid Heimdal conflict.
+
+2001-11-07  Sam Hartman  <hartmans@mit.edu>
+
+	* client_init.c: Allow arcfour-hmac-md5 to be used for  kadmin
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* client_init.c (_kadm5_init_any): Add casts to (gss_OID) in calls
+	to gss library.
+
+Sun Feb 18 17:32:53 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* client_rpc.c: Insure pointer argument type is same as passed
+        onto xdr functions. (arguments specified to *3_1 functions were
+        for the *_1 functions).
+
+	* client_init.c, client_principal.c, clnt_policy.c: Cleanup unused
+        variables and assignments in conditionals.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* clnt_chpass_util.c (kadm5_chpass_principal_util): Change msg_len
+	to unsigned int.
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: The client library does not depend on the database
+	library. Remove reference to it.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): Add libdb.
+	(SHLIB_EXPLIBS): Add -ldb.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* client_init.c (_kadm5_init_any): gss_krb5_ccache_name returns
+	const char *, but the code was treating it as a char *.
+
+2000-06-23  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* clnt_chpass_util.c (kadm5_chpass_principal_util): Adjust for new
+	length parameter in both kadm5_chpass_principal_util() and in
+	_kadm5_chpass_principal_util().
+
+	* client_init.c (_kadm5_init_any): Fix determination of client
+	name length for overflow checking.
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* client_init.c (enctypes): Add des3 and des-md5 to the list of
+	permitted enctypes.
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* client_init.c, client_principal.c, client_rpc.c: Check for
+	existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-02-26  Tom Yu  <tlyu@mit.edu>
+
+	* client_principal.c (kadm5_create_principal_3): Remove keepold
+	argument.
+
+	* Makefile.in (LIBMAJOR): Bump major number due to call signature
+	changes.
+
+2000-02-13  Tom Yu  <tlyu@mit.edu>
+
+	* client_rpc.c: Add new client stubs.
+
+	* client_principal.c: Add new functions for client-side kadm rpc
+	calls.
+
+2000-01-27  Ken Raeburn  <raeburn@raeburn.org>
+
+	* client_init.c (enctypes): New array, listing only
+	ENCTYPE_DES_CBC_CRC.
+	(_kadm5_init_any): Pass it in krb5_get_in_tkt_with_* calls for
+	now, while GSSAPI/krb5 can only handle DES.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-27  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c (_kadm5_init_any): Remove support for krb5-mech2
+	for now.
+
+Thu May 13 17:24:44 1999  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c (_kadm5_init_any): Use gss_krb5_ccache_name() to
+	set the gssapi ccache name.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* client_init.c (_kadm5_init_any): try the krb5 v2 mechanism
+	first, and if that fails, try the krb5 v1 mech.
+
+Sun Jul 26 18:11:56 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* Makefile.in (LIBMAJOR): bump libmajor
+
+Wed Apr 15 18:05:57 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): 
+	(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
+
+Fri Feb 27 22:32:16 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/kadm5
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel lib/kadm5 configure.in
+
+Wed Feb 18 16:14:27 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 21:30:34 1998  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c:
+	* client_principal.c:
+	* client_rpc.c:
+	* clnt_policy.c:
+	* clnt_privs.c: Update header locations.
+
+	* Makefile.in (LIBMAJOR): Bump major version to reflect change in
+	rpc library.
+
+Wed Jan 28 16:32:36 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in, Makefile.in: Remove the CopySrcHeader macro
+		from configure.in and substitute equivalent
+		functionality in Makefile.in
+
+Mon Oct 13 10:55:02 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* client_init.c (kadm5_destroy): Free handle->lhandle field, call
+        kadm5_free_config_params and krb5_free_context.
+
+Tue Jul  1 02:34:46 1997  Tom Yu  <tlyu@mit.edu>
+
+	* client_principal.c, client_rpc.c: Add support for setv4key.
+
+Mon Mar 31 17:40:48 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* client_principal.c, client_rpc.c: add support for
+ 	setkey_principal
+
+Sat Feb 22 01:35:19 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): s/.so/$(SHLIBEXT)
+
+Wed Jan 15 20:49:34 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Wed Nov 13 19:20:11 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (clean-unix): Remove shared/*.
+
+Wed Nov  6 10:35:01 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* client_init.c (_kadm5_init_any): Use a more fined grained error
+ 		code, KADM5_MISSING_CONF_PARAMS instead of
+ 		KRB5_CONFIG_BADFORMAT
+	(_kadm5_init_any): Use a more fined grained error code,
+ 	 	KADM5_BAD_SERVER_NAME, instead of KRB5_CONFIG_BADFORMAT.
+
+Thu Nov  7 11:41:08 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* client_principal.c (kadm5_get_principal,
+		kadm5_modify_principal): For a V1 request, copy only the
+		memory that is allocated for the incomming principal.
+		
+Fri Oct  4 08:38:16 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* client_principal.c (kadm5_randkey_principal): Do not assume that
+		malloc(0) returns non-NULL. [krb5-admin/29]
+
+Mon Aug 26 16:33:31 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* client_init.c (_kadm5_init_any): use DEFAULT_PROFILE_PATH
+ 	instead of "/etc/krb5.conf"
+
+Wed Jul 31 17:01:38 1996  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c: Revert prior change due to netdb.h shuffling.
+
+Tue Jul 30 19:47:53 1996  Tom Yu  <tlyu@mit.edu>
+
+	* client_init.c: Remove #include <netdb.h> because rpc/types.h
+		(included from kadm5/admin.h) gets it.
+
+Wed Jul 24 20:59:35 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Don't replace setenv
+
+	* client_init.c (_kadm5_init_any): Use krb5_setenv and krb5_unsetenv
+
+Wed Jul 24 18:20:47 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in, configure.in: break out client lib into a
+		subdirectory
+
diff --git a/mechglue/src/lib/kadm5/clnt/Makefile.in b/mechglue/src/lib/kadm5/clnt/Makefile.in
new file mode 100644
index 000000000..71b84c477
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/Makefile.in
@@ -0,0 +1,160 @@
+thisconfigdir=./..
+myfulldir=lib/kadm5/clnt
+mydir=clnt
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(BUILDTOP)/include/kadm5
+
+LIBBASE=kadm5clnt
+LIBMAJOR=5
+LIBMINOR=1
+STOBJLISTS=../OBJS.ST OBJS.ST
+SHLIB_EXPDEPS=\
+	$(TOPLIBD)/libgssrpc$(SHLIBEXT) \
+	$(TOPLIBD)/libgssapi_krb5$(SHLIBEXT) \
+	$(TOPLIBD)/libkrb5$(SHLIBEXT) \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(COM_ERR_DEPLIB)
+SHLIB_EXPLIBS=-lgssrpc -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+RELDIR=kadm5/clnt
+
+##DOSBUILDTOP = ..\..\..
+##DOSLIBNAME = libkadm5clnt.lib
+
+SRCS =	$(srcdir)/clnt_policy.c \
+	$(srcdir)/client_rpc.c \
+	$(srcdir)/client_principal.c \
+	$(srcdir)/client_init.c \
+	$(srcdir)/clnt_privs.c \
+	$(srcdir)/err_handle.c \
+	$(srcdir)/clnt_chpass_util.c
+
+OBJS =	\
+	clnt_policy.$(OBJEXT) \
+	client_rpc.$(OBJEXT) \
+	client_principal.$(OBJEXT) \
+	client_init.$(OBJEXT) \
+	clnt_privs.$(OBJEXT) \
+	err_handle.$(OBJEXT) \
+	clnt_chpass_util.$(OBJEXT)
+
+STLIBOBJS = \
+	clnt_policy.o \
+	client_rpc.o \
+	client_principal.o \
+	client_init.o \
+	clnt_privs.o \
+	err_handle.o \
+	clnt_chpass_util.o
+
+err_handle.o : err_handle.h err_handle.c
+
+all-unix:: includes
+all-unix:: all-liblinks
+all-windows:: $(OBJS)
+
+includes:: client_internal.h
+	if cmp $(srcdir)/client_internal.h \
+	$(BUILDTOP)/include/kadm5/client_internal.h >/dev/null 2>&1; then :; \
+	else \
+		(set -x; $(RM) $(BUILDTOP)/include/kadm5/client_internal.h; \
+		 $(CP) $(srcdir)/client_internal.h \
+			$(BUILDTOP)/include/kadm5/client_internal.h) ; \
+	fi
+
+clean-unix::
+	$(RM) $(BUILDTOP)/include/kadm5/client_internal.h
+
+check-windows::
+
+clean-windows::
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+install:: install-libs
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+clnt_policy.so clnt_policy.po $(OUTPRE)clnt_policy.$(OBJEXT): \
+  clnt_policy.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_rpc.h \
+  client_internal.h $(BUILDTOP)/include/kadm5/admin_internal.h \
+  err_handle.h
+client_rpc.so client_rpc.po $(OUTPRE)client_rpc.$(OBJEXT): \
+  client_rpc.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/kadm5/kadm_rpc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/kadm5/admin.h $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h
+client_principal.so client_principal.po $(OUTPRE)client_principal.$(OBJEXT): \
+  client_principal.c $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/include/kadm5/kadm_rpc.h client_internal.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h err_handle.h
+client_init.so client_init.po $(OUTPRE)client_init.$(OBJEXT): \
+  client_init.c $(COM_ERR_DEPS) $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/include/kadm5/kadm_rpc.h client_internal.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+  $(BUILDTOP)/include/gssrpc/auth_gssapi.h
+clnt_privs.so clnt_privs.po $(OUTPRE)clnt_privs.$(OBJEXT): \
+  clnt_privs.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_rpc.h \
+  client_internal.h $(BUILDTOP)/include/kadm5/admin_internal.h \
+  err_handle.h
+err_handle.so err_handle.po $(OUTPRE)err_handle.$(OBJEXT): \
+  err_handle.c err_handle.h $(COM_ERR_DEPS) $(BUILDTOP)/include/krb5.h
+clnt_chpass_util.so clnt_chpass_util.po $(OUTPRE)clnt_chpass_util.$(OBJEXT): \
+  clnt_chpass_util.c $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  client_internal.h $(BUILDTOP)/include/kadm5/admin_internal.h
diff --git a/mechglue/src/lib/kadm5/clnt/client_handle.c b/mechglue/src/lib/kadm5/clnt/client_handle.c
new file mode 100644
index 000000000..895777a6e
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/client_handle.c
@@ -0,0 +1,9 @@
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include "client_internal.h"
+
+int _kadm5_check_handle(void *handle)
+{
+     CHECK_HANDLE(handle);
+     return 0;
+}
diff --git a/mechglue/src/lib/kadm5/clnt/client_init.c b/mechglue/src/lib/kadm5/clnt/client_init.c
new file mode 100644
index 000000000..a4e313628
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/client_init.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <stdio.h>
+#include <netdb.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <string.h>
+#include <com_err.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */
+#include <krb5.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include "client_internal.h"
+
+#include <gssrpc/rpc.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssrpc/auth_gssapi.h>
+
+#define	ADM_CCACHE  "/tmp/ovsec_adm.XXXXXX"
+
+enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS };
+
+static kadm5_ret_t _kadm5_init_any(char *client_name,
+				   enum init_type init_type,
+				   char *pass,
+				   krb5_ccache ccache_in,
+				   char *service_name,
+				   kadm5_config_params *params,
+				   krb5_ui_4 struct_version,
+				   krb5_ui_4 api_version,
+				   char **db_args,
+				   void **server_handle);
+
+static kadm5_ret_t
+kadm5_get_init_creds(kadm5_server_handle_t handle,
+		     char *client_name, enum init_type init_type,
+		     char *pass, krb5_ccache ccache_in,
+		     char *svcname_in, char *realm,
+		     char *full_svcname, unsigned int full_svcname_len);
+
+static kadm5_ret_t
+kadm5_gic_iter(kadm5_server_handle_t handle,
+	       enum init_type init_type,
+	       krb5_ccache ccache,
+	       krb5_principal client, char *pass,
+	       char *svcname, char *realm,
+	       char *full_svcname, unsigned int full_svcname_len);
+
+static kadm5_ret_t
+kadm5_setup_gss(kadm5_server_handle_t handle,
+		kadm5_config_params *params_in,
+		char *client_name, char *full_svcname);
+
+static void
+kadm5_rpc_auth(kadm5_server_handle_t handle,
+	       kadm5_config_params *params_in,
+	       gss_cred_id_t gss_client_creds,
+	       gss_name_t gss_target);
+
+kadm5_ret_t kadm5_init_with_creds(char *client_name,
+				  krb5_ccache ccache,
+				  char *service_name,
+				  kadm5_config_params *params,
+				  krb5_ui_4 struct_version,
+				  krb5_ui_4 api_version,
+				  char **db_args,
+				  void **server_handle)
+{
+     return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache,
+			    service_name, params,
+			    struct_version, api_version, db_args,
+			    server_handle);
+}
+
+
+kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
+				     char *service_name,
+				     kadm5_config_params *params,
+				     krb5_ui_4 struct_version,
+				     krb5_ui_4 api_version,
+				     char **db_args,
+				     void **server_handle)
+{
+     return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
+			    service_name, params, struct_version,
+			    api_version, db_args, server_handle);
+}
+
+kadm5_ret_t kadm5_init(char *client_name, char *pass,
+		       char *service_name, 
+		       kadm5_config_params *params,
+		       krb5_ui_4 struct_version,
+		       krb5_ui_4 api_version,
+		       char **db_args,
+		       void **server_handle)
+{
+     return _kadm5_init_any(client_name, INIT_PASS, pass, NULL,
+			    service_name, params, struct_version,
+			    api_version, db_args, server_handle);
+}
+
+kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
+				 char *service_name,
+				 kadm5_config_params *params,
+				 krb5_ui_4 struct_version,
+				 krb5_ui_4 api_version,
+				 char **db_args,
+				 void **server_handle)
+{
+     return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL,
+			    service_name, params, struct_version,
+			    api_version, db_args, server_handle);
+}
+
+static kadm5_ret_t _kadm5_init_any(char *client_name,
+				   enum init_type init_type,
+				   char *pass,
+				   krb5_ccache ccache_in,
+				   char *service_name,
+				   kadm5_config_params *params_in,
+				   krb5_ui_4 struct_version,
+				   krb5_ui_4 api_version,
+				   char **db_args,
+				   void **server_handle)
+{
+     struct sockaddr_in addr;
+     struct hostent *hp;
+     int fd;
+
+     char full_svcname[BUFSIZ];
+     char *realm;
+     
+     kadm5_server_handle_t handle;
+     kadm5_config_params params_local;
+
+     int code = 0;
+     generic_ret *r;
+
+     initialize_ovk_error_table();
+/*      initialize_adb_error_table(); */
+     initialize_ovku_error_table();
+     
+     if (! server_handle) {
+	 return EINVAL;
+     }
+
+     if (! (handle = malloc(sizeof(*handle)))) {
+	  return ENOMEM;
+     }
+     if (! (handle->lhandle = malloc(sizeof(*handle)))) {
+	  free(handle);
+	  return ENOMEM;
+     }
+
+     handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
+     handle->struct_version = struct_version;
+     handle->api_version = api_version;
+     handle->clnt = 0;
+     handle->cache_name = 0;
+     handle->destroy_cache = 0;
+     *handle->lhandle = *handle;
+     handle->lhandle->api_version = KADM5_API_VERSION_2;
+     handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
+     handle->lhandle->lhandle = handle->lhandle;
+
+     krb5_init_context(&handle->context);
+
+     if(client_name == NULL) {
+	free(handle);
+	return EINVAL;
+     }
+
+     /*
+      * Verify the version numbers before proceeding; we can't use
+      * CHECK_HANDLE because not all fields are set yet.
+      */
+     GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
+			  KADM5_NEW_LIB_API_VERSION);
+     
+     /*
+      * Acquire relevant profile entries.  In version 2, merge values
+      * in params_in with values from profile, based on
+      * params_in->mask.
+      *
+      * In version 1, we've given a realm (which may be NULL) instead
+      * of params_in.  So use that realm, make params_in contain an
+      * empty mask, and behave like version 2.
+      */
+     memset((char *) ¶ms_local, 0, sizeof(params_local));
+     if (api_version == KADM5_API_VERSION_1) {
+	  realm = params_local.realm = (char *) params_in;
+	  if (params_in)
+	       params_local.mask = KADM5_CONFIG_REALM;
+
+	  /* Use old AUTH_GSSAPI for version 1 protocol. */
+	  params_local.mask |= KADM5_CONFIG_OLD_AUTH_GSSAPI;
+	  params_in = ¶ms_local;
+     } else {
+	  if (params_in && (params_in->mask & KADM5_CONFIG_REALM))
+	       realm = params_in->realm;
+	  else
+	       realm = NULL;
+     }
+
+#define ILLEGAL_PARAMS (KADM5_CONFIG_DBNAME | KADM5_CONFIG_ADBNAME | \
+			KADM5_CONFIG_ADB_LOCKFILE | \
+			KADM5_CONFIG_ACL_FILE | KADM5_CONFIG_DICT_FILE \
+			| KADM5_CONFIG_ADMIN_KEYTAB | \
+			KADM5_CONFIG_STASH_FILE | \
+			KADM5_CONFIG_MKEY_NAME | KADM5_CONFIG_ENCTYPE \
+			| KADM5_CONFIG_MAX_LIFE | \
+			KADM5_CONFIG_MAX_RLIFE | \
+			KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_FLAGS | \
+			KADM5_CONFIG_ENCTYPES | KADM5_CONFIG_MKEY_FROM_KBD)
+
+     if (params_in && params_in->mask & ILLEGAL_PARAMS) {
+	  free(handle);
+	  return KADM5_BAD_CLIENT_PARAMS;
+     }
+			
+     if ((code = kadm5_get_config_params(handle->context,
+					DEFAULT_PROFILE_PATH,
+					"KRB5_CONFIG",
+					params_in,
+					&handle->params))) {
+	  krb5_free_context(handle->context);
+	  free(handle);
+	  return(code);
+     }
+
+#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
+			 KADM5_CONFIG_ADMIN_SERVER | \
+			 KADM5_CONFIG_KADMIND_PORT) 
+
+     if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
+	  krb5_free_context(handle->context);
+	  free(handle);
+	  return KADM5_MISSING_KRB5_CONF_PARAMS;
+     }
+
+     /*
+      * Get credentials.  Also does some fallbacks in case kadmin/fqdn
+      * principal doesn't exist.
+      */
+     code = kadm5_get_init_creds(handle, client_name, init_type, pass,
+				 ccache_in, service_name, realm,
+				 full_svcname, sizeof(full_svcname));
+     if (code)
+	  goto error;
+     /*
+      * We have ticket; open the RPC connection.
+      */
+
+     hp = gethostbyname(handle->params.admin_server);
+     if (hp == (struct hostent *) NULL) {
+	  code = KADM5_BAD_SERVER_NAME;
+	  goto cleanup;
+     }
+
+     memset(&addr, 0, sizeof(addr));
+     addr.sin_family = hp->h_addrtype;
+     (void) memcpy((char *) &addr.sin_addr, (char *) hp->h_addr,
+		   sizeof(addr.sin_addr));
+     addr.sin_port = htons((u_short) handle->params.kadmind_port);
+     
+     fd = RPC_ANYSOCK;
+     
+     handle->clnt = clnttcp_create(&addr, KADM, KADMVERS, &fd, 0, 0);
+     if (handle->clnt == NULL) {
+	  code = KADM5_RPC_ERROR;
+#ifdef DEBUG
+	  clnt_pcreateerror("clnttcp_create");
+#endif
+	  goto error;
+     }
+     handle->lhandle->clnt = handle->clnt;
+
+     /* now that handle->clnt is set, we can check the handle */
+     if ((code = _kadm5_check_handle((void *) handle)))
+	  goto error;
+
+     /*
+      * The RPC connection is open; establish the GSS-API
+      * authentication context.
+      */
+     code = kadm5_setup_gss(handle, params_in, client_name, full_svcname);
+     if (code)
+	  goto error;
+
+     r = init_2(&handle->api_version, handle->clnt);
+     if (r == NULL) {
+	  code = KADM5_RPC_ERROR;
+#ifdef DEBUG
+	  clnt_perror(handle->clnt, "init_2 null resp");
+#endif
+	  goto error;
+     }
+     if (r->code) {
+	  code = r->code;
+	  goto error;
+     }
+
+     *server_handle = (void *) handle;
+
+     goto cleanup;
+
+error:
+     /*
+      * Note that it is illegal for this code to execute if "handle"
+      * has not been allocated and initialized.  I.e., don't use "goto
+      * error" before the block of code at the top of the function
+      * that allocates and initializes "handle".
+      */
+     if (handle->cache_name)
+	 free(handle->cache_name);
+     if(handle->clnt && handle->clnt->cl_auth)
+	  AUTH_DESTROY(handle->clnt->cl_auth);
+     if(handle->clnt)
+	  clnt_destroy(handle->clnt);
+
+cleanup:
+     if (code)
+	  free(handle);
+
+     return code;
+}
+
+/*
+ * kadm5_get_init_creds
+ *
+ * Get initial credentials for authenticating to server.  Perform
+ * fallback from kadmin/fqdn to kadmin/admin if svcname_in is NULL.
+ */
+static kadm5_ret_t
+kadm5_get_init_creds(kadm5_server_handle_t handle,
+		     char *client_name, enum init_type init_type,
+		     char *pass, krb5_ccache ccache_in,
+		     char *svcname_in, char *realm,
+		     char *full_svcname, unsigned int full_svcname_len)
+{
+     kadm5_ret_t code;
+     krb5_principal client;
+     krb5_ccache ccache;
+     char svcname[BUFSIZ];
+
+     client = NULL;
+     ccache = NULL;
+     /* NULL svcname means use host-based. */
+     if (svcname_in == NULL) {
+	  code = kadm5_get_admin_service_name(handle->context,
+					      handle->params.realm,
+					      svcname, sizeof(svcname));
+	  if (code) {
+	       code = KADM5_MISSING_KRB5_CONF_PARAMS;
+	       goto error;
+	  }
+     } else {
+	  strncpy(svcname, svcname_in, sizeof(svcname));
+	  svcname[sizeof(svcname)-1] = '\0';
+     }
+     /*
+      * Acquire a service ticket for svcname@realm in the name of
+      * client_name, using password pass (which could be NULL), and
+      * create a ccache to store them in.  If INIT_CREDS, use the
+      * ccache we were provided instead.
+      */
+     code = krb5_parse_name(handle->context, client_name, &client);
+     if (code)
+	  goto error;
+
+     if (init_type == INIT_CREDS) {
+	  ccache = ccache_in;
+	  handle->cache_name = (char *)
+	       malloc(strlen(krb5_cc_get_type(handle->context, ccache)) +
+		      strlen(krb5_cc_get_name(handle->context, ccache)) + 2);
+	  if (handle->cache_name == NULL) {
+	       code = ENOMEM;
+	       goto error;
+	  }
+	  sprintf(handle->cache_name, "%s:%s",
+		  krb5_cc_get_type(handle->context, ccache),
+		  krb5_cc_get_name(handle->context, ccache));
+     } else {
+	  static int counter = 0;
+
+	  handle->cache_name = malloc(sizeof("MEMORY:kadm5_")
+				      + 3*sizeof(counter));
+	  sprintf(handle->cache_name, "MEMORY:kadm5_%u", counter++);
+
+	  code = krb5_cc_resolve(handle->context, handle->cache_name,
+				 &ccache);
+	  if (code) 
+	       goto error;
+
+	  code = krb5_cc_initialize (handle->context, ccache, client);
+	  if (code) 
+	       goto error;
+
+	  handle->destroy_cache = 1;
+     }
+     handle->lhandle->cache_name = handle->cache_name;
+
+     code = kadm5_gic_iter(handle, init_type, ccache,
+			   client, pass, svcname, realm,
+			   full_svcname, full_svcname_len);
+     if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
+	  || code == KRB5_CC_NOTFOUND) && svcname_in == NULL) {
+	  /* Retry with old host-independent service princpal. */
+	  code = kadm5_gic_iter(handle, init_type, ccache,
+				client, pass,
+				KADM5_ADMIN_SERVICE, realm,
+				full_svcname, full_svcname_len);
+     }
+     /* Improved error messages */
+     if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
+     if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
+	  code = KADM5_SECURE_PRINC_MISSING;
+
+error:
+     if (ccache != NULL && init_type != INIT_CREDS)
+	  krb5_cc_close(handle->context, ccache);
+     return code;
+}
+
+/*
+ * kadm5_gic_iter
+ *
+ * Perform one iteration of attempting to get credentials.  This
+ * includes searching existing ccache for requested service if
+ * INIT_CREDS.
+ */
+static kadm5_ret_t
+kadm5_gic_iter(kadm5_server_handle_t handle,
+	       enum init_type init_type,
+	       krb5_ccache ccache,
+	       krb5_principal client, char *pass,
+	       char *svcname, char *realm,
+	       char *full_svcname, unsigned int full_svcname_len)
+{
+     kadm5_ret_t code;
+     krb5_context ctx;
+     krb5_keytab kt;
+     krb5_get_init_creds_opt opt;
+     krb5_creds mcreds, outcreds;
+
+     ctx = handle->context;
+     kt = NULL;
+     memset(full_svcname, 0, full_svcname_len);
+     memset(&opt, 0, sizeof(opt));
+     memset(&mcreds, 0, sizeof(mcreds));
+     memset(&outcreds, 0, sizeof(outcreds));
+
+     code = ENOMEM;
+     if (realm) {
+          if ((strlen(svcname) + strlen(realm) + 1) >= full_svcname_len)
+	       goto error;
+	  sprintf(full_svcname, "%s@%s", svcname, realm);
+     } else {
+	  /* krb5_princ_realm(client) is not null terminated */
+          if ((strlen(svcname) + krb5_princ_realm(ctx, client)->length + 1)
+	      >= full_svcname_len)
+	       goto error;
+
+	  strcpy(full_svcname, svcname);
+	  strcat(full_svcname, "@");
+	  strncat(full_svcname,
+		  krb5_princ_realm(ctx, client)->data,
+		  krb5_princ_realm(ctx, client)->length);
+     }
+
+     if (init_type != INIT_CREDS)
+	  krb5_get_init_creds_opt_init(&opt);
+
+     if (init_type == INIT_PASS) {
+	  code = krb5_get_init_creds_password(ctx, &outcreds, client, pass,
+					      krb5_prompter_posix,
+					      NULL, 0,
+					      full_svcname, &opt);
+	  if (code)
+	       goto error;
+     } else if (init_type == INIT_SKEY) {
+	  if (pass) {
+	       code = krb5_kt_resolve(ctx, pass, &kt);
+	       if (code)
+		   goto error;
+	  }
+	  code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt,
+					    0, full_svcname, &opt);
+	  if (pass)
+	       krb5_kt_close(ctx, kt);
+	  if (code)
+	       goto error;
+     } else if (init_type == INIT_CREDS) {
+	  mcreds.client = client;
+	  code = krb5_parse_name(ctx, full_svcname, &mcreds.server);
+	  if (code)
+	       goto error;
+	  code = krb5_cc_retrieve_cred(ctx, ccache, 0,
+				       &mcreds, &outcreds);
+	  krb5_free_principal(ctx, mcreds.server);
+	  if (code)
+	       goto error;
+     }
+     if (init_type != INIT_CREDS) {
+	  /* Caller has initialized ccache. */
+	  code = krb5_cc_store_cred(ctx, ccache, &outcreds);
+	  if (code)
+	       goto error;
+     }
+error:
+     krb5_free_cred_contents(ctx, &outcreds);
+     return code;
+}
+
+/*
+ * kadm5_setup_gss
+ *
+ * Acquire GSSAPI credentials and set up RPC auth flavor.
+ */
+static kadm5_ret_t
+kadm5_setup_gss(kadm5_server_handle_t handle,
+		kadm5_config_params *params_in,
+		char *client_name, char *full_svcname)
+{
+     kadm5_ret_t code;
+     OM_uint32 gssstat, minor_stat;
+     gss_buffer_desc buf;
+     gss_name_t gss_client;
+     gss_name_t gss_target;
+     gss_cred_id_t gss_client_creds;
+     const char *c_ccname_orig;
+     char *ccname_orig;
+
+     code = KADM5_GSS_ERROR;
+     gss_client_creds = GSS_C_NO_CREDENTIAL;
+     ccname_orig = NULL;
+
+     /* Temporarily use the kadm5 cache. */
+     gssstat = gss_krb5_ccache_name(&minor_stat, handle->cache_name,
+				    &c_ccname_orig);
+     if (gssstat != GSS_S_COMPLETE) {
+	  code = KADM5_GSS_ERROR;
+	  goto error;
+     }
+     if (c_ccname_orig)
+	  ccname_orig = strdup(c_ccname_orig);
+     else
+	  ccname_orig = 0;
+
+     buf.value = full_svcname;
+     buf.length = strlen((char *)buf.value) + 1;
+     gssstat = gss_import_name(&minor_stat, &buf,
+			       (gss_OID) gss_nt_krb5_name, &gss_target);
+     if (gssstat != GSS_S_COMPLETE) {
+	  code = KADM5_GSS_ERROR;
+	  goto error;
+     }
+
+     buf.value = client_name;
+     buf.length = strlen((char *)buf.value) + 1;
+     gssstat = gss_import_name(&minor_stat, &buf,
+			       (gss_OID) gss_nt_krb5_name, &gss_client);
+     if (gssstat != GSS_S_COMPLETE) {
+	  code = KADM5_GSS_ERROR;
+	  goto error;
+     }
+
+     gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
+				GSS_C_NULL_OID_SET, GSS_C_INITIATE,
+				&gss_client_creds, NULL, NULL);
+     if (gssstat != GSS_S_COMPLETE) {
+	  code = KADM5_GSS_ERROR;
+	  goto error;
+     }
+
+     /*
+      * Do actual creation of RPC auth handle.  Implements auth flavor
+      * fallback.
+      */
+     kadm5_rpc_auth(handle, params_in, gss_client_creds, gss_target);
+
+error:
+     if (gss_client_creds != GSS_C_NO_CREDENTIAL)
+	  (void) gss_release_cred(&minor_stat, &gss_client_creds);
+
+     if (gss_client)
+	  gss_release_name(&minor_stat, &gss_client);
+     if (gss_target)
+	  gss_release_name(&minor_stat, &gss_target);
+
+     /* Revert to prior gss_krb5 ccache. */
+     if (ccname_orig) {
+	 gssstat = gss_krb5_ccache_name(&minor_stat, ccname_orig, NULL);
+	 if (gssstat) {
+	     return KADM5_GSS_ERROR;
+	 }
+	 free(ccname_orig);
+     } else {
+	 gssstat = gss_krb5_ccache_name(&minor_stat, NULL, NULL);
+	 if (gssstat) {
+	     return KADM5_GSS_ERROR;
+	 }
+     }
+
+     if (handle->clnt->cl_auth == NULL) {
+	  return KADM5_GSS_ERROR;
+     }
+     return 0;
+}
+
+/*
+ * kadm5_rpc_auth
+ *
+ * Create RPC auth handle.  Do auth flavor fallback if needed.
+ */
+static void
+kadm5_rpc_auth(kadm5_server_handle_t handle,
+	       kadm5_config_params *params_in,
+	       gss_cred_id_t gss_client_creds,
+	       gss_name_t gss_target)
+{
+     OM_uint32 gssstat, minor_stat;
+     struct rpc_gss_sec sec;
+
+     /* Allow unauthenticated option for testing. */
+     if (params_in != NULL && (params_in->mask & KADM5_CONFIG_NO_AUTH))
+	  return;
+
+     /* Use RPCSEC_GSS by default. */
+     if (params_in == NULL ||
+	 !(params_in->mask & KADM5_CONFIG_OLD_AUTH_GSSAPI)) {
+	  sec.mech = gss_mech_krb5;
+	  sec.qop = GSS_C_QOP_DEFAULT;
+	  sec.svc = RPCSEC_GSS_SVC_PRIVACY;
+	  sec.cred = gss_client_creds;
+	  sec.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
+
+	  handle->clnt->cl_auth = authgss_create(handle->clnt,
+						 gss_target, &sec);
+	  if (handle->clnt->cl_auth != NULL)
+	       return;
+     }
+
+     if (params_in != NULL && (params_in->mask & KADM5_CONFIG_AUTH_NOFALLBACK))
+	  return;
+
+     /* Fall back to old AUTH_GSSAPI. */
+     handle->clnt->cl_auth = auth_gssapi_create(handle->clnt,
+						&gssstat,
+						&minor_stat,
+						gss_client_creds,
+						gss_target,
+						(gss_OID) gss_mech_krb5,
+						GSS_C_MUTUAL_FLAG
+						| GSS_C_REPLAY_FLAG,
+						0, NULL, NULL, NULL);
+}
+
+kadm5_ret_t
+kadm5_destroy(void *server_handle)
+{
+     krb5_ccache	    ccache = NULL;
+     int		    code = KADM5_OK;
+     kadm5_server_handle_t	handle =
+	  (kadm5_server_handle_t) server_handle;
+
+     CHECK_HANDLE(server_handle);
+
+     if (handle->destroy_cache && handle->cache_name) {
+	 if ((code = krb5_cc_resolve(handle->context,
+				     handle->cache_name, &ccache)) == 0) 
+	     code = krb5_cc_destroy (handle->context, ccache);
+     }
+     if (handle->cache_name)
+	 free(handle->cache_name);
+     if (handle->clnt && handle->clnt->cl_auth)
+	  AUTH_DESTROY(handle->clnt->cl_auth);
+     if (handle->clnt)
+	  clnt_destroy(handle->clnt);
+     if (handle->lhandle)
+          free (handle->lhandle);
+
+     kadm5_free_config_params(handle->context, &handle->params);
+     krb5_free_context(handle->context);
+
+     handle->magic_number = 0;
+     free(handle);
+
+     return code;
+}
+/* not supported on client */
+kadm5_ret_t kadm5_lock(void *server_handle)
+{
+    return EINVAL;
+}
+
+/* not supported on client */
+kadm5_ret_t kadm5_unlock(void *server_handle)
+{
+    return EINVAL;
+}
+
+kadm5_ret_t kadm5_flush(void *server_handle)
+{
+     return KADM5_OK;
+}
+
+int _kadm5_check_handle(void *handle)
+{
+     CHECK_HANDLE(handle);
+     return 0;
+}
diff --git a/mechglue/src/lib/kadm5/clnt/client_internal.h b/mechglue/src/lib/kadm5/clnt/client_internal.h
new file mode 100644
index 000000000..c5ebfec77
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/client_internal.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ * 
+ * $Log$
+ * Revision 1.1  1996/07/24 22:22:43  tlyu
+ * 	* Makefile.in, configure.in: break out client lib into a
+ * 		subdirectory
+ *
+ * Revision 1.11  1996/07/22 20:35:46  marc
+ * this commit includes all the changes on the OV_9510_INTEGRATION and
+ * OV_MERGE branches.  This includes, but is not limited to, the new openvision
+ * admin system, and major changes to gssapi to add functionality, and bring
+ * the implementation in line with rfc1964.  before committing, the
+ * code was built and tested for netbsd and solaris.
+ *
+ * Revision 1.10.4.1  1996/07/18 03:08:37  marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.10.2.1  1996/06/20  02:16:46  marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.10  1996/06/06  20:09:16  bjaspan
+ * add destroy_cache, for kadm5_init_with_creds
+ *
+ * Revision 1.9  1996/05/30 21:04:42  bjaspan
+ * add lhandle to handle
+ *
+ * Revision 1.8  1996/05/28 20:33:49  bjaspan
+ * rework kadm5_config
+ *
+ * Revision 1.7  1996/05/17 21:36:59  bjaspan
+ * rename to kadm5, begin implementing version 2
+ *
+ * Revision 1.6  1996/05/16 21:45:07  bjaspan
+ * add context
+ *
+ * Revision 1.5  1996/05/08 21:10:23  bjaspan
+ * marc's changes
+ *
+ * Revision 1.4  1996/01/16  20:54:30  grier
+ * secure/3570 use krb5_ui_4 not unsigned int
+ *
+ * Revision 1.3  1995/11/14  17:48:57  grier
+ * long to int
+ *
+ * Revision 1.2  1994/08/16  18:53:47  jik
+ * Versioning stuff.
+ *
+ * Revision 1.1  1994/08/09  21:14:38  jik
+ * Initial revision
+ *
+ */
+
+/*
+ * This header file is used internally by the Admin API client
+ * libraries.  IF YOU THINK YOU NEED TO USE THIS FILE FOR ANYTHING,
+ * YOU'RE ALMOST CERTAINLY WRONG.
+ */
+
+#ifndef __KADM5_CLIENT_INTERNAL_H__
+#define __KADM5_CLIENT_INTERNAL_H__
+
+#include "admin_internal.h"
+
+typedef struct _kadm5_server_handle_t {
+	krb5_ui_4	magic_number;
+	krb5_ui_4	struct_version;
+	krb5_ui_4	api_version;
+	char *		cache_name;
+	int		destroy_cache;
+	CLIENT *	clnt;
+	krb5_context	context;
+	kadm5_config_params params;
+	struct _kadm5_server_handle_t *lhandle;
+} kadm5_server_handle_rec, *kadm5_server_handle_t;
+
+#define CLIENT_CHECK_HANDLE(handle) \
+{ \
+	kadm5_server_handle_t srvr = \
+	     (kadm5_server_handle_t) handle; \
+ \
+	if (! srvr->clnt) \
+	     return KADM5_BAD_SERVER_HANDLE; \
+	if (! srvr->cache_name) \
+	     return KADM5_BAD_SERVER_HANDLE; \
+	if (! srvr->lhandle) \
+	     return KADM5_BAD_SERVER_HANDLE; \
+}
+
+#define CHECK_HANDLE(handle) \
+     GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION, \
+			  KADM5_NEW_LIB_API_VERSION) \
+     CLIENT_CHECK_HANDLE(handle)
+
+#endif /* __KADM5_CLIENT_INTERNAL_H__ */
diff --git a/mechglue/src/lib/kadm5/clnt/client_principal.c b/mechglue/src/lib/kadm5/clnt/client_principal.c
new file mode 100644
index 000000000..735d2bfc9
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/client_principal.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include    <gssrpc/rpc.h>
+#include    <kadm5/admin.h>
+#include    <kadm5/kadm_rpc.h>
+#ifdef HAVE_MEMORY_H
+#include    <memory.h>
+#endif
+#include    <errno.h>
+#include    "client_internal.h"
+#include    "err_handle.h"
+
+#ifdef DEBUG
+#define eret() do { clnt_perror(handle->clnt, "null ret"); return KADM5_RPC_ERROR; } while (0)
+#else
+#define eret() do { return KADM5_RPC_ERROR; } while (0)
+#endif
+
+kadm5_ret_t
+kadm5_create_principal(void *server_handle,
+			    kadm5_principal_ent_t princ, long mask,
+			    char *pw)
+{
+    generic_ret		*r;
+    cprinc_arg		arg;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    memset(&arg, 0, sizeof(arg));
+    arg.mask = mask;
+    arg.passwd = pw;
+    arg.api_version = handle->api_version;
+
+    if(princ == NULL)
+	return EINVAL;
+
+    if (handle->api_version == KADM5_API_VERSION_1) {
+       memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1));
+    } else {
+       memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec));
+    }
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 /*
+	  * hack hack cough cough.
+	  * krb5_unparse name dumps core if we pass it in garbage
+	  * or null. So, since the client is not allowed to set mod_name
+	  * anyway, we just fill it in with a dummy principal. The server of
+	  * course ignores this.
+	  */
+	 krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name);
+    } else
+	 arg.rec.mod_name = NULL;
+    
+    if(!(mask & KADM5_POLICY))
+	arg.rec.policy = NULL;
+    if (! (mask & KADM5_KEY_DATA)) {
+	 arg.rec.n_key_data = 0;
+	 arg.rec.key_data = NULL;
+    }
+    if (! (mask & KADM5_TL_DATA)) {
+	 arg.rec.n_tl_data = 0;
+	 arg.rec.tl_data = NULL;
+    }
+	 
+    r = create_principal_2(&arg, handle->clnt);
+
+    if (handle->api_version == KADM5_API_VERSION_1)
+	 krb5_free_principal(handle->context, arg.rec.mod_name);
+
+    if(r == NULL)
+	eret();
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_create_principal_3(void *server_handle,
+			 kadm5_principal_ent_t princ, long mask,
+			 int n_ks_tuple,
+			 krb5_key_salt_tuple *ks_tuple,
+			 char *pw)
+{
+    generic_ret		*r;
+    cprinc3_arg		arg;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    memset(&arg, 0, sizeof(arg));
+    arg.mask = mask;
+    arg.passwd = pw;
+    arg.api_version = handle->api_version;
+    arg.n_ks_tuple = n_ks_tuple;
+    arg.ks_tuple = ks_tuple;
+
+    if(princ == NULL)
+	return EINVAL;
+
+    if (handle->api_version == KADM5_API_VERSION_1) {
+       memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1));
+    } else {
+       memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec));
+    }
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 /*
+	  * hack hack cough cough.
+	  * krb5_unparse name dumps core if we pass it in garbage
+	  * or null. So, since the client is not allowed to set mod_name
+	  * anyway, we just fill it in with a dummy principal. The server of
+	  * course ignores this.
+	  */
+	 krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name);
+    } else
+	 arg.rec.mod_name = NULL;
+    
+    if(!(mask & KADM5_POLICY))
+	arg.rec.policy = NULL;
+    if (! (mask & KADM5_KEY_DATA)) {
+	 arg.rec.n_key_data = 0;
+	 arg.rec.key_data = NULL;
+    }
+    if (! (mask & KADM5_TL_DATA)) {
+	 arg.rec.n_tl_data = 0;
+	 arg.rec.tl_data = NULL;
+    }
+	 
+    r = create_principal3_2(&arg, handle->clnt);
+
+    if (handle->api_version == KADM5_API_VERSION_1)
+	 krb5_free_principal(handle->context, arg.rec.mod_name);
+
+    if(r == NULL)
+	eret();
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_delete_principal(void *server_handle, krb5_principal principal)
+{
+    dprinc_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if(principal == NULL)
+	return EINVAL;
+    arg.princ = principal;
+    arg.api_version = handle->api_version;
+    r = delete_principal_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();    
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_modify_principal(void *server_handle,
+			    kadm5_principal_ent_t princ, long mask)
+{
+    mprinc_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    memset(&arg, 0, sizeof(arg));
+    arg.mask = mask;
+    arg.api_version = handle->api_version;
+    /*
+     * cough cough gag gag
+     * see comment in create_principal.
+     */
+    if(princ == NULL)
+	return EINVAL;
+    if (handle->api_version == KADM5_API_VERSION_1) {
+        memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1));
+    } else {
+        memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec));
+    }
+    if(!(mask & KADM5_POLICY))
+	arg.rec.policy = NULL;
+    if (! (mask & KADM5_KEY_DATA)) {
+	 arg.rec.n_key_data = 0;
+	 arg.rec.key_data = NULL;
+    }
+    if (! (mask & KADM5_TL_DATA)) {
+	 arg.rec.n_tl_data = 0;
+	 arg.rec.tl_data = NULL;
+    }
+
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 /*
+	  * See comment in create_principal
+	  */
+	 krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name);
+    } else
+	 arg.rec.mod_name = NULL;
+    
+    r = modify_principal_2(&arg, handle->clnt);
+
+    if (handle->api_version == KADM5_API_VERSION_1)
+	 krb5_free_principal(handle->context, arg.rec.mod_name);    
+
+    if(r == NULL)
+	eret();    
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_get_principal(void *server_handle,
+		    krb5_principal princ, kadm5_principal_ent_t ent,
+		    long mask)
+{
+    gprinc_arg	arg;
+    gprinc_ret	*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if(princ == NULL)
+	return EINVAL;
+    arg.princ = princ;
+    if (handle->api_version == KADM5_API_VERSION_1)
+       arg.mask = KADM5_PRINCIPAL_NORMAL_MASK;
+    else
+       arg.mask = mask;
+    arg.api_version = handle->api_version;
+    r = get_principal_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 kadm5_principal_ent_t_v1 *entp;
+
+	 entp = (kadm5_principal_ent_t_v1 *) ent;
+	 if (r->code == 0) {
+	      if (!(*entp = (kadm5_principal_ent_t_v1)
+		    malloc(sizeof(kadm5_principal_ent_rec_v1))))
+		   return ENOMEM;
+	      /* this memcpy works because the v1 structure is an initial
+		 subset of the v2 struct.  C guarantees that this will
+		 result in the same layout in memory */
+	      memcpy(*entp, &r->rec, sizeof(**entp));
+	 } else {
+	    *entp = NULL;
+	 }
+    } else {
+	 if (r->code == 0)
+	      memcpy(ent, &r->rec, sizeof(r->rec));
+    }
+    
+
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_get_principals(void *server_handle,
+			  char *exp, char ***princs, int *count)
+{
+    gprincs_arg	arg;
+    gprincs_ret	*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if(princs == NULL || count == NULL)
+	return EINVAL;
+    arg.exp = exp;
+    arg.api_version = handle->api_version;
+    r = get_princs_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();
+    if(r->code == 0) {
+	 *count = r->count;
+	 *princs = r->princs;
+    } else {
+	 *count = 0;
+	 *princs = NULL;
+    }
+    
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_rename_principal(void *server_handle,
+			    krb5_principal source, krb5_principal dest)
+{
+    rprinc_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.src = source;
+    arg.dest = dest;
+    arg.api_version = handle->api_version;
+    if (source == NULL || dest == NULL)
+	return EINVAL;
+    r = rename_principal_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();        
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_chpass_principal(void *server_handle,
+			    krb5_principal princ, char *password)
+{
+    chpass_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.princ = princ;
+    arg.pass = password;
+    arg.api_version = handle->api_version;
+
+    if(princ == NULL)
+	return EINVAL;
+    r = chpass_principal_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();        
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_chpass_principal_3(void *server_handle,
+			 krb5_principal princ, krb5_boolean keepold,
+			 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
+			 char *password)
+{
+    chpass3_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.princ = princ;
+    arg.pass = password;
+    arg.api_version = handle->api_version;
+    arg.keepold = keepold;
+    arg.n_ks_tuple = n_ks_tuple;
+    arg.ks_tuple = ks_tuple;
+
+    if(princ == NULL)
+	return EINVAL;
+    r = chpass_principal3_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();        
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_setv4key_principal(void *server_handle,
+			 krb5_principal princ,
+			 krb5_keyblock *keyblock)
+{
+    setv4key_arg	arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.princ = princ;
+    arg.keyblock = keyblock;
+    arg.api_version = handle->api_version;
+
+    if(princ == NULL || keyblock == NULL)
+	return EINVAL;
+    r = setv4key_principal_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();        
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_setkey_principal(void *server_handle,
+		       krb5_principal princ,
+		       krb5_keyblock *keyblocks,
+		       int n_keys)
+{
+    setkey_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.princ = princ;
+    arg.keyblocks = keyblocks;
+    arg.n_keys = n_keys;
+    arg.api_version = handle->api_version;
+
+    if(princ == NULL || keyblocks == NULL)
+	return EINVAL;
+    r = setkey_principal_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();        
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_setkey_principal_3(void *server_handle,
+			 krb5_principal princ,
+			 krb5_boolean keepold, int n_ks_tuple,
+			 krb5_key_salt_tuple *ks_tuple,
+			 krb5_keyblock *keyblocks,
+			 int n_keys)
+{
+    setkey3_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.princ = princ;
+    arg.keyblocks = keyblocks;
+    arg.n_keys = n_keys;
+    arg.api_version = handle->api_version;
+    arg.keepold = keepold;
+    arg.n_ks_tuple = n_ks_tuple;
+    arg.ks_tuple = ks_tuple;
+
+    if(princ == NULL || keyblocks == NULL)
+	return EINVAL;
+    r = setkey_principal3_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();        
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_randkey_principal_3(void *server_handle,
+			  krb5_principal princ,
+			  krb5_boolean keepold, int n_ks_tuple,
+			  krb5_key_salt_tuple *ks_tuple,
+			  krb5_keyblock **key, int *n_keys)
+{
+    chrand3_arg		arg;
+    chrand_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+    int			i, ret;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.princ = princ;
+    arg.api_version = handle->api_version;
+    arg.keepold = keepold;
+    arg.n_ks_tuple = n_ks_tuple;
+    arg.ks_tuple = ks_tuple;
+
+    if(princ == NULL)
+	return EINVAL;
+    r = chrand_principal3_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 if (key)
+	      krb5_copy_keyblock(handle->context, &r->key, key);
+    } else {
+	 if (n_keys)
+	      *n_keys = r->n_keys;
+	 if (key) {
+	      if(r->n_keys) {
+		      *key = (krb5_keyblock *) 
+			      malloc(r->n_keys*sizeof(krb5_keyblock));
+		      if (*key == NULL)
+			      return ENOMEM;
+		      for (i = 0; i < r->n_keys; i++) {
+			      ret = krb5_copy_keyblock_contents(handle->context,
+								&r->keys[i],
+								&(*key)[i]);
+			      if (ret) {
+				      free(*key);
+				      return ENOMEM;
+			      }
+		      }
+	      } else *key = NULL;
+         }
+    }
+
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_randkey_principal(void *server_handle,
+			krb5_principal princ,
+			krb5_keyblock **key, int *n_keys)
+{
+    chrand_arg		arg;
+    chrand_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+    int			i, ret;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.princ = princ;
+    arg.api_version = handle->api_version;
+
+    if(princ == NULL)
+	return EINVAL;
+    r = chrand_principal_2(&arg, handle->clnt);
+    if(r == NULL)
+	eret();
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 if (key)
+	      krb5_copy_keyblock(handle->context, &r->key, key);
+    } else {
+	 if (n_keys)
+	      *n_keys = r->n_keys;
+	 if (key) {
+	      if(r->n_keys) {
+		      *key = (krb5_keyblock *) 
+			      malloc(r->n_keys*sizeof(krb5_keyblock));
+		      if (*key == NULL)
+			      return ENOMEM;
+		      for (i = 0; i < r->n_keys; i++) {
+			      ret = krb5_copy_keyblock_contents(handle->context,
+								&r->keys[i],
+								&(*key)[i]);
+			      if (ret) {
+				      free(*key);
+				      return ENOMEM;
+			      }
+		      }
+	      } else *key = NULL;
+         }
+    }
+
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+
+    return r->code;
+}
+
+/* not supported on client side */
+kadm5_ret_t kadm5_decrypt_key(void *server_handle,
+			      kadm5_principal_ent_t entry, krb5_int32
+			      ktype, krb5_int32 stype, krb5_int32
+			      kvno, krb5_keyblock *keyblock,
+			      krb5_keysalt *keysalt, int *kvnop)
+{
+     return EINVAL;
+}
diff --git a/mechglue/src/lib/kadm5/clnt/client_rpc.c b/mechglue/src/lib/kadm5/clnt/client_rpc.c
new file mode 100644
index 000000000..768d8265f
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/client_rpc.c
@@ -0,0 +1,307 @@
+#include <gssrpc/rpc.h>
+#include <kadm5/kadm_rpc.h>
+#include <krb5.h>
+#include <kadm5/admin.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+generic_ret *
+create_principal_2(argp, clnt)
+	cprinc_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, CREATE_PRINCIPAL, xdr_cprinc_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+create_principal3_2(argp, clnt)
+	cprinc3_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, CREATE_PRINCIPAL3, xdr_cprinc3_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+delete_principal_2(argp, clnt)
+	dprinc_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, DELETE_PRINCIPAL, xdr_dprinc_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+modify_principal_2(argp, clnt)
+	mprinc_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, MODIFY_PRINCIPAL, xdr_mprinc_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+rename_principal_2(argp, clnt)
+	rprinc_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, RENAME_PRINCIPAL, xdr_rprinc_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+gprinc_ret *
+get_principal_2(argp, clnt)
+	gprinc_arg *argp;
+	CLIENT *clnt;
+{
+	static gprinc_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, GET_PRINCIPAL, xdr_gprinc_arg, argp, xdr_gprinc_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+gprincs_ret *
+get_princs_2(argp, clnt)
+	gprincs_arg *argp;
+	CLIENT *clnt;
+{
+	static gprincs_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, GET_PRINCS, xdr_gprincs_arg, argp,
+		      xdr_gprincs_ret, &res, TIMEOUT) != RPC_SUCCESS) { 
+	     return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+chpass_principal_2(argp, clnt)
+	chpass_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, CHPASS_PRINCIPAL, xdr_chpass_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+chpass_principal3_2(argp, clnt)
+	chpass3_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, CHPASS_PRINCIPAL3, xdr_chpass3_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+setv4key_principal_2(argp, clnt)
+	setv4key_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, SETV4KEY_PRINCIPAL, xdr_setv4key_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+setkey_principal_2(argp, clnt)
+	setkey_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, SETKEY_PRINCIPAL, xdr_setkey_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+setkey_principal3_2(argp, clnt)
+	setkey3_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, SETKEY_PRINCIPAL3, xdr_setkey3_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+chrand_ret *
+chrand_principal_2(argp, clnt)
+	chrand_arg *argp;
+	CLIENT *clnt;
+{
+	static chrand_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, CHRAND_PRINCIPAL, xdr_chrand_arg, argp, xdr_chrand_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+chrand_ret *
+chrand_principal3_2(argp, clnt)
+	chrand3_arg *argp;
+	CLIENT *clnt;
+{
+	static chrand_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, CHRAND_PRINCIPAL3, xdr_chrand3_arg, argp, xdr_chrand_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+create_policy_2(argp, clnt)
+	cpol_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, CREATE_POLICY, xdr_cpol_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+delete_policy_2(argp, clnt)
+	dpol_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, DELETE_POLICY, xdr_dpol_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
+modify_policy_2(argp, clnt)
+	mpol_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, MODIFY_POLICY, xdr_mpol_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+gpol_ret *
+get_policy_2(argp, clnt)
+	gpol_arg *argp;
+	CLIENT *clnt;
+{
+	static gpol_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, GET_POLICY, xdr_gpol_arg, argp, xdr_gpol_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+gpols_ret *
+get_pols_2(argp, clnt)
+	gpols_arg *argp;
+	CLIENT *clnt;
+{
+	static gpols_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, GET_POLS, xdr_gpols_arg, argp,
+		      xdr_gpols_ret, &res, TIMEOUT) != RPC_SUCCESS) { 
+	     return (NULL);
+	}
+	return (&res);
+}
+
+getprivs_ret *get_privs_2(argp, clnt)
+   void *argp;
+   CLIENT *clnt;
+{
+     static getprivs_ret res;
+
+     memset((char *)&res, 0, sizeof(res));
+     if (clnt_call(clnt, GET_PRIVS, xdr_u_int32, argp,
+		   xdr_getprivs_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+	  return (NULL);
+     }
+     return (&res);
+}
+
+generic_ret *
+init_2(argp, clnt)
+   void *argp;
+   CLIENT *clnt;
+{
+     static generic_ret res;
+
+     memset((char *)&res, 0, sizeof(res));
+     if (clnt_call(clnt, INIT, xdr_u_int32, argp,
+		   xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+	  return (NULL);
+     }
+     return (&res);
+}
diff --git a/mechglue/src/lib/kadm5/clnt/clnt_chpass_util.c b/mechglue/src/lib/kadm5/clnt/clnt_chpass_util.c
new file mode 100644
index 000000000..71ab64937
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/clnt_chpass_util.c
@@ -0,0 +1,16 @@
+#include <kadm5/admin.h>
+#include "client_internal.h"
+
+kadm5_ret_t kadm5_chpass_principal_util(void *server_handle,
+					krb5_principal princ,
+					char *new_pw, 
+					char **ret_pw,
+					char *msg_ret,
+					unsigned int msg_len)
+{
+  kadm5_server_handle_t handle = server_handle;
+
+  CHECK_HANDLE(server_handle);
+  return _kadm5_chpass_principal_util(handle, handle->lhandle, princ,
+				      new_pw, ret_pw, msg_ret, msg_len);
+}
diff --git a/mechglue/src/lib/kadm5/clnt/clnt_policy.c b/mechglue/src/lib/kadm5/clnt/clnt_policy.c
new file mode 100644
index 000000000..b1157d1e7
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/clnt_policy.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include    <gssrpc/rpc.h>
+#include    <kadm5/admin.h>
+#include    <kadm5/kadm_rpc.h>
+#include    "client_internal.h"
+#include	<stdlib.h>
+#include	<string.h>
+#include	<errno.h>
+#include    "err_handle.h"
+
+kadm5_ret_t
+kadm5_create_policy(void *server_handle,
+			 kadm5_policy_ent_t policy, long mask)
+{
+    cpol_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if(policy == (kadm5_policy_ent_t) NULL)
+	return EINVAL;
+
+    arg.mask = mask;
+    arg.api_version = handle->api_version;
+    memcpy(&arg.rec, policy, sizeof(kadm5_policy_ent_rec));
+    r = create_policy_2(&arg, handle->clnt);
+    if(r == NULL)
+	return KADM5_RPC_ERROR;    
+
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_delete_policy(void *server_handle, char *name)
+{
+    dpol_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+	 
+    CHECK_HANDLE(server_handle);
+
+    if(name == NULL)
+	return EINVAL;
+
+    arg.name = name;
+    arg.api_version = handle->api_version;
+
+    r = delete_policy_2(&arg, handle->clnt);
+    if(r == NULL)
+	return KADM5_RPC_ERROR;    
+
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_modify_policy(void *server_handle,
+			 kadm5_policy_ent_t policy, long mask)
+{
+    mpol_arg		arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if(policy == (kadm5_policy_ent_t) NULL)
+	return EINVAL;
+	
+    arg.mask = mask;
+    arg.api_version = handle->api_version;
+
+    memcpy(&arg.rec, policy, sizeof(kadm5_policy_ent_rec));
+    r = modify_policy_2(&arg, handle->clnt);
+    if(r == NULL)
+	return KADM5_RPC_ERROR;    
+
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_get_policy(void *server_handle, char *name, kadm5_policy_ent_t ent)
+{
+    gpol_arg	    arg;
+    gpol_ret	    *r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    arg.name = name;
+    arg.api_version = handle->api_version;
+
+    if(name == NULL)
+	return EINVAL;
+	
+    r = get_policy_2(&arg, handle->clnt);
+    if(r == NULL)
+	return KADM5_RPC_ERROR;
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 kadm5_policy_ent_t *entp;
+
+	 entp = (kadm5_policy_ent_t *) ent;
+	 if(r->code == 0) {
+	      if (!(*entp = (kadm5_policy_ent_t)
+		    malloc(sizeof(kadm5_policy_ent_rec))))
+		   return ENOMEM;
+	      memcpy(*entp, &r->rec, sizeof(**entp));
+	 } else {
+	      *entp = NULL;
+	 }
+    } else {
+	 if (r->code == 0)
+	      memcpy(ent, &r->rec, sizeof(r->rec));
+    }
+	 
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+    return r->code;
+}
+
+kadm5_ret_t
+kadm5_get_policies(void *server_handle,
+			  char *exp, char ***pols, int *count)
+{
+    gpols_arg	arg;
+    gpols_ret	*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if(pols == NULL || count == NULL)
+	return EINVAL;
+    arg.exp = exp;
+    arg.api_version = handle->api_version;
+    r = get_pols_2(&arg, handle->clnt);
+    if(r == NULL)
+	return KADM5_RPC_ERROR;
+    if(r->code == 0) {
+	 *count = r->count;
+	 *pols = r->pols;
+    } else {
+	 *count = 0;
+	 *pols = NULL;
+    }
+    
+    if(r->code)
+    {
+	krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+    }
+    return r->code;
+}
diff --git a/mechglue/src/lib/kadm5/clnt/clnt_privs.c b/mechglue/src/lib/kadm5/clnt/clnt_privs.c
new file mode 100644
index 000000000..e594080a8
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/clnt_privs.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ * 
+ * $Log$
+ * Revision 1.4  2005/08/20 09:14:59  raeburn
+ * Rename all RPC functions from _1 to _2 to match current program version number;
+ * likewise _1_svc to _2_svc in the kadmin server.  Delete the RPC functions from
+ * the libkadm5clnt export list.
+ *
+ * Revision 1.3  2005/06/21 01:35:56  raeburn
+ * Novell Database Abstraction Layer merge.
+ * Will probably break things.
+ *
+ * Revision 1.2.26.1  2005/06/17 21:11:24  raeburn
+ * Initial checkin of Novell Database Abstraction Layer changes.
+ * Patches applied to 1.4.1 release code, updated to trunk, makefile dependencies
+ * deleted when they caused cvs merge conflicts.
+ *
+ * Revision 1.2  1998/02/14 02:32:58  tlyu
+ * 	* client_init.c:
+ * 	* client_principal.c:
+ * 	* client_rpc.c:
+ * 	* clnt_policy.c:
+ * 	* clnt_privs.c: Update header locations.
+ *
+ * 	* Makefile.in (LIBMAJOR): Bump major version to reflect change in
+ * 	rpc library.
+ *
+ * Revision 1.1  1996/07/24 22:22:48  tlyu
+ * 	* Makefile.in, configure.in: break out client lib into a
+ * 		subdirectory
+ *
+ * Revision 1.6  1996/07/22 20:35:57  marc
+ * this commit includes all the changes on the OV_9510_INTEGRATION and
+ * OV_MERGE branches.  This includes, but is not limited to, the new openvision
+ * admin system, and major changes to gssapi to add functionality, and bring
+ * the implementation in line with rfc1964.  before committing, the
+ * code was built and tested for netbsd and solaris.
+ *
+ * Revision 1.5.4.1  1996/07/18 03:08:45  marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+ * Revision 1.5.2.1  1996/06/20  02:16:53  marc
+ * File added to the repository on a branch
+ *
+ * Revision 1.5  1996/05/17  21:36:50  bjaspan
+ * rename to kadm5, begin implementing version 2
+ *
+ * Revision 1.4  1996/05/16 21:45:51  bjaspan
+ * u_int32 -> long, add krb5_context
+ *
+ * Revision 1.3  1994/09/20 16:25:05  bjaspan
+ * [secure-admin/2436: API versioning fixes to various admin files]
+ * [secure-releng/2502: audit secure-admin/2436: random API versioning fixes]
+ *
+ * Sandbox:
+ *
+ *  Unnecessary variable initialization removed.
+ *
+ * Revision 1.3  1994/09/12  20:26:39  jik
+ * Unnecessary variable initialization removed.
+ *
+ * Revision 1.2  1994/08/16  18:52:02  jik
+ * Versioning changes.
+ *
+ * Revision 1.1  1993/11/10  23:10:39  bjaspan
+ * Initial revision
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include    <gssrpc/rpc.h>
+#include    <kadm5/admin.h>
+#include    <kadm5/kadm_rpc.h>
+#include    "client_internal.h"
+#include    "err_handle.h"
+
+kadm5_ret_t kadm5_get_privs(void *server_handle, long *privs)
+{
+     getprivs_ret *r;
+     kadm5_server_handle_t handle = server_handle;
+
+     r = get_privs_2(&handle->api_version, handle->clnt);
+     if (r == NULL)
+	  return KADM5_RPC_ERROR;
+     else if (r->code == KADM5_OK)
+	  *privs = r->privs;
+
+     if(r->code)
+     {
+	 krb5_set_err( handle->context, krb5_err_have_str, r->code, r->err_str );
+     }
+     return r->code;
+}
diff --git a/mechglue/src/lib/kadm5/clnt/err_handle.c b/mechglue/src/lib/kadm5/clnt/err_handle.c
new file mode 100644
index 000000000..24bf2912e
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/err_handle.c
@@ -0,0 +1,197 @@
+/**********************************************************************
+*
+*	C %name:		err_handle.c %
+*	Instance:		idc_sec_1
+*	Description:	
+*	%created_by:	spradeep %
+*	%date_created:	Thu Apr  7 15:36:27 2005 %
+*
+**********************************************************************/
+#ifndef lint
+static char *_csrc =
+    "@(#) %filespec: err_handle.c~1 %  (%full_filespec: err_handle.c~1:csrc:idc_sec#2 %)";
+#endif
+
+/* This file should be ideally be in util/et.  But, for now thread
+   safety requirement stops me from putting there.  If I do, then all
+   the applications have to link to pthread.  */
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+#include "err_handle.h"
+#include <assert.h>
+
+#ifdef NOVELL
+krb5_errcode_2_string_func old_error_2_string = NULL;
+#endif
+
+typedef struct
+{
+    char    krb5_err_str[KRB5_MAX_ERR_STR + 1];
+    long    err_code;
+    krb5_err_subsystem subsystem;
+    krb5_context kcontext;
+} krb5_err_struct_t;
+
+#ifdef HAVE_PTHREAD_H
+static void
+tsd_key_destructor(void *data)
+{
+    free(data);
+}
+
+static void
+init_err_handling(void)
+{
+    assert(!k5_key_register(K5_KEY_KADM_CLNT_ERR_HANDLER, tsd_key_destructor));
+#ifdef NOVELL
+    old_error_2_string = error_message;
+    error_message = krb5_get_err_string;
+#endif
+}
+
+static pthread_once_t krb5_key_create = PTHREAD_ONCE_INIT;
+
+krb5_error_code
+krb5_set_err(krb5_context kcontext, krb5_err_subsystem subsystem,
+	     long err_code, char *str)
+{
+    int     ret;
+    krb5_err_struct_t *err_struct;
+    pthread_once(&krb5_key_create, init_err_handling);
+
+    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KADM_CLNT_ERR_HANDLER);
+    if (err_struct == NULL) {
+	err_struct = calloc(sizeof(krb5_err_struct_t), 1);
+	if (err_struct == NULL)
+	    return ENOMEM;
+
+	if ((ret = k5_setspecific(K5_KEY_KADM_CLNT_ERR_HANDLER, err_struct))) {
+	    free(err_struct);
+	    return ret;
+	}
+    }
+
+    err_struct->subsystem = subsystem;
+    err_struct->err_code = err_code;
+    err_struct->kcontext = kcontext;
+    if (err_struct->subsystem == krb5_err_have_str) {
+	strncpy(err_struct->krb5_err_str, str,
+		sizeof(err_struct->krb5_err_str));
+	err_struct->krb5_err_str[KRB5_MAX_ERR_STR] = '\0';
+    }
+
+    return 0;
+}
+
+const char *KRB5_CALLCONV
+krb5_get_err_string(long err_code)
+{
+    krb5_err_struct_t *err_struct;
+    pthread_once(&krb5_key_create, init_err_handling);
+
+    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KADM_CLNT_ERR_HANDLER);
+    if (err_struct && (err_struct->subsystem == krb5_err_have_str)
+	&& (err_code == err_struct->err_code)) {
+	/* checking error code is for safety.
+	   In case, the caller ignores a database error and calls
+	   other calls before doing com_err.  Though not perfect,
+	   caller should call krb5_clr_error before this.  */
+	err_struct->subsystem = krb5_err_unknown;
+	return err_struct->krb5_err_str;
+    }
+
+    /* Error strings are not generated here. the remaining two cases
+       are handled by the default error string convertor.  */
+#ifdef NOVELL
+    return old_error_2_string(err_code);
+#else
+    return error_message(err_code);
+#endif
+}
+
+void
+krb5_clr_error()
+{
+    krb5_err_struct_t *err_struct;
+    pthread_once(&krb5_key_create, init_err_handling);
+
+    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KADM_CLNT_ERR_HANDLER);
+    if (err_struct)
+	err_struct->subsystem = krb5_err_unknown;
+}
+
+#else
+krb5_err_struct_t krb5_err = { {0}, 0, 0, 0 };
+krb5_boolean krb5_init_once = TRUE;
+
+static void
+init_err_handling(void)
+{
+    if (krb5_init_once) {
+#ifdef NOVELL
+	old_error_2_string = error_message;
+	error_message = krb5_get_err_string;
+#endif
+	krb5_init_once = FALSE;
+    }
+}
+
+krb5_error_code
+krb5_set_err(krb5_context kcontext, krb5_err_subsystem subsystem,
+	     long err_code, char *str)
+{
+    krb5_err_struct_t *err_struct = &krb5_err;
+
+    init_err_handling();	/* takes care for multiple inits */
+
+    err_struct->subsystem = subsystem;
+    err_struct->err_code = err_code;
+    err_struct->kcontext = kcontext;
+    if (err_struct->subsystem == krb5_err_have_str) {
+	strncpy(err_struct->krb5_err_str, str,
+		sizeof(err_struct->krb5_err_str));
+	err_struct->krb5_err_str[KRB5_MAX_ERR_STR] = '\0';
+    }
+
+    return 0;
+}
+
+const char *KRB5_CALLCONV
+krb5_get_err_string(long err_code)
+{
+    krb5_err_struct_t *err_struct = &krb5_err;
+
+    init_err_handling();	/* takes care for multiple inits */
+
+    if ((err_struct->subsystem == krb5_err_have_str)
+	&& (err_code == err_struct->err_code)) {
+	/* checking error code is for safety.
+	   In case, the caller ignores a database error and calls
+	   other calls before doing com_err.  Though not perfect,
+	   caller should call krb5_clr_error before this.  */
+	err_struct->subsystem = krb5_err_unknown;
+	return err_struct->krb5_err_str;
+    }
+
+    /* It is not generated here. the remaining two cases are handled
+       by the default error string convertor.  */
+#ifdef NOVELL
+    return old_error_2_string(err_code);
+#else
+    return error_message(err_code);
+#endif
+}
+
+void
+krb5_clr_error()
+{
+    krb5_err_struct_t *err_struct = &krb5_err;
+
+    init_err_handling();	/* takes care for multiple inits */
+
+    err_struct->subsystem = krb5_err_unknown;
+}
+
+#endif
diff --git a/mechglue/src/lib/kadm5/clnt/err_handle.h b/mechglue/src/lib/kadm5/clnt/err_handle.h
new file mode 100644
index 000000000..7dea7b608
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/err_handle.h
@@ -0,0 +1,38 @@
+/**********************************************************************
+*
+*	C Header:		err_handle.h
+*	Instance:		idc_sec_1
+*	Description:	
+*	%created_by:	spradeep %
+*	%date_created:	Thu Apr  7 15:36:49 2005 %
+*
+**********************************************************************/
+#ifndef _idc_sec_1_err_handle_h_H
+#define _idc_sec_1_err_handle_h_H
+#include <com_err.h>
+#include <krb5.h>
+
+/* Everything else goes here */
+
+#define KRB5_MAX_ERR_STR 1024
+typedef enum krb5_err_subsystem {
+    krb5_err_unknown = 0, /* no error or unknown system. Has to be probed */
+    krb5_err_system,	/* error in system call */
+    krb5_err_krblib,	/* error in kerberos library call, should lookup in the error table */
+    krb5_err_have_str,	/* error message is available in the string */
+    krb5_err_db		/* error is a database error, should be handled by calling DB */
+} krb5_err_subsystem;
+
+typedef krb5_error_code(*krb5_set_err_func_t) (krb5_context,
+					       krb5_err_subsystem, long,
+					       char *);
+
+krb5_error_code krb5_set_err(krb5_context kcontext,
+			     krb5_err_subsystem subsystem, long err_code,
+			     char *str);
+
+const char *KRB5_CALLCONV krb5_get_err_string(long err_code);
+
+void    krb5_clr_error(void);
+
+#endif
diff --git a/mechglue/src/lib/kadm5/clnt/libkadm5clnt.exports b/mechglue/src/lib/kadm5/clnt/libkadm5clnt.exports
new file mode 100644
index 000000000..cb169c410
--- /dev/null
+++ b/mechglue/src/lib/kadm5/clnt/libkadm5clnt.exports
@@ -0,0 +1,130 @@
+_kadm5_check_handle
+_kadm5_chpass_principal_util
+kadm5_chpass_principal
+kadm5_chpass_principal_3
+kadm5_chpass_principal_util
+kadm5_create_policy
+kadm5_create_principal
+kadm5_create_principal_3
+kadm5_decrypt_key
+kadm5_delete_policy
+kadm5_delete_principal
+kadm5_destroy
+kadm5_flush
+kadm5_free_config_params
+kadm5_free_key_data
+kadm5_free_name_list
+kadm5_free_policy_ent
+kadm5_free_principal_ent
+kadm5_get_admin_service_name
+kadm5_get_config_params
+kadm5_get_policies
+kadm5_get_policy
+kadm5_get_principal
+kadm5_get_principals
+kadm5_get_privs
+kadm5_init
+kadm5_init_with_creds
+kadm5_init_with_password
+kadm5_init_with_skey
+kadm5_lock
+kadm5_modify_policy
+kadm5_modify_principal
+kadm5_randkey_principal
+kadm5_randkey_principal_3
+kadm5_rename_principal
+kadm5_setkey_principal
+kadm5_setkey_principal_3
+kadm5_setv4key_principal
+kadm5_unlock
+krb5_aprof_finish
+krb5_aprof_get_boolean
+krb5_aprof_get_deltat
+krb5_aprof_get_int32
+krb5_aprof_get_string
+krb5_aprof_getvals
+krb5_aprof_init
+krb5_flags_to_string
+krb5_free_key_data_contents
+krb5_free_realm_params
+krb5_input_flag_to_string
+krb5_keysalt_is_present
+krb5_keysalt_iterate
+krb5_klog_close
+krb5_klog_init
+krb5_klog_reopen
+krb5_klog_syslog
+krb5_read_realm_params
+krb5_string_to_flags
+krb5_string_to_keysalts
+ovsec_kadm_chpass_principal
+ovsec_kadm_chpass_principal_util
+ovsec_kadm_create_policy
+ovsec_kadm_create_principal
+ovsec_kadm_delete_policy
+ovsec_kadm_delete_principal
+ovsec_kadm_destroy
+ovsec_kadm_flush
+ovsec_kadm_free_name_list
+ovsec_kadm_free_policy_ent
+ovsec_kadm_free_principal_ent
+ovsec_kadm_get_policies
+ovsec_kadm_get_policy
+ovsec_kadm_get_principal
+ovsec_kadm_get_principals
+ovsec_kadm_get_privs
+ovsec_kadm_init
+ovsec_kadm_init_with_password
+ovsec_kadm_init_with_skey
+ovsec_kadm_modify_policy
+ovsec_kadm_modify_principal
+ovsec_kadm_randkey_principal
+ovsec_kadm_rename_principal
+xdr_chpass3_arg
+xdr_chpass_arg
+xdr_chrand3_arg
+xdr_chrand_arg
+xdr_chrand_ret
+xdr_cpol_arg
+xdr_cprinc3_arg
+xdr_cprinc_arg
+xdr_dpol_arg
+xdr_dprinc_arg
+xdr_generic_ret
+xdr_getprivs_ret
+xdr_gpol_arg
+xdr_gpol_ret
+xdr_gpols_arg
+xdr_gpols_ret
+xdr_gprinc_arg
+xdr_gprinc_ret
+xdr_gprincs_arg
+xdr_gprincs_ret
+xdr_kadm5_policy_ent_rec
+xdr_kadm5_principal_ent_rec
+xdr_kadm5_principal_ent_rec_v1
+xdr_kadm5_ret_t
+xdr_krb5_deltat
+xdr_krb5_enctype
+xdr_krb5_flags
+xdr_krb5_int16
+xdr_krb5_key_data_nocontents
+xdr_krb5_key_salt_tuple
+xdr_krb5_keyblock
+xdr_krb5_kvno
+xdr_krb5_octet
+xdr_krb5_principal
+xdr_krb5_salttype
+xdr_krb5_timestamp
+xdr_krb5_tl_data
+xdr_krb5_ui_2
+xdr_krb5_ui_4
+xdr_mpol_arg
+xdr_mprinc_arg
+xdr_nullstring
+xdr_nulltype
+xdr_rprinc_arg
+xdr_setkey3_arg
+xdr_setkey_arg
+xdr_setv4key_arg
+xdr_ui_4
diff --git a/mechglue/src/lib/kadm5/configure.in b/mechglue/src/lib/kadm5/configure.in
new file mode 100644
index 000000000..f9193a3f1
--- /dev/null
+++ b/mechglue/src/lib/kadm5/configure.in
@@ -0,0 +1,23 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+AC_PROG_LEX
+AC_PROG_AWK
+AC_CHECK_HEADERS(syslog.h memory.h)
+AC_CHECK_FUNCS(openlog syslog closelog strftime vsprintf)
+KRB5_AC_REGEX_FUNCS
+dnl The following are tests for the presence of programs required for testing 
+AC_CHECK_PROG(RUNTEST,runtest,runtest)
+AC_CHECK_PROG(PERL,perl,perl)
+AC_CHECK_FUNCS(srand48 srand srandom)
+AC_KRB5_TCL	
+if test "$PERL" = perl -a "$RUNTEST" = runtest -a "$TCL_LIBS" != ""; then
+ 	DO_TEST=ok
+fi
+AC_SUBST(DO_TEST) 
+dnl
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+KRB5_BUILD_PROGRAM
+KRB5_AC_PRIOCNTL_HACK
+dnl
+V5_AC_OUTPUT_MAKEFILE(. clnt srv unit-test)
diff --git a/mechglue/src/lib/kadm5/kadm_err.et b/mechglue/src/lib/kadm5/kadm_err.et
new file mode 100644
index 000000000..da18a74eb
--- /dev/null
+++ b/mechglue/src/lib/kadm5/kadm_err.et
@@ -0,0 +1,63 @@
+# This is the KADM5 error table.  The order of error codes
+# defined in this file MUST match that specified in the API
+# functionality specification, which is the master version.
+#
+error_table ovk
+# vv 0
+error_code KADM5_FAILURE, "Operation failed for unspecified reason"
+error_code KADM5_AUTH_GET, "Operation requires ``get'' privilege"
+error_code KADM5_AUTH_ADD, "Operation requires ``add'' privilege"
+error_code KADM5_AUTH_MODIFY, "Operation requires ``modify'' privilege"
+error_code KADM5_AUTH_DELETE, "Operation requires ``delete'' privilege"
+error_code KADM5_AUTH_INSUFFICIENT, "Insufficient authorization for operation"
+error_code KADM5_BAD_DB, "Database inconsistency detected"
+error_code KADM5_DUP, "Principal or policy already exists"
+error_code KADM5_RPC_ERROR, "Communication failure with server"
+error_code KADM5_NO_SRV, "No administration server found for realm"
+error_code KADM5_BAD_HIST_KEY, "Password history principal key version mismatch"
+error_code KADM5_NOT_INIT, "Connection to server not initialized"
+error_code KADM5_UNK_PRINC, "Principal does not exist"
+error_code KADM5_UNK_POLICY, "Policy does not exist"
+error_code KADM5_BAD_MASK, "Invalid field mask for operation"
+error_code KADM5_BAD_CLASS, "Invalid number of character classes"
+error_code KADM5_BAD_LENGTH, "Invalid password length"
+error_code KADM5_BAD_POLICY, "Illegal policy name"
+error_code KADM5_BAD_PRINCIPAL, "Illegal principal name"
+error_code KADM5_BAD_AUX_ATTR, "Invalid auxillary attributes"
+error_code KADM5_BAD_HISTORY, "Invalid password history count"
+error_code KADM5_BAD_MIN_PASS_LIFE, "Password minimum life is greater than password maximum life"
+error_code KADM5_PASS_Q_TOOSHORT, "Password is too short"
+error_code KADM5_PASS_Q_CLASS, "Password does not contain enough character classes"
+error_code KADM5_PASS_Q_DICT, "Password is in the password dictionary"
+error_code KADM5_PASS_REUSE, "Cannot reuse password"
+error_code KADM5_PASS_TOOSOON, "Current password's minimum life has not expired"
+error_code KADM5_POLICY_REF, "Policy is in use"
+error_code KADM5_INIT,	"Connection to server already initialized"
+error_code KADM5_BAD_PASSWORD, "Incorrect password"
+error_code KADM5_PROTECT_PRINCIPAL, "Cannot change protected principal"
+error_code KADM5_BAD_SERVER_HANDLE, "Programmer error!  Bad Admin server handle"
+error_code KADM5_BAD_STRUCT_VERSION, "Programmer error!  Bad API structure version"
+error_code KADM5_OLD_STRUCT_VERSION, "API structure version specified by application is no longer supported (to fix, recompile application against current KADM5 API header files and libraries)"
+error_code KADM5_NEW_STRUCT_VERSION, "API structure version specified by application is unknown to libraries (to fix, obtain current KADM5 API header files and libraries and recompile application)"
+error_code KADM5_BAD_API_VERSION, "Programmer error!  Bad API version"
+error_code KADM5_OLD_LIB_API_VERSION, "API version specified by application is no longer supported by libraries (to fix, update application to adhere to current API version and recompile)"
+error_code KADM5_OLD_SERVER_API_VERSION, "API version specified by application is no longer supported by server (to fix, update application to adhere to current API version and recompile)"
+error_code KADM5_NEW_LIB_API_VERSION, "API version specified by application is unknown to libraries (to fix, obtain current KADM5 API header files and libraries and recompile application)"
+error_code KADM5_NEW_SERVER_API_VERSION, "API version specified by application is unknown to server (to fix, obtain and install newest KADM5 Admin Server)"
+error_code KADM5_SECURE_PRINC_MISSING, "Database error! Required KADM5 principal missing"
+error_code KADM5_NO_RENAME_SALT, "The salt type of the specified principal does not support renaming"
+error_code KADM5_BAD_CLIENT_PARAMS, "Illegal configuration parameter for remote KADM5 client"
+error_code KADM5_BAD_SERVER_PARAMS, "Illegal configuration parameter for local KADM5 client"
+error_code KADM5_AUTH_LIST, "Operation requires ``list'' privilege"
+error_code KADM5_AUTH_CHANGEPW, "Operation requires ``change-password'' privilege"
+error_code KADM5_GSS_ERROR, "GSS-API (or Kerberos) error"
+error_code KADM5_BAD_TL_TYPE, "Programmer error!  Illegal tagged data list type"
+error_code KADM5_MISSING_CONF_PARAMS, "Required parameters in kdc.conf missing"
+error_code KADM5_BAD_SERVER_NAME, "Bad krb5 admin server hostname"
+error_code KADM5_AUTH_SETKEY, "Operation requires ``set-key'' privilege"
+error_code KADM5_SETKEY_DUP_ENCTYPES, "Multiple values for single or folded enctype"
+error_code KADM5_SETV4KEY_INVAL_ENCTYPE, "Invalid enctype for setv4key"
+error_code KADM5_SETKEY3_ETYPE_MISMATCH, "Mismatched enctypes for setkey3"
+error_code KADM5_MISSING_KRB5_CONF_PARAMS, "Missing parameters in krb5.conf required for kadmin client"
+error_code KADM5_XDR_FAILURE,		"XDR encoding error"
+end
diff --git a/mechglue/src/lib/kadm5/kadm_rpc.h b/mechglue/src/lib/kadm5/kadm_rpc.h
new file mode 100644
index 000000000..3d11f0916
--- /dev/null
+++ b/mechglue/src/lib/kadm5/kadm_rpc.h
@@ -0,0 +1,312 @@
+#ifndef __KADM_RPC_H__
+#define __KADM_RPC_H__
+
+#include <gssrpc/types.h>
+
+#include	<krb5.h>
+#include	<kadm5/admin.h>
+
+struct cprinc_arg {
+	krb5_ui_4 api_version;
+	kadm5_principal_ent_rec rec;
+	long mask;
+	char *passwd;
+};
+typedef struct cprinc_arg cprinc_arg;
+
+struct cprinc3_arg {
+	krb5_ui_4 api_version;
+	kadm5_principal_ent_rec rec;
+	long mask;
+	int n_ks_tuple;
+	krb5_key_salt_tuple *ks_tuple;
+	char *passwd;
+};
+typedef struct cprinc3_arg cprinc3_arg;
+
+struct generic_ret {
+	krb5_ui_4 api_version;
+	kadm5_ret_t code;
+        char *err_str;
+};
+typedef struct generic_ret generic_ret;
+
+struct dprinc_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+};
+typedef struct dprinc_arg dprinc_arg;
+
+struct mprinc_arg {
+	krb5_ui_4 api_version;
+	kadm5_principal_ent_rec rec;
+	long mask;
+};
+typedef struct mprinc_arg mprinc_arg;
+
+struct rprinc_arg {
+	krb5_ui_4 api_version;
+	krb5_principal src;
+	krb5_principal dest;
+};
+typedef struct rprinc_arg rprinc_arg;
+
+struct gprincs_arg {
+        krb5_ui_4 api_version;
+	char *exp;
+};
+typedef struct gprincs_arg gprincs_arg;
+
+struct gprincs_ret {
+        krb5_ui_4 api_version;
+	kadm5_ret_t code;
+	char **princs;
+	int count;
+        char *err_str;
+};
+typedef struct gprincs_ret gprincs_ret;
+
+struct chpass_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+	char *pass;
+};
+typedef struct chpass_arg chpass_arg;
+
+struct chpass3_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+	krb5_boolean keepold;
+	int n_ks_tuple;
+	krb5_key_salt_tuple *ks_tuple;
+	char *pass;
+};
+typedef struct chpass3_arg chpass3_arg;
+
+struct setv4key_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+        krb5_keyblock *keyblock;
+};
+typedef struct setv4key_arg setv4key_arg;
+
+struct setkey_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+        krb5_keyblock *keyblocks;
+        int n_keys;
+};
+typedef struct setkey_arg setkey_arg;
+
+struct setkey3_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+	krb5_boolean keepold;
+	int n_ks_tuple;
+	krb5_key_salt_tuple *ks_tuple;
+        krb5_keyblock *keyblocks;
+        int n_keys;
+};
+typedef struct setkey3_arg setkey3_arg;
+
+struct chrand_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+};
+typedef struct chrand_arg chrand_arg;
+
+struct chrand3_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+	krb5_boolean keepold;
+	int n_ks_tuple;
+	krb5_key_salt_tuple *ks_tuple;
+};
+typedef struct chrand3_arg chrand3_arg;
+
+struct chrand_ret {
+	krb5_ui_4 api_version;
+	kadm5_ret_t code;
+	krb5_keyblock key;
+	krb5_keyblock *keys;
+	int n_keys;
+        char *err_str;
+};
+typedef struct chrand_ret chrand_ret;
+
+struct gprinc_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+	long mask;
+};
+typedef struct gprinc_arg gprinc_arg;
+
+struct gprinc_ret {
+	krb5_ui_4 api_version;
+	kadm5_ret_t code;
+	kadm5_principal_ent_rec rec;
+        char *err_str;
+};
+typedef struct gprinc_ret gprinc_ret;
+
+struct cpol_arg {
+	krb5_ui_4 api_version;
+	kadm5_policy_ent_rec rec;
+	long mask;
+};
+typedef struct cpol_arg cpol_arg;
+
+struct dpol_arg {
+	krb5_ui_4 api_version;
+	char *name;
+};
+typedef struct dpol_arg dpol_arg;
+
+struct mpol_arg {
+	krb5_ui_4 api_version;
+	kadm5_policy_ent_rec rec;
+	long mask;
+};
+typedef struct mpol_arg mpol_arg;
+
+struct gpol_arg {
+	krb5_ui_4 api_version;
+	char *name;
+};
+typedef struct gpol_arg gpol_arg;
+
+struct gpol_ret {
+	krb5_ui_4 api_version;
+	kadm5_ret_t code;
+	kadm5_policy_ent_rec rec;
+        char *err_str;
+};
+typedef struct gpol_ret gpol_ret;
+
+struct gpols_arg {
+        krb5_ui_4 api_version;
+	char *exp;
+};
+typedef struct gpols_arg gpols_arg;
+
+struct gpols_ret {
+        krb5_ui_4 api_version;
+	kadm5_ret_t code;
+	char **pols;
+	int count;
+        char *err_str;
+};
+typedef struct gpols_ret gpols_ret;
+
+struct getprivs_ret {
+	krb5_ui_4 api_version;
+	kadm5_ret_t code;
+	long privs;
+        char *err_str;
+};
+typedef struct getprivs_ret getprivs_ret;
+
+#define KADM 2112
+#define KADMVERS 2
+#define CREATE_PRINCIPAL 1
+extern  generic_ret * create_principal_2(cprinc_arg *, CLIENT *);
+extern  generic_ret * create_principal_2_svc(cprinc_arg *, struct svc_req *);
+#define DELETE_PRINCIPAL 2
+extern  generic_ret * delete_principal_2(dprinc_arg *, CLIENT *);
+extern  generic_ret * delete_principal_2_svc(dprinc_arg *, struct svc_req *);
+#define MODIFY_PRINCIPAL 3
+extern  generic_ret * modify_principal_2(mprinc_arg *, CLIENT *);
+extern  generic_ret * modify_principal_2_svc(mprinc_arg *, struct svc_req *);
+#define RENAME_PRINCIPAL 4
+extern  generic_ret * rename_principal_2(rprinc_arg *, CLIENT *);
+extern  generic_ret * rename_principal_2_svc(rprinc_arg *, struct svc_req *);
+#define GET_PRINCIPAL 5
+extern  gprinc_ret * get_principal_2(gprinc_arg *, CLIENT *);
+extern  gprinc_ret * get_principal_2_svc(gprinc_arg *, struct svc_req *);
+#define CHPASS_PRINCIPAL 6
+extern  generic_ret * chpass_principal_2(chpass_arg *, CLIENT *);
+extern  generic_ret * chpass_principal_2_svc(chpass_arg *, struct svc_req *);
+#define CHRAND_PRINCIPAL 7
+extern  chrand_ret * chrand_principal_2(chrand_arg *, CLIENT *);
+extern  chrand_ret * chrand_principal_2_svc(chrand_arg *, struct svc_req *);
+#define CREATE_POLICY 8
+extern  generic_ret * create_policy_2(cpol_arg *, CLIENT *);
+extern  generic_ret * create_policy_2_svc(cpol_arg *, struct svc_req *);
+#define DELETE_POLICY 9
+extern  generic_ret * delete_policy_2(dpol_arg *, CLIENT *);
+extern  generic_ret * delete_policy_2_svc(dpol_arg *, struct svc_req *);
+#define MODIFY_POLICY 10
+extern  generic_ret * modify_policy_2(mpol_arg *, CLIENT *);
+extern  generic_ret * modify_policy_2_svc(mpol_arg *, struct svc_req *);
+#define GET_POLICY 11
+extern  gpol_ret * get_policy_2(gpol_arg *, CLIENT *);
+extern  gpol_ret * get_policy_2_svc(gpol_arg *, struct svc_req *);
+#define GET_PRIVS 12
+extern  getprivs_ret * get_privs_2(void *, CLIENT *);
+extern  getprivs_ret * get_privs_2_svc(krb5_ui_4 *, struct svc_req *);
+#define INIT 13
+extern  generic_ret * init_2(void *, CLIENT *);
+extern  generic_ret * init_2_svc(krb5_ui_4 *, struct svc_req *);
+#define GET_PRINCS 14
+extern  gprincs_ret * get_princs_2(gprincs_arg *, CLIENT *);
+extern  gprincs_ret * get_princs_2_svc(gprincs_arg *, struct svc_req *);
+#define GET_POLS 15
+extern  gpols_ret * get_pols_2(gpols_arg *, CLIENT *);
+extern  gpols_ret * get_pols_2_svc(gpols_arg *, struct svc_req *);
+#define SETKEY_PRINCIPAL 16
+extern  generic_ret * setkey_principal_2(setkey_arg *, CLIENT *);
+extern  generic_ret * setkey_principal_2_svc(setkey_arg *, struct svc_req *);
+#define SETV4KEY_PRINCIPAL 17
+extern  generic_ret * setv4key_principal_2(setv4key_arg *, CLIENT *);
+extern  generic_ret * setv4key_principal_2_svc(setv4key_arg *, struct svc_req *);
+#define CREATE_PRINCIPAL3 18
+extern  generic_ret * create_principal3_2(cprinc3_arg *, CLIENT *);
+extern  generic_ret * create_principal3_2_svc(cprinc3_arg *, struct svc_req *);
+#define CHPASS_PRINCIPAL3 19
+extern  generic_ret * chpass_principal3_2(chpass3_arg *, CLIENT *);
+extern  generic_ret * chpass_principal3_2_svc(chpass3_arg *, struct svc_req *);
+#define CHRAND_PRINCIPAL3 20
+extern  chrand_ret * chrand_principal3_2(chrand3_arg *, CLIENT *);
+extern  chrand_ret * chrand_principal3_2_svc(chrand3_arg *, struct svc_req *);
+#define SETKEY_PRINCIPAL3 21
+extern  generic_ret * setkey_principal3_2(setkey3_arg *, CLIENT *);
+extern  generic_ret * setkey_principal3_2_svc(setkey3_arg *, struct svc_req *);
+
+extern bool_t xdr_cprinc_arg ();
+extern bool_t xdr_cprinc3_arg ();
+extern bool_t xdr_generic_ret ();
+extern bool_t xdr_dprinc_arg ();
+extern bool_t xdr_mprinc_arg ();
+extern bool_t xdr_rprinc_arg ();
+extern bool_t xdr_gprincs_arg ();
+extern bool_t xdr_gprincs_ret ();
+extern bool_t xdr_chpass_arg ();
+extern bool_t xdr_chpass3_arg ();
+extern bool_t xdr_setv4key_arg ();
+extern bool_t xdr_setkey_arg ();
+extern bool_t xdr_setkey3_arg ();
+extern bool_t xdr_chrand_arg ();
+extern bool_t xdr_chrand3_arg ();
+extern bool_t xdr_chrand_ret ();
+extern bool_t xdr_gprinc_arg ();
+extern bool_t xdr_gprinc_ret ();
+extern bool_t xdr_kadm5_ret_t ();
+extern bool_t xdr_kadm5_principal_ent_rec ();
+extern bool_t xdr_kadm5_policy_ent_rec ();
+extern bool_t	xdr_krb5_keyblock ();
+extern bool_t	xdr_krb5_principal ();
+extern bool_t	xdr_krb5_enctype ();
+extern bool_t	xdr_krb5_octet ();
+extern bool_t	xdr_krb5_int32 ();
+extern bool_t	xdr_u_int32 ();
+extern bool_t xdr_cpol_arg ();
+extern bool_t xdr_dpol_arg ();
+extern bool_t xdr_mpol_arg ();
+extern bool_t xdr_gpol_arg ();
+extern bool_t xdr_gpol_ret ();
+extern bool_t xdr_gpols_arg ();
+extern bool_t xdr_gpols_ret ();
+extern bool_t xdr_getprivs_ret ();
+
+
+#endif /* __KADM_RPC_H__ */
diff --git a/mechglue/src/lib/kadm5/kadm_rpc_xdr.c b/mechglue/src/lib/kadm5/kadm_rpc_xdr.c
new file mode 100644
index 000000000..346a36ea9
--- /dev/null
+++ b/mechglue/src/lib/kadm5/kadm_rpc_xdr.c
@@ -0,0 +1,1128 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ */
+
+#include <gssrpc/rpc.h>
+#include <krb5.h>
+#include <errno.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include <kadm5/admin_xdr.h>
+#include <stdlib.h>
+#include <string.h>
+
+static bool_t
+_xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp,
+			     int v);
+/*
+ * Function: xdr_ui_4
+ *
+ * Purpose: XDR function which serves as a wrapper for xdr_u_int32,
+ * to prevent compiler warnings about type clashes between u_int32
+ * and krb5_ui_4.
+ */
+bool_t xdr_ui_4(XDR *xdrs, krb5_ui_4 *objp)
+{
+  /* Assumes that krb5_ui_4 and u_int32 are both four bytes long.
+     This should not be a harmful assumption. */
+  return xdr_u_int32(xdrs, (uint32_t *) objp);
+}
+
+
+/*
+ * Function: xdr_nullstring
+ *
+ * Purpose: XDR function for "strings" that are either NULL-terminated
+ * or NULL.
+ */
+bool_t xdr_nullstring(XDR *xdrs, char **objp)
+{
+     u_int size;
+
+     if (xdrs->x_op == XDR_ENCODE) {
+	  if (*objp == NULL)
+	       size = 0;
+	  else
+	       size = strlen(*objp) + 1;
+     }
+     if (! xdr_u_int(xdrs, &size)) {
+	  return FALSE;
+	}
+     switch (xdrs->x_op) {
+     case XDR_DECODE:
+	  if (size == 0) {
+	       *objp = NULL;
+	       return TRUE;
+	  } else if (*objp == NULL) {
+	       *objp = (char *) mem_alloc(size);
+	       if (*objp == NULL) {
+		    errno = ENOMEM;
+		    return FALSE;
+	       }
+	  }
+	  return (xdr_opaque(xdrs, *objp, size));
+	  
+     case XDR_ENCODE:
+	  if (size != 0)
+	       return (xdr_opaque(xdrs, *objp, size));
+	  return TRUE;
+
+     case XDR_FREE:
+	  if (*objp != NULL)
+	       mem_free(*objp, size);
+	  *objp = NULL;
+	  return TRUE;
+     }
+
+     return FALSE;
+}
+
+/*
+ * Function: xdr_nulltype
+ *
+ * Purpose: XDR function for arbitrary pointer types that are either
+ * NULL or contain data.
+ */
+bool_t xdr_nulltype(XDR *xdrs, void **objp, xdrproc_t proc)
+{
+     bool_t null;
+
+     switch (xdrs->x_op) {
+     case XDR_DECODE:
+	  if (!xdr_bool(xdrs, &null))
+	      return FALSE;
+	  if (null) {
+	       *objp = NULL;
+	       return TRUE;
+	  }
+	  return (*proc)(xdrs, objp);
+
+     case XDR_ENCODE:
+	  if (*objp == NULL)
+	       null = TRUE;
+	  else
+	       null = FALSE;
+	  if (!xdr_bool(xdrs, &null))
+	       return FALSE;
+	  if (null == FALSE)
+	       return (*proc)(xdrs, objp);
+	  return TRUE;
+
+     case XDR_FREE:
+	  if (*objp)
+	       return (*proc)(xdrs, objp);
+	  return TRUE;
+     }
+
+     return FALSE;
+}
+
+bool_t
+xdr_krb5_timestamp(XDR *xdrs, krb5_timestamp *objp)
+{
+  /* This assumes that int32 and krb5_timestamp are the same size.
+     This shouldn't be a problem, since we've got a unit test which
+     checks for this. */
+	if (!xdr_int32(xdrs, (int32_t *) objp)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp)
+{
+	unsigned char tmp;
+
+	tmp = '\0'; /* for purify, else xdr_u_char performs a umr */
+
+	if (xdrs->x_op == XDR_ENCODE)
+		tmp = (unsigned char) *objp;
+
+	if (!xdr_u_char(xdrs, &tmp))
+		return (FALSE);
+
+	if (xdrs->x_op == XDR_DECODE)
+		*objp = (krb5_kvno) tmp;
+
+	return (TRUE);
+}
+
+bool_t
+xdr_krb5_deltat(XDR *xdrs, krb5_deltat *objp)
+{
+  /* This assumes that int32 and krb5_deltat are the same size.
+     This shouldn't be a problem, since we've got a unit test which
+     checks for this. */
+	if (!xdr_int32(xdrs, (int32_t *) objp)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_krb5_flags(XDR *xdrs, krb5_flags *objp)
+{
+  /* This assumes that int32 and krb5_flags are the same size.
+     This shouldn't be a problem, since we've got a unit test which
+     checks for this. */
+	if (!xdr_int32(xdrs, (int32_t *) objp)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_krb5_ui_4(XDR *xdrs, krb5_ui_4 *objp)
+{
+	if (!xdr_u_int32(xdrs, (uint32_t *) objp)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_krb5_int16(XDR *xdrs, krb5_int16 *objp)
+{
+    int tmp;
+
+    tmp = (int) *objp;
+
+    if (!xdr_int(xdrs, &tmp))
+	return(FALSE);
+
+    *objp = (krb5_int16) tmp;
+
+    return(TRUE);
+}
+
+/*
+ * Function: xdr_krb5_ui_2
+ *
+ * Purpose: XDR function which serves as a wrapper for xdr_u_int,
+ * to prevent compiler warnings about type clashes between u_int
+ * and krb5_ui_2.
+ */
+bool_t
+xdr_krb5_ui_2(XDR *xdrs, krb5_ui_2 *objp)
+{
+    unsigned int tmp;
+
+    tmp = (unsigned int) *objp;
+
+    if (!xdr_u_int(xdrs, &tmp))
+	return(FALSE);
+
+    *objp = (krb5_ui_2) tmp;
+
+    return(TRUE);
+}
+
+
+
+bool_t xdr_krb5_key_data_nocontents(XDR *xdrs, krb5_key_data *objp)
+{
+     /*
+      * Note that this function intentionally DOES NOT tranfer key
+      * length or contents!  xdr_krb5_key_data in adb_xdr.c does, but
+      * that is only for use within the server-side library.
+      */
+     unsigned int tmp;
+
+     if (xdrs->x_op == XDR_DECODE)
+	  memset((char *) objp, 0, sizeof(krb5_key_data));
+
+     if (!xdr_krb5_int16(xdrs, &objp->key_data_ver)) {
+	  return (FALSE);
+     }
+     if (!xdr_krb5_int16(xdrs, &objp->key_data_kvno)) {
+	  return (FALSE);
+     }
+     if (!xdr_krb5_int16(xdrs, &objp->key_data_type[0])) {
+	  return (FALSE);
+     }
+     if (objp->key_data_ver > 1) {
+	  if (!xdr_krb5_int16(xdrs, &objp->key_data_type[1])) {
+	       return (FALSE);
+	  }
+     }
+     /*
+      * kadm5_get_principal on the server side allocates and returns
+      * key contents when asked.  Even though this function refuses to
+      * transmit that data, it still has to *free* the data at the
+      * appropriate time to avoid a memory leak.
+      */
+     if (xdrs->x_op == XDR_FREE) {
+	  tmp = (unsigned int) objp->key_data_length[0];
+	  if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[0],
+			 &tmp, ~0))
+	       return FALSE;
+	  
+	  tmp = (unsigned int) objp->key_data_length[1];
+	  if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[1],
+			 &tmp, ~0))
+	       return FALSE;
+     }
+     
+     return (TRUE);
+}
+
+
+bool_t
+xdr_krb5_key_salt_tuple(XDR *xdrs, krb5_key_salt_tuple *objp)
+{
+    if (!xdr_krb5_enctype(xdrs, &objp->ks_enctype))
+	return FALSE;
+    if (!xdr_krb5_salttype(xdrs, &objp->ks_salttype))
+	return FALSE;
+    return TRUE;
+}
+
+bool_t xdr_krb5_tl_data(XDR *xdrs, krb5_tl_data **tl_data_head)
+{
+     krb5_tl_data *tl, *tl2;
+     bool_t more;
+     unsigned int len;
+
+     switch (xdrs->x_op) {
+     case XDR_FREE:
+	  tl = tl2 = *tl_data_head;
+	  while (tl) {
+	       tl2 = tl->tl_data_next;
+	       free(tl->tl_data_contents);
+	       free(tl);
+	       tl = tl2;
+	  }
+	  break;
+	  
+     case XDR_ENCODE:
+	  tl = *tl_data_head;
+	  while (1) {
+	       more = (tl != NULL);
+	       if (!xdr_bool(xdrs, &more))
+		    return FALSE;
+	       if (tl == NULL)
+		    break;
+	       if (!xdr_krb5_int16(xdrs, &tl->tl_data_type))
+		    return FALSE;
+	       len = tl->tl_data_length;
+	       if (!xdr_bytes(xdrs, (char **) &tl->tl_data_contents, &len, ~0))
+		    return FALSE;
+	       tl = tl->tl_data_next;
+	  }
+	  break;
+
+     case XDR_DECODE:
+	  tl = NULL;
+	  while (1) {
+	       if (!xdr_bool(xdrs, &more))
+		    return FALSE;
+	       if (more == FALSE)
+		    break;
+	       tl2 = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
+	       if (tl2 == NULL)
+		    return FALSE;
+	       memset((char *) tl2, 0, sizeof(krb5_tl_data));
+	       if (!xdr_krb5_int16(xdrs, &tl2->tl_data_type))
+		    return FALSE;
+	       if (!xdr_bytes(xdrs, (char **)&tl2->tl_data_contents, &len, ~0))
+		    return FALSE;
+	       tl2->tl_data_length = len;
+
+	       tl2->tl_data_next = tl;
+	       tl = tl2;
+	  }
+
+	  *tl_data_head = tl;
+	  break;
+     }
+
+     return TRUE;
+}
+
+bool_t
+xdr_kadm5_ret_t(XDR *xdrs, kadm5_ret_t *objp)
+{
+	uint32_t tmp;
+
+	if (xdrs->x_op == XDR_ENCODE)
+		tmp = (uint32_t) *objp;
+
+	if (!xdr_u_int32(xdrs, &tmp))
+		return (FALSE);
+
+	if (xdrs->x_op == XDR_DECODE)
+		*objp = (kadm5_ret_t) tmp;
+
+	return (TRUE);
+}
+
+bool_t xdr_kadm5_principal_ent_rec_v1(XDR *xdrs,
+				      kadm5_principal_ent_rec *objp)
+{
+     return _xdr_kadm5_principal_ent_rec(xdrs, objp, KADM5_API_VERSION_1);
+}
+
+bool_t xdr_kadm5_principal_ent_rec(XDR *xdrs,
+				   kadm5_principal_ent_rec *objp)
+{
+     return _xdr_kadm5_principal_ent_rec(xdrs, objp, KADM5_API_VERSION_2);
+}
+
+static bool_t
+_xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp,
+			     int v)
+{
+     unsigned int n;
+     
+	if (!xdr_krb5_principal(xdrs, &objp->principal)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_timestamp(xdrs, &objp->princ_expire_time)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_timestamp(xdrs, &objp->last_pwd_change)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_timestamp(xdrs, &objp->pw_expiration)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_deltat(xdrs, &objp->max_life)) {
+		return (FALSE);
+	}
+        if (v == KADM5_API_VERSION_1) {
+	     if (!xdr_krb5_principal(xdrs, &objp->mod_name)) {
+		  return (FALSE);
+	     }
+	} else {
+	     if (!xdr_nulltype(xdrs, (void **) &objp->mod_name,
+			       xdr_krb5_principal)) {
+		  return (FALSE);
+	     }
+	}
+	if (!xdr_krb5_timestamp(xdrs, &objp->mod_date)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_flags(xdrs, &objp->attributes)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_kvno(xdrs, &objp->kvno)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_kvno(xdrs, &objp->mkvno)) {
+		return (FALSE);
+	}
+	if (!xdr_nullstring(xdrs, &objp->policy)) {
+		return (FALSE);
+	}
+	if (!xdr_long(xdrs, &objp->aux_attributes)) {
+		return (FALSE);
+	}
+	if (v != KADM5_API_VERSION_1) {
+	     if (!xdr_krb5_deltat(xdrs, &objp->max_renewable_life)) {
+		  return (FALSE);
+	     }
+	     if (!xdr_krb5_timestamp(xdrs, &objp->last_success)) {
+		  return (FALSE);
+	     }
+	     if (!xdr_krb5_timestamp(xdrs, &objp->last_failed)) {
+		  return (FALSE);
+	     }
+	     if (!xdr_krb5_kvno(xdrs, &objp->fail_auth_count)) {
+		  return (FALSE);
+	     }
+	     if (!xdr_krb5_int16(xdrs, &objp->n_key_data)) {
+		  return (FALSE);
+	     }
+	     if (!xdr_krb5_int16(xdrs, &objp->n_tl_data)) {
+		  return (FALSE);
+	     }
+	     if (!xdr_nulltype(xdrs, (void **) &objp->tl_data,
+			       xdr_krb5_tl_data)) { 
+		  return FALSE;
+	     }
+	     n = objp->n_key_data;
+	     if (!xdr_array(xdrs, (caddr_t *) &objp->key_data,
+			    &n, ~0, sizeof(krb5_key_data),
+			    xdr_krb5_key_data_nocontents)) {
+		  return (FALSE);
+	     }
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_kadm5_policy_ent_rec(XDR *xdrs, kadm5_policy_ent_rec *objp)
+{
+	if (!xdr_nullstring(xdrs, &objp->policy)) {
+		return (FALSE);
+	}
+	/* these all used to be u_int32, but it's stupid for sized types
+	   to be exposed at the api, and they're the same as longs on the
+	   wire. */
+	if (!xdr_long(xdrs, &objp->pw_min_life)) {
+		return (FALSE);
+	}
+	if (!xdr_long(xdrs, &objp->pw_max_life)) {
+		return (FALSE);
+	}
+	if (!xdr_long(xdrs, &objp->pw_min_length)) {
+		return (FALSE);
+	}
+	if (!xdr_long(xdrs, &objp->pw_min_classes)) {
+		return (FALSE);
+	}
+	if (!xdr_long(xdrs, &objp->pw_history_num)) {
+		return (FALSE);
+	}
+	if (!xdr_long(xdrs, &objp->policy_refcnt)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_cprinc_arg(XDR *xdrs, cprinc_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (objp->api_version == KADM5_API_VERSION_1) {
+	     if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) {
+		  return (FALSE);
+	     }
+	} else {
+	     if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) {
+		  return (FALSE);
+	     }
+	}
+	if (!xdr_long(xdrs, &objp->mask)) {
+		return (FALSE);
+	}
+	if (!xdr_nullstring(xdrs, &objp->passwd)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_cprinc3_arg(XDR *xdrs, cprinc3_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (objp->api_version == KADM5_API_VERSION_1) {
+		if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) {
+			return (FALSE);
+		}
+	} else {
+		if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) {
+			return (FALSE);
+		}
+	}
+	if (!xdr_long(xdrs, &objp->mask)) {
+		return (FALSE);
+	}
+	if (!xdr_array(xdrs, (caddr_t *)&objp->ks_tuple,
+		       (unsigned int *)&objp->n_ks_tuple, ~0,
+		       sizeof(krb5_key_salt_tuple),
+		       xdr_krb5_key_salt_tuple)) {
+		return (FALSE);
+	}
+	if (!xdr_nullstring(xdrs, &objp->passwd)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_generic_ret(XDR *xdrs, generic_ret *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_kadm5_ret_t(xdrs, &objp->code)) {
+		return (FALSE);
+	}
+
+	if( xdrs->x_op == XDR_ENCODE )
+	{
+	    char *tmp_str = "Unknown error code";
+	    if(!xdr_string(xdrs, objp->err_str?&objp->err_str:&tmp_str, (unsigned int)-1 )) {
+		return (FALSE);
+	    }
+	} else {
+	    if(!xdr_string(xdrs, &objp->err_str, (unsigned int)-1 )) {
+		return (FALSE);
+	    }
+	}
+
+	return(TRUE);
+}
+
+bool_t
+xdr_dprinc_arg(XDR *xdrs, dprinc_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_mprinc_arg(XDR *xdrs, mprinc_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (objp->api_version == KADM5_API_VERSION_1) {
+	     if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) {
+		  return (FALSE);
+	     }
+	} else {
+	     if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) {
+		  return (FALSE);
+	     }
+	}
+	if (!xdr_long(xdrs, &objp->mask)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_rprinc_arg(XDR *xdrs, rprinc_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->src)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->dest)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_gprincs_arg(XDR *xdrs, gprincs_arg *objp)
+{
+     if (!xdr_ui_4(xdrs, &objp->api_version)) {
+	  return (FALSE);
+     }
+     if (!xdr_nullstring(xdrs, &objp->exp)) {
+	  return (FALSE);
+     }
+     return (TRUE);
+}
+
+bool_t
+xdr_gprincs_ret(XDR *xdrs, gprincs_ret *objp)     
+{
+     if (!xdr_ui_4(xdrs, &objp->api_version)) {
+	  return (FALSE);
+     }
+     if (!xdr_kadm5_ret_t(xdrs, &objp->code)) {
+	  return (FALSE);
+     }
+     if (objp->code == KADM5_OK) {
+	  if (!xdr_int(xdrs, &objp->count)) {
+	       return (FALSE);
+	  }
+	  if (!xdr_array(xdrs, (caddr_t *) &objp->princs,
+			 (unsigned int *) &objp->count, ~0,
+			 sizeof(char *), xdr_nullstring)) {
+	       return (FALSE);
+	  }
+     }
+
+     if( xdrs->x_op == XDR_ENCODE )
+     {
+	 char *tmp_str = "Unknown error code";
+	 if(!xdr_string(xdrs, objp->err_str?&objp->err_str:&tmp_str, (unsigned int)-1 )) {
+	     return (FALSE);
+	 }
+     } else {
+	 if(!xdr_string(xdrs, &objp->err_str, (unsigned int)-1 )) {
+	     return (FALSE);
+	 }
+     }
+
+     return (TRUE);
+}
+
+bool_t
+xdr_chpass_arg(XDR *xdrs, chpass_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	if (!xdr_nullstring(xdrs, &objp->pass)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_chpass3_arg(XDR *xdrs, chpass3_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	if (!xdr_bool(xdrs, &objp->keepold)) {
+		return (FALSE);
+	}
+	if (!xdr_array(xdrs, (caddr_t *)&objp->ks_tuple,
+		       (unsigned int*)&objp->n_ks_tuple, ~0,
+		       sizeof(krb5_key_salt_tuple),
+		       xdr_krb5_key_salt_tuple)) {
+		return (FALSE);
+	}
+	if (!xdr_nullstring(xdrs, &objp->pass)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_setv4key_arg(XDR *xdrs, setv4key_arg *objp)
+{
+	unsigned int n_keys = 1;
+
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	if (!xdr_array(xdrs, (caddr_t *) &objp->keyblock,
+		       &n_keys, ~0,
+		       sizeof(krb5_keyblock), xdr_krb5_keyblock)) {
+	        return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_setkey_arg(XDR *xdrs, setkey_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	if (!xdr_array(xdrs, (caddr_t *) &objp->keyblocks,
+		       (unsigned int *) &objp->n_keys, ~0,
+		       sizeof(krb5_keyblock), xdr_krb5_keyblock)) {
+	        return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_setkey3_arg(XDR *xdrs, setkey3_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	if (!xdr_bool(xdrs, &objp->keepold)) {
+		return (FALSE);
+	}
+	if (!xdr_array(xdrs, (caddr_t *) &objp->ks_tuple,
+		       (unsigned int *) &objp->n_ks_tuple, ~0,
+		       sizeof(krb5_key_salt_tuple), xdr_krb5_key_salt_tuple)) {
+		return (FALSE);
+	}
+	if (!xdr_array(xdrs, (caddr_t *) &objp->keyblocks,
+		       (unsigned int *) &objp->n_keys, ~0,
+		       sizeof(krb5_keyblock), xdr_krb5_keyblock)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_chrand_arg(XDR *xdrs, chrand_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_chrand3_arg(XDR *xdrs, chrand3_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	if (!xdr_bool(xdrs, &objp->keepold)) {
+		return (FALSE);
+	}
+	if (!xdr_array(xdrs, (caddr_t *)&objp->ks_tuple,
+		       (unsigned int*)&objp->n_ks_tuple, ~0,
+		       sizeof(krb5_key_salt_tuple),
+		       xdr_krb5_key_salt_tuple)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_chrand_ret(XDR *xdrs, chrand_ret *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_kadm5_ret_t(xdrs, &objp->code)) {
+		return (FALSE);
+	}
+	if (objp->api_version == KADM5_API_VERSION_1) {
+	     if(objp->code == KADM5_OK) {
+		  if (!xdr_krb5_keyblock(xdrs, &objp->key)) {
+		       return (FALSE);
+		  }
+	     }
+	} else {
+	     if (objp->code == KADM5_OK) {
+		  if (!xdr_array(xdrs, (char **)&objp->keys, &objp->n_keys, ~0,
+				 sizeof(krb5_keyblock),
+				 xdr_krb5_keyblock))
+		       return FALSE;
+	     }
+	}
+
+	if( xdrs->x_op == XDR_ENCODE )
+	{
+	    char *tmp_str = "Unknown error code";
+	    if(!xdr_string(xdrs, objp->err_str?&objp->err_str:&tmp_str, (unsigned int)-1 )) {
+		return (FALSE);
+	    }
+	} else {
+	    if(!xdr_string(xdrs, &objp->err_str, (unsigned int)-1 )) {
+		return (FALSE);
+	    }
+	}
+
+	return (TRUE);
+}
+
+bool_t
+xdr_gprinc_arg(XDR *xdrs, gprinc_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	if ((objp->api_version > KADM5_API_VERSION_1) &&
+	    !xdr_long(xdrs, &objp->mask)) {
+	     return FALSE;
+	}
+	     
+	return (TRUE);
+}
+
+bool_t
+xdr_gprinc_ret(XDR *xdrs, gprinc_ret *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_kadm5_ret_t(xdrs, &objp->code)) {
+		return (FALSE);
+	}
+	if(objp->code == KADM5_OK)  {
+	     if (objp->api_version == KADM5_API_VERSION_1) {
+		  if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) {
+		       return (FALSE);
+		  }
+	     } else {
+		  if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) {
+		       return (FALSE);
+		  }
+	     }
+	}
+
+	if( xdrs->x_op == XDR_ENCODE )
+	{
+	    char *tmp_str = "Unknown error code";
+	    if(!xdr_string(xdrs, objp->err_str?&objp->err_str:&tmp_str, (unsigned int)-1 )) {
+		return (FALSE);
+	    }
+	} else {
+	    if(!xdr_string(xdrs, &objp->err_str, (unsigned int)-1 )) {
+		return (FALSE);
+	    }
+	}
+
+	return (TRUE);
+}
+
+bool_t
+xdr_cpol_arg(XDR *xdrs, cpol_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec)) {
+		return (FALSE);
+	}
+	if (!xdr_long(xdrs, &objp->mask)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_dpol_arg(XDR *xdrs, dpol_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_nullstring(xdrs, &objp->name)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_mpol_arg(XDR *xdrs, mpol_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec)) {
+		return (FALSE);
+	}
+	if (!xdr_long(xdrs, &objp->mask)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_gpol_arg(XDR *xdrs, gpol_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_nullstring(xdrs, &objp->name)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_gpol_ret(XDR *xdrs, gpol_ret *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_kadm5_ret_t(xdrs, &objp->code)) {
+		return (FALSE);
+	}
+	if(objp->code == KADM5_OK) {
+	    if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec))
+		return (FALSE);
+	}
+
+	if( xdrs->x_op == XDR_ENCODE )
+	{
+	    char *tmp_str = "Unknown error code";
+	    if(!xdr_string(xdrs, objp->err_str?&objp->err_str:&tmp_str, (unsigned int)-1 )) {
+		return (FALSE);
+	    }
+	} else {
+	    if(!xdr_string(xdrs, &objp->err_str, (unsigned int)-1 )) {
+		return (FALSE);
+	    }
+	}
+
+	return (TRUE);
+}
+
+bool_t
+xdr_gpols_arg(XDR *xdrs, gpols_arg *objp)
+{
+     if (!xdr_ui_4(xdrs, &objp->api_version)) {
+	  return (FALSE);
+     }
+     if (!xdr_nullstring(xdrs, &objp->exp)) {
+	  return (FALSE);
+     }
+     return (TRUE);
+}
+
+bool_t
+xdr_gpols_ret(XDR *xdrs, gpols_ret *objp)     
+{
+     if (!xdr_ui_4(xdrs, &objp->api_version)) {
+	  return (FALSE);
+     }
+     if (!xdr_kadm5_ret_t(xdrs, &objp->code)) {
+	  return (FALSE);
+     }
+     if (objp->code == KADM5_OK) {
+	  if (!xdr_int(xdrs, &objp->count)) {
+	       return (FALSE);
+	  }
+	  if (!xdr_array(xdrs, (caddr_t *) &objp->pols,
+			 (unsigned int *) &objp->count, ~0,
+			 sizeof(char *), xdr_nullstring)) {
+	       return (FALSE);
+	  }
+     }
+
+     if( xdrs->x_op == XDR_ENCODE )
+     {
+	 char *tmp_str = "Unknown error code";
+	 if(!xdr_string(xdrs, objp->err_str?&objp->err_str:&tmp_str, (unsigned int)-1 )) {
+	     return (FALSE);
+	 }
+     } else {
+	 if(!xdr_string(xdrs, &objp->err_str, (unsigned int)-1 )) {
+	     return (FALSE);
+	 }
+     }
+
+     return (TRUE);
+}
+
+bool_t xdr_getprivs_ret(XDR *xdrs, getprivs_ret *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+     if (! xdr_kadm5_ret_t(xdrs, &objp->code) ||
+	 ! xdr_long(xdrs, &objp->privs))
+	  return FALSE;
+
+     if( xdrs->x_op == XDR_ENCODE )
+     {
+	 char *tmp_str = "Unknown error code";
+	 if(!xdr_string(xdrs, objp->err_str?&objp->err_str:&tmp_str, (unsigned int)-1 )) {
+	     return (FALSE);
+	 }
+     } else {
+	 if(!xdr_string(xdrs, &objp->err_str, (unsigned int)-1 )) {
+	     return (FALSE);
+	 }
+     }
+
+     return TRUE;
+}
+
+bool_t
+xdr_krb5_principal(XDR *xdrs, krb5_principal *objp)
+{
+    int	    ret;
+    char	    *p = NULL;
+    krb5_principal  pr = NULL;
+    static krb5_context context = NULL;
+
+    /* using a static context here is ugly, but should work
+       ok, and the other solutions are even uglier */
+
+    if (!context &&
+	krb5_init_context(&context))
+       return(FALSE);
+
+    switch(xdrs->x_op) {
+    case XDR_ENCODE:
+	if (*objp) {
+	     if((ret = krb5_unparse_name(context, *objp, &p)) != 0) 
+		  return FALSE;
+	}
+	if(!xdr_nullstring(xdrs, &p))
+	    return FALSE;
+	if (p) free(p);
+	break;
+    case XDR_DECODE:
+	if(!xdr_nullstring(xdrs, &p))
+	    return FALSE;
+	if (p) {
+	     ret = krb5_parse_name(context, p, &pr);
+	     if(ret != 0) 
+		  return FALSE;
+	     *objp = pr;
+	     free(p);
+	} else
+	     *objp = NULL;
+	break;
+    case XDR_FREE:
+	if(*objp != NULL) 
+	    krb5_free_principal(context, *objp);
+	break;
+    }
+    return TRUE;
+}
+
+bool_t
+xdr_krb5_octet(XDR *xdrs, krb5_octet *objp)
+{
+   if (!xdr_u_char(xdrs, objp))
+	return (FALSE);
+   return (TRUE);
+}
+
+bool_t
+xdr_krb5_enctype(XDR *xdrs, krb5_enctype *objp)
+{
+   /*
+    * This used to be xdr_krb5_keytype, but keytypes and enctypes have
+    * been merged into only enctypes.  However, randkey_principal
+    * already ensures that only a key of ENCTYPE_DES_CBC_CRC will be
+    * returned to v1 clients, and ENCTYPE_DES_CBC_CRC has the same
+    * value as KEYTYPE_DES used too, which is what all v1 clients
+    * expect.  Therefore, IMHO, just encoding whatever enctype we get
+    * is safe.
+    */
+
+   if (!xdr_u_int(xdrs, (unsigned int *) objp))
+	return (FALSE);
+   return (TRUE);
+}
+
+bool_t
+xdr_krb5_salttype(XDR *xdrs, krb5_int32 *objp)
+{
+    if (!xdr_int32(xdrs, (int32_t *) objp))
+	return FALSE;
+    return TRUE;
+}
+
+bool_t
+xdr_krb5_keyblock(XDR *xdrs, krb5_keyblock *objp)
+{
+   /* XXX This only works because free_keyblock assumes ->contents
+      is allocated by malloc() */
+
+   if(!xdr_krb5_enctype(xdrs, &objp->enctype))
+      return FALSE;
+   if(!xdr_bytes(xdrs, (char **) &objp->contents, (unsigned int *)
+		 &objp->length, ~0))
+      return FALSE;
+   return TRUE;
+}
diff --git a/mechglue/src/lib/kadm5/logger.c b/mechglue/src/lib/kadm5/logger.c
new file mode 100644
index 000000000..69f53a0a4
--- /dev/null
+++ b/mechglue/src/lib/kadm5/logger.c
@@ -0,0 +1,961 @@
+/*
+ * lib/kadm/logger.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/* KADM5 wants non-syslog log files to contain syslog-like entries */
+#define VERBOSE_LOGS
+
+/*
+ * logger.c	- Handle logging functions for those who want it.
+ */
+#include "k5-int.h"
+#include "adm_proto.h"
+#include "com_err.h"
+#include <stdio.h>
+#include <ctype.h>
+#ifdef	HAVE_SYSLOG_H
+#include <syslog.h>
+#endif	/* HAVE_SYSLOG_H */
+#ifdef	HAVE_STDARG_H
+#include <stdarg.h>
+#else	/* HAVE_STDARG_H */
+#include <varargs.h>
+#endif	/* HAVE_STDARG_H */
+
+#define	KRB5_KLOG_MAX_ERRMSG_SIZE	1024
+#ifndef	MAXHOSTNAMELEN
+#define	MAXHOSTNAMELEN	256
+#endif	/* MAXHOSTNAMELEN */
+
+/* This is to assure that we have at least one match in the syslog stuff */
+#ifndef	LOG_AUTH
+#define	LOG_AUTH	0
+#endif	/* LOG_AUTH */
+#ifndef	LOG_ERR
+#define	LOG_ERR		0
+#endif	/* LOG_ERR */
+
+#define lspec_parse_err_1	"%s: cannot parse <%s>\n"
+#define lspec_parse_err_2	"%s: warning - logging entry syntax error\n"
+#define log_file_err		"%s: error writing to %s\n"
+#define log_device_err		"%s: error writing to %s device\n"
+#define log_ufo_string		"?\?\?" /* nb: avoid trigraphs */
+#define log_emerg_string	"EMERGENCY"
+#define log_alert_string	"ALERT"
+#define log_crit_string		"CRITICAL"
+#define log_err_string		"Error"
+#define log_warning_string	"Warning"
+#define log_notice_string	"Notice"
+#define log_info_string		"info"
+#define log_debug_string	"debug"
+
+/*
+ * Output logging.
+ *
+ * Output logging is now controlled by the configuration file.  We can specify
+ * the following syntaxes under the [logging]->entity specification.
+ *	FILE<opentype><pathname>
+ *	SYSLOG[=<severity>[:<facility>]]
+ *	STDERR
+ *	CONSOLE
+ *	DEVICE=<device-spec>
+ *
+ * Where:
+ *	<opentype> is ":" for open/append, "=" for open/create.
+ *	<pathname> is a valid path name.
+ *	<severity> is one of: (default = ERR)
+ *		EMERG
+ *		ALERT
+ *		CRIT
+ *		ERR
+ *		WARNING
+ *		NOTICE
+ *		INFO
+ *		DEBUG
+ *	<facility> is one of: (default = AUTH)
+ *		KERN
+ *		USER
+ *		MAIL
+ *		DAEMON
+ *		AUTH
+ *		LPR
+ *		NEWS
+ *		UUCP
+ *		CRON
+ *		LOCAL0..LOCAL7
+ *	<device-spec> is a valid device specification.
+ */
+struct log_entry {
+    enum log_type { K_LOG_FILE,
+			K_LOG_SYSLOG,
+			K_LOG_STDERR,
+			K_LOG_CONSOLE,
+			K_LOG_DEVICE,
+			K_LOG_NONE } log_type;
+    krb5_pointer log_2free;
+    union log_union {
+	struct log_file {
+	    FILE	*lf_filep;
+	    char	*lf_fname;
+	} log_file;
+	struct log_syslog {
+	    int		ls_facility;
+	    int		ls_severity;
+	} log_syslog;
+	struct log_device {
+	    FILE	*ld_filep;
+	    char	*ld_devname;
+	} log_device;
+    } log_union;
+};
+#define	lfu_filep	log_union.log_file.lf_filep
+#define	lfu_fname	log_union.log_file.lf_fname
+#define	lsu_facility	log_union.log_syslog.ls_facility
+#define	lsu_severity	log_union.log_syslog.ls_severity
+#define	ldu_filep	log_union.log_device.ld_filep
+#define	ldu_devname	log_union.log_device.ld_devname
+
+struct log_control {
+    struct log_entry	*log_entries;
+    int			log_nentries;
+    char		*log_whoami;
+    char		*log_hostname;
+    krb5_boolean	log_opened;
+};
+
+static struct log_control log_control = {
+    (struct log_entry *) NULL,
+    0,
+    (char *) NULL,
+    (char *) NULL,
+    0
+};
+static struct log_entry	def_log_entry;
+
+/*
+ * These macros define any special processing that needs to happen for
+ * devices.  For unix, of course, this is hardly anything.
+ */
+#define	DEVICE_OPEN(d, m)	fopen(d, m)
+#define	CONSOLE_OPEN(m)		fopen("/dev/console", m)
+#define	DEVICE_PRINT(f, m)	((fprintf(f, "%s\r\n", m) >= 0) ? 	\
+				 (fflush(f), 0) :			\
+				 -1)
+#define	DEVICE_CLOSE(d)		fclose(d)
+
+
+/*
+ * klog_com_err_proc()	- Handle com_err(3) messages as specified by the
+ *			  profile.
+ */
+static void
+klog_com_err_proc(const char *whoami, long int code, const char *format, va_list ap)
+{
+    char	outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE];
+    int		lindex;
+    const char	*actual_format;
+#ifdef	HAVE_SYSLOG
+    int		log_pri = -1;
+#endif	/* HAVE_SYSLOG */
+    char	*cp;
+    char	*syslogp;
+
+    /* Make the header */
+    sprintf(outbuf, "%s: ", whoami);
+    /*
+     * Squirrel away address after header for syslog since syslog makes
+     * a header
+     */
+    syslogp = &outbuf[strlen(outbuf)];
+
+    /* If reporting an error message, separate it. */
+    if (code) {
+        outbuf[sizeof(outbuf) - 1] = '\0';
+	strncat(outbuf, error_message(code), sizeof(outbuf) - 1 - strlen(outbuf));
+	strncat(outbuf, " - ", sizeof(outbuf) - 1 - strlen(outbuf));
+    }
+    cp = &outbuf[strlen(outbuf)];
+    
+    actual_format = format;
+#ifdef	HAVE_SYSLOG
+    /*
+     * This is an unpleasant hack.  If the first character is less than
+     * 8, then we assume that it is a priority.
+     *
+     * Since it is not guaranteed that there is a direct mapping between
+     * syslog priorities (e.g. Ultrix and old BSD), we resort to this
+     * intermediate representation.
+     */
+    if ((((unsigned char) *format) > 0) && (((unsigned char) *format) <= 8)) {
+	actual_format = (format + 1);
+	switch ((unsigned char) *format) {
+#ifdef	LOG_EMERG
+	case 1:
+	    log_pri = LOG_EMERG;
+	    break;
+#endif /* LOG_EMERG */
+#ifdef	LOG_ALERT
+	case 2:
+	    log_pri = LOG_ALERT;
+	    break;
+#endif /* LOG_ALERT */
+#ifdef	LOG_CRIT
+	case 3:
+	    log_pri = LOG_CRIT;
+	    break;
+#endif /* LOG_CRIT */
+	default:
+	case 4:
+	    log_pri = LOG_ERR;
+	    break;
+#ifdef	LOG_WARNING
+	case 5:
+	    log_pri = LOG_WARNING;
+	    break;
+#endif /* LOG_WARNING */
+#ifdef	LOG_NOTICE
+	case 6:
+	    log_pri = LOG_NOTICE;
+	    break;
+#endif /* LOG_NOTICE */
+#ifdef	LOG_INFO
+	case 7:
+	    log_pri = LOG_INFO;
+	    break;
+#endif /* LOG_INFO */
+#ifdef	LOG_DEBUG
+	case 8:
+	    log_pri = LOG_DEBUG;
+	    break;
+#endif /* LOG_DEBUG */
+	}
+    } 
+#endif	/* HAVE_SYSLOG */
+
+    /* Now format the actual message */
+#if	HAVE_VSPRINTF
+    vsprintf(cp, actual_format, ap);
+#else	/* HAVE_VSPRINTF */
+    sprintf(cp, actual_format, ((int *) ap)[0], ((int *) ap)[1],
+	    ((int *) ap)[2], ((int *) ap)[3],
+	    ((int *) ap)[4], ((int *) ap)[5]);
+#endif	/* HAVE_VSPRINTF */
+    
+    /*
+     * Now that we have the message formatted, perform the output to each
+     * logging specification.
+     */
+    for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
+	switch (log_control.log_entries[lindex].log_type) {
+	case K_LOG_FILE:
+	case K_LOG_STDERR:
+	    /*
+	     * Files/standard error.
+	     */
+	    if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n",
+			outbuf) < 0) {
+		/* Attempt to report error */
+		fprintf(stderr, log_file_err, whoami,
+			log_control.log_entries[lindex].lfu_fname);
+	    }
+	    else {
+		fflush(log_control.log_entries[lindex].lfu_filep);
+	    }
+	    break;
+	case K_LOG_CONSOLE:
+	case K_LOG_DEVICE:
+	    /*
+	     * Devices (may need special handling)
+	     */
+	    if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep,
+			     outbuf) < 0) {
+		/* Attempt to report error */
+		fprintf(stderr, log_device_err, whoami,
+			log_control.log_entries[lindex].ldu_devname);
+	    }
+	    break;
+#ifdef	HAVE_SYSLOG
+	case K_LOG_SYSLOG:
+	    /*
+	     * System log.
+	     */
+	    /*
+	     * If we have specified a priority through our hackery, then
+	     * use it, otherwise use the default.
+	     */
+	    if (log_pri >= 0)
+		log_pri |= log_control.log_entries[lindex].lsu_facility;
+	    else
+		log_pri = log_control.log_entries[lindex].lsu_facility |
+		    log_control.log_entries[lindex].lsu_severity;
+					       
+	    /* Log the message with our header trimmed off */
+	    syslog(log_pri, "%s", syslogp);
+	    break;
+#endif /* HAVE_SYSLOG */
+	default:
+	    break;
+	}
+    }
+}
+
+/*
+ * krb5_klog_init()	- Initialize logging.
+ *
+ * This routine parses the syntax described above to specify destinations for
+ * com_err(3) or krb5_klog_syslog() messages generated by the caller.
+ *
+ * Parameters:
+ *	kcontext	- Kerberos context.
+ *	ename		- Entity name as it is to appear in the profile.
+ *	whoami		- Entity name as it is to appear in error output.
+ *	do_com_err	- Take over com_err(3) processing.
+ *
+ * Implicit inputs:
+ *	stderr		- This is where STDERR output goes.
+ *
+ * Implicit outputs:
+ *	log_nentries	- Number of log entries, both valid and invalid.
+ *	log_control	- List of entries (log_nentries long) which contains
+ *			  data for klog_com_err_proc() to use to determine
+ *			  where/how to send output.
+ */
+krb5_error_code
+krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do_com_err)
+{
+    const char	*logging_profent[3];
+    const char	*logging_defent[3];
+    char	**logging_specs;
+    int		i, ngood;
+    char	*cp, *cp2;
+    char	savec = '\0';
+    int		error;
+    int		do_openlog, log_facility;
+    FILE	*f;
+
+    /* Initialize */
+    do_openlog = 0;
+    log_facility = 0;
+
+    /*
+     * Look up [logging]-><ename> in the profile.  If that doesn't
+     * succeed, then look for [logging]->default.
+     */
+    logging_profent[0] = "logging";
+    logging_profent[1] = ename;
+    logging_profent[2] = (char *) NULL;
+    logging_defent[0] = "logging";
+    logging_defent[1] = "default";
+    logging_defent[2] = (char *) NULL;
+    logging_specs = (char **) NULL;
+    ngood = 0;
+    log_control.log_nentries = 0;
+    if (!profile_get_values(kcontext->profile,
+			    logging_profent,
+			    &logging_specs) ||
+	!profile_get_values(kcontext->profile,
+			    logging_defent,
+			    &logging_specs)) {
+	/*
+	 * We have a match, so we first count the number of elements
+	 */
+	for (log_control.log_nentries = 0;
+	     logging_specs[log_control.log_nentries];
+	     log_control.log_nentries++);
+
+	/*
+	 * Now allocate our structure.
+	 */
+	log_control.log_entries = (struct log_entry *)
+	    malloc(log_control.log_nentries * sizeof(struct log_entry));
+	if (log_control.log_entries) {
+	    /*
+	     * Scan through the list.
+	     */
+	    for (i=0; i<log_control.log_nentries; i++) {
+		log_control.log_entries[i].log_type = K_LOG_NONE;
+		log_control.log_entries[i].log_2free = logging_specs[i];
+		/*
+		 * The format is:
+		 *	<whitespace><data><whitespace>
+		 * so, trim off the leading and trailing whitespace here.
+		 */
+		for (cp = logging_specs[i]; isspace((int) *cp); cp++);
+		for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1];
+		     isspace((int) *cp2); cp2--);
+		cp2++;
+		*cp2 = '\0';
+		/*
+		 * Is this a file?
+		 */
+		if (!strncasecmp(cp, "FILE", 4)) {
+		    /*
+		     * Check for append/overwrite, then open the file.
+		     */
+		    if (cp[4] == ':' || cp[4] == '=') {
+			f = fopen(&cp[5], (cp[4] == ':') ? "a+" : "w");
+			if (f) {
+			    log_control.log_entries[i].lfu_filep = f;
+			    log_control.log_entries[i].log_type = K_LOG_FILE;
+			    log_control.log_entries[i].lfu_fname = &cp[5];
+			} else {
+			    fprintf(stderr,"Couldn't open log file %s: %s\n",
+				    &cp[5], error_message(errno));
+			    continue;
+			}
+		    }
+		}
+#ifdef	HAVE_SYSLOG
+		/*
+		 * Is this a syslog?
+		 */
+		else if (!strncasecmp(cp, "SYSLOG", 6)) {
+		    error = 0;
+		    log_control.log_entries[i].lsu_facility = LOG_AUTH;
+		    log_control.log_entries[i].lsu_severity = LOG_ERR;
+		    /*
+		     * Is there a severify specified?
+		     */
+		    if (cp[6] == ':') {
+			/*
+			 * Find the end of the severity.
+			 */
+			cp2 = strchr(&cp[7], ':');
+			if (cp2) {
+			    savec = *cp2;
+			    *cp2 = '\0';
+			    cp2++;
+			}
+
+			/*
+			 * Match a severity.
+			 */
+			if (!strcasecmp(&cp[7], "ERR")) {
+			    log_control.log_entries[i].lsu_severity = LOG_ERR;
+			}
+#ifdef	LOG_EMERG
+			else if (!strcasecmp(&cp[7], "EMERG")) {
+			    log_control.log_entries[i].lsu_severity =
+				LOG_EMERG;
+			}
+#endif	/* LOG_EMERG */
+#ifdef	LOG_ALERT
+			else if (!strcasecmp(&cp[7], "ALERT")) {
+			    log_control.log_entries[i].lsu_severity =
+				LOG_ALERT;
+			}
+#endif	/* LOG_ALERT */
+#ifdef	LOG_CRIT
+			else if (!strcasecmp(&cp[7], "CRIT")) {
+			    log_control.log_entries[i].lsu_severity = LOG_CRIT;
+			}
+#endif	/* LOG_CRIT */
+#ifdef	LOG_WARNING
+			else if (!strcasecmp(&cp[7], "WARNING")) {
+			    log_control.log_entries[i].lsu_severity =
+				LOG_WARNING;
+			}
+#endif	/* LOG_WARNING */
+#ifdef	LOG_NOTICE
+			else if (!strcasecmp(&cp[7], "NOTICE")) {
+			    log_control.log_entries[i].lsu_severity =
+				LOG_NOTICE;
+			}
+#endif	/* LOG_NOTICE */
+#ifdef	LOG_INFO
+			else if (!strcasecmp(&cp[7], "INFO")) {
+			    log_control.log_entries[i].lsu_severity = LOG_INFO;
+			}
+#endif	/* LOG_INFO */
+#ifdef	LOG_DEBUG
+			else if (!strcasecmp(&cp[7], "DEBUG")) {
+			    log_control.log_entries[i].lsu_severity =
+				LOG_DEBUG;
+			}
+#endif	/* LOG_DEBUG */
+			else
+			    error = 1;
+
+			/*
+			 * If there is a facility present, then parse that.
+			 */
+			if (cp2) {
+			    const struct {
+				const char *name;
+				int value;
+			    } facilities[] = {
+				{ "AUTH",	LOG_AUTH	},
+#ifdef	LOG_AUTHPRIV
+				{ "AUTHPRIV",	LOG_AUTHPRIV	},
+#endif	/* LOG_AUTHPRIV */
+#ifdef	LOG_KERN
+				{ "KERN",	LOG_KERN	},
+#endif	/* LOG_KERN */
+#ifdef	LOG_USER
+				{ "USER",	LOG_USER	},
+#endif	/* LOG_USER */
+#ifdef	LOG_MAIL
+				{ "MAIL",	LOG_MAIL	},
+#endif	/* LOG_MAIL */
+#ifdef	LOG_DAEMON
+				{ "DAEMON",	LOG_DAEMON	},
+#endif	/* LOG_DAEMON */
+#ifdef	LOG_FTP
+				{ "FTP",	LOG_FTP		},
+#endif	/* LOG_FTP */
+#ifdef	LOG_LPR
+				{ "LPR",	LOG_LPR		},
+#endif	/* LOG_LPR */
+#ifdef	LOG_NEWS
+				{ "NEWS",	LOG_NEWS	},
+#endif	/* LOG_NEWS */
+#ifdef	LOG_UUCP
+				{ "UUCP",	LOG_UUCP	},
+#endif	/* LOG_UUCP */
+#ifdef	LOG_CRON
+				{ "CRON",	LOG_CRON	},
+#endif	/* LOG_CRON */
+#ifdef	LOG_LOCAL0
+				{ "LOCAL0",	LOG_LOCAL0	},
+#endif	/* LOG_LOCAL0 */
+#ifdef	LOG_LOCAL1
+				{ "LOCAL1",	LOG_LOCAL1	},
+#endif	/* LOG_LOCAL1 */
+#ifdef	LOG_LOCAL2
+				{ "LOCAL2",	LOG_LOCAL2	},
+#endif	/* LOG_LOCAL2 */
+#ifdef	LOG_LOCAL3
+				{ "LOCAL3",	LOG_LOCAL3	},
+#endif	/* LOG_LOCAL3 */
+#ifdef	LOG_LOCAL4
+				{ "LOCAL4",	LOG_LOCAL4	},
+#endif	/* LOG_LOCAL4 */
+#ifdef	LOG_LOCAL5
+				{ "LOCAL5",	LOG_LOCAL5	},
+#endif	/* LOG_LOCAL5 */
+#ifdef	LOG_LOCAL6
+				{ "LOCAL6",	LOG_LOCAL6	},
+#endif	/* LOG_LOCAL6 */
+#ifdef	LOG_LOCAL7
+				{ "LOCAL7",	LOG_LOCAL7	},
+#endif	/* LOG_LOCAL7 */
+			    };
+			    int j;
+
+			    for (j = 0; j < sizeof(facilities)/sizeof(facilities[0]); j++)
+				if (!strcasecmp(cp2, facilities[j].name)) {
+				    log_control.log_entries[i].lsu_facility = facilities[j].value;
+				    break;
+				}
+			    cp2--;
+			    *cp2 = savec;
+			}
+		    }
+		    if (!error) {
+			log_control.log_entries[i].log_type = K_LOG_SYSLOG;
+			do_openlog = 1;
+			log_facility = log_control.log_entries[i].lsu_facility;
+		    }
+		}
+#endif	/* HAVE_SYSLOG */
+		/*
+		 * Is this a standard error specification?
+		 */
+		else if (!strcasecmp(cp, "STDERR")) {
+		    log_control.log_entries[i].lfu_filep =
+			fdopen(fileno(stderr), "a+");
+		    if (log_control.log_entries[i].lfu_filep) {
+			log_control.log_entries[i].log_type = K_LOG_STDERR;
+			log_control.log_entries[i].lfu_fname =
+			    "standard error";
+		    }
+		}
+		/*
+		 * Is this a specification of the console?
+		 */
+		else if (!strcasecmp(cp, "CONSOLE")) {
+		    log_control.log_entries[i].ldu_filep =
+			CONSOLE_OPEN("a+");
+		    if (log_control.log_entries[i].ldu_filep) {
+			log_control.log_entries[i].log_type = K_LOG_CONSOLE;
+			log_control.log_entries[i].ldu_devname = "console";
+		    }
+		}
+		/*
+		 * Is this a specification of a device?
+		 */
+		else if (!strncasecmp(cp, "DEVICE", 6)) {
+		    /*
+		     * We handle devices very similarly to files.
+		     */
+		    if (cp[6] == '=') {
+			log_control.log_entries[i].ldu_filep = 
+			    DEVICE_OPEN(&cp[7], "w");
+			if (log_control.log_entries[i].ldu_filep) {
+			    log_control.log_entries[i].log_type = K_LOG_DEVICE;
+			    log_control.log_entries[i].ldu_devname = &cp[7];
+			}
+		    }
+		}
+		/*
+		 * See if we successfully parsed this specification.
+		 */
+		if (log_control.log_entries[i].log_type == K_LOG_NONE) {
+		    fprintf(stderr, lspec_parse_err_1, whoami, cp);
+		    fprintf(stderr, lspec_parse_err_2, whoami);
+		}
+		else
+		    ngood++;
+	    }
+	}
+	/*
+	 * If we didn't find anything, then free our lists.
+	 */
+	if (ngood == 0) {
+	    for (i=0; i<log_control.log_nentries; i++)
+		free(logging_specs[i]);
+	}
+	free(logging_specs);
+    }
+    /*
+     * If we didn't find anything, go for the default which is to log to
+     * the system log.
+     */
+    if (ngood == 0) {
+	if (log_control.log_entries)
+	    free(log_control.log_entries);
+	log_control.log_entries = &def_log_entry;
+	log_control.log_entries->log_type = K_LOG_SYSLOG;
+	log_control.log_entries->log_2free = (krb5_pointer) NULL;
+	log_facility = log_control.log_entries->lsu_facility = LOG_AUTH;
+	log_control.log_entries->lsu_severity = LOG_ERR;
+	do_openlog = 1;
+	log_control.log_nentries = 1;
+    }
+    if (log_control.log_nentries) {
+	log_control.log_whoami = (char *) malloc(strlen(whoami)+1);
+	if (log_control.log_whoami)
+	    strcpy(log_control.log_whoami, whoami);
+
+	log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN + 1);
+	if (log_control.log_hostname) {
+	    gethostname(log_control.log_hostname, MAXHOSTNAMELEN);
+	    log_control.log_hostname[MAXHOSTNAMELEN] = '\0';
+	}
+#ifdef	HAVE_OPENLOG
+	if (do_openlog) {
+	    openlog(whoami, LOG_NDELAY|LOG_PID, log_facility);
+	    log_control.log_opened = 1;
+	}
+#endif /* HAVE_OPENLOG */
+	if (do_com_err)
+	    (void) set_com_err_hook(klog_com_err_proc);
+    }
+    return((log_control.log_nentries) ? 0 : ENOENT);
+}
+
+/*
+ * krb5_klog_close()	- Close the logging context and free all data.
+ */
+void
+krb5_klog_close(krb5_context kcontext)
+{
+    int lindex;
+    (void) reset_com_err_hook();
+    for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
+	switch (log_control.log_entries[lindex].log_type) {
+	case K_LOG_FILE:
+	case K_LOG_STDERR:
+	    /*
+	     * Files/standard error.
+	     */
+	    fclose(log_control.log_entries[lindex].lfu_filep);
+	    break;
+	case K_LOG_CONSOLE:
+	case K_LOG_DEVICE:
+	    /*
+	     * Devices (may need special handling)
+	     */
+	    DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep);
+	    break;
+#ifdef	HAVE_SYSLOG
+	case K_LOG_SYSLOG:
+	    /*
+	     * System log.
+	     */
+	    break;
+#endif	/* HAVE_SYSLOG */
+	default:
+	    break;
+	}
+	if (log_control.log_entries[lindex].log_2free)
+	    free(log_control.log_entries[lindex].log_2free);
+    }
+    if (log_control.log_entries != &def_log_entry)
+	free(log_control.log_entries);
+    log_control.log_entries = (struct log_entry *) NULL;
+    log_control.log_nentries = 0;
+    if (log_control.log_whoami)
+	free(log_control.log_whoami);
+    log_control.log_whoami = (char *) NULL;
+    if (log_control.log_hostname)
+	free(log_control.log_hostname);
+    log_control.log_hostname = (char *) NULL;
+#ifdef	HAVE_CLOSELOG
+    if (log_control.log_opened)
+	closelog();
+#endif	/* HAVE_CLOSELOG */
+}
+
+/*
+ * severity2string()	- Convert a severity to a string.
+ */
+static const char *
+severity2string(int severity)
+{
+    int s;
+    const char *ss;
+
+    s = severity & LOG_PRIMASK;
+    ss = log_ufo_string;
+    switch (s) {
+#ifdef	LOG_EMERG
+    case LOG_EMERG:
+	ss = log_emerg_string;
+	break;
+#endif	/* LOG_EMERG */
+#ifdef	LOG_ALERT
+    case LOG_ALERT:
+	ss = log_alert_string;
+	break;
+#endif	/* LOG_ALERT */
+#ifdef	LOG_CRIT
+    case LOG_CRIT:
+	ss = log_crit_string;
+	break;
+#endif	/* LOG_CRIT */
+    case LOG_ERR:
+	ss = log_err_string;
+	break;
+#ifdef	LOG_WARNING
+    case LOG_WARNING:
+	ss = log_warning_string;
+	break;
+#endif	/* LOG_WARNING */
+#ifdef	LOG_NOTICE
+    case LOG_NOTICE:
+	ss = log_notice_string;
+	break;
+#endif	/* LOG_NOTICE */
+#ifdef	LOG_INFO
+    case LOG_INFO:
+	ss = log_info_string;
+	break;
+#endif	/* LOG_INFO */
+#ifdef	LOG_DEBUG
+    case LOG_DEBUG:
+	ss = log_debug_string;
+	break;
+#endif	/* LOG_DEBUG */
+    }
+    return(ss);
+}
+
+/*
+ * krb5_klog_syslog()	- Simulate the calling sequence of syslog(3), while
+ *			  also performing the logging redirection as specified
+ *			  by krb5_klog_init().
+ */
+static int
+klog_vsyslog(int priority, const char *format, va_list arglist)
+{
+    char	outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE];
+    int		lindex;
+    char	*syslogp;
+    char	*cp;
+    time_t	now;
+#ifdef	HAVE_STRFTIME
+    size_t	soff;
+#endif	/* HAVE_STRFTIME */
+
+    /*
+     * Format a syslog-esque message of the format:
+     *
+     * (verbose form)
+     * 		<date> <hostname> <id>[<pid>](<priority>): <message>
+     *
+     * (short form)
+     *		<date> <message>
+     */
+    cp = outbuf;
+    (void) time(&now);
+#ifdef	HAVE_STRFTIME
+    /*
+     * Format the date: mon dd hh:mm:ss
+     */
+    soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", localtime(&now));
+    if (soff > 0)
+	cp += soff;
+    else
+	return(-1);
+#else	/* HAVE_STRFTIME */
+    /*
+     * Format the date:
+     * We ASSUME here that the output of ctime is of the format:
+     *	dow mon dd hh:mm:ss tzs yyyy\n
+     *  012345678901234567890123456789
+     */
+    strncpy(outbuf, ctime(&now) + 4, 15);
+    cp += 15;
+#endif	/* HAVE_STRFTIME */
+#ifdef VERBOSE_LOGS
+    sprintf(cp, " %s %s[%ld](%s): ",
+	    log_control.log_hostname ? log_control.log_hostname : "", 
+	    log_control.log_whoami ? log_control.log_whoami : "", 
+	    (long) getpid(),
+	    severity2string(priority));
+#else
+    sprintf(cp, " ");
+#endif
+    syslogp = &outbuf[strlen(outbuf)];
+
+    /* Now format the actual message */
+#ifdef	HAVE_VSPRINTF
+    vsprintf(syslogp, format, arglist);
+#else	/* HAVE_VSPRINTF */
+    sprintf(syslogp, format, ((int *) arglist)[0], ((int *) arglist)[1],
+	    ((int *) arglist)[2], ((int *) arglist)[3],
+	    ((int *) arglist)[4], ((int *) arglist)[5]);
+#endif	/* HAVE_VSPRINTF */
+
+    /*
+     * If the user did not use krb5_klog_init() instead of dropping
+     * the request on the floor, syslog it - if it exists
+     */
+#ifdef HAVE_SYSLOG
+    if (log_control.log_nentries == 0) {
+	/* Log the message with our header trimmed off */
+	syslog(priority, "%s", syslogp);
+    }
+#endif
+
+    /*
+     * Now that we have the message formatted, perform the output to each
+     * logging specification.
+     */
+    for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
+	switch (log_control.log_entries[lindex].log_type) {
+	case K_LOG_FILE:
+	case K_LOG_STDERR:
+	    /*
+	     * Files/standard error.
+	     */
+	    if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s\n",
+			outbuf) < 0) {
+		/* Attempt to report error */
+		fprintf(stderr, log_file_err, log_control.log_whoami,
+			log_control.log_entries[lindex].lfu_fname);
+	    }
+	    else {
+		fflush(log_control.log_entries[lindex].lfu_filep);
+	    }
+	    break;
+	case K_LOG_CONSOLE:
+	case K_LOG_DEVICE:
+	    /*
+	     * Devices (may need special handling)
+	     */
+	    if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep,
+			     outbuf) < 0) {
+		/* Attempt to report error */
+		fprintf(stderr, log_device_err, log_control.log_whoami,
+			log_control.log_entries[lindex].ldu_devname);
+	    }
+	    break;
+#ifdef	HAVE_SYSLOG
+	case K_LOG_SYSLOG:
+	    /*
+	     * System log.
+	     */
+					       
+	    /* Log the message with our header trimmed off */
+	    syslog(priority, "%s", syslogp);
+	    break;
+#endif /* HAVE_SYSLOG */
+	default:
+	    break;
+	}
+    }
+    return(0);
+}
+
+int
+krb5_klog_syslog(int priority, const char *format, ...)
+{
+    int		retval;
+    va_list	pvar;
+
+    va_start(pvar, format);
+    retval = klog_vsyslog(priority, format, pvar);
+    va_end(pvar);
+    return(retval);
+}
+
+/*
+ * krb5_klog_reopen() - Close and reopen any open (non-syslog) log files.
+ *                      This function is called when a SIGHUP is received
+ *                      so that external log-archival utilities may
+ *                      alert the Kerberos daemons that they should get
+ *                      a new file descriptor for the give filename.
+ */
+void
+krb5_klog_reopen(krb5_context kcontext)
+{
+    int lindex;
+    FILE *f;
+
+    /*
+     * Only logs which are actually files need to be closed
+     * and reopened in response to a SIGHUP
+     */
+    for (lindex = 0; lindex < log_control.log_nentries; lindex++) {
+	if (log_control.log_entries[lindex].log_type == K_LOG_FILE) {
+	    fclose(log_control.log_entries[lindex].lfu_filep);
+	    /*
+	     * In case the old logfile did not get moved out of the
+	     * way, open for append to prevent squashing the old logs.
+	     */
+	    f = fopen(log_control.log_entries[lindex].lfu_fname, "a+");
+	    if (f) {
+		log_control.log_entries[lindex].lfu_filep = f;
+	    } else {
+		fprintf(stderr, "Couldn't open log file %s: %s\n",
+			log_control.log_entries[lindex].lfu_fname,
+			error_message(errno));
+	    }
+	}
+    }
+}
diff --git a/mechglue/src/lib/kadm5/misc_free.c b/mechglue/src/lib/kadm5/misc_free.c
new file mode 100644
index 000000000..9dc91b53f
--- /dev/null
+++ b/mechglue/src/lib/kadm5/misc_free.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+#include	<kadm5/admin.h>
+#include	<stdlib.h>
+#include	"server_internal.h"
+
+kadm5_ret_t
+kadm5_free_policy_ent(void *server_handle, kadm5_policy_ent_t val)
+{
+    kadm5_server_handle_t	handle = server_handle;
+
+    _KADM5_CHECK_HANDLE(server_handle);
+
+    if(val) {
+	if (val->policy)
+	    free(val->policy);
+	if (handle->api_version == KADM5_API_VERSION_1)
+	     free(val);
+    }
+    return KADM5_OK;
+}
+
+kadm5_ret_t
+     kadm5_free_name_list(void *server_handle, char **names, int count)
+{
+    _KADM5_CHECK_HANDLE(server_handle);
+	  
+    while (count--)
+	  free(names[count]);
+     free(names);
+    return KADM5_OK;
+}
+
+/* XXX this ought to be in libkrb5.a, but isn't */
+kadm5_ret_t krb5_free_key_data_contents(context, key)
+   krb5_context context;
+   krb5_key_data *key;
+{
+     int i, idx;
+     
+     idx = (key->key_data_ver == 1 ? 1 : 2);
+     for (i = 0; i < idx; i++) {
+	  if (key->key_data_contents[i]) {
+	       memset(key->key_data_contents[i], 0, key->key_data_length[i]);
+	       free(key->key_data_contents[i]);
+	  }
+     }
+     return KADM5_OK;
+}
+
+kadm5_ret_t kadm5_free_key_data(void *server_handle,
+				krb5_int16 *n_key_data,
+				krb5_key_data *key_data)
+{
+     kadm5_server_handle_t	handle = server_handle;
+     int i, nkeys = (int) *n_key_data;
+
+     _KADM5_CHECK_HANDLE(server_handle);
+
+     if (key_data == NULL)
+	  return KADM5_OK;
+     
+     for (i = 0; i < nkeys; i++)
+	  krb5_free_key_data_contents(handle->context, &key_data[i]);
+     free(key_data);
+     return KADM5_OK;
+}
+
+kadm5_ret_t
+kadm5_free_principal_ent(void *server_handle,
+			      kadm5_principal_ent_t val)
+{
+    kadm5_server_handle_t	handle = server_handle;
+    int i;
+
+    _KADM5_CHECK_HANDLE(server_handle);
+
+    if(val) {
+	if(val->principal) 
+	    krb5_free_principal(handle->context, val->principal);
+	if(val->mod_name)
+	    krb5_free_principal(handle->context, val->mod_name);
+	if(val->policy)
+	    free(val->policy);
+	if (handle->api_version > KADM5_API_VERSION_1) {
+	     if (val->n_key_data) {
+		  for (i = 0; i < val->n_key_data; i++)
+		       krb5_free_key_data_contents(handle->context,
+						   &val->key_data[i]);
+		  free(val->key_data);
+	     }
+	     if (val->tl_data) {
+		  krb5_tl_data *tl;
+		  
+		  while (val->tl_data) {
+		       tl = val->tl_data->tl_data_next;
+		       free(val->tl_data->tl_data_contents);
+		       free(val->tl_data);
+		       val->tl_data = tl;
+		  }
+	     }
+	}
+	
+	if (handle->api_version == KADM5_API_VERSION_1)
+	     free(val);
+    }
+    return KADM5_OK;
+}
diff --git a/mechglue/src/lib/kadm5/ovsec_glue.c b/mechglue/src/lib/kadm5/ovsec_glue.c
new file mode 100644
index 000000000..750aa3f81
--- /dev/null
+++ b/mechglue/src/lib/kadm5/ovsec_glue.c
@@ -0,0 +1,193 @@
+#define USE_KADM5_API_VERSION 1
+#include <kadm5/admin.h>
+
+ovsec_kadm_ret_t ovsec_kadm_init_with_password(char *client_name, char *pass,
+					       char *service_name,
+					       char *realm,
+					       krb5_ui_4 struct_version,
+					       krb5_ui_4 api_version,
+					       char **db_args,
+					       void **server_handle)
+{
+     return kadm5_init_with_password(client_name, pass, service_name,
+				     realm, struct_version, api_version, db_args,
+				     server_handle);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_init_with_skey(char *client_name, char *keytab,
+					   char *service_name,
+					   char *realm,
+					   krb5_ui_4 struct_version,
+					   krb5_ui_4 api_version,
+					   char **db_args,
+					   void **server_handle)
+{
+     return kadm5_init_with_skey(client_name, keytab, service_name, realm,
+				 struct_version, api_version, db_args,
+				 server_handle);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_init(char *client_name, char *from_stash,
+				 char *service_name,
+				 char *realm,
+				 krb5_ui_4 struct_version,
+				 krb5_ui_4 api_version,
+				 char **db_args,
+				 void **server_handle)
+{
+     return kadm5_init(client_name, from_stash, service_name,
+		       realm, struct_version, api_version, db_args,
+		       server_handle);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_destroy(void *server_handle)
+{
+     return kadm5_destroy(server_handle);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_flush(void *server_handle)
+{
+     return kadm5_flush(server_handle);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_create_principal(void *server_handle,
+					     ovsec_kadm_principal_ent_t entry,
+					     long mask,
+					     char *password)
+{
+     return kadm5_create_principal(server_handle,
+				   (kadm5_principal_ent_t)
+				   entry, mask, password);
+}
+
+
+ovsec_kadm_ret_t ovsec_kadm_delete_principal(void *server_handle,
+					     krb5_principal principal)
+{
+     return kadm5_delete_principal(server_handle, principal);
+}
+
+
+ovsec_kadm_ret_t ovsec_kadm_modify_principal(void *server_handle,
+					     ovsec_kadm_principal_ent_t entry,
+					     long mask)
+{
+     return kadm5_modify_principal(server_handle,
+				   (kadm5_principal_ent_t) entry, mask);
+}
+
+
+ovsec_kadm_ret_t ovsec_kadm_rename_principal(void *server_handle,
+					     krb5_principal source,
+					     krb5_principal target)
+{
+     return kadm5_rename_principal(server_handle, source, target);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_get_principal(void *server_handle,
+					  krb5_principal principal,
+					  ovsec_kadm_principal_ent_t *entry)
+{
+     return kadm5_get_principal(server_handle, principal,
+				(kadm5_principal_ent_t *) entry);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_chpass_principal(void *server_handle,
+					     krb5_principal principal,
+					     char *password)
+{
+     return kadm5_chpass_principal(server_handle, principal, password);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_chpass_principal_util(void *server_handle,
+						  krb5_principal princ,
+						  char *new_pw, 
+						  char **ret_pw,
+						  char *msg_ret)
+{
+    /* Oh crap.  Can't change the API without bumping the API version... */
+    memset(msg_ret, '\0', 1024);
+    return kadm5_chpass_principal_util(server_handle, princ, new_pw,
+				       ret_pw, msg_ret, 1024);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_randkey_principal(void *server_handle,
+					      krb5_principal principal,
+					      krb5_keyblock **key)
+{
+     return kadm5_randkey_principal(server_handle, principal, key);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_create_policy(void *server_handle,
+					  ovsec_kadm_policy_ent_t entry,
+					  long mask)
+{
+     return kadm5_create_policy(server_handle,
+				(kadm5_policy_ent_t) entry, mask); 
+}
+
+ovsec_kadm_ret_t ovsec_kadm_delete_policy(void *server_handle,
+					  ovsec_kadm_policy_t name)
+{
+     return kadm5_delete_policy(server_handle, (kadm5_policy_t) name);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_modify_policy(void *server_handle,
+					  ovsec_kadm_policy_ent_t entry,
+					  long mask)
+{
+     return kadm5_modify_policy(server_handle,
+				(kadm5_policy_ent_t) entry, mask); 
+}
+
+
+ovsec_kadm_ret_t ovsec_kadm_get_policy(void *server_handle,
+				       ovsec_kadm_policy_t name,
+				       ovsec_kadm_policy_ent_t *entry)
+{
+     return kadm5_get_policy(server_handle, (kadm5_policy_t) name,
+			     (kadm5_policy_ent_t *) entry);
+}
+
+
+ovsec_kadm_ret_t ovsec_kadm_free_policy_ent(void *server_handle,
+					    ovsec_kadm_policy_ent_t val)
+{
+     return kadm5_free_policy_ent(server_handle, (kadm5_policy_ent_t) val);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_free_name_list(void *server_handle,
+					   char **names, int count) 
+{
+     return kadm5_free_name_list(server_handle, names, count);
+}
+
+ovsec_kadm_ret_t
+ovsec_kadm_free_principal_ent(void *server_handle,
+			      ovsec_kadm_principal_ent_t val)
+{
+     return kadm5_free_principal_ent(server_handle,
+				     (kadm5_principal_ent_t) val);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_get_privs(void *server_handle, long *privs)
+{
+     return kadm5_get_privs(server_handle, privs);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_get_principals(void *server_handle,
+					   char *exp,
+					   char ***princs,
+					   int *count)
+{
+     return kadm5_get_principals(server_handle, exp, princs, count);
+}
+
+ovsec_kadm_ret_t ovsec_kadm_get_policies(void *server_handle,
+					   char *exp,
+					   char ***pols,
+					   int *count)
+{
+     return kadm5_get_policies(server_handle, exp, pols, count);
+}
+
diff --git a/mechglue/src/lib/kadm5/server_internal.h b/mechglue/src/lib/kadm5/server_internal.h
new file mode 100644
index 000000000..cf4755b6d
--- /dev/null
+++ b/mechglue/src/lib/kadm5/server_internal.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+/*
+ * This header file is used internally by the Admin API server
+ * libraries and Admin server.  IF YOU THINK YOU NEED TO USE THIS FILE
+ * FOR ANYTHING, YOU'RE ALMOST CERTAINLY WRONG.
+ */
+
+#ifndef __KADM5_SERVER_INTERNAL_H__
+#define __KADM5_SERVER_INTERNAL_H__
+
+#ifdef HAVE_MEMORY_H
+#include    <memory.h>
+#endif
+#include    <stdlib.h>
+#include    <errno.h>
+#include    <krb5/kdb.h>
+#include    <kadm5/admin.h>
+#include    "admin_internal.h"
+
+typedef struct _kadm5_server_handle_t {
+	krb5_ui_4	magic_number;
+	krb5_ui_4	struct_version;
+	krb5_ui_4	api_version;
+	krb5_context	context;
+	krb5_principal	current_caller;
+	kadm5_config_params  params;
+	struct _kadm5_server_handle_t *lhandle;
+        char **db_args;
+} kadm5_server_handle_rec, *kadm5_server_handle_t;
+
+#define OSA_ADB_PRINC_VERSION_1  0x12345C01
+
+typedef struct _osa_pw_hist_t {
+  int n_key_data;
+  krb5_key_data *key_data;
+} osa_pw_hist_ent, *osa_pw_hist_t;
+
+typedef struct _osa_princ_ent_t {
+  int                         version;
+  char                        *policy;
+  long                        aux_attributes;
+  unsigned int                old_key_len;
+  unsigned int                old_key_next;
+  krb5_kvno                   admin_history_kvno;
+  osa_pw_hist_ent             *old_keys;
+} osa_princ_ent_rec, *osa_princ_ent_t;
+
+
+kadm5_ret_t    adb_policy_init(kadm5_server_handle_t handle);
+kadm5_ret_t    adb_policy_close(kadm5_server_handle_t handle);
+kadm5_ret_t    passwd_check(kadm5_server_handle_t handle,
+			    char *pass, int use_policy,
+			    kadm5_policy_ent_t policy,
+			    krb5_principal principal);
+kadm5_ret_t    principal_exists(krb5_principal principal);
+krb5_error_code	    kdb_init_master(kadm5_server_handle_t handle,
+				    char *r, int from_keyboard);
+krb5_error_code	    kdb_init_hist(kadm5_server_handle_t handle,
+				  char *r);
+krb5_error_code     kdb_get_entry(kadm5_server_handle_t handle,
+				  krb5_principal principal, krb5_db_entry *kdb,
+				  osa_princ_ent_rec *adb);
+krb5_error_code     kdb_free_entry(kadm5_server_handle_t handle,
+				   krb5_db_entry *kdb, osa_princ_ent_rec *adb);
+krb5_error_code     kdb_put_entry(kadm5_server_handle_t handle,
+				  krb5_db_entry *kdb, osa_princ_ent_rec *adb);
+krb5_error_code     kdb_delete_entry(kadm5_server_handle_t handle,
+				     krb5_principal name);
+krb5_error_code     kdb_iter_entry(kadm5_server_handle_t handle,
+				   char *match_entry,
+				   void (*iter_fct)(void *, krb5_principal), 
+				   void *data);
+
+int		    init_dict(kadm5_config_params *);
+int		    find_word(const char *word);
+void		    destroy_dict(void);
+
+/* XXX this ought to be in libkrb5.a, but isn't */
+kadm5_ret_t krb5_copy_key_data_contents(krb5_context context,
+					krb5_key_data *from, 
+					krb5_key_data *to);
+kadm5_ret_t krb5_free_key_data_contents(krb5_context context, 
+					krb5_key_data *key);
+
+/*
+ * *Warning* 
+ * *Warning*	    This is going to break if we     
+ * *Warning*	    ever go multi-threaded	     
+ * *Warning* 
+ */
+extern	krb5_principal	current_caller;
+
+/*
+ * Why is this (or something similar) not defined *anywhere* in krb5?
+ */
+#define KSUCCESS	0
+#define WORD_NOT_FOUND	1
+
+/*
+ * all the various mask bits or'd together
+ */
+
+#define	ALL_PRINC_MASK \
+ (KADM5_PRINCIPAL | KADM5_PRINC_EXPIRE_TIME | KADM5_PW_EXPIRATION | \
+  KADM5_LAST_PWD_CHANGE | KADM5_ATTRIBUTES | KADM5_MAX_LIFE | \
+  KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_KVNO | KADM5_MKVNO | \
+  KADM5_AUX_ATTRIBUTES | KADM5_POLICY_CLR | KADM5_POLICY | \
+  KADM5_MAX_RLIFE | KADM5_TL_DATA | KADM5_KEY_DATA)
+
+#define ALL_POLICY_MASK \
+ (KADM5_POLICY | KADM5_PW_MAX_LIFE | KADM5_PW_MIN_LIFE | \
+  KADM5_PW_MIN_LENGTH | KADM5_PW_MIN_CLASSES | KADM5_PW_HISTORY_NUM | \
+  KADM5_REF_COUNT)
+
+#define SERVER_CHECK_HANDLE(handle) \
+{ \
+	kadm5_server_handle_t srvr = \
+	     (kadm5_server_handle_t) handle; \
+ \
+	if (! srvr->current_caller) \
+		return KADM5_BAD_SERVER_HANDLE; \
+	if (! srvr->lhandle) \
+	        return KADM5_BAD_SERVER_HANDLE; \
+}
+
+#define CHECK_HANDLE(handle) \
+     GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION, \
+			  KADM5_NEW_SERVER_API_VERSION) \
+     SERVER_CHECK_HANDLE(handle)
+
+bool_t          xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp);
+
+void
+osa_free_princ_ent(osa_princ_ent_t val);
+
+#endif /* __KADM5_SERVER_INTERNAL_H__ */
diff --git a/mechglue/src/lib/kadm5/srv/ChangeLog b/mechglue/src/lib/kadm5/srv/ChangeLog
new file mode 100644
index 000000000..39fb06e3a
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/ChangeLog
@@ -0,0 +1,581 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* server_init.c, svr_policy.c: Include errno.h.
+
+2005-10-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkadm5srv.exports: Don't export internal error-table symbols,
+	or osa* symbols that no longer exist in this library.
+
+2005-09-27  Tom Yu  <tlyu@mit.edu>
+
+	* svr_iters.c (glob_to_regexp): Increment pointer, not character,
+	when handling backslash quoting.  Patch from K.G. Gokulavasan.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	Novell merge.
+	* Makefile.in (SRCS, OBJS, STLIBOBJS): Remove adb_policy,
+	adb_free, and adb_openclose.
+	* adb_free.c: Deleted.
+	* adb_openclose.c, adb_policy.c: Moved to lib/kdb/kdb_db2.
+	* adb_xdr.c: Include server_internal.h; don't include adb.h.
+	(xdr_osa_policy_ent_rec): Function deleted.
+	(osa_free_princ_ent): Moved here from old adb_free.c.
+	* server_init.c (dup_db_args, free_db_args): New functions.
+	(kadm5_init_with_password, kadm5_init_with_creds,
+	kadm5_init_with_skey): Accept new db_args argument, and pass it to
+	kadm5_init.
+	(kadm5_init): Accept new db_args argument.  Don't set the database
+	name; instead, set the default realm for the context.  Call
+	krb5_db_open instead of krb5_db_init, requesting write access and
+	passing in the database arguments.  Don't call adb_policy_init,
+	and don't set deleted field handle->lhandle->policy_db.
+	(kadm5_lock): Don't lock the policy database.  Use
+	KRB5_DB_LOCKMODE_EXCLUSIVE flags instead of
+	KRB5_LOCKMODE_EXCLUSIVE.
+	(kadm5_unlock): Don't unlock the policy database.
+	(kadm5_flush): In the error case, use krb5_db_open instead of
+	krb5_db_set_name and krb5_db_init.
+	* server_kdb.c (kdb_init_master): Don't call krb5_db_init.  Use
+	KADM5_XDR_FAILURE instead of OSA_ADB_XDR_FAILURE.
+	(kdb_iter_entry): Accept new string argument match_entry; pass it
+	to krb5_db_iterate.
+	* server_misc.c: Don't include adb.h.
+	(adb_policy_init): Don't call osa_adb_open_policy.  If
+	krb5_db_inited is falso on the context, call krb5_db_open.
+	(adb_policy_close): Don't call osa_adb_close_policy; do nothing.
+	* svr_iters.c: Don't include adb.h.
+	(kadm5_get_either): Pass glob pattern ("*" if not specified) to
+	kdb_iter_entry.
+	* svr_policy.c: Don't include adb.h.
+	(kadm5_create_policy, kadm5_delete_policy, kadm5_modify_policy,
+	kadm5_get_policy): Call krb5_db_clr_error.  Call
+	krb5_db_create_policy etc instead of osa_adb_* versions, passing
+	the krb5 context instead of the policy database handle.  For
+	krb5_db_get_policy, treat a returned count of zero as a not-found
+	indication.
+	(kadm5_modify_policy_internal): Don't translate the returned error
+	code from krb5_db_put_policy.
+	* svr_principal.c: Don't include adb.h.
+	(kadm5_copy_principal, kadm5_free_principal): New functions, using
+	krb5_db_alloc and krb5_db_free for storage.
+	(cleanup_key_data): Use krb5_db_free.
+	(kadm5_create_principal_3, kadm5_delete_principal,
+	kadm5_modify_principal, kadm5_rename_principal,
+	kadm5_get_principal, kadm5_chpass_principal_3,
+	kadm5_randkey_principal_3, kadm5_setv4key_principal,
+	kadm5_setkey_principal_3, 
+
+	): Call krb5_db_clr_error.
+	(kadm5_create_principal_3): Use kadm5_copy_principal instead of
+	krb5_copy_principal.  If the KADM5_TL_DATA flag is set, call
+	krb5_dbe_update_tl_data on each element supplied, to augment
+	and/or replace the existing tl data with a copy of the supplied
+	data, instead of splicing the supplied list and the existing list
+	together.  Use krb5_db_free_principal instead of
+	krb5_dbe_free_contents.
+	(kadm5_modify_principal): Use krb5_dbe_update_tl_data to merge tl
+	data records.
+	(kadm5_rename_principal): Use kadm5_{copy,free}_principal.
+	(kadm5_chpass_principal_3): Use krb5_db_free_principal instead of
+	krb5_dbe_free_contents.
+	(kadm5_setv4key_principal): Use krb5_db_alloc, not malloc, for key
+	data to be returned.  Use an automatic variable for the key data,
+	before copying out to the object so allocated.
+	(kadm5_setkey_principal_3): Likewise.
+	(decrypt_key_data): On error, clear and free any key storage that
+	might've been returned from previous calls
+	krb5_dbekd_decrypt_key_data.
+
+2004-12-20  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c (add_to_history): Rewrite somewhat, using
+	temporary variables to make things somewhat more readable.  Fix
+	buffer overflow case where the next pointer points into
+	unallocated space but resizing wasn't done, i.e., when someone
+	decreases the policy history count to the exact "right" number.
+	Fix some memory leaks.  To avoid losing entries, shift some
+	entries forward after growing the array.
+
+2004-08-21  Tom Yu  <tlyu@mit.edu>
+
+	* libkadm5srv.exports: Update for previous renaming.
+
+2004-08-20  Alexandra Ellwood <lxs@mit.edu>
+
+        * server_acl.[ch]: renamed acl_* functions to kadm5int_acl_*
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (clean-mac): Target deleted.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkadm5srv.exports: New file.
+
+2003-09-02  Alexandra Ellwood  <lxs@mit.edu>
+
+	* svr_principal.c: Added Apple password server support.
+
+2003-06-13  Tom Yu  <tlyu@mit.edu>
+
+	* server_kdb.c (kdb_init_hist): Force history principal's key to
+	be of the same enctype as the master key, as searches for it later
+	on explicitly specify the enctype.
+
+2003-04-01  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove $(SHLIB_DBLIB_DEPS) and related variables.
+	(SHLIB_EXPDEPS): Remove $(SHLIB_DBLIB_DEPS).
+	(SHLIB_EXPLIBS): Change $(DB_LIB) to $(KDB5_DB_LIB).
+
+2003-01-12  Ezra Peisach  <epeisach@bu.edu>
+
+	* svr_iters.c (kadm5_get_either): For POSIX_REGEXPS
+	(i.e. regcomp), call regfree() to cleanup memory.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* server_dict.c: Remove declaration of errno
+
+	* adb_policy.c: Remove declaration of errno
+
+2002-12-16  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in: Change to allow compilation with-system-db and
+	shared libraries.
+
+2002-11-07  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c (kadm5_setkey_principal_3): Apply patch from
+	Emily Ratliff to allow n_ks_tuple to be zero, which is the case if
+	being called from kadmind answering a client's setkey_principal
+	request.
+
+2002-10-15  Ezra Peisach  <epeisach@bu.edu>
+
+	* server_init.c (kadm5_lock, kadm5_unlock): Return KADM5_OK
+	instead of falling off end of function.
+
+2002-10-08  Tom Yu  <tlyu@mit.edu>
+
+	* adb_openclose.c (osa_adb_init_db): Reset opencnt.
+	(osa_adb_open_and_lock): Don't open multiple times; merely
+	increment opencnt if already open.
+	(osa_adb_close_and_unlock): Decrement opencnt instead of
+	unconditionaly closing.
+
+	* server_init.c (kadm5_lock, kadm5_unlock): New functions to
+	support persistent exclusive locks across multiple API calls.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* svr_iters.c (struct iter_data): Replace DynObject "matches" with
+	pointer, allocation size, current count, and error flag.
+	(get_either_iter): Grow array if needed, noting failures.
+	(kadm5_get_either): Set up the array before calling the iterator
+	and use their values after.
+	* Makefile.in (SHLIB_EXPDEPS, SHLIB_EXPLIBS): Drop libdyn
+	references.
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBMAJOR): Bump to avoid Heimdal conflict.
+
+2002-03-02  Sam Hartman  <hartmans@mit.edu>
+
+	* server_acl.c (acl_find_entry):  Patch from sxw@sxw.org.uk:
+	patch to correct handling of ACL targets.  Previous patch from
+	Matt Crawford  seems to only work for * targets where it ignores
+	the restrictions.  This patch seems to work for all the semantics
+	described in MATt's original message, at least as far as I tested.
+
+2001-10-22  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c (kadm5_decrypt_key): For now, coerce enctype of
+	output keyblock in case we got a match on a similar enctype.
+
+2001-10-16  Mitchell Berger  <mitchb@mit.edu>
+	    Matt Crawford  <crawdad@fnal.gov>
+
+	* svr_principal.c (add_to_history): If the policy a principal uses has
+	been changed to hold a lesser number of history entries than it did
+	before, extract the correct number and value of old keys from the
+	history array into a newly allocated array of the proper size.  Failing
+	to do this made kadmind vulnerable to a crash upon changing such a
+	principal's password.  Original patch written by Matt Crawford, with
+	a few changes.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* server_acl.h: Make prototypes unconditional.
+
+2001-07-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* svr_principal.c (check_pw_reuse): Change argument for
+	n_pw_hist_data to unsigned to be consistant with calling convention.
+
+2001-07-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* adb_xdr.c (xdr_krb5_key_data): Use xdr_krb5_ui_2 instead of
+	xdr_krb5_int16 for key_data_length field.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* svr_iters.c: Declare kadm5_get_either static
+
+2001-06-20  Mitchell Berger  <mitchb@mit.edu>
+
+	* server_dict.c: Silly typo fixed.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* server_misc.c (passwd_check): cast argument to
+	islower()/isupper(), isdigit(), ispunct() to int.
+
+	* server_acl.c (acl_parse_line): Cast argument to
+	isupper()/isspace() to int.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* svr_principal.c (check_pw_reuse): Cleanup assignment in conditional.
+
+2001-06-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* svr_principal.c: Cleanup assignments in conditionals.
+
+Sun Feb 18 17:40:23 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* adb_openclose.c, adb_policy.c, server_acl.c, server_dict.c,
+        server_init.c, server_kdb.c, server_misc.c, svr_iters.c,
+        svr_principal.c: Cleanup assignments in conditionals, variables
+        sadowing one another, unused variables and declared some functions
+        as static.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* svr_chpass_util.c (kadm5_chpass_principal_util): Change msg_len
+	to unsigned int.
+
+Tue Oct 10 03:09:27 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* server_dict.c (init_dict): Change syslog() to krb5_klog_syslog()
+ 	so that errors go to the intended place as indicated by krb5.conf.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* adb_openclose.c (osa_adb_create_db): Default to btree.
+	(osa_adb_init_db): Set up btinfo as well.
+	(osa_adb_open_and_lock): Try btree, then hash.
+
+	* Makefile.in (SHLIB_EXPDEPS): Add libdb.
+	(SHLIB_EXPLIBS): Add -ldb.
+
+2000-06-23  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* adb_openclose.c (osa_adb_create_db): Open lock files using O_EXCL
+	and fdopen() the descriptor instead of using fopen().
+	* svr_chpass_util.c (kadm5_chpass_principal_util): Adjust for new
+	length parameter in both kadm5_chpass_principal_util() and in
+	_kadm5_chpass_principal_util().
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* adb_free.c, adb_xdr.c, server_dict.c: Check for existance
+	of<memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-03-16  Ken Raeburn  <raeburn@mit.edu>
+	    Matt Crawford  <crawdad@fnal.gov>
+
+	* server_acl.c: Include kadm5/admin.h.
+	(struct _acl_entry): Add new fields for restrictions.
+	(struct _wildstate): New type.
+	(acl_parse_line): Input is const.  Parse and save restrictions.
+	Allow backslash at end of line to indicate continuation.
+	(acl_parse_restrictions, acl_impose_restrictions): New functions.
+	(acl_free_entries): Free up restriction data if any.
+	(acl_load_acl_file): Don't use tmpbuf for catch-all entry.
+	(acl_match_data): Add new arguments for wildcard state.
+	(acl_find_entry): Support wildcard component matching.
+	Reorganized checks for bad ACL entries.
+	(acl_check): Add restrictions parameter.
+	* server_acl.h (struct _restriction): New type.
+	(acl_check): Update prototype.
+	(acl_impose_restrictions): Declare.
+
+2000-02-26  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c (kadm5_create_principal_3): Remove keepold
+	argument.
+
+	* Makefile.in (LIBMAJOR): Bump major number due to call signature
+	changes.
+
+2000-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* server_acl.c (acl_get_line): Patch from Matt Crawford to permit
+	line continuation by ending a line with a backslash.
+
+2000-02-13  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c (kadm5_setkey_principal_3): New function.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* adb_openclose.c (osa_adb_fini_db): Don't fclose the lock file if
+	the lock is permanent, because it's already been done.
+
+Mon Dec  7 15:19:11 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* svr_principal.c (kadm5_randkey_principal_3): Fix typo in
+	 	arguments to krb5_dbe_crk().
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Dec  4 23:10:32 1998  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c (kadm5_create_principal): Modify to call
+	create_principal_3.
+	(kadm5_create_principal_3): New function including flag to keep
+	old keys and optional explicit keysalt_tuples.
+	(kadm5_chpass_principal): Modify to call chpass_principal_3.
+	(kadm5_chpass_principal_3): New function including flag to keep
+	old keys and optional explicit keysalt_tuples.
+	(kadm5_randkey_principal): Modify to call randkey_principal_3.
+	(kadm5_randkey_principal_3): New function including flag to keep
+	old keys and optional explicit keysalt_tuples.
+
+Tue Nov 17 18:20:48 1998  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c (kadm5_create_principal): 
+	(kadm5_chpass_principal): 
+	(kadm5_randkey_principal): Fix up for new calling conventions of
+	dbe_crk and dbe_cpw.
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* server_kdb.c, svr_principal.c: convert to new crypto api
+
+Sun Jul 26 18:09:55 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* Makefile.in (LIBMAJOR): bump libmajor
+
+Wed Apr 15 18:06:14 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): 
+	(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
+
+Fri Feb 27 22:33:05 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/kadm5
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel lib/kadm5 configure.in.
+		Instead of adding @LIBS@ to the list of libraries which
+		should be linked as shared library dependencies, add
+		@GEN_LIB@ and @AIX_DB_LIB@ which will get expanded if
+		necessary. 
+
+Wed Feb 18 16:15:22 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 21:30:58 1998  Tom Yu  <tlyu@mit.edu>
+
+	* adb_xdr.c: Update header locations.
+
+	* Makefile.in (LIBMAJOR): Bump major version to reflect change in
+	rpc library.
+
+Wed Jan 28 16:32:36 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in, Makefile.in: Remove the CopySrcHeader macro
+		from configure.in and substitute equivalent
+		functionality in Makefile.in
+
+Mon Oct 13 10:59:22 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* server_init.c (kadm5_destroy): Call kadm5_free_config_params.
+
+	* server_acl.c: Include <ctype.h> for tolower().
+	(acl_load_acl_file): Close acl file, even when acl_catchall_entry is
+	    not set.
+
+Wed Aug  6 20:22:23 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add flags to conditionally compile with Hesiod.
+
+	* server_misc.c: Add support for checking GECOS field of Hesiod
+	passwd entry.
+
+Fri Jul 25 15:37:08 1997  Tom Yu  <tlyu@mit.edu>
+
+	* server_init.c: Change a few calls to align with the new kdb
+	API.
+
+	* Makefile.in: Bump version.
+
+Tue Jul  1 02:32:49 1997  Tom Yu  <tlyu@mit.edu>
+
+	* server_acl.h: Fix ACL_ALL_MASK to include ACL_SETKEY.
+
+	* svr_principal.c: Fix setv4key_principal.
+
+Sun Jun 29 14:52:51 1997  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c: Add new function kadm5_setv4key_principal.
+
+Mon Mar 31 17:40:24 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* server_acl.c, server_acl.h, svr_pricipal.c: add support for
+ 	setkey_principal
+
+Sun Mar  9 13:40:33 1997  Tom Yu  <tlyu@mit.edu>
+
+	* svr_principal.c (add_to_history): Don't call realloc() on a NULL
+	pointer, lest non-ANSI compliant systems like SunOS fail.
+
+Sat Feb 22 01:34:08 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): s/.so/$(SHLIBEXT)
+
+Wed Jan 15 20:59:11 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Tue Dec  3 15:14:29 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* server_acl.c (acl_load_acl_file): log errors via
+ 	krb5_klog_syslog, not fprintf and com_err [krb5-admin/238]; don't
+ 	coredump when an acl line is too long; handle catchall_entry ==
+ 	NULL
+
+Fri Nov 22 11:11:34 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (SHLIB_LIBS): Do not link shared against -ldb [224]
+
+Tue Nov 26 03:04:04 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* server_acl.c (acl_load_acl_file): Fix coredump by allowing
+ 	catchall_entry to be null, but do not reference it if it is.
+  	Thanks to marc.  [242]
+
+Mon Nov 25 17:53:20 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* server_acl.c: set acl_catchall_entry to "" instead of NULL,
+ 	since it is presumed to contain something, but we don't want any
+ 	default entry [krb5-admin/237]
+
+Wed Nov 13 19:20:36 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (clean-unix): Remove shared/*.
+
+Mon Nov 11 17:01:00 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_principal.c (kadm5_modify_principal): fix memory leak
+ 	handling tl_data
+
+Thu Nov  7 16:42:38 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_iters.c (glob_to_regexp): a principal glob with no @
+ 	defaults to @*, not @LOCAL.REAM [krb5-admin/161]
+ 
+Wed Nov  6 10:45:12 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* server_init.c (kadm5_init): Use a more fined grained error
+ 		code, KADM5_MISSING_CONF_PARAMS instead of
+ 		KRB5_CONFIG_BADFORMAT
+
+Wed Nov  6 16:22:05 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_principal.c (kadm5_modify_principal): don't free the
+ 	caller's tl_data (oops)
+
+Fri Nov  1 13:18:40 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_principal.c (kadm5_modify_principal): update for new tl_data
+ 	semantics [krb5-admin/140]
+
+Mon Oct 21 16:28:52 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_principal.c (kadm5_modify_principal): fix modify_principal's
+ 	handling of KADM5_TL_DATA [krb5-admin/20]
+
+Fri Oct 18 14:24:12 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_misc_free.c, server_dict.c, adb_policy.c, adb_free.c:
+ 	include stdlib.h instead of malloc.h [krb5-admin/35]
+
+	* adb_openclose.c (osa_adb_rename_db): create the destination
+ 	database if necessary before renaming [krb5-admin/58]
+
+Thu Oct 17 16:22:07 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svr_principal.c: update for new pw_expiration semantics
+ 	[krb5-admin/87]
+
+Tue Oct  8 13:33:48 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* adb_policy.c (osa_adb_rename_policy_db): rename
+ 	osa_adb_rename_policy to *_db
+
+	* adb_openclose.c, adb_policy.c: implement database renaming;
+ 	also, only create a db lockfile after the database has been
+ 	successfully created [krb5-admin/62]
+
+Fri Oct  4 08:40:21 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* svr_principal.c (kadm5_get_principal): Do not assume malloc(0)
+		returns non-NULL. [krb5-admin/29]
+
+Fri Aug  2 14:07:31 1996  Barry Jaspan  <bjaspan@DUN-DUN-NOODLES>
+
+	* svr_principal.c: remove krb5_free_keyblock_contents (moved to
+        libkrb5.a)
+
+Fri Jul 26 17:48:14 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* svr_principal.c (krb5_copy_key_data_contents): If
+ 	key_data_length[i] == 0, don't complain if malloc(0) returns 0;
+ 	this is allowed by ANSI.
+
+Thu Jul 25 18:42:47 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in (LIBS): Link against -ldb under AIX for shared
+ 	library construction; we should eventually make libdb a shared
+ 	library.
+
+Wed Jul 24 18:21:28 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in, configure.in: break out server lib into a
+		subdirectory
+
diff --git a/mechglue/src/lib/kadm5/srv/Makefile.in b/mechglue/src/lib/kadm5/srv/Makefile.in
new file mode 100644
index 000000000..f9b9ba894
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/Makefile.in
@@ -0,0 +1,220 @@
+thisconfigdir=./..
+myfulldir=lib/kadm5/srv
+mydir=srv
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I$(BUILDTOP)/include/kadm5
+DEFINES = @HESIOD_DEFS@
+
+##DOSBUILDTOP = ..\..\..
+##DOSLIBNAME = libkadm5srv.lib
+
+LIBBASE=kadm5srv
+LIBMAJOR=5
+LIBMINOR=1
+STOBJLISTS=../OBJS.ST OBJS.ST
+
+SHLIB_EXPDEPS=\
+	$(TOPLIBD)/libgssrpc$(SHLIBEXT) \
+	$(TOPLIBD)/libgssapi_krb5$(SHLIBEXT) \
+	$(TOPLIBD)/libkdb5$(SHLIBEXT) \
+	$(TOPLIBD)/libkrb5$(SHLIBEXT) \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(COM_ERR_DEPLIB)
+SHLIB_EXPLIBS =	-lgssrpc -lgssapi_krb5 -lkdb5 $(KDB5_DB_LIB) \
+		-lkrb5 -lk5crypto -lcom_err @GEN_LIB@
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+RELDIR=kadm5/srv
+
+SRCS =	$(srcdir)/svr_policy.c \
+	$(srcdir)/svr_principal.c \
+	$(srcdir)/server_acl.c \
+	$(srcdir)/server_kdb.c \
+	$(srcdir)/server_misc.c \
+	$(srcdir)/server_init.c \
+	$(srcdir)/server_dict.c \
+	$(srcdir)/svr_iters.c \
+	$(srcdir)/svr_chpass_util.c \
+	$(srcdir)/adb_xdr.c 
+
+OBJS =	svr_policy.$(OBJEXT) \
+	svr_principal.$(OBJEXT) \
+	server_acl.$(OBJEXT) \
+	server_kdb.$(OBJEXT) \
+	server_misc.$(OBJEXT) \
+	server_init.$(OBJEXT) \
+	server_dict.$(OBJEXT) \
+	svr_iters.$(OBJEXT) \
+	svr_chpass_util.$(OBJEXT) \
+	adb_xdr.$(OBJEXT) 
+
+STLIBOBJS = \
+	svr_policy.o \
+	svr_principal.o \
+	server_acl.o \
+	server_kdb.o \
+	server_misc.o \
+	server_init.o \
+	server_dict.o \
+	svr_iters.o \
+	svr_chpass_util.o \
+	adb_xdr.o
+
+all-unix:: includes
+all-unix:: all-liblinks
+all-windows:: $(OBJS)
+
+includes:: server_acl.h
+	if cmp $(srcdir)/server_acl.h \
+	$(BUILDTOP)/include/kadm5/server_acl.h >/dev/null 2>&1; then :; \
+	else \
+		(set -x; $(RM) $(BUILDTOP)/include/kadm5/server_acl.h; \
+		 $(CP) $(srcdir)/server_acl.h \
+			$(BUILDTOP)/include/kadm5/server_acl.h) ; \
+	fi
+
+clean-unix::
+	$(RM) $(BUILDTOP)/include/kadm5/server_acl.h
+
+check-windows::
+
+clean-windows::
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+install:: install-libs
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+svr_policy.so svr_policy.po $(OUTPRE)svr_policy.$(OBJEXT): \
+  svr_policy.c $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/server_internal.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h
+svr_principal.so svr_principal.po $(OUTPRE)svr_principal.$(OBJEXT): \
+  svr_principal.c $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/server_internal.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h
+server_acl.so server_acl.po $(OUTPRE)server_acl.$(OBJEXT): \
+  server_acl.c $(SRCTOP)/include/syslog.h $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/server_internal.h \
+  $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h $(SRCTOP)/include/krb5/adm_proto.h \
+  server_acl.h
+server_kdb.so server_kdb.po $(OUTPRE)server_kdb.$(OBJEXT): \
+  server_kdb.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/server_internal.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h
+server_misc.so server_misc.po $(OUTPRE)server_misc.$(OBJEXT): \
+  server_misc.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h
+server_init.so server_init.po $(OUTPRE)server_init.$(OBJEXT): \
+  server_init.c $(COM_ERR_DEPS) $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/krb5.h $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/kadm5/admin_internal.h
+server_dict.so server_dict.po $(OUTPRE)server_dict.$(OBJEXT): \
+  server_dict.c $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(SRCTOP)/include/krb5/adm_proto.h \
+  $(SRCTOP)/include/syslog.h $(BUILDTOP)/include/kadm5/server_internal.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h
+svr_iters.so svr_iters.po $(OUTPRE)svr_iters.$(OBJEXT): \
+  svr_iters.c $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/kadm_err.h \
+  $(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/server_internal.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h
+svr_chpass_util.so svr_chpass_util.po $(OUTPRE)svr_chpass_util.$(OBJEXT): \
+  svr_chpass_util.c $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/kadm5/admin_internal.h
+adb_xdr.so adb_xdr.po $(OUTPRE)adb_xdr.$(OBJEXT): adb_xdr.c \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/kadm5/server_internal.h \
+  $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/kadm5/admin.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/include/kadm5/admin_internal.h $(BUILDTOP)/include/kadm5/admin_xdr.h \
+  $(BUILDTOP)/include/kadm5/kadm_rpc.h
diff --git a/mechglue/src/lib/kadm5/srv/adb_xdr.c b/mechglue/src/lib/kadm5/srv/adb_xdr.c
new file mode 100644
index 000000000..d5d17062a
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/adb_xdr.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <sys/types.h>
+#include <krb5.h>
+#include <gssrpc/rpc.h>
+#include	"server_internal.h"
+#include "admin_xdr.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+bool_t
+xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp)
+{
+    unsigned int tmp;
+
+    if (!xdr_krb5_int16(xdrs, &objp->key_data_ver))
+	return(FALSE);
+    if (!xdr_krb5_int16(xdrs, &objp->key_data_kvno))
+	return(FALSE);
+    if (!xdr_krb5_int16(xdrs, &objp->key_data_type[0]))
+	return(FALSE);
+    if (!xdr_krb5_int16(xdrs, &objp->key_data_type[1]))
+	return(FALSE);
+    if (!xdr_krb5_ui_2(xdrs, &objp->key_data_length[0]))
+	return(FALSE);
+    if (!xdr_krb5_ui_2(xdrs, &objp->key_data_length[1]))
+	return(FALSE);
+
+    tmp = (unsigned int) objp->key_data_length[0];
+    if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[0],
+		   &tmp, ~0))
+	return FALSE;
+
+    tmp = (unsigned int) objp->key_data_length[1];
+    if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[1],
+		   &tmp, ~0))
+	return FALSE;
+
+    /* don't need to copy tmp out, since key_data_length will be set
+       by the above encoding. */
+
+    return(TRUE);
+}
+
+bool_t
+xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp)
+{
+    if (!xdr_array(xdrs, (caddr_t *) &objp->key_data,
+		   (u_int *) &objp->n_key_data, ~0,
+		   sizeof(krb5_key_data),
+		   xdr_krb5_key_data))
+	return (FALSE);
+    return (TRUE);
+}
+
+bool_t
+xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp)
+{
+    switch (xdrs->x_op) {
+    case XDR_ENCODE:
+	 objp->version = OSA_ADB_PRINC_VERSION_1;
+	 /* fall through */
+    case XDR_FREE:
+	 if (!xdr_int(xdrs, &objp->version))
+	      return FALSE;
+	 break;
+    case XDR_DECODE:
+	 if (!xdr_int(xdrs, &objp->version))
+	      return FALSE;
+	 if (objp->version != OSA_ADB_PRINC_VERSION_1)
+	      return FALSE;
+	 break;
+    }
+    
+    if (!xdr_nullstring(xdrs, &objp->policy))
+	return (FALSE);
+    if (!xdr_long(xdrs, &objp->aux_attributes))
+	return (FALSE);
+    if (!xdr_u_int(xdrs, &objp->old_key_next))
+	return (FALSE);
+    if (!xdr_krb5_kvno(xdrs, &objp->admin_history_kvno))
+	return (FALSE);
+    if (!xdr_array(xdrs, (caddr_t *) &objp->old_keys,
+		   (unsigned int *) &objp->old_key_len, ~0,
+		   sizeof(osa_pw_hist_ent),
+		   xdr_osa_pw_hist_ent))
+	return (FALSE);
+    return (TRUE);
+}
+
+void
+osa_free_princ_ent(osa_princ_ent_t val)
+{
+    XDR xdrs;
+                                                                                                                            
+    xdrmem_create(&xdrs, NULL, 0, XDR_FREE);
+                                                                                                                            
+    xdr_osa_princ_ent_rec(&xdrs, val);
+    free(val);
+}
+                                                                                                                            
diff --git a/mechglue/src/lib/kadm5/srv/libkadm5srv.exports b/mechglue/src/lib/kadm5/srv/libkadm5srv.exports
new file mode 100644
index 000000000..e698c6957
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/libkadm5srv.exports
@@ -0,0 +1,160 @@
+_kadm5_check_handle
+_kadm5_chpass_principal_util
+kadm5int_acl_check
+kadm5int_acl_finish
+kadm5int_acl_impose_restrictions
+kadm5int_acl_init
+adb_policy_close
+adb_policy_init
+destroy_dict
+find_word
+hist_db
+hist_key
+hist_kvno
+hist_princ
+init_dict
+kadm5_chpass_principal
+kadm5_chpass_principal_3
+kadm5_chpass_principal_util
+kadm5_create_policy
+kadm5_create_policy_internal
+kadm5_create_principal
+kadm5_create_principal_3
+kadm5_decrypt_key
+kadm5_delete_policy
+kadm5_delete_principal
+kadm5_destroy
+kadm5_flush
+kadm5_free_config_params
+kadm5_free_key_data
+kadm5_free_name_list
+kadm5_free_policy_ent
+kadm5_free_principal_ent
+kadm5_get_config_params
+kadm5_get_policies
+kadm5_get_policy
+kadm5_get_principal
+kadm5_get_principals
+kadm5_get_privs
+kadm5_init
+kadm5_init_with_creds
+kadm5_init_with_password
+kadm5_init_with_skey
+kadm5_lock
+kadm5_modify_policy
+kadm5_modify_policy_internal
+kadm5_modify_principal
+kadm5_randkey_principal
+kadm5_randkey_principal_3
+kadm5_rename_principal
+kadm5_setkey_principal
+kadm5_setkey_principal_3
+kadm5_setv4key_principal
+kadm5_unlock
+kdb_delete_entry
+kdb_free_entry
+kdb_get_entry
+kdb_init_hist
+kdb_init_master
+kdb_iter_entry
+kdb_put_entry
+krb5_aprof_finish
+krb5_aprof_get_boolean
+krb5_aprof_get_deltat
+krb5_aprof_get_int32
+krb5_aprof_get_string
+krb5_aprof_getvals
+krb5_aprof_init
+krb5_copy_key_data_contents
+krb5_flags_to_string
+krb5_free_key_data_contents
+krb5_free_realm_params
+krb5_input_flag_to_string
+krb5_keysalt_is_present
+krb5_keysalt_iterate
+krb5_klog_close
+krb5_klog_init
+krb5_klog_reopen
+krb5_klog_syslog
+krb5_read_realm_params
+krb5_string_to_flags
+krb5_string_to_keysalts
+master_db
+master_keyblock
+master_princ
+osa_free_princ_ent
+ovsec_kadm_chpass_principal
+ovsec_kadm_chpass_principal_util
+ovsec_kadm_create_policy
+ovsec_kadm_create_principal
+ovsec_kadm_delete_policy
+ovsec_kadm_delete_principal
+ovsec_kadm_destroy
+ovsec_kadm_flush
+ovsec_kadm_free_name_list
+ovsec_kadm_free_policy_ent
+ovsec_kadm_free_principal_ent
+ovsec_kadm_get_policies
+ovsec_kadm_get_policy
+ovsec_kadm_get_principal
+ovsec_kadm_get_principals
+ovsec_kadm_get_privs
+ovsec_kadm_init
+ovsec_kadm_init_with_password
+ovsec_kadm_init_with_skey
+ovsec_kadm_modify_policy
+ovsec_kadm_modify_principal
+ovsec_kadm_randkey_principal
+ovsec_kadm_rename_principal
+passwd_check
+xdr_chpass3_arg
+xdr_chpass_arg
+xdr_chrand3_arg
+xdr_chrand_arg
+xdr_chrand_ret
+xdr_cpol_arg
+xdr_cprinc3_arg
+xdr_cprinc_arg
+xdr_dpol_arg
+xdr_dprinc_arg
+xdr_generic_ret
+xdr_getprivs_ret
+xdr_gpol_arg
+xdr_gpol_ret
+xdr_gpols_arg
+xdr_gpols_ret
+xdr_gprinc_arg
+xdr_gprinc_ret
+xdr_gprincs_arg
+xdr_gprincs_ret
+xdr_kadm5_policy_ent_rec
+xdr_kadm5_principal_ent_rec
+xdr_kadm5_principal_ent_rec_v1
+xdr_kadm5_ret_t
+xdr_krb5_deltat
+xdr_krb5_enctype
+xdr_krb5_flags
+xdr_krb5_int16
+xdr_krb5_key_data
+xdr_krb5_key_data_nocontents
+xdr_krb5_key_salt_tuple
+xdr_krb5_keyblock
+xdr_krb5_kvno
+xdr_krb5_octet
+xdr_krb5_principal
+xdr_krb5_salttype
+xdr_krb5_timestamp
+xdr_krb5_tl_data
+xdr_krb5_ui_2
+xdr_krb5_ui_4
+xdr_mpol_arg
+xdr_mprinc_arg
+xdr_nullstring
+xdr_nulltype
+xdr_osa_princ_ent_rec
+xdr_osa_pw_hist_ent
+xdr_rprinc_arg
+xdr_setkey3_arg
+xdr_setkey_arg
+xdr_setv4key_arg
+xdr_ui_4
diff --git a/mechglue/src/lib/kadm5/srv/server_acl.c b/mechglue/src/lib/kadm5/srv/server_acl.c
new file mode 100644
index 000000000..fa63027f7
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/server_acl.c
@@ -0,0 +1,807 @@
+/*
+ * lib/kadm5/srv/server_acl.c
+ *
+ * Copyright 1995-2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * srv_acl.c - Handle Kerberos ACL related functions.
+ */
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <gssapi/gssapi_generic.h>
+#include "k5-int.h"
+#include <kadm5/server_internal.h>
+#include <kadm5/admin.h>
+#include "adm_proto.h"
+#include "server_acl.h"
+#include <ctype.h>
+
+typedef struct _acl_op_table {
+    char	ao_op;
+    krb5_int32	ao_mask;
+} aop_t;
+
+typedef struct _acl_entry {
+    struct _acl_entry	*ae_next;
+    char		*ae_name;
+    krb5_boolean	ae_name_bad;
+    krb5_principal	ae_principal;
+    krb5_int32		ae_op_allowed;
+    char		*ae_target;
+    krb5_boolean	ae_target_bad;
+    krb5_principal	ae_target_princ;
+    char		*ae_restriction_string;
+			/* eg: "-maxlife 3h -service +proxiable" */
+    krb5_boolean	ae_restriction_bad;
+    restriction_t	*ae_restrictions;
+} aent_t;
+
+static const aop_t acl_op_table[] = {
+    { 'a',	ACL_ADD },
+    { 'd',	ACL_DELETE },
+    { 'm',	ACL_MODIFY },
+    { 'c',	ACL_CHANGEPW },
+    { 'i',	ACL_INQUIRE },
+    { 'l',	ACL_LIST },
+    { 's',	ACL_SETKEY },
+    { 'x',	ACL_ALL_MASK },
+    { '*',	ACL_ALL_MASK },
+    { '\0',	0 }
+};
+
+typedef struct _wildstate {
+    int		nwild;
+    krb5_data	*backref[9];
+} wildstate_t;
+
+static aent_t	*acl_list_head = (aent_t *) NULL;
+static aent_t	*acl_list_tail = (aent_t *) NULL;
+
+static const char *acl_acl_file = (char *) NULL;
+static int acl_inited = 0;
+static int acl_debug_level = 0;
+/*
+ * This is the catchall entry.  If nothing else appropriate is found, or in
+ * the case where the ACL file is not present, this entry controls what can
+ * be done.
+ */
+static const char *acl_catchall_entry = NULL;
+
+static const char *acl_line2long_msg = "%s: line %d too long, truncated";
+static const char *acl_op_bad_msg = "Unrecognized ACL operation '%c' in %s";
+static const char *acl_syn_err_msg = "%s: syntax error at line %d <%10s...>";
+static const char *acl_cantopen_msg = "%s while opening ACL file %s";
+
+
+/*
+ * kadm5int_acl_get_line() - Get a line from the ACL file.
+ *			Lines ending with \ are continued on the next line
+ */
+static char *
+kadm5int_acl_get_line(fp, lnp)
+    FILE	*fp;
+    int		*lnp;		/* caller should set to 1 before first call */
+{
+    int		i, domore;
+    static int	line_incr = 0;
+    static char acl_buf[BUFSIZ];
+
+    *lnp += line_incr;
+    line_incr = 0;
+    for (domore = 1; domore && !feof(fp); ) {
+	/* Copy in the line, with continuations */
+	for (i=0; ((i < sizeof acl_buf) && !feof(fp)); i++ ) {
+	    acl_buf[i] = fgetc(fp);
+	    if (acl_buf[i] == (char)EOF) {
+		if (i > 0 && acl_buf[i-1] == '\\')
+		    i--;
+		break;		/* it gets nulled-out below */
+	    }
+	    else if (acl_buf[i] == '\n') {
+		if (i == 0 || acl_buf[i-1] != '\\')
+		    break;	/* empty line or normal end of line */
+		else {
+		    i -= 2;	/* back up over "\\\n" and continue */
+		    line_incr++;
+		}
+	    }
+	}
+	/* Check if we exceeded our buffer size */
+	if (i == sizeof acl_buf && (i--, !feof(fp))) {
+	    int	c1 = acl_buf[i], c2;
+
+	    krb5_klog_syslog(LOG_ERR, acl_line2long_msg, acl_acl_file, *lnp);
+	    while ((c2 = fgetc(fp)) != EOF) {
+		if (c2 == '\n') {
+		    if (c1 != '\\')
+			break;
+		    line_incr++;
+		}
+		c1 = c2;
+	    }
+	}
+	acl_buf[i] = '\0';
+	if (acl_buf[0] == (char) EOF)	/* ptooey */
+	    acl_buf[0] = '\0';
+	else
+	    line_incr++;
+	if ((acl_buf[0] != '#') && (acl_buf[0] != '\0'))
+	    domore = 0;
+    }
+    if (domore || (strlen(acl_buf) == 0))
+	return((char *) NULL);
+    else
+	return(acl_buf);
+}
+
+/*
+ * kadm5int_acl_parse_line() - Parse the contents of an ACL line.
+ */
+static aent_t *
+kadm5int_acl_parse_line(lp)
+    const char *lp;
+{
+    static char acle_principal[BUFSIZ];
+    static char acle_ops[BUFSIZ];
+    static char acle_object[BUFSIZ];
+    static char acle_restrictions[BUFSIZ];
+    aent_t	*acle;
+    char	*op;
+    int		t, found, opok, nmatch;
+
+    DPRINT(DEBUG_CALLS, acl_debug_level,
+	   ("* kadm5int_acl_parse_line(line=%20s)\n", lp));
+    /*
+     * Format is still simple:
+     *  entry ::= [<whitespace>] <principal> <whitespace> <opstring>
+     *		  [<whitespace> <target> [<whitespace> <restrictions>
+     *					  [<whitespace>]]]
+     */
+    acle = (aent_t *) NULL;
+    acle_object[0] = '\0';
+    nmatch = sscanf(lp, "%s %s %s %[^\n]", acle_principal, acle_ops,
+		    acle_object, acle_restrictions);
+    if (nmatch >= 2) {
+	acle = (aent_t *) malloc(sizeof(aent_t));
+	if (acle) {
+	    acle->ae_next = (aent_t *) NULL;
+	    acle->ae_op_allowed = (krb5_int32) 0;
+	    acle->ae_target =
+		(nmatch >= 3) ? strdup(acle_object) : (char *) NULL;
+	    acle->ae_target_bad = 0;
+	    acle->ae_target_princ = (krb5_principal) NULL;
+	    opok = 1;
+	    for (op=acle_ops; *op; op++) {
+		char rop;
+
+		rop = (isupper((int) *op)) ? tolower((int) *op) : *op;
+		found = 0;
+		for (t=0; acl_op_table[t].ao_op; t++) {
+		    if (rop == acl_op_table[t].ao_op) {
+			found = 1;
+			if (rop == *op)
+			    acle->ae_op_allowed |= acl_op_table[t].ao_mask;
+			else
+			    acle->ae_op_allowed &= ~acl_op_table[t].ao_mask;
+		    }
+		}
+		if (!found) {
+		    krb5_klog_syslog(LOG_ERR, acl_op_bad_msg, *op, lp);
+		    opok = 0;
+		}
+	    }
+	    if (opok) {
+		acle->ae_name = (char *) malloc(strlen(acle_principal)+1);
+		if (acle->ae_name) {
+		    strcpy(acle->ae_name, acle_principal);
+		    acle->ae_principal = (krb5_principal) NULL;
+		    acle->ae_name_bad = 0;
+		    DPRINT(DEBUG_ACL, acl_debug_level,
+			   ("A ACL entry %s -> opmask %x\n",
+			    acle->ae_name, acle->ae_op_allowed));
+		}
+		else {
+		    if (acle->ae_target)
+			free(acle->ae_target);
+		    free(acle);
+		    acle = (aent_t *) NULL;
+		}
+	    }
+	    else {
+		if (acle->ae_target)
+		    free(acle->ae_target);
+		free(acle);
+		acle = (aent_t *) NULL;
+	    }
+	    if ( nmatch >= 4 ) {
+		char	*trailing;
+
+		trailing = &acle_restrictions[strlen(acle_restrictions)-1];
+		while ( isspace((int) *trailing) )
+		    trailing--;
+		trailing[1] = '\0';
+		acle->ae_restriction_string = strdup(acle_restrictions);
+	    }
+	    else {
+		acle->ae_restriction_string = (char *) NULL;
+	    }
+	    acle->ae_restriction_bad = 0;
+	    acle->ae_restrictions = (restriction_t *) NULL;
+	}
+    }
+    DPRINT(DEBUG_CALLS, acl_debug_level,
+	   ("X kadm5int_acl_parse_line() = %x\n", (long) acle));
+    return(acle);
+}
+
+/*
+ * kadm5int_acl_parse_restrictions() - Parse optional restrictions field
+ *
+ * Allowed restrictions are:
+ *	[+-]flagname		(recognized by krb5_string_to_flags)
+ *				flag is forced to indicated value
+ *	-clearpolicy		policy is forced clear
+ *	-policy pol		policy is forced to be "pol"
+ *	-{expire,pwexpire,maxlife,maxrenewlife} deltat
+ *				associated value will be forced to
+ *				MIN(deltat, requested value)
+ *
+ * Returns: 0 on success, or system errors
+ */
+static krb5_error_code
+kadm5int_acl_parse_restrictions(s, rpp)
+    char		*s;
+    restriction_t	**rpp;
+{
+    char		*sp, *tp, *ap;
+    static const char	*delims = "\t\n\f\v\r ,";
+    krb5_deltat		dt;
+    krb5_flags		flag;
+    krb5_error_code	code;
+
+   DPRINT(DEBUG_CALLS, acl_debug_level,
+	   ("* kadm5int_acl_parse_restrictions(s=%20s, rpp=0x%08x)\n", s, (long)rpp));
+
+    *rpp = (restriction_t *) NULL;
+    code = 0;
+    if (s) {
+	if (!(sp = strdup(s))	/* Don't munge the original */
+	    || !(*rpp = (restriction_t *) malloc(sizeof(restriction_t)))) {
+	    code = ENOMEM;
+	} else {
+	    memset(*rpp, 0, sizeof(**rpp));
+	    for (tp=strtok(sp, delims); tp; tp=strtok((char *)NULL, delims)) {
+		flag = 0;
+		if (!krb5_string_to_flags(tp, "+", "-", &flag)) {
+		    /* OK, but was it in the positive or negative sense? */
+		    if (flag) {
+			(*rpp)->require_attrs |= flag;
+		    } else {
+			flag = ~0;
+			(void) krb5_string_to_flags(tp, "+", "-", &flag);
+			(*rpp)->forbid_attrs |= ~flag;
+		    }
+		    (*rpp)->mask |= KADM5_ATTRIBUTES;
+		} else if (!strcmp(tp, "-clearpolicy")) {
+		    (*rpp)->mask |= KADM5_POLICY_CLR;
+		} else {
+		    /* everything else needs an argument ... */
+		    if (!(ap = strtok((char *)NULL, delims))) {
+			code = EINVAL;
+			break;
+		    }
+		    if (!strcmp(tp, "-policy")) {
+			if (!((*rpp)->policy = strdup(ap))) {
+			    code = ENOMEM;
+			    break;
+			}
+			(*rpp)->mask |= KADM5_POLICY;
+		    } else {
+			/* all other arguments must be a deltat ... */
+			if (krb5_string_to_deltat(ap, &dt)) {
+			    code = EINVAL;
+			    break;
+			}
+			if (!strcmp(tp, "-expire")) {
+			    (*rpp)->princ_lifetime = dt;
+			    (*rpp)->mask |= KADM5_PRINC_EXPIRE_TIME;
+			} else if (!strcmp(tp, "-pwexpire")) {
+			    (*rpp)->pw_lifetime = dt;
+			    (*rpp)->mask |= KADM5_PW_EXPIRATION;
+			} else if (!strcmp(tp, "-maxlife")) {
+			    (*rpp)->max_life = dt;
+			    (*rpp)->mask |= KADM5_MAX_LIFE;
+			} else if (!strcmp(tp, "-maxrenewlife")) {
+			    (*rpp)->max_renewable_life = dt;
+			    (*rpp)->mask |= KADM5_MAX_RLIFE;
+			} else {
+			    code = EINVAL;
+			    break;
+			}
+		    }
+		}
+	    }
+	}
+    }
+    if (sp)
+	free(sp);
+    if (*rpp && code) {
+	if ((*rpp)->policy)
+	    free((*rpp)->policy);
+	free(*rpp);
+	*rpp = (restriction_t *) NULL;
+    }
+    DPRINT(DEBUG_CALLS, acl_debug_level,
+	   ("X kadm5int_acl_parse_restrictions() = %d, mask=0x%08x\n",
+	    code, (*rpp) ? (*rpp)->mask : 0));
+    return code;
+}
+
+/*
+ * kadm5int_acl_impose_restrictions()	- impose restrictions, modifying *recp, *maskp
+ *
+ * Returns: 0 on success;
+ *	    malloc or timeofday errors
+ */
+krb5_error_code
+kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp)
+     krb5_context		kcontext;
+     kadm5_principal_ent_rec	*recp;
+     long			*maskp;
+     restriction_t		*rp;
+{
+    krb5_error_code	code;
+    krb5_int32		now;
+
+    DPRINT(DEBUG_CALLS, acl_debug_level,
+	   ("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n",
+	    *maskp, (long)rp));
+    if (!rp)
+	return 0;
+    if (rp->mask & (KADM5_PRINC_EXPIRE_TIME|KADM5_PW_EXPIRATION))
+	if ((code = krb5_timeofday(kcontext, &now)))
+	    return code;
+
+    if (rp->mask & KADM5_ATTRIBUTES) {
+	recp->attributes |= rp->require_attrs;
+	recp->attributes &= ~(rp->forbid_attrs);
+	*maskp |= KADM5_ATTRIBUTES;
+    }
+    if (rp->mask & KADM5_POLICY_CLR) {
+	*maskp &= ~KADM5_POLICY;
+	*maskp |= KADM5_POLICY_CLR;
+    } else if (rp->mask & KADM5_POLICY) {
+	if (recp->policy && strcmp(recp->policy, rp->policy)) {
+		free(recp->policy);
+		recp->policy = (char *) NULL;
+	}
+	if (!recp->policy) {
+	    recp->policy = strdup(rp->policy);  /* XDR will free it */
+	    if (!recp->policy)
+		return ENOMEM;
+	}
+	*maskp |= KADM5_POLICY;
+    }
+    if (rp->mask & KADM5_PRINC_EXPIRE_TIME) {
+	if (!(*maskp & KADM5_PRINC_EXPIRE_TIME)
+	    || (recp->princ_expire_time > (now + rp->princ_lifetime)))
+	    recp->princ_expire_time = now + rp->princ_lifetime;
+	*maskp |= KADM5_PRINC_EXPIRE_TIME;
+    }
+    if (rp->mask & KADM5_PW_EXPIRATION) {
+	if (!(*maskp & KADM5_PW_EXPIRATION)
+	    || (recp->pw_expiration > (now + rp->pw_lifetime)))
+	    recp->pw_expiration = now + rp->pw_lifetime;
+	*maskp |= KADM5_PW_EXPIRATION;
+    }
+    if (rp->mask & KADM5_MAX_LIFE) {
+	if (!(*maskp & KADM5_MAX_LIFE)
+	    || (recp->max_life > rp->max_life))
+	    recp->max_life = rp->max_life;
+	*maskp |= KADM5_MAX_LIFE;
+    }
+    if (rp->mask & KADM5_MAX_RLIFE) {
+	if (!(*maskp & KADM5_MAX_RLIFE)
+	    || (recp->max_renewable_life > rp->max_renewable_life))
+	    recp->max_renewable_life = rp->max_renewable_life;
+	*maskp |= KADM5_MAX_RLIFE;
+    }
+    DPRINT(DEBUG_CALLS, acl_debug_level,
+	   ("X kadm5int_acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp));
+    return 0;
+}
+
+/*
+ * kadm5int_acl_free_entries() - Free all ACL entries.
+ */
+static void
+kadm5int_acl_free_entries()
+{
+    aent_t	*ap;
+    aent_t	*np;
+
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_free_entries()\n"));
+    for (ap=acl_list_head; ap; ap = np) {
+	if (ap->ae_name)
+	    free(ap->ae_name);
+	if (ap->ae_principal)
+	    krb5_free_principal((krb5_context) NULL, ap->ae_principal);
+	if (ap->ae_target)
+	    free(ap->ae_target);
+	if (ap->ae_target_princ)
+	    krb5_free_principal((krb5_context) NULL, ap->ae_target_princ);
+	if (ap->ae_restriction_string)
+	    free(ap->ae_restriction_string);
+	if (ap->ae_restrictions) {
+	    if (ap->ae_restrictions->policy)
+		free(ap->ae_restrictions->policy);
+	    free(ap->ae_restrictions);
+	}
+	np = ap->ae_next;
+	free(ap);
+    }
+    acl_list_head = acl_list_tail = (aent_t *) NULL;
+    acl_inited = 0;
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_free_entries()\n"));
+}
+
+/*
+ * kadm5int_acl_load_acl_file()	- Open and parse the ACL file.
+ */
+static int
+kadm5int_acl_load_acl_file()
+{
+    FILE 	*afp;
+    char 	*alinep;
+    aent_t	**aentpp;
+    int		alineno;
+    int		retval = 1;
+
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_load_acl_file()\n"));
+    /* Open the ACL file for read */
+    afp = fopen(acl_acl_file, "r");
+    if (afp) {
+	alineno = 1;
+	aentpp = &acl_list_head;
+
+	/* Get a non-comment line */
+	while ((alinep = kadm5int_acl_get_line(afp, &alineno))) {
+	    /* Parse it */
+	    *aentpp = kadm5int_acl_parse_line(alinep);
+	    /* If syntax error, then fall out */
+	    if (!*aentpp) {
+		krb5_klog_syslog(LOG_ERR, acl_syn_err_msg,
+			acl_acl_file, alineno, alinep);
+		retval = 0;
+		break;
+	    }
+	    acl_list_tail = *aentpp;
+	    aentpp = &(*aentpp)->ae_next;
+	}
+
+	fclose(afp);
+
+	if (acl_catchall_entry) {
+	     *aentpp = kadm5int_acl_parse_line(acl_catchall_entry);
+	     if (*aentpp) {
+		  acl_list_tail = *aentpp;
+	     }
+	     else {
+		  retval = 0;
+		  DPRINT(DEBUG_OPERATION, acl_debug_level,
+			 ("> catchall acl entry (%s) load failed\n",
+			  acl_catchall_entry));
+	     }
+	}
+    }
+    else {
+	krb5_klog_syslog(LOG_ERR, acl_cantopen_msg,
+			 error_message(errno), acl_acl_file);
+	if (acl_catchall_entry &&
+	    (acl_list_head = kadm5int_acl_parse_line(acl_catchall_entry))) {
+	    acl_list_tail = acl_list_head;
+	}
+	else {
+	    retval = 0;
+	    DPRINT(DEBUG_OPERATION, acl_debug_level,
+		   ("> catchall acl entry (%s) load failed\n",
+		    acl_catchall_entry));
+	}
+    }
+
+    if (!retval) {
+	kadm5int_acl_free_entries();
+    }
+    DPRINT(DEBUG_CALLS, acl_debug_level,
+	   ("X kadm5int_acl_load_acl_file() = %d\n", retval));
+    return(retval);
+}
+
+/*
+ * kadm5int_acl_match_data()	- See if two data entries match.
+ *
+ * Wildcarding is only supported for a whole component.
+ */
+static krb5_boolean
+kadm5int_acl_match_data(e1, e2, targetflag, ws)
+    krb5_data	*e1, *e2;
+    int		targetflag;
+    wildstate_t	*ws;
+{
+    krb5_boolean	retval;
+
+    DPRINT(DEBUG_CALLS, acl_debug_level, 
+	   ("* acl_match_entry(%s, %s)\n", e1->data, e2->data));
+    retval = 0;
+    if (!strncmp(e1->data, "*", e1->length)) {
+	retval = 1;
+	if (ws && !targetflag) {
+	    if (ws->nwild >= 9) {
+		DPRINT(DEBUG_ACL, acl_debug_level,
+		    ("Too many wildcards in ACL entry %s\n", entry->ae_name));
+	    }
+	    else
+		ws->backref[ws->nwild++] = e2;
+	}
+    }
+    else if (ws && targetflag && (e1->length == 2) && (e1->data[0] == '*') &&
+	     (e1->data[1] >= '1') && (e1->data[1] <= '9')) {
+	int	n = e1->data[1] - '1';
+	if (n >= ws->nwild) {
+	    DPRINT(DEBUG_ACL, acl_debug_level,
+		   ("Too many backrefs in ACL entry %s\n", entry->ae_name));
+	}
+	else if ((ws->backref[n]->length == e2->length) &&
+		 (!strncmp(ws->backref[n]->data, e2->data, e2->length)))
+	    retval = 1;
+	
+    }
+    else {
+	if ((e1->length == e2->length) &&
+	    (!strncmp(e1->data, e2->data, e1->length)))
+	    retval = 1;
+    }
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval));
+    return(retval);
+}
+
+/*
+ * kadm5int_acl_find_entry()	- Find a matching entry.
+ */
+static aent_t *
+kadm5int_acl_find_entry(kcontext, principal, dest_princ)
+    krb5_context	kcontext;
+    krb5_principal	principal;
+    krb5_principal	dest_princ;
+{
+    aent_t		*entry;
+    krb5_error_code	kret;
+    int			i;
+    int			matchgood;
+    wildstate_t		state;
+
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_find_entry()\n"));
+    memset((char *)&state, 0, sizeof state);
+    for (entry=acl_list_head; entry; entry = entry->ae_next) {
+	if (entry->ae_name_bad)
+	    continue;
+	if (!strcmp(entry->ae_name, "*")) {
+	    DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n"));
+	    matchgood = 1;
+	}
+	else {
+	    if (!entry->ae_principal && !entry->ae_name_bad) {
+		kret = krb5_parse_name(kcontext,
+				       entry->ae_name,
+				       &entry->ae_principal);
+		if (kret)
+		    entry->ae_name_bad = 1;
+	    }
+	    if (entry->ae_name_bad) {
+		DPRINT(DEBUG_ACL, acl_debug_level,
+		       ("Bad ACL entry %s\n", entry->ae_name));
+		continue;
+	    }
+	    matchgood = 0;
+	    if (kadm5int_acl_match_data(&entry->ae_principal->realm,
+			       &principal->realm, 0, (wildstate_t *)0) &&
+		(entry->ae_principal->length == principal->length)) {
+		matchgood = 1;
+		for (i=0; i<principal->length; i++) {
+		    if (!kadm5int_acl_match_data(&entry->ae_principal->data[i],
+					&principal->data[i], 0, &state)) {
+			matchgood = 0;
+			break;
+		    }
+		}
+	    }
+	}
+	if (!matchgood)
+	    continue;
+
+	/* We've matched the principal.  If we have a target, then try it */
+	if (entry->ae_target && strcmp(entry->ae_target, "*")) {
+	    if (!entry->ae_target_princ && !entry->ae_target_bad) {
+		kret = krb5_parse_name(kcontext, entry->ae_target,
+				       &entry->ae_target_princ);
+		if (kret)
+		    entry->ae_target_bad = 1;
+	    }
+	    if (entry->ae_target_bad) {
+	        DPRINT(DEBUG_ACL, acl_debug_level,
+		       ("Bad target in ACL entry for %s\n", entry->ae_name));
+	        entry->ae_name_bad = 1;
+	        continue;
+	    }
+	    if (!dest_princ)
+	        matchgood = 0;
+	    else if (entry->ae_target_princ && dest_princ) {
+	        if (kadm5int_acl_match_data(&entry->ae_target_princ->realm,
+			           &dest_princ->realm, 1, (wildstate_t *)0) &&
+		    (entry->ae_target_princ->length == dest_princ->length)) {
+		    for (i=0; i<dest_princ->length; i++) {
+		        if (!kadm5int_acl_match_data(&entry->ae_target_princ->data[i],
+			  		    &dest_princ->data[i], 1, &state)) {
+			    matchgood = 0;
+			    break;
+		        }
+		    }
+	        }
+	        else
+		    matchgood = 0;
+	    }
+        }
+	if (!matchgood)
+	    continue;
+
+	if (entry->ae_restriction_string
+	    && !entry->ae_restriction_bad
+	    && !entry->ae_restrictions
+	    && kadm5int_acl_parse_restrictions(entry->ae_restriction_string,
+				      &entry->ae_restrictions)) {
+	    DPRINT(DEBUG_ACL, acl_debug_level,
+		   ("Bad restrictions in ACL entry for %s\n", entry->ae_name));
+	    entry->ae_restriction_bad = 1;
+	}
+	if (entry->ae_restriction_bad) {
+	    entry->ae_name_bad = 1;
+	    continue;
+	}
+	break;
+    }
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_find_entry()=%x\n",entry));
+    return(entry);
+}
+
+/*
+ * kadm5int_acl_init()	- Initialize ACL context.
+ */
+krb5_error_code
+kadm5int_acl_init(kcontext, debug_level, acl_file)
+    krb5_context	kcontext;
+    int			debug_level;
+    char		*acl_file;
+{
+    krb5_error_code	kret;
+
+    kret = 0;
+    acl_debug_level = debug_level;
+    DPRINT(DEBUG_CALLS, acl_debug_level,
+	   ("* kadm5int_acl_init(afile=%s)\n",
+	    ((acl_file) ? acl_file : "(null)")));
+    acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL;
+    acl_inited = kadm5int_acl_load_acl_file();
+
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_init() = %d\n", kret));
+    return(kret);
+}
+
+/*
+ * kadm5int_acl_finish	- Terminate ACL context.
+ */
+void
+kadm5int_acl_finish(kcontext, debug_level)
+    krb5_context	kcontext;
+    int			debug_level;
+{
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_finish()\n"));
+    kadm5int_acl_free_entries();
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_finish()\n"));
+}
+
+/*
+ * kadm5int_acl_check()	- Is this operation permitted for this principal?
+ *			this code used not to be based on gssapi.  In order
+ *			to minimize porting hassles, I've put all the
+ *			gssapi hair in this function.  This might not be
+ *			the best medium-term solution.  (The best long-term
+ *			solution is, of course, a real authorization service.)
+ */
+krb5_boolean
+kadm5int_acl_check(kcontext, caller, opmask, principal, restrictions)
+    krb5_context	kcontext;
+    gss_name_t		caller;
+    krb5_int32		opmask;
+    krb5_principal	principal;
+    restriction_t	**restrictions;
+{
+    krb5_boolean	retval;
+    aent_t		*aentry;
+    gss_buffer_desc	caller_buf;
+    gss_OID		caller_oid;
+    OM_uint32		emaj, emin;
+    krb5_error_code	code;
+    krb5_principal	caller_princ;
+
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n"));
+
+    if (GSS_ERROR(emaj = gss_display_name(&emin, caller, &caller_buf,
+					  &caller_oid)))
+       return(0);
+
+    code = krb5_parse_name(kcontext, (char *) caller_buf.value,
+			   &caller_princ);
+
+    gss_release_buffer(&emin, &caller_buf);
+
+    if (code)
+       return(code);
+
+    retval = 0;
+
+    aentry = kadm5int_acl_find_entry(kcontext, caller_princ, principal);
+    if (aentry) {
+	if ((aentry->ae_op_allowed & opmask) == opmask) {
+	    retval = 1;
+	    if (restrictions) {
+		*restrictions =
+		    (aentry->ae_restrictions && aentry->ae_restrictions->mask)
+		    ? aentry->ae_restrictions
+		    : (restriction_t *) NULL;
+	    }
+	}
+    }
+
+    krb5_free_principal(kcontext, caller_princ);
+
+    DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n",
+					  retval));
+    return(retval);
+}
+
+kadm5_ret_t
+kadm5_get_privs(void *server_handle, long *privs)
+{
+     CHECK_HANDLE(server_handle);
+
+     /* this is impossible to do with the current interface.  For now,
+	return all privs, which will confuse some clients, but not
+	deny any access to users of "smart" clients which try to cache */
+
+     *privs = ~0;
+
+     return KADM5_OK;
+}
diff --git a/mechglue/src/lib/kadm5/srv/server_acl.h b/mechglue/src/lib/kadm5/srv/server_acl.h
new file mode 100644
index 000000000..3e24a6357
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/server_acl.h
@@ -0,0 +1,103 @@
+/*
+ * lib/kadm5/srv/server_acl.h
+ *
+ * Copyright 1995-2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#ifndef	SERVER_ACL_H__
+#define	SERVER_ACL_H__
+
+/*
+ * Debug definitions.
+ */
+#define	DEBUG_SPROC	1
+#define	DEBUG_OPERATION	2
+#define	DEBUG_HOST	4
+#define	DEBUG_REALM	8
+#define	DEBUG_REQUESTS	16
+#define	DEBUG_ACL	32
+#define	DEBUG_PROTO	64
+#define	DEBUG_CALLS	128
+#define	DEBUG_NOSLAVES	256
+#ifdef	DEBUG
+#define	DPRINT(l1, cl, al)	if ((cl & l1) != 0) xprintf al
+#else	/* DEBUG */
+#define	DPRINT(l1, cl, al)
+#endif	/* DEBUG */
+#define	DLOG(l1, cl, msg)	if ((cl & l1) != 0)	\
+					com_err(programname, 0, msg)
+
+/*
+ * Access control bits.
+ */
+#define	ACL_ADD			1
+#define	ACL_DELETE		2
+#define	ACL_MODIFY		4
+#define	ACL_CHANGEPW		8
+/* #define ACL_CHANGE_OWN_PW	16 */
+#define	ACL_INQUIRE		32
+/* #define ACL_EXTRACT		64 */
+#define	ACL_LIST		128
+#define ACL_SETKEY		256
+#define	ACL_RENAME		(ACL_ADD+ACL_DELETE)
+
+#define	ACL_ALL_MASK		(ACL_ADD	| \
+				 ACL_DELETE	| \
+				 ACL_MODIFY	| \
+				 ACL_CHANGEPW	| \
+				 ACL_INQUIRE	| \
+				 ACL_LIST	| \
+				 ACL_SETKEY)
+
+typedef struct _restriction {
+    long		mask;
+    krb5_flags		require_attrs;
+    krb5_flags		forbid_attrs;
+    krb5_deltat		princ_lifetime;
+    krb5_deltat		pw_lifetime;
+    krb5_deltat		max_life;
+    krb5_deltat		max_renewable_life;
+    long		aux_attributes;
+    char		*policy;
+} restriction_t;
+
+krb5_error_code kadm5int_acl_init
+	(krb5_context,
+		   int,
+		   char *);
+void kadm5int_acl_finish
+	(krb5_context,
+		   int);
+krb5_boolean kadm5int_acl_check
+	(krb5_context,
+		   gss_name_t,
+		   krb5_int32,
+		   krb5_principal,
+		   restriction_t **);
+krb5_error_code kadm5int_acl_impose_restrictions
+	(krb5_context,
+		   kadm5_principal_ent_rec *,
+		   long *,
+		   restriction_t *);
+#endif	/* SERVER_ACL_H__ */
diff --git a/mechglue/src/lib/kadm5/srv/server_dict.c b/mechglue/src/lib/kadm5/srv/server_dict.c
new file mode 100644
index 000000000..53df800b9
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/server_dict.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include    <sys/types.h>
+#include    <sys/file.h>
+#include    <fcntl.h>
+#include    <sys/stat.h>
+#include    <unistd.h>
+#include <errno.h>
+#include    <kadm5/admin.h>
+#include    <stdlib.h>
+#include    <stdio.h>
+#include    <string.h>
+#ifdef HAVE_MEMORY_H
+#include    <memory.h>
+#endif
+#include    "adm_proto.h"
+#include    <syslog.h>
+#include    "server_internal.h"
+
+static char	    **word_list = NULL;	    /* list of word pointers */
+static char	    *word_block = NULL;	    /* actual word data */
+static unsigned int word_count = 0;	    /* number of words */
+
+
+/*
+ * Function: word_compare
+ * 
+ * Purpose: compare two words in the dictionary.
+ *
+ * Arguments:
+ *	w1		(input)	pointer to first word
+ *	w2		(input) pointer to second word
+ *	<return value>	result of strcmp
+ *
+ * Requires:
+ *	w1 and w2 to point to valid memory
+ * 
+ */
+
+static int
+word_compare(const void *s1, const void *s2)
+{
+    return (strcasecmp(*(const char **)s1, *(const char **)s2));
+}
+
+/*
+ * Function: init-dict
+ * 
+ * Purpose: Initialize in memory word dictionary
+ *
+ * Arguments:
+ *	    none
+ *	    <return value> KADM5_OK on success errno on failure;
+ * 			   (but success on ENOENT)
+ *
+ * Requires:
+ *	If WORDFILE exists, it must contain a list of words,
+ *	one word per-line.
+ * 
+ * Effects:
+ *	If WORDFILE exists, it is read into memory sorted for future
+ * use.  If it does not exist, it syslogs an error message and returns
+ * success.
+ *
+ * Modifies:
+ *	word_list to point to a chunck of allocated memory containing
+ *	pointers to words
+ *	word_block to contain the dictionary.
+ * 
+ */
+
+int init_dict(kadm5_config_params *params)
+{
+    int		    fd,
+		    len,
+		    i;
+    char	    *p,
+		    *t;
+    struct  stat    sb;
+    
+    if(word_list != NULL && word_block != NULL)
+	return KADM5_OK;
+    if (! (params->mask & KADM5_CONFIG_DICT_FILE)) {
+	 krb5_klog_syslog(LOG_INFO, "No dictionary file specified, continuing "
+		"without one.");
+	 return KADM5_OK;
+    }
+    if ((fd = open(params->dict_file, O_RDONLY)) == -1) {
+	 if (errno == ENOENT) {
+	      krb5_klog_syslog(LOG_ERR, 
+			       "WARNING!  Cannot find dictionary file %s, "
+			       "continuing without one.", params->dict_file);
+	      return KADM5_OK;
+	 } else
+	      return errno;
+    }
+    if (fstat(fd, &sb) == -1) 
+	return errno;
+    if ((word_block = (char *) malloc(sb.st_size + 1)) == NULL)
+	return errno;
+    if (read(fd, word_block, sb.st_size) != sb.st_size)
+	return errno;
+    (void) close(fd);
+    word_block[sb.st_size] = '\0';
+
+    p = word_block;
+    len = sb.st_size;
+    while(len > 0 && (t = memchr(p, '\n', len)) != NULL) {
+	*t = '\0';
+	len -= t - p + 1;	
+	p = t + 1;
+	word_count++;
+    }
+    if ((word_list = (char **) malloc(word_count * sizeof(char *))) == NULL)
+	return errno;
+    p = word_block;
+    for (i = 0; i < word_count; i++) {
+	word_list[i] = p;
+	p += strlen(p) + 1;
+    }
+    qsort(word_list, word_count, sizeof(char *), word_compare);
+    return KADM5_OK;
+}
+
+/*
+ * Function: find_word
+ * 
+ * Purpose: See if the specified word exists in the in-core dictionary
+ *
+ * Arguments:
+ *	word		(input) word to search for.
+ * 	<return value>	WORD_NOT_FOUND if not in dictionary,
+ *			KADM5_OK if if found word
+ *			errno if init needs to be called and returns an
+ *			error
+ *
+ * Requires:
+ *	word to be a null terminated string.
+ *	That word_list and word_block besetup
+ * 
+ * Effects:
+ *	finds word in dictionary.
+ * Modifies:
+ *	nothing.
+ * 
+ */
+
+int
+find_word(const char *word)
+{
+    char    **value;
+
+    if(word_list == NULL || word_block == NULL) 
+	    return WORD_NOT_FOUND;
+    if ((value = (char **) bsearch(&word, word_list, word_count, sizeof(char *),
+				   word_compare)) == NULL)
+	return WORD_NOT_FOUND;
+    else
+	return KADM5_OK;
+}
+
+/*
+ * Function: destroy_dict
+ * 
+ * Purpose: destroy in-core copy of dictionary.
+ *
+ * Arguments:
+ *	    none
+ *	    <return value>  none
+ * Requires:
+ *	    nothing
+ * Effects:
+ *	frees up memory occupied by word_list and word_block
+ *	sets count back to 0, and resets the pointers to NULL
+ *
+ * Modifies:
+ *	word_list, word_block, and word_count.
+ * 
+ */
+
+void
+destroy_dict(void)
+{
+    if(word_list) {
+	free(word_list);
+	word_list = NULL;
+    }
+    if(word_block) {
+	free(word_block);
+	word_block = NULL;
+    }
+    if(word_count)
+	word_count = 0;
+    return;
+}
diff --git a/mechglue/src/lib/kadm5/srv/server_handle.c b/mechglue/src/lib/kadm5/srv/server_handle.c
new file mode 100644
index 000000000..53abe94dd
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/server_handle.c
@@ -0,0 +1,9 @@
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include "server_internal.h"
+
+int _kadm5_check_handle(void *handle)
+{
+     CHECK_HANDLE(handle);
+     return 0;
+}
diff --git a/mechglue/src/lib/kadm5/srv/server_init.c b/mechglue/src/lib/kadm5/srv/server_init.c
new file mode 100644
index 000000000..dd1fe6693
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/server_init.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <com_err.h>
+#include <kadm5/admin.h>
+#include <krb5.h>
+#include "server_internal.h"
+
+/*
+ * Function check_handle
+ *
+ * Purpose: Check a server handle and return a com_err code if it is
+ * invalid or 0 if it is valid.
+ *
+ * Arguments:
+ *
+ * 	handle		The server handle.
+ */
+
+static int check_handle(void *handle)
+{
+     CHECK_HANDLE(handle);
+     return 0;
+}
+
+static int dup_db_args( kadm5_server_handle_t handle, char **db_args )
+{
+    int count  = 0;
+    int ret = 0;
+
+    for( count=0; db_args && db_args[count]; count++ );
+    if( count == 0 )
+    {
+	handle->db_args = NULL;
+	goto clean_n_exit;
+    }
+
+    handle->db_args = calloc(sizeof(char*), count+1);
+    if( handle->db_args == NULL )
+    {
+	ret=ENOMEM;
+	goto clean_n_exit;
+    }
+
+    for(count=0; db_args[count]; count++)
+    {
+	handle->db_args[count] = strdup(db_args[count]);
+	if( handle->db_args[count] == NULL )
+	{
+	    ret = ENOMEM;
+	    goto clean_n_exit;
+	}
+    }
+
+ clean_n_exit:
+    if( ret && handle->db_args )
+    {
+	for(count=0; handle->db_args[count]; count++ )
+	    free( handle->db_args[count] );
+
+	free(handle->db_args), handle->db_args = NULL;
+    }
+
+    return ret;
+}
+
+static void free_db_args(kadm5_server_handle_t handle)
+{
+    int count;
+
+    if( handle->db_args )
+    {
+	for(count=0; handle->db_args[count]; count++ )
+	    free( handle->db_args[count] );
+	
+	free(handle->db_args), handle->db_args = NULL;
+    }
+}
+
+kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
+				     char *service_name,
+				     kadm5_config_params *params,
+				     krb5_ui_4 struct_version,
+				     krb5_ui_4 api_version,
+				     char **db_args,
+				     void **server_handle)
+{
+     return kadm5_init(client_name, pass, service_name, params,
+		       struct_version, api_version, db_args,
+		       server_handle);
+}
+
+kadm5_ret_t kadm5_init_with_creds(char *client_name,
+				  krb5_ccache ccache,
+				  char *service_name,
+				  kadm5_config_params *params,
+				  krb5_ui_4 struct_version,
+				  krb5_ui_4 api_version,
+				  char **db_args,
+				  void **server_handle)
+{
+     /*
+      * A program calling init_with_creds *never* expects to prompt the
+      * user.  Therefore, always pass a dummy password in case this is
+      * KADM5_API_VERSION_1.  If this is KADM5_API_VERSION_2 and
+      * MKEY_FROM_KBD is non-zero, return an error.
+      */
+     if (api_version == KADM5_API_VERSION_2 && params &&
+	 (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
+	 params->mkey_from_kbd)
+	  return KADM5_BAD_SERVER_PARAMS;
+     return kadm5_init(client_name, NULL, service_name, params,
+		       struct_version, api_version, db_args,
+		       server_handle);
+}
+
+
+kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
+				 char *service_name,
+				 kadm5_config_params *params,
+				 krb5_ui_4 struct_version,
+				 krb5_ui_4 api_version,
+				 char **db_args,
+				 void **server_handle)
+{
+     /*
+      * A program calling init_with_skey *never* expects to prompt the
+      * user.  Therefore, always pass a dummy password in case this is
+      * KADM5_API_VERSION_1.  If this is KADM5_API_VERSION_2 and
+      * MKEY_FROM_KBD is non-zero, return an error.
+      */
+     if (api_version == KADM5_API_VERSION_2 && params &&
+	 (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
+	 params->mkey_from_kbd)
+	  return KADM5_BAD_SERVER_PARAMS;
+     return kadm5_init(client_name, NULL, service_name, params,
+		       struct_version, api_version, db_args,
+		       server_handle);
+}
+
+kadm5_ret_t kadm5_init(char *client_name, char *pass,
+		       char *service_name,
+		       kadm5_config_params *params_in,
+		       krb5_ui_4 struct_version,
+		       krb5_ui_4 api_version,
+		       char **db_args,
+		       void **server_handle)
+{
+     int ret;
+     kadm5_server_handle_t handle;
+     kadm5_config_params params_local; /* for v1 compat */
+
+    if (! server_handle)
+	 return EINVAL;
+
+    if (! client_name)
+	 return EINVAL;
+    
+    if (! (handle = (kadm5_server_handle_t) malloc(sizeof *handle)))
+	 return ENOMEM;
+    memset(handle, 0, sizeof(*handle));
+
+    ret = dup_db_args( handle, db_args );
+    if( ret )
+    {
+	free(handle);
+	return ret;
+    }
+
+    ret = (int) krb5_init_context(&(handle->context));
+    if (ret) {
+	 free_db_args(handle);
+	 free(handle);
+	 return(ret);
+    }
+
+    initialize_ovk_error_table();
+/*     initialize_adb_error_table(); */
+    initialize_ovku_error_table();
+
+    handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
+    handle->struct_version = struct_version;
+    handle->api_version = api_version;
+
+     /*
+      * Verify the version numbers before proceeding; we can't use
+      * CHECK_HANDLE because not all fields are set yet.
+      */
+     GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION,
+			  KADM5_NEW_SERVER_API_VERSION);
+     
+     /*
+      * Acquire relevant profile entries.  In version 2, merge values
+      * in params_in with values from profile, based on
+      * params_in->mask.
+      *
+      * In version 1, we've given a realm (which may be NULL) instead
+      * of params_in.  So use that realm, make params_in contain an
+      * empty mask, and behave like version 2.
+      */
+     memset((char *) ¶ms_local, 0, sizeof(params_local));
+     if (api_version == KADM5_API_VERSION_1) {
+	  params_local.realm = (char *) params_in;
+	  if (params_in)
+	       params_local.mask = KADM5_CONFIG_REALM;
+	  params_in = ¶ms_local;
+     }
+
+#define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER)
+     if (params_in && (params_in->mask & ILLEGAL_PARAMS)) {
+	  krb5_free_context(handle->context);
+	  free_db_args(handle);
+	  free(handle);
+	  return KADM5_BAD_SERVER_PARAMS;
+     }
+
+     ret = kadm5_get_config_params(handle->context, (char *) NULL,
+				       (char *) NULL, params_in,
+				       &handle->params);
+     if (ret) {
+	  krb5_free_context(handle->context);
+	  free_db_args(handle);
+	  free(handle);
+	  return(ret);
+     }
+
+#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_DBNAME | \
+			 KADM5_CONFIG_ADBNAME | \
+			 KADM5_CONFIG_ADB_LOCKFILE | \
+			 KADM5_CONFIG_ENCTYPE | \
+			 KADM5_CONFIG_FLAGS | \
+			 KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE | \
+			 KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES) 
+
+     if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
+	  krb5_free_context(handle->context);
+	  free_db_args(handle);
+	  free(handle);
+	  return KADM5_MISSING_CONF_PARAMS;
+     }
+
+     ret = krb5_set_default_realm(handle->context, handle->params.realm);
+     if( ret )
+     {
+	  krb5_free_context(handle->context);
+	  free_db_args(handle);
+	  free(handle);
+	  return ret;
+     }
+
+    ret = krb5_db_open(handle->context, db_args, KRB5_KDB_OPEN_RW);
+    if (ret) {
+	 krb5_free_context(handle->context);
+	 free_db_args(handle);
+	 free(handle);
+	 return(ret);
+    }
+
+    if ((ret = krb5_parse_name(handle->context, client_name,
+			       &handle->current_caller))) {
+	 krb5_db_fini(handle->context);
+	 krb5_free_context(handle->context);
+	 free_db_args(handle);
+	 free(handle);
+	 return ret;
+    }
+
+    if (! (handle->lhandle = malloc(sizeof(*handle)))) {
+	 krb5_db_fini(handle->context);
+	 krb5_free_context(handle->context);
+	 free_db_args(handle);
+	 free(handle);
+	 return ENOMEM;
+    }
+    *handle->lhandle = *handle;
+    handle->lhandle->api_version = KADM5_API_VERSION_2;
+    handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
+    handle->lhandle->lhandle = handle->lhandle;
+
+    /* can't check the handle until current_caller is set */
+    ret = check_handle((void *) handle);
+    if (ret) {
+	free_db_args(handle);
+        free(handle);
+	return ret;
+    }
+     
+    /*
+     * The KADM5_API_VERSION_1 spec said "If pass (or keytab) is NULL
+     * or an empty string, reads the master password from [the stash
+     * file].  Otherwise, the non-NULL password is ignored and the
+     * user is prompted for it via the tty."  However, the code was
+     * implemented the other way: when a non-NULL password was
+     * provided, the stash file was used.  This is somewhat more
+     * sensible, as then a local or remote client that provides a
+     * password does not prompt the user.  This code maintains the
+     * previous actual behavior, and not the old spec behavior,
+     * because that is how the unit tests are written.
+     *
+     * In KADM5_API_VERSION_2, this decision is controlled by
+     * params.
+     *
+     * kdb_init_master's third argument is "from_keyboard".
+     */
+    ret = kdb_init_master(handle, handle->params.realm,
+			  (handle->api_version == KADM5_API_VERSION_1 ?
+			   ((pass == NULL) || !(strlen(pass))) :
+			   ((handle->params.mask & KADM5_CONFIG_MKEY_FROM_KBD)
+			    && handle->params.mkey_from_kbd)
+			   )); 
+    if (ret) {
+        krb5_db_fini(handle->context);
+	krb5_free_context(handle->context);
+	free_db_args(handle);
+	free(handle);
+	return ret;
+    }
+    
+    ret = kdb_init_hist(handle, handle->params.realm);
+    if (ret) {
+	 krb5_db_fini(handle->context);
+	 krb5_free_context(handle->context);
+	 free_db_args(handle);
+	 free(handle);
+	 return ret;
+    }
+
+    ret = init_dict(&handle->params);
+    if (ret) {
+         krb5_db_fini(handle->context);
+	 krb5_free_principal(handle->context, handle->current_caller);
+	 krb5_free_context(handle->context);
+	 free_db_args(handle);
+	 free(handle);
+	 return ret;
+    }
+    
+    *server_handle = (void *) handle;
+    
+    return KADM5_OK;
+}
+
+kadm5_ret_t kadm5_destroy(void *server_handle)
+{
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    destroy_dict();
+
+    adb_policy_close(handle);
+    krb5_db_fini(handle->context);
+    krb5_free_principal(handle->context, handle->current_caller);
+    kadm5_free_config_params(handle->context, &handle->params);
+    krb5_free_context(handle->context);
+    handle->magic_number = 0;
+    free(handle->lhandle);
+    free_db_args(handle);
+    free(handle);
+ 
+    return KADM5_OK;
+}
+
+kadm5_ret_t kadm5_lock(void *server_handle)
+{
+    kadm5_server_handle_t handle = server_handle;
+    kadm5_ret_t ret;
+
+    CHECK_HANDLE(server_handle);
+    ret = krb5_db_lock(handle->context, KRB5_DB_LOCKMODE_EXCLUSIVE);
+    if (ret)
+	return ret;
+
+    return KADM5_OK;
+}
+
+kadm5_ret_t kadm5_unlock(void *server_handle)
+{
+    kadm5_server_handle_t handle = server_handle;
+    kadm5_ret_t ret;
+
+    CHECK_HANDLE(server_handle);
+    ret = krb5_db_unlock(handle->context);
+    if (ret)
+	return ret;
+
+    return KADM5_OK;
+}
+
+kadm5_ret_t kadm5_flush(void *server_handle)
+{
+     kadm5_server_handle_t handle = server_handle;
+     kadm5_ret_t ret;
+
+     CHECK_HANDLE(server_handle);
+
+     if ((ret = krb5_db_fini(handle->context)) ||
+	 (ret = krb5_db_open(handle->context, handle->db_args, KRB5_KDB_OPEN_RW)) ||
+	 (ret = adb_policy_close(handle)) ||
+	 (ret = adb_policy_init(handle))) {
+	  (void) kadm5_destroy(server_handle);
+	  return ret;
+     }
+     return KADM5_OK;
+}
+
+int _kadm5_check_handle(void *handle)
+{
+     CHECK_HANDLE(handle);
+     return 0;
+}
diff --git a/mechglue/src/lib/kadm5/srv/server_kdb.c b/mechglue/src/lib/kadm5/srv/server_kdb.c
new file mode 100644
index 000000000..6392ef10d
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/server_kdb.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "k5-int.h"
+#include <kadm5/admin.h>
+#include "server_internal.h"
+
+krb5_principal	    master_princ;
+krb5_keyblock	    master_keyblock;
+krb5_db_entry	    master_db;
+
+krb5_principal	    hist_princ;
+krb5_keyblock	    hist_key;
+krb5_db_entry	    hist_db;
+krb5_kvno	    hist_kvno;
+
+/* much of this code is stolen from the kdc.  there should be some
+   library code to deal with this. */
+
+krb5_error_code kdb_init_master(kadm5_server_handle_t handle,
+				char *r, int from_keyboard)
+{
+    int		   ret = 0;
+    char	   *realm;
+    krb5_boolean   from_kbd = FALSE;
+
+    if (from_keyboard)
+      from_kbd = TRUE;
+
+    if (r == NULL)  {
+	if ((ret = krb5_get_default_realm(handle->context, &realm)))
+	    return ret;
+    } else {
+	realm = r;
+    }
+
+    if ((ret = krb5_db_setup_mkey_name(handle->context,
+				       handle->params.mkey_name,
+				       realm, NULL, &master_princ)))
+	goto done;
+
+    master_keyblock.enctype = handle->params.enctype;
+
+    ret = krb5_db_fetch_mkey(handle->context, master_princ,
+			     master_keyblock.enctype, from_kbd,
+			     FALSE /* only prompt once */,
+			     handle->params.stash_file,
+			     NULL /* I'm not sure about this,
+				     but it's what the kdc does --marc */,
+			     &master_keyblock);
+    if (ret)
+	goto done;
+				 
+    if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
+					 &master_keyblock))) {
+	  krb5_db_fini(handle->context);
+	  return ret;
+    }
+
+done:
+    if (r == NULL)
+	free(realm);
+
+    return(ret);
+}
+
+/*
+ * Function: kdb_init_hist
+ *
+ * Purpose: Initializes the global history variables.
+ *
+ * Arguments:
+ *
+ *	handle		(r) kadm5 api server handle
+ *	r		(r) realm of history principal to use, or NULL
+ *
+ * Effects: This function sets the value of the following global
+ * variables:
+ *
+ *	hist_princ	krb5_principal holding the history principal
+ *	hist_db		krb5_db_entry of the history principal
+ *	hist_key	krb5_keyblock holding the history principal's key
+ *	hist_encblock	krb5_encrypt_block holding the procssed hist_key
+ *	hist_kvno	the version number of the history key
+ *
+ * If the history principal does not already exist, this function
+ * attempts to create it with kadm5_create_principal.  WARNING!
+ * If the history principal is deleted and this function is executed
+ * (by kadmind, or kadmin.local, or anything else with permission),
+ * the principal will be assigned a new random key and all existing
+ * password history information will become useless.
+ */
+krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r)
+{
+    int	    ret = 0;
+    char    *realm, *hist_name;
+    krb5_key_data *key_data;
+    krb5_key_salt_tuple ks[1];
+
+    if (r == NULL)  {
+	if ((ret = krb5_get_default_realm(handle->context, &realm)))
+	    return ret;
+    } else {
+	realm = r;
+    }
+
+    if ((hist_name = (char *) malloc(strlen(KADM5_HIST_PRINCIPAL) +
+				     strlen(realm) + 2)) == NULL)
+	goto done;
+
+    (void) sprintf(hist_name, "%s@%s", KADM5_HIST_PRINCIPAL, realm);
+
+    if ((ret = krb5_parse_name(handle->context, hist_name, &hist_princ)))
+	goto done;
+
+    if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) {
+	kadm5_principal_ent_rec ent;
+
+	if (ret != KADM5_UNK_PRINC)
+	    goto done;
+
+	/* try to create the principal */
+
+	memset(&ent, 0, sizeof(ent));
+
+	ent.principal = hist_princ;
+	ent.max_life = KRB5_KDB_DISALLOW_ALL_TIX;
+	ent.attributes = 0;
+
+	/* this uses hist_kvno.  So we set it to 2, which will be the
+	   correct value once the principal is created and randomized.
+	   Of course, it doesn't make sense to keep a history for the
+	   history principal, anyway. */
+
+	hist_kvno = 2;
+	ks[0].ks_enctype = handle->params.enctype;
+	ks[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
+	ret = kadm5_create_principal_3(handle, &ent,
+				       (KADM5_PRINCIPAL | KADM5_MAX_LIFE |
+					KADM5_ATTRIBUTES),
+				       1, ks,
+				       "to-be-random");
+	if (ret)
+	    goto done;
+
+	/* this won't let us randomize the hist_princ.  So we cheat. */
+
+	hist_princ = NULL;
+
+	ret = kadm5_randkey_principal_3(handle, ent.principal, 0, 1, ks,
+					NULL, NULL);
+
+	hist_princ = ent.principal;
+
+	if (ret)
+	    goto done;
+
+	/* now read the newly-created kdb record out of the
+	   database. */
+
+	if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL)))
+	    goto done;
+
+    }
+
+    ret = krb5_dbe_find_enctype(handle->context, &hist_db,
+				handle->params.enctype, -1, -1, &key_data);
+    if (ret)
+	goto done;
+
+    ret = krb5_dbekd_decrypt_key_data(handle->context, &master_keyblock,
+				  key_data, &hist_key, NULL);
+    if (ret)
+	goto done;
+
+    hist_kvno = key_data->key_data_kvno;
+
+done:
+    free(hist_name);
+    if (r == NULL)
+	free(realm);
+    return ret;
+}
+
+/*
+ * Function: kdb_get_entry
+ *
+ * Purpose: Gets an entry from the kerberos database and breaks
+ * it out into a krb5_db_entry and an osa_princ_ent_t.
+ *
+ * Arguments:
+ *
+ *		handle		(r) the server_handle
+ * 		principal	(r) the principal to get
+ * 		kdb		(w) krb5_db_entry to fill in
+ * 		adb		(w) osa_princ_ent_rec to fill in
+ *
+ * when the caller is done with kdb and adb, kdb_free_entry must be
+ * called to release them.  The adb record is filled in with the
+ * contents of the KRB5_TL_KADM_DATA record; if that record doesn't
+ * exist, an empty but valid adb record is returned.
+ */
+krb5_error_code
+kdb_get_entry(kadm5_server_handle_t handle,
+	      krb5_principal principal, krb5_db_entry *kdb,
+	      osa_princ_ent_rec *adb)
+{
+    krb5_error_code ret;
+    int nprincs;
+    krb5_boolean more;
+    krb5_tl_data tl_data;
+    XDR xdrs;
+
+    ret = krb5_db_get_principal(handle->context, principal, kdb, &nprincs,
+				&more);
+    if (ret)
+	return(ret);
+
+    if (more) {
+	krb5_db_free_principal(handle->context, kdb, nprincs);
+	return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
+    } else if (nprincs != 1) {
+	krb5_db_free_principal(handle->context, kdb, nprincs);
+	return(KADM5_UNK_PRINC);
+    }
+
+    if (adb) {
+	memset(adb, 0, sizeof(*adb));
+
+	tl_data.tl_data_type = KRB5_TL_KADM_DATA;
+	/*
+	 * XXX Currently, lookup_tl_data always returns zero; it sets
+	 * tl_data->tl_data_length to zero if the type isn't found.
+	 * This should be fixed...
+	 */
+	if ((ret = krb5_dbe_lookup_tl_data(handle->context, kdb, &tl_data))
+	    || (tl_data.tl_data_length == 0)) {
+	    /* there's no admin data.  this can happen, if the admin
+	       server is put into production after some principals
+	       are created.  In this case, return valid admin
+	       data (which is all zeros with the hist_kvno filled
+	       in), and when the entry is written, the admin
+	       data will get stored correctly. */
+
+	    adb->admin_history_kvno = hist_kvno;
+
+	    return(ret);
+	}
+
+	xdrmem_create(&xdrs, tl_data.tl_data_contents,
+		      tl_data.tl_data_length, XDR_DECODE);
+	if (! xdr_osa_princ_ent_rec(&xdrs, adb)) {
+	   xdr_destroy(&xdrs);
+	   krb5_db_free_principal(handle->context, kdb, 1);
+	   return(KADM5_XDR_FAILURE);
+	}
+	xdr_destroy(&xdrs);
+    }
+
+    return(0);
+}
+
+/*
+ * Function: kdb_free_entry
+ *
+ * Purpose: frees the resources allocated by kdb_get_entry
+ *
+ * Arguments:
+ *
+ *		handle		(r) the server_handle
+ * 		kdb		(w) krb5_db_entry to fill in
+ * 		adb		(w) osa_princ_ent_rec to fill in
+ *
+ * when the caller is done with kdb and adb, kdb_free_entry must be
+ * called to release them.
+ */
+
+krb5_error_code
+kdb_free_entry(kadm5_server_handle_t handle,
+	       krb5_db_entry *kdb, osa_princ_ent_rec *adb)
+{
+    XDR xdrs;
+
+
+    if (kdb)
+	krb5_db_free_principal(handle->context, kdb, 1);
+
+    if (adb) {
+	xdrmem_create(&xdrs, NULL, 0, XDR_FREE);
+	xdr_osa_princ_ent_rec(&xdrs, adb);
+	xdr_destroy(&xdrs);
+    }
+
+    return(0);
+}
+
+/*
+ * Function: kdb_put_entry
+ *
+ * Purpose: Stores the osa_princ_ent_t and krb5_db_entry into to
+ * database.
+ *
+ * Arguments:
+ *
+ *		handle	(r) the server_handle
+ * 		kdb	(r/w) the krb5_db_entry to store
+ * 		adb	(r) the osa_princ_db_ent to store
+ *
+ * Effects:
+ *
+ * The last modifier field of the kdb is set to the caller at now.
+ * adb is encoded with xdr_osa_princ_ent_ret and stored in kbd as
+ * KRB5_TL_KADM_DATA.  kdb is then written to the database.
+ */
+krb5_error_code
+kdb_put_entry(kadm5_server_handle_t handle,
+	      krb5_db_entry *kdb, osa_princ_ent_rec *adb)
+{
+    krb5_error_code ret;
+    krb5_int32 now;
+    XDR xdrs;
+    krb5_tl_data tl_data;
+    int one;
+
+    ret = krb5_timeofday(handle->context, &now);
+    if (ret)
+	return(ret);
+
+    ret = krb5_dbe_update_mod_princ_data(handle->context, kdb, now,
+					 handle->current_caller);
+    if (ret)
+	return(ret);
+    
+    xdralloc_create(&xdrs, XDR_ENCODE); 
+    if(! xdr_osa_princ_ent_rec(&xdrs, adb)) {
+	xdr_destroy(&xdrs);
+	return(KADM5_XDR_FAILURE);
+    }
+    tl_data.tl_data_type = KRB5_TL_KADM_DATA;
+    tl_data.tl_data_length = xdr_getpos(&xdrs);
+    tl_data.tl_data_contents = xdralloc_getdata(&xdrs);
+
+    ret = krb5_dbe_update_tl_data(handle->context, kdb, &tl_data);
+
+    xdr_destroy(&xdrs);
+
+    if (ret)
+	return(ret);
+
+    one = 1;
+
+    ret = krb5_db_put_principal(handle->context, kdb, &one);
+    if (ret)
+	return(ret);
+
+    return(0);
+}
+
+krb5_error_code
+kdb_delete_entry(kadm5_server_handle_t handle, krb5_principal name)
+{
+    int one = 1;
+    krb5_error_code ret;
+    
+    ret = krb5_db_delete_principal(handle->context, name, &one);
+
+    return ret;
+}
+
+typedef struct _iter_data {
+    void (*func)(void *, krb5_principal);
+    void *data;
+} iter_data;
+
+static krb5_error_code
+kdb_iter_func(krb5_pointer data, krb5_db_entry *kdb)
+{
+    iter_data *id = (iter_data *) data;
+
+    (*(id->func))(id->data, kdb->princ);
+
+    return(0);
+}
+
+krb5_error_code
+kdb_iter_entry(kadm5_server_handle_t handle, char *match_entry,
+	       void (*iter_fct)(void *, krb5_principal), void *data)
+{
+    iter_data id;
+    krb5_error_code ret;
+
+    id.func = iter_fct;
+    id.data = data;
+
+    ret = krb5_db_iterate(handle->context, match_entry, kdb_iter_func, &id);
+    if (ret)
+	return(ret);
+
+    return(0);
+}
+
diff --git a/mechglue/src/lib/kadm5/srv/server_misc.c b/mechglue/src/lib/kadm5/srv/server_misc.c
new file mode 100644
index 000000000..4f15fd3b2
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/server_misc.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include    "k5-int.h"
+#include    <krb5/kdb.h>
+#include    <ctype.h>
+#include    <pwd.h>
+
+/* for strcasecmp */
+#include    <string.h>
+
+#include    "server_internal.h"
+
+kadm5_ret_t
+adb_policy_init(kadm5_server_handle_t handle)
+{
+    /* now policy is initialized as part of database. No seperate call needed */
+    if( krb5_db_inited( handle->context ) )
+	return KADM5_OK;
+
+    return krb5_db_open( handle->context, NULL, KRB5_KDB_OPEN_RW );
+}
+
+kadm5_ret_t
+adb_policy_close(kadm5_server_handle_t handle)
+{
+    /* will be taken care by database close */
+    return KADM5_OK;
+}
+
+#ifdef HESIOD
+/* stolen from v4sever/kadm_funcs.c */
+static char *
+reverse(str)
+	char	*str;
+{
+	static char newstr[80];
+	char	*p, *q;
+	int	i;
+
+	i = strlen(str);
+	if (i >= sizeof(newstr))
+		i = sizeof(newstr)-1;
+	p = str+i-1;
+	q = newstr;
+	q[i]='\0';
+	for(; i > 0; i--) 
+		*q++ = *p--;
+	
+	return(newstr);
+}
+#endif /* HESIOD */
+
+#if 0
+static int
+lower(str)
+	char	*str;
+{
+	register char	*cp;
+	int	effect=0;
+
+	for (cp = str; *cp; cp++) {
+		if (isupper(*cp)) {
+			*cp = tolower(*cp);
+			effect++;
+		}
+	}
+	return(effect);
+}
+#endif
+
+#ifdef HESIOD
+static int
+str_check_gecos(gecos, pwstr)
+	char	*gecos;
+	char	*pwstr;
+{
+	char		*cp, *ncp, *tcp;
+	
+	for (cp = gecos; *cp; ) {
+		/* Skip past punctuation */
+		for (; *cp; cp++)
+			if (isalnum(*cp))
+				break;
+		/* Skip to the end of the word */
+		for (ncp = cp; *ncp; ncp++)
+			if (!isalnum(*ncp) && *ncp != '\'')
+				break;
+		/* Delimit end of word */
+		if (*ncp)
+			*ncp++ = '\0';
+		/* Check word to see if it's the password */
+		if (*cp) {
+			if (!strcasecmp(pwstr, cp))
+				return 1;
+			tcp = reverse(cp);
+			if (!strcasecmp(pwstr, tcp))
+				return 1;
+			cp = ncp;				
+		} else
+			break;
+	}
+	return 0;
+}
+#endif /* HESIOD */
+
+/* some of this is stolen from gatekeeper ... */
+kadm5_ret_t
+passwd_check(kadm5_server_handle_t handle,
+	     char *password, int use_policy, kadm5_policy_ent_t pol,
+	     krb5_principal principal)
+{
+    int	    nupper = 0,
+	    nlower = 0,
+	    ndigit = 0, 
+	    npunct = 0,
+	    nspec = 0;
+    char    c, *s, *cp;
+#ifdef HESIOD
+    extern  struct passwd *hes_getpwnam();
+    struct  passwd *ent;
+#endif
+    
+    if(use_policy) {
+	if(strlen(password) < pol->pw_min_length)
+	    return KADM5_PASS_Q_TOOSHORT;
+	s = password;
+	while ((c = *s++)) {
+	    if (islower((int) c)) {
+		nlower = 1;
+		continue;
+	    }
+	    else if (isupper((int) c)) {
+		nupper = 1;
+		continue;
+	    } else if (isdigit((int) c)) {
+		ndigit = 1;
+		continue;
+	    } else if (ispunct((int) c)) {
+		npunct = 1;
+		continue;
+	    } else {
+		nspec = 1;
+		continue;
+	    }
+	}
+	if ((nupper + nlower + ndigit + npunct + nspec) < pol->pw_min_classes) 
+	    return KADM5_PASS_Q_CLASS;
+	if((find_word(password) == KADM5_OK))
+	    return KADM5_PASS_Q_DICT;
+	else { 
+	    int	i, n = krb5_princ_size(handle->context, principal);
+	    cp = krb5_princ_realm(handle->context, principal)->data;
+	    if (strcasecmp(cp, password) == 0)
+		return KADM5_PASS_Q_DICT;
+	    for (i = 0; i < n ; i++) {
+		cp = krb5_princ_component(handle->context, principal, i)->data;
+		if (strcasecmp(cp, password) == 0)
+		    return KADM5_PASS_Q_DICT;
+#ifdef HESIOD
+		ent = hes_getpwnam(cp);
+		if (ent && ent->pw_gecos)
+		    if (str_check_gecos(ent->pw_gecos, password))
+			return KADM5_PASS_Q_DICT; /* XXX new error code? */
+#endif
+	    }
+	    return KADM5_OK;
+	}
+    } else {
+	if (strlen(password) < 1)
+	    return KADM5_PASS_Q_TOOSHORT;
+    }
+    return KADM5_OK;    
+}
+
diff --git a/mechglue/src/lib/kadm5/srv/svr_chpass_util.c b/mechglue/src/lib/kadm5/srv/svr_chpass_util.c
new file mode 100644
index 000000000..c8b63100a
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/svr_chpass_util.c
@@ -0,0 +1,16 @@
+#include <kadm5/admin.h>
+#include "server_internal.h"
+
+kadm5_ret_t kadm5_chpass_principal_util(void *server_handle,
+					krb5_principal princ,
+					char *new_pw, 
+					char **ret_pw,
+					char *msg_ret,
+					unsigned int msg_len)
+{
+  kadm5_server_handle_t handle = server_handle;
+
+  CHECK_HANDLE(server_handle);
+  return _kadm5_chpass_principal_util(handle, handle->lhandle, princ,
+				      new_pw, ret_pw, msg_ret, msg_len);
+}
diff --git a/mechglue/src/lib/kadm5/srv/svr_iters.c b/mechglue/src/lib/kadm5/srv/svr_iters.c
new file mode 100644
index 000000000..949388380
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/svr_iters.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#if defined(HAVE_COMPILE) && defined(HAVE_STEP)
+#define SOLARIS_REGEXPS
+#elif defined(HAVE_REGCOMP) && defined(HAVE_REGEXEC)
+#define POSIX_REGEXPS
+#elif defined(HAVE_RE_COMP) && defined(HAVE_RE_EXEC)
+#define BSD_REGEXPS
+#else
+#error I cannot find any regexp functions
+#endif
+
+#include	<sys/types.h>
+#include	<string.h>
+#include	<kadm5/admin.h>
+#ifdef SOLARIS_REGEXPS
+#include	<regexpr.h>
+#endif
+#ifdef POSIX_REGEXPS
+#include	<regex.h>
+#endif
+#include <stdlib.h>
+
+#include	"server_internal.h"
+
+struct iter_data {
+     krb5_context context;
+     char **names;
+     int n_names, sz_names;
+     unsigned int malloc_failed;
+     char *exp;
+#ifdef SOLARIS_REGEXPS
+     char *expbuf;
+#endif
+#ifdef POSIX_REGEXPS
+     regex_t preg;
+#endif
+};
+
+/*
+ * Function: glob_to_regexp
+ *
+ * Arguments:
+ *
+ *	glob	(r) the shell-style glob (?*[]) to convert
+ *	realm	(r) the default realm to append, or NULL
+ *	regexp	(w) the ed-style regexp created from glob
+ *
+ * Effects:
+ *
+ * regexp is filled in with allocated memory contained a regular
+ * expression to be used with re_comp/compile that matches what the
+ * shell-style glob would match.  If glob does not contain an "@"
+ * character and realm is not NULL, "@*" is appended to the regexp.
+ *
+ * Conversion algorithm:
+ *
+ *	quoted characters are copied quoted
+ *	? is converted to .
+ *	* is converted to .*
+ * 	active characters are quoted: ^, $, .
+ *	[ and ] are active but supported and have the same meaning, so
+ *		they are copied
+ *	other characters are copied
+ *	regexp is anchored with ^ and $
+ */
+static kadm5_ret_t glob_to_regexp(char *glob, char *realm, char **regexp)
+{
+     int append_realm;
+     char *p;
+
+     /* validate the glob */
+     if (glob[strlen(glob)-1] == '\\')
+	  return EINVAL;
+
+     /* A character of glob can turn into two in regexp, plus ^ and $ */
+     /* and trailing null.  If glob has no @, also allocate space for */
+     /* the realm. */
+     append_realm = (realm != NULL) && (strchr(glob, '@') == NULL);
+     p = (char *) malloc(strlen(glob)*2+ 3 + (append_realm ? 2 : 0));
+     if (p == NULL)
+	  return ENOMEM;
+     *regexp = p;
+
+     *p++ = '^';
+     while (*glob) {
+	  switch (*glob) {
+	  case '?':
+	       *p++ = '.';
+	       break;
+	  case '*':
+	       *p++ = '.';
+	       *p++ = '*';
+	       break;
+	  case '.':
+	  case '^':
+	  case '$':
+	       *p++ = '\\';
+	       *p++ = *glob;
+	       break;
+	  case '\\':
+	       *p++ = '\\';
+	       *p++ = *++glob;
+	       break;
+	  default:
+	       *p++ = *glob;
+	       break;
+	  }
+	  glob++;
+     }
+
+     if (append_realm) {
+	  *p++ = '@';
+	  *p++ = '*';
+     }
+
+     *p++ = '$';
+     *p++ = '\0';
+     return KADM5_OK;
+}
+
+static void get_either_iter(struct iter_data *data, char *name)
+{
+     int match;
+#ifdef SOLARIS_REGEXPS
+     match = (step(name, data->expbuf) != 0);
+#endif
+#ifdef POSIX_REGEXPS
+     match = (regexec(&data->preg, name, 0, NULL, 0) == 0);
+#endif
+#ifdef BSD_REGEXPS
+     match = (re_exec(name) != 0);
+#endif
+     if (match) {
+	  if (data->n_names == data->sz_names) {
+	       int new_sz = data->sz_names * 2;
+	       char **new_names = realloc(data->names,
+					  new_sz * sizeof(char *));
+	       if (new_names) {
+		    data->names = new_names;
+		    data->sz_names = new_sz;
+	       } else {
+		    data->malloc_failed = 1;
+		    free(name);
+		    return;
+	       }
+	  }
+	  data->names[data->n_names++] = name;
+     } else
+	  free(name);
+}
+
+static void get_pols_iter(void *data, osa_policy_ent_t entry)
+{
+     char *name;
+
+     if ((name = strdup(entry->name)) == NULL)
+	  return;
+     get_either_iter(data, name);
+}
+
+static void get_princs_iter(void *data, krb5_principal princ)
+{
+     struct iter_data *id = (struct iter_data *) data;
+     char *name;
+     
+     if (krb5_unparse_name(id->context, princ, &name) != 0)
+	  return;
+     get_either_iter(data, name);
+}
+
+static kadm5_ret_t kadm5_get_either(int princ,
+				       void *server_handle,
+				       char *exp,
+				       char ***princs,
+				       int *count)
+{
+     struct iter_data data;
+#ifdef BSD_REGEXPS
+     char *msg;
+#endif
+     char *regexp;
+     int i, ret;
+     kadm5_server_handle_t handle = server_handle;
+     
+     *count = 0;
+     if (exp == NULL)
+	  exp = "*";
+
+     CHECK_HANDLE(server_handle);
+
+     if ((ret = glob_to_regexp(exp, princ ? handle->params.realm : NULL,
+			       ®exp)) != KADM5_OK)
+	  return ret;
+
+     if (
+#ifdef SOLARIS_REGEXPS
+	 ((data.expbuf = compile(regexp, NULL, NULL)) == NULL)
+#endif
+#ifdef POSIX_REGEXPS
+	 ((regcomp(&data.preg, regexp, REG_NOSUB)) != 0)
+#endif
+#ifdef BSD_REGEXPS
+	 ((msg = (char *) re_comp(regexp)) != NULL)
+#endif
+	 )
+     {
+	  /* XXX syslog msg or regerr(regerrno) */
+	  free(regexp);
+	  return EINVAL;
+     }
+
+     data.n_names = 0;
+     data.sz_names = 10;
+     data.malloc_failed = 0;
+     data.names = malloc(sizeof(char *) * data.sz_names);
+     if (data.names == NULL) {
+	  free(regexp);
+	  return ENOMEM;
+     }
+
+     if (princ) {
+	  data.context = handle->context;
+	  ret = kdb_iter_entry(handle, exp, get_princs_iter, (void *) &data);
+     } else {
+	  ret = krb5_db_iter_policy(handle->context, exp, get_pols_iter, (void *)&data);
+     }
+     
+     free(regexp);
+#ifdef POSIX_REGEXPS
+     regfree(&data.preg);
+#endif
+     if ( !ret && data.malloc_failed)
+	  ret = ENOMEM;
+     if ( ret ) {
+	  for (i = 0; i < data.n_names; i++)
+	       free(data.names[i]);
+	  free(data.names);
+	  return ret;
+     }
+
+     *princs = data.names;
+     *count = data.n_names;
+     return KADM5_OK;
+}
+
+kadm5_ret_t kadm5_get_principals(void *server_handle,
+					   char *exp,
+					   char ***princs,
+					   int *count)
+{
+     return kadm5_get_either(1, server_handle, exp, princs, count);
+}
+
+kadm5_ret_t kadm5_get_policies(void *server_handle,
+					   char *exp,
+					   char ***pols,
+					   int *count)
+{
+     return kadm5_get_either(0, server_handle, exp, pols, count);
+}
+
diff --git a/mechglue/src/lib/kadm5/srv/svr_misc_free.c b/mechglue/src/lib/kadm5/srv/svr_misc_free.c
new file mode 100644
index 000000000..d20339705
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/svr_misc_free.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ * 
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+#include	<kadm5/admin.h>
+#include	<stdlib.h>
+#include	"server_internal.h"
+
+kadm5_ret_t
+kadm5_free_principal_ent(void *server_handle,
+			      kadm5_principal_ent_t val)
+{
+    kadm5_server_handle_t	handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if(val) {
+	if(val->principal) 
+	    krb5_free_principal(handle->context, val->principal);
+	if(val->mod_name)
+	    krb5_free_principal(handle->context, val->mod_name);
+	if(val->policy)
+	    free(val->policy);
+
+	/* XXX free key_data and tl_data */
+
+	if (handle->api_version == KADM5_API_VERSION_1)
+	     free(val);
+    }
+    return KADM5_OK;
+}
diff --git a/mechglue/src/lib/kadm5/srv/svr_policy.c b/mechglue/src/lib/kadm5/srv/svr_policy.c
new file mode 100644
index 000000000..31333b73c
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/svr_policy.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include	<sys/types.h>
+#include	<kadm5/admin.h>
+#include	"server_internal.h"
+#include	<stdlib.h>
+#include	<errno.h>
+
+#define MAX_PW_HISTORY	10
+#define MIN_PW_HISTORY	1
+#define	MIN_PW_CLASSES	1
+#define MAX_PW_CLASSES	5
+#define	MIN_PW_LENGTH	1
+
+/*
+ * Function: kadm5_create_policy
+ * 
+ * Purpose: Create Policies in the policy DB.
+ *
+ * Arguments:
+ *	entry	(input) The policy entry to be written out to the DB.
+ *	mask	(input)	Specifies which fields in entry are to ge written out
+ *			and which get default values.
+ *	<return value> 0 if successful otherwise an error code is returned.
+ *
+ * Requires:
+ *	Entry must be a valid principal entry, and mask have a valid value.
+ * 
+ * Effects:
+ *	Verifies that mask does not specify that the refcount should
+ *	be set as part of the creation, and calls
+ *	kadm5_create_policy_internal.  If the refcount *is*
+ *	specified, returns KADM5_BAD_MASK.
+ */
+
+kadm5_ret_t
+kadm5_create_policy(void *server_handle,
+			 kadm5_policy_ent_t entry, long mask)
+{
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    if (mask & KADM5_REF_COUNT)
+	return KADM5_BAD_MASK;
+    else
+	return kadm5_create_policy_internal(server_handle, entry, mask);
+}
+
+/*
+ * Function: kadm5_create_policy_internal
+ * 
+ * Purpose: Create Policies in the policy DB.
+ *
+ * Arguments:
+ *	entry	(input) The policy entry to be written out to the DB.
+ *	mask	(input)	Specifies which fields in entry are to ge written out
+ *			and which get default values.
+ *	<return value> 0 if successful otherwise an error code is returned.
+ *
+ * Requires:
+ *	Entry must be a valid principal entry, and mask have a valid value.
+ * 
+ * Effects:
+ *	Writes the data to the database, and does a database sync if
+ *	successful.
+ *
+ */
+
+kadm5_ret_t
+kadm5_create_policy_internal(void *server_handle,
+				  kadm5_policy_ent_t entry, long mask)
+{
+    kadm5_server_handle_t handle = server_handle;
+    osa_policy_ent_rec	pent;
+    int			ret;
+    char		*p;
+
+    CHECK_HANDLE(server_handle);
+
+    if ((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL))
+	return EINVAL;
+    if(strlen(entry->policy) == 0)
+	return KADM5_BAD_POLICY;
+    if (!(mask & KADM5_POLICY))
+	return KADM5_BAD_MASK;
+	
+    pent.name = entry->policy;
+    p = entry->policy;
+    while(*p != '\0') {
+	if(*p < ' ' || *p > '~')
+	    return KADM5_BAD_POLICY;
+	else
+	    p++;
+    }
+    if (!(mask & KADM5_PW_MAX_LIFE))
+	pent.pw_max_life = 0;
+    else
+	pent.pw_max_life = entry->pw_max_life;
+    if (!(mask & KADM5_PW_MIN_LIFE))
+	pent.pw_min_life = 0;
+    else {
+	if((mask & KADM5_PW_MAX_LIFE)) {
+	    if(entry->pw_min_life > entry->pw_max_life && entry->pw_max_life != 0)
+		return KADM5_BAD_MIN_PASS_LIFE;
+	}
+	pent.pw_min_life = entry->pw_min_life;
+    }
+    if (!(mask & KADM5_PW_MIN_LENGTH))
+	pent.pw_min_length = MIN_PW_LENGTH;
+    else {
+	if(entry->pw_min_length < MIN_PW_LENGTH)
+	    return KADM5_BAD_LENGTH;
+	pent.pw_min_length = entry->pw_min_length;
+    }
+    if (!(mask & KADM5_PW_MIN_CLASSES))
+	pent.pw_min_classes = MIN_PW_CLASSES;
+    else {
+	if(entry->pw_min_classes > MAX_PW_CLASSES || entry->pw_min_classes < MIN_PW_CLASSES)
+	    return KADM5_BAD_CLASS;
+	pent.pw_min_classes = entry->pw_min_classes;
+    }
+    if (!(mask & KADM5_PW_HISTORY_NUM))
+	pent.pw_history_num = MIN_PW_HISTORY;
+    else {
+	if(entry->pw_history_num < MIN_PW_HISTORY ||
+	   entry->pw_history_num > MAX_PW_HISTORY)
+	    return KADM5_BAD_HISTORY;
+	else
+	    pent.pw_history_num = entry->pw_history_num;
+    }
+    if (!(mask & KADM5_REF_COUNT))
+	pent.policy_refcnt = 0;
+    else
+	pent.policy_refcnt = entry->policy_refcnt;
+    if ((ret = krb5_db_create_policy(handle->context, &pent)))
+	return ret;
+    else
+	return KADM5_OK;
+}
+	  
+kadm5_ret_t
+kadm5_delete_policy(void *server_handle, kadm5_policy_t name)
+{
+    kadm5_server_handle_t handle = server_handle;
+    osa_policy_ent_t		entry;
+    int				ret;
+    int                         cnt=1;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    if(name == (kadm5_policy_t) NULL)
+	return EINVAL;
+    if(strlen(name) == 0)
+	return KADM5_BAD_POLICY;
+    if((ret = krb5_db_get_policy(handle->context, name, &entry,&cnt)))
+	return ret;
+    if( cnt != 1 )
+	return KADM5_UNK_POLICY;
+
+    if(entry->policy_refcnt != 0) {
+	krb5_db_free_policy(handle->context, entry);
+	return KADM5_POLICY_REF;
+    }
+    krb5_db_free_policy(handle->context, entry);
+    if ((ret = krb5_db_delete_policy(handle->context, name)))
+	return ret;
+    else
+	return KADM5_OK;
+}
+
+kadm5_ret_t
+kadm5_modify_policy(void *server_handle,
+			 kadm5_policy_ent_t entry, long mask)
+{
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    if (mask & KADM5_REF_COUNT)
+	return KADM5_BAD_MASK;
+    else
+	return kadm5_modify_policy_internal(server_handle, entry, mask);
+}
+
+kadm5_ret_t
+kadm5_modify_policy_internal(void *server_handle,
+				  kadm5_policy_ent_t entry, long mask)
+{
+    kadm5_server_handle_t handle = server_handle;
+    osa_policy_ent_t	p;
+    int			ret;
+    int                 cnt=1;
+
+    CHECK_HANDLE(server_handle);
+
+    if((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL))
+	return EINVAL;
+    if(strlen(entry->policy) == 0)
+	return KADM5_BAD_POLICY;
+    if((mask & KADM5_POLICY))
+	return KADM5_BAD_MASK;
+		
+    ret = krb5_db_get_policy(handle->context, entry->policy, &p, &cnt);
+    if( ret && (cnt==0) )
+	return KADM5_UNK_POLICY;
+
+    if ((mask & KADM5_PW_MAX_LIFE))
+	p->pw_max_life = entry->pw_max_life;
+    if ((mask & KADM5_PW_MIN_LIFE)) {
+	if(entry->pw_min_life > p->pw_max_life && p->pw_max_life != 0)	{
+	     krb5_db_free_policy(handle->context, p);
+	     return KADM5_BAD_MIN_PASS_LIFE;
+	}
+	p->pw_min_life = entry->pw_min_life;
+    }
+    if ((mask & KADM5_PW_MIN_LENGTH)) {
+	if(entry->pw_min_length < MIN_PW_LENGTH) {
+	      krb5_db_free_policy(handle->context, p);
+	      return KADM5_BAD_LENGTH;
+	 }
+	p->pw_min_length = entry->pw_min_length;
+    }
+    if ((mask & KADM5_PW_MIN_CLASSES)) {
+	if(entry->pw_min_classes > MAX_PW_CLASSES ||
+	   entry->pw_min_classes < MIN_PW_CLASSES) {
+	     krb5_db_free_policy(handle->context, p);
+	     return KADM5_BAD_CLASS;
+	}
+	p->pw_min_classes = entry->pw_min_classes;
+    }
+    if ((mask & KADM5_PW_HISTORY_NUM)) {
+	if(entry->pw_history_num < MIN_PW_HISTORY ||
+	   entry->pw_history_num > MAX_PW_HISTORY) {
+	     krb5_db_free_policy(handle->context, p);
+	     return KADM5_BAD_HISTORY;
+	}
+	p->pw_history_num = entry->pw_history_num;
+    }
+    if ((mask & KADM5_REF_COUNT))
+	p->policy_refcnt = entry->policy_refcnt;
+    ret = krb5_db_put_policy(handle->context, p);
+    krb5_db_free_policy(handle->context, p);
+    return ret;
+}
+
+kadm5_ret_t
+kadm5_get_policy(void *server_handle, kadm5_policy_t name,
+		 kadm5_policy_ent_t entry) 
+{
+    osa_policy_ent_t		t;
+    kadm5_policy_ent_rec	entry_local, **entry_orig, *new;
+    int				ret;
+    kadm5_server_handle_t handle = server_handle;
+    int                         cnt=1;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    /*
+     * In version 1, entry is a pointer to a kadm5_policy_ent_t that
+     * should be filled with allocated memory.
+     */
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 entry_orig = (kadm5_policy_ent_rec **) entry;
+	 *entry_orig = NULL;
+	 entry = &entry_local;
+    }
+    
+    if (name == (kadm5_policy_t) NULL)
+	return EINVAL;
+    if(strlen(name) == 0)
+	return KADM5_BAD_POLICY;
+    if((ret = krb5_db_get_policy(handle->context, name, &t, &cnt)))
+	return ret;
+
+    if( cnt != 1 )
+	return KADM5_UNK_POLICY;
+
+    if ((entry->policy = (char *) malloc(strlen(t->name) + 1)) == NULL) {
+	 krb5_db_free_policy(handle->context, t);
+	 return ENOMEM;
+    }
+    strcpy(entry->policy, t->name);
+    entry->pw_min_life = t->pw_min_life;
+    entry->pw_max_life = t->pw_max_life;
+    entry->pw_min_length = t->pw_min_length;
+    entry->pw_min_classes = t->pw_min_classes;
+    entry->pw_history_num = t->pw_history_num;
+    entry->policy_refcnt = t->policy_refcnt;
+    krb5_db_free_policy(handle->context, t);
+
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 new = (kadm5_policy_ent_t) malloc(sizeof(kadm5_policy_ent_rec));
+	 if (new == NULL) {
+	      free(entry->policy);
+	      krb5_db_free_policy(handle->context, t);
+	      return ENOMEM;
+	 }
+	 *new = *entry;
+	 *entry_orig = new;
+    }
+    
+    return KADM5_OK;
+}
diff --git a/mechglue/src/lib/kadm5/srv/svr_principal.c b/mechglue/src/lib/kadm5/srv/svr_principal.c
new file mode 100644
index 000000000..6cecbb5d2
--- /dev/null
+++ b/mechglue/src/lib/kadm5/srv/svr_principal.c
@@ -0,0 +1,2097 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include	<sys/types.h>
+#include	<sys/time.h>
+#include	<errno.h>
+#include	<kadm5/admin.h>
+#include	<krb5/kdb.h>
+#include	<stdio.h>
+#include	<string.h>
+#include	"server_internal.h"
+#include	<stdarg.h>
+#include	<stdlib.h>
+#ifdef USE_PASSWORD_SERVER
+#include	<sys/wait.h>
+#endif
+
+extern	krb5_principal	    master_princ;
+extern	krb5_principal	    hist_princ;
+extern	krb5_keyblock	    master_keyblock;
+extern	krb5_keyblock	    hist_key;
+extern	krb5_db_entry	    master_db;
+extern	krb5_db_entry	    hist_db;
+extern  krb5_kvno	    hist_kvno;
+
+static int decrypt_key_data(krb5_context context,
+			    int n_key_data, krb5_key_data *key_data,
+			    krb5_keyblock **keyblocks, int *n_keys);
+
+static krb5_error_code 
+kadm5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc)
+{
+    register krb5_principal tempprinc;
+    register int i, nelems;
+                                                                                                                            
+    tempprinc = (krb5_principal)krb5_db_alloc(context, NULL, sizeof(krb5_principal_data));
+                                                                                                                            
+    if (tempprinc == 0)
+        return ENOMEM;
+                                                                                                                            
+    memcpy(tempprinc, inprinc, sizeof(krb5_principal_data));
+                                                                                                                            
+    nelems = (int) krb5_princ_size(context, inprinc);
+    tempprinc->data = krb5_db_alloc(context, NULL, nelems * sizeof(krb5_data));
+                                                                                                                            
+    if (tempprinc->data == 0) {
+	krb5_db_free(context, (char *)tempprinc);
+        return ENOMEM;
+    }
+                                                                                                                            
+    for (i = 0; i < nelems; i++) {
+        unsigned int len = krb5_princ_component(context, inprinc, i)->length;
+        krb5_princ_component(context, tempprinc, i)->length = len;
+        if (((krb5_princ_component(context, tempprinc, i)->data =
+              krb5_db_alloc(context, NULL, len)) == 0) && len) {
+            while (--i >= 0)
+                krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
+            krb5_db_free (context, tempprinc->data);
+            krb5_db_free (context, tempprinc);
+            return ENOMEM;
+        }
+        if (len)
+            memcpy(krb5_princ_component(context, tempprinc, i)->data,
+                   krb5_princ_component(context, inprinc, i)->data, len);
+    }
+                                                                                                                            
+    tempprinc->realm.data =
+	krb5_db_alloc(context, NULL, tempprinc->realm.length = inprinc->realm.length);
+    if (!tempprinc->realm.data && tempprinc->realm.length) {
+            for (i = 0; i < nelems; i++)
+		krb5_db_free(context, krb5_princ_component(context, tempprinc, i)->data);
+            krb5_db_free(context, tempprinc->data);
+            krb5_db_free(context, tempprinc);
+            return ENOMEM;
+    }
+    if (tempprinc->realm.length)
+        memcpy(tempprinc->realm.data, inprinc->realm.data,
+               inprinc->realm.length);
+                                                                                                                            
+    *outprinc = tempprinc;
+    return 0;
+}
+                                                                                                                            
+static void
+kadm5_free_principal(krb5_context context, krb5_principal val)
+{
+    register krb5_int32 i;
+                                                                                                                            
+    if (!val)
+        return;
+                                                                                                                            
+    if (val->data) {
+        i = krb5_princ_size(context, val);
+        while(--i >= 0)
+            krb5_db_free(context, krb5_princ_component(context, val, i)->data);
+        krb5_db_free(context, val->data);
+    }
+    if (val->realm.data)
+        krb5_db_free(context, val->realm.data);
+    krb5_db_free(context, val);
+}
+
+/*
+ * XXX Functions that ought to be in libkrb5.a, but aren't.
+ */
+kadm5_ret_t krb5_copy_key_data_contents(context, from, to)
+   krb5_context context;
+   krb5_key_data *from, *to;
+{
+     int i, idx;
+     
+     *to = *from;
+
+     idx = (from->key_data_ver == 1 ? 1 : 2);
+
+     for (i = 0; i < idx; i++) {
+       if ( from->key_data_length[i] ) {
+	 to->key_data_contents[i] = malloc(from->key_data_length[i]);
+	 if (to->key_data_contents[i] == NULL) {
+	   for (i = 0; i < idx; i++) {
+	     if (to->key_data_contents[i]) {
+	       memset(to->key_data_contents[i], 0,
+		      to->key_data_length[i]);
+	       free(to->key_data_contents[i]);
+	     }
+	   }
+	   return ENOMEM;
+	 }
+	 memcpy(to->key_data_contents[i], from->key_data_contents[i],
+		from->key_data_length[i]);
+       }
+     }
+     return 0;
+}
+
+static krb5_tl_data *dup_tl_data(krb5_tl_data *tl)
+{
+     krb5_tl_data *n;
+
+     n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data));
+     if (n == NULL)
+	  return NULL;
+     n->tl_data_contents = malloc(tl->tl_data_length);
+     if (n->tl_data_contents == NULL) {
+	  free(n);
+	  return NULL;
+     }
+     memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length);
+     n->tl_data_type = tl->tl_data_type;
+     n->tl_data_length = tl->tl_data_length;
+     n->tl_data_next = NULL;
+     return n;
+}
+
+/* This is in lib/kdb/kdb_cpw.c, but is static */
+static void cleanup_key_data(context, count, data)
+   krb5_context	  context;
+   int			  count;
+   krb5_key_data	* data;
+{
+     int i, j;
+     
+     for (i = 0; i < count; i++)
+	  for (j = 0; j < data[i].key_data_ver; j++)
+	       if (data[i].key_data_length[j])
+		   krb5_db_free(context, data[i].key_data_contents[j]);
+     krb5_db_free(context, data);
+}
+
+kadm5_ret_t
+kadm5_create_principal(void *server_handle,
+			    kadm5_principal_ent_t entry, long mask,
+			    char *password)
+{
+    return
+	kadm5_create_principal_3(server_handle, entry, mask,
+				 0, NULL, password);
+}
+kadm5_ret_t
+kadm5_create_principal_3(void *server_handle,
+			 kadm5_principal_ent_t entry, long mask,
+			 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
+			 char *password)
+{
+    krb5_db_entry		kdb;
+    osa_princ_ent_rec		adb;
+    kadm5_policy_ent_rec	polent;
+    krb5_int32			now;
+    krb5_tl_data		*tl_data_orig, *tl_data_tail;
+    unsigned int		ret;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    /*
+     * Argument sanity checking, and opening up the DB
+     */
+    if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) ||
+       (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) ||
+       (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) ||
+       (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) ||
+       (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) ||
+       (mask & KADM5_FAIL_AUTH_COUNT))
+	return KADM5_BAD_MASK;
+    if((mask & ~ALL_PRINC_MASK))
+	return KADM5_BAD_MASK;
+    if (entry == (kadm5_principal_ent_t) NULL || password == NULL)
+	return EINVAL;
+
+    /*
+     * Check to see if the principal exists
+     */
+    ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
+
+    switch(ret) {
+    case KADM5_UNK_PRINC:
+	break;
+    case 0:
+	kdb_free_entry(handle, &kdb, &adb);
+	return KADM5_DUP;
+    default:
+	return ret;
+    }
+
+    memset(&kdb, 0, sizeof(krb5_db_entry));
+    memset(&adb, 0, sizeof(osa_princ_ent_rec));
+
+    /*
+     * If a policy was specified, load it.
+     * If we can not find the one specified return an error
+     */
+    if ((mask & KADM5_POLICY)) {
+	 if ((ret = kadm5_get_policy(handle->lhandle, entry->policy,
+				     &polent)) != KADM5_OK) {
+	    if(ret == EINVAL) 
+		return KADM5_BAD_POLICY;
+	    else
+		return ret;
+	}
+    }
+    if ((ret = passwd_check(handle, password, (mask & KADM5_POLICY),
+			    &polent, entry->principal))) {
+	if (mask & KADM5_POLICY)
+	     (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+	return ret;
+    }
+    /*
+     * Start populating the various DB fields, using the
+     * "defaults" for fields that were not specified by the
+     * mask.
+     */
+    if ((ret = krb5_timeofday(handle->context, &now))) {
+	 if (mask & KADM5_POLICY)
+	      (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+	 return ret;
+    }
+
+    kdb.magic = KRB5_KDB_MAGIC_NUMBER;
+    kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */
+
+    if ((mask & KADM5_ATTRIBUTES)) 
+	kdb.attributes = entry->attributes;
+    else
+       kdb.attributes = handle->params.flags;
+
+    if ((mask & KADM5_MAX_LIFE))
+	kdb.max_life = entry->max_life; 
+    else 
+	kdb.max_life = handle->params.max_life;
+
+    if (mask & KADM5_MAX_RLIFE)
+	 kdb.max_renewable_life = entry->max_renewable_life;
+    else
+	 kdb.max_renewable_life = handle->params.max_rlife;
+
+    if ((mask & KADM5_PRINC_EXPIRE_TIME))
+	kdb.expiration = entry->princ_expire_time;
+    else
+	kdb.expiration = handle->params.expiration;
+
+    kdb.pw_expiration = 0;
+    if ((mask & KADM5_POLICY)) {
+	if(polent.pw_max_life)
+	    kdb.pw_expiration = now + polent.pw_max_life;
+	else
+	    kdb.pw_expiration = 0;
+    }
+    if ((mask & KADM5_PW_EXPIRATION))
+	 kdb.pw_expiration = entry->pw_expiration;
+    
+    kdb.last_success = 0;
+    kdb.last_failed = 0;
+    kdb.fail_auth_count = 0;
+
+    /* this is kind of gross, but in order to free the tl data, I need
+       to free the entire kdb entry, and that will try to free the
+       principal. */
+
+    if ((ret = kadm5_copy_principal(handle->context,
+				    entry->principal, &(kdb.princ)))) {
+	if (mask & KADM5_POLICY)
+	     (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+	return(ret);
+    }
+
+    if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now))) {
+         krb5_db_free_principal(handle->context, &kdb, 1);
+	 if (mask & KADM5_POLICY)
+	     (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+	 return(ret);
+    }
+
+    if (mask & KADM5_TL_DATA) {
+	/* splice entry->tl_data onto the front of kdb.tl_data */
+	tl_data_orig = kdb.tl_data;
+	for (tl_data_tail = entry->tl_data; tl_data_tail;
+	     tl_data_tail = tl_data_tail->tl_data_next)
+	{
+	    ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl_data_tail);
+	    if( ret )
+	    {
+		krb5_db_free_principal(handle->context, &kdb, 1);
+		if (mask & KADM5_POLICY)
+		    (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+		return ret;
+	    }
+	}
+    }
+
+    /* initialize the keys */
+
+    if ((ret = krb5_dbe_cpw(handle->context, &master_keyblock,
+			    n_ks_tuple?ks_tuple:handle->params.keysalts,
+			    n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+			    password,
+			    (mask & KADM5_KVNO)?entry->kvno:1,
+			    FALSE, &kdb))) {
+	krb5_db_free_principal(handle->context, &kdb, 1);
+	if (mask & KADM5_POLICY)
+	     (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+	return(ret);
+    }
+
+    /* populate the admin-server-specific fields.  In the OV server,
+       this used to be in a separate database.  Since there's already
+       marshalling code for the admin fields, to keep things simple,
+       I'm going to keep it, and make all the admin stuff occupy a
+       single tl_data record, */
+
+    adb.admin_history_kvno = hist_kvno;
+    if ((mask & KADM5_POLICY)) {
+	adb.aux_attributes = KADM5_POLICY;
+
+	/* this does *not* need to be strdup'ed, because adb is xdr */
+	/* encoded in osa_adb_create_princ, and not ever freed */
+
+	adb.policy = entry->policy;
+    }
+
+    /* increment the policy ref count, if any */
+
+    if ((mask & KADM5_POLICY)) {
+	polent.policy_refcnt++;
+	if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
+						    KADM5_REF_COUNT))
+	    != KADM5_OK) {
+	    krb5_db_free_principal(handle->context, &kdb, 1);
+	    if (mask & KADM5_POLICY)
+		 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+	    return(ret);
+	}
+    }
+
+    /* store the new db entry */
+    ret = kdb_put_entry(handle, &kdb, &adb);
+
+    krb5_db_free_principal(handle->context, &kdb, 1);
+
+    if (ret) {
+	if ((mask & KADM5_POLICY)) {
+	    /* decrement the policy ref count */
+
+	    polent.policy_refcnt--;
+	    /*
+	     * if this fails, there's nothing we can do anyway.  the
+	     * policy refcount wil be too high.
+	     */
+	    (void) kadm5_modify_policy_internal(handle->lhandle, &polent,
+						     KADM5_REF_COUNT);
+	}
+
+	if (mask & KADM5_POLICY)
+	     (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+	return(ret);
+    }
+
+    if (mask & KADM5_POLICY)
+	 (void) kadm5_free_policy_ent(handle->lhandle, &polent);
+
+    return KADM5_OK;
+}
+
+	
+kadm5_ret_t
+kadm5_delete_principal(void *server_handle, krb5_principal principal)
+{
+    unsigned int		ret;
+    kadm5_policy_ent_rec	polent;
+    krb5_db_entry		kdb;
+    osa_princ_ent_rec		adb;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    if (principal == NULL)
+	return EINVAL;
+
+    if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+	return(ret);
+
+    if ((adb.aux_attributes & KADM5_POLICY)) {
+	if ((ret = kadm5_get_policy(handle->lhandle,
+				    adb.policy, &polent))
+	    == KADM5_OK) {
+	    polent.policy_refcnt--;
+	    if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent,
+							 KADM5_REF_COUNT))
+		!= KADM5_OK) {
+		(void) kadm5_free_policy_ent(handle->lhandle, &polent);
+		kdb_free_entry(handle, &kdb, &adb);
+		return(ret);
+	    }
+	}
+	if ((ret = kadm5_free_policy_ent(handle->lhandle, &polent))) {
+	     kdb_free_entry(handle, &kdb, &adb);
+	     return ret;
+	}
+    }
+
+    ret = kdb_delete_entry(handle, principal);
+
+    kdb_free_entry(handle, &kdb, &adb);
+
+    return ret;
+}
+
+kadm5_ret_t
+kadm5_modify_principal(void *server_handle,
+			    kadm5_principal_ent_t entry, long mask)
+{
+    int			    ret, ret2, i;
+    kadm5_policy_ent_rec    npol, opol;
+    int			    have_npol = 0, have_opol = 0;
+    krb5_db_entry	    kdb;
+    krb5_tl_data	    *tl_data_orig;
+    osa_princ_ent_rec	    adb;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
+       (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
+       (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
+       (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
+       (mask & KADM5_LAST_FAILED))
+	return KADM5_BAD_MASK;
+    if((mask & ~ALL_PRINC_MASK))
+	return KADM5_BAD_MASK;
+    if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR))
+	return KADM5_BAD_MASK;
+    if(entry == (kadm5_principal_ent_t) NULL)
+	return EINVAL;
+    if (mask & KADM5_TL_DATA) {
+	 tl_data_orig = entry->tl_data;
+	 while (tl_data_orig) {
+	      if (tl_data_orig->tl_data_type < 256)
+		   return KADM5_BAD_TL_TYPE;
+	      tl_data_orig = tl_data_orig->tl_data_next;
+	 }
+    }
+
+    ret = kdb_get_entry(handle, entry->principal, &kdb, &adb);
+    if (ret)
+	return(ret);
+
+    /*
+     * This is pretty much the same as create ...
+     */
+
+    if ((mask & KADM5_POLICY)) {
+	 /* get the new policy */
+	 ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol);
+	 if (ret) {
+	      switch (ret) {
+	      case EINVAL:
+		   ret = KADM5_BAD_POLICY;
+		   break;
+	      case KADM5_UNK_POLICY:
+	      case KADM5_BAD_POLICY:
+		   ret =  KADM5_UNK_POLICY;
+		   break;
+	      }
+	      goto done;
+	 }
+	 have_npol = 1;
+
+	 /* if we already have a policy, get it to decrement the refcnt */
+	 if(adb.aux_attributes & KADM5_POLICY) {
+	      /* ... but not if the old and new are the same */
+	      if(strcmp(adb.policy, entry->policy)) {
+		   ret = kadm5_get_policy(handle->lhandle,
+					  adb.policy, &opol);
+		   switch(ret) {
+		   case EINVAL:
+		   case KADM5_BAD_POLICY:
+		   case KADM5_UNK_POLICY:
+			break;
+		   case KADM5_OK:
+			have_opol = 1;
+			opol.policy_refcnt--;
+			break;
+		   default:
+			goto done;
+			break;
+		   }
+		   npol.policy_refcnt++;
+	      }
+	 } else npol.policy_refcnt++;
+
+	 /* set us up to use the new policy */
+	 adb.aux_attributes |= KADM5_POLICY;
+	 if (adb.policy)
+	      free(adb.policy);
+	 adb.policy = strdup(entry->policy);
+
+	 /* set pw_max_life based on new policy */
+	 if (npol.pw_max_life) {
+	     ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
+						   &(kdb.pw_expiration));
+	     if (ret)
+		 goto done;
+	     kdb.pw_expiration += npol.pw_max_life;
+	 } else {
+	     kdb.pw_expiration = 0;
+	 }
+    }
+
+    if ((mask & KADM5_POLICY_CLR) &&
+	(adb.aux_attributes & KADM5_POLICY)) {
+	 ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol);
+	 switch(ret) {
+	 case EINVAL:
+	 case KADM5_BAD_POLICY:
+	 case KADM5_UNK_POLICY:
+	      ret = KADM5_BAD_DB;
+	      goto done;
+	      break;
+	 case KADM5_OK:
+	      have_opol = 1;
+	      if (adb.policy)
+		   free(adb.policy);
+	      adb.policy = NULL;
+	      adb.aux_attributes &= ~KADM5_POLICY;
+	      kdb.pw_expiration = 0;
+	      opol.policy_refcnt--;
+	      break;
+	 default:
+	      goto done;
+	      break;
+	 }
+    }
+
+    if (((mask & KADM5_POLICY) || (mask & KADM5_POLICY_CLR)) &&
+	(((have_opol) &&
+	  (ret =
+	   kadm5_modify_policy_internal(handle->lhandle, &opol,
+					     KADM5_REF_COUNT))) ||
+	 ((have_npol) &&
+	  (ret =
+	   kadm5_modify_policy_internal(handle->lhandle, &npol,
+					     KADM5_REF_COUNT)))))
+	goto done;
+
+    if ((mask & KADM5_ATTRIBUTES)) 
+	kdb.attributes = entry->attributes;
+    if ((mask & KADM5_MAX_LIFE))
+	kdb.max_life = entry->max_life;
+    if ((mask & KADM5_PRINC_EXPIRE_TIME))
+	kdb.expiration = entry->princ_expire_time;
+    if (mask & KADM5_PW_EXPIRATION)
+	 kdb.pw_expiration = entry->pw_expiration;
+    if (mask & KADM5_MAX_RLIFE)
+	 kdb.max_renewable_life = entry->max_renewable_life;
+    if (mask & KADM5_FAIL_AUTH_COUNT)
+	 kdb.fail_auth_count = entry->fail_auth_count;
+    
+    if((mask & KADM5_KVNO)) {
+	 for (i = 0; i < kdb.n_key_data; i++)
+	      kdb.key_data[i].key_data_kvno = entry->kvno;
+    }
+
+    if (mask & KADM5_TL_DATA) {
+	 krb5_tl_data *tl;
+
+	 /* may have to change the version number of the API. Updates the list with the given tl_data rather than over-writting */
+
+	 for (tl = entry->tl_data; tl;
+	      tl = tl->tl_data_next)
+	 {
+	     ret = krb5_dbe_update_tl_data(handle->context, &kdb, tl);
+	     if( ret )
+	     {
+		 goto done;
+	     }
+	 }
+    }
+
+    ret = kdb_put_entry(handle, &kdb, &adb);
+    if (ret) goto done;
+
+    ret = KADM5_OK;
+done:
+    if (have_opol) {
+	 ret2 = kadm5_free_policy_ent(handle->lhandle, &opol);
+	 ret = ret ? ret : ret2;
+    }
+    if (have_npol) {
+	 ret2 = kadm5_free_policy_ent(handle->lhandle, &npol);
+	 ret = ret ? ret : ret2;
+    }
+    kdb_free_entry(handle, &kdb, &adb);
+    return ret;
+}
+    
+kadm5_ret_t
+kadm5_rename_principal(void *server_handle,
+			    krb5_principal source, krb5_principal target)
+{
+    krb5_db_entry	kdb;
+    osa_princ_ent_rec	adb;
+    int			ret, i;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    if (source == NULL || target == NULL)
+	return EINVAL;
+
+    if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) {
+	kdb_free_entry(handle, &kdb, &adb);
+	return(KADM5_DUP);
+    }
+
+    if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
+	return ret;
+
+    /* this is kinda gross, but unavoidable */
+
+    for (i=0; i<kdb.n_key_data; i++) {
+	if ((kdb.key_data[i].key_data_ver == 1) ||
+	    (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
+	    ret = KADM5_NO_RENAME_SALT;
+	    goto done;
+	}
+    }
+
+    kadm5_free_principal(handle->context, kdb.princ);
+    ret = kadm5_copy_principal(handle->context, target, &kdb.princ);
+    if (ret) {
+	kdb.princ = NULL; /* so freeing the dbe doesn't lose */
+	goto done;
+    }
+
+    if ((ret = kdb_put_entry(handle, &kdb, &adb)))
+	goto done;
+
+    ret = kdb_delete_entry(handle, source);
+
+done:
+    kdb_free_entry(handle, &kdb, &adb);
+    return ret;
+}
+
+kadm5_ret_t
+kadm5_get_principal(void *server_handle, krb5_principal principal,
+		    kadm5_principal_ent_t entry,
+		    long in_mask)
+{
+    krb5_db_entry		kdb;
+    osa_princ_ent_rec		adb;
+    krb5_error_code		ret = 0;
+    long			mask;
+    int i;
+    kadm5_server_handle_t handle = server_handle;
+    kadm5_principal_ent_rec	entry_local, *entry_orig;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    /*
+     * In version 1, all the defined fields are always returned.
+     * entry is a pointer to a kadm5_principal_ent_t_v1 that should be
+     * filled with allocated memory.
+     */
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 mask = KADM5_PRINCIPAL_NORMAL_MASK;
+	 entry_orig = entry;
+	 entry = &entry_local;
+    } else {
+	 mask = in_mask;
+    }
+
+    memset((char *) entry, 0, sizeof(*entry));
+
+    if (principal == NULL)
+	return EINVAL;
+
+    if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+	return ret;
+
+    if ((mask & KADM5_POLICY) &&
+	adb.policy && (adb.aux_attributes & KADM5_POLICY)) {
+	if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) {
+	    ret = ENOMEM;
+	    goto done;
+	}
+	strcpy(entry->policy, adb.policy);
+    }
+
+    if (mask & KADM5_AUX_ATTRIBUTES)
+	 entry->aux_attributes = adb.aux_attributes;
+
+    if ((mask & KADM5_PRINCIPAL) &&
+	(ret = krb5_copy_principal(handle->context, principal,
+				   &entry->principal))) { 
+	goto done;
+    }
+
+    if (mask & KADM5_PRINC_EXPIRE_TIME)
+	 entry->princ_expire_time = kdb.expiration;
+
+    if ((mask & KADM5_LAST_PWD_CHANGE) &&
+	(ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb,
+					       &(entry->last_pwd_change)))) {
+	goto done;
+    }
+
+    if (mask & KADM5_PW_EXPIRATION)
+	 entry->pw_expiration = kdb.pw_expiration;
+    if (mask & KADM5_MAX_LIFE)
+	 entry->max_life = kdb.max_life;
+
+    /* this is a little non-sensical because the function returns two */
+    /* values that must be checked separately against the mask */
+    if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) {
+	ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb,
+					     &(entry->mod_date), 
+					     &(entry->mod_name));
+	if (ret) {
+	    goto done;
+	}
+	
+	if (! (mask & KADM5_MOD_TIME))
+	    entry->mod_date = 0;
+	if (! (mask & KADM5_MOD_NAME)) {
+	    krb5_free_principal(handle->context, entry->principal);
+	    entry->principal = NULL;
+	}
+    }
+
+    if (mask & KADM5_ATTRIBUTES)
+	 entry->attributes = kdb.attributes;
+
+    if (mask & KADM5_KVNO)
+	 for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++)
+	      if (kdb.key_data[i].key_data_kvno > entry->kvno)
+		   entry->kvno = kdb.key_data[i].key_data_kvno;
+    
+    if (handle->api_version == KADM5_API_VERSION_2)
+	 entry->mkvno = 0;
+    else {
+	 /* XXX I'll be damned if I know how to deal with this one --marc */
+	 entry->mkvno = 1;
+    }
+
+    /*
+     * The new fields that only exist in version 2 start here
+     */
+    if (handle->api_version == KADM5_API_VERSION_2) {
+	 if (mask & KADM5_MAX_RLIFE)
+	      entry->max_renewable_life = kdb.max_renewable_life;
+	 if (mask & KADM5_LAST_SUCCESS)
+	      entry->last_success = kdb.last_success;
+	 if (mask & KADM5_LAST_FAILED)
+	      entry->last_failed = kdb.last_failed;
+	 if (mask & KADM5_FAIL_AUTH_COUNT)
+	      entry->fail_auth_count = kdb.fail_auth_count;
+	 if (mask & KADM5_TL_DATA) {
+	      krb5_tl_data *tl, *tl2;
+
+	      entry->tl_data = NULL;
+	      
+	      tl = kdb.tl_data;
+	      while (tl) {
+		   if (tl->tl_data_type > 255) {
+			if ((tl2 = dup_tl_data(tl)) == NULL) {
+			     ret = ENOMEM;
+			     goto done;
+			}
+			tl2->tl_data_next = entry->tl_data;
+			entry->tl_data = tl2;
+			entry->n_tl_data++;
+		   }
+			
+		   tl = tl->tl_data_next;
+	      }
+	 }
+	 if (mask & KADM5_KEY_DATA) {
+	      entry->n_key_data = kdb.n_key_data;
+	      if(entry->n_key_data) {
+		      entry->key_data = (krb5_key_data *)
+			      malloc(entry->n_key_data*sizeof(krb5_key_data));
+		      if (entry->key_data == NULL) {
+			      ret = ENOMEM;
+			      goto done;
+		      }
+	      } else 
+		      entry->key_data = NULL;
+
+	      for (i = 0; i < entry->n_key_data; i++)
+		  ret = krb5_copy_key_data_contents(handle->context,
+						    &kdb.key_data[i],
+						    &entry->key_data[i]);
+		   if (ret)
+			goto done;
+	 }
+    }
+
+    /*
+     * If KADM5_API_VERSION_1, we return an allocated structure, and
+     * we need to convert the new structure back into the format the
+     * caller is expecting.
+     */
+    if (handle->api_version == KADM5_API_VERSION_1) {
+	 kadm5_principal_ent_t_v1 newv1;
+
+	 newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1)));
+	 if (newv1 == NULL) {
+	      ret = ENOMEM;
+	      goto done;
+	 }
+	 
+	 newv1->principal = entry->principal;
+	 newv1->princ_expire_time = entry->princ_expire_time;
+	 newv1->last_pwd_change = entry->last_pwd_change;
+	 newv1->pw_expiration = entry->pw_expiration;
+	 newv1->max_life = entry->max_life;
+	 newv1->mod_name = entry->mod_name;
+	 newv1->mod_date = entry->mod_date;
+	 newv1->attributes = entry->attributes;
+	 newv1->kvno = entry->kvno;
+	 newv1->mkvno = entry->mkvno;
+	 newv1->policy = entry->policy;
+	 newv1->aux_attributes = entry->aux_attributes;
+
+	 *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1;
+    }
+
+    ret = KADM5_OK;
+
+done:
+    if (ret && entry->principal)
+	 krb5_free_principal(handle->context, entry->principal);
+    kdb_free_entry(handle, &kdb, &adb);
+
+    return ret;
+}
+
+/*
+ * Function: check_pw_reuse
+ *
+ * Purpose: Check if a key appears in a list of keys, in order to
+ * enforce password history.
+ *
+ * Arguments:
+ *
+ *	context			(r) the krb5 context
+ *	hist_keyblock		(r) the key that hist_key_data is
+ *				encrypted in
+ *	n_new_key_data		(r) length of new_key_data
+ *	new_key_data		(r) keys to check against
+ *				pw_hist_data, encrypted in hist_keyblock
+ *	n_pw_hist_data		(r) length of pw_hist_data
+ *	pw_hist_data		(r) passwords to check new_key_data against
+ *
+ * Effects:
+ * For each new_key in new_key_data:
+ * 	decrypt new_key with the master_keyblock
+ * 	for each password in pw_hist_data:
+ *		for each hist_key in password:
+ *			decrypt hist_key with hist_keyblock
+ *			compare the new_key and hist_key
+ *
+ * Returns krb5 errors, KADM5_PASS_RESUSE if a key in
+ * new_key_data is the same as a key in pw_hist_data, or 0.
+ */
+static kadm5_ret_t
+check_pw_reuse(krb5_context context,
+	       krb5_keyblock *hist_keyblock,
+	       int n_new_key_data, krb5_key_data *new_key_data,
+	       unsigned int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data)
+{
+    int x, y, z;
+    krb5_keyblock newkey, histkey;
+    krb5_error_code ret;
+
+    for (x = 0; x < n_new_key_data; x++) {
+	ret = krb5_dbekd_decrypt_key_data(context,
+					  &master_keyblock,
+					  &(new_key_data[x]),
+					  &newkey, NULL);
+	if (ret)
+	    return(ret);
+	for (y = 0; y < n_pw_hist_data; y++) {
+	     for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
+		 ret = krb5_dbekd_decrypt_key_data(context,
+						   hist_keyblock,
+						   &pw_hist_data[y].key_data[z],
+						   &histkey, NULL);
+		 if (ret)
+		     return(ret);		
+		 
+		 if ((newkey.length == histkey.length) &&
+		     (newkey.enctype == histkey.enctype) &&
+		     (memcmp(newkey.contents, histkey.contents,
+			     histkey.length) == 0)) {
+		     krb5_free_keyblock_contents(context, &histkey);
+		     krb5_free_keyblock_contents(context, &newkey);
+		     
+		     return(KADM5_PASS_REUSE);
+		 }
+		 krb5_free_keyblock_contents(context, &histkey);
+	     }
+	}
+	krb5_free_keyblock_contents(context, &newkey);
+    }
+
+    return(0);
+}
+
+/*
+ * Function: create_history_entry
+ *
+ * Purpose: Creates a password history entry from an array of
+ * key_data.
+ *
+ * Arguments:
+ *
+ *	context		(r) krb5_context to use
+ *	n_key_data	(r) number of elements in key_data
+ *	key_data	(r) keys to add to the history entry
+ *	hist		(w) history entry to fill in
+ *
+ * Effects:
+ *
+ * hist->key_data is allocated to store n_key_data key_datas.  Each
+ * element of key_data is decrypted with master_keyblock, re-encrypted
+ * in hist_key, and added to hist->key_data.  hist->n_key_data is
+ * set to n_key_data.
+ */
+static
+int create_history_entry(krb5_context context, int n_key_data,
+			 krb5_key_data *key_data, osa_pw_hist_ent *hist)
+{
+     int i, ret;
+     krb5_keyblock key;
+     krb5_keysalt salt;
+     
+     hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data));
+     if (hist->key_data == NULL)
+	  return ENOMEM;
+     memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data));
+
+     for (i = 0; i < n_key_data; i++) {
+	 ret = krb5_dbekd_decrypt_key_data(context,
+					   &master_keyblock,
+					   &key_data[i],
+					   &key, &salt);
+	 if (ret)
+	     return ret;
+
+	 ret = krb5_dbekd_encrypt_key_data(context, &hist_key,
+					   &key, &salt,
+					   key_data[i].key_data_kvno,
+					   &hist->key_data[i]);
+	 if (ret)
+	     return ret;
+	 
+	 krb5_free_keyblock_contents(context, &key);
+	 /* krb5_free_keysalt(context, &salt); */
+     }
+
+     hist->n_key_data = n_key_data;
+     return 0;
+}
+
+static
+void free_history_entry(krb5_context context, osa_pw_hist_ent *hist)
+{
+     int i;
+
+     for (i = 0; i < hist->n_key_data; i++)
+	  krb5_free_key_data_contents(context, &hist->key_data[i]);
+     free(hist->key_data);
+}
+
+/*
+ * Function: add_to_history
+ *
+ * Purpose: Adds a password to a principal's password history.
+ *
+ * Arguments:
+ *
+ *	context		(r) krb5_context to use
+ *	adb		(r/w) admin principal entry to add keys to
+ *	pol		(r) adb's policy
+ *	pw		(r) keys for the password to add to adb's key history
+ *
+ * Effects:
+ *
+ * add_to_history adds a single password to adb's password history.
+ * pw contains n_key_data keys in its key_data, in storage should be
+ * allocated but not freed by the caller (XXX blech!).
+ *
+ * This function maintains adb->old_keys as a circular queue.  It
+ * starts empty, and grows each time this function is called until it
+ * is pol->pw_history_num items long.  adb->old_key_len holds the
+ * number of allocated entries in the array, and must therefore be [0,
+ * pol->pw_history_num).  adb->old_key_next is the index into the
+ * array where the next element should be written, and must be [0,
+ * adb->old_key_len).
+ */
+static kadm5_ret_t add_to_history(krb5_context context,
+				  osa_princ_ent_t adb,
+				  kadm5_policy_ent_t pol,
+				  osa_pw_hist_ent *pw)
+{
+     osa_pw_hist_ent *histp;
+     uint32_t nhist;
+     unsigned int i, knext, nkeys;
+
+     nhist = pol->pw_history_num;
+     /* A history of 1 means just check the current password */
+     if (nhist <= 1)
+	  return 0;
+
+     nkeys = adb->old_key_len;
+     knext = adb->old_key_next;
+     /* resize the adb->old_keys array if necessary */
+     if (nkeys + 1 < nhist) {
+	  if (adb->old_keys == NULL) {
+	       adb->old_keys = (osa_pw_hist_ent *)
+		    malloc((nkeys + 1) * sizeof (osa_pw_hist_ent));
+	  } else {
+	       adb->old_keys = (osa_pw_hist_ent *)
+		    realloc(adb->old_keys,
+			    (nkeys + 1) * sizeof (osa_pw_hist_ent));
+	  }
+	  if (adb->old_keys == NULL)
+	       return(ENOMEM);
+	  
+	  memset(&adb->old_keys[nkeys], 0, sizeof(osa_pw_hist_ent));
+     	  nkeys = ++adb->old_key_len;
+	  /*
+	   * To avoid losing old keys, shift forward each entry after
+	   * knext.
+	   */
+	  for (i = nkeys - 1; i > knext; i--) {
+	      adb->old_keys[i] = adb->old_keys[i - 1];
+	  }
+	  memset(&adb->old_keys[knext], 0, sizeof(osa_pw_hist_ent));
+     } else if (nkeys + 1 > nhist) {
+	 /*
+	  * The policy must have changed!  Shrink the array.
+	  * Can't simply realloc() down, since it might be wrapped.
+	  * To understand the arithmetic below, note that we are
+	  * copying into new positions 0 .. N-1 from old positions
+	  * old_key_next-N .. old_key_next-1, modulo old_key_len,
+	  * where N = pw_history_num - 1 is the length of the
+	  * shortened list.        Matt Crawford, FNAL
+	  */
+	 /*
+	  * M = adb->old_key_len, N = pol->pw_history_num - 1
+	  *
+	  * tmp[0] .. tmp[N-1] = old[(knext-N)%M] .. old[(knext-1)%M]
+	  */
+	 int j;
+	 osa_pw_hist_t tmp;
+
+	 tmp = (osa_pw_hist_ent *)
+	     malloc((nhist - 1) * sizeof (osa_pw_hist_ent));
+	 if (tmp == NULL)
+	     return ENOMEM;
+	 for (i = 0; i < nhist - 1; i++) {
+	     /*
+	      * Add nkeys once before taking remainder to avoid
+	      * negative values.
+	      */
+	     j = (i + nkeys + knext - (nhist - 1)) % nkeys;
+	     tmp[i] = adb->old_keys[j];
+	 }
+	 /* Now free the ones we don't keep (the oldest ones) */
+	 for (i = 0; i < nkeys - (nhist - 1); i++) {
+	     j = (i + nkeys + knext) % nkeys;
+	     histp = &adb->old_keys[j];
+	     for (j = 0; j < histp->n_key_data; j++) {
+		 krb5_free_key_data_contents(context, &histp->key_data[j]);
+	     }
+	     free(histp->key_data);
+	 }
+	 free((void *)adb->old_keys);
+	 adb->old_keys = tmp;
+	 nkeys = adb->old_key_len = nhist - 1;
+	 knext = adb->old_key_next = 0;
+     }
+
+     /*
+      * If nhist decreased since the last password change, and nkeys+1
+      * is less than the previous nhist, it is possible for knext to
+      * index into unallocated space.  This condition would not be
+      * caught by the resizing code above.
+      */
+     if (knext + 1 > nkeys)
+	 knext = adb->old_key_next = 0;
+     /* free the old pw history entry if it contains data */
+     histp = &adb->old_keys[knext];
+     for (i = 0; i < histp->n_key_data; i++)
+	  krb5_free_key_data_contents(context, &histp->key_data[i]);
+     free(histp->key_data);
+
+     /* store the new entry */
+     adb->old_keys[knext] = *pw;
+
+     /* update the next pointer */
+     if (++adb->old_key_next == nhist - 1)
+	 adb->old_key_next = 0;
+
+     return(0);
+}
+
+#ifdef USE_PASSWORD_SERVER
+
+/* FIXME: don't use global variable for this */
+krb5_boolean use_password_server = 0;
+
+static krb5_boolean
+kadm5_use_password_server (void)
+{
+    return use_password_server;
+}
+
+void
+kadm5_set_use_password_server (void)
+{
+    use_password_server = 1;
+}
+
+/*
+ * kadm5_launch_task () runs a program (task_path) to synchronize the 
+ * Apple password server with the Kerberos database.  Password server
+ * programs can receive arguments on the command line (task_argv)
+ * and a block of data via stdin (data_buffer).
+ *
+ * Because a failure to communicate with the tool results in the
+ * password server falling out of sync with the database,
+ * kadm5_launch_task() always fails if it can't talk to the tool.
+ */
+
+static kadm5_ret_t
+kadm5_launch_task (krb5_context context,
+                   const char *task_path, char * const task_argv[],
+                   const char *data_buffer) 
+{
+    kadm5_ret_t ret = 0;
+    int data_pipe[2];
+    
+    if (data_buffer != NULL) {
+        ret = pipe (data_pipe);
+        if (ret) { ret = errno; }
+    }
+
+    if (!ret) {
+        pid_t pid = fork ();
+        if (pid == -1) {
+            ret = errno;
+        } else if (pid == 0) {
+            /* The child: */
+            
+            if (data_buffer != NULL) {
+                if (dup2 (data_pipe[0], STDIN_FILENO) == -1) {
+                    _exit (1);
+                }
+            } else {
+                close (data_pipe[0]);
+            }
+
+            close (data_pipe[1]);
+            
+            execv (task_path, task_argv);
+            
+            _exit (1); /* Fail if execv fails */
+        } else {
+            /* The parent: */
+            int status;
+                       
+            if (data_buffer != NULL) {
+                /* Write out the buffer to the child */
+                if (krb5_net_write (context, data_pipe[1],
+                                    data_buffer, strlen (data_buffer)) < 0) {
+                    /* kill the child to make sure waitpid() won't hang later */
+                    ret = errno;
+                    kill (pid, SIGKILL);
+                }
+            }
+
+            close (data_buffer[0]);
+            close (data_buffer[1]);
+
+            waitpid (pid, &status, 0);
+
+            if (!ret) {
+                if (WIFEXITED (status)) {
+                    /* child read password and exited.  Check the return value. */
+                    if ((WEXITSTATUS (status) != 0) && (WEXITSTATUS (status) != 252)) {
+                       ret = KRB5KDC_ERR_POLICY; /* password change rejected */
+                    }
+                } else {
+                    /* child read password but crashed or was killed */
+                    ret = KRB5KRB_ERR_GENERIC; /* FIXME: better error */
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+#endif
+
+kadm5_ret_t
+kadm5_chpass_principal(void *server_handle,
+			    krb5_principal principal, char *password)
+{
+    return
+	kadm5_chpass_principal_3(server_handle, principal, FALSE,
+				 0, NULL, password);
+}
+
+kadm5_ret_t
+kadm5_chpass_principal_3(void *server_handle,
+			 krb5_principal principal, krb5_boolean keepold,
+			 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
+			 char *password)
+{
+    krb5_int32			now;
+    kadm5_policy_ent_rec	pol;
+    osa_princ_ent_rec		adb;
+    krb5_db_entry		kdb, kdb_save;
+    int				ret, ret2, last_pwd, hist_added;
+    int				have_pol = 0;
+    kadm5_server_handle_t	handle = server_handle;
+    osa_pw_hist_ent		hist;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    hist_added = 0;
+    memset(&hist, 0, sizeof(hist));
+
+    if (principal == NULL || password == NULL)
+	return EINVAL;
+    if ((krb5_principal_compare(handle->context,
+				principal, hist_princ)) == TRUE)
+	return KADM5_PROTECT_PRINCIPAL;
+
+    if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+       return(ret);
+
+    /* we are going to need the current keys after the new keys are set */
+    if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) {
+	 kdb_free_entry(handle, &kdb, &adb);
+	 return(ret);
+    }
+    
+    if ((adb.aux_attributes & KADM5_POLICY)) {
+	if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol)))
+	     goto done;
+	have_pol = 1;
+    }
+
+    if ((ret = passwd_check(handle, password, adb.aux_attributes &
+			    KADM5_POLICY, &pol, principal)))
+	 goto done;
+
+    ret = krb5_dbe_cpw(handle->context, &master_keyblock,
+		       n_ks_tuple?ks_tuple:handle->params.keysalts,
+		       n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+		       password, 0 /* increment kvno */,
+		       keepold, &kdb);
+    if (ret)
+	goto done;
+
+    kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+
+    ret = krb5_timeofday(handle->context, &now);
+    if (ret)
+	 goto done;
+    
+    if ((adb.aux_attributes & KADM5_POLICY)) {
+       /* the policy was loaded before */
+
+	ret = krb5_dbe_lookup_last_pwd_change(handle->context,
+					      &kdb, &last_pwd);
+	if (ret)
+	    goto done;
+
+#if 0
+	 /*
+	  * The spec says this check is overridden if the caller has
+	  * modify privilege.  The admin server therefore makes this
+	  * check itself (in chpass_principal_wrapper, misc.c). A
+	  * local caller implicitly has all authorization bits.
+	  */
+	if ((now - last_pwd) < pol.pw_min_life &&
+	    !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+	     ret = KADM5_PASS_TOOSOON;
+	     goto done;
+	}
+#endif
+
+	ret = create_history_entry(handle->context,
+				   kdb_save.n_key_data,
+				   kdb_save.key_data, &hist);
+	if (ret)
+	    goto done;
+
+	ret = check_pw_reuse(handle->context, &hist_key,
+			     kdb.n_key_data, kdb.key_data,
+			     1, &hist);
+	if (ret)
+	    goto done;
+	 
+	if (pol.pw_history_num > 1) {
+	    if (adb.admin_history_kvno != hist_kvno) {
+		ret = KADM5_BAD_HIST_KEY;
+		goto done;
+	    }
+
+	    ret = check_pw_reuse(handle->context, &hist_key,
+				 kdb.n_key_data, kdb.key_data,
+				 adb.old_key_len, adb.old_keys);
+	    if (ret)
+		goto done;
+
+	    ret = add_to_history(handle->context, &adb, &pol, &hist);
+	    if (ret)
+		goto done;
+	    hist_added = 1;
+       }
+
+	if (pol.pw_max_life)
+	   kdb.pw_expiration = now + pol.pw_max_life;
+	else
+	   kdb.pw_expiration = 0;
+    } else {
+	kdb.pw_expiration = 0;
+    }
+
+#ifdef USE_PASSWORD_SERVER
+    if (kadm5_use_password_server () &&
+        (krb5_princ_size (handle->context, principal) == 1)) {
+        krb5_data *princ = krb5_princ_component (handle->context, principal, 0);
+        const char *path = "/usr/sbin/mkpassdb";
+        char *argv[] = { "mkpassdb", "-setpassword", NULL, NULL };
+        char *pstring = NULL;
+        char pwbuf[256];
+        int pwlen = strlen (password);
+
+        if (pwlen > 254) pwlen = 254;
+        strncpy (pwbuf, password, pwlen);
+        pwbuf[pwlen] = '\n';
+        pwbuf[pwlen + 1] = '\0';
+
+        if (!ret) {
+            pstring = malloc ((princ->length + 1) * sizeof (char));
+            if (pstring == NULL) { ret = errno; }
+        }
+
+        if (!ret) {
+            memcpy (pstring, princ->data, princ->length);
+            pstring [princ->length] = '\0';
+            argv[2] = pstring;
+
+            ret = kadm5_launch_task (handle->context, path, argv, pwbuf);
+        }
+        
+        if (pstring != NULL)
+            free (pstring);
+        
+        if (ret)
+            goto done;
+    }
+#endif
+
+    ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
+    if (ret)
+	goto done;
+
+    if ((ret = kdb_put_entry(handle, &kdb, &adb)))
+	goto done;
+
+    ret = KADM5_OK;
+done:
+    if (!hist_added && hist.key_data)
+	 free_history_entry(handle->context, &hist);
+    kdb_free_entry(handle, &kdb, &adb);
+    kdb_free_entry(handle, &kdb_save, NULL);
+    krb5_db_free_principal(handle->context, &kdb, 1);
+
+    if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol))
+	&& !ret) 
+	 ret = ret2;
+
+    return ret;
+}
+
+kadm5_ret_t
+kadm5_randkey_principal(void *server_handle,
+			krb5_principal principal,
+			krb5_keyblock **keyblocks,
+			int *n_keys)
+{
+    return
+	kadm5_randkey_principal_3(server_handle, principal,
+				  FALSE, 0, NULL,
+				  keyblocks, n_keys);
+}
+kadm5_ret_t
+kadm5_randkey_principal_3(void *server_handle,
+			krb5_principal principal,
+			krb5_boolean keepold,
+			int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
+			krb5_keyblock **keyblocks,
+			int *n_keys)
+{
+    krb5_db_entry		kdb;
+    osa_princ_ent_rec		adb;
+    krb5_int32			now;
+    kadm5_policy_ent_rec	pol;
+    krb5_key_data		*key_data;
+    int				ret, last_pwd, have_pol = 0;
+    kadm5_server_handle_t	handle = server_handle;
+
+    krb5_db_clr_error();
+
+    if (keyblocks)
+	 *keyblocks = NULL;
+
+    CHECK_HANDLE(server_handle);
+
+    if (principal == NULL)
+	return EINVAL;
+    if (hist_princ && /* this will be NULL when initializing the databse */
+	((krb5_principal_compare(handle->context,
+				 principal, hist_princ)) == TRUE))
+	return KADM5_PROTECT_PRINCIPAL;
+
+    if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+       return(ret);
+
+    ret = krb5_dbe_crk(handle->context, &master_keyblock,
+		       n_ks_tuple?ks_tuple:handle->params.keysalts,
+		       n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+		       keepold,
+		       &kdb);
+    if (ret)
+	goto done;
+
+    kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+
+    ret = krb5_timeofday(handle->context, &now);
+    if (ret)
+	goto done;
+
+    if ((adb.aux_attributes & KADM5_POLICY)) {
+	if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
+				    &pol)) != KADM5_OK) 
+	   goto done;
+	have_pol = 1;
+
+	ret = krb5_dbe_lookup_last_pwd_change(handle->context,
+					      &kdb, &last_pwd);
+	if (ret)
+	     goto done;
+
+#if 0
+	 /*
+	  * The spec says this check is overridden if the caller has
+	  * modify privilege.  The admin server therefore makes this
+	  * check itself (in chpass_principal_wrapper, misc.c).  A
+	  * local caller implicitly has all authorization bits.
+	  */
+	if((now - last_pwd) < pol.pw_min_life &&
+	   !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+	     ret = KADM5_PASS_TOOSOON;
+	     goto done;
+	}
+#endif
+
+	if(pol.pw_history_num > 1) {
+	    if(adb.admin_history_kvno != hist_kvno) {
+		ret = KADM5_BAD_HIST_KEY;
+		goto done;
+	    }
+
+	    ret = check_pw_reuse(handle->context, &hist_key,
+				 kdb.n_key_data, kdb.key_data,
+				 adb.old_key_len, adb.old_keys);
+	    if (ret)
+		goto done;
+	}
+	if (pol.pw_max_life)
+	   kdb.pw_expiration = now + pol.pw_max_life;
+	else
+	   kdb.pw_expiration = 0;
+    } else {
+	kdb.pw_expiration = 0;
+    }
+
+    ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
+    if (ret)
+	 goto done;
+
+    if (keyblocks) {
+	 if (handle->api_version == KADM5_API_VERSION_1) {
+	      /* Version 1 clients will expect to see a DES_CRC enctype. */
+	     ret = krb5_dbe_find_enctype(handle->context, &kdb,
+					 ENCTYPE_DES_CBC_CRC,
+					 -1, -1, &key_data);
+	     if (ret)
+		 goto done;
+	     
+	     ret = decrypt_key_data(handle->context, 1, key_data,
+				     keyblocks, NULL);
+	     if (ret)
+		 goto done;
+	 } else {
+	     ret = decrypt_key_data(handle->context,
+				     kdb.n_key_data, kdb.key_data,
+				     keyblocks, n_keys);
+	     if (ret)
+		 goto done;
+	 }
+    }	 
+    
+    if ((ret = kdb_put_entry(handle, &kdb, &adb)))
+	goto done;
+
+    ret = KADM5_OK;
+done:
+    kdb_free_entry(handle, &kdb, &adb);
+    if (have_pol)
+	 kadm5_free_policy_ent(handle->lhandle, &pol);
+
+    return ret;
+}
+
+/*
+ * kadm5_setv4key_principal:
+ *
+ * Set only ONE key of the principal, removing all others.  This key
+ * must have the DES_CBC_CRC enctype and is entered as having the
+ * krb4 salttype.  This is to enable things like kadmind4 to work.
+ */
+kadm5_ret_t
+kadm5_setv4key_principal(void *server_handle,
+		       krb5_principal principal,
+		       krb5_keyblock *keyblock)
+{
+    krb5_db_entry		kdb;
+    osa_princ_ent_rec		adb;
+    krb5_int32			now;
+    kadm5_policy_ent_rec	pol;
+    krb5_keysalt		keysalt;
+    int				i, k, kvno, ret, have_pol = 0;
+#if 0
+    int                         last_pwd;
+#endif
+    kadm5_server_handle_t	handle = server_handle;
+    krb5_key_data               tmp_key_data;
+
+    krb5_db_clr_error();
+
+    memset( &tmp_key_data, 0, sizeof(tmp_key_data));
+
+    CHECK_HANDLE(server_handle);
+
+    if (principal == NULL || keyblock == NULL)
+	return EINVAL;
+    if (hist_princ && /* this will be NULL when initializing the databse */
+	((krb5_principal_compare(handle->context,
+				 principal, hist_princ)) == TRUE))
+	return KADM5_PROTECT_PRINCIPAL;
+
+    if (keyblock->enctype != ENCTYPE_DES_CBC_CRC)
+	return KADM5_SETV4KEY_INVAL_ENCTYPE;
+    
+    if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+       return(ret);
+
+    for (kvno = 0, i=0; i<kdb.n_key_data; i++)
+	 if (kdb.key_data[i].key_data_kvno > kvno)
+	      kvno = kdb.key_data[i].key_data_kvno;
+
+    if (kdb.key_data != NULL)
+	 cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
+    
+    kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, sizeof(krb5_key_data));
+    if (kdb.key_data == NULL)
+	 return ENOMEM;
+    memset(kdb.key_data, 0, sizeof(krb5_key_data));
+    kdb.n_key_data = 1;
+    keysalt.type = KRB5_KDB_SALTTYPE_V4;
+    /* XXX data.magic? */
+    keysalt.data.length = 0;
+    keysalt.data.data = NULL;
+
+    /* use tmp_key_data as temporary location and reallocate later */
+    ret = krb5_dbekd_encrypt_key_data(handle->context, &master_keyblock,
+				      keyblock, &keysalt, kvno + 1,
+				      &tmp_key_data);
+    if (ret) {
+	goto done;
+    }
+
+    for (k = 0; k < tmp_key_data.key_data_ver; k++) {
+	kdb.key_data->key_data_type[k] = tmp_key_data.key_data_type[k];
+	kdb.key_data->key_data_length[k] = tmp_key_data.key_data_length[k];
+	if (tmp_key_data.key_data_contents[k]) {
+	    kdb.key_data->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
+	    if (kdb.key_data->key_data_contents[k] == NULL) {
+		cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
+		kdb.key_data = NULL;
+		kdb.n_key_data = 0;
+		ret = ENOMEM;
+		goto done;
+	    }
+	    memcpy (kdb.key_data->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
+
+	    memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
+	    free (tmp_key_data.key_data_contents[k]);
+	    tmp_key_data.key_data_contents[k] = NULL;
+	}
+    }
+
+
+
+    kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+
+    ret = krb5_timeofday(handle->context, &now);
+    if (ret)
+	goto done;
+
+    if ((adb.aux_attributes & KADM5_POLICY)) {
+	if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
+				    &pol)) != KADM5_OK) 
+	   goto done;
+	have_pol = 1;
+
+#if 0
+	/*
+	  * The spec says this check is overridden if the caller has
+	  * modify privilege.  The admin server therefore makes this
+	  * check itself (in chpass_principal_wrapper, misc.c).  A
+	  * local caller implicitly has all authorization bits.
+	  */
+	if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
+						  &kdb, &last_pwd))
+	     goto done;
+	if((now - last_pwd) < pol.pw_min_life &&
+	   !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+	     ret = KADM5_PASS_TOOSOON;
+	     goto done;
+	}
+#endif
+#if 0
+	/*
+	 * Should we be checking/updating pw history here?
+	 */
+	if(pol.pw_history_num > 1) {
+	    if(adb.admin_history_kvno != hist_kvno) {
+		ret = KADM5_BAD_HIST_KEY;
+		goto done;
+	    }
+
+	    if (ret = check_pw_reuse(handle->context,
+				     &hist_key,
+				     kdb.n_key_data, kdb.key_data,
+				     adb.old_key_len, adb.old_keys))
+		goto done;
+	}
+#endif
+	
+	if (pol.pw_max_life)
+	   kdb.pw_expiration = now + pol.pw_max_life;
+	else
+	   kdb.pw_expiration = 0;
+    } else {
+	kdb.pw_expiration = 0;
+    }
+
+    ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now);
+    if (ret)
+	 goto done;
+
+    if ((ret = kdb_put_entry(handle, &kdb, &adb)))
+	goto done;
+
+    ret = KADM5_OK;
+done:
+    for (i = 0; i < tmp_key_data.key_data_ver; i++) {
+	if (tmp_key_data.key_data_contents[i]) {
+	    memset (tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
+	    free (tmp_key_data.key_data_contents[i]);
+	}
+    }
+
+    kdb_free_entry(handle, &kdb, &adb);
+    if (have_pol)
+	 kadm5_free_policy_ent(handle->lhandle, &pol);
+
+    return ret;
+}
+
+kadm5_ret_t
+kadm5_setkey_principal(void *server_handle,
+		       krb5_principal principal,
+		       krb5_keyblock *keyblocks,
+		       int n_keys)
+{
+    return
+	kadm5_setkey_principal_3(server_handle, principal,
+				 FALSE, 0, NULL,
+				 keyblocks, n_keys);
+}
+
+kadm5_ret_t
+kadm5_setkey_principal_3(void *server_handle,
+			 krb5_principal principal,
+			 krb5_boolean keepold,
+			 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
+			 krb5_keyblock *keyblocks,
+			 int n_keys)
+{
+    krb5_db_entry		kdb;
+    osa_princ_ent_rec		adb;
+    krb5_int32			now;
+    kadm5_policy_ent_rec	pol;
+    krb5_key_data		*old_key_data;
+    int				n_old_keys;
+    int				i, j, k, kvno, ret, have_pol = 0;
+#if 0
+    int                         last_pwd;
+#endif
+    kadm5_server_handle_t	handle = server_handle;
+    krb5_boolean		similar;
+    krb5_keysalt		keysalt;
+    krb5_key_data         tmp_key_data;
+    krb5_key_data        *tptr;
+
+    CHECK_HANDLE(server_handle);
+
+    krb5_db_clr_error();
+
+    if (principal == NULL || keyblocks == NULL)
+	return EINVAL;
+    if (hist_princ && /* this will be NULL when initializing the databse */
+	((krb5_principal_compare(handle->context,
+				 principal, hist_princ)) == TRUE))
+	return KADM5_PROTECT_PRINCIPAL;
+
+    for (i = 0; i < n_keys; i++) {
+	for (j = i+1; j < n_keys; j++) {
+	    if ((ret = krb5_c_enctype_compare(handle->context,
+					      keyblocks[i].enctype,
+					      keyblocks[j].enctype,
+					      &similar)))
+		return(ret);
+	    if (similar) {
+		if (n_ks_tuple) {
+		    if (ks_tuple[i].ks_salttype == ks_tuple[j].ks_salttype)
+			return KADM5_SETKEY_DUP_ENCTYPES;
+		} else
+		    return KADM5_SETKEY_DUP_ENCTYPES;
+	    }
+	}
+    }
+
+    if (n_ks_tuple && n_ks_tuple != n_keys)
+	return KADM5_SETKEY3_ETYPE_MISMATCH;
+
+    if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+       return(ret);
+    
+    for (kvno = 0, i=0; i<kdb.n_key_data; i++)
+	 if (kdb.key_data[i].key_data_kvno > kvno)
+	      kvno = kdb.key_data[i].key_data_kvno;
+
+    if (keepold) {
+	old_key_data = kdb.key_data;
+	n_old_keys = kdb.n_key_data;
+    } else {
+	if (kdb.key_data != NULL)
+	    cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
+	n_old_keys = 0;
+	old_key_data = NULL;
+    }
+    
+    kdb.key_data = (krb5_key_data*)krb5_db_alloc(handle->context, NULL, (n_keys+n_old_keys)
+						 *sizeof(krb5_key_data));
+    if (kdb.key_data == NULL) {
+	ret = ENOMEM;
+	goto done;
+    }
+
+    memset(kdb.key_data, 0, (n_keys+n_old_keys)*sizeof(krb5_key_data));
+    kdb.n_key_data = 0;
+
+    for (i = 0; i < n_keys; i++) {
+	if (n_ks_tuple) {
+	    keysalt.type = ks_tuple[i].ks_salttype;
+	    keysalt.data.length = 0;
+	    keysalt.data.data = NULL;
+	    if (ks_tuple[i].ks_enctype != keyblocks[i].enctype) {
+		ret = KADM5_SETKEY3_ETYPE_MISMATCH;
+		goto done;
+	    }
+	}
+	memset (&tmp_key_data, 0, sizeof(tmp_key_data));
+
+	ret = krb5_dbekd_encrypt_key_data(handle->context,
+					  &master_keyblock,
+					  &keyblocks[i],
+					  n_ks_tuple ? &keysalt : NULL,
+					  kvno + 1,
+					  &tmp_key_data);
+	if (ret) {
+	    goto done;
+	}
+	tptr = &kdb.key_data[i];
+	for (k = 0; k < tmp_key_data.key_data_ver; k++) {
+	    tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
+	    tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
+	    if (tmp_key_data.key_data_contents[k]) {
+		tptr->key_data_contents[k] = krb5_db_alloc(handle->context, NULL, tmp_key_data.key_data_length[k]);
+		if (tptr->key_data_contents[k] == NULL) {
+		    int i1;
+		    for (i1 = k; i1 < tmp_key_data.key_data_ver; i1++) {
+			if (tmp_key_data.key_data_contents[i1]) {
+			    memset (tmp_key_data.key_data_contents[i1], 0, tmp_key_data.key_data_length[i1]);
+			    free (tmp_key_data.key_data_contents[i1]);
+			}
+		    }
+
+		    ret =  ENOMEM;
+		    goto done;
+		}
+		memcpy (tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
+
+		memset (tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
+		free (tmp_key_data.key_data_contents[k]);
+		tmp_key_data.key_data_contents[k] = NULL;
+	    }
+	}
+	kdb.n_key_data++;
+    }
+
+    /* copy old key data if necessary */
+    for (i = 0; i < n_old_keys; i++) {
+	kdb.key_data[i+n_keys] = old_key_data[i];
+	memset(&old_key_data[i], 0, sizeof (krb5_key_data));
+	kdb.n_key_data++;
+    }
+
+    if (old_key_data)
+	krb5_db_free(handle->context, old_key_data);
+
+    /* assert(kdb.n_key_data == n_keys + n_old_keys) */
+    kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+
+    if ((ret = krb5_timeofday(handle->context, &now)))
+	goto done;
+
+    if ((adb.aux_attributes & KADM5_POLICY)) {
+	if ((ret = kadm5_get_policy(handle->lhandle, adb.policy,
+				    &pol)) != KADM5_OK) 
+	   goto done;
+	have_pol = 1;
+
+#if 0
+	/*
+	  * The spec says this check is overridden if the caller has
+	  * modify privilege.  The admin server therefore makes this
+	  * check itself (in chpass_principal_wrapper, misc.c).  A
+	  * local caller implicitly has all authorization bits.
+	  */
+	if (ret = krb5_dbe_lookup_last_pwd_change(handle->context,
+						  &kdb, &last_pwd))
+	     goto done;
+	if((now - last_pwd) < pol.pw_min_life &&
+	   !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
+	     ret = KADM5_PASS_TOOSOON;
+	     goto done;
+	}
+#endif
+#if 0
+	/*
+	 * Should we be checking/updating pw history here?
+	 */
+	if (pol.pw_history_num > 1) {
+	    if(adb.admin_history_kvno != hist_kvno) {
+		ret = KADM5_BAD_HIST_KEY;
+		goto done;
+	    }
+
+	    if (ret = check_pw_reuse(handle->context,
+				     &hist_key,
+				     kdb.n_key_data, kdb.key_data,
+				     adb.old_key_len, adb.old_keys))
+		goto done;
+	}
+#endif
+	
+	if (pol.pw_max_life)
+	   kdb.pw_expiration = now + pol.pw_max_life;
+	else
+	   kdb.pw_expiration = 0;
+    } else {
+	kdb.pw_expiration = 0;
+    }
+
+    if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)))
+        goto done;
+
+    if ((ret = kdb_put_entry(handle, &kdb, &adb)))
+	goto done;
+
+    ret = KADM5_OK;
+done:
+    kdb_free_entry(handle, &kdb, &adb);
+    if (have_pol)
+	 kadm5_free_policy_ent(handle->lhandle, &pol);
+
+    return ret;
+}
+
+/*
+ * Allocate an array of n_key_data krb5_keyblocks, fill in each
+ * element with the results of decrypting the nth key in key_data with
+ * master_keyblock, and if n_keys is not NULL fill it in with the
+ * number of keys decrypted.
+ */
+static int decrypt_key_data(krb5_context context,
+			    int n_key_data, krb5_key_data *key_data,
+			    krb5_keyblock **keyblocks, int *n_keys)
+{
+     krb5_keyblock *keys;
+     int ret, i;
+
+     keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock));
+     if (keys == NULL)
+	  return ENOMEM;
+     memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
+
+     for (i = 0; i < n_key_data; i++) {
+          ret = krb5_dbekd_decrypt_key_data(context, &master_keyblock,
+					    &key_data[i], 
+					    &keys[i], NULL);
+	  if (ret) {
+	       for (; i >= 0; i--) {
+		   if (keys[i].contents) {
+		       memset (keys[i].contents, 0, keys[i].length);
+		       free( keys[i].contents );
+		   }
+	       }
+
+	       memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock));
+	       free(keys);
+	       return ret;
+	  }
+     }
+
+     *keyblocks = keys;
+     if (n_keys)
+	  *n_keys = n_key_data;
+
+     return 0;
+}
+
+/*
+ * Function: kadm5_decrypt_key
+ *
+ * Purpose: Retrieves and decrypts a principal key.
+ *
+ * Arguments:
+ *
+ *	server_handle	(r) kadm5 handle
+ *	entry		(r) principal retrieved with kadm5_get_principal
+ *	ktype		(r) enctype to search for, or -1 to ignore
+ *	stype		(r) salt type to search for, or -1 to ignore
+ *	kvno		(r) kvno to search for, -1 for max, 0 for max
+ *			only if it also matches ktype and stype
+ *	keyblock	(w) keyblock to fill in
+ *	keysalt		(w) keysalt to fill in, or NULL
+ *	kvnop		(w) kvno to fill in, or NULL
+ *
+ * Effects: Searches the key_data array of entry, which must have been
+ * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to
+ * find a key with a specified enctype, salt type, and kvno in a
+ * principal entry.  If not found, return ENOENT.  Otherwise, decrypt
+ * it with the master key, and return the key in keyblock, the salt
+ * in salttype, and the key version number in kvno.
+ *
+ * If ktype or stype is -1, it is ignored for the search.  If kvno is
+ * -1, ktype and stype are ignored and the key with the max kvno is
+ * returned.  If kvno is 0, only the key with the max kvno is returned
+ * and only if it matches the ktype and stype; otherwise, ENOENT is
+ * returned.
+ */
+kadm5_ret_t kadm5_decrypt_key(void *server_handle,
+			      kadm5_principal_ent_t entry, krb5_int32
+			      ktype, krb5_int32 stype, krb5_int32
+			      kvno, krb5_keyblock *keyblock,
+			      krb5_keysalt *keysalt, int *kvnop)
+{
+    kadm5_server_handle_t handle = server_handle;
+    krb5_db_entry dbent;
+    krb5_key_data *key_data;
+    int ret;
+
+    CHECK_HANDLE(server_handle);
+
+    if (entry->n_key_data == 0 || entry->key_data == NULL)
+	 return EINVAL;
+
+    /* find_enctype only uses these two fields */
+    dbent.n_key_data = entry->n_key_data;
+    dbent.key_data = entry->key_data;
+    if ((ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype,
+				    stype, kvno, &key_data)))
+	 return ret;
+
+    if ((ret = krb5_dbekd_decrypt_key_data(handle->context,
+					   &master_keyblock, key_data,
+					   keyblock, keysalt)))
+	 return ret;
+
+    /*
+     * Coerce the enctype of the output keyblock in case we got an
+     * inexact match on the enctype; this behavior will go away when
+     * the key storage architecture gets redesigned for 1.3.
+     */
+    keyblock->enctype = ktype;
+
+    if (kvnop)
+	 *kvnop = key_data->key_data_kvno;
+
+    return KADM5_OK;
+}
+
diff --git a/mechglue/src/lib/kadm5/str_conv.c b/mechglue/src/lib/kadm5/str_conv.c
new file mode 100644
index 000000000..4a2a67873
--- /dev/null
+++ b/mechglue/src/lib/kadm5/str_conv.c
@@ -0,0 +1,417 @@
+/*
+ * lib/kadm/str_conv.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * str_conv.c - Convert between strings and Kerberos internal data.
+ */
+
+/*
+ * Table of contents:
+ *
+ * String decoding:
+ * ----------------
+ * krb5_string_to_flags()	- Convert string to krb5_flags.
+ *
+ * String encoding:
+ * ----------------
+ * krb5_flags_to_string()	- Convert krb5_flags to string.
+ */
+
+#include "k5-int.h"
+#include "admin_internal.h"
+#include "adm_proto.h"
+
+/*
+ * Local data structures.
+ */
+struct flags_lookup_entry {
+    krb5_flags		fl_flags;		/* Flag			*/
+    krb5_boolean	fl_sense;		/* Sense of the flag	*/
+    const char *	fl_specifier;		/* How to recognize it	*/
+    const char *	fl_output;		/* How to spit it out	*/
+};
+
+/*
+ * Local strings
+ */
+
+static const char default_tupleseps[]   = ", \t";
+static const char default_ksaltseps[]   = ":.";
+
+/* Keytype strings */
+/* Flags strings */
+static const char flags_pdate_in[]	= "postdateable";
+static const char flags_fwd_in[]	= "forwardable";
+static const char flags_tgtbased_in[]	= "tgt-based";
+static const char flags_renew_in[]	= "renewable";
+static const char flags_proxy_in[]	= "proxiable";
+static const char flags_dup_skey_in[]	= "dup-skey";
+static const char flags_tickets_in[]	= "allow-tickets";
+static const char flags_preauth_in[]	= "preauth";
+static const char flags_hwauth_in[]	= "hwauth";
+static const char flags_pwchange_in[]	= "pwchange";
+static const char flags_service_in[]	= "service";
+static const char flags_pwsvc_in[]	= "pwservice";
+static const char flags_md5_in[]	= "md5";
+static const char flags_pdate_out[]	= "Not Postdateable";
+static const char flags_fwd_out[]	= "Not Forwardable";
+static const char flags_tgtbased_out[]	= "No TGT-based requests";
+static const char flags_renew_out[]	= "Not renewable";
+static const char flags_proxy_out[]	= "Not proxiable";
+static const char flags_dup_skey_out[]	= "No DUP_SKEY requests";
+static const char flags_tickets_out[]	= "All Tickets Disallowed";
+static const char flags_preauth_out[]	= "Preauthorization required";
+static const char flags_hwauth_out[]	= "HW Authorization required";
+static const char flags_pwchange_out[]	= "Password Change required";
+static const char flags_service_out[]	= "Service Disabled";
+static const char flags_pwsvc_out[]	= "Password Changing Service";
+static const char flags_md5_out[]	= "RSA-MD5 supported";
+static const char flags_default_neg[]	= "-";
+static const char flags_default_sep[]	= " ";
+
+/*
+ * Lookup tables.
+ */
+
+static const struct flags_lookup_entry flags_table[] = {
+/* flag				sense	input specifier	   output string     */
+/*----------------------------- -------	------------------ ------------------*/
+{ KRB5_KDB_DISALLOW_POSTDATED,	0,	flags_pdate_in,	   flags_pdate_out   },
+{ KRB5_KDB_DISALLOW_FORWARDABLE,0,	flags_fwd_in,	   flags_fwd_out     },
+{ KRB5_KDB_DISALLOW_TGT_BASED,	0,	flags_tgtbased_in, flags_tgtbased_out},
+{ KRB5_KDB_DISALLOW_RENEWABLE,	0,	flags_renew_in,	   flags_renew_out   },
+{ KRB5_KDB_DISALLOW_PROXIABLE,	0,	flags_proxy_in,	   flags_proxy_out   },
+{ KRB5_KDB_DISALLOW_DUP_SKEY,	0,	flags_dup_skey_in, flags_dup_skey_out},
+{ KRB5_KDB_DISALLOW_ALL_TIX,	0,	flags_tickets_in,  flags_tickets_out },
+{ KRB5_KDB_REQUIRES_PRE_AUTH,	1,	flags_preauth_in,  flags_preauth_out },
+{ KRB5_KDB_REQUIRES_HW_AUTH,	1,	flags_hwauth_in,   flags_hwauth_out  },
+{ KRB5_KDB_REQUIRES_PWCHANGE,	1,	flags_pwchange_in, flags_pwchange_out},
+{ KRB5_KDB_DISALLOW_SVR,	0,	flags_service_in,  flags_service_out },
+{ KRB5_KDB_PWCHANGE_SERVICE,	1,	flags_pwsvc_in,	   flags_pwsvc_out   },
+{ KRB5_KDB_SUPPORT_DESMD5,	1,	flags_md5_in,	   flags_md5_out     }
+};
+static const int flags_table_nents = sizeof(flags_table)/
+				     sizeof(flags_table[0]);
+
+
+krb5_error_code
+krb5_string_to_flags(string, positive, negative, flagsp)
+    char	* string;
+    const char	* positive;
+    const char	* negative;
+    krb5_flags	* flagsp;
+{
+    int 	i;
+    int 	found;
+    const char	*neg;
+    size_t	nsize, psize;
+    int		cpos;
+    int		sense;
+
+    found = 0;
+    /* We need to have a way to negate it. */
+    neg = (negative) ? negative : flags_default_neg;
+    nsize = strlen(neg);
+    psize = (positive) ? strlen(positive) : 0;
+
+    cpos = 0;
+    sense = 1;
+    /* First check for positive or negative sense */
+    if (!strncasecmp(neg, string, nsize)) {
+	sense = 0;
+	cpos += (int) nsize;
+    }
+    else if (psize && !strncasecmp(positive, string, psize)) {
+	cpos += (int) psize;
+    }
+
+    for (i=0; i<flags_table_nents; i++) {
+	if (!strcasecmp(&string[cpos], flags_table[i].fl_specifier)) {
+	    found = 1;
+	    if (sense == (int) flags_table[i].fl_sense)
+		*flagsp |= flags_table[i].fl_flags;
+	    else
+		*flagsp &= ~flags_table[i].fl_flags;
+
+	    break;
+	}
+    }
+    return((found) ? 0 : EINVAL);
+}
+
+krb5_error_code
+krb5_flags_to_string(flags, sep, buffer, buflen)
+    krb5_flags	flags;
+    const char	* sep;
+    char	* buffer;
+    size_t	buflen;
+{
+    int			i;
+    krb5_flags		pflags;
+    const char		*sepstring;
+    char		*op;
+    int			initial;
+    krb5_error_code	retval;
+
+    retval = 0;
+    op = buffer;
+    pflags = 0;
+    initial = 1;
+    sepstring = (sep) ? sep : flags_default_sep;
+    /* Blast through the table matching all we can */
+    for (i=0; i<flags_table_nents; i++) {
+	if (flags & flags_table[i].fl_flags) {
+	    /* Found a match, see if it'll fit into the output buffer */
+	    if ((op+strlen(flags_table[i].fl_output)+strlen(sepstring)) <
+		(buffer + buflen)) {
+		if (!initial) {
+		    strcpy(op, sep);
+		    op += strlen(sep);
+		}
+		initial = 0;
+		strcpy(op, flags_table[i].fl_output);
+		op += strlen(flags_table[i].fl_output);
+	    }
+	    else {
+		retval = ENOMEM;
+		break;
+	    }
+	    /* Keep track of what we matched */
+	    pflags |= flags_table[i].fl_flags;
+	}
+    }
+    if (!retval) {
+	/* See if there's any leftovers */
+	if (flags & ~pflags)
+	    retval = EINVAL;
+	else if (initial)
+	    *buffer = '\0';
+    }
+    return(retval);
+}
+
+krb5_error_code
+krb5_input_flag_to_string(flag, buffer, buflen)
+    int		flag;
+    char	* buffer;
+    size_t	buflen;
+{
+    if(flag < 0 || flag >= flags_table_nents) return ENOENT; /* End of list */
+    if(strlen(flags_table[flag].fl_specifier) > buflen) return ENOMEM;
+    strcpy(buffer, flags_table[flag].fl_specifier);
+    return  0;
+}
+
+/*
+ * krb5_keysalt_is_present()	- Determine if a key/salt pair is present
+ *				  in a list of key/salt tuples.
+ *
+ *	Salttype may be negative to indicate a search for only a enctype.
+ */
+krb5_boolean
+krb5_keysalt_is_present(ksaltlist, nksalts, enctype, salttype)
+    krb5_key_salt_tuple	*ksaltlist;
+    krb5_int32		nksalts;
+    krb5_enctype	enctype;
+    krb5_int32		salttype;
+{
+    krb5_boolean	foundit;
+    int			i;
+
+    foundit = 0;
+    if (ksaltlist) {
+	for (i=0; i<nksalts; i++) {
+	    if ((ksaltlist[i].ks_enctype == enctype) &&
+		((ksaltlist[i].ks_salttype == salttype) ||
+		 (salttype < 0))) {
+		foundit = 1;
+		break;
+	    }
+	}
+    }
+    return(foundit);
+}
+
+/*
+ * krb5_string_to_keysalts()	- Convert a string representation to a list
+ *				  of key/salt tuples.
+ */
+krb5_error_code
+krb5_string_to_keysalts(string, tupleseps, ksaltseps, dups, ksaltp, nksaltp)
+    char		*string;
+    const char		*tupleseps;
+    const char		*ksaltseps;
+    krb5_boolean	dups;
+    krb5_key_salt_tuple	**ksaltp;
+    krb5_int32		*nksaltp;
+{
+    krb5_error_code	kret;
+    char 		*kp, *sp, *ep;
+    char		sepchar, trailchar;
+    krb5_enctype	ktype;
+    krb5_int32		stype;
+    krb5_key_salt_tuple	*savep;
+    const char		*tseplist;
+    const char		*ksseplist;
+    const char		*septmp;
+    size_t		len;
+    
+    kret = 0;
+    kp = string;
+    tseplist = (tupleseps) ? tupleseps : default_tupleseps;
+    ksseplist = (ksaltseps) ? ksaltseps : default_ksaltseps;
+    while (kp) {
+	/* Attempt to find a separator */
+	ep = (char *) NULL;
+	if (*tseplist) {
+	    septmp = tseplist;
+	    for (ep = strchr(kp, (int) *septmp);
+		 *(++septmp) && !ep;
+		 ep = strchr(kp, (int) *septmp));
+	}
+
+	if (ep) {
+	    trailchar = *ep;
+	    *ep = '\0';
+	    ep++;
+	}
+	/*
+	 * kp points to something (hopefully) of the form:
+	 *	<enctype><ksseplist><salttype>
+	 *	or
+	 *	<enctype>
+	 */
+	sp = (char *) NULL;
+	/* Attempt to find a separator */
+	septmp = ksseplist;
+	for (sp = strchr(kp, (int) *septmp);
+	     *(++septmp) && !sp;
+	     ep = strchr(kp, (int) *septmp));
+
+	if (sp) {
+	    /* Separate enctype from salttype */
+	    sepchar = *sp;
+	    *sp = '\0';
+	    sp++;
+	}
+	else
+	    stype = -1;
+
+	/*
+	 * Attempt to parse enctype and salttype.  If we parse well
+	 * then make sure that it specifies a unique key/salt combo
+	 */
+	if (!(kret = krb5_string_to_enctype(kp, &ktype)) &&
+	    (!sp || !(kret = krb5_string_to_salttype(sp, &stype))) &&
+	    (dups ||
+	     !krb5_keysalt_is_present(*ksaltp, *nksaltp, ktype, stype))) {
+
+	    /* Squirrel away old keysalt array */
+	    savep = *ksaltp;
+	    len = (size_t) *nksaltp;
+
+	    /* Get new keysalt array */
+	    *ksaltp = (krb5_key_salt_tuple *) 
+		malloc((len + 1) * sizeof(krb5_key_salt_tuple));
+	    if (*ksaltp) {
+
+		/* Copy old keysalt if appropriate */
+		if (savep) {
+		    memcpy(*ksaltp, savep,
+			   len * sizeof(krb5_key_salt_tuple));
+		    krb5_xfree(savep);
+		}
+
+		/* Save our values */
+		(*ksaltp)[(*nksaltp)].ks_enctype = ktype;
+		(*ksaltp)[(*nksaltp)].ks_salttype = stype;
+		(*nksaltp)++;
+	    }
+	    else {
+		*ksaltp = savep;
+		break;
+	    }
+	}
+	if (kret)
+	     return kret;
+	if (sp)
+	    sp[-1] = sepchar;
+	if (ep)
+	    ep[-1] = trailchar;
+	kp = ep;
+
+	/* Skip over extra separators - like spaces */
+	if (kp && *tseplist) {
+	  septmp = tseplist;
+	  while(*septmp && *kp) {
+	    if(*septmp == *kp) {
+	      /* Increment string - reset separator list */
+	      kp++;
+	      septmp = tseplist;
+	    } else {
+	      septmp++;
+	    }
+	  }
+	  if (!*kp) kp = NULL;
+	}
+    } /* while kp */
+    return(kret);
+}
+
+/*
+ * krb5_keysalt_iterate()	- Do something for each unique key/salt
+ *				  combination.
+ *
+ * If ignoresalt set, then salttype is ignored.
+ */
+krb5_error_code
+krb5_keysalt_iterate(ksaltlist, nksalt, ignoresalt, iterator, arg)
+    krb5_key_salt_tuple	*ksaltlist;
+    krb5_int32		nksalt;
+    krb5_boolean	ignoresalt;
+    krb5_error_code	(*iterator) (krb5_key_salt_tuple *, krb5_pointer);
+    krb5_pointer	arg;
+{
+    int			i;
+    krb5_error_code	kret;
+    krb5_key_salt_tuple	scratch;
+
+    kret = 0;
+    for (i=0; i<nksalt; i++) {
+	scratch.ks_enctype = ksaltlist[i].ks_enctype;
+	scratch.ks_salttype = (ignoresalt) ? -1 : ksaltlist[i].ks_salttype;
+	if (!krb5_keysalt_is_present(ksaltlist,
+				     i,
+				     scratch.ks_enctype,
+				     scratch.ks_salttype)) {
+	    kret = (*iterator)(&scratch, arg);
+	    if (kret)
+		break;
+	}
+    }
+    return(kret);
+}
diff --git a/mechglue/src/lib/kadm5/unit-test/ChangeLog b/mechglue/src/lib/kadm5/unit-test/ChangeLog
new file mode 100644
index 000000000..f3bbd0afe
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/ChangeLog
@@ -0,0 +1,442 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* setkey-test.c: Include k5-int.h instead of krb5.h.
+
+2005-10-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* lock-test.c (main): Don't call error table initialization
+	routines; kadm5_init* routines will do that.
+
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* api.1/lock.exp: Temporarily disabled tests.  See RT ticket
+	3201.
+
+	* api.2/init-v2.exp: Temporarily disabled test103.  See RT ticket
+	3202.
+
+2005-07-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* api.1/lock.exp (lock_test_continue): After exiting the loop,
+	send the process a signal before waiting for it to die.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KDB_DEP_LIB): Use DL_LIB and THREAD_LINKOPTS
+	instead of explicitly using -ldl and -lpthread.
+
+	Novell merge.
+	* Makefile.in (randkey-test, server-handle-test, lock-test,
+	server-iter-test, server-setkey-test): Link in pthread and dl
+	libraries.
+	* destroy-test.c (main): Pass NULL db_args argument to
+	ovsec_kadm_init.
+	* handle-test.c (main): Likewise.
+	* init-test.c (main): Likewise.
+	* iter-test.c (main): Likewise.
+	* randkey-test.c (main): Likewise.
+	* setkey-test.c (main): Likewise.
+	* lock-test.c: Include krb5/kdb.h, not kadm5/adb.h.
+	(main): Don't call initialize_adb_error_table.  Call krb5_db_open,
+	not osa_adb_open_policy, krb5_db_ lock functions instead of
+	osa_adb_ ones, etc.
+
+2005-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* api.2/init-v2.exp: Handle improved error codes from
+	client_init.c.
+	(test152): Expect KRB5_FCC_NOFILE.
+	(test153): Expect KRB5_CC_NOTFOUND.
+
+2004-08-20  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (init-test): Don't use local copy of client_init.o
+
+	* init-test.c (main): Use kadm5_init() instead of
+	ovsec_kadm_init().  Make error messages a little more
+	informative.  Use KADM5_CONFIG_NO_AUTH to test no-auth condition,
+	as the previous method was really gross.
+
+2004-02-13  Tom Yu  <tlyu@mit.edu>
+
+	* config/unix.exp (PRIOCNTL_HACK): Use "==" instead of "eq", which
+	is not present in tcl-8.3.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* config/unix.exp (PRIOCNTL_HACK): Wrap "spawn" to do priocntl
+	things to work around Solaris 9 pty-close bug.
+
+	* Makefile.in (unit-test-client-body, unit-test-server-body): Add
+	PRIOCNTL_HACK.
+
+2003-10-16  Tom Yu  <tlyu@mit.edu>
+
+	* api.1/lock.exp: Work around a race condition in the Solaris 9
+	pty implementation: output sent to a pty slave immediately before
+	last close/exit can get lost on the way to the master.  This is
+	Sun bug #4927647.  The workaround consists of changing the tests
+	to always make lock-test wait to read a character prior to
+	exiting, so any output prior to the "wait" directive will not get
+	lost.
+
+2003-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* api.2/init-v2.exp (test117): Update lifetime expected for new
+	defaults.
+
+2003-05-21  Tom Yu  <tlyu@mit.edu>
+
+	* api.0/init.exp (test6, test7): Be slightly more lenient about
+	matching password prompt.
+
+	* api.2/init.exp (test6, test7): Be slightly more lenient about
+	matching password prompt.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-12-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* api.2/init-v2.exp (test150, test151, test153): Don't try to set
+	KRB5CCNAME; only the fact that it wasn't being done correctly
+	prevented it from causing test failures.
+
+	* lib/lib.t (kinit): If kinit reports a problem initializing the
+	credentials cache, raise an error.
+
+2002-10-18  Tom Yu  <tlyu@mit.edu>
+
+	* api.2/init-v2.exp (test106): Make regexp more forgiving of
+	variant password prompts.
+
+	* api.0/init.exp (test7, test22, test225): Make regexp more
+	forgiving of variant password prompts.
+
+2002-09-15  Tom Yu  <tlyu@mit.edu>
+
+	* api.0/chpass-principal.exp:
+	* api.0/crte-policy.exp:
+	* api.0/crte-principal.exp:
+	* api.0/destroy.exp:
+	* api.0/dlte-policy.exp:
+	* api.0/dlte-principal.exp:
+	* api.0/get-policy.exp:
+	* api.0/get-principal.exp:
+	* api.0/init.exp:
+	* api.0/mod-policy.exp:
+	* api.0/mod-principal.exp:
+	* api.0/randkey-principal.exp:
+	* api.0/rename-principal.exp:
+	* api.1/lock.exp:
+	* api.2/chpass-principal-v2.exp:
+	* api.2/chpass-principal.exp:
+	* api.2/crte-policy.exp:
+	* api.2/crte-principal.exp:
+	* api.2/destroy.exp:
+	* api.2/dlte-policy.exp:
+	* api.2/dlte-principal.exp:
+	* api.2/get-policy.exp:
+	* api.2/get-principal-v2.exp:
+	* api.2/get-principal.exp:
+	* api.2/init-v2.exp:
+	* api.2/init.exp:
+	* api.2/mod-policy.exp:
+	* api.2/mod-principal-v2.exp:
+	* api.2/mod-principal.exp:
+	* api.2/randkey-principal-v2.exp:
+	* api.2/randkey-principal.exp:
+	* lib/lib.t: s/error/perror.
+
+	* config/unix.exp: Work around tcl 8.4's (incorrect?) output EOL
+	translation.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* api.2/init-v2.exp (test100): Expect MISSING_KRB5_CONF_PARAMS
+	error now.
+
+2001-11-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* api.2/init-v2.exp: For test 101 failure, change port number 1 -
+	which is used by tcpmux under Irix, to 4 - which is unassigned by
+	IANA.
+
+2001-06-20  Mitchell Berger  <mitchb@mit.edu>
+
+	* api.0/init.exp: Silly typo fixed.
+
+	* api.2/init.exp: Same silly typo fixed.
+
+2000-10-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* lock-test.c (main): Cleanup assignments in conditionals. If
+	USE_KADM5_API_VERSION is 1, set to 2. This program uses the V2 api
+	(kadm5_get_config_params).
+	
+	* setkey-test.c: Declare main() as int. Enclose initialization of
+	elements of arrays in '{', '}'. Use krb5_enctype type instead of
+	unsigned int. Break out assignments in conditionals.
+
+	* destroy-test.c, handle-test.c, init-test.c, iter-test.c,
+	randkey-test.c: Declare main() as int.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* iter-test.c (main): Code was using ovsec_kadm_ret_t in place of
+	an int for referencing array.
+
+2000-05-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* api.2/chpass-principal-v2.exp (test200): Expect an additional
+	key to be reported, since des3 has been added to the list.
+	* api.2/get-principal-v2.exp (test101_102): Likewise.
+	* api.2/randkey-principal-v2.exp (test100): Likewise.
+
+2000-02-08  Tom Yu  <tlyu@mit.edu>
+
+	* api.1/lock.exp: Since a "wait" directive to the command list of
+	the lock_test procedures does not wait for any synchronization,
+	change lock9 to acquire and release a lock before the "wait"
+	directive in order to avoid a race condition where lock9 spawns
+	the ./lock-test but the program has not opened the database prior
+	to lock9_1 acquiring a permanent lock.  This was causing
+	difficult-to-reproduce failures.
+
+2000-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* lib/lib.t: Call kinit and kdestroy with -5 flag to accomodate
+	new behavior.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* api.2/init-v2.exp (test109): Wait for prompt between commands.
+
+1999-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* api.2/init-v2.exp (RESOLVE): New variable.
+	(get_hostname): New proc, taken from tests/dejagnu.
+	(test101): Use get_hostname, set a variable in the target process
+	to hold the result, and use that variable in the other commands
+	passed, instead of "localhost".
+
+	* Makefile.in (unit-test-client-body): Pass $(RUNTESTFLAGS) to
+	runtest, so the user can run subsets of the test suite.
+	(unit-test-server-body): Likewise.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Feb 27 22:32:54 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/kadm5
+ 		directory, since we've moved all of the configure.in
+		tests to the toplevel lib/kadm5 configure.in
+
+Wed Feb 18 16:15:53 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Nov 19 10:55:20 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean): Remove server-setkey-test
+	 	client-setkey-test setkey-test.o
+
+Fri Jul 25 15:38:35 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove test-randkey since it was breaking the
+	server-side tests; api.2/getprinc-v2.exp wants *two* keys, while
+	randkey results in only one.
+
+Mon May  5 17:11:44 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* setkey-test.c, configure.in: add rules to test for correct
+ 	random()-equivlant function
+
+Mon Mar 31 17:39:52 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.in, setkey-test.c: add support for setkey
+
+Wed Mar 12 15:49:46 1997  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.in (unit-test-server-body): depend on test-randkey, not
+ 	randkey-test, so the test gets run
+
+Wed Feb  5 23:10:56 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Mon Dec  9 15:57:55 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.0/init.exp, api.2/init.exp: use spawn/expect instead of exec
+ 	so tests don't fail when kadmin.local produces output
+	
+Wed Nov 20 15:59:34 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.in (check-): warn more loudly about unrun tests
+
+Mon Nov 11 20:51:27 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add AC_CANONICAL_HOST to deal with new pre.in.
+
+Thu Nov  7 20:54:24 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Remove spurious WITH_CCOPTS and KRB_INCLUDE.
+
+Thu Nov  7 13:02:28 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.2/init-v2.exp: update tests for new init error codes and
+ 	get_config_params behavior when KDC_PROFILE does not exist
+
+	* api.2/mod-principal-v2.exp: provide finer-grained test numbers
+ 	in case of failure
+
+Wed Nov  6 17:48:49 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* lib/lib.t: global $test everywhere it is used
+
+	* api.2/mod-principal-v2.exp: init to kadmin/admin, not
+ 	kadmin/changepw; specify real principal, not null (obviously I
+ 	never ran these tests via the client library before)
+
+Fri Nov  1 13:15:37 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.2/get-principal-v2.exp, api.2/mod-principal-v2.exp: update
+ 	for new tl_data semantics [krb5-admin/140]
+
+Thu Oct 31 08:42:18 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (check): Only run tests is Perl, tcl, runtest.
+
+	* configure.in: Check for Perl before running tests.
+
+Fri Oct 25 16:43:52 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (init-test): Add -UUSE_KADM5_API_VERSION before the
+		-D of same.  
+
+Wed Oct 23 13:32:40 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* api.2/get-principal-v2.exp: Fix for test 100 where {} is not
+		equivalent to "{}" for empty tl_data field.
+
+Mon Oct 21 16:27:28 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.2/mod-principal-v2.exp: create this file, implement tests
+ 	100-104 [krb5-admin/20]
+
+Fri Oct 18 13:21:08 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.2/init-v2.exp: add test 117, for default max_life
+ 	[krb5-admin/18]
+
+Thu Oct 17 16:14:11 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* config/unix.exp, lib/lib.t: begin in process of making these
+ 	unit tests less horribly inefficient
+
+	* api.[02]/crte-principal.exp, api.[02].mod-principal: update unit
+ 	tests for new pw_expiration semantics [krb5-admin/87]
+
+	* Makefile.in: ditch the capi and sapi hack, just the api for
+ 	everything, and rename the log files after the tests complete so
+ 	they are both kept around for viewing [krb5-admin/82]
+
+Mon Oct 14 07:04:27 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: Only try to run tests if both runtest and the tcl
+		libraries present.
+
+	* configure.in: Check for runtest and Tcl.
+
+Fri Oct  4 08:31:50 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* sizes-test.c: Removed program.
+
+	* Makefile.in: Remove sizes-test.
+
+Tue Oct  1 14:45:37 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* api.2/init-v2.exp: Remove tests 104 & 105 as lockfile and
+		policy database names are hard wired. [krb5-admin/46]
+
+Thu Sep 26 17:44:10 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.0/init.exp, api.1/lock.exp, api.2/init.exp: use $K5ROOT
+ 	instead of /krb5
+
+Wed Sep 25 17:45:44 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.1/lock.exp: lockfile is now kdb5.kadm5.lock
+
+Mon Sep 23 16:31:24 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* changes to use runtest --srcdir:
+	- Makefile.in: rewrote [csapi].* links to work in srcdir (boo,
+ 	hiss)
+	- move lib.t to lib/lib.t
+	- api.*/*.exp: s/source lib.t/load_lib lib.t/
+	
+Fri Sep 20 16:51:26 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* created Makefile.in and configure.in
+
+Wed Sep 11 17:03:22 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.2/init-v2.exp: make test100 only run on client
+
+Tue Aug 20 13:46:54 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.ov (unit-test-server-body): remove kdb5_edit
+
+	* api.0/init.exp, api.2/init.exp, config/unix.exp, Makefile.ov:
+ 	use kadmin.local instead of kdb5_edit
+
+Fri Aug 16 17:16:46 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.ov: update for new lib/kadm5 layout
+
+	* api.1/lock.exp: jik's fix for lock test 13
+
+Thu Jul 18 20:18:30 1996  Marc Horowitz  <marc@mit.edu>
+
+	* api.2/init-v2.exp (test150, test151): -s flag is now -S
+
+Mon Jul  8 17:00:26 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* api.2/init-v2.exp: admin databases must now be created before
+ 	use (not created implicitly)
+
+	* api.1/lock.exp: lock-test 13 should be a warning, not a failure.
+
+	* api.0/rename-principal.exp: fix rename test to create principal
+ 	with correct salt first, and check explicitly for NO_RENAME_SALT
+ 	when appropriate
+
+	* lib.t: add create_principal_with_keysalts
+	
+
diff --git a/mechglue/src/lib/kadm5/unit-test/Makefile.in b/mechglue/src/lib/kadm5/unit-test/Makefile.in
new file mode 100644
index 000000000..88c0905b3
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/Makefile.in
@@ -0,0 +1,139 @@
+thisconfigdir=./..
+myfulldir=lib/kadm5/unit-test
+mydir=unit-test
+BUILDTOP=$(REL)..$(S)..$(S)..
+DEFINES = -DUSE_KADM5_API_VERSION=1
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+KDB_DEP_LIB=$(DL_LIB) $(THREAD_LINKOPTS)
+
+all:: init-test destroy-test client-handle-test client-iter-test
+all:: randkey-test server-handle-test lock-test server-iter-test 
+all:: server-setkey-test client-setkey-test
+
+#
+# The client-side test programs.
+#
+
+init-test: init-test.o $(KADMCLNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o init-test init-test.o \
+		$(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
+
+destroy-test: destroy-test.o $(KADMCLNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o destroy-test destroy-test.o \
+		$(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
+
+client-handle-test: handle-test.o $(KADMCLNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o client-handle-test handle-test.o \
+		$(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
+
+client-iter-test: iter-test.o $(KADMLCNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o client-iter-test iter-test.o \
+		$(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
+
+client-setkey-test: setkey-test.o $(KADMCLNT_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o client-setkey-test setkey-test.o \
+		$(KADMCLNT_LIBS) $(KRB5_BASE_LIBS)
+
+#
+# The server-side test programs.
+#
+
+randkey-test: randkey-test.o $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o randkey-test randkey-test.o \
+		$(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS)
+
+server-handle-test: handle-test.o $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o server-handle-test handle-test.o \
+		$(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS)
+
+lock-test: lock-test.o $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o lock-test lock-test.o \
+		$(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS)
+
+server-iter-test: iter-test.o $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o server-iter-test iter-test.o \
+		$(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS)
+
+setkey-test.o: $(SRCTOP)/lib/kadm5/unit-test/setkey-test.c
+	$(CC) $(ALL_CFLAGS) -UUSE_KADM5_API_VERSION -DUSE_KADM5_API_VERSION=2 -c $(SRCTOP)/lib/kadm5/unit-test/setkey-test.c
+
+server-setkey-test: setkey-test.o $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o server-setkey-test setkey-test.o \
+		$(KADMSRV_LIBS) $(KDB_DEP_LIB) $(KRB5_BASE_LIBS)
+
+#
+# The unit-test targets
+#
+
+check:: check-@DO_TEST@
+
+check-::
+	@echo "+++"
+	@echo "+++ WARNING: lib/kadm5 unit tests not run."
+	@echo "+++ Either tcl, runtest, or Perl is unavailable."
+	@echo "+++"
+
+check-ok unit-test:: unit-test-client unit-test-server
+
+unit-test-client: unit-test-client-setup unit-test-client-body \
+	unit-test-client-cleanup
+
+unit-test-server: unit-test-server-setup unit-test-server-body \
+	unit-test-server-cleanup
+
+test-randkey:: randkey-test
+	$(ENV_SETUP) ./randkey-test
+
+test-handle-server:: server-handle-test
+	$(ENV_SETUP) ./server-handle-test
+
+test-handle-client:: client-handle-test
+	$(ENV_SETUP) ./client-handle-test
+
+test-noauth: init-test
+	$(ENV_SETUP) ./init-test
+
+test-destroy: destroy-test
+	$(ENV_SETUP) ./destroy-test
+
+unit-test-client-setup::
+	$(ENV_SETUP) $(START_SERVERS)
+
+unit-test-client-cleanup::
+	$(ENV_SETUP) $(STOP_SERVERS)
+
+unit-test-server-setup::
+	$(ENV_SETUP) $(START_SERVERS_LOCAL)
+
+unit-test-server-cleanup::
+	$(ENV_SETUP) $(STOP_SERVERS_LOCAL)
+
+unit-test-client-body: site.exp test-noauth test-destroy test-handle-client 
+	$(ENV_SETUP) $(RUNTEST) --tool api RPC=1 API=$(CLNTTCL) \
+		KINIT=$(BUILDTOP)/clients/kinit/kinit \
+		KDESTROY=$(BUILDTOP)/clients/kdestroy/kdestroy \
+		KADMIN_LOCAL=$(BUILDTOP)/kadmin/cli/kadmin.local \
+		PRIOCNTL_HACK=@PRIOCNTL_HACK@ $(RUNTESTFLAGS)
+	-mv api.log capi.log
+	-mv api.sum capi.sum
+
+unit-test-server-body: site.exp test-handle-server lock-test 
+	$(ENV_SETUP) $(RUNTEST) --tool api RPC=0 API=$(SRVTCL) \
+		LOCKTEST=./lock-test \
+		KADMIN_LOCAL=$(BUILDTOP)/kadmin/cli/kadmin.local \
+		PRIOCNTL_HACK=@PRIOCNTL_HACK@ $(RUNTESTFLAGS)
+	-mv api.log sapi.log
+	-mv api.sum sapi.sum
+
+clean::
+	$(RM) init-test client_init.o init-test.o
+	$(RM) destroy-test destroy-test.o
+	$(RM) client-handle-test handle-test.o
+	$(RM) client-iter-test iter-test.o
+	$(RM) randkey-test randkey-test.o
+	$(RM) server-handle-test handle-test.o
+	$(RM) lock-test lock-test.o
+	$(RM) server-iter-test iter-test.o
+	$(RM) server-setkey-test client-setkey-test setkey-test.o
+	$(RM) *.log *.plog *.sum *.psum unit-test-log.*
diff --git a/mechglue/src/lib/kadm5/unit-test/README.new-tests b/mechglue/src/lib/kadm5/unit-test/README.new-tests
new file mode 100644
index 000000000..d63ecc285
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/README.new-tests
@@ -0,0 +1,12 @@
+The deja-gnu unit tests in this directory are arranged as follows:
+
+api.0: original unit tests for the ovsec_kadm_api
+
+api.1: additional tests for ovsec_kadm_api that run after api.0
+
+api.2: Each file whose name is the same as a file in api.0 contains
+all of the same tests, but using the kadm5 with KADM5_API_VERSION_1.
+Each file with a -v2 suffix tests KADM5_API_VERSION_2-specific
+functionality.  New tests should be added to the files in this
+directory, not api.0.  Tests should be added to the lowest-numbered
+version file they apply to.
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/chpass-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.0/chpass-principal.exp
new file mode 100644
index 000000000..93869f7d7
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/chpass-principal.exp
@@ -0,0 +1,176 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "chpass-principal 180"
+proc test180 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_chpass_principal $server_handle "%s/a" FoobarBax
+    } $test]
+
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test180 }
+
+test "chpass-principal 180.5"
+proc test1805 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_chpass_principal $server_handle "%s/a" FoobarBax
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test1805 }
+
+#
+# admin with changepw service tickets try to change other principals
+# password, failes with AUTH error
+test "chpass-principal 180.625"
+proc test180625 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_chpass_principal $server_handle "%s/a" password
+    } $test] "AUTH"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test180625 }
+
+test "chpass-principal 180.75"
+proc test18075 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_chpass_principal $server_handle "%s/a" Foobar
+    } $test] "AUTH_CHANGEPW"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test18075 }
+
+test "chpass-principal 182"
+proc test182 {} {
+    global test
+
+    if { ! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_chpass_principal $server_handle kadmin/history password
+    } "PROTECT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test182
+
+test "chpass-principal 183"
+proc test183 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if { ! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_chpass_principal null "%s/a" password
+    } $test] "BAD_SERVER_HANDLE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test183
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/crte-policy.exp b/mechglue/src/lib/kadm5/unit-test/api.0/crte-policy.exp
new file mode 100644
index 000000000..e2d02a37f
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/crte-policy.exp
@@ -0,0 +1,991 @@
+load_lib lib.t
+api_exit
+api_start
+
+# Description: (1) Fails for mask with undefined bit set.
+# 01/24/94: pshuang: untried.
+test "create-policy 1"
+proc test1 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+           [delete_policy "$test/a"])} {
+            error_and_restart "$test: couldn't delete policy \"$test/a\""
+            return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		0xF01000
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test1
+
+# Description: (2) Fails if caller connected with CHANGEPW_SERVICE.
+test "create-policy 2"
+proc test2 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy";
+	return
+    }
+}
+if {$RPC} { test2 }
+
+# Description: (3) Fails for mask without POLICY bit set.
+# 01/24/94: pshuang: untried.
+test "create-policy 3"
+proc test3 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+           [delete_policy "$test/a"])} {
+            error_and_restart "$test: couldn't delete policy \"$test/a\""
+            return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		0x000000
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test3
+
+# Description: (4) Fails for mask with REF_COUNT bit set.
+test "create-policy 4"
+proc test4 {} {
+    global test
+    
+    if {! (( ! [policy_exists "$test/a"]) ||
+           [delete_policy "$test/a"])} {
+            error_and_restart "$test: couldn't delete policy \"$test/a\""
+            return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY OVSEC_KADM_REF_COUNT}
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test4
+
+# Description: (5) Fails for invalid policy name.
+# 01/24/94: pshuang: untried.
+test "create-policy 5"
+proc test5 {} {
+    global test
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/"] \
+		{OVSEC_KADM_POLICY}
+    } $test] "BAD_POLICY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test5
+
+# Description: (6) Fails for existing policy name.
+test "create-policy 6"
+proc test6 {} {
+    global test
+#    set prms_id 777
+#    setup_xfail {*-*-*} $prms_id
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_create_policy $server_handle [simple_policy test-pol] \
+		{OVSEC_KADM_POLICY}
+    } "DUP"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test6
+
+# Description: (7) Fails for null policy name.
+# 01/24/94: pshuang: untried.
+test "create-policy 7"
+proc test7 {} {
+    global test
+#    set prms_id 1977
+#    setup_xfail {*-*-*} $prms_id
+    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_create_policy $server_handle [simple_policy null] \
+		{OVSEC_KADM_POLICY}
+    } "EINVAL"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test7
+
+# Description: (8) Fails for empty-string policy name.
+test "create-policy 8"
+proc test8 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_create_policy $server_handle [simple_policy ""] \
+		{OVSEC_KADM_POLICY}
+    } "BAD_POLICY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test8
+
+# Description: (9) Accepts 0 for pw_min_life.
+test "create-policy 9"
+proc test9 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LIFE}
+    } $test]]} {
+	fail "$test: create failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 1\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test9
+
+# Description: (10) Accepts non-zero for pw_min_life.
+test "create-policy 10"
+proc test10 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 32 0 0 0 0 0 } \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LIFE}
+    } $test]]} {
+	fail "$test"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 1\n"
+    expect {
+	-re "32\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test10
+
+# Description: (11) Accepts 0 for pw_max_life.
+test "create-policy 11"
+proc test11 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MAX_LIFE}
+    } $test]]} {
+	fail "$test"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test11
+
+# Description: (12) Accepts non-zero for pw_max_life.
+test "create-policy 12"
+proc test12 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 0 32 0 0 0 0 } \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MAX_LIFE}
+    } $test]]} {
+	fail "$test"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "32\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+# Description: (13) Rejects 0 for pw_min_length.
+test "create-policy 13"
+proc test13 {} {
+    global test
+    global prompt
+
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LENGTH}
+    } $test] "BAD_LENGTH"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test13
+
+# Description: (14) Accepts non-zero for pw_min_length.
+test "create-policy 14"
+proc test14 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 8 0 0 0 } \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LENGTH}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 3\n"
+    expect {
+	-re "8\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test14
+
+# Description: (15) Rejects 0 for pw_min_classes.
+test "create-policy 15"
+proc test15 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_CLASSES}
+    } $test] "BAD_CLASS"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+# Description: (16) Accepts 1 for pw_min_classes.
+test "create-policy 16"
+proc test16 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 1 0 0 } \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_CLASSES}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 4\n"
+    expect {
+	-re "1\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test16
+
+# Description: (17) Accepts 4 for pw_min_classes.
+test "create-policy 17"
+proc test17 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 5 0 0} \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_CLASSES}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 4\n"
+    expect {
+	-re "5\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test17
+
+# Description: (18) Rejects 5 for pw_min_classes.
+test "create-policy 18"
+proc test18 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 6 0 0} \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_CLASSES}
+    } $test] "BAD_CLASS"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test18
+
+# Description: (19) Rejects 0 for pw_history_num.
+test "create-policy 19"
+proc test19 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM}
+    } $test] "BAD_HISTORY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test19
+
+# Description: (20) Accepts 1 for pw_history_num.
+test "create-policy 20"
+proc test20 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd  [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 0 1 0} \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 5\n"
+    expect {
+	-re "1\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test20
+
+# Description: (21) Accepts 10 for pw_history_num.
+test "create-policy 21"
+proc test21 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 0 10 0} \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 5\n"
+    expect {
+	-re "10\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test21
+    
+# Description: (21.5) Rejects 11 for pw_history_num.
+# 01/24/94: pshuang: untried.
+
+test "create-policy 21.5"
+proc test215 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 0 11 0} \
+		{OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM}
+    } $test] "BAD_HISTORY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test215
+
+
+# Description: (22) Fails for user with no access bits.
+test "create-policy 22"
+proc test22 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test22
+
+# Description: (23) Fails for user with "get" but not "add".
+test "create-policy 23"
+proc test23 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test23
+
+# Description: (24) Fails for user with "modify" but not "add".
+# 01/24/94: pshuang: untried.
+test "create-policy 24"
+proc test24 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test24
+
+# Description: (25) Fails for user with "delete" but not "add".
+# 01/24/94: pshuang: untried.
+test "create-policy 25"
+proc test25 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test25
+
+# Description: Succeeds for user with "add".
+test "create-policy 26"
+proc test26 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY}
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test26
+
+# Description: Succeeds for user with "get" and "add".
+# 01/24/94: pshuang: untried.
+test "create-policy 27"
+proc test27 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/get-add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY}
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test27
+
+# Description: (28) Rejects null policy argument.
+# 01/24/94: pshuang: untried.
+test "create-policy 28"
+proc test28 {} {
+    global test
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_create_policy $server_handle null {OVSEC_KADM_POLICY}
+    } "EINVAL"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test28
+
+test "create-policy 30"
+proc test30 {} {
+    global test
+    one_line_fail_test [format {
+	ovsec_kadm_create_policy null [simple_policy "%s/a"] \
+		{OVSEC_KADM_POLICY}
+    } $test] "BAD_SERVER_HANDLE"
+}
+test30
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/crte-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.0/crte-principal.exp
new file mode 100644
index 000000000..676a83013
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/crte-principal.exp
@@ -0,0 +1,1336 @@
+load_lib lib.t
+api_exit
+api_start
+
+#test "create-principal 1"
+#
+#proc test1 {} {
+#	global test
+#	begin_dump
+#	one_line_fail_test [format {
+#	    ovsec_kadm_create_principal $server_handle \
+#		    [simple_principal "%s/a"] {OVSEC_KADM_PRINCIPAL} "%s/a"
+#	} $test $test] "NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test1
+
+test "create-principal 2"
+
+proc test2 {} {
+    global test
+    begin_dump
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_create_principal $server_handle null \
+		{OVSEC_KADM_PRINCIPAL} testpass
+    } "EINVAL"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"
+}
+test2
+
+test "create-principal 3"
+proc test3 {} {
+    global test
+#    set prms_id 777
+#    setup_xfail {*-*-*} $prms_id
+    begin_dump
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} null
+    } $test] "EINVAL"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+test3
+
+test "create-principal 4"
+proc test4 {} {
+    global test
+
+    begin_dump    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} ""
+    } $test] "_Q_TOOSHORT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"     
+}
+test4
+
+test "create-principal 5"
+proc test5 {} {
+    global test
+    begin_dump    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle \
+		[simple_principal "%s/a"] {0x100001} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+test5
+
+test "create-principal 6"
+proc test6 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_LAST_PWD_CHANGE} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test6
+
+test "create-principal 7"
+proc test7 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_MOD_TIME} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test7
+
+test "create-principal 8"
+proc test8 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_MOD_NAME} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test8
+
+test "create-principal 9"
+proc test9 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_MKVNO} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test9
+
+test "create-principal 10"
+proc test10 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_AUX_ATTRIBUTES} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test10
+
+test "create-principal 11"
+proc test11 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_POLICY_CLR} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test11
+
+test "create-principal 12"
+proc test12 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+
+}
+if {$RPC} { test12 }
+
+test "create-principal 13"
+proc test13 {} {
+    global test
+    begin_dump        
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+if {$RPC} { test13 }
+
+test "create-principal 14"
+proc test14 {} {
+    global test
+    begin_dump        
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+if {$RPC} { test14 }
+
+test "create-principal 15"
+proc test15 {} {
+    global test
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+if {$RPC} { test15 }
+
+test "create-principal 16"
+proc test16 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+if {$RPC} { test16 }
+
+test "create-principal 17"
+proc test17 {} {
+    global test
+
+    begin_dump    
+    if {! (( [principal_exists "$test/a"]) || [create_principal "$test/a"])} {
+		error_and_restart "$test: couldn't create principal \"$test/a\""
+		return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} testpass
+    } $test] "DUP"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test17
+
+test "create-principal 18"
+proc test18 {} {
+    global test
+
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} tP
+    } $test] "_Q_TOOSHORT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+test18
+
+test "create-principal 19"
+proc test19 {} {
+    global test
+
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} testpassword
+    } $test] "_Q_CLASS"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test19
+
+test "create-principal 20"
+proc test20 {} {
+    global test
+
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} Abyssinia
+    } $test] "_Q_DICT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test20
+
+test "create-principal 21"
+proc test21 {} {
+    global test
+
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal $server_handle \
+		[princ_w_pol "%s/a" non-existant-pol] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} NotinTheDictionary
+    } $test] "UNK_POLICY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test21
+
+test "create-principal 23"
+proc test23 {} {
+    global test
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    one_line_succeed_test \
+	    [format {ovsec_kadm_get_principal $server_handle "%s/a" p} $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test23
+
+test "create-principal 24"
+proc test24 {} {
+    global test
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/rename admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    one_line_succeed_test \
+	    [format {ovsec_kadm_get_principal $server_handle "%s/a" p} $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test24 }
+
+
+test "create-principal 28"
+proc test28 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol.*$prompt$"   { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test28
+
+test "create-principal 29"
+proc test29 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_PRINC_EXPIRE_TIME} \
+		inTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 1\n"
+    expect {
+	-re "0.*$prompt$"   { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test29
+
+test "create-principal 30"
+proc test30 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_PW_EXPIRATION} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test30
+
+test "create-principal 31"
+proc test31 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol-nopw] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \
+		OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test31
+
+test "create-principal 32"
+proc test32 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \
+		OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy}]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+
+    send "lindex \$principal 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { $pw_expire != 0 } {
+	fail "$test: pw_expire $pw_expire should be 0"
+	return
+    } else {
+	pass "$test" 
+    }
+
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+perror"$test: unexpected failure in destroy"
+	return
+    }
+}
+test32
+
+test "create-principal 33"
+proc test33 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+perror"$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle \
+		{"%s/a" 0 0 1234 0 null 0 0 0 0 null 0} \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_PW_EXPIRATION} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test33
+
+test "create-principal 34"
+proc test34 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle \
+		{ "%s/a" 0 0 1234 0 null 0 0 0 0 test-pol-nopw 0} \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \
+		OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test34
+
+test "create-principal 35"
+proc test35 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle \
+		{"%s/a" 0 0 1234 0 null 0 0 0 0 test-pol 0} \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \
+		OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test35
+
+test "create-principal 36"
+proc test36 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle \
+		{"%s/a" 0 0 999999999 0 null 0 0 0 0 test-pol 0} \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \
+		OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {    
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy} ]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+
+    send "lindex \$principal 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { $pw_expire != 999999999 } {
+	fail "$test: pw_expire $pw_expire should be 999999999"
+	return
+    } else {
+	pass "$test"
+    }
+
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+perror"$test: unexpected failure in destroy"
+	return
+    }
+}
+test36
+
+test "create-principal 37"
+proc test37 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test37
+
+test "create-principal 38"
+proc test38 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol-nopw] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test38
+
+test "create-principal 39"
+proc test39 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: cannot not retrieve principal"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy}]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+    send "lindex \$principal 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } {
+	fail "$test: pw_expire is wrong"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+perror"$test: unexpected failure in destroy"
+	return
+    }
+}
+test39
+
+test "create-principal 40"
+proc test40 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+perror"$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL OVSEC_KADM_PW_EXPIRATION} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 4\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test40
+
+test "create-principal 43"
+proc test43 {} {
+    global test
+    one_line_fail_test [format {
+	ovsec_kadm_create_principal null \
+		    [simple_principal "%s/a"] {OVSEC_KADM_PRINCIPAL} "%s/a"
+    } $test $test] "BAD_SERVER_HANDLE"
+}
+test43
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/destroy.exp b/mechglue/src/lib/kadm5/unit-test/api.0/destroy.exp
new file mode 100644
index 000000000..0f103991e
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/destroy.exp
@@ -0,0 +1,203 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "destroy 1"
+
+proc test1 {} {
+	global test
+	begin_dump
+	if {! [cmd {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+	}]} {
+		perror "$test: unexpected failure in init"
+		return
+	}
+	one_line_succeed_test {ovsec_kadm_destroy $server_handle}
+	end_dump_compare "no-diffs"
+}
+test1
+
+#test "destroy 2"
+#
+#proc test2 {} {
+#	global test
+#	begin_dump
+#	if {! [cmd {
+#	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+#		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		    server_handle
+#	}]} {
+#	    perror "$test: unexpected failure on init"
+#	    return
+#	}
+#	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#		return
+#	}
+#	one_line_fail_test \
+#		{ovsec_kadm_get_principal $server_handle admin principal} \
+#		"NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test2
+
+#test "destroy 3"
+#proc test3 {} {
+#	global test
+#
+#	begin_dump
+#	if {! (( ! [principal_exists "$test/a"]) || [delete_principal "$test/a"])} {
+#	    error_and_restart "$test couldn't delete principal \"$test/a\""
+#	    return
+#	}
+#	if {! [cmd {
+#	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+#		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		    server_handle
+#	}]} {
+#	    perror "$test: unexpected failure on init"
+#	    return
+#	}
+#	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#		return
+#	}
+#	one_line_fail_test [format {
+#	    ovsec_kadm_create_principal $server_handle \
+#		    [simple_principal "%s/a"] {OVSEC_KADM_PRINCIPAL} "%s/a"
+#	} $test $test] "NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test3
+
+#test "destroy 4"
+#proc test4 {} {
+#	global test prompt
+#
+#	if {! (([principal_exists "$test/a"]) || [create_principal "$test/a"])} {
+#		error_and_restart "$test: couldn't create principal \"$test/a\""
+#		return
+#	}
+#	begin_dump
+#	if {! ([cmd {
+#	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+#		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		    server_handle
+#	}] &&
+#	    [cmd [format {
+#		ovsec_kadm_get_principal $server_handle "%s/a" principal
+#	    } $test]])} {
+#		error_and_restart "$test: error getting principal"
+#		return;
+#	}
+#	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#		return
+#	}
+#	one_line_fail_test [format {
+#	    ovsec_kadm_modify_principal $server_handle \
+#		    {"%s/a" 0 0 0 0 0 0 0 %d 0 0 0} {OVSEC_KADM_KVNO}
+#	} $test "77"] "NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test4
+
+#test "destroy 5"
+#
+#proc test5 {} {
+#	global test
+#
+#	if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+#		error_and_restart "$test: couldn't create principal \"$test/a\""
+#		return
+#	}
+#	begin_dump
+#	if {! [cmd {
+#	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+#		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		    server_handle
+#	}]} {
+#	    perror "$test: unexpected failure on init"
+#	    return
+#	}
+#	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#		return
+#	}
+#	one_line_fail_test [format {
+#	    ovsec_kadm_delete_principal $server_handle "%s/a"
+#	} $test] "NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test5
+
+#test	"destroy 6"
+#
+#proc test6 {} {
+#	global test
+#	begin_dump	
+#	one_line_fail_test {ovsec_kadm_destroy $server_handle} "NOT_INIT"
+#	end_dump_compare "no-diffs"	
+#}
+#test6
+
+
+#test	"destroy 7"
+#
+#proc test7 {} {
+#	global test
+#	begin_dump	
+#	if {! [cmd {
+#	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+#		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		    server_handle
+#	}]} {
+#		perror "$test: unexpected failure in init"
+#		return
+#	}
+#	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#	}
+#	one_line_fail_test {ovsec_kadm_destroy $server_handle} "NOT_INIT"
+#	end_dump_compare "no-diffs"	
+#}
+#test7
+
+test	"destroy 8"
+proc test8 {} {
+	global test
+	begin_dump	
+	if {! [cmd {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}]} {
+		perror "$test: unexpected failure in init"
+		return
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+	one_line_succeed_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+	end_dump_compare "no-diffs"		
+}
+test8
+
+test "destroy 9"
+proc test9 {} {
+	global test
+	one_line_fail_test {ovsec_kadm_destroy null} "BAD_SERVER_HANDLE"
+}
+test9
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/dlte-policy.exp b/mechglue/src/lib/kadm5/unit-test/api.0/dlte-policy.exp
new file mode 100644
index 000000000..cd82738e6
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/dlte-policy.exp
@@ -0,0 +1,207 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "delete-policy 2"
+proc test2 {} {
+    global test
+#    set prms_id 744
+#    setup_xfail {*-*-*} $prms_id
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test \
+	    {ovsec_kadm_delete_policy $server_handle ""} "BAD_POL"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test2
+
+test "delete-policy 5"
+proc test5 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_policy $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if ${RPC} test5
+
+test "delete-policy 6"
+proc test6 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_policy $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if ${RPC} test6
+
+test "delete-policy 7"
+proc test7 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_policy $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test7
+
+test "delete-policy 10"
+proc test10 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_delete_policy $server_handle  "%s/a"
+    } $test]]} {
+	fail "$test"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    if { [policy_exists "$test/a"]} {
+	fail "$test"
+	return
+    }
+}
+test10
+
+test "delete-policy 12"
+proc test12 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test unexecpted failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_create_principal $server_handle [princ_w_pol "%s/a" \
+		"%s/a"] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} \
+		NotinTheDictionary
+    } $test $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test \
+	    {ovsec_kadm_delete_policy $server_handle test-pol} "POLICY_REF"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+test "delete-policy 13"
+proc test13 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_policy null "%s/a"
+    } $test] "BAD_SERVER_HANDLE"
+}
+test13
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/dlte-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.0/dlte-principal.exp
new file mode 100644
index 000000000..5c617fb35
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/dlte-principal.exp
@@ -0,0 +1,329 @@
+load_lib lib.t
+
+api_exit
+api_start
+
+#test "delete-principal 1"
+#proc test1 {} {
+#	global test
+#	one_line_fail_test [format {
+#	    ovsec_kadm_delete_principal $server_handle "%s/a"
+#	} $test] "NOT_INIT"
+#}
+#test1
+
+test "delete-principal 2"
+proc test2 {} {
+    global test
+   
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	error_and_restart "$test: couldn't delete principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test \
+	    {ovsec_kadm_delete_principal $server_handle null} "EINVAL"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	error_and_restart "$test: unexpected failure in destroy"
+	return
+    }
+}
+test2
+
+test "delete-principal 5"
+proc test5 {} {
+    global test
+   
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	error_and_restart "$test: couldn't delete principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_principal $server_handle "%s/a"
+    } $test] "UNK_PRINC"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test5
+
+test "delete-principal 6"
+proc test6 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" test-pol])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test6 }
+    
+	
+test "delete-principal 7"
+proc test7 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test7 }
+    
+	
+test "delete-principal 8"
+proc test8 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test8 }
+
+test "delete-principal 9"
+proc test9 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test9 }
+
+test "delete-principal 10"
+proc test10 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test10 }
+
+test "delete-principal 11"
+proc test11 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_delete_principal $server_handle "%s/a"
+    } $test]]} {
+	fail "$test: delete failed"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    if { [principal_exists "$test/a"] } {
+	fail "$test"
+	return
+    }
+}
+test11
+
+test "delete-principal 12"
+proc test12 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" test-pol])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_delete_principal $server_handle "%s/a"
+    } $test]]} {
+	fail "$test: delete failed"
+	return
+    }
+    if { [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" p
+    } $test]]} {
+	fail "$test: principal still exists"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    send "lindex \$p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    
+    send "lindex \$p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$oldref - 1"] != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    pass "$test"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+
+test12
+
+test "delete-principal 13"
+proc test13 {} {
+	global test
+	one_line_fail_test [format {
+	    ovsec_kadm_delete_principal null "%s/a"
+	} $test] "BAD_SERVER_HANDLE"
+}
+test13
+    
+return ""
+
+
+
+
+
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/get-policy.exp b/mechglue/src/lib/kadm5/unit-test/api.0/get-policy.exp
new file mode 100644
index 000000000..7b0181412
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/get-policy.exp
@@ -0,0 +1,199 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "get-policy 3"
+proc test3 {} {
+    global test
+#    set prms_id 744
+#    setup_xfail {*-*-*} $prms_id
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+	server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {ovsec_kadm_get_policy $server_handle "" p} "BAD_POLICY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test3
+
+test "get-policy 6"
+proc test6 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+	    server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {ovsec_kadm_get_policy $server_handle test-pol p} \
+	    "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } test6
+
+test "get-policy 7"
+proc test7 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+	    server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {ovsec_kadm_get_policy $server_handle test-pol p} \
+	    "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } test7
+
+test "get-policy 11"
+proc test11 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin/get-pol StupidAdmin $OVSEC_KADM_ADMIN_SERVICE \
+		null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {ovsec_kadm_get_policy $server_handle test-pol p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test11
+
+test "get-policy 12"
+proc test12 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin/get-pol StupidAdmin \
+		$OVSEC_KADM_CHANGEPW_SERVICE null $OVSEC_KADM_STRUCT_VERSION \
+		$OVSEC_KADM_API_VERSION_1 server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {ovsec_kadm_get_policy $server_handle test-pol-nopw p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+test "get-policy 15"
+proc test15 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin/pol StupidAdmin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {ovsec_kadm_get_policy $server_handle test-pol-nopw p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+test "get-policy 16"
+proc test16 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin/pol StupidAdmin $OVSEC_KADM_CHANGEPW_SERVICE \
+		null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {ovsec_kadm_get_policy $server_handle test-pol-nopw p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test16
+
+test "get-policy 17"
+proc test17 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+	    server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {ovsec_kadm_get_policy $server_handle test-pol p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test17
+
+test "get-policy 18"
+proc test18 {} {
+    global test
+
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {ovsec_kadm_get_policy $server_handle test-pol p} \
+	    "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } test18
+
+test "get-policy 21"
+proc test21 {} {
+    global test
+
+    one_line_fail_test {ovsec_kadm_get_policy null "pol1" p} "BAD_SERVER_HANDLE"
+}
+test21
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/get-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.0/get-principal.exp
new file mode 100644
index 000000000..cf055f787
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/get-principal.exp
@@ -0,0 +1,346 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "get-principal 1"
+proc test1 {} {
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test \
+	    {ovsec_kadm_get_principal $server_handle null p} "EINVAL"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test1
+
+test "get-principal 2"
+proc test2 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" p
+    } $test] "UNK_PRINC"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test2
+
+test "get-principal 3"
+proc test3 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" p
+    } $test] "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test3 }
+    
+test "get-principal 4"
+proc test4 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" p
+    } $test] "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test4 }
+
+test "get-principal 5"
+proc test5 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" p
+    } $test] "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test5 }
+
+test "get-principal 6"
+proc test6 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" p
+    } $test] "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test6 }
+
+test "get-principal 7"
+proc test7 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" p
+    } $test] "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test7 }
+
+    
+test "get-principal 8"
+proc test8 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" p
+    } $test] "AUTH_GET"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test8 }
+
+    
+test "get-principal 9"
+proc test9 {} {
+    global test
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {ovsec_kadm_get_principal $server_handle admin/none p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test9
+
+test "get-principal 10"
+proc test10 {} {
+    global test
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {ovsec_kadm_get_principal $server_handle admin/none p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test10
+
+test "get-principal 11"
+proc test11 {} {
+    global test
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {ovsec_kadm_get_principal $server_handle admin/get p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test11
+
+test "get-principal 12"
+proc test12 {} {
+    global test
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {ovsec_kadm_get_principal $server_handle admin/get p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+test "get-principal 13"
+proc test13 {} {
+    global test
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {ovsec_kadm_get_principal $server_handle admin/add p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test13
+
+test "get-principal 14"
+proc test14 {} {
+    global test
+    if {! [cmd {
+	ovsec_kadm_init admin/get-mod admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {ovsec_kadm_get_principal $server_handle admin/add p}
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test14
+
+test "get-principal 15"
+proc test15 {} {
+    one_line_fail_test \
+	    {ovsec_kadm_get_principal null "admin" p} "BAD_SERVER_HANDLE"
+}
+test15
+
+return ""
+
+
+
+
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/init.exp b/mechglue/src/lib/kadm5/unit-test/api.0/init.exp
new file mode 100644
index 000000000..d39ecce07
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/init.exp
@@ -0,0 +1,728 @@
+load_lib lib.t
+
+# Assumptions:
+# 
+# Principal "admin" exists, with "get", "add", "modify" and "delete"
+#   access bits and password "admin".
+# The string "not-the-password" isn't the password of any user in the database.
+# Database master password is "mrroot".
+
+api_exit
+api_start
+test "init 1"
+
+one_line_fail_test_nochk \
+	{ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE "" \
+	 $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle}
+
+test "init 2"
+
+one_line_fail_test_nochk \
+	{ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE @ \
+	 $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle}
+
+test "init 2.5"
+
+one_line_fail_test_nochk \
+	{ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE BAD.REALM \
+	 $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle}
+
+test "init 3"
+
+proc test3 {} {
+    global test
+    if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+    one_line_fail_test_nochk [format {
+	ovsec_kadm_init admin admin "%s/a" null $OVSEC_KADM_STRUCT_VERSION \
+		$OVSEC_KADM_API_VERSION_1 server_handle
+    } $test]
+}
+if {$RPC} { test3 }
+
+test "init 4"
+
+proc test4 {} {
+    global test
+	if {! ((! [principal_exists "$test/a"]) || 
+         [delete_principal "$test/a"])} {
+		error_and_restart "$test: couldn't delete principal \"$test/a\""
+		return
+	}
+		
+	one_line_fail_test_nochk [format {
+	    ovsec_kadm_init admin admin "%s/a" null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	} $test]
+}
+if {$RPC} { test4 }
+
+test "init 5"
+
+if {$RPC} {
+    one_line_fail_test_nochk {
+	ovsec_kadm_init admin admin admin null $OVSEC_KADM_STRUCT_VERSION \
+		$OVSEC_KADM_API_VERSION_1 server_handle
+    }
+}
+
+test "init 6"
+
+proc test6 {} {
+    global test
+
+    send "ovsec_kadm_init admin null \$OVSEC_KADM_ADMIN_SERVICE null \$OVSEC_KADM_STRUCT_VERSION \$OVSEC_KADM_API_VERSION_1 server_handle\n"
+
+    expect {
+	-re "assword\[^\r\n\]*: *" { }
+	eof {
+		fail "$test: eof instead of password prompt"
+		api_exit
+		api_start
+		return
+	}
+	timeout {
+	    fail "$test: timeout instead of password prompt"
+	    return
+	}
+    }
+    one_line_succeed_test "admin"
+    if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	error_and_restart "$test: couldn't close database"
+    }
+}
+if { $RPC } { test6 } 
+
+test "init 7"
+proc test7 {} {
+    global test
+
+    send "ovsec_kadm_init admin \"\" \$OVSEC_KADM_ADMIN_SERVICE null \$OVSEC_KADM_STRUCT_VERSION \$OVSEC_KADM_API_VERSION_1 server_handle\n"
+
+    expect {
+	-re "assword\[^\r\n\]*: *" { }
+	-re "\n\[^\n\]+key:\[^\n\]*$" { }
+	eof {
+		fail "$test: eof instead of password prompt"
+		api_exit
+		api_start
+		return
+	}
+	timeout {
+	    fail "$test: timeout instead of password prompt"
+	    return
+	}
+    }
+    one_line_succeed_test "admin"
+    if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	error_and_restart "$test: couldn't close database"
+    }
+}
+if { $RPC } { test7 } 
+
+test "init 8"
+
+proc test8 {} {
+    global test
+	if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+		error_and_restart "$test: couldn't create principal \"$test/a\""
+		return
+	}
+ 	one_line_fail_test_nochk [format {
+	    ovsec_kadm_init "%s/a" admin $OVSEC_KADM_ADMIN_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	} $test]
+}
+if {$RPC} { test8 }
+
+test "init 9"
+
+if {$RPC} {
+    global test
+  one_line_fail_test_nochk {
+      ovsec_kadm_init admin not-the-password $OVSEC_KADM_ADMIN_SERVICE null \
+	      $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+	      server_handle
+  }
+}
+
+test "init 10"
+
+proc test10 {} {
+	global test
+#	set prms_id 562
+#	setup_xfail {*-*-*} $prms_id
+	one_line_fail_test_nochk {
+	    ovsec_kadm_init null admin $OVSEC_KADM_ADMIN_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+}
+test10
+
+#test "init 11"
+#
+#proc test11 {} {
+#	global test
+#	set prms_id 563
+#	setup_xfail {*-*-*} $prms_id
+#	one_line_fail_test_nochk {
+#	    ovsec_kadm_init "" admin $OVSEC_KADM_ADMIN_SERVICE null \
+#		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		    server_handle
+#	}
+#}
+#test11
+
+test "init 12"
+
+proc test12 {} {
+	global test
+    one_line_fail_test_nochk [format {
+	ovsec_kadm_init "%s/a" admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    } $test]
+}
+if {$RPC} { test12 }
+
+test "init 13"
+
+proc test13 {} {
+	global test
+    one_line_fail_test_nochk [format {
+	ovsec_kadm_init "%s/a@SECURE-TEST.OV.COM" admin \
+		$OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION \
+		$OVSEC_KADM_API_VERSION_1 server_handle
+    } $test]
+}
+if {$RPC} { test13 }
+
+test "init 14"
+
+proc test14 {} {
+	global test
+    one_line_fail_test_nochk [format {
+	ovsec_kadm_init "%s/a@BAD.REALM" admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    } $test]
+}
+if {$RPC} { test14 }
+
+test "init 15"
+
+if {$RPC} {
+    one_line_fail_test_nochk {
+	ovsec_kadm_init admin@BAD.REALM admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }
+}
+
+test "init 16"
+
+proc test16 {} {
+	global test
+	one_line_succeed_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test16
+
+test "init 17"
+
+proc test17 {} {
+	global test
+	one_line_succeed_test {
+	    ovsec_kadm_init admin@SECURE-TEST.OV.COM admin \
+		    $OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION \
+		    $OVSEC_KADM_API_VERSION_1 server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test17
+
+test "init 18"
+
+proc test18 {} {
+	global test
+	one_line_succeed_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test18
+
+test "init 19"
+
+proc test19 {} {
+	global test
+	one_line_succeed_test {
+	    ovsec_kadm_init admin@SECURE-TEST.OV.COM admin \
+		    $OVSEC_KADM_ADMIN_SERVICE SECURE-TEST.OV.COM \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test19
+
+test "init 20"
+
+proc test20 {} {
+	global test
+  if {! [cmd {
+      ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	      $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+	      server_handle
+  }]} {
+		error_and_restart "$test: couldn't init database"
+		return
+	}
+	one_line_succeed_test \
+		{ovsec_kadm_get_principal $server_handle admin principal}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test20
+
+#test "init 21"
+#
+#proc test21 {} {
+#    global test
+#    if {! [cmd {
+#	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+#		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		server_handle
+#    }]} {
+#	error_and_restart "$test: couldn't init database"
+#	return
+#    }
+#    one_line_fail_test_nochk {
+#	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+#		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		server_handle
+#    }
+#    if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+#	error_and_restart "$test: couldn't close database"
+#    }
+#}
+#test21
+
+
+proc test22 {} {
+	global test prompt
+	set prompting 0
+	send [string trim {
+	    ovsec_kadm_init admin null null null $OVSEC_KADM_STRUCT_VERSION \
+		    $OVSEC_KADM_API_VERSION_1 server_handle
+	}]
+	send "\n"
+	expect {
+	    -re "\n\[^\n\]+:\[^\n\]*$" { set prompting 1}
+	    -re "\nOK .*$prompt$" { fail "$test: premature success" }
+	    -re "\nERROR .*$prompt$" { fail "$test: premature failure" }
+		timeout { fail "$test: timeout" }
+		eof { fail "$test: eof" }
+	}
+	if {$prompting} {
+	    one_line_succeed_test mrroot
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	    error_and_restart "$test: couldn't close database"
+	}
+}
+if {! $RPC} { test22 }
+
+test "init 22.5"
+proc test225 {} {
+	global test prompt
+	set prompting 0
+	send [string trim {
+	    ovsec_kadm_init admin null null null $OVSEC_KADM_STRUCT_VERSION \
+		    $OVSEC_KADM_API_VERSION_1 server_handle
+	}]
+	send "\n"
+	expect {
+	    -re "\n\[^\n\]+:\[^\n\]*$" { set prompting 1}
+	    -re "\nOK .*$prompt$" { fail "$test: premature success" }
+	    -re "\nERROR .*$prompt$" { fail "$test: premature failure" }
+		timeout { fail "$test: timeout" }
+		eof { fail "$test: eof" }
+	}
+	if {$prompting} {
+	    one_line_succeed_test mrroot
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	    error_and_restart "$test: couldn't close database"
+	}
+}
+if {! $RPC} { test225 }
+
+test "init 23"
+
+proc test23 {} {
+	global test
+	one_line_succeed_test {
+	    ovsec_kadm_init admin not-the-password $OVSEC_KADM_ADMIN_SERVICE \
+		    null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+if {! $RPC} { test23 }
+
+test "init 24"
+
+proc test24 {} {
+	global test
+	one_line_succeed_test {
+	    ovsec_kadm_init admin admin null null $OVSEC_KADM_STRUCT_VERSION \
+		    $OVSEC_KADM_API_VERSION_1 server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+if {! $RPC} { test24 }
+
+test "init 25"
+
+proc test25 {} {
+	global test
+	one_line_succeed_test {
+	    ovsec_kadm_init admin admin foobar null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+if {! $RPC} { test25 }
+
+test "init 26"
+
+#proc test26 {} {
+#	global test
+#
+#	api_exit
+#	api_start
+#	one_line_fail_test_nochk {
+#	    ovsec_kadm_get_principal $server_handle admin principal
+#	}
+#}
+#test26
+
+#test "init 27"
+#
+#proc test27 {} {
+#	global test
+#
+#	if {! ((! [principal_exists "$test/a"]) || [delete_principal "$test/a"])} {
+#		error_and_restart "$test: couldn't delete principal \"$test/a\""
+#		return
+#	}
+#	begin_dump
+#	if {[cmd [format {
+#	    ovsec_kadm_create_principal $server_handle [simple_principal \
+#		    "%s/a"] {OVSEC_KADM_PRINCIPAL} "%s/a"
+#	} $test $test]]} {
+#		fail "$test: unexpected success in add"
+#		return
+#	}
+#	end_dump_compare "no-diffs"
+#}
+#test27
+
+#test "init 28"
+#
+#proc test28 {} {
+#    global test prompt
+#
+#    if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+#	error_and_restart "$test: couldn't create principal \"$test/a\""
+#	return
+#    }
+#    begin_dump
+#    if {! ([cmd {
+#	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+#		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+#		server_handle
+#    }] && [cmd [format {
+#	ovsec_kadm_get_principal $server_handle "%s/a" principal
+#    } $test]])} {
+#	error_and_restart "$test: error getting principal"
+#	return;
+#    }
+#    send "lindex \$principal 8\n"
+#    expect {
+#	-re "\n(\[0-9\]+).*$prompt$" {set kvno $expect_out(1,string) }
+#	timeout {
+#	    error_and_restart "$test: timeout getting principal kvno"
+#	    return
+#	}
+#	eof {
+#	    error_and_restart "$test: eof getting principal kvno"
+#	    return
+#	}
+#    }
+#    api_exit
+#    api_start
+#    set new_kvno [expr "$kvno + 1"]
+#    if {[cmd [format {
+#	ovsec_kadm_modify_principal $server_handle \
+#		{"%s/a" 0 0 0 0 0 0 0 %d 0 0 0} {OVSEC_KADM_KVNO}
+#    } $test $new_kvno]]} {
+#	fail "$test: unexpected success in modify"
+#	return;
+#    }
+#    end_dump_compare "no-diffs"
+#}
+#test28
+
+#test "init 29"
+#
+#proc test29 {} {
+#    global test
+#
+#    if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+#	error_and_restart "$test: couldn't create principal \"$test/a\""
+#	return
+#    }
+#    begin_dump
+#    if {[cmd [format {
+#	ovsec_kadm_delete_principal $server_handle "%s/a"
+#    } $test]]} {
+#	fail "$test: unexpected success in delete"
+#	return
+#    }
+#    end_dump_compare "no-diffs"
+#}
+#test29
+
+test "init 30"
+proc test30 {} {
+	global test
+	if {[cmd {
+	    ovsec_kadm_init admin foobar $OVSEC_KADM_ADMIN_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}]} {
+		error_and_restart "$test: unexpected success"
+		return
+	}
+	one_line_succeed_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+if ${RPC} { test30 }
+
+test "init 31"
+proc test31 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $bad_struct_version_mask $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	} "BAD_STRUCT_VERSION" 
+}
+test31
+
+test "init 32"
+proc test32 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $no_struct_version_mask $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	} "BAD_STRUCT_VERSION" 
+}
+test32
+
+test "init 33"
+proc test33 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $old_struct_version $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	} "OLD_STRUCT_VERSION" 
+}
+test33
+
+test "init 34"
+proc test34 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $new_struct_version $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	} "NEW_STRUCT_VERSION" 
+}
+test34
+
+test "init 35"
+proc test35 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $OVSEC_KADM_STRUCT_VERSION $bad_api_version_mask \
+		    server_handle
+	} "BAD_API_VERSION" 
+}
+test35
+
+test "init 36"
+proc test36 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $OVSEC_KADM_STRUCT_VERSION $no_api_version_mask \
+		    server_handle
+	} "BAD_API_VERSION" 
+}
+test36
+
+test "init 37"
+proc test37 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $OVSEC_KADM_STRUCT_VERSION $old_api_version \
+		    server_handle
+	} "OLD_LIB_API_VERSION" 
+}
+if { $RPC } test37
+
+test "init 38"
+proc test38 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $OVSEC_KADM_STRUCT_VERSION $old_api_version \
+		    server_handle
+	} "OLD_SERVER_API_VERSION" 
+}
+if { ! $RPC } test38
+
+test "init 39"
+proc test39 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $OVSEC_KADM_STRUCT_VERSION $new_api_version \
+		    server_handle
+	} "NEW_LIB_API_VERSION" 
+}
+if { $RPC } test39
+
+test "init 40"
+proc test40 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $OVSEC_KADM_STRUCT_VERSION $new_api_version \
+		    server_handle
+	} "NEW_SERVER_API_VERSION" 
+}
+if { ! $RPC } test40
+
+test "init 41"
+proc test41 {} {
+	global test
+	one_line_fail_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $OVSEC_KADM_API_VERSION_1 $OVSEC_KADM_STRUCT_VERSION \
+		    server_handle
+	} "BAD_"
+}
+test41
+
+test "init 42"
+proc test42 {} {
+	global test
+	one_line_succeed_test {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+	    	    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    server_handle
+	}
+	if {! [cmd {ovsec_kadm_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test42
+
+
+proc test45_46 {service} {
+    global test kadmin_local env
+
+    spawn $kadmin_local -q "delprinc -force $service"
+    expect {
+	-re "Principal .* deleted." {}
+	default {
+	    perror "kadmin.local delprinc failed\n";
+	}
+    }
+    expect eof
+    wait
+
+    one_line_fail_test [concat {ovsec_kadm_init admin admin } \
+	    $service \
+	    { null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+	    server_handle}] "SECURE_PRINC_MISSING"
+
+    # this leaves the keytab with an incorrect entry
+    spawn $kadmin_local -q "ank -randkey $service"
+    expect eof
+    wait
+
+    # restart the api so it gets a new ccache
+    api_exit
+    api_start
+}
+
+if {$RPC} {
+    test "init 45"
+
+    test45_46 ovsec_adm/admin
+
+    test "init 46"
+
+    test45_46 ovsec_adm/changepw
+
+    # re-extract the keytab so it is right
+    exec rm $env(K5ROOT)/ovsec_adm.srvtab
+    exec $env(MAKE_KEYTAB) -princ ovsec_adm/admin -princ ovsec_adm/changepw \
+	    -princ kadmin/admin -princ kadmin/changepw \
+	    $env(K5ROOT)/ovsec_adm.srvtab
+}
+
+return ""
+
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/mod-policy.exp b/mechglue/src/lib/kadm5/unit-test/api.0/mod-policy.exp
new file mode 100644
index 000000000..ec55999b7
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/mod-policy.exp
@@ -0,0 +1,703 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "modify-policy 2"
+proc test2 {} {
+    global test
+
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MAX_LIFE}
+    } $test] "AUTH_MODIFY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test2 }
+
+test "modify-policy 4"
+proc test4 {} {
+    global test
+    
+    if {! ([policy_exists "$test/a"] ||
+	   [create_policy "$test/a"])} {
+            error_and_restart "$test: couldn't create policy \"$test/a\""
+            return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_REF_COUNT}
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test4
+
+test "modify-policy 8"
+proc test8 {} {
+    global test
+#    set prms_id 744
+#    setup_xfail {*-*-*} $prms_id
+
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_modify_policy $server_handle [simple_policy ""] \
+		{OVSEC_KADM_PW_MAX_LIFE}
+    } "BAD_POLICY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test8
+
+test "modify-policy 9"
+proc test9 {} {
+    global test
+    global prompt
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MIN_LIFE}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 1\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test9
+
+test "modify-policy 10"
+proc test10 {} {
+    global test
+    global prompt
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle {"%s/a" 32 0 0 0 0 0} \
+		{OVSEC_KADM_PW_MIN_LIFE}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 1\n"
+    expect {
+	-re "32\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test10
+
+
+test "modify-policy 11"
+proc test11 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MAX_LIFE}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test11
+
+test "modify-policy 12"
+proc test12 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle {"%s/a" 0 32 0 0 0 0} \
+		{OVSEC_KADM_PW_MAX_LIFE}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "32\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+test "modify-policy 13"
+proc test13 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MIN_LENGTH}
+    } $test] "BAD_LENGTH"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test13
+
+test "modify-policy 14"
+proc test14 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 8 0 0 0} \
+		{OVSEC_KADM_PW_MIN_LENGTH}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 3\n"
+    expect {
+	-re "8\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test14
+
+test "modify-policy 15"
+proc test15 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MIN_CLASSES}
+    } $test] "BAD_CLASS"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+test "modify-policy 16"
+proc test16 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 1 0 0} \
+		{OVSEC_KADM_PW_MIN_CLASSES}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 4\n"
+    expect {
+	-re "1\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test16
+
+test "modify-policy 17"
+proc test17 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 5 0 0} \
+		{OVSEC_KADM_PW_MIN_CLASSES}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 4\n"
+    expect {
+	-re "5\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test17
+
+test "modify-policy 18"
+proc test18 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 6 0 0} \
+		{OVSEC_KADM_PW_MIN_CLASSES}
+    } $test] "BAD_CLASS"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test18
+
+test "modify-policy 19"
+proc test19 {} {
+    global test
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_HISTORY_NUM}
+    } $test] "BAD_HISTORY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test19
+
+test "modify-policy 20"
+proc test20 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 0 1 0} \
+		{OVSEC_KADM_PW_HISTORY_NUM}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 5\n"
+    expect {
+	-re "1\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test20
+
+test "modify-policy 21"
+proc test21 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 0 10 0} \
+		{OVSEC_KADM_PW_HISTORY_NUM}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 5\n"
+    expect {
+	-re "10\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test21
+
+test "modify-policy 22"
+proc test22 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MAX_LIFE}
+    } $test] "AUTH_MODIFY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test22
+
+test "modify-policy 23"
+proc test23 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MAX_LIFE}
+    } $test] "AUTH_MODIFY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test23
+
+test "modify-policy 26"
+proc test26 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MAX_LIFE}
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test26
+
+test "modify-policy 30"
+proc test30 {} {
+    global test
+
+    one_line_fail_test [format {
+	ovsec_kadm_modify_policy null [simple_policy "%s/a"] \
+		{OVSEC_KADM_PW_MAX_LIFE}
+    } $test] "BAD_SERVER_HANDLE"
+}
+test30
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/mod-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.0/mod-principal.exp
new file mode 100644
index 000000000..d6a9cbc90
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/mod-principal.exp
@@ -0,0 +1,1942 @@
+load_lib lib.t
+api_exit
+api_start
+
+#test "modify-principal 1"
+#proc test1 {} {
+#	global test
+#	one_line_fail_test [format {
+#	    ovsec_kadm_modify_principal $server_handle [simple_principal \
+#		    "%s/a"] {OVSEC_KADM_PW_EXPIRATION}
+#	} $test] "NOT_INIT"
+#}
+#test1
+
+test "modify-principal 2"
+proc test2 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MODIFY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test2 }
+
+test "modify-principal 4"
+proc test4 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINCIPAL}
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test4
+
+
+test "modify-principal 5"
+proc test5 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_LAST_PWD_CHANGE}
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test5
+
+test "modify-principal 6"
+proc test6 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_MOD_TIME}
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test6
+
+test "modify-principal 7"
+proc test7 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_MOD_NAME}
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test7
+
+test "modify-principal 8"
+proc test8 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_MKVNO}
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test8
+
+test "modify-principal 9"
+proc test9 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_AUX_ATTRIBUTES}
+    } $test] "BAD_MASK"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test9
+
+test "modify-principal 10"
+proc test10 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test] "UNK_PRINC"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test10
+
+test "modify-principal 11"
+proc test11 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MOD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test11 }
+
+test "modify-principal 12"
+proc test12 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MOD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test12 }
+
+test "modify-principal 13"
+proc test13 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MOD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test13 }
+
+test "modify-principal 14"
+proc test14 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MOD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test14 }
+
+test "modify-principal 15"
+proc test15 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+test "modify-principal 17"
+proc test17 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		no-policy] {OVSEC_KADM_POLICY}
+    } $test] "UNK_POLICY"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test17
+
+test "modify-principal 18"
+proc test18 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal "$test/a"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {OVSEC_KADM_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol\n$prompt$"	{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    send "lindex \$p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$oldref + 1"] != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test18
+
+test "modify-principal 19"
+proc test19 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal "$test/a"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {OVSEC_KADM_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol\n$prompt$"	{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    send "lindex \$p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$oldref + 1"] != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test19
+
+test "modify-principal 20"
+proc test20 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal_pol "$test/a" "test-pol"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_POLICY_CLR}
+    } $test]]} {
+	perror "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol\n$prompt$"	{ fail "$test" }
+	timeout				{ pass "$test" }
+    }
+    send "lindex \$p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$oldref - 1"] != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test20
+
+test "modify-principal 21"
+proc test21 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal_pol "$test/a" "test-pol"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol old_p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol-nopw old_p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol-nopw] {OVSEC_KADM_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$old_p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set old_p1_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    send "lindex \$old_p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set old_p2_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol new_p1}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol-nopw new_p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$new_p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set new_p1_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    send "lindex \$new_p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set new_p2_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$old_p1_ref - 1"] != $new_p1_ref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { [expr "$old_p2_ref + 1"] != $new_p2_ref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test21
+
+test "modify-principal 21.5"
+proc test21.5 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal_pol "$test/a" "test-pol"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol old_p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {OVSEC_KADM_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$old_p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set old_p1_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol new_p1}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$new_p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set new_p1_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+
+    if {$old_p1_ref != $new_p1_ref} {
+	fail "$test: policy reference count changed ($old_p1_ref to $new_p1_ref)"
+	return
+    }
+
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test21.5
+
+test "modify-principal 22"
+proc test22 {} {
+    global test
+    global prompt
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modifiy failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test22
+
+test "modify-principal 23"
+proc test23 {} {
+    global test
+    global prompt
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" test-pol-nopw])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modifiy failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test23
+
+test "modify-principal 24"
+proc test24 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" "test-pol" ])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	error_and_restart "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PW_EXPIRATION}
+    } $test]]} {
+    	fail "$test: could not modify principal"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_get_policy $server_handle %s policy
+    } test-pol]]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+    send "lindex \$principal 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { $pw_expire != 0 } {
+	fail "$test: pw_expire $pw_expire should be 0"
+	return
+    } else {
+	pass "$test"
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { 
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test24
+
+test "modify-principal 25"
+proc test25 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {OVSEC_KADM_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test25
+
+test "modify-principal 26"
+proc test26 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" "test-pol-nopw" ])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {OVSEC_KADM_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test26
+
+test "modify-principal 27"
+proc test27 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" "test-pol" ])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {OVSEC_KADM_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test27
+
+test "modify-principal 28"
+proc test28 {} {
+    global test
+    global prompt
+#    set prms_id 1358
+#    setup_xfail {*-*-*} $prms_id    
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" "test-pol" ])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 999999999 0 0 0 0 0 0 0 0} {OVSEC_KADM_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy}]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+    send "lindex \$principal 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { $pw_expire != 999999999 } {
+	fail "$test: pw_expire $pw_expire should be 999999999"
+	return
+    }
+    pass "$test"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test28
+
+test "modify-principal 29"
+proc test29 {} {
+    global test
+    global prompt
+    
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { ! ([create_principal_pol "$test/a" test-pol])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_POLICY_CLR}
+    } $test]]} {
+	fail "$test: modifiy failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test29
+
+test "modify-principal 30"
+proc test30 {} {
+    global test
+    global prompt
+
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal_pol "$test/a" test-pol])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol-nopw] {OVSEC_KADM_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test30
+
+test "modify-principal 31"
+proc test31 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {OVSEC_KADM_POLICY}
+    } $test]]} {
+	fail "modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy}]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+    send "lindex \$principal 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { [expr "$pw_mod_date + $pw_max_life"] != $pw_expire } {
+	fail "$test: pw_expire is wrong"
+	return
+    }
+
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test31
+
+test "modify-principal 32"
+proc test32 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	error_and_restart "$test: couldn't delete principal \"$test/a\""
+	return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 1234 0 0 0 0 0 0 0 0 0 0} \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 1\n"
+    expect {
+	-re "1234\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test32
+
+test "modify-principal 33"
+proc test33 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 0 0 0 0 KRB5_KDB_DISALLOW_ALL_TIX 0 0 0 0} \
+		{OVSEC_KADM_ATTRIBUTES}
+    } $test]]} {
+	fail "$test: modified fail"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 7\n"
+    expect {
+	-re "KRB5_KDB_DISALLOW_ALL_TIX.*$prompt$"		{ pass "$test" }
+	timeout							{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test33
+
+test "modify-principal 33.25"
+proc test3325 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 0 0 0 0 KRB5_KDB_REQUIRES_PWCHANGE 0 0 0 0} \
+		{OVSEC_KADM_ATTRIBUTES}
+    } $test]]} {
+	fail "$test: modified fail"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 7\n"
+    expect {
+	-re "KRB5_KDB_REQUIRES_PWCHANGE.*$prompt$"		{ pass "$test" }
+	timeout							{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test3325
+
+test "modify-principal 33.5"
+proc test335 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 0 0 0 0 KRB5_KDB_DISALLOW_TGT_BASED 0 0 0 0} \
+		{OVSEC_KADM_ATTRIBUTES}
+    } $test]]} {
+	fail "$test: modified fail"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 7\n"
+    expect {
+	-re "KRB5_KDB_DISALLOW_TGT_BASED.*$prompt$"		{ pass "$test" }
+	timeout							{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test335
+
+
+test "modify-principal 34"
+proc test34 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 0 3456 0 0 0 0 0 0 0} {OVSEC_KADM_MAX_LIFE}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 4\n"
+    expect {
+	-re "3456\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test34
+
+test "modify-principal 35"
+proc test35 {} {
+    global prompt
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle \
+		{"%s/a" 0 0 0 0 0 0 0 7 0 0 0} {OVSEC_KADM_KVNO}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 8\n"
+    expect {
+	-re "7\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test35
+
+test "modify-principal 36"
+proc test36 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal_pol "$test/a" "test-pol"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol pol}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {OVSEC_KADM_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol\n$prompt$"	{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    send "lindex \$pol 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol pol2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    send "lindex \$pol2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { $oldref != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test36
+
+test "modify-principal 37"
+proc test37 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal "$test/a"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_POLICY_CLR}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test37
+
+test "modify-principal 38"
+proc test38 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 1\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test38
+
+test "modify-principal 39"
+proc test39 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \
+		{OVSEC_KADM_MAX_LIFE}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_get_principal $server_handle "%s/a" principal
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 4\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test39
+
+test "modify-principal 40"
+proc test40 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_modify_principal $server_handle null \
+		{OVSEC_KADM_PRINC_EXPIRE_TIME}
+    } "EINVAL"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test40
+
+test "modify-principal 43"
+proc test43 {} {
+	global test
+	one_line_fail_test [format {
+	    ovsec_kadm_modify_principal null [simple_principal \
+		    "%s/a"] {OVSEC_KADM_PW_EXPIRATION}
+	} $test] "BAD_SERVER_HANDLE"
+}
+test43
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/randkey-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.0/randkey-principal.exp
new file mode 100644
index 000000000..c96700194
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/randkey-principal.exp
@@ -0,0 +1,319 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "randkey-principal 1"
+proc test1 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd [format {
+	ovsec_kadm_init "%s/a" "%s/a" $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    } $test $test]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test] "PASS_TOOSOON"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test1 } 
+
+test "randkey-principal 3"
+proc test3 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd [format {
+	ovsec_kadm_init "%s/a" "%s/a" $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    } $test $test]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test] "PASS_TOOSOON"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if ${RPC} { test3 } 
+
+test "randkey-principal 13"
+proc test13 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \
+		once-a-min] OVSEC_KADM_POLICY
+    } $test]]} {
+	perror "$test: failed modify"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test13
+
+test "randkey-principal 15"
+proc test15 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test] "AUTH_CHANGEPW"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test15 }
+
+test "randkey-principal 28"
+proc test28 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test28
+
+test "randkey-principal 28.25"
+proc test2825 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test] "AUTH"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test2825 }
+
+test "randkey-principal 28.5"
+proc test285 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test285
+
+test "randkey-principal 30"
+proc test30 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal "$test/a"]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    if {! [cmd [format {
+	ovsec_kadm_init "%s/a" "%s/a" $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    } $test $test]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test30
+
+test "randkey-principal 31"
+proc test31 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal "$test/a"]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd [format {
+	ovsec_kadm_init "%s/a" "%s/a" $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    } $test $test]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_randkey_principal $server_handle "%s/a" key
+    } $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test31
+
+test "randkey-principal 32"
+proc test32 {} {
+    global test
+
+    if { ! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	ovsec_kadm_randkey_principal $server_handle kadmin/history key
+    } "PROTECT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test32
+
+test "randkey-principal 33"
+proc test33 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if { ! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_randkey_principal null "%s/a" key
+    } $test] "BAD_SERVER_HANDLE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+
+test33
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.0/rename-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.0/rename-principal.exp
new file mode 100644
index 000000000..d5f012f8b
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.0/rename-principal.exp
@@ -0,0 +1,509 @@
+load_lib lib.t
+api_exit
+api_start
+
+#test "rename-principal 1"
+#proc test1 {} {
+#	global test
+#	one_line_fail_test [format {
+#	    ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+#	} $test $test] "NOT_INIT"
+#}
+#test1
+
+test "rename-principal 2"
+proc test2 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "INSUFFICIENT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+
+}
+if {$RPC} { test2 }
+
+test "rename-principal 3"
+proc test3 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_INSUFFICIENT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test3 }
+
+test "rename-principal 4"
+proc test4 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_INSUFFICIENT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test4 }
+
+test "rename-principal 5"
+proc test5 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_INSUFFICIENT"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test5 }
+
+test "rename-principal 6"
+proc test6 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/mod-add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test6 }
+
+test "rename-principal 7"
+proc test7 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/mod-delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test7 }
+
+test "rename-principal 8"
+proc test8 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/get-add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test8 }
+
+test "rename-principal 9"
+proc test9 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/get-delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test9 }
+
+test "rename-principal 10"
+proc test10 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/no-delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_DELETE"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test10 }
+
+test "rename-principal 11"
+proc test11 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/no-add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH_ADD"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test11 }
+
+test "rename-principal 12"
+proc test12 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test12 }
+
+
+test "rename-principal 13"
+proc test13 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "AUTH"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test13 }
+
+test "rename-principal 14"
+proc test14 {} {
+    global test
+    
+    if {[principal_exists "$test/a"]} {
+	delete_principal "$test/a"
+    }
+
+    if {[create_principal_with_keysalts "$test/a" "des-cbc-crc:v4"]} {
+	error_and_restart "$test: couldn't create no-salt principal \"$test/a\""
+	return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/rename admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test]
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test14
+
+test "rename-principal 15"
+proc test15 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( [principal_exists "$test/b"]) ||
+	   [create_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/rename admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "DUP"
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+test "rename-principal 16"
+proc test16 {} {
+	global test
+	one_line_fail_test [format {
+	    ovsec_kadm_rename_principal null "%s/a" "%s/b"
+	} $test $test] "BAD_SERVER_HANDLE"
+}
+test16
+
+test "rename-principal 18"
+proc test18 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! (( ! [principal_exists "$test/b"]) ||
+	   [delete_principal "$test/b"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	ovsec_kadm_init admin/rename admin $OVSEC_KADM_ADMIN_SERVICE null \
+		$OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b"
+    } $test $test] "NO_RENAME_SALT"
+
+    if { ! [cmd {ovsec_kadm_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test18
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.1/lock.exp b/mechglue/src/lib/kadm5/unit-test/api.1/lock.exp
new file mode 100644
index 000000000..02df75bf7
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.1/lock.exp
@@ -0,0 +1,287 @@
+# This is in api.1 so that it happens after all the tests in api.0.
+# If some API function does not unlock the database then the server
+# (whichs runs through all api tests) will still have it locked, and
+# these tests will fail.
+
+load_lib lib.t
+
+api_exit
+
+if { $RPC } {
+    return
+}
+
+send_user "UNTESTED: lock: DAL changes broke locking code (see MIT RT ticket 3201)\n"
+untested "lock: DAL changes broke locking code (see MIT RT ticket 3201)"
+return
+
+set locktest $LOCKTEST
+set lockfile $env(K5ROOT)/kdb5.kadm5.lock
+
+# The lock tests use the program lock-test in the unit test
+# directory.  The basic idea is that lock-test can be told to acquire
+# various kinds of locks and then wait for input before proceeding;
+# this is necessary because otherwise we'd have no way to test locking
+# interactions without a race condition.
+#
+# lock_test_start and lock_test_continue work together to give a crude
+# form of continuations.  lock_test_continue expects a list of
+# commands for lock-test (passed on the command line) and responses
+# (read from stdout).  When it gets to a command of "wait",
+# lock_test_continue returns, and its return value is a list of the
+# arguments that it should be passed to continue processing that
+# particular list of commands for that particular lock-test after
+# whatever that requried lock-test to wait has been completed.
+#
+# lock_test is simply a wrapper for tests that do not involve wait.
+
+proc lock_test_setup {test cmds} {
+    global locktest spawn_id
+
+    verbose "test $test"
+
+    set cmdline ""
+    foreach cmdpair $cmds {
+	if {[lindex $cmdpair 0] == "eof"} {
+	    break
+	}
+	set cmdline "$cmdline [lindex $cmdpair 0]"
+    }
+
+    verbose "spawning $locktest $cmdline"
+    eval "spawn $locktest $cmdline"
+}
+
+proc lock_test {test cmds} {
+    global spawn_id
+
+    lock_test_setup $test $cmds
+    set lockany [lock_test_continue $test $spawn_id 0 "" 0 $cmds]
+    while {$lockany != {}} {
+	set lockany [eval lock_test_continue $lockany]
+    }
+}
+
+proc lock_test_start {test cmds} {
+    global spawn_id
+
+    lock_test_setup $test $cmds
+    return [lock_test_continue $test $spawn_id 0 "" 0 $cmds]
+}
+
+proc lock_test_continue {test my_spawn_id test_failed fail_output cont cmds} {
+    global wait_error_index wait_errno_index wait_status_index
+    global spawn_id
+
+    set spawn_id $my_spawn_id
+
+    if {$cont == 1} {
+	send -i $spawn_id "\n"
+    }
+
+    while {[llength $cmds] > 0} {
+	set cmdpair [lindex $cmds 0]
+	set cmds [lrange $cmds 1 end]
+	set cmd [lindex $cmdpair 0]
+	set output [lindex $cmdpair 1]
+
+	verbose "test $test: command: $cmd"
+
+	if {$cmd == "wait"} {
+	    # ah, for continuations...
+	    return [list $test $spawn_id $test_failed $fail_output 1 $cmds]
+	} 
+	if {$cmd == "eof"} {
+	    set status $output
+	    set output "doesnotmatchanything"
+	}
+
+	expect {
+	    -i $spawn_id
+	    -re "$output" { verbose "test $test: read: $output" }
+	    timeout {
+		set test_failed 1
+		set fail_output "timeout while waiting for $output"
+	    }
+	    eof {
+		if {$cmd != "eof"} {
+		    set test_failed 1
+		    set fail_output "eof while waiting for $output"
+		}
+	    }
+	}
+
+	if {$test_failed == 1} { break }
+    }
+
+    # In timeout cases, the process may not be dead yet.
+    catch { exec kill -9 [exp_pid -i $spawn_id] } x
+    set ret [wait -i $spawn_id]
+    verbose "% Exit $ret" 2
+
+    if {$test_failed == 0} {
+	if {[lindex $ret $wait_error_index] == -1} {
+	    set test_failed 1
+	    set fail_output "wait returned error [lindex $ret $wait_errno_index]"
+	} else {
+	    if { [lindex $ret $wait_status_index] == $status ||
+	    (($status<0) && ([lindex $ret $wait_status_index] == ($status+256))) } {
+		verbose "test $test: status $status"
+	    } else {
+		set test_failed 1
+		set fail_output "unexpected return status [lindex $ret $wait_status_index], should be $status"
+	    }
+	}
+    }
+    
+    if {$test_failed == 0} {
+	pass $test 
+    } else { 
+	fail "$test: $fail_output"
+    }
+
+    return {}
+}
+
+set lock1 [lock_test_start 1 [list \
+	[list shared	"shared"] \
+	[list release	"released"] \
+	[list wait	""] \
+	[list eof	0]]]
+eval lock_test_continue $lock1
+
+set lock2 [lock_test_start 2 [list \
+	[list exclusive	exclusive] \
+	[list release	released] \
+	[list wait	""] \
+	[list eof	0]]]
+eval lock_test_continue $lock2
+
+set lock3 [lock_test_start 5 [list \
+	[list permanent	permanent] \
+	[list release	released] \
+	[list wait	""] \
+	[list eof	0]]]
+eval lock_test_continue $lock3
+
+set lock4 [lock_test_start 4 [list \
+	[list release	"Database not locked"] \
+	[list wait	""] \
+	[list eof	0]]]
+eval lock_test_continue $lock4
+
+set lock5 [lock_test_start 5 [list \
+	[list shared	shared] \
+	[list wait	""] \
+	[list eof	0]]]
+set lock5_1 [lock_test_start 5.1 [list \
+	[list shared	shared] \
+	[list wait	""] \
+	[list eof	0]]]
+eval lock_test_continue $lock5_1
+eval lock_test_continue $lock5
+
+set lock6 [lock_test_start 6 [list \
+	[list exclusive exclusive] \
+	[list wait	""] \
+	[list eof	0]]]
+set lock6_1 [lock_test_start 6.1 [list \
+	[list shared	"Cannot lock database"] \
+	[list wait	""] \
+	[list eof	0]]]
+eval lock_test_continue $lock6_1
+eval lock_test_continue $lock6
+
+set lock7 [lock_test_start 7 [list \
+	[list shared	shared] \
+	[list wait	""] \
+	[list eof	0]]]
+set lock7_1 [lock_test_start 7.1 [list \
+	[list exclusive	"Cannot lock database"] \
+	[list wait	""] \
+	[list eof	0]]]
+eval lock_test_continue $lock7_1
+eval lock_test_continue $lock7
+
+set lock8 [lock_test_start 8 [list \
+	[list permanent	permanent] \
+	[list wait	""] \
+	[list release	"released" ] \
+	[list wait	""] \
+	[list eof	0]]]
+set lock8_1 [lock_test_start 8.1 [list \
+	[list "" "administration database lock file missing while opening database" ] \
+	[list wait	""] \
+	[list eof	1]]]
+eval lock_test_continue $lock8_1
+eval set lock8 \[lock_test_continue $lock8\]
+eval lock_test_continue $lock8
+
+set lock9 [lock_test_start 9 [list \
+	[list exclusive exclusive] \
+	[list release released] \
+	[list wait	""] \
+	[list exclusive	"database lock file missing while getting exclusive"] \
+	[list wait	""] \
+	[list eof	0]]]
+set lock9_1 [lock_test_start 9.1 [list \
+	[list permanent	permanent] \
+	[list wait	""] \
+	[list release	released] \
+	[list wait	""] \
+	[list eof	0]]]
+eval set lock9 \[lock_test_continue $lock9\]
+eval lock_test_continue $lock9
+eval set lock9_1 \[lock_test_continue $lock9_1\]
+eval lock_test_continue $lock9_1
+
+if {! [file exists $lockfile]} {
+    perror "lock file missing before test 10"
+}
+set lock10 [lock_test_start 10 [list \
+	[list permanent	permanent] \
+	[list wait	""] \
+	[list release	released] \
+	[list wait	""] \
+	[list eof	0]]]
+if {[file exists $lockfile]} {
+    fail "test 10: lock file exists"
+}
+eval set lock10 \[lock_test_continue $lock10\]
+eval lock_test_continue $lock10
+if {[file exists $lockfile]} {
+    pass "test 11: lock file exists"
+} else {
+    fail "test 11: lock file does not exist"
+}
+
+set lock12 [lock_test_start 12 [list \
+	[list shared	shared] \
+	[list wait	""] \
+	[list eof	0]]]
+set lock12_1 [lock_test_start 12.1 [list \
+	[list "get test-pol"	retrieved] \
+	[list wait	""] \
+	[list eof	0]]]
+eval lock_test_continue $lock12_1
+eval lock_test_continue $lock12
+
+set lock13 [lock_test_start 13 [list \
+	[list "get lock13"	"Principal or policy does not exist"] \
+	[list wait	""] \
+	[list "get lock13"	retrieved] \
+	[list wait	""] \
+	[list eof	0]]]
+set test13_spawn_id $spawn_id
+# create_policy could call api_exit immediately when it starts up.
+# If it does, and the spawn ID in $spawn_id is ours rather than its,
+# it'll close our spawn ID.  So, we call api_start to give it something
+# to close.
+api_start
+create_policy lock13
+set api_spawn_id $spawn_id
+set spawn_id $test13_spawn_id
+eval set lock13 \[lock_test_continue $lock13\]
+eval lock_test_continue $lock13
+set spawn_id $api_spawn_id
+delete_policy lock13
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp b/mechglue/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp
new file mode 100644
index 000000000..d249af0d9
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp
@@ -0,0 +1,68 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "chpass-principal 200"
+proc test200 {} {
+    global test prompt
+
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal "$test/a"]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+
+    # I'd like to specify a long list of keysalt tuples and make sure
+    # that chpass does the right thing, but we can only use those
+    # enctypes that krbtgt has a key for: des-cbc-crc:normal and
+    # des-cbc-crc:v4, according to the prototype kdc.conf.
+    if {! [cmd [format {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_chpass_principal $server_handle "%s/a" newpassword
+    } $test]]} {
+	perror "$test: unexpected failure in chpass_principal"
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle  "%s/a" p \
+		{KADM5_PRINCIPAL_NORMAL_MASK KADM5_KEY_DATA}
+    } $test]]} {
+	perror "$test: unexpected failure in get_principal"
+    }
+    send "lindex \$p 16\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" { set num_keys $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting num_keys"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting num_keys"
+	    return
+	}
+    }
+
+    # XXX Perhaps I should actually check the key type returned.
+    if {$num_keys == 3} {
+	pass "$test"
+    } else {
+	fail "$test: $num_keys keys, should be 3"
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test200
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/chpass-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.2/chpass-principal.exp
new file mode 100644
index 000000000..0571df20c
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/chpass-principal.exp
@@ -0,0 +1,176 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "chpass-principal 180"
+proc test180 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_chpass_principal $server_handle "%s/a" FoobarBax
+    } $test]
+
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test180 }
+
+test "chpass-principal 180.5"
+proc test1805 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_chpass_principal $server_handle "%s/a" FoobarBax
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test1805 }
+
+#
+# admin with changepw service tickets try to change other principals
+# password, failes with AUTH error
+test "chpass-principal 180.625"
+proc test180625 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_chpass_principal $server_handle "%s/a" password
+    } $test] "AUTH"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test180625 }
+
+test "chpass-principal 180.75"
+proc test18075 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_chpass_principal $server_handle "%s/a" Foobar
+    } $test] "AUTH_CHANGEPW"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test18075 }
+
+test "chpass-principal 182"
+proc test182 {} {
+    global test
+
+    if { ! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_chpass_principal $server_handle kadmin/history password
+    } "PROTECT"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test182
+
+test "chpass-principal 183"
+proc test183 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if { ! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_chpass_principal null "%s/a" password
+    } $test] "BAD_SERVER_HANDLE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test183
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/crte-policy.exp b/mechglue/src/lib/kadm5/unit-test/api.2/crte-policy.exp
new file mode 100644
index 000000000..f11253c2c
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/crte-policy.exp
@@ -0,0 +1,991 @@
+load_lib lib.t
+api_exit
+api_start
+
+# Description: (1) Fails for mask with undefined bit set.
+# 01/24/94: pshuang: untried.
+test "create-policy 1"
+proc test1 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+           [delete_policy "$test/a"])} {
+            error_and_restart "$test: couldn't delete policy \"$test/a\""
+            return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		0xF01000
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test1
+
+# Description: (2) Fails if caller connected with CHANGEPW_SERVICE.
+test "create-policy 2"
+proc test2 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy";
+	return
+    }
+}
+if {$RPC} { test2 }
+
+# Description: (3) Fails for mask without POLICY bit set.
+# 01/24/94: pshuang: untried.
+test "create-policy 3"
+proc test3 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+           [delete_policy "$test/a"])} {
+            error_and_restart "$test: couldn't delete policy \"$test/a\""
+            return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		0x000000
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test3
+
+# Description: (4) Fails for mask with REF_COUNT bit set.
+test "create-policy 4"
+proc test4 {} {
+    global test
+    
+    if {! (( ! [policy_exists "$test/a"]) ||
+           [delete_policy "$test/a"])} {
+            error_and_restart "$test: couldn't delete policy \"$test/a\""
+            return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY KADM5_REF_COUNT}
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test4
+
+# Description: (5) Fails for invalid policy name.
+# 01/24/94: pshuang: untried.
+test "create-policy 5"
+proc test5 {} {
+    global test
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/"] \
+		{KADM5_POLICY}
+    } $test] "BAD_POLICY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test5
+
+# Description: (6) Fails for existing policy name.
+test "create-policy 6"
+proc test6 {} {
+    global test
+#    set prms_id 777
+#    setup_xfail {*-*-*} $prms_id
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_create_policy $server_handle [simple_policy test-pol] \
+		{KADM5_POLICY}
+    } "DUP"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test6
+
+# Description: (7) Fails for null policy name.
+# 01/24/94: pshuang: untried.
+test "create-policy 7"
+proc test7 {} {
+    global test
+#    set prms_id 1977
+#    setup_xfail {*-*-*} $prms_id
+    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_create_policy $server_handle [simple_policy null] \
+		{KADM5_POLICY}
+    } "EINVAL"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test7
+
+# Description: (8) Fails for empty-string policy name.
+test "create-policy 8"
+proc test8 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_create_policy $server_handle [simple_policy ""] \
+		{KADM5_POLICY}
+    } "BAD_POLICY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test8
+
+# Description: (9) Accepts 0 for pw_min_life.
+test "create-policy 9"
+proc test9 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY KADM5_PW_MIN_LIFE}
+    } $test]]} {
+	fail "$test: create failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 1\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test9
+
+# Description: (10) Accepts non-zero for pw_min_life.
+test "create-policy 10"
+proc test10 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_create_policy $server_handle {"%s/a" 32 0 0 0 0 0 } \
+		{KADM5_POLICY KADM5_PW_MIN_LIFE}
+    } $test]]} {
+	fail "$test"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 1\n"
+    expect {
+	-re "32\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test10
+
+# Description: (11) Accepts 0 for pw_max_life.
+test "create-policy 11"
+proc test11 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY KADM5_PW_MAX_LIFE}
+    } $test]]} {
+	fail "$test"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test11
+
+# Description: (12) Accepts non-zero for pw_max_life.
+test "create-policy 12"
+proc test12 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_policy $server_handle {"%s/a" 0 32 0 0 0 0 } \
+		{KADM5_POLICY KADM5_PW_MAX_LIFE}
+    } $test]]} {
+	fail "$test"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "32\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+# Description: (13) Rejects 0 for pw_min_length.
+test "create-policy 13"
+proc test13 {} {
+    global test
+    global prompt
+
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY KADM5_PW_MIN_LENGTH}
+    } $test] "BAD_LENGTH"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test13
+
+# Description: (14) Accepts non-zero for pw_min_length.
+test "create-policy 14"
+proc test14 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_policy $server_handle {"%s/a" 0 0 8 0 0 0 } \
+		{KADM5_POLICY KADM5_PW_MIN_LENGTH}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 3\n"
+    expect {
+	-re "8\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test14
+
+# Description: (15) Rejects 0 for pw_min_classes.
+test "create-policy 15"
+proc test15 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY KADM5_PW_MIN_CLASSES}
+    } $test] "BAD_CLASS"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+# Description: (16) Accepts 1 for pw_min_classes.
+test "create-policy 16"
+proc test16 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_policy $server_handle {"%s/a" 0 0 0 1 0 0 } \
+		{KADM5_POLICY KADM5_PW_MIN_CLASSES}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 4\n"
+    expect {
+	-re "1\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test16
+
+# Description: (17) Accepts 4 for pw_min_classes.
+test "create-policy 17"
+proc test17 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_policy $server_handle {"%s/a" 0 0 0 5 0 0} \
+		{KADM5_POLICY KADM5_PW_MIN_CLASSES}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 4\n"
+    expect {
+	-re "5\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test17
+
+# Description: (18) Rejects 5 for pw_min_classes.
+test "create-policy 18"
+proc test18 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle {"%s/a" 0 0 0 6 0 0} \
+		{KADM5_POLICY KADM5_PW_MIN_CLASSES}
+    } $test] "BAD_CLASS"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test18
+
+# Description: (19) Rejects 0 for pw_history_num.
+test "create-policy 19"
+proc test19 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY KADM5_PW_HISTORY_NUM}
+    } $test] "BAD_HISTORY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test19
+
+# Description: (20) Accepts 1 for pw_history_num.
+test "create-policy 20"
+proc test20 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd  [format {
+	kadm5_create_policy $server_handle {"%s/a" 0 0 0 0 1 0} \
+		{KADM5_POLICY KADM5_PW_HISTORY_NUM}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retreuve policy"
+	return
+    }
+    send "lindex \$policy 5\n"
+    expect {
+	-re "1\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test20
+
+# Description: (21) Accepts 10 for pw_history_num.
+test "create-policy 21"
+proc test21 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_policy $server_handle {"%s/a" 0 0 0 0 10 0} \
+		{KADM5_POLICY KADM5_PW_HISTORY_NUM}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 5\n"
+    expect {
+	-re "10\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test21
+    
+# Description: (21.5) Rejects 11 for pw_history_num.
+# 01/24/94: pshuang: untried.
+
+test "create-policy 21.5"
+proc test215 {} {
+    global test
+    global prompt
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle {"%s/a" 0 0 0 0 11 0} \
+		{KADM5_POLICY KADM5_PW_HISTORY_NUM}
+    } $test] "BAD_HISTORY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test215
+
+
+# Description: (22) Fails for user with no access bits.
+test "create-policy 22"
+proc test22 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test22
+
+# Description: (23) Fails for user with "get" but not "add".
+test "create-policy 23"
+proc test23 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test23
+
+# Description: (24) Fails for user with "modify" but not "add".
+# 01/24/94: pshuang: untried.
+test "create-policy 24"
+proc test24 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test24
+
+# Description: (25) Fails for user with "delete" but not "add".
+# 01/24/94: pshuang: untried.
+test "create-policy 25"
+proc test25 {} {
+    global test
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY}
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test25
+
+# Description: Succeeds for user with "add".
+test "create-policy 26"
+proc test26 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY}
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test26
+
+# Description: Succeeds for user with "get" and "add".
+# 01/24/94: pshuang: untried.
+test "create-policy 27"
+proc test27 {} {
+    global test
+
+    if {! (( ! [policy_exists "$test/a"]) ||
+	   [delete_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/get-add admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_create_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_POLICY}
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test27
+
+# Description: (28) Rejects null policy argument.
+# 01/24/94: pshuang: untried.
+test "create-policy 28"
+proc test28 {} {
+    global test
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_create_policy $server_handle null {KADM5_POLICY}
+    } "EINVAL"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test28
+
+test "create-policy 30"
+proc test30 {} {
+    global test
+    one_line_fail_test [format {
+	kadm5_create_policy null [simple_policy "%s/a"] \
+		{KADM5_POLICY}
+    } $test] "BAD_SERVER_HANDLE"
+}
+test30
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/crte-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.2/crte-principal.exp
new file mode 100644
index 000000000..8a84af271
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/crte-principal.exp
@@ -0,0 +1,1335 @@
+load_lib lib.t
+api_exit
+api_start
+
+#test "create-principal 1"
+#
+#proc test1 {} {
+#	global test
+#	begin_dump
+#	one_line_fail_test [format {
+#	    kadm5_create_principal $server_handle \
+#		    [simple_principal "%s/a"] {KADM5_PRINCIPAL} "%s/a"
+#	} $test $test] "NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test1
+
+test "create-principal 2"
+
+proc test2 {} {
+    global test
+    begin_dump
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_create_principal $server_handle null \
+		{KADM5_PRINCIPAL} testpass
+    } "EINVAL"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"
+}
+test2
+
+test "create-principal 3"
+proc test3 {} {
+    global test
+#    set prms_id 777
+#    setup_xfail {*-*-*} $prms_id
+    begin_dump
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} null
+    } $test] "EINVAL"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+test3
+
+test "create-principal 4"
+proc test4 {} {
+    global test
+
+    begin_dump    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} ""
+    } $test] "_Q_TOOSHORT"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"     
+}
+test4
+
+test "create-principal 5"
+proc test5 {} {
+    global test
+    begin_dump    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle \
+		[simple_principal "%s/a"] {0x100001} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+test5
+
+test "create-principal 6"
+proc test6 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_LAST_PWD_CHANGE} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test6
+
+test "create-principal 7"
+proc test7 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_MOD_TIME} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test7
+
+test "create-principal 8"
+proc test8 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_MOD_NAME} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test8
+
+test "create-principal 9"
+proc test9 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_MKVNO} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test9
+
+test "create-principal 10"
+proc test10 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_AUX_ATTRIBUTES} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test10
+
+test "create-principal 11"
+proc test11 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_POLICY_CLR} "%s/a"
+    } $test $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test11
+
+test "create-principal 12"
+proc test12 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+
+}
+if {$RPC} { test12 }
+
+test "create-principal 13"
+proc test13 {} {
+    global test
+    begin_dump        
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+if {$RPC} { test13 }
+
+test "create-principal 14"
+proc test14 {} {
+    global test
+    begin_dump        
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+if {$RPC} { test14 }
+
+test "create-principal 15"
+proc test15 {} {
+    global test
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+if {$RPC} { test15 }
+
+test "create-principal 16"
+proc test16 {} {
+    global test
+    begin_dump        
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+if {$RPC} { test16 }
+
+test "create-principal 17"
+proc test17 {} {
+    global test
+
+    begin_dump    
+    if {! (( [principal_exists "$test/a"]) || [create_principal "$test/a"])} {
+		error_and_restart "$test: couldn't create principal \"$test/a\""
+		return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test] "DUP"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test17
+
+test "create-principal 18"
+proc test18 {} {
+    global test
+
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{KADM5_PRINCIPAL KADM5_POLICY} tP
+    } $test] "_Q_TOOSHORT"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"    
+}
+test18
+
+test "create-principal 19"
+proc test19 {} {
+    global test
+
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{KADM5_PRINCIPAL KADM5_POLICY} testpassword
+    } $test] "_Q_CLASS"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test19
+
+test "create-principal 20"
+proc test20 {} {
+    global test
+
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{KADM5_PRINCIPAL KADM5_POLICY} Abyssinia
+    } $test] "_Q_DICT"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test20
+
+test "create-principal 21"
+proc test21 {} {
+    global test
+
+    begin_dump    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_create_principal $server_handle \
+		[princ_w_pol "%s/a" non-existant-pol] \
+		{KADM5_PRINCIPAL KADM5_POLICY} NotinTheDictionary
+    } $test] "UNK_POLICY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    end_dump_compare "no-diffs"        
+}
+test21
+
+test "create-principal 23"
+proc test23 {} {
+    global test
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    one_line_succeed_test \
+	    [format {kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK} $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test23
+
+test "create-principal 24"
+proc test24 {} {
+    global test
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/rename admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    one_line_succeed_test \
+	    [format {kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK} $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test24 }
+
+
+test "create-principal 28"
+proc test28 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{KADM5_PRINCIPAL KADM5_POLICY} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol.*$prompt$"   { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test28
+
+test "create-principal 29"
+proc test29 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL KADM5_PRINC_EXPIRE_TIME} \
+		inTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 1\n"
+    expect {
+	-re "0.*$prompt$"   { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test29
+
+test "create-principal 30"
+proc test30 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL KADM5_PW_EXPIRATION} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test30
+
+test "create-principal 31"
+proc test31 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol-nopw] \
+		{KADM5_PRINCIPAL KADM5_POLICY \
+		KADM5_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test31
+
+test "create-principal 32"
+proc test32 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle \
+		[princ_w_pol "%s/a" test-pol] \
+		{KADM5_PRINCIPAL KADM5_POLICY \
+		KADM5_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol policy}]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+
+    send "lindex \$principal 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { $pw_expire != 0 } {
+	fail "$test: pw_expire $pw_expire should be 0"
+	return
+    } else {
+	pass "$test"
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test32
+
+test "create-principal 33"
+proc test33 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle \
+		{"%s/a" 0 0 1234 0 null 0 0 0 0 null 0} \
+		{KADM5_PRINCIPAL KADM5_PW_EXPIRATION} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test33
+
+test "create-principal 34"
+proc test34 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle \
+		{ "%s/a" 0 0 1234 0 null 0 0 0 0 test-pol-nopw 0} \
+		{KADM5_PRINCIPAL KADM5_POLICY \
+		KADM5_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test34
+
+test "create-principal 35"
+proc test35 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle \
+		{"%s/a" 0 0 1234 0 null 0 0 0 0 test-pol 0} \
+		{KADM5_PRINCIPAL KADM5_POLICY \
+		KADM5_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test35
+
+test "create-principal 36"
+proc test36 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle \
+		{"%s/a" 0 0 999999999 0 null 0 0 0 0 test-pol 0} \
+		{KADM5_PRINCIPAL KADM5_POLICY \
+		KADM5_PW_EXPIRATION} NotinTheDictionary
+    } $test]]} {    
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol policy} ]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+
+    send "lindex \$principal 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { $pw_expire != 999999999 } {
+	fail "$test: pw_expire is wrong"
+	return
+    } else {
+	pass "$test"
+    }
+
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test36
+
+test "create-principal 37"
+proc test37 {} {
+    global test
+    global prompt
+
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test37
+
+test "create-principal 38"
+proc test38 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol-nopw] {KADM5_PRINCIPAL KADM5_POLICY} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test38
+
+test "create-principal 39"
+proc test39 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {KADM5_PRINCIPAL KADM5_POLICY} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if { ! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: cannot not retrieve principal"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol policy}]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+    send "lindex \$principal 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } {
+	fail "$test: pw_expire is wrong"
+	return
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test39
+
+test "create-principal 40"
+proc test40 {} {
+    global test
+    global prompt
+    
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL KADM5_PW_EXPIRATION} \
+		NotinTheDictionary
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: can not retreive principal"
+	return;
+    }
+    send "lindex \$principal 4\n"
+    expect {
+	-re "0.*$prompt$"	    { pass "$test" }
+	timeout			    { fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test40
+
+test "create-principal 43"
+proc test43 {} {
+    global test
+    one_line_fail_test [format {
+	kadm5_create_principal null \
+		    [simple_principal "%s/a"] {KADM5_PRINCIPAL} "%s/a"
+    } $test $test] "BAD_SERVER_HANDLE"
+}
+test43
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/destroy.exp b/mechglue/src/lib/kadm5/unit-test/api.2/destroy.exp
new file mode 100644
index 000000000..744cacd21
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/destroy.exp
@@ -0,0 +1,203 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "destroy 1"
+
+proc test1 {} {
+	global test
+	begin_dump
+	if {! [cmd {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+	}]} {
+		perror "$test: unexpected failure in init"
+		return
+	}
+	one_line_succeed_test {kadm5_destroy $server_handle}
+	end_dump_compare "no-diffs"
+}
+test1
+
+#test "destroy 2"
+#
+#proc test2 {} {
+#	global test
+#	begin_dump
+#	if {! [cmd {
+#	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+#		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		    server_handle
+#	}]} {
+#	    perror "$test: unexpected failure on init"
+#	    return
+#	}
+#	if {! [cmd {kadm5_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#		return
+#	}
+#	one_line_fail_test \
+#		{kadm5_get_principal $server_handle admin principal} \
+#		"NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test2
+
+#test "destroy 3"
+#proc test3 {} {
+#	global test
+#
+#	begin_dump
+#	if {! (( ! [principal_exists "$test/a"]) || [delete_principal "$test/a"])} {
+#	    error_and_restart "$test couldn't delete principal \"$test/a\""
+#	    return
+#	}
+#	if {! [cmd {
+#	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+#		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		    server_handle
+#	}]} {
+#	    perror "$test: unexpected failure on init"
+#	    return
+#	}
+#	if {! [cmd {kadm5_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#		return
+#	}
+#	one_line_fail_test [format {
+#	    kadm5_create_principal $server_handle \
+#		    [simple_principal "%s/a"] {KADM5_PRINCIPAL} "%s/a"
+#	} $test $test] "NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test3
+
+#test "destroy 4"
+#proc test4 {} {
+#	global test prompt
+#
+#	if {! (([principal_exists "$test/a"]) || [create_principal "$test/a"])} {
+#		error_and_restart "$test: couldn't create principal \"$test/a\""
+#		return
+#	}
+#	begin_dump
+#	if {! ([cmd {
+#	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+#		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		    server_handle
+#	}] &&
+#	    [cmd [format {
+#		kadm5_get_principal $server_handle "%s/a" principal
+#	    } $test]])} {
+#		error_and_restart "$test: error getting principal"
+#		return;
+#	}
+#	if {! [cmd {kadm5_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#		return
+#	}
+#	one_line_fail_test [format {
+#	    kadm5_modify_principal $server_handle \
+#		    {"%s/a" 0 0 0 0 0 0 0 %d 0 0 0} {KADM5_KVNO}
+#	} $test "77"] "NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test4
+
+#test "destroy 5"
+#
+#proc test5 {} {
+#	global test
+#
+#	if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+#		error_and_restart "$test: couldn't create principal \"$test/a\""
+#		return
+#	}
+#	begin_dump
+#	if {! [cmd {
+#	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+#		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		    server_handle
+#	}]} {
+#	    perror "$test: unexpected failure on init"
+#	    return
+#	}
+#	if {! [cmd {kadm5_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#		return
+#	}
+#	one_line_fail_test [format {
+#	    kadm5_delete_principal $server_handle "%s/a"
+#	} $test] "NOT_INIT"
+#	end_dump_compare "no-diffs"
+#}
+#test5
+
+#test	"destroy 6"
+#
+#proc test6 {} {
+#	global test
+#	begin_dump	
+#	one_line_fail_test {kadm5_destroy $server_handle} "NOT_INIT"
+#	end_dump_compare "no-diffs"	
+#}
+#test6
+
+
+#test	"destroy 7"
+#
+#proc test7 {} {
+#	global test
+#	begin_dump	
+#	if {! [cmd {
+#	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+#		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		    server_handle
+#	}]} {
+#		perror "$test: unexpected failure in init"
+#		return
+#	}
+#	if {! [cmd {kadm5_destroy $server_handle}]} {
+#		error_and_restart "$test: couldn't close database"
+#	}
+#	one_line_fail_test {kadm5_destroy $server_handle} "NOT_INIT"
+#	end_dump_compare "no-diffs"	
+#}
+#test7
+
+test	"destroy 8"
+proc test8 {} {
+	global test
+	begin_dump	
+	if {! [cmd {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}]} {
+		perror "$test: unexpected failure in init"
+		return
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+	one_line_succeed_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+	end_dump_compare "no-diffs"		
+}
+test8
+
+test "destroy 9"
+proc test9 {} {
+	global test
+	one_line_fail_test {kadm5_destroy null} "BAD_SERVER_HANDLE"
+}
+test9
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/dlte-policy.exp b/mechglue/src/lib/kadm5/unit-test/api.2/dlte-policy.exp
new file mode 100644
index 000000000..c2a53182a
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/dlte-policy.exp
@@ -0,0 +1,207 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "delete-policy 2"
+proc test2 {} {
+    global test
+#    set prms_id 744
+#    setup_xfail {*-*-*} $prms_id
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test \
+	    {kadm5_delete_policy $server_handle ""} "BAD_POL"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test2
+
+test "delete-policy 5"
+proc test5 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_policy $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if ${RPC} test5
+
+test "delete-policy 6"
+proc test6 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_policy $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if ${RPC} test6
+
+test "delete-policy 7"
+proc test7 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_policy $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test7
+
+test "delete-policy 10"
+proc test10 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_delete_policy $server_handle  "%s/a"
+    } $test]]} {
+	fail "$test"
+	return
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    if { [policy_exists "$test/a"]} {
+	fail "$test"
+	return
+    }
+}
+test10
+
+test "delete-policy 12"
+proc test12 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+    if {! ((! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test unexecpted failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [princ_w_pol "%s/a" \
+		"%s/a"] {KADM5_PRINCIPAL KADM5_POLICY} \
+		NotinTheDictionary
+    } $test $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test \
+	    {kadm5_delete_policy $server_handle test-pol} "POLICY_REF"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+test "delete-policy 13"
+proc test13 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_policy null "%s/a"
+    } $test] "BAD_SERVER_HANDLE"
+}
+test13
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/dlte-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.2/dlte-principal.exp
new file mode 100644
index 000000000..f9dad7801
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/dlte-principal.exp
@@ -0,0 +1,329 @@
+load_lib lib.t
+
+api_exit
+api_start
+
+#test "delete-principal 1"
+#proc test1 {} {
+#	global test
+#	one_line_fail_test [format {
+#	    kadm5_delete_principal $server_handle "%s/a"
+#	} $test] "NOT_INIT"
+#}
+#test1
+
+test "delete-principal 2"
+proc test2 {} {
+    global test
+   
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	error_and_restart "$test: couldn't delete principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test \
+	    {kadm5_delete_principal $server_handle null} "EINVAL"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	error_and_restart "$test: unexpected failure in destroy"
+	return
+    }
+}
+test2
+
+test "delete-principal 5"
+proc test5 {} {
+    global test
+   
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	error_and_restart "$test: couldn't delete principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_principal $server_handle "%s/a"
+    } $test] "UNK_PRINC"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test5
+
+test "delete-principal 6"
+proc test6 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" test-pol])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test6 }
+    
+	
+test "delete-principal 7"
+proc test7 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test7 }
+    
+	
+test "delete-principal 8"
+proc test8 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test8 }
+
+test "delete-principal 9"
+proc test9 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test9 }
+
+test "delete-principal 10"
+proc test10 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_delete_principal $server_handle "%s/a"
+    } $test] "AUTH_DELETE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test10 }
+
+test "delete-principal 11"
+proc test11 {} {
+    global test
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_delete_principal $server_handle "%s/a"
+    } $test]]} {
+	fail "$test: delete failed"
+	return;
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    if { [principal_exists "$test/a"] } {
+	fail "$test"
+	return
+    }
+}
+test11
+
+test "delete-principal 12"
+proc test12 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" test-pol])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_delete_principal $server_handle "%s/a"
+    } $test]]} {
+	fail "$test: delete failed"
+	return
+    }
+    if { [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	fail "$test: principal still exists"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    send "lindex \$p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    
+    send "lindex \$p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$oldref - 1"] != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    pass "$test"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+
+test12
+
+test "delete-principal 13"
+proc test13 {} {
+	global test
+	one_line_fail_test [format {
+	    kadm5_delete_principal null "%s/a"
+	} $test] "BAD_SERVER_HANDLE"
+}
+test13
+    
+return ""
+
+
+
+
+
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/get-policy.exp b/mechglue/src/lib/kadm5/unit-test/api.2/get-policy.exp
new file mode 100644
index 000000000..83aef80e8
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/get-policy.exp
@@ -0,0 +1,199 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "get-policy 3"
+proc test3 {} {
+    global test
+#    set prms_id 744
+#    setup_xfail {*-*-*} $prms_id
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {kadm5_get_policy $server_handle "" p} "BAD_POLICY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test3
+
+test "get-policy 6"
+proc test6 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+	    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	    server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {kadm5_get_policy $server_handle test-pol p} \
+	    "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } test6
+
+test "get-policy 7"
+proc test7 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \
+	    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	    server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {kadm5_get_policy $server_handle test-pol p} \
+	    "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } test7
+
+test "get-policy 11"
+proc test11 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin/get-pol StupidAdmin $KADM5_ADMIN_SERVICE \
+		null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {kadm5_get_policy $server_handle test-pol p}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test11
+
+test "get-policy 12"
+proc test12 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin/get-pol StupidAdmin \
+		$KADM5_CHANGEPW_SERVICE null $KADM5_STRUCT_VERSION \
+		$KADM5_API_VERSION_2 server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {kadm5_get_policy $server_handle test-pol-nopw p}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+test "get-policy 15"
+proc test15 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin/pol StupidAdmin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {kadm5_get_policy $server_handle test-pol-nopw p}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+test "get-policy 16"
+proc test16 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin/pol StupidAdmin $KADM5_CHANGEPW_SERVICE \
+		null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {kadm5_get_policy $server_handle test-pol-nopw p}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test16
+
+test "get-policy 17"
+proc test17 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \
+	    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	    server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {kadm5_get_policy $server_handle test-pol p}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test17
+
+test "get-policy 18"
+proc test18 {} {
+    global test
+
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {kadm5_get_policy $server_handle test-pol p} \
+	    "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } test18
+
+test "get-policy 21"
+proc test21 {} {
+    global test
+
+    one_line_fail_test {kadm5_get_policy null "pol1" p} "BAD_SERVER_HANDLE"
+}
+test21
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp b/mechglue/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp
new file mode 100644
index 000000000..65c28b808
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp
@@ -0,0 +1,250 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "get-principal 100"
+proc test100 {} {
+    global test prompt
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd {
+	kadm5_get_principal $server_handle testuser p \
+		{KADM5_PRINCIPAL_NORMAL_MASK}
+    }]} {
+	perror "$test: unexpected failure in get_principal"
+    }
+    send "lindex \$p 16\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" { set num_keys $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting num_keys"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting num_keys"
+	    return
+	}
+    }
+    send "lindex \$p 17\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" { set num_tl $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting num_tl"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting num_tl"
+	    return
+	}
+    }
+    send "lindex \$p 18\n"
+    expect {
+	-re "({.*})\n$prompt" {set key_data $expect_out(1,string) }
+	-re "\n$prompt" { set key_data {} }
+	timeout {
+	    error_and_restart "$test: timeout getting key_data"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting key_data"
+	    return
+	}
+    }
+    send "lindex \$p 19\n"
+    expect {
+	-re "({.*})\n$prompt" {set tl_data $expect_out(1,string) }
+	-re "\n$prompt" { set tl_data {} }
+	timeout {
+	    error_and_restart "$test: timeout getting tl_data"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting tl_data"
+	    return
+	}
+    }
+    
+    set failed 0
+    if {$num_keys != 0} {
+	fail "$test: num_keys $num_keys should be 0"
+	set failed 1
+    }
+    if {$num_tl != 0} {
+	fail "$test: num_tl $num_tl should be 0"
+	set failed 1
+    }
+    if {$key_data != {}} {
+	fail "$test: key_data $key_data should be {}"
+	set failed 1
+    }
+    if {$tl_data != "{}"} {
+	fail "$test: tl_data $tl_data should be empty"
+	set failed 1
+    }
+    if {$failed == 0} {
+	pass "$test"
+    }
+
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test100
+
+proc test101_102 {rpc} {
+    global test prompt
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd {
+	kadm5_get_principal $server_handle testuser p \
+		{KADM5_PRINCIPAL_NORMAL_MASK KADM5_KEY_DATA}
+    }]} {
+	perror "$test: unexpected failure in get_principal"
+    }
+    send "lindex \$p 16\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" { set num_keys $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting num_keys"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting num_keys"
+	    return
+	}
+    }
+    send "lindex \$p 18\n"
+    expect {
+	-re "({.*})\n$prompt" {set key_data $expect_out(1,string) }
+	-re "\n$prompt" { set key_data {} }
+	timeout {
+	    error_and_restart "$test: timeout getting key_data"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting key_data"
+	    return
+	}
+    }
+
+    set failed 0
+    if {$num_keys != 3} {
+	fail "$test: num_keys $num_keys should be 3"
+	set failed 1
+    }
+    for {set i 0} {$i < $num_keys} {incr i} {
+	set key "[lindex [lindex $key_data $i] 2]"
+	if {($rpc && [string compare $key ""] != 0) ||
+	    ((! $rpc) && [string compare $key ""] == 0)} {
+	    fail "$test: key_data $key is wrong"
+	    set failed 1
+	    
+	}
+    }
+    if {$failed == 0} { pass "$test" }
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test "get-principal 101" 
+if {$RPC} {test101_102 $RPC}
+test "get-principal 102" 
+if {! $RPC} {test101_102 $RPC}
+
+test "get-principal 103"
+proc test103 {} {
+    global test prompt
+
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		"{%s/a} 0 0 0 0 {%s/a} 0 0 0 0 null 0 0 0 0 0 0 1 {} {{999 6 foobar}}" \
+		{KADM5_TL_DATA}
+    } $test $test]]} {
+	fail "$test: cannot set TL_DATA"
+	return
+    }
+
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle {%s/a} p \
+		{KADM5_PRINCIPAL_NORMAL_MASK KADM5_TL_DATA}
+    } $test]]} {
+	perror "$test: unexpected failure in get_principal"
+    }
+    send "lindex \$p 17\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" { set num_tl $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting num_tl"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting num_tl"
+	    return
+	}
+    }
+    send "lindex \$p 19\n"
+    expect {
+	-re "({.*})\n$prompt" {set tl_data $expect_out(1,string) }
+	-re "\n$prompt" { set tl_data {} }
+	timeout {
+	    error_and_restart "$test: timeout getting tl_data"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting tl_data"
+	    return
+	}
+    }
+    
+    if {$num_tl == 0} {
+	fail "$test: num_tl $num_tl should not be 0"
+    } elseif {$tl_data == "{{999 6 foobar}}"} {
+	pass "$test"
+    } else {
+	fail "$test: tl_data $tl_data should be {{999 6 foobar}}"
+    }
+
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test103
+
+return ""
+
+
+
+
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/get-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.2/get-principal.exp
new file mode 100644
index 000000000..f7a73078d
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/get-principal.exp
@@ -0,0 +1,346 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "get-principal 1"
+proc test1 {} {
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test \
+	    {kadm5_get_principal $server_handle null p KADM5_PRINCIPAL_NORMAL_MASK} "EINVAL"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test1
+
+test "get-principal 2"
+proc test2 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK
+    } $test] "UNK_PRINC"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test2
+
+test "get-principal 3"
+proc test3 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK
+    } $test] "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test3 }
+    
+test "get-principal 4"
+proc test4 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK
+    } $test] "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test4 }
+
+test "get-principal 5"
+proc test5 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK
+    } $test] "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test5 }
+
+test "get-principal 6"
+proc test6 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK
+    } $test] "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test6 }
+
+test "get-principal 7"
+proc test7 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK
+    } $test] "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test7 }
+
+    
+test "get-principal 8"
+proc test8 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK
+    } $test] "AUTH_GET"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test8 }
+
+    
+test "get-principal 9"
+proc test9 {} {
+    global test
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {kadm5_get_principal $server_handle admin/none p KADM5_PRINCIPAL_NORMAL_MASK} 
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test9
+
+test "get-principal 10"
+proc test10 {} {
+    global test
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test \
+	    {kadm5_get_principal $server_handle admin/none p KADM5_PRINCIPAL_NORMAL_MASK}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test10
+
+test "get-principal 11"
+proc test11 {} {
+    global test
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {kadm5_get_principal $server_handle admin/get p KADM5_PRINCIPAL_NORMAL_MASK}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test11
+
+test "get-principal 12"
+proc test12 {} {
+    global test
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {kadm5_get_principal $server_handle admin/get p KADM5_PRINCIPAL_NORMAL_MASK}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+test "get-principal 13"
+proc test13 {} {
+    global test
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {kadm5_get_principal $server_handle admin/add p KADM5_PRINCIPAL_NORMAL_MASK} 
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test13
+
+test "get-principal 14"
+proc test14 {} {
+    global test
+    if {! [cmd {
+	kadm5_init admin/get-mod admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test {kadm5_get_principal $server_handle admin/add p KADM5_PRINCIPAL_NORMAL_MASK}
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test14
+
+test "get-principal 15"
+proc test15 {} {
+    one_line_fail_test \
+	    {kadm5_get_principal null "admin" p KADM5_PRINCIPAL_NORMAL_MASK} "BAD_SERVER_HANDLE"
+}
+test15
+
+return ""
+
+
+
+
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/init-v2.exp b/mechglue/src/lib/kadm5/unit-test/api.2/init-v2.exp
new file mode 100644
index 000000000..8d78794ba
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/init-v2.exp
@@ -0,0 +1,648 @@
+load_lib lib.t
+
+api_exit
+api_start
+
+test "init 100"
+proc test100 {} {
+    global test
+
+    # We used to check for ENOENT, but kadm5_get_config_params no
+    # longer fails if it cannot find the file---it just provides
+    # defaults instead.... XXX will fail on srv test!
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_PROFILE} /does-not-exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "MISSING_KRB5_CONF_PARAMS"
+}
+if {$RPC} test100
+
+if ![info exists RESOLVE] {
+    set RESOLVE [findfile $objdir/../../../tests/resolve/resolve]
+}
+proc get_hostname { } {
+    global RESOLVE
+    global hostname
+    global localhostname
+    global domain
+
+    if {[info exists hostname] && [info exists localhostname]} {
+	return 1
+    }
+
+    catch "exec $RESOLVE -q >myname" exec_output
+    if ![string match "" $exec_output] {
+	send_log "$exec_output\n"
+	verbose $exec_output
+	send_error "ERROR: can't get hostname\n"
+	return 0
+    }
+    set file [open myname r]
+    if { [ gets $file hostname ] == -1 } {
+	send_error "ERROR: no output from hostname\n"
+	return 0
+    }
+    close $file
+    catch "exec rm -f myname" exec_output
+    regexp "^(\[^.\]*)\.(.*)$" $hostname foo localhostname domain
+
+    set hostname [string tolower $hostname]
+    set localhostname [string tolower $localhostname]
+    set domain [string tolower $domain]
+    verbose "hostname: $hostname; localhostname: $localhostname; domain $domain"
+
+    return 1
+}
+
+
+test "init 101"
+proc test101 {} {
+    global test
+    global hostname
+
+    get_hostname
+    tcl_cmd "set hostname $hostname"
+
+    # XXX Fix to work with a remote TEST_SERVER.  For now, make sure
+    # it fails in that case.
+    one_line_succeed_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ADMIN_SERVER KADM5_CONFIG_KADMIND_PORT} [list $hostname 1751]] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ADMIN_SERVER KADM5_CONFIG_KADMIND_PORT} [list $hostname 4]] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "RPC_ERROR"
+}
+if {$RPC} test101
+
+test "init 102"
+proc test102 {} {
+    global test
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ADMIN_SERVER} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_SERVER_NAME"
+}
+if {$RPC} test102
+
+test "init 103"
+proc test103 {} {
+    global test
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_DBNAME} /does-not-exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "ENOENT"
+}
+#if {! $RPC} test103
+if {! $RPC} {
+    send_user "UNTESTED: test103: test needs updating for DAL changes (see MIT RT ticket 3202)\n"
+    untested "test103: test needs updating for DAL changes (see MIT RT ticket 3202)"
+}
+
+
+test "init 106"
+proc test106 {} {
+    global test prompt
+
+    set prompting 0
+    send [string trim {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_MKEY_FROM_KBD} 1] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]
+    send "\n"
+    expect {
+	-re "\n\[^\n\]+:\[^\n\]*$" { set prompting 1}
+	-re "\nOK .*$prompt$" { fail "$test: premature success" }
+	-re "\nERROR .*$prompt$" { fail "$test: premature failure" }
+	timeout { fail "$test: timeout" }
+	eof { fail "$test: eof" }
+    }
+    if {$prompting} {
+	one_line_succeed_test mrroot
+    }
+    if {! [cmd {kadm5_destroy $server_handle}]} {
+	error_and_restart "$test: couldn't close database"
+    }
+}
+if {! $RPC} test106
+
+test "init 107"
+proc test107 {} {
+    global test
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_STASH_FILE} /does-not-exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "KDB_CANTREAD_STORED"
+}
+if {! $RPC} test107
+
+test "init 108"
+proc test108 {} {
+    global test
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_MKEY_NAME} does/not/exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "KDB_NOMASTERKEY"
+}
+if {! $RPC} test108
+
+test "init 109-113"
+proc test109 {} {
+    global test prompt
+
+    delete_principal "$test/a"
+
+    # I'd like to specify flags explicitly and check them, as in the
+    # following config_params, but tcl gets mighty confused if I do and 
+    # I have no idea why.
+#		[config_params {KADM5_CONFIG_MAX_LIFE KADM5_CONFIG_MAX_RLIFE KADM5_CONFIG_EXPIRATION KADM5_CONFIG_FLAGS KADM5_CONFIG_ENCTYPES} {10 20 30 KRB5_KDB_DISALLOW_TGT_BASED {}} ]
+    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_MAX_LIFE KADM5_CONFIG_MAX_RLIFE KADM5_CONFIG_EXPIRATION KADM5_CONFIG_ENCTYPES} {10 20 30 {}} ] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	fail "$test: cannot init with max_life"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test]]} {
+	fail "$test: can not create principal"
+	return;
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" p \
+		{KADM5_PRINCIPAL_NORMAL_MASK KADM5_KEY_DATA}
+    } $test]]} {
+	fail "$test: can not get principal"
+	return;
+    }
+    send "puts \$p\n"
+    expect {
+	-re "$prompt" { }
+	timeout {
+	    error_and_restart "$test: timeout getting prompt"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting prompt"
+	    return
+	}
+    }
+    send "lindex \$p 4\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting max_life"
+	    return
+	}
+    }
+    send "lindex \$p 12\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set max_rlife $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting max_rlife"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting max_rlife"
+	    return
+	}
+    }
+    send "lindex \$p 1\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set expiration $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting expiration"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting expiration"
+	    return
+	}
+    }
+    send "lindex \$p 7\n"
+    expect {
+	-re "(\[A-Z_\]*)\n$prompt" {set flags $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting flags"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting flags"
+	    return
+	}
+    }
+    # This sorta worries me.  Since the test is setting ENCTYPES to
+    # nothing, the principal has no keys.  That means that nothing is
+    # printed for the keys in the correct case; but it feels too
+    # likely that nothing will be printed in the case of some problem.
+    send "lindex \$p 18\n"
+    expect {
+	-re "({.*})\n$prompt" {set key_data $expect_out(1,string) }
+	-re "\n$prompt" { set key_data {} }
+	timeout {
+	    error_and_restart "$test: timeout getting flags"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting flags"
+	    return
+	}
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+    if {$max_life == 10} {
+	pass "$test"
+    } else {
+	fail "$test: $max_life is not 10"
+    }
+    if {$max_rlife == 20} {
+	pass "$test"
+    } else {
+	fail "$test: $max_rlife is not 20"
+    }
+    if {$expiration == 30} {
+	pass "$test"
+    } else {
+	fail "$test: $expiration is not 30"
+    }
+    if {$flags == ""} {
+	pass "$test"
+    } else {
+	fail "$test: flags $flags are wrong"
+    }
+    if {$key_data == {}} {
+	pass "$test"
+    } else {
+	fail "$test: key_data $key_data is wrong"
+    }
+}
+if {! $RPC} test109
+
+test "init 114"
+proc test114 {} {
+    global test
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ADMIN_SERVER} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_SERVER_PARAMS"
+}
+if {! $RPC} test114
+
+test "init 115"
+proc test115 {} {
+    global test
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_DBNAME} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ADBNAME} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ACL_FILE} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_DICT_FILE} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ADMIN_KEYTAB} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_MKEY_FROM_KBD} 0] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_STASH_FILE} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_MKEY_NAME} does.not.exist] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ENCTYPE} 0] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_MAX_LIFE} 0] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_MAX_RLIFE} 0] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_EXPIRATION} 0] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_FLAGS} 0] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+		[config_params {KADM5_CONFIG_ENCTYPES} {{}}] \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "BAD_CLIENT_PARAMS"
+}
+if {$RPC} test115
+
+test "init 116"
+proc test116 {} {
+    global test
+
+    delete_principal "$test/a"
+
+    if {! [cmd {kadm5_init admin/get-add admin $KADM5_ADMIN_SERVICE \
+	    null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	    get_add_handle}]} {
+	error_and_restart "$test: couldn't init with admin/get-add"
+    }
+
+    if {! [cmd {kadm5_init admin/mod-delete admin $KADM5_ADMIN_SERVICE \
+	    null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	    mod_delete_handle}]} {
+	error_and_restart "$test: couldn't init with admin/get-add"
+    }
+
+    one_line_succeed_test {
+	kadm5_get_principal $get_add_handle testuser p \
+		KADM5_PRINCIPAL_NORMAL_MASK
+    }
+    one_line_succeed_test [format {
+	kadm5_create_principal $get_add_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test]
+    one_line_fail_test { 
+	kadm5_modify_principal $get_add_handle [simple_principal testuser] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } "AUTH_MODIFY"
+    one_line_fail_test {
+	kadm5_delete_principal $get_add_handle testuser
+    } "AUTH_DELETE"
+
+    one_line_fail_test {
+	kadm5_get_principal $mod_delete_handle testuser p \
+		KADM5_PRINCIPAL_NORMAL_MASK
+    } "AUTH_GET"
+    one_line_fail_test [format {
+	kadm5_create_principal $mod_delete_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} testpass
+    } $test] "AUTH_ADD"
+    one_line_succeed_test { 
+	kadm5_modify_principal $mod_delete_handle [simple_principal testuser] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    }
+    one_line_succeed_test [format {
+	kadm5_delete_principal $mod_delete_handle "%s/a"
+    } $test]
+
+    if {! [cmd {kadm5_destroy $get_add_handle}]} {
+	error_and_restart "$test: couldn't close get_add_handle"
+    }
+    if {! [cmd {kadm5_destroy $mod_delete_handle}]} {
+	error_and_restart "$test: couldn't close mod_delete_handle"
+    }
+}
+if {$RPC} test116
+
+test "init 117"
+proc test117 {} {
+    global test env prompt
+
+    if {[catch "exec grep max_life $env(KRB5_KDC_PROFILE)"] != 1} {
+	warning \
+	   "$test: max_life in $env(KRB5_KDC_PROFILE), cannot perform test"
+	return
+    }
+
+    if {! (( ! [principal_exists "$test/a"]) ||
+        [delete_principal "$test/a"])} {
+        error_and_restart "$test: couldn't delete principal \"$test/a\""
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	fail "$test: unexpected failure in init"
+	return
+    }
+
+    if {! [cmd [format {
+	kadm5_create_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL} "%s/a"
+    } $test $test]]} {
+	perror "$test: unexpected failure creating principal"
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_MAX_LIFE
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 4\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting max_life"
+	    return
+	}
+    }
+    
+    if {$max_life == 86400} {
+	pass "$test"
+    } else {
+	fail "$test: max_life $max_life should be 86400"
+    }
+
+    if {! [cmd {kadm5_destroy $server_handle}]} {
+	error_and_restart "$test: couldn't close server_handle"
+    }
+}
+test117
+    
+send "puts \$KADM5_ADMIN_SERVICE\n"
+expect {
+    -re "(\[a-zA-Z/@\]+)\n$prompt" {
+	set KADM5_ADMIN_SERVICE $expect_out(1,string) 
+    }
+    default {
+	error_and_restart "$test: timeout/eof getting admin_service"
+	return
+    }
+}
+
+send "puts \$KADM5_CHANGEPW_SERVICE\n"
+expect {
+    -re "(\[a-zA-Z/@\]+)\n$prompt" {
+	set KADM5_CHANGEPW_SERVICE $expect_out(1,string) 
+    }
+    default {
+	error_and_restart "$test: timeout/eof getting changepw_service"
+	return
+    }
+}
+
+test "init 150"
+proc test150 {} {
+    global test KADM5_ADMIN_SERVICE
+
+    kdestroy
+    kinit testuser notathena "-S $KADM5_ADMIN_SERVICE"
+    one_line_succeed_test {
+	kadm5_init_with_creds testuser null $KADM5_ADMIN_SERVICE \
+		null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }
+    kdestroy
+}
+if {$RPC} test150
+
+test "init 151"
+proc test151 {} {
+    global test KADM5_CHANGEPW_SERVICE
+
+    kdestroy
+    kinit testuser notathena "-S $KADM5_CHANGEPW_SERVICE"
+    one_line_succeed_test {
+	kadm5_init_with_creds testuser null $KADM5_CHANGEPW_SERVICE \
+		null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }
+    kdestroy
+}
+if {$RPC} test151
+
+test "init 152"
+proc test152 {} {
+    global test KADM5_ADMIN_SERVICE
+
+    kdestroy
+    one_line_fail_test {
+	kadm5_init_with_creds testuser null $KADM5_ADMIN_SERVICE \
+		null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "KRB5_FCC_NOFILE"
+}
+if {$RPC} test152
+
+test "init 153"
+proc test153 {} {
+    global test KADM5_ADMIN_SERVICE
+
+    kinit testuser notathena
+    one_line_fail_test {
+	kadm5_init_with_creds testuser null $KADM5_ADMIN_SERVICE \
+		null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "KRB5_CC_NOTFOUND"
+}
+if {$RPC} test153
+
+test "init 154"
+proc test154 {} {
+    global test env
+
+    set orig $env(KRB5_KDC_PROFILE)
+    set env(KRB5_KDC_PROFILE) /does-not-exist
+    api_exit; api_start
+    set env(KRB5_KDC_PROFILE) $orig
+
+    one_line_fail_test {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } "ENOENT"
+
+    api_exit; lib_start_api
+}
+if {! $RPC} test154
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/init.exp b/mechglue/src/lib/kadm5/unit-test/api.2/init.exp
new file mode 100644
index 000000000..335f6e041
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/init.exp
@@ -0,0 +1,732 @@
+load_lib lib.t
+
+# Assumptions:
+# 
+# Principal "admin" exists, with "get", "add", "modify" and "delete"
+#   access bits and password "admin".
+# The string "not-the-password" isn't the password of any user in the database.
+# Database master password is "mrroot".
+
+api_exit
+api_start
+test "init 1"
+
+one_line_fail_test_nochk \
+	{kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+	[config_params {KADM5_CONFIG_REALM} {""}] \
+	 $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle}
+
+test "init 2"
+
+one_line_fail_test_nochk \
+	{kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+	[config_params {KADM5_CONFIG_REALM} {@}] \
+	 $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle}
+
+test "init 2.5"
+
+one_line_fail_test_nochk \
+	{kadm5_init admin admin $KADM5_ADMIN_SERVICE \
+	[config_params {KADM5_CONFIG_REALM} {BAD.REALM}] \
+	 $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle}
+
+test "init 3"
+
+proc test3 {} {
+    global test
+    if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+	error_and_restart "$test: couldn't create principal \"$test/a\""
+	return
+    }
+    one_line_fail_test_nochk [format {
+	kadm5_init admin admin "%s/a" null $KADM5_STRUCT_VERSION \
+		$KADM5_API_VERSION_2 server_handle
+    } $test]
+}
+if {$RPC} { test3 }
+
+test "init 4"
+
+proc test4 {} {
+    global test
+	if {! ((! [principal_exists "$test/a"]) || 
+         [delete_principal "$test/a"])} {
+		error_and_restart "$test: couldn't delete principal \"$test/a\""
+		return
+	}
+		
+	one_line_fail_test_nochk [format {
+	    kadm5_init admin admin "%s/a" null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	} $test]
+}
+if {$RPC} { test4 }
+
+test "init 5"
+
+if {$RPC} {
+    one_line_fail_test_nochk {
+	kadm5_init admin admin admin null $KADM5_STRUCT_VERSION \
+		$KADM5_API_VERSION_2 server_handle
+    }
+}
+
+test "init 6"
+
+proc test6 {} {
+    global test
+
+    send "kadm5_init admin null \$KADM5_ADMIN_SERVICE null \$KADM5_STRUCT_VERSION \$KADM5_API_VERSION_2 server_handle\n"
+
+    expect {
+	-re "assword\[^\r\n\]*:" { }
+	eof {
+		fail "$test: eof instead of password prompt"
+		api_exit
+		api_start
+		return
+	}
+	timeout {
+	    fail "$test: timeout instead of password prompt"
+	    return
+	}
+    }
+    one_line_succeed_test "admin"
+    if {! [cmd {kadm5_destroy $server_handle}]} {
+	error_and_restart "$test: couldn't close database"
+    }
+}
+if { $RPC } { test6 } 
+
+test "init 7"
+proc test7 {} {
+    global test
+
+    send "kadm5_init admin \"\" \$KADM5_ADMIN_SERVICE null \$KADM5_STRUCT_VERSION \$KADM5_API_VERSION_2 server_handle\n"
+
+    expect {
+	-re "assword\[^\r\n\]*:" { }
+	-re "key:$" { }
+	eof {
+		fail "$test: eof instead of password prompt"
+		api_exit
+		api_start
+		return
+	}
+	timeout {
+	    fail "$test: timeout instead of password prompt"
+	    return
+	}
+    }
+    one_line_succeed_test "admin"
+    if {! [cmd {kadm5_destroy $server_handle}]} {
+	error_and_restart "$test: couldn't close database"
+    }
+}
+if { $RPC } { test7 } 
+
+test "init 8"
+
+proc test8 {} {
+    global test
+	if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+		error_and_restart "$test: couldn't create principal \"$test/a\""
+		return
+	}
+ 	one_line_fail_test_nochk [format {
+	    kadm5_init "%s/a" admin $KADM5_ADMIN_SERVICE null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	} $test]
+}
+if {$RPC} { test8 }
+
+test "init 9"
+
+if {$RPC} {
+    global test
+  one_line_fail_test_nochk {
+      kadm5_init admin not-the-password $KADM5_ADMIN_SERVICE null \
+	      $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	      server_handle
+  }
+}
+
+test "init 10"
+
+proc test10 {} {
+	global test
+#	set prms_id 562
+#	setup_xfail {*-*-*} $prms_id
+	one_line_fail_test_nochk {
+	    kadm5_init null admin $KADM5_ADMIN_SERVICE null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+}
+test10
+
+#test "init 11"
+#
+#proc test11 {} {
+#	global test
+#	set prms_id 563
+#	setup_xfail {*-*-*} $prms_id
+#	one_line_fail_test_nochk {
+#	    kadm5_init "" admin $KADM5_ADMIN_SERVICE null \
+#		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		    server_handle
+#	}
+#}
+#test11
+
+test "init 12"
+
+proc test12 {} {
+	global test
+    one_line_fail_test_nochk [format {
+	kadm5_init "%s/a" admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } $test]
+}
+if {$RPC} { test12 }
+
+test "init 13"
+
+proc test13 {} {
+	global test
+    one_line_fail_test_nochk [format {
+	kadm5_init "%s/a@SECURE-TEST.OV.COM" admin \
+		$KADM5_ADMIN_SERVICE null $KADM5_STRUCT_VERSION \
+		$KADM5_API_VERSION_2 server_handle
+    } $test]
+}
+if {$RPC} { test13 }
+
+test "init 14"
+
+proc test14 {} {
+	global test
+    one_line_fail_test_nochk [format {
+	kadm5_init "%s/a@BAD.REALM" admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } $test]
+}
+if {$RPC} { test14 }
+
+test "init 15"
+
+if {$RPC} {
+    one_line_fail_test_nochk {
+	kadm5_init admin@BAD.REALM admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }
+}
+
+test "init 16"
+
+proc test16 {} {
+	global test
+	one_line_succeed_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test16
+
+test "init 17"
+
+proc test17 {} {
+	global test
+	one_line_succeed_test {
+	    kadm5_init admin@SECURE-TEST.OV.COM admin \
+		    $KADM5_ADMIN_SERVICE null $KADM5_STRUCT_VERSION \
+		    $KADM5_API_VERSION_2 server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test17
+
+test "init 18"
+
+proc test18 {} {
+	global test
+	one_line_succeed_test {
+	    kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test18
+
+test "init 19"
+
+proc test19 {} {
+	global test
+	one_line_succeed_test {
+	    kadm5_init admin@SECURE-TEST.OV.COM admin \
+		    $KADM5_ADMIN_SERVICE \
+		    [config_params {KADM5_CONFIG_REALM} {SECURE-TEST.OV.COM}] \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test19
+
+test "init 20"
+
+proc test20 {} {
+	global test
+  if {! [cmd {
+      kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	      $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	      server_handle
+  }]} {
+		error_and_restart "$test: couldn't init database"
+		return
+	}
+	one_line_succeed_test \
+		{kadm5_get_principal $server_handle admin principal KADM5_PRINCIPAL_NORMAL_MASK}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test20
+
+#test "init 21"
+#
+#proc test21 {} {
+#    global test
+#    if {! [cmd {
+#	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+#		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		server_handle
+#    }]} {
+#	error_and_restart "$test: couldn't init database"
+#	return
+#    }
+#    one_line_fail_test_nochk {
+#	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+#		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		server_handle
+#    }
+#    if {! [cmd {kadm5_destroy $server_handle}]} {
+#	error_and_restart "$test: couldn't close database"
+#    }
+#}
+#test21
+
+
+# proc test22 {} {
+# 	global test prompt
+# 	set prompting 0
+# 	send [string trim {
+# 	    kadm5_init admin null null null $KADM5_STRUCT_VERSION \
+# 		    $KADM5_API_VERSION_2 server_handle
+# 	}]
+# 	send "\n"
+# 	expect {
+# 	    -re ":$" { set prompting 1}
+# 	    -re "\nOK .*$prompt$" { fail "$test: premature success" }
+# 	    -re "\nERROR .*$prompt$" { fail "$test: premature failure" }
+# 		timeout { fail "$test: timeout" }
+# 		eof { fail "$test: eof" }
+# 	}
+# 	if {$prompting} {
+# 	    one_line_succeed_test mrroot
+# 	}
+# 	if {! [cmd {kadm5_destroy $server_handle}]} {
+# 	    error_and_restart "$test: couldn't close database"
+# 	}
+# }
+# if {! $RPC} { test22 }
+# 
+# test "init 22.5"
+# proc test225 {} {
+# 	global test prompt
+# 	set prompting 0
+# 	send [string trim {
+# 	    kadm5_init admin null null null $KADM5_STRUCT_VERSION \
+# 		    $KADM5_API_VERSION_2 server_handle
+# 	}]
+# 	send "\n"
+# 	expect {
+# 	    -re ":$" { set prompting 1}
+# 	    -re "\nOK .*$prompt$" { fail "$test: premature success" }
+# 	    -re "\nERROR .*$prompt$" { fail "$test: premature failure" }
+# 		timeout { fail "$test: timeout" }
+# 		eof { fail "$test: eof" }
+# 	}
+# 	if {$prompting} {
+# 	    one_line_succeed_test mrroot
+# 	}
+# 	if {! [cmd {kadm5_destroy $server_handle}]} {
+# 	    error_and_restart "$test: couldn't close database"
+# 	}
+# }
+# if {! $RPC} { test225 }
+
+test "init 23"
+
+proc test23 {} {
+	global test
+	one_line_succeed_test {
+	    kadm5_init admin not-the-password $KADM5_ADMIN_SERVICE \
+		    null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+if {! $RPC} { test23 }
+
+test "init 24"
+
+proc test24 {} {
+	global test
+	one_line_succeed_test {
+	    kadm5_init admin admin null null $KADM5_STRUCT_VERSION \
+		    $KADM5_API_VERSION_2 server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+if {! $RPC} { test24 }
+
+test "init 25"
+
+proc test25 {} {
+	global test
+	one_line_succeed_test {
+	    kadm5_init admin admin foobar null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+if {! $RPC} { test25 }
+
+test "init 26"
+
+#proc test26 {} {
+#	global test
+#
+#	api_exit
+#	api_start
+#	one_line_fail_test_nochk {
+#	    kadm5_get_principal $server_handle admin principal
+#	}
+#}
+#test26
+
+#test "init 27"
+#
+#proc test27 {} {
+#	global test
+#
+#	if {! ((! [principal_exists "$test/a"]) || [delete_principal "$test/a"])} {
+#		error_and_restart "$test: couldn't delete principal \"$test/a\""
+#		return
+#	}
+#	begin_dump
+#	if {[cmd [format {
+#	    kadm5_create_principal $server_handle [simple_principal \
+#		    "%s/a"] {KADM5_PRINCIPAL} "%s/a"
+#	} $test $test]]} {
+#		fail "$test: unexpected success in add"
+#		return
+#	}
+#	end_dump_compare "no-diffs"
+#}
+#test27
+
+#test "init 28"
+#
+#proc test28 {} {
+#    global test prompt
+#
+#    if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+#	error_and_restart "$test: couldn't create principal \"$test/a\""
+#	return
+#    }
+#    begin_dump
+#    if {! ([cmd {
+#	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+#		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+#		server_handle
+#    }] && [cmd [format {
+#	kadm5_get_principal $server_handle "%s/a" principal
+#    } $test]])} {
+#	error_and_restart "$test: error getting principal"
+#	return;
+#    }
+#    send "lindex \$principal 8\n"
+#    expect {
+#	-re "\n(\[0-9\]+).*$prompt$" {set kvno $expect_out(1,string) }
+#	timeout {
+#	    error_and_restart "$test: timeout getting principal kvno"
+#	    return
+#	}
+#	eof {
+#	    error_and_restart "$test: eof getting principal kvno"
+#	    return
+#	}
+#    }
+#    api_exit
+#    api_start
+#    set new_kvno [expr "$kvno + 1"]
+#    if {[cmd [format {
+#	kadm5_modify_principal $server_handle \
+#		{"%s/a" 0 0 0 0 0 0 0 %d 0 0 0} {KADM5_KVNO}
+#    } $test $new_kvno]]} {
+#	fail "$test: unexpected success in modify"
+#	return;
+#    }
+#    end_dump_compare "no-diffs"
+#}
+#test28
+
+#test "init 29"
+#
+#proc test29 {} {
+#    global test
+#
+#    if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} {
+#	error_and_restart "$test: couldn't create principal \"$test/a\""
+#	return
+#    }
+#    begin_dump
+#    if {[cmd [format {
+#	kadm5_delete_principal $server_handle "%s/a"
+#    } $test]]} {
+#	fail "$test: unexpected success in delete"
+#	return
+#    }
+#    end_dump_compare "no-diffs"
+#}
+#test29
+
+test "init 30"
+proc test30 {} {
+	global test
+	if {[cmd {
+	    kadm5_init admin foobar $KADM5_ADMIN_SERVICE null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}]} {
+		error_and_restart "$test: unexpected success"
+		return
+	}
+	one_line_succeed_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+if ${RPC} { test30 }
+
+test "init 31"
+proc test31 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $bad_struct_version_mask $KADM5_API_VERSION_2 \
+		    server_handle
+	} "BAD_STRUCT_VERSION" 
+}
+test31
+
+test "init 32"
+proc test32 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $no_struct_version_mask $KADM5_API_VERSION_2 \
+		    server_handle
+	} "BAD_STRUCT_VERSION" 
+}
+test32
+
+test "init 33"
+proc test33 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $old_struct_version $KADM5_API_VERSION_2 \
+		    server_handle
+	} "OLD_STRUCT_VERSION" 
+}
+test33
+
+test "init 34"
+proc test34 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $new_struct_version $KADM5_API_VERSION_2 \
+		    server_handle
+	} "NEW_STRUCT_VERSION" 
+}
+test34
+
+test "init 35"
+proc test35 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $KADM5_STRUCT_VERSION $bad_api_version_mask \
+		    server_handle
+	} "BAD_API_VERSION" 
+}
+test35
+
+test "init 36"
+proc test36 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $KADM5_STRUCT_VERSION $no_api_version_mask \
+		    server_handle
+	} "BAD_API_VERSION" 
+}
+test36
+
+test "init 37"
+proc test37 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $KADM5_STRUCT_VERSION $old_api_version \
+		    server_handle
+	} "OLD_LIB_API_VERSION" 
+}
+if { $RPC } test37
+
+test "init 38"
+proc test38 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $KADM5_STRUCT_VERSION $old_api_version \
+		    server_handle
+	} "OLD_SERVER_API_VERSION" 
+}
+if { ! $RPC } test38
+
+test "init 39"
+proc test39 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $KADM5_STRUCT_VERSION $new_api_version \
+		    server_handle
+	} "NEW_LIB_API_VERSION" 
+}
+if { $RPC } test39
+
+test "init 40"
+proc test40 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $KADM5_STRUCT_VERSION $new_api_version \
+		    server_handle
+	} "NEW_SERVER_API_VERSION" 
+}
+if { ! $RPC } test40
+
+test "init 41"
+proc test41 {} {
+	global test
+	one_line_fail_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $KADM5_API_VERSION_2 $KADM5_STRUCT_VERSION \
+		    server_handle
+	} "BAD_"
+}
+test41
+
+test "init 42"
+proc test42 {} {
+	global test
+	one_line_succeed_test {
+	    kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+	    	    $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		    server_handle
+	}
+	if {! [cmd {kadm5_destroy $server_handle}]} {
+		error_and_restart "$test: couldn't close database"
+	}
+}
+test42
+
+
+proc test45_46 {service} {
+    global test kadmin_local env
+
+    spawn $kadmin_local -q "delprinc -force $service"
+    expect {
+	-re "Principal .* deleted." {}
+	default {
+	    perror "kadmin.local delprinc failed\n";
+	}
+    }
+    expect eof
+    wait
+
+    one_line_fail_test [concat {kadm5_init admin admin } \
+	    $service \
+	    { null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+	    server_handle}] "SECURE_PRINC_MISSING"
+
+    # this leaves the keytab with an incorrect entry
+    spawn $kadmin_local -q "ank -randkey $service"
+    expect eof
+    wait
+
+    # restart the api so it gets a new ccache
+    api_exit
+    api_start
+}
+
+if {$RPC} {
+    test "init 45"
+
+    test45_46 ovsec_adm/admin
+
+    test "init 46"
+
+    test45_46 ovsec_adm/changepw
+
+    # re-extract the keytab so it is right
+    exec rm $env(K5ROOT)/ovsec_adm.srvtab
+    exec $env(MAKE_KEYTAB) -princ ovsec_adm/admin -princ ovsec_adm/changepw \
+	    -princ kadmin/admin -princ kadmin/changepw \
+	    $env(K5ROOT)/ovsec_adm.srvtab
+}
+
+return ""
+
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/mod-policy.exp b/mechglue/src/lib/kadm5/unit-test/api.2/mod-policy.exp
new file mode 100644
index 000000000..2cc168648
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/mod-policy.exp
@@ -0,0 +1,703 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "modify-policy 2"
+proc test2 {} {
+    global test
+
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_MAX_LIFE}
+    } $test] "AUTH_MODIFY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test2 }
+
+test "modify-policy 4"
+proc test4 {} {
+    global test
+    
+    if {! ([policy_exists "$test/a"] ||
+	   [create_policy "$test/a"])} {
+            error_and_restart "$test: couldn't create policy \"$test/a\""
+            return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_REF_COUNT}
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+        perror "$test: unexpected failure in destroy"
+        return
+    }
+}
+test4
+
+test "modify-policy 8"
+proc test8 {} {
+    global test
+#    set prms_id 744
+#    setup_xfail {*-*-*} $prms_id
+
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_modify_policy $server_handle [simple_policy ""] \
+		{KADM5_PW_MAX_LIFE}
+    } "BAD_POLICY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test8
+
+test "modify-policy 9"
+proc test9 {} {
+    global test
+    global prompt
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_MIN_LIFE}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 1\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test9
+
+test "modify-policy 10"
+proc test10 {} {
+    global test
+    global prompt
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle {"%s/a" 32 0 0 0 0 0} \
+		{KADM5_PW_MIN_LIFE}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 1\n"
+    expect {
+	-re "32\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test10
+
+
+test "modify-policy 11"
+proc test11 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_MAX_LIFE}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test11
+
+test "modify-policy 12"
+proc test12 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle {"%s/a" 0 32 0 0 0 0} \
+		{KADM5_PW_MAX_LIFE}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "32\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test12
+
+test "modify-policy 13"
+proc test13 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_MIN_LENGTH}
+    } $test] "BAD_LENGTH"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test13
+
+test "modify-policy 14"
+proc test14 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle {"%s/a" 0 0 8 0 0 0} \
+		{KADM5_PW_MIN_LENGTH}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 3\n"
+    expect {
+	-re "8\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test14
+
+test "modify-policy 15"
+proc test15 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_MIN_CLASSES}
+    } $test] "BAD_CLASS"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+test "modify-policy 16"
+proc test16 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle {"%s/a" 0 0 0 1 0 0} \
+		{KADM5_PW_MIN_CLASSES}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 4\n"
+    expect {
+	-re "1\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test16
+
+test "modify-policy 17"
+proc test17 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a"])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle {"%s/a" 0 0 0 5 0 0} \
+		{KADM5_PW_MIN_CLASSES}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 4\n"
+    expect {
+	-re "5\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test17
+
+test "modify-policy 18"
+proc test18 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_policy $server_handle {"%s/a" 0 0 0 6 0 0} \
+		{KADM5_PW_MIN_CLASSES}
+    } $test] "BAD_CLASS"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test18
+
+test "modify-policy 19"
+proc test19 {} {
+    global test
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_HISTORY_NUM}
+    } $test] "BAD_HISTORY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test19
+
+test "modify-policy 20"
+proc test20 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle {"%s/a" 0 0 0 0 1 0} \
+		{KADM5_PW_HISTORY_NUM}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 5\n"
+    expect {
+	-re "1\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test20
+
+test "modify-policy 21"
+proc test21 {} {
+    global test
+    global prompt
+    
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_policy $server_handle {"%s/a" 0 0 0 0 10 0} \
+		{KADM5_PW_HISTORY_NUM}
+    } $test]]} {
+	fail $test
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_policy $server_handle "%s/a" policy
+    } $test]]} {
+	fail "$test: can not retrieve policy"
+	return
+    }
+    send "lindex \$policy 5\n"
+    expect {
+	-re "10\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test21
+
+test "modify-policy 22"
+proc test22 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_MAX_LIFE}
+    } $test] "AUTH_MODIFY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test22
+
+test "modify-policy 23"
+proc test23 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_MAX_LIFE}
+    } $test] "AUTH_MODIFY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} test23
+
+test "modify-policy 26"
+proc test26 {} {
+    global test
+    if {! ((  [policy_exists "$test/a"]) ||
+	   [create_policy "$test/a" ])} {
+	    error_and_restart "$test: couldn't create policy \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_modify_policy $server_handle [simple_policy "%s/a"] \
+		{KADM5_PW_MAX_LIFE}
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test26
+
+test "modify-policy 30"
+proc test30 {} {
+    global test
+
+    one_line_fail_test [format {
+	kadm5_modify_policy null [simple_policy "%s/a"] \
+		{KADM5_PW_MAX_LIFE}
+    } $test] "BAD_SERVER_HANDLE"
+}
+test30
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/mod-principal-v2.exp b/mechglue/src/lib/kadm5/unit-test/api.2/mod-principal-v2.exp
new file mode 100644
index 000000000..44c835e57
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/mod-principal-v2.exp
@@ -0,0 +1,114 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "modify-principal 100-105"
+proc test100_104 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+
+    set origtest "$test"
+
+    test "modify-principal 100"
+    one_line_succeed_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_MAX_RLIFE}
+    } $origtest]
+
+    test "modify-principal 101"
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_LAST_SUCCESS}
+    } $origtest] "BAD_MASK"
+
+    test "modify-principal 102"
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_LAST_FAILED}
+    } $origtest] "BAD_MASK"
+
+    test "modify-principal 103"
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_FAIL_AUTH_COUNT}
+    } $origtest] "BAD_MASK"
+
+    test "modify-principal 103.5"
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_KEY_DATA}
+    } $origtest] "BAD_MASK"
+
+    test "modify-principal 105"
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle \
+            "{%s/a} 0 0 0 0 {%s/a} 0 0 0 0 null 0 0 0 0 0 0 1 {} {{1 1 x}}" \
+		{KADM5_TL_DATA}
+    } $origtest $origtest] "BAD_TL_TYPE"
+
+    test "modify-principal 100,104"
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		"{%s/a} 0 0 0 0 {%s/a} 0 0 0 0 null 0 88 0 0 0 0 1 {} {{990 6 foobar}}" \
+		{KADM5_MAX_RLIFE KADM5_TL_DATA}
+    } $origtest $origtest]]} {
+	fail "$test: cannot set MAX_RLIFE or TL_DATA"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal {KADM5_PRINCIPAL_NORMAL_MASK KADM5_TL_DATA}
+    } $origtest]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 12\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set rlife $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting rlife"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting rlife"
+	    return
+	}
+    }
+    send "lindex \$principal 19\n"
+    expect {
+	-re "\(\{.*\}\)\n$prompt$" {set tl $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting tl_data"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting tl_data"
+	    return
+	}
+    }
+    if {($rlife == 88) && ($tl == "{{990 6 foobar}}")} {
+	pass "$test"
+    } else {
+	fail "$test: $rlife should be 88, $tl should be {{990 6 foobar}}"
+    }
+
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test100_104
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/mod-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.2/mod-principal.exp
new file mode 100644
index 000000000..4472c78ce
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/mod-principal.exp
@@ -0,0 +1,1942 @@
+load_lib lib.t
+api_exit
+api_start
+
+#test "modify-principal 1"
+#proc test1 {} {
+#	global test
+#	one_line_fail_test [format {
+#	    kadm5_modify_principal $server_handle [simple_principal \
+#		    "%s/a"] {KADM5_PW_EXPIRATION}
+#	} $test] "NOT_INIT"
+#}
+#test1
+
+test "modify-principal 2"
+proc test2 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MODIFY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test2 }
+
+test "modify-principal 4"
+proc test4 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINCIPAL}
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test4
+
+
+test "modify-principal 5"
+proc test5 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_LAST_PWD_CHANGE}
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test5
+
+test "modify-principal 6"
+proc test6 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_MOD_TIME}
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test6
+
+test "modify-principal 7"
+proc test7 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_MOD_NAME}
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test7
+
+test "modify-principal 8"
+proc test8 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_MKVNO}
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test8
+
+test "modify-principal 9"
+proc test9 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_AUX_ATTRIBUTES}
+    } $test] "BAD_MASK"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test9
+
+test "modify-principal 10"
+proc test10 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test] "UNK_PRINC"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test10
+
+test "modify-principal 11"
+proc test11 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MOD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test11 }
+
+test "modify-principal 12"
+proc test12 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MOD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test12 }
+
+test "modify-principal 13"
+proc test13 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MOD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test13 }
+
+test "modify-principal 14"
+proc test14 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test] "AUTH_MOD"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test14 }
+
+test "modify-principal 15"
+proc test15 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test15
+
+test "modify-principal 17"
+proc test17 {} {
+    global test
+    if {! (( [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		no-policy] {KADM5_POLICY}
+    } $test] "UNK_POLICY"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test17
+
+test "modify-principal 18"
+proc test18 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal "$test/a"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {KADM5_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol\n$prompt$"	{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    send "lindex \$p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$oldref + 1"] != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test18
+
+test "modify-principal 19"
+proc test19 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal "$test/a"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {KADM5_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol\n$prompt$"	{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    send "lindex \$p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$oldref + 1"] != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test19
+
+test "modify-principal 20"
+proc test20 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal_pol "$test/a" "test-pol"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_POLICY_CLR}
+    } $test]]} {
+	perror "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol\n$prompt$"	{ fail "$test" }
+	timeout				{ pass "$test" }
+    }
+    send "lindex \$p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$oldref - 1"] != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test20
+
+test "modify-principal 21"
+proc test21 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal_pol "$test/a" "test-pol"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol old_p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol-nopw old_p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol-nopw] {KADM5_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$old_p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set old_p1_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    send "lindex \$old_p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set old_p2_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol new_p1}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol-nopw new_p2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$new_p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set new_p1_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    send "lindex \$new_p2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set new_p2_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { [expr "$old_p1_ref - 1"] != $new_p1_ref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { [expr "$old_p2_ref + 1"] != $new_p2_ref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test21
+
+test "modify-principal 21.5"
+proc test21.5 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal_pol "$test/a" "test-pol"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol old_p1}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {KADM5_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$old_p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set old_p1_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol new_p1}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    
+    send "lindex \$new_p1 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set new_p1_ref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+
+    if {$old_p1_ref != $new_p1_ref} {
+	fail "$test: policy reference count changed ($old_p1_ref to $new_p1_ref)"
+	return
+    }
+
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test21.5
+
+test "modify-principal 22"
+proc test22 {} {
+    global test
+    global prompt
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modifiy failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test22
+
+test "modify-principal 23"
+proc test23 {} {
+    global test
+    global prompt
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" test-pol-nopw])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modifiy failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test23
+
+test "modify-principal 24"
+proc test24 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" "test-pol" ])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	error_and_restart "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PW_EXPIRATION}
+    } $test]]} {
+    	fail "$test: could not modify principal"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_get_policy $server_handle %s policy
+    } test-pol]]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+    send "lindex \$principal 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { $pw_expire != 0 } {
+	fail "$test: pw_expire $pw_expire should be 0"
+	return
+    } else {
+	pass "$test"
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} { 
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test24
+
+test "modify-principal 25"
+proc test25 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {KADM5_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test25
+
+test "modify-principal 26"
+proc test26 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" "test-pol-nopw" ])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {KADM5_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test26
+
+test "modify-principal 27"
+proc test27 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" "test-pol" ])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {KADM5_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "1234\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test27
+
+test "modify-principal 28"
+proc test28 {} {
+    global test
+    global prompt
+#    set prms_id 1358
+#    setup_xfail {*-*-*} $prms_id    
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal_pol "$test/a" "test-pol" ])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 999999999 0 0 0 0 0 0 0 0} {KADM5_PW_EXPIRATION}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol policy}]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+    send "lindex \$principal 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { $pw_expire != 999999999 } {
+	fail "$test: pw_expire $pw_expire should be 999999999"
+	return
+    }
+    pass "$test"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test28
+
+test "modify-principal 29"
+proc test29 {} {
+    global test
+    global prompt
+    
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { ! ([create_principal_pol "$test/a" test-pol])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_POLICY_CLR}
+    } $test]]} {
+	fail "$test: modifiy failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test29
+
+test "modify-principal 30"
+proc test30 {} {
+    global test
+    global prompt
+
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal_pol "$test/a" test-pol])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol-nopw] {KADM5_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 3\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test30
+
+test "modify-principal 31"
+proc test31 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {KADM5_POLICY}
+    } $test]]} {
+	fail "modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol policy}]} {
+	error_and_restart "$test: cannot retrieve policy"
+	return
+    }
+    send "lindex \$principal 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_mod_date"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_mod_date"
+	    return
+	}
+    }
+
+    send "lindex \$principal 3\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_expire"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_expire"
+	    return
+	}
+    }
+
+    send "lindex \$policy 2\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting pw_max_life"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting pw_max_life"
+	    return
+	}
+    }
+    if { [expr "$pw_mod_date + $pw_max_life"] != $pw_expire } {
+	fail "$test: pw_expire is wrong"
+	return
+    }
+
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test31
+
+test "modify-principal 32"
+proc test32 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	error_and_restart "$test: couldn't delete principal \"$test/a\""
+	return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 1234 0 0 0 0 0 0 0 0 0 0} \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 1\n"
+    expect {
+	-re "1234\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test32
+
+test "modify-principal 33"
+proc test33 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 0 0 0 0 KRB5_KDB_DISALLOW_ALL_TIX 0 0 0 0} \
+		{KADM5_ATTRIBUTES}
+    } $test]]} {
+	fail "$test: modified fail"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 7\n"
+    expect {
+	-re "KRB5_KDB_DISALLOW_ALL_TIX.*$prompt$"		{ pass "$test" }
+	timeout							{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test33
+
+test "modify-principal 33.25"
+proc test3325 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 0 0 0 0 KRB5_KDB_REQUIRES_PWCHANGE 0 0 0 0} \
+		{KADM5_ATTRIBUTES}
+    } $test]]} {
+	fail "$test: modified fail"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 7\n"
+    expect {
+	-re "KRB5_KDB_REQUIRES_PWCHANGE.*$prompt$"		{ pass "$test" }
+	timeout							{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test3325
+
+test "modify-principal 33.5"
+proc test335 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 0 0 0 0 KRB5_KDB_DISALLOW_TGT_BASED 0 0 0 0} \
+		{KADM5_ATTRIBUTES}
+    } $test]]} {
+	fail "$test: modified fail"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 7\n"
+    expect {
+	-re "KRB5_KDB_DISALLOW_TGT_BASED.*$prompt$"		{ pass "$test" }
+	timeout							{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test335
+
+
+test "modify-principal 34"
+proc test34 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 0 3456 0 0 0 0 0 0 0} {KADM5_MAX_LIFE}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 4\n"
+    expect {
+	-re "3456\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test34
+
+test "modify-principal 35"
+proc test35 {} {
+    global prompt
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd [format {
+	kadm5_modify_principal $server_handle \
+		{"%s/a" 0 0 0 0 0 0 0 7 0 0 0} {KADM5_KVNO}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 8\n"
+    expect {
+	-re "7\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test35
+
+test "modify-principal 36"
+proc test36 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal_pol "$test/a" "test-pol"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol pol}]}  {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		test-pol] {KADM5_POLICY}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 10\n"
+    expect {
+	-re "test-pol\n$prompt$"	{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    send "lindex \$pol 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { ! [cmd {kadm5_get_policy $server_handle test-pol pol2}]} {
+	perror "$test: unexpected failure on get policy"
+	return
+    }
+    send "lindex \$pol2 6\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting principal kvno (second time)"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting principal kvno (second time)"
+	    return
+	}
+    }
+    if { $oldref != $newref } {
+	fail "$test: policy reference count is wrong"
+	return;
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test36
+
+test "modify-principal 37"
+proc test37 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if { !( [create_principal "$test/a"])} {
+	error_and_restart "$test: could not create principal \"$test/a\""
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_POLICY_CLR}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test37
+
+test "modify-principal 38"
+proc test38 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 1\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test38
+
+test "modify-principal 39"
+proc test39 {} {
+    global test
+    global prompt
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! ([create_principal "$test/a"])} {
+	perror "$test: unexpected failure in creating principal"
+	return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [simple_principal "%s/a"] \
+		{KADM5_MAX_LIFE}
+    } $test]]} {
+	fail "$test: modify failed"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK
+    } $test]]} {
+	error_and_restart "$test: could not retrieve principal"
+	return
+    }
+    send "lindex \$principal 4\n"
+    expect {
+	-re "0\n$prompt$"		{ pass "$test" }
+	timeout				{ fail "$test" }
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test39
+
+test "modify-principal 40"
+proc test40 {} {
+    global test
+    global prompt
+    
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_modify_principal $server_handle null \
+		{KADM5_PRINC_EXPIRE_TIME}
+    } "EINVAL"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test40
+
+test "modify-principal 43"
+proc test43 {} {
+	global test
+	one_line_fail_test [format {
+	    kadm5_modify_principal null [simple_principal \
+		    "%s/a"] {KADM5_PW_EXPIRATION}
+	} $test] "BAD_SERVER_HANDLE"
+}
+test43
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp b/mechglue/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp
new file mode 100644
index 000000000..c9d1104bc
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp
@@ -0,0 +1,62 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "randkey-principal 100"
+proc test100 {} {
+    global test prompt
+
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal "$test/a"]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+
+    # I'd like to specify a long list of keysalt tuples and make sure
+    # that randkey does the right thing, but we can only use those
+    # enctypes that krbtgt has a key for: des-cbc-crc:normal and
+    # des-cbc-crc:v4, according to the prototype kdc.conf.
+    if {! [cmd [format {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test]]} {
+	perror "$test: unexpected failure in randkey_principal"
+    }
+    send "puts \$num_keys\n"
+    expect {
+	-re "(\[0-9\]+)\n$prompt" { set num_keys $expect_out(1,string) }
+	timeout {
+	    error_and_restart "$test: timeout getting num_keys"
+	    return
+	}
+	eof {
+	    error_and_restart "$test: eof getting num_keys"
+	    return
+	}
+    }
+
+    # XXX Perhaps I should actually check the key type returned.
+    if {$num_keys == 2} {
+	pass "$test"
+    } else {
+	fail "$test: $num_keys keys, should be 2"
+    }
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test100
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/api.2/randkey-principal.exp b/mechglue/src/lib/kadm5/unit-test/api.2/randkey-principal.exp
new file mode 100644
index 000000000..ecf79e476
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/api.2/randkey-principal.exp
@@ -0,0 +1,319 @@
+load_lib lib.t
+api_exit
+api_start
+
+test "randkey-principal 1"
+proc test1 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd [format {
+	kadm5_init "%s/a" "%s/a" $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } $test $test]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test] "PASS_TOOSOON"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test1 } 
+
+test "randkey-principal 3"
+proc test3 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd [format {
+	kadm5_init "%s/a" "%s/a" $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } $test $test]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test] "PASS_TOOSOON"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if ${RPC} { test3 } 
+
+test "randkey-principal 13"
+proc test13 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \
+		once-a-min] KADM5_POLICY
+    } $test]]} {
+	perror "$test: failed modify"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test13
+
+test "randkey-principal 15"
+proc test15 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal_pol "$test/a" once-a-min]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test] "AUTH_CHANGEPW"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if { $RPC } { test15 }
+
+test "randkey-principal 28"
+proc test28 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test28
+
+test "randkey-principal 28.25"
+proc test2825 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test] "AUTH"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+if {$RPC} { test2825 }
+
+test "randkey-principal 28.5"
+proc test285 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [cmd {
+	kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test285
+
+test "randkey-principal 30"
+proc test30 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't delete principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal "$test/a"]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    if {! [cmd [format {
+	kadm5_init "%s/a" "%s/a" $KADM5_CHANGEPW_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } $test $test]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test30
+
+test "randkey-principal 31"
+proc test31 {} {
+    global test
+    if {! (( ! [principal_exists "$test/a"]) ||
+	   [delete_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if {! [create_principal "$test/a"]} {
+	error_and_restart "$test: creating principal"
+	return
+    }
+    
+    if {! [cmd [format {
+	kadm5_init "%s/a" "%s/a" $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    } $test $test]]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_succeed_test [format {
+	kadm5_randkey_principal $server_handle "%s/a" keys num_keys
+    } $test]
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test31
+
+test "randkey-principal 32"
+proc test32 {} {
+    global test
+
+    if { ! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test {
+	kadm5_randkey_principal $server_handle kadmin/history keys num_keys
+    } "PROTECT"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+test32
+
+test "randkey-principal 33"
+proc test33 {} {
+    global test
+    if {! ((  [principal_exists "$test/a"]) ||
+	   [create_principal "$test/a"])} {
+	    error_and_restart "$test: couldn't create principal \"$test/a\""
+	    return
+    }
+    if { ! [cmd {
+	kadm5_init admin admin $KADM5_ADMIN_SERVICE null \
+		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \
+		server_handle
+    }]} {
+	perror "$test: unexpected failure in init"
+	return
+    }
+    one_line_fail_test [format {
+	kadm5_randkey_principal null "%s/a" keys num_keys
+    } $test] "BAD_SERVER_HANDLE"
+    if { ! [cmd {kadm5_destroy $server_handle}]} {
+	perror "$test: unexpected failure in destroy"
+	return
+    }
+}
+
+test33
+
+return ""
diff --git a/mechglue/src/lib/kadm5/unit-test/config/unix.exp b/mechglue/src/lib/kadm5/unit-test/config/unix.exp
new file mode 100644
index 000000000..a78515f91
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/config/unix.exp
@@ -0,0 +1,179 @@
+set prompt "% "
+set stty_init {-onlcr -opost intr \^C kill \^U}
+set kadmin_local $KADMIN_LOCAL
+
+# Backward compatibility until we're using expect 5 everywhere
+if {[info exists exp_version_4]} {
+	global wait_error_index wait_errno_index wait_status_index
+	set wait_error_index 0
+	set wait_errno_index 1
+	set wait_status_index 1
+} else {
+	set wait_error_index 2
+	set wait_errno_index 3
+	set wait_status_index 3
+}
+
+# Hack around Solaris 9 kernel race condition that causes last output
+# from a pty to get dropped.
+if { $PRIOCNTL_HACK } {
+    catch {exec priocntl -s -c FX -m 30 -p 30 -i pid [getpid]}
+    rename spawn oldspawn
+    proc spawn { args } {
+	upvar 1 spawn_id spawn_id
+	set newargs {}
+	set inflags 1
+	set eatnext 0
+	foreach arg $args {
+	    if { $arg == "-ignore" \
+		     || $arg == "-open" \
+		     || $arg == "-leaveopen" } {
+		lappend newargs $arg
+		set eatnext 1
+		continue
+	    }
+	    if [string match "-*" $arg] {
+		lappend newargs $arg
+		continue
+	    }
+	    if { $eatnext } {
+		set eatnext 0
+		lappend newargs $arg
+		continue
+	    }
+	    if { $inflags } {
+		set inflags 0
+		set newargs [concat $newargs {priocntl -e -c FX -p 0}]
+	    }
+	    lappend newargs $arg
+	}
+	set pid [eval oldspawn $newargs]
+	return $pid
+    }
+}
+
+# Variables for keeping track of api process state
+set api_pid "0"
+
+proc api_exit {} {
+	global spawn_id
+        global api_pid
+
+#	puts stdout "Starting api_exit (spawn_id $spawn_id)."
+	catch {close} errMsg
+        catch {wait} errMsg
+#       puts stdout "Finishing api_exit for $api_pid."
+        set api_pid "0"
+}
+
+proc api_isrunning {pid} {
+        global api_pid
+    
+#        puts stdout "testing $pid, api_pid is $api_pid"
+        if {$pid == $api_pid} {
+	    return 1;
+	} else {
+	    return 0;
+	}
+}
+
+proc api_version {} {
+}
+
+proc api_start {} {
+	global API 
+	global env
+	global spawn_id
+	global prompt
+        global api_pid
+
+	set pid [spawn $API]
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF starting API" }
+		timeout { error "Timeout starting API" }
+	}
+	if {! [info exists env(TCLUTIL)]} {
+		error "TCLUTIL environment variable isn't set"
+	}
+	# tcl 8.4 for some reason screws up autodetection of output
+	# EOL translation.  Work around it for now.
+	send "if { \[info commands fconfigure\] ne \"\" } { fconfigure stdout -translation lf }\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF starting API" }
+		timeout { error "Timeout starting API" }
+	}
+	send "source $env(TCLUTIL)\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF starting API" }
+		timeout { error "Timeout starting API" }
+	}
+	send "set current_struct_version \[expr \$OVSEC_KADM_STRUCT_VERSION &~ \$OVSEC_KADM_STRUCT_VERSION_MASK\]\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set current_api_version \[expr \$OVSEC_KADM_API_VERSION_1 &~ \$OVSEC_KADM_API_VERSION_MASK\]\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set bad_struct_version_mask \[expr 0x65432100 | \$current_struct_version\]\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set bad_api_version_mask \[expr 0x65432100 | \$current_api_version\]\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set no_api_version_mask \$current_api_version\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set no_struct_version_mask \$current_struct_version\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set old_api_version \[expr \$OVSEC_KADM_API_VERSION_MASK | 0x00\]\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set old_struct_version \[expr \$OVSEC_KADM_STRUCT_VERSION_MASK | 0x00\]\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set new_api_version \[expr \$OVSEC_KADM_API_VERSION_MASK | 0xca\]\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+	send "set new_struct_version \[expr \$OVSEC_KADM_STRUCT_VERSION_MASK | 0xca\]\n"
+	expect {
+		-re "$prompt$" {}
+		eof { error "EOF setting API varibles"}
+		timeout { error "timeout setting API varibles"}
+	}
+
+	set api_pid $pid
+#	puts stdout "Finishing api_start (spawn_id $spawn_id, pid $api_pid)."
+	return $pid
+}
+api_start
+
diff --git a/mechglue/src/lib/kadm5/unit-test/destroy-test.c b/mechglue/src/lib/kadm5/unit-test/destroy-test.c
new file mode 100644
index 000000000..6d7435c45
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/destroy-test.c
@@ -0,0 +1,42 @@
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <stdio.h>
+#include <krb5.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <kadm5/client_internal.h>
+#include <string.h>
+
+#define	TEST_NUM    25
+
+int main()
+{
+     ovsec_kadm_ret_t ret;
+     char   *cp;
+     int    x;
+     void *server_handle;
+     kadm5_server_handle_t handle;
+
+     for(x = 0; x < TEST_NUM; x++) {
+	ret = ovsec_kadm_init("admin", "admin", "ovsec_adm/admin", 0,
+			      OVSEC_KADM_STRUCT_VERSION,
+			      OVSEC_KADM_API_VERSION_1, NULL,
+			      &server_handle);
+	if(ret != OVSEC_KADM_OK) {
+	    com_err("test", ret, "init");
+	    exit(2);
+	}
+	handle = (kadm5_server_handle_t) server_handle;
+	cp = (char *) strdup(((char *) (strchr(handle->cache_name, ':')) + 1));
+	ovsec_kadm_destroy(server_handle);
+	if(access(cp, F_OK) == 0) {
+	    puts("ticket cache not destroyed");
+	    exit(2);
+	}
+	free(cp);
+     }
+     exit(0);
+}
+
diff --git a/mechglue/src/lib/kadm5/unit-test/diff-files/destroy-1 b/mechglue/src/lib/kadm5/unit-test/diff-files/destroy-1
new file mode 100644
index 000000000..593d67320
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/diff-files/destroy-1
@@ -0,0 +1,2 @@
+##! nochanges
+
diff --git a/mechglue/src/lib/kadm5/unit-test/diff-files/no-diffs b/mechglue/src/lib/kadm5/unit-test/diff-files/no-diffs
new file mode 100644
index 000000000..593d67320
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/diff-files/no-diffs
@@ -0,0 +1,2 @@
+##! nochanges
+
diff --git a/mechglue/src/lib/kadm5/unit-test/handle-test.c b/mechglue/src/lib/kadm5/unit-test/handle-test.c
new file mode 100644
index 000000000..6743e6e8e
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/handle-test.c
@@ -0,0 +1,130 @@
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <stdio.h>
+#include <krb5.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <kadm5/client_internal.h>
+
+
+int main(int argc, char *argv[])
+{
+     ovsec_kadm_ret_t ret;
+     void *server_handle;
+     kadm5_server_handle_t handle;
+     kadm5_server_handle_rec orig_handle;
+     ovsec_kadm_policy_ent_t	pol;
+     ovsec_kadm_principal_ent_t	princ;
+     krb5_keyblock	*key;
+     krb5_principal	tprinc;
+     krb5_context	context;
+
+
+    krb5_init_context(&context);
+     
+    ret = ovsec_kadm_init("admin/none", "admin", "ovsec_adm/admin", 0,
+			  OVSEC_KADM_STRUCT_VERSION, OVSEC_KADM_API_VERSION_1, NULL,
+			  &server_handle);
+    if(ret != OVSEC_KADM_OK) {
+	com_err("test", ret, "init");
+	exit(2);
+    }
+    handle = (kadm5_server_handle_t) server_handle;
+    orig_handle = *handle;
+    handle->magic_number = OVSEC_KADM_STRUCT_VERSION;
+    krb5_parse_name(context, "testuser", &tprinc);
+    ret = ovsec_kadm_get_principal(server_handle, tprinc, &princ);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "get-principal",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_get_policy(server_handle, "pol1", &pol);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "get-policy",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_create_principal(server_handle, princ, OVSEC_KADM_PRINCIPAL, "pass");
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "create-principal",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_create_policy(server_handle, pol, OVSEC_KADM_POLICY);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "create-policy",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_modify_principal(server_handle, princ, OVSEC_KADM_PW_EXPIRATION);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "modify-principal",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_modify_policy(server_handle, pol, OVSEC_KADM_PW_MAX_LIFE);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "modify-policy",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_delete_principal(server_handle, tprinc);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "delete-principal",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_delete_policy(server_handle, "pol1");
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "delete-policy",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_chpass_principal(server_handle, tprinc, "FooBar");
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "chpass",
+		error_message(ret));
+	exit(1);
+    }
+    ret = ovsec_kadm_randkey_principal(server_handle, tprinc, &key);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "randkey",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_rename_principal(server_handle, tprinc, tprinc);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "rename",
+		error_message(ret));
+	exit(1);
+    }
+    
+    ret = ovsec_kadm_destroy(server_handle);
+    if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) {
+	fprintf(stderr, "%s -- returned -- %s\n", "destroy",
+		error_message(ret));
+	exit(1);
+    }
+
+    *handle = orig_handle;
+    ret = ovsec_kadm_destroy(server_handle);
+    if (ret != OVSEC_KADM_OK) {
+	fprintf(stderr, "valid %s -- returned -- %s\n", "destroy",
+		error_message(ret));
+	exit(1);
+    }
+
+    exit(0);
+}
diff --git a/mechglue/src/lib/kadm5/unit-test/init-test.c b/mechglue/src/lib/kadm5/unit-test/init-test.c
new file mode 100644
index 000000000..9677698a7
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/init-test.c
@@ -0,0 +1,29 @@
+#undef USE_KADM5_API_VERSION
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <krb5.h>
+
+int main()
+{
+     kadm5_ret_t ret;
+     void *server_handle;
+     kadm5_config_params params;
+
+     memset(¶ms, 0, sizeof(params));
+     params.mask |= KADM5_CONFIG_NO_AUTH;
+     ret = kadm5_init("admin", "admin", NULL, ¶ms,
+		      KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, NULL,
+		      &server_handle);
+     if (ret == KADM5_RPC_ERROR)
+	  exit(0);
+     else if (ret != 0) {
+	  com_err("init-test", ret, "while initializing without auth");
+	  exit(1);
+     } else {
+	 fprintf(stderr, "Unexpected success while initializing without auth!\n");
+	 (void) kadm5_destroy(server_handle);
+	 exit(1);
+     }
+}
diff --git a/mechglue/src/lib/kadm5/unit-test/iter-test.c b/mechglue/src/lib/kadm5/unit-test/iter-test.c
new file mode 100644
index 000000000..4b85a5490
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/iter-test.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <kadm5/admin.h>
+
+int main(int argc, char **argv)
+{
+     ovsec_kadm_ret_t ret;
+     void *server_handle;
+     char **names;
+     int count, princ, i;
+
+     if (argc != 3) {
+	  fprintf(stderr, "Usage: %s [-princ|-pol] exp\n", argv[0]);
+	  exit(1);
+     }
+     princ = (strcmp(argv[1], "-princ") == 0);
+     
+     ret = ovsec_kadm_init("admin", "admin", OVSEC_KADM_ADMIN_SERVICE, 0,
+			   OVSEC_KADM_STRUCT_VERSION,
+			   OVSEC_KADM_API_VERSION_1, NULL,
+			   &server_handle);
+     if (ret != OVSEC_KADM_OK) {
+	  com_err("iter-test", ret, "while initializing");
+	  exit(1);
+     }
+
+     if (princ)
+	  ret = ovsec_kadm_get_principals(server_handle, argv[2], &names,
+					  &count);
+     else
+	  ret = ovsec_kadm_get_policies(server_handle, argv[2],
+					&names, &count);
+					
+     if (ret != OVSEC_KADM_OK) {
+	  com_err("iter-test", ret, "while retrieving list");
+	  exit(1);
+     }
+
+     for (i = 0; i < count; i++)
+	  printf("%d: %s\n", i, names[i]);
+
+     ovsec_kadm_free_name_list(server_handle, names, count);
+
+     (void) ovsec_kadm_destroy(server_handle);
+
+     return 0;
+}
+
diff --git a/mechglue/src/lib/kadm5/unit-test/lib/lib.t b/mechglue/src/lib/kadm5/unit-test/lib/lib.t
new file mode 100644
index 000000000..20277942c
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/lib/lib.t
@@ -0,0 +1,305 @@
+global timeout
+set timeout 60
+
+set lib_pid 0
+
+#
+# The functions in this library used to be responsible for bazillions
+# of wasted api_starts.  Now, they all just use their own library
+# handle so they are not interrupted when the main tests call init or
+# destroy.  They have to keep track of when the api exists and
+# restarts, though, since the lib_handle needs to be re-opened in that
+# case.
+#
+proc lib_start_api {} {
+    global spawn_id lib_pid test
+
+    if {! [api_isrunning $lib_pid]} {
+	api_exit
+	set lib_pid [api_start]
+	if {! [cmd {
+	    ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \
+		    $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \
+		    lib_handle
+	}]} {
+	    error "$test: unexpected failure in init"
+	    return
+	}
+	verbose "+++ restarted api ($lib_pid) for lib"
+    } else {
+	verbose "+++ api $lib_pid already running for lib"
+    }	
+}
+
+proc cmd {command} {
+    global prompt
+    global spawn_id
+    global test
+
+    send "[string trim $command]\n"
+    expect {
+	-re "OK .*$prompt$" { return 1 }
+        -re "ERROR .*$prompt$" { return 0 }
+	"wrong # args" { error "$test: wrong number args"; return 0 }
+        timeout { fail "$test: timeout"; return 0 }
+        eof { fail "$test: eof"; api_exit; lib_start_api; return 0 }
+    }
+}
+
+proc tcl_cmd {command} {
+    global prompt spawn_id test
+
+    send "[string trim $command]\n"
+    expect {
+	-re "$prompt$" { return 1}
+	"wrong # args" { error "$test: wrong number args"; return 0 }
+	timeout { error_and_restart "timeout" }
+	eof { api_exit; lib_start_api; return 0 }
+    }
+}
+
+proc one_line_succeed_test {command} {
+    global prompt
+    global spawn_id
+    global test
+
+    send "[string trim $command]\n"
+    expect {
+	-re "OK .*$prompt$"		{ pass "$test"; return 1 }
+	-re "ERROR .*$prompt$" { 
+		fail "$test: $expect_out(buffer)"; return 0
+	}
+	"wrong # args" { error "$test: wrong number args"; return 0 }
+	timeout				{ fail "$test: timeout"; return 0 }
+	eof				{ fail "$test: eof"; api_exit; lib_start_api; return 0 }
+    }
+}
+
+proc one_line_fail_test {command code} {
+    global prompt
+    global spawn_id
+    global test
+
+    send "[string trim $command]\n"
+    expect {
+	-re "ERROR .*$code.*$prompt$"	{ pass "$test"; return 1 }
+	-re "ERROR .*$prompt$"	{ fail "$test: bad failure"; return 0 }
+	-re "OK .*$prompt$"		{ fail "$test: bad success"; return 0 }
+	"wrong # args" { error "$test: wrong number args"; return 0 }
+	timeout				{ fail "$test: timeout"; return 0 }
+	eof				{ fail "$test: eof"; api_exit; lib_start_api; return 0 }
+    }
+}
+
+proc one_line_fail_test_nochk {command} {
+    global prompt
+    global spawn_id
+    global test
+
+    send "[string trim $command]\n"
+    expect {
+	-re "ERROR .*$prompt$"	{ pass "$test:"; return 1 }
+	-re "OK .*$prompt$"		{ fail "$test: bad success"; return 0 }
+	"wrong # args" { error "$test: wrong number args"; return 0 }
+	timeout				{ fail "$test: timeout"; return 0 }
+	eof				{ fail "$test: eof"; api_exit; lib_start_api; return 0 }
+    }
+}
+
+proc resync {} {
+    global prompt spawn_id test
+
+    expect {
+	-re "$prompt$"	{}
+	"wrong # args" { error "$test: wrong number args"; return 0 }
+	eof { api_exit; lib_start_api }
+    }
+}
+
+proc create_principal {name} {
+    lib_start_api
+
+    set ret [cmd [format {
+	ovsec_kadm_create_principal $lib_handle [simple_principal \
+		"%s"] {OVSEC_KADM_PRINCIPAL} "%s"
+    } $name $name]]
+
+    return $ret
+}
+
+proc create_policy {name} {
+    lib_start_api
+
+    set ret [cmd [format {
+	    ovsec_kadm_create_policy $lib_handle [simple_policy "%s"] \
+		    {OVSEC_KADM_POLICY}
+	} $name $name]]
+
+    return $ret
+}
+
+proc create_principal_pol {name policy} {
+    lib_start_api
+
+    set ret [cmd [format {
+	    ovsec_kadm_create_principal $lib_handle [princ_w_pol "%s" \
+		    "%s"] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} "%s"
+    } $name $policy $name]]
+
+    return $ret
+}
+
+proc delete_principal {name} {
+    lib_start_api
+
+    set ret [cmd [format {
+	    ovsec_kadm_delete_principal $lib_handle "%s"
+    } $name]]
+
+    return $ret
+}
+
+proc delete_policy {name} {
+    lib_start_api
+
+    set ret [cmd [format {ovsec_kadm_delete_policy $lib_handle "%s"} $name]]
+
+    return $ret
+}
+
+proc principal_exists {name} {
+#    puts stdout "Starting principal_exists."
+
+    lib_start_api
+
+    set ret [cmd [format {
+	ovsec_kadm_get_principal $lib_handle "%s" principal
+    } $name]]
+
+#   puts stdout "Finishing principal_exists."
+
+    return $ret
+}
+
+proc policy_exists {name} {
+    lib_start_api
+
+#    puts stdout "Starting policy_exists."
+
+    set ret [cmd [format {
+	    ovsec_kadm_get_policy $lib_handle "%s" policy
+	} $name]]
+
+#    puts stdout "Finishing policy_exists."
+
+    return $ret
+}
+
+proc error_and_restart {error} {
+    api_exit
+    api_start
+    perror $error
+}
+
+proc test {name} {
+   global test verbose
+
+   set test $name
+   if {$verbose >= 1} {
+	puts stdout "At $test"
+   }
+}
+
+proc begin_dump {} {
+    global TOP
+    global RPC
+    
+    if { ! $RPC } {
+#	exec $env(SIMPLE_DUMP) > /tmp/dump.before
+    }
+}
+
+proc end_dump_compare {name} {
+    global  file
+    global  TOP
+    global  RPC
+
+    if { ! $RPC } { 
+#	set file $TOP/admin/lib/unit-test/diff-files/$name
+#	exec $env(SIMPLE_DUMP) > /tmp/dump.after
+#	exec $env(COMPARE_DUMP) /tmp/dump.before /tmp/dump.after $file
+    }
+}
+
+proc kinit { princ pass {opts ""} } {
+	global env;
+        global KINIT
+
+	eval spawn $KINIT -5 $opts $princ
+	expect {
+		-re {Password for .*: $}
+		    {send "$pass\n"}
+		timeout {puts "Timeout waiting for prompt" ; close }
+	}
+
+	# this necessary so close(1) in the child will not sleep waiting for
+	# the parent, which is us, to read pending data.
+
+	expect {
+		"when initializing cache" { error "kinit failed: $expect_out(buffer)" }
+		eof {}
+	}
+	wait
+}
+
+proc kdestroy {} {
+        global KDESTROY
+	global errorCode errorInfo
+	global env
+
+	if {[info exists errorCode]} {
+		set saveErrorCode $errorCode
+	}
+	if {[info exists errorInfo]} {
+		set saveErrorInfo $errorInfo
+	}
+	catch "system $KDESTROY -5 2>/dev/null"
+	if {[info exists saveErrorCode]} {
+		set errorCode $saveErrorCode
+	} elseif {[info exists errorCode]} {
+		unset errorCode
+	}
+	if {[info exists saveErrorInfo]} {
+		set errorInfo $saveErrorInfo
+	} elseif {[info exists errorInfo]} {
+		unset errorInfo
+	}
+}
+
+proc create_principal_with_keysalts {name keysalts} {
+    global kadmin_local
+
+    spawn $kadmin_local -e "$keysalts"
+    expect {
+	"kadmin.local:" {}
+	default { error "waiting for kadmin.local prompt"; return 1}
+    }
+    send "ank -pw \"$name\" \"$name\"\n"
+    expect {
+	-re "Principal \"$name.*\" created." {}
+	"kadmin.local:" {
+	    error "expecting principal created message"; 
+	    return 1
+	}
+	default { error "waiting for principal created message"; return 1 }
+    }
+    expect {
+	"kadmin.local:" {}
+	default { error "waiting for kadmin.local prompt"; return 1 }
+    }
+    close
+    wait
+    return 0
+}
+
+    
diff --git a/mechglue/src/lib/kadm5/unit-test/lock-test.c b/mechglue/src/lib/kadm5/unit-test/lock-test.c
new file mode 100644
index 000000000..4da6aead8
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/lock-test.c
@@ -0,0 +1,111 @@
+#if USE_KADM5_API_VERSION == 1
+#undef USE_KADM5_API_VERSION
+#define USE_KADM5_API_VERSION 2
+#endif
+
+#include <stdio.h>
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <krb5/kdb.h>
+
+char *whoami;
+
+static void usage()
+{
+     fprintf(stderr,
+	     "Usage: %s {shared|exclusive|permanent|release|"
+	     "get name|wait} ...\n", whoami);
+     exit(1);
+}
+
+int main(int argc, char **argv)
+{
+     krb5_error_code ret;
+     osa_policy_ent_t entry;
+     krb5_context context;
+     kadm5_config_params params;
+     krb5_error_code kret;
+
+     whoami = argv[0];
+
+     kret = krb5_init_context(&context);
+     if (kret) {
+	 com_err(whoami, kret, "while initializing krb5");
+	 exit(1);
+     }
+
+     params.mask = 0;
+     ret = kadm5_get_config_params(context, NULL, NULL, ¶ms,
+				   ¶ms);
+     if (ret) {
+	  com_err(whoami, ret, "while retrieving configuration parameters");
+	  exit(1);
+     }
+     if (! (params.mask & KADM5_CONFIG_ADBNAME)) {
+	  com_err(whoami, KADM5_BAD_SERVER_PARAMS,
+		  "while retrieving configuration parameters");
+	  exit(1);
+     }
+
+     ret = krb5_db_open( context, NULL, KRB5_KDB_OPEN_RW);
+     if (ret) {
+	  com_err(whoami, ret, "while opening database");
+	  exit(1);
+     }
+
+     argc--; argv++;
+     while (argc) {
+	  if (strcmp(*argv, "shared") == 0) {
+	       ret = krb5_db_lock(context, KRB5_DB_LOCKMODE_SHARED);
+	       if (ret)
+		    com_err(whoami, ret, "while getting shared lock");
+	       else
+		    printf("shared\n");
+	  } else if (strcmp(*argv, "exclusive") == 0) {
+	       ret = krb5_db_lock(context, KRB5_DB_LOCKMODE_EXCLUSIVE );
+	       if (ret)
+		    com_err(whoami, ret, "while getting exclusive lock");
+	       else
+		    printf("exclusive\n");
+	  } else if (strcmp(*argv, "permanent") == 0) {
+	       ret = krb5_db_lock(context, KRB5_DB_LOCKMODE_EXCLUSIVE );
+	       if (ret)
+		    com_err(whoami, ret, "while getting permanent lock");
+	       else
+		    printf("permanent\n");
+	  } else if (strcmp(*argv, "release") == 0) {
+	       ret = krb5_db_unlock(context);
+	       if (ret)
+		    com_err(whoami, ret, "while releasing lock");
+	       else
+		    printf("released\n");
+	  } else if (strcmp(*argv, "get") == 0) {
+	       int cnt = 1;
+	       argc--; argv++;
+	       if (!argc) usage();
+	       if ((ret = krb5_db_get_policy(context, *argv,
+					     &entry, &cnt)) ) {
+		    com_err(whoami, ret, "while getting policy");
+	       } else {
+		    printf("retrieved\n");
+		    krb5_db_free_policy(context, entry);
+	       }
+	  } else if (strcmp(*argv, "wait") == 0) {
+	       getchar();
+	  } else {
+	       fprintf(stderr, "%s: Invalid argument \"%s\"\n",
+		       whoami, *argv);
+	       usage();
+	  }
+
+	  argc--; argv++;
+     }
+
+     ret = krb5_db_fini(context);
+     if (ret) {
+	  com_err(whoami, ret, "while closing database");
+	  exit(1);
+     }
+
+     return 0;
+}
diff --git a/mechglue/src/lib/kadm5/unit-test/randkey-test.c b/mechglue/src/lib/kadm5/unit-test/randkey-test.c
new file mode 100644
index 000000000..5722302de
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/randkey-test.c
@@ -0,0 +1,44 @@
+#include <kadm5/admin.h>
+#include <com_err.h>
+#include <stdio.h>
+#include <krb5.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#define	TEST_NUM    1000
+
+int main()
+{
+     ovsec_kadm_ret_t ret;
+     krb5_keyblock  *keys[TEST_NUM];
+     krb5_principal tprinc;
+     krb5_keyblock  *newkey;
+     krb5_context context;
+     void *server_handle;
+
+     int    x, i;
+
+     krb5_init_context(&context);
+
+     krb5_parse_name(context, "testuser", &tprinc);
+     ret = ovsec_kadm_init("admin", "admin", "ovsec_adm/admin", 0,
+			   OVSEC_KADM_STRUCT_VERSION,
+			   OVSEC_KADM_API_VERSION_1, NULL,
+			   &server_handle);
+     if(ret != OVSEC_KADM_OK) {
+	com_err("test", ret, "init");
+	exit(2);
+     }
+     for(x = 0; x < TEST_NUM; x++) {
+	ovsec_kadm_randkey_principal(server_handle, tprinc, &newkey);
+	for(i = 0; i < x; i++) {
+	    if (!memcmp(newkey->contents, keys[i]->contents, newkey->length))
+		puts("match found");
+	}
+	krb5_copy_keyblock(context, newkey, &keys[x]);
+	krb5_free_keyblock(context, newkey);
+     }
+     ovsec_kadm_destroy(server_handle);
+     exit(0);
+}
+
diff --git a/mechglue/src/lib/kadm5/unit-test/setkey-test.c b/mechglue/src/lib/kadm5/unit-test/setkey-test.c
new file mode 100644
index 000000000..eafa039e5
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/setkey-test.c
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+
+#if	HAVE_SRAND48
+#define	RAND()		lrand48()
+#define	SRAND(a)	srand48(a)
+#define	RAND_TYPE	long
+#elif	HAVE_SRAND
+#define	RAND()		rand()
+#define	SRAND(a)	srand(a)
+#define	RAND_TYPE	int
+#elif	HAVE_SRANDOM
+#define	RAND()		random()
+#define	SRAND(a)	srandom(a)
+#define	RAND_TYPE	long
+#else	/* no random */
+need a random number generator
+#endif	/* no random */
+
+krb5_keyblock test1[] = {
+    {0, ENCTYPE_DES_CBC_CRC, 0, 0},
+    {-1},
+};
+krb5_keyblock test2[] = {
+     {0, ENCTYPE_DES_CBC_RAW, 0, 0},
+     {-1},
+};
+krb5_keyblock test3[] = {
+     {0, ENCTYPE_DES_CBC_MD5, 0, 0},
+     {-1},
+};
+
+krb5_keyblock *tests[] = { 
+  test1, test2, test3, NULL
+};
+
+#if 0
+int keyblocks_equal(krb5_keyblock *kb1, krb5_keyblock *kb2)
+{
+  return (kb1->enctype == kb2->enctype &&
+	  kb1->length == kb2->length &&
+	  memcmp(kb1->contents, kb2->contents, kb1->length) == 0);
+}
+#endif
+
+krb5_data tgtname = {
+    0,
+    KRB5_TGS_NAME_SIZE,
+    KRB5_TGS_NAME
+};
+
+krb5_enctype ktypes[] = { 0, 0 };
+
+extern krb5_kt_ops krb5_ktf_writable_ops;
+
+int
+main(int argc, char **argv)
+{
+  krb5_context context;
+  krb5_keytab kt;
+  krb5_keytab_entry ktent;
+  krb5_encrypt_block eblock;
+  krb5_creds my_creds;
+  kadm5_principal_ent_rec princ_ent;
+  krb5_principal princ, server;
+  char pw[16];
+  char *whoami, *principal, *authprinc;
+  krb5_data pwdata;
+  void *handle;
+  int ret, i, test, encnum;
+
+  whoami = argv[0];
+
+  if (argc != 2 && argc != 3) {
+    fprintf(stderr, "Usage: %s principal [authuser]\n", whoami);
+    exit(1);
+  }
+  principal = argv[1];
+  authprinc = argv[2] ? argv[2] : argv[0];
+
+  /*
+   * Setup.  Initialize data structures, open keytab, open connection
+   * to kadm5 server.
+   */
+
+  memset((char *) &context, 0, sizeof(context));
+  krb5_init_context(&context);
+
+  ret = krb5_parse_name(context, principal, &princ);
+  if (ret) {
+    com_err(whoami, ret, "while parsing principal name %s", principal);
+    exit(1);
+  }
+    
+  if((ret = krb5_build_principal_ext(context, &server,
+				     krb5_princ_realm(kcontext, princ)->length,
+				     krb5_princ_realm(kcontext, princ)->data,
+				     tgtname.length, tgtname.data,
+				     krb5_princ_realm(kcontext, princ)->length,
+				     krb5_princ_realm(kcontext, princ)->data,
+				     0))) {
+       com_err(whoami, ret, "while building server name");
+       exit(1);
+  }
+
+  /* register the WRFILE keytab type  */
+  ret = krb5_kt_register(context, &krb5_ktf_writable_ops);
+  if (ret) {
+       com_err(whoami, ret,
+	       "while registering writable key table functions");
+       exit(1);
+  }
+
+  ret = krb5_kt_default(context, &kt);
+  if (ret) {
+       com_err(whoami, ret, "while opening keytab");
+       exit(1);
+  }
+
+  ret = kadm5_init(authprinc, NULL, KADM5_ADMIN_SERVICE, NULL,
+		   KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, NULL,
+		   &handle);
+  if (ret) {
+    com_err(whoami, ret, "while initializing connection");
+    exit(1);
+  }
+
+  /* these pw's don't need to be secure, just different every time */
+  SRAND((RAND_TYPE)time((void *) NULL));
+  pwdata.data = pw;
+  pwdata.length = sizeof(pw);
+  
+  /*
+   * For each test:
+   *
+   * For each enctype in the test, construct a random password/key.
+   * Assign all keys to principal with kadm5_setkey_principal.  Add
+   * each key to the keytab, and acquire an initial ticket with the
+   * keytab (XXX can I specify the enctype & kvno explicitly?).  If
+   * krb5_get_in_tkt_with_keytab succeeds, then the keys were set
+   * successfully.
+   */
+  for (test = 0; tests[test] != NULL; test++) {
+       krb5_keyblock *testp = tests[test];
+       printf("+ Test %d:\n", test);
+
+       for (encnum = 0; testp[encnum].magic != -1; encnum++) {
+	    for (i = 0; i < sizeof(pw); i++)
+		 pw[i] = (RAND() % 26) + '0'; /* XXX */
+
+	    krb5_use_enctype(context, &eblock, testp[encnum].enctype);
+	    ret = krb5_string_to_key(context, &eblock, &testp[encnum],
+				     &pwdata, NULL);
+	    if (ret) {
+		 com_err(whoami, ret, "while converting string to key");
+		 exit(1);
+	    }
+       }
+       
+       /* now, encnum == # of keyblocks in testp */
+       ret = kadm5_setkey_principal(handle, princ, testp, encnum);
+       if (ret) {
+	    com_err(whoami, ret, "while setting keys");
+	    exit(1);
+       }
+
+       ret = kadm5_get_principal(handle, princ, &princ_ent, KADM5_KVNO);
+       if (ret) {
+	    com_err(whoami, ret, "while retrieving principal");
+	    exit(1);
+       }
+
+       for (encnum = 0; testp[encnum].magic != -1; encnum++) {
+	    printf("+   enctype %d\n", testp[encnum].enctype);
+		   
+	    memset((char *) &ktent, 0, sizeof(ktent));
+	    ktent.principal = princ;
+	    ktent.key = testp[encnum];
+	    ktent.vno = princ_ent.kvno;
+
+	    ret = krb5_kt_add_entry(context, kt, &ktent);
+	    if (ret) {
+		 com_err(whoami, ret, "while adding keytab entry");
+		 exit(1);
+	    }
+
+	    memset((char *)&my_creds, 0, sizeof(my_creds));
+	    my_creds.client = princ;
+	    my_creds.server = server;
+	    
+	    ktypes[0] = testp[encnum].enctype;
+	    ret = krb5_get_in_tkt_with_keytab(context,
+					      0 /* options */,
+					      NULL /* addrs */,
+					      ktypes,
+					      NULL /* preauth */,
+					      kt, 0,
+					      &my_creds, 0);
+	    if (ret) {
+		 com_err(whoami, ret, "while acquiring initial ticket");
+		 exit(1);
+	    }
+
+	    /* since I can't specify enctype explicitly ... */
+	    ret = krb5_kt_remove_entry(context, kt, &ktent);
+	    if (ret) {
+		 com_err(whoami, ret, "while removing keytab entry");
+		 exit(1);
+	    }
+       }
+  }
+  
+  ret = krb5_kt_close(context, kt);
+  if (ret) {
+       com_err(whoami, ret, "while closing keytab");
+       exit(1);
+  }
+
+  ret = kadm5_destroy(handle);
+  if (ret) {
+       com_err(whoami, ret, "while closing kadmin connection");
+       exit(1);
+  }
+
+  return 0;
+}
+
+  
+  
+    
+    
+  
diff --git a/mechglue/src/lib/kadm5/unit-test/site.exp b/mechglue/src/lib/kadm5/unit-test/site.exp
new file mode 100644
index 000000000..18b435dd1
--- /dev/null
+++ b/mechglue/src/lib/kadm5/unit-test/site.exp
@@ -0,0 +1,2 @@
+set tool ovsec_kadm_srv_tcl
+set prompt "% "
diff --git a/mechglue/src/lib/kdb/.Sanitize b/mechglue/src/lib/kdb/.Sanitize
new file mode 100644
index 000000000..3e97cda7a
--- /dev/null
+++ b/mechglue/src/lib/kdb/.Sanitize
@@ -0,0 +1,48 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+decrypt_key.c
+encrypt_key.c
+fetch_mkey.c
+kdb_compat.h
+kdb_cpw.c
+kdb_dbm.c
+kdb_xdr.c
+keytab.c
+setup_mkey.c
+store_mkey.c
+t_kdb.c
+verify_mky.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/kdb/ChangeLog b/mechglue/src/lib/kdb/ChangeLog
new file mode 100644
index 000000000..ae159d434
--- /dev/null
+++ b/mechglue/src/lib/kdb/ChangeLog
@@ -0,0 +1,1159 @@
+2005-12-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5.c (kdb_load_library): Make dbpath_names static, to keep
+	Solaris native compiler happier.
+
+2005-10-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Include support library.  Don't
+	include system db library (if in use).
+
+	* libkdb5.exports: Delete __kdb2_*, kdb2_*, and a bunch of other
+	symbols that no longer exist in this library.
+
+2005-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't pull in libdb on AIX any more.
+
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (DBDIR, DBOBJLISTS, DBOBJLISTS-sys, DBOBJLISTS-k5):
+	Variables deleted.
+	(STOBJLISTS): Don't include DBOBJLISTS.
+
+	* kdb5.c (kdb_get_conf_section): If the default realm is null,
+	return null.
+	(krb5_db_open): Don't pass null pointer to sprintf if
+	default_realm is null.
+
+2005-09-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_db2: Directory moved to modules/kdb/db2.
+	* configure.in: Don't configure it.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-08-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5.c (kdb_load_library): Look up db_modules>db_module_dir in
+	config file, and use any indicated directories before the
+	compiled-in directories.
+
+2005-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5.c (kdb_get_library_name, kdb_load_library): Change default
+	name to "db2".
+	(kdb_get_library_name): On error reading from the config file,
+	don't just use the default.
+	(kdb_load_library): Don't add "lib" prefix on module name.
+
+2005-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* err_handle.c (krb5_err_key): Variable deleted.
+	(init_err_handling, krb5_set_err, krb5_get_err_string,
+	krb5_clr_error): Use k5_ macros for thread-specific data instead
+	of pthread versions.
+
+2005-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_kdb, check, clean): Delete t_kdb references.
+
+2005-06-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Add $(DL_LIB).
+
+	* err_handle.c, kdb5.c: Test ENABLE_THREADS, not just
+	HAVE_PTHREAD_H.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	Novell merge.
+	* Makefile.in (CFLAGS): Define KDB5_USE_LIB_KDB_DB2.
+	(LOCALINCLUDES): Add local directory.
+	(adb_err.c, adb_err.h, adb_err.$(OBJEXT)): New targets.
+	(SRCS, STLIBOBJS): Add adb_err, err_handle, kdb_default, kdb5;
+	delete kdb_db2, kdb_xdr, verify_mky, fetch_mkey, setup_mkey,
+	store_mkey.
+	* adb_err.et: Moved here from lib/kadm5.
+	* configure.in: Check for pthread.h.  Configure new kdb_db2
+	subdirectory.
+	* decrypt_key.c (krb5_dbekd_decrypt_key_data): Change definition
+	to prototype-style.
+	* encrypt_key.c: Likewise.
+	* err_handle.c, err_handle.h: New file.
+	* kdb5.c, kdb5.h: New file.
+	* fetch_mkey.c, setup_mkey.c, store_mkey.c, verify_mky.c:
+	Deleted.
+	* kdb_compat.h: Moved to kdb_db2 subdirectory.
+	* kdb_cpw.c: Don't include krb5/adm.h.
+	(cleanup_key_data): Use krb5_db_free.
+	(add_key_rnd): Use krb5_db_alloc for key storage.
+	(krb5_dbe_crk): Use krb5_db_free for key storage.
+	(add_key_pwd):
+	* kdb_db2.c, kdb_db2.h: Moved to kdb_db2 subdirectory.
+	* kdb_default.c:
+	* kdb_xdr.c:
+	* keytab.c:
+	* libkrb5.exports:
+	* t_kdb.c:
+	* t_krb5.conf:
+
+2005-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_dbm.c: Unused file deleted.
+
+2004-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_db2.c (krb5_db2_db_get_principal): Rename local variable
+	"try" to "trynum" because some systems (*cough*Tru64*cough*) turn
+	on some exception handling support when thread support is
+	enabled.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-05-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* keytab.c (krb5_ktkdb_get_entry): Change local variable rom int
+	to krb5_boolean to match prototype for as argument to
+	krb5_c_enctype_compare.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkdb5.exports: New file.
+
+2004-04-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_kdb.c (add_principal): Delete unused argument 'rseed'.
+	(do_testing): Update callers.
+
+	* keytab.c (krb5_ktkdb_get_entry): Don't use local variable
+	"context" until after it's been set.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* keytab.c (krb5_ktkdb_get_name): New function.
+	(krb5_kt_kdb_ops): Add pointer to it.
+
+2003-05-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* keytab.c (is_xrealm_tgt): Use strncmp instead of strcmp - as
+	principal and realm name do not need to be null terminated.
+
+2003-04-01  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove $(SHLIB_DBLIB_DEPS) and related variables.
+	(SHLIB_EXPDEPS): Remove $(SHLIB_DBLIB_DEPS).
+	(SHLIB_EXPLIBS): Change $(DB_LIB) to $(KDB5_DB_LIB).
+	(DBOBJLISTS, STOBJLISTS): Pull in object lists of in-tree libdb so
+	we don't need to install libdb.  Don't do this if building with
+	system libdb, though, since we need to explicitly link against the
+	system libdb in that case.
+
+2003-03-18  Tom Yu  <tlyu@mit.edu>
+
+	* keytab.c (krb5_ktkdb_get_entry): Do not perform the enctype
+	comparison if the requested enctype is a wildcard.
+
+2003-03-16  Sam Hartman  <hartmans@mit.edu>
+
+	* keytab.c (krb5_ktkdb_get_entry):  Match only against the first
+	enctype  for non-cross-realm tickets so we will only accept
+	tickets that the current configuration would have issued.  For
+	cross-realm tickets be liberal and match against the specified
+	enctype. 
+
+2003-03-05  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_search_enctype): Check for ktype > 0 rather
+	than ktype >= 0; file keytab uses ktype 0 to indicate "first
+	match", as does acquire_cred.  The kdc uses -1, though.
+
+	* Makefile.in (LIBMAJOR): Bump major version due to change in
+	krb5_ktkdb_resolve's signature.
+
+	* keytab.c (krb5_ktkdb_resolve): Add NAME parameter, which is
+	ignored, so that kdb keytab can be registered.
+	(krb5_ktkdb_set_context): New function; allows caller to set a
+	different context for use with ktkdb_get_entry().  This is
+	primarily useful for kadmind, where the gssapi library context,
+	which will be used for the keytab, will necessarily have a
+	different context than that used by the kadm5 library to access
+	the database for its own purposes.
+
+2003-02-08  Tom Yu  <tlyu@mit.edu>
+
+	* keytab.c (krb5_ktkdb_get_entry): Fix comment; not going to
+	redesign key storage architecture for 1.3.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_ARCHIVE,
+	AC_PROG_ARCHIVE_ADD, AC_PROG_RANLIB, AC_PROG_INSTALL.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* setup_mkey.c (krb5_db_setup_mkey_name): Use size_t instead of
+	int for lengths.
+
+2002-12-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (check): Remove test_db before running tests.
+
+2002-12-16  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in: Change to allow compilation with-system-db and
+	shared libraries.
+
+2002-09-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_db2.c (krb5_db2_db_iterate_ext): Don't call bt_rseq if
+	HAVE_BT_RSEQ is undefined; instead, just return an error.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-23  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_db2.h: Add prototype and rename for
+	krb5_db2_db_iterate_ext().
+
+	* kdb_db2.c (krb5_db2_db_iterate_ext): New function; allow
+	optional backwards or recursive (if btree) traversal of the
+	database.
+
+	* Makefile.in (LIBMINOR): Bump due to addition of
+	krb5_db_iterate_ext().
+
+2002-08-15  Tom Yu  <tlyu@mit.edu>
+
+	* keytab.c (krb5_ktkdb_get_entry): For consistency, check for
+	DISALLOW_ALL_TIX and DISALLOW_SVR when looking up keys.
+
+2002-08-09  Sam Hartman  <hartmans@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_search_enctype): Initialize ret to 0; thanks
+	to  Lubos Kejzlar <kejzlar@civ.zcu.cz> 
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBMINOR): Bump due to some behavior changes
+	regarding enctype similarity.  (Importing Tom's change from 1.2.x
+	branch.)
+
+2002-02-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_lookup_mod_princ_data): Use const instead of
+	krb5_const.
+
+2001-11-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_kdb.c (do_testing): Invoke krb5_free_principal and
+	krb5_free_keyblock_contents on master key to prevent minor memory
+	leak.
+
+2001-10-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_cpw.c (cleanup_key_data): Do not free NULL pointer.
+
+2001-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_xdr.c (krb5_encode_princ_contents): Use krb5_ui_2 instead of
+	krb5_int16 for key_data_length.
+
+2001-10-22  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_search_enctype): Filter out enctypes that
+	aren't in permitted_enctypes.  This prevents the KDC from issuing
+	a ticket whose enctype that it won't accept.
+
+2001-10-20  Tom Yu  <tlyu@mit.edu>
+
+	* keytab.c (krb5_ktkdb_get_entry): For now, coerce enctype of
+	output keyblock in case we got a match on a similar enctype.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_db2.c, kdb_db2.h, kdb_dbm.c, keytab.c, t_kdb.c: Make
+	prototypes unconditional.
+
+2001-07-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_update_mod_princ_data,
+ 	krb5_encode_princ_contents): Delcare local variable unsigned.
+
+	* kdb_cpw.c (add_key_pwd): Declare local variable unsigned based
+	on use.
+
+2001-04-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_dbm.c (destroy_file_suffix): Declare as static.
+
+2001-03-10  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb_xdr.c: Change the variable index to idx to prevent function
+	name shadowing.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_CHECK_HEADERS instead of AC_HAVE_HEADERS. 
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* fetch_mkey.c: Signed/unsigned int cleanup. 
+
+	* kdb_cpw.c (add_key_pwd): Change salt data length of -1 to
+	SALT_TYPE_AFS_LENGTH.
+
+2000-09-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_free_contents): Clean up signedness warning.
+
+	* fetch_mkey.c (krb5_db_fetch_mkey): Clean up signedness warnings. 
+
+	* kdb_db2.c (destroy_file_suffix): Declare function as
+	static. Rewrite code to use off_t and unsigned ints to handle gcc
+	warnings. (kdb5_context_internalize) Unmarshal boolean type properly. 
+	
+	* store_mkey.c (krb5_db_store_mkey): Use mode_t instead of int in
+	call to umask.
+
+	* configure.in: Add AC_TYPE_MODE_T and AC_TYPE_OFF_T for mode_t
+	and off_t declarations.
+
+2000-07-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* encrypt_key.c, kdb_cpw.c, kdb_xdr.c: Add parenthesis about
+	assignment in conditional and remove unused variables.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): Add libdb, since we can build this
+	shared now.
+	(SHLIB_EXPLIBS): Add -ldb.
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* t_kdb.c (gen_principal): Don't overflow "pnamebuf" if bad data was
+	passed in.
+
+2000-05-03  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* setup_mkey.c (krb5_db_setup_mkey_name): Use REALM_SEP_STRING
+	when computing size of buffer that is to include it.
+
+	* fetch_mkey.c (krb5_db_fetch_mkey): Make sure "defkeyfile" is
+	null terminated after construction.
+	* store_mkey.c (krb5_db_store_mkey): Likewise.
+
+2000-04-27  Ken Raeburn  <raeburn@mit.edu>
+	    Ezra Peisach  <epeisach@mit.edu>
+
+	* t_kdb.c (gen_principal): Force argument to isalnum to be in
+	range 0..255.
+	(do_testing): Cast pid_t to long before passing to fprintf, and
+	use %ld format.  Fix argument lists to find_principal and
+	delete_principal.
+
+2000-03-16  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_lookup_mod_princ_data): Get rid of
+	unused variable.
+
+2000-03-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_lookup_mod_princ_data): In casting argument
+	to krb5_parse_name, use krb5_const not const.
+
+2000-02-21  Bear Giles  <bgiles@coyotesong.com>
+
+	* fetch_mkey.c (krb5_db_fetch_mkey): Don't attempt to override
+	type of key read from stash file.
+
+2000-02-18  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_cpw.c (krb5_dbe_crk): 
+	(krb5_dbe_cpw): Fix to actually save old keys.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_kdb.c (add_principal): Free only contents of a generated key,
+	since the keyblock structure itself is on the stack.
+
+1999-08-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_kdb.c (add_principal): Update for new calling sequence to
+	krb5_dbekd_encrypt_key_data.
+	(do_testing): Update calls.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Tue Nov 17 18:19:41 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_cpw.c (krb5_dbe_crk): 
+	(krb5_dbe_cpw): Add "keepold" boolean argument to indicate whether
+	to retain old keys.
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* kdb_xdr.c, kdb_cpw.c: remove the special knowledge of ENCTYPE
+	string-to-key equivalances.  the crypto api has a function for
+	this now.
+
+	* decrypt_key.c, encrypt_key.c, fetch_mkey.c, kdb_cpw.c,
+	kdb_db2.c, kdb_db2.h, kdb_dbm.c, keytab.c, verify_mky.c: change or
+	remove all the places krb5_encrypt_block was used
+	(this is mostly relevant to kdb manipulations).  It was usually
+	used to specify an enctype (which is now implied by the keyblock),
+	or to store or pass in a processed key (now the api just takes a
+	key directly, so these structures and functions do, too).  The kdb
+	key manuipulation functions also need to be made to use the new
+	api.
+
+Fri Sep 25 19:42:10 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_xdr.c (krb5_dbe_search_enctype): Re-order booleans so that
+	similar doesn't get checked unless (ktype >= 0) to avoid it being
+	stack garbage.
+
+Sun Aug 16 16:52:10 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* Makefile.in (SHLIB_EXPLIBS): Include $(LIBS) so building on AIX works
+
+Sun Jul 26 18:12:22 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* Makefile.in (LIBMAJOR): bump libmajor
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* t_kdb.c (main): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Wed Apr 15 18:06:34 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): 
+	(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
+
+Fri Feb 27 21:21:03 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Remove check for the regular expression functions,
+		since they aren't used in lib/kdb.
+
+Wed Feb 18 16:16:35 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+ 	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Oct 28 10:18:10 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_cpw.c (add_key_pwd): For KRB5_KDB_SALTTYPE_AFS3, the salt
+	 	key for afs_mit_string_to_key mut be null terminated. 
+
+Mon Oct 13 10:18:19 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_kdb.c (do_testing): Add krb5_free_context.
+
+Mon Sep 15 15:05:30 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* keytab.c: (krb5_ktkdb_get_entry): Incoming principal is const.
+
+	* kdb_dbm.c (krb5_dbm_db_get_principal, krb5_dbm_db_delete_principal):
+	        Incoming principal is const.
+
+	* kdb_xdr.c (krb5_dbe_update_mod_princ_data, krb5_encode_princ_dbkey): 
+	        Incoming principal is const.
+
+	* kdb_db2.h (krb5_db2_db_get_principal): Change prototype to const
+                principal.
+
+	* kdb_db2.c (krb5_db2_db_get_principal, krb5_db2_db_delete_principal):
+	        The search for principal is const.
+
+Thu Jul 31 14:54:10 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb_db2.c (krb5_db2_db_delete_principal): Fix switch statement
+	        so that all cases have one statement.
+
+Tue Jul 29 02:35:09 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_db2.c (krb5_db2_db_set_hashfirst): Don't cast a
+	krb5_context * to a krb5_db2_context *.
+
+Fri Jul 25 15:29:03 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kdb_db2.c: Fix typo; also, tweak page size in attempt to speed
+	things up.
+
+	* kdb_db2.h: Fix typo.
+
+	* t_kdb.c: Reflect changes in the API, mostly db_create.
+
+	* Makefile.in: Bump version due to major reworking.
+
+	* kdb_db2.h:
+	* kdb_db2.c: Add Berkely DB backend.
+
+	* keytab.c: Add support for new kdb API; delete dead arguments.
+
+	* kdb_xdr.c: Remove dependencies on dbm; encode things to
+	krb5_datas rather than datums.
+
+Mon Mar 24 12:19:03 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* t_kdb.c (do_testing): Clean up error handling for krb5_init_context.
+
+	* Makefile.in (check): Define and use KRB5_CONFIG_SETUP which sets
+ 		up the environment variables appropriately.
+
+Sun Mar 16 21:20:00 1997  Tom Yu  <tlyu@mit.edu>
+
+	* keytab.c: Don't assume dbm_db_get_mkey() and dbe_find_enctype
+	won't error out.  Also, some gcc -Wall warning
+	cleanups. [krb5-kdc/361]
+
+Sat Feb 22 01:15:30 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): depend on -lcrypto
+
+Thu Feb  6 15:33:34 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Wed Jan  8 01:59:15 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in, configure.in: Convert to new build procedure for libs.
+
+Mon Nov 18 20:40:12 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Set shared library version to 1.0. [krb5-libs/201]
+
+Tue Nov 12 23:41:55 1996  Mark Eichin <eichin@cygnus.com>
+
+	* kdb_dbm.c: Ditch DB_OPENCLOSE conditionals, and fix the real
+ 	problem.  Like the policy db, the main db is now opened on first
+ 	lock and closed on last unlock.  
+	Set db_dbm_ctx to NULL after closing it, to help detect dangling
+	references.
+	(krb5_dbm_db_put_principal, krb5_dbm_db_delete_principal):
+ 	KDBM_STORE can fail (in case of database corruption, for example)
+ 	*without* causing errno to be set.  If errno is zero, use
+ 	KRB5_KDB_DB_CORRUPT instead. (If it is non-zero, it may still be
+ 	wrong, but at least something gets reported. This will be properly
+	fixed by ditching KDBM_* altogether, and using the non-lossy db
+	interfaces, so it's a good enough fix for now.)
+	(krb5_dbm_db_rename): grab errno from rename *before*
+ 	calling krb5_dbm_db_end_update, to avoid "not a typewriter"
+ 	syndrome.
+ 	(krb5_dbm_db_unlock): only close on zero refcount.
+
+Mon Nov 11 20:21:02 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kdb_cpw.c (add_key_pwd): set length to -1 so krb5_string_to_key
+	handles the AFS3 salttype, but then replace it with the actual
+	length for later processing.
+
+Mon Nov 11 17:03:16 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdb_cpw.c (cleanup_key_data): fix memory leak [krb5-kdc/163]
+	(add_key_pwd): fix memory leak [krb5-kdc/164]
+
+Sat Nov  9 15:57:50 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_krb5.conf: Dummy krb5.conf file from the krb5 library. 
+
+	* Makefile.in (check): Set KRB5_CONFIG to a valid krb5.conf file.
+
+	* t_kdb.c (do_testing): Check return value from krb5_init_context.
+
+Thu Oct 31 11:10:56 1996  Ezra Peisach  <epeisach@trane.rose.brandeis.edu>
+
+	* Makefile.in (t_kdb): Link with $(TOPLIBD)/libdb.a
+
+Wed Sep  4 19:29:57 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (t_kdb): Fix up dependencies of t_kdb so it will
+		build on non-shared architectures; also ensure that libs
+		get linked after the objects.
+
+Fri Aug 23 16:34:45 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (t_kdb): Fix Makefile so that t_kdb is linked
+	 	correctly with the appropriate libraries.
+
+Thu Aug 22 16:22:01 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdb_dbm.c: Remove vestigal code which was using BERK_DB_DBM
+		define.  Still need to remove kludgey database "switch"
+		code and recode to use the db interface.
+
+	* t_kdb.c: Update t_kdb to use the new libkdb interface.
+
+Mon Aug 12 14:11:29 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdb_dbm.c (krb5_dbm_db_rename): rename should not insist that
+ 	the target database not already exist
+
+Fri Aug  9 15:21:34 1996  Ezra Peisach  <epeisach@dumpster.rose.brandeis.edu>
+
+	* Makefile.in (shared): Convert shared:: to shared: so will not
+		always be called upon. 
+
+Thu Aug  8 20:26:47 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (shared): Always mkdir shared; test -d shared ||
+		mkdir shared breaks under Ultrix sh (grrr...).
+
+Thu Aug  8 18:29:15 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* keytab.c (krb5_ktkdb_get_entry): Return KRB5_KT_NOTFOUND if the
+ 	principal doesn't exist instead of dereferencing a null pointer.
+
+Fri Aug  2 14:08:03 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in(LIBS): AIX wants to link against -ldb when building
+ 	the shared lib.
+
+Mon Jul 29 23:07:14 1996  Samuel D Hartman  (hartmans@vorlon)
+
+	* kdb_dbm.c: Don't bother referencing dbm_pagfno, because we don't
+        actually use it; same for dbm_dirfno.
+
+Tue Jul 23 11:09:08 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: libkdb5.so needs to be built with
+		libcrypto and libkrb5.
+
+	* configure.in: Pass version numbers of teh crypto and krb5 shared
+		libraries. 
+
+Fri Jul 12 15:32:26 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kdb_cpw.c (add_key_pwd): initialize retval = 0, in case the
+ 	function is called with ks_tuple_count == 0.
+
+Wed Jul 10 16:22:14 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in (USE_KDB5_LIBRARY): removed.  the library does not
+ 	need itself to build, and in fact fails to do so if I try.
+	* Makefile.in (clean-unix): remove the shared/ subdir
+
+Tue Jul  9 17:55:30 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in, Makefile.in: added rules and macros to do shared
+ 	library creation
+
+Mon Jul  8 17:06:00 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kdb_dbm.c: Create DB_OPENCLOSE, which opens and closes the
+ 	databases for each lock.  This is slower than the previous method,
+ 	but unlike the previous method it works.
+
+Tue Jun 11 19:27:22 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* keytab.c (krb5_ktkdb_close): Free memory allocated by
+		krb5_ktkdb_resolve. 
+
+Mon May 20 18:02:07 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdb_dbm.c (krb5_dbm_db_create): Remove vestigal ODBM support.
+
+Sat May 18 15:07:09 1996  Ezra Peisach  (epeisach@paris)
+
+	* kdb_dbm.c: Do not provide prototypes for dbm_error or
+		dbm_clearerr if they are really macros.
+
+Sun May 12 01:03:07 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kdb_xdr.c: reworked all of the krb5_dbe_* tl_data functions.
+  	This was necessary so that the admin system could store it's own
+ 	tl_data, without needing code here.  This has the side-effect of
+ 	eliminating some structures which added no value, therefore
+ 	changing about a half-dozen files elsewhere in the tree.
+
+	* kdb_cpw.c (add_key_rnd): handle kvno incrementing in the caller,
+ 	not here.
+	(krb5_dbe_crk): increment the kvno here, not in add_key_rnd
+	(krb5_dbe_ark): increment the kvno here, not in add_key_rnd
+	(add_key_pwd): handle kvno incrementing in the caller, not here.
+	(krb5_dbe_cpw): take an arg to specify the new kvno.  if it's
+	<= the old kvno, just increment.  Otherwise, pass it to add_key_pwd.
+	This is why all the code in this revision was changed.
+	(krb5_dbe_apw): increment the kvno here, not in add_key_pwd
+
+Tue May  7 19:48:57 1996  Ezra Peisach  <epeisach@dumpster.rose.brandeis.edu>
+
+	* t_kdb.c (do_testing): Compile if using BERK_DB and dbm is not
+        available on system.
+
+Thu Mar 21 20:38:38 1996  Richard Basch  <basch@lehman.com>
+
+	* decrypt_key.c (krb5_dbekd_decrypt_key_data): bullet-proofing the
+	code -- if the data contents are NULL, do not coredump.
+
+Mon Mar 18 21:46:39 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add KRB5_RUN_FLAGS
+
+	* Makefile.in: Use the run flags.
+
+Sun Mar 17 20:55:41 1996  Ezra Peisach  <epeisach@dumpster.rose.brandeis.edu>
+
+ 	* configure.in: Change WITH_KDB_DB to USE_KDB5_LIBRARIES and add
+		KRB5_LIBRARIES.
+
+	* Makefile.in: Use libraries as specified by configure. Set
+		LD_LIBRARY_PATH for tests.
+
+Sun Mar  3 10:41:04 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Change WITH_DB to WITH_KDB_DB
+
+Fri Feb 23 19:39:52 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* keytab.c (krb5_ktkdb_close): new function, non-optional.
+	(krb5_kt_kdb_ops): include _close method, comment what the other
+	slots are.
+
+Tue Feb 13 21:33:03 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb_dbm.c (krb5_dbm_db_rename): Initialize pointer before use
+		for case where new db does not exist.
+
+Tue Jan 30 18:26:38 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kdb_dbm.c (krb5_dbm_db_rename): O_EXCL is meaningless without
+	O_CREAT.
+
+Sat Jan 27 01:01:17 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* t_kdb.c: wrap db_dbm decls and berkely_dispatch in ifdefs
+	BERK_DB_DBM.
+	(do_testing): wrap references as well.
+
+	* keytab.c (krb5_ktkdb_get_entry): use KRB5_PROTOTYPE.
+
+Wed Dec 13 09:28:33 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* keytab.c (krb5_ktkdb_resolve): Fix casting
+
+	* t_kdb.c (add_principal): Remove mkvno
+
+Wed Dec 13 07:09:30 1995  Chris Provenzano (proven@mit.edu)
+
+	* Makefile.in, keytab.c : Move db keytab routines here.
+
+Wed Dec 13 03:51:53 1995  Chris Provenzano (proven@mit.edu)
+
+        * kdb_xdr.c : Remove mkvno for krb5_db_entry
+
+Tue Dec 12 01:20:02 1995  Chris Provenzano (proven@mit.edu)
+
+	* kdb_dbm.c : Move the krb5_db_context to include/krb5/kdb_dbc.h.
+	* kdb_dbm.c krb5_dbm_db_set_mkey(), krb5_dbm_db_get_mkey():
+		Functions for associating a master key (krb5_encrypt_block *)
+		to a krb5_db_context. Currently it associates it to the
+		krb5_context and will be fixed once the krb5_db_context
+		is better defined (Post 1.0).
+
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * fetch_mkey.c, kdb_cpw.c, t_kdb.c : 
+		Remove krb5_enctype from krb5_string_to_key() args.
+
+Tue Nov  7 16:35:03 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdb_xdr.c (krb5_dbe_search_enctype): Make a more general version
+		of kdb5_dbe_find_enctype() which allows you to search the
+		keylist looking for multiple keys that fit your criteria.
+		Eventually we should convert all programs to use
+		kdb5_dbe_search_enctype() instead of kdb5_dbe_find_enctype().
+
+Fri Nov 03 04:49:58 1995  Chris Provenzano (proven@mit.edu)
+
+	* decrypt_key.c (krb5_dbekd_decrypt_key_data()) : If key salt length
+		is 0 then set keysalt->data.data to NULL.
+	* kdb_cpw.c (add_key_rnd(), add_key_pwd()) : When creating new keys 
+		for a new kvno and there are multiple enctypes that use a 
+		common keytype, then set the enctype in the key to the first
+		specified enctype and skip all other enctypes that use 
+		the same keytype. (This assumes the salt type is the same too.)
+		This way when the kdc needs to get the server key it doesn't
+		need to gues what enctypes the server supports.
+	* kdb_xdr.c (krb5_dbe_find_enctype()): Match keys that use common
+		keytypes but different enctypes. Eg. ENCTYPE_DES_CBC_MD5
+		matches ENCTYPE_DES_CBC_CRC and vice versa.
+	* kdb_xdr.c krb5_dbe_find_enctype()): If kvno = 0 then determine
+		maxkvno for all the keys and then search keys for a key that 
+		matches enctype salttype and has kvno == maxkvno. This
+		is different than when kvno = -1 which searches the keys
+		for THE key with the greatest kvno which also matches enctype
+		and salttype.
+	* kdb_kdr.c (krb5_dbe_find_enctype()): If kvno = ktype = stype = -1
+		then set kvno = 0. The first doesn't make a lot of sense.
+	* kdb_xdr.c (krb5_dbe_encode_last_pwd_change(), 
+		krb5_dbe_decode_last_pwd_change()) : Added.
+	* kdb_xdr.c (krb5_decode_princ_contents()) : Don't try to allocate 
+		space for keys if n_key_data = 0. 
+
+Mon Sep 25 17:31:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+	        Makefile.
+
+Wed Sep 13 15:19:17 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kdb_xdr.c (krb5_dbe_encode_mod_princ_data): Fix memory leaks.
+		Fix lint flames.
+
+	* fetch_mkey.c (krb5_db_fetch_mkey): This routine now sets the
+		master encblock's crypto system using krb5_use_enctype()
+		from the stored keytype of the master key.
+
+	* decrypt_key.c (krb5_dbekd_decrypt_key_data): Remove the
+		encryption type; the master_encblock should always be set
+		correctly.
+
+Sat Sep  9 14:53:39 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* decrypt_key.c (krb5_dbekd_decrypt_key_data): Set the encryption
+		type before decrypting.
+
+Fri Sep  8 19:52:34 1995  Ezra Peisach  (epeisach@dcl)
+
+	* decrypt_key.c: Upon error, after freeing contents field, set to
+		null to indicate to upper levels that it is really empty.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * decrypt_key.c, encrypt_key.c, fetch_mkey.c, kdb_compat.c,
+	* kdb_cpw.c, kdb_xdr.c, store_mkey.c, t_kdb.c : 
+		s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * decrypt_key.c, fetch_mkey.c, t_kdb.c : Remove krb5_enctype 
+		references, and replace with krb5_keytype where appropriate
+
+Tue Aug 29 13:34:23 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_dbm.c - Add routines to support serialization of the database
+		context.  Clean up gcc -Wall complaints.
+
+Thu Aug 24 18:54:51 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Fri Aug 18 17:27:20 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_dbm.c - Bump timestamp to the future if we can't discriminate
+		between updates within a second.  Fix database rename.  Reopen
+		database after put or delete.
+	* t_kdb.c - Add test code to fork off a few processes to beat on the
+		database.
+
+
+Thu Aug 17 13:46:29 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_dbm.c - Remove argument from dbm_db_end_update().  It was never
+		used.  Remove gen_dbsuffix() logic from dbm_db_end_update() and
+		dbm_db_get_age().  This logic was incorrect (end_update) or
+		unused (get_age).  Reorg db_init() to reflect change in
+		dbm_db_get_age().
+
+
+Wed Aug 16 03:10:57 1995  Chris Provenzano  <proven@mit.edu>
+
+	* decrypt_key.c, encrypt_key.c
+		Only save the salt data if salt type != 0.
+	* kdb_dbm.c :
+		Rewritten to NOT open/close the db for every transaction.
+
+Tue Aug 15 14:25:42 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_xdr.c - Add krb5_dbe_find_keytype() and clean up gcc -Wall
+		complaints.
+
+
+Wed Aug 9 17:17:36 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_cpw.c - Add check for uniqueness of key or key/salt combo.  Don't
+		generate a new key_data entry if one already exists.  Also,
+		fill in the key_data list at the end so as not to overwrite
+		already present data.
+		- Free krbtgt_keyblock contents in add_key_rnd().
+		- Put a "break" at the end of the KRB5_KDB_SALTTYPE_ONLYREALM
+		  in add_key_pwd().  Also pass in key_salt to encrypt_key_data
+		  always.
+	* kdb_xdr.c - initialize retval to 0 in decode_mod_princ data.  This is
+		questionable whether we should return an error if there's no
+		mod_princ data.  Also, free the allocated mod_princ only if
+		we allocated it and there's a failure.
+
+
+Wed Aug 9 09:47:08 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_cpw.c(add_key_rnd) - Terminate the variable length argument list
+		to krb5_build_principal_ext() with a zero.
+
+Tue Aug  8 21:32:30 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* kdb_cpw.c (add_key_rnd): remove bletcherous aggregate
+		initializer stuff and use build_principal_ext like we
+		should have in the first place to build the tgt principal.
+
+Tue Aug 8 17:35:58 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* encrypt_key.c - When allocating the actual key_data_contents use the
+		correct length (e.g. containing the two length bytes).
+	* kdb_xdr.c - Clean the each key_data structure so that unfilled
+		data becomes zero.
+
+
+Mon Aug 7 17:40:10 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* encrypt_key.c - Handle keysalt specification with null data length.
+	* decrypt_key.c - Handle salttypes with zero salt length.  Also, copy
+		out stored salt.
+
+
+Mon Aug 7 14:15:59 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* decrypt_key.c - Deserialize key length into a 16 bit integer, then
+		jam it into the keyblock.
+
+
+Mon Aug 7 13:05:53 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_cpw.c(add_key_rnd) - Manually initialize krbtgt_princ.data to
+		point to krbtgt_princ_entries since some compilers do not
+		support dynamic initializers.
+
+
+Mon Aug 07 11:27:37 1995  Chris Provenzano (proven@mit.edu)
+
+	* kdb_cpw.c: New routines for changing passwords of db_entried.
+
+Fri Aug  4 23:26:22 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* setup_mkey.c (krb5_db_setup_mkey_name), 
+	* fetch_mkey.c (krb5_db_fetch_mkey), 
+	* verify_mky.c (krb5_db_verify_master_key),
+	* decrypt_key.c (krb5_dbekd_decrypt_key_data),
+	* encrypt_key.c (krb5_dbekd_encrypt_key_data),
+	* kdb_xdr.c, kdb_dbm.c,
+		Add parens to shut up gcc -Wall
+
+Fri Aug 4 16:22:46 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_xdr,{de,en}crypt_key.c - Use encode/decode macros to [de]serialize
+		data going in and out of the database.
+
+
+Thu Aug 3 11:52:40 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* encrypt_key.c - Actually copy in the salt data which we allocated
+		space for in krb5_dbekd_encrypt_key_data().
+	* kdb_xdr.c - Correctly generate the tl_data list in krb5_decode_princ_
+		contents().  Also allow for key_data_ver to be KRB5_KDB_V1_DATA_
+		ARRAY.
+
+
+Mon Jul 31 15:55:46 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_xdr.c - Correctly parenthesize realloc() expression in create_key
+		_data().
+
+
+Thu Jul 27 15:28:41 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdbint.h - Obsolete.
+
+Thu Jul 27 02:59:05 1995  Chris Provenzano (proven@mit.edu)
+        * decrypt_key.c, encrypt_key.c, kdb_dbm.c, kdb_xdr.c:
+		Rewritten for new kdb format.
+	* kdb_cpw.c : New password changing routines for new kdb format.
+	* verify_mky.c, t_kdb.c : Use new kdb format.
+
+Tue Jul 25 14:06:50 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* kdb_dbm.c, t_kdb.c: Add prototype for dbm_error and dbm_clearerr
+		in case they're not prototyped in the header files.
+
+	* configure.in: Add test for missing prototypes for dbm_error and
+		dbm_clearerr.
+
+Thu Jul 20 23:59:18 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* kdb_dbm.c (krb5_dbm_db_create): move dirname, pagname
+	declarations to the top of function, so it compiles...
+
+Mon Jul 17 15:17:53 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* fetch_mkey.c - Remove inclusion of kdbint.h and add handling of
+		stash file argument.
+	* store_mkey.c - Remove inclusion of kdbint.h.  The default name of
+		the stash file is in osconf.h now.
+
+Sat Jul  8 22:37:14 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb_dbm.c (kdb5_kdbm_db_create): Make sure the dbm context is
+		initialized before we start.
+
+Fri Jul 7 16:29:22 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS, find com_err in TOPLIBD.
+
+
+Fri Jun 30 14:39:45 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_dbm.c - Add function dispatch table to context and use it to
+		perform database accesses.  Add kdb5_db_set_dbops() to set
+		a context's function dispatch table.
+	* Makefile.in - Remove Berkeley database object modules from this
+		library.  They're now in libkrb5 since we use them in
+		other places.
+	* t_kdb.c - Add ability to test both DBM and Berkeley database
+		format.
+
+Thu Jun 29 06:54:00 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in (--with-dbm): new option, allows easy building of
+	normal dbm support for compatibility.
+	* Makefile.in (DBFLAGS): variable to hold substitution of flags to
+	enable Berkeley db support.
+
+Thu Jun 22 11:59:28 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_dbm.c - Replace static kdb context with context which is attached
+		to krb5 context.  This allows for multiple open databases
+		within the same process.
+
+
+Thu Jun 15 18:04:58 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit copying of archive library to library
+		directory.  Add dependency on all-$(WHAT)
+	* configure.in - Create symlink for archive when we build it.
+
+Wed Jun 14 12:37:51 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* configure.in: Check for umask being defined.
+
+	* store_mkey.c (krb5_db_store_mkey): Use HAVE_UMASK instead of
+	unix as a preprocessor define for setting the umask.  AIX doesn't
+	define unix.
+
+	* t_kdb.c (main): Declare option as int, not char.  When char is
+	unsigned, the comparison to EOF fails and it loops forever.
+
+
+Sun Jun 11 09:26:48 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean): Remove t_kdb and t_kdb.o
+
+Fri Jun  9 19:26:49 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Tue May 30 12:31:26 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in: ranlib the library again after doing $(LIBUPDATE).
+		Some archivers don't do this.
+
+Fri May 26 17:52:03 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb_dbm.c - Change usage of dbm package or Berkeley db package
+		based on setting of BERK_DB_DBM.  Also, conditionalize
+		implicit knowledge of dbm/Berkeley db filename extensions.
+	* Makefile.in - Set BERK_DB_DBM when compiling.  Update from Berkeley
+		db build directory.
+	* configure.in - Check for random number generators.
+	* t_kdb.c - New tester for kdb code.
+
+Fri Mar 24 21:59:34 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* store_mkey.c (krb5_db_store_mkey): 
+	* fetch_mkey.c (krb5_db_fetch_mkey): Hardcode the size of the
+		keytype field in the file format, to be compatible with
+		what was used in the Beta 4 release (before we changed the
+		size of a krb5_keytype type).
+
+Fri Mar 24 15:13:53 1995    <tytso@rsx-11.mit.edu>
+
+	* kdb_dbm.c: Don't cast dbm_close() to void, because dbm_close is
+		already void.
+
+Tue Feb 28 00:30:10 1995  John Gilmore  (gnu at toad.com)
+
+	* decrypt_key.c, encrypt_key.c, fetch_mkey.c, kdb_dbm.c,
+	setup_mkey.c, store-mkey.c, verify_mky.c:  Avoid <krb5/...> includes.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Thu Nov 17 19:22:16 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* kdb_dbm.c (krb5_dbm_db_unlock): Use krb5_lock_file.
+	(krb5_dbm_db_lock): Same. (Changes from jtkohl@mit.edu.)
+
+Thu Nov 10 17:20:42 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* decrypt_key.c (krb5_kdb_decrypt_key): Set the keyblock's magic
+		number and ecryption type information appropriately.
+
+Tue Nov  8 18:03:23 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* fetch_mkey.c (krb5_db_fetch_mkey): Set the keyblock's magic
+		number and encryption type information appropriately.
+
+Sat Oct 22 10:13:25 1994    (tytso@rsx-11)
+
+	* kdb_dbm.c: Don't need to define POSIX_FILE_LOCKS; just include
+		config.h instead.
+
+Wed Oct 19 12:15:36 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR) completely
+
+Fri Oct 14 00:57:33 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add test for unistd.h
+
+	* lock_file.c: Use POSIX_FILE_LOCKS if _POSIX_VERSION is defined
+		in unistd.h
+
+Tue Oct  4 15:08:03 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb_dbm.c (decode_princ_contents): Add backwards compatibility
+		for version numbers 1.0 and 2.0.  
+
+Mon Oct  3 22:47:49 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb_dbm.c (decode_princ_contents): Force an incompatible version
+		number change to the database --- we are now at database
+		entry version 2.0.  Unfortunately, the way we encode the
+		database is completely broken, and any structure changes
+		change the encoding format.  We will need to redo this
+		completely at some point, so we don't have to make people
+		go through this again.
+
+	* Makefile.in: make install obey $(DESTDIR)
+
+Thu Aug  4 03:41:44 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: look for install program
+
+	* Makefile.in: make install fixes
+
+Fri Jul 15 14:54:10 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* kdb_dbm.c (krb5_dbm_db_end_update): Change use of utimes() to
+	the POSIX utime() function.
+
+
diff --git a/mechglue/src/lib/kdb/Makefile.in b/mechglue/src/lib/kdb/Makefile.in
new file mode 100644
index 000000000..e33a2d445
--- /dev/null
+++ b/mechglue/src/lib/kdb/Makefile.in
@@ -0,0 +1,108 @@
+thisconfigdir=.
+myfulldir=lib/kdb
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ;
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+CFLAGS=@CFLAGS@ -DKDB5_USE_LIB_KDB_DB2
+LOCALINCLUDES= -I.
+
+LIBBASE=kdb5
+LIBMAJOR=4
+LIBMINOR=0
+RELDIR=kdb
+# Depends on libk5crypto and libkrb5
+
+SHLIB_EXPDEPS = \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(TOPLIBD)/libkrb5$(SHLIBEXT)
+SHLIB_EXPLIBS=-lkrb5 -lcom_err -lk5crypto $(SUPPORT_LIB) $(DL_LIB) $(LIBS)
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+all:: 
+
+adb_err.$(OBJEXT): adb_err.c
+adb_err.c adb_err.h: $(srcdir)/adb_err.et
+
+SRCS= \
+	$(srcdir)/kdb5.c \
+	$(srcdir)/encrypt_key.c \
+	$(srcdir)/decrypt_key.c \
+	$(srcdir)/kdb_default.c \
+	$(srcdir)/kdb_cpw.c \
+	adb_err.c \
+	$(srcdir)/err_handle.c \
+	$(srcdir)/keytab.c
+
+STOBJLISTS=OBJS.ST
+STLIBOBJS= \
+	kdb5.o \
+	encrypt_key.o \
+	decrypt_key.o \
+	kdb_default.o \
+	kdb_cpw.o \
+	adb_err.o \
+	err_handle.o \
+	keytab.o
+
+all-unix:: all-liblinks
+install-unix:: install-libs
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+kdb5.so kdb5.po $(OUTPRE)kdb5.$(OBJEXT): kdb5.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h kdb5.h err_handle.h adb_err.h
+encrypt_key.so encrypt_key.po $(OUTPRE)encrypt_key.$(OBJEXT): \
+  encrypt_key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+decrypt_key.so decrypt_key.po $(OUTPRE)decrypt_key.$(OBJEXT): \
+  decrypt_key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+kdb_default.so kdb_default.po $(OUTPRE)kdb_default.$(OBJEXT): \
+  kdb_default.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+kdb_cpw.so kdb_cpw.po $(OUTPRE)kdb_cpw.$(OBJEXT): kdb_cpw.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+adb_err.so adb_err.po $(OUTPRE)adb_err.$(OBJEXT): adb_err.c \
+  $(COM_ERR_DEPS)
+err_handle.so err_handle.po $(OUTPRE)err_handle.$(OBJEXT): \
+  err_handle.c err_handle.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h
+keytab.so keytab.po $(OUTPRE)keytab.$(OBJEXT): keytab.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/krb5/kdb_kt.h
diff --git a/mechglue/src/lib/kdb/adb_err.et b/mechglue/src/lib/kdb/adb_err.et
new file mode 100644
index 000000000..394802571
--- /dev/null
+++ b/mechglue/src/lib/kdb/adb_err.et
@@ -0,0 +1,16 @@
+error_table adb
+error_code OSA_ADB_NOERR,		"No Error"
+error_code OSA_ADB_DUP,			"Principal or policy already exists"
+error_code OSA_ADB_NOENT,		"Principal or policy does not exist"
+error_code OSA_ADB_DBINIT,		"Database not initialized"
+error_code OSA_ADB_BAD_POLICY,		"Invalid policy name"
+error_code OSA_ADB_BAD_PRINC,		"Invalid principal name"
+error_code OSA_ADB_BAD_DB,		"Database inconsistency detected"
+error_code OSA_ADB_XDR_FAILURE,		"XDR encoding error"
+error_code OSA_ADB_FAILURE,		"Failure!"
+error_code OSA_ADB_BADLOCKMODE,		"Bad lock mode"
+error_code OSA_ADB_CANTLOCK_DB,		"Cannot lock database"
+error_code OSA_ADB_NOTLOCKED,		"Database not locked"
+error_code OSA_ADB_NOLOCKFILE,		"KADM5 administration database lock file missing"
+error_code OSA_ADB_NOEXCL_PERM,		"Insufficient permission to lock file"
+end
diff --git a/mechglue/src/lib/kdb/configure.in b/mechglue/src/lib/kdb/configure.in
new file mode 100644
index 000000000..7d6a1ed47
--- /dev/null
+++ b/mechglue/src/lib/kdb/configure.in
@@ -0,0 +1,15 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+AC_CHECK_HEADERS(unistd.h)
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+
+AC_CHECK_HEADERS(pthread.h)
+AC_CHECK_FUNCS(srand48 srand srandom umask)
+
+KRB5_RUN_FLAGS
+dnl The following is for check...
+KRB5_BUILD_PROGRAM
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/lib/kdb/decrypt_key.c b/mechglue/src/lib/kdb/decrypt_key.c
new file mode 100644
index 000000000..53d02ffb7
--- /dev/null
+++ b/mechglue/src/lib/kdb/decrypt_key.c
@@ -0,0 +1,138 @@
+/*
+ * lib/kdb/decrypt_key.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_kdb_encrypt_key(), krb5_kdb_decrypt_key functions
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+/*
+ * Decrypt a key from storage in the database.  "eblock" is used
+ * to decrypt the key in "in" into "out"; the storage pointed to by "out"
+ * is allocated before use.
+ */
+
+krb5_error_code
+krb5_dbekd_decrypt_key_data( krb5_context 	  context,
+			     const krb5_keyblock	* mkey,
+			     const krb5_key_data	* key_data,
+			     krb5_keyblock 	* dbkey,
+			     krb5_keysalt 	* keysalt)
+{
+    krb5_error_code 	  retval = 0;
+    krb5_int16		  tmplen;
+    krb5_octet		* ptr;
+    krb5_enc_data	  cipher;
+    krb5_data		  plain;
+
+    ptr = key_data->key_data_contents[0];
+
+    if (ptr) {
+	krb5_kdb_decode_int16(ptr, tmplen);
+	ptr += 2;
+
+	cipher.enctype = ENCTYPE_UNKNOWN;
+	cipher.ciphertext.length = key_data->key_data_length[0]-2;
+	cipher.ciphertext.data = ptr;
+	plain.length = key_data->key_data_length[0]-2;
+	if ((plain.data = (krb5_octet *) malloc(plain.length)) == NULL)
+	    return(ENOMEM);
+
+	if ((retval = krb5_c_decrypt(context, mkey, 0 /* XXX */, 0,
+				     &cipher, &plain))) {
+	    krb5_xfree(plain.data);
+	    return retval;
+	}
+
+	/* tmplen is the true length of the key.  plain.data is the
+	   plaintext data length, but it may be padded, since the
+	   old-style etypes didn't store the real length.  I can check
+	   to make sure that there are enough bytes, but I can't do
+	   any better than that. */
+
+	if (tmplen > plain.length) {
+	    krb5_xfree(plain.data);
+	    return(KRB5_CRYPTO_INTERNAL);
+	}
+
+	dbkey->magic = KV5M_KEYBLOCK;
+	dbkey->enctype = key_data->key_data_type[0];
+	dbkey->length = tmplen;
+	dbkey->contents = plain.data;
+    }
+
+    /* Decode salt data */
+    if (keysalt) {
+	if (key_data->key_data_ver == 2) {
+	    keysalt->type = key_data->key_data_type[1];
+	    if ((keysalt->data.length = key_data->key_data_length[1])) {
+		if (!(keysalt->data.data=(char *)malloc(keysalt->data.length))){
+		    if (key_data->key_data_contents[0]) {
+			krb5_xfree(dbkey->contents);
+			dbkey->contents = 0;
+			dbkey->length = 0;
+		    }
+		    return ENOMEM;
+		}
+		memcpy(keysalt->data.data, key_data->key_data_contents[1],
+		       (size_t) keysalt->data.length);
+	    } else
+		keysalt->data.data = (char *) NULL;
+	} else {
+	    keysalt->type = KRB5_KDB_SALTTYPE_NORMAL;
+	    keysalt->data.data = (char *) NULL;
+	    keysalt->data.length = 0;
+	}
+    }
+
+    return retval;
+}
diff --git a/mechglue/src/lib/kdb/encrypt_key.c b/mechglue/src/lib/kdb/encrypt_key.c
new file mode 100644
index 000000000..13686a4ed
--- /dev/null
+++ b/mechglue/src/lib/kdb/encrypt_key.c
@@ -0,0 +1,135 @@
+/*
+ * lib/kdb/encrypt_key.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_kdb_encrypt_key(), krb5_kdb_decrypt_key functions
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+/*
+ * Encrypt a key for storage in the database.  "eblock" is used
+ * to encrypt the key in "in" into "out"; the storage pointed to by "out"
+ * is allocated before use.
+ */
+
+krb5_error_code
+krb5_dbekd_encrypt_key_data( krb5_context 		  context,
+			     const krb5_keyblock	* mkey,
+			     const krb5_keyblock 	* dbkey,
+			     const krb5_keysalt		* keysalt,
+			     int			  keyver,
+			     krb5_key_data	        * key_data)
+{
+    krb5_error_code 		  retval;
+    krb5_octet			* ptr;
+    size_t			  len;
+    int				  i;
+    krb5_data			  plain;
+    krb5_enc_data		  cipher;
+
+    for (i = 0; i < key_data->key_data_ver; i++)
+	if (key_data->key_data_contents[i])
+	    krb5_xfree(key_data->key_data_contents[i]);
+
+    key_data->key_data_ver = 1;
+    key_data->key_data_kvno = keyver;
+
+    /* 
+     * The First element of the type/length/contents 
+     * fields is the key type/length/contents
+     */
+    if ((retval = krb5_c_encrypt_length(context, mkey->enctype, dbkey->length,
+					&len)))
+	return(retval);
+
+    if ((ptr = (krb5_octet *) malloc(2 + len)) == NULL)
+	return(ENOMEM);
+
+    key_data->key_data_type[0] = dbkey->enctype;
+    key_data->key_data_length[0] = 2 + len;
+    key_data->key_data_contents[0] = ptr;
+
+    krb5_kdb_encode_int16(dbkey->length, ptr);
+    ptr += 2;
+
+    plain.length = dbkey->length;
+    plain.data = dbkey->contents;
+
+    cipher.ciphertext.length = len;
+    cipher.ciphertext.data = ptr;
+
+    if ((retval = krb5_c_encrypt(context, mkey, /* XXX */ 0, 0,
+				 &plain, &cipher))) {
+	krb5_xfree(key_data->key_data_contents[0]);
+	return retval;
+    }
+
+    /* After key comes the salt in necessary */
+    if (keysalt) {
+	if (keysalt->type > 0) {
+	    key_data->key_data_ver++;
+	    key_data->key_data_type[1] = keysalt->type;
+	    if ((key_data->key_data_length[1] = keysalt->data.length) != 0) {
+		key_data->key_data_contents[1] =
+		    (krb5_octet *)malloc(keysalt->data.length);
+		if (key_data->key_data_contents[1] == NULL) {
+		    krb5_xfree(key_data->key_data_contents[0]);
+		    return ENOMEM;
+		}
+		memcpy(key_data->key_data_contents[1], keysalt->data.data,
+		       (size_t) keysalt->data.length);
+	    }
+	}
+    }
+
+    return retval;
+}
diff --git a/mechglue/src/lib/kdb/err_handle.c b/mechglue/src/lib/kdb/err_handle.c
new file mode 100644
index 000000000..bfd3c752c
--- /dev/null
+++ b/mechglue/src/lib/kdb/err_handle.c
@@ -0,0 +1,209 @@
+/**********************************************************************
+*
+*	C %name:		err_handle.c %
+*	Instance:		idc_sec_1
+*	Description:	
+*	%created_by:	spradeep %
+*	%date_created:	Thu Apr  7 14:05:00 2005 %
+*
+**********************************************************************/
+#ifndef lint
+static char *_csrc =
+    "@(#) %filespec: err_handle.c~1 %  (%full_filespec: err_handle.c~1:csrc:idc_sec#1 %)";
+#endif
+
+/* This file should be ideally be in util/et.  But, for now thread
+   safety requirement stops me from putting there.  if I do, then all
+   the applications have to link to pthread.  */
+
+#if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+#include "err_handle.h"
+#include <assert.h>
+
+#ifdef NOVELL
+krb5_errcode_2_string_func old_error_2_string = NULL;
+#endif
+
+typedef struct
+{
+    char    krb5_err_str[KRB5_MAX_ERR_STR + 1];
+    long    err_code;
+    krb5_err_subsystem subsystem;
+    krb5_context kcontext;
+} krb5_err_struct_t;
+
+#if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H)
+static void
+tsd_key_destructor(void *data)
+{
+    free(data);
+}
+
+static void
+init_err_handling(void)
+{
+    assert(!k5_key_register(K5_KEY_KDB_ERR_HANDLER, tsd_key_destructor));
+#ifdef NOVELL
+    old_error_2_string = error_message;
+    error_message = krb5_get_err_string;
+#endif
+}
+
+static pthread_once_t krb5_key_create = PTHREAD_ONCE_INIT;
+
+krb5_error_code
+krb5_set_err(krb5_context kcontext, krb5_err_subsystem subsystem,
+	     long err_code, char *str)
+{
+    int     ret;
+    krb5_err_struct_t *err_struct;
+    pthread_once(&krb5_key_create, init_err_handling);
+
+    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KDB_ERR_HANDLER);
+    if (err_struct == NULL) {
+	err_struct = calloc(sizeof(krb5_err_struct_t), 1);
+	if (err_struct == NULL)
+	    return ENOMEM;
+
+	if ((ret = k5_setspecific(K5_KEY_KDB_ERR_HANDLER, err_struct))) {
+	    free(err_struct);
+	    return ret;
+	}
+    }
+
+    err_struct->subsystem = subsystem;
+    err_struct->err_code = err_code;
+    err_struct->kcontext = kcontext;
+    if (err_struct->subsystem == krb5_err_have_str) {
+	strncpy(err_struct->krb5_err_str, str,
+		sizeof(err_struct->krb5_err_str));
+	err_struct->krb5_err_str[KRB5_MAX_ERR_STR] = '\0';
+    }
+
+    return 0;
+}
+
+const char *KRB5_CALLCONV
+krb5_get_err_string(long err_code)
+{
+    krb5_err_struct_t *err_struct;
+    pthread_once(&krb5_key_create, init_err_handling);
+
+    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KDB_ERR_HANDLER);
+    if (err_struct && (err_struct->subsystem == krb5_err_have_str)
+	&& (err_code == err_struct->err_code)) {
+	/* Checking error code is for safety.
+	   In case, the caller ignores a database error and calls
+	   other calls before doing com_err.  Though not perfect,
+	   caller should call krb5_clr_error before this.  */
+	err_struct->subsystem = krb5_err_unknown;
+	return err_struct->krb5_err_str;
+    }
+
+    if (err_struct && (err_struct->subsystem == krb5_err_db)
+	&& (err_code == err_struct->err_code)) {
+	err_struct->subsystem = krb5_err_unknown;
+	return krb5_db_errcode2string(err_struct->kcontext, err_code);
+    }
+
+    /* Error strings are not generated here. the remaining two cases
+       are handled by the default error string convertor.  */
+#ifdef NOVELL
+    return old_error_2_string(err_code);
+#else
+    return error_message(err_code);
+#endif
+}
+
+void
+krb5_clr_error()
+{
+    krb5_err_struct_t *err_struct;
+    pthread_once(&krb5_key_create, init_err_handling);
+
+    err_struct = (krb5_err_struct_t *) k5_getspecific(K5_KEY_KDB_ERR_HANDLER);
+    if (err_struct)
+	err_struct->subsystem = krb5_err_unknown;
+}
+
+#else
+krb5_err_struct_t krb5_err = { {0}, 0, 0, 0 };
+krb5_boolean krb5_init_once = TRUE;
+
+static void
+init_err_handling(void)
+{
+    if (krb5_init_once) {
+#ifdef NOVELL
+	old_error_2_string = error_message;
+	error_message = krb5_get_err_string;
+#endif
+	krb5_init_once = FALSE;
+    }
+}
+
+krb5_error_code
+krb5_set_err(krb5_context kcontext, krb5_err_subsystem subsystem,
+	     long err_code, char *str)
+{
+    krb5_err_struct_t *err_struct = &krb5_err;
+
+    init_err_handling();	/* takes care for multiple inits */
+
+    err_struct->subsystem = subsystem;
+    err_struct->err_code = err_code;
+    err_struct->kcontext = kcontext;
+    if (err_struct->subsystem == krb5_err_have_str) {
+	strncpy(err_struct->krb5_err_str, str,
+		sizeof(err_struct->krb5_err_str));
+	err_struct->krb5_err_str[KRB5_MAX_ERR_STR] = '\0';
+    }
+
+    return 0;
+}
+
+const char *KRB5_CALLCONV
+krb5_get_err_string(long err_code)
+{
+    krb5_err_struct_t *err_struct = &krb5_err;
+
+    init_err_handling();	/* takes care for multiple inits */
+
+    if ((err_struct->subsystem == krb5_err_have_str)
+	&& (err_code == err_struct->err_code)) {
+	/* checking error code is for safety.
+	   In case, the caller ignores a database error and calls
+	   other calls before doing com_err.  Though not perfect,
+	   caller should call krb5_clr_error before this.  */
+	err_struct->subsystem = krb5_err_unknown;
+	return err_struct->krb5_err_str;
+    }
+
+    if ((err_struct->subsystem == krb5_err_db)
+	&& (err_code == err_struct->err_code)) {
+	err_struct->subsystem = krb5_err_unknown;
+	return krb5_db_errcode2string(err_struct->kcontext, err_code);
+    }
+
+    /* It is not generated here. the remaining two cases are handled
+       by the default error string convertor.  */
+#ifdef NOVELL
+    return old_error_2_string(err_code);
+#else
+    return error_message(err_code);
+#endif
+}
+
+void
+krb5_clr_error()
+{
+    krb5_err_struct_t *err_struct = &krb5_err;
+
+    init_err_handling();	/* takes care for multiple inits */
+
+    err_struct->subsystem = krb5_err_unknown;
+}
+
+#endif
diff --git a/mechglue/src/lib/kdb/err_handle.h b/mechglue/src/lib/kdb/err_handle.h
new file mode 100644
index 000000000..ba1e32028
--- /dev/null
+++ b/mechglue/src/lib/kdb/err_handle.h
@@ -0,0 +1,37 @@
+/**********************************************************************
+*
+*	C Header:		err_handle.h
+*	Instance:		idc_sec_1
+*	Description:	
+*	%created_by:	spradeep %
+*	%date_created:	Thu Apr  7 14:05:33 2005 %
+*
+**********************************************************************/
+#ifndef _idc_sec_1_err_handle_h_H
+#define _idc_sec_1_err_handle_h_H
+#include <k5-int.h>
+
+/* Everything else goes here */
+
+#define KRB5_MAX_ERR_STR 1024
+typedef enum krb5_err_subsystem {
+    krb5_err_unknown = 0, /* no error or unknown system. Has to be probed */
+    krb5_err_system,	/* error in system call */
+    krb5_err_krblib,	/* error in kerberos library call, should lookup in the error table */
+    krb5_err_have_str,	/* error message is available in the string */
+    krb5_err_db		/* error is a database error, should be handled by calling DB */
+} krb5_err_subsystem;
+
+typedef krb5_error_code(*krb5_set_err_func_t) (krb5_context,
+					       krb5_err_subsystem, long,
+					       char *);
+
+krb5_error_code krb5_set_err(krb5_context kcontext,
+			     krb5_err_subsystem subsystem, long err_code,
+			     char *str);
+
+const char *KRB5_CALLCONV krb5_get_err_string(long err_code);
+
+void    krb5_clr_error(void);
+
+#endif
diff --git a/mechglue/src/lib/kdb/kdb5.c b/mechglue/src/lib/kdb/kdb5.c
new file mode 100644
index 000000000..91f4f8ee3
--- /dev/null
+++ b/mechglue/src/lib/kdb/kdb5.c
@@ -0,0 +1,1960 @@
+/* 
+ * Include files
+ */
+
+#if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <k5-int.h>
+#include <osconf.h>
+#include "kdb5.h"
+#include <assert.h>
+
+/* Currently DB2 policy related errors are exported from DAL.  But
+   other databases should set_err function to return string.  */
+#include "adb_err.h"
+
+/*
+ * Type definitions
+ */
+#define KRB5_TL_DB_ARGS                 0x7fff
+
+/*
+ * internal static variable
+ */
+
+#if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H)
+/* static pthread_once_t db_inited = PTHREAD_ONCE_INIT; */
+static pthread_mutex_t db_lock = PTHREAD_MUTEX_INITIALIZER;
+#else
+/* static int db_inited = 0; */
+#endif
+
+#ifdef _KDB5_STATIC_LINK
+#undef _KDB5_DYNAMIC_LINK
+#else
+#undef _KDB5_DYNAMIC_LINK
+/* to avoid redefinition problem */
+#define _KDB5_DYNAMIC_LINK
+#endif
+
+static db_library lib_list;
+
+/*
+ * Helper Functions
+ */
+#if defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H)
+
+/* 
+ * KNOWN ISSUES with locking: This code does not handle a scenario
+ * where a library is thread-safe for different DB contexts, but not
+ * with the same context. It locks the complete DB library. If this is
+ * not the scenario, then lock has to be moved from db_library to
+ * kdb5_dal_handle. For now doing a pessimistic locking.
+ *
+ * If any thread does a DB lock, all the other threads are barred from
+ * accessing DB using this context (infact library because of the
+ * previous defect).  This is with the assumption that, DB's lock code
+ * will take care of excluding other processes/machines from using the
+ * DB. But there could be a scenario where access by some other thread
+ * using the same context might corrupt the database.
+ */
+
+static int
+kdb_lock_list()
+{
+    return pthread_mutex_lock(&db_lock);
+}
+
+static int
+kdb_unlock_list()
+{
+    return pthread_mutex_unlock(&db_lock);
+}
+
+static int
+kdb_init_lib_lock(db_library lib)
+{
+    krb5_error_code retval;
+    if ((retval = pthread_mutex_init(&lib->lib_lock, NULL))) {
+	return retval;
+    }
+
+    lib->lock_holder = pthread_self();
+    lib->excl = 0;
+    lib->recursive_cnt = 0;
+
+    return pthread_cond_init(&lib->unlocked, NULL);
+}
+
+static int
+kdb_destroy_lib_lock(db_library lib)
+{
+    krb5_error_code retval;
+    if ((retval = pthread_mutex_destroy(&lib->lib_lock))) {
+	return retval;
+    }
+
+    return pthread_cond_destroy(&lib->unlocked);
+}
+
+static int
+kdb_lock_lib_lock(db_library lib, krb5_boolean exclusive)
+{
+    /* Since, handle locked by one thread should not allow another
+       thread to continue.  */
+    krb5_error_code retval = 0;
+    pthread_t myid = pthread_self();
+
+    if ((retval = pthread_mutex_lock(&lib->lib_lock)))
+	return retval;
+
+    while ((exclusive && (lib->excl || lib->recursive_cnt)) ||
+	   (!pthread_equal(lib->lock_holder, myid)
+	    && !lib->vftabl.is_thread_safe && lib->recursive_cnt)) {
+	/* Exclusive lock held or some one using lock when exclusive
+	   is requested or library not-re-entrant.  */
+	if ((retval = pthread_cond_wait(&lib->unlocked, &lib->lib_lock)))
+	    return retval;
+    }
+
+    /* exclusive lock and recursive_cnt allow a thread to lock even it
+       already holds a lock */
+    if (exclusive)
+	lib->excl++;
+
+    lib->recursive_cnt++;
+
+    lib->lock_holder = myid;
+
+    return pthread_mutex_unlock(&lib->lib_lock);
+}
+
+static int
+kdb_unlock_lib_lock(db_library lib, krb5_boolean exclusive)
+{
+    krb5_error_code retval = 0;
+
+    if ((retval = pthread_mutex_lock(&lib->lib_lock)))
+	return retval;
+
+    lib->recursive_cnt--;
+    if (exclusive)
+	lib->excl--;
+
+    if ((retval = pthread_cond_broadcast(&lib->unlocked)))
+	return retval;
+
+    return pthread_mutex_unlock(&lib->lib_lock);
+}
+
+#else /* no PTHREAD */
+
+/* program is not using pthread. So, threads wont be there. No need to lock */
+#define kdb_lock_list() 0
+#define kdb_unlock_list() 0
+#define kdb_init_lib_lock(a) 0
+#define kdb_destroy_lib_lock(a) 0
+#define kdb_lock_lib_lock(a, b) 0
+#define kdb_unlock_lib_lock(a, b) 0
+
+#endif /* end of HAVE_PTHREAD_H */
+
+static char *
+kdb_get_conf_section(krb5_context kcontext)
+{
+    krb5_error_code status = 0;
+    char   *result = NULL;
+    char   *value = NULL;
+
+    if (kcontext->default_realm == NULL)
+	return NULL;
+    /* The profile has to have been initialized.  If the profile was
+       not initialized, expect nothing less than a crash.  */
+    status = profile_get_string(kcontext->profile,
+				/* realms */
+				KDB_REALM_SECTION,
+				kcontext->default_realm,
+				/* under the realm name, database_module */
+				KDB_MODULE_POINTER,
+				/* default value is the realm name itself */
+				kcontext->default_realm,
+				&value);
+
+    if (status) {
+	/* some problem */
+	result = strdup(kcontext->default_realm);
+	/* let NULL be handled by the caller */
+    } else {
+	result = strdup(value);
+	/* free profile string */
+	profile_release_string(value);
+    }
+
+    return result;
+}
+
+static char *
+kdb_get_library_name(krb5_context kcontext)
+{
+    krb5_error_code status = 0;
+    char   *result = NULL;
+    char   *value = NULL;
+    char   *lib = NULL;
+
+    status = profile_get_string(kcontext->profile,
+				/* realms */
+				KDB_REALM_SECTION,
+				kcontext->default_realm,
+				/* under the realm name, database_module */
+				KDB_MODULE_POINTER,
+				/* default value is the realm name itself */
+				kcontext->default_realm,
+				&value);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    /* we got the module section. Get the library name from the module */
+    status = profile_get_string(kcontext->profile, KDB_MODULE_SECTION, value,
+				KDB_LIB_POINTER,
+				/* default to db2 */
+				"db2",
+				&lib);
+
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    result = strdup(lib);
+  clean_n_exit:
+    if (value) {
+	/* free profile string */
+	profile_release_string(value);
+    }
+
+    if (lib) {
+	/* free profile string */
+	profile_release_string(lib);
+    }
+    return result;
+}
+
+static void
+kdb_setup_opt_functions(db_library lib)
+{
+    if (lib->vftabl.set_master_key == NULL) {
+	lib->vftabl.set_master_key = kdb_def_set_mkey;
+    }
+
+    if (lib->vftabl.get_master_key == NULL) {
+	lib->vftabl.get_master_key = kdb_def_get_mkey;
+    }
+
+    if (lib->vftabl.fetch_master_key == NULL) {
+	lib->vftabl.fetch_master_key = krb5_db_def_fetch_mkey;
+    }
+
+    if (lib->vftabl.verify_master_key == NULL) {
+	lib->vftabl.verify_master_key = krb5_def_verify_master_key;
+    }
+
+    if (lib->vftabl.dbe_search_enctype == NULL) {
+	lib->vftabl.dbe_search_enctype = krb5_dbe_def_search_enctype;
+    }
+
+    if (lib->vftabl.db_change_pwd == NULL) {
+	lib->vftabl.db_change_pwd = krb5_dbe_def_cpw;
+    }
+
+    if (lib->vftabl.store_master_key == NULL) {
+	lib->vftabl.store_master_key = krb5_def_store_mkey;
+    }
+}
+
+static int kdb_db2_pol_err_loaded = 0;
+#ifdef _KDB5_STATIC_LINK
+#define DEF_SYMBOL(a) extern kdb_vftabl krb5_db_vftabl_ ## a
+#define GET_SYMBOL(a) (krb5_db_vftabl_ ## a)
+static krb5_error_code
+kdb_load_library(krb5_context kcontext, char *lib_name, db_library * lib)
+{
+    krb5_error_code status;
+    void   *vftabl_addr = NULL;
+    char    buf[KRB5_MAX_ERR_STR];
+
+    if (!strcmp("kdb_db2", lib_name) && (kdb_db2_pol_err_loaded == 0)) {
+	initialize_adb_error_table();
+	kdb_db2_pol_err_loaded = 1;
+    }
+
+    *lib = calloc((size_t) 1, sizeof(**lib));
+    if (*lib == NULL) {
+	status = ENOMEM;
+	goto clean_n_exit;
+    }
+
+    status = kdb_init_lib_lock(*lib);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    strcpy((*lib)->name, lib_name);
+
+#if !defined(KDB5_USE_LIB_KDB_DB2) && !defined(KDB5_USE_LIB_TEST)
+#error No database module defined
+#endif
+
+#ifdef KDB5_USE_LIB_KDB_DB2
+    if (strcmp(lib_name, "kdb_db2") == 0) {
+	DEF_SYMBOL(kdb_db2);
+	vftabl_addr = (void *) &GET_SYMBOL(kdb_db2);
+    } else
+#endif
+#ifdef KDB5_USE_LIB_TEST
+    if (strcmp(lib_name, "test") == 0) {
+	DEF_SYMBOL(test);
+	vftabl_addr = (void *) &GET_SYMBOL(test);
+    } else
+#endif
+    {
+	sprintf(buf, "Program not built to support %s database type\n",
+		lib_name);
+	status = -1;
+	krb5_db_set_err(kcontext, krb5_err_have_str, status, buf);
+	goto clean_n_exit;
+    }
+
+    memcpy(&(*lib)->vftabl, vftabl_addr, sizeof(kdb_vftabl));
+
+    kdb_setup_opt_functions(*lib);
+
+    if ((status = (*lib)->vftabl.init_library(krb5_set_err))) {
+	/* ERROR. library not initialized cleanly */
+	sprintf(buf, "%s library initialization failed, error code %ld\n",
+		lib_name, status);
+	status = -1;
+	krb5_db_set_err(kcontext, krb5_err_have_str, status, buf);
+	goto clean_n_exit;
+    }
+
+  clean_n_exit:
+    if (status) {
+	free(*lib), *lib = NULL;
+    }
+    return status;
+}
+
+#else
+
+static char *db_dl_location[] = DEFAULT_KDB_LIB_PATH;
+#define db_dl_n_locations (sizeof(db_dl_location) / sizeof(db_dl_location[0]))
+
+static krb5_error_code
+kdb_load_library(krb5_context kcontext, char *lib_name, db_library * lib)
+{
+    krb5_error_code status = 0;
+    char    dl_name[1024];
+    int     ndx;
+    void   *vftabl_addr;
+    char   *err_str = NULL;
+    /* N.B.: If this is "const" but not "static", the Solaris 10
+       native compiler has trouble building the library because of
+       absolute relocations needed in read-only section ".rodata".
+       When it's static, it goes into ".picdata", which is
+       read-write.  */
+    static const char *const dbpath_names[] = {
+	KDB_MODULE_SECTION, "db_module_dir", NULL,
+    };
+    char **profpath = NULL;
+    char **path = NULL;
+
+    if (!strcmp("db2", lib_name) && (kdb_db2_pol_err_loaded == 0)) {
+	initialize_adb_error_table();
+	kdb_db2_pol_err_loaded = 1;
+    }
+
+    *lib = calloc((size_t) 1, sizeof(**lib));
+    if (*lib == NULL) {
+	status = ENOMEM;
+	goto clean_n_exit;
+    }
+
+    status = kdb_init_lib_lock(*lib);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    strcpy((*lib)->name, lib_name);
+
+    /* Fetch the list of directories specified in the config
+       file(s) first.  */
+    status = profile_get_values(kcontext->profile, dbpath_names, &profpath);
+    if (status != 0 && status != PROF_NO_RELATION)
+	goto clean_n_exit;
+    ndx = 0;
+    if (profpath)
+	while (profpath[ndx] != NULL)
+	    ndx++;
+
+    path = calloc(ndx + db_dl_n_locations, sizeof (char *));
+    if (path == NULL) {
+	status = errno;
+	goto clean_n_exit;
+    }
+    if (ndx)
+	memcpy(path, profpath, ndx * sizeof(profpath[0]));
+    memcpy(path + ndx, db_dl_location, db_dl_n_locations * sizeof(char *));
+    status = 0;
+
+    for (ndx = 0; path[ndx]; ndx++) {
+	sprintf(dl_name, "%s/%s.so", path[ndx], lib_name);
+	(*lib)->dl_handle = dlopen(dl_name, RTLD_NOW);
+	if ((*lib)->dl_handle) {
+	    /* found the module */
+	    sprintf(dl_name, "krb5_db_vftabl_%s", lib_name);
+
+	    dlerror();
+	    vftabl_addr = dlsym((*lib)->dl_handle, dl_name);
+	    if (vftabl_addr) {
+		memcpy(&(*lib)->vftabl, vftabl_addr, sizeof(kdb_vftabl));
+
+		kdb_setup_opt_functions(*lib);
+
+		if ((status = (*lib)->vftabl.init_library(krb5_set_err))) {
+		    /* ERROR. library not initialized cleanly */
+		    goto clean_n_exit;
+
+		}
+	    } else {
+		status = -1;
+		krb5_set_err(kcontext, krb5_err_have_str, status, dlerror());
+		goto clean_n_exit;
+	    }
+	    break;
+	} else {
+	    /* set the error. Later if we find everything fine.. we will reset this */
+	    err_str = dlerror();
+/* 	    fprintf(stderr, "Error loading library %s\n", t); */
+	}
+    }
+
+    if (!(*lib)->dl_handle) {
+	/* library not found in the given list. Error str is already set */
+	status = -1;
+	krb5_set_err(kcontext, krb5_err_have_str, status, err_str);
+	goto clean_n_exit;
+    }
+
+  clean_n_exit:
+    /* Both of these DTRT with NULL.  */
+    profile_free_list(profpath);
+    free(path);
+    if (status) {
+	if (*lib) {
+	    kdb_destroy_lib_lock(*lib);
+	    if ((*lib)->dl_handle) {
+		dlclose((*lib)->dl_handle);
+	    }
+	    free(*lib);
+	    *lib = NULL;
+	}
+    }
+    return status;
+}
+
+#endif /* end of _KDB5_STATIC_LINK */
+
+static krb5_error_code
+kdb_find_library(krb5_context kcontext, char *lib_name, db_library * lib)
+{
+    /* lock here so that no two threads try to do the same at the same time */
+    krb5_error_code status = 0;
+    int     locked = 0;
+    db_library curr_elt, prev_elt = NULL;
+
+    if ((status = kdb_lock_list()) != 0) {
+	goto clean_n_exit;
+    }
+    locked = 1;
+
+    curr_elt = lib_list;
+    while (curr_elt != NULL) {
+	if (strcmp(lib_name, curr_elt->name) == 0) {
+	    *lib = curr_elt;
+	    goto clean_n_exit;
+	}
+	prev_elt = curr_elt;
+	curr_elt = curr_elt->next;
+    }
+
+    /* module not found. create and add to list */
+    status = kdb_load_library(kcontext, lib_name, lib);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    if (prev_elt) {
+	/* prev_elt points to the last element in the list */
+	prev_elt->next = *lib;
+	(*lib)->prev = prev_elt;
+    } else {
+	lib_list = *lib;
+    }
+
+  clean_n_exit:
+    if (*lib) {
+	(*lib)->reference_cnt++;
+    }
+
+    if (locked) {
+	kdb_unlock_list();
+    }
+
+    return status;
+}
+
+static krb5_error_code
+kdb_free_library(db_library lib)
+{
+    krb5_error_code status = 0;
+    int     locked = 0;
+
+    if ((status = kdb_lock_list()) != 0) {
+	goto clean_n_exit;
+    }
+    locked = 1;
+
+    lib->reference_cnt--;
+
+    if (lib->reference_cnt == 0) {
+	status = lib->vftabl.fini_library();
+	if (status) {
+	    goto clean_n_exit;
+	}
+
+	/* close the library */
+	if (lib->dl_handle) {
+	    dlclose(lib->dl_handle);
+	}
+
+	kdb_destroy_lib_lock(lib);
+
+	if (lib->prev == NULL) {
+	    /* first element in the list */
+	    lib_list = lib->next;
+	} else {
+	    lib->prev->next = lib->next;
+	}
+
+	if (lib->next) {
+	    lib->next->prev = lib->prev;
+	}
+	free(lib);
+    }
+
+  clean_n_exit:
+    if (locked) {
+	kdb_unlock_list();
+    }
+
+    return status;
+}
+
+static krb5_error_code
+kdb_setup_lib_handle(krb5_context kcontext)
+{
+    char   *library = NULL;
+    krb5_error_code status = 0;
+    db_library lib = NULL;
+    kdb5_dal_handle *dal_handle = NULL;
+
+    dal_handle = calloc((size_t) 1, sizeof(kdb5_dal_handle));
+    if (dal_handle == NULL) {
+	status = ENOMEM;
+	goto clean_n_exit;
+    }
+
+    library = kdb_get_library_name(kcontext);
+    if (library == NULL) {
+	status = -1;
+	goto clean_n_exit;
+    }
+
+    status = kdb_find_library(kcontext, library, &lib);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    dal_handle->lib_handle = lib;
+    kcontext->db_context = (void *) dal_handle;
+
+  clean_n_exit:
+    free(library);
+
+    if (status) {
+	free(dal_handle);
+	if (lib) {
+	    kdb_free_library(lib);
+	}
+    }
+
+    return status;
+}
+
+static krb5_error_code
+kdb_free_lib_handle(krb5_context kcontext)
+{
+    krb5_error_code status = 0;
+
+    status =
+	kdb_free_library(((kdb5_dal_handle *) kcontext->db_context)->
+			 lib_handle);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    free(kcontext->db_context);
+    kcontext->db_context = NULL;
+
+  clean_n_exit:
+    return status;
+}
+
+/*
+ *      External functions... DAL API
+ */
+void
+krb5_db_clr_error()
+{
+    krb5_clr_error();
+}
+
+krb5_error_code
+krb5_db_open(krb5_context kcontext, char **db_args, int mode)
+{
+    krb5_error_code status = 0;
+    char   *section = NULL;
+    kdb5_dal_handle *dal_handle;
+    char    buf[KRB5_MAX_ERR_STR];
+
+    section = kdb_get_conf_section(kcontext);
+    if (section == NULL) {
+	sprintf(buf,
+		"unable to determine configuration section for realm %s\n",
+		kcontext->default_realm ? kcontext->default_realm : "[UNSET]");
+	status = -1;
+	krb5_set_err(kcontext, krb5_err_have_str, status, buf);
+	goto clean_n_exit;
+    }
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.init_module(kcontext, section, db_args,
+						   mode);
+
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    if (section)
+	free(section);
+    return status;
+}
+
+const char *
+krb5_db_errcode2string(krb5_context kcontext, long err_code)
+{
+    const char *err_str = NULL;
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    err_str =
+	dal_handle->lib_handle->vftabl.errcode_2_string(kcontext, err_code);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return err_str;
+}
+
+krb5_error_code
+krb5_db_inited(krb5_context kcontext)
+{
+    return !(kcontext && kcontext->db_context &&
+	     ((kdb5_dal_handle *) kcontext->db_context)->db_context);
+}
+
+krb5_error_code
+krb5_db_create(krb5_context kcontext, char **db_args)
+{
+    krb5_error_code status = 0;
+    char   *section = NULL;
+    kdb5_dal_handle *dal_handle;
+    char    buf[KRB5_MAX_ERR_STR];
+
+    section = kdb_get_conf_section(kcontext);
+    if (section == NULL) {
+	sprintf(buf,
+		"unable to determine configuration section for realm %s\n",
+		kcontext->default_realm);
+	status = -1;
+	krb5_set_err(kcontext, krb5_err_have_str, status, buf);
+	goto clean_n_exit;
+    }
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_create(kcontext, section, db_args);
+
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    if (section)
+	free(section);
+    return status;
+}
+
+krb5_error_code
+krb5_db_fini(krb5_context kcontext)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	/* module not loaded. So nothing to be done */
+	goto clean_n_exit;
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.fini_module(kcontext);
+
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = kdb_free_lib_handle(kcontext);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_destroy(krb5_context kcontext, char **db_args)
+{
+    krb5_error_code status = 0;
+    char   *section = NULL;
+    kdb5_dal_handle *dal_handle;
+    char    buf[KRB5_MAX_ERR_STR];
+
+    section = kdb_get_conf_section(kcontext);
+    if (section == NULL) {
+	sprintf(buf,
+		"unable to determine configuration section for realm %s\n",
+		kcontext->default_realm);
+	status = -1;
+	krb5_set_err(kcontext, krb5_err_have_str, status, buf);
+	goto clean_n_exit;
+    }
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_destroy(kcontext, section, db_args);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    if (section)
+	free(section);
+    return status;
+}
+
+krb5_error_code
+krb5_db_get_age(krb5_context kcontext, char *db_name, time_t * t)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_get_age(kcontext, db_name, t);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_set_option(krb5_context kcontext, int option, void *value)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_set_option(kcontext, option, value);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_lock(krb5_context kcontext, int lock_mode)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    /* acquire an exclusive lock, ensures no other thread uses this context */
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, TRUE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_lock(kcontext, lock_mode);
+
+    /* exclusive lock is still held, so no other thread could use this context */
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_unlock(krb5_context kcontext)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    /* normal lock acquired and exclusive lock released */
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_unlock(kcontext);
+
+    kdb_unlock_lib_lock(dal_handle->lib_handle, TRUE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_get_principal(krb5_context kcontext,
+		      krb5_const_principal search_for,
+		      krb5_db_entry * entries,
+		      int *nentries, krb5_boolean * more)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_get_principal(kcontext, search_for,
+							entries, nentries,
+							more);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_free_principal(krb5_context kcontext, krb5_db_entry * entry, int count)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_free_principal(kcontext, entry,
+							 count);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_put_principal(krb5_context kcontext,
+		      krb5_db_entry * entries, int *nentries)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+    char  **db_args = NULL;
+    krb5_tl_data *prev, *curr, *next;
+    int     db_args_size = 0;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    /* Giving db_args as part of tl data causes, db2 to store the
+       tl_data as such.  To prevent this, tl_data is collated and
+       passed as a sepearte argument. Currently supports only one
+       principal.  but passing it as a seperate argument makes it
+       difficult for kadmin remote to pass arguments to server.  */
+    prev = NULL, curr = entries->tl_data;
+    while (curr) {
+	if (curr->tl_data_type == KRB5_TL_DB_ARGS) {
+	    char  **t;
+	    /* Since this is expected to be NULL terminated string and
+	       this could come from any client, do a check before
+	       passing it to db.  */
+	    if (((char *) curr->tl_data_contents)[curr->tl_data_length - 1] !=
+		'\0') {
+		/* not null terminated. Dangerous input */
+		status = EINVAL;
+		goto clean_n_exit;
+	    }
+
+	    db_args_size++;
+	    t = realloc(db_args, sizeof(char *) * (db_args_size + 1));	/* 1 for NULL */
+	    if (t == NULL) {
+		status = ENOMEM;
+		goto clean_n_exit;
+	    }
+
+	    db_args = t;
+	    db_args[db_args_size - 1] = (char *) curr->tl_data_contents;
+	    db_args[db_args_size] = NULL;
+
+	    next = curr->tl_data_next;
+	    if (prev == NULL) {
+		/* current node is the first in the linked list. remove it */
+		entries->tl_data = curr->tl_data_next;
+	    } else {
+		prev->tl_data_next = curr->tl_data_next;
+	    }
+	    entries->n_tl_data--;
+	    krb5_db_free(kcontext, curr);
+
+	    /* previous does not change */
+	    curr = next;
+	} else {
+	    prev = curr;
+	    curr = curr->tl_data_next;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_put_principal(kcontext, entries,
+							     nentries,
+							     db_args);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    while (db_args_size) {
+	if (db_args[db_args_size - 1])
+	    krb5_db_free(kcontext, db_args[db_args_size - 1]);
+
+	db_args_size--;
+    }
+
+    if (db_args)
+	free(db_args);
+
+    return status;
+}
+
+krb5_error_code
+krb5_db_delete_principal(krb5_context kcontext,
+			 krb5_principal search_for, int *nentries)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_delete_principal(kcontext,
+							   search_for,
+							   nentries);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_iterate(krb5_context kcontext,
+		char *match_entry,
+		int (*func) (krb5_pointer, krb5_db_entry *),
+		krb5_pointer func_arg)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_iterate(kcontext,
+						       match_entry,
+						       func, func_arg);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_supported_realms(krb5_context kcontext, char **realms)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_supported_realms(kcontext, realms);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_free_supported_realms(krb5_context kcontext, char **realms)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_free_supported_realms(kcontext,
+								realms);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_set_master_key_ext(krb5_context kcontext,
+			   char *pwd, krb5_keyblock * key)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.set_master_key(kcontext, pwd, key);
+
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_set_mkey(krb5_context context, krb5_keyblock * key)
+{
+    return krb5_db_set_master_key_ext(context, NULL, key);
+}
+
+krb5_error_code
+krb5_db_get_mkey(krb5_context kcontext, krb5_keyblock ** key)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    /* Lets use temp key and copy it later to avoid memory problems
+       when freed by the caller.  */
+    status = dal_handle->lib_handle->vftabl.get_master_key(kcontext, key);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_store_master_key(krb5_context kcontext,
+			 char *db_arg,
+			 krb5_principal mname,
+			 krb5_keyblock * key, char *master_pwd)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.store_master_key(kcontext,
+							     db_arg,
+							     mname,
+							     key, master_pwd);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+char   *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1;
+char   *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2;
+
+krb5_error_code
+krb5_db_fetch_mkey(krb5_context context,
+		   krb5_principal mname,
+		   krb5_enctype etype,
+		   krb5_boolean fromkeyboard,
+		   krb5_boolean twice,
+		   char *db_args, krb5_data * salt, krb5_keyblock * key)
+{
+    krb5_error_code retval;
+    char    password[BUFSIZ];
+    krb5_data pwd;
+    unsigned int size = sizeof(password);
+    int     kvno;
+    krb5_keyblock tmp_key;
+
+    memset(&tmp_key, 0, sizeof(tmp_key));
+
+    if (fromkeyboard) {
+	krb5_data scratch;
+
+	if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1,
+					 twice ? krb5_mkey_pwd_prompt2 : 0,
+					 password, &size))) {
+	    goto clean_n_exit;
+	}
+
+	pwd.data = password;
+	pwd.length = size;
+	if (!salt) {
+	    retval = krb5_principal2salt(context, mname, &scratch);
+	    if (retval)
+		goto clean_n_exit;
+	}
+	retval =
+	    krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch,
+				 key);
+
+	if (!salt)
+	    krb5_xfree(scratch.data);
+	memset(password, 0, sizeof(password));	/* erase it */
+
+    } else {
+	kdb5_dal_handle *dal_handle;
+
+	if (context->db_context == NULL) {
+	    retval = kdb_setup_lib_handle(context);
+	    if (retval) {
+		goto clean_n_exit;
+	    }
+	}
+
+	dal_handle = (kdb5_dal_handle *) context->db_context;
+	retval = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+	if (retval) {
+	    goto clean_n_exit;
+	}
+
+	tmp_key.enctype = key->enctype;
+	retval = dal_handle->lib_handle->vftabl.fetch_master_key(context,
+								 mname,
+								 &tmp_key,
+								 &kvno,
+								 db_args);
+	kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+	if (retval) {
+	    goto clean_n_exit;
+	}
+
+	key->contents = malloc(tmp_key.length);
+	if (key->contents == NULL) {
+	    retval = ENOMEM;
+	    goto clean_n_exit;
+	}
+
+	key->magic = tmp_key.magic;
+	key->enctype = tmp_key.enctype;
+	key->length = tmp_key.length;
+	memcpy(key->contents, tmp_key.contents, tmp_key.length);
+    }
+
+  clean_n_exit:
+    if (tmp_key.contents) {
+	memset(tmp_key.contents, 0, tmp_key.length);
+	krb5_db_free(context, tmp_key.contents);
+    }
+    return retval;
+}
+
+krb5_error_code
+krb5_db_verify_master_key(krb5_context kcontext,
+			  krb5_principal mprinc, krb5_keyblock * mkey)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.verify_master_key(kcontext,
+							      mprinc, mkey);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+void   *
+krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size)
+{
+    krb5_error_code status;
+    kdb5_dal_handle *dal_handle;
+    void   *new_ptr = NULL;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+
+    new_ptr = dal_handle->lib_handle->vftabl.db_alloc(kcontext, ptr, size);
+
+  clean_n_exit:
+    return new_ptr;
+}
+
+void
+krb5_db_free(krb5_context kcontext, void *ptr)
+{
+    krb5_error_code status;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+
+    dal_handle->lib_handle->vftabl.db_free(kcontext, ptr);
+
+  clean_n_exit:
+    return;
+}
+
+/* has to be modified */
+
+krb5_error_code
+krb5_dbe_find_enctype(krb5_context kcontext,
+		      krb5_db_entry * dbentp,
+		      krb5_int32 ktype,
+		      krb5_int32 stype,
+		      krb5_int32 kvno, krb5_key_data ** kdatap)
+{
+    krb5_int32 start = 0;
+    return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype,
+				   kvno, kdatap);
+}
+
+krb5_error_code
+krb5_dbe_search_enctype(krb5_context kcontext,
+			krb5_db_entry * dbentp,
+			krb5_int32 * start,
+			krb5_int32 ktype,
+			krb5_int32 stype,
+			krb5_int32 kvno, krb5_key_data ** kdatap)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.dbe_search_enctype(kcontext,
+							       dbentp,
+							       start,
+							       ktype,
+							       stype,
+							       kvno, kdatap);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+#define	REALM_SEP_STRING	"@"
+
+krb5_error_code
+krb5_db_setup_mkey_name(krb5_context context,
+			const char *keyname,
+			const char *realm,
+			char **fullname, krb5_principal * principal)
+{
+    krb5_error_code retval;
+    size_t  keylen;
+    size_t  rlen = strlen(realm);
+    char   *fname;
+
+    if (!keyname)
+	keyname = KRB5_KDB_M_NAME;	/* XXX external? */
+
+    keylen = strlen(keyname);
+
+    fname = malloc(keylen + rlen + strlen(REALM_SEP_STRING) + 1);
+    if (!fname)
+	return ENOMEM;
+
+    strcpy(fname, keyname);
+    strcat(fname, REALM_SEP_STRING);
+    strcat(fname, realm);
+
+    if ((retval = krb5_parse_name(context, fname, principal)))
+	return retval;
+    if (fullname)
+	*fullname = fname;
+    else
+	free(fname);
+    return 0;
+}
+
+krb5_error_code
+krb5_dbe_lookup_last_pwd_change(context, entry, stamp)
+    krb5_context context;
+    krb5_db_entry *entry;
+    krb5_timestamp *stamp;
+{
+    krb5_tl_data tl_data;
+    krb5_error_code code;
+    krb5_int32 tmp;
+
+    tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
+
+    if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
+	return (code);
+
+    if (tl_data.tl_data_length != 4) {
+	*stamp = 0;
+	return (0);
+    }
+
+    krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp);
+
+    *stamp = (krb5_timestamp) tmp;
+
+    return (0);
+}
+
+krb5_error_code
+krb5_dbe_lookup_tl_data(context, entry, ret_tl_data)
+    krb5_context context;
+    krb5_db_entry *entry;
+    krb5_tl_data *ret_tl_data;
+{
+    krb5_tl_data *tl_data;
+
+    for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
+	if (tl_data->tl_data_type == ret_tl_data->tl_data_type) {
+	    *ret_tl_data = *tl_data;
+	    return (0);
+	}
+    }
+
+    /* if the requested record isn't found, return zero bytes.
+     * if it ever means something to have a zero-length tl_data,
+     * this code and its callers will have to be changed */
+
+    ret_tl_data->tl_data_length = 0;
+    ret_tl_data->tl_data_contents = NULL;
+    return (0);
+}
+
+krb5_error_code
+krb5_dbe_create_key_data(context, entry)
+    krb5_context context;
+    krb5_db_entry *entry;
+{
+    if ((entry->key_data =
+	 (krb5_key_data *) krb5_db_alloc(context, entry->key_data,
+					 (sizeof(krb5_key_data) *
+					  (entry->n_key_data + 1)))) == NULL)
+	return (ENOMEM);
+
+    memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data));
+    entry->n_key_data++;
+
+    return 0;
+}
+
+krb5_error_code
+krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ)
+    krb5_context context;
+    krb5_db_entry *entry;
+    krb5_timestamp mod_date;
+    krb5_const_principal mod_princ;
+{
+    krb5_tl_data tl_data;
+
+    krb5_error_code retval = 0;
+    krb5_octet *nextloc = 0;
+    char   *unparse_mod_princ = 0;
+    unsigned int unparse_mod_princ_size;
+
+    if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ)))
+	return (retval);
+
+    unparse_mod_princ_size = strlen(unparse_mod_princ) + 1;
+
+    if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4))
+	== NULL) {
+	free(unparse_mod_princ);
+	return (ENOMEM);
+    }
+
+    tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
+    tl_data.tl_data_length = unparse_mod_princ_size + 4;
+    tl_data.tl_data_contents = nextloc;
+
+    /* Mod Date */
+    krb5_kdb_encode_int32(mod_date, nextloc);
+
+    /* Mod Princ */
+    memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size);
+
+    retval = krb5_dbe_update_tl_data(context, entry, &tl_data);
+
+    free(unparse_mod_princ);
+    free(nextloc);
+
+    return (retval);
+}
+
+krb5_error_code
+krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ)
+    krb5_context context;
+    krb5_db_entry *entry;
+    krb5_timestamp *mod_time;
+    krb5_principal *mod_princ;
+{
+    krb5_tl_data tl_data;
+    krb5_error_code code;
+
+    tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
+
+    if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
+	return (code);
+
+    if ((tl_data.tl_data_length < 5) ||
+	(tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0'))
+	return (KRB5_KDB_TRUNCATED_RECORD);
+
+    /* Mod Date */
+    krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time);
+
+    /* Mod Princ */
+    if ((code = krb5_parse_name(context,
+				(const char *) (tl_data.tl_data_contents + 4),
+				mod_princ)))
+	return (code);
+
+    return (0);
+}
+
+krb5_error_code
+krb5_dbe_update_last_pwd_change(context, entry, stamp)
+    krb5_context context;
+    krb5_db_entry *entry;
+    krb5_timestamp stamp;
+{
+    krb5_tl_data tl_data;
+    krb5_octet buf[4];		/* this is the encoded size of an int32 */
+
+    tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
+    tl_data.tl_data_length = sizeof(buf);
+    krb5_kdb_encode_int32((krb5_int32) stamp, buf);
+    tl_data.tl_data_contents = buf;
+
+    return (krb5_dbe_update_tl_data(context, entry, &tl_data));
+}
+
+krb5_error_code
+krb5_dbe_update_tl_data(context, entry, new_tl_data)
+    krb5_context context;
+    krb5_db_entry *entry;
+    krb5_tl_data *new_tl_data;
+{
+    krb5_tl_data *tl_data = NULL;
+    krb5_octet *tmp;
+
+    /* copy the new data first, so we can fail cleanly if malloc()
+     * fails */
+    if ((tmp =
+	 (krb5_octet *) krb5_db_alloc(context, NULL,
+				      new_tl_data->tl_data_length)) == NULL)
+	return (ENOMEM);
+
+    /* Find an existing entry of the specified type and point at
+     * it, or NULL if not found */
+
+    if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) {	/* db_args can be multiple */
+	for (tl_data = entry->tl_data; tl_data;
+	     tl_data = tl_data->tl_data_next)
+	    if (tl_data->tl_data_type == new_tl_data->tl_data_type)
+		break;
+    }
+
+    /* if necessary, chain a new record in the beginning and point at it */
+
+    if (!tl_data) {
+	if ((tl_data =
+	     (krb5_tl_data *) krb5_db_alloc(context, NULL,
+					    sizeof(krb5_tl_data)))
+	    == NULL) {
+	    free(tmp);
+	    return (ENOMEM);
+	}
+	memset(tl_data, 0, sizeof(krb5_tl_data));
+	tl_data->tl_data_next = entry->tl_data;
+	entry->tl_data = tl_data;
+	entry->n_tl_data++;
+    }
+
+    /* fill in the record */
+
+    if (tl_data->tl_data_contents)
+	krb5_db_free(context, tl_data->tl_data_contents);
+
+    tl_data->tl_data_type = new_tl_data->tl_data_type;
+    tl_data->tl_data_length = new_tl_data->tl_data_length;
+    tl_data->tl_data_contents = tmp;
+    memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);
+
+    return (0);
+}
+
+/* change password functions */
+krb5_error_code
+krb5_dbe_cpw(krb5_context kcontext,
+	     krb5_keyblock * master_key,
+	     krb5_key_salt_tuple * ks_tuple,
+	     int ks_tuple_count,
+	     char *passwd,
+	     int new_kvno, krb5_boolean keepold, krb5_db_entry * db_entry)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_change_pwd(kcontext,
+							  master_key,
+							  ks_tuple,
+							  ks_tuple_count,
+							  passwd,
+							  new_kvno,
+							  keepold, db_entry);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+/* policy management functions */
+krb5_error_code
+krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_create_policy(kcontext, policy);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_get_policy(krb5_context kcontext, char *name,
+		   osa_policy_ent_t * policy, int *cnt)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_get_policy(kcontext, name, policy,
+						     cnt);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_put_policy(kcontext, policy);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_iter_policy(krb5_context kcontext, char *match_entry,
+		    osa_adb_iter_policy_func func, void *data)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status =
+	dal_handle->lib_handle->vftabl.db_iter_policy(kcontext, match_entry,
+						      func, data);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db_delete_policy(krb5_context kcontext, char *policy)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    status = dal_handle->lib_handle->vftabl.db_delete_policy(kcontext, policy);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return status;
+}
+
+void
+krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy)
+{
+    krb5_error_code status = 0;
+    kdb5_dal_handle *dal_handle;
+
+    if (kcontext->db_context == NULL) {
+	status = kdb_setup_lib_handle(kcontext);
+	if (status) {
+	    goto clean_n_exit;
+	}
+    }
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
+    if (status) {
+	goto clean_n_exit;
+    }
+
+    dal_handle->lib_handle->vftabl.db_free_policy(kcontext, policy);
+    kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
+
+  clean_n_exit:
+    return;
+}
diff --git a/mechglue/src/lib/kdb/kdb5.h b/mechglue/src/lib/kdb/kdb5.h
new file mode 100644
index 000000000..93b594a52
--- /dev/null
+++ b/mechglue/src/lib/kdb/kdb5.h
@@ -0,0 +1,219 @@
+#ifndef _KRB5_KDB5_H_
+#define _KRB5_KDB5_H_
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <utime.h>
+#include <utime.h>
+#include <k5-int.h>
+#include "err_handle.h"
+
+#define KDB_MAX_DB_NAME 128
+#define KDB_REALM_SECTION  "realms"
+#define KDB_MODULE_POINTER "database_module"
+#define KDB_MODULE_SECTION "db_modules"
+#define KDB_LIB_POINTER    "db_library"
+#define KDB_DATABASE_CONF_FILE  DEFAULT_SECURE_PROFILE_PATH
+#define KDB_DATABASE_ENV_PROF KDC_PROFILE_ENV
+
+#define KRB5_KDB_OPEN_RW                0
+#define KRB5_KDB_OPEN_RO                1
+
+#define KRB5_KDB_OPT_SET_DB_NAME        0
+#define KRB5_KDB_OPT_SET_LOCK_MODE      1
+
+#define KRB5_DB_GET_DB_CONTEXT(kcontext)   ( ((kdb5_dal_handle*) (kcontext)->db_context)->db_context )
+#define KRB5_DB_GET_PROFILE(kcontext)  ( (kcontext)->profile )
+#define KRB5_DB_GET_REALM(kcontext)    ( (kcontext)->default_realm )
+
+#ifndef KRB5_DB_LOCKMODE_SHARED
+#define KRB5_DB_LOCKMODE_SHARED       0x0001
+#endif
+
+#ifndef KRB5_DB_LOCKMODE_EXCLUSIVE
+#define KRB5_DB_LOCKMODE_EXCLUSIVE    0x0002
+#endif
+
+#ifndef KRB5_DB_LOCKMODE_DONTBLOCK
+#define KRB5_DB_LOCKMODE_DONTBLOCK    0x0004
+#endif
+
+#ifndef KRB5_DB_LOCKMODE_PERMANENT
+#define KRB5_DB_LOCKMODE_PERMANENT    0x0008
+#endif
+
+typedef struct _kdb_vftabl{
+    short int maj_ver;
+    short int min_ver;
+
+    short int is_thread_safe;
+
+    krb5_error_code (*init_library)(krb5_set_err_func_t);
+    krb5_error_code (*fini_library)();
+    krb5_error_code (*init_module) ( krb5_context kcontext,
+				     char * conf_section,
+				     char ** db_args,
+				     int mode );
+
+    krb5_error_code (*fini_module) ( krb5_context kcontext );
+
+    krb5_error_code (*db_create) ( krb5_context kcontext,
+				   char * conf_section,
+				   char ** db_args );
+
+    krb5_error_code (*db_destroy) ( krb5_context kcontext,
+				    char *conf_section,
+				    char ** db_args );
+
+    krb5_error_code (*db_get_age) ( krb5_context kcontext, 
+				    char *db_name, 
+				    time_t *age );
+
+    krb5_error_code (*db_set_option) ( krb5_context kcontext,
+				       int option,
+				       void *value );
+
+    krb5_error_code (*db_lock) ( krb5_context kcontext,
+				 int mode );
+
+    krb5_error_code (*db_unlock) ( krb5_context kcontext);
+
+    krb5_error_code (*db_get_principal) ( krb5_context kcontext,
+					  krb5_const_principal search_for,
+					  krb5_db_entry *entries,
+					  int *nentries,
+					  krb5_boolean *more );
+
+    krb5_error_code (*db_free_principal) ( krb5_context kcontext,
+					   krb5_db_entry *entry,
+					   int count );
+
+    krb5_error_code (*db_put_principal) ( krb5_context kcontext,
+					  krb5_db_entry *entries,
+					  int *nentries,
+					  char **db_args);
+
+    krb5_error_code (*db_delete_principal) ( krb5_context kcontext,
+					     krb5_const_principal search_for,
+					     int *nentries );
+
+    krb5_error_code (*db_iterate) ( krb5_context kcontext,
+				    char *match_entry,
+				    int (*func) (krb5_pointer, krb5_db_entry *),
+				    krb5_pointer func_arg );
+
+    krb5_error_code (*db_create_policy) ( krb5_context kcontext,
+					  osa_policy_ent_t policy );
+
+    krb5_error_code (*db_get_policy) ( krb5_context kcontext,
+				       char *name,
+				       osa_policy_ent_t *policy,
+				       int *cnt);
+
+    krb5_error_code (*db_put_policy) ( krb5_context kcontext,
+				       osa_policy_ent_t policy );
+
+    krb5_error_code (*db_iter_policy) ( krb5_context kcontext,
+					char *match_entry,
+					osa_adb_iter_policy_func func,
+					void *data );
+
+
+    krb5_error_code (*db_delete_policy) ( krb5_context kcontext,
+					  char *policy );
+
+    void (*db_free_policy) ( krb5_context kcontext,
+			     osa_policy_ent_t val );
+
+    krb5_error_code (*db_supported_realms) ( krb5_context kcontext,
+					    char **realms );
+
+    krb5_error_code (*db_free_supported_realms) ( krb5_context kcontext,
+						  char **realms );
+
+
+    const char * (*errcode_2_string) ( krb5_context kcontext,
+				       long err_code );
+
+    void * (*db_alloc) (krb5_context kcontext, void *ptr, size_t size);
+    void   (*db_free)  (krb5_context kcontext, void *ptr);
+
+
+
+    /* optional functions */
+    krb5_error_code (*set_master_key)    ( krb5_context kcontext, 
+					   char *pwd, 
+					   krb5_keyblock *key);
+
+    krb5_error_code (*get_master_key)    ( krb5_context kcontext,
+					   krb5_keyblock **key);
+
+
+    krb5_error_code (*setup_master_key_name) ( krb5_context kcontext,
+					       char *keyname,
+					       char *realm, 
+					       char **fullname, 
+					       krb5_principal  *principal);
+
+    krb5_error_code (*store_master_key)  ( krb5_context kcontext, 
+					   char *db_arg, 
+					   krb5_principal mname,
+					   krb5_keyblock *key,
+					   char *master_pwd);
+
+    krb5_error_code (*fetch_master_key)  ( krb5_context kcontext,
+					   krb5_principal mname,
+					   krb5_keyblock *key,
+					   int *kvno,
+					   char *db_args);
+
+    krb5_error_code (*verify_master_key) ( krb5_context kcontext,
+					   krb5_principal mprinc,
+					   krb5_keyblock *mkey );
+
+    krb5_error_code (*dbe_search_enctype) ( krb5_context kcontext, 
+					    krb5_db_entry *dbentp, 
+					    krb5_int32 *start, 
+					    krb5_int32 ktype, 
+					    krb5_int32 stype, 
+					    krb5_int32 kvno, 
+					    krb5_key_data **kdatap);
+    
+
+    krb5_error_code
+    (*db_change_pwd) ( krb5_context	  context,
+		       krb5_keyblock       * master_key,
+		       krb5_key_salt_tuple	* ks_tuple,
+		       int			  ks_tuple_count,
+		       char 		* passwd,
+		       int			  new_kvno,
+		       krb5_boolean	  keepold,
+		       krb5_db_entry	* db_entry);
+
+} kdb_vftabl;
+
+typedef struct _db_library {
+    char name[KDB_MAX_DB_NAME];
+    int reference_cnt;
+#ifdef HAVE_PTHREAD_H
+    pthread_mutex_t lib_lock;
+    pthread_cond_t unlocked; /*  To check whether some one has called db_unlock */
+    int recursive_cnt;               /* this is used as lock to help recursive locking */
+    pthread_t lock_holder;
+    int excl;
+#endif
+    void *dl_handle;
+    kdb_vftabl vftabl;
+    struct _db_library *next, *prev;
+} *db_library;
+
+typedef struct _kdb5_dal_handle
+{
+    void *db_context;               /* helps us to change db_library without affecting modules to some extend */
+    db_library lib_handle;
+} kdb5_dal_handle;
+
+#endif  /* end of _KRB5_KDB5_H_ */
diff --git a/mechglue/src/lib/kdb/kdb_cpw.c b/mechglue/src/lib/kdb/kdb_cpw.c
new file mode 100644
index 000000000..f873a3945
--- /dev/null
+++ b/mechglue/src/lib/kdb/kdb_cpw.c
@@ -0,0 +1,648 @@
+/*
+ * lib/kdb/kdb_cpw.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology. 
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include <errno.h>
+
+static int
+get_key_data_kvno(context, count, data)
+    krb5_context	  context;
+    int			  count;
+    krb5_key_data	* data;
+{
+    int i, kvno;
+    /* Find last key version number */
+    for (kvno = i = 0; i < count; i++) {
+	if (kvno < data[i].key_data_kvno) {
+	    kvno = data[i].key_data_kvno;
+	}
+    }
+    return(kvno);
+}
+
+static void
+cleanup_key_data(context, count, data)
+    krb5_context	  context;
+    int			  count;
+    krb5_key_data	* data;
+{
+    int i, j;
+
+    /* If data is NULL, count is always 0 */
+    if (data == NULL) return;
+
+    for (i = 0; i < count; i++) {
+	for (j = 0; j < data[i].key_data_ver; j++) {
+	    if (data[i].key_data_length[j]) {
+	    	krb5_db_free(context, data[i].key_data_contents[j]);
+	    }
+	}
+    }
+    krb5_db_free(context, data);
+}
+
+static krb5_error_code
+add_key_rnd(context, master_key, ks_tuple, ks_tuple_count, db_entry, kvno)
+    krb5_context	  context;
+    krb5_keyblock       * master_key;
+    krb5_key_salt_tuple	* ks_tuple;
+    int			  ks_tuple_count;
+    krb5_db_entry	* db_entry;
+    int			  kvno;
+{
+    krb5_principal	  krbtgt_princ;
+    krb5_keyblock	  key;
+    krb5_db_entry	  krbtgt_entry;
+    krb5_boolean	  more;
+    int			  max_kvno, one, i, j, k;
+    krb5_error_code	  retval;
+    krb5_key_data         tmp_key_data;
+    krb5_key_data        *tptr;
+
+    memset( &tmp_key_data, 0, sizeof(tmp_key_data));
+
+
+    retval = krb5_build_principal_ext(context, &krbtgt_princ,
+				      db_entry->princ->realm.length,
+				      db_entry->princ->realm.data,
+				      KRB5_TGS_NAME_SIZE,
+				      KRB5_TGS_NAME,
+				      db_entry->princ->realm.length,
+				      db_entry->princ->realm.data,
+				      0);
+    if (retval)
+	return retval;
+
+    /* Get tgt from database */
+    retval = krb5_db_get_principal(context, krbtgt_princ, &krbtgt_entry,
+				   &one, &more);
+    krb5_free_principal(context, krbtgt_princ); /* don't need it anymore */
+    if (retval)
+	return(retval);
+    if ((one > 1) || (more)) {
+	krb5_db_free_principal(context, &krbtgt_entry, one);
+	return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
+    }
+    if (!one) 
+	return KRB5_KDB_NOENTRY;
+
+    /* Get max kvno */
+    for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
+	 if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
+	     max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
+	}
+    }
+
+    for (i = 0; i < ks_tuple_count; i++) {
+	krb5_boolean similar;
+
+	similar = 0;
+
+	/*
+	 * We could use krb5_keysalt_iterate to replace this loop, or use
+	 * krb5_keysalt_is_present for the loop below, but we want to avoid
+	 * circular library dependencies.
+	 */
+	for (j = 0; j < i; j++) {
+	    if ((retval = krb5_c_enctype_compare(context,
+						 ks_tuple[i].ks_enctype,
+						 ks_tuple[j].ks_enctype,
+						 &similar)))
+		return(retval);
+
+	    if (similar)
+		break;
+	}
+
+	if (similar)
+	    continue;
+
+        if ((retval = krb5_dbe_create_key_data(context, db_entry))) 
+	    goto add_key_rnd_err;
+
+	/* there used to be code here to extract the old key, and derive
+	   a new key from it.  Now that there's a unified prng, that isn't
+	   necessary. */
+
+	/* make new key */
+	if ((retval = krb5_c_make_random_key(context, ks_tuple[i].ks_enctype,
+					     &key)))
+	    goto add_key_rnd_err;
+
+
+	/* db library will free this. Since, its a so, it could actually be using different memory management
+	   function. So, its better if the memory is allocated by the db's malloc. So, a temporary memory is used
+	   here which will later be copied to the db_entry */
+    	retval = krb5_dbekd_encrypt_key_data(context, master_key, 
+					     &key, NULL, kvno, 
+					     &tmp_key_data); 
+
+	krb5_free_keyblock_contents(context, &key);
+	if( retval )
+	    goto add_key_rnd_err;
+
+	tptr = &db_entry->key_data[db_entry->n_key_data-1];
+
+	tptr->key_data_ver = tmp_key_data.key_data_ver;
+	tptr->key_data_kvno = tmp_key_data.key_data_kvno;
+
+	for( k = 0; k < tmp_key_data.key_data_ver; k++ )
+	{
+	    tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
+	    tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
+	    if( tmp_key_data.key_data_contents[k] )
+	    {
+		tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
+		if( tptr->key_data_contents[k] == NULL )
+		{
+		    cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+		    db_entry->key_data = NULL;
+		    db_entry->n_key_data = 0;
+		    retval = ENOMEM;
+		    goto add_key_rnd_err;
+		}
+		memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
+
+		memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
+		free( tmp_key_data.key_data_contents[k] );
+		tmp_key_data.key_data_contents[k] = NULL;
+	    }
+	}
+
+    }
+
+add_key_rnd_err:
+    krb5_db_free_principal(context, &krbtgt_entry, one);
+
+    for( i = 0; i < tmp_key_data.key_data_ver; i++ )
+    {
+	if( tmp_key_data.key_data_contents[i] )
+	{
+	    memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
+	    free( tmp_key_data.key_data_contents[i] );
+	}
+    }
+    return(retval);
+}
+
+/*
+ * Change random key for a krb5_db_entry 
+ * Assumes the max kvno
+ *
+ * As a side effect all old keys are nuked if keepold is false.
+ */
+krb5_error_code
+krb5_dbe_crk(context, master_key, ks_tuple, ks_tuple_count, keepold, db_entry)
+    krb5_context	  context;
+    krb5_keyblock       * master_key;
+    krb5_key_salt_tuple	* ks_tuple;
+    int			  ks_tuple_count;
+    krb5_boolean	  keepold;
+    krb5_db_entry	* db_entry;
+{
+    int 		  key_data_count;
+    int			  n_new_key_data;
+    krb5_key_data 	* key_data;
+    krb5_error_code	  retval;
+    int			  kvno;
+    int			  i;
+
+    /* First save the old keydata */
+    kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
+    key_data_count = db_entry->n_key_data;
+    key_data = db_entry->key_data;
+    db_entry->key_data = NULL;
+    db_entry->n_key_data = 0;
+
+    /* increment the kvno */
+    kvno++;
+
+    retval = add_key_rnd(context, master_key, ks_tuple,
+			 ks_tuple_count, db_entry, kvno);
+    if (retval) {
+	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+	db_entry->n_key_data = key_data_count;
+	db_entry->key_data = key_data;
+    } else if (keepold) {
+	n_new_key_data = db_entry->n_key_data;
+	for (i = 0; i < key_data_count; i++) {
+	    retval = krb5_dbe_create_key_data(context, db_entry);
+	    if (retval) {
+		cleanup_key_data(context, db_entry->n_key_data,
+				 db_entry->key_data);
+		break;
+	    }
+	    db_entry->key_data[i+n_new_key_data] = key_data[i];
+	    memset(&key_data[i], 0, sizeof(krb5_key_data));
+	}
+	krb5_db_free(context, key_data); /* we moved the cotents to new memory. But, the original block which contained the data */
+    } else {
+	cleanup_key_data(context, key_data_count, key_data);
+    }
+    return(retval);
+}
+
+/*
+ * Add random key for a krb5_db_entry 
+ * Assumes the max kvno
+ *
+ * As a side effect all old keys older than the max kvno are nuked.
+ */
+krb5_error_code
+krb5_dbe_ark(context, master_key, ks_tuple, ks_tuple_count, db_entry)
+    krb5_context	  context;
+    krb5_keyblock       * master_key;
+    krb5_key_salt_tuple	* ks_tuple;
+    int			  ks_tuple_count;
+    krb5_db_entry	* db_entry;
+{
+    int 		  key_data_count;
+    krb5_key_data 	* key_data;
+    krb5_error_code	  retval;
+    int			  kvno;
+    int			  i;
+
+    /* First save the old keydata */
+    kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
+    key_data_count = db_entry->n_key_data;
+    key_data = db_entry->key_data;
+    db_entry->key_data = NULL;
+    db_entry->n_key_data = 0;
+
+    /* increment the kvno */
+    kvno++;
+
+    if ((retval = add_key_rnd(context, master_key, ks_tuple, 
+			     ks_tuple_count, db_entry, kvno))) {
+	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+	db_entry->n_key_data = key_data_count;
+	db_entry->key_data = key_data;
+    } else {
+	/* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */
+	for (i = 0; i < key_data_count; i++) {
+	    if (key_data[i].key_data_kvno == (kvno - 1)) {
+		if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
+		    cleanup_key_data(context, db_entry->n_key_data,
+				     db_entry->key_data);
+		    break;
+		}
+		/* We should decrypt/re-encrypt the data to use the same mkvno*/
+		db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
+		memset(&key_data[i], 0, sizeof(krb5_key_data));
+	    }
+	}
+	cleanup_key_data(context, key_data_count, key_data);
+    }
+    return(retval);
+}
+
+/*
+ * Add key_data for a krb5_db_entry 
+ * If passwd is NULL the assumes that the caller wants a random password.
+ */
+static krb5_error_code
+add_key_pwd(context, master_key, ks_tuple, ks_tuple_count, passwd, 
+	    db_entry, kvno)
+    krb5_context	  context;
+    krb5_keyblock       * master_key;
+    krb5_key_salt_tuple	* ks_tuple;
+    int			  ks_tuple_count;
+    char 		* passwd;
+    krb5_db_entry	* db_entry;
+    int			  kvno;
+{
+    krb5_error_code	  retval;
+    krb5_keysalt	  key_salt;
+    krb5_keyblock	  key;
+    krb5_data	  	  pwd;
+    int			  i, j, k;
+    krb5_key_data         tmp_key_data;
+    krb5_key_data        *tptr;
+
+    memset( &tmp_key_data, 0, sizeof(tmp_key_data));
+
+    retval = 0;
+
+    for (i = 0; i < ks_tuple_count; i++) {
+	krb5_boolean similar;
+
+	similar = 0;
+
+	/*
+	 * We could use krb5_keysalt_iterate to replace this loop, or use
+	 * krb5_keysalt_is_present for the loop below, but we want to avoid
+	 * circular library dependencies.
+	 */
+	for (j = 0; j < i; j++) {
+	    if ((retval = krb5_c_enctype_compare(context,
+						 ks_tuple[i].ks_enctype,
+						 ks_tuple[j].ks_enctype,
+						 &similar)))
+		return(retval);
+
+	    if (similar &&
+		(ks_tuple[j].ks_salttype == ks_tuple[i].ks_salttype))
+		break;
+	}
+
+	if (j < i)
+	    continue;
+
+	if ((retval = krb5_dbe_create_key_data(context, db_entry))) 
+	    return(retval);
+
+	/* Convert password string to key using appropriate salt */
+	switch (key_salt.type = ks_tuple[i].ks_salttype) {
+    	case KRB5_KDB_SALTTYPE_ONLYREALM: {
+            krb5_data * saltdata;
+            if ((retval = krb5_copy_data(context, krb5_princ_realm(context,
+					      db_entry->princ), &saltdata)))
+	 	return(retval);
+
+	    key_salt.data = *saltdata;
+	    krb5_xfree(saltdata);
+	}
+		break;
+    	case KRB5_KDB_SALTTYPE_NOREALM:
+            if ((retval=krb5_principal2salt_norealm(context, db_entry->princ,
+						    &key_salt.data))) 
+		return(retval);
+            break;
+	case KRB5_KDB_SALTTYPE_NORMAL:
+            if ((retval = krb5_principal2salt(context, db_entry->princ,
+					      &key_salt.data))) 
+		return(retval);
+            break;
+    	case KRB5_KDB_SALTTYPE_V4:
+            key_salt.data.length = 0;
+            key_salt.data.data = 0;
+            break;
+    	case KRB5_KDB_SALTTYPE_AFS3: {
+#if 0
+            krb5_data * saltdata;
+            if (retval = krb5_copy_data(context, krb5_princ_realm(context,
+					db_entry->princ), &saltdata))
+	 	return(retval);
+
+	    key_salt.data = *saltdata;
+	    key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
+	    krb5_xfree(saltdata);
+#else
+	    /* Why do we do this? Well, the afs_mit_string_to_key needs to
+	       use strlen, and the realm is not NULL terminated.... */
+	    unsigned int slen = 
+		(*krb5_princ_realm(context,db_entry->princ)).length;
+	    if(!(key_salt.data.data = (char *) malloc(slen+1)))
+	        return ENOMEM;
+	    key_salt.data.data[slen] = 0;
+	    memcpy((char *)key_salt.data.data,
+		   (char *)(*krb5_princ_realm(context,db_entry->princ)).data,
+		   slen);
+	    key_salt.data.length = SALT_TYPE_AFS_LENGTH; /*length actually used below...*/
+#endif
+
+	}
+		break;
+	default:
+	    return(KRB5_KDB_BAD_SALTTYPE);
+	}
+
+    	pwd.data = passwd;
+    	pwd.length = strlen(passwd);
+
+	/* AFS string to key will happen here */
+	if ((retval = krb5_c_string_to_key(context, ks_tuple[i].ks_enctype,
+					   &pwd, &key_salt.data, &key))) {
+	     if (key_salt.data.data)
+		  free(key_salt.data.data);
+	     return(retval);
+	}
+
+	if (key_salt.data.length == SALT_TYPE_AFS_LENGTH)
+	    key_salt.data.length = 
+	      krb5_princ_realm(context, db_entry->princ)->length;
+
+	/* memory allocation to be done by db. So, use temporary block and later copy
+	   it to the memory allocated by db */
+	retval = krb5_dbekd_encrypt_key_data(context, master_key, &key,
+					     (const krb5_keysalt *)&key_salt,
+					     kvno, &tmp_key_data);
+	if (key_salt.data.data)
+	    free(key_salt.data.data);
+	krb5_xfree(key.contents);
+
+	if( retval )
+	    return retval;
+
+	tptr = &db_entry->key_data[db_entry->n_key_data-1];
+
+	tptr->key_data_ver = tmp_key_data.key_data_ver;
+	tptr->key_data_kvno = tmp_key_data.key_data_kvno;
+
+	for( k = 0; k < tmp_key_data.key_data_ver; k++ )
+	{
+	    tptr->key_data_type[k] = tmp_key_data.key_data_type[k];
+	    tptr->key_data_length[k] = tmp_key_data.key_data_length[k];
+	    if( tmp_key_data.key_data_contents[k] )
+	    {
+		tptr->key_data_contents[k] = krb5_db_alloc(context, NULL, tmp_key_data.key_data_length[k]);
+		if( tptr->key_data_contents[k] == NULL )
+		{
+		    cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+		    db_entry->key_data = NULL;
+		    db_entry->n_key_data = 0;
+		    retval = ENOMEM;
+		    goto add_key_pwd_err;
+		}
+		memcpy( tptr->key_data_contents[k], tmp_key_data.key_data_contents[k], tmp_key_data.key_data_length[k]);
+
+		memset( tmp_key_data.key_data_contents[k], 0, tmp_key_data.key_data_length[k]);
+		free( tmp_key_data.key_data_contents[k] );
+		tmp_key_data.key_data_contents[k] = NULL;
+	    }
+	}
+    }
+ add_key_pwd_err:
+    for( i = 0; i < tmp_key_data.key_data_ver; i++ )
+    {
+	if( tmp_key_data.key_data_contents[i] )
+	{
+	    memset( tmp_key_data.key_data_contents[i], 0, tmp_key_data.key_data_length[i]);
+	    free( tmp_key_data.key_data_contents[i] );
+	}
+    }
+
+    return(retval);
+}
+
+/*
+ * Change password for a krb5_db_entry 
+ * Assumes the max kvno
+ *
+ * As a side effect all old keys are nuked if keepold is false.
+ */
+krb5_error_code
+krb5_dbe_def_cpw(context, master_key, ks_tuple, ks_tuple_count, passwd,
+	     new_kvno, keepold, db_entry)
+    krb5_context	  context;
+    krb5_keyblock       * master_key;
+    krb5_key_salt_tuple	* ks_tuple;
+    int			  ks_tuple_count;
+    char 		* passwd;
+    int			  new_kvno;
+    krb5_boolean	  keepold;
+    krb5_db_entry	* db_entry;
+{
+    int 		  key_data_count;
+    int			  n_new_key_data;
+    krb5_key_data 	* key_data;
+    krb5_error_code	  retval;
+    int			  old_kvno;
+    int			  i;
+
+    /* First save the old keydata */
+    old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
+				 db_entry->key_data);
+    key_data_count = db_entry->n_key_data;
+    key_data = db_entry->key_data;
+    db_entry->key_data = NULL;
+    db_entry->n_key_data = 0;
+
+    /* increment the kvno.  if the requested kvno is too small, 
+       increment the old kvno */
+    if (new_kvno < old_kvno+1)
+       new_kvno = old_kvno+1;
+
+    retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
+			 passwd, db_entry, new_kvno);
+    if (retval) {
+	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+	db_entry->n_key_data = key_data_count;
+	db_entry->key_data = key_data;
+    } else if (keepold) {
+	n_new_key_data = db_entry->n_key_data;
+	for (i = 0; i < key_data_count; i++) {
+	    retval = krb5_dbe_create_key_data(context, db_entry);
+	    if (retval) {
+		cleanup_key_data(context, db_entry->n_key_data,
+				 db_entry->key_data);
+		break;
+	    }
+	    db_entry->key_data[i+n_new_key_data] = key_data[i];
+	    memset(&key_data[i], 0, sizeof(krb5_key_data));
+	}
+	krb5_db_free( context, key_data );
+    } else {
+	cleanup_key_data(context, key_data_count, key_data);
+    }
+    return(retval);
+}
+
+/*
+ * Add password for a krb5_db_entry 
+ * Assumes the max kvno
+ *
+ * As a side effect all old keys older than the max kvno are nuked.
+ */
+krb5_error_code
+krb5_dbe_apw(context, master_key, ks_tuple, ks_tuple_count, passwd, db_entry)
+    krb5_context	  context;
+    krb5_keyblock       * master_key;
+    krb5_key_salt_tuple	* ks_tuple;
+    int			  ks_tuple_count;
+    char 		* passwd;
+    krb5_db_entry	* db_entry;
+{
+    int 		  key_data_count;
+    krb5_key_data 	* key_data;
+    krb5_error_code	  retval;
+    int			  old_kvno, new_kvno;
+    int			  i;
+
+    /* First save the old keydata */
+    old_kvno = get_key_data_kvno(context, db_entry->n_key_data,
+				 db_entry->key_data);
+    key_data_count = db_entry->n_key_data;
+    key_data = db_entry->key_data;
+    db_entry->key_data = NULL;
+    db_entry->n_key_data = 0;
+
+    /* increment the kvno */
+    new_kvno = old_kvno+1;
+
+    if ((retval = add_key_pwd(context, master_key, ks_tuple, ks_tuple_count,
+			     passwd, db_entry, new_kvno))) {
+	cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
+	db_entry->n_key_data = key_data_count;
+	db_entry->key_data = key_data;
+    } else {
+	/* Copy keys with key_data_kvno == old_kvno */
+	for (i = 0; i < key_data_count; i++) {
+	    if (key_data[i].key_data_kvno == old_kvno) {
+		if ((retval = krb5_dbe_create_key_data(context, db_entry))) {
+		    cleanup_key_data(context, db_entry->n_key_data,
+				     db_entry->key_data);
+		    break;
+		}
+		/* We should decrypt/re-encrypt the data to use the same mkvno*/
+		db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
+		memset(&key_data[i], 0, sizeof(krb5_key_data));
+	    }
+	}
+	cleanup_key_data(context, key_data_count, key_data);
+    }
+    return(retval);
+}
+
+
diff --git a/mechglue/src/lib/kdb/kdb_default.c b/mechglue/src/lib/kdb/kdb_default.c
new file mode 100644
index 000000000..07d1cef3b
--- /dev/null
+++ b/mechglue/src/lib/kdb/kdb_default.c
@@ -0,0 +1,329 @@
+/*
+ * lib/kdb/kdb_helper.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology. 
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "k5-int.h"
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+/*
+ * Given a particular enctype and optional salttype and kvno, find the
+ * most appropriate krb5_key_data entry of the database entry.
+ *
+ * If stype or kvno is negative, it is ignored.
+ * If kvno is 0 get the key which is maxkvno for the princ and matches
+ * the other attributes.
+ */
+krb5_error_code
+krb5_dbe_def_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, kdatap)
+    krb5_context	kcontext;
+    krb5_db_entry	*dbentp;
+    krb5_int32		*start;
+    krb5_int32		ktype;
+    krb5_int32		stype;
+    krb5_int32		kvno;
+    krb5_key_data	**kdatap;
+{
+    int			i, idx;
+    int			maxkvno;
+    krb5_key_data	*datap;
+    krb5_error_code	ret;
+
+    ret = 0;
+    if (kvno == -1 && stype == -1 && ktype == -1)
+	kvno = 0;
+
+    if (kvno == 0) { 
+	/* Get the max key version */
+	for (i = 0; i < dbentp->n_key_data; i++) {
+	    if (kvno < dbentp->key_data[i].key_data_kvno) { 
+		kvno = dbentp->key_data[i].key_data_kvno;
+	    }
+	}
+    }
+
+    maxkvno = -1;
+    datap = (krb5_key_data *) NULL;
+    for (i = *start; i < dbentp->n_key_data; i++) {
+        krb5_boolean    similar;
+        krb5_int32      db_stype;
+
+	ret = 0;
+	if (dbentp->key_data[i].key_data_ver > 1) {
+	    db_stype = dbentp->key_data[i].key_data_type[1];
+	} else {
+	    db_stype = KRB5_KDB_SALTTYPE_NORMAL;
+	}
+
+	/*
+	 * Filter out non-permitted enctypes.
+	 */
+	if (!krb5_is_permitted_enctype(kcontext,
+				       dbentp->key_data[i].key_data_type[0])) {
+	    ret = KRB5_KDB_NO_PERMITTED_KEY;
+	    continue;
+	}
+	
+
+	if (ktype > 0) {
+	    if ((ret = krb5_c_enctype_compare(kcontext, (krb5_enctype) ktype,
+					      dbentp->key_data[i].key_data_type[0],
+					      &similar)))
+
+		return(ret);
+	}
+
+	if (((ktype <= 0) || similar) &&
+	    ((db_stype == stype) || (stype < 0))) {
+	    if (kvno >= 0) {
+		if (kvno == dbentp->key_data[i].key_data_kvno) {
+		    datap = &dbentp->key_data[i];
+		    idx = i;
+		    maxkvno = kvno;
+		    break;
+		}
+	    } else {
+		if (dbentp->key_data[i].key_data_kvno > maxkvno) {
+		    maxkvno = dbentp->key_data[i].key_data_kvno;
+		    datap = &dbentp->key_data[i];
+		    idx = i;
+		}
+	    }
+	}
+    }
+    if (maxkvno < 0)
+	return ret ? ret : KRB5_KDB_NO_MATCHING_KEY;
+    *kdatap = datap;
+    *start = idx+1;
+    return 0;
+}
+    
+/*
+ *  kdb default functions. Ideally, some other file should have this functions. For now, TBD.
+ */
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+krb5_error_code
+krb5_def_store_mkey(context, keyfile, mname, key, master_pwd)
+    krb5_context context;
+    char *keyfile;
+    krb5_principal mname;
+    krb5_keyblock *key;
+    char *master_pwd;
+{
+    FILE *kf;
+    krb5_error_code retval = 0;
+    krb5_ui_2 enctype;
+    char defkeyfile[MAXPATHLEN+1];
+    krb5_data *realm = krb5_princ_realm(context, mname);
+#if HAVE_UMASK
+    mode_t oumask;
+#endif
+
+    if (!keyfile) {
+	(void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB);
+	(void) strncat(defkeyfile, realm->data,
+		       min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1,
+			   realm->length));
+	defkeyfile[sizeof(defkeyfile) - 1] = '\0';
+	keyfile = defkeyfile;
+    }
+
+#if HAVE_UMASK
+    oumask = umask(077);
+#endif
+#ifdef ANSI_STDIO
+    if (!(kf = fopen(keyfile, "wb")))
+#else
+    if (!(kf = fopen(keyfile, "w")))
+#endif
+    {
+#if HAVE_UMASK
+	(void) umask(oumask);
+#endif
+	return errno;
+    }
+    enctype = key->enctype;
+    if ((fwrite((krb5_pointer) &enctype,
+		2, 1, kf) != 1) ||
+	(fwrite((krb5_pointer) &key->length,
+		sizeof(key->length), 1, kf) != 1) ||
+	(fwrite((krb5_pointer) key->contents,
+		sizeof(key->contents[0]), (unsigned) key->length, 
+		kf) != key->length)) {
+	retval = errno;
+	(void) fclose(kf);
+    }
+    if (fclose(kf) == EOF)
+	retval = errno;
+#if HAVE_UMASK
+    (void) umask(oumask);
+#endif
+    return retval;
+}
+
+
+krb5_error_code
+krb5_db_def_fetch_mkey( krb5_context   context,
+			krb5_principal mname,
+			krb5_keyblock *key,
+			int           *kvno,
+			char          *db_args)
+{
+    krb5_error_code retval;
+    krb5_ui_2 enctype;
+    char defkeyfile[MAXPATHLEN+1];
+    krb5_data *realm = krb5_princ_realm(context, mname);
+    FILE *kf = NULL;
+
+    retval = 0;
+    key->magic = KV5M_KEYBLOCK;
+    (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB);
+    (void) strncat(defkeyfile, realm->data,
+		   min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1,
+		       realm->length));
+    defkeyfile[sizeof(defkeyfile) - 1] = '\0';
+	
+#ifdef ANSI_STDIO
+    if (!(kf = fopen((db_args) ? db_args : defkeyfile, "rb")))
+#else
+    if (!(kf = fopen((db_args) ? db_args : defkeyfile, "r")))
+#endif
+	return KRB5_KDB_CANTREAD_STORED;
+
+    if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) {
+	retval = KRB5_KDB_CANTREAD_STORED;
+	goto errout;
+    }
+
+    if (key->enctype == ENCTYPE_UNKNOWN)
+	key->enctype = enctype;
+    else if (enctype != key->enctype) {
+	retval = KRB5_KDB_BADSTORED_MKEY;
+	goto errout;
+    }
+
+    if (fread((krb5_pointer) &key->length,
+	      sizeof(key->length), 1, kf) != 1) {
+	retval = KRB5_KDB_CANTREAD_STORED;
+	goto errout;
+    }
+
+    if (!key->length || ((int) key->length) < 0) {
+	retval = KRB5_KDB_BADSTORED_MKEY;
+	goto errout;
+    }
+	
+    if (!(key->contents = (krb5_octet *)malloc(key->length))) {
+	retval = ENOMEM;
+	goto errout;
+    }
+
+    if (fread((krb5_pointer) key->contents,
+	      sizeof(key->contents[0]), key->length, kf) 
+	!= key->length) {
+	retval = KRB5_KDB_CANTREAD_STORED;
+	memset(key->contents, 0,  key->length);
+	free(key->contents);
+	key->contents = 0;
+    } else
+	retval = 0;
+
+    *kvno = 0;
+
+ errout:
+    (void) fclose(kf);
+    return retval;
+
+}
+
+
+krb5_error_code
+krb5_def_verify_master_key(context, mprinc, mkey)
+    krb5_context context;
+    krb5_principal mprinc;
+    krb5_keyblock *mkey;
+{
+    krb5_error_code retval;
+    krb5_db_entry master_entry;
+    int nprinc;
+    krb5_boolean more;
+    krb5_keyblock tempkey;
+
+    nprinc = 1;
+    if ((retval = krb5_db_get_principal(context, mprinc,
+					&master_entry, &nprinc, &more)))
+	return(retval);
+	
+    if (nprinc != 1) {
+	if (nprinc)
+	    krb5_db_free_principal(context, &master_entry, nprinc);
+	return(KRB5_KDB_NOMASTERKEY);
+    } else if (more) {
+	krb5_db_free_principal(context, &master_entry, nprinc);
+	return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
+    }	
+
+    if ((retval = krb5_dbekd_decrypt_key_data(context, mkey, 
+					      &master_entry.key_data[0],
+					      &tempkey, NULL))) {
+	krb5_db_free_principal(context, &master_entry, nprinc);
+	return retval;
+    }
+
+    if (mkey->length != tempkey.length ||
+	memcmp((char *)mkey->contents,
+	       (char *)tempkey.contents,mkey->length)) {
+	retval = KRB5_KDB_BADMASTERKEY;
+    }
+
+    memset((char *)tempkey.contents, 0, tempkey.length);
+    krb5_xfree(tempkey.contents);
+    krb5_db_free_principal(context, &master_entry, nprinc);
+    
+    return retval;
+}
+
+
+krb5_error_code kdb_def_set_mkey ( krb5_context kcontext,
+				   char *pwd,
+				   krb5_keyblock *key )
+{
+    printf("default set master key\n");
+    return 0;
+}
+
+krb5_error_code kdb_def_get_mkey ( krb5_context kcontext,
+				   krb5_keyblock **key )
+{
+    printf("default get master key\n");
+    return 0;
+}
+
diff --git a/mechglue/src/lib/kdb/keytab.c b/mechglue/src/lib/kdb/keytab.c
new file mode 100644
index 000000000..227a42e08
--- /dev/null
+++ b/mechglue/src/lib/kdb/keytab.c
@@ -0,0 +1,236 @@
+/*
+ * kadmin/v5server/keytab.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+#include <string.h>
+
+#include "k5-int.h"
+#include "kdb_kt.h"
+
+static int
+is_xrealm_tgt(krb5_context, krb5_const_principal);
+
+krb5_error_code krb5_ktkdb_close (krb5_context, krb5_keytab);
+
+krb5_error_code krb5_ktkdb_get_entry (krb5_context, krb5_keytab, krb5_const_principal,
+		   krb5_kvno, krb5_enctype, krb5_keytab_entry *);
+
+static krb5_error_code
+krb5_ktkdb_get_name(krb5_context context, krb5_keytab keytab,
+		    char *name, unsigned int namelen)
+{
+    if (namelen < sizeof("KDB:"))
+	return KRB5_KT_NAME_TOOLONG;
+    strcpy(name, "KDB:");
+    return 0;
+}
+
+krb5_kt_ops krb5_kt_kdb_ops = {
+    0,
+    "KDB", 	/* Prefix -- this string should not appear anywhere else! */
+    krb5_ktkdb_resolve,		/* resolve */
+    krb5_ktkdb_get_name,	/* get_name */
+    krb5_ktkdb_close,		/* close */
+    krb5_ktkdb_get_entry,	/* get */
+    NULL,			/* start_seq_get */
+    NULL,			/* get_next */
+    NULL,			/* end_get */
+    NULL,			/* add (extended) */
+    NULL,			/* remove (extended) */
+    NULL, 		/* (void *) &krb5_ktfile_ser_entry */
+};
+
+typedef struct krb5_ktkdb_data {
+    char * name;
+} krb5_ktkdb_data;
+
+krb5_error_code
+krb5_ktkdb_resolve(context, name, id)
+    krb5_context  	  context;
+    const char		* name;
+    krb5_keytab		* id;
+{
+    if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
+        return(ENOMEM);
+    (*id)->ops = &krb5_kt_kdb_ops;
+    (*id)->magic = KV5M_KEYTAB;
+    return(0);
+}
+
+krb5_error_code
+krb5_ktkdb_close(context, kt)
+     krb5_context context;
+     krb5_keytab kt;
+{
+  /*
+   * This routine is responsible for freeing all memory allocated 
+   * for this keytab.  There are no system resources that need
+   * to be freed nor are there any open files.
+   *
+   * This routine should undo anything done by krb5_ktkdb_resolve().
+   */
+
+  kt->ops = NULL;
+  krb5_xfree(kt);
+
+  return 0;
+}
+
+static krb5_context ktkdb_ctx = NULL;
+
+/*
+ * Set a different context for use with ktkdb_get_entry().  This is
+ * primarily useful for kadmind, where the gssapi library context,
+ * which will be used for the keytab, will necessarily have a
+ * different context than that used by the kadm5 library to access the
+ * database for its own purposes.
+ */
+krb5_error_code
+krb5_ktkdb_set_context(krb5_context ctx)
+{
+    ktkdb_ctx = ctx;
+    return 0;
+}
+
+krb5_error_code
+krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
+    krb5_context 	  in_context;
+    krb5_keytab 	  id;
+    krb5_const_principal  principal;
+    krb5_kvno 	 	  kvno;
+    krb5_enctype 	  enctype;
+    krb5_keytab_entry 	* entry;
+{
+    krb5_context	  context;
+    krb5_keyblock       * master_key;
+    krb5_error_code 	  kerror = 0;
+    krb5_key_data 	* key_data;
+    krb5_db_entry 	  db_entry;
+    krb5_boolean 	  more = 0;
+    int 	 	  n = 0;
+    int xrealm_tgt;
+    krb5_boolean similar;
+
+    if (ktkdb_ctx)
+	context = ktkdb_ctx;
+    else
+	context = in_context;
+
+    xrealm_tgt = is_xrealm_tgt(context, principal);
+
+    /* Check whether database is inited. Open is commented */
+    if ((kerror = krb5_db_inited(context)))
+        return(kerror);
+
+    /* get_principal */
+    kerror = krb5_db_get_principal(context, principal, &
+				       db_entry, &n, &more);
+    if (kerror) {
+      /*        krb5_db_close_database(context); */
+        return(kerror);
+    }
+    if (n != 1) {
+      /* krb5_db_close_database(context); */
+	return KRB5_KT_NOTFOUND;
+    }
+
+    if (db_entry.attributes & KRB5_KDB_DISALLOW_SVR
+	|| db_entry.attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
+	kerror = KRB5_KT_NOTFOUND;
+	goto error;
+    }
+
+    /* match key */
+    kerror = krb5_db_get_mkey(context, &master_key);
+    if (kerror)
+	goto error;
+
+    /* For cross realm tgts, we match whatever enctype is provided;
+     * for other principals, we only match the first enctype that is
+     * found.  Since the TGS and AS code do the same thing, then we
+     * will only successfully decrypt  tickets we have issued.*/
+    kerror = krb5_dbe_find_enctype(context, &db_entry,
+				   xrealm_tgt?enctype:-1,
+				   -1, kvno, &key_data);
+    if (kerror)
+	goto error;
+
+
+    kerror = krb5_dbekd_decrypt_key_data(context, master_key,
+					 key_data, &entry->key, NULL);
+    if (kerror)
+	goto error;
+
+    if (enctype > 0) {	
+	kerror = krb5_c_enctype_compare(context, enctype,
+					entry->key.enctype, &similar);
+	if (kerror)
+	    goto error;
+
+	if (!similar) {
+	    kerror = KRB5_KDB_NO_PERMITTED_KEY;
+	    goto error;
+	}
+    }
+    /*
+     * Coerce the enctype of the output keyblock in case we got an
+     * inexact match on the enctype.
+     */
+    entry->key.enctype = enctype;
+
+    kerror = krb5_copy_principal(context, principal, &entry->principal);
+    if (kerror)
+	goto error;
+
+    /* Close database */
+  error:
+    krb5_db_free_principal(context, &db_entry, 1);
+    /*    krb5_db_close_database(context); */
+    return(kerror);
+}
+
+/*
+ * is_xrealm_tgt: Returns true if the principal is a cross-realm  TGT
+ * principal-- a principal with first component  krbtgt and second
+ * component not equal to realm.
+ */
+static int
+is_xrealm_tgt(krb5_context context, krb5_const_principal princ)
+{
+    krb5_data *dat;
+    if (krb5_princ_size(context, princ) != 2)
+	return 0;
+    dat = krb5_princ_component(context, princ, 0);
+    if (strncmp("krbtgt", dat->data, dat->length) != 0)
+	return 0;
+    dat = krb5_princ_component(context, princ, 1);
+    if (dat->length != princ->realm.length)
+	return 1;
+    if (strncmp(dat->data, princ->realm.data, dat->length) == 0)
+	return 0;
+    return 1;
+
+}
+
diff --git a/mechglue/src/lib/kdb/libkdb5.exports b/mechglue/src/lib/kdb/libkdb5.exports
new file mode 100644
index 000000000..c4d2c8846
--- /dev/null
+++ b/mechglue/src/lib/kdb/libkdb5.exports
@@ -0,0 +1,50 @@
+krb5_db_open
+krb5_db_inited
+krb5_db_clr_error
+krb5_db_alloc
+krb5_db_free
+krb5_db_create
+krb5_db_delete_principal
+krb5_db_destroy
+krb5_db_fetch_mkey
+krb5_db_fini
+krb5_db_free_principal
+krb5_db_get_age
+krb5_db_get_mkey
+krb5_db_get_principal
+krb5_db_iterate
+krb5_db_lock
+krb5_db_put_principal
+krb5_db_set_mkey
+krb5_db_setup_mkey_name
+krb5_db_unlock
+krb5_db_store_master_key
+krb5_db_verify_master_key
+krb5_dbe_apw
+krb5_dbe_ark
+krb5_dbe_cpw
+krb5_dbe_create_key_data
+krb5_dbe_crk
+krb5_dbe_find_enctype
+krb5_dbe_lookup_last_pwd_change
+krb5_dbe_lookup_mod_princ_data
+krb5_dbe_lookup_tl_data
+krb5_dbe_search_enctype
+krb5_dbe_update_last_pwd_change
+krb5_dbe_update_mod_princ_data
+krb5_dbe_update_tl_data
+krb5_dbekd_decrypt_key_data
+krb5_dbekd_encrypt_key_data
+krb5_kt_kdb_ops
+krb5_ktkdb_close
+krb5_ktkdb_get_entry
+krb5_ktkdb_resolve
+krb5_ktkdb_set_context
+krb5_mkey_pwd_prompt1
+krb5_mkey_pwd_prompt2
+krb5_db_create_policy
+krb5_db_get_policy
+krb5_db_put_policy
+krb5_db_iter_policy
+krb5_db_delete_policy
+krb5_db_free_policy
diff --git a/mechglue/src/lib/krb4/.Sanitize b/mechglue/src/lib/krb4/.Sanitize
new file mode 100644
index 000000000..714bc7bbc
--- /dev/null
+++ b/mechglue/src/lib/krb4/.Sanitize
@@ -0,0 +1,131 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+DNR.c
+Makefile.in
+Password.c
+ad_print.c
+configure.in
+configure
+cr_auth_repl.c
+cr_ciph.c
+cr_death_pkt.c
+cr_err_repl.c
+cr_tkt.c
+debug.c
+decomp_tkt.c
+dest_tkt.c
+err_txt.c
+fakeenv.c
+fgetst.c
+g_ad_tkt.c
+g_admhst.c
+g_cnffile.c
+g_cred.c
+g_in_tkt.c
+g_krbhst.c
+g_krbrlm.c
+g_phost.c
+g_pw_in_tkt.c
+g_pw_tkt.c
+g_svc_in_tkt.c
+g_tf_fname.c
+g_tf_realm.c
+g_tkt_svc.c
+gethostname.c
+getst.c
+in_tkt.c
+kerberos.def
+klog.c
+kname_parse.c
+kntoln.c
+kparse.c
+krb_err.et
+kuserok.c
+log.c
+mac_glue.c
+mac_store.c
+mac_store.h
+mac_stubs.c
+mac_time.c
+memcache.c
+memcache.h
+mk_auth.c
+mk_err.c
+mk_preauth.c
+mk_priv.c
+mk_req.c
+mk_safe.c
+month_sname.c
+netread.c
+netwrite.c
+one.c
+pkt_cipher.c
+pkt_clen.c
+put_svc_key.c
+rd_err.c
+rd_preauth.c
+rd_priv.c
+rd_req.c
+rd_safe.c
+rd_svc_key.c
+realmofhost.c
+recvauth.c
+ren-cyg.sh
+ren-pc.bat
+ren-pc.sh
+ren-pl10.sh
+ren.msg
+ren2dos.sh
+ren2long.sh
+save_creds.c
+sed-cyg.sh
+sed-pc.sh
+sed-pl10.sh
+send_to_kdc.c
+sendauth.c
+setenv.c
+stime.c
+strcasecmp.c
+swab.c
+tf_shm.c
+tf_util.c
+tkt_string.c
+unix_glue.c
+unix_time.c
+vmslink.com
+vmsswab.c
+win_glue.c
+win_store.c
+win_time.c
+winsock.def
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb4/CCache-glue.c b/mechglue/src/lib/krb4/CCache-glue.c
new file mode 100644
index 000000000..db00631f8
--- /dev/null
+++ b/mechglue/src/lib/krb4/CCache-glue.c
@@ -0,0 +1,741 @@
+/*
+ * CCache-glue.c
+ *
+ * This file contains implementations of krb4 credentials cache operations in terms
+ * of the CCache API (<http://www.umich.edu/~sgr/v4Cache/>).
+ *
+ * $Header$
+ */
+
+
+#include "krb.h"
+#include "krb4int.h"
+
+#if !defined (USE_CCAPI) || !USE_CCAPI
+#error "Cannot use CCache glue without the CCAPI!"
+#endif
+
+#ifdef USE_LOGIN_LIBRARY
+#include <KerberosLoginPrivate.h>
+#endif /* USE_LOGIN_LIBRARY */
+#include <CredentialsCache.h>
+
+#include <string.h>
+#include <stdlib.h>
+ 
+/*
+ * The following functions are part of the KfM ABI.  
+ * They are deprecated, so they only appear here, not in krb.h.
+ *
+ * Do not change the ABI of these functions!
+ */
+int KRB5_CALLCONV krb_get_num_cred(void);
+int KRB5_CALLCONV krb_get_nth_cred(char *, char *, char *, int);
+int KRB5_CALLCONV krb_delete_cred(char *, char *,char *);
+int KRB5_CALLCONV dest_all_tkts(void);
+ 
+/* Internal functions */
+static void UpdateDefaultCache (void);
+
+/* 
+ * The way Kerberos v4 normally works is that at any given point in time there is a
+ * file where all the tickets go, determined by an environment variable. If a user kinits
+ * to a new principal, the existing tickets are replaced with new ones. At any point in time, there is a 
+ * "current" or "default" principal, which is determined by the principal associated with
+ * the current ticket file.
+ * 
+ * In the CCache API implementation, this corresponds to always having a "default"
+ * or "current" named cache. The default principal then corresponds to that cache.
+ *
+ * Unfortunately, Kerberos v4 also has this notion that the default cache exists (in the sense
+ * that its name is known) even before the actual file has been created.
+ *
+ * In addition to this, we cannot make the default cache system-wide global, because then
+ * we get all sorts of interesting scenarios in which context switches between processes
+ * can cause credentials to be stored in wrong caches.
+ *
+ * To solve all the problems, we have to emulate the concept of an environment variable,
+ * by having a system-wide concept of what a default credentials cache is; then, we copy 
+ * the system-wide value into the per-process value when the application starts up.
+ *
+ * However, in order to allow applications to be able to sanely handle the user model we
+ * want to support, in which the user has some way of selecting the system-wide default
+ * user _without_ quitting and relaunching all applications (this is also necessary for
+ * KClient support), calls had to be added to the Kerberos v4 library to reset the 
+ * per-process cached value of default cache.
+ */
+ 
+/*
+ * Name of the default cache
+ */
+char* gDefaultCacheName = NULL;
+
+/*
+ * Initialize credentials cache
+ *
+ * Creating the cache will blow away an existing one. The assumption is that
+ * whoever called us made sure that the one that we blow away if it exists
+ * is the right one to blow away.
+ */
+
+int KRB5_CALLCONV
+krb_in_tkt (
+	char*		pname,
+	char*		pinst,
+	char*		realm)
+{
+	char			principal [MAX_K_NAME_SZ + 1];
+	cc_int32		err = ccNoError;
+	cc_context_t	cc_context = NULL;
+    cc_int32		cc_version;
+    cc_ccache_t		ccache = NULL;
+	
+	err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+    
+	if (err == ccNoError) {
+        sprintf (principal, "%s%s%s@%s", pname, (pinst [0] == '\0') ? "" : ".", pinst, realm);
+	}
+    
+	if (err == ccNoError) {
+        err = cc_context_create_ccache (cc_context, TKT_FILE, cc_credentials_v4, principal, &ccache);
+	}
+
+    if (ccache != NULL)
+    	cc_ccache_release (ccache);
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+    if (err != ccNoError)
+		return KFAILURE;
+    else
+        return KSUCCESS;
+}
+
+int KRB5_CALLCONV
+krb_save_credentials(
+    char	*service,
+    char	*instance,
+    char	*realm,
+    C_Block	session,
+    int		lifetime,
+    int		kvno,
+    KTEXT	ticket,
+    long	issue_date)
+{
+    return krb4int_save_credentials_addr(service, instance, realm,
+					 session, lifetime, kvno,
+					 ticket, issue_date, 0);
+}
+
+/*
+ * Store a ticket into the default credentials cache
+ * cache must exist (if it didn't exist, it would have been created by in_tkt)
+ */
+int
+krb4int_save_credentials_addr(
+	char*			service,
+	char*			instance,
+	char*			realm,
+	C_Block			session,
+	int				lifetime,
+	int				kvno,
+	KTEXT			ticket,
+	long			issue_date,
+	KRB_UINT32		local_address)
+{
+	cc_int32				cc_err = ccNoError;
+	int						kerr = KSUCCESS;
+	cc_credentials_v4_t		v4creds;
+	cc_credentials_union	creds;
+	cc_ccache_t				ccache = NULL;
+	cc_string_t				principal;
+	cc_context_t			cc_context = NULL;
+    cc_int32				cc_version;
+	
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+	
+	if (cc_err == ccNoError) {
+        /* First try existing cache */
+        cc_err = cc_context_open_ccache (cc_context, TKT_FILE, &ccache);
+	}
+	
+    if (cc_err == ccNoError) {
+        /* Now we have a cache. Fill out the credentials and put them in the cache. */
+        /* To fill out the credentials, we need the principal */
+        cc_err = cc_ccache_get_principal (ccache, cc_credentials_v4, &principal);
+	}
+    
+    if (cc_err == ccNoError) {
+        kerr = kname_parse (v4creds.principal, v4creds.principal_instance, v4creds.realm, (char*) principal -> data);
+        cc_string_release (principal);
+	}
+    
+	if ((cc_err == ccNoError) && (kerr == KSUCCESS)) {
+		strncpy (v4creds.service, service, SNAME_SZ);
+        strncpy (v4creds.service_instance, instance, INST_SZ);
+        strncpy (v4creds.realm, realm, REALM_SZ);
+        memmove (v4creds.session_key, session, sizeof (C_Block));
+        v4creds.kvno = kvno;
+        v4creds.string_to_key_type = cc_v4_stk_unknown;
+        v4creds.issue_date = issue_date;
+        v4creds.address = local_address;
+        v4creds.lifetime = lifetime;
+        v4creds.ticket_size = ticket -> length;
+        memmove (v4creds.ticket, ticket -> dat, ticket -> length);
+        
+        creds.version = cc_credentials_v4;
+        creds.credentials.credentials_v4 = &v4creds;
+        
+        cc_err = cc_ccache_store_credentials (ccache, &creds);
+    }
+	
+    if (ccache != NULL)
+        cc_ccache_release (ccache);
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+    if (kerr != KSUCCESS)
+        return kerr;
+	if (cc_err != ccNoError)
+		return KFAILURE;
+    else
+        return KSUCCESS;
+}
+
+/*
+ * Credentials file -> realm mapping
+ *
+ * Determine the realm by opening the named cache and parsing realm from the principal
+ */
+int KRB5_CALLCONV
+krb_get_tf_realm (
+	const char*		ticket_file,
+	char*			realm)
+{
+	cc_string_t		principal;
+	char			pname [ANAME_SZ];
+	char			pinst [INST_SZ];
+	char			prealm [REALM_SZ];
+    int				kerr = KSUCCESS;
+	cc_int32		cc_err = ccNoError;
+	cc_context_t	cc_context = NULL;
+    cc_int32		cc_version = NULL;
+    cc_ccache_t		ccache = NULL;
+	
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+	
+    if (cc_err == ccNoError) {
+        cc_err = cc_context_open_ccache (cc_context, ticket_file, &ccache);
+	}
+
+    if (cc_err == ccNoError) {
+        cc_err = cc_ccache_get_principal (ccache, cc_credentials_v4, &principal);
+	}
+
+    if (cc_err == ccNoError) {
+        /* found cache. get princiapl and parse it */
+        kerr = kname_parse (pname, pinst, prealm, (char*) principal -> data);
+        cc_string_release (principal);
+    }
+    
+    if ((cc_err == ccNoError) && (kerr == KSUCCESS)) {
+        strcpy (realm, prealm);
+    }
+    
+    if (ccache != NULL) 
+        cc_ccache_release (ccache);
+    if (cc_context != NULL) 
+        cc_context_release (cc_context);
+    
+    if (kerr != KSUCCESS)
+        return kerr;
+	if (cc_err != ccNoError)
+		return GC_NOTKT;
+    else
+        return KSUCCESS;
+}
+
+/*
+ * Credentials file -> name, instance, realm mapping
+ */
+int KRB5_CALLCONV
+krb_get_tf_fullname (
+	const char*		ticket_file,
+	char*			name,
+	char*			instance,
+	char*			realm)
+{
+	cc_string_t		principal;
+	int				kerr = KSUCCESS;
+	cc_int32		cc_err = ccNoError;
+	cc_context_t	cc_context = NULL;
+    cc_int32		cc_version;
+    cc_ccache_t		ccache = NULL;
+	
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+	
+    if (cc_err == ccNoError) {
+        cc_err = cc_context_open_ccache (cc_context, ticket_file, &ccache);
+	}
+
+    if (cc_err == ccNoError) {
+        /* found cache. get principal and parse it */
+        cc_err = cc_ccache_get_principal (ccache, cc_credentials_v4, &principal);
+	}
+
+    if (cc_err == ccNoError) {
+        kerr = kname_parse (name, instance, realm, (char*) principal -> data);
+        cc_string_release (principal);
+	}
+    
+    if (ccache != NULL)
+        cc_ccache_release (ccache);    
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+    if (kerr != KSUCCESS)
+        return kerr;
+	if (cc_err != ccNoError)
+		return GC_NOTKT;
+    else
+        return KSUCCESS;
+}
+
+
+/*
+ * Retrieval from credentials cache
+ */
+int KRB5_CALLCONV
+krb_get_cred (
+	char*			service,
+	char*			instance,
+	char*			realm,
+	CREDENTIALS*	creds)
+{
+	int							kerr = KSUCCESS;
+    cc_int32					cc_err = ccNoError;
+	cc_credentials_t			theCreds = NULL;
+	cc_credentials_iterator_t	iterator = NULL;
+	cc_context_t				cc_context = NULL;
+    cc_int32					cc_version;
+    cc_ccache_t					ccache = NULL;
+		
+#ifdef USE_LOGIN_LIBRARY
+	// If we are requesting a tgt, prompt for it
+	if (strncmp (service, KRB_TICKET_GRANTING_TICKET, ANAME_SZ) == 0) {
+		OSStatus	err;
+		char		*cacheName;
+		KLPrincipal	outPrincipal;
+		
+		err = __KLInternalAcquireInitialTicketsForCache (TKT_FILE, kerberosVersion_V4, NULL, 
+                                                                 &outPrincipal, &cacheName);
+
+		if (err == klNoErr) {
+                	krb_set_tkt_string (cacheName);		// Tickets for the krb4 principal went here
+			KLDisposeString (cacheName);	
+			KLDisposePrincipal (outPrincipal);
+		} else {
+			return GC_NOTKT;
+		}
+	}
+#endif /* USE_LOGIN_LIBRARY */     
+	
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+
+	if (cc_err == ccNoError) {
+        cc_err = cc_context_open_ccache (cc_context, TKT_FILE, &ccache);
+	}
+
+	if (cc_err == ccNoError) {
+        cc_err = cc_ccache_new_credentials_iterator (ccache, &iterator);
+	}
+
+	if (cc_err == ccNoError) {
+        for (;;) {
+            /* get next creds */
+            cc_err = cc_credentials_iterator_next (iterator, &theCreds);
+            if (cc_err == ccIteratorEnd) {
+                kerr = GC_NOTKT;
+                break;
+            }
+            if (cc_err != ccNoError) {
+                kerr = KFAILURE;
+                break;
+            }
+            
+            /* version, service, instance, realm check */
+            if ((theCreds -> data -> version == cc_credentials_v4) &&
+                (strcmp (theCreds -> data -> credentials.credentials_v4 -> service, service) == 0) &&
+                (strcmp (theCreds -> data -> credentials.credentials_v4 -> service_instance, instance) == 0) &&
+                (strcmp (theCreds -> data -> credentials.credentials_v4 -> realm, realm) == 0)) {
+                
+                /* Match! */
+                strcpy (creds -> service, service);
+                strcpy (creds -> instance, instance);
+                strcpy (creds -> realm, realm);
+                memmove (creds -> session, theCreds -> data -> credentials.credentials_v4 -> session_key, sizeof (C_Block));
+                creds -> lifetime = theCreds -> data -> credentials.credentials_v4 -> lifetime;
+                creds -> kvno = theCreds -> data -> credentials.credentials_v4 -> kvno;
+                creds -> ticket_st.length = theCreds -> data -> credentials.credentials_v4 -> ticket_size;
+                memmove (creds -> ticket_st.dat, theCreds -> data -> credentials.credentials_v4 -> ticket, creds -> ticket_st.length);
+                creds -> issue_date = theCreds -> data -> credentials.credentials_v4 -> issue_date;
+                strcpy (creds -> pname, theCreds -> data -> credentials.credentials_v4 -> principal);
+                strcpy (creds -> pinst, theCreds -> data -> credentials.credentials_v4 -> principal_instance);
+                creds -> stk_type = theCreds -> data -> credentials.credentials_v4 -> string_to_key_type;
+                
+                cc_credentials_release (theCreds);
+                kerr = KSUCCESS;
+                break;
+            } else  {
+                cc_credentials_release (theCreds);
+            }
+        }
+	}
+    
+    if (iterator != NULL)
+        cc_credentials_iterator_release (iterator);
+    if (ccache != NULL)
+        cc_ccache_release (ccache);    
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+    if (kerr != KSUCCESS)
+        return kerr;
+	if (cc_err != ccNoError)
+		return GC_NOTKT;
+    else
+        return KSUCCESS;
+}
+
+
+/*
+ * Getting name of default credentials cache
+ */
+const char* KRB5_CALLCONV
+tkt_string (void)
+{
+	if (gDefaultCacheName == NULL) {
+        UpdateDefaultCache ();
+    }
+	return gDefaultCacheName;
+}
+
+/*
+ * Synchronize default cache for this process with system default cache
+ */
+ 
+static void
+UpdateDefaultCache (void)
+{
+	cc_string_t 	name;
+    cc_int32		cc_err = ccNoError;
+	cc_context_t	cc_context = NULL;
+    cc_int32		cc_version;
+	
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+    
+    if (cc_err == ccNoError) {
+        cc_err = cc_context_get_default_ccache_name (cc_context, &name);
+	}
+    
+	if (cc_err == ccNoError) {
+		krb_set_tkt_string ((char*) name -> data);
+		cc_string_release (name);
+	}
+    
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+}
+
+/*
+ * Setting name of default credentials cache
+ */
+void
+krb_set_tkt_string (
+	const char*			val)
+{
+	/* If we get called with the return value of tkt_string, we
+	   shouldn't dispose of the input string */
+	if (val != gDefaultCacheName) {
+		if (gDefaultCacheName != NULL)
+			free (gDefaultCacheName);
+			
+		gDefaultCacheName = malloc (strlen (val) + 1);
+		if (gDefaultCacheName != NULL)
+			strcpy (gDefaultCacheName, val);
+	}
+}
+
+/*
+ * Destroy credentials file
+ *
+ * Implementation in dest_tkt.c
+ */
+int KRB5_CALLCONV
+dest_tkt (void)
+{
+	cc_int32		cc_err = ccNoError;
+	cc_context_t	cc_context = NULL;
+    cc_int32		cc_version;
+    cc_ccache_t		ccache = NULL;
+	
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+
+    if (cc_err == ccNoError) {
+        cc_err = cc_context_open_ccache (cc_context, TKT_FILE, &ccache);
+	}
+    
+	if (cc_err == ccNoError) {
+        cc_ccache_destroy (ccache);
+	}
+    
+    if (ccache != NULL)
+        cc_ccache_release (ccache);    
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+	if (cc_err != ccNoError)
+		return RET_TKFIL;
+    else
+        return KSUCCESS;
+}
+
+/*
+ * The following functions are not part of the standard Kerberos v4 API. 
+ * They were created for Mac implementation, and used by admin tools 
+ * such as CNS-Config.
+ */
+ 
+/*
+ * Number of credentials in credentials cache
+ */
+int KRB5_CALLCONV
+krb_get_num_cred (void)
+{
+	cc_credentials_t			theCreds = NULL;
+	int							count = 0;
+	cc_credentials_iterator_t	iterator = NULL;
+    cc_int32					cc_err = ccNoError;
+	cc_context_t				cc_context = NULL;
+    cc_int32					cc_version;
+    cc_ccache_t					ccache = NULL;
+    
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+
+    if (cc_err == ccNoError) {
+        cc_err = cc_context_open_ccache (cc_context, TKT_FILE, &ccache);
+	}
+		
+    if (cc_err == ccNoError) {
+        cc_err = cc_ccache_new_credentials_iterator (ccache, &iterator);
+	}
+	
+    if (cc_err == ccNoError) {
+        for (;;) {
+            /* get next creds */
+            cc_err = cc_credentials_iterator_next (iterator, &theCreds);
+            if (cc_err != ccNoError)
+                break;
+    
+            if (theCreds -> data -> version == cc_credentials_v4) 
+                count++;
+                
+            cc_credentials_release (theCreds);
+        }
+    }
+    
+    if (iterator != NULL)
+        cc_credentials_iterator_release (iterator);
+    if (ccache != NULL)
+        cc_ccache_release (ccache);    
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+	if (cc_err != ccNoError)
+		return 0;
+    else
+        return count;
+}
+
+/*
+ * Retrieval from credentials file
+ * This function is _not_!! well-defined under CCache API, because
+ * there is no guarantee about order of credentials remaining the same.
+ */
+int KRB5_CALLCONV
+krb_get_nth_cred (
+	char*			sname,
+	char*			sinstance,
+	char*			srealm,
+	int				n)
+{
+	cc_credentials_t 			theCreds = NULL;
+	int							count = 0;
+	cc_credentials_iterator_t	iterator = NULL;
+    cc_int32					cc_err = ccNoError;
+	cc_context_t				cc_context = NULL;
+    cc_int32					cc_version;
+    cc_ccache_t					ccache = NULL;
+	
+	if (n < 1)
+		return KFAILURE;
+
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+		
+    if (cc_err == ccNoError) {
+        cc_err = cc_context_open_ccache (cc_context, TKT_FILE, &ccache);
+	}
+		
+    if (cc_err == ccNoError) {   
+        cc_err = cc_ccache_new_credentials_iterator (ccache, &iterator);
+	}
+	
+    if (cc_err == ccNoError) {
+        for (count = 0; count < n;) {
+            /* get next creds */
+            cc_err = cc_credentials_iterator_next (iterator, &theCreds);
+            if (cc_err != ccNoError)
+                break;
+    
+            if (theCreds -> data -> version == cc_credentials_v4) 
+                count++;
+            
+            if (count < n - 1)	
+                cc_credentials_release (theCreds);
+        }
+    }
+    
+    if (cc_err == ccNoError) {
+        strcpy (sname, theCreds -> data -> credentials.credentials_v4 -> service);
+        strcpy (sinstance, theCreds -> data -> credentials.credentials_v4 -> service_instance);
+        strcpy (srealm, theCreds -> data -> credentials.credentials_v4 -> realm);
+	}
+    
+    if (theCreds != NULL)
+        cc_credentials_release (theCreds);
+    if (iterator != NULL)
+        cc_credentials_iterator_release (iterator);
+    if (ccache != NULL)
+        cc_ccache_release (ccache);    
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+	if (cc_err != ccNoError)
+		return KFAILURE;
+    else
+        return KSUCCESS;
+}
+
+/*
+ * Deletion from credentials file
+ */
+int KRB5_CALLCONV
+krb_delete_cred (
+	char*	sname,
+	char*	sinstance,
+	char*	srealm)
+{
+	cc_credentials_t			theCreds = NULL;
+	cc_credentials_iterator_t	iterator = NULL;
+    cc_int32					cc_err = ccNoError;
+	cc_context_t				cc_context = NULL;
+    cc_int32					cc_version;
+    cc_ccache_t					ccache = NULL;
+	
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+
+	if (cc_err == ccNoError) {
+        cc_err = cc_context_open_ccache (cc_context, TKT_FILE, &ccache);
+	}
+		
+	if (cc_err == ccNoError) {
+        cc_err = cc_ccache_new_credentials_iterator (ccache, &iterator);
+	}
+	
+	if (cc_err == ccNoError) {
+        for (;;) {
+            /* get next creds */
+            cc_err = cc_credentials_iterator_next (iterator, &theCreds);
+            if (cc_err != ccNoError) {
+                break;
+            }
+    
+            if ((theCreds -> data -> version == cc_credentials_v4) &&
+                (strcmp (theCreds -> data -> credentials.credentials_v4 -> service, sname) == 0) &&
+                (strcmp (theCreds -> data -> credentials.credentials_v4 -> service_instance, sinstance) == 0) &&
+                (strcmp (theCreds -> data -> credentials.credentials_v4 -> realm, srealm) == 0)) {
+                
+                cc_ccache_remove_credentials (ccache, theCreds);
+                cc_credentials_release (theCreds);
+                break;
+            }
+            
+            cc_credentials_release (theCreds);
+        }
+    }
+    
+    if (iterator != NULL)
+        cc_credentials_iterator_release (iterator);
+    if (ccache != NULL)
+        cc_ccache_release (ccache);    
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+	if (cc_err != ccNoError)
+		return KFAILURE;
+    else
+        return KSUCCESS;    
+}
+
+/*
+ * Destroy all credential caches
+ *
+ * Implementation in memcache.c
+ */
+int KRB5_CALLCONV
+dest_all_tkts (void)
+{
+	int						count = 0;
+	cc_ccache_iterator_t	iterator = NULL;
+    cc_int32				cc_err = ccNoError;
+	cc_context_t			cc_context = NULL;
+    cc_int32				cc_version;
+    cc_ccache_t				ccache = NULL;
+	
+	cc_err = cc_initialize (&cc_context, ccapi_version_3, &cc_version, NULL);
+    
+    if (cc_err == ccNoError) {
+        cc_err = cc_context_new_ccache_iterator (cc_context, &iterator);
+	}
+    
+    if (cc_err == ccNoError) {
+        for (;;) {
+            /* get next ccache */
+            cc_err = cc_ccache_iterator_next (iterator, &ccache);
+            
+            if (cc_err != ccNoError)
+                break;
+            
+            cc_ccache_destroy (ccache);
+            count++;
+        }	
+    }
+    
+    if (iterator != NULL)
+        cc_credentials_iterator_release (iterator);
+    if (cc_context != NULL)
+        cc_context_release (cc_context);
+    
+    if ((cc_err == ccIteratorEnd) && (count == 0)) {
+        /* first time, nothing to destroy */
+        return KFAILURE;
+    } else {
+        if (cc_err == ccIteratorEnd) {
+             /* done */
+            return KSUCCESS;
+        } else {
+            /* error */
+            return KFAILURE;
+        }
+    }
+}
diff --git a/mechglue/src/lib/krb4/ChangeLog b/mechglue/src/lib/krb4/ChangeLog
new file mode 100644
index 000000000..a7e3fbe43
--- /dev/null
+++ b/mechglue/src/lib/krb4/ChangeLog
@@ -0,0 +1,2904 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-05-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* err_txt.c: Don't include krb_err.c if DEPEND is defined.
+
+2004-12-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* RealmsConfig-glue.c (krb_get_krbhst): Check if DNS should be
+	used for getting KDC names before actually using it.
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* macsock.c: Deleted.
+
+2004-07-15  Alexandra Ellwood  <lxs@mit.edu>
+
+	* CCache-glue.c (krb_get_cred) 
+        Removed default principal tracking.
+
+2004-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* recvauth.c (krb_recvauth): Initialize cp and tmp_buf.  Check
+	length of data read before evaluating the value.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* g_pw_in_tkt.c (passwd_to_key): Don't test macintosh.
+	* kadm_net.c (SIGNAL): Don't test macintosh.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (check-mac): Target deleted.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkrb4.exports: New file.
+
+2004-02-26  Jeffrey Altman <jaltman@mit.edu>
+
+    * send_to_kdc.c: modify call to internals.sendto_udp to support
+      the new declaration which contains an additional output parameter
+      which will not be used.
+
+2004-02-24  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* rd_svc_key.c (krb54_get_service_keyblock): Remove ENCTYPE_LOCAL_DES3_HMAC_SHA1
+
+2003-12-11  Sam Hartman  <hartmans@mit.edu>
+
+	* rd_req.c (krb_rd_req_with_key): Note that the expiration difference between krb5 and krb4 is important
+
+2003-08-15  Alexandra Ellwood  <lxs@mit.edu>
+
+        * mk_auth.c: krb_check_auth clears the return value for the 
+        schedule parameter with a memset.  This prevents callers 
+        from using the key schedule, which breaks code.
+
+2003-08-06  Alexandra Ellwood  <lxs@mit.edu>
+
+        * configure.in: Don't assume all darwin boxes are powerpc.
+        (eg: OpenDarwin/x86).
+
+2003-07-11  Alexandra Ellwood  <lxs@mit.edu>
+
+        * RealmsConfig-glue.c: Check for NULL realm argument and n
+        not equal to 1.  Fill in realm with an empty string on error 
+        in case the caller doesn't check the return value.
+
+2003-07-11  Alexandra Ellwood  <lxs@mit.edu>
+
+        * RealmsConfig-glue.c: Don't fail when krb5.conf is valid
+        and krb.conf isn't.  Also, don't assert v4 realm is in profile
+        unless that realm is a valid v4 realm.
+
+2003-07-10  Alexandra Ellwood  <lxs@mit.edu>
+
+        * RealmsConfig-glue.c: krb_get_lrealm fix so that if there is no
+        "v4_realm" tag, krb_get_lrealm doesn't just always return
+        ATHENA.MIT.EDU even though a different realm is specified in
+        krb5.conf and there is a [v4 realm] config
+
+2003-07-07  Alexandra Ellwood  <lxs@mit.edu>
+
+        * RealmsConfig-glue.c: krb_prof_get_nth() no longer assumes that
+        its retlen argument is correct (call strcpy instead of strncpy)
+        because this argument is a guess for some callers 
+        (eg: krb_get_admhst())
+
+2003-06-11  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (KRB_ERR_C): New variable; Darwin needs err_txt.o to
+	have a dependency on krb_err.c so that krb_err.c will be generated
+	first.
+
+	* configure.in: Set KRB_ERR_C to krb_err.c on Darwin.
+
+2003-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* RealmsConfig-glue.c (krb_get_krbhst): Don't fall back to DNS if
+	entries were found in krb.conf, and just not enough to fill the
+	request.
+
+2003-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* RealmsConfig-glue.c: Include k5-int.h.
+	(dnscache): New variable.
+	(DNS_CACHE_TIMEOUT): New macro.
+	(krb_get_krbhst) [KRB5_DNS_LOOKUP]: If no krb.conf info is found,
+	try DNS SRV records for "kerberos-iv".  Cache results in case
+	they're immediately requested again.
+
+2003-06-06  Tom Yu  <tlyu@mit.edu>
+
+	* g_cnffile.c (krb__get_srvtabname): Make retname be a static
+	array rather than a static pointer, to avoid callers' possible
+	retention of free()d pointers.  Yes, this may cause difficulty
+	with making this function thread-safe.
+
+2003-06-04  Tom Yu  <tlyu@mit.edu>
+
+	* password_to_key.c (mit_passwd_to_key, afs_passwd_to_key): Delete
+	spurious space from prompt.
+
+2003-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* RealmsConfig-glue.c (get_krbhst_default): Deleted.
+	(krb_get_krbhst): Don't call it.
+
+2003-06-03  Sam Hartman  <hartmans@mit.edu>
+
+	* g_pw_in_tkt.c (passwd_to_key): Fix password prompt
+
+	* password_to_key.c (mit_passwd_to_key): Fix password prompt
+	(afs_passwd_to_key): Fix password prompt
+
+	* g_in_tkt.c (krb_get_in_tkt_preauth_creds): Keep copy of
+	ciphertext while trying different keyprocs 
+
+2003-06-02  Tom Yu  <tlyu@mit.edu>
+
+	* change_password.c (krb_change_password): Explicitly zero the
+	session key.  Zero the key derived from the new password.
+
+	* mk_req.c (krb_mk_req): Explicitly zero the session key.
+	(krb_mk_req_creds_prealm): Don't zero the session key, in case the
+	caller wants to make use of it.
+
+2003-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* lifetime.c (krb_life_to_time, krb_time_to_life): Rewrite to use
+	support functions in the krb5 library via krb5int_accessor.  Moved
+	old implementation into krb5 library.
+
+2003-05-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add setting of KRB_ERR on Windows.
+
+2003-05-11  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in: Build krb_err.c when appropriate.
+
+	* configure.in: Set KRB_ERR to be the object file generated by
+	krb_err.c on non-Darwin
+
+	* err_txt.c :  Don't include krb_err.c on non-Darwin UNIX.  Doing
+	so may break with some compile_et implementations.  Also not
+	included on Windows.
+
+2003-05-01  Alexandra Ellwood  <lxs@mit.edu>
+ ÊÊ
+    * kadm_stream.c: Fixed vts_long() and vts_short() so they return a
+    pointer to the beginning of the memory they allocate and place 
+    their data at the end of the buffer which was passed in.
+
+2003-04-14  Alexandra Ellwood  <lxs@mit.edu>
+    
+    * g_ad_tkt.c: Added support for login library to get_ad_tkt.
+    Support is copied from Mac Kerberos4 library and conditionalized
+    for USE_LOGIN_LIBRARY to avoid changing get_ad_tkt's behavior for
+    non-Kerberos Login Library builds.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+
+    * CCache-glue.c: Added prototypes for deprecated functions.
+    Made internal functions static.  Removed unused CoreServices
+    include.  Changed TICKET_GRANTING_TICKET to new macro:
+    KRB_TICKET_GRANTING_TICKET.
+    
+    * change_password.c: Added check of inputs to krb_change_password
+    so we don't crash on bad inputs.  Call des_string_to_key not
+    mit_password_to_key on all platforms because we don't want to 
+    prompt for a password.
+    
+    * FSp-glue.c: Added prototypes for deprecated functions.  Changed to
+    use KfM's FSSpecToPOSIXPath which correctly handles FSSpecs where
+    the file does not exist.
+    
+    * g_in_tkt.c: Added explanatory comments.  Made TARGET_OS_MAC sections
+    a little smaller and easier to read.
+    
+    * g_pw_in_tkt.c: Only prompt when we are not using the login library.
+    This is so that Darwin builds do prompt but KfM builds don't.
+    
+    * g_svc_in_tkt.c, g_tkt_svc.c: Changed to use KRB_TICKET_GRANTING_TICKET.
+    
+    * kadm_net.c:  Use autoconf variable krb5_sigtype instead of sigtype, 
+    which doesn't seem to be defined on Mac OS X.
+
+    * krb4int.h, RealmsConfig-glue.c: Removed krb_get_stk().
+    
+    * rd_req.c: Added #ifdef KRB4_USE_KEYTAB to avoid unused variable warning
+    when KRB4_USE_KEYTAB is not defined.
+    
+    * sendauth.c: Fixed warnings with casts. 
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* password_to_key.c (mit_passwd_to_key, afs_passwd_to_key):
+	Comment out pragmas not recognized by gcc or cl.
+
+	* gethostname.c, getst.c, kadm_net.c, klog.c, kparse.c: Include
+	krb5/autoconf.h.
+	* kuserok.c, log.c, memcache.c, mk_preauth.c, netread.c: Ditto.
+	* netwrite.c, put_svc_key.c, recvauth.c, send_to_kdc.c: Ditto.
+	* tkt_string.c: Ditto.
+	* Makefile.in: Update dependencies.
+	(DEFINES): Define KRB4_USE_KEYTAB.
+	* configure.in: Don't define KRB4_USE_KEYTAB.  Don't check for any
+	headers or functions; include/configure.in already does it.  Don't
+	invoke AC_C_CONST explicitly; CONFIG_RULES does that.
+
+2003-03-03  Tom Yu  <tlyu@mit.edu>
+
+	* g_cnffile.c (krb__get_srvtabname): Keep strdup()ed string in a
+	static variable and free it called again; this prevents a memory
+	leak.
+
+2003-02-28  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (clean-unix): Remove krb_err_txt.c on clean. Update
+	dependencies
+
+	* g_pw_in_tkt.c: Include krb4int.h for krb_get_keyprocs() prototype.
+
+2003-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* in_tkt.c: Include k5-util.h.
+	(do_seteuid): Define as krb5_seteuid instead of testing system
+	characteristics here.
+	* dest_tkt.c: Likewise.
+
+	* change_password.c (krb_change_password): Use int, not KRB_INT32,
+	for krb4 error codes.  Check for malloc failure allocating
+	sendStream.
+
+2003-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Update dependencies.
+	(KRB_ERR_TXT): Set by configure to be either empty
+	(on Darwin) or krb_err_txt.c (on other platforms).  This avoids
+	building krb_err_txt.c on Darwin, as the type of krb_err_txt is a
+	pointer there, so we don't need another copy of the array.
+	(DEFINES): Remove.  It wasn't doing anything useful and was
+	cluttering up the compile command line.
+
+	* configure.in: On Darwin, don't use krb_err_txt.c.
+
+	* err_txt.c: On Darwin, actually use the array generated by
+	compile_et, and assign it to krb_err_txt, which is a pointer, not
+	an array, on that platform.
+
+2003-02-11  Tom Yu  <tlyu@mit.edu>
+
+	* CCache-glue.c: Delete in_tkt().
+
+	* change_password.c: Fix incorrect filename in comment.
+
+	* g_in_tkt.c (krb_get_in_tkt_preauth): Call krb_in_tkt() rather
+	than in_tkt().
+
+	* CCache-glue.c (krb_in_tkt): Rename from in_tkt().
+	(in_tkt): Implement in terms of krb_in_tkt() to match existing
+	Unix and Windows API.  This shouldn't be a problem because it
+	appears to be considered an internal API on Mac.
+
+2003-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* password_to_key.c (krb5_passwd_to_key): Replace snprintf() call
+	with explicit length checking.
+
+	* memcache.c (krb4int_save_credentials_addr): Renamed from
+	krb_save_credentials().
+	(krb_save_credentials): Implement in terms of
+	krb4int_save_credentials_addr().
+
+	* password_to_key.c (mit_passwd_to_key, krb5_passwd_to_key) 
+	(afs_passwd_to_key): Fix to have KRB5_CALLCONV.
+
+	* krb4int.h (mit_passwd_to_key, krb5_passwd_to_key):
+	(afs_passwd_to_key): Fix prototypes to have KRB5_CALLCONV.
+
+	* CCache-glue.c (krb4int_save_credentials_addr): Renamed from
+	krb_save_credentials().
+	(krb_save_credentials): Implement in terms of
+	krb4int_save_credentials_addr().
+
+	* Makefile.in (SRCS, OBJS): Add password_to_key.
+
+	* g_ad_tkt.c (get_ad_tkt): Call krb4int_send_to_kdc_addr() instead
+	of send_to_kdc().  Call krb4int_save_credentials_addr() instead of
+	krb_save_credentials().  These changes deal with Mac-specific
+	storage of the local address without introducing more
+	conditionally compiled code.
+
+	* g_in_tkt.c: Fix to minimize Mac-specific code.  Basically, pass
+	around local address in lots of places.  There is still a
+	Mac-specific difference involving krb_get_in_tkt_creds().
+
+	* krb4int.h: Include port-sockets.h to get some socket stuff for
+	some prototypes.  Update prototype for
+	krb_get_in_tkt_preauth_creds().  Add prototypes for
+	krb4int_save_credentials_addr() and krb4int_send_to_kdc_addr().
+
+	* password_to_key.c (krb_get_keyprocs): Fix typo.
+	(mit_passwd_to_key, krb5_passwd_to_key): mit_string_to_key ->
+	des_string_to_key.
+
+	* save_creds.c (krb_save_credentials): Re-implement in terms of
+	krb4itn_save_credentials_addr(), which is what library internals
+	will call.
+	(krb4int_save_credentials_addr): Renamed from
+	krb_save_credentials.
+
+	* tkt_string.c (krb_set_tkt_string): Fix to take const char *.
+
+2003-02-10  Alexandra Ellwood <lxs@mit.edu>
+    Note: these checkins are partial progress for Tom Yu.
+    They probably don't build; Tom is expecting that.
+
+    * CCache-glue.c: Removed copying of the string_to_key type in
+    krb_save_credentials.  Saving the string_to_key type is unnecessary
+    and was just for display purposes.  Will be removed for KfM 5.0.
+    Updated to use KRB5_CALLCONV instead of INTERFACE and include the
+    krb5's krb4 headers instead of the KfM ones.
+
+    * change-password.c: Removed include of CredentialsCache.h and
+    code that switches between string to key types.  This doesn't make
+    sense for password changing because the krb4 protocol for password
+    changing implemented here only supports mit's string to key.  Bug 
+    was in KfM and got ported forward.  Should the code call 
+    mit_password_to_key for all platforms?  
+    
+    * FSp-glue.c: Removed dependency on MoreFiles and replaced it with
+    code to use FSRefs now that we are Carbon-only.
+    
+    * g_in_tkt.c: Added loop which calls password to key functions 
+    trying each one.  This technique was imported from KTH-KRB into 
+    KfM.  This code still needs to have the TARGET_OS_MAC code made more
+    Unix friendly for Darwin builds.  The behavior differences (store
+    the address or not) should be deferred until the very last moment to
+    avoid excessive #ifdefs.
+
+    * g_pw_in_tkt.c: Added loop which calls password to key functions 
+    trying each one.  This technique was imported from KTH-KRB into KfM.
+    
+    * krb4int.h: Added password-to-key.c functions so they can be used by
+    g_in_tkt.c and g_pw_in_tkt.c.
+    
+    * password-to-key.c: Removed dependence on the CCAPI so this code can
+    be used on all platforms to implement looping over the password to
+    key functions.
+    
+    * RealmsConfig-glue.c: Changed to use #ifdef USE_CCAPI like is used 
+    elsewhere in the krb5 sources.  This is just for consistency in krb5.
+
+2003-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add rules to generate krb_err_txt.c.
+
+	* err_txt.c: Include two copies of the error table, one generated
+	by com_err, and one generated by a special-purpose awk script.
+
+	* et_errtxt.awk: New file; used to generate krb_err_txt.c
+
+2003-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* decomp_tkt.c (dcmp_tkt_int): Patch from Booker Bense to use
+	krb_get_lrealm() instead of copying KRB_REALM into prealm.
+
+2003-01-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* RealmsConfig-glue.c (get_krbhst_default, krb_get_krbhst):
+	(krb_realmofhost): Use strcpy instead of strncpy.
+
+2003-01-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* RealmsConfig-glue.c (krb_get_admhst): Use strcpy instead of
+	strncpy, and max length of MAX_HSTNM.
+
+2003-01-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendauth.c (krb_net_rd_sendauth): Arg raw_len now points to
+	KRB4_32; don't cast it to pointer to unsigned long.  Change ld.so
+	warning message check to be byte-order independent.
+	* krb4int.h (krb_net_rd_sendauth): Decl updated.
+
+2003-01-15  Tom Yu  <tlyu@mit.edu>
+
+	* CCache-glue.c: New file from KfM.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_ARCHIVE,
+	AC_PROG_ARCHIVE_ADD, AC_PROG_RANLIB, AC_PROG_INSTALL.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* tf_util.c: Remove declaration of errno
+
+	* dest_tkt.c (dest_tkt): Remove declaration of errno
+
+2002-12-18  Tom Yu  <tlyu@mit.edu>
+
+	* RealmsConfig-glue.c: Fix up KRB5_CALLCONV.
+
+	* win_store.c (krb__get_srvtabname): Add const to parameter.
+
+2002-12-16  Tom Yu  <tlyu@mit.edu>
+
+	* tkt_string.c (krb5_set_tkt_string): Add KRB5_CALLCONV.
+
+	* win_glue.c (krb_set_tkt_string): Add KRB5_CALLCONV.
+
+2002-12-13  Tom Yu  <tlyu@mit.edu>
+
+	* ad_print.c, g_in_tkt.c, g_pw_in_tkt.c, kadm_net.c, klog.c:
+	* kuserok.c, log.c, memcache.c, netread.c, netwrite.c:
+	* password_to_key.c, recvauth.c, stime.c, tkt_string.c: 
+	Change _WINDOWS to _WIN32 in many places.  Update copyright
+	notices.  Remove _WINDOWS handling completely in a few places
+	where it's not needed.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* FSp-glue.c: Extracted and ported from various files from KfM.
+	Not built on Unix.
+
+	* Makefile.in: Removed srcdir references from various SRCS
+	variables.  Stop building krb_err.o because of gross hack in
+	err_txt.c.  Adjust some dependency generation things.
+	(REALMDBOBJS): Use RealmsConfig-glue instead of lots of other
+	files.
+	(LOCALINCLUDES): Use current directory, so we can pick up
+	krb_err.c as an include file.
+
+	* RealmsConfig-glue.c: Ported from KfM and cleaned up.  Old
+	REALMDBSRCS inlined here too.
+
+	* g_admhst.c, g_in_tkt.c, g_krbhst.c, g_krbrlm.c, realmofhost.c:
+	Removed.  Functionality is now in RealmsConfig-glue.c.
+
+	* g_in_tkt.c (krb_get_in_tkt_creds): Add KRB5_CALLCONV.
+
+	* dest_tkt.c (dest_tkt): TKT_FILE now assigned to a const char *,
+	due to change in tkt_string() return type.
+
+	* err_txt.c: Much grossness.  Suck in krb_err.c here, so we can
+	use the static array to initialize the krb_err_txt array.
+
+	* g_in_tkt.c: Call krb4int_send_to_kdc_addr() on MacOS.
+
+	* g_svc_in_tkt.c: Fix up copyright notice; punt gratuitous
+	definition of NULL.
+
+	* g_tf_fname.c (krb_get_tf_fullname): Takes a const char * for
+	ticket file name now, due to change in tkt_string() return type.
+
+	* g_tf_realm.c (krb_get_tf_realm): Takes a const char * for ticket
+	file name now, due to change in tkt_string() return type.
+
+	* in_tkt.c: Include errno.h.
+	(in_tkt): TKT_FILE now assigned to a const char *, due to change
+	in tkt_string() return type.
+
+	* krb4int.h: Add prototype for krb_get_in_tkt_preauth_creds().
+	Fix _WINDOWS->_WIN32.
+
+	* krb_err.et: Sync somewhat with old contents of err_txt.c.
+
+	* tf_util.c (tf_init): Takes const char *tf_name now.
+
+2002-12-06  Tom Yu  <tlyu@mit.edu>
+
+	* g_ad_tkt.c (get_ad_tkt): Add KRB5_CALLCONV.
+
+	* g_in_tkt.c (krb_get_in_tkt_preauth): Add KRB5_CALLCONV.
+	(krb_get_in_tkt): Add KRB5_CALLCONV.
+
+	* send_to_kdc.c (krb4int_send_to_kdc_addr): New function; does
+	what send_to_kdc() used to do but can also return local address.
+
+2002-12-05  Tom Yu  <tlyu@mit.edu>
+
+	* kname_parse.c (kname_unparse): Add new function ported from
+	KfM, including support functions.
+
+	* decomp_tkt.c (decomp_ticket): Add KRB5_CALLCONV.
+
+2002-12-04  Tom Yu  <tlyu@mit.edu>
+
+	* krb4int.h: Remove now conflicting prototype for
+	krb_set_lifetime().
+
+	* Makefile.in: Fix up includes handling somewhat.
+
+2002-12-02  Tom Yu  <tlyu@mit.edu>
+
+	* change_password.c: Remove netdb.h inclusion.
+
+2002-11-27  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SRCS): Add kadm_err.c.  It was missing.
+
+2002-11-26  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (OBJS, SRCS): Add change_password.c, kadm_err.c,
+	kadm_net.c, kadm_stream.c.  Remove one.c.
+	Also, add com_err support for kadm_err.et.  Update dependencies.
+
+	* change_password.c: New file.
+
+	* configure.in: Remove checks for BITS16, BITS32, MSBFIRST, and
+	LSBFIRST.
+
+	* g_in_tkt.c (krb_mk_in_tkt_preauth): Update to optionally return
+	local address --  not yet fully implemented.
+	(krb_parse_in_tkt_creds): Renamed from krb_parse_in_tkt().  Now
+	fills in a CREDENTIALS instead of storing into a ticket file.
+	(krb_get_in_tkt_preauth_creds): Renamed from
+	krb_get_in_tkt_preauth().  Now fills in a CREDENTIALS instead of
+	storing into a ticket file.
+	(krb_get_in_tkt_creds): Port from KfM.
+	(krb_get_in_tkt_preauth): Reimplement in terms of
+	krb_get_in_tkt_creds_preauth().
+
+	* g_pw_in_tkt.c (krb_get_pw_in_tkt_creds): Port from KfM.
+
+	* kadm_err.et:
+	* kadm_net.c:
+	* kadm_stream.c: New files to implement password changing, ported
+	from KfM.
+
+	* mk_req.c (krb_mk_req_creds_prealm): New internal function --
+	similar to krb_mk_req_creds() but takes the client's realm, since
+	it's needed for forming a correct request but is not present in a
+	CREDENTIALS.
+	(krb_mk_req): Reimplement in terms of krb_mk_req_creds_prealm().
+	Move the logic for acquiring credentials and determining client's
+	realm here.
+	(krb_mk_req_creds): Port from KfM.
+	(krb_set_lifetime): Make KRB5_CALLCONV now.
+
+	* one.c: Remove.
+
+	* password_to_key.c: New file, ported from KfM.  Will eventually
+	implement some string-to-key stuff.
+
+	* prot_client.c: Eliminate references to {LSB,MSB}_FIRST.
+
+	* prot_kdc.c: Eliminate references to {LSB,MSB}_FIRST.
+
+	* rd_req.c (krb_rd_req_with_key): New internal function -- can
+	take a key schedule or a krb5_keyblock and use one of those to
+	decrypt the ticket.
+	(krb_rd_req_int): Ported from KfM.  Calls into
+	krb_rd_req_with_key().
+	(krb_rd_req): Reimplement in terms of krb_rd_req_with_key().  Copy
+	some of the realm and kvno reading logic here.
+
+	* tkt_string.c: Returns pointer to const now.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* cr_tkt.c (krb_cr_tkt_int): Don't take key arguments any more.
+	(krb_create_ticket, krb_cr_tkt_krb5): Do the encryption here; drop
+	NOENCRYPTION test.
+
+2002-07-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* log.c: Include stdarg.h.
+	(krb_log): Use va_ macros and vfprintf instead of a bunch of
+	pointer arguments.
+	* krb4int.h (krb_log): Declaration updated.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* ad_print.c, g_phost.c, g_tkt_svc.c, gethostname.c, mac_glue.c,
+	mac_stubs.c, mac_time.c, mk_auth.c, mk_priv.c, mk_req.c,
+	mk_safe.c, netread.c, netwrite.c, rd_priv.c, rd_safe.c,
+	realmofhost.c, recvauth.c, send_to_kdc.c, sendauth.c, stime.c,
+	win_glue.c: Don't define DEFINE_SOCKADDR.
+
+	* mac_time.c, stime.c: Don't define NEED_TIME_H; instead, include
+	time.h and sys/time.h when _WINDOWS isn't defined, which is what
+	krb.h used to do for NEED_TIME_H.
+
+	* ad_print.c, cr_tkt.c, decomp_tkt.c, g_krbhst.c, g_phost.c,
+	g_tkt_svc.c, mk_priv.c, mk_safe.c, netread.c, netwrite.c,
+	prot_kdc.c, rd_priv.c, rd_safe.c, realmofhost.c, recvauth.c,
+	send_to_kdc.c, sendauth.c, tkt_string.c: Include port-sockets.h.
+
+2002-06-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* mk_priv.c (krb4int_address_less): Put braces around v4mapped
+	address processing to permit local variable declaration.  Pass
+	correct value to IN6_IS_ADDR_V4MAPPED.
+
+2002-05-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* DNR.c: Deleted.
+
+2002-03-11  Ken Raeburn  <raeburn@mit.edu>
+
+	Handle IPv6 sockets that are used to communicate over IPv4, and
+	permit use of non-IPv4 addresses if address checking is turned
+	off:
+	* mk_priv.c (krb4int_address_less): New function.  Compares IPv4
+	addresses for ordering, but also handles the IPv6 v4-mapped form.
+	(krb_mk_priv): Use krb4int_address_less.  Handle sender/receiver
+	addresses that are IPv6 v4-mapped like IPv4 addresses, or store
+	zero for other addresses.
+	* mk_safe.c (krb_mk_safe): Use krb4int_address_less.  Handle
+	sender/receiver addresses that are IPv6 v4-mapped like IPv4
+	addresses, or store zero for other addresses.
+	* rd_priv.c (krb_rd_priv): Use krb4int_address_less.  Deal with
+	socket addresses that are v4-mapped IPv6 addresses.
+	* rd_safe.c (krb_rd_safe): Use krb4int_address_less.  Deal with
+	socket addresses that are v4-mapped IPv6 addresses.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* cr_tkt.c, decomp_tkt.c, g_in_tkt.c, tf_util.c: Make prototypes
+	unconditional.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* dest_tkt.c, err_txt.c, g_admhst.c, g_cred.c, g_krbhst.c,
+	g_krbrlm.c, g_phost.c, g_pw_in_tkt.c, g_pw_tkt.c, g_svc_in_tkt.c,
+	g_tf_fname.c, g_tf_realm.c, g_tkt_svc.c, in_tkt.c, kname_parse.c,
+	kuserok.c, lifetime.c, memcache.c, mk_auth.c, mk_err.c, mk_priv.c,
+	mk_req.c, mk_safe.c, put_svc_key.c, rd_err.c, rd_priv.c, rd_req.c,
+	rd_safe.c, rd_svc_key.c, realmofhost.c, recvauth.c, save_creds.c,
+	send_to_kdc.c, sendauth.c, tf_util.c, unix_time.c, win_glue.c,
+	win_store.c: Don't use KRB5_DLLIMP.  Don't explicitly declare
+	pointers FAR any more.
+
+2001-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): Renamed from DEFINES.  Add
+	build-tree version of kerberosIV include directory.
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* fgetst.c: Include krb4int.h.
+
+	* krb4int.h: Add fgetst prototype.
+
+2001-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb4int.h: Provide prototype for krb_get_default_user and
+	krb_set_default_user if _WINDOWS is not defined. There is a
+	conditional prototype in krb.h for them.
+
+2001-06-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb4int.h: Add prototypes for ad_print, krb_svc_init,
+	krb_svc_init_preauth, krb_get_svc_in_tkt_preauth, kset_logfile,
+	krb_log, krb_set_logfile, krb_set_lifetime, month_sname,
+	krb_rd_preauth, krb_net_rd_preauth, krb_net_rd_sendauth,
+	krb_stime, krb_start_session, krb_end_session,
+	krb_get_default_user, krb_set_default_user.
+
+	* ad_print.c, g_svc_in_tkt.c, klog.c, log.c, mk_req.c,
+ 	month_sname.c, rd_preauth.c, sendauth.c, stime.c, unix_glue.c:
+ 	Include krb4int.h for prototypes.
+
+	* decomp_tkt.c: Include krb54proto.h for decomp_tkt_krb5() prototype.
+
+2001-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb4int.h: Add prototypes for krb__get_realmsfile(),
+	krb5 prototypes are declarted from krb.hkrb__get_cnffile() and
+	krb5 prototypes are declarted from krb.hk_gethostname(). 
+
+	* g_pw_in_tkt.c: Declare passwd_to_key() static.
+
+	* cr_tkt.c: Move krb5.h inclusion before krb.h so that certain
+	krb5 prototypes are declarted from krb.h.
+
+	* g_admhost.c, g_cnffile.c, g_krbhst.c, g_krbrlm.c, gethostname.c
+	krb5 prototypes are declarted from krb.hrealmofhost.c: 
+	Include krb4int.h and remove prototypes included in there.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* kname_parse.c (k_isrealm, k_isname, k_isrealm): Add
+	KRB5_DLLIMP/KRB5_CALLCONV definitions for function with exported
+	prototype in krb.h.
+
+	* g_cnffile.c (krb__get_srvtabname, krb__v5_get_file): Declare
+	argument as const.
+
+	* g_svc_in_tkt.c, put_svc_key.c, rd_req.c, rd_svc_key.c: Get rid
+	of krb__get_srvtabname() prototype - in krb.h now.
+
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* kparse.c (strutol): Cast argument to isupper()/tolower() to int.
+	* realmofhost.c (krb_realmofhost): Likewise.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* g_pw_in_tkt.c: Include krb5.h so that des_read_password()
+	prototype is present in des.h. Cast argument to des_read_password.
+
+	* getst.c, put_svc_key.c, rd_svc_key.c, save_creds.c, tf_util.c:
+	Include krb4int.h for prototypes.
+
+	* krb4int.h: New file containing private prototypes for krb4
+	functions not used outside the library. Contains getst() and
+	tf_save_cred().
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* sendauth.c (krb_sendauth): Add KRB5_DLLIMP/KRB5_CALLCONV definitions
+	for function with exported prototype in krb.h
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* cr_tkt.c (krb_create_ticket): Get rid of last argument (k5key)
+	which was added erroneously and is not how code is used in tree.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* ad_print.c (ad_print): Cast arguments to printf() to longs to
+	match format string.
+
+2001-06-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* g_krbrlm.c: Remove unused static variable krb_conf. 
+
+	* g_svc_in_tkt.c (krb_svc_init, krb_svc_init_preauth): Declare as
+	returning int.
+
+	* gethostname.c: Include unistd.h for gethostname() prototype.
+
+	* getst.c: Include unistd.h for read() prototype.
+
+	* in_tkt.c (in_tkt): Cast arguments to debugging printf to int
+	from uid_t to match format statement. 
+
+	* kname_parse.c: Declare k_isname() and k_isinst() as returning
+	int. Cleanup assigments in conditionals.
+
+	* kuserok.c (kuserok): Cleanup assignment in conditional.
+
+	* log.c (krb_set_logfile): Declare function as void. 
+	* klog.c (kset_logfile): Likewise.
+
+	* pkt_clen.c (pkt_clen): Declare as returning int.
+	* kntoln.c (krb_kntoln): Likewise.
+	* fgetst.c (fgetst): Likewise.
+
+	* rd_req.c: Declare local variable only if KRB_CRYPT_DEBUG defined. 
+
+	* recvauth.c: Include stdlib.h and unistd.h for read() and atoi()
+	prototypes.
+
+	* send_to_kdc.c: Include unistd.h for close() prototype.
+
+	* sendauth.c (krb_sendauth): Clean up assignment in conditional.
+
+	* tkt_string.c (tkt_string): Likewise
+
+2001-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (EHDRDIR): Install into kerberosIV subdirectory.
+
+	* ad_print.c (ad_print): Pass address of session key to
+	des_cblock_print_file, not the session key.
+
+	* g_tkt_svc.c (CredIsExpired): Don't use a variable named "time".
+
+2001-04-13  Danilo Almeida  <dalmeida@mit.edu>
+
+	* memcache.h: Don't use macro PROTOTYPE.
+
+2001-04-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* cr_err_repl.c (req_act_vno): Delete commented-out declaration.
+
+	* kparse.c, send_to_kdc.c: Don't use macro PROTOTYPE.
+
+2001-01-29  Tom Yu  <tlyu@mit.edu>
+
+	* lifetime.c: Remove support for "magic" lifetime value of 255.
+
+2001-01-26  Tom Yu  <tlyu@mit.edu>
+
+	* dest_tkt.c: Clean up uid handling.  Fix stat checks.
+
+	* in_tkt.c: Clean up uid handling.  Fix stat checks.
+
+	* tf_util.c: Clean up uid handling.  Fix stat checks.
+
+2001-01-25  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (OBJS, SRCS): Add prot_client.o, prot_client.c.
+
+	* prot_client.c: New file; client-side protocol support.
+
+	* prot_common.c (krb4prot_decode_header): Decode the first two
+	bytes of a krb4 packet.
+
+2001-01-24  Tom Yu  <tlyu@mit.edu>
+
+	* prot_common.c: Fix up some error returns.
+
+	* prot_kdc.c: Fix up some error returns.  Add
+	decode_kdc_request().
+
+2001-01-23  Tom Yu  <tlyu@mit.edu>
+
+	* prot_common.c: New file; contains functions to encode/decode
+	string triples for principals.
+
+	* prot_kdc.c: New file; contains encoders and decoders
+	(eventually) for the KDC's use.
+
+	* Makefile.in (OBJS, SRCS): Add prot_common.o, prot_kdc.o.
+
+	* cr_auth_repl.c: KRB4_PUT{16,32} -> KRB4_PUT{16,32}BE.
+
+	* cr_ciph.c: Include prot.h.  KRB4_PUT32 -> KRB4_PUT32BE.
+
+	* cr_err_repl.c: KRB4_PUT32 -> KRB4_PUT32BE.
+
+	* cr_tkt.c: KRB4_PUT32 -> KRB4_PUT32BE.
+
+	* decomp_tkt.c: krb_strnlen -> krb4int_strnlen.
+
+	* g_ad_tkt.c: krb_strnlen -> krb4int_strnlen.  KRB4_PUT32 ->
+	KRB4_PUT32BE.  Properly skip date while parsing error.
+
+	* g_in_tkt.c: krb_strnlen -> krb4int_strnlen.  KRB4_PUT32 ->
+	KRB4_PUT32BE.  Properly skip date while parsing error.
+
+	* g_phost.c: Changes from audit.  Actually bail out instead of
+	failing silently if h->h_name is too long.
+
+	* kname_parse.c: Changes from audit.  Check overrun per character
+	processed.
+
+	* mk_auth.c: krb_strnlen -> krb4int_strnlen.  KRB4_PUT32 ->
+	KRB4_PUT32BE.  Include prot.h.
+
+	* mk_err.c: KRB4_PUT32 -> KRB4_PUT32BE.
+
+	* mk_priv.c: KRB4_PUT32 -> KRB4_PUT32BE.
+
+	* mk_req.c: KRB4_PUT32 -> KRB4_PUT32BE.
+
+	* mk_safe.c: KRB4_PUT32 -> KRB4_PUT32BE.
+
+	* rd_req.c: krb_strnlen -> krb4int_strnlen.
+
+	* strnlen.c: Rename to krb4int_strnlen.  Also include prot.h,
+	which is where strnlen is declared now.
+
+2001-01-18  Tom Yu  <tlyu@mit.edu>
+
+	* g_ad_tkt.c: Fix error packet parsing.
+
+	* g_in_tkt.c: Fix error packet parsing.  Also, declare some
+	internal functions as static and add prototypes.
+
+2000-11-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* strnlen.c (krb_strnlen): Put The return type before the calling
+	convention.
+
+2000-11-08  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (OBJS, SRCS): Add strnlen.o, strnlen.c.
+
+	* cr_auth_repl.c: Audit.  Fix up copyright.  Use new KRB4_PUT*
+	macros for encoding so output is always big-endian.  Precompute
+	string lengths for better length-checking.
+
+	* cr_ciph.c: Audit.  Fix up copyright.  Use new KRB4_PUT* macros
+	for encoding so that output is always big-endian.  Precompute
+	string lengths for better length-checking.  Zero out the key
+	schedule after encrypting.
+
+	* cr_death_pkt.c: Audit.  Fix up copyright.  Precompute string
+	lengths for better length-checking.
+
+	* cr_err_repl.c: Audit.  Fix up copyright.  Use moving pointer to
+	do encoding.  Precompute string lengths for better
+	length-checking.  Use KRB4_PUT* macros so that output is always
+	big-endian.
+
+	* cr_tkt.c: Audit.  Fix up copyright.  Use KRB4_PUT* macros for
+	encoding so that output is always big-endian.  Zero out the key
+	schedule after encrypting.
+
+	* decomp_tkt.c: Audit.  Fix up copyright.  Use krb_strnlen() for
+	actually detecting string length errors.  Use a struct in_addr to
+	retrieve the IP address and assign it to paddress for return.  Use
+	KRB4_GET* macros for decoding to avoid byteswapping problems.
+	Zero out session key and decrypted ticket on error.
+
+	* g_ad_tkt.c: Audit.  Fix up copyright.  Break out parsing of
+	decrypted KDC reply packet into a separate function to simplify
+	error handling somewhat.  Precompute string lengths for better
+	length-checking.  Use KRB4_PUT* macros for encoding so that output
+	is always big-endian.  Use KRB4_GET* macros for decoding to avoid
+	byteswapping problems.  Stomp on session key on error conditions.
+
+	* g_in_tkt.c: Audit.  Fix up copyright.  Precompute string lengths
+	for better length-checking.  Use KRB4_PUT* macros for encoding so
+	output is always big-endian.  Use KRB4_GET* macros for decoding to
+	avoid byteswapping problems.  Use krb_strnlen() to actually detect
+	string length errors.  Zero out session key and decrypted KDC
+	reply once they're no longer useful.
+
+	* mk_auth.c: Audit.  Fix up copyright.  Use moving pointer for
+	encoding.  Use KRB4_PUT* macros for encoding to avoid alignment
+	issues with using memcpy().  Use KRB4_GET* macros for decoding to
+	avoid alignment issues with using memcpy().
+
+	* mk_err.c: Audit.  Fix up copyright.  Precompute string length.
+	Use KRB4_PUT* macros to always encode as big-endian.
+
+	* mk_preauth.c: Audit.  Zero out key schedule after encryption.
+
+	* mk_priv.c: Audit.  Fix up copyright.  Use KRB4_PUT* macros for
+	encoding so output is always big-endian.
+
+	* mk_req.c: Audit.  Fix up copyright.  Use moving pointer for
+	encoding.  Precompute string lengths for better length-checking.
+	Use KRB4_PUT* macros for encoding so output is always big-endian.
+	Zero out session key after encryption.
+
+	* mk_safe.c: Audit.  Fix up copyright.  Use KRB4_PUT* macros for
+	encoding so output is always big-endian.
+
+	* rd_err.c: Audit.  Fix up copyright.  Use KRB4_GET* macros to
+	avoid alignment issues.
+
+	* rd_preauth.c: Audit.  Zero key schedule after decrypting.
+
+	* rd_priv.c: Audit.  Fix up copyright.  Use KRB4_GET* macros to
+	avoid alignment issues.
+
+	* rd_req.c: Audit.  Fix up copyright.
+
+	* send_to_kdc.c (send_recv): Actually set rpkt->length, since some
+	callers actually use it now to do length-checking.
+
+	* strnlen.c: New file; compute string length, bounded by a
+	maximum.  If the maximum number of characters has been read
+	without encountering a NUL character, return -1.  This makes
+	overflow checking of strings in buffers much easier.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_C_CONST and AC_CHECK_FUNCS instead of
+	AC_CONST and AC_HAVE_FUNCS.
+
+2000-10-23  Tom Yu  <tlyu@mit.edu>
+
+	* mk_auth.c (krb_check_auth): Modify call to rd_priv() by kludging
+	a cast of session key to C_Block *, since CNS is inconsistent in
+	this area as well.
+
+	* mk_priv.c (krb_mk_priv): Align with CNS by taking C_Block *.
+
+	* mk_safe.c (krb_mk_safe): Align with CNS by taking C_Block *.
+
+	* rd_priv.c (krb_rd_priv): Align with CNS by taking C_Block *.
+
+	* rd_safe.c (krb_rd_safe): Align with CNS by taking C_Block *.
+
+	* recvauth.c (krb_recvauth): Update call to mk_priv() to have the
+	correct type.
+
+Tue Oct 10 05:03:50 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* kparse.c: Provide prototype for static struol(). Do not define
+ 	void as int (autoconf can handle that). 
+
+2000-10-07  Tom Yu  <tlyu@mit.edu>
+
+	* g_tkt_svc.c (CredIsExpired): Fix logic bug.
+
+2000-10-06  Tom Yu  <tlyu@mit.edu>
+
+	* rd_req.c (krb_rd_req): Call life_to_fime().
+
+	* g_tkt_svc.c (CredIsExpired): Call life_to_time().
+
+	* lifetime.c: Add comments for lifetimes[].  Add provisions for
+	compile-time switching of short lifetimes.  Fix sign bug in
+	time_to_life().
+
+2000-10-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* netread.c, netwrite.c: Include unistd.h if present on machine
+	for read/write prototypes.
+
+	* in_tkt.c: Argument to umask should be of type mode_t.
+
+	* configure.in: Test for uid_t (AC_TYPE_UID_T) and mode_t
+	(AC_TYPE_MODE_T). 
+	
+
+2000-08-31  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in(OBJS, SRCS): Add lifetime.{o,c}.
+
+	* lifetime.c: New file.  For the purposes of CMU and AFS
+	compatibility, this implements the exponential krb4 ticket
+	lifetimes for lifetime values above 127, in the krb_life_to_time()
+	and krb_time_to_life() functions.  Values 127 and below are still
+	treated normally.
+
+Tue Aug 22 09:56:14 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* rd_svc_key.c (krb54_get_service_keyblock): If the keytab
+ 	encryption type is a non-raw des3 key, bash its enctype. This
+ 	matches kdc/kerberos_v4.c.
+
+Mon Aug 14 12:13:20 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* cr_tkt.c (krb_cr_tkt_int): When prototypes were changed to not
+ 	include a narrow prototype, the flags were being sent OTW as four
+ 	bytes instead of one.
+
+2000-08-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* tf_util.c (tf_init): Add KRB5_DLLIMP/KRB5_CALLCONV definitions
+	for functions exported prototypes in krb.h.
+
+2000-07-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* g_pw_tkt.c, unix_time.c: Add KRB5_DLLIMP/KRB5_CALLCONV defintion.
+
+Thu Jun 29 17:13:53 2000  Ezra Peisach  <epeisach@home>
+
+	* getst.c: Include <unistd.h> for read() prototype.
+
+	* gethostname.c: Include <unistd.h> (if present) for gethostname()
+	prototype.
+
+	* g_pw_tkt.c (get_pw_tkt): Declare function returning as int.
+
+	* g_ad_tkt.c, g_in_tkt.c, g_tkt_svc: Add parenthesis about
+ 	assignment used as truth value.
+
+	* cr_ciph.c (create_ciph): Declare as returning int.
+
+2000-07-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* memcache.c: Add krb_in_tkt() function to initialize ticket for a
+	given principal.  It is like in_tkt() but it is public and also
+	takes a realm for credentials caches that require a full
+	principal name (e.g., CCAPI).
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* in_tkt.c: Add krb_in_tkt() function to initialize ticket for a
+	given principal.  It is like in_tkt() but it is public and also
+	takes a realm for credentials caches that require a full
+	principal name (e.g., CCAPI).
+
+2000-07-03  Tom Yu  <tlyu@mit.edu>
+
+	* cr_tkt.c: Frob prototypes so they don't involve narrow types.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* cr_tkt.c: Provide prototype for static krb_cr_tkt_int function
+	before being used.
+
+	* getst.c: Remove unused variable.
+
+2000-06-09  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Check for strdup().
+
+	* kparse.c: Remove strsave() and replace with an inlined static
+	version of strdup() if HAVE_STRDUP is not defined.
+
+	* g_ad_tkt.c (get_ad_tkt): ptr may be signed; cast while
+	assigning to larger types.  [from Charles Hannum by way of
+	ghudson]
+
+2000-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* decomp_tkt.c (dcmp_tkt_int): Add a couple more length checks.
+	Reject names that are exactly ANAME_SZ (etc) bytes long without
+	the trailing nul, because krb.h says the *_SZ macros are "maximum
+	sizes ... +1".
+	* mk_auth.c (krb_mk_auth): Force nul termination of inst.
+	* sendauth.c (krb_sendauth): Force nul termination of srv_inst.
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* Password.c (GetUserInfo): Truncate user name if it's too long
+	to fit.
+	* cr_auth_repl.c (cr_auth_reply): Bail if the reply packet won't
+	fit into its buffer.
+	* cr_ciph.c (create_ciph): Ditto.
+	* cr_death_pkt.c (krb_create_death_packet): Truncate "aname" to
+	make it fit into the packet's data buffer.
+	* cr_err_repl.c (cr_err_reply): Bail if the reply packet won't
+	fit into its buffer.
+	* cr_tkt.c (krb_create_ticket): Ditto.
+	* g_ad_tkt.c (get_ad_tkt): Stop if data being added to buffer
+	would overflow it.  Add more sanity checks when decomposing the
+	credential received.
+	* g_in_tkt.c (krb_mk_in_tkt_preauth): Bail if the request packet
+	won't fit into its buffer.
+	* g_krbhst.c (get_krbhst_default): Truncate the guessed KDC's
+	hostname if it is too long.
+	* g_pw_in_tkt.c: Remove useless strcpy() prototype.
+	* kntoln.c (krb_kntoln): Don't overflow buffer "lname".
+	* mk_err.c (krb_mk_err): Return the needed buffer length if the
+	pointer passed in is NULL.
+	* mk_req.c (krb_mk_req): Bail if the reply packet won't 
+        fit into its buffer.
+	* rd_req.c (krb_rd_req): Sanity check the realm name being read,
+	and truncate the service name, nstance, and realm from credential
+	read from keytab.
+	* realmofhost.c (krb_realmofhost): Truncate realm names read
+	from file if they are too long.
+	* send_to_kdc.c (send_to_kdc): Truncate passed-in realm name.
+
+2000-05-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* rd_req.c (krb_rd_req): Mask length byte with 0xff in case the
+	length is over 127 and char is signed.
+
+	* recvauth.c (krb_recvauth): If the number of bytes to be read
+	from the net is not positive, just return an error.
+
+2000-05-03  Tom Yu  <tlyu@mit.edu>
+
+	* cr_tkt.c: Delete prototype for krb_cr_tkt_int(), since the
+	definition is K&R style and contains narrow types.  Thank you
+	HP/UX for having a compiler that actually makes this a fatal
+	error.
+
+2000-04-28  Ken Raeburn  <raeburn@mit.edu>
+	    Nalin Dahyabhai  <nalin@redhat.com>
+
+	* dest_tkt.c (dest_tkt): Don't overflow buffer "shmidname".
+	* in_tkt.c (in_tkt): Don't overflow buffer "shmidname".
+	* kuserok.c (kuserok): Don't overflow buffer "pbuf".
+	* tf_util.c (tf_init): Don't overflow buffer "shmidname".
+	* win_store.c (krb__get_cnffile): Don't overflow buffers "defname"
+	and "cnfname".
+	(krb__get_realmsfile): Don't overflow buffers "defname" and
+	"realmsname".
+
+2000-04-28  Tom Yu  <tlyu@mit.edu>
+
+	* rd_req.c (krb_rd_req): Fix some uses of strcpy().
+
+2000-03-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* cr_tkt.c (krb_cr_tkt_int): Add static prototype.
+	* decomp_tkt.c: (dcmp_tkt_int): Add static prototype
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-10-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* rd_svc_key.c (krb54_get_service_keyblock): Close keytab before
+	returning in success case.  Patch from Greg Hudson
+	<ghudson@mit.edu>.
+
+1999-08-26  Danilo Almeida  <dalmeida@mit.edu>
+
+	* memcache.c (change_cache): Use PostMessage instead of SendMessage
+	so we do not block.
+
+Fri Aug 13 23:23:00 1999  Brad Thompson  <yak@mit.edu>
+
+	* sendauth.c: Initialize __krb_sendauth_hidden_tkt_len so
+	it doesn't end up in the common block.
+
+	* pkt_clen.c: Initialize swap_bytes so that it doesn't end
+	up in the common block.
+
+Mon May 10 15:23:15 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Thu Apr 15 20:18:38 1999  Tom Yu  <tlyu@mit.edu>
+
+	* g_cnffile.c (krb__get_srvtabname): Fix to actually extract
+	krb5_srvtab value from profile, instead of always ignoring it.
+
+Mon Feb  8 21:56:45 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* rd_req.c (krb_rd_req): Add appropriate #ifdef so that this code
+		compiles cleanly when KRB4_USE_KEYTAB is not defined.
+
+1998-12-05  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* rd_svc_key.c (krb54_get_service_keyblock): New function which
+		searches the appropaite krb5 keytab file for the key to be
+		used by the krb4 library.
+
+	* rd_req.c (krb_rd_req): If the appropriate key cannot be found in
+		the krb4 srvtab file, try calling krb54_get_service_keyblock.
+
+	* decomp_tkt.c (dcmp_tkt_int): 
+	* g_in_tkt.c (krb_mk_in_tkt_preauth): 
+	* g_ad_tkt.c (get_ad_tkt): 
+	* pkt_clen.c (pkt_clen): 
+	* rd_err.c (krb_rd_err): 
+	* rd_priv.c (krb_rd_priv): 
+	* rd_req.c (krb_rd_req): 
+	* rd_safe.c (krb_rd_safe): Use krb4_swab32 and krb4_swab16 instead
+		of swap_u_long and swap_u_short.  The new byte swapping
+		routines are faster and cleaner.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+	* configure.in: Remove KRB5_POSIX_LOCKS test.
+
+	* win_store.c (krb__get_srvtabname): 
+	* g_cnffile.c: Use krb5__krb4_context instead of init'ing and
+		free'ing a krb5_context each time we need to read data
+		from the configuration file.  We also define
+		krb5__krb4_context in g_cnnfile.c, since it's a likely
+		that any use of the krb4 library will pull in that file.
+
+	* tf_util.c (tf_init): Use krb5_lock_file instead of trying to
+		roll our own flock emulation.
+
+Wed Aug 12 18:32:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* rd_req.c (krb_set_key): Nuke the krb5_keyblock if it's set.
+	(krb_set_key_krb5): New function to set a static krb5_keyblock for
+	decryption purposes.
+	(krb_clear_key_krb5): New function to clear the static
+	krb5_keyblock if it's set.
+	(krb_rd_req): Call decomp_ticket or decomp_tkt_krb5 as appropriate
+	to the key type.
+
+	* decomp_tkt.c (decomp_tkt_krb5): New wrapper to call
+	dcmp_tkt_int.
+	(decomp_ticket): Transform into wrapper to call dcmp_tkt_int.
+	(dcmp_tkt_int): New internal function; use a krb5_keyblock to
+	decrypt the ticket if present; else just use plain old C_Block.
+
+	* cr_tkt.c (krb_create_ticket): Transform into a wrapper that
+	calls krb_cr_tkt_int.
+	(krb_cr_tkt_krb5): New wrapper to call krb_cr_tkt_int.
+	(krb_cr_tkt_int): New internal function that potentially uses a
+	krb5_keyblock to encrypt the ticket, or just a C_Block if the
+	krb5_keyblock is not set.
+
+Mon Aug 10 17:51:59 1998  Matthew D Hancher  <mdh@mit.edu>
+
+	* rd_svc_key.c (read_service_key): Don't call krb5_kt_close() if 
+	krb5_kt_resolve() fails, so we don't segfault if the keytab name 
+	is invalid.
+
+Fri Aug  7 11:04:03 1998  Tom Yu  <tlyu@mit.edu>
+
+	* rd_safe.c (krb_rd_safe): Fix up call to quad_cksum().
+
+	* mk_safe.c (krb_mk_safe): Fix up call to quad_cksum().
+
+	* tf_util.c (tf_init): Add call to getuid() to initialize me.
+
+Thu Jul 30 13:13:30 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* tf_util.c (tf_init): s/,/= so getuid() actually gets called
+
+Sun Jul 26 17:51:24 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* Makefile.in (LIBMAJOR): Bump libmajor
+
+Thu Jul  9 19:35:01 1998  Matthew D Hancher  <mdh@mit.edu>
+
+	* tf_util.c (tf_init): Fixed a potential race condition in the opening 
+	of v4 ticket files. tf_init() was calling lstat() followed by fopen().
+	Now it calls fopen() and then calls lstat() and fstat() to check file 
+	ownership and to check that it opened the file it thought it did. I 
+	patched the shared memory code similarly, but since nothing uses it I
+	don't have a good way to test it properly.
+	
+Wed Jun 24 03:09:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* mk_priv.c (krb_mk_priv): Fix up call to pcbc_encrypt().  By
+ 	taking the address of key, the 5th arg to pcbc_encrypt() was
+ 	actually a (char **) cast to a (C_Block *).  The reason for this
+ 	is that a C_Block (actually a des_cblock) is typedef'ed from a
+ 	char[8], which by being in the parameters of the definition of
+ 	krb_mk_priv() becomes of type (char *).  This means that using the
+ 	address operator on key resulted in a pointer to a pointer to a
+ 	char rather than a pointer to a des_cblock, which would have been
+ 	innocuous in this case because pcbc_encrypt() actually takes a
+	(des_cblock *) as the 5th (ivec) argument.  The moral is to never
+ 	pass around naked arrays as function arguments; instead, pass
+ 	around pointers to arrays to avoid spontaneous conversions to
+ 	pointers sneaking up.  Note that CNS actually uses a (C_Block *)
+	everywhere, and maybe we should as well.  *whew*
+
+1998-05-08  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* stime.c (krb_stime): 
+	* log.c (krb_new_log, krb_log): 
+	* klog.c (klog): Print the year using 4 digits to avoid Y2K issues.
+
+Wed Apr 15 18:07:00 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): 
+	(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
+
+Thu Apr  9 18:44:16 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (includes): The header is krb_err.h, not
+	/krb_err.h.
+
+Sun Apr  5 19:51:21 1998  Tom Yu  <tlyu@mit.edu>
+
+	* g_cnffile.c (krb__get_srvtabname): Fix up to not free context
+	unless it is valid.
+
+Wed Feb 18 16:17:49 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* configure.in, Makefile.in: Remove use of CopyHeader from
+		configure.in and move functionality to Makefile.in
+
+Tue Jan  6 17:11:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* in_tkt.c: Conditionalize use of macro do_seteuid, rather than
+	redefining setreuid. [krb5-libs/521]
+
+Sat Dec  6 22:17:28 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* dest_tkt.c: Add <string.h> for memset prototype.
+
+Wed Nov 19 11:04:27 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean-unix): krb_err.h resides in the kerberosIV
+	 	subdir for make clean.
+
+Wed Nov 19 00:01:07 1997  Tom Yu  <tlyu@mit.edu>
+
+	* rd_safe.c (krb_rd_safe): Fix up call to quad_cksum.
+
+	* mk_priv.c (krb_mk_priv): Fix up call to pcbc_encrypt.
+
+	* mk_safe.c (krb_mk_safe): Fix up call to quad_cksum.
+
+Tue Nov 18 23:49:01 1997  Tom Yu  <tlyu@mit.edu>
+
+	* mk_req.c (krb_mk_req): Fix up call to pcbc_encrypt.
+
+	* rd_req.c (krb_rd_req): Fix up call to pcbc_encrypt.
+
+Tue Oct 21 09:02:51 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* kparse.c: Include stdlib.h if present (for malloc prototyp)
+
+Fri Oct 17 20:33:17 1997  Tom Yu  <tlyu@mit.edu>
+
+	* mac_time.c: Don't use the type KRB_INT32; it was leaked from
+	des.h and was just the wrong answer.  Use long instead.  While
+	we're at it, declare gettimeofdaynet_no_offset() as static because
+	we have no real need to export it.
+
+Tue Sep 30 19:00:33 1997  Tom Yu  <tlyu@mit.edu>
+
+	* tkt_string.c: Replace HAS_STDLIB_H with something more sane.
+
+	* send_to_kdc.c: Replace HAS_STDLIB_H with something more sane.
+
+	* realmofhost.c: Replace HAS_STDLIB_H with something more sane.
+
+	* mk_preauth.c: Repalce HAS_STDLIB_H with something more sane.
+
+	* memcache.c: Replace HAS_STDLIB_H with something more sane.
+
+	* kparse.c: Replace HAS_STDLIB_H with something more sane.
+
+	* configure.in: Replace HAS_STDLIB_H with something more sane.
+
+Thu Sep 25 21:11:16 1997  Tom Yu  <tlyu@mit.edu>
+
+	* put_svc_key.c: Replace HAS_UNISTD_H with something more sane.
+
+	* kuserok.c: Replace HAS_UNISTD_H with something more sane.
+
+	* configure.in: Replace HAS_UNISTD_H with something more sane.
+
+Mon Sep  1 21:37:36 1997  Tom Yu  <tlyu@mit.edu>
+
+	* decomp_tkt.c (decomp_ticket): Fix swapped args to memset.
+
+Tue Aug 12 09:10:41 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (OSSRCS): Add $(srcdir)/ to source location.
+
+Thu Aug  7 15:53:13 1997  Tom Yu  <tlyu@mit.edu>
+
+	* g_cnffile.c: Check to see if context is NULL prior to calling
+	profile_get_values.  Fixes krb5-libs/317.
+
+Wed Apr  9 23:15:39 1997  Tom Yu  <tlyu@mit.edu>
+
+	* realmofhost.c (krb_realmofhost): Add bounds checking to various
+	things.
+
+	* g_krbhst.c (krb_get_krbhst): Fix to bound fscanf and sscanf.
+
+	* g_krbrlm.c (krb_get_lrealm): Fix to bound fscanf.
+
+Sat Feb 22 19:02:08 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Sat Feb 22 01:16:01 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (SHLIB_DIRS): Remove extra shlib_explibs
+
+Sat Feb 22 00:55:42 1997  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Depend on -lcrypto -ldes425
+
+Thu Feb 20 23:27:39 1997  Richard Basch  <basch@lehman.com>
+
+	* memcache.c: Just use malloc/free, since _nmalloc isn't on
+		all versions of Windows.
+
+Sun Feb 16 21:11:51 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Win16/Win32 cleanup
+
+	* err_txt.c g_admhst.c g_cred.c g_krbhst.c g_krbrlm.c g_phost.c
+	g_pw_in_tkt.c g_svc_in_tkt.c g_tkt_svc.c kname_parse.c mk_auth.c
+	mk_err.c mk_preauth.c mk_priv.c mk_req.c mk_safe.c rd_err.c
+	rd_priv.c rd_req.c rd_safe.c rd_svc_key.c realmofhost.c
+	recvauth.c save_creds.c unix_glue.c
+		Changed declaration of functions to use
+		KRB5_DLLIMP/KRB5_CALLCONV instead of INTERFACE.
+
+Sat Feb  1 08:44:00 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (STOBJLISTS): Fix up des425 reference.
+
+Wed Jan  8 01:34:30 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in, configure.in: Convert to new build procedure.
+
+Mon Nov 18 20:40:39 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Set shared library version to 1.0. [krb5-libs/201]
+
+Thu Nov  7 12:33:06 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* g_in_tkt.c: 
+	* sendauth.c: Fixed mangled copyright notice
+
+Thu Jun 13 22:12:57 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to ET_RULES
+
+Wed Jun 12 01:02:45 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Remove unnecessary include config/windows.in.
+		wconfig takes care of this automatically.
+
+Wed May 22 07:41:15 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (install-unix): Don't include an install rule, as it
+ 	is generated by aclocal.m4 for shared libs.
+
+Tue Apr 30 19:26:11 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Evaluate AC_C_CROSS before AC_TRY_RUN, to clean up
+	the output style.
+
+Sun Apr 14 04:16:50 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* rd_svc_key.c (get_service_key): Don't declare open().
+
+Wed Apr 10 19:18:57 1996  Richard Basch  <basch@lehman.com>
+
+	* rd_svc_key.c (read_service_key): First try to read the V4
+	service key from the V4 srvtab, and if it fails, try the keytab.
+	A * instance will be translated into the default instance component
+	(usually the FQDN of the local hostname).
+
+Fri Mar 29 16:45:00 1996  Richard Basch  <basch@lehman.com>
+
+	* rd_svc_key.c, configure.in: Try to read the V4 service key from a
+		V5 keytab.
+
+Tue Mar 19 11:23:13 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* tf_util.c (tf_get_cred): Issue date is written out as a long,
+		read back in as same.
+
+Sat Feb 24 09:27:08 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* g_svc_in_tkt.c, put_svc_key.c, rd_req.c, rd_svc_key.c: Declare
+		krb__get_srvtabname(). 
+
+Sat Jan 27 01:05:12 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kuserok.c: use HAVE_SETEUID and HAVE_SETRESUID to figure out how
+	to emulate seteuid instead of assuming hpux.
+	* configure.in: test for seteuid as well; fold some tests into a
+	single AC_HAVE_FUNCS.
+
+Tue Dec  5 20:53:40 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: Shared library depends on krb5 library now.
+
+	* configure.in: Pass krb5 library version number to Makefile.
+
+Wed Nov 15 20:38:38 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* tf_util.c (emul_flock): initialize f to a copy of a static
+ 	(thus zero) struct flock, to avoid panic'ing sunos 4.1.4.
+
+Sun Nov 12 05:26:08 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* g_cnffile.c (krb__get_srvtabname): new function, looks up
+	[libdefaults]krb4_srvtab for use where KEYFILE used to be.
+	* g_cnffile.c (krb__v5_get_file): new function, looks up argument
+	in [libdefaults] and tries to open it as a filename. Returns
+	filehandle (or NULL, if fopen failed.)
+	(krb__get_cnffile, krb__get_realmsfile): use krb__v5_get_file to
+	look up "krb4_config" or "krb4_realms" respectively. Also add
+	$KRB_REALMS override for realms file.
+
+Mon Oct  2 11:12:05 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in (V5_MAKE_SHARED_LIB): Change rule to install
+		version 0.1 of the library. Pass the libcrypto version
+		number to Makefile
+
+	* Makefile.in (CRYPTO_VER): Get the proper libcrypto version number
+
+Mon Sep 25 16:54:34 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * DNR.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Mon Aug  7 18:40:34 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS): Include $(NETIO_SRCS) in the list of source
+		files, instead of $(NETIO_OBJS)
+
+	* tf_util.c (utimes): If __SVR4 is defined, #include <utime.h>,
+		just as we do if __svr4__ is defined.
+
+	* g_pw_in_tkt.c: If __SVR4 is defined, #include <sgtty.h>, just as
+		we do if __svr4__ is defined.  (WARNING: This code still
+		assumes that the BSD ioctl's are being supported, at least
+		in compatibility mode.  We should really upgrade this code
+		to use POSIX termios calls.)
+
+Tue Jun 27 23:59:28 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* rd_req.c (krb_rd_req): from_addr is an address, so use unsigned
+	KRB4_32 instead of long.
+
+Tue Jun 27 23:50:08 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* rd_safe.c (krb_rd_safe): use KRB4_32 for address comparison
+	and checksum swapping.
+
+Tue Jun 27 15:49:35 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kparse.c - Change LineNbr to sLineNbr to avoid conflict with kparse.h
+
+Mon Jun 26 14:58:02 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* log.c: Use HAVE_TIME_H not NEED_TIME_H
+
+	* klog.c: Change NEED_TIME_H to HAVE_TIME_H
+
+	* configure.in: Check for sys/select.h.  Also check for time.h.
+
+	* send_to_kdc.c: If sys/select.h exists, include it.
+
+Fri Jun 23 18:15:07 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: fix Sam's typo so libkrb4.a gets symlinked
+		properly
+
+Fri Jun 23 12:29:39 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* configure.in: Handle generation of rules to make static libs.
+
+	* Makefile.in (LIBNAME): Changed to support new handling of static
+        libraries
+
+
+Fri Jun 16 11:15:45 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change "./DONE" to "DONE" since we know how to make
+		"DONE", hence a clean make won't get confused any more.
+	* configure.in - Add shared library install target.
+
+
+Thu Jun 15 18:07:24 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add definitions for shared library build rules.
+	* configure.in - Create symlinks for archive and shared library
+		when we build them.
+
+Fri Jun  9 19:28:22 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Fri Jun  9 00:01:35 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in, configure.in: use CopyHeader rather than hand-coded
+		header install rule.
+
+Fri May 26 21:11:38 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* cr_err_repl.c (cr_err_reply): Remove backward compatibility code
+		for Kerberos V3 (!) which was causing problems for shared
+		libraries.  Library code shouldn't try to reference global
+		variables defined by the calling application!
+
+Sun May 21 16:06:20 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* dest_tkt.c: If O_SYNC is not defined, define as 0.
+
+	* in_tkt.c: If O_SYNC is not defined, define as 0.
+
+Thu May 18 14:43:51 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* in_tkt.c: Use HAVE_SETREUID and HAVE_SETRESUID to define 
+		setreuid properly.
+
+	* configure.in: Check for setreuid and setresuid
+
+Sun May  7 08:05:56 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* mk_preauth.c: Add <string.h> and either <stdlib.h> or provide
+		prototypes for malloc.
+
+	* g_svc_in_tkt.c: Add <string.h>
+
+
+	* rd_preauth.c: Add <string.h>
+
+	* mk_auth.c: Include "krb4-proto.h" for get_phost definition.
+
+	* g_pw_in_tkt.c (stub_key): Add <string.h>
+
+	* send_to_kdc.c: Ifdef on HAS_STDLIB_H not POSIX
+
+	* realmofhost.c: Ifdef on HAS_STDLIB_H not POSIX
+
+	* memcache.c: Ifdef on HAS_STDLIB_H not POSIX
+
+	* configure.in: Check for stdlib.h
+
+Thu May  4 10:03:22 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* put_svc_key.c (put_svc_key): remove spurious & in front of fkey
+		(it's a char[] and takint address of it is redundant)
+
+	* recvauth.c (krb_recvauth): remove spurious & in front of
+		reference to kdata->session
+
+	* rd_req.c (krb_rd_req): remove spurious & in front of reference
+		to ad->session
+
+	* g_in_tkt.c(decrypt_tkt): remove spurious & in front of reference
+		to key (it is a C_Block and taking address of it is
+		redundant)
+
+	* Makefile.in: new includes target to install krb_err.h in
+		$(BUILDTOP)/include; includes depends on krb_err.h.
+		Previously, it was attempting to install a header that had
+		not yet been generated!
+
+Tue May  2 09:30:50 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean-unix): Remove krb_err.h from the include
+		directory. 
+
+Sat Apr 29 00:33:47 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* g_phost.c: removed references to sys/param.h and netdb.h
+	* realmofhost.c: ditto
+
+Fri Apr 28 13:03:23 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* tf_util.c, configure.in: Added check for POSIX_FILE_LOCK to
+		enable POSIX file locking.
+
+	* tf_util.c: Add #include of fcntl.h
+
+	* month_sname.c, one.c: Remove unnecessary include of conf.h
+
+Fri Apr 28 01:55:18 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* kuserok.c: HAS_UNISTD_H instead of USE_.
+	* configure.in: test for HAVE_STRSAVE (for kparse.c).
+
+Fri Apr 28 01:38:42 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* configure.in: use AC_CHECK_SIZEOF(int) to set BITS16/BITS32.
+	Use AC_TRY_RUN test to set MSBFIRST or LSBFIRST.
+
+Tue Mar 28 09:19:23 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* send_to_kdc.c (send_to_kdc): only use secondary port if entry
+	for primary doesn't have an explicit port number. Secondary port
+	is still guessed to be 750. Also *don't* switch to the secondary
+	port in general, since we might be using multiple realms.
+
+Tue Feb 14 23:24:50 1995  John Gilmore  <gnu@cygnus.com>
+
+	* sendauth.c (krb_net_rd_sendauth):  Result is a Kerberos error
+	code, not an errno.
+
+Mon Feb  6 16:11:52 1995  John Gilmore  (gnu at toad.com)
+
+	* mac_store.c (DeleteServerMap):  When skipping a realm map, skip
+	also the admin-flag byte; else walking the list of strings gets
+	very confused. 
+
+	* mac_stubs.c (kdriver):  Rename static variable to mac_stubs_kdriver,
+	and export it to callers.
+	(krb_get_ticket_for_service):  Circumvent MPW compiler bug that
+	doesn't like array->memb inside a sizeof.  array[0].memb works.
+
+Wed Feb 1 12:00:00 1995  John Rivlin  <jrivlin@cygnus.com>
+
+	* Makefile.in: Modify install-windows and clean-windows
+	targets to install libraries into src/windows directory.
+
+Tue Jan 24 10:35:31 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* g_pw_in_tkt.c (krb_get_pw_in_tkt_preauth): Check for a NULL
+	password if _WINDOWS or macintosh.
+
+Mon Jan 23 17:06:10 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* g_pw_in_tkt.c (passwd_to_key): When not _WINDOWS or macintosh,
+	restore code to call des_read_password if passwd is NULL.
+	(krb_get_pw_in_tkt): Only error out if password is NULL if
+	_WINDOWS or macintosh.
+
+	* g_krbhst.c (get_krbhst_default): New static function.
+	(krb_get_krbhst): Use get_krbhst_default.
+
+Fri Jan 20 12:00:00 1995  John Rivlin  (jrivlin@fusion.com)
+
+	* Makefile.in: Changed libentry to debug in link command as
+	libentry is no longer provided in the Visual C++ environment.
+	Libentry is part of the library in Visual C++.  Debug is used
+	purely to satisfy the syntax requirements of the link command.
+
+Thu Jan 19 14:18:10 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* sendauth.c (krb_net_rd_sendauth): If the raw ticket length looks
+	like the start of a warning from SunOS4 ld.so, just ignore the
+	warning message, and look for the ticket after it.
+
+Mon Jan 16 16:11:21 1995  John Gilmore  <gnu@cygnus.com>
+
+	* kuserok.c (kuserok):  Allow realm to be defaulted in the
+	~/.klogin file; this simplfies DejaGnu testing of Kerberos.
+	Fix bug that left kname_parse arguments uninitialized. 
+
+Mon Jan 16 11:54:01 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* krb_err.et: Change KRBET_RD_APTIME message from ``delta_t too
+	big'' to ``time is out of bounds.''
+
+	* send_to_kdc.c: If POSIX, include <stdlib.h> instead of declaring
+	malloc, calloc, and realloc.
+	(cached_krb_udp_port): Make static.
+	(send_to_kdc): If send_recv fails, and the kerberos port number
+	used is from getservbyname, and is not 750, then try sending to
+	port 750.
+
+	* realmofhost.c (krb_realmofhost): If DO_REVERSE_RESOLVE is
+	defined, canonicalize using gethostbyaddr.
+
+Thu Jan 12 17:40:26 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* in_tkt.c (in_tkt): Set umask to 077 around creation of ticket
+	file to ensure that it is created with write access, even if the
+	user has a screwy umask value.
+
+Thu Dec 29 23:59:49 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* g_in_tkt.c (krb_get_in_tkt_preauth): factored out into
+	krb_mk_in_tkt_preauth and krb_parse_in_tkt. This simplifies the
+	SNK4 support on platforms that can't do callbacks from (shared)
+	libraries.
+
+Tue Dec 27 11:12:54 1994  Ian Lance Taylor  <ian@cygnus.com>
+
+	* g_in_tkt.c (krb_get_in_tkt_preauth): Rewrite switch statement to
+	work when compiled by SCO 3.2v4 native C compiler.
+	* g_ad_tkt.c (get_ad_tkt): Likewise.
+
+Fri Dec 23 15:47:20 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* memcache.c (unix): Define if _AIX is defined (AIX compiler does
+	not predefine unix).
+
+Fri Dec 16 18:57:40 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* memcache.h: Use PROTOTYPE in declarations.
+	* memcache.c: Rewrite function definitions to use Classic C
+	parameter repetition rather than prototypes.
+
+Thu Dec 15 18:23:37 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* memcache.c: Add typedefs and macro definitions to make this file
+	compile on Unix as well as on Windows and the Mac.
+
+Wed Dec 14 19:31:24 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* g_in_tkt.c (krb_get_in_tkt_preauth): Comment out assignment to
+	exp_date, since it is not used.
+
+Wed Nov 23 12:30:49 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* fakeenv.c (_findenv, unsetenv): New functions, copied in from
+	setenv.c.  The telnet server uses unsetenv.
+
+Wed Nov 23 00:53:10 1994  John Gilmore  (gnu@cygnus.com)
+
+	* realmofhost.c (krb_realmofhost):  Allow arbitrary host
+	names here, as in krb_get_phost, by canonicalizing the name
+	into a fully qualified name using gethostbyname().  This
+	has the effect of letting users not set the "local realm"
+	config knob in more cases, since a name without a dot will
+	be canonicalized and searched-for in the domain-to-realm
+	database, rather than being assumed to be in the local realm.
+	This problem was found by using unqualified hostnames in Wintel.
+
+Wed Nov 23 00:26:17 1994  John Gilmore  (gnu@cygnus.com)
+
+	Clean up a few misleading error messages.
+
+	* memcache.c (krb_get_tf_fullname):  Return NO_TKT_FIL if
+	there are no tickets cached, just like from tf_util.c.
+	* g_ad_tkt.c (get_ad_ticket):  If we try cross-realm 
+	authentication, and it fails for lack of a key in the
+	kerberos database, return AD_NOTGT ("No ticket-
+	granting ticket") rather than KDC_PR_UNKNOWN ("Principal unknown").
+	* krb_err.et, err_txt.c:  Update NO_TKT_FIL error message from
+	"No ticket file (tf_util)" to "You have no tickets cached".
+
+Thu Nov 17 12:31:27 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* mk_preauth.c (krb_mk_preauth): des_key_sched takes a des_cblock
+	argument, not des_cblock *, so remove the cast.
+	* rd_preauth.c (krb_rd_preauth): Likewise.
+
+Wed Nov 16 22:13:28 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* mk_preauth.c (krb_mk_preauth): use des_key_sched instead; check
+	its return value and fail if it fails.
+	* rd_preauth.c (krb_rd_preauth): ditto.
+
+Wed Nov 16 17:35:07 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* mk_preauth.c (krb_mk_preauth): add R3 implementation (and
+	NOENCRYPTION version) which passes encrypted aname.
+	(krb_free_preauth): free storage from both implementations.
+	* rd_preauth.c (krb_rd_preauth): add R3 implementation.
+
+Wed Nov 16 17:28:14 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* g_pw_in_tkt.c (stub_key): use memcpy, in case the C_Block is an
+	array and not a struct.
+
+Wed Nov  9 12:45:02 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* in_tkt.c: Fix thinko in last change.
+
+Fri Nov  4 12:05:57 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* in_tkt.c: Don't redefine setreuid if both hpux and __svr4__.
+
+Fri Nov  4 02:10:58 1994  John Gilmore  (gnu@cygnus.com)
+
+	Make it build on MS-Windows again.
+
+	* Makefile.in (NETIO_SRCS, NETIO_OBJS):  Break out, since these
+	are required on MS-Windows and prohibited on Mac.
+	(kerberos.dll):  Avoid line-length problems by copying 
+	libraries from other directories and using very short names.
+
+Tue Nov  1 15:47:44 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* dest_tkt.c: Include "krb.h" before <stdio.h>.
+
+Mon Oct 31 19:41:14 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* Makefile.in (CODE): Use Makefile.in instead of Imakefile.
+
+Fri Oct 28 15:21:56 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
+
+	* month_sname.c: Include conf.h.
+	* one.c: Likewise.
+
+	* rd_req.c (krb_rd_req): Pass address of the array ad->session, to
+	match function definition.
+
+Wed Oct 12 00:37:46 1994  Julia Menapace  (jcm at toad.com)
+
+	* Password.c: Include kerberos.h not Krb.h.  Define KRB_DEFS to
+	avoid multiple symbol definitions from krb_driver.h.  Needs further
+	cleanup but not just before release.
+
+Mon Oct 10 20:07:56 1994  Julia Menapace  (jcm at toad.com)
+
+	* g_tkt_svc.c: (cacheInitialTicket) moved to new file Password.c
+
+	* mac_glue.c:  Remove superfluous comment.
+
+	* mac_stubs.c: Add code translating unix function call to mac
+	driver control call for krb_get_tf_fullname
+
+	* macsock.c: Remove superflous comment.
+
+	* memcache.c: Remove unused #includes
+	(krb_get_tf_realm) pass tktfile instead of blank to
+	krb_get_tf_fullname.
+
+	(get_tf_fullname): Because the symantics of GetNthCredentials
+	(called by this routine) were changed to disable multiple named
+	caches (for UNIX compatability) we have to replace the user name
+	and instance it returns with the actual name and instance of the
+	current cache, set by in_tkt and stored in file static global
+	variables.
+
+Mon Oct 10 13:37:34 1994  Julia Menapace  (jcm at toad.com)
+
+	* mk_auth.c:  New file, created from sendauth.c.  Contains just
+	the portable parts of sendauth.c (krb_mk_auth and krb_check_auth).
+	* sendauth.c (krb_mk_auth, mrb_check_auth):  Move these functions
+	to mk_auth.c.
+	* Makefile.in (SRCS, OBJS, SERVER_KRB_SRCS, SERVER_KRB_OBJS):
+	Add mk_auth.c to SRCS/OBJS; remove sendauth.c, netread.c, and 
+	netwrite.c from SRCS/OBJS to SERVER_KRB_SRCS/OBJS.
+
+Thu Sep 29 15:31:24 1994  John Gilmore  (gnu@cygnus.com)
+
+	* realmofhost.c (krb_realmofhost):  Correct off-by-one error in
+	default handling of top and second-level domains.
+
+Fri Sep 23 12:00:00 1994  John Rivlin  (jrivlin@fusion.com)
+
+	* Makefile.in: Added kstream library to kerberos.dll
+
+	* kerberos.def: Added kstream library to kerberos.dll
+
+Fri Aug 19 12:00:00 1994  John Rivlin  (jrivlin@fusion.com)
+
+	* g_pw_in_.c: Added (key_proc_type) cast for stub_key to remove
+	warnings with prototypes active.
+
+	* kerberos.def: Added des_ecb_encrypt to externals for telnet.
+
+Wed Sep 14 12:58:05 1994  Julia Menapace  (jcm@cygnus.com)
+
+	* mac_stubs.c (krb_get_err_text): make return type const.
+	(GetNthRealmMap): add routine to stubs library to generate a
+	driver call returning the Nth Realm mapping.
+	(GetNthServerMap): add routine to stubs library to generate a
+	driver call returning the Nth server mapping.
+	* g_tkt_svc.c (CacheInitialTicket): If user name has changed save
+	it.
+	* memcache.c (krb_save_credentials): Fill in credential with
+	currently authorized user name and instance expected by kerberos,
+	(passed to and stored by in_tkt) instead of FIXED user name and
+	instance used to select credentials cache (is same for all cases to
+	disable multi named caches, using/reusing single named cache for
+	all cases).
+
+Tue Sep 13 16:45:01 1994 Julia Menapace (jcm@cygnus.com)
+
+	* err_txt.c (MULTIDIMENSIONAL_ERR_TXT):  Rename from 
+	UNIDIMENSIONAL_ARRAYS to reflect what's actually going on.
+
+Thu Aug 18 20:26:16 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* g_tkt_svc.c (CredIsExpired): use proper style of declaration so
+	that it works with k&r compilers.
+
+Wed Aug 10 13:47:55 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* err_txt.c (krb_err_txt): Export it again, to avoid gratuitous
+	incompatibility. Programs that can't deal with the use of the
+	array don't have to use it.
+
+Fri Aug  5 15:55:02 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* tf_util.c (tf_save_cred): cast 0 to (off_t), don't assume 0L
+	will work (it doesn't in netbsd.)
+
+Mon Aug 6 12:00:00 1994  John Rivlin  (jrivlin@fusion.com)
+
+	* g_cnffile.c: Added definition for getenv.
+
+	* Makefile.in: Added KADM_LIB_FOR_DLL library in kerberos.dll
+	Updated clean target to avoid deleteion of krb_err.h under
+	Windows.
+
+	* kerberos.def: Added inteface for KRB_GET_NOTIFICATION_MESSAGE,
+	KADM_INIT_LINK, KADM_CHANGE_PW, KADM_CHANGE_PW and KADM_GET_ERR_TEXT
+	and renumbered entrypoints for consistency.
+
+	* memcache.c (change_session_count, change_cache): Changed 
+	change_session_count to change_cache.  This
+	routine now maintains the lock on the library as well as sending
+	ot broadcast messages to all to level windows when the cache
+	changes. Also changed all calls to above routine throughout 
+	memcache.c.
+
+	* netwrite.c: use newly added SOCKET_READ and SOCKET_EINTR values
+	to avoid use of read on Windows.  VMS dependencies moved to c-vms.h
+	for uniformity with other platforms.
+
+	* netread.c: use newly added SOCKET_READ and SOCKET_EINTR values
+	to avoid use of read on Windows.  VMS dependencies moved to c-vms.h
+	for uniformity with other platforms.
+	
+	* memcache.c: sname, sinst, srealm not stored if null pointers
+	passed in.  This avoids problems found porting kpasssd.
+
+Mon Aug 1 12:00:00 1994  John Rivlin  (jrivlin@fusion.com)
+
+	* kerberos.def: Changed heapsize to 8192 to avoid LocalAlloc
+	failure messages on startup. Added kadm_change_pw2 to external
+	interface.
+	
+	* win_glue.c (krb_get_default_user, krb_set_default_user): Have
+	been moved to win_store.c.
+
+	* win_store.c: Use KERBEROS_INI and INI_xxx values in c-windows.h
+	rather than hard coded strings.
+
+	* win_store.c (krb_get_default_user, krb_set_default_user): Added
+	to save and retieve value of "[DEFAULTS] user =" in kerberos.ini
+	file.
+
+	* realmofhost.c (krb_realmofhost): Now calls krb__get_relmsfile
+	rather than opening up the krb.realms file directly so that
+	Windows version can override the location of the file.
+
+	* win_stor.c: Stores the 
+
+Wed Jul 27 12:00:00 1994  John Rivlin  (jrivlin@fusion.com)
+
+	* g_cnffil.c (krb__get_realmsfile): Added a routine to open
+	the krb.realms file so that the routine can be overridden
+	in Windows implementation with a routine which looks up
+	the name of the realms file in the kerberos.ini file.
+
+	* win_store.c: Created to parallel the Mac implementation.
+	Routines in this file will provide access to the krb.conf,
+	krb.realms files and other configuration information.
+
+	* ren.msg: Created entry for win_store.
+
+	* Makefile.in: Move g_cnffile.c to REALMDBSRCS to allow 
+	Windows to override this functionality with a routine in 
+	win_store.c routine.
+
+Tue Jul 26 12:00:00 1994  John Rivlin  (jrivlin@fusion.com)
+
+	* netread.c: errno redefinition under Windows ifdefed out.
+	* netwrite.c: errno redefinition under Windows ifdefed out.
+
+Fri Jul 22 23:07:21 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* rd_preauth.c (krb_rd_preauth): change interface to include the
+	decrypted key (since the server has already looked it up.)
+
+Thu Jul 21 17:24:13 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* g_krbrlm.c (krb_get_lrealm): use krb__get_cnffile, don't
+	(mis)declare fopen.
+	* g_krbhst.c (krb_get_krbhst): ditto.
+	* g_admhst.c (krb_get_admhst): ditto.
+	* Makefile.in (OBJS, SRCS): build get_cnffile.c.
+
+Thu Jul 21 17:10:35 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* g_pw_in_tkt.c (krb_get_pw_in_tkt_preauth): *MUST* continue to
+	allow the password not to be passed in, since there is code that
+	does interesting things in the passwd_to_key routine.
+
+	* g_svc_in_tkt.c (stub_key): don't assume C_Block is a struct; use
+	memcpy instead of *.
+
+	* log.c (krb_log): use char* instead of int for default args.
+	Don't declare fopen explicitly, let stdio.h do it.
+	Don't include sys/time.h under VMS.
+	* klog.c (klog): ditto.
+
+Wed Jul 20 22:34:11 1994  Mark Eichin  (eichin@tweedledumber.cygnus.com)
+
+	* rd_safe.c (krb_rd_safe): handle direction bit correctly when
+	krb_ignore_ip_address is set.
+
+	* rd_priv.c (krb_rd_priv): same.
+
+	* send_to_kdc.c: support arbitrary KDC port number in krb.conf file.
+
+	* g_cnffile.c: new file. common interface to krb.conf.
+	vmslink.com: new file. linker script to build libkrb.olb under
+	VMS; run as @vmslink.
+	vmsswab.c: vms runtime doesn't have swab.
+
+Wed Jul 20 20:38:19 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* kparse.c (strsave): only define locally if HAVE_STRSAVE isn't set.
+
+Tue Jul 19 12:00:00 1994  John Rivlin (jrivlin@fusion.com)
+
+	* memcache.c (NewHandle, SetHandleSize, MemError): Updated to return
+	valid Mac compatable error codes.  Got rid of warning messages for 
+	pointer mismatches.
+
+	* memcache.c (change_session_count): added routine and calls to it
+	to facilitate cross session ticket cacheing under Windows.  
+	Moved fNumSessions definition up so that Windows code can get to it.
+	
+	* win_glue.c (LibMain, get_lib_instance): added to return HINSTANCE 
+	of library which is now saved in LibMain.
+
+Tue Jul 19 16:08:49 1994  Ken Raeburn  (raeburn@cujo.cygnus.com)
+
+	* klog.c (klog): Leave local static array logtype_array
+	uninitialized, to put it in bss.
+
+	* g_ad_tkt.c (rep_err_code): Variable deleted.
+	(get_ad_tkt): Make it automatic here.  Local variables pkt_st,
+	rpkt_st, cip_st, tkt_st no longer static.
+	* kname_parse.c (kname_parse): Local variable buf no longer
+	static.
+	* rd_req.c (krb_rd_req): Local variables ticket, tkt, req_id_st,
+	seskey_sched, swap_bytes, mutual, s_kvno no longer static.
+	* rd_safe.c (calc_cksum, big_cksum, swap_bytes): Variables
+	deleted.
+	(krb_rd_safe): Make them automatic variables here.  Local variable
+	src_addr no longer static.
+	* rd_priv.c (c_length, swap_bytes, t_local, delta_t): Variables
+	deleted.
+	(krb_rd_priv): Make them automatic variables here.  Local variable
+	src_addr no longer static.
+	* mk_safe.c (cksum, big_cksum, msg_secs, msg_usecs, msg_time_5ms,
+	msg_time_seg): Variables deleted.
+	(krb_mk_safe): Make them automatic variables here.
+	* mk_priv.c (c_length, msg_time_5ms, msg_time_sec, msg_time_usec):
+	Variables deleted.
+	(krb_mk_priv): Make them automatic variables here.  Local variable
+	c_length_ptr also no longer static.
+
+	* pkt_clen.c (swap_bytes): No longer explicitly extern.
+	* g_ad_tkt.c (swap_bytes): Make it extern here.
+
+	* kparse.c (LineNbr, ErrorMsg): Now static.
+
+	* err_txt.c (krb_err_txt): Don't export this name.  Make it const
+	again.
+
+	* netread.c: Include errno.h.
+	(errno): Declare.
+	(krb_net_read): On EINTR, retry read.
+	* netwrite.c: Include errno.h.
+	(errno): Declare.
+	(krb_net_write): On EINTR, retry write.
+
+Mon Jul 18 19:04:03 1994  Julia Menapace (jcm@cygnus.com)
+
+	* err_txt.c (krb_err_txt): if the C compiler can't initialize
+	multidimentional arrays, declare it differently (controlled by
+	UNIDIMENSIONAL_ARRAYS).
+
+	* mac_stubs.c (krb_get_cred, krb_save_credentials,
+	krb_delete_cred, krb_get_nth_cred, krb_get_num_cred): new
+	functions to implement credentials caching.
+
+	* memcache.c  (krb_get_cred, krb_save_credentials,
+	krb_delete_cred, krb_get_nth_cred, krb_get_num_cred): actual
+	implementation of this functionality.
+
+Fri Jul 15 17:35:30 1994  John Rivlin (jrivlin@fusion.com)
+
+	* ren.msg: updated to handle all files (changelogs, makefiles etc)
+
+	* Makefile.in: added "-" on clean: to avoid stupid messages
+
+	* g_pw_in_tkt.c (get_pw_in_tkt_preauth): added INTERFACE 
+	for kinit.
+
+	* kerberos.def: clean up, removed unused function references
+	
+	* win_glue.c (krb_start_session): fixed syntax error
+
+	* win_glue.c (krb_end_session): fixed syntax error
+
+Tue Jul 12 17:35:30 1994  D. V. Henkel-Wallace  (gumby@rtl.cygnus.com)
+
+	* ren.msg: add record for g_tkt_svc.c
+
+Fri June 8 02:40:54 1994  John Rivlin  (jrivlin@fusion.com)
+
+	* makefile.in: Updated file with portable directory syntax for PC.
+	Changed .o and .a references to portable syntax
+	Removed all response files which needed to be generated under unix
+	to simplify configure process so that it may be run on the PC.
+	Placed objects in .lib file so that DLL construction can take place
+	without a response file.  This solves a problem with running out of
+	memory on the PC during builds.
+	Updated clean: target to place rm commands on seperate lines for
+	compatibility with PC DEL command.
+
+	* win_glue (krb_start_session): Added a dummy parameter to match 
+	prototype.
+
+	* win_glue (krb_end_session): Added a dummy parameter to match 
+	prototype.
+
+Tue Jul  5 11:25:31 1994  Ken Raeburn  (raeburn@cujo.cygnus.com)
+
+	* err_txt.c (krb_err_txt): Now const.
+	(krb_get_err_text): Returns pointer to const.
+	* month_sname.c (month_sname): Month name array and return type
+	now both const.
+	* one.c (krbONE): Now const.
+
+	* g_tkt_svc.c: Include string.h.
+
+	* kntoln.c (krb_kntoln): Static variable lrealm is no longer
+	explicitly initialized; now in bss.
+	* tf_util.c (krb_shm_addr, tmp_shm_addr, krb_dummy_skey): Ditto.
+	* tkt_string.c (krb_ticket_string): Ditto.
+
+	* mk_req.c (krb_mk_req): Removed "static" from many function
+	variables.
+
+	* tkt_string.c (krb_set_tkt_string): Deleted extra whitespace,
+	unnecessary "return" statement.
+
+Fri Jul  1 04:50:06 1994  John Gilmore  (gnu@cygnus.com)
+
+	* macsock.c:  Eliminate "TCPTB.h".
+	* mac_stubs.c (isname, isinst, isrealm):  Remove, useless.
+	(krb_get_pw_in_tkt_preauth):  Stub out to be the same as
+	krb_get_pw_in_tkt, for kinit's sake.
+
+	* mac_stubs.c (hicall):  Fix error handling somewhat.
+
+	* Makefile.in (SRCS, OBJS):  Add g_tkt_svc.c, .o.
+
+	* kname_parse.c, rd_priv.c, rd_safe.c, unix_glue.c:  Typos.
+
+Fri Jul  1 03:55:29 1994  John Gilmore  (gnu@cygnus.com)
+
+	Make Kerberos work in a Macintosh driver using Think C.
+
+	* %KrbLib-project:  Think C "project file" (sort of
+	makefile and object files rolled into one -- all binary)
+	for the Kerberos library built for linking into applications
+	(for debugging).
+	* %KrbLib-project-A4:  Ditto, for linking into device drivers.
+
+	* mac_stubs.c:  New file, implements the function-call
+	interface of "kerberos.h" by making calls to a device-driver
+	using the hairy Mac interface of "krb_driver.h".  If you
+	link with this, your Mac program can use a portable, clean
+	interface to Kerberos.
+
+	* g_tkt_svc.c:  New file, krb_get_ticket_for_service,
+	an "easy application kerberizer", derived from kclient.
+
+	* err_txt.c (krb_err_txt):  Avoid pointers to string initializers,
+	since Think C can't cope with this in device drivers.
+	(krb_get_err_table):  Remove interface, unused.
+
+	* month_sname.c:  Avoid pointers to string initializers.
+	* kname_parse.c:  Add FIXME comment about args.
+	* mac_glue.c (read, write krb_ignore_ip_address):  Stub out.
+	* macsock.c, memcache.c, sendauth.c:  Lint.  Think includes.
+
+	* mac_store.h:  Eliminate static and obsolete stuff.
+	* mac_store.c:  Update includes for Think.
+	(gUserName):  Make static.
+	(krb_get_default_user, krb_set_default_user):  Add.
+	* unix_glue.c, win_glue.c (krb_set_default_user):  Add stub.
+
+	* g_ad_tkt.c, kname_parse.c, memcache.c, mk_priv.c, mk_req.c,
+	mk_safe.c, pkt_clen.c, rd_priv.c, rd_safe.c:  Remove uses of
+	printf, by using DEB macro.
+
+	* send_to_kdc.c:  Change to "krbports.h".
+	(DEB):  Remove definition in favor of krb.h.
+	(all calls to DEB):  Avoid passing stdout or stderr.
+
+Thu Jun 30 22:58:59 1994  John Gilmore  (gnu@tweedledumb.cygnus.com)
+
+	* *.c:  Remove remaining RCS ID strings.  Strings used as `char *'
+	initializers upset Think C when building device drivers, since it
+	doesn't have a good way to relocate the pointers when the driver
+	is loaded.
+
+	* *.c:  Use #include "..." rather than #include <...> for
+	our own local include files, because Think C can't find them
+	when enclosed in <...>.
+
+Thu Jun 30 17:48:26 1994  Ken Raeburn  (raeburn@cujo.cygnus.com)
+
+	* send_to_kdc.c (prog): Now const pointer to const.
+	(timeout): Static var deleted.
+	(send_recv): Use a local timeout structure instead, reinitialized
+	before each use, in case select modifies its value.
+
+Wed Jun 22 19:42:50 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* mk_preauth.c (krb_free_preauth): New function to free up storage
+	allocated by krb_mk_preauth (if any.)
+
+	* g_pw_in_tkt.c (krb_get_pw_in_tkt_preauth): use krb_free_preauth
+	to possibly release storage used by krb_mk_preauth.
+
+	* g_svc_in_tkt.c (krb_get_svc_in_tkt_preauth): use
+	krb_free_preauth to possibly release storage used by krb_mk_preauth.
+
+Wed Jun 22 19:33:21 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* put_svc_key.c: USE_UNISTD_H to get SEEK_CUR if neccessary.
+
+Wed Jun 22 18:11:49 1994  Ken Raeburn  (raeburn@cujo.cygnus.com)
+
+	* sendauth.c (krb_mk_auth): Don't call memset with BUFSIZ, since
+	the field in question is only MAX_KTXT_LEN bytes long.
+
+	* in_tkt.c, mk_priv.c, mk_safe.c, pkt_cipher.c, pkt_clen.c,
+	rd_err.c, rd_priv.c, rd_safe.c, tf_util.c: Include string.h.
+
+Wed Jun 22 15:11:35 1994  John Gilmore  (gnu@cygnus.com)
+
+	* ren.msg:  Add put_svc_key.c.
+
+Wed Jun 22 15:03:53 1994  Mark Eichin  (eichin at tweedledumber.cygnus.com)
+
+	* put_svc_key.c (put_svc_key): new file, new function.
+	* Makefile.in: add put_svc_key to SERVER_KRB_*.
+
+Tue Jun 21 01:20:44 1994  John Gilmore  (gnu@cygnus.com)
+
+	* kname_parse.c (kname_parse, isinst):  Allow periods in instance
+	names.  Pull RCS crud.
+
+Tue Jun 21 00:20:20 1994  John Gilmore  (gnu@cygnus.com)
+
+	* Makefile.in (all):  First rule in file just calls all-really.
+	(all-really):  Call $(ALL_WHAT) after it's been set.
+	* memcache.c:  Remove typedef kludges to
+	../../include/mt-windows.h.  Add Size.  WINDOWS -> _WINDOWS.	
+
+Sat Jun 18 09:11:49 1994  John Gilmore  (gnu@cygnus.com)
+
+	Make DES library independent of krb library.
+
+	* unix_glue.c, mac_glue.c, win_glue.c:  Remove time-handling
+	code to ../../lib/des/*_time.c.
+
+Sat Jun 18 07:46:32 1994  John Gilmore  (gnu@cygnus.com)
+
+	* send_to_kdc.c (send_recv):  Use SOCKET_NFDS as first arg to
+	select().
+	* macsock.c (gethostname):  Add incomplete stab at gethostname(),
+	under #if 0.
+	* cr_ciph.c, cr_tkt.c, decomp_tkt.c, g_ad_tkt.c, mac_store.c,
+	mk_req.c, mk_safe.c: Lint.
+
+Fri Jun 17 02:02:00 1994  John Gilmore  (gnu@cygnus.com)
+
+	* DNR.c:  New file of MacTCP interface code.
+	* macsock.c:  To avoid using StreamPtr in <macsock.h>, declare
+	fStream as unsigned long.  Cast it whenever we need it.  This
+	removes the need to include MacTCP header files in <macsock.h>.
+	* macsock.c, mac_glue.c:  Eliminate inclusion of "mac_glue.h".
+	* mac_glue.h:  Remove.
+
+Thu Jun 16 17:30:04 1994  John Gilmore  (gnu@cygnus.com)
+
+	* Makefile.in (unixmac):  New target.
+	* g_in_tkt.c:  MPW complains about types without a cast.
+	* mac_glue.c:  Pull networking code out into macsock.c.
+	(krb_get_phost):  Pull this; use ordinary common version.
+	(krb_start_session, krb_end_session):  Add.
+	* mac_store.c (gUserName):  Add definition.
+	Move static declarations above where they're needed.
+	(krb_realmofhost):  Return null pointer, not KFAILURE.
+	* macsock.c:  New file, implements socket abstraction for UDP.
+	* memcache.c: Update header file handling.  FIXME, works on Mac,
+	not on Windows too.
+	* send_to_kdc.c (send_to_kdc):  Clean up error handling.
+	Improve comments.  Add prototype for static function.
+	* stime.c:  #define NEED_TIME_H.  Use proper type for time_t.
+
+Wed Jun 15 16:35:52 1994  John Gilmore  (gnu@cygnus.com)
+
+	* unix_glue.c (krb_start_session, krb_end_session):  Take
+	args and ignore them, to match the prototypes.
+
+Fri Jun 10 22:52:14 1994  John Gilmore  (gnu@cygnus.com)
+
+	* g_in_tkt.c (swap_bytes):  Declare extern, not common.
+	* mac_glue.h:  New (was called MacMachineDependencies.h in
+	an earlier incarnation).
+	* mac_glue.c:  Add code for time zone and Domain Name
+	Service resolution.
+	* mac_store.c:  Eliminate credential storage, leaving just
+	configuration storage.  Initialize the store whenever a
+	high-level routine is called and we haven't initialized.
+	Return result from init_store, so callers can return
+	KFAILURE if we can't read the config data.
+	* mac_store.h:  Pull credential storage (now in memcache.h).
+	* unix_glue.c (krb_start_session, krb_end_session,
+	krb_get_default_user):  Provide dummy ones on Unix.
+
+Thu Jun  9 00:47:59 1994  John Gilmore  (gnu@cygnus.com)
+
+	* Makefile.in (SRCS, OBJS):  Move cr_death_pkt.c and kparse.c
+	to SERVER_SRCS and SERVER_OBJS.
+	(DELIVERABLES, INSTALL_DELIVERABLES):  Replace with ALL_WHAT
+	and INSTALL_WHAT, which actually work.
+	(all-unix):  Main rule for building on Unix now.
+	(clean):  Consolidate `make clean' entries so it actually works.
+
+Wed Jun  8 23:47:30 1994  John Gilmore  (gnu@cygnus.com)
+
+	Further DLL support for Windows, plus, make previous
+	changes work on Unix again.
+
+	* memcache.c:  New file implements ticket cacheing in RAM.
+	* memcache.h:  Interface for memcache.c.
+
+	* win_glue.c: Remove stub interfaces for in_tkt, save_credentials,
+	krb_save_credentials, krb_get_cred, dest_tkt, krb_get_tf_realm.
+
+	* g_ad_tkt.c, g_in_tkt.c:  Rename save_credentials to
+	krb_save_credentials.
+	* save_creds.c (save_credentials):  Remove.
+	* g_in_tkt.c (decrypt_tkt, krb_get_in_tkt_preauth):
+	Declare and use new key_proc_type and decrypt_tkt_type
+	typedefs for pointers to function prototypes.
+	(krb_get_in_tkt):  Move after krb_get_in_tkt_preauth.
+	* mk_preauth.c (krb_mk_preauth):  Declare and use key_proc_type.
+
+	* dest_tkt.c (dest_tkt), in_tkt.c (in_tkt), g_tf_fname.c
+	(krb_get_tf_fullname): If ticket cache selector is null, use
+	default cache.  (Cache selector used to be the result of
+	tkt_string; now tkt_string is called when it is null.)
+
+	* send_to_kdc.c:  Replace all debug printf's with calls to
+	the DEB macro, which is a no-op unless #define DEBUG.
+	Insert #ifdef DEBUG where that is inconvenient.  (DLL libc
+	doesn't seem to have printf.)  Lint.
+
+	* g_krbrlm.c (krb_get_lrealm):  Declare as INTERFACE.
+	Break out KRB_CONF into a static variable so we can debug it
+	easier.
+	
+	* g_pw_in_tkt.c (krb_get_pw_in_tkt):  Declare as INTERFACE.
+	Give an explicit error if the supplied password is null;
+	this forces the caller to supply us one, rather than relying
+	on a Kerberos library routine to interact with the user.  Lint.
+	(passwd_to_key):  Make extern.  Don't call *_read_password.
+	(krb_get_pw_in_tkt_preauth):  Give error for null password.	
+	(placebo_read_password):  Add FIXME comment.
+
+	* kerberos.def:  Use PASCAL calling sequence (uppercase names,
+	no leading underlines) for interface functions.
+
+	* in_tkt.c, g_pw_in_tkt.c, kparse.c:  Remove RCS crud.
+
+Fri May 27 09:25:14 1994  John Gilmore  (gnu@cygnus.com)
+
+	Initial Dynamic Link Library support for MS-Windows.
+
+	* Makefile.in:  Move more files to only build on SERVER machines.
+	(kerberos.dll, c-krbdll.rsp):  Build dynamic link library for
+	MS-Windows.
+	(kerberos.lib):  Build import library for MS-Windows.
+	(all-windows, install-windows):  New targets for MS-Windows.
+
+	* kerberos.def:  New file defines the Kerberos DLL interface.
+
+	* winsock.def:  New file defines the WinSock DLL interface that
+	we rely upon.  This file is from FTP:
+	//sunsite.unc.edu/pub/micro/pc-stuff/ms-windows/winsock/winsock-1.1
+	except that we made all the routine names uppercase, to match what
+	MicroSoft C does when you declare an interface routine PASCAL
+	(like all these routines).
+
+	* err_txt.c (krb_get_err_table, krb_get_err_text):  New
+	functions for DLL access to the error table.
+
+	* g_admhst.c, g_cred.c, g_krbhst.c, g_phost.c, g_svc_in_tkt.c,
+	kname_parse.c, mk_err.c, mk_priv.c, mk_req.c, mk_safe.c, rd_err.c,
+	rd_priv.c, rd_req.c, rd_safe.c, realmofhost.c, recvauth.c,
+	sendauth.c: Add INTERFACE declaration to definitions of functions
+	that are exported via the DLL interface.
+
+	* win_glue.c (win_time_gmt_unixsec):  Use static storage for
+	_ftime() arg, since it takes a near pointer and can't point to
+	stack storage when SS!=DS.
+	(in_tkt, save_credentials, krb_save_credentials, krb_get_cred,
+	dest_tkt, krb_get_tf_realm, krb_set_tkt_string,
+	krb_ignore_ip_address):  Dummy routines for now.
+	(LibMain, WEP):  No-op routines required for DLL initialization.
+	(krb_start_session, krb_end_session): No-op routines required for
+	Kerberos Mac interface compatability.
+
+	* save_creds.c (krb_save_credentials):  Add new interface function
+	to replace save_credentials, which isn't well enough named to
+	export as part of the Kerberos interface.
+
+	* kname_parse.c, kparse.c, rd_safe.c, send_to_kdc.c:  Move
+	printf's under #ifdef DEBUG since printf is not usually available
+	in MS-Windows.  Change exit()'s under "can't happen" conditions to
+	return statements.
+
+	* g_krbhst.c:  Clean up #ifdef'd braces so they match up.
+	* sendauth.c:  Remove unused "extern int errno;".
+	* kname_parse.c:  Remove unused extern of krb_err_txt.
+	* mk_err.c, save_creds.c:  Remove RCS crud.
+	* ren.msg:  Add rd_preauth.c and mk_preauth.c to DOS rename table.
+
+Wed May 25 09:17:06 1994  D V Henkel-Wallace  (gumby@tweedledumb.cygnus.com)
+
+	* g_pw_in_tkt.c: when read_password.c was inserted whole into this
+	file, des.h and conf.h were #include'ed, which causes circularity
+	problems.  #include's removed; they weren't needed anyway.
+
+Tue May 24 00:55:30 1994  John Gilmore  (gnu@cygnus.com)
+
+	* sendauth.c:  Break up into separately callable functions to
+	avoid pushing binary data down a socket supposedly controlled
+	by the kerberos library's caller.
+	(krb_mk_auth):  New; builds a packet and returns it to you.
+	(krb_net_rd_sendauth):  Reads a packet from the net.
+	(krb_check_auth):  Checks an incoming response for validity.
+	FIXME:  ATHENA_COMPAT code in here is now broken.  Remove it?
+	FIXME:  Break up into separate files so that the non file
+	descriptor part can be included on Mac.
+
+	* g_admhst.c, mk_req.c:  Pull RCS crud.
+
+	* mk_req.c:  Allow the realm argument to be defaulted with a null
+	pointer.  This makes it suitable for building krb_sendauth
+	messages directly.
+
+	* tf_util.c (tf_init): If argument is null, call tkt_string to
+	select a ticket cache.  See also ../../include/krb-sed.h, where
+	the default argument was changed to be null.
+
+	* send_to_kdc.c (MAX_HSTNM):  Eliminate only use of this obsolete
+	define; use MAXHOSTNAMELEN which is set properly in each system.
+
+	* fakeenv.c:  Update copyright notice (it's now public domain,
+	freed by Cygnus Support, for whom the work was done for hire).
+
+Mon May 23 00:19:46 1994  Mark Eichin  (eichin at tweedledumb.cygnus.com)
+
+	* rd_svc_key.c (get_service_key): new function. Same as original
+	read_service_key except that it takes argument kvno by reference,
+	so the caller can figure out what key actually matched. Also
+	defaults to KEYFILE if file argument is NULL (instead of just
+	calling open with that value.) Also defaults to current realm if
+	realm argument not passed in.
+	(read_service_key): now calls get_service_key.
+
+	* rd_safe.c (krb_rd_safe): check krb_ignore_ip_address before
+	deciding to fail on an IP address check.
+	(krb_rd_safe): remove "direction checking" code which doesn't
+	actually help, and can interfere if IP addresses are optional.
+
+	* rd_req.c (krb_rd_req): check krb_ignore_ip_address before
+	deciding to fail on an IP address check; move test to end of
+	function as well (to provide more information value in the
+	RD_AP_BADD error return.)
+
+	* rd_req.c: define (allocate) krb_ignore_ip_address.
+
+	* rd_priv.c (krb_rd_priv): check global variable
+	krb_ignore_ip_address before deciding to fail on an IP address
+	check.
+	(krb_rd_priv): remove "direction checking" code which doesn't
+	actually help, and can interfere if IP addresses are optional.
+
+	* netread.c (krb_net_read): use socket_read under VMS, assuming
+	MultiNet. 
+
+	* netwrite.c (krb_net_write): use socket_write under VMS, assuming
+	MultiNet. 
+
+	* mk_priv.c (krb_mk_priv): If private_msg_ver isn't set yet, use
+	the expected version (KRB_PROT_VERSION) instead.
+
+	* Makefile.in (SRCS, OBJS): added mk_preauth, rd_preauth.
+
+	* g_in_tkt.c (krb_get_in_tkt_preauth): New function. Supports
+	simple preauthentication by appending data to the initial packet.
+	Demonstration hooks only.
+
+	* g_svc_in_tkt.c (krb_get_svc_in_tkt_preauth): New function.
+	Preauthentication support for initial tickets for servers.
+	(krb_svc_init): New function. An interface to krb_get_svc_in_tkt
+	that is provided by DEC's dss-kerberos, added here for
+	compatibility.
+	(krb_svc_init_preauth): preauthentication version of krb_svc_init.
+
+	* g_pw_in_tkt.c	(krb_get_pw_in_tkt_preauth): New function.
+	Higher level interface to g_in_tkt for users.
+
+	* g_pw_in_tkt.c: in NOENCRYPTION section, pull in <sgtty.h>
+	under __svr4__ so the ioctls work under Solaris.
+
+Sat May 21 04:02:59 1994  John Gilmore  (gnu@cygnus.com)
+
+	* Makefile.in (c-libkrb.${LIBEXT}):  Typos, do .o->.obj.
+	* gethostname.c:  Simplify to call GETHOSTNAME macro.
+	* stime.c:  Arg is *time, not time.  Oops.  Also simplify.
+	* win_glue.c:  Support CONVERT_TIME_EPOCH and make it work
+	for the odd epoch on MSC 7.0.
+	(win_socket_initialize):  New routine implements SOCKET_INITIALIZE.
+	(in_tkt, save_credentials, dest_tkt):  Stubs to link kinit with.
+
+	First FAR crap in our clean sources (sigh).
+
+	* win_glue.c (far_fputs):  Print a far string returned by WinSock.
+	* ad_print.c:  Handle FAR pointer from inet_ntoa.
+	* g_phost.c:  Handle FAR pointer returned by gethostby*.
+	
+	* send_to_kdc.c: Convert to WinSock plus local macros that make
+	compatability easier.  Initialize and terminate WinSock access
+	each time we are called.  Handle FAR pointer from get*by* and
+	inet_ntoa.  Bind the datagram socket before using it, to get
+	beyond a bug in FTP Software's WinSock libraries.  Improve debug
+	messages.
+
+Thu May 19 22:57:13 1994  John Gilmore  (gnu@cygnus.com)
+
+	More Windows support.
+
+	* Makefile.in (LIBEXT):  Use everywhere.
+	(SERVER_KRB_{SRCS,OBJS}):  Rename from SERVERSIDE*.
+	(ARCHIVEARGS):  Implement MSC LIB support.
+	(####):  Move insertion point of host-configuration fragments
+	down so they can override the various Makefile macros.
+	(libkrb.$(LIBEXT)):  Avoid keeping a .bak file.  Use ARCHIVEARGS.
+	(unixdos):  New target for things that have to run on Unix
+	after configuring for DOS.  (FIXME, make these work on DOS.)
+	(c-libkrb.$(LIBEXT)):  Build control file for MSC.  This
+	currently must run on Unix (FIXME).
+
+	* stime.c:  Use CONVERT_TIME_EPOCH.
+
+Sat May 14 00:49:11 1994  John Gilmore  (gnu@cygnus.com)
+
+	More Macintosh merging.
+
+	* Makefile.in (CACHESRCS, CACHEOBJS, REALMDBSRCS, REALMDBOBJS,
+	SERVERSIDESRCS, SERVERSIDEOBJS):  Update the lists of files that
+	belong to each category.
+	* unix-glue.c, mac-glue.c, win-glue.c:  Rename to unix_glue.c,
+	mac_glue.c, win_glue.c.
+	* g_ad_tkt.c:  Improve comments on cross-realm support.
+	* g_phost.c:  Remove RCS crud.
+	* store.c, store.h:  Rename to mac_store.c, mac_store.h.  Insert
+	all the Kerberos glue routines needed to talk to the Cygnus code.
+
+Fri May 13 17:40:02 1994  John Gilmore  (gnu@cygnus.com)
+
+	* Makefile.in (SERVERSIDESRCS, SERVERSIDEOBJS):  Create
+	as lists of lib/krb files only used on servers, so they can
+	be avoided when on client-only machines.
+	(CACHESRCS, CACHEOBJS):  Put all the rightful files in there.
+	* realmofhost.c:  Pull <sys/param.h> and default MAXHOSTNAMELEN.
+	* dest_tkt.c, realmofhost.c, tf_shm.c:  Remove RCS crud.
+	* rd_safe.c, tf_shm.c:  Remove errno declaration, <errno.h>, etc.
+	* mk_priv.c:  Comment changes.
+	* g_ad_tkt.c:  Remove obsolete defn of <sys/time.h>.
+
+Fri May 13 12:17:32 1994  John Gilmore  (gnu@cygnus.com)
+
+	Macintosh changes.
+
+	* store.h, store.c:  Ticket storage in memory on the Mac.
+	* mac-glue.c:  New file, deals with OS and time interface.
+	* Makefile.in:  Pull tf_util.[co] out into CACHESRCS and
+	CACHEOBJS, so it can be excluded on Mac and Windows.
+	* g_in_tkt.c:  Don't declare signed difference t_diff as unsigned!
+	* g_ad_tkt.c, rd_safe.c, rd_req.c, rd_priv.c, mk_safe.c, mk_req.c:
+	Remove <sys/time.h>.  Use TIME_GMT_UNIXSEC and clean up datatype
+	issues around clock-skew/ticket-replay checking.  Remove __i960__
+	conditionals, which should be handled by changing CLOCK_SKEW in
+	960-specific config files.
+	* mk_priv.c:  Rename TIME_GMT_UNIXSEC_MS to TIME_GMT_UNIXSEC_US.
+	* setenv.c:  Remove <sys/types.h>.
+	* rd_priv.c, mk_safe.c:  Remove <errno.h>, and decls of errno and
+	errmsg.
+	* rd_req.c, stime.c, mk_safe.c:  Remove RCS crud.
+
+Fri May 13 02:02:56 1994  John Gilmore  (gnu@cygnus.com)
+
+	* Makefile.in:  Support glue files for each major architecture
+	(Unix, mac, windows).  Replace {} with () for DOS NMAKE.
+	Build krb_err.h without `make depend'.  Remove -DBSD42 since it
+	is no longer used.
+	* unix-glue.c:  New file, interfaces to Unix gettimeofday.
+	* win-glue.c:  New file, interfaces to Windows _ftime.
+	* g_in_tkt.c, mk_priv.c:  Pull <sys/time.h>, use new macro interface
+	TIME_GMT_UNIXSEC to get the time.
+	* gethostname.c:  Pull BSD42.  Insert FIXME comments about the
+	poor DOS support.
+	* mk_priv.c:  Pull <errno.h>, errno, and errmsg as unused.
+
+	* ad_print.c:  Pull <arpa/inet.h>, which is now in <krb.h>.
+	* decomp_tkt.c:  Add file name to title comments.
+	* fakeenv.c:  Pull <sys/types.h> and <stdio.h>.
+	* g_phost.c:  Replace <netdb.h> and <osconf.h> with <krb.h>.
+	* ren.msg:  Remove get_request.c (g_request.c), now gone.
+	* send_to_kdc.c:  Pull <netdb.h>.
+	* setenv.c:  Add "conf.h" for non-cmd-line configuration.
+
+Sun May  8 23:34:16 1994  John Gilmore  (gnu@cygnus.com)
+
+	Include-file straightening:  Remove Unix include
+	files from as many routines as possible -- particularly
+	<sys/types.h> and network include files.
+
+	* ad_print.c:  Use DEFINE_SOCKADDR to get struct sockaddr_in.
+	Lint.  Pull RCS crud.
+	* cr_err_repl.c, tf_shm.c, tf_util.c, tkt_string.c:  Pull
+	<sys/types.h>.
+	* cr_tkt.c, decomp_tkt.c:  Pull <stdio.h>.
+	* dest_tkt.c, in_tkt.c, mk_err.c:  Pull <sys/types.h>
+	* g_ad_tkt.c:  Pull <sys/types.h>, <errno.h>, RCS crud.
+	* g_cred.c:  Pull RCS crud, add <string.h>.
+	* g_in_tkt.c:  Pull <sys/types.h>, <errno.h>, <stdio.h>, RCS crud.
+	* g_tf_fname.c:  Lint, pull RCS crud.
+	* kuserok.c:  <pull <sys/types.h> and <sys/socket.h>.
+	* rd_err.c:  Pull <stdio.h>, <errno.h>, <sys/types.h>, <sys/times.h>.
+	* mk_priv.c, mk_safe.c, rd_err.c, rd_priv.c, rd_safe.c,
+	recvauth.c, send_to_kdc.c, sendauth.c:  Use DEFINE_SOCKADDR to get
+	struct sockaddr_in.
+	* cr_tkt.c, debug.c, mk_safe.c, rd_err.c, rd_safe.c, recvauth.c,
+	sendauth.c:  Pull RCS crud. 
+	* rd_safe.c, sendauth.c:  Lint.
+	* strcasecmp.c:  Remove <sys/types.h> and change the few
+	occurrances of u_foo types to `unsigned foo'.  Pull SCCS crud(!).
+
+Sun May  8 19:24:08 1994  John Gilmore  (gnu@cygnus.com)
+
+	* add_tkt.c, ext_tkt.c:  Remove, unused.  As its comments say:
+	This routine is now obsolete.  It used to be possible to request
+	more than one ticket at a time from the authentication server, and
+	it looks like this routine was used by the server to package the
+	tickets to be returned to the client.
+
+	* g_request.c:  Remove, unused.  Its comments:
+	This procedure is obsolete.  It is used in the kerberos_slave
+	code for Version 3 tickets.
+
+	* getopt.c:  Remove, unused.
+	* Makefile.in:  Remove unused files.
+
+Sat May  7 13:44:20 1994  John Gilmore  (gnu@cygnus.com)
+
+	* krbglue.c:  Remove, unused.  Mark Eichin says:
+	krbglue, if I recall correctly, was backwards compatibility code so
+	that programs that were written with V3 could be relinked with V4
+	without recompiling. The Zephyr code used it at one point, though I
+	doubt it does anymore. It's probably sufficient to note that in the
+	cvs log when you delete it.
+
+	* krbglue.c, recvauth.c, sendauth.c:  Lint.
+
+Fri May  6 21:11:10 1994  John Gilmore  (gnu@cygnus.com)
+
+	* ren-cyg.sh, ren-pc.sh, ren-pl10.sh, ren.msg.sh, ren2dos,
+	ren2long.sh sed-cyg.sh, ren-pc.bat, sed-pc.sh:  Update for final
+	DOS renaming.
+
+Fri May  6 18:32:11 1994  John Gilmore  (gnu@cygnus.com)
+
+	* rd_priv.c, mk_priv.c, rd_safe.c, mk_safe.c:  Rename include
+	file "lsb_addr_comp.h" to "lsb_addr_cmp.h" for DOS/SYSV.
+
+Fri May  6 02:10:50 1994  John Gilmore  (gnu@cygnus.com)
+
+	* krbglue.c: Move Kerberos function prototypes to ../include/krb.h.
+	Yank RCS.  Lint.
+	* mk_priv.c (krb_mk_priv), rd_priv.c (krb_rd_priv):  Lint.  Yank RCS.
+
+Thu May  5 12:49:34 1994  John Gilmore  (gnu@cygnus.com)
+
+	* decomp_tkt.c: Remove need for <sys/file.h> under KRB_CRYPT_DEBUG
+	by using stdio.  Call krb_log, not log.  Lint.  Remove RCS ID's.
+
+	* g_tf_realm.c:  Lint.
+
+Tue Apr 26 20:54:29 1994  John Gilmore  (gnu@tweedledumb.cygnus.com)
+
+	Massive file renaming for DOS compatability.
+
+	* ren.msg, ren-cyg.sh, sed-cyg.sh:  New files.
+
+	* Imakefile, Makefile.in:  File names edited throughout.
+
+	* add_ticket.c, cr_auth_reply.c, cr_err_reply.c, create_ciph.c,
+	create_ticket.c, debug_decl.c, decomp_ticket.c, extract_tkt.c,
+	get_ad_tkt.c, get_admhst.c, get_cred.c, get_in_tkt.c, get_krbhst.c,
+	get_krbrlm.c, get_phost.c, get_pw_tkt.c, get_request.c, get_svc_in.c,
+	get_tf_fname.c, get_tf_realm.c, getrealm.c, k_gethostname.c,
+	krb_err_txt.c, krb_get_in.c, read_svc_key.c, util.c:  Renamed.
+
+	* ad_print.c, add_tkt.c, cr_auth_repl.c, cr_ciph.c, cr_err_repl.c,
+	cr_tkt.c, debug.c, decomp_tkt.c, err_txt.c, ext_tkt.c, g_ad_tkt.c,
+	g_admhst.c, g_cred.c, g_in_tkt.c, g_krbhst.c, g_krbrlm.c,
+	g_phost.c, g_pw_in_tkt.c, g_pw_tkt.c, g_request.c, g_svc_in_tkt.c,
+	g_tf_fname.c, g_tf_realm.c, gethostname.c, rd_svc_key.c,
+	realmofhost.c:  Same files, renamed.
+
+Sun Jan 30 17:28:57 1994  Ken Raeburn  (raeburn@cujo.cygnus.com)
+
+	* getrealm.c (krb_realmofhost): Rearrange loop so that strcasecmp
+	is called only once for domains listed in krb.conf, and exiting
+	function is cleaner.
+
diff --git a/mechglue/src/lib/krb4/FSp-glue.c b/mechglue/src/lib/krb4/FSp-glue.c
new file mode 100644
index 000000000..7bf0e7b54
--- /dev/null
+++ b/mechglue/src/lib/krb4/FSp-glue.c
@@ -0,0 +1,112 @@
+/*
+ * lib/krb4/FSp-glue.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2002 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * MacOS-specific glue for using FSSpecs to deal with srvtabs.
+ */
+
+#include "krb.h"
+#include "krb4int.h"
+#include <stdio.h>
+#include <string.h>
+
+#include <Kerberos/FSpUtils.h>
+/* 
+ * These functions are compiled in for ABI compatibility with older versions of KfM.
+ * They are deprecated so they do not appear in the KfM headers anymore.
+ * 
+ * Do not change their ABIs!
+ */
+int KRB5_CALLCONV FSp_krb_get_svc_in_tkt (char *, char *, char *, char *, char *, int, const FSSpec *);
+int KRB5_CALLCONV FSp_put_svc_key (const FSSpec *, char *, char *, char *, int, char *);
+int KRB5_CALLCONV FSp_read_service_key (char *, char *, char *, int, const FSSpec*, char *);
+
+static int FSp_srvtab_to_key (char *, char *, char *, char *, C_Block);
+
+int KRB5_CALLCONV
+FSp_read_service_key(
+    char *service,              /* Service Name */
+    char *instance,             /* Instance name or "*" */
+    char *realm,                /* Realm */
+    int kvno,                   /* Key version number */
+    const FSSpec *filespec,     /* Filespec */
+    char *key)                  /* Pointer to key to be filled in */
+{
+    int retval = KFAILURE;
+    char file [MAXPATHLEN];
+    if (filespec != NULL) {
+        if (FSSpecToPOSIXPath (filespec, file, sizeof(file)) != noErr) {
+            return retval;
+        }
+    }
+    retval = read_service_key(service, instance, realm, kvno, file, key);
+    if (file != NULL) {
+        free (file);
+    }
+    return retval;
+}
+
+int KRB5_CALLCONV
+FSp_put_svc_key(
+    const FSSpec *sfilespec,
+    char *name,
+    char *inst,
+    char *realm,
+    int newvno,
+    char *key)
+{
+    int retval = KFAILURE;
+    char sfile[MAXPATHLEN];
+
+    if (sfilespec != NULL) {
+        if (FSSpecToPOSIXPath (sfilespec, sfile, sizeof(sfile)) != noErr) {
+            return retval;
+        }
+    }
+    retval = put_svc_key(sfile, name, inst, realm, newvno, key);
+    if (sfile != NULL) {
+        free (sfile);
+    }
+    return retval;
+}
+
+int KRB5_CALLCONV
+FSp_krb_get_svc_in_tkt(
+    char *user, char *instance, char *realm, 
+    char *service, char *sinstance, int life,
+    const FSSpec *srvtab)
+{
+    /* Cast the FSSpec into the password field.  It will be pulled out again */
+    /* by FSp_srvtab_to_key and used to read the real password */
+    return krb_get_in_tkt(user, instance, realm, service, sinstance,
+                          life, FSp_srvtab_to_key, NULL, (char *)srvtab);
+}
+
+static int FSp_srvtab_to_key(char *user, char *instance, char *realm, 
+			     char *srvtab, C_Block key)
+{
+    /* FSp_read_service_key correctly handles a NULL FSSpecPtr */
+    return FSp_read_service_key(user, instance, realm, 0,
+				(FSSpec *)srvtab, (char *)key);
+}
diff --git a/mechglue/src/lib/krb4/Makefile.in b/mechglue/src/lib/krb4/Makefile.in
new file mode 100644
index 000000000..6aff2077a
--- /dev/null
+++ b/mechglue/src/lib/krb4/Makefile.in
@@ -0,0 +1,604 @@
+thisconfigdir=.
+myfulldir=lib/krb4
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCALINCLUDES = -I$(BUILDTOP)/include/kerberosIV -I$(srcdir)/../../include/kerberosIV -I.
+DEFINES= -DKRB4_USE_KEYTAB
+
+##DOS##BUILDTOP = ..\..
+##DOS##LIBNAME=$(OUTPRE)krb4.lib
+##DOS##OBJFILE=$(OUTPRE)krb4.lst
+
+LIBBASE=krb4
+LIBMAJOR=2
+LIBMINOR=0
+RELDIR=krb4
+
+# Depends on libk5crypto, libkrb5, KRB4_CRYPTO_LIB and _et_list...
+# Depends on libkrb5, expect to find
+#	krb5_init_context, krb5_free_context, profile_get_values
+#
+KRB4_CRYPTO_LIBS=-ldes425
+
+SHLIB_EXPDEPS = \
+	$(TOPLIBD)/libdes425$(SHLIBEXT) \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(TOPLIBD)/libkrb5$(SHLIBEXT)
+SHLIB_EXPLIBS=-lkrb5 -lcom_err -ldes425 -lk5crypto
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+EHDRDIR=$(BUILDTOP)$(S)include$(S)kerberosIV
+KRB_ERR=@KRB_ERR@
+##DOS##KRB_ERR=$(OUTPRE)krb_err.$(OBJEXT)
+
+# Name of generated krb_err.c, needed for err_txt.* dependency on Darwin.
+KRB_ERR_C=@KRB_ERR_C@
+##DOS##KRB_ERR_C=
+
+OBJS	= \
+	$(OUTPRE)change_password.$(OBJEXT) \
+	$(OUTPRE)cr_auth_repl.$(OBJEXT) \
+	$(OUTPRE)cr_ciph.$(OBJEXT) \
+	$(OUTPRE)cr_tkt.$(OBJEXT) \
+	$(OUTPRE)debug.$(OBJEXT) \
+	$(OUTPRE)decomp_tkt.$(OBJEXT) \
+	$(OUTPRE)err_txt.$(OBJEXT) \
+	$(OUTPRE)g_ad_tkt.$(OBJEXT) \
+	$(OUTPRE)g_in_tkt.$(OBJEXT) \
+	$(OUTPRE)g_phost.$(OBJEXT) \
+	$(OUTPRE)g_pw_in_tkt.$(OBJEXT) \
+	$(OUTPRE)g_pw_tkt.$(OBJEXT) \
+	$(OUTPRE)g_tkt_svc.$(OBJEXT) \
+	$(OUTPRE)gethostname.$(OBJEXT) \
+	$(OUTPRE)getst.$(OBJEXT) \
+	$(OUTPRE)kadm_err.$(OBJEXT) \
+	$(OUTPRE)kadm_net.$(OBJEXT) \
+	$(OUTPRE)kadm_stream.$(OBJEXT) \
+	$(OUTPRE)kname_parse.$(OBJEXT) \
+	$(OUTPRE)lifetime.$(OBJEXT) \
+	$(OUTPRE)mk_auth.$(OBJEXT) \
+	$(OUTPRE)mk_err.$(OBJEXT) \
+	$(OUTPRE)mk_priv.$(OBJEXT) \
+	$(OUTPRE)mk_req.$(OBJEXT) \
+	$(OUTPRE)mk_safe.$(OBJEXT) \
+	$(OUTPRE)month_sname.$(OBJEXT) \
+	$(OUTPRE)password_to_key.$(OBJEXT) \
+	$(OUTPRE)prot_client.$(OBJEXT) \
+	$(OUTPRE)prot_common.$(OBJEXT) \
+	$(OUTPRE)prot_kdc.$(OBJEXT) \
+	$(OUTPRE)pkt_cipher.$(OBJEXT) \
+	$(OUTPRE)pkt_clen.$(OBJEXT) \
+	$(OUTPRE)rd_err.$(OBJEXT) \
+	$(OUTPRE)rd_priv.$(OBJEXT) \
+	$(OUTPRE)rd_safe.$(OBJEXT) \
+	$(OUTPRE)send_to_kdc.$(OBJEXT) \
+	$(OUTPRE)stime.$(OBJEXT) \
+	$(OUTPRE)strnlen.$(OBJEXT) \
+	$(OUTPRE)rd_preauth.$(OBJEXT) \
+	$(OUTPRE)mk_preauth.$(OBJEXT) \
+	$(OSOBJS) $(CACHEOBJS) $(SETENVOBJS) $(STRCASEOBJS) $(SHMOBJS) \
+	$(LIB_KRB_HOSTOBJS) $(SERVER_KRB_OBJS) $(NETIO_OBJS) $(REALMDBOBJS) $(KRB_ERR)
+
+SRCS = \
+	change_password.c \
+	cr_auth_repl.c \
+	cr_ciph.c \
+	cr_tkt.c \
+	debug.c \
+	decomp_tkt.c \
+	g_ad_tkt.c \
+	g_pw_in_tkt.c \
+	g_phost.c \
+	g_pw_tkt.c \
+	g_tkt_svc.c \
+	getst.c \
+	gethostname.c \
+	kadm_err.c \
+	kadm_net.c \
+	kadm_stream.c \
+	kname_parse.c \
+	err_txt.c \
+	lifetime.c \
+	g_in_tkt.c \
+	mk_auth.c \
+	mk_err.c \
+	mk_priv.c \
+	mk_req.c \
+	mk_safe.c \
+	month_sname.c \
+	password_to_key.c \
+	pkt_cipher.c \
+	pkt_clen.c \
+	prot_client.c \
+	prot_common.c \
+	prot_kdc.c \
+	rd_err.c \
+	rd_priv.c \
+	rd_safe.c \
+	send_to_kdc.c \
+	stime.c \
+	strnlen.c \
+	rd_preauth.c \
+	mk_preauth.c \
+	unix_time.c \
+	$(OSSRCS) $(CACHESRCS) $(SETENVSRCS) $(STRCASESRCS) $(SHMSRCS) \
+	$(LIB_KRB_HOSTSRCS) $(SERVER_KRB_SRCS) $(NETIO_SRCS) $(REALMDBSRCS)
+
+STLIBOBJS  = $(OBJS)
+STOBJLISTS=OBJS.ST
+
+#
+# These objects implement the time computation routines.
+#
+OSOBJS = $(OUTPRE)unix_time.$(OBJEXT)
+OSSRCS = unix_time.c
+
+##DOS##OSOBJS = $(OUTPRE)win_time.obj
+
+#
+# These objects implement ticket cacheing for Unix.  They are
+# replaced by other files when compiling for Windows or Mac.
+#
+CACHESRCS = \
+	tf_util.c	dest_tkt.c	in_tkt.c \
+	tkt_string.c	g_tf_fname.c	g_tf_realm.c \
+	g_cred.c	save_creds.c
+CACHEOBJS = \
+	$(OUTPRE)tf_util.$(OBJEXT) $(OUTPRE)dest_tkt.$(OBJEXT) $(OUTPRE)in_tkt.$(OBJEXT) \
+	$(OUTPRE)tkt_string.$(OBJEXT) $(OUTPRE)g_tf_fname.$(OBJEXT) $(OUTPRE)g_tf_realm.$(OBJEXT) \
+	$(OUTPRE)g_cred.$(OBJEXT) $(OUTPRE)save_creds.$(OBJEXT)
+
+##DOS##CACHEOBJS = $(OUTPRE)memcache.$(OBJEXT)
+
+#
+# These objects implement Kerberos realm<->host database lookup.
+# They read config files and/or network databases in various ways
+# on various platforms.
+#
+
+CNFFILE = g_cnffile
+##DOS##CNFFILE = win_store
+
+REALMDBSRCS=$(CNFFILE).c RealmsConfig-glue.c
+REALMDBOBJS=$(OUTPRE)$(CNFFILE).$(OBJEXT) $(OUTPRE)RealmsConfig-glue.$(OBJEXT)
+
+#
+# These objects are only used on server or debug implementations of Kerberos,
+# and they cause some major or minor sort of trouble for some
+# client-only platform (Mac or Windows).
+#
+SERVER_KRB_SRCS = \
+	klog.c		kuserok.c	log.c \
+	kntoln.c \
+	fgetst.c	rd_svc_key.c	cr_err_repl.c \
+	rd_req.c	g_svc_in_tkt.c	recvauth.c \
+	ad_print.c	cr_death_pkt.c \
+	kparse.c	put_svc_key.c	sendauth.c
+SERVER_KRB_OBJS = \
+	$(OUTPRE)klog.$(OBJEXT) $(OUTPRE)kuserok.$(OBJEXT) $(OUTPRE)log.$(OBJEXT) \
+	$(OUTPRE)kntoln.$(OBJEXT) \
+	$(OUTPRE)fgetst.$(OBJEXT) $(OUTPRE)rd_svc_key.$(OBJEXT) $(OUTPRE)cr_err_repl.$(OBJEXT) \
+	$(OUTPRE)rd_req.$(OBJEXT) $(OUTPRE)g_svc_in_tkt.$(OBJEXT) $(OUTPRE)recvauth.$(OBJEXT) \
+	$(OUTPRE)ad_print.$(OBJEXT) $(OUTPRE)cr_death_pkt.$(OBJEXT) \
+	$(OUTPRE)kparse.$(OBJEXT) $(OUTPRE)put_svc_key.$(OBJEXT) $(OUTPRE)sendauth.$(OBJEXT)
+#
+# These objects are included on Unix and Windows (for kstream and kadm)
+# but not under Mac (there are no file descriptors).
+#
+NETIO_SRCS=netread.c netwrite.c
+NETIO_OBJS=$(OUTPRE)netread.$(OBJEXT) $(OUTPRE)netwrite.$(OBJEXT)
+
+#
+# These objects glue the Kerberos library to the operating system
+# (time-of-day access, etc).  They are replaced in Mac and Windows
+# by other _glue.* routines.
+#
+LIB_KRB_HOSTSRCS=unix_glue.c
+LIB_KRB_HOSTOBJS=$(OUTPRE)unix_glue.$(OBJEXT)
+
+##DOS##LIB_KRB_HOSTOBJS=$(OUTPRE)win_glue.obj
+
+ARCHIVEARGS= $@ $(OBJS)
+
+# We want *library* compiler options...
+DBG=$(DBG_LIB)
+
+all-unix:: includes all-liblinks
+
+##DOS##LIBOBJS = $(OBJS)
+
+# comp_et_depend(krb_err)
+krb_err.h: krb_err.et
+krb_err.c: krb_err.et
+
+kadm_err.h: kadm_err.et
+kadm_err.c: kadm_err.et
+
+GEN_ERRTXT=$(AWK) -f $(srcdir)$(S)et_errtxt.awk outfile=$@
+
+krb_err_txt.c: krb_err.et $(srcdir)$(S)et_errtxt.awk
+	$(GEN_ERRTXT) $(srcdir)/krb_err.et
+
+# Will be empty on Darwin, krb_err_txt.c elsewhere.
+KRB_ERR_TXT=@KRB_ERR_TXT@
+##DOS##KRB_ERR_TXT=krb_err_txt.c
+err_txt.so err_txt.po $(OUTPRE)err_txt.$(OBJEXT): err_txt.c $(KRB_ERR_C) $(KRB_ERR_TXT)
+
+depend-dependencies: krb_err.h $(EHDRDIR)$(S)krb_err.h \
+	kadm_err.h $(EHDRDIR)$(S)kadm_err.h \
+	krb_err.c
+
+includes: $(EHDRDIR)$(S)krb_err.h $(EHDRDIR)$(S)kadm_err.h
+
+$(EHDRDIR)$(S)krb_err.h: krb_err.h
+	$(CP) krb_err.h $@
+$(EHDRDIR)$(S)kadm_err.h: kadm_err.h
+	$(CP) kadm_err.h $@
+
+clean-unix::
+	$(RM) $(EHDRDIR)/krb_err.h
+	$(RM) $(EHDRDIR)/kadm_err.h
+	$(RM) krb_err_txt.c
+
+clean::
+	-$(RM) $(OBJS)
+
+clean-:: clean-unix
+
+clean-unix::
+	-$(RM) krb_err.c
+	-$(RM) krb_err.h
+	-$(RM) kadm_err.c
+	-$(RM) kadm_err.h
+	-$(RM) ../../include/kerberosIV/krb_err.h
+	-$(RM) ../../include/kerberosIV/kadm_err.h
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+
+check-unix:: $(TEST_PROGS)
+check-windows::
+
+
+install-unix:: install-libs
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+change_password.so change_password.po $(OUTPRE)change_password.$(OBJEXT): \
+  change_password.c $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h krb4int.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/kerberosIV/kadm.h $(SRCTOP)/include/kerberosIV/prot.h
+cr_auth_repl.so cr_auth_repl.po $(OUTPRE)cr_auth_repl.$(OBJEXT): \
+  cr_auth_repl.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+cr_ciph.so cr_ciph.po $(OUTPRE)cr_ciph.$(OBJEXT): cr_ciph.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+cr_tkt.so cr_tkt.po $(OUTPRE)cr_tkt.$(OBJEXT): cr_tkt.c \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/des.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h $(SRCTOP)/include/kerberosIV/prot.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+debug.so debug.po $(OUTPRE)debug.$(OBJEXT): debug.c \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h
+decomp_tkt.so decomp_tkt.po $(OUTPRE)decomp_tkt.$(OBJEXT): \
+  decomp_tkt.c $(SRCTOP)/include/kerberosIV/des.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h $(BUILDTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb54proto.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+g_ad_tkt.so g_ad_tkt.po $(OUTPRE)g_ad_tkt.$(OBJEXT): \
+  g_ad_tkt.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+g_pw_in_tkt.so g_pw_in_tkt.po $(OUTPRE)g_pw_in_tkt.$(OBJEXT): \
+  g_pw_in_tkt.c $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(BUILDTOP)/include/profile.h krb4int.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+g_phost.so g_phost.po $(OUTPRE)g_phost.$(OBJEXT): g_phost.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+g_pw_tkt.so g_pw_tkt.po $(OUTPRE)g_pw_tkt.$(OBJEXT): \
+  g_pw_tkt.c $(SRCTOP)/include/kerberosIV/mit-copyright.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+g_tkt_svc.so g_tkt_svc.po $(OUTPRE)g_tkt_svc.$(OBJEXT): \
+  g_tkt_svc.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+getst.so getst.po $(OUTPRE)getst.$(OBJEXT): getst.c \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h krb4int.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+gethostname.so gethostname.po $(OUTPRE)gethostname.$(OBJEXT): \
+  gethostname.c $(SRCTOP)/include/kerberosIV/mit-copyright.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+kadm_err.so kadm_err.po $(OUTPRE)kadm_err.$(OBJEXT): \
+  kadm_err.c $(COM_ERR_DEPS)
+kadm_net.so kadm_net.po $(OUTPRE)kadm_net.$(OBJEXT): \
+  kadm_net.c $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/krbports.h $(SRCTOP)/include/kerberosIV/kadm.h \
+  $(BUILDTOP)/include/kerberosIV/kadm_err.h $(SRCTOP)/include/kerberosIV/prot.h
+kadm_stream.so kadm_stream.po $(OUTPRE)kadm_stream.$(OBJEXT): \
+  kadm_stream.c $(SRCTOP)/include/kerberosIV/kadm.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(BUILDTOP)/include/kerberosIV/kadm_err.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+kname_parse.so kname_parse.po $(OUTPRE)kname_parse.$(OBJEXT): \
+  kname_parse.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+err_txt.so err_txt.po $(OUTPRE)err_txt.$(OBJEXT): err_txt.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+lifetime.so lifetime.po $(OUTPRE)lifetime.$(OBJEXT): \
+  lifetime.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h
+g_in_tkt.so g_in_tkt.po $(OUTPRE)g_in_tkt.$(OBJEXT): \
+  g_in_tkt.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+mk_auth.so mk_auth.po $(OUTPRE)mk_auth.$(OBJEXT): mk_auth.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+mk_err.so mk_err.po $(OUTPRE)mk_err.$(OBJEXT): mk_err.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+mk_priv.so mk_priv.po $(OUTPRE)mk_priv.$(OBJEXT): mk_priv.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h $(SRCTOP)/include/kerberosIV/lsb_addr_cmp.h \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+mk_req.so mk_req.po $(OUTPRE)mk_req.$(OBJEXT): mk_req.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h krb4int.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+mk_safe.so mk_safe.po $(OUTPRE)mk_safe.$(OBJEXT): mk_safe.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h $(SRCTOP)/include/kerberosIV/lsb_addr_cmp.h \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+month_sname.so month_sname.po $(OUTPRE)month_sname.$(OBJEXT): \
+  month_sname.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+password_to_key.so password_to_key.po $(OUTPRE)password_to_key.$(OBJEXT): \
+  password_to_key.c $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h krb4int.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+pkt_cipher.so pkt_cipher.po $(OUTPRE)pkt_cipher.$(OBJEXT): \
+  pkt_cipher.c $(SRCTOP)/include/kerberosIV/mit-copyright.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+pkt_clen.so pkt_clen.po $(OUTPRE)pkt_clen.$(OBJEXT): \
+  pkt_clen.c $(SRCTOP)/include/kerberosIV/mit-copyright.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+prot_client.so prot_client.po $(OUTPRE)prot_client.$(OBJEXT): \
+  prot_client.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+prot_common.so prot_common.po $(OUTPRE)prot_common.$(OBJEXT): \
+  prot_common.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+prot_kdc.so prot_kdc.po $(OUTPRE)prot_kdc.$(OBJEXT): \
+  prot_kdc.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+rd_err.so rd_err.po $(OUTPRE)rd_err.$(OBJEXT): rd_err.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+rd_priv.so rd_priv.po $(OUTPRE)rd_priv.$(OBJEXT): rd_priv.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h $(SRCTOP)/include/kerberosIV/lsb_addr_cmp.h \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+rd_safe.so rd_safe.po $(OUTPRE)rd_safe.$(OBJEXT): rd_safe.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h $(SRCTOP)/include/kerberosIV/lsb_addr_cmp.h \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+send_to_kdc.so send_to_kdc.po $(OUTPRE)send_to_kdc.$(OBJEXT): \
+  send_to_kdc.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/krbports.h $(SRCTOP)/include/kerberosIV/prot.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5.h $(SRCTOP)/include/krb5/kdb.h \
+  krb4int.h
+stime.so stime.po $(OUTPRE)stime.$(OBJEXT): stime.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+strnlen.so strnlen.po $(OUTPRE)strnlen.$(OBJEXT): strnlen.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+rd_preauth.so rd_preauth.po $(OUTPRE)rd_preauth.$(OBJEXT): \
+  rd_preauth.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/krb_db.h $(SRCTOP)/include/kerberosIV/prot.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+mk_preauth.so mk_preauth.po $(OUTPRE)mk_preauth.$(OBJEXT): \
+  mk_preauth.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+unix_time.so unix_time.po $(OUTPRE)unix_time.$(OBJEXT): \
+  unix_time.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+tf_util.so tf_util.po $(OUTPRE)tf_util.$(OBJEXT): tf_util.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h krb4int.h
+dest_tkt.so dest_tkt.po $(OUTPRE)dest_tkt.$(OBJEXT): \
+  dest_tkt.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/k5-util.h $(BUILDTOP)/include/krb5/autoconf.h
+in_tkt.so in_tkt.po $(OUTPRE)in_tkt.$(OBJEXT): in_tkt.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/k5-util.h $(BUILDTOP)/include/krb5/autoconf.h
+tkt_string.so tkt_string.po $(OUTPRE)tkt_string.$(OBJEXT): \
+  tkt_string.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h
+g_tf_fname.so g_tf_fname.po $(OUTPRE)g_tf_fname.$(OBJEXT): \
+  g_tf_fname.c $(SRCTOP)/include/kerberosIV/mit-copyright.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+g_tf_realm.so g_tf_realm.po $(OUTPRE)g_tf_realm.$(OBJEXT): \
+  g_tf_realm.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+g_cred.so g_cred.po $(OUTPRE)g_cred.$(OBJEXT): g_cred.c \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+save_creds.so save_creds.po $(OUTPRE)save_creds.$(OBJEXT): \
+  save_creds.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+unix_glue.so unix_glue.po $(OUTPRE)unix_glue.$(OBJEXT): \
+  unix_glue.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+klog.so klog.po $(OUTPRE)klog.$(OBJEXT): klog.c $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(BUILDTOP)/include/krb5/autoconf.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/kerberosIV/klog.h
+kuserok.so kuserok.po $(OUTPRE)kuserok.$(OBJEXT): kuserok.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+log.so log.po $(OUTPRE)log.$(OBJEXT): log.c $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(BUILDTOP)/include/krb5/autoconf.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/kerberosIV/klog.h
+kntoln.so kntoln.po $(OUTPRE)kntoln.$(OBJEXT): kntoln.c \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+fgetst.so fgetst.po $(OUTPRE)fgetst.$(OBJEXT): fgetst.c \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h krb4int.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+rd_svc_key.so rd_svc_key.po $(OUTPRE)rd_svc_key.$(OBJEXT): \
+  rd_svc_key.c $(SRCTOP)/include/kerberosIV/mit-copyright.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SRCTOP)/include/krb54proto.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+cr_err_repl.so cr_err_repl.po $(OUTPRE)cr_err_repl.$(OBJEXT): \
+  cr_err_repl.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+rd_req.so rd_req.po $(OUTPRE)rd_req.$(OBJEXT): rd_req.c \
+  $(SRCTOP)/include/kerberosIV/des.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h $(BUILDTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb54proto.h
+g_svc_in_tkt.so g_svc_in_tkt.po $(OUTPRE)g_svc_in_tkt.$(OBJEXT): \
+  g_svc_in_tkt.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h krb4int.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+recvauth.so recvauth.po $(OUTPRE)recvauth.$(OBJEXT): \
+  recvauth.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h
+ad_print.so ad_print.po $(OUTPRE)ad_print.$(OBJEXT): \
+  ad_print.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+cr_death_pkt.so cr_death_pkt.po $(OUTPRE)cr_death_pkt.$(OBJEXT): \
+  cr_death_pkt.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/kerberosIV/prot.h
+kparse.so kparse.po $(OUTPRE)kparse.$(OBJEXT): kparse.c \
+  $(SRCTOP)/include/kerberosIV/mit-copyright.h $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/kerberosIV/kparse.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+put_svc_key.so put_svc_key.po $(OUTPRE)put_svc_key.$(OBJEXT): \
+  put_svc_key.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+sendauth.so sendauth.po $(OUTPRE)sendauth.$(OBJEXT): \
+  sendauth.c $(SRCTOP)/include/kerberosIV/mit-copyright.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  krb4int.h $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+netread.so netread.po $(OUTPRE)netread.$(OBJEXT): netread.c \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h
+netwrite.so netwrite.po $(OUTPRE)netwrite.$(OBJEXT): \
+  netwrite.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/port-sockets.h
+g_cnffile.so g_cnffile.po $(OUTPRE)g_cnffile.$(OBJEXT): \
+  g_cnffile.c $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h krb4int.h
+RealmsConfig-glue.so RealmsConfig-glue.po $(OUTPRE)RealmsConfig-glue.$(OBJEXT): \
+  RealmsConfig-glue.c $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP) krb4int.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
diff --git a/mechglue/src/lib/krb4/Password.c b/mechglue/src/lib/krb4/Password.c
new file mode 100644
index 000000000..5862e0e65
--- /dev/null
+++ b/mechglue/src/lib/krb4/Password.c
@@ -0,0 +1,436 @@
+#include "kerberos.h"
+#define KRB_DEFS
+#include "krb_driver.h"
+
+#include <Types.h>
+#include <Dialogs.h>
+#include <Controls.h>
+#include <ToolUtils.h>
+#include <OSUtils.h>
+#include <Resources.h>
+
+/* 	added for OpenInitRF.c
+ 	FIXME jcm - should check that they are not in c-mac 
+	or other included file
+*/
+
+#include <Errors.h>
+#include <Files.h>
+#include <Memory.h>
+#include <Traps.h>
+#include <GestaltEqu.h>
+#include <Folders.h>
+
+
+// #include "debug.h"
+
+#define kLoginDLOGID		-4081
+#define kErrorALERTID		-4082
+#define kLoginOKItem		1
+#define kLoginCnclItem		2
+#define kLoginNameItem		10
+#define kLoginVisPwItem		9
+#define kLoginFrameItem		5
+#define kLoginIvisPwItem	6
+#define kBadUserError		1
+#define kNotUniqueError		2
+#define kGenError			3
+#define kIntegrityError		4
+#define kBadPasswordError	5
+#define cr 					0x0D
+#define enter 				0x03
+#define bs 					0x08
+#define tab 				0x09
+#define larrow 				0x1C
+#define rarrow 				0x1D
+#define uarrow 				0x1E
+#define darrow 				0x1F
+#define DialogNotDone 		1
+
+typedef union {								// used to convert ProcPtr to Handle
+	Handle		H;
+	ProcPtr		P;
+} Proc2Hand;
+
+static char gPassword [MAX_K_NAME_SZ]	= "\0";
+
+pascal void FrameOKbtn( WindowPtr myWindow, short itemNo );
+pascal Boolean TwoItemFilter( DialogPtr dlog, EventRecord *event, short *itemHit );
+
+/* 
+	FIXME jcm - begin OpenInitRF
+	Mac_store thinks that it is managing the open resource file
+	is this code in conflict?
+*/
+
+void GetExtensionsFolder(short *vRefNumP, long *dirIDP)
+{
+	Boolean hasFolderMgr = false;
+	long feature;
+	
+/*	
+	FIXME Error:   Ô_GestaltDispatchÕ has not been declared - not needed now? - jcm
+	if (TrapAvailable(_GestaltDispatch)) 
+*/
+	if (Gestalt(gestaltFindFolderAttr, &feature) == noErr) hasFolderMgr = true;
+	if (!hasFolderMgr) {
+		GetSystemFolder(vRefNumP, dirIDP);
+		return;
+	}
+	else {
+		if (FindFolder(kOnSystemDisk, kExtensionFolderType, kDontCreateFolder, vRefNumP, dirIDP) != noErr) {
+			*vRefNumP = 0;
+			*dirIDP = 0;
+		}
+	}
+}
+	
+short SearchFolderForINIT(long targetType, long targetCreator, short vRefNum, long dirID)
+{
+	HParamBlockRec fi;
+	Str255 filename;
+	short refnum;
+	
+	fi.fileParam.ioCompletion = nil;
+	fi.fileParam.ioNamePtr = filename;
+	fi.fileParam.ioVRefNum = vRefNum;
+	fi.fileParam.ioDirID = dirID;
+	fi.fileParam.ioFDirIndex = 1;
+	
+	while (PBHGetFInfo(&fi, false) == noErr) {
+		/* scan system folder for driver resource files of specific type & creator */
+		if (fi.fileParam.ioFlFndrInfo.fdType == targetType &&
+			fi.fileParam.ioFlFndrInfo.fdCreator == targetCreator) {
+			refnum = HOpenResFile(vRefNum, dirID, filename, fsRdPerm);
+			return refnum;
+			}
+		/* check next file in folder */
+		fi.fileParam.ioFDirIndex++;
+		fi.fileParam.ioDirID = dirID;	/* PBHGetFInfo() clobbers ioDirID */
+		}
+	return(-1);
+}	
+
+short OpenInitRF()
+{
+	short refnum;
+	short vRefNum;
+	long dirID;
+	
+	/* first search Extensions Panels */
+	GetExtensionsFolder(&vRefNum, &dirID);
+	refnum = SearchFolderForINIT('INIT', 'krbL', vRefNum, dirID);
+	if (refnum != -1) return(refnum);
+		
+	/* next search System Folder  */
+	GetSystemFolder(&vRefNum, &dirID);
+	refnum = SearchFolderForINIT('INIT', 'krbL', vRefNum, dirID);
+	if (refnum != -1) return(refnum);
+		
+	/* finally, search Control Panels */
+	GetCPanelFolder(&vRefNum, &dirID);
+	refnum = SearchFolderForINIT('INIT', 'krbL', vRefNum, dirID);
+	if (refnum != -1) return(refnum);
+		
+	return -1;
+}	
+
+int DisplayError( short errorID )
+{
+	OSErr			err;
+	Str255			errText;
+	
+	GetIndString(errText,kErrorALERTID,errorID);
+	if (errText[0] == 0) {
+		SysBeep(1);		// nothing else we can do
+		return cKrbCorruptedFile;
+	}
+
+	ParamText(errText,"\p","\p","\p");
+	err = StopAlert(kErrorALERTID,nil);
+	
+	return DialogNotDone;
+}
+
+
+
+OSErr GetUserInfo( char *password )
+{
+	DialogPtr		myDLOG;
+	short			itemHit;
+	short			itemType;
+	Handle			itemHandle;
+	Rect			itemRect;
+	OSErr			rc = DialogNotDone;
+	Str255			tempStr,tpswd,tuser;
+	Proc2Hand		procConv;
+	short			rf;
+	char uname[ANAME_SZ]="\0";
+	char uinst[INST_SZ]="\0";
+	char realm[REALM_SZ]="\0";
+	char UserName[MAX_K_NAME_SZ]="\0";
+	CursHandle		aCursor;
+	
+	krb_get_lrealm (realm, 1);
+
+	//////////////////////////////////////////////////////
+	// already got a password, just get the initial ticket
+	//////////////////////////////////////////////////////
+	if (*gPassword)	{
+		strncpy (UserName, krb_get_default_user( ), sizeof(UserName)-1);
+		UserName[sizeof(UserName) - 1] = '\0';
+		/* FIXME jcm - if we have a password then no dialog 
+		   comes up for setting the uinstance. */
+		rc = kname_parse(uname, uinst, realm, UserName);
+			if (rc) return rc;
+		(void) dest_all_tkts();		// start from scratch
+		rc = krb_get_pw_in_tkt(uname,uinst,realm,"krbtgt",realm,DEFAULT_TKT_LIFE,gPassword);
+		*gPassword = 0;		// Always clear, password only good for one shot
+		return rc;
+	}
+	
+	/////////////////////////
+	// Ask user for password
+	/////////////////////////
+	rf = OpenInitRF();		// need the resource file for the dialog resources
+	if (rf<=0) return rf;
+	password[0] = 0;
+	myDLOG = GetNewDialog( kLoginDLOGID, (void *) NULL, (WindowPtr) -1 );
+	if( myDLOG == NULL ) {
+		CloseResFile(rf);
+		return cKrbCorruptedFile;
+	}
+
+	// Insert user's name in dialog
+	strncpy (UserName, krb_get_default_user( ), sizeof(UserName) - 1);
+	UserName[sizeof(UserName) - 1] = '\0';
+	if (*UserName) {
+		tempStr[0] = strlen(UserName);
+		memcpy( &(tempStr[1]), UserName, tempStr[0]);
+		GetDItem( myDLOG, kLoginNameItem, &itemType, &itemHandle, &itemRect );
+		SetIText( itemHandle, tempStr );
+		SelIText( myDLOG, kLoginVisPwItem,0,0 );
+	}
+	else SelIText( myDLOG, kLoginNameItem,0,0 );
+	
+	// Establish a user item around the OK button to draw the default button frame in
+	GetDItem( myDLOG, kLoginOKItem, &itemType, &itemHandle, &itemRect );
+	InsetRect( &itemRect, -4, -4 );				// position user item around OK button
+	procConv.P = (ProcPtr) FrameOKbtn;			// convert ProcPtr to a Handle
+	SetDItem( myDLOG, kLoginFrameItem, userItem, procConv.H, &itemRect );
+	
+	InitCursor();
+	do {
+		do {										// display the dialog & handle events
+			SetOKEnable(myDLOG);
+			ModalDialog( (ModalFilterProcPtr) TwoItemFilter, (short *) &itemHit );
+		} while( itemHit != kLoginOKItem && itemHit != kLoginCnclItem );
+		
+		if( itemHit == kLoginOKItem ) {				// OK button pressed?			
+			GetDItem( myDLOG, kLoginNameItem, &itemType, &itemHandle, &itemRect );
+			GetIText( itemHandle, tempStr );
+		
+			tempStr[0] = ( tempStr[0] < MAX_K_NAME_SZ ) ? tempStr[0] : MAX_K_NAME_SZ-1 ;
+			memcpy ((void*) UserName, (void*) &(tempStr[1]), tempStr[0]);
+			UserName[tempStr[0]] = 0;
+			
+			GetDItem( myDLOG, kLoginIvisPwItem, &itemType, &itemHandle, &itemRect );
+			GetIText( itemHandle, tempStr );
+		
+			tempStr[0] = ( tempStr[0] < ANAME_SZ ) ? tempStr[0] : ANAME_SZ-1 ;
+			memcpy( (void*) password, (void*) &(tempStr[1]), tempStr[0]);
+			password[tempStr[0]] = 0;
+
+			//----------------------------------------------------
+			// Get the ticket
+			//----------------------------------------------------
+			aCursor = GetCursor(watchCursor);
+			SetCursor(*aCursor);
+			ShowCursor();
+			
+			rc = kname_parse(uname, uinst, realm, UserName);
+			if (rc) return rc;
+
+			(void) dest_all_tkts();		// start from scratch
+			rc = krb_get_pw_in_tkt(uname,uinst,realm,"krbtgt",realm,DEFAULT_TKT_LIFE,password);
+			InitCursor();
+			if (!rc) 
+			switch (rc) {
+				case KDC_PR_UNKNOWN:
+				case KDC_NULL_KEY:
+					rc = DisplayError(kBadUserError);
+					SelIText( myDLOG, kLoginNameItem,0,256 );
+					break;
+				case KDC_PR_N_UNIQUE:
+					rc = DisplayError(kNotUniqueError);
+					SelIText( myDLOG, kLoginNameItem,0,256 );
+					break;
+				case KDC_GEN_ERR:
+					rc = DisplayError(kGenError);
+					SelIText( myDLOG, kLoginNameItem,0,256 );
+					break;
+				case RD_AP_MODIFIED:
+					rc = DisplayError(kIntegrityError);
+					SelIText( myDLOG, kLoginNameItem,0,256 );
+					break;
+				case INTK_BADPW:
+					rc = DisplayError(kBadPasswordError);
+					SelIText( myDLOG, kLoginVisPwItem,0,256 );
+					break;
+				default:
+					break;
+			}
+			//----------------------------------------------------
+		}
+		else rc = cKrbUserCancelled;						// pressed the Cancel button
+	} while( rc == DialogNotDone );
+
+	DisposDialog( myDLOG );
+	CloseResFile(rf);
+	return rc;
+}
+
+
+static pascal void FrameOKbtn( WindowPtr myWindow, short itemNo )
+{
+	short		tempType;
+	Handle		tempHandle;
+	Rect		itemRect;
+
+	GetDItem( (DialogPtr) myWindow, itemNo, &tempType, &tempHandle, &itemRect );
+	PenSize( 3, 3 );
+	FrameRoundRect( &itemRect, 16, 16 );		// make it an OK button suitable for framing
+}
+
+
+static pascal Boolean TwoItemFilter( DialogPtr dlog, EventRecord *event, short *itemHit )
+{
+	DialogPtr	evtDlog;
+	short		selStart, selEnd;
+	Handle		okBtnHandle;
+	short		tempType;
+	Rect		tempRect;
+	long		tempTicks;
+
+	if( event->what != keyDown && event->what != autoKey )
+		return false;				// don't care about this event
+
+	switch( event->message & charCodeMask )
+	{
+	case cr:						// Return  (hitting return or enter is the same as hitting the OK button)
+	case enter:						// Enter
+	
+		if (!OKIsEnabled(dlog)) {
+			event->what = nullEvent;
+			return false;
+		}
+		
+		GetDItem( dlog, kLoginOKItem, &tempType, &okBtnHandle, &tempRect );
+		HiliteControl( (ControlHandle) okBtnHandle, 1 );	// hilite the OK button
+		Delay( 10, &tempTicks );	// wait a little while
+		HiliteControl( (ControlHandle) okBtnHandle, 0 );
+
+		*itemHit = kLoginOKItem;		// OK Button
+		return true;				// We handled the event
+
+	case tab:						// Tab
+	case larrow:					// Left arrow  (Keys that just change the selection)
+	case rarrow:					// Right arrow
+	case uarrow:					// Up arrow
+	case darrow:					// Down arrow
+		return false;				// Let ModalDialog handle them
+
+	default:
+	
+		// First see if we're in password field, do stuff to make ¥ displayed
+		
+		if( ((DialogPeek) dlog)->editField == kLoginVisPwItem - 1 ) {
+
+			selStart = (**((DialogPeek) dlog)->textH).selStart;	// Get the selection in the visible item
+			selEnd = (**((DialogPeek) dlog)->textH).selEnd;
+
+			SelIText( dlog, kLoginIvisPwItem, selStart, selEnd );	// Select text in invisible item
+			DialogSelect( event,&evtDlog, itemHit );			// Input key
+
+			SelIText( dlog, kLoginVisPwItem, selStart, selEnd );	// Select same area in visible item
+			if( ( event->message & charCodeMask ) != bs )		// If it's not a backspace (backspace is the only key that can affect both the text and the selection- thus we need to process it in both fields, but not change it for the hidden field.
+				event->message = 'Â¥';							// Replace with character to use
+		}
+		
+		// Do the key event and set the hilite on the OK button accordingly
+		
+		DialogSelect( event,&evtDlog, itemHit );			// Input key
+		SetOKEnable(dlog);
+		
+		// Pass a NULL event back to DialogMgr
+		
+		event->what = nullEvent;
+		
+		return false;
+	}
+}
+
+static int SetOKEnable( DialogPtr dlog )
+{
+	short		itemType,state;
+	Handle		itemHandle;
+	Rect		itemRect;
+	Str255		tpswd,tuser;
+	ControlHandle okButton;
+
+	GetDItem( dlog, kLoginNameItem, &itemType, &itemHandle, &itemRect );
+	GetIText( itemHandle, tuser );
+	GetDItem( dlog, kLoginVisPwItem, &itemType, &itemHandle, &itemRect );
+	GetIText( itemHandle, tpswd );
+	GetDItem( dlog, kLoginOKItem, &itemType, (Handle *) &okButton, &itemRect );
+	state = (tuser[0] && tpswd[0]) ? 0 : 255;
+	HiliteControl(okButton,state);
+}
+
+static int OKIsEnabled( DialogPtr dlog )
+{
+	short		itemType;
+	Rect		itemRect;
+	ControlHandle okButton;
+
+	GetDItem( dlog, kLoginOKItem, &itemType, (Handle *) &okButton, &itemRect );
+	return ((**okButton).contrlHilite != 255);
+}
+
+
+extern OSErr INTERFACE 
+CacheInitialTicket( serviceName )
+     char *serviceName;
+{
+	char service[ANAME_SZ]="\0";
+	char instance[INST_SZ]="\0";
+	char realm[REALM_SZ]="\0";
+	OSErr err = noErr;
+	char uname[ANAME_SZ]="\0";
+	char uinst[INST_SZ]="\0";
+	char urealm[REALM_SZ]="\0";
+	char password[KKEY_SZ]="\0";
+	char UserName[MAX_K_NAME_SZ]="\0";
+	char oldName[120]="\0";	
+								
+	err = GetUserInfo( password );
+	if (err) return err;
+	
+	if (!serviceName || (serviceName[0] == '\0'))
+		return err;
+	
+	strncpy (UserName, krb_get_default_user(), sizeof(UserName) - 1);
+	UserName[sizeof(UserName) - 1] = '\0';
+			
+ 	err = kname_parse(uname, uinst, urealm, UserName);
+ 	if (err) return err;
+ 	
+ 	if (urealm[0] == '\0')
+ 		krb_get_lrealm (urealm, 1);
+	
+	err = kname_parse(service, instance, realm, serviceName); // check if there is a service name
+	if (err) return err;
+	
+	err = krb_get_pw_in_tkt(uname,uinst,urealm,service,instance,DEFAULT_TKT_LIFE,password);
+	return err;
+}
diff --git a/mechglue/src/lib/krb4/RealmsConfig-glue.c b/mechglue/src/lib/krb4/RealmsConfig-glue.c
new file mode 100644
index 000000000..dbdfe54cd
--- /dev/null
+++ b/mechglue/src/lib/krb4/RealmsConfig-glue.c
@@ -0,0 +1,697 @@
+/*
+ * lib/krb4/RealmsConfig-glue.c
+ *
+ * Copyright 1985-2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * These calls implement the layer of Kerberos v4 library which
+ * accesses realms configuration by calling into the Kerberos Profile
+ * library.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "profile.h"
+#include "krb.h"
+#include "krb4int.h"
+#include "k5-int.h"		/* for accessor, addrlist stuff */
+#include "port-sockets.h"
+
+#define KRB5_PRIVATE 1
+/* For krb5_get_default_config_files and krb5_free_config_files */
+#include "krb5.h"
+#undef KRB5_PRIVATE
+
+/* These two *must* be kept in sync to avoid buffer overflows. */
+#define SCNSCRATCH	"%1023s"
+#define SCRATCHSZ	1024
+#if SCRATCHSZ < MAXHOSTNAMELEN
+#error "SCRATCHSZ must be at least MAXHOSTNAMELEN"
+#endif
+
+/*
+ * Returns to the caller an initialized profile using the same files
+ * as Kerberos4Lib would.
+ */
+int KRB5_CALLCONV
+krb_get_profile(profile_t* profile)
+{
+    int			retval = KSUCCESS;
+    profile_filespec_t	*files = NULL;
+
+    /* Use krb5 to get the config files */
+    retval = krb5_get_default_config_files(&files);
+
+    if (retval == KSUCCESS) {
+	retval = profile_init((const_profile_filespec_t *)files, profile);
+    }
+
+    if (files) {
+	krb5_free_config_files(files);
+    }
+
+    if (retval == ENOENT) {
+	/* No edu.mit.Kerberos file */
+	return KFAILURE;
+    }
+
+    if ((retval == PROF_SECTION_NOTOP) ||
+	(retval == PROF_SECTION_SYNTAX) ||
+	(retval == PROF_RELATION_SYNTAX) ||
+	(retval == PROF_EXTRA_CBRACE) ||
+	(retval == PROF_MISSING_OBRACE)) {
+	/* Bad config file format */
+	return retval;
+    }
+
+    return retval;
+}
+
+/* Caller must ensure that n >= 1 and that pointers are non-NULL. */
+static int
+krb_prof_get_nth(
+    char	*ret,
+    size_t	retlen,
+    const char	*realm,
+    int		n,
+    const char	*sec,
+    const char	*key)
+{
+    int		result;
+    long	profErr;
+    profile_t	profile = NULL;
+    const	char *names[4];
+    void	*iter = NULL;
+    char	*name = NULL;
+    char	*value = NULL;
+    int		i;
+
+    result = KFAILURE;
+
+    profErr = krb_get_profile(&profile);
+    if (profErr) {
+	/*
+	 * Can krb_get_profile() return errors that change PROFILE?
+	 */
+	goto cleanup;
+    }
+    names[0] = sec;
+    names[1] = realm;
+    names[2] = key;
+    names[3] = NULL;
+    profErr = profile_iterator_create(profile, names,
+				      PROFILE_ITER_RELATIONS_ONLY, &iter);
+    if (profErr)
+	goto cleanup;
+
+    result = KSUCCESS;
+    for (i = 1; i <= n; i++) {
+	if (name != NULL)
+	    profile_release_string(name);
+	if (value != NULL)
+	    profile_release_string(value);
+	name = value = NULL;
+
+	profErr = profile_iterator(&iter, &name, &value);
+	if (profErr || (name == NULL)) {
+	    result = KFAILURE;
+	    break;
+	}
+    }
+    if (result == KSUCCESS) {
+	/* Return error rather than truncating. */
+	/* Don't strncpy because retlen is a guess for some callers */
+	if (strlen(value) >= retlen)
+	    result = KFAILURE;
+	else
+	    strcpy(ret, value);
+    }
+cleanup:
+    if (name != NULL)
+	profile_release_string(name);
+    if (value != NULL)
+	profile_release_string(value);
+    if (iter != NULL)
+	profile_iterator_free(&iter);
+    if (profile != NULL)
+	profile_abandon(profile);
+    return result;
+}
+
+/*
+ * Index -> realm name mapping
+ *
+ * Not really. The original implementation has a cryptic comment
+ * indicating that the function can only work for n = 1, and always
+ * returns the default realm. I don't know _why_ that's the case, but
+ * I have to do it that way...
+ *
+ * Old description from g_krbrlm.c:
+ *
+ * krb_get_lrealm takes a pointer to a string, and a number, n.  It fills
+ * in the string, r, with the name of the nth realm specified on the
+ * first line of the kerberos config file (KRB_CONF, defined in "krb.h").
+ * It returns 0 (KSUCCESS) on success, and KFAILURE on failure.  If the
+ * config file does not exist, and if n=1, a successful return will occur
+ * with r = KRB_REALM (also defined in "krb.h").
+ *
+ * NOTE: for archaic & compatibility reasons, this routine will only return
+ * valid results when n = 1.
+ *
+ * For the format of the KRB_CONF file, see comments describing the routine
+ * krb_get_krbhst().  This will also look in KRB_FB_CONF is
+ * ATHENA_CONF_FALLBACK is defined.
+ */
+int KRB5_CALLCONV
+krb_get_lrealm(
+    char	*realm,
+    int		n)
+{
+    int         result = KSUCCESS;
+    profile_t   profile = NULL;
+    char       *profileDefaultRealm = NULL;
+    char      **profileV4Realms = NULL;
+    int         profileHasDefaultRealm = 0;
+    int         profileDefaultRealmIsV4RealmInProfile = 0;
+    char        krbConfLocalRealm[REALM_SZ];
+    int         krbConfHasLocalRealm = 0;
+
+    if ((realm == NULL) || (n != 1)) { result = KFAILURE; }
+
+    if (result == KSUCCESS) {
+        /* Some callers don't check the return value so we initialize
+         * to an empty string in case it never gets filled in. */
+        realm [0] = '\0';  
+    }
+    
+    if (result == KSUCCESS) {
+        int profileErr = krb_get_profile (&profile);
+
+        if (!profileErr) {
+            /* Get the default realm from the profile */
+            profileErr = profile_get_string(profile, REALMS_V4_PROF_LIBDEFAULTS_SECTION,
+                                            REALMS_V4_DEFAULT_REALM, NULL, NULL,
+                                            &profileDefaultRealm);
+            if (profileDefaultRealm == NULL) { profileErr = KFAILURE; }
+        }
+
+        if (!profileErr) {
+            /* If there is an equivalent v4 realm to the default realm, use that instead */
+            char *profileV4EquivalentRealm = NULL;
+
+            if (profile_get_string (profile, "realms", profileDefaultRealm, "v4_realm", NULL,
+                                    &profileV4EquivalentRealm) == 0 &&
+                profileV4EquivalentRealm != NULL) {
+
+                profile_release_string (profileDefaultRealm);
+                profileDefaultRealm = profileV4EquivalentRealm;
+            }
+        }
+
+        if (!profileErr) {
+            if (strlen (profileDefaultRealm) < REALM_SZ) {
+                profileHasDefaultRealm = 1;  /* a reasonable default realm */
+            } else {
+                profileErr = KFAILURE;
+            }
+        }
+
+        if (!profileErr) {
+            /* Walk through the v4 realms list looking for the default realm */
+            const char *profileV4RealmsList[] = { REALMS_V4_PROF_REALMS_SECTION, NULL };
+
+            if (profile_get_subsection_names (profile, profileV4RealmsList,
+                                              &profileV4Realms) == 0 &&
+                profileV4Realms != NULL) {
+
+                char **profileRealm;
+                for (profileRealm = profileV4Realms; *profileRealm != NULL; profileRealm++) {
+                    if (strcmp (*profileRealm, profileDefaultRealm) == 0) {
+                        /* default realm is a v4 realm */
+                        profileDefaultRealmIsV4RealmInProfile = 1;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    
+    if (result == KSUCCESS) {
+        /* Try to get old-style config file lookup for fallback. */
+        FILE	*cnffile = NULL;
+        char	scratch[SCRATCHSZ];
+
+        cnffile = krb__get_cnffile();
+        if (cnffile != NULL) {
+            if (fscanf(cnffile, SCNSCRATCH, scratch) == 1) {
+                if (strlen(scratch) < REALM_SZ) {
+                    strncpy(krbConfLocalRealm, scratch, REALM_SZ);
+                    krbConfHasLocalRealm = 1;
+                }
+            }
+            fclose(cnffile);
+        }
+    }
+
+    if (result == KSUCCESS) {
+        /*
+         * We want to favor the profile value over the krb.conf value
+         * but not stop suppporting its use with a v5-only profile. 
+         * So we only use the krb.conf realm when the default profile
+         * realm doesn't exist in the v4 realm section of the profile.
+         */
+        if (krbConfHasLocalRealm && !profileDefaultRealmIsV4RealmInProfile) {
+            strncpy (realm, krbConfLocalRealm, REALM_SZ);
+        } else if (profileHasDefaultRealm) {
+            strncpy (realm, profileDefaultRealm, REALM_SZ);
+        } else {
+            result = KFAILURE;  /* No default realm */
+        }
+    }
+
+    if (profileDefaultRealm != NULL) { profile_release_string (profileDefaultRealm); }
+    if (profileV4Realms     != NULL) { profile_free_list (profileV4Realms); }
+    if (profile             != NULL) { profile_abandon (profile); }
+
+    return result;
+}
+
+/*
+ * Realm, index -> admin KDC mapping
+ *
+ * Old description from g_admhst.c:
+ *
+ * Given a Kerberos realm, find a host on which the Kerberos database
+ * administration server can be found.
+ *
+ * krb_get_admhst takes a pointer to be filled in, a pointer to the name
+ * of the realm for which a server is desired, and an integer n, and
+ * returns (in h) the nth administrative host entry from the configuration
+ * file (KRB_CONF, defined in "krb.h") associated with the specified realm.
+ * If ATHENA_CONF_FALLBACK is defined, also look in old location.
+ *
+ * On error, get_admhst returns KFAILURE. If all goes well, the routine
+ * returns KSUCCESS.
+ *
+ * For the format of the KRB_CONF file, see comments describing the routine
+ * krb_get_krbhst().
+ *
+ * This is a temporary hack to allow us to find the nearest system running
+ * a Kerberos admin server.  In the long run, this functionality will be
+ * provided by a nameserver.
+ */
+int KRB5_CALLCONV
+krb_get_admhst(
+    char	*host,
+    char	*realm,
+    int		n)
+{
+    int		result;
+    int		i;
+    FILE	*cnffile;
+    char	linebuf[BUFSIZ];
+    char	trealm[SCRATCHSZ];
+    char	thost[SCRATCHSZ];
+    char	scratch[SCRATCHSZ];
+
+    if (n < 1 || host == NULL || realm == NULL)
+	return KFAILURE;
+
+    result = krb_prof_get_nth(host, MAXHOSTNAMELEN, realm, n,
+			      REALMS_V4_PROF_REALMS_SECTION,
+			      REALMS_V4_PROF_ADMIN_KDC);
+    if (result == KSUCCESS)
+	return result;
+
+    /*
+     * Do old-style config file lookup.
+     */
+    cnffile = krb__get_cnffile();
+    if (cnffile == NULL)
+	return KFAILURE;
+    result = KSUCCESS;
+    for (i = 0; i < n;) {
+	if (fgets(linebuf, BUFSIZ, cnffile) == NULL) {
+	    result = KFAILURE;
+	    break;
+	}
+	if (!strchr(linebuf, '\n')) {
+	    result = KFAILURE;
+	    break;
+	}
+	/*
+	 * Need to scan for a token after 'admin' to make sure that
+	 * admin matched correctly.
+	 */
+	if (sscanf(linebuf, SCNSCRATCH " " SCNSCRATCH " admin " SCNSCRATCH,
+		   trealm, thost, scratch) != 3)
+	    continue;
+	if (!strcmp(trealm, realm))
+	    i++;
+    }
+    fclose(cnffile);
+    if (result == KSUCCESS && strlen(thost) < MAX_HSTNM)
+	strcpy(host, thost);
+    else
+	result = KFAILURE;
+    return result;
+}
+
+/*
+ * Realm, index -> kpasswd KDC mapping
+ */
+int
+krb_get_kpasswdhst(
+    char	*host,
+    char	*realm,
+    int		n)
+{
+    if (n < 1 || host == NULL || realm == NULL)
+	return KFAILURE;
+
+    return krb_prof_get_nth(host, MAXHOSTNAMELEN, realm, n,
+			    REALMS_V4_PROF_REALMS_SECTION,
+			    REALMS_V4_PROF_KPASSWD_KDC);
+}
+
+/*
+ * Realm, index -> KDC mapping
+ *
+ * Old description from g_krbhst.c:
+ *
+ * Given a Kerberos realm, find a host on which the Kerberos authenti-
+ * cation server can be found.
+ *
+ * krb_get_krbhst takes a pointer to be filled in, a pointer to the name
+ * of the realm for which a server is desired, and an integer, n, and
+ * returns (in h) the nth entry from the configuration file (KRB_CONF,
+ * defined in "krb.h") associated with the specified realm.
+ *
+ * On end-of-file, krb_get_krbhst returns KFAILURE.  If n=1 and the
+ * configuration file does not exist, krb_get_krbhst will return KRB_HOST
+ * (also defined in "krb.h").  If all goes well, the routine returnes
+ * KSUCCESS.
+ *
+ * The KRB_CONF file contains the name of the local realm in the first
+ * line (not used by this routine), followed by lines indicating realm/host
+ * entries.  The words "admin server" following the hostname indicate that
+ * the host provides an administrative database server.
+ * This will also look in KRB_FB_CONF if ATHENA_CONF_FALLBACK is defined.
+ *
+ * For example:
+ *
+ *	ATHENA.MIT.EDU
+ *	ATHENA.MIT.EDU kerberos-1.mit.edu admin server
+ *	ATHENA.MIT.EDU kerberos-2.mit.edu
+ *	LCS.MIT.EDU kerberos.lcs.mit.edu admin server
+ *
+ * This is a temporary hack to allow us to find the nearest system running
+ * kerberos.  In the long run, this functionality will be provided by a
+ * nameserver.
+ */
+#ifdef KRB5_DNS_LOOKUP
+static struct {
+    time_t when;
+    char realm[REALM_SZ+1];
+    struct srv_dns_entry *srv;
+} dnscache = { 0, { 0 }, 0 };
+#define DNS_CACHE_TIMEOUT	60 /* seconds */
+#endif
+
+int KRB5_CALLCONV
+krb_get_krbhst(
+    char	*host,
+    const char	*realm,
+    int		n)
+{
+    int		result;
+    int		i;
+    FILE	*cnffile;
+    char	linebuf[BUFSIZ];
+    char	tr[SCRATCHSZ];
+    char	scratch[SCRATCHSZ];
+#ifdef KRB5_DNS_LOOKUP
+    time_t now;
+#endif
+
+    if (n < 1 || host == NULL || realm == NULL)
+	return KFAILURE;
+
+#ifdef KRB5_DNS_LOOKUP
+    /* We'll only have this realm's info in the DNS cache if there is
+       no data in the local config files.
+
+       XXX The files could've been updated in the last few seconds.
+       Do we care?  */
+    if (!strncmp(dnscache.realm, realm, REALM_SZ)
+	&& (time(&now), abs(dnscache.when - now) < DNS_CACHE_TIMEOUT)) {
+	struct srv_dns_entry *entry;
+
+    get_from_dnscache:
+	/* n starts at 1, addrs indices run 0..naddrs */
+	for (i = 1, entry = dnscache.srv; i < n && entry; i++)
+	    entry = entry->next;
+	if (entry == NULL)
+	    return KFAILURE;
+	if (strlen(entry->host) + 6 >= MAXHOSTNAMELEN)
+	    return KFAILURE;
+	sprintf(host, "%s:%d", entry->host, entry->port);
+	return KSUCCESS;
+    }
+#endif
+
+    result = krb_prof_get_nth(host, MAXHOSTNAMELEN, realm, n,
+			      REALMS_V4_PROF_REALMS_SECTION,
+			      REALMS_V4_PROF_KDC);
+    if (result == KSUCCESS)
+	return result;
+    /*
+     * Do old-style config file lookup.
+     */
+    do {
+	cnffile = krb__get_cnffile();
+	if (cnffile == NULL)
+	    break;
+	/* Skip default realm name. */
+	if (fscanf(cnffile, SCNSCRATCH, tr) == EOF) {
+	    fclose(cnffile);
+	    break;
+	}
+	result = KSUCCESS;
+	for (i = 0; i < n;) {
+	    if (fgets(linebuf, BUFSIZ, cnffile) == NULL) {
+		result = KFAILURE;
+		break;
+	    }
+	    if (!strchr(linebuf, '\n')) {
+		result = KFAILURE;
+		break;
+	    }
+	    if ((sscanf(linebuf, SCNSCRATCH " " SCNSCRATCH,
+			tr, scratch) != 2))
+		continue;
+	    if (!strcmp(tr, realm))
+		i++;
+	}
+	fclose(cnffile);
+	if (result == KSUCCESS && strlen(scratch) < MAXHOSTNAMELEN) {
+	    strcpy(host, scratch);
+	    return KSUCCESS;
+	}
+	if (i > 0)
+	    /* Found some, but not as many as requested.  */
+	    return KFAILURE;
+    } while (0);
+#ifdef KRB5_DNS_LOOKUP
+    do {
+	krb5int_access k5;
+	krb5_error_code err;
+	krb5_data realmdat;
+	struct srv_dns_entry *srv;
+
+	err = krb5int_accessor(&k5, KRB5INT_ACCESS_VERSION);
+	if (err)
+	    break;
+
+	if (k5.use_dns_kdc(krb5__krb4_context)) {
+	    realmdat.data = realm;
+	    realmdat.length = strlen(realm);
+	    err = k5.make_srv_query_realm(&realmdat, "_kerberos-iv", "_udp",
+					  &srv);
+	    if (err)
+		break;
+
+	    if (srv == 0)
+		break;
+
+	    if (dnscache.srv)
+		k5.free_srv_dns_data(dnscache.srv);
+	    dnscache.srv = srv;
+	    strncpy(dnscache.realm, realm, REALM_SZ);
+	    dnscache.when = now;
+	    goto get_from_dnscache;
+	}
+    } while (0);
+#endif
+    return KFAILURE;
+}
+
+/*
+ * Hostname -> realm name mapping
+ *
+ * Old description from realmofhost.c:
+ *
+ * Given a fully-qualified domain-style primary host name,
+ * return the name of the Kerberos realm for the host.
+ * If the hostname contains no discernable domain, or an error occurs,
+ * return the local realm name, as supplied by get_krbrlm().
+ * If the hostname contains a domain, but no translation is found,
+ * the hostname's domain is converted to upper-case and returned.
+ *
+ * The format of each line of the translation file is:
+ * domain_name kerberos_realm
+ * -or-
+ * host_name kerberos_realm
+ *
+ * domain_name should be of the form .XXX.YYY (e.g. .LCS.MIT.EDU)
+ * host names should be in the usual form (e.g. FOO.BAR.BAZ)
+ */
+char * KRB5_CALLCONV
+krb_realmofhost(char *host)
+{
+    /* Argh! */
+    static char	realm[REALM_SZ];
+    char	*lhost;
+    const char	*names[] = {REALMS_V4_PROF_DOMAIN_SECTION, NULL, NULL};
+    char	**values = NULL;
+    profile_t	profile = NULL;
+    long	profErr;
+    char	hostname[MAXHOSTNAMELEN];
+    char	*p;
+    char	*domain;
+    FILE	*trans_file = NULL;
+    int		retval;
+    char	thost[SCRATCHSZ];
+    char	trealm[SCRATCHSZ];
+    struct hostent	*h;
+
+    /* Return local realm if all else fails */
+    krb_get_lrealm(realm, 1);
+
+    /* Forward-resolve in case domain is missing. */
+    h = gethostbyname(host);
+    if (h == NULL)
+	lhost = host;
+    else
+	lhost = h->h_name;
+
+    if (strlen(lhost) >= MAXHOSTNAMELEN)
+	return realm;
+    strcpy(hostname, lhost);
+
+    /* Remove possible trailing dot. */
+    p = strrchr(hostname, '.');
+    if (p != NULL && p[1] == '\0')
+	*p = '\0';
+    domain = strchr(hostname, '.');
+    /*
+     * If the hostname is just below the top, e.g., CYGNUS.COM, then
+     * we special-case it; if someone really wants a realm called COM
+     * they will just have to specify it properly.
+     */
+    if (domain != NULL) {
+	domain++;
+	p = strchr(domain, '.');
+	if (p == NULL)
+	    domain = lhost;
+	if (strlen(domain) < REALM_SZ) {
+	    strncpy(realm, domain, REALM_SZ);
+	    /* Upcase realm name. */
+	    for (p = hostname; *p != '\0'; p++) {
+		if (*p > 0 && islower((unsigned char)*p))
+		    *p = toupper((unsigned char)*p);
+	    }
+	}
+    }
+    /* Downcase hostname. */
+    for (p = hostname; *p != '\0'; p++) {
+	if (*p > 0 && isupper((unsigned char)*p))
+	    *p = tolower((unsigned char)*p);
+    }
+
+    profErr = krb_get_profile(&profile);
+    if (profErr)
+	goto cleanup;
+
+    for (domain = hostname; domain != NULL && *domain != '\0';) {
+	names[1] = domain;
+	values = NULL;
+	profErr = profile_get_values(profile, names, &values);
+	if (!profErr && strlen(values[0]) < REALM_SZ) {
+	    /* Found, return it */
+	    strncpy(realm, values[0], REALM_SZ);
+	    profile_free_list(values);
+	    break;
+	} else {
+	    /* Skip over leading dot. */
+	    if (*domain == '.')
+		domain++;
+	    domain = strchr(domain, '.');
+	}
+	profile_free_list(values);
+    }
+cleanup:
+    if (profile != NULL)
+	profile_abandon(profile);
+
+    trans_file = krb__get_realmsfile();
+    if (trans_file == NULL)
+	return realm;
+    domain = strchr(hostname, '.');
+    for (;;) {
+	retval = fscanf(trans_file, SCNSCRATCH " " SCNSCRATCH,
+			thost, trealm);
+	if (retval == EOF)
+	    break;
+	if (retval != 2 || strlen(trealm) >= REALM_SZ)
+	    continue;		/* Ignore malformed lines. */
+	/* Attempt to match domain. */
+	if (*thost == '.') {
+	    if (domain && !strcasecmp(thost, domain)) {
+		strncpy(realm, trealm, REALM_SZ);
+		continue;	/* Try again for an exact match. */
+	    }
+	} else {
+	    /* Hostname must match exactly. */
+	    if (!strcasecmp(thost, hostname)) {
+		strncpy(realm, trealm, REALM_SZ);
+		break;
+	    }
+	}
+    }
+    fclose(trans_file);
+    return realm;
+}
diff --git a/mechglue/src/lib/krb4/ad_print.c b/mechglue/src/lib/krb4/ad_print.c
new file mode 100644
index 000000000..632957208
--- /dev/null
+++ b/mechglue/src/lib/krb4/ad_print.c
@@ -0,0 +1,85 @@
+/*
+ * lib/krb4/ad_print.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.  All
+ * Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "des.h"
+#include "krb4int.h"
+#include <stdio.h>
+#include "port-sockets.h"
+
+#ifndef _WIN32
+
+/*
+ * Print some of the contents of the given authenticator structure
+ * (AUTH_DAT defined in "krb.h").  Fields printed are:
+ *
+ * pname, pinst, prealm, netaddr, flags, cksum, timestamp, session
+ */
+
+void
+ad_print(x)
+    AUTH_DAT *x;
+{
+    struct in_addr ina;
+    ina.s_addr = x->address;
+  
+    printf("\n%s %s %s ", x->pname, x->pinst, x->prealm);
+    far_fputs (inet_ntoa(ina), stdout);
+    printf(" flags %u cksum 0x%lX\n\ttkt_tm 0x%lX sess_key",
+            x->k_flags, (long) x->checksum, (long) x->time_sec);
+    printf("[8] =");
+#ifdef NOENCRYPTION
+    placebo_cblock_print(x->session);
+#else /* Do Encryption */
+    des_cblock_print_file(&x->session,stdout);
+#endif /* NOENCRYPTION */
+    /* skip reply for now */
+}
+
+#ifdef NOENCRYPTION
+/*
+ * Print in hex the 8 bytes of the given session key.
+ *
+ * Printed format is:  " 0x { x, x, x, x, x, x, x, x }"
+ */
+
+placebo_cblock_print(x)
+    des_cblock x;
+{
+    unsigned char *y = (unsigned char *) x;
+    register int i = 0;
+
+    printf(" 0x { ");
+
+    while (i++ <8) {
+        printf("%x",*y++);
+        if (i<8) printf(", ");
+    }
+    printf(" }");
+}
+#endif /* NOENCRYPTION */
+
+#endif
diff --git a/mechglue/src/lib/krb4/change_password.c b/mechglue/src/lib/krb4/change_password.c
new file mode 100644
index 000000000..7c3bcd01d
--- /dev/null
+++ b/mechglue/src/lib/krb4/change_password.c
@@ -0,0 +1,127 @@
+/*
+ * change_password.c
+ *
+ * Copyright 1987, 1988, 2002 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "krb.h"
+#include "krb4int.h"
+#include "kadm.h"
+#include "prot.h"
+
+/*
+ * krb_change_password(): This disgusting function handles changing passwords
+ * in a krb4-only environment.  
+ * -1783126240
+ * THIS IS NOT A NORMAL KRB4 API FUNCTION!  DON'T USE IN PORTABLE CODE!
+ */
+
+int KRB5_CALLCONV
+krb_change_password(char *principal, char *instance, char *realm, 
+		    char *oldPassword, char *newPassword)
+{
+    int		err;
+    des_cblock	key;
+    KRB_UINT32	tempKey;
+    size_t	sendSize;
+    u_char	*sendStream;
+    size_t	receiveSize;
+    u_char	*receiveStream;
+    Kadm_Client	client_parm;
+    u_char	*p;
+
+    err = 0;
+    
+    /* Check inputs: */
+    if (principal == NULL || instance == NULL || realm == NULL ||
+        oldPassword == NULL || newPassword == NULL) {
+        return KFAILURE;
+    }
+    
+    /*
+     * Get tickets to change the old password and shove them in the
+     * client_parm
+     */
+    err = krb_get_pw_in_tkt_creds(principal, instance, realm, 
+				  PWSERV_NAME, KADM_SINST, 1,
+				  oldPassword, &client_parm.creds);
+    if (err != KSUCCESS)
+	goto cleanup;
+
+    /* Now create the key to send to the server */
+    /* Use this and not mit_password_to_key so that we don't prompt */
+    des_string_to_key(newPassword, key);
+
+    /* Create the link to the server */
+    err = kadm_init_link(PWSERV_NAME, KRB_MASTER, realm, &client_parm, 1);
+    if (err != KADM_SUCCESS)
+	goto cleanup;
+
+    /* Connect to the KDC */
+    err = kadm_cli_conn(&client_parm);
+    if (err != KADM_SUCCESS)
+	goto cleanup;
+
+    /* possible problem with vts_long on a non-multiple of four boundary */
+    sendSize = 0;		/* start of our output packet */
+    sendStream = malloc(1);	/* to make it reallocable */
+    if (sendStream == NULL)
+	goto disconnect;
+    sendStream[sendSize++] = CHANGE_PW;
+
+    /* change key to stream */
+    /* This looks backwards but gets inverted on the server side. */
+    p = key + 4;
+    KRB4_GET32BE(tempKey, p);
+    sendSize += vts_long(tempKey, &sendStream, (int)sendSize);
+    p = key;
+    KRB4_GET32BE(tempKey, p);
+    sendSize += vts_long(tempKey, &sendStream, (int)sendSize);
+    tempKey = 0;
+
+    if (newPassword) {
+	sendSize += vts_string(newPassword, &sendStream, (int)sendSize);
+    }
+
+    /* send the data to the kdc */
+    err = kadm_cli_send(&client_parm, sendStream, sendSize,
+			&receiveStream, &receiveSize);
+    free(sendStream);
+    if (receiveSize > 0)
+	/* If there is a string from the kdc, free it - we don't care */
+	free(receiveStream);
+    if (err != KADM_SUCCESS)
+	goto disconnect;
+
+disconnect:	
+    /* Disconnect */
+    kadm_cli_disconn(&client_parm);
+
+cleanup:
+    memset(&client_parm.creds.session, 0, sizeof(client_parm.creds.session));
+    memset(&key, 0, sizeof(key));
+    return err;
+}
diff --git a/mechglue/src/lib/krb4/configure.in b/mechglue/src/lib/krb4/configure.in
new file mode 100644
index 000000000..109120eed
--- /dev/null
+++ b/mechglue/src/lib/krb4/configure.in
@@ -0,0 +1,23 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+AC_TYPE_MODE_T
+AC_TYPE_UID_T
+case $krb5_cv_host in
+     *-apple-darwin*)
+     KRB_ERR_TXT=
+     KRB_ERR=
+     KRB_ERR_C=krb_err.c
+     ;;
+     *)
+     KRB_ERR='$(OUTPRE)krb_err.$(OBJEXT)'
+     KRB_ERR_TXT=krb_err_txt.c
+     KRB_ERR_C=
+     ;;
+esac
+AC_SUBST([KRB_ERR_TXT])
+AC_SUBST([KRB_ERR])
+AC_SUBST([KRB_ERR_C])
+AC_PROG_AWK
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/lib/krb4/cr_auth_repl.c b/mechglue/src/lib/krb4/cr_auth_repl.c
new file mode 100644
index 000000000..277d9af8e
--- /dev/null
+++ b/mechglue/src/lib/krb4/cr_auth_repl.c
@@ -0,0 +1,136 @@
+/*
+ * lib/krb4/cr_auth_repl.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+
+/*
+ * This routine is called by the Kerberos authentication server
+ * to create a reply to an authentication request.  The routine
+ * takes the user's name, instance, and realm, the client's
+ * timestamp, the number of tickets, the user's key version
+ * number and the ciphertext containing the tickets themselves.
+ * It constructs a packet and returns a pointer to it.
+ *
+ * Notes: The packet returned by this routine is static.  Thus, if you
+ * intend to keep the result beyond the next call to this routine, you
+ * must copy it elsewhere.
+ *
+ * The packet is built in the following format:
+ * 
+ * 			variable
+ * type			or constant	   data
+ * ----			-----------	   ----
+ * 
+ * unsigned char	KRB_PROT_VERSION   protocol version number
+ * 
+ * unsigned char	AUTH_MSG_KDC_REPLY protocol message type
+ * 
+ * [least significant	HOST_BYTE_ORDER	   sender's (server's) byte
+ *  bit of above field]			   order
+ * 
+ * string		pname		   principal's name
+ * 
+ * string		pinst		   principal's instance
+ * 
+ * string		prealm		   principal's realm
+ * 
+ * unsigned long	time_ws		   client's timestamp
+ * 
+ * unsigned char	n		   number of tickets
+ * 
+ * unsigned long	x_date		   expiration date
+ * 
+ * unsigned char	kvno		   master key version
+ * 
+ * short		w_1		   cipher length
+ * 
+ * ---			cipher->dat	   cipher data
+ */
+
+KTEXT
+create_auth_reply(pname, pinst, prealm, time_ws, n, x_date, kvno, cipher)
+    char *pname;                /* Principal's name */
+    char *pinst;                /* Principal's instance */
+    char *prealm;               /* Principal's authentication domain */
+    long time_ws;               /* Workstation time */
+    int n;                      /* Number of tickets */
+    unsigned long x_date;	/* Principal's expiration date */
+    int kvno;                   /* Principal's key version number */
+    KTEXT cipher;               /* Cipher text with tickets and
+				 * session keys */
+{
+    static KTEXT_ST pkt_st;
+    KTEXT pkt = &pkt_st;
+    unsigned char *p;
+    size_t pnamelen, pinstlen, prealmlen;
+
+    /* Create fixed part of packet */
+    p = pkt->dat;
+    /* This is really crusty. */
+    if (n != 0)
+	*p++ = 3;
+    else
+	*p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_KDC_REPLY;	/* always big-endian */
+
+    /* Make sure the response will actually fit into its buffer. */
+    pnamelen = strlen(pname) + 1;
+    pinstlen = strlen(pinst) + 1;
+    prealmlen = strlen(prealm) + 1;
+    if (sizeof(pkt->dat) < (1 + 1 + pnamelen + pinstlen + prealmlen
+			    + 4 + 1 + 4 + 1 + 2 + cipher->length)
+	|| cipher->length > 65535 || cipher->length < 0) {
+	pkt->length = 0;
+        return NULL;
+    }
+    /* Add the basic info */
+    memcpy(p, pname, pnamelen);
+    p += pnamelen;
+    memcpy(p, pinst, pinstlen);
+    p += pinstlen;
+    memcpy(p, prealm, prealmlen);
+    p += prealmlen;
+
+    /* Workstation timestamp */
+    KRB4_PUT32BE(p, time_ws);
+
+    *p++ = n;
+
+    /* Expiration date */
+    KRB4_PUT32BE(p, x_date);
+
+    /* Now send the ciphertext and info to help decode it */
+    *p++ = kvno;
+    KRB4_PUT16BE(p, cipher->length);
+    memcpy(p, cipher->dat, (size_t)cipher->length);
+    p += cipher->length;
+
+    /* And return the packet */
+    pkt->length = p - pkt->dat;
+    return pkt;
+}
diff --git a/mechglue/src/lib/krb4/cr_ciph.c b/mechglue/src/lib/krb4/cr_ciph.c
new file mode 100644
index 000000000..481cb7ee3
--- /dev/null
+++ b/mechglue/src/lib/krb4/cr_ciph.c
@@ -0,0 +1,136 @@
+/*
+ * lib/krb4/cr_ciph.c
+ *
+ * Copyright 1986, 1987, 1988, 2000 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include "des.h"
+#include <string.h>
+
+/*
+ * This routine is used by the authentication server to create
+ * a packet for its client, containing a ticket for the requested
+ * service (given in "tkt"), and some information about the ticket,
+#ifndef NOENCRYPTION
+ * all encrypted in the given key ("key").
+#endif
+ *
+ * Returns KSUCCESS no matter what.
+ *
+ * The length of the cipher is stored in c->length; the format of
+ * c->dat is as follows:
+ *
+ * 			variable
+ * type			or constant	   data
+ * ----			-----------	   ----
+ * 
+ * 
+ * 8 bytes		session		session key for client, service
+ * 
+ * string		service		service name
+ * 
+ * string		instance	service instance
+ * 
+ * string		realm		KDC realm
+ * 
+ * unsigned char	life		ticket lifetime
+ * 
+ * unsigned char	kvno		service key version number
+ * 
+ * unsigned char	tkt->length	length of following ticket
+ * 
+ * data			tkt->dat	ticket for service
+ * 
+ * 4 bytes		kdc_time	KDC's timestamp
+ *
+ * <=7 bytes		null		   null pad to 8 byte multiple
+ *
+ */
+
+int
+create_ciph(c, session, service, instance, realm, life, kvno, tkt,
+	    kdc_time, key)
+    KTEXT           c;		/* Text block to hold ciphertext */
+    C_Block         session;	/* Session key to send to user */
+    char            *service;	/* Service name on ticket */
+    char            *instance;	/* Instance name on ticket */
+    char            *realm;	/* Realm of this KDC */
+    unsigned long   life;	/* Lifetime of the ticket */
+    int             kvno;	/* Key version number for service */
+    KTEXT           tkt;	/* The ticket for the service */
+    unsigned long   kdc_time;	/* KDC time */
+    C_Block         key;	/* Key to encrypt ciphertext with */
+{
+    unsigned char   *ptr;
+    size_t          servicelen, instancelen, realmlen;
+    Key_schedule    key_s;
+
+    ptr = c->dat;
+
+    /* Validate lengths. */
+    servicelen = strlen(service) + 1;
+    instancelen = strlen(instance) + 1;
+    realmlen = strlen(realm) + 1;
+    if (sizeof(c->dat) / 8 < ((8 + servicelen + instancelen + realmlen
+			       + 1 + 1 + 1 + tkt->length
+			       + 4 + 7) / 8)
+	|| tkt->length > 255 || tkt->length < 0) {
+        c->length = 0;
+        return KFAILURE;
+    }
+
+    memcpy(ptr, session, 8);
+    ptr += 8;
+
+    memcpy(ptr, service, servicelen);
+    ptr += servicelen;
+    memcpy(ptr, instance, instancelen);
+    ptr += instancelen;
+    memcpy(ptr, realm, realmlen);
+    ptr += realmlen;
+
+    *ptr++ = life;
+    *ptr++ = kvno;
+    *ptr++ = tkt->length;
+
+    memcpy(ptr, tkt->dat, (size_t)tkt->length);
+    ptr += tkt->length;
+
+    KRB4_PUT32BE(ptr, kdc_time);
+
+    /* guarantee null padded encrypted data to multiple of 8 bytes */
+    memset(ptr, 0, 7);
+
+    c->length = (((ptr - c->dat) + 7) / 8) * 8;
+
+#ifndef NOENCRYPTION
+    key_sched(key, key_s);
+    pcbc_encrypt((C_Block *)c->dat, (C_Block *)c->dat,
+		 (long)c->length, key_s, (C_Block*)key, ENCRYPT);
+    memset(key_s, 0, sizeof(key_s));
+#endif /* NOENCRYPTION */
+
+    return KSUCCESS;
+}
diff --git a/mechglue/src/lib/krb4/cr_death_pkt.c b/mechglue/src/lib/krb4/cr_death_pkt.c
new file mode 100644
index 000000000..63d756277
--- /dev/null
+++ b/mechglue/src/lib/krb4/cr_death_pkt.c
@@ -0,0 +1,78 @@
+/*
+ * lib/krb4/cr_death_pkt.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+
+/*
+ * This routine creates a packet to type AUTH_MSG_DIE which is sent to
+ * the Kerberos server to make it shut down.  It is used only in the
+ * development environment.
+ *
+ * It takes a string "a_name" which is sent in the packet.  A pointer
+ * to the packet is returned.
+ *
+ * The format of the killer packet is:
+ *
+ * type			variable		data
+ *			or constant
+ * ----			-----------		----
+ *
+ * unsigned char	KRB_PROT_VERSION	protocol version number
+ * 
+ * unsigned char	AUTH_MSG_DIE		message type
+ * 
+ * [least significant	HOST_BYTE_ORDER		byte order of sender
+ *  bit of above field]
+ * 
+ * string		a_name			presumably, name of
+ * 						principal sending killer
+ * 						packet
+ */
+
+#ifdef DEBUG
+KTEXT
+krb_create_death_packet(a_name)
+    char *a_name;
+{
+    static KTEXT_ST pkt_st;
+    KTEXT pkt = &pkt_st;
+    unsigned char *p;
+    size_t namelen;
+
+    p = pkt->dat;
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_DIE;
+    namelen = strlen(a_name) + 1;
+    if (1 + 1 + namelen > sizeof(pkt->dat))
+	return NULL;
+    memcpy(p, a_name, namelen);
+    p += namelen;
+    pkt->length = p - pkt->dat;
+    return pkt;
+}
+#endif /* DEBUG */
diff --git a/mechglue/src/lib/krb4/cr_err_repl.c b/mechglue/src/lib/krb4/cr_err_repl.c
new file mode 100644
index 000000000..5dad8c1b1
--- /dev/null
+++ b/mechglue/src/lib/krb4/cr_err_repl.c
@@ -0,0 +1,110 @@
+/*
+ * lib/krb4/cr_err_repl.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+
+/*
+ * This routine is used by the Kerberos authentication server to
+ * create an error reply packet to send back to its client.
+ *
+ * It takes a pointer to the packet to be built, the name, instance,
+ * and realm of the principal, the client's timestamp, an error code
+ * and an error string as arguments.  Its return value is undefined.
+ *
+ * The packet is built in the following format:
+ * 
+ * type			variable	   data
+ *			or constant
+ * ----			-----------	   ----
+ *
+ * unsigned char	req_ack_vno	   protocol version number
+ * 
+ * unsigned char	AUTH_MSG_ERR_REPLY protocol message type
+ * 
+ * [least significant	HOST_BYTE_ORDER	   sender's (server's) byte
+ * bit of above field]			   order
+ * 
+ * string		pname		   principal's name
+ * 
+ * string		pinst		   principal's instance
+ * 
+ * string		prealm		   principal's realm
+ * 
+ * unsigned long	time_ws		   client's timestamp
+ * 
+ * unsigned long	e		   error code
+ * 
+ * string		e_string	   error text
+ */
+
+void
+cr_err_reply(pkt,pname,pinst,prealm,time_ws,e,e_string)
+    KTEXT pkt;
+    char *pname;		/* Principal's name */
+    char *pinst;		/* Principal's instance */
+    char *prealm;		/* Principal's authentication domain */
+    u_long time_ws;		/* Workstation time */
+    u_long e;			/* Error code */
+    char *e_string;		/* Text of error */
+{
+    unsigned char *p;
+    size_t pnamelen, pinstlen, prealmlen, e_stringlen;
+
+    p = pkt->dat;
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_ERR_REPLY;
+
+    /* Make sure the reply will fit into the buffer. */
+    pnamelen = strlen(pname) + 1;
+    pinstlen = strlen(pinst) + 1;
+    prealmlen = strlen(prealm) + 1;
+    e_stringlen = strlen(e_string) + 1;
+    if(sizeof(pkt->dat) < (1 + 1 + pnamelen + pinstlen + prealmlen
+			   + 4 + 4 + e_stringlen)) {
+        pkt->length = 0;
+	return;
+    }
+    /* Add the basic info */
+    memcpy(p, pname, pnamelen);
+    p += pnamelen;
+    memcpy(p, pinst, pinstlen);
+    p += pinstlen;
+    memcpy(p, prealm, prealmlen);
+    p += prealmlen;
+    /* ws timestamp */
+    KRB4_PUT32BE(p, time_ws);
+    /* err code */
+    KRB4_PUT32BE(p, e);
+    /* err text */
+    memcpy(p, e_string, e_stringlen);
+    p += e_stringlen;
+
+    /* And return */
+    pkt->length = p - pkt->dat;
+    return;
+}
diff --git a/mechglue/src/lib/krb4/cr_tkt.c b/mechglue/src/lib/krb4/cr_tkt.c
new file mode 100644
index 000000000..2c01257d8
--- /dev/null
+++ b/mechglue/src/lib/krb4/cr_tkt.c
@@ -0,0 +1,254 @@
+/*
+ * lib/krb4/cr_tkt.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <krb5.h>
+#include "des.h"
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+#include "port-sockets.h"
+
+static int
+krb_cr_tkt_int (KTEXT tkt, unsigned int flags_in, char *pname, 
+		char *pinstance, char *prealm, long paddress,
+		char *session, int life, long time_sec, 
+		char *sname, char *sinstance);
+
+/*
+ * Create ticket takes as arguments information that should be in a
+ * ticket, and the KTEXT object in which the ticket should be
+ * constructed.  It then constructs a ticket and returns, leaving the
+ * newly created ticket in tkt.
+#ifndef NOENCRYPTION
+ * The data in tkt->dat is encrypted in the server's key.
+#endif
+ * The length of the ticket is a multiple of
+ * eight bytes and is in tkt->length.
+ *
+ * If the ticket is too long, the ticket will contain nulls.
+ * The return value of the routine is undefined.
+ *
+ * The corresponding routine to extract information from a ticket it
+ * decomp_ticket.  When changes are made to this routine, the
+ * corresponding changes should also be made to that file.
+ *
+ * The packet is built in the following format:
+ * 
+ * 			variable
+ * type			or constant	   data
+ * ----			-----------	   ----
+ *
+ * tkt->length		length of ticket (multiple of 8 bytes)
+ * 
+#ifdef NOENCRYPTION
+ * tkt->dat:
+#else
+ * tkt->dat:		(encrypted in server's key)
+#endif
+ * 
+ * unsigned char	flags		   namely, HOST_BYTE_ORDER
+ * 
+ * string		pname		   client's name
+ * 
+ * string		pinstance	   client's instance
+ * 
+ * string		prealm		   client's realm
+ * 
+ * 4 bytes		paddress	   client's address
+ * 
+ * 8 bytes		session		   session key
+ * 
+ * 1 byte		life		   ticket lifetime
+ * 
+ * 4 bytes		time_sec	   KDC timestamp
+ * 
+ * string		sname		   service's name
+ * 
+ * string		sinstance	   service's instance
+ * 
+ * <=7 bytes		null		   null pad to 8 byte multiple
+ *
+ */
+int
+krb_create_ticket(tkt, flags, pname, pinstance, prealm, paddress,
+		  session, life, time_sec, sname, sinstance, key)
+    KTEXT   tkt;                /* Gets filled in by the ticket */
+    unsigned int flags;         /* Various Kerberos flags */
+    char    *pname;             /* Principal's name */
+    char    *pinstance;         /* Principal's instance */
+    char    *prealm;            /* Principal's authentication domain */
+    long    paddress;           /* Net address of requesting entity */
+    char    *session;           /* Session key inserted in ticket */
+    int     life;               /* Lifetime of the ticket */
+    long    time_sec;           /* Issue time and date */
+    char    *sname;             /* Service Name */
+    char    *sinstance;         /* Instance Name */
+    C_Block key;                /* Service's secret key */
+{
+    int kerr;
+    Key_schedule key_s;
+
+    kerr = krb_cr_tkt_int(tkt, flags, pname, pinstance, prealm, paddress,
+			  session, life, time_sec, sname, sinstance);
+    if (kerr)
+	return kerr;
+
+    /* Encrypt the ticket in the services key */
+    key_sched(key, key_s);
+    pcbc_encrypt((C_Block *)tkt->dat, (C_Block *)tkt->dat,
+		 (long)tkt->length, key_s, (C_Block *)key, 1);
+    memset(key_s, 0, sizeof(key_s));
+    return 0;
+}
+
+int
+krb_cr_tkt_krb5(tkt, flags, pname, pinstance, prealm, paddress,
+		  session, life, time_sec, sname, sinstance, k5key)
+    KTEXT   tkt;                /* Gets filled in by the ticket */
+    unsigned int flags;         /* Various Kerberos flags */
+    char    *pname;             /* Principal's name */
+    char    *pinstance;         /* Principal's instance */
+    char    *prealm;            /* Principal's authentication domain */
+    long    paddress;           /* Net address of requesting entity */
+    char    *session;           /* Session key inserted in ticket */
+    int     life;               /* Lifetime of the ticket */
+    long    time_sec;           /* Issue time and date */
+    char    *sname;             /* Service Name */
+    char    *sinstance;         /* Instance Name */
+    krb5_keyblock *k5key;	/* NULL if not present */
+{
+    int kerr;
+    krb5_data in;
+    krb5_enc_data out;
+    krb5_error_code ret;
+    size_t enclen;
+
+    kerr = krb_cr_tkt_int(tkt, flags, pname, pinstance, prealm,
+			  paddress, session, life, time_sec,
+			  sname, sinstance);
+    if (kerr)
+	return kerr;
+
+    /* Encrypt the ticket in the services key */
+    in.length = tkt->length;
+    in.data = (char *)tkt->dat;
+    /* XXX assumes context arg is ignored */
+    ret = krb5_c_encrypt_length(NULL, k5key->enctype,
+				(size_t)in.length, &enclen);
+    if (ret)
+	return KFAILURE;
+    out.ciphertext.length = enclen;
+    out.ciphertext.data = malloc(enclen);
+    if (out.ciphertext.data == NULL)
+	return KFAILURE;	/* XXX maybe ENOMEM? */
+
+    /* XXX assumes context arg is ignored */
+    ret = krb5_c_encrypt(NULL, k5key, KRB5_KEYUSAGE_KDC_REP_TICKET,
+			 NULL, &in, &out);
+    if (ret) {
+	free(out.ciphertext.data);
+	return KFAILURE;
+    } else {
+	tkt->length = out.ciphertext.length;
+	memcpy(tkt->dat, out.ciphertext.data, out.ciphertext.length);
+	memset(out.ciphertext.data, 0, out.ciphertext.length);
+	free(out.ciphertext.data);
+    }
+    return 0;
+}
+
+static int
+krb_cr_tkt_int(tkt, flags_in, pname, pinstance, prealm, paddress,
+	       session, life, time_sec, sname, sinstance)
+    KTEXT   tkt;                /* Gets filled in by the ticket */
+    unsigned int flags_in;      /* Various Kerberos flags */
+    char    *pname;             /* Principal's name */
+    char    *pinstance;         /* Principal's instance */
+    char    *prealm;            /* Principal's authentication domain */
+    long    paddress;           /* Net address of requesting entity */
+    char    *session;           /* Session key inserted in ticket */
+    int     life;               /* Lifetime of the ticket */
+    long    time_sec;           /* Issue time and date */
+    char    *sname;             /* Service Name */
+    char    *sinstance;         /* Instance Name */
+{
+    register unsigned char *data; /* running index into ticket */
+    size_t pnamelen, pinstlen, prealmlen, snamelen, sinstlen;
+    struct in_addr paddr;
+
+    /* Be really paranoid. */
+    if (sizeof(paddr.s_addr) != 4)
+	return KFAILURE;
+
+    tkt->length = 0;            /* Clear previous data  */
+
+    /* Check length of ticket */
+    pnamelen = strlen(pname) + 1;
+    pinstlen = strlen(pinstance) + 1;
+    prealmlen = strlen(prealm) + 1;
+    snamelen = strlen(sname) + 1;
+    sinstlen = strlen(sinstance) + 1;
+    if (sizeof(tkt->dat) / 8 < ((1 + pnamelen + pinstlen + prealmlen
+				 + 4 /* address */
+				 + 8 /* session */
+				 + 1 /* life */
+				 + 4 /* issue time */
+				 + snamelen + sinstlen
+				 + 7) / 8) /* roundoff */
+	|| life > 255 || life < 0) {
+        memset(tkt->dat, 0, sizeof(tkt->dat));
+        return KFAILURE /* XXX */;
+    }
+
+    data = tkt->dat;
+    *data++ = flags_in;
+    memcpy(data, pname, pnamelen);
+    data += pnamelen;
+    memcpy(data, pinstance, pinstlen);
+    data += pinstlen;
+    memcpy(data, prealm, prealmlen);
+    data += prealmlen;
+
+    paddr.s_addr = paddress;
+    memcpy(data, &paddr.s_addr, sizeof(paddr.s_addr));
+    data += sizeof(paddr.s_addr);
+
+    memcpy(data, session, 8);
+    data += 8;
+    *data++ = life;
+    /* issue time */
+    KRB4_PUT32BE(data, time_sec);
+
+    memcpy(data, sname, snamelen);
+    data += snamelen;
+    memcpy(data, sinstance, sinstlen);
+    data += sinstlen;
+
+    /* guarantee null padded ticket to multiple of 8 bytes */
+    memset(data, 0, 7);
+    tkt->length = ((data - tkt->dat + 7) / 8) * 8;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb4/debug.c b/mechglue/src/lib/krb4/debug.c
new file mode 100644
index 000000000..bd2ec904a
--- /dev/null
+++ b/mechglue/src/lib/krb4/debug.c
@@ -0,0 +1,15 @@
+/*
+ * debug.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+
+/* Declare global debugging variables. */
+
+int krb_ap_req_debug = 0;
+int krb_debug = 0;
diff --git a/mechglue/src/lib/krb4/decomp_tkt.c b/mechglue/src/lib/krb4/decomp_tkt.c
new file mode 100644
index 000000000..7d85991a0
--- /dev/null
+++ b/mechglue/src/lib/krb4/decomp_tkt.c
@@ -0,0 +1,295 @@
+/*
+ * lib/krb4/decomp_tkt.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000, 2001 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "des.h"
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+#include <krb5.h>
+#include "krb54proto.h"
+#include "port-sockets.h"
+
+#ifdef KRB_CRYPT_DEBUG
+extern int krb_debug;
+#endif
+
+static int dcmp_tkt_int (KTEXT tkt, unsigned char *flags, 
+				   char *pname, char *pinstance, char *prealm,
+				   unsigned KRB4_32 *paddress, C_Block session,
+				   int *life, unsigned KRB4_32 *time_sec, 
+				   char *sname, char *sinstance, C_Block key, 
+				   Key_schedule key_s, krb5_keyblock *k5key);
+/*
+ * This routine takes a ticket and pointers to the variables that
+ * should be filled in based on the information in the ticket.  It
+#ifndef NOENCRYPTION
+ * decrypts the ticket using the given key, and 
+#endif
+ * fills in values for its arguments.
+ *
+ * Note: if the client realm field in the ticket is the null string,
+ * then the "prealm" variable is filled in with the local realm (as
+ * defined by KRB_REALM).
+ *
+ * If the ticket byte order is different than the host's byte order
+ * (as indicated by the byte order bit of the "flags" field), then
+ * the KDC timestamp "time_sec" is byte-swapped.  The other fields
+ * potentially affected by byte order, "paddress" and "session" are
+ * not byte-swapped.
+ *
+ * The routine returns KFAILURE if any of the "pname", "pinstance",
+ * or "prealm" fields is too big, otherwise it returns KSUCCESS.
+ *
+ * The corresponding routine to generate tickets is create_ticket.
+ * When changes are made to this routine, the corresponding changes
+ * should also be made to that file.
+ *
+ * See create_ticket.c for the format of the ticket packet.
+ */
+
+int KRB5_CALLCONV		/* XXX should this be exported on win32? */
+decomp_ticket(tkt, flags, pname, pinstance, prealm, paddress, session,
+              life, time_sec, sname, sinstance, key, key_s)
+    KTEXT tkt;			/* The ticket to be decoded */
+    unsigned char *flags;       /* Kerberos ticket flags */
+    char *pname;		/* Authentication name */
+    char *pinstance;		/* Principal's instance */
+    char *prealm;		/* Principal's authentication domain */
+    unsigned KRB4_32 *paddress; /* Net address of entity
+                                 * requesting ticket */
+    C_Block session;		/* Session key inserted in ticket */
+    int *life; 		        /* Lifetime of the ticket */
+    unsigned KRB4_32 *time_sec; /* Issue time and date */
+    char *sname;		/* Service name */
+    char *sinstance;		/* Service instance */
+    C_Block key;		/* Service's secret key
+                                 * (to decrypt the ticket) */
+    Key_schedule key_s;		/* The precomputed key schedule */
+{
+    return
+	dcmp_tkt_int(tkt, flags, pname, pinstance, prealm,
+		     paddress, session, life, time_sec, sname, sinstance,
+		     key, key_s, NULL);
+}
+
+int
+decomp_tkt_krb5(tkt, flags, pname, pinstance, prealm, paddress, session,
+              life, time_sec, sname, sinstance, k5key)
+    KTEXT tkt;			/* The ticket to be decoded */
+    unsigned char *flags;       /* Kerberos ticket flags */
+    char *pname;		/* Authentication name */
+    char *pinstance;		/* Principal's instance */
+    char *prealm;		/* Principal's authentication domain */
+    unsigned KRB4_32 *paddress; /* Net address of entity
+                                 * requesting ticket */
+    C_Block session;		/* Session key inserted in ticket */
+    int *life; 		        /* Lifetime of the ticket */
+    unsigned KRB4_32 *time_sec; /* Issue time and date */
+    char *sname;		/* Service name */
+    char *sinstance;		/* Service instance */
+    krb5_keyblock *k5key;	/* krb5 keyblock of service */
+{
+    C_Block key;		/* placeholder; doesn't get used */
+    Key_schedule key_s;		/* placeholder; doesn't get used */
+
+    return
+	dcmp_tkt_int(tkt, flags, pname, pinstance, prealm, paddress, session,
+		     life, time_sec, sname, sinstance, key, key_s, k5key);
+}
+
+static int
+dcmp_tkt_int(tkt, flags, pname, pinstance, prealm, paddress, session,
+              life, time_sec, sname, sinstance, key, key_s, k5key)
+    KTEXT tkt;			/* The ticket to be decoded */
+    unsigned char *flags;       /* Kerberos ticket flags */
+    char *pname;		/* Authentication name */
+    char *pinstance;		/* Principal's instance */
+    char *prealm;		/* Principal's authentication domain */
+    unsigned KRB4_32 *paddress; /* Net address of entity
+                                 * requesting ticket */
+    C_Block session;		/* Session key inserted in ticket */
+    int *life; 		        /* Lifetime of the ticket */
+    unsigned KRB4_32 *time_sec; /* Issue time and date */
+    char *sname;		/* Service name */
+    char *sinstance;		/* Service instance */
+    C_Block key;		/* Service's secret key
+                                 * (to decrypt the ticket) */
+    Key_schedule key_s;		/* The precomputed key schedule */
+    krb5_keyblock *k5key;	/* krb5 keyblock of service */
+{
+    int tkt_le;			/* little-endian ticket? */
+    unsigned char *ptr = tkt->dat;
+    int kret, len;
+    struct in_addr paddr;
+
+    /* Be really paranoid. */
+    if (sizeof(paddr.s_addr) != 4)
+	return KFAILURE;
+
+#ifndef NOENCRYPTION
+    /* Do the decryption */
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_debug) {
+	FILE *fp;
+	char *keybuf[BUFSIZ];	/* Avoid secret stuff in stdio buffers */
+
+	fp = fopen("/kerberos/tkt.des", "wb");
+	setbuf(fp, keybuf);
+	fwrite(tkt->dat, 1, tkt->length, fp);
+	fclose(fp);
+	memset(keybuf, 0, sizeof(keybuf));	/* Clear the buffer */
+    }
+#endif
+    if (k5key != NULL) {
+	/* block locals */
+	krb5_enc_data in;
+	krb5_data out;
+	krb5_error_code ret;
+
+	in.enctype = k5key->enctype;
+	in.kvno = 0;
+	in.ciphertext.length = tkt->length;
+	in.ciphertext.data = (char *)tkt->dat;
+	out.length = tkt->length;
+	out.data = malloc((size_t)tkt->length);
+	if (out.data == NULL)
+	    return KFAILURE;	/* XXX maybe ENOMEM? */
+
+	/* XXX note the following assumes that context arg isn't used  */
+	ret =
+	    krb5_c_decrypt(NULL, k5key,
+			   KRB5_KEYUSAGE_KDC_REP_TICKET, NULL, &in, &out);
+	if (ret) {
+	    free(out.data);
+	    return KFAILURE;
+	} else {
+	    memcpy(tkt->dat, out.data, out.length);
+	    memset(out.data, 0, out.length);
+	    free(out.data);
+	}
+    } else {
+	pcbc_encrypt((C_Block *)tkt->dat, (C_Block *)tkt->dat,
+		     (long)tkt->length, key_s, (C_Block *)key, 0);
+    }
+#endif /* ! NOENCRYPTION */
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_debug) {
+	FILE *fp;
+	char *keybuf[BUFSIZ];	/* Avoid secret stuff in stdio buffers */
+
+	fp = fopen("/kerberos/tkt.clear", "wb");
+	setbuf(fp, keybuf);
+	fwrite(tkt->dat, 1, tkt->length, fp);
+	fclose(fp);
+	memset(keybuf, 0, sizeof(keybuf));	/* Clear the buffer */
+    }
+#endif
+
+#define TKT_REMAIN (tkt->length - (ptr - tkt->dat))
+    kret = KFAILURE;
+    if (TKT_REMAIN < 1)
+	goto cleanup;
+    *flags = *ptr++;
+    tkt_le = (*flags >> K_FLAG_ORDER) & 1;
+
+    len = krb4int_strnlen((char *)ptr, TKT_REMAIN) + 1;
+    if (len <= 0 || len > ANAME_SZ)
+	goto cleanup;
+    memcpy(pname, ptr, (size_t)len);
+    ptr += len;
+
+    len = krb4int_strnlen((char *)ptr, TKT_REMAIN) + 1;
+    if (len <= 0 || len > INST_SZ)
+	goto cleanup;
+    memcpy(pinstance, ptr, (size_t)len);
+    ptr += len;
+
+    len = krb4int_strnlen((char *)ptr, TKT_REMAIN) + 1;
+    if (len <= 0 || len > REALM_SZ)
+	goto cleanup;
+    memcpy(prealm, ptr, (size_t)len);
+    ptr += len;
+
+    /*
+     * This hack may be needed for some really krb4 servers, such as
+     * AFS kaserver (?), that fail to fill in the realm of a ticket
+     * under some circumstances.
+     */
+    if (*prealm == '\0')
+	krb_get_lrealm(prealm, 1);
+
+    /*
+     * Ensure there's enough remaining in the ticket to get the
+     * fixed-size stuff.
+     */
+    if (TKT_REMAIN < 4 + 8 + 1 + 4)
+	goto cleanup;
+
+    memcpy(&paddr.s_addr, ptr, sizeof(paddr.s_addr));
+    ptr += sizeof(paddr.s_addr);
+    *paddress = paddr.s_addr;
+
+    memcpy(session, ptr, 8); /* session key */
+    memset(ptr, 0, 8);
+    ptr += 8;
+#ifdef notdef /* DONT SWAP SESSION KEY spm 10/22/86 */
+    if (tkt_swap_bytes)
+        swap_C_Block(session);
+#endif
+
+    *life = *ptr++;
+
+    KRB4_GET32(*time_sec, ptr, tkt_le);
+
+    len = krb4int_strnlen((char *)ptr, TKT_REMAIN) + 1;
+    if (len <= 0 || len > SNAME_SZ)
+	goto cleanup;
+    memcpy(sname, ptr, (size_t)len);
+    ptr += len;
+
+    len = krb4int_strnlen((char *)ptr, TKT_REMAIN) + 1;
+    if (len <= 0 || len > INST_SZ)
+	goto cleanup;
+    memcpy(sinstance, ptr, (size_t)len);
+    ptr += len;
+    kret = KSUCCESS;
+
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_debug) {
+	krb_log("service=%s.%s len(sname)=%d, len(sinstance)=%d",
+		sname, sinstance, strlen(sname), strlen(sinstance));
+	krb_log("ptr - tkt->dat=%d",(char *)ptr - (char *)tkt->dat);
+    }
+#endif
+
+cleanup:
+    if (kret != KSUCCESS) {
+	memset(session, 0, sizeof(session));
+	memset(tkt->dat, 0, (size_t)tkt->length);
+	return kret;
+    }
+    return KSUCCESS;
+}
diff --git a/mechglue/src/lib/krb4/dest_tkt.c b/mechglue/src/lib/krb4/dest_tkt.c
new file mode 100644
index 000000000..4f7c1e377
--- /dev/null
+++ b/mechglue/src/lib/krb4/dest_tkt.c
@@ -0,0 +1,160 @@
+/*
+ * lib/krb4/dest_tkt.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000, 2001 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "k5-util.h"
+#define do_seteuid krb5_seteuid
+
+#ifdef TKT_SHMEM
+#include <sys/param.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#ifndef O_SYNC
+#define O_SYNC 0
+#endif
+
+/*
+ * dest_tkt() is used to destroy the ticket store upon logout.
+ * If the ticket file does not exist, dest_tkt() returns RET_TKFIL.
+ * Otherwise the function returns RET_OK on success, KFAILURE on
+ * failure.
+ *
+ * The ticket file (TKT_FILE) is defined in "krb.h".
+ */
+
+int KRB5_CALLCONV
+dest_tkt()
+{
+    const char *file = TKT_FILE;
+    int i,fd;
+    int ret;
+    struct stat statpre, statpost;
+    char buf[BUFSIZ];
+    uid_t me, metoo;
+#ifdef TKT_SHMEM
+    char shmidname[MAXPATHLEN];
+    size_t shmidlen;
+#endif /* TKT_SHMEM */
+
+    /* If ticket cache selector is null, use default cache.  */
+    if (file == 0)
+	file = tkt_string();
+
+    errno = 0;
+    ret = KSUCCESS;
+    me = getuid();
+    metoo = geteuid();
+
+    if (lstat(file, &statpre) < 0)
+	return (errno == ENOENT) ? RET_TKFIL : KFAILURE;
+    /*
+     * This does not guard against certain cases that are vulnerable
+     * to race conditions, such as world-writable or group-writable
+     * directories that are not stickybitted, or untrusted path
+     * components.  In all other cases, the following checks should be
+     * sufficient.  It is assumed that the aforementioned certain
+     * vulnerable cases are unlikely to arise on a well-administered
+     * system where the user is not deliberately being stupid.
+     */
+    if (!(statpre.st_mode & S_IFREG) || me != statpre.st_uid
+	|| statpre.st_nlink != 1)
+	return KFAILURE;
+    /*
+     * Yes, we do uid twiddling here.  It's not optimal, but some
+     * applications may expect that the ruid is what should really own
+     * the ticket file, e.g. setuid applications.
+     */
+    if (me != metoo && do_seteuid(me) < 0)
+	return KFAILURE;
+    if ((fd = open(file, O_RDWR|O_SYNC, 0)) < 0) {
+	ret = (errno == ENOENT) ? RET_TKFIL : KFAILURE;
+	goto out;
+    }
+    /*
+     * Do some additional paranoid things.  The worst-case situation
+     * is that a user may be fooled into opening a non-regular file
+     * briefly if the file is in a directory with improper
+     * permissions.
+     */
+    if (fstat(fd, &statpost) < 0) {
+	(void)close(fd);
+	ret = KFAILURE;
+	goto out;
+    }
+    if (statpre.st_dev != statpost.st_dev
+	|| statpre.st_ino != statpost.st_ino) {
+	(void)close(fd);
+	errno = 0;
+	ret = KFAILURE;
+	goto out;
+    }
+
+    memset(buf, 0, BUFSIZ);
+    for (i = 0; i < statpost.st_size; i += BUFSIZ)
+	if (write(fd, buf, BUFSIZ) != BUFSIZ) {
+#ifndef NO_FSYNC
+	    (void) fsync(fd);
+#endif
+	    (void) close(fd);
+	    goto out;
+	}
+
+#ifndef NO_FSYNC
+    (void) fsync(fd);
+#endif
+    (void) close(fd);
+
+    (void) unlink(file);
+
+out:
+    if (me != metoo && do_seteuid(metoo) < 0)
+	return KFAILURE;
+    if (ret != KSUCCESS)
+	return ret;
+
+#ifdef TKT_SHMEM
+    /* 
+     * handle the shared memory case 
+     */
+    shmidlen = strlen(file) + sizeof(".shm");
+    if (shmidlen > sizeof(shmidname))
+	return RET_TKFIL;
+    (void)strcpy(shmidname, file);
+    (void)strcat(shmidname, ".shm");
+    return krb_shm_dest(shmidname);
+#else  /* !TKT_SHMEM */
+    return KSUCCESS;
+#endif /* !TKT_SHMEM */
+}
diff --git a/mechglue/src/lib/krb4/err_txt.c b/mechglue/src/lib/krb4/err_txt.c
new file mode 100644
index 000000000..0c4a01158
--- /dev/null
+++ b/mechglue/src/lib/krb4/err_txt.c
@@ -0,0 +1,87 @@
+/*
+ * lib/krb4/err_txt.c
+ *
+ * Copyright 1988, 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "krb4int.h"
+
+/*
+ * This is gross.  We want krb_err_txt to match the contents of the
+ * com_err error table, but the text is static in krb_err.c.  We can't
+ * alias it by making a pointer to it, either, so we have to suck in
+ * another copy of it that is named differently.   */
+#if TARGET_OS_MAC && !defined(DEPEND)
+#undef initialize_krb_error_table
+#define initialize_krb_error_table	krb4int_init_krb_err_tbl
+void krb4int_init_krb_err_tbl(void);
+#include "krb_err.c"
+#undef initialize_krb_error_table
+
+/*
+ * Depends on the name of the static table generated by compile_et,
+ * but since this is only on Darwin, where we will always use a
+ * certain compile_et, it should be ok.
+ */
+const char * const * const krb_err_txt = text;
+#else
+#ifndef DEPEND
+/* Don't put this in auto-generated dependencies. */
+#include "krb_err_txt.c"
+#endif
+#endif
+
+void initialize_krb_error_table(void);
+
+static int inited = 0;
+
+void
+krb4int_et_init(void)
+{
+    if (inited)
+	return;
+    add_error_table(&et_krb_error_table);
+    inited = 1;\
+}
+
+void
+krb4int_et_fini(void)
+{
+    if (inited)
+	remove_error_table(&et_krb_error_table);
+}
+
+const char * KRB5_CALLCONV
+krb_get_err_text(code)
+    int code;
+{
+    krb4int_et_init();
+    /*
+     * Shift krb error code into com_err number space.
+     */
+    if (code >= 0 && code < MAX_KRB_ERRORS)
+	return error_message(ERROR_TABLE_BASE_krb + code);
+    else
+	return "Invalid Kerberos error code";
+}
diff --git a/mechglue/src/lib/krb4/et_errtxt.awk b/mechglue/src/lib/krb4/et_errtxt.awk
new file mode 100755
index 000000000..888dad695
--- /dev/null
+++ b/mechglue/src/lib/krb4/et_errtxt.awk
@@ -0,0 +1,71 @@
+/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ {
+	print "/*" > outfile
+	print " * " outfile ":" > outfile
+	print " * This file is automatically generated; please do not edit it." > outfile
+	print " */" > outfile
+	print "#if TARGET_OS_MAC" > outfile
+	print "const char * const * const krb_err_txt" > outfile
+	print "#else" > outfile
+	print "const char * const krb_err_txt[]" > outfile
+	print "#endif" > outfile
+	print "\t= {" > outfile
+	table_item_count = 0
+}
+
+(continuation == 1) && ($0 ~ /\\[ \t]*$/) {
+	text=substr($0,1,length($0)-1);
+#	printf "\t\t\"%s\"\n", text > outfile
+	cont_buf=cont_buf text;
+}
+
+(continuation == 1) && ($0 ~ /"[ \t]*$/) {
+# "
+#	printf "\t\t\"%s,\n", $0 > outfile
+	printf "\t%s,\n", cont_buf $0 > outfile
+	continuation = 0;
+}
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*$/ {
+	table_item_count++
+	skipone=1
+	next
+}
+
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*"[ \t]*$/ {
+	text=""
+	for (i=3; i<=NF; i++) { 
+	    text = text FS $i
+	}
+	text=substr(text,2,length(text)-1);
+	printf "\t%s,\n", text > outfile
+	table_item_count++
+}
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*\\[ \t]*$/ {
+	text=""
+	for (i=3; i<=NF; i++) { 
+	    text = text FS $i
+	}
+	text=substr(text,2,length(text)-2);
+#	printf "\t%s\"\n", text > outfile
+	cont_buf=text
+	continuation++;
+}
+
+/^[ \t]*".*\\[ \t]*$/ {
+	if (skipone) {
+	    text=substr($0,1,length($0)-1);
+#	    printf "\t%s\"\n", text > outfile
+	    cont_buf=text
+	    continuation++;
+	}
+	skipone=0
+}
+
+{ 
+	if (skipone) {
+	    printf "\t%s,\n", $0 > outfile
+	}
+	skipone=0
+}
+END {
+	print "};" > outfile
+}
diff --git a/mechglue/src/lib/krb4/fakeenv.c b/mechglue/src/lib/krb4/fakeenv.c
new file mode 100644
index 000000000..d4f4d7638
--- /dev/null
+++ b/mechglue/src/lib/krb4/fakeenv.c
@@ -0,0 +1,88 @@
+/*
+ * fakeenv.c
+ *
+ * Originally written by Mark Eichin, Cygnus Support, 1992.
+ * Public Domain.
+ *
+ * setenv --
+ *	Set the value of the environmental variable "name" to be
+ *	"value".  If rewrite is set, replace any current value.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+setenv(name, value, rewrite)
+	register char *name, *value;
+	int rewrite;
+{
+	char *combo = malloc(strlen(name)+strlen(value)+2);
+	strcpy(combo,name);
+	strcat(combo,"=");
+	strcat(combo,value);
+	putenv(combo);
+}
+
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * _findenv --
+ *	Returns pointer to value associated with name, if any, else NULL.
+ *	Sets offset to be the offset of the name/value combination in the
+ *	environmental array, for use by setenv(3) and unsetenv(3).
+ *	Explicitly removes '=' in argument name.
+ *
+ *	This routine *should* be a static; don't use it.
+ */
+static char *
+_findenv(name, offset)
+	register char *name;
+	int *offset;
+{
+	extern char **environ;
+	register int len;
+	register char **P, *C;
+
+	for (C = name, len = 0; *C && *C != '='; ++C, ++len);
+	for (P = environ; *P; ++P)
+		if (!strncmp(*P, name, len))
+			if (*(C = *P + len) == '=') {
+				*offset = P - environ;
+				return(++C);
+			}
+	return(NULL);
+}
+
+/*
+ * unsetenv(name) --
+ *	Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+	char	*name;
+{
+	extern	char	**environ;
+	register char	**P;
+	int	offset;
+	char    *_findenv();
+
+	while (_findenv(name, &offset))		/* if set multiple times */
+		for (P = &environ[offset];; ++P)
+			if (!(*P = *(P + 1)))
+				break;
+}
diff --git a/mechglue/src/lib/krb4/fgetst.c b/mechglue/src/lib/krb4/fgetst.c
new file mode 100644
index 000000000..e652ac93a
--- /dev/null
+++ b/mechglue/src/lib/krb4/fgetst.c
@@ -0,0 +1,38 @@
+/*
+ * fgetst.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology. 
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>. 
+ */
+
+#include "mit-copyright.h"
+#include <stdio.h>
+#include "krb.h"
+#include "krb4int.h"
+
+/*
+ * fgetst takes a file descriptor, a character pointer, and a count.
+ * It reads from the file it has either read "count" characters, or
+ * until it reads a null byte.  When finished, what has been read exists
+ * in "s". If "count" characters were actually read, the last is changed
+ * to a null, so the returned string is always null-terminated.  fgetst
+ * returns the number of characters read, including the null terminator. 
+ */
+
+int
+fgetst(f, s, n)
+    FILE   *f;
+    register char *s;
+    int     n;
+{
+    register int count = n;
+    int     ch;		/* NOT char; otherwise you don't see EOF */
+
+    while ((ch = getc(f)) != EOF && ch && --count) {
+	*s++ = ch;
+    }
+    *s = '\0';
+    return (n - count);
+}
diff --git a/mechglue/src/lib/krb4/g_ad_tkt.c b/mechglue/src/lib/krb4/g_ad_tkt.c
new file mode 100644
index 000000000..353fdcee5
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_ad_tkt.c
@@ -0,0 +1,383 @@
+/*
+ * lib/krb4/g_ad_tkt.c
+ *
+ * Copyright 1986, 1987, 1988, 2000, 2001 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "des.h"
+#include "krb4int.h"
+#include "prot.h"
+#include <string.h>
+
+#include <stdio.h>
+
+extern int krb_debug;
+extern int swap_bytes;
+
+/*
+ * get_ad_tkt obtains a new service ticket from Kerberos, using
+ * the ticket-granting ticket which must be in the ticket file.
+ * It is typically called by krb_mk_req() when the client side
+ * of an application is creating authentication information to be
+ * sent to the server side.
+ *
+ * get_ad_tkt takes four arguments: three pointers to strings which
+ * contain the name, instance, and realm of the service for which the
+ * ticket is to be obtained; and an integer indicating the desired
+ * lifetime of the ticket.
+ *
+ * It returns an error status if the ticket couldn't be obtained,
+ * or AD_OK if all went well.  The ticket is stored in the ticket
+ * cache.
+ *
+ * The request sent to the Kerberos ticket-granting service looks
+ * like this:
+ *
+ * pkt->dat
+ *
+ * TEXT			original contents of	authenticator+ticket
+ *			pkt->dat		built in krb_mk_req call
+ * 
+ * 4 bytes		time_ws			always 0 (?)  FIXME!
+ * char			lifetime		lifetime argument passed
+ * string		service			service name argument
+ * string		sinstance		service instance arg.
+ *
+ * See "prot.h" for the reply packet layout and definitions of the
+ * extraction macros like pkt_version(), pkt_msg_type(), etc.
+ */
+
+/*
+ * g_ad_tk_parse()
+ *
+ * Parse the returned packet from the KDC.
+ *
+ * Note that the caller is responsible for clearing the returned
+ * session key if there is an error; that makes the error handling
+ * code a little less hairy.
+ */
+static int
+g_ad_tkt_parse(KTEXT rpkt, C_Block tgtses, C_Block ses,
+	       char *s_name, char *s_instance, char *rlm,
+	       char *service, char *sinstance, char *realm,
+	       int *lifetime, int *kvno, KTEXT tkt,
+	       unsigned KRB4_32 *kdc_time,
+	       KRB4_32 *t_local)
+{
+    unsigned char *ptr;
+    unsigned int t_switch;
+    int msg_byte_order;
+    unsigned long rep_err_code;
+    unsigned long cip_len;
+    KTEXT_ST cip_st;
+    KTEXT cip = &cip_st;	/* Returned Ciphertext */
+    Key_schedule key_s;
+    int len, i;
+    KRB4_32 t_diff;		/* Difference between timestamps */
+
+    ptr = rpkt->dat;
+#define RPKT_REMAIN (rpkt->length - (ptr - rpkt->dat))
+    if (RPKT_REMAIN < 1 + 1)
+	return INTK_PROT;
+    /* check packet version of the returned packet */
+    if (*ptr++ != KRB_PROT_VERSION)
+	return INTK_PROT;
+
+    /* This used to be
+         switch (pkt_msg_type(rpkt) & ~1) {
+       but SCO 3.2v4 cc compiled that incorrectly.  */
+    t_switch = *ptr++;
+    /* Check byte order (little-endian == 1) */
+    msg_byte_order = t_switch & 1;
+    t_switch &= ~1;
+    /*
+     * Skip over some stuff (3 strings and various integers -- see
+     * cr_auth_repl.c for details).  Maybe we should actually verify
+     * these?
+     */
+    for (i = 0; i < 3; i++) {
+	len = krb4int_strnlen((char *)ptr, RPKT_REMAIN) + 1;
+	if (len <= 0)
+	    return INTK_PROT;
+	ptr += len;
+    }
+    switch (t_switch) {
+    case AUTH_MSG_KDC_REPLY:
+	if (RPKT_REMAIN < 4 + 1 + 4 + 1)
+	    return INTK_PROT;
+	ptr += 4 + 1 + 4 + 1;
+	break;
+    case AUTH_MSG_ERR_REPLY:
+	if (RPKT_REMAIN < 8)
+	    return INTK_PROT;
+	ptr += 4;
+	KRB4_GET32(rep_err_code, ptr, msg_byte_order);
+	return rep_err_code;
+
+    default:
+	return INTK_PROT;
+    }
+
+    /* Extract the ciphertext */
+    if (RPKT_REMAIN < 2)
+	return INTK_PROT;
+    KRB4_GET16(cip_len, ptr, msg_byte_order);
+    if (RPKT_REMAIN < cip_len)
+	return INTK_PROT;
+    /*
+     * RPKT_REMAIN will always be non-negative and at most the maximum
+     * possible value of cip->length, so this assignment is safe.
+     */
+    cip->length = cip_len;
+    memcpy(cip->dat, ptr, (size_t)cip->length);
+    ptr += cip->length;
+
+#ifndef NOENCRYPTION
+    /* Attempt to decrypt it */
+
+    key_sched(tgtses, key_s);
+    DEB (("About to do decryption ..."));
+    pcbc_encrypt((C_Block *)cip->dat, (C_Block *)cip->dat,
+                 (long)cip->length, key_s, (C_Block *)tgtses, 0);
+#endif /* !NOENCRYPTION */
+    /*
+     * Stomp on key schedule.  Caller should stomp on tgtses.
+     */
+    memset(key_s, 0, sizeof(key_s));
+
+    ptr = cip->dat;
+#define CIP_REMAIN (cip->length - (ptr - cip->dat))
+    if (CIP_REMAIN < 8)
+	return RD_AP_MODIFIED;
+    memcpy(ses, ptr, 8);
+    /*
+     * Stomp on decrypted session key immediately after copying it.
+     */
+    memset(ptr, 0, 8);
+    ptr += 8;
+
+    len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
+    if (len <= 0 || len > SNAME_SZ)
+	return RD_AP_MODIFIED;
+    memcpy(s_name, ptr, (size_t)len);
+    ptr += len;
+
+    len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
+    if (len <= 0 || len > INST_SZ)
+	return RD_AP_MODIFIED;
+    memcpy(s_instance, ptr, (size_t)len);
+    ptr += len;
+
+    len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
+    if (len <= 0 || len > REALM_SZ)
+	return RD_AP_MODIFIED;
+    memcpy(rlm, ptr, (size_t)len);
+    ptr += len;
+
+    if (strcmp(s_name, service) || strcmp(s_instance, sinstance)
+	|| strcmp(rlm, realm))	/* not what we asked for */
+	return INTK_ERR;	/* we need a better code here XXX */
+
+    if (CIP_REMAIN < 1 + 1 + 1)
+	return RD_AP_MODIFIED;
+    *lifetime = *ptr++;
+    *kvno = *ptr++;
+    tkt->length = *ptr++;
+
+    if (CIP_REMAIN < tkt->length)
+	return RD_AP_MODIFIED;
+    memcpy(tkt->dat, ptr, (size_t)tkt->length);
+    ptr += tkt->length;
+
+    /* Time (coarse) */
+    if (CIP_REMAIN < 4)
+	return RD_AP_MODIFIED;
+    KRB4_GET32(*kdc_time, ptr, msg_byte_order);
+
+    /* check KDC time stamp */
+    *t_local = TIME_GMT_UNIXSEC;
+    t_diff = *t_local - *kdc_time;
+    if (t_diff < 0)
+	t_diff = -t_diff;	/* Absolute value of difference */
+    if (t_diff > CLOCK_SKEW)
+	return RD_AP_TIME;	/* XXX should probably be better code */
+
+    return 0;
+}
+
+int KRB5_CALLCONV
+get_ad_tkt(service, sinstance, realm, lifetime)
+    char    *service;
+    char    *sinstance;
+    char    *realm;
+    int     lifetime;
+{
+    KTEXT_ST pkt_st;
+    KTEXT pkt = & pkt_st;	/* Packet to KDC */
+    KTEXT_ST rpkt_st;
+    KTEXT rpkt = &rpkt_st;	/* Returned packet */
+    KTEXT_ST tkt_st;
+    KTEXT tkt = &tkt_st;	/* Current ticket */
+    C_Block ses;                /* Session key for tkt */
+    CREDENTIALS cr;
+    int kvno;			/* Kvno for session key */
+    int kerror;
+    char lrealm[REALM_SZ];
+    KRB4_32 time_ws = 0;
+    char s_name[SNAME_SZ];
+    char s_instance[INST_SZ];
+    char rlm[REALM_SZ];
+    unsigned char *ptr;
+    KRB4_32 t_local;
+    struct sockaddr_in laddr;
+    socklen_t addrlen;
+    unsigned KRB4_32 kdc_time;   /* KDC time */
+    size_t snamelen, sinstlen;
+
+    kerror = krb_get_tf_realm(TKT_FILE, lrealm);
+#if USE_LOGIN_LIBRARY
+    if (kerror == GC_NOTKT) {
+        /* No tickets... call krb_get_cred (KLL will prompt) and try again. */
+        if ((kerror = krb_get_cred ("krbtgt", realm, realm, &cr)) == KSUCCESS) {
+            /* Now get the realm again. */
+            kerror = krb_get_tf_realm (TKT_FILE, lrealm);
+        }
+    }
+#endif
+    if (kerror != KSUCCESS)
+	return kerror;
+
+    /* Create skeleton of packet to be sent */
+    pkt->length = 0;
+
+    /*
+     * Look for the session key (and other stuff we don't need)
+     * in the ticket file for krbtgt.realm@lrealm where "realm" 
+     * is the service's realm (passed in "realm" argument) and 
+     * "lrealm" is the realm of our initial ticket (the local realm).
+     * If that fails, and the server's realm and the local realm are
+     * the same thing, give up - no TGT available for local realm.
+     *
+     * If the server realm and local realm are different, though,
+     * try getting a ticket-granting ticket for the server's realm,
+     * i.e. a ticket for "krbtgt.alienrealm@lrealm", by calling get_ad_tkt().
+     * If that succeeds, the ticket will be in ticket cache, get it
+     * into the "cr" structure by calling krb_get_cred().
+     */
+    kerror = krb_get_cred("krbtgt", realm, lrealm, &cr);
+    if (kerror != KSUCCESS) {
+	/*
+	 * If realm == lrealm, we have no hope, so let's not even try.
+	 */
+	if (strncmp(realm, lrealm, sizeof(lrealm)) == 0)
+	    return AD_NOTGT;
+	else {
+	    kerror = get_ad_tkt("krbtgt", realm, lrealm, lifetime);
+	    if (kerror != KSUCCESS) {
+		if (kerror == KDC_PR_UNKNOWN)	/* no cross-realm ticket */
+		    return AD_NOTGT;		/* So call it no ticket */
+		return kerror;
+	    }
+	    kerror = krb_get_cred("krbtgt",realm,lrealm,&cr);
+	    if (kerror != KSUCCESS)
+		return kerror;
+	}
+    }
+
+    /*
+     * Make up a request packet to the "krbtgt.realm@lrealm".
+     * Start by calling krb_mk_req() which puts ticket+authenticator
+     * into "pkt".  Then tack other stuff on the end.
+     */
+    kerror = krb_mk_req(pkt, "krbtgt", realm, lrealm, 0L);
+    if (kerror) {
+	/* stomp stomp stomp */
+	memset(cr.session, 0, sizeof(cr.session));
+	return AD_NOTGT;
+    }
+
+    ptr = pkt->dat + pkt->length;
+
+    snamelen = strlen(service) + 1;
+    sinstlen = strlen(sinstance) + 1;
+    if (sizeof(pkt->dat) - (ptr - pkt->dat) < (4 + 1
+					       + snamelen
+					       + sinstlen)) {
+	/* stomp stomp stomp */
+	memset(cr.session, 0, sizeof(cr.session));
+	return INTK_ERR;
+    }
+
+    /* timestamp */   /* FIXME -- always 0 now, should we fill it in??? */
+    KRB4_PUT32BE(ptr, time_ws);
+
+    *ptr++ = lifetime;
+
+    memcpy(ptr, service, snamelen);
+    ptr += snamelen;
+    memcpy(ptr, sinstance, sinstlen);
+    ptr += sinstlen;
+
+    pkt->length = ptr - pkt->dat;
+
+    /* Send the request to the local ticket-granting server */
+    rpkt->length = 0;
+    addrlen = sizeof(laddr);
+    kerror = krb4int_send_to_kdc_addr(pkt, rpkt, realm,
+				      (struct sockaddr *)&laddr, &addrlen);
+
+    if (!kerror) {
+	/* No error; parse return packet from KDC. */
+	kerror = g_ad_tkt_parse(rpkt, cr.session, ses,
+				s_name, s_instance, rlm,
+				service, sinstance, realm,
+				&lifetime, &kvno, tkt,
+				&kdc_time, &t_local);
+    }
+    /*
+     * Unconditionally stomp on cr.session because we don't need it
+     * anymore.
+     */
+    memset(cr.session, 0, sizeof(cr.session));
+    if (kerror) {
+	/*
+	 * Stomp on ses for good measure, since g_ad_tkt_parse()
+	 * doesn't do that for us.
+	 */
+	memset(ses, 0, sizeof(ses));
+	return kerror;
+    }
+
+    kerror = krb4int_save_credentials_addr(s_name, s_instance, rlm,
+					   ses, lifetime, kvno, tkt,
+					   t_local,
+					   laddr.sin_addr.s_addr);
+    /*
+     * Unconditionally stomp on ses because we don't need it anymore.
+     */
+    memset(ses, 0, sizeof(ses));
+    if (kerror)
+	return kerror;
+    return AD_OK;
+}
diff --git a/mechglue/src/lib/krb4/g_cnffile.c b/mechglue/src/lib/krb4/g_cnffile.c
new file mode 100644
index 000000000..dd5ed5c60
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_cnffile.c
@@ -0,0 +1,123 @@
+/* Copyright 1994 Cygnus Support */
+/* Mark W. Eichin */
+/*
+ * Permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation.
+ * Cygnus Support makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/* common code for looking at krb.conf and krb.realms file */
+/* this may be superceded by <gnu>'s work for the Mac port, but
+   it solves a problem for now. */
+
+#include <stdio.h>
+#include "krb.h"
+#include "k5-int.h"
+#include "krb4int.h"
+
+krb5_context krb5__krb4_context = 0;
+
+static FILE*
+krb__v5_get_file(s)
+     const char *s;
+{
+	FILE *cnffile = 0;
+	const char* names[3];
+	char **full_name = 0, **cpp;
+	krb5_error_code retval;
+
+	if (!krb5__krb4_context)
+		krb5_init_context(&krb5__krb4_context);
+	names[0] = "libdefaults";
+	names[1] = s;
+	names[2] = 0;
+	if (krb5__krb4_context) {
+	    retval = profile_get_values(krb5__krb4_context->profile, names, 
+					&full_name);
+	    if (retval == 0 && full_name && full_name[0]) {
+		cnffile = fopen(full_name[0],"r");
+		for (cpp = full_name; *cpp; cpp++) 
+		    krb5_xfree(*cpp);
+		krb5_xfree(full_name);
+	    }
+	}
+	return cnffile;
+}
+
+char *
+krb__get_srvtabname(default_srvtabname)
+	const char *default_srvtabname;
+{
+	const char* names[3];
+	char **full_name = 0, **cpp;
+	krb5_error_code retval;
+	static char retname[MAXPATHLEN];
+
+	if (!krb5__krb4_context)
+		krb5_init_context(&krb5__krb4_context);
+	names[0] = "libdefaults";
+	names[1] = "krb4_srvtab";
+	names[2] = 0;
+	if (krb5__krb4_context) {
+	    retval = profile_get_values(krb5__krb4_context->profile, names, 
+					&full_name);
+	    if (retval == 0 && full_name && full_name[0]) {
+		retname[0] = '\0';
+		strncat(retname, full_name[0], sizeof(retname));
+		for (cpp = full_name; *cpp; cpp++) 
+		    krb5_xfree(*cpp);
+		krb5_xfree(full_name);
+		return retname;
+	    }
+	}
+	retname[0] = '\0';
+	strncat(retname, default_srvtabname, sizeof(retname));
+	return retname;
+}
+
+FILE*
+krb__get_cnffile()
+{
+	char *s;
+	FILE *cnffile = 0;
+	extern char *getenv();
+
+	/* standard V4 override first */
+	s = getenv("KRB_CONF");
+	if (s) cnffile = fopen(s,"r");
+	/* if that's wrong, use V5 config */
+	if (!cnffile) cnffile = krb__v5_get_file("krb4_config");
+	/* and if V5 config doesn't have it, go to hard-coded values */
+	if (!cnffile) cnffile = fopen(KRB_CONF,"r");
+#ifdef ATHENA_CONF_FALLBACK
+	if (!cnffile) cnffile = fopen(KRB_FB_CONF,"r");
+#endif
+	return cnffile;
+}
+
+
+FILE*
+krb__get_realmsfile()
+{
+	FILE *realmsfile = 0;
+	char *s;
+
+	/* standard (not really) V4 override first */
+	s = getenv("KRB_REALMS");
+	if (s) realmsfile = fopen(s,"r");
+	if (!realmsfile) realmsfile = krb__v5_get_file("krb4_realms");
+	if (!realmsfile) realmsfile = fopen(KRB_RLM_TRANS, "r");
+
+#ifdef ATHENA_CONF_FALLBACK
+	if (!realmsfile) realmsfile = fopen(KRB_FB_RLM_TRANS, "r");
+#endif
+
+	return realmsfile;
+}
+
+
diff --git a/mechglue/src/lib/krb4/g_cred.c b/mechglue/src/lib/krb4/g_cred.c
new file mode 100644
index 000000000..498a5f106
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_cred.c
@@ -0,0 +1,58 @@
+/*
+ * g_cred.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include <stdio.h>
+#include <string.h>
+#include "krb.h"
+
+/*
+ * krb_get_cred takes a service name, instance, and realm, and a
+ * structure of type CREDENTIALS to be filled in with ticket
+ * information.  It then searches the ticket file for the appropriate
+ * ticket and fills in the structure with the corresponding
+ * information from the file.  If successful, it returns KSUCCESS.
+ * On failure it returns a Kerberos error code.
+ */
+
+int KRB5_CALLCONV
+krb_get_cred(service,instance,realm,c)
+    char *service;		/* Service name */
+    char *instance;		/* Instance */
+    char *realm;		/* Auth domain */
+    CREDENTIALS *c;		/* Credentials struct */
+{
+    int tf_status;              /* return value of tf function calls */
+
+    /* Open ticket file and lock it for shared reading */
+    if ((tf_status = tf_init(TKT_FILE, R_TKT_FIL)) != KSUCCESS)
+	return(tf_status);
+
+    /* Copy principal's name and instance into the CREDENTIALS struc c */
+
+    if ( (tf_status = tf_get_pname(c->pname)) != KSUCCESS ||
+    	 (tf_status = tf_get_pinst(c->pinst)) != KSUCCESS )
+	return (tf_status);
+
+    /* Search for requested service credentials and copy into c */
+       
+    while ((tf_status = tf_get_cred(c)) == KSUCCESS) {
+        /* Is this the right ticket? */
+	if ((strcmp(c->service,service) == 0) &&
+           (strcmp(c->instance,instance) == 0) &&
+           (strcmp(c->realm,realm) == 0))
+		   break;
+    }
+    (void) tf_close();
+
+    if (tf_status == EOF)
+	return (GC_NOTKT);
+    return(tf_status);
+}
diff --git a/mechglue/src/lib/krb4/g_in_tkt.c b/mechglue/src/lib/krb4/g_in_tkt.c
new file mode 100644
index 000000000..58a91b00d
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_in_tkt.c
@@ -0,0 +1,535 @@
+/*
+ * lib/krb4/g_in_tkt.c
+ *
+ * Copyright 1986-2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "des.h"
+#include "krb4int.h"
+#include "prot.h"
+
+#include "port-sockets.h"
+#include <string.h>
+
+/* Define a couple of function types including parameters.  These
+   are needed on MS-Windows to convert arguments of the function pointers
+   to the proper types during calls.  These declarations are found
+   in <krb-sed.h>, but the code below is too opaque if you can't also
+   see them here.  */
+#ifndef	KEY_PROC_TYPE_DEFINED
+typedef int (*key_proc_type) (char *, char *, char *,
+					     char *, C_Block);
+#endif
+#ifndef	DECRYPT_TKT_TYPE_DEFINED
+typedef int (*decrypt_tkt_type) (char *, char *, char *, char *,
+				     key_proc_type, KTEXT *);
+#endif
+
+static int decrypt_tkt(char *, char *, char *, char *, key_proc_type, KTEXT *);
+static int krb_mk_in_tkt_preauth(char *, char *, char *, char *, char *,
+				 int, char *, int, KTEXT, int *, struct sockaddr_in *);			
+static int krb_parse_in_tkt_creds(char *, char *, char *, char *, char *,
+				  int, KTEXT, int, CREDENTIALS *);
+
+/*
+ * decrypt_tkt(): Given user, instance, realm, passwd, key_proc
+ * and the cipher text sent from the KDC, decrypt the cipher text
+ * using the key returned by key_proc.
+ */
+
+static int
+decrypt_tkt(user, instance, realm, arg, key_proc, cipp)
+    char *user;
+    char *instance;
+    char *realm;
+    char *arg;
+    key_proc_type key_proc;
+    KTEXT *cipp;
+{
+    KTEXT cip = *cipp;
+    C_Block key;		/* Key for decrypting cipher */
+    Key_schedule key_s;
+    register int rc;
+
+#ifndef NOENCRYPTION
+    /* Attempt to decrypt it */
+#endif
+    /* generate a key from the supplied arg or password.  */
+    rc = (*key_proc)(user, instance, realm, arg, key);
+    if (rc)
+	return rc;
+
+#ifndef NOENCRYPTION
+    key_sched(key, key_s);
+    pcbc_encrypt((C_Block *)cip->dat, (C_Block *)cip->dat,
+		 (long)cip->length, key_s, (C_Block *)key, 0);
+#endif /* !NOENCRYPTION */
+    /* Get rid of all traces of key */
+    memset(key, 0, sizeof(key));
+    memset(key_s, 0, sizeof(key_s));
+
+    return 0;
+}
+
+/*
+ * krb_get_in_tkt() gets a ticket for a given principal to use a given
+ * service and stores the returned ticket and session key for future
+ * use.
+ *
+ * The "user", "instance", and "realm" arguments give the identity of
+ * the client who will use the ticket.  The "service" and "sinstance"
+ * arguments give the identity of the server that the client wishes
+ * to use.  (The realm of the server is the same as the Kerberos server
+ * to whom the request is sent.)  The "life" argument indicates the
+ * desired lifetime of the ticket; the "key_proc" argument is a pointer
+ * to the routine used for getting the client's private key to decrypt
+ * the reply from Kerberos.  The "decrypt_proc" argument is a pointer
+ * to the routine used to decrypt the reply from Kerberos; and "arg"
+ * is an argument to be passed on to the "key_proc" routine.
+ *
+ * If all goes well, krb_get_in_tkt() returns INTK_OK, otherwise it
+ * returns an error code:  If an AUTH_MSG_ERR_REPLY packet is returned
+ * by Kerberos, then the error code it contains is returned.  Other
+ * error codes returned by this routine include INTK_PROT to indicate
+ * wrong protocol version, INTK_BADPW to indicate bad password (if
+ * decrypted ticket didn't make sense), INTK_ERR if the ticket was for
+ * the wrong server or the ticket store couldn't be initialized.
+ *
+ * The format of the message sent to Kerberos is as follows:
+ *
+ * Size			Variable		Field
+ * ----			--------		-----
+ *
+ * 1 byte		KRB_PROT_VERSION	protocol version number
+ * 1 byte		AUTH_MSG_KDC_REQUEST |	message type
+ *			HOST_BYTE_ORDER		local byte order in lsb
+ * string		user			client's name
+ * string		instance		client's instance
+ * string		realm			client's realm
+ * 4 bytes		tlocal.tv_sec		timestamp in seconds
+ * 1 byte		life			desired lifetime
+ * string		service			service's name
+ * string		sinstance		service's instance
+ */
+
+static int
+krb_mk_in_tkt_preauth(user, instance, realm, service, sinstance, life,
+		      preauth_p, preauth_len, cip, byteorder, local_addr)
+    char *user;
+    char *instance;
+    char *realm;
+    char *service;
+    char *sinstance;
+    int life;
+    char *preauth_p;
+    int   preauth_len;
+    KTEXT cip;
+    int  *byteorder;
+    struct sockaddr_in *local_addr;
+{
+    KTEXT_ST pkt_st;
+    KTEXT pkt = &pkt_st;	/* Packet to KDC */
+    KTEXT_ST rpkt_st;
+    KTEXT rpkt = &rpkt_st;	/* Returned packet */
+    unsigned char *p;
+    size_t userlen, instlen, realmlen, servicelen, sinstlen;
+    unsigned KRB4_32 t_local;
+
+    int msg_byte_order;
+    int kerror;
+    socklen_t addrlen;
+#if 0
+    unsigned long exp_date;
+#endif
+    unsigned long rep_err_code;
+    unsigned long cip_len;
+    unsigned int t_switch;
+    int i, len;
+
+    /* BUILD REQUEST PACKET */
+
+    p = pkt->dat;
+
+    userlen = strlen(user) + 1;
+    instlen = strlen(instance) + 1;
+    realmlen = strlen(realm) + 1;
+    servicelen = strlen(service) + 1;
+    sinstlen = strlen(sinstance) + 1;
+    /* Make sure the ticket data will fit into the buffer. */
+    if (sizeof(pkt->dat) < (1 + 1 + userlen + instlen + realmlen
+			    + 4 + 1 + servicelen + sinstlen
+			    + preauth_len)) {
+        pkt->length = 0;
+	return INTK_ERR;
+    }
+
+    /* Set up the fixed part of the packet */
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_KDC_REQUEST;
+
+    /* Now for the variable info */
+    memcpy(p, user, userlen);
+    p += userlen;
+    memcpy(p, instance, instlen);
+    p += instlen;
+    memcpy(p, realm, realmlen);
+    p += realmlen;
+
+    /* timestamp */
+    t_local = TIME_GMT_UNIXSEC;
+    KRB4_PUT32BE(p, t_local);
+
+    *p++ = life;
+
+    memcpy(p, service, servicelen);
+    p += servicelen;
+    memcpy(p, sinstance, sinstlen);
+    p += sinstlen;
+
+    if (preauth_len)
+	memcpy(p, preauth_p, (size_t)preauth_len);
+    p += preauth_len;
+
+    pkt->length = p - pkt->dat;
+
+    /* SEND THE REQUEST AND RECEIVE THE RETURN PACKET */
+    rpkt->length = 0;
+    addrlen = sizeof(struct sockaddr_in);
+    kerror = krb4int_send_to_kdc_addr(pkt, rpkt, realm,
+				      (struct sockaddr *)local_addr,
+				      &addrlen);
+    if (kerror)
+	return kerror;
+
+    p = rpkt->dat;
+#define RPKT_REMAIN (rpkt->length - (p - rpkt->dat))
+
+    /* check packet version of the returned packet */
+    if (RPKT_REMAIN < 1 + 1)
+	return INTK_PROT;
+    if (*p++ != KRB_PROT_VERSION)
+        return INTK_PROT;
+
+    /* This used to be
+         switch (pkt_msg_type(rpkt) & ~1) {
+       but SCO 3.2v4 cc compiled that incorrectly.  */
+    t_switch = *p++;
+    /* Check byte order */
+    msg_byte_order = t_switch & 1;
+    t_switch &= ~1;
+
+    /* EXTRACT INFORMATION FROM RETURN PACKET */
+
+    /*
+     * Skip over some stuff (3 strings and various integers -- see
+     * cr_auth_repl.c for details).
+     */
+    for (i = 0; i < 3; i++) {
+	len = krb4int_strnlen((char *)p, RPKT_REMAIN) + 1;
+	if (len <= 0)
+	    return INTK_PROT;
+	p += len;
+    }
+    switch (t_switch) {
+    case AUTH_MSG_KDC_REPLY:
+	if (RPKT_REMAIN < 4 + 1 + 4 + 1)
+	    return INTK_PROT;
+	p += 4 + 1 + 4 + 1;
+        break;
+    case AUTH_MSG_ERR_REPLY:
+	if (RPKT_REMAIN < 8)
+	    return INTK_PROT;
+	p += 4;
+	KRB4_GET32(rep_err_code, p, msg_byte_order);
+	return rep_err_code;
+    default:
+        return INTK_PROT;
+    }
+
+    /* Extract the ciphertext */
+    if (RPKT_REMAIN < 2)
+	return INTK_PROT;
+    KRB4_GET16(cip_len, p, msg_byte_order);
+    if (RPKT_REMAIN < cip_len)
+	return INTK_ERR;
+    /*
+     * RPKT_REMAIN will always be non-negative and at most the maximum
+     * possible value of cip->length, so this assignment is safe.
+     */
+    cip->length = cip_len;
+    memcpy(cip->dat, p, (size_t)cip->length);
+    p += cip->length;
+
+    *byteorder = msg_byte_order;
+    return INTK_OK;
+}
+
+static int
+krb_parse_in_tkt_creds(user, instance, realm, service, sinstance, life, cip,
+		       byteorder, creds)
+    char *user;
+    char *instance;
+    char *realm;
+    char *service;
+    char *sinstance;
+    int life;
+    KTEXT cip;
+    int byteorder;
+    CREDENTIALS *creds;
+{
+    unsigned char *ptr;
+    int len;
+    int kvno;			/* Kvno for session key */
+    char s_name[SNAME_SZ];
+    char s_instance[INST_SZ];
+    char rlm[REALM_SZ];
+    KTEXT_ST tkt_st;
+    KTEXT tkt = &tkt_st;	/* Current ticket */
+    unsigned long kdc_time;   /* KDC time */
+    unsigned KRB4_32 t_local;	/* Must be 4 bytes long for memcpy below! */
+    KRB4_32 t_diff;	/* Difference between timestamps */
+    int lifetime;
+
+    ptr = cip->dat;
+    /* Assume that cip->length >= 0 for now. */
+#define CIP_REMAIN (cip->length - (ptr - cip->dat))
+
+    /* Skip session key for now */
+    if (CIP_REMAIN < 8)
+	return INTK_BADPW;
+    ptr += 8;
+
+    /* extract server's name */
+    len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
+    if (len <= 0 || len > sizeof(s_name))
+	return INTK_BADPW;
+    memcpy(s_name, ptr, (size_t)len);
+    ptr += len;
+
+    /* extract server's instance */
+    len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
+    if (len <= 0 || len > sizeof(s_instance))
+	return INTK_BADPW;
+    memcpy(s_instance, ptr, (size_t)len);
+    ptr += len;
+
+    /* extract server's realm */
+    len = krb4int_strnlen((char *)ptr, CIP_REMAIN) + 1;
+    if (len <= 0 || len > sizeof(rlm))
+	return INTK_BADPW;
+    memcpy(rlm, ptr, (size_t)len);
+    ptr += len;
+
+    /* extract ticket lifetime, server key version, ticket length */
+    /* be sure to avoid sign extension on lifetime! */
+    if (CIP_REMAIN < 3)
+	return INTK_BADPW;
+    lifetime = *ptr++;
+    kvno = *ptr++;
+    tkt->length = *ptr++;
+
+    /* extract ticket itself */
+    if (CIP_REMAIN < tkt->length)
+	return INTK_BADPW;
+    memcpy(tkt->dat, ptr, (size_t)tkt->length);
+    ptr += tkt->length;
+
+    if (strcmp(s_name, service) || strcmp(s_instance, sinstance)
+	|| strcmp(rlm, realm))	/* not what we asked for */
+	return INTK_ERR;	/* we need a better code here XXX */
+
+    /* check KDC time stamp */
+    if (CIP_REMAIN < 4)
+	return INTK_BADPW;
+    KRB4_GET32(kdc_time, ptr, byteorder);
+
+    t_local = TIME_GMT_UNIXSEC;
+    t_diff = t_local - kdc_time;
+    if (t_diff < 0)
+	t_diff = -t_diff;	/* Absolute value of difference */
+    if (t_diff > CLOCK_SKEW) {
+        return RD_AP_TIME;	/* XXX should probably be better code */
+    }
+
+    /* stash ticket, session key, etc. for future use */
+    strncpy(creds->service, s_name, sizeof(creds->service));
+    strncpy(creds->instance, s_instance, sizeof(creds->instance));
+    strncpy(creds->realm, rlm, sizeof(creds->realm));
+    memmove(creds->session, cip->dat, sizeof(C_Block));
+    creds->lifetime = lifetime;
+    creds->kvno = kvno;
+    creds->ticket_st.length = tkt->length;
+    memmove(creds->ticket_st.dat, tkt->dat, (size_t)tkt->length);
+    creds->issue_date = t_local;
+    strncpy(creds->pname, user, sizeof(creds->pname));
+    strncpy(creds->pinst, instance, sizeof(creds->pinst));
+
+    return INTK_OK;
+}
+
+int
+krb_get_in_tkt_preauth_creds(user, instance, realm, service, sinstance, life,
+			     key_proc, decrypt_proc,
+			     arg, preauth_p, preauth_len, creds, laddrp)
+    char *user;
+    char *instance;
+    char *realm;
+    char *service;
+    char *sinstance;
+    int life;
+    key_proc_type key_proc;
+    decrypt_tkt_type decrypt_proc;
+    char *arg;
+    char *preauth_p;
+    int   preauth_len;
+    CREDENTIALS *creds;
+    KRB_UINT32 *laddrp;
+{
+    KTEXT_ST cip_st;
+    KTEXT cip = &cip_st;	/* Returned Ciphertext */
+    int kerror;
+    int byteorder;
+    key_proc_type *keyprocs = krb_get_keyprocs (key_proc);
+    int i = 0;
+    struct sockaddr_in local_addr;
+
+    kerror = krb_mk_in_tkt_preauth(user, instance, realm, 
+				   service, sinstance,
+				   life, preauth_p, preauth_len,
+				   cip, &byteorder, &local_addr);
+    if (kerror)
+	return kerror;
+    
+    /* Attempt to decrypt the reply.  Loop trying password_to_key algorithms 
+       until we succeed or we get an error other than "bad password" */
+    do {
+	KTEXT_ST cip_copy_st;
+	memcpy(&cip_copy_st, &cip_st, sizeof(cip_st));
+	cip = &cip_copy_st;
+        if (decrypt_proc == NULL) {
+            decrypt_tkt (user, instance, realm, arg, keyprocs[i], &cip);
+        } else {
+            (*decrypt_proc)(user, instance, realm, arg, keyprocs[i], &cip);
+        }
+        kerror = krb_parse_in_tkt_creds(user, instance, realm,
+                    service, sinstance, life, cip, byteorder, creds);
+    } while ((keyprocs [++i] != NULL) && (kerror == INTK_BADPW));
+    cip = &cip_st;
+
+    /* Fill in the local address if the caller wants it */
+    if (laddrp != NULL) {
+        *laddrp = local_addr.sin_addr.s_addr;
+    }
+
+    /* stomp stomp stomp */
+    memset(cip->dat, 0, (size_t)cip->length);
+    return kerror;
+}
+
+int KRB5_CALLCONV
+krb_get_in_tkt_creds(user, instance, realm, service, sinstance, life,
+		     key_proc, decrypt_proc, arg, creds)
+    char *user;
+    char *instance;
+    char *realm;
+    char *service;
+    char *sinstance;
+    int life;
+    key_proc_type key_proc;
+    decrypt_tkt_type decrypt_proc;
+    char *arg;
+    CREDENTIALS *creds;
+{
+#if TARGET_OS_MAC
+    KRB_UINT32 *laddrp = &creds->address;
+#else
+    KRB_UINT32 *laddrp = NULL; /* Only the Mac stores the address */
+#endif
+    
+    return krb_get_in_tkt_preauth_creds(user, instance, realm,
+					service, sinstance, life,
+					key_proc, decrypt_proc, arg,
+					NULL, 0, creds, laddrp);
+}
+
+int KRB5_CALLCONV
+krb_get_in_tkt_preauth(user, instance, realm, service, sinstance, life,
+		       key_proc, decrypt_proc,
+		       arg, preauth_p, preauth_len)
+    char *user;
+    char *instance;
+    char *realm;
+    char *service;
+    char *sinstance;
+    int life;
+    key_proc_type key_proc;
+    decrypt_tkt_type decrypt_proc;
+    char *arg;
+    char *preauth_p;
+    int   preauth_len;
+{
+    int retval;
+    KRB_UINT32 laddr;
+    CREDENTIALS creds;
+
+    do {
+	retval = krb_get_in_tkt_preauth_creds(user, instance, realm,
+					      service, sinstance, life,
+					      key_proc, decrypt_proc,
+					      arg, preauth_p, preauth_len,
+					      &creds, &laddr);
+	if (retval != KSUCCESS) break;
+	if (krb_in_tkt(user, instance, realm) != KSUCCESS) {
+	    retval = INTK_ERR;
+	    break;
+	}
+	retval = krb4int_save_credentials_addr(creds.service, creds.instance,
+					       creds.realm, creds.session,
+					       creds.lifetime, creds.kvno,
+					       &creds.ticket_st,
+					       creds.issue_date, laddr);
+	if (retval != KSUCCESS) break;
+    } while (0);
+    memset(&creds, 0, sizeof(creds));
+    return retval;
+}
+
+int KRB5_CALLCONV
+krb_get_in_tkt(user, instance, realm, service, sinstance, life,
+               key_proc, decrypt_proc, arg)
+    char *user;
+    char *instance;
+    char *realm;
+    char *service;
+    char *sinstance;
+    int life;
+    key_proc_type key_proc;
+    decrypt_tkt_type decrypt_proc;
+    char *arg;
+{
+    return krb_get_in_tkt_preauth(user, instance, realm,
+				  service, sinstance, life,
+			   	  key_proc, decrypt_proc, arg,
+				  NULL, 0);
+}
diff --git a/mechglue/src/lib/krb4/g_phost.c b/mechglue/src/lib/krb4/g_phost.c
new file mode 100644
index 000000000..ba1108f21
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_phost.c
@@ -0,0 +1,92 @@
+/*
+ * lib/krb4/g_phost.c
+ *
+ * Copyright 1988, 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "port-sockets.h"
+
+/*
+ * This routine takes an alias for a host name and returns the first
+ * field, lower case, of its domain name.  For example, if "menel" is
+ * an alias for host officially named "menelaus" (in /etc/hosts), for
+ * the host whose official name is "MENELAUS.MIT.EDU", the name "menelaus"
+ * is returned.
+ *
+ * This is done for historical Athena reasons: the Kerberos name of
+ * rcmd servers (rlogin, rsh, rcp) is of the form "rcmd.host@realm"
+ * where "host"is the lowercase for of the host name ("menelaus").
+ * This should go away: the instance should be the domain name
+ * (MENELAUS.MIT.EDU).  But for now we need this routine...
+ *
+ * A pointer to the name is returned, if found, otherwise a pointer
+ * to the original "alias" argument is returned.
+ */
+
+char * KRB5_CALLCONV
+krb_get_phost(alias)
+    char *alias;
+{
+    struct hostent *h;
+    char *p;
+    unsigned char *ucp;
+    static char hostname_mem[MAXHOSTNAMELEN];
+#ifdef DO_REVERSE_RESOLVE
+    char *rev_addr; int rev_type, rev_len;
+#endif
+
+    if ((h=gethostbyname(alias)) != (struct hostent *)NULL ) {
+#ifdef DO_REVERSE_RESOLVE
+	if (! h->h_addr_list ||! h->h_addr_list[0]) {
+		return(0);
+	}
+	rev_type = h->h_addrtype;
+	rev_len = h->h_length;
+	rev_addr = malloc(rev_len);
+	_fmemcpy(rev_addr, h->h_addr_list[0], rev_len);
+	h = gethostbyaddr(rev_addr, rev_len, rev_type);
+	free(rev_addr);
+	if (h == 0) {
+		return (0);
+	}
+#endif
+	/* We don't want to return a *, so we copy to a safe location. */
+	strncpy (hostname_mem, h->h_name, sizeof (hostname_mem));
+	/* Bail out if h_name is too long. */
+	if (hostname_mem[MAXHOSTNAMELEN-1] != '\0')
+	    return NULL;
+	p = strchr( hostname_mem, '.' );
+        if (p)
+            *p = 0;
+        ucp = (unsigned char *)hostname_mem;
+        do {
+            if (isupper(*ucp)) *ucp=tolower(*ucp);
+        } while (*ucp++);
+    }
+    return(hostname_mem);
+}
diff --git a/mechglue/src/lib/krb4/g_pw_in_tkt.c b/mechglue/src/lib/krb4/g_pw_in_tkt.c
new file mode 100644
index 000000000..db2bb8730
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_pw_in_tkt.c
@@ -0,0 +1,383 @@
+/*
+ * lib/krb4/g_pw_in_tkt.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <krb5.h>
+#include "krb.h"
+#include "krb4int.h"
+#include "krb_err.h"
+#include "prot.h"
+#include <string.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef INTK_PW_NULL
+#define INTK_PW_NULL KRBET_GT_PW_NULL
+#endif
+
+/*
+ * This file contains two routines: passwd_to_key() converts
+ * a password into a DES key (prompting for the password if
+ * not supplied), and krb_get_pw_in_tkt() gets an initial ticket for
+ * a user.
+ */
+
+/*
+ * passwd_to_key(): given a password, return a DES key.
+ * There are extra arguments here which (used to be?)
+ * used by srvtab_to_key().
+ *
+ * If the "passwd" argument is not null, generate a DES
+ * key from it, using string_to_key().
+ *
+ * If the "passwd" argument is null, then on a Unix system we call
+ * des_read_password() to prompt for a password and then convert it
+ * into a DES key.  But "prompting" the user is harder in a Windows or
+ * Macintosh environment, so we rely on our caller to explicitly do
+ * that now.
+ *
+ * In either case, the resulting key is put in the "key" argument,
+ * and 0 is returned.
+ */
+/*ARGSUSED */
+static int
+passwd_to_key(user,instance,realm,passwd,key)
+    char *user, *instance, *realm, *passwd;
+    C_Block key;
+{
+#if defined(_WIN32)
+    string_to_key(passwd, key);
+#else /* unix */
+#ifdef NOENCRYPTION
+    if (!passwd)
+	placebo_read_password(key, "Password: ", 0);
+#else /* Do encyryption */
+    if (passwd)
+        string_to_key(passwd, key);
+    else {
+        des_read_password((des_cblock *)key, "Password", 0);
+    }
+#endif /* NOENCRYPTION */
+#endif /* unix */
+    return (0);
+}
+
+/*
+ * krb_get_pw_in_tkt() takes the name of the server for which the initial
+ * ticket is to be obtained, the name of the principal the ticket is
+ * for, the desired lifetime of the ticket, and the user's password.
+ * It passes its arguments on to krb_get_in_tkt(), which contacts
+ * Kerberos to get the ticket, decrypts it using the password provided,
+ * and stores it away for future use.
+ *
+ * On a Unix system, krb_get_pw_in_tkt() is able to prompt the user
+ * for a password, if the supplied password is null.  On a a non Unix
+ * system, it now requires the caller to supply a non-null password.
+ * This is because of the complexities of prompting the user in a
+ * non-terminal-oriented environment like the Macintosh (running in a
+ * driver) or MS-Windows (in a DLL).
+ *
+ * krb_get_pw_in_tkt() passes two additional arguments to krb_get_in_tkt():
+ * the name of a routine (passwd_to_key()) to be used to get the
+ * password in case the "password" argument is null and NULL for the
+ * decryption procedure indicating that krb_get_in_tkt should use the 
+ * default method of decrypting the response from the KDC.
+ *
+ * The result of the call to krb_get_in_tkt() is returned.
+ */
+
+int KRB5_CALLCONV
+krb_get_pw_in_tkt(user,instance,realm,service,sinstance,life,password)
+    char *user, *instance, *realm, *service, *sinstance;
+    int life;
+    char *password;
+{
+#if defined(_WIN32) || (defined(USE_LOGIN_LIBRARY) && USE_LOGIN_LIBRARY)
+    /* In spite of the comments above, we don't allow that path here,
+       to simplify coding the non-UNIX clients. The only code that now
+       depends on this behavior is the preauth support, which has a
+       seperate function without this trap. Strictly speaking, this 
+       is an API change. */
+
+    if (password == 0)
+    	return INTK_PW_NULL;
+#endif
+
+    return(krb_get_in_tkt(user,instance,realm,service,sinstance,life,
+                          (key_proc_type)NULL, /* krb_get_in_tkt will try them all */
+                          (decrypt_tkt_type)NULL, password));
+}
+
+int KRB5_CALLCONV
+krb_get_pw_in_tkt_creds(
+    char *user, char *instance, char *realm, char *service, char *sinstance,
+    int life, char *password, CREDENTIALS *creds)
+{
+    return krb_get_in_tkt_creds(user, instance, realm,
+				service, sinstance, life,
+				(key_proc_type)NULL,  /* krb_get_in_tkt_creds will try them all */
+				NULL, password, creds);
+}
+
+
+/*
+ * krb_get_pw_in_tkt_preauth() gets handed the password or key explicitly,
+ * since the whole point of "pre" authentication is to prove that we've
+ * already got the key, and the only way to do that is to ask the user
+ * for it. Clearly we shouldn't ask twice.
+ */
+ 
+static C_Block old_key;
+
+static int stub_key(user,instance,realm,passwd,key)
+    char *user, *instance, *realm, *passwd;
+    C_Block key;
+{
+   (void) memcpy((char *) key, (char *) old_key, sizeof(old_key));
+   return 0;
+}
+
+int KRB5_CALLCONV
+krb_get_pw_in_tkt_preauth(user,instance,realm,service,sinstance,life,password)
+    char *user, *instance, *realm, *service, *sinstance;
+    int life;
+    char *password;
+{
+    char          *preauth_p;
+    int            preauth_len;
+    int            ret_st;
+    key_proc_type *keyprocs = krb_get_keyprocs (NULL);
+    int            i = 0;
+    
+#if defined(_WIN32) || (defined(USE_LOGIN_LIBRARY) && USE_LOGIN_LIBRARY)
+   /* On non-Unix systems, we can't handle a null password, because
+      passwd_to_key can't handle prompting for the password.  */
+    if (password == 0)
+        return INTK_PW_NULL;
+#endif
+
+    /* Loop trying all the key_proc types */
+	do {
+        krb_mk_preauth(&preauth_p, &preauth_len, keyprocs[i],
+                            user, instance, realm, password, old_key);
+        ret_st = krb_get_in_tkt_preauth(user,instance,realm,service,sinstance,life,
+				   (key_proc_type) stub_key,
+				   (decrypt_tkt_type) NULL, password,
+				   preauth_p, preauth_len);
+                   
+        krb_free_preauth(preauth_p, preauth_len);
+    } while ((keyprocs[++i] != NULL) && (ret_st == INTK_BADPW));
+    
+      return ret_st;
+}
+
+/* FIXME!  This routine belongs in the krb library and should simply
+   be shared between the encrypted and NOENCRYPTION versions!  */
+ 
+#ifdef NOENCRYPTION
+/*
+ * This routine prints the supplied string to standard
+ * output as a prompt, and reads a password string without
+ * echoing.
+ */
+
+#include <stdio.h>
+#ifdef	BSDUNIX
+#include <string.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <setjmp.h>
+#else
+int      strcmp();
+#endif
+#if defined(__svr4__) || defined(__SVR4)
+#include <sgtty.h>
+#endif
+
+#ifdef	BSDUNIX
+static jmp_buf env;
+#endif
+
+#ifdef BSDUNIX
+static void sig_restore();
+static push_signals(), pop_signals();
+int placebo_read_pw_string();
+#endif
+
+/*** Routines ****************************************************** */
+int
+placebo_read_password(k,prompt,verify)
+    des_cblock *k;
+    char *prompt;
+    int	verify;
+{
+    int ok;
+    char key_string[BUFSIZ];
+
+#ifdef BSDUNIX
+    if (setjmp(env)) {
+	ok = -1;
+	goto lose;
+    }
+#endif
+
+    ok = placebo_read_pw_string(key_string, BUFSIZ, prompt, verify);
+    if (ok == 0)
+	memset(k, 0, sizeof(C_Block));
+
+lose:
+    memset(key_string, 0, sizeof (key_string));
+    return ok;
+}
+
+/*
+ * This version just returns the string, doesn't map to key.
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+
+int
+placebo_read_pw_string(s,max,prompt,verify)
+    char *s;
+    int	max;
+    char *prompt;
+    int	verify;
+{
+    int ok = 0;
+    char *ptr;
+    
+#ifdef BSDUNIX
+    jmp_buf old_env;
+    struct sgttyb tty_state;
+#endif
+    char key_string[BUFSIZ];
+
+    if (max > BUFSIZ) {
+	return -1;
+    }
+
+#ifdef	BSDUNIX
+    memcpy(env, old_env, sizeof(env));
+    if (setjmp(env))
+	goto lose;
+
+    /* save terminal state */
+    if (ioctl(0,TIOCGETP,&tty_state) == -1) 
+	return -1;
+
+    push_signals();
+    /* Turn off echo */
+    tty_state.sg_flags &= ~ECHO;
+    if (ioctl(0,TIOCSETP,&tty_state) == -1)
+	return -1;
+#endif
+    while (!ok) {
+	printf(prompt);
+	fflush(stdout);
+#ifdef	CROSSMSDOS
+	h19line(s,sizeof(s),0);
+	if (!strlen(s))
+	    continue;
+#else
+	if (!fgets(s, max, stdin)) {
+	    clearerr(stdin);
+	    continue;
+	}
+	if ((ptr = strchr(s, '\n')))
+	    *ptr = '\0';
+#endif
+	if (verify) {
+	    printf("\nVerifying, please re-enter %s",prompt);
+	    fflush(stdout);
+#ifdef CROSSMSDOS
+	    h19line(key_string,sizeof(key_string),0);
+	    if (!strlen(key_string))
+		continue;
+#else
+	    if (!fgets(key_string, sizeof(key_string), stdin)) {
+		clearerr(stdin);
+		continue;
+	    }
+            if ((ptr = strchr(key_string, '\n')))
+	    *ptr = '\0';
+#endif
+	    if (strcmp(s,key_string)) {
+		printf("\n\07\07Mismatch - try again\n");
+		fflush(stdout);
+		continue;
+	    }
+	}
+	ok = 1;
+    }
+
+#ifdef	BSDUNIX
+lose:
+    if (!ok)
+	memset(s, 0, max);
+    printf("\n");
+    /* turn echo back on */
+    tty_state.sg_flags |= ECHO;
+    if (ioctl(0,TIOCSETP,&tty_state))
+	ok = 0;
+    pop_signals();
+    memcpy(old_env, env, sizeof(env));
+#endif
+    if (verify)
+	memset(key_string, 0, sizeof (key_string));
+    s[max-1] = 0;		/* force termination */
+    return !ok;			/* return nonzero if not okay */
+}
+
+#ifdef	BSDUNIX
+/*
+ * this can be static since we should never have more than
+ * one set saved....
+ */
+static sigtype (*old_sigfunc[NSIG])();
+
+static push_signals()
+{
+    register i;
+    for (i = 0; i < NSIG; i++)
+	old_sigfunc[i] = signal(i,sig_restore);
+}
+
+static pop_signals()
+{
+    register i;
+    for (i = 0; i < NSIG; i++)
+	signal(i,old_sigfunc[i]);
+}
+
+static void sig_restore(sig,code,scp)
+    int sig,code;
+    struct sigcontext *scp;
+{
+    longjmp(env,1);
+}
+#endif
+#endif /* NOENCRYPTION */
diff --git a/mechglue/src/lib/krb4/g_pw_tkt.c b/mechglue/src/lib/krb4/g_pw_tkt.c
new file mode 100644
index 000000000..f074fbc6c
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_pw_tkt.c
@@ -0,0 +1,68 @@
+/*
+ * g_pw_tkt.c
+ *
+ * Copyright 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+
+/*
+ * Get a ticket for the password-changing server ("changepw.KRB_MASTER").
+ *
+ * Given the name, instance, realm, and current password of the
+ * principal for which the user wants a password-changing-ticket,
+ * return either:
+ *
+ *	GT_PW_BADPW if current password was wrong,
+ *	GT_PW_NULL  if principal had a NULL password,
+ *	or the result of the krb_get_pw_in_tkt() call.
+ *
+ * First, try to get a ticket for "user.instance@realm" to use the
+ * "changepw.KRB_MASTER" server (KRB_MASTER is defined in "krb.h").
+ * The requested lifetime for the ticket is "1", and the current
+ * password is the "cpw" argument given.
+ *
+ * If the password was bad, give up.
+ *
+ * If the principal had a NULL password in the Kerberos database
+ * (indicating that the principal is known to Kerberos, but hasn't
+ * got a password yet), try instead to get a ticket for the principal
+ * "default.changepw@realm" to use the "changepw.KRB_MASTER" server.
+ * Use the password "changepwkrb" instead of "cpw".  Return GT_PW_NULL
+ * if all goes well, otherwise the error.
+ *
+ * If this routine succeeds, a ticket and session key for either the
+ * principal "user.instance@realm" or "default.changepw@realm" to use
+ * the password-changing server will be in the user's ticket file.
+ */
+
+int KRB5_CALLCONV
+get_pw_tkt(user,instance,realm,cpw)
+    char *user;
+    char *instance;
+    char *realm;
+    char *cpw;
+{
+    int kerror;
+
+    kerror = krb_get_pw_in_tkt(user, instance, realm, "changepw",
+			       KRB_MASTER, 1, cpw);
+
+    if (kerror == INTK_BADPW)
+	return(GT_PW_BADPW);
+
+    if (kerror == KDC_NULL_KEY) {
+	kerror = krb_get_pw_in_tkt("default","changepw",realm,"changepw",
+				   KRB_MASTER,1,"changepwkrb");
+	if (kerror)
+	    return(kerror);
+	return(GT_PW_NULL);
+    }
+
+    return(kerror);
+}
diff --git a/mechglue/src/lib/krb4/g_svc_in_tkt.c b/mechglue/src/lib/krb4/g_svc_in_tkt.c
new file mode 100644
index 000000000..7ed4efd2a
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_svc_in_tkt.c
@@ -0,0 +1,152 @@
+/*
+ * lib/krb4/g_svc_in_tkt.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "krb.h"
+#include "prot.h"
+#include "krb4int.h"
+
+/*
+ * This file contains two routines: srvtab_to_key(), which gets
+ * a server's key from a srvtab file, and krb_get_svc_in_tkt() which
+ * gets an initial ticket for a server.
+ */
+
+/*
+ * srvtab_to_key(): given a "srvtab" file (where the keys for the
+ * service on a host are stored), return the private key of the
+ * given service (user.instance@realm).
+ *
+ * srvtab_to_key() passes its arguments on to read_service_key(),
+ * plus one additional argument, the key version number.
+ * (Currently, the key version number is always 0; this value
+ * is treated as a wildcard by read_service_key().)
+ *
+ * If the "srvtab" argument is null, KEYFILE (defined in "krb.h")
+ * is passed in its place.
+ *
+ * It returns the return value of the read_service_key() call.
+ * The service key is placed in "key".
+ */
+
+static int srvtab_to_key(user, instance, realm, srvtab, key)
+    char *user, *instance, *realm, *srvtab;
+    C_Block key;
+{
+    if (!srvtab)
+        srvtab = KEYFILE;
+
+    return(read_service_key(user, instance, realm, 0, srvtab,
+                            (char *)key));
+}
+
+/*
+ * krb_get_svc_in_tkt() passes its arguments on to krb_get_in_tkt(),
+ * plus two additional arguments: a pointer to the srvtab_to_key()
+ * function to be used to get the key from the key file and a NULL
+ * for the decryption procedure indicating that krb_get_in_tkt should 
+ * use the default method of decrypting the response from the KDC.
+ *
+ * It returns the return value of the krb_get_in_tkt() call.
+ */
+
+int KRB5_CALLCONV
+krb_get_svc_in_tkt(user, instance, realm, service, sinstance, life, srvtab)
+    char *user, *instance, *realm, *service, *sinstance;
+    int life;
+    char *srvtab;
+{
+    return(krb_get_in_tkt(user, instance, realm, service, sinstance, life,
+                          (key_proc_type) srvtab_to_key, NULL, srvtab));
+}
+
+/* and we need a preauth version as well. */
+static C_Block old_key;
+ 
+static int stub_key(user,instance,realm,passwd,key)
+    char *user, *instance, *realm, *passwd;
+    C_Block key;
+{
+   memcpy(key, old_key, sizeof(C_Block));
+   return 0;
+}
+
+int
+krb_get_svc_in_tkt_preauth(user, instance, realm, service, sinstance, life, srvtab)
+    char *user, *instance, *realm, *service, *sinstance;
+    int life;
+    char *srvtab;
+{
+   char *preauth_p;
+   int   preauth_len;
+   int   ret_st;
+ 
+   krb_mk_preauth(&preauth_p, &preauth_len,
+                  (key_proc_type) srvtab_to_key, user, instance, realm,
+		  srvtab, old_key);
+   ret_st = krb_get_in_tkt_preauth(user,instance,realm,service,sinstance,life,
+				   (key_proc_type) stub_key, NULL, srvtab,
+				   preauth_p, preauth_len);
+ 
+   krb_free_preauth(preauth_p, preauth_len);
+   return ret_st;
+}
+
+/* DEC's dss-kerberos adds krb_svc_init; simple enough */
+
+int
+krb_svc_init(user,instance,realm,lifetime,srvtab_file,tkt_file)
+    char *user;
+    char *instance;
+    char *realm;
+    int lifetime;
+    char *srvtab_file;
+    char *tkt_file;
+{
+    if (tkt_file)
+	krb_set_tkt_string(tkt_file);
+
+    return krb_get_svc_in_tkt(user,instance,realm,
+			      KRB_TICKET_GRANTING_TICKET,realm,lifetime,srvtab_file);
+}
+
+
+int
+krb_svc_init_preauth(user,instance,realm,lifetime,srvtab_file,tkt_file)
+    char *user;
+    char *instance;
+    char *realm;
+    int lifetime;
+    char *srvtab_file;
+    char *tkt_file;
+{
+    if (tkt_file)
+        krb_set_tkt_string(tkt_file);
+ 
+    return krb_get_svc_in_tkt_preauth(user,instance,realm,
+                              	      KRB_TICKET_GRANTING_TICKET,realm,lifetime,srvtab_file);
+}
diff --git a/mechglue/src/lib/krb4/g_tf_fname.c b/mechglue/src/lib/krb4/g_tf_fname.c
new file mode 100644
index 000000000..e03fe24b1
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_tf_fname.c
@@ -0,0 +1,67 @@
+/*
+ * g_tf_fname.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+#include <string.h>
+#include <stdio.h>		/* For EOF */
+
+/*
+ * This file contains a routine to extract the fullname of a user
+ * from the ticket file.
+ */
+
+/*
+ * krb_get_tf_fullname() takes four arguments: the name of the 
+ * ticket file, and variables for name, instance, and realm to be
+ * returned in.  Since the realm of a ticket file is not really fully 
+ * supported, the realm used will be that of the the first ticket in 
+ * the file as this is the one that was obtained with a password by
+ * krb_get_in_tkt().
+ */
+
+int KRB5_CALLCONV
+krb_get_tf_fullname(ticket_file, name, instance, realm)
+  const char *ticket_file;
+  char *name;
+  char *instance;
+  char *realm;
+{
+    int tf_status;
+    CREDENTIALS c;
+
+    /* If ticket cache selector is null, use default cache.  */
+    if (ticket_file == 0)
+	ticket_file = tkt_string();
+
+    if ((tf_status = tf_init(ticket_file, R_TKT_FIL)) != KSUCCESS)
+	return(tf_status);
+
+    if (((tf_status = tf_get_pname(c.pname)) != KSUCCESS) ||
+	((tf_status = tf_get_pinst(c.pinst)) != KSUCCESS))
+	return (tf_status);
+    
+    if (name)
+	strcpy(name, c.pname);
+    if (instance)
+	strcpy(instance, c.pinst);
+    if ((tf_status = tf_get_cred(&c)) == KSUCCESS) {
+	if (realm)
+	    strcpy(realm, c.realm);
+    }
+    else {
+	if (tf_status == EOF)
+	    return(KFAILURE);
+	else
+	    return(tf_status);
+    }    
+    (void) tf_close();
+    
+    return(tf_status);
+}
diff --git a/mechglue/src/lib/krb4/g_tf_realm.c b/mechglue/src/lib/krb4/g_tf_realm.c
new file mode 100644
index 000000000..fe99e61e1
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_tf_realm.c
@@ -0,0 +1,44 @@
+/*
+ * lib/krb4/g_tf_realm.c
+ *
+ * Copyright 1987-2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+
+/*
+ * This file contains a routine to extract the realm of a kerberos
+ * ticket file.
+ */
+
+/*
+ * krb_get_tf_realm() takes two arguments: the name of a ticket 
+ * and a variable to store the name of the realm in.
+ * 
+ */
+
+int KRB5_CALLCONV
+krb_get_tf_realm(const char *ticket_file, char *realm)
+{
+    return krb_get_tf_fullname(ticket_file, NULL, NULL, realm);
+}
diff --git a/mechglue/src/lib/krb4/g_tkt_svc.c b/mechglue/src/lib/krb4/g_tkt_svc.c
new file mode 100644
index 000000000..a16451776
--- /dev/null
+++ b/mechglue/src/lib/krb4/g_tkt_svc.c
@@ -0,0 +1,174 @@
+/* 
+ * g_tkt_svc.c
+ *
+ * Gets a ticket for a service.  Adopted from KClient.
+ */
+
+#include <string.h>
+#include "krb.h"
+#include "port-sockets.h"
+
+/* FIXME -- this should probably be calling mk_auth nowadays.  */
+#define	KRB_SENDAUTH_VERS "AUTHV0.1" 	/* MUST be KRB_SENDAUTH_VLEN chars */
+
+
+static int
+ParseFullName(name, instance, realm, fname)
+	char *name;
+	char *instance;
+	char *realm;
+	char *fname;
+{
+	int err;
+	
+	if (!*fname) return KNAME_FMT;					/* null names are not OK */
+	*instance = '\0';
+	err = kname_parse(name,instance,realm,fname);
+	if (err) return err;
+	if (!*name) return KNAME_FMT;					/* null names are not OK */
+	if (!*realm) { 
+		if ((err = krb_get_lrealm (realm, 1)))
+			return err;
+		if (!*realm) return KNAME_FMT;		/* FIXME -- should give better error */
+	}
+	return KSUCCESS;
+}
+
+
+
+static void
+CopyTicket(dest, src, numBytes, version, includeVersion)
+	char *dest;
+	KTEXT src;
+	unsigned long *numBytes;
+	char *version;
+	int includeVersion;
+{
+	unsigned long tkt_len;
+	unsigned long nbytes = 0;
+		
+    /* first put version info into the buffer */
+    if (includeVersion) {
+		(void) strncpy(dest, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN);
+		(void) strncpy(dest+KRB_SENDAUTH_VLEN, version, KRB_SENDAUTH_VLEN);
+		nbytes = 2*KRB_SENDAUTH_VLEN;
+	}
+    
+    /* put ticket length into buffer */
+    tkt_len = htonl((unsigned long) src->length);
+	(void) memcpy((char *)(dest+nbytes), (char *) &tkt_len, sizeof(tkt_len));
+    nbytes += sizeof(tkt_len);
+
+    /* put ticket into buffer */
+    (void) memcpy ((char *)(dest+nbytes), (char *) src->dat, src->length);
+    nbytes += src->length;
+    
+    *numBytes = nbytes;
+}
+
+
+static int
+CredIsExpired( cr )
+     CREDENTIALS *cr;
+{
+    KRB4_32 now;
+
+    /* This routine is for use with clients only in order to determine
+       if a credential is still good.
+       Note: twice CLOCK_SKEW was added to age of ticket so that we could 
+       be more sure that the ticket was good. 
+       FIXME:  I think this is a bug -- should use the same algorithm
+       everywhere to determine ticket expiration.   */
+
+    now = TIME_GMT_UNIXSEC;	
+    return now + 2 * CLOCK_SKEW > krb_life_to_time(cr->issue_date,
+						   cr->lifetime);
+}
+
+
+/*
+ * Gets a ticket and returns it to application in buf
+	  -> service		Formal Kerberos name of service
+	  -> buf		Buffer to receive ticket
+	  -> checksum		checksum for this service
+	 <-> buflen		length of ticket buffer (must be at least
+					1258 bytes)
+	 <-  sessionKey		for internal use
+	 <-  schedule		for internal use
+
+ * Result is:
+ *   GC_NOTKT		if there is no matching TGT in the cache
+ *   MK_AP_TGTEXP	if the matching TGT is expired
+ * Other errors possible.  These could cause a dialogue with the user
+ * to get a new TGT.
+ */ 
+
+int KRB5_CALLCONV
+krb_get_ticket_for_service (serviceName, buf, buflen, checksum, sessionKey,
+		schedule, version, includeVersion)
+	char *serviceName;
+	char *buf;
+	unsigned KRB4_32 *buflen;
+	int checksum;
+	des_cblock sessionKey;
+	Key_schedule schedule;
+	char *version;
+	int includeVersion;
+{
+	char service[SNAME_SZ];
+	char instance[INST_SZ];
+	char realm[REALM_SZ];
+	int err;
+	char lrealm[REALM_SZ];
+	CREDENTIALS cr;
+	
+	service[0] = '\0';
+	instance[0] = '\0';
+	realm[0] = '\0';
+	
+	/* parse out service name */
+	
+	err = ParseFullName(service, instance, realm, serviceName);
+	if (err)
+		return err;
+
+    if ((err = krb_get_tf_realm(TKT_FILE, lrealm)) != KSUCCESS)
+		return(err);
+
+ 	/* Make sure we have an intial ticket for the user in this realm 
+ 	   Check local realm, not realm for service since krb_mk_req will
+ 	   get additional krbtgt if necessary. This is so that inter-realm
+ 	   works without asking for a password twice.
+ 	   FIXME gnu - I think this is a bug.  We should allow direct
+ 	   authentication to the desired realm, regardless of what the "local"
+ 	   realm is.   I fixed it.   FIXME -- not quite right.   */
+ 	err = krb_get_cred (KRB_TICKET_GRANTING_TICKET, realm, lrealm, &cr);
+ 	if (err) 
+ 		return err;
+
+	err = CredIsExpired(&cr);
+  	if (err)
+  		return RD_AP_EXP;		/* Expired ticket */
+	
+	/* Get a ticket for the service */
+	err = krb_mk_req(&(cr.ticket_st),service,instance,realm,checksum);
+	if (err)
+		return err;
+	
+	CopyTicket(buf, &(cr.ticket_st), buflen, version, includeVersion);
+	
+	/* get the session key for later use in deciphering the server response */
+	err = krb_get_cred(service,instance,realm,&cr);
+	if (err)
+		return err;
+	memcpy((char *)sessionKey, (char *)cr.session, sizeof(C_Block));
+  	err = key_sched(sessionKey, schedule);
+	if (err)
+		return KFAILURE;		/* Bad DES key for some reason (FIXME better error) */
+	
+	else
+		return KSUCCESS;
+	
+}
+
+
diff --git a/mechglue/src/lib/krb4/gethostname.c b/mechglue/src/lib/krb4/gethostname.c
new file mode 100644
index 000000000..c09be7299
--- /dev/null
+++ b/mechglue/src/lib/krb4/gethostname.c
@@ -0,0 +1,36 @@
+/*
+ * gethostname.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+#include "krb4int.h"
+#include "krb5/autoconf.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef	GETHOSTNAME
+#define	GETHOSTNAME	gethostname	/* A rather simple default */
+#endif
+
+/*
+ * Return the local host's name in "name", up to "namelen" characters.
+ * "name" will be null-terminated if "namelen" is big enough.
+ * The return code is 0 on success, -1 on failure.  (The calling
+ * interface is identical to BSD gethostname(2).)
+ */
+
+int
+k_gethostname(name, namelen)
+    char *name;
+    int namelen;
+{
+    return GETHOSTNAME(name, namelen);
+}
diff --git a/mechglue/src/lib/krb4/getst.c b/mechglue/src/lib/krb4/getst.c
new file mode 100644
index 000000000..252571eaf
--- /dev/null
+++ b/mechglue/src/lib/krb4/getst.c
@@ -0,0 +1,40 @@
+/*
+ * getst.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+#include "krb4int.h"
+#include "krb5/autoconf.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/*
+ * getst() takes a file descriptor, a string and a count.  It reads
+ * from the file until either it has read "count" characters, or until
+ * it reads a null byte.  When finished, what has been read exists in
+ * the given string "s".  If "count" characters were actually read, the
+ * last is changed to a null, so the returned string is always null-
+ * terminated.  getst() returns the number of characters read, including
+ * the null terminator.
+ */
+
+int
+getst(fd, s, n)
+    int fd;
+    register char *s;
+    int n;
+{
+    register int count = n;
+    while (read(fd, s, 1) > 0 && --count)
+        if (*s++ == '\0')
+            return (n - count);
+    *s = '\0';
+    return (n - count);
+}
diff --git a/mechglue/src/lib/krb4/in_tkt.c b/mechglue/src/lib/krb4/in_tkt.c
new file mode 100644
index 000000000..4a7624878
--- /dev/null
+++ b/mechglue/src/lib/krb4/in_tkt.c
@@ -0,0 +1,199 @@
+/*
+ * lib/krb4/in_tkt.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000, 2001 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "krb.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifdef TKT_SHMEM
+#include <sys/param.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+extern int krb_debug;
+
+/*
+ * in_tkt() is used to initialize the ticket store.  It creates the
+ * file to contain the tickets and writes the given user's name "pname"
+ * and instance "pinst" in the file.  in_tkt() returns KSUCCESS on
+ * success, or KFAILURE if something goes wrong.
+ */
+
+#include "k5-util.h"
+#define do_seteuid krb5_seteuid
+
+#ifndef O_SYNC
+#define O_SYNC 0
+#endif
+
+int KRB5_CALLCONV
+in_tkt(pname,pinst)
+    char *pname;
+    char *pinst;
+{
+    int tktfile;
+    uid_t me, metoo, getuid(), geteuid();
+    struct stat statpre, statpost;
+    int count;
+    const char *file = TKT_FILE;
+    int fd;
+    register int i;
+    char charbuf[BUFSIZ];
+    mode_t mask;
+#ifdef TKT_SHMEM
+    char shmidname[MAXPATHLEN];
+#endif /* TKT_SHMEM */
+
+    /* If ticket cache selector is null, use default cache.  */
+    if (file == 0)
+	file = tkt_string();
+
+    me = getuid ();
+    metoo = geteuid();
+    if (lstat(file, &statpre) == 0) {
+	if (statpre.st_uid != me || !(statpre.st_mode & S_IFREG)
+	    || statpre.st_nlink != 1 || statpre.st_mode & 077) {
+	    if (krb_debug)
+		fprintf(stderr,"Error initializing %s",file);
+	    return(KFAILURE);
+	}
+	/*
+	 * Yes, we do uid twiddling here.  It's not optimal, but some
+	 * applications may expect that the ruid is what should really
+	 * own the ticket file, e.g. setuid applications.
+	 */
+	if (me != metoo && do_seteuid(me) < 0)
+	    return KFAILURE;
+	/* file already exists, and permissions appear ok, so nuke it */
+	fd = open(file, O_RDWR|O_SYNC, 0);
+	(void)unlink(file);
+	if (me != metoo && do_seteuid(metoo) < 0)
+	    return KFAILURE;
+	if (fd < 0) {
+	    goto out; /* can't zero it, but we can still try truncating it */
+	}
+
+	/*
+	 * Do some additional paranoid things.  The worst-case
+	 * situation is that a user may be fooled into opening a
+	 * non-regular file briefly if the file is in a directory with
+	 * improper permissions.
+	 */
+	if (fstat(fd, &statpost) < 0) {
+	    (void)close(fd);
+	    goto out;
+	}
+	if (statpre.st_dev != statpost.st_dev
+	    || statpre.st_ino != statpost.st_ino) {
+	    (void)close(fd);
+	    errno = 0;
+	    goto out;
+	}
+
+	memset(charbuf, 0, sizeof(charbuf));
+
+	for (i = 0; i < statpost.st_size; i += sizeof(charbuf))
+	    if (write(fd, charbuf, sizeof(charbuf)) != sizeof(charbuf)) {
+#ifndef NO_FSYNC
+		(void) fsync(fd);
+#endif
+		(void) close(fd);
+		goto out;
+	    }
+	
+#ifndef NO_FSYNC
+	(void) fsync(fd);
+#endif
+	(void) close(fd);
+    }
+ out:
+    /* arrange so the file is owned by the ruid
+       (swap real & effective uid if necessary).
+       This isn't a security problem, since the ticket file, if it already
+       exists, has the right uid (== ruid) and mode. */
+    if (me != metoo) {
+	if (do_seteuid(me) < 0) {
+	    /* can't switch??? barf! */
+	    if (krb_debug)
+		perror("in_tkt: seteuid");
+	    return(KFAILURE);
+	} else
+	    if (krb_debug)
+		printf("swapped UID's %d and %d\n",(int) metoo, (int) me);
+    }
+    /* Set umask to ensure that we have write access on the created
+       ticket file.  */
+    mask = umask(077);
+    tktfile = open(file, O_RDWR|O_SYNC|O_CREAT|O_EXCL, 0600);
+    umask(mask);
+    if (me != metoo) {
+	if (do_seteuid(metoo) < 0) {
+	    /* can't switch??? barf! */
+	    if (krb_debug)
+		perror("in_tkt: seteuid2");
+	    return(KFAILURE);
+	} else
+	    if (krb_debug)
+		printf("swapped UID's %d and %d\n", (int) me, (int) metoo);
+    }
+    if (tktfile < 0) {
+	if (krb_debug)
+	    fprintf(stderr,"Error initializing %s",TKT_FILE);
+        return(KFAILURE);
+    }
+    count = strlen(pname)+1;
+    if (write(tktfile,pname,count) != count) {
+        (void) close(tktfile);
+        return(KFAILURE);
+    }
+    count = strlen(pinst)+1;
+    if (write(tktfile,pinst,count) != count) {
+        (void) close(tktfile);
+        return(KFAILURE);
+    }
+    (void) close(tktfile);
+#ifdef TKT_SHMEM
+    (void) strncpy(shmidname, file, sizeof(shmidname) - 1);
+    shmidname[sizeof(shmidname) - 1] = '\0';
+    (void) strncat(shmidname, ".shm", sizeof(shmidname) - 1 - strlen(shmidname));
+    return(krb_shm_create(shmidname));
+#else /* !TKT_SHMEM */
+    return(KSUCCESS);
+#endif /* TKT_SHMEM */
+}
+
+int KRB5_CALLCONV
+krb_in_tkt(pname, pinst, prealm)
+    char *pname;
+    char *pinst;
+    char *prealm;
+{
+    return in_tkt(pname, pinst);
+}
diff --git a/mechglue/src/lib/krb4/kadm_err.et b/mechglue/src/lib/krb4/kadm_err.et
new file mode 100644
index 000000000..07ab9da4b
--- /dev/null
+++ b/mechglue/src/lib/krb4/kadm_err.et
@@ -0,0 +1,58 @@
+#	kadmin.v4/server/kadm_err.et
+#
+# Copyright 1988 by the Massachusetts Institute of Technology.
+#
+# For copying and distribution information, please see the file
+# <mit-copyright.h>.
+#
+# Kerberos administration server error table
+#
+	et	kadm
+
+# KADM_SUCCESS, as all success codes should be, is zero
+
+ec KADM_RCSID,		"$Header$"
+# /* Building and unbuilding the packet errors */
+ec KADM_NO_REALM,	"Cannot fetch local realm"
+ec KADM_NO_CRED,	"Unable to fetch credentials"
+ec KADM_BAD_KEY,	"Bad key supplied"
+ec KADM_NO_ENCRYPT,	"Can't encrypt data"
+ec KADM_NO_AUTH,	"Cannot encode/decode authentication info"
+ec KADM_WRONG_REALM,	"Principal attemping change is in wrong realm"
+ec KADM_NO_ROOM,	"Packet is too large"
+ec KADM_BAD_VER,	"Version number is incorrect"
+ec KADM_BAD_CHK,	"Checksum does not match"
+ec KADM_NO_READ,	"Unsealing private data failed"
+ec KADM_NO_OPCODE,	"Unsupported operation"
+ec KADM_NO_HOST,	"Could not find administrating host"
+ec KADM_UNK_HOST,	"Administrating host name is unknown"
+ec KADM_NO_SERV,	"Could not find service name in services database"
+ec KADM_NO_SOCK,	"Could not create socket"
+ec KADM_NO_CONN,	"Could not connect to server"
+ec KADM_NO_HERE,	"Could not fetch local socket address"
+ec KADM_NO_MAST,	"Could not fetch master key"
+ec KADM_NO_VERI,	"Could not verify master key"
+
+# /* From the server side routines */
+ec KADM_INUSE,		"Entry already exists in database"
+ec KADM_UK_SERROR,	"Database store error"
+ec KADM_UK_RERROR,	"Database read error"
+ec KADM_UNAUTH,		"Insufficient access to perform requested operation"
+# KADM_DATA isn't really an error, but...
+ec KADM_DATA,		"Data is available for return to client"
+ec KADM_NOENTRY,	"No such entry in the database"
+
+ec KADM_NOMEM,		"Memory exhausted"
+ec KADM_NO_HOSTNAME,	"Could not fetch system hostname"
+ec KADM_NO_BIND,	"Could not bind port"
+ec KADM_LENGTH_ERROR,	"Length mismatch problem"
+ec KADM_ILL_WILDCARD,	"Illegal use of wildcard"
+
+ec KADM_DB_INUSE,	"Database locked or in use"
+
+ec KADM_INSECURE_PW,	"Insecure password rejected"
+ec KADM_PW_MISMATCH,	"Cleartext password and DES key did not match"
+
+ec KADM_NOT_SERV_PRINC,	"Invalid principal for change srvtab request"
+ec KADM_REALM_TOO_LONG, "Realm name too long"
+end
diff --git a/mechglue/src/lib/krb4/kadm_net.c b/mechglue/src/lib/krb4/kadm_net.c
new file mode 100644
index 000000000..4173af2b0
--- /dev/null
+++ b/mechglue/src/lib/krb4/kadm_net.c
@@ -0,0 +1,392 @@
+/*
+ * lib/krb4/kadm_net.c
+ *
+ * Copyright 1988, 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Kerberos administration server client-side network access routines
+ * These routines do actual network traffic, in a machine dependent manner.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include "krb5/autoconf.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#define	DEFINE_SOCKADDR		/* Ask krb.h for struct sockaddr, etc */
+#include "port-sockets.h"
+#include "krb.h"
+#include "krbports.h"
+#include "kadm.h"
+#include "kadm_err.h"
+#include "prot.h"
+
+/* XXX FIXME! */
+#if defined(_WIN32)
+	#define SIGNAL(s, f) 0
+#else
+	#define SIGNAL(s, f) signal(s, f)
+#endif
+
+static void clear_secrets(des_cblock sess_key, Key_schedule sess_sched);
+/* XXX FIXME! */
+#ifdef SIGPIPE
+static krb5_sigtype (*opipe)();
+#endif
+
+/*
+ * kadm_init_link
+ *	receives    : principal, instance, realm
+ *
+ * initializes client parm, the Kadm_Client structure which holds the
+ * data about the connection between the server and client, the services
+ * used, the locations and other fun things
+ */
+int
+kadm_init_link(char *principal, char *instance, char *realm,
+	       Kadm_Client *client_parm, int changepw)
+{
+    struct servent *sep;	       /* service we will talk to */
+    u_short sep_port;
+    struct hostent *hop;	       /* host we will talk to */
+    char adm_hostname[MAXHOSTNAMELEN];
+    char *scol = 0;
+
+    (void) strcpy(client_parm->sname, principal);
+    (void) strcpy(client_parm->sinst, instance);
+    (void) strcpy(client_parm->krbrlm, realm);
+    client_parm->admin_fd = -1;
+    client_parm->default_port = 1;
+
+    /*
+     * set up the admin_addr - fetch name of admin or kpasswd host
+     * (usually the admin host is the kpasswd host unless you have
+     * some sort of realm on crack)
+     */
+    if (changepw) {
+#if 0 /* XXX */
+	if (krb_get_kpasswdhst(adm_hostname, client_parm->krbrlm, 1) != KSUCCESS)
+#endif
+	    if (krb_get_admhst(adm_hostname, client_parm->krbrlm, 1) != KSUCCESS)
+		return KADM_NO_HOST;
+    } else {
+	if (krb_get_admhst(adm_hostname, client_parm->krbrlm, 1) != KSUCCESS)
+	    return KADM_NO_HOST;
+    }
+    scol = strchr(adm_hostname,':');
+    if (scol) *scol = 0;
+    if ((hop = gethostbyname(adm_hostname)) == NULL)
+	/*
+	 * couldn't find the admin servers address
+	 */
+	return KADM_UNK_HOST;
+    if (scol) {
+	sep_port = htons(atoi(scol+1));
+	client_parm->default_port = 0;
+    } else if ((sep = getservbyname(KADM_SNAME, "tcp")) != NULL)
+	sep_port = sep->s_port;
+    else
+	sep_port = htons(KADM_PORT); /* KADM_SNAME = kerberos_master/tcp */
+    memset(&client_parm->admin_addr, 0, sizeof(client_parm->admin_addr));
+    client_parm->admin_addr.sin_family = hop->h_addrtype;
+    memcpy(&client_parm->admin_addr.sin_addr, hop->h_addr, hop->h_length);
+    client_parm->admin_addr.sin_port = sep_port;
+
+    return KADM_SUCCESS;
+}
+
+/*
+ * kadm_cli_send
+ *	recieves   : opcode, packet, packet length, serv_name, serv_inst
+ *	returns    : return code from the packet build, the server, or
+ *			 something else
+ *
+ * It assembles a packet as follows:
+ *	 8 bytes    : VERSION STRING
+ *	 4 bytes    : LENGTH OF MESSAGE DATA and OPCODE
+ *		    : KTEXT
+ *		    : OPCODE       \
+ *		    : DATA          > Encrypted (with make priv)
+ *		    : ......       /
+ *
+ * If it builds the packet and it is small enough, then it attempts to open the
+ * connection to the admin server.  If the connection is succesfully open
+ * then it sends the data and waits for a reply.
+ */
+int
+kadm_cli_send(Kadm_Client *client_parm,
+	      u_char *st_dat,	/* the actual data */
+	      size_t st_siz,	/* length of said data */
+	      u_char **ret_dat, /* to give return info */
+	      size_t *ret_siz)	/* length of returned info */
+{
+/* Macros for use in returning data... used in kadm_cli_send */
+#define RET_N_FREE(r) {clear_secrets(sess_key, sess_sched); free((char *)act_st); free((char *)priv_pak); return r;}
+#define RET_N_FREE2(r) {free((char *)*ret_dat); *ret_dat = 0; *ret_siz = 0; clear_secrets(sess_key, sess_sched); return(r);}
+
+    int		act_len;      /* current offset into packet, return */
+    KRB_INT32	retdat;		/* data */
+    KTEXT_ST	authent;	/* the authenticator we will build */
+    u_char	*act_st;      /* the pointer to the complete packet */
+    u_char	*priv_pak;	/* private version of the packet */
+    long	priv_len;	/* length of private packet */
+    u_long	cksum;		/* checksum of the packet */
+    MSG_DAT	mdat;
+    u_char	*return_dat;
+    u_char	*p;
+    KRB_UINT32	uretdat;
+
+    /* Keys for use in the transactions */
+    des_cblock	sess_key;	/* to be filled in by kadm_cli_keyd */
+    Key_schedule sess_sched;
+
+    act_st = malloc(KADM_VERSIZE); /* verstr stored first */
+    strncpy((char *)act_st, KADM_VERSTR, KADM_VERSIZE);
+    act_len = KADM_VERSIZE;
+
+    if ((retdat = kadm_cli_keyd(client_parm, sess_key, sess_sched)) != KADM_SUCCESS) {
+	free(act_st);
+	return retdat;	       /* couldnt get key working */
+    }
+    priv_pak = malloc(st_siz + 200);
+    /* 200 bytes for extra info case */
+    /* XXX Check mk_priv return type */
+    if ((priv_len = krb_mk_priv(st_dat, priv_pak, (u_long)st_siz,
+				sess_sched, (C_Block *)sess_key,
+				&client_parm->my_addr,
+				&client_parm->admin_addr)) < 0)
+	RET_N_FREE(KADM_NO_ENCRYPT); /* whoops... we got a lose here */
+    /*
+     * here is the length of priv data.  receiver calcs size of
+     * authenticator by subtracting vno size, priv size, and
+     * sizeof(u_long) (for the size indication) from total size
+     */
+    act_len += vts_long((KRB_UINT32)priv_len, &act_st, (int)act_len);
+#ifdef NOENCRYPTION
+    cksum = 0;
+#else
+    cksum = quad_cksum(priv_pak, NULL, priv_len, 0, &sess_key);
+#endif
+    /* XXX cast unsigned->signed */
+    if ((retdat = krb_mk_req_creds(&authent, &client_parm->creds, (long)cksum)) != NULL) {
+	/* authenticator? */
+	RET_N_FREE(retdat);
+    }
+
+    act_st = realloc(act_st, (unsigned) (act_len + authent.length
+					    + priv_len));
+    if (!act_st) {
+	clear_secrets(sess_key, sess_sched);
+	free(priv_pak);
+	return KADM_NOMEM;
+    }
+    memcpy(act_st + act_len, authent.dat, authent.length);
+    memcpy(act_st + act_len + authent.length, priv_pak, priv_len);
+    free(priv_pak);
+    if ((retdat = kadm_cli_out(client_parm, act_st,
+			       act_len + authent.length + priv_len,
+			       ret_dat, ret_siz)) != KADM_SUCCESS)
+	RET_N_FREE(retdat);
+    free(act_st);
+
+    /* first see if it's a YOULOSE */
+    if ((*ret_siz >= KADM_VERSIZE) &&
+	!strncmp(KADM_ULOSE, (char *)*ret_dat, KADM_VERSIZE))
+    {
+	/* it's a youlose packet */
+	if (*ret_siz < KADM_VERSIZE + 4)
+	    RET_N_FREE2(KADM_BAD_VER);
+	p = *ret_dat + KADM_VERSIZE;
+	KRB4_GET32BE(uretdat, p);
+	/* XXX unsigned->signed */
+	retdat = (KRB_INT32)uretdat;
+	RET_N_FREE2(retdat);
+    }
+    /* need to decode the ret_dat */
+    if ((retdat = krb_rd_priv(*ret_dat, (u_long)*ret_siz, sess_sched,
+			      (C_Block *)sess_key, &client_parm->admin_addr,
+			      &client_parm->my_addr, &mdat)) != NULL)
+	RET_N_FREE2(retdat);
+    if (mdat.app_length < KADM_VERSIZE + 4)
+	/* too short! */
+	RET_N_FREE2(KADM_BAD_VER);
+    if (strncmp((char *)mdat.app_data, KADM_VERSTR, KADM_VERSIZE))
+	/* bad version */
+	RET_N_FREE2(KADM_BAD_VER);
+    p = mdat.app_data + KADM_VERSIZE;
+    KRB4_GET32BE(uretdat, p);
+    /* XXX unsigned->signed */
+    retdat = (KRB_INT32)uretdat;
+    if ((mdat.app_length - KADM_VERSIZE - 4) != 0) {
+	if (!(return_dat =
+	      malloc((unsigned)(mdat.app_length - KADM_VERSIZE - 4))))
+	    RET_N_FREE2(KADM_NOMEM);
+	memcpy(return_dat, p, mdat.app_length - KADM_VERSIZE - 4);
+    } else {
+	/* If it's zero length, still need to malloc a 1 byte string; */
+	/* malloc's of zero will return NULL on AIX & A/UX */
+	if (!(return_dat = malloc((unsigned) 1)))
+	    RET_N_FREE2(KADM_NOMEM);
+	*return_dat = '\0';
+    }
+    free(*ret_dat);
+    clear_secrets(sess_key, sess_sched);
+    *ret_dat = return_dat;
+    *ret_siz = mdat.app_length - KADM_VERSIZE - 4;
+    return retdat;
+}
+
+int kadm_cli_conn(Kadm_Client *client_parm)
+{					/* this connects and sets my_addr */
+#if 0
+    int on = 1;
+#endif
+    if ((client_parm->admin_fd =
+	 socket(client_parm->admin_addr.sin_family, SOCK_STREAM,0)) < 0)
+	return KADM_NO_SOCK;		/* couldnt create the socket */
+    if (SOCKET_CONNECT(client_parm->admin_fd,
+		(struct sockaddr *) & client_parm->admin_addr,
+		sizeof(client_parm->admin_addr))) {
+	(void) SOCKET_CLOSE(client_parm->admin_fd);
+	client_parm->admin_fd = -1;
+
+        /* The V4 kadmind port number is 751.  The RFC assigned
+	   number, for V5, is 749.  Sometimes the entry in
+	   /etc/services on a client machine will say 749, but the
+	   server may be listening on port 751.  We try to partially
+	   cope by automatically falling back to try port 751 if we
+	   don't get a reply on port we are using.  */
+        if (client_parm->admin_addr.sin_port != htons(KADM_PORT)
+	     && client_parm->default_port) {
+	    client_parm->admin_addr.sin_port = htons(KADM_PORT);
+	    return kadm_cli_conn(client_parm);
+	}
+
+	return KADM_NO_CONN;		/* couldnt get the connect */
+    }
+#ifdef SIGPIPE
+    opipe = SIGNAL(SIGPIPE, SIG_IGN);
+#endif
+    client_parm->my_addr_len = sizeof(client_parm->my_addr);
+    if (SOCKET_GETSOCKNAME(client_parm->admin_fd,
+		    (struct sockaddr *) & client_parm->my_addr,
+		    &client_parm->my_addr_len) < 0) {
+	(void) SOCKET_CLOSE(client_parm->admin_fd);
+	client_parm->admin_fd = -1;
+#ifdef SIGPIPE
+	(void) SIGNAL(SIGPIPE, opipe);
+#endif
+	return KADM_NO_HERE;		/* couldnt find out who we are */
+    }
+#if 0
+    if (setsockopt(client_parm.admin_fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
+		   sizeof(on)) < 0) {
+	(void) closesocket(client_parm.admin_fd);
+	client_parm.admin_fd = -1;
+#ifdef SIGPIPE
+	(void) SIGNAL(SIGPIPE, opipe);
+#endif
+	return KADM_NO_CONN;		/* XXX */
+    }
+#endif
+    return KADM_SUCCESS;
+}
+
+void kadm_cli_disconn(Kadm_Client *client_parm)
+{
+    (void) SOCKET_CLOSE(client_parm->admin_fd);
+#ifdef SIGPIPE
+    (void) SIGNAL(SIGPIPE, opipe);
+#endif
+    return;
+}
+
+int kadm_cli_out(Kadm_Client *client_parm, u_char *dat, int dat_len,
+		 u_char **ret_dat, size_t *ret_siz)
+{
+    u_short		dlen;
+    int			retval;
+    unsigned char	buf[2], *p;
+
+    dlen = (u_short)dat_len;
+    if (dlen > 0x7fff)		/* XXX krb_net_write signedness */
+	return KADM_NO_ROOM;
+
+    p = buf;
+    KRB4_PUT16BE(p, dlen);
+    if (krb_net_write(client_parm->admin_fd, (char *)buf, 2) < 0)
+	return SOCKET_ERRNO;	/* XXX */
+
+    if (krb_net_write(client_parm->admin_fd, (char *)dat, (int)dat_len) < 0)
+	return SOCKET_ERRNO;	/* XXX */
+
+    retval = krb_net_read(client_parm->admin_fd, (char *)buf, 2);
+    if (retval != 2) {
+	if (retval < 0)
+	    return SOCKET_ERRNO; /* XXX */
+	else
+	    return EPIPE;	/* short read ! */
+    }
+
+    p = buf;
+    KRB4_GET16BE(dlen, p);
+    if (dlen > INT_MAX)		/* XXX krb_net_read signedness */
+	return KADM_NO_ROOM;
+    *ret_dat = malloc(dlen);
+    if (!*ret_dat)
+	return KADM_NOMEM;
+
+    retval = krb_net_read(client_parm->admin_fd, (char *)*ret_dat, (int)dlen);
+    if (retval != dlen) {
+	if (retval < 0)
+	    return SOCKET_ERRNO; /* XXX */
+	else
+	    return EPIPE;	/* short read ! */
+    }
+    *ret_siz = dlen;
+    return KADM_SUCCESS;
+}
+
+static void
+clear_secrets(des_cblock sess_key, Key_schedule sess_sched)
+{
+    memset(sess_key, 0, sizeof(sess_key));
+    memset(sess_sched, 0, sizeof(sess_sched));
+    return;
+}
+
+/* takes in the sess_key and key_schedule and sets them appropriately */
+int kadm_cli_keyd(Kadm_Client *client_parm,
+		  des_cblock s_k, des_key_schedule s_s)
+{
+    int stat;
+
+    memcpy(s_k, client_parm->creds.session, sizeof(des_cblock));
+    stat = key_sched(s_k, s_s);
+    if (stat)
+	return stat;
+    return KADM_SUCCESS;
+}				       /* This code "works" */
diff --git a/mechglue/src/lib/krb4/kadm_stream.c b/mechglue/src/lib/krb4/kadm_stream.c
new file mode 100644
index 000000000..dc9fef110
--- /dev/null
+++ b/mechglue/src/lib/krb4/kadm_stream.c
@@ -0,0 +1,325 @@
+/*
+ * kadm_stream.c
+ *
+ * Copyright 1988, 2002 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Stream conversion functions for Kerberos administration server
+ */
+
+/*
+  kadm_stream.c
+  this holds the stream support routines for the kerberos administration server
+
+    vals_to_stream: converts a vals struct to a stream for transmission
+       internals build_field_header, vts_[string, char, long, short]
+    stream_to_vals: converts a stream to a vals struct
+       internals check_field_header, stv_[string, char, long, short]
+    error: prints out a kadm error message, returns
+    fatal: prints out a kadm fatal error message, exits
+*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "kadm.h"
+#include "kadm_err.h"
+#include "prot.h"
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+/*
+vals_to_stream
+  recieves    : kadm_vals *, u_char *
+  returns     : a realloced and filled in u_char *
+
+this function creates a byte-stream representation of the kadm_vals structure
+*/
+int
+vals_to_stream(Kadm_vals *dt_in, u_char **dt_out)
+{
+    int vsloop, stsize;		/* loop counter, stream size */
+
+    stsize = build_field_header(dt_in->fields, dt_out);
+    for (vsloop = 31; vsloop >= 0; vsloop--)
+	if (IS_FIELD(vsloop, dt_in->fields)) {
+	    switch (vsloop) {
+	    case KADM_NAME:
+		stsize += vts_string(dt_in->name, dt_out, stsize);
+		break;
+	    case KADM_INST:
+		stsize += vts_string(dt_in->instance, dt_out, stsize);
+		break;
+	    case KADM_EXPDATE:
+		stsize += vts_long((KRB_UINT32)dt_in->exp_date,
+				   dt_out, stsize);
+		break;
+	    case KADM_ATTR:
+		stsize += vts_short(dt_in->attributes, dt_out, stsize);
+		break;
+	    case KADM_MAXLIFE:
+		stsize += vts_char(dt_in->max_life, dt_out, stsize);
+		break;
+	    case KADM_DESKEY:
+		stsize += vts_long(dt_in->key_high, dt_out, stsize);
+		stsize += vts_long(dt_in->key_low, dt_out, stsize);
+		break;
+	    default:
+		break;
+	    }
+	}
+    return stsize;
+}
+
+int
+build_field_header(
+    u_char *cont,		/* container for fields data */
+    u_char **st)		/* stream */
+{
+    *st = malloc(4);
+    if (*st == NULL)
+	return -1;
+    memcpy(*st, cont, 4);
+    return 4;	       /* return pointer to current stream location */
+}
+
+int
+vts_string(char *dat, u_char **st, int loc)
+{
+    size_t len;
+    unsigned char *p;
+
+    if (loc < 0)
+	return -1;
+    len = strlen(dat) + 1;
+    p = realloc(*st, (size_t)loc + len);
+    if (p == NULL)
+	return -1;
+    memcpy(p + loc, dat, len);
+    *st = p;
+    return len;
+}
+
+int
+vts_short(KRB_UINT32 dat, u_char **st, int loc)
+{
+    unsigned char *p;
+
+    if (loc < 0)
+	return -1;
+    p = realloc(*st, (size_t)loc + 2);
+    if (p == NULL)
+	return -1;
+
+    *st = p; /* KRB4_PUT32BE will modify p */
+
+    p += loc; /* place bytes at the end */
+    KRB4_PUT16BE(p, dat);
+
+    return 2;
+}
+
+int
+vts_long(KRB_UINT32 dat, u_char **st, int loc)
+{
+    unsigned char *p;
+
+    if (loc < 0)
+	return -1;
+    p = realloc(*st, (size_t)loc + 4);
+    if (p == NULL)
+	return -1;
+
+    *st = p; /* KRB4_PUT32BE will modify p */
+
+    p += loc; /* place bytes at the end */
+    KRB4_PUT32BE(p, dat);
+
+    return 4;
+}
+
+int
+vts_char(KRB_UINT32 dat, u_char **st, int loc)
+{
+    unsigned char *p;
+
+    if (loc < 0)
+	return -1;
+    p = realloc(*st, (size_t)loc + 1);
+    if (p == NULL)
+	return -1;
+    p[loc] = dat & 0xff;
+    *st = p;
+    return 1;
+}
+
+/*
+stream_to_vals
+  recieves    : u_char *, kadm_vals *
+  returns     : a kadm_vals filled in according to u_char *
+
+this decodes a byte stream represntation of a vals struct into kadm_vals
+*/
+int
+stream_to_vals(
+    u_char *dt_in,
+    Kadm_vals *dt_out,
+    int maxlen)			/* max length to use */
+{
+    register int vsloop, stsize; /* loop counter, stream size */
+    register int status;
+
+    memset(dt_out, 0, sizeof(*dt_out));
+
+    stsize = check_field_header(dt_in, dt_out->fields, maxlen);
+    if (stsize < 0)
+	return -1;
+    for (vsloop = 31; vsloop >= 0; vsloop--)
+	if (IS_FIELD(vsloop, dt_out->fields))
+	    switch (vsloop) {
+	    case KADM_NAME:
+		status = stv_string(dt_in, dt_out->name, stsize,
+				    sizeof(dt_out->name), maxlen);
+		if (status < 0)
+		    return -1;
+		stsize += status;
+		break;
+	    case KADM_INST:
+		status = stv_string(dt_in, dt_out->instance, stsize,
+				    sizeof(dt_out->instance), maxlen);
+		if (status < 0)
+		    return -1;
+		stsize += status;
+		break;
+	    case KADM_EXPDATE:
+	    {
+		KRB_UINT32 exp_date;
+
+		status = stv_long(dt_in, &exp_date, stsize, maxlen);
+		if (status < 0)
+		    return -1;
+		dt_out->exp_date = exp_date;
+		stsize += status;
+	    }
+	    break;
+	    case KADM_ATTR:
+		status = stv_short(dt_in, &dt_out->attributes, stsize,
+				   maxlen);
+		if (status < 0)
+		    return -1;
+		stsize += status;
+		break;
+	    case KADM_MAXLIFE:
+		status = stv_char(dt_in, &dt_out->max_life, stsize,
+				  maxlen);
+		if (status < 0)
+		    return -1;
+		stsize += status;
+		break;
+	    case KADM_DESKEY:
+		status = stv_long(dt_in, &dt_out->key_high, stsize,
+				  maxlen);
+		if (status < 0)
+		    return -1;
+		stsize += status;
+		status = stv_long(dt_in, &dt_out->key_low, stsize,
+				  maxlen);
+		if (status < 0)
+		    return -1;
+		stsize += status;
+		break;
+	    default:
+		break;
+	    }
+    return stsize;
+}
+
+int
+check_field_header(
+    u_char *st,			/* stream */
+    u_char *cont,		/* container for fields data */
+    int maxlen)
+{
+    if (4 > maxlen)
+	return -1;
+    memcpy(cont, st, 4);
+    return 4;	       /* return pointer to current stream location */
+}
+
+int
+stv_string(
+    register u_char *st,	/* base pointer to the stream */
+    char *dat,			/* a string to read from the stream */
+    register int loc,	 /* offset into the stream for current data */
+    int stlen,			/* max length of string to copy in */
+    int maxlen)			/* max length of input stream */
+{
+    int maxcount;		/* max count of chars to copy */
+
+    if (loc < 0)
+	return -1;
+    maxcount = min(maxlen - loc, stlen);
+    if (maxcount <= 0)	     /* No strings left in the input stream */
+	return -1;
+
+    (void) strncpy(dat, (char *)st + loc, (size_t)maxcount);
+
+    if (dat[maxcount - 1]) /* not null-term --> not enuf room */
+	return -1;
+    return strlen(dat) + 1;
+}
+
+int
+stv_short(u_char *st, u_short *dat, int loc, int maxlen)
+{
+    u_short temp;
+    unsigned char *p;
+
+    if (loc < 0 || loc + 2 > maxlen)
+	return -1;
+    p = st + loc;
+    KRB4_GET16BE(temp, p);
+    *dat = temp;
+    return 2;
+}
+
+int
+stv_long(u_char *st, KRB_UINT32 *dat, int loc, int maxlen)
+{
+    KRB_UINT32 temp;
+    unsigned char *p;
+
+    if (loc < 0 || loc + 4 > maxlen)
+	return -1;
+    p = st + loc;
+    KRB4_GET32BE(temp, p);
+    *dat = temp;
+    return 4;
+}
+
+int
+stv_char(u_char *st, u_char *dat, int loc, int maxlen)
+{
+    if (loc < 0 || loc + 1 > maxlen)
+	return -1;
+    *dat = *(st + loc);
+    return 1;
+}
diff --git a/mechglue/src/lib/krb4/klog.c b/mechglue/src/lib/krb4/klog.c
new file mode 100644
index 000000000..f0b87631a
--- /dev/null
+++ b/mechglue/src/lib/krb4/klog.c
@@ -0,0 +1,124 @@
+/*
+ * lib/krb4/klog.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "krb5/autoconf.h"
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#if !defined(VMS) && !defined(_WIN32)
+#include <sys/time.h>
+#endif
+#include <stdio.h>
+
+#include "krb4int.h"
+#include <klog.h>
+
+static char *log_name = KRBLOG;
+static char logtxt[1000];
+
+/*
+ * This file contains two logging routines: kset_logfile()
+ * to determine the file to which log entries should be written;
+ * and klog() to write log entries to the file.
+ */
+
+/*
+ * klog() is used to add entries to the logfile (see kset_logfile()
+ * below).  Note that it is probably not portable since it makes
+ * assumptions about what the compiler will do when it is called
+ * with less than the correct number of arguments which is the
+ * way it is usually called.
+ *
+ * The log entry consists of a timestamp and the given arguments
+ * printed according to the given "format" string.
+ *
+ * The log file is opened and closed for each log entry.
+ *
+ * If the given log type "type" is unknown, or if the log file
+ * cannot be opened, no entry is made to the log file.
+ *
+ * The return value is always a pointer to the formatted log
+ * text string "logtxt".
+ */
+
+char * klog(type,format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a0)
+    int type;
+    char *format;
+    char *a1,*a2,*a3,*a4,*a5,*a6,*a7,*a8,*a9,*a0;
+{
+    FILE *logfile;
+    time_t now;
+    struct tm *tm;
+    static int logtype_array[NLOGTYPE];
+    static int array_initialized;
+
+    if (!(array_initialized++)) {
+        logtype_array[L_NET_ERR] = 1;
+        logtype_array[L_KRB_PERR] = 1;
+        logtype_array[L_KRB_PWARN] = 1;
+        logtype_array[L_APPL_REQ] = 1;
+        logtype_array[L_INI_REQ] = 1;
+        logtype_array[L_DEATH_REQ] = 1;
+        logtype_array[L_NTGT_INTK] = 1;
+        logtype_array[L_ERR_SEXP] = 1;
+        logtype_array[L_ERR_MKV] = 1;
+        logtype_array[L_ERR_NKY] = 1;
+        logtype_array[L_ERR_NUN] = 1;
+        logtype_array[L_ERR_UNK] = 1;
+    }
+
+    (void) sprintf(logtxt,format,a1,a2,a3,a4,a5,a6,a7,a8,a9,a0);
+
+    if (!logtype_array[type])
+	return(logtxt);
+
+    if ((logfile = fopen(log_name,"a")) == NULL)
+        return(logtxt);
+
+    (void) time(&now);
+    tm = localtime(&now);
+
+    fprintf(logfile,"%2d-%s-%d %02d:%02d:%02d ",tm->tm_mday,
+            month_sname(tm->tm_mon + 1),1900+tm->tm_year,
+            tm->tm_hour, tm->tm_min, tm->tm_sec);
+    fprintf(logfile,"%s\n",logtxt);
+    (void) fclose(logfile);
+    return(logtxt);
+}
+
+/*
+ * kset_logfile() changes the name of the file to which
+ * messages are logged.  If kset_logfile() is not called,
+ * the logfile defaults to KRBLOG, defined in "krb.h".
+ */
+
+void
+kset_logfile(filename)
+    char *filename;
+{
+    log_name = filename;
+}
diff --git a/mechglue/src/lib/krb4/kname_parse.c b/mechglue/src/lib/krb4/kname_parse.c
new file mode 100644
index 000000000..db3a1cf0b
--- /dev/null
+++ b/mechglue/src/lib/krb4/kname_parse.c
@@ -0,0 +1,411 @@
+/*
+ * lib/krb4/kname_parse.c
+ *
+ * Copyright 1987, 1988, 2001 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+#include "krb.h"
+#include <string.h>
+
+static int k_isname_unparsed(const char *s);
+static int k_isinst_unparsed(const char *s);
+static int k_isrealm_unparsed(const char *s);
+
+/*
+ * max size of full name
+ *
+ * XXX This does not account for backslach quoting, and besides we
+ * might want to use MAX_K_NAME_SZ.
+ */
+#define FULL_SZ (ANAME_SZ + INST_SZ + REALM_SZ)
+
+#define NAME    0		/* which field are we in? */
+#define INST    1
+#define REALM   2
+
+/*
+ * This file contains four routines for handling Kerberos names.
+ *
+ * kname_parse() breaks a Kerberos name into its name, instance,
+ * and realm components.
+ *
+ * k_isname(), k_isinst(), and k_isrealm() check a given string to see if
+ * it's a syntactically legitimate respective part of a Kerberos name,
+ * returning 1 if it is, 0 if it isn't.
+ *
+ * Definition of "syntactically legitimate" names is according to
+ * the Project Athena Technical Plan Section E.2.1, page 7 "Specifying
+ * names", version dated 21 Dec 1987.
+ */
+
+/*
+ * kname_parse() takes a Kerberos name "fullname" of the form:
+ *
+ *		username[.instance][@realm]
+ *
+ * and returns the three components ("name", "instance", and "realm"
+ * in the example above) in the given arguments "np", "ip", and "rp".
+ *
+ * If successful, it returns KSUCCESS.  If there was an error,
+ * KNAME_FMT is returned.
+ *
+ * For proper operation, this routine requires that the ip, np, and rp
+ * arguments be initialized, either to null strings, or to default values
+ * of name, instance, and realm.  FIXME-gnu:  Does anyone use it this way?
+ */
+
+int KRB5_CALLCONV
+kname_parse(np, ip, rp, fullname)
+    char *np;
+    char *ip;
+    char *rp;
+    char *fullname;
+{
+    char buf[FULL_SZ];
+    char *rnext, *wnext;	/* next char to read, write */
+    register char c;
+    int backslash;
+    int field;
+
+    backslash = 0;
+    rnext = buf;
+    wnext = np;
+    field = NAME;
+
+    if (strlen(fullname) > FULL_SZ)
+        return KNAME_FMT;
+    (void) strcpy(buf, fullname);
+
+    while ((c = *rnext++)) {
+        if (backslash) {
+            *wnext++ = c;
+            backslash = 0;
+            continue;
+        }
+        switch (c) {
+        case '\\':
+            backslash++;
+            break;
+        case '.':
+            switch (field) {
+            case NAME:
+                if (wnext == np)
+                    return KNAME_FMT;
+                *wnext = '\0';
+                field = INST;
+                wnext = ip;
+                break;
+            case INST:		/* We now allow period in instance */
+            case REALM:
+                *wnext++ = c;
+                break;
+            default:
+                DEB (("unknown field value\n"));
+                return KNAME_FMT;
+            }
+            break;
+        case '@':
+            switch (field) {
+            case NAME:
+                if (wnext == np)
+                    return KNAME_FMT;
+                *ip = '\0';
+                /* fall through */
+            case INST:
+                *wnext = '\0';
+                field = REALM;
+                wnext = rp;
+                break;
+            case REALM:
+                return KNAME_FMT;
+            default:
+                DEB (("unknown field value\n"));
+                return KNAME_FMT;
+            }
+            break;
+        default:
+            *wnext++ = c;
+        }
+	/*
+	 * Paranoia: check length each time through to ensure that we
+	 * don't overwrite things.
+	 */
+	switch (field) {
+	case NAME:
+	    if (wnext - np >= ANAME_SZ)
+		return KNAME_FMT;
+	    break;
+	case INST:
+	    if (wnext - ip >= INST_SZ)
+		return KNAME_FMT;
+	    break;
+	case REALM:
+	    if (wnext - rp >= REALM_SZ)
+		return KNAME_FMT;
+	    break;
+	default:
+	    DEB (("unknown field value\n"));
+	    return KNAME_FMT;
+	}
+    }
+    *wnext = '\0';
+    return KSUCCESS;
+}
+
+/*
+ * k_isname() returns 1 if the given name is a syntactically legitimate
+ * Kerberos name; returns 0 if it's not.
+ */
+
+int KRB5_CALLCONV
+k_isname(s)
+    char *s;
+{
+    register char c;
+    int backslash = 0;
+
+    if (!*s)
+        return 0;
+    if (strlen(s) > ANAME_SZ - 1)
+        return 0;
+    while((c = *s++)) {
+        if (backslash) {
+            backslash = 0;
+            continue;
+        }
+        switch(c) {
+        case '\\':
+            backslash = 1;
+            break;
+        case '.':
+            return 0;
+            /* break; */
+        case '@':
+            return 0;
+            /* break; */
+        }
+    }
+    return 1;
+}
+
+
+/*
+ * k_isinst() returns 1 if the given name is a syntactically legitimate
+ * Kerberos instance; returns 0 if it's not.
+ *
+ * We now allow periods in instance names -- they are unambiguous.
+ */
+
+int KRB5_CALLCONV
+k_isinst(s)
+    char *s;
+{
+    register char c;
+    int backslash = 0;
+
+    if (strlen(s) > INST_SZ - 1)
+        return 0;
+    while((c = *s++)) {
+        if (backslash) {
+            backslash = 0;
+            continue;
+        }
+        switch(c) {
+        case '\\':
+            backslash = 1;
+            break;
+        case '@':
+            return 0;
+            /* break; */
+        }
+    }
+    return 1;
+}
+
+/*
+ * k_isrealm() returns 1 if the given name is a syntactically legitimate
+ * Kerberos realm; returns 0 if it's not.
+ */
+
+int KRB5_CALLCONV
+k_isrealm(s)
+    char *s;
+{
+    register char c;
+    int backslash = 0;
+
+    if (!*s)
+        return 0;
+    if (strlen(s) > REALM_SZ - 1)
+        return 0;
+    while((c = *s++)) {
+        if (backslash) {
+            backslash = 0;
+            continue;
+        }
+        switch(c) {
+        case '\\':
+            backslash = 1;
+            break;
+        case '@':
+            return 0;
+            /* break; */
+        }
+    }
+    return 1;
+}
+
+int KRB5_CALLCONV
+kname_unparse(
+    char	*outFullName,
+    const char	*inName,
+    const char	*inInstance,
+    const char	*inRealm)
+{
+    const char	*read;
+    char	*write = outFullName;
+
+    if (inName == NULL)
+	return KFAILURE;
+
+    if (outFullName == NULL)
+        return KFAILURE;
+
+    if (!k_isname_unparsed(inName) ||
+	((inInstance != NULL) && !k_isinst_unparsed(inInstance)) ||
+	((inRealm != NULL) && !k_isrealm_unparsed(inRealm))) {
+
+	return KFAILURE;
+    }
+
+    for (read = inName; *read != '\0'; read++, write++) {
+	if ((*read == '.') || (*read == '@')) {
+	    *write = '\\';
+	    write++;
+	}
+	*write = *read;
+    }
+
+    if ((inInstance != NULL) && (inInstance[0] != '\0')) {
+	*write = '.';
+	write++;
+	for (read = inInstance; *read != '\0'; read++, write++) {
+	    if (*read == '@') {
+		*write = '\\';
+		write++;
+	    }
+	    *write = *read;
+	}
+    }
+
+    if ((inRealm != NULL) && (inRealm[0] != '\0')) {
+	*write = '@';
+	write++;
+	for (read = inRealm; *read != '\0'; read++, write++) {
+	    if (*read == '@') {
+		*write = '\\';
+		write++;
+	    }
+	    *write = *read;
+	}
+    }
+
+    *write = '\0';
+    return KSUCCESS;
+}
+
+/*
+ * k_isname, k_isrealm, k_isinst expect an unparsed realm -- i.e., one where all
+ * components have special characters escaped with \. However,
+ * for kname_unparse, we need to be able to sanity-check components without \.
+ * That's what k_is*_unparsed are for.
+ */
+
+static int
+k_isname_unparsed(const char *s)
+{
+    int len = strlen(s);
+    const char* c;
+    /* Has to be non-empty and has to fit in ANAME_SZ when escaped with \ */
+
+    if (!*s)
+        return 0;
+
+    for (c = s; *c != '\0'; c++) {
+    	switch (*c) {
+	case '.':
+	case '@':
+	    len++;
+	    break;
+    	}
+    }
+
+    if (len > ANAME_SZ - 1)
+        return 0;
+    return 1;
+}
+
+static int
+k_isinst_unparsed(const char *s)
+{
+    int len = strlen(s);
+    const char* c;
+    /* Has to fit in INST_SZ when escaped with \ */
+
+    for (c = s; *c != '\0'; c++) {
+    	switch (*c) {
+	case '.':
+	case '@':
+	    len++;
+	    break;
+    	}
+    }
+
+    if (len > INST_SZ - 1)
+        return 0;
+    return 1;
+}
+
+static int
+k_isrealm_unparsed(const char *s)
+{
+    int len = strlen(s);
+    const char* c;
+    /* Has to be non-empty and has to fit in REALM_SZ when escaped with \ */
+
+    if (!*s)
+        return 0;
+
+    for (c = s; *c != '\0'; c++) {
+    	switch (*c) {
+	case '@':
+	    len++;
+	    break;
+    	}
+    }
+
+    if (len > REALM_SZ - 1)
+        return 0;
+    return 1;
+}
diff --git a/mechglue/src/lib/krb4/kntoln.c b/mechglue/src/lib/krb4/kntoln.c
new file mode 100644
index 000000000..ca48381b9
--- /dev/null
+++ b/mechglue/src/lib/krb4/kntoln.c
@@ -0,0 +1,62 @@
+/*
+ * kntoln.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+#include <string.h>
+
+/*
+ * krb_kntoln converts an auth name into a local name by looking up
+ * the auth name in the /etc/aname file.  The format of the aname
+ * file is:
+ *
+ * +-----+-----+-----+-----+------+----------+-------+-------+
+ * | anl | inl | rll | lnl | name | instance | realm | lname |
+ * +-----+-----+-----+-----+------+----------+-------+-------+
+ * | 1by | 1by | 1by | 1by | name | instance | realm | lname |
+ * +-----+-----+-----+-----+------+----------+-------+-------+
+ *
+ * If the /etc/aname file can not be opened it will set the
+ * local name to the auth name.  Thus, in this case it performs as
+ * the identity function.
+ *
+ * The name instance and realm are passed to krb_kntoln through
+ * the AUTH_DAT structure (ad).
+ *
+ * Now here's what it *really* does:
+ *
+ * Given a Kerberos name in an AUTH_DAT structure, check that the
+ * instance is null, and that the realm is the same as the local
+ * realm, and return the principal's name in "lname".  Return
+ * KSUCCESS if all goes well, otherwise KFAILURE.
+ */
+
+/* The definition of MAX_USERNAME here MUST agree with kuserok.c, or bad
+ * things will happen. */
+#define MAX_USERNAME 10
+
+int
+krb_kntoln(ad,lname)
+    AUTH_DAT *ad;
+    char *lname;
+{
+    static char lrealm[REALM_SZ];
+
+    if (!(*lrealm) && (krb_get_lrealm(lrealm,1) == KFAILURE))
+        return(KFAILURE);
+
+    if (strcmp(ad->pinst,""))
+        return(KFAILURE);
+    if (strcmp(ad->prealm,lrealm))
+        return(KFAILURE);
+    (void) strncpy(lname,ad->pname,MAX_USERNAME-1);
+    lname[MAX_USERNAME - 1] = '\0';
+    return(KSUCCESS);
+}
diff --git a/mechglue/src/lib/krb4/kparse.c b/mechglue/src/lib/krb4/kparse.c
new file mode 100644
index 000000000..94e5b935e
--- /dev/null
+++ b/mechglue/src/lib/krb4/kparse.c
@@ -0,0 +1,784 @@
+/*
+ * kparse.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Purpose:
+ * This module was developed to parse the "~/.klogin" files for
+ * Kerberos-authenticated rlogin/rcp/rsh services.  However, it is
+ * general purpose and can be used to parse any such parameter file.
+ *
+ * The parameter file should consist of one or more entries, with each
+ * entry on a separate line and consisting of zero or more
+ * "keyword=value" combinations.  The keyword is case insensitive, but
+ * the value is not.  Any string may be enclosed in quotes, and
+ * c-style "\" literals are supported.  A comma may be used to
+ * separate the k/v combinations, and multiple commas are ignored.
+ * Whitespace (blank or tab) may be used freely and is ignored.
+ *
+ * Full error processing is available.  When PS_BAD_KEYWORD or
+ * PS_SYNTAX is returned from fGetParameterSet(), the string ErrorMsg
+ * contains a meaningful error message.
+ *
+ * Keywords and their default values are programmed by an external
+ * table.
+ *
+ * Routines:
+ * fGetParameterSet()      parse one line of the parameter file
+ * fGetKeywordValue()      parse one "keyword=value" combo
+ * fGetToken()             parse one token
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <kparse.h>
+#include <string.h>
+#include "krb5/autoconf.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+#define MAXKEY          80
+#define MAXVALUE        80
+
+static char *strutol (char *);
+
+
+#ifndef HAVE_STRDUP
+static char *strdup();
+#endif
+#ifndef HAVE_STDLIB_H
+extern char *malloc();
+#endif
+
+static int sLineNbr=1;		/* current line nbr in parameter file */
+static char ErrorMsg[80];	/* meaningful only when KV_SYNTAX, PS_SYNTAX,
+				 * or PS_BAD_KEYWORD is returned by
+				 * fGetKeywordValue or fGetParameterSet */
+
+int fGetParameterSet( fp,parm,parmcount )
+    FILE *fp;
+    parmtable parm[];
+    int parmcount;
+{
+    int rc,i;
+    char keyword[MAXKEY];
+    char value[MAXVALUE];
+
+    while (TRUE) {
+        rc=fGetKeywordValue(fp,keyword,MAXKEY,value,MAXVALUE);
+
+        switch (rc) {
+
+        case KV_EOF:
+            return(PS_EOF);
+
+        case KV_EOL:
+            return(PS_OKAY);
+
+        case KV_SYNTAX:
+            return(PS_SYNTAX);
+
+        case KV_OKAY:
+            /*
+             * got a reasonable keyword/value pair.  Search the
+             * parameter table to see if we recognize the keyword; if
+             * not, return an error.  If we DO recognize it, make sure
+             * it has not already been given.  If not already given,
+             * save the value.
+             */
+            for (i=0; i<parmcount; i++) {
+                if (strcmp(strutol(keyword),parm[i].keyword)==0) {
+                    if (parm[i].value) {
+                        sprintf(ErrorMsg,"duplicate keyword \"%s\" found",
+                                keyword);
+                        return(PS_BAD_KEYWORD);
+                    }
+                    parm[i].value = strdup(value);
+                    break;
+                }
+            }
+            if (i >= parmcount) {
+                sprintf(ErrorMsg, "unrecognized keyword \"%s\" found",
+			keyword);
+                return(PS_BAD_KEYWORD);
+            }
+            break;
+
+        default:
+            sprintf(ErrorMsg,
+		    "panic: bad return (%d) from fGetToken()",rc);
+            break;
+        }
+    }
+}
+
+/*
+ * Routine: ParmCompare
+ *
+ * Purpose:
+ * ParmCompare checks a specified value for a particular keyword.
+ * fails if keyword not found or keyword found but the value was
+ * different. Like strcmp, ParmCompare returns 0 for a match found, -1
+ * otherwise
+ */
+int ParmCompare( parm, parmcount, keyword, value )
+    parmtable parm[];
+    int parmcount;
+    char *keyword;
+    char *value;
+{
+    int i;
+
+    for (i=0; i<parmcount; i++) {
+        if (strcmp(parm[i].keyword,keyword)==0) {
+            if (parm[i].value) {
+                return(strcmp(parm[i].value,value));
+            } else {
+                return(strcmp(parm[i].defvalue,value));
+            }
+        }
+    }
+    return(-1);
+}
+
+void FreeParameterSet(parm,parmcount)
+    parmtable parm[];
+    int parmcount;
+{
+    int i;
+
+    for (i=0; i<parmcount; i++) {
+        if (parm[i].value) {
+            free(parm[i].value);
+            parm[i].value = (char *)NULL;
+        }
+    }
+}
+
+int fGetKeywordValue( fp, keyword, klen, value, vlen )
+    FILE *fp;
+    char *keyword;
+    int klen;
+    char *value;
+    int vlen;
+{
+    int rc;
+    int gotit;
+
+    *keyword = *value = '\0';   /* preset strings to NULL */
+
+    /*
+     * Looking for a keyword.
+     *          return an exception for EOF or BAD_QSTRING
+     *          ignore leading WHITEspace
+     *          ignore any number of leading commas
+     *          newline means we have all the parms for this
+     *          	statement; give an indication that there is
+     *          	nothing more on this line.
+     *          stop looking if we find QSTRING, STRING, or NUMBER
+     *          return syntax error for any other PUNKtuation
+     */
+    gotit = FALSE;
+    do {
+        rc = fGetToken(fp,keyword,klen);
+
+        switch (rc) {
+
+        case GTOK_WHITE:
+            break;
+
+        case GTOK_EOF:
+            return(KV_EOF);
+
+        case GTOK_BAD_QSTRING:
+            sprintf(ErrorMsg,"unterminated string \"%s found",keyword);
+            return(KV_SYNTAX);
+
+        case GTOK_PUNK:
+            if (strcmp("\n",keyword)==0) {
+                return(KV_EOL);
+            } else if (strcmp(",",keyword)!=0) {
+                sprintf(ErrorMsg,"expecting rvalue, found \'%s\'",keyword);
+            }
+            break;
+
+        case GTOK_STRING:
+        case GTOK_QSTRING:
+        case GTOK_NUMBER:
+            gotit = TRUE;
+            break;
+
+        default:
+            sprintf(ErrorMsg,"panic: bad return (%d) from fGetToken()",rc);
+            return(KV_SYNTAX);
+        }
+
+    } while (!gotit);
+
+    /*
+     * now we expect an equal sign.
+     *          skip any whitespace
+     *          stop looking if we find an equal sign
+     *          anything else causes a syntax error
+     */
+    gotit = FALSE;
+    do {
+        rc = fGetToken(fp,value,vlen);
+
+        switch (rc) {
+
+        case GTOK_WHITE:
+            break;
+
+        case GTOK_BAD_QSTRING:
+            sprintf(ErrorMsg,
+		    "expecting \'=\', found unterminated string \"%s",
+                    value);
+            return(KV_SYNTAX);
+
+        case GTOK_PUNK:
+            if (strcmp("=",value)==0) {
+                gotit = TRUE;
+            } else {
+                if (strcmp("\n",value)==0) {
+                    sprintf(ErrorMsg,"expecting \"=\", found newline");
+                    fUngetChar('\n',fp);
+                } else {
+                    sprintf(ErrorMsg,
+			    "expecting rvalue, found \'%s\'",keyword);
+                }
+                return(KV_SYNTAX);
+            }
+            break;
+
+        case GTOK_STRING:
+        case GTOK_QSTRING:
+        case GTOK_NUMBER:
+            sprintf(ErrorMsg,"expecting \'=\', found \"%s\"",value);
+            return(KV_SYNTAX);
+
+        case GTOK_EOF:
+            sprintf(ErrorMsg,"expecting \'=\', found EOF");
+            return(KV_SYNTAX);
+
+        default:
+            sprintf(ErrorMsg,
+		    "panic: bad return (%d) from fGetToken()",rc);
+            return(KV_SYNTAX);
+        }
+
+    } while ( !gotit );
+
+    /*
+     * got the keyword and equal sign, now get a value.
+     *          ignore any whitespace
+     *          any punctuation is a syntax error
+     */
+    gotit = FALSE;
+    do {
+        rc = fGetToken(fp,value,vlen);
+
+        switch (rc) {
+
+        case GTOK_WHITE:
+            break;
+
+        case GTOK_EOF:
+            sprintf(ErrorMsg,"expecting rvalue, found EOF");
+            return(KV_SYNTAX);
+
+        case GTOK_BAD_QSTRING:
+            sprintf(ErrorMsg,"unterminated quoted string \"%s",value);
+            return(KV_SYNTAX);
+
+        case GTOK_PUNK:
+            if (strcmp("\n",value)==0) {
+                sprintf(ErrorMsg,"expecting rvalue, found newline");
+                fUngetChar('\n',fp);
+            } else {
+                sprintf(ErrorMsg,
+			"expecting rvalue, found \'%s\'",value);
+            }
+            return(KV_SYNTAX);
+            break;
+
+        case GTOK_STRING:
+        case GTOK_QSTRING:
+        case GTOK_NUMBER:
+            gotit = TRUE;
+            return(KV_OKAY);
+
+        default:
+            sprintf(ErrorMsg,
+		    "panic: bad return (%d) from fGetToken()",rc);
+            return(KV_SYNTAX);
+        }
+
+    } while ( !gotit );
+    /*NOTREACHED*/
+    return 0; /* to keep gcc happy */
+}
+
+/*
+ * Routine Name: fGetToken
+ *
+ * Function: read the next token from the specified file.
+ * A token is defined as a group of characters
+ * terminated by a white space char (SPACE, CR,
+ * LF, FF, TAB). The token returned is stripped of
+ * both leading and trailing white space, and is
+ * terminated by a NULL terminator.  An alternate
+ * definition of a token is a string enclosed in
+ * single or double quotes.
+ *
+ * Explicit Parameters:
+ * fp              pointer to the input FILE
+ * dest    pointer to destination buffer
+ * maxlen  length of the destination buffer. The buffer
+ * length INCLUDES the NULL terminator.
+ *
+ * Implicit Parameters: stderr  where the "token too long" message goes
+ *
+ * External Procedures: fgetc
+ *
+ * Side Effects:                None
+ *
+ * Return Value:                A token classification value, as
+ *				defined in kparse.h. Note that the
+ *				classification for end of file is
+ *				always zero.
+ */
+int fGetToken(fp, dest, maxlen)
+    FILE *fp;
+    char *dest;
+    int  maxlen;
+{
+    int ch='\0';
+    int len=0;
+    char *p = dest;
+    int digits;
+
+    ch=fGetChar(fp);
+
+    /*
+     * check for a quoted string.  If found, take all characters
+     * that fit until a closing quote is found.  Note that this
+     * algorithm will not behave well for a string which is too long.
+     */
+    if (ISQUOTE(ch)) {
+        int done = FALSE;
+        do {
+            ch = fGetChar(fp);
+            done = ((maxlen<++len)||ISLINEFEED(ch)||(ch==EOF)
+		    ||ISQUOTE(ch));
+            if (ch=='\\')
+                ch = fGetLiteral(fp);
+            if (!done)
+                *p++ = ch;
+            else if ((ch!=EOF) && !ISQUOTE(ch))
+                fUngetChar(ch,fp);
+        } while (!done);
+        *p = '\0';
+        if (ISLINEFEED(ch)) return(GTOK_BAD_QSTRING);
+        return(GTOK_QSTRING);
+    }
+
+    /*
+     * Not a quoted string.  If its a token character (rules are
+     * defined via the ISTOKENCHAR macro, in kparse.h) take it and all
+     * token chars following it until we run out of space.
+     */
+    digits=TRUE;
+    if (ISTOKENCHAR(ch)) {
+        while ( (ISTOKENCHAR(ch)) && len<maxlen-1 ) {
+            if (!isdigit(ch)) digits=FALSE;
+            *p++ = ch;
+            len++;
+            ch = fGetChar(fp);
+        };
+        *p = '\0';
+
+        if (ch!=EOF) {
+            fUngetChar(ch,fp);
+        }
+        if (digits) {
+            return(GTOK_NUMBER);
+        } else {
+            return(GTOK_STRING);
+        }
+    }
+
+    /*
+     * Neither a quoted string nor a token character.  Return a string
+     * with just that one character in it.
+     */
+    if (ch==EOF) {
+        return(GTOK_EOF);
+    }
+    if (!ISWHITESPACE(ch)) {
+        *p++ = ch;
+        *p='\0';
+    } else {
+        *p++ = ' ';		/* white space is always the
+				 * blank character */
+        *p='\0';
+        /*
+         * The character is a white space. Flush all additional white
+         * space.
+         */
+        while (ISWHITESPACE(ch) && ((ch=fGetChar(fp)) != EOF))
+            ;
+        if (ch!=EOF) {
+            fUngetChar(ch,fp);
+        }
+        return(GTOK_WHITE);
+    }
+    return(GTOK_PUNK);
+}
+
+/*
+ * fGetLiteral is called after we find a '\' in the input stream.  A
+ * string of numbers following the backslash are converted to the
+ * appropriate value; hex (0xn), octal (0n), and decimal (otherwise)
+ * are all supported.  If the char after the \ is not a number, we
+ * special case certain values (\n, \f, \r, \b) or return a literal
+ * otherwise (useful for \", for example).
+ */
+int fGetLiteral(fp)
+    FILE *fp;
+{
+    int ch;
+    int n=0;
+    int base;
+
+    ch = fGetChar(fp);
+
+    if (!isdigit(ch)) {
+        switch (ch) {
+        case 'n':       return('\n');
+        case 'f':       return('\f');
+        case 'r':       return('\r');
+        case 'b':       return('\b');
+        default:        return(ch);
+        }
+    }
+
+    /*
+     * got a number.  might be decimal (no prefix), octal (prefix 0),
+     * or hexadecimal (prefix 0x).  Set the base appropriately.
+     */
+    if (ch!='0') {
+        base=10;                /* its a decimal number */
+    } else {
+        /*
+         * found a zero, its either hex or octal
+         */
+        ch = fGetChar(fp);
+        if ((ch!='x') && (ch!='X')) {
+            base=010;
+        } else {
+            ch = fGetChar(fp);
+            base=0x10;
+        }
+    }
+
+    switch (base) {
+
+    case 010:                   /* octal */
+        while (ISOCTAL(ch)) {
+            n = (n*base) + ch - '0';
+            ch = fGetChar(fp);
+        }
+        break;
+
+    case 10:                    /* decimal */
+        while (isdigit(ch)) {
+            n = (n*base) + ch - '0';
+            ch = fGetChar(fp);
+        }
+        break;
+    case 0x10:                  /* hexadecimal */
+        while (isxdigit(ch)) {
+            if (isdigit(ch)) {
+                n = (n*base) + ch - '0';
+            } else {
+                n = (n*base) + toupper(ch) - 'A' + 0xA ;
+            }
+            ch = fGetChar(fp);
+        }
+        break;
+    default:
+#ifdef DEBUG
+        fprintf(stderr,"fGetLiteral() died real bad. Fix kparse.c.");
+#endif
+        break;
+    }
+    fUngetChar(ch,fp);
+    return(n);
+}
+
+/*
+ * exactly the same as ungetc(3) except that the line number of the
+ * input file is maintained.
+ */
+int fUngetChar(ch,fp)
+    int ch;
+    FILE *fp;
+{
+    if (ch=='\n') sLineNbr--;
+    return(ungetc(ch,fp));
+}
+
+
+/*
+ * exactly the same as fgetc(3) except that the line number of the
+ * input file is maintained.
+ */
+int fGetChar(fp)
+    FILE *fp;
+{
+    int ch = fgetc(fp);
+    if (ch=='\n') sLineNbr++;
+    return(ch);
+}
+
+/*
+ * strutol changes all characters in a string to lower case, in place.
+ * the pointer to the beginning of the string is returned.
+ */
+
+static char * strutol( start )
+    char *start;
+{
+    char *q;
+    for (q=start; *q; q++)
+        if (isupper((int) *q))
+	    *q=tolower((int) *q);
+    return(start);
+}
+
+#ifdef GTOK_TEST	     /* mainline test routine for fGetToken() */
+
+#define MAXTOKEN 100
+
+char *pgm = "gettoken";
+
+main(argc,argv)
+    int argc;
+    char **argv;
+{
+    char *p;
+    int type;
+    FILE *fp;
+
+    if (--argc) {
+        fp = fopen(*++argv,"ra");
+        if (fp == (FILE *)NULL) {
+            fprintf(stderr,"can\'t open \"%s\"\n",*argv);
+        }
+    } else
+        fp = stdin;
+
+    p = malloc(MAXTOKEN);
+    while (type = fGetToken(fp,p,MAXTOKEN)) {
+        switch(type) {
+        case GTOK_BAD_QSTRING:
+	    printf("BAD QSTRING!\t");
+	    break;
+        case GTOK_EOF:
+	    printf("EOF!\t");
+	    break;
+        case GTOK_QSTRING:
+	    printf("QSTRING\t");
+	    break;
+        case GTOK_STRING:
+	    printf("STRING\t");
+	    break;
+        case GTOK_NUMBER:
+	    printf("NUMBER\t");
+	    break;
+        case GTOK_PUNK:
+	    printf("PUNK\t");
+	    break;
+        case GTOK_WHITE:
+	    printf("WHITE\t");
+	    break;
+        default:
+	    printf("HUH?\t");
+	    break;
+        }
+        if (*p=='\n')
+            printf("\\n\n");
+	else
+            printf("%s\n",p);
+    }
+    exit(0);
+}
+#endif
+
+#ifdef KVTEST
+
+main(argc,argv)
+    int argc;
+    char **argv;
+{
+    int rc,ch;
+    FILE *fp;
+    char key[MAXKEY],valu[MAXVALUE];
+    char *filename;
+
+    if (argc != 2) {
+        fprintf(stderr,"usage: test <filename>\n");
+        exit(1);
+    }
+
+    if (!(fp=fopen(*++argv,"r"))) {
+        fprintf(stderr,"can\'t open input file \"%s\"\n",filename);
+        exit(1);
+    }
+    filename = *argv;
+
+    while ((rc=fGetKeywordValue(fp,key,MAXKEY,valu,MAXVALUE))!=KV_EOF){
+
+        switch (rc) {
+
+        case KV_EOL:
+            printf("%s, line %d: nada mas.\n",filename,sLineNbr-1);
+            break;
+
+        case KV_SYNTAX:
+            printf("%s, line %d: syntax error: %s\n",
+                   filename,sLineNbr,ErrorMsg);
+            while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
+            break;
+
+        case KV_OKAY:
+            printf("%s, line %d: okay, %s=\"%s\"\n",
+                   filename,sLineNbr,key,valu);
+            break;
+
+        default:
+            printf("panic: bad return (%d) from fGetKeywordValue\n",rc);
+            break;
+        }
+    }
+    printf("EOF");
+    fclose(fp);
+    exit(0);
+}
+#endif
+
+#ifdef PSTEST
+
+parmtable kparm[] = {
+    /*  keyword, default, found value */
+    { "user",       "",    (char *)NULL },
+    { "realm",   "Athena", (char *)NULL },
+    { "instance",   "",    (char *)NULL }
+};
+
+main(argc,argv)
+    int argc;
+    char **argv;
+{
+    int rc,i,ch;
+    FILE *fp;
+    char *filename;
+
+    if (argc != 2) {
+        fprintf(stderr,"usage: test <filename>\n");
+        exit(1);
+    }
+
+    if (!(fp=fopen(*++argv,"r"))) {
+        fprintf(stderr,"can\'t open input file \"%s\"\n",filename);
+        exit(1);
+    }
+    filename = *argv;
+
+    while ((rc=fGetParameterSet(fp,kparm,PARMCOUNT(kparm))) != PS_EOF) {
+
+        switch (rc) {
+
+        case PS_BAD_KEYWORD:
+            printf("%s, line %d: %s\n",filename,sLineNbr,ErrorMsg);
+            while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
+            break;
+
+        case PS_SYNTAX:
+            printf("%s, line %d: syntax error: %s\n",
+                   filename,sLineNbr,ErrorMsg);
+            while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
+            break;
+
+        case PS_OKAY:
+            printf("%s, line %d: valid parameter set found:\n",
+                   filename,sLineNbr-1);
+            for (i=0; i<PARMCOUNT(kparm); i++) {
+                printf("\t%s = \"%s\"\n",kparm[i].keyword,
+                       (kparm[i].value ? kparm[i].value
+			: kparm[i].defvalue));
+            }
+            break;
+
+        default:
+            printf("panic: bad return (%d) from fGetParameterSet\n",rc);
+            break;
+        }
+        FreeParameterSet(kparm,PARMCOUNT(kparm));
+    }
+    printf("EOF");
+    fclose(fp);
+    exit(0);
+}
+#endif
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)strdup.c	5.3 (Berkeley) 6/1/90 */
+
+#ifndef HAVE_STRDUP
+static char *
+strdup(str)
+	const char *str;
+{
+	int len;
+	char *copy;
+
+	if (!str)
+		return((char *)0);
+	len = strlen(str) + 1;
+	if (!(copy = malloc((u_int)len)))
+		return((char *)0);
+	memcpy(copy, str, len);
+	return(copy);
+}
+#endif
diff --git a/mechglue/src/lib/krb4/krb4int.h b/mechglue/src/lib/krb4/krb4int.h
new file mode 100644
index 000000000..e513cfeda
--- /dev/null
+++ b/mechglue/src/lib/krb4/krb4int.h
@@ -0,0 +1,118 @@
+/*
+ * lib/krb4/krb4int.h
+ *
+ * Copyright 2001-2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * A series of private prototypes that we are not exporting but should
+ * be available for self consistancy in the library.
+ */
+
+#include "port-sockets.h"
+
+/* ad_print.c */
+void ad_print(AUTH_DAT *x);
+
+/* fgetst.c */
+int fgetst(FILE *, char *, int);
+
+/* getst.c */
+int getst(int, char *, int);
+
+/* g_cnffile.c */
+FILE *krb__get_realmsfile(void);
+
+FILE *krb__get_cnffile(void);
+
+/* g_svc_in_tkt.c */
+int krb_svc_init(char *, char *, char *, int, char *, char *);
+int krb_svc_init_preauth(char *, char *, char *, int, char *, char *);
+
+int krb_get_svc_in_tkt_preauth(char *, char *, char *, char *, char *, int, char *);
+
+/* gethostname.c */
+int k_gethostname(char *, int);
+
+/* g_in_tkt.c */
+int krb_get_in_tkt_preauth_creds(char *, char *, char *,
+				 char *, char *, int,
+				 key_proc_type, decrypt_tkt_type,
+				 char *, char *, int, CREDENTIALS *, KRB_UINT32 *);
+
+/* klog.c */
+void kset_logfile(char *);
+
+/* log.c */
+void krb_log(const char *, ...);
+
+void krb_set_logfile(char *);
+
+/* month_sname.c */
+const char * month_sname(int);
+
+/* password_to_key.c */
+key_proc_type *krb_get_keyprocs (key_proc_type keyproc);
+int KRB5_CALLCONV mit_passwd_to_key(char *user, char *instance, char *realm, 
+				    char *passwd, C_Block key);
+int KRB5_CALLCONV krb5_passwd_to_key(char *user, char *instance, char *realm,
+				     char *passwd, C_Block key);
+int KRB5_CALLCONV afs_passwd_to_key(char *user, char *instance, char *realm,
+				    char *passwd, C_Block key);
+
+/* rd_preauth.c */
+#ifdef KRB_DB_DEFS
+int krb_rd_preauth(KTEXT, char *, int, Principal *, des_cblock);
+#endif
+
+/* sendauth.c */
+int krb_net_rd_sendauth(int, KTEXT, KRB4_32 *);
+
+/* stime.c */
+char *krb_stime(long *);
+
+/* tf_util.c */
+int tf_save_cred(char *, char *, char *, C_Block, int , int, KTEXT, long);
+
+/* unix_glue.c */
+int krb_start_session(char *);
+
+int krb_end_session(char *);
+
+#ifndef _WIN32
+/* For windows users, these are defined in krb.h */
+char *krb_get_default_user (void);
+
+int krb_set_default_user (char *);
+#endif
+
+/* RealmConfig-glue.c */
+int krb_get_kpasswdhst(char *, char *, int);
+
+/* err_txt.c */
+void krb4int_et_init(void);
+void krb4int_et_fini(void);
+
+int krb4int_save_credentials_addr(
+    char *, char *, char *, C_Block, int, int, KTEXT, long, KRB_UINT32);
+
+int krb4int_send_to_kdc_addr(KTEXT, KTEXT, char *,
+			     struct sockaddr *, socklen_t *);
diff --git a/mechglue/src/lib/krb4/krb_err.et b/mechglue/src/lib/krb4/krb_err.et
new file mode 100644
index 000000000..c4f225d6c
--- /dev/null
+++ b/mechglue/src/lib/krb4/krb_err.et
@@ -0,0 +1,776 @@
+#	Copyright 1987,1988 Massachusetts Institute of Technology
+#
+#	For copying and distribution information, see the file
+#	"mit-copyright.h".
+# 
+#
+	error_table	krb
+
+	ec		KRBET_KSUCCESS,
+			"Kerberos successful"
+
+	ec		KRBET_KDC_NAME_EXP,
+			"Kerberos principal expired"
+
+	ec		KRBET_KDC_SERVICE_EXP,
+			"Kerberos service expired"
+
+	ec		KRBET_KDC_AUTH_EXP,
+			"Kerberos auth expired"
+
+	ec		KRBET_KDC_PKT_VER,
+			"Unknown kerberos protocol version"
+
+	ec		KRBET_KDC_P_MKEY_VER,
+			"Incorrect kerberos master key version for principal"
+
+	ec		KRBET_KDC_S_MKEY_VER,
+			"Incorrect kerberos master key version for service"
+
+	ec		KRBET_KDC_BYTE_ORDER,
+			"Bad byte order (kerberos)"
+
+	ec		KRBET_KDC_PR_UNKNOWN,
+			"Kerberos principal unknown"
+
+	ec		KRBET_KDC_PR_N_UNIQUE,
+			"Kerberos principal not unique"
+
+	ec		KRBET_KDC_NULL_KEY,
+			"Kerberos principal has null key"
+
+	ec		KRBET_KRB_RES11,
+		        "Reserved error message 11 (kerberos)"
+
+	ec		KRBET_KRB_RES12,
+		        "Reserved error message 12 (kerberos)"
+  
+	ec		KRBET_KRB_RES13,
+		        "Reserved error message 13 (kerberos)"
+
+	ec		KRBET_KRB_RES14,
+		        "Reserved error message 14 (kerberos)"
+
+	ec		KRBET_KRB_RES15,
+		        "Reserved error message 15 (kerberos)"
+
+	ec		KRBET_KRB_RES16,
+		        "Reserved error message 16 (kerberos)"
+
+	ec		KRBET_KRB_RES17,
+		        "Reserved error message 17 (kerberos)"
+
+	ec		KRBET_KRB_RES18,
+		        "Reserved error message 18 (kerberos)"
+
+	ec		KRBET_KRB_RES19,
+		        "Reserved error message 19 (kerberos)"
+
+	ec		KRBET_KDC_GEN_ERR,
+			"Generic error from Kerberos KDC"
+
+	ec		KRBET_GC_TKFIL,
+			"Can't read Kerberos ticket file"
+
+	ec		KRBET_GC_NOTKT,
+			"Can't find Kerberos ticket or TGT"
+
+	ec		KRBET_KRB_RES23,
+			"Reserved error message 23 (krb_get_cred)"
+
+	ec		KRBET_KRB_RES24,
+			"Reserved error message 24 (krb_get_cred)"
+
+	ec		KRBET_KRB_RES25,
+			"Reserved error message 25 (krb_get_cred)"
+
+	ec		KRBET_MK_AP_TGTEXP,
+			"Kerberos TGT Expired"
+
+	ec		KRBET_KRB_RES27,
+			"Reserved error message 27 (krb_mk_req)"
+
+	ec		KRBET_KRB_RES28,
+			"Reserved error message 28 (krb_mk_req)"
+
+	ec		KRBET_KRB_RES29,
+			"Reserved error message 29 (krb_mk_req)"
+
+	ec		KRBET_KRB_RES30,
+			"Reserved error message 30 (krb_mk_req)"
+
+	ec		KRBET_RD_AP_UNDEC,
+			"Can't decode authenticator (krb_rd_req)"
+
+	ec		KRBET_RD_AP_EXP,
+			"Kerberos ticket expired (krb_rd_req)"
+
+	ec		KRBET_RD_AP_NYV,
+			"Kerberos ticket not yet valid (krb_rd_req)"
+
+	ec		KRBET_RD_AP_REPEAT,
+			"Repeated request (krb_rd_req)"
+
+	ec		KRBET_RD_AP_NOT_US,
+			"Kerberos ticket is for wrong server (krb_rd_req)"
+
+	ec		KRBET_RD_AP_INCON,
+			"Kerberos request inconsistent"
+
+	ec		KRBET_RD_AP_TIME,
+			"Time is out of bounds (krb_rd_req)"
+
+	ec		KRBET_RD_AP_BADD,
+			"Incorrect net address (krb_rd_req)"
+
+	ec		KRBET_RD_AP_VERSION,
+			"Kerberos protocol version mismatch (krb_rd_req)"
+
+	ec		KRBET_RD_AP_MSG_TYPE,
+			"Invalid msg type (krb_rd_req)"
+
+	ec		KRBET_RD_AP_MODIFIED,
+			"Message integrity error (krb_rd_req)"
+
+	ec		KRBET_RD_AP_ORDER,
+			"Message out of order (krb_rd_req)"
+
+	ec		KRBET_RD_AP_UNAUTHOR,
+			"Unauthorized request (krb_rd_req)"
+
+	ec		KRBET_KRB_RES44,
+			"Reserved error message 44 (krb_rd_req)"
+
+	ec		KRBET_KRB_RES45,
+			"Reserved error message 45 (krb_rd_req)"
+
+	ec		KRBET_KRB_RES46,
+			"Reserved error message 46 (krb_rd_req)"
+
+	ec		KRBET_KRB_RES47,
+			"Reserved error message 47 (krb_rd_req)"
+
+	ec		KRBET_KRB_RES48,
+			"Reserved error message 48 (krb_rd_req)"
+
+	ec		KRBET_KRB_RES49,
+			"Reserved error message 49 (krb_rd_req)"
+
+	ec		KRBET_KRB_RES50,
+			"Reserved error message 50 (krb_rd_req)"
+
+	ec		KRBET_GT_PW_NULL,
+			"Current password is null (get_pw_tkt)"
+
+	ec		KRBET_GT_PW_BADPW,
+			"Incorrect current password (get_pw_tkt)"
+
+	ec		KRBET_GT_PW_PROT,
+			"Protocol error (get_pw_tkt)"
+
+	ec		KRBET_GT_PW_KDCERR,
+			"Error returned by KDC (get_pw_tkt)"
+
+	ec		KRBET_GT_PW_NULLTKT,
+			"Null Kerberos ticket returned by KDC (get_pw_tkt)"
+
+	ec		KRBET_SKDC_RETRY,
+			"Retry count exceeded (send_to_kdc)"
+
+	ec		KRBET_SKDC_CANT,
+			"Can't send request (send_to_kdc)"
+
+	ec		KRBET_KRB_RES58,
+			"Reserved error message 58 (send_to_kdc)"
+
+	ec		KRBET_KRB_RES59,
+			"Reserved error message 59 (send_to_kdc)"
+
+	ec		KRBET_KRB_RES60,
+			"Reserved error message 60 (send_to_kdc)"
+
+	ec		KRBET_INTK_W_NOTALL,
+			"Kerberos error: not all tickets returned"
+
+	ec		KRBET_INTK_BADPW,
+			"Incorrect password (get_in_tkt)"
+
+	ec		KRBET_INTK_PROT,
+			"Protocol error (get_in_tkt)"
+
+	ec		KRBET_KRB_RES64,
+			"Reserved error message 64 (get_in_tkt)"
+
+	ec		KRBET_KRB_RES65,
+			"Reserved error message 65 (get_in_tkt)"
+
+	ec		KRBET_KRB_RES66,
+			"Reserved error message 66 (get_in_tkt)"
+
+	ec		KRBET_KRB_RES67,
+			"Reserved error message 67 (get_in_tkt)"
+
+	ec		KRBET_KRB_RES68,
+			"Reserved error message 68 (get_in_tkt)"
+
+	ec		KRBET_KRB_RES69,
+			"Reserved error message 69 (get_in_tkt)"
+
+	ec		KRBET_INTK_ERR,
+			"Other error (get_in_tkt)"
+
+	ec		KRBET_AD_NOTGT,
+			"Don't have Kerberos ticket-granting ticket (get_ad_tkt)"
+
+	ec		KRBET_KRB_RES72,
+			"Reserved error message 72 (get_ad_tkt)"
+
+	ec		KRBET_KRB_RES73,
+			"Reserved error message 73 (get_ad_tkt)"
+
+	ec		KRBET_KRB_RES74,
+			"Reserved error message 74 (get_ad_tkt)"
+
+	ec		KRBET_KRB_RES75,
+			"Reserved error message 75 (get_ad_tkt)"
+
+	ec		KRBET_NO_TKT_FIL,
+			"You have no tickets cached"
+
+	ec		KRBET_TKT_FIL_ACC,
+			"Couldn't access ticket file (tf_util)"
+
+	ec		KRBET_TKT_FIL_LCK,
+			"Couldn't lock ticket file (tf_util)"
+
+	ec		KRBET_TKT_FIL_FMT,
+			"Bad ticket file format (tf_util)"
+
+	ec		KRBET_TKT_FIL_INI,
+			"tf_init not called before reading from ticket file (tf_util)"
+
+	ec		KRBET_KNAME_FMT,
+			"Bad Kerberos name format (kname_parse)"
+
+	ec		KRBET_RES82,
+			"Reserved error message 82"
+
+	ec		KRBET_RES83,
+			"Reserved error message 83"
+
+	ec		KRBET_RES84,
+			"Reserved error message 84"
+
+	ec		KRBET_RES85,
+			"Reserved error message 85"
+
+	ec		KRBET_RES86,
+			"Reserved error message 86"
+
+	ec		KRBET_RES87,
+			"Reserved error message 87"
+
+	ec		KRBET_RES88,
+			"Reserved error message 88"
+
+	ec		KRBET_RES89,
+			"Reserved error message 89"
+
+	ec		KRBET_RES90,
+			"Reserved error message 90"
+
+	ec		KRBET_RES91,
+			"Reserved error message 91"
+
+	ec		KRBET_RES92,
+			"Reserved error message 92"
+
+	ec		KRBET_RES93,
+			"Reserved error message 93"
+
+	ec		KRBET_RES94,
+			"Reserved error message 94"
+
+	ec		KRBET_RES95,
+			"Reserved error message 95"
+
+	ec		KRBET_RES96,
+			"Reserved error message 96"
+
+	ec		KRBET_RES97,
+			"Reserved error message 97"
+
+	ec		KRBET_RES98,
+			"Reserved error message 98"
+
+	ec		KRBET_RES99,
+			"Reserved error message 99"
+
+	ec		KRBET_RES100,
+			"Reserved error message 100"
+
+	ec		KRBET_RES101,
+			"Reserved error message 101"
+
+	ec		KRBET_RES102,
+			"Reserved error message 102"
+
+	ec		KRBET_RES103,
+			"Reserved error message 103"
+
+	ec		KRBET_RES104,
+			"Reserved error message 104"
+
+	ec		KRBET_RES105,
+			"Reserved error message 105"
+
+	ec		KRBET_RES106,
+			"Reserved error message 106"
+
+	ec		KRBET_RES107,
+			"Reserved error message 107"
+
+	ec		KRBET_RES108,
+			"Reserved error message 108"
+
+	ec		KRBET_RES109,
+			"Reserved error message 109"
+
+	ec		KRBET_RES110,
+			"Reserved error message 110"
+
+	ec		KRBET_RES111,
+			"Reserved error message 111"
+
+	ec		KRBET_RES112,
+			"Reserved error message 112"
+
+	ec		KRBET_RES113,
+			"Reserved error message 113"
+
+	ec		KRBET_RES114,
+			"Reserved error message 114"
+
+	ec		KRBET_RES115,
+			"Reserved error message 115"
+
+	ec		KRBET_RES116,
+			"Reserved error message 116"
+
+	ec		KRBET_RES117,
+			"Reserved error message 117"
+
+	ec		KRBET_RES118,
+			"Reserved error message 118"
+
+	ec		KRBET_RES119,
+			"Reserved error message 119"
+
+	ec		KRBET_RES120,
+			"Reserved error message 120"
+
+	ec		KRBET_RES121,
+			"Reserved error message 121"
+
+	ec		KRBET_RES122,
+			"Reserved error message 122"
+
+	ec		KRBET_RES123,
+			"Reserved error message 123"
+
+	ec		KRBET_RES124,
+			"Reserved error message 124"
+
+	ec		KRBET_RES125,
+			"Reserved error message 125"
+
+	ec		KRBET_RES126,
+			"Reserved error message 126"
+
+	ec		KRBET_RES127,
+			"Reserved error message 127"
+
+	ec		KRBET_RES128,
+			"Reserved error message 128"
+
+	ec		KRBET_RES129,
+			"Reserved error message 129"
+
+	ec		KRBET_RES130,
+			"Reserved error message 130"
+
+	ec		KRBET_RES131,
+			"Reserved error message 131"
+
+	ec		KRBET_RES132,
+			"Reserved error message 132"
+
+	ec		KRBET_RES133,
+			"Reserved error message 133"
+
+	ec		KRBET_RES134,
+			"Reserved error message 134"
+
+	ec		KRBET_RES135,
+			"Reserved error message 135"
+
+	ec		KRBET_RES136,
+			"Reserved error message 136"
+
+	ec		KRBET_RES137,
+			"Reserved error message 137"
+
+	ec		KRBET_RES138,
+			"Reserved error message 138"
+
+	ec		KRBET_RES139,
+			"Reserved error message 139"
+
+	ec		KRBET_RES140,
+			"Reserved error message 140"
+
+	ec		KRBET_RES141,
+			"Reserved error message 141"
+
+	ec		KRBET_RES142,
+			"Reserved error message 142"
+
+	ec		KRBET_RES143,
+			"Reserved error message 143"
+
+	ec		KRBET_RES144,
+			"Reserved error message 144"
+
+	ec		KRBET_RES145,
+			"Reserved error message 145"
+
+	ec		KRBET_RES146,
+			"Reserved error message 146"
+
+	ec		KRBET_RES147,
+			"Reserved error message 147"
+
+	ec		KRBET_RES148,
+			"Reserved error message 148"
+
+	ec		KRBET_RES149,
+			"Reserved error message 149"
+
+	ec		KRBET_RES150,
+			"Reserved error message 150"
+
+	ec		KRBET_RES151,
+			"Reserved error message 151"
+
+	ec		KRBET_RES152,
+			"Reserved error message 152"
+
+	ec		KRBET_RES153,
+			"Reserved error message 153"
+
+	ec		KRBET_RES154,
+			"Reserved error message 154"
+
+	ec		KRBET_RES155,
+			"Reserved error message 155"
+
+	ec		KRBET_RES156,
+			"Reserved error message 156"
+
+	ec		KRBET_RES157,
+			"Reserved error message 157"
+
+	ec		KRBET_RES158,
+			"Reserved error message 158"
+
+	ec		KRBET_RES159,
+			"Reserved error message 159"
+
+	ec		KRBET_RES160,
+			"Reserved error message 160"
+
+	ec		KRBET_RES161,
+			"Reserved error message 161"
+
+	ec		KRBET_RES162,
+			"Reserved error message 162"
+
+	ec		KRBET_RES163,
+			"Reserved error message 163"
+
+	ec		KRBET_RES164,
+			"Reserved error message 164"
+
+	ec		KRBET_RES165,
+			"Reserved error message 165"
+
+	ec		KRBET_RES166,
+			"Reserved error message 166"
+
+	ec		KRBET_RES167,
+			"Reserved error message 167"
+
+	ec		KRBET_RES168,
+			"Reserved error message 168"
+
+	ec		KRBET_RES169,
+			"Reserved error message 169"
+
+	ec		KRBET_RES170,
+			"Reserved error message 170"
+
+	ec		KRBET_RES171,
+			"Reserved error message 171"
+
+	ec		KRBET_RES172,
+			"Reserved error message 172"
+
+	ec		KRBET_RES173,
+			"Reserved error message 173"
+
+	ec		KRBET_RES174,
+			"Reserved error message 174"
+
+	ec		KRBET_RES175,
+			"Reserved error message 175"
+
+	ec		KRBET_RES176,
+			"Reserved error message 176"
+
+	ec		KRBET_RES177,
+			"Reserved error message 177"
+
+	ec		KRBET_RES178,
+			"Reserved error message 178"
+
+	ec		KRBET_RES179,
+			"Reserved error message 179"
+
+	ec		KRBET_RES180,
+			"Reserved error message 180"
+
+	ec		KRBET_RES181,
+			"Reserved error message 181"
+
+	ec		KRBET_RES182,
+			"Reserved error message 182"
+
+	ec		KRBET_RES183,
+			"Reserved error message 183"
+
+	ec		KRBET_RES184,
+			"Reserved error message 184"
+
+	ec		KRBET_RES185,
+			"Reserved error message 185"
+
+	ec		KRBET_RES186,
+			"Reserved error message 186"
+
+	ec		KRBET_RES187,
+			"Reserved error message 187"
+
+	ec		KRBET_RES188,
+			"Reserved error message 188"
+
+	ec		KRBET_RES189,
+			"Reserved error message 189"
+
+	ec		KRBET_RES190,
+			"Reserved error message 190"
+
+	ec		KRBET_RES191,
+			"Reserved error message 191"
+
+	ec		KRBET_RES192,
+			"Reserved error message 192"
+
+	ec		KRBET_RES193,
+			"Reserved error message 193"
+
+	ec		KRBET_RES194,
+			"Reserved error message 194"
+
+	ec		KRBET_RES195,
+			"Reserved error message 195"
+
+	ec		KRBET_RES196,
+			"Reserved error message 196"
+
+	ec		KRBET_RES197,
+			"Reserved error message 197"
+
+	ec		KRBET_RES198,
+			"Reserved error message 198"
+
+	ec		KRBET_RES199,
+			"Reserved error message 199"
+
+	ec		KRBET_RES200,
+			"Reserved error message 200"
+
+	ec		KRBET_RES201,
+			"Reserved error message 201"
+
+	ec		KRBET_RES202,
+			"Reserved error message 202"
+
+	ec		KRBET_RES203,
+			"Reserved error message 203"
+
+	ec		KRBET_RES204,
+			"Reserved error message 204"
+
+	ec		KRBET_RES205,
+			"Reserved error message 205"
+
+	ec		KRBET_RES206,
+			"Reserved error message 206"
+
+	ec		KRBET_RES207,
+			"Reserved error message 207"
+
+	ec		KRBET_RES208,
+			"Reserved error message 208"
+
+	ec		KRBET_RES209,
+			"Reserved error message 209"
+
+	ec		KRBET_RES210,
+			"Reserved error message 210"
+
+	ec		KRBET_RES211,
+			"Reserved error message 211"
+
+	ec		KRBET_RES212,
+			"Reserved error message 212"
+
+	ec		KRBET_RES213,
+			"Reserved error message 213"
+
+	ec		KRBET_RES214,
+			"Reserved error message 214"
+
+	ec		KRBET_RES215,
+			"Reserved error message 215"
+
+	ec		KRBET_RES216,
+			"Reserved error message 216"
+
+	ec		KRBET_RES217,
+			"Reserved error message 217"
+
+	ec		KRBET_RES218,
+			"Reserved error message 218"
+
+	ec		KRBET_RES219,
+			"Reserved error message 219"
+
+	ec		KRBET_RES220,
+			"Reserved error message 220"
+
+	ec		KRBET_RES221,
+			"Reserved error message 221"
+
+	ec		KRBET_RES222,
+			"Reserved error message 222"
+
+	ec		KRBET_RES223,
+			"Reserved error message 223"
+
+	ec		KRBET_RES224,
+			"Reserved error message 224"
+
+	ec		KRBET_RES225,
+			"Reserved error message 225"
+
+	ec		KRBET_RES226,
+			"Reserved error message 226"
+
+	ec		KRBET_RES227,
+			"Reserved error message 227"
+
+	ec		KRBET_RES228,
+			"Reserved error message 228"
+
+	ec		KRBET_RES229,
+			"Reserved error message 229"
+
+	ec		KRBET_RES230,
+			"Reserved error message 230"
+
+	ec		KRBET_RES231,
+			"Reserved error message 231"
+
+	ec		KRBET_RES232,
+			"Reserved error message 232"
+
+	ec		KRBET_RES233,
+			"Reserved error message 233"
+
+	ec		KRBET_RES234,
+			"Reserved error message 234"
+
+	ec		KRBET_RES235,
+			"Reserved error message 235"
+
+	ec		KRBET_RES236,
+			"Reserved error message 236"
+
+	ec		KRBET_RES237,
+			"Reserved error message 237"
+
+	ec		KRBET_RES238,
+			"Reserved error message 238"
+
+	ec		KRBET_RES239,
+			"Reserved error message 239"
+
+	ec		KRBET_RES240,
+			"Reserved error message 240"
+
+	ec		KRBET_RES241,
+			"Reserved error message 241"
+
+	ec		KRBET_RES242,
+			"Reserved error message 242"
+
+	ec		KRBET_RES243,
+			"Reserved error message 243"
+
+	ec		KRBET_RES244,
+			"Reserved error message 244"
+
+	ec		KRBET_RES245,
+			"Reserved error message 245"
+
+	ec		KRBET_RES246,
+			"Reserved error message 246"
+
+	ec		KRBET_RES247,
+			"Reserved error message 247"
+
+	ec		KRBET_RES248,
+			"Reserved error message 248"
+
+	ec		KRBET_RES249,
+			"Reserved error message 249"
+
+	ec		KRBET_RES250,
+			"Reserved error message 250"
+
+	ec		KRBET_RES251,
+			"Reserved error message 251"
+
+	ec		KRBET_RES252,
+			"Reserved error message 252"
+
+	ec		KRBET_RES253,
+			"Reserved error message 253"
+
+	ec		KRBET_RES254,
+			"Reserved error message 254"
+
+	ec		KRBET_KFAILURE,
+			"Generic kerberos error (kfailure)"
+	end
diff --git a/mechglue/src/lib/krb4/kuserok.c b/mechglue/src/lib/krb4/kuserok.c
new file mode 100644
index 000000000..e2f673001
--- /dev/null
+++ b/mechglue/src/lib/krb4/kuserok.c
@@ -0,0 +1,258 @@
+/*
+ * lib/krb4/kuserok.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * kuserok: check if a kerberos principal has
+ * access to a local account
+ */
+
+#include "krb.h"
+
+#if !defined(_WIN32)
+
+#include <stdio.h>
+#include <pwd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <string.h>
+#include "krb5/autoconf.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef __SCO__
+/* just for F_OK for sco */
+#include <sys/unistd.h>
+#endif
+
+#ifndef HAVE_SETEUID
+#ifdef HAVE_SETRESUID
+#define seteuid(e) setresuid(-1,e,-1)
+#define setegid(e) setresgid(-1,e,-1)
+#endif
+#endif
+
+#define OK 0
+#define NOTOK 1
+#define MAX_USERNAME 10
+
+/*
+ * Given a Kerberos principal "kdata", and a local username "luser",
+ * determine whether user is authorized to login according to the
+ * authorization file ("~luser/.klogin" by default).  Returns OK
+ * if authorized, NOTOK if not authorized.
+ *
+ * If there is no account for "luser" on the local machine, returns
+ * NOTOK.  If there is no authorization file, and the given Kerberos
+ * name "kdata" translates to the same name as "luser" (using
+ * krb_kntoln()), returns OK.  Otherwise, if the authorization file
+ * can't be accessed, returns NOTOK.  Otherwise, the file is read for
+ * a matching principal name, instance, and realm.  If one is found,
+ * returns OK, if none is found, returns NOTOK.
+ *
+ * The file entries are in the format:
+ *
+ *	name.instance@realm
+ *
+ * one entry per line.
+ *
+ * The ATHENA_COMPAT code supports old-style Athena ~luser/.klogin
+ * file entries.  See the file "kparse.c".
+ */
+
+#if defined(ATHENA_COMPAT) || defined(ATHENA_OLD_KLOGIN)
+
+#include <kparse.h>
+
+/*
+ * The parmtable defines the keywords we will recognize with their
+ * default values, and keeps a pointer to the found value.  The found
+ * value should be filled in with strsave(), since FreeParameterSet()
+ * will release memory for all non-NULL found strings. 
+ *
+*** NOTE WELL! *** 
+ *
+ * The table below is very nice, but we cannot hard-code a default for the
+ * realm: we have to get the realm via krb_get_lrealm().  Even though the
+ * default shows as "from krb_get_lrealm, below", it gets changed in
+ * kuserok to whatever krb_get_lrealm() tells us.  That code assumes that
+ * the realm will be the entry number in the table below, so if you
+ * change the order of the entries below, you have to change the
+ * #definition of REALM_SCRIPT to reflect it. 
+ */
+#define REALM_SUBSCRIPT 1
+parmtable kparm[] = {
+
+/* keyword	default 			found value     */
+{"user",	"", 				(char *) NULL},
+{"realm",	"see krb_get_lrealm, below",	(char *) NULL},
+{"instance",	 "",				(char *) NULL},
+};
+#define KPARMS kparm,PARMCOUNT(kparm)
+#endif
+
+int KRB5_CALLCONV
+kuserok(kdata, luser)
+    AUTH_DAT	*kdata;
+    char	*luser;
+{
+    struct stat sbuf;
+    struct passwd *pwd;
+    char pbuf[MAXPATHLEN];
+    int isok = NOTOK, rc;
+    FILE *fp;
+    char kuser[MAX_USERNAME];
+    char principal[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
+    char linebuf[BUFSIZ];
+    char *newline;
+    int gobble;
+#if defined(ATHENA_COMPAT) || defined(ATHENA_OLD_KLOGIN)
+    char local_realm[REALM_SZ];
+#endif
+
+    /* no account => no access */
+    if ((pwd = getpwnam(luser)) == NULL) {
+	return(NOTOK);
+    }
+    if (strlen (pwd->pw_dir) + sizeof ("/.klogin") >= sizeof (pbuf))
+	return NOTOK;
+    (void) strncpy(pbuf, pwd->pw_dir, sizeof(pbuf) - 1);
+    pbuf[sizeof(pbuf) - 1] = '\0';
+    (void) strncat(pbuf, "/.klogin", sizeof(pbuf) - 1 - strlen(pbuf));
+
+    if (access(pbuf, F_OK)) {	 /* not accessible */
+	/*
+	 * if he's trying to log in as himself, and there is no .klogin file,
+	 * let him.  To find out, call
+	 * krb_kntoln to convert the triple in kdata to a name which we can
+	 * string compare. 
+	 */
+	if (!krb_kntoln(kdata, kuser) && (strcmp(kuser, luser) == 0)) {
+	    return(OK);
+	}
+    }
+    /* open ~/.klogin */
+    if ((fp = fopen(pbuf, "r")) == NULL) {
+        /* however, root might not have enough access, so temporarily switch
+	 * over to the user's uid, try the access again, and switch back
+	 */
+        if(getuid() == 0) {
+	  uid_t old_euid = geteuid();
+	  seteuid(pwd->pw_uid);
+	  fp = fopen(pbuf, "r");
+	  seteuid(old_euid);	  
+	  if ((fp) == NULL) {
+	    return(NOTOK);
+	  }
+	} else {
+	  return(NOTOK);
+	}
+    }
+    /*
+     * security:  if the user does not own his own .klogin file,
+     * do not grant access
+     */
+    if (fstat(fileno(fp), &sbuf)) {
+	fclose(fp);
+	return(NOTOK);
+    }
+    /*
+     * however, allow root to own the .klogin file, to allow creative
+     * access management schemes.
+     */
+    if (sbuf.st_uid && (sbuf.st_uid != pwd->pw_uid)) {
+	fclose(fp);
+	return(NOTOK);
+    }
+
+#if defined(ATHENA_COMPAT) || defined(ATHENA_OLD_KLOGIN)
+    /* Accept old-style .klogin files */
+
+    /*
+     * change the default realm from the hard-coded value to the
+     * accepted realm that Kerberos specifies. 
+     */
+    rc = krb_get_lrealm(local_realm, 1);
+    if (rc == KSUCCESS)
+	kparm[REALM_SUBSCRIPT].defvalue = local_realm;
+    else
+	return (rc);
+
+    /* check each line */
+    while ((isok != OK) && (rc = fGetParameterSet(fp, KPARMS)) != PS_EOF) {
+	switch (rc) {
+	case PS_BAD_KEYWORD:
+	case PS_SYNTAX:
+	    while (((gobble = fGetChar(fp)) != EOF) && (gobble != '\n'));
+	    break;
+
+	case PS_OKAY:
+	    isok = (ParmCompare(KPARMS, "user", kdata->pname) ||
+		    ParmCompare(KPARMS, "instance", kdata->pinst) ||
+		    ParmCompare(KPARMS, "realm", kdata->prealm));
+	    break;
+
+	default:
+	    break;
+	}
+	FreeParameterSet(kparm, PARMCOUNT(kparm));
+    }
+    /* reset the stream for parsing new-style names, if necessary */
+    rewind(fp);
+#endif
+
+    /* check each line */
+    while ((isok != OK) && (fgets(linebuf, BUFSIZ, fp) != NULL)) {
+	/* null-terminate the input string */
+	linebuf[BUFSIZ-1] = '\0';
+	newline = NULL;
+	/* nuke the newline if it exists */
+	if ((newline = strchr(linebuf, '\n')))
+	    *newline = '\0';
+
+	/* Default the fields (default realm is filled in later) */
+	principal[0] = '\0';
+	inst[0] = '\0';
+	realm[0] = '\0';
+	rc = kname_parse(principal, inst, realm, linebuf);
+	if (rc == KSUCCESS) {
+	    if (realm[0] == '\0') {
+		rc = krb_get_lrealm(realm, 1);
+		if (rc != KSUCCESS)
+		    goto nextline;
+	    }
+	    isok = (strncmp(kdata->pname, principal, ANAME_SZ) ||
+		    strncmp(kdata->pinst, inst, INST_SZ) ||
+		    strncmp(kdata->prealm, realm, REALM_SZ));
+	}
+    nextline:
+	/* clean up the rest of the line if necessary */
+	if (!newline)
+	    while (((gobble = getc(fp)) != EOF) && gobble != '\n');
+    }
+    fclose(fp);
+    return(isok);
+}
+
+#endif
diff --git a/mechglue/src/lib/krb4/libkrb4.exports b/mechglue/src/lib/krb4/libkrb4.exports
new file mode 100644
index 000000000..ff35a4684
--- /dev/null
+++ b/mechglue/src/lib/krb4/libkrb4.exports
@@ -0,0 +1,165 @@
+FreeParameterSet
+ParmCompare
+__krb_sendauth_hidden_tkt_len
+ad_print
+afs_passwd_to_key
+cr_err_reply
+create_auth_reply
+create_ciph
+decomp_ticket
+decomp_tkt_krb5
+dest_tkt
+et_kadm_error_table
+et_krb_error_table
+fGetChar
+fGetKeywordValue
+fGetLiteral
+fGetParameterSet
+fGetToken
+fUngetChar
+fgetst
+get_ad_tkt
+get_pw_tkt
+get_service_key
+getst
+in_tkt
+initialize_kadm_error_table
+initialize_krb_error_table
+k_gethostname
+k_isinst
+k_isname
+k_isrealm
+kadm_build_field_header
+kadm_check_field_header
+kadm_cli_conn
+kadm_cli_disconn
+kadm_cli_keyd
+kadm_cli_out
+kadm_cli_send
+kadm_init_link
+kadm_stream_to_vals
+kadm_stv_char
+kadm_stv_long
+kadm_stv_short
+kadm_stv_string
+kadm_vals_to_stream
+kadm_vts_char
+kadm_vts_long
+kadm_vts_short
+kadm_vts_string
+klog
+kname_parse
+kname_unparse
+krb4int_address_less
+krb4int_et_fini
+krb4int_et_init
+krb4int_save_credentials_addr
+krb4int_send_to_kdc_addr
+krb4int_strnlen
+krb4prot_decode_ciph
+krb4prot_decode_error
+krb4prot_decode_header
+krb4prot_decode_kdc_reply
+krb4prot_decode_kdc_request
+krb4prot_decode_naminstrlm
+krb4prot_encode_apreq
+krb4prot_encode_authent
+krb4prot_encode_ciph
+krb4prot_encode_err_reply
+krb4prot_encode_kdc_reply
+krb4prot_encode_kdc_request
+krb4prot_encode_naminstrlm
+krb4prot_encode_tkt
+krb54_get_service_keyblock
+krb5__krb4_context
+krb5_passwd_to_key
+krb__get_cnffile
+krb__get_realmsfile
+krb__get_srvtabname
+krb_ap_req_debug
+krb_change_password
+krb_check_auth
+krb_clear_key_krb5
+krb_cr_tkt_krb5
+krb_create_ticket
+krb_debug
+krb_end_session
+krb_err_txt
+krb_free_preauth
+krb_get_admhst
+krb_get_cred
+krb_get_default_user
+krb_get_err_text
+krb_get_in_tkt
+krb_get_in_tkt_creds
+krb_get_in_tkt_preauth
+krb_get_in_tkt_preauth_creds
+krb_get_keyprocs
+krb_get_kpasswdhst
+krb_get_krbhst
+krb_get_lrealm
+krb_get_phost
+krb_get_profile
+krb_get_pw_in_tkt
+krb_get_pw_in_tkt_creds
+krb_get_pw_in_tkt_preauth
+krb_get_svc_in_tkt
+krb_get_svc_in_tkt_preauth
+krb_get_tf_fullname
+krb_get_tf_realm
+krb_get_ticket_for_service
+krb_ignore_ip_address
+krb_in_tkt
+krb_kntoln
+krb_life_to_time
+krb_log
+krb_mk_auth
+krb_mk_err
+krb_mk_preauth
+krb_mk_priv
+krb_mk_req
+krb_mk_req_creds
+krb_mk_safe
+krb_net_rd_sendauth
+krb_net_read
+krb_net_write
+krb_rd_err
+krb_rd_preauth
+krb_rd_priv
+krb_rd_req
+krb_rd_req_int
+krb_rd_safe
+krb_realmofhost
+krb_recvauth
+krb_save_credentials
+krb_sendauth
+krb_set_default_user
+krb_set_key
+krb_set_key_krb5
+krb_set_lifetime
+krb_set_logfile
+krb_set_tkt_string
+krb_start_session
+krb_stime
+krb_svc_init
+krb_svc_init_preauth
+krb_time_to_life
+kset_logfile
+kuserok
+mit_passwd_to_key
+month_sname
+pkt_cipher
+pkt_clen
+private_msg_ver
+put_svc_key
+read_service_key
+send_to_kdc
+swap_bytes
+tf_close
+tf_get_cred
+tf_get_pinst
+tf_get_pname
+tf_init
+tf_save_cred
+tkt_string
+unix_time_gmt_unixsec
diff --git a/mechglue/src/lib/krb4/lifetime.c b/mechglue/src/lib/krb4/lifetime.c
new file mode 100644
index 000000000..826e090df
--- /dev/null
+++ b/mechglue/src/lib/krb4/lifetime.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000, 2001, 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "krb.h"
+#include "k5-int.h"
+
+/*
+ * krb_life_to_time
+ *
+ * Given a start date and a lifetime byte, compute the expiration
+ * date.
+ */
+KRB4_32 KRB5_CALLCONV
+krb_life_to_time(KRB4_32 start, int life)
+{
+    krb5int_access k5internals;
+
+    if (krb5int_accessor(&k5internals, KRB5INT_ACCESS_VERSION)
+	|| k5internals.krb_life_to_time == NULL)
+	return start;
+    return k5internals.krb_life_to_time(start, life);
+}
+
+/*
+ * krb_time_to_life
+ *
+ * Given the start date and the end date, compute the lifetime byte.
+ * Round up, since we can adjust the start date backwards if we are
+ * issuing the ticket to cause it to expire at the correct time.
+ */
+int KRB5_CALLCONV
+krb_time_to_life(KRB4_32 start, KRB4_32 end)
+{
+    krb5int_access k5internals;
+
+    if (krb5int_accessor(&k5internals, KRB5INT_ACCESS_VERSION)
+	|| k5internals.krb_time_to_life == NULL)
+	return 0;
+    return k5internals.krb_time_to_life(start, end);
+}
diff --git a/mechglue/src/lib/krb4/log.c b/mechglue/src/lib/krb4/log.c
new file mode 100644
index 000000000..d7447aebb
--- /dev/null
+++ b/mechglue/src/lib/krb4/log.c
@@ -0,0 +1,148 @@
+/*
+ * lib/krb4/log.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifdef KRB_CRYPT_DEBUG
+/* This file used to contain log() and set_logfile(). If you define 
+   KRB_CRYPT_DEBUG, you'll need to define those to point to krb_log and
+   krb_set_logfile, or change all the invokers. */
+#endif
+
+#include "krb.h"
+#include "krb5/autoconf.h"
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#if !defined(VMS) && !defined(_WIN32)
+#include <sys/time.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "krb4int.h"
+#include <klog.h>
+
+static char *log_name = KRBLOG;
+#if 0
+static is_open;
+#endif
+
+/*
+ * This file contains three logging routines: set_logfile()
+ * to determine the file that log entries should be written to;
+ * and log() and new_log() to write log entries to the file.
+ */
+
+/*
+ * krb_log() is used to add entries to the logfile (see krb_set_logfile()
+ * below).  Note that it is probably not portable since it makes
+ * assumptions about what the compiler will do when it is called
+ * with less than the correct number of arguments which is the
+ * way it is usually called.
+ *
+ * The log entry consists of a timestamp and the given arguments
+ * printed according to the given "format".
+ *
+ * The log file is opened and closed for each log entry.
+ *
+ * The return value is undefined.
+ */
+
+void krb_log(const char *format,...)
+{
+    FILE *logfile;
+    time_t now;
+    struct tm *tm;
+    va_list args;
+
+    va_start(args, format);
+
+    if ((logfile = fopen(log_name,"a")) != NULL) {
+	(void) time(&now);
+	tm = localtime(&now);
+
+	fprintf(logfile,"%2d-%s-%d %02d:%02d:%02d ",tm->tm_mday,
+		month_sname(tm->tm_mon + 1),1900+tm->tm_year,
+		tm->tm_hour, tm->tm_min, tm->tm_sec);
+	vfprintf(logfile,format,args);
+	fprintf(logfile,"\n");
+	(void) fclose(logfile);
+    }
+    va_end(args);
+    return;
+}
+
+/*
+ * krb_set_logfile() changes the name of the file to which
+ * messages are logged.  If krb_set_logfile() is not called,
+ * the logfile defaults to KRBLOG, defined in "krb.h".
+ */
+
+void
+krb_set_logfile(filename)
+    char *filename;
+{
+    log_name = filename;
+#if 0
+    is_open = 0;
+#endif
+}
+
+#if 0
+/*
+ * new_log() appends a log entry containing the give time "t" and the
+ * string "string" to the logfile (see set_logfile() above).  The file
+ * is opened once and left open.  The routine returns 1 on failure, 0
+ * on success.
+ */
+
+krb_new_log(t,string)
+    long t;
+    char *string;
+{
+    static FILE *logfile;
+
+    struct tm *tm;
+
+    if (!is_open) {
+        if ((logfile = fopen(log_name,"a")) == NULL) return(1);
+        is_open = 1;
+    }
+
+    if (t) {
+        tm = localtime(&t);
+
+        fprintf(logfile,"\n%2d-%s-%d %02d:%02d:%02d  %s",tm->tm_mday,
+                month_sname(tm->tm_mon + 1),1900+tm->tm_year,
+                tm->tm_hour, tm->tm_min, tm->tm_sec, string);
+    }
+    else {
+        fprintf(logfile,"\n%20s%s","",string);
+    }
+
+    (void) fflush(logfile);
+    return(0);
+}
+#endif
diff --git a/mechglue/src/lib/krb4/mac_glue.c b/mechglue/src/lib/krb4/mac_glue.c
new file mode 100644
index 000000000..77d11c2cc
--- /dev/null
+++ b/mechglue/src/lib/krb4/mac_glue.c
@@ -0,0 +1,48 @@
+/*
+ * mac_glue.c
+ *
+ * Copyright 1989 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Macintosh ooperating system interface for Kerberos.
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+
+/* Mac Cincludes */
+#include <string.h>
+#include <stddef.h>
+
+/* FIXME!  swab should be swapping, but for initial test, don't bother.  */
+
+void swab(char *from, char *to, int nbytes) {}
+
+mymemset( void *s, register int c, register size_t n )
+{
+	// written because memset doesn't work in think C (ARGGGG!!!!!!)
+	register char *j = s;
+	while( n-- )
+		*j++ = c;
+}
+
+int INTERFACE
+krb_start_session (x)
+	char *x;
+{
+	return KSUCCESS;
+}
+
+int INTERFACE
+krb_end_session (x)
+	char *x;
+{
+	return KSUCCESS;
+}
+
+/* FIXME:  These stubs should go away.  */
+int read() {return 0;}
+int write () {return 0;}
+int krb_ignore_ip_address = 0;
diff --git a/mechglue/src/lib/krb4/mac_store.c b/mechglue/src/lib/krb4/mac_store.c
new file mode 100644
index 000000000..262ba58bd
--- /dev/null
+++ b/mechglue/src/lib/krb4/mac_store.c
@@ -0,0 +1,731 @@
+/*
+ * mac_store.c
+ *
+ * Kerberos configuration store
+ * Originally coded by Tim Miller / Brown University as KRB_Store.c
+ * Mods 1/92 By Peter Bosanko
+ *
+ * Modified May-June 1994 by Julia Menapace and John Gilmore
+ * of Cygnus Support.
+ *
+ * This file incorporates replacements for the Unix files
+ * g_admhst.c, g_krbhst.c, realmofhost.c, and g_krbrlm.c.
+ */
+
+/* Headers from in_tkt.c, merged in by gnu FIXME */
+#include <types.h>
+
+/* Headers from store.c from KClient */
+#include <string.h>
+#include <traps.h>
+#include <gestaltEqu.h>
+#include <Folders.h>
+#include <Resources.h>
+#include <Memory.h>
+#include <Files.h>
+
+#include "krb.h"
+#include "mac_store.h"	/* includes memcache.h */
+#include "krb_driver.h"
+
+#define	prefname	"\pKerberos Client Preferences"
+const	OSType	preftype = 'PREF';
+const	OSType	prefcrea	= 'krbL';
+const	OSType	unametype = 'UNam';
+const	OSType	lrealmtype = 'LRlm';
+const	OSType	templatetype = 'TMPL';
+const	OSType	realmmaptype = 'RMap';
+const	OSType	servermaptype = 'SMap';
+#define kNumTemplates 4
+#define kFirstTemplate 128
+#define kMapResNum 1024
+
+
+/* Lower level routines and data structures  */
+
+
+/* Need to check this in each high-level routine, and call init_store
+   if not set.  */
+static	int		initialized_store = 0;		
+
+static	char		fLRealm[REALM_SZ] = "";
+static	Handle		fRealmMap = 0;
+static	Handle		fServerMap = 0;
+static	short		fPrefVRefNum;
+static	long		fPrefDirID;
+OSErr			fConstructErr = -1;
+
+/* Current default user name (for prompts, etc).  */
+
+static char gUserName[MAX_K_NAME_SZ]; 
+
+
+/* Routines for dealing with the realm versus host database */
+
+/*
+ * krb_get_admhst
+ *
+ * Given a Kerberos realm, find a host on which the Kerberos database
+ * administration server can be found.
+ *
+ * krb_get_admhst takes a pointer to be filled in, a pointer to the name
+ * of the realm for which a server is desired, and an integer n, and
+ * returns (in h) the nth administrative host entry from the configuration
+ * file (KRB_CONF, defined in "krb.h") associated with the specified realm.
+ * If ATHENA_CONF_FALLBACK is defined, also look in old location.
+ *
+ * On error, get_admhst returns KFAILURE. If all goes well, the routine
+ * returns KSUCCESS.
+ *
+ * For the format of the KRB_CONF file, see comments describing the routine
+ * krb_get_krbhst().
+ *
+ * This is a temporary hack to allow us to find the nearest system running
+ * a Kerberos admin server.  In the long run, this functionality will be
+ * provided by a nameserver.  (HAH!)
+ */
+int
+krb_get_admhst (h, r, n)
+	char *h;
+	char *r;
+	int n;
+{
+	if (!initialized_store) 
+		if (init_store())
+			return KFAILURE;
+	if(GetNthServer(n, r, 1, h)) return KFAILURE;
+	else return KSUCCESS;
+}
+
+/*
+ * Given a Kerberos realm, find a host on which the Kerberos authenti-
+ * cation server can be found.
+ *
+ * krb_get_krbhst takes a pointer to be filled in, a pointer to the name
+ * of the realm for which a server is desired, and an integer, n, and
+ * returns (in h) the nth entry from the configuration information
+ * associated with the specified realm.
+ *
+ * If no info is found, krb_get_krbhst returns KFAILURE.  If n=1 and the
+ * configuration file does not exist, krb_get_krbhst will return KRB_HOST
+ * (defined in "krb.h").  If all goes well, the routine returnes
+ * KSUCCESS.
+ *
+ * This is a temporary hack to allow us to find the nearest system running
+ * kerberos.  In the long run, this functionality will be provided by a
+ * nameserver.  (AH SO!)
+ */
+int	krb_get_krbhst(h, r, n)
+	char *h;
+	char *r;
+	int n;
+{
+	if (!initialized_store) 
+		if (init_store())
+			return KFAILURE;
+	if (GetNthServer(n, r, 0, h)) return KFAILURE;
+	else return KSUCCESS;
+}
+
+
+/*
+ * krb_get_lrealm takes a pointer to a string, and a number, n.  It fills
+ * in the string, r, with the name of the local realm specified in
+ * the local Kerberos configuration.
+ * It returns 0 (KSUCCESS) on success, and KFAILURE on failure.  If the
+ * config info does not exist, and if n=1, a successful return will occur
+ * with r = KRB_REALM (also defined in "krb.h").  [FIXME -- not implem.]
+ *
+ * NOTE: for archaic & compatibility reasons, this routine will only return
+ * valid results when n = 1.
+ */
+
+int	krb_get_lrealm(char *r, int n)
+{
+	if (!initialized_store) 
+		if (init_store())
+			return KFAILURE;
+	if (n != 1)
+		return KFAILURE;
+	if (GetLocalRealm(r))
+		return KFAILURE;
+	return KSUCCESS;
+}
+
+
+/*
+ * krb_realmofhost.
+ * Given a fully-qualified domain-style primary host name,
+ * return the name of the Kerberos realm for the host.
+ * If the hostname contains no discernable domain, or an error occurs,
+ * return the local realm name, as supplied by get_krbrlm().
+ * If the hostname contains a domain, but no translation is found,
+ * the hostname's domain is converted to upper-case and returned.
+ *
+ * In the database,
+ * domain_name should be of the form .XXX.YYY (e.g. .LCS.MIT.EDU)
+ * host names should be in the usual form (e.g. FOO.BAR.BAZ)
+ */
+
+char *krb_realmofhost(char *host)
+{
+	static char	realm[REALM_SZ];
+	
+	if (!initialized_store) 
+		if (init_store())
+			return 0;
+
+	/* Store realm string through REALM pointer arg */
+	GetRealm(host, realm);	
+	return realm;
+}
+
+
+char * INTERFACE
+krb_get_default_user (void)
+{
+    if (!initialized_store)
+	if (init_store())
+	    return 0;
+
+    return gUserName;
+}
+
+
+int INTERFACE
+krb_set_default_user (uName)
+    char* uName;
+{
+    if (!initialized_store)
+	if (init_store())
+	    return KFAILURE;
+
+    if( strcmp( gUserName, uName ) != 0 ) {
+	strcpy( gUserName, uName );
+	if (WriteUser() != 0)
+	    return KFAILURE;
+    }
+    return KSUCCESS;
+}
+
+
+
+void GetPrefsFolder(short *vRefNumP, long *dirIDP)
+{
+	Boolean hasFolderMgr = false;
+	long feature;
+/*	
+	FIXME Error:   Ô_GestaltDispatchÕ has not been declared - not needed now? - jcm
+	if (TrapAvailable(_GestaltDispatch)) 
+*/
+	if (Gestalt(gestaltFindFolderAttr, &feature) == noErr) hasFolderMgr = true;
+	if (!hasFolderMgr) {
+		GetSystemFolder(vRefNumP, dirIDP);
+		return;
+		}
+	else {
+		if (FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, vRefNumP, dirIDP) != noErr) {
+			*vRefNumP = 0;
+			*dirIDP = 0;
+			}
+		}
+	}
+
+
+/*
+    init_store() is used to initialize the config store.  It opens the
+    driver preferences file and reads the local realm, user name, and
+    realm and server maps from resources in the prefs file into driver
+    storage.  If the preferences file doesn't exist, init_store creates it.
+    Returns 0 on success, or 1 if something goes wrong.
+ */
+int
+init_store()
+{
+	short refnum;
+	Handle	temp;
+	int hasPrefFile;
+	
+	/* If a prefs file exists, load from it, otherwise load defaults from self */
+	GetPrefsFolder(&fPrefVRefNum, &fPrefDirID);
+	refnum = HOpenResFile(fPrefVRefNum, fPrefDirID, (unsigned char *)prefname, fsRdPerm);
+	hasPrefFile = (refnum != -1); 		// did we open it?
+	
+	temp = GetResource(lrealmtype, kMapResNum);
+	if(ResError() || !temp) {
+		if(refnum != -1) CloseResFile(refnum);
+		fConstructErr = cKrbCorruptedFile;
+		return 1;
+	}
+	strcpy(fLRealm, *temp);
+	ReleaseResource(temp);
+	
+	temp = GetResource(unametype, kMapResNum);
+	if(ResError() || !temp) {
+		if(refnum != -1) CloseResFile(refnum);
+		fConstructErr = cKrbCorruptedFile;
+		return 1;
+	}
+	strcpy(gUserName, *temp);
+	ReleaseResource(temp);
+	
+	fRealmMap = GetResource(realmmaptype, kMapResNum);
+	if(ResError() || !fRealmMap) {
+		if(refnum != -1) CloseResFile(refnum);
+		*fLRealm = 0;
+		fConstructErr = cKrbCorruptedFile;
+		return 1;
+	}
+	DetachResource(fRealmMap);
+	
+	fServerMap = GetResource(servermaptype, kMapResNum);
+	if(ResError() || !fServerMap) {
+		if(refnum != -1) CloseResFile(refnum);
+		*fLRealm = 0;
+		DisposeHandle(fRealmMap);
+		fRealmMap = 0;
+		fConstructErr = cKrbCorruptedFile;
+		return 1;
+	}
+	DetachResource(fServerMap);
+	
+	if(refnum != -1) CloseResFile(refnum);
+	fConstructErr = noErr;
+	
+	if (!hasPrefFile) {
+		fConstructErr = CreatePrefFile();		// make prefs file if we need to
+	}
+	
+	initialized_store = 1;
+	return 0;
+}
+
+
+/****************Private routines******************/
+
+OSErr	OpenPrefsFile(short *refnum)
+{
+	*refnum = HOpenResFile(fPrefVRefNum, fPrefDirID, (unsigned char *)prefname, fsRdWrPerm);
+	
+	if(ResError()) {	/* doesn't exist, create it */
+		FInfo	fndrinfo;
+		
+		HCreateResFile(fPrefVRefNum, fPrefDirID, (unsigned char *)prefname);
+		if(ResError()) {
+			return ResError();
+			}
+		*refnum = HOpenResFile(fPrefVRefNum, fPrefDirID, (unsigned char *)prefname, fsRdWrPerm);
+		if(ResError()) {
+			return ResError();
+			}
+		HGetFInfo(fPrefVRefNum, fPrefDirID, (unsigned char *)prefname, &fndrinfo); 
+		fndrinfo.fdCreator = prefcrea;
+		fndrinfo.fdType = preftype;
+		HSetFInfo(fPrefVRefNum, fPrefDirID, (unsigned char *)prefname, &fndrinfo); 
+		}
+	
+	return noErr;
+	}
+
+
+
+OSErr	CreatePrefFile()
+{
+	short	refnum, i;
+	OSErr	err;
+	Handle	tmpls[ kNumTemplates ];
+
+	// Get all the templates for ResEdit
+	for( i = 0; i < kNumTemplates; i++ ) {
+		tmpls[i] = GetResource( templatetype, kFirstTemplate + i );
+		if( ResError() || !tmpls[i] ) return cKrbCorruptedFile;
+	}
+	
+	err = OpenPrefsFile( &refnum );
+	if( err ) return err;
+	
+	// write out the templates
+	for( i = 0; i < kNumTemplates && !err; i++ ) {
+		short	tmplid;
+		ResType	theType;
+		Str255	resName;
+
+		GetResInfo( tmpls[i], &tmplid, &theType, resName );
+		err = WritePref( refnum, tmpls[i], templatetype, tmplid, resName );	
+		ReleaseResource( tmpls[i] );
+	}
+
+	if( !err )
+		err = WritePref( refnum, fRealmMap, realmmaptype, kMapResNum, "\p" );	
+	if( !err )
+		err = WritePref( refnum, fServerMap, servermaptype, kMapResNum, "\p" );	
+	if( !err )
+		err = WritePrefStr( refnum, fLRealm, lrealmtype, kMapResNum, "\p" );	
+	if( !err )
+		err = WritePrefStr( refnum, gUserName, unametype, kMapResNum, "\p" );	
+
+	CloseResFile( refnum );
+	if( !err ) err = ResError();
+	return err;
+}
+
+OSErr	WriteUser()
+{
+	short	refnum;
+	OSErr	err;
+
+	err = OpenPrefsFile( &refnum );
+	if( err ) return err;
+
+	err = WritePrefStr( refnum, gUserName, unametype, kMapResNum, "\p" );	
+
+	CloseResFile( refnum );
+	if( !err ) err = ResError();
+	return err;
+}
+
+OSErr	WritePref( short refnum, Handle dataHandle, OSType mapType, short resID, Str255 resName )
+{
+	OSErr	err;
+	Handle	resHandle;
+
+	resHandle = Get1Resource( mapType, resID );
+	if( !resHandle ) {								// create a new resource:
+		resHandle = dataHandle;
+		err = HandToHand( &resHandle );				// copy the data handle
+		if( err != noErr ) return err;
+
+		AddResource( resHandle, mapType, resID, resName );
+		if( ( err = ResError() ) != noErr ) {
+			DisposHandle( resHandle );
+			return err;
+		}
+		SetResAttrs( resHandle, resSysHeap | GetResAttrs( resHandle ) );
+	}
+	else {											/* modify an existing resource: */
+		Size handleSize = GetHandleSize( dataHandle );
+		SetHandleSize( resHandle, handleSize );
+		if( ( err = MemError() ) != noErr ) {
+			ReleaseResource( resHandle );
+			return err;
+		}
+		BlockMove( *dataHandle, *resHandle, handleSize );
+		ChangedResource( resHandle );
+		if( ( err = ResError() ) != noErr ) {
+			ReleaseResource( resHandle );
+			return err;
+		}
+	}
+
+	UpdateResFile( refnum );
+	err = ResError();
+	ReleaseResource( resHandle );
+	return err;
+}
+
+OSErr	WritePrefStr( short refnum, char *dataString, OSType mapType, short resID, Str255 resName )
+{
+	OSErr		err;
+	Handle	dataHandle;
+
+	err = PtrToHand( dataString, &dataHandle, strlen( dataString ) + 1 );
+	if( err == noErr ) {
+		err = WritePref( refnum, dataHandle, mapType, resID, resName );
+		DisposHandle( dataHandle );
+	}
+	return err;
+}
+	
+OSErr	WriteRealmMap()
+{
+	short	refnum;
+	OSErr	err;
+	
+	err = OpenPrefsFile( &refnum );
+	if( err ) return err;
+		
+ 	err = WritePref( refnum, fRealmMap, realmmaptype, kMapResNum, "\p" );	
+
+	CloseResFile( refnum );
+	if( !err ) err = ResError();
+	return err;
+}
+
+OSErr	WriteServerMap()
+{
+	short	refnum;
+	OSErr	err;
+	
+	err = OpenPrefsFile(&refnum);
+	if( err ) return err;
+	
+	err = WritePref( refnum, fServerMap, servermaptype, kMapResNum,"\p" );	
+
+	CloseResFile( refnum );
+	if( !err ) err = ResError();
+	return err;
+}
+
+OSErr	GetLocalRealm(char *lrealm)
+{
+	if (!initialized_store)
+		init_store();
+	
+	strcpy(lrealm, fLRealm);
+	return noErr;
+	}
+
+OSErr	SetLocalRealm( const char *lrealm )
+{
+	short	refnum;
+	OSErr	err;
+		
+	if (!initialized_store)
+		init_store();
+	
+	strcpy( fLRealm, (char *) lrealm );
+	
+	err = OpenPrefsFile( &refnum );
+	if( err ) return err;
+	
+	err = WritePrefStr( refnum, fLRealm, lrealmtype, kMapResNum, "\p" );	
+
+	CloseResFile( refnum );
+	if( !err ) err = ResError();
+	return err;
+}
+
+OSErr	GetRealm(const char *host, char *realm)
+{
+	int	numrealms;
+	char	*curnetorhost, *currealm;
+	char	*domain;
+	
+	if (!initialized_store)
+		init_store();
+	
+	numrealms = *((short *)*fRealmMap);
+	GetLocalRealm(realm);
+	
+	domain = strchr( host, '.');
+	if(!domain) return noErr;
+	
+	curnetorhost = (*fRealmMap) + 2;
+	currealm = strchr(curnetorhost, '\0') + 1;
+	for( ; numrealms > 0; numrealms--) {
+		if(!strcasecmp(curnetorhost, host)) {
+			strcpy(realm, currealm);
+			return noErr;
+			}
+		if(!strcasecmp(curnetorhost, domain)) {
+			strcpy(realm, currealm);
+			}
+		
+		if(numrealms > 1) {
+			curnetorhost = strchr(currealm, '\0') + 1;
+			currealm = strchr(curnetorhost, '\0') + 1;
+			}
+		}
+	
+	return noErr;
+	}
+
+OSErr	AddRealmMap(const char *netorhost, const char *realm)
+{
+	int	numrealms;
+	char	*curptr;
+	
+	SetHandleSize(fRealmMap, strlen(netorhost)+1 + strlen(realm)+1 +
+										GetHandleSize(fRealmMap));
+	if(MemError()) return MemError();
+	
+	numrealms = ++(*((short *)*fRealmMap));
+	
+	for(curptr = (*fRealmMap)+2; numrealms > 1; numrealms--) {
+		curptr = strchr(curptr, '\0') + 1;
+		curptr = strchr(curptr, '\0') + 1;
+		}
+	
+	strcpy(curptr, netorhost);
+	curptr = strchr(curptr, '\0') + 1;
+	strcpy(curptr, realm);
+	
+	return WriteRealmMap();
+	}
+
+OSErr	DeleteRealmMap(const char *netorhost)
+{
+	int	numrealms = *((short *)*fRealmMap);
+	char	*curptr, *fromptr, *nextptr;
+		
+	for(curptr = (*fRealmMap)+2; numrealms > 0; numrealms--) {
+		if(!strcasecmp(curptr, netorhost)) break;	/* got it! */
+		
+		curptr = strchr(curptr, '\0') + 1;
+		curptr = strchr(curptr, '\0') + 1;
+		}
+	
+	if(numrealms == 0) return cKrbMapDoesntExist;
+	
+	*(short*)*fRealmMap -= 1;
+	
+	if(numrealms > 1) {
+		fromptr = strchr(curptr, '\0') + 1;
+		fromptr = strchr(fromptr, '\0') + 1;
+		}
+	
+	for( ; numrealms > 1; numrealms--) {
+		nextptr = strchr(fromptr, '\0') + 1;
+		strcpy(curptr, fromptr);
+		curptr = strchr(curptr, '\0') + 1;
+		fromptr = nextptr;
+		
+		nextptr = strchr(fromptr, '\0') + 1;
+		strcpy(curptr, fromptr);
+		curptr = strchr(curptr, '\0') + 1;
+		fromptr = nextptr;
+		}
+	
+	SetHandleSize(fRealmMap, curptr-(*fRealmMap));
+	if(MemError()) return MemError();
+	return WriteRealmMap();
+	}
+
+OSErr	GetNthRealmMap(const int n, char *netorhost, char *realm)
+{
+	int	i;
+	char	*curptr;
+	
+	if(n > *(short*)*fRealmMap) return cKrbMapDoesntExist;
+	
+	for(curptr = (*fRealmMap) + 2, i = 1; i < n; i++) {
+		curptr = strchr(curptr, '\0') + 1;
+		curptr = strchr(curptr, '\0') + 1;
+		}
+	
+	strcpy(netorhost, curptr);
+	curptr = strchr(curptr, '\0') + 1;
+	strcpy(realm, curptr);
+	
+	return noErr;
+	}
+
+OSErr	GetNthServer(const int n, const char *realm, const int mustadmin,
+										char *server)
+{
+	int	numservers = *(short*)*fServerMap, i = 0;
+	char	*currealm, *curserver;
+	
+	currealm = (*fServerMap) + 2;
+	curserver = strchr(currealm, '\0') + 1 + 1;
+	for( ; numservers > 0; numservers--) {
+		if(!strcmp(currealm, realm)) {
+			if(!mustadmin || *(curserver-1)) i++;
+			if(i >= n) {
+				strcpy(server, curserver);
+				return noErr;
+				}
+			}
+		
+		if(numservers > 1) {
+			currealm = strchr(curserver, '\0') + 1;
+			curserver = strchr(currealm, '\0') + 1 + 1;
+			}
+		}
+
+	return cKrbMapDoesntExist;
+	}
+
+OSErr	AddServerMap(const char *realm, const char *server,
+										const int isadmin)
+{
+	int	numservers;
+	char	*curptr;
+	
+	SetHandleSize(fServerMap, strlen(realm)+1 + 1 + strlen(server)+1 +
+										GetHandleSize(fServerMap));
+	if(MemError()) return MemError();
+	
+	numservers = ++(*((short *)*fServerMap));
+	
+	for(curptr = (*fServerMap)+2; numservers > 1; numservers--) {
+		curptr = strchr(curptr, '\0') + 1 + 1;
+		curptr = strchr(curptr, '\0') + 1;
+		}
+	
+	strcpy(curptr, realm);
+	curptr = strchr(curptr, '\0') + 1;
+	*curptr = (char) isadmin;
+	curptr++;
+	strcpy(curptr, server);
+	
+	return WriteServerMap();
+	}
+
+OSErr	DeleteServerMap(const char *realm, const char *server)
+{
+	int	numservers = *((short *)*fServerMap);
+	char	*curptr, *fromptr, *nextptr;
+		
+	for(curptr = (*fServerMap)+2; numservers > 0; numservers--) {
+		if(!strcmp(curptr, realm)) {
+			nextptr = strchr(curptr, '\0') + 1 + 1;
+			if(!strcasecmp(nextptr, server)) {
+				break;	/* got it! */
+				}
+			}
+		
+		curptr = strchr(curptr, '\0') + 1 + 1;
+		curptr = strchr(curptr, '\0') + 1;
+		}
+	
+	if(numservers == 0) return cKrbMapDoesntExist;
+	
+	*(short*)*fServerMap -= 1;
+	
+	if(numservers > 1) {
+		fromptr = strchr(curptr, '\0') + 1 + 1;
+		fromptr = strchr(fromptr, '\0') + 1;
+		}
+	
+	for( ; numservers > 1; numservers--) {
+		nextptr = strchr(fromptr, '\0') + 1;
+		strcpy(curptr, fromptr);
+		curptr = strchr(curptr, '\0') + 1;
+		fromptr = nextptr;
+		
+		*curptr = *fromptr;
+		curptr++;
+		fromptr++;
+		
+		nextptr = strchr(fromptr, '\0') + 1;
+		strcpy(curptr, fromptr);
+		curptr = strchr(curptr, '\0') + 1;
+		fromptr = nextptr;
+		}
+	
+	SetHandleSize(fServerMap, curptr-(*fServerMap));
+	if(MemError()) return MemError();
+	return WriteServerMap();
+	}
+
+OSErr	GetNthServerMap(const int n, char *realm, char *server, int *admin)
+{
+	int	i;
+	char	*curptr;
+	
+	if(n > *(short*)*fServerMap) return cKrbMapDoesntExist;
+	
+	for(curptr = (*fServerMap) + 2, i = 1; i < n; i++) {
+		curptr = strchr(curptr, '\0') + 1 + 1;
+		curptr = strchr(curptr, '\0') + 1;
+		}
+	
+	strcpy(realm, curptr);
+	curptr = strchr(curptr, '\0') + 1;
+	*admin = *curptr;
+	curptr++;
+	strcpy(server, curptr);
+	
+	return noErr;
+}
diff --git a/mechglue/src/lib/krb4/mac_store.h b/mechglue/src/lib/krb4/mac_store.h
new file mode 100644
index 000000000..b1652dc55
--- /dev/null
+++ b/mechglue/src/lib/krb4/mac_store.h
@@ -0,0 +1,56 @@
+/*
+	store.h
+		Kerberos credential store
+		Originally coded by Tim Miller / Brown University
+		Mods 1/92 By Peter Bosanko
+
+		Modified May 1994 by Julia Menapace and John Gilmore, Cygnus
+		Support.
+*/
+
+#include "memcache.h"
+
+extern	OSErr		fConstructErr;
+
+		OSErr	CreatePrefFile();
+		OSErr	WriteUser();		/* saves gUserName to prefs file  */
+
+		/* Used internally...  */
+		OSErr	WritePref(short refnum, Handle dataHandle, OSType mapType, short resID,
+							Str255 resName);
+		OSErr	WritePrefStr(short refnum, char *dataString, OSType mapType, short resID,
+							Str255 resName);
+
+			/*** Realm info routines: ***/
+		OSErr	GetLocalRealm(char *lrealm);	/* stuffs local realm in lrealm */
+		OSErr	SetLocalRealm(const char *lrealm);	/* sets local realm */
+
+		OSErr	GetRealm(const char *host, char *realm);	/* yields realm for given
+												host's net name */
+		OSErr	AddRealmMap(const char *netorhost, const char *realm);	/* says hosts
+												with this name or in this domain (if
+												begins with period) map to this realm
+												(provided no more specific map is
+												found) */
+		OSErr	DeleteRealmMap(const char *netorhost);	/* deletes realm map for the
+												net or net hostname */
+		OSErr	GetNthRealmMap(const int n, char *netorhost, char *realm);	/* yields
+												the Nth mapping of a net or host to
+												a kerberos realm */
+
+		OSErr	GetNthServer(const int n, const char *realm, const int mustadmin,
+								char *server);	/* yields Nth (administrating if
+													mustadmin is true) server for
+													the given realm */
+		OSErr	AddServerMap(const char *realm, const char *server,
+								const int isadmin);	/* says this server services this
+												realm (administratively if isadmin) */
+		OSErr	DeleteServerMap(const char *realm, const char *server);	/* deletes
+												the map of this realm to this server */
+		OSErr	GetNthServerMap(const int n, char *realm, char *server, int *admin);
+											/* yields Nth realm-server mapping */
+
+		OSErr		OpenPrefsFile(short *refnum);	/* open (create if necessary) prefs file
+																for writing */
+		OSErr		WriteRealmMap();
+		OSErr		WriteServerMap();
diff --git a/mechglue/src/lib/krb4/mac_stubs.c b/mechglue/src/lib/krb4/mac_stubs.c
new file mode 100644
index 000000000..2cd1f0ac7
--- /dev/null
+++ b/mechglue/src/lib/krb4/mac_stubs.c
@@ -0,0 +1,525 @@
+/* 
+ * mac_stubs.c
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Macintosh oopserating system stub interface for Kerberos.
+ * Applications call these routines, which then call the driver to do the work.
+ */
+
+#include "krb.h"
+#include "krb_driver.h"	/* Mac driver interface */
+
+#include <string.h>
+#include <stddef.h>
+#include <Files.h>
+#include <Devices.h>
+
+/* We export the driver reference under the name mac_stubs_kdriver,
+   but for convenience throughout this code, we call it "kdriver",
+   which was its name when it was static.  */
+short mac_stubs_kdriver = 0;		/* .Kerberos driver ref */
+#define	kdriver mac_stubs_kdriver
+
+ParamBlockRec pb[1];
+struct krbHiParmBlock khipb[1];
+struct krbParmBlock klopb[1];
+
+short lowcall (long cscode, krbParmBlock *klopb, short kdriver)
+{
+	short s;
+	ParamBlockRec pb;
+	
+	memset (&pb, 0, sizeof(ParamBlockRec));
+	*(long *)pb.cntrlParam.csParam = (long)klopb;
+	pb.cntrlParam.ioCompletion = nil;
+	pb.cntrlParam.ioCRefNum = kdriver;
+	pb.cntrlParam.csCode = cscode;
+	
+	if (s = PBControl(&pb, false))
+		return KFAILURE;
+	if (s = pb.cntrlParam.ioResult)
+		return -(s - cKrbKerberosErrBlock);	/* Restore krb err code from driver err */
+
+	return KSUCCESS;
+}
+
+
+short hicall (long cscode, krbHiParmBlock *khipb, short kdriver)
+{
+	short s;
+	ParamBlockRec pb;
+	memset(&pb, 0, sizeof(ParamBlockRec));
+	*(long *)pb.cntrlParam.csParam = (long)khipb;
+	pb.cntrlParam.ioCompletion = nil;
+	pb.cntrlParam.ioCRefNum = kdriver;
+
+	pb.cntrlParam.csCode = cscode;
+	if (s = PBControl(&pb, false))
+		return KFAILURE;
+	if (s = pb.cntrlParam.ioResult)
+		return -(s - cKrbKerberosErrBlock);	/* Restore krb err code from driver err */
+
+	return KSUCCESS;
+}
+
+
+int INTERFACE
+krb_start_session (x)
+	char *x;
+{
+	short s;
+	
+	/*
+	 * Open the .Kerberos driver if not already open
+	 */
+	if (!kdriver) {
+		s = OpenDriver("\p.Kerberos", &kdriver);
+		if (s) {
+			return KFAILURE;	/* Improve this error code */
+		}
+	}
+
+	return KSUCCESS;
+}
+
+
+int INTERFACE
+krb_end_session (x)
+	char *x;
+{
+	short s;
+
+#if 0 /* This driver doesn't want to be closed.  FIXME, is this OK? */
+	if (kdriver) {
+		s = CloseDriver(kdriver);
+		if (s)
+			return KFAILURE;
+		kdriver = 0;
+	}
+#endif
+	return KSUCCESS;
+}
+
+
+char * INTERFACE
+krb_realmofhost (host)
+	char *host;
+{
+	short s;
+	ParamBlockRec pb;
+	static char realm[REALM_SZ];
+
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->host = host;
+	klopb->uRealm = realm;
+	
+	/* FIXME jcm - no error handling for return value of lowcall in krb_realmofhost */
+	s = lowcall (cKrbGetRealm , klopb, kdriver);
+
+	return realm;
+}
+
+int INTERFACE
+krb_get_lrealm (realm, n)
+	char *realm;
+	int n;
+{
+	short s;
+	ParamBlockRec pb;
+
+	if (n != 1)
+		return KFAILURE;
+
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->uRealm = realm;
+
+	s = lowcall (cKrbGetLocalRealm, klopb, kdriver);
+	return s;
+		
+}
+
+
+int INTERFACE
+kname_parse (name, instance, realm, fullname)
+	char *name, *instance, *realm, *fullname;
+{
+	short s;
+	ParamBlockRec pb;
+
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->uName = name;
+	klopb->uInstance = instance;
+	klopb->uRealm = realm;
+	klopb->fullname = fullname;
+
+	s = lowcall (cKrbKnameParse, klopb, kdriver);
+	return s;
+}
+
+const char* INTERFACE
+krb_get_err_text (error_code)
+	int error_code;
+{
+	short s;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->admin = error_code;	
+	s = lowcall (cKrbGetErrText, klopb, kdriver);
+	if (s != KSUCCESS)
+		return "Error in get_err_text";	
+	return klopb->uName;
+}
+
+
+int INTERFACE
+krb_get_pw_in_tkt(user,instance,realm,service,sinstance,life,password)
+    char *user, *instance, *realm, *service, *sinstance;
+    int life;
+    char *password;
+{
+	short s;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->uName = user;	
+	klopb->uInstance = instance;
+	klopb->uRealm = realm;
+	klopb->sName = service;
+	klopb->sInstance = sinstance;
+	klopb->admin = life;
+	klopb->fullname = password;
+	
+	s = lowcall (cKrbGetPwInTkt, klopb, kdriver);
+	return s;
+}
+
+
+/* FIXME:  For now, we handle the preauth version exactly the same
+   as the non-preauth.   */
+krb_get_pw_in_tkt_preauth(user,instance,realm,service,sinstance,life,password)
+    char *user, *instance, *realm, *service, *sinstance;
+    int life;
+    char *password;
+{
+	short s;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->uName = user;	
+	klopb->uInstance = instance;
+	klopb->uRealm = realm;
+	klopb->sName = service;
+	klopb->sInstance = sinstance;
+	klopb->admin = life;
+	klopb->fullname = password;
+	
+	s = lowcall (cKrbGetPwInTkt, klopb, kdriver);
+	return s;
+}
+
+
+
+char* INTERFACE
+krb_get_default_user (void)
+{
+	short s;
+	static char return_name[MAX_K_NAME_SZ];
+	
+	memset(khipb, 0, sizeof(*khipb));
+	khipb->user = return_name;
+	s = hicall (cKrbGetUserName, khipb, kdriver);
+	if (s != KSUCCESS)
+		return 0;
+	return return_name;
+}
+
+
+int INTERFACE
+krb_set_default_user (uName)
+	char* uName;
+{
+	short s;
+	
+	memset(khipb, 0, sizeof(*khipb));
+	khipb->user = uName;
+	s = hicall (cKrbSetUserName, khipb, kdriver);
+	return s;
+}
+
+int INTERFACE
+krb_get_cred (name, instance, realm, cr)
+	char *name;
+	char *instance;
+	char *realm;
+	CREDENTIALS *cr;
+{
+	short s;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	
+	strcpy(cr->service, name);
+	strcpy(cr->instance, instance);
+	strcpy(cr->realm, realm);
+	
+	klopb->cred = cr;
+
+	s = lowcall (cKrbGetCredentials, klopb, kdriver);
+	return s;
+}
+
+int INTERFACE
+krb_save_credentials (sname, sinstance, srealm, session, 
+			lifetime, kvno,ticket, issue_date)
+	char *sname;		/* service name */
+	char *sinstance;	/* service instance */
+	char *srealm;		/* service realm */
+	C_Block session;	/* Session key */
+	int lifetime;		/* Lifetime */
+	int kvno;			/* Key version number */
+    KTEXT ticket; 	    /* The ticket itself */
+	long issue_date;	/* The issue time */
+	
+{
+	short s;
+	CREDENTIALS cr;
+	
+	strcpy(cr.service, sname);
+	strcpy(cr.instance, sinstance);
+	strcpy(cr.realm, srealm);
+	memcpy(cr.session, session, sizeof(C_Block));
+	cr.lifetime = lifetime;
+	cr.kvno = kvno;
+	cr.ticket_st = *ticket;
+	cr.issue_date = issue_date;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->cred = &cr;
+
+	s = lowcall (cKrbAddCredentials, klopb, kdriver);
+	return s;
+}
+
+
+int INTERFACE
+krb_delete_cred (sname, sinstance, srealm)
+	char *sname;
+	char *sinstance;
+	char *srealm;
+{
+	short s;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	
+	klopb->sName = sname;
+	klopb->sInstance = sinstance;
+	klopb->sRealm = srealm;
+	
+	s = lowcall (cKrbDeleteCredentials, klopb, kdriver);
+	return s;
+}
+
+int INTERFACE
+dest_tkt (cachename)
+	char *cachename;		/* This parameter is ignored. */
+{
+	short s;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	s = lowcall (cKrbDeleteAllSessions, klopb, kdriver);
+	return s;
+}
+
+/* 
+ *	returns service name, service instance and realm of the nth credential. 
+ *  credential numbering is 1 based.
+ */
+
+int INTERFACE
+krb_get_nth_cred (sname, sinstance, srealm, n)
+	char *sname;
+	char *sinstance;
+	char *srealm;
+	int n;
+{
+	short s;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	
+	klopb->sName = sname;
+	klopb->sInstance = sinstance;
+	klopb->sRealm = srealm;
+	klopb->itemNumber = &n;
+	
+	s = lowcall (cKrbGetNthCredentials, klopb, kdriver);
+	return s;
+}
+
+/*
+ * Return the number of credentials in the current credential cache (ticket cache).
+ * On error, returns -1. 
+ */
+int INTERFACE
+krb_get_num_cred ()
+{
+	int s;
+	int n;
+	
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->itemNumber = &n;
+	
+	s = lowcall (cKrbGetNumCredentials, klopb, kdriver);
+	if (s) 
+		return -1;
+	return *(klopb->itemNumber);
+}
+
+
+
+/* GetNthRealmMap
+   yields the Nth mapping of a net or host to a Kerberos realm 
+	  -> itemNumber 	which mapping, traditionally the first
+	  -> host	   		host or net
+	  -> uRealm    		pointer to buffer that will receive realm name
+*/
+
+OSErr INTERFACE
+GetNthRealmMap(n, netorhost, realm)
+	int n;
+	char *netorhost;
+	char *realm;
+{
+	int s;
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->itemNumber = &n;
+	klopb->host = netorhost;
+	klopb->uRealm = realm;
+	
+	s = lowcall (cKrbGetNthRealmMap, klopb, kdriver);
+	return s;
+}
+
+/* GetNthServerMap
+   yields Nth realm-server mapping
+   -> itemNumber		which mapping should be returned
+   -> uRealm			pointer to buffer that will receive realm name	
+   -> host				pointer to buffer that will receive server name
+   -> admin				pointer to admin flag
+ */
+	
+OSErr	INTERFACE
+GetNthServerMap(n, realm, server, admin)	
+    int n;
+    char *realm;
+    char *server; 
+    int *admin;
+{
+	int s;
+	memset(klopb, 0, sizeof(*klopb));
+	klopb->itemNumber = &n;
+	klopb->uRealm = realm;
+	klopb->host = server;
+	klopb->adminReturn = admin;
+
+	s = lowcall (cKrbGetNthServerMap, klopb, kdriver);
+	return s;
+}
+
+
+
+/* krb_get_ticket_for_service
+ * Gets a ticket and returns it to application in buf
+	  -> service		Formal Kerberos name of service
+	  -> buf		Buffer to receive ticket
+	  -> checksum		checksum for this service
+	 <-> buflen		length of ticket buffer (must be at least
+					1258 bytes)
+	 <-  sessionKey		for internal use
+	 <-  schedule		for internal use
+
+ * Result is:
+ *   GC_NOTKT		if there is no matching TGT in the cache
+ *   MK_AP_TGTEXP	if the matching TGT is expired
+ * Other errors possible.  These could cause a dialogue with the user
+ * to get a new TGT.
+ */ 
+
+int INTERFACE
+krb_get_ticket_for_service (serviceName, buf, buflen, checksum, sessionKey,
+		schedule, version, includeVersion)
+	char *serviceName;
+	char *buf;
+	unsigned KRB4_32 *buflen;
+	int checksum;
+	des_cblock sessionKey;
+	Key_schedule schedule;
+	char *version;
+	int includeVersion;
+{
+	short s;
+
+	if (includeVersion)
+		return KFAILURE;		/* Not implmented in the kclient driver iface */
+	
+	memset(khipb, 0, sizeof(*khipb));
+	khipb->service = serviceName;
+	khipb->buf = buf;
+	khipb->buflen = *buflen;
+	khipb->checksum = checksum;
+
+	s = hicall (cKrbGetTicketForService, khipb, kdriver);
+	/* These are ARRAYS in the hiparmblock, for some reason! */
+	memcpy (sessionKey, khipb->sessionKey, sizeof (khipb[0].sessionKey));
+	memcpy (schedule,   khipb->schedule,   sizeof (khipb[0].schedule));
+	*buflen = khipb->buflen;
+	return s;
+}
+
+
+/* 	krb_get_tf_fullname -- return name, instance and realm of the
+	principal in the current ticket file. The ticket file name is not 
+	currently used for anything since there is only one credentials 
+	cache/ticket file
+*/
+
+int INTERFACE
+krb_get_tf_fullname (tktfile, name, instance, realm)
+  char *tktfile;
+  char *name;
+  char *instance;
+  char *realm;
+
+{
+	short s;
+	memset (klopb, 0, sizeof(*klopb));
+	klopb->fullname = tktfile;
+	klopb->uName = name;
+	klopb->uInstance = instance;
+	klopb->uRealm = realm;
+	
+	s = lowcall (cKrbGetTfFullname, klopb, kdriver);
+	return s;
+}
+
+
+
+#if 0
+	xbzero(khipb, sizeof(krbHiParmBlock));
+	khipb->service = (char *)cannon;
+	khipb->buf = (char *)buf;				/* where to build it */
+	khipb->checksum = 0;
+	khipb->buflen = sizeof(buf);
+	if (s = hicall(cKrbGetTicketForService, khipb, kdriver))
+		return s;
+	xbcopy(khipb->sessionKey, sessionKey, sizeof(sessionKey));	/* save the session key */
+	/*
+	 * cKrbGetTicketForService put a longword buffer length into the buffer
+	 * which we don't want, so we ignore it.
+     * Make room for first 3 bytes which preceed the auth data.
+	 */
+	cp = &buf[4-3];						/* skip long, make room for 3 bytes */
+	cp[0] = tp[0];						/* copy type and modifier */
+	cp[1] = tp[1];
+	cp[2] = KRB_AUTH;					/* suboption command */
+	len = khipb->buflen - sizeof(long) + 3; /* data - 4 + 3 */
+
+#endif /* 0 */
diff --git a/mechglue/src/lib/krb4/mac_time.c b/mechglue/src/lib/krb4/mac_time.c
new file mode 100644
index 000000000..bec4d8f53
--- /dev/null
+++ b/mechglue/src/lib/krb4/mac_time.c
@@ -0,0 +1,152 @@
+/*
+ * mac_time.c
+ * (Originally time_stuff.c)
+ *
+ * Copyright 1989 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Macintosh ooperating system interface for Kerberos.
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+#include "des.h"
+#include "AddressXlation.h"	/* for ip_addr */
+#include <time.h>
+#include <sys/time.h>
+
+#include <script.h>			/* Defines MachineLocation, used by getTimeZoneOffset */
+#include <ToolUtils.h>		/* Defines BitTst(), called by getTimeZoneOffset() */
+#include <OSUtils.h>		/* Defines GetDateTime */
+
+/* Mac Cincludes */
+#include <string.h>
+#include <stddef.h>
+
+
+  /*******************************
+  The Unix epoch is 1/1/70, the Mac epoch is 1/1/04.
+
+  70 - 4 = 66 year differential
+
+  Thus the offset is:
+
+  (66 yrs) * (365 days/yr) * (24 hours/day) * (60 mins/hour) * (60 secs/min)
+  plus
+  (17 leap days) * (24 hours/day) * (60 mins/hour) * (60 secs/min)
+
+  Don't forget the offset from GMT.
+  *******************************/
+
+
+/* returns the offset in hours between the mac local time and the GMT  */
+
+unsigned long
+getTimeZoneOffset()
+{
+	MachineLocation		macLocation;
+	long			gmtDelta;
+
+	macLocation.gmtFlags.gmtDelta=0L;
+	ReadLocation(&macLocation); 
+	gmtDelta=macLocation.gmtFlags.gmtDelta & 0x00FFFFFF;
+	if (BitTst((void *)&gmtDelta,23L))	gmtDelta |= 0xFF000000;
+	gmtDelta /= 3600L;
+	return(gmtDelta);
+}
+
+
+/* Returns the GMT in seconds using the Unix epoch, ie. Net time */
+
+static unsigned long
+gettimeofdaynet_no_offset()
+{
+	time_t the_time;
+	
+	GetDateTime (&the_time);
+	the_time = the_time - 
+		((66 * 365 * 24 * 60 * 60) + 
+		      (17 *  24 * 60 * 60) +
+           (getTimeZoneOffset() * 60 * 60));
+	return the_time;
+}
+
+
+
+int	
+gettimeofdaynet (struct timeval *tp, struct timezone *tz)
+{ 
+	tp->tv_sec = gettimeofdaynet_no_offset();
+	return 0;
+}
+
+
+#if 0
+
+int	
+gettimeofdaynet (struct timeval *tp, struct timezone *tz)
+{
+	int result;
+	
+	if (!net_got_offset)
+		result = get_net_offset();
+	else result = 0;
+	
+	time ((time_t *) &(tp->tv_sec));
+
+	tp->tv_sec = tp->tv_sec - (66 * 365 * 24 * 60 * 60
+            + 17 * 60 * 60 * 24) + net_offset;
+
+	return (result);
+}
+
+
+#define TIME_PORT 37
+#define TM_OFFSET 2208988800
+
+/*
+ *
+ *   get_net_offset () -- Use UDP time protocol to figure out the
+ *	offset between what the Mac thinks the time is an what
+ *	the network thinks.
+ *
+ */
+int
+get_net_offset()
+{
+     time_t tv;
+     char buf[512],ts[256];
+     long *nettime;
+     int attempts, cc, time_port;
+     long unixtime;
+	 char	realm[REALM_SZ];
+	 ip_addr	fromaddr;
+	 unsigned short	fromport;
+	 int result;
+	 
+     nettime = (long *)buf;
+	 time_port = TIME_PORT;
+
+	 cc = sizeof(buf);
+	 result = hosts_send_recv(ts, 1, buf, &cc, "", time_port);
+     time (&tv);
+	 
+	 if (result!=KSUCCESS || cc<4) {
+	 	net_offset = 0;
+	 	if (!result) result = 100;
+	 	return result;
+	 }
+						
+     unixtime = (long) ntohl(*nettime) - TM_OFFSET;
+
+     tv  -= 66 * 365 * 24 * 60 * 60
+	  + 17 * 60 * 60 * 24;			/* Convert to unix time w/o offset */
+     net_offset = unixtime - tv;
+     net_got_offset = 1;
+     
+     return 0;
+}
+
+#endif
diff --git a/mechglue/src/lib/krb4/memcache.c b/mechglue/src/lib/krb4/memcache.c
new file mode 100644
index 000000000..6a7b48a70
--- /dev/null
+++ b/mechglue/src/lib/krb4/memcache.c
@@ -0,0 +1,891 @@
+/*
+ * memcache.c
+ *
+ * Kerberos credential cache
+ * Originally coded by Tim Miller / Brown University as KRB_Store.c
+ * Mods 1/92 By Peter Bosanko
+ *
+ * Modified May-June 1994 by Julia Menapace and John Gilmore
+ * of Cygnus Support.
+ *
+ * This file incorporates replacements for the Unix files
+ * in_tkt.c, dest_tkt.c, tf_util.c, and tkt_string.c.
+ */
+
+#include "krb.h"
+#include "krb4int.h"
+#include "krb5/autoconf.h"
+
+#ifdef _WIN32
+#include <errno.h>
+
+typedef DWORD OSErr;
+#define noErr 0
+#define cKrbCredsDontExist 12001
+#define cKrbSessDoesntExist 12002
+#define memFullErr ENOMEM
+#endif
+
+#ifndef unix
+#ifdef _AIX
+#define unix
+#endif
+#endif
+
+#ifdef unix
+/* Unix interface to memory cache Mac functions.  */
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc (), *realloc ();
+#endif
+
+typedef int OSErr;
+#define noErr 0
+#define memFullErr ENOMEM
+
+#endif /* unix */
+
+#include "memcache.h"
+
+
+/* Lower level data structures  */
+
+static	int		fNumSessions = 0;
+static	Session		**fSessions = 0;
+
+#ifndef _WIN32
+#define change_cache()
+#endif
+
+#if defined (_WIN32) || defined (unix)
+/* Fake Mac handles up for general use.  */
+#define	Handle	char **
+#define	Size	int
+
+static OSErr memerror = noErr;
+
+/*
+ * Simulates Macintosh routine by allocating a block of memory
+ * and a pointer to that block of memory.  If the requested block
+ * size is 0, then we just allocate the indirect pointer and 0
+ * it, otherwise we allocate an indirect pointer and place a pointer
+ * to the actual allocated block in the indirect pointer location.
+ */
+Handle 
+NewHandleSys(s)
+	int s;
+{
+	Handle h;
+
+	h = (char **) malloc(sizeof(char *));
+
+	if (h == NULL) {
+		memerror = memFullErr;
+		return (NULL);
+	}
+
+	if (s > 0) {
+		*h = malloc(s);
+
+		if (*h == NULL) {
+			free(h);
+			memerror = memFullErr;
+			return (NULL);
+		}
+	}
+	else
+		*h = NULL;
+
+	memerror = noErr;
+
+	return h;
+}
+
+/*
+ * Frees allocated indirect pointer and the block of memory it points
+ * to.  If the indirect pointer is NULL, then the block is considered
+ * to have 0 length.
+ */
+void
+DisposHandle(h)
+	Handle h;
+{
+	if (*h != NULL)
+		free(*h);
+	free(h);
+}
+
+/*
+ * Resizes a block of memory pointed to by and indirect pointer.  The
+ * indirect pointer is updated when the block of memory is reallocated.
+ * If the indirect pointer is 0, then the block of memory is allocated
+ * rather than reallocated.  If the size requested is 0, then the block
+ * is deallcated rather than reallocated.
+ */
+void
+SetHandleSize(h, s)
+	Handle h;
+	int s;
+{
+	if (*h != NULL) {
+		if (s > 0) {
+			*h = realloc(*h, s);
+			if (*h == NULL) {
+				memerror = memFullErr;
+				return;
+			}
+		}
+		else {
+			free(*h);
+			*h = NULL;
+		}
+	}
+
+	else {
+		if (s > 0) {
+			*h = malloc(s);
+			if (*h == NULL) {
+				memerror = memFullErr;
+				return;
+			}
+		}
+	}
+
+	memerror = noErr;
+}
+
+OSErr
+MemError()
+{
+	return memerror;
+}
+
+#endif /* Windows || unix */
+
+#ifdef _WIN32
+
+/*
+ * change_cache should be called after the cache changes.
+ * If the session count is > 0 it forces the DLL to stay in
+ * memory even after the calling program exits providing cross
+ * session ticket cacheing.  Also a notification message is
+ * is posted out to all top level Windows so that they may
+ * recheck the cache based on the changes made.  The
+ * krb_get_notifcation_message routine will return the
+ * current notificaiton message for the system which an
+ * application can expect to get.
+ */
+void
+change_cache()
+{
+	char fname[260];
+	static BOOL locked = FALSE;
+
+	if (fNumSessions > 0 && !locked) {
+		GetModuleFileName(get_lib_instance(), fname, sizeof(fname));
+		LoadLibrary(fname);
+		locked = TRUE;
+	}
+
+	else if (fNumSessions == 0 && locked) {
+		FreeLibrary(get_lib_instance());
+		locked = FALSE;
+	}
+
+	PostMessage(HWND_BROADCAST, krb_get_notification_message(), 0, 0);
+}
+
+
+/*
+ * Returns a system wide unique notification message.  This
+ * message will be broadcast to all top level windows when
+ * the credential cache changes.
+ */
+unsigned int
+krb_get_notification_message(void)
+{
+	static UINT message = 0;
+
+	if (message == 0)
+		message = RegisterWindowMessage(WM_KERBEROS_CHANGED);
+
+	return message;
+}
+
+
+#endif /* Windows */
+
+
+/* The low level routines in this file are capable of storing
+   tickets for multiple "sessions", each led by a different
+   ticket-granting ticket.  For now, since the top level code
+   doesn't know how to handle that, we are short-cutting all
+   that with a fixed top level identifying tag for the (one)
+   session supported. 
+
+   FIXME jcm - Force one named cache for now for compatibility with
+   Cygnus source tree.  Figure out later how to access the multiple
+   cache functionality in KClient.
+ */
+
+char uname[] = "Fixed User";
+char uinstance[] = "Fixed Instance";
+char urealm[] = "Fixed Realm";
+
+static char curr_auth_uname [ANAME_SZ];
+static char curr_auth_uinst [INST_SZ];
+
+
+/*
+    in_tkt() is used to initialize the ticket cache.
+    It inits the driver's credentials storage, by deleting any tickets.  
+    in_tkt() returns KSUCCESS on success, or KFAILURE if something goes wrong.
+
+    User name, instance and realm are not currently being stored in
+    the credentials cache because currently we are forcing a single
+    named cache by using a fixed user name,inst,and realm in the
+    memcache accessor routines.
+
+    FIXME jcm - needed while stubbing out multi-caching with fixed
+    user etc...  Store currently authenticated user name and instance
+    in this file.  We will use this information to fill out the p_user
+    and p_inst fields in the credential.
+
+    FIXME jcm - more kludges: make sure default user name matches the
+    current credentials cache.  Telnet asks for default user name.  It
+    may have last been set to another user name programmatically or
+    via ResEdit.
+
+ */
+int KRB5_CALLCONV
+in_tkt(pname,pinst)
+    char *pname;
+    char *pinst;
+{
+  int retval;
+	
+  strncpy (curr_auth_uname, pname, ANAME_SZ);
+  strncpy (curr_auth_uinst, pinst, INST_SZ);
+	
+  krb_set_default_user (pname);
+	
+  retval = dest_tkt();
+  if (!retval) 
+    return retval;
+  else 	
+    return KSUCCESS;
+	
+}
+
+int KRB5_CALLCONV
+krb_in_tkt(pname, pinst, prealm)
+    char *pname;
+    char *pinst;
+    char *prealm;
+{
+    return in_tkt(pname, pinst);
+}
+
+/*
+ * dest_tkt() is used to destroy the ticket store upon logout.
+ * If the ticket file does not exist, dest_tkt() returns RET_TKFIL.
+ * Otherwise the function returns RET_OK on success, KFAILURE on
+ * failure.
+ *
+ */
+int KRB5_CALLCONV
+dest_tkt()
+{
+ 	/* 	
+		FIXME jcm - Force one named cache for now for
+		compatibility with Cygnus source tree.  Figure out
+		later how to access the multiple cache functionality in
+		KClient.
+	*/
+	OSErr err;
+ 
+	err = DeleteSession(uname, uinstance, urealm);
+ 
+	change_cache();
+ 
+	switch(err) {
+		case noErr:	
+			return RET_OK;
+		case cKrbSessDoesntExist:
+			return RET_TKFIL;
+		default:
+			return KFAILURE;
+		}
+	}
+
+
+int	dest_all_tkts()		
+{
+	int	i=0;
+	char	name[ANAME_SZ], inst[INST_SZ], realm[REALM_SZ];
+	int ndeletes=0;
+	int err=0;
+
+	(void) GetNumSessions(&i);
+	if(!i) return RET_TKFIL;
+
+	for( ; i; i--) {
+		if(!GetNthSession(i, name, inst, realm)) {
+			if (err = DeleteSession(name, inst, realm))
+				break;
+			ndeletes++;
+			}
+		else {
+			err = KFAILURE;
+			break;
+			}
+		}
+
+	if (ndeletes > 0)
+		change_cache();
+
+	if (err)
+		return KFAILURE;
+	else
+		return KSUCCESS;
+	}
+
+
+/* krb_get_tf_realm -- return the realm of the current ticket file. */
+int KRB5_CALLCONV
+krb_get_tf_realm (tktfile, lrealm)
+	char *tktfile;
+	char *lrealm;		/* Result stored through here */
+{
+	
+	return krb_get_tf_fullname(tktfile, (char*) 0, (char*) 0 , lrealm);
+}
+
+
+/* krb_get_tf_fullname -- return name, instance and realm of the
+principal in the current ticket file. */
+int KRB5_CALLCONV
+krb_get_tf_fullname (tktfile, name, instance, realm)
+  char *tktfile;
+  char *name;
+  char *instance;
+  char *realm;
+  
+{
+	OSErr err;
+
+/* 
+	Explaining this ugly hack:
+	uname, uinstance, and urealm in the session record are "fixed" 
+	to short circuit multicache functionality, yielding only one 
+	session/cache for all cases.  This was done under protest to remain 
+	API compatable with UNIX. The principal's and service realm are 
+	always the same and are stored in the same field of the credential. 
+	Principal's name and instance are stored neither in the session 
+	record or the credentials cache but in the file static variables 
+	curr_auth_uname, and curr_auth_uinst as set by in_tkt from its 
+	arguments pname and pinst.  
+	
+   FIXME for multiple sessions -- keep track of which one is
+   the "current" session, as picked by the user.  tktfile not
+   used for anything right now...
+*/
+	   
+	err = GetNthCredentials(uname, uinstance, urealm, name,
+				instance, realm, 1);
+				
+	if (err != noErr) 
+		return NO_TKT_FIL;
+	
+	if (name)
+		strcpy(name, curr_auth_uname);	
+	if (instance)
+		strcpy(instance, curr_auth_uinst);
+
+	return KSUCCESS;
+	
+}
+
+
+/*
+ * krb_get_cred takes a service name, instance, and realm, and a
+ * structure of type CREDENTIALS to be filled in with ticket
+ * information.  It then searches the ticket file for the appropriate
+ * ticket and fills in the structure with the corresponding
+ * information from the file.  If successful, it returns KSUCCESS.
+ * On failure it returns a Kerberos error code.
+ */
+int KRB5_CALLCONV
+krb_get_cred (service, instance, realm, c)
+	char *service;		/* Service name */
+	char *instance;		/* Instance */
+	char *realm;		/* Authorization domain */
+	CREDENTIALS *c;		/* Credentials struct */
+{
+	strcpy(c->service, service);
+	strcpy(c->instance, instance);
+	strcpy(c->realm, realm);
+
+	/* 	
+		FIXME jcm - Force one named cache for now for
+		compatibility with Cygnus source tree.  Figure out
+		later how to access the multiple cache functionality
+		from KClient.
+	*/
+
+	switch(GetCredentials(uname, uinstance, urealm, c)) {
+		case noErr:
+			return KSUCCESS;
+		case cKrbCredsDontExist:
+		case cKrbSessDoesntExist: 
+			return GC_NOTKT;
+		default:
+			return KFAILURE;
+		}
+}
+
+/*
+ * This routine takes a ticket and associated info and 
+ * stores them in the ticket cache.  The peer
+ * routine for extracting a ticket and associated info from the
+ * ticket cache is krb_get_cred().  When changes are made to
+ * this routine, the corresponding changes should be made
+ * in krb_get_cred() as well.
+ *
+ * Returns KSUCCESS if all goes well, otherwise KFAILURE.
+ */
+
+int
+krb4int_save_credentials_addr(sname, sinst, srealm, session, 
+			      lifetime, kvno, ticket, issue_date, laddr)
+
+	char* sname;		/* Service name */
+	char* sinst;		/* Instance */	
+	char* srealm;		/* Auth domain */
+	C_Block session;	/* Session key */
+	int lifetime;		/* Lifetime */
+	int kvno;		/* Key version number */
+    	KTEXT ticket; 		/* The ticket itself */
+	long issue_date;	/* The issue time */
+	KRB_UINT32 laddr;
+{
+	CREDENTIALS	cr;
+
+	strcpy(cr.service, sname);
+	strcpy(cr.instance, sinst);
+	strcpy(cr.realm, srealm);
+	memcpy((void*)cr.session, (void*)session, sizeof(C_Block));
+	cr.lifetime = lifetime;
+	cr.kvno = kvno;
+	cr.ticket_st = *ticket;
+	cr.issue_date = issue_date;
+	strcpy(cr.pname, curr_auth_uname);	/* FIXME for mult sessions */
+	strcpy(cr.pinst, curr_auth_uinst);	/* FIXME for mult sessions */
+
+	if(AddCredentials(uname, uinstance, urealm, &cr)) return KFAILURE;
+	change_cache();
+	return KSUCCESS;
+}
+
+int KRB5_CALLCONV
+krb_save_credentials(
+    char	*name,
+    char	*inst,
+    char	*realm,
+    C_Block	session,
+    int		lifetime,
+    int		kvno,
+    KTEXT	ticket,
+    long	issue_date)
+{
+    return krb4int_save_credentials_addr(name, inst, realm, session,
+					 lifetime, kvno, ticket,
+					 issue_date, 0);
+}
+
+
+int
+krb_delete_cred (sname, sinstance, srealm)
+	char *sname;
+	char *sinstance;
+	char *srealm;
+{
+	
+    if (DeleteCredentials (uname, uinstance, urealm, sname, sinstance, srealm))
+	return KFAILURE;
+
+	change_cache();
+
+	return KSUCCESS;
+	
+  /*
+    FIXME jcm - translate better between KClient internal OSErr errors 
+    (eg. cKrbCredsDontExist) and kerberos error codes (eg. GC_NOTKT)
+    */
+}	
+
+int
+krb_get_nth_cred (sname, sinstance, srealm, n)
+	char *sname;
+	char *sinstance;
+	char *srealm;
+	int n;
+{	
+    if (GetNthCredentials(uname, uinstance, urealm, sname, sinstance, srealm, n))
+	return KFAILURE;
+    else
+	return KSUCCESS;
+}
+
+/*
+ * Return the number of credentials in the current credential cache (ticket cache).
+ * On error, returns -1. 
+ */
+int
+krb_get_num_cred ()
+{
+  int n;
+  int s;
+
+  s = GetNumCredentials(uname, uinstance, urealm, &n);
+  if (s) return -1;
+  else return n;
+}
+
+
+
+/* Lower level routines */
+
+OSErr	GetNumSessions(n)
+     int *n;
+{
+	*n = fNumSessions;
+	return 0;
+	}
+
+/* n starts at 1, not 0 */
+OSErr
+GetNthSession(n, name, instance, realm)
+     const int n;
+     char *name;
+     char *instance;
+     char *realm;
+{
+	Session	*sptr;
+
+	if(n > fNumSessions || !fSessions) return cKrbSessDoesntExist;
+
+	sptr = (*fSessions) + n-1;
+	if (name)	strcpy(name, sptr->name);
+	if (instance)	strcpy(instance, sptr->instance);
+	if (realm)	strcpy(realm, sptr->realm);
+
+	return noErr;
+	}
+
+OSErr	DeleteSession(name, instance, realm)
+     const char *name;
+     const char *instance;
+     const char *realm;
+{
+	int		i;
+	Session	*sptr;
+	Handle	creds;
+
+	if(!fNumSessions || !fSessions) return cKrbSessDoesntExist;
+
+	sptr = *fSessions;
+
+	for(i = 0; i < fNumSessions; i++) {
+		if(!strcmp(sptr[i].name, name) &&
+			!strcmp(sptr[i].instance, instance) &&
+			!strcmp(sptr[i].realm, realm)) {
+			break;
+			}
+		}
+
+	if(i == fNumSessions) return cKrbSessDoesntExist;
+
+	fNumSessions--;
+
+	creds = (Handle) sptr[i].creds;
+
+	for( ; i < fNumSessions; i++) {
+		strcpy(sptr[i].name, sptr[i+1].name);
+		strcpy(sptr[i].instance, sptr[i+1].instance);
+		strcpy(sptr[i].realm, sptr[i+1].realm);
+		}
+
+	SetHandleSize((Handle) fSessions, fNumSessions * sizeof(Session));
+	if(creds) DisposHandle(creds);
+
+	return MemError();
+	}
+
+OSErr	GetCredentials(name, instance, realm, cr)
+     const char *name;
+     const char *instance;
+     const char *realm;
+     CREDENTIALS *cr;
+{
+	int		i;
+	Session	*sptr;
+	CREDENTIALS	*cptr;
+	
+	if(!fNumSessions || !fSessions) return cKrbSessDoesntExist;
+
+	sptr = *fSessions;
+
+	for(i = 0; i < fNumSessions; i++) {
+		if(!strcmp(sptr[i].name, name) &&
+			!strcmp(sptr[i].instance, instance) &&
+			!strcmp(sptr[i].realm, realm)) {
+			break;
+			}
+		}
+
+	if(i == fNumSessions) return cKrbSessDoesntExist;
+
+	sptr = sptr + i;
+
+	if(!sptr->numcreds || !sptr->creds) return cKrbCredsDontExist;
+
+	cptr = *(sptr->creds);
+
+	for(i = 0; i < sptr->numcreds; i++) {
+		if(!strcmp(cptr[i].service, cr->service) &&
+			!strcmp(cptr[i].instance, cr->instance) &&
+			!strcmp(cptr[i].realm, cr->realm)) {
+			break;
+			}
+		}
+
+	if(i == sptr->numcreds) return cKrbCredsDontExist;
+
+	*cr = cptr[i];
+	return noErr;
+	}
+
+OSErr	AddCredentials(name, instance, realm, cr)
+     const char *name;
+     const char *instance;
+     const char *realm;
+     const CREDENTIALS *cr;
+{
+	Session	*sptr;
+	Handle	creds;
+	int		i, thesess;
+	CREDENTIALS	*cptr;
+
+	/* find the appropriate session, or create it if it doesn't exist */
+	if(!fSessions) {
+		fSessions = (Session**) NewHandleSys(0);
+		if(MemError()) return MemError();
+		fNumSessions = 0;
+		}
+
+	sptr = *fSessions;
+
+	for(thesess = 0; thesess < fNumSessions; thesess++) {
+		if(!strcmp(sptr[thesess].name, name) &&
+			!strcmp(sptr[thesess].instance, instance) &&
+			!strcmp(sptr[thesess].realm, realm)) {
+			break;
+			}
+		}
+
+	sptr = (*fSessions) + thesess;
+
+	if(thesess == fNumSessions) {	/* doesn't exist, create it */
+		fNumSessions++;
+		SetHandleSize((Handle) fSessions, fNumSessions * sizeof(Session));
+		if(MemError()) return MemError();
+
+		/* fSessions may have been moved, so redereference */
+		sptr = (*fSessions) + thesess;
+		strcpy(sptr->name, (char *)name);
+		strcpy(sptr->instance, (char *)instance);
+		strcpy(sptr->realm, (char *)realm);
+		sptr->numcreds = 0;
+		sptr->creds = 0;
+		}
+
+		/* if the session has no assoc creds, create storage for them so rest of algorithm
+			doesn't break */
+	if(!sptr->numcreds || !sptr->creds) {
+		creds = NewHandleSys((Size) 0);
+		if(MemError()) return MemError();
+
+		/* rederef */ 
+		sptr = (*fSessions) + thesess;
+		sptr->creds = (CREDENTIALS **)creds;
+		sptr->numcreds = 0;
+		}
+
+		/* find creds if we already have an instance of them, or create a new slot for them
+			if we don't */
+	cptr = *(sptr->creds);
+
+	for(i = 0; i < sptr->numcreds; i++) {
+		if(!strcmp(cptr[i].service, cr->service) &&
+			!strcmp(cptr[i].instance, cr->instance) &&
+			!strcmp(cptr[i].realm, cr->realm)) {
+			break;
+			}
+		}
+
+	if(i == sptr->numcreds) {
+		sptr->numcreds++;
+		SetHandleSize((Handle)sptr->creds, sptr->numcreds * sizeof(CREDENTIALS));
+		if(MemError()) return MemError();
+
+		/* rederef */
+		sptr = (*fSessions) + thesess;
+		cptr = *(sptr->creds);
+		}
+
+		/* store them (possibly replacing previous creds if they already exist) */
+	cptr[i] = *cr;
+	return noErr;
+	}
+
+OSErr
+DeleteCredentials (uname, uinst, urealm, sname, sinst, srealm)
+     const char *uname;
+     const char *uinst;
+     const char *urealm;
+     const char *sname;
+     const char *sinst;
+     const char *srealm;
+{
+	int		i;
+	Session	*sptr;
+	CREDENTIALS	*cptr;
+
+	if(!fNumSessions || !fSessions) return cKrbSessDoesntExist;
+
+	sptr = *fSessions;
+
+	for(i = 0; i < fNumSessions; i++) {
+		if(!strcmp(sptr[i].name, uname) &&
+			!strcmp(sptr[i].instance, uinstance) &&
+			!strcmp(sptr[i].realm, urealm)) {
+			break;
+			}
+		}
+
+	if(i == fNumSessions) return cKrbSessDoesntExist;
+
+	sptr = sptr + i;
+
+	if(!sptr->numcreds || !sptr->creds) return cKrbCredsDontExist;
+
+	cptr = *(sptr->creds);
+
+	for(i = 0; i < sptr->numcreds; i++) {
+		if(!strcmp(cptr[i].service, sname) &&
+			!strcmp(cptr[i].instance, sinst) &&
+			!strcmp(cptr[i].realm, srealm)) {
+			break;
+			}
+		}
+
+	if(i == sptr->numcreds) return cKrbCredsDontExist;
+
+	sptr->numcreds--;
+
+	for( ; i < sptr->numcreds; i++) {
+		cptr[i] = cptr[i+1];
+		}
+
+	SetHandleSize((Handle) sptr->creds, sptr->numcreds * sizeof(CREDENTIALS));
+
+	return MemError();
+	}
+
+OSErr	GetNumCredentials(name, instance, realm, n)
+     const char *name;
+     const char *instance;
+     const char *realm;
+     int *n;
+{
+	int		i;
+	Session	*sptr;
+
+	if(!fNumSessions || !fSessions) {
+		*n = 0;
+		return cKrbSessDoesntExist;
+		}
+
+	sptr = *fSessions;
+
+	for(i = 0; i < fNumSessions; i++) {
+		if(!strcmp(sptr[i].name, name) &&
+			!strcmp(sptr[i].instance, instance) &&
+			!strcmp(sptr[i].realm, realm)) {
+			break;
+			}
+		}
+
+	if(i == fNumSessions) {
+		*n = 0;
+		return cKrbCredsDontExist;
+		}
+
+	*n = sptr[i].numcreds;
+	return noErr;
+	}
+
+/* returns service name, service instance and realm of the nth credential. */
+/* n starts at 1, not 0 */
+OSErr
+GetNthCredentials(uname, uinstance, urealm, sname, sinst, srealm, n)
+     const char *uname;
+     const char *uinstance;
+     const char *urealm;
+     char *sname;
+     char *sinst;
+     char *srealm;
+     const int n;
+{
+	int		i;
+	Session	*sptr;
+	CREDENTIALS	*cptr;
+
+	if(!fNumSessions || !fSessions) return cKrbSessDoesntExist;
+
+	sptr = *fSessions;
+
+	for(i = 0; i < fNumSessions; i++) {
+		if(!strcmp(sptr[i].name, uname) &&
+			!strcmp(sptr[i].instance, uinstance) &&
+			!strcmp(sptr[i].realm, urealm)) {
+			break;
+			}
+		}
+
+	if(i == fNumSessions) return cKrbSessDoesntExist;
+
+	sptr = (*fSessions) + i;
+
+	if(n > sptr->numcreds || !sptr->creds) return cKrbCredsDontExist;
+
+	cptr = (*(sptr->creds)) + n-1;
+
+	/* 
+	   check for null pointers cuz. some callers don't provide  
+	   storage for all this info, eg. Kerb_get_tf_fullname. 
+	*/
+	
+	if (sname) 
+		strcpy(sname, cptr->service);
+	if (sinst)
+		strcpy(sinst, cptr->instance);
+	if (srealm)
+		strcpy(srealm, cptr->realm);
+	return noErr;
+}
diff --git a/mechglue/src/lib/krb4/memcache.h b/mechglue/src/lib/krb4/memcache.h
new file mode 100644
index 000000000..d6d04190b
--- /dev/null
+++ b/mechglue/src/lib/krb4/memcache.h
@@ -0,0 +1,36 @@
+/*
+	memcache.h
+		Kerberos credential store in memory
+		Originally coded by Tim Miller / Brown University
+		Mods 1/92 By Peter Bosanko
+
+		Modified May-June 1994 by Julia Menapace and John Gilmore,
+		Cygnus Support.
+*/
+
+struct Session {
+	char		name[ANAME_SZ];
+	char		instance[INST_SZ];
+	char		realm[REALM_SZ];
+	int		numcreds;
+	CREDENTIALS	**creds;
+};
+typedef struct Session Session;
+
+OSErr GetNumSessions(int *n);
+OSErr GetNthSession(const int n, char *name, char *instance, char *realm);
+OSErr DeleteSession(const char *name, const char *instance, const char *realm);
+OSErr GetCredentials(const char *name, const char *instance, const char *realm,
+		     CREDENTIALS *cr);	
+/* name, instance, and realm of service wanted should be set in *cr
+   before calling */
+OSErr AddCredentials(const char *name, const char *instance, const char *realm,
+		     const CREDENTIALS *cr);
+OSErr DeleteCredentials(const char *uname, const char *uinst,
+			const char *urealm, const char *sname,
+			const char *sinst, const char *srealm);
+OSErr GetNumCredentials(const char *name, const char *instance,
+			const char *realm, int *n);
+OSErr GetNthCredentials(const char *uname, const char *uinst,
+			const char *urealm, char *sname, char *sinst,
+			char *srealm, const int n);
diff --git a/mechglue/src/lib/krb4/mk_auth.c b/mechglue/src/lib/krb4/mk_auth.c
new file mode 100644
index 000000000..cf85ea2f8
--- /dev/null
+++ b/mechglue/src/lib/krb4/mk_auth.c
@@ -0,0 +1,249 @@
+/*
+ * lib/krb4/mk_auth.c
+ *
+ * Copyright 1987, 1988, 2000, 2001 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Derived from sendauth.c by John Gilmore, 10 October 1994.
+ */
+
+#include <stdio.h>
+#include "krb.h"
+#include "prot.h"
+#include <errno.h>
+#include <string.h>
+
+#define	KRB_SENDAUTH_VERS "AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN chars */
+/*
+ * If the protocol changes, you will need to change the version string
+ * and make appropriate changes in recvauth.c and sendauth.c.
+ */
+
+/*
+ * This file contains two routines: krb_mk_auth() and krb_check_auth().
+ *
+ * krb_mk_auth() packages a ticket for transmission to an application
+ * server.
+ *
+ * krb_krb_check_auth() validates a mutual-authentication response from
+ * the application server.
+ * 
+ * These routines are portable versions that implement a protocol
+ * compatible with the original Unix "sendauth".
+ */
+
+/*
+ * The first argument to krb_mk_auth() contains a bitfield of
+ * options (the options are defined in "krb.h"):
+ *
+ * KOPT_DONT_CANON	Don't canonicalize instance as a hostname.
+ *			(If this option is not chosen, krb_get_phost()
+ *			is called to canonicalize it.)
+ *
+ * KOPT_DONT_MK_REQ 	Don't request server ticket from Kerberos.
+ *			A ticket must be supplied in the "ticket"
+ *			argument.
+ *			(If this option is not chosen, and there
+ *			is no ticket for the given server in the
+ *			ticket cache, one will be fetched using
+ *			krb_mk_req() and returned in "ticket".)
+ *
+ * KOPT_DO_MUTUAL	Do mutual authentication, requiring that the
+ * 			receiving server return the checksum+1 encrypted
+ *			in the session key.  The mutual authentication
+ *			is done using krb_mk_priv() on the other side
+ *			(see "recvauth.c") and krb_rd_priv() on this
+ *			side.
+ *
+ * The "ticket" argument is used to store the new ticket
+ * from the krb_mk_req() call. If the KOPT_DONT_MK_REQ options is
+ * chosen, the ticket must be supplied in the "ticket" argument.
+ * The "service", "inst", and "realm" arguments identify the ticket.
+ * If "realm" is null, the local realm is used.
+ *
+ * The following argument is only needed if the KOPT_DO_MUTUAL option
+ * is chosen:
+ *
+ *   The "checksum" argument is a number that the server will add 1 to
+ *   to authenticate itself back to the client.
+ *
+ * The application protocol version number (of up to KRB_SENDAUTH_VLEN
+ * characters) is passed in "version".
+ *
+ * The ticket is packaged into a message in the buffer pointed to by
+ * the argument "buf".
+ *
+ * If all goes well, KSUCCESS is returned, otherwise some error code.
+ *
+ * The format of the message packaged to send to the application server is:
+ *
+ * Size			Variable		Field
+ * ----			--------		-----
+ *
+ * KRB_SENDAUTH_VLEN	KRB_SENDAUTH_VER	sendauth protocol
+ * bytes					version number
+ *
+ * KRB_SENDAUTH_VLEN	version			application protocol
+ * bytes					version number
+ *
+ * 4 bytes		ticket->length		length of ticket
+ *
+ * ticket->length	ticket->dat		ticket itself
+ */
+
+/*
+ * Build a "sendauth" packet compatible with Unix sendauth/recvauth.
+ */
+int KRB5_CALLCONV
+krb_mk_auth(options, ticket, service, inst, realm, checksum, version, buf)
+     long options;		/* bit-pattern of options */
+     KTEXT ticket;		/* where to put ticket (return); or
+				   supplied in case of KOPT_DONT_MK_REQ */
+     char *service;		/* service name */
+     char *inst;		/* instance (OUTPUT canonicalized) */
+     char *realm;		/* realm */
+     unsigned KRB4_32 checksum; /* checksum to include in request */
+     char *version;		/* version string */
+     KTEXT buf;			/* Output buffer to fill  */
+{
+    int rem;
+    char krb_realm[REALM_SZ];
+    char *phost;
+    int phostlen;
+    unsigned char *p;
+
+    rem = KSUCCESS;
+
+    /* get current realm if not passed in */
+    if (!realm) {
+	rem = krb_get_lrealm(krb_realm,1);
+	if (rem != KSUCCESS)
+	    return rem;
+	realm = krb_realm;
+    }
+
+    if (!(options & KOPT_DONT_CANON)) {
+	phost = krb_get_phost(inst);
+	phostlen = krb4int_strnlen(phost, INST_SZ) + 1;
+	if (phostlen <= 0 || phostlen > INST_SZ)
+	    return KFAILURE;
+	memcpy(inst, phost, (size_t)phostlen);
+    }
+
+    /* get the ticket if desired */
+    if (!(options & KOPT_DONT_MK_REQ)) {
+	rem = krb_mk_req(ticket, service, inst, realm, (KRB4_32)checksum);
+	if (rem != KSUCCESS)
+	    return rem;
+    }
+
+#ifdef ATHENA_COMPAT
+    /* this is only for compatibility with old servers */
+    if (options & KOPT_DO_OLDSTYLE) {
+	(void) sprintf(buf->dat,"%d ",ticket->length);
+	(void) write(fd, buf, strlen(buf));
+	(void) write(fd, (char *) ticket->dat, ticket->length);
+	return(rem);
+    }
+#endif /* ATHENA_COMPAT */
+
+    /* Check buffer size */
+    if (sizeof(buf->dat) < (KRB_SENDAUTH_VLEN + KRB_SENDAUTH_VLEN
+			    + 4 + ticket->length)
+	|| ticket->length < 0)
+	return KFAILURE;
+
+    /* zero the buffer */
+    memset(buf->dat, 0, sizeof(buf->dat));
+    p = buf->dat;
+
+    /* insert version strings */
+    strncpy((char *)p, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN);
+    p += KRB_SENDAUTH_VLEN;
+    strncpy((char *)p, version, KRB_SENDAUTH_VLEN);
+    p += KRB_SENDAUTH_VLEN;
+
+    /* put ticket length into buffer */
+    KRB4_PUT32BE(p, ticket->length);
+
+    /* put ticket into buffer */
+    memcpy(p, ticket->dat, (size_t)ticket->length);
+    p += ticket->length;
+
+    buf->length = p - buf->dat;
+    return KSUCCESS;
+}
+
+/*
+ * For mutual authentication using mk_auth, check the server's response
+ * to validate that we're really talking to the server which holds the
+ * key that we obtained from the Kerberos key server.
+ *
+ * The "buf" argument is the response we received from the app server.
+ * The "checksum" argument is a number that the server has added 1 to
+ * to authenticate itself back to the client (us); the "msg_data" argument
+ * returns the returned mutual-authentication message from the server
+ * (i.e., the checksum+1); "session" holds the
+ * session key of the server, extracted from the ticket file, for use
+ * in decrypting the mutual authentication message from the server;
+ * and "schedule" returns the key schedule for that decryption.  The
+ * the local and server addresses are given in "laddr" and "faddr".
+ */
+int KRB5_CALLCONV
+krb_check_auth (buf, checksum, msg_data, session, schedule, laddr, faddr)
+     KTEXT buf;			/* The response we read from app server */
+     unsigned KRB4_32 checksum; /* checksum we included in request */
+     MSG_DAT *msg_data;	/* mutual auth MSG_DAT (return) */
+     C_Block session;		/* credentials (input) */
+     Key_schedule schedule;	/* key schedule (return) */
+     struct sockaddr_in *laddr;	/* local address */
+     struct sockaddr_in *faddr;	/* address of foreign host on fd */
+{
+    int cc;
+    unsigned KRB4_32 cksum;
+    unsigned char *p;
+
+    /* decrypt it */
+#ifndef NOENCRYPTION
+    key_sched(session, schedule);
+#endif /* !NOENCRYPTION */
+    if (buf->length < 0)
+	return KFAILURE;
+    cc = krb_rd_priv(buf->dat, (unsigned KRB4_32)buf->length, schedule,
+		     (C_Block *)session, faddr, laddr, msg_data);
+    if (cc)
+	return cc;
+
+    /*
+     * Fetch the (incremented) checksum that we supplied in the
+     * request.
+     */
+    if (msg_data->app_length < 4)
+	return KFAILURE;
+    p = msg_data->app_data;
+    KRB4_GET32BE(cksum, p);
+
+    /* if it doesn't match, fail -- reply wasn't from our real server.  */
+    if (cksum != checksum + 1)
+	return KFAILURE;	/* XXX */
+    return KSUCCESS;
+}
diff --git a/mechglue/src/lib/krb4/mk_err.c b/mechglue/src/lib/krb4/mk_err.c
new file mode 100644
index 000000000..5eeca1bdb
--- /dev/null
+++ b/mechglue/src/lib/krb4/mk_err.c
@@ -0,0 +1,83 @@
+/*
+ * lib/krb4/mk_err.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+
+/*
+ * This routine creates a general purpose error reply message.  It
+ * doesn't use KTEXT because application protocol may have long
+ * messages, and may want this part of buffer contiguous to other
+ * stuff.
+ *
+ * The error reply is built in "p", using the error code "e" and
+ * error text "e_string" given.  The length of the error reply is
+ * returned.
+ *
+ * The error reply is in the following format:
+ *
+ * unsigned char	KRB_PROT_VERSION	protocol version no.
+ * unsigned char	AUTH_MSG_APPL_ERR	message type
+ * (least significant
+ * bit of above)	HOST_BYTE_ORDER		local byte order
+ * 4 bytes		e			given error code
+ * string		e_string		given error text
+ */
+
+long KRB5_CALLCONV
+krb_mk_err(p, e, e_string)
+    u_char *p;		/* Where to build error packet */
+    KRB4_32 e;			/* Error code */
+    char *e_string;		/* Text of error */
+{
+    u_char      *start;
+    size_t	e_len;
+
+    e_len = strlen(e_string) + 1;
+
+    /* Just return the buffer length if p is NULL, because writing to the
+     * buffer would be a bad idea.  Note that this feature is a change from
+     * previous versions, and can therefore only be used safely in this
+     * source tree, where we know this function supports it. */
+    if (p == NULL) {
+        return 1 + 1 + 4 + e_len;
+    }
+
+    start = p;
+
+    /* Create fixed part of packet */
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_APPL_ERR;
+
+    /* Add the basic info */
+    KRB4_PUT32BE(p, e);
+    memcpy(p, e_string, e_len); /* err text */
+    p += e_len;
+
+    /* And return the length */
+    return p - start;
+}
diff --git a/mechglue/src/lib/krb4/mk_preauth.c b/mechglue/src/lib/krb4/mk_preauth.c
new file mode 100644
index 000000000..342654ada
--- /dev/null
+++ b/mechglue/src/lib/krb4/mk_preauth.c
@@ -0,0 +1,78 @@
+/* mk_preauth.c */
+/* part of Cygnus Network Security */
+/* Copyright 1994 Cygnus Support */
+/*
+ * Permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation.
+ * Cygnus Support makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include <string.h>
+
+#include "krb5/autoconf.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc(), *calloc(), *realloc();
+#endif
+
+int
+krb_mk_preauth(preauth_p, preauth_len,
+	       key_proc, aname, inst, realm, password, key)
+    char **preauth_p;
+    int  *preauth_len;
+    key_proc_type key_proc;
+    char *aname;
+    char *inst;
+    char *realm;
+    char *password;
+    C_Block key;
+{
+#ifdef NOENCRYPTION
+    *preauth_len = strlen(aname) + 1; /* include the trailing 0 */
+    *preauth_p = malloc(*preauth_len);
+    strcpy(*preauth_p, aname);	/* this will copy the trailing 0 */
+#else
+    des_key_schedule key_s;
+    int sl = strlen(aname);
+#endif
+
+    (*key_proc)(aname, inst, realm, password, key);
+
+#ifndef NOENCRYPTION
+    /* 
+     * preauth_len is set to a length greater than sl + 1 
+     * and a multpile of 8
+     */
+    *preauth_len = (((sl + 1) / 8) + 1) * 8;
+    /* allocate memory for preauth_p and fill it with 0 */
+    *preauth_p = malloc((size_t)*preauth_len);
+    /* create the key schedule */
+    if (des_key_sched(key, key_s)) {
+	return 1;
+    }
+    /* 
+     * encrypt aname using key_s as the key schedule and key as the
+     * initialization vector.
+     */
+    des_pcbc_encrypt((des_cblock *)aname, (des_cblock *)*preauth_p,
+		     (long)(sl + 1), key_s, (des_cblock *)key, DES_ENCRYPT);
+    memset(key_s, 0, sizeof(key_s));
+#endif
+    return 0;
+}
+
+void
+krb_free_preauth(preauth_p, preauth_len)
+     char *preauth_p;
+     int preauth_len;
+{
+    free(preauth_p);
+    return;
+}
diff --git a/mechglue/src/lib/krb4/mk_priv.c b/mechglue/src/lib/krb4/mk_priv.c
new file mode 100644
index 000000000..470ad9473
--- /dev/null
+++ b/mechglue/src/lib/krb4/mk_priv.c
@@ -0,0 +1,301 @@
+/*
+ * lib/krb4/mk_priv.c
+ *
+ * Copyright 1986, 1987, 1988, 2000 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * This routine constructs a Kerberos 'private msg', i.e.
+ * cryptographically sealed with a private session key.
+ *
+ * Returns either < 0 ===> error, or resulting size of message
+ *
+ * Steve Miller    Project Athena  MIT/DEC
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "krb.h"
+#include "prot.h"
+#include "des.h"
+#include "lsb_addr_cmp.h"
+#include "port-sockets.h"
+
+extern int krb_debug;
+
+/*
+ * krb_mk_priv() constructs an AUTH_MSG_PRIVATE message.  It takes
+ * some user data "in" of "length" bytes and creates a packet in "out"
+ * consisting of the user data, a timestamp, and the sender's network
+ * address.
+#ifndef NOENCRYTION
+ * The packet is encrypted by pcbc_encrypt(), using the given
+ * "key" and "schedule".
+#endif
+ * The length of the resulting packet "out" is
+ * returned.
+ *
+ * It is similar to krb_mk_safe() except for the additional key
+ * schedule argument "schedule" and the fact that the data is encrypted
+ * rather than appended with a checksum.  Also, the protocol version
+ * number is "private_msg_ver", defined in krb_rd_priv.c, rather than
+ * KRB_PROT_VERSION, defined in "krb.h".
+ *
+ * The "out" packet consists of:
+ *
+ * Size			Variable		Field
+ * ----			--------		-----
+ *
+ * 1 byte		private_msg_ver		protocol version number
+ * 1 byte		AUTH_MSG_PRIVATE |	message type plus local
+ *			HOST_BYTE_ORDER		byte order in low bit
+ *
+#ifdef NOENCRYPTION
+ * 4 bytes		c_length		length of data
+#else
+ * 4 bytes		c_length		length of encrypted data
+ *
+ * ===================== begin encrypt ================================
+#endif
+ * 
+ * 4 bytes		length			length of user data
+ * length		in			user data
+ * 1 byte		msg_time_5ms		timestamp milliseconds
+ * 4 bytes		sender->sin.addr.s_addr	sender's IP address
+ *
+ * 4 bytes		msg_time_sec or		timestamp seconds with
+ *			-msg_time_sec		direction in sign bit
+ *
+ * 0<=n<=7  bytes	pad to 8 byte multiple	zeroes
+#ifndef NOENCRYPTION
+ *			(done by pcbc_encrypt())
+ *
+ * ======================= end encrypt ================================
+#endif
+ */
+
+/* Utility function:
+
+   Determine order of addresses, if SENDER less than RECEIVER return 1
+   so caller will negate timestamp.  Return -1 for failure.  */
+int
+krb4int_address_less (struct sockaddr_in *sender, struct sockaddr_in *receiver)
+{
+    unsigned long sender_addr, receiver_addr;
+    unsigned short sender_port, receiver_port;
+    switch (sender->sin_family) {
+    case AF_INET:
+	sender_addr = sender->sin_addr.s_addr;
+	sender_port = sender->sin_port;
+	break;
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+    {
+	struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sender;
+	if (IN6_IS_ADDR_V4MAPPED (&s6->sin6_addr)) {
+	    struct sockaddr_in sintmp = { 0 };
+	    memcpy (&sintmp.sin_addr.s_addr,
+		    12+(char*)&s6->sin6_addr.s6_addr,
+		    4);
+	    sender_addr = sintmp.sin_addr.s_addr;
+	} else
+	    return -1;
+	sender_port = s6->sin6_port;
+	break;
+    }
+#endif
+    default:
+	return -1;
+    }
+    switch (receiver->sin_family) {
+    case AF_INET:
+	receiver_addr = receiver->sin_addr.s_addr;
+	receiver_port = receiver->sin_port;
+	break;
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+    {
+	struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) receiver;
+	if (IN6_IS_ADDR_V4MAPPED (&s6->sin6_addr)) {
+	    struct sockaddr_in sintmp = { 0 };
+	    memcpy (&sintmp.sin_addr.s_addr,
+		    12+(char*)&s6->sin6_addr.s6_addr,
+		    4);
+	    receiver_addr = sintmp.sin_addr.s_addr;
+	} else
+	    return -1;
+	receiver_port = s6->sin6_port;
+	break;
+    }
+#endif
+    default:
+	return -1;
+    }
+    /* For compatibility with broken old code, compares are done in
+       VAX byte order (LSBFIRST).  */
+    if (lsb_net_ulong_less(sender_addr, receiver_addr) == -1
+	|| (lsb_net_ulong_less(sender_addr, receiver_addr) == 0
+	    && lsb_net_ushort_less(sender_port, receiver_port) == -1))
+	return 1;
+    return 0;
+    /*
+     * all that for one tiny bit!  Heaven help those that talk to
+     * themselves.
+     */
+}
+
+long KRB5_CALLCONV
+krb_mk_priv(in, out, length, schedule, key, sender, receiver)
+    u_char *in;		/* application data */
+    u_char *out;		/* put msg here, leave room for
+				 * header! breaks if in and out
+				 * (header stuff) overlap */
+    unsigned KRB4_32 length;	/* of in data */
+    Key_schedule schedule;	/* precomputed key schedule */
+    C_Block *key;		/* encryption key for seed and ivec */
+    struct sockaddr_in *sender;   /* sender address */
+    struct sockaddr_in *receiver; /* receiver address */
+{
+    register u_char     *p,*q;
+    u_char *c_length_ptr;
+    extern int private_msg_ver; /* in krb_rd_priv.c */
+
+    unsigned KRB4_32 c_length, c_length_raw;
+    u_char msg_time_5ms;
+    unsigned KRB4_32 msg_time_sec;
+    unsigned KRB4_32 msg_time_usec;
+
+    /* Be really paranoid. */
+    if (sizeof(sender->sin_addr.s_addr) != 4)
+	return -1;
+    /*
+     * get the current time to use instead of a sequence #, since
+     * process lifetime may be shorter than the lifetime of a session
+     * key.
+     */
+    msg_time_sec = TIME_GMT_UNIXSEC_US(&msg_time_usec);
+    msg_time_5ms = msg_time_usec / 5000; /* 5ms quanta */
+
+    p = out;
+
+    /* Cruftiness below! */
+    *p++ = private_msg_ver ? private_msg_ver : KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_PRIVATE;
+
+    /* save ptr to cipher length */
+    c_length_ptr = p;
+    p += 4;
+
+#ifndef NOENCRYPTION
+    /* start for encrypted stuff */
+#endif
+    q = p;
+
+    /* stuff input length */
+    KRB4_PUT32BE(p, length);
+
+#ifdef NOENCRYPTION
+    /* make all the stuff contiguous for checksum */
+#else
+    /* make all the stuff contiguous for checksum and encryption */
+#endif
+    memcpy(p, in, (size_t)length);
+    p += length;
+
+    /* stuff time 5ms */
+    *p++ = msg_time_5ms;
+
+    /* stuff source address */
+    if (sender->sin_family == AF_INET)
+	memcpy(p, &sender->sin_addr.s_addr, sizeof(sender->sin_addr.s_addr));
+#ifdef KRB5_USE_INET6
+    else if (sender->sin_family == AF_INET6
+	     && IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr))
+	memcpy(p, 12+(char*)&((struct sockaddr_in6 *)sender)->sin6_addr, 4);
+#endif
+    else
+	/* The address isn't one we can encode in 4 bytes -- but
+	   that's okay if the receiver doesn't care.  */
+	memset(p, 0, 4);
+    p += sizeof(sender->sin_addr.s_addr);
+
+    /*
+     * direction bit is the sign bit of the timestamp.  Ok
+     * until 2038??
+     */
+    switch (krb4int_address_less (sender, receiver)) {
+    case 1:
+	msg_time_sec = -msg_time_sec;
+	break;
+    case -1:
+	/* Which way should we go in this case?  */
+    case 0:
+	break;
+    }
+
+    /* stuff time sec */
+    KRB4_PUT32BE(p, msg_time_sec);
+
+    /*
+     * All that for one tiny bit!  Heaven help those that talk to
+     * themselves.
+     */
+
+#ifdef notdef
+    /*
+     * calculate the checksum of the length, address, sequence, and
+     * inp data
+     */
+    cksum = quad_cksum(q,NULL,p-q,0,key);
+    DEB (("\ncksum = %u",cksum));
+    /* stuff checksum */
+    memcpy(p, &cksum, sizeof(cksum));
+    p += sizeof(cksum);
+#endif
+
+#ifdef NOENCRYPTION
+    /*
+     * All the data have been assembled, compute length
+     */
+#else
+    /*
+     * All the data have been assembled, compute length and encrypt
+     * starting with the length, data, and timestamps use the key as
+     * an ivec.
+     */
+#endif
+
+    c_length_raw = p - q;
+    c_length = ((c_length_raw + sizeof(C_Block) -1)
+		/ sizeof(C_Block)) * sizeof(C_Block);
+    /* stuff the length */
+    p = c_length_ptr;
+    KRB4_PUT32BE(p, c_length);
+
+#ifndef NOENCRYPTION
+    /* pcbc encrypt, pad as needed, use key as ivec */
+    pcbc_encrypt((C_Block *)q,(C_Block *)q, (long)c_length_raw,
+		 schedule, key, ENCRYPT);
+#endif /* NOENCRYPTION */
+
+    return q - out + c_length;	/* resulting size */
+}
diff --git a/mechglue/src/lib/krb4/mk_req.c b/mechglue/src/lib/krb4/mk_req.c
new file mode 100644
index 000000000..3066f43d7
--- /dev/null
+++ b/mechglue/src/lib/krb4/mk_req.c
@@ -0,0 +1,281 @@
+/*
+ * lib/krb4/mk_req.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000, 2002 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include "des.h"
+#include <string.h>
+#include "krb4int.h"
+
+extern int krb_ap_req_debug;
+static int lifetime = 255;		/* Default based on the TGT */
+
+static int krb_mk_req_creds_prealm(KTEXT, CREDENTIALS *, KRB4_32, char *);
+
+/*
+ * krb_mk_req takes a text structure in which an authenticator is to
+ * be built, the name of a service, an instance, a realm,
+ * and a checksum.  It then retrieves a ticket for
+ * the desired service and creates an authenticator in the text
+ * structure passed as the first argument.  krb_mk_req returns
+ * KSUCCESS on success and a Kerberos error code on failure.
+ *
+ * The peer procedure on the other end is krb_rd_req.  When making
+ * any changes to this routine it is important to make corresponding
+ * changes to krb_rd_req.
+ *
+ * The authenticator consists of the following:
+ *
+ * authent->dat
+ *
+ * unsigned char	KRB_PROT_VERSION	protocol version no.
+ * unsigned char	AUTH_MSG_APPL_REQUEST	message type
+ * (least significant
+ * bit of above)	HOST_BYTE_ORDER		local byte ordering
+ * unsigned char	kvno from ticket	server's key version
+ * string		realm			server's realm
+ * unsigned char	tl			ticket length
+ * unsigned char	idl			request id length
+ * text			ticket->dat		ticket for server
+ * text			req_id->dat		request id
+ *
+ * The ticket information is retrieved from the ticket cache or
+ * fetched from Kerberos.  The request id (called the "authenticator"
+#ifdef NOENCRYPTION
+ * in the papers on Kerberos) contains the following:
+#else
+ * in the papers on Kerberos) contains information encrypted in the session
+ * key for the client and ticket-granting service:  {req_id}Kc,tgs
+ * Before encryption, it contains the following:
+#endif
+ *
+ * req_id->dat
+ *
+ * string		cr.pname		{name, instance, and
+ * string		cr.pinst		realm of principal
+ * string		myrealm			making this request}
+ * 4 bytes		checksum		checksum argument given
+ * unsigned char	time_usecs		time (microseconds)
+ * 4 bytes		time_secs		time (seconds)
+ *
+ * req_id->length = 3 strings + 3 terminating nulls + 5 bytes for time,
+ *                  all rounded up to multiple of 8.
+ */
+
+static int
+krb_mk_req_creds_prealm(authent, creds, checksum, myrealm)
+    register	KTEXT authent;	/* Place to build the authenticator */
+    CREDENTIALS	*creds;
+    KRB4_32	checksum;	/* Checksum of data (optional) */
+    char	*myrealm;	/* Client's realm */
+{
+    KTEXT_ST req_st; /* Temp storage for req id */
+    KTEXT req_id = &req_st;
+    unsigned char *p, *q, *reqid_lenp;
+    int tl;			/* Tkt len */
+    int idl;			/* Reqid len */
+    register KTEXT ticket;	/* Pointer to tkt_st */
+    Key_schedule  key_s;
+    size_t realmlen, pnamelen, pinstlen, myrealmlen;
+    unsigned KRB4_32 time_secs;
+    unsigned KRB4_32 time_usecs;
+
+    ticket = &creds->ticket_st;
+    /* Get the ticket and move it into the authenticator */
+    if (krb_ap_req_debug)
+        DEB (("Realm: %s\n", creds->realm));
+
+    realmlen = strlen(creds->realm) + 1;
+    if (sizeof(authent->dat) < (1 + 1 + 1
+				+ realmlen
+				+ 1 + 1 + ticket->length)
+	|| ticket->length < 0 || ticket->length > 255) {
+	authent->length = 0;
+	return KFAILURE;
+    }
+
+    if (krb_ap_req_debug)
+        DEB (("%s %s %s %s %s\n", creds->service, creds->instance,
+	      creds->realm, creds->pname, creds->pinst));
+
+    p = authent->dat;
+
+    /* The fixed parts of the authenticator */
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_APPL_REQUEST;
+    *p++ = creds->kvno;
+
+    memcpy(p, creds->realm, realmlen);
+    p += realmlen;
+
+    tl = ticket->length;
+    *p++ = tl;
+    /* Save ptr to where req_id->length goes. */
+    reqid_lenp = p;
+    p++;
+    memcpy(p, ticket->dat, (size_t)tl);
+    p += tl;
+
+    if (krb_ap_req_debug)
+        DEB (("Ticket->length = %d\n",ticket->length));
+    if (krb_ap_req_debug)
+        DEB (("Issue date: %d\n",creds->issue_date));
+
+    pnamelen = strlen(creds->pname) + 1;
+    pinstlen = strlen(creds->pinst) + 1;
+    myrealmlen = strlen(myrealm) + 1;
+    if (sizeof(req_id->dat) / 8 < (pnamelen + pinstlen + myrealmlen
+				   + 4 + 1 + 4 + 7) / 8) {
+	return KFAILURE;
+    }
+
+    q = req_id->dat;
+
+    /* Build request id */
+    /* Auth name */
+    memcpy(q, creds->pname, pnamelen);
+    q += pnamelen;
+    /* Principal's instance */
+    memcpy(q, creds->pinst, pinstlen);
+    q += pinstlen;    
+    /* Authentication domain */
+    memcpy(q, myrealm, myrealmlen);
+    q += myrealmlen;
+    /* Checksum */
+    KRB4_PUT32BE(q, checksum);
+
+    /* Fill in the times on the request id */
+    time_secs = TIME_GMT_UNIXSEC_US (&time_usecs);
+    *q++ = time_usecs;		/* time_usecs % 255 */
+    /* Time (coarse) */
+    KRB4_PUT32BE(q, time_secs);
+
+    /* Fill to a multiple of 8 bytes for DES */
+    req_id->length = ((q - req_id->dat + 7) / 8) * 8;
+
+#ifndef NOENCRYPTION
+    /* Encrypt the request ID using the session key */
+    key_sched(creds->session, key_s);
+    pcbc_encrypt((C_Block *)req_id->dat, (C_Block *)req_id->dat,
+                 (long)req_id->length, key_s, &creds->session, 1);
+    /* clean up */
+    memset(key_s, 0, sizeof(key_s));
+#endif /* NOENCRYPTION */
+
+    /* Copy it into the authenticator */
+    idl = req_id->length;
+    if (idl > 255)
+	return KFAILURE;
+    *reqid_lenp = idl;
+    memcpy(p, req_id->dat, (size_t)idl);
+    p += idl;
+
+    authent->length = p - authent->dat;
+
+    /* clean up */
+    memset(req_id, 0, sizeof(*req_id));
+
+    if (krb_ap_req_debug)
+        DEB (("Authent->length = %d\n",authent->length));
+    if (krb_ap_req_debug)
+        DEB (("idl = %d, tl = %d\n", idl, tl));
+
+    return KSUCCESS;
+}
+
+int KRB5_CALLCONV
+krb_mk_req(authent, service, instance, realm, checksum)
+    register	KTEXT authent;	/* Place to build the authenticator */
+    char	*service;	/* Name of the service */
+    char	*instance;	/* Service instance */
+    char	*realm;	/* Authentication domain of service */
+    KRB4_32	checksum;	/* Checksum of data (optional) */
+{
+    char krb_realm[REALM_SZ];	/* Our local realm, if not specified */
+    char myrealm[REALM_SZ];	/* Realm of initial TGT. */
+    int retval;
+    CREDENTIALS creds;
+
+    /* get current realm if not passed in */
+    if (realm == NULL) {
+	retval = krb_get_lrealm(krb_realm, 1);
+	if (retval != KSUCCESS)
+	    return retval;
+	realm = krb_realm;
+    }
+    /*
+     * Determine realm of these tickets.  We will send this to the
+     * KDC from which we are requesting tickets so it knows what to
+     * with our session key.
+     */
+    retval = krb_get_tf_realm(TKT_FILE, myrealm);
+    if (retval != KSUCCESS)
+	retval = krb_get_lrealm(myrealm, 1);
+    if (retval != KSUCCESS)
+	return retval;
+
+    retval = krb_get_cred(service, instance, realm, &creds);
+    if (retval == RET_NOTKT) {
+	retval = get_ad_tkt(service, instance, realm, lifetime);
+        if (retval)
+            return retval;
+	retval = krb_get_cred(service, instance, realm, &creds);
+        if (retval)
+	    return retval;
+    }
+    if (retval != KSUCCESS)
+	return retval;
+
+    retval = krb_mk_req_creds_prealm(authent, &creds, checksum, myrealm);
+    memset(&creds.session, 0, sizeof(creds.session));
+    return retval;
+}
+
+int KRB5_CALLCONV
+krb_mk_req_creds(authent, creds, checksum)
+    register	KTEXT authent;	/* Place to build the authenticator */
+    CREDENTIALS	*creds;
+    KRB4_32	checksum;	/* Checksum of data (optional) */
+{
+    return krb_mk_req_creds_prealm(authent, creds, checksum, creds->realm);
+}
+
+/* 
+ * krb_set_lifetime sets the default lifetime for additional tickets
+ * obtained via krb_mk_req().
+ * 
+ * It returns the previous value of the default lifetime.
+ */
+
+int KRB5_CALLCONV
+krb_set_lifetime(newval)
+int newval;
+{
+    int olife = lifetime;
+
+    lifetime = newval;
+    return olife;
+}
diff --git a/mechglue/src/lib/krb4/mk_safe.c b/mechglue/src/lib/krb4/mk_safe.c
new file mode 100644
index 000000000..2a157caad
--- /dev/null
+++ b/mechglue/src/lib/krb4/mk_safe.c
@@ -0,0 +1,167 @@
+/*
+ * lib/krb4/mk_req.c
+ *
+ * Copyright 1986, 1987, 1988, 2000 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * This routine constructs a Kerberos 'safe msg', i.e. authenticated
+ * using a private session key to seed a checksum. Msg is NOT
+ * encrypted.
+ *
+ * Returns either <0 ===> error, or resulting size of message
+ *
+ * Steve Miller    Project Athena  MIT/DEC
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "krb.h"
+#include "des.h"
+#include "prot.h"
+#include "lsb_addr_cmp.h"
+#include "port-sockets.h"
+
+extern int krb_debug;
+
+/*
+ * krb_mk_safe() constructs an AUTH_MSG_SAFE message.  It takes some
+ * user data "in" of "length" bytes and creates a packet in "out"
+ * consisting of the user data, a timestamp, and the sender's network
+ * address, followed by a checksum computed on the above, using the
+ * given "key".  The length of the resulting packet is returned.
+ *
+ * The "out" packet consists of:
+ *
+ * Size			Variable		Field
+ * ----			--------		-----
+ *
+ * 1 byte		KRB_PROT_VERSION	protocol version number
+ * 1 byte		AUTH_MSG_SAFE |		message type plus local
+ *			HOST_BYTE_ORDER		byte order in low bit
+ *
+ * ===================== begin checksum ================================
+ * 
+ * 4 bytes		length			length of user data
+ * length		in			user data
+ * 1 byte		msg_time_5ms		timestamp milliseconds
+ * 4 bytes		sender->sin.addr.s_addr	sender's IP address
+ *
+ * 4 bytes		msg_time_sec or		timestamp seconds with
+ *			-msg_time_sec		direction in sign bit
+ *
+ * ======================= end checksum ================================
+ *
+ * 16 bytes		big_cksum		quadratic checksum of
+ *						above using "key"
+ */
+
+long KRB5_CALLCONV
+krb_mk_safe(in, out, length, key, sender, receiver)
+    u_char *in;			/* application data */
+    u_char *out;		/*
+				 * put msg here, leave room for header!
+				 * breaks if in and out (header stuff)
+				 * overlap
+				 */
+    unsigned KRB4_32 length;	/* of in data */
+    C_Block *key;		/* encryption key for seed and ivec */
+    struct sockaddr_in *sender;	/* sender address */
+    struct sockaddr_in *receiver; /* receiver address */
+{
+    register u_char     *p,*q;
+
+    unsigned KRB4_32 cksum;
+    unsigned KRB4_32 big_cksum[4];
+    unsigned KRB4_32 msg_secs;
+    unsigned KRB4_32 msg_usecs;
+    u_char msg_time_5ms;
+    KRB4_32 msg_time_sec;
+    int i;
+
+    /* Be really paranoid. */
+    if (sizeof(sender->sin_addr.s_addr) != 4)
+	return -1;
+    /*
+     * get the current time to use instead of a sequence #, since
+     * process lifetime may be shorter than the lifetime of a session
+     * key.
+     */
+    msg_secs = TIME_GMT_UNIXSEC_US(&msg_usecs);
+    msg_time_sec = msg_secs;
+    msg_time_5ms = msg_usecs / 5000; /* 5ms quanta */
+
+    p = out;
+
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_SAFE;
+
+    q = p;			/* start for checksum stuff */
+    /* stuff input length */
+    KRB4_PUT32BE(p, length);
+
+    /* make all the stuff contiguous for checksum */
+    memcpy(p, in, length);
+    p += length;
+
+    /* stuff time 5ms */
+    *p++ = msg_time_5ms;
+
+    /* stuff source address */
+    if (sender->sin_family == AF_INET)
+	memcpy(p, &sender->sin_addr.s_addr, sizeof(sender->sin_addr.s_addr));
+#ifdef KRB5_USE_INET6
+    else if (sender->sin_family == AF_INET6
+	     && IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr))
+	memcpy(p, 12+(char*)&((struct sockaddr_in6 *)sender)->sin6_addr, 4);
+#endif
+    else
+	/* The address isn't one we can encode in 4 bytes -- but
+	   that's okay if the receiver doesn't care.  */
+	memset(p, 0, 4);
+    p += sizeof(sender->sin_addr.s_addr);
+
+    /*
+     * direction bit is the sign bit of the timestamp.  Ok until
+     * 2038??
+     */
+    if (krb4int_address_less (sender, receiver) == 1)
+	msg_time_sec = -msg_time_sec;
+    /* stuff time sec */
+    KRB4_PUT32BE(p, msg_time_sec);
+
+#ifdef NOENCRYPTION
+    cksum = 0;
+    memset(big_cksum, 0, sizeof(big_cksum));
+#else /* Do encryption */
+    /* calculate the checksum of length, timestamps, and input data */
+    cksum = quad_cksum(q, (unsigned KRB4_32 *)big_cksum,
+		       p - q, 2, key);
+#endif /* NOENCRYPTION */
+    DEB(("\ncksum = %u",cksum));
+
+    /* stuff checksum */
+    for (i = 0; i < 4; i++)
+	KRB4_PUT32BE(p, big_cksum[i]);
+
+    return p - out;		/* resulting size */
+}
diff --git a/mechglue/src/lib/krb4/month_sname.c b/mechglue/src/lib/krb4/month_sname.c
new file mode 100644
index 000000000..48be89e53
--- /dev/null
+++ b/mechglue/src/lib/krb4/month_sname.c
@@ -0,0 +1,28 @@
+/*
+ * month_sname.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+/*
+ * Given an integer 1-12, month_sname() returns a string
+ * containing the first three letters of the corresponding
+ * month.  Returns 0 if the argument is out of range.
+ */
+
+#include <krb.h>
+#include "krb4int.h"
+
+const char *month_sname(n)
+    int n;
+{
+    static const char name[][4] = {
+        "Jan","Feb","Mar","Apr","May","Jun",
+        "Jul","Aug","Sep","Oct","Nov","Dec"
+    };
+    return((n < 1 || n > 12) ? 0 : name [n-1]);
+}
diff --git a/mechglue/src/lib/krb4/netread.c b/mechglue/src/lib/krb4/netread.c
new file mode 100644
index 000000000..87ead207f
--- /dev/null
+++ b/mechglue/src/lib/krb4/netread.c
@@ -0,0 +1,69 @@
+/*
+ * lib/krb4/netwrite.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <errno.h>
+#include "krb.h"
+#include "krb5/autoconf.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "port-sockets.h"
+
+/*
+ * krb_net_read() reads from the file descriptor "fd" to the buffer
+ * "buf", until either 1) "len" bytes have been read or 2) cannot
+ * read anymore from "fd".  It returns the number of bytes read
+ * or a read() error.  (The calling interface is identical to
+ * read(2).)
+ *
+ * XXX must not use non-blocking I/O
+ */
+int
+krb_net_read(fd, buf, len)
+int fd;
+register char *buf;
+register int len;
+{
+    int cc, len2 = 0;
+
+    do {
+	cc = SOCKET_READ(fd, buf, len);
+	if (cc < 0)
+	  {
+	    if (SOCKET_ERRNO == SOCKET_EINTR)
+	      continue;
+	    return(cc);		 /* errno is already set */
+	  }
+	else if (cc == 0) {
+	    return(len2);
+	} else {
+	    buf += cc;
+	    len2 += cc;
+	    len -= cc;
+	}
+    } while (len > 0);
+    return(len2);
+}
diff --git a/mechglue/src/lib/krb4/netwrite.c b/mechglue/src/lib/krb4/netwrite.c
new file mode 100644
index 000000000..1447b7c3c
--- /dev/null
+++ b/mechglue/src/lib/krb4/netwrite.c
@@ -0,0 +1,65 @@
+/*
+ * lib/krb4/netwrite.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <errno.h>
+#include "krb.h"
+#include "krb5/autoconf.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "port-sockets.h"
+
+/*
+ * krb_net_write() writes "len" bytes from "buf" to the file
+ * descriptor "fd".  It returns the number of bytes written or
+ * a write() error.  (The calling interface is identical to
+ * write(2).)
+ *
+ * XXX must not use non-blocking I/O
+ */
+int
+krb_net_write(fd, buf, len)
+int fd;
+register char *buf;
+int len;
+{
+    int cc;
+    register int wrlen = len;
+    do {
+	cc = SOCKET_WRITE(fd, buf, wrlen);
+	if (cc < 0)
+	  {
+	    if (SOCKET_ERRNO == SOCKET_EINTR)
+	      continue;
+	    return(cc);
+	  }
+	else {
+	    buf += cc;
+	    wrlen -= cc;
+	}
+    } while (wrlen > 0);
+    return(len);
+}
diff --git a/mechglue/src/lib/krb4/password_to_key.c b/mechglue/src/lib/krb4/password_to_key.c
new file mode 100644
index 000000000..c6e60d98c
--- /dev/null
+++ b/mechglue/src/lib/krb4/password_to_key.c
@@ -0,0 +1,152 @@
+/*
+ * lib/krb4/password_to_key.c
+ *
+ * Copyright 1999, 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * password_to_key functions merged from KfM
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef USE_CCAPI
+#include <CredentialsCache.h>
+#endif
+#include "krb.h"
+#include "krb4int.h"
+
+/*
+ * passwd_to_key(): given a password, return a DES key.
+ * There are extra arguments here which (used to be?)
+ * used by srvtab_to_key().
+ *
+ * If the "passwd" argument is not null, generate a DES
+ * key from it, using string_to_key().
+ *
+ * If the "passwd" argument is null, then on a Unix system we call
+ * des_read_password() to prompt for a password and then convert it
+ * into a DES key.  But "prompting" the user is harder in a Windows or
+ * Macintosh environment, so we rely on our caller to explicitly do
+ * that now.
+ *
+ * In either case, the resulting key is put in the "key" argument,
+ * and 0 is returned.
+ */
+
+
+key_proc_type *krb_get_keyprocs (key_proc_type keyproc)
+{
+    static key_proc_type default_keyprocs[4] = { mit_passwd_to_key, 
+                                                 afs_passwd_to_key, 
+                                                 krb5_passwd_to_key, 
+                                                 NULL };
+                                                  
+    static key_proc_type user_keyprocs[2] = { NULL, NULL };
+    
+    /* generate the list of key procs */
+    if (keyproc == NULL) {
+        return default_keyprocs; /* use the default */
+    } else {
+        user_keyprocs[0] = keyproc;
+        return user_keyprocs;  /* use the caller provided keyprocs */
+    }
+}
+
+int KRB5_CALLCONV
+mit_passwd_to_key(
+    char	*user,
+    char	*instance,
+    char	*realm,
+    char	*passwd,
+    C_Block	key)
+{
+#if 0 /* what system? */
+#pragma unused(user)
+#pragma unused(instance)
+#pragma unused(realm)
+#endif
+
+    if (passwd) {
+        des_string_to_key(passwd, key);
+    } else {
+#if !(defined(_WIN32) || defined(USE_LOGIN_LIBRARY))
+        des_read_password((des_cblock *)key, "Password", 0);
+#else
+        return (-1);
+#endif
+    }
+    return (0);
+}
+
+/* So we can use a v4 kinit against a v5 kdc with no krb4 salted key */
+int KRB5_CALLCONV
+krb5_passwd_to_key(
+    char	*user,
+    char	*instance,
+    char	*realm,
+    char	*passwd,
+    C_Block	key)
+{
+    size_t	len, tlen;
+    char	*p;
+
+    if (user && instance && realm && passwd) {
+        len = MAX_K_NAME_SZ + strlen(passwd) + 1;
+	tlen = strlen(passwd) + strlen(realm) + strlen(user) + strlen(instance) + 1;
+	if (tlen > len)
+	    return 0;
+        p = malloc (tlen);
+        if (p != NULL) {
+            sprintf (p, "%s%s%s%s", passwd, realm, user, instance);
+            des_string_to_key (p, key);
+            free (p);
+            return 0;
+        }
+    }
+    return -1;
+}
+
+int KRB5_CALLCONV
+afs_passwd_to_key(
+    char	*user,
+    char	*instance,
+    char	*realm,
+    char	*passwd,
+    C_Block	key)
+{
+#if 0 /* what system? */
+#pragma unused(user)
+#pragma unused(instance)
+#endif
+
+    if (passwd) {
+        afs_string_to_key(passwd, realm, key);
+    } else {
+#if !(defined(_WIN32) || defined(USE_LOGIN_LIBRARY))
+        des_read_password((des_cblock *)key, "Password", 0);
+#else
+        return (-1);
+#endif
+    }
+    return (0);
+}
diff --git a/mechglue/src/lib/krb4/pkt_cipher.c b/mechglue/src/lib/krb4/pkt_cipher.c
new file mode 100644
index 000000000..29123480e
--- /dev/null
+++ b/mechglue/src/lib/krb4/pkt_cipher.c
@@ -0,0 +1,35 @@
+/*
+ * pkt_cipher.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include <string.h>
+#include "krb.h"
+#include "prot.h"
+
+
+/*
+ * This routine takes a reply packet from the Kerberos ticket-granting
+ * service and returns a pointer to the beginning of the ciphertext in it.
+ *
+ * See "prot.h" for packet format.
+ */
+
+KTEXT
+pkt_cipher(packet)
+    KTEXT packet;
+{
+    unsigned char *ptr = pkt_a_realm(packet) + 6
+	+ strlen((char *)pkt_a_realm(packet));
+    /* Skip a few more fields */
+    ptr += 3 + 4;		/* add 4 for exp_date */
+
+    /* And return the pointer */
+    return((KTEXT) ptr);
+}
diff --git a/mechglue/src/lib/krb4/pkt_clen.c b/mechglue/src/lib/krb4/pkt_clen.c
new file mode 100644
index 000000000..52763a4dd
--- /dev/null
+++ b/mechglue/src/lib/krb4/pkt_clen.c
@@ -0,0 +1,47 @@
+/*
+ * pkt_clen.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include <string.h>
+#include "krb.h"
+#include "prot.h"
+
+extern int krb_debug;
+int swap_bytes=0;
+
+/*
+ * Given a pointer to an AUTH_MSG_KDC_REPLY packet, return the length of
+ * its ciphertext portion.  The external variable "swap_bytes" is assumed
+ * to have been set to indicate whether or not the packet is in local
+ * byte order.  pkt_clen() takes this into account when reading the
+ * ciphertext length out of the packet.
+ */
+
+int
+pkt_clen(pkt)
+    KTEXT pkt;
+{
+    static unsigned short temp;
+    int clen = 0;
+
+    /* Start of ticket list */
+    unsigned char *ptr = pkt_a_realm(pkt) + 10
+	+ strlen((char *)pkt_a_realm(pkt));
+
+    /* Finally the length */
+    memcpy((char *)&temp, (char *)(++ptr), 2); /* alignment */
+    if (swap_bytes)
+	temp = krb4_swab16(temp);    
+
+    clen = (int) temp;
+
+    DEB (("Clen is %d\n",clen));
+    return(clen);
+}
diff --git a/mechglue/src/lib/krb4/prot_client.c b/mechglue/src/lib/krb4/prot_client.c
new file mode 100644
index 000000000..315f7f08a
--- /dev/null
+++ b/mechglue/src/lib/krb4/prot_client.c
@@ -0,0 +1,370 @@
+/*
+ * lib/krb4/prot_client.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.  All
+ * Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Contains protocol encoders and decoders used by a krb4 client.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+
+/*
+ * encode_kdc_request
+ *
+ * Packet format is originally from g_in_tkt.c.
+ *
+ * Size			Variable		Field
+ * ----			--------		-----
+ * 1 byte		KRB_PROT_VERSION	protocol version number
+ * 1 byte		AUTH_MSG_KDC_REQUEST |	message type
+ *			HOST_BYTE_ORDER		local byte order in lsb
+ * string		user			client's name
+ * string		instance		client's instance
+ * string		realm			client's realm
+ * 4 bytes		tlocal.tv_sec		timestamp in seconds
+ * 1 byte		life			desired lifetime
+ * string		service			service's name
+ * string		sinstance		service's instance
+ */
+int KRB5_CALLCONV
+krb4prot_encode_kdc_request(char *pname, char *pinst, char *prealm,
+			    KRB4_32 tlocal, int life,
+			    char *sname, char *sinst,
+			    char *preauth, int preauthlen,
+			    int chklen,	/* check input str len? */
+			    int le, /* little-endian? */
+			    KTEXT pkt)
+{
+    unsigned char *p;
+    int ret;
+    size_t snamelen, sinstlen;
+
+    p = pkt->dat;
+
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_KDC_REQUEST | !!le;
+
+    ret = krb4prot_encode_naminstrlm(pname, pinst, prealm, chklen,
+				     pkt, &p);
+    if (ret)
+	return ret;
+
+    snamelen = strlen(sname) + 1;
+    sinstlen = strlen(sinst) + 1;
+    if (chklen && (snamelen > ANAME_SZ || sinstlen > INST_SZ))
+	return KRB4PROT_ERR_OVERRUN;
+    if ((sizeof(pkt->dat) - (p - pkt->dat))
+	< (4 + 1 + snamelen + sinstlen + preauthlen))
+	return KRB4PROT_ERR_OVERRUN;
+
+    /* timestamp */
+    KRB4_PUT32(p, tlocal, le);
+
+    *p++ = life;
+
+    memcpy(p, sname, snamelen);
+    p += snamelen;
+    memcpy(p, sinst, sinstlen);
+    p += sinstlen;
+
+    if (preauthlen)
+	memcpy(p, preauth, (size_t)preauthlen);
+    p += preauthlen;
+
+    pkt->length = p - pkt->dat;
+    return KRB4PROT_OK;
+}
+
+/*
+ * decode_kdc_reply
+ */
+int KRB5_CALLCONV
+krb4prot_decode_kdc_reply(KTEXT pkt,
+			  int *le,
+			  char *pname, char *pinst, char *prealm,
+			  long *time_ws, int *n,
+			  unsigned long *x_date, int *kvno,
+			  KTEXT ciph)
+{
+    unsigned char *p;
+    int msg_type;
+    int ret;
+    unsigned int ciph_len;
+
+    p = pkt->dat;
+    if (pkt->length < 2)
+	return KRB4PROT_ERR_UNDERRUN;
+    if (*p++ != KRB_PROT_VERSION)
+	return KRB4PROT_ERR_PROT_VERS;
+    msg_type = *p++;
+    *le = msg_type & 1;
+    msg_type &= ~1;
+    if (msg_type != AUTH_MSG_KDC_REPLY)
+	return KRB4PROT_ERR_MSG_TYPE;
+
+    ret = krb4prot_decode_naminstrlm(ciph, &p, pname, pinst, prealm);
+    if (ret)
+	return ret;
+
+#define PKT_REMAIN (pkt->length - (p - pkt->dat))
+
+    if (PKT_REMAIN < (4		/* time */
+		      + 1	/* number of tickets */
+		      + 4	/* exp date */
+		      + 1	/* kvno */
+		      + 2))	/* ciph length */
+	return KRB4PROT_ERR_UNDERRUN;
+    if (time_ws != NULL)
+	KRB4_GET32(*time_ws, p, *le); /* XXX signed/unsigned */
+    else
+	p += 4;
+    if (n != NULL)
+	*n = *p++;
+    else
+	p++;
+    if (x_date != NULL)
+	KRB4_GET32(*x_date, p, *le);
+    else
+	p += 4;
+    if (kvno != NULL)
+	*kvno = *p++;
+    else
+	p++;
+    KRB4_GET16(ciph_len, p, *le);
+    if (PKT_REMAIN < ciph_len)
+	return KRB4PROT_ERR_UNDERRUN;
+    ciph->length = ciph_len;
+    memcpy(ciph->dat, p, (size_t)ciph->length);
+    return KRB4PROT_OK;
+#undef PKT_REMAIN
+}
+
+int KRB5_CALLCONV
+krb4prot_decode_ciph(KTEXT ciph, int le,
+		     C_Block session,
+		     char *name, char *inst, char *realm,
+		     int *life, int *kvno,
+		     KTEXT tkt, unsigned long *kdc_time)
+{
+    unsigned char *p;
+    int ret;
+
+    p = ciph->dat;
+    if (ciph->length < 8)
+	return KRB4PROT_ERR_UNDERRUN;
+    memcpy(session, p, 8);
+    p += 8;
+    ret = krb4prot_decode_naminstrlm(ciph, &p, name, inst, realm);
+    if (ret)
+	return ret;
+#define CIPH_REMAIN (ciph->length - (p - ciph->dat))
+    if (CIPH_REMAIN < (1	/* life */
+		       + 1	/* kvno */
+		       + 1))	/* tkt->length */
+	return KRB4PROT_ERR_UNDERRUN;
+    if (life != NULL)
+	*life = *p++;
+    else
+	p++;
+    if (kvno != NULL)
+	*kvno = *p++;
+    else
+	p++;
+    tkt->length = *p++;
+    if (CIPH_REMAIN < (tkt->length
+		       + 4))	/* kdc_time */
+	return KRB4PROT_ERR_UNDERRUN;
+    memcpy(tkt->dat, p, (size_t)tkt->length);
+    p += tkt->length;
+
+    if (kdc_time != NULL)
+	KRB4_GET32(*kdc_time, p, le);
+
+    return KRB4PROT_OK;
+#undef CIPH_REMAIN
+}
+
+/*
+ * encode_apreq
+ *
+ * The following was originally from mk_req.c.
+ *
+ * unsigned char	KRB_PROT_VERSION	protocol version no.
+ * unsigned char	AUTH_MSG_APPL_REQUEST	message type
+ * (least significant
+ * bit of above)	HOST_BYTE_ORDER		local byte ordering
+ * unsigned char	kvno from ticket	server's key version
+ * string		realm			server's realm
+ * unsigned char	tl			ticket length
+ * unsigned char	idl			request id length
+ * binary		ticket->dat		ticket for server
+ * binary		req_id->dat		request id
+ */
+int KRB5_CALLCONV
+krb4prot_encode_apreq(int kvno, char *realm,
+		      KTEXT tkt, KTEXT req_id,
+		      int chklen, /* check str len? */
+		      int le,	/* little-endian? */
+		      KTEXT pkt)
+{
+    unsigned char *p;
+    size_t realmlen;
+
+    p = pkt->dat;
+    /* Assume >= 3 bytes in a KTEXT. */
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_APPL_REQUEST | !!le;
+
+    *p++ = kvno;
+
+    realmlen = strlen(realm) + 1;
+    if (chklen && realmlen > REALM_SZ)
+	return KRB4PROT_ERR_OVERRUN;
+    if (tkt->length > 255 || req_id->length > 255)
+	return KRB4PROT_ERR_OVERRUN;
+    if ((sizeof(pkt->dat) - (p - pkt->dat))
+	< (realmlen
+	   + 1			/* tkt->length */
+	   + 1			/* req_id->length */
+	   + tkt->length + req_id->length))
+	return KRB4PROT_ERR_OVERRUN;
+
+    memcpy(p, realm, realmlen);
+    p += realmlen;
+
+    *p++ = tkt->length;
+    *p++ = req_id->length;
+    memcpy(p, tkt->dat, (size_t)tkt->length);
+    p += tkt->length;
+    memcpy(p, req_id->dat, (size_t)req_id->length);
+    p += req_id->length;
+
+    pkt->length = p - pkt->dat;
+    return KRB4PROT_OK;
+}
+
+/*
+ * encode_authent
+ *
+ * Encodes an authenticator (called req_id in some of the code for
+ * some weird reason).  Does not encrypt.
+ *
+ * The following packet layout is originally from mk_req.c.  It is
+ * rounded up to the next multiple of 8 bytes.
+ *
+ * string		cr.pname		{name, instance, and
+ * string		cr.pinst		realm of principal
+ * string		myrealm			making this request}
+ * 4 bytes		checksum		checksum argument given
+ * unsigned char	time_usecs		time (microseconds)
+ * 4 bytes		time_secs		time (seconds)
+ */
+int KRB5_CALLCONV
+krb4prot_encode_authent(char *pname, char *pinst, char *prealm,
+			KRB4_32 checksum,
+			int time_usec, long time_sec,
+			int chklen, /* check str lens? */
+			int le,	/* little-endian? */
+			KTEXT pkt)
+{
+    unsigned char *p;
+    int ret;
+
+    p = pkt->dat;
+    ret = krb4prot_encode_naminstrlm(pname, pinst, prealm, chklen,
+				     pkt, &p);
+    if (ret)
+	return ret;
+    if ((sizeof(pkt->dat) - (p - pkt->dat)) / 8
+	< (4			/* checksum */
+	   + 1			/* microsec */
+	   + 4			/* time */
+	   + 7) / 8)		/* roundoff */
+	return KRB4PROT_ERR_OVERRUN;
+
+    KRB4_PUT32(p, checksum, le);
+    *p++ = time_usec;
+    KRB4_PUT32(p, time_sec, le);
+
+    memset(p, 0, 7);		/* nul-pad */
+    pkt->length = (((p - pkt->dat) + 7) / 8) * 8;
+    return KRB4PROT_OK;
+}
+
+/*
+ * decode_error
+ *
+ * Decodes an error reply from the KDC.
+ */
+int KRB5_CALLCONV
+krb4prot_decode_error(KTEXT pkt, int *le,
+		      char *pname, char *pinst, char *prealm,
+		      unsigned long *time_ws,
+		      unsigned long *err, char *err_string)
+{
+    unsigned char *p;
+    int msg_type, ret, errstrlen;
+
+    p = pkt->dat;
+    if (pkt->length < 2)
+	return KRB4PROT_ERR_UNDERRUN;
+    if (*p++ != KRB_PROT_VERSION)
+	return KRB4PROT_ERR_PROT_VERS;
+    msg_type = *p++;
+    *le = msg_type & 1;
+    msg_type &= ~1;
+    if (msg_type != AUTH_MSG_ERR_REPLY)
+	return KRB4PROT_ERR_MSG_TYPE;
+
+    ret = krb4prot_decode_naminstrlm(pkt, &p, pname, pinst, prealm);
+    if (ret)
+	return ret;
+
+#define PKT_REMAIN (pkt->length - (p - pkt->dat))
+    if (PKT_REMAIN < (4		/* time */
+		      + 4))	/* err code */
+	return KRB4PROT_ERR_UNDERRUN;
+
+    if (time_ws != NULL)
+	KRB4_GET32(*time_ws, p, le);
+    else
+	p += 4;
+    if (err != NULL)
+	KRB4_GET32(*err, p, le);
+    else
+	p += 4;
+
+    if (PKT_REMAIN <= 0)	/* allow for missing error string */
+	return KRB4PROT_OK;
+
+    errstrlen = krb4int_strnlen((char *)p, PKT_REMAIN) + 1;
+    if (errstrlen <= 0)		/* If it's there, it must be nul-terminated. */
+	return KRB4PROT_ERR_OVERRUN;
+    if (err_string != NULL)
+	memcpy(err_string, p, (size_t)errstrlen);
+
+    return KRB4PROT_OK;
+#undef PKT_REMAIN
+}
diff --git a/mechglue/src/lib/krb4/prot_common.c b/mechglue/src/lib/krb4/prot_common.c
new file mode 100644
index 000000000..3e36de129
--- /dev/null
+++ b/mechglue/src/lib/krb4/prot_common.c
@@ -0,0 +1,136 @@
+/*
+ * lib/krb4/prot_common.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.  All
+ * Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Contains some common code used by multiple encoders/decoders.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+
+/*
+ * encode_naminstrlm
+ *
+ * Takes input string triplet of a principal, encodes into PKT.
+ * Assumes that input strings are properly terminated.  If CHKLEN is
+ * non-zero, validate input string lengths against their respective
+ * limits.  The pointer P is the address of the moving pointer used by
+ * the caller, and is updated here.
+ *
+ * Returns zero on success, non-zero on failure.
+ *
+ * PKT->LENGTH is NOT updated.  The caller must update it.
+ */
+int KRB5_CALLCONV
+krb4prot_encode_naminstrlm(char *name, char *inst, char *realm,
+			   int chklen, /* check input str len? */
+			   KTEXT pkt, /* buffer to encode into */
+			   unsigned char **p /* moving pointer */)
+{
+    size_t namelen, instlen, realmlen;
+
+    namelen = strlen(name) + 1;
+    instlen = strlen(inst) + 1;
+    realmlen = strlen(realm) + 1;
+    if (chklen && (namelen > ANAME_SZ || instlen > INST_SZ
+		   || realmlen > REALM_SZ))
+	return KRB4PROT_ERR_OVERRUN;
+    if (*p - pkt->dat < namelen + instlen + realmlen)
+	return KRB4PROT_ERR_OVERRUN;
+    memcpy(*p, name, namelen);
+    *p += namelen;
+    memcpy(*p, inst, instlen);
+    *p += namelen;
+    memcpy(*p, realm, realmlen);
+    *p += namelen;
+    return KRB4PROT_OK;
+}
+
+/*
+ * decode_naminstrlm
+ *
+ * Grabs a string triplet corresponding to a principal.  The input
+ * buffer PKT should have its length properly set.  The pointer P is
+ * the address of the moving pointer used by the caller, and will be
+ * updated.  If any input pointer is NULL, merely skip the string.
+ *
+ * The output strings NAME, INST, and REALM are assumed to be of the
+ * correct sizes (ANAME_SZ, INST_SZ, REALM_SZ).
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+int KRB5_CALLCONV
+krb4prot_decode_naminstrlm(KTEXT pkt, /* buffer to decode from */
+			   unsigned char **p, /* moving pointer */
+			   char *name, char *inst, char *realm)
+{
+    int len;
+
+#define PKT_REMAIN (pkt->length - (*p - pkt->dat))
+    if (PKT_REMAIN <= 0)
+	return KRB4PROT_ERR_UNDERRUN;
+    len = krb4int_strnlen((char *)*p, PKT_REMAIN) + 1;
+    if (len == 0 || len > ANAME_SZ)
+	return KRB4PROT_ERR_OVERRUN;
+    if (name != NULL)
+	memcpy(name, *p, (size_t)len);
+    *p += len;
+
+    if (PKT_REMAIN <= 0)
+	return KRB4PROT_ERR_UNDERRUN;
+    len = krb4int_strnlen((char *)*p, PKT_REMAIN) + 1;
+    if (len <= 0 || len > INST_SZ)
+	return KRB4PROT_ERR_OVERRUN;
+    if (name != NULL)
+	memcpy(inst, *p, (size_t)len);
+    *p += len;
+
+    if (PKT_REMAIN <= 0)
+	return KRB4PROT_ERR_UNDERRUN;
+    len = krb4int_strnlen((char *)*p, PKT_REMAIN) + 1;
+    if (len <= 0 || len > REALM_SZ)
+	return KRB4PROT_ERR_OVERRUN;
+    if (realm != NULL)
+	memcpy(realm, *p, (size_t)len);
+    *p += len;
+    return KRB4PROT_OK;
+#undef PKT_REMAIN
+}
+
+int KRB5_CALLCONV
+krb4prot_decode_header(KTEXT pkt,
+		       int *pver, int *msgtype, int *le)
+{
+    unsigned char *p;
+
+    p = pkt->dat;
+    if (pkt->length < 2)
+	return KRB4PROT_ERR_UNDERRUN;
+    *pver = *p++;
+    *msgtype = *p++;
+    *le = *msgtype & 1;
+    *msgtype &= ~1;
+    return KRB4PROT_OK;
+}
diff --git a/mechglue/src/lib/krb4/prot_kdc.c b/mechglue/src/lib/krb4/prot_kdc.c
new file mode 100644
index 000000000..aaaa9d00c
--- /dev/null
+++ b/mechglue/src/lib/krb4/prot_kdc.c
@@ -0,0 +1,461 @@
+/*
+ * lib/krb4/prot_kdc.c
+ *
+ * Copyright 1985--1988, 2000, 2001 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Contains the protocol encoders and decoders used by the KDC.
+ */
+
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+#include "port-sockets.h"
+
+/*
+ * encode_kdc_reply
+ *
+ * Encodes a reply from the KDC to the client.
+ *
+ * Returns KRB4PROT_OK on success, non-zero on failure.
+ *
+ * Caller is responsible for cleaning up OUTBUF.
+ *
+ * This packet layout description was originally in cr_auth_repl.c:
+ *
+ * 			variable
+ * type			or constant	   data
+ * ----			-----------	   ----
+ * unsigned char	KRB_PROT_VERSION   protocol version number
+ * 
+ * unsigned char	AUTH_MSG_KDC_REPLY protocol message type
+ * 
+ * [least significant	HOST_BYTE_ORDER	   sender's (server's) byte
+ *  bit of above field]			   order
+ * 
+ * string		pname		   principal's name
+ * 
+ * string		pinst		   principal's instance
+ * 
+ * string		prealm		   principal's realm
+ * 
+ * unsigned long	time_ws		   client's timestamp
+ * 
+ * unsigned char	n		   number of tickets
+ * 
+ * unsigned long	x_date		   expiration date
+ * 
+ * unsigned char	kvno		   master key version
+ * 
+ * short		cipher->length	   cipher length
+ * 
+ * binary		cipher->dat	   cipher data
+ */
+int KRB5_CALLCONV
+krb4prot_encode_kdc_reply(char *pname, char *pinst, char *prealm,
+			  long time_ws,
+			  int n, /* Number of tickets; 0 for krb4 (!) */
+			  unsigned long x_date,	/* exp date */
+			  int kvno,
+			  KTEXT cipher,	/* encrypted ticket */
+			  int chklen, /* check input str len? */
+			  int le, /* little-endian? */
+			  KTEXT outbuf)
+{
+    unsigned char *p;
+    int ret;
+
+    p = outbuf->dat;
+    /* This is really crusty. */
+    if (n != 0)
+	*p++ = 3;
+    else
+	*p++ = KRB_PROT_VERSION;
+    /* little-endianness based on input, usually big-endian, though. */
+    *p++ = AUTH_MSG_KDC_REPLY | !!le;
+
+    ret = krb4prot_encode_naminstrlm(pname, pinst, prealm, chklen,
+				     outbuf, &p);
+    if (ret)
+	return ret;
+
+    /* Check lengths */
+    if (cipher->length > 65535 || cipher->length < 0)
+	return KRB4PROT_ERR_OVERRUN;
+    if ((sizeof(outbuf->dat) - (p - outbuf->dat)
+	 < (4			/* timestamp */
+	    + 1			/* num of tickets */
+	    + 4			/* exp date */
+	    + 1			/* kvno */
+	    + 2			/* cipher->length */
+	    + cipher->length)))	/* cipher->dat */
+        return KRB4PROT_ERR_OVERRUN;
+
+    /* Workstation timestamp */
+    KRB4_PUT32(p, time_ws, le);
+
+    /* Number of tickets */
+    *p++ = n;
+
+    /* Expiration date */
+    KRB4_PUT32(p, x_date, le);
+
+    /* Now send the ciphertext and info to help decode it */
+    *p++ = kvno;
+    KRB4_PUT16(p, cipher->length, le);
+    memcpy(p, cipher->dat, (size_t)cipher->length);
+    p += cipher->length;
+
+    /* And return the packet */
+    outbuf->length = p - outbuf->dat;
+    return KRB4PROT_OK;
+}
+
+/*
+ * encode_ciph
+ *
+ * Encodes a "cipher" that is to be included in a KDC reply message.
+ *
+ * Caller is responsible for cleaning up CIPH.
+ *
+ * Returns KRB4PROT_OK on success, non-zero on failure.
+ *
+ * Packet format below is originally from cr_ciph.c:
+ *
+ * 			variable
+ * type			or constant	data
+ * ----			-----------	----
+ * 8 bytes		session		session key for client, service
+ * 
+ * string		service		service name
+ * 
+ * string		instance	service instance
+ * 
+ * string		realm		KDC realm
+ * 
+ * unsigned char	life		ticket lifetime
+ * 
+ * unsigned char	kvno		service key version number
+ * 
+ * unsigned char	tkt->length	length of following ticket
+ * 
+ * data			tkt->dat	ticket for service
+ * 
+ * 4 bytes		kdc_time	KDC's timestamp
+ *
+ * <=7 bytes		null		null pad to 8 byte multiple
+ */
+int KRB5_CALLCONV
+krb4prot_encode_ciph(C_Block session,
+		     char *name, char *inst, char *realm,
+		     unsigned long life, int kvno,
+		     KTEXT tkt,	/* ticket */
+		     unsigned long kdc_time,
+		     int chklen, /* check str lens? */
+		     int le,	/* little-endian? */
+		     KTEXT ciph) /* output buffer */
+{
+    unsigned char *p;
+    int ret;
+
+    p = ciph->dat;
+    /*
+     * Assume that there will be >= 8 bytes in a KTEXT.  If there
+     * aren't, we have worse problems.
+     */
+    memcpy(p, session, 8);
+    p += 8;
+
+    ret = krb4prot_encode_naminstrlm(name, inst, realm, chklen,
+				     ciph, &p);
+    if (ret)
+	return ret;
+    if (tkt->length > 255 || tkt->length < 0)
+	return KRB4PROT_ERR_OVERRUN;
+    if ((sizeof(ciph->dat) - (p - ciph->dat)) / 8
+	< (1			/* life */
+	   + 1			/* kvno */
+	   + 1			/* tkt->length */
+	   + tkt->length	/* tkt->dat */
+	   + 4			/* kdc_time */
+	   + 7) / 8)		/* roundoff */
+	return KRB4PROT_ERR_OVERRUN;
+
+    *p++ = life;
+    *p++ = kvno;
+    *p++ = tkt->length;
+
+    memcpy(p, tkt->dat, (size_t)tkt->length);
+    p += tkt->length;
+
+    KRB4_PUT32(p, kdc_time, le);
+
+    /* Guarantee null pad to multiple of 8 bytes */
+    memset(p, 0, 7);
+    ciph->length = (((p - ciph->dat) + 7) / 8) * 8;
+    return KRB4PROT_OK;
+}
+
+/*
+ * encode_tkt
+ *
+ * Encode ticket to include in a "cipher".  Does not encrypt.
+ *
+ * Caller is responsible for cleaning TKT.
+ *
+ * The length of the ticket is a multiple of
+ * eight bytes and is in tkt->length.
+ *
+ * If the ticket is not a multiple of eight bytes long, the ticket
+ * will contain nulls.
+ *
+ * Returns KRB4PROT_OK on success, non-zero on failure.
+ *
+ * The following packet layout is from cr_tkt.c:
+ *
+ * 			variable
+ * type			or constant	   data
+ * ----			-----------	   ----
+ * unsigned char	flags		   namely, HOST_BYTE_ORDER
+ * 
+ * string		pname		   client's name
+ * 
+ * string		pinstance	   client's instance
+ * 
+ * string		prealm		   client's realm
+ * 
+ * 4 bytes		paddress	   client's address
+ * 
+ * 8 bytes		session		   session key
+ * 
+ * 1 byte		life		   ticket lifetime
+ * 
+ * 4 bytes		time_sec	   KDC timestamp
+ * 
+ * string		sname		   service's name
+ * 
+ * string		sinstance	   service's instance
+ * 
+ * <=7 bytes		null		   null pad to 8 byte multiple
+ */
+int KRB5_CALLCONV
+krb4prot_encode_tkt(unsigned int flags,
+		    char *pname, char *pinst, char *prealm,
+		    unsigned long paddress,
+		    char *session,
+		    int life, long time_sec,
+		    char *sname, char *sinst,
+		    int chklen,	/* check str lens? */
+		    int le,	/* little-endian? */
+		    KTEXT tkt)	/* output buf */
+{
+    struct in_addr paddr;
+    unsigned char *p;
+    size_t snamelen, sinstlen;
+
+    /* Be really paranoid. */
+    if (sizeof(paddr.s_addr) != 4)
+	return KFAILURE;
+
+    p = tkt->dat;
+    /*
+     * Assume at least one byte in a KTEXT.  If not, we have bigger
+     * problems.  Also, bitwise-OR in the little-endian flag.
+     */
+    *p++ = flags | !!le;
+
+    if (krb4prot_encode_naminstrlm(pname, pinst, prealm, chklen,
+				   tkt, &p))
+	return KFAILURE;
+
+    snamelen = strlen(sname) + 1;
+    sinstlen = strlen(sinst) + 1;
+    if (life > 255 || life < 0)
+	return KFAILURE;
+    if (chklen && (snamelen > ANAME_SZ || sinstlen > INST_SZ))
+	return KFAILURE;
+    if ((sizeof(tkt->dat) - (p - tkt->dat)) / 8
+	< (4			/* address */
+	   + 8			/* session */
+	   + 1			/* life */
+	   + 4			/* issue time */
+	   + snamelen + sinstlen
+	   + 7) / 8)		/* roundoff */
+        return KFAILURE;
+
+    paddr.s_addr = paddress;
+    memcpy(p, &paddr.s_addr, sizeof(paddr.s_addr));
+    p += sizeof(paddr.s_addr);
+
+    memcpy(p, session, 8);
+    p += 8;
+    *p++ = life;
+    /* issue time */
+    KRB4_PUT32(p, time_sec, le);
+
+    memcpy(p, sname, snamelen);
+    p += snamelen;
+    memcpy(p, sinst, sinstlen);
+    p += sinstlen;
+
+    /* guarantee null padded ticket to multiple of 8 bytes */
+    memset(p, 0, 7);
+    tkt->length = ((p - tkt->dat + 7) / 8) * 8;
+    return KSUCCESS;
+}
+
+/*
+ * encode_err_reply
+ *
+ * Encode an error reply message from the KDC to the client.
+ *
+ * Returns KRB4PROT_OK on success, non-zero on error.
+ *
+ * The following packet layout description is from cr_err_repl.c:
+ * 
+ * type			variable	   data
+ *			or constant
+ * ----			-----------	   ----
+ * unsigned char	req_ack_vno	   protocol version number
+ * 
+ * unsigned char	AUTH_MSG_ERR_REPLY protocol message type
+ * 
+ * [least significant	HOST_BYTE_ORDER	   sender's (server's) byte
+ * bit of above field]			   order
+ * 
+ * string		pname		   principal's name
+ * 
+ * string		pinst		   principal's instance
+ * 
+ * string		prealm		   principal's realm
+ * 
+ * unsigned long	time_ws		   client's timestamp
+ * 
+ * unsigned long	e		   error code
+ * 
+ * string		e_string	   error text
+ */
+int KRB5_CALLCONV
+krb4prot_encode_err_reply(char *pname, char *pinst, char *prealm,
+			  unsigned long time_ws,
+			  unsigned long err, /* error code */
+			  char *err_string, /* error text */
+			  int chklen, /* check str lens? */
+			  int le, /* little-endian? */
+			  KTEXT pkt) /* output buf */
+{
+    unsigned char *p;
+    size_t err_stringlen;
+
+    p = pkt->dat;
+    /* Assume >= 2 bytes in KTEXT. */
+    *p++ = KRB_PROT_VERSION;
+    *p++ = AUTH_MSG_ERR_REPLY | !!le;
+
+    if (krb4prot_encode_naminstrlm(pname, pinst, prealm, chklen,
+				   pkt, &p))
+	return KFAILURE;
+
+    err_stringlen = strlen(err_string) + 1;
+    if ((sizeof(pkt->dat) - (p - pkt->dat))
+	< (4			/* timestamp */
+	   + 4			/* err code */
+	   + err_stringlen))
+	return KFAILURE;
+    /* ws timestamp */
+    KRB4_PUT32(p, time_ws, le);
+    /* err code */
+    KRB4_PUT32(p, err, le);
+    /* err text */
+    memcpy(p, err_string, err_stringlen);
+    p += err_stringlen;
+
+    /* And return */
+    pkt->length = p - pkt->dat;
+    return KSUCCESS;
+}
+
+/*
+ * decode_kdc_request
+ *
+ * Decode an initial ticket request sent from the client to the KDC.
+ *
+ * Packet format is described in g_in_tkt.c.
+ *
+ * Returns KRB4PROT_OK on success, non-zero on failure.
+ */
+int KRB5_CALLCONV
+krb4prot_decode_kdc_request(KTEXT pkt,
+			    int *le,
+			    char *pname, char *pinst, char *prealm,
+			    long *req_time, int *life,
+			    char *sname, char *sinst)
+{
+    unsigned char *p;
+    int msg_type, ret, len;
+
+    p = pkt->dat;
+
+    /* Get prot vers and msg type */
+    if (pkt->length < 2)
+	return KRB4PROT_ERR_UNDERRUN;
+    if (*p++ != KRB_PROT_VERSION)
+	return KRB4PROT_ERR_PROT_VERS;
+    msg_type = *p++;
+    *le = msg_type & 1;
+    msg_type &= ~1;
+    if (msg_type != AUTH_MSG_KDC_REQUEST)
+	return KRB4PROT_ERR_MSG_TYPE;
+
+    ret = krb4prot_decode_naminstrlm(pkt, &p, pname, pinst, prealm);
+    if (ret)
+	return ret;
+
+#define PKT_REMAIN (pkt->length - (p - pkt->dat))
+
+    if (PKT_REMAIN < (4		/* time */
+		      + 1))	/* life */
+	return KRB4PROT_ERR_UNDERRUN;
+
+    KRB4_GET32(*req_time, p, *le);
+
+    *life = *p++;
+
+    if (PKT_REMAIN <= 0)
+	return KRB4PROT_ERR_UNDERRUN;
+    len = krb4int_strnlen((char *)p, PKT_REMAIN) + 1;
+    if (len <= 0 || len > ANAME_SZ)
+	return KRB4PROT_ERR_OVERRUN;
+    memcpy(sname, p, (size_t)len);
+    p += len;
+
+    if (PKT_REMAIN <= 0)
+	return KRB4PROT_ERR_UNDERRUN;
+    len = krb4int_strnlen((char *)p, PKT_REMAIN) + 1;
+    if (len <= 0 || len > INST_SZ)
+	return KRB4PROT_ERR_OVERRUN;
+    memcpy(sinst, p, (size_t)len);
+    p += len;
+
+    /* XXX krb4 preauth? */
+    return KRB4PROT_OK;
+}
diff --git a/mechglue/src/lib/krb4/put_svc_key.c b/mechglue/src/lib/krb4/put_svc_key.c
new file mode 100644
index 000000000..80561cc4f
--- /dev/null
+++ b/mechglue/src/lib/krb4/put_svc_key.c
@@ -0,0 +1,94 @@
+/* lib/krb/put_svc_key.c */
+/* Copyright 1994 Cygnus Support */
+/* Mark W. Eichin */
+/*
+ * Permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation.
+ * Cygnus Support makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * put_svc_key is a simple version of what 'ksrvutil add' provides, for some
+ *    circumstances when service keys are distributed by applictions.
+ *
+ * Caveats: currently uses UNIX I/O (open, read) rather than stdio - this 
+ *    should be fixed.
+ *          It could probably be made more general (and then actually be used
+ *    by ksrvutil.) This version supports just enough to be useful.
+ */
+
+#include "krb.h"
+#include "krb4int.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include "krb5/autoconf.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#define KEYSZ sizeof(C_Block)
+/* strict put_svc_key.
+   The srvtab must already exist;
+   The key (exact match) must already be in the file;
+   version numbers are not checked.
+ */
+int KRB5_CALLCONV
+put_svc_key(sfile,name,inst,realm,newvno,key)
+	char *sfile;
+	char *name;
+	char *inst;
+	char *realm;
+	int newvno;
+	char *key;
+{
+	int fd;
+	char fname[SNAME_SZ], finst[INST_SZ], frlm[REALM_SZ];
+	unsigned char fvno;
+	char fkey[KEYSZ];
+
+	if (!sfile)
+		sfile = KEYFILE;
+
+	if ((fd = open(sfile, O_RDWR)) < 0)
+		return KFAILURE;
+
+	while(getst(fd,fname,SNAME_SZ) > 0) {
+		getst(fd,finst,INST_SZ);
+		getst(fd,frlm,REALM_SZ);
+		if (!strcmp(fname,name)
+		    && !strcmp(finst,inst)
+		    && !strcmp(frlm,realm)) {
+			/* all matched, so write new data */
+			fvno = newvno;
+			lseek(fd,0,SEEK_CUR);
+			if (write(fd,&fvno,1) != 1) {
+				close(fd);
+				return KFAILURE;
+			}
+			if (write(fd,key,KEYSZ) != KEYSZ) {
+				close(fd);
+				return KFAILURE;
+			}
+			close(fd);
+			return KSUCCESS;
+		}
+                if (read(fd,&fvno,1) != 1) {
+                        close(fd);
+                        return KFAILURE;
+                }
+                if (read(fd,fkey,KEYSZ) != KEYSZ) {
+                        close(fd);
+                        return KFAILURE;
+                }
+	}
+	/* never found it */
+	close(fd);
+	return KFAILURE;
+}
diff --git a/mechglue/src/lib/krb4/rd_err.c b/mechglue/src/lib/krb4/rd_err.c
new file mode 100644
index 000000000..47f5167b5
--- /dev/null
+++ b/mechglue/src/lib/krb4/rd_err.c
@@ -0,0 +1,78 @@
+/*
+ * lib/krb4/rd_err.c
+ *
+ * Copyright 1986, 1987, 1988, 2000 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Steve Miller    Project Athena  MIT/DEC
+ */
+
+#include <string.h>
+
+#include "krb.h"
+#include "prot.h"
+
+/*
+ * Given an AUTH_MSG_APPL_ERR message, "in" and its length "in_length",
+ * return the error code from the message in "code" and the text in
+ * "m_data" as follows:
+ *
+ *	m_data->app_data	points to the error text
+ *	m_data->app_length	points to the length of the error text
+ *
+ * If all goes well, return RD_AP_OK.  If the version number
+ * is wrong, return RD_AP_VERSION, and if it's not an AUTH_MSG_APPL_ERR
+ * type message, return RD_AP_MSG_TYPE.
+ *
+ * The AUTH_MSG_APPL_ERR message format can be found in mk_err.c
+ */
+
+int KRB5_CALLCONV
+krb_rd_err(in, in_length, code, m_data)
+    u_char *in;                 /* pointer to the msg received */
+    u_long in_length;           /* of in msg */
+    long *code;                 /* received error code */
+    MSG_DAT *m_data;
+{
+    register u_char *p;
+    int le;
+    unsigned KRB4_32 raw_code;
+
+    p = in;                     /* beginning of message */
+
+    if (in_length < 1 + 1 + 4)
+	return RD_AP_MODIFIED;	/* XXX should have better error code */
+    if (*p++ != KRB_PROT_VERSION)
+        return RD_AP_VERSION;
+    if (((*p) & ~1) != AUTH_MSG_APPL_ERR)
+        return RD_AP_MSG_TYPE;
+    le = *p++ & 1;
+
+    KRB4_GET32(raw_code, p, le);
+    *code = raw_code;		/* XXX unsigned->signed conversion! */
+
+    m_data->app_data = p;       /* we're now at the error text
+                                 * message */
+    m_data->app_length = p - in;
+
+    return RD_AP_OK;           /* OK == 0 */
+}
diff --git a/mechglue/src/lib/krb4/rd_preauth.c b/mechglue/src/lib/krb4/rd_preauth.c
new file mode 100644
index 000000000..b30838cc4
--- /dev/null
+++ b/mechglue/src/lib/krb4/rd_preauth.c
@@ -0,0 +1,62 @@
+/* rd_preauth.c */
+/* part of Cygnus Network Security */
+/* Copyright 1994 Cygnus Support */
+/*
+ * Permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation.
+ * Cygnus Support makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "krb_db.h"
+#include "prot.h"
+#include "des.h"
+#include "krb4int.h"
+#include <string.h>
+
+/* #define      KERB_ERR_PREAUTH_SHORT		11 */
+/* #define	KERB_ERR_PREAUTH_MISMATCH	12 */
+
+
+int
+krb_rd_preauth(pkt, preauth_p, preauth_len, auth_pr, key)
+    KTEXT pkt;
+    char *preauth_p;
+    int preauth_len;
+    Principal *auth_pr;
+    des_cblock key;
+{
+    int st;
+    char *name_p;
+
+    name_p = auth_pr->name;
+   
+#ifndef NOENCRYPTION
+    /* Decrypt preauth_p using key as the key and initialization vector. */
+    /* check preauth_len */
+    if ((((strlen(name_p) + 1) / 8) + 1) * 8 != preauth_len)
+	return KERB_ERR_PREAUTH_SHORT;
+    else {
+	des_key_schedule key_s;
+
+	if (des_key_sched(key, key_s)) {
+	    return 1;
+	}
+	des_pcbc_encrypt((des_cblock *)preauth_p, (des_cblock *)preauth_p,
+			 (long)preauth_len, key_s, (des_cblock *)key, 
+			 DES_DECRYPT);
+	memset(key_s, 0, sizeof(key_s));
+    }
+#endif /* R3_NO_MODIFICATIONS */
+
+    /* since the preauth data has the trailing 0, this just works */
+    st = strcmp(preauth_p, name_p);
+    if (st)
+	return KERB_ERR_PREAUTH_MISMATCH;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb4/rd_priv.c b/mechglue/src/lib/krb4/rd_priv.c
new file mode 100644
index 000000000..1ba60081c
--- /dev/null
+++ b/mechglue/src/lib/krb4/rd_priv.c
@@ -0,0 +1,233 @@
+/*
+ * lib/krb4/rd_priv.c
+ *
+ * Copyright 1986, 1987, 1988, 2000 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * This routine dissects a a Kerberos 'private msg', decrypting it,
+ * checking its integrity, and returning a pointer to the application
+ * data contained and its length.
+ *
+ * Returns 0 (RD_AP_OK) for success or an error code (RD_AP_...).  If
+ * the return value is RD_AP_TIME, then either the times are too far
+ * out of synch, OR the packet was modified.
+ *
+ * Steve Miller    Project Athena  MIT/DEC
+ */
+
+/* system include files */
+#include <stdio.h>
+#include <string.h>
+
+/* application include files */
+#include "krb.h"
+#include "prot.h"
+#include "des.h"
+#include "lsb_addr_cmp.h"
+#include "port-sockets.h"
+
+extern int krb_debug;
+
+/* This one is exported, for use by krb_mk_priv.  */
+int private_msg_ver = KRB_PROT_VERSION;
+
+/*
+#ifdef NOENCRPYTION
+ * krb_rd_priv() checks the integrity of an
+#else
+ * krb_rd_priv() decrypts and checks the integrity of an
+#endif
+ * AUTH_MSG_PRIVATE message.  Given the message received, "in",
+ * the length of that message, "in_length", the key "schedule"
+#ifdef NOENCRYPTION
+ * and "key", and the network addresses of the
+#else
+ * and "key" to decrypt with, and the network addresses of the
+#endif
+ * "sender" and "receiver" of the message, krb_rd_safe() returns
+ * RD_AP_OK if the message is okay, otherwise some error code.
+ *
+ * The message data retrieved from "in" are returned in the structure
+#ifdef NOENCRYPTION
+ * "m_data".  The pointer to the application data
+#else
+ * "m_data".  The pointer to the decrypted application data
+#endif
+ * (m_data->app_data) refers back to the appropriate place in "in".
+ *
+ * See the file "mk_priv.c" for the format of the AUTH_MSG_PRIVATE
+ * message.  The structure containing the extracted message
+ * information, MSG_DAT, is defined in "krb.h".
+ */
+
+long KRB5_CALLCONV
+krb_rd_priv(in, in_length, schedule, key, sender, receiver, m_data)
+    u_char *in;			/* pointer to the msg received */
+    unsigned KRB4_32 in_length; /* length of "in" msg */
+    Key_schedule schedule;	/* precomputed key schedule */
+    C_Block *key;		/* encryption key for seed and ivec */
+    struct sockaddr_in *sender;
+    struct sockaddr_in *receiver;
+    MSG_DAT *m_data;		/*various input/output data from msg */
+{
+    register u_char *p,*q;
+    int v, t, le;
+    struct in_addr src_addr;
+    unsigned KRB4_32 c_length;
+    int swap_bytes;
+    unsigned KRB4_32 t_local;
+    KRB4_32 delta_t;		/* Difference between timestamps */
+
+    p = in;			/* beginning of message */
+#define IN_REMAIN (in_length - (p - in))
+    swap_bytes = 0;
+
+    if (IN_REMAIN < 1 + 1 + 4)
+	return RD_AP_MODIFIED;
+    v = *p++;
+    if (v != KRB_PROT_VERSION && v != 3)
+        return RD_AP_VERSION;
+    private_msg_ver = v;
+    t = *p++;
+    if ((t & ~1) != AUTH_MSG_PRIVATE)
+        return RD_AP_MSG_TYPE;
+    le = t & 1;
+
+    /* get cipher length */
+    KRB4_GET32(c_length, p, le);
+    /* check for rational length so we don't go comatose */
+    if (IN_REMAIN < c_length)
+        return RD_AP_MODIFIED;
+
+#ifndef NOENCRYPTION
+    /*
+     * decrypt to obtain length, timestamps, app_data, and checksum
+     * use the session key as an ivec
+     */
+#endif
+
+    q = p;			/* mark start of encrypted stuff */
+
+#ifndef NOENCRYPTION
+    /* pcbc decrypt, use key as ivec */
+    pcbc_encrypt((C_Block *)q, (C_Block *)q, (long)c_length,
+                 schedule, key, DECRYPT);
+#endif
+
+    /* safely get application data length */
+    KRB4_GET32(m_data->app_length, p, le);
+
+    if (IN_REMAIN < m_data->app_length + 4 + 1 + 4)
+	return RD_AP_MODIFIED;
+
+#ifndef NOENCRYPTION
+    /* we're now at the decrypted application data */
+#endif
+    m_data->app_data = p;
+
+    p += m_data->app_length;
+
+    /* safely get time_5ms */
+    m_data->time_5ms = *p++;
+
+    /* safely get src address */
+    memcpy(&src_addr.s_addr, p, sizeof(src_addr.s_addr));
+    /* don't swap, net order always */
+    p += sizeof(src_addr.s_addr);
+
+    if (!krb_ignore_ip_address) {
+	switch (sender->sin_family) {
+	case AF_INET:
+	    if (src_addr.s_addr != sender->sin_addr.s_addr)
+		return RD_AP_MODIFIED;
+	    break;
+#ifdef KRB5_USE_INET6
+	case AF_INET6:
+	    if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr)
+		&& !memcmp (&src_addr.s_addr,
+			    12 + (char *) &((struct sockaddr_in6 *)sender)->sin6_addr,
+			    4))
+		break;
+	    /* Not v4 mapped?  Not ignoring addresses?  You lose.  */
+	    return RD_AP_MODIFIED;
+#endif
+	default:
+	    return RD_AP_MODIFIED;
+	}
+    }
+
+    /* safely get time_sec */
+    KRB4_GET32(m_data->time_sec, p, le);
+
+    /* check direction bit is the sign bit */
+    /* For compatibility with broken old code, compares are done in VAX 
+       byte order (LSBFIRST) */ 
+    /* However, if we don't have good ip addresses anyhow, just clear
+       the bit. This makes it harder to detect replay of sent packets
+       back to the receiver, but most higher level protocols can deal
+       with that more directly. */
+    if (krb_ignore_ip_address) {
+	if (m_data->time_sec < 0)
+	    m_data->time_sec = -m_data->time_sec;
+    } else
+	switch (krb4int_address_less (sender, receiver)) {
+	case 1:
+	    m_data->time_sec = -m_data->time_sec;
+	    break;
+	case -1:
+	    if (m_data->time_sec < 0)
+		m_data->time_sec = -m_data->time_sec;
+	    break;
+	}
+
+    /* check the time integrity of the msg */
+    t_local = TIME_GMT_UNIXSEC;
+    delta_t = t_local - m_data->time_sec;
+    if (delta_t < 0)
+	delta_t = -delta_t;	/* Absolute value of difference */
+    if (delta_t > CLOCK_SKEW)
+        return RD_AP_TIME;	/* XXX should probably be better code */
+    DEB(("\ndelta_t = %d", delta_t));
+
+    /*
+     * caller must check timestamps for proper order and
+     * replays, since server might have multiple clients
+     * each with its own timestamps and we don't assume
+     * tightly synchronized clocks.
+     */
+
+#ifdef notdef
+    memcpy((char *)&cksum, (char *) p, sizeof(cksum));
+    if (swap_bytes) cksum = krb4_swab32(cksum)
+    /*
+     * calculate the checksum of the length, sequence,
+     * and input data, on the sending byte order!!
+     */
+    calc_cksum = quad_cksum(q, NULL, p-q, 0, key);
+
+    DEB (("\ncalc_cksum = %u, received cksum = %u",
+	       calc_cksum, cksum));
+    if (cksum != calc_cksum)
+	return RD_AP_MODIFIED;
+#endif
+    return RD_AP_OK;        /* OK == 0 */
+}
diff --git a/mechglue/src/lib/krb4/rd_req.c b/mechglue/src/lib/krb4/rd_req.c
new file mode 100644
index 000000000..a1d70c643
--- /dev/null
+++ b/mechglue/src/lib/krb4/rd_req.c
@@ -0,0 +1,543 @@
+/*
+ * lib/krb4/rd_req.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000, 2001, 2002 by the
+ * Massachusetts Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "des.h"
+#include "krb.h"
+#include "prot.h"
+#include <string.h>
+#include <krb5.h>
+#include <krb54proto.h>
+
+extern int krb_ap_req_debug;
+
+static int
+krb_rd_req_with_key(KTEXT, char *, char *, KRB_UINT32, AUTH_DAT *,
+		    Key_schedule, krb5_keyblock *);
+
+/* declared in krb.h */
+int krb_ignore_ip_address = 0;
+
+/*
+ * Keep the following information around for subsequent calls
+ * to this routine by the same server using the same key.
+ */
+
+static Key_schedule serv_key;	/* Key sched to decrypt ticket */
+static C_Block ky;              /* Initialization vector */
+static int st_kvno;		/* version number for this key */
+static char st_rlm[REALM_SZ];	/* server's realm */
+static char st_nam[ANAME_SZ];	/* service name */
+static char st_inst[INST_SZ];	/* server's instance */
+static int krb5_key;		/* whether krb5 key is used for decrypt */
+
+/*
+ * This file contains two functions.  krb_set_key() takes a DES
+ * key or password string and returns a DES key (either the original
+ * key, or the password converted into a DES key) and a key schedule
+ * for it.
+ *
+ * krb_rd_req() reads an authentication request and returns information
+ * about the identity of the requestor, or an indication that the
+ * identity information was not authentic.
+ */
+
+/*
+ * krb_set_key() takes as its first argument either a DES key or a
+ * password string.  The "cvt" argument indicates how the first
+ * argument "key" is to be interpreted: if "cvt" is null, "key" is
+ * taken to be a DES key; if "cvt" is non-null, "key" is taken to
+ * be a password string, and is converted into a DES key using
+ * string_to_key().  In either case, the resulting key is returned
+ * in the external static variable "ky".  A key schedule is
+ * generated for "ky" and returned in the external static variable
+ * "serv_key".
+ *
+ * This routine returns the return value of des_key_sched.
+ *
+ * krb_set_key() needs to be in the same .o file as krb_rd_req() so that
+ * the key set by krb_set_key() is available in private storage for
+ * krb_rd_req().
+ */
+
+static krb5_keyblock srv_k5key;
+
+int
+krb_set_key(key, cvt)
+    char *key;
+    int cvt;
+{
+    if (krb5_key)
+	/* XXX assumes that context arg is ignored */
+	krb5_free_keyblock_contents(NULL, &srv_k5key);
+    krb5_key = 0;
+#ifdef NOENCRYPTION
+    memset(ky, 0, sizeof(ky));
+    return KSUCCESS;
+#else /* Encrypt */
+    if (cvt)
+        string_to_key(key, ky);
+    else
+        memcpy((char *)ky, key, 8);
+    return des_key_sched(ky,serv_key);
+#endif /* NOENCRYPTION */
+}
+
+int
+krb_set_key_krb5(ctx, key)
+    krb5_context ctx;
+    krb5_keyblock *key;
+{
+    if (krb5_key)
+	krb5_free_keyblock_contents(ctx, &srv_k5key);
+    krb5_key = 1;
+    return krb5_copy_keyblock_contents(ctx, key, &srv_k5key);
+}
+
+void
+krb_clear_key_krb5(ctx)
+    krb5_context ctx;
+{
+    if (krb5_key)
+	krb5_free_keyblock_contents(ctx, &srv_k5key);
+    krb5_key = 0;
+}
+
+/*
+ * krb_rd_req() takes an AUTH_MSG_APPL_REQUEST or
+ * AUTH_MSG_APPL_REQUEST_MUTUAL message created by krb_mk_req(),
+ * checks its integrity and returns a judgement as to the requestor's
+ * identity.
+ *
+ * The "authent" argument is a pointer to the received message.
+ * The "service" and "instance" arguments name the receiving server,
+ * and are used to get the service's ticket to decrypt the ticket
+ * in the message, and to compare against the server name inside the
+ * ticket.  "from_addr" is the network address of the host from which
+ * the message was received; this is checked against the network
+ * address in the ticket.  If "from_addr" is zero, the check is not
+ * performed.  "ad" is an AUTH_DAT structure which is
+ * filled in with information about the sender's identity according
+ * to the authenticator and ticket sent in the message.  Finally,
+ * "fn" contains the name of the file containing the server's key.
+ * (If "fn" is NULL, the server's key is assumed to have been set
+ * by krb_set_key().  If "fn" is the null string ("") the default
+ * file KEYFILE, defined in "krb.h", is used.)
+ *
+ * krb_rd_req() returns RD_AP_OK if the authentication information
+ * was genuine, or one of the following error codes (defined in
+ * "krb.h"):
+ *
+ *	RD_AP_VERSION		- wrong protocol version number
+ *	RD_AP_MSG_TYPE		- wrong message type
+ *	RD_AP_UNDEC		- couldn't decipher the message
+ *	RD_AP_INCON		- inconsistencies found
+ *	RD_AP_BADD		- wrong network address
+ *	RD_AP_TIME		- client time (in authenticator)
+ *				  too far off server time
+ *	RD_AP_NYV		- Kerberos time (in ticket) too
+ *				  far off server time
+ *	RD_AP_EXP		- ticket expired
+ *
+ * For the message format, see krb_mk_req().
+ *
+ * Mutual authentication is not implemented.
+ */
+
+static int
+krb_rd_req_with_key(authent, service, instance, from_addr, ad, ks, k5key)
+    register KTEXT authent;	/* The received message */
+    char *service;		/* Service name */
+    char *instance;		/* Service instance */
+    unsigned KRB4_32 from_addr; /* Net address of originating host */
+    AUTH_DAT *ad;		/* Structure to be filled in */
+    Key_schedule ks;
+    krb5_keyblock *k5key;
+{
+    KTEXT_ST ticket;		/* Temp storage for ticket */
+    KTEXT tkt = &ticket;
+    KTEXT_ST req_id_st;		/* Temp storage for authenticator */
+    register KTEXT req_id = &req_id_st;
+
+    char realm[REALM_SZ];	/* Realm of issuing kerberos */
+    Key_schedule seskey_sched; /* Key sched for session key */
+    char sname[SNAME_SZ];	/* Service name from ticket */
+    char iname[INST_SZ];	/* Instance name from ticket */
+    char r_aname[ANAME_SZ];	/* Client name from authenticator */
+    char r_inst[INST_SZ];	/* Client instance from authenticator */
+    char r_realm[REALM_SZ];	/* Client realm from authenticator */
+    unsigned int r_time_ms;     /* Fine time from authenticator */
+    unsigned KRB4_32 r_time_sec;   /* Coarse time from authenticator */
+    register unsigned char *ptr; /* For stepping through */
+    unsigned KRB4_32 t_local;	/* Local time on our side of the protocol */
+    KRB4_32 delta_t;      	/* Time in authenticator minus local time */
+#ifdef KRB_CRYPT_DEBUG
+    KRB4_32 tkt_age;		/* Age of ticket */
+#endif
+    int le;			/* is little endian? */
+    int mutual;			/* Mutual authentication requested? */
+    int t;			/* msg type */
+    unsigned char s_kvno;	/* Version number of the server's key
+				   Kerberos used to encrypt ticket */
+    int ret;
+    int len;
+
+    tkt->mbz = req_id->mbz = 0;
+
+    if (authent->length < 1 + 1 + 1)
+	return RD_AP_MODIFIED;
+
+    ptr = authent->dat;
+#define AUTHENT_REMAIN (authent->length - (ptr - authent->dat))
+
+    /* get msg version, type and byte order, and server key version */
+
+    /* check version */
+    if (KRB_PROT_VERSION != *ptr++)
+        return RD_AP_VERSION;
+
+    /* byte order */
+    t = *ptr++;
+    le = t & 1;
+
+    /* check msg type */
+    mutual = 0;
+    switch (t & ~1) {
+    case AUTH_MSG_APPL_REQUEST:
+        break;
+    case AUTH_MSG_APPL_REQUEST_MUTUAL:
+        mutual++;
+        break;
+    default:
+        return RD_AP_MSG_TYPE;
+    }
+
+#ifdef lint
+    /* XXX mutual is set but not used; why??? */
+    /* this is a crock to get lint to shut up */
+    if (mutual)
+        mutual = 0;
+#endif /* lint */
+    s_kvno = *ptr++;		/* get server key version */
+    len = krb4int_strnlen((char *)ptr, AUTHENT_REMAIN) + 1;
+    if (len <= 0 || len > sizeof(realm)) {
+	return RD_AP_MODIFIED;  /* must have been modified, the client wouldn't
+	                           try to trick us with wacky data */
+    }
+    /* And the realm of the issuing KDC */
+    (void)memcpy(realm, ptr, (size_t)len);
+    ptr += len;			/* skip the realm "hint" */
+
+    /* Get ticket length */
+    tkt->length = *ptr++;
+    /* Get authenticator length while we're at it. */
+    req_id->length = *ptr++;
+    if (AUTHENT_REMAIN < tkt->length + req_id->length)
+	return RD_AP_MODIFIED;
+    /* Copy ticket */
+    memcpy(tkt->dat, ptr, (size_t)tkt->length);
+    ptr += tkt->length;
+
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_ap_req_debug)
+        log("ticket->length: %d",tkt->length);
+    if (krb_ap_req_debug)
+	log("authent->length: %d", authent->length);
+#endif
+
+#ifndef NOENCRYPTION
+    /* Decrypt and take apart ticket */
+#endif
+
+    if (k5key == NULL) {
+	if (decomp_ticket(tkt,&ad->k_flags,ad->pname,ad->pinst,ad->prealm,
+			  &(ad->address),ad->session, &(ad->life),
+			  &(ad->time_sec),sname,iname,ky,ks)) {
+#ifdef KRB_CRYPT_DEBUG
+	    log("Can't decode ticket");
+#endif
+	    return(RD_AP_UNDEC);
+	}
+    } else {
+	if (decomp_tkt_krb5(tkt, &ad->k_flags, ad->pname, ad->pinst,
+			    ad->prealm, &ad->address, ad->session,
+			    &ad->life, &ad->time_sec, sname, iname,
+			    k5key)) {
+	    return RD_AP_UNDEC;
+	}
+    }
+
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_ap_req_debug) {
+        log("Ticket Contents.");
+        log(" Aname:   %s%s%s@%s",ad->pname,
+	    ((int)*(ad->pinst) ? "." : ""), ad->pinst,
+            ((int)*(ad->prealm) ? ad->prealm : "Athena"));
+        log(" Service: %s%s%s",sname,((int)*iname ? "." : ""),iname);
+	log("    sname=%s, sinst=%s", sname, iname);
+    }
+#endif
+
+    /* Extract the authenticator */
+    memcpy(req_id->dat, ptr, (size_t)req_id->length);
+
+#ifndef NOENCRYPTION
+    /* And decrypt it with the session key from the ticket */
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_ap_req_debug) log("About to decrypt authenticator");
+#endif
+
+    key_sched(ad->session, seskey_sched);
+    pcbc_encrypt((C_Block *)req_id->dat, (C_Block *)req_id->dat,
+                 (long)req_id->length,
+		 seskey_sched, &ad->session, DES_DECRYPT);
+    memset(seskey_sched, 0, sizeof(seskey_sched));
+
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_ap_req_debug) log("Done.");
+#endif
+#endif /* NOENCRYPTION */
+
+    ptr = req_id->dat;
+#define REQID_REMAIN (req_id->length - (ptr - req_id->dat))
+
+    ret = RD_AP_MODIFIED;
+
+    len = krb4int_strnlen((char *)ptr, REQID_REMAIN) + 1;
+    if (len <= 0 || len > ANAME_SZ)
+	goto cleanup;
+    memcpy(r_aname, ptr, (size_t)len); /* Authentication name */
+    ptr += len;
+    len = krb4int_strnlen((char *)ptr, REQID_REMAIN) + 1;
+    if (len <= 0 || len > INST_SZ)
+	goto cleanup;
+    memcpy(r_inst, ptr, (size_t)len); /* Authentication instance */
+    ptr += len;
+    len = krb4int_strnlen((char *)ptr, REQID_REMAIN) + 1;
+    if (len <= 0 || len > REALM_SZ)
+	goto cleanup;
+    memcpy(r_realm, ptr, (size_t)len); /* Authentication name */
+    ptr += len;
+
+    if (REQID_REMAIN < 4 + 1 + 4)
+	goto cleanup;
+    KRB4_GET32(ad->checksum, ptr, le);
+    r_time_ms = *ptr++;		/* Time (fine) */
+#ifdef lint
+    /* XXX r_time_ms is set but not used.  why??? */
+    /* this is a crock to get lint to shut up */
+    if (r_time_ms)
+        r_time_ms = 0;
+#endif /* lint */
+    /* Time (coarse) */
+    KRB4_GET32(r_time_sec, ptr, le);
+
+    /* Check for authenticity of the request */
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_ap_req_debug)
+        log("Pname:   %s %s",ad->pname,r_aname);
+#endif
+
+    ret = RD_AP_INCON;
+    if (strcmp(ad->pname,r_aname) != 0)
+	goto cleanup;
+    if (strcmp(ad->pinst,r_inst) != 0)
+	goto cleanup;
+
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_ap_req_debug)
+        log("Realm:   %s %s",ad->prealm,r_realm);
+#endif
+
+    if (strcmp(ad->prealm,r_realm) != 0)
+	goto cleanup;
+
+    /* check the time integrity of the msg */
+    ret = RD_AP_TIME;
+    t_local = TIME_GMT_UNIXSEC;
+    delta_t = t_local - r_time_sec;
+    if (delta_t < 0) delta_t = -delta_t;  /* Absolute value of difference */
+    if (delta_t > CLOCK_SKEW) {
+#ifdef KRB_CRYPT_DEBUG
+        if (krb_ap_req_debug)
+            log("Time out of range: %d - %d = %d",
+                time_secs, r_time_sec, delta_t);
+#endif
+	goto cleanup;
+    }
+
+    /* Now check for expiration of ticket */
+
+    ret = RD_AP_NYV;
+#ifdef KRB_CRYPT_DEBUG
+    tkt_age = t_local - ad->time_sec;
+    if (krb_ap_req_debug)
+        log("Time: %d Issue Date: %d Diff: %d Life %x",
+            time_secs, ad->time_sec, tkt_age, ad->life);
+#endif
+    if (t_local < ad->time_sec) {
+        if ((ad->time_sec - t_local) > CLOCK_SKEW)
+	    goto cleanup;
+    } else if (krb_life_to_time((KRB4_32)ad->time_sec, ad->life)
+	     < t_local + CLOCK_SKEW) {
+        /*
+	 * This calculation is different than the same expiration
+	 * calculation in  krb5.  In krb5  the ticket lasts for
+	 * clock_skew seconds longer than its expiration; in krb4 it
+	 * lasts clock_skew seconds less.  This difference is
+	 * necessary to avoid using an almost expired tgt to get a new
+	 * tgt that will last for another 5 minutes.  This code
+	 * interacts with the login in src/kdc/kerberos_v4.c to
+	 * back-date tickets to avoid them expiring late.  The
+	 * combination may be overly conservative, but I'm fairly sure
+	 * either  removing the kerberos_v4 backdating or replacing
+	 * this check with the krb5 check is sufficient to create a
+	 * security problem.
+	 */
+	ret = RD_AP_EXP;
+	goto cleanup;
+    }
+
+#ifdef KRB_CRYPT_DEBUG
+    if (krb_ap_req_debug)
+        log("Address: %d %d",ad->address,from_addr);
+#endif
+
+    if (!krb_ignore_ip_address
+	&& from_addr && (ad->address != from_addr)) {
+	ret = RD_AP_BADD;
+	goto cleanup;
+    }
+
+    /* All seems OK */
+    ad->reply.length = 0;
+    ret = 0;
+
+cleanup:
+    if (ret) {
+	/* Stomp on session key if there is an error. */
+	memset(ad->session, 0, sizeof(ad->session));
+	return ret;
+    }
+
+    return RD_AP_OK;
+}
+
+int KRB5_CALLCONV
+krb_rd_req_int(authent, service, instance, from_addr, ad, key)
+    KTEXT authent;		/* The received message */
+    char *service;		/* Service name */
+    char *instance;		/* Service instance */
+    KRB_UINT32 from_addr;	/* Net address of originating host */
+    AUTH_DAT *ad;		/* Structure to be filled in */
+    C_Block key;		/* Key to decrypt ticket with */
+{
+    Key_schedule ks;
+    int ret;
+
+    do {
+	ret = des_key_sched(key, ks);
+	if (ret) break;
+	ret = krb_rd_req_with_key(authent, service, instance,
+				  from_addr, ad, ks, NULL);
+    } while (0);
+    memset(ks, 0, sizeof(ks));
+    return ret;
+}
+
+int KRB5_CALLCONV
+krb_rd_req(authent, service, instance, from_addr, ad, fn)
+    register KTEXT authent;	/* The received message */
+    char *service;		/* Service name */
+    char *instance;		/* Service instance */
+    unsigned KRB4_32 from_addr; /* Net address of originating host */
+    AUTH_DAT *ad;		/* Structure to be filled in */
+    char *fn;		/* Filename to get keys from */
+{
+    unsigned char *ptr;
+    unsigned char s_kvno;
+    char realm[REALM_SZ];
+    unsigned char skey[KKEY_SZ];
+#ifdef KRB4_USE_KEYTAB
+    krb5_keyblock keyblock;
+#endif
+    int len;
+    int status;
+
+#define AUTHENT_REMAIN (authent->length - (ptr - authent->dat))
+    if (authent->length < 3)
+	return RD_AP_MODIFIED;
+    ptr = authent->dat + 2;
+    s_kvno = *ptr++;		/* get server key version */
+    len = krb4int_strnlen((char *)ptr, AUTHENT_REMAIN) + 1;
+    if (len <= 0 || len > sizeof(realm))
+	return RD_AP_MODIFIED;
+    (void)memcpy(realm, ptr, (size_t)len);
+#undef AUTHENT_REMAIN
+    /*
+     * If "fn" is NULL, key info should already be set; don't
+     * bother with ticket file.  Otherwise, check to see if we
+     * already have key info for the given server and key version
+     * (saved in the static st_* variables).  If not, go get it
+     * from the ticket file.  If "fn" is the null string, use the
+     * default ticket file.
+     */
+    if (fn && (strcmp(st_nam,service) || strcmp(st_inst,instance)
+	       || strcmp(st_rlm,realm) || (st_kvno != s_kvno))) {
+        if (*fn == 0)
+	    fn = KEYFILE;
+        st_kvno = s_kvno;
+        if (read_service_key(service,instance,realm, (int)s_kvno,
+			     fn, (char *)skey) == 0) {
+	    if ((status = krb_set_key((char *)skey,0)))
+		return(status);
+#ifdef KRB4_USE_KEYTAB
+	} else if (krb54_get_service_keyblock(service, instance,
+					      realm, (int)s_kvno,
+					      fn, &keyblock) == 0) {
+	    krb_set_key_krb5(krb5__krb4_context, &keyblock);
+	    krb5_free_keyblock_contents(krb5__krb4_context, &keyblock);
+#endif
+	} else
+	    return RD_AP_UNDEC;
+
+	len = krb4int_strnlen(realm, sizeof(st_rlm)) + 1;
+	if (len <= 0)
+	    return KFAILURE;
+	memcpy(st_rlm, realm, (size_t)len);
+	len = krb4int_strnlen(service, sizeof(st_nam)) + 1;
+	if (len <= 0)
+	    return KFAILURE;
+	memcpy(st_nam, service, (size_t)len);
+	len = krb4int_strnlen(instance, sizeof(st_inst)) + 1;
+	if (len <= 0)
+	    return KFAILURE;
+	memcpy(st_inst, instance, (size_t)len);
+    }
+    return krb_rd_req_with_key(authent, service, instance,
+			       from_addr, ad,
+			       krb5_key ? NULL : serv_key,
+			       krb5_key ? &srv_k5key : NULL);
+}
diff --git a/mechglue/src/lib/krb4/rd_safe.c b/mechglue/src/lib/krb4/rd_safe.c
new file mode 100644
index 000000000..7df0d6599
--- /dev/null
+++ b/mechglue/src/lib/krb4/rd_safe.c
@@ -0,0 +1,208 @@
+/*
+ * lib/krb4/rd_safe.c
+ *
+ * Copyright 1986, 1987, 1988, 2000 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * This routine dissects a a Kerberos 'safe msg', checking its
+ * integrity, and returning a pointer to the application data
+ * contained and its length.
+ *
+ * Returns 0 (RD_AP_OK) for success or an error code (RD_AP_...)
+ *
+ * Steve Miller    Project Athena  MIT/DEC
+ */
+
+/* system include files */
+#include <stdio.h>
+#include <string.h>
+
+/* application include files */
+#include "krb.h"
+#include "prot.h"
+#include "des.h"
+#include "lsb_addr_cmp.h"
+#include "port-sockets.h"
+
+extern int krb_debug;
+
+/*
+ * krb_rd_safe() checks the integrity of an AUTH_MSG_SAFE message.
+ * Given the message received, "in", the length of that message,
+ * "in_length", the "key" to compute the checksum with, and the
+ * network addresses of the "sender" and "receiver" of the message,
+ * krb_rd_safe() returns RD_AP_OK if message is okay, otherwise
+ * some error code.
+ *
+ * The message data retrieved from "in" is returned in the structure
+ * "m_data".  The pointer to the application data (m_data->app_data)
+ * refers back to the appropriate place in "in".
+ *
+ * See the file "mk_safe.c" for the format of the AUTH_MSG_SAFE
+ * message.  The structure containing the extracted message
+ * information, MSG_DAT, is defined in "krb.h".
+ */
+
+long KRB5_CALLCONV
+krb_rd_safe(in,in_length,key,sender,receiver,m_data)
+    u_char *in;			/* pointer to the msg received */
+    unsigned KRB4_32 in_length;		/* length of "in" msg */
+    C_Block *key;			/* encryption key for seed and ivec */
+    struct sockaddr_in *sender;	/* sender's address */
+    struct sockaddr_in *receiver;	/* receiver's address -- me */
+    MSG_DAT *m_data;		/* where to put message information */
+{
+    int i;
+    unsigned KRB4_32 calc_cksum[4];
+    unsigned KRB4_32 big_cksum[4];
+    int le;
+
+    u_char     *p,*q;
+    int t;
+    struct in_addr src_addr;
+    unsigned KRB4_32 t_local;	/* Local time in our machine */
+    KRB4_32 delta_t;		/* Difference between timestamps */
+
+    /* Be very conservative */
+    if (sizeof(src_addr.s_addr) != 4) {
+#ifdef DEBUG
+	fprintf(stderr, "\nkrb_rd_safe protocol err "
+		"sizeof(src_addr.s_addr) != 4\n");
+#endif
+	return RD_AP_VERSION;
+    }
+
+    p = in;                     /* beginning of message */
+#define IN_REMAIN (in_length - (p - in))
+    if (IN_REMAIN < 1 + 1 + 4)
+	return RD_AP_MODIFIED;
+
+    if (*p++ != KRB_PROT_VERSION)
+	return RD_AP_VERSION;
+    t = *p++;
+    if ((t & ~1) != AUTH_MSG_SAFE)
+	return RD_AP_MSG_TYPE;
+    le = t & 1;
+
+    q = p;                      /* mark start of cksum stuff */
+
+    /* safely get length */
+    KRB4_GET32(m_data->app_length, p, le);
+
+    if (IN_REMAIN < m_data->app_length + 1 + 4 + 4 + 4 * 4)
+	return RD_AP_MODIFIED;
+
+    m_data->app_data = p;       /* we're now at the application data */
+
+    /* skip app data */
+    p += m_data->app_length;
+
+    /* safely get time_5ms */
+    m_data->time_5ms = *p++;
+
+    /* safely get src address */
+    (void)memcpy(&src_addr.s_addr, p, sizeof(src_addr.s_addr));
+    /* don't swap, net order always */
+    p += sizeof(src_addr.s_addr);
+
+    if (!krb_ignore_ip_address) {
+	switch (sender->sin_family) {
+	case AF_INET:
+	    if (src_addr.s_addr != sender->sin_addr.s_addr)
+		return RD_AP_MODIFIED;
+	    break;
+#ifdef KRB5_USE_INET6
+	case AF_INET6:
+	    if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)sender)->sin6_addr)
+		&& !memcmp (&src_addr.s_addr,
+			    12 + (char *) &((struct sockaddr_in6 *)sender)->sin6_addr,
+			    4))
+		break;
+	    /* Not v4 mapped?  Not ignoring addresses?  You lose.  */
+	    return RD_AP_MODIFIED;
+#endif
+	default:
+	    return RD_AP_MODIFIED;
+	}
+    }
+
+    /* safely get time_sec */
+    KRB4_GET32(m_data->time_sec, p, le);
+
+    /* check direction bit is the sign bit */
+    /* For compatibility with broken old code, compares are done in VAX 
+       byte order (LSBFIRST) */ 
+    /* However, if we don't have good ip addresses anyhow, just clear
+       the bit. This makes it harder to detect replay of sent packets
+       back to the receiver, but most higher level protocols can deal
+       with that more directly. */
+    if (krb_ignore_ip_address) {
+	if (m_data->time_sec < 0)
+	    m_data->time_sec = -m_data->time_sec;
+    } else
+	switch (krb4int_address_less (sender, receiver)) {
+	case 1:
+	    m_data->time_sec = -m_data->time_sec;
+	    break;
+	case -1:
+	    if (m_data->time_sec < 0)
+		m_data->time_sec = -m_data->time_sec;
+	    break;
+	}
+
+    /* check the time integrity of the msg */
+    t_local = TIME_GMT_UNIXSEC;
+    delta_t = t_local - m_data->time_sec;
+    if (delta_t < 0) delta_t = -delta_t;  /* Absolute value of difference */
+    if (delta_t > CLOCK_SKEW) {
+        return(RD_AP_TIME);		/* XXX should probably be better
+					   code */
+    }
+
+    /*
+     * caller must check timestamps for proper order and replays, since
+     * server might have multiple clients each with its own timestamps
+     * and we don't assume tightly synchronized clocks.
+     */
+
+#ifdef NOENCRYPTION
+    memset(calc_cksum, 0, sizeof(calc_cksum));
+#else /* Do encryption */
+    /* calculate the checksum of the length, timestamps, and
+     * input data, on the sending byte order !! */
+    quad_cksum(q,calc_cksum,p-q,2,key);
+#endif /* NOENCRYPTION */
+
+    for (i = 0; i < 4; i++)
+	KRB4_GET32(big_cksum[i], p, le);
+
+    DEB (("\n0: calc %l big %lx\n1: calc %lx big %lx\n2: calc %lx big %lx\n3: calc %lx big %lx\n",
+               calc_cksum[0], big_cksum[0],
+               calc_cksum[1], big_cksum[1],
+               calc_cksum[2], big_cksum[2],
+               calc_cksum[3], big_cksum[3]));
+    for (i = 0; i < 4; i++)
+	if (big_cksum[i] != calc_cksum[i])
+	    return RD_AP_MODIFIED;
+
+    return RD_AP_OK;		/* OK == 0 */
+}
diff --git a/mechglue/src/lib/krb4/rd_svc_key.c b/mechglue/src/lib/krb4/rd_svc_key.c
new file mode 100644
index 000000000..2728f4a1c
--- /dev/null
+++ b/mechglue/src/lib/krb4/rd_svc_key.c
@@ -0,0 +1,344 @@
+/*
+ * rd_svc_key.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
+ * of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include "mit-copyright.h"
+#include "krb.h"
+#include "krb4int.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "k5-int.h"
+#include <krb54proto.h>
+#include "prot.h"
+
+/*
+ * The private keys for servers on a given host are stored in a
+ * "srvtab" file (typically "/etc/srvtab").  This routine extracts
+ * a given server's key from the file.
+ *
+ * read_service_key() takes the server's name ("service"), "instance",
+ * and "realm" and a key version number "kvno", and looks in the given
+ * "file" for the corresponding entry, and if found, returns the entry's
+ * key field in "key".
+ * 
+ * If "instance" contains the string "*", then it will match
+ * any instance, and the chosen instance will be copied to that
+ * string.  For this reason it is important that the there is enough
+ * space beyond the "*" to receive the entry.
+ *
+ * If "kvno" is 0, it is treated as a wild card and the first
+ * matching entry regardless of the "vno" field is returned.
+ *
+ * This routine returns KSUCCESS on success, otherwise KFAILURE.
+ *
+ * The format of each "srvtab" entry is as follows:
+ *
+ * Size			Variable		Field in file
+ * ----			--------		-------------
+ * string		serv			server name
+ * string		inst			server instance
+ * string		realm			server realm
+ * 1 byte		vno			server key version #
+ * 8 bytes		key			server's key
+ * ...			...			...
+ */
+
+#ifdef __i960__
+/* special hack to use a global srvtab variable... */
+#define open vxworks_srvtab_open
+#define close vxworks_srvtab_close
+#define getst vxworks_srvtab_getst
+#define read vxworks_srvtab_read
+
+extern char *vxworks_srvtab_base;
+char *vxworks_srvtab_ptr;
+int vxworks_srvtab_getchar(s)
+     char *s;
+{
+  int tmp1;
+  if(vxworks_srvtab_ptr >= (vxworks_srvtab_base + strlen(vxworks_srvtab_base)))
+    return 0;
+
+  sscanf(vxworks_srvtab_ptr, "%2x", &tmp1);
+
+  *s = tmp1;
+  vxworks_srvtab_ptr+=2;
+  return 1;
+}
+
+int vxworks_srvtab_getst(fd,s,n)
+    int fd;
+    register char *s;
+    int n;
+{
+    register count = n;
+    while (vxworks_srvtab_getchar(s) && --count)
+        if (*s++ == '\0')
+            return (n - count);
+    *s = '\0';
+    return (n - count);
+}
+
+int vxworks_srvtab_open(s, n, m)
+     char *s;
+     int n, m;
+{
+  vxworks_srvtab_ptr = vxworks_srvtab_base;
+  return 1;
+}
+
+int vxworks_srvtab_close(fd)
+     int fd;
+{
+  vxworks_srvtab_ptr = 0;
+  return 0;
+}
+
+int vxworks_srvtab_read(fd, s, n)
+     int fd;
+     char *s;
+     int n;
+{
+  int count = n;
+  /* we want to get exactly n chars. */
+  while(vxworks_srvtab_getchar(s) && --count)
+    s++;
+  return (n-count);
+}
+#endif
+
+#ifdef KRB4_USE_KEYTAB
+/*
+ * This function looks up the requested Krb4 srvtab key using the krb5
+ * keytab format, if possible.
+ */
+extern krb5_error_code
+krb54_get_service_keyblock(service,instance,realm,kvno,file,keyblock)
+    char *service;		/* Service Name */
+    char *instance;		/* Instance name or "*" */
+    char *realm;		/* Realm */
+    int kvno;			/* Key version number */
+    char *file;		/* Filename */
+    krb5_keyblock * keyblock;
+{
+    krb5_error_code retval;
+    krb5_principal princ = NULL;
+    krb5_keytab kt_id;
+    krb5_keytab_entry kt_entry;
+    char sname[ANAME_SZ+1];
+    char sinst[INST_SZ+1];
+    char srealm[REALM_SZ+1];
+    char keytabname[MAX_KEYTAB_NAME_LEN + 1];	/* + 1 for NULL termination */
+
+    if (!krb5__krb4_context) {
+	    retval = krb5_init_context(&krb5__krb4_context);
+	    if (retval)
+		    return retval;
+    }
+
+    if (!strcmp(instance, "*")) {
+	if ((retval = krb5_sname_to_principal(krb5__krb4_context, NULL, NULL,
+					      KRB5_NT_SRV_HST, &princ)))
+	    goto errout;
+	
+	if ((retval = krb5_524_conv_principal(krb5__krb4_context, princ,
+					      sname, sinst, srealm)))
+	    goto errout;
+
+	instance = sinst;
+	krb5_free_principal(krb5__krb4_context, princ);
+	princ = 0;
+    }
+    
+    if ((retval = krb5_425_conv_principal(krb5__krb4_context, service,
+					  instance, realm, &princ)))
+	goto errout;
+
+    /*
+     * Figure out what name to use; if the name is one of the standard
+     * /etc/srvtab, /etc/athena/srvtab, etc., use the default keytab
+     * name.  Otherwise, append .krb5 to the filename and try to use
+     * that.
+     */
+    if (file &&
+	strcmp(file, "/etc/srvtab") &&
+	strcmp(file, "/etc/athena/srvtab") &&
+	strcmp(file, KEYFILE)) {
+	    strncpy(keytabname, file, sizeof(keytabname));
+	    keytabname[sizeof(keytabname)-1] = 0;
+	    if (strlen(keytabname)+6 < sizeof(keytabname))
+		    strcat(keytabname, ".krb5");
+    } else {
+	    if ((retval = krb5_kt_default_name(krb5__krb4_context,
+				(char *)keytabname, sizeof(keytabname)-1)))
+		    goto errout;
+    }
+    
+    if ((retval = krb5_kt_resolve(krb5__krb4_context, keytabname, &kt_id)))
+	    goto errout;
+
+    if ((retval = krb5_kt_get_entry(krb5__krb4_context, kt_id, princ, kvno,
+				    0, &kt_entry))) {
+	krb5_kt_close(krb5__krb4_context, kt_id);
+	goto errout;
+    }
+
+    retval = krb5_copy_keyblock_contents(krb5__krb4_context,
+					 &kt_entry.key, keyblock);
+    /* Bash types */
+    /* KLUDGE! If it's a non-raw des3 key, bash its enctype */
+    /* See kdc/kerberos_v4.c */
+    if (keyblock->enctype == ENCTYPE_DES3_CBC_SHA1 )
+      keyblock->enctype = ENCTYPE_DES3_CBC_RAW;
+    
+    krb5_kt_free_entry(krb5__krb4_context, &kt_entry);
+    krb5_kt_close (krb5__krb4_context, kt_id);
+
+errout:
+    if (princ)
+	krb5_free_principal(krb5__krb4_context, princ);
+    return retval;
+}
+#endif
+
+
+int KRB5_CALLCONV
+read_service_key(service,instance,realm,kvno,file,key)
+    char *service;		/* Service Name */
+    char *instance;		/* Instance name or "*" */
+    char *realm;		/* Realm */
+    int kvno;			/* Key version number */
+    char *file;		/* Filename */
+    char *key;		/* Pointer to key to be filled in */
+{
+    int kret;
+    
+#ifdef KRB4_USE_KEYTAB
+    krb5_error_code	retval;
+    krb5_keyblock 	keyblock;
+#endif
+
+    kret = get_service_key(service,instance,realm,&kvno,file,key);
+
+    if (! kret)
+	return KSUCCESS;
+
+#ifdef KRB4_USE_KEYTAB
+    kret = KFAILURE;
+    keyblock.magic = KV5M_KEYBLOCK;
+    keyblock.contents = 0;
+
+    retval = krb54_get_service_keyblock(service,instance,realm,kvno,file,
+					&keyblock);
+    if (retval)
+	    goto errout;
+
+    if ((keyblock.length != sizeof(C_Block)) ||
+	((keyblock.enctype != ENCTYPE_DES_CBC_CRC) &&
+	 (keyblock.enctype != ENCTYPE_DES_CBC_MD4) &&
+	 (keyblock.enctype != ENCTYPE_DES_CBC_MD5))) {
+	    goto errout;
+    }
+    (void) memcpy(key, keyblock.contents, sizeof(C_Block));
+    kret = KSUCCESS;
+    
+errout:
+    if (keyblock.contents)
+	    krb5_free_keyblock_contents(krb5__krb4_context, &keyblock);
+#endif
+    
+    return kret;
+}
+
+/* kvno is passed by reference, so that if it is zero, and we find a match,
+   the match gets written back into *kvno so the caller can find it.
+ */
+int KRB5_CALLCONV
+get_service_key(service,instance,realm,kvno,file,key)
+    char *service;              /* Service Name */
+    char *instance;             /* Instance name or "*" */
+    char *realm;                /* Realm */
+    int *kvno;                 /* Key version number */
+    char *file;                 /* Filename */
+    char *key;                  /* Pointer to key to be filled in */
+{
+    char serv[SNAME_SZ];
+    char inst[INST_SZ];
+    char rlm[REALM_SZ];
+    unsigned char vno;          /* Key version number */
+    int wcard;
+    char krb_realm[REALM_SZ];
+
+    int stab;
+
+    if (!file)
+	file = KEYFILE;
+
+    if ((stab = open(file, 0, 0)) < 0)
+        return(KFAILURE);
+
+    wcard = (instance[0] == '*') && (instance[1] == '\0');
+    /* get current realm if not passed in */
+    if (!realm) {
+	int rem;
+
+	rem = krb_get_lrealm(krb_realm,1);
+	if (rem != KSUCCESS)
+	    return(rem);
+	realm = krb_realm;
+    }
+
+    while(getst(stab,serv,SNAME_SZ) > 0) { /* Read sname */
+        (void) getst(stab,inst,INST_SZ); /* Instance */
+        (void) getst(stab,rlm,REALM_SZ); /* Realm */
+        /* Vers number */
+        if (read(stab,(char *)&vno,1) != 1) {
+	    close(stab);
+            return(KFAILURE);
+	}
+        /* Key */
+        if (read(stab,key,8) != 8) {
+	    close(stab);
+            return(KFAILURE);
+	}
+        /* Is this the right service */
+        if (strcmp(serv,service))
+            continue;
+        /* How about instance */
+        if (!wcard && strcmp(inst,instance))
+            continue;
+        if (wcard)
+            (void) strncpy(instance,inst,INST_SZ);
+        /* Is this the right realm */
+#if defined(ATHENA_COMPAT) || defined(ATHENA_OLD_SRVTAB)
+	/* XXX For backward compatibility:  if keyfile says "Athena"
+	   and caller wants "ATHENA.MIT.EDU", call it a match */
+        if (strcmp(rlm,realm) &&
+	    (strcmp(rlm,"Athena") ||
+	     strcmp(realm,"ATHENA.MIT.EDU")))
+	    continue;
+#else /* ! ATHENA_COMPAT */
+        if (strcmp(rlm,realm)) 
+	    continue;
+#endif /* ATHENA_COMPAT */
+
+        /* How about the key version number */
+        if (*kvno && *kvno != (int) vno)
+            continue;
+
+        (void) close(stab);
+	*kvno = vno;
+        return(KSUCCESS);
+    }
+
+    /* Can't find the requested service */
+    (void) close(stab);
+    return(KFAILURE);
+}
diff --git a/mechglue/src/lib/krb4/recvauth.c b/mechglue/src/lib/krb4/recvauth.c
new file mode 100644
index 000000000..bd2aca56a
--- /dev/null
+++ b/mechglue/src/lib/krb4/recvauth.c
@@ -0,0 +1,308 @@
+/*
+ * lib/krb4/recvauth.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "krb5/autoconf.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "port-sockets.h"
+
+
+#define	KRB_SENDAUTH_VERS	"AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN
+					      chars */
+
+/*
+ * If the protocol changes, you will need to change the version string
+ * and make appropriate changes in krb_sendauth.c
+ * be sure to support old versions of krb_sendauth!
+ */
+
+/*
+ * krb_recvauth() reads (and optionally responds to) a message sent
+ * using krb_sendauth().  The "options" argument is a bit-field of
+ * selected options (see "sendauth.c" for options description).
+ * The only option relevant to krb_recvauth() is KOPT_DO_MUTUAL
+ * (mutual authentication requested).  The "fd" argument supplies
+ * a file descriptor to read from (and write to, if mutual authenti-
+ * cation is requested).
+ *
+ * Part of the received message will be a Kerberos ticket sent by the
+ * client; this is read into the "ticket" argument.  The "service" and
+ * "instance" arguments supply the server's Kerberos name.  If the
+ * "instance" argument is the string "*", it is treated as a wild card
+ * and filled in during the krb_rd_req() call (see read_service_key()).
+ *
+ * The "faddr" and "laddr" give the sending (client) and receiving
+ * (local server) network addresses.  ("laddr" may be left NULL unless
+ * mutual authentication is requested, in which case it must be set.)
+ *
+ * The authentication information extracted from the message is returned
+ * in "kdata".  The "filename" argument indicates the file where the
+ * server's key can be found.  (It is passed on to krb_rd_req().)  If
+ * left null, the default "/etc/srvtab" will be used.
+ *
+ * If mutual authentication is requested, the session key schedule must
+ * be computed in order to reply; this schedule is returned in the
+ * "schedule" argument.  A string containing the application version
+ * number from the received message is returned in "version", which
+ * should be large enough to hold a KRB_SENDAUTH_VLEN-character string.
+ *
+ * See krb_sendauth() for the format of the received client message.
+ *
+ * This routine supports another client format, for backward
+ * compatibility, consisting of:
+ *
+ * Size			Variable		Field
+ * ----			--------		-----
+ *
+ * string		tmp_buf, tkt_len	length of ticket, in
+ * 						ascii
+ *
+ * char			' ' (space char)	separator
+ *
+ * tkt_len		ticket->dat		the ticket
+ *
+ * This old-style version does not support mutual authentication.
+ *
+ * krb_recvauth() first reads the protocol version string from the
+ * given file descriptor.  If it doesn't match the current protocol
+ * version (KRB_SENDAUTH_VERS), the old-style format is assumed.  In
+ * that case, the string of characters up to the first space is read
+ * and interpreted as the ticket length, then the ticket is read.
+ *
+ * If the first string did match KRB_SENDAUTH_VERS, krb_recvauth()
+ * next reads the application protocol version string.  Then the
+ * ticket length and ticket itself are read.
+ *
+ * The ticket is decrypted and checked by the call to krb_rd_req().
+ * If no mutual authentication is required, the result of the
+ * krb_rd_req() call is retured by this routine.  If mutual authenti-
+ * cation is required, a message in the following format is returned
+ * on "fd":
+ *
+ * Size			Variable		Field
+ * ----			--------		-----
+ *
+ * 4 bytes		tkt_len			length of ticket or -1
+ *						if error occurred
+ *
+ * priv_len		tmp_buf			"private" message created
+ *						by krb_mk_priv() which
+ *						contains the incremented
+ *						checksum sent by the client
+ *						encrypted in the session
+ *						key.  (This field is not
+ *						present in case of error.)
+ *
+ * If all goes well, KSUCCESS is returned; otherwise KFAILURE or some
+ * other error code is returned.
+ */
+
+#ifndef max
+#define	max(a,b) (((a) > (b)) ? (a) : (b))
+#endif /* max */
+
+int KRB5_CALLCONV
+krb_recvauth(options, fd, ticket, service, instance, faddr, laddr, kdata,
+	     filename, schedule, version)
+    long options;			 /* bit-pattern of options */
+    int fd;				 /* file descr. to read from */
+    KTEXT ticket;			 /* storage for client's ticket */
+    char *service;			 /* service expected */
+    char *instance;			 /* inst expected (may be filled in) */
+    struct sockaddr_in *faddr;	 /* address of foreign host on fd */
+    struct sockaddr_in *laddr;	 /* local address */
+    AUTH_DAT *kdata;		 /* kerberos data (returned) */
+    char *filename;			 /* name of file with service keys */
+    Key_schedule schedule;		 /* key schedule (return) */
+    char *version;			 /* version string (filled in) */
+{
+
+    int i, cc, old_vers = 0;
+    char krb_vers[KRB_SENDAUTH_VLEN + 1]; /* + 1 for the null terminator */
+    char *cp = NULL;
+    int rem;
+    KRB4_32 tkt_len, priv_len;
+    unsigned KRB4_32 cksum;
+    u_char tmp_buf[MAX_KTXT_LEN+max(KRB_SENDAUTH_VLEN+1,21)] = { 0 };
+
+    /* read the protocol version number */
+    if (krb_net_read(fd, krb_vers, KRB_SENDAUTH_VLEN) !=
+	KRB_SENDAUTH_VLEN)
+	    return(errno);
+    krb_vers[KRB_SENDAUTH_VLEN] = '\0';
+
+    /* check version string */
+    if (strcmp(krb_vers,KRB_SENDAUTH_VERS)) {
+	/* Assume the old version of sendkerberosdata: send ascii
+	   length, ' ', and ticket. */
+	if (options & KOPT_DO_MUTUAL)
+	    return(KFAILURE);	 /* XXX can't do old style with mutual auth */
+	old_vers = 1;
+
+	/* copy what we have read into tmp_buf */
+	(void) memcpy((char *) tmp_buf, krb_vers, KRB_SENDAUTH_VLEN);
+
+	/* search for space, and make it a null */
+	for (i = 0; i < KRB_SENDAUTH_VLEN; i++)
+	    if (tmp_buf[i]== ' ') {
+		tmp_buf[i] = '\0';
+		/* point cp to the beginning of the real ticket */
+		cp = (char *) &tmp_buf[i+1];
+		break;
+	    }
+
+	if (i == KRB_SENDAUTH_VLEN)
+	    /* didn't find the space, keep reading to find it */
+	    for (; i<20; i++) {
+		if (read(fd, (char *)&tmp_buf[i], 1) != 1) {
+		    return(KFAILURE);
+		}
+		if (tmp_buf[i] == ' ') {
+		    tmp_buf[i] = '\0';
+		    /* point cp to the beginning of the real ticket */
+		    cp = (char *) &tmp_buf[i+1];
+		    break;
+		}
+	    }
+
+	if (i==20)
+	    return(KFAILURE);
+
+	tkt_len = (KRB4_32) atoi((char *) tmp_buf);
+
+	/* sanity check the length */
+	/* These conditions make sure that cp got initialized */
+	if ((tkt_len<=0)||(tkt_len>MAX_KTXT_LEN))
+	    return(KFAILURE);
+
+	if (i < KRB_SENDAUTH_VLEN) {
+	    /* since we already got the space, and part of the ticket,
+	       we read fewer bytes to get the rest of the ticket */
+	    int len_to_read = tkt_len - KRB_SENDAUTH_VLEN + 1 + i;
+	    if (len_to_read <= 0)
+		return KFAILURE;
+	    if (krb_net_read(fd, (char *)(tmp_buf+KRB_SENDAUTH_VLEN),
+			     len_to_read)
+		!= len_to_read)
+		return(errno);
+	} else {
+	    if (krb_net_read(fd, (char *)(tmp_buf+i), (int)tkt_len) !=
+		(int) tkt_len)
+		return(errno);
+	}
+	ticket->length = tkt_len;
+	/* copy the ticket into the struct */
+	(void) memcpy((char *) ticket->dat, cp, ticket->length);
+
+    } else {
+	/* read the application version string */
+	if (krb_net_read(fd, version, KRB_SENDAUTH_VLEN) !=
+	    KRB_SENDAUTH_VLEN)
+	    return(errno);
+	version[KRB_SENDAUTH_VLEN] = '\0';
+
+	/* get the length of the ticket */
+	if (krb_net_read(fd, (char *)&tkt_len, sizeof(tkt_len)) !=
+	    sizeof(tkt_len))
+	    return(errno);
+    
+	/* sanity check */
+	ticket->length = ntohl((unsigned KRB4_32)tkt_len);
+	if ((ticket->length <= 0) || (ticket->length > MAX_KTXT_LEN)) {
+	    if (options & KOPT_DO_MUTUAL) {
+		rem = KFAILURE;
+		goto mutual_fail;
+	    } else
+		return(KFAILURE); /* XXX there may still be junk on the fd? */
+	}
+
+	/* read the ticket */
+	if (krb_net_read(fd, (char *) ticket->dat, ticket->length)
+	    != ticket->length)
+	    return(errno);
+    }
+    /*
+     * now have the ticket.  decrypt it to get the authenticated
+     * data.
+     */
+    rem = krb_rd_req(ticket,service,instance,faddr->sin_addr.s_addr,
+		     kdata,filename);
+
+    if (old_vers) return(rem);	 /* XXX can't do mutual with old client */
+
+    /* if we are doing mutual auth, compose a response */
+    if (options & KOPT_DO_MUTUAL) {
+	if (rem != KSUCCESS)
+	    /* the krb_rd_req failed */
+	    goto mutual_fail;
+
+	/* add one to the (formerly) sealed checksum, and re-seal it
+	   for return to the client */
+	cksum = kdata->checksum + 1;
+	cksum = htonl(cksum);
+#ifndef NOENCRYPTION
+	key_sched(kdata->session,schedule);
+#endif /* !NOENCRYPTION */
+	priv_len = krb_mk_priv((unsigned char *)&cksum,
+			       tmp_buf,
+			       (unsigned KRB4_32) sizeof(cksum),
+			       schedule,
+			       &kdata->session,
+			       laddr,
+			       faddr);
+	if (priv_len < 0) {
+	    /* re-sealing failed; notify the client */
+	    rem = KFAILURE;	 /* XXX */
+mutual_fail:
+	    priv_len = -1;
+	    tkt_len = htonl((unsigned KRB4_32) priv_len);
+	    /* a length of -1 is interpreted as an authentication
+	       failure by the client */
+	    if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
+		!= sizeof(tkt_len))
+		return(cc);
+	    return(rem);
+	} else {
+	    /* re-sealing succeeded, send the private message */
+	    tkt_len = htonl((unsigned KRB4_32)priv_len);
+	    if ((cc = krb_net_write(fd, (char *)&tkt_len, sizeof(tkt_len)))
+		 != sizeof(tkt_len))
+		return(cc);
+	    if ((cc = krb_net_write(fd, (char *)tmp_buf, (int) priv_len))
+		!= (int) priv_len)
+		return(cc);
+	}
+    }
+    return(rem);
+}
diff --git a/mechglue/src/lib/krb4/ren-cyg.sh b/mechglue/src/lib/krb4/ren-cyg.sh
new file mode 100755
index 000000000..d3d31a9d4
--- /dev/null
+++ b/mechglue/src/lib/krb4/ren-cyg.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Rename Kerberos Cygnus V4 filenames to proposed names
+# for converting old trees.
+awk '/^@ / {	if ($6 != "")
+			if ($6 != $4)
+				print "mv	" $6 "	" $4
+			else ;
+		else if ($2 != $4 && $2 != "-")
+			print "mv	" $2 "	" $4
+	  }
+    ' <ren.msg | grep -v '(gone)' | sh -x
diff --git a/mechglue/src/lib/krb4/ren-pc.bat b/mechglue/src/lib/krb4/ren-pc.bat
new file mode 100644
index 000000000..e25755fdb
--- /dev/null
+++ b/mechglue/src/lib/krb4/ren-pc.bat
@@ -0,0 +1,29 @@
+rename	crerrep.c	cr_err_repl.c
+rename	crauthre.c	cr_auth_repl.c
+rename	cr_death.c	cr_death_pkt.c
+rename	crticket.c	cr_tkt.c
+rename	decomtkt.c	decomp_tkt.c
+rename	getadtkt.c	g_ad_tkt.c
+rename	getadmhs.c	g_admhst.c
+rename	get_cred.c	g_cred.c
+rename	getintkt.c	g_pw_in_tkt.c
+rename	getkrbhs.c	g_krbhst.c
+rename	getphost.c	g_phost.c
+rename	getpwtkt.c	g_pw_tkt.c
+rename	get_req.c	g_request.c
+rename	g_svctkt.c	g_svc_in_tkt.c
+rename	gettfnam.c	g_tf_fname.c
+rename	gettfrlm.c	g_tf_realm.c
+rename	getrealm.c	realmofhost.c
+rename	k_gethst.c	gethostname.c
+rename	knm_pars.c	kname_parse.c
+rename	k_errtxt.c	err_txt.c
+rename	k_gettkt.c	g_in_tkt.c
+rename	mth_snam.c	month_sname.c
+rename	pkt_ciph.c	pkt_cipher.c
+rename	rdservky.c	rd_svc_key.c
+rename	savecred.c	save_creds.c
+rename	send_kdc.c	send_to_kdc.c
+rename	s_cascmp.c	strcasecmp.c
+rename	tkt_strg.c	tkt_string.c
+rename	util.c	ad_print.c
diff --git a/mechglue/src/lib/krb4/ren-pc.sh b/mechglue/src/lib/krb4/ren-pc.sh
new file mode 100644
index 000000000..bea2beb01
--- /dev/null
+++ b/mechglue/src/lib/krb4/ren-pc.sh
@@ -0,0 +1,7 @@
+# Rename Kerberos V4 MIT PC-port filenames to proposed names
+# for converting old PC trees on Unix systems.
+awk '/^@ / {
+		if ($3 != $4 && $3 != "-")
+			print "mv	" $3 "	" $4
+	   }
+    ' <ren.msg | grep -v '(gone)' | sh -x
diff --git a/mechglue/src/lib/krb4/ren-pl10.sh b/mechglue/src/lib/krb4/ren-pl10.sh
new file mode 100644
index 000000000..d72a72c50
--- /dev/null
+++ b/mechglue/src/lib/krb4/ren-pl10.sh
@@ -0,0 +1,7 @@
+# Rename Kerberos V4 pl10 filenames to proposed names
+# for converting old trees.
+awk '/^@ / {
+		if ($2 != $4 && $2 != "-")
+			print "mv	" $2 "	" $4
+	   }
+    ' <ren.msg | grep -v '(gone)' | sh -x
diff --git a/mechglue/src/lib/krb4/ren.msg b/mechglue/src/lib/krb4/ren.msg
new file mode 100644
index 000000000..45b404afa
--- /dev/null
+++ b/mechglue/src/lib/krb4/ren.msg
@@ -0,0 +1,117 @@
+Subject: Kerberos file renaming for short DOS names
+Date: Tue, 19 Apr 1994 13:34:28 -0700
+From: John Gilmore <gnu@cygnus.com>
+
+[edited since sending, to bring it up to date with what actually happened.]
+
+I'd like to come up with some file naming and configuration
+conventions that will work in DOS, Unix, and Mac environments.  At
+Cygnus, we are creating a single freely available K4 source tree that
+works on many Unixes, Windows, and Mac.  It currently works on Unixes.
+(To get a copy, send mail to info@cygnus.com requesting our Kerberos
+release.  It's in a hidden FTP location due to export control.)
+
+I diffed the current MIT release of Kerberos for PC and Windows
+against the V4 patchlevel 10 release, and identified some 30 files in
+lib/krb that have been renamed between Unix and PC.  Comparing source
+trees becomes much more painful when files are renamed.  If we don't
+come to sync on the file names, it will be very hard to collaborate,
+which would make more work for all of us.
+
+My plan, which we have used successfully in the GNU software, is to
+make sure that all filenames are unique if you take the first 8 chars
+and the first 3 after the dot.  No files have more than a single dot
+in them.  We don't restrict file names to just 8.3 characters, since
+doing so would impact readability for the (99.9%) of the developers
+who are on Unix or Mac, where long file names are fine.
+
+There's an additional complication that names longer than 14
+characters present problems to old System V Unix and to `ar' on Unix.
+DJ Delorie's excellent `doschk' program points out all these problems.
+(prep.ai.mit.edu:/pub/gnu/doschk-1.1.tar.gz).
+
+Here's my proposal for the lib/krb directory.  In general, I tried to
+regularize the names, turning get_ into g_, removing krb_, turning
+reply into repl, turning ticket into tkt, keeping all file names
+unique across the various libraries, and making a file name more like
+the function name contained in it when there were conflicts.  Some
+resulting truncated names are more readable than in the current MIT K4
+PC, some are less readable -- but the overall advantage is that the
+new names should be acceptable to Unix/Mac developers, while the old
+ones weren't.
+
+  MIT K4 patch10	MIT K4 PC	PROPOSED NAME	(trunc to 8.3)	old Cyg
+$1     $2		$3		$4		$5		$6
+
+@ add_ticket.c		(gone)		add_tkt.c	add_tkt.c	
+@ -			-		ChangeLog	changelo
+@ cr_err_reply.c	crerrep.c	cr_err_repl.c	cr_err_r.c
+@ create_auth_reply.c	crauthre.c	cr_auth_repl.c	cr_auth_.c	cr_auth_reply.c
+@ create_ciph.c		cr_ciph.c	cr_ciph.c	cr_ciph.c
+@ create_death_packet.c	cr_death.c	cr_death_pkt.c	cr_death.c	cr_death_pkt.c
+@ create_ticket.c	crticket.c	cr_tkt.c	cr_tkt.c
+@ debug_decl.c		debug.c		debug.c		debug.c
+@ decomp_ticket.c	decomtkt.c	decomp_tkt.c	decomp_t.c
+@ -			-		DNR.c		dnr.c
+@ extract_ticket.c	ext_tkt.c	ext_tkt.c	ext_tkt.c	extract_tkt.c
+@ -			-		g_cnffile.c	g_cnffil.c
+@ get_ad_tkt.c		getadtkt.c	g_ad_tkt.c	g_ad_tkt.c
+@ get_admhst.c		getadmhs.c	g_admhst.c	g_admhst.c
+@ get_cred.c		get_cred.c	g_cred.c	g_cred.c
+@ get_in_tkt.c		getintkt.c	g_pw_in_tkt.c	g_pw_in_.c
+@ get_krbhst.c		getkrbhs.c	g_krbhst.c	g_krbhst.c
+@ get_krbrlm.c		g_krbrlm.c	g_krbrlm.c	g_krbrlm.c
+@ get_phost.c		getphost.c	g_phost.c	g_phost.c
+@ get_pw_tkt.c		getpwtkt.c	g_pw_tkt.c	g_pw_tkt.c
+@ get_request.c		get_req.c	(gone)		(gone)
+@ get_svc_in_tkt.c	g_svctkt.c	g_svc_in_tkt.c	g_svc_in.c	get_svc_in.c
+@ get_tf_fullname.c	gettfnam.c	g_tf_fname.c	g_tf_fna.c	get_tf_fname.c
+@ get_tf_realm.c	gettfrlm.c	g_tf_realm.c	g_tf_rea.c
+@ -			-		g_tkt_svc.c	g_tkt_sv.c
+@ getrealm.c		getrealm.c	realmofhost.c	realmofh.c
+@ k_gethostname.c	k_gethst.c	gethostname.c	gethostn.c
+@ kname_parse.c		knm_pars.c	kname_parse.c	kname_pa.c
+@ krb_err_txt.c		k_errtxt.c	err_txt.c	err_txt.c
+@ krb_get_in_tkt.c	k_gettkt.c	g_in_tkt.c	g_in_tkt.c	krb_get_in.c
+@ -			-		mac_store.c	mac_stor.c
+@ -			-		mac_store.h	mac_stor.h
+@ -			-		mac_stubs.c	mac_stub.c
+@ -			-		Makefile.in	makefile.in
+@ -			-		mk_preauth.c	mk_preau.c
+@ month_sname.c		mth_snam.c	month_sname.c	month_sn.c
+@ pkt_cipher.c		pkt_ciph.c	pkt_cipher.c	pkt_ciph.c
+@ -			-		Password.c	password.c
+@ -			-		rd_preauth.c	rd_preau.c
+@ -			-		put_svc_key.c	put_svc_.c
+@ read_service_key.c	rdservky.c	rd_svc_key.c	rd_svc_k.c	read_svc_key.c
+@ save_credentials.c	savecred.c	save_creds.c	save_cre.c	save_creds.c
+@ send_to_kdc.c		send_kdc.c	send_to_kdc.c	send_to_.c
+@ strcasecmp.c		s_cascmp.c	strcasecmp.c	strcasec.c
+@ tkt_string.c		tkt_strg.c	tkt_string.c	tkt_stri.c
+@ -			-		unix_glue.c	unix_glu.c
+@ util.c		util.c		ad_print.c	ad_print.c
+@ -			-		win_store.c	win_stor.c
+# Cleanup for simplified sed scripts that use this table
+@sed s/tf_ad_print\./tf_util\./g
+
+I've supplied Unix shell scripts in the distribution for moving:
+ren-pl10.sh	V4 pl10 filenames to proposed names	for converting old trees
+ren-pc.sh	V4 MIT PC names to proposed names	for converting old trees
+ren2long.sh	truncated names to proposed names	for moving DOS->unix
+ren2dos.sh	proposed names to truncated names	for unix->DOS names
+
+There's also shell scripts to produce sed scripts for converting Makefiles
+and documentation.  You use them like:
+	./sed-pl10.sh >/tmp/sed
+	sed -f /tmp/sed <Makefile >newMakefile
+sed-pl10.sh	V4 pl10 filenames to proposed names	for converting old trees
+sed-pc.sh	V4 MIT PC names to proposed names	for converting old trees
+
+I'll also supply a DOS script for moving:
+ren-pc.bat	V4 MIT PC names to proposed names	for converting old trees
+
+And an MPW script for moving
+ren-pl10.mpw	V4 pl10 filenames to proposed names	for converting old trees
+
+	John Gilmore
+	Cygnus Support
diff --git a/mechglue/src/lib/krb4/ren2dos.sh b/mechglue/src/lib/krb4/ren2dos.sh
new file mode 100644
index 000000000..3989e2c6e
--- /dev/null
+++ b/mechglue/src/lib/krb4/ren2dos.sh
@@ -0,0 +1,7 @@
+# Rename Unix filenames to DOS-truncated filenames for KRB library.
+# for converting Unix distributions to DOS distributions
+awk '/^@ / {
+		if ($4 != $5)
+			print "mv	" $4 "	" $5
+	  }
+    ' <ren.msg | sh -x
diff --git a/mechglue/src/lib/krb4/ren2long.sh b/mechglue/src/lib/krb4/ren2long.sh
new file mode 100644
index 000000000..7d1a25966
--- /dev/null
+++ b/mechglue/src/lib/krb4/ren2long.sh
@@ -0,0 +1,7 @@
+# Rename DOS-truncated filenames to Unix filenames for KRB library.
+# for converting DOS distributions to Unix distributions
+awk '/^@ / {
+		if ($4 != $5)
+			print "mv	" $5 "	" $4
+	  }
+    ' <ren.msg | sh -x
diff --git a/mechglue/src/lib/krb4/save_creds.c b/mechglue/src/lib/krb4/save_creds.c
new file mode 100644
index 000000000..62961c1b5
--- /dev/null
+++ b/mechglue/src/lib/krb4/save_creds.c
@@ -0,0 +1,87 @@
+/*
+ * save_creds.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2002 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+#include "krb.h"
+#include "krb4int.h"
+
+/*
+ * This routine takes a ticket and associated info and calls
+ * tf_save_cred() to store them in the ticket cache.  The peer
+ * routine for extracting a ticket and associated info from the
+ * ticket cache is krb_get_cred().  When changes are made to
+ * this routine, the corresponding changes should be made
+ * in krb_get_cred() as well.
+ *
+ * Returns KSUCCESS if all goes well, otherwise an error returned
+ * by the tf_init() or tf_save_cred() routines.
+ *
+ * This used to just be called save_credentials, but when we formalized
+ * the DOS/Mac interface, we created and exported krb_save_credentials
+ * to avoid namespace pollution.
+ */
+
+int
+krb4int_save_credentials_addr(service, instance, realm, session, lifetime, kvno,
+                 ticket, issue_date, local_addr)
+    char *service;		/* Service name */
+    char *instance;		/* Instance */
+    char *realm;		/* Auth domain */
+    C_Block session;		/* Session key */
+    int lifetime;		/* Lifetime */
+    int kvno;			/* Key version number */
+    KTEXT ticket;		/* The ticket itself */
+    long issue_date;		/* The issue time */
+    KRB_UINT32 local_addr;
+{
+    int tf_status;   /* return values of the tf_util calls */
+
+    /* Open and lock the ticket file for writing */
+    if ((tf_status = tf_init(TKT_FILE, W_TKT_FIL)) != KSUCCESS)
+	return(tf_status);
+
+    /* Save credentials by appending to the ticket file */
+    tf_status = tf_save_cred(service, instance, realm, session,
+			     lifetime, kvno, ticket, issue_date);
+    (void) tf_close();
+    return (tf_status);
+}
+
+int KRB5_CALLCONV
+krb_save_credentials(
+    char	*service,
+    char	*instance,
+    char	*realm,
+    C_Block	session,
+    int		lifetime,
+    int		kvno,
+    KTEXT	ticket,
+    long	issue_date)
+{
+    return krb4int_save_credentials_addr(service, instance, realm,
+					 session, lifetime, kvno,
+					 ticket, issue_date, 0);
+}
diff --git a/mechglue/src/lib/krb4/sed-cyg.sh b/mechglue/src/lib/krb4/sed-cyg.sh
new file mode 100755
index 000000000..3859df138
--- /dev/null
+++ b/mechglue/src/lib/krb4/sed-cyg.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Produce a sed script for converting Kerberos Cygnus V4 filenames to proposed
+# names -- for converting old makefiles and doc.
+# We fix any "oldfoo." into "newfoo." including .c and .o and .h files.
+awk '/^@ / {	if ($6 != "")
+			if ($6 != $4)
+				print "s/" $6 "/" $4 "/g"
+			else ;
+		else if ($2 != $4 && $2 != "-")
+			print "s/" $2 "/" $4 "/g"
+	  }
+     /^@sed / { print $2 }
+    ' <ren.msg | grep -v '(gone)' | sed 's/\.c/\\./g'
diff --git a/mechglue/src/lib/krb4/sed-pc.sh b/mechglue/src/lib/krb4/sed-pc.sh
new file mode 100755
index 000000000..a222dca3f
--- /dev/null
+++ b/mechglue/src/lib/krb4/sed-pc.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Produce a sed script for converting Kerberos V4 MIT PC filenames to proposed
+# names -- for converting old makefiles and doc.
+# We fix any "oldfoo." into "newfoo." including .c and .o and .h files.
+awk '/^@ / {	
+		if ($3 != $4)
+			print "s/" $3 "/" $4 "/g"
+	  }
+     /^@sed / { print $2 }
+    ' <ren.msg | grep -v '(gone)' | sed 's/\.c/\\./g'
+
diff --git a/mechglue/src/lib/krb4/sed-pl10.sh b/mechglue/src/lib/krb4/sed-pl10.sh
new file mode 100755
index 000000000..a6ab27c96
--- /dev/null
+++ b/mechglue/src/lib/krb4/sed-pl10.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Produce a sed script for converting Kerberos V4 pl10 filenames to proposed
+# names -- for converting old makefiles and doc.
+# We fix any "oldfoo." into "newfoo." including .c and .o and .h files.
+awk '/^@ / {	
+		if ($2 != $4)
+			print "s/" $2 "/" $4 "/g"
+	  }
+     /^@sed / { print $2 }
+    ' <ren.msg | sed 's/\.c/\\./g'
diff --git a/mechglue/src/lib/krb4/send_to_kdc.c b/mechglue/src/lib/krb4/send_to_kdc.c
new file mode 100644
index 000000000..3a2544d57
--- /dev/null
+++ b/mechglue/src/lib/krb4/send_to_kdc.c
@@ -0,0 +1,206 @@
+/*
+ * lib/krb4/send_to_kdc.c
+ *
+ * Copyright 1987-2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "krbports.h"
+#include "prot.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "krb5/autoconf.h"
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "port-sockets.h"
+#include "fake-addrinfo.h"
+#include "k5-int.h"
+#include "krb4int.h"
+
+#define S_AD_SZ sizeof(struct sockaddr_in)
+
+/* These are really defaults from getservbyname() or hardcoded. */
+static int cached_krb_udp_port = 0;
+static int cached_krbsec_udp_port = 0;
+
+int krb4int_send_to_kdc_addr(KTEXT, KTEXT, char *,
+			     struct sockaddr *, socklen_t *);
+
+#ifdef DEBUG
+static char *prog = "send_to_kdc";
+#endif
+
+/*
+ * send_to_kdc() sends a message to the Kerberos authentication
+ * server(s) in the given realm and returns the reply message.
+ * The "pkt" argument points to the message to be sent to Kerberos;
+ * the "rpkt" argument will be filled in with Kerberos' reply.
+ * The "realm" argument indicates the realm of the Kerberos server(s)
+ * to transact with.  If the realm is null, the local realm is used.
+ *
+ * If more than one Kerberos server is known for a given realm,
+ * different servers will be queried until one of them replies.
+ * Several attempts (retries) are made for each server before
+ * giving up entirely.
+ *
+ * The following results can be returned:
+ *
+ * KSUCCESS	- an answer was received from a Kerberos host
+ *
+ * SKDC_CANT    - can't get local realm
+ *              - can't find "kerberos" in /etc/services database
+ *              - can't open socket
+ *              - can't bind socket
+ *              - all ports in use
+ *              - couldn't find any Kerberos host
+ *
+ * SKDC_RETRY   - couldn't get an answer from any Kerberos server,
+ *		  after several retries
+ */
+
+int
+krb4int_send_to_kdc_addr(
+    KTEXT pkt, KTEXT rpkt, char *realm,
+    struct sockaddr *addr, socklen_t *addrlen)
+{
+    struct addrlist	al = ADDRLIST_INIT;
+    char		lrealm[REALM_SZ];
+    krb5int_access	internals;
+    krb5_error_code	retval;
+    struct servent	*sp;
+    int			krb_udp_port = 0;
+    int			krbsec_udp_port = 0;
+    char		krbhst[MAXHOSTNAMELEN];
+    char		*scol;
+    int			i;
+    int			err;
+    krb5_data		message, reply;
+
+    /*
+     * If "realm" is non-null, use that, otherwise get the
+     * local realm.
+     */
+    if (realm)
+	strncpy(lrealm, realm, sizeof(lrealm) - 1);
+    else {
+	if (krb_get_lrealm(lrealm, 1)) {
+	    DEB (("%s: can't get local realm\n", prog));
+	    return SKDC_CANT;
+	}
+    }
+    lrealm[sizeof(lrealm) - 1] = '\0';
+    DEB (("lrealm is %s\n", lrealm));
+
+    retval = krb5int_accessor(&internals, KRB5INT_ACCESS_VERSION);
+    if (retval)
+	return KFAILURE;
+
+    /* The first time, decide what port to use for the KDC.  */
+    if (cached_krb_udp_port == 0) {
+	sp = getservbyname("kerberos","udp");
+        if (sp)
+	    cached_krb_udp_port = sp->s_port;
+	else
+	    cached_krb_udp_port = htons(KERBEROS_PORT); /* kerberos/udp */
+        DEB (("cached_krb_udp_port is %d\n", cached_krb_udp_port));
+    }
+    /* If kerberos/udp isn't 750, try using kerberos-sec/udp (or 750) 
+       as a fallback. */
+    if (cached_krbsec_udp_port == 0 && 
+	cached_krb_udp_port != htons(KERBEROS_PORT)) {
+	sp = getservbyname("kerberos-sec","udp");
+        if (sp)
+	    cached_krbsec_udp_port = sp->s_port;
+	else
+	    cached_krbsec_udp_port = htons(KERBEROS_PORT); /* kerberos/udp */
+        DEB (("cached_krbsec_udp_port is %d\n", cached_krbsec_udp_port));
+    }
+
+    for (i = 1; krb_get_krbhst(krbhst, lrealm, i) == KSUCCESS; ++i) {
+#ifdef DEBUG
+        if (krb_debug) {
+            DEB (("Getting host entry for %s...",krbhst));
+            (void) fflush(stdout);
+        }
+#endif
+	if (0 != (scol = strchr(krbhst,':'))) {
+	    krb_udp_port = htons(atoi(scol+1));
+	    *scol = 0;
+	    if (krb_udp_port == 0) {
+#ifdef DEBUG
+		if (krb_debug) {
+		    DEB (("bad port number %s\n",scol+1));
+		    (void) fflush(stdout);
+		}
+#endif
+		continue;
+	    }
+	    krbsec_udp_port = 0;
+	} else {
+	    krb_udp_port = cached_krb_udp_port;
+	    krbsec_udp_port = cached_krbsec_udp_port;
+	}
+        err = internals.add_host_to_list(&al, krbhst,
+					 krb_udp_port, krbsec_udp_port,
+					 SOCK_DGRAM, PF_INET);
+	if (err) {
+	    retval = SKDC_CANT;
+	    goto free_al;
+	}
+    }
+    if (al.naddrs == 0) {
+	DEB (("%s: can't find any Kerberos host.\n", prog));
+        retval = SKDC_CANT;
+    }
+
+    message.length = pkt->length;
+    message.data = (char *)pkt->dat; /* XXX yuck */
+    retval = internals.sendto_udp(NULL, &message, &al, &reply, addr,
+				  addrlen, NULL);
+    DEB(("sendto_udp returns %d\n", retval));
+free_al:
+    internals.free_addrlist(&al);
+    if (retval)
+	return SKDC_CANT;
+    DEB(("reply.length=%d\n", reply.length));
+    if (reply.length > sizeof(rpkt->dat))
+	retval = SKDC_CANT;
+    rpkt->length = 0;
+    if (!retval) {
+	memcpy(rpkt->dat, reply.data, reply.length);
+	rpkt->length = reply.length;
+    }
+    krb5_free_data_contents(NULL, &reply);
+    return retval;
+}
+
+int
+send_to_kdc(KTEXT pkt, KTEXT rpkt, char *realm)
+{
+    return krb4int_send_to_kdc_addr(pkt, rpkt, realm, NULL, NULL);
+}
diff --git a/mechglue/src/lib/krb4/sendauth.c b/mechglue/src/lib/krb4/sendauth.c
new file mode 100644
index 000000000..83729442a
--- /dev/null
+++ b/mechglue/src/lib/krb4/sendauth.c
@@ -0,0 +1,282 @@
+/*
+ * sendauth.c
+ *
+ * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+#include "mit-copyright.h"
+
+#include "krb.h"
+#include "krb4int.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "port-sockets.h"
+
+#define	KRB_SENDAUTH_VERS "AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN chars */
+/*
+ * If the protocol changes, you will need to change the version string
+ * and make appropriate changes in krb_recvauth.c
+ */
+
+/*
+ * This file contains two routines: krb_sendauth() and krb_sendsrv().
+ *
+ * krb_sendauth() transmits a ticket over a file descriptor for a
+ * desired service, instance, and realm, doing mutual authentication
+ * with the server if desired.
+ *
+ * Most of the real work of krb_sendauth() has been moved into mk_auth.c
+ * for portability; sendauth takes a Unix file descriptor as argument,
+ * which doesn't work on other operating systems.
+ *
+ * krb_sendsvc() sends a service name to a remote knetd server, and is
+ * only for Athena compatability.
+ */
+
+/*
+ * The first argument to krb_sendauth() contains a bitfield of
+ * options (the options are defined in "krb.h"):
+ *
+ * KOPT_DONT_CANON	Don't canonicalize instance as a hostname.
+ *			(If this option is not chosen, krb_get_phost()
+ *			is called to canonicalize it.)
+ *
+ * KOPT_DONT_MK_REQ 	Don't request server ticket from Kerberos.
+ *			A ticket must be supplied in the "ticket"
+ *			argument.
+ *			(If this option is not chosen, and there
+ *			is no ticket for the given server in the
+ *			ticket cache, one will be fetched using
+ *			krb_mk_req() and returned in "ticket".)
+ *
+ * KOPT_DO_MUTUAL	Do mutual authentication, requiring that the
+ * 			receiving server return the checksum+1 encrypted
+ *			in the session key.  The mutual authentication
+ *			is done using krb_mk_priv() on the other side
+ *			(see "recvauth.c") and krb_rd_priv() on this
+ *			side.
+ *
+ * The "fd" argument is a file descriptor to write to the remote
+ * server on.  The "ticket" argument is used to store the new ticket
+ * from the krb_mk_req() call. If the KOPT_DONT_MK_REQ options is
+ * chosen, the ticket must be supplied in the "ticket" argument.
+ * The "service", "inst", and "realm" arguments identify the ticket.
+ * If "realm" is null, the local realm is used.
+ *
+ * The following arguments are only needed if the KOPT_DO_MUTUAL option
+ * is chosen:
+ *
+ *   The "checksum" argument is a number that the server will add 1 to
+ *   to authenticate itself back to the client; the "msg_data" argument
+ *   holds the returned mutual-authentication message from the server
+ *   (i.e., the checksum+1); the "cred" structure is used to hold the
+ *   session key of the server, extracted from the ticket file, for use
+ *   in decrypting the mutual authentication message from the server;
+ *   and "schedule" holds the key schedule for that decryption.  The
+ *   the local and server addresses are given in "laddr" and "faddr".
+ *
+ * The application protocol version number (of up to KRB_SENDAUTH_VLEN
+ * characters) is passed in "version".
+ *
+ * If all goes well, KSUCCESS is returned, otherwise some error code.
+ *
+ * The format of the message sent to the server is:
+ *
+ * Size			Variable		Field
+ * ----			--------		-----
+ *
+ * KRB_SENDAUTH_VLEN	KRB_SENDAUTH_VER	sendauth protocol
+ * bytes					version number
+ *
+ * KRB_SENDAUTH_VLEN	version			application protocol
+ * bytes					version number
+ *
+ * 4 bytes		ticket->length		length of ticket
+ *
+ * ticket->length	ticket->dat		ticket itself
+ */
+
+/*
+ * XXX: Note that krb_rd_priv() is coded in such a way that
+ * "msg_data->app_data" will be pointing into "packet", which
+ * will disappear when krb_sendauth() returns.
+ * 
+ * See FIXME KLUDGE code in appl/bsd/kcmd.c.
+ */
+KRB4_32 __krb_sendauth_hidden_tkt_len=0;
+#define raw_tkt_len __krb_sendauth_hidden_tkt_len
+
+
+/* 
+ * Read a server's sendauth response out of a file descriptor.
+ * Returns a Kerberos error code.
+ *
+ * Note sneaky code using raw_tkt_len to stash away a bit of info
+ * for use by appl/bsd/kcmd.c.  Now that krb_net_rd_sendauth is
+ * a separate function, kcmd should call it directly to get this
+ * sneaky info.  
+ */
+int
+krb_net_rd_sendauth (fd, reply, raw_len)
+     int fd;			/* file descriptor to write onto */
+     KTEXT reply;		/* Where we put the reply message */
+     KRB4_32 *raw_len;		/* Where to read the length field info */
+{
+    KRB4_32 tkt_len;
+    int got;
+
+    reply->length = 0;		/* Nothing read from net yet */
+    reply->mbz = 0;
+
+    /* get the length of the reply */
+  reread:
+    got = krb_net_read(fd, (char *)raw_len, sizeof(KRB4_32));
+    if (got != sizeof(KRB4_32))
+	return KFAILURE;
+
+    /* Here's an amazing hack.  If we are contacting an rlogin server,
+       and it is running on a Sun4, and it was compiled with the wrong
+       shared libary version, it will print an ld.so warning message
+       when it starts up.  We just ignore any such message and keep
+       going.  This doesn't affect security: we just require the
+       ticket to follow the warning message.  */
+    if (!memcmp("ld.s", raw_len, 4)) {
+    	char c;
+
+	while (krb_net_read(fd, &c, 1) == 1 && c != '\n')
+	    ;
+	goto reread;
+    }
+
+    tkt_len = ntohl(*raw_len);
+
+    /* if the length is negative, the server failed to recognize us. */
+    if ((tkt_len < 0) || (tkt_len > sizeof(reply->dat)))
+	return KFAILURE;	 /* XXX */
+    /* read the reply... */
+    got = krb_net_read(fd, (char *)reply->dat, (int) tkt_len);
+    if (got != (int) tkt_len)
+	return KFAILURE;
+
+    reply->length = tkt_len;
+    reply->mbz = 0;
+    return KSUCCESS;
+}
+
+
+/*
+ * krb_sendauth
+ * 
+ * The original routine, provided on Unix.
+ * Obtains a service ticket using the ticket-granting ticket,
+ * uses it to stuff an authorization request down a Unix socket to the
+ * end-user application server, sucks a response out of the socket, 
+ * and decodes it to verify mutual authentication.
+ */
+int KRB5_CALLCONV
+krb_sendauth(options, fd, ticket, service, inst, realm, checksum,
+	     msg_data, cred, schedule, laddr, faddr, version)
+     long options;		/* bit-pattern of options */
+     int fd;			/* file descriptor to write onto */
+     KTEXT ticket;		/* where to put ticket (return); or
+				   supplied in case of KOPT_DONT_MK_REQ */
+     char *service;         /* service name */
+     char *inst;            /* service instance */
+     char *realm;           /* service realm */
+     unsigned KRB4_32 checksum; /* checksum to include in request */
+     MSG_DAT *msg_data;		/* mutual auth MSG_DAT (return) */
+     CREDENTIALS *cred;		/* credentials (return) */
+     Key_schedule schedule;	/* key schedule (return) */
+     struct sockaddr_in *laddr;	/* local address */
+     struct sockaddr_in *faddr;	/* address of foreign host on fd */
+     char *version;		/* version string */
+{
+    int rem, cc;
+    char srv_inst[INST_SZ];
+    char krb_realm[REALM_SZ];
+    KTEXT_ST packet[1];		/* Re-use same one for msg and reply */
+
+    /* get current realm if not passed in */
+    if (!realm) {
+	rem = krb_get_lrealm(krb_realm,1);
+	if (rem != KSUCCESS)
+	    return(rem);
+	realm = krb_realm;
+    }
+
+    /* copy instance into local storage, so mk_auth can canonicalize */
+    (void) strncpy(srv_inst, inst, INST_SZ-1);
+    srv_inst[INST_SZ-1] = 0;
+    rem = krb_mk_auth (options, ticket, service, srv_inst, realm, checksum,
+   			   version, packet);
+    if (rem != KSUCCESS)
+	return rem;
+
+#ifdef ATHENA_COMPAT
+    /* this is only for compatibility with old servers */
+    if (options & KOPT_DO_OLDSTYLE) {
+	(void) sprintf(buf,"%d ",ticket->length);
+	(void) write(fd, buf, strlen(buf));
+	(void) write(fd, (char *) ticket->dat, ticket->length);
+	return(rem);
+    }
+#endif /* ATHENA_COMPAT */
+
+    /* write the request to the server */
+    if ((cc = krb_net_write(fd, packet->dat, packet->length)) != packet->length)
+	return(cc);
+
+    /* mutual authentication, if desired */
+    if (options & KOPT_DO_MUTUAL) {
+	/* get credentials so we have service session
+	   key for decryption below */
+	cc = krb_get_cred(service, srv_inst, realm, cred);
+	if (cc)
+	    return(cc);
+
+	/* Get the reply out of the socket.  */
+	cc = krb_net_rd_sendauth (fd, packet, &raw_tkt_len);
+	if (cc != KSUCCESS)
+	    return cc;
+
+	/* Check the reply to verify that server is really who we expect.  */
+	cc = krb_check_auth (packet, checksum,
+		msg_data, cred->session, schedule, laddr, faddr);
+	if (cc != KSUCCESS)
+	    return cc;
+    }
+    return(KSUCCESS);
+}
+
+
+#ifdef ATHENA_COMPAT
+/*
+ * krb_sendsvc
+ */
+
+int
+krb_sendsvc(fd, service)
+     int fd;
+     char *service;
+{
+    /* write the service name length and then the service name to
+       the fd */
+    KRB4_32 serv_length;
+    int cc;
+
+    serv_length = htonl((unsigned long)strlen(service));
+    if ((cc = krb_net_write(fd, (char *) &serv_length,
+	sizeof(serv_length)))
+	!= sizeof(serv_length))
+	return(cc);
+    if ((cc = krb_net_write(fd, service, strlen(service)))
+	!= strlen(service))
+	return(cc);
+    return(KSUCCESS);
+}
+#endif /* ATHENA_COMPAT */
diff --git a/mechglue/src/lib/krb4/setenv.c b/mechglue/src/lib/krb4/setenv.c
new file mode 100644
index 000000000..76a2a615b
--- /dev/null
+++ b/mechglue/src/lib/krb4/setenv.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)setenv.c	5.2 (Berkeley) 6/27/88";
+#endif /* LIBC_SCCS and not lint */
+
+#include "conf.h"
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * setenv --
+ *	Set the value of the environmental variable "name" to be
+ *	"value".  If rewrite is set, replace any current value.
+ */
+int setenv(name, value, rewrite)
+	register char *name, *value;
+	int rewrite;
+{
+	extern char **environ;
+	static int alloced;			/* if allocated space before */
+	register char *C;
+	int l_value, offset;
+	char *malloc(), *realloc(), *_findenv();
+
+	if (*value == '=')			/* no `=' in value */
+		++value;
+	l_value = strlen(value);
+	if ((C = _findenv(name, &offset))) {	/* find if already exists */
+		if (!rewrite)
+			return(0);
+		if (strlen(C) >= l_value) {	/* old larger; copy over */
+			while (*C++ = *value++);
+			return(0);
+		}
+	}
+	else {					/* create new slot */
+		register int	cnt;
+		register char	**P;
+
+		for (P = environ, cnt = 0; *P; ++P, ++cnt);
+		if (alloced) {			/* just increase size */
+			environ = (char **)realloc((char *)environ,
+			    (u_int)(sizeof(char *) * (cnt + 2)));
+			if (!environ)
+				return(-1);
+		}
+		else {				/* get new space */
+			alloced = 1;		/* copy old entries into it */
+			P = (char **)malloc((u_int)(sizeof(char *) *
+			    (cnt + 2)));
+			if (!P)
+				return(-1);
+			memcpy(P, environ, cnt * sizeof(char *));
+			environ = P;
+		}
+		environ[cnt + 1] = NULL;
+		offset = cnt;
+	}
+	for (C = name; *C && *C != '='; ++C);	/* no `=' in name */
+	if (!(environ[offset] =			/* name + `=' + value */
+	    malloc((u_int)((int)(C - name) + l_value + 2))))
+		return(-1);
+	for (C = environ[offset]; (*C = *name++) && *C != '='; ++C);
+	for (*C++ = '='; *C++ = *value++;);
+	return(0);
+}
+
+/*
+ * unsetenv(name) --
+ *	Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+	char	*name;
+{
+	extern	char	**environ;
+	register char	**P;
+	int	offset;
+	char    *_findenv();
+
+	while (_findenv(name, &offset))		/* if set multiple times */
+		for (P = &environ[offset];; ++P)
+			if (!(*P = *(P + 1)))
+				break;
+}
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef HAVE_GETENV
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getenv.c	5.5 (Berkeley) 6/27/88";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * getenv --
+ *	Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+	char *name;
+{
+	int offset;
+	char *_findenv();
+
+	return(_findenv(name, &offset));
+}
+#endif
+/*
+ * _findenv --
+ *	Returns pointer to value associated with name, if any, else NULL.
+ *	Sets offset to be the offset of the name/value combination in the
+ *	environmental array, for use by setenv(3) and unsetenv(3).
+ *	Explicitly removes '=' in argument name.
+ *
+ *	This routine *should* be a static; don't use it.
+ */
+char *
+_findenv(name, offset)
+	register char *name;
+	int *offset;
+{
+	extern char **environ;
+	register int len;
+	register char **P, *C;
+
+	for (C = name, len = 0; *C && *C != '='; ++C, ++len);
+	for (P = environ; *P; ++P)
+		if (!strncmp(*P, name, len))
+			if (*(C = *P + len) == '=') {
+				*offset = P - environ;
+				return(++C);
+			}
+	return(NULL);
+}
diff --git a/mechglue/src/lib/krb4/stime.c b/mechglue/src/lib/krb4/stime.c
new file mode 100644
index 000000000..92c86895e
--- /dev/null
+++ b/mechglue/src/lib/krb4/stime.c
@@ -0,0 +1,57 @@
+/*
+ * lib/krb4/stime.c
+ *
+ * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute of
+ * Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "krb4int.h"
+#include <stdio.h>                      /* for sprintf() */
+#ifndef _WIN32
+#include <time.h>
+#include <sys/time.h>
+#endif
+
+/*
+ * Given a pointer to a long containing the number of seconds
+ * since the beginning of time (midnight 1 Jan 1970 GMT), return
+ * a string containing the local time in the form:
+ *
+ * "25-Jan-88 10:17:56"
+ */
+
+char *krb_stime(t)
+    long *t;
+{
+    static char st[40];
+    static time_t adjusted_time;
+    struct tm *tm;
+
+    adjusted_time = *t - CONVERT_TIME_EPOCH;
+    tm = localtime(&adjusted_time);
+    (void) sprintf(st,"%2d-%s-%d %02d:%02d:%02d",tm->tm_mday,
+                   month_sname(tm->tm_mon + 1),1900+tm->tm_year,
+                   tm->tm_hour, tm->tm_min, tm->tm_sec);
+    return st;
+}
+
diff --git a/mechglue/src/lib/krb4/strcasecmp.c b/mechglue/src/lib/krb4/strcasecmp.c
new file mode 100644
index 000000000..31bf0afbf
--- /dev/null
+++ b/mechglue/src/lib/krb4/strcasecmp.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+strcasecmp(s1, s2)
+	char *s1, *s2;
+{
+	register unsigned char	*cm = charmap,
+			*us1 = (unsigned char *)s1,
+			*us2 = (unsigned char *)s2;
+
+	while (cm[*us1] == cm[*us2++])
+		if (*us1++ == '\0')
+			return(0);
+	return(cm[*us1] - cm[*--us2]);
+}
+
+strncasecmp(s1, s2, n)
+	char *s1, *s2;
+	register int n;
+{
+	register unsigned char	*cm = charmap,
+			*us1 = (unsigned char *)s1,
+			*us2 = (unsigned char *)s2;
+
+	while (--n >= 0 && cm[*us1] == cm[*us2++])
+		if (*us1++ == '\0')
+			return(0);
+	return(n < 0 ? 0 : cm[*us1] - cm[*--us2]);
+}
diff --git a/mechglue/src/lib/krb4/strnlen.c b/mechglue/src/lib/krb4/strnlen.c
new file mode 100644
index 000000000..5dc80115c
--- /dev/null
+++ b/mechglue/src/lib/krb4/strnlen.c
@@ -0,0 +1,50 @@
+/*
+ * lib/krb4/strnlen.c
+ *
+ * Copyright 2000, 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include <stddef.h>
+#include "krb.h"
+#include "prot.h"
+
+/*
+ * krb4int_strnlen()
+ *
+ * Return the length of the string if a NUL is found in the first n
+ * bytes, otherwise, -1.
+ */
+
+int KRB5_CALLCONV
+krb4int_strnlen(const char *s, int n)
+{
+    int i = 0;
+
+    for (i = 0; i < n; i++) {
+        if (s[i] == '\0') {
+            return i;
+	}
+    }
+    return -1;
+}
diff --git a/mechglue/src/lib/krb4/swab.c b/mechglue/src/lib/krb4/swab.c
new file mode 100644
index 000000000..e07b28b43
--- /dev/null
+++ b/mechglue/src/lib/krb4/swab.c
@@ -0,0 +1,18 @@
+/* simple implementation of swab. */
+
+swab(from,to,nbytes) 
+        char *from;
+        char *to;
+        int nbytes;
+{
+	char tmp;
+        while ( (nbytes-=2) >= 0 ) {
+                tmp = from[1];
+                to[1] = from[0];
+		to[0] = tmp;
+                to++; to++;
+                from++; from++;
+        }
+}
+
+
diff --git a/mechglue/src/lib/krb4/tf_shm.c b/mechglue/src/lib/krb4/tf_shm.c
new file mode 100644
index 000000000..bd08f7f72
--- /dev/null
+++ b/mechglue/src/lib/krb4/tf_shm.c
@@ -0,0 +1,171 @@
+/*
+ * tf_shm.c
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Shared memory segment functions for session keys.  Derived from code
+ * contributed by Dan Kolkowitz (kolk@jessica.stanford.edu).
+ */
+
+#include "mit-copyright.h"
+
+#include <stdio.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include "krb.h"
+#include "des.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define MAX_BUFF sizeof(des_cblock)*1000 /* room for 1k keys */
+
+extern int krb_debug;
+
+/*
+ * krb_create_shmtkt:
+ *
+ * create a shared memory segment for session keys, leaving its id
+ * in the specified filename.
+ */
+
+int
+krb_shm_create(file_name)
+char *file_name;
+{
+    int retval;
+    int shmid;
+    struct shmid_ds shm_buf;
+    FILE *sfile;
+    uid_t me, metoo, getuid(), geteuid();
+
+    (void) krb_shm_dest(file_name);	/* nuke it if it exists...
+					 this cleans up to make sure we
+					 don't slowly lose memory. */
+
+    shmid = shmget((long)IPC_PRIVATE,MAX_BUFF, IPC_CREAT);
+    if (shmid == -1) { 
+	if (krb_debug)
+	    perror("krb_shm_create shmget");
+	return(KFAILURE);		/* XXX */
+    }
+    me = getuid();
+    metoo = geteuid();
+    /* 
+     * now set up the buffer so that we can modify it 
+     */
+    shm_buf.shm_perm.uid = me;
+    shm_buf.shm_perm.gid = getgid();
+    shm_buf.shm_perm.mode = 0600;
+    if (shmctl(shmid,IPC_SET,&shm_buf) < 0) { /*can now map it */
+	if (krb_debug)
+	    perror("krb_shm_create shmctl");
+	(void) shmctl(shmid, IPC_RMID, 0);
+	return(KFAILURE);		/* XXX */
+    }
+#if !defined(_AIX)
+    (void) shmctl(shmid, SHM_LOCK, 0);	/* attempt to lock-in-core */
+#endif
+    /* arrange so the file is owned by the ruid
+       (swap real & effective uid if necessary). */
+    if (me != metoo) {
+	if (setreuid(metoo, me) < 0) {
+	    /* can't switch??? barf! */
+	    if (krb_debug)
+		perror("krb_shm_create: setreuid");
+	    (void) shmctl(shmid, IPC_RMID, 0);
+	    return(KFAILURE);
+	} else
+	    if (krb_debug)
+		printf("swapped UID's %d and %d\n",metoo,me);
+    }
+    if ((sfile = fopen(file_name,"w")) == 0) {
+	if (krb_debug)
+	    perror("krb_shm_create file");
+	(void) shmctl(shmid, IPC_RMID, 0);
+	return(KFAILURE);		/* XXX */
+    } 
+    if (fchmod(fileno(sfile),0600) < 0) {
+	if (krb_debug)
+	    perror("krb_shm_create fchmod");
+	(void) shmctl(shmid, IPC_RMID, 0);
+	return(KFAILURE);		/* XXX */
+    }	
+    if (me != metoo) {
+	if (setreuid(me, metoo) < 0) {
+	    /* can't switch??? barf! */
+	    if (krb_debug)
+		perror("krb_shm_create: setreuid2");
+	    (void) shmctl(shmid, IPC_RMID, 0);
+	    return(KFAILURE);
+	} else
+	    if (krb_debug)
+		printf("swapped UID's %d and %d\n",me,metoo);
+    }
+
+    (void) fprintf(sfile,"%d",shmid);
+    (void) fflush(sfile);
+    (void) fclose(sfile);
+    return(KSUCCESS);
+}
+
+
+/*
+ * krb_is_diskless:
+ *
+ * check / to see if file .diskless exists.  If so it is diskless.
+ *     Do it this way now to avoid dependencies on a particular routine.
+ *      Choose root file system since that will be private to the client.
+ */
+
+int krb_is_diskless()
+{
+	struct stat buf;
+	if (stat("/.diskless",&buf) < 0) 
+		return(0);
+	else return(1);
+}
+			
+/*
+ * krb_shm_dest: destroy shared memory segment with session keys, and remove
+ * file pointing to it.
+ */
+
+int krb_shm_dest(file)
+char *file;
+{
+    int shmid;
+    FILE *sfile;
+    struct stat st_buf;
+
+    if (stat(file,&st_buf) == 0) {
+	/* successful stat */
+	if ((sfile = fopen(file,"r")) == 0) {
+	    if (krb_debug)
+		perror("cannot open shared memory file");
+	    return(KFAILURE);		/* XXX */
+	}
+	if (fscanf(sfile,"%d",&shmid) == 1) {
+		if (shmctl(shmid,IPC_RMID,0) != 0) {
+		    if (krb_debug)
+			perror("krb_shm_dest: cannot delete shm segment");
+		    (void) fclose(sfile);
+		    return(KFAILURE);	/* XXX */
+		}		    
+	} else {
+	    if (krb_debug)
+		fprintf(stderr, "bad format in shmid file\n");
+	    (void) fclose(sfile);
+	    return(KFAILURE);		/* XXX */
+	}
+	(void) fclose(sfile);
+	(void) unlink(file);
+	return(KSUCCESS);
+    } else
+	return(RET_TKFIL);		/* XXX */
+}
+
+	
+
diff --git a/mechglue/src/lib/krb4/tf_util.c b/mechglue/src/lib/krb4/tf_util.c
new file mode 100644
index 000000000..6cb9eeb8f
--- /dev/null
+++ b/mechglue/src/lib/krb4/tf_util.c
@@ -0,0 +1,788 @@
+/*
+ * lib/krb4/tf_util.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2000, 2001 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include "k5-int.h"
+#include "krb4int.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef TKT_SHMEM
+#include <sys/param.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif /* TKT_SHMEM */
+
+#define TOO_BIG -1
+#define TF_LCK_RETRY ((unsigned)2)	/* seconds to sleep before
+					 * retry if ticket file is
+					 * locked */
+extern int krb_debug;
+
+void tf_close();
+
+#ifdef TKT_SHMEM
+char *krb_shm_addr;
+static char *tmp_shm_addr;
+static const char krb_dummy_skey[8];
+
+char *shmat();
+#endif /* TKT_SHMEM */
+
+#ifdef NEED_UTIMES
+
+#include <sys/time.h>
+#ifdef __SCO__
+#include <utime.h>
+#endif
+#if defined(__svr4__) || defined(__SVR4)
+#include <utime.h>
+#endif
+int utimes(path, times)
+     char* path;
+     struct timeval times[2];
+{
+  struct utimbuf tv;
+  tv.actime = times[0].tv_sec;
+  tv.modtime = times[1].tv_sec;
+  return utime(path,&tv);
+}
+#endif
+
+#ifdef HAVE_SETEUID
+#define do_seteuid(e) seteuid((e))
+#else
+#ifdef HAVE_SETRESUID
+#define do_seteuid(e) setresuid(-1, (e), -1)
+#else
+#ifdef HAVE_SETREUID
+#define do_seteuid(e) setreuid(geteuid(), (e))
+#else
+#define do_seteuid(e) (errno = EPERM, -1)
+#endif
+#endif
+#endif
+
+/*
+ * fd must be initialized to something that won't ever occur as a real
+ * file descriptor. Since open(2) returns only non-negative numbers as
+ * valid file descriptors, and tf_init always stuffs the return value
+ * from open in here even if it is an error flag, we must
+ * 	a. Initialize fd to a negative number, to indicate that it is
+ * 	   not initially valid.
+ *	b. When checking for a valid fd, assume that negative values
+ *	   are invalid (ie. when deciding whether tf_init has been
+ *	   called.)
+ *	c. In tf_close, be sure it gets reinitialized to a negative
+ *	   number. 
+ */
+static int  fd = -1;
+static int  curpos;			/* Position in tfbfr */
+static int  lastpos;			/* End of tfbfr */
+static char tfbfr[BUFSIZ];		/* Buffer for ticket data */
+
+static int tf_gets (char *, int), tf_read (char *, int);
+
+/*
+ * This file contains routines for manipulating the ticket cache file.
+ *
+ * The ticket file is in the following format:
+ *
+ *      principal's name        (null-terminated string)
+ *      principal's instance    (null-terminated string)
+ *      CREDENTIAL_1
+ *      CREDENTIAL_2
+ *      ...
+ *      CREDENTIAL_n
+ *      EOF
+ *
+ *      Where "CREDENTIAL_x" consists of the following fixed-length
+ *      fields from the CREDENTIALS structure (see "krb.h"):
+ *
+ *              string          service[ANAME_SZ]
+ *              string          instance[INST_SZ]
+ *              string          realm[REALM_SZ]
+ *              C_Block         session
+ *              int             lifetime
+ *              int             kvno
+ *              KTEXT_ST        ticket_st
+ *              long            issue_date
+ *
+ * Strings are stored NUL-terminated, and read back until a NUL is
+ * found or the indicated number of bytes have been read.  (So if you
+ * try to store a string exactly that long or longer, reading them
+ * back will not work.)  The KTEXT_ST structure is stored as an int
+ * length followed by that many data bytes.  All ints are stored using
+ * host size and byte order for "int".
+ *
+ * Short description of routines:
+ *
+ * tf_init() opens the ticket file and locks it.
+ *
+ * tf_get_pname() returns the principal's name.
+ *
+ * tf_get_pinst() returns the principal's instance (may be null).
+ *
+ * tf_get_cred() returns the next CREDENTIALS record.
+ *
+ * tf_save_cred() appends a new CREDENTIAL record to the ticket file.
+ *
+ * tf_close() closes the ticket file and releases the lock.
+ *
+ * tf_gets() returns the next null-terminated string.  It's an internal
+ * routine used by tf_get_pname(), tf_get_pinst(), and tf_get_cred().
+ *
+ * tf_read() reads a given number of bytes.  It's an internal routine
+ * used by tf_get_cred().
+ */
+
+/*
+ * tf_init() should be called before the other ticket file routines.
+ * It takes the name of the ticket file to use, "tf_name", and a
+ * read/write flag "rw" as arguments. 
+ *
+ * It tries to open the ticket file, checks the mode, and if everything
+ * is okay, locks the file.  If it's opened for reading, the lock is
+ * shared.  If it's opened for writing, the lock is exclusive. 
+ *
+ * Returns KSUCCESS if all went well, otherwise one of the following: 
+ *
+ * NO_TKT_FIL   - file wasn't there
+ * TKT_FIL_ACC  - file was in wrong mode, etc.
+ * TKT_FIL_LCK  - couldn't lock the file, even after a retry
+ */
+
+int KRB5_CALLCONV tf_init(tf_name, rw)
+    const char   *tf_name;
+    int rw;
+{
+    int     wflag;
+    uid_t   me, metoo;
+    struct stat stat_buf, stat_buffd;
+#ifdef TKT_SHMEM
+    char shmidname[MAXPATHLEN]; 
+    FILE *sfp;
+    int shmid;
+#endif
+
+    if (!krb5__krb4_context) {
+	    if (krb5_init_context(&krb5__krb4_context))
+		    return TKT_FIL_LCK;
+    }
+
+    me = getuid();
+    metoo = geteuid();
+
+    switch (rw) {
+    case R_TKT_FIL:
+	wflag = 0;
+	break;
+    case W_TKT_FIL:
+	wflag = 1;
+	break;
+    default:
+	if (krb_debug) fprintf(stderr, "tf_init: illegal parameter\n");
+	return TKT_FIL_ACC;
+    }
+
+    /* If ticket cache selector is null, use default cache.  */
+    if (tf_name == 0)
+	tf_name = tkt_string();
+
+#ifdef TKT_SHMEM
+    (void) strncpy(shmidname, tf_name, sizeof(shmidname) - 1);
+    shmidname[sizeof(shmidname) - 1] = '\0';
+    (void) strncat(shmidname, ".shm", sizeof(shmidname) - 1 - strlen(shmidname));
+#endif /* TKT_SHMEM */
+
+    /*
+     * If "wflag" is set, open the ticket file in append-writeonly mode
+     * and lock the ticket file in exclusive mode.  If unable to lock
+     * the file, sleep and try again.  If we fail again, return with the
+     * proper error message. 
+     */
+
+    curpos = sizeof(tfbfr);
+
+#ifdef TKT_SHMEM
+    if (lstat(shmidname, &stat_buf) < 0) {
+	switch (errno) {
+	case ENOENT:
+	    return NO_TKT_FIL;
+	default:
+	    return TKT_FIL_ACC;
+	}
+    }
+    if (stat_buf.st_uid != me || !(stat_buf.st_mode & S_IFREG)
+	|| stat_buf.st_nlink != 1 || stat_buf.st_mode & 077) {
+	return TKT_FIL_ACC;
+    }
+
+    /*
+     * Yes, we do uid twiddling here.  It's not optimal, but some
+     * applications may expect that the ruid is what should really own
+     * the ticket file, e.g. setuid applications.
+     */
+    if (me != metoo && do_seteuid(me) < 0)
+	return KFAILURE;
+    sfp = fopen(shmidname, "r");	/* only need read/write on the
+					   actual tickets */
+    if (me != metoo && do_seteuid(metoo) < 0)
+	return KFAILURE;
+    if (sfp == 0) {
+        switch(errno) {
+        case ENOENT:
+	    return NO_TKT_FIL;
+	default:
+	    return TKT_FIL_ACC;
+	}
+    }
+
+    /*
+     * fstat() the file to check that the file we opened is the one we
+     * think it is.
+     */
+    if (fstat(fileno(sfp), &stat_buffd) < 0) {
+        (void) close(fd);
+	fd = -1;
+	switch(errno) {
+	case ENOENT:
+	    return NO_TKT_FIL;
+	default:
+	    return TKT_FIL_ACC;
+	}
+    }
+    /* Check that it's the right file */
+    if ((stat_buf.st_ino != stat_buffd.st_ino) ||
+	(stat_buf.st_dev != stat_buffd.st_dev)) {
+        (void) close(fd);
+	fd = -1;
+	return TKT_FIL_ACC;
+    }
+    /* Check ownership */
+    if ((stat_buffd.st_uid != me && me != 0) ||
+	((stat_buffd.st_mode & S_IFMT) != S_IFREG)) {
+        (void) close(fd);
+	fd = -1;
+	return TKT_FIL_ACC;
+    }
+
+
+
+    shmid = -1;
+    {
+	char buf[BUFSIZ];
+	int val;			/* useful for debugging fscanf */
+	/* We provide our own buffer here since some STDIO libraries
+	   barf on unbuffered input with fscanf() */
+	setbuf(sfp, buf);
+	if ((val = fscanf(sfp,"%d",&shmid)) != 1) {
+	    (void) fclose(sfp);
+	    return TKT_FIL_ACC;
+	}
+	if (shmid < 0) {
+	    (void) fclose(sfp);
+	    return TKT_FIL_ACC;
+	}
+	(void) fclose(sfp);
+    }
+    /*
+    * global krb_shm_addr is initialized to 0.  Ultrix bombs when you try and
+    * attach the same segment twice so we need this check.
+    */
+    if (!krb_shm_addr) {
+    	if ((krb_shm_addr = shmat(shmid,0,0)) == -1){
+		if (krb_debug)
+		    fprintf(stderr,
+			    "cannot attach shared memory for segment %d\n",
+			    shmid);
+		krb_shm_addr = 0;	/* reset so we catch further errors */
+		return TKT_FIL_ACC;
+	    }
+    }
+    tmp_shm_addr = krb_shm_addr;
+#endif /* TKT_SHMEM */
+    
+    if (lstat(tf_name, &stat_buf) < 0) {
+	switch (errno) {
+	case ENOENT:
+	    return NO_TKT_FIL;
+	default:
+	    return TKT_FIL_ACC;
+	}
+    }
+    if (stat_buf.st_uid != me || !(stat_buf.st_mode & S_IFREG)
+	|| stat_buf.st_nlink != 1 || stat_buf.st_mode & 077) {
+	return TKT_FIL_ACC;
+    }
+
+    if (wflag) {
+	if (me != metoo && do_seteuid(me) < 0)
+	    return KFAILURE;
+	fd = open(tf_name, O_RDWR, 0600);
+	if (me != metoo && do_seteuid(metoo) < 0)
+	    return KFAILURE;
+	if (fd < 0) {
+	    switch(errno) {
+	    case ENOENT:
+	        return NO_TKT_FIL;
+	    default:
+	        return TKT_FIL_ACC;
+	  }
+	}
+	/*
+	 * fstat() the file to check that the file we opened is the
+	 * one we think it is, and to check ownership.
+	 */
+	if (fstat(fd, &stat_buffd) < 0) {
+	    (void) close(fd);
+	    fd = -1;
+	    switch(errno) {
+	    case ENOENT:
+	        return NO_TKT_FIL;
+	    default:
+	        return TKT_FIL_ACC;
+	    }
+	}
+	/* Check that it's the right file */
+	if ((stat_buf.st_ino != stat_buffd.st_ino) ||
+	    (stat_buf.st_dev != stat_buffd.st_dev)) {
+	    (void) close(fd);
+	    fd = -1;
+	    return TKT_FIL_ACC;
+	}
+	/* Check ownership */
+	if ((stat_buffd.st_uid != me && me != 0) ||
+	    ((stat_buffd.st_mode & S_IFMT) != S_IFREG)) {
+	    (void) close(fd);
+	    fd = -1;
+	    return TKT_FIL_ACC;
+	}
+	if (krb5_lock_file(krb5__krb4_context, fd,
+			   KRB5_LOCKMODE_EXCLUSIVE |
+			   KRB5_LOCKMODE_DONTBLOCK) < 0) {
+	    sleep(TF_LCK_RETRY);
+	    if (krb5_lock_file(krb5__krb4_context, fd,
+			   KRB5_LOCKMODE_EXCLUSIVE |
+			   KRB5_LOCKMODE_DONTBLOCK) < 0) {
+		(void) close(fd);
+		fd = -1;
+		return TKT_FIL_LCK;
+	    }
+	}
+	return KSUCCESS;
+    }
+    /*
+     * Otherwise "wflag" is not set and the ticket file should be opened
+     * for read-only operations and locked for shared access. 
+     */
+
+    if (me != metoo && do_seteuid(me) < 0)
+	return KFAILURE;
+    fd = open(tf_name, O_RDONLY, 0600);
+    if (me != metoo && do_seteuid(metoo) < 0)
+	return KFAILURE;
+    if (fd < 0) {
+        switch(errno) {
+	case ENOENT:
+	    return NO_TKT_FIL;
+	default:
+	    return TKT_FIL_ACC;
+	}
+    }
+    /*
+     * fstat() the file to check that the file we opened is the one we
+     * think it is, and to check ownership.
+     */
+    if (fstat(fd, &stat_buffd) < 0) {
+        (void) close(fd);
+	fd = -1;
+	switch(errno) {
+	case ENOENT:
+	    return NO_TKT_FIL;
+	default:
+	    return TKT_FIL_ACC;
+	}
+    }
+    /* Check that it's the right file */
+    if ((stat_buf.st_ino != stat_buffd.st_ino) ||
+	(stat_buf.st_dev != stat_buffd.st_dev)) {
+        (void) close(fd);
+	fd = -1;
+	return TKT_FIL_ACC;
+    }
+    /* Check ownership */
+    if ((stat_buffd.st_uid != me && me != 0) ||
+	((stat_buffd.st_mode & S_IFMT) != S_IFREG)) {
+        (void) close(fd);
+	fd = -1;
+	return TKT_FIL_ACC;
+    }
+    if (krb5_lock_file(krb5__krb4_context, fd,
+			   KRB5_LOCKMODE_SHARED |
+			   KRB5_LOCKMODE_DONTBLOCK) < 0) {
+	sleep(TF_LCK_RETRY);
+	if (krb5_lock_file(krb5__krb4_context, fd,
+			   KRB5_LOCKMODE_SHARED |
+			   KRB5_LOCKMODE_DONTBLOCK) < 0) {
+	    (void) close(fd);
+	    fd = -1;
+	    return TKT_FIL_LCK;
+	}
+    }
+    return KSUCCESS;
+}
+
+/*
+ * tf_get_pname() reads the principal's name from the ticket file. It
+ * should only be called after tf_init() has been called.  The
+ * principal's name is filled into the "p" parameter.  If all goes well,
+ * KSUCCESS is returned.  If tf_init() wasn't called, TKT_FIL_INI is
+ * returned.  If the name was null, or EOF was encountered, or the name
+ * was longer than ANAME_SZ, TKT_FIL_FMT is returned. 
+ */
+
+int KRB5_CALLCONV tf_get_pname(p)
+    char   *p;
+{
+    if (fd < 0) {
+	if (krb_debug)
+	    fprintf(stderr, "tf_get_pname called before tf_init.\n");
+	return TKT_FIL_INI;
+    }
+    if (tf_gets(p, ANAME_SZ) < 2)	/* can't be just a null */
+	return TKT_FIL_FMT;
+    return KSUCCESS;
+}
+
+/*
+ * tf_get_pinst() reads the principal's instance from a ticket file.
+ * It should only be called after tf_init() and tf_get_pname() have been
+ * called.  The instance is filled into the "inst" parameter.  If all
+ * goes well, KSUCCESS is returned.  If tf_init() wasn't called,
+ * TKT_FIL_INI is returned.  If EOF was encountered, or the instance
+ * was longer than ANAME_SZ, TKT_FIL_FMT is returned.  Note that the
+ * instance may be null. 
+ */
+
+int KRB5_CALLCONV tf_get_pinst(inst)
+    char   *inst;
+{
+    if (fd < 0) {
+	if (krb_debug)
+	    fprintf(stderr, "tf_get_pinst called before tf_init.\n");
+	return TKT_FIL_INI;
+    }
+    if (tf_gets(inst, INST_SZ) < 1)
+	return TKT_FIL_FMT;
+    return KSUCCESS;
+}
+
+/*
+ * tf_get_cred() reads a CREDENTIALS record from a ticket file and fills
+ * in the given structure "c".  It should only be called after tf_init(),
+ * tf_get_pname(), and tf_get_pinst() have been called. If all goes well,
+ * KSUCCESS is returned.  Possible error codes are: 
+ *
+ * TKT_FIL_INI  - tf_init wasn't called first
+ * TKT_FIL_FMT  - bad format
+ * EOF          - end of file encountered
+ */
+
+int KRB5_CALLCONV tf_get_cred(c)
+    CREDENTIALS *c;
+{
+    KTEXT   ticket = &c->ticket_st;	/* pointer to ticket */
+    int     k_errno;
+    long issue_date;
+
+    if (fd < 0) {
+	if (krb_debug)
+	    fprintf(stderr, "tf_get_cred called before tf_init.\n");
+	return TKT_FIL_INI;
+    }
+    if ((k_errno = tf_gets(c->service, SNAME_SZ)) < 2)
+	switch (k_errno) {
+	case TOO_BIG:
+	case 1:		/* can't be just a null */
+	    tf_close();
+	    return TKT_FIL_FMT;
+	case 0:
+	    return EOF;
+	}
+    if ((k_errno = tf_gets(c->instance, INST_SZ)) < 1)
+	switch (k_errno) {
+	case TOO_BIG:
+	    return TKT_FIL_FMT;
+	case 0:
+	    return EOF;
+	}
+    if ((k_errno = tf_gets(c->realm, REALM_SZ)) < 2)
+	switch (k_errno) {
+	case TOO_BIG:
+	case 1:		/* can't be just a null */
+	    tf_close();
+	    return TKT_FIL_FMT;
+	case 0:
+	    return EOF;
+	}
+    if (
+	tf_read((char *) (c->session), KEY_SZ) < 1 ||
+	tf_read((char *) &(c->lifetime), sizeof(c->lifetime)) < 1 ||
+	tf_read((char *) &(c->kvno), sizeof(c->kvno)) < 1 ||
+	tf_read((char *) &(ticket->length), sizeof(ticket->length))
+	< 1 ||
+    /* don't try to read a silly amount into ticket->dat */
+	ticket->length > MAX_KTXT_LEN ||
+	tf_read((char *) (ticket->dat), ticket->length) < 1 ||
+	tf_read((char *) &(issue_date), sizeof(issue_date)) < 1
+	) {
+	tf_close();
+	return TKT_FIL_FMT;
+    }
+    c->issue_date = issue_date;
+#ifdef TKT_SHMEM
+    memcpy(c->session, tmp_shm_addr, KEY_SZ);
+    tmp_shm_addr += KEY_SZ;
+#endif /* TKT_SHMEM */
+    return KSUCCESS;
+}
+
+/*
+ * tf_close() closes the ticket file and sets "fd" to -1. If "fd" is
+ * not a valid file descriptor, it just returns.  It also clears the
+ * buffer used to read tickets.
+ *
+ * The return value is not defined.
+ */
+
+void KRB5_CALLCONV tf_close()
+{
+    if (!(fd < 0)) {
+#ifdef TKT_SHMEM
+	if (shmdt(krb_shm_addr)) {
+	    /* what kind of error? */
+	    if (krb_debug)
+		fprintf(stderr, "shmdt 0x%x: errno %d",krb_shm_addr, errno);
+	} else {
+	    krb_shm_addr = 0;
+	}
+#endif /* TKT_SHMEM */
+	if (!krb5__krb4_context)
+		krb5_init_context(&krb5__krb4_context);
+	(void) krb5_lock_file(krb5__krb4_context, fd, KRB5_LOCKMODE_UNLOCK);
+	(void) close(fd);
+	fd = -1;		/* see declaration of fd above */
+    }
+    memset(tfbfr, 0, sizeof(tfbfr));
+}
+
+/*
+ * tf_gets() is an internal routine.  It takes a string "s" and a count
+ * "n", and reads from the file until either it has read "n" characters,
+ * or until it reads a null byte. When finished, what has been read exists
+ * in "s". If it encounters EOF or an error, it closes the ticket file. 
+ *
+ * Possible return values are:
+ *
+ * n            the number of bytes read (including null terminator)
+ *              when all goes well
+ *
+ * 0            end of file or read error
+ *
+ * TOO_BIG      if "count" characters are read and no null is
+ *		encountered. This is an indication that the ticket
+ *		file is seriously ill.
+ */
+
+static int
+tf_gets(s, n)
+    register char *s;
+    int n;
+{
+    register int count;
+
+    if (fd < 0) {
+	if (krb_debug)
+	    fprintf(stderr, "tf_gets called before tf_init.\n");
+	return TKT_FIL_INI;
+    }
+    for (count = n - 1; count > 0; --count) {
+	if (curpos >= sizeof(tfbfr)) {
+	    lastpos = read(fd, tfbfr, sizeof(tfbfr));
+	    curpos = 0;
+	}
+	if (curpos == lastpos) {
+	    tf_close();
+	    return 0;
+	}
+	*s = tfbfr[curpos++];
+	if (*s++ == '\0')
+	    return (n - count);
+    }
+    tf_close();
+    return TOO_BIG;
+}
+
+/*
+ * tf_read() is an internal routine.  It takes a string "s" and a count
+ * "n", and reads from the file until "n" bytes have been read.  When
+ * finished, what has been read exists in "s".  If it encounters EOF or
+ * an error, it closes the ticket file.
+ *
+ * Possible return values are:
+ *
+ * n		the number of bytes read when all goes well
+ *
+ * 0		on end of file or read error
+ */
+
+static int
+tf_read(s, n)
+    register char *s;
+    register int  n;
+{
+    register int count;
+    
+    for (count = n; count > 0; --count) {
+	if (curpos >= sizeof(tfbfr)) {
+	    lastpos = read(fd, tfbfr, sizeof(tfbfr));
+	    curpos = 0;
+	}
+	if (curpos == lastpos) {
+	    tf_close();
+	    return 0;
+	}
+	*s++ = tfbfr[curpos++];
+    }
+    return n;
+}
+     
+/*
+ * tf_save_cred() appends an incoming ticket to the end of the ticket
+ * file.  You must call tf_init() before calling tf_save_cred().
+ *
+ * The "service", "instance", and "realm" arguments specify the
+ * server's name; "session" contains the session key to be used with
+ * the ticket; "kvno" is the server key version number in which the
+ * ticket is encrypted, "ticket" contains the actual ticket, and
+ * "issue_date" is the time the ticket was requested (local host's time).
+ *
+ * Returns KSUCCESS if all goes well, TKT_FIL_INI if tf_init() wasn't
+ * called previously, and KFAILURE for anything else that went wrong.
+ */
+
+int tf_save_cred(service, instance, realm, session, lifetime, kvno,
+		 ticket, issue_date)
+    char   *service;		/* Service name */
+    char   *instance;		/* Instance */
+    char   *realm;		/* Auth domain */
+    C_Block session;		/* Session key */
+    int     lifetime;		/* Lifetime */
+    int     kvno;		/* Key version number */
+    KTEXT   ticket;		/* The ticket itself */
+    long    issue_date;		/* The issue time */
+{
+
+    off_t   lseek();
+    unsigned int count;		/* count for write */
+#ifdef TKT_SHMEM
+    int	    *skey_check;
+#endif /* TKT_SHMEM */
+
+    if (fd < 0) {		/* fd is ticket file as set by tf_init */
+	  if (krb_debug)
+	      fprintf(stderr, "tf_save_cred called before tf_init.\n");
+	  return TKT_FIL_INI;
+    }
+    /* Find the end of the ticket file */
+    (void) lseek(fd, (off_t)0, 2);
+#ifdef TKT_SHMEM
+    /* scan to end of existing keys: pick first 'empty' slot.
+       we assume that no real keys will be completely zero (it's a weak
+       key under DES) */
+
+    skey_check = (int *) krb_shm_addr;
+
+    while (*skey_check && *(skey_check+1))
+	skey_check += 2;
+    tmp_shm_addr = (char *)skey_check;
+#endif /* TKT_SHMEM */
+
+    /* Write the ticket and associated data */
+    /* Service */
+    count = strlen(service) + 1;
+    if (write(fd, service, count) != count)
+	goto bad;
+    /* Instance */
+    count = strlen(instance) + 1;
+    if (write(fd, instance, count) != count)
+	goto bad;
+    /* Realm */
+    count = strlen(realm) + 1;
+    if (write(fd, realm, count) != count)
+	goto bad;
+    /* Session key */
+#ifdef TKT_SHMEM
+    memcpy(tmp_shm_addr, session, 8);
+    tmp_shm_addr+=8;
+    if (write(fd,krb_dummy_skey,8) != 8)
+	goto bad;
+#else /* ! TKT_SHMEM */
+    if (write(fd, (char *) session, 8) != 8)
+	goto bad;
+#endif /* TKT_SHMEM */
+    /* Lifetime */
+    if (write(fd, (char *) &lifetime, sizeof(int)) != sizeof(int))
+	goto bad;
+    /* Key vno */
+    if (write(fd, (char *) &kvno, sizeof(int)) != sizeof(int))
+	goto bad;
+    /* Tkt length */
+    if (write(fd, (char *) &(ticket->length), sizeof(int)) !=
+	sizeof(int))
+	goto bad;
+    /* Ticket */
+    count = ticket->length;
+    if (write(fd, (char *) (ticket->dat), count) != count)
+	goto bad;
+    /* Issue date */
+    if (write(fd, (char *) &issue_date, sizeof(long))
+	!= sizeof(long))
+	goto bad;
+
+    /* Actually, we should check each write for success */
+    return (KSUCCESS);
+bad:
+    return (KFAILURE);
+}
diff --git a/mechglue/src/lib/krb4/tkt_string.c b/mechglue/src/lib/krb4/tkt_string.c
new file mode 100644
index 000000000..97a62d174
--- /dev/null
+++ b/mechglue/src/lib/krb4/tkt_string.c
@@ -0,0 +1,100 @@
+/*
+ * tkt_string.c
+ *
+ * Copyright 1985, 1986, 1987, 1988, 2002 by the Massachusetts
+ * Institute of Technology.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "krb.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "krb5/autoconf.h"
+#include "port-sockets.h" /* XXX this gets us MAXPATHLEN but we should find
+			     a better way */
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+char *getenv();
+#endif
+
+
+#ifdef _WIN32
+typedef unsigned long uid_t;
+uid_t getuid(void) { return 0; }
+#endif /* _WIN32 */
+
+/*
+ * This routine is used to generate the name of the file that holds
+ * the user's cache of server tickets and associated session keys.
+ *
+ * If it is set, krb_ticket_string contains the ticket file name.
+ * Otherwise, the filename is constructed as follows:
+ *
+ * If it is set, the environment variable "KRBTKFILE" will be used as
+ * the ticket file name.  Otherwise TKT_ROOT (defined in "krb.h") and
+ * the user's uid are concatenated to produce the ticket file name
+ * (e.g., "/tmp/tkt123").  A pointer to the string containing the ticket
+ * file name is returned.
+ */
+
+static char krb_ticket_string[MAXPATHLEN];
+
+const char *tkt_string()
+{
+    char *env;
+    uid_t getuid();
+
+    if (!*krb_ticket_string) {
+	env = getenv("KRBTKFILE");
+        if (env) {
+	    (void) strncpy(krb_ticket_string, env,
+			   sizeof(krb_ticket_string)-1);
+	    krb_ticket_string[sizeof(krb_ticket_string)-1] = '\0';
+	} else {
+	    /* 32 bits of signed integer will always fit in 11 characters
+	     (including the sign), so no need to worry about overflow */
+	    (void) sprintf(krb_ticket_string, "%s%d",TKT_ROOT,(int) getuid());
+        }
+    }
+    return krb_ticket_string;
+}
+
+/*
+ * This routine is used to set the name of the file that holds the user's
+ * cache of server tickets and associated session keys.
+ *
+ * The value passed in is copied into local storage.
+ *
+ * NOTE:  This routine should be called during initialization, before other
+ * Kerberos routines are called; otherwise tkt_string() above may be called
+ * and return an undesired ticket file name until this routine is called.
+ */
+
+void KRB5_CALLCONV
+krb_set_tkt_string(val)
+    const char *val;
+{
+    (void) strncpy(krb_ticket_string, val, sizeof(krb_ticket_string)-1);
+    krb_ticket_string[sizeof(krb_ticket_string)-1] = '\0';
+}
diff --git a/mechglue/src/lib/krb4/unix_glue.c b/mechglue/src/lib/krb4/unix_glue.c
new file mode 100644
index 000000000..93a30ed01
--- /dev/null
+++ b/mechglue/src/lib/krb4/unix_glue.c
@@ -0,0 +1,40 @@
+/*
+ * unix_glue.c
+ * 
+ * Glue code for pasting Kerberos into the Unix environment.
+ *
+ * Originally written by John Gilmore, Cygnus Support, May '94.
+ * Public Domain.
+ */
+
+#include "krb.h"
+#include <sys/time.h>
+#include "krb4int.h"
+
+/* Start and end Kerberos library access.  On Unix, this is a No-op.  */
+int
+krb_start_session (x)
+	char *x;
+{
+	return KSUCCESS;
+}
+
+int
+krb_end_session (x)
+	char *x;
+{
+	return KSUCCESS;
+}
+
+char *
+krb_get_default_user ()
+{
+	return 0;		/* FIXME */
+}
+
+int
+krb_set_default_user (x)
+	char *x;
+{
+	return KFAILURE;	/* FIXME */
+}
diff --git a/mechglue/src/lib/krb4/unix_time.c b/mechglue/src/lib/krb4/unix_time.c
new file mode 100644
index 000000000..411ee38d6
--- /dev/null
+++ b/mechglue/src/lib/krb4/unix_time.c
@@ -0,0 +1,26 @@
+/*
+ * unix_time.c
+ * 
+ * Glue code for pasting Kerberos into the Unix environment.
+ *
+ * Originally written by John Gilmore, Cygnus Support, May '94.
+ * Public Domain.
+ */
+
+#include "krb.h"
+#include <sys/time.h>
+
+/* Time handling.  Translate Unix time calls into Kerberos cnternal 
+   procedure calls.  See ../../include/cc-unix.h.  */
+
+unsigned KRB4_32 KRB5_CALLCONV
+unix_time_gmt_unixsec (usecptr)
+	unsigned KRB4_32	*usecptr;
+{
+	struct timeval	now;
+
+	(void) gettimeofday (&now, (struct timezone *)0);
+	if (usecptr)
+		*usecptr = now.tv_usec;
+	return now.tv_sec;
+}
diff --git a/mechglue/src/lib/krb4/vmslink.com b/mechglue/src/lib/krb4/vmslink.com
new file mode 100644
index 000000000..95cabfe1d
--- /dev/null
+++ b/mechglue/src/lib/krb4/vmslink.com
@@ -0,0 +1,79 @@
+$ write sys$output "start of run"
+$ cc /decc /inc=inc /debug=all des.c
+$ cc /decc /inc=inc /debug=all d3des.c
+$ cc /decc /inc=inc /debug=all cbc.c
+$ cc /decc /inc=([],inc) /debug=all qcksum.c
+$ cc /decc /inc=([],inc) /debug=all str2key.c
+$ cc /decc /inc=([],inc) /debug=all parity.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all ad_print.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all add_tkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all cr_auth_repl.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all cr_ciph.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all cr_death_pkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all cr_err_repl.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all cr_tkt.c
+$ write sys$output "begin d"
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all debug.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all decomp_tkt.c
+stat $ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all dest_tkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all err_txt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all ext_tkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all fakeenv.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all fgetst.c
+$ write sys$output "begin g"
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_ad_tkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_admhst.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_cnffile.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_cred.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_in_tkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_krbhst.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_krbrlm.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_phost.c
+sgtty $ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_pw_in_tkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_pw_tkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_request.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_svc_in_tkt.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_tf_fname.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all g_tf_realm.c
+$ write sys$output "end g_"
+$ cc/decc/inc=inc /define=("HOST_BYTE_ORDER=1",BSD42) /debug=all gethostname.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all getst.c
+stat $ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all in_tkt.c
+$ cc/decc/inc=inc /define=("HOST_BYTE_ORDER=1",NEED_TIME_H) /debug=all klog.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all kname_parse.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all kntoln.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all kparse.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all krbglue.c
+stat $ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all kuserok.c
+$ write sys$output "end k"
+$ cc/decc/inc=inc /define=("HOST_BYTE_ORDER=1",NEED_TIME_H) /debug=all log.c 
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all mk_err.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all mk_preauth.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all mk_priv.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all mk_req.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all mk_safe.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all month_sname.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all netread.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all netwrite.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all pkt_cipher.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all pkt_clen.c
+$ write sys$output "begin rd"
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all rd_err.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all rd_preauth.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all rd_priv.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all rd_req.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all rd_safe.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all rd_svc_key.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all realmofhost.c
+$ write sys$output "begin recv"
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all recvauth.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all save_creds.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all send_to_kdc.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all sendauth.c
+$ cc/decc/inc=inc /define=("HOST_BYTE_ORDER=1",NEED_TIME_H) /debug=all stime.c 
+stat $ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all tf_shm.c
+stat $ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all tf_util.c
+MAXPATHLEN $ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all tkt_string.c
+$ cc/decc/inc=inc /define="HOST_BYTE_ORDER=1" /debug=all vmsswab.c
+$ library /create /list libkrb *.obj
+
diff --git a/mechglue/src/lib/krb4/vmsswab.c b/mechglue/src/lib/krb4/vmsswab.c
new file mode 100644
index 000000000..019580882
--- /dev/null
+++ b/mechglue/src/lib/krb4/vmsswab.c
@@ -0,0 +1,34 @@
+/* Copyright 1994 Cygnus Support */
+/* Mark W. Eichin */
+/*
+ * Permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation.
+ * Cygnus Support makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/* VMS doesn't have swab, but everything else does */
+/* so make this available anyway ... someday it might go
+   into the VMS makefile fragment, but for now it is only
+   referenced by l.com. */
+
+swab(from,to,nbytes) 
+        char *from;
+        char *to;
+        int nbytes;
+{
+	char tmp;
+
+        while ( (nbytes-=2) >= 0 ) {
+		tmp = from[1];
+                to[1] = from[0];
+		to[0] = tmp;
+                to++; to++;
+                from++; from++;
+        }
+}
+
diff --git a/mechglue/src/lib/krb4/win_glue.c b/mechglue/src/lib/krb4/win_glue.c
new file mode 100644
index 000000000..e9cb5db33
--- /dev/null
+++ b/mechglue/src/lib/krb4/win_glue.c
@@ -0,0 +1,51 @@
+/*
+ * win-glue.c
+ * 
+ * Glue code for pasting Kerberos into the Windows environment.
+ *
+ * Originally written by John Gilmore, Cygnus Support, May '94.
+ * Public Domain.
+ */
+
+#include "krb.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <windows.h>
+
+
+/*
+ * We needed a way to print out what might be FAR pointers on Windows,
+ * but might be ordinary pointers on real machines.  Printf modifiers
+ * scattered through the code don't cut it,
+ * since they might break on real machines.  Microloss
+ * didn't provide a function to print a char *, so we wrote one.
+ * It gets #define'd to fputs on real machines. 
+ */
+int
+far_fputs(string, stream)
+	char *string;
+	FILE *stream;
+{
+	return fprintf(stream, "%Fs", string);
+}
+
+int
+krb_start_session(x)
+     char *x;
+{
+	return KSUCCESS;
+}
+
+int
+krb_end_session(x)
+     char *x;
+{
+	return KSUCCESS;
+}
+
+void KRB5_CALLCONV
+krb_set_tkt_string(val)
+char *val;
+{
+}
diff --git a/mechglue/src/lib/krb4/win_store.c b/mechglue/src/lib/krb4/win_store.c
new file mode 100644
index 000000000..74c79ac5a
--- /dev/null
+++ b/mechglue/src/lib/krb4/win_store.c
@@ -0,0 +1,150 @@
+/*
+ * win_store.c
+ *
+ * Kerberos configuration storage management routines.
+ *
+ * Originally coded by John Rivlin / Fusion Software, Inc.
+ *
+ * This file incorporates replacements for the following Unix files:
+ *   g_cnffil.c
+ */
+
+#include "krb.h"
+#include "k5-int.h"
+#include <stdio.h>
+#include <assert.h>
+
+krb5_context krb5__krb4_context = 0;
+
+char *
+krb__get_srvtabname(default_srvtabname)
+	const char *default_srvtabname;
+{
+	const char* names[3];
+	char **full_name = 0, **cpp;
+	krb5_error_code retval;
+	char *retname;
+
+	if (!krb5__krb4_context) {
+		retval = krb5_init_context(&krb5__krb4_context);
+		if (!retval)
+			return NULL;
+	}
+	names[0] = "libdefaults";
+	names[1] = "krb4_srvtab";
+	names[2] = 0;
+	retval = profile_get_values(krb5__krb4_context->profile, names, 
+				    &full_name);
+	if (retval == 0 && full_name && full_name[0]) {
+		retname = strdup(full_name[0]);
+		for (cpp = full_name; *cpp; cpp++) 
+			krb5_xfree(*cpp);
+		krb5_xfree(full_name);
+	} else {
+		retname = strdup(default_srvtabname);
+	}
+	return retname;
+}
+
+/*
+ * Returns an open file handle to the configuration file.  This
+ * file was called "krb.conf" on Unix.  Here we search for the entry
+ * "krb.conf=" in the "[FILES]" section of the "kerberos.ini" file
+ * located in the Windows directory.  If the entry doesn't exist in
+ * the kerberos.ini file, then "krb.con" in the Windows directory is
+ * used in its place.
+ */
+FILE*
+krb__get_cnffile()
+{
+	FILE *cnffile = 0;
+	char cnfname[FILENAME_MAX];
+	char defname[FILENAME_MAX];
+	UINT rc;
+
+	defname[sizeof(defname) - 1] = '\0';
+	rc = GetWindowsDirectory(defname, sizeof(defname) - 1);
+	assert(rc > 0);
+
+	strncat(defname, "\\", sizeof(defname) - 1 - strlen(defname));
+
+	strncat(defname, DEF_KRB_CONF, sizeof(defname) - 1 - strlen(defname));
+
+	cnfname[sizeof(cnfname) - 1] = '\0';
+	GetPrivateProfileString(INI_FILES, INI_KRB_CONF, defname,
+		cnfname, sizeof(cnfname) - 1, KERBEROS_INI);
+
+	cnffile = fopen(cnfname, "r");
+
+	return cnffile;
+}
+
+
+/*
+ * Returns an open file handle to the realms file.  This
+ * file was called "krb.realms" on Unix.  Here we search for the entry
+ * "krb.realms=" in the "[FILES]" section of the "kerberos.ini" file
+ * located in the Windows directory.  If the entry doesn't exist in
+ * the kerberos.ini file, then "krb.rea" in the Windows directory is
+ * used in its place.
+ */
+FILE*
+krb__get_realmsfile()
+{
+	FILE *realmsfile = 0;
+	char realmsname[FILENAME_MAX];
+	char defname[FILENAME_MAX];
+	UINT rc;
+
+	defname[sizeof(defname) - 1] = '\0';
+	rc = GetWindowsDirectory(defname, sizeof(defname) - 1);
+	assert(rc > 0);
+
+	strncat(defname, "\\", sizeof(defname) - 1 - strlen(defname));
+
+	strncat(defname, DEF_KRB_REALMS, sizeof(defname) - 1 - strlen(defname));
+
+	defname[sizeof(defname) - 1] = '\0';
+	GetPrivateProfileString(INI_FILES, INI_KRB_REALMS, defname,
+		realmsname, sizeof(realmsname) - 1, KERBEROS_INI);
+
+	realmsfile = fopen(realmsname, "r");
+
+	return realmsfile;
+}
+
+
+/*
+ * Returns the current default user.  This information is stored in
+ * the [DEFAULTS] section of the "kerberos.ini" file located in the
+ * Windows directory.
+ */
+char * KRB5_CALLCONV
+krb_get_default_user()
+{
+	static char username[ANAME_SZ];
+
+	GetPrivateProfileString(INI_DEFAULTS, INI_USER, "",
+		username, sizeof(username), KERBEROS_INI);
+
+	return username;
+}
+
+
+/*
+ * Sets the default user name stored in the "kerberos.ini" file.
+ */
+int KRB5_CALLCONV
+krb_set_default_user(username)
+	char *username;
+{
+	BOOL rc;
+
+	rc = WritePrivateProfileString(INI_DEFAULTS, INI_USER,
+		username, KERBEROS_INI);
+
+	if (rc)
+		return KSUCCESS;
+	else
+		return KFAILURE;
+}
diff --git a/mechglue/src/lib/krb4/win_time.c b/mechglue/src/lib/krb4/win_time.c
new file mode 100644
index 000000000..2560c3192
--- /dev/null
+++ b/mechglue/src/lib/krb4/win_time.c
@@ -0,0 +1,121 @@
+/*
+ * win_time.c
+ * 
+ * Glue code for pasting Kerberos into the Windows environment.
+ *
+ * Originally written by John Gilmore, Cygnus Support, May '94.
+ * Public Domain.
+ */
+
+#include "krb.h"
+
+#include <sys/types.h>
+#include <time.h>
+#include <sys/timeb.h>
+#include <stdio.h>
+#include <windows.h>
+#include <dos.h>
+
+#ifdef _WIN32
+
+unsigned KRB4_32
+win_time_gmt_unixsec (usecptr)
+    unsigned KRB4_32	*usecptr;
+{
+    struct _timeb timeptr;
+
+    _ftime(&timeptr);                           /* Get the current time */
+
+    if (usecptr)
+	*usecptr = timeptr.millitm * 1000;
+
+    return timeptr.time + CONVERT_TIME_EPOCH;
+}
+
+#else
+
+/*
+ * Time handling.  Translate Unix time calls into Kerberos internal 
+ * procedure calls.  See ../../include/c-win.h.
+ *
+ * Due to the fact that DOS time can be unreliable we have reverted
+ * to using the AT hardware clock and converting it to Unix time.
+ */
+
+unsigned KRB4_32
+win_time_gmt_unixsec (usecptr)
+	unsigned KRB4_32	*usecptr;
+{
+	struct tm tm;
+	union _REGS inregs;
+	union _REGS outregs;
+	struct _timeb now;
+	time_t time;
+
+	_ftime(&now);
+
+	#if 0
+		if (usecptr)
+			*usecptr = now.millitm * 1000;
+	#endif
+
+	/* Get time from AT hardware clock INT 0x1A, AH=2 */
+	memset(&inregs, 0, sizeof(inregs));
+	inregs.h.ah = 2;
+
+	_int86(0x1a, &inregs, &outregs);
+
+	/* 0x13 = decimal 13, hence the decoding below */
+	tm.tm_sec = 10 * ((outregs.h.dh & 0xF0) >> 4) + (outregs.h.dh & 0x0F);
+	tm.tm_min = 10 * ((outregs.h.cl & 0xF0) >> 4) + (outregs.h.cl & 0x0F);
+	tm.tm_hour = 10 * ((outregs.h.ch & 0xF0) >> 4) + (outregs.h.ch & 0x0F);
+
+	/* Get date from AT hardware clock INT 0x1A, AH=4 */
+	memset(&inregs, 0, sizeof(inregs));
+	inregs.h.ah = 4;
+
+	_int86(0x1a, &inregs, &outregs);
+
+	tm.tm_mday = 10 * ((outregs.h.dl & 0xF0) >> 4) + (outregs.h.dl & 0x0F);
+	tm.tm_mon = 10 * ((outregs.h.dh & 0xF0) >> 4) + (outregs.h.dh & 0x0F) - 1;
+	tm.tm_year = 10 * ((outregs.h.cl & 0xF0) >> 4) + (outregs.h.cl & 0x0F);
+	tm.tm_year += 100 * ((10 * (outregs.h.ch & 0xF0) >> 4)
+	            + (outregs.h.ch & 0x0F) - 19);
+
+    	tm.tm_wday = 0;
+	tm.tm_yday = 0;
+	tm.tm_isdst = now.dstflag;
+
+	time = mktime(&tm);
+
+	if (usecptr)
+		*usecptr = 0;
+
+	return time + CONVERT_TIME_EPOCH;
+}
+
+#endif
+
+/*
+ * This routine figures out the current time epoch and returns the
+ * conversion factor.  It exists because 
+ * Microloss screwed the pooch on the time() and _ftime() calls in
+ * its release 7.0 libraries.  They changed the epoch to Dec 31, 1899!
+ * Idiots...   We try to cope.
+ */
+
+static struct tm jan_1_70 = {0, 0, 0, 1, 0, 70};
+static long epoch = 0;
+static int epoch_set = 0;
+
+long
+win_time_get_epoch()
+{
+
+	if (!epoch_set) {
+		epoch = - mktime (&jan_1_70);	/* Seconds til 1970 localtime */
+		epoch += timezone;		/* Seconds til 1970 GMT */
+		epoch_set = 1;
+	}
+	return epoch;
+}
diff --git a/mechglue/src/lib/krb4_32.def b/mechglue/src/lib/krb4_32.def
new file mode 100644
index 000000000..11814cebd
--- /dev/null
+++ b/mechglue/src/lib/krb4_32.def
@@ -0,0 +1,86 @@
+;-----------------------------
+;   KRB4_32.DEF - module definition file
+;-----------------------------
+
+;LIBRARY		KRB4_32
+DESCRIPTION	'DLL for Kerberos support'
+HEAPSIZE	8192
+
+EXPORTS
+	dest_tkt
+	get_service_key
+	in_tkt
+	kname_parse
+	krb_check_auth
+	krb_get_admhst
+	krb_get_cred
+	krb_get_default_user
+	krb_get_err_text
+	krb_get_krbhst
+	krb_get_lrealm
+	krb_get_phost
+	krb_get_pw_in_tkt
+	krb_get_pw_in_tkt_preauth
+	krb_get_svc_in_tkt
+	krb_get_tf_fullname
+	krb_get_tf_realm
+	krb_get_ticket_for_service
+	krb_mk_auth
+	krb_mk_err
+	krb_mk_priv
+	krb_mk_req
+	krb_mk_safe
+	krb_rd_err
+	krb_rd_priv
+	krb_rd_req
+	krb_rd_safe
+	krb_realmofhost
+	krb_recvauth
+	krb_save_credentials
+	krb_set_default_user
+;	kuserok
+	put_svc_key
+	read_service_key
+;	kadm_change_pw2
+;	kadm_init_link
+;	kadm_get_err_text
+;	kadm_change_pw
+;	kstream_create_from_fd
+;	kstream_create_rlogin_from_fd
+;	kstream_create_rcp_from_fd
+;	kstream_write
+;	kstream_read
+;	kstream_flush
+;	kstream_destroy
+;	kstream_set_buffer_mode
+	krb_in_tkt
+
+; Added to match exports from KfM
+    krb_change_password
+    decomp_ticket
+    krb_err_txt
+    ;krb_ad_tkt
+    krb_get_in_tkt
+    krb_get_in_tkt_creds
+    krb_get_pw_in_tkt_creds
+    ;krb_pw_tkt
+    k_isrealm
+    k_isinst
+    k_isname
+    kname_unparse
+    ;kuserok
+    krb_set_lifetime
+    krb_rd_req_int
+    krb_sendauth
+    ;tkt_string
+    krb_set_tkt_string
+    krb_get_num_cred
+    krb_get_nth_cred
+    krb_delete_cred
+    dest_all_tkts
+    krb_get_profile 
+    ;FSp_krb_get_svc_in_tkt
+    ;FSp_put_svc_key
+    ;FSp_read_service_key
+    krb_time_to_life
+    krb_life_to_time
diff --git a/mechglue/src/lib/krb5.rc b/mechglue/src/lib/krb5.rc
new file mode 100644
index 000000000..f8e540024
--- /dev/null
+++ b/mechglue/src/lib/krb5.rc
@@ -0,0 +1,44 @@
+/*
+ * lib/krb5/os/win-pwd.h
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "win-mac.h"
+
+ID_READ_PWD_DIALOG DIALOG 60, 72, 200, 84
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU |
+	DS_SETFONT
+CAPTION "Kerberos Password/Challenge"
+FONT 8, "Helv"
+{
+  LTEXT "", ID_READ_PWD_PROMPT, 10, 8, 180, 10
+  LTEXT "", ID_READ_PWD_PROMPT2, 10, 24, 180, 10
+  EDITTEXT ID_READ_PWD_PWD, 10, 42, 180, 12, ES_AUTOHSCROLL | ES_PASSWORD |
+	WS_BORDER | WS_TABSTOP
+  DEFPUSHBUTTON "&OK", IDOK, 55, 61, 40, 14
+  PUSHBUTTON "&Cancel", IDCANCEL, 107, 61, 40, 14
+}
+
+#include "..\windows\version.rc"
diff --git a/mechglue/src/lib/krb5.saber.warnings b/mechglue/src/lib/krb5.saber.warnings
new file mode 100644
index 000000000..9fa9d2e15
--- /dev/null
+++ b/mechglue/src/lib/krb5.saber.warnings
@@ -0,0 +1,294 @@
+----------------
+"/mit/krb5/src/lib/krb/gc_via_tgt.c":119, krb5_get_cred_via_tgt(), Statement not reached (Warning #529)
+   118:         return retval;
+ * 119:         break;                          /* not strictly necessary... */   120:     }
+( while sourcing "/tmp/saber.source":4 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/krb/in_tkt_sky.c":48, skey_keyproc(), Unused formal parameter (Warning #590)
+    47:  */
+ *  48: static krb5_error_code
+    49: skey_keyproc(DECLARG(const krb5_keytype, type),
+( while sourcing "/tmp/saber.source":4 )
+Formal parameter 'padata' was not used.
+----------------
+"/mit/krb5/src/lib/krb/rd_priv.c":63, krb5_rd_priv(), Unused formal parameter (Warning #590)
+    62:
+ *  63: krb5_error_code
+    64: krb5_rd_priv(DECLARG(const krb5_data *, inbuf),
+( while sourcing "/tmp/saber.source":4 )
+Formal parameter 'recv_addr' was not used.
+----------------
+"/usr/include/unistd.h":182, Function redeclared (Warning #701)
+   181:
+ * 182: extern unsigned int
+   183:         alarm(),
+( while sourcing "/tmp/saber.source":4 )
+Function 'alarm' was previously declared as:
+    extern int alarm();
+----------------
+"/usr/include/unistd.h":198, Function redeclared (Warning #701)
+   197:
+ * 198: extern void
+   199:         _exit();
+( while sourcing "/tmp/saber.source":4 )
+Function '_exit' was previously declared as:
+    extern int _exit();
+----------------
+"/mit/krb5/src/lib/asn.1/kpwd2pwd.c":75, krb5_pwd_seq2KRB5_PWD__SEQ(), Functionredeclared (Warning #701)
+    74:                 sizeof(struct type_KRB5_PasswdSequence))) == NULL) {
+ *  75:         com_err("kpwd2pwd", 0, "Unable to Allocate PasswdSequence");
+    76:         *error = ENOMEM;
+( while sourcing "/tmp/saber.source":6 )
+Function 'com_err' was previously declared as:
+    extern void com_err();
+----------------
+"/mit/krb5/src/lib/keytab/file/ktf_util.c":601, krb5_ktfileint_size_entry(), Unused automatic variable (Warning #591)
+   600: {
+ * 601:     krb5_int16 count, size;
+   602:     krb5_int32 total_size, i;
+( while sourcing "/tmp/saber.source":12 )
+Automatic variable 'size' was not used.
+----------------
+"/mit/krb5/src/lib/keytab/file/ktf_util.c":757, krb5_ktfileint_find_slot(), Unused label (Warning #593)
+( while sourcing "/tmp/saber.source":12 )
+Label 'abend' was not used.
+----------------
+"/mit/krb5/src/lib/ccache/file/fcc_gennew.c":40, Unknown directive (Warning #471)
+    39: #else
+    40:  #error find some way to use net-byte-order file version numbers.
+          ^
+    41: #endif
+( while sourcing "/tmp/saber.source":16 )
+Directive 'error' is undefined.
+
+----------------
+"/mit/krb5/src/lib/ccache/file/fcc_gennew.c":77, krb5_fcc_generate_new(), Function redeclared (Warning #701)
+    76:      (void) strcat(scratch, "XXXXXX");
+ *  77:      mktemp(scratch);
+    78:
+( while sourcing "/tmp/saber.source":16 )
+Function 'mktemp' was previously declared as:
+    extern char *mktemp();
+----------------
+"/mit/krb5/src/lib/ccache/file/fcc_maybe.c":41, Unknown directive (Warning #471)
+    40: #else
+    41:  #error find some way to use net-byte-order file version numbers.
+          ^
+    42: #endif
+( while sourcing "/tmp/saber.source":16 )
+Directive 'error' is undefined.
+Warning: 1 module currently not loaded.
+Loading: -I. /mit/krb5/src/lib/rcache/rc_base.c
+
+----------------
+"/mit/krb5/src/lib/rcache/rc_base.h":13, Cannot read file (Error #400)
+    12: #define KRB5_RC_H
+ *  13: #include <krb5/krb5.h>
+    14: #include <krb5/ext-proto.h>
+( while sourcing "/tmp/saber.source":18 )
+Cannot open 'krb5/krb5.h' for input.
+----------------
+"/mit/krb5/src/lib/rcache/rc_dfl.c":335, krb5_rc_dfl_recover(), Unused automatic variable (Warning #591)
+   334:  struct dfl_data *t = (struct dfl_data *)id->data;
+ * 335:  int i;
+   336:  krb5_donot_replay *rep;
+( while sourcing "/tmp/saber.source":18 )
+Automatic variable 'i' was not used.
+----------------
+"/mit/krb5/src/lib/rcache/rc_dfl.c":402, krb5_rc_dfl_recover(), Unused label (Warning #593)
+( while sourcing "/tmp/saber.source":18 )
+Label 'end_loop' was not used.
+----------------
+"/mit/krb5/src/lib/rcache/rc_dfl.c":443, krb5_rc_dfl_store(), Statement not reached (Warning #529)
+   442:    case CMP_MALLOC:
+ * 443:        return KRB5_RC_MALLOC; break;
+   444:    case CMP_REPLAY:
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_dfl.c":445, krb5_rc_dfl_store(), Statement not reached (Warning #529)
+   444:    case CMP_REPLAY:
+ * 445:        return KRB5KRB_AP_ERR_REPEAT; break;
+   446:    case 0: break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_dfl.c":438, krb5_rc_dfl_store(), Unused automatic variable (Warning #591)
+   437:  struct dfl_data *t = (struct dfl_data *)id->data;
+ * 438:  int i;
+   439:
+( while sourcing "/tmp/saber.source":18 )
+Automatic variable 'i' was not used.
+----------------
+"/mit/krb5/src/lib/rcache/rc_dfl.c":525, krb5_rc_dfl_expunge(), Benign argumentmismatch (Warning #68)
+   524:   {
+ * 525:         if (krb5_rc_io_store (&tmp, &q->rep))
+   526:      return KRB5_RC_IO;
+( while sourcing "/tmp/saber.source":18 )
+Benign type mismatch in call to function 'krb5_rc_io_store':
+Argument #1 has type (struct krb5_rc_iostuff *) but type (struct dfl_data *) was expected.
+Defined/declared in "/mit/krb5/src/lib/rcache/rc_dfl.c":404
+----------------
+"/mit/krb5/src/lib/rcache/rc_dfl.c":473, krb5_rc_dfl_expunge(), Unused automatic variable (Warning #591)
+   472:  struct dfl_data *t = (struct dfl_data *)id->data;
+ * 473:  int i;
+   474: #ifdef NOIOSTUFF
+( while sourcing "/tmp/saber.source":18 )
+Automatic variable 'i' was not used.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":33, Unknown directive (Warning #471)
+    32: #else
+    33:  #error find some way to use net-byte-order file version numbers.
+          ^
+    34: #endif
+( while sourcing "/tmp/saber.source":18 )
+Directive 'error' is undefined.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":73, krb5_rc_io_creat(), Constant in conditional (Warning #558)
+    72:
+ *  73:  GETDIR;
+    74:  if (fn && *fn)
+( while sourcing "/tmp/saber.source":18 )
+The conditional expression for 'do/while' is always false.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":156, krb5_rc_io_open(), Constant in conditional (Warning #558)
+   155:
+ * 156:  GETDIR;
+   157:  if (!(d->fn = malloc(strlen(fn) + dirlen + 1)))
+( while sourcing "/tmp/saber.source":18 )
+The conditional expression for 'do/while' is always false.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":165, krb5_rc_io_open(), Function redeclared (Warning #701)
+   164:
+ * 165:      me = getuid();
+   166:      /* must be owned by this user, to prevent some security problems with
+( while sourcing "/tmp/saber.source":18 )
+Function 'getuid' was previously declared as:
+    extern short getuid();
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":238, krb5_rc_io_write(), Statement not reached (Warning #529)
+   237:     {
+ * 238:      case EBADF: return KRB5_RC_IO_UNKNOWN; break;
+   239:      case EFBIG: return KRB5_RC_IO_SPACE; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":239, krb5_rc_io_write(), Statement not reached (Warning #529)
+   238:      case EBADF: return KRB5_RC_IO_UNKNOWN; break;
+ * 239:      case EFBIG: return KRB5_RC_IO_SPACE; break;
+   240: #ifdef EDQUOT
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":241, krb5_rc_io_write(), Statement not reached (Warning #529)
+   240: #ifdef EDQUOT
+ * 241:      case EDQUOT: return KRB5_RC_IO_SPACE; break;
+   242: #endif
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":243, krb5_rc_io_write(), Statement not reached (Warning #529)
+   242: #endif
+ * 243:      case ENOSPC: return KRB5_RC_IO_SPACE; break;
+   244:      case EIO: return KRB5_RC_IO_IO; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":244, krb5_rc_io_write(), Statement not reached (Warning #529)
+   243:      case ENOSPC: return KRB5_RC_IO_SPACE; break;
+ * 244:      case EIO: return KRB5_RC_IO_IO; break;
+   245:      default: return KRB5_RC_IO_UNKNOWN; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":245, krb5_rc_io_write(), Statement not reached (Warning #529)
+   244:      case EIO: return KRB5_RC_IO_IO; break;
+ * 245:      default: return KRB5_RC_IO_UNKNOWN; break;
+   246:     }
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":256, krb5_rc_io_sync(), Statement not reached (Warning #529)
+   255:       {
+ * 256:       case EBADF: return KRB5_RC_IO_UNKNOWN; break;
+   257:       case EIO: return KRB5_RC_IO_IO; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":257, krb5_rc_io_sync(), Statement not reached (Warning #529)
+   256:       case EBADF: return KRB5_RC_IO_UNKNOWN; break;
+ * 257:       case EIO: return KRB5_RC_IO_IO; break;
+   258:       default: return KRB5_RC_IO_UNKNOWN; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":258, krb5_rc_io_sync(), Statement not reached (Warning #529)
+   257:       case EIO: return KRB5_RC_IO_IO; break;
+ * 258:       default: return KRB5_RC_IO_UNKNOWN; break;
+   259:       }
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":273, krb5_rc_io_read(), Statement not reached (Warning #529)
+   272:     {
+ * 273:      case EBADF: return KRB5_RC_IO_UNKNOWN; break;
+   274:      case EIO: return KRB5_RC_IO_IO; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":274, krb5_rc_io_read(), Statement not reached (Warning #529)
+   273:      case EBADF: return KRB5_RC_IO_UNKNOWN; break;
+ * 274:      case EIO: return KRB5_RC_IO_IO; break;
+   275:      default: return KRB5_RC_IO_UNKNOWN; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":275, krb5_rc_io_read(), Statement not reached (Warning #529)
+   274:      case EIO: return KRB5_RC_IO_IO; break;
+ * 275:      default: return KRB5_RC_IO_UNKNOWN; break;
+   276:     }
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":298, krb5_rc_io_destroy(), Statement not reached (Warning #529)
+   297:     {
+ * 298:      case EBADF: return KRB5_RC_IO_UNKNOWN; break;
+   299:      case EIO: return KRB5_RC_IO_IO; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":299, krb5_rc_io_destroy(), Statement not reached (Warning #529)
+   298:      case EBADF: return KRB5_RC_IO_UNKNOWN; break;
+ * 299:      case EIO: return KRB5_RC_IO_IO; break;
+   300:      case EPERM: return KRB5_RC_IO_PERM; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":300, krb5_rc_io_destroy(), Statement not reached (Warning #529)
+   299:      case EIO: return KRB5_RC_IO_IO; break;
+ * 300:      case EPERM: return KRB5_RC_IO_PERM; break;
+   301:      case EBUSY: return KRB5_RC_IO_PERM; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":301, krb5_rc_io_destroy(), Statement not reached (Warning #529)
+   300:      case EPERM: return KRB5_RC_IO_PERM; break;
+ * 301:      case EBUSY: return KRB5_RC_IO_PERM; break;
+   302:      case EROFS: return KRB5_RC_IO_PERM; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":302, krb5_rc_io_destroy(), Statement not reached (Warning #529)
+   301:      case EBUSY: return KRB5_RC_IO_PERM; break;
+ * 302:      case EROFS: return KRB5_RC_IO_PERM; break;
+   303:      default: return KRB5_RC_IO_UNKNOWN; break;
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
+----------------
+"/mit/krb5/src/lib/rcache/rc_io.c":303, krb5_rc_io_destroy(), Statement not reached (Warning #529)
+   302:      case EROFS: return KRB5_RC_IO_PERM; break;
+ * 303:      default: return KRB5_RC_IO_UNKNOWN; break;
+   304:     }
+( while sourcing "/tmp/saber.source":18 )
+The statement cannot be reached.
diff --git a/mechglue/src/lib/krb5/.Sanitize b/mechglue/src/lib/krb5/.Sanitize
new file mode 100644
index 000000000..9858cf32a
--- /dev/null
+++ b/mechglue/src/lib/krb5/.Sanitize
@@ -0,0 +1,45 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+asn.1
+ccache
+configure
+configure.in
+error_tables
+free
+keytab
+krb
+os
+posix
+rcache
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/ChangeLog b/mechglue/src/lib/krb5/ChangeLog
new file mode 100644
index 000000000..f7849aea5
--- /dev/null
+++ b/mechglue/src/lib/krb5/ChangeLog
@@ -0,0 +1,597 @@
+2005-11-14  Jeffrey Altman <jaltman@mit.edu>
+
+	* krb5_libinit.c: include k5-int.h instead of krb5.h
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-02-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_libinit.c (krb5int_lib_fini): Only show "skipping" message
+	if SHOW_INITFINI_FUNCS is defined.
+
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_libinit.c (krb5int_lib_init, krb5int_lib_fini): If
+	SHOW_INITFINI_FUNCS is defined, print tracing messages.
+
+	* Makefile.in (LIBINITFUNC, LIBFINIFUNC): Define.
+
+2005-01-17  Jeffrey Altman <jaltman@mit.edu>
+
+        * krb5_libinit.c: implement library cleanup of mutexes, static vars, etc
+
+2005-01-04  Jeffrey Altman <jaltman@mit.edu>
+      
+        * libkrb5.exports: add krb5_is_thread_safe
+
+2004-11-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Remove -ldl accidentally added in
+	last change.
+
+2004-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS, SHLIB_EXPLIBS): Add support
+	library.
+
+2004-08-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkrb5.exports: Remove memory ccache symbols except ops table.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (OBJFILEDEP, OBJFILELIST) [DOS]: Include locally
+	built object files.
+	(OBJFILE, LIBOBJS, LOCALINCLUDES) [DOS]: Define.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Don't set.
+
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): Add $srcdir/os.
+
+	* krb5_libinit.c: Include os-proto.h.
+	(krb5int_lib_init): Initialize krb5int_us_time_mutex.
+
+	* libkrb5.exports: Drop krb5_init_ets, krb5_free_ets,
+	krb5_kt_default_vno, and krb5int_profile_shared_data.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_libinit.c (initialized): Variable deleted, all references
+	removed.
+	(krb5int_lib_init): Initialize error tables here, including k524.
+	(krb5int_initialize_library): Don't do it here.
+	(krb5int_lib_fini): Remove k524 error table too.
+
+2004-05-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): Include ccache, keytab and rcache
+	directories.
+
+	* krb5_libinit.c: Include cc-int.h, kt-int.h, rc-int.h for
+	init/fini prototypes.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkrb5.exports: Export krb5int_foreach_localaddr for now.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_libinit.c: Include k5-platform.h.
+	(krb5int_lib_init, krb5int_lib_fini): New init/fini functions.
+	Call the corresponding functions for the ccache, keytab, and
+	rcache code.  Incorporate the finalization code from
+	krb5int_cleanup_library.
+	(krb5int_initialize_library): Make sure the init function runs
+	successfully.
+	(krb5int_cleanup_library): Now empty.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkrb5.exports: New file.
+
+2003-12-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Remove basic checks for header files and
+	functions, now moved into include/configure.in.
+
+2003-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't substitute LIBOBJS, newer autoconfs don't
+	like it.
+
+2003-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't replace any missing system functions.  Just
+	set LIBOBJS empty for now and substitute it.
+
+2003-08-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't check for or replace vfprintf, vsprintf,
+	strerror, memmove, or sscanf, all part of C 89.
+
+2003-07-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_libinit.c: Include autoconf.h.
+
+2003-03-07  Alexandra Ellwood  <lxs@mit.edu>
+
+    * krb5_libinit.c: Changed USE_HARDCODED_FALLBACK_ERROR_TABLES macro 
+    to !USE_BUNDLE_ERROR_STRINGS so Darwin based builds get com_err
+    style error tables.
+
+2003-03-06  Alexandra Ellwood <lxs@mit.edu>
+
+    * krb5_libinit.c: Removed Mac OS X header goober.  Conditionalize
+    CCAPI calls on USE_CCAPI so Darwin builds work.
+
+2003-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add KRB5_SIGTYPE and CHECK_SIGNALS for
+	os/prompter.c.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_INSTALL.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SUBDIROBJLISTS): New variable.
+
+2002-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_libinit.c: Put # for cpp directives in first column.
+
+2002-07-03  Alexandra Ellwood <lxs@mit.edu>
+
+	* krb5_libinit.c: Conditionalized error table loading for
+	Mac OS X.  Error tables should always be loaded on other 
+	platforms.
+
+	* krb5_libinit.c: Added an include for com_err.h since
+	it is not included by error table headers on Mac OS X.  Also
+	fixed busted check for Mac OS
+
+	[pullups form 1-2-2-branch]
+
+2002-06-25 Alexandra Ellwood <lxs@mit.edu>
+
+	* krb5_libinit.c: Added an include for com_err.h since
+	it is not included by error table headers on Mac OS X.  Also
+	fixed busted check for Mac OS
+
+	* krb5_libinit.c: added #define for Mac OS X so
+	that krb5int_cleanup_library calls krb5_stdcc_shutdown.
+
+	[pullups from 1-2-2-branch]
+
+2002-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't set up keytab/file or keytab/srvtab
+	subdirectories.
+	* Makefile.in (STOBJLISTS): Delete keytab/file/OBJS.ST and
+	keytab/srvtab/OBJS.ST.
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBMINOR): Bump due to changes in error tables.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_libinit.c: Drop _MSDOS support.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Use $(srcdir) not $(subdir).
+
+2001-07-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add KRB5_GETSOCKNAME_ARGS and KRB5_GETPEERNAME_ARGS.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Test for strptime() prototype. Debian linux has
+	strptime in the C library but does not provide a prototype.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't use HAS_ANSI_VOLATILE.
+
+2001-04-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Moved test for socklen_t to include directory.
+
+2001-03-05  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Check for sys/filio.h for FIONBIO.
+
+2000-12-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Look for socklen_t, define HAVE_SOCKLEN_T if
+	found.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_C_CONST instead of AC_CONST.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5_libinit.c: Include krb5_libinit.h for prototypes. 
+
+2000-10-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for getifaddrs and ifaddrs.h.
+
+2000-09-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add AC_TYPE_OFF_T for off_t declaraion.
+
+2000-08-29  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Don't generate keytab/db/Makefile, since it isn't
+	used.
+
+	* Makefile.in: Garbage collect a little.  Don't include keytab/*
+	directories directly on $(LOCAL_SUBDIRS), as keytab/Makefile.in
+	lists them itself.
+
+2000-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't generate Makefile in ccache/file,
+	ccache/stdio, ccache/memory.
+	* Makefile.in (LOCAL_SUBDIRS, LIB_SUBDIRS, LIBDONE, STOBJLISTS):
+	Delete references to those directories.
+
+2000-07-01  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Use $(LIBS) not @RESOLV_LIB@ in
+	order to get -lnsl, -lsocket, etc. if necessary.
+
+2000-06-23  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (LIBMAJOR, LIBMINOR): Bump version.
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Add @RESOLV_LIB@.
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* configure.in: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for gethostbyname2.
+
+Tue Feb 22 10:20:57 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean-unix): Add clean-libobjs.
+
+2000-01-24  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_libinit.c: Conditionalize call to stdcc_shutdown().
+
+	* configure.in: Fix to build library objects in this directory.
+
+	* Makefile.in (STOBJLISTS): Fix to actually build krb5_libinit.o.
+
+	* krb5_libinit.c: Fix to use 0 and 1 instead of false and true.
+
+Fri Jan 21 22:47:00 2000  Miro Jurisic  <meeroh@mit.edu>
+
+	* Makefile.in: added krb5_libinit.[co]
+	* krb5_libinit.[ch]: new files, contain library initialization
+		and cleanup code
+
+1999-12-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBMINOR): Update to 2.
+
+1999-06-13  Geoffrey King  <gjking@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Add new subdirectory keytab/srvtab.
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+Mon May 17 14:09:28 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Make directories for clean-windows target lowercase
+		like everywhere else.
+
+Mon May 10 15:23:34 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+	* configure.in: Add test for the fcntl.h header file.
+
+Thu Jul 30 13:12:57 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* configure.in: Test for sa_len so localaddr works on NetBSD.
+
+Sun Jul 26 17:46:47 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* Makefile.in (LIBMAJOR): bump to 2
+
+Wed Apr 15 18:07:20 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): 
+	(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
+
+Fri Feb 27 23:15:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Replace @SHLIB_GEN@ with @GEN_LIB@
+
+Fri Feb 27 18:00:15 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Move the regular expression function tests into
+		aclocal.m4, since they also need to be shared by
+		lib/kadm5's configure script.
+
+	* configure.in: Move tests from all of krb5's subdirectories into
+		this configure.in, and make it generate makefiles for all
+		of the subdirectories.
+
+	* Makefile.in: Add a LOCAL_SUBDIRS macro for all subdirectories in
+		the krb5 library.
+
+Wed Feb 18 16:18:18 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Sat Feb 14 10:37:26 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Remove USE_ANAME, and the defines for ANAME_DBDEP and
+	        ANAME_DBLIB as they are no longer used.
+
+	* Makefile.in: Remove unused ANAME_DBDEP and ANAME_DBLIB definitions.
+
+Fri Feb 13 15:26:42 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, configure.in: Remove the free directory from the
+ 		list of subdirectories to be built.  (All functions moved
+ 		into lib/krb5/free/kfree.c)
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Use AC_CONFIG_DIRS instead of CONFIG_DIRS, and
+		remove use of DO_SUBDIRS.
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jul 25 15:24:41 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Bump version due to et changes.
+
+Sat Feb 22 01:37:03 1997  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+	* Makefile.in (LIBMINOR): Bump minor version
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+Fri Feb  7 21:48:10 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add rule to install libraries.
+
+Fri Jan  3 16:47:59 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to use new KRB5_BUILD_LIBRARY_WITH_DEPS
+ 	macro.
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Mon Nov 18 20:42:39 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Set shared library version to 1.0. [krb5-libs/201]
+
+Wed Oct 23 01:15:40 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* configure.in, Makefile.in: Check to see if the -lgen library
+		exists; if so, add it to the SHLIB_LIBS line, since it
+		will be needed by an_to_ln.c, in all probability.
+
+Fri Jun  7 17:38:09 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows, clean-windows): Use full directory
+		name "error_tables" when building under Windows so that
+		the build will work correctly under VFAT and NTFS filesystems.
+
+Thu Jun  6 00:04:38 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Don't pass $(LIBCMD) on the command
+		line.  It's set in the windows.in prologue for all Makefiles anyway.
+
+Mon May 20 10:56:51 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* Makefile.in (libkrb5.$(STEXT)): fix sense of test; also deal
+		with new improved libupdate
+
+Tue Apr 30 16:31:50 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* Makefile.in (libkrb5.$(STEXT)): Set a variable with or without
+	"--force" and use it, instead of duplicating the rest of the
+	code.  Use LIBDONE as list to process, so berk_db will be skipped
+	when not in use.  Check exit status of LIBUPDATE invocation.
+	Remove library before creating as workaround for libupdate bug.
+
+Wed Feb  7 00:23:18 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Sat Jan 27 18:25:42 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in (hashloc): Fix quoting so it makes it into the Makefile.
+
+Mon Jan 22 15:23:05 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Merge in berk_db library if needed.
+
+	* Makefile.in (LIB_SUBDIRS): Get location of berk_db from
+		configure if needed.
+
+Wed Dec 13 07:09:30 1995  Chris Provenzano (proven@mit.edu)
+
+        * Makefile.in : Move db keytab routines to lib/kdb.
+
+Tue Dec  5 20:57:06 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in: Removed dependency on krb4 library in building
+		shared library. 
+
+Fri Nov  3 21:31:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Added the ccache/memory subdirectory.
+
+Fri Oct  6 22:05:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Oct  2 11:12:24 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in (V5_MAKE_SHARED_LIB): Change rule to install
+		version 0.1 of the library. Pass the libcrypto and
+		libcom_err version number to Makefile
+
+	* Makefile.in (CRYPTO_VER): Get the proper libcrypto version number
+
+Mon Sep 25 17:01:48 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 13 11:11:38 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: Put back in all:: all-$(WHAT) rule--PC needs it.
+
+Fri Jun 30 14:43:38 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add Berkeley database code here.  Remove typo in
+		libupdate section.
+
+Wed Jun 28 21:25:29 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: with static libs, we need install-unix, not install.
+
+Mon Jun 26 17:36:53 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* Makefile.in (install-unix): This should be generated by configure.in, not Makefile.in.  My typo was there, not here.
+
+Sun Jun 25 08:24:46 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: Typo: install-mac was really supposed to be
+		install-unix
+
+Fri Jun 23 12:15:02 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* configure.in: Typo: krb5_cv_staticlibs_enabled, not
+        krb5_cv_enable_staticlibs
+
+Thu Jun 22 18:03:35 1995  Sam Hartman  (hartmans@tardis)
+
+	* Makefile.in: Treat libcom_err.a as shared, use new conventions
+	regarding static version.
+
+
+Fri Jun 16 11:16:44 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add shared library install target.
+
+
+Thu Jun 15 18:08:12 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add definitions for shared library build rules.  Also,
+		remove explicit "all" target at front so we do subdirectories
+		first.
+	* configure.in - Create symlinks for archive and shared library when
+		we build them.
+
+Fri Jun  9 18:51:24 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Fri May 26 20:12:37 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for building shared libraries.
+
+Sat Apr 22 10:58:49 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* configure.in: Add rule for make check to descend to subdirs
+
+Fri Apr 21 20:47:35 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Added the profile directory for the profile routines.
+
+Wed Mar 15 20:23:17 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: cleaned up for the PC
+
+Wed Mar 15 12:26:21 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made so it recurses into the subdirs for the PC.
+
+Fri Nov 18 00:17:47 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: move WITH_CCOPTS, WITH_KRB5ROOT.
+
+Wed Nov  2 02:35:44 1994  Mark W. Eichin  (eichin@paycheck.cygnus.com)
+
+	* Makefile.in (libkrb5.a): done needs a trailing semicolon if it
+	isn't followed by a newline, as does fi, with certain shells.
+
+Tue Nov  1 14:56:47 1994    (tytso@rsx-11)
+
+	* Makefile.in: Change the way libupdate works so that we use
+		libkrb5.stamp to determine whether or not $arcmd needs to
+		be rerun. 
+
+	* Makefile.in:
+	* configure.in: Change the way the library is built to use the
+		libupdate script.
+
+Mon Oct  3 21:11:19 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: make install obey $(DESTDIR)
+
+Thu Aug  4 03:42:31 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: oops look for install program
+
+	* Makefile.in: make install fixes
+
diff --git a/mechglue/src/lib/krb5/Makefile.in b/mechglue/src/lib/krb5/Makefile.in
new file mode 100644
index 000000000..72aa7cd45
--- /dev/null
+++ b/mechglue/src/lib/krb5/Makefile.in
@@ -0,0 +1,147 @@
+thisconfigdir=.
+myfulldir=lib/krb5
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/ccache -I$(srcdir)/keytab -I$(srcdir)/rcache -I$(srcdir)/os
+LOCAL_SUBDIRS= error_tables asn.1 ccache keytab krb os rcache posix
+
+##DOSBUILDTOP = ..\..
+##DOSLIBNAME=$(OUTPRE)krb5.lib
+##DOSOBJFILEDEP=$(OUTPRE)asn1.lst $(OUTPRE)ccache.lst $(OUTPRE)err_tbls.lst $(OUTPRE)keytab.lst $(OUTPRE)krb.lst $(OUTPRE)os.lst $(OUTPRE)posix.lst $(OUTPRE)rcache.lst $(OUTPRE)krb5.lst
+##DOSOBJFILELIST=@$(OUTPRE)asn1.lst @$(OUTPRE)ccache.lst @$(OUTPRE)err_tbls.lst @$(OUTPRE)keytab.lst @$(OUTPRE)krb.lst @$(OUTPRE)os.lst @$(OUTPRE)posix.lst @$(OUTPRE)rcache.lst @$(OUTPRE)krb5.lst
+##DOSOBJFILE=$(OUTPRE)krb5.lst
+##DOSLIBOBJS=$(OBJS)
+##DOSLOCALINCLUDES=-Iccache\ccapi -I..\..\windows\lib -Iccache -Ikeytab -Ircache -Ios
+
+TST=if test -n "`cat DONE`" ; then
+
+STLIBOBJS=krb5_libinit.o
+
+LIBBASE=krb5
+LIBMAJOR=3
+LIBMINOR=2
+LIBINITFUNC=profile_library_initializer krb5int_lib_init
+LIBFINIFUNC=profile_library_finalizer krb5int_lib_fini
+
+STOBJLISTS= \
+	OBJS.ST \
+	error_tables/OBJS.ST \
+	asn.1/OBJS.ST \
+	ccache/OBJS.ST \
+	keytab/OBJS.ST \
+	krb/OBJS.ST \
+	rcache/OBJS.ST \
+	os/OBJS.ST \
+	posix/OBJS.ST \
+	$(BUILDTOP)/util/profile/OBJS.ST
+
+SUBDIROBJLISTS= \
+	error_tables/OBJS.ST \
+	asn.1/OBJS.ST \
+	ccache/OBJS.ST \
+	keytab/OBJS.ST \
+	krb/OBJS.ST \
+	rcache/OBJS.ST \
+	os/OBJS.ST \
+	posix/OBJS.ST \
+	$(BUILDTOP)/util/profile/OBJS.ST
+
+OBJS=\
+	$(OUTPRE)krb5_libinit.$(OBJEXT)
+
+SRCS=\
+	$(srcdir)/krb5_libinit.c
+
+RELDIR=krb5
+SHLIB_EXPDEPS = \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
+SHLIB_EXPLIBS=-lk5crypto -lcom_err $(SUPPORT_LIB) @GEN_LIB@ $(LIBS)
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+all-unix:: all-liblinks
+
+all-windows::
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+clean-windows::
+	$(RM) $(OUTPRE)krb5.lib krb5.bak
+
+all-windows::
+	cd asn.1
+	@echo Making in krb5\asn.1
+	$(MAKE) -$(MFLAGS)
+	cd ..\ccache
+	@echo Making in krb5\ccache
+	$(MAKE) -$(MFLAGS)
+	cd ..\error_tables
+	@echo Making in krb5\error_tables
+	$(MAKE) -$(MFLAGS)
+	cd ..\keytab
+	@echo Making in krb5\keytab
+	$(MAKE) -$(MFLAGS)
+	cd ..\krb
+	@echo Making in krb5\krb
+	$(MAKE) -$(MFLAGS)
+	cd ..\os
+	@echo Making in krb5\os
+	$(MAKE) -$(MFLAGS)
+	cd ..\posix
+	@echo Making in krb5\posix
+	$(MAKE) -$(MFLAGS)
+	cd ..\rcache
+	@echo Making in krb5\rcache
+	$(MAKE) -$(MFLAGS)
+	cd ..
+
+clean-windows::
+	cd asn.1
+	@echo Making clean in krb5\asn.1
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\ccache
+	@echo Making clean in krb5\ccache
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\error_tables
+	@echo Making clean in krb5\error_tables
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\keytab
+	@echo Making clean in krb5\keytab
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\krb
+	@echo Making clean in krb5\krb
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\os
+	@echo Making clean in krb5\os
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\posix
+	@echo Making clean in krb5\posix
+	$(MAKE) -$(MFLAGS) clean
+	cd ..\rcache
+	@echo Making clean in krb5\rcache
+	$(MAKE) -$(MFLAGS) clean
+	cd ..
+	@echo Making clean locally
+
+install-unix:: install-libs
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+krb5_libinit.so krb5_libinit.po $(OUTPRE)krb5_libinit.$(OBJEXT): \
+  krb5_libinit.c $(BUILDTOP)/include/krb5/autoconf.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/krb5_err.h \
+  $(BUILDTOP)/include/kv5m_err.h $(BUILDTOP)/include/asn1_err.h \
+  $(BUILDTOP)/include/kdb5_err.h krb5_libinit.h $(srcdir)/ccache/cc-int.h \
+  $(srcdir)/keytab/kt-int.h $(srcdir)/rcache/rc-int.h \
+  $(srcdir)/os/os-proto.h
diff --git a/mechglue/src/lib/krb5/asn.1/.Sanitize b/mechglue/src/lib/krb5/asn.1/.Sanitize
new file mode 100644
index 000000000..d3b1ca973
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/.Sanitize
@@ -0,0 +1,59 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+.saberinit
+ChangeLog
+KRB5-asn.py
+Makefile.in
+asn1_decode.c
+asn1_decode.h
+asn1_encode.c
+asn1_encode.h
+asn1_get.c
+asn1_get.h
+asn1_k_decode.c
+asn1_k_decode.h
+asn1_k_encode.c
+asn1_k_encode.h
+asn1_make.c
+asn1_make.h
+asn1_misc.c
+asn1_misc.h
+asn1buf.c
+asn1buf.h
+asn1glue.h
+configure
+configure.in
+krb5_decode.c
+krb5_encode.c
+krbasn1.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/asn.1/.rconf b/mechglue/src/lib/krb5/asn.1/.rconf
new file mode 100644
index 000000000..abd941953
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/.rconf
@@ -0,0 +1,8 @@
+ignore KRB5-types.c
+ignore KRB5-types.h
+ignore KRB5-types.py
+ignore TAGS
+ignore KRB5.ph
+ignore Makefile.jtk
+ignore glue2.c
+ignore process.perl
diff --git a/mechglue/src/lib/krb5/asn.1/.saberinit b/mechglue/src/lib/krb5/asn.1/.saberinit
new file mode 100644
index 000000000..d14fddb66
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/.saberinit
@@ -0,0 +1,4 @@
+alias hex print (unsigned)
+setopt load_flags -I../include
+load -lisode
+alias reload load
diff --git a/mechglue/src/lib/krb5/asn.1/ChangeLog b/mechglue/src/lib/krb5/asn.1/ChangeLog
new file mode 100644
index 000000000..821b2a0a5
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/ChangeLog
@@ -0,0 +1,1293 @@
+2005-11-14  Jeffrey Altman <jaltman@mit.edu>
+
+	* krb5_decode.c, krb5_encode.c: include k5-int.h instead of krb5.h
+
+2005-10-03  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_get.c (asn1_get_tag_2): Patch from Zhihong Zhang to properly
+	handle tag numbers >= 30.
+
+2005-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1_encode.c (asn1_encode_generaltime): If gmtime_r returns int
+	instead of pointer, do the appropriate error checking.
+
+2004-12-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* asn1_decode.c (asn1_decode_generaltime): Fix memory leak when
+	time sent is "19700101000000Z".
+
+2004-08-31  Tom Yu  <tlyu@mit.edu>
+
+	* asn1buf.c: Fix denial-of-service bug.
+
+	* asn1buf.c:
+	* krb5_decode.c: Fix double-free vulnerabilities.
+
+2004-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1_encode.c (asn1_encode_generaltime): Fix memcpy argument to
+	actually be a pointer.
+	(asn1_encode_enumerated): Drop "const" from scalar argument type.
+	* asn1_encode.h (asn1_encode_integer, asn1_encode_enumerated,
+	asn1_encode_unsigned_integer, asn1_encode_octetstring,
+	asn1_encode_charstring, asn1_encode_printablestring,
+	asn1_encode_ia5string, asn1_encode_generaltime,
+	asn1_encode_generalstring): Drop "const" from scalar argument
+	types.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1_encode.c (asn1_encode_generaltime): Use gmtime_r if
+	available.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1_decode.c (asn1_decode_generaltime): If the input string is
+	the magic UNIX time zero, bypass all the arithmetic and return 0.
+	* asn1_encode.c (asn1_encode_generaltime): If the input time
+	value is the UNIX epoch, use a hardcoded string instead of doing
+	the math.
+
+2003-10-08  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_k_encode.c (asn1_encode_krb_saved_safe_body): New function;
+	kludge to insert a raw pre-encoded KRB-SAFE-BODY.
+
+	* asn1_k_encode.h (asn1_encode_krb_saved_safe_body): Add
+	prototype.
+
+	* krb5_decode.c (decode_krb5_safe_with_body): New function; saves
+	a copy of the encoding of the KRB-SAFE-BODY to avoid problems
+	caused by re-encoding it during verification.
+
+	* krb5_encode.c (encode_krb5_safe_with_body): New function;
+	re-encode a KRB-SAFE using a saved KRB-SAFE-BODY encoding, to
+	avoid trouble with re-encoding a KRB-SAFE-BODY.
+
+2003-07-22  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* asn1_k_decode.c (asn1_decode_etype_info2_entry_1_3): Decoder for
+	the broken 1.3 ASN.1 behavior for  etype_info2; see bug 1681.
+
+	* asn1_k_decode.h (asn1_decode_etype_info2): Add v1_3_behavior
+	flag for parsing the broken 1.3 behavior  of using an octetString
+	instead of generalString
+
+	* asn1_k_decode.c (asn1_decode_etype_info2_entry):  Expect etype_info2 as generalstring not octetstring
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-06-20  Sam Hartman  <hartmans@mit.edu>
+
+	* asn1_k_decode.h (asn1_decode_etype_info2): Prototype.  Also
+	deleted prototype for asn1_decode_etype_info_entry as that is not
+	used outside asn1_k_decode.c
+
+	* krb5_decode.c (decode_krb5_etype_info2): Call etype_info2 decoder
+
+	* asn1_k_decode.c (asn1_decode_etype_info_entry): Split out
+	etype_info2 and etype_info decoder  so we ignore tag 2 in the
+	heimdal encoder
+	(asn1_decode_etype_info2): new function
+
+2003-05-23  Sam Hartman  <hartmans@mit.edu>
+
+	* asn1_k_decode.c (asn1_decode_etype_info_entry): Fix logic error
+	that incorrectly set up s2kparams.data 
+
+2003-05-20  Ezra Peisach  <epeisach@bu.edu>
+
+	* asn1_k_encode.c (asn1_encode_krb_safe_body): Use
+	asn1_encode_unsigned_integer for sequence number.
+
+	* asn1_k_decode.c (asn1_decode_krb_safe_body): Use
+	asn1_decode_seqnum to decode sequence number.
+	
+
+2003-05-18  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_decode.c (asn1_decode_maybe_unsigned): New function; decode
+	negative 32-bit numbers into positive unsigned numbers for the
+	sake of backwards compatibility with old code.
+
+	* asn1_decode.h: Add prototype for asn1_decode_maybe_unsigned.
+
+	* asn1_k_decode.c (asn1_decode_seqnum): New function; wrapper
+	around asn1_decode_maybe_unsigned.
+
+	* asn1_k_decode.h: Add prototype for asn1_decode_seqnum.
+
+	* krb5_decode.c (decode_krb5_authenticator) 
+	(decode_krb5_ap_rep_enc_part, decode_krb5_enc_priv_part): Sequence
+	numbers are now unsigned.  Use asn1_decode_seqnum to handle
+	backwards compat with negative sequence numbers.
+
+	* krb5_encode.c (encode_krb5_authenticator) 
+	(encode_krb5_ap_rep_enc_part, encode_krb5_enc_priv_part): Sequence
+	numbers are now unsigned.
+
+2003-05-06  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5_decode.c (decode_krb5_etype_info2): New function; currently
+	the same code as decode_krb5_etype_info.  This means that we can
+	manage to accept s2kparams in etype_info which is wrong but
+	probably harmless.
+
+	* asn1_k_decode.c (asn1_decode_etype_info_entry): Add etype_info2
+	support 
+
+	* asn1_k_encode.c (asn1_encode_etype_info_entry):  Add support for
+	etype-info2 
+
+	* krb5_encode.c (encode_krb5_etype_info2): New function
+
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5_encode.c (encode_krb5_setpw_req): new function
+
+2003-04-13  Ezra Peisach  <epeisach@mit.edu>
+
+	* asn1_k_decode.c (asn1_decode_kdc_req_body): Fix memory leak if
+	optional server field is lacking,
+
+2003-03-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1_get.c (asn1_get_tag): Deleted.
+	(asn1_get_tag_2): Renamed from asn1_get_tag_indef, now uses a
+	pointer to taginfo rather than a bunch of pointer args.
+	(asn1_get_id, asn1_get_length): Folded into asn1_get_tag_2.
+	(asn1_get_sequence): Call asn1_get_tag_2.
+	* asn1_get.h (taginfo): New structure.
+	(asn1_get_tag_indef, asn1_get_tag, asn1_get_id, asn1_get_length):
+	Declarations deleted.
+	(asn1_get_tag_2): Declare.
+	* asn1_decode.c (setup): Declare only a taginfo variable.
+	(asn1class, construction, tagnum, length): New macros.
+	(tag): Call asn1_get_tag_2.
+	* asn1_k_decode.c (next_tag, get_eoc, apptag, end_sequence_of,
+	end_sequence_of_no_tagvars, asn1_decode_krb5_flags): Call
+	asn1_get_tag_2; if no error, copy out values into scalar
+	variables.
+	(asn1_decode_ticket): Call asn1_get_tag_2.
+	* asn1buf.c (asn1buf_skiptail): Call asn1_get_tag_2.
+	* krb5_decode.c (check_apptag, next_tag, get_eoc): Call
+	asn1_get_tag_2; if no error, copy out values into scalar
+	variables.
+	(decode_krb5_enc_kdc_rep_part): Call asn1_get_tag_2.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* asn1_k_decode.c (asn1_decode_sam_challenge_2_body): Add
+	unused_var declaration to cleanup warnings. Signed/unsigned fix as
+	well.
+
+2002-11-07  Ezra Peisach  <epeisach@bu.edu>
+
+	* asn1_k_encode.c (asn1_encode_sam_challenge_2): Test for error
+	returned from asn1buf_insert_oxtetstring and cleanup strctures
+	properly.
+
+	* asn1_k_decode.c (asn1_decode_sam_challenge_2_body): Change
+	sequence_of/end_sequence_of to use
+	sequence_of_no_tagvars/end_sequence_of_no_tagravs to avoid
+	shadowing variables.
+
+2002-11-07  Ezra Peisach  <epeisach@bu.edu>
+
+	* asn1_k_encode.c (add_optstring): Add optional string only if
+	length > 0.
+
+2002-11-05  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_encode.h (asn1_encode_oid):
+	* asn1_encode.c (asn1_encode_oid): New function.
+
+	* asn1_decode.h (asn1_decode_oid):
+	* asn1_decode.c (asn1_decode_oid): New function.
+
+2002-10-30  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* KRB5-asn.py: Fix definition for sam-pk-for-sad element.
+
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* KRB5-asn.py, asn1_k_decode.c, asn1_k_decode.h, asn1_k_encode.c,
+	asn1_k_encode.h, krb5_decode.c, krb5_encode.c: New functions,
+	prototypes, and ASN.1 definitions for the new hardware
+	preauthentication protocol.
+
+2002-07-02  Sam Hartman  <hartmans@mit.edu>
+
+	* asn1_encode.h: Document asn1_encode_enumerated
+
+	* asn1_encode.c (asn1_encode_enumerated): New function; split out
+	asn1_encode_integer's guts into asn1_encode_integer_interal and
+	add this function to add different universal tag for enumerated 
+
+	* krbasn1.h (ASN1_ENUMERATED): enumerated is universal 10
+
+2002-10-07  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_get.c (asn1_get_tag_indef): Stomp on asn1class,
+	construction, retlen, and indef, even if we've hit the end of the
+	buffer, to avoid passing uninitialized values around.
+
+	* asn1_k_decode.c: Reformat somewhat and add comments to demystify
+	things a little.
+	(opt_field): Fix to explicitly check for end of subbuf before
+	verifying the pre-fetched tag, which may have been stomped on by
+	asn1_get_tag_indef() encountering end-of-buffer.
+
+	* krb5_decode.c (opt_field, opt_lenfield): Fix to explicitly check
+	for end of subbuf before verifying the pre-fetched tag, which may
+	have been stomped on by asn1_get_tag_indef() encountering
+	end-of-buffer.
+
+2002-09-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1_decode.c, asn1_encode.c, asn1_get.c, asn1_get.h,
+	asn1_k_decode.c, asn1_k_encode.c, asn1_make.c, asn1_make.h,
+	asn1buf,c. asn1buf.h, krb5_decode.c, krb5_encode.c: Use prototype
+	style definitions for functions.  Avoid variable name "class".
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-24  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_encode.c (asn1_encode_generaltime): Remove call to
+	unix_time_to_msl_time(), as it's Mac OS 9 specific and was missed
+	in the previous change.
+
+2002-06-24 Alexandra Ellwood <lxs@mit.edu>
+
+	* asn1_encode.c: Removed unused Mac OS 9 code
+	[pullup from 1-2-2-branch]
+
+2000-06-24  Miro Jurisic  <meeroh@mit.edu>
+
+	* asn1_encode.c (asn1_encode_generaltime): Fixed the Mac code to
+	use the correct epoch.
+
+	* asn1_encode.c: Updated Utilities.h #include
+
+	[pullups from 1-2-2-branch]
+
+2002-06-24  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_get.c (asn1_get_length): Check for negative length.
+	[pullup from 1-2-2-branch]
+
+2002-04-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1buf.c (asn1buf_remove_octetstring,
+	asn1buf_remove_charstring): Fix bounds test for correctness in
+	overflow cases.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1_decode.c, asn1_decode.h, asn1_encode.h, asn1_get.h,
+	asn1_k_decode.h, asn1_k_encode.h, asn1_make.h, asn1_misc.h,
+	asn1buf.h: Make prototypes unconditional.
+
+2001-07-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* asn1_k_encode.c: (asn1_encode_predicted_sam_response): Use
+	asn1_encode_charstring() instead of asn1_decode_octetstring() for
+	krb5_data. (signed vs. unsigned)
+
+2001-06-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* asn1_k_decode.c (asn1_decode_predicted_sam_response): Use
+	asn1_decode_charstring() instead of asn1_decode_octetstring() to
+	decode krb5_data.
+
+2000-10-26  Tom Yu  <tlyu@mit.edu>
+
+	* asn1buf.c (asn1buf_sync): Add new arguments to include the full
+	complement of data about a prefetched tag, as well as to indicate
+	whether the prefetched tag or the surrounding sequence is of an
+	indefinite length.
+	(asn1buf_skiptail): Add new arguments to indicate whether the
+	prefetched tag is indefinite, as well as its length.  This
+	facilitates proper skipping of trailing garbage.
+	(asn1buf_remains): Add new argument to indicate whether the
+	surrounding encoding is indefinite.  Don't advance buf->next if an
+	EOC encoding is detected; the caller will do that.
+
+	* asn1buf.h: Update prototypes.
+
+	* asn1_get.c (asn1_get_tag_indef): Don't treat EOC encoding as
+	special anymore, since previous behavior was overloading the
+	tag number in a bad way.  Also, report a MISMATCH_INDEF error if
+	the tag encoding is for the forbidden primitive constructed
+	encoding.
+
+	* asn1_k_decode.c (next_tag): Call get_tag_indef() in order to get
+	information about whether the length is indefinite.  Don't check
+	the tag class and construction explicitly.
+	(get_eoc): New macro to get a tag and check if it is an EOC
+	encoding.
+	(get_field, opt_field): Move the check for the tag class and
+	construction to here.
+	(get_field_body, get_lenfield_body): Call get_eoc() instead of
+	next_tag() if we are decoding a constructed indefinite encoding.
+	(begin_structure): Use a different variable to indicate whether
+	the sequence is indefinite as opposed to whether an individual
+	field is indefinite.
+	(end_structure): Update to new calling convention of
+	asn1buf_sync().
+	(sequence_of): Rewrite significantly.
+	(sequence_of_common): Move the bulk of previous sequence_of()
+	macro to here.  Does not declare some variables that sequence_of()
+	declares.
+	(sequence_of_no_tagvars): Similar to sequence_of() macro but
+	declares different variables for the purpose of prefetching the
+	final tag.
+	(end_sequence_of_no_tagvars): Similar to end_sequence_of() macro
+	but uses variables declared by the sequence_of_no_tagvars() macro
+	to prefetch the final tag.
+	(asn1_decode_principal_name): Update for new asn1buf_remains()
+	calling convention.  Call sequence_of_no_tagvars(), etc. instead
+	of sequence_of(), etc. in order to not declare shadowing
+	block-local variables.
+	(decode_array_body): Update for new asn1buf_remains() calling
+	convention.
+	(asn1_decode_sequence_of_enctype): Update for new
+	asn1buf_remains() calling convention.
+
+	* krb5_decode.c (next_tag): Call get_tag_indef() in order to get
+	information about whether the length is indefinite.  Don't check
+	the tag class and construction explicitly.
+	(get_eoc): New macro to get a tag and check if it is an EOC
+	encoding.
+	(get_field, opt_field): Move the check for the tag class and
+	construction to here.
+	(get_field_body, get_lenfield_body): Call get_eoc() instead of
+	next_tag() if we are decoding a constructed indefinite encoding.
+	(begin_structure): Use a different variable to indicate whether
+	the sequence is indefinite as opposed to whether an individual
+	field is indefinite.
+	(end_structure): Update to new calling convention of
+	asn1buf_sync().
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* asn1buf.h: Lengths are now unsigned int for
+	asn1buf_ensure_space(), asn1buf_expand(), asn1buf_imbed(),
+	asn1buf_sync(), asn1buf_insert_octetstring(),
+	asn1buf_insert_charstring(), asn1_remove_octetstring(),
+	asn1buf_remove_charstring(),
+
+	* krb5_decode.c, krb5_encode.c: Length fields are unsigned ints. 
+	
+	* asn1_make.c, asn1_make.h: Prototypes changed to use an unsigned
+	int * in_len and retlen for: asn1_make_etag(), asn1_make_tag(),
+	asn1_make_sequence(), asn1_make_set(), asn1_make_string(),
+	asn1_make_length(), asn1_make_id().
+
+	* asn1_k_encode.h, asn1_k_encode.c: Change length fields to
+	unsigned ints for all functions.
+	(asn1_encode_etype_info_entry): Test for KRB5_ETYPE_NO_SALT
+	instead of -1.
+	
+	* asn1_k_decode.c (asn1_decode_etype_info_entry): Use a length of
+	KRB5_ETYPE_NO_SALT to indicate the optional salt not being
+	present. (instead of -1).
+	(setup): Length is now unsigned int.
+
+	* asn1_get.c, asn1_get.h: Change retlent to unsigned int * for
+	asn1_get_tag(), asn1_get_tag_indef(), asn1_get_sequence,
+	asn1_get_length().
+
+	* asn1_encode.c, asn1_encode.h: Change retlen to unsigned int *
+	for asn1_encode_integer(), asn1_encode_unsigned_integer(),
+	asn1_encode_octetstring(), asn1_encode_charstring(),
+	asn1_encode_printable_string(), asn1_encode_ia5string(),
+	asn1_encode_generaltime(), asn1_encode_generalstring()
+
+	* asn1_decode.c, asn1_decode.h: Change retlen to unsigned int *
+	for asn1_decode_octetstring(), asn1_decode_generalstring(),
+	asn1_decode_charstring(),
+
+2000-09-26  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_get.c (asn1_get_tag_indef): Fix to not deref random garbage
+	while checking for EOC encoding.  At least the indefinite decoding
+	breaks consistently now.
+
+2000-08-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* asn1_k_decode.c (asn1_decode_last_req_entry): Decode the lr_type
+	as an int32. Handle backwards compatibility if KRB5_GENEROUS_LR_TYPE
+	is defined. 
+
+	* krbasn1.h: Define KRB5_GENEROUS_LR_TYPE for compatibility with
+	one byte negative lr_types which are sent as a positive integer.
+
+2000-06-29  Tom Yu  <tlyu@mit.edu>
+
+	* asn1buf.h (asn1buf_insert_octet): Define using __inline__ rather
+	than inline in order to shut up gcc -pedantic.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* asn1_get.c (asn1_get_tag):  Remove unused variable.
+
+2000-02-06  Ken Raeburn  <raeburn@mit.edu>
+
+	Patches from Frank Cusack for helping in preauth replay
+	detection and spec (passwd-04 draft) compliance.
+	* asn1_k_decode.c (asn1_decode_enc_sam_response_enc): Update for
+	field name change.
+	(asn1_decode_predicted_sam_response): Handle new fields.
+	* asn1_k_encode.c (asn1_encode_enc_sam_response_enc): Update for
+	field name change.
+	(asn1_encode_predicted_sam_response): Handle new fields.
+
+2000-02-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* krb5_decode.c (krb5_decode_ticket): Add function to provide
+	decode_krb5_ticket functionality as part of krb5 API.
+
+1999-11-01  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_decode.c (begin_structure): Update to deal with indefinite
+	encodings better; also call asn1_get_sequence().
+
+	* asn1_k_decode.c (sequence_of): Update to deal with indefinite
+	encodings better.
+	(begin_structure): Update to deal with indefinite encodings
+	better; also call asn1_get_sequence().
+
+	* asn1_get.h: Update prototypes for asn1_get_tag_indef(),
+	asn1_get_tag(), asn1_get_sequence(), asn1_get_length().
+
+	* asn1_get.c (asn1_get_tag_indef): New function; get tag info,
+	lengths, etc. as well as flag indicating whether the length is
+	indefinite.
+	(asn1_get_tag): Modify to just call asn1_get_tag_indef().
+	(asn1_get_sequence): Call asn1_get_tag_indef() in order to
+	determine whether encoding is indefinite length.
+	(asn1_get_length): Add "indef" arg to indicate whether an encoding
+	has an indefinite length.
+
+	* asn1buf.h: Update asn1buf_imbed() prototype.
+
+	* asn1buf.c (asn1buf_imbed): Add "indef" arg so that we don't
+	treat a definite zero-length encoding as an indefinite encoding.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-10-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* asn1_decode.c (asn1_decode_integer): Initialize "n", to keep gcc
+	happy.
+
+Sat Jul 10 10:21:40 1999  Tom Yu  <chaoself@mit.edu>
+
+	* asn1_decode.c (asn1_decode_integer): Fix to deal with overflows
+ 	and negative integers.
+	(asn1_decode_unsigned_integer): Fix to deal with overflows and to
+ 	return errors on encountering negative integers.
+
+1999-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* KRB5-asn.py (PA-SAM-RESPONSE): Fix syntax error -- comma
+	separating sequence components doesn't belong buried in a
+	comment.
+
+1999-07-03  Tom Yu  <tlyu@mit.edu>
+
+	* asn1buf.c (asn1buf_sync): Add length parameter to disambiguate
+	constructed-indefinite encoding from constructed-definite encoding
+	which happens to end at the same place as the enclosing buf.
+
+	* asn1buf.h: Update to match definition.
+
+	* krb5_decode.c (end_structure): Update to deal with additional
+	length parameter to asn1buf_sync().
+
+	* asn1_k_decode.c (end_sequence_of, end_structure): Update to deal
+	with additional length parameter to asn1buf_sync().
+
+	* asn1buf.h: New prototpyes for asn1buf_sync() and
+	asn1buf_skiptail().
+
+	* asn1buf.c (asn1buf_sync): Fix to deal with
+	constructed-indefinite encodings with trailing fields.  As a
+	result, this requires that the most recently read tag number be
+	passed in.
+	(asn1buf_skiptail): New helper function to skip trailing fields in
+	a constructed-indefinite encoding.
+
+	* krb5_decode.c (end_structure): Hack to deal with changed
+	asn1buf_sync().
+
+	* asn1_k_decode.c (end_structure, end_sequence_of): Hack to deal
+	with changed asn1buf_sync().
+
+1999-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* asn1buf.c (asn1buf_sync): Interim fix for DCE compat problem
+	with indefinite length encodings.
+
+1999-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_encode.c (asn1_encode_generaltime): Fix minor bug in
+	bounds-checking for tm_year: 1900 + 8099 = 9999.
+
+Mon May 10 15:23:51 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Thu Dec  3 19:41:06 1998  Tom Yu  <tlyu@mit.edu>
+
+
+	* asn1_k_decode.c (asn1_decode_krb5_flags): Fix previous to
+	properly left-justify bit strings less than 32 bits.
+
+	* asn1_k_decode.c (asn1_decode_krb5_flags): Modify to deal with
+	BIT STRING values that are not exactly 32 bits.  Throw away bits
+	beyond number 31 in a bit string for now.  Deal with masking out
+	unused bits.
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* asn1buf.c (asn1buf_sync): interoperation testing against heimdal
+	revealed a bug.  if extra fields are present in a SEQUENCE, they
+	are not ignored and skipped.  This caused the decoder to get out
+	of sync.
+
+Thu Jul  2 15:30:25 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* asn1_encode.c: Make the magic Macintosh EPOCH offset be 70 years
+ 		instead of 66 years, since CodeWarrior Pro 2 now bases
+ 		everything off of 1900.
+
+Thu Apr 16 17:01:27 1998  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_encode.c (asn1_encode_generaltime): Sanity check the return
+	from gmtime() to avoid overruns.
+
+Fri Feb 27 18:03:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/krb5
+ 		directory, since we've moved the configure.in tests in
+ 		this directory to the toplevel lib/krb5 configure.in
+
+Wed Feb 18 16:18:46 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 22:32:06 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* asn1buf.h (asn1buf_insert_octet): Use static inline function to
+		define asn1_insert_octet, since the GCC specific hack
+		we're using doesn't work on GCC compilers that also have 
+		Objective C enabled.
+
+	* asn1buf.c: define ASN1BUF_OMIT_INLINE_FUNCS before including
+		asn1buf.h, since we don't want inline functions declared
+		when we're defining the linkable version of the functions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jan  2 21:18:30 1998  Tom Yu  <tlyu@mit.edu>
+
+	* asn1buf.c (asn12krb5_buf): Check return value of
+	malloc. [krb5-libs/518]
+
+Tue Sep 30 19:03:34 1997  Tom Yu  <tlyu@mit.edu>
+
+	* krbasn1.h: Replace HAS_STDLIB_H with something more sane.
+
+Thu Jul 31 15:38:10 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+        * asn1buf.h (asn1buf_remove_octet, asn1buf_size, asn1buf_free,
+        asn1buf_ensure_space, asn1buf_len): Add macro versions.
+        (asn1buf_insert_octet) [__GNUC__ >= 2]: Ditto, using a GNU C
+        extension.
+        * asn1buf.c (asn1buf_remove_octet, asn1buf_size, asn1buf_free,
+        asn1buf_ensure_space, asn1buf_len, asn1buf_insert_octet): Undef
+        macros before defining as functions.
+	[Kerbnet changes made by raeburn@cygnus.com]
+
+Thu Jul 31 12:34:43 1997  Ezra Peisach  <epeisach@mit.edu>
+
+        * asn1buf.h (asn1buf_expand): Remove "const" from int arg in
+        prototype.
+
+        * asn1buf.c (asn1buf_remove_charstring, asn1buf_create,
+        asn1buf_remove_octetstring, asn12krb5_buf): Call malloc instead of
+        calloc.
+        (asn1buf_unparse, asn1buf_hex_unparse): Ditto.  Also don't
+        allocate extra byte, since sizeof(STRING) does count the trailing
+        null.
+        (asn1buf_expand): Adjust bound based on increment 
+        value used, not value specified by caller.
+
+	[Kerbnet changes made by raeburn@cygnus.com]
+
+Thu Jul 31 11:17:06 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add / after $(srcdir) in SRCS line.
+
+Sat Feb 22 22:13:35 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+Thu Jan  2 16:56:10 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Thu Nov 14 20:57:55 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* asn1_k_encode.c (asn1_encode_principal_name): Be liberal about
+		accepting a principal with a zero-length component where
+		the data pointer is NULL.  After all,
+		asn1_decode_principal_name generates them that way! [PR#188]
+		(asn1_encode_encrypted_data): 
+		(asn1_encode_krb5_authdata_elt): 
+		(asn1_encode_encryption_key): 
+		(asn1_encode_checksum): 
+		(asn1_encode_realm): If the length is zero, allow the data
+				field to be NULL.
+
+Thu Jun 27 10:31:34 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* asn1buf.c (asn12krb5_buf): Initialize magic fields of structure. 
+	(asn1buf_expand): If pre-allocating memory for future use, store
+		proper end of buffer.
+
+Wed Jun 12 14:25:11 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* asn1_k_encode.h, asn1_k_decode.h: Add prototypes for the SAM
+	 	encoding and decoding functions, which are necessary for
+	 	the Win32 port (and a good idea in general).
+
+Wed Jun  5 15:37:50 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* asn1_k_decode.c (asn1_decode_enc_kdc_rep_part): If starttime is
+		not sent over the wire, set equal to authtime.
+
+Thu May  2 21:59:23 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5_decode.c (decode_krb5_enc_tkt_part): use tagnum correctly
+	to handle optional starttime (previous code *always* replaced
+	starttime with authtime.)
+
+Tue Apr  9 22:51:36 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5_decode.c (decode_krb5_sam_challenge,
+	decode_krb5_enc_sam_key, decode_krb5_enc_sam_response_enc,
+	decode_krb5_sam_response, decode_krb5_predicted_sam_response):
+	Change to new indirect interface.
+
+	* asn1_k_decode.c (opt_encfield): macro for handling optional
+	encrypted_data fields (see asn1_decode_kdc_req_body for original
+	version.) 
+	(asn1_decode_sam_response): use opt_encfield, since we're making
+	sam_enc_key optional (as it is reserved for future use.)
+	* asn1_k_encode.c (asn1_encode_sam_response): check sam_enc_key
+	for content before adding it.
+	* KRB5-asn.py: note sam-enc-key as OPTIONAL regardless of future
+	plans.
+
+Wed Mar 20 22:43:17 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* asn1_k_decode.c: Decode pa_type in the krb5_pa_data structure as
+		a krb5_int32, since it is now type krb5_preauthtype.
+		(asn1_decode_etype_info_entry): Decode etype in the
+		krb5_etype_info_entry as krb5_enctype.
+
+	* krb5_decode.c (decode_krb5_pa_enc_ts): Fix 16 bit vs. 32bit
+		error in the encoded timestamp structure.
+
+Wed Mar 13 12:52:32 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5_decode.c (decode_krb5_ticket, decode_krb5_enc_tkt_part,
+		decode_krb5_authenticator, decode_krb5_error,
+		decode_krb5_ap_req, decode_krb5_ap_rep,
+		decode_krb5_ap_rep_enc_part, decode_krb5_safe, 
+		decode_krb5_priv, decode_krb5_enc_priv_part,
+		decode_krb5_cred, decode_krb5_enc_part): Add magic values.
+
+	* asn1_k_decode.c (asn1_decode_passwdsequence): Set magic values
+		     in structures.
+		(asn1_decode_kdc_req_body): Set magic in
+		     authorization_data if not sent OTW.
+
+Tue Feb 27 19:23:55 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_decode.c (decode_krb5_enc_tkt_part): If starttime is not
+		set, then use authtime as a default.  (This fixes the bug
+		where if you try to immediately use a TGT to get a ticket,
+		you get a time skew error.)
+
+Wed Feb  7 00:23:18 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Wed Nov  8 20:00:13 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* asn1_k_decode.c (asn1_decode_etype_info_entry): If the optional
+		salt element is not present, set etype.length to -1.
+
+	* asn1_k_encode.c (asn1_encode_etype_info_entry): When encoding
+		the etype_info_entry structure, use length == -1 to mean
+		that the optional salt structure should not be sent.  (It
+		used to be if length == -1.)
+
+Tue Oct 31 20:06:49 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_decode.c (decode_krb5_pa_enc_ts, decode_krb5_enc_data):
+	        Added new functions.
+
+	* krb5_encode.c (encode_krb5_pa_enc_ts, encode_krb5_enc_data):
+	        Added new functions.
+
+	* KRB5-asn.py (PA-ENC-TS-ENC): Added new definition for the
+		krb5_pa_enc_ts structure.
+
+Fri Oct  6 22:03:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Thu Sep 28 23:35:06 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* krb5_encode.c (krb5_cleanup): If asn1buf_destroy fails, don't
+	call it again. (Not that it can ever fail anyhow.)
+
+Tue Sep 26 19:59:56 1995    <tytso@rsts-11.mit.edu>
+
+	* krb5_decode.c: Systematic rework of all the cleanup code to make
+		the generated object file subtatially (40% on the i386
+		platform) smaller.  The cleanup is now handled with a
+		"goto error_out" statement, which prevents the cleanup
+		statements from being replicated many, many, many times
+		throughout the entire file.
+
+Mon Sep 25 16:56:13 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Fri Sep 22 22:27:33 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* asn1_k_decode.c (asn1_decode_etype_info_entry): 
+	* krb5_decode.c (decode_krb5_alt_method): Remove the (int) cast,
+		since you can't take address of a value which has been
+		casted.  Instead we change the underlying type in the
+		structure to be an int.
+
+Wed Sep 13 10:51:31 1995 Keith Vetter (keithv@fusion.com)
+
+        * asn1_k_decode.c, asn1_k_encode.c, krb5_dec.c, krb5_enc.c: 32
+		bit word being passed as an int.
+
+Wed Sep 20 11:50:35 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5_decode.c (setup_buf_only): Declare cleanup routine as
+		void and propogate through file.
+
+Mon Sep 18 14:17:15 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* asn1_encode.c (asn1_encode_generaltime): Don't modify a const
+		input variable val; copy it to a scratch variable and
+		modify that.
+
+Wed Sep 13 19:53:30 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5_decode.c (clean_krb5_authenticator, clean_krb5_ticket,
+	clean_krb5_enc_tkt_part,clean_krb5_ap_req,
+	clean_krb5_ap_rep_enc_part, clean_krb5_safe,
+	clean_krb5_priv_enc_part, clean_krb5_cred_enc_part,
+	clean_krb5_error): new static functions to free objects that may
+	be partially constructed.
+	(setup_buf_only, setup_no_tagnum, setup_no_length, setup): define
+	in terms of each other to remove duplication, then add local
+	variable error_cleanup to common declarations.
+	(clean_return): new macro, uses error_cleanup on rep if possible
+	and the allows the argument to be returned.
+	(alloc_field, check_apptag, next_tag, begin_structure,
+	get_field_body, get_field, get_lenfield_body, get_lenfield): use
+	clean_return. 
+	(free_field): new macro to simplify the writing of clean_*.
+	(clear_field): macro to clean up preparation of fields for later
+	use by clean_* functions.
+	(decode_krb5_authenticator, decode_krb5_ticket,
+	decode_krb5_encryption_key, decode_krb5_enc_tkt_part, 
+	decode_krb5_enc_kdc_rep_part, decode_krb5_as_rep,
+	decode_krb5_tgs_rep, decode_krb5_ap_req, decode_krb5_ap_rep,
+	decode_krb5_ap_rep_enc_part, decode_krb5_as_req,
+	decode_krb5_tgs_req, decode_krb5_kdc_req_body, decode_krb5_safe,
+	decode_krb5_priv, decode_krb5_enc_priv_part, decode_krb5_cred,
+	decode_krb5_enc_cred_part, decode_krb5_error,
+	decode_krb5_authdata, decode_krb5_pwd_sequence,
+	decode_krb5_pwd_data, decode_krb5_padata_sequence,
+	decode_krb5_alt_method, decode_krb5_etype_info): change setup
+	macro to pass a cleanup method (or just free if there were no
+	partial allocations, or 0 for the two cases with no allocation at
+	all.) Also explicitly zero pointer subfields, since calloc is not
+	a safe way to assure that. Generally, provide for automatic
+	deallocation of storage on error.
+	
+Sun Sep 10 12:00:00 1995    <mattly@fusion.com>
+
+	* asn1_encode.c: Removed use of localtime for encoding of generaltime.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * asn1_k_decode.c, asn1_k_decode.h, asn1_k_encode.c, asn1_k_encode.h,
+	* krb5_decode.c, krb5_encode.c: s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Wed Sept 6 12:00:00 1995    <mattly@fusion.com>
+
+	* asn1_encode.c: added EPOCH to account for macintosh time keeping
+		differences in asn1_encode_generaltime.
+
+	* asn1buf.c: removed some debugging cruft.
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * asn1_k_decode.c, asn1_k_decode.h, asn1_k_encode.c, asn1_k_encode.h
+	* krb5_decode.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate
+  
+Mon Aug 28 12:54:05 1995    <tytso@rsts-11.mit.edu>
+
+	* krb5_decode.c (decode_krb5_alt_method,
+		decode_krb5_etype_info): New functions for
+		decoding some new data structures.
+
+	* krb5_encode.c (encode_krb5_alt_method, encode_krb5_etype_info):
+		New functions for encoding some new data structures.
+
+	* asn1_k_decode.c (asn1_decode_etype_info_entry,
+		asn1_decode_etype_info): Added new functions to decode 
+		some new data structures.
+
+	* asn1_k_encode.c (asn1_encode_etype_info_entry,
+		asn1_encode_etype_info): Added new functions to encode
+		some new data structures.
+
+Fri Aug 25 21:43:42 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_encode.c (encode_krb5_padata_sequence): New function which
+		encodes a sequence of pa_data elements
+
+	* krb5_decode.c (decode_krb5_padata_sequence): New function which
+		decodes a sequence of pa_data elements.
+
+	* asn1_k_encode.c (asn1_encode_sequence_of_pa_data): Make it
+		possible to encode sequence of zero pa_data elements.
+
+	* asn1_k_decode.c (decode_array_body): Make it possible to decode
+		SEQUENCE OF encodinges of zero items (which is legal
+		according to ASN.1)
+
+Sat Jun 17 00:00:33 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* asn1_get.c (asn1_get_tag): Added change to allow for 
+		ASN.1 indefinite encoding; needed for DCE compatibility.
+
+Fri Jun  9 19:34:05 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Fri May 26 20:19:15 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for building shared libraries.
+
+Tue May 23 16:22:57 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* asn1_decode.c: Rearrange #include files so that krb5.h gets
+		included first, so that the debugging information can be
+		more efficiently collapsed since the type numbers will be
+		the same.
+
+	* asn1_encode.h: Rearrange the #include files so that the type
+		numbers are the same.
+
+Thu Apr 13 20:13:38 1995 Keith Vetter (keithv@fusion.com)
+
+	* asn1_k_decode.c: fixed up 'unreferenced local variable' problems.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+
+Wed Mar 22 09:39:55 1995    <tytso@rsx-11.mit.edu>
+
+	* asn1_k_decode.c (setup, next_tag, apptag, get_field_body,
+		get_lenfield_body, asn1_decode_ticket): Use the
+		taglength to determine whether or not the indefinite
+		encoding was used, and if so skip over the termination
+		flag bytes in the ASN.1 stream.
+
+	* asn1buf.c (asn1buf_imbed, asn1buf_remains): Make changes to
+		allow for indefinite encodings.  asn1buf_remains() is now
+		only used for decoding structures and arrays (i.e., asn.1
+		constructs which terminate indefinite encodings with two
+		zero octets.
+
+		[ Note these fixes to support indefinite encoding
+		aren't terribly clean; some invalid encodings may
+		be accepted when they should not be.  This should be
+		looked at in more detail later.]
+
+	* asn1_get.c (asn1_get_tag): Inline original asn1buf_remains()
+		code, since asn1_get_tag doesn't use asn1buf_remains in
+		the context of a structure or an array.
+
+Sat Mar 25 14:12:31 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* asn1_decode.c: move declaration of gmt_mktime() outside of
+	asn1_decode_generaltime() so that compilers like Ultrix cc that
+	don't support prototypes within function bodies don't break
+
+Fri Mar 17 19:05:22 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in:  Remove redundant definitions from config/pre.in
+	(clean-mac):  Add.
+	* asn1_misc.c:  Avoid <malloc.h> and <memory.h> includes, for Mac.
+	(asn1_krb5_realm_copy):  Use malloc, not calloc, since we're
+	about to clobber the storage anyway.
+	* configure.in (WITH_KRB5ROOT):  Remove, not needed.
+	* krbasn1.h:  Document that <limits.h> is needed for INT_MAX.
+
+Fri Mar 10 15:39:24 1995  Theodore Y. Ts'o  (tytso@kenmore)
+
+	* asn1buf.c. asn1buf.h (asn1buf_insert_octet): Make the second
+		argument of asn1buf_insert_octet be an int, instead of
+		asn1_octet.  ANSI C narrow types screws us again....
+
+Tue Mar 7 21:40:18 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed library name for the PC.
+
+Wed Mar 1 18:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* asn1_decode.c, asn1_encode.c, ans1_k_encode.c, asn1_misc.c: 16 vs 
+	   32 bit casts.
+	* asn1_k_encode.h: added missing INTERFACE to a prototype
+
+Tue Feb 28 00:32:48 1995  John Gilmore  (gnu at toad.com)
+
+	* asn1_decode.h, asn1_encode.h, asn1_get.h, asn1_k_decode.h,
+	asn1_k_encode.h, asn1_make.h asn1_misc.h, asn1_buf.h, glue2.c,
+	krb5_decode.c, krb5_encode.c, krbasn1.h:  Avoid <krb5/...> includes.
+
+Tue Feb 21 12:00:00 1995  Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work for the PC
+	* *.c, *.h: added windows INTERFACE keyword to all functions
+
+Tue Feb 21 20:11:30 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* asn1_k_decode.h(asn1_decode_kvno, asn1_decode_krb_safe_body):
+		Removed duplicate declarations.
+
+	* asn1_k_decode.h(asn1_decode_passwdsequence, 
+		asn1_decode_sequence_of_passwdsequence): Added missing
+		declarations.
+
+Thu Feb 16 19:29:59 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* asn1_k_encode.h(asn1_encode_enc_kdc_rep_part): Remove duplicate
+		declaration of asn1_encode_enc_kdc_rep_part.
+
+Fri Feb 10 15:30:45 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* asn1_k_encode.c: Remove #include of krb5_encode.h (it's not
+	        needed).
+
+	* krb5_encode.h:
+	* krb5_decode.h: These files removed; their contents have been
+		poured into include/krb5/asn1.h.
+
+	* Makefile.isode.in: Removed.
+
+	* process.perl: Removed (isode cruft).
+
+	* Makefile.sane.in: Removed; contents moved to Makefile.in
+
+	* configure.in: 
+	* Makefile.in: Removed isode croft.  (Makefile.in was
+		Makefile.sane.in) 
+
+Fri Feb  3 01:02:43 1995  John Gilmore  <gnu@cygnus.com>
+
+	* asn1_decode_k.c => asn1_k_decode.c
+	* asn1_decode_k.h => asn1_k_decode.h
+	* asn1_encode_k.c => asn1_k_encode.c
+	* asn1_encode_k.h => asn1_k_encode.h
+	* Makefile.sane.in, krb5_decode.c, krb5_encode.c,
+	asn1_k_encode.c, asn1_k_decode.c:  updated to match.
+
+Fri Nov 18 16:24:35 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_decode.c (decode_krb5_encryption_key): Add magic number to
+		keyblock structure.
+
+Thu Nov 10 21:51:55 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* asn1_decode_k.c (asn1_decode_principal_name,
+		asn1_decode_checksum, asn1_decode_encrypted_data,
+		asn1_decode_transited_encoding,
+		asn1_decode_enc_kdc_rep_part, asn1_decode_ticket,
+		asn1_decode_kdc_req, asn1_decode_kdc_req_body,
+		asn1_decode_safe_body, asn1_decode_host_address,
+		asn1_decode_kdc_rep, asn1_decode_authdata_elt,
+		asn1_decode_krb_cred_info, asn1_decode_pa_data,
+		asn1_decode_last_req_entry): Initialize magic number field
+		in the relevant structures.
+
+	* asn1_decode_k.c (asn1_decode_encryption_key): Add appropriate
+		magic number and encryption type.
+
+Wed Nov  2 23:10:36 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add WITH_CPPOPTS since we're not using
+		CONFIG_RULES (yet).
+
+Thu Oct 27 22:32:13 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.sane.in: Remove duplicate definitions for DEFS, CC,
+		CCOPTS, and LIBS.  (now defined in config/pre.in).
+
+Wed Oct 19 10:51:16 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* err2kerr.c (KRB5_KRB__ERROR2krb5_error): The e_data field
+		wasn't being decoded when it should have been.
+
+	* qbuf2data.c (qbuf2krb5_data): Set magic number field to zero.
+
+	* asn1_decode_k.c (asn1_decode_kdc_req_body): If the authorization
+		field is not present, fill in the authorization data
+		fields with all zeros.  Don't set kvno (that's *key*
+		version number, not *Kerberos* version number) to 5.
+
+Tue Oct 18 23:07:20 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* tgrq2ktgrq.c (KRB5_KDC__REQ__BODY2krb5_kdc_req): Allow the
+		service principal to be optional.
+
+	* ktgrq2tgrq.c (krb5_kdc_req2KRB5_KDC__REQ__BODY): Allow the
+		server principal to be optional.
+
+Fri Oct  7 15:05:35 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.isode.in: Add -DKRB5_USE_ISODE so that include files
+		are right.
+
+Tue Oct  4 16:13:45 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* asn1_decode_k.c (asn1_decode_kerberos_time): Don't assume that
+		  krb5_timestamp and time_t are the same.
+
+Thu Sep 29 14:26:34 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* asn1buf.c (asn1buf_remove_octetstring, asn1buf_remove_charstring): 
+		If the length is zero, don't call calloc(0,1); instead
+		return a NULL pointer.  This way, we get consistent
+		behavior even on systems where malloc(0) returns a
+		non-null pointer.
+
+Tue Sep 27 23:31:50 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_encode.c (encode_krb5_enc_kdc_rep_part): = should have been
+	        == in commented-out code.  Get it right for the future...
+
+Wed Sep 21 00:18:12 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_decode.c (decode_krb5_authdata): Initialize variable where
+		the authdata is returned to NULL first.  (Caller shouldn't
+		have to do this.)
+
+	* asn1_decode.c (asn1_decode_generaltime): Plug memory leak caused
+		by not freeing temporary string.
+
+Wed Aug 17 16:07:06 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* krb5_encode.c (encode_krb5_enc_kdc_rep_part): Older versions of
+	the Kerberos are always sending the enc_kdc_rep_part structure
+	with an application tag of #26, instead of using the application
+	tag of #25 (AS REP) or #26 (AS REP) as necessary.  Worse yet, they
+	will only accept a tag of #26, so we need to follow this for
+	backwards compatibility.  #defining KRB5_ENCKRB5KDCREPPART_COMPAT
+	will preserve this wrong (but compatible) behavior.
+
+	* krb5_decode.c (decode_krb5_enc_kdc_rep_part): Record the tag
+	value of the ASN.1 sequence in the rkb5_enc_kdc_rep structure.
+	Allow both tag #25 and #26 (although old software was always
+	sending tag #26).
+
+	* krb5_decode.c (decode_krb5_as_rep, decode_krb5_tgs_rep,
+	decode_krb5_ap_req, decode_krb5_ap_rep, decode_krb5_as_req,
+	decode_krb5_tgs_req, decode_krb5_safe, decode_krb5_priv,
+	decode_krb5_cred, decode_krb5_error): Only check the ASN.1 message
+	type if KRB5_MSGTYPE_STRICT is defined.  "Be strict in what you
+	send out, liberal in what you receive..."
+
+	* asn1_decode_k.c (asn1_decode_msgtype): Stop checking the
+	validity of the message type here.  Each routine that calls
+	asn1_decode_msgtype is checking the message type anyway, so it's
+	just duplicated effort.
+
+Sat Aug 13 03:40:16 1994  Mark Eichin  (eichin@perdiem)
+
+	* krbasn1.h: include stdlib.h for calloc declaration (if we can)
+
+Thu Aug 11 00:38:10 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* asn1_encode_k.c (asn1_encode_kdc_req): Add extra argument which
+	specifies the msg_type of the encoding; don't use req->msg_type
+	which is generally not set right.  (That output is only as a place
+	to stash the msg_type from decode).  All callers updated.
+
+	* asn1_encode_k.c (asn1_encode_kdc_rep): Add extra argument which
+	specifies the msg_type of the encoding; don't use rep->msg_type
+	which is generally not set right.  (That output is only as a place
+	to stash the msg_type from decode).  All callers updated.
+
+	* asn1_encode_k.c (asn1_encode_msgtype): Routine removed.  Not
+	really necessary, since a msg_type is really just an integer.  
+
+
+Thu Aug  4 13:19:14 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* asn1_decode_k.c (asn1_decode_sequence_of_enctype): fix typo
+
+Tue Aug  2 07:22:57 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* asn1_decode_k.c (asn1_decode_sequence_of_enctype): more fixing
+	of realloc(NULL) returning NULL
+
+Sat Jul 23 08:48:18 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* asn1buf.h: include ext-proto.h now to avoid type warnings
+
+Sat Jul 16 00:19:18 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* asn1_encode_k.c (asn1_encode_transited_encoding): whoops don't
+	bomb if val->tr_contents.dlength == 0
+
+	* asn1_decode_k.c (asn1_decode_encrypted_data): oops looks like
+	Harry made a brain fart here.... default value for kvno was 5, not
+	0.
+
+Thu Jul 14 11:37:59 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* asn1_*.[ch]: 
+	* krb5_*.[ch]: Add MIT Copyright notices.
+
+Thu Jul 14 01:26:22 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* asn1_encode_k.c (asn1_encode_pa_data): oops still check NULL if
+	length != 0
+
+Sat Jul  9 00:26:48 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* asn1_encode_k.c (asn1_encode_pa_data): the contents field of a
+	krb5_pa_data structure can be NULL (e.g.
+	salt_type==KRB5_KDB_SALTTYPE_V4), and the encoder was treating
+	this as a missing required field
+
+Fri Jul  8 17:32:29 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* asn1_decode_k.c: yet another instance of the SunOS realloc bug
+
+	* asn1buf.c: whee SunOS realloc of a NULL pointer returns NULL.
+	sigh.
+
+Wed Jul  6 13:21:35 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* an1buf.c: Harry saves vs. Unix again.  Making sure that anything
+	that can call calloc with a zero argument won't return ENOMEM if
+	calloc retuns NULL in this case.  This was prompted by breakage
+	under linux.
+
+	* asn1_encode.c (asn1_encode_generaltime): don't use strftime on
+	the output of gmtime -- under Solaris, it mutates it! (seems to be
+	doing a timezone offset.) Besides, sprintf is quite sufficient.
+	Also rename local variable time to gtime to avoid name collision.
+	(asn1_decode_generaltime): the fixed-point method below doesn't
+	actually work because it doesn't handle the current timezone
+	offset. Simpler, and more general -- always call gmt_mktime, which
+	is now provided in lib/krb5/os/gmt_mktime.c.
+
+Sun Jul  3 04:43:42 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* asn1_encode_k.h:
+	* asn1buf.c:
+	* krbasn1.h: punt stdlib.h in favor of stdio.h.  It looks like
+	Harry was assuming that NULL gets defined in stdlib instead of
+	stdio
+
+Fri Jul  1 13:03:39 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* asn1_encode_k.c (asn1_encode_msgtype): comment out krb5_msgtype
+	decl of val arg, use int (to match prototype in header.) Throw out
+	OLDDECLARG, DECLARG, and use old-style definition to match style
+	of the rest of the code.
+	(asn1_encode_ui_4): comment out krb5_ui_4 decl of val arg, use int
+	(to match prototype in header.) Also rewrote definition header.
+
+	* asn1_decode.c (asn1_decode_generaltime): tm_gmtoff is *not* in
+	System V either. The only portable way to find the delta is to
+	subtract gmtime from localtime at a fixed point (epoch+24hours is
+	an easy way to simplify the arithmetic.)
+	HAVE_GMTOFF: might someday be defined, but for now merely labels
+	what the code original did/was intended to do.
+
+	* configure.in: redo "autoconf frobbage" since the old way didn't
+	work with srcdir. Now, AC_OUTPUT generates all three Makefiles,
+	and ISODEMAKEFILE is subst'ed in to be either Makefile.isode or
+	Makefile.sane. EXTRA_RULES_IN is used to append the extra stuff to
+	the end of the "real" one of the two.
+	* configure.in: krb5_encode.h and krb5_encode.h are source, not
+	generated, so use CopySrcHeader instead.
+
+
+Tue Jun 28 19:57:28 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in:
+	* Makefile.in: autoconf frobbage
+
diff --git a/mechglue/src/lib/krb5/asn.1/KRB5-asn.py b/mechglue/src/lib/krb5/asn.1/KRB5-asn.py
new file mode 100644
index 000000000..e455fd9a1
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/KRB5-asn.py
@@ -0,0 +1,436 @@
+-- lib/krb5/asn.1/KRB5-asn.py
+--
+-- Copyright 1989 by the Massachusetts Institute of Technology.
+--
+-- Export of this software from the United States of America may
+--   require a specific license from the United States Government.
+--   It is the responsibility of any person or organization contemplating
+--   export to obtain such a license before exporting.
+-- 
+-- WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+-- distribute this software and its documentation for any purpose and
+-- without fee is hereby granted, provided that the above copyright
+-- notice appear in all copies and that both that copyright notice and
+-- this permission notice appear in supporting documentation, and that
+-- the name of M.I.T. not be used in advertising or publicity pertaining
+-- to distribution of the software without specific, written prior
+-- permission.  Furthermore if you modify this software you must label
+-- your software as modified software and not distribute it in such a
+-- fashion that it might be confused with the original M.I.T. software.
+-- M.I.T. makes no representations about the suitability of
+-- this software for any purpose.  It is provided "as is" without express
+-- or implied warranty.
+--
+-- ASN.1 definitions for the kerberos network objects
+--
+-- Do not change the order of any structure containing some
+-- element_KRB5_xx unless the corresponding translation code is also
+-- changed.
+--
+
+KRB5 DEFINITIONS ::=
+BEGIN
+
+-- needed to do the Right Thing with pepsy; this isn't a valid ASN.1
+-- token, however.
+
+SECTIONS encode decode none
+
+-- the order of stuff in this file matches the order in the draft RFC
+
+Realm ::= GeneralString
+
+HostAddress ::= SEQUENCE  {
+	addr-type[0]			INTEGER,
+	address[1]			OCTET STRING
+}
+
+HostAddresses ::=	SEQUENCE OF SEQUENCE {
+	addr-type[0]	INTEGER,
+	address[1]	OCTET STRING
+}
+
+AuthorizationData ::=	SEQUENCE OF SEQUENCE {
+	ad-type[0]	INTEGER,
+	ad-data[1]	OCTET STRING
+}
+
+KDCOptions ::= BIT STRING {
+	reserved(0),
+	forwardable(1),
+	forwarded(2),
+	proxiable(3),
+	proxy(4),
+	allow-postdate(5),
+	postdated(6),
+	unused7(7),
+	renewable(8),
+	unused9(9),
+	renewable-ok(27),
+	enc-tkt-in-skey(28),
+	renew(30),
+	validate(31)
+}
+
+LastReq ::=	SEQUENCE OF SEQUENCE {
+	lr-type[0]	INTEGER,
+	lr-value[1]	KerberosTime
+}
+
+KerberosTime ::=	GeneralizedTime -- Specifying UTC time zone (Z)
+
+PrincipalName ::= SEQUENCE{
+	name-type[0]	INTEGER,
+	name-string[1]	SEQUENCE OF GeneralString
+}
+
+Ticket ::=	[APPLICATION 1] SEQUENCE {
+	tkt-vno[0]	INTEGER,
+	realm[1]	Realm,
+	sname[2]	PrincipalName,
+	enc-part[3]	EncryptedData	-- EncTicketPart
+}
+
+TransitedEncoding ::= SEQUENCE {
+	tr-type[0]	INTEGER, -- Only supported value is 1 == DOMAIN-COMPRESS
+	contents[1]	OCTET STRING
+}
+
+-- Encrypted part of ticket
+EncTicketPart ::=	[APPLICATION 3] SEQUENCE {
+	flags[0]	TicketFlags,
+	key[1]		EncryptionKey,
+	crealm[2]	Realm,
+	cname[3]	PrincipalName,
+	transited[4]	TransitedEncoding,
+	authtime[5]	KerberosTime,
+	starttime[6]	KerberosTime OPTIONAL,
+	endtime[7]	KerberosTime,
+	renew-till[8]	KerberosTime OPTIONAL,
+	caddr[9]	HostAddresses OPTIONAL,
+	authorization-data[10]	AuthorizationData OPTIONAL
+}
+
+-- Unencrypted authenticator
+Authenticator ::=	[APPLICATION 2] SEQUENCE  {
+	authenticator-vno[0]	INTEGER,
+	crealm[1]		Realm,
+	cname[2]		PrincipalName,
+	cksum[3]		Checksum OPTIONAL,
+	cusec[4]		INTEGER,
+	ctime[5]		KerberosTime,
+	subkey[6]		EncryptionKey OPTIONAL,
+	seq-number[7]		INTEGER OPTIONAL,
+	authorization-data[8]	AuthorizationData OPTIONAL
+}
+
+TicketFlags ::= BIT STRING {
+	reserved(0),
+	forwardable(1),
+	forwarded(2),
+	proxiable(3),
+	proxy(4),
+	may-postdate(5),
+	postdated(6),
+	invalid(7),
+	renewable(8),
+	initial(9)
+}
+
+AS-REQ ::= [APPLICATION 10] KDC-REQ
+TGS-REQ ::= [APPLICATION 12] KDC-REQ
+
+KDC-REQ ::= SEQUENCE {
+	pvno[1]		INTEGER,
+	msg-type[2]	INTEGER,
+	padata[3]	SEQUENCE OF PA-DATA OPTIONAL,
+	req-body[4]	KDC-REQ-BODY
+}
+
+PA-DATA ::= SEQUENCE {
+	padata-type[1]	INTEGER,
+	pa-data[2]	OCTET STRING -- might be encoded AP-REQ
+}
+
+KDC-REQ-BODY ::=	SEQUENCE {
+	 kdc-options[0]	KDCOptions,
+	 cname[1]	PrincipalName OPTIONAL, -- Used only in AS-REQ
+	 realm[2]	Realm, -- Server's realm  Also client's in AS-REQ
+	 sname[3]	PrincipalName OPTIONAL,
+	 from[4]	KerberosTime OPTIONAL,
+	 till[5]	KerberosTime,
+	 rtime[6]	KerberosTime OPTIONAL,
+	 nonce[7]	INTEGER,
+	 etype[8]	SEQUENCE OF INTEGER, -- EncryptionType, 
+			-- in preference order
+	 addresses[9]	HostAddresses OPTIONAL,
+	 enc-authorization-data[10]	EncryptedData OPTIONAL, 
+			-- AuthorizationData
+	 additional-tickets[11]	SEQUENCE OF Ticket OPTIONAL
+}
+
+AS-REP ::= [APPLICATION 11] KDC-REP
+TGS-REP ::= [APPLICATION 13] KDC-REP
+KDC-REP ::= SEQUENCE {
+	pvno[0]				INTEGER,
+	msg-type[1]			INTEGER,
+	padata[2]			SEQUENCE OF PA-DATA OPTIONAL,
+	crealm[3]			Realm,
+	cname[4]			PrincipalName,
+	ticket[5]			Ticket,		-- Ticket
+	enc-part[6]			EncryptedData	-- EncKDCRepPart
+}
+
+EncASRepPart ::= [APPLICATION 25] EncKDCRepPart
+EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart
+EncKDCRepPart ::=  SEQUENCE {
+	key[0]		EncryptionKey,
+	last-req[1]	LastReq,
+	nonce[2]	INTEGER,
+	key-expiration[3]	KerberosTime OPTIONAL,
+	flags[4]	TicketFlags,
+	authtime[5]	KerberosTime,
+	starttime[6]	KerberosTime OPTIONAL,
+	endtime[7]	KerberosTime,
+	renew-till[8]	KerberosTime OPTIONAL,
+	srealm[9]	Realm,
+	sname[10]	PrincipalName,
+	caddr[11]	HostAddresses OPTIONAL
+}
+
+AP-REQ ::= [APPLICATION 14] SEQUENCE {
+	pvno[0]				INTEGER,
+	msg-type[1]			INTEGER,
+	ap-options[2]			APOptions,
+	ticket[3]			Ticket,
+	authenticator[4]		EncryptedData	-- Authenticator
+}
+
+APOptions ::= BIT STRING {
+	reserved(0),
+	use-session-key(1),
+	mutual-required(2)
+}
+
+AP-REP ::= [APPLICATION 15] SEQUENCE {
+	pvno[0]				INTEGER,
+	msg-type[1]			INTEGER,
+	enc-part[2]			EncryptedData	-- EncAPRepPart
+}
+
+EncAPRepPart ::= [APPLICATION 27] SEQUENCE {
+	ctime[0]			KerberosTime,
+	cusec[1]			INTEGER,
+	subkey[2]			EncryptionKey OPTIONAL,
+	seq-number[3]			INTEGER OPTIONAL
+}
+
+KRB-SAFE ::= [APPLICATION 20] SEQUENCE {
+	pvno[0]				INTEGER,
+	msg-type[1]			INTEGER,
+	safe-body[2]			KRB-SAFE-BODY,
+	cksum[3]			Checksum			
+}
+
+KRB-SAFE-BODY ::= SEQUENCE {
+	user-data[0]			OCTET STRING,
+	timestamp[1]			KerberosTime OPTIONAL,
+	usec[2]				INTEGER OPTIONAL,
+	seq-number[3]			INTEGER OPTIONAL,
+	s-address[4]			HostAddress,	-- sender's addr
+	r-address[5]			HostAddress OPTIONAL -- recip's addr 
+}
+
+KRB-PRIV ::=	[APPLICATION 21] SEQUENCE {
+	pvno[0]		INTEGER,
+	msg-type[1]	INTEGER,
+	enc-part[3]	EncryptedData	-- EncKrbPrivPart 
+}
+
+EncKrbPrivPart ::=	[APPLICATION 28] SEQUENCE {
+	user-data[0]	OCTET STRING,
+	timestamp[1]	KerberosTime OPTIONAL,
+	usec[2]		INTEGER OPTIONAL,
+	seq-number[3]	INTEGER OPTIONAL,
+	s-address[4]	HostAddress,	-- sender's addr
+	r-address[5]	HostAddress OPTIONAL	-- recip's addr 
+}
+
+-- The KRB-CRED message allows easy forwarding of credentials.
+
+KRB-CRED ::= [APPLICATION 22] SEQUENCE {
+	pvno[0]		INTEGER,
+	msg-type[1]	INTEGER, -- KRB_CRED
+	tickets[2]	SEQUENCE OF Ticket,
+	enc-part[3]	EncryptedData -- EncKrbCredPart 
+}
+
+EncKrbCredPart ::= [APPLICATION 29] SEQUENCE {
+	ticket-info[0] 	SEQUENCE OF KRB-CRED-INFO,	
+	nonce[1]	INTEGER OPTIONAL,
+	timestamp[2]	KerberosTime OPTIONAL,
+	usec[3]		INTEGER OPTIONAL,
+	s-address[4]	HostAddress OPTIONAL,
+	r-address[5]	HostAddress OPTIONAL
+}
+
+KRB-CRED-INFO	::=	SEQUENCE {
+	key[0]		EncryptionKey,
+        prealm[1] 	Realm OPTIONAL,
+        pname[2] 	PrincipalName OPTIONAL,
+        flags[3] 	TicketFlags OPTIONAL,
+        authtime[4] 	KerberosTime OPTIONAL,
+        starttime[5] 	KerberosTime OPTIONAL,
+        endtime[6] 	KerberosTime OPTIONAL,
+        renew-till[7] 	KerberosTime OPTIONAL,
+        srealm[8] 	Realm OPTIONAL,
+        sname[9] 	PrincipalName OPTIONAL,
+        caddr[10] 	HostAddresses OPTIONAL 
+}
+
+KRB-ERROR ::=	[APPLICATION 30] SEQUENCE {
+	pvno[0]		INTEGER,
+	msg-type[1]	INTEGER,
+	ctime[2]	KerberosTime OPTIONAL,
+	cusec[3]	INTEGER OPTIONAL,
+	stime[4]	KerberosTime,
+	susec[5]	INTEGER,
+	error-code[6]	INTEGER,
+	crealm[7]	Realm OPTIONAL,
+	cname[8]	PrincipalName OPTIONAL,
+	realm[9]	Realm, -- Correct realm
+	sname[10]	PrincipalName, -- Correct name
+	e-text[11]	GeneralString OPTIONAL,
+	e-data[12]	OCTET STRING OPTIONAL
+}
+
+EncryptedData ::=	SEQUENCE {
+	etype[0]	INTEGER, -- EncryptionType
+	kvno[1]		INTEGER OPTIONAL,
+	cipher[2]	OCTET STRING -- CipherText
+}
+
+EncryptionKey ::= SEQUENCE {
+	keytype[0]			INTEGER,
+	keyvalue[1]			OCTET STRING
+}
+
+Checksum ::= SEQUENCE {
+	cksumtype[0]			INTEGER,
+	checksum[1]			OCTET STRING
+}
+
+METHOD-DATA ::= SEQUENCE {
+	method-type[0]	INTEGER,
+	method-data[1]	OCTET STRING OPTIONAL
+}
+
+ETYPE-INFO-ENTRY ::= SEQUENCE {
+	etype[0]	INTEGER,
+	salt[1]		OCTET STRING OPTIONAL
+}
+
+ETYPE-INFO ::= SEQUENCE OF ETYPE-INFO-ENTRY
+
+PA-ENC-TS-ENC   ::= SEQUENCE {
+       patimestamp[0]               KerberosTime, -- client's time
+       pausec[1]                    INTEGER OPTIONAL
+}
+
+-- These ASN.1 definitions are NOT part of the official Kerberos protocol... 
+
+-- New ASN.1 definitions for the kadmin protocol.
+-- Originally contributed from the Sandia modifications
+
+PasswdSequence ::= SEQUENCE {
+	passwd[0]			OCTET STRING,
+	phrase[1]			OCTET STRING
+}
+
+PasswdData ::= SEQUENCE {
+	passwd-sequence-count[0]	INTEGER,
+	passwd-sequence[1]		SEQUENCE OF PasswdSequence
+}
+
+-- encodings from 
+-- Integrating Single-use Authentication Mechanisms with Kerberos
+
+PA-SAM-CHALLENGE ::= SEQUENCE {
+    sam-type[0]                 INTEGER,
+    sam-flags[1]                SAMFlags,
+    sam-type-name[2]            GeneralString OPTIONAL,
+    sam-track-id[3]             GeneralString OPTIONAL,
+    sam-challenge-label[4]      GeneralString OPTIONAL,
+    sam-challenge[5]            GeneralString OPTIONAL,
+    sam-response-prompt[6]      GeneralString OPTIONAL,
+    sam-pk-for-sad[7]           OCTET STRING OPTIONAL,
+    sam-nonce[8]                INTEGER OPTIONAL,
+    sam-cksum[9]                Checksum OPTIONAL
+}
+
+PA-SAM-CHALLENGE-2 ::= SEQUENCE {
+    sam-body[0]                 PA-SAM-CHALLENGE-2-BODY,
+    sam-cksum[1]                SEQUENCE (1..MAX) OF Checksum,
+    ...
+}
+
+PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE {
+    sam-type[0]                 INTEGER,
+    sam-flags[1]                SAMFlags,
+    sam-type-name[2]            GeneralString OPTIONAL,
+    sam-track-id[3]             GeneralString OPTIONAL,
+    sam-challenge-label[4]      GeneralString OPTIONAL,
+    sam-challenge[5]            GeneralString OPTIONAL,
+    sam-response-prompt[6]      GeneralString OPTIONAL,
+    sam-pk-for-sad[7]           EncryptionKey OPTIONAL,
+    sam-nonce[8]                INTEGER,
+    sam-etype[9]		INTEGER,
+    ...
+}
+
+-- these are [0].. [2] in the draft
+SAMFlags ::= BIT STRING (SIZE (32..MAX))
+    -- use-sad-as-key(0)
+    -- send-encrypted-sad(1)
+    -- must-pk-encrypt-sad(2)
+
+PA-SAM-RESPONSE ::= SEQUENCE {
+    sam-type[0]                 INTEGER,
+    sam-flags[1]                SAMFlags,
+    sam-track-id[2]             GeneralString OPTIONAL,
+    -- sam-enc-key is reserved for future use, so I'm making it OPTIONAL - mwe
+    sam-enc-key[3]              EncryptedData,
+                                   -- PA-ENC-SAM-KEY
+    sam-enc-nonce-or-ts[4]      EncryptedData,
+                                   -- PA-ENC-SAM-RESPONSE-ENC
+    sam-nonce[5]                INTEGER OPTIONAL,
+    sam-patimestamp[6]          KerberosTime OPTIONAL
+}
+
+PA-SAM-RESPONSE-2 ::= SEQUENCE {
+    sam-type[0]                 INTEGER,
+    sam-flags[1]                SAMFlags,
+    sam-track-id[2]             GeneralString OPTIONAL,
+    sam-enc-nonce-or-sad[3]     EncryptedData,
+                                   -- PA-ENC-SAM-RESPONSE-ENC
+    sam-nonce[4]                INTEGER,
+    ...
+}
+
+PA-ENC-SAM-KEY ::= SEQUENCE {
+             sam-key[0]                 EncryptionKey
+}
+
+PA-ENC-SAM-RESPONSE-ENC ::= SEQUENCE {
+     sam-nonce[0]               INTEGER OPTIONAL,
+     sam-timestamp[1]           KerberosTime OPTIONAL,
+     sam-usec[2]                INTEGER OPTIONAL,
+     sam-passcode[3]            GeneralString OPTIONAL
+}
+
+PA-ENC-SAM-RESPONSE-ENC-2 ::= SEQUENCE {
+     sam-nonce[0]               INTEGER,
+     sam-sad[1]                 GeneralString OPTIONAL,
+     ...
+}
+END
diff --git a/mechglue/src/lib/krb5/asn.1/Makefile.in b/mechglue/src/lib/krb5/asn.1/Makefile.in
new file mode 100644
index 000000000..f0db39fc3
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/Makefile.in
@@ -0,0 +1,132 @@
+thisconfigdir=./..
+myfulldir=lib/krb5/asn.1
+mydir=asn.1
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=asn.1
+##DOS##OBJFILE=..\$(OUTPRE)asn1.lst
+
+EHDRDIR=$(BUILDTOP)/include/krb5/asn.1
+
+STLIBOBJS= \
+	asn1_decode.o\
+	asn1_k_decode.o\
+	asn1_encode.o\
+	asn1_get.o\
+	asn1_make.o\
+	asn1buf.o\
+	krb5_decode.o\
+	krb5_encode.o\
+	asn1_k_encode.o\
+	asn1_misc.o
+
+SRCS= \
+	$(srcdir)/asn1_decode.c\
+	$(srcdir)/asn1_k_decode.c\
+	$(srcdir)/asn1_encode.c\
+	$(srcdir)/asn1_get.c\
+	$(srcdir)/asn1_make.c\
+	$(srcdir)/asn1buf.c\
+	$(srcdir)/krb5_decode.c\
+	$(srcdir)/krb5_encode.c\
+	$(srcdir)/asn1_k_encode.c\
+	$(srcdir)/asn1_misc.c
+
+OBJS= \
+	$(OUTPRE)asn1_decode.$(OBJEXT)\
+	$(OUTPRE)asn1_k_decode.$(OBJEXT)\
+	$(OUTPRE)asn1_encode.$(OBJEXT)\
+	$(OUTPRE)asn1_get.$(OBJEXT)\
+	$(OUTPRE)asn1_make.$(OBJEXT)\
+	$(OUTPRE)asn1buf.$(OBJEXT)\
+	$(OUTPRE)krb5_decode.$(OBJEXT)\
+	$(OUTPRE)krb5_encode.$(OBJEXT)\
+	$(OUTPRE)asn1_k_encode.$(OBJEXT)\
+	$(OUTPRE)asn1_misc.$(OBJEXT)
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+asn1_decode.so asn1_decode.po $(OUTPRE)asn1_decode.$(OBJEXT): \
+  asn1_decode.c asn1_decode.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h krbasn1.h asn1buf.h asn1_get.h
+asn1_k_decode.so asn1_k_decode.po $(OUTPRE)asn1_k_decode.$(OBJEXT): \
+  asn1_k_decode.c asn1_k_decode.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h krbasn1.h asn1buf.h asn1_decode.h \
+  asn1_get.h asn1_misc.h
+asn1_encode.so asn1_encode.po $(OUTPRE)asn1_encode.$(OBJEXT): \
+  asn1_encode.c asn1_encode.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h krbasn1.h asn1buf.h asn1_make.h
+asn1_get.so asn1_get.po $(OUTPRE)asn1_get.$(OBJEXT): \
+  asn1_get.c asn1_get.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  krbasn1.h asn1buf.h
+asn1_make.so asn1_make.po $(OUTPRE)asn1_make.$(OBJEXT): \
+  asn1_make.c asn1_make.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h krbasn1.h asn1buf.h
+asn1buf.so asn1buf.po $(OUTPRE)asn1buf.$(OBJEXT): asn1buf.c \
+  asn1buf.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  krbasn1.h asn1_get.h
+krb5_decode.so krb5_decode.po $(OUTPRE)krb5_decode.$(OBJEXT): \
+  krb5_decode.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  krbasn1.h asn1_k_decode.h asn1buf.h asn1_decode.h asn1_get.h
+krb5_encode.so krb5_encode.po $(OUTPRE)krb5_encode.$(OBJEXT): \
+  krb5_encode.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  asn1_k_encode.h asn1buf.h krbasn1.h asn1_encode.h asn1_make.h
+asn1_k_encode.so asn1_k_encode.po $(OUTPRE)asn1_k_encode.$(OBJEXT): \
+  asn1_k_encode.c asn1_k_encode.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h asn1buf.h krbasn1.h asn1_make.h \
+  asn1_encode.h
+asn1_misc.so asn1_misc.po $(OUTPRE)asn1_misc.$(OBJEXT): \
+  asn1_misc.c asn1_misc.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h krbasn1.h
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_decode.c b/mechglue/src/lib/krb5/asn.1/asn1_decode.c
new file mode 100644
index 000000000..d31ce3e3b
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_decode.c
@@ -0,0 +1,261 @@
+/*
+ * src/lib/krb5/asn.1/asn1_decode.c
+ * 
+ * Copyright 1994, 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/* ASN.1 primitive decoders */
+#include "asn1_decode.h"
+#include "asn1_get.h"
+#include <stdio.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#include <time.h>
+#endif
+
+#define setup()\
+asn1_error_code retval;\
+taginfo tinfo
+
+#define asn1class	(tinfo.asn1class)
+#define construction	(tinfo.construction)
+#define tagnum		(tinfo.tagnum)
+#define length		(tinfo.length)
+
+#define tag(type)\
+retval = asn1_get_tag_2(buf,&tinfo);\
+if(retval) return retval;\
+if(asn1class != UNIVERSAL || construction != PRIMITIVE || tagnum != type)\
+  return ASN1_BAD_ID
+  
+#define cleanup()\
+return 0
+
+time_t gmt_mktime (struct tm *);
+
+asn1_error_code asn1_decode_integer(asn1buf *buf, long int *val)
+{
+  setup();
+  asn1_octet o;
+  long n = 0; /* initialize to keep gcc happy */
+  int i;
+
+  tag(ASN1_INTEGER);
+
+  for (i = 0; i < length; i++) {
+    retval = asn1buf_remove_octet(buf, &o);
+    if (retval) return retval;
+    if (!i) {
+      n = (0x80 & o) ? -1 : 0;	/* grab sign bit */
+      if (n < 0 && length > sizeof (long))
+	return ASN1_OVERFLOW;
+      else if (length > sizeof (long) + 1) /* allow extra octet for positive */
+	return ASN1_OVERFLOW;
+    }
+    n = (n << 8) | o;
+  }
+  *val = n;
+  cleanup();
+}
+
+asn1_error_code asn1_decode_unsigned_integer(asn1buf *buf, long unsigned int *val)
+{
+  setup();
+  asn1_octet o;
+  unsigned long n;
+  int i;
+
+  tag(ASN1_INTEGER);
+
+  for (i = 0, n = 0; i < length; i++) {
+    retval = asn1buf_remove_octet(buf, &o);
+    if(retval) return retval;
+    if (!i) {
+      if (0x80 & o)
+	return ASN1_OVERFLOW;
+      else if (length > sizeof (long) + 1)
+	return ASN1_OVERFLOW;
+    }
+    n = (n << 8) | o;
+  }
+  *val = n;
+  cleanup();
+}
+
+/*
+ * asn1_decode_maybe_unsigned
+ *
+ * This is needed because older releases of MIT krb5 have signed
+ * sequence numbers.  We want to accept both signed and unsigned
+ * sequence numbers, in the range -2^31..2^32-1, mapping negative
+ * numbers into their positive equivalents in the same way that C's
+ * normal integer conversions do, i.e., would preserve bits on a
+ * two's-complement architecture.
+ */
+asn1_error_code asn1_decode_maybe_unsigned(asn1buf *buf, unsigned long *val)
+{
+  setup();
+  asn1_octet o;
+  unsigned long n, bitsremain;
+  unsigned int i;
+
+  tag(ASN1_INTEGER);
+  o = 0;
+  n = 0;
+  bitsremain = ~0UL;
+  for (i = 0; i < length; i++) {
+    /* Accounts for u_long width not being a multiple of 8. */
+    if (bitsremain < 0xff) return ASN1_OVERFLOW;
+    retval = asn1buf_remove_octet(buf, &o);
+    if (retval) return retval;
+    if (bitsremain == ~0UL) {
+      if (i == 0)
+	n = (o & 0x80) ? ~0UL : 0UL; /* grab sign bit */
+      /*
+       * Skip leading zero or 0xFF octets to humor non-compliant encoders.
+       */
+      if (n == 0 && o == 0)
+	continue;
+      if (n == ~0UL && o == 0xff)
+	continue;
+    }
+    n = (n << 8) | o;
+    bitsremain >>= 8;
+  }
+  *val = n;
+  cleanup();
+}
+
+asn1_error_code asn1_decode_oid(asn1buf *buf, unsigned int *retlen, asn1_octet **val)
+{
+  setup();
+  tag(ASN1_OBJECTIDENTIFIER);
+  retval = asn1buf_remove_octetstring(buf, length, val);
+  if (retval) return retval;
+  *retlen = length;
+  cleanup();
+}
+
+asn1_error_code asn1_decode_octetstring(asn1buf *buf, unsigned int *retlen, asn1_octet **val)
+{
+  setup();
+  tag(ASN1_OCTETSTRING);
+  retval = asn1buf_remove_octetstring(buf,length,val);
+  if(retval) return retval;
+  *retlen = length;
+  cleanup();
+}
+
+asn1_error_code asn1_decode_charstring(asn1buf *buf, unsigned int *retlen, char **val)
+{
+  setup();
+  tag(ASN1_OCTETSTRING);
+  retval = asn1buf_remove_charstring(buf,length,val);
+  if(retval) return retval;
+  *retlen = length;
+  cleanup();
+}
+
+
+asn1_error_code asn1_decode_generalstring(asn1buf *buf, unsigned int *retlen, char **val)
+{
+  setup();
+  tag(ASN1_GENERALSTRING);
+  retval = asn1buf_remove_charstring(buf,length,val);
+  if(retval) return retval;
+  *retlen = length;
+  cleanup();
+}
+
+
+asn1_error_code asn1_decode_null(asn1buf *buf)
+{
+  setup();
+  tag(ASN1_NULL);
+  if(length != 0) return ASN1_BAD_LENGTH;
+  cleanup();
+}
+
+asn1_error_code asn1_decode_printablestring(asn1buf *buf, int *retlen, char **val)
+{
+  setup();
+  tag(ASN1_PRINTABLESTRING);
+  retval = asn1buf_remove_charstring(buf,length,val);
+  if(retval) return retval;
+  *retlen = length;
+  cleanup();
+}
+
+asn1_error_code asn1_decode_ia5string(asn1buf *buf, int *retlen, char **val)
+{
+  setup();
+  tag(ASN1_IA5STRING);
+  retval = asn1buf_remove_charstring(buf,length,val);
+  if(retval) return retval;
+  *retlen = length;
+  cleanup();
+}
+
+asn1_error_code asn1_decode_generaltime(asn1buf *buf, time_t *val)
+{
+  setup();
+  char *s;
+  struct tm ts;
+  time_t t;
+
+  tag(ASN1_GENERALTIME);
+
+  if(length != 15) return ASN1_BAD_LENGTH;
+  retval = asn1buf_remove_charstring(buf,15,&s);
+  /* Time encoding: YYYYMMDDhhmmssZ */
+  if(s[14] != 'Z') {
+      free(s);
+      return ASN1_BAD_FORMAT;
+  }
+  if(s[0] == '1' && !memcmp("19700101000000Z", s, 15)) {
+      t = 0;
+      free(s);
+      goto done;
+  }
+#define c2i(c) ((c)-'0')
+  ts.tm_year = 1000*c2i(s[0]) + 100*c2i(s[1]) + 10*c2i(s[2]) + c2i(s[3])
+    - 1900;
+  ts.tm_mon = 10*c2i(s[4]) + c2i(s[5]) - 1;
+  ts.tm_mday = 10*c2i(s[6]) + c2i(s[7]);
+  ts.tm_hour = 10*c2i(s[8]) + c2i(s[9]);
+  ts.tm_min = 10*c2i(s[10]) + c2i(s[11]);
+  ts.tm_sec = 10*c2i(s[12]) + c2i(s[13]);
+  ts.tm_isdst = -1;
+  t = gmt_mktime(&ts);
+  free(s);
+
+  if(t == -1) return ASN1_BAD_TIMEFORMAT;
+
+done:
+  *val = t;
+  cleanup();
+}
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_decode.h b/mechglue/src/lib/krb5/asn.1/asn1_decode.h
new file mode 100644
index 000000000..cafbf3fd3
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_decode.h
@@ -0,0 +1,92 @@
+/*
+ * src/lib/krb5/asn.1/asn1_decode.h
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __ASN1_DECODE_H__
+#define __ASN1_DECODE_H__
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "asn1buf.h"
+
+/*
+   Overview
+
+     These procedures take an asn1buf whose current position points
+     to the beginning of an ASN.1 primitive (<id><length><contents>).
+     The primitive is removed from the buffer and decoded.
+
+   Operations
+
+    asn1_decode_integer
+    asn1_decode_unsigned_integer
+    asn1_decode_octetstring
+    asn1_decode_charstring
+    asn1_decode_generalstring
+    asn1_decode_null
+    asn1_decode_printablestring
+    asn1_decode_ia5string
+    asn1_decode_generaltime
+*/
+
+/* asn1_error_code asn1_decode_type(asn1buf *buf, ctype *val); */
+/* requires  *buf is allocated
+   modifies  *buf, *len
+   effects   Decodes the octet string in *buf into *val.
+             Returns ENOMEM if memory is exhausted.
+	     Returns asn1 errors. */
+
+asn1_error_code asn1_decode_integer
+	(asn1buf *buf, long *val);
+asn1_error_code asn1_decode_unsigned_integer
+	(asn1buf *buf, unsigned long *val);
+asn1_error_code asn1_decode_maybe_unsigned
+	(asn1buf *buf, unsigned long *val);
+asn1_error_code asn1_decode_null
+	(asn1buf *buf);
+
+asn1_error_code asn1_decode_oid
+	(asn1buf *buf, unsigned int *retlen, asn1_octet **val);
+asn1_error_code asn1_decode_octetstring
+	(asn1buf *buf, unsigned int *retlen, asn1_octet **val);
+asn1_error_code asn1_decode_generalstring
+	(asn1buf *buf, unsigned int *retlen, char **val);
+asn1_error_code asn1_decode_charstring
+	(asn1buf *buf, unsigned int *retlen, char **val);
+/* Note: A charstring is a special hack to account for the fact that
+         krb5 structures store some OCTET STRING values in krb5_octet
+	 arrays and others in krb5_data structures 
+	 (which use char arrays).
+	 From the ASN.1 point of view, the two string types are the same,
+	 only the receptacles differ. */
+asn1_error_code asn1_decode_printablestring
+	(asn1buf *buf, int *retlen, char **val);
+asn1_error_code asn1_decode_ia5string
+	(asn1buf *buf, int *retlen, char **val);
+
+asn1_error_code asn1_decode_generaltime
+	(asn1buf *buf, time_t *val);
+
+#endif
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_encode.c b/mechglue/src/lib/krb5/asn.1/asn1_encode.c
new file mode 100644
index 000000000..c5e3452b8
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_encode.c
@@ -0,0 +1,297 @@
+/*
+ * src/lib/krb5/asn.1/asn1_encode.c
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/* ASN.1 primitive encoders */
+
+#include "asn1_encode.h"
+#include "asn1_make.h"
+
+static asn1_error_code asn1_encode_integer_internal(asn1buf *buf,  long val,
+						    unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length = 0;
+  long valcopy;
+  int digit;
+  
+  valcopy = val;
+  do {
+    digit = (int) (valcopy&0xFF);
+    retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
+    if(retval) return retval;
+    length++;
+    valcopy = valcopy >> 8;
+  } while (valcopy != 0 && valcopy != ~0);
+
+  if((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */
+    retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
+    if(retval) return retval;
+    length++;
+  }else if((val < 0) && ((digit&0x80) != 0x80)){
+    retval = asn1buf_insert_octet(buf,0xFF);
+    if(retval) return retval;
+    length++;
+  }
+
+
+  *retlen = length;
+  return 0;
+}
+
+asn1_error_code asn1_encode_integer(asn1buf * buf,  long val,
+ unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length = 0;
+  unsigned  int partlen;
+  retval = asn1_encode_integer_internal(buf, val, &partlen);
+  if (retval) return retval;
+
+  length = partlen;
+    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen); 
+  if(retval) return retval;
+  length += partlen;
+
+  *retlen = length;
+  return 0;
+}
+
+asn1_error_code
+asn1_encode_enumerated(asn1buf * buf, long val,
+		       unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length = 0;
+  unsigned  int partlen;
+  retval = asn1_encode_integer_internal(buf, val, &partlen);
+  if (retval) return retval;
+
+  length = partlen;
+    retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_ENUMERATED,length, &partlen); 
+  if(retval) return retval;
+  length += partlen;
+
+  *retlen = length;
+  return 0;
+}
+
+asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, unsigned long val,
+					     unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length = 0;
+  unsigned int partlen;
+  unsigned long valcopy;
+  int digit;
+  
+  valcopy = val;
+  do {
+    digit = (int) (valcopy&0xFF);
+    retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
+    if(retval) return retval;
+    length++;
+    valcopy = valcopy >> 8;
+  } while (valcopy != 0 && valcopy != ~0);
+
+  if(digit&0x80) {		          /* make sure the high bit is */
+    retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
+    if(retval) return retval;
+    length++;
+  }
+
+  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen); 
+  if(retval) return retval;
+  length += partlen;
+
+  *retlen = length;
+  return 0;
+}
+
+asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len,
+				const asn1_octet *val,
+				unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length;
+
+  retval = asn1buf_insert_octetstring(buf, len, val);
+  if (retval) return retval;
+  retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_OBJECTIDENTIFIER,
+			 len, &length);
+  if (retval) return retval;
+
+  *retlen = len + length;
+  return 0;
+}
+
+asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len,
+					const asn1_octet *val,
+					unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length;
+
+  retval = asn1buf_insert_octetstring(buf,len,val);
+  if(retval) return retval;
+  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length);
+  if(retval) return retval;
+
+  *retlen = len + length;
+  return 0;
+}
+
+asn1_error_code asn1_encode_charstring(asn1buf *buf, unsigned int len,
+				       const char *val, unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length;
+
+  retval = asn1buf_insert_charstring(buf,len,val);
+  if(retval) return retval;
+  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length);
+  if(retval) return retval;
+
+  *retlen = len + length;
+  return 0;
+}
+
+asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen)
+{
+  asn1_error_code retval;
+  
+  retval = asn1buf_insert_octet(buf,0x00);
+  if(retval) return retval;
+  retval = asn1buf_insert_octet(buf,0x05);
+  if(retval) return retval;
+
+  *retlen = 2;
+  return 0;
+}
+
+asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len,
+					    const char *val, int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length;
+
+  retval = asn1buf_insert_charstring(buf,len,val);
+  if(retval) return retval;
+  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_PRINTABLESTRING,len,			 &length);
+  if(retval) return retval;
+
+  *retlen = len + length;
+  return 0;
+}
+
+asn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len,
+				      const char *val, int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length;
+
+  retval = asn1buf_insert_charstring(buf,len,val);
+  if(retval) return retval;
+  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_IA5STRING,len,			 &length);
+  if(retval) return retval;
+
+  *retlen = len + length;
+  return 0;
+}
+
+asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val,
+					unsigned int *retlen)
+{
+  asn1_error_code retval;
+  struct tm *gtime, gtimebuf;
+  char s[16], *sp;
+  unsigned int length, sum=0;
+  time_t gmt_time = val;
+
+  /*
+   * Time encoding: YYYYMMDDhhmmssZ
+   */
+  if (gmt_time == 0) {
+      sp = "19700101000000Z";
+  } else {
+
+      /*
+       * Sanity check this just to be paranoid, as gmtime can return NULL,
+       * and some bogus implementations might overrun on the sprintf.
+       */
+#ifdef HAVE_GMTIME_R
+# ifdef GMTIME_R_RETURNS_INT
+      if (gmtime_r(&gmt_time, >imebuf) != 0)
+	  return ASN1_BAD_GMTIME;
+# else
+      if (gmtime_r(&gmt_time, >imebuf) == NULL)
+	  return ASN1_BAD_GMTIME;
+# endif
+#else
+      gtime = gmtime(&gmt_time);
+      if (gtime == NULL)
+	  return ASN1_BAD_GMTIME;
+      memcpy(>imebuf, gtime, sizeof(gtimebuf));
+#endif
+      gtime = >imebuf;
+
+      if (gtime->tm_year > 8099 || gtime->tm_mon > 11 ||
+	  gtime->tm_mday > 31 || gtime->tm_hour > 23 ||
+	  gtime->tm_min > 59 || gtime->tm_sec > 59)
+	  return ASN1_BAD_GMTIME;
+      sprintf(s, "%04d%02d%02d%02d%02d%02dZ",
+	      1900+gtime->tm_year, gtime->tm_mon+1, gtime->tm_mday,
+	      gtime->tm_hour, gtime->tm_min, gtime->tm_sec);
+      sp = s;
+  }
+
+  retval = asn1buf_insert_charstring(buf,15,sp);
+  if(retval) return retval;
+  sum = 15;
+
+  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALTIME,sum,&length);
+  if(retval) return retval;
+  sum += length;
+
+  *retlen = sum;
+  return 0;
+}
+
+asn1_error_code asn1_encode_generalstring(asn1buf *buf, unsigned int len,
+					  const char *val,
+					  unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int length;
+
+  retval = asn1buf_insert_charstring(buf,len,val);
+  if(retval) return retval;
+  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALSTRING,len,
+			 &length);
+  if(retval) return retval;
+
+  *retlen = len + length;
+  return 0;
+}
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_encode.h b/mechglue/src/lib/krb5/asn.1/asn1_encode.h
new file mode 100644
index 000000000..79eee48d5
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_encode.h
@@ -0,0 +1,159 @@
+/*
+ * src/lib/krb5/asn.1/asn1_encode.h
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __ASN1_ENCODE_H__
+#define __ASN1_ENCODE_H__
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "asn1buf.h"
+#include <time.h>
+
+/*
+   Overview
+
+     Each of these procedures inserts the encoding of an ASN.1
+     primitive in a coding buffer.
+
+   Operations
+
+     asn1_encode_integer
+     asn1_encode_octetstring
+     asn1_encode_null
+     asn1_encode_printablestring
+     asn1_encode_ia5string
+     asn1_encode_generaltime
+     asn1_encode_generalstring
+*/
+
+asn1_error_code asn1_encode_integer
+	(asn1buf *buf, long val, unsigned int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_enumerated
+(asn1buf *buf, long val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_unsigned_integer
+	(asn1buf *buf, unsigned long val, 
+		   unsigned int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_octetstring
+	(asn1buf *buf,
+		   unsigned int len, const asn1_octet *val,
+		   unsigned int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_oid
+	(asn1buf *buf,
+		   unsigned int len, const asn1_octet *val,
+		   unsigned int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_charstring
+	(asn1buf *buf,
+		   unsigned int len, const char *val,
+		   unsigned int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_null
+	(asn1buf *buf, int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of NULL into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_printablestring
+	(asn1buf *buf,
+		   unsigned int len, const char *val,
+		   int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_ia5string
+	(asn1buf *buf,
+		   unsigned int len, const char *val,
+		   int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+asn1_error_code asn1_encode_generaltime
+	(asn1buf *buf, time_t val, unsigned int *retlen);
+/* requires  *buf is allocated
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer.
+   Note: The encoding of GeneralizedTime is YYYYMMDDhhmmZ */
+
+asn1_error_code asn1_encode_generalstring
+	(asn1buf *buf,
+		   unsigned int len, const char *val,
+		   unsigned int *retlen);
+/* requires  *buf is allocated,  val has a length of len characters
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of val into *buf and returns 
+              the length of the encoding in *retlen.
+             Returns ENOMEM to signal an unsuccesful attempt
+              to expand the buffer. */
+
+#endif
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_get.c b/mechglue/src/lib/krb5/asn.1/asn1_get.c
new file mode 100644
index 000000000..8da5fd880
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_get.c
@@ -0,0 +1,118 @@
+/*
+ * src/lib/krb5/asn.1/asn1_get.c
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_get.h"
+
+asn1_error_code
+asn1_get_tag_2(asn1buf *buf, taginfo *t)
+{
+    asn1_error_code retval;
+
+    if (buf == NULL || buf->base == NULL ||
+	buf->bound - buf->next + 1 <= 0) {
+	t->tagnum = ASN1_TAGNUM_CEILING; /* emphatically not an EOC tag */
+	t->asn1class = UNIVERSAL;
+	t->construction = PRIMITIVE;
+	t->length = 0;
+	t->indef = 0;
+	return 0;
+    }
+    {
+	/* asn1_get_id(buf, t) */
+	asn1_tagnum tn=0;
+	asn1_octet o;
+
+#define ASN1_CLASS_MASK 0xC0
+#define ASN1_CONSTRUCTION_MASK 0x20
+#define ASN1_TAG_NUMBER_MASK 0x1F
+
+	retval = asn1buf_remove_octet(buf,&o);
+	if (retval)
+	    return retval;
+
+	t->asn1class = (asn1_class)(o&ASN1_CLASS_MASK);
+	t->construction = (asn1_construction)(o&ASN1_CONSTRUCTION_MASK);
+	if ((o&ASN1_TAG_NUMBER_MASK) != ASN1_TAG_NUMBER_MASK){
+	    /* low-tag-number form */
+	    t->tagnum = (asn1_tagnum)(o&ASN1_TAG_NUMBER_MASK);
+	} else {
+	    /* high-tag-number form */
+	    do {
+		retval = asn1buf_remove_octet(buf,&o);
+		if (retval) return retval;
+		tn = (tn<<7) + (asn1_tagnum)(o&0x7F);
+	    }while(o&0x80);
+	    t->tagnum = tn;
+	}
+    }
+
+    {
+	/* asn1_get_length(buf, t) */
+	asn1_octet o;
+
+	t->indef = 0;
+	retval = asn1buf_remove_octet(buf,&o);
+	if (retval) return retval;
+	if ((o&0x80) == 0) {
+	    t->length = (int)(o&0x7F);
+	} else {
+	    int num;
+	    int len=0;
+    
+	    for (num = (int)(o&0x7F); num>0; num--) {
+		retval = asn1buf_remove_octet(buf,&o);
+		if(retval) return retval;
+		len = (len<<8) + (int)o;
+	    }
+	    if (len < 0)
+		return ASN1_OVERRUN;
+	    if (!len)
+		t->indef = 1;
+	    t->length = len;
+	}
+    }
+    if (t->indef && t->construction != CONSTRUCTED)
+	return ASN1_MISMATCH_INDEF;
+    return 0;
+}
+
+asn1_error_code asn1_get_sequence(asn1buf *buf, unsigned int *retlen, int *indef)
+{
+    taginfo t;
+    asn1_error_code retval;
+
+    retval = asn1_get_tag_2(buf, &t);
+    if (retval)
+	return retval;
+    if (t.asn1class != UNIVERSAL || t.construction != CONSTRUCTED ||
+	t.tagnum != ASN1_SEQUENCE)
+	return ASN1_BAD_ID;
+    if (retlen)
+	*retlen = t.length;
+    if (indef)
+	*indef = t.indef;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_get.h b/mechglue/src/lib/krb5/asn.1/asn1_get.h
new file mode 100644
index 000000000..50a1b75ce
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_get.h
@@ -0,0 +1,77 @@
+/*
+ * src/lib/krb5/asn.1/asn1_get.h
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __ASN1_GET_H__
+#define __ASN1_GET_H__
+
+/* ASN.1 substructure decoding procedures */
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "asn1buf.h"
+
+typedef struct {
+    asn1_class asn1class;
+    asn1_construction construction;
+    asn1_tagnum tagnum;
+    unsigned int length;
+    int indef;
+} taginfo;
+
+asn1_error_code asn1_get_tag_2 (asn1buf *buf, taginfo *tinfo);
+
+#if 0
+asn1_error_code asn1_get_tag_indef
+	(asn1buf *buf,
+		   asn1_class *Class,
+		   asn1_construction *construction,
+		   asn1_tagnum *tagnum,
+		   unsigned int *retlen, int *indef);
+
+asn1_error_code asn1_get_tag
+	(asn1buf *buf,
+		   asn1_class *Class,
+		   asn1_construction *construction,
+		   asn1_tagnum *tagnum,
+		   unsigned int *retlen);
+/* requires  *buf is allocated
+   effects   Decodes the tag in *buf.  If class != NULL, returns
+              the class in *Class.  Similarly, the construction,
+	      tag number, and length are returned in *construction,
+	      *tagnum, and *retlen, respectively.
+	     If *buf is empty to begin with,
+	      *tagnum is set to ASN1_TAGNUM_CEILING.
+	     Returns ASN1_OVERRUN if *buf is exhausted during the parse. */
+#endif
+
+asn1_error_code asn1_get_sequence
+	(asn1buf *buf, unsigned int *retlen, int *indef);
+/* requires  *buf is allocated
+   effects   Decodes a tag from *buf and returns ASN1_BAD_ID if it
+              doesn't have a sequence ID.  If retlen != NULL, the
+	      associated length is returned in *retlen. */
+
+#endif
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_k_decode.c b/mechglue/src/lib/krb5/asn.1/asn1_k_decode.c
new file mode 100644
index 000000000..3ffb701fe
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_k_decode.c
@@ -0,0 +1,1094 @@
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode.c
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_k_decode.h"
+#include "asn1_decode.h"
+#include "asn1_get.h"
+#include "asn1_misc.h"
+
+/* Declare useful decoder variables. */
+#define setup()					\
+  asn1_error_code retval;			\
+  asn1_class asn1class;				\
+  asn1_construction construction;		\
+  asn1_tagnum tagnum;				\
+  unsigned int length, taglen
+
+#define unused_var(x) if (0) { x = 0; x = x - x; }
+
+/* This is used for prefetch of next tag in sequence. */
+#define next_tag()								\
+{ taginfo t2;									\
+  retval = asn1_get_tag_2(&subbuf, &t2);					\
+  if (retval) return retval;							\
+  /* Copy out to match previous functionality, until better integrated.  */	\
+  asn1class = t2.asn1class;							\
+  construction = t2.construction;						\
+  tagnum = t2.tagnum;								\
+  taglen = t2.length;								\
+  indef = t2.indef;								\
+}
+
+/* Force check for EOC tag. */
+#define get_eoc()									\
+    {											\
+	taginfo t3;									\
+	retval = asn1_get_tag_2(&subbuf, &t3);						\
+	if(retval) return retval;							\
+        if (t3.asn1class != UNIVERSAL || t3.tagnum || t3.indef)				\
+	    return ASN1_MISSING_EOC;							\
+        /* Copy out to match previous functionality, until better integrated.  */	\
+	asn1class = t3.asn1class;							\
+	construction = t3.construction;							\
+	tagnum = t3.tagnum;								\
+	taglen = t3.length;								\
+	indef = t3.indef;								\
+    }
+
+#define alloc_field(var, type)			\
+  var = (type*)calloc(1, sizeof(type));		\
+  if ((var) == NULL) return ENOMEM
+
+/* Fetch an expected APPLICATION class tag and verify. */
+#define apptag(tagexpect)								\
+  {											\
+      taginfo t1;									\
+      retval = asn1_get_tag_2(buf, &t1);						\
+      if (retval) return retval;						   	\
+      if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED ||	   	\
+	  t1.tagnum != (tagexpect)) return ASN1_BAD_ID;					\
+      /* Copy out to match previous functionality, until better integrated.  */		\
+      asn1class = t1.asn1class;								\
+      construction = t1.construction;							\
+      tagnum = t1.tagnum;								\
+      applen = t1.length;								\
+  }
+
+/**** normal fields ****/
+
+/*
+ * get_field_body
+ *
+ * Get bare field.  This also prefetches the next tag.  The call to
+ * get_eoc() assumes that any values fetched by this macro are
+ * enclosed in a context-specific tag.
+ */
+#define get_field_body(var, decoder)		\
+  retval = decoder(&subbuf, &(var));		\
+  if (retval) return retval;			\
+  if (!taglen && indef) { get_eoc(); }		\
+  next_tag()
+
+/*
+ * get_field
+ *
+ * Get field having an expected context specific tag.  This assumes
+ * that context-specific tags are monotonically increasing in its
+ * verification of tag numbers.
+ */
+#define get_field(var, tagexpect, decoder)				\
+  if (tagnum > (tagexpect)) return ASN1_MISSING_FIELD;			\
+  if (tagnum < (tagexpect)) return ASN1_MISPLACED_FIELD;		\
+  if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
+      && (tagnum || taglen || asn1class != UNIVERSAL))			\
+    return ASN1_BAD_ID;							\
+  get_field_body(var,decoder)
+
+/*
+ * opt_field
+ *
+ * Get an optional field with an expected context specific tag.
+ * Assumes that OPTVAL will have the default value, thus failing to
+ * distinguish between absent optional values and present optional
+ * values that happen to have the value of OPTVAL.
+ */
+#define opt_field(var, tagexpect, decoder, optvalue)			\
+  if (asn1buf_remains(&subbuf, seqindef)) {				\
+    if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
+	&& (tagnum || taglen || asn1class != UNIVERSAL))		\
+      return ASN1_BAD_ID;						\
+    if (tagnum == (tagexpect)) {					\
+      get_field_body(var, decoder);					\
+    } else var = optvalue;						\
+  }
+  
+/**** fields w/ length ****/
+
+/* similar to get_field_body */
+#define get_lenfield_body(len, var, decoder)	\
+  retval = decoder(&subbuf, &(len), &(var));	\
+  if (retval) return retval;			\
+  if (!taglen && indef) { get_eoc(); }		\
+  next_tag()
+
+/* similar to get_field_body */
+#define get_lenfield(len, var, tagexpect, decoder)			\
+  if (tagnum > (tagexpect)) return ASN1_MISSING_FIELD;			\
+  if (tagnum < (tagexpect)) return ASN1_MISPLACED_FIELD;		\
+  if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
+      && (tagnum || taglen || asn1class != UNIVERSAL))			\
+    return ASN1_BAD_ID;							\
+  get_lenfield_body(len, var, decoder)
+
+/* similar to opt_field */
+#define opt_lenfield(len, var, tagexpect, decoder)	\
+  if (tagnum == (tagexpect)) {				\
+    get_lenfield_body(len, var, decoder);		\
+  } else { len = 0; var = 0; }
+
+/*
+ * begin_structure
+ *
+ * Declares some variables for decoding SEQUENCE types.  This is meant
+ * to be called in an inner block that ends with a call to
+ * end_structure().
+ */
+#define begin_structure()					\
+  asn1buf subbuf;						\
+  int seqindef;							\
+  int indef;							\
+  retval = asn1_get_sequence(buf, &length, &seqindef);		\
+  if (retval) return retval;					\
+  retval = asn1buf_imbed(&subbuf, buf, length, seqindef);	\
+  if (retval) return retval;					\
+  next_tag()
+
+/* skip trailing garbage */
+#define end_structure()						\
+  retval = asn1buf_sync(buf, &subbuf, asn1class, tagnum,	\
+			length, indef, seqindef);		\
+  if (retval) return retval
+
+/*
+ * sequence_of
+ *
+ * Declares some variables for decoding SEQUENCE OF types.  This is
+ * meant to be called in an inner block that ends with a call to
+ * end_sequence_of().
+ */
+#define sequence_of(buf)			\
+  unsigned int length, taglen;			\
+  asn1_class asn1class;				\
+  asn1_construction construction;		\
+  asn1_tagnum tagnum;				\
+  int indef;					\
+  sequence_of_common(buf)
+
+/*
+ * sequence_of_no_tagvars
+ *
+ * This is meant for use inside decoder functions that have an outer
+ * sequence structure and thus declares variables of different names
+ * than does sequence_of() to avoid shadowing.
+ */
+#define sequence_of_no_tagvars(buf)		\
+  asn1_class eseqclass;				\
+  asn1_construction eseqconstr;			\
+  asn1_tagnum eseqnum;				\
+  unsigned int eseqlen;				\
+  int eseqindef;				\
+  sequence_of_common(buf)
+
+/*
+ * sequence_of_common
+ *
+ * Fetches the outer SEQUENCE OF length info into {length,seqofindef}
+ * and imbeds an inner buffer seqbuf.  Unlike begin_structure(), it
+ * does not prefetch the next tag.
+ */
+#define sequence_of_common(buf)					\
+  int size = 0;							\
+  asn1buf seqbuf;						\
+  int seqofindef;						\
+  retval = asn1_get_sequence(buf, &length, &seqofindef);	\
+  if (retval) return retval;					\
+  retval = asn1buf_imbed(&seqbuf, buf, length, seqofindef);	\
+  if (retval) return retval
+
+/*
+ * end_sequence_of
+ *
+ * Attempts to fetch an EOC tag, if any, and to sync over trailing
+ * garbage, if any.
+ */
+#define end_sequence_of(buf)							\
+  {										\
+      taginfo t4;								\
+      retval = asn1_get_tag_2(&seqbuf, &t4);					\
+      if (retval) return retval;						\
+      /* Copy out to match previous functionality, until better integrated.  */	\
+      asn1class = t4.asn1class;							\
+      construction = t4.construction;						\
+      tagnum = t4.tagnum;							\
+      taglen = t4.length;							\
+      indef = t4.indef;								\
+  }										\
+  retval = asn1buf_sync(buf, &seqbuf, asn1class, tagnum,			\
+			length, indef, seqofindef);				\
+  if (retval) return retval;
+
+/*
+ * end_sequence_of_no_tagvars
+ *
+ * Like end_sequence_of(), but uses the different (non-shadowing)
+ * variable names.
+ */
+#define end_sequence_of_no_tagvars(buf)						\
+  {										\
+      taginfo t5;								\
+      retval = asn1_get_tag_2(&seqbuf, &t5);					\
+      if (retval) return retval;						\
+      /* Copy out to match previous functionality, until better integrated.  */	\
+      eseqclass = t5.asn1class;							\
+      eseqconstr = t5.construction;						\
+      eseqnum = t5.tagnum;							\
+      eseqlen = t5.length;							\
+      eseqindef = t5.indef;							\
+  }										\
+  retval = asn1buf_sync(buf, &seqbuf, eseqclass, eseqnum,			\
+			eseqlen, eseqindef, seqofindef);			\
+  if (retval) return retval;
+
+#define cleanup()				\
+  return 0
+
+/* scalars */
+asn1_error_code asn1_decode_kerberos_time(asn1buf *buf, krb5_timestamp *val)
+{
+    time_t	t;
+    asn1_error_code retval;
+    
+    retval =  asn1_decode_generaltime(buf,&t);
+    if (retval)
+	return retval;
+
+    *val = t;
+    return 0;
+}
+
+#define integer_convert(fname,ktype)\
+asn1_error_code fname(asn1buf * buf, ktype * val)\
+{\
+  asn1_error_code retval;\
+  long n;\
+  retval = asn1_decode_integer(buf,&n);\
+  if(retval) return retval;\
+  *val = (ktype)n;\
+  return 0;\
+}
+#define unsigned_integer_convert(fname,ktype)\
+asn1_error_code fname(asn1buf * buf, ktype * val)\
+{\
+  asn1_error_code retval;\
+  unsigned long n;\
+  retval = asn1_decode_unsigned_integer(buf,&n);\
+  if(retval) return retval;\
+  *val = (ktype)n;\
+  return 0;\
+}
+integer_convert(asn1_decode_int,int)
+integer_convert(asn1_decode_int32,krb5_int32)
+integer_convert(asn1_decode_kvno,krb5_kvno)
+integer_convert(asn1_decode_enctype,krb5_enctype)
+integer_convert(asn1_decode_cksumtype,krb5_cksumtype)
+integer_convert(asn1_decode_octet,krb5_octet)
+integer_convert(asn1_decode_addrtype,krb5_addrtype)
+integer_convert(asn1_decode_authdatatype,krb5_authdatatype)
+unsigned_integer_convert(asn1_decode_ui_2,krb5_ui_2)
+unsigned_integer_convert(asn1_decode_ui_4,krb5_ui_4)
+
+asn1_error_code asn1_decode_seqnum(asn1buf *buf, krb5_ui_4 *val)
+{
+  asn1_error_code retval;
+  unsigned long n;
+
+  retval = asn1_decode_maybe_unsigned(buf, &n);
+  if (retval) return retval;
+  *val = (krb5_ui_4)n & 0xffffffff;
+  return 0;
+}
+
+asn1_error_code asn1_decode_msgtype(asn1buf *buf, krb5_msgtype *val)
+{
+  asn1_error_code retval;
+  unsigned long n;
+  
+  retval = asn1_decode_unsigned_integer(buf,&n);
+  if(retval) return retval;
+  
+  *val = (krb5_msgtype) n;
+  return 0;
+}
+
+
+/* structures */
+asn1_error_code asn1_decode_realm(asn1buf *buf, krb5_principal *val)
+{
+  return asn1_decode_generalstring(buf,
+				   &((*val)->realm.length),
+				   &((*val)->realm.data));
+}
+
+asn1_error_code asn1_decode_principal_name(asn1buf *buf, krb5_principal *val)
+{
+  setup();
+  { begin_structure();
+    get_field((*val)->type,0,asn1_decode_int32);
+  
+    { sequence_of_no_tagvars(&subbuf);
+      while(asn1buf_remains(&seqbuf,seqofindef) > 0){
+	size++;
+	if ((*val)->data == NULL)
+	  (*val)->data = (krb5_data*)malloc(size*sizeof(krb5_data));
+	else
+	  (*val)->data = (krb5_data*)realloc((*val)->data,
+					     size*sizeof(krb5_data));
+	if((*val)->data == NULL) return ENOMEM;
+	retval = asn1_decode_generalstring(&seqbuf,
+					   &((*val)->data[size-1].length),
+					   &((*val)->data[size-1].data));
+	if(retval) return retval;
+      }
+      (*val)->length = size;
+      end_sequence_of_no_tagvars(&subbuf);
+    }
+    if (indef) {
+	get_eoc();
+    }
+    next_tag();
+    end_structure();
+    (*val)->magic = KV5M_PRINCIPAL;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_checksum(asn1buf *buf, krb5_checksum *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->checksum_type,0,asn1_decode_cksumtype);
+    get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
+    end_structure();
+    val->magic = KV5M_CHECKSUM;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_encryption_key(asn1buf *buf, krb5_keyblock *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->enctype,0,asn1_decode_enctype);
+    get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
+    end_structure();
+    val->magic = KV5M_KEYBLOCK;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_encrypted_data(asn1buf *buf, krb5_enc_data *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->enctype,0,asn1_decode_enctype);
+    opt_field(val->kvno,1,asn1_decode_kvno,0);
+    get_lenfield(val->ciphertext.length,val->ciphertext.data,2,asn1_decode_charstring);
+    end_structure();
+    val->magic = KV5M_ENC_DATA;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_krb5_flags(asn1buf *buf, krb5_flags *val)
+{
+  asn1_error_code retval;
+  asn1_octet unused, o;
+  taginfo t;
+  int i;
+  krb5_flags f=0;
+  unsigned int length;
+
+  retval = asn1_get_tag_2(buf, &t);
+  if (retval) return retval;
+  if (t.asn1class != UNIVERSAL || t.construction != PRIMITIVE ||
+      t.tagnum != ASN1_BITSTRING)
+      return ASN1_BAD_ID;
+  length = t.length;
+
+  retval = asn1buf_remove_octet(buf,&unused); /* # of padding bits */
+  if(retval) return retval;
+
+  /* Number of unused bits must be between 0 and 7. */
+  if (unused > 7) return ASN1_BAD_FORMAT;
+  length--;
+
+  for(i = 0; i < length; i++) {
+    retval = asn1buf_remove_octet(buf,&o);
+    if(retval) return retval;
+    /* ignore bits past number 31 */
+    if (i < 4)
+      f = (f<<8) | ((krb5_flags)o&0xFF);
+  }
+  if (length <= 4) {
+    /* Mask out unused bits, but only if necessary. */
+    f &= ~(krb5_flags)0 << unused;
+  }
+  /* left-justify */
+  if (length < 4)
+    f <<= (4 - length) * 8;
+  *val = f;
+  return 0;
+}
+
+asn1_error_code asn1_decode_ticket_flags(asn1buf *buf, krb5_flags *val)
+{ return asn1_decode_krb5_flags(buf,val); }
+
+asn1_error_code asn1_decode_ap_options(asn1buf *buf, krb5_flags *val)
+{ return asn1_decode_krb5_flags(buf,val); }
+
+asn1_error_code asn1_decode_kdc_options(asn1buf *buf, krb5_flags *val)
+{ return asn1_decode_krb5_flags(buf,val); }
+
+asn1_error_code asn1_decode_transited_encoding(asn1buf *buf, krb5_transited *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->tr_type,0,asn1_decode_octet);
+    get_lenfield(val->tr_contents.length,val->tr_contents.data,1,asn1_decode_charstring);
+    end_structure();
+    val->magic = KV5M_TRANSITED;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_enc_kdc_rep_part(asn1buf *buf, krb5_enc_kdc_rep_part *val)
+{
+  setup();
+  { begin_structure();
+    alloc_field(val->session,krb5_keyblock);
+    get_field(*(val->session),0,asn1_decode_encryption_key);
+    get_field(val->last_req,1,asn1_decode_last_req);
+    get_field(val->nonce,2,asn1_decode_int32);
+    opt_field(val->key_exp,3,asn1_decode_kerberos_time,0);
+    get_field(val->flags,4,asn1_decode_ticket_flags);
+    get_field(val->times.authtime,5,asn1_decode_kerberos_time);
+    /* Set to authtime if missing */
+    opt_field(val->times.starttime,6,asn1_decode_kerberos_time,val->times.authtime);
+    get_field(val->times.endtime,7,asn1_decode_kerberos_time);
+    opt_field(val->times.renew_till,8,asn1_decode_kerberos_time,0);
+    alloc_field(val->server,krb5_principal_data);
+    get_field(val->server,9,asn1_decode_realm);
+    get_field(val->server,10,asn1_decode_principal_name);
+    opt_field(val->caddrs,11,asn1_decode_host_addresses,NULL);
+    end_structure();
+    val->magic = KV5M_ENC_KDC_REP_PART;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_ticket(asn1buf *buf, krb5_ticket *val)
+{
+  setup();
+  unsigned int applen;
+  apptag(1);
+  { begin_structure();
+    { krb5_kvno vno;
+      get_field(vno,0,asn1_decode_kvno);
+      if(vno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
+    alloc_field(val->server,krb5_principal_data);
+    get_field(val->server,1,asn1_decode_realm);
+    get_field(val->server,2,asn1_decode_principal_name);
+    get_field(val->enc_part,3,asn1_decode_encrypted_data);
+    end_structure();
+    val->magic = KV5M_TICKET;
+  }
+  if (!applen) {
+      taginfo t;
+      retval = asn1_get_tag_2(buf, &t);
+      if (retval) return retval;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_kdc_req(asn1buf *buf, krb5_kdc_req *val)
+{
+  setup();
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,1,asn1_decode_kvno);
+      if(kvno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
+    get_field(val->msg_type,2,asn1_decode_msgtype);
+    opt_field(val->padata,3,asn1_decode_sequence_of_pa_data,NULL);
+    get_field(*val,4,asn1_decode_kdc_req_body);
+    end_structure();
+    val->magic = KV5M_KDC_REQ;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_kdc_req_body(asn1buf *buf, krb5_kdc_req *val)
+{
+  setup();
+  { 
+    krb5_principal psave;
+    begin_structure();
+    get_field(val->kdc_options,0,asn1_decode_kdc_options);
+    if(tagnum == 1){ alloc_field(val->client,krb5_principal_data); }
+    opt_field(val->client,1,asn1_decode_principal_name,NULL);
+    alloc_field(val->server,krb5_principal_data);
+    get_field(val->server,2,asn1_decode_realm);
+    if(val->client != NULL){
+      retval = asn1_krb5_realm_copy(val->client,val->server);
+      if(retval) return retval; }
+
+    /* If opt_field server is missing, memory reference to server is
+       lost and results in memory leak */
+    psave = val->server;
+    opt_field(val->server,3,asn1_decode_principal_name,NULL);
+    if(val->server == NULL){
+      if(psave->realm.data) {
+	free(psave->realm.data);
+	psave->realm.data = NULL;
+	psave->realm.length=0;
+      }
+      free(psave);
+    }
+    opt_field(val->from,4,asn1_decode_kerberos_time,0);
+    get_field(val->till,5,asn1_decode_kerberos_time);
+    opt_field(val->rtime,6,asn1_decode_kerberos_time,0);
+    get_field(val->nonce,7,asn1_decode_int32);
+    get_lenfield(val->nktypes,val->ktype,8,asn1_decode_sequence_of_enctype);
+    opt_field(val->addresses,9,asn1_decode_host_addresses,0);
+    if(tagnum == 10){
+      get_field(val->authorization_data,10,asn1_decode_encrypted_data); }
+    else{
+      val->authorization_data.magic = KV5M_ENC_DATA;
+      val->authorization_data.enctype = 0;
+      val->authorization_data.kvno = 0;
+      val->authorization_data.ciphertext.data = NULL;
+      val->authorization_data.ciphertext.length = 0;
+    }
+    opt_field(val->second_ticket,11,asn1_decode_sequence_of_ticket,NULL);
+    end_structure();
+    val->magic = KV5M_KDC_REQ;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_krb_safe_body(asn1buf *buf, krb5_safe *val)
+{
+  setup();
+  { begin_structure();
+    get_lenfield(val->user_data.length,val->user_data.data,0,asn1_decode_charstring);
+    opt_field(val->timestamp,1,asn1_decode_kerberos_time,0);
+    opt_field(val->usec,2,asn1_decode_int32,0);
+    opt_field(val->seq_number,3,asn1_decode_seqnum,0);
+    alloc_field(val->s_address,krb5_address);
+    get_field(*(val->s_address),4,asn1_decode_host_address);
+    if(tagnum == 5){
+      alloc_field(val->r_address,krb5_address);
+      get_field(*(val->r_address),5,asn1_decode_host_address);
+    } else val->r_address = NULL;
+    end_structure();
+    val->magic = KV5M_SAFE;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_host_address(asn1buf *buf, krb5_address *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->addrtype,0,asn1_decode_addrtype);
+    get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
+    end_structure();
+    val->magic = KV5M_ADDRESS;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_kdc_rep(asn1buf *buf, krb5_kdc_rep *val)
+{
+  setup();
+  { begin_structure();
+    { krb5_kvno pvno;
+      get_field(pvno,0,asn1_decode_kvno);
+      if(pvno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
+    get_field(val->msg_type,1,asn1_decode_msgtype);
+    opt_field(val->padata,2,asn1_decode_sequence_of_pa_data,NULL);
+    alloc_field(val->client,krb5_principal_data);
+    get_field(val->client,3,asn1_decode_realm);
+    get_field(val->client,4,asn1_decode_principal_name);
+    alloc_field(val->ticket,krb5_ticket);
+    get_field(*(val->ticket),5,asn1_decode_ticket);
+    get_field(val->enc_part,6,asn1_decode_encrypted_data);
+    end_structure();
+    val->magic = KV5M_KDC_REP;
+  }
+  cleanup();
+}
+
+
+/* arrays */
+#define get_element(element,decoder)\
+retval = decoder(&seqbuf,element);\
+if(retval) return retval
+     
+#define array_append(array,size,element,type)\
+size++;\
+if (*(array) == NULL)\
+     *(array) = (type**)malloc((size+1)*sizeof(type*));\
+else\
+  *(array) = (type**)realloc(*(array),\
+			     (size+1)*sizeof(type*));\
+if(*(array) == NULL) return ENOMEM;\
+(*(array))[(size)-1] = elt
+     
+#define decode_array_body(type,decoder)\
+  asn1_error_code retval;\
+  type *elt;\
+\
+  { sequence_of(buf);\
+    while(asn1buf_remains(&seqbuf,seqofindef) > 0){\
+      alloc_field(elt,type);\
+      get_element(elt,decoder);\
+      array_append(val,size,elt,type);\
+    }\
+    if (*val == NULL)\
+	*val = (type **)malloc(sizeof(type*));\
+    (*val)[size] = NULL;\
+    end_sequence_of(buf);\
+  }\
+  cleanup()
+
+
+asn1_error_code asn1_decode_authorization_data(asn1buf *buf, krb5_authdata ***val)
+{
+  decode_array_body(krb5_authdata,asn1_decode_authdata_elt);
+}
+
+asn1_error_code asn1_decode_authdata_elt(asn1buf *buf, krb5_authdata *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->ad_type,0,asn1_decode_authdatatype);
+    get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
+    end_structure();
+    val->magic = KV5M_AUTHDATA;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_host_addresses(asn1buf *buf, krb5_address ***val)
+{
+  decode_array_body(krb5_address,asn1_decode_host_address);
+}
+
+asn1_error_code asn1_decode_sequence_of_ticket(asn1buf *buf, krb5_ticket ***val)
+{
+  decode_array_body(krb5_ticket,asn1_decode_ticket);
+}
+
+asn1_error_code asn1_decode_sequence_of_krb_cred_info(asn1buf *buf, krb5_cred_info ***val)
+{
+  decode_array_body(krb5_cred_info,asn1_decode_krb_cred_info);
+}
+
+asn1_error_code asn1_decode_krb_cred_info(asn1buf *buf, krb5_cred_info *val)
+{
+  setup();
+  { begin_structure();
+    alloc_field(val->session,krb5_keyblock);
+    get_field(*(val->session),0,asn1_decode_encryption_key);
+    if(tagnum == 1){
+      alloc_field(val->client,krb5_principal_data);
+      opt_field(val->client,1,asn1_decode_realm,NULL);
+      opt_field(val->client,2,asn1_decode_principal_name,NULL); }
+    opt_field(val->flags,3,asn1_decode_ticket_flags,0);
+    opt_field(val->times.authtime,4,asn1_decode_kerberos_time,0);
+    opt_field(val->times.starttime,5,asn1_decode_kerberos_time,0);
+    opt_field(val->times.endtime,6,asn1_decode_kerberos_time,0);
+    opt_field(val->times.renew_till,7,asn1_decode_kerberos_time,0);
+    if(tagnum == 8){
+      alloc_field(val->server,krb5_principal_data);
+      opt_field(val->server,8,asn1_decode_realm,NULL);
+      opt_field(val->server,9,asn1_decode_principal_name,NULL); }
+    opt_field(val->caddrs,10,asn1_decode_host_addresses,NULL);
+    end_structure();
+    val->magic = KV5M_CRED_INFO;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_sequence_of_pa_data(asn1buf *buf, krb5_pa_data ***val)
+{
+  decode_array_body(krb5_pa_data,asn1_decode_pa_data);
+}
+
+asn1_error_code asn1_decode_pa_data(asn1buf *buf, krb5_pa_data *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->pa_type,1,asn1_decode_int32);
+    get_lenfield(val->length,val->contents,2,asn1_decode_octetstring);
+    end_structure();
+    val->magic = KV5M_PA_DATA;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_last_req(asn1buf *buf, krb5_last_req_entry ***val)
+{
+  decode_array_body(krb5_last_req_entry,asn1_decode_last_req_entry);
+}
+
+asn1_error_code asn1_decode_last_req_entry(asn1buf *buf, krb5_last_req_entry *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->lr_type,0,asn1_decode_int32);
+    get_field(val->value,1,asn1_decode_kerberos_time);
+    end_structure();
+    val->magic = KV5M_LAST_REQ_ENTRY;
+#ifdef KRB5_GENEROUS_LR_TYPE
+    /* If we are only a single byte wide and negative - fill in the
+       other bits */
+    if((val->lr_type & 0xffffff80U) == 0x80) val->lr_type |= 0xffffff00U;
+#endif
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_sequence_of_enctype(asn1buf *buf, int *num, krb5_enctype **val)
+{
+  asn1_error_code retval;
+  { sequence_of(buf);
+    while(asn1buf_remains(&seqbuf,seqofindef) > 0){
+      size++;
+      if (*val == NULL)
+        *val = (krb5_enctype*)malloc(size*sizeof(krb5_enctype));
+      else
+        *val = (krb5_enctype*)realloc(*val,size*sizeof(krb5_enctype));
+      if(*val == NULL) return ENOMEM;
+      retval = asn1_decode_enctype(&seqbuf,&((*val)[size-1]));
+      if(retval) return retval;
+    }
+    *num = size;
+    end_sequence_of(buf);
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_sequence_of_checksum(asn1buf *buf, krb5_checksum ***val)
+{
+  decode_array_body(krb5_checksum, asn1_decode_checksum);
+}
+
+static asn1_error_code asn1_decode_etype_info2_entry(asn1buf *buf, krb5_etype_info_entry *val )
+{
+  setup();
+  { begin_structure();
+    get_field(val->etype,0,asn1_decode_enctype);
+    if (tagnum == 1) {
+	    get_lenfield(val->length,val->salt,1,asn1_decode_generalstring);
+    } else {
+	    val->length = KRB5_ETYPE_NO_SALT;
+	    val->salt = 0;
+    }
+    if ( tagnum ==2) {
+      krb5_octet *params ;
+      get_lenfield( val->s2kparams.length, params,
+		      2, asn1_decode_octetstring);
+      val->s2kparams.data = ( char *) params;
+    } else {
+	val->s2kparams.data = NULL;
+	val->s2kparams.length = 0;
+    }
+    end_structure();
+    val->magic = KV5M_ETYPE_INFO_ENTRY;
+  }
+  cleanup();
+}
+
+static asn1_error_code asn1_decode_etype_info2_entry_1_3(asn1buf *buf, krb5_etype_info_entry *val )
+{
+  setup();
+  { begin_structure();
+    get_field(val->etype,0,asn1_decode_enctype);
+    if (tagnum == 1) {
+	    get_lenfield(val->length,val->salt,1,asn1_decode_octetstring);
+    } else {
+	    val->length = KRB5_ETYPE_NO_SALT;
+	    val->salt = 0;
+    }
+    if ( tagnum ==2) {
+      krb5_octet *params ;
+      get_lenfield( val->s2kparams.length, params,
+		      2, asn1_decode_octetstring);
+      val->s2kparams.data = ( char *) params;
+    } else {
+	val->s2kparams.data = NULL;
+	val->s2kparams.length = 0;
+    }
+    end_structure();
+    val->magic = KV5M_ETYPE_INFO_ENTRY;
+  }
+  cleanup();
+}
+
+
+static asn1_error_code asn1_decode_etype_info_entry(asn1buf *buf, krb5_etype_info_entry *val )
+{
+  setup();
+  { begin_structure();
+    get_field(val->etype,0,asn1_decode_enctype);
+    if (tagnum == 1) {
+	    get_lenfield(val->length,val->salt,1,asn1_decode_octetstring);
+    } else {
+	    val->length = KRB5_ETYPE_NO_SALT;
+	    val->salt = 0;
+    }
+    val->s2kparams.data = NULL;
+    val->s2kparams.length = 0;
+    
+    end_structure();
+    val->magic = KV5M_ETYPE_INFO_ENTRY;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_etype_info(asn1buf *buf, krb5_etype_info_entry ***val )
+{
+  decode_array_body(krb5_etype_info_entry,asn1_decode_etype_info_entry);
+}
+
+asn1_error_code asn1_decode_etype_info2(asn1buf *buf, krb5_etype_info_entry ***val ,
+					krb5_boolean v1_3_behavior)
+{
+    if (v1_3_behavior) {
+	decode_array_body(krb5_etype_info_entry,
+			  asn1_decode_etype_info2_entry_1_3);
+    } else {
+	decode_array_body(krb5_etype_info_entry,
+			  asn1_decode_etype_info2_entry);
+    }
+}
+
+asn1_error_code asn1_decode_passwdsequence(asn1buf *buf, passwd_phrase_element *val)
+{
+  setup();
+  { begin_structure();
+    alloc_field(val->passwd,krb5_data);
+    get_lenfield(val->passwd->length,val->passwd->data,
+		 0,asn1_decode_charstring);
+    val->passwd->magic = KV5M_DATA;
+    alloc_field(val->phrase,krb5_data);
+    get_lenfield(val->phrase->length,val->phrase->data,
+		 1,asn1_decode_charstring);
+    val->phrase->magic = KV5M_DATA;
+    end_structure();
+    val->magic = KV5M_PASSWD_PHRASE_ELEMENT;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_sequence_of_passwdsequence(asn1buf *buf, passwd_phrase_element ***val)
+{
+  decode_array_body(passwd_phrase_element,asn1_decode_passwdsequence);
+}
+
+asn1_error_code asn1_decode_sam_flags(asn1buf *buf, krb5_flags *val)
+{ return asn1_decode_krb5_flags(buf,val); }
+
+#define opt_string(val,n,fn) opt_lenfield((val).length,(val).data,n,fn)
+#define opt_cksum(var,tagexpect,decoder)\
+if(tagnum == (tagexpect)){\
+  get_field_body(var,decoder); }\
+else var.length = 0
+
+asn1_error_code asn1_decode_sam_challenge(asn1buf *buf, krb5_sam_challenge *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_type,0,asn1_decode_int32);
+    get_field(val->sam_flags,1,asn1_decode_sam_flags);
+    opt_string(val->sam_type_name,2,asn1_decode_charstring);
+    opt_string(val->sam_track_id,3,asn1_decode_charstring);
+    opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
+    opt_string(val->sam_challenge,5,asn1_decode_charstring);
+    opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
+    opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
+    opt_field(val->sam_nonce,8,asn1_decode_int32,0);
+    opt_cksum(val->sam_cksum,9,asn1_decode_checksum);
+    end_structure();
+    val->magic = KV5M_SAM_CHALLENGE;
+  }
+  cleanup();
+}
+asn1_error_code asn1_decode_sam_challenge_2(asn1buf *buf, krb5_sam_challenge_2 *val)
+{
+  setup();
+  { char *save, *end;
+    size_t alloclen;
+    begin_structure();
+    if (tagnum != 0) return ASN1_MISSING_FIELD;
+    if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED) 
+      return ASN1_BAD_ID;
+    save = subbuf.next;
+    { sequence_of_no_tagvars(&subbuf);
+      unused_var(size);
+      end_sequence_of_no_tagvars(&subbuf);
+    }
+    end = subbuf.next;
+    alloclen = end - save;
+    if ((val->sam_challenge_2_body.data = (char *) malloc(alloclen)) == NULL)
+      return ENOMEM;
+    val->sam_challenge_2_body.length = alloclen;
+    memcpy(val->sam_challenge_2_body.data, save, alloclen);
+    next_tag();
+    get_field(val->sam_cksum, 1, asn1_decode_sequence_of_checksum);
+    end_structure();
+  }
+  cleanup();
+}
+asn1_error_code asn1_decode_sam_challenge_2_body(asn1buf *buf, krb5_sam_challenge_2_body *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_type,0,asn1_decode_int32);
+    get_field(val->sam_flags,1,asn1_decode_sam_flags);
+    opt_string(val->sam_type_name,2,asn1_decode_charstring);
+    opt_string(val->sam_track_id,3,asn1_decode_charstring);
+    opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
+    opt_string(val->sam_challenge,5,asn1_decode_charstring);
+    opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
+    opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
+    get_field(val->sam_nonce,8,asn1_decode_int32);
+    get_field(val->sam_etype, 9, asn1_decode_int32);
+    end_structure();
+    val->magic = KV5M_SAM_CHALLENGE;
+  }
+  cleanup();
+}
+asn1_error_code asn1_decode_enc_sam_key(asn1buf *buf, krb5_sam_key *val)
+{
+  setup();
+  { begin_structure();
+    /* alloc_field(val->sam_key,krb5_keyblock); */
+    get_field(val->sam_key,0,asn1_decode_encryption_key);
+    end_structure();
+    val->magic = KV5M_SAM_KEY;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_enc_sam_response_enc(asn1buf *buf, krb5_enc_sam_response_enc *val)
+{
+  setup();
+  { begin_structure();
+    opt_field(val->sam_nonce,0,asn1_decode_int32,0);
+    opt_field(val->sam_timestamp,1,asn1_decode_kerberos_time,0);
+    opt_field(val->sam_usec,2,asn1_decode_int32,0);
+    opt_string(val->sam_sad,3,asn1_decode_charstring);
+    end_structure();
+    val->magic = KV5M_ENC_SAM_RESPONSE_ENC;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_enc_sam_response_enc_2(asn1buf *buf, krb5_enc_sam_response_enc_2 *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_nonce,0,asn1_decode_int32);
+    opt_string(val->sam_sad,1,asn1_decode_charstring);
+    end_structure();
+    val->magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
+  }
+  cleanup();
+}
+
+#define opt_encfield(fld,tag,fn) \
+    if(tagnum == tag){ \
+      get_field(fld,tag,fn); } \
+    else{\
+      fld.magic = 0;\
+      fld.enctype = 0;\
+      fld.kvno = 0;\
+      fld.ciphertext.data = NULL;\
+      fld.ciphertext.length = 0;\
+    }
+
+asn1_error_code asn1_decode_sam_response(asn1buf *buf, krb5_sam_response *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_type,0,asn1_decode_int32);
+    get_field(val->sam_flags,1,asn1_decode_sam_flags);
+    opt_string(val->sam_track_id,2,asn1_decode_charstring);
+    opt_encfield(val->sam_enc_key,3,asn1_decode_encrypted_data);
+    get_field(val->sam_enc_nonce_or_ts,4,asn1_decode_encrypted_data);
+    opt_field(val->sam_nonce,5,asn1_decode_int32,0);
+    opt_field(val->sam_patimestamp,6,asn1_decode_kerberos_time,0);
+    end_structure();
+    val->magic = KV5M_SAM_RESPONSE;
+  }
+  cleanup();
+}
+
+asn1_error_code asn1_decode_sam_response_2(asn1buf *buf, krb5_sam_response_2 *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_type,0,asn1_decode_int32);
+    get_field(val->sam_flags,1,asn1_decode_sam_flags);
+    opt_string(val->sam_track_id,2,asn1_decode_charstring);
+    get_field(val->sam_enc_nonce_or_sad,3,asn1_decode_encrypted_data);
+    get_field(val->sam_nonce,4,asn1_decode_int32);
+    end_structure();
+    val->magic = KV5M_SAM_RESPONSE;
+  }
+  cleanup();
+}
+
+
+asn1_error_code asn1_decode_predicted_sam_response(asn1buf *buf, krb5_predicted_sam_response *val)
+{
+  setup();
+  { begin_structure();
+    get_field(val->sam_key,0,asn1_decode_encryption_key);
+    get_field(val->sam_flags,1,asn1_decode_sam_flags);
+    get_field(val->stime,2,asn1_decode_kerberos_time);
+    get_field(val->susec,3,asn1_decode_int32);
+    alloc_field(val->client,krb5_principal_data);
+    get_field(val->client,4,asn1_decode_realm);
+    get_field(val->client,5,asn1_decode_principal_name);
+    opt_string(val->msd,6,asn1_decode_charstring); /* should be octet */
+    end_structure();
+    val->magic = KV5M_PREDICTED_SAM_RESPONSE;
+  }
+  cleanup();
+}
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_k_decode.h b/mechglue/src/lib/krb5/asn.1/asn1_k_decode.h
new file mode 100644
index 000000000..22e43fd73
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_k_decode.h
@@ -0,0 +1,192 @@
+/*
+ * src/lib/krb5/asn.1/asn1_k_decode.h
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __ASN1_DECODE_KRB5_H__
+#define __ASN1_DECODE_KRB5_H__
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "asn1buf.h"
+
+/* asn1_error_code asn1_decode_scalar_type(asn1buf *buf, krb5_scalar *val); */
+/* requires  *buf is allocated, *buf's current position points to the
+              beginning of an encoding (<id> <len> <contents>),
+	      *val is allocated
+   effects   Decodes the encoding in *buf, returning the result in *val.
+             Returns ASN1_BAD_ID if the encoded id does not
+	      indicate the proper type.
+             Returns ASN1_OVERRUN if the encoded length exceeds
+	      the bounds of *buf */
+
+
+/* asn1_error_code asn1_decode_structure_type(asn1buf *buf,
+                                              krb5_structure *val); */
+/* requires  *buf is allocated, *buf's current position points to the
+              beginning of an encoding (<id> <len> <contents>),
+	      *val is allocated
+	     Assumes that *val is a freshly-allocated structure (i.e.
+	      does not attempt to clean up or free *val).
+   effects   Decodes the encoding in *buf, returning the result in *val.
+             Returns ASN1_BAD_ID if the encoded id does not
+	      indicate the proper type.
+             Returns ASN1_OVERRUN if the encoded length exceeds
+	      the bounds of *buf */
+
+/* asn1_error_code asn1_decode_array_type(asn1buf *buf, krb5_scalar ***val); */
+/* requires  *buf is allocated, *buf's current position points to the
+              beginning of an encoding (<id> <len> <contents>)
+	     Assumes that *val is empty (i.e. does not attempt to
+	      clean up or free *val).
+   effects   Decodes the encoding in *buf, returning the result in *val.
+             Returns ASN1_BAD_ID if the encoded id does not
+	      indicate the proper type.
+             Returns ASN1_OVERRUN if the encoded length exceeds
+	      the bounds of *buf */
+
+/* scalars */
+asn1_error_code asn1_decode_int
+	(asn1buf *buf, int *val);
+asn1_error_code asn1_decode_int32
+	(asn1buf *buf, krb5_int32 *val);
+asn1_error_code asn1_decode_kvno
+	(asn1buf *buf, krb5_kvno *val);
+asn1_error_code asn1_decode_enctype
+	(asn1buf *buf, krb5_enctype *val);
+asn1_error_code asn1_decode_msgtype
+	(asn1buf *buf, krb5_msgtype *val);
+asn1_error_code asn1_decode_cksumtype
+	(asn1buf *buf, krb5_cksumtype *val);
+asn1_error_code asn1_decode_octet
+	(asn1buf *buf, krb5_octet *val);
+asn1_error_code asn1_decode_addrtype
+	(asn1buf *buf, krb5_addrtype *val);
+asn1_error_code asn1_decode_authdatatype
+	(asn1buf *buf, krb5_authdatatype *val);
+asn1_error_code asn1_decode_ui_2
+	(asn1buf *buf, krb5_ui_2 *val);
+asn1_error_code asn1_decode_ui_4
+	(asn1buf *buf, krb5_ui_4 *val);
+asn1_error_code asn1_decode_seqnum
+	(asn1buf *buf, krb5_ui_4 *val);
+asn1_error_code asn1_decode_kerberos_time
+	(asn1buf *buf, krb5_timestamp *val);
+asn1_error_code asn1_decode_sam_flags
+	(asn1buf *buf, krb5_flags *val);
+
+/* structures */
+asn1_error_code asn1_decode_realm
+	(asn1buf *buf, krb5_principal *val);
+asn1_error_code asn1_decode_principal_name
+	(asn1buf *buf, krb5_principal *val);
+asn1_error_code asn1_decode_checksum
+	(asn1buf *buf, krb5_checksum *val);
+asn1_error_code asn1_decode_encryption_key
+	(asn1buf *buf, krb5_keyblock *val);
+asn1_error_code asn1_decode_encrypted_data
+	(asn1buf *buf, krb5_enc_data *val);
+asn1_error_code asn1_decode_ticket_flags
+	(asn1buf *buf, krb5_flags *val);
+asn1_error_code asn1_decode_transited_encoding
+	(asn1buf *buf, krb5_transited *val);
+asn1_error_code asn1_decode_enc_kdc_rep_part
+	(asn1buf *buf, krb5_enc_kdc_rep_part *val);
+asn1_error_code asn1_decode_krb5_flags
+	(asn1buf *buf, krb5_flags *val);
+asn1_error_code asn1_decode_ap_options
+	(asn1buf *buf, krb5_flags *val);
+asn1_error_code asn1_decode_kdc_options
+	(asn1buf *buf, krb5_flags *val);
+asn1_error_code asn1_decode_ticket
+	(asn1buf *buf, krb5_ticket *val);
+asn1_error_code asn1_decode_kdc_req
+	(asn1buf *buf, krb5_kdc_req *val);
+asn1_error_code asn1_decode_kdc_req_body
+	(asn1buf *buf, krb5_kdc_req *val);
+asn1_error_code asn1_decode_krb_safe_body
+	(asn1buf *buf, krb5_safe *val);
+asn1_error_code asn1_decode_host_address
+	(asn1buf *buf, krb5_address *val);
+asn1_error_code asn1_decode_kdc_rep
+	(asn1buf *buf, krb5_kdc_rep *val);
+asn1_error_code asn1_decode_last_req_entry
+	(asn1buf *buf, krb5_last_req_entry *val);
+asn1_error_code asn1_decode_authdata_elt
+	(asn1buf *buf, krb5_authdata *val);
+asn1_error_code asn1_decode_krb_cred_info
+	(asn1buf *buf, krb5_cred_info *val);
+asn1_error_code asn1_decode_pa_data
+	(asn1buf *buf, krb5_pa_data *val);
+asn1_error_code asn1_decode_passwdsequence
+	(asn1buf *buf, passwd_phrase_element *val);
+asn1_error_code asn1_decode_sam_challenge
+	(asn1buf *buf, krb5_sam_challenge *val);
+asn1_error_code asn1_decode_sam_challenge_2
+	(asn1buf *buf, krb5_sam_challenge_2 *val);
+asn1_error_code asn1_decode_sam_challenge_2_body
+	(asn1buf *buf, krb5_sam_challenge_2_body *val);
+asn1_error_code asn1_decode_enc_sam_key
+	(asn1buf *buf, krb5_sam_key *val);
+asn1_error_code asn1_decode_enc_sam_response_enc
+	(asn1buf *buf, krb5_enc_sam_response_enc *val);
+asn1_error_code asn1_decode_enc_sam_response_enc_2
+	(asn1buf *buf, krb5_enc_sam_response_enc_2 *val);
+asn1_error_code asn1_decode_sam_response
+	(asn1buf *buf, krb5_sam_response *val);
+asn1_error_code asn1_decode_sam_response_2
+	(asn1buf *buf, krb5_sam_response_2 *val);
+asn1_error_code asn1_decode_predicted_sam_response
+	(asn1buf *buf, krb5_predicted_sam_response *val);
+
+/* arrays */
+asn1_error_code asn1_decode_authorization_data
+	(asn1buf *buf, krb5_authdata ***val);
+asn1_error_code asn1_decode_host_addresses
+	(asn1buf *buf, krb5_address ***val);
+asn1_error_code asn1_decode_sequence_of_ticket
+	(asn1buf *buf, krb5_ticket ***val);
+asn1_error_code asn1_decode_sequence_of_krb_cred_info
+	(asn1buf *buf, krb5_cred_info ***val);
+asn1_error_code asn1_decode_sequence_of_pa_data
+	(asn1buf *buf, krb5_pa_data ***val);
+asn1_error_code asn1_decode_last_req
+	(asn1buf *buf, krb5_last_req_entry ***val);
+
+asn1_error_code asn1_decode_sequence_of_enctype
+	(asn1buf *buf, int *num, krb5_enctype **val);
+
+asn1_error_code asn1_decode_sequence_of_checksum
+	(asn1buf *buf, krb5_checksum ***val);
+
+asn1_error_code asn1_decode_sequence_of_passwdsequence
+	(asn1buf *buf, passwd_phrase_element ***val);
+
+asn1_error_code asn1_decode_etype_info
+	(asn1buf *buf, krb5_etype_info_entry ***val);
+asn1_error_code asn1_decode_etype_info2
+	(asn1buf *buf, krb5_etype_info_entry ***val, krb5_boolean v1_3_behavior);
+
+
+#endif
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_k_encode.c b/mechglue/src/lib/krb5/asn.1/asn1_k_encode.c
new file mode 100644
index 000000000..00cfab032
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_k_encode.c
@@ -0,0 +1,961 @@
+/*
+ * src/lib/krb5/asn.1/asn1_k_encode.c
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_k_encode.h"
+#include "asn1_make.h"
+#include "asn1_encode.h"
+#include <assert.h>
+
+/**** asn1 macros ****/
+#if 0
+   How to write an asn1 encoder function using these macros:
+
+   asn1_error_code asn1_encode_krb5_substructure(asn1buf *buf,
+                                                 const krb5_type *val,
+                                                 int *retlen)
+   {
+     asn1_setup();
+
+     asn1_addfield(val->last_field, n, asn1_type);
+     asn1_addfield(rep->next_to_last_field, n-1, asn1_type);
+     ...
+
+     /* for OPTIONAL fields */
+     if(rep->field_i == should_not_be_omitted)
+       asn1_addfield(rep->field_i, i, asn1_type);
+
+     /* for string fields (these encoders take an additional argument,
+	the length of the string) */
+     addlenfield(rep->field_length, rep->field, i-1, asn1_type);
+
+     /* if you really have to do things yourself... */
+     retval = asn1_encode_asn1_type(buf,rep->field,&length);
+     if(retval) return retval;
+     sum += length;
+     retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, tag_number, length,
+			     &length);
+     if(retval) return retval;
+     sum += length;
+
+     ...
+     asn1_addfield(rep->second_field, 1, asn1_type);
+     asn1_addfield(rep->first_field, 0, asn1_type);
+     asn1_makeseq();
+
+     asn1_cleanup();
+   }
+#endif
+
+/* setup() -- create and initialize bookkeeping variables
+     retval: stores error codes returned from subroutines
+     length: length of the most-recently produced encoding
+     sum: cumulative length of the entire encoding */
+#define asn1_setup()\
+  asn1_error_code retval;\
+  unsigned int length, sum=0
+  
+/* asn1_addfield -- add a field, or component, to the encoding */
+#define asn1_addfield(value,tag,encoder)\
+{ retval = encoder(buf,value,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length;\
+  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length; }
+
+/* asn1_addlenfield -- add a field whose length must be separately specified */
+#define asn1_addlenfield(len,value,tag,encoder)\
+{ retval = encoder(buf,len,value,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length;\
+  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length; }
+
+/* form a sequence (by adding a sequence header to the current encoding) */
+#define asn1_makeseq()\
+  retval = asn1_make_sequence(buf,sum,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length
+
+/* add an APPLICATION class tag to the current encoding */
+#define asn1_apptag(num)\
+  retval = asn1_make_etag(buf,APPLICATION,num,sum,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length
+
+/* produce the final output and clean up the workspace */
+#define asn1_cleanup()\
+  *retlen = sum;\
+  return 0
+
+asn1_error_code asn1_encode_ui_4(asn1buf *buf, const krb5_ui_4 val, unsigned int *retlen)
+{
+  return asn1_encode_unsigned_integer(buf,val,retlen);
+}
+
+
+asn1_error_code asn1_encode_realm(asn1buf *buf, const krb5_principal val, unsigned int *retlen)
+{
+  if (val == NULL ||
+      (val->realm.length && val->realm.data == NULL))
+	  return ASN1_MISSING_FIELD;
+  return asn1_encode_generalstring(buf,val->realm.length,val->realm.data,
+				   retlen);
+}
+
+asn1_error_code asn1_encode_principal_name(asn1buf *buf, const krb5_principal val, unsigned int *retlen)
+{
+  asn1_setup();
+  int n;
+
+  if (val == NULL || val->data == NULL) return ASN1_MISSING_FIELD;
+
+  for(n = (int) ((val->length)-1); n >= 0; n--){
+    if (val->data[n].length &&
+	val->data[n].data == NULL)
+	    return ASN1_MISSING_FIELD;
+    retval = asn1_encode_generalstring(buf,
+				       (val->data)[n].length,
+				       (val->data)[n].data,
+				       &length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,1,sum,&length);
+  if(retval) return retval;
+  sum += length;
+
+  asn1_addfield(val->type,0,asn1_encode_integer);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_kerberos_time(asn1buf *buf, const krb5_timestamp val, unsigned int *retlen)
+{
+  return asn1_encode_generaltime(buf,val,retlen);
+}
+
+asn1_error_code asn1_encode_host_address(asn1buf *buf, const krb5_address *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if (val == NULL || val->contents == NULL) return ASN1_MISSING_FIELD;
+
+  asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
+  asn1_addfield(val->addrtype,0,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_host_addresses(asn1buf *buf, const krb5_address **val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+
+  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+
+  for(i=0; val[i] != NULL; i++); /* go to end of array */
+  for(i--; i>=0; i--){
+    retval = asn1_encode_host_address(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_encrypted_data(asn1buf *buf, const krb5_enc_data *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL ||
+     (val->ciphertext.length && val->ciphertext.data == NULL))
+	  return ASN1_MISSING_FIELD;
+
+  asn1_addlenfield(val->ciphertext.length,val->ciphertext.data,2,asn1_encode_charstring);
+  /* krb5_kvno should be int */
+  if(val->kvno)
+    asn1_addfield((int) val->kvno,1,asn1_encode_integer);
+  asn1_addfield(val->enctype,0,asn1_encode_integer);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_krb5_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
+{
+  asn1_setup();
+  krb5_flags valcopy = val;
+  int i;
+
+  for(i=0; i<4; i++){
+    retval = asn1buf_insert_octet(buf,(asn1_octet) (valcopy&0xFF));
+    if(retval) return retval;
+    valcopy >>= 8;
+  }
+  retval = asn1buf_insert_octet(buf,0);	/* 0 padding bits */
+  if(retval) return retval;
+  sum = 5;
+
+  retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_BITSTRING,sum,
+			 &length);
+  if(retval) return retval;
+  sum += length;
+
+  *retlen = sum;
+  return 0;
+}
+
+asn1_error_code asn1_encode_ap_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
+{
+  return asn1_encode_krb5_flags(buf,val,retlen);
+}
+
+asn1_error_code asn1_encode_ticket_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
+{
+  return asn1_encode_krb5_flags(buf,val,retlen);
+}
+
+asn1_error_code asn1_encode_kdc_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
+{
+  return asn1_encode_krb5_flags(buf,val,retlen);
+}
+
+asn1_error_code asn1_encode_authorization_data(asn1buf *buf, const krb5_authdata **val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+  
+  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+  
+  for(i=0; val[i] != NULL; i++); /* get to the end of the array */
+  for(i--; i>=0; i--){
+    retval = asn1_encode_krb5_authdata_elt(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_krb5_authdata_elt(asn1buf *buf, const krb5_authdata *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if (val == NULL ||
+     (val->length && val->contents == NULL))
+	  return ASN1_MISSING_FIELD;
+
+  /* ad-data[1]		OCTET STRING */
+  asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
+  /* ad-type[0]		INTEGER */
+  asn1_addfield(val->ad_type,0,asn1_encode_integer);
+  /* SEQUENCE */
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_kdc_rep(int msg_type, asn1buf *buf, const krb5_kdc_rep *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  asn1_addfield(&(val->enc_part),6,asn1_encode_encrypted_data);
+  asn1_addfield(val->ticket,5,asn1_encode_ticket);
+  asn1_addfield(val->client,4,asn1_encode_principal_name);
+  asn1_addfield(val->client,3,asn1_encode_realm);
+  if(val->padata != NULL && val->padata[0] != NULL)
+    asn1_addfield((const krb5_pa_data**)val->padata,2,asn1_encode_sequence_of_pa_data);
+  if (msg_type != KRB5_AS_REP && msg_type != KRB5_TGS_REP)
+	  return KRB5_BADMSGTYPE;
+  asn1_addfield(msg_type,1,asn1_encode_integer);
+  asn1_addfield(KVNO,0,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_enc_kdc_rep_part(asn1buf *buf, const krb5_enc_kdc_rep_part *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  /* caddr[11]		HostAddresses OPTIONAL */
+  if(val->caddrs != NULL && val->caddrs[0] != NULL)
+    asn1_addfield((const krb5_address**)(val->caddrs),11,asn1_encode_host_addresses);
+
+  /* sname[10]		PrincipalName */
+  asn1_addfield(val->server,10,asn1_encode_principal_name);
+
+  /* srealm[9]		Realm */
+  asn1_addfield(val->server,9,asn1_encode_realm);
+
+  /* renew-till[8]	KerberosTime OPTIONAL */
+  if(val->flags & TKT_FLG_RENEWABLE)
+    asn1_addfield(val->times.renew_till,8,asn1_encode_kerberos_time);
+
+  /* endtime[7]		KerberosTime */
+  asn1_addfield(val->times.endtime,7,asn1_encode_kerberos_time);
+
+  /* starttime[6]	KerberosTime OPTIONAL */
+  if(val->times.starttime)
+    asn1_addfield(val->times.starttime,6,asn1_encode_kerberos_time);
+
+  /* authtime[5]	KerberosTime */
+  asn1_addfield(val->times.authtime,5,asn1_encode_kerberos_time);
+
+  /* flags[4]		TicketFlags */
+  asn1_addfield(val->flags,4,asn1_encode_ticket_flags);
+
+  /* key-expiration[3]	KerberosTime OPTIONAL */
+  if(val->key_exp)
+    asn1_addfield(val->key_exp,3,asn1_encode_kerberos_time);
+
+  /* nonce[2]		INTEGER */
+  asn1_addfield(val->nonce,2,asn1_encode_integer);
+
+  /* last-req[1]	LastReq */
+  asn1_addfield((const krb5_last_req_entry**)val->last_req,1,asn1_encode_last_req);
+
+  /* key[0]		EncryptionKey */
+  asn1_addfield(val->session,0,asn1_encode_encryption_key);
+
+  /* EncKDCRepPart ::= SEQUENCE */
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sequence_of_checksum(asn1buf *buf, const krb5_checksum ** val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  for (i=0; val[i] != NULL; i++);
+  for (i--; i>=0; i--){
+    retval = asn1_encode_checksum(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *rep, unsigned int *retlen)
+{
+  asn1_setup();
+  
+  if(rep == NULL) return ASN1_MISSING_FIELD;
+
+  /* additional-tickets[11]	SEQUENCE OF Ticket OPTIONAL */
+  if(rep->second_ticket != NULL && rep->second_ticket[0] != NULL)
+    asn1_addfield((const krb5_ticket**)rep->second_ticket,
+		  11,asn1_encode_sequence_of_ticket);
+
+  /* enc-authorization-data[10]	EncryptedData OPTIONAL, */
+  /* 				-- Encrypted AuthorizationData encoding */
+  if(rep->authorization_data.ciphertext.data != NULL)
+    asn1_addfield(&(rep->authorization_data),10,asn1_encode_encrypted_data);
+
+  /* addresses[9]		HostAddresses OPTIONAL, */
+  if(rep->addresses != NULL && rep->addresses[0] != NULL)
+    asn1_addfield((const krb5_address**)rep->addresses,9,asn1_encode_host_addresses);
+
+  /* etype[8]			SEQUENCE OF INTEGER, -- EncryptionType, */
+  /* 				-- in preference order */
+  asn1_addlenfield(rep->nktypes,rep->ktype,8,asn1_encode_sequence_of_enctype);
+
+  /* nonce[7]			INTEGER, */
+  asn1_addfield(rep->nonce,7,asn1_encode_integer);
+
+  /* rtime[6]			KerberosTime OPTIONAL, */
+  if(rep->rtime)
+    asn1_addfield(rep->rtime,6,asn1_encode_kerberos_time);
+
+  /* till[5]			KerberosTime, */
+  asn1_addfield(rep->till,5,asn1_encode_kerberos_time);
+
+  /* from[4]			KerberosTime OPTIONAL, */
+  if(rep->from)
+  asn1_addfield(rep->from,4,asn1_encode_kerberos_time);
+
+  /* sname[3]			PrincipalName OPTIONAL, */
+  if(rep->server != NULL)
+    asn1_addfield(rep->server,3,asn1_encode_principal_name);
+
+  /* realm[2]			Realm, -- Server's realm */
+  /* 				-- Also client's in AS-REQ */
+  if(rep->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY){
+    if(rep->second_ticket != NULL && rep->second_ticket[0] != NULL){
+      asn1_addfield(rep->second_ticket[0]->server,2,asn1_encode_realm)
+    } else return ASN1_MISSING_FIELD;
+  }else if(rep->server != NULL){
+    asn1_addfield(rep->server,2,asn1_encode_realm);
+  }else return ASN1_MISSING_FIELD;
+
+  /* cname[1]			PrincipalName OPTIONAL, */
+  /* 				-- Used only in AS-REQ */
+  if(rep->client != NULL)
+    asn1_addfield(rep->client,1,asn1_encode_principal_name);
+
+  /* kdc-options[0]		KDCOptions, */
+  asn1_addfield(rep->kdc_options,0,asn1_encode_kdc_options);
+
+  /* KDC-REQ-BODY ::= SEQUENCE */
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_encryption_key(asn1buf *buf, const krb5_keyblock *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if (val == NULL ||
+      (val->length && val->contents == NULL))
+	  return ASN1_MISSING_FIELD;
+
+  asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
+  asn1_addfield(val->enctype,0,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_checksum(asn1buf *buf, const krb5_checksum *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if (val == NULL ||
+     (val->length && val->contents == NULL))
+	  return ASN1_MISSING_FIELD;
+
+  asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
+  asn1_addfield(val->checksum_type,0,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_transited_encoding(asn1buf *buf, const krb5_transited *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL ||
+     (val->tr_contents.length != 0 && val->tr_contents.data == NULL))
+    return ASN1_MISSING_FIELD;
+
+  asn1_addlenfield(val->tr_contents.length,val->tr_contents.data,
+		   1,asn1_encode_charstring);
+  asn1_addfield(val->tr_type,0,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_last_req(asn1buf *buf, const krb5_last_req_entry **val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+
+  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+
+  for(i=0; val[i] != NULL; i++); /* go to end of array */
+  for(i--; i>=0; i--){
+    retval = asn1_encode_last_req_entry(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_last_req_entry(asn1buf *buf, const krb5_last_req_entry *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  asn1_addfield(val->value,1,asn1_encode_kerberos_time);
+  asn1_addfield(val->lr_type,0,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sequence_of_pa_data(asn1buf *buf, const krb5_pa_data **val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+
+  if (val == NULL) return ASN1_MISSING_FIELD;
+
+  for(i=0; val[i] != NULL; i++);
+  for(i--; i>=0; i--){
+    retval = asn1_encode_pa_data(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_pa_data(asn1buf *buf, const krb5_pa_data *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL || (val->length != 0 && val->contents == NULL))
+     return ASN1_MISSING_FIELD;
+
+  asn1_addlenfield(val->length,val->contents,2,asn1_encode_octetstring);
+  asn1_addfield(val->pa_type,1,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sequence_of_ticket(asn1buf *buf, const krb5_ticket **val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+
+  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+
+  for(i=0; val[i] != NULL; i++);
+  for(i--; i>=0; i--){
+    retval = asn1_encode_ticket(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_ticket(asn1buf *buf, const krb5_ticket *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  asn1_addfield(&(val->enc_part),3,asn1_encode_encrypted_data);
+  asn1_addfield(val->server,2,asn1_encode_principal_name);
+  asn1_addfield(val->server,1,asn1_encode_realm);
+  asn1_addfield(KVNO,0,asn1_encode_integer);
+  asn1_makeseq();
+  asn1_apptag(1);
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sequence_of_enctype(asn1buf *buf, const int len, const krb5_enctype *val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  for(i=len-1; i>=0; i--){
+    retval = asn1_encode_integer(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_kdc_req(int msg_type, asn1buf *buf, const krb5_kdc_req *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  asn1_addfield(val,4,asn1_encode_kdc_req_body);
+  if(val->padata != NULL && val->padata[0] != NULL)
+    asn1_addfield((const krb5_pa_data**)val->padata,3,asn1_encode_sequence_of_pa_data);
+  if (msg_type != KRB5_AS_REQ && msg_type != KRB5_TGS_REQ)
+	  return KRB5_BADMSGTYPE;
+  asn1_addfield(msg_type,2,asn1_encode_integer);
+  asn1_addfield(KVNO,1,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_krb_safe_body(asn1buf *buf, const krb5_safe *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  if(val->r_address != NULL)
+    asn1_addfield(val->r_address,5,asn1_encode_host_address);
+  asn1_addfield(val->s_address,4,asn1_encode_host_address);
+  if(val->seq_number)
+    asn1_addfield(val->seq_number,3,asn1_encode_unsigned_integer);
+  if(val->timestamp){
+    asn1_addfield(val->usec,2,asn1_encode_integer);
+    asn1_addfield(val->timestamp,1,asn1_encode_kerberos_time);
+  }
+  if (val->user_data.length && val->user_data.data == NULL)
+	  return ASN1_MISSING_FIELD;
+  asn1_addlenfield(val->user_data.length,val->user_data.data,0,asn1_encode_charstring)
+;
+
+  asn1_makeseq();
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sequence_of_krb_cred_info(asn1buf *buf, const krb5_cred_info **val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  for(i=0; val[i] != NULL; i++);
+  for(i--; i>=0; i--){
+    retval = asn1_encode_krb_cred_info(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_krb_cred_info(asn1buf *buf, const krb5_cred_info *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if(val == NULL) return ASN1_MISSING_FIELD;
+
+  if(val->caddrs != NULL && val->caddrs[0] != NULL)
+    asn1_addfield((const krb5_address**)val->caddrs,10,asn1_encode_host_addresses);
+  if(val->server != NULL){
+    asn1_addfield(val->server,9,asn1_encode_principal_name);
+    asn1_addfield(val->server,8,asn1_encode_realm);
+  }
+  if(val->times.renew_till)
+    asn1_addfield(val->times.renew_till,7,asn1_encode_kerberos_time);
+  if(val->times.endtime)
+    asn1_addfield(val->times.endtime,6,asn1_encode_kerberos_time);
+  if(val->times.starttime)
+    asn1_addfield(val->times.starttime,5,asn1_encode_kerberos_time);
+  if(val->times.authtime)
+    asn1_addfield(val->times.authtime,4,asn1_encode_kerberos_time);
+  if(val->flags)
+    asn1_addfield(val->flags,3,asn1_encode_ticket_flags);
+  if(val->client != NULL){
+    asn1_addfield(val->client,2,asn1_encode_principal_name);
+    asn1_addfield(val->client,1,asn1_encode_realm);
+  }
+  asn1_addfield(val->session,0,asn1_encode_encryption_key);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_etype_info_entry(asn1buf *buf, const krb5_etype_info_entry *val,
+					     unsigned int *retlen, int etype_info2)
+{
+  asn1_setup();
+
+  assert(val->s2kparams.data == NULL || etype_info2);
+  if(val == NULL || (val->length > 0 && val->length != KRB5_ETYPE_NO_SALT &&
+		     val->salt == NULL))
+     return ASN1_MISSING_FIELD;
+  if(val->s2kparams.data != NULL)
+      asn1_addlenfield(val->s2kparams.length, val->s2kparams.data, 2,
+		       asn1_encode_octetstring);
+  if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT){
+      if (etype_info2)
+	  asn1_addlenfield(val->length,val->salt,1,
+			   asn1_encode_generalstring)
+      else 	  asn1_addlenfield(val->length,val->salt,1,
+				   asn1_encode_octetstring);
+  }
+asn1_addfield(val->etype,0,asn1_encode_integer);
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_etype_info(asn1buf *buf, const krb5_etype_info_entry **val,
+				       unsigned int *retlen, int etype_info2)
+{
+    asn1_setup();
+    int i;
+  
+    if (val == NULL) return ASN1_MISSING_FIELD;
+  
+    for(i=0; val[i] != NULL; i++); /* get to the end of the array */
+    for(i--; i>=0; i--){
+	retval = asn1_encode_etype_info_entry(buf,val[i],&length, etype_info2);
+	if(retval) return retval;
+	sum += length;
+    }
+    asn1_makeseq();
+    asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sequence_of_passwdsequence(asn1buf *buf, const passwd_phrase_element **val, unsigned int *retlen)
+{
+  asn1_setup();
+  int i;
+  
+  if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
+  
+  for(i=0; val[i] != NULL; i++); /* get to the end of the array */
+  for(i--; i>=0; i--){
+    retval = asn1_encode_passwdsequence(buf,val[i],&length);
+    if(retval) return retval;
+    sum += length;
+  }
+  asn1_makeseq();
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_passwdsequence(asn1buf *buf, const passwd_phrase_element *val, unsigned int *retlen)
+{
+  asn1_setup();
+  asn1_addlenfield(val->phrase->length,val->phrase->data,1,asn1_encode_charstring);
+  asn1_addlenfield(val->passwd->length,val->passwd->data,0,asn1_encode_charstring);
+  asn1_makeseq();
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sam_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
+{
+  return asn1_encode_krb5_flags(buf,val,retlen);
+}
+
+#define add_optstring(val,n,fn) \
+     if ((val).length > 0) {asn1_addlenfield((val).length,(val).data,n,fn);}
+
+asn1_error_code asn1_encode_sam_challenge(asn1buf *buf, const krb5_sam_challenge *val, unsigned int *retlen)
+{
+  asn1_setup();
+  /* possibly wrong */
+  if (val->sam_cksum.length)
+    asn1_addfield(&(val->sam_cksum),9,asn1_encode_checksum);
+
+  if (val->sam_nonce)
+    asn1_addfield(val->sam_nonce,8,asn1_encode_integer);
+
+  add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring);
+  add_optstring(val->sam_response_prompt,6,asn1_encode_charstring);
+  add_optstring(val->sam_challenge,5,asn1_encode_charstring);
+  add_optstring(val->sam_challenge_label,4,asn1_encode_charstring);
+  add_optstring(val->sam_track_id,3,asn1_encode_charstring);
+  add_optstring(val->sam_type_name,2,asn1_encode_charstring);
+
+  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
+  asn1_addfield(val->sam_type,0,asn1_encode_integer);
+
+  asn1_makeseq();
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *val, unsigned int *retlen)
+{
+  asn1_setup();
+  if ( (!val) || (!val->sam_cksum) || (!val->sam_cksum[0]))
+      return ASN1_MISSING_FIELD;
+
+  asn1_addfield((const krb5_checksum **) val->sam_cksum, 1, asn1_encode_sequence_of_checksum);
+  retval = asn1buf_insert_octetstring(buf, val->sam_challenge_2_body.length,
+				      (unsigned char *)val->sam_challenge_2_body.data);
+  if(retval){
+	  asn1buf_destroy(&buf);
+	  return retval; 
+  }
+  sum += val->sam_challenge_2_body.length;
+  retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0,
+			  val->sam_challenge_2_body.length, &length);
+  if(retval) {
+	  asn1buf_destroy(&buf);
+	  return retval;
+  }
+  sum += length;
+  
+  asn1_makeseq();
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sam_challenge_2_body(asn1buf *buf, const krb5_sam_challenge_2_body *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  asn1_addfield(val->sam_etype, 9, asn1_encode_integer);
+  asn1_addfield(val->sam_nonce,8,asn1_encode_integer);
+  add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring);
+  add_optstring(val->sam_response_prompt,6,asn1_encode_charstring);
+  add_optstring(val->sam_challenge,5,asn1_encode_charstring);
+  add_optstring(val->sam_challenge_label,4,asn1_encode_charstring);
+  add_optstring(val->sam_track_id,3,asn1_encode_charstring);
+  add_optstring(val->sam_type_name,2,asn1_encode_charstring);
+
+  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
+  asn1_addfield(val->sam_type,0,asn1_encode_integer);
+
+  asn1_makeseq();
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sam_key(asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen)
+{
+  asn1_setup();
+  asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+
+asn1_error_code asn1_encode_enc_sam_response_enc(asn1buf *buf, const krb5_enc_sam_response_enc *val, unsigned int *retlen)
+{
+  asn1_setup();
+  add_optstring(val->sam_sad,3,asn1_encode_charstring);
+  asn1_addfield(val->sam_usec,2,asn1_encode_integer);
+  asn1_addfield(val->sam_timestamp,1,asn1_encode_kerberos_time);
+  asn1_addfield(val->sam_nonce,0,asn1_encode_integer);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_enc_sam_response_enc_2(asn1buf *buf, const krb5_enc_sam_response_enc_2 *val, unsigned int *retlen)
+{
+  asn1_setup();
+  add_optstring(val->sam_sad,1,asn1_encode_charstring);
+  asn1_addfield(val->sam_nonce,0,asn1_encode_integer);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sam_response(asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  if (val->sam_patimestamp)
+    asn1_addfield(val->sam_patimestamp,6,asn1_encode_kerberos_time);
+  if (val->sam_nonce)
+    asn1_addfield(val->sam_nonce,5,asn1_encode_integer);
+  asn1_addfield(&(val->sam_enc_nonce_or_ts),4,asn1_encode_encrypted_data);
+  if (val->sam_enc_key.ciphertext.length)
+    asn1_addfield(&(val->sam_enc_key),3,asn1_encode_encrypted_data);
+  add_optstring(val->sam_track_id,2,asn1_encode_charstring);
+  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
+  asn1_addfield(val->sam_type,0,asn1_encode_integer);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_sam_response_2(asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  asn1_addfield(val->sam_nonce,4,asn1_encode_integer);
+  asn1_addfield(&(val->sam_enc_nonce_or_sad),3,asn1_encode_encrypted_data);
+  add_optstring(val->sam_track_id,2,asn1_encode_charstring);
+  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
+  asn1_addfield(val->sam_type,0,asn1_encode_integer);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+asn1_error_code asn1_encode_predicted_sam_response(asn1buf *buf, const krb5_predicted_sam_response *val, unsigned int *retlen)
+{
+  asn1_setup();
+
+  add_optstring(val->msd,6,asn1_encode_charstring);
+  asn1_addfield(val->client,5,asn1_encode_principal_name);
+  asn1_addfield(val->client,4,asn1_encode_realm);
+  asn1_addfield(val->susec,3,asn1_encode_integer);
+  asn1_addfield(val->stime,2,asn1_encode_kerberos_time);
+  asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
+  asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);
+
+  asn1_makeseq();
+
+  asn1_cleanup();
+}
+
+/*
+ * Do some ugliness to insert a raw pre-encoded KRB-SAFE-BODY.
+ */
+asn1_error_code asn1_encode_krb_saved_safe_body(asn1buf *buf, const krb5_data *body, unsigned int *retlen)
+{
+  asn1_error_code retval;
+
+  retval = asn1buf_insert_octetstring(buf, body->length,
+				      (krb5_octet *)body->data);
+  if (retval){
+    asn1buf_destroy(&buf);
+    return retval; 
+  }
+  *retlen = body->length;
+  return 0;
+}
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_k_encode.h b/mechglue/src/lib/krb5/asn.1/asn1_k_encode.h
new file mode 100644
index 000000000..caa46c570
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_k_encode.h
@@ -0,0 +1,272 @@
+/*
+ * src/lib/krb5/asn.1/asn1_k_encode.h
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __ASN1_ENCODE_KRB5_H__
+#define __ASN1_ENCODE_KRB5_H__
+
+#include "k5-int.h"
+#include <stdio.h>
+#include "asn1buf.h"
+
+/*
+   Overview
+
+     Encoding routines for various ASN.1 "substructures" as defined in
+     the krb5 protocol.
+
+   Operations
+
+    asn1_encode_krb5_flags
+    asn1_encode_ap_options
+    asn1_encode_ticket_flags
+    asn1_encode_kdc_options
+    asn1_encode_kerberos_time
+
+    asn1_encode_realm
+    asn1_encode_principal_name
+    asn1_encode_encrypted_data
+    asn1_encode_authorization_data
+    asn1_encode_krb5_authdata_elt
+    asn1_encode_kdc_rep
+    asn1_encode_ticket
+    asn1_encode_encryption_key
+    asn1_encode_checksum
+    asn1_encode_host_address
+    asn1_encode_transited_encoding
+    asn1_encode_enc_kdc_rep_part
+    asn1_encode_kdc_req
+    asn1_encode_kdc_req_body
+    asn1_encode_krb_safe_body
+    asn1_encode_krb_cred_info
+    asn1_encode_last_req_entry
+    asn1_encode_pa_data
+
+    asn1_encode_host_addresses
+    asn1_encode_last_req
+    asn1_encode_sequence_of_pa_data
+    asn1_encode_sequence_of_ticket
+    asn1_encode_sequence_of_enctype
+    asn1_encode_sequence_of_checksum
+    asn1_encode_sequence_of_krb_cred_info
+*/
+
+/*
+**** for simple val's ****
+asn1_error_code asn1_encode_asn1_type(asn1buf *buf,
+                                      const krb5_type val,
+				      int *retlen);
+   requires  *buf is allocated
+   effects   Inserts the encoding of val into *buf and
+              returns the length of this encoding in *retlen.
+	     Returns ASN1_MISSING_FIELD if a required field is empty in val.
+	     Returns ENOMEM if memory runs out.
+
+**** for struct val's ****
+asn1_error_code asn1_encode_asn1_type(asn1buf *buf,
+                                      const krb5_type *val,
+				      int *retlen);
+   requires  *buf is allocated
+   effects   Inserts the encoding of *val into *buf and
+              returns the length of this encoding in *retlen.
+	     Returns ASN1_MISSING_FIELD if a required field is empty in val.
+	     Returns ENOMEM if memory runs out.
+
+**** for array val's ****
+asn1_error_code asn1_encode_asn1_type(asn1buf *buf,
+                                      const krb5_type **val,
+				      int *retlen);
+   requires  *buf is allocated, **val != NULL, *val[0] != NULL,
+              **val is a NULL-terminated array of pointers to krb5_type
+   effects   Inserts the encoding of **val into *buf and
+              returns the length of this encoding in *retlen.
+	     Returns ASN1_MISSING_FIELD if a required field is empty in val.
+	     Returns ENOMEM if memory runs out.
+*/
+
+asn1_error_code asn1_encode_ui_4 (asn1buf *buf,
+					    const krb5_ui_4 val,
+					    unsigned int *retlen);
+
+asn1_error_code asn1_encode_msgtype (asn1buf *buf,
+					       const /*krb5_msgtype*/int val,
+					       unsigned int *retlen);
+
+asn1_error_code asn1_encode_realm
+	(asn1buf *buf, const krb5_principal val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_principal_name
+	(asn1buf *buf, const krb5_principal val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_encrypted_data
+	(asn1buf *buf, const krb5_enc_data *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_krb5_flags
+	(asn1buf *buf, const krb5_flags val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_ap_options
+	(asn1buf *buf, const krb5_flags val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_ticket_flags
+	(asn1buf *buf, const krb5_flags val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_kdc_options
+	(asn1buf *buf, const krb5_flags val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_authorization_data
+	(asn1buf *buf, const krb5_authdata **val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_krb5_authdata_elt
+	(asn1buf *buf, const krb5_authdata *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_kdc_rep
+	(int msg_type, asn1buf *buf, const krb5_kdc_rep *val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_enc_kdc_rep_part
+	(asn1buf *buf, const krb5_enc_kdc_rep_part *val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_ticket
+	(asn1buf *buf, const krb5_ticket *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_encryption_key
+	(asn1buf *buf, const krb5_keyblock *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_kerberos_time
+	(asn1buf *buf, const krb5_timestamp val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_checksum
+	(asn1buf *buf, const krb5_checksum *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_host_address
+	(asn1buf *buf, const krb5_address *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_host_addresses
+	(asn1buf *buf, const krb5_address **val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_transited_encoding
+	(asn1buf *buf, const krb5_transited *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_last_req
+	(asn1buf *buf, const krb5_last_req_entry **val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_sequence_of_pa_data
+	(asn1buf *buf, const krb5_pa_data **val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sequence_of_ticket
+	(asn1buf *buf, const krb5_ticket **val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sequence_of_enctype
+	(asn1buf *buf,
+		   const int len, const krb5_enctype *val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_sequence_of_checksum
+	(asn1buf *buf, const krb5_checksum **val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_kdc_req
+	(int msg_type,
+		   asn1buf *buf,
+		   const krb5_kdc_req *val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_kdc_req_body
+	(asn1buf *buf, const krb5_kdc_req *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_krb_safe_body
+	(asn1buf *buf, const krb5_safe *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sequence_of_krb_cred_info
+	(asn1buf *buf, const krb5_cred_info **val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_krb_cred_info
+	(asn1buf *buf, const krb5_cred_info *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_last_req_entry
+	(asn1buf *buf, const krb5_last_req_entry *val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_pa_data
+	(asn1buf *buf, const krb5_pa_data *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_alt_method
+	(asn1buf *buf, const krb5_alt_method *val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_etype_info_entry
+	(asn1buf *buf, const krb5_etype_info_entry *val,
+		   unsigned int *retlen, int etype_info2);
+
+asn1_error_code asn1_encode_etype_info
+	(asn1buf *buf, const krb5_etype_info_entry **val,
+		   unsigned int *retlen, int etype_info2);
+
+asn1_error_code asn1_encode_passwdsequence
+	(asn1buf *buf, const passwd_phrase_element *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sequence_of_passwdsequence
+	(asn1buf *buf, const passwd_phrase_element **val,
+	unsigned int *retlen);
+
+asn1_error_code asn1_encode_sam_flags
+	(asn1buf * buf, const krb5_flags val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sam_challenge
+	(asn1buf *buf, const krb5_sam_challenge * val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sam_challenge_2
+	(asn1buf *buf, const krb5_sam_challenge_2 * val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sam_challenge_2_body
+	(asn1buf *buf, const krb5_sam_challenge_2_body * val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_sam_key
+	(asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_enc_sam_response_enc
+	(asn1buf *buf, const krb5_enc_sam_response_enc *val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_enc_sam_response_enc_2
+	(asn1buf *buf, const krb5_enc_sam_response_enc_2 *val,
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_sam_response
+	(asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_sam_response_2
+	(asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen);
+
+asn1_error_code asn1_encode_predicted_sam_response
+	(asn1buf *buf, const krb5_predicted_sam_response *val, 
+		   unsigned int *retlen);
+
+asn1_error_code asn1_encode_krb_saved_safe_body
+	(asn1buf *buf, const krb5_data *body, unsigned int *retlen);
+
+#endif
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_make.c b/mechglue/src/lib/krb5/asn.1/asn1_make.c
new file mode 100644
index 000000000..dddf2da8f
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_make.c
@@ -0,0 +1,160 @@
+/*
+ * src/lib/krb5/asn.1/asn1_make.c
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_make.h"
+
+asn1_error_code asn1_make_etag(asn1buf *buf, asn1_class asn1class,
+			       asn1_tagnum tagnum, unsigned int in_len,
+			       unsigned int *retlen)
+{
+  return asn1_make_tag(buf,asn1class,CONSTRUCTED,tagnum,in_len,retlen);
+}
+
+
+asn1_error_code asn1_make_tag(asn1buf *buf, asn1_class asn1class,
+			      asn1_construction construction,
+			      asn1_tagnum tagnum, unsigned int in_len,
+			      unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int sumlen=0, length;
+
+  if(tagnum > ASN1_TAGNUM_MAX) return ASN1_OVERFLOW;
+
+  retval = asn1_make_length(buf,in_len, &length);
+  if(retval) return retval;
+  sumlen += length;
+  retval = asn1_make_id(buf,asn1class,construction,tagnum,&length);
+  if(retval) return retval;
+  sumlen += length;
+
+  *retlen = sumlen;
+  return 0;
+}
+
+asn1_error_code asn1_make_length(asn1buf *buf, const unsigned int in_len, unsigned int *retlen)
+{
+  asn1_error_code retval;
+
+  if(in_len < 128){
+    retval = asn1buf_insert_octet(buf, (asn1_octet)(in_len&0x7F));
+    if(retval) return retval;
+    *retlen = 1;
+  }else{
+    int in_copy=in_len, length=0;
+
+    while(in_copy != 0){
+      retval = asn1buf_insert_octet(buf, (asn1_octet)(in_copy&0xFF));
+      if(retval) return retval;
+      in_copy = in_copy >> 8;
+      length++;
+    }
+    retval = asn1buf_insert_octet(buf, (asn1_octet) (0x80 | (asn1_octet)(length&0x7F)));
+    if(retval) return retval;
+    length++;
+    *retlen = length;
+  }
+
+  return 0;
+}
+
+asn1_error_code asn1_make_id(asn1buf *buf, asn1_class asn1class,
+			     asn1_construction construction,
+			     asn1_tagnum tagnum, unsigned int *retlen)
+{
+  asn1_error_code retval;
+
+  if(tagnum < 31) {
+    retval = asn1buf_insert_octet(buf, (asn1_octet) (asn1class | construction |
+						     (asn1_octet)tagnum));
+    if(retval) return retval;
+    *retlen = 1;
+  }else{
+    asn1_tagnum tagcopy = tagnum;
+    int length = 0;
+
+    retval = asn1buf_insert_octet(buf, (asn1_octet)(tagcopy&0x7F));
+    if(retval) return retval;
+    tagcopy >>= 7;
+    length++;
+
+    for(; tagcopy != 0; tagcopy >>= 7){
+      retval = asn1buf_insert_octet(buf, (asn1_octet) (0x80 | (asn1_octet)(tagcopy&0x7F)));
+      if(retval) return retval;
+      length++;
+    }
+
+    retval = asn1buf_insert_octet(buf, (asn1_octet) (asn1class | construction | 0x1F));
+    if(retval) return retval;
+    length++;
+    *retlen = length;
+  }
+
+  return 0;
+}
+
+asn1_error_code asn1_make_sequence(asn1buf *buf, const unsigned int seq_len, unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int len, sum=0;
+
+  retval = asn1_make_length(buf,seq_len,&len);
+  if(retval) return retval;
+  sum += len;
+  retval = asn1_make_id(buf,UNIVERSAL,CONSTRUCTED,ASN1_SEQUENCE,&len);
+  if(retval) return retval;
+  sum += len;
+
+  *retlen = sum;
+  return 0;
+}
+
+asn1_error_code asn1_make_set(asn1buf *buf, const unsigned int set_len, unsigned int *retlen)
+{
+  asn1_error_code retval;
+  unsigned int len, sum=0;
+
+  retval = asn1_make_length(buf,set_len,&len);
+  if(retval) return retval;
+  sum += len;
+  retval = asn1_make_id(buf,UNIVERSAL,CONSTRUCTED,ASN1_SET,&len);
+  if(retval) return retval;
+  sum += len;
+
+  *retlen = sum;
+  return 0;
+}
+
+asn1_error_code asn1_make_string(asn1buf *buf, const unsigned int length, const char *string, int *retlen)
+{
+  asn1_error_code retval;
+
+  retval = asn1buf_insert_charstring(buf,length,string);
+  if(retval) return retval;
+
+  *retlen = length;
+  return 0;
+}
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_make.h b/mechglue/src/lib/krb5/asn.1/asn1_make.h
new file mode 100644
index 000000000..715054908
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_make.h
@@ -0,0 +1,134 @@
+/*
+ * src/lib/krb5/asn.1/asn1_make.h
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __ASN1_MAKE_H__
+#define __ASN1_MAKE_H__
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "asn1buf.h"
+
+/*
+   Overview
+
+     Each of these procedures constructs a subpart of an ASN.1
+     primitive in a coding buffer.
+
+    Operations
+
+      asn1_make_etag
+      asn1_make_sequence
+      asn1_make_set
+      asn1_make_tag
+      asn1_make_string
+*/
+
+asn1_error_code asn1_make_etag
+	(asn1buf *buf,
+		   const asn1_class asn1class,
+		   const asn1_tagnum tagnum,
+		   const unsigned int in_len,
+		   unsigned int *retlen);
+/* requires  *buf is allocated, in_len is the length of an ASN.1 encoding
+             which has just been inserted in *buf
+   modifies  *buf, *retlen
+   effects   Inserts an explicit tag with class = asn1class, id# = tag
+              length = in_len into *buf.
+	     Returns the length of this encoding in *retlen.
+	     Returns ENOMEM if memory runs out. */
+
+asn1_error_code asn1_make_tag
+	(asn1buf *buf, const asn1_class asn1class,
+		   const asn1_construction construction,
+		   const asn1_tagnum tagnum,
+		   const unsigned int in_len,
+		   unsigned int *retlen);
+/* requires  *buf is allocated, in_len is the length of an ASN.1 encoding
+             which has just been inserted in *buf
+   modifies  *buf, *retlen
+   effects   Inserts the encoding of a tag with class = asn1class,
+              primitive/constructed staus = construction,
+	      id# = tag and length = in_len into *buf.
+	     Returns the length of this encoding in *retlen.
+	     Returns ENOMEM if memory runs out.
+	     Returns ASN1_OVERFLOW if tagnum exceeds the limits of
+	      the implementation. */
+
+asn1_error_code asn1_make_sequence
+	(asn1buf *buf, const unsigned int seq_len, unsigned int *len);
+/* requires  *buf is allocated, seq_len is the length of a series of
+             sequence components which have just been inserted in *buf
+   modifies  *buf, *retlen
+   effects   Inserts the sequence header for a sequence of length seq_len
+              in *buf.  Returns the length of this encoding in *retlen.
+             Returns ENOMEM if memory runs out. */
+
+asn1_error_code asn1_make_set
+	(asn1buf *buf, const unsigned int set_len, 
+		   unsigned int *retlen);
+/* requires  *buf is allocated, seq_len is the length of a series of
+             sequence components which have just been inserted in *buf
+   modifies  *buf, *retlen
+   effects   Inserts the set header for a set of length set_len in *buf.
+             Returns the length of this encoding in *retlen.
+             Returns ENOMEM if memory runs out. */
+
+asn1_error_code asn1_make_string
+	(asn1buf *buf,
+		   const unsigned int len, const char *string,
+		   int *retlen);
+/* requires  *buf is allocated, len is the length of *string
+   effects   Inserts the encoding of *string (a series of octets) in *buf.
+             Returns the length of this encoding in *retlen.
+             Returns ENOMEM if memory runs out. */
+
+
+/****************************************************************/
+/* Private procedures */
+
+/* "helper" procedure for asn1_make_tag */
+asn1_error_code asn1_make_length
+	(asn1buf *buf, const unsigned int in_len, 
+		   unsigned int *retlen);
+/* requires  *buf is allocated, in_len is the length of an ASN.1 encoding
+             which has just been inserted in *buf
+   modifies  *buf, *retlen
+   effects   inserts length octet(s) for in_len into *buf */
+
+/* "helper" procedure for asn1_make_tag */
+asn1_error_code asn1_make_id
+	(asn1buf *buf,
+		   const asn1_class asn1class,
+		   const asn1_construction construction,
+		   const asn1_tagnum tagnum,
+		   unsigned int *retlen);
+/* requires  *buf is allocated, asn1class and tagnum are appropriate for
+             the ASN.1 encoding which has just been inserted in *buf
+   modifies  *buf, *retlen
+   effects   Inserts id octet(s) of class asn1class and tag number tagnum
+             into *buf */
+
+#endif
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_misc.c b/mechglue/src/lib/krb5/asn.1/asn1_misc.c
new file mode 100644
index 000000000..62412ae6e
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_misc.c
@@ -0,0 +1,37 @@
+/*
+ * src/lib/krb5/asn.1/asn1_misc.c
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "asn1_misc.h"
+
+asn1_error_code asn1_krb5_realm_copy(krb5_principal target, krb5_principal source)
+{
+  target->realm.length = source->realm.length;
+  target->realm.data = (char*)malloc(target->realm.length); /* copy realm */
+  if (target->realm.data == NULL) return ENOMEM;
+  memcpy(target->realm.data,source->realm.data, /* to client */
+	 target->realm.length);
+  return 0;
+}
diff --git a/mechglue/src/lib/krb5/asn.1/asn1_misc.h b/mechglue/src/lib/krb5/asn.1/asn1_misc.h
new file mode 100644
index 000000000..31b30dac2
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1_misc.h
@@ -0,0 +1,39 @@
+/*
+ * src/lib/krb5/asn.1/asn1_misc.h
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __ASN1_MISC_H__
+#define __ASN1_MISC_H__
+
+#include "k5-int.h"
+#include "krbasn1.h"
+
+asn1_error_code asn1_krb5_realm_copy
+	(krb5_principal target, krb5_principal source);
+/* requires  target, source, and source->realm are allocated
+   effects   Copies source->realm into target->realm.
+             Returns ENOMEM if memory is exhausted. */
+
+#endif
diff --git a/mechglue/src/lib/krb5/asn.1/asn1buf.c b/mechglue/src/lib/krb5/asn.1/asn1buf.c
new file mode 100644
index 000000000..8baac2424
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1buf.c
@@ -0,0 +1,384 @@
+/* Coding Buffer Implementation */
+
+/*
+  Implementation
+
+    Encoding mode
+
+    The encoding buffer is filled from bottom (lowest address) to top
+    (highest address).  This makes it easier to expand the buffer,
+    since realloc preserves the existing portion of the buffer.
+
+    Note: Since ASN.1 encoding must be done in reverse, this means
+    that you can't simply memcpy out the buffer data, since it will be
+    backwards.  You need to reverse-iterate through it, instead.
+
+    ***This decision may have been a mistake.  In practice, the
+    implementation will probably be tuned such that reallocation is
+    rarely necessary.  Also, the realloc probably has recopy the
+    buffer itself, so we don't really gain that much by avoiding an
+    explicit copy of the buffer.  --Keep this in mind for future reference.
+
+
+    Decoding mode
+
+    The decoding buffer is in normal order and is created by wrapping
+    an asn1buf around a krb5_data structure.
+  */
+
+/* Abstraction Function
+
+   Programs should use just pointers to asn1buf's (e.g. asn1buf *mybuf).
+   These pointers must always point to a valid, allocated asn1buf
+   structure or be NULL.
+
+   The contents of the asn1buf represent an octet string.  This string
+   begins at base and continues to the octet immediately preceding next.
+   If next == base or mybuf == NULL, then the asn1buf represents an empty
+   octet string. */
+
+/* Representation Invariant
+
+   Pointers to asn1buf's must always point to a valid, allocated
+   asn1buf structure or be NULL.
+
+   base points to a valid, allocated octet array or is NULL
+   bound, if non-NULL, points to the last valid octet
+   next >= base
+   next <= bound+2  (i.e. next should be able to step just past the bound,
+                     but no further.  (The bound should move out in response
+		     to being crossed by next.)) */
+
+#define ASN1BUF_OMIT_INLINE_FUNCS
+#include "asn1buf.h"
+#undef ASN1BUF_OMIT_INLINE_FUNCS
+#include <stdio.h>
+#include "asn1_get.h"
+
+#define asn1_is_eoc(class, num, indef)	\
+((class) == UNIVERSAL && !(num) && !(indef))
+
+asn1_error_code asn1buf_create(asn1buf **buf)
+{
+  *buf = (asn1buf*)malloc(sizeof(asn1buf));
+  if (*buf == NULL) return ENOMEM;
+  (*buf)->base = NULL;
+  (*buf)->bound = NULL;
+  (*buf)->next = NULL;
+  return 0;
+}
+
+asn1_error_code asn1buf_wrap_data(asn1buf *buf, const krb5_data *code)
+{
+  if(code == NULL || code->data == NULL) return ASN1_MISSING_FIELD;
+  buf->next = buf->base = code->data;
+  buf->bound = code->data + code->length - 1;
+  return 0;
+}
+
+asn1_error_code asn1buf_imbed(asn1buf *subbuf, const asn1buf *buf, const unsigned int length, const int indef)
+{
+  subbuf->base = subbuf->next = buf->next;
+  if (!indef) {
+      subbuf->bound = subbuf->base + length - 1;
+      if (subbuf->bound > buf->bound)
+	  return ASN1_OVERRUN;
+  } else /* constructed indefinite */
+      subbuf->bound = buf->bound;
+  return 0;
+}
+
+asn1_error_code asn1buf_sync(asn1buf *buf, asn1buf *subbuf,
+			     asn1_class asn1class, asn1_tagnum lasttag,
+			     unsigned int length, int indef, int seqindef)
+{
+  asn1_error_code retval;
+
+  if (!seqindef) {
+    /* sequence was encoded as definite length */
+    buf->next = subbuf->bound + 1;
+  } else if (!asn1_is_eoc(asn1class, lasttag, indef)) {
+      retval = asn1buf_skiptail(subbuf, length, indef);
+      if (retval)
+	  return retval;
+  } else {
+    /* We have just read the EOC octets. */
+    buf->next = subbuf->next;
+  }
+  return 0;
+}
+
+asn1_error_code asn1buf_skiptail(asn1buf *buf, const unsigned int length, const int indef)
+{
+  asn1_error_code retval;
+  taginfo t;
+  int nestlevel;
+
+  nestlevel = 1 + indef;
+  if (!indef) {
+    if (length <= buf->bound - buf->next + 1)
+      buf->next += length;
+    else
+      return ASN1_OVERRUN;
+  }
+  while (nestlevel > 0) {
+    if (buf->bound - buf->next + 1 <= 0)
+      return ASN1_OVERRUN;
+    retval = asn1_get_tag_2(buf, &t);
+    if (retval) return retval;
+    if (!t.indef) {
+      if (t.length <= buf->bound - buf->next + 1)
+	buf->next += t.length;
+      else
+	return ASN1_OVERRUN;
+    }
+    if (t.indef)
+      nestlevel++;
+    if (asn1_is_eoc(t.asn1class, t.tagnum, t.indef))
+      nestlevel--;		/* got an EOC encoding */
+  }
+  return 0;
+}
+
+asn1_error_code asn1buf_destroy(asn1buf **buf)
+{
+  if (*buf != NULL) {
+    if ((*buf)->base != NULL) free((*buf)->base);
+    free(*buf);
+    *buf = NULL;
+  }
+  return 0;
+}
+
+#ifdef asn1buf_insert_octet
+#undef asn1buf_insert_octet
+#endif
+asn1_error_code asn1buf_insert_octet(asn1buf *buf, const int o)
+{
+  asn1_error_code retval;
+
+  retval = asn1buf_ensure_space(buf,1U);
+  if(retval) return retval;
+  *(buf->next) = (char)o;
+  (buf->next)++;
+  return 0;
+}
+
+asn1_error_code asn1buf_insert_octetstring(asn1buf *buf, const unsigned int len, const krb5_octet *s)
+{
+  asn1_error_code retval;
+  int length;
+
+  retval = asn1buf_ensure_space(buf,len);
+  if(retval) return retval;
+  for(length=1; length<=len; length++,(buf->next)++)
+    *(buf->next) = (char)(s[len-length]);
+  return 0;
+}
+
+asn1_error_code asn1buf_insert_charstring(asn1buf *buf, const unsigned int len, const char *s)
+{
+  asn1_error_code retval;
+  int length;
+
+  retval = asn1buf_ensure_space(buf,len);
+  if(retval) return retval;
+  for(length=1; length<=len; length++,(buf->next)++)
+    *(buf->next) = (char)(s[len-length]);
+  return 0;
+}
+
+#undef asn1buf_remove_octet
+asn1_error_code asn1buf_remove_octet(asn1buf *buf, asn1_octet *o)
+{
+  if(buf->next > buf->bound) return ASN1_OVERRUN;
+  *o = (asn1_octet)(*((buf->next)++));
+  return 0;
+}
+
+asn1_error_code asn1buf_remove_octetstring(asn1buf *buf, const unsigned int len, asn1_octet **s)
+{
+  int i;
+
+  if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
+  if (len == 0) {
+      *s = 0;
+      return 0;
+  }
+  *s = (asn1_octet*)malloc(len*sizeof(asn1_octet));
+  if (*s == NULL)
+      return ENOMEM;
+  for(i=0; i<len; i++)
+    (*s)[i] = (asn1_octet)(buf->next)[i];
+  buf->next += len;
+  return 0;
+}
+
+asn1_error_code asn1buf_remove_charstring(asn1buf *buf, const unsigned int len, char **s)
+{
+  int i;
+
+  if (len > buf->bound + 1 - buf->next) return ASN1_OVERRUN;
+  if (len == 0) {
+      *s = 0;
+      return 0;
+  }
+  *s = (char*)malloc(len*sizeof(char));
+  if (*s == NULL) return ENOMEM;
+  for(i=0; i<len; i++)
+    (*s)[i] = (char)(buf->next)[i];
+  buf->next += len;
+  return 0;
+}
+
+int asn1buf_remains(asn1buf *buf, int indef)
+{
+  int remain;
+  if(buf == NULL || buf->base == NULL) return 0;
+  remain = buf->bound - buf->next +1;
+  if (remain <= 0) return remain;
+  /*
+   * Two 0 octets means the end of an indefinite encoding.
+   */
+  if (indef && remain >= 2 && !*(buf->next) && !*(buf->next + 1))
+      return 0;
+  else return remain;
+}
+
+asn1_error_code asn12krb5_buf(const asn1buf *buf, krb5_data **code)
+{
+  int i;
+  *code = (krb5_data*)calloc(1,sizeof(krb5_data));
+  if(*code == NULL) return ENOMEM;
+  (*code)->magic = KV5M_DATA;
+  (*code)->data = NULL;
+  (*code)->length = 0;
+  (*code)->length = asn1buf_len(buf);
+  (*code)->data = (char*)malloc((((*code)->length)+1)*sizeof(char));
+  if ((*code)->data == NULL) {
+    free(*code);
+    *code = NULL;
+    return ENOMEM;
+  }
+  for(i=0; i < (*code)->length; i++)
+    ((*code)->data)[i] = (buf->base)[((*code)->length)-i-1];
+  ((*code)->data)[(*code)->length] = '\0';
+  return 0;
+}
+
+
+
+/* These parse and unparse procedures should be moved out. They're
+   useful only for debugging and superfluous in the production version. */
+
+asn1_error_code asn1buf_unparse(const asn1buf *buf, char **s)
+{
+  if(*s != NULL) free(*s);
+  if(buf == NULL){
+    *s = malloc(sizeof("<NULL>"));
+    if(*s == NULL) return ENOMEM;
+    strcpy(*s,"<NULL>");
+  }else if(buf->base == NULL){
+    *s = malloc(sizeof("<EMPTY>"));
+    if(*s == NULL) return ENOMEM;
+    strcpy(*s,"<EMPTY>");
+  }else{
+    unsigned int length = asn1buf_len(buf);
+    int i;
+
+    *s = calloc(length+1, sizeof(char));
+    if(*s == NULL) return ENOMEM;
+    (*s)[length] = '\0';
+    for(i=0; i<length; i++) ;
+/*      OLDDECLARG( (*s)[i] = , (buf->base)[length-i-1]) */
+  }
+  return 0;
+}
+
+asn1_error_code asn1buf_hex_unparse(const asn1buf *buf, char **s)
+{
+#define hexchar(d) ((d)<=9 ? ('0'+(d)) :\
+		    ((d)<=15 ? ('A'+(d)-10) :\
+		    'X'))
+
+  if(*s != NULL) free(*s);
+
+  if(buf == NULL){
+    *s = malloc(sizeof("<NULL>"));
+    if(*s == NULL) return ENOMEM;
+    strcpy(*s,"<NULL>");
+  }else if(buf->base == NULL){
+    *s = malloc(sizeof("<EMPTY>"));
+    if(*s == NULL) return ENOMEM;
+    strcpy(*s,"<EMPTY>");
+  }else{
+    unsigned int length = asn1buf_len(buf);
+    int i;
+
+    *s = malloc(3*length);
+    if(*s == NULL) return ENOMEM;
+    for(i = length-1; i >= 0; i--){
+      (*s)[3*(length-i-1)] = hexchar(((buf->base)[i]&0xF0)>>4);
+      (*s)[3*(length-i-1)+1] = hexchar((buf->base)[i]&0x0F);
+      (*s)[3*(length-i-1)+2] = ' ';
+    }
+    (*s)[3*length-1] = '\0';
+  }
+  return 0;
+}
+
+/****************************************************************/
+/* Private Procedures */
+
+#undef asn1buf_size
+int asn1buf_size(const asn1buf *buf)
+{
+  if(buf == NULL || buf->base == NULL) return 0;
+  return buf->bound - buf->base + 1;
+}
+
+#undef asn1buf_free
+int asn1buf_free(const asn1buf *buf)
+{
+  if(buf == NULL || buf->base == NULL) return 0;
+  else return buf->bound - buf->next + 1;
+}
+
+#undef asn1buf_ensure_space
+asn1_error_code asn1buf_ensure_space(asn1buf *buf, const unsigned int amount)
+{
+  int avail = asn1buf_free(buf);
+  if(avail < amount){
+    asn1_error_code retval = asn1buf_expand(buf, amount-avail);
+    if(retval) return retval;
+  }
+  return 0;
+}
+
+asn1_error_code asn1buf_expand(asn1buf *buf, unsigned int inc)
+{
+#define STANDARD_INCREMENT 200
+  int next_offset = buf->next - buf->base;
+  int bound_offset;
+  if (buf->base == NULL) bound_offset = -1;
+  else bound_offset = buf->bound - buf->base;
+
+  if (inc < STANDARD_INCREMENT)
+    inc = STANDARD_INCREMENT;
+
+  if (buf->base == NULL)
+    buf->base = malloc((asn1buf_size(buf)+inc) * sizeof(asn1_octet));
+  else
+    buf->base = realloc(buf->base,
+			(asn1buf_size(buf)+inc) * sizeof(asn1_octet));
+  if (buf->base == NULL) return ENOMEM;
+  buf->bound = (buf->base) + bound_offset + inc;
+  buf->next = (buf->base) + next_offset;
+  return 0;
+}
+
+#undef asn1buf_len
+int asn1buf_len(const asn1buf *buf)
+{
+  return buf->next - buf->base;
+}
diff --git a/mechglue/src/lib/krb5/asn.1/asn1buf.h b/mechglue/src/lib/krb5/asn.1/asn1buf.h
new file mode 100644
index 000000000..854801edd
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1buf.h
@@ -0,0 +1,231 @@
+/* Coding Buffer Specifications */
+#ifndef __ASN1BUF_H__
+#define __ASN1BUF_H__
+
+#include "k5-int.h"
+#include "krbasn1.h"
+
+typedef struct code_buffer_rep {
+  char *base, *bound, *next;
+} asn1buf;
+
+
+/**************** Private Procedures ****************/
+
+int asn1buf_size
+	(const asn1buf *buf);
+/* requires  *buf has been created and not destroyed
+   effects   Returns the total size 
+	(in octets) of buf's octet buffer. */
+#define asn1buf_size(buf) \
+  (((buf) == NULL || (buf)->base == NULL) \
+   ? 0 \
+   : ((buf)->bound - (buf)->base + 1))
+
+int asn1buf_free
+	(const asn1buf *buf);
+/* requires  *buf is allocated
+   effects   Returns the number of unused, allocated octets in *buf. */
+#define asn1buf_free(buf) \
+  (((buf) == NULL || (buf)->base == NULL) \
+   ? 0 \
+   : ((buf)->bound - (buf)->next + 1))
+
+
+asn1_error_code asn1buf_ensure_space
+	(asn1buf *buf, const unsigned int amount);
+/* requires  *buf is allocated
+   modifies  *buf
+   effects  If buf has less than amount octets of free space, then it is
+            expanded to have at least amount octets of free space.
+            Returns ENOMEM memory is exhausted. */
+#define asn1buf_ensure_space(buf,amount) \
+  ((asn1buf_free(buf) < (amount)) \
+   ? (asn1buf_expand((buf), (amount)-asn1buf_free(buf))) \
+   : 0)
+
+
+asn1_error_code asn1buf_expand
+	(asn1buf *buf, unsigned int inc);
+/* requires  *buf is allocated
+   modifies  *buf
+   effects   Expands *buf by allocating space for inc more octets.
+             Returns ENOMEM if memory is exhausted. */
+
+int asn1buf_len
+	(const asn1buf *buf);
+/* requires  *buf is allocated
+   effects   Returns the length of the encoding in *buf. */
+#define asn1buf_len(buf)	((buf)->next - (buf)->base)
+
+/****** End of private procedures *****/
+	
+/*
+  Overview 
+    
+    The coding buffer is an array of char (to match a krb5_data structure)
+     with 3 reference pointers:
+     1) base - The bottom of the octet array.  Used for memory management
+               operations on the array (e.g. alloc, realloc, free).
+     2) next - Points to the next available octet position in the array.
+               During encoding, this is the next free position, and it
+                 advances as octets are added to the array.
+	       During decoding, this is the next unread position, and it
+                 advances as octets are read from the array.
+     3) bound - Points to the top of the array. Used for bounds-checking.
+    
+    All pointers to encoding buffers should be initalized to NULL.
+    
+  Operations
+
+    asn1buf_create
+    asn1buf_wrap_data
+    asn1buf_destroy
+    asn1buf_insert_octet
+    asn1buf_insert_charstring
+    asn1buf_remove_octet
+    asn1buf_remove_charstring
+    asn1buf_unparse
+    asn1buf_hex_unparse
+    asn12krb5_buf
+    asn1buf_remains
+
+    (asn1buf_size)
+    (asn1buf_free)
+    (asn1buf_ensure_space)
+    (asn1buf_expand)
+    (asn1buf_len)
+*/
+
+asn1_error_code asn1buf_create
+	(asn1buf **buf);
+/* effects   Creates a new encoding buffer pointed to by *buf.
+             Returns ENOMEM if the buffer can't be created. */
+
+asn1_error_code asn1buf_wrap_data
+	(asn1buf *buf, const krb5_data *code);
+/* requires  *buf has already been allocated
+   effects   Turns *buf into a "wrapper" for *code.  i.e. *buf is set up
+              such that its bottom is the beginning of *code, and its top
+	      is the top of *code.
+	     Returns ASN1_MISSING_FIELD if code is empty. */
+
+asn1_error_code asn1buf_imbed
+	(asn1buf *subbuf, const asn1buf *buf, 
+		   const unsigned int length,
+		   const int indef);
+/* requires  *subbuf and *buf are allocated
+   effects   *subbuf becomes a sub-buffer of *buf.  *subbuf begins
+              at *buf's current position and is length octets long.
+              (Unless this would exceed the bounds of *buf -- in
+	      that case, ASN1_OVERRUN is returned)  *subbuf's current
+	      position starts at the beginning of *subbuf. */
+
+asn1_error_code asn1buf_sync
+	(asn1buf *buf, asn1buf *subbuf, const asn1_class Class, 
+		   const asn1_tagnum lasttag,
+		   const unsigned int length, const int indef,
+		   const int seqindef);
+/* requires  *subbuf is a sub-buffer of *buf, as created by asn1buf_imbed.
+             lasttag is the last tagnumber read.
+   effects   Synchronizes *buf's current position to match that of *subbuf. */
+
+asn1_error_code asn1buf_skiptail
+	(asn1buf *buf, const unsigned int length,
+		   const int indef);
+/* requires  *buf is a subbuffer used in a decoding of a
+             constructed indefinite sequence.
+   effects   skips trailing fields. */
+
+asn1_error_code asn1buf_destroy
+	(asn1buf **buf);
+/* effects   Deallocates **buf, sets *buf to NULL. */
+
+asn1_error_code asn1buf_insert_octet
+	(asn1buf *buf, const int o);
+/* requires  *buf is allocated
+   effects   Inserts o into the buffer *buf, expanding the buffer if
+             necessary.  Returns ENOMEM memory is exhausted. */
+#if ((__GNUC__ >= 2) && !defined(ASN1BUF_OMIT_INLINE_FUNCS))
+extern __inline__ asn1_error_code asn1buf_insert_octet(asn1buf *buf, const int o)
+{
+  asn1_error_code retval;
+
+  retval = asn1buf_ensure_space(buf,1U);
+  if(retval) return retval;
+  *(buf->next) = (char)o;
+  (buf->next)++;
+  return 0;
+}
+#endif
+
+asn1_error_code asn1buf_insert_octetstring
+	(asn1buf *buf, const unsigned int len, const asn1_octet *s);
+/* requires  *buf is allocated
+   modifies  *buf
+   effects   Inserts the contents of s (an octet array of length len)
+              into the buffer *buf, expanding the buffer if necessary.
+	     Returns ENOMEM if memory is exhausted. */
+
+asn1_error_code asn1buf_insert_charstring
+	(asn1buf *buf, const unsigned int len, const char *s);
+/* requires  *buf is allocated
+   modifies  *buf
+   effects   Inserts the contents of s (a character array of length len)
+              into the buffer *buf, expanding the buffer if necessary.
+	     Returns ENOMEM if memory is exhausted. */
+
+asn1_error_code asn1buf_remove_octet
+	(asn1buf *buf, asn1_octet *o);
+/* requires  *buf is allocated
+   effects   Returns *buf's current octet in *o and advances to
+              the next octet.
+	     Returns ASN1_OVERRUN if *buf has already been exhausted. */
+#define asn1buf_remove_octet(buf,o) \
+  (((buf)->next > (buf)->bound) \
+   ? ASN1_OVERRUN \
+   : ((*(o) = (asn1_octet)(*(((buf)->next)++))),0))
+
+asn1_error_code asn1buf_remove_octetstring
+	(asn1buf *buf, const unsigned int len, asn1_octet **s);
+/* requires  *buf is allocated
+   effects   Removes the next len octets of *buf and returns them in **s.
+	     Returns ASN1_OVERRUN if there are fewer than len unread octets
+	      left in *buf.
+	     Returns ENOMEM if *s could not be allocated. */
+
+asn1_error_code asn1buf_remove_charstring
+	(asn1buf *buf, const unsigned int len,
+					  char **s);
+/* requires  *buf is allocated
+   effects   Removes the next len octets of *buf and returns them in **s.
+	     Returns ASN1_OVERRUN if there are fewer than len unread octets
+	      left in *buf.
+	     Returns ENOMEM if *s could not be allocated. */
+
+asn1_error_code asn1buf_unparse
+	(const asn1buf *buf, char **s);
+/* modifies  *s
+   effects   Returns a human-readable representation of *buf in *s,
+             where each octet in *buf is represented by a character in *s. */
+
+asn1_error_code asn1buf_hex_unparse
+	(const asn1buf *buf, char **s);
+/* modifies  *s
+   effects   Returns a human-readable representation of *buf in *s,
+             where each octet in *buf is represented by a 2-digit
+	     hexadecimal number in *s. */
+
+asn1_error_code asn12krb5_buf
+	(const asn1buf *buf, krb5_data **code);
+/* modifies  *code
+   effects   Instantiates **code with the krb5_data representation of **buf. */
+
+
+int asn1buf_remains
+	(asn1buf *buf, int indef);
+/* requires  *buf is a buffer containing an asn.1 structure or array
+   modifies  *buf
+   effects   Returns the number of unprocessed octets remaining in *buf. */
+
+#endif
diff --git a/mechglue/src/lib/krb5/asn.1/asn1glue.h b/mechglue/src/lib/krb5/asn.1/asn1glue.h
new file mode 100644
index 000000000..fa3c95675
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/asn1glue.h
@@ -0,0 +1,46 @@
+/*
+ * lib/krb5/asn.1/asn1glue.h
+ *
+ * Copyright 1989,1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Header file for some glue functions (macros, mostly)
+ */
+
+
+#ifndef __KRB5_GLUE_H__
+#define __KRB5_GLUE_H__
+
+#define krb5_data2qbuf(val) str2qb((val)->data, (val)->length, 1)
+
+#define krb5_kdcoptions2KRB5_KDCOptions(val, err) (struct type_KRB5_KDCOptions *)krb5_flags2KRB5_TicketFlags(val, err)
+#define KRB5_KDCOptions2krb5_kdcoptions(val, err) KRB5_TicketFlags2krb5_flags((struct type_KRB5_TicketFlags *) (val), err)
+#define krb5_apoptions2KRB5_APOptions(val, err) (struct type_KRB5_APOptions *)krb5_flags2KRB5_TicketFlags(val, err)
+#define KRB5_APOptions2krb5_apoptions(val, err) KRB5_TicketFlags2krb5_flags((struct type_KRB5_APOptions *) (val), err)
+
+/* to keep lint happy */
+#define xbcopy(src,dst,size) memcpy((char *)(dst), (char *)(src), size)
+#define xmalloc(n) malloc((unsigned) (n))
+#define xcalloc(n,s) calloc((unsigned)(n), (unsigned)(s))
+
+#endif /* __KRB5_GLUE_H__ */
diff --git a/mechglue/src/lib/krb5/asn.1/krb5_decode.c b/mechglue/src/lib/krb5/asn.1/krb5_decode.c
new file mode 100644
index 000000000..04097b0d1
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/krb5_decode.c
@@ -0,0 +1,935 @@
+/*
+ * src/lib/krb5/asn.1/krb5_decode.c
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "asn1_k_decode.h"
+#include "asn1_decode.h"
+#include "asn1_get.h"
+
+/* setup *********************************************************/
+/* set up variables */
+/* the setup* macros can return, but are always used at function start
+   and thus need no malloc cleanup */
+#define setup_buf_only()\
+asn1_error_code retval;\
+asn1buf buf;\
+\
+retval = asn1buf_wrap_data(&buf,code);\
+if(retval) return retval
+
+#define setup_no_tagnum()\
+asn1_class asn1class;\
+asn1_construction construction;\
+setup_buf_only()
+
+#define setup_no_length()\
+asn1_tagnum tagnum;\
+setup_no_tagnum()
+
+#define setup()\
+unsigned int length;\
+setup_no_length()
+
+/* helper macros for cleanup */
+#define clean_return(val) { retval = val; goto error_out; }
+
+/* alloc_field is the first thing to allocate storage that may need cleanup */
+#define alloc_field(var,type)\
+var = (type*)calloc(1,sizeof(type));\
+if((var) == NULL) clean_return(ENOMEM)
+
+/* process encoding header ***************************************/
+/* decode tag and check that it == [APPLICATION tagnum] */
+#define check_apptag(tagexpect)						\
+{									\
+    taginfo t1;								\
+    retval = asn1_get_tag_2(&buf, &t1);					\
+    if (retval) clean_return (retval);					\
+    if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED)	\
+	clean_return(ASN1_BAD_ID);					\
+    if (t1.tagnum != (tagexpect)) clean_return(KRB5_BADMSGTYPE);	\
+    asn1class = t1.asn1class;						\
+    construction = t1.construction;					\
+    tagnum = t1.tagnum;							\
+}
+
+
+
+/* process a structure *******************************************/
+
+/* decode an explicit tag and place the number in tagnum */
+#define next_tag()				\
+{ taginfo t2;					\
+  retval = asn1_get_tag_2(&subbuf, &t2);	\
+  if(retval) clean_return(retval);		\
+  asn1class = t2.asn1class;			\
+  construction = t2.construction;		\
+  tagnum = t2.tagnum;				\
+  indef = t2.indef;				\
+  taglen = t2.length;				\
+}
+
+#define get_eoc()						\
+{								\
+    taginfo t3;							\
+    retval = asn1_get_tag_2(&subbuf, &t3);			\
+    if (retval) return retval;					\
+    if (t3.asn1class != UNIVERSAL || t3.tagnum || t3.indef)	\
+        return ASN1_MISSING_EOC;				\
+    asn1class = t3.asn1class;					\
+    construction = t3.construction;				\
+    tagnum = t3.tagnum;						\
+    indef = t3.indef;						\
+}
+
+/* decode sequence header and initialize tagnum with the first field */
+#define begin_structure()\
+unsigned int taglen;\
+asn1buf subbuf;\
+int seqindef;\
+int indef;\
+retval = asn1_get_sequence(&buf,&length,&seqindef);\
+if(retval) clean_return(retval);\
+retval = asn1buf_imbed(&subbuf,&buf,length,seqindef);\
+if(retval) clean_return(retval);\
+next_tag()
+
+#define end_structure()\
+retval = asn1buf_sync(&buf,&subbuf,asn1class,tagnum,length,indef,seqindef);\
+if (retval) clean_return(retval)
+
+/* process fields *******************************************/
+/* normal fields ************************/
+#define get_field_body(var,decoder)\
+retval = decoder(&subbuf,&(var));\
+if(retval) clean_return(retval);\
+if (indef) { get_eoc(); }\
+next_tag()
+
+/* decode a field (<[UNIVERSAL id]> <length> <contents>)
+    check that the id number == tagexpect then
+    decode into var
+    get the next tag */
+#define get_field(var,tagexpect,decoder)\
+if(tagnum > (tagexpect)) clean_return(ASN1_MISSING_FIELD);\
+if(tagnum < (tagexpect)) clean_return(ASN1_MISPLACED_FIELD);\
+if(asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
+  clean_return(ASN1_BAD_ID);\
+get_field_body(var,decoder)
+
+/* decode (or skip, if not present) an optional field */
+#define opt_field(var,tagexpect,decoder)				\
+  if (asn1buf_remains(&subbuf, seqindef)) {				\
+    if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
+      clean_return(ASN1_BAD_ID);					\
+    if (tagnum == (tagexpect)) {					\
+      get_field_body(var,decoder);					\
+    }									\
+  }
+
+/* field w/ accompanying length *********/
+#define get_lenfield_body(len,var,decoder)\
+retval = decoder(&subbuf,&(len),&(var));\
+if(retval) clean_return(retval);\
+if (indef) { get_eoc(); }\
+next_tag()
+
+/* decode a field w/ its length (for string types) */
+#define get_lenfield(len,var,tagexpect,decoder)\
+if(tagnum > (tagexpect)) clean_return(ASN1_MISSING_FIELD);\
+if(tagnum < (tagexpect)) clean_return(ASN1_MISPLACED_FIELD);\
+if(asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)\
+  clean_return(ASN1_BAD_ID);\
+get_lenfield_body(len,var,decoder)
+
+/* decode an optional field w/ length */
+#define opt_lenfield(len,var,tagexpect,decoder)				\
+  if (asn1buf_remains(&subbuf, seqindef)) {				\
+    if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
+      clean_return(ASN1_BAD_ID);					\
+    if (tagnum == (tagexpect)) {					\
+      get_lenfield_body(len,var,decoder);				\
+    }									\
+  }
+  
+
+/* clean up ******************************************************/
+/* finish up */
+/* to make things less painful, assume the cleanup is passed rep */
+#define cleanup(cleanup_routine)\
+   return 0; \
+error_out: \
+   if (rep && *rep) { \
+	cleanup_routine(*rep); \
+	*rep = NULL; \
+   } \
+   return retval;
+
+#define cleanup_none()\
+   return 0; \
+error_out: \
+   return retval;
+	
+#define cleanup_manual()\
+   return 0;
+
+#define free_field(rep,f) if ((rep)->f) free((rep)->f)
+#define clear_field(rep,f) (*(rep))->f = 0
+
+krb5_error_code decode_krb5_authenticator(const krb5_data *code, krb5_authenticator **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_authenticator);
+  clear_field(rep,subkey);
+  clear_field(rep,checksum);
+  clear_field(rep,client);
+
+  check_apptag(2);
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,0,asn1_decode_kvno);
+      if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+    alloc_field((*rep)->client,krb5_principal_data);
+    get_field((*rep)->client,1,asn1_decode_realm);
+    get_field((*rep)->client,2,asn1_decode_principal_name);
+    if(tagnum == 3){
+      alloc_field((*rep)->checksum,krb5_checksum);
+      get_field(*((*rep)->checksum),3,asn1_decode_checksum); }
+    get_field((*rep)->cusec,4,asn1_decode_int32);
+    get_field((*rep)->ctime,5,asn1_decode_kerberos_time);
+    if(tagnum == 6){ alloc_field((*rep)->subkey,krb5_keyblock); }
+    opt_field(*((*rep)->subkey),6,asn1_decode_encryption_key);
+    opt_field((*rep)->seq_number,7,asn1_decode_seqnum);
+    opt_field((*rep)->authorization_data,8,asn1_decode_authorization_data);
+    (*rep)->magic = KV5M_AUTHENTICATOR;
+    end_structure();
+  }
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,subkey);
+      free_field(*rep,checksum);
+      free_field(*rep,client);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+krb5_error_code
+KRB5_CALLCONV
+krb5_decode_ticket(const krb5_data *code, krb5_ticket **rep)
+{
+    return decode_krb5_ticket(code, rep);
+}
+
+krb5_error_code decode_krb5_ticket(const krb5_data *code, krb5_ticket **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_ticket);
+  clear_field(rep,server);
+  
+  check_apptag(1);
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,0,asn1_decode_kvno);
+      if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO);
+    }
+    alloc_field((*rep)->server,krb5_principal_data);
+    get_field((*rep)->server,1,asn1_decode_realm);
+    get_field((*rep)->server,2,asn1_decode_principal_name);
+    get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
+    (*rep)->magic = KV5M_TICKET;
+    end_structure();
+  }
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,server);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+krb5_error_code decode_krb5_encryption_key(const krb5_data *code, krb5_keyblock **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_keyblock);
+
+  { begin_structure();
+    get_field((*rep)->enctype,0,asn1_decode_enctype);
+    get_lenfield((*rep)->length,(*rep)->contents,1,asn1_decode_octetstring);
+    end_structure();
+    (*rep)->magic = KV5M_KEYBLOCK;
+  }
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_enc_tkt_part(const krb5_data *code, krb5_enc_tkt_part **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_enc_tkt_part);
+  clear_field(rep,session);
+  clear_field(rep,client);
+
+  check_apptag(3);
+  { begin_structure();
+    get_field((*rep)->flags,0,asn1_decode_ticket_flags);
+    alloc_field((*rep)->session,krb5_keyblock);
+    get_field(*((*rep)->session),1,asn1_decode_encryption_key);
+    alloc_field((*rep)->client,krb5_principal_data);
+    get_field((*rep)->client,2,asn1_decode_realm);
+    get_field((*rep)->client,3,asn1_decode_principal_name);
+    get_field((*rep)->transited,4,asn1_decode_transited_encoding);
+    get_field((*rep)->times.authtime,5,asn1_decode_kerberos_time);
+    if (tagnum == 6)
+      { get_field((*rep)->times.starttime,6,asn1_decode_kerberos_time); }
+    else
+      (*rep)->times.starttime=(*rep)->times.authtime;
+    get_field((*rep)->times.endtime,7,asn1_decode_kerberos_time);
+    opt_field((*rep)->times.renew_till,8,asn1_decode_kerberos_time);
+    opt_field((*rep)->caddrs,9,asn1_decode_host_addresses);
+    opt_field((*rep)->authorization_data,10,asn1_decode_authorization_data);
+    (*rep)->magic = KV5M_ENC_TKT_PART;
+    end_structure();
+  }
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,session);
+      free_field(*rep,client);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+krb5_error_code decode_krb5_enc_kdc_rep_part(const krb5_data *code, krb5_enc_kdc_rep_part **rep)
+{
+  taginfo t4;
+  setup_buf_only();
+  alloc_field(*rep,krb5_enc_kdc_rep_part);
+
+  retval = asn1_get_tag_2(&buf, &t4);
+  if (retval) clean_return(retval);
+  if (t4.asn1class != APPLICATION || t4.construction != CONSTRUCTED) clean_return(ASN1_BAD_ID);
+  if (t4.tagnum == 25) (*rep)->msg_type = KRB5_AS_REP;
+  else if(t4.tagnum == 26) (*rep)->msg_type = KRB5_TGS_REP;
+  else clean_return(KRB5_BADMSGTYPE);
+
+  retval = asn1_decode_enc_kdc_rep_part(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_as_rep(const krb5_data *code, krb5_kdc_rep **rep)
+{
+  setup_no_length();
+  alloc_field(*rep,krb5_kdc_rep);
+
+  check_apptag(11);
+  retval = asn1_decode_kdc_rep(&buf,*rep);
+  if(retval) clean_return(retval);
+#ifdef KRB5_MSGTYPE_STRICT
+  if((*rep)->msg_type != KRB5_AS_REP)
+    clean_return(KRB5_BADMSGTYPE);
+#endif
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_tgs_rep(const krb5_data *code, krb5_kdc_rep **rep)
+{
+  setup_no_length();
+  alloc_field(*rep,krb5_kdc_rep);
+
+  check_apptag(13);
+  retval = asn1_decode_kdc_rep(&buf,*rep);
+  if(retval) clean_return(retval);
+#ifdef KRB5_MSGTYPE_STRICT
+  if((*rep)->msg_type != KRB5_TGS_REP) clean_return(KRB5_BADMSGTYPE);
+#endif
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_ap_req(const krb5_data *code, krb5_ap_req **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_ap_req);
+  clear_field(rep,ticket);
+
+  check_apptag(14);
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,0,asn1_decode_kvno);
+      if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+    { krb5_msgtype msg_type;
+      get_field(msg_type,1,asn1_decode_msgtype);
+#ifdef KRB5_MSGTYPE_STRICT
+      if(msg_type != KRB5_AP_REQ) clean_return(KRB5_BADMSGTYPE);
+#endif
+    }
+    get_field((*rep)->ap_options,2,asn1_decode_ap_options);
+    alloc_field((*rep)->ticket,krb5_ticket);
+    get_field(*((*rep)->ticket),3,asn1_decode_ticket);
+    get_field((*rep)->authenticator,4,asn1_decode_encrypted_data);
+    end_structure();
+    (*rep)->magic = KV5M_AP_REQ;
+  }
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,ticket);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+krb5_error_code decode_krb5_ap_rep(const krb5_data *code, krb5_ap_rep **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_ap_rep);
+
+  check_apptag(15);
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,0,asn1_decode_kvno);
+      if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+    { krb5_msgtype msg_type;
+      get_field(msg_type,1,asn1_decode_msgtype);
+#ifdef KRB5_MSGTYPE_STRICT
+      if(msg_type != KRB5_AP_REP) clean_return(KRB5_BADMSGTYPE);
+#endif
+    }
+    get_field((*rep)->enc_part,2,asn1_decode_encrypted_data);
+    end_structure();
+    (*rep)->magic = KV5M_AP_REP;
+  }
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_ap_rep_enc_part(const krb5_data *code, krb5_ap_rep_enc_part **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_ap_rep_enc_part);
+  clear_field(rep,subkey);
+
+  check_apptag(27);
+  { begin_structure();
+    get_field((*rep)->ctime,0,asn1_decode_kerberos_time);
+    get_field((*rep)->cusec,1,asn1_decode_int32);
+    if(tagnum == 2){ alloc_field((*rep)->subkey,krb5_keyblock); }
+    opt_field(*((*rep)->subkey),2,asn1_decode_encryption_key);
+    opt_field((*rep)->seq_number,3,asn1_decode_seqnum);
+    end_structure();
+    (*rep)->magic = KV5M_AP_REP_ENC_PART;
+  }
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,subkey);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+krb5_error_code decode_krb5_as_req(const krb5_data *code, krb5_kdc_req **rep)
+{
+  setup_no_length();
+  alloc_field(*rep,krb5_kdc_req);
+
+  check_apptag(10);
+  retval = asn1_decode_kdc_req(&buf,*rep);
+  if(retval) clean_return(retval);
+#ifdef KRB5_MSGTYPE_STRICT
+  if((*rep)->msg_type != KRB5_AS_REQ) clean_return(KRB5_BADMSGTYPE);
+#endif
+  
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_tgs_req(const krb5_data *code, krb5_kdc_req **rep)
+{
+  setup_no_length();
+  alloc_field(*rep,krb5_kdc_req);
+
+  check_apptag(12);
+  retval = asn1_decode_kdc_req(&buf,*rep);
+  if(retval) clean_return(retval);
+#ifdef KRB5_MSGTYPE_STRICT
+  if((*rep)->msg_type != KRB5_TGS_REQ) clean_return(KRB5_BADMSGTYPE);
+#endif
+  
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_kdc_req_body(const krb5_data *code, krb5_kdc_req **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_kdc_req);
+
+  retval = asn1_decode_kdc_req_body(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+/*
+ * decode_krb5_safe_with_body
+ *
+ * Like decode_krb5_safe(), but grabs the encoding of the
+ * KRB-SAFE-BODY as well, in case re-encoding would produce a
+ * different encoding.  (Yes, we're using DER, but there's this
+ * annoying problem with pre-1.3.x code using signed sequence numbers,
+ * which we permissively decode and cram into unsigned 32-bit numbers.
+ * When they're re-encoded, they're no longer negative if they started
+ * out negative, so checksum verification fails.)
+ *
+ * This does *not* perform any copying; the returned pointer to the
+ * encoded KRB-SAFE-BODY points into the input buffer.
+ */
+krb5_error_code decode_krb5_safe_with_body(
+  const krb5_data *code,
+  krb5_safe **rep,
+  krb5_data *body)
+{
+  krb5_data tmpbody;
+  setup();
+  alloc_field(*rep,krb5_safe);
+  clear_field(rep,checksum);
+
+  check_apptag(20);
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,0,asn1_decode_kvno);
+      if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+    { krb5_msgtype msg_type;
+      get_field(msg_type,1,asn1_decode_msgtype);
+#ifdef KRB5_MSGTYPE_STRICT
+      if(msg_type != KRB5_SAFE) clean_return(KRB5_BADMSGTYPE);
+#endif
+    }
+    /*
+     * Gross kludge to extract pointer to encoded safe-body.  Relies
+     * on tag prefetch done by next_tag().  Don't handle indefinite
+     * encoding, as it's too much work.
+     */
+    if (!indef) {
+      tmpbody.length = taglen;
+      tmpbody.data = subbuf.next;
+    } else {
+      tmpbody.length = 0;
+      tmpbody.data = NULL;
+    }
+    get_field(**rep,2,asn1_decode_krb_safe_body);
+    alloc_field((*rep)->checksum,krb5_checksum);
+    get_field(*((*rep)->checksum),3,asn1_decode_checksum);
+  (*rep)->magic = KV5M_SAFE;
+    end_structure();
+  }
+  if (body != NULL)
+    *body = tmpbody;
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,checksum);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+krb5_error_code decode_krb5_safe(const krb5_data *code, krb5_safe **rep)
+{
+  return decode_krb5_safe_with_body(code, rep, NULL);
+}
+
+krb5_error_code decode_krb5_priv(const krb5_data *code, krb5_priv **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_priv);
+
+  check_apptag(21);
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,0,asn1_decode_kvno);
+      if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+    { krb5_msgtype msg_type;
+      get_field(msg_type,1,asn1_decode_msgtype);
+#ifdef KRB5_MSGTYPE_STRICT
+      if(msg_type != KRB5_PRIV) clean_return(KRB5_BADMSGTYPE);
+#endif
+    }
+    get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
+    (*rep)->magic = KV5M_PRIV;
+    end_structure();
+  }
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_enc_priv_part(const krb5_data *code, krb5_priv_enc_part **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_priv_enc_part);
+  clear_field(rep,r_address);
+  clear_field(rep,s_address);
+
+  check_apptag(28);
+  { begin_structure();
+    get_lenfield((*rep)->user_data.length,(*rep)->user_data.data,0,asn1_decode_charstring);
+    opt_field((*rep)->timestamp,1,asn1_decode_kerberos_time);
+    opt_field((*rep)->usec,2,asn1_decode_int32);
+    opt_field((*rep)->seq_number,3,asn1_decode_seqnum);
+    alloc_field((*rep)->s_address,krb5_address);
+    get_field(*((*rep)->s_address),4,asn1_decode_host_address);
+    if(tagnum == 5){ alloc_field((*rep)->r_address,krb5_address); }
+    opt_field(*((*rep)->r_address),5,asn1_decode_host_address);
+    (*rep)->magic = KV5M_PRIV_ENC_PART;
+    end_structure();
+  }
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,r_address);
+      free_field(*rep,s_address);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+krb5_error_code decode_krb5_cred(const krb5_data *code, krb5_cred **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_cred);
+
+  check_apptag(22);
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,0,asn1_decode_kvno);
+      if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+    { krb5_msgtype msg_type;
+      get_field(msg_type,1,asn1_decode_msgtype);
+#ifdef KRB5_MSGTYPE_STRICT
+      if(msg_type != KRB5_CRED) clean_return(KRB5_BADMSGTYPE);
+#endif
+    }
+    get_field((*rep)->tickets,2,asn1_decode_sequence_of_ticket);
+    get_field((*rep)->enc_part,3,asn1_decode_encrypted_data);
+    (*rep)->magic = KV5M_CRED;
+    end_structure();
+  }
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_enc_cred_part(const krb5_data *code, krb5_cred_enc_part **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_cred_enc_part);
+  clear_field(rep,r_address);
+  clear_field(rep,s_address);
+
+  check_apptag(29);
+  { begin_structure();
+    get_field((*rep)->ticket_info,0,asn1_decode_sequence_of_krb_cred_info);
+    opt_field((*rep)->nonce,1,asn1_decode_int32);
+    opt_field((*rep)->timestamp,2,asn1_decode_kerberos_time);
+    opt_field((*rep)->usec,3,asn1_decode_int32);
+    if(tagnum == 4){ alloc_field((*rep)->s_address,krb5_address); }
+    opt_field(*((*rep)->s_address),4,asn1_decode_host_address);
+    if(tagnum == 5){ alloc_field((*rep)->r_address,krb5_address); }
+    opt_field(*((*rep)->r_address),5,asn1_decode_host_address);
+    (*rep)->magic = KV5M_CRED_ENC_PART;
+    end_structure();
+  }
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,r_address);
+      free_field(*rep,s_address);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+
+krb5_error_code decode_krb5_error(const krb5_data *code, krb5_error **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_error);
+  clear_field(rep,server);
+  clear_field(rep,client);
+  
+  check_apptag(30);
+  { begin_structure();
+    { krb5_kvno kvno;
+      get_field(kvno,0,asn1_decode_kvno);
+      if(kvno != KVNO) clean_return(KRB5KDC_ERR_BAD_PVNO); }
+    { krb5_msgtype msg_type;
+      get_field(msg_type,1,asn1_decode_msgtype);
+#ifdef KRB5_MSGTYPE_STRICT
+      if(msg_type != KRB5_ERROR) clean_return(KRB5_BADMSGTYPE);
+#endif
+    }
+    opt_field((*rep)->ctime,2,asn1_decode_kerberos_time);
+    opt_field((*rep)->cusec,3,asn1_decode_int32);
+    get_field((*rep)->stime,4,asn1_decode_kerberos_time);
+    get_field((*rep)->susec,5,asn1_decode_int32);
+    get_field((*rep)->error,6,asn1_decode_ui_4);
+    if(tagnum == 7){ alloc_field((*rep)->client,krb5_principal_data); }
+    opt_field((*rep)->client,7,asn1_decode_realm);
+    opt_field((*rep)->client,8,asn1_decode_principal_name);
+    alloc_field((*rep)->server,krb5_principal_data);
+    get_field((*rep)->server,9,asn1_decode_realm);
+    get_field((*rep)->server,10,asn1_decode_principal_name);
+    opt_lenfield((*rep)->text.length,(*rep)->text.data,11,asn1_decode_generalstring);
+    opt_lenfield((*rep)->e_data.length,(*rep)->e_data.data,12,asn1_decode_charstring);
+    (*rep)->magic = KV5M_ERROR;
+    end_structure();
+  }
+  cleanup_manual();
+error_out:
+  if (rep && *rep) {
+      free_field(*rep,server);
+      free_field(*rep,client);
+      free(*rep);
+      *rep = NULL;
+  }
+  return retval;
+}
+
+krb5_error_code decode_krb5_authdata(const krb5_data *code, krb5_authdata ***rep)
+{
+  setup_buf_only();
+  *rep = 0;
+  retval = asn1_decode_authorization_data(&buf,rep);
+  if(retval) clean_return(retval);
+  cleanup_none();		/* we're not allocating anything here... */
+}
+
+krb5_error_code decode_krb5_pwd_sequence(const krb5_data *code, passwd_phrase_element **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,passwd_phrase_element);
+  retval = asn1_decode_passwdsequence(&buf,*rep);
+  if(retval) clean_return(retval);
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_pwd_data(const krb5_data *code, krb5_pwd_data **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_pwd_data);
+  { begin_structure();
+    get_field((*rep)->sequence_count,0,asn1_decode_int);
+    get_field((*rep)->element,1,asn1_decode_sequence_of_passwdsequence);
+    (*rep)->magic = KV5M_PWD_DATA;
+    end_structure (); }
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_padata_sequence(const krb5_data *code, krb5_pa_data ***rep)
+{
+  setup_buf_only();
+  *rep = 0;
+  retval = asn1_decode_sequence_of_pa_data(&buf,rep);
+  if(retval) clean_return(retval);
+  cleanup_none();		/* we're not allocating anything here */
+}
+
+krb5_error_code decode_krb5_alt_method(const krb5_data *code, krb5_alt_method **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_alt_method);
+  { begin_structure();
+    get_field((*rep)->method,0,asn1_decode_int32);
+    if (tagnum == 1) {
+	get_lenfield((*rep)->length,(*rep)->data,1,asn1_decode_octetstring);
+    } else {
+	(*rep)->length = 0;
+	(*rep)->data = 0;
+    }
+    (*rep)->magic = KV5M_ALT_METHOD;
+    end_structure();
+  }
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_etype_info(const krb5_data *code, krb5_etype_info_entry ***rep)
+{
+  setup_buf_only();
+  *rep = 0;
+  retval = asn1_decode_etype_info(&buf,rep);
+  if(retval) clean_return(retval);
+  cleanup_none();		/* we're not allocating anything here */
+}
+
+krb5_error_code decode_krb5_etype_info2(const krb5_data *code, krb5_etype_info_entry ***rep)
+{
+    setup_buf_only();
+    *rep = 0;
+    retval = asn1_decode_etype_info2(&buf,rep, 0);
+    if (retval == ASN1_BAD_ID) {
+	retval = asn1buf_wrap_data(&buf,code);
+	if(retval) clean_return(retval);
+	retval = asn1_decode_etype_info2(&buf, rep, 1);
+    }
+    if(retval) clean_return(retval);
+    cleanup_none();		/* we're not allocating anything here */
+}
+
+
+krb5_error_code decode_krb5_enc_data(const krb5_data *code, krb5_enc_data **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_enc_data);
+
+  retval = asn1_decode_encrypted_data(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_pa_enc_ts(const krb5_data *code, krb5_pa_enc_ts **rep)
+{
+  setup();
+  alloc_field(*rep,krb5_pa_enc_ts);
+  { begin_structure();
+    get_field((*rep)->patimestamp,0,asn1_decode_kerberos_time);
+    if (tagnum == 1) {
+	get_field((*rep)->pausec,1,asn1_decode_int32);
+    } else
+	(*rep)->pausec = 0;
+    end_structure (); }
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_sam_challenge(const krb5_data *code, krb5_sam_challenge **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_sam_challenge);
+
+  retval = asn1_decode_sam_challenge(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_sam_challenge_2(const krb5_data *code, krb5_sam_challenge_2 **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_sam_challenge_2);
+
+  retval = asn1_decode_sam_challenge_2(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_sam_challenge_2_body(const krb5_data *code, krb5_sam_challenge_2_body **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep, krb5_sam_challenge_2_body);
+
+  retval = asn1_decode_sam_challenge_2_body(&buf, *rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_enc_sam_key(const krb5_data *code, krb5_sam_key **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_sam_key);
+
+  retval = asn1_decode_enc_sam_key(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_enc_sam_response_enc(const krb5_data *code, krb5_enc_sam_response_enc **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_enc_sam_response_enc);
+
+  retval = asn1_decode_enc_sam_response_enc(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_enc_sam_response_enc_2(const krb5_data *code, krb5_enc_sam_response_enc_2 **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_enc_sam_response_enc_2);
+
+  retval = asn1_decode_enc_sam_response_enc_2(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_sam_response(const krb5_data *code, krb5_sam_response **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_sam_response);
+
+  retval = asn1_decode_sam_response(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_sam_response_2(const krb5_data *code, krb5_sam_response_2 **rep)
+{
+  setup_buf_only();
+  alloc_field(*rep,krb5_sam_response_2);
+
+  retval = asn1_decode_sam_response_2(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
+krb5_error_code decode_krb5_predicted_sam_response(const krb5_data *code, krb5_predicted_sam_response **rep)
+{
+  setup_buf_only();		/* preallocated */
+  alloc_field(*rep,krb5_predicted_sam_response);
+
+  retval = asn1_decode_predicted_sam_response(&buf,*rep);
+  if(retval) clean_return(retval);
+
+  cleanup(free);
+}
+
diff --git a/mechglue/src/lib/krb5/asn.1/krb5_encode.c b/mechglue/src/lib/krb5/asn.1/krb5_encode.c
new file mode 100644
index 000000000..639db4347
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/krb5_encode.c
@@ -0,0 +1,889 @@
+/*
+ * src/lib/krb5/asn.1/krb5_encode.c
+ * 
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "asn1_k_encode.h"
+#include "asn1_encode.h"
+#include "krbasn1.h"
+#include "asn1buf.h"
+#include "asn1_make.h"
+
+/**************** Macros (these save a lot of typing) ****************/
+
+/**** krb5 macros ****/
+#if 0
+   How to write a krb5 encoder function using these macros:
+
+   asn1_error_code encode_krb5_structure(const krb5_type *rep,
+                                         krb5_data **code)
+   {
+     krb5_setup();
+
+     krb5_addfield(rep->last_field, n, asn1_type);
+     krb5_addfield(rep->next_to_last_field, n-1, asn1_type);
+     ...
+
+     /* for OPTIONAL fields */
+     if(rep->field_i == should_not_be_omitted)
+       krb5_addfield(rep->field_i, i, asn1_type);
+
+     /* for string fields (these encoders take an additional argument,
+	the length of the string) */
+     addlenfield(rep->field_length, rep->field, i-1, asn1_type);
+
+     /* if you really have to do things yourself... */
+     retval = asn1_encode_asn1_type(buf,rep->field,&length);
+     if(retval) return retval;
+     sum += length;
+     retval = asn1_make_etag(buf,
+			    [UNIVERSAL/APPLICATION/CONTEXT_SPECIFIC/PRIVATE],
+			    tag_number, length, &length);
+     if(retval) return retval;
+     sum += length;
+
+     ...
+     krb5_addfield(rep->second_field, 1, asn1_type);
+     krb5_addfield(rep->first_field, 0, asn1_type);
+     krb5_makeseq();
+     krb5_apptag(tag_number);
+
+     krb5_cleanup();
+   }
+#endif
+
+/* setup() -- create and initialize bookkeeping variables
+     retval: stores error codes returned from subroutines
+     buf: the coding buffer
+     length: length of the most-recently produced encoding
+     sum: cumulative length of the entire encoding */
+#define krb5_setup()\
+  asn1_error_code retval;\
+  asn1buf *buf=NULL;\
+  unsigned int length, sum=0;\
+\
+  if(rep == NULL) return ASN1_MISSING_FIELD;\
+\
+  retval = asn1buf_create(&buf);\
+  if(retval) return retval
+  
+/* krb5_addfield -- add a field, or component, to the encoding */
+#define krb5_addfield(value,tag,encoder)\
+{ retval = encoder(buf,value,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length;\
+  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length; }
+
+/* krb5_addlenfield -- add a field whose length must be separately specified */
+#define krb5_addlenfield(len,value,tag,encoder)\
+{ retval = encoder(buf,len,value,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length;\
+  retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length; }
+
+/* form a sequence (by adding a sequence header to the current encoding) */
+#define krb5_makeseq()\
+  retval = asn1_make_sequence(buf,sum,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length
+
+/* add an APPLICATION class tag to the current encoding */
+#define krb5_apptag(num)\
+  retval = asn1_make_etag(buf,APPLICATION,num,sum,&length);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  sum += length
+
+/* produce the final output and clean up the workspace */
+#define krb5_cleanup()\
+  retval = asn12krb5_buf(buf,code);\
+  if(retval){\
+    asn1buf_destroy(&buf);\
+    return retval; }\
+  retval = asn1buf_destroy(&buf);\
+  if(retval){\
+    return retval; }\
+\
+  return 0
+
+krb5_error_code encode_krb5_authenticator(const krb5_authenticator *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* authorization-data[8]	AuthorizationData OPTIONAL */
+  if(rep->authorization_data != NULL &&
+     rep->authorization_data[0] != NULL){
+    retval = asn1_encode_authorization_data(buf, (const krb5_authdata **)
+					    rep->authorization_data,
+					    &length);
+    if(retval){
+      asn1buf_destroy(&buf);
+      return retval; }
+    sum += length;
+    retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,8,length,&length);
+    if(retval){
+      asn1buf_destroy(&buf);
+      return retval; }
+    sum += length;
+  }
+
+  /* seq-number[7]		INTEGER OPTIONAL */
+  if(rep->seq_number != 0)
+    krb5_addfield(rep->seq_number,7,asn1_encode_unsigned_integer);
+
+  /* subkey[6]			EncryptionKey OPTIONAL */
+  if(rep->subkey != NULL)
+    krb5_addfield(rep->subkey,6,asn1_encode_encryption_key);
+
+  /* ctime[5]			KerberosTime */
+  krb5_addfield(rep->ctime,5,asn1_encode_kerberos_time);
+
+  /* cusec[4]			INTEGER */
+  krb5_addfield(rep->cusec,4,asn1_encode_integer);
+
+  /* cksum[3]			Checksum OPTIONAL */
+  if(rep->checksum != NULL)
+    krb5_addfield(rep->checksum,3,asn1_encode_checksum);
+
+  /* cname[2]			PrincipalName */
+  krb5_addfield(rep->client,2,asn1_encode_principal_name);
+
+  /* crealm[1]			Realm */
+  krb5_addfield(rep->client,1,asn1_encode_realm);
+
+  /* authenticator-vno[0]	INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* Authenticator ::= [APPLICATION 2] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(2);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* enc-part[3]	EncryptedData */
+  krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data);
+
+  /* sname [2]		PrincipalName */
+  krb5_addfield(rep->server,2,asn1_encode_principal_name);
+
+  /* realm [1]		Realm */
+  krb5_addfield(rep->server,1,asn1_encode_realm);
+
+  /* tkt-vno [0]	INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* Ticket ::= [APPLICATION 1] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(1);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_encryption_key(const krb5_keyblock *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* keyvalue[1]	OCTET STRING */
+  krb5_addlenfield(rep->length,rep->contents,1,asn1_encode_octetstring);
+
+  /* enctype[0]		INTEGER */
+  krb5_addfield(rep->enctype,0,asn1_encode_integer);
+
+  /* EncryptionKey ::= SEQUENCE */
+  krb5_makeseq();
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_enc_tkt_part(const krb5_enc_tkt_part *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* authorization-data[10]	AuthorizationData OPTIONAL */
+  if(rep->authorization_data != NULL &&
+     rep->authorization_data[0] != NULL)
+    krb5_addfield((const krb5_authdata**)rep->authorization_data,
+		  10,asn1_encode_authorization_data);
+
+  /* caddr[9]			HostAddresses OPTIONAL */
+  if(rep->caddrs != NULL && rep->caddrs[0] != NULL)
+    krb5_addfield((const krb5_address**)rep->caddrs,9,asn1_encode_host_addresses);
+
+  /* renew-till[8]		KerberosTime OPTIONAL */
+  if(rep->times.renew_till)
+    krb5_addfield(rep->times.renew_till,8,asn1_encode_kerberos_time);
+
+  /* endtime[7]			KerberosTime */
+  krb5_addfield(rep->times.endtime,7,asn1_encode_kerberos_time);
+
+  /* starttime[6]		KerberosTime OPTIONAL */
+  if(rep->times.starttime)
+    krb5_addfield(rep->times.starttime,6,asn1_encode_kerberos_time);
+
+  /* authtime[5]		KerberosTime */
+  krb5_addfield(rep->times.authtime,5,asn1_encode_kerberos_time);
+
+  /* transited[4]		TransitedEncoding */
+  krb5_addfield(&(rep->transited),4,asn1_encode_transited_encoding);
+
+  /* cname[3]			PrincipalName */
+  krb5_addfield(rep->client,3,asn1_encode_principal_name);
+
+  /* crealm[2]			Realm */
+  krb5_addfield(rep->client,2,asn1_encode_realm);
+
+  /* key[1]			EncryptionKey */
+  krb5_addfield(rep->session,1,asn1_encode_encryption_key);
+
+  /* flags[0]			TicketFlags */
+  krb5_addfield(rep->flags,0,asn1_encode_ticket_flags);
+
+  /* EncTicketPart ::= [APPLICATION 3] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(3);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_enc_kdc_rep_part(const krb5_enc_kdc_rep_part *rep, krb5_data **code)
+{
+  asn1_error_code retval;
+  asn1buf *buf=NULL;
+  unsigned int length, sum=0;
+
+  if(rep == NULL) return ASN1_MISSING_FIELD;
+
+  retval = asn1buf_create(&buf);
+  if(retval) return retval;
+
+  retval = asn1_encode_enc_kdc_rep_part(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+
+#ifdef KRB5_ENCKRB5KDCREPPART_COMPAT
+  krb5_apptag(26);
+#else
+  /* XXX WRONG!!! Should use 25 || 26, not the outer KDC_REP tags! */
+  if (rep->msg_type == KRB5_AS_REP) { krb5_apptag(ASN1_KRB_AS_REP); }
+  else if (rep->msg_type == KRB5_TGS_REP) { krb5_apptag(ASN1_KRB_TGS_REP); }
+  else return KRB5_BADMSGTYPE;
+#endif
+  krb5_cleanup();
+}
+
+/* yes, the translation is identical to that used for KDC__REP */ 
+krb5_error_code encode_krb5_as_rep(const krb5_kdc_rep *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* AS-REP ::= [APPLICATION 11] KDC-REP */
+  retval = asn1_encode_kdc_rep(KRB5_AS_REP,buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+
+  krb5_apptag(11);
+
+  krb5_cleanup();
+}
+
+/* yes, the translation is identical to that used for KDC__REP */ 
+krb5_error_code encode_krb5_tgs_rep(const krb5_kdc_rep *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* TGS-REP ::= [APPLICATION 13] KDC-REP */
+  retval = asn1_encode_kdc_rep(KRB5_TGS_REP,buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+
+  krb5_apptag(13);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_ap_req(const krb5_ap_req *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* authenticator[4]	EncryptedData */
+  krb5_addfield(&(rep->authenticator),4,asn1_encode_encrypted_data);
+
+  /* ticket[3]		Ticket */
+  krb5_addfield(rep->ticket,3,asn1_encode_ticket);
+
+  /* ap-options[2]	APOptions */
+  krb5_addfield(rep->ap_options,2,asn1_encode_ap_options);
+
+  /* msg-type[1]	INTEGER */
+  krb5_addfield(ASN1_KRB_AP_REQ,1,asn1_encode_integer);
+
+  /* pvno[0]		INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* AP-REQ ::=	[APPLICATION 14] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(14);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_ap_rep(const krb5_ap_rep *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* enc-part[2]	EncryptedData */
+  krb5_addfield(&(rep->enc_part),2,asn1_encode_encrypted_data);
+  
+  /* msg-type[1]	INTEGER */
+  krb5_addfield(ASN1_KRB_AP_REP,1,asn1_encode_integer);
+  
+  /* pvno[0]		INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+  
+  /* AP-REP ::=	[APPLICATION 15] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(15);
+  
+  krb5_cleanup();
+}
+
+
+krb5_error_code encode_krb5_ap_rep_enc_part(const krb5_ap_rep_enc_part *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* seq-number[3]	INTEGER OPTIONAL */
+  if(rep->seq_number)
+    krb5_addfield(rep->seq_number,3,asn1_encode_unsigned_integer);
+
+  /* subkey[2]		EncryptionKey OPTIONAL */
+  if(rep->subkey != NULL)
+    krb5_addfield(rep->subkey,2,asn1_encode_encryption_key);
+
+  /* cusec[1]		INTEGER */
+  krb5_addfield(rep->cusec,1,asn1_encode_integer);
+
+  /* ctime[0]		KerberosTime */
+  krb5_addfield(rep->ctime,0,asn1_encode_kerberos_time);
+
+  /* EncAPRepPart ::= [APPLICATION 27] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(27);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_as_req(const krb5_kdc_req *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* AS-REQ ::= [APPLICATION 10] KDC-REQ */
+  retval = asn1_encode_kdc_req(KRB5_AS_REQ,buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+
+  krb5_apptag(10);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_tgs_req(const krb5_kdc_req *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* TGS-REQ ::= [APPLICATION 12] KDC-REQ */
+  retval = asn1_encode_kdc_req(KRB5_TGS_REQ,buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+
+  krb5_apptag(12);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_kdc_req_body(const krb5_kdc_req *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  retval = asn1_encode_kdc_req_body(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+
+  krb5_cleanup();
+}
+
+
+krb5_error_code encode_krb5_safe(const krb5_safe *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* cksum[3]		Checksum */
+  krb5_addfield(rep->checksum,3,asn1_encode_checksum);
+
+  /* safe-body[2]	KRB-SAFE-BODY */
+  krb5_addfield(rep,2,asn1_encode_krb_safe_body);
+
+  /* msg-type[1]	INTEGER */
+  krb5_addfield(ASN1_KRB_SAFE,1,asn1_encode_integer);
+
+  /* pvno[0]		INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* KRB-SAFE ::= [APPLICATION 20] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(20);
+
+  krb5_cleanup();
+}
+
+/*
+ * encode_krb5_safe_with_body
+ *
+ * Like encode_krb5_safe(), except takes a saved KRB-SAFE-BODY
+ * encoding to avoid problems with re-encoding.
+ */
+krb5_error_code encode_krb5_safe_with_body(
+  const krb5_safe *rep,
+  const krb5_data *body,
+  krb5_data **code)
+{
+  krb5_setup();
+
+  if (body == NULL) {
+      asn1buf_destroy(&buf);
+      return ASN1_MISSING_FIELD;
+  }
+
+  /* cksum[3]		Checksum */
+  krb5_addfield(rep->checksum,3,asn1_encode_checksum);
+
+  /* safe-body[2]	KRB-SAFE-BODY */
+  krb5_addfield(body,2,asn1_encode_krb_saved_safe_body);
+
+  /* msg-type[1]	INTEGER */
+  krb5_addfield(ASN1_KRB_SAFE,1,asn1_encode_integer);
+
+  /* pvno[0]		INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* KRB-SAFE ::= [APPLICATION 20] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(20);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_priv(const krb5_priv *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* enc-part[3]	EncryptedData */
+  krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data);
+
+  /* msg-type[1]	INTEGER */
+  krb5_addfield(ASN1_KRB_PRIV,1,asn1_encode_integer);
+
+  /* pvno[0]		INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* KRB-PRIV ::= [APPLICATION 21] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(21);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_enc_priv_part(const krb5_priv_enc_part *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* r-address[5]	HostAddress OPTIONAL -- recip's addr */
+  if(rep->r_address)
+    krb5_addfield(rep->r_address,5,asn1_encode_host_address);
+
+  /* s-address[4]	HostAddress -- sender's addr */
+  krb5_addfield(rep->s_address,4,asn1_encode_host_address);
+
+  /* seq-number[3]	INTEGER OPTIONAL */
+  if(rep->seq_number)
+    krb5_addfield(rep->seq_number,3,asn1_encode_unsigned_integer);
+
+  /* usec[2]		INTEGER OPTIONAL */
+  if(rep->timestamp){
+    krb5_addfield(rep->usec,2,asn1_encode_integer);
+    /* timestamp[1]	KerberosTime OPTIONAL */
+    krb5_addfield(rep->timestamp,1,asn1_encode_kerberos_time);
+  }
+
+  /* user-data[0]	OCTET STRING */
+  krb5_addlenfield(rep->user_data.length,rep->user_data.data,0,asn1_encode_charstring);
+
+  /* EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(28);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_cred(const krb5_cred *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* enc-part[3]	EncryptedData */
+  krb5_addfield(&(rep->enc_part),3,asn1_encode_encrypted_data);
+
+  /* tickets[2]		SEQUENCE OF Ticket */
+  krb5_addfield((const krb5_ticket**)rep->tickets,2,asn1_encode_sequence_of_ticket);
+
+  /* msg-type[1]	INTEGER, -- KRB_CRED */
+  krb5_addfield(ASN1_KRB_CRED,1,asn1_encode_integer);
+
+  /* pvno[0]		INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* KRB-CRED ::= [APPLICATION 22] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(22);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_enc_cred_part(const krb5_cred_enc_part *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* r-address[5]	HostAddress OPTIONAL */
+  if(rep->r_address != NULL)
+    krb5_addfield(rep->r_address,5,asn1_encode_host_address);
+
+  /* s-address[4]	HostAddress OPTIONAL */
+  if(rep->s_address != NULL)
+    krb5_addfield(rep->s_address,4,asn1_encode_host_address);
+
+  /* usec[3]		INTEGER OPTIONAL */
+  if(rep->timestamp){
+    krb5_addfield(rep->usec,3,asn1_encode_integer);
+    /* timestamp[2]	KerberosTime OPTIONAL */
+    krb5_addfield(rep->timestamp,2,asn1_encode_kerberos_time);
+  }
+
+  /* nonce[1]		INTEGER OPTIONAL */
+  if(rep->nonce)
+    krb5_addfield(rep->nonce,1,asn1_encode_integer);
+
+  /* ticket-info[0]	SEQUENCE OF KrbCredInfo */
+  krb5_addfield((const krb5_cred_info**)rep->ticket_info,
+		0,asn1_encode_sequence_of_krb_cred_info);
+
+  /* EncKrbCredPart ::= [APPLICATION 29] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(29);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_error(const krb5_error *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* e-data[12]		OCTET STRING OPTIONAL */
+  if(rep->e_data.data != NULL && rep->e_data.length > 0)
+    krb5_addlenfield(rep->e_data.length,rep->e_data.data,12,asn1_encode_charstring);
+
+  /* e-text[11]		GeneralString OPTIONAL */
+  if(rep->text.data != NULL && rep->text.length > 0)
+    krb5_addlenfield(rep->text.length,rep->text.data,11,asn1_encode_generalstring);
+
+  /* sname[10]		PrincipalName -- Correct name */
+  krb5_addfield(rep->server,10,asn1_encode_principal_name);
+
+  /* realm[9]		Realm -- Correct realm */
+  krb5_addfield(rep->server,9,asn1_encode_realm);
+
+  /* cname[8]		PrincipalName OPTIONAL */
+  if(rep->client != NULL){
+    krb5_addfield(rep->client,8,asn1_encode_principal_name);
+    /* crealm[7]		Realm OPTIONAL */
+    krb5_addfield(rep->client,7,asn1_encode_realm);
+  }
+
+  /* error-code[6]	INTEGER */
+  krb5_addfield(rep->error,6,asn1_encode_ui_4);
+
+  /* susec[5]		INTEGER */
+  krb5_addfield(rep->susec,5,asn1_encode_integer);
+
+  /* stime[4]		KerberosTime */
+  krb5_addfield(rep->stime,4,asn1_encode_kerberos_time);
+
+  /* cusec[3]		INTEGER OPTIONAL */
+  if(rep->cusec)
+    krb5_addfield(rep->cusec,3,asn1_encode_integer);
+
+  /* ctime[2]		KerberosTime OPTIONAL */
+  if(rep->ctime)
+    krb5_addfield(rep->ctime,2,asn1_encode_kerberos_time);
+
+  /* msg-type[1]	INTEGER */
+  krb5_addfield(ASN1_KRB_ERROR,1,asn1_encode_integer);
+
+  /* pvno[0]		INTEGER */
+  krb5_addfield(KVNO,0,asn1_encode_integer);
+
+  /* KRB-ERROR ::= [APPLICATION 30] SEQUENCE */
+  krb5_makeseq();
+  krb5_apptag(30);
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_authdata(const krb5_authdata **rep, krb5_data **code)
+{
+  asn1_error_code retval;
+  asn1buf *buf=NULL;
+  unsigned int length;
+  
+  if(rep == NULL) return ASN1_MISSING_FIELD;
+
+  retval = asn1buf_create(&buf);
+  if(retval) return retval;
+
+  retval = asn1_encode_authorization_data(buf,(const krb5_authdata**)rep,
+					  &length);
+  if(retval) return retval;
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_alt_method(const krb5_alt_method *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* method-data[1]		OctetString OPTIONAL */
+  if(rep->data != NULL && rep->length > 0)
+    krb5_addlenfield(rep->length,rep->data,1,asn1_encode_octetstring);
+
+  /* method-type[0]		Integer */
+  krb5_addfield(rep->method,0,asn1_encode_integer);
+
+  krb5_makeseq();
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_etype_info(const krb5_etype_info_entry **rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_etype_info(buf,rep,&length, 0);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_etype_info2(const krb5_etype_info_entry **rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_etype_info(buf,rep,&length, 1);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+  
+
+krb5_error_code encode_krb5_enc_data(const krb5_enc_data *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  retval = asn1_encode_encrypted_data(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_pa_enc_ts(const krb5_pa_enc_ts *rep, krb5_data **code)
+{
+  krb5_setup();
+
+  /* pausec[1]                    INTEGER OPTIONAL */
+  if (rep->pausec)
+	  krb5_addfield(rep->pausec,1,asn1_encode_integer);
+
+  /* patimestamp[0]               KerberosTime, -- client's time */
+  krb5_addfield(rep->patimestamp,0,asn1_encode_kerberos_time);
+
+  krb5_makeseq();
+
+  krb5_cleanup();
+}
+
+/* Sandia Additions */
+krb5_error_code encode_krb5_pwd_sequence(const passwd_phrase_element *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_passwdsequence(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_pwd_data(const krb5_pwd_data *rep, krb5_data **code)
+{
+  krb5_setup();
+  krb5_addfield((const passwd_phrase_element**)rep->element,1,asn1_encode_sequence_of_passwdsequence);
+  krb5_addfield(rep->sequence_count,0,asn1_encode_integer);
+  krb5_makeseq();
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_padata_sequence(const krb5_pa_data **rep, krb5_data **code)
+{
+  krb5_setup();
+
+  retval = asn1_encode_sequence_of_pa_data(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+
+  krb5_cleanup();
+}
+
+/* sam preauth additions */
+krb5_error_code encode_krb5_sam_challenge(const krb5_sam_challenge *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_challenge(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_sam_challenge_2(const krb5_sam_challenge_2 *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_challenge_2(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_sam_challenge_2_body(const krb5_sam_challenge_2_body *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_challenge_2_body(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_sam_key(const krb5_sam_key *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_key(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_enc_sam_response_enc(const krb5_enc_sam_response_enc *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_enc_sam_response_enc(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_enc_sam_response_enc_2(const krb5_enc_sam_response_enc_2 *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_enc_sam_response_enc_2(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_sam_response(const krb5_sam_response *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_response(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_sam_response_2(const krb5_sam_response_2 *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_sam_response_2(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_predicted_sam_response(const krb5_predicted_sam_response *rep, krb5_data **code)
+{
+  krb5_setup();
+  retval = asn1_encode_predicted_sam_response(buf,rep,&length);
+  if(retval) return retval;
+  sum += length;
+  krb5_cleanup();
+}
+
+krb5_error_code encode_krb5_setpw_req(const krb5_principal target,
+				      char *password, krb5_data **code)
+{
+  /* Macros really want us to have a variable called rep which we do not need*/
+  const char *rep = "dummy string";
+
+  krb5_setup();
+
+  krb5_addfield(target,2,asn1_encode_realm);
+  krb5_addfield(target,1,asn1_encode_principal_name);
+  krb5_addlenfield(strlen(password), password,0,asn1_encode_octetstring);
+  krb5_makeseq();
+
+
+  krb5_cleanup();
+}
diff --git a/mechglue/src/lib/krb5/asn.1/krbasn1.h b/mechglue/src/lib/krb5/asn.1/krbasn1.h
new file mode 100644
index 000000000..7a45298ad
--- /dev/null
+++ b/mechglue/src/lib/krb5/asn.1/krbasn1.h
@@ -0,0 +1,81 @@
+#ifndef __KRBASN1_H__
+#define __KRBASN1_H__
+
+#include "k5-int.h"
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>		/* For INT_MAX */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+/*
+ * Older versions of the Kerberos are always sending the
+ * enc_kdc_rep_part structure with an application tag of #26, instead
+ * of using the application tag of #25 (AS REP) or #26 (AS REP) as
+ * necessary.  Worse yet, they will only accept a tag of #26, so we
+ * need to follow this for backwards compatibility.  #defining
+ * KRB5_ENCKRB5KDCREPPART_COMPAT will preserve this wrong (but
+ * compatible) behavior.
+ */
+#define KRB5_ENCKRB5KDCREPPART_COMPAT
+
+/*
+ * If KRB5_MSGTYPE_STRICT is defined, then be strict about checking
+ * the msgtype fields.  Unfortunately, there old versions of Kerberos
+ * don't set these fields correctly, so we have to make allowances for
+ * them.
+ */
+/* #define KRB5_MSGTYPE_STRICT */
+
+/*
+ * If KRB5_GENEROUS_LR_TYPE is defined, then we are generous about
+ * accepting a one byte negative lr_type - which is not sign
+ * extended. Prior to July 2000, we were sending a negative lr_type as
+ * a positve single byte value - instead of a signed integer. This
+ * allows us to receive the old value and deal
+ */
+#define KRB5_GENEROUS_LR_TYPE
+
+typedef krb5_octet asn1_octet;
+typedef krb5_error_code asn1_error_code;
+
+typedef enum { PRIMITIVE = 0x00, CONSTRUCTED = 0x20 } asn1_construction;
+
+typedef enum { UNIVERSAL = 0x00, APPLICATION = 0x40,
+		 CONTEXT_SPECIFIC = 0x80, PRIVATE = 0xC0 } asn1_class;
+
+typedef int asn1_tagnum;
+#define ASN1_TAGNUM_CEILING INT_MAX
+#define ASN1_TAGNUM_MAX (ASN1_TAGNUM_CEILING-1)
+
+/* This is Kerberos Version 5 */
+#define KVNO 5
+
+/* Universal Tag Numbers */
+#define ASN1_INTEGER		2
+#define ASN1_BITSTRING		3
+#define ASN1_OCTETSTRING	4
+#define ASN1_NULL		5
+#define ASN1_OBJECTIDENTIFIER	6
+#define ASN1_ENUMERATED 10
+#define ASN1_SEQUENCE		16
+#define ASN1_SET		17
+#define ASN1_PRINTABLESTRING	19
+#define ASN1_IA5STRING		22
+#define ASN1_UTCTIME		23
+#define ASN1_GENERALTIME	24
+#define ASN1_GENERALSTRING	27
+
+/* Kerberos Message Types */
+#define ASN1_KRB_AS_REQ		10
+#define ASN1_KRB_AS_REP		11
+#define ASN1_KRB_TGS_REQ	12
+#define ASN1_KRB_TGS_REP	13
+#define ASN1_KRB_AP_REQ		14
+#define ASN1_KRB_AP_REP		15
+#define ASN1_KRB_SAFE		20
+#define ASN1_KRB_PRIV		21
+#define ASN1_KRB_CRED		22
+#define ASN1_KRB_ERROR		30
+
+#endif
diff --git a/mechglue/src/lib/krb5/ccache/.Sanitize b/mechglue/src/lib/krb5/ccache/.Sanitize
new file mode 100644
index 000000000..ec2030f21
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/.Sanitize
@@ -0,0 +1,43 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+ccbase.c
+ccdefault.c
+ccdefops.c
+configure
+configure.in
+file
+memory
+ser_cc.c
+stdio
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/ccache/ChangeLog b/mechglue/src/lib/krb5/ccache/ChangeLog
new file mode 100644
index 000000000..c5063fb42
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ChangeLog
@@ -0,0 +1,1069 @@
+2005-12-02  Jeffrey Altman <jaltman@mit.edu>
+
+	* cc_mslsa.c: increase the size of the PurgeRequest
+
+2005-10-27  Jeffrey Altman <jaltman@mit.edu>
+	* ccdefault.c: 
+          (krb5int_cc_default) - add KFW support for multiple ccaches
+
+2005-10-20  Jeffrey Altman <jaltman@mit.edu>
+
+	* cc_mslsa.c: 
+          - provide defaults for client and server names in purge 
+            ticket routines
+          - properly size the buffers used to store the names.
+
+2005-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (dereference): Fix test is list-walking loop.
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (NEED_SOCKETS, NEED_LOWLEVEL_IO): Don't define.
+
+2005-01-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (struct _krb5_fcc_data): Fields disk_file_lock,
+	file_is_locked deleted.
+	(krb5_fcc_open_file, krb5_fcc_close_file, dereference,
+	krb5_fcc_resolve, krb5_fcc_generate_new, krb5_fcc_set_flags):
+	Don't set or check them.
+
+2005-01-11  Jeffrey Altman <jaltman@mit.edu>
+
+        * cc_mslsa.c: 
+          - do not free krb5_creds if krb5_copy_creds fails
+          - cause MSTicketToMITTicket to return failure if
+            krb5_copy_data fails
+
+2004-12-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* cc_file.c (krb5_fcc_close): Free the cache id.
+	(dereference): When removing fcc_set entry from list, free the
+	pointer as well.
+
+2004-12-16  Jeffrey Altman <jaltman@mit.edu>
+        * cc_mslsa.c:
+          Temporarily deactivate support for KerbSubmitTicketMessage   
+          and KerbQueryTicketCacheEx2Message until the new Platform SDK
+          becomes publicly available.
+
+2004-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * cc_mslsa.c: 
+          - Activate support for KerbSubmitTicketMessage
+          - Activate support for KerbQueryTicketCacheEx2Message
+          - Add locale support for regions which use MultiByte characters
+
+2004-11-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_mslsa.c (MSCredToMITCred): Don't create an empty array for
+	addresses, just use a null pointer now.
+
+2004-11-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_retr.c (krb5_cc_retrieve_cred_seq): Temporarily clear the
+	KRB5_TC_OPENCLOSE flag on the credentials cache while reading
+	multiple entries from it.
+
+2004-11-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (krb5_fcc_get_flags): New function.
+	(krb5_fcc_ops, krb5_cc_file_ops): Add it.
+	* cc_memory.c (krb5_mcc_get_flags): New function.
+	(krb5_mcc_ops): Add it.
+	* cc_mslsa.c (krb5_lcc_get_flags): New function.
+	(krb5_lcc_ops): Add it.
+	* ccfns.c (krb5_cc_get_flags): New function.
+
+2004-10-07  Jeffrey Altman <jaltman@mit.edu>
+        * cc_mslsa.c: Fix the forced setting of the Initial Ticket Flag
+                on Win2000 and add it to XP and 2003 SP1
+
+2004-09-17  Jeffrey Altman <jaltman@mit.edu>
+        * cc_mslsa.c: Fix the error returned when krb5_lcc_start_seq_get()
+          discovers the cache is empty.  Check for the new error in 
+          krb5_lcc_initialize()
+
+2004-09-10  Jeffrey Altman <jaltman@mit.edu>
+        * cc_mslsa.c: Implement krb5_lcc_initialize()
+          Remove all tickets from the cache which have a client
+          principal that matches the input principal.
+
+2004-09-10  Jeffrey Altman <jaltman@mit.edu>
+        * cc_mslsa.c: Correct test for KerbQueryTicketCacheExMessage
+
+2004-09-09  Jeffrey Altman <jaltman@mit.edu>
+
+        * cc_mslsa.c: The following functionality is being committed
+                      but commented out because it is not presently
+                      available in public Microsoft SDKs
+        - support for KerbSubmitTicket which allows a KERB_CRED 
+          message to be forwarded to the LSA.  (KERB_SUBMIT_TICKET)
+        - support for the KerbQueryTicketCacheEx2Message which 
+          adds the Session Key Enctype to the contents of the
+          response from KerbQueryTicketCacheExMessage.  
+          (HAVE_CACHE_INFO_EX2)
+
+2004-09-01  Jeffrey Altman <jaltman@mit.edu>
+
+        * cc_mslsa.c: 
+        - Fix MITPrincToMSPrinc to prevent writing to the output
+          buffer if the input won't fit.
+        - Add internal UnicodeStringToMITPrinc function
+        - Rename internal MSPrincToMITPrinc to ExternalNameToMITPrinc
+        - Rename internal PurgeMSTGT to PurgeAllTickets
+        - Add internal PurgeTicket2000 
+        - Add internal PurgeTicketXP
+        - Since tickets can only be requested via KDC Opt Flags it is
+          not possible to specifically request the Initial ticket.  If
+          more than one ticket exists which matching service names,
+          enctypes, and ticket flags the initial ticket flag may not be
+          set.  If the caller requested the initial ticket, set the flag
+          manually.
+        - Add preliminary support for krb5_lcc_set_flags
+        - Modify krb5_lcc_initialize to return success
+        - Modify krb5_lcc_get_principal to support an LSA cache
+          which does not contain a TGT when krb5_lcc_resolve is 
+          called.
+        - Implement krb5_lcc_remove_cred
+            
+
+2004-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_cc.c (init_test_cred): Terminate argument list to
+	krb5_build_principal with NULL, not 0.  Patch from Nalin
+	Dahyabhai.
+
+2004-08-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (struct _krb5_fcc_data): Add new mutex
+	disk_file_lock and flag file_is_locked.
+	(krb5_fcc_close_file): Unlock the mutex and clear the flag.
+	(krb5_fcc_open_file): Acquire the mutex before locking the file,
+	and set the flag after.
+	(krb5_fcc_resolve): Initialize the new mutex and flag.
+	(krb5_fcc_generate_new): Initialize both mutexes and the flag.
+	(dereference): Destroy the new mutex.
+
+	* cc_file.c: Add buffering on reading.
+	(FCC_BUFSIZ): New macro.
+	(struct _krb5_fcc_data): Add new fields buf, valid_bytes,
+	cur_offset.
+	(krb5_fcc_resolve, krb5_fcc_generate_new): Initialize
+	valid_bytes.
+	(invalidate_cache): New function.
+	(krb5_fcc_write, krb5_fcc_open_file, krb5_fcc_destroy): Call
+	invalidate_cache.
+	(fcc_lseek): New function.
+	(krb5_fcc_skip_header, krb5_fcc_destroy, krb5_fcc_start_seq_get,
+	krb5_fcc_next_cred, krb5_fcc_store): Use fcc_lseek instead of
+	lseek.
+	(fcc_read): Use and maybe refill the buffer.
+	(dereference): Zap the contents of the buffer before freeing it.
+
+	* cc_file.c (dereference): Lock mutex around call to
+	krb5_fcc_close_file.
+
+2004-08-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (krb5_fcc_close_file): Change first argument to be an
+	fcc-data pointer, not a krb5_ccache.  All calls changed.
+	(struct fcc_set): Add a refcount member.  (Definition
+	accidentally introduced without comment in an earlier patch.)
+	(krb5int_cc_file_mutex, fccs): New variables, for managing a
+	global list of open credential cache files.
+	(dereference): New function, with most of old close/destroy
+	operations.  Decrements reference count and only frees the object
+	and removes it from the global list if the refcount hits zero.
+	(krb5_fcc_close, krb5_fcc_destroy): Call dereference.
+	(krb5_fcc_resolve): If a file cache is already open with the same
+	file name, increment its reference count and don't create a new
+	one.  When a new one is created, add it to the global list.
+	* cc-int.h (krb5int_cc_file_mutex): Declare.
+	* ccbase.c (krb5int_cc_initialize): Initialize it.
+	(krb5int_cc_finalize): Destroy it, and krb5int_mcc_mutex.
+
+2004-08-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c: Remove USE_STDIO support.
+
+2004-07-25  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c:  is_windows_xp() should test for major version 
+        > 5 not >= 5. 
+
+2004-07-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* cc_memory.c (krb5_mcc_store): When allocating krb5_mcc_link
+	memory - allocate sizeof() - not sizeof(sizeof()).
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c: Don't check for macsock.h.
+
+2004-07-15  Alexandra Ellwood  <lxs@mit.edu>
+
+	* ccdefault.c (krb5_cc_default, krb5int_cc_default) 
+        Removed default_ccprincipal field from krb5_context
+
+2004-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_cc.c (cc_test): Rename one of the "resolve" cases so the
+	messages can be distinguished.
+
+2004-07-07  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c:  Fix thread safety
+
+2004-07-07  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c:  When obtaining a TGT from MSLSA, do not ignore 
+      the cache if the requested enctype is the NULL enctype.
+
+2004-06-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (krb5_fcc_data): Added a mutex.
+	(krb5_fcc_read*, krb5_fcc_write, krb5_fcc_store_*,
+	krb5_fcc_open_file, krb5_fcc_skip_header,
+	krb5_fcc_skip_principal): Verify that the mutex is locked.
+	(MAYBE_OPEN): Verify that the mutex is locked; unlock it if
+	returning an error.
+	(krb5_fcc_initialize, krb5_fcc_start_seq_get,
+	krb5_fcc_get_principal, krb5_fcc_store, krb5_fcc_set_flags): Lock
+	and unlock the mutex.
+	(krb5_fcc_close): Likewise.  Destroy the mutex when done.
+	(krb5_fcc_destroy): Merge stdio and non-stdio versions a little
+	more.  Destroy the mutex when done.
+	(krb5_fcc_resolve): Initialize and lock the mutex.
+	(krb5_fcc_next_cred): Lock and unlock the mutex.  Merge the stdio
+	and non-stdio branches a little more.
+
+2004-06-29  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c: 
+    - is_windows_2000() indicates the OS is Windows 2000 or higher
+    - is_windows_xp() indicates the OS is Windows XP or higher which
+      indicates that PKERB_QUERY_TKT_CACHE_EX_RESPONSE and 
+      PKERB_TICKET_CACHE_INFO_EX are available.
+    - does_retrieve_ticket_cache_ticket() checks to see if a Microsoft
+      private fix is available which adds a new Cache Flag,
+      KERB_RETRIEVE_TICKET_CACHE_TICKET, which when set causes the 
+      requested ticket to be stored in the LSA cache even when the
+      TicketFlags and EncType are not set to 0.
+    - KerbExternalTicketMatch() is a test to determine if two 
+      Microsoft External Tickets are identical
+    + use the KerbQueryTicketCacheExMessage LSA call on XP or higher
+    + specify the KERB_RETRIEVE_TICKET_CACHE_TICKET flag when it is
+      available
+    = The combination of both + items will cause the ClientRealm
+      to be displayed properly for all cross realm tickets obtained
+      via the MSLSA
+    
+
+2004-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_memory.c (krb5_mcc_free): Don't destroy the mutex here.
+
+2004-06-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_memory.c: Include k5-thread.h.
+	(krb5int_mcc_mutex): New lock.
+	(krb5_mcc_store): Rewrite.
+	(NEED_WINDOWS): Don't define.
+	(krb5_mcc_*): All functions now static.
+	(struct _krb5_mcc_data): Delete 'next' pointer.  Add a mutex.
+	(krb5_mcc_*): Lock and unlock the mutex as appropriate.
+	(struct krb5_mcc_list_node): New type, separates the linked-list
+	container from the data for individual nodes.
+	(mcc_head): Now points to krb5_mcc_list_node.
+	* cc-int.h (krb5int_mcc_mutex): Declare.
+	* ccbase.c (krb5int_cc_initialize): Initialize it.
+
+2004-06-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (krb5_fcc_read_data): Combine stdio and posix versions
+	of code with gratuitous minor differences.
+	(krb5_fcc_read_int32, krb5_fcc_next_cred): Likewise.
+	(krb5_fcc_read_addr): Likewise.  Check that filled-in length field
+	matches the value we tried to store (i.e., that type conversion
+	didn't throw away information).
+	(krb5_fcc_read_authdatum): Likewise.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (my_fopen): Function deleted.
+	(krb5_fcc_open_file): Use fopen, not my_fopen.
+
+2004-06-21  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c: Comment out call to FormatMessage() which fails
+      horribly on non-English systems.  We do not need the output
+      or printf statements as part of a library.  Therefore, we 
+      will ignore this for the time being.   When we decide we
+      want to log event to the Event Log then we can properly 
+      implement this function.
+
+2004-06-18  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c: Enforce acceptable enctypes by checking against
+      the default_tgs_enctypes list instead of the permitted_enctypes
+      list;  only enforce the desired enctype when retrieving tickets
+      to deliver to an application.  do not enforce when attempting 
+      to determine the current principal name.  this is important
+      because specifying an enctype results in a TGS_REQ being sent
+      to the KDC;  close memory leak of krb5_cred objects in 
+      krb5_lcc_retrieve().
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Don't set.
+
+2004-05-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* ccbase.c: Include cc-int.h.
+
+	* cc-int.h (krb5int_cc_finalize): Add prototypes for 
+	krb5int_cc_{finalize,initialize}.
+
+2004-05-25  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c:  GetMSTGT().  Initialize pTicketRequest to NULL 
+      to prevent it being freed prior to allocation.  Add krb5_context
+      parameter to allow krb5_get_permitted_enctype() to be called
+      instead of using a hardcoded list of enctypes which may change
+      in the future.
+      krb5_lcc_get_name(): fix return value if Kerberos is not supported.
+
+
+2004-05-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_cc.c (cc_test): Clean up memory leaks in tests.
+
+2004-05-15  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c:  The FAILED() macro only considered an error 
+      to be a failure if the value is negative.  ConstructTicketRequest()
+      returns positive errors.  Do not use FAILED() to test the result.
+      Fix a potential leak of LSA allocated memory.  Fix a leak of 
+      LocalAlloc memory.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* ccbase.c: Include ctype.h.
+	(cc_typelist_lock): Use the new partial initializer.
+	(krb5int_cc_initialize): New function; finish the initialization.
+	(krb5int_cc_finalize): New function; destroy the mutex and free
+	any storage for registered types.
+
+2004-04-13  Jeffrey Altman <jaltman@mit.edu>
+
+    * ccbase.c:
+      Since we have to reserve all the single letter
+      prefixes make them apply to all platforms
+
+2004-04-13  Jeffrey Altman <jaltman@mit.edu>
+
+    * ccbase.c:
+      On Windows, if there is a ccache name provided without
+      a prefix but which appears to start with a drive letter,
+      treat it as a FILE: ccache instead of failing with a
+      ccache type unknown error.
+     
+2004-04-13  Jeffrey Altman <jaltman@mit.edu>
+
+    * ccbase.c:
+      krb5_cc_resolve() defines a function pointer ccresolver
+      which must be of type KRB5_CALLCONV
+
+
+2004-04-06  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c:
+      In at least one case on Win2003 it appears that it is possible 
+      for the logon session to be authenticated via NTLM and yet for
+      there to be Kerberos credentials obtained by the LSA on behalf
+      of the logged in user.  Therefore, we are removing the test 
+      for IsKerberosLogon() within krb5_lcc_resolve()
+      which was meant to avoid the need to perform GetMSTGT() when
+      there was no possibility of credentials being found.
+
+2004-03-31  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_mslsa.c: Add IsWindows2000() function and use it to return 
+      errors whenever the MSLSA: ccache type is used on platforms
+      older than Windows 2000.  This is needed to prevent calls to
+      the functions loaded from ADVAPI32.DLL and SECUR32.DLL which 
+      do not exist on the Windows 9x platforms.
+
+2004-03-26  Sam Hartman  <hartmans@mit.edu>
+
+	* fcc.h: Remove all but the definition of krb5_cc_file_ops because
+	the rest is static in cc_file.c 
+
+	* Makefile.in (T_file):  Remove (no longer builds, no longer used)
+
+2004-03-25  Sam Hartman  <hartmans@mit.edu>
+
+	* cc_file.c (krb5_fcc_generate_new): Use mkstemp not mktemp when possible
+	
+2004-03-18  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_mslsa.c:
+     Add missing return statements in krb5_lcc_start_seq_get()
+
+     Return error if principal name cannot be determined during
+     krb5_lcc_resolve()
+
+   * cc-int.h:
+     New file - Add prototypes for cc internal functions
+
+   * cc_retr.c - include cc-int.h
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* ccbase.c: Include k5-thread.h.
+	(struct krb5_cc_typelist): Ops pointer now points to const.
+	(cc_typelist_lock): New mutex var.
+	(krb5_cc_register, krb5_cc_resolve): Lock it while working with
+	the type list.
+
+2004-02-04  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_mslsa.c:
+     Remove reference to <ntstatus.h> as it is not present in the August 2001
+     Platform SDK used by Pismere.  Instead copy the error value.
+
+2004-02-02  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_msla.c: 
+     GetMSCacheTicketFromCacheInfo() uses the tktinfo->TicketFlags as the
+     value to assign to TicketRequest->TicketFlags.  This field is blindly
+     inserted into the kdc-options[0] field of the TGS_REQ.  If there are
+     bits such as TRANSIT_POLICY_CHECKED in the TicketFlags, this will result
+     in an unknown TGS_OPTION being processed by the KDC.
+
+     This has been fixed by mapping the Ticket Flags to KDC options.
+     We only map Forwardable, Forwarded, Proxiable, and Renewable.  The others
+     should not be used.
+
+2004-02-02  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_mslsa.c: the MSLSA code was crashing on Pismere machines when 
+     logging on with cross realm credentials.  On these machines there are
+     8 tickets within the LSA cache from two different realms.  One of the
+     krbtgt/CLIENT-REALM@CLIENT-REALM tickets (not the Initial ticket but
+     a Forwarded ticket) is inaccessible to the ms2mit.exe and leash32.exe
+     processes.  The attempt to access the ticket returns a SubStatus code
+     of STATUS_LOGON_FAILURE (0xC000006DL) which is supposed to mean that
+     the logon attempt was invalid due to bad authentication information.
+     kerbtray has no problem listing this ticket.  The other seven tickets
+     in the cache including the Initial Ticket are accessible.  Modified 
+     krb5_lcc_next_cred() to skip to the next ticket if an attempt to read
+     a single ticket fails.
+
+2004-01-31  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_mslsa.c: Optimize the get next logic by storing a handle to
+     the MS TGT in the lcc_cursor data structure
+
+2004-01-31  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_mslsa.c: Do not return tickets to the caller if they contain
+     NULL session keys.  This is to prevent useless TGTs from being
+     placed into the MIT credential cache.
+
+2004-01-30  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_mslsa.c: As per extensive conversations with Doug Engert we have
+     concluded that MS is not specifying a complete set of domain information
+     when it comes to service tickets other than the initial TGT.  What happens
+     is the client principal domain cannot be derived from the fields they
+     export.  Code has now been added to obtain the domain from the initial
+     TGT and use that when constructing the client principals for all tickets.
+
+     This behavior can be turned off by setting a registry either on a per-user
+     or a system-wide basis:
+
+        {HKCU,HKLM}\Software\MIT\Kerberos5
+            PreserveInitialTicketIdentity = 0x0 (DWORD)
+           
+
+2004-01-06  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_file.c, cc_memory.c:
+     Add stub implementations for unimplemented krb5_cc_remove_cred()
+     Returns KRB5_CC_NOSUPP
+
+   * cc_mslsa.c:
+     Add implementation for krb5_cc_remove_cred().  Returns KRB5_CC_READONLY.
+
+2003-12-19  Jeffrey Altman <jaltman@mit.edu>
+              
+   * cc_mslsa.c: fix indirection of a krb5_creds structure which
+     is passed into MSCredToMITCred().
+
+2003-12-18  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_retr.c:  Extract the test to determine if a credential matches
+     a requested credential according to the specified fields into 
+     a private function: krb5int_cc_creds_match_request()
+
+   * cc_mslsa.c: Extend the functionality of krb5_lcc_retrieve() to
+     perform a MS Kerberos LSA ticket request if there is no matching
+     credential in the cache.  The MS Kerberos LSA places the following
+     restriction on what tickets it will place into the LSA cache:
+         tickets obtained by an application request for a specific
+         set of kerberos flags or enctype will not be cached.
+     Therefore, we first make a request with no flags or enctype in 
+     the hope that we will be lucky and get the right ones anyway.
+     If not, we make the application's request and return that ticket
+     if it matches the other criteria.
+
+     Implemented a similar technique for krb5_lcc_store().  Since we
+     can not write to the cache, when a store request is made we 
+     instead perform a ticket request through the lsa for a matching
+     credential.  If we receive one, we return success.  Otherwise,
+     we return the KRB5_CC_READONLY error.
+
+   With these changes I am now able to operate entirely with the MSLSA
+   ccache as the default cache provided the MS LSA credentials are
+   for the principal I wish to use.  Obviously, one cannot change
+   principals while the MSLSA ccache is the default.
+
+2003-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_msla.c:   Enable purging of the MS Kerberos LSA cache when the TGT
+     has expired.  This will force the LSA to get a new TGT instead of 
+     returning the expired version.
+
+2003-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+   * cc_mslsa.c:  Perform a GetMSTGT() call as part of krb5_lcc_start_seq_get
+     to ensure that the tgt is refreshed
+
+2003-12-13  Jeffrey Altman <jaltman@mit.edu>
+
+   * Makefile.in: Remove extranenous spaces in ##WIN32## constructs
+     defining MSLSA_SRC MSLSA_OBJ
+
+2003-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Move ##WIN32## constructs from inside
+	backslash-continued lists, as it was breaking them.  Move explicit
+	dependency information from under automatic dependencies.
+
+2003-12-11  Jeffrey Altman <jaltman@mit.edu>
+
+    * Makefile.in, ccbase.c, cc_mslsa.c (new)
+
+    Remove all of the code which was duplicated between ms2mit.c
+    and the KfW Leash libraries (and who knows how many applications
+    shipped by third parties) and use it as the basis for a new
+    krb5_ccache type, "MSLSA:".  The "MSLSA:" ccache type is a
+    read-only ccache which can be used either as a monitor of the
+    contents of the Microsoft LSA cache or as a source for copying
+    the contents to another ccache type.  The purpose of migrating
+    this code to the krb5_32.dll is to avoid the need for applications
+    to be consistently updated each time Microsoft makes a change
+    to the behavior of the LSA cache.  Changes have occurred with
+    the release of 2000, XP, and 2003 so far.  Also, the code for
+    working with the MS LSA cache is not well documented and many
+    mistakes were made in the original versions of the ms2mit.c
+    code base.  Unfortunately, the ms2mit.c code has been copied
+    into many other applications.  
+
+    With access to this new ccache type, the ms2mit.c source file
+    is reduced from 890 lines to 80 lines including the copyright
+    banner.
+
+2003-11-26  Jeffrey Altman <jaltman@mit.edu>
+
+    * cc_default.c: Add support for Leash Kinit Dialog on Windows to
+            krb5int_c_default()
+
+2003-08-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (krb5_fcc_store_int32, krb5_fcc_store_ui_4) 
+	(krb5_fcc_store_ui_2, krb5_fcc_store_octet): Remove gratuitous
+	conditionalizing of casts on USE_STDIO, left over from merge.
+
+2003-07-22  Sam Hartman  <hartmans@mit.edu>
+
+	* ccbase.c: Always register the file credentials cache type.  If
+	we do not, then when USE_CCAPI is defined, it will not be
+	available. 
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+	($(OBJFILE)) [##WIN16##]: Omit CP action.
+
+2003-03-06  Alexandra Ellwood <lxs@mit.edu>
+
+    * ccdefault.c: Remove Mac header goober and include
+    k5-int.h after KerberosLoginPrivate.h.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (krb5_cc_file_ops, krb5_fcc_ops): Now const.
+	* fcc.h (krb5_cc_file_ops): Update decl.
+	* cc_memory.c (krb5_mcc_ops): Now const.
+	* ccbase.c (krb5_mcc_ops): Update decl.
+	* ccdefops.c (krb5_cc_dfl_ops): Now points to const.
+	* t_cc.c (krb5_fcc_ops, krb5_mcc_ops): Update decls.
+
+2002-09-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c, cc_memory.c, cc_retr.c, ccbase.c, cccopy.c,
+	ccdefault.c, ser_cc.c, t_cc.c: Use prototype style function
+	definitions.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c (ALLOC): Use calloc, not malloc.
+	(krb5_fcc_read_principal): Check bounds on number of components
+	before calling ALLOC.
+
+2002-08-15  Tom Yu  <tlyu@mit.edu>
+
+	* t_cc.c: Remove references to STDIO ccache.
+
+2002-08-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c: Merge in cc_stdio.c, under preprocessor test for
+	USE_STDIO.
+	(USE_STDIO): Define it if HAVE_SYS_TYPES_H.
+	(krb5_change_cache, krb5_get_notification_message): Always
+	define.
+	(ALLOC): New macro, with overflow checking.
+	(krb5_fcc_read_principal, krb5_fcc_read_addrs,
+	krb5_fcc_read_authdata): Use it, and fix other overflow checks.
+	(my_fopen): Support non-Mac environments.
+	(krb5_fcc_open_file) [USE_STDIO]: Always use my_fopen.
+	(NO_FILE): New macro.  All functions changed to test or assign it
+	rather than -1 or (FILE*)NULL.
+	(krb5_fcc_read_keyblock, krb5_fcc_read_data): Rewrite bounds
+	check.
+	(BINARY_MODE): Always define.
+	(setvbuf) [!HAVE_SETVBUF]: Define as macro using setbuf.
+	(krb5_fcc_open_file): Change file descriptor variable to "f" and
+	combine newly matching stdio and file sections.  Use setvbuf
+	instead of checking whether to use setbuf.
+
+	* cc_stdio.c: Deleted.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Updated.
+	* ccdefops.c (krb5_cc_dfl_ops) [!USE_CCAPI]: Always use
+	krb5_fcc_ops.
+
+2002-08-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c: All functions except krb5_change_cache and
+	krb5_get_notification_message now static.  Minor other shuffling
+	to become more similar to cc_stdio.c.
+	(krb5_fcc_data): Rename "fd" to "file"; change all uses.
+	* cc_stdio.c: All functions now static.  Rename all krb5_scc_
+	functions, data types and macros to use krb5_fcc_ prefix instead.
+	Minor other shuffling to become more similar to cc_file.c.
+	(krb5_fcc_data): Rename from krb5_scc_data; reorder some fields.
+	(krb5_fcc_close_file): Never call fflush on a read-only file.
+	(BINARY_MODE): New macro.
+	(krb5_fcc_open_file): Combine ANSI_STDIO and non-ANSI cases
+	statements by using BINARY_MODE and compile-time string
+	concatenation.  Choose lock flag value separately from call to
+	krb5_lock_file.
+	(krb5_fcc_generate_new): Use BINARY_MODE.
+
+2002-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c: Put # for cpp directives in first column.
+
+2002-60-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Build cc accessor functions on Windows.
+	[pullup from 1-2-2-branch]
+
+2002-06-20 Alexandra Ellwood <lxs@mit.edu>
+
+	* ccdefault.c: updated to new KLL function name
+
+	* ccdefault.c: swapped include of KerberosLoginPrivate with
+	k5-int.h to avoid problems with including CoreServices.h after
+	profile.h and krb.h
+
+	* ccdefault.c: Updated Mac OS X headers to new framework layout
+
+	* ccdefops.c: created #define for USE_CCAPI now that both Mac OS 9
+	and Mac OS 10 use ccapi.
+
+	[pullups from 1-2-2-branch]
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* cc_file.c: Use _WIN32 instead of _WINSOCKAPI_ because
+	_WINSOCKAPI_ depends on the Winsock header used (i.e., Winsock 2
+	does not define this).  What we are really trying to check for is
+	Win32.  Include port-sockets.h for Win32.  (NOTE: Why is
+	NEED_SOCKETS being defined after the inclusion of k5-int.h?  That
+	is pretty useless...  What we probably should do is more
+	consitently used NEED_SOCKETS instead of manually putting in
+	network code.  However, some people would probably have issues
+	with the build being slower...)
+
+2001-10-10  Ezra Peisach  <epeisach@mit.edu>
+
+	* cc_file.c (krb5_fcc_read): Remove const from fourth argument to
+	function to match prototype earlier in file.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c, cc_memory.c, cc_stdio.c, ser_cc.c: Make prototypes
+	unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c, cc_stdio.c: Delete _MSDOS (win16) support.
+
+	* cc_memory.c, ccbase.c, ccdefault.c, ccfns.c: Don't explicitly
+	declare pointers FAR any more.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_file.c, ccbase.c, cccopy.c, ccdefault.c, fcc.h, ser_cc.c:
+	Don't use KRB5_DLLIMP.
+
+2000-10-30  Tom Yu  <tlyu@mit.edu>
+
+	* cc_stdio.c: Add a "mode" field to krb5_scc_data to keep track of
+	what mode the file was opened in.
+	(krb5_scc_close_file): Ignore EBADF from fflush() if the file was
+	opened for readonly access.  For some reason NetBSD's fflush()
+	exhibits this behavior.
+	(krb5_scc_open_file): Save the mode with which the file was opened
+	in data->mode.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* cc_stdio.c, cc_file.c: Unsigned/signed int cleanup.
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* ser_cc.c (krb5_ccache_externalize): Use krb5_cc_get_name instead
+	of krb5_rc_get_name on credential cache.
+
+	* cc_file.c (krb5_fcc_get_name): 
+	* cc_stdio.c (krb5_scc_get_name): 
+	* cc_memory.c (krb5_mcc_get_name): 
+	* ccfns.c (krb5_cc_get_name): Declare as returning const char *.
+
+2000-09-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* cc_file.c ccbase.c, cc_stdio.c, cc_retr.c, cc_memory.c: More
+	signed/unsigned fixes.
+
+Sat Sep 23 23:42:32 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_cc.c: Code cleanup. Test more failure modes of the cache library. 
+
+	* cccopy.c (krb5_cc_copy_creds): Memory leak. Call krb5_cc_end_seq_get.
+
+	* cc_file.c (krb5_fcc_generate_new): Set flags to
+ 	KRB5_TC_OPENCLOSE, otherwise parts of the library assumes that the
+ 	file is open, when it is not.
+
+	* cc_stdio.c (krb5_scc_generate_new): Same as cc_file.c change.
+	
+
+2000-09-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (check-unix): Build and exectute t_cc.
+
+	* t_cc.c: Test harness for memory, stdio and file caches. 
+
+2000-07-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* cc_file.c, cc_stdio.c: Remove unused krb5_[fs]cc_default_name()
+	prototype.
+
+	* cc_stdio.c: Fix calling convention for op functions.
+
+	* ccfns.c (krb5_cc_get_type): Fix calling convention.
+
+	* Makefile.in: Change ${CC} and ${OBJS} to $(CC) and $(OBJS) so
+	nmake does not freak out.
+
+2000-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_memory.c (mcc_head): Combine static declaration and
+	initialization.
+
+2000-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_stdio.c, t_file.c, t_memory.c: Test cases copied from old
+	subdirectories.  Currently unused.
+	* Makefile.in (t_stdio): New target, basically same as 'test' in
+	old stdio/Makefile.in.
+	* file, memory, stdio: Subdirectories deleted.
+
+	* cc_file.c, cc_stdio.c, cc_memory.c: New files, built from source
+	files of appropriate subdirectories.
+	* fcc.h, scc.h: New files, copied from subdirectories; temporary.
+	* ccfns.c: New file, implementing what used to be krb5_cc_* macros
+	in krb5.h.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Updated.
+	(LOCAL_SUBDIRS): Now empty.
+	(LOCALINCLUDES): Remove file and stdio subdirs.
+	(MAC_SUBDIRS): Remove file, stdio, memory.
+	(##DOS## stuff, clean-windows): Delete file and memory parts.
+
+	* cc_memory.c (mcc_head): Now static.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* ccdefault.c: Add newline at end of file (compiler warning)
+
+2000-5-31	Alexandra Ellwood <lxs@mit.edu>
+
+	* ccdefault.c: Changed kerberosPrincipal_V5 to kerberosVersion_V5
+	to reflect the new constant name.
+
+2000-4-26	Alexandra Ellwood <lxs@mit.edu>
+
+	* ccdefault.c: Added version number to internal Kerberos Login
+	Library routine.
+
+2000-4-13	Alexandra Ellwood <lxs@mit.edu>
+
+	* ccdefault.c: Added Kerberos Login library support (with ifdefs
+	to control whether or not it is on.  Also added support to store a
+	krb5_principal in the os_context along with the default ccache
+	name (if known, this principal is the same as the last time we
+	looked at the ccache.  * ccdefname.c: Added support to store a
+	krb5_principal in the os_context along with the default ccache
+	name (if known, this principal is the same as the last time we
+	looked at the ccache.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* cc_retr.c: New file.
+	(krb5_cc_retrieve_cred_seq): New function, derived from
+	fcc_retrieve but takes an optional list of enctypes to look for in
+	priority order.
+	(krb5_cc_retrieve_cred_default): New function.  Same signature as
+	original fcc_retrieve but if new flag KRB5_TC_SUPPORTED_KTYPES is
+	set, calls krb5_get_tgs_ktypes to get a list of enctypes to look
+	for.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Add it.
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+Mon May 17 14:11:45 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Clean ccapi subdirectory in clean-windows target.
+
+Mon May 10 15:24:08 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1999-03-31  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ccdefops.c: Change the default ccache type under windows to be
+		original FILE ccache type; this will get set to ccapi if
+		the krbcc32.dll can be found.
+
+Mon Feb  8 21:53:37 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Enable the ccapi directory for windows builds.  
+
+	* ccdefops.c: Make the ccapi the default ccache type for Windows
+		machines.
+
+1999-01-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Add ccapi to the include path so we can find stdcc.h
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Sat Dec  5 01:20:31 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in, ccdefops.c: Temporarily back out the ccapi ccache
+		under Windows so we can make sure the rest of the krb5
+		tree builds correctly under Windows.  (Note: I didn't
+		revert lib/krb5/os/ccdefname.c, so setting KRB5_CC_NAME to
+		FILE:C:\tmp\tkt is required to make things work.)
+
+1998-08-24  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Add windows build instructions to build CCache API
+		Cache implementation. 
+
+Fri Aug 20 18:30:00 1998  Miro Jurisic  <meeroh@mit.edu>
+	* Added Frank's CCache API cache implementation and made
+		it default on the Mac
+
+Thu Jul 30 13:12:30 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* ccbase.c: Enable memory ccache (merge adapted from Kerbnet)
+
+1998-05-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Add ccache/memory as a directory to be recursively
+		built by this makefile under Windows.
+
+Fri Feb 27 18:03:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/krb5
+ 		directory, since we've moved the configure.in tests in
+ 		this directory to the toplevel lib/krb5 configure.in
+
+Wed Feb 18 16:19:12 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Thu Feb 12 16:17:46 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented out AC_OUTPUT to force autoreconf to
+	rebuild the configure script.
+
+Wed Feb 11 22:56:49 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* configure.in: Create the makefiles for all of the subdirectories
+		and move all of the configure.in tests from the
+		subdirectories into this configure.in.
+
+Sat Dec  6 02:26:16 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add cccopy.c.
+
+	* cccopy.c: New file; krb5_cc_copy_creds from Cygnus.
+
+Mon Sep 15 15:14:16 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* ccbase.c (krb5_cc_resolve): Incoming cache name is const.
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+	* ccbase.c, ccdefault.c:
+	DLL export basic ccache functions
+
+Thu Jan  2 16:57:35 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new lib build procedure.
+
+Thu Jun  6 00:04:38 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Don't pass $(LIBCMD) on the command
+		line.  It's set in the windows.in prologue for all
+		Makefiles anyway.
+
+Wed Feb  7 00:23:18 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Fri Nov  3 21:12:31 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Added memory subdirectory
+
+Fri Oct  6 22:03:30 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:56:30 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Tue Aug 29 13:35:23 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in, .Sanitize, ser_cc.c - Add new ccache handle serialization
+		routines.
+
+Fri Jun  9 19:31:13 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Fri May 26 20:19:26 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for building shared libraries.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* ccbase.c: removed unneeded INTERFACE from non-api functions.
+
+Wed Mar 22 11:47:49 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in (CFLAGS): Make -I options work when the build and
+		source tree are different.
+
+Fri Mar 17 19:19:07 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Remove, duplicates config/pre.in.
+	(CFLAGS):  Add -I options for file and stdio, to avoid paths in
+	#include statements.
+	(all-mac, clean-mac):  Add.
+	* ccdefops.c:  Avoid includes with pathnames, since they don't work
+	on the Mac.  Configure the default cache based on whether the
+	system has <sys/types.h> (which defines types for low-level file
+	operations, among other things).
+	* configure.in (CONFIG_DIRS):  Build stdio before file, for Mac
+	convenience (where file doesn't build).
+
+Wed Mar 15 20:23:17 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: cleaned up for the PC
+
+Tue Mar  7 19:53:05 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: take out ISODE_DEFS.
+
+Tue Mar 7 15:55:12 1995 Keith Vetter (keithv@fusion.com)
+
+	* ccbase.c, ccdefault.c: added window INTERFACE keyword.
+        * Makefile.in: made to work on the PC.
+
+Tue Feb 28 00:35:33 1995  John Gilmore  (gnu at toad.com)
+
+	* ccbase.c, ccdefault.c:  Avoid <krb5/...> includes.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines 
+
+Thu Oct 13 17:23:08 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* configure.in: Add ISODE_DEFS
+
diff --git a/mechglue/src/lib/krb5/ccache/Makefile.in b/mechglue/src/lib/krb5/ccache/Makefile.in
new file mode 100644
index 000000000..56227b6dc
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/Makefile.in
@@ -0,0 +1,159 @@
+thisconfigdir=./..
+myfulldir=lib/krb5/ccache
+mydir=ccache
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCAL_SUBDIRS =
+
+RUN_SETUP = @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+LOCALINCLUDES = -I$(srcdir)$(S)ccapi $(WIN_INCLUDES)
+
+##DOS##WIN_INCLUDES = -I$(SRCTOP)\windows\lib
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=ccache
+##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
+
+##WIN32##MSLSA_OBJ = $(OUTPRE)cc_mslsa.$(OBJEXT)
+##WIN32##MSLSA_SRC = $(srcdir)/cc_mslsa.c
+
+STLIBOBJS= \
+	ccbase.o \
+	cccopy.o \
+	ccdefault.o \
+	ccdefops.o \
+	cc_retr.o \
+	cc_file.o cc_memory.o \
+	ccfns.o \
+	ser_cc.o
+
+OBJS=	$(OUTPRE)ccbase.$(OBJEXT) \
+	$(OUTPRE)cccopy.$(OBJEXT) \
+	$(OUTPRE)ccdefault.$(OBJEXT) \
+	$(OUTPRE)ccdefops.$(OBJEXT) \
+	$(OUTPRE)cc_retr.$(OBJEXT) \
+	$(OUTPRE)cc_file.$(OBJEXT) \
+	$(OUTPRE)cc_memory.$(OBJEXT) \
+	$(OUTPRE)ccfns.$(OBJEXT) \
+	$(OUTPRE)ser_cc.$(OBJEXT) $(MSLSA_OBJ)
+
+SRCS=	$(srcdir)/ccbase.c \
+	$(srcdir)/cccopy.c \
+	$(srcdir)/ccdefault.c \
+	$(srcdir)/ccdefops.c \
+	$(srcdir)/cc_retr.c \
+	$(srcdir)/cc_file.c \
+	$(srcdir)/cc_memory.c \
+	$(srcdir)/ccfns.c \
+	$(srcdir)/ser_cc.c $(MSLSA_SRC)
+
+##DOS##OBJS=$(OBJS) $(OUTPRE)ccfns.$(OBJEXT)
+
+all-unix:: all-libobjs
+
+all-windows:: subdirs $(OBJFILE) 
+
+##DOS##subdirs:: ccapi\$(OUTPRE)file.lst
+
+##DOS##ccapi\$(OUTPRE)file.lst::
+##DOS##	cd ccapi
+##DOS##	@echo Making in krb5\ccache\ccapi
+##DOS##	$(MAKE) -$(MFLAGS)
+##DOS##	cd ..
+
+##DOS##$(OBJFILE): $(OBJS) ccapi\$(OUTPRE)file.lst
+##DOS##	$(RM) $(OBJFILE)
+##WIN32##	$(LIBECHO) -p $(PREFIXDIR)\ $(OUTPRE)*.obj \
+##WIN32##		ccapi\$(OUTPRE)*.obj > $(OBJFILE)
+
+
+clean-unix:: clean-libobjs
+
+clean-windows::
+	cd ccapi
+	@echo Making clean in krb5\ccache\ccapi
+	$(MAKE) -$(MFLAGS) clean
+	cd ..
+	@echo Making clean in krb5\ccache
+	$(RM) $(OBJFILE)
+
+T_CC_OBJS=t_cc.o
+
+t_cc: $(T_CC_OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_cc $(T_CC_OBJS) $(KRB5_BASE_LIBS)
+
+check-unix:: t_cc
+	KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\
+	$(RUN_SETUP) ./t_cc 
+
+clean-unix::
+	$(RM) t_cc t_cc.o
+
+##WIN32## $(OUTPRE)cc_mslsa.$(OBJEXT): cc_mslsa.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS)
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+ccbase.so ccbase.po $(OUTPRE)ccbase.$(OBJEXT): ccbase.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  fcc.h cc-int.h
+cccopy.so cccopy.po $(OUTPRE)cccopy.$(OBJEXT): cccopy.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ccdefault.so ccdefault.po $(OUTPRE)ccdefault.$(OBJEXT): \
+  ccdefault.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ccdefops.so ccdefops.po $(OUTPRE)ccdefops.$(OBJEXT): \
+  ccdefops.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  fcc.h
+cc_retr.so cc_retr.po $(OUTPRE)cc_retr.$(OBJEXT): cc_retr.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cc-int.h
+cc_file.so cc_file.po $(OUTPRE)cc_file.$(OBJEXT): cc_file.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+cc_memory.so cc_memory.po $(OUTPRE)cc_memory.$(OBJEXT): \
+  cc_memory.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ccfns.so ccfns.po $(OUTPRE)ccfns.$(OBJEXT): ccfns.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ser_cc.so ser_cc.po $(OUTPRE)ser_cc.$(OBJEXT): ser_cc.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
diff --git a/mechglue/src/lib/krb5/ccache/cc-int.h b/mechglue/src/lib/krb5/ccache/cc-int.h
new file mode 100644
index 000000000..b2d6c78c9
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/cc-int.h
@@ -0,0 +1,48 @@
+/*
+ * lib/krb5/ccache/file/cc-int.h
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This file contains constant and function declarations used in the
+ * file-based credential cache routines.
+ */
+
+#ifndef __KRB5_CCACHE_H__
+#define __KRB5_CCACHE_H__
+
+#include "k5-int.h"
+
+krb5_boolean
+krb5int_cc_creds_match_request(krb5_context, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds);
+
+int
+krb5int_cc_initialize(void);
+
+void
+krb5int_cc_finalize(void);
+
+extern k5_mutex_t krb5int_mcc_mutex;
+extern k5_mutex_t krb5int_cc_file_mutex;
+
+#endif /* __KRB5_CCACHE_H__ */
diff --git a/mechglue/src/lib/krb5/ccache/cc_file.c b/mechglue/src/lib/krb5/ccache/cc_file.c
new file mode 100644
index 000000000..c4fc49bb0
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/cc_file.c
@@ -0,0 +1,2371 @@
+/*
+ * lib/krb5/ccache/cc_file.c
+ *
+ * Copyright 1990,1991,1992,1993,1994,2000,2004 Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Original stdio support copyright 1995 by Cygnus Support.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * implementation of file-based credentials cache
+ */
+
+/*
+If OPENCLOSE is defined, each of the functions opens and closes the
+file whenever it needs to access it.  Otherwise, the file is opened
+once in initialize and closed once is close.
+
+This library depends on UNIX-like file descriptors, and UNIX-like
+behavior from the functions: open, close, read, write, lseek.
+
+The quasi-BNF grammar for a credentials cache:
+
+file ::= 
+        principal list-of-credentials
+
+credential ::=
+	client (principal)
+	server (principal)
+	keyblock (keyblock)
+	times (ticket_times)
+	is_skey (boolean)
+	ticket_flags (flags)
+	ticket (data)
+	second_ticket (data)
+
+principal ::= 
+	number of components (int32)
+	component 1 (data)
+	component 2 (data)
+	...
+	
+data ::=
+	length (int32)
+	string of length bytes
+
+etc.
+ */
+/* todo:
+   Make sure that each time a function returns KRB5_NOMEM, everything
+   allocated earlier in the function and stack tree is freed.
+
+   File locking
+
+   Use pread/pwrite if available, so multiple threads can read
+   simultaneously.  (That may require reader/writer locks.)
+
+   fcc_nseq.c and fcc_read don't check return values a lot.
+ */
+#include "k5-int.h"
+
+
+#include <stdio.h>
+#include <errno.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#if !defined(_WIN32)
+#include <netinet/in.h>
+#else
+#include "port-sockets.h"
+#endif
+#else
+# error find some way to use net-byte-order file version numbers.
+#endif
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_close
+        (krb5_context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_destroy
+        (krb5_context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_end_seq_get
+        (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_generate_new
+        (krb5_context, krb5_ccache *id);
+
+static const char * KRB5_CALLCONV krb5_fcc_get_name
+        (krb5_context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_get_principal
+        (krb5_context, krb5_ccache id, krb5_principal *princ);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_initialize
+        (krb5_context, krb5_ccache id, krb5_principal princ);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_next_cred
+        (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor,
+	 krb5_creds *creds);
+
+static krb5_error_code krb5_fcc_read
+        (krb5_context, krb5_ccache id, krb5_pointer buf, unsigned int len);
+static krb5_error_code krb5_fcc_read_principal
+        (krb5_context, krb5_ccache id, krb5_principal *princ);
+static krb5_error_code krb5_fcc_read_keyblock
+        (krb5_context, krb5_ccache id, krb5_keyblock *keyblock);
+static krb5_error_code krb5_fcc_read_data
+        (krb5_context, krb5_ccache id, krb5_data *data);
+static krb5_error_code krb5_fcc_read_int32
+        (krb5_context, krb5_ccache id, krb5_int32 *i);
+static krb5_error_code krb5_fcc_read_ui_2
+        (krb5_context, krb5_ccache id, krb5_ui_2 *i);
+static krb5_error_code krb5_fcc_read_octet
+        (krb5_context, krb5_ccache id, krb5_octet *i);
+static krb5_error_code krb5_fcc_read_times
+        (krb5_context, krb5_ccache id, krb5_ticket_times *t);
+static krb5_error_code krb5_fcc_read_addrs
+        (krb5_context, krb5_ccache, krb5_address ***);
+static krb5_error_code krb5_fcc_read_addr
+        (krb5_context, krb5_ccache, krb5_address *);
+static krb5_error_code krb5_fcc_read_authdata
+        (krb5_context, krb5_ccache, krb5_authdata ***);
+static krb5_error_code krb5_fcc_read_authdatum
+        (krb5_context, krb5_ccache, krb5_authdata *);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_resolve
+        (krb5_context, krb5_ccache *id, const char *residual);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_retrieve
+        (krb5_context, krb5_ccache id, krb5_flags whichfields,
+	 krb5_creds *mcreds, krb5_creds *creds);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_start_seq_get
+        (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_store
+        (krb5_context, krb5_ccache id, krb5_creds *creds);
+
+static krb5_error_code krb5_fcc_skip_header
+        (krb5_context, krb5_ccache);
+static krb5_error_code krb5_fcc_skip_principal
+        (krb5_context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_fcc_set_flags
+        (krb5_context, krb5_ccache id, krb5_flags flags);
+
+extern const krb5_cc_ops krb5_cc_file_ops;
+
+krb5_error_code krb5_change_cache (void);
+
+static krb5_error_code krb5_fcc_write
+        (krb5_context, krb5_ccache id, krb5_pointer buf, unsigned int len);
+static krb5_error_code krb5_fcc_store_principal
+        (krb5_context, krb5_ccache id, krb5_principal princ);
+static krb5_error_code krb5_fcc_store_keyblock
+        (krb5_context, krb5_ccache id, krb5_keyblock *keyblock);
+static krb5_error_code krb5_fcc_store_data
+        (krb5_context, krb5_ccache id, krb5_data *data);
+static krb5_error_code krb5_fcc_store_int32
+        (krb5_context, krb5_ccache id, krb5_int32 i);
+static krb5_error_code krb5_fcc_store_ui_4
+        (krb5_context, krb5_ccache id, krb5_ui_4 i);
+static krb5_error_code krb5_fcc_store_ui_2
+        (krb5_context, krb5_ccache id, krb5_int32 i);
+static krb5_error_code krb5_fcc_store_octet
+        (krb5_context, krb5_ccache id, krb5_int32 i);
+static krb5_error_code krb5_fcc_store_times
+        (krb5_context, krb5_ccache id, krb5_ticket_times *t);
+static krb5_error_code krb5_fcc_store_addrs
+        (krb5_context, krb5_ccache, krb5_address **);
+static krb5_error_code krb5_fcc_store_addr
+        (krb5_context, krb5_ccache, krb5_address *);
+static krb5_error_code krb5_fcc_store_authdata
+        (krb5_context, krb5_ccache, krb5_authdata **);
+static krb5_error_code krb5_fcc_store_authdatum
+        (krb5_context, krb5_ccache, krb5_authdata *);
+
+static krb5_error_code krb5_fcc_interpret
+        (krb5_context, int);
+
+struct _krb5_fcc_data;
+static krb5_error_code krb5_fcc_close_file
+        (krb5_context, struct _krb5_fcc_data *data);
+static krb5_error_code krb5_fcc_open_file
+        (krb5_context, krb5_ccache, int);
+
+
+#define KRB5_OK 0
+
+#define KRB5_FCC_MAXLEN 100
+
+/*
+ * FCC version 2 contains type information for principals.  FCC
+ * version 1 does not.
+ *  
+ * FCC version 3 contains keyblock encryption type information, and is
+ * architecture independent.  Previous versions are not.
+ *
+ * The code will accept version 1, 2, and 3 ccaches, and depending 
+ * what KRB5_FCC_DEFAULT_FVNO is set to, it will create version 1, 2,
+ * or 3 FCC caches.
+ *
+ * The default credentials cache should be type 3 for now (see
+ * init_ctx.c).
+ */
+
+#define KRB5_FCC_FVNO_1 0x0501		/* krb v5, fcc v1 */
+#define KRB5_FCC_FVNO_2 0x0502		/* krb v5, fcc v2 */
+#define KRB5_FCC_FVNO_3 0x0503		/* krb v5, fcc v3 */
+#define KRB5_FCC_FVNO_4 0x0504		/* krb v5, fcc v4 */
+
+#define	FCC_OPEN_AND_ERASE	1
+#define	FCC_OPEN_RDWR		2
+#define	FCC_OPEN_RDONLY		3
+
+/* Credential file header tags.
+ * The header tags are constructed as:
+ *	krb5_ui_2	tag
+ *	krb5_ui_2	len
+ *	krb5_octet	data[len]
+ * This format allows for older versions of the fcc processing code to skip
+ * past unrecognized tag formats.
+ */
+#define FCC_TAG_DELTATIME	1
+
+#ifndef TKT_ROOT
+#ifdef MSDOS_FILESYSTEM
+#define TKT_ROOT "\\tkt"
+#else
+#define TKT_ROOT "/tmp/tkt"
+#endif
+#endif
+
+/* macros to make checking flags easier */
+#define OPENCLOSE(id) (((krb5_fcc_data *)id->data)->flags & KRB5_TC_OPENCLOSE)
+
+typedef struct _krb5_fcc_data {
+    char *filename;
+    /* Lock this one before reading or modifying the data stored here
+       that can be changed.  (Filename is fixed after
+       initialization.)  */
+    k5_mutex_t lock;
+    int file;
+    krb5_flags flags;
+    int mode;				/* needed for locking code */
+    int version;	      		/* version number of the file */
+
+    /* Buffer data on reading, for performance.
+       We used to have a stdio option, but we get more precise control
+       by using the POSIX I/O functions.  */
+#define FCC_BUFSIZ 1024
+    int valid_bytes;
+    int cur_offset;
+    char buf[FCC_BUFSIZ];
+} krb5_fcc_data;
+
+static inline void invalidate_cache(krb5_fcc_data *data)
+{
+    data->valid_bytes = 0;
+}
+
+static off_t fcc_lseek(krb5_fcc_data *data, off_t offset, int whence)
+{
+    /* If we read some extra data in advance, and then want to know or
+       use our "current" position, we need to back up a little.  */
+    if (whence == SEEK_CUR && data->valid_bytes) {
+	assert(data->valid_bytes > 0);
+	assert(data->cur_offset > 0);
+	assert(data->cur_offset <= data->valid_bytes);
+	offset -= (data->valid_bytes - data->cur_offset);
+    }
+    invalidate_cache(data);
+    return lseek(data->file, offset, whence);
+}
+
+struct fcc_set {
+    struct fcc_set *next;
+    krb5_fcc_data *data;
+    unsigned int refcount;
+};
+
+k5_mutex_t krb5int_cc_file_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+static struct fcc_set *fccs = NULL;
+
+/* An off_t can be arbitrarily complex */
+typedef struct _krb5_fcc_cursor {
+    off_t pos;
+} krb5_fcc_cursor;
+
+#define MAYBE_OPEN(CONTEXT, ID, MODE)					\
+{									\
+    k5_assert_locked(&((krb5_fcc_data *)(ID)->data)->lock);		\
+    if (OPENCLOSE (ID)) {						\
+	krb5_error_code maybe_open_ret;					\
+	maybe_open_ret = krb5_fcc_open_file (CONTEXT,ID,MODE);		\
+	if (maybe_open_ret) {						\
+	    k5_mutex_unlock(&((krb5_fcc_data *)(ID)->data)->lock);	\
+	    return maybe_open_ret;					\
+	}								\
+    }									\
+}
+
+#define MAYBE_CLOSE(CONTEXT, ID, RET)					\
+{									\
+    if (OPENCLOSE (ID)) {						\
+	krb5_error_code maybe_close_ret;				\
+        maybe_close_ret = krb5_fcc_close_file (CONTEXT,			\
+					       (krb5_fcc_data *)(ID)->data); \
+	if (!(RET)) RET = maybe_close_ret; } }
+
+#define MAYBE_CLOSE_IGNORE(CONTEXT, ID) \
+{                                                                       \
+    if (OPENCLOSE (ID)) {                                               \
+        (void) krb5_fcc_close_file (CONTEXT,(krb5_fcc_data *)(ID)->data); } }
+
+#define CHECK(ret) if (ret != KRB5_OK) goto errout;
+
+#define NO_FILE -1
+
+/*
+ * Effects:
+ * Reads len bytes from the cache id, storing them in buf.
+ *
+ * Requires:
+ * Must be called with mutex locked.
+ *
+ * Errors:
+ * KRB5_CC_END - there were not len bytes available
+ * system errors (read)
+ */
+static krb5_error_code
+krb5_fcc_read(krb5_context context, krb5_ccache id, krb5_pointer buf, unsigned int len)
+{
+#if 0
+     int ret;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     ret = read(((krb5_fcc_data *) id->data)->file, (char *) buf, len);
+     if (ret == -1)
+	  return krb5_fcc_interpret(context, errno);
+     if (ret != len)
+	  return KRB5_CC_END;
+     else
+	  return KRB5_OK;
+#else
+     krb5_fcc_data *data = (krb5_fcc_data *) id->data;
+
+     k5_assert_locked(&data->lock);
+
+     while (len > 0) {
+	 int nread, e;
+	 size_t ncopied;
+
+	 assert (data->valid_bytes >= 0);
+	 if (data->valid_bytes > 0)
+	     assert(data->cur_offset <= data->valid_bytes);
+	 if (data->valid_bytes == 0
+	     || data->cur_offset == data->valid_bytes) {
+	     /* Fill buffer from current file position.  */
+	     nread = read(data->file, data->buf, sizeof(data->buf));
+	     e = errno;
+	     if (nread < 0)
+		 return krb5_fcc_interpret(context, e);
+	     if (nread == 0)
+		 /* EOF */
+		 return KRB5_CC_END;
+	     data->valid_bytes = nread;
+	     data->cur_offset = 0;
+	 }
+	 assert(data->cur_offset < data->valid_bytes);
+	 ncopied = len;
+	 assert(ncopied == len);
+	 if (data->valid_bytes - data->cur_offset < ncopied)
+	     ncopied = data->valid_bytes - data->cur_offset;
+	 memcpy(buf, data->buf + data->cur_offset, ncopied);
+	 data->cur_offset += ncopied;
+	 assert(data->cur_offset > 0);
+	 assert(data->cur_offset <= data->valid_bytes);
+	 len -= ncopied;
+	 assert(len >= 0);
+	 /* Don't do arithmetic on void pointers.  */
+	 buf = (char*)buf + ncopied;
+     }
+     return 0;
+#endif
+}
+
+/*
+ * FOR ALL OF THE FOLLOWING FUNCTIONS:
+ *
+ * Requires:
+ * id is open and set to read at the appropriate place in the file
+ *
+ * mutex is locked
+ *
+ * Effects:
+ * Fills in the second argument with data of the appropriate type from
+ * the file.  In some cases, the functions have to allocate space for
+ * variable length fields; therefore, krb5_destroy_<type> must be
+ * called for each filled in structure.
+ *
+ * Errors:
+ * system errors (read errors)
+ * KRB5_CC_NOMEM
+ */
+
+#define ALLOC(NUM,TYPE) \
+    (((NUM) <= (((size_t)0-1)/ sizeof(TYPE)))		\
+     ? (TYPE *) calloc((NUM), sizeof(TYPE))		\
+     : (errno = ENOMEM,(TYPE *) 0))
+
+static krb5_error_code
+krb5_fcc_read_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    krb5_error_code kret;
+    register krb5_principal tmpprinc;
+    krb5_int32 length, type;
+    int i;
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if (data->version == KRB5_FCC_FVNO_1) {
+	type = KRB5_NT_UNKNOWN;
+    } else {
+        /* Read principal type */
+        kret = krb5_fcc_read_int32(context, id, &type);
+        if (kret != KRB5_OK)
+	    return kret;
+    }
+
+    /* Read the number of components */
+    kret = krb5_fcc_read_int32(context, id, &length);
+    if (kret != KRB5_OK)
+	return kret;
+
+    /*
+     * DCE includes the principal's realm in the count; the new format
+     * does not.
+     */
+    if (data->version == KRB5_FCC_FVNO_1)
+	length--;
+    if (length < 0)
+	return KRB5_CC_NOMEM;
+
+    tmpprinc = (krb5_principal) malloc(sizeof(krb5_principal_data));
+    if (tmpprinc == NULL)
+	return KRB5_CC_NOMEM;
+    if (length) {
+	size_t msize = length;
+	if (msize != length) {
+	    free(tmpprinc);
+	    return KRB5_CC_NOMEM;
+	}
+	tmpprinc->data = ALLOC (msize, krb5_data);
+	if (tmpprinc->data == 0) {
+	    free((char *)tmpprinc);
+	    return KRB5_CC_NOMEM;
+	}
+    } else
+	tmpprinc->data = 0;
+    tmpprinc->magic = KV5M_PRINCIPAL;
+    tmpprinc->length = length;
+    tmpprinc->type = type;
+
+    kret = krb5_fcc_read_data(context, id, krb5_princ_realm(context, tmpprinc));
+
+    i = 0;
+    CHECK(kret);
+
+    for (i=0; i < length; i++) {
+	kret = krb5_fcc_read_data(context, id, krb5_princ_component(context, tmpprinc, i));
+	CHECK(kret);
+    }
+    *princ = tmpprinc;
+    return KRB5_OK;
+
+ errout:
+    while(--i >= 0)
+	free(krb5_princ_component(context, tmpprinc, i)->data);
+    free((char *)tmpprinc->data);
+    free((char *)tmpprinc);
+    return kret;
+}
+
+static krb5_error_code
+krb5_fcc_read_addrs(krb5_context context, krb5_ccache id, krb5_address ***addrs)
+{
+     krb5_error_code kret;
+     krb5_int32 length;
+     size_t msize;
+     int i;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     *addrs = 0;
+
+     /* Read the number of components */
+     kret = krb5_fcc_read_int32(context, id, &length);
+     CHECK(kret);
+
+     /* Make *addrs able to hold length pointers to krb5_address structs
+      * Add one extra for a null-terminated list
+      */
+     msize = length;
+     msize += 1;
+     if (msize == 0 || msize - 1 != length || length < 0)
+	 return KRB5_CC_NOMEM;
+     *addrs = ALLOC (msize, krb5_address *);
+     if (*addrs == NULL)
+	  return KRB5_CC_NOMEM;
+
+     for (i=0; i < length; i++) {
+	  (*addrs)[i] = (krb5_address *) malloc(sizeof(krb5_address));
+	  if ((*addrs)[i] == NULL) {
+	      krb5_free_addresses(context, *addrs);
+	      return KRB5_CC_NOMEM;
+	  }	  
+	  kret = krb5_fcc_read_addr(context, id, (*addrs)[i]);
+	  CHECK(kret);
+     }
+
+     return KRB5_OK;
+ errout:
+     if (*addrs)
+	 krb5_free_addresses(context, *addrs);
+     return kret;
+}
+
+static krb5_error_code
+krb5_fcc_read_keyblock(krb5_context context, krb5_ccache id, krb5_keyblock *keyblock)
+{
+     krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+     krb5_error_code kret;
+     krb5_ui_2 ui2;
+     krb5_int32 int32;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     keyblock->magic = KV5M_KEYBLOCK;
+     keyblock->contents = 0;
+
+     kret = krb5_fcc_read_ui_2(context, id, &ui2);
+     keyblock->enctype = ui2;
+     CHECK(kret);
+     if (data->version == KRB5_FCC_FVNO_3) {
+	 /* This works because the old etype is the same as the new enctype. */
+	     kret = krb5_fcc_read_ui_2(context, id, &ui2);
+	     /* keyblock->enctype = ui2; */
+	     CHECK(kret);
+     }
+
+     kret = krb5_fcc_read_int32(context, id, &int32);
+     CHECK(kret);
+     if (int32 < 0)
+	  return KRB5_CC_NOMEM;
+     keyblock->length = int32;
+     /* Overflow check.  */
+     if (keyblock->length != int32)
+	 return KRB5_CC_NOMEM;
+     if ( keyblock->length == 0 )
+	 return KRB5_OK;
+     keyblock->contents = ALLOC (keyblock->length, krb5_octet);
+     if (keyblock->contents == NULL)
+	 return KRB5_CC_NOMEM;
+     
+     kret = krb5_fcc_read(context, id, keyblock->contents, keyblock->length);
+     if (kret)
+	 goto errout;
+
+     return KRB5_OK;
+ errout:
+     if (keyblock->contents)
+	 krb5_xfree(keyblock->contents);
+     return kret;
+}
+
+static krb5_error_code
+krb5_fcc_read_data(krb5_context context, krb5_ccache id, krb5_data *data)
+{
+     krb5_error_code kret;
+     krb5_int32 len;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     data->magic = KV5M_DATA;
+     data->data = 0;
+
+     kret = krb5_fcc_read_int32(context, id, &len);
+     CHECK(kret);
+     if (len < 0)
+        return KRB5_CC_NOMEM;
+     data->length = len;
+     if (data->length != len || data->length + 1 == 0)
+	 return KRB5_CC_NOMEM;
+
+     if (data->length == 0) {
+	data->data = 0;
+	return KRB5_OK;
+     }
+
+     data->data = (char *) malloc(data->length+1);
+     if (data->data == NULL)
+	  return KRB5_CC_NOMEM;
+
+     kret = krb5_fcc_read(context, id, data->data, (unsigned) data->length);
+     CHECK(kret);
+     
+     data->data[data->length] = 0; /* Null terminate, just in case.... */
+     return KRB5_OK;
+ errout:
+     if (data->data)
+	 krb5_xfree(data->data);
+     return kret;
+}
+
+static krb5_error_code
+krb5_fcc_read_addr(krb5_context context, krb5_ccache id, krb5_address *addr)
+{
+     krb5_error_code kret;
+     krb5_ui_2 ui2;
+     krb5_int32 int32;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     addr->magic = KV5M_ADDRESS;
+     addr->contents = 0;
+
+     kret = krb5_fcc_read_ui_2(context, id, &ui2);
+     CHECK(kret);
+     addr->addrtype = ui2;
+     
+     kret = krb5_fcc_read_int32(context, id, &int32);
+     CHECK(kret);
+     if ((int32 & VALID_INT_BITS) != int32)     /* Overflow int??? */
+	  return KRB5_CC_NOMEM;
+     addr->length = int32;
+     /* Length field is "unsigned int", which may be smaller than 32
+        bits.  */
+     if (addr->length != int32)
+	 return KRB5_CC_NOMEM;	/* XXX */
+
+     if (addr->length == 0)
+	     return KRB5_OK;
+
+     addr->contents = (krb5_octet *) malloc(addr->length);
+     if (addr->contents == NULL)
+	  return KRB5_CC_NOMEM;
+
+     kret = krb5_fcc_read(context, id, addr->contents, addr->length);
+     CHECK(kret);
+
+     return KRB5_OK;
+ errout:
+     if (addr->contents)
+	 krb5_xfree(addr->contents);
+     return kret;
+}
+
+static krb5_error_code
+krb5_fcc_read_int32(krb5_context context, krb5_ccache id, krb5_int32 *i)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    krb5_error_code retval;
+    unsigned char buf[4];
+    krb5_int32 val;
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if ((data->version == KRB5_FCC_FVNO_1) ||
+	(data->version == KRB5_FCC_FVNO_2)) 
+	return krb5_fcc_read(context, id, (krb5_pointer) i, sizeof(krb5_int32));
+    else {
+	retval = krb5_fcc_read(context, id, buf, 4);
+	if (retval)
+	    return retval;
+        val = buf[0];
+        val = (val << 8) | buf[1];
+        val = (val << 8) | buf[2];
+        val = (val << 8) | buf[3];
+        *i = val;
+	return 0;
+    }
+}
+
+static krb5_error_code
+krb5_fcc_read_ui_2(krb5_context context, krb5_ccache id, krb5_ui_2 *i)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    krb5_error_code retval;
+    unsigned char buf[2];
+    
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if ((data->version == KRB5_FCC_FVNO_1) ||
+	(data->version == KRB5_FCC_FVNO_2))
+	return krb5_fcc_read(context, id, (krb5_pointer) i, sizeof(krb5_ui_2));
+    else {
+	retval = krb5_fcc_read(context, id, buf, 2);
+	if (retval)
+	    return retval;
+	*i = (buf[0] << 8) + buf[1];
+	return 0;
+    }
+}    
+
+static krb5_error_code
+krb5_fcc_read_octet(krb5_context context, krb5_ccache id, krb5_octet *i)
+{
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+    return krb5_fcc_read(context, id, (krb5_pointer) i, 1);
+}    
+
+
+static krb5_error_code
+krb5_fcc_read_times(krb5_context context, krb5_ccache id, krb5_ticket_times *t)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    krb5_error_code retval;
+    krb5_int32 i;
+    
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if ((data->version == KRB5_FCC_FVNO_1) ||
+	(data->version == KRB5_FCC_FVNO_2))
+	return krb5_fcc_read(context, id, (krb5_pointer) t, sizeof(krb5_ticket_times));
+    else {
+	retval = krb5_fcc_read_int32(context, id, &i);
+	CHECK(retval);
+	t->authtime = i;
+	
+	retval = krb5_fcc_read_int32(context, id, &i);
+	CHECK(retval);
+	t->starttime = i;
+
+	retval = krb5_fcc_read_int32(context, id, &i);
+	CHECK(retval);
+	t->endtime = i;
+
+	retval = krb5_fcc_read_int32(context, id, &i);
+	CHECK(retval);
+	t->renew_till = i;
+    }
+    return 0;
+errout:
+    return retval;
+}
+
+static krb5_error_code
+krb5_fcc_read_authdata(krb5_context context, krb5_ccache id, krb5_authdata ***a)
+{
+     krb5_error_code kret;
+     krb5_int32 length;
+     size_t msize;
+     int i;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     *a = 0;
+
+     /* Read the number of components */
+     kret = krb5_fcc_read_int32(context, id, &length);
+     CHECK(kret);
+
+     if (length == 0)
+	 return KRB5_OK;
+
+     /* Make *a able to hold length pointers to krb5_authdata structs
+      * Add one extra for a null-terminated list
+      */
+     msize = length;
+     msize += 1;
+     if (msize == 0 || msize - 1 != length || length < 0)
+	 return KRB5_CC_NOMEM;
+     *a = ALLOC (msize, krb5_authdata *);
+     if (*a == NULL)
+	  return KRB5_CC_NOMEM;
+
+     for (i=0; i < length; i++) {
+	  (*a)[i] = (krb5_authdata *) malloc(sizeof(krb5_authdata));
+	  if ((*a)[i] == NULL) {
+	      krb5_free_authdata(context, *a);
+	      return KRB5_CC_NOMEM;
+	  }	  
+	  kret = krb5_fcc_read_authdatum(context, id, (*a)[i]);
+	  CHECK(kret);
+     }
+
+     return KRB5_OK;
+ errout:
+     if (*a)
+	 krb5_free_authdata(context, *a);
+     return kret;
+}
+
+static krb5_error_code
+krb5_fcc_read_authdatum(krb5_context context, krb5_ccache id, krb5_authdata *a)
+{
+    krb5_error_code kret;
+    krb5_int32 int32;
+    krb5_ui_2 ui2;
+    
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    a->magic = KV5M_AUTHDATA;
+    a->contents = NULL;
+
+    kret = krb5_fcc_read_ui_2(context, id, &ui2);
+    CHECK(kret);
+    a->ad_type = (krb5_authdatatype)ui2;
+    kret = krb5_fcc_read_int32(context, id, &int32);
+    CHECK(kret);
+    if ((int32 & VALID_INT_BITS) != int32)     /* Overflow int??? */
+          return KRB5_CC_NOMEM;
+    a->length = int32;
+    /* Value could have gotten truncated if int is smaller than 32
+       bits.  */
+    if (a->length != int32)
+	return KRB5_CC_NOMEM;	/* XXX */
+    
+    if (a->length == 0 )
+	    return KRB5_OK;
+
+    a->contents = (krb5_octet *) malloc(a->length);
+    if (a->contents == NULL)
+	return KRB5_CC_NOMEM;
+
+    kret = krb5_fcc_read(context, id, a->contents, a->length);
+    CHECK(kret);
+    
+     return KRB5_OK;
+ errout:
+     if (a->contents)
+	 krb5_xfree(a->contents);
+     return kret;
+    
+}
+#undef CHECK
+
+#define CHECK(ret) if (ret != KRB5_OK) return ret;
+
+/*
+ * Requires:
+ * id is open
+ *
+ * Effects:
+ * Writes len bytes from buf into the file cred cache id.
+ *
+ * Errors:
+ * system errors
+ */
+static krb5_error_code
+krb5_fcc_write(krb5_context context, krb5_ccache id, krb5_pointer buf, unsigned int len)
+{
+     int ret;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+     invalidate_cache((krb5_fcc_data *) id->data);
+
+     ret = write(((krb5_fcc_data *)id->data)->file, (char *) buf, len);
+     if (ret < 0)
+	  return krb5_fcc_interpret(context, errno);
+     if (ret != len)
+         return KRB5_CC_WRITE;
+     return KRB5_OK;
+}
+
+/*
+ * FOR ALL OF THE FOLLOWING FUNCTIONS:
+ * 
+ * Requires:
+ * ((krb5_fcc_data *) id->data)->file is open and at the right position.
+ *
+ * mutex is locked
+ * 
+ * Effects:
+ * Stores an encoded version of the second argument in the
+ * cache file.
+ *
+ * Errors:
+ * system errors
+ */
+
+static krb5_error_code
+krb5_fcc_store_principal(krb5_context context, krb5_ccache id, krb5_principal princ)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    krb5_error_code ret;
+    krb5_int32 i, length, tmp, type;
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    type = krb5_princ_type(context, princ);
+    tmp = length = krb5_princ_size(context, princ);
+
+    if (data->version == KRB5_FCC_FVNO_1) {
+	/*
+	 * DCE-compatible format means that the length count
+	 * includes the realm.  (It also doesn't include the
+	 * principal type information.)
+	 */
+	tmp++;
+    } else {
+	ret = krb5_fcc_store_int32(context, id, type);
+	CHECK(ret);
+    }
+    
+    ret = krb5_fcc_store_int32(context, id, tmp);
+    CHECK(ret);
+
+    ret = krb5_fcc_store_data(context, id, krb5_princ_realm(context, princ));
+    CHECK(ret);
+
+    for (i=0; i < length; i++) {
+	ret = krb5_fcc_store_data(context, id, krb5_princ_component(context, princ, i));
+	CHECK(ret);
+    }
+
+    return KRB5_OK;
+}
+
+static krb5_error_code
+krb5_fcc_store_addrs(krb5_context context, krb5_ccache id, krb5_address **addrs)
+{
+     krb5_error_code ret;
+     krb5_address **temp;
+     krb5_int32 i, length = 0;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     /* Count the number of components */
+     if (addrs) {
+	     temp = addrs;
+	     while (*temp++)
+		     length += 1;
+     }
+
+     ret = krb5_fcc_store_int32(context, id, length);
+     CHECK(ret);
+     for (i=0; i < length; i++) {
+	  ret = krb5_fcc_store_addr(context, id, addrs[i]);
+	  CHECK(ret);
+     }
+
+     return KRB5_OK;
+}
+
+static krb5_error_code
+krb5_fcc_store_keyblock(krb5_context context, krb5_ccache id, krb5_keyblock *keyblock)
+{
+     krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+     krb5_error_code ret;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     ret = krb5_fcc_store_ui_2(context, id, keyblock->enctype);
+     CHECK(ret);
+     if (data->version == KRB5_FCC_FVNO_3) {
+	 ret = krb5_fcc_store_ui_2(context, id, keyblock->enctype);
+	 CHECK(ret);
+     }
+     ret = krb5_fcc_store_ui_4(context, id, keyblock->length);
+     CHECK(ret);
+     return krb5_fcc_write(context, id, (char *) keyblock->contents, keyblock->length);
+}
+
+static krb5_error_code
+krb5_fcc_store_addr(krb5_context context, krb5_ccache id, krb5_address *addr)
+{
+     krb5_error_code ret;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     ret = krb5_fcc_store_ui_2(context, id, addr->addrtype);
+     CHECK(ret);
+     ret = krb5_fcc_store_ui_4(context, id, addr->length);
+     CHECK(ret);
+     return krb5_fcc_write(context, id, (char *) addr->contents, addr->length);
+}
+
+
+static krb5_error_code
+krb5_fcc_store_data(krb5_context context, krb5_ccache id, krb5_data *data)
+{
+     krb5_error_code ret;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     ret = krb5_fcc_store_ui_4(context, id, data->length);
+     CHECK(ret);
+     return krb5_fcc_write(context, id, data->data, data->length);
+}
+
+static krb5_error_code
+krb5_fcc_store_int32(krb5_context context, krb5_ccache id, krb5_int32 i)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    unsigned char buf[4];
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if ((data->version == KRB5_FCC_FVNO_1) ||
+	(data->version == KRB5_FCC_FVNO_2)) 
+	return krb5_fcc_write(context, id, (char *) &i, sizeof(krb5_int32));
+    else {
+        buf[3] = (unsigned char) (i & 0xFF);
+	i >>= 8;
+        buf[2] = (unsigned char) (i & 0xFF);
+	i >>= 8;
+        buf[1] = (unsigned char) (i & 0xFF);
+	i >>= 8;
+        buf[0] = (unsigned char) (i & 0xFF);
+	return krb5_fcc_write(context, id, buf, 4);
+    }
+}
+
+static krb5_error_code
+krb5_fcc_store_ui_4(krb5_context context, krb5_ccache id, krb5_ui_4 i)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    unsigned char buf[4];
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if ((data->version == KRB5_FCC_FVNO_1) ||
+	(data->version == KRB5_FCC_FVNO_2)) 
+	return krb5_fcc_write(context, id, (char *) &i, sizeof(krb5_int32));
+    else {
+        buf[3] = (unsigned char) (i & 0xFF);
+	i >>= 8;
+        buf[2] = (unsigned char) (i & 0xFF);
+	i >>= 8;
+        buf[1] = (unsigned char) (i & 0xFF);
+	i >>= 8;
+        buf[0] = (unsigned char) (i & 0xFF);
+	return krb5_fcc_write(context, id, buf, 4);
+    }
+}
+
+static krb5_error_code
+krb5_fcc_store_ui_2(krb5_context context, krb5_ccache id, krb5_int32 i)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    krb5_ui_2 ibuf;
+    unsigned char buf[2];
+    
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if ((data->version == KRB5_FCC_FVNO_1) ||
+	(data->version == KRB5_FCC_FVNO_2)) {
+        ibuf = (krb5_ui_2) i;
+	return krb5_fcc_write(context, id, (char *) &ibuf, sizeof(krb5_ui_2));
+    } else {
+        buf[1] = (unsigned char) (i & 0xFF);
+	i >>= 8;
+        buf[0] = (unsigned char) (i & 0xFF);
+	return krb5_fcc_write(context, id, buf, 2);
+    }
+}
+   
+static krb5_error_code
+krb5_fcc_store_octet(krb5_context context, krb5_ccache id, krb5_int32 i)
+{
+    krb5_octet ibuf;
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    ibuf = (krb5_octet) i;
+    return krb5_fcc_write(context, id, (char *) &ibuf, 1);
+}
+   
+static krb5_error_code
+krb5_fcc_store_times(krb5_context context, krb5_ccache id, krb5_ticket_times *t)
+{
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    krb5_error_code retval;
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if ((data->version == KRB5_FCC_FVNO_1) ||
+	(data->version == KRB5_FCC_FVNO_2))
+	return krb5_fcc_write(context, id, (char *) t, sizeof(krb5_ticket_times));
+    else {
+	retval = krb5_fcc_store_int32(context, id, t->authtime);
+	CHECK(retval);
+	retval = krb5_fcc_store_int32(context, id, t->starttime);
+	CHECK(retval);
+	retval = krb5_fcc_store_int32(context, id, t->endtime);
+	CHECK(retval);
+	retval = krb5_fcc_store_int32(context, id, t->renew_till);
+	CHECK(retval);
+	return 0;
+    }
+}
+   
+static krb5_error_code
+krb5_fcc_store_authdata(krb5_context context, krb5_ccache id, krb5_authdata **a)
+{
+    krb5_error_code ret;
+    krb5_authdata **temp;
+    krb5_int32 i, length=0;
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    if (a != NULL) {
+	for (temp=a; *temp; temp++)
+	    length++;
+    }
+
+    ret = krb5_fcc_store_int32(context, id, length);
+    CHECK(ret);
+    for (i=0; i<length; i++) {
+	ret = krb5_fcc_store_authdatum (context, id, a[i]);
+	CHECK(ret);
+    }
+    return KRB5_OK;
+}
+
+static krb5_error_code
+krb5_fcc_store_authdatum (krb5_context context, krb5_ccache id, krb5_authdata *a)
+{
+    krb5_error_code ret;
+
+    k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+    ret = krb5_fcc_store_ui_2(context, id, a->ad_type);
+    CHECK(ret);
+    ret = krb5_fcc_store_ui_4(context, id, a->length);
+    CHECK(ret);
+    return krb5_fcc_write(context, id, (krb5_pointer) a->contents, a->length);
+}
+#undef CHECK
+
+static krb5_error_code
+krb5_fcc_close_file (krb5_context context, krb5_fcc_data *data)
+{
+     int ret;
+     krb5_error_code retval;
+
+     k5_assert_locked(&data->lock);
+
+     if (data->file == NO_FILE)
+	 return KRB5_FCC_INTERNAL;
+
+     retval = krb5_unlock_file(context, data->file);
+     ret = close (data->file);
+     data->file = NO_FILE;
+     if (retval)
+	 return retval;
+
+     return ret ? krb5_fcc_interpret (context, errno) : 0;
+}
+
+#if defined(ANSI_STDIO) || defined(_WIN32)
+#define BINARY_MODE "b"
+#else
+#define BINARY_MODE ""
+#endif
+
+#ifndef HAVE_SETVBUF
+#undef setvbuf
+#define setvbuf(FILE,BUF,MODE,SIZE) \
+  ((SIZE) < BUFSIZE ? (abort(),0) : setbuf(FILE, BUF))
+#endif
+
+static krb5_error_code
+krb5_fcc_open_file (krb5_context context, krb5_ccache id, int mode)
+{
+    krb5_os_context os_ctx = (krb5_os_context)context->os_context;
+    krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+    krb5_ui_2 fcc_fvno;
+    krb5_ui_2 fcc_flen;
+    krb5_ui_2 fcc_tag;
+    krb5_ui_2 fcc_taglen;
+    int f, open_flag;
+    int lock_flag;
+    krb5_error_code retval = 0;
+
+    k5_assert_locked(&data->lock);
+    invalidate_cache(data);
+
+    if (data->file != NO_FILE) {
+	/* Don't know what state it's in; shut down and start anew.  */
+	(void) krb5_unlock_file(context, data->file);
+	(void) close (data->file);
+	data->file = NO_FILE;
+    }
+
+    switch(mode) {
+    case FCC_OPEN_AND_ERASE:
+	unlink(data->filename);
+	open_flag = O_CREAT|O_EXCL|O_TRUNC|O_RDWR;
+	break;
+    case FCC_OPEN_RDWR:
+	open_flag = O_RDWR;
+	break;
+    case FCC_OPEN_RDONLY:
+    default:
+	open_flag = O_RDONLY;
+	break;
+    }
+
+    f = THREEPARAMOPEN (data->filename, open_flag | O_BINARY, 0600);
+    if (f == NO_FILE)
+	return krb5_fcc_interpret (context, errno);
+
+    data->mode = mode;
+
+    if (data->mode == FCC_OPEN_RDONLY)
+	lock_flag = KRB5_LOCKMODE_SHARED;
+    else 
+	lock_flag = KRB5_LOCKMODE_EXCLUSIVE;
+    if ((retval = krb5_lock_file(context, f, lock_flag))) {
+	(void) close(f);
+	return retval;
+    }
+
+    if (mode == FCC_OPEN_AND_ERASE) {
+	 /* write the version number */
+         int cnt;
+
+         fcc_fvno = htons(context->fcc_default_format);
+         data->version = context->fcc_default_format;
+         if ((cnt = write(f, (char *)&fcc_fvno, sizeof(fcc_fvno))) !=
+             sizeof(fcc_fvno)) {
+             retval = ((cnt == -1) ? krb5_fcc_interpret(context, errno) :
+                       KRB5_CC_IO);
+             goto done;
+         }
+         data->file = f;
+
+	 if (data->version == KRB5_FCC_FVNO_4) {
+             /* V4 of the credentials cache format allows for header tags */
+	     fcc_flen = 0;
+
+	     if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)
+		 fcc_flen += (2*sizeof(krb5_ui_2) + 2*sizeof(krb5_int32));
+
+	     /* Write header length */
+	     retval = krb5_fcc_store_ui_2(context, id, (krb5_int32)fcc_flen);
+	     if (retval) goto done;
+
+	     if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
+		 /* Write time offset tag */
+		 fcc_tag = FCC_TAG_DELTATIME;
+		 fcc_taglen = 2*sizeof(krb5_int32);
+		 
+		 retval = krb5_fcc_store_ui_2(context,id,(krb5_int32)fcc_tag);
+		 if (retval) goto done;
+		 retval = krb5_fcc_store_ui_2(context,id,(krb5_int32)fcc_taglen);
+		 if (retval) goto done;
+		 retval = krb5_fcc_store_int32(context,id,os_ctx->time_offset);
+		 if (retval) goto done;
+		 retval = krb5_fcc_store_int32(context,id,os_ctx->usec_offset);
+		 if (retval) goto done;
+	     }
+	 }
+	 invalidate_cache(data);
+	 goto done;
+     }
+
+     /* verify a valid version number is there */
+    invalidate_cache(data);
+     if (read(f, (char *)&fcc_fvno, sizeof(fcc_fvno)) != sizeof(fcc_fvno)) {
+	 retval = KRB5_CC_FORMAT;
+	 goto done;
+     }
+     data->version = ntohs(fcc_fvno);
+    if ((data->version != KRB5_FCC_FVNO_4) &&
+	(data->version != KRB5_FCC_FVNO_3) &&
+	(data->version != KRB5_FCC_FVNO_2) &&
+	(data->version != KRB5_FCC_FVNO_1)) {
+	retval = KRB5_CCACHE_BADVNO;
+	goto done;
+    }
+
+    data->file = f;
+
+     if (data->version == KRB5_FCC_FVNO_4) {
+	 char buf[1024];
+
+	 if (krb5_fcc_read_ui_2(context, id, &fcc_flen) ||
+	     (fcc_flen > sizeof(buf)))
+	 {
+	     retval = KRB5_CC_FORMAT;
+	     goto done;
+	 }
+
+	 while (fcc_flen) {
+	     if ((fcc_flen < (2 * sizeof(krb5_ui_2))) ||
+		 krb5_fcc_read_ui_2(context, id, &fcc_tag) ||
+		 krb5_fcc_read_ui_2(context, id, &fcc_taglen) ||
+		 (fcc_taglen > (fcc_flen - 2*sizeof(krb5_ui_2))))
+	     {
+		 retval = KRB5_CC_FORMAT;
+		 goto done;
+	     }
+
+	     switch (fcc_tag) {
+	     case FCC_TAG_DELTATIME:
+		 if (fcc_taglen != 2*sizeof(krb5_int32)) {
+		     retval = KRB5_CC_FORMAT;
+		     goto done;
+		 }
+		 if (!(context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) ||
+		     (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID))
+		 {
+		     if (krb5_fcc_read(context, id, buf, fcc_taglen)) {
+			 retval = KRB5_CC_FORMAT;
+			 goto done;
+		     }
+		     break;
+		 }
+		 if (krb5_fcc_read_int32(context, id, &os_ctx->time_offset) ||
+		     krb5_fcc_read_int32(context, id, &os_ctx->usec_offset))
+		 {
+		     retval = KRB5_CC_FORMAT;
+		     goto done;
+		 }
+		 os_ctx->os_flags =
+		     ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
+		      KRB5_OS_TOFFSET_VALID);
+		 break;
+	     default:
+		 if (fcc_taglen && krb5_fcc_read(context,id,buf,fcc_taglen)) {
+		     retval = KRB5_CC_FORMAT;
+		     goto done;
+		 }
+		 break;
+	     }
+	     fcc_flen -= (2*sizeof(krb5_ui_2) + fcc_taglen);
+	 }
+     }
+
+done:
+     if (retval) {
+         data->file = -1;
+         (void) krb5_unlock_file(context, f);
+         (void) close(f);
+     }
+     return retval;
+}
+
+static krb5_error_code
+krb5_fcc_skip_header(krb5_context context, krb5_ccache id)
+{
+     krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+     krb5_error_code kret;
+     krb5_ui_2 fcc_flen;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     fcc_lseek(data, (off_t) sizeof(krb5_ui_2), SEEK_SET);
+     if (data->version == KRB5_FCC_FVNO_4) {
+	 kret = krb5_fcc_read_ui_2(context, id, &fcc_flen);
+	 if (kret) return kret;
+         if(fcc_lseek(data, (off_t) fcc_flen, SEEK_CUR) < 0)
+		return errno;
+     }
+     return KRB5_OK;
+}
+
+static krb5_error_code
+krb5_fcc_skip_principal(krb5_context context, krb5_ccache id)
+{
+     krb5_error_code kret;
+     krb5_principal princ;
+
+     k5_assert_locked(&((krb5_fcc_data *) id->data)->lock);
+
+     kret = krb5_fcc_read_principal(context, id, &princ);
+     if (kret != KRB5_OK)
+	  return kret;
+
+     krb5_free_principal(context, princ);
+     return KRB5_OK;
+}
+
+
+/*
+ * Modifies:
+ * id
+ *
+ * Effects:
+ * Creates/refreshes the file cred cache id.  If the cache exists, its
+ * contents are destroyed.
+ *
+ * Errors:
+ * system errors
+ * permission errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
+{
+     krb5_error_code kret = 0;
+     int reti = 0;
+
+     kret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+     if (kret)
+	 return kret;
+
+     MAYBE_OPEN(context, id, FCC_OPEN_AND_ERASE);
+
+#if defined(HAVE_FCHMOD) || defined(HAVE_CHMOD)
+     {
+#ifdef HAVE_FCHMOD
+         reti = fchmod(((krb5_fcc_data *) id->data)->file, S_IREAD | S_IWRITE);
+#else
+         reti = chmod(((krb5_fcc_data *) id->data)->filename, S_IREAD | S_IWRITE);
+#endif
+         if (reti == -1) {
+             kret = krb5_fcc_interpret(context, errno);
+             MAYBE_CLOSE(context, id, kret);
+	     k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+             return kret;
+         }
+     }
+#endif
+     kret = krb5_fcc_store_principal(context, id, princ);
+
+     MAYBE_CLOSE(context, id, kret);
+     k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+     krb5_change_cache ();
+     return kret;
+}
+
+/*
+ * Drop the ref count; if it hits zero, remove the entry from the
+ * fcc_set list and free it.
+ */
+static krb5_error_code dereference(krb5_context context, krb5_fcc_data *data)
+{
+    krb5_error_code kerr;
+    struct fcc_set **fccsp;
+
+    kerr = k5_mutex_lock(&krb5int_cc_file_mutex);
+    if (kerr)
+	return kerr;
+    for (fccsp = &fccs; *fccsp != NULL; fccsp = &(*fccsp)->next)
+	if ((*fccsp)->data == data)
+	    break;
+    assert(*fccsp != NULL);
+    assert((*fccsp)->data == data);
+    (*fccsp)->refcount--;
+    if ((*fccsp)->refcount == 0) {
+        struct fcc_set *temp;
+	data = (*fccsp)->data;
+	temp = *fccsp;
+	*fccsp = (*fccsp)->next;
+	free(temp);
+	k5_mutex_unlock(&krb5int_cc_file_mutex);
+	k5_mutex_assert_unlocked(&data->lock);
+	free(data->filename);
+	zap(data->buf, sizeof(data->buf));
+	if (data->file >= 0) {
+	    k5_mutex_lock(&data->lock);
+	    krb5_fcc_close_file(context, data);
+	    k5_mutex_unlock(&data->lock);
+	}
+	k5_mutex_destroy(&data->lock);
+	free(data);
+    } else
+	k5_mutex_unlock(&krb5int_cc_file_mutex);
+    return 0;
+}
+
+/*
+ * Modifies:
+ * id
+ *
+ * Effects:
+ * Closes the file cache, invalidates the id, and frees any resources
+ * associated with the cache.
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_close(krb5_context context, krb5_ccache id)
+{
+     dereference(context, (krb5_fcc_data *) id->data);
+     krb5_xfree(id);
+     return KRB5_OK;
+}
+
+/*
+ * Effects:
+ * Destroys the contents of id.
+ *
+ * Errors:
+ * system errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_destroy(krb5_context context, krb5_ccache id)
+{
+     krb5_error_code kret = 0;
+     krb5_fcc_data *data = (krb5_fcc_data *) id->data;
+     register int ret;
+
+     struct stat buf;
+     unsigned long i, size;
+     unsigned int wlen;
+     char zeros[BUFSIZ];
+
+     kret = k5_mutex_lock(&data->lock);
+     if (kret)
+	 return kret;
+
+     if (OPENCLOSE(id)) {
+	 invalidate_cache(data);
+	  ret = THREEPARAMOPEN(data->filename,
+			       O_RDWR | O_BINARY, 0);
+	  if (ret < 0) {
+	      kret = krb5_fcc_interpret(context, errno);
+	      goto cleanup;
+	  }
+	  data->file = ret;
+     }
+     else
+	  fcc_lseek(data, (off_t) 0, SEEK_SET);
+
+#ifdef MSDOS_FILESYSTEM
+/* "disgusting bit of UNIX trivia" - that's how the writers of NFS describe
+** the ability of UNIX to still write to a file which has been unlinked.
+** Naturally, the PC can't do this. As a result, we have to delete the file
+** after we wipe it clean but that throws off all the error handling code.
+** So we have do the work ourselves.
+*/
+    ret = fstat(data->file, &buf);
+    if (ret == -1) {
+        kret = krb5_fcc_interpret(context, errno);
+        size = 0;                               /* Nothing to wipe clean */
+    } else
+        size = (unsigned long) buf.st_size;
+
+    memset(zeros, 0, BUFSIZ);
+    while (size > 0) {
+        wlen = (int) ((size > BUFSIZ) ? BUFSIZ : size); /* How much to write */
+        i = write(data->file, zeros, wlen);
+        if (i < 0) {
+            kret = krb5_fcc_interpret(context, errno);
+            /* Don't jump to cleanup--we still want to delete the file. */
+            break;
+        }
+        size -= i;                              /* We've read this much */
+    }
+
+    if (OPENCLOSE(id)) {
+        (void) close(((krb5_fcc_data *)id->data)->file);
+        data->file = -1;
+    }
+
+    ret = unlink(data->filename);
+    if (ret < 0) {
+        kret = krb5_fcc_interpret(context, errno);
+        goto cleanup;
+    }
+
+#else /* MSDOS_FILESYSTEM */
+
+     ret = unlink(data->filename);
+     if (ret < 0) {
+	 kret = krb5_fcc_interpret(context, errno);
+	 if (OPENCLOSE(id)) {
+	     (void) close(((krb5_fcc_data *)id->data)->file);
+	     data->file = -1;
+             kret = ret;
+	 }
+	 goto cleanup;
+     }
+     
+     ret = fstat(data->file, &buf);
+     if (ret < 0) {
+	 kret = krb5_fcc_interpret(context, errno);
+	 if (OPENCLOSE(id)) {
+	     (void) close(((krb5_fcc_data *)id->data)->file);
+	     data->file = -1;
+	 }
+	 goto cleanup;
+     }
+
+     /* XXX This may not be legal XXX */
+     size = (unsigned long) buf.st_size;
+     memset(zeros, 0, BUFSIZ);
+     for (i=0; i < size / BUFSIZ; i++)
+	  if (write(data->file, zeros, BUFSIZ) < 0) {
+	      kret = krb5_fcc_interpret(context, errno);
+	      if (OPENCLOSE(id)) {
+		  (void) close(((krb5_fcc_data *)id->data)->file);
+		  data->file = -1;
+	      }
+	      goto cleanup;
+	  }
+
+     wlen = (unsigned int) (size % BUFSIZ);
+     if (write(data->file, zeros, wlen) < 0) {
+	 kret = krb5_fcc_interpret(context, errno);
+	 if (OPENCLOSE(id)) {
+	     (void) close(((krb5_fcc_data *)id->data)->file);
+	     data->file = -1;
+	 }
+	 goto cleanup;
+     }
+
+     ret = close(data->file);
+     data->file = -1;
+
+     if (ret)
+	 kret = krb5_fcc_interpret(context, errno);
+
+#endif /* MSDOS_FILESYSTEM */
+
+  cleanup:
+     k5_mutex_unlock(&data->lock);
+     dereference(context, data);
+     krb5_xfree(id);
+
+     krb5_change_cache ();
+     return kret;
+}
+
+extern const krb5_cc_ops krb5_fcc_ops;
+
+/*
+ * Requires:
+ * residual is a legal path name, and a null-terminated string
+ *
+ * Modifies:
+ * id
+ * 
+ * Effects:
+ * creates a file-based cred cache that will reside in the file
+ * residual.  The cache is not opened, but the filename is reserved.
+ * 
+ * Returns:
+ * A filled in krb5_ccache structure "id".
+ *
+ * Errors:
+ * KRB5_CC_NOMEM - there was insufficient memory to allocate the
+ * 		krb5_ccache.  id is undefined.
+ * permission errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
+{
+     krb5_ccache lid;
+     krb5_error_code kret;
+     krb5_fcc_data *data;
+     struct fcc_set *setptr;
+
+     kret = k5_mutex_lock(&krb5int_cc_file_mutex);
+     if (kret)
+	 return kret;
+     for (setptr = fccs; setptr; setptr = setptr->next) {
+	 if (!strcmp(setptr->data->filename, residual))
+	     break;
+     }
+     if (setptr) {
+	 data = setptr->data;
+	 assert(setptr->refcount != 0);
+	 setptr->refcount++;
+	 assert(setptr->refcount != 0);
+	 kret = k5_mutex_lock(&data->lock);
+	 if (kret) {
+	     k5_mutex_unlock(&krb5int_cc_file_mutex);
+	     return kret;
+	 }
+	 k5_mutex_unlock(&krb5int_cc_file_mutex);
+     } else {
+	 data = malloc(sizeof(krb5_fcc_data));
+	 if (data == NULL) {
+	     k5_mutex_unlock(&krb5int_cc_file_mutex);
+	     return KRB5_CC_NOMEM;
+	 }
+	 data->filename = strdup(residual);
+	 if (data->filename == NULL) {
+	     k5_mutex_unlock(&krb5int_cc_file_mutex);
+	     free(data);
+	     return KRB5_CC_NOMEM;
+	 }
+	 kret = k5_mutex_init(&data->lock);
+	 if (kret) {
+	     k5_mutex_unlock(&krb5int_cc_file_mutex);
+	     free(data->filename);
+	     free(data);
+	     return kret;
+	 }
+	 kret = k5_mutex_lock(&data->lock);
+	 if (kret) {
+	     k5_mutex_unlock(&krb5int_cc_file_mutex);
+	     k5_mutex_destroy(&data->lock);
+	     free(data->filename);
+	     free(data);
+	     return kret;
+	 }
+	 /* data->version,mode filled in for real later */
+	 data->version = data->mode = 0;
+	 data->flags = KRB5_TC_OPENCLOSE;
+	 data->file = -1;
+	 data->valid_bytes = 0;
+	 setptr = malloc(sizeof(struct fcc_set));
+	 if (setptr == NULL) {
+	     k5_mutex_unlock(&krb5int_cc_file_mutex);
+	     k5_mutex_destroy(&data->lock);
+	     free(data->filename);
+	     free(data);
+	     return KRB5_CC_NOMEM;
+	 }
+	 setptr->refcount = 1;
+	 setptr->data = data;
+	 setptr->next = fccs;
+	 fccs = setptr;
+	 k5_mutex_unlock(&krb5int_cc_file_mutex);
+     }
+
+     k5_mutex_assert_locked(&data->lock);
+     k5_mutex_unlock(&data->lock);
+     lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
+     if (lid == NULL) {
+	 dereference(context, data);
+	 return KRB5_CC_NOMEM;
+     }
+
+     lid->ops = &krb5_fcc_ops;
+     lid->data = data;
+     lid->magic = KV5M_CCACHE;
+
+     /* other routines will get errors on open, and callers must expect them,
+	if cache is non-existent/unusable */
+     *id = lid;
+     return KRB5_OK;
+}
+
+/*
+ * Effects:
+ * Prepares for a sequential search of the credentials cache.
+ * Returns and krb5_cc_cursor to be used with krb5_fcc_next_cred and
+ * krb5_fcc_end_seq_get.
+ *
+ * If the cache is modified between the time of this call and the time
+ * of the final krb5_fcc_end_seq_get, the results are undefined.
+ *
+ * Errors:
+ * KRB5_CC_NOMEM
+ * system errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_start_seq_get(krb5_context context, krb5_ccache id,
+		       krb5_cc_cursor *cursor)
+{
+     krb5_fcc_cursor *fcursor;
+     krb5_error_code kret = KRB5_OK;
+     krb5_fcc_data *data = (krb5_fcc_data *)id->data;
+
+     kret = k5_mutex_lock(&data->lock);
+     if (kret)
+	 return kret;
+
+     fcursor = (krb5_fcc_cursor *) malloc(sizeof(krb5_fcc_cursor));
+     if (fcursor == NULL) {
+	 k5_mutex_unlock(&data->lock);
+	 return KRB5_CC_NOMEM;
+     }
+     if (OPENCLOSE(id)) {
+          kret = krb5_fcc_open_file(context, id, FCC_OPEN_RDONLY);
+          if (kret) {
+              krb5_xfree(fcursor);
+	      k5_mutex_unlock(&data->lock);
+              return kret;
+          }
+     }
+
+     /* Make sure we start reading right after the primary principal */
+     kret = krb5_fcc_skip_header(context, id);
+     if (kret) goto done;
+     kret = krb5_fcc_skip_principal(context, id);
+     if (kret) goto done;
+
+     fcursor->pos = fcc_lseek(data, (off_t) 0, SEEK_CUR);
+     *cursor = (krb5_cc_cursor) fcursor;
+
+done:
+     MAYBE_CLOSE(context, id, kret);
+     k5_mutex_unlock(&data->lock);
+     return kret;
+}
+
+
+/*
+ * Requires:
+ * cursor is a krb5_cc_cursor originally obtained from
+ * krb5_fcc_start_seq_get.
+ *
+ * Modifes:
+ * cursor, creds
+ * 
+ * Effects:
+ * Fills in creds with the "next" credentals structure from the cache
+ * id.  The actual order the creds are returned in is arbitrary.
+ * Space is allocated for the variable length fields in the
+ * credentials structure, so the object returned must be passed to
+ * krb5_destroy_credential.
+ *
+ * The cursor is updated for the next call to krb5_fcc_next_cred.
+ *
+ * Errors:
+ * system errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
+		   krb5_creds *creds)
+{
+#define TCHECK(ret) if (ret != KRB5_OK) goto lose;
+     krb5_error_code kret;
+     krb5_fcc_cursor *fcursor;
+     krb5_int32 int32;
+     krb5_octet octet;
+     krb5_fcc_data *d = (krb5_fcc_data *) id->data;
+
+     kret = k5_mutex_lock(&d->lock);
+     if (kret)
+	 return kret;
+
+     memset((char *)creds, 0, sizeof(*creds));
+     MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
+     fcursor = (krb5_fcc_cursor *) *cursor;
+
+     kret = (fcc_lseek(d, fcursor->pos, SEEK_SET) == (off_t) -1);
+     if (kret) {
+	 kret = krb5_fcc_interpret(context, errno);
+	 MAYBE_CLOSE(context, id, kret);
+	 k5_mutex_unlock(&d->lock);
+	 return kret;
+     }
+
+     kret = krb5_fcc_read_principal(context, id, &creds->client);
+     TCHECK(kret);
+     kret = krb5_fcc_read_principal(context, id, &creds->server);
+     TCHECK(kret);
+     kret = krb5_fcc_read_keyblock(context, id, &creds->keyblock);
+     TCHECK(kret);
+     kret = krb5_fcc_read_times(context, id, &creds->times);
+     TCHECK(kret);
+     kret = krb5_fcc_read_octet(context, id, &octet);
+     TCHECK(kret);
+     creds->is_skey = octet;
+     kret = krb5_fcc_read_int32(context, id, &int32);
+     TCHECK(kret);
+     creds->ticket_flags = int32;
+     kret = krb5_fcc_read_addrs(context, id, &creds->addresses);
+     TCHECK(kret);
+     kret = krb5_fcc_read_authdata(context, id, &creds->authdata);
+     TCHECK(kret);
+     kret = krb5_fcc_read_data(context, id, &creds->ticket);
+     TCHECK(kret);
+     kret = krb5_fcc_read_data(context, id, &creds->second_ticket);
+     TCHECK(kret);
+     
+     fcursor->pos = fcc_lseek(d, (off_t) 0, SEEK_CUR);
+     cursor = (krb5_cc_cursor *) fcursor;
+
+lose:
+     MAYBE_CLOSE (context, id, kret);
+     k5_mutex_unlock(&d->lock);
+     if (kret != KRB5_OK)
+	 krb5_free_cred_contents(context, creds);
+     return kret;
+}
+
+/*
+ * Requires:
+ * cursor is a krb5_cc_cursor originally obtained from
+ * krb5_fcc_start_seq_get.
+ *
+ * Modifies:
+ * id, cursor
+ *
+ * Effects:
+ * Finishes sequential processing of the file credentials ccache id,
+ * and invalidates the cursor (it must never be used after this call).
+ */
+/* ARGSUSED */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
+{
+     /* We don't do anything with the file cache itself, so
+	no need to lock anything.  */
+
+     /* don't close; it may be left open by the caller,
+        and if not, fcc_start_seq_get and/or fcc_next_cred will do the
+        MAYBE_CLOSE.
+     MAYBE_CLOSE(context, id, kret); */
+     krb5_xfree((krb5_fcc_cursor *) *cursor);
+     return 0;
+}
+
+
+/*
+ * Effects:
+ * Creates a new file cred cache whose name is guaranteed to be
+ * unique.  The name begins with the string TKT_ROOT (from fcc.h).
+ * The cache is not opened, but the new filename is reserved.
+ *  
+ * Returns:
+ * The filled in krb5_ccache id.
+ *
+ * Errors:
+ * KRB5_CC_NOMEM - there was insufficient memory to allocate the
+ * 		krb5_ccache.  id is undefined.
+ * system errors (from open)
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_generate_new (krb5_context context, krb5_ccache *id)
+{
+     krb5_ccache lid;
+     int ret;
+     krb5_error_code    retcode = 0;
+     char scratch[sizeof(TKT_ROOT)+6+1]; /* +6 for the scratch part, +1 for
+					    NUL */
+     krb5_fcc_data *data;
+     
+     /* Allocate memory */
+     lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
+     if (lid == NULL)
+	  return KRB5_CC_NOMEM;
+
+     lid->ops = &krb5_fcc_ops;
+
+     (void) strcpy(scratch, TKT_ROOT);
+     (void) strcat(scratch, "XXXXXX");
+#ifdef HAVE_MKSTEMP
+     ret = mkstemp(scratch);
+     if (ret == -1) {
+	 return krb5_fcc_interpret(context, errno);
+     } else close(ret);
+#else /*HAVE_MKSTEMP*/
+     mktemp(scratch);
+#endif
+
+     lid->data = (krb5_pointer) malloc(sizeof(krb5_fcc_data));
+     if (lid->data == NULL) {
+	  krb5_xfree(lid);
+	  return KRB5_CC_NOMEM;
+     }
+
+     ((krb5_fcc_data *) lid->data)->filename = (char *)
+	  malloc(strlen(scratch) + 1);
+     if (((krb5_fcc_data *) lid->data)->filename == NULL) {
+	  krb5_xfree(((krb5_fcc_data *) lid->data));
+	  krb5_xfree(lid);
+	  return KRB5_CC_NOMEM;
+     }
+
+     /*
+      * The file is initially closed at the end of this call...
+      */
+     ((krb5_fcc_data *) lid->data)->flags = 0;
+     ((krb5_fcc_data *) lid->data)->file = -1;
+     ((krb5_fcc_data *) lid->data)->valid_bytes = 0;
+     data = (krb5_fcc_data *) lid->data;
+
+     retcode = k5_mutex_init(&data->lock);
+     if (retcode)
+	 goto err_out;
+
+     /* Set up the filename */
+     strcpy(((krb5_fcc_data *) lid->data)->filename, scratch);
+
+     /* Make sure the file name is reserved */
+     ret = THREEPARAMOPEN(((krb5_fcc_data *) lid->data)->filename,
+                O_CREAT | O_EXCL | O_WRONLY | O_BINARY, 0);
+     if (ret == -1) {
+	  retcode = krb5_fcc_interpret(context, errno);
+          goto err_out;
+     } else {
+          krb5_int16 fcc_fvno = htons(context->fcc_default_format);
+          krb5_int16 fcc_flen = 0;
+          int errsave, cnt;
+
+          /* Ignore user's umask, set mode = 0600 */
+#ifndef HAVE_FCHMOD
+#ifdef HAVE_CHMOD
+          chmod(((krb5_fcc_data *) lid->data)->filename, S_IRUSR | S_IWUSR);
+#endif
+#else
+          fchmod(ret, S_IRUSR | S_IWUSR);
+#endif
+          if ((cnt = write(ret, (char *)&fcc_fvno, sizeof(fcc_fvno)))
+              != sizeof(fcc_fvno)) {
+              errsave = errno;
+              (void) close(ret);
+              (void) unlink(((krb5_fcc_data *) lid->data)->filename);
+              retcode = (cnt == -1) ? krb5_fcc_interpret(context, errsave) : KRB5_CC_IO;
+              goto err_out;
+	  }
+	  /* For version 4 we save a length for the rest of the header */
+          if (context->fcc_default_format == KRB5_FCC_FVNO_4) {
+            if ((cnt = write(ret, (char *)&fcc_flen, sizeof(fcc_flen)))
+                != sizeof(fcc_flen)) {
+                errsave = errno;
+                (void) close(ret);
+                (void) unlink(((krb5_fcc_data *) lid->data)->filename);
+                retcode = (cnt == -1) ? krb5_fcc_interpret(context, errsave) : KRB5_CC_IO;
+                goto err_out;
+	    }
+	  }
+          if (close(ret) == -1) {
+              errsave = errno;
+              (void) unlink(((krb5_fcc_data *) lid->data)->filename);
+              retcode = krb5_fcc_interpret(context, errsave);
+              goto err_out;
+	  }
+	  *id = lid;
+          /* default to open/close on every trn - otherwise destroy 
+             will get as to state confused */
+          ((krb5_fcc_data *) lid->data)->flags = KRB5_TC_OPENCLOSE;
+	  krb5_change_cache ();
+	  return KRB5_OK;
+     }
+
+err_out:
+     krb5_xfree(((krb5_fcc_data *) lid->data)->filename);
+     krb5_xfree(((krb5_fcc_data *) lid->data));
+     krb5_xfree(lid);
+     return retcode;
+}
+
+/*
+ * Requires:
+ * id is a file credential cache
+ * 
+ * Returns:
+ * The name of the file cred cache id.
+ */
+static const char * KRB5_CALLCONV
+krb5_fcc_get_name (krb5_context context, krb5_ccache id)
+{
+     return (char *) ((krb5_fcc_data *) id->data)->filename;
+}
+
+/*
+ * Modifies:
+ * id, princ
+ *
+ * Effects:
+ * Retrieves the primary principal from id, as set with
+ * krb5_fcc_initialize.  The principal is returned is allocated
+ * storage that must be freed by the caller via krb5_free_principal.
+ *
+ * Errors:
+ * system errors
+ * KRB5_CC_NOMEM
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
+{
+     krb5_error_code kret = KRB5_OK;
+
+     kret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+     if (kret)
+	 return kret;
+
+     MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
+     
+     /* make sure we're beyond the header */
+     kret = krb5_fcc_skip_header(context, id);
+     if (kret) goto done;
+     kret = krb5_fcc_read_principal(context, id, princ);
+
+done:
+     MAYBE_CLOSE(context, id, kret);
+     k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+     return kret;
+}
+
+     
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds)
+{
+    return krb5_cc_retrieve_cred_default (context, id, whichfields,
+					  mcreds, creds);
+}
+
+
+/*
+ * Modifies:
+ * the file cache
+ *
+ * Effects:
+ * stores creds in the file cred cache
+ *
+ * Errors:
+ * system errors
+ * storage failure errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
+{
+#define TCHECK(ret) if (ret != KRB5_OK) goto lose;
+     krb5_error_code ret;
+
+     ret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+     if (ret)
+	 return ret;
+
+     /* Make sure we are writing to the end of the file */
+     MAYBE_OPEN(context, id, FCC_OPEN_RDWR);
+
+     /* Make sure we are writing to the end of the file */
+     ret = fcc_lseek((krb5_fcc_data *) id->data, (off_t) 0, SEEK_END);
+     if (ret < 0) {
+          MAYBE_CLOSE_IGNORE(context, id);
+	  k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+	  return krb5_fcc_interpret(context, errno);
+     }
+
+     ret = krb5_fcc_store_principal(context, id, creds->client);
+     TCHECK(ret);
+     ret = krb5_fcc_store_principal(context, id, creds->server);
+     TCHECK(ret);
+     ret = krb5_fcc_store_keyblock(context, id, &creds->keyblock);
+     TCHECK(ret);
+     ret = krb5_fcc_store_times(context, id, &creds->times);
+     TCHECK(ret);
+     ret = krb5_fcc_store_octet(context, id, (krb5_int32) creds->is_skey);
+     TCHECK(ret);
+     ret = krb5_fcc_store_int32(context, id, creds->ticket_flags);
+     TCHECK(ret);
+     ret = krb5_fcc_store_addrs(context, id, creds->addresses);
+     TCHECK(ret);
+     ret = krb5_fcc_store_authdata(context, id, creds->authdata);
+     TCHECK(ret);
+     ret = krb5_fcc_store_data(context, id, &creds->ticket);
+     TCHECK(ret);
+     ret = krb5_fcc_store_data(context, id, &creds->second_ticket);
+     TCHECK(ret);
+
+lose:
+     MAYBE_CLOSE(context, id, ret);
+     k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+     krb5_change_cache ();
+     return ret;
+#undef TCHECK
+}
+
+/* 
+ * Non-functional stub implementation for krb5_fcc_remove
+ * 
+ * Errors:
+ *    KRB5_CC_NOSUPP - not implemented
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags,
+                     krb5_creds *creds)
+{
+    return KRB5_CC_NOSUPP;
+}
+
+/*
+ * Requires:
+ * id is a cred cache returned by krb5_fcc_resolve or
+ * krb5_fcc_generate_new, but has not been opened by krb5_fcc_initialize.
+ *
+ * Modifies:
+ * id
+ * 
+ * Effects:
+ * Sets the operational flags of id to flags.
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
+{
+    krb5_error_code ret = KRB5_OK;
+
+    ret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+    if (ret)
+	return ret;
+
+    /* XXX This should check for illegal combinations, if any.. */
+    if (flags & KRB5_TC_OPENCLOSE) {
+	/* asking to turn on OPENCLOSE mode */
+	if (!OPENCLOSE(id)
+	    /* XXX Is this test necessary? */
+	    && ((krb5_fcc_data *) id->data)->file != NO_FILE)
+            (void) krb5_fcc_close_file (context, ((krb5_fcc_data *) id->data));
+    } else {
+	/* asking to turn off OPENCLOSE mode, meaning it must be
+	   left open.  We open if it's not yet open */
+        MAYBE_OPEN(context, id, FCC_OPEN_RDONLY);
+    }
+
+    ((krb5_fcc_data *) id->data)->flags = flags;
+    k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+    return ret;
+}
+
+/*
+ * Requires:
+ * id is a cred cache returned by krb5_fcc_resolve or
+ * krb5_fcc_generate_new, but has not been opened by krb5_fcc_initialize.
+ *
+ * Modifies:
+ * id (mutex only; temporary)
+ * 
+ * Effects:
+ * Returns the operational flags of id.
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_fcc_get_flags(krb5_context context, krb5_ccache id, krb5_flags *flags)
+{
+    krb5_error_code ret = KRB5_OK;
+
+    ret = k5_mutex_lock(&((krb5_fcc_data *) id->data)->lock);
+    if (ret)
+	return ret;
+    *flags = ((krb5_fcc_data *) id->data)->flags;
+    k5_mutex_unlock(&((krb5_fcc_data *) id->data)->lock);
+    return ret;
+}
+
+
+static krb5_error_code
+krb5_fcc_interpret(krb5_context context, int errnum)
+{
+    register krb5_error_code retval;
+    switch (errnum) {
+    case ENOENT:
+	retval = KRB5_FCC_NOFILE;
+	break;
+    case EPERM:
+    case EACCES:
+#ifdef EISDIR
+    case EISDIR:                        /* Mac doesn't have EISDIR */
+#endif
+    case ENOTDIR:
+#ifdef ELOOP
+    case ELOOP:                         /* Bad symlink is like no file. */
+#endif
+#ifdef ETXTBSY
+    case ETXTBSY:
+#endif
+    case EBUSY:
+    case EROFS:
+	retval = KRB5_FCC_PERM;
+	break;
+    case EINVAL:
+    case EEXIST:			/* XXX */
+    case EFAULT:
+    case EBADF:
+#ifdef ENAMETOOLONG
+    case ENAMETOOLONG:
+#endif
+#ifdef EWOULDBLOCK
+    case EWOULDBLOCK:
+#endif
+	retval = KRB5_FCC_INTERNAL;
+	break;
+#ifdef EDQUOT
+    case EDQUOT:
+#endif
+    case ENOSPC:
+    case EIO:
+    case ENFILE:
+    case EMFILE:
+    case ENXIO:
+    default:
+	retval = KRB5_CC_IO;		/* XXX */
+    }
+    return retval;
+}
+
+const krb5_cc_ops krb5_fcc_ops = {
+     0,
+     "FILE",
+     krb5_fcc_get_name,
+     krb5_fcc_resolve,
+     krb5_fcc_generate_new,
+     krb5_fcc_initialize,
+     krb5_fcc_destroy,
+     krb5_fcc_close,
+     krb5_fcc_store,
+     krb5_fcc_retrieve,
+     krb5_fcc_get_principal,
+     krb5_fcc_start_seq_get,
+     krb5_fcc_next_cred,
+     krb5_fcc_end_seq_get,
+     krb5_fcc_remove_cred,
+     krb5_fcc_set_flags,
+     krb5_fcc_get_flags,
+};
+
+#if defined(_WIN32)
+/*
+ * krb5_change_cache should be called after the cache changes.
+ * A notification message is is posted out to all top level
+ * windows so that they may recheck the cache based on the
+ * changes made.  We register a unique message type with which
+ * we'll communicate to all other processes. 
+ */
+
+krb5_error_code 
+krb5_change_cache (void) {
+
+    PostMessage(HWND_BROADCAST, krb5_get_notification_message(), 0, 0);
+
+    return 0;
+}
+
+unsigned int KRB5_CALLCONV
+krb5_get_notification_message (void) {
+    static unsigned int message = 0;
+
+    if (message == 0)
+        message = RegisterWindowMessage(WM_KERBEROS5_CHANGED);
+
+    return message;
+}
+#else /* _WIN32 */
+
+krb5_error_code
+krb5_change_cache (void)
+{
+    return 0;
+}
+unsigned int
+krb5_get_notification_message (void)
+{
+    return 0;
+}
+
+#endif /* _WIN32 */
+
+const krb5_cc_ops krb5_cc_file_ops = {
+     0,
+     "FILE",
+     krb5_fcc_get_name,
+     krb5_fcc_resolve,
+     krb5_fcc_generate_new,
+     krb5_fcc_initialize,
+     krb5_fcc_destroy,
+     krb5_fcc_close,
+     krb5_fcc_store,
+     krb5_fcc_retrieve,
+     krb5_fcc_get_principal,
+     krb5_fcc_start_seq_get,
+     krb5_fcc_next_cred,
+     krb5_fcc_end_seq_get,
+     krb5_fcc_remove_cred,
+     krb5_fcc_set_flags,
+     krb5_fcc_get_flags,
+};
diff --git a/mechglue/src/lib/krb5/ccache/cc_memory.c b/mechglue/src/lib/krb5/ccache/cc_memory.c
new file mode 100644
index 000000000..1417aabb7
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/cc_memory.c
@@ -0,0 +1,617 @@
+/*
+ * lib/krb5/ccache/cc_memory.c
+ *
+ * Copyright 1990,1991,2000,2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * implementation of memory-based credentials cache
+ */
+#include "k5-int.h"
+#include <errno.h>
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_close
+	(krb5_context, krb5_ccache id );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_destroy 
+	(krb5_context, krb5_ccache id );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_end_seq_get 
+	(krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_generate_new 
+	(krb5_context, krb5_ccache *id );
+
+static const char * KRB5_CALLCONV krb5_mcc_get_name 
+	(krb5_context, krb5_ccache id );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_get_principal 
+	(krb5_context, krb5_ccache id , krb5_principal *princ );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_initialize 
+	(krb5_context, krb5_ccache id , krb5_principal princ );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_next_cred 
+	(krb5_context, 
+		   krb5_ccache id , 
+		   krb5_cc_cursor *cursor , 
+		   krb5_creds *creds );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_resolve 
+	(krb5_context, krb5_ccache *id , const char *residual );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_retrieve 
+	(krb5_context, 
+		   krb5_ccache id , 
+		   krb5_flags whichfields , 
+		   krb5_creds *mcreds , 
+		   krb5_creds *creds );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_start_seq_get 
+	(krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_store 
+	(krb5_context, krb5_ccache id , krb5_creds *creds );
+
+static krb5_error_code KRB5_CALLCONV krb5_mcc_set_flags 
+	(krb5_context, krb5_ccache id , krb5_flags flags );
+
+extern const krb5_cc_ops krb5_mcc_ops;
+extern krb5_error_code krb5_change_cache (void);
+
+#define KRB5_OK 0
+
+typedef struct _krb5_mcc_link {
+    struct _krb5_mcc_link *next;
+    krb5_creds *creds;
+} krb5_mcc_link, *krb5_mcc_cursor;
+
+typedef struct _krb5_mcc_data {
+    char *name;
+    k5_mutex_t lock;
+    krb5_principal prin;
+    krb5_mcc_cursor link;
+} krb5_mcc_data;
+
+typedef struct krb5_mcc_list_node {
+    struct krb5_mcc_list_node *next;
+    krb5_mcc_data *cache;
+} krb5_mcc_list_node;
+
+k5_mutex_t krb5int_mcc_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+static krb5_mcc_list_node *mcc_head = 0;
+
+/*
+ * Modifies:
+ * id
+ *
+ * Effects:
+ * Creates/refreshes the file cred cache id.  If the cache exists, its
+ * contents are destroyed.
+ *
+ * Errors:
+ * system errors
+ * permission errors
+ */
+static void krb5_mcc_free (krb5_context context, krb5_ccache id);
+
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
+{
+    krb5_error_code ret; 
+
+    krb5_mcc_free(context, id);
+    ret = krb5_copy_principal(context, princ,
+			      &((krb5_mcc_data *)id->data)->prin);
+    if (ret == KRB5_OK)
+        krb5_change_cache();
+    return ret;
+}
+
+/*
+ * Modifies:
+ * id
+ *
+ * Effects:
+ * Closes the file cache, invalidates the id, and frees any resources
+ * associated with the cache.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_close(krb5_context context, krb5_ccache id)
+{
+     krb5_xfree(id);
+     return KRB5_OK;
+}
+
+void
+krb5_mcc_free(krb5_context context, krb5_ccache id)
+{
+    krb5_mcc_cursor curr,next;
+    krb5_mcc_data *d;
+
+    d = (krb5_mcc_data *) id->data;
+    for (curr = d->link; curr;) {
+	krb5_free_creds(context, curr->creds);
+	next = curr->next;
+	krb5_xfree(curr);
+	curr = next;
+    }
+    d->link = NULL;
+    krb5_free_principal(context, d->prin);
+}
+
+/*
+ * Effects:
+ * Destroys the contents of id.
+ *
+ * Errors:
+ * none
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_destroy(krb5_context context, krb5_ccache id)
+{
+    krb5_mcc_list_node **curr, *node;
+    krb5_mcc_data *d;
+    krb5_error_code err;
+
+    err = k5_mutex_lock(&krb5int_mcc_mutex);
+    if (err)
+	return err;
+
+    d = (krb5_mcc_data *)id->data;
+    for (curr = &mcc_head; *curr; curr = &(*curr)->next) {
+	if ((*curr)->cache == d) {
+	    node = *curr;
+	    *curr = node->next;
+	    free(node);
+	    break;
+	}
+    }
+    k5_mutex_unlock(&krb5int_mcc_mutex);
+
+    krb5_mcc_free(context, id);
+    krb5_xfree(d->name);
+    k5_mutex_destroy(&d->lock);
+    krb5_xfree(d); 
+    krb5_xfree(id);
+
+    krb5_change_cache ();
+    return KRB5_OK;
+}
+
+/*
+ * Requires:
+ * residual is a legal path name, and a null-terminated string
+ *
+ * Modifies:
+ * id
+ * 
+ * Effects:
+ * creates a file-based cred cache that will reside in the file
+ * residual.  The cache is not opened, but the filename is reserved.
+ * 
+ * Returns:
+ * A filled in krb5_ccache structure "id".
+ *
+ * Errors:
+ * KRB5_CC_NOMEM - there was insufficient memory to allocate the
+ *              krb5_ccache.  id is undefined.
+ * permission errors
+ */
+static krb5_error_code new_mcc_data (const char *, krb5_mcc_data **);
+
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
+{
+    krb5_ccache lid;
+    krb5_mcc_list_node *ptr;
+    krb5_error_code err;
+    krb5_mcc_data *d;
+
+    lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
+    if (lid == NULL)
+	return KRB5_CC_NOMEM;
+
+    lid->ops = &krb5_mcc_ops;
+
+    err = k5_mutex_lock(&krb5int_mcc_mutex);
+    if (err)
+	return err;
+    for (ptr = mcc_head; ptr; ptr=ptr->next)
+	if (!strcmp(ptr->cache->name, residual))
+	    break;
+    if (ptr)
+	d = ptr->cache;
+    else {
+	err = new_mcc_data(residual, &d);
+	if (err) {
+	    k5_mutex_unlock(&krb5int_mcc_mutex);
+	    krb5_xfree(lid);
+	    return err;
+	}
+    }
+    k5_mutex_unlock(&krb5int_mcc_mutex);
+    lid->data = d;
+    *id = lid; 
+    return KRB5_OK;
+}
+
+/*
+ * Effects:
+ * Prepares for a sequential search of the credentials cache.
+ * Returns a krb5_cc_cursor to be used with krb5_mcc_next_cred and
+ * krb5_mcc_end_seq_get.
+ *
+ * If the cache is modified between the time of this call and the time
+ * of the final krb5_mcc_end_seq_get, the results are undefined.
+ *
+ * Errors:
+ * KRB5_CC_NOMEM
+ * system errors
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_start_seq_get(krb5_context context, krb5_ccache id,
+		       krb5_cc_cursor *cursor)
+{
+     krb5_mcc_cursor mcursor;
+     krb5_error_code err;
+     krb5_mcc_data *d;
+
+     d = id->data;
+     err = k5_mutex_lock(&d->lock);
+     if (err)
+	 return err;
+     mcursor = d->link;
+     k5_mutex_unlock(&d->lock);
+     *cursor = (krb5_cc_cursor) mcursor;
+     return KRB5_OK;
+}
+
+/*
+ * Requires:
+ * cursor is a krb5_cc_cursor originally obtained from
+ * krb5_mcc_start_seq_get.
+ *
+ * Modifes:
+ * cursor, creds
+ * 
+ * Effects:
+ * Fills in creds with the "next" credentals structure from the cache
+ * id.  The actual order the creds are returned in is arbitrary.
+ * Space is allocated for the variable length fields in the
+ * credentials structure, so the object returned must be passed to
+ * krb5_destroy_credential.
+ *
+ * The cursor is updated for the next call to krb5_mcc_next_cred.
+ *
+ * Errors:
+ * system errors
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_next_cred(krb5_context context, krb5_ccache id,
+		   krb5_cc_cursor *cursor, krb5_creds *creds)
+{
+     krb5_mcc_cursor mcursor;
+     krb5_error_code retval;
+     krb5_data *scratch;
+
+     /* Once the node in the linked list is created, it's never
+	modified, so we don't need to worry about locking here.  (Note
+	that we don't support _remove_cred.)  */
+     mcursor = (krb5_mcc_cursor) *cursor;
+     if (mcursor == NULL)
+	return KRB5_CC_END;
+     memset(creds, 0, sizeof(krb5_creds));     
+     if (mcursor->creds) {
+	*creds = *mcursor->creds;
+	retval = krb5_copy_principal(context, mcursor->creds->client, &creds->client);
+	if (retval)
+		return retval;
+	retval = krb5_copy_principal(context, mcursor->creds->server,
+		&creds->server);
+	if (retval)
+		goto cleanclient;
+	retval = krb5_copy_keyblock_contents(context, &mcursor->creds->keyblock,
+		&creds->keyblock);
+	if (retval)
+		goto cleanserver;
+	retval = krb5_copy_addresses(context, mcursor->creds->addresses,
+		&creds->addresses);
+	if (retval)
+		goto cleanblock;
+	retval = krb5_copy_data(context, &mcursor->creds->ticket, &scratch);
+	if (retval)
+		goto cleanaddrs;
+	creds->ticket = *scratch;
+	krb5_xfree(scratch);
+	retval = krb5_copy_data(context, &mcursor->creds->second_ticket, &scratch);
+	if (retval)
+		goto cleanticket;
+	creds->second_ticket = *scratch;
+	krb5_xfree(scratch);
+	retval = krb5_copy_authdata(context, mcursor->creds->authdata,
+		&creds->authdata);
+	if (retval)
+		goto clearticket;
+     }
+     *cursor = (krb5_cc_cursor)mcursor->next;
+     return KRB5_OK;
+
+clearticket:
+	memset(creds->ticket.data,0, (unsigned) creds->ticket.length);
+cleanticket:
+	krb5_xfree(creds->ticket.data);
+cleanaddrs:
+	krb5_free_addresses(context, creds->addresses);
+cleanblock:
+	krb5_xfree(creds->keyblock.contents);
+cleanserver:
+	krb5_free_principal(context, creds->server);
+cleanclient:
+	krb5_free_principal(context, creds->client);
+	return retval;
+}
+
+/*
+ * Requires:
+ * cursor is a krb5_cc_cursor originally obtained from
+ * krb5_mcc_start_seq_get.
+ *
+ * Modifies:
+ * id, cursor
+ *
+ * Effects:
+ * Finishes sequential processing of the file credentials ccache id,
+ * and invalidates the cursor (it must never be used after this call).
+ */
+/* ARGSUSED */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
+{
+     *cursor = 0L;
+     return KRB5_OK;
+}
+
+/* Utility routine: Creates the back-end data for a memory cache, and
+   threads it into the global linked list.
+
+   Call with the global list lock held.  */
+static krb5_error_code
+new_mcc_data (const char *name, krb5_mcc_data **dataptr)
+{
+    krb5_error_code err;
+    krb5_mcc_data *d;
+    krb5_mcc_list_node *n;
+
+    d = malloc(sizeof(krb5_mcc_data));
+    if (d == NULL)
+	return KRB5_CC_NOMEM;
+
+    err = k5_mutex_init(&d->lock);
+    if (err) {
+	krb5_xfree(d);
+	return err;
+    }
+
+    d->name = malloc(strlen(name) + 1);
+    if (d->name == NULL) {
+	k5_mutex_destroy(&d->lock);
+	krb5_xfree(d);
+	return KRB5_CC_NOMEM;
+    }
+    d->link = NULL;
+    d->prin = NULL;
+
+    /* Set up the filename */
+    strcpy(d->name, name);
+
+    n = malloc(sizeof(krb5_mcc_list_node));
+    if (n == NULL) {
+	free(d->name);
+	k5_mutex_destroy(&d->lock);
+	free(d);
+	return KRB5_CC_NOMEM;
+    }
+
+    n->cache = d;
+    n->next = mcc_head;
+    mcc_head = n;
+
+    *dataptr = d;
+    return 0;
+}
+
+/*
+ * Effects:
+ * Creates a new file cred cache whose name is guaranteed to be
+ * unique.  The name begins with the string TKT_ROOT (from mcc.h).
+ * The cache is not opened, but the new filename is reserved.
+ *  
+ * Returns:
+ * The filled in krb5_ccache id.
+ *
+ * Errors:
+ * KRB5_CC_NOMEM - there was insufficient memory to allocate the
+ *              krb5_ccache.  id is undefined.
+ * system errors (from open)
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
+{
+    krb5_ccache lid;
+    char scratch[6+1]; /* 6 for the scratch part, +1 for NUL */
+    krb5_error_code err;
+    krb5_mcc_data *d;
+
+    /* Allocate memory */
+    lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
+    if (lid == NULL)
+	return KRB5_CC_NOMEM;
+
+    lid->ops = &krb5_mcc_ops;
+
+    (void) strcpy(scratch, "XXXXXX");
+    mktemp(scratch);
+
+    err = k5_mutex_lock(&krb5int_mcc_mutex);
+    if (err) {
+	free(lid);
+	return err;
+    }
+    err = new_mcc_data(scratch, &d);
+    k5_mutex_unlock(&krb5int_mcc_mutex);
+    if (err) {
+	krb5_xfree(lid);
+	return err;
+    }
+    lid->data = d;
+    krb5_change_cache ();
+    return KRB5_OK;
+}
+
+/*
+ * Requires:
+ * id is a file credential cache
+ * 
+ * Returns:
+ * The name of the file cred cache id.
+ */
+const char * KRB5_CALLCONV
+krb5_mcc_get_name (krb5_context context, krb5_ccache id)
+{
+     return (char *) ((krb5_mcc_data *) id->data)->name;
+}
+
+/*
+ * Modifies:
+ * id, princ
+ *
+ * Effects:
+ * Retrieves the primary principal from id, as set with
+ * krb5_mcc_initialize.  The principal is returned is allocated
+ * storage that must be freed by the caller via krb5_free_principal.
+ *
+ * Errors:
+ * system errors
+ * KRB5_CC_NOMEM
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
+{
+     krb5_mcc_data *ptr = (krb5_mcc_data *)id->data;
+     if (!ptr->prin) {
+        *princ = 0L;
+        return KRB5_FCC_NOFILE;
+     }
+     return krb5_copy_principal(context, ptr->prin, princ);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields,
+		  krb5_creds *mcreds, krb5_creds *creds)
+{
+    return krb5_cc_retrieve_cred_default (context, id, whichfields,
+					  mcreds, creds);
+}
+
+/* 
+ * Non-functional stub implementation for krb5_mcc_remove
+ * 
+ * Errors:
+ *    KRB5_CC_NOSUPP - not implemented
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_mcc_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags,
+                     krb5_creds *creds)
+{
+    return KRB5_CC_NOSUPP;
+}
+
+
+/*
+ * Requires:
+ * id is a cred cache returned by krb5_mcc_resolve or
+ * krb5_mcc_generate_new, but has not been opened by krb5_mcc_initialize.
+ *
+ * Modifies:
+ * id
+ * 
+ * Effects:
+ * Sets the operational flags of id to flags.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
+{
+    return KRB5_OK;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_get_flags(krb5_context context, krb5_ccache id, krb5_flags *flags)
+{
+    *flags = 0;
+    return KRB5_OK;
+}
+
+/* store: Save away creds in the ccache.  */
+krb5_error_code KRB5_CALLCONV
+krb5_mcc_store(krb5_context ctx, krb5_ccache id, krb5_creds *creds)
+{
+    krb5_error_code err;
+    krb5_mcc_link *new_node;
+    krb5_mcc_data *mptr = (krb5_mcc_data *)id->data;
+
+    new_node = malloc(sizeof(krb5_mcc_link));
+    if (new_node == NULL)
+	return errno;
+    err = krb5_copy_creds(ctx, creds, &new_node->creds);
+    if (err) {
+	free(new_node);
+	return err;
+    }
+    err = k5_mutex_lock(&mptr->lock);
+    if (err)
+	return err;
+    new_node->next = mptr->link;
+    mptr->link = new_node;
+    k5_mutex_unlock(&mptr->lock);
+    return 0;
+}
+
+const krb5_cc_ops krb5_mcc_ops = {
+     0,
+     "MEMORY",
+     krb5_mcc_get_name,
+     krb5_mcc_resolve,
+     krb5_mcc_generate_new,
+     krb5_mcc_initialize,
+     krb5_mcc_destroy,
+     krb5_mcc_close,
+     krb5_mcc_store,
+     krb5_mcc_retrieve,
+     krb5_mcc_get_principal,
+     krb5_mcc_start_seq_get,
+     krb5_mcc_next_cred,
+     krb5_mcc_end_seq_get,
+     krb5_mcc_remove_cred,
+     krb5_mcc_set_flags,
+     krb5_mcc_get_flags,
+};
diff --git a/mechglue/src/lib/krb5/ccache/cc_mslsa.c b/mechglue/src/lib/krb5/ccache/cc_mslsa.c
new file mode 100644
index 000000000..6a75aef86
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/cc_mslsa.c
@@ -0,0 +1,2613 @@
+/*
+ * lib/krb5/ccache/cc_mslsa.c
+ *
+ * Copyright 2003,2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Copyright 2000 by Carnegie Mellon University
+ *
+ * All Rights Reserved
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Carnegie Mellon
+ * University not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.
+ * 
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
+ * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Implementation of microsoft windows lsa credentials cache
+ */
+
+#ifdef _WIN32
+#define UNICODE
+#define _UNICODE
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "cc-int.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <conio.h>
+#include <time.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <ntsecapi.h>
+#include <ntstatus.h>
+
+#ifdef COMMENT
+/* The following two features can only be built using a version of the
+ * Microsoft Windows Platform SDK which is not currently public.  These
+ * features will be disabled until the SDK is made publicly available.
+ */
+#define KERB_SUBMIT_TICKET 1
+#define HAVE_CACHE_INFO_EX2 1
+#endif
+
+#define MAX_MSG_SIZE 256
+#define MAX_MSPRINC_SIZE 1024
+
+/* THREAD SAFETY 
+ * The functions is_windows_2000(), is_windows_xp(), 
+ * does_retrieve_ticket_cache_ticket() and does_query_ticket_cache_ex2() 
+ * contain static variables to cache the responses of the tests being 
+ * performed.  There is no harm in the test being performed more than 
+ * once since the result will always be the same.
+ */
+
+static BOOL 
+is_windows_2000 (void)
+{
+   static BOOL fChecked = FALSE;
+   static BOOL fIsWin2K = FALSE;
+
+   if (!fChecked)
+   {
+       OSVERSIONINFO Version;
+
+       memset (&Version, 0x00, sizeof(Version));
+       Version.dwOSVersionInfoSize = sizeof(Version);
+
+       if (GetVersionEx (&Version))
+       {
+           if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+                Version.dwMajorVersion >= 5)
+               fIsWin2K = TRUE;
+       }
+       fChecked = TRUE;
+   }
+
+   return fIsWin2K;
+}
+
+static BOOL 
+is_windows_xp (void)
+{
+   static BOOL fChecked = FALSE;
+   static BOOL fIsWinXP = FALSE;
+
+   if (!fChecked)
+   {
+       OSVERSIONINFO Version;
+
+       memset (&Version, 0x00, sizeof(Version));
+       Version.dwOSVersionInfoSize = sizeof(Version);
+
+       if (GetVersionEx (&Version))
+       {
+           if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+                (Version.dwMajorVersion > 5 ||
+                 Version.dwMajorVersion == 5 && Version.dwMinorVersion >= 1) )
+               fIsWinXP = TRUE;
+       }
+       fChecked = TRUE;
+   }
+
+   return fIsWinXP;
+}
+
+/* This flag is only supported by versions of Windows which have obtained
+ * a code change from Microsoft.   When the code change is installed,
+ * setting this flag will cause all retrieved credentials to be stored 
+ * in the LSA cache.
+ */
+#ifndef KERB_RETRIEVE_TICKET_CACHE_TICKET
+#define KERB_RETRIEVE_TICKET_CACHE_TICKET  0x20
+#endif
+
+static VOID
+ShowWinError(LPSTR szAPI, DWORD dwError)
+{
+
+    // TODO - Write errors to event log so that scripts that don't
+    // check for errors will still get something in the event log
+
+    // This code is completely unsafe for use on non-English systems
+    // Any call to this function will result in the FormatMessage
+    // call failing and the program terminating.  This might have
+    // been acceptable when this code was part of ms2mit.exe as
+    // a standalone executable but it is not appropriate for a library
+
+#ifdef COMMENT
+    WCHAR szMsgBuf[MAX_MSG_SIZE];
+    DWORD dwRes;
+
+    printf("Error calling function %s: %lu\n", szAPI, dwError);
+
+    dwRes = FormatMessage (
+        FORMAT_MESSAGE_FROM_SYSTEM,
+        NULL,
+        dwError,
+        MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US),
+        szMsgBuf,
+        MAX_MSG_SIZE,
+        NULL);
+    if (0 == dwRes) {
+        printf("FormatMessage failed with %d\n", GetLastError());
+        ExitProcess(EXIT_FAILURE);
+    }
+
+    printf("%S",szMsgBuf);
+#endif /* COMMENT */
+}
+
+static VOID
+ShowLsaError(LPSTR szAPI, NTSTATUS Status)
+{
+    //
+    // Convert the NTSTATUS to Winerror. Then call ShowWinError().
+    //
+    ShowWinError(szAPI, LsaNtStatusToWinError(Status));
+}
+
+static BOOL
+WINAPI
+UnicodeToANSI(LPTSTR lpInputString, LPSTR lpszOutputString, int nOutStringLen)
+{
+    CPINFO CodePageInfo;
+
+    GetCPInfo(CP_ACP, &CodePageInfo);
+
+    if (CodePageInfo.MaxCharSize > 1) {
+        // Only supporting non-Unicode strings
+        int reqLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) lpInputString, -1,
+                                         NULL, 0, NULL, NULL);
+        if ( reqLen > nOutStringLen) 
+        {
+            return FALSE;
+        } else {
+            WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) lpInputString, -1,
+                                lpszOutputString, nOutStringLen, NULL, NULL);
+        }
+    } 
+    else if (((LPBYTE) lpInputString)[1] == '\0')
+    {
+        // Looks like unicode, better translate it
+        WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) lpInputString, -1,
+                            lpszOutputString, nOutStringLen, NULL, NULL);
+    }
+    else
+        lstrcpyA(lpszOutputString, (LPSTR) lpInputString);
+
+    return TRUE;
+}  // UnicodeToANSI
+
+static VOID
+WINAPI
+ANSIToUnicode(LPSTR lpInputString, LPTSTR lpszOutputString, int nOutStringLen)
+{
+
+    CPINFO CodePageInfo;
+
+    lstrcpy(lpszOutputString, (LPTSTR) lpInputString);
+
+    GetCPInfo(CP_ACP, &CodePageInfo);
+
+    if (CodePageInfo.MaxCharSize > 1 || ((LPBYTE) lpInputString)[1] != '\0')
+    {
+        // Looks like ANSI or MultiByte, better translate it
+        MultiByteToWideChar(CP_ACP, 0, (LPCSTR) lpInputString, -1,
+                            (LPWSTR) lpszOutputString, nOutStringLen);
+    }
+    else
+        lstrcpy(lpszOutputString, (LPTSTR) lpInputString);
+}  // ANSIToUnicode
+
+
+static void
+MITPrincToMSPrinc(krb5_context context, krb5_principal principal, UNICODE_STRING * msprinc)
+{
+    char *aname = NULL;
+
+    if (!krb5_unparse_name(context, principal, &aname)) {
+        msprinc->Length = strlen(aname) * sizeof(WCHAR);
+        if ( msprinc->Length <= msprinc->MaximumLength )
+            ANSIToUnicode(aname, msprinc->Buffer, msprinc->MaximumLength);
+        else 
+            msprinc->Length = 0;
+        krb5_free_unparsed_name(context,aname);
+    }
+}
+
+static BOOL
+UnicodeStringToMITPrinc(UNICODE_STRING *service, WCHAR *realm, krb5_context context, 
+                        krb5_principal *principal)
+{
+    WCHAR princbuf[512];
+    char aname[512];
+
+    princbuf[0]=0;
+    wcsncpy(princbuf, service->Buffer, service->Length/sizeof(WCHAR));
+    princbuf[service->Length/sizeof(WCHAR)]=0;
+    wcscat(princbuf, L"@");
+    wcscat(princbuf, realm);
+    if (UnicodeToANSI(princbuf, aname, sizeof(aname))) {
+        krb5_parse_name(context, aname, principal);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+
+static BOOL
+KerbExternalNameToMITPrinc(KERB_EXTERNAL_NAME *msprinc, WCHAR *realm, krb5_context context, 
+                           krb5_principal *principal)
+{
+    WCHAR princbuf[512],tmpbuf[128];
+    char aname[512];
+    USHORT i;
+    princbuf[0]=0;
+    for (i=0;i<msprinc->NameCount;i++) {
+        wcsncpy(tmpbuf, msprinc->Names[i].Buffer,
+                msprinc->Names[i].Length/sizeof(WCHAR));
+        tmpbuf[msprinc->Names[i].Length/sizeof(WCHAR)]=0;
+        if (princbuf[0])
+            wcscat(princbuf, L"/");
+        wcscat(princbuf, tmpbuf);
+    }
+    wcscat(princbuf, L"@");
+    wcscat(princbuf, realm);
+    if (UnicodeToANSI(princbuf, aname, sizeof(aname))) {
+        krb5_parse_name(context, aname, principal);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static time_t
+FileTimeToUnixTime(LARGE_INTEGER *ltime)
+{
+    FILETIME filetime, localfiletime;
+    SYSTEMTIME systime;
+    struct tm utime;
+    filetime.dwLowDateTime=ltime->LowPart;
+    filetime.dwHighDateTime=ltime->HighPart;
+    FileTimeToLocalFileTime(&filetime, &localfiletime);
+    FileTimeToSystemTime(&localfiletime, &systime);
+    utime.tm_sec=systime.wSecond;
+    utime.tm_min=systime.wMinute;
+    utime.tm_hour=systime.wHour;
+    utime.tm_mday=systime.wDay;
+    utime.tm_mon=systime.wMonth-1;
+    utime.tm_year=systime.wYear-1900;
+    utime.tm_isdst=-1;
+    return(mktime(&utime));
+}
+
+static void
+MSSessionKeyToMITKeyblock(KERB_CRYPTO_KEY *mskey, krb5_context context, krb5_keyblock *keyblock)
+{
+    krb5_keyblock tmpblock;
+    tmpblock.magic=KV5M_KEYBLOCK;
+    tmpblock.enctype=mskey->KeyType;
+    tmpblock.length=mskey->Length;
+    tmpblock.contents=mskey->Value;
+    krb5_copy_keyblock_contents(context, &tmpblock, keyblock);
+}
+
+
+static void
+MSFlagsToMITFlags(ULONG msflags, ULONG *mitflags)
+{
+    *mitflags=msflags;
+}
+
+static BOOL
+MSTicketToMITTicket(KERB_EXTERNAL_TICKET *msticket, krb5_context context, krb5_data *ticket)
+{
+    krb5_data tmpdata, *newdata = 0;
+    krb5_error_code rc;
+
+    tmpdata.magic=KV5M_DATA;
+    tmpdata.length=msticket->EncodedTicketSize;
+    tmpdata.data=msticket->EncodedTicket;
+
+    // this is ugly and will break krb5_free_data() 
+    // now that this is being done within the library it won't break krb5_free_data()
+    rc = krb5_copy_data(context, &tmpdata, &newdata);
+    if (rc)
+        return FALSE;
+    
+    memcpy(ticket, newdata, sizeof(krb5_data));
+    krb5_xfree(newdata);
+    return TRUE;
+}
+
+/*
+ * PreserveInitialTicketIdentity()
+ *
+ * This will find the "PreserveInitialTicketIdentity" key in the registry.  
+ * Returns 1 to preserve and 0 to not.
+ */
+
+static DWORD
+PreserveInitialTicketIdentity(void)
+{
+    HKEY hKey;
+    DWORD size = sizeof(DWORD);
+    DWORD type = REG_DWORD;
+    const char *key_path = "Software\\MIT\\Kerberos5";
+    const char *value_name = "PreserveInitialTicketIdentity";
+    DWORD retval = 1;     /* default to Preserve */
+
+    if (RegOpenKeyExA(HKEY_CURRENT_USER, key_path, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
+        goto syskey;
+    if (RegQueryValueExA(hKey, value_name, 0, &type, (LPBYTE)&retval, &size) != ERROR_SUCCESS)
+    {
+        RegCloseKey(hKey);
+        goto syskey;
+    }
+    RegCloseKey(hKey);
+    goto done;
+
+  syskey:
+    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key_path, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
+        goto done;
+    if (RegQueryValueExA(hKey, value_name, 0, &type, (LPBYTE)&retval, &size) != ERROR_SUCCESS)
+    {
+        RegCloseKey(hKey);
+        goto done;
+    }
+    RegCloseKey(hKey);
+
+  done:
+    return retval;
+}
+
+
+static BOOL
+MSCredToMITCred(KERB_EXTERNAL_TICKET *msticket, UNICODE_STRING ClientRealm, 
+                krb5_context context, krb5_creds *creds)
+{
+    WCHAR wrealm[128];
+    ZeroMemory(creds, sizeof(krb5_creds));
+    creds->magic=KV5M_CREDS;
+
+    // construct Client Principal
+    wcsncpy(wrealm, ClientRealm.Buffer, ClientRealm.Length/sizeof(WCHAR));
+    wrealm[ClientRealm.Length/sizeof(WCHAR)]=0;
+    if (!KerbExternalNameToMITPrinc(msticket->ClientName, wrealm, context, &creds->client))
+        return FALSE;
+
+    // construct Service Principal
+    wcsncpy(wrealm, msticket->DomainName.Buffer,
+            msticket->DomainName.Length/sizeof(WCHAR));
+    wrealm[msticket->DomainName.Length/sizeof(WCHAR)]=0;
+    if (!KerbExternalNameToMITPrinc(msticket->ServiceName, wrealm, context, &creds->server))
+        return FALSE;
+    MSSessionKeyToMITKeyblock(&msticket->SessionKey, context, 
+                              &creds->keyblock);
+    MSFlagsToMITFlags(msticket->TicketFlags, &creds->ticket_flags);
+    creds->times.starttime=FileTimeToUnixTime(&msticket->StartTime);
+    creds->times.endtime=FileTimeToUnixTime(&msticket->EndTime);
+    creds->times.renew_till=FileTimeToUnixTime(&msticket->RenewUntil);
+
+    creds->addresses = NULL;
+
+    return MSTicketToMITTicket(msticket, context, &creds->ticket);
+}
+
+#ifdef HAVE_CACHE_INFO_EX2
+/* CacheInfoEx2ToMITCred is used when we do not need the real ticket */
+static void
+CacheInfoEx2ToMITCred(KERB_TICKET_CACHE_INFO_EX2 *info,
+                      krb5_context context, krb5_creds *creds)
+{
+    WCHAR wrealm[128];
+    ZeroMemory(creds, sizeof(krb5_creds));
+    creds->magic=KV5M_CREDS;
+
+    // construct Client Principal
+    wcsncpy(wrealm, info->ClientRealm.Buffer, info->ClientRealm.Length/sizeof(WCHAR));
+    wrealm[info->ClientRealm.Length/sizeof(WCHAR)]=0;
+    UnicodeStringToMITPrinc(&info->ClientName, wrealm, context, &creds->client);
+
+    // construct Service Principal
+    wcsncpy(wrealm, info->ServerRealm.Buffer,
+            info->ServerRealm.Length/sizeof(WCHAR));
+    wrealm[info->ServerRealm.Length/sizeof(WCHAR)]=0;
+    UnicodeStringToMITPrinc(&info->ServerName, wrealm, context, &creds->server);
+
+    creds->keyblock.magic = KV5M_KEYBLOCK;
+    creds->keyblock.enctype = info->SessionKeyType;
+    creds->ticket_flags = info->TicketFlags;
+    MSFlagsToMITFlags(info->TicketFlags, &creds->ticket_flags);
+    creds->times.starttime=FileTimeToUnixTime(&info->StartTime);
+    creds->times.endtime=FileTimeToUnixTime(&info->EndTime);
+    creds->times.renew_till=FileTimeToUnixTime(&info->RenewTime);
+
+    /* MS Tickets are addressless.  MIT requires an empty address
+     * not a NULL list of addresses.
+     */
+    creds->addresses = (krb5_address **)malloc(sizeof(krb5_address *));
+    memset(creds->addresses, 0, sizeof(krb5_address *));
+}
+#endif /* HAVE_CACHE_INFO_EX2 */
+
+static BOOL
+PackageConnectLookup(HANDLE *pLogonHandle, ULONG *pPackageId)
+{
+    LSA_STRING Name;
+    NTSTATUS Status;
+
+    Status = LsaConnectUntrusted(
+        pLogonHandle
+        );
+
+    if (FAILED(Status))
+    {
+        ShowLsaError("LsaConnectUntrusted", Status);
+        return FALSE;
+    }
+
+    Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
+    Name.Length = strlen(Name.Buffer);
+    Name.MaximumLength = Name.Length + 1;
+
+    Status = LsaLookupAuthenticationPackage(
+        *pLogonHandle,
+        &Name,
+        pPackageId
+        );
+
+    if (FAILED(Status))
+    {
+        ShowLsaError("LsaLookupAuthenticationPackage", Status);
+        return FALSE;
+    }
+
+    return TRUE;
+
+}
+
+static BOOL 
+does_retrieve_ticket_cache_ticket (void)
+{
+   static BOOL fChecked = FALSE;
+   static BOOL fCachesTicket = FALSE;
+
+   if (!fChecked)
+   {
+       NTSTATUS Status = 0;
+       NTSTATUS SubStatus = 0;
+       HANDLE LogonHandle;
+       ULONG  PackageId;
+       ULONG RequestSize;
+       PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
+       PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
+       ULONG ResponseSize;
+
+       RequestSize = sizeof(*pTicketRequest) + 1;
+
+       if (!PackageConnectLookup(&LogonHandle, &PackageId))
+           return FALSE;
+
+       pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize);
+       if (!pTicketRequest) {
+           CloseHandle(LogonHandle);
+           return FALSE;
+       }
+
+       pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
+       pTicketRequest->LogonId.LowPart = 0;
+       pTicketRequest->LogonId.HighPart = 0;
+       pTicketRequest->TargetName.Length = 0;
+       pTicketRequest->TargetName.MaximumLength = 0;
+       pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
+       pTicketRequest->CacheOptions = 
+           KERB_RETRIEVE_TICKET_DONT_USE_CACHE | KERB_RETRIEVE_TICKET_CACHE_TICKET;
+       pTicketRequest->EncryptionType = 0;
+       pTicketRequest->TicketFlags = 0;
+
+       Status = LsaCallAuthenticationPackage( LogonHandle,
+                                              PackageId,
+                                              pTicketRequest,
+                                              RequestSize,
+                                              &pTicketResponse,
+                                              &ResponseSize,
+                                              &SubStatus
+                                              );                                             
+
+       LocalFree(pTicketRequest);
+       CloseHandle(LogonHandle);
+
+       if (FAILED(Status) || FAILED(SubStatus)) {
+           if ( SubStatus == STATUS_NOT_SUPPORTED )
+               /* The combination of the two CacheOption flags 
+                * is not supported; therefore, the new flag is supported 
+                */
+               fCachesTicket = TRUE;
+       }
+       fChecked = TRUE;
+   }
+
+   return fCachesTicket;
+}
+
+#ifdef HAVE_CACHE_INFO_EX2
+static BOOL 
+does_query_ticket_cache_ex2 (void)
+{
+   static BOOL fChecked = FALSE;
+   static BOOL fEx2Response = FALSE;
+
+   if (!fChecked)
+   {
+       NTSTATUS Status = 0;
+       NTSTATUS SubStatus = 0;
+       HANDLE LogonHandle;
+       ULONG  PackageId;
+       ULONG RequestSize;
+       PKERB_QUERY_TKT_CACHE_REQUEST pCacheRequest = NULL;
+       PKERB_QUERY_TKT_CACHE_EX2_RESPONSE pCacheResponse = NULL;
+       ULONG ResponseSize;
+
+       RequestSize = sizeof(*pCacheRequest) + 1;
+
+       if (!PackageConnectLookup(&LogonHandle, &PackageId))
+           return FALSE;
+
+       pCacheRequest = (PKERB_QUERY_TKT_CACHE_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize);
+       if (!pCacheRequest) {
+           CloseHandle(LogonHandle);
+           return FALSE;
+       }
+
+       pCacheRequest->MessageType = KerbQueryTicketCacheEx2Message;
+       pCacheRequest->LogonId.LowPart = 0;
+       pCacheRequest->LogonId.HighPart = 0;
+
+       Status = LsaCallAuthenticationPackage( LogonHandle,
+                                              PackageId,
+                                              pCacheRequest,
+                                              RequestSize,
+                                              &pCacheResponse,
+                                              &ResponseSize,
+                                              &SubStatus
+                                              );                                             
+
+       LocalFree(pCacheRequest);
+       CloseHandle(LogonHandle);
+
+       if (!(FAILED(Status) || FAILED(SubStatus))) {
+           LsaFreeReturnBuffer(pCacheResponse);
+           fEx2Response = TRUE;
+       }
+       fChecked = TRUE;
+   }
+
+   return fEx2Response;
+}
+#endif /* HAVE_CACHE_INFO_EX2 */
+
+static DWORD
+ConcatenateUnicodeStrings(UNICODE_STRING *pTarget, UNICODE_STRING Source1, UNICODE_STRING Source2)
+{
+    //
+    // The buffers for Source1 and Source2 cannot overlap pTarget's
+    // buffer.  Source1.Length + Source2.Length must be <= 0xFFFF,
+    // otherwise we overflow...
+    //
+
+    USHORT TotalSize = Source1.Length + Source2.Length;
+    PBYTE buffer = (PBYTE) pTarget->Buffer;
+
+    if (TotalSize > pTarget->MaximumLength)
+        return ERROR_INSUFFICIENT_BUFFER;
+
+    if ( pTarget->Buffer != Source1.Buffer )
+        memcpy(buffer, Source1.Buffer, Source1.Length);
+    memcpy(buffer + Source1.Length, Source2.Buffer, Source2.Length);
+
+    pTarget->Length = TotalSize;
+    return ERROR_SUCCESS;
+}
+
+static BOOL
+get_STRING_from_registry(HKEY hBaseKey, char * key, char * value, char * outbuf, DWORD  outlen)
+{
+    HKEY hKey;
+    DWORD dwCount;
+    LONG rc;
+
+	if (!outbuf || outlen == 0)
+		return FALSE;
+
+    rc = RegOpenKeyExA(hBaseKey, key, 0, KEY_QUERY_VALUE, &hKey);
+    if (rc)
+        return FALSE;
+
+    dwCount = outlen;
+    rc = RegQueryValueExA(hKey, value, 0, 0, (LPBYTE) outbuf, &dwCount);
+    RegCloseKey(hKey);
+
+    return rc?FALSE:TRUE;
+}
+
+static BOOL
+GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
+{
+    NTSTATUS Status = 0;
+    HANDLE  TokenHandle;
+    TOKEN_STATISTICS Stats;
+    DWORD   ReqLen;
+    BOOL    Success;
+
+    if (!ppSessionData)
+        return FALSE;
+    *ppSessionData = NULL;
+
+    Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
+    if ( !Success )
+        return FALSE;
+
+    Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
+    CloseHandle( TokenHandle );
+    if ( !Success )
+        return FALSE;
+
+    Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
+    if ( FAILED(Status) || !ppSessionData )
+        return FALSE;
+
+    return TRUE;
+}
+
+//
+// IsKerberosLogon() does not validate whether or not there are valid tickets in the 
+// cache.  It validates whether or not it is reasonable to assume that if we 
+// attempted to retrieve valid tickets we could do so.  Microsoft does not 
+// automatically renew expired tickets.  Therefore, the cache could contain
+// expired or invalid tickets.  Microsoft also caches the user's password 
+// and will use it to retrieve new TGTs if the cache is empty and tickets
+// are requested.
+
+static BOOL
+IsKerberosLogon(VOID)
+{
+    PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
+    BOOL    Success = FALSE;
+
+    if ( GetSecurityLogonSessionData(&pSessionData) ) {
+        if ( pSessionData->AuthenticationPackage.Buffer ) {
+            WCHAR buffer[256];
+            WCHAR *usBuffer;
+            int usLength;
+
+            Success = FALSE;
+            usBuffer = (pSessionData->AuthenticationPackage).Buffer;
+            usLength = (pSessionData->AuthenticationPackage).Length;
+            if (usLength < 256)
+            {
+                lstrcpyn (buffer, usBuffer, usLength);
+                lstrcat (buffer,L"");
+                if ( !lstrcmp(L"Kerberos",buffer) )
+                    Success = TRUE;
+            }
+        }
+        LsaFreeReturnBuffer(pSessionData);
+    }
+    return Success;
+}
+
+static DWORD
+ConstructTicketRequest(UNICODE_STRING DomainName, PKERB_RETRIEVE_TKT_REQUEST * outRequest, ULONG * outSize)
+{
+    DWORD Error;
+    UNICODE_STRING TargetPrefix;
+    USHORT TargetSize;
+    ULONG RequestSize;
+    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
+
+    *outRequest = NULL;
+    *outSize = 0;
+
+    //
+    // Set up the "krbtgt/" target prefix into a UNICODE_STRING so we
+    // can easily concatenate it later.
+    //
+
+    TargetPrefix.Buffer = L"krbtgt/";
+    TargetPrefix.Length = wcslen(TargetPrefix.Buffer) * sizeof(WCHAR);
+    TargetPrefix.MaximumLength = TargetPrefix.Length;
+
+    //
+    // We will need to concatenate the "krbtgt/" prefix and the 
+    // Logon Session's DnsDomainName into our request's target name.
+    //
+    // Therefore, first compute the necessary buffer size for that.
+    //
+    // Note that we might theoretically have integer overflow.
+    //
+
+    TargetSize = TargetPrefix.Length + DomainName.Length;
+
+    //
+    // The ticket request buffer needs to be a single buffer.  That buffer
+    // needs to include the buffer for the target name.
+    //
+
+    RequestSize = sizeof(*pTicketRequest) + TargetSize;
+
+    //
+    // Allocate the request buffer and make sure it's zero-filled.
+    //
+
+    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize);
+    if (!pTicketRequest)
+        return GetLastError();
+
+    //
+    // Concatenate the target prefix with the previous reponse's
+    // target domain.
+    //
+
+    pTicketRequest->TargetName.Length = 0;
+    pTicketRequest->TargetName.MaximumLength = TargetSize;
+    pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
+    Error = ConcatenateUnicodeStrings(&(pTicketRequest->TargetName),
+                                        TargetPrefix,
+                                        DomainName);
+    *outRequest = pTicketRequest;
+    *outSize    = RequestSize;
+    return Error;
+}
+
+static BOOL
+PurgeAllTickets(HANDLE LogonHandle, ULONG  PackageId)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    KERB_PURGE_TKT_CACHE_REQUEST PurgeRequest;
+
+    PurgeRequest.MessageType = KerbPurgeTicketCacheMessage;
+    PurgeRequest.LogonId.LowPart = 0;
+    PurgeRequest.LogonId.HighPart = 0;
+    PurgeRequest.ServerName.Buffer = L"";
+    PurgeRequest.ServerName.Length = 0;
+    PurgeRequest.ServerName.MaximumLength = 0;
+    PurgeRequest.RealmName.Buffer = L"";
+    PurgeRequest.RealmName.Length = 0;
+    PurgeRequest.RealmName.MaximumLength = 0;
+    Status = LsaCallAuthenticationPackage(LogonHandle,
+                                           PackageId,
+                                           &PurgeRequest,
+                                           sizeof(PurgeRequest),
+                                           NULL,
+                                           NULL,
+                                           &SubStatus
+                                           );
+    if (FAILED(Status) || FAILED(SubStatus))
+        return FALSE;
+    return TRUE;
+}
+
+static BOOL
+PurgeTicket2000( HANDLE LogonHandle, ULONG  PackageId, 
+                 krb5_context context, krb5_creds *cred )
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    KERB_PURGE_TKT_CACHE_REQUEST * pPurgeRequest;
+    DWORD dwRequestLen = sizeof(KERB_PURGE_TKT_CACHE_REQUEST) + 2048;
+    char * sname = NULL, * srealm = NULL;
+
+    if (krb5_unparse_name(context, cred->server, &sname))
+        return FALSE;
+
+    pPurgeRequest = malloc(dwRequestLen);
+    if ( pPurgeRequest == NULL )
+        return FALSE;
+    memset(pPurgeRequest, 0, dwRequestLen);
+
+    srealm = strrchr(sname, '@');
+    *srealm = '\0';
+    srealm++;
+
+    pPurgeRequest->MessageType = KerbPurgeTicketCacheMessage;
+    pPurgeRequest->LogonId.LowPart = 0;
+    pPurgeRequest->LogonId.HighPart = 0;
+    pPurgeRequest->ServerName.Buffer = (PWSTR)(((CHAR *)pPurgeRequest)+sizeof(KERB_PURGE_TKT_CACHE_REQUEST));
+    pPurgeRequest->ServerName.Length = strlen(sname)*sizeof(WCHAR);
+    pPurgeRequest->ServerName.MaximumLength = 256;
+    ANSIToUnicode(sname, pPurgeRequest->ServerName.Buffer,
+                  pPurgeRequest->ServerName.MaximumLength);
+    pPurgeRequest->RealmName.Buffer = (PWSTR)(((CHAR *)pPurgeRequest)+sizeof(KERB_PURGE_TKT_CACHE_REQUEST)+512);
+    pPurgeRequest->RealmName.Length = strlen(srealm)*sizeof(WCHAR);
+    pPurgeRequest->RealmName.MaximumLength = 256;
+    ANSIToUnicode(srealm, pPurgeRequest->RealmName.Buffer,
+                  pPurgeRequest->RealmName.MaximumLength);
+
+    Status = LsaCallAuthenticationPackage( LogonHandle,
+                                           PackageId,
+                                           pPurgeRequest,
+                                           dwRequestLen,
+                                           NULL,
+                                           NULL,
+                                           &SubStatus
+                                           );
+    free(pPurgeRequest);
+    krb5_free_unparsed_name(context, sname);
+
+    if (FAILED(Status) || FAILED(SubStatus))
+        return FALSE;
+
+    return TRUE;
+}
+
+
+static BOOL
+PurgeTicketXP( HANDLE LogonHandle, ULONG  PackageId, 
+               krb5_context context, krb5_flags flags, krb5_creds *cred)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    KERB_PURGE_TKT_CACHE_EX_REQUEST * pPurgeRequest;
+    DWORD dwRequestLen = sizeof(KERB_PURGE_TKT_CACHE_EX_REQUEST) + 4096;
+    char * cname = NULL, * crealm = NULL;
+    char * sname = NULL, * srealm = NULL;
+
+    if (krb5_unparse_name(context, cred->client, &cname))
+        return FALSE;
+    
+    if (krb5_unparse_name(context, cred->server, &sname)) {
+        krb5_free_unparsed_name(context, cname);
+        return FALSE;
+    }
+
+    pPurgeRequest = malloc(dwRequestLen);
+    if ( pPurgeRequest == NULL )
+        return FALSE;
+    memset(pPurgeRequest, 0, dwRequestLen);
+
+    crealm = strrchr(cname, '@');
+    *crealm = '\0';
+    crealm++;
+
+    srealm = strrchr(sname, '@');
+    *srealm = '\0';
+    srealm++;
+
+    pPurgeRequest->MessageType = KerbPurgeTicketCacheExMessage;
+    pPurgeRequest->LogonId.LowPart = 0;
+    pPurgeRequest->LogonId.HighPart = 0;
+    pPurgeRequest->Flags = 0;
+    pPurgeRequest->TicketTemplate.ClientName.Buffer = (PWSTR)((CHAR *)pPurgeRequest + sizeof(KERB_PURGE_TKT_CACHE_EX_REQUEST));
+    pPurgeRequest->TicketTemplate.ClientName.Length = strlen(cname)*sizeof(WCHAR);
+    pPurgeRequest->TicketTemplate.ClientName.MaximumLength = 256;
+    ANSIToUnicode(cname, pPurgeRequest->TicketTemplate.ClientName.Buffer,
+                  pPurgeRequest->TicketTemplate.ClientName.MaximumLength);
+
+    pPurgeRequest->TicketTemplate.ClientRealm.Buffer = (PWSTR)(((CHAR *)pPurgeRequest)+sizeof(KERB_PURGE_TKT_CACHE_EX_REQUEST) + 512);
+    pPurgeRequest->TicketTemplate.ClientRealm.Length = strlen(crealm)*sizeof(WCHAR);
+    pPurgeRequest->TicketTemplate.ClientRealm.MaximumLength = 256;
+    ANSIToUnicode(crealm, pPurgeRequest->TicketTemplate.ClientRealm.Buffer,
+                  pPurgeRequest->TicketTemplate.ClientRealm.MaximumLength);
+
+    pPurgeRequest->TicketTemplate.ServerName.Buffer = (PWSTR)(((CHAR *)pPurgeRequest)+sizeof(KERB_PURGE_TKT_CACHE_EX_REQUEST) + 1024);
+    pPurgeRequest->TicketTemplate.ServerName.Length = strlen(sname)*sizeof(WCHAR);
+    pPurgeRequest->TicketTemplate.ServerName.MaximumLength = 256;
+    ANSIToUnicode(sname, pPurgeRequest->TicketTemplate.ServerName.Buffer,
+                  pPurgeRequest->TicketTemplate.ServerName.MaximumLength);
+
+    pPurgeRequest->TicketTemplate.ServerRealm.Buffer = (PWSTR)(((CHAR *)pPurgeRequest)+sizeof(KERB_PURGE_TKT_CACHE_EX_REQUEST) + 1536);
+    pPurgeRequest->TicketTemplate.ServerRealm.Length = strlen(srealm)*sizeof(WCHAR);
+    pPurgeRequest->TicketTemplate.ServerRealm.MaximumLength = 256;
+    ANSIToUnicode(srealm, pPurgeRequest->TicketTemplate.ServerRealm.Buffer,
+                  pPurgeRequest->TicketTemplate.ServerRealm.MaximumLength);
+
+    pPurgeRequest->TicketTemplate.StartTime;
+    pPurgeRequest->TicketTemplate.EndTime;
+    pPurgeRequest->TicketTemplate.RenewTime;
+    pPurgeRequest->TicketTemplate.EncryptionType = cred->keyblock.enctype;
+    pPurgeRequest->TicketTemplate.TicketFlags = flags;
+
+    Status = LsaCallAuthenticationPackage( LogonHandle,
+                                           PackageId,
+                                           pPurgeRequest,
+                                           dwRequestLen,
+                                           NULL,
+                                           NULL,
+                                           &SubStatus
+                                           );
+    free(pPurgeRequest);
+    krb5_free_unparsed_name(context,cname);
+    krb5_free_unparsed_name(context,sname);
+
+    if (FAILED(Status) || FAILED(SubStatus))
+        return FALSE;
+    return TRUE;
+}
+
+#ifdef KERB_SUBMIT_TICKET
+static BOOL
+KerbSubmitTicket( HANDLE LogonHandle, ULONG  PackageId, 
+                  krb5_context context, krb5_creds *cred)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    KERB_SUBMIT_TKT_REQUEST * pSubmitRequest;
+    DWORD dwRequestLen;
+    krb5_auth_context auth_context;
+    krb5_keyblock * keyblock = 0;
+    krb5_replay_data replaydata;
+    krb5_data * krb_cred = 0;
+    krb5_error_code rc;
+
+    if (krb5_auth_con_init(context, &auth_context)) {
+        return FALSE;
+    }
+
+    if (krb5_auth_con_setflags(context, auth_context,
+                               KRB5_AUTH_CONTEXT_RET_TIME)) {
+        return FALSE;
+    }
+    
+    krb5_auth_con_getsendsubkey(context, auth_context, &keyblock);
+    if (keyblock == NULL)
+        krb5_auth_con_getkey(context, auth_context, &keyblock);
+#ifdef TESTING
+    /* do not use this code unless testing the LSA */
+    if (keyblock == NULL) {
+        keyblock = (krb5_keyblock *)malloc(sizeof(krb5_keyblock));
+        keyblock->enctype = ENCTYPE_ARCFOUR_HMAC;
+        keyblock->length = 16;
+        keyblock->contents = (krb5_octet *)malloc(16);
+        keyblock->contents[0] = 0xde;
+        keyblock->contents[1] = 0xad;
+        keyblock->contents[2] = 0xbe;
+        keyblock->contents[3] = 0xef;
+        keyblock->contents[4] = 0xfe;
+        keyblock->contents[5] = 0xed;
+        keyblock->contents[6] = 0xf0;
+        keyblock->contents[7] = 0xd;
+        keyblock->contents[8] = 0xde;
+        keyblock->contents[9] = 0xad;
+        keyblock->contents[10] = 0xbe;
+        keyblock->contents[11] = 0xef;
+        keyblock->contents[12] = 0xfe;
+        keyblock->contents[13] = 0xed;
+        keyblock->contents[14] = 0xf0;
+        keyblock->contents[15] = 0xd;
+        krb5_auth_con_setsendsubkey(context, auth_context, keyblock);
+    }
+#endif
+    rc = krb5_mk_1cred(context, auth_context, cred, &krb_cred, &replaydata);
+    if (rc) {
+        krb5_auth_con_free(context, auth_context);
+        if (keyblock)
+            krb5_free_keyblock(context, keyblock);
+        if (krb_cred)
+            krb5_free_data(context, krb_cred);
+        return FALSE;
+    }
+
+    dwRequestLen = sizeof(KERB_SUBMIT_TKT_REQUEST) + krb_cred->length + (keyblock ? keyblock->length : 0);
+
+    pSubmitRequest = (PKERB_SUBMIT_TKT_REQUEST)malloc(dwRequestLen);
+    memset(pSubmitRequest, 0, dwRequestLen);
+
+    pSubmitRequest->MessageType = KerbSubmitTicketMessage;
+    pSubmitRequest->LogonId.LowPart = 0;
+    pSubmitRequest->LogonId.HighPart = 0;
+    pSubmitRequest->Flags = 0;
+    
+    if (keyblock) {
+        pSubmitRequest->Key.KeyType = keyblock->enctype;
+        pSubmitRequest->Key.Length = keyblock->length;
+        pSubmitRequest->Key.Offset = sizeof(KERB_SUBMIT_TKT_REQUEST)+krb_cred->length;
+    } else {
+        pSubmitRequest->Key.KeyType = ENCTYPE_NULL;
+        pSubmitRequest->Key.Length = 0;
+        pSubmitRequest->Key.Offset = 0;
+    }
+    pSubmitRequest->KerbCredSize = krb_cred->length;
+    pSubmitRequest->KerbCredOffset = sizeof(KERB_SUBMIT_TKT_REQUEST);
+    memcpy(((CHAR *)pSubmitRequest)+sizeof(KERB_SUBMIT_TKT_REQUEST),
+           krb_cred->data, krb_cred->length);
+    if (keyblock)
+        memcpy(((CHAR *)pSubmitRequest)+sizeof(KERB_SUBMIT_TKT_REQUEST)+krb_cred->length,
+                keyblock->contents, keyblock->length);
+    krb5_free_data(context, krb_cred);
+
+    Status = LsaCallAuthenticationPackage( LogonHandle,
+                                           PackageId,
+                                           pSubmitRequest,
+                                           dwRequestLen,
+                                           NULL,
+                                           NULL,
+                                           &SubStatus
+                                           );
+    free(pSubmitRequest);
+    if (keyblock)
+        krb5_free_keyblock(context, keyblock);
+    krb5_auth_con_free(context, auth_context);
+
+    if (FAILED(Status) || FAILED(SubStatus)) {
+        return FALSE;                         
+    }
+    return TRUE;
+}
+#endif /* KERB_SUBMIT_TICKET */
+
+/* 
+ * A simple function to determine if there is an exact match between two tickets
+ * We rely on the fact that the external tickets contain the raw Kerberos ticket.
+ * If the EncodedTicket fields match, the KERB_EXTERNAL_TICKETs must be the same.
+ */
+static BOOL
+KerbExternalTicketMatch( PKERB_EXTERNAL_TICKET one, PKERB_EXTERNAL_TICKET two )
+{
+    if ( one->EncodedTicketSize != two->EncodedTicketSize )
+        return FALSE;
+
+    if ( memcmp(one->EncodedTicket, two->EncodedTicket, one->EncodedTicketSize) )
+         return FALSE;
+
+    return TRUE;
+}
+
+krb5_boolean
+krb5_is_permitted_tgs_enctype(krb5_context context, krb5_const_principal princ, krb5_enctype etype)
+{
+    krb5_enctype *list, *ptr;
+    krb5_boolean ret;
+
+    if (krb5_get_tgs_ktypes(context, princ, &list))
+        return(0);
+    
+    ret = 0;
+
+    for (ptr = list; *ptr; ptr++)
+	if (*ptr == etype)
+	    ret = 1;
+
+    krb5_free_ktypes (context, list);
+
+    return(ret);
+}
+
+#define ENABLE_PURGING 1
+// to allow the purging of expired tickets from LSA cache.  This is necessary
+// to force the retrieval of new TGTs.  Microsoft does not appear to retrieve
+// new tickets when they expire.  Instead they continue to accept the expired
+// tickets.  This is safe to do because the LSA purges its cache when it 
+// retrieves a new TGT (ms calls this renew) but not when it renews the TGT
+// (ms calls this refresh).
+
+static BOOL
+GetMSTGT(krb5_context context, HANDLE LogonHandle, ULONG PackageId, KERB_EXTERNAL_TICKET **ticket, BOOL enforce_tgs_enctypes)
+{
+    //
+    // INVARIANTS:
+    //
+    //   (FAILED(Status) || FAILED(SubStatus)) ==> error
+    //   bIsLsaError ==> LsaCallAuthenticationPackage() error
+    //
+
+    BOOL bIsLsaError = FALSE;
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    DWORD   Error;
+
+    KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
+    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
+    PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
+    ULONG RequestSize;
+    ULONG ResponseSize;
+#ifdef ENABLE_PURGING
+    int    purge_cache = 0;
+#endif /* ENABLE_PURGING */
+    int    ignore_cache = 0;
+    krb5_enctype *etype_list = NULL, *ptr = NULL, etype = 0;
+
+    memset(&CacheRequest, 0, sizeof(KERB_QUERY_TKT_CACHE_REQUEST));
+    CacheRequest.MessageType = KerbRetrieveTicketMessage;
+    CacheRequest.LogonId.LowPart = 0;
+    CacheRequest.LogonId.HighPart = 0;
+
+    Status = LsaCallAuthenticationPackage(
+        LogonHandle,
+        PackageId,
+        &CacheRequest,
+        sizeof(CacheRequest),
+        &pTicketResponse,
+        &ResponseSize,
+        &SubStatus
+        );
+
+    if (FAILED(Status))
+    {
+        // if the call to LsaCallAuthenticationPackage failed we cannot
+        // perform any queries most likely because the Kerberos package 
+        // is not available or we do not have access
+        bIsLsaError = TRUE;
+        goto cleanup;
+    }
+
+    if (FAILED(SubStatus)) {
+        PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
+        BOOL    Success = FALSE;
+        OSVERSIONINFOEX verinfo;
+        int supported = 0;
+
+        // SubStatus 0x8009030E is not documented.  However, it appears
+        // to mean there is no TGT
+        if (SubStatus != 0x8009030E) {
+            bIsLsaError = TRUE;
+            goto cleanup;
+        }
+
+        verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+        GetVersionEx((OSVERSIONINFO *)&verinfo);
+        supported = (verinfo.dwMajorVersion > 5) || 
+            (verinfo.dwMajorVersion == 5 && verinfo.dwMinorVersion >= 1);
+
+        // If we could not get a TGT from the cache we won't know what the
+        // Kerberos Domain should have been.  On Windows XP and 2003 Server
+        // we can extract it from the Security Logon Session Data.  However,
+        // the required fields are not supported on Windows 2000.  :(
+        if ( supported && GetSecurityLogonSessionData(&pSessionData) ) {
+            if ( pSessionData->DnsDomainName.Buffer ) {
+                Error = ConstructTicketRequest(pSessionData->DnsDomainName,
+                                                &pTicketRequest, &RequestSize);
+                LsaFreeReturnBuffer(pSessionData);
+                if ( Error )
+                    goto cleanup;
+            } else {
+                LsaFreeReturnBuffer(pSessionData);
+                bIsLsaError = TRUE;
+                goto cleanup;
+            }
+        } else {
+            CHAR  UserDnsDomain[256];
+            WCHAR UnicodeUserDnsDomain[256];
+            UNICODE_STRING wrapper;
+            if ( !get_STRING_from_registry(HKEY_CURRENT_USER,
+                                          "Volatile Environment",
+                                          "USERDNSDOMAIN",
+                                           UserDnsDomain,
+                                           sizeof(UserDnsDomain)
+                                           ) )
+            {
+                goto cleanup;
+            }
+
+            ANSIToUnicode(UserDnsDomain,UnicodeUserDnsDomain,256);
+            wrapper.Buffer = UnicodeUserDnsDomain;
+            wrapper.Length = wcslen(UnicodeUserDnsDomain) * sizeof(WCHAR);
+            wrapper.MaximumLength = 256;
+
+            Error = ConstructTicketRequest(wrapper,
+                                             &pTicketRequest, &RequestSize);
+            if ( Error )
+                goto cleanup;
+        }
+    } else {
+        /* We have succeeded in obtaining a credential from the cache. 
+         * Assuming the enctype is one that we support and the ticket
+         * has not expired and is not marked invalid we will use it.
+         * Otherwise, we must create a new ticket request and obtain
+         * a credential we can use. 
+         */
+
+#ifdef PURGE_ALL
+        purge_cache = 1;
+#else
+        /* Check Supported Enctypes */
+        if ( !enforce_tgs_enctypes ||
+             pTicketResponse->Ticket.SessionKey.KeyType == KERB_ETYPE_NULL ||
+             krb5_is_permitted_tgs_enctype(context, NULL, pTicketResponse->Ticket.SessionKey.KeyType) ) {
+            FILETIME Now, MinLife, EndTime, LocalEndTime;
+            __int64  temp;
+            // FILETIME is in units of 100 nano-seconds
+            // If obtained tickets are either expired or have a lifetime
+            // less than 20 minutes, retry ...
+            GetSystemTimeAsFileTime(&Now);
+            EndTime.dwLowDateTime=pTicketResponse->Ticket.EndTime.LowPart;
+            EndTime.dwHighDateTime=pTicketResponse->Ticket.EndTime.HighPart;
+            FileTimeToLocalFileTime(&EndTime, &LocalEndTime);
+            temp = Now.dwHighDateTime;
+            temp <<= 32;
+            temp = Now.dwLowDateTime;
+            temp += 1200 * 10000;
+            MinLife.dwHighDateTime = (DWORD)((temp >> 32) & 0xFFFFFFFF);
+            MinLife.dwLowDateTime = (DWORD)(temp & 0xFFFFFFFF);
+            if (CompareFileTime(&MinLife, &LocalEndTime) >= 0) {
+#ifdef ENABLE_PURGING
+                purge_cache = 1;
+#else
+                ignore_cache = 1;
+#endif /* ENABLE_PURGING */
+            }
+            if (pTicketResponse->Ticket.TicketFlags & KERB_TICKET_FLAGS_invalid) {
+                ignore_cache = 1;   // invalid, need to attempt a TGT request
+            }
+            goto cleanup;           // we have a valid ticket, all done
+        } else {
+            // not supported
+            ignore_cache = 1;
+        }
+#endif /* PURGE_ALL */
+
+        Error = ConstructTicketRequest(pTicketResponse->Ticket.TargetDomainName,
+                                        &pTicketRequest, &RequestSize);
+        if ( Error ) {
+            goto cleanup;
+        }
+
+        //
+        // Free the previous response buffer so we can get the new response.
+        //
+
+        if ( pTicketResponse ) {
+            memset(pTicketResponse,0,sizeof(KERB_RETRIEVE_TKT_RESPONSE));
+            LsaFreeReturnBuffer(pTicketResponse);
+            pTicketResponse = NULL;
+        }
+
+#ifdef ENABLE_PURGING
+        if ( purge_cache ) {
+            //
+            // Purge the existing tickets which we cannot use so new ones can 
+            // be requested.  It is not possible to purge just the TGT.  All
+            // service tickets must be purged.
+            //
+            PurgeAllTickets(LogonHandle, PackageId);
+        }
+#endif /* ENABLE_PURGING */
+    }
+    
+    //
+    // Intialize the request of the request.
+    //
+
+    pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
+    pTicketRequest->LogonId.LowPart = 0;
+    pTicketRequest->LogonId.HighPart = 0;
+    // Note: pTicketRequest->TargetName set up above
+#ifdef ENABLE_PURGING
+    pTicketRequest->CacheOptions = ((ignore_cache || !purge_cache) ? 
+                                     KERB_RETRIEVE_TICKET_DONT_USE_CACHE : 0L);
+#else
+    pTicketRequest->CacheOptions = (ignore_cache ? KERB_RETRIEVE_TICKET_DONT_USE_CACHE : 0L);
+#endif /* ENABLE_PURGING */
+    pTicketRequest->TicketFlags = 0L;
+    pTicketRequest->EncryptionType = 0L;
+
+    Status = LsaCallAuthenticationPackage( LogonHandle,
+                                           PackageId,
+                                           pTicketRequest,
+                                           RequestSize,
+                                           &pTicketResponse,
+                                           &ResponseSize,
+                                           &SubStatus
+                                           );
+
+    if (FAILED(Status) || FAILED(SubStatus))
+    {
+        bIsLsaError = TRUE;
+        goto cleanup;
+    }
+
+    //
+    // Check to make sure the new tickets we received are of a type we support
+    //
+
+    /* Check Supported Enctypes */
+    if ( !enforce_tgs_enctypes ||
+         krb5_is_permitted_tgs_enctype(context, NULL, pTicketResponse->Ticket.SessionKey.KeyType) ) {
+        goto cleanup;       // we have a valid ticket, all done
+    }
+
+    if (krb5_get_tgs_ktypes(context, NULL, &etype_list)) {
+        ptr = etype_list = NULL;
+        etype = ENCTYPE_DES_CBC_CRC;
+    } else {
+        ptr = etype_list + 1;
+        etype = *etype_list;
+    }
+
+    while ( etype ) {
+        // Try once more but this time specify the Encryption Type
+        // (This will not store the retrieved tickets in the LSA cache unless
+        // 0 is supported.)
+        pTicketRequest->EncryptionType = etype;
+        pTicketRequest->CacheOptions = 0;
+        if ( does_retrieve_ticket_cache_ticket() )
+            pTicketRequest->CacheOptions |= KERB_RETRIEVE_TICKET_CACHE_TICKET;
+
+        if ( pTicketResponse ) {
+            memset(pTicketResponse,0,sizeof(KERB_RETRIEVE_TKT_RESPONSE));
+            LsaFreeReturnBuffer(pTicketResponse);
+            pTicketResponse = NULL;
+        }
+
+        Status = LsaCallAuthenticationPackage( LogonHandle,
+                                               PackageId,
+                                               pTicketRequest,
+                                               RequestSize,
+                                               &pTicketResponse,
+                                               &ResponseSize,
+                                               &SubStatus
+                                               );
+
+        if (FAILED(Status) || FAILED(SubStatus))
+        {
+            bIsLsaError = TRUE;
+            goto cleanup;
+        }
+
+        if ( pTicketResponse->Ticket.SessionKey.KeyType == etype && 
+             (!enforce_tgs_enctypes ||
+             krb5_is_permitted_tgs_enctype(context, NULL, pTicketResponse->Ticket.SessionKey.KeyType)) ) {
+            goto cleanup;       // we have a valid ticket, all done
+        }
+
+        if ( ptr ) {
+            etype = *ptr++;
+        } else {
+            etype = 0;
+        }
+    }
+
+  cleanup:
+    if ( etype_list )
+        krb5_free_ktypes(context, etype_list);
+
+    if ( pTicketRequest )
+        LocalFree(pTicketRequest);
+
+    if (FAILED(Status) || FAILED(SubStatus))
+    {
+        if (bIsLsaError)
+        {
+            // XXX - Will be fixed later
+            if (FAILED(Status))
+                ShowLsaError("LsaCallAuthenticationPackage", Status);
+            if (FAILED(SubStatus))
+                ShowLsaError("LsaCallAuthenticationPackage", SubStatus);
+        }
+        else
+        {
+            ShowWinError("GetMSTGT", Status);
+        }
+
+        if (pTicketResponse) {
+            memset(pTicketResponse,0,sizeof(KERB_RETRIEVE_TKT_RESPONSE));
+            LsaFreeReturnBuffer(pTicketResponse);
+            pTicketResponse = NULL;
+        }
+        return(FALSE);
+    }
+
+    *ticket = &(pTicketResponse->Ticket);
+    return(TRUE);
+}
+
+static BOOL
+GetQueryTktCacheResponseW2K( HANDLE LogonHandle, ULONG PackageId,
+                             PKERB_QUERY_TKT_CACHE_RESPONSE * ppResponse)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+
+    KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
+    PKERB_QUERY_TKT_CACHE_RESPONSE pQueryResponse = NULL;
+    ULONG ResponseSize;
+    
+    CacheRequest.MessageType = KerbQueryTicketCacheMessage;
+    CacheRequest.LogonId.LowPart = 0;
+    CacheRequest.LogonId.HighPart = 0;
+
+    Status = LsaCallAuthenticationPackage(
+        LogonHandle,
+        PackageId,
+        &CacheRequest,
+        sizeof(CacheRequest),
+        &pQueryResponse,
+        &ResponseSize,
+        &SubStatus
+        );
+
+    if ( !(FAILED(Status) || FAILED(SubStatus)) ) {
+        *ppResponse = pQueryResponse;
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static BOOL
+GetQueryTktCacheResponseXP( HANDLE LogonHandle, ULONG PackageId,
+                            PKERB_QUERY_TKT_CACHE_EX_RESPONSE * ppResponse)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+
+    KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
+    PKERB_QUERY_TKT_CACHE_EX_RESPONSE pQueryResponse = NULL;
+    ULONG ResponseSize;
+    
+    CacheRequest.MessageType = KerbQueryTicketCacheExMessage;
+    CacheRequest.LogonId.LowPart = 0;
+    CacheRequest.LogonId.HighPart = 0;
+
+    Status = LsaCallAuthenticationPackage(
+        LogonHandle,
+        PackageId,
+        &CacheRequest,
+        sizeof(CacheRequest),
+        &pQueryResponse,
+        &ResponseSize,
+        &SubStatus
+        );
+
+    if ( !(FAILED(Status) || FAILED(SubStatus)) ) {
+        *ppResponse = pQueryResponse;
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+#ifdef HAVE_CACHE_INFO_EX2
+static BOOL
+GetQueryTktCacheResponseEX2( HANDLE LogonHandle, ULONG PackageId,
+                             PKERB_QUERY_TKT_CACHE_EX2_RESPONSE * ppResponse)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+
+    KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
+    PKERB_QUERY_TKT_CACHE_EX2_RESPONSE pQueryResponse = NULL;
+    ULONG ResponseSize;
+    
+    CacheRequest.MessageType = KerbQueryTicketCacheEx2Message;
+    CacheRequest.LogonId.LowPart = 0;
+    CacheRequest.LogonId.HighPart = 0;
+
+    Status = LsaCallAuthenticationPackage(
+        LogonHandle,
+        PackageId,
+        &CacheRequest,
+        sizeof(CacheRequest),
+        &pQueryResponse,
+        &ResponseSize,
+        &SubStatus
+        );
+
+    if ( !(FAILED(Status) || FAILED(SubStatus)) ) {
+        *ppResponse = pQueryResponse;
+        return TRUE;
+    }
+
+    return FALSE;
+}
+#endif /* HAVE_CACHE_INFO_EX2 */
+
+static BOOL
+GetMSCacheTicketFromMITCred( HANDLE LogonHandle, ULONG PackageId,
+                             krb5_context context, krb5_creds *creds, 
+                             PKERB_EXTERNAL_TICKET *ticket)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    ULONG RequestSize;
+    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
+    PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
+    ULONG ResponseSize;
+
+    RequestSize = sizeof(*pTicketRequest) + MAX_MSPRINC_SIZE;
+
+    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize);
+    if (!pTicketRequest)
+        return FALSE;
+
+    pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
+    pTicketRequest->LogonId.LowPart = 0;
+    pTicketRequest->LogonId.HighPart = 0;
+
+    pTicketRequest->TargetName.Length = 0;
+    pTicketRequest->TargetName.MaximumLength = MAX_MSPRINC_SIZE;
+    pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
+    MITPrincToMSPrinc(context, creds->server, &pTicketRequest->TargetName);
+    pTicketRequest->CacheOptions = 0;
+    if ( does_retrieve_ticket_cache_ticket() )
+        pTicketRequest->CacheOptions |= KERB_RETRIEVE_TICKET_CACHE_TICKET;
+    pTicketRequest->TicketFlags = creds->ticket_flags;
+    pTicketRequest->EncryptionType = creds->keyblock.enctype;
+
+    Status = LsaCallAuthenticationPackage( LogonHandle,
+                                           PackageId,
+                                           pTicketRequest,
+                                           RequestSize,
+                                           &pTicketResponse,
+                                           &ResponseSize,
+                                           &SubStatus
+                                           );
+
+    LocalFree(pTicketRequest);
+
+    if (FAILED(Status) || FAILED(SubStatus))
+        return(FALSE);
+
+    /* otherwise return ticket */
+    *ticket = &(pTicketResponse->Ticket);
+    return(TRUE);
+}
+
+static BOOL
+GetMSCacheTicketFromCacheInfoW2K( HANDLE LogonHandle, ULONG PackageId,
+                  PKERB_TICKET_CACHE_INFO tktinfo, PKERB_EXTERNAL_TICKET *ticket)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    ULONG RequestSize;
+    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
+    PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
+    ULONG ResponseSize;
+
+    RequestSize = sizeof(*pTicketRequest) + tktinfo->ServerName.Length;
+
+    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize);
+    if (!pTicketRequest)
+        return FALSE;
+
+    pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
+    pTicketRequest->LogonId.LowPart = 0;
+    pTicketRequest->LogonId.HighPart = 0;
+    pTicketRequest->TargetName.Length = tktinfo->ServerName.Length;
+    pTicketRequest->TargetName.MaximumLength = tktinfo->ServerName.Length;
+    pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
+    memcpy(pTicketRequest->TargetName.Buffer,tktinfo->ServerName.Buffer, tktinfo->ServerName.Length);
+    pTicketRequest->CacheOptions = 0;
+    if ( does_retrieve_ticket_cache_ticket() )
+        pTicketRequest->CacheOptions |= KERB_RETRIEVE_TICKET_CACHE_TICKET;
+    pTicketRequest->EncryptionType = tktinfo->EncryptionType;
+    pTicketRequest->TicketFlags = 0;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwardable )
+        pTicketRequest->TicketFlags |= KDC_OPT_FORWARDABLE;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwarded )
+        pTicketRequest->TicketFlags |= KDC_OPT_FORWARDED;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_proxiable )
+        pTicketRequest->TicketFlags |= KDC_OPT_PROXIABLE;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_renewable )
+        pTicketRequest->TicketFlags |= KDC_OPT_RENEWABLE;
+
+    Status = LsaCallAuthenticationPackage(
+        LogonHandle,
+        PackageId,
+        pTicketRequest,
+        RequestSize,
+        &pTicketResponse,
+        &ResponseSize,
+        &SubStatus
+        );
+
+    LocalFree(pTicketRequest);
+
+    if (FAILED(Status) || FAILED(SubStatus))
+        return(FALSE);
+    
+    /* otherwise return ticket */
+    *ticket = &(pTicketResponse->Ticket);
+
+    /* set the initial flag if we were attempting to retrieve one
+     * because Windows won't necessarily return the initial ticket
+     * to us.
+     */
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_initial )
+        (*ticket)->TicketFlags |= KERB_TICKET_FLAGS_initial;
+
+    return(TRUE);
+}
+
+static BOOL
+GetMSCacheTicketFromCacheInfoXP( HANDLE LogonHandle, ULONG PackageId,
+                  PKERB_TICKET_CACHE_INFO_EX tktinfo, PKERB_EXTERNAL_TICKET *ticket)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    ULONG RequestSize;
+    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
+    PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
+    ULONG ResponseSize;
+
+    RequestSize = sizeof(*pTicketRequest) + tktinfo->ServerName.Length;
+
+    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize);
+    if (!pTicketRequest)
+        return FALSE;
+
+    pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
+    pTicketRequest->LogonId.LowPart = 0;
+    pTicketRequest->LogonId.HighPart = 0;
+    pTicketRequest->TargetName.Length = tktinfo->ServerName.Length;
+    pTicketRequest->TargetName.MaximumLength = tktinfo->ServerName.Length;
+    pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
+    memcpy(pTicketRequest->TargetName.Buffer,tktinfo->ServerName.Buffer, tktinfo->ServerName.Length);
+    pTicketRequest->CacheOptions = 0;
+    pTicketRequest->EncryptionType = tktinfo->EncryptionType;
+    pTicketRequest->TicketFlags = 0;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwardable )
+        pTicketRequest->TicketFlags |= KDC_OPT_FORWARDABLE;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwarded )
+        pTicketRequest->TicketFlags |= KDC_OPT_FORWARDED;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_proxiable )
+        pTicketRequest->TicketFlags |= KDC_OPT_PROXIABLE;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_renewable )
+        pTicketRequest->TicketFlags |= KDC_OPT_RENEWABLE;
+
+    Status = LsaCallAuthenticationPackage(
+        LogonHandle,
+        PackageId,
+        pTicketRequest,
+        RequestSize,
+        &pTicketResponse,
+        &ResponseSize,
+        &SubStatus
+        );
+
+    LocalFree(pTicketRequest);
+
+    if (FAILED(Status) || FAILED(SubStatus))
+        return(FALSE);
+    
+    /* otherwise return ticket */
+    *ticket = &(pTicketResponse->Ticket);
+    
+    /* set the initial flag if we were attempting to retrieve one
+     * because Windows won't necessarily return the initial ticket
+     * to us.
+     */
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_initial )
+        (*ticket)->TicketFlags |= KERB_TICKET_FLAGS_initial;
+
+    return(TRUE);
+}
+
+#ifdef HAVE_CACHE_INFO_EX2
+static BOOL
+GetMSCacheTicketFromCacheInfoEX2( HANDLE LogonHandle, ULONG PackageId,
+                  PKERB_TICKET_CACHE_INFO_EX2 tktinfo, PKERB_EXTERNAL_TICKET *ticket)
+{
+    NTSTATUS Status = 0;
+    NTSTATUS SubStatus = 0;
+    ULONG RequestSize;
+    PKERB_RETRIEVE_TKT_REQUEST pTicketRequest = NULL;
+    PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
+    ULONG ResponseSize;
+
+    RequestSize = sizeof(*pTicketRequest) + tktinfo->ServerName.Length;
+
+    pTicketRequest = (PKERB_RETRIEVE_TKT_REQUEST) LocalAlloc(LMEM_ZEROINIT, RequestSize);
+    if (!pTicketRequest)
+        return FALSE;
+
+    pTicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
+    pTicketRequest->LogonId.LowPart = 0;
+    pTicketRequest->LogonId.HighPart = 0;
+    pTicketRequest->TargetName.Length = tktinfo->ServerName.Length;
+    pTicketRequest->TargetName.MaximumLength = tktinfo->ServerName.Length;
+    pTicketRequest->TargetName.Buffer = (PWSTR) (pTicketRequest + 1);
+    memcpy(pTicketRequest->TargetName.Buffer,tktinfo->ServerName.Buffer, tktinfo->ServerName.Length);
+    pTicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_CACHE_TICKET;
+    pTicketRequest->EncryptionType = tktinfo->SessionKeyType;
+    pTicketRequest->TicketFlags = 0;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwardable )
+        pTicketRequest->TicketFlags |= KDC_OPT_FORWARDABLE;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_forwarded )
+        pTicketRequest->TicketFlags |= KDC_OPT_FORWARDED;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_proxiable )
+        pTicketRequest->TicketFlags |= KDC_OPT_PROXIABLE;
+    if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_renewable )
+        pTicketRequest->TicketFlags |= KDC_OPT_RENEWABLE;
+
+    Status = LsaCallAuthenticationPackage(
+        LogonHandle,
+        PackageId,
+        pTicketRequest,
+        RequestSize,
+        &pTicketResponse,
+        &ResponseSize,
+        &SubStatus
+        );
+
+    LocalFree(pTicketRequest);
+
+    if (FAILED(Status) || FAILED(SubStatus))
+        return(FALSE);
+    
+    /* otherwise return ticket */
+    *ticket = &(pTicketResponse->Ticket);
+
+    
+    /* set the initial flag if we were attempting to retrieve one
+    * because Windows won't necessarily return the initial ticket
+    * to us.
+    */
+   if ( tktinfo->TicketFlags & KERB_TICKET_FLAGS_initial )
+       (*ticket)->TicketFlags |= KERB_TICKET_FLAGS_initial;
+
+    return(TRUE);
+}
+#endif /* HAVE_CACHE_INFO_EX2 */
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_close
+        (krb5_context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_destroy
+        (krb5_context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_end_seq_get
+        (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_generate_new
+        (krb5_context, krb5_ccache *id);
+
+static const char * KRB5_CALLCONV krb5_lcc_get_name
+        (krb5_context, krb5_ccache id);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_get_principal
+        (krb5_context, krb5_ccache id, krb5_principal *princ);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_initialize
+        (krb5_context, krb5_ccache id, krb5_principal princ);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_next_cred
+        (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor,
+	 krb5_creds *creds);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_resolve
+        (krb5_context, krb5_ccache *id, const char *residual);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_retrieve
+        (krb5_context, krb5_ccache id, krb5_flags whichfields,
+	 krb5_creds *mcreds, krb5_creds *creds);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_start_seq_get
+        (krb5_context, krb5_ccache id, krb5_cc_cursor *cursor);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_store
+        (krb5_context, krb5_ccache id, krb5_creds *creds);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_set_flags
+        (krb5_context, krb5_ccache id, krb5_flags flags);
+
+static krb5_error_code KRB5_CALLCONV krb5_lcc_get_flags
+        (krb5_context, krb5_ccache id, krb5_flags *flags);
+
+extern const krb5_cc_ops krb5_lcc_ops;
+
+krb5_error_code krb5_change_cache (void);
+
+krb5_boolean
+krb5int_cc_creds_match_request(krb5_context, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds);
+
+#define KRB5_OK 0
+
+typedef struct _krb5_lcc_data {
+    HANDLE LogonHandle;
+    ULONG  PackageId;
+    char * cc_name;
+    krb5_principal princ;
+    krb5_flags flags;
+} krb5_lcc_data;
+
+typedef struct _krb5_lcc_cursor {
+    union {
+        PKERB_QUERY_TKT_CACHE_RESPONSE w2k;
+        PKERB_QUERY_TKT_CACHE_EX_RESPONSE xp;
+#ifdef HAVE_CACHE_INFO_EX2
+        PKERB_QUERY_TKT_CACHE_EX2_RESPONSE ex2;
+#endif /* HAVE_CACHE_INFO_EX2 */
+    } response;
+    unsigned int index;
+    PKERB_EXTERNAL_TICKET mstgt;
+} krb5_lcc_cursor;
+
+
+/*
+ * Requires:
+ * residual is ignored
+ *
+ * Modifies:
+ * id
+ * 
+ * Effects:
+ * Acccess the MS Kerberos LSA cache in the current logon session
+ * Ignore the residual.
+ * 
+ * Returns:
+ * A filled in krb5_ccache structure "id".
+ *
+ * Errors:
+ * KRB5_CC_NOMEM - there was insufficient memory to allocate the
+ * 
+ * 		krb5_ccache.  id is undefined.
+ * permission errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
+{
+    krb5_ccache lid;
+    krb5_lcc_data *data;
+    HANDLE LogonHandle;
+    ULONG  PackageId;
+    KERB_EXTERNAL_TICKET *msticket;
+    krb5_error_code retval = KRB5_OK;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+#ifdef COMMENT
+    /* In at least one case on Win2003 it appears that it is possible 
+     * for the logon session to be authenticated via NTLM and yet for
+     * there to be Kerberos credentials obtained by the LSA on behalf
+     * of the logged in user.  Therefore, we are removing this test
+     * which was meant to avoid the need to perform GetMSTGT() when
+     * there was no possibility of credentials being found.
+     */
+    if (!IsKerberosLogon())
+        return KRB5_FCC_NOFILE;
+#endif
+
+    if (!PackageConnectLookup(&LogonHandle, &PackageId))
+        return KRB5_FCC_NOFILE;
+
+    lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
+    if (lid == NULL) {
+        CloseHandle(LogonHandle);
+        return KRB5_CC_NOMEM;
+    }
+
+    lid->ops = &krb5_lcc_ops;
+
+    lid->data = (krb5_pointer) malloc(sizeof(krb5_lcc_data));
+    if (lid->data == NULL) {
+        krb5_xfree(lid);
+        CloseHandle(LogonHandle);
+        return KRB5_CC_NOMEM;
+    }
+
+    lid->magic = KV5M_CCACHE;
+    data = (krb5_lcc_data *)lid->data;    
+    data->LogonHandle = LogonHandle;
+    data->PackageId = PackageId;
+    data->princ = 0;
+
+    data->cc_name = (char *)malloc(strlen(residual)+1);
+    if (data->cc_name == NULL) {
+        krb5_xfree(lid->data);
+        krb5_xfree(lid);
+        CloseHandle(LogonHandle);
+        return KRB5_CC_NOMEM;
+    }
+    strcpy(data->cc_name, residual);
+
+    /*
+     * we must obtain a tgt from the cache in order to determine the principal
+     */
+    if (GetMSTGT(context, data->LogonHandle, data->PackageId, &msticket, FALSE)) {
+        /* convert the ticket */
+        krb5_creds creds;
+        if (!MSCredToMITCred(msticket, msticket->DomainName, context, &creds))
+            retval = KRB5_FCC_INTERNAL;
+        LsaFreeReturnBuffer(msticket);
+
+        if (retval == KRB5_OK)
+            krb5_copy_principal(context, creds.client, &data->princ);
+        krb5_free_cred_contents(context,&creds);
+    } else if (!does_retrieve_ticket_cache_ticket()) {
+        krb5_xfree(data->cc_name);
+        krb5_xfree(lid->data);
+        krb5_xfree(lid);
+        CloseHandle(LogonHandle);
+        return KRB5_FCC_NOFILE;
+    }
+
+    /*
+     * other routines will get errors on open, and callers must expect them,
+     * if cache is non-existent/unusable 
+     */
+    *id = lid;
+    return retval;
+}
+
+/*
+*  return success although we do not do anything
+*  We should delete all tickets belonging to the specified principal
+*/
+
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_remove_cred(krb5_context context, krb5_ccache id, krb5_flags flags,
+                     krb5_creds *creds);
+
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
+{
+    krb5_cc_cursor cursor;
+    krb5_error_code code;
+    krb5_creds cred;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    code = krb5_cc_start_seq_get(context, id, &cursor);
+    if (code) {
+        if (code == KRB5_CC_NOTFOUND)
+            return KRB5_OK;
+        return code;
+    }
+
+    while ( !(code = krb5_cc_next_cred(context, id, &cursor, &cred)) )
+    {
+        if ( krb5_principal_compare(context, princ, cred.client) ) {
+            code = krb5_lcc_remove_cred(context, id, 0, &cred);
+        }
+        krb5_free_cred_contents(context, &cred);
+    }
+
+    if (code == KRB5_CC_END || code == KRB5_CC_NOTFOUND)
+    {
+        krb5_cc_end_seq_get(context, id, &cursor);
+        return KRB5_OK;
+    }
+    return code;
+}
+
+/*
+ * Modifies:
+ * id
+ *
+ * Effects:
+ * Closes the microsoft lsa cache, invalidates the id, and frees any resources
+ * associated with the cache.
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_close(krb5_context context, krb5_ccache id)
+{
+    register int closeval = KRB5_OK;
+    register krb5_lcc_data *data;
+    
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    if (id) {
+        data = (krb5_lcc_data *) id->data;
+
+        if (data) {
+            CloseHandle(data->LogonHandle);
+            krb5_xfree(data);
+        }
+        krb5_xfree(id);
+    }
+    return closeval;
+}
+
+/*
+ * Effects:
+ * Destroys the contents of id.
+ *
+ * Errors:
+ * system errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_destroy(krb5_context context, krb5_ccache id)
+{
+    register krb5_lcc_data *data;
+    
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    if (id) { 
+        data = (krb5_lcc_data *) id->data;
+
+        return PurgeAllTickets(data->LogonHandle, data->PackageId) ? KRB5_OK : KRB5_FCC_INTERNAL;
+    }   
+    return KRB5_FCC_INTERNAL;
+}
+
+/*
+ * Effects:
+ * Prepares for a sequential search of the credentials cache.
+ * Returns a krb5_cc_cursor to be used with krb5_lcc_next_cred and
+ * krb5_lcc_end_seq_get.
+ *
+ * If the cache is modified between the time of this call and the time
+ * of the final krb5_lcc_end_seq_get, the results are undefined.
+ *
+ * Errors:
+ * KRB5_CC_NOMEM
+ * KRB5_FCC_INTERNAL - system errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_start_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
+{
+    krb5_lcc_cursor *lcursor;
+    krb5_lcc_data *data = (krb5_lcc_data *)id->data;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    lcursor = (krb5_lcc_cursor *) malloc(sizeof(krb5_lcc_cursor));
+    if (lcursor == NULL) {
+        *cursor = 0;
+        return KRB5_CC_NOMEM;
+    }
+
+    /*
+     * obtain a tgt to refresh the ccache in case the ticket is expired
+     */
+    if (!GetMSTGT(context, data->LogonHandle, data->PackageId, &lcursor->mstgt, TRUE)) {
+        free(lcursor);
+        *cursor = 0;
+        return KRB5_CC_NOTFOUND;
+    }
+
+#ifdef HAVE_CACHE_INFO_EX2
+    if ( does_query_ticket_cache_ex2() ) {
+        if ( !GetQueryTktCacheResponseEX2(data->LogonHandle, data->PackageId, &lcursor->response.ex2) ) {
+            LsaFreeReturnBuffer(lcursor->mstgt);
+            free(lcursor);
+            *cursor = 0;
+            return KRB5_FCC_INTERNAL;
+        }
+    } else 
+#endif /* HAVE_CACHE_INFO_EX2 */
+    if ( is_windows_xp() ) {
+        if ( !GetQueryTktCacheResponseXP(data->LogonHandle, data->PackageId, &lcursor->response.xp) ) {
+            LsaFreeReturnBuffer(lcursor->mstgt);
+            free(lcursor);
+            *cursor = 0;
+            return KRB5_FCC_INTERNAL;
+        }
+    } else {
+        if ( !GetQueryTktCacheResponseW2K(data->LogonHandle, data->PackageId, &lcursor->response.w2k) ) {
+            LsaFreeReturnBuffer(lcursor->mstgt);
+            free(lcursor);
+            *cursor = 0;
+            return KRB5_FCC_INTERNAL;
+        }
+    }
+    lcursor->index = 0;
+    *cursor = (krb5_cc_cursor) lcursor;
+    return KRB5_OK;
+}
+
+
+/*
+ * Requires:
+ * cursor is a krb5_cc_cursor originally obtained from
+ * krb5_lcc_start_seq_get.
+ *
+ * Modifes:
+ * cursor
+ * 
+ * Effects:
+ * Fills in creds with the TGT obtained from the MS LSA
+ *
+ * The cursor is updated to indicate TGT retrieval
+ *
+ * Errors:
+ * KRB5_CC_END
+ * KRB5_FCC_INTERNAL - system errors
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor, krb5_creds *creds)
+{
+    krb5_lcc_cursor *lcursor = (krb5_lcc_cursor *) *cursor;
+    krb5_lcc_data *data;
+    KERB_EXTERNAL_TICKET *msticket;
+    krb5_error_code  retval = KRB5_OK;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    data = (krb5_lcc_data *)id->data;
+
+  next_cred:
+#ifdef HAVE_CACHE_INFO_EX2
+    if ( does_query_ticket_cache_ex2() ) {
+        if ( lcursor->index >= lcursor->response.ex2->CountOfTickets ) {
+            if (retval == KRB5_OK)
+                return KRB5_CC_END;
+            else {
+                LsaFreeReturnBuffer(lcursor->mstgt);
+                LsaFreeReturnBuffer(lcursor->response.ex2);
+                free(*cursor);
+                *cursor = 0;
+                return retval;
+            }
+        }
+
+        if ( data->flags & KRB5_TC_NOTICKET ) {
+             CacheInfoEx2ToMITCred( &lcursor->response.ex2->Tickets[lcursor->index++], 
+                                    context, creds);
+            return KRB5_OK;
+        } else {
+            if (!GetMSCacheTicketFromCacheInfoEX2(data->LogonHandle, data->PackageId,
+                                                      &lcursor->response.ex2->Tickets[lcursor->index++],&msticket)) {
+                retval = KRB5_FCC_INTERNAL;
+                goto next_cred;
+            }
+        }
+    } else 
+#endif /* HAVE_CACHE_INFO_EX2 */
+    if ( is_windows_xp() ) {
+        if ( lcursor->index >= lcursor->response.xp->CountOfTickets ) {
+            if (retval == KRB5_OK)
+                return KRB5_CC_END;
+            else {
+                LsaFreeReturnBuffer(lcursor->mstgt);
+                LsaFreeReturnBuffer(lcursor->response.xp);
+                free(*cursor);
+                *cursor = 0;
+                return retval;
+            }
+        }
+
+        if (!GetMSCacheTicketFromCacheInfoXP(data->LogonHandle, data->PackageId,
+                                            &lcursor->response.xp->Tickets[lcursor->index++],&msticket)) {
+            retval = KRB5_FCC_INTERNAL;
+            goto next_cred;
+        }
+    } else {
+        if ( lcursor->index >= lcursor->response.w2k->CountOfTickets ) {
+            if (retval == KRB5_OK)
+                return KRB5_CC_END;
+            else {
+                LsaFreeReturnBuffer(lcursor->mstgt);
+                LsaFreeReturnBuffer(lcursor->response.w2k);
+                free(*cursor);
+                *cursor = 0;
+                return retval;
+            }
+        }
+
+        if (!GetMSCacheTicketFromCacheInfoW2K(data->LogonHandle, data->PackageId,
+                                            &lcursor->response.w2k->Tickets[lcursor->index++],&msticket)) {
+            retval = KRB5_FCC_INTERNAL;
+            goto next_cred;
+        }
+    }
+
+    /* Don't return tickets with NULL Session Keys */
+    if ( msticket->SessionKey.KeyType == KERB_ETYPE_NULL) {
+        LsaFreeReturnBuffer(msticket);
+        goto next_cred;
+    }
+
+    /* convert the ticket */
+#ifdef HAVE_CACHE_INFO_EX2
+    if ( does_query_ticket_cache_ex2() ) {
+        if (!MSCredToMITCred(msticket, lcursor->response.ex2->Tickets[lcursor->index-1].ClientRealm, context, creds))
+            retval = KRB5_FCC_INTERNAL;
+    } else 
+#endif /* HAVE_CACHE_INFO_EX2 */
+    if ( is_windows_xp() ) {
+        if (!MSCredToMITCred(msticket, lcursor->response.xp->Tickets[lcursor->index-1].ClientRealm, context, creds))
+            retval = KRB5_FCC_INTERNAL;
+    } else {
+        if (!MSCredToMITCred(msticket, lcursor->mstgt->DomainName, context, creds))
+            retval = KRB5_FCC_INTERNAL;
+    }
+    LsaFreeReturnBuffer(msticket);
+    return retval;
+}
+
+/*
+ * Requires:
+ * cursor is a krb5_cc_cursor originally obtained from
+ * krb5_lcc_start_seq_get.
+ *
+ * Modifies:
+ * id, cursor
+ *
+ * Effects:
+ * Finishes sequential processing of the file credentials ccache id,
+ * and invalidates the cursor (it must never be used after this call).
+ */
+/* ARGSUSED */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
+{
+    krb5_lcc_cursor *lcursor = (krb5_lcc_cursor *) *cursor;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    if ( lcursor ) {
+        LsaFreeReturnBuffer(lcursor->mstgt);
+#ifdef HAVE_CACHE_INFO_EX2
+        if ( does_query_ticket_cache_ex2() )
+            LsaFreeReturnBuffer(lcursor->response.ex2);
+        else 
+#endif /* HAVE_CACHE_INFO_EX2 */
+        if ( is_windows_xp() )
+            LsaFreeReturnBuffer(lcursor->response.xp);
+        else
+            LsaFreeReturnBuffer(lcursor->response.w2k);
+        free(*cursor);
+    }
+    *cursor = 0;
+
+    return KRB5_OK;
+}
+
+
+/*
+ * Errors:
+ * KRB5_CC_READONLY - not supported
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_generate_new (krb5_context context, krb5_ccache *id)
+{
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    return KRB5_CC_READONLY;
+}
+
+/*
+ * Requires:
+ * id is a ms lsa credential cache
+ * 
+ * Returns:
+ *   The ccname specified during the krb5_lcc_resolve call
+ */
+static const char * KRB5_CALLCONV
+krb5_lcc_get_name (krb5_context context, krb5_ccache id)
+{
+
+    if (!is_windows_2000())
+        return "";
+
+    if ( !id )
+        return "";
+
+    return (char *) ((krb5_lcc_data *) id->data)->cc_name;
+}
+
+/*
+ * Modifies:
+ * id, princ
+ *
+ * Effects:
+ * Retrieves the primary principal from id, as set with
+ * krb5_lcc_initialize.  The principal is returned is allocated
+ * storage that must be freed by the caller via krb5_free_principal.
+ *
+ * Errors:
+ * system errors
+ * KRB5_CC_NOT_KTYPE
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
+{
+    krb5_lcc_data *data = (krb5_lcc_data *)id->data;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    /* obtain principal */
+    if (data->princ)
+        return krb5_copy_principal(context, data->princ, princ);
+    else {
+        /*
+         * we must obtain a tgt from the cache in order to determine the principal
+         */
+        KERB_EXTERNAL_TICKET *msticket;
+        if (GetMSTGT(context, data->LogonHandle, data->PackageId, &msticket, FALSE)) {
+            /* convert the ticket */
+            krb5_creds creds;
+            if (!MSCredToMITCred(msticket, msticket->DomainName, context, &creds))
+            {
+                LsaFreeReturnBuffer(msticket);
+                return KRB5_FCC_INTERNAL;
+            }
+            LsaFreeReturnBuffer(msticket);
+
+            krb5_copy_principal(context, creds.client, &data->princ);
+            krb5_free_cred_contents(context,&creds);
+            return krb5_copy_principal(context, data->princ, princ);
+        }    
+    }
+    return KRB5_CC_NOTFOUND;
+}
+
+     
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields, 
+                  krb5_creds *mcreds, krb5_creds *creds)
+{
+    krb5_error_code kret = KRB5_OK;
+    krb5_lcc_data *data = (krb5_lcc_data *)id->data;
+    KERB_EXTERNAL_TICKET *msticket = 0, *mstgt = 0, *mstmp = 0;
+    krb5_creds * mcreds_noflags = 0;
+    krb5_creds   fetchcreds;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    memset(&fetchcreds, 0, sizeof(krb5_creds));
+
+    /* first try to find out if we have an existing ticket which meets the requirements */
+    kret = krb5_cc_retrieve_cred_default (context, id, whichfields, mcreds, creds);
+    if ( !kret )
+        return KRB5_OK;
+    
+    /* if not, we must try to get a ticket without specifying any flags or etypes */
+    kret = krb5_copy_creds(context, mcreds, &mcreds_noflags);
+    if (kret)
+        goto cleanup;
+    mcreds_noflags->ticket_flags = 0;
+    mcreds_noflags->keyblock.enctype = 0;
+
+    if (!GetMSCacheTicketFromMITCred(data->LogonHandle, data->PackageId, context, mcreds_noflags, &msticket)) {
+        kret = KRB5_CC_NOTFOUND;
+        goto cleanup;
+    }
+
+    /* try again to find out if we have an existing ticket which meets the requirements */
+    kret = krb5_cc_retrieve_cred_default (context, id, whichfields, mcreds, creds);
+    if ( !kret )
+        goto cleanup;
+
+    /* if not, obtain a ticket using the request flags and enctype even though it may not
+     * be stored in the LSA cache for future use.
+     */
+    if ( msticket ) {
+        LsaFreeReturnBuffer(msticket);
+        msticket = 0;
+    }
+
+    if (!GetMSCacheTicketFromMITCred(data->LogonHandle, data->PackageId, context, mcreds, &msticket)) {
+        kret = KRB5_CC_NOTFOUND;
+        goto cleanup;
+    }
+
+    /* convert the ticket */
+    if ( !is_windows_xp() || !does_retrieve_ticket_cache_ticket() ) {
+        if ( PreserveInitialTicketIdentity() )
+            GetMSTGT(context, data->LogonHandle, data->PackageId, &mstgt, FALSE);
+
+        if (!MSCredToMITCred(msticket, mstgt ? mstgt->DomainName : msticket->DomainName, context, &fetchcreds))
+        {
+            kret = KRB5_FCC_INTERNAL;
+            goto cleanup;
+        }
+    } else {
+        /* We can obtain the correct client realm for a ticket by walking the
+         * cache contents until we find the matching service ticket.
+         */
+        PKERB_QUERY_TKT_CACHE_EX_RESPONSE pResponse = 0;
+        unsigned int i;
+
+        if (!GetQueryTktCacheResponseXP( data->LogonHandle, data->PackageId, &pResponse)) {
+            kret = KRB5_FCC_INTERNAL;
+            goto cleanup;
+        }
+
+        for ( i=0; i<pResponse->CountOfTickets; i++ ) {
+            if (!GetMSCacheTicketFromCacheInfoXP(data->LogonHandle, data->PackageId,
+                                                  &pResponse->Tickets[i],&mstmp)) {
+                continue;
+            }
+
+            if ( KerbExternalTicketMatch(msticket,mstmp) )
+                break;
+
+            LsaFreeReturnBuffer(mstmp);
+            mstmp = 0;
+        }
+
+        if (!MSCredToMITCred(msticket, mstmp ? pResponse->Tickets[i].ClientRealm : msticket->DomainName, context, &fetchcreds))
+        {
+            LsaFreeReturnBuffer(pResponse);
+            kret = KRB5_FCC_INTERNAL;
+            goto cleanup;
+        }
+        LsaFreeReturnBuffer(pResponse);
+    }
+
+
+    /* check to see if this ticket matches the request using logic from
+     * krb5_cc_retrieve_cred_default()
+     */
+    if ( krb5int_cc_creds_match_request(context, whichfields, mcreds, &fetchcreds) ) {
+        *creds = fetchcreds;
+    } else {
+        krb5_free_cred_contents(context, &fetchcreds);
+        kret = KRB5_CC_NOTFOUND;
+    }
+
+  cleanup:
+    if ( mstmp )
+        LsaFreeReturnBuffer(mstmp);
+    if ( mstgt )
+        LsaFreeReturnBuffer(mstgt);
+    if ( msticket )
+        LsaFreeReturnBuffer(msticket);
+    if ( mcreds_noflags )
+        krb5_free_creds(context, mcreds_noflags);
+    return kret;
+}
+
+
+/*
+ * We can't write to the MS LSA cache.  So we request the cache to obtain a ticket for the same
+ * principal in the hope that next time the application requires a ticket for the service it
+ * is attempt to store, the retrieved ticket will be good enough.
+ *
+ * Errors:
+ * KRB5_CC_READONLY - not supported
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
+{
+    krb5_error_code kret = KRB5_OK;
+    krb5_lcc_data *data = (krb5_lcc_data *)id->data;
+    KERB_EXTERNAL_TICKET *msticket = 0, *msticket2 = 0;
+    krb5_creds * creds_noflags = 0;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+#ifdef KERB_SUBMIT_TICKET
+    /* we can use the new KerbSubmitTicketMessage to store the ticket */
+    if (KerbSubmitTicket( data->LogonHandle, data->PackageId, context, creds ))
+        return KRB5_OK;
+#endif /* KERB_SUBMIT_TICKET */
+
+    /* If not, lets try to obtain a matching ticket from the KDC */
+    if ( creds->ticket_flags != 0 && creds->keyblock.enctype != 0 ) {
+        /* if not, we must try to get a ticket without specifying any flags or etypes */
+        kret = krb5_copy_creds(context, creds, &creds_noflags);
+        if (kret == 0) {
+            creds_noflags->ticket_flags = 0;
+            creds_noflags->keyblock.enctype = 0;
+
+            GetMSCacheTicketFromMITCred(data->LogonHandle, data->PackageId, context, creds_noflags, &msticket2);
+            krb5_free_creds(context, creds_noflags);
+        }
+    }
+
+    GetMSCacheTicketFromMITCred(data->LogonHandle, data->PackageId, context, creds, &msticket);
+    if (msticket || msticket2) {
+        if (msticket)
+            LsaFreeReturnBuffer(msticket);
+        if (msticket2)
+            LsaFreeReturnBuffer(msticket2);
+        return KRB5_OK;
+    }
+    return KRB5_CC_READONLY;
+}
+
+/* 
+ * Individual credentials can be implemented differently depending
+ * on the operating system version.  (undocumented.)
+ * 
+ * Errors:
+ *    KRB5_CC_READONLY: 
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_remove_cred(krb5_context context, krb5_ccache id, krb5_flags flags,
+                     krb5_creds *creds)
+{
+    krb5_lcc_data *data = (krb5_lcc_data *)id->data;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    if (!is_windows_xp()) {
+        if ( PurgeTicket2000( data->LogonHandle, data->PackageId, context, creds) )
+            return KRB5_OK;
+    } else {
+        if ( PurgeTicketXP( data->LogonHandle, data->PackageId, context, flags, creds) )
+            return KRB5_OK;
+    }
+
+    return KRB5_CC_READONLY;
+}
+
+
+/*
+ * Effects:
+ *   Set
+ */
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
+{
+    krb5_lcc_data *data = (krb5_lcc_data *)id->data;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    data->flags = flags;
+    return KRB5_OK;
+}
+
+static krb5_error_code KRB5_CALLCONV
+krb5_lcc_get_flags(krb5_context context, krb5_ccache id, krb5_flags *flags)
+{
+    krb5_lcc_data *data = (krb5_lcc_data *)id->data;
+
+    if (!is_windows_2000())
+        return KRB5_FCC_NOFILE;
+
+    *flags = data->flags;
+    return KRB5_OK;
+}
+
+const krb5_cc_ops krb5_lcc_ops = {
+     0,
+     "MSLSA",
+     krb5_lcc_get_name,
+     krb5_lcc_resolve,
+     krb5_lcc_generate_new,
+     krb5_lcc_initialize,
+     krb5_lcc_destroy,
+     krb5_lcc_close,
+     krb5_lcc_store,
+     krb5_lcc_retrieve,
+     krb5_lcc_get_principal,
+     krb5_lcc_start_seq_get,
+     krb5_lcc_next_cred,
+     krb5_lcc_end_seq_get,
+     krb5_lcc_remove_cred,
+     krb5_lcc_set_flags,
+     krb5_lcc_get_flags
+};
+#endif /* _WIN32 */
diff --git a/mechglue/src/lib/krb5/ccache/cc_retr.c b/mechglue/src/lib/krb5/ccache/cc_retr.c
new file mode 100644
index 000000000..cadd3e5fe
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/cc_retr.c
@@ -0,0 +1,289 @@
+/*
+ * lib/krb5/ccache/cc_retr.c
+ *
+ * Copyright 1990,1991,1999 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+#include "k5-int.h"
+#include "cc-int.h"
+
+#define KRB5_OK 0
+
+#define set(bits) (whichfields & bits)
+#define flags_match(a,b) (((a) & (b)) == (a))
+#define times_match_exact(t1,t2) (memcmp((char *)(t1), (char *)(t2), sizeof(*(t1))) == 0)
+
+static krb5_boolean
+times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2)
+{
+    if (t1->renew_till) {
+	if (t1->renew_till > t2->renew_till)
+	    return FALSE;		/* this one expires too late */
+    }
+    if (t1->endtime) {
+	if (t1->endtime > t2->endtime)
+	    return FALSE;		/* this one expires too late */
+    }
+    /* only care about expiration on a times_match */
+    return TRUE;
+}
+
+static krb5_boolean
+standard_fields_match(krb5_context context, const krb5_creds *mcreds, const krb5_creds *creds)
+{
+  return (krb5_principal_compare(context, mcreds->client,creds->client)
+	  && krb5_principal_compare(context, mcreds->server,creds->server));
+}
+
+/* only match the server name portion, not the server realm portion */
+
+static krb5_boolean
+srvname_match(krb5_context context, const krb5_creds *mcreds, const krb5_creds *creds)
+{
+    krb5_boolean retval;
+    krb5_principal_data p1, p2;
+    
+    retval = krb5_principal_compare(context, mcreds->client,creds->client);
+    if (retval != TRUE)
+	return retval;
+    /*
+     * Hack to ignore the server realm for the purposes of the compare.
+     */
+    p1 = *mcreds->server;
+    p2 = *creds->server;
+    p1.realm = p2.realm;
+    return krb5_principal_compare(context, &p1, &p2);
+}
+
+static krb5_boolean
+authdata_match(krb5_authdata *const *mdata, krb5_authdata *const *data)
+{
+    const krb5_authdata *mdatap, *datap;
+
+    if (mdata == data)
+      return TRUE;
+
+    if (mdata == NULL)
+	return *data == NULL;
+	
+    if (data == NULL)
+	return *mdata == NULL;
+    
+    while ((mdatap = *mdata) && (datap = *data)) {
+      if ((mdatap->ad_type != datap->ad_type) ||
+          (mdatap->length != datap->length) ||
+          (memcmp ((char *)mdatap->contents,
+		 (char *)datap->contents, (unsigned) mdatap->length) != 0))
+          return FALSE;
+      mdata++;
+      data++;
+    }
+    return (*mdata == NULL) && (*data == NULL);
+}
+
+static krb5_boolean
+data_match(const krb5_data *data1, const krb5_data *data2)
+{
+    if (!data1) {
+	if (!data2)
+	    return TRUE;
+	else
+	    return FALSE;
+    }
+    if (!data2) return FALSE;
+
+    if (data1->length != data2->length)
+	return FALSE;
+    else
+	return memcmp(data1->data, data2->data, (unsigned) data1->length) 
+	  ? FALSE : TRUE;
+}
+
+static int
+pref (krb5_enctype my_ktype, int nktypes, krb5_enctype *ktypes)
+{
+  int i;
+  for (i = 0; i < nktypes; i++)
+    if (my_ktype == ktypes[i])
+      return i;
+  return -1;
+}
+
+/*
+ * Effects:
+ * Searches the credentials cache for a credential matching mcreds,
+ * with the fields specified by whichfields.  If one if found, it is
+ * returned in creds, which should be freed by the caller with
+ * krb5_free_credentials().
+ * 
+ * The fields are interpreted in the following way (all constants are
+ * preceded by KRB5_TC_).  MATCH_IS_SKEY requires the is_skey field to
+ * match exactly.  MATCH_TIMES requires the requested lifetime to be
+ * at least as great as that specified; MATCH_TIMES_EXACT requires the
+ * requested lifetime to be exactly that specified.  MATCH_FLAGS
+ * requires only the set bits in mcreds be set in creds;
+ * MATCH_FLAGS_EXACT requires all bits to match.
+ *
+ * Flag SUPPORTED_KTYPES means check all matching entries that have
+ * any supported enctype (according to tgs_enctypes) and return the one
+ * with the enctype listed earliest.  Return CC_NOT_KTYPE if a match
+ * is found *except* for having a supported enctype.
+ *
+ * Errors:
+ * system errors
+ * permission errors
+ * KRB5_CC_NOMEM
+ * KRB5_CC_NOT_KTYPE
+ */
+
+krb5_boolean
+krb5int_cc_creds_match_request(krb5_context context, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds)
+{
+    if (((set(KRB5_TC_MATCH_SRV_NAMEONLY) &&
+		   srvname_match(context, mcreds, creds)) ||
+	       standard_fields_match(context, mcreds, creds))
+	      &&
+	      (! set(KRB5_TC_MATCH_IS_SKEY) ||
+	       mcreds->is_skey == creds->is_skey)
+	      &&
+	      (! set(KRB5_TC_MATCH_FLAGS_EXACT) ||
+	       mcreds->ticket_flags == creds->ticket_flags)
+	      &&
+	      (! set(KRB5_TC_MATCH_FLAGS) ||
+	       flags_match(mcreds->ticket_flags, creds->ticket_flags))
+	      &&
+	      (! set(KRB5_TC_MATCH_TIMES_EXACT) ||
+	       times_match_exact(&mcreds->times, &creds->times))
+	      &&
+	      (! set(KRB5_TC_MATCH_TIMES) ||
+	       times_match(&mcreds->times, &creds->times))
+	      &&
+	      ( ! set(KRB5_TC_MATCH_AUTHDATA) ||
+	       authdata_match(mcreds->authdata, creds->authdata))
+	      &&
+	      (! set(KRB5_TC_MATCH_2ND_TKT) ||
+	       data_match (&mcreds->second_ticket, &creds->second_ticket))
+	      &&
+	     ((! set(KRB5_TC_MATCH_KTYPE))||
+		(mcreds->keyblock.enctype == creds->keyblock.enctype)))
+        return TRUE;
+    return FALSE;
+}
+
+static krb5_error_code
+krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id,
+			   krb5_flags whichfields, krb5_creds *mcreds,
+			   krb5_creds *creds, int nktypes, krb5_enctype *ktypes)
+{
+     /* This function could be considerably faster if it kept indexing */
+     /* information.. sounds like a "next version" idea to me. :-) */
+
+     krb5_cc_cursor cursor;
+     krb5_error_code kret;
+     krb5_error_code nomatch_err = KRB5_CC_NOTFOUND;
+     struct {
+       krb5_creds creds;
+       int pref;
+     } fetched, best;
+     int have_creds = 0;
+     krb5_flags oflags = 0;
+#define fetchcreds (fetched.creds)
+
+     kret = krb5_cc_get_flags(context, id, &oflags);
+     if (kret != KRB5_OK)
+	  return kret;
+     if (oflags & KRB5_TC_OPENCLOSE)
+	 (void) krb5_cc_set_flags(context, id, oflags & ~KRB5_TC_OPENCLOSE);
+     kret = krb5_cc_start_seq_get(context, id, &cursor);
+     if (kret != KRB5_OK) {
+	  if (oflags & KRB5_TC_OPENCLOSE)
+	       krb5_cc_set_flags(context, id, oflags);
+	  return kret;
+     }
+
+     while ((kret = krb5_cc_next_cred(context, id, &cursor, &fetchcreds)) == KRB5_OK) {
+      if (krb5int_cc_creds_match_request(context, whichfields, mcreds, &fetchcreds))
+      {
+	      if (ktypes) {
+		  fetched.pref = pref (fetchcreds.keyblock.enctype,
+				       nktypes, ktypes);
+		  if (fetched.pref < 0)
+		      nomatch_err = KRB5_CC_NOT_KTYPE;
+		  else if (!have_creds || fetched.pref < best.pref) {
+		      if (have_creds)
+			  krb5_free_cred_contents (context, &best.creds);
+		      else
+			  have_creds = 1;
+		      best = fetched;
+		      continue;
+		  }
+	      } else {
+		  krb5_cc_end_seq_get(context, id, &cursor);
+		  *creds = fetchcreds;
+		  if (oflags & KRB5_TC_OPENCLOSE)
+		      krb5_cc_set_flags(context, id, oflags);
+		  return KRB5_OK;
+	      }
+	  }
+
+	  /* This one doesn't match */
+	  krb5_free_cred_contents(context, &fetchcreds);
+     }
+
+     /* If we get here, a match wasn't found */
+     krb5_cc_end_seq_get(context, id, &cursor);
+     if (oflags & KRB5_TC_OPENCLOSE)
+	 krb5_cc_set_flags(context, id, oflags);
+     if (have_creds) {
+	 *creds = best.creds;
+	 return KRB5_OK;
+     } else
+	 return nomatch_err;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_retrieve_cred_default (krb5_context context, krb5_ccache id, krb5_flags flags, krb5_creds *mcreds, krb5_creds *creds)
+{
+    krb5_enctype *ktypes;
+    int nktypes;
+    krb5_error_code ret;
+
+    if (flags & KRB5_TC_SUPPORTED_KTYPES) {
+	ret = krb5_get_tgs_ktypes (context, mcreds->server, &ktypes);
+	if (ret)
+	    return ret;
+	nktypes = 0;
+	while (ktypes[nktypes])
+	    nktypes++;
+
+	ret = krb5_cc_retrieve_cred_seq (context, id, flags, mcreds, creds,
+					 nktypes, ktypes);
+	free (ktypes);
+	return ret;
+    } else {
+	return krb5_cc_retrieve_cred_seq (context, id, flags, mcreds, creds,
+					  0, 0);
+    }
+}
diff --git a/mechglue/src/lib/krb5/ccache/ccapi/ChangeLog b/mechglue/src/lib/krb5/ccache/ccapi/ChangeLog
new file mode 100644
index 000000000..005a0430d
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccapi/ChangeLog
@@ -0,0 +1,232 @@
+2005-11-14  Jeffrey Altman <jaltman@mit.edu>
+
+	* winccld.c, stdcc.c: include k5-int.h before stdcc.h
+
+2004-11-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* stdcc.c (krb5_stdcc_get_flags): New function.
+	(krb5_cc_stdcc_ops): Add it.
+	* stdcc.h (krb5_stdcc_get_flags): Declare.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* stdcc_util.c (dupK5toCC): Don't test macintosh.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-03-06  Alexandra Ellwood <lxs@mit.edu>
+
+    * stdcc.h, stdcc_util.h: Removed Mac header goober.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* winccld.c (krb5_fcc_ops): Updated decl.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* winccld.c: Include k5-int.h to get hidden ops struct.
+	[pullup from 1-2-2-branch]
+
+2002-06-20  Alexandra Ellwood <lxs@mit.edu>
+
+	* stdcc.h: Added prototype for krb5_stdcc_shutdown.
+
+	* stdcc.h, stdcc_util.h, stdcc_util.c: Updated Mac OS X headers to new 
+	framework layout
+
+	* stdcc.c: Removed unused variables and fixed macros to reduce warnings
+
+	[pullups from 1-2-2-branch]
+
+2002-06-20  Miro Jurisic  <meeroh@mit.edu>
+
+	* stdcc.c: Replaced cc_* macros with functions
+	* stdcc.h, stdcc_util.h: Updated Mac OS #defines and #includes for new 
+	header layout and Mac OS X frameworks
+	[pullup from 1-2-2-branch]
+
+2002-04-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* stdcc_util.c: Include errno.h.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* stdcc.h: Make prototypes unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* stdcc.c, stdcc.h, stdcc_util.c, stdcc_util.h, winccld.c: Delete
+	_MSDOS support.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* stdcc.h, winccld.c: Don't use KRB5_DLLIMP.
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* stdcc.c, stdcc.h (krb5_stdcc_get_name): Declare as returning
+	const char *.
+
+2000-07-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* stdcc.h: Include k5-int.h to get krb5_ccache definition.
+
+2000-06-08  Alexandra Ellwood  <lxs@mit.edu>
+
+	* stdcc_util.c (dupCCtoK5, dupK5toCC): 
+		Fixed code that stores times in localtime, not in kdc time.
+
+2000-05-18  Danilo Almeida  <dalmeida@mit.edu>
+
+	* stdcc_util.c (dupK5toCC): Remove unused variables.
+
+	* stdcc_util.c: Reindent to krb5 coding style.  Remove whitespace
+	at end of lines.  Replace C++ comments with C comments.
+
+	* stdcc_util.h: Replace C++ comments with C comments.
+
+	* winccld.h: Do not define or try to load cc_lock_request, which is
+	not actually used anywhere in the code.
+
+2000-05-04  Miro Jurisic  <meeroh@mit.edu>
+
+	* stdcc_util.c (dupCCtoK5, dupK5toCC): 
+		Conditionalized local/KDC time conversions for Mac-only
+		until we figure out what to do about that
+
+2000-04-18  Danilo Almeida  <dalmeida@mit.edu>
+
+	* winccld.h: Define CC_API_VER2 for all Windows code using ccapi.
+	Update dynamic loading declarations to use CC_API_VER2.
+
+	* stdcc.c: Define CC_API_VER2 if not defined rather than just if
+	not Windows.
+
+	* winccld.c (LoadFuncs): Get error on DLL load failure even though
+	we do not use it in case we are doing source-level debugging.
+
+2000-04-07  Jeffrey Altman <jaltman@columbia.edu>
+
+	* stdcc_util.c (copyCCDataArrayToK5, copyCCDataArrayToK5): 
+	* stdcc_util.c (dupCCtoK5, dupK5toCC): 
+
+          memory was being allocated as   (sizeof(foo) * count + 1)
+          instead of                      (sizeof(foo) * (count + 1))
+
+2000-04-03  Jeffrey Altman <jaltman@columbia.edu>
+
+	* stdcc_util.c (copyCCDataArrayToK5, copyCCDataArrayToK5): 
+	* stdcc_util.c (dupCCtoK5, dupK5toCC): 
+
+          Changed all references to the type UInt32 to unsigned int
+          since UInt32 is not a standard type on Unix or Win32    
+
+2000-03-24  Alexandra Ellwood  <lxs@mit.edu>
+
+	* stdcc_util.c (copyCCDataArrayToK5, copyCCDataArrayToK5): 
+		Modified to copy authdata as well... this code may have 
+		bugs since I couldn't get a good case where authdata != NULL
+	
+	* stdcc_util.c (dupCCtoK5, dupK5toCC): 
+		Added code to store times in localtime, not in kdc time.
+
+2000-03-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* stdcc.c (krb5_stdcc_destroy): Do not mask KRB5_FCC_NOFILE error
+	on destroy.
+
+2000-02-10  Miro Jurisic <meeroh@mit.edu>
+
+	* stdcc_util.c: Fixed lxs' fix
+
+2000-02-10  Alexandra Ellwood <lxs@mit.edu>
+
+	* stdcc_util.c: Added +1 to strlen()'s so that the null terminator 
+		will fit in the buffer.
+
+2000-02-04  Scott McGuire  <smcguire@mit.edu>
+
+	* stdcc.c (krb5_stdcc_initialize):  Removed calls that destroyed
+	   and recreated ccapi_data->NamedCache; instead close
+	   and call create on it again.  (This makes sure the data stays
+	   in the same cache the whole time so external pointers don't
+	   get confused.)
+	
+1999-11-22  Miro Jurisic  <meeroh@mit.edu>
+
+	* stdcc.h, stdcc_util.h: use CCache2.h under MacOS for CCAPI v2
+	compatibility
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* stdcc.c (krb5_stdcc_retrieve): Replace with a version that calls
+	krb5_cc_retrieve_cred_default.
+
+1999-08-05	Alexandra Ellwood <lxs@mit.edu>
+
+	* stdcc_util.c (deep_free_cc_v5_creds):
+		Added free(creds) so that the cc_creds gets freed when a 
+		cred_union gets freed.  Before it was leaking memory.
+
+		I searched the k5 sources for folks calling deep_free_cc_v5_creds 
+		and my change seems to not break anyone else.
+	
+1999-08-03	Alexandra Ellwood <lxs@mit.edu>
+	
+	* stdcc.c (krb5_stdcc_destroy):
+		Added code to free the krb5_ccache like krb5_stdcc_close does 
+		so we don't leak memory.
+		
+1999-06-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* stdcc.c (cache_changed): Use PostMessage instead of SendMessage
+		so that we don't block.
+
+1999-06-08  Danilo Almeida  <dalmeida@mit.edu>
+
+	* winccld.h:  Remove references to cc_*_instance functions.
+
+Thu May 13 18:01:58 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* winccld.c (krb5_win_ccdll_load): Register the FILE ccache type
+		if we are using ccapi, so that we make sure the FILE
+		ccache type will work if the user specifies it in an
+		environment variable.
+
+Mon May 10 15:24:36 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Thu Apr  8 16:09:08 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* winccld.c: Only compile this file on Windows (to avoid screwing
+		up the Macintosh build).
+
+1999-03-31  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* winccld.c, winccld.h, stdcc.c: Add files to dynamically load
+		krbcc32.dll, so that we can fall back and use the built-in
+		file ccache type if krbcc32.dll doesn't exist.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
diff --git a/mechglue/src/lib/krb5/ccache/ccapi/Makefile.in b/mechglue/src/lib/krb5/ccache/ccapi/Makefile.in
new file mode 100644
index 000000000..9d99438d6
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccapi/Makefile.in
@@ -0,0 +1,25 @@
+thisconfigdir=./../..
+myfulldir=lib/krb5/ccache/ccapi
+mydir=ccache/ccapi
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
+LOCALINCLUDES = $(WIN_INCLUDES)
+
+##DOS##WIN_INCLUDES = -I$(SRCTOP)\windows\lib
+
+##DOS##BUILDTOP = ..\..\..\..
+##DOS##PREFIXDIR = ccache\file
+##DOS##OBJFILE = $(OUTPRE)file.lst
+
+STLIBOBJS 	= \
+	stdcc.o \
+	stdcc_util.o \
+	winccld.o
+
+OBJS 	= $(OUTPRE)stdcc.$(OBJEXT) $(OUTPRE)stdcc_util.$(OBJEXT) $(OUTPRE)winccld.$(OBJEXT)
+
+SRCS 	= $(srcdir)/stdcc.c $(srcdir)/stdcc_util.c $(srcdir)/winccld.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
diff --git a/mechglue/src/lib/krb5/ccache/ccapi/stdcc.c b/mechglue/src/lib/krb5/ccache/ccapi/stdcc.c
new file mode 100644
index 000000000..885abf5bb
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccapi/stdcc.c
@@ -0,0 +1,772 @@
+/*
+ * stdcc.c - additions to the Kerberos 5 library to support the memory
+ *	 credentical cache API
+ *	
+ * Written by Frank Dabek July 1998
+ *
+ * Copyright 1998, 1999 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#define NEED_WINDOWS
+#include "k5-int.h"
+#include "stdcc.h"
+#include "stdcc_util.h"
+#include "string.h"
+#include <stdio.h>
+
+apiCB *gCntrlBlock = NULL;
+
+#if defined(_WIN32)
+#include "winccld.h"	
+#endif
+
+#ifndef CC_API_VER2
+#define CC_API_VER2
+#endif
+
+#ifdef DEBUG
+#if defined(_WIN32)
+#include <io.h>
+#define SHOW_DEBUG(buf)   MessageBox((HWND)NULL, (buf), "ccapi debug", MB_OK)
+#endif
+	/* XXX need macintosh debugging statement if we want to debug */
+	/* on the mac */
+#else
+#define SHOW_DEBUG(buf)
+#endif
+
+/*
+ * declare our global object wanna-be
+ * must be installed in ccdefops.c
+ */
+
+krb5_cc_ops krb5_cc_stdcc_ops = {
+     0,
+     "API",
+      krb5_stdcc_get_name,
+      krb5_stdcc_resolve,
+      krb5_stdcc_generate_new,
+      krb5_stdcc_initialize,
+      krb5_stdcc_destroy,
+      krb5_stdcc_close,
+      krb5_stdcc_store,
+      krb5_stdcc_retrieve,
+      krb5_stdcc_get_principal,
+      krb5_stdcc_start_seq_get,
+      krb5_stdcc_next_cred,
+      krb5_stdcc_end_seq_get,
+      krb5_stdcc_remove, 
+      krb5_stdcc_set_flags,
+      krb5_stdcc_get_flags,
+};
+
+#if defined(_WIN32)
+/*
+ * cache_changed be called after the cache changes.
+ * A notification message is is posted out to all top level
+ * windows so that they may recheck the cache based on the
+ * changes made.  We register a unique message type with which
+ * we'll communicate to all other processes. 
+ */
+void cache_changed()
+{
+	static unsigned int message = 0;
+	
+	if (message == 0)
+		message = RegisterWindowMessage(WM_KERBEROS5_CHANGED);
+
+	PostMessage(HWND_BROADCAST, message, 0, 0);
+}
+#else /* _WIN32 */
+
+void cache_changed()
+{
+	return;
+}
+#endif /* _WIN32 */
+
+struct err_xlate
+{
+	int	cc_err;
+	krb5_error_code	krb5_err;
+};
+
+static const struct err_xlate err_xlate_table[] =
+{
+	{ CC_BADNAME,				KRB5_CC_BADNAME },
+	{ CC_NOTFOUND,				KRB5_CC_NOTFOUND },
+	{ CC_END,				KRB5_CC_END },
+	{ CC_IO,				KRB5_CC_IO },
+	{ CC_WRITE,				KRB5_CC_WRITE },
+	{ CC_NOMEM,				KRB5_CC_NOMEM },
+	{ CC_FORMAT,				KRB5_CC_FORMAT },
+	{ CC_WRITE,				KRB5_CC_WRITE },
+	{ CC_LOCKED,				KRB5_FCC_INTERNAL /* XXX */ },
+	{ CC_BAD_API_VERSION,			KRB5_FCC_INTERNAL /* XXX */ },
+	{ CC_NO_EXIST,				KRB5_FCC_NOFILE },
+	{ CC_NOT_SUPP,				KRB5_FCC_INTERNAL /* XXX */ },
+	{ CC_BAD_PARM,				KRB5_FCC_INTERNAL /* XXX */ },
+	{ CC_ERR_CACHE_ATTACH,			KRB5_FCC_INTERNAL /* XXX */ },
+	{ CC_ERR_CACHE_RELEASE,			KRB5_FCC_INTERNAL /* XXX */ },
+	{ CC_ERR_CACHE_FULL,			KRB5_FCC_INTERNAL /* XXX */ },
+	{ CC_ERR_CRED_VERSION,			KRB5_FCC_INTERNAL /* XXX */ },
+	{ 0,					0 }
+};
+
+static krb5_error_code cc_err_xlate(int err)
+{
+	const struct err_xlate *p;
+
+	if (err == CC_NOERROR)
+		return 0;
+
+	for (p = err_xlate_table; p->cc_err; p++) {
+		if (err == p->cc_err)
+			return p->krb5_err;
+	}
+	return KRB5_FCC_INTERNAL; /* XXX we need a miscellaneous return */
+}
+
+static krb5_error_code stdcc_setup(krb5_context context,
+				   stdccCacheDataPtr ccapi_data)
+{
+	int	err;
+
+  	/* make sure the API has been intialized */
+  	if (gCntrlBlock == NULL) {
+#ifdef CC_API_VER2
+		err = cc_initialize(&gCntrlBlock, CC_API_VER_2, NULL, NULL);
+#else
+		err = cc_initialize(&gCntrlBlock, CC_API_VER_1, NULL, NULL);
+#endif
+		if (err != CC_NOERROR)
+			return cc_err_xlate(err);
+	}
+
+	/*
+	 * No ccapi_data structure, so we don't need to make sure the
+	 * ccache exists.
+	 */
+	if (!ccapi_data)
+		return 0;
+
+	/*
+	 * The ccache already exists
+	 */
+	if (ccapi_data->NamedCache)
+		return 0;
+
+	err = cc_open(gCntrlBlock, ccapi_data->cache_name,
+		      CC_CRED_V5, 0L, &ccapi_data->NamedCache);
+	if (err == CC_NOTFOUND)
+	  err = CC_NO_EXIST;
+	if (err == CC_NOERROR)
+		return 0;
+
+	ccapi_data->NamedCache = NULL;
+	return cc_err_xlate(err);
+}
+
+void krb5_stdcc_shutdown()
+{
+	if (gCntrlBlock)
+		cc_shutdown(&gCntrlBlock);
+	gCntrlBlock = 0;
+}
+
+/*
+ * -- generate_new --------------------------------
+ * 
+ * create a new cache with a unique name, corresponds to creating a
+ * named cache iniitialize the API here if we have to.
+ */
+krb5_error_code KRB5_CALLCONV  krb5_stdcc_generate_new 
+	(krb5_context context, krb5_ccache *id ) 
+{
+  	krb5_ccache 		newCache = NULL;
+	krb5_error_code		retval;
+	stdccCacheDataPtr	ccapi_data = NULL;
+	char 			*name = NULL;
+	cc_time_t 		time;
+	int 			err;
+
+	if ((retval = stdcc_setup(context, NULL)))
+		return retval;
+	
+	retval = KRB5_CC_NOMEM;
+	if (!(newCache = (krb5_ccache) malloc(sizeof(struct _krb5_ccache))))
+		goto errout;
+  	if (!(ccapi_data = (stdccCacheDataPtr)malloc(sizeof(stdccCacheData))))
+		goto errout;
+	if (!(name = malloc(256)))
+		goto errout;
+	
+  	/* create a unique name */
+  	cc_get_change_time(gCntrlBlock, &time);
+  	sprintf(name, "gen_new_cache%d", time);
+  	
+  	/* create the new cache */
+  	err = cc_create(gCntrlBlock, name, name, CC_CRED_V5, 0L,
+			&ccapi_data->NamedCache);
+	if (err != CC_NOERROR) {
+		retval = cc_err_xlate(err);
+		goto errout;
+	}
+
+  	/* setup some fields */
+  	newCache->ops = &krb5_cc_stdcc_ops;
+  	newCache->data = ccapi_data;
+	ccapi_data->cache_name = name;
+  	
+  	/* return a pointer to the new cache */
+	*id = newCache;
+	  	
+	return 0;
+
+errout:
+	if (newCache)
+		free(newCache);
+	if (ccapi_data)
+		free(ccapi_data);
+	if (name)
+		free(name);
+	return retval;
+}
+  
+/*
+ * resolve
+ *
+ * create a new cache with the name stored in residual
+ */
+krb5_error_code KRB5_CALLCONV  krb5_stdcc_resolve 
+        (krb5_context context, krb5_ccache *id , const char *residual ) 
+{
+	krb5_ccache 		newCache = NULL;
+	stdccCacheDataPtr	ccapi_data = NULL;
+	int 			err;
+	krb5_error_code		retval;
+	char 			*cName = NULL;
+	
+	if ((retval = stdcc_setup(context, NULL)))
+		return retval;
+	
+	retval = KRB5_CC_NOMEM;
+	if (!(newCache = (krb5_ccache) malloc(sizeof(struct _krb5_ccache))))
+		goto errout;
+  	
+  	if (!(ccapi_data = (stdccCacheDataPtr)malloc(sizeof(stdccCacheData))))
+		goto errout;
+
+	if (!(cName = malloc(strlen(residual)+1)))
+		goto errout;
+	
+  	newCache->ops = &krb5_cc_stdcc_ops;
+	newCache->data = ccapi_data;
+	ccapi_data->cache_name = cName;
+
+	strcpy(cName, residual);
+	
+ 	err = cc_open(gCntrlBlock, cName, CC_CRED_V5, 0L,
+		      &ccapi_data->NamedCache);
+	if (err != CC_NOERROR)
+		ccapi_data->NamedCache = NULL;
+	
+  	/* return new cache structure */
+	*id = newCache;
+	
+  	return 0;
+	
+errout:
+	if (newCache)
+		free(newCache);
+	if (ccapi_data)
+		free(ccapi_data);
+	if (cName)
+		free(cName);
+	return retval;
+}
+  
+/*
+ * initialize
+ *
+ * initialize the cache, check to see if one already exists for this
+ * principal if not set our principal to this principal. This
+ * searching enables ticket sharing
+ */
+krb5_error_code KRB5_CALLCONV  krb5_stdcc_initialize 
+       (krb5_context context, krb5_ccache id,  krb5_principal princ) 
+{
+	stdccCacheDataPtr	ccapi_data = NULL;
+  	int 			err;
+  	char 			*cName = NULL;
+	krb5_error_code		retval;
+  	
+	if ((retval = stdcc_setup(context, NULL)))
+		return retval;
+	
+  	/* test id for null */
+  	if (id == NULL) return KRB5_CC_NOMEM;
+  	
+	if ((retval = krb5_unparse_name(context, princ, &cName)))
+		return retval;
+
+	ccapi_data = id->data;
+
+
+	if (ccapi_data->NamedCache)
+		cc_close(gCntrlBlock, &ccapi_data->NamedCache);
+
+	err = cc_create(gCntrlBlock, ccapi_data->cache_name, cName,
+			CC_CRED_V5, 0L, &ccapi_data->NamedCache);
+	if (err != CC_NOERROR) {
+		krb5_free_unparsed_name(context, cName);
+		return cc_err_xlate(err);
+	}
+
+#if 0
+	/*
+	 * Some implementations don't set the principal name
+	 * correctly, so we force set it to the correct value.
+	 */
+	err = cc_set_principal(gCntrlBlock, ccapi_data->NamedCache,
+			       CC_CRED_V5, cName);
+#endif
+	krb5_free_unparsed_name(context, cName);
+	cache_changed();
+	
+	return cc_err_xlate(err);
+}
+
+/*
+ * store
+ *
+ * store some credentials in our cache
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdcc_store 
+        (krb5_context context, krb5_ccache id, krb5_creds *creds )
+{
+	krb5_error_code	retval;
+	stdccCacheDataPtr	ccapi_data = id->data;
+	cred_union *cu = NULL;
+	int err;
+
+	if ((retval = stdcc_setup(context, ccapi_data)))
+		return retval;
+	
+	/* copy the fields from the almost identical structures */
+	dupK5toCC(context, creds, &cu);
+			
+	/*
+	 * finally store the credential
+	 * store will copy (that is duplicate) everything
+	 */
+	err = cc_store(gCntrlBlock,
+		       ((stdccCacheDataPtr)(id->data))->NamedCache, *cu);
+	if (err != CC_NOERROR)
+		return cc_err_xlate(err);
+		
+	/* free the cred union using our local version of cc_free_creds()
+	   since we allocated it locally */
+	err = krb5_free_cc_cred_union(&cu);
+		 
+	cache_changed();
+	return err;
+}
+
+/*
+ * start_seq_get
+ *
+ * begin an iterator call to get all of the credentials in the cache
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdcc_start_seq_get 
+(krb5_context context, krb5_ccache id , krb5_cc_cursor *cursor )
+{
+	stdccCacheDataPtr	ccapi_data = id->data;
+	krb5_error_code	retval;
+	int	err;
+	ccache_cit	*iterator;
+
+	if ((retval = stdcc_setup(context, ccapi_data)))
+		return retval;
+
+#ifdef CC_API_VER2
+	err = cc_seq_fetch_creds_begin(gCntrlBlock, ccapi_data->NamedCache,
+				       &iterator);
+	if (err != CC_NOERROR)
+		return cc_err_xlate(err);
+	*cursor = iterator;
+#else
+	/* all we have to do is initialize the cursor */
+	*cursor = NULL;
+#endif
+	return 0;
+}
+
+/*
+ * next cred
+ * 
+ * - get the next credential in the cache as part of an iterator call
+ * - this maps to call to cc_seq_fetch_creds
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdcc_next_cred 
+        (krb5_context context, krb5_ccache id,  krb5_cc_cursor *cursor, 
+	 krb5_creds *creds)
+{
+	krb5_error_code	retval;
+	stdccCacheDataPtr	ccapi_data = id->data;
+	int err;
+	cred_union *credU = NULL;
+	ccache_cit	*iterator;
+	
+	if ((retval = stdcc_setup(context, ccapi_data)))
+		return retval;
+	
+#ifdef CC_API_VER2
+	iterator = *cursor;
+	if (iterator == 0)
+		return KRB5_CC_END;
+	err = cc_seq_fetch_creds_next(gCntrlBlock, &credU, iterator);
+
+	if (err == CC_END) {
+		cc_seq_fetch_creds_end(gCntrlBlock, &iterator);
+		*cursor = 0;
+	}
+#else
+	err = cc_seq_fetch_creds(gCntrlBlock, ccapi_data->NamedCache,
+				 &credU, (ccache_cit **)cursor); 
+#endif
+
+	if (err != CC_NOERROR)
+		return cc_err_xlate(err);
+	
+	/* copy data	(with translation) */
+	dupCCtoK5(context, credU->cred.pV5Cred, creds);
+	
+	/* free our version of the cred - okay to use cc_free_creds() here
+	   because we got it from the CCache library */
+	cc_free_creds(gCntrlBlock, &credU);
+	
+	return 0;
+}
+
+
+/*
+ * retreive
+ *
+ * - try to find a matching credential in the cache
+ */
+#if 0
+krb5_error_code KRB5_CALLCONV krb5_stdcc_retrieve 
+       		(krb5_context context, 
+		   krb5_ccache id, 
+		   krb5_flags whichfields, 
+		   krb5_creds *mcreds, 
+		   krb5_creds *creds )
+{
+	krb5_error_code	retval;
+	krb5_cc_cursor curs = NULL;
+	krb5_creds *fetchcreds;
+		
+	if ((retval = stdcc_setup(context, NULL)))
+		return retval;
+	
+	fetchcreds = (krb5_creds *)malloc(sizeof(krb5_creds));
+  	if (fetchcreds == NULL) return KRB5_CC_NOMEM;
+	
+	/* we're going to use the iterators */
+	krb5_stdcc_start_seq_get(context, id, &curs);
+	
+	while (!krb5_stdcc_next_cred(context, id, &curs, fetchcreds)) {
+		/*
+		 * look at each credential for a match
+		 * use this match routine since it takes the
+		 * whichfields and the API doesn't
+		 */
+		if (stdccCredsMatch(context, fetchcreds,
+				    mcreds, whichfields)) {
+			/* we found it, copy and exit */
+			*creds = *fetchcreds;
+			krb5_stdcc_end_seq_get(context, id, &curs);
+			return 0;
+		}
+		/* free copy allocated by next_cred */
+		krb5_free_cred_contents(context, fetchcreds);
+	}
+		
+	/* no luck, end get and exit */
+	krb5_stdcc_end_seq_get(context, id, &curs);
+	
+	/* we're not using this anymore so we should get rid of it! */
+	free(fetchcreds);
+	
+	return KRB5_CC_NOTFOUND;
+}
+#else
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_stdcc_retrieve(context, id, whichfields, mcreds, creds)
+   krb5_context context;
+   krb5_ccache id;
+   krb5_flags whichfields;
+   krb5_creds *mcreds;
+   krb5_creds *creds;
+{
+    return krb5_cc_retrieve_cred_default (context, id, whichfields,
+					  mcreds, creds);
+}
+
+#endif
+
+/*
+ *  end seq
+ *
+ * just free up the storage assoicated with the cursor (if we could)
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdcc_end_seq_get 
+        (krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
+{
+	krb5_error_code		retval;
+	stdccCacheDataPtr	ccapi_data = NULL;
+	int			err;
+#ifndef CC_API_VER2
+	cred_union 		*credU = NULL;
+#endif
+
+	ccapi_data = id->data;
+	
+	if ((retval = stdcc_setup(context, ccapi_data)))
+		return retval;
+
+	if (*cursor == NULL)
+		return 0;
+
+#ifdef CC_API_VER2
+	err = cc_seq_fetch_creds_end(gCntrlBlock, (ccache_cit **)cursor);
+	if (err != CC_NOERROR)
+		return cc_err_xlate(err);
+#else	
+	/*
+	 * Finish calling cc_seq_fetch_creds to clear out the cursor
+	 */
+	while (*cursor) {
+		err = cc_seq_fetch_creds(gCntrlBlock, ccapi_data->NamedCache,
+				 &credU, (ccache_cit **)cursor);
+		if (err)
+			break;
+		
+		/* okay to call cc_free_creds() here because we got credU from CCache lib */
+		cc_free_creds(gCntrlBlock, &credU);
+	}
+#endif
+	
+	return(0);
+}
+     
+/*
+ * close
+ *
+ * - free our pointers to the NC
+ */
+krb5_error_code KRB5_CALLCONV 
+krb5_stdcc_close(krb5_context context, krb5_ccache id)
+{
+	krb5_error_code	retval;
+	stdccCacheDataPtr	ccapi_data = id->data;
+
+	if ((retval = stdcc_setup(context, NULL)))
+		return retval;
+	
+	/* free it */
+	
+	if (ccapi_data) {
+		if (ccapi_data->cache_name)
+			free(ccapi_data->cache_name);
+		if (ccapi_data->NamedCache)
+			cc_close(gCntrlBlock, &ccapi_data->NamedCache);
+		free(ccapi_data);
+		id->data = NULL;
+	}
+	free(id);
+	
+	return 0;
+}
+
+/*
+ * destroy
+ *
+ * - free our storage and the cache
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_stdcc_destroy (krb5_context context, krb5_ccache id)
+{
+	int err;
+	krb5_error_code	retval;
+	stdccCacheDataPtr	ccapi_data = id->data;
+
+	if ((retval = stdcc_setup(context, ccapi_data))) {
+		return retval;
+	}
+
+	/* free memory associated with the krb5_ccache */
+	if (ccapi_data) {
+		if (ccapi_data->cache_name)
+			free(ccapi_data->cache_name);
+		if (ccapi_data->NamedCache) {
+			/* destroy the named cache */
+			err = cc_destroy(gCntrlBlock, &ccapi_data->NamedCache);
+			retval = cc_err_xlate(err);
+			cache_changed();
+		}
+		free(ccapi_data);
+		id->data = NULL;
+	}
+	free(id);
+
+	/* If the cache does not exist when we tried to destroy it,
+	   that's fine.  That means someone else destryoed it since
+	   we resolved it. */
+	if (retval == KRB5_FCC_NOFILE)
+		return 0;
+	return retval;
+}
+
+/*
+ *  getname
+ *
+ * - return the name of the named cache
+ */
+const char * KRB5_CALLCONV krb5_stdcc_get_name 
+        (krb5_context context, krb5_ccache id )
+{
+	stdccCacheDataPtr	ccapi_data = id->data;
+
+	if (!ccapi_data)
+		return 0;
+
+	return (ccapi_data->cache_name);
+}
+
+
+/* get_principal
+ *
+ * - return the principal associated with the named cache
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdcc_get_principal
+	(krb5_context context, krb5_ccache id , krb5_principal *princ) 
+{
+	int 			err;
+	char 	  		*name = NULL;
+	stdccCacheDataPtr	ccapi_data = id->data;
+	krb5_error_code		retval;
+	
+	if ((retval = stdcc_setup(context, ccapi_data)))
+		return retval;
+
+	/* another wrapper */
+	err = cc_get_principal(gCntrlBlock, ccapi_data->NamedCache,
+			       &name);
+
+	if (err != CC_NOERROR) 
+		return cc_err_xlate(err);
+		
+	/* turn it into a krb principal */
+	err = krb5_parse_name(context, name, princ);
+
+	cc_free_principal(gCntrlBlock, &name);
+	
+	return err;	
+}
+
+/*
+ * set_flags
+ *
+ * - currently a NOP since we don't store any flags in the NC
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdcc_set_flags 
+        (krb5_context context, krb5_ccache id , krb5_flags flags)
+{
+	stdccCacheDataPtr	ccapi_data = id->data;
+	krb5_error_code		retval;
+	
+	if ((retval = stdcc_setup(context, ccapi_data)))
+		return retval;
+
+	return 0;
+}
+
+/*
+ * get_flags
+ *
+ * - currently a NOP since we don't store any flags in the NC
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdcc_get_flags 
+        (krb5_context context, krb5_ccache id , krb5_flags *flags)
+{
+	stdccCacheDataPtr	ccapi_data = id->data;
+	krb5_error_code		retval;
+	
+	if ((retval = stdcc_setup(context, ccapi_data)))
+		return retval;
+
+	return 0;
+}
+
+/*
+ * remove
+ *
+ * - remove the specified credentials from the NC
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdcc_remove 
+        (krb5_context context, krb5_ccache id,
+	 krb5_flags flags, krb5_creds *creds)
+{
+    	cred_union *cu = NULL;
+    	int err;
+	stdccCacheDataPtr	ccapi_data = id->data;
+	krb5_error_code		retval;
+	
+	if ((retval = stdcc_setup(context, ccapi_data))) {
+		if (retval == KRB5_FCC_NOFILE)
+			return 0;
+		return retval;
+	}
+    	
+    	/* convert to a cred union */
+    	dupK5toCC(context, creds, &cu);
+    	
+    	/* remove it */
+    	err = cc_remove_cred(gCntrlBlock, ccapi_data->NamedCache, *cu);
+    	if (err != CC_NOERROR)
+		return cc_err_xlate(err);
+    	
+    	/* free the cred union using our local version of cc_free_creds()
+	       since we allocated it locally */
+    	err = krb5_free_cc_cred_union(&cu);
+	cache_changed();
+    	if (err != CC_NOERROR)
+		return cc_err_xlate(err);
+
+        return 0;
+}
diff --git a/mechglue/src/lib/krb5/ccache/ccapi/stdcc.h b/mechglue/src/lib/krb5/ccache/ccapi/stdcc.h
new file mode 100644
index 000000000..81ce883cb
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccapi/stdcc.h
@@ -0,0 +1,80 @@
+#include "krb5.h"
+#include "k5-int.h"
+	
+#ifdef USE_CCAPI
+#include <CredentialsCache2.h>
+#endif
+
+#if defined(_WIN32)
+#include "cacheapi.h"
+#endif
+
+#define kStringLiteralLen 255
+
+/* globals to be exported */
+extern krb5_cc_ops krb5_cc_stdcc_ops;
+
+/*
+ * structure to stash in the cache's data field
+ */
+typedef struct _stdccCacheData {
+     	char *cache_name;
+	ccache_p *NamedCache;
+} stdccCacheData, *stdccCacheDataPtr;
+
+
+/* function protoypes  */
+
+void krb5_stdcc_shutdown(void);
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_close
+        (krb5_context, krb5_ccache id );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_destroy 
+        (krb5_context, krb5_ccache id );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_end_seq_get 
+        (krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_generate_new 
+        (krb5_context, krb5_ccache *id );
+
+const char * KRB5_CALLCONV krb5_stdcc_get_name 
+        (krb5_context, krb5_ccache id );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_get_principal 
+        (krb5_context, krb5_ccache id , krb5_principal *princ );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_initialize 
+        (krb5_context, krb5_ccache id , krb5_principal princ );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_next_cred 
+        (krb5_context, 
+		   krb5_ccache id , 
+		   krb5_cc_cursor *cursor , 
+		   krb5_creds *creds );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_resolve 
+        (krb5_context, krb5_ccache *id , const char *residual );
+     
+krb5_error_code KRB5_CALLCONV krb5_stdcc_retrieve 
+        (krb5_context, 
+		   krb5_ccache id , 
+		   krb5_flags whichfields , 
+		   krb5_creds *mcreds , 
+		   krb5_creds *creds );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_start_seq_get 
+        (krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_store 
+        (krb5_context, krb5_ccache id , krb5_creds *creds );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_set_flags 
+        (krb5_context, krb5_ccache id , krb5_flags flags );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_get_flags 
+        (krb5_context, krb5_ccache id , krb5_flags *flags );
+
+krb5_error_code KRB5_CALLCONV krb5_stdcc_remove 
+        (krb5_context, krb5_ccache id , krb5_flags flags, krb5_creds *creds);
diff --git a/mechglue/src/lib/krb5/ccache/ccapi/stdcc_util.c b/mechglue/src/lib/krb5/ccache/ccapi/stdcc_util.c
new file mode 100644
index 000000000..7f9358dca
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccapi/stdcc_util.c
@@ -0,0 +1,555 @@
+/*
+ * stdcc_util.c
+ * utility functions used in implementing the ccache api for krb5
+ * not publicly exported
+ * Frank Dabek, July 1998
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#if defined(_WIN32)
+#include <malloc.h>
+#endif
+
+#include "stdcc_util.h"
+#include "krb5.h"
+#include "kv5m_err.h"
+
+#define fieldSize 255
+
+/*
+ * CopyCCDataArrayToK5
+ * - copy and translate the null terminated arrays of data records
+ * 	 used in k5 tickets
+ */
+int copyCCDataArrayToK5(cc_creds *ccCreds, krb5_creds *v5Creds, char whichArray) {
+
+    if (whichArray == kAddressArray) {
+	if (ccCreds->addresses == NULL) {
+	    v5Creds->addresses = NULL;
+	} else {
+
+	    krb5_address 	**addrPtr, *addr;
+	    cc_data			**dataPtr, *data;
+	    unsigned int		numRecords = 0;
+
+	    /* Allocate the array of pointers: */
+	    for (dataPtr = ccCreds->addresses; *dataPtr != NULL; numRecords++, dataPtr++) {}
+
+	    v5Creds->addresses = (krb5_address **) malloc (sizeof(krb5_address *) * (numRecords + 1));
+	    if (v5Creds->addresses == NULL)
+		return ENOMEM;
+
+	    /* Fill in the array, allocating the address structures: */
+	    for (dataPtr = ccCreds->addresses, addrPtr = v5Creds->addresses; *dataPtr != NULL; addrPtr++, dataPtr++) {
+
+		*addrPtr = (krb5_address *) malloc (sizeof(krb5_address));
+		if (*addrPtr == NULL)
+		    return ENOMEM;
+		data = *dataPtr;
+		addr = *addrPtr;
+
+		addr->addrtype = data->type;
+		addr->magic    = KV5M_ADDRESS;
+		addr->length   = data->length;
+		addr->contents = (krb5_octet *) malloc (sizeof(krb5_octet) * addr->length);
+		if (addr->contents == NULL)
+		    return ENOMEM;
+		memmove(addr->contents, data->data, addr->length); /* copy contents */
+	    }
+
+	    /* Write terminator: */
+	    *addrPtr = NULL;
+	}
+    }
+
+    if (whichArray == kAuthDataArray) {
+	if (ccCreds->authdata == NULL) {
+	    v5Creds->authdata = NULL;
+	} else {
+	    krb5_authdata 	**authPtr, *auth;
+	    cc_data			**dataPtr, *data;
+	    unsigned int		numRecords = 0;
+
+	    /* Allocate the array of pointers: */
+	    for (dataPtr = ccCreds->authdata; *dataPtr != NULL; numRecords++, dataPtr++) {}
+
+	    v5Creds->authdata = (krb5_authdata **) malloc (sizeof(krb5_authdata *) * (numRecords + 1));
+	    if (v5Creds->authdata == NULL)
+		return ENOMEM;
+
+	    /* Fill in the array, allocating the address structures: */
+	    for (dataPtr = ccCreds->authdata, authPtr = v5Creds->authdata; *dataPtr != NULL; authPtr++, dataPtr++) {
+
+		*authPtr = (krb5_authdata *) malloc (sizeof(krb5_authdata));
+		if (*authPtr == NULL)
+		    return ENOMEM;
+		data = *dataPtr;
+		auth = *authPtr;
+
+		auth->ad_type  = data->type;
+		auth->magic    = KV5M_AUTHDATA;
+		auth->length   = data->length;
+		auth->contents = (krb5_octet *) malloc (sizeof(krb5_octet) * auth->length);
+		if (auth->contents == NULL)
+		    return ENOMEM;
+		memmove(auth->contents, data->data, auth->length); /* copy contents */
+	    }
+
+	    /* Write terminator: */
+	    *authPtr = NULL;
+	}
+    }
+
+    return 0;
+}
+
+/*
+ * copyK5DataArrayToCC
+ * - analagous to above, but in the other direction
+ */
+int copyK5DataArrayToCC(krb5_creds *v5Creds, cc_creds *ccCreds, char whichArray)
+{
+    if (whichArray == kAddressArray) {
+	if (v5Creds->addresses == NULL) {
+	    ccCreds->addresses = NULL;
+	} else {
+
+	    krb5_address 	**addrPtr, *addr;
+	    cc_data			**dataPtr, *data;
+	    unsigned int			numRecords = 0;
+
+	    /* Allocate the array of pointers: */
+	    for (addrPtr = v5Creds->addresses; *addrPtr != NULL; numRecords++, addrPtr++) {}
+
+	    ccCreds->addresses = (cc_data **) malloc (sizeof(cc_data *) * (numRecords + 1));
+	    if (ccCreds->addresses == NULL)
+		return ENOMEM;
+
+	    /* Fill in the array, allocating the address structures: */
+	    for (dataPtr = ccCreds->addresses, addrPtr = v5Creds->addresses; *addrPtr != NULL; addrPtr++, dataPtr++) {
+
+		*dataPtr = (cc_data *) malloc (sizeof(cc_data));
+		if (*dataPtr == NULL)
+		    return ENOMEM;
+		data = *dataPtr;
+		addr = *addrPtr;
+
+		data->type   = addr->addrtype;
+		data->length = addr->length;
+		data->data   = malloc (sizeof(char) * data->length);
+		if (data->data == NULL)
+		    return ENOMEM;
+		memmove(data->data, addr->contents, data->length); /* copy contents */
+	    }
+
+	    /* Write terminator: */
+	    *dataPtr = NULL;
+	}
+    }
+
+    if (whichArray == kAuthDataArray) {
+	if (v5Creds->authdata == NULL) {
+	    ccCreds->authdata = NULL;
+	} else {
+	    krb5_authdata 	**authPtr, *auth;
+	    cc_data			**dataPtr, *data;
+	    unsigned int			numRecords = 0;
+
+	    /* Allocate the array of pointers: */
+	    for (authPtr = v5Creds->authdata; *authPtr != NULL; numRecords++, authPtr++) {}
+
+	    ccCreds->authdata = (cc_data **) malloc (sizeof(cc_data *) * (numRecords + 1));
+	    if (ccCreds->authdata == NULL)
+		return ENOMEM;
+
+	    /* Fill in the array, allocating the address structures: */
+	    for (dataPtr = ccCreds->authdata, authPtr = v5Creds->authdata; *authPtr != NULL; authPtr++, dataPtr++) {
+
+		*dataPtr = (cc_data *) malloc (sizeof(cc_data));
+		if (*dataPtr == NULL)
+		    return ENOMEM;
+		data = *dataPtr;
+		auth = *authPtr;
+
+		data->type   = auth->ad_type;
+		data->length = auth->length;
+		data->data   = malloc (sizeof(char) * data->length);
+		if (data->data == NULL)
+		    return ENOMEM;
+		memmove(data->data, auth->contents, data->length); /* copy contents */
+	    }
+
+	    /* Write terminator: */
+	    *dataPtr = NULL;
+	}
+    }
+
+    return 0;
+}
+
+/*
+ * dupcctok5
+ * - allocate an empty k5 style ticket and copy info from the cc_creds ticket
+ */
+
+void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest)
+{
+    krb5_int32 offset_seconds = 0, offset_microseconds = 0;
+    int err;
+
+    /*
+     * allocate and copy
+     * copy all of those damn fields back
+     */
+    err = krb5_parse_name(context, src->client, &(dest->client));
+    err = krb5_parse_name(context, src->server, &(dest->server));
+    if (err) return; /* parsename fails w/o krb5.ini for example */
+
+    /* copy keyblock */
+    dest->keyblock.enctype = src->keyblock.type;
+    dest->keyblock.length = src->keyblock.length;
+    dest->keyblock.contents = (krb5_octet *)malloc(dest->keyblock.length);
+    memcpy(dest->keyblock.contents, src->keyblock.data, dest->keyblock.length);
+
+    /* copy times */
+#if TARGET_OS_MAC
+    err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
+    if (err) return;
+#endif
+    dest->times.authtime   = src->authtime     + offset_seconds;
+    dest->times.starttime  = src->starttime    + offset_seconds;
+    dest->times.endtime    = src->endtime      + offset_seconds;
+    dest->times.renew_till = src->renew_till   + offset_seconds;
+    dest->is_skey          = src->is_skey;
+    dest->ticket_flags     = src->ticket_flags;
+
+    /* more branching fields */
+    err = copyCCDataArrayToK5(src, dest, kAddressArray);
+    if (err) return;
+
+    dest->ticket.length = src->ticket.length;
+    dest->ticket.data = (char *)malloc(src->ticket.length);
+    memcpy(dest->ticket.data, src->ticket.data, src->ticket.length);
+    dest->second_ticket.length = src->second_ticket.length;
+    (dest->second_ticket).data = ( char *)malloc(src->second_ticket.length);
+    memcpy(dest->second_ticket.data, src->second_ticket.data, src->second_ticket.length);
+
+    /* zero out magic number */
+    dest->magic = 0;
+
+    /* authdata */
+    err = copyCCDataArrayToK5(src, dest, kAuthDataArray);
+    if (err) return;
+
+    return;
+}
+
+/*
+ * dupK5toCC
+ * - analagous to above but in the reverse direction
+ */
+void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu)
+{
+    cc_creds *c;
+    int err;
+    krb5_int32 offset_seconds = 0, offset_microseconds = 0;
+
+    if (cu == NULL) return;
+
+    /* allocate the cred_union */
+    *cu = (cred_union *)malloc(sizeof(cred_union));
+    if ((*cu) == NULL)
+	return;
+
+    (*cu)->cred_type = CC_CRED_V5;
+
+    /* allocate creds structure (and install) */
+    c  = (cc_creds *)malloc(sizeof(cc_creds));
+    if (c == NULL) return;
+    (*cu)->cred.pV5Cred = c;
+
+    /* convert krb5 principals to flat principals */
+    err = krb5_unparse_name(context, creds->client, &(c->client));
+    err = krb5_unparse_name(context, creds->server, &(c->server));
+    if (err) return;
+
+    /* copy more fields */
+    c->keyblock.type = creds->keyblock.enctype;
+    c->keyblock.length = creds->keyblock.length;
+
+    if (creds->keyblock.contents != NULL) {
+	c->keyblock.data = (unsigned char *)malloc(creds->keyblock.length);
+	memcpy(c->keyblock.data, creds->keyblock.contents, creds->keyblock.length);
+    } else {
+	c->keyblock.data = NULL;
+    }
+
+#if TARGET_OS_MAC
+    err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
+    if (err) return;
+#endif
+    c->authtime     = creds->times.authtime   - offset_seconds;
+    c->starttime    = creds->times.starttime  - offset_seconds;
+    c->endtime      = creds->times.endtime    - offset_seconds;
+    c->renew_till   = creds->times.renew_till - offset_seconds;
+    c->is_skey      = creds->is_skey;
+    c->ticket_flags = creds->ticket_flags;
+
+    err = copyK5DataArrayToCC(creds, c, kAddressArray);
+    if (err) return;
+
+    c->ticket.length = creds->ticket.length;
+    if (creds->ticket.data != NULL) {
+	c->ticket.data = (unsigned char *)malloc(creds->ticket.length);
+	memcpy(c->ticket.data, creds->ticket.data, creds->ticket.length);
+    } else {
+	c->ticket.data = NULL;
+    }
+
+    c->second_ticket.length = creds->second_ticket.length;
+    if (creds->second_ticket.data != NULL) {
+	c->second_ticket.data = (unsigned char *)malloc(creds->second_ticket.length);
+	memcpy(c->second_ticket.data, creds->second_ticket.data, creds->second_ticket.length);
+    } else {
+	c->second_ticket.data = NULL;
+    }
+
+    err = copyK5DataArrayToCC(creds, c, kAuthDataArray);
+    if (err) return;
+
+    return;
+}
+
+/*
+ * Utility functions...
+ */
+static krb5_boolean
+times_match(t1, t2)
+    register const krb5_ticket_times *t1;
+register const krb5_ticket_times *t2;
+{
+    if (t1->renew_till) {
+	if (t1->renew_till > t2->renew_till)
+	    return FALSE;		/* this one expires too late */
+    }
+    if (t1->endtime) {
+	if (t1->endtime > t2->endtime)
+	    return FALSE;		/* this one expires too late */
+    }
+    /* only care about expiration on a times_match */
+    return TRUE;
+}
+
+static krb5_boolean
+times_match_exact (t1, t2)
+    register const krb5_ticket_times *t1, *t2;
+{
+    return (t1->authtime == t2->authtime
+	    && t1->starttime == t2->starttime
+	    && t1->endtime == t2->endtime
+	    && t1->renew_till == t2->renew_till);
+}
+
+static krb5_boolean
+standard_fields_match(context, mcreds, creds)
+    krb5_context context;
+register const krb5_creds *mcreds, *creds;
+{
+    return (krb5_principal_compare(context, mcreds->client,creds->client) &&
+	    krb5_principal_compare(context, mcreds->server,creds->server));
+}
+
+/* only match the server name portion, not the server realm portion */
+
+static krb5_boolean
+srvname_match(context, mcreds, creds)
+    krb5_context context;
+register const krb5_creds *mcreds, *creds;
+{
+    krb5_boolean retval;
+    krb5_principal_data p1, p2;
+
+    retval = krb5_principal_compare(context, mcreds->client,creds->client);
+    if (retval != TRUE)
+	return retval;
+    /*
+     * Hack to ignore the server realm for the purposes of the compare.
+     */
+    p1 = *mcreds->server;
+    p2 = *creds->server;
+    p1.realm = p2.realm;
+    return krb5_principal_compare(context, &p1, &p2);
+}
+
+
+static krb5_boolean
+authdata_match(mdata, data)
+    krb5_authdata *const *mdata, *const *data;
+{
+    const krb5_authdata *mdatap, *datap;
+
+    if (mdata == data)
+	return TRUE;
+
+    if (mdata == NULL)
+	return *data == NULL;
+
+    if (data == NULL)
+	return *mdata == NULL;
+
+    while ((mdatap = *mdata)
+	   && (datap = *data)
+	   && mdatap->ad_type == datap->ad_type
+	   && mdatap->length == datap->length
+	   && !memcmp ((char *) mdatap->contents, (char *) datap->contents,
+		       datap->length)) {
+	mdata++;
+	data++;
+    }
+
+    return !*mdata && !*data;
+}
+
+static krb5_boolean
+data_match(data1, data2)
+    register const krb5_data *data1, *data2;
+{
+    if (!data1) {
+	if (!data2)
+	    return TRUE;
+	else
+	    return FALSE;
+    }
+    if (!data2) return FALSE;
+
+    if (data1->length != data2->length)
+	return FALSE;
+    else
+	return memcmp(data1->data, data2->data, data1->length) ? FALSE : TRUE;
+}
+
+#define MATCH_SET(bits) (whichfields & bits)
+#define flags_match(a,b) (((a) & (b)) == (a))
+
+/*  stdccCredsMatch
+ *  - check to see if the creds match based on the whichFields variable
+ *  NOTE: if whichfields is zero we are now comparing 'standard fields.'
+ * 		 This is the bug that was killing fetch for a
+ * 		 week. The behaviour is what krb5 expects, however.
+ */
+int stdccCredsMatch(krb5_context context, krb5_creds *base,
+		    krb5_creds *match, int whichfields)
+{
+    if (((MATCH_SET(KRB5_TC_MATCH_SRV_NAMEONLY) &&
+	  srvname_match(context, match, base)) ||
+	 standard_fields_match(context, match, base))
+	&&
+	(! MATCH_SET(KRB5_TC_MATCH_IS_SKEY) ||
+	 match->is_skey == base->is_skey)
+	&&
+	(! MATCH_SET(KRB5_TC_MATCH_FLAGS_EXACT) ||
+	 match->ticket_flags == base->ticket_flags)
+	&&
+	(! MATCH_SET(KRB5_TC_MATCH_FLAGS) ||
+	 flags_match(match->ticket_flags, base->ticket_flags))
+	&&
+	(! MATCH_SET(KRB5_TC_MATCH_TIMES_EXACT) ||
+	 times_match_exact(&match->times, &base->times))
+	&&
+	(! MATCH_SET(KRB5_TC_MATCH_TIMES) ||
+	 times_match(&match->times, &base->times))
+	&&
+	(! MATCH_SET(KRB5_TC_MATCH_AUTHDATA) ||
+	 authdata_match (match->authdata, base->authdata))
+	&&
+	(! MATCH_SET(KRB5_TC_MATCH_2ND_TKT) ||
+	 data_match (&match->second_ticket, &base->second_ticket))
+	&&
+	((! MATCH_SET(KRB5_TC_MATCH_KTYPE))||
+	 (match->keyblock.enctype == base->keyblock.enctype))
+	)
+	return TRUE;
+    return FALSE;
+}
+
+/* ----- free_cc_cred_union, etc -------------- */
+/*
+  Since the Kerberos5 library allocates a credentials cache structure
+  (in dupK5toCC() above) with its own memory allocation routines - which
+  may be different than how the CCache allocates memory - the Kerb5 library
+  must have its own version of cc_free_creds() to deallocate it.  These
+  functions do that.  The top-level function to substitue for cc_free_creds()
+  is krb5_free_cc_cred_union().
+
+  If the CCache library wants to use a cred_union structure created by
+  the Kerb5 library, it should make a deep copy of it to "translate" to its
+  own memory allocation space.
+*/
+static void deep_free_cc_data (cc_data data)
+{
+    if (data.data != NULL)
+	free (data.data);
+}
+
+static void deep_free_cc_data_array (cc_data** data) {
+
+    unsigned int	index;
+
+    if (data == NULL)
+	return;
+
+    for (index = 0; data [index] != NULL; index++) {
+	deep_free_cc_data (*(data [index]));
+	free (data [index]);
+    }
+
+    free (data);
+}
+
+static void deep_free_cc_v5_creds (cc_creds* creds)
+{
+    if (creds == NULL)
+	return;
+
+    if (creds -> client != NULL)
+	free (creds -> client);
+    if (creds -> server != NULL)
+	free (creds -> server);
+
+    deep_free_cc_data (creds -> keyblock);
+    deep_free_cc_data (creds -> ticket);
+    deep_free_cc_data (creds -> second_ticket);
+
+    deep_free_cc_data_array (creds -> addresses);
+    deep_free_cc_data_array (creds -> authdata);
+
+    free(creds);
+}
+
+static void deep_free_cc_creds (cred_union creds)
+{
+    if (creds.cred_type == CC_CRED_V4) {
+	/* we shouldn't get this, of course */
+	free (creds.cred.pV4Cred);
+    } else if (creds.cred_type == CC_CRED_V5) {
+	deep_free_cc_v5_creds (creds.cred.pV5Cred);
+    }
+}
+
+/* top-level exported function */
+cc_int32 krb5_free_cc_cred_union (cred_union** creds)
+{
+    if (creds == NULL)
+	return CC_BAD_PARM;
+
+    if (*creds != NULL) {
+	deep_free_cc_creds (**creds);
+	free (*creds);
+	*creds = NULL;
+    }
+
+    return CC_NOERROR;
+}
diff --git a/mechglue/src/lib/krb5/ccache/ccapi/stdcc_util.h b/mechglue/src/lib/krb5/ccache/ccapi/stdcc_util.h
new file mode 100644
index 000000000..b80a3cf19
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccapi/stdcc_util.h
@@ -0,0 +1,27 @@
+/* stdcc_util.h
+ *
+ * Frank Dabek, July 1998
+ */
+
+#if USE_CCAPI
+#include <CredentialsCache2.h>
+#endif
+
+#if defined(_WIN32)
+#include "cacheapi.h"
+#endif
+
+#include "krb5.h"
+
+/* protoypes for private functions declared in stdcc_util.c */
+int copyCCDataArrayToK5(cc_creds *cc, krb5_creds *kc, char whichArray);
+int copyK5DataArrayToCC(krb5_creds *kc, cc_creds *cc, char whichArray);
+void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest);
+void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu);
+int stdccCredsMatch(krb5_context context, krb5_creds *base, krb5_creds *match, int whichfields);
+int bitTst(int var, int mask);
+cc_int32 krb5_free_cc_cred_union (cred_union** creds);
+
+#define kAddressArray 4 
+#define kAuthDataArray 5
+
diff --git a/mechglue/src/lib/krb5/ccache/ccapi/winccld.c b/mechglue/src/lib/krb5/ccache/ccapi/winccld.c
new file mode 100644
index 000000000..ac3a8e478
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccapi/winccld.c
@@ -0,0 +1,96 @@
+#if defined(_WIN32)
+/*
+ * winccld.c --- routine for dynamically loading the ccache DLL if
+ * it's present.
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include "k5-int.h"
+#include "stdcc.h"
+
+/* from fcc-proto.h */
+extern const krb5_cc_ops krb5_fcc_ops;
+
+#define KRB5_WINCCLD_C_
+#include "winccld.h"
+
+static int krb5_win_ccdll_loaded = 0;
+
+extern void krb5_win_ccdll_load();
+extern int krb5_is_ccdll_loaded();
+
+/*
+ * return codes
+ */
+#define LF_OK		0
+#define LF_NODLL	1
+#define LF_NOFUNC	2
+
+#define KRBCC_DLL      "krbcc32.dll"
+
+static int LoadFuncs(const char* dll_name, FUNC_INFO fi[],
+		     HINSTANCE* ph, int debug);
+
+static int LoadFuncs(const char* dll_name, FUNC_INFO fi[],
+		     HINSTANCE* ph, int debug)
+{
+    HINSTANCE h;
+    int i, n;
+    int error = 0;
+
+    if (ph) *ph = 0;
+
+    for (n = 0; fi[n].func_ptr_var; n++) {
+	*(fi[n].func_ptr_var) = 0;
+    }
+
+    if (!(h = LoadLibrary(dll_name))) {
+	/* Get error for source debugging purposes. */
+	error = (int)GetLastError();
+	return LF_NODLL;
+    }
+
+    if (debug)
+	printf("Loaded %s\n", dll_name);
+    for (i = 0; !error && (i < n); i++) {
+	void* p = (void*)GetProcAddress(h, fi[i].func_name);
+	if (!p) {
+	    if (debug)
+		printf("Could not get function: %s\n", fi[i].func_name);
+	    error = 1;
+	} else {
+	    *(fi[i].func_ptr_var) = p;
+	    if (debug)
+		printf("Loaded function %s at 0x%08X\n", fi[i].func_name, p);
+	}
+    }
+    if (error) {
+	for (i = 0; i < n; i++) {
+	    *(fi[i].func_ptr_var) = 0;
+	}
+	FreeLibrary(h);
+	return LF_NOFUNC;
+    }
+    if (ph) *ph = h;
+    return LF_OK;
+}
+
+void krb5_win_ccdll_load(context)
+	krb5_context	context;
+{
+	krb5_cc_register(context, &krb5_fcc_ops, 0);
+	if (krb5_win_ccdll_loaded)
+		return;
+	if (LoadFuncs(KRBCC_DLL, krbcc_fi, 0, 0))
+		return;		/* Error, give up */
+	krb5_win_ccdll_loaded = 1;
+	krb5_cc_dfl_ops = &krb5_cc_stdcc_ops; /* Use stdcc! */
+}
+
+int krb5_is_ccdll_loaded()
+{
+	return krb5_win_ccdll_loaded;
+}
+
+#endif	/* Windows */
diff --git a/mechglue/src/lib/krb5/ccache/ccapi/winccld.h b/mechglue/src/lib/krb5/ccache/ccapi/winccld.h
new file mode 100644
index 000000000..e285d1faf
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccapi/winccld.h
@@ -0,0 +1,184 @@
+/*
+ * winccld.h -- the dynamic loaded version of the ccache DLL
+ */
+
+
+#ifndef KRB5_WINCCLD_H_
+#define KRB5_WINCCLD_H_
+
+#ifndef CC_API_VER2
+#define CC_API_VER2
+#endif
+
+#include "cacheapi.h"
+
+typedef cc_int32 (*FP_cc_initialize)(apiCB**, const cc_int32, 
+			cc_int32*, const char**);     
+typedef cc_int32 (*FP_cc_shutdown)(apiCB**);            
+typedef cc_int32 (*FP_cc_get_change_time)(apiCB*, cc_time_t*);    
+typedef cc_int32 (*FP_cc_create)(apiCB*, const char*, const char*,
+			const enum cc_cred_vers, const cc_int32, ccache_p**);
+typedef cc_int32 (*FP_cc_open)(apiCB*, const char*, const enum cc_cred_vers,
+			const cc_int32, ccache_p**);
+typedef cc_int32 (*FP_cc_close)(apiCB*, ccache_p**);
+typedef cc_int32 (*FP_cc_destroy)(apiCB*, ccache_p**);
+typedef cc_int32 (*FP_cc_seq_fetch_NCs)(apiCB*, ccache_p**, ccache_cit**);
+typedef cc_int32 (*FP_cc_seq_fetch_NCs_begin)(apiCB*, ccache_cit**);
+typedef cc_int32 (*FP_cc_seq_fetch_NCs_next)(apiCB*, ccache_p**, ccache_cit*);
+typedef cc_int32 (*FP_cc_seq_fetch_NCs_end)(apiCB*, ccache_cit**);
+typedef cc_int32 (*FP_cc_get_NC_info)(apiCB*, struct _infoNC***);
+typedef cc_int32 (*FP_cc_free_NC_info)(apiCB*, struct _infoNC***);
+typedef cc_int32 (*FP_cc_get_name)(apiCB*, const ccache_p*, char**);
+typedef cc_int32 (*FP_cc_set_principal)(apiCB*, const ccache_p*,
+			const enum cc_cred_vers, const char*);
+typedef cc_int32 (*FP_cc_get_principal)(apiCB*, ccache_p*, char**);
+typedef cc_int32 (*FP_cc_get_cred_version)(apiCB*, const ccache_p*,
+			enum cc_cred_vers*);
+typedef cc_int32 (*FP_cc_lock_request)(apiCB*, const ccache_p*,
+			const cc_int32);
+typedef cc_int32 (*FP_cc_store)(apiCB*, const ccache_p*, const cred_union);
+typedef cc_int32 (*FP_cc_remove_cred)(apiCB*, const ccache_p*,
+			const cred_union);
+typedef cc_int32 (*FP_cc_seq_fetch_creds)(apiCB*, const ccache_p*, 
+			cred_union**, ccache_cit**);
+typedef cc_int32 (*FP_cc_seq_fetch_creds_begin)(apiCB*, const ccache_p*, 
+			ccache_cit**);
+typedef cc_int32 (*FP_cc_seq_fetch_creds_next)(apiCB*, cred_union**, 
+			ccache_cit*);
+typedef cc_int32 (*FP_cc_seq_fetch_creds_end)(apiCB*, ccache_cit**);
+typedef cc_int32 (*FP_cc_free_principal)(apiCB*, char**);
+typedef cc_int32 (*FP_cc_free_name)(apiCB*, char** name);
+typedef cc_int32 (*FP_cc_free_creds)(apiCB*, cred_union** pCred);
+
+#ifdef KRB5_WINCCLD_C_
+typedef struct _FUNC_INFO {
+    void** func_ptr_var;
+    char* func_name;
+} FUNC_INFO;
+
+#define DECL_FUNC_PTR(x) FP_##x p##x
+#define MAKE_FUNC_INFO(x) { (void**) &p##x, #x }
+#define END_FUNC_INFO { 0, 0 }
+#else
+#define DECL_FUNC_PTR(x) extern FP_##x p##x
+#endif
+
+DECL_FUNC_PTR(cc_initialize);
+DECL_FUNC_PTR(cc_shutdown);
+DECL_FUNC_PTR(cc_get_change_time);
+DECL_FUNC_PTR(cc_create);
+DECL_FUNC_PTR(cc_open);
+DECL_FUNC_PTR(cc_close);
+DECL_FUNC_PTR(cc_destroy);
+#if 0 /* Not used */
+#ifdef CC_API_VER2
+DECL_FUNC_PTR(cc_seq_fetch_NCs_begin);
+DECL_FUNC_PTR(cc_seq_fetch_NCs_next);
+DECL_FUNC_PTR(cc_seq_fetch_NCs_end);
+#else
+DECL_FUNC_PTR(cc_seq_fetch_NCs);
+#endif
+DECL_FUNC_PTR(cc_get_NC_info);
+DECL_FUNC_PTR(cc_free_NC_info);
+#endif
+DECL_FUNC_PTR(cc_get_name);
+DECL_FUNC_PTR(cc_set_principal);
+DECL_FUNC_PTR(cc_get_principal);
+DECL_FUNC_PTR(cc_get_cred_version);
+#if 0 /* Not used */
+DECL_FUNC_PTR(cc_lock_request);
+#endif
+DECL_FUNC_PTR(cc_store);
+DECL_FUNC_PTR(cc_remove_cred);
+#ifdef CC_API_VER2
+DECL_FUNC_PTR(cc_seq_fetch_creds_begin);
+DECL_FUNC_PTR(cc_seq_fetch_creds_next);
+DECL_FUNC_PTR(cc_seq_fetch_creds_end);
+#else
+DECL_FUNC_PTR(cc_seq_fetch_creds);
+#endif
+DECL_FUNC_PTR(cc_free_principal);
+DECL_FUNC_PTR(cc_free_name);
+DECL_FUNC_PTR(cc_free_creds);
+
+#ifdef KRB5_WINCCLD_C_
+FUNC_INFO krbcc_fi[] = {
+    MAKE_FUNC_INFO(cc_initialize),
+    MAKE_FUNC_INFO(cc_shutdown),
+    MAKE_FUNC_INFO(cc_get_change_time),
+    MAKE_FUNC_INFO(cc_create),
+    MAKE_FUNC_INFO(cc_open),
+    MAKE_FUNC_INFO(cc_close),
+    MAKE_FUNC_INFO(cc_destroy),
+#if 0 /* Not used */
+    MAKE_FUNC_INFO(cc_seq_fetch_NCs),
+    MAKE_FUNC_INFO(cc_get_NC_info),
+    MAKE_FUNC_INFO(cc_free_NC_info),
+#endif
+    MAKE_FUNC_INFO(cc_get_name),
+    MAKE_FUNC_INFO(cc_set_principal),
+    MAKE_FUNC_INFO(cc_get_principal),
+    MAKE_FUNC_INFO(cc_get_cred_version),
+#if 0 /* Not used */
+    MAKE_FUNC_INFO(cc_lock_request),
+#endif
+    MAKE_FUNC_INFO(cc_store),
+    MAKE_FUNC_INFO(cc_remove_cred),
+#ifdef CC_API_VER2
+    MAKE_FUNC_INFO(cc_seq_fetch_creds_begin),
+    MAKE_FUNC_INFO(cc_seq_fetch_creds_next),
+    MAKE_FUNC_INFO(cc_seq_fetch_creds_end),
+#else
+    MAKE_FUNC_INFO(cc_seq_fetch_creds),
+#endif
+    MAKE_FUNC_INFO(cc_free_principal),
+    MAKE_FUNC_INFO(cc_free_name),
+    MAKE_FUNC_INFO(cc_free_creds),
+    END_FUNC_INFO
+};
+#undef MAKE_FUNC_INFO
+#undef END_FUNC_INFO
+#else
+
+#define cc_initialize pcc_initialize
+#define cc_shutdown pcc_shutdown
+#define cc_get_change_time pcc_get_change_time
+#define cc_create pcc_create
+#define cc_open pcc_open
+#define cc_close pcc_close
+#define cc_destroy pcc_destroy
+#if 0 /* Not used */
+#ifdef CC_API_VER2
+#define cc_seq_fetch_NCs_begin pcc_seq_fetch_NCs_begin
+#define cc_seq_fetch_NCs_next pcc_seq_fetch_NCs_next
+#define cc_seq_fetch_NCs_end pcc_seq_fetch_NCs_end
+#else
+#define cc_seq_fetch_NCs pcc_seq_fetch_NCs
+#endif
+#define cc_get_NC_info pcc_get_NC_info
+#define cc_free_NC_info pcc_free_NC_info
+#endif /* End of Not used */
+#define cc_get_name pcc_get_name
+#define cc_set_principal pcc_set_principal
+#define cc_get_principal pcc_get_principal
+#define cc_get_cred_version pcc_get_cred_version
+#if 0 /* Not used */
+#define cc_lock_request pcc_lock_request
+#endif
+#define cc_store pcc_store
+#define cc_remove_cred pcc_remove_cred
+#ifdef CC_API_VER2
+#define cc_seq_fetch_creds_begin pcc_seq_fetch_creds_begin
+#define cc_seq_fetch_creds_next pcc_seq_fetch_creds_next
+#define cc_seq_fetch_creds_end pcc_seq_fetch_creds_end
+#else
+#define cc_seq_fetch_creds pcc_seq_fetch_creds
+#endif
+#define cc_free_principal pcc_free_principal
+#define cc_free_name pcc_free_name
+#define cc_free_creds pcc_free_creds
+#endif
+
+#undef DECL_FUNC_PTR
+
+#endif /* KRB5_WINCCLD_H_ */
diff --git a/mechglue/src/lib/krb5/ccache/ccbase.c b/mechglue/src/lib/krb5/ccache/ccbase.c
new file mode 100644
index 000000000..2b15ff6f3
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccbase.c
@@ -0,0 +1,194 @@
+/*
+ * lib/krb5/ccache/ccbase.c
+ *
+ * Copyright 1990,2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Registration functions for ccache.
+ */
+
+#include "k5-int.h"
+#include "k5-thread.h"
+
+#include "fcc.h"
+#include "cc-int.h"
+
+struct krb5_cc_typelist {
+    const krb5_cc_ops *ops;
+    struct krb5_cc_typelist *next;
+};
+extern const krb5_cc_ops krb5_mcc_ops;
+
+#ifdef _WIN32
+extern const krb5_cc_ops krb5_lcc_ops;
+static struct krb5_cc_typelist cc_lcc_entry = { &krb5_lcc_ops, NULL };
+static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_lcc_entry };
+#else
+static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL };
+#endif
+
+static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops,
+						&cc_mcc_entry };
+
+static struct krb5_cc_typelist *cc_typehead = &cc_fcc_entry;
+static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+int
+krb5int_cc_initialize(void)
+{
+    int err;
+
+    err = k5_mutex_finish_init(&krb5int_mcc_mutex);
+    if (err)
+	return err;
+    err = k5_mutex_finish_init(&cc_typelist_lock);
+    if (err)
+	return err;
+    err = k5_mutex_finish_init(&krb5int_cc_file_mutex);
+    if (err)
+	return err;
+    return 0;
+}
+
+void
+krb5int_cc_finalize(void)
+{
+    struct krb5_cc_typelist *t, *t_next;
+    k5_mutex_destroy(&cc_typelist_lock);
+    k5_mutex_destroy(&krb5int_cc_file_mutex);
+    k5_mutex_destroy(&krb5int_mcc_mutex);
+    for (t = cc_typehead; t != &cc_fcc_entry; t = t_next) {
+	t_next = t->next;
+	free(t);
+    }
+}
+
+
+/*
+ * Register a new credentials cache type
+ * If override is set, replace any existing ccache with that type tag
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_register(krb5_context context, krb5_cc_ops *ops, krb5_boolean override)
+{
+    struct krb5_cc_typelist *t;
+    krb5_error_code err;
+
+    err = k5_mutex_lock(&cc_typelist_lock);
+    if (err)
+	return err;
+    for (t = cc_typehead;t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
+	;
+    if (t) {
+	if (override) {
+	    t->ops = ops;
+	    k5_mutex_unlock(&cc_typelist_lock);
+	    return 0;
+	} else {
+	    k5_mutex_unlock(&cc_typelist_lock);
+	    return KRB5_CC_TYPE_EXISTS;
+	}
+    }
+    if (!(t = (struct krb5_cc_typelist *) malloc(sizeof(*t)))) {
+	k5_mutex_unlock(&cc_typelist_lock);
+	return ENOMEM;
+    }
+    t->next = cc_typehead;
+    t->ops = ops;
+    cc_typehead = t;
+    k5_mutex_unlock(&cc_typelist_lock);
+    return 0;
+}
+
+/*
+ * Resolve a credential cache name into a cred. cache object.
+ *
+ * The name is currently constrained to be of the form "type:residual";
+ *
+ * The "type" portion corresponds to one of the predefined credential
+ * cache types, while the "residual" portion is specific to the
+ * particular cache type.
+ */
+
+#include <ctype.h>
+krb5_error_code KRB5_CALLCONV
+krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
+{
+    struct krb5_cc_typelist *tlist;
+    char *pfx, *cp;
+    const char *resid;
+    unsigned int pfxlen;
+    krb5_error_code err;
+    
+    cp = strchr (name, ':');
+    if (!cp) {
+	if (krb5_cc_dfl_ops)
+	    return (*krb5_cc_dfl_ops->resolve)(context, cache, name);
+	else
+	    return KRB5_CC_BADNAME;
+    }
+
+    pfxlen = cp - name;
+
+    if ( pfxlen == 1 && isalpha(name[0]) ) {
+        /* We found a drive letter not a prefix - use FILE: */
+        pfx = strdup("FILE:");
+        if (!pfx)
+            return ENOMEM;
+
+        resid = name;
+    } else {
+        resid = name + pfxlen + 1;
+
+        pfx = malloc (pfxlen+1);
+        if (!pfx)
+            return ENOMEM;
+
+        memcpy (pfx, name, pfxlen);
+        pfx[pfxlen] = '\0';
+    }
+
+    *cache = (krb5_ccache) 0;
+
+    err = k5_mutex_lock(&cc_typelist_lock);
+    if (err) {
+	free(pfx);
+	return err;
+    }
+    for (tlist = cc_typehead; tlist; tlist = tlist->next) {
+	if (strcmp (tlist->ops->prefix, pfx) == 0) {
+	    krb5_error_code (KRB5_CALLCONV *ccresolver)() = tlist->ops->resolve;
+	    k5_mutex_unlock(&cc_typelist_lock);
+	    free(pfx);
+	    return (*ccresolver)(context, cache, resid);
+	}
+    }
+    k5_mutex_unlock(&cc_typelist_lock);
+    if (krb5_cc_dfl_ops && !strcmp (pfx, krb5_cc_dfl_ops->prefix)) {
+	free (pfx);
+	return (*krb5_cc_dfl_ops->resolve)(context, cache, resid);
+    }
+    free(pfx);
+    return KRB5_CC_UNKNOWN_TYPE;
+}
diff --git a/mechglue/src/lib/krb5/ccache/cccopy.c b/mechglue/src/lib/krb5/ccache/cccopy.c
new file mode 100644
index 000000000..a9a45b501
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/cccopy.c
@@ -0,0 +1,62 @@
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_copy_creds(krb5_context context, krb5_ccache incc, krb5_ccache outcc)
+{
+    krb5_error_code code;
+    krb5_flags flags;
+    krb5_cc_cursor cur = 0;
+    krb5_creds creds;
+
+    flags = 0;				/* turns off OPENCLOSE mode */
+    if ((code = krb5_cc_set_flags(context, incc, flags)))
+	return(code);
+    /* the code for this will open the file for reading only, which
+       is not what I had in mind.  So I won't turn off OPENCLOSE
+       for the output ccache */
+#if 0
+    if ((code = krb5_cc_set_flags(context, outcc, flags)))
+	return(code);
+#endif
+
+    if ((code = krb5_cc_start_seq_get(context, incc, &cur)))
+	goto cleanup;
+
+    while (!(code = krb5_cc_next_cred(context, incc, &cur, &creds))) {
+	code = krb5_cc_store_cred(context, outcc, &creds);
+	krb5_free_cred_contents(context, &creds);
+	if (code)
+	    goto cleanup;
+    }
+
+    if (code != KRB5_CC_END)
+	goto cleanup;
+
+    code = krb5_cc_end_seq_get(context, incc, &cur);
+    cur = 0;
+    if (code)
+        goto cleanup;
+
+    code = 0;
+
+cleanup:
+    flags = KRB5_TC_OPENCLOSE;
+
+    /* If set then we are in an error pathway */
+    if (cur) 
+      krb5_cc_end_seq_get(context, incc, &cur);
+
+    if (code)
+	krb5_cc_set_flags(context, incc, flags);
+    else
+	code = krb5_cc_set_flags(context, incc, flags);
+
+#if 0
+    if (code)
+	krb5_cc_set_flags(context, outcc, flags);
+    else
+	code = krb5_cc_set_flags(context, outcc, flags);
+#endif
+
+    return(code);
+}
diff --git a/mechglue/src/lib/krb5/ccache/ccdefault.c b/mechglue/src/lib/krb5/ccache/ccdefault.c
new file mode 100644
index 000000000..3c363229a
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccdefault.c
@@ -0,0 +1,109 @@
+/*
+ * lib/krb5/ccache/ccdefault.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Find default credential cache
+ */
+
+#include "k5-int.h"
+
+#if defined(USE_LOGIN_LIBRARY)
+#include "KerberosLoginPrivate.h"
+#elif defined(USE_LEASH)
+static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL;
+static HANDLE hLeashDLL = INVALID_HANDLE_VALUE;
+#endif
+
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_default(krb5_context context, krb5_ccache *ccache)
+{
+	krb5_os_context	os_ctx;
+
+	if (!context || context->magic != KV5M_CONTEXT)
+		return KV5M_CONTEXT;
+	
+	os_ctx = context->os_context;
+	
+	return krb5_cc_resolve(context, krb5_cc_default_name(context), ccache);
+}
+
+/* This is the internal function which opens the default ccache.  On platforms supporting
+   the login library's automatic popup dialog to get tickets, this function also updated the
+   library's internal view of the current principal associated with this cache. 
+   
+   All krb5 and GSS functions which need to open a cache to get a tgt to obtain service tickets
+   should call this function, not krb5_cc_default() */
+
+krb5_error_code KRB5_CALLCONV
+krb5int_cc_default(krb5_context context, krb5_ccache *ccache)
+{
+    if (!context || context->magic != KV5M_CONTEXT) {
+        return KV5M_CONTEXT;
+    }
+
+#ifdef USE_LOGIN_LIBRARY
+    {
+        /* make sure the default cache has tix before you open it */
+        KLStatus err = klNoErr;
+        char *outCacheName = NULL;
+        
+        /* Try to make sure a krb5 tgt is in the cache */
+        err = __KLInternalAcquireInitialTicketsForCache (krb5_cc_default_name (context), kerberosVersion_V5, 
+                                                         NULL, NULL, &outCacheName);
+        if (err == klNoErr) {
+            /* This function tries to get tickets and put them in the specified 
+            cache, however, if the cache does not exist, it may choose to put 
+            them elsewhere (ie: the system default) so we set that here */
+            if (strcmp (krb5_cc_default_name (context), outCacheName) != 0) {
+                krb5_cc_set_default_name (context, outCacheName);
+            }
+            KLDisposeString (outCacheName);
+        }
+    }
+#else
+#ifdef USE_LEASH
+    if ( hLeashDLL == INVALID_HANDLE_VALUE ) {
+        hLeashDLL = LoadLibrary("leashw32.dll");
+        if ( hLeashDLL != INVALID_HANDLE_VALUE ) {
+            (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
+            GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
+        }
+    }
+    
+    if ( pLeash_AcquireInitialTicketsIfNeeded ) {
+	char ccname[256]="";
+        pLeash_AcquireInitialTicketsIfNeeded(context, NULL, ccname, sizeof(ccname));
+	if (ccname[0]) {
+            if (strcmp (krb5_cc_default_name (context),ccname) != 0) {
+                krb5_cc_set_default_name (context, ccname);
+            }
+	}
+    }
+#endif
+#endif
+
+    return krb5_cc_default (context, ccache);
+}
diff --git a/mechglue/src/lib/krb5/ccache/ccdefops.c b/mechglue/src/lib/krb5/ccache/ccdefops.c
new file mode 100644
index 000000000..cdeab0674
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccdefops.c
@@ -0,0 +1,50 @@
+/*
+ * lib/krb5/ccache/ccdefops.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Default credentials cache determination.  This is a separate file
+ * so that the user can more easily override it.
+ */
+
+#include "k5-int.h"
+
+#if defined(USE_CCAPI)
+
+/*
+ * Macs use the shared, memory based credentials cache
+ * Windows may also use the ccapi cache, but only if the Krbcc32.dll
+ * can be found; otherwise it falls back to using the old 
+ * file-based ccache.
+ */
+#include "stdcc.h" /* from ccapi subdir */
+
+const krb5_cc_ops *krb5_cc_dfl_ops = &krb5_cc_stdcc_ops;
+
+#else
+
+#include "fcc.h"
+const krb5_cc_ops *krb5_cc_dfl_ops = &krb5_cc_file_ops;
+
+#endif
diff --git a/mechglue/src/lib/krb5/ccache/ccfns.c b/mechglue/src/lib/krb5/ccache/ccfns.c
new file mode 100644
index 000000000..5e80059ae
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ccfns.c
@@ -0,0 +1,130 @@
+/*
+ * lib/krb5/ccache/ccfns.c
+ *
+ * Copyright 2000 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Dispatch methods for credentials cache code.
+ */
+
+#include "k5-int.h"
+
+const char * KRB5_CALLCONV
+krb5_cc_get_name (krb5_context context, krb5_ccache cache)
+{
+    return cache->ops->get_name(context, cache);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_gen_new (krb5_context context, krb5_ccache *cache)
+{
+    return (*cache)->ops->gen_new(context, cache);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_initialize(krb5_context context, krb5_ccache cache,
+		   krb5_principal principal)
+{
+    return cache->ops->init(context, cache, principal);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_destroy (krb5_context context, krb5_ccache cache)
+{
+    return cache->ops->destroy(context, cache);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_close (krb5_context context, krb5_ccache cache)
+{
+    return cache->ops->close(context, cache);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_store_cred (krb5_context context, krb5_ccache cache,
+		    krb5_creds *creds)
+{
+    return cache->ops->store(context, cache, creds);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_retrieve_cred (krb5_context context, krb5_ccache cache,
+		       krb5_flags flags, krb5_creds *mcreds,
+		       krb5_creds *creds)
+{
+    return cache->ops->retrieve(context, cache, flags, mcreds, creds);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_get_principal (krb5_context context, krb5_ccache cache,
+		       krb5_principal *principal)
+{
+    return cache->ops->get_princ(context, cache, principal);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_start_seq_get (krb5_context context, krb5_ccache cache,
+		       krb5_cc_cursor *cursor)
+{
+    return cache->ops->get_first(context, cache, cursor);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_next_cred (krb5_context context, krb5_ccache cache,
+		   krb5_cc_cursor *cursor, krb5_creds *creds)
+{
+    return cache->ops->get_next(context, cache, cursor, creds);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_end_seq_get (krb5_context context, krb5_ccache cache,
+		     krb5_cc_cursor *cursor)
+{
+    return cache->ops->end_get(context, cache, cursor);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_remove_cred (krb5_context context, krb5_ccache cache, krb5_flags flags,
+		     krb5_creds *creds)
+{
+    return cache->ops->remove_cred(context, cache, flags, creds);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_set_flags (krb5_context context, krb5_ccache cache, krb5_flags flags)
+{
+    return cache->ops->set_flags(context, cache, flags);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_get_flags (krb5_context context, krb5_ccache cache, krb5_flags *flags)
+{
+    return cache->ops->get_flags(context, cache, flags);
+}
+
+const char * KRB5_CALLCONV
+krb5_cc_get_type (krb5_context context, krb5_ccache cache)
+{
+    return cache->ops->prefix;
+}
diff --git a/mechglue/src/lib/krb5/ccache/fcc.h b/mechglue/src/lib/krb5/ccache/fcc.h
new file mode 100644
index 000000000..f349da998
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/fcc.h
@@ -0,0 +1,36 @@
+/*
+ * lib/krb5/ccache/file/fcc.h
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This file contains constant and function declarations used in the
+ * file-based credential cache routines.
+ */
+
+#ifndef __KRB5_FILE_CCACHE__
+#define __KRB5_FILE_CCACHE__
+
+extern const krb5_cc_ops krb5_cc_file_ops;
+
+#endif /* __KRB5_FILE_CCACHE__ */
diff --git a/mechglue/src/lib/krb5/ccache/scc.h b/mechglue/src/lib/krb5/ccache/scc.h
new file mode 100644
index 000000000..98acbc25c
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/scc.h
@@ -0,0 +1,101 @@
+/*
+ * lib/krb5/ccache/stdio/scc.h
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This file contains constant and function declarations used in the
+ * file-based credential cache routines.
+ */
+
+#ifndef __KRB5_FILE_CCACHE__
+#define __KRB5_FILE_CCACHE__
+
+#include "k5-int.h"
+#include <stdio.h>
+
+#define KRB5_OK 0
+
+#define KRB5_SCC_MAXLEN 100
+
+/*
+ * SCC version 2 contains type information for principals.  SCC
+ * version 1 does not.  The code will accept either, and depending on
+ * what KRB5_SCC_DEFAULT_FVNO is set to, it will create version 1 or
+ * version 2 SCC caches.
+ *
+ */
+
+#define KRB5_SCC_FVNO_1   0x0501	/* krb v5, scc v1 */
+#define KRB5_SCC_FVNO_2   0x0502	/* krb v5, scc v2 */
+#define KRB5_SCC_FVNO_3   0x0503	/* krb v5, scc v3 */
+#define KRB5_SCC_FVNO_4   0x0504	/* krb v5, scc v4 */
+
+#define	SCC_OPEN_AND_ERASE	1
+#define	SCC_OPEN_RDWR		2
+#define	SCC_OPEN_RDONLY		3
+
+/* Credential file header tags.
+ * The header tags are constructed as:
+ *     krb5_ui_2       tag
+ *     krb5_ui_2       len
+ *     krb5_octet      data[len]
+ * This format allows for older versions of the fcc processing code to skip
+ * past unrecognized tag formats.
+ */
+#define SCC_TAG_DELTATIME	1
+
+#ifndef TKT_ROOT
+#define TKT_ROOT "/tmp/tkt"
+#endif
+
+/* macros to make checking flags easier */
+#define OPENCLOSE(id) (((krb5_scc_data *)id->data)->flags & KRB5_TC_OPENCLOSE)
+
+typedef struct _krb5_scc_data {
+     char *filename;
+     FILE *file;
+     krb5_flags flags;
+     char stdio_buffer[BUFSIZ];
+     int version;
+} krb5_scc_data;
+
+/* An off_t can be arbitrarily complex */
+typedef struct _krb5_scc_cursor {
+    long pos;
+} krb5_scc_cursor;
+
+#define MAYBE_OPEN(context, ID, MODE) \
+{									\
+    if (OPENCLOSE (ID)) {						\
+	krb5_error_code maybe_open_ret = krb5_scc_open_file (context, ID,MODE);	\
+	if (maybe_open_ret) return maybe_open_ret; } }
+
+#define MAYBE_CLOSE(context, ID, RET) \
+{									\
+    if (OPENCLOSE (ID)) {						\
+	krb5_error_code maybe_close_ret = krb5_scc_close_file (context, ID);	\
+	if (!(RET)) RET = maybe_close_ret; } }
+
+/* DO NOT ADD ANYTHING AFTER THIS #endif */
+#endif /* __KRB5_FILE_CCACHE__ */
diff --git a/mechglue/src/lib/krb5/ccache/ser_cc.c b/mechglue/src/lib/krb5/ccache/ser_cc.c
new file mode 100644
index 000000000..a7d34f93d
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/ser_cc.c
@@ -0,0 +1,202 @@
+/*
+ * lib/krb5/ccache/ser_rc.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_rcdfl.c - Serialize replay cache context.
+ */
+#include "k5-int.h"
+
+/*
+ * Routines to deal with externalizing krb5_ccache.
+ *	krb5_ccache_size();
+ *	krb5_ccache_externalize();
+ *	krb5_ccache_internalize();
+ */
+static krb5_error_code krb5_ccache_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_ccache_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_ccache_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/*
+ * Serialization entry for this type.
+ */
+static const krb5_ser_entry krb5_ccache_ser_entry = {
+    KV5M_CCACHE,			/* Type			*/
+    krb5_ccache_size,			/* Sizer routine	*/
+    krb5_ccache_externalize,		/* Externalize routine	*/
+    krb5_ccache_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_ccache_size()	- Determine the size required to externalize
+ *				  this krb5_ccache variant.
+ */
+static krb5_error_code
+krb5_ccache_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_ccache		ccache;
+    size_t		required;
+
+    kret = EINVAL;
+    if ((ccache = (krb5_ccache) arg)) {
+	/*
+	 * Saving FILE: variants of krb5_ccache requires at minimum:
+	 *	krb5_int32	for KV5M_CCACHE
+	 *	krb5_int32	for length of ccache name.
+	 *	krb5_int32	for KV5M_CCACHE
+	 */
+	required = sizeof(krb5_int32) * 3;
+	if (ccache->ops && ccache->ops->prefix)
+	    required += (strlen(ccache->ops->prefix)+1);
+
+	/*
+	 * The ccache name is formed as follows:
+	 *	<prefix>:<name>
+	 */
+	required += strlen(krb5_cc_get_name(kcontext, ccache));
+
+	kret = 0;
+	*sizep += required;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_ccache_externalize()	- Externalize the krb5_ccache.
+ */
+static krb5_error_code
+krb5_ccache_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_ccache		ccache;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+    char		*ccname;
+    size_t		namelen;
+    const char		*fnamep;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((ccache = (krb5_ccache) arg)) {
+	kret = ENOMEM;
+	if (!krb5_ccache_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KV5M_CCACHE, &bp, &remain);
+
+	    /* Calculate the length of the name */
+	    namelen = (ccache->ops && ccache->ops->prefix) ?
+		strlen(ccache->ops->prefix)+1 : 0;
+	    fnamep = krb5_cc_get_name(kcontext, ccache);
+	    namelen += (strlen(fnamep)+1);
+
+	    if ((ccname = (char *) malloc(namelen))) {
+		/* Format the ccache name. */
+		if (ccache->ops && ccache->ops->prefix)
+		    sprintf(ccname, "%s:%s", ccache->ops->prefix, fnamep);
+		else
+		    strcpy(ccname, fnamep);
+
+		/* Put the length of the file name */
+		(void) krb5_ser_pack_int32((krb5_int32) strlen(ccname),
+					   &bp, &remain);
+		
+		/* Put the name */
+		(void) krb5_ser_pack_bytes((krb5_octet *) ccname,
+					   strlen(ccname),
+					   &bp, &remain);
+
+		/* Put the trailer */
+		(void) krb5_ser_pack_int32(KV5M_CCACHE, &bp, &remain);
+		kret = 0;
+		*buffer = bp;
+		*lenremain = remain;
+		free(ccname);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_ccache_internalize()	- Internalize the krb5_ccache.
+ */
+static krb5_error_code
+krb5_ccache_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_ccache		ccache;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    char		*ccname;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_CCACHE) {
+	kret = ENOMEM;
+
+	/* Get the length of the ccache name */
+	kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+
+	if (!kret &&
+	    (ccname = (char *) malloc((size_t) (ibuf+1))) &&
+	    !(kret = krb5_ser_unpack_bytes((krb5_octet *) ccname,
+					   (size_t) ibuf,
+					   &bp, &remain))) {
+	    ccname[ibuf] = '\0';
+	    if (!(kret = krb5_cc_resolve(kcontext, ccname, &ccache)) &&
+		!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) &&
+		(ibuf == KV5M_CCACHE)) {
+		*buffer = bp;
+		*lenremain = remain;
+		*argp = (krb5_pointer) ccache;
+	    }
+	    free(ccname);
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the ccache serializer.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_ccache_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_ccache_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5/ccache/t_cc.c b/mechglue/src/lib/krb5/ccache/t_cc.c
new file mode 100644
index 000000000..6559fb2bd
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/t_cc.c
@@ -0,0 +1,292 @@
+/*
+ * lib/krb5/ccache/scc_test.c
+ *
+ * Copyright 2000 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+
+#include "krb5.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "com_err.h"
+
+#define KRB5_OK 0
+
+krb5_creds test_creds;
+
+int debug=0;
+
+static void init_structs(void)
+{
+  static int add=0x12345;
+
+  static krb5_address addr;
+
+  static krb5_address *addrs[] = {
+    &addr,
+    0,
+  };
+
+  addr.magic = KV5M_ADDRESS;
+  addr.addrtype = ADDRTYPE_INET;
+  addr.length = 4;
+  addr.contents = (krb5_octet *) &add;
+
+  test_creds.magic = KV5M_CREDS;
+  test_creds.client = NULL;
+  test_creds.server = NULL;
+
+  test_creds.keyblock.magic = KV5M_KEYBLOCK;
+  test_creds.keyblock.contents = 0;
+  test_creds.keyblock.enctype = 1;
+  test_creds.keyblock.length = 1;
+  test_creds.keyblock.contents = (unsigned char *) "1";
+  test_creds.times.authtime = 1111;
+  test_creds.times.starttime = 2222;
+  test_creds.times.endtime = 3333;
+  test_creds.times.renew_till = 4444;
+  test_creds.is_skey = 1;
+  test_creds.ticket_flags = 5555;
+  test_creds.addresses = addrs;
+  
+#define SET_TICKET(ent, str) {ent.magic = KV5M_DATA; ent.length = sizeof(str); ent.data = str;}
+  SET_TICKET(test_creds.ticket, "This is ticket 1");
+  SET_TICKET(test_creds.second_ticket, "This is ticket 2");
+  test_creds.authdata = NULL;
+}
+
+static void init_test_cred(krb5_context context)
+{
+#define REALM "REALM"
+  krb5_build_principal(context, &test_creds.client, sizeof(REALM), REALM,
+		       "client-comp1", "client-comp2", NULL);
+
+  krb5_build_principal(context, &test_creds.server, sizeof(REALM), REALM,
+		       "server-comp1", "server-comp2", NULL);
+}
+
+static void free_test_cred(krb5_context context)
+{
+  krb5_free_principal(context, test_creds.client);
+
+  krb5_free_principal(context, test_creds.server);
+
+}
+
+#define CHECK(kret,msg) \
+     if (kret != KRB5_OK) {\
+	  com_err(msg, kret, ""); \
+          fflush(stderr);\
+          exit(1);\
+     } else if(debug) printf("%s went ok\n", msg);
+
+#define CHECK_STR(str,msg) \
+     if (str == 0) {\
+	  com_err(msg, kret, "");\
+          exit(1);\
+     } else if(debug) printf("%s went ok\n", msg);
+
+#define CHECK_FAIL(experr, kret, msg) \
+     if (experr != kret) { CHECK(kret, msg);}
+
+static void cc_test(krb5_context context, const char *name, int flags)
+{
+     krb5_ccache id, id2;
+     krb5_creds creds;
+     krb5_error_code kret;
+     krb5_cc_cursor cursor;
+     const char *c_name;
+     char newcache[300];
+
+     init_test_cred(context);
+
+     kret = krb5_cc_resolve(context, name, &id);
+     CHECK(kret, "resolve");
+     kret = krb5_cc_initialize(context, id, test_creds.client);
+     CHECK(kret, "initialize");
+     
+     c_name = krb5_cc_get_name(context, id);
+     CHECK_STR(c_name, "get_name");
+
+     c_name = krb5_cc_get_type(context, id);
+     CHECK_STR(c_name, "get_prefix");
+
+     kret = krb5_cc_store_cred(context, id, &test_creds);
+     CHECK(kret, "store");
+
+     kret = krb5_cc_set_flags (context, id, flags);
+     CHECK(kret, "set_flags");
+     kret = krb5_cc_start_seq_get(context, id, &cursor);
+     CHECK(kret, "start_seq_get");
+     kret = 0;
+     while (kret != KRB5_CC_END) {
+	  if(debug) printf("Calling next_cred\n");
+	  kret = krb5_cc_next_cred(context, id, &cursor, &creds);
+	  if(kret == KRB5_CC_END) {
+	    if(debug) printf("next_cred: ok at end\n");
+	  }
+	  else {
+	    CHECK(kret, "next_cred");
+	    krb5_free_cred_contents(context, &creds);
+	  }
+
+     }
+     kret = krb5_cc_end_seq_get(context, id, &cursor);
+     CHECK(kret, "end_seq_get");
+
+     kret = krb5_cc_close(context, id);
+     CHECK(kret, "close");
+
+
+     /* ------------------------------------------------- */
+     kret = krb5_cc_resolve(context, name, &id);
+     CHECK(kret, "resolve2");
+
+     {
+       /* Copy the cache test*/
+       sprintf(newcache, "%s.new", name);
+       kret = krb5_cc_resolve(context, newcache, &id2);
+       CHECK(kret, "resolve of new cache");
+       
+       /* This should fail as the new creds are not initialized */
+       kret = krb5_cc_copy_creds(context, id, id2);
+       CHECK_FAIL(KRB5_FCC_NOFILE, kret, "copy_creds");
+       
+       kret = krb5_cc_initialize(context, id2, test_creds.client);
+       CHECK(kret, "initialize of id2");
+
+       kret = krb5_cc_copy_creds(context, id, id2);
+       CHECK(kret, "copy_creds");
+
+       kret = krb5_cc_destroy(context, id2);
+       CHECK(kret, "destroy new cache");
+     }
+
+     /* Destroy the first cache */
+     kret = krb5_cc_destroy(context, id);
+     CHECK(kret, "destroy");
+
+#if 0
+     /* ----------------------------------------------------- */
+     /* Tests the generate new code */
+     kret = krb5_cc_resolve(context, name, &id);
+     CHECK(kret, "resolve");
+     kret = krb5_cc_gen_new(context, &id);
+     CHECK(kret, "gen_new");
+     kret = krb5_cc_destroy(context, id);
+     CHECK(kret, "destroy");
+#endif
+
+     free_test_cred(context);
+
+}
+
+static void do_test(krb5_context context, const char *prefix)
+{
+  char name[300];
+
+  sprintf(name, "%s/tmp/cctest.%ld", prefix, (long) getpid());
+  printf("Starting test on %s\n", name);
+  cc_test (context, name, 0);
+  cc_test (context, name, !0);
+  printf("Test on %s passed\n", name);
+}
+
+static void test_misc(krb5_context context)
+{
+  /* Tests for certain error returns */
+  krb5_error_code	kret;
+  krb5_ccache id;
+  extern krb5_cc_ops *krb5_cc_dfl_ops;
+  krb5_cc_ops *ops_save;
+
+  fprintf(stderr, "Testing miscellaneous error conditions\n");
+
+  kret = krb5_cc_resolve(context, "unknown_method_ep:/tmp/name", &id);
+  if (kret != KRB5_CC_UNKNOWN_TYPE) {
+    CHECK(kret, "resolve unknown type");
+  }
+
+  /* Test for not specifiying a cache type with no defaults */
+  ops_save = krb5_cc_dfl_ops;
+  krb5_cc_dfl_ops = 0;
+
+  kret = krb5_cc_resolve(context, "/tmp/e", &id);
+  if (kret != KRB5_CC_BADNAME) {
+    CHECK(kret, "resolve no builtin type");
+  }
+
+  krb5_cc_dfl_ops = ops_save;
+
+}
+extern const krb5_cc_ops krb5_mcc_ops;
+extern const krb5_cc_ops krb5_fcc_ops;
+
+int main (void)
+{
+    krb5_context context;
+    krb5_error_code	kret;
+
+    initialize_krb5_error_table ();
+
+    if ((kret = krb5_init_context(&context))) {
+	    printf("Couldn't initialize krb5 library: %s\n",
+		   error_message(kret));
+	    exit(1);
+    }
+
+    kret = krb5_cc_register(context, &krb5_mcc_ops,0);
+    if(kret && kret != KRB5_CC_TYPE_EXISTS) {
+      CHECK(kret, "register_mem");
+    }
+
+    kret = krb5_cc_register(context, &krb5_fcc_ops,0);
+    if(kret && kret != KRB5_CC_TYPE_EXISTS) {
+      CHECK(kret, "register_mem");
+    }
+
+    /* Registering a second time tests for error return */
+    kret = krb5_cc_register(context, &krb5_fcc_ops,0);
+    if(kret != KRB5_CC_TYPE_EXISTS) {
+      CHECK(kret, "register_mem");
+    }
+
+    /* Registering with override should work */
+    kret = krb5_cc_register(context, &krb5_fcc_ops,1);
+    CHECK(kret, "register_mem override");
+
+    init_structs();
+
+    test_misc(context);
+    do_test(context, "");
+    do_test(context, "MEMORY:");
+    do_test(context, "FILE:");
+
+    krb5_free_context(context);
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/ccache/t_memory.c b/mechglue/src/lib/krb5/ccache/t_memory.c
new file mode 100644
index 000000000..b117aed33
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/t_memory.c
@@ -0,0 +1,140 @@
+/*
+ * lib/krb5/ccache/file/mcc_test.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+
+#include "mcc.h"
+
+krb5_data client1 = {
+#define DATA "client1-comp1"
+     sizeof(DATA),
+     DATA,
+#undef DATA
+};
+
+krb5_data client2 = {
+#define DATA "client1-comp2"
+     sizeof(DATA),
+     DATA,
+#undef DATA
+};
+
+krb5_data server1 = {
+#define DATA "server1-comp1"
+     sizeof(DATA),
+     DATA,
+#undef DATA
+};
+
+krb5_data server2 = {
+#define DATA "server1-comp2"
+     sizeof(DATA),
+     DATA,
+#undef DATA
+};
+
+krb5_creds test_creds = {
+     NULL,
+     NULL,
+     {
+	  1,
+	  1,
+	  (unsigned char *) "1"
+     },
+     {
+	  1111,
+	  2222,
+	  3333,
+	  4444
+     },
+     1,
+     5555,
+     {
+#define TICKET "This is ticket 1"
+     sizeof(TICKET),
+     TICKET,
+#undef TICKET
+     },
+     {
+#define TICKET "This is ticket 2"
+     sizeof(TICKET),
+     TICKET,
+#undef TICKET
+     },
+};
+
+void init_test_cred()
+{
+     test_creds.client = (krb5_principal) malloc(sizeof(krb5_data *)*3);
+     test_creds.client[0] = &client1;
+     test_creds.client[1] = &client2;
+     test_creds.client[2] = NULL;
+
+     test_creds.server = (krb5_principal) malloc(sizeof(krb5_data *)*3);
+     test_creds.server[0] = &server1;
+     test_creds.server[1] = &server2;
+     test_creds.server[2] = NULL;
+}
+
+#define CHECK(kret,msg) \
+     if (kret != KRB5_OK) {\
+	  printf("%s returned %d\n", msg, kret);\
+     };
+						   
+void mcc_test()
+{
+     krb5_ccache id;
+     krb5_creds creds;
+     krb5_error_code kret;
+     krb5_cc_cursor cursor;
+
+     init_test_cred();
+
+     kret = krb5_mcc_resolve(context, &id, "/tmp/tkt_test");
+     CHECK(kret, "resolve");
+     kret = krb5_mcc_initialize(context, id, test_creds.client);
+     CHECK(kret, "initialize");
+     kret = krb5_mcc_store(context, id, &test_creds);
+     CHECK(kret, "store");
+
+     kret = krb5_mcc_start_seq_get(context, id, &cursor);
+     CHECK(kret, "start_seq_get");
+     kret = 0;
+     while (kret != KRB5_CC_END) {
+	  printf("Calling next_cred\n");
+	  kret = krb5_mcc_next_cred(context, id, &cursor, &creds);
+	  CHECK(kret, "next_cred");
+     }
+     kret = krb5_mcc_end_seq_get(context, id, &cursor);
+     CHECK(kret, "end_seq_get");
+
+     kret = krb5_mcc_destroy(context, id);
+     CHECK(kret, "destroy");
+     kret = krb5_mcc_close(context, id);
+     CHECK(kret, "close");
+}
+
diff --git a/mechglue/src/lib/krb5/ccache/t_stdio.c b/mechglue/src/lib/krb5/ccache/t_stdio.c
new file mode 100644
index 000000000..a76d1fcd7
--- /dev/null
+++ b/mechglue/src/lib/krb5/ccache/t_stdio.c
@@ -0,0 +1,169 @@
+/*
+ * lib/krb5/ccache/stdio/scc_test.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+
+#include "scc.h"
+
+krb5_data client1 = {
+#define DATA "client1-comp1"
+     sizeof(DATA),
+     DATA,
+#undef DATA
+};
+
+krb5_data client2 = {
+#define DATA "client1-comp2"
+     sizeof(DATA),
+     DATA,
+#undef DATA
+};
+
+krb5_data server1 = {
+#define DATA "server1-comp1"
+     sizeof(DATA),
+     DATA,
+#undef DATA
+};
+
+krb5_data server2 = {
+#define DATA "server1-comp2"
+     sizeof(DATA),
+     DATA,
+#undef DATA
+};
+
+int x = 0x12345;
+krb5_address addr = {
+    ADDRTYPE_INET,
+    4,
+    (krb5_octet *) &x,
+};
+
+krb5_address *addrs[] = {
+    &addr,
+    0,
+};
+
+krb5_creds test_creds = {
+     NULL,
+     NULL,
+     {
+	  1,
+	  1,
+	  (unsigned char *) "1"
+     },
+     {
+	  1111,
+	  2222,
+	  3333,
+	  4444,
+     },
+     1,
+     5555,
+     addrs,
+     {
+#define TICKET "This is ticket 1"
+     sizeof(TICKET),
+     TICKET,
+#undef TICKET
+     },
+     {
+#define TICKET "This is ticket 2"
+     sizeof(TICKET),
+     TICKET,
+#undef TICKET
+     },
+};
+
+void init_test_cred()
+{
+     test_creds.client = (krb5_principal) malloc(sizeof(krb5_data *)*3);
+     test_creds.client[0] = &client1;
+     test_creds.client[1] = &client2;
+     test_creds.client[2] = NULL;
+
+     test_creds.server = (krb5_principal) malloc(sizeof(krb5_data *)*3);
+     test_creds.server[0] = &server1;
+     test_creds.server[1] = &server2;
+     test_creds.server[2] = NULL;
+}
+
+#define CHECK(kret,msg) \
+     if (kret != KRB5_OK) {\
+	  com_err(msg, kret, "");\
+     } else printf("%s went ok\n", msg);
+						   
+int flags = 0;
+void scc_test()
+{
+     krb5_ccache id;
+     krb5_creds creds;
+     krb5_error_code kret;
+     krb5_cc_cursor cursor;
+
+     init_test_cred();
+
+     kret = krb5_scc_resolve(context, &id, "/tmp/tkt_test");
+     CHECK(kret, "resolve");
+     kret = krb5_scc_initialize(context, id, test_creds.client);
+     CHECK(kret, "initialize");
+     kret = krb5_scc_store(id, &test_creds);
+     CHECK(kret, "store");
+
+     kret = krb5_scc_set_flags (id, flags);
+     CHECK(kret, "set_flags");
+     kret = krb5_scc_start_seq_get(id, &cursor);
+     CHECK(kret, "start_seq_get");
+     kret = 0;
+     while (kret != KRB5_CC_END) {
+	  printf("Calling next_cred\n");
+	  kret = krb5_scc_next_cred(id, &cursor, &creds);
+	  CHECK(kret, "next_cred");
+     }
+     kret = krb5_scc_end_seq_get(id, &cursor);
+     CHECK(kret, "end_seq_get");
+
+     kret = krb5_scc_close(id);
+     CHECK(kret, "close");
+
+
+     kret = krb5_scc_resolve(&id, "/tmp/tkt_test");
+     CHECK(kret, "resolve");
+     kret = krb5_scc_destroy(id);
+     CHECK(kret, "destroy");
+}
+
+int remove (s) char*s; { return unlink(s); }
+int main () {
+    initialize_krb5_error_table ();
+    init_test_cred ();
+    scc_test ();
+    flags = !flags;
+    scc_test ();
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/configure.in b/mechglue/src/lib/krb5/configure.in
new file mode 100644
index 000000000..1ddf76509
--- /dev/null
+++ b/mechglue/src/lib/krb5/configure.in
@@ -0,0 +1,23 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+AC_PROG_AWK
+dnl
+AC_C_CONST
+AC_TYPE_UID_T
+AC_TYPE_OFF_T
+dnl
+dnl
+KRB5_AC_REGEX_FUNCS
+KRB5_NEED_PROTO([#include <time.h>],strptime)
+dnl
+KRB5_SIGTYPE
+CHECK_SIGNALS
+KRB5_SOCKADDR_SA_LEN
+KRB5_GETPEERNAME_ARGS
+KRB5_GETSOCKNAME_ARGS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_PROGRAM
+KRB5_RUN_FLAGS
+dnl
+V5_AC_OUTPUT_MAKEFILE(. error_tables asn.1 ccache keytab krb rcache os posix)
diff --git a/mechglue/src/lib/krb5/error_tables/.Sanitize b/mechglue/src/lib/krb5/error_tables/.Sanitize
new file mode 100644
index 000000000..ba18e42bf
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/.Sanitize
@@ -0,0 +1,44 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+Makefile.in
+adm_err.et
+asn1_err.et
+configure
+configure.in
+init_ets.c
+kdb5_err.et
+krb5_err.et
+krb524_err.et
+kv5m_err.et
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/error_tables/.rconf b/mechglue/src/lib/krb5/error_tables/.rconf
new file mode 100644
index 000000000..9adf82b0c
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/.rconf
@@ -0,0 +1,4 @@
+ignore *.h
+ignore *.c
+ignore .rconf
+link init_ets.c
diff --git a/mechglue/src/lib/krb5/error_tables/ChangeLog b/mechglue/src/lib/krb5/error_tables/ChangeLog
new file mode 100644
index 000000000..326106b5e
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/ChangeLog
@@ -0,0 +1,468 @@
+2004-10-13  Alexandra Ellwood  <lxs@mit.edu>
+
+	* krb5_err.et: added KRB5_DELTAT_BADFORMAT for 
+	krb5_string_to_deltat.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Drop init_ets code.
+
+2004-01-06  Jeffrey Altman <jaltman@mit.edu>
+
+    * krb5_err.et (KRB5_CC_NOSUPP) new ccache error code
+
+2003-12-12  Jeffrey Altman <jaltman@mit.edu>
+
+    * krb5_err.et (KRB5_CC_READONLY) new ccache error code
+
+2003-07-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* init_ets.c (krb5_init_ets): Only initialize error tables once -
+	so that init_conext/free_context loops do not result in memory
+	leaks.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et (KRB5_ERR_NO_SERVICE): New error code.
+
+2003-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb524_err.et: New file, moved from ../../../krb524.  Add new
+	error code KRB524_KRB4_DISABLED.
+	* Makefile.in (STLIBOBJS, HDRS, OBJS, ETSRCS, SRCS, awk-windows):
+	Add it.
+	($(OUTPRE)krb524_err.$(OBJEXT)): List dependence on .c file.
+	* init_ets.c (krb5_init_ets): Call initialize_k524_error_table.
+
+2003-03-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et (KRB5_ERR_BAD_S2K_PARAMS): New error code.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-11-14  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove references to adm_err.et.  It's not used,
+	and conflicts with the krb4 kadm error table.
+
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil
+
+	* kv5m_err.et: Add magic numbers for new hardware preauth structures.
+
+	* krb5_err.et (KRB5_SAM_INVALID_ETYPE, KRB5_SAM_NO_CHECKSUM,
+	KRB5_SAM_BAD_CHECKSUM): New error codes for the new hardware
+	preauthentication code.
+
+2002-09-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ets.c (krb5_init_ets, krb5_free_ets): Use prototype style
+	function definitions.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (awk-windows): Put quotes around $(EHDRDIR) since it
+	contains forward slashes now.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et (KRB5_ERR_NUMERIC_REALM): New error code.
+
+2002-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et (KRB5KRB_AP_PATH_NOT_ACCEPTED,
+	KRB5KRB_ERR_RESPONSE_TOO_BIG): New error codes.
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et: Change several "credentials cache file" messages to
+	just say "credentials cache", so as to be applicable in the ccapi
+	case too.  (Miro's change from 1.2.x branch.)
+
+2002-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et (KRB5_EAI_FAIL, KRB5_EAI_NODATA, KRB5_EAI_NONAME,
+	KRB5_EAI_SERVICE): New error codes for getaddrinfo failures.
+
+2001-10-24  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_err.et: Add KRB5_KDB_NO_PERMITTED_KEY,
+	KRB5_KDB_NO_MATCHING_KEY for libkdb so we can return something
+	other than ENOENT (which was Just Wrong).
+
+2001-04-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (includes): New target.  Copy headers into proper
+	include directory.
+	(unixmac): Target deleted.
+	(THDRDIR): New variable.
+
+2000-10-26  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_err.et: Add error codes MISMATCH_INDEF and MISSING_EOC.
+
+2000-06-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* init_ets.c: Remove unused variable.
+
+1999-12-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et (KRB5_OBSOLETE_FN): New error code.
+
+1999-11-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et (KRB5_CONFIG_ETYPE_NOSUPP): New error code.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* krb5_err.et (KRB5_CC_NOT_KTYPE): New error code.
+
+1999-07-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Delete dependency info for isode error table that
+	was removed in early 1995.
+
+Mon May 10 15:25:19 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Mon May 18 17:09:22 1998  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_err.et: Clarify error for REALM_CANT_RESOLVE.
+
+Thu Apr 16 20:51:40 1998  Tom Yu  <tlyu@mit.edu>
+
+	* asn1_err.et (ASN1_BAD_GMTIME): Add code for case where bad
+	values are returned from gmtime().
+
+Fri Feb 27 18:03:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/krb5
+ 		directory, since we've moved the configure.in tests in
+ 		this directory to the toplevel lib/krb5 configure.in
+
+Wed Feb 18 16:21:57 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Feb  5 22:58:09 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5_err.et: Add a comment about the low 128 error codes being
+		defined by the Krb5 protocol spec.
+
+Sat Dec  6 02:27:37 1997  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_err.et: Add codes for Cygnus chpw.
+
+Fri Jul 25 15:25:02 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_err.et: Add error code for bad creation flags.
+
+Sat Feb 22 22:26:16 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Sat Feb 15 15:41:58 1997  Richard Basch  <basch@lehman.com>
+
+	* init_ets.c (krb5_finish_ets):
+		New routine to cleanup krb5 error tables
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+	* init_ets.c: dll export krb5_init_ets()
+
+Thu Jan  2 17:07:07 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Fri Dec 13 14:55:43 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5_err.et: Added the error codes KRB5_APPL_EXPIRED and
+	 	KRB5_LIB_EXPIRED.
+
+Tue Nov 19 17:06:26 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* krb5_err.et: add KRB5_KT_KVNONOTFOUND [krb5-libs/198]
+
+Wed Nov  6 11:15:32 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5_err.et: Make the KRB5_CONFIG_CANTOPEN and
+ 		KRB5_CONFIG_BADFORMAT error messages more clear that the
+  		problem is with the _Kerberos_ configuration file.
+
+Fri Oct 18 17:49:51 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kv5m_err.et: Add magic code for GSSAPI OID and GSSAPI QUEUE,
+ 		which are needed for the serialization routines.
+		
+Wed Jul 24 16:03:52 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* krb5_err.et: Added new error code KRB5_KT_NAME_TOOLONG
+
+Thu Jun 13 21:43:23 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to SS_RULES, ET_RULES
+
+Sat Mar 30 22:55:26 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS): Inlined the list of et-build source files in
+		SRCS, so that they are correctly included in the Mac
+		build.
+
+Wed Mar 13 13:05:46 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kv5m_err.et: Add KV5M_PASSWD_PHRASE_ELEMENT
+
+Fri Feb 16 12:04:06 1996  Theodore Y. Ts'o  <tytso@pao.MIT.EDU>
+
+	* krb5_err.et: Added new error table code KRB5_CONFIG_NODEFREALM.
+
+Fri Jan  5 12:23:44 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_err.et: Added error table code KRB5_FWD_BAD_PRINCIPAL.
+
+Thu Dec 21 18:46:45 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_err.et: Changed KRB5_SENDAUTH_MUTUAL_FAILED to
+		KRB5_MUTUAL_FAILED (since the error code is no longer used
+		in sendauth).  Added KRB5_CC_FORMAT for indicating a
+		problem in the credentials cache format.
+
+Wed Nov  8 02:45:56 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kv5m_err.et: Added magic number for krb5_preauth_ops.
+
+Mon Oct 23 21:24:12 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_err.et: Added new error code KRB5_GET_IN_TKT_LOOP.
+
+Fri Oct  6 22:03:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:57:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * kdb5_err.et : Change KRB5_KDB_BAD_KEYTYPE to KRB5_KDB_BAD_ENCTYPE
+	* krb5_err.et : Change KRB5_BAD_KEYTYPE to KRB5_BAD_ENCTYPE
+
+Tue Aug 29 13:37:14 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kv5m_err.et - Add magic numbers for DB_CONTEXT, AUTH_CONTEXT, KEYTAB
+		RCACHE and CCACHE.
+
+Mon Aug 28 12:53:01 1995    <tytso@rsts-11.mit.edu>
+
+	* kv5m_err.et: Added new error codes KV5M_ALT_METHOD and
+	        KV5M_ETYPE_INFO_ENTRY.
+
+Mon Aug 07 11:29:49 1995   Chris Provenzano  (proven@mit.edu)
+
+	* krb5_err.et: Add new error KRB5_KDB_BAD_KEYTYPE.
+
+Thu Aug 03 12:35:47 1995   Chris Provenzano  (proven@mit.edu)
+
+        * krb5_err.et: Add new error KRB5_KDB_BAD_SALTTYPE.
+
+Fri Jun  9 19:34:12 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Jun  8 23:46:29 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: don't install et-generated headers in the build tree
+
+Fri May 26 20:19:59 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for building shared libraries.
+
+Tue May 23 16:46:30 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Don't install the error table header files; they
+		shouldn't be needed by an end-programmer.
+
+Tue Apr 25 21:58:23 1995  Chris Provenzano  (proven@mit.edu)
+
+        * krb5_err.et: Add new error KRB5_TKT_NOT_FORWARDABLE.
+
+Thu Apr 13 16:36:10 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: clean target was cleaning too much for the PC.
+
+Wed Apr 5 16:29:25 1995 Keith Vetter (keithv@fusion.com)
+
+	* krb5_err.et: added KRB5_REALM_CANT_RESOLVE for more precise 
+           handling of not finding KDC.
+
+Fri Mar 31 16:06:21 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in (BUILDTOP2, etc): Back out previous change so that
+		it doesn't break people who are using VPATH to have
+		separate build directories.  (See comments in the Makefile.)
+
+Tue Mar 28 18:29:44 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (BUILDTOP2, etc):  Make it possible
+	to build the error tables on Unix before a Mac build.
+	(all-mac):  Don't build $(HDRS) on Mac.
+	(unixmac):  Build `includes'.
+	(clean-mac):  Add.
+	(includes, clean, .SUFFIXES, .et.h, .et.c):  Add, to make it
+	possible to run `make -f Makefile.in unixmac' successfully.
+	* configure.in (ASN1_{HDRS,OBJS,SRCS, BOGUS):  Remove, unused.
+	(CopyHeader rules):  Remove, they're now in Makefile.in.
+
+Fri Mar 24 14:25:15 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in (install): Add install rule for the error table
+		headers. 
+
+Tue Mar 21 21:06:06 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (all-unix): The "includes" target is *not* obsolete;
+		it's necessary to copy the header files to the build tree.
+
+Fri Mar 17 19:42:45 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Eliminate, duplicate.
+	(SRCS):  Eliminate $(srcdir) which causes mac problems.
+	(all-unix):  Eliminate obsolete "includes".
+	(all-mac):  Add.
+	(unixmac):  Add $(SRCS) so that the .c source files will be created
+	here in the original "configure tree on Unix" stage of the build.
+
+Wed Mar 15 12:24:25 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: disabled the awk part of the makefile.
+
+Tue Mar 7 21:40:18 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed library name for the PC.
+
+Thu Mar  2 23:33:21 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (unixmac):  New target, runs on Unix to build include
+	files for Mac build.
+
+Tue Feb 28 00:37:58 1995  John Gilmore  (gnu at toad.com)
+
+	* init_ets.c:  Avoid <krb5/...> includes.
+
+Tue Feb 21 18:25:51 1995  Mark Eichin  (eichin@tweedledumber.cygnus.com)
+
+	* init_ets.c (krb5_init_ets): use old-style definition.
+
+Tue Feb 21 0:57:40 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work for PC
+        * init_ets.c: 
+           added INTERFACE for windows
+           removed PROTOTYPE macro from the function
+
+Fri Feb 10 14:56:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile:
+	* configure.in: 
+	* init_ets.c (krb5_init_ets): Remove isode cruft.
+
+Thu Feb  2 20:49:10 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* krb5_err.et (KRB5KRB_AP_ERR_V4_REPLY): new error code for V4
+	reply to a V5 request.
+
+Mon Dec 19 17:10:13 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_err.et (KV5M_CONTEXT, KV5M_OS_CONTEXT): Add new error codes.
+
+Fri Nov 18 15:29:55 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_err.et (KV5M_KEYTAB_ENTRY): Add new error code
+
+Fri Nov 18 00:23:51 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* Makefile.in (clean): remove $(BOGUS)
+	(HDRS): use ASN1_HDRS, not ASN1_SRCS. (from epeisach)
+
+Thu Nov 17 00:41:39 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_err.et (KRB5_CC_WRITE_ERR): Add new error code.
+
+Fri Nov 11 07:10:25 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: fix some typos for kv5m_err.et
+
+Thu Nov 10 22:12:43 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kv5m_err.et: Add support for krb5_address table; rename
+		KV5M_AUTH_DATA to follow the convention properly.
+
+Thu Nov  3 16:39:49 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in:
+	* Makefile.in:
+	* kv5m_err.et: Add the kv5m error table.
+
+Fri Oct 14 23:07:48 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* init_ets.c (krb5_init_ets): Fix typo in spelling of KRB5_USE_ISODE.
+
+Thu Sep 29 15:09:03 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_err.et (KRB5_KDCREP_SKEW, KRB5_IN_TKT_REALM_MISMATCH,
+	  KRB5_SERVICE_UNKNOWN):
+	  	Added two new error codes.
+
+Wed Sep 21 18:00:25 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_err.et (KRB5KRB_AP_ERR_ILL_CR_TKT): Added new error code.
+
+Sat Jul 16 05:59:53 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* krb5_err.et: missing space between comma and doublequote
+
+Tue Jun 28 19:11:43 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: doing the right thing with new error tables
+
+	* configure.in: adding ISODE_DEFS
+	* init_ets.c: folding in Harry's changes
+
diff --git a/mechglue/src/lib/krb5/error_tables/Makefile.in b/mechglue/src/lib/krb5/error_tables/Makefile.in
new file mode 100644
index 000000000..cbcc3360d
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/Makefile.in
@@ -0,0 +1,81 @@
+thisconfigdir=./..
+myfulldir=lib/krb5/error_tables
+mydir=error_tables
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=error_tables
+##DOS##OBJFILE=..\$(OUTPRE)err_tbls.lst
+
+THDRDIR=$(BUILDTOP)$(S)include
+EHDRDIR=$(BUILDTOP)$(S)include$(S)krb5
+
+STLIBOBJS= asn1_err.o kdb5_err.o krb5_err.o \
+      kv5m_err.o krb524_err.o
+
+HDRS= asn1_err.h kdb5_err.h krb5_err.h kv5m_err.h krb524_err.h
+OBJS= $(OUTPRE)asn1_err.$(OBJEXT) $(OUTPRE)kdb5_err.$(OBJEXT) $(OUTPRE)krb5_err.$(OBJEXT) \
+      $(OUTPRE)kv5m_err.$(OBJEXT) $(OUTPRE)krb524_err.$(OBJEXT)
+ETSRCS= asn1_err.c kdb5_err.c krb5_err.c kv5m_err.c krb524_err.c
+SRCS= asn1_err.c kdb5_err.c krb5_err.c kv5m_err.c krb524_err.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+all-libobjs: $(HDRS)
+
+includes:: $(HDRS)
+	for f in $(HDRS) ; do \
+		if cmp $$f $(THDRDIR)/$$f >/dev/null 2>&1; then :; \
+		else \
+			(set -x; $(RM) $(THDRDIR)/$$f; \
+			 $(CP) $$f $(THDRDIR)/$$f) ; \
+		fi ; \
+	done
+
+awk-windows:
+	$(AWK) -f $(SRCTOP)/util/et/et_h.awk outfile=asn1_err.h asn1_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_h.awk outfile=kdb5_err.h kdb5_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_h.awk outfile=krb5_err.h krb5_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_h.awk outfile=kv5m_err.h kv5m_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_h.awk outfile=krb524_err.h krb524_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_c.awk outfile=asn1_err.c asn1_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_c.awk outfile=kdb5_err.c kdb5_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_c.awk outfile=krb5_err.c krb5_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_c.awk outfile=kv5m_err.c kv5m_err.et
+	$(AWK) -f $(SRCTOP)/util/et/et_c.awk outfile=krb524_err.c krb524_err.et
+	if exist asn1_err.h copy asn1_err.h "$(EHDRDIR)"
+	if exist kdb5_err.h copy kdb5_err.h "$(EHDRDIR)"
+	if exist krb5_err.h copy krb5_err.h "$(EHDRDIR)"
+	if exist kv5m_err.h copy kv5m_err.h "$(EHDRDIR)"
+	if exist krb524_err.h copy krb524_err.h "$(EHDRDIR)"
+
+#
+# dependencies for traditional makes
+#
+$(OUTPRE)asn1_err.$(OBJEXT): asn1_err.c
+$(OUTPRE)kdb5_err.$(OBJEXT): kdb5_err.c
+$(OUTPRE)krb5_err.$(OBJEXT): krb5_err.c
+$(OUTPRE)kv5m_err.$(OBJEXT): kv5m_err.c
+$(OUTPRE)krb524_err.$(OBJEXT): krb524_err.c
+
+clean-unix:: clean-libobjs
+	$(RM) $(HDRS) $(ETSRCS)
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+asn1_err.so asn1_err.po $(OUTPRE)asn1_err.$(OBJEXT): \
+  asn1_err.c $(COM_ERR_DEPS)
+kdb5_err.so kdb5_err.po $(OUTPRE)kdb5_err.$(OBJEXT): \
+  kdb5_err.c $(COM_ERR_DEPS)
+krb5_err.so krb5_err.po $(OUTPRE)krb5_err.$(OBJEXT): \
+  krb5_err.c $(COM_ERR_DEPS)
+kv5m_err.so kv5m_err.po $(OUTPRE)kv5m_err.$(OBJEXT): \
+  kv5m_err.c $(COM_ERR_DEPS)
+krb524_err.so krb524_err.po $(OUTPRE)krb524_err.$(OBJEXT): \
+  krb524_err.c $(COM_ERR_DEPS)
diff --git a/mechglue/src/lib/krb5/error_tables/asn1_err.et b/mechglue/src/lib/krb5/error_tables/asn1_err.et
new file mode 100644
index 000000000..06078ffbc
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/asn1_err.et
@@ -0,0 +1,15 @@
+error_table asn1
+error_code ASN1_BAD_TIMEFORMAT, "ASN.1 failed call to system time library"
+error_code ASN1_MISSING_FIELD, "ASN.1 structure is missing a required field"
+error_code ASN1_MISPLACED_FIELD, "ASN.1 unexpected field number"
+error_code ASN1_TYPE_MISMATCH, "ASN.1 type numbers are inconsistent"
+error_code ASN1_OVERFLOW, "ASN.1 value too large"
+error_code ASN1_OVERRUN, "ASN.1 encoding ended unexpectedly"
+error_code ASN1_BAD_ID, "ASN.1 identifier doesn't match expected value"
+error_code ASN1_BAD_LENGTH, "ASN.1 length doesn't match expected value"
+error_code ASN1_BAD_FORMAT, "ASN.1 badly-formatted encoding"
+error_code ASN1_PARSE_ERROR, "ASN.1 parse error"
+error_code ASN1_BAD_GMTIME, "ASN.1 bad return from gmtime"
+error_code ASN1_MISMATCH_INDEF, "ASN.1 non-constructed indefinite encoding"
+error_code ASN1_MISSING_EOC, "ASN.1 missing expected EOC"
+end
diff --git a/mechglue/src/lib/krb5/error_tables/init_ets.c b/mechglue/src/lib/krb5/error_tables/init_ets.c
new file mode 100644
index 000000000..56a750e75
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/init_ets.c
@@ -0,0 +1,50 @@
+/*
+ * lib/krb5/error_tables/init_ets.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Initialize Kerberos library error tables.
+ */
+
+#include "k5-int.h"
+
+void
+krb5_init_ets (krb5_context context)
+{
+    static int inited = 0;
+
+    if (inited == 0) {
+	    initialize_krb5_error_table();
+	    initialize_kv5m_error_table();
+	    initialize_kdb5_error_table();
+	    initialize_asn1_error_table();
+	    initialize_k524_error_table();
+	    inited++;
+    }
+}
+
+void
+krb5_free_ets (krb5_context context)
+{
+}
diff --git a/mechglue/src/lib/krb5/error_tables/kdb5_err.et b/mechglue/src/lib/krb5/error_tables/kdb5_err.et
new file mode 100644
index 000000000..aee3c4a6d
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/kdb5_err.et
@@ -0,0 +1,71 @@
+#
+# lib/krb5/error_tables/kdb5_err.et
+#
+# Copyright 1990 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+#
+# The Kerberos v5 database library error code table.
+#
+error_table kdb5
+
+ec KRB5_KDB_RCSID,	"$Id$"
+# /* From the server side routines */
+ec KRB5_KDB_INUSE,		"Entry already exists in database"
+ec KRB5_KDB_UK_SERROR,		"Database store error"
+ec KRB5_KDB_UK_RERROR,		"Database read error"
+ec KRB5_KDB_UNAUTH,		"Insufficient access to perform requested operation"
+# KRB5_KDB_DATA isn't really an error, but...
+ec KRB5_KDB_NOENTRY,		"No such entry in the database"
+
+ec KRB5_KDB_ILL_WILDCARD,	"Illegal use of wildcard"
+
+ec KRB5_KDB_DB_INUSE,		"Database is locked or in use--try again later"
+
+ec KRB5_KDB_DB_CHANGED,		"Database was modified during read"
+
+ec KRB5_KDB_TRUNCATED_RECORD,	"Database record is incomplete or corrupted"
+ec KRB5_KDB_RECURSIVELOCK,	"Attempt to lock database twice"
+ec KRB5_KDB_NOTLOCKED,		"Attempt to unlock database when not locked"
+ec KRB5_KDB_BADLOCKMODE,	"Invalid kdb lock mode"
+ec KRB5_KDB_DBNOTINITED,	"Database has not been initialized"
+ec KRB5_KDB_DBINITED,		"Database has already been initialized"
+
+ec KRB5_KDB_ILLDIRECTION,	"Bad direction for converting keys"
+
+ec KRB5_KDB_NOMASTERKEY,	"Cannot find master key record in database"
+ec KRB5_KDB_BADMASTERKEY,	"Master key does not match database"
+ec KRB5_KDB_INVALIDKEYSIZE,	"Key size in database is invalid"
+ec KRB5_KDB_CANTREAD_STORED,	"Cannot find/read stored master key"
+ec KRB5_KDB_BADSTORED_MKEY,	"Stored master key is corrupted"
+
+ec KRB5_KDB_CANTLOCK_DB,	"Insufficient access to lock database"
+
+ec KRB5_KDB_DB_CORRUPT,		"Database format error"
+ec KRB5_KDB_BAD_VERSION,	"Unsupported version in database entry"
+
+ec KRB5_KDB_BAD_SALTTYPE,	"Unsupported salt type"
+ec KRB5_KDB_BAD_ENCTYPE,	"Unsupported encryption type"
+ec KRB5_KDB_BAD_CREATEFLAGS,	"Bad database creation flags"
+ec KRB5_KDB_NO_PERMITTED_KEY,	"No matching key in entry having a permitted enctype"
+ec KRB5_KDB_NO_MATCHING_KEY,	"No matching key in entry"
+end
diff --git a/mechglue/src/lib/krb5/error_tables/krb524_err.et b/mechglue/src/lib/krb5/error_tables/krb524_err.et
new file mode 100644
index 000000000..5a4a004c7
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/krb524_err.et
@@ -0,0 +1,34 @@
+# Copyright 1994 by OpenVision Technologies, Inc.
+# 
+# Permission to use, copy, modify, distribute, and sell this software
+# and its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appears in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of OpenVision not be used
+# in advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. OpenVision makes no
+# representations about the suitability of this software for any
+# purpose.  It is provided "as is" without express or implied warranty.
+# 
+# OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+# 
+
+error_table k524
+
+error_code KRB524_BADKEY, "Cannot convert V5 keyblock"
+error_code KRB524_BADADDR, "Cannot convert V5 address information"
+error_code KRB524_BADPRINC, "Cannot convert V5 principal"
+error_code KRB524_BADREALM, "V5 realm name longer than V4 maximum"
+error_code KRB524_V4ERR, "Kerberos V4 error"
+error_code KRB524_ENCFULL, "Encoding too large"
+error_code KRB524_DECEMPTY, "Decoding out of data"
+error_code KRB524_NOTRESP, "Service not responding"
+error_code KRB524_KRB4_DISABLED,	"Kerberos version 4 support is disabled"
+
+end
diff --git a/mechglue/src/lib/krb5/error_tables/krb5_err.et b/mechglue/src/lib/krb5/error_tables/krb5_err.et
new file mode 100644
index 000000000..1f2bfca53
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/krb5_err.et
@@ -0,0 +1,345 @@
+#
+# lib/krb5/error_tables/krb5_err.et
+#
+# Copyright 1989,1990,1991 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+#
+# The Kerberos v5 library error code table.
+# Protocol error codes are ERROR_TABLE_BASE_krb5 + the protocol error
+# code number; other error codes start at ERROR_TABLE_BASE_krb5 + 128.
+#
+error_table krb5
+
+
+#
+# Note: the first 128 error codes are hard-coded and must match the error
+# numbers defined in the Kerberos protocol specification, RFC-1510 or
+# its successors.
+#
+
+# vv 0
+error_code KRB5KDC_ERR_NONE,		"No error"
+error_code KRB5KDC_ERR_NAME_EXP,	"Client's entry in database has expired"
+error_code KRB5KDC_ERR_SERVICE_EXP,	"Server's entry in database has expired"
+error_code KRB5KDC_ERR_BAD_PVNO,	"Requested protocol version not supported"
+error_code KRB5KDC_ERR_C_OLD_MAST_KVNO,	"Client's key is encrypted in an old master key"
+error_code KRB5KDC_ERR_S_OLD_MAST_KVNO,	"Server's key is encrypted in an old master key"
+error_code KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN, "Client not found in Kerberos database"
+error_code KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, "Server not found in Kerberos database"
+error_code KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE, "Principal has multiple entries in Kerberos database"
+error_code KRB5KDC_ERR_NULL_KEY,	"Client or server has a null key"
+error_code KRB5KDC_ERR_CANNOT_POSTDATE,	"Ticket is ineligible for postdating"
+error_code KRB5KDC_ERR_NEVER_VALID,	"Requested effective lifetime is negative or too short"
+error_code KRB5KDC_ERR_POLICY,		"KDC policy rejects request"
+error_code KRB5KDC_ERR_BADOPTION,	"KDC can't fulfill requested option"
+error_code KRB5KDC_ERR_ETYPE_NOSUPP,	"KDC has no support for encryption type"
+error_code KRB5KDC_ERR_SUMTYPE_NOSUPP,	"KDC has no support for checksum type"
+error_code KRB5KDC_ERR_PADATA_TYPE_NOSUPP, "KDC has no support for padata type"
+error_code KRB5KDC_ERR_TRTYPE_NOSUPP,	"KDC has no support for transited type"
+error_code KRB5KDC_ERR_CLIENT_REVOKED,	"Clients credentials have been revoked"
+error_code KRB5KDC_ERR_SERVICE_REVOKED,	"Credentials for server have been revoked"
+error_code KRB5KDC_ERR_TGT_REVOKED,	"TGT has been revoked"
+error_code KRB5KDC_ERR_CLIENT_NOTYET,	"Client not yet valid - try again later"
+error_code KRB5KDC_ERR_SERVICE_NOTYET,	"Server not yet valid - try again later"
+error_code KRB5KDC_ERR_KEY_EXP,  	"Password has expired"
+error_code KRB5KDC_ERR_PREAUTH_FAILED,  "Preauthentication failed"
+# ^^ 24
+error_code KRB5KDC_ERR_PREAUTH_REQUIRED, "Additional pre-authentication required"
+error_code KRB5KDC_ERR_SERVER_NOMATCH,	"Requested server and ticket don't match"
+error_code KRB5PLACEHOLD_27,		"KRB5 error code 27"
+error_code KRB5PLACEHOLD_28,		"KRB5 error code 28"
+error_code KRB5PLACEHOLD_29,		"KRB5 error code 29"
+error_code KRB5PLACEHOLD_30,		"KRB5 error code 30"
+# vv 31
+error_code KRB5KRB_AP_ERR_BAD_INTEGRITY, "Decrypt integrity check failed"
+error_code KRB5KRB_AP_ERR_TKT_EXPIRED,	"Ticket expired"
+error_code KRB5KRB_AP_ERR_TKT_NYV,	"Ticket not yet valid"
+error_code KRB5KRB_AP_ERR_REPEAT,	"Request is a replay"
+error_code KRB5KRB_AP_ERR_NOT_US,	"The ticket isn't for us"
+error_code KRB5KRB_AP_ERR_BADMATCH,	"Ticket/authenticator don't match"
+error_code KRB5KRB_AP_ERR_SKEW,	"Clock skew too great"
+error_code KRB5KRB_AP_ERR_BADADDR,	"Incorrect net address"
+error_code KRB5KRB_AP_ERR_BADVERSION,	"Protocol version mismatch"
+error_code KRB5KRB_AP_ERR_MSG_TYPE,	"Invalid message type"
+error_code KRB5KRB_AP_ERR_MODIFIED,	"Message stream modified"
+error_code KRB5KRB_AP_ERR_BADORDER,	"Message out of order"
+error_code KRB5KRB_AP_ERR_ILL_CR_TKT, "Illegal cross-realm ticket"
+error_code KRB5KRB_AP_ERR_BADKEYVER,	"Key version is not available"
+error_code KRB5KRB_AP_ERR_NOKEY,	"Service key not available"
+error_code KRB5KRB_AP_ERR_MUT_FAIL,	"Mutual authentication failed"
+error_code KRB5KRB_AP_ERR_BADDIRECTION,	"Incorrect message direction"
+error_code KRB5KRB_AP_ERR_METHOD,	"Alternative authentication method required"
+error_code KRB5KRB_AP_ERR_BADSEQ,	"Incorrect sequence number in message"
+error_code KRB5KRB_AP_ERR_INAPP_CKSUM,	"Inappropriate type of checksum in message"
+#^^ 50
+error_code KRB5KRB_AP_PATH_NOT_ACCEPTED,	"Policy rejects transited path"
+error_code KRB5KRB_ERR_RESPONSE_TOO_BIG,	"Response too big for UDP, retry with TCP"
+error_code KRB5PLACEHOLD_53,	"KRB5 error code 53"
+error_code KRB5PLACEHOLD_54,	"KRB5 error code 54"
+error_code KRB5PLACEHOLD_55,	"KRB5 error code 55"
+error_code KRB5PLACEHOLD_56,	"KRB5 error code 56"
+error_code KRB5PLACEHOLD_57,	"KRB5 error code 57"
+error_code KRB5PLACEHOLD_58,	"KRB5 error code 58"
+error_code KRB5PLACEHOLD_59,	"KRB5 error code 59"
+error_code KRB5KRB_ERR_GENERIC,	"Generic error (see e-text)"
+error_code KRB5KRB_ERR_FIELD_TOOLONG,	"Field is too long for this implementation"
+error_code KRB5PLACEHOLD_62,	"KRB5 error code 62"
+error_code KRB5PLACEHOLD_63,	"KRB5 error code 63"
+error_code KRB5PLACEHOLD_64,	"KRB5 error code 64"
+error_code KRB5PLACEHOLD_65,	"KRB5 error code 65"
+error_code KRB5PLACEHOLD_66,	"KRB5 error code 66"
+error_code KRB5PLACEHOLD_67,	"KRB5 error code 67"
+error_code KRB5PLACEHOLD_68,	"KRB5 error code 68"
+error_code KRB5PLACEHOLD_69,	"KRB5 error code 69"
+error_code KRB5PLACEHOLD_70,	"KRB5 error code 70"
+error_code KRB5PLACEHOLD_71,	"KRB5 error code 71"
+error_code KRB5PLACEHOLD_72,	"KRB5 error code 72"
+error_code KRB5PLACEHOLD_73,	"KRB5 error code 73"
+error_code KRB5PLACEHOLD_74,	"KRB5 error code 74"
+error_code KRB5PLACEHOLD_75,	"KRB5 error code 75"
+error_code KRB5PLACEHOLD_76,	"KRB5 error code 76"
+error_code KRB5PLACEHOLD_77,	"KRB5 error code 77"
+error_code KRB5PLACEHOLD_78,	"KRB5 error code 78"
+error_code KRB5PLACEHOLD_79,	"KRB5 error code 79"
+error_code KRB5PLACEHOLD_80,	"KRB5 error code 80"
+error_code KRB5PLACEHOLD_81,	"KRB5 error code 81"
+error_code KRB5PLACEHOLD_82,	"KRB5 error code 82"
+error_code KRB5PLACEHOLD_83,	"KRB5 error code 83"
+error_code KRB5PLACEHOLD_84,	"KRB5 error code 84"
+error_code KRB5PLACEHOLD_85,	"KRB5 error code 85"
+error_code KRB5PLACEHOLD_86,	"KRB5 error code 86"
+error_code KRB5PLACEHOLD_87,	"KRB5 error code 87"
+error_code KRB5PLACEHOLD_88,	"KRB5 error code 88"
+error_code KRB5PLACEHOLD_89,	"KRB5 error code 89"
+error_code KRB5PLACEHOLD_90,	"KRB5 error code 90"
+error_code KRB5PLACEHOLD_91,	"KRB5 error code 91"
+error_code KRB5PLACEHOLD_92,	"KRB5 error code 92"
+error_code KRB5PLACEHOLD_93,	"KRB5 error code 93"
+error_code KRB5PLACEHOLD_94,	"KRB5 error code 94"
+error_code KRB5PLACEHOLD_95,	"KRB5 error code 95"
+error_code KRB5PLACEHOLD_96,	"KRB5 error code 96"
+error_code KRB5PLACEHOLD_97,	"KRB5 error code 97"
+error_code KRB5PLACEHOLD_98,	"KRB5 error code 98"
+error_code KRB5PLACEHOLD_99,	"KRB5 error code 99"
+error_code KRB5PLACEHOLD_100,	"KRB5 error code 100"
+error_code KRB5PLACEHOLD_101,	"KRB5 error code 101"
+error_code KRB5PLACEHOLD_102,	"KRB5 error code 102"
+error_code KRB5PLACEHOLD_103,	"KRB5 error code 103"
+error_code KRB5PLACEHOLD_104,	"KRB5 error code 104"
+error_code KRB5PLACEHOLD_105,	"KRB5 error code 105"
+error_code KRB5PLACEHOLD_106,	"KRB5 error code 106"
+error_code KRB5PLACEHOLD_107,	"KRB5 error code 107"
+error_code KRB5PLACEHOLD_108,	"KRB5 error code 108"
+error_code KRB5PLACEHOLD_109,	"KRB5 error code 109"
+error_code KRB5PLACEHOLD_110,	"KRB5 error code 110"
+error_code KRB5PLACEHOLD_111,	"KRB5 error code 111"
+error_code KRB5PLACEHOLD_112,	"KRB5 error code 112"
+error_code KRB5PLACEHOLD_113,	"KRB5 error code 113"
+error_code KRB5PLACEHOLD_114,	"KRB5 error code 114"
+error_code KRB5PLACEHOLD_115,	"KRB5 error code 115"
+error_code KRB5PLACEHOLD_116,	"KRB5 error code 116"
+error_code KRB5PLACEHOLD_117,	"KRB5 error code 117"
+error_code KRB5PLACEHOLD_118,	"KRB5 error code 118"
+error_code KRB5PLACEHOLD_119,	"KRB5 error code 119"
+error_code KRB5PLACEHOLD_120,	"KRB5 error code 120"
+error_code KRB5PLACEHOLD_121,	"KRB5 error code 121"
+error_code KRB5PLACEHOLD_122,	"KRB5 error code 122"
+error_code KRB5PLACEHOLD_123,	"KRB5 error code 123"
+error_code KRB5PLACEHOLD_124,	"KRB5 error code 124"
+error_code KRB5PLACEHOLD_125,	"KRB5 error code 125"
+error_code KRB5PLACEHOLD_126,	"KRB5 error code 126"
+error_code KRB5PLACEHOLD_127,	"KRB5 error code 127"
+
+error_code KRB5_ERR_RCSID,	"$Id$"
+
+error_code KRB5_LIBOS_BADLOCKFLAG,	"Invalid flag for file lock mode"
+error_code KRB5_LIBOS_CANTREADPWD,	"Cannot read password"
+error_code KRB5_LIBOS_BADPWDMATCH,	"Password mismatch"
+error_code KRB5_LIBOS_PWDINTR,		"Password read interrupted"
+
+error_code KRB5_PARSE_ILLCHAR,		"Illegal character in component name"
+error_code KRB5_PARSE_MALFORMED,	"Malformed representation of principal"
+
+error_code KRB5_CONFIG_CANTOPEN,	"Can't open/find Kerberos configuration file"
+error_code KRB5_CONFIG_BADFORMAT,	"Improper format of Kerberos configuration file"
+error_code KRB5_CONFIG_NOTENUFSPACE,	"Insufficient space to return complete information"
+
+error_code KRB5_BADMSGTYPE,		"Invalid message type specified for encoding"
+
+error_code KRB5_CC_BADNAME,		"Credential cache name malformed"
+error_code KRB5_CC_UNKNOWN_TYPE,	"Unknown credential cache type" 
+error_code KRB5_CC_NOTFOUND,		"Matching credential not found"
+error_code KRB5_CC_END,			"End of credential cache reached"
+
+error_code KRB5_NO_TKT_SUPPLIED,	"Request did not supply a ticket"
+
+error_code KRB5KRB_AP_WRONG_PRINC,		"Wrong principal in request"
+error_code KRB5KRB_AP_ERR_TKT_INVALID,	"Ticket has invalid flag set"
+
+error_code KRB5_PRINC_NOMATCH,		"Requested principal and ticket don't match"
+error_code KRB5_KDCREP_MODIFIED,	"KDC reply did not match expectations"
+error_code KRB5_KDCREP_SKEW,		"Clock skew too great in KDC reply"
+error_code KRB5_IN_TKT_REALM_MISMATCH,	"Client/server realm mismatch in initial ticket request"
+
+error_code KRB5_PROG_ETYPE_NOSUPP,	"Program lacks support for encryption type"
+error_code KRB5_PROG_KEYTYPE_NOSUPP,	"Program lacks support for key type"
+error_code KRB5_WRONG_ETYPE,		"Requested encryption type not used in message"
+error_code KRB5_PROG_SUMTYPE_NOSUPP,	"Program lacks support for checksum type"
+
+error_code KRB5_REALM_UNKNOWN,		"Cannot find KDC for requested realm"
+error_code KRB5_SERVICE_UNKNOWN,	"Kerberos service unknown"
+error_code KRB5_KDC_UNREACH,		"Cannot contact any KDC for requested realm"
+error_code KRB5_NO_LOCALNAME,		"No local name found for principal name"
+
+error_code KRB5_MUTUAL_FAILED,		"Mutual authentication failed"
+
+# some of these should be combined/supplanted by system codes
+
+error_code KRB5_RC_TYPE_EXISTS,		"Replay cache type is already registered"
+error_code KRB5_RC_MALLOC,		"No more memory to allocate (in replay cache code)"
+error_code KRB5_RC_TYPE_NOTFOUND,	"Replay cache type is unknown"
+error_code KRB5_RC_UNKNOWN,		"Generic unknown RC error"
+error_code KRB5_RC_REPLAY,		"Message is a replay"
+error_code KRB5_RC_IO,			"Replay I/O operation failed XXX"
+error_code KRB5_RC_NOIO,		"Replay cache type does not support non-volatile storage"
+error_code KRB5_RC_PARSE,		"Replay cache name parse/format error"
+
+error_code KRB5_RC_IO_EOF,		"End-of-file on replay cache I/O"
+error_code KRB5_RC_IO_MALLOC,		"No more memory to allocate (in replay cache I/O code)"
+error_code KRB5_RC_IO_PERM,		"Permission denied in replay cache code"
+error_code KRB5_RC_IO_IO,		"I/O error in replay cache i/o code"
+error_code KRB5_RC_IO_UNKNOWN,		"Generic unknown RC/IO error"
+error_code KRB5_RC_IO_SPACE,		"Insufficient system space to store replay information"
+
+error_code KRB5_TRANS_CANTOPEN,		"Can't open/find realm translation file"
+error_code KRB5_TRANS_BADFORMAT,	"Improper format of realm translation file"
+
+error_code KRB5_LNAME_CANTOPEN,		"Can't open/find lname translation database"
+error_code KRB5_LNAME_NOTRANS,		"No translation available for requested principal"
+error_code KRB5_LNAME_BADFORMAT,	"Improper format of translation database entry"
+
+error_code KRB5_CRYPTO_INTERNAL,	"Cryptosystem internal error"
+
+error_code KRB5_KT_BADNAME,		"Key table name malformed"
+error_code KRB5_KT_UNKNOWN_TYPE,	"Unknown Key table type" 
+error_code KRB5_KT_NOTFOUND,		"Key table entry not found"
+error_code KRB5_KT_END,			"End of key table reached"
+error_code KRB5_KT_NOWRITE,		"Cannot write to specified key table"
+error_code KRB5_KT_IOERR,		"Error writing to key table"
+
+error_code KRB5_NO_TKT_IN_RLM,		"Cannot find ticket for requested realm"
+error_code KRB5DES_BAD_KEYPAR,		"DES key has bad parity"
+error_code KRB5DES_WEAK_KEY,		"DES key is a weak key"
+
+error_code KRB5_BAD_ENCTYPE,		"Bad encryption type"
+error_code KRB5_BAD_KEYSIZE,		"Key size is incompatible with encryption type"
+error_code KRB5_BAD_MSIZE,		"Message size is incompatible with encryption type"
+
+error_code KRB5_CC_TYPE_EXISTS,		"Credentials cache type is already registered."
+error_code KRB5_KT_TYPE_EXISTS,		"Key table type is already registered."
+
+error_code KRB5_CC_IO,			"Credentials cache I/O operation failed XXX"
+error_code KRB5_FCC_PERM,		"Credentials cache permissions incorrect"
+error_code KRB5_FCC_NOFILE,		"No credentials cache found"
+error_code KRB5_FCC_INTERNAL,		"Internal credentials cache error"
+error_code KRB5_CC_WRITE,		"Error writing to credentials cache"
+error_code KRB5_CC_NOMEM,		"No more memory to allocate (in credentials cache code)"
+error_code KRB5_CC_FORMAT,		"Bad format in credentials cache"
+error_code KRB5_CC_NOT_KTYPE,		"No credentials found with supported encryption types"
+
+# errors for dual tgt library calls
+error_code KRB5_INVALID_FLAGS,		"Invalid KDC option combination (library internal error)"
+error_code KRB5_NO_2ND_TKT,		"Request missing second ticket"
+
+error_code KRB5_NOCREDS_SUPPLIED,	"No credentials supplied to library routine"
+
+# errors for sendauth (and recvauth)
+
+error_code KRB5_SENDAUTH_BADAUTHVERS,	"Bad sendauth version was sent"
+error_code KRB5_SENDAUTH_BADAPPLVERS,	"Bad application version was sent (via sendauth)"
+error_code KRB5_SENDAUTH_BADRESPONSE,	"Bad response (during sendauth exchange)"
+error_code KRB5_SENDAUTH_REJECTED,	"Server rejected authentication (during sendauth exchange)"
+
+# errors for preauthentication
+
+error_code KRB5_PREAUTH_BAD_TYPE,	"Unsupported preauthentication type"
+error_code KRB5_PREAUTH_NO_KEY,		"Required preauthentication key not supplied"
+error_code KRB5_PREAUTH_FAILED,		"Generic preauthentication failure"
+
+# version number errors
+
+error_code KRB5_RCACHE_BADVNO,	"Unsupported replay cache format version number"
+error_code KRB5_CCACHE_BADVNO,	"Unsupported credentials cache format version number"
+error_code KRB5_KEYTAB_BADVNO,	"Unsupported key table format version number"
+
+#
+#
+
+error_code KRB5_PROG_ATYPE_NOSUPP,	"Program lacks support for address type"
+error_code KRB5_RC_REQUIRED,	"Message replay detection requires rcache parameter"
+error_code KRB5_ERR_BAD_HOSTNAME,	"Hostname cannot be canonicalized"
+error_code KRB5_ERR_HOST_REALM_UNKNOWN,	"Cannot determine realm for host"
+error_code KRB5_SNAME_UNSUPP_NAMETYPE,	"Conversion to service principal undefined for name type"
+
+error_code KRB5KRB_AP_ERR_V4_REPLY, "Initial Ticket response appears to be Version 4 error"
+error_code KRB5_REALM_CANT_RESOLVE,	"Cannot resolve network address for KDC in requested realm"
+error_code KRB5_TKT_NOT_FORWARDABLE,	"Requesting ticket can't get forwardable tickets"
+error_code KRB5_FWD_BAD_PRINCIPAL, "Bad principal name while trying to forward credentials"
+
+error_code KRB5_GET_IN_TKT_LOOP,  "Looping detected inside krb5_get_in_tkt"
+error_code KRB5_CONFIG_NODEFREALM,	"Configuration file does not specify default realm"
+
+error_code KRB5_SAM_UNSUPPORTED,  "Bad SAM flags in obtain_sam_padata"
+error_code KRB5_SAM_INVALID_ETYPE,	"Invalid encryption type in SAM challenge"
+error_code KRB5_SAM_NO_CHECKSUM,	"Missing checksum in SAM challenge"
+error_code KRB5_SAM_BAD_CHECKSUM,	"Bad checksum in SAM challenge"
+error_code KRB5_KT_NAME_TOOLONG,	"Keytab name too long"
+error_code KRB5_KT_KVNONOTFOUND,	"Key version number for principal in key table is incorrect"
+error_code KRB5_APPL_EXPIRED,	"This application has expired"
+error_code KRB5_LIB_EXPIRED,	"This Krb5 library has expired"
+
+error_code KRB5_CHPW_PWDNULL,		"New password cannot be zero length"
+error_code KRB5_CHPW_FAIL,		"Password change failed"
+error_code KRB5_KT_FORMAT,		"Bad format in keytab"
+
+error_code KRB5_NOPERM_ETYPE,	"Encryption type not permitted"
+error_code KRB5_CONFIG_ETYPE_NOSUPP,	"No supported encryption types (config file error?)"
+error_code KRB5_OBSOLETE_FN,	"Program called an obsolete, deleted function"
+
+# translated versions of getaddrinfo errors
+error_code KRB5_EAI_FAIL,	"unknown getaddrinfo failure"
+error_code KRB5_EAI_NODATA,	"no data available for host/domain name"
+error_code KRB5_EAI_NONAME,	"host/domain name not found"
+error_code KRB5_EAI_SERVICE,	"service name unknown"
+
+error_code KRB5_ERR_NUMERIC_REALM, "Cannot determine realm for numeric host address"
+
+error_code KRB5_ERR_BAD_S2K_PARAMS, "Invalid key generation parameters from KDC"
+
+error_code KRB5_ERR_NO_SERVICE,	"service not available"
+
+error_code KRB5_CC_READONLY,    "Ccache function not supported: read-only ccache type"
+error_code KRB5_CC_NOSUPP,      "Ccache function not supported: not implemented"
+
+error_code KRB5_DELTAT_BADFORMAT,	"Invalid format of Kerberos lifetime or clock skew string"
+end
diff --git a/mechglue/src/lib/krb5/error_tables/kv5m_err.et b/mechglue/src/lib/krb5/error_tables/kv5m_err.et
new file mode 100644
index 000000000..1b79de252
--- /dev/null
+++ b/mechglue/src/lib/krb5/error_tables/kv5m_err.et
@@ -0,0 +1,90 @@
+#
+# src/lib/krb5/kv5m_err.et
+#
+# Copyright 1994 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+#
+# The Kerberos v5 magic numbers errorcode table
+
+error_table kv5m
+
+error_code KV5M_NONE,		"Kerberos V5 magic number table"
+error_code KV5M_PRINCIPAL,	"Bad magic number for krb5_principal structure"
+error_code KV5M_DATA,		"Bad magic number for krb5_data structure"
+error_code KV5M_KEYBLOCK,	"Bad magic number for krb5_keyblock structure"
+error_code KV5M_CHECKSUM,	"Bad magic number for krb5_checksum structure"
+error_code KV5M_ENCRYPT_BLOCK,	"Bad magic number for krb5_encrypt_block structure"
+error_code KV5M_ENC_DATA,	"Bad magic number for krb5_enc_data structure"
+error_code KV5M_CRYPTOSYSTEM_ENTRY,	"Bad magic number for krb5_cryptosystem_entry structure"
+error_code KV5M_CS_TABLE_ENTRY,	"Bad magic number for krb5_cs_table_entry structure"
+error_code KV5M_CHECKSUM_ENTRY,	"Bad magic number for krb5_checksum_entry structure"
+
+error_code KV5M_AUTHDATA,	"Bad magic number for krb5_authdata structure"
+error_code KV5M_TRANSITED,	"Bad magic number for krb5_transited structure"
+error_code KV5M_ENC_TKT_PART,	"Bad magic number for krb5_enc_tkt_part structure"
+error_code KV5M_TICKET,		"Bad magic number for krb5_ticket structure"
+error_code KV5M_AUTHENTICATOR,	"Bad magic number for krb5_authenticator structure"
+error_code KV5M_TKT_AUTHENT,	"Bad magic number for krb5_tkt_authent structure"
+error_code KV5M_CREDS,		"Bad magic number for krb5_creds structure"
+error_code KV5M_LAST_REQ_ENTRY,	"Bad magic number for krb5_last_req_entry structure"
+error_code KV5M_PA_DATA,		"Bad magic number for krb5_pa_data structure"
+error_code KV5M_KDC_REQ,		"Bad magic number for krb5_kdc_req structure"
+error_code KV5M_ENC_KDC_REP_PART, "Bad magic number for krb5_enc_kdc_rep_part structure"
+error_code KV5M_KDC_REP,		"Bad magic number for krb5_kdc_rep structure"
+error_code KV5M_ERROR,		"Bad magic number for krb5_error structure"
+error_code KV5M_AP_REQ,		"Bad magic number for krb5_ap_req structure"
+error_code KV5M_AP_REP,		"Bad magic number for krb5_ap_rep structure"
+error_code KV5M_AP_REP_ENC_PART,	"Bad magic number for krb5_ap_rep_enc_part structure"
+error_code KV5M_RESPONSE,	"Bad magic number for krb5_response structure"
+error_code KV5M_SAFE,		"Bad magic number for krb5_safe structure"
+error_code KV5M_PRIV,		"Bad magic number for krb5_priv structure"
+error_code KV5M_PRIV_ENC_PART,	"Bad magic number for krb5_priv_enc_part structure"
+error_code KV5M_CRED,		"Bad magic number for krb5_cred structure"
+error_code KV5M_CRED_INFO,	"Bad magic number for krb5_cred_info structure"
+error_code KV5M_CRED_ENC_PART,	"Bad magic number for krb5_cred_enc_part structure"
+error_code KV5M_PWD_DATA,	"Bad magic number for krb5_pwd_data structure"
+error_code KV5M_ADDRESS,	"Bad magic number for krb5_address structure"
+error_code KV5M_KEYTAB_ENTRY,	"Bad magic number for krb5_keytab_entry structure"
+error_code KV5M_CONTEXT,	"Bad magic number for krb5_context structure"
+error_code KV5M_OS_CONTEXT,	"Bad magic number for krb5_os_context structure"
+error_code KV5M_ALT_METHOD,	"Bad magic number for krb5_alt_method structure"
+error_code KV5M_ETYPE_INFO_ENTRY, "Bad magic number for krb5_etype_info_entry structure"
+error_code KV5M_DB_CONTEXT,	"Bad magic number for krb5_db_context structure"
+error_code KV5M_AUTH_CONTEXT,	"Bad magic number for krb5_auth_context structure"
+error_code KV5M_KEYTAB,		"Bad magic number for krb5_keytab structure"
+error_code KV5M_RCACHE,		"Bad magic number for krb5_rcache structure"
+error_code KV5M_CCACHE,		"Bad magic number for krb5_ccache structure"
+error_code KV5M_PREAUTH_OPS,	"Bad magic number for krb5_preauth_ops"
+error_code KV5M_SAM_CHALLENGE,	"Bad magic number for krb5_sam_challenge"
+error_code KV5M_SAM_CHALLENGE_2,	"Bad magic number for krb5_sam_challenge_2"
+error_code KV5M_SAM_KEY,	"Bad magic number for krb5_sam_key"
+error_code KV5M_ENC_SAM_RESPONSE_ENC,	"Bad magic number for krb5_enc_sam_response_enc"
+error_code KV5M_ENC_SAM_RESPONSE_ENC_2,	"Bad magic number for krb5_enc_sam_response_enc"
+error_code KV5M_SAM_RESPONSE,	"Bad magic number for krb5_sam_response"
+error_code KV5M_SAM_RESPONSE_2,	"Bad magic number for krb5_sam_response 2"
+error_code KV5M_PREDICTED_SAM_RESPONSE,	"Bad magic number for krb5_predicted_sam_response"
+error_code KV5M_PASSWD_PHRASE_ELEMENT,	"Bad magic number for passwd_phrase_element"
+error_code KV5M_GSS_OID,	"Bad magic number for GSSAPI OID"
+error_code KV5M_GSS_QUEUE,	"Bad magic number for GSSAPI QUEUE"
+
+end
diff --git a/mechglue/src/lib/krb5/keytab/.Sanitize b/mechglue/src/lib/krb5/keytab/.Sanitize
new file mode 100644
index 000000000..4f7dada30
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/.Sanitize
@@ -0,0 +1,45 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+db
+file
+srvtab
+ktadd.c
+ktbase.c
+ktdefault.c
+ktfr_entry.c
+ktremove.c
+read_servi.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/keytab/ChangeLog b/mechglue/src/lib/krb5/keytab/ChangeLog
new file mode 100644
index 000000000..943aad139
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/ChangeLog
@@ -0,0 +1,676 @@
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_file.c (NEED_SOCKETS): Don't define.
+	* kt_srvtab.c (NEED_SOCKETS): Don't define.
+
+2004-11-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_file.c (krb5_ktfile_wresolve): Initialize mutex here too.
+
+2004-11-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_file.c (struct _krb5_ktfile_data): Add mutex and buffer.
+	(KTFILEBUFP, KTLOCK, KTUNLOCK, KTCHECKLOCK): New macros.
+	(krb5_ktfile_resolve): Initialize mutex.
+	(krb5_ktfile_close): Zap data buffer before freeing.
+	(krb5_ktfile_get_entry, krb5_ktfile_start_seq_get,
+	krb5_ktfile_get_next, krb5_ktfile_end_get, krb5_ktfile_add,
+	krb5_ktfile_remove): Lock and unlock the mutex.
+	(krb5_ktfileint_open): Check that the mutex is locked.  Set the
+	stdio buffer to the new buffer in the ktfile data.
+	(krb5_ktfileint_write_entry, krb5_ktfileint_find_slot): Check that
+	the mutex is locked.  Don't call setbuf.  Flush the stdio buffer
+	after writing.
+
+2004-11-23  Tom Yu  <tlyu@mit.edu>
+
+	* kt_file.c (krb5_ktfileint_open): Update previous change by
+	explicitly setting errno=0 prior to calling fopen().  Also, return
+	EMFILE, not ENFILE, for compatibility with Solaris 8, which does
+	set errno when out of file descriptors.
+
+2004-11-19  Tom Yu  <tlyu@mit.edu>
+
+	* kt_file.c (krb5_ktfileint_open): Patch from Roland Dowdeswell to
+	return ENFILE when fopen() returns NULL but doesn't set errno.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_file.c (krb5_ktf_keytab_externalize,
+	krb5_ktf_keytab_internalize): Don't test macintosh.
+
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_file.c (krb5_kt_default_vno): Replaced variable with macro.
+
+2004-05-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* ktbase.c: Include kt-int.h
+
+	* kt-int.h: Create file with prototypes for krb5int_kt_initialize and 
+	krb5int_kt_finalize(void);
+
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktbase.c: Include ctype.h.
+	(k5_typehead_lock): Use new partial initializer.
+	(krb5int_kt_initialize): New function; finish mutex
+	initialization.
+	(krb5int_kt_finalize): New function; destroy the mutex and free
+	storage associated with registered types.
+
+2004-04-13  Jeffrey Altman <jaltman@mit.edu>
+
+    * ktbase.c:
+      Since we have to reserve all the single letter
+      prefixes make them apply to all platforms
+
+2004-04-13  Jeffrey Altman <jaltman@mit.edu>
+
+    * ktbase.c:  On Windows, improve the treat drive letter
+      prefix string as a FILE: keytab change to work if the
+      default keytab type was changed to not be of type FILE:
+
+2004-04-08  Jeffrey Altman <jaltman@mit.edu>
+
+    * ktbase.c:  Restore the thread safety fixes
+
+2004-04-08  Jeffrey Altman <jaltman@mit.edu>
+
+    * ktbase.c:  On Windows, if we see a colon do not assume it means
+      we found a prefix string unless the length of the prefix is 
+      not equal to one.  If it is one, it means we found a drive letter
+      and not a prefix.  
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktbase.c: Include k5-thread.h.
+	(k5_typehead_lock): New mutex variable.
+	(krb5_kt_register, krb5_kt_resolve): Lock it while accessing the
+	type list.
+	(krb5_kt_register): Ops table is now const.
+	(struct krb5_kt_typelist): "next" pointer now points to const.
+	(krb5_kt_typelist_wrfile, krb5_kt_typelist_file,
+	krb5_kt_typelist_srvtab): Now const.
+	(kt_typehead): Now points to const.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-05-22  Tom Yu  <tlyu@mit.edu>
+
+	* kt_file.c (krb5_ktfile_get_entry): Check principal name prior to
+	checking enctype.  Suggested by Wyllys Ingersoll.
+
+2003-05-19  Sam Hartman  <hartmans@mit.edu>
+
+	* ktbase.c: Register writable keytab by default
+
+2003-04-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kt_file.c (krb5_ktfileint_internal_read_entry): Use
+	krb5_princ_size instead of direct field access.
+	(krb5_ktfileint_write_entry, krb5_ktfileint_size_entry):
+	Likewise.
+
+2003-02-08  Tom Yu  <tlyu@mit.edu>
+
+	* kt_file.c (krb5_ktfile_get_entry): Fix comment; not going to
+	redesign key storage architecture for 1.3.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2002-10-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_file.c (krb5_ktf_ops, krb5_ktf_writable_ops): Now const.
+	Drop cast of serializer entry initializer.
+	(fopen_mode_rbplus, fopen_mode_rb): Now const.
+	* kt_srvtab.c (krb5_kts_ops): Now const.
+	* ktbase.c (krb5_ktf_ops, krb5_kts_ops): Update declarations.
+	(struct krb5_kt_typelist): Field ops now points to const.
+
+2002-09-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_file.c, kt_srvtab.c, ktadd.c, ktbase.c, ktdefault.c,
+	ktfr_entry.c, ktremove.c, read_servi.c: Use prototype style
+	function definitions.
+
+	* kt_file.c (errno), kt_srvtab.c (errno): Don't declare.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-18  Danilo Almeida  <dalmeida@mit.edu>
+
+	* ktfr_entry.c: Rename krb5_kt_free_entry_contents as
+	krb5_free_keytab_entry_contents to make it consistent with rest of
+	API.
+	[pullup from 1-2-2-branch]
+
+2002-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktfr_entry.c (krb5_kt_free_entry_contents): Rename from
+	krb5_kt_free_entry, keep old name as wrapper.
+	[pullup from 1-2-2-branch]
+
+2002-06-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_file.c: Undo non-logged part of last change that added
+	inclusion of netinet/in.h; k5-int.h should pull it in with
+	NEED_SOCKETS defined.
+
+2002-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* kt_srvtab.c: New file, combines all srvtab functions.  All
+	functions now static, only the ops table is exported.
+	* srvtab/*: All files deleted.
+	* kt_file.c: New file, combines all file/wrfile functions.
+	* file/*: All files deleted.
+	* Makefile.in (LOCAL_SUBDIRS, MAC_SUBDIRS): Deleted.
+	(STLIBOBJS, OBJS, SRCS): Added new files.
+	(all-windows): Skip subdirs target.
+	(subdirs, file\$(OUTPRE)file.lst, srvtab\$(OUTPRE)file.lst)[DOS]:
+	Deleted targets.
+	($(OBJFILE))[DOS]: Skip subdir stuff.
+	(clean-windows): Don't go into subdirs.
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* srvtab/kts_g_ent.c (krb5_ktsrvtab_get_entry): If a specific DES
+	enctype was requested, set the key's enctype to it, instead of
+	always returning des-cbc-crc.
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): For non-zero kvno,
+	match only low 8 bits.  For zero kvno, if any kvno in the keytab
+	is over 240, assume we're dealing with numbers 128
+	through (127+256) instead.  This allows for wrapping at 256 while
+	retaining a small set of consecutively numbered prior keys in the
+	keytab.
+
+2002-02-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktbase.c (krb5_kt_resolve): Use const instead of krb5_const.
+
+2001-11-19  Tom Yu  <tlyu@mit.edu>
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): Coerce enctype for now
+	to restore 1.0.x enctype similarity behavior.
+
+2001-10-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* ktfns.c (krb5_kt_get_type): KRB5_CALLCONV.
+
+2001-10-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktfns.c: New file.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Build it.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktbase.c: Make prototypes unconditional.
+	* srvtab/ktsrvtab.h: Make prototypes unconditional.
+	* file/ktfile.h, file/ser_ktf.c: Make prototypes unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* file/ser_ktf.c: Drop _MSDOS support.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktadd.c, ktbase.c, ktdefault.c, ktfr_entry.c, ktremove.c,
+	read_servi.c: Don't use KRB5_DLLIMP.  Don't explicitly declare
+	pointers FAR any more.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* ktbase.c (krb5_kt_resolve): Signed/unsigned int
+	cleanups. Maintain const char * attribute of incomming name.
+
+	* srvtab/kts_g_name.c, srvtab/ktsrvtab.h (krb5_ktsrvtab_get_name):
+	Uses unsigned int length now.
+
+	* file/ktf_util.c: Unsigned/signed int cleanups.
+
+	* file/ktf_g_name.c, file/ktfile.h (krb5_ktfile_get_name): Length
+	field now unsigned int.
+
+2000-09-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* file/ser_ktf.c (krb5_ktf_keytab_externalize): Do not violate
+	const char * declaration of ktfile_def_name.
+
+	* file/ktf_util.c (xfwrite): Cast length field to fwrite/fread as
+	unsigned.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* srvtab/kts_util.c (read_field): Cleanup unused variable.
+
+2000-03-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* ktbase.c (krb5_kt_resolve): Change prototype from const to
+	krb5_const to match krb5.hin
+
+Fri Jan 28 19:53:44 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* srvtab/kts_g_ent.c, srvtab/ktsrvtab.h (krb5_ktsrvtab_get_entry):
+	Change the third argument to krb5_const_principal (from
+	krb5_principal) to agree with krb5_kts_ops entries.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in, file/Makefile.in, srvtab/Makefile.in: Clean up
+	usage of CFLAGS, CPPFLAGS, DEFS, DEFINES, LOCAL_INCLUDES such that
+	one can override CFLAGS from the command line without losing CPP
+	search patchs and defines. Some associated Makefile cleanup.
+
+1999-06-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Fix windows build.
+
+	* srvtab/Makefile.in: Fix windows build.
+
+	* srvtab/ktsrvtab.h, srvtab/kts_resolv.c (krb5_ktsrvtab_resolve), 
+	srvtab/kts_g_name.c (krb5_ktsrvtab_get_name), 
+	srvtab/kts_close.c (krb5_ktsrvtab_close),
+	srvtab/kts_g_ent.c (krb5_ktsrvtab_get_entry), 
+	srvtab/kts_ssget.c (krb5_ktsrvtab_start_seq_get), 
+	srvtab/kts_next.c (krb5_ktsrvtab_get_next), 
+	srvtab/kts_endget.c (krb5_ktsrvtab_end_get): Fix calling
+	convention.
+
+1999-06-13  Geoffrey King  <gjking@mit.edu>
+
+	* Makefile.in: Add new subdirectory srvtab.
+
+	* srvtab: Initial checkin of ghudson's code to implement the
+	SRVTAB keytab type, which can read a krb4 srvtab.
+
+	* ktbase.c: Support FILE and SRVTAB types by default.  Use
+	krb5_ktf_ops instead of krb5_dfl_ops.
+	
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+Mon May 10 15:25:32 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in, file/Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, file/Makefile.in: Set the myfulldir and mydir
+	variables (which are relative to buildtop and thisconfigdir,
+	respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): restructure the code
+	to use the compare_enctypes function and not leak memory
+
+Fri Feb 27 18:03:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, file/Makefile.in: Changed thisconfigdir to point at
+	the lib/krb5 directory, since we've moved the configure.in tests
+	in this directory to the toplevel lib/krb5 configure.in
+
+Wed Feb 18 16:22:33 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in, file/Makefile.in: Remove trailing slash from
+	thisconfigdir.  Fix up BUILDTOP for new conventions.
+
+Thu Feb 12 16:18:05 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented out AC_OUTPUT to force autoreconf to
+	rebuild the configure script.
+
+Mon Feb  2 16:47:05 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, file/Makefile.in: Define BUILDTOP and thisconfigdir
+	in the Makefile
+
+	* configure.in: Create the makefiles for the file subdirectory
+		and move all of the configure.in tests from in the
+		subdirectory into this configure.in.
+	
+Tue Oct 28 10:53:10 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ktf_wreslv.c, ktf_resolv.c:Initialize version element of
+	        krb5_ktfile_data structure.
+
+Mon Sep 15 15:15:33 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* ktfile.h, ktf_g_ent.c (krb5_ktfile_get_entry): Incoming principal
+	        is krb5_const_principal.
+
+Sat Feb 22 22:27:53 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+	* Makefile.in: win32 build
+
+	* ktadd.c,ktbase.c,ktdefault.c,ktfr_entry.c,ktremove.c,read_servi.c:
+	DLL export the keytab dispatch functions
+
+	* file/Makefile.in: win32 build
+
+	* file/ktf_add.c, file/ktf_close.c, file/ktf_g_ent.c,
+	file/ktf_g_name.c, file/ktf_next.c, file/ktf_remove.c,
+	file/ktf_resolv.c, file/ktf_ssget.c, file/ktf_wreslv.c,
+	file/ktfile.h: Change the functions declarations to include FAR
+	pointers and KRB5_CALLCONV so that they can be utilized by a DLL.
+
+Thu Jan  2 17:11:59 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in, configure.in, file/Makefile.in, file/configure.in:
+	Update to new library build procedure.
+
+Tue Nov 19 17:06:59 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): return
+	KRB5_KT_KVNONOTFOUND when appropriate [krb5-libs/198]
+
+Wed Jul 24 17:10:11 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* file/ktf_g_name.c (krb5_ktfile_get_name): Use the error code
+ 		KRB5_KT_NAME_TOOLONG instead of ENAMETOOLONG, which isn't
+ 		portable.
+
+Fri Jul 12 21:16:50 1996  Marc Horowitz  <marc@mit.edu>
+
+	* file/ktf_g_name.c (krb5_ktfile_get_name): include the prefix in
+	the returned name.
+
+Wed Jun 12 01:09:01 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* file/ser_ktf.c: Add #ifdef _WIN32 in places where we had #ifdef
+	_MSDOS
+
+Thu Jun  6 00:04:38 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (all-windows): Don't pass $(LIBCMD) on the command
+		line.  It's set in the windows.in prologue for all Makefiles anyway.
+
+Thu May  9 03:05:51 1996  Richard Basch  <basch@lehman.com>
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): don't skip over keytab
+		entries with kvno=0.
+
+Tue Mar 19 22:28:43 1996  Richard Basch  <basch@lehman.com>
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): all des enctypes are
+	equivalent
+
+Wed Feb  7 00:23:18 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Thu Jan 25 15:52:34 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): Match against enctype.
+
+Fri Jan  5 04:50:41 1996  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* file/ser_ktf.c (krb5_ktf_keytab_internalize): Take care of gcc
+		warning under OSF/1.
+
+Wed Dec 13 07:09:30 1995  Chris Provenzano (proven@mit.edu)
+
+        * configure.in : Remove subdirectory db. 
+
+Tue Dec 12 01:26:30 1995  Chris Provenzano (proven@mit.edu)
+
+	* configure.in : Added subdirectory db.
+
+Fri Oct  6 22:04:28 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in, file/Makefile.in: Remove ##DOS!include of
+		config/windows.in. config/windows.in is now included by
+		wconfig.
+
+Mon Sep 25 16:57:28 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in, file/Makefile.in: Removed "foo:: foo-$(WHAT)" lines
+		from the Makefile. 
+
+Wed Sep 13 10:57:08 1995 Keith Vetter (keithv@fusion.com)
+
+	* file/ser_ktf.c: Added MSDOS to wherever MACINTOSH was used.
+
+Mon Sep 11 21:22:44 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* file/ser_ktf.c (krb5_ktf_keytab_externalize): On Macintosh,
+		keytab file is not left open
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * read_servi.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+	* file/ktf_g_ent.c, file/ktf_remove.c, file/ktf_util.c,
+		file/ktfile.h : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * file/ktf_util.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate
+
+Tue Aug 29 13:37:56 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* ktbase.c - Add routines to deal with externalizing krb5_keytab.  These
+		search the registered keytab types for a match and dispatch
+		via the serializer handle.
+	* file/Makefile.in, file/.Sanitize, file/ser_ktf.c - Add new module to support
+		serialization of [WR]FILE keytabs.
+	* file/ktf_{defops,ops,wops}.c - Add serializer entry.
+	* file/ktf_{resolv,wreslv}.c - Set magic number in successfully resolved
+		keytab.
+
+Wed Aug 16 02:45:19 1995  Chris Provenzano <proven@mit.edu>
+
+        * file/ktf_util.c: Pass fds to krb5_lock_file() and krb5_unlock_file()
+
+Tue Aug 15 01:34:57 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* file/ktf_util.c: return KRB5_KEYTAB_BADVNO instead of -1
+
+Fri Aug  4 21:48:41 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* read_servi.c (krb5_kt_read_service_key): add more parens to shut
+		up gcc -Wall
+
+	* ktdefault.c (krb5_kt_default): add more parens to shut up gcc
+		-Wall
+
+	* file/ktf_util.c: shut up gcc -Wall
+
+	* file/ktf_remove.c: more stuff to shut up gcc -Wall
+
+	* file/ktf_next.c: Add more parens to shut up gcc -Wall
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): Add more parens to shut up
+		gcc -Wall
+
+	* file/ktf_add.c (krb5_ktfile_add): Add parens to shut up gcc -Wall
+
+Wed Jun 28 12:05:34 1995    <tytso@rsx-11.mit.edu>
+
+	* file/ktf_g_ent.c (krb5_ktfile_get_entry): If the key version number
+		is specified, check to make sure that the entry has the
+		correct key version number.
+
+Fri Jun  9 19:33:33 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+	* file/configure.in: Remove standardized set of autoconf macros,
+		which are now handled by CONFIG_RULES.
+
+Fri May 26 20:20:18 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in, file/configure.in, file/Makefile.in:
+	Add support for building shared libraries.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.c, file/*.[ch]: removed unneeded INTERFACE from non-api
+	functions.
+
+Fri Mar 17 19:46:07 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Zap duplicate defn.
+	(all-mac, clean-mac):  Add.
+	* file/Makefile.in (LDFLAGS):  Zap duplicate.
+
+Wed Mar 15 20:23:17 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: cleaned up for the PC
+
+Tue Mar 7 21:40:18 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in, file/Makefile.in: changed library name for the PC.
+
+Tue Mar  7 19:53:56 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in, file/configure.in: take out ISODE_DEFS.
+
+Wed Mar 3 16:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed LIB to LIBCMD for the PC
+
+Thu Mar 2 11:50:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* file/ktf_util.c: Changed NEED_WINSOCK_H to NEED_SOCKETS
+
+Wed Mar 1 16:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* file/ktf_util.c: fixed up some 16 vs 32 bit conversions.
+
+Tue Feb 28 00:59:22 1995  John Gilmore  (gnu at toad.com)
+
+	* *.c, file/*.c:  Avoid <krb5/...> includes.
+
+Wed Feb 22 01:38:54 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work on the PC
+        * *.c: added windows INTERFACE keyword
+
+        * file/Makefile.in: made to work on the PC
+        * file/*.c, file/ktfile.h: added windows INTERFACE keyword
+	* file/ktf_util.c: removed include of <netinet/in.h>
+           cast some 32bit ints to size_t ints
+
+Fri Feb  3 01:53:44 1995  John Gilmore  <gnu@cygnus.com>
+
+	Rename files for DOS 8.3 uniqueness:
+	* file/ktf_get_en.c => ktf_g_ent.c
+	* file/ktf_get_na.c => ktf_g_name.c
+	* file/Makefile.in:  changed to match.
+
+Fri Jan 27 12:54:54 1995  Chris Provenzano (proven@mit.edu)
+
+	* file/ktf_get_en.c, file/ktfile.h (krb5_ktfile_get_entry())
+		Added krb5_keytype arg.
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+        * Removed all narrow types and references to wide.h and narrow.h
+	* file/ktf_util.c : Use a constant size for file data not subfield
+		size from krb5_keytab_entry
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+	* read_servi.c (krb5_kt_read_service_key) Add krb5_keytype arg.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    	* Added krb5_context to all krb5_routines
+
+Fri Nov 18 15:34:35 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* file/ktf_util.c (krb5_ktfileint_internal_read_entry): Add magic
+		numbers for keytab, principal, and keyblock.
+
+Wed Oct 26 14:41:31 1994    (tytso@rsx-11)
+
+	* file/ktf_get_en.c (krb5_ktfile_get_entry): If the requested kvno
+		is IGNORE_KVNO, fix the error return so that 0 (no error)
+		is returned instead of KTF_NOT_FOUND.
+
+Fri Oct 14 23:09:02 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add ISODE_DEFS rule.
+
+Thu Oct 13 17:26:12 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* file/configure.in: Add ISODE_DEFS
+
+Tue Oct  4 22:06:15 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* ktfr_entry.c (krb5_kt_free_entry): Only try to free
+		entry->key.contents if it is non-NULL.  If entry is NULL,
+		return.
+
+	* file/ktf_get_en.c (krb5_ktfile_get_entry): Fix to compare using
+		new_entry instead of cur_entry.  (Bug made in modification
+		on Sep 28th).  Don't free cur_entry twice on errors.
+
+        * file/ktfile.h
+	* file/ktf_wreslv.c (krb5_ktfile_wresolve):
+	* file/ktf_resolv.c (krb5_ktf_resolv): Resolv's first argument is now a
+		const char *.
+
+Fri Sep 30 21:56:02 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* file/ktf_ops.c (krb5_ktf_ops): 
+	  file/ktf_wops.c (krb5_ktf_writable_ops):
+	  file/ktf_defops.c (krb5_kt_dfl_ops): Add placeholder for magic number.
+
+Thu Sep 29 23:19:06 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* ktbase.c (krb5_kt_resolve_name): If the prefix "FILE:" is not
+		given, assume the default operations list (whcih is
+		krb5_kt_dfl_ops).
+
+Wed Sep 28 21:14:49 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* file/ktf_get_en.c (krb5_ktfile_get_entry): Modified to return the
+		most recent key (with the greatest kvno), instead of the
+		first.
+
+Thu Sep 22 21:51:53 1994  Theodore Y. Ts'o  (tytso@dcl)
+    
+    	* file/ktf_get_en.c (krb5_ktfile_get_entry):
+	* file/ktf_next.c (krb5_ktfile_get_next):
+	* file/ktf_remove.c (krb5_ktfile_remove):
+	* file/ktf_util.c (krb5_ktfileint_read_entry,
+		krb5_ktfileint_internal_read_entry):
+	* file/ktfile.h: Change the interface of krb5_ktfile_read_entry and
+		krb5_ktfile_internal_read_entry so that they don't
+		allocate memory for the top-level structure.  All of their
+		callers didn't need it and were freeing it anyway.
+
+	* file/ktf_remove.c (krb5_ktfile_remove): Fix memory leak caused by not
+		freeing the top-level structure.
+
+Wed Sep 14 21:56:15 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* file/ktf_util.c (krb5_ktfileint_delete_entry):  Fixed bug reported by
+		Bill Sommerfeld where a missing byte-swap on a
+		little-endian machine causes the delete operation fail.
+
diff --git a/mechglue/src/lib/krb5/keytab/Makefile.in b/mechglue/src/lib/krb5/keytab/Makefile.in
new file mode 100644
index 000000000..e685b0655
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/Makefile.in
@@ -0,0 +1,118 @@
+thisconfigdir=./..
+myfulldir=lib/krb5/keytab
+mydir=keytab
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=keytab
+##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
+
+STLIBOBJS= \
+	ktadd.o		\
+	ktbase.o	\
+	ktdefault.o	\
+	ktfr_entry.o	\
+	ktremove.o	\
+	ktfns.o		\
+	kt_file.o	\
+	kt_srvtab.o	\
+	read_servi.o
+
+OBJS=	\
+	$(OUTPRE)ktadd.$(OBJEXT)		\
+	$(OUTPRE)ktbase.$(OBJEXT)	\
+	$(OUTPRE)ktdefault.$(OBJEXT)	\
+	$(OUTPRE)ktfr_entry.$(OBJEXT)	\
+	$(OUTPRE)ktremove.$(OBJEXT)	\
+	$(OUTPRE)ktfns.$(OBJEXT)	\
+	$(OUTPRE)kt_file.$(OBJEXT)	\
+	$(OUTPRE)kt_srvtab.$(OBJEXT)	\
+	$(OUTPRE)read_servi.$(OBJEXT)
+
+SRCS=	\
+	$(srcdir)/ktadd.c	\
+	$(srcdir)/ktbase.c	\
+	$(srcdir)/ktdefault.c	\
+	$(srcdir)/ktfr_entry.c	\
+	$(srcdir)/ktremove.c	\
+	$(srcdir)/ktfns.c	\
+	$(srcdir)/kt_file.c	\
+	$(srcdir)/kt_srvtab.c	\
+	$(srcdir)/read_servi.c
+
+all-windows:: $(OBJFILE)
+
+##DOS$(OBJFILE): $(OBJS)
+##DOS	$(RM) $(OBJFILE)
+##WIN32##	$(LIBECHO) -p $(PREFIXDIR)\ $(OUTPRE)*.obj > $(OBJFILE)
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+
+clean-windows::
+	@echo Making clean in krb5\keytab
+	$(RM) $(OBJFILE)
+
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+ktadd.so ktadd.po $(OUTPRE)ktadd.$(OBJEXT): ktadd.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ktbase.so ktbase.po $(OUTPRE)ktbase.$(OBJEXT): ktbase.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  kt-int.h
+ktdefault.so ktdefault.po $(OUTPRE)ktdefault.$(OBJEXT): \
+  ktdefault.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ktfr_entry.so ktfr_entry.po $(OUTPRE)ktfr_entry.$(OBJEXT): \
+  ktfr_entry.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ktremove.so ktremove.po $(OUTPRE)ktremove.$(OBJEXT): \
+  ktremove.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ktfns.so ktfns.po $(OUTPRE)ktfns.$(OBJEXT): ktfns.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+kt_file.so kt_file.po $(OUTPRE)kt_file.$(OBJEXT): kt_file.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+kt_srvtab.so kt_srvtab.po $(OUTPRE)kt_srvtab.$(OBJEXT): \
+  kt_srvtab.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+read_servi.so read_servi.po $(OUTPRE)read_servi.$(OBJEXT): \
+  read_servi.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
diff --git a/mechglue/src/lib/krb5/keytab/kt-int.h b/mechglue/src/lib/krb5/keytab/kt-int.h
new file mode 100644
index 000000000..23bbc5505
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/kt-int.h
@@ -0,0 +1,39 @@
+/*
+ * lib/krb5/keytab/kt-int.h
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This file contains constant and function declarations used in the
+ * file-based credential cache routines.
+ */
+
+#ifndef __KRB5_KEYTAB_INT_H__
+#define __KRB5_KEYTAB_INT_H__
+
+
+int krb5int_kt_initialize(void);
+
+void krb5int_kt_finalize(void);
+
+#endif /* __KRB5_KEYTAB_INT_H__ */
diff --git a/mechglue/src/lib/krb5/keytab/kt_file.c b/mechglue/src/lib/krb5/keytab/kt_file.c
new file mode 100644
index 000000000..c53c2b644
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/kt_file.c
@@ -0,0 +1,1717 @@
+/*
+ * lib/krb5/keytab/kt_file.c
+ *
+ * Copyright 1990,1991,1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+
+/*
+ * Information needed by internal routines of the file-based ticket
+ * cache implementation.
+ */
+
+
+/*
+ * Constants
+ */
+#define IGNORE_VNO 0
+#define IGNORE_ENCTYPE 0
+
+#define KRB5_KT_VNO_1	0x0501	/* krb v5, keytab version 1 (DCE compat) */
+#define KRB5_KT_VNO	0x0502	/* krb v5, keytab version 2 (standard)  */
+
+#define KRB5_KT_DEFAULT_VNO KRB5_KT_VNO
+
+/* 
+ * Types
+ */
+typedef struct _krb5_ktfile_data {
+    char *name;			/* Name of the file */
+    FILE *openf;		/* open file, if any. */
+    char iobuf[BUFSIZ];		/* so we can zap it later */
+    int	version;		/* Version number of keytab */
+    k5_mutex_t lock;		/* Protect openf, version */
+} krb5_ktfile_data;
+
+/*
+ * Macros
+ */
+#define KTPRIVATE(id) ((krb5_ktfile_data *)(id)->data)
+#define KTFILENAME(id) (((krb5_ktfile_data *)(id)->data)->name)
+#define KTFILEP(id) (((krb5_ktfile_data *)(id)->data)->openf)
+#define KTFILEBUFP(id) (((krb5_ktfile_data *)(id)->data)->iobuf)
+#define KTVERSION(id) (((krb5_ktfile_data *)(id)->data)->version)
+#define KTLOCK(id) k5_mutex_lock(&((krb5_ktfile_data *)(id)->data)->lock)
+#define KTUNLOCK(id) k5_mutex_unlock(&((krb5_ktfile_data *)(id)->data)->lock)
+#define KTCHECKLOCK(id) k5_mutex_assert_locked(&((krb5_ktfile_data *)(id)->data)->lock)
+
+extern const struct _krb5_kt_ops krb5_ktf_ops;
+extern const struct _krb5_kt_ops krb5_ktf_writable_ops;
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_resolve 
+	(krb5_context,
+		   const char *,
+		   krb5_keytab *);
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_wresolve 
+	(krb5_context,
+		   const char *,
+		   krb5_keytab *);
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_get_name 
+	(krb5_context,
+		   krb5_keytab,
+		   char *,
+		   unsigned int);
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_close 
+	(krb5_context,
+		   krb5_keytab);
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_get_entry 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_const_principal,
+		   krb5_kvno,
+		   krb5_enctype,
+		   krb5_keytab_entry *);
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_start_seq_get 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_kt_cursor *);
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_get_next 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_keytab_entry *,
+		   krb5_kt_cursor *);
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_end_get 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_kt_cursor *);
+
+/* routines to be included on extended version (write routines) */
+krb5_error_code KRB5_CALLCONV krb5_ktfile_add 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_keytab_entry *);
+
+krb5_error_code KRB5_CALLCONV krb5_ktfile_remove 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_keytab_entry *);
+
+krb5_error_code krb5_ktfileint_openr 
+	(krb5_context,
+		   krb5_keytab);
+
+krb5_error_code krb5_ktfileint_openw 
+	(krb5_context,
+		   krb5_keytab);
+
+krb5_error_code krb5_ktfileint_close 
+	(krb5_context,
+		   krb5_keytab);
+
+krb5_error_code krb5_ktfileint_read_entry 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_keytab_entry *);
+
+krb5_error_code krb5_ktfileint_write_entry 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_keytab_entry *);
+
+krb5_error_code krb5_ktfileint_delete_entry 
+	(krb5_context,
+		   krb5_keytab,
+                   krb5_int32);
+
+krb5_error_code krb5_ktfileint_internal_read_entry 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_keytab_entry *,
+                   krb5_int32 *);
+
+krb5_error_code krb5_ktfileint_size_entry 
+	(krb5_context,
+		   krb5_keytab_entry *,
+                   krb5_int32 *);
+
+krb5_error_code krb5_ktfileint_find_slot 
+	(krb5_context,
+		   krb5_keytab,
+                   krb5_int32 *,
+                   krb5_int32 *);
+
+
+/*
+ * This is an implementation specific resolver.  It returns a keytab id 
+ * initialized with file keytab routines.
+ */
+
+krb5_error_code KRB5_CALLCONV 
+krb5_ktfile_resolve(krb5_context context, const char *name, krb5_keytab *id)
+{
+    krb5_ktfile_data *data;
+    krb5_error_code err;
+
+    if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
+	return(ENOMEM);
+    
+    (*id)->ops = &krb5_ktf_ops;
+    if ((data = (krb5_ktfile_data *)malloc(sizeof(krb5_ktfile_data))) == NULL) {
+	krb5_xfree(*id);
+	return(ENOMEM);
+    }
+
+    err = k5_mutex_init(&data->lock);
+    if (err) {
+	krb5_xfree(*id);
+	return err;
+    }
+
+    if ((data->name = (char *)calloc(strlen(name) + 1, sizeof(char))) == NULL) {
+	k5_mutex_destroy(&data->lock);
+	krb5_xfree(data);
+	krb5_xfree(*id);
+	return(ENOMEM);
+    }
+
+    (void) strcpy(data->name, name);
+    data->openf = 0;
+    data->version = 0;
+
+    (*id)->data = (krb5_pointer)data;
+    (*id)->magic = KV5M_KEYTAB;
+    return(0);
+}
+
+
+/*
+ * "Close" a file-based keytab and invalidate the id.  This means
+ * free memory hidden in the structures.
+ */
+
+krb5_error_code KRB5_CALLCONV 
+krb5_ktfile_close(krb5_context context, krb5_keytab id)
+  /*
+   * This routine is responsible for freeing all memory allocated 
+   * for this keytab.  There are no system resources that need
+   * to be freed nor are there any open files.
+   *
+   * This routine should undo anything done by krb5_ktfile_resolve().
+   */
+{
+    krb5_xfree(KTFILENAME(id));
+    zap(KTFILEBUFP(id), BUFSIZ);
+    k5_mutex_destroy(&((krb5_ktfile_data *)id->data)->lock);
+    krb5_xfree(id->data);
+    id->ops = 0;
+    krb5_xfree(id);
+    return (0);
+}
+
+/*
+ * This is the get_entry routine for the file based keytab implementation.
+ * It opens the keytab file, and either retrieves the entry or returns
+ * an error.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktfile_get_entry(krb5_context context, krb5_keytab id,
+		      krb5_const_principal principal, krb5_kvno kvno,
+		      krb5_enctype enctype, krb5_keytab_entry *entry)
+{
+    krb5_keytab_entry cur_entry, new_entry;
+    krb5_error_code kerror = 0;
+    int found_wrong_kvno = 0;
+    krb5_boolean similar;
+    int kvno_offset = 0;
+
+    kerror = KTLOCK(id);
+    if (kerror)
+	return kerror;
+
+    /* Open the keyfile for reading */
+    if ((kerror = krb5_ktfileint_openr(context, id))) {
+	KTUNLOCK(id);
+	return(kerror);
+    }
+    
+    /* 
+     * For efficiency and simplicity, we'll use a while true that 
+     * is exited with a break statement.
+     */
+    cur_entry.principal = 0;
+    cur_entry.vno = 0;
+    cur_entry.key.contents = 0;
+
+    while (TRUE) {
+	if ((kerror = krb5_ktfileint_read_entry(context, id, &new_entry)))
+	    break;
+
+	/* by the time this loop exits, it must either free cur_entry,
+	   and copy new_entry there, or free new_entry.  Otherwise, it
+	   leaks. */
+
+	/* if the principal isn't the one requested, free new_entry
+	   and continue to the next. */
+
+	if (!krb5_principal_compare(context, principal, new_entry.principal)) {
+	    krb5_kt_free_entry(context, &new_entry);
+	    continue;
+	}
+
+	/* if the enctype is not ignored and doesn't match, free new_entry
+	   and continue to the next */
+
+	if (enctype != IGNORE_ENCTYPE) {
+	    if ((kerror = krb5_c_enctype_compare(context, enctype, 
+						 new_entry.key.enctype,
+						 &similar))) {
+		krb5_kt_free_entry(context, &new_entry);
+		break;
+	    }
+
+	    if (!similar) {
+		krb5_kt_free_entry(context, &new_entry);
+		continue;
+	    }
+	    /*
+	     * Coerce the enctype of the output keyblock in case we
+	     * got an inexact match on the enctype.
+	     */
+	    new_entry.key.enctype = enctype;
+
+	}
+
+	if (kvno == IGNORE_VNO) {
+	    /* if this is the first match, or if the new vno is
+	       bigger, free the current and keep the new.  Otherwise,
+	       free the new. */
+	    /* A 1.2.x keytab contains only the low 8 bits of the key
+	       version number.  Since it can be much bigger, and thus
+	       the 8-bit value can wrap, we need some heuristics to
+	       figure out the "highest" numbered key if some numbers
+	       close to 255 and some near 0 are used.
+
+	       The heuristic here:
+
+	       If we have any keys with versions over 240, then assume
+	       that all version numbers 0-127 refer to 256+N instead.
+	       Not perfect, but maybe good enough?  */
+
+#define M(VNO) (((VNO) - kvno_offset + 256) % 256)
+
+	    if (new_entry.vno > 240)
+		kvno_offset = 128;
+	    if (! cur_entry.principal ||
+		M(new_entry.vno) > M(cur_entry.vno)) {
+		krb5_kt_free_entry(context, &cur_entry);
+		cur_entry = new_entry;
+	    } else {
+		krb5_kt_free_entry(context, &new_entry);
+	    }
+	} else {
+	    /* if this kvno matches, free the current (will there ever
+	       be one?), keep the new, and break out.  Otherwise, remember
+	       that we were here so we can return the right error, and
+	       free the new */
+	    /* Yuck.  The krb5-1.2.x keytab format only stores one byte
+	       for the kvno, so we're toast if the kvno requested is
+	       higher than that.  Short-term workaround: only compare
+	       the low 8 bits.  */
+
+	    if (new_entry.vno == (kvno & 0xff)) {
+		krb5_kt_free_entry(context, &cur_entry);
+		cur_entry = new_entry;
+		break;
+	    } else {
+		found_wrong_kvno++;
+		krb5_kt_free_entry(context, &new_entry);
+	    }
+	}
+    }
+
+    if (kerror == KRB5_KT_END) {
+	 if (cur_entry.principal)
+	      kerror = 0;
+	 else if (found_wrong_kvno)
+	      kerror = KRB5_KT_KVNONOTFOUND;
+	 else
+	      kerror = KRB5_KT_NOTFOUND;
+    }
+    if (kerror) {
+	(void) krb5_ktfileint_close(context, id);
+	KTUNLOCK(id);
+	krb5_kt_free_entry(context, &cur_entry);
+	return kerror;
+    }
+    if ((kerror = krb5_ktfileint_close(context, id)) != 0) {
+	KTUNLOCK(id);
+	krb5_kt_free_entry(context, &cur_entry);
+	return kerror;
+    }
+    KTUNLOCK(id);
+    *entry = cur_entry;
+    return 0;
+}
+
+/*
+ * Get the name of the file containing a file-based keytab.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktfile_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len)
+  /* 
+   * This routine returns the name of the name of the file associated with
+   * this file-based keytab.  name is zeroed and the filename is truncated
+   * to fit in name if necessary.  The name is prefixed with PREFIX:, so that
+   * trt will happen if the name is passed back to resolve.
+   */
+{
+    memset(name, 0, len);
+
+    if (len < strlen(id->ops->prefix)+2)
+	return(KRB5_KT_NAME_TOOLONG);
+    strcpy(name, id->ops->prefix);
+    name += strlen(id->ops->prefix);
+    name[0] = ':';
+    name++;
+    len -= strlen(id->ops->prefix)+1;
+
+    if (len < strlen(KTFILENAME(id)+1))
+	return(KRB5_KT_NAME_TOOLONG);
+    strcpy(name, KTFILENAME(id));
+    /* strcpy will NUL-terminate the destination */
+
+    return(0);
+}
+
+/*
+ * krb5_ktfile_start_seq_get()
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktfile_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp)
+{
+    krb5_error_code retval;
+    long *fileoff;
+
+    retval = KTLOCK(id);
+    if (retval)
+	return retval;
+
+    if ((retval = krb5_ktfileint_openr(context, id))) {
+	KTUNLOCK(id);
+	return retval;
+    }
+
+    if (!(fileoff = (long *)malloc(sizeof(*fileoff)))) {
+	krb5_ktfileint_close(context, id);
+	KTUNLOCK(id);
+	return ENOMEM;
+    }
+    *fileoff = ftell(KTFILEP(id));
+    *cursorp = (krb5_kt_cursor)fileoff;
+    KTUNLOCK(id);
+
+    return 0;
+}
+
+/*
+ * krb5_ktfile_get_next()
+ */
+
+krb5_error_code KRB5_CALLCONV 
+krb5_ktfile_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor)
+{
+    long *fileoff = (long *)*cursor;
+    krb5_keytab_entry cur_entry;
+    krb5_error_code kerror;
+
+    kerror = KTLOCK(id);
+    if (kerror)
+	return kerror;
+    if (fseek(KTFILEP(id), *fileoff, 0) == -1) {
+	KTUNLOCK(id);
+	return KRB5_KT_END;
+    }
+    if ((kerror = krb5_ktfileint_read_entry(context, id, &cur_entry))) {
+	KTUNLOCK(id);
+	return kerror;
+    }
+    *fileoff = ftell(KTFILEP(id));
+    *entry = cur_entry;
+    KTUNLOCK(id);
+    return 0;
+}
+
+/*
+ * krb5_ktfile_end_get()
+ */
+
+krb5_error_code KRB5_CALLCONV 
+krb5_ktfile_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor)
+{
+    krb5_error_code kerror;
+
+    krb5_xfree(*cursor);
+    KTLOCK(id);
+    kerror = krb5_ktfileint_close(context, id);
+    KTUNLOCK(id);
+    return kerror;
+}
+
+/*
+ * ser_ktf.c - Serialize keytab file context for subsequent reopen.
+ */
+
+static const char ktfile_def_name[] = ".";
+
+/*
+ * Routines to deal with externalizing krb5_keytab for [WR]FILE: variants.
+ *	krb5_ktf_keytab_size();
+ *	krb5_ktf_keytab_externalize();
+ *	krb5_ktf_keytab_internalize();
+ */
+static krb5_error_code krb5_ktf_keytab_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_ktf_keytab_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_ktf_keytab_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/*
+ * Serialization entry for this type.
+ */
+const krb5_ser_entry krb5_ktfile_ser_entry = {
+    KV5M_KEYTAB,			/* Type			*/
+    krb5_ktf_keytab_size,		/* Sizer routine	*/
+    krb5_ktf_keytab_externalize,	/* Externalize routine	*/
+    krb5_ktf_keytab_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_ktf_keytab_size()	- Determine the size required to externalize
+ *				  this krb5_keytab variant.
+ */
+static krb5_error_code
+krb5_ktf_keytab_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_keytab		keytab;
+    size_t		required;
+    krb5_ktfile_data	*ktdata;
+
+    kret = EINVAL;
+    if ((keytab = (krb5_keytab) arg)) {
+	/*
+	 * Saving FILE: variants of krb5_keytab requires at minimum:
+	 *	krb5_int32	for KV5M_KEYTAB
+	 *	krb5_int32	for length of keytab name.
+	 *	krb5_int32	for file status.
+	 *	krb5_int32	for file position.
+	 *	krb5_int32	for file position.
+	 *	krb5_int32	for version.
+	 *	krb5_int32	for KV5M_KEYTAB
+	 */
+	required = sizeof(krb5_int32) * 7;
+	if (keytab->ops && keytab->ops->prefix)
+	    required += (strlen(keytab->ops->prefix)+1);
+
+	/*
+	 * The keytab name is formed as follows:
+	 *	<prefix>:<name>
+	 * If there's no name, we use a default name so that we have something
+	 * to call krb5_keytab_resolve with.
+	 */
+	ktdata = (krb5_ktfile_data *) keytab->data;
+	required += strlen((ktdata && ktdata->name) ?
+			   ktdata->name : ktfile_def_name);
+	kret = 0;
+
+	if (!kret)
+	    *sizep += required;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_ktf_keytab_externalize()	- Externalize the krb5_keytab.
+ */
+static krb5_error_code
+krb5_ktf_keytab_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_keytab		keytab;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+    krb5_ktfile_data	*ktdata;
+    krb5_int32		file_is_open;
+    krb5_int32		file_pos[2];
+    char		*ktname;
+    size_t		namelen;
+    const char		*fnamep;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((keytab = (krb5_keytab) arg)) {
+	kret = ENOMEM;
+	if (!krb5_ktf_keytab_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KV5M_KEYTAB, &bp, &remain);
+
+	    ktdata = (krb5_ktfile_data *) keytab->data;
+	    file_is_open = 0;
+	    file_pos[0] = 0;
+	    file_pos[1] = 0;
+
+	    /* Calculate the length of the name */
+	    namelen = (keytab->ops && keytab->ops->prefix) ?
+		strlen(keytab->ops->prefix)+1 : 0;
+	    if (ktdata && ktdata->name)
+		fnamep = ktdata->name;
+	    else
+		fnamep = ktfile_def_name;
+	    namelen += (strlen(fnamep)+1);
+
+	    if ((ktname = (char *) malloc(namelen))) {
+		/* Format the keytab name. */
+		if (keytab->ops && keytab->ops->prefix)
+		    sprintf(ktname, "%s:%s", keytab->ops->prefix, fnamep);
+
+		else
+		    strcpy(ktname, fnamep);
+
+		/* Fill in the file-specific keytab information. */
+		if (ktdata) {
+		    if (ktdata->openf) {
+			long	fpos;
+			int	fflags = 0;
+
+			file_is_open = 1;
+#if !defined(_WIN32)
+			fflags = fcntl(fileno(ktdata->openf), F_GETFL, 0);
+			if (fflags > 0)
+			    file_is_open |= ((fflags & O_ACCMODE) << 1);
+#else
+			file_is_open = 0;
+#endif
+			fpos = ftell(ktdata->openf);
+#if	SIZEOF_LONG == 4
+			file_pos[0] = fpos;
+#else	/* SIZEOF_LONG == 4 */
+			file_pos[0] = fpos & 0xffffffff;
+			file_pos[1] = (fpos >> 32) & 0xffffffff;
+#endif	/* SIZEOF_LONG == 4 */
+		    }
+		}
+
+		/* Put the length of the file name */
+		(void) krb5_ser_pack_int32((krb5_int32) strlen(ktname),
+					   &bp, &remain);
+		
+		/* Put the name */
+		(void) krb5_ser_pack_bytes((krb5_octet *) ktname,
+					   strlen(ktname),
+					   &bp, &remain);
+
+		/* Put the file open flag */
+		(void) krb5_ser_pack_int32(file_is_open, &bp, &remain);
+
+		/* Put the file position */
+		(void) krb5_ser_pack_int32(file_pos[0], &bp, &remain);
+		(void) krb5_ser_pack_int32(file_pos[1], &bp, &remain);
+
+		/* Put the version */
+		(void) krb5_ser_pack_int32((krb5_int32) ((ktdata) ?
+							 ktdata->version : 0),
+					   &bp, &remain);
+
+		/* Put the trailer */
+		(void) krb5_ser_pack_int32(KV5M_KEYTAB, &bp, &remain);
+		kret = 0;
+		*buffer = bp;
+		*lenremain = remain;
+		free(ktname);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_ktf_keytab_internalize()	- Internalize the krb5_ktf_keytab.
+ */
+static krb5_error_code
+krb5_ktf_keytab_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_keytab		keytab;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    char		*ktname;
+    krb5_ktfile_data	*ktdata;
+    krb5_int32		file_is_open;
+    krb5_int32		foffbuf[2];
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_KEYTAB) {
+	kret = ENOMEM;
+
+	/* Get the length of the keytab name */
+	kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+
+	if (!kret &&
+	    (ktname = (char *) malloc((size_t) (ibuf+1))) &&
+	    !(kret = krb5_ser_unpack_bytes((krb5_octet *) ktname,
+					   (size_t) ibuf,
+					   &bp, &remain))) {
+	    ktname[ibuf] = '\0';
+	    kret = krb5_kt_resolve(kcontext, ktname, &keytab);
+	    if (!kret) {
+		kret = ENOMEM;
+		ktdata = (krb5_ktfile_data *) keytab->data;
+		if (!ktdata) {
+		    /* XXX */
+		    keytab->data = (void *) malloc(sizeof(krb5_ktfile_data));
+		    ktdata = (krb5_ktfile_data *) keytab->data;
+		    memset(ktdata, 0, sizeof(krb5_ktfile_data));
+		    if (strchr(ktname, (int) ':'))
+			ktdata->name = strdup(strchr(ktname, (int) ':')+1);
+		    else
+			ktdata->name = strdup(ktname);
+		}
+		if (ktdata) {
+		    if (remain >= (sizeof(krb5_int32)*5)) {
+			(void) krb5_ser_unpack_int32(&file_is_open,
+						     &bp, &remain);
+			(void) krb5_ser_unpack_int32(&foffbuf[0],
+						     &bp, &remain);
+			(void) krb5_ser_unpack_int32(&foffbuf[1],
+						     &bp, &remain);
+			(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+			ktdata->version = (int) ibuf;
+
+			(void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+			if (ibuf == KV5M_KEYTAB) {
+			    if (file_is_open) {
+				int 	fmode;
+				long	fpos;
+
+#if !defined(_WIN32)
+				fmode = (file_is_open >> 1) & O_ACCMODE;
+#else
+				fmode = 0;
+#endif
+				if (fmode)
+				    kret = krb5_ktfileint_openw(kcontext,
+								keytab);
+				else
+				    kret = krb5_ktfileint_openr(kcontext,
+								keytab);
+				if (!kret) {
+#if	SIZEOF_LONG == 4
+				    fpos = foffbuf[0];
+#else	/* SIZEOF_LONG == 4 */
+				    fpos = foffbuf[0] | ((long) foffbuf[1] << 32);
+#endif	/* SIZEOF_LONG == 4 */
+				    fseek(KTFILEP(keytab), fpos, SEEK_SET);
+				}
+			    }
+			    kret = 0;
+			}
+			else
+			    kret = EINVAL;
+		    }
+		}
+		if (kret) {
+		    if (keytab->data) {
+			if (KTFILENAME(keytab))
+			    krb5_xfree(KTFILENAME(keytab));
+			krb5_xfree(keytab->data);
+		    }
+		    krb5_xfree(keytab);
+		}
+		else {
+		    *buffer = bp;
+		    *lenremain = remain;
+		    *argp = (krb5_pointer) keytab;
+		}
+	    }
+	    free(ktname);
+	}
+    }
+    return(kret);
+}
+
+/*
+ * This is an implementation specific resolver.  It returns a keytab id 
+ * initialized with file keytab routines.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktfile_wresolve(krb5_context context, const char *name, krb5_keytab *id)
+{
+    krb5_ktfile_data *data;
+    krb5_error_code err;
+
+    if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
+	return(ENOMEM);
+    
+    (*id)->ops = &krb5_ktf_writable_ops;
+    if ((data = (krb5_ktfile_data *)malloc(sizeof(krb5_ktfile_data))) == NULL) {
+	krb5_xfree(*id);
+	return(ENOMEM);
+    }
+
+    err = k5_mutex_init(&data->lock);
+    if (err) {
+	krb5_xfree(*id);
+	return err;
+    }
+
+    if ((data->name = (char *)calloc(strlen(name) + 1, sizeof(char))) == NULL) {
+	k5_mutex_destroy(&data->lock);
+	krb5_xfree(data);
+	krb5_xfree(*id);
+	return(ENOMEM);
+    }
+
+    (void) strcpy(data->name, name);
+    data->openf = 0;
+    data->version = 0;
+
+    (*id)->data = (krb5_pointer)data;
+    (*id)->magic = KV5M_KEYTAB;
+    return(0);
+}
+
+
+/*
+ * krb5_ktfile_add()
+ */
+
+krb5_error_code KRB5_CALLCONV 
+krb5_ktfile_add(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
+{
+    krb5_error_code retval;
+
+    retval = KTLOCK(id);
+    if (retval)
+	return retval;
+    if ((retval = krb5_ktfileint_openw(context, id))) {
+	KTUNLOCK(id);
+	return retval;
+    }
+    if (fseek(KTFILEP(id), 0, 2) == -1) {
+	KTUNLOCK(id);
+	return KRB5_KT_END;
+    }
+    retval = krb5_ktfileint_write_entry(context, id, entry);
+    krb5_ktfileint_close(context, id);
+    KTUNLOCK(id);
+    return retval;
+}
+
+/*
+ * krb5_ktfile_remove()
+ */
+
+krb5_error_code KRB5_CALLCONV 
+krb5_ktfile_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
+{
+    krb5_keytab_entry   cur_entry;
+    krb5_error_code     kerror;
+    krb5_int32          delete_point;
+
+    kerror = KTLOCK(id);
+    if (kerror)
+	return kerror;
+
+    if ((kerror = krb5_ktfileint_openw(context, id))) {
+	KTUNLOCK(id);
+	return kerror;
+    }
+
+    /* 
+     * For efficiency and simplicity, we'll use a while true that 
+     * is exited with a break statement.
+     */
+    while (TRUE) {
+	if ((kerror = krb5_ktfileint_internal_read_entry(context, id,
+							 &cur_entry,
+							 &delete_point)))
+  	    break;
+
+	if ((entry->vno == cur_entry.vno) &&
+            (entry->key.enctype == cur_entry.key.enctype) &&
+	    krb5_principal_compare(context, entry->principal, cur_entry.principal)) {
+	    /* found a match */
+            krb5_kt_free_entry(context, &cur_entry);
+	    break;
+	}
+	krb5_kt_free_entry(context, &cur_entry);
+    }
+
+    if (kerror == KRB5_KT_END)
+	kerror = KRB5_KT_NOTFOUND;
+
+    if (kerror) {
+	(void) krb5_ktfileint_close(context, id);
+	KTUNLOCK(id);
+	return kerror;
+    }
+
+    kerror = krb5_ktfileint_delete_entry(context, id, delete_point);
+
+    if (kerror) {
+	(void) krb5_ktfileint_close(context, id);
+    } else {
+        kerror = krb5_ktfileint_close(context, id);
+    }
+    KTUNLOCK(id);
+    return kerror;
+}
+
+/*
+ * krb5_ktf_ops
+ */
+
+const struct _krb5_kt_ops krb5_ktf_ops = {
+    0,
+    "FILE", 	/* Prefix -- this string should not appear anywhere else! */
+    krb5_ktfile_resolve,
+    krb5_ktfile_get_name, 
+    krb5_ktfile_close,
+    krb5_ktfile_get_entry,
+    krb5_ktfile_start_seq_get,
+    krb5_ktfile_get_next,
+    krb5_ktfile_end_get,
+    0,
+    0,
+    &krb5_ktfile_ser_entry
+};
+
+/*
+ * krb5_ktf_writable_ops
+ */
+
+const struct _krb5_kt_ops krb5_ktf_writable_ops = {
+    0,
+    "WRFILE", 	/* Prefix -- this string should not appear anywhere else! */
+    krb5_ktfile_wresolve,
+    krb5_ktfile_get_name, 
+    krb5_ktfile_close,
+    krb5_ktfile_get_entry,
+    krb5_ktfile_start_seq_get,
+    krb5_ktfile_get_next,
+    krb5_ktfile_end_get,
+    krb5_ktfile_add,
+    krb5_ktfile_remove,
+    &krb5_ktfile_ser_entry
+};
+
+/*
+ * krb5_kt_dfl_ops
+ */
+
+const krb5_kt_ops krb5_kt_dfl_ops = {
+    0,
+    "FILE", 	/* Prefix -- this string should not appear anywhere else! */
+    krb5_ktfile_resolve,
+    krb5_ktfile_get_name, 
+    krb5_ktfile_close,
+    krb5_ktfile_get_entry,
+    krb5_ktfile_start_seq_get,
+    krb5_ktfile_get_next,
+    krb5_ktfile_end_get,
+    0,
+    0,
+    &krb5_ktfile_ser_entry
+};
+
+/*
+ * lib/krb5/keytab/file/ktf_util.c
+ *
+ * Copyright (c) Hewlett-Packard Company 1991
+ * Released to the Massachusetts Institute of Technology for inclusion
+ * in the Kerberos source code distribution.
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This function contains utilities for the file based implementation of 
+ * the keytab.  There are no public functions in this file.
+ *
+ * This file is the only one that has knowledge of the format of a
+ * keytab file.
+ *
+ * The format is as follows:
+ * 
+ * <file format vno>
+ * <record length>
+ * principal timestamp vno key
+ * <record length>
+ * principal timestamp vno key
+ * ....
+ *
+ * A length field (sizeof(krb5_int32)) exists between entries.  When this
+ * length is positive it indicates an active entry, when negative a hole.
+ * The length indicates the size of the block in the file (this may be 
+ * larger than the size of the next record, since we are using a first
+ * fit algorithm for re-using holes and the first fit may be larger than
+ * the entry we are writing).  Another (compatible) implementation could
+ * break up holes when allocating them to smaller entries to minimize 
+ * wasted space.  (Such an implementation should also coalesce adjacent
+ * holes to reduce fragmentation).  This implementation does neither.
+ *
+ * There are no separators between fields of an entry.  
+ * A principal is a length-encoded array of length-encoded strings.  The
+ * length is a krb5_int16 in each case.  The specific format, then, is 
+ * multiple entries concatinated with no separators.  An entry has this 
+ * exact format:
+ *
+ * sizeof(krb5_int16) bytes for number of components in the principal; 
+ * then, each component listed in ordser.
+ * For each component, sizeof(krb5_int16) bytes for the number of bytes
+ * in the component, followed by the component.
+ * sizeof(krb5_int32) for the principal type (for KEYTAB V2 and higher)
+ * sizeof(krb5_int32) bytes for the timestamp
+ * sizeof(krb5_octet) bytes for the key version number
+ * sizeof(krb5_int16) bytes for the enctype
+ * sizeof(krb5_int32) bytes for the key length, followed by the key
+ */
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#endif
+
+typedef krb5_int16  krb5_kt_vno;
+
+#define krb5_kt_default_vno ((krb5_kt_vno)KRB5_KT_DEFAULT_VNO)
+
+#define xfwrite(a, b, c, d) fwrite((char *)a, b, (unsigned) c, d)
+#define xfread(a, b, c, d) fread((char *)a, b, (unsigned) c, d)
+
+#ifdef ANSI_STDIO
+static char *const fopen_mode_rbplus= "rb+";
+static char *const fopen_mode_rb = "rb";
+#else
+static char *const fopen_mode_rbplus= "r+";
+static char *const fopen_mode_rb = "r";
+#endif
+
+static krb5_error_code
+krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
+{
+    krb5_error_code kerror;
+    krb5_kt_vno kt_vno;
+    int writevno = 0;
+
+    KTCHECKLOCK(id);
+    errno = 0;
+    KTFILEP(id) = fopen(KTFILENAME(id),
+			(mode == KRB5_LOCKMODE_EXCLUSIVE) ?
+			  fopen_mode_rbplus : fopen_mode_rb);
+    if (!KTFILEP(id)) {
+	if ((mode == KRB5_LOCKMODE_EXCLUSIVE) && (errno == ENOENT)) {
+	    /* try making it first time around */
+            krb5_create_secure_file(context, KTFILENAME(id));
+	    errno = 0;
+	    KTFILEP(id) = fopen(KTFILENAME(id), fopen_mode_rbplus);
+	    if (!KTFILEP(id))
+		return errno ? errno : EMFILE;
+	    writevno = 1;
+	} else				/* some other error */
+	    return errno ? errno : EMFILE;
+    }
+    if ((kerror = krb5_lock_file(context, fileno(KTFILEP(id)), mode))) {
+	(void) fclose(KTFILEP(id));
+	KTFILEP(id) = 0;
+	return kerror;
+    }
+    /* assume ANSI or BSD-style stdio */
+    setbuf(KTFILEP(id), KTFILEBUFP(id));
+
+    /* get the vno and verify it */
+    if (writevno) {
+	kt_vno = htons(krb5_kt_default_vno);
+	KTVERSION(id) = krb5_kt_default_vno;
+	if (!xfwrite(&kt_vno, sizeof(kt_vno), 1, KTFILEP(id))) {
+	    kerror = errno;
+	    (void) krb5_unlock_file(context, fileno(KTFILEP(id)));
+	    (void) fclose(KTFILEP(id));
+	    return kerror;
+	}
+    } else {
+	/* gotta verify it instead... */
+	if (!xfread(&kt_vno, sizeof(kt_vno), 1, KTFILEP(id))) {
+	    kerror = errno;
+	    (void) krb5_unlock_file(context, fileno(KTFILEP(id)));
+	    (void) fclose(KTFILEP(id));
+	    return kerror;
+	}
+	kt_vno = KTVERSION(id) = ntohs(kt_vno);
+	if ((kt_vno != KRB5_KT_VNO) &&
+	    (kt_vno != KRB5_KT_VNO_1)) {
+	    (void) krb5_unlock_file(context, fileno(KTFILEP(id)));
+	    (void) fclose(KTFILEP(id));
+	    return KRB5_KEYTAB_BADVNO;
+	}
+    }
+    return 0;
+}
+
+krb5_error_code
+krb5_ktfileint_openr(krb5_context context, krb5_keytab id)
+{
+    return krb5_ktfileint_open(context, id, KRB5_LOCKMODE_SHARED);
+}
+
+krb5_error_code
+krb5_ktfileint_openw(krb5_context context, krb5_keytab id)
+{
+    return krb5_ktfileint_open(context, id, KRB5_LOCKMODE_EXCLUSIVE);
+}
+
+krb5_error_code
+krb5_ktfileint_close(krb5_context context, krb5_keytab id)
+{
+    krb5_error_code kerror;
+
+    KTCHECKLOCK(id);
+    if (!KTFILEP(id))
+	return 0;
+    kerror = krb5_unlock_file(context, fileno(KTFILEP(id)));
+    (void) fclose(KTFILEP(id));
+    KTFILEP(id) = 0;
+    return kerror;
+}
+
+krb5_error_code
+krb5_ktfileint_delete_entry(krb5_context context, krb5_keytab id, krb5_int32 delete_point)
+{
+    krb5_int32  size;
+    krb5_int32  len;
+    char        iobuf[BUFSIZ];
+
+    KTCHECKLOCK(id);
+    if (fseek(KTFILEP(id), delete_point, SEEK_SET)) {
+        return errno;
+    }
+    if (!xfread(&size, sizeof(size), 1, KTFILEP(id))) {
+        return KRB5_KT_END;
+    }
+    if (KTVERSION(id) != KRB5_KT_VNO_1)
+	size = ntohl(size);
+
+    if (size > 0) {
+        krb5_int32 minus_size = -size;
+	if (KTVERSION(id) != KRB5_KT_VNO_1)
+	    minus_size = htonl(minus_size);
+
+        if (fseek(KTFILEP(id), delete_point, SEEK_SET)) {
+            return errno;
+        }
+
+        if (!xfwrite(&minus_size, sizeof(minus_size), 1, KTFILEP(id))) {
+            return KRB5_KT_IOERR;
+        }
+
+        if (size < BUFSIZ) {
+            len = size;
+        } else {
+            len = BUFSIZ;
+        }
+
+        memset(iobuf, 0, (size_t) len);
+        while (size > 0) {
+            xfwrite(iobuf, 1, (size_t) len, KTFILEP(id));
+            size -= len;
+            if (size < len) {
+                len = size;
+            }
+        }
+
+        return krb5_sync_disk_file(context, KTFILEP(id));
+    }
+
+    return 0;
+}
+
+krb5_error_code
+krb5_ktfileint_internal_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *ret_entry, krb5_int32 *delete_point)
+{
+    krb5_octet vno;
+    krb5_int16 count;
+    unsigned int u_count, u_princ_size;
+    krb5_int16 enctype;
+    krb5_int16 princ_size;
+    register int i;
+    krb5_int32 size;
+    krb5_int32 start_pos;
+    krb5_error_code error;
+    char	*tmpdata;
+    krb5_data	*princ;
+
+    KTCHECKLOCK(id);
+    memset(ret_entry, 0, sizeof(krb5_keytab_entry));
+    ret_entry->magic = KV5M_KEYTAB_ENTRY;
+
+    /* fseek to synchronise buffered I/O on the key table. */
+
+    if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
+    {
+        return errno;
+    }
+
+    do {
+        *delete_point = ftell(KTFILEP(id));
+        if (!xfread(&size, sizeof(size), 1, KTFILEP(id))) {
+            return KRB5_KT_END;
+        }
+	if (KTVERSION(id) != KRB5_KT_VNO_1)
+		size = ntohl(size);
+
+        if (size < 0) {
+            if (fseek(KTFILEP(id), -size, SEEK_CUR)) {
+                return errno;
+            }
+        }
+    } while (size < 0);
+
+    if (size == 0) {
+        return KRB5_KT_END;
+    }
+
+    start_pos = ftell(KTFILEP(id));
+
+    /* deal with guts of parsing... */
+
+    /* first, int16 with #princ components */
+    if (!xfread(&count, sizeof(count), 1, KTFILEP(id)))
+	return KRB5_KT_END;
+    if (KTVERSION(id) == KRB5_KT_VNO_1) {
+	    count -= 1;		/* V1 includes the realm in the count */
+    } else {
+	    count = ntohs(count);
+    }
+    if (!count || (count < 0))
+	return KRB5_KT_END;
+    ret_entry->principal = (krb5_principal)malloc(sizeof(krb5_principal_data));
+    if (!ret_entry->principal)
+        return ENOMEM;
+    
+    u_count = count;
+    ret_entry->principal->magic = KV5M_PRINCIPAL;
+    ret_entry->principal->length = u_count;
+    ret_entry->principal->data = (krb5_data *) 
+                                 calloc(u_count, sizeof(krb5_data));
+    if (!ret_entry->principal->data) {
+	free(ret_entry->principal);
+	ret_entry->principal = 0;
+	return ENOMEM;
+    }
+
+    /* Now, get the realm data */
+    if (!xfread(&princ_size, sizeof(princ_size), 1, KTFILEP(id))) {
+	    error = KRB5_KT_END;
+	    goto fail;
+    }
+    if (KTVERSION(id) != KRB5_KT_VNO_1)
+	    princ_size = ntohs(princ_size);
+    if (!princ_size || (princ_size < 0)) {
+	    error = KRB5_KT_END;
+	    goto fail;
+    }
+    u_princ_size = princ_size;
+
+    krb5_princ_set_realm_length(context, ret_entry->principal, u_princ_size);
+    tmpdata = malloc(u_princ_size+1);
+    if (!tmpdata) {
+	    error = ENOMEM;
+	    goto fail;
+    }
+    if (fread(tmpdata, 1, u_princ_size, KTFILEP(id)) != (size_t) princ_size) {
+	    free(tmpdata);
+	    error = KRB5_KT_END;
+	    goto fail;
+    }
+    tmpdata[princ_size] = 0;	/* Some things might be expecting null */
+				/* termination...  ``Be conservative in */
+				/* what you send out'' */
+    krb5_princ_set_realm_data(context, ret_entry->principal, tmpdata);
+    
+    for (i = 0; i < count; i++) {
+	princ = krb5_princ_component(context, ret_entry->principal, i);
+	if (!xfread(&princ_size, sizeof(princ_size), 1, KTFILEP(id))) {
+	    error = KRB5_KT_END;
+	    goto fail;
+        }
+	if (KTVERSION(id) != KRB5_KT_VNO_1)
+	    princ_size = ntohs(princ_size);
+	if (!princ_size || (princ_size < 0)) {
+	    error = KRB5_KT_END;
+	    goto fail;
+        }
+
+	u_princ_size = princ_size; 
+	princ->length = u_princ_size;
+	princ->data = malloc(u_princ_size+1);
+	if (!princ->data) {
+	    error = ENOMEM;
+	    goto fail;
+        }
+	if (!xfread(princ->data, sizeof(char), u_princ_size, KTFILEP(id))) {
+	    error = KRB5_KT_END;
+	    goto fail;
+        }
+	princ->data[princ_size] = 0; /* Null terminate */
+    }
+
+    /* read in the principal type, if we can get it */
+    if (KTVERSION(id) != KRB5_KT_VNO_1) {
+	    if (!xfread(&ret_entry->principal->type,
+			sizeof(ret_entry->principal->type), 1, KTFILEP(id))) {
+		    error = KRB5_KT_END;
+		    goto fail;
+	    }
+	    ret_entry->principal->type = ntohl(ret_entry->principal->type);
+    }
+    
+    /* read in the timestamp */
+    if (!xfread(&ret_entry->timestamp, sizeof(ret_entry->timestamp), 1, KTFILEP(id))) {
+	error = KRB5_KT_END;
+	goto fail;
+    }
+    if (KTVERSION(id) != KRB5_KT_VNO_1)
+	ret_entry->timestamp = ntohl(ret_entry->timestamp);
+    
+    /* read in the version number */
+    if (!xfread(&vno, sizeof(vno), 1, KTFILEP(id))) {
+	error = KRB5_KT_END;
+	goto fail;
+    }
+    ret_entry->vno = (krb5_kvno)vno;
+    
+    /* key type */
+    if (!xfread(&enctype, sizeof(enctype), 1, KTFILEP(id))) {
+	error = KRB5_KT_END;
+	goto fail;
+    }
+    ret_entry->key.enctype = (krb5_enctype)enctype;
+
+    if (KTVERSION(id) != KRB5_KT_VNO_1)
+	ret_entry->key.enctype = ntohs(ret_entry->key.enctype);
+    
+    /* key contents */
+    ret_entry->key.magic = KV5M_KEYBLOCK;
+    
+    if (!xfread(&count, sizeof(count), 1, KTFILEP(id))) {
+	error = KRB5_KT_END;
+	goto fail;
+    }
+    if (KTVERSION(id) != KRB5_KT_VNO_1)
+	count = ntohs(count);
+    if (!count || (count < 0)) {
+	error = KRB5_KT_END;
+	goto fail;
+    }
+
+    u_count = count;
+    ret_entry->key.length = u_count;
+    
+    ret_entry->key.contents = (krb5_octet *)malloc(u_count);
+    if (!ret_entry->key.contents) {
+	error = ENOMEM;
+	goto fail;
+    }		
+    if (!xfread(ret_entry->key.contents, sizeof(krb5_octet), count,
+		KTFILEP(id))) {
+	error = KRB5_KT_END;
+	goto fail;
+    }
+
+    /*
+     * Reposition file pointer to the next inter-record length field.
+     */
+    fseek(KTFILEP(id), start_pos + size, SEEK_SET);
+    return 0;
+fail:
+    
+    for (i = 0; i < krb5_princ_size(context, ret_entry->principal); i++) {
+	    princ = krb5_princ_component(context, ret_entry->principal, i);
+	    if (princ->data)
+		    free(princ->data);
+    }
+    free(ret_entry->principal->data);
+    ret_entry->principal->data = 0;
+    free(ret_entry->principal);
+    ret_entry->principal = 0;
+    return error;
+}
+
+krb5_error_code
+krb5_ktfileint_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entryp)
+{
+    krb5_int32 delete_point;
+
+    return krb5_ktfileint_internal_read_entry(context, id, entryp, &delete_point);
+}
+
+krb5_error_code
+krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
+{
+    krb5_octet vno;
+    krb5_data *princ;
+    krb5_int16 count, size, enctype;
+    krb5_error_code retval = 0;
+    krb5_timestamp timestamp;
+    krb5_int32	princ_type;
+    krb5_int32  size_needed;
+    krb5_int32  commit_point;
+    int		i;
+
+    KTCHECKLOCK(id);
+    retval = krb5_ktfileint_size_entry(context, entry, &size_needed);
+    if (retval)
+        return retval;
+    retval = krb5_ktfileint_find_slot(context, id, &size_needed, &commit_point);
+    if (retval)
+        return retval;
+
+    /* fseek to synchronise buffered I/O on the key table. */
+    /* XXX Without the weird setbuf crock, can we get rid of this now?  */
+    if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
+    {
+        return errno;
+    }
+
+    if (KTVERSION(id) == KRB5_KT_VNO_1) {
+	    count = (krb5_int16) krb5_princ_size(context, entry->principal) + 1;
+    } else {
+	    count = htons((u_short) krb5_princ_size(context, entry->principal));
+    }
+    
+    if (!xfwrite(&count, sizeof(count), 1, KTFILEP(id))) {
+    abend:
+	return KRB5_KT_IOERR;
+    }
+    size = krb5_princ_realm(context, entry->principal)->length;
+    if (KTVERSION(id) != KRB5_KT_VNO_1)
+	    size = htons(size);
+    if (!xfwrite(&size, sizeof(size), 1, KTFILEP(id))) {
+	    goto abend;
+    }
+    if (!xfwrite(krb5_princ_realm(context, entry->principal)->data, sizeof(char),
+		 krb5_princ_realm(context, entry->principal)->length, KTFILEP(id))) {
+	    goto abend;
+    }
+
+    count = (krb5_int16) krb5_princ_size(context, entry->principal);
+    for (i = 0; i < count; i++) {
+	princ = krb5_princ_component(context, entry->principal, i);
+	size = princ->length;
+	if (KTVERSION(id) != KRB5_KT_VNO_1)
+		size = htons(size);
+	if (!xfwrite(&size, sizeof(size), 1, KTFILEP(id))) {
+	    goto abend;
+	}
+	if (!xfwrite(princ->data, sizeof(char), princ->length, KTFILEP(id))) {
+	    goto abend;
+	}
+    }
+
+    /*
+     * Write out the principal type
+     */
+    if (KTVERSION(id) != KRB5_KT_VNO_1) {
+	    princ_type = htonl(krb5_princ_type(context, entry->principal));
+	    if (!xfwrite(&princ_type, sizeof(princ_type), 1, KTFILEP(id))) {
+		    goto abend;
+	    }
+    }
+    
+    /*
+     * Fill in the time of day the entry was written to the keytab.
+     */
+    if (krb5_timeofday(context, &entry->timestamp)) {
+        entry->timestamp = 0;
+    }
+    if (KTVERSION(id) == KRB5_KT_VNO_1)
+	    timestamp = entry->timestamp;
+    else
+	    timestamp = htonl(entry->timestamp);
+    if (!xfwrite(×tamp, sizeof(timestamp), 1, KTFILEP(id))) {
+	goto abend;
+    }
+    
+    /* key version number */
+    vno = (krb5_octet)entry->vno;
+    if (!xfwrite(&vno, sizeof(vno), 1, KTFILEP(id))) {
+	goto abend;
+    }
+    /* key type */
+    if (KTVERSION(id) == KRB5_KT_VNO_1)
+	    enctype = entry->key.enctype;
+    else
+	    enctype = htons(entry->key.enctype);
+    if (!xfwrite(&enctype, sizeof(enctype), 1, KTFILEP(id))) {
+	goto abend;
+    }
+    /* key length */
+    if (KTVERSION(id) == KRB5_KT_VNO_1)
+	    size = entry->key.length;
+    else
+	    size = htons(entry->key.length);
+    if (!xfwrite(&size, sizeof(size), 1, KTFILEP(id))) {
+	goto abend;
+    }
+    if (!xfwrite(entry->key.contents, sizeof(krb5_octet),
+		 entry->key.length, KTFILEP(id))) {
+	goto abend;
+    }	
+
+    if (fflush(KTFILEP(id)))
+	goto abend;
+
+    retval = krb5_sync_disk_file(context, KTFILEP(id));
+
+    if (retval) {
+        return retval;
+    }
+
+    if (fseek(KTFILEP(id), commit_point, SEEK_SET)) {
+        return errno;
+    }
+    if (KTVERSION(id) != KRB5_KT_VNO_1)
+	    size_needed = htonl(size_needed);
+    if (!xfwrite(&size_needed, sizeof(size_needed), 1, KTFILEP(id))) {
+        goto abend;
+    }
+    if (fflush(KTFILEP(id)))
+	goto abend;
+    retval = krb5_sync_disk_file(context, KTFILEP(id));
+
+    return retval;
+}
+
+/*
+ * Determine the size needed for a file entry for the given
+ * keytab entry.
+ */
+krb5_error_code
+krb5_ktfileint_size_entry(krb5_context context, krb5_keytab_entry *entry, krb5_int32 *size_needed)
+{
+    krb5_int16 count;
+    krb5_int32 total_size, i;
+    krb5_error_code retval = 0;
+
+    count = (krb5_int16) krb5_princ_size(context, entry->principal);
+        
+    total_size = sizeof(count);
+    total_size += krb5_princ_realm(context, entry->principal)->length + (sizeof(krb5_int16));
+    
+    for (i = 0; i < count; i++) {
+	    total_size += krb5_princ_component(context, entry->principal,i)->length
+		    + (sizeof(krb5_int16));
+    }
+
+    total_size += sizeof(entry->principal->type);
+    total_size += sizeof(entry->timestamp);
+    total_size += sizeof(krb5_octet);
+    total_size += sizeof(krb5_int16);
+    total_size += sizeof(krb5_int16) + entry->key.length;
+
+    *size_needed = total_size;
+    return retval;
+}
+
+/*
+ * Find and reserve a slot in the file for an entry of the needed size.
+ * The commit point will be set to the position in the file where the
+ * the length (sizeof(krb5_int32) bytes) of this node should be written
+ * when commiting the write.  The file position left as a result of this
+ * call is the position where the actual data should be written.
+ *
+ * The size_needed argument may be adjusted if we find a hole that is
+ * larger than the size needed.  (Recall that size_needed will be used
+ * to commit the write, but that this field must indicate the size of the
+ * block in the file rather than the size of the actual entry)  
+ */
+krb5_error_code
+krb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_needed, krb5_int32 *commit_point)
+{
+    krb5_int32      size;
+    krb5_int32      remainder;
+    krb5_int32      zero_point;
+    krb5_kt_vno     kt_vno;
+    krb5_boolean    found = FALSE;
+    char            iobuf[BUFSIZ];
+
+    KTCHECKLOCK(id);
+    /*
+     * Skip over file version number
+     */
+    if (fseek(KTFILEP(id), 0, SEEK_SET)) {
+        return errno;
+    }
+    if (!xfread(&kt_vno, sizeof(kt_vno), 1, KTFILEP(id))) {
+        return KRB5_KT_IOERR;
+    }
+
+    while (!found) {
+        *commit_point = ftell(KTFILEP(id));
+        if (!xfread(&size, sizeof(size), 1, KTFILEP(id))) {
+            /*
+             * Hit the end of file, reserve this slot.
+             */
+            size = 0;
+
+            /* fseek to synchronise buffered I/O on the key table. */
+	    /* XXX Without the weird setbuf hack, can we nuke this now?  */
+            if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
+            {
+                return errno;
+            }
+	    
+#ifdef notdef
+	    /* We don't have to do this because htonl(0) == 0 */
+	    if (KTVERSION(id) != KRB5_KT_VNO_1)
+		    size = htonl(size);
+#endif
+	    
+            if (!xfwrite(&size, sizeof(size), 1, KTFILEP(id))) {
+                return KRB5_KT_IOERR;
+            }
+            found = TRUE;
+        }
+
+	if (KTVERSION(id) != KRB5_KT_VNO_1)
+		size = ntohl(size);
+
+        if (size > 0) {
+            if (fseek(KTFILEP(id), size, SEEK_CUR)) {
+                return errno;
+            }
+        } else if (!found) {
+            size = -size;
+            if (size >= *size_needed) {
+                *size_needed = size;
+                found = TRUE;	
+            } else if (size > 0) {
+                /*
+                 * The current hole is not large enough, so skip it
+                 */
+                if (fseek(KTFILEP(id), size, SEEK_CUR)) {
+                    return errno;
+                }
+            } else {
+
+                 /* fseek to synchronise buffered I/O on the key table. */
+
+                 if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
+                 {
+                     return errno;
+                 }
+
+                /*
+                 * Found the end of the file (marked by a 0 length buffer)
+                 * Make sure we zero any trailing data.
+                 */
+                zero_point = ftell(KTFILEP(id));
+                while ((size = xfread(iobuf, 1, sizeof(iobuf), KTFILEP(id)))) {
+                    if (size != sizeof(iobuf)) {
+                        remainder = size % sizeof(krb5_int32);
+                        if (remainder) {
+                            size += sizeof(krb5_int32) - remainder;
+                        }
+                    }
+
+                    if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
+                    {
+                        return errno;
+                    }
+
+                    memset(iobuf, 0, (size_t) size);
+                    xfwrite(iobuf, 1, (size_t) size, KTFILEP(id));
+		    fflush(KTFILEP(id));
+                    if (feof(KTFILEP(id))) {
+                        break;
+                    }
+
+                    if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
+                    {
+                        return errno;
+                    }
+
+                }
+                if (fseek(KTFILEP(id), zero_point, SEEK_SET)) {
+                    return errno;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/keytab/kt_srvtab.c b/mechglue/src/lib/krb5/keytab/kt_srvtab.c
new file mode 100644
index 000000000..cb9d9c1bc
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/kt_srvtab.c
@@ -0,0 +1,482 @@
+/*
+ * lib/krb5/keytab/srvtab/kts_resolv.c
+ *
+ * Copyright 1990,1991,2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+
+/*
+ * Constants
+ */
+#define IGNORE_VNO 0
+#define IGNORE_ENCTYPE 0
+
+#define KRB5_KT_VNO_1	0x0501	/* krb v5, keytab version 1 (DCE compat) */
+#define KRB5_KT_VNO	0x0502	/* krb v5, keytab version 2 (standard)  */
+
+#define KRB5_KT_DEFAULT_VNO KRB5_KT_VNO
+
+/* 
+ * Types
+ */
+typedef struct _krb5_ktsrvtab_data {
+    char *name;			/* Name of the file */
+    FILE *openf;		/* open file, if any. */
+} krb5_ktsrvtab_data;
+
+/*
+ * Macros
+ */
+#define KTPRIVATE(id) ((krb5_ktsrvtab_data *)(id)->data)
+#define KTFILENAME(id) (((krb5_ktsrvtab_data *)(id)->data)->name)
+#define KTFILEP(id) (((krb5_ktsrvtab_data *)(id)->data)->openf)
+
+extern const struct _krb5_kt_ops krb5_kts_ops;
+
+static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_resolve
+	(krb5_context,
+		   const char *,
+		   krb5_keytab *);
+
+static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_name
+	(krb5_context,
+		   krb5_keytab,
+		   char *,
+		   unsigned int);
+
+static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_close
+	(krb5_context,
+		   krb5_keytab);
+
+static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_entry
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_const_principal,
+		   krb5_kvno,
+		   krb5_enctype,
+		   krb5_keytab_entry *);
+
+static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_start_seq_get
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_kt_cursor *);
+
+static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_next
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_keytab_entry *,
+		   krb5_kt_cursor *);
+
+static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_end_get
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_kt_cursor *);
+
+static krb5_error_code krb5_ktsrvint_open
+	(krb5_context,
+		   krb5_keytab);
+
+static krb5_error_code krb5_ktsrvint_close
+	(krb5_context,
+		   krb5_keytab);
+
+static krb5_error_code krb5_ktsrvint_read_entry 
+	(krb5_context,
+		   krb5_keytab,
+		   krb5_keytab_entry *);
+
+/*
+ * This is an implementation specific resolver.  It returns a keytab id 
+ * initialized with srvtab keytab routines.
+ */
+
+static krb5_error_code KRB5_CALLCONV
+krb5_ktsrvtab_resolve(krb5_context context, const char *name, krb5_keytab *id)
+{
+    krb5_ktsrvtab_data *data;
+    FILE *fp;
+
+    /* Make sure we can open the srvtab file for reading. */
+    fp = fopen(name, "r");
+    if (!fp)
+	return(errno);
+    fclose(fp);
+
+    if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
+	return(ENOMEM);
+    
+    (*id)->ops = &krb5_kts_ops;
+    data = (krb5_ktsrvtab_data *)malloc(sizeof(krb5_ktsrvtab_data));
+    if (data == NULL) {
+	krb5_xfree(*id);
+	return(ENOMEM);
+    }
+
+    data->name = (char *)malloc(strlen(name) + 1);
+    if (data->name == NULL) {
+	krb5_xfree(data);
+	krb5_xfree(*id);
+	return(ENOMEM);
+    }
+
+    (void) strcpy(data->name, name);
+    data->openf = 0;
+
+    (*id)->data = (krb5_pointer)data;
+    (*id)->magic = KV5M_KEYTAB;
+    return(0);
+}
+
+/*
+ * "Close" a file-based keytab and invalidate the id.  This means
+ * free memory hidden in the structures.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktsrvtab_close(krb5_context context, krb5_keytab id)
+  /*
+   * This routine is responsible for freeing all memory allocated 
+   * for this keytab.  There are no system resources that need
+   * to be freed nor are there any open files.
+   *
+   * This routine should undo anything done by krb5_ktsrvtab_resolve().
+   */
+{
+    krb5_xfree(KTFILENAME(id));
+    krb5_xfree(id->data);
+    id->ops = 0;
+    krb5_xfree(id);
+    return (0);
+}
+
+/*
+ * This is the get_entry routine for the file based keytab implementation.
+ * It opens the keytab file, and either retrieves the entry or returns
+ * an error.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktsrvtab_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, krb5_enctype enctype, krb5_keytab_entry *entry)
+{
+    krb5_keytab_entry best_entry, ent;
+    krb5_error_code kerror = 0;
+    int found_wrong_kvno = 0;
+
+    /* Open the srvtab. */
+    if ((kerror = krb5_ktsrvint_open(context, id)))
+	return(kerror);
+
+    /* srvtab files only have DES_CBC_CRC keys. */
+    switch (enctype) {
+    case ENCTYPE_DES_CBC_CRC:
+    case ENCTYPE_DES_CBC_MD5:
+    case ENCTYPE_DES_CBC_MD4:
+    case ENCTYPE_DES_CBC_RAW:
+    case IGNORE_ENCTYPE:
+	break;
+    default:
+	return KRB5_KT_NOTFOUND;
+    }
+
+    best_entry.principal = 0;
+    best_entry.vno = 0;
+    best_entry.key.contents = 0;
+    while ((kerror = krb5_ktsrvint_read_entry(context, id, &ent)) == 0) {
+	ent.key.enctype = enctype;
+	if (krb5_principal_compare(context, principal, ent.principal)) {
+	    if (kvno == IGNORE_VNO) {
+		if (!best_entry.principal || (best_entry.vno < ent.vno)) {
+		    krb5_kt_free_entry(context, &best_entry);
+		    best_entry = ent;
+		}
+	    } else {
+		if (ent.vno == kvno) {
+		    best_entry = ent;
+		    break;
+		} else {
+		    found_wrong_kvno = 1;
+		}
+	    }
+	} else {
+	    krb5_kt_free_entry(context, &ent);
+	}
+    }
+    if (kerror == KRB5_KT_END) {
+	 if (best_entry.principal)
+	      kerror = 0;
+	 else if (found_wrong_kvno)
+	      kerror = KRB5_KT_KVNONOTFOUND;
+	 else
+	      kerror = KRB5_KT_NOTFOUND;
+    }
+    if (kerror) {
+	(void) krb5_ktsrvint_close(context, id);
+	krb5_kt_free_entry(context, &best_entry);
+	return kerror;
+    }
+    if ((kerror = krb5_ktsrvint_close(context, id)) != 0) {
+	krb5_kt_free_entry(context, &best_entry);
+	return kerror;
+    }
+    *entry = best_entry;
+    return 0;
+}
+
+/*
+ * Get the name of the file containing a srvtab-based keytab.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktsrvtab_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len)
+  /* 
+   * This routine returns the name of the name of the file associated with
+   * this srvtab-based keytab.  The name is prefixed with PREFIX:, so that
+   * trt will happen if the name is passed back to resolve.
+   */
+{
+    memset(name, 0, len);
+
+    if (len < strlen(id->ops->prefix)+2)
+	return(KRB5_KT_NAME_TOOLONG);
+    strcpy(name, id->ops->prefix);
+    name += strlen(id->ops->prefix);
+    name[0] = ':';
+    name++;
+    len -= strlen(id->ops->prefix)+1;
+
+    if (len < strlen(KTFILENAME(id)+1))
+	return(KRB5_KT_NAME_TOOLONG);
+    strcpy(name, KTFILENAME(id));
+    /* strcpy will NUL-terminate the destination */
+
+    return(0);
+}
+
+/*
+ * krb5_ktsrvtab_start_seq_get()
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktsrvtab_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp)
+{
+    krb5_error_code retval;
+    long *fileoff;
+
+    if ((retval = krb5_ktsrvint_open(context, id)))
+	return retval;
+
+    if (!(fileoff = (long *)malloc(sizeof(*fileoff)))) {
+	krb5_ktsrvint_close(context, id);
+	return ENOMEM;
+    }
+    *fileoff = ftell(KTFILEP(id));
+    *cursorp = (krb5_kt_cursor)fileoff;
+
+    return 0;
+}
+
+/*
+ * krb5_ktsrvtab_get_next()
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktsrvtab_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor)
+{
+    long *fileoff = (long *)*cursor;
+    krb5_keytab_entry cur_entry;
+    krb5_error_code kerror;
+
+    if (fseek(KTFILEP(id), *fileoff, 0) == -1)
+	return KRB5_KT_END;
+    if ((kerror = krb5_ktsrvint_read_entry(context, id, &cur_entry)))
+	return kerror;
+    *fileoff = ftell(KTFILEP(id));
+    *entry = cur_entry;
+    return 0;
+}
+
+/*
+ * krb5_ktsrvtab_end_get()
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_ktsrvtab_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor)
+{
+    krb5_xfree(*cursor);
+    return krb5_ktsrvint_close(context, id);
+}
+
+/*
+ * krb5_kts_ops
+ */
+
+const struct _krb5_kt_ops krb5_kts_ops = {
+    0,
+    "SRVTAB", 	/* Prefix -- this string should not appear anywhere else! */
+    krb5_ktsrvtab_resolve,
+    krb5_ktsrvtab_get_name, 
+    krb5_ktsrvtab_close,
+    krb5_ktsrvtab_get_entry,
+    krb5_ktsrvtab_start_seq_get,
+    krb5_ktsrvtab_get_next,
+    krb5_ktsrvtab_end_get,
+    0,
+    0,
+    0
+};
+
+/*
+ * formerly: lib/krb5/keytab/srvtab/kts_util.c
+ *
+ * Copyright (c) Hewlett-Packard Company 1991
+ * Released to the Massachusetts Institute of Technology for inclusion
+ * in the Kerberos source code distribution.
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This function contains utilities for the srvtab based implementation
+ * of the keytab.  There are no public functions in this file.
+ */
+
+#include <stdio.h>
+
+#ifdef ANSI_STDIO
+#define		READ_MODE	"rb"
+#else
+#define		READ_MODE	"r"
+#endif
+
+/* The maximum sizes for V4 aname, realm, sname, and instance +1 */
+/* Taken from krb.h */
+#define 	ANAME_SZ	40
+#define		REALM_SZ	40
+#define		SNAME_SZ	40
+#define		INST_SZ		40
+
+static krb5_error_code
+read_field(FILE *fp, char *s, int len)
+{
+    int c;
+
+    while ((c = getc(fp)) != 0) {
+	if (c == EOF || len <= 1)
+	    return KRB5_KT_END;
+	*s = c;
+	s++;
+	len--;
+    }
+    *s = 0;
+    return 0;
+}
+
+krb5_error_code
+krb5_ktsrvint_open(krb5_context context, krb5_keytab id)
+{
+    KTFILEP(id) = fopen(KTFILENAME(id), READ_MODE);
+    if (!KTFILEP(id))
+	return errno;
+    return 0;
+}
+
+krb5_error_code
+krb5_ktsrvint_close(krb5_context context, krb5_keytab id)
+{
+    if (!KTFILEP(id))
+	return 0;
+    (void) fclose(KTFILEP(id));
+    KTFILEP(id) = 0;
+    return 0;
+}
+
+krb5_error_code
+krb5_ktsrvint_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *ret_entry)
+{
+    FILE *fp;
+    char name[SNAME_SZ], instance[INST_SZ], realm[REALM_SZ];
+    unsigned char key[8];
+    int vno;
+    krb5_error_code kerror;
+
+    /* Read in an entry from the srvtab file. */
+    fp = KTFILEP(id);
+    kerror = read_field(fp, name, sizeof(name));
+    if (kerror != 0)
+	return kerror;
+    kerror = read_field(fp, instance, sizeof(instance));
+    if (kerror != 0)
+	return kerror;
+    kerror = read_field(fp, realm, sizeof(realm));
+    if (kerror != 0)
+	return kerror;
+    vno = getc(fp);
+    if (vno == EOF)
+	return KRB5_KT_END;
+    if (fread(key, 1, sizeof(key), fp) != sizeof(key))
+	return KRB5_KT_END;
+
+    /* Fill in ret_entry with the data we read.  Everything maps well
+     * except for the timestamp, which we don't have a value for.  For
+     * now we just set it to 0. */
+    memset(ret_entry, 0, sizeof(*ret_entry));
+    ret_entry->magic = KV5M_KEYTAB_ENTRY;
+    kerror = krb5_425_conv_principal(context, name, instance, realm,
+				     &ret_entry->principal);
+    if (kerror != 0)
+	return kerror;
+    ret_entry->vno = vno;
+    ret_entry->timestamp = 0;
+    ret_entry->key.enctype = ENCTYPE_DES_CBC_CRC;
+    ret_entry->key.magic = KV5M_KEYBLOCK;
+    ret_entry->key.length = sizeof(key);
+    ret_entry->key.contents = malloc(sizeof(key));
+    if (!ret_entry->key.contents) {
+	krb5_free_principal(context, ret_entry->principal);
+	return ENOMEM;
+    }
+    memcpy(ret_entry->key.contents, key, sizeof(key));
+
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/keytab/ktadd.c b/mechglue/src/lib/krb5/keytab/ktadd.c
new file mode 100644
index 000000000..b7c1b9216
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/ktadd.c
@@ -0,0 +1,39 @@
+/*
+ * lib/krb5/keytab/ktadd.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_kt_add_entry()
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_add_entry (krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
+{
+    if (id->ops->add)
+	return (*id->ops->add)(context, id, entry);
+    else
+	return KRB5_KT_NOWRITE;
+}
diff --git a/mechglue/src/lib/krb5/keytab/ktbase.c b/mechglue/src/lib/krb5/keytab/ktbase.c
new file mode 100644
index 000000000..e633c0c3a
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/ktbase.c
@@ -0,0 +1,244 @@
+/*
+ * lib/krb5/keytab/ktbase.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Registration functions for keytab.
+ */
+
+#include "k5-int.h"
+#include "k5-thread.h"
+#include "kt-int.h"
+
+extern const krb5_kt_ops krb5_ktf_ops;
+extern const krb5_kt_ops krb5_ktf_writable_ops;
+extern const krb5_kt_ops krb5_kts_ops;
+
+struct krb5_kt_typelist {
+    const krb5_kt_ops *ops;
+    const struct krb5_kt_typelist *next;
+};
+const static struct krb5_kt_typelist krb5_kt_typelist_wrfile  = {
+    &krb5_ktf_writable_ops,
+    0
+};
+const static struct krb5_kt_typelist krb5_kt_typelist_file  = {
+    &krb5_ktf_ops,
+    &krb5_kt_typelist_wrfile
+};
+const static struct krb5_kt_typelist krb5_kt_typelist_srvtab = {
+    &krb5_kts_ops,
+    &krb5_kt_typelist_file
+};
+static const struct krb5_kt_typelist *kt_typehead = &krb5_kt_typelist_srvtab;
+/* Lock for protecting the type list.  */
+static k5_mutex_t kt_typehead_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+int krb5int_kt_initialize(void)
+{
+    return k5_mutex_finish_init(&kt_typehead_lock);
+}
+
+void
+krb5int_kt_finalize(void)
+{
+    struct krb5_kt_typelist *t, *t_next;
+    k5_mutex_destroy(&kt_typehead_lock);
+    for (t = kt_typehead; t != &krb5_kt_typelist_srvtab; t = t_next) {
+	t_next = t->next;
+	free(t);
+    }
+}
+
+
+/*
+ * Register a new key table type
+ * don't replace if it already exists; return an error instead.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_register(krb5_context context, const krb5_kt_ops *ops)
+{
+    const struct krb5_kt_typelist *t;
+    struct krb5_kt_typelist *newt;
+    krb5_error_code err;
+
+    err = k5_mutex_lock(&kt_typehead_lock);
+    if (err)
+	return err;
+    for (t = kt_typehead; t && strcmp(t->ops->prefix,ops->prefix);t = t->next)
+	;
+    if (t) {
+	k5_mutex_unlock(&kt_typehead_lock);
+	return KRB5_KT_TYPE_EXISTS;
+    }
+    if (!(newt = (struct krb5_kt_typelist *) malloc(sizeof(*t)))) {
+	k5_mutex_unlock(&kt_typehead_lock);
+	return ENOMEM;
+    }
+    newt->next = kt_typehead;
+    newt->ops = ops;
+    kt_typehead = newt;
+    k5_mutex_unlock(&kt_typehead_lock);
+    return 0;
+}
+
+/*
+ * Resolve a key table name into a keytab object.
+ *
+ * The name is currently constrained to be of the form "type:residual";
+ *
+ * The "type" portion corresponds to one of the registered key table
+ * types, while the "residual" portion is specific to the
+ * particular keytab type.
+ */
+
+#include <ctype.h>
+krb5_error_code KRB5_CALLCONV
+krb5_kt_resolve (krb5_context context, const char *name, krb5_keytab *ktid)
+{
+    const struct krb5_kt_typelist *tlist;
+    char *pfx;
+    unsigned int pfxlen;
+    const char *cp, *resid;
+    krb5_error_code err;
+    
+    cp = strchr (name, ':');
+    if (!cp) {
+	    return (*krb5_kt_dfl_ops.resolve)(context, name, ktid);
+    }
+
+    pfxlen = cp - name;
+
+    if ( pfxlen == 1 && isalpha(name[0]) ) {
+        /* We found a drive letter not a prefix - use FILE: */
+        pfx = strdup("FILE:");
+        if (!pfx)
+            return ENOMEM;
+
+        resid = name;
+    } else {
+        resid = name + pfxlen + 1;
+	
+        pfx = malloc (pfxlen+1);
+        if (!pfx)
+            return ENOMEM;
+
+        memcpy (pfx, name, pfxlen);
+        pfx[pfxlen] = '\0';
+    }
+
+    *ktid = (krb5_keytab) 0;
+
+    err = k5_mutex_lock(&kt_typehead_lock);
+    if (err)
+	return err;
+    tlist = kt_typehead;
+    /* Don't need to hold the lock, since entries are never modified
+       or removed once they're in the list.  Just need to protect
+       access to the list head variable itself.  */
+    k5_mutex_unlock(&kt_typehead_lock);
+    for (; tlist; tlist = tlist->next) {
+	if (strcmp (tlist->ops->prefix, pfx) == 0) {
+	    free(pfx);
+	    return (*tlist->ops->resolve)(context, resid, ktid);
+	}
+    }
+    free(pfx);
+    return KRB5_KT_UNKNOWN_TYPE;
+}
+
+/*
+ * Routines to deal with externalizingt krb5_keytab.
+ *	krb5_keytab_size();
+ *	krb5_keytab_externalize();
+ *	krb5_keytab_internalize();
+ */
+static krb5_error_code krb5_keytab_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_keytab_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_keytab_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/*
+ * Serialization entry for this type.
+ */
+static const krb5_ser_entry krb5_keytab_ser_entry = {
+    KV5M_KEYTAB,			/* Type			*/
+    krb5_keytab_size,			/* Sizer routine	*/
+    krb5_keytab_externalize,		/* Externalize routine	*/
+    krb5_keytab_internalize		/* Internalize routine	*/
+};
+
+static krb5_error_code
+krb5_keytab_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_keytab		keytab;
+    krb5_ser_handle	shandle;
+
+    kret = EINVAL;
+    if ((keytab = (krb5_keytab) arg) &&
+	keytab->ops &&
+	(shandle = (krb5_ser_handle) keytab->ops->serializer) &&
+	shandle->sizer)
+	kret = (*shandle->sizer)(kcontext, arg, sizep);
+    return(kret);
+}
+
+static krb5_error_code
+krb5_keytab_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_keytab		keytab;
+    krb5_ser_handle	shandle;
+
+    kret = EINVAL;
+    if ((keytab = (krb5_keytab) arg) &&
+	keytab->ops &&
+	(shandle = (krb5_ser_handle) keytab->ops->serializer) &&
+	shandle->externalizer)
+	kret = (*shandle->externalizer)(kcontext, arg, buffer, lenremain);
+    return(kret);
+}
+
+static krb5_error_code
+krb5_keytab_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_ser_handle	shandle;
+
+    kret = EINVAL;
+    if ((shandle = (krb5_ser_handle) krb5_kt_dfl_ops.serializer) &&
+	shandle->internalizer)
+	kret = (*shandle->internalizer)(kcontext, argp, buffer, lenremain);
+    return(kret);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_ser_keytab_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_keytab_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5/keytab/ktdefault.c b/mechglue/src/lib/krb5/keytab/ktdefault.c
new file mode 100644
index 000000000..971f29f59
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/ktdefault.c
@@ -0,0 +1,45 @@
+/*
+ * lib/krb5/keytab/ktdefault.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Get a default keytab.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_default(krb5_context context, krb5_keytab *id)
+{
+    char defname[BUFSIZ];
+    krb5_error_code retval;
+
+    if ((retval = krb5_kt_default_name(context, defname, sizeof(defname))))
+	return retval;
+    return krb5_kt_resolve(context, defname, id);
+}
+
+
+
diff --git a/mechglue/src/lib/krb5/keytab/ktfns.c b/mechglue/src/lib/krb5/keytab/ktfns.c
new file mode 100644
index 000000000..70da40695
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/ktfns.c
@@ -0,0 +1,79 @@
+/*
+ * lib/krb5/keytab/ktfns.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Dispatch methods for keytab code.
+ */
+
+#include "k5-int.h"
+
+char * KRB5_CALLCONV
+krb5_kt_get_type (krb5_context context, krb5_keytab keytab)
+{
+    return keytab->ops->prefix;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_get_name(krb5_context context, krb5_keytab keytab, char *name,
+		 unsigned int namelen)
+{
+    return krb5_x((keytab)->ops->get_name,(context, keytab,name,namelen));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_close(krb5_context context, krb5_keytab keytab)
+{
+    return krb5_x((keytab)->ops->close,(context, keytab));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_get_entry(krb5_context context, krb5_keytab keytab,
+		  krb5_const_principal principal, krb5_kvno vno,
+		  krb5_enctype enctype, krb5_keytab_entry *entry)
+{
+    return krb5_x((keytab)->ops->get,(context, keytab, principal, vno, enctype, entry));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_start_seq_get(krb5_context context, krb5_keytab keytab,
+		      krb5_kt_cursor *cursor)
+{
+    return krb5_x((keytab)->ops->start_seq_get,(context, keytab, cursor));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_next_entry(krb5_context context, krb5_keytab keytab,
+		   krb5_keytab_entry *entry, krb5_kt_cursor *cursor)
+{
+    return krb5_x((keytab)->ops->get_next,(context, keytab, entry, cursor));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_end_seq_get(krb5_context context, krb5_keytab keytab,
+		    krb5_kt_cursor *cursor)
+{
+    return krb5_x((keytab)->ops->end_get,(context, keytab, cursor));
+}
diff --git a/mechglue/src/lib/krb5/keytab/ktfr_entry.c b/mechglue/src/lib/krb5/keytab/ktfr_entry.c
new file mode 100644
index 000000000..a86b38bc2
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/ktfr_entry.c
@@ -0,0 +1,50 @@
+/*
+ * lib/krb5/keytab/ktfr_entry.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_kt_free_entry()
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_free_keytab_entry_contents (krb5_context context, krb5_keytab_entry *entry)
+{
+    if (!entry)
+	return 0;
+    
+    krb5_free_principal(context, entry->principal);
+    if (entry->key.contents) {
+	memset((char *)entry->key.contents, 0, entry->key.length);
+	krb5_xfree(entry->key.contents);
+    }
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_free_entry (krb5_context context, krb5_keytab_entry *entry)
+{
+    return krb5_free_keytab_entry_contents (context, entry);
+}
diff --git a/mechglue/src/lib/krb5/keytab/ktremove.c b/mechglue/src/lib/krb5/keytab/ktremove.c
new file mode 100644
index 000000000..d101a7065
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/ktremove.c
@@ -0,0 +1,39 @@
+/*
+ * lib/krb5/keytab/ktremove.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_kt_remove_entry()
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_remove_entry (krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)
+{
+    if (id->ops->remove)
+	return (*id->ops->remove)(context, id, entry);
+    else
+	return KRB5_KT_NOWRITE;
+}
diff --git a/mechglue/src/lib/krb5/keytab/read_servi.c b/mechglue/src/lib/krb5/keytab/read_servi.c
new file mode 100644
index 000000000..3455300ab
--- /dev/null
+++ b/mechglue/src/lib/krb5/keytab/read_servi.c
@@ -0,0 +1,81 @@
+/*
+ * lib/krb5/keytab/read_servi.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This routine is designed to be passed to krb5_rd_req.  
+ * It is a convenience function that reads a key out of a keytab.
+ * It handles all of the opening and closing of the keytab 
+ * internally. 
+ */
+
+#include "k5-int.h"
+
+#define KSUCCESS 0
+
+/*
+ * effects: If keyprocarg is not NULL, it is taken to be the name of a 
+ *	keytab.  Otherwise, the default keytab will be used.  This 
+ *	routine opens the keytab and finds the principal associated with
+ *	principal, vno, and enctype and returns the resulting key in *key 
+ *	or returning an error code if it is not	found. 
+ * returns: Either KSUCCESS or error code.
+ * errors: error code if not found or keyprocarg is invalid.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_kt_read_service_key(krb5_context context, krb5_pointer keyprocarg, krb5_principal principal, krb5_kvno vno, krb5_enctype enctype, krb5_keyblock **key)
+{
+    krb5_error_code kerror = KSUCCESS;
+    char keytabname[MAX_KEYTAB_NAME_LEN + 1]; /* + 1 for NULL termination */
+    krb5_keytab id;
+    krb5_keytab_entry entry;
+        
+    /*
+     * Get the name of the file that we should use. 
+     */
+    if (!keyprocarg) {
+	if ((kerror = krb5_kt_default_name(context, (char *)keytabname, 
+					   sizeof(keytabname) - 1))!= KSUCCESS)
+	    return (kerror);
+    } else {
+	memset(keytabname, 0, sizeof(keytabname));
+	(void) strncpy(keytabname, (char *)keyprocarg, 
+		       sizeof(keytabname) - 1);
+    }
+
+    if ((kerror = krb5_kt_resolve(context, (char *)keytabname, &id)))
+	return (kerror);
+
+    kerror = krb5_kt_get_entry(context, id, principal, vno, enctype, &entry);
+    krb5_kt_close(context, id);
+
+    if (kerror)
+	return(kerror);
+
+    krb5_copy_keyblock(context, &entry.key, key);
+
+    krb5_kt_free_entry(context, &entry);
+
+    return (KSUCCESS);
+}
diff --git a/mechglue/src/lib/krb5/krb/.Sanitize b/mechglue/src/lib/krb5/krb/.Sanitize
new file mode 100644
index 000000000..a2ab3a0d0
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/.Sanitize
@@ -0,0 +1,116 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+addr_comp.c
+addr_order.c
+addr_srch.c
+auth_con.c
+auth_con.h
+bld_pr_ext.c
+bld_princ.c
+chk_trans.c
+cleanup.h
+configure
+configure.in
+conv_creds.c
+conv_princ.c
+copy_addrs.c
+copy_athctr.c
+copy_auth.c
+copy_cksum.c
+copy_creds.c
+copy_data.c
+copy_key.c
+copy_princ.c
+copy_tick.c
+cp_key_cnt.c
+decode_kdc.c
+decrypt_tk.c
+encode_kdc.c
+encrypt_tk.c
+free_rtree.c
+fwd_tgt.c
+gc_frm_kdc.c
+gc_via_tkt.c
+gen_seqnum.c
+gen_subkey.c
+get_creds.c
+get_in_tkt.c
+in_tkt_sky.c
+init_ctx.c
+int-proto.h
+kdc_rep_dc.c
+mk_cred.c
+mk_error.c
+mk_priv.c
+mk_rep.c
+mk_req.c
+mk_req_ext.c
+mk_safe.c
+parse.c
+pr_to_salt.c
+preauth.c
+princ_comp.c
+rd_cred.c
+rd_error.c
+rd_priv.c
+rd_rep.c
+rd_req.c
+rd_req_dec.c
+rd_safe.c
+recvauth.c
+send_tgs.c
+sendauth.c
+ser_actx.c
+ser_addr.c
+ser_adata.c
+ser_auth.c
+ser_cksum.c
+ser_ctx.c
+ser_eblk.c
+ser_key.c
+ser_princ.c
+serialize.c
+srv_rcache.c
+str_conv.c
+t_walk_rtree.c
+t_kerb.c
+t_krb5.conf
+t_ref_kerb.out
+t_ser.c
+tgtname.c
+unparse.c
+v4lifetime.c
+valid_times.c
+walk_rtree.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/krb/ChangeLog b/mechglue/src/lib/krb5/krb/ChangeLog
new file mode 100644
index 000000000..14ef1b566
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ChangeLog
@@ -0,0 +1,3615 @@
+2006-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_deltat): Include support library.
+
+2005-12-30  Tom Yu  <tlyu@mit.edu>
+
+	* gc_frm_kdc.c: Rewrite to modularize significantly.  (~400-line
+	functions do not deserve to live.)  The outer loop no longer
+	explicitly attempts the direct path to the target; that attempt
+	has been folded into the inner loop.  Remove some redundant
+	credential lookups present in the old code.  Treat unexpected
+	realm referrals as soft errors, in case some intermediate KDC
+	disagrees with client regarding a transit path.
+
+2005-12-28  Tom Yu  <tlyu@mit.edu>
+
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Cause free_tgt and
+	free_otgt to track the states of tgt and otgt correctly, to avoid
+	a double-free condition which previously happened when this
+	function returned to krb5_get_credentials(), which proceeded to
+	free a previously freed TGT in the returned TGT list.
+
+2005-10-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_ser): Add dl library and thread link options,
+	since kdb5 library is linked in and needs them.
+
+2005-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* mk_req_ext.c (krb5int_generate_and_save_subkey): Check for and
+	free pre-existing subkeys before clobbering the pointers.  This
+	fixes some memory leaks.
+
+2005-08-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_ser.c (ser_kcontext_test): Remove statement declaring an
+	unused variable using a non-portable gcc extension.
+
+2005-08-15  Tom Yu  <tlyu@mit.edu>
+
+	* get_in_tkt.c (krb5_get_init_creds): Free tempstr on non-error
+	returns from krb5_string_to_deltat() to avoid memory leak.
+
+2005-07-12  Tom Yu  <tlyu@mit.edu>
+
+	* recvauth.c (recvauth_common): Avoid double-free on invalid
+	version string.  Thanks to Magnus Hagander.  Fix for
+	MITKRB5-SA-2005-003 [CAN-2005-1689, VU#623332].
+
+	* unparse.c (krb5_unparse_name_ext): Account for zero-component
+	principal, to avoid single-byte overflow.  Thanks to Daniel
+	Wachdorf.  Part of fix for MITKRB5-SA-2005-002 [CAN-2005-1175,
+	VU#885830].
+
+2005-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_ser.c (ser_data): Don't initialize db serialization code that
+	doesn't exist any more.
+	(ser_kcontext_test): Don't create and destroy databases.
+
+2005-05-19  Sam Hartman  <hartmans@mit.edu>
+
+	* kfree.c (krb5_free_keyblock_contents krb5_free_keyblock):   Make
+	stubs into libk5crypto so that libk5crypto can call these. 
+	* init_keyblock.c (krb5_init_keyblock): As above.
+
+2005-04024  Jeffrey Altman <jaltman@mit.edu>
+
+        * get_creds.c: 
+        the purpose of the krb5_get_credentials call is to 
+        obtain a set of credentials for the caller.  the 
+        krb5_cc_store_cred() call is to optimize performance
+        for future calls.  Ignore any errors, since the credentials
+        are still valid even if we fail to store them in the cache.
+        
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (BISONFLAGS): Drop -v.
+	($(srcdir)/deltat.c): Change to source directory before
+	rebuilding, so path to source tree doesn't get inserted.
+
+	* fwd_tgt.c (NEED_SOCKETS): Don't define.
+	* recvauth.c (NEED_SOCKETS): Don't define.
+	* sendauth.c (NEED_SOCKETS): Don't define.
+
+2005-03-22  Tom Yu  <tlyu@mit.edu>
+
+	* x-deltat.y (wsnum): Add missing semicolon following YYERROR,
+	which was preventing bison-1.75 from producing compilable C
+	output.
+
+	* gic_keytab.c (krb5_get_init_creds_keytab): When calling
+	krb5_get_init_creds() for the second time (with use_master=1),
+	also accept KRB5_REALM_UNKNOWN as a soft error, and use the result
+	from the first call to krb5_get_init_creds().  This can happen
+	when no master KDC is configured.
+
+2005-03-14  Jeffrey Altman <jaltman@mit.edu>
+
+        * Makefile.in: fix maintainer mode since it is not supported on 
+          Windows.
+
+2005-03-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* x-deltat.y (tok_WS): Renamed terminal from "WS", which conflicts
+	with HP-UX 10 header files.  Updated all productions.
+	(mylex): Updated.
+	* Makefile.in ($(srcdir)/deltat.c): Enable dependencies in
+	maintainer mode.
+	* deltat.c: Updated.
+
+2005-02-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (init_common): Delete redundant library
+	initialization call that was run only on UNIX.  Test assertion
+	that krb5_ui_8 really did get a proper 64-bit type.
+
+2005-02-09  Tom Yu  <tlyu@mit.edu>
+
+	* gic_pwd.c (krb5_get_init_creds_password): Fix so empty password
+	string causes prompting and doesn't cause truncation of password
+	to zero characters.
+
+2005-01-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_walk_rtree.c (main): Free context at end to allow searching
+	for memory leaks.
+
+2005-01-17  Jeffrey Altman <jaltman@mit.edu>
+        * unparse.c: krb5_unparse_name, krb5_unparse_name_ext()
+          prevent null pointer dereferencing if either 'name' or 'size'    
+          are NULL.
+
+2005-01-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): More memory leaks
+	fixed as introduced in ticket #2541. Do not rely on knowledge that
+	upon failure from krb5_cc_retrieve_cred, returned credential data
+	is untouched.
+
+2005-01-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* preauth2.c (krb5_do_preauth): Upon error in decoding
+	krb5_type_info{,2}, on failure, do not call krb5_free_type_info
+	with a null pointer.
+
+2005-01-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * cp_key_cnt.c, copy_princ.c:
+          prevent krb5_copy_principal() and krb5_copy_keyblock() from
+          calling malloc(0).  On platforms in which malloc(0) returns   
+          NULL, these functions will return an ENOMEM error the way
+          they were written.  
+
+2005-01-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Free credentials
+	retrieved from ccache before returning.  Based on patch from
+	fumihiko kakuma <kakuma@valinux.co.jp>.
+
+2005-01-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* parse.c (krb5_parse_name): Don't cache the default realm name.
+
+2004-10-26  Tom Yu  <tlyu@mit.edu>
+
+	* mk_req_ext.c (krb5_mk_req_extended): Free keyblock before
+	copying new one in.
+
+2004-10-14  Tom Yu  <tlyu@mit.edu>
+
+	* t_deltat.c (main): Unadorned integer no longer fails now that we
+	default to seconds.
+
+2004-10-13  Alexandra Ellwood  <lxs@mit.edu>
+
+	* deltat.c, x-deltat.y: Default to seconds if no unit is provided.
+
+2004-09-24  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): Include SRCTOP to get patchlevel.h.
+
+	* brand.c: Use patchlevel.h as master version stamp file.
+
+2004-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* rd_cred.c (decrypt_credencdata): Clear and free ppart to avoid
+	leak, reported by Derrick Schommer.
+
+2004-08-31  Tom Yu  <tlyu@mit.edu>
+
+	* rd_rep.c:
+	* send_tgs.c: Fix double-free vulnerabilities.
+
+2004-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_princ.c (krb5_425_conv_principal): Terminate argument list
+	to krb5_build_principal with NULL, not 0.  Patch from Nalin
+	Dahyabhai.
+
+2004-08-12  Alexandra Ellwood  <lxs@mit.edu>
+
+        * get_in_tkt.c (get_init_creds):
+        Support ticket_lifetime libdefault.
+        Made aware of 32 bit min and max for times.
+        Allow renew_until time < expiration time.
+        
+2004-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* srv_rcache.c (krb5_get_server_rcache): Call
+	krb5_rc_recover_or_initialize.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* parse.c (krb5_parse_name): Don't test macintosh.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* str_conv.c (krb5_string_to_timestamp): Use localtime_r if
+	available.
+	(krb5_timestamp_to_string, krb5_timestamp_to_sfstring): Likewise.
+
+	* parse.c (krb5_parse_name): Use assert and abort, not exit.
+
+	* srv_rcache.c (krb5_get_server_rcache): Don't forget to actually
+	include the cache type in the cache name, after looking it up.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (init_common): Don't call krb5_init_ets.
+	(krb5_free_context): Don't call krb5_free_ets.
+
+	* srv_rcache.c (krb5_get_server_rcache): Use krb5_rc_resolve_full
+	instead of constructing an rcache object locally.
+
+2004-05-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* conv_creds.c (krb5int_encode_v4tkt): Unsigned vs signed warning fix.
+
+2004-05-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_ser.c (ser_keytab_test): Cleanup memory leak of forgetting to
+	close keytab.
+
+	* chpw.c: Add parenthesis around assignments in conditionals.
+
+2004-05-12  Jeffrey Altman <jaltman@mit.edu>
+
+    * send_tgs.c: krb5_send_tgs() was broken in the case of a KRB_ERROR
+      message.  The krb5_response message_type field was never set 
+      resulting in stack garbage being used instead.  This would 
+      break code which used transitive cross-realm to obtain service
+      tickets.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_creds.c (krb524_init_ets, krb524_convert_creds_kdc): Add
+	forward declarations to silence gcc warnings.
+
+	* init_ctx.c (init_common): In UNIX case, check the return value
+	from krb5int_initialize_library.
+
+2004-04-16  Sam Hartman  <hartmans@mit.edu>
+
+	* gic_pwd.c (krb5int_populate_gic_opt): Take credentials and
+	populate lifetime options based on them.
+
+	* gic_keytab.c gic_pwd.c :  update callers
+
+2004-04-15  Sam Hartman  <hartmans@mit.edu>
+
+	* gic_pwd.c (krb5_get_init_creds_password): Free the as reply in
+	the !use_master case  (Thanks to Lijian Liu)
+
+2004-03-09  Ken Hornstein <kenh@cmf.nrl.navy.mil>
+
+	* gic_keytab.c (krb5_get_in_tkt_with_keytab): Fix a case I missed
+	originally.
+
+2004-02-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* gic_pwd.c (krb5_get_in_tkt_with_password): Fix a case Jeff
+	missed.
+
+2004-02-26  Jeffrey Altman <jaltman@mit.edu>
+  
+    * get_in_tkt.c, gic_keytab.c, gic_pwd.c, send_tgs.c: 
+      Implement changes to support the use of 
+      krb5_get_init_creds_password's use_master as an in/out
+      parameter.  This allows us to prevent a duplicate request
+      being sent to the KDC in the situation that the password
+      used is incorrect.  This behavior results a negative user
+      experience and had to be corrected.
+
+2004-02-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendauth.c: Don't specify defaults for
+	GET{PEER,SOCK}NAME_ARG{2,3}_TYPE macros.
+
+2004-02-06  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* init_ctx.c (DEFAULT_ETYPE_LIST): Include aes128-cts
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_in_tkt.c (get_in_tkt_enctypes): Now const.
+
+2003-12-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_creds.c (krb5int_encode_v4tkt): Zero out unused parts of
+	ticket.  Use a temorary in case krb5_int32 isn't "int".
+	(decode_v4tkt): Use a temorary in case krb5_int32 isn't "int".
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* mk_req_ext.c (krb5int_generate_and_save_subkey): New function,
+	split out from krb5_mk_req_extended.
+	(krb5_mk_req_extended): Call it.
+	* mk_rep.c (krb5_mk_rep): If KRB5_AUTH_CONTEXT_USE_SUBKEY flag is
+	set, call krb5int_generate_and_save_subkey to set up a new subkey
+	to send to the client.
+
+	* serialize.c (krb5_ser_pack_int64, krb5_ser_unpack_int64): New
+	functions.
+
+2003-10-30  Tom Yu  <tlyu@mit.edu>
+
+	* gen_seqnum.c (krb5_generate_seq_number): Fix mask; was short by
+	4 bits.
+
+2003-10-08  Tom Yu  <tlyu@mit.edu>
+
+	* rd_safe.c (krb5_rd_safe_basic): Save the encoded KRB-SAFE-BODY
+	to avoid trouble caused by re-encoding.  Also, handle correctly
+	implemented RFC 1510 KRB-SAFE, i.e., checksummed over
+	KRB-SAFE-BODY only.
+
+2003-09-02  Tom Yu  <tlyu@mit.edu>
+
+	* conv_creds.c (krb524_convert_creds_plain): Apply patch from
+	Cesar Garcia to fix lifetime computation.
+
+2003-08-19  SamHartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* rd_cred.c (decrypt_credencdata): Don't double free credentials.
+
+2003-08-08  Tom Yu  <tlyu@mit.edu>
+
+	* gic_pwd.c (krb5_get_init_creds_password): If DNS SRV support is
+	turned off, the second call to get_init_creds() will fail with
+	KRB5_REALM_UNKNOWN under certain circumstances.  If that happens,
+	return the error from the first call to get_init_creds(), which
+	will be more useful to the user.
+
+2003-07-22  Sam Hartman  <hartmans@avalanche-breakdown.mit.edu>
+
+	* preauth2.c (krb5_do_preauth): Use the etype_info2 decoder for decoding etype_info2
+	(krb5_do_preauth): If an invalid encoding of etype_info or
+	etype_info2 is received, ignore it rather  than failing the request
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-07-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (STLIBOBJS, OBJS, T_SER_OBJS): Drop ser_eblk.o.
+
+2003-06-03  Alexandra Ellwood  <lxs@mit.edu>
+
+        * init_ctx.c: Export krb5_get_permitted_enctypes for Samba.
+
+2003-06-27  Tom Yu  <tlyu@mit.edu>
+
+	* gic_keytab.c (krb5_get_in_tkt_with_keytab): Pass (void*)keytab,
+	not &keytab, to get_init_creds.  Thanks to Herb Lewis.
+
+2003-06-16  Sam Hartman  <hartmans@mit.edu>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): Set use_conf_ktypes to true while getting the TGT key
+
+2003-06-13  Tom Yu  <tlyu@mit.edu>
+
+	* rd_rep.c (krb5_rd_rep): Free subkeys before replacing them, if
+	needed.  This avoids a memory leak.
+
+2003-06-11  Tom Yu  <tlyu@mit.edu>
+
+	* srv_rcache.c (krb5_get_server_rcache): Octal escapes begin with
+	hyphen now, since backslash is a pathname separator on DOS.
+
+2003-06-06  Sam Hartman  <hartmans@mit.edu>
+
+	* get_in_tkt.c (krb5_get_init_creds): Mask out renewable_ok if the
+	request is for a renewable ticket with rtime greater than till 
+
+2003-06-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* mk_req_ext.c (krb5_generate_authenticator): Sequence numbers are
+	unsigned now.
+
+2003-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_in_tkt.c (krb5_get_init_creds): Change hardcoded default
+	ticket lifetime from 10 hours to 24 hours.
+
+	* init_ctx.c (DEFAULT_KDC_TIMESYNC): Define as 1 always.
+	(DEFAULT_CCACHE_TYPE): Define as 4 always.
+
+2003-05-30  Alexandra Ellwood <lxs@mit.edu>
+
+	* get_in_tkt.c: (verify_as_reply) Only check the renewable lifetime
+	of tickets whose request options included KDC_OPT_RENEWABLE_OK
+	if those options did not also include KDC_OPT_RENEWABLE.   Otherwise 
+	verify_as_reply() will fail for all renewable tickets.
+
+2003-05-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_creds.c: Enable support on Windows always.
+	(krb5_524_convert_creds): Renamed from krb524_convert_creds_kdc.
+	(krb524_convert_creds_kdc, krb524_init_ets) [!_WIN32]: Backwards
+	compatibility functions.
+
+2003-05-27  Sam Hartman  <hartmans@mit.edu>
+
+	* gic_keytab.c (krb5_get_in_tkt_with_keytab): as below
+
+	* gic_pwd.c (krb5_get_in_tkt_with_password): Store client and
+	server principals to avoid memory leak  
+
+2003-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_creds.c: New file, moved from krb524/conv_creds.c and
+	krb524/encode.c.  Rename exported encode routine, make other
+	encode and decode routines static.  If KRB5_KRB4_COMPAT is not
+	defined, return an error.
+	* v4lifetime.c: New file, moved from lib/krb4/lifetime.c.  Renamed
+	functions, changed interface to use krb5 types.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Add them.
+
+2003-05-23  Sam Hartman  <hartmans@mit.edu>
+
+	* get_in_tkt.c (krb5_get_init_creds): Initialize options based on
+	context.kdc_default_options 
+2003-05-22  Tom Yu  <tlyu@mit.edu>
+
+	* gen_seqnum.c (krb5_generate_seq_number): Fix think-o on sequence
+	number mask.
+
+	* auth_con.c (krb5int_auth_con_chkseqnum): New function; implement
+	heuristic for broken Heimdal sequence number encoding.
+	(chk_heimdal_seqnum): Auxiliary function for above.
+
+	* auth_con.h: Add flags for sequence number heuristic.
+
+	* rd_priv.c: Use krb5int_auth_con_chkseqnum.
+
+	* rd_safe.c: Use krb5int_auth_con_chkseqnum.
+
+2003-05-22  Sam Hartman  <hartmans@mit.edu>
+
+	* gic_pwd.c (krb5int_populate_gic_opt): returns void
+
+2003-05-21  Tom Yu  <tlyu@mit.edu>
+
+	* gic_pwd.c (krb5_get_in_tkt_with_password): Set pw0.length
+	correctly if a password is passed in.
+
+2003-05-20  Sam Hartman  <hartmans@mit.edu>
+
+	* get_in_tkt.c: get_in_tkt only supports old (non-etype-info2)
+	enctypes. 
+
+	* Makefile.in (SRCS): Remove in_ktb.c
+
+	* gic_keytab.c (krb5_get_in_tkt_with_keytab): Move from
+	in_tkt_keytab.c and rewrite to use krb5_get_init_creds 
+
+	* gic_pwd.c (krb5_get_in_tkt_with_password): Moved here from
+	in_tkt_pwd.c so it can share code with
+	krb5_get_init_creds_password.  Rewritten to call
+	krb5_get_in_tkt_password 
+
+	* Makefile.in (SRCS): Delete in_tkt_pwd.c
+
+2003-05-18  Tom Yu  <tlyu@mit.edu>
+
+	* auth_con.h: Sequence numbers are now unsigned.
+
+	* gen_seqnum.c (krb5_generate_seq_number): Constrain initial
+	sequence number space to facilitate backwards compatibility.
+
+2003-05-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* ser_ctx.c (krb5_context_internalize): Copy read-in OS context
+	data into krb5_context and free up the newly allocated OS
+	context.
+
+	* chpw.c (krb5int_rd_chpw_rep): Allow new kpasswd error codes up
+	through _INITIAL_FLAG_NEEDED.
+
+2003-05-13  Sam Hartman  <hartmans@mit.edu>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): Try with no specified enctype if
+	forwarding a specific enctype fails. l
+
+	* get_in_tkt.c (krb5_get_init_creds): Free s2kparams
+
+	* preauth2.c (krb5_do_preauth): Fix memory management
+	(pa_salt): Use copy_data_contents
+
+	* copy_data.c (krb5int_copy_data_contents): New function
+
+2003-05-09  Sam Hartman  <hartmans@mit.edu>
+
+	* preauth2.c: Patch from Sun to reorganize code   for handling
+	etype_info requests.  More efficient  and easier to implement etype_info2
+	(krb5_do_preauth): Support enctype_info2
+
+2003-05-08  Sam Hartman  <hartmans@mit.edu>
+
+	* preauth2.c: Add s2kparams to the declaration of a preauth
+	function, to every instance of a preauth function and to every
+	call to gak_fct 
+
+	* get_in_tkt.c (krb5_get_init_creds): Add s2kparams support
+
+	* gic_keytab.c (krb5_get_as_key_keytab): Add s2kparams
+
+	* gic_pwd.c (krb5_get_as_key_password): Add s2kparams support
+
+2003-05-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (init_common): Copy tgs_ktypes array to
+	conf_tgs_ktypes.  Clear use_conf_ktypes.
+	(krb5_free_context): Free conf_tgs_ktypes.
+	(krb5_get_tgs_ktypes): Use use_conf_ktypes to choose between
+	tgs_ktypes and conf_tgs_ktypes.
+
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Set use_conf_ktypes
+	in context to 1 for all operations except the acquisition of the
+	desired service ticket.
+
+2003-05-09  Tom Yu  <tlyu@mit.edu>
+
+	* auth_con.c (krb5_auth_con_setsendsubkey) 
+	(krb5_auth_con_setrecvsubkey, krb5_auth_con_getsendsubkey) 
+	(krb5_auth_con_getrecvsubkey): New functions.  Set or retrieve
+	subkeys from an auth_context.
+	(krb5_auth_con_getlocalsubkey, krb5_auth_con_getremotesubkey):
+	Reimplement in terms of the above.
+
+	* auth_con.h, ser_actx.c: Rename {local,remote}_subkey ->
+	{send,recv}_subkey.
+
+	* chpw.c (krb5int_rd_chpw_rep): Save send_subkey prior to rd_rep;
+	use saved send_subkey to smash recv_subkey obtained from rd_rep.
+
+	* mk_req_ext.c (krb5_mk_req_extended): Rename
+	{local,remote}_subkey -> {send,recv}_subkey.  Set both subkeys if
+	subkey generation is requested.
+
+	* mk_cred.c, mk_priv.c, mk_safe.c: Rename {local,remote}_subkey ->
+	{send,recv}_subkey.  Use either send_subkey or keyblock, in that
+	order.
+
+	* rd_cred.c, rd_priv.c, rd_safe.c: Rename {local,remote}_subkey ->
+	{send,recv}_subkey.  Use either recv_subkey or keyblock, in that
+	order.
+
+	* rd_rep.c (krb5_rd_rep): Rename {local,remote}_subkey ->
+	{send,recv}_subkey.  Set both subkeys if a subkey is present in
+	the AP-REP message.
+
+	* rd_req_dec.c (krb5_rd_req_decoded_opt): Rename
+	{local,remote}_subkey -> {send,recv}_subkey.  Set both subkeys if
+	a subkey is present in the AP-REQ message.
+
+2003-05-06  Sam Hartman  <hartmans@mit.edu>
+
+	* kfree.c (krb5_free_etype_info): Free s2kparams
+
+2003-04-27  Sam Hartman  <hartmans@mit.edu>
+
+	* chpw.c (krb5int_setpw_result_code_string): Make internal 
+
+2003-04-25  Sam Hartman  <hartmans@mit.edu>
+
+	* chpw.c (krb5int_rd_setpw_rep): Fix error handling; allow
+	krberrors to be read correctly; fix memory alloctaion so that
+	allocated structures are freed. 
+
+2003-04-16  Sam Hartman  <hartmans@mit.edu>
+
+	* chpw.c (krb5int_mk_setpw_req): Use encode_krb5_setpw_req.  Fix
+	memory handling to free data that is allocated  
+
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+	* chpw.c (krb5int_mk_setpw_req krb5int_rd_setpw_rep): New function
+
+2003-04-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* kfree.c (krb5_free_pwd_sequences): Correction to previous
+	fix. Free contents of krb5_data - not just the pointer.
+
+2003-04-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* kfree.c (krb5_free_pwd_sequences): Actually free the entire
+	sequence of passwd_phase_elements and not just the first one.
+
+2003-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (DEFAULT_ETYPE_LIST): Add AES with 256 bits at the
+	front of the list.  No 128-bit support by default.
+
+2003-04-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Check principal name
+	length before examining components.
+
+	* parse.c (krb5_parse_name): Double-check principal name length
+	before filling in components.
+
+	* srv_rcache.c (krb5_get_server_rcache): Check for null pointer
+	supplied in place of name.
+
+	* unparse.c (krb5_unparse_name_ext): Don't move buffer pointer
+	backwards if nothing has been put into the buffer yet.
+
+2003-04-01  Sam Hartman  <hartmans@mit.edu>
+
+	* rd_req.c (krb5_rd_req): If AUTH_CONTEXT_DO_TIME is cleared,
+	don't set up a replay cache. 
+
+2003-03-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_kerb.c: Only include krb.h if krb4 support compiled in,
+	otherwise define ANAME_SZ, INST_SZ and REALM_SZ.
+	
+2003-03-06  Tom Yu  <tlyu@mit.edu>
+
+	* preauth2.c (pa_sam_2): Add intermediate size_t variable to hold
+	output of krb5_c_encrypt_length().
+
+2003-03-06  Alexandra Ellwood <lxs@mit.edu>
+
+    * appdefault.c: Fix constness to avoid warning.
+    
+    * init_ctx.c: Do the same stuff on the Mac as on Unix.
+    
+    * preauth2.c: Added cast to fix warning.
+
+2003-03-04  Tom Yu  <tlyu@mit.edu>
+
+	* srv_rcache.c (krb5_get_server_rcache): Fix missed
+	isinvalidrcname -> isvalidrcname.
+
+2003-03-02  Sam Hartman  <hartmans@mit.edu>
+
+	* srv_rcache.c (krb5_get_server_rcache): If punctuation or graphic characters in replay ccache name then use  escaping
+
+	* rd_req.c (krb5_rd_req): Allow initializing the replay cache from  the ticket
+
+2003-02-25  Tom Yu  <tlyu@mit.edu>
+
+	* gic_pwd.c (krb5_get_init_creds_password): Don't pass a NULL
+	pointer to sprintf().
+
+2003-02-14  Sam Hartman  <hartmans@mit.edu>
+
+	* preauth2.c (krb5_do_preauth): Sort incoming etype info based on
+	preference order in request  
+
+2003-02-13  Sam Hartman  <hartmans@mit.edu>
+
+	* gic_keytab.c (krb5_get_as_key_keytab): Nathan Neulinger points
+	out that  the AS key is double freed; fix.
+
+2003-02-11  Sam Hartman  <hartmans@mit.edu>
+
+	* rd_cred.c (krb5_rd_cred): Free creds using krb5_free_tgt_creds
+	and make sure they are set to null in case of  error.
+
+2003-02-07  Sam Hartman  <hartmans@mit.edu>
+
+	* rd_cred.c (krb5_rd_cred): Allow the tickets to be encrypted the
+	session key as well as the  subsession key; for GSSAPI this tends
+	to be what happens.
+
+2003-02-04  Sam Hartman  <hartmans@mit.edu>
+
+	* get_in_tkt.c (krb5_get_init_creds): Default to addressless tickets
+
+2003-01-12  Ezra Peisach  <epeisach@bu.edu>
+
+	* send_tgs.c (krb5_send_tgs): Free memory leak of TGS_REQ.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-09  Sam Hartman  <hartmans@mit.edu>
+
+	* get_creds.c (krb5_get_credentials_core): Patch from Ben Cox
+	<cox-work@djehuti.com> to not use expired service credentials if
+	the endtime is null but instead to search for unexpired
+	credentials.  If none are found, get new credentials.
+	
+
+2003-01-08  Sam Hartman  <hartmans@mit.edu>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): Don't require hostname to be supplied unless you are using addresses in the ticket.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* appdefault.c (conf_yes, conf_no): Now const.
+
+2003-01-07  Sam Hartman  <hartmans@mit.edu>
+
+	* mk_req_ext.c (krb5_mk_req_extended): Fix logic error in checksum function handling
+	(krb5_mk_req_extended): For consistency with Microsoft, never use a subkey before calling the checksum callback
+
+2003-01-06  Sam Hartman  <hartmans@mit.edu>
+
+	* mk_req_ext.c (krb5_mk_req_extended): Inf no in_data is provided
+	but krb5_auth_con_set_checksum_func has been called, then use that
+	callback to generate the in_data.
+
+	* auth_con.c (krb5_auth_con_init): Initialize checksum_func fields
+	(krb5_auth_con_set_checksum_func):  new function-- set the mk_req
+	checksum function 
+	(krb5_auth_con_get_checksum_func): return the same
+
+	* auth_con.h: Add checksum_func and checksum_func_data
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* t_kerb.c: Include string.h for strcmp prototype.
+
+2002-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_princ.c (krb5_524_conv_principal): Clean up use of "const"
+	in API.
+
+2002-11-14  Ezra Peisach  <epeisach@bu.edu>
+
+	* get_in_tkt.c (krb5_get_in_tkt): Do not pass NULL when an
+	integer 0 is intended to send_as_request().
+
+2002-11-07  Ezra Peisach  <epeisach@bu.edu>
+
+	* conv_princ.c (strnchr): Make length argument unsigned int.
+
+	* preauth2.c: Add parentheses around assignment used as truth
+	value. Cleanup unused variable.
+
+
+2002-10-30  Tom Yu  <tlyu@mit.edu>
+
+	* chk_trans.c (krb5_check_transited_list): Style nit: check
+	character against '\0' not NULL.
+
+2002-10-30  Sam Hartman  <hartmans@mit.edu>
+
+	* chk_trans.c: Ignore trailing null in transited  encoding; older
+	versions  of MIT code included this.
+
+2002-10-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_in_tkt.c (conf_yes, conf_no): Now const.  References
+	updated.
+	* preauth.c (preauth_systems): Now const.  References updated.
+	* preauth2.c (pa_types): Now const.
+	(krb5_do_preauth): Local array paorder now const.
+
+2002-10-28  Sam Hartman  <hartmans@mit.edu>
+
+	* gic_keytab.c (krb5_get_init_creds_keytab): Don't allow failure
+	to  resolve master KDC to mask error from a slave we did talk to. 
+
+2002-10-24  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* gic_pwd.c (krb5_get_init_creds_password): Exit out of the loop
+	when preauth fails.
+
+	* kfree.c: Add various free functions for new preauth
+	data structures.
+
+	* preauth2.c (pa_sam): Fix up support for "old" hardware preauth.
+	Also implement new hardware preauth in pa_sam2().
+
+2002-10-23  Ken Hornstein  <kenh@cmf.nrl.navy.mil>
+
+	* gic_pwd.c (krb5_get_init_creds_password): Fix bug in previous
+	password expiration warning; also, check for password expiration
+	warnings via LRQ type from krb-clarifications.
+
+2002-09-11  Sam Hartman  <hartmans@mit.edu>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds):  If our initial tickets don't
+	have addresses, neither should forwarded tickets.  Also, noticed
+	that cc was being used before initialized in some cases; fixed.
+
+2002-09-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* addr_comp.c, addr_order.c, addr_srch.c, appdefault.c,
+	auth_con.c, bld_princ.c, chpw.c, cleanup.h, conv_princ.c,
+	copy_addrs.c, copy_athctr.c, copy_auth.c, copy_cksum.c,
+	copy_creds.c, copy_data.c, copy_key.c, copy_princ.c, copy_tick.c,
+	cp_key_cnt.c, decode_kdc.c, decrypt_tk.c, enc_helper.c,
+	encode_kdc.c, encrypt_tk.c, free_rtree.c, fwd_tgt.c, gc_frm_kdc.c,
+	gc_via_tkt.c, gen_seqnum.c, gen_subkey.c, get_creds.c,
+	get_in_tkt.c, gic_keytab.c, gic_opt.c, gic_pwd.c, in_tkt_ktb.c,
+	in_tkt_pwd.c, in_tkt_sky.c, init_ctx.c, kdc_rep_dc.c, kfree.c,
+	mk_cred.c, mk_error.c, mk_priv.c, mk_rep.c, mk_req.c,
+	mk_req_ext.c, mk_safe.c, parse.c, pr_to_salt.c, preauth.c,
+	preauth2.c, princ_comp.c, rd_cred.c, rd_error.c, rd_priv.c,
+	rd_rep.c, rd_req.c, rd_req_dec.c, rd_safe.c, recvauth.c,
+	send_tgs.c, sendauth.c, ser_actx.c, ser_adata.c, ser_addr.c,
+	ser_auth.c, ser_cksum.c, ser_ctx.c, ser_key.c, ser_princ.c,
+	serialize.c, set_realm.c, srv_rcache.c, str_conv.c, t_deltat.c,
+	t_kerb.c, t_ser.c, t_walk_rtree.c, tgtname.c, unparse.c,
+	valid_times.c, vfy_increds.c, vic_opt.c, walk_rtree.c,
+	x-deltat.y: Use prototype style function definitions.
+	* deltat.c: Regenerated.
+	* bld_princ.c: Include stdarg.h before k5-int.h.
+	* cleanup.h (struct cleanup): Include prototype for function
+	pointer field 'func'.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (init_common): Initialize udp_pref_limit field.
+
+2002-08-15  Tom Yu  <tlyu@mit.edu>
+
+	* t_ser.c (ser_ccache_test): Remove references to STDIO ccaches.
+
+2002-08-01  Tom Yu  <tlyu@mit.edu>
+
+	* unparse.c (krb5_unparse_name_ext): Error out if passed a NULL
+	pointer.  Patch from Mark Levinson; fixes [krb5-admin/1140].
+
+2002-06-26  Ezra Peisach  <epeisach@bu.edu>
+
+	* appdefault.c (conf_boolean): Change variable from char ** to
+	const char ** to prevent warning of const to non-const.
+	
+	* get_in_tkt.c (_krb5_conf_boolean): Same
+
+2002-06-25  Alexandra Ellwood <lxs@mit.edu>
+
+	* appdefault.c, get_in_tkt.c: made conf_yes and conf_no const to 
+	improve load time on Mach-O
+
+	* init_ctx: fixed Mac OS macros
+
+	[pullups from 1-2-2-branch]
+
+2001-06-25  Miro Jurisic  <meeroh@mit.edu>
+
+	* rd_safe.c, rd_priv.c, rd_cred.c, preauth.c, mk_safe.c,
+	mk_cred.c, appdefault.c: use "" includes for krb5.h, k5-int.h and
+	syslog.h
+	[pullup from 1-2-2-branch]
+
+2002-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendauth.c (ECONNABORTED): Don't define here now that it's
+	defined in port-sockets.h.
+
+2002-06-18  Danilo Almeida  <dalmeida@mit.edu>
+
+	* princ_comp.c (krb5_realm_compare), auth_con.c
+	(krb5_auth_con_setports, krb5_auth_con_getaddrs,
+	krb5_auth_con_initivector), addr_order.c (krb5_address_order),
+	addr_comp.c (krb5_address_compare): Make KRB5_CALLCONV.
+	[pullup from 1-2-2-branch]
+
+2002-06-18  Danilo Almeida  <dalmeida@mit.edu>
+
+	* bld_princ.c (krb5_build_principal_va): Make
+	krb5_build_principal_va() KRB5_CALLCONV.
+	[pullup from 1-2-2-branch]
+
+2002-06-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* preauth.c: Don't include syslog.h.
+
+2002-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_in_tkt.c (send_as_request): Update arg list for
+	sendto_kdc.  If a RESPONSE_TOO_BIG error is returned from the KDC,
+	use a TCP connection.
+	* send_tgs.c (krb5_send_tgs): Update arg list for sendto_kdc.  If
+	a RESPONSE_TOO_BIG error is returned from the KDC, use a TCP
+	connection.
+
+2002-04-12  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (clean): Remove t_expand and t_expand.o
+
+2002-04-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_princ.c (struct krb_convert): Add new field 'len'.
+	(RC, R, NR): New macros.
+	(sconv_list): Use them.
+	(krb5_524_conv_principal): Compare lengths and then use memcmp.
+
+	* recvauth.c (sendauth_version): Now a const array.
+	* sendauth.c (sendauth_version): Now a const array.
+	(krb5_sendauth): Cast address when assigning to outbuf data
+	field.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* decrypt_tk.c (krb5_decrypt_tkt_part): Call krb5_c_valid_enctype
+	instead of valid_enctype.
+	* encode_kdc.c (krb5_encode_kdc_rep): Likewise.
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Likewise.
+	* gic_keytab.c (krb5_get_as_key_keytab): Likewise.
+	* in_tkt_ktb.c (keytab_keyproc): Likewise.
+	* in_tkt_sky.c (skey_keyproc): Likewise.
+	* init_ctx.c (krb5_set_default_in_tkt_ktypes,
+	krb5_set_default_tgs_enctypes): Likewise.
+	* send_tgs.c (krb5_send_tgs): Likewise.
+
+	* mk_safe.c (krb5_mk_safe_basic): Call krb5_c_valid_cksumtype,
+	krb5_c_is_coll_proof_cksum, krb5_c_is_keyed_cksum instead of
+	non-prefixed forms.
+	* rd_safe.c (krb5_rd_safe_basic): Likewise.
+
+2002-03-28  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in :  New file init_keyblock.c
+
+	* init_keyblock.c (krb5_init_keyblock): New function
+
+2002-03-16  Sam Hartman  <hartmans@mit.edu>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): Fix merge of patch from 1.2.2
+	back to mainline. 
+
+2002-03-14  Sam Hartman  <hartmans@mit.edu>
+
+	* walk_rtree.c (krb5_walk_realm_tree):  Fix handling of null client or server realm
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* ser_actx.c (krb5_auth_context_externalize): Do bounds checking
+	on converted size value.
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): If no session key has been set,
+	try getting credentials and use the session key type as a hint
+	for the enctype to use for the forwarded credentials.
+
+2002-02-27  Sam Hartman  <hartmans@mit.edu>
+
+	* rd_cred.c (krb5_rd_cred_basic): Don't check IP addresses; if
+	someone knows the key and wants to give us credentials, that's OK.
+	No reflection attack is possible in most protocols since  krb_cred
+	is almost always client->server.  Address checking created
+	significant problems for NATs.    We also ran into problems
+	getting our code to work with Heimdal  and removing checking was
+	easier than a staged upgrade to fix the problems.
+	(krb5_rd_cred): Don't pass in addresses
+
+2002-02-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* addr_comp.c, addr_order.c, addr_srch.c, bld_pr_ext.c,
+	bld_princ.c, enc_helper.c, encrypt_tk.c, gen_seqnum.c,
+	gen_subkey.c, preauth.c: Use const instead of krb5_const.
+	* bld_pr_ext.c, bld_princ.c: Always use stdarg macros and not
+	varargs.
+
+2002-01-08  Sam Hartman  <hartmans@mit.edu>
+
+	* gen_subkey.c (krb5_generate_subkey): Label entropy sources
+
+	* init_ctx.c (init_common): Use /dev/urandom if present for random data
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_ser.c (main): Free context on failure exit route.
+
+ 2001-11-24  Sam Hartman  <hartmans@mit.edu>
+ 
+ 	* fwd_tgt.c (krb5_fwd_tgt_creds): Get a session key for the
+ 	forwarded tgt that is the same as the  session key for  the
+ 	auth_context.  This  is an enctype we know the remote side
+ 	supports.  
+ 
+2001-11-26  Sam Hartman  <hartmans@mit.edu>
+
+	* gen_seqnum.c (krb5_generate_seq_number):  add entropy source id
+
+	* sendauth.c (krb5_sendauth): Add entropy source ID
+
+	* mk_req_ext.c (krb5_mk_req_extended):  Add entropy source ID to random seed call
+
+	* init_ctx.c (init_common): Specify entropy source for random seed
+
+2001-11-16  Sam Hartman  <hartmans@mit.edu>
+
+	* init_ctx.c (krb5_set_default_tgs_enctypes):  rename from
+	set_default_ktypes; old function provided as APIA 
+
+2001-11-16  Ezra Peisach  <epeisach@mit.edu>
+
+	* init_ctx.c (DEFAULT_ETYPE_LIST): Ensure space present after
+	arcfour-hmac-md5 entry for when ANSI strings concatenated the
+	des-cbc-crc entry was dropped.
+
+2001-11-07  Sam Hartman  <hartmans@mit.edu>
+
+	* init_ctx.c (DEFAULT_ETYPE_LIST): Add arcfour-hmac-md5; it really
+	is probably at least as good as DES 
+
+2001-10-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* gic_pwd.c (krb5_get_as_key_password),
+	gic_keytab.c (krb5_get_as_key_keytab): Use ANSI-style
+	declaration in definition.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (init_common): After fetching kdc_default_options
+	value from krb5.conf, actually use that value.  Pointed out by
+	Emily Ratliff, <ratliff@austin.ibm.com>.
+
+	* get_in_tkt.c, in_tkt_ktb.c, in_tkt_pwd.c, in_tkt_sky.c,
+	int-proto.h, mk_req_ext.c, pr_to_salt.c, rd_req_dec.c, ser_actx.c,
+	ser_adata.c, ser_addr.c, ser_auth.c, ser_cksum.c, ser_ctx.c,
+	ser_eblk.c, ser_key.c, ser_princ.c, t_kerb.c: Make prototypes
+	unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c, preauth.c: Drop _MSDOS support.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* appdefault.c, auth_con.c, bld_pr_ext.c, bld_princ.c, chpw.c,
+	conv_princ.c, copy_addrs.c, copy_athctr.c, copy_auth.c,
+	copy_cksum.c, copy_creds.c, copy_data.c, copy_key.c, copy_princ.c,
+	copy_tick.c, cp_key_cnt.c, decrypt_tk.c, fwd_tgt.c, get_creds.c,
+	get_in_tkt.c, gic_keytab.c, gic_opt.c, gic_pwd.c, in_tkt_ktb.c,
+	in_tkt_pwd.c, in_tkt_sky.c, init_ctx.c, kfree.c, mk_cred.c,
+	mk_error.c, mk_priv.c, mk_rep.c, mk_req.c, mk_req_ext.c,
+	mk_safe.c, parse.c, princ_comp.c, rd_cred.c, rd_error.c,
+	rd_priv.c, rd_rep.c, rd_req.c, rd_safe.c, recvauth.c, sendauth.c,
+	ser_actx.c, ser_ctx.c, serialize.c, set_realm.c, srv_rcache.c,
+	str_conv.c, unparse.c, vfy_increds.c, vic_opt.c, x-deltat.y: Don't
+	use KRB5_DLLIMP.  Don't explicitly declare pointers FAR any more.
+
+2001-09-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_expand.c: New file.
+	* Makefile.in (SRCS): Add test-case source files; rebuilt
+	dependencies.
+	(t_expand.o): Build from t_expand.c now, no special build rule.
+
+2001-09-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* rd_req_dec.c (krb5_rd_req_decoded_opt): Pass server realm to
+	transited-list check, not local realm, in case they're different.
+
+2001-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* walk_rtree.c (krb5_walk_realm_tree): Initialize slen to silence
+	compiler warning.
+
+2001-08-08    <epeisach@mit.edu>
+
+	* walk_rtree.c (krb5_walk_realm_tree): Do not try to free const char *.
+
+	* mk_safe.c (krb5_mk_safe_basic): Do not declare local_addr and
+	remote_addr const and then cast the attribute away.
+
+	* mk_req_ext.c (krb5_generate_authenticator): Static function -
+	remove const attribute from cksum pointer.
+
+	* gc_via_tkt.c (krb5_get_cred_via_tkt): Cast unsigned integer
+	krb5_error error_value to signed before adding
+	ERROR_TABLE_BASE_krb5.
+
+2001-07-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* chk_trans.c (krb5_check_transited_list): Pointer args now point
+	to const.
+
+2001-07-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* get_in_tkt.c: Cast to unsigned krb5_error error value to 
+	krb5_error_code before trying to add to ERROR_TABLE_BASE_krb5. 
+
+2001-07-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* sendauth.c (krb5_sendauth): Instead of casting second argument
+	to getpeername() and getsockname() to "struct sockaddr *", cast to
+	system specific type as determined by autoconf. 
+
+2001-07-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* in_tkt_sky.c (krb5_get_in_tkt_with_skey): Change cast from
+ 	krb5_pointer to krb5_const_pointer to ensure const integrity of
+ 	parameter.
+
+	* in_tkt_ktb.c (keytab_keyproc): Add const argument to cast of
+ 	keyseed to struct keytab_keyproc_arg to maintain const status.
+
+	* conv_princ.c (krb5_524_conv_principal): Cast argument to memcpy
+ 	to size_t.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* conv_princ.c (krb5_425_conv_principal): Cast argument to tolower
+	to int.
+
+	* get_in_tkt.c: Include os-proto.h for _krb5_conf_boolean prototype.
+
+	* Makefile.in (LOCALINCLUDES): Add -I$(srcdir)/../os so os-proto.h
+	can be included.
+
+2001-06-29  Tom Yu  <tlyu@mit.edu>
+
+	* init_ctx.c (get_profile_etype_list): Fix etype-counting loop so
+	that trailing separator characters (as in the DEFAULT_ETYPE_LIST)
+	don't cause another iteration, which was causing the following
+	loop to fall off the end of the string due to count being one too
+	great.
+
+2001-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* chk_trans.c (foreach_realm): Cleanup loal variable set but never
+	used.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* chk_trans.c: Cast length arguments of %.*s in formats to int.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (check-unix): Add $(RUN_SETUP) before invocation of
+	transit-tests for shared library environment variables.
+
+2001-06-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* chk_trans.c: Reimplemented from scratch.
+	* transit-tests: New file.
+	* Makefile.in (t_expand, t_expand.o): New targets.  Build test
+	program from chk_trans.c.
+	(T_EXPAND_OBJS): New variable.
+	(TEST_PROGS): Add t_expand.
+	(check-unix): Run transit-tests.
+	* t_krb5.conf: Added capaths section.
+
+2001-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): Copy enctype for new creds from
+	tgt.
+
+2001-06-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (t_walk_rtree, t_kerb): Do not link against kdb libraries
+	for these test executables. 
+
+	* srv_rcache.c (krb5_get_server_rcache): Cast argument to
+	isgraph() to int.
+
+	* init_ctx.c: Cast arguments to isspace() to int. If unix is defined, 
+	include ../krb5_libinit.h. There has to be a better was for windows.
+
+	* conv_princ.c (krb5_425_conv_principal): Cast argument to isupper().
+	to int.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* str_conv.c: If strptime() is present on system without a
+	prototype, provide one.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* vfy_increds.c (krb5_verify_init_creds): Get rid of a variable
+	that was set in a conditional and never used afterwards.
+
+2001-06-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (get_profile_etype_list): Zero out multiple separator
+	characters between tokens, so the second can be recognized
+	properly.
+
+2001-04-04  Tom Yu  <tlyu@mit.edu>
+
+	* mk_safe.c (krb5_mk_safe): Only use safe_cksumtype from the
+	auth_context (derived from the config file or hardcoded default)
+	if it's suitable for the enctype of the key we're going to
+	use. [pullup from krb5-1-2-2-branch]
+
+2001-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (DEFAULT_ETYPE_LIST): New macro.  Old etype list,
+	plus des-md4, with des-crc before des-mdX for now.
+	(get_profile_etype_list): Use DEFAULT_ETYPE_LIST.
+
+2001-03-10  Ezra Peisach  <epeisach@mit.edu>
+
+	* init_ctx.c: Provide a full prototype for init_common().
+
+	* recvauth.c (recvauth_common): Declare recvauth_common as static. 
+
+	* parse.c, sendauth.c: Changes to prevent shadowing of local
+	variables.
+
+	* get_in_tkt.c, tgtname.c: Include int-proto.h for prototypes.
+
+2001-03-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* preauth2.c (pa_sam): Return an error if no prompter was
+	provided.
+
+2001-02-15  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_deltat.c (main): Test of overflow and underflow of krb5_int32. 
+
+	* x-deltat.y: Test for over/underflow of krb5_int32 for a
+	krb5_deltat. Return EINVAL. [krb5-libs/922]
+
+	* deltat.c: Regenerated from x-deltat.y
+
+	* str_conv.c (krb5_string_to_timestamp): Do not accept a time
+	format that only partially matches the input string. [krb5-lib/922]
+
+2001-01-30  Tom Yu  <tlyu@mit.edu>
+
+	* preauth.c (krb5_obtain_padata): Don't dereference a NULL pointer
+	if we receive an empty ETYPE_INFO preauth. [krb5-libs/903 from
+	craziboy77@hotmail.com]
+
+	* preauth2.c (krb5_do_preauth): Don't dereference a NULL pointer
+	if we receive an empty ETYPE_INFO preauth. [krb5-libs/903 from
+	craziboy77@hotmail.com]
+
+2001-01-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* rd_req_dec.c (krb5_rd_req_decrypt_tkt_part): Free
+	krb5_keytab_entry if call to krb5_decrypt_tkt_part()
+	fails. [krb5-libs/855 reported by guy@packeteer.com]
+
+2001-01-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* preauth.c: Don't use PROTOTYPE macro, just always use the
+	prototypes.
+
+2001-01-19  Tom Yu  <tlyu@mit.edu>
+
+	* preauth.c: Remove uses of KRB5_NPROTOTYPE() macro.
+
+2000-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_ser.c: Cast getpid() calls to int as arguments to sprintf.
+
+	* ser_actx.c: Move prototypes (listed below) to int-proto.h
+
+	* int-proto.h: Add prototypes for krb5_ser_authdata_init,
+	krb5_ser_address_init, krb5_ser_authenticator_init,
+	krb5_ser_checksum_init, krb5_ser_keyblock_init,
+	krb5_ser_principal_init.
+	
+	* ser_adata.c, ser_addr.c, ser_auth.c, ser_cksum.c, ser_key.c,
+	ser_princ.c: Include int-proto.h for prototypes.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* bld_pr_ext.c, bld_princ.c (krb5_build_principal_ext,
+	krb5_build_principal_va, krb5_build_principal): Take an unsigned
+	int realm length.
+
+	* get_in_tkt.c (krb5_get_init_creds): Use SALT_TYPE_AFS_LENGTH
+	instead of -1.
+
+	* gic_pwd.c (krb5_get_as_key_password): Use SALT_TYPE_AFS_LENGTH
+	instead of -1.
+
+	* in_tkt_pwd.c (pwd_keyproc): Argument to krb5_read_password is
+	unsigned int.
+
+	* pr_to_salt.c (krb5_principal2salt_internal): Declare as
+	static. Unsigned int fix.
+
+	* preauth.c (krb5_obtain_padata): Use SALT_TYPE_AFS_LENGTH instead
+	of -1.
+
+	* preauth2.c (pa_salt): Use SALT_TYPE_AFS_LENGTH instead of -1. 
+
+	* conv_princ.c, copy_auth.c, copy_princ.c, gc_frm_kdc.c, parse.c,
+	send_tgs.c, srv_rcache.c: Unsigned/signed int cleanup.
+
+	* unparse.c (krb5_unparse_name_ext): size parameter changed to
+	unsigned int *.
+
+2000-10-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* rd_req_dec.c (krb5_rd_req_decrypt_tkt_part): Fix memory leak if
+	krb5_decrypt_tkt_part() fails. [krb5-libs/855]
+
+2000-10-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* srv_rcache.c (krb5_get_server_rcache): Signed vs unsigned int
+	warning fix.
+
+	* pr_to_salt.c (krb5_principal2salt_internal): Add prototype for
+	internal function, and declare static.
+
+	* copy_addrs.c (krb5_copy_addresses): Cleanup unsigned vs signed
+	warnings as arguments to malloc().
+
+Tue Sep 26 13:00:54 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* conv_princ.c (krb5_425_conv_principal): Call profile_free_list
+ 	on v4realms during the iteration loop. Do not call
+ 	profile_release_string with a NULL pointer.
+
+2000-09-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_kerb.c: Add prototypes for test functions.
+
+2000-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_creds.c (krb5_get_credentials_core): If the supplied enctype
+	is not supported, return an error; can't satisfy both
+	TC_SUPPORTED_KTYPES and TC_MATCH_KTYPE that way.  Delete unused
+	arguments CCACHE and OUT_CREDS; fix callers.
+
+2000-07-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* vfy_increds.c: include int-proto.h for krb5_libdefault_boolean
+	prototype.
+
+	* t_ser.c (ser_eblock_test): ifdef out old eblock serialization
+	test which is no longer called. (see 1999-09-01 ChangeLog)
+
+	* t_kerb.c: Cast argument to fprintf to long to agree with format
+	string.
+
+	* t_deltat.c: If MIN is defined, undef before redefined as 60.
+
+	* str_conv.c: Provide strptime prototype if the system header
+	files fail to provide a prototype.
+
+	* int-proto.h:  Add prototype for krb5_libdefault_boolean()
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* conv_princ.c (krb5_425_conv_principal): NULL, not nil.
+
+2000-06-30  Miro Jurisic  <meeroh@mit.edu>
+
+	* conv_princ.c (krb5_425_conv_principal): Fixed a memory leak
+
+2000-06-29  Ezra Peisach  <epeisach@engrailed.mit.edu>
+
+	* t_walk_rtree.c (main): Declare as returning int.
+
+	* get_in_tkt.c (_krb5_conf_boolean): Declare as taking a const char *
+
+	* str_conv.c (krb5_timestamp_to_string): Work around gcc's warning
+	that %c format in strftime might return only two digits for the
+	year.
+
+	* mk_safe.c, rd_rep.c, send_tgs.c: Remove unused goto label.
+
+	* kdc_rep_dc.c (krb5_kdc_rep_decrypt_proc): Remove code with no
+	effect.
+
+	* init_ctx.c: Make krb5_brand[] look used.
+
+	* chpw.c, decode_kdc.c, decrypt_tk.c, enc_helper.c, get_creds.c,
+	get_in_tkt.c, gic_keytab.c, gic_pwd.c, preauth2.c, vfy_increds.c:
+	Add parentheses around assignment used as truth value
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* conv_princ.c, get_creds.c, get_in_tkt.c, mk_rep.c, parse.c,
+	send_tgs.c: Remove unused variable.
+
+2000-06-23  Miro Jurisic  <meeroh@mit.edu>
+
+	* conv_princ.c (krb5_425_conv_principal): Fixed v4->v5 realm
+	name conversion
+
+	* conv_princ.c (krb5_425_conv_principal): Honor v4/v5 realm name
+	differences when convertion from v4 principals to v5.
+
+2000-06-23  Tom Yu  <tlyu@mit.edu>
+
+	* get_creds.c (krb5_get_credentials): Translate KRB5_CC_NOTFOUND
+	returned from krb5_get_cred_from_kdc() if a prior call to
+	krb5_cc_retrieve_cred() returned KRB5_CC_NOT_KTYPE.
+
+	* rd_priv.c (krb5_rd_priv_basic): Delete code that was incorrectly
+	doing explicit ivec chaining; c_decrypt() does it now.
+
+	* mk_priv.c (krb5_mk_priv_basic): Delete code that was incorrectly
+	doing explicit ivec chaining; c_encrypt() does it now.
+
+	* conv_princ.c (krb5_524_conv_principal): Make a copy of the krb5
+	realm that is nul-terminated to avoid falling off the end of the
+	krb5 realm, which is not necessarily nul-terminated.
+
+2000-06-23  Danilo Almeida  <dalmeida@mit.edu>
+
+	* init_ctx.c (krb5_get_tgs_ktypes, krb5_free_ktypes): Fix linkage to
+	be KRB5_CALLCONV.
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_in_tkt.c (krb5_get_in_tkt): If enctypes are specified, send
+	the server the intersection of that list and the supported types,
+	in the order requested.
+
+	* recvauth.c (krb5_recvauth_version): New routine, takes a
+	krb5_data in which to store the client's application version
+	string.
+	(recvauth_common): Renamed from krb5_recvauth, added above
+	functionality depending on extra argument values.
+	(krb5_recvauth): New stub, calls above routine with extra dummy
+	values.
+
+	* kfree.c: Remove unneeded "return" statements at the end of many
+	functions.
+	(krb5_free_*_content, krb5_free_*_contents,
+	krb5_free_cred_enc_part, krb5_free_pwd_sequences): Set freed
+	pointer members to null when containing structure isn't being
+	freed.
+
+	* t_kerb.c (test_524_conv_principal): New test code, to exercise
+	bbense's code addition.
+	(main, usage): Updated.
+	* t_krb5.conf: Added stanford.edu->IR.STANFORD.EDU mapping, and a
+	test case for improperly long v4 realm names.
+	* Makefile.in (check-unix): Run 524 conversion test for some test
+	Athena and Stanford names.
+	* t_ref_kerb.out: Updated.
+
+	* init_ctx.c (init_common): Feed current-microsecond time and
+	process-id into PRNG, instead of just current-second time.
+	* mk_req_ext.c (krb5_mk_req_extended): Feed current time into
+	PRNG if a subkey will be generated.
+	* sendauth.c (krb5_sendauth): Feed local and remote addresses of
+	socket, if they can be determined, into the PRNG if a subkey will
+	be used.
+
+	* init_ctx.c (krb5_free_ktypes): New routine, to free values
+	returned by krb5_get_tgs_ktypes, krb5_get_permitted_enctypes, and
+	krb5_get_default_in_tkt_ktypes.
+	(krb5_set_default_tgs_ktypes, krb5_is_permitted_enctype): Use it.
+	(get_profile_etype_list): Use passed-in enctype list if the
+	passed-in count is non-zero, instead of checking the
+	in_tkt_ktype_count value in the context.
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+            Nalin Dahyabhai  <nalin@redhat.com>
+
+	* conv_princ.c (krb5_524_conv_principal): Return an error if name
+	is too long.  Use memcpy for character data since we already know
+	the length.
+
+2000-06-23  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kfree.c (krb5_free_keyblock_contents): Set contents pointer to
+	null after freeing.
+
+	* chk_trans.c (krb5_check_transited_list): Don't overflow buffers
+	"prev" and "next".
+	* conv_princ.c (krb5_425_conv_principal): Don't overflow buffer
+	"buf".
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+	    Booker C. Bense  <bbense@networking.stanford.edu>
+
+	* conv_princ.c (krb5_524_conv_principal): Look up v4_realm in
+	config file, in case site's krb4 realm name isn't the same as the
+	krb5 realm name.
+
+2000-05-31  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* fwd_tgt.c: Check for existance of <memory.h>.
+	[from Nathan Neulinger <nneul@umr.edu>]
+
+2000-5-19	Alexandra Ellwood <lxs@mit.edu>
+
+	* sendauth.c, fwd_tgt.c: Changed to use krb5int_cc_default.  This function 
+	supports the Kerberos Login Library and pops up a dialog if the cache does 
+	not contain valid tickets.  This is used to automatically get a tgt before
+	obtaining service tickets.  Note that this should be an internal function
+	because callers don't expect krb5_cc_default to pop up a dialog!
+	(We found this out the hard way :-)
+
+2000-05-15      Jeffrey Altman          <jaltman@columbia.edu>
+
+        * Added new source file appdefault.c
+          Implements new public functions
+
+               krb5_appdefault_string
+               krb5_appdefault_boolean
+
+2000-04-28	Alexandra Ellwood	<lxs@mit.edu>
+
+	* gic_pwd.c (krb5_init_creds_password) added code to return to
+	login library if the password is expired (login library handles
+	this error appropriately).
+
+2000-04-08  Tom Yu  <tlyu@mit.edu>
+
+	* vfy_increds.c (krb5_verify_init_creds): appdefault_boolean ->
+	libdefault_boolean; it somehow got missed earlier.
+
+2000-04-07  Jeffrey Altman  <jaltman@columbia.edu>
+
+	* gic_pwd.c (krb5_get_init_creds_keytab), gic_pwd.c
+	(krb5_get_init_creds_password) when determining whether or not to
+	retry with a "master kdc" do not retry if the return value from
+	the first attempt was KRB5_REALM_CANT_RESOLV.  Also, do not
+	overwrite the return code if the return value from the access to
+	the "master kdc" was KRB5_REALM_CANT_RESOLV.
+
+2000-03-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* init_ctx.c (init_common), gic_pwd.c (krb5_get_as_key_password,
+	krb5_get_init_creds_password), preauth2.c (pa_sam): Add support
+	for krb5_get_prompt_types().
+
+2000-03-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* preauth2.c (pa_function): Called function now takes new
+	krb5_enctype pointer argument.
+	(pa_salt, pa_sam): Accept new arg, ignore it.
+	(pa_enc_timestamp): Accept new arg.  If value pointed to is
+	nonzero, pass it to get-AS-key fn instead of first requested
+	enctype.  Added some debugging fprintf calls, conditionally
+	compiled.
+	(krb5_do_preauth): Accept new arg, and pass it through to the
+	specific preauth functions.  Added some debugging fprintf calls,
+	conditionally compiled.
+
+	* get_in_tkt.c (krb5_get_init_creds): Pass etype pointer to
+	krb5_do_preauth.
+
+2000-03-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* addr_comp.c, addr_order.c, addr_srch.c, bld_pr_ext.c,
+	bld_princ.c, encrypt_tk.c, gen_seqnum.c, gen_subkey.c: Change
+	prototypes to use krb5_const instead of const to match the entries
+	in krb5.hin
+
+2000-03-10  Miro Jurisic  <meeroh@mit.edu>
+
+	* get_in_tkt.c (krb5_get_init_creds): Always initialize local_as_reply
+	to avoid returning garbage on error returns.
+
+2000-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* preauth2.c (krb5_do_preauth): Check paorder[h] not h for
+	PA_REAL.  Fix from Matt Crawford.
+
+2000-02-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* preauth2.c (pa_sam): In send-encrypted-sad mode, check for magic
+	salt length and generate a salt from the principal name if found;
+	use the password and salt to generate a key.  Provide timestamp if
+	nonce is zero, regardless of preauth mode.  (Patch from Chas
+	Williams.)
+
+2000-02-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* gic_pwd.c (krb5_get_as_key_password): If the as_key enctype is
+	already set to the correct type, do continue and ask for the
+	password anyways.  (Patch from Chas Williams, PR krb5-libs/730.)
+
+	* preauth2.c (pa_sam): If no sam_flags were set, return
+	KRB5_PREAUTH_BAD_TYPE, because we don't currently handle that
+	case.
+
+2000-02-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* preauth2.c (pa_sam): Remove unused variable use_sam_key.
+	(SAMDATA): Cast first result to int, which is what sprintf needs.
+	(pa_salt): Delete unused variable ret.
+
+	Patches from Frank Cusack:
+	* kfree.c (krb5_free_predicted_sam_response_contents): Fix typo.
+	Free new data fields if needed.
+	(krb5_free_enc_sam_response_enc_contents): Update for field name
+	change.
+	* preauth.c (obtain_sam_padata): Update for field name change.
+	* preauth2.c (pa_sam): Likewise.
+
+2000-01-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (get_profile_etype_list): Discard DESONLY changes
+	from 1999-09-01, and revert call sites.
+
+1999-12-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (get_profile_etype_list): Report an error if no
+	recognized enctypes are found in the config file.
+
+1999-11-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (init_common): Renamed from krb5_init_context, now
+	static.  New argument SECURE provides initialization of
+	profile_secure field.
+	(krb5_init_context): Call it.
+	(krb5_init_secure_context): New function.
+
+	* in_tkt_ktb.c (keytab_keyproc): Now static.
+	* in_tkt_pwd.c (pwd_keyproc): Now static.
+	* in_tkt_sky.c (skey_keyproc): Now static.
+
+	* preauth2.c (krb5_do_preauth): Fix syntax in switch statement.
+	Cast padata contents pointer to avoid warning.
+	(pa_types): Now static.
+
+	* str_conv.c (krb5_deltat_to_string): Always write to a local
+	temporary buffer that's guaranteed to be large enough, then see if
+	the supplied output buffer is big enough.
+	(krb5_string_to_deltat): Deleted.
+	* x-deltat.y, deltat.c: New files.
+	* Makefile.in (deltat.c): Add rule for building from x-deltat.y,
+	but comment out dependencies for easier maintenance.
+	(BISON, BISONFLAGS): New variables.
+
+	* str_conv.c: Removed most static char arrays, substituting the
+	values in place.
+	(krb5_string_to_timestamp): Move atime_format_table inside here.
+	(krb5_timestamp_to_sfstring): Move sftime_format_table inside
+	here.
+
+	* str_conv.c: If strftime or strptime are not available, include
+	the renamed NetBSD versions, and define the function names as
+	macros to map them to the replacement names.
+	(__P, _CurrentTimeLocale, dummy_locale_info, TM_YEAR_BASE,
+	DAYSPERLYEAR, DAYSPERNYEAR, DAYSPERWEEK, isleap, tzname, tzset):
+	Define some dummies for strftime/strptime to use.
+	(strptime): Deleted old stub version.
+	(krb5_timestamp_to_string, krb5_timestamp_to_sfstring): Always
+	assume strftime is available.
+	(krb5_string_to_timestamp): Assume strptime is always available.
+	* strftime.c, strptime.c: New files, based on NetBSD versions.
+	Modified to rename the functions and not export any symbols.
+
+	* Makefile.in (T_DELTAT_OBJS): New variable.
+	(TEST_PROGS): Add t_deltat.
+	(t_deltat): Add rule.
+	(clean): Added t_deltat stuff.  Run rm only once.
+	* t_deltat.c: New file.
+
+1999-11-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_ref_kerb.out: Fix expected zephyr/zephyr output.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-10-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* conv_princ.c (sconv_list): Don't do conversion for "zephyr"
+	principal.  (Noticed by Derrick Brashear.)  Delete about a dozen
+	duplicate entries.
+
+1999-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (get_profile_etype_list): Update name of the des3
+	entry in the default etype list.
+
+	* init_ctx.c (get_profile_etype_list): New argument DESONLY; if
+	set, ignore any ktype values other than NULL, DES_CBC_CRC, and
+	DES_CBC_MD5.
+	(krb5_get_default_in_tkt_ktypes, krb5_get_tgs_ktypes): Set it.
+	(krb5_get_permitted_enctypes): Don't set it.
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): Use KRB5_TC_SUPPORTED_KTYPES
+	when calling krb5_cc_retrieve_cred.
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Ditto.
+	* get_creds.c (krb5_get_credentials_core): Set that flag.
+	(krb5_get_credentials): Check for KRB5_CC_NOT_KTYPE error return.
+
+	* t_ser.c (main): Disable eblock serialization test, since the
+	code it tests was disabled nearly a year ago.
+
+	* str_conv.c (krb5_timestamp_to_sfstring): Don't pass extra
+	argument to sprintf.
+
+1999-08-10	Alexandra Ellwood	<lxs@mit.edu>
+
+	* chpw.c (krb5_mk_chpw_req):
+		Added call to free cipherpw.data.  cipherpw.data is allocated 
+		by krb5_mk_priv and passed back.  Since cipherpw is never
+		passed back, krb5_mk_chpw_req should free it.
+
+1999-08-05  Danilo Almeida  <dalmeida@mit.edu>
+
+	* init_ctx.c (krb5_init_context): Document why krb5_win_ccdll_load
+	is called way early in code.  (It is because we need to have the
+	ccapi stuff loaded before trying to get the OS-specific context
+	initialization where we figure out default cache names and such.)
+
+1999-08-05  Danilo Almeida  <dalmeida@mit.edu>
+
+	* init_ctx.c (get_profile_etype_list): Use profile_release_string
+	to free string allocated by profile_get_string.
+	(krb5_init_context): Use a real context for krb5_win_ccdll_load.
+
+	* get_in_tkt.c (krb5_appdefault_string):
+	* conv_princ.c (krb5_425_conv_principal): Use profile_free_list
+	to free values allocated by profile_get_values.
+
+1999-08-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* get_in_tkt.c (_krb5_conf_boolean, krb5_appdefault_boolean): 
+	Rename krb5_conf_boolean to _krb5_conf_boolean to denote that
+	it is not public so that folks outside the libraries won't
+	be tempted to use it.
+
+1999-08-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* get_creds.c (krb5_validate_or_renew_creds): Intialize out_creds
+	pointer to 0 and then check whether it is 0 before trying to 
+	dereference it, in case lower-level routine failed to assign
+	a value to it.
+
+1999-07-22  Jeffrey Altman <jaltman@columbia.edu>
+
+        get_in_tkt.c:  rename conf_boolean to krb5_conf_boolean so that
+        it may be used in additional modules.
+
+1999-06-28  Tom Yu  <tlyu@mit.edu>
+
+	* enc_helper.c (krb5_encrypt_helper): NULL out the pointer to the
+	ciphertext if there is an error; this prevents stuff farther up
+	from freeing freed memory.
+
+1999-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_ctx.c (krb5_free_context): Set field pointers to NULL after
+	freeing targets, in case higher-level code retains pointers into
+	the context structure.  (From Jeffrey Altman.)
+
+Thu May 13 17:31:34 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_ctx.c (krb5_init_context): Pass the context to
+		kkrb5_win_ccdll_load so that it can register the FILE
+		ccache type if using ccapi (so that the FILE ccache type
+		will always work).
+
+Mon May 10 15:26:00 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1999-04-09  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kfree.c (krb5_free_sam_challenge, krb5_free_sam_challenge_contents,
+		krb5_free_sam_response, krb5_free_sam_response_contents,
+		krb5_free_predicted_sam_response, 
+		krb5_free_predicted_sam_response_contents,
+		krb5_free_enc_sam_response_enc, 
+		krb5_free_enc_sam_response_enc_contents,
+		krb5_free_pa_enc_ts): Added new functions.  Part of
+		patches from [krb5-kdc/662]
+
+	* gic_pwd.c (krb5_get_init_creds_password): Add new argument to
+		calls to the prompter function.  Part of patches from
+		[krb5-kdc/662].
+
+	* preauth2.c (pa_enc_timestamp, pa_sam): Update calls to new
+		prompter function.   [krb5-kdc/662].
+
+1999-03-31  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* init_ctx.c (krb5_init_context): Call krb5_win_ccdll_load() to
+		load the krbcc32.dll under windows.
+
+Mon Mar  8 22:39:01 1999  Tom Yu  <tlyu@mit.edu>
+
+	* sendauth.c (krb5_sendauth): Set credspout to NULL if it's
+	destined to be returned to avoid freeing it.  Also,
+	unconditionally free credspout if it's non-NULL so that if someone
+	doesn't pass in a ticket and doesn't give us a non-NULL out_creds,
+	we don't leak it. [krb5-libs/699]
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Mon Nov  2 19:00:23 1998  Tom Yu  <tlyu@mit.edu>
+
+	* str_conv.c: Remove krb5_cksumtype_to_string after merge.
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* vfy_increds.c: rearrange the code a bit to make it more clear
+	that the logic is correct.
+
+	* str_conv.c: remove enctype and cksumtype string converstions.
+	They're in the crypto library now, since the information drops
+	right into the enctype table.
+
+	* ser_eblk.c: ifdef the whole file out, since it's not used
+	anywhere.  it should probably be deleted, but I'm not sure about
+	backward-compatibility issues yet.
+
+	* rd_req_dec.c: check the auth_context permit-all flag and
+	permitted_enctypes list, and reject the request if the policy
+	check fails.
+
+	* init_ctx.c: add code to initialize the prng.  It's not great,
+	but can be improved, and the prng is reseeded when new keys are
+	processed. Read permitted_enctypes from the krb5.conf file, and
+	provide accessor functions for it.  Make the various etype list
+	parsers share code as a side effect.
+
+	* get_creds.c: add krb5_get_{validat,renew}ed_creds functions,
+	which are part of the new init_creds api.  The prototypes were
+	already in, krb5.hin but there was no implementing code.
+
+	* auth_con.c, auth_con.h: add a list of permitted enctypes to the
+	auth_context for rd_req to check, and create accessor functions
+	for this list.
+
+	* Makefile.in, enc_helper.c: add enc_helper.c.  This provides a
+	wrapper around the conventional way the library encrypts and wraps
+	encoded asn.1 structures, so the code isn't repeated in a dozen
+	places.
+
+Wed Aug 19 17:27:51 1998  Tom Yu  <tlyu@mit.edu>
+
+	* conv_princ.c: Add some additional entries to sconv_list that
+	were forgotten.
+
+Wed Jul 15 11:46:05 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* gic_pwd.c (krb5_get_init_creds_password): Remove unused argument
+	 	to sprintf().
+
+	* t_ref_kerb.out: Fix test case for zephyr principal to reflect
+	 	addition to conv_princ.c
+
+Tue Jul  7 17:06:13 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* conv_princ.c: Add additional commonly seen Kerberos V4 services
+		to the hard-coded list.
+
+Tue Jul  7 16:59:03 1998  Tom Yu  <tlyu@mit.edu>
+
+	* chk_trans.c: Fix up previous fix; short-circuit out when
+	trans->length == 0.
+
+Wed Jul  1 17:59:26 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* chk_trans.c (krb5_check_transited_list): Fix use of an
+ 		uninitialized variable; apparently the code was depending
+ 		on the stack garbage being non-zero(!)
+
+1998-05-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* srv_rcache.c (krb5_get_server_rcache): 
+	* auth_con.c (krb5_auth_con_setrcache): Export this function in
+		Windows DLL.
+
+1998-05-12  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* str_conv.c (krb5_timestamp_to_sfstring): Make sure the date
+		string printed uses 4 digit years.
+
+1998-05-08  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* str_conv.c (krb5_string_to_timestamp, strptime): Fix routines to
+		be able to properly parse Y2K dates.  
+
+	* t_kerb.c: Add ability to test krb5_string_to_timestamp
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* t_ser.c (main): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+1998-05-05  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* get_in_tkt.c (krb5_get_init_creds): If
+		libdefaults/{REALM}/noaddresses is true, then don't put
+		any addresses in the ticket request.
+
+Mon May  4 15:54:07 1998  Tom Yu  <tlyu@mit.edu>
+
+	* get_in_tkt.c: Add prototype for make_preauth_list.
+
+Sat May  2 21:46:02 1998  Tom Yu  <tlyu@mit.edu>
+
+	* get_in_tkt.c (krb5_get_in_tkt): Add missing argument to call to
+	make_preauth_list to avoid stack smashing.  Pointed out by lxs.
+
+Mon Mar 16 19:50:55 1998  Tom Yu  <tlyu@mit.edu>
+
+	* chk_trans.c (krb5_check_transited_list): Check lengths when
+	appending to next and prev.
+
+Fri Feb 27 18:03:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/krb5
+ 		directory, since we've moved the configure.in tests in
+ 		this directory to the toplevel lib/krb5 configure.in
+
+Thu Feb 19 19:03:20 1998  Tom Yu  <tlyu@mit.edu>
+
+	* recvauth.c (krb5_recvauth): Add some bookkeeping flags so we
+	know how much stuff to free upon cleanup.  Fix the up cleanup
+	code.
+
+Wed Feb 18 16:24:02 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 15:27:35 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Added new file kfree.c, which contained all of the
+		functions previously in the lib/krb5/free directory.
+
+Mon Feb  2 17:02:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Feb  5 23:48:34 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* rd_cred.c (krb5_rd_cred): 
+	* rd_safe.c (krb5_rd_safe): 
+	* rd_priv.c (krb5_rd_priv): Use the remote_subkey first, since the
+		mk_* routines try to use their local_subkey first.
+		Otherwise, the wrong keys will get used if subkeys are
+		used in both directions.
+
+Fri Jan  2 21:21:29 1998  Tom Yu  <tlyu@mit.edu>
+
+	* preauth.c (handle_sam_labels):
+	(obtain_sam_padata): Check return of malloc. [krb5-libs/518]
+
+	* chpw.c (krb5_mk_chpw_req): Check return of malloc.
+	(krb5_rd_chpw_rep): Check return of malloc. [krb5-libs/518]
+
+Tue Dec 16 00:08:33 1997  Tom Yu  <tlyu@mit.edu>
+
+	* mk_req_ext.c (krb5_mk_req_extended): Check enctype of session
+	key, not that of the ticket, which we really shouldn't care about.
+
+Sun Dec  7 07:24:23 1997  Ezra Peisach  <epeisach@dumpster.rose.brandeis.edu>
+
+	* gic_pwd.c (krb5_get_init_creds_password): Change fourth argument
+ 	in call to prompter (which is an int) from NULL to 0.
+
+Sat Dec  6 02:28:17 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add files chpw.c, gic_*, preauth2.c, vfy_increds.c,
+	vic_opt.c.
+
+	* chpw.c: New file; implement Cygnus chpw.
+
+	* get_in_tkt.c: Implement support for Cygnus initial credentials
+	API.
+
+	* gic_keytab.c: New file; Cygnus initial creds.
+
+	* gic_opt.c: New file; Cygnus initial creds.
+
+	* gic_pwd.c: New file; Cygnus initial creds.
+
+	* preauth.c: Add more SAM support (from Cygnus).
+
+	* preauth2.c: New file; additional SAM support from Cygnus.
+
+	* send_tgs.c: Account for additional parameter to sendto_kdc.
+
+	* vfy_increds.c: New file; Cygnus initial creds.
+
+	* vic_opt.c: New file; Cygnus initial creds.
+
+Wed Oct 22 00:29:33 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* send_tgs.c (krb5_send_tgs): Don't send a zero endtime; if the
+		requested endtime is zero, set it equal to the TGT endtime.
+
+Mon Oct  6 12:07:19 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* set_realm.c (krb5_set_principal_realm): Allocate extra byte for
+	        \0 after realm.
+
+Mon Sep  1 21:38:16 1997  Tom Yu  <tlyu@mit.edu>
+
+	* rd_cred.c (krb5_rd_cred_basic): Fix swapped args to memset.
+
+Fri Aug 29 16:41:25 1997  Tom Yu  <tlyu@mit.edu>
+
+	* get_in_tkt.c (krb5_get_in_tkt): Move nulling out of
+	request.padata before the os_localaddr call in order to avoid
+	freeing a null pointer in the cleanup code.
+
+Tue Aug 12 09:13:22 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* init_ctx.c (krb5_init_context): Initialize local variable ctx
+	 	before calling krb5_init_ets.
+
+Fri Aug  8 17:04:54 1997  Tom Yu  <tlyu@mit.edu>
+
+	* rd_cred.c (krb5_rd_cred_basic): Check remote_addr and
+	encpart.s_address before calling krb5_address_compare.  Fixes
+	krb5-libs/456.
+
+Fri Jul 25 15:25:32 1997  Tom Yu  <tlyu@mit.edu>
+
+	* t_ser.c: Add support for changed kdb API.
+
+Tue Jul 15 22:15:09 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* serialize.c (krb5_register_serializer): Only copy over the old
+		table when there's an old table to copy over.  Otherwise,
+		BoundsChecker complains about memcpy(foo, NULL, 0).
+
+Tue Mar 25 00:32:55 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* preauth.c (obtain_sam_padata): Fix handling of the sam-timestamp
+ 		and sam-usec fields, which should always be set if the
+		nonce is not available, not just SAM_USE_SAD_AS_KEY is
+		being used.  [krb5-libs/325]
+
+Mon Mar 24 12:21:38 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* t_ser.c: Clean up error reporting for krb5_init_context().  Also
+ 		report errors for each subtest, so we know which subtest
+ 		failed.
+
+Sat Feb 22 22:39:49 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Fri Feb 21 18:38:06 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* crypto_glue.c: Move into libcrypto as krb5_glue.c; I need to
+        avoid libcrypto depending on libkrb5
+
+Wed Feb 19 14:21:12 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* t_kerb.c (test_set_realm): New function used to test
+	krb5_set_principal_realm().  Called by using the new "set_realm"
+	command to t_kerb.
+
+	* set_realm.c (krb5_set_principal_realm): New function which sets
+		the realm of a principal.
+
+Thu Feb 13 14:17:00 1997  Richard Basch  <basch@lehman.com>
+
+	* get_in_tkt.c (krb5_get_in_tkt): Initialize as_reply; if
+		krb5_os_localaddr() returns an error, the cleanup
+		routine may try to free a garbage pointer (as_reply).
+
+Wed Feb 12 20:47:30 1997  Tom Yu  <tlyu@mit.edu>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): Use the client's realm rather
+		than the server's realm for constructing the tgs principal.
+		Remove TC_MATCH_SRV_NAMEONLY from call to retrieve_cred()
+		because we want to get an exact match.
+
+Mon Feb 10 10:41:36 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* crypto_glue.c (krb5_calculate_checksum): Add krb5_const to
+	        krb5_pointer of in data to match prototype.
+
+Sat Feb  8 15:02:39 1997  Richard Basch  <basch@lehman.com>
+
+	* get_creds.c:
+		Export krb5_get_credentials_{renew,validate} (win32)
+		Removed unused variable.
+
+Fri Feb  7 09:41:33 1997  Richard Basch  <basch@lehman.com>
+
+	* mk_cred.c (krb5_mk_ncred): Declare ncred as krb5_int32 so that
+		the right value is pushed onto the stack when calling
+		krb5_mk_ncred_basic()
+
+	* copy_addrs.c fwd_tgt.c mk_cred.c:
+		Use FAR keyword in pointer declarations.
+
+	* sendauth.c (krb5_sendauth): Do not free the credentials if they
+		are being returned to the caller [krb5-libs/357]
+
+Sun Feb  2 20:57:15 1997  Richard Basch  <basch@lehman.com>
+
+	* serialize.c: Added FAR declarations to pointer arguments for
+		all functions declared as KRB5_DLLIMP.
+
+Thu Jan 30 21:44:37 1997  Richard Basch  <basch@lehman.com>
+
+	* crypto_glue.c:
+		Export more crypto-layer functions:
+		krb5_encrypt, krb5_decrypt, krb5_eblock_enctype,
+		krb5_process_key, krb5_finish_key, krb5_string_to_key,
+		krb5_init_random_key, krb5_finish_random_key, krb5_random_key
+
+Sat Feb  8 18:41:42 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Jan  2 17:16:18 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Mon Dec 23 17:20:03 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (SRCS): Add brand.c to the SRCS line so that the
+		kerbsrc.mac.tar includes brand.c
+
+Sat Dec 21 01:26:11 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* brand.c: New file, which allows a release engineer to "brand"
+ 		the krb5 library or a binary application program
+ 		statically linked against the krb5 library.  This file is
+		statically included by init_ctx.c, to force it be in a
+		binary library or application program.
+	
+	* init_ctx.c (krb5_init_context): Use new call krb5_vercheck() for
+ 		Windows timebomb checking; this call returns an error
+		code, which is returned to the user if the timebomb should
+		be activated.
+
+Thu Nov 21 14:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+	* auth_con.c bld_pr_ext.c conv_princ.c copy_addrs.c copy_athctr.c
+	copy_auth.c copy_cksum.c copy_creds.c copy_data.c copy_key.c
+	copy_princ.c copy_tick.c cp_key_cnt.c decrypt_tk.c fwd_tgt.c
+	gc_via_tkt.c get_creds.c get_in_tkt.c in_tkt_ktb.c in_tkt_pwd.c
+	in_tkt_sky.c init_ctx.c mk_cred.c mk_error.c mk_priv.c mk_rep.c
+	mk_req.c mk_req_ext.c mk_safe.c parse.c princ_comp.c rd_cred.c
+	rd_error.c rd_priv.c rd_rep.c rd_req.c rd_safe.c recvauth.c
+	sendauth.c str_conv.c unparse.c valid_times.c
+		DLL export various functions (see lib/krb5.def for full list)
+
+Thu Nov 21 13:54:01 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* recvauth.c (krb5_recvauth): If there is an error, and the server
+		argument to krb5_recvauth is NULL, create a dummy server
+		entry for the krb5_error structure so that krb5_mk_error
+		will not die with missing required fields. [krb5-libs/209]
+
+Wed Nov 13 14:30:47 1996  Tom Yu  <tlyu@mit.edu>
+
+	* init_ctx.c: Revert previous kt_default_name changes.
+
+Tue Nov 12 22:07:33 1996  Tom Yu  <tlyu@mit.edu>
+
+	* init_ctx.c (krb5_init_context): Oops. Initialize kt_default_name
+ 	to NULL.
+	
+	* init_ctx.c (krb5_free_context): Free kt_default_name if it's
+	non-NULL.
+
+Sat Nov  9 14:19:28 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (check-unix): Invoking t_ser requires that
+		KRB5_CONFIG points to a valid krb5.conf 
+
+	* t_ser.c (main): If verbose flag is set and there is an error,
+	 	display error message.
+
+Wed Nov  6 14:02:21 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_ctx.c (krb5_init_context): Initialize the error tables, so
+		applications don't need to call krb5_init_ets().
+
+Tue Nov  5 08:09:23 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* serialize.c (krb5_register_serializer): Do not free a NULL pointer. 
+
+Thu Oct 31 13:48:14 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_ctx.c (krb5_init_context): Make it more obvious that
+		default ticket lifetimes is not yet supported.
+
+Tue Sep 24 20:59:14 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* get_in_tkt.c (make_preauth_list): Correctly null-terminate the
+		preauth list generated by make_preauth_list.
+
+Thu Sep 19 12:29:59 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* unparse.c (krb5_unparse_name_ext): Make unparse correctly handle
+		a all cases where a principal contains a nulls, backspace,
+		newlines, or tabs.
+
+	* t_kerb.c (test_parse_principal): Add test for checking
+	 	krb5_parse_principal()
+
+	* parse.c (krb5_parse_name): Set all of the magic field values.
+
+Wed Jul 24 17:09:39 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* preauth.c (find_pa_system): Change type of first argument to be
+ 	 	krb5_preauthtype, to eliminate compiler warnings under
+ 	 	Windows.
+	
+Wed Jul 10 20:22:41 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_ctx.c (krb5_init_context): Add a call to krb5_win_do_init()
+		on Win16 and Win32 machines.  This is where we do timebomb
+		and version server checking.
+
+Sun Jul  7 15:14:43 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* get_creds.c: (krb5_get_credentials_val_renew_core) Combine
+		common internals needed from krb5_get_credentials_validate()
+		and used by new function krb5_get_credentials_renew()
+
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_renew): A wrapper that
+		passes KDC_OPT_RENEW to the static
+		krb5_get_cred_from_kdc_opt so that kinit can use it.
+
+
+Mon Jun 24 09:45:04 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* bld_princ.c (krb5_build_principal_va): Change const to
+ 		krb5_const, so that it works on compilers that don't
+ 		support const.
+
+Mon Jun 17 20:23:48 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* str_conv.c (krb5_string_to_timestamp): Ensure that all fields of
+		the timestamp are filled in if strptime does not fill in
+		unspecified fields.
+
+Wed Jun 12 01:10:09 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* sendauth.c (krb5_sendauth): If ECCONABORTED is not defined, try
+		using the Winsock equivalent (WSAECONNABORTED).
+
+Mon Jun 10 21:47:21 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* parse.c (krb5_parse_name): Change use of _WINDOWS to _MSDOS, and
+		add check for _WIN32.
+
+Thu Jun  6 00:06:18 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* get_creds.c (krb5_get_credentials_core): A static function must
+		not use the INTERFACE keyword.
+
+Tue May 14 18:39:22 1996  Richard Basch  <basch@lehman.com>
+
+	* mk_req_ext.c mk_safe.c send_tgs.c:
+		set the length field of the krb5_checksum structure before
+		calling krb5_calculate_checksum.
+
+	* str_conv.c: replaced sha-des3 cksum with hmac-sha.
+
+Tue May 14 02:53:42 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ser_ctx.c (krb5_context_size, krb5_context_externalize,
+	 	krb5_context_internalize): Add missing fields from the
+		serialized context: clockskew, default_kdc_req_sumtype,
+	 	default_ap_req_sumtype, default_safe_sumtype,
+	 	kdc_default_options, library_options, profile_secure,
+	 	fcc_default_format, scc_default_format.
+
+	* ser_actx.c (krb5_auth_context_size, krb5_auth_context_externalize,
+		krb5_auth_context_internalize): Serialize the two fields
+		req_cksumtype and safe_cksumtype, instead of the one
+		cksumtype field.
+
+	* mk_safe.c (krb_mk_safe): Use safe_cksumtype instead of cksumtype
+		in the auth context.
+
+	* mk_req_ext.c (krb5_mk_req_extended): Use req_cksumtype instead
+		of cksumtype in the auth context.
+
+	* init_ctx.c (krb5_init_context): Add support for new profile
+ 		relations libdefaults/tkt_lifetime,
+ 		libdefaults/kdc_req_checksum_type,
+ 		libdefaults/ap_req_cksumtype,
+ 		libdefaults/safe_checksumtype, and
+ 		libdefaults/kdc_default_options.
+
+	* auth_con.h: Remove old cksumtype element, and replace it with
+		req_cksumtype and safe_cksumtype.
+
+	* auth_con.c (krb5_auth_con_init): Initialize the req_cksumtype
+ 	 	and safe_cksumtype from the context's default
+ 	 	req_cksumtype and safe_cksumtype.
+		(krb5_auth_con_set_req_cksumtype,
+	 	krb5_auth_con_set_safe_cksumtype): New functions, to
+	 	replace old krb5_auth_con_setcksumtype
+	
+Fri May 10 18:48:38 EDT 1996  Richard Basch  <basch@lehman.com>
+
+	* init_ctx.c: Removed des3-cbc-md5 default support
+
+Fri May 10 02:51:17 1996  Richard Basch  <basch@lehman.com>
+
+	* str_conv.c: changes des3-md5 to des3-sha & added sha cksum types
+
+Sun May  5 09:46:18 1996  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* preauth.c: Add casts and const keywords as needed.
+
+Fri May  3 00:15:18 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* get_creds.c (krb5_get_credentials_core): new function. Common
+	part of krb5_get_credentials and krb5_get_credentials_validate.
+	Some formerly local variables are now arguments.
+	(krb5_get_credentials): same as before, but calls _core to do some
+	of the work.
+	(krb5_get_credentials_validate): uses
+	krb5_get_cred_from_kdc_validate and only stores the returned
+	credential in the cache, instead of storing all of them.
+
+Thu May  2 22:48:56 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): new function. Same
+	body as krb5_get_cred_from_kdc, but takes one new argument,
+	kdcopts, and combines it with the other kdc options when calling
+	krb5_get_cred_via_tkt. This is static and only called by
+	(krb5_get_cred_from_kdc): a wrapper that provides the same
+	function it did before, and
+	(krb5_get_cred_from_kdc_validate): a wrapper that passes
+	KDC_OPT_VALIDATE, so that kinit can use it.
+	We'll probably need another one for renewing tickets as well.
+
+	* rd_req_dec.c (krb5_rd_req_decoded_opt): new function. Same body
+	as krb5_rd_req_decoded, but takes one new argument,
+	check_valid_flag, to determine whether or not to check if the
+	"invalid flag" is set in the ticket. Also made static, so that it
+	is only called via:
+	(krb5_rd_req_decoded): wrapper for krb5_rd_req_decoded_opt that
+	specifies the "invalid flag" gets checked, and
+	(krb5_rd_req_decoded_anyflag): wrapper for krb5_rd_req_decoded_opt
+	that specifies that the "invalid flag" doesn't get checked. (This
+	version is only called from kdc_util.c:kdc_process_tgs_req.)
+
+Wed May  1 14:30:29 1996  Richard Basch  <basch@lehman.com>
+
+	* srv_rcache.c (krb5_get_server_rcache): include the uid in the
+		default server replay cachename, for systems with geteuid.
+
+	* configure.in: test if the system has geteuid()
+
+Wed May  1 02:26:53 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* str_conv.c (krb5_string_to_timestamp): double check that
+	strptime at least parsed *some* of the string, avoid degenerate
+	cases from GNU libc strptime.
+
+Tue Apr 30 18:19:01 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* t_ser.c (stuff): New variable.
+	(ser_acontext_test, ser_eblock_test, ser_cksum_test): Use it,
+	instead of assuming it's valid to treat &FUNCTION as a data
+	pointer.
+
+	* conv_princ.c (sconv_list): Now const.
+	(krb5_*_conv_principal): Use pointer to const for it.
+
+	Tue Apr 23 19:39:59 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* get_creds.c (krb5_get_credentials): this isn't the kernel, so
+	don't return negative errno values.
+
+Sat Apr 27 19:14:21 1996  Richard Basch  <basch@lehman.com>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): fixed a possible null dereference.
+
+Wed Apr 17 14:22:10 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* conv_princ.c: Added ftp and ecat to the list of services which
+ 	 	should be converted.  This really ought to be something
+	 	that's configurable in the profile...
+
+Thu Apr 11 21:30:23 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* init_ctx.c (krb5_init_context): On a Macintosh, turn on
+		kdc_timesync and use the v4 credentials cache by default.
+
+	* get_in_tkt.c (stash_as_reply, verify_as_reply): Move time offset
+		code from stash_as_reply to verify_as_reply, and fix it so
+		that it actually works.
+
+Wed Apr  3 16:04:36 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rd_req_dec.c (krb5_rd_req_decoded): Move code which
+	        validated the ticket times to krb5_validate_times.
+
+	* valid_times.c (krb5_validate_times): New function which
+		determines whether or not the ticket times are valid.
+
+	* mk_req_ext.c (krb5_mk_req_extended): Call krb5_validate_time()
+		to determine whether or not the ticket in passed-in
+		credentials is valid.  If it isn't, return an error right
+		away. 
+
+Wed Mar 27 17:05:47 1996  Richard Basch  <basch@lehman.com>
+
+	* in_tkt_ktb.c (keytab_keyproc): Do not check to see that the
+	enctype of the key is identical; there are several equivalent
+	DES enctypes.
+
+	* in_tkt_ktb.c (krb5_get_in_tkt_with_keytab): Removed the fancy
+	logic to only request the keytypes that correspond to those in
+	the keytab.  There were too many fencepost conditions that could
+	get you into trouble.  Either it should be there and *fully*
+	functional, or not in there at all.  Besides, there are too many
+	other components in Kerberos that expect the end-service to know
+	all its keys that this sanity check is overkill.
+
+Tue Mar 26 14:45:03 1996  Richard Basch  <basch@lehman.com>
+
+	* conv_princ.c: added "imap" service to the conversion list as
+	requiring domain conversion for the instance.  (imap/<host> is used
+	by some of the new imap mail implementations)
+
+Sun Mar 24 01:34:14 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* send_tgs.c (krb5_send_tgs_basic): You want to setup the eblock
+ 	used for the authenticator using the in_cred->keyblock, *not*
+ 	request.ticket.enc_part.enctype.  Under a multi-enctype system,
+ 	the session key may be different from the ticket key.
+
+Wed Mar 20 23:00:59 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* walk_rtree.c (krb5_walk_realm_tree): Fix 16bit vs. 32bit error.
+		(cap_code should been a krb5_error_code, not an int!)
+
+	* mk_cred.c (krb5_mk_ncred_basic): Fix windows lint flame.
+
+	* get_in_tkt.c (krb5_get_in_tkt): Fix 16bit vs. 32bit error.
+		(do_more should not have been an int!)
+
+Tue Mar 19 13:03:26 1996  Richard Basch  <basch@lehman.com>
+
+	* in_tkt_ktb.c (krb5_get_in_tkt_with_keytab):
+	Only request keytypes that correspond to those in the keytab.
+
+Mon Mar 18 21:49:39 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add KRB5_RUN_FLAGS
+
+	* Makefile.in: Use runtime flags.
+
+Sun Mar 17 20:32:08 1996  Ezra Peisach  <epeisach@dumpster.rose.brandeis.edu>
+
+	* configure.in: Add USE_ANAME, USE_KRB5_LIBRARY, KRB5_LIBRARIES so
+		that Makefile does not have to know build tree layout.
+
+        * Makefile.in: Rework to be consistant with configure defines so
+		that configure can specify other needed libraries.
+
+Sun Mar 17 02:10:19 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* copy_addrs.c (krb5_copy_addr): make non-static so we can use it
+	in mk_cred.
+	* mk_cred.c (krb5_mk_ncred_basic): copy local_addr and remote_addr
+	instead of just aliasing them, so we can safely free them ourselves.
+
+Fri Mar 15 14:29:00 1996  Richard Basch  <basch@lehman.com>
+
+	* in_tkt_ktb.c: Close the keytab if we opened it, not if the
+	caller opened it.
+
+Wed Mar 13 17:31:30 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Use AC_HEADER_STDARG.
+
+Mon Mar 11 11:15:26 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* str_conv.c (krb5_timestamp_to_string): Handle statement not
+		reached warning.
+
+	* ser_addr.c (krb5_address_internalize): Add magic numbers
+
+Thu Feb 29 11:49:38 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* fwd_tgt.c (NEED_SOCKETS): Use NEED_SOCKETS instead of #including
+	        <netdb.h>
+
+Sat Feb 24 16:27:54 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gc_via_tkt.c (krb5_get_cred_via_tkt): Fix memory leak; free
+		enctypes after use.
+
+Thu Jan 25 01:35:52 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* rd_req_dec.c (krb5_rd_req_decrypt_tkt_part): Remove outdated
+        comment about mapping etype to ktype.
+
+	* gc_via_tkt.c (krb5_get_cred_via_tkt): If the keyblock.enctype is
+        non-null in in_cred, then request that particular key.
+
+Wed Jan 24 21:48:53 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* get_creds.c (krb5_get_credentials): Only match against enctype
+        if it is non-null in increds.
+
+Sun Jan 21 23:32:53 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* gc_via_tkt.c (krb5_kdcrep2creds): Set is_skey so get_creds won't
+		break trying to match is_skey in the ccache.  This way we
+		won't end up with many copies of user-to-user tickets.
+
+Fri Jan 19 23:16:17 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* mk_req.c (krb5_mk_req): krb5_get_credentials does not take
+		default_kdc_options. 
+
+	* sendauth.c (krb5_sendauth): krb5_get_credentials does not take
+		default_kdc_options. 
+
+Wed Jan 10 21:01:36 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* init_ctx.c (krb5_init_context): Added checking of profile for
+	        DCE compatability options (ccache type, and checksum type).
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): Initialize addrs to 0 so that we
+		don't try to free stack garbage on an error.
+
+	* krbconfig.c, Makefile.in: Removed krbconfig.c; it contained
+		global variables which are no longer used.
+
+	* recvauth.c: Removed the global extern of
+		krb5_kdc_default_options, which wasn't being used anyway.
+
+	* mk_req.c (krb5_mk_req): Replace use of krb5_kdc_default_options
+		with context->kdc_default_options.
+
+	* gc_frm_kdc.c: Remove the global extern of krb5_kdc_req_sumtype,
+		which wasn't being used anymore anyway.
+
+	* send_tgs.c (krb5_send_tgs_basic): Remove use of the global
+		variable krb5_kdc_req_sumtype, and use the kdc_req_sumtype
+		in the context structure instead.
+
+	* walk_rtree.c (krb5_walk_realm_tree): Applied patch submitted by
+		Doug Engbert, so that the configurable authentication
+		patch takes into account the null entry at the end of the
+		list.
+
+Tue Jan  9 22:04:09 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* fwd_tgt.c (krb5_fwd_tgt_creds): New function which handles all
+		of the dirty work of forwarding TGT's.
+
+	* rd_cred.c (krb5_rd_cred_basic): Clean up memory allocation
+		discpline to remove memory leaks.
+
+	* mk_cred.c (krb5_mk_ncred_basic, krb5_mk_ncred, krb5_mk_1cred):
+		Clean up memory allocation discpline to remove memory
+		leaks.
+
+	* init_ctx.c (krb5_get_tgs_ktypes): Clean up parsing of the etype
+		list.  Don't overrun the string containing the etype list.
+
+Wed Jan  3 21:32:59 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rd_cred.c (krb5_rd_cred_basic): When the keyblock is NULL,
+		assume we're being called from the gssapi code, which
+		doesn't have access to the sender or receive address
+		information, don't check the sender address, since it
+		won't be available.
+
+	* rd_cred.c (decrypt_credencdata): When calling krb5_rd_credd(),
+		if the keyblock is null, just copy the encoded structure
+		from the "ciphertext" part of the structure and decode it.
+
+	* mk_cred.c (encrypt_credencpart):  When calling krb5_mk_cred(), if
+		the keyblock is NULL, don't encrypt it; just encode it and
+		leave it in the ciphertext area of the structure.
+
+Thu Dec 21 18:47:54 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rd_rep.c (krb5_rd_rep): Change use of
+		KRB5_SENDAUTH_MUTUAL_FAILED to KRB5_MUTUAL_FAILED.
+
+Tue Dec 19 17:15:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rd_cred.c (krb5_rd_cred_basic): Missing parenthesis meant that
+		wrong number of bytes was being allocated.
+
+Sun Dec  3 11:49:09 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (SRCS/OBJS): Move compat_recv.c to krb5util library.
+
+Fri Dec  1 17:04:43 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* recvauth.c (krb5_recvauth): Initialize rcache to zero, so that
+		on cleanup we don't try to free stack garbage.
+
+Sun Nov 26 19:31:18 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* preauth.c: Ultrix is broken.  Prototype obtain_enc_ts_padata()
+		and process_pw_salt() explicitly rather than using the
+		typedef in k5-int.h becaus that typedef is to a function
+		pointer now.
+
+Fri Nov 17 22:35:52 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* get_in_tkt.c (decrypt_as_reply): 
+	* preauth.c (process_pw_salt): When fetching the key to decrypting
+		the encrypted kdc reply, use the etype associated with the
+		etype reply, not the etype associated with the included
+		ticket. 
+
+	* encode_kdc.c: Remove eblock argument from krb5_encode_kdc_rep;
+		set the eblock type from the client_key's enctype.
+
+Thu Nov 16 20:29:17 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* srv_rcache.c (krb5_get_server_rcache): Use krb5_rc_default_type
+		instead of assuming default rcache type is "dfl".
+
+Mon Nov 13 14:40:05 1995    <tytso@rsts-11.mit.edu>
+
+	* walk_rtree.c (krb5_walk_realm_tree): Added ANL changes to
+		support configuration authentication paths.
+
+Mon Nov 13 12:57:12 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* preauth.c (krb5_process_padata): Added generalized processing
+		for preauth information which is returned by the KDC.
+		This should be general enough to support the AFS3_SALT
+		preauth type, the SNK4 preauth type, and the public-key
+		mods to Kerberos.
+	(process_pw_salt): New function for processing the KRB5_PW_SALT
+		preauthentication type.
+
+	* get_in_tkt.c (decrypt_as_reply): Removed temporary kludge for
+		processing the PW_SALT preauth type; that's now done in
+		preauth.c
+	(krb5_get_in_tkt): Call krb5_process_padata with new arguments so
+		that the preauth code can set the decryption_key if
+		necessary. 
+		
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * in_tkt_pwd.c : Remove krb5_enctype from krb5_string_to_key() args.
+
+Thu Nov  9 00:02:43 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* get_in_tkt.c (krb5_get_in_tkt): Remove the etype_info argument
+		from the call to krb5_obtain_padata.
+
+	* preauth.c (krb5_obtain_padata): Use the PADATA_ETYPE_INFO
+		preauth, if it exists, to determine which salt type to use
+		when encrypting the preauthentication data.  Remove the
+		etype_info argument.
+
+Wed Nov  8 02:50:59 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krbconfig.c: Removed the krb5_clockskew variable.
+
+	* srv_rcache.c (krb5_get_server_rcache): 
+	* rd_safe.c (krb5_rd_safe): 
+	* rd_req_dec.c (krb5_rd_req_decoded): 
+	* rd_priv.c (krb5_rd_priv): 
+	* rd_cred.c (krb5_rd_cred): 
+	* gc_via_tkt.c (krb5_get_cred_via_tkt): 
+	* get_in_tkt.c (verify_as_reply): Replace use of krb5_clockskew
+		with context->clockskew.
+
+	* encrypt_tk.c (cleanup_scratch): Changed interface to no longer
+		require an eblock; we can use our own and figure out the
+		enctype from the passed-in key.
+
+	* get_in_tkt.c (krb5_get_in_tkt): Added calls to
+		krb5_obtain_padata(). 
+
+	* preauth.c: Completely restructured file to support
+		preauthentication. 
+		
+
+Fri Oct 27 22:15:33 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* get_in_tkt.c (krb5_get_in_tkt): Extensive reworking of the
+		structure of this file to make it possible to support
+		preauthentication.
+
+Mon Oct 23 17:08:59 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* in_tkt_pwd.c (krb5_get_in_tkt_with_password): Fix to properly
+		malloc password buffer.
+
+Mon Oct 23 11:09:56 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rd_req_dec.c (krb5_rd_req_decoded): For heirarchal cross-realm,
+		set the length after initializing string.
+
+	* rd_req.c (krb5_rd_req): If a new auth_context is created
+		and then there is an error, make sure return pointer is not
+		looking at freed memory.
+
+Fri Oct  6 22:04:42 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Fri Sep 29 00:08:53 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gc_via_tkt.c (krb5_get_cred_via_tkt): Only check the returned
+		starttime to make sure it matches the requested starttime
+		if we requested a postdated ticket.
+
+Thu Sep 28 22:58:53 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* conv_princ.c (krb5_425_conv_principal): Only convert instances
+		which don't have a '.' in them.  If they have a '.',
+		assume that they are fully qualified already.
+
+Thu Sep 28 12:00:00 1995  John Rivlin <jrivlin@fusion.com)
+
+	* gc_via_tkt.c: Cleaned up corrupt ticket error testing to 
+		make it more debugable and I think work around a compiler
+		bug.
+
+Mon Sep 25 16:57:59 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 13 10:58:20 1995 Keith Vetter (keithv@fusion.com)
+
+        * get_in_t.c: removed unused variable.
+        * rd_cred.c: removed INTERFACE keyword.
+        * ser_auth.c: passing int32 where a size_t is wanted.
+        * ser_ctx.c: 16/32 bit int size mismatch.
+
+Sun Sep 17 23:41:19 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rd_safe.c: Fix typo error.
+
+Sat Sep 16 01:23:14 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sendauth.c (krb5_sendauth): Make sure the scratch credentials
+		structure may have possible been used be freed..
+
+	* rd_safe.c (krb5_rd_safe_basic): Fall through to the cleanup code
+		at the end, to make sure the decoded message in message is
+		freed.
+
+	* rd_req_dec.c (krb5_rd_req_decoded): Use krb5_copy_keyblock to
+		copy authent->subkey to auth_context->remote_subkey.
+		Keeping them separate avoids aliasing problems.
+
+	* mk_req_ext.c (krb5_generate_authenticator): Fix memory leak.
+		Don't bash authent->subkey with key after carefully
+		copying it using krb5_copy_keyblock!
+
+	* recvauth.c (krb5_recvauth): krb5_get_server_rcache() already
+		opens the rcache; doing it again merely causes a memory leak.
+
+Fri Sep 15 17:20:08 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gen_subkey.c (krb5_generate_subkey): Eliminate memory leak.
+		krb5_init_random_key() does its own allocation of the
+		keyblock.
+
+	* gc_via_tkt.c (krb5_kdcrep2creds): Fix memory leak.
+
+	* srv_rcache.c (krb5_get_server_rcache): Fix memory leak.
+
+	* rd_safe.c (krb5_rd_safe_basic): Fix memory leak.
+
+Tue Sep 12 12:40:30 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* t_ser.c (ser_cksum_test): Work around an optimizer bug unser
+		OSF/1 and gcc.
+
+Sun Sep 10 12:00:00 1995	James Mattly	(mattly@fusion.com)
+
+	* gen_seqnum.c:  change usage of krb5_crypto_us_timeofday to krb5_timeofday
+	* get_in_tkt.c:  change usage of  krb5_crypto_us_timeofday to krb5_timeofday
+	* mk_priv.c: change usage of krb5_crypto_us_timeofday to krb5_timeofday
+	* mk_req_ext.c: change usage of krb5_crypto_us_timeofday to krb5_timeofday
+	* send_tgs.c: change usage of krb5_timeofday over to krb5_crypto_us_timeofday
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * auth_con.c, decrypt_tk.c, encode_kdc.c, encrypt_tk.c,
+	* gc_frm_kdc.c, gen_seqnum.c, get_creds.c, get_in_tkt.c,
+	* in_tkt_ktb.c, in_tkt_pwd.c, in_tkt_sky.c, init_ctx.c,
+	* kdc_rep_dc.c, mk_cred.c, mk_priv.c, mk_rep.c, mk_req._ext.c,
+	* preauth.c, rd_cred.c, rd_priv.c, rd_rep.c, rd_req_dec.c,
+	* send_tgs.c, sendauth.c, ser_actx.c, ser_ctx.c, ser_eblk.c,
+	* ser_key.c, t_ser.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Wed Sept 6 12:00:00 EDT 1995	James Mattly	(mattly@fusion.com)
+
+	* get_in_tkt.c:  change usage of krb5_timeofday to krb5_crypto_us_timeofday
+	* mk_req_ext.c: change usage of timeofday
+	* parse.c:  disabled a usage of exit for macintosh
+	* send_tgs.c: change usage of krb5_timeofday over to
+		krb5_crypto_us_timeofday
+	* unparse.c: include <stdio.h>
+
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * decode_kdc.c, decrypt_tk.c, encode_kdc.c, encrypt_tk.c, gc_frm_kdc.c
+	* gc_via_tkt.c, get_in_tkt.c, in_tkt_ktb.c, in_tkt_pwd.c, in_tkt_sky.c
+	* init_ctx.c, kdc_rep_dc.c, mk_cred.c, mk_priv.c, mk_rep.c
+	* mk_req_ext.c, rd_cred.c, rd_priv.c, rd_rep.c, rd_req_dec.c,
+	* send_tgs.c, ser_ctx.c, ser_eblk.c, ser_key.c, t_ser.c: 
+		Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate
+
+Fri Sep  1 20:03:41 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* get_in_tkt.c (krb5_get_in_tkt): If kdc_settime is enabled, then
+		set the time_offset fields from the returned ticket's
+		authtime value.
+
+	* init_ctx.c (krb5_init_context): Initialize new fields in
+		krb5_context (clockskew, kdc_req_sumtype, and
+		kdc_default_options).
+
+	* gc_via_tkt.c (krb5_get_cred_via_tkt): Perform the necessary
+		sanity checking on the KDC response to make sure we detect
+		tampering.
+  
+	* send_tgs.c (krb5_send_tgs): Set the expected nonce in the
+		response structure.
+
+	* krbconfig.c: Set the default checksum to use MD5
+
+Fri Sep 1 11:16:43 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* ser_ctx.c - Add handling of new time offset fields in the os_context.
+
+
+Tue Aug 29 14:14:26 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in, .Sanitize, ser_{actx,adata,addr,auth,cksum,ctx,eblk,key,
+		princ}.c, serialize.c, t_ser.c - Add serialization operations
+		for data structures required to serialize krb5_context, krb5_
+		auth_context, krb5_encrypt_block and krb5_principal.
+	* auth_con.h - Add magic number.
+	* auth_con.c - Add static routine to copy an address and use this
+		instead of the other code.  Set the magic number when initing
+		an auth_context.  Use krb5_free_address to release an address.
+	* init_ctx.c - Free the allocated serializers when releasing context.
+	* rd_rep.c - Copy the keyblock from the message instead of setting
+		a pointer into it.
+
+Thu Aug 24 18:55:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list.
+
+Mon Aug  7 18:54:35 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* in_tkt_ktb.c (keytab_keyproc): If there is an error looking up
+		the key, make sure the keytab is closed as part of the
+		cleanup. 
+
+Fri Aug  4 22:04:08 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* conv_princ.c: Add braces to initializer to shut up gcc -Wall
+
+Fri Jul 7 16:31:06 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Find com_err in TOPLIBD.
+	* rd_safe.c - Use checksum verifier instead of doing it manually.
+
+Thu Jul  6 17:31:40 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* rd_safe.c (krb5_rd_safe_basic): Pass context to os_localaddr.
+
+	* rd_priv.c (krb5_rd_priv_basic): Pass context to os_localaddr.
+
+	* rd_cred.c (krb5_rd_cred_basic): Pass context to os_localaddr.
+
+	* get_in_tkt.c (krb5_get_in_tkt): Pass context to os_localaddr.
+
+Wed July  5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* added condition for _MACINTOSH
+
+Sun Jul  2 18:59:53 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* recvauth.c (krb5_recvauth): recvauth should send an error reply
+        if problem is not zero. Removed if that caused it to only send a
+        reply on success.
+
+Fri Jun 16 22:11:21 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* get_in_tkt.c (krb5_get_in_tkt): Allow the credentials cache
+		argument to be optional; allow it to be NULL, meaning that
+		the credentials shouldn't be stored in a credentials cache.
+
+Mon Jun 12 16:49:42 1995  Chris Provenzano (proven@mit.edu)
+
+	A couple bug reports/patches from Ed Phillips (flaregun@udel.edu)
+	* in_tkt_ktb.c (keytab_keyproc()): Fix memory leak. 
+	* recvauth.c (krb5_recvauth()): Don't open a new rcache if
+		the auth_context already has one.
+	* auth_con.c (krb5_auth_con_free()): Close rcache is the
+		auth_context has one set.
+	* auth_con.c (krb5_auth_con_getrcache()): Return pointer
+		to the rcache set in the auth_context.
+
+Sun Jun 11 12:31:39 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* auth_con.c (krb5_auth_con_init): Zero newly allocated
+		krb5_auth_context. (Fixed error in redefinitions).
+
+Sat Jun 10 23:05:51 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* auth_con.c, compat_recv.c, mk_cred.c, mk_priv.c, mk_rep.c,
+	  mk_req.c, mk_req_ext.c, mk_safe.c, rd_cred.c, rd_priv.c,
+	  rd_rep.c, rd_req.c rd_req_dec.c, rd_safe.c, recvauth.c,
+	  sendauth.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:48:43 1995    <tytso@rsx-11.mit.edu>
+
+	* rd_req_dec.c (krb5_rd_req_decoded): Fix -Wall nits
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+	* Makefile.in, faddr_ordr.c: Remove faddr_ordr.c; its function,
+		krb5_fulladdr_order, isn't used anywhere.
+
+Fri Jun  9 02:42:54 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* rd_cred.c (krb5_rd_cred_basic): fix typo (extra "context"
+		argument passed to krb5_xfree)
+
+Thu Jun  8 22:48:27 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rd_cred.c (krb5_rd_cred_basic): Fix problem where the ticket
+		field was assigned with a krb5_data, which was then
+		immediately freed.
+
+Thu Jun  8 16:06:44 1995    <tytso@rsx-11.mit.edu>
+
+	* compat_recv.c, auth_con.c, chk_trans.c, encrypt_tk.c,
+		gc_frm_kdc.c, gc_via_tkt.c, gen_seqnum.c, gen_subkey.c,
+		get_creds.c, get_in_tkt.c, in_tkt_ktb.c, in_tkt_pwd.c,
+		in_tkt_skey.c, init_ctx.c, kdc_rep_dc.c, mk_cred.c,
+		mk_error.c, mk_priv.c, mk_rep.c, mk_req.c, mk_req_ext.c,
+		mk_cred.c, mk_safe.c, parse.c, preauth.c, rd_cred.c,
+		rd_rep.c, rd_req.c, rd_req_dec.c, rd_safe.c, recvauth.c,
+		sendauth.c, send_tgs.c, srv_rcache.c, walk_rtree.c: Clean
+		up GCC -Wall flames.
+
+Wed Jun  7 15:23:21 1995    <tytso@rsx-11.mit.edu>
+
+	* conv_princ.c (krb5_425_conv_principal): Remove old CONFIG_FILES
+		code. 
+
+Fri May 26 10:18:28 1995 Keith Vetter (keithv@fusion.com)
+
+	* makefile.in: removed for the PC creating shared directory.
+	  (still bug with the '@SHARED_RULE@' line but I'm waiting
+	  on tytso for that since I don't want to break Unix).
+
+Thu May 25 09:58:42 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gc_via_tkt.c (krb5_kdcrep2creds): Fix syntax error in the
+		freeing of the keyblock.
+
+Wed May 24 18:19:17 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in, configure.in: Add rules for building shared library.
+
+	* gc_via_tkt.c (krb5_kdcrep2creds): On an error, free the keyblock.
+
+Tue May 23 16:28:42 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* gc_frm_kdc.c, preauth.c, t_kerb.c, t_walk_rtree.c, unparse.c:
+		Rearrange #include files so that krb5.h gets included
+		first, so that the debugging information can be more
+		efficiently collapsed since the type numbers will be the
+		same.
+
+Sat May 20 14:01:16 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rd_safe.c (krb5_rd_safe): Increment remote_seq_number if
+		KRB5_AUTH_CONTEXT_DO_SEQUENCE is set.
+
+Thu May 11 22:42:30 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rd_cred.c (krb5_rd_cred_basic): If address don't match, return
+		KRB5KRB_AP_ERR_BADADDR (add missing retval).
+
+Thu May 11 18:30:21 1995  Chris Provenzano (proven@mit.edu)
+
+	* mk_cred.c (krb5_mk_cred()), mk_priv.c (krb5_mk_priv()),
+	* mk_safe.c (krb5_mk_safe()), rd_cred.c (krb5_rd_cred()),
+	* rd_priv.c (krb5_rd_prev()), rd_safe.c (krb5_rd_safe()):
+		Pass the contents pointer returned from krb5_make_fulladdr()
+		to free() not the address of the pointer.
+
+Tue May  9 08:34:21 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean): Remove t_kerb and t_kerb.o
+
+Fri May  5 00:06:24 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* conv_princ.c (krb5_425_conv_principal): Use new calling
+		convention of krb5_get_realm_domain, which is that it
+		returns the realm *without* the leading dot.
+
+		Also use the profile code to look up individual instance
+		conversions using [realms]/<realm>/v4_instance_convert/<inst>
+		This allows special case handling of mit.edu and
+		lithium.lcs.mit.edu.
+
+	* t_kerb.c: New file for testing krb library functions.  Currently
+		only tests krb5_425_conv_principal.
+
+Wed May 03 03:30:51 1995  Chris Provenzano (proven@mit.edu)
+
+        * recvauth.c, compat_recv.c (krb5_recvauth()): 
+	* compat_recv.c (krb5_compat_recvauth()):
+		No longer needs the rc_type arg.
+
+Tue May 02 19:29:18 1995  Chris Provenzano (proven@mit.edu)
+
+        * mk_cred.c (mk_cred()), mk_priv.c (mk_priv()), mk_safe.c (mk_safe()),
+	* rd_cred.c (rd_cred()), rd_priv.c (rd_priv()), rd_safe.c (rd_safe()):
+		Don't call krb5_make_fulladdrs() if a port isn't specified.
+
+Mon May 01 15:56:32 1995  Chris Provenzano (proven@mit.edu)
+
+        * auth_con.c (krb5_auth_con_free()) :
+		Free all the data associated with the auth_context.
+
+	* auth_con.c (krb5_auth_con_setkey()) : Removed.
+	* mk_rep.c (mk_rep()),
+                The krb5_mk_rep() routine must always encode the data in
+                the keyblock of the ticket, not the subkey.
+
+	* cleanup.h, auth_con.c (krb5_auth_con_setports()) : Added.
+        * auth_con.h, mk_cred.c (mk_cred()), mk_priv.c (mk_priv()),
+	* mk_safe.c (mk_safe()), rd_cred.c (rd_cred()), 
+	* rd_priv.c (rd_priv()), rd_safe.c (rd_safe()) :
+		Changes to auth_context to better support full addresses.
+
+Sat Apr 29 00:09:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* srv_rcache.c (krb5_get_server_rcache): Fix fencepost error which
+		caused an access beyond the allocated memory of piece->data.
+
+	* rd_priv.c (krb5_rd_priv_basic): Call krb5_free_priv_enc_part to free 
+		the entire privenc_msg structure.
+
+Fri Apr 28 09:54:51 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	Move adm_rw.c from libkrb5 to libkadm.
+
+Fri Apr 28 08:36:03 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* init_ctx.c (krb5_free_context): Extra semicolon meant the etypes
+		field in the context was never being freed.
+
+Fri Apr 28 01:44:51 1995  Chris Provenzano  (proven@mit.edu)
+
+        * send_tgs.c (krb5_send_tgs()), gc_via_tkt.c (krb5_get_cred_via_tkt()):
+		Removed krb5_cksumtype argument.
+
+Thu Apr 27 21:36:01 1995  Chris Provenzano  (proven@mit.edu)
+
+	* auth_con.c (krb5_auth_con_getaddrs() and krb5_auth_con_getflags()):
+		Added for completeness.
+	* mk_req_ext.c (krb5_mk_req_extended()) : Don't send the 
+		AP_OPTS_USE_SUBKEY option over the wire.
+
+Thu Apr 27 17:40:20 1995 Keith Vetter (keithv@fusion.com)
+
+	* adm_rw.c, mk_cred.c, rd_cred.c:
+	   malloc on the PC must be size SIZE_T not int32.
+	* adm_rw.c: krb5_free_adm_data second argument now a krb5_int32.
+
+Thu Apr 27 16:33:17 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* mk_priv.c	- Back out previous change which always put in
+			  timestamp, regardless of DO_TIME setting and
+			  instead, clear out the replaydata before calling
+			  mk_priv_basic from mk_priv.
+	* mk_safe.c	- Same replaydata fix.
+
+Thu Apr 26 15:59:51 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* Add adm_rw.c - routines to read and write commands from/to the
+	  administrative (kpasswd/kadmin) server.
+
+Wed Apr 27 11:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* init_ctx.c: krb5_init_context wasn't checking return values.
+	* mk_req.c: deleted unused local variable.
+
+Wed Apr 26 22:49:18 1995  Chris Provenzano  (proven@mit.edu)
+
+	* gc_via_tgt.c, and gc_2tgt.c : Removed.
+	* Makefile.in, gc_via_tkt.c, gc_frm_kdc.c, and, int-proto.h : 
+		Replaced get_cred_via_tgt() and get_cred_via_2tgt()
+		with more general function get_cred_via_tkt().
+
+Tue Apr 25 21:58:23 1995  Chris Provenzano  (proven@mit.edu)
+
+	* Makefile.in : Added gc_via_tkt.c and removed get_fcreds.c
+	* auth_con.c (krb5_auth_con_setaddrs()) : Fixed so it allocates 
+		space and copies addresses, not just pointer.
+	* mk_cred.c: Completely rewritten from sources donated by asriniva.
+	* rd_cred.c: Completely rewritten from sources donated by asriniva.
+	* mk_priv.c (krb5_mk_priv()), mk_safe.c (krb5_mk_safe()), 
+	  rd_priv.c (krb5_rd_priv()), and rd_safe (krb5_rd_safe()) : 
+		Try using a subkey before using the session key for encryption.
+	* recvauth.c (krb5_recvauth()): Don't close the rcache on success.
+
+Mon Apr 24 23:12:21 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in, configure.in (t_walk_rtree): Add WITH_NETLIBS and
+		$(LIBS), so that t_walk_rtree can compile under solaris.
+
+Mon Apr 24 17:09:36 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* parse.c (krb5_parse_name): Add magic number to new structure
+
+	* get_creds.c: Fix comments describing operation
+
+	* gc_frm_kdc.c: Fix comments describing operation
+
+	* copy_cksum.c (krb5_copy_checksum): Fix comment in file
+
+	* copy_addrs.c (krb5_append_addresses): ifdef out unused
+		krb5_append_addresses function. (no API or prototype
+		existed). 
+
+	* copy_data.c (krb5_copy_data): Initialize magic number
+
+	* init_ctx.c (krb5_init_context): If an error is returned from
+		krb5_set_default_in_tkt_etypes or krb5_os_init_context,
+		pass to caller instead of stack garbage.
+
+Sat Apr 22 11:06:45 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* Makefile.in: t_walk_rtree needs libcrypto
+
+	* t_walk_rtree.c: error in checking for argument count
+
+Thu Apr 20 16:23:23 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* copy_addrs.c, copy_athctr.c, copy_auth.c, copy_cksum.c,
+	copy_creds.c, copy_key.c, copy_princ.c, copy_tick.c,
+	gc_2tgt.c, gc_frm_kdc.c, gc_via_tgt.c, get_creds.c,
+	mk_req_ext.c: Unless HAVE_C_STRUCTURE_ASSIGNMENT is defined, use
+		memcpy to copy structures around, instead of using
+		structure assignments.  (Which aren't guaranteed to work
+		on some broken compilers.)
+
+	* mk_req.c (krb5_mk_req): Use krb5_sname_to_principal() in order
+		to create the service principal from the service and
+		hostname pair.  This allows for the host cannoncialization
+		to work correctly.
+
+	* mk_req_ext.c (krb5_mk_req_extended): Revamp checksum handling
+		code so that no checksum is performed in in_data is NULL,
+		and the special case handing of cksumtype == 0x8003 for
+		the GSSAPI library is handled correctly.
+
+Wed Apr 19 13:39:34 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* init_ctx.c: (krb5_init_context) initialize context default
+		realm. (krb5_free_context) free default realm.
+
+Fri Apr 14 15:05:51 1995    <tytso@rsx-11.mit.edu>
+
+	* sendauth.c (krb5_sendauth): initialize error return parameter
+
+	* copy_princ.c (krb5_copy_principal): Fix bug where
+		krb5_copy_principal can fail if it is asked to copy a
+		principal with a zero-length component on a system where
+		malloc(0) returns null. 
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+
+Fri Mar 31 16:45:47 1995 Keith Vetter (keithv@fusion.com)
+
+	* krb5_get_in_tkt: changed error return value for when clocks
+           are out of skew to be KRB5_KDCREP_SKEW.
+
+Fri Mar 31 00:44:26 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rd_req.c (krb5_rd_req): Fix typo which caused new_keytab to not
+		get freed, causing a memory leak.
+
+Thu Mar 30 15:49:27 1995 Keith Vetter (keithv@fusion.com)
+
+	* rd_req.c: removed unused local variable.
+
+Tue Mar 28 18:34:20 1995  John Gilmore  (gnu at toad.com)
+
+	* rd_req_sim.c:  Really remove the file.
+
+Mon Mar 27 08:34:49 1995 Chris Provenzano (proven@mit.edu)
+
+	* Makefile.in: Removed rd_req_sim.c
+
+	* auth_con.c: Default cksumtype is now CKSUMTYPE_RSA_MD4_DES.
+
+	* auth_con.c: Added krb5_auth_con_setuseruserkey(), 
+		krb5_auth_con_getkey(), 
+		krb5_auth_con_getremotesubkey(),
+		krb5_auth_con_getauthenticator(), 
+		krb5_auth_con_getremoteseqnumber(),
+		krb5_auth_con_initivector().
+
+	* auth_con.c: Fixed krb5_auth_con_getlocalsubkey() to check for
+		a valid local_subkey before calling krb5_copy_keyblock().
+
+	* auth_con.h: Fixed some comments.
+
+	* mk_req_ext.c (krb5_mk_req_extended()): Always pass in a seed
+		(the keyblock contents) to krb5_calculate_checksum()
+
+	* rd_rep.c (krb5_rd_rep()): Use appropriate key to decode reply.
+
+	* rd_safe.c (krb5_rd_safe()): Don't pass checksum to 
+		krb5_rd_safe_basic(), it's unnecessary.
+
+	* compat_recv.c (krb5_compat_recvauth()):
+	* mk_rep.c (krb5_mk_rep()):
+	* rd_req.c (krb5_rd_req()):
+	* rd_req_dec.c (krb5_rd_req_decode()):
+	* recvauth.c (krb5_recvauth()):
+		Added a krb5_auth_context argument and eliminated many of 
+		the other arguments because they are included in the
+		krb5_auth_context structure.
+
+
+Tue Mar 21 19:22:51 1995 Keith Vetter (keithv@fusion.com)
+
+	* mk_safe.c: fixed signed/unsigned mismatch.
+	* rd_safe.c: removed unused local variable currentime.
+        * mk_req_e.c: fixed signed/unsigned mismatch.
+
+Sat Mar 18 18:58:02 1995  John Gilmore  (gnu at toad.com)
+
+	* bld_pr_ext.c, bld_princ.c:  Replace STDARG_PROTOTYPES with
+	HAVE_STDARG_H for consistency.
+
+Fri Mar 17 19:48:07 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (check-mac):  Add.
+	* compat_recv.c, get_fcreds.c, recvauth.c:  Eliminate Unix socket
+	#includes, which are now handled by k5-int.h (via k5-config.h).
+	* conv_princ.c:  Rename variable "comp" to another name; "comp"
+	apparently bothers the MPW compiler...
+	* rd_cred.c:  Avoid (void) casts of void functions, for MPW.
+	* t_walk_rtree.c:  Put com_err.h after k5_int for <sys/types> stuff.
+	(main):  Declare and initialize the krb5_context that's being
+	passed to everything.
+
+Fri Mar 10 10:58:59 1995  Chris Provenzano (proven@mit.edu)
+
+	* auth_con.h auth_con.c Added for krb5_auth_con definition and
+		support routines.
+
+	* mk_req.c (krb5_mk_req())
+	* mk_req_ext.c (krb5_mk_req_extended())
+	* rd_rep.c (krb5_rd_rep())
+	* sendauth.c (krb5_sendauth())
+	* mk_priv.c (krb5_mk_priv())
+	* mk_safe.c (krb5_mk_safe())
+	* rd_priv.c (krb5_rd_priv())
+	* rd_safe.c (krb5_rd_safe())
+		Added a krb5_auth_context argument and eliminated many of 
+		the other arguments because they are included in the
+		krb5_auth_context structure.
+
+	* send_tgs.c (krb5_send_tgs()) Eliminate call to krb5_mk_req_extended(),
+		which does far more than krb5_send_tgs() needs.
+
+Tue Mar  7 19:57:34 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: take out ISODE_INCLUDE.
+
+Tue Mar 7 13:20:06 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed library name on the pc.
+	* parse.c: disabled for the PC error messages to stderr.
+	* chk_trans.c: fixed signed/unsigned assignment.
+
+Thu Mar 2 11:45:00 1995 Keith Vetter (keithv@fusion.com)
+	
+	* compat_recv.c, get_fcre.c, recvauth.c, sendauth.c: changed
+	   NEED_WINSOCK_H to NEED_SOCKETS.
+
+Wed Mar 1 20:15:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* compat_r.c, copy_pri.c, get_fcre.c, get_in_t.c, init_ctx.c, in_tkt_p.c
+	   in_tkt_s.c, preauth.c, princ_co.c, pr_to_sa.c, rd_req_d.c, recvauth.c
+	   sendauth.c, send_tgs.c, unparse.c: 16 vs 32 bit casts, removed some
+	   unused local variables, and pulled in winsock.h for network byte
+	   ordering.
+
+Tue Feb 28 01:14:57 1995  John Gilmore  (gnu at toad.com)
+
+	* *.c:  Avoid <krb5/...> includes.
+	* parse.c:  Exdent #ifndef to left margin for old compilers.
+
+Wed Feb 22 17:14:31 1995 Keith Vetter (keithv@fusion.com)
+
+	* walk_rtr.c (krb5_walk_realm_tree): formal parameter wasn't declared.
+        * send_tgs.c: const in wrong place in the prototype.
+        * get_in_tkt.c, preauth.c, rd_cred.c, rd_priv.c, rd_req_dec.c, 
+           rd_safe.c: needed a 32 bit abs() function.
+        * parse.c: removed call to fprintf on error the windows version
+        * send_auth.c: defined for windows the ECONNABORTED errno (will
+           be removed when the socket layer is fully implemented).
+
+Tue Feb 21 23:38:34 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* mk_cred.c (krb5_mk_cred): Fix argument type to
+		krb5_free_cred_enc_part().
+
+Mon Feb 13 20:25:20 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* get_in_tkt.c (krb5_get_in_tkt): Fix memory leak --- the default
+		encryption types was not being freed.
+
+Fri Feb 10 15:45:59 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rd_req.c (krb5_rd_req): Remove ISODE cruft.
+
+Thu Feb  9 17:43:04 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gc_via_tgt.c (krb5_get_cred_via_tgt): Set up the keyblock's
+		etype field correctly (after copying the keyblock, so it
+		doesn't get overwritten!)
+
+Mon Feb 06 17:19:04 1995 Chris Provenzano  (proven@mit.edu)
+
+	* get_in_tkt.c (krb5_get_in_tkt())
+	* in_tkt_sky.c (krb5_get_in_tkt_with_skey())
+	* in_tkt_pwd.c (krb5_get_in_tkt_with_password())
+		Removed krb5_keytype, changed krb5_enctype to krb5_enctype *,
+		changed krb5_preauthtype to krb5_preauthtype *.
+
+		Changed the args to the key_proc arg of krb5_get_in_tkt()
+		to be the following (krb5_context, const krb5_keytype, 
+		krb5_data *, krb5_const_pointer, krb5_keyblock **)
+
+	* in_tkt_ktb.c (krb5_get_in_tkt_with_keytab()) Added this routine
+		to replace krb5_get_in_tkt_with_skey() in kinit.
+
+	* Makefile.in Added new source file in_tkt_ktb.c.
+		
+Fri Feb  3 16:41:19 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* get_in_tkt.c (krb5_get_in_tkt): also check for the version
+	number of the reply being whatever we had in the first byte of the
+	request.
+
+Fri Feb  3 08:07:55 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* compat_recv.c (krb_v4_recvauth): Use explicit 32 bit types so
+		this will work on an Alpha.
+
+Fri Feb  3 00:43:48 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* get_in_tkt.c (krb5_get_in_tkt): fix typo
+
+Thu Feb  2 20:51:55 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* get_in_tkt.c (krb5_get_in_tkt): if krb5_is_as_rep fails, check
+	if the packet might be a V4 error packet. Use modified V4 check so
+	that it compiles under SCO.
+
+Mon Jan 30 15:46:14 1995 Chris Provenzano (proven@mit.edu)
+
+	* int-proto.h Update prototypes for krb5_get_cred_via_tgt(), and
+		krb5_get_cred_via_2tgt().
+
+	* get_fcreds.c (krb5_get_for_creds()) 
+	* gc_via_tgt.c (krb5_get_cred_via_tgt())
+	* gc_2tgt.c (krb5_get_cred_via_2tgt())
+		Removed krb5_enctype argument. Pass NULL list of encryption
+		types to krb5_send_tgs to get default encryption types.
+
+	* gc_frm_kdc.c Removed krb5_enctype argument passed to 
+		krb5_get_cred_via_tgt()
+
+	* send_tgs.c (krb5_send_tgs()) Changed krb5_enctype arg to
+		krb5_enctype *, a NULL terminated array of encryption 
+		types. If argument is NULL then krb5_send_tgs() will 
+		use defaul list of encryption types.
+
+	* send_tgs.c (krb5_send_tgs()) To encrypt request ticket use
+		usecred->keyblock.etype instead of (and now defunct) 
+		krb5_enctype arg.
+
+	* init_ctx.c Added krb5_set_default_in_tkt_etypes() and
+		krb5_get_default_in_tkt_etypes().
+	
+	* rd_req.c, rd_req_decode.c Removed typedef for rdreq_key_proc
+		and use krb5_rd_req_decoded in its place.
+
+Mon Jan 30 11:26:05 1995 Chris Provenzano (proven@mit.edu)
+
+	* get_fcreds.c Really needs #include<krb5/asn1.h> for definition
+		of krb5_is_krb_error()
+
+Sat Jan 28 14:45:55 1995 Chris Provenzano (proven@mit.edu)
+
+	* in_tkt_sky.c (skey_keyproc()), rd_req_dec.c (krb5_rd_req_decoded())
+		use new API for krb5_kt_get_entry.
+
+Fri Jan 27 15:45:45 1995 Chris Provenzano (proven@mit.edu)
+
+	* get_fcreds.c Removed #include<krb5/crc-32.h> and #include<krb5/asn1.h>
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+	* Removed all narrow types and references to wide.h and narrow.h
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+	* Added krb5_context to all krb5_routines
+
+Mon Dec 19 21:55:44 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* init_ctx.c: New file.  Initializes and frees the krb5_context
+	  structure.
+
+Wed Dec  7 17:52:08 1994    <tytso@localhost>
+
+	* rd_req_dec.c (decrypt_authenticator): If the subkey doesn't
+		exist, don't try to set the subkey's etype.
+
+Wed Nov 30 17:10:39 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* bld_princ.c (krb5_build_principal_va): Set the principal's type
+		and magic number.
+
+        * Makefile.in: Build new test driver (t_walk_rtree) for
+		krb5_walk_realm_tree.
+
+ 	* walk_realm_tree.c (krb5_walk_realm_tree): Fix bug which occured
+		when the client or the server is a subdomain of the other;
+		walk_realm_tree would return the wrong answer, and suffer
+		from memory access errors.
+
+	* unparse.c (krb5_unparse_name_ext): Quote the '/' and '@'
+		characters properly.
+
+	* configure.in: Add appropriate help text for the --with-krb4
+		option.  Remove ISODE_DEFS call, since ISODE_INCLUDES now
+		defines ISODE automatically.
+
+Mon Nov 21 15:30:07 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* mk_req_ext.c (krb5_mk_req_extended): Sanitize how memory is
+		freed in both error and normal cases, to remove memory
+		leaks. 
+
+        * mk_req_ext.c (krb5_mk_req_extended): Use the encryption type
+		specified by the ticket to generate the authenticator.
+
+	* encode_kdc.c (krb5_encode_kdc_rep): Now requires that the
+		caller pass in the encryption block to be used for
+		encrpyting the ticket.  That way, this routine doesn't
+		need to create its own encryption block.
+
+	* encrypt_tk.c (krb5_encrypt_tkt_part): Now requires that the
+		caller pass in the encryption block to be used for
+		encrpyting the ticket.  That way, this routine doesn't
+		need to create its own encryption block.
+
+Fri Nov 18 17:30:44 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* mk_req_ext.c (krb5_mk_req_extended): Encrypt the authenticator
+		using the same encryption system used to encrypt the ticket.
+
+Thu Nov 17 01:56:05 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* gc_via_tgt.c (krb5_get_cred_via_tgt): 
+	* gc_2tgt.c (krb5_get_cred_via_2tgt): Set the encryption type of
+		the session keyblock to be the type used to encrypt the
+		ticket. 
+
+Fri Nov 11 01:20:22 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* get_in_tkt.c (krb5_get_in_tkt): Set the encryption type of the
+		session keyblock to be the type used to encrypt the
+		ticket. 
+
+Thu Nov 10 23:56:43 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rd_rep.c (krb5_rd_rep): Set the encryption type in
+		the subkey keyblock to be the encryption type used to
+		encrypt the rd_rep message.
+
+	* decrypt_tk.c (krb5_decrypt_tkt_part): Set the encryption type in
+		the session keyblock to be the encryption type used to
+		encrypt the ticket.
+
+	* rd_req_dec.c (decrypt_authenticator): Set the encryption type in
+		the subkey keyblock to be the encryption type used to
+		encrypt the authenticator. 
+
+Tue Nov  8 17:09:48 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* in_tkt_pwd.c (pwd_keyproc): Use the documented interface for
+		calling krb5_string_to_key().
+
+Tue Oct 25 23:34:57 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* srv_rcache.c (krb5_get_server_rcache): Added missing continue so
+	 	that we don't copy both the unprintable character as well
+		as the quoted version of it.
+
+Mon Oct 24 15:50:19 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: If KRB4 is defined, define KRB5_KRB4_COMPAT for
+		compat_recv.c.
+
+Thu Oct 13 17:26:28 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* configure.in: Add ISODE_DEFS
+
+Tue Oct  4 16:29:19 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* in_tkt_sky.c (skey_keyproc):
+	* in_tkt_pwd.c (pwd_keyproc): Add widen.h and narrow.h includes
+		around pwd_keyproc, so that the keyproc input arguments
+		are appropriately widened.
+
+Fri Sep 30 21:58:15 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* preauth.c (preauth_systems): Add placeholder for magic number
+
+Thu Sep 29 15:31:10 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* srv_rcache.c (krb5_get_server_rcache): cachename was not being
+		properly null-terminated.
+
+	* get_in_tkt.c (krb5_get_in_tkt): Return KRB5_IN_TKT_REALM_MISATCH
+		if the client and server realms don't match.  Return
+		KRB5_KDCREP_SKEW if the KDC reply has an unacceptible
+		clock skew (instead of KDCREP_MODIFIED.)
+
+	* gc_via_tgt.c (krb5_get_cred_via_tgt): Use a distinct error code
+		for KDC skew separate from the standard KDCREP_MODIFIED
+
+	* princ_comp.c (krb5_realm_compare): Added new function from
+		OpenVision.
+
+Wed Sep 21 17:57:35 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rd_req_dec.c (krb5_rd_req_decoded): Added Changes from Cybersafe
+		to do transited realm path checking.
+
+	* chk_trans.c: Added donated module from CyberSafe.  It checks to
+		see if a transited path is a legal one between two realms.
+
+Thu Sep 15 11:08:39 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rd_req_sim.c (krb5_rd_req_simple): Use krb5_rd_req instead of
+		krb5_rd_req_decoded, to eliminate some code duplication.
+
+Sat Aug 20 01:43:43 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* mk_req_ext.c (krb5_generate_authenticator): Fix pointer aliasing
+	problem between newkey and authent->subkey.
+
+Wed Aug 17 17:58:22 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* encode_kdc.c (krb5_encode_kdc_rep): Pass in to
+	encode_krb5_enc_kdc_rep_part the msg_type which should be used.
+	Old versions of Kerberos always assume TGS_REP; this merely allows
+	the right msg_type to be passed down to the encoding routines.
+	For now, the encoding routines will ignore this value and do
+	things the old way, for compatibility's sake.
+
+Mon Aug  8 22:38:16 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* preauth.c: Renamed preauthentication mechanism names to match
+	what bcn and I agreed upon.
+
+Tue Jun 28 19:35:07 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* decode_kdc.c: folding in Harry's changes
+	* rd_req.c: ditto
+	* rd_req_sim.c: ditto
+	* configure.in: adding ISODE_DEFS
+
diff --git a/mechglue/src/lib/krb5/krb/Makefile.in b/mechglue/src/lib/krb5/krb/Makefile.in
new file mode 100644
index 000000000..a15eb374e
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/Makefile.in
@@ -0,0 +1,933 @@
+thisconfigdir=./..
+myfulldir=lib/krb5/krb
+mydir=krb
+BUILDTOP=$(REL)..$(S)..$(S)..
+RUN_SETUP = @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+LOCALINCLUDES = -I$(srcdir)/../os -I$(SRCTOP)
+
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=krb
+##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
+
+STLIBOBJS= \
+	addr_comp.o	\
+	addr_order.o	\
+	addr_srch.o	\
+	appdefault.o	\
+	auth_con.o	\
+	bld_pr_ext.o	\
+	bld_princ.o	\
+	chk_trans.o	\
+	chpw.o		\
+	conv_creds.o	\
+	conv_princ.o	\
+	copy_addrs.o	\
+	copy_auth.o	\
+	copy_athctr.o	\
+	copy_cksum.o    \
+	copy_creds.o	\
+	copy_data.o	\
+	copy_key.o	\
+	copy_princ.o	\
+	copy_tick.o	\
+	cp_key_cnt.o	\
+	decode_kdc.o	\
+	decrypt_tk.o	\
+	deltat.o	\
+        enc_helper.o	\
+	encode_kdc.o	\
+	encrypt_tk.o	\
+	free_rtree.o	\
+	fwd_tgt.o	\
+	gc_frm_kdc.o	\
+	gc_via_tkt.o	\
+	gen_seqnum.o	\
+	gen_subkey.o	\
+	get_creds.o	\
+	get_in_tkt.o	\
+	gic_keytab.o	\
+	gic_opt.o	\
+	gic_pwd.o	\
+	in_tkt_sky.o	\
+	init_ctx.o	\
+	init_keyblock.o \
+	kdc_rep_dc.o	\
+	kfree.o		\
+	mk_cred.o	\
+	mk_error.o	\
+	mk_priv.o	\
+	mk_rep.o	\
+	mk_req.o	\
+	mk_req_ext.o	\
+	mk_safe.o	\
+	parse.o		\
+	pr_to_salt.o	\
+	preauth.o	\
+	preauth2.o	\
+	princ_comp.o	\
+	rd_cred.o	\
+	rd_error.o	\
+	rd_priv.o	\
+	rd_rep.o	\
+	rd_req.o	\
+	rd_req_dec.o	\
+	rd_safe.o	\
+	recvauth.o	\
+	sendauth.o	\
+	send_tgs.o	\
+	ser_actx.o	\
+	ser_adata.o	\
+	ser_addr.o	\
+	ser_auth.o	\
+	ser_cksum.o	\
+	ser_ctx.o	\
+	ser_key.o	\
+	ser_princ.o	\
+	serialize.o	\
+	set_realm.o	\
+	srv_rcache.o	\
+	str_conv.o	\
+	tgtname.o	\
+	unparse.o	\
+	v4lifetime.o	\
+	valid_times.o	\
+	vfy_increds.o	\
+	vic_opt.o	\
+	walk_rtree.o
+
+OBJS=	$(OUTPRE)addr_comp.$(OBJEXT)	\
+	$(OUTPRE)addr_order.$(OBJEXT)	\
+	$(OUTPRE)addr_srch.$(OBJEXT)	\
+	$(OUTPRE)appdefault.$(OBJEXT)	\
+	$(OUTPRE)auth_con.$(OBJEXT)	\
+	$(OUTPRE)bld_pr_ext.$(OBJEXT)	\
+	$(OUTPRE)bld_princ.$(OBJEXT)	\
+	$(OUTPRE)chk_trans.$(OBJEXT)	\
+	$(OUTPRE)chpw.$(OBJEXT)		\
+	$(OUTPRE)conv_creds.$(OBJEXT)	\
+	$(OUTPRE)conv_princ.$(OBJEXT)	\
+	$(OUTPRE)copy_addrs.$(OBJEXT)	\
+	$(OUTPRE)copy_auth.$(OBJEXT)	\
+	$(OUTPRE)copy_athctr.$(OBJEXT)	\
+	$(OUTPRE)copy_cksum.$(OBJEXT)    \
+	$(OUTPRE)copy_creds.$(OBJEXT)	\
+	$(OUTPRE)copy_data.$(OBJEXT)	\
+	$(OUTPRE)copy_key.$(OBJEXT)	\
+	$(OUTPRE)copy_princ.$(OBJEXT)	\
+	$(OUTPRE)copy_tick.$(OBJEXT)	\
+	$(OUTPRE)cp_key_cnt.$(OBJEXT)	\
+	$(OUTPRE)decode_kdc.$(OBJEXT)	\
+	$(OUTPRE)decrypt_tk.$(OBJEXT)	\
+	$(OUTPRE)deltat.$(OBJEXT)	\
+        $(OUTPRE)enc_helper.$(OBJEXT)	\
+	$(OUTPRE)encode_kdc.$(OBJEXT)	\
+	$(OUTPRE)encrypt_tk.$(OBJEXT)	\
+	$(OUTPRE)free_rtree.$(OBJEXT)	\
+	$(OUTPRE)fwd_tgt.$(OBJEXT)	\
+	$(OUTPRE)gc_frm_kdc.$(OBJEXT)	\
+	$(OUTPRE)gc_via_tkt.$(OBJEXT)	\
+	$(OUTPRE)gen_seqnum.$(OBJEXT)	\
+	$(OUTPRE)gen_subkey.$(OBJEXT)	\
+	$(OUTPRE)get_creds.$(OBJEXT)	\
+	$(OUTPRE)get_in_tkt.$(OBJEXT)	\
+	$(OUTPRE)gic_keytab.$(OBJEXT)	\
+	$(OUTPRE)gic_opt.$(OBJEXT)	\
+	$(OUTPRE)gic_pwd.$(OBJEXT)	\
+	$(OUTPRE)in_tkt_sky.$(OBJEXT)	\
+	$(OUTPRE)init_ctx.$(OBJEXT)	\
+	$(OUTPRE)init_keyblock.$(OBJEXT) \
+	$(OUTPRE)kdc_rep_dc.$(OBJEXT)	\
+	$(OUTPRE)kfree.$(OBJEXT)		\
+	$(OUTPRE)mk_cred.$(OBJEXT)	\
+	$(OUTPRE)mk_error.$(OBJEXT)	\
+	$(OUTPRE)mk_priv.$(OBJEXT)	\
+	$(OUTPRE)mk_rep.$(OBJEXT)	\
+	$(OUTPRE)mk_req.$(OBJEXT)	\
+	$(OUTPRE)mk_req_ext.$(OBJEXT)	\
+	$(OUTPRE)mk_safe.$(OBJEXT)	\
+	$(OUTPRE)parse.$(OBJEXT)		\
+	$(OUTPRE)pr_to_salt.$(OBJEXT)	\
+	$(OUTPRE)preauth.$(OBJEXT)	\
+	$(OUTPRE)preauth2.$(OBJEXT)	\
+	$(OUTPRE)princ_comp.$(OBJEXT)	\
+	$(OUTPRE)rd_cred.$(OBJEXT)	\
+	$(OUTPRE)rd_error.$(OBJEXT)	\
+	$(OUTPRE)rd_priv.$(OBJEXT)	\
+	$(OUTPRE)rd_rep.$(OBJEXT)	\
+	$(OUTPRE)rd_req.$(OBJEXT)	\
+	$(OUTPRE)rd_req_dec.$(OBJEXT)	\
+	$(OUTPRE)rd_safe.$(OBJEXT)	\
+	$(OUTPRE)recvauth.$(OBJEXT)	\
+	$(OUTPRE)sendauth.$(OBJEXT)	\
+	$(OUTPRE)send_tgs.$(OBJEXT)	\
+	$(OUTPRE)ser_actx.$(OBJEXT)	\
+	$(OUTPRE)ser_adata.$(OBJEXT)	\
+	$(OUTPRE)ser_addr.$(OBJEXT)	\
+	$(OUTPRE)ser_auth.$(OBJEXT)	\
+	$(OUTPRE)ser_cksum.$(OBJEXT)	\
+	$(OUTPRE)ser_ctx.$(OBJEXT)	\
+	$(OUTPRE)ser_key.$(OBJEXT)	\
+	$(OUTPRE)ser_princ.$(OBJEXT)	\
+	$(OUTPRE)serialize.$(OBJEXT)	\
+	$(OUTPRE)set_realm.$(OBJEXT)	\
+	$(OUTPRE)srv_rcache.$(OBJEXT)	\
+	$(OUTPRE)str_conv.$(OBJEXT)	\
+	$(OUTPRE)tgtname.$(OBJEXT)	\
+	$(OUTPRE)unparse.$(OBJEXT)	\
+	$(OUTPRE)v4lifetime.$(OBJEXT)	\
+	$(OUTPRE)valid_times.$(OBJEXT)	\
+	$(OUTPRE)vfy_increds.$(OBJEXT)	\
+	$(OUTPRE)vic_opt.$(OBJEXT)	\
+	$(OUTPRE)walk_rtree.$(OBJEXT)
+
+SRCS=	$(srcdir)/addr_comp.c	\
+	$(srcdir)/addr_order.c	\
+	$(srcdir)/addr_srch.c	\
+	$(srcdir)/appdefault.c	\
+	$(srcdir)/auth_con.c	\
+	$(srcdir)/bld_pr_ext.c	\
+	$(srcdir)/bld_princ.c	\
+	$(srcdir)/brand.c	\
+	$(srcdir)/chk_trans.c	\
+	$(srcdir)/chpw.c	\
+	$(srcdir)/conv_creds.c	\
+	$(srcdir)/conv_princ.c	\
+	$(srcdir)/copy_addrs.c	\
+	$(srcdir)/copy_auth.c	\
+	$(srcdir)/copy_athctr.c	\
+	$(srcdir)/copy_cksum.c   \
+	$(srcdir)/copy_creds.c	\
+	$(srcdir)/copy_data.c	\
+	$(srcdir)/copy_key.c	\
+	$(srcdir)/copy_princ.c	\
+	$(srcdir)/copy_tick.c	\
+	$(srcdir)/cp_key_cnt.c	\
+	$(srcdir)/decode_kdc.c	\
+	$(srcdir)/decrypt_tk.c	\
+	$(srcdir)/deltat.c	\
+	$(srcdir)/enc_helper.c	\
+	$(srcdir)/encode_kdc.c	\
+	$(srcdir)/encrypt_tk.c	\
+	$(srcdir)/free_rtree.c	\
+	$(srcdir)/fwd_tgt.c	\
+	$(srcdir)/gc_frm_kdc.c	\
+	$(srcdir)/gc_via_tkt.c	\
+	$(srcdir)/gen_seqnum.c	\
+	$(srcdir)/gen_subkey.c	\
+	$(srcdir)/get_creds.c	\
+	$(srcdir)/get_in_tkt.c	\
+	$(srcdir)/gic_keytab.c	\
+	$(srcdir)/gic_opt.c	\
+	$(srcdir)/gic_pwd.c	\
+	$(srcdir)/in_tkt_sky.c	\
+	$(srcdir)/init_ctx.c	\
+	$(srcdir)/init_keyblock.c \
+	$(srcdir)/kdc_rep_dc.c	\
+	$(srcdir)/kfree.c	\
+	$(srcdir)/mk_cred.c	\
+	$(srcdir)/mk_error.c	\
+	$(srcdir)/mk_priv.c	\
+	$(srcdir)/mk_rep.c	\
+	$(srcdir)/mk_req.c	\
+	$(srcdir)/mk_req_ext.c	\
+	$(srcdir)/mk_safe.c	\
+	$(srcdir)/parse.c	\
+	$(srcdir)/pr_to_salt.c	\
+	$(srcdir)/preauth.c	\
+	$(srcdir)/preauth2.c	\
+	$(srcdir)/princ_comp.c	\
+	$(srcdir)/rd_cred.c	\
+	$(srcdir)/rd_error.c	\
+	$(srcdir)/rd_priv.c	\
+	$(srcdir)/rd_rep.c	\
+	$(srcdir)/rd_req.c	\
+	$(srcdir)/rd_req_dec.c	\
+	$(srcdir)/rd_safe.c	\
+	$(srcdir)/recvauth.c	\
+	$(srcdir)/sendauth.c	\
+	$(srcdir)/send_tgs.c	\
+	$(srcdir)/ser_actx.c	\
+	$(srcdir)/ser_adata.c	\
+	$(srcdir)/ser_addr.c	\
+	$(srcdir)/ser_auth.c	\
+	$(srcdir)/ser_cksum.c	\
+	$(srcdir)/ser_ctx.c	\
+	$(srcdir)/ser_key.c	\
+	$(srcdir)/ser_princ.c	\
+	$(srcdir)/serialize.c	\
+	$(srcdir)/set_realm.c	\
+	$(srcdir)/srv_rcache.c	\
+	$(srcdir)/str_conv.c	\
+	$(srcdir)/tgtname.c	\
+	$(srcdir)/unparse.c	\
+	$(srcdir)/v4lifetime.c	\
+	$(srcdir)/valid_times.c	\
+	$(srcdir)/vfy_increds.c \
+	$(srcdir)/vic_opt.c	\
+	$(srcdir)/walk_rtree.c	\
+	$(srcdir)/t_walk_rtree.c \
+	$(srcdir)/t_kerb.c	\
+	$(srcdir)/t_ser.c	\
+	$(srcdir)/t_deltat.c	\
+	$(srcdir)/t_expand.c
+
+# Someday, when we have a "maintainer mode", do this right:
+BISON=bison
+BISONFLAGS= # -v -> .output; -d -> .h
+DELTAT_DEP=@MAINT@ x-deltat.y
+##WIN32##DELTAT_DEP=
+
+$(srcdir)/deltat.c : $(DELTAT_DEP)
+	(cd $(srcdir) && $(BISON) $(BISONFLAGS) -o deltat.c x-deltat.y)
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+
+COMERRLIB=$(TOPLIBD)/libcom_err.a
+
+T_WALK_RTREE_OBJS= t_walk_rtree.o walk_rtree.o tgtname.o unparse.o \
+	free_rtree.o bld_pr_ext.o 
+
+T_KERB_OBJS= t_kerb.o conv_princ.o unparse.o set_realm.o str_conv.o
+
+T_SER_OBJS= t_ser.o ser_actx.o ser_adata.o ser_addr.o ser_auth.o ser_cksum.o \
+	ser_ctx.o ser_key.o ser_princ.o serialize.o 
+
+T_DELTAT_OBJS= t_deltat.o deltat.o
+
+t_walk_rtree: $(T_WALK_RTREE_OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_walk_rtree $(T_WALK_RTREE_OBJS) $(KRB5_BASE_LIBS)
+
+t_kerb: $(T_KERB_OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_kerb $(T_KERB_OBJS) $(KRB5_BASE_LIBS)
+
+t_ser: $(T_SER_OBJS) $(KDB5_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_ser $(T_SER_OBJS) \
+		$(KDB5_LIBS) $(KRB5_BASE_LIBS) $(DL_LIB) $(THREAD_LINKOPTS)
+
+t_deltat : $(T_DELTAT_OBJS) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o t_deltat $(T_DELTAT_OBJS) $(SUPPORT_LIB)
+
+T_EXPAND_OBJS=t_expand.o
+t_expand.o : t_expand.c
+t_expand : $(T_EXPAND_OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_expand $(T_EXPAND_OBJS) $(KRB5_BASE_LIBS)
+
+TEST_PROGS= t_walk_rtree t_kerb t_ser t_deltat t_expand
+
+check-unix:: $(TEST_PROGS)
+	KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\
+	$(RUN_SETUP) ./t_kerb \
+		parse_name tytso \
+		parse_name tytso@SHAZAAM \
+		parse_name tytso/root@VEGGIE.COM \
+		parse_name tytso/tuber/carrot@VEGGIE.COM \
+		parse_name tytso/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t \
+		parse_name tytso/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t@FOO \
+		parse_name tytso\\\\0/\\0@B\\n\\t\\\\GAG \
+		parse_name tytso/\\n/\\b\\t@B\\0hacky-test \
+		parse_name \\/slash/\\@atsign/octa\\/thorpe@\\/slash\\@at\\/sign \
+		425_conv_principal rcmd e40-po ATHENA.MIT.EDU \
+		425_conv_principal rcmd mit ATHENA.MIT.EDU \
+		425_conv_principal rcmd lithium ATHENA.MIT.EDU \
+		425_conv_principal rcmd tweedledumb CYGNUS.COM \
+		425_conv_principal rcmd uunet UU.NET \
+		425_conv_principal zephyr zephyr ATHENA.MIT.EDU \
+		425_conv_principal kadmin ATHENA.MIT.EDU ATHENA.MIT.EDU \
+		524_conv_principal host/e40-po.mit.edu@ATHENA.MIT.EDU \
+		524_conv_principal host/foobar.stanford.edu@stanford.edu \
+		set_realm marc@MIT.EDU CYGNUS.COM \
+		> test.out
+	cmp test.out $(srcdir)/t_ref_kerb.out
+	$(RM) test.out
+	KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\
+		$(RUN_SETUP) ./t_ser
+	./t_deltat
+	$(RUN_SETUP) sh $(srcdir)/transit-tests
+
+clean::
+	$(RM) $(OUTPRE)t_walk_rtree$(EXEEXT) $(OUTPRE)t_walk_rtree.$(OBJEXT) \
+		$(OUTPRE)t_kerb$(EXEEXT) $(OUTPRE)t_kerb.$(OBJEXT)	\
+		$(OUTPRE)t_ser$(EXEEXT) $(OUTPRE)t_ser.$(OBJEXT)	\
+		$(OUTPRE)t_deltat$(EXEEXT) $(OUTPRE)t_deltat.$(OBJEXT) \
+		$(OUTPRE)t_expand$(EXEEXT) $(OUTPRE)t_expand.$(OBJEXT)
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+addr_comp.so addr_comp.po $(OUTPRE)addr_comp.$(OBJEXT): \
+  addr_comp.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+addr_order.so addr_order.po $(OUTPRE)addr_order.$(OBJEXT): \
+  addr_order.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+addr_srch.so addr_srch.po $(OUTPRE)addr_srch.$(OBJEXT): \
+  addr_srch.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+appdefault.so appdefault.po $(OUTPRE)appdefault.$(OBJEXT): \
+  appdefault.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+auth_con.so auth_con.po $(OUTPRE)auth_con.$(OBJEXT): \
+  auth_con.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+bld_pr_ext.so bld_pr_ext.po $(OUTPRE)bld_pr_ext.$(OBJEXT): \
+  bld_pr_ext.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+bld_princ.so bld_princ.po $(OUTPRE)bld_princ.$(OBJEXT): \
+  bld_princ.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+brand.so brand.po $(OUTPRE)brand.$(OBJEXT): brand.c \
+  $(SRCTOP)/patchlevel.h
+chk_trans.so chk_trans.po $(OUTPRE)chk_trans.$(OBJEXT): \
+  chk_trans.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+chpw.so chpw.po $(OUTPRE)chpw.$(OBJEXT): chpw.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/krb5_err.h \
+  auth_con.h
+conv_creds.so conv_creds.po $(OUTPRE)conv_creds.$(OBJEXT): \
+  conv_creds.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/kerberosIV/krb.h $(SRCTOP)/include/kerberosIV/des.h \
+  $(KRB_ERR_H_DEP)
+conv_princ.so conv_princ.po $(OUTPRE)conv_princ.$(OBJEXT): \
+  conv_princ.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_addrs.so copy_addrs.po $(OUTPRE)copy_addrs.$(OBJEXT): \
+  copy_addrs.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_auth.so copy_auth.po $(OUTPRE)copy_auth.$(OBJEXT): \
+  copy_auth.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_athctr.so copy_athctr.po $(OUTPRE)copy_athctr.$(OBJEXT): \
+  copy_athctr.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_cksum.so copy_cksum.po $(OUTPRE)copy_cksum.$(OBJEXT): \
+  copy_cksum.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_creds.so copy_creds.po $(OUTPRE)copy_creds.$(OBJEXT): \
+  copy_creds.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_data.so copy_data.po $(OUTPRE)copy_data.$(OBJEXT): \
+  copy_data.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_key.so copy_key.po $(OUTPRE)copy_key.$(OBJEXT): \
+  copy_key.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_princ.so copy_princ.po $(OUTPRE)copy_princ.$(OBJEXT): \
+  copy_princ.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+copy_tick.so copy_tick.po $(OUTPRE)copy_tick.$(OBJEXT): \
+  copy_tick.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+cp_key_cnt.so cp_key_cnt.po $(OUTPRE)cp_key_cnt.$(OBJEXT): \
+  cp_key_cnt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+decode_kdc.so decode_kdc.po $(OUTPRE)decode_kdc.$(OBJEXT): \
+  decode_kdc.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+decrypt_tk.so decrypt_tk.po $(OUTPRE)decrypt_tk.$(OBJEXT): \
+  decrypt_tk.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+deltat.so deltat.po $(OUTPRE)deltat.$(OBJEXT): deltat.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+enc_helper.so enc_helper.po $(OUTPRE)enc_helper.$(OBJEXT): \
+  enc_helper.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+encode_kdc.so encode_kdc.po $(OUTPRE)encode_kdc.$(OBJEXT): \
+  encode_kdc.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+encrypt_tk.so encrypt_tk.po $(OUTPRE)encrypt_tk.$(OBJEXT): \
+  encrypt_tk.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+free_rtree.so free_rtree.po $(OUTPRE)free_rtree.$(OBJEXT): \
+  free_rtree.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+fwd_tgt.so fwd_tgt.po $(OUTPRE)fwd_tgt.$(OBJEXT): fwd_tgt.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+gc_frm_kdc.so gc_frm_kdc.po $(OUTPRE)gc_frm_kdc.$(OBJEXT): \
+  gc_frm_kdc.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+gc_via_tkt.so gc_via_tkt.po $(OUTPRE)gc_via_tkt.$(OBJEXT): \
+  gc_via_tkt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+gen_seqnum.so gen_seqnum.po $(OUTPRE)gen_seqnum.$(OBJEXT): \
+  gen_seqnum.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+gen_subkey.so gen_subkey.po $(OUTPRE)gen_subkey.$(OBJEXT): \
+  gen_subkey.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+get_creds.so get_creds.po $(OUTPRE)get_creds.$(OBJEXT): \
+  get_creds.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+get_in_tkt.so get_in_tkt.po $(OUTPRE)get_in_tkt.$(OBJEXT): \
+  get_in_tkt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h $(srcdir)/../os/os-proto.h
+gic_keytab.so gic_keytab.po $(OUTPRE)gic_keytab.$(OBJEXT): \
+  gic_keytab.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+gic_opt.so gic_opt.po $(OUTPRE)gic_opt.$(OBJEXT): gic_opt.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+gic_pwd.so gic_pwd.po $(OUTPRE)gic_pwd.$(OBJEXT): gic_pwd.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+in_tkt_sky.so in_tkt_sky.po $(OUTPRE)in_tkt_sky.$(OBJEXT): \
+  in_tkt_sky.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+init_ctx.so init_ctx.po $(OUTPRE)init_ctx.$(OBJEXT): \
+  init_ctx.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  brand.c $(SRCTOP)/patchlevel.h $(srcdir)/../krb5_libinit.h
+init_keyblock.so init_keyblock.po $(OUTPRE)init_keyblock.$(OBJEXT): \
+  init_keyblock.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+kdc_rep_dc.so kdc_rep_dc.po $(OUTPRE)kdc_rep_dc.$(OBJEXT): \
+  kdc_rep_dc.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+kfree.so kfree.po $(OUTPRE)kfree.$(OBJEXT): kfree.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+mk_cred.so mk_cred.po $(OUTPRE)mk_cred.$(OBJEXT): mk_cred.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cleanup.h auth_con.h
+mk_error.so mk_error.po $(OUTPRE)mk_error.$(OBJEXT): \
+  mk_error.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+mk_priv.so mk_priv.po $(OUTPRE)mk_priv.$(OBJEXT): mk_priv.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cleanup.h auth_con.h
+mk_rep.so mk_rep.po $(OUTPRE)mk_rep.$(OBJEXT): mk_rep.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+mk_req.so mk_req.po $(OUTPRE)mk_req.$(OBJEXT): mk_req.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+mk_req_ext.so mk_req_ext.po $(OUTPRE)mk_req_ext.$(OBJEXT): \
+  mk_req_ext.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+mk_safe.so mk_safe.po $(OUTPRE)mk_safe.$(OBJEXT): mk_safe.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cleanup.h auth_con.h
+parse.so parse.po $(OUTPRE)parse.$(OBJEXT): parse.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+pr_to_salt.so pr_to_salt.po $(OUTPRE)pr_to_salt.$(OBJEXT): \
+  pr_to_salt.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+preauth.so preauth.po $(OUTPRE)preauth.$(OBJEXT): preauth.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+preauth2.so preauth2.po $(OUTPRE)preauth2.$(OBJEXT): \
+  preauth2.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+princ_comp.so princ_comp.po $(OUTPRE)princ_comp.$(OBJEXT): \
+  princ_comp.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+rd_cred.so rd_cred.po $(OUTPRE)rd_cred.$(OBJEXT): rd_cred.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cleanup.h auth_con.h
+rd_error.so rd_error.po $(OUTPRE)rd_error.$(OBJEXT): \
+  rd_error.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+rd_priv.so rd_priv.po $(OUTPRE)rd_priv.$(OBJEXT): rd_priv.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cleanup.h auth_con.h
+rd_rep.so rd_rep.po $(OUTPRE)rd_rep.$(OBJEXT): rd_rep.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+rd_req.so rd_req.po $(OUTPRE)rd_req.$(OBJEXT): rd_req.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+rd_req_dec.so rd_req_dec.po $(OUTPRE)rd_req_dec.$(OBJEXT): \
+  rd_req_dec.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+rd_safe.so rd_safe.po $(OUTPRE)rd_safe.$(OBJEXT): rd_safe.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  cleanup.h auth_con.h
+recvauth.so recvauth.po $(OUTPRE)recvauth.$(OBJEXT): \
+  recvauth.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+sendauth.so sendauth.po $(OUTPRE)sendauth.$(OBJEXT): \
+  sendauth.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+send_tgs.so send_tgs.po $(OUTPRE)send_tgs.$(OBJEXT): \
+  send_tgs.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ser_actx.so ser_actx.po $(OUTPRE)ser_actx.$(OBJEXT): \
+  ser_actx.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h auth_con.h
+ser_adata.so ser_adata.po $(OUTPRE)ser_adata.$(OBJEXT): \
+  ser_adata.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+ser_addr.so ser_addr.po $(OUTPRE)ser_addr.$(OBJEXT): \
+  ser_addr.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+ser_auth.so ser_auth.po $(OUTPRE)ser_auth.$(OBJEXT): \
+  ser_auth.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+ser_cksum.so ser_cksum.po $(OUTPRE)ser_cksum.$(OBJEXT): \
+  ser_cksum.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+ser_ctx.so ser_ctx.po $(OUTPRE)ser_ctx.$(OBJEXT): ser_ctx.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ser_key.so ser_key.po $(OUTPRE)ser_key.$(OBJEXT): ser_key.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+ser_princ.so ser_princ.po $(OUTPRE)ser_princ.$(OBJEXT): \
+  ser_princ.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+serialize.so serialize.po $(OUTPRE)serialize.$(OBJEXT): \
+  serialize.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+set_realm.so set_realm.po $(OUTPRE)set_realm.$(OBJEXT): \
+  set_realm.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+srv_rcache.so srv_rcache.po $(OUTPRE)srv_rcache.$(OBJEXT): \
+  srv_rcache.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+str_conv.so str_conv.po $(OUTPRE)str_conv.$(OBJEXT): \
+  str_conv.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+tgtname.so tgtname.po $(OUTPRE)tgtname.$(OBJEXT): tgtname.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+unparse.so unparse.po $(OUTPRE)unparse.$(OBJEXT): unparse.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+v4lifetime.so v4lifetime.po $(OUTPRE)v4lifetime.$(OBJEXT): \
+  v4lifetime.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+valid_times.so valid_times.po $(OUTPRE)valid_times.$(OBJEXT): \
+  valid_times.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+vfy_increds.so vfy_increds.po $(OUTPRE)vfy_increds.$(OBJEXT): \
+  vfy_increds.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+vic_opt.so vic_opt.po $(OUTPRE)vic_opt.$(OBJEXT): vic_opt.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+walk_rtree.so walk_rtree.po $(OUTPRE)walk_rtree.$(OBJEXT): \
+  walk_rtree.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  int-proto.h
+t_walk_rtree.so t_walk_rtree.po $(OUTPRE)t_walk_rtree.$(OBJEXT): \
+  t_walk_rtree.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+t_kerb.so t_kerb.po $(OUTPRE)t_kerb.$(OBJEXT): t_kerb.c \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/kerberosIV/krb.h \
+  $(SRCTOP)/include/kerberosIV/des.h $(KRB_ERR_H_DEP) \
+  $(BUILDTOP)/include/profile.h
+t_ser.so t_ser.po $(OUTPRE)t_ser.$(OBJEXT): t_ser.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  auth_con.h
+t_deltat.so t_deltat.po $(OUTPRE)t_deltat.$(OBJEXT): \
+  t_deltat.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+t_expand.so t_expand.po $(OUTPRE)t_expand.$(OBJEXT): \
+  t_expand.c chk_trans.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
diff --git a/mechglue/src/lib/krb5/krb/addr_comp.c b/mechglue/src/lib/krb5/krb/addr_comp.c
new file mode 100644
index 000000000..16ab03bbf
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/addr_comp.c
@@ -0,0 +1,48 @@
+/*
+ * lib/krb5/krb/addr_comp.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_address_compare()
+ */
+
+#include "k5-int.h"
+
+/*
+ * If the two addresses are the same, return TRUE, else return FALSE
+ */
+krb5_boolean KRB5_CALLCONV
+krb5_address_compare(krb5_context context, const krb5_address *addr1, const krb5_address *addr2)
+{
+    if (addr1->addrtype != addr2->addrtype)
+	return(FALSE);
+
+    if (addr1->length != addr2->length)
+	return(FALSE);
+    if (memcmp((char *)addr1->contents, (char *)addr2->contents,
+	       addr1->length))
+	return FALSE;
+    else
+	return TRUE;
+}
diff --git a/mechglue/src/lib/krb5/krb/addr_order.c b/mechglue/src/lib/krb5/krb/addr_order.c
new file mode 100644
index 000000000..2f01e1fbc
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/addr_order.c
@@ -0,0 +1,63 @@
+/*
+ * lib/krb5/krb/addr_order.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_address_order()
+ */
+
+#include "k5-int.h"
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * Return an ordering on two addresses:  0 if the same,
+ * < 0 if first is less than 2nd, > 0 if first is greater than 2nd.
+ */
+int KRB5_CALLCONV
+krb5_address_order(krb5_context context, const krb5_address *addr1, const krb5_address *addr2)
+{
+    int dir;
+    register int i;
+    const int minlen = min(addr1->length, addr2->length);
+
+    if (addr1->addrtype != addr2->addrtype)
+	return(FALSE);
+
+    dir = addr1->length - addr2->length;
+
+    
+    for (i = 0; i < minlen; i++) {
+	if ((unsigned char) addr1->contents[i] <
+	    (unsigned char) addr2->contents[i])
+	    return -1;
+	else if ((unsigned char) addr1->contents[i] >
+		 (unsigned char) addr2->contents[i])
+	    return 1;
+    }
+    /* compared equal so far...which is longer? */
+    return dir;
+}
diff --git a/mechglue/src/lib/krb5/krb/addr_srch.c b/mechglue/src/lib/krb5/krb/addr_srch.c
new file mode 100644
index 000000000..efab59f8f
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/addr_srch.c
@@ -0,0 +1,46 @@
+/*
+ * lib/krb5/krb/addr_srch.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_address_search()
+ */
+
+#include "k5-int.h"
+
+/*
+ * if addr is listed in addrlist, or addrlist is null, return TRUE.
+ * if not listed, return FALSE
+ */
+krb5_boolean
+krb5_address_search(krb5_context context, const krb5_address *addr, krb5_address *const *addrlist)
+{
+    if (!addrlist)
+	return TRUE;
+    for (; *addrlist; addrlist++) {
+	if (krb5_address_compare(context, addr, *addrlist))
+	    return TRUE;
+    }
+    return FALSE;
+}
diff --git a/mechglue/src/lib/krb5/krb/appdefault.c b/mechglue/src/lib/krb5/krb/appdefault.c
new file mode 100644
index 000000000..94788899b
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/appdefault.c
@@ -0,0 +1,166 @@
+/*
+ * appdefault - routines designed to be called from applications to
+ *		 handle the [appdefaults] profile section
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "k5-int.h"
+
+
+
+ /*xxx Duplicating this is annoying; try to work on a better way.*/
+static const char *const conf_yes[] = {
+	"y", "yes", "true", "t", "1", "on",
+	0,
+};
+
+static const char *const conf_no[] = {
+	"n", "no", "false", "nil", "0", "off",
+	0,
+};
+
+static int conf_boolean(char *s)
+{
+	const char * const *p;
+	for(p=conf_yes; *p; p++) {
+		if (!strcasecmp(*p,s))
+			return 1;
+	}
+	for(p=conf_no; *p; p++) {
+		if (!strcasecmp(*p,s))
+		return 0;
+	}
+	/* Default to "no" */
+	return 0;
+}
+
+static krb5_error_code appdefault_get(krb5_context context, const char *appname, const krb5_data *realm, const char *option, char **ret_value)
+{
+        profile_t profile;
+        const char *names[5];
+	char **nameval = NULL;
+	krb5_error_code retval;
+	const char * realmstr =  realm?realm->data:NULL;
+
+	    if (!context || (context->magic != KV5M_CONTEXT)) 
+	    return KV5M_CONTEXT;
+
+	    profile = context->profile;
+	    
+	/*
+	 * Try number one:
+	 *
+	 * [appdefaults]
+	 *	app = {
+	 *		SOME.REALM = {
+	 *			option = <boolean>
+	 *		}
+	 *	}
+	 */
+
+	names[0] = "appdefaults";
+	names[1] = appname;
+
+	if (realmstr) {
+		names[2] = realmstr;
+		names[3] = option;
+		names[4] = 0;
+		retval = profile_get_values(profile, names, &nameval);
+		if (retval == 0 && nameval && nameval[0]) {
+			*ret_value = strdup(nameval[0]);
+			goto goodbye;
+		}
+	}
+
+	/*
+	 * Try number two:
+	 *
+	 * [appdefaults]
+	 *	app = {
+	 *		option = <boolean>
+	 *      }
+	 */
+
+	names[2] = option;
+	names[3] = 0;
+	retval = profile_get_values(profile, names, &nameval);
+	if (retval == 0 && nameval && nameval[0]) {
+		*ret_value = strdup(nameval[0]);
+		goto goodbye;
+	}
+
+	/*
+	 * Try number three:
+	 *
+	 * [appdefaults]
+	 *	realm = {
+	 *		option = <boolean>
+	 */
+	
+	if (realmstr) {
+		names[1] = realmstr;
+		names[2] = option;
+		names[3] = 0;
+		retval = profile_get_values(profile, names, &nameval);
+		if (retval == 0 && nameval && nameval[0]) {
+			*ret_value = strdup(nameval[0]);
+			goto goodbye;
+		}
+	}
+
+	/*
+	 * Try number four:
+	 *
+	 * [appdefaults]
+	 *	option = <boolean>
+	 */
+
+	names[1] = option;
+	names[2] = 0;
+	retval = profile_get_values(profile, names, &nameval);
+	if (retval == 0 && nameval && nameval[0]) {
+		*ret_value = strdup(nameval[0]);
+	} else {
+		return retval;
+	}
+
+goodbye:
+	if (nameval) {
+		char **cpp;
+		for (cpp = nameval; *cpp; cpp++)
+			free(*cpp);
+		free(nameval);
+	}
+	return 0;
+}
+
+void KRB5_CALLCONV 
+krb5_appdefault_boolean(krb5_context context, const char *appname, const krb5_data *realm, const char *option, int default_value, int *ret_value)
+{
+	char *string = NULL;
+	krb5_error_code retval;
+
+	retval = appdefault_get(context, appname, realm, option, &string);
+
+	if (! retval && string) {
+		*ret_value = conf_boolean(string);
+		free(string);
+	} else
+		*ret_value = default_value;
+}
+
+void KRB5_CALLCONV 
+krb5_appdefault_string(krb5_context context, const char *appname, const krb5_data *realm, const char *option, const char *default_value, char **ret_value)
+{
+	krb5_error_code retval;
+	char *string;
+
+	retval = appdefault_get(context, appname, realm, option, &string);
+
+	if (! retval && string) {
+		*ret_value = string;
+	} else {
+		*ret_value = strdup(default_value);
+	}
+}
diff --git a/mechglue/src/lib/krb5/krb/auth_con.c b/mechglue/src/lib/krb5/krb/auth_con.c
new file mode 100644
index 000000000..cd3acf176
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/auth_con.c
@@ -0,0 +1,563 @@
+#include "k5-int.h"
+#include "auth_con.h"
+
+static krb5_boolean chk_heimdal_seqnum(krb5_ui_4, krb5_ui_4);
+
+static krb5_error_code
+actx_copy_addr(krb5_context context, const krb5_address *inad, krb5_address **outad)
+{
+    krb5_address *tmpad;
+
+    if (!(tmpad = (krb5_address *)malloc(sizeof(*tmpad))))
+	return ENOMEM;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tmpad = *inad;
+#else
+    memcpy(tmpad, inad, sizeof(krb5_address));
+#endif
+    if (!(tmpad->contents = (krb5_octet *)malloc(inad->length))) {
+	krb5_xfree(tmpad);
+	return ENOMEM;
+    }
+    memcpy((char *)tmpad->contents, (char *)inad->contents, inad->length);
+    *outad = tmpad;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_init(krb5_context context, krb5_auth_context *auth_context)
+{
+    *auth_context =
+            (krb5_auth_context)malloc(sizeof(struct _krb5_auth_context));
+    if (!*auth_context)
+	    return ENOMEM;
+    
+    memset(*auth_context, 0, sizeof(struct _krb5_auth_context));
+
+    /* Default flags, do time not seq */
+    (*auth_context)->auth_context_flags = 
+	    KRB5_AUTH_CONTEXT_DO_TIME |  KRB5_AUTH_CONN_INITIALIZED;
+
+    (*auth_context)->req_cksumtype = context->default_ap_req_sumtype;
+    (*auth_context)->safe_cksumtype = context->default_safe_sumtype;
+    (*auth_context) -> checksum_func = NULL;
+    (*auth_context)->checksum_func_data = NULL;
+    (*auth_context)->magic = KV5M_AUTH_CONTEXT;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
+{
+    if (auth_context->local_addr) 
+	krb5_free_address(context, auth_context->local_addr);
+    if (auth_context->remote_addr) 
+	krb5_free_address(context, auth_context->remote_addr);
+    if (auth_context->local_port) 
+	krb5_free_address(context, auth_context->local_port);
+    if (auth_context->remote_port) 
+	krb5_free_address(context, auth_context->remote_port);
+    if (auth_context->authentp) 
+	krb5_free_authenticator(context, auth_context->authentp);
+    if (auth_context->keyblock) 
+	krb5_free_keyblock(context, auth_context->keyblock);
+    if (auth_context->send_subkey) 
+	krb5_free_keyblock(context, auth_context->send_subkey);
+    if (auth_context->recv_subkey) 
+	krb5_free_keyblock(context, auth_context->recv_subkey);
+    if (auth_context->rcache)
+	krb5_rc_close(context, auth_context->rcache);
+    if (auth_context->permitted_etypes)
+	krb5_xfree(auth_context->permitted_etypes);
+    free(auth_context);
+    return 0;
+}
+
+krb5_error_code
+krb5_auth_con_setaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address *local_addr, krb5_address *remote_addr)
+{
+    krb5_error_code	retval;
+
+    /* Free old addresses */
+    if (auth_context->local_addr)
+	(void) krb5_free_address(context, auth_context->local_addr);
+    if (auth_context->remote_addr)
+	(void) krb5_free_address(context, auth_context->remote_addr);
+
+    retval = 0;
+    if (local_addr)
+	retval = actx_copy_addr(context,
+				local_addr,
+				&auth_context->local_addr);
+    else
+	auth_context->local_addr = NULL;
+
+    if (!retval && remote_addr)
+	retval = actx_copy_addr(context,
+				remote_addr,
+				&auth_context->remote_addr);
+    else
+	auth_context->remote_addr = NULL;
+
+    return retval;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getaddrs(krb5_context context, krb5_auth_context auth_context, krb5_address **local_addr, krb5_address **remote_addr)
+{
+    krb5_error_code	retval;
+
+    retval = 0;
+    if (local_addr && auth_context->local_addr) {
+	retval = actx_copy_addr(context,
+				auth_context->local_addr,
+				local_addr);
+    }
+    if (!retval && (remote_addr) && auth_context->remote_addr) {
+	retval = actx_copy_addr(context,
+				auth_context->remote_addr,
+				remote_addr);
+    }
+    return retval;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_setports(krb5_context context, krb5_auth_context auth_context, krb5_address *local_port, krb5_address *remote_port)
+{
+    krb5_error_code	retval;
+
+    /* Free old addresses */
+    if (auth_context->local_port)
+	(void) krb5_free_address(context, auth_context->local_port);
+    if (auth_context->remote_port)
+	(void) krb5_free_address(context, auth_context->remote_port);
+
+    retval = 0;
+    if (local_port)
+	retval = actx_copy_addr(context,
+				local_port,
+				&auth_context->local_port);
+    else
+	auth_context->local_port = NULL;
+
+    if (!retval && remote_port)
+	retval = actx_copy_addr(context,
+				remote_port,
+				&auth_context->remote_port);
+    else
+	auth_context->remote_port = NULL;
+
+    return retval;
+}
+
+
+/*
+ * This function overloads the keyblock field. It is only useful prior to
+ * a krb5_rd_req_decode() call for user to user authentication where the
+ * server has the key and needs to use it to decrypt the incoming request.
+ * Once decrypted this key is no longer necessary and is then overwritten
+ * with the session key sent by the client.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock)
+{
+    if (auth_context->keyblock)
+	krb5_free_keyblock(context, auth_context->keyblock);
+    return(krb5_copy_keyblock(context, keyblock, &(auth_context->keyblock)));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
+{
+    if (auth_context->keyblock)
+    	return krb5_copy_keyblock(context, auth_context->keyblock, keyblock);
+    *keyblock = NULL;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getlocalsubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
+{
+    return krb5_auth_con_getsendsubkey(context, auth_context, keyblock);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getremotesubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
+{
+    return krb5_auth_con_getrecvsubkey(context, auth_context, keyblock);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_setsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
+{
+    if (ac->send_subkey != NULL)
+	krb5_free_keyblock(ctx, ac->send_subkey);
+    ac->send_subkey = NULL;
+    if (keyblock !=NULL)
+	return krb5_copy_keyblock(ctx, keyblock, &ac->send_subkey);
+    else
+	return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_setrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
+{
+    if (ac->recv_subkey != NULL)
+	krb5_free_keyblock(ctx, ac->recv_subkey);
+    ac->recv_subkey = NULL;
+    if (keyblock != NULL)
+	return krb5_copy_keyblock(ctx, keyblock, &ac->recv_subkey);
+    else
+	return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getsendsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
+{
+    if (ac->send_subkey != NULL)
+	return krb5_copy_keyblock(ctx, ac->send_subkey, keyblock);
+    *keyblock = NULL;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock **keyblock)
+{
+    if (ac->recv_subkey != NULL)
+	return krb5_copy_keyblock(ctx, ac->recv_subkey, keyblock);
+    *keyblock = NULL;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_set_req_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
+{
+    auth_context->req_cksumtype = cksumtype;
+    return 0;
+}
+
+krb5_error_code
+krb5_auth_con_set_safe_cksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype)
+{
+    auth_context->safe_cksumtype = cksumtype;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getlocalseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
+{
+    *seqnumber = auth_context->local_seq_number;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getauthenticator(krb5_context context, krb5_auth_context auth_context, krb5_authenticator **authenticator)
+{
+    return (krb5_copy_authenticator(context, auth_context->authentp,
+				    authenticator));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getremoteseqnumber(krb5_context context, krb5_auth_context auth_context, krb5_int32 *seqnumber)
+{
+    *seqnumber = auth_context->remote_seq_number;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_initivector(krb5_context context, krb5_auth_context auth_context)
+{
+    krb5_error_code ret;
+
+    if (auth_context->keyblock) {
+	size_t blocksize;
+
+	if ((ret = krb5_c_block_size(context, auth_context->keyblock->enctype,
+				    &blocksize)))
+	    return(ret);
+	if ((auth_context->i_vector = (krb5_pointer)malloc(blocksize))) {
+	    memset(auth_context->i_vector, 0, blocksize);
+	    return 0;
+	}
+	return ENOMEM;
+    }
+    return EINVAL; /* XXX need an error for no keyblock */
+}
+
+krb5_error_code
+krb5_auth_con_setivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer ivector)
+{
+    auth_context->i_vector = ivector;
+    return 0;
+}
+
+krb5_error_code
+krb5_auth_con_getivector(krb5_context context, krb5_auth_context auth_context, krb5_pointer *ivector)
+{
+    *ivector = auth_context->i_vector;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_setflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 flags)
+{
+    auth_context->auth_context_flags = flags;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_getflags(krb5_context context, krb5_auth_context auth_context, krb5_int32 *flags)
+{
+    *flags = auth_context->auth_context_flags;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_setrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache rcache)
+{
+    auth_context->rcache = rcache;
+    return 0;
+}
+    
+krb5_error_code
+krb5_auth_con_getrcache(krb5_context context, krb5_auth_context auth_context, krb5_rcache *rcache)
+{
+    *rcache = auth_context->rcache;
+    return 0;
+}
+    
+krb5_error_code
+krb5_auth_con_setpermetypes(krb5_context context, krb5_auth_context auth_context, const krb5_enctype *permetypes)
+{
+    krb5_enctype	* newpe;
+    int i;
+
+    for (i=0; permetypes[i]; i++)
+	;
+    i++; /* include the zero */
+
+    if ((newpe = (krb5_enctype *) malloc(i*sizeof(krb5_enctype)))
+	== NULL)
+	return(ENOMEM);
+
+    if (auth_context->permitted_etypes)
+	krb5_xfree(auth_context->permitted_etypes);
+
+    auth_context->permitted_etypes = newpe;
+
+    memcpy(newpe, permetypes, i*sizeof(krb5_enctype));
+
+    return 0;
+}
+
+krb5_error_code
+krb5_auth_con_getpermetypes(krb5_context context, krb5_auth_context auth_context, krb5_enctype **permetypes)
+{
+    krb5_enctype	* newpe;
+    int i;
+
+    if (! auth_context->permitted_etypes) {
+	*permetypes = NULL;
+	return(0);
+    }
+
+    for (i=0; auth_context->permitted_etypes[i]; i++)
+	;
+    i++; /* include the zero */
+
+    if ((newpe = (krb5_enctype *) malloc(i*sizeof(krb5_enctype)))
+	== NULL)
+	return(ENOMEM);
+
+    *permetypes = newpe;
+
+    memcpy(newpe, auth_context->permitted_etypes, i*sizeof(krb5_enctype));
+
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_set_checksum_func( krb5_context context,
+				 krb5_auth_context  auth_context,
+				 krb5_mk_req_checksum_func func,
+				 void *data)
+{
+  auth_context->checksum_func = func;
+  auth_context->checksum_func_data = data;
+  return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_get_checksum_func( krb5_context context,
+				 krb5_auth_context auth_context,
+				 krb5_mk_req_checksum_func *func,
+				 void **data)
+{
+  *func = auth_context->checksum_func;
+  *data = auth_context->checksum_func_data;
+  return 0;
+}
+
+/*
+ * krb5int_auth_con_chkseqnum
+ *
+ * We use a somewhat complex heuristic for validating received
+ * sequence numbers.  We must accommodate both our older
+ * implementation, which sends negative sequence numbers, and the
+ * broken Heimdal implementation (at least as of 0.5.2), which
+ * violates X.690 BER for integer encodings.  The requirement of
+ * handling negative sequence numbers removes one of easier means of
+ * detecting a Heimdal implementation, so we resort to this mess
+ * here.
+ *
+ * X.690 BER (and consequently DER, which are the required encoding
+ * rules in RFC1510) encode all integer types as signed integers.
+ * This means that the MSB being set on the first octet of the
+ * contents of the encoding indicates a negative value.  Heimdal does
+ * not prepend the required zero octet to unsigned integer encodings
+ * which would otherwise have the MSB of the first octet of their
+ * encodings set.
+ *
+ * Our ASN.1 library implements a special decoder for sequence
+ * numbers, accepting both negative and positive 32-bit numbers but
+ * mapping them both into the space of positive unsigned 32-bit
+ * numbers in the obvious bit-pattern-preserving way.  This maintains
+ * compatibility with our older implementations.  This also means that
+ * encodings emitted by Heimdal are ambiguous.
+ *
+ * Heimdal counter value	received uint32 value
+ *
+ * 0x00000080			0xFFFFFF80
+ * 0x000000FF			0xFFFFFFFF
+ * 0x00008000			0xFFFF8000
+ * 0x0000FFFF			0xFFFFFFFF
+ * 0x00800000			0xFF800000
+ * 0x00FFFFFF			0xFFFFFFFF
+ * 0xFF800000			0xFF800000
+ * 0xFFFFFFFF			0xFFFFFFFF
+ *
+ * We use two auth_context flags, SANE_SEQ and HEIMDAL_SEQ, which are
+ * only set after we can unambiguously determine the sanity of the
+ * sending implementation.  Once one of these flags is set, we accept
+ * only the sequence numbers appropriate to the remote implementation
+ * type.  We can make the determination in two different ways.  The
+ * first is to note the receipt of a "negative" sequence number when a
+ * "positive" one was expected.  The second is to note the receipt of
+ * a sequence number that wraps through "zero" in a weird way.  The
+ * latter corresponds to the receipt of an initial sequence number in
+ * the ambiguous range.
+ *
+ * There are 2^7 + 2^15 + 2^23 + 2^23 = 16810112 total ambiguous
+ * initial Heimdal counter values, but we receive them as one of 2^23
+ * possible values.  There is a ~1/256 chance of a Heimdal
+ * implementation sending an intial sequence number in the ambiguous
+ * range.
+ *
+ * We have to do special treatment when receiving sequence numbers
+ * between 0xFF800000..0xFFFFFFFF, or when wrapping through zero
+ * weirdly (due to ambiguous initial sequence number).  If we are
+ * expecting a value corresponding to an ambiguous Heimdal counter
+ * value, and we receive an exact match, we can mark the remote end as
+ * sane.
+ */
+krb5_boolean
+krb5int_auth_con_chkseqnum(
+    krb5_context ctx,
+    krb5_auth_context ac,
+    krb5_ui_4 in_seq)
+{
+    krb5_ui_4 exp_seq;
+
+    exp_seq = ac->remote_seq_number;
+
+    /*
+     * If sender is known to be sane, accept _only_ exact matches.
+     */
+    if (ac->auth_context_flags & KRB5_AUTH_CONN_SANE_SEQ)
+	return in_seq == exp_seq;
+
+    /*
+     * If sender is not known to be sane, first check the ambiguous
+     * range of received values, 0xFF800000..0xFFFFFFFF.
+     */
+    if ((in_seq & 0xFF800000) == 0xFF800000) {
+	/*
+	 * If expected sequence number is in the range
+	 * 0xFF800000..0xFFFFFFFF, then we can't make any
+	 * determinations about the sanity of the sending
+	 * implementation.
+	 */
+	if ((exp_seq & 0xFF800000) == 0xFF800000 && in_seq == exp_seq)
+	    return 1;
+	/*
+	 * If sender is not known for certain to be a broken Heimdal
+	 * implementation, check for exact match.
+	 */
+	if (!(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)
+	    && in_seq == exp_seq)
+	    return 1;
+	/*
+	 * Now apply hairy algorithm for matching sequence numbers
+	 * sent by broken Heimdal implementations.  If it matches, we
+	 * know for certain it's a broken Heimdal sender.
+	 */
+	if (chk_heimdal_seqnum(exp_seq, in_seq)) {
+	    ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
+	    return 1;
+	}
+	return 0;
+    }
+
+    /*
+     * Received value not in the ambiguous range?  If the _expected_
+     * value is in the range of ambiguous Hemidal counter values, and
+     * it matches the received value, sender is known to be sane.
+     */
+    if (in_seq == exp_seq) {
+	if ((   exp_seq & 0xFFFFFF80) == 0x00000080
+	    || (exp_seq & 0xFFFF8000) == 0x00008000
+	    || (exp_seq & 0xFF800000) == 0x00800000)
+	    ac->auth_context_flags |= KRB5_AUTH_CONN_SANE_SEQ;
+	return 1;
+    }
+
+    /*
+     * Magic wraparound for the case where the intial sequence number
+     * is in the ambiguous range.  This means that the sender's
+     * counter is at a different count than ours, so we correct ours,
+     * and mark the sender as being a broken Heimdal implementation.
+     */
+    if (exp_seq == 0
+	&& !(ac->auth_context_flags & KRB5_AUTH_CONN_HEIMDAL_SEQ)) {
+	switch (in_seq) {
+	case 0x100:
+	case 0x10000:
+	case 0x1000000:
+	    ac->auth_context_flags |= KRB5_AUTH_CONN_HEIMDAL_SEQ;
+	    exp_seq = in_seq;
+	    return 1;
+	default:
+	    return 0;
+	}
+    }
+    return 0;
+}
+
+static krb5_boolean
+chk_heimdal_seqnum(krb5_ui_4 exp_seq, krb5_ui_4 in_seq)
+{
+    if (( exp_seq & 0xFF800000) == 0x00800000
+	&& (in_seq & 0xFF800000) == 0xFF800000
+	&& (in_seq & 0x00FFFFFF) == exp_seq)
+	return 1;
+    else if ((  exp_seq & 0xFFFF8000) == 0x00008000
+	     && (in_seq & 0xFFFF8000) == 0xFFFF8000
+	     && (in_seq & 0x0000FFFF) == exp_seq)
+	return 1;
+    else if ((  exp_seq & 0xFFFFFF80) == 0x00000080
+	     && (in_seq & 0xFFFFFF80) == 0xFFFFFF80
+	     && (in_seq & 0x000000FF) == exp_seq)
+	return 1;
+    else
+	return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/auth_con.h b/mechglue/src/lib/krb5/krb/auth_con.h
new file mode 100644
index 000000000..9543de355
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/auth_con.h
@@ -0,0 +1,36 @@
+
+#ifndef KRB5_AUTH_CONTEXT
+#define KRB5_AUTH_CONTEXT
+
+struct _krb5_auth_context {
+    krb5_magic		magic;
+    krb5_address      *	remote_addr;
+    krb5_address      *	remote_port;
+    krb5_address      *	local_addr;
+    krb5_address      *	local_port;
+    krb5_keyblock     * keyblock;
+    krb5_keyblock     * send_subkey;
+    krb5_keyblock     * recv_subkey;
+
+    krb5_int32		auth_context_flags;
+    krb5_ui_4		remote_seq_number;
+    krb5_ui_4		local_seq_number;
+    krb5_authenticator *authentp;		/* mk_req, rd_req, mk_rep, ...*/
+    krb5_cksumtype	req_cksumtype;		/* mk_safe, ... */
+    krb5_cksumtype	safe_cksumtype;		/* mk_safe, ... */
+    krb5_pointer	i_vector;		/* mk_priv, rd_priv only */
+    krb5_rcache		rcache;
+    krb5_enctype      * permitted_etypes;	/* rd_req */
+  krb5_mk_req_checksum_func checksum_func;
+  void *checksum_func_data;
+};
+
+
+/* Internal auth_context_flags */
+#define KRB5_AUTH_CONN_INITIALIZED	0x00010000
+#define KRB5_AUTH_CONN_USED_W_MK_REQ	0x00020000
+#define KRB5_AUTH_CONN_USED_W_RD_REQ	0x00040000
+#define KRB5_AUTH_CONN_SANE_SEQ		0x00080000
+#define KRB5_AUTH_CONN_HEIMDAL_SEQ	0x00100000
+
+#endif
diff --git a/mechglue/src/lib/krb5/krb/bld_pr_ext.c b/mechglue/src/lib/krb5/krb/bld_pr_ext.c
new file mode 100644
index 000000000..c1af72616
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/bld_pr_ext.c
@@ -0,0 +1,102 @@
+/*
+ * lib/krb5/krb/bld_pr_ext.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Build a principal from a list of lengths and strings
+ */
+
+#include "k5-int.h"
+
+#include <stdarg.h>
+
+krb5_error_code KRB5_CALLCONV_C
+krb5_build_principal_ext(krb5_context context,  krb5_principal * princ,
+			 unsigned int rlen, const char * realm, ...)
+{
+    va_list ap;
+    register int i, count = 0;
+    register unsigned int size;
+    register char *next;
+    char *tmpdata;
+    krb5_data *princ_data;
+    krb5_principal princ_ret;
+
+    va_start(ap, realm);
+    /* count up */
+    while (va_arg(ap, int) != 0) {
+	(void)va_arg(ap, char *);		/* pass one up */
+	count++;
+    }
+    va_end(ap);
+
+    /* we do a 2-pass to avoid the need to guess on allocation needs
+       cf. bld_princ.c */
+    /* get space for array */
+    princ_data = (krb5_data *) malloc(sizeof(krb5_data) * count);
+    if (!princ_data)
+	return ENOMEM;
+    princ_ret = (krb5_principal) malloc(sizeof(krb5_principal_data));
+    if (!princ_ret) {
+	krb5_xfree(princ_data);
+	return ENOMEM;
+    }
+    princ_ret->data = princ_data;
+    princ_ret->length = count;
+    tmpdata = malloc(rlen+1);
+    if (!tmpdata) {
+	krb5_xfree(princ_data);
+	krb5_xfree(princ_ret);
+	return ENOMEM;
+    }	
+    krb5_princ_set_realm_length(context, princ_ret, rlen);
+    krb5_princ_set_realm_data(context, princ_ret, tmpdata);
+    memcpy(tmpdata, realm, rlen);
+    tmpdata[rlen] = 0;
+
+    /* process rest of components */
+    va_start(ap, realm);
+    for (i = 0; i < count; i++) {
+	size = va_arg(ap, unsigned int);
+	next = va_arg(ap, char *);
+	princ_data[i].length = size;
+	princ_data[i].data = malloc(size+1);
+	if (!princ_data[i].data)
+	    goto free_out;
+	memcpy(princ_data[i].data, next, size);
+	princ_data[i].data[size] = 0;
+    }
+    va_end(ap);
+    *princ = princ_ret;
+    krb5_princ_type(context, princ_ret) = KRB5_NT_UNKNOWN;
+    return 0;
+
+free_out:
+    while (i-- >= 0)
+	krb5_xfree(princ_data[i].data);
+    krb5_xfree(princ_data);
+    krb5_xfree(princ_ret);
+    va_end(ap);
+    return ENOMEM;
+}
diff --git a/mechglue/src/lib/krb5/krb/bld_princ.c b/mechglue/src/lib/krb5/krb/bld_princ.c
new file mode 100644
index 000000000..c6cb7af05
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/bld_princ.c
@@ -0,0 +1,110 @@
+/*
+ * lib/krb5/krb/bld_princ.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Build a principal from a list of strings
+ */
+
+#include <stdarg.h>
+#include "k5-int.h"
+
+krb5_error_code
+KRB5_CALLCONV
+krb5_build_principal_va(krb5_context context, krb5_principal princ, unsigned int rlen, const char *realm, va_list ap)
+{
+    register int i, count = 0;
+    register char *next;
+    char *tmpdata;
+    krb5_data *data;
+
+    /* guess at an initial sufficent count of 2 pieces */
+    count = 2;
+
+    /* get space for array and realm, and insert realm */
+    data = (krb5_data *) malloc(sizeof(krb5_data) * count);
+    if (data == 0)
+	return ENOMEM;
+    krb5_princ_set_realm_length(context, princ, rlen);
+    tmpdata = malloc(rlen);
+    if (!tmpdata) {
+	free (data);
+	return ENOMEM;
+    }
+    krb5_princ_set_realm_data(context, princ, tmpdata);
+    memcpy(tmpdata, realm, rlen);
+
+    /* process rest of components */
+
+    for (i = 0, next = va_arg(ap, char *);
+	 next;
+	 next = va_arg(ap, char *), i++) {
+	if (i == count) {
+	    /* not big enough.  realloc the array */
+	    krb5_data *p_tmp;
+	    p_tmp = (krb5_data *) realloc((char *)data,
+					  sizeof(krb5_data)*(count*2));
+	    if (!p_tmp) {
+	    free_out:
+		    while (--i >= 0)
+			krb5_xfree(data[i].data);
+		    krb5_xfree(data);
+		    krb5_xfree(tmpdata);
+		    return (ENOMEM);
+	    }
+	    count *= 2;
+	    data = p_tmp;
+	}
+
+	data[i].length = strlen(next);
+	data[i].data = strdup(next);
+	if (!data[i].data)
+	    goto free_out;
+    }
+    princ->data = data;
+    princ->length = i;
+    princ->type = KRB5_NT_UNKNOWN;
+    princ->magic = KV5M_PRINCIPAL;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV_C
+krb5_build_principal(krb5_context context,  krb5_principal * princ, 
+		     unsigned int rlen,
+		     const char * realm, ...)
+{
+    va_list ap;
+    krb5_error_code retval;
+    krb5_principal pr_ret = (krb5_principal)malloc(sizeof(krb5_principal_data));
+
+    if (!pr_ret)
+	return ENOMEM;
+
+    va_start(ap, realm);
+    retval = krb5_build_principal_va(context, pr_ret, rlen, realm, ap);
+    va_end(ap);
+    if (retval == 0)
+	*princ = pr_ret;
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/brand.c b/mechglue/src/lib/krb5/krb/brand.c
new file mode 100644
index 000000000..7e4e0dbd0
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/brand.c
@@ -0,0 +1,72 @@
+/*
+ * lib/krb5/krb/brand.c
+ *
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * This file is used to put a "release brand" on a Krb5 library before
+ * it is released via some release engineering process.  This gives us
+ * an easy way to tell where a binary came from.
+ *
+ * It depends on patchlevel.h for the master version stamp info.
+ */
+
+/* Format: "KRB5_BRAND: <cvs_tag> <release_name> <date>" */
+
+#include "patchlevel.h"
+
+#define XSTR(x) #x
+#define STR(x) XSTR(x)
+
+#ifdef KRB5_RELTAG
+#define RELTAG KRB5_RELTAG
+#else
+#define RELTAG "[untagged]"
+#endif
+
+#define MAJOR_MINOR STR(KRB5_MAJOR_RELEASE) "." STR(KRB5_MINOR_RELEASE)
+
+#if KRB5_PATCHLEVEL != 0
+#define MAYBE_PATCH "." STR(KRB5_PATCHLEVEL)
+#else
+#define MAYBE_PATCH ""
+#endif
+
+#ifdef KRB5_RELTAIL
+#define RELTAIL "-" KRB5_RELTAIL
+#else
+#define RELTAIL ""
+#endif
+
+#define RELNAME MAJOR_MINOR MAYBE_PATCH RELTAIL
+
+#ifdef KRB5_RELDATE
+#define RELDATE KRB5_RELDATE
+#else
+#define RELDATE "[date unknown]"
+#endif
+
+#define BRANDSTR RELTAG " " RELNAME " " RELDATE
+
+static char krb5_brand[] = "KRB5_BRAND: " BRANDSTR;
diff --git a/mechglue/src/lib/krb5/krb/chk_trans.c b/mechglue/src/lib/krb5/krb/chk_trans.c
new file mode 100644
index 000000000..9fe73c878
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/chk_trans.c
@@ -0,0 +1,441 @@
+/*
+ * lib/krb5/krb/chk_trans.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_check_transited_list()
+ */
+#include "k5-int.h"
+#include <stdarg.h>
+
+#if defined (TEST) || defined (TEST2)
+# undef DEBUG
+# define DEBUG
+#endif
+
+#ifdef DEBUG
+#define verbose krb5int_chk_trans_verbose
+static int verbose = 0;
+# define Tprintf(ARGS) if (verbose) printf ARGS
+#else
+# define Tprintf(ARGS) (void)(0)
+#endif
+
+#define MAXLEN 512
+
+static krb5_error_code
+process_intermediates (krb5_error_code (*fn)(krb5_data *, void *), void *data,
+		       const krb5_data *n1, const krb5_data *n2) {
+    unsigned int len1, len2, i;
+    char *p1, *p2;
+
+    Tprintf (("process_intermediates(%.*s,%.*s)\n",
+	      (int) n1->length, n1->data, (int) n2->length, n2->data));
+
+    len1 = n1->length;
+    len2 = n2->length;
+
+    Tprintf (("(walking intermediates now)\n"));
+    /* Simplify...  */
+    if (len1 > len2) {
+	const krb5_data *p;
+	int tmp = len1;
+	len1 = len2;
+	len2 = tmp;
+	p = n1;
+	n1 = n2;
+	n2 = p;
+    }
+    /* Okay, now len1 is always shorter or equal.  */
+    if (len1 == len2) {
+	if (memcmp (n1->data, n2->data, len1)) {
+	    Tprintf (("equal length but different strings in path: '%.*s' '%.*s'\n",
+		      (int) n1->length, n1->data, (int) n2->length, n2->data));
+	    return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	}
+	Tprintf (("(end intermediates)\n"));
+	return 0;
+    }
+    /* Now len1 is always shorter.  */
+    if (len1 == 0)
+	/* Shouldn't be possible.  Internal error?  */
+	return KRB5KRB_AP_ERR_ILL_CR_TKT;
+    p1 = n1->data;
+    p2 = n2->data;
+    if (p1[0] == '/') {
+	/* X.500 style names, with common prefix.  */
+	if (p2[0] != '/') {
+	    Tprintf (("mixed name formats in path: x500='%.*s' domain='%.*s'\n",
+		      (int) len1, p1, (int) len2, p2));
+	    return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	}
+	if (memcmp (p1, p2, len1)) {
+	    Tprintf (("x500 names with different prefixes '%.*s' '%.*s'\n",
+		      (int) len1, p1, (int) len2, p2));
+	    return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	}
+	for (i = len1 + 1; i < len2; i++)
+	    if (p2[i] == '/') {
+		krb5_data d;
+		krb5_error_code r;
+
+		d.data = p2;
+		d.length = i;
+		r = (*fn) (&d, data);
+		if (r)
+		    return r;
+	    }
+    } else {
+	/* Domain style names, with common suffix.  */
+	if (p2[0] == '/') {
+	    Tprintf (("mixed name formats in path: domain='%.*s' x500='%.*s'\n",
+		      (int) len1, p1, (int) len2, p2));
+	    return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	}
+	if (memcmp (p1, p2 + (len2 - len1), len1)) {
+	    Tprintf (("domain names with different suffixes '%.*s' '%.*s'\n",
+		      (int) len1, p1, (int) len2, p2));
+	    return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	}
+	for (i = len2 - len1 - 1; i > 0; i--) {
+	    Tprintf (("looking at '%.*s'\n", (int) (len2 - i), p2+i));
+	    if (p2[i-1] == '.') {
+		krb5_data d;
+		krb5_error_code r;
+
+		d.data = p2+i;
+		d.length = len2 - i;
+		r = (*fn) (&d, data);
+		if (r)
+		    return r;
+	    }
+	}
+    }
+    Tprintf (("(end intermediates)\n"));
+    return 0;
+}
+
+static krb5_error_code
+maybe_join (krb5_data *last, krb5_data *buf, int bufsiz)
+{
+    if (buf->length == 0)
+	return 0;
+    if (buf->data[0] == '/') {
+	if (last->length + buf->length > bufsiz) {
+	    Tprintf (("too big: last=%d cur=%d max=%d\n", last->length, buf->length, bufsiz));
+	    return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	}
+	memmove (buf->data+last->length, buf->data, buf->length);
+	memcpy (buf->data, last->data, last->length);
+	buf->length += last->length;
+    } else if (buf->data[buf->length-1] == '.') {
+	/* We can ignore the case where the previous component was
+	   empty; the strcat will be a no-op.  It should probably
+	   be an error case, but let's be flexible.  */
+	if (last->length+buf->length > bufsiz) {
+	    Tprintf (("too big\n"));
+	    return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	}
+	memcpy (buf->data + buf->length, last->data, last->length);
+	buf->length += last->length;
+    }
+    /* Otherwise, do nothing.  */
+    return 0;
+}
+
+/* The input strings cannot contain any \0 bytes, according to the
+   spec, but our API is such that they may not be \0 terminated
+   either.  Thus we keep on treating them as krb5_data objects instead
+   of C strings.  */
+static krb5_error_code
+foreach_realm (krb5_error_code (*fn)(krb5_data *comp,void *data), void *data,
+	       const krb5_data *crealm, const krb5_data *srealm,
+	       const krb5_data *transit)
+{
+    char buf[MAXLEN], last[MAXLEN];
+    char *p, *bufp;
+    int next_lit, intermediates, l;
+    krb5_data this_component;
+    krb5_error_code r;
+    krb5_data last_component;
+
+    /* Invariants:
+       - last_component points to last[]
+       - this_component points to buf[]
+       - last_component has length of last
+       - this_component has length of buf when calling out
+       Keep these consistent, and we should be okay.  */
+
+    next_lit = 0;
+    intermediates = 0;
+    memset (buf, 0, sizeof (buf));
+
+    this_component.data = buf;
+    last_component.data = last;
+    last_component.length = 0;
+
+#define print_data(fmt,d) Tprintf((fmt,(int)(d)->length,(d)->data))
+    print_data ("client realm: %.*s\n", crealm);
+    print_data ("server realm: %.*s\n", srealm);
+    print_data ("transit enc.: %.*s\n", transit);
+
+    if (transit->length == 0) {
+	Tprintf (("no other realms transited\n"));
+	return 0;
+    }
+
+    bufp = buf;
+    for (p = transit->data, l = transit->length; l; p++, l--) {
+	if (next_lit) {
+	    *bufp++ = *p;
+	    if (bufp == buf+sizeof(buf))
+		return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	    next_lit = 0;
+	} else if (*p == '\\') {
+	    next_lit = 1;
+	} else if (*p == ',') {
+	    if (bufp != buf) {
+		this_component.length = bufp - buf;
+		r = maybe_join (&last_component, &this_component, sizeof(buf));
+		if (r)
+		    return r;
+		r = (*fn) (&this_component, data);
+		if (r)
+		    return r;
+		if (intermediates) {
+		    if (p == transit->data)
+			r = process_intermediates (fn, data,
+						   &this_component, crealm);
+		    else {
+			r = process_intermediates (fn, data, &this_component,
+						   &last_component);
+		    }
+		    if (r)
+			return r;
+		}
+		intermediates = 0;
+		memcpy (last, buf, sizeof (buf));
+		last_component.length = this_component.length;
+		memset (buf, 0, sizeof (buf));
+		bufp = buf;
+	    } else {
+		intermediates = 1;
+		if (p == transit->data) {
+		    if (crealm->length >= MAXLEN)
+			return KRB5KRB_AP_ERR_ILL_CR_TKT;
+		    memcpy (last, crealm->data, crealm->length);
+		    last[crealm->length] = '\0';
+		    last_component.length = crealm->length;
+		}
+	    }
+	} else if (*p == ' ' && bufp == buf) {
+	    /* This next component stands alone, even if it has a
+	       trailing dot or leading slash.  */
+	    memset (last, 0, sizeof (last));
+	    last_component.length = 0;
+	} else {
+	    /* Not a special character; literal.  */
+	    *bufp++ = *p;
+	    if (bufp == buf+sizeof(buf))
+		return KRB5KRB_AP_ERR_ILL_CR_TKT;
+	}
+    }
+    /* At end.  Must be normal state.  */
+    if (next_lit)
+	Tprintf (("ending in next-char-literal state\n"));
+    /* Process trailing element or comma.  */
+    if (bufp == buf) {
+	/* Trailing comma.  */
+	r = process_intermediates (fn, data, &last_component, srealm);
+    } else {
+	/* Trailing component.  */
+	this_component.length = bufp - buf;
+	r = maybe_join (&last_component, &this_component, sizeof(buf));
+	if (r)
+	    return r;
+	r = (*fn) (&this_component, data);
+	if (r)
+	    return r;
+	if (intermediates)
+	    r = process_intermediates (fn, data, &this_component,
+				       &last_component);
+    }
+    if (r != 0)
+	return r;
+    return 0;
+}
+
+
+struct check_data {
+    krb5_context ctx;
+    krb5_principal *tgs;
+};
+
+static int
+same_data (krb5_data *d1, krb5_data *d2)
+{
+    return (d1->length == d2->length
+	    && !memcmp (d1->data, d2->data, d1->length));
+}
+
+static krb5_error_code
+check_realm_in_list (krb5_data *realm, void *data)
+{
+    struct check_data *cdata = data;
+    int i;
+
+    Tprintf ((".. checking '%.*s'\n", (int) realm->length, realm->data));
+    for (i = 0; cdata->tgs[i]; i++) {
+	if (same_data (krb5_princ_realm (cdata->ctx, cdata->tgs[i]), realm))
+	    return 0;
+    }
+    Tprintf (("BAD!\n"));
+    return KRB5KRB_AP_ERR_ILL_CR_TKT;
+}
+
+krb5_error_code
+krb5_check_transited_list (krb5_context ctx, const krb5_data *trans_in,
+			   const krb5_data *crealm, const krb5_data *srealm)
+{
+    krb5_data trans;
+    struct check_data cdata;
+    krb5_error_code r;
+
+    trans.length = trans_in->length;
+    trans.data = (char *) trans_in->data;
+    if (trans.length && (trans.data[trans.length-1] == '\0'))
+	trans.length--;
+
+    Tprintf (("krb5_check_transited_list(trans=\"%.*s\", crealm=\"%.*s\", srealm=\"%.*s\")\n",
+	      (int) trans.length, trans.data,
+	      (int) crealm->length, crealm->data,
+	      (int) srealm->length, srealm->data));
+    if (trans.length == 0)
+	return 0;
+    r = krb5_walk_realm_tree (ctx, crealm, srealm, &cdata.tgs,
+			      KRB5_REALM_BRANCH_CHAR);
+    if (r) {
+	Tprintf (("error %ld\n", (long) r));
+	return r;
+    }
+#ifdef DEBUG /* avoid compiler warning about 'd' unused */
+    {
+	int i;
+	Tprintf (("tgs list = {\n"));
+	for (i = 0; cdata.tgs[i]; i++) {
+	    char *name;
+	    r = krb5_unparse_name (ctx, cdata.tgs[i], &name);
+	    Tprintf (("\t'%s'\n", name));
+	    free (name);
+	}
+	Tprintf (("}\n"));
+    }
+#endif
+    cdata.ctx = ctx;
+    r = foreach_realm (check_realm_in_list, &cdata, crealm, srealm, &trans);
+    krb5_free_realm_tree (ctx, cdata.tgs);
+    return r;
+}
+
+#ifdef TEST
+
+static krb5_error_code
+print_a_realm (krb5_data *realm, void *data)
+{
+    printf ("%.*s\n", (int) realm->length, realm->data);
+    return 0;
+}
+
+int main (int argc, char *argv[]) {
+    const char *me;
+    krb5_data crealm, srealm, transit;
+    krb5_error_code r;
+    int expand_only = 0;
+
+    me = strrchr (argv[0], '/');
+    me = me ? me+1 : argv[0];
+
+    while (argc > 3 && argv[1][0] == '-') {
+	if (!strcmp ("-v", argv[1]))
+	    verbose++, argc--, argv++;
+	else if (!strcmp ("-x", argv[1]))
+	    expand_only++, argc--, argv++;
+	else
+	    goto usage;
+    }
+
+    if (argc != 4) {
+    usage:
+	printf ("usage: %s [-v] [-x] clientRealm serverRealm transitEncoding\n",
+		me);
+	return 1;
+    }
+
+    crealm.data = argv[1];
+    crealm.length = strlen(argv[1]);
+    srealm.data = argv[2];
+    srealm.length = strlen(argv[2]);
+    transit.data = argv[3];
+    transit.length = strlen(argv[3]);
+
+    if (expand_only) {
+
+	printf ("client realm: %s\n", argv[1]);
+	printf ("server realm: %s\n", argv[2]);
+	printf ("transit enc.: %s\n", argv[3]);
+
+	if (argv[3][0] == 0) {
+	    printf ("no other realms transited\n");
+	    return 0;
+	}
+
+	r = foreach_realm (print_a_realm, NULL, &crealm, &srealm, &transit);
+	if (r)
+	    printf ("--> returned error %ld\n", (long) r);
+	return r != 0;
+
+    } else {
+
+	/* Actually check the values against the supplied krb5.conf file.  */
+	krb5_context ctx;
+	r = krb5_init_context (&ctx);
+	if (r) {
+	    com_err (me, r, "initializing krb5 context");
+	    return 1;
+	}
+	r = krb5_check_transited_list (ctx, &transit, &crealm, &srealm);
+	if (r == KRB5KRB_AP_ERR_ILL_CR_TKT) {
+	    printf ("NO\n");
+	} else if (r == 0) {
+	    printf ("YES\n");
+	} else {
+	    printf ("kablooey!\n");
+	    com_err (me, r, "checking transited-realm list");
+	    return 1;
+	}
+	return 0;
+    }
+}
+
+#endif /* TEST */
diff --git a/mechglue/src/lib/krb5/krb/chpw.c b/mechglue/src/lib/krb5/krb/chpw.c
new file mode 100644
index 000000000..640124601
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/chpw.c
@@ -0,0 +1,515 @@
+/*
+** set password functions added by Paul W. Nelson, Thursby Software Systems, Inc.
+*/
+#include <string.h>
+
+#include "k5-int.h"
+#include "krb5_err.h"
+#include "auth_con.h"
+
+
+krb5_error_code 
+krb5int_mk_chpw_req(krb5_context context, krb5_auth_context auth_context, krb5_data *ap_req, char *passwd, krb5_data *packet)
+{
+    krb5_error_code ret = 0;
+    krb5_data clearpw;
+    krb5_data cipherpw;
+    krb5_replay_data replay;
+    char *ptr;
+
+    cipherpw.data = NULL;
+
+    if ((ret = krb5_auth_con_setflags(context, auth_context,
+				      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
+	  goto cleanup;
+
+    clearpw.length = strlen(passwd);
+    clearpw.data = passwd;
+
+    if ((ret = krb5_mk_priv(context, auth_context,
+			    &clearpw, &cipherpw, &replay)))
+      goto cleanup;
+
+    packet->length = 6 + ap_req->length + cipherpw.length;
+    packet->data = (char *) malloc(packet->length);
+    if (packet->data == NULL)
+	  {
+	    ret = ENOMEM;
+	    goto cleanup;
+	  }
+    ptr = packet->data;
+
+    /* length */
+
+    *ptr++ = (packet->length>>8) & 0xff;
+    *ptr++ = packet->length & 0xff;
+
+    /* version == 0x0001 big-endian */
+
+    *ptr++ = 0;
+    *ptr++ = 1;
+
+    /* ap_req length, big-endian */
+
+    *ptr++ = (ap_req->length>>8) & 0xff;
+    *ptr++ = ap_req->length & 0xff;
+
+    /* ap-req data */
+
+    memcpy(ptr, ap_req->data, ap_req->length);
+    ptr += ap_req->length;
+
+    /* krb-priv of password */
+
+    memcpy(ptr, cipherpw.data, cipherpw.length);
+
+cleanup:
+    if(cipherpw.data != NULL)  /* allocated by krb5_mk_priv */
+      free(cipherpw.data);
+      
+    return(ret);
+}
+
+krb5_error_code 
+krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
+{
+    char *ptr;
+    int plen, vno;
+    krb5_data ap_rep;
+    krb5_ap_rep_enc_part *ap_rep_enc;
+    krb5_error_code ret;
+    krb5_data cipherresult;
+    krb5_data clearresult;
+    krb5_error *krberror;
+    krb5_replay_data replay;
+    krb5_keyblock *tmp;
+
+    if (packet->length < 4)
+	/* either this, or the server is printing bad messages,
+	   or the caller passed in garbage */
+	return(KRB5KRB_AP_ERR_MODIFIED);
+
+    ptr = packet->data;
+
+    /* verify length */
+
+    plen = (*ptr++ & 0xff);
+    plen = (plen<<8) | (*ptr++ & 0xff);
+
+    if (plen != packet->length)
+	return(KRB5KRB_AP_ERR_MODIFIED);
+
+    /* verify version number */
+
+    vno = (*ptr++ & 0xff);
+    vno = (vno<<8) | (*ptr++ & 0xff);
+
+    if (vno != 1)
+	return(KRB5KDC_ERR_BAD_PVNO);
+
+    /* read, check ap-rep length */
+
+    ap_rep.length = (*ptr++ & 0xff);
+    ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff);
+
+    if (ptr + ap_rep.length >= packet->data + packet->length)
+	return(KRB5KRB_AP_ERR_MODIFIED);
+
+    if (ap_rep.length) {
+	/* verify ap_rep */
+	ap_rep.data = ptr;
+	ptr += ap_rep.length;
+
+	/*
+	 * Save send_subkey to later smash recv_subkey.
+	 */
+	ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmp);
+	if (ret)
+	    return ret;
+
+	ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
+	if (ret) {
+	    krb5_free_keyblock(context, tmp);
+	    return(ret);
+	}
+
+	krb5_free_ap_rep_enc_part(context, ap_rep_enc);
+
+	/* extract and decrypt the result */
+
+	cipherresult.data = ptr;
+	cipherresult.length = (packet->data + packet->length) - ptr;
+
+	/*
+	 * Smash recv_subkey to be send_subkey, per spec.
+	 */
+	ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmp);
+	krb5_free_keyblock(context, tmp);
+	if (ret)
+	    return ret;
+
+	ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
+			   &replay);
+
+	if (ret)
+	    return(ret);
+    } else {
+	cipherresult.data = ptr;
+	cipherresult.length = (packet->data + packet->length) - ptr;
+
+	if ((ret = krb5_rd_error(context, &cipherresult, &krberror)))
+	    return(ret);
+
+	clearresult = krberror->e_data;
+    }
+
+    if (clearresult.length < 2) {
+	ret = KRB5KRB_AP_ERR_MODIFIED;
+	goto cleanup;
+    }
+
+    ptr = clearresult.data;
+
+    *result_code = (*ptr++ & 0xff);
+    *result_code = (*result_code<<8) | (*ptr++ & 0xff);
+
+    if ((*result_code < KRB5_KPASSWD_SUCCESS) ||
+	(*result_code > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)) {
+	ret = KRB5KRB_AP_ERR_MODIFIED;
+	goto cleanup;
+    }
+
+    /* all success replies should be authenticated/encrypted */
+
+    if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS)) {
+	ret = KRB5KRB_AP_ERR_MODIFIED;
+	goto cleanup;
+    }
+
+    result_data->length = (clearresult.data + clearresult.length) - ptr;
+
+    if (result_data->length) {
+	result_data->data = (char *) malloc(result_data->length);
+	if (result_data->data == NULL) {
+	    ret = ENOMEM;
+	    goto cleanup;
+	}
+	memcpy(result_data->data, ptr, result_data->length);
+    } else {
+	result_data->data = NULL;
+    }
+
+    ret = 0;
+
+cleanup:
+    if (ap_rep.length) {
+	krb5_xfree(clearresult.data);
+    } else {
+	krb5_free_error(context, krberror);
+    }
+
+    return(ret);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_chpw_result_code_string(krb5_context context, int result_code, char **code_string)
+{
+   switch (result_code) {
+   case KRB5_KPASSWD_MALFORMED:
+      *code_string = "Malformed request error";
+      break;
+   case KRB5_KPASSWD_HARDERROR:
+      *code_string = "Server error";
+      break;
+   case KRB5_KPASSWD_AUTHERROR:
+      *code_string = "Authentication error";
+      break;
+   case KRB5_KPASSWD_SOFTERROR:
+      *code_string = "Password change rejected";
+      break;
+   default:
+      *code_string = "Password change failed";
+      break;
+   }
+
+   return(0);
+}
+
+krb5_error_code 
+krb5int_mk_setpw_req(
+     krb5_context context,
+     krb5_auth_context auth_context,
+     krb5_data *ap_req,
+     krb5_principal targprinc,
+     char *passwd,
+     krb5_data *packet )
+{
+    krb5_error_code ret;
+    krb5_data	cipherpw;
+    krb5_data	*encoded_setpw;
+
+    char *ptr;
+
+     cipherpw.data = NULL;
+     cipherpw.length = 0;
+     
+    if ((ret = krb5_auth_con_setflags(context, auth_context,
+				      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
+		return(ret);
+
+    ret = encode_krb5_setpw_req(targprinc, passwd, &encoded_setpw);
+    if (ret) {
+	return ret;
+    }
+
+    if ( (ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
+	krb5_free_data( context, encoded_setpw);
+	return(ret);
+    }
+    krb5_free_data( context, encoded_setpw);
+    
+
+    packet->length = 6 + ap_req->length + cipherpw.length;
+    packet->data = (char *) malloc(packet->length);
+    if (packet->data  == NULL) {
+	ret = ENOMEM;
+	goto cleanup;
+    }
+    ptr = packet->data;
+/*
+** build the packet -
+*/
+/* put in the length */
+    *ptr++ = (packet->length>>8) & 0xff;
+    *ptr++ = packet->length & 0xff;
+/* put in the version */
+    *ptr++ = (char)0xff;
+    *ptr++ = (char)0x80;
+/* the ap_req length is big endian */
+    *ptr++ = (ap_req->length>>8) & 0xff;
+    *ptr++ = ap_req->length & 0xff;
+/* put in the request data */
+    memcpy(ptr, ap_req->data, ap_req->length);
+    ptr += ap_req->length;
+/*
+** put in the "private" password data -
+*/
+    memcpy(ptr, cipherpw.data, cipherpw.length);
+    ret = 0;
+ cleanup:
+    if (cipherpw.data)
+	krb5_free_data_contents(context, &cipherpw);
+    if ((ret != 0) && packet->data) {
+	free( packet->data);
+	packet->data = NULL;
+    }
+    return ret;
+}
+
+krb5_error_code 
+krb5int_rd_setpw_rep( krb5_context context, krb5_auth_context auth_context, krb5_data *packet,
+     int *result_code, krb5_data *result_data )
+{
+    char *ptr;
+    unsigned int message_length, version_number;
+    krb5_data ap_rep;
+    krb5_ap_rep_enc_part *ap_rep_enc;
+    krb5_error_code ret;
+    krb5_data cipherresult;
+    krb5_data clearresult;
+    krb5_keyblock *tmpkey;
+/*
+** validate the packet length -
+*/
+    if (packet->length < 4)
+	return(KRB5KRB_AP_ERR_MODIFIED);
+
+    ptr = packet->data;
+
+/*
+** see if it is an error
+*/
+    if (krb5_is_krb_error(packet)) {
+	krb5_error *krberror;
+	if ((ret = krb5_rd_error(context, packet, &krberror)))
+	    return(ret);
+	if (krberror->e_data.data  == NULL) {
+	    ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
+	    krb5_free_error(context, krberror);
+	    return (ret);
+	}
+	clearresult = krberror->e_data;
+	krberror->e_data.data  = NULL; /*So we can free it later*/
+	krberror->e_data.length = 0;
+	krb5_free_error(context, krberror);
+		
+    } else { /* Not an error*/
+
+/*
+** validate the message length -
+** length is big endian 
+*/
+	message_length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
+	ptr += 2;
+/*
+** make sure the message length and packet length agree -
+*/
+	if (message_length != packet->length)
+	    return(KRB5KRB_AP_ERR_MODIFIED);
+/*
+** get the version number -
+*/
+	version_number = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
+	ptr += 2;
+/*
+** make sure we support the version returned -
+*/
+/*
+** set password version is 0xff80, change password version is 1
+*/
+	if (version_number != 0xff80 && version_number != 1)
+	    return(KRB5KDC_ERR_BAD_PVNO);
+/*
+** now fill in ap_rep with the reply -
+*/
+/*
+** get the reply length -
+*/
+	ap_rep.length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
+	ptr += 2;
+/*
+** validate ap_rep length agrees with the packet length -
+*/
+	if (ptr + ap_rep.length >= packet->data + packet->length)
+	    return(KRB5KRB_AP_ERR_MODIFIED);
+/*
+** if data was returned, set the ap_rep ptr -
+*/
+	if( ap_rep.length ) {
+	    ap_rep.data = ptr;
+	    ptr += ap_rep.length;
+
+	    /*
+	     * Save send_subkey to later smash recv_subkey.
+	     */
+	    ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmpkey);
+	    if (ret)
+		return ret;
+
+	    ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
+	    if (ret) {
+		krb5_free_keyblock(context, tmpkey);
+		return(ret);
+	    }
+
+	    krb5_free_ap_rep_enc_part(context, ap_rep_enc);
+/*
+** now decrypt the result -
+*/
+	    cipherresult.data = ptr;
+	    cipherresult.length = (packet->data + packet->length) - ptr;
+
+	    /*
+	     * Smash recv_subkey to be send_subkey, per spec.
+	     */
+	    ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmpkey);
+	    krb5_free_keyblock(context, tmpkey);
+	    if (ret)
+		return ret;
+
+	    ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
+			       NULL);
+	    if (ret)
+		return(ret);
+	} /*We got an ap_rep*/
+	else
+	    return (KRB5KRB_AP_ERR_MODIFIED);
+    } /*Response instead of error*/
+
+/*
+** validate the cleartext length 
+*/
+    if (clearresult.length < 2) {
+	ret = KRB5KRB_AP_ERR_MODIFIED;
+	goto cleanup;
+    }
+/*
+** now decode the result -
+*/
+    ptr = clearresult.data;
+
+    *result_code = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
+    ptr += 2;
+
+/*
+** result code 5 is access denied
+*/
+    if ((*result_code < KRB5_KPASSWD_SUCCESS) || (*result_code > 5))
+    {
+	ret = KRB5KRB_AP_ERR_MODIFIED;
+	goto cleanup;
+    }
+/*
+** all success replies should be authenticated/encrypted
+*/
+    if( (ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS) )
+    {
+	ret = KRB5KRB_AP_ERR_MODIFIED;
+	goto cleanup;
+    }
+
+    if (result_data) {
+	result_data->length = (clearresult.data + clearresult.length) - ptr;
+
+	if (result_data->length)
+	{
+	    result_data->data = (char *) malloc(result_data->length);
+	    if (result_data->data)
+		memcpy(result_data->data, ptr, result_data->length);
+	}
+	else
+	    result_data->data = NULL;
+    }
+    ret = 0;
+
+ cleanup:
+    krb5_free_data_contents(context, &clearresult);
+    return(ret);
+}
+
+krb5_error_code 
+krb5int_setpw_result_code_string( krb5_context context, int result_code, const char **code_string )
+{
+   switch (result_code)
+   {
+   case KRB5_KPASSWD_MALFORMED:
+      *code_string = "Malformed request error";
+      break;
+   case KRB5_KPASSWD_HARDERROR:
+      *code_string = "Server error";
+      break;
+   case KRB5_KPASSWD_AUTHERROR:
+      *code_string = "Authentication error";
+      break;
+   case KRB5_KPASSWD_SOFTERROR:
+      *code_string = "Password change rejected";
+      break;
+   case 5: /* access denied */
+      *code_string = "Access denied";
+      break;
+   case 6:	/* bad version */
+      *code_string = "Wrong protocol version";
+      break;
+   case 7: /* initial flag is needed */
+      *code_string = "Initial password required";
+      break;
+   case 0:
+	  *code_string = "Success";
+   default:
+      *code_string = "Password change failed";
+      break;
+   }
+
+   return(0);
+}
+
diff --git a/mechglue/src/lib/krb5/krb/cleanup.h b/mechglue/src/lib/krb5/krb/cleanup.h
new file mode 100644
index 000000000..94b39f757
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/cleanup.h
@@ -0,0 +1,29 @@
+
+#ifndef KRB5_CLEANUP
+#define KRB5_CLEANUP
+
+struct cleanup {
+    void 		* arg;
+    void		(*func)(void *);
+};
+
+#define CLEANUP_INIT(x)							\
+    struct cleanup cleanup_data[x];					\
+    int cleanup_count = 0;		
+
+#define CLEANUP_PUSH(x, y)						\
+    cleanup_data[cleanup_count].arg = x;				\
+    cleanup_data[cleanup_count].func = y;				\
+    cleanup_count++;
+
+#define CLEANUP_POP(x)							\
+    if ((--cleanup_count) && x && (cleanup_data[cleanup_count].func)) 	\
+	cleanup_data[cleanup_count].func(cleanup_data[cleanup_count].arg); 
+	
+#define CLEANUP_DONE()							\
+    while(cleanup_count--) 						\
+	if (cleanup_data[cleanup_count].func)  				\
+	    cleanup_data[cleanup_count].func(cleanup_data[cleanup_count].arg); 
+    
+
+#endif
diff --git a/mechglue/src/lib/krb5/krb/conv_creds.c b/mechglue/src/lib/krb5/krb/conv_creds.c
new file mode 100644
index 000000000..68af73301
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/conv_creds.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "port-sockets.h"
+#include "socket-utils.h"
+
+#if defined(KRB5_KRB4_COMPAT) || defined(_WIN32) /* yuck */
+#include "kerberosIV/krb.h"
+
+#ifdef USE_CCAPI
+#include <CredentialsCache.h>
+#endif
+
+#define krb524_debug krb5int_krb524_debug
+int krb524_debug = 0;
+
+static krb5_error_code krb524_convert_creds_plain
+(krb5_context context, krb5_creds *v5creds, 
+		   CREDENTIALS *v4creds);
+
+static int decode_v4tkt
+	(struct ktext *v4tkt, char *buf, unsigned int *encoded_len);
+
+krb5_error_code KRB5_CALLCONV
+krb5_524_convert_creds(krb5_context context, krb5_creds *v5creds,
+		       CREDENTIALS *v4creds)
+{
+     krb5_error_code ret;
+     krb5_data reply;
+     char *p;
+     struct sockaddr_storage ss;
+     socklen_t slen = sizeof(ss);
+
+     ret = krb524_convert_creds_plain(context, v5creds, v4creds);
+     if (ret)
+	 return ret;
+
+     reply.data = NULL;
+     ret = krb5int_524_sendto_kdc(context, &v5creds->ticket,
+				  &v5creds->server->realm, &reply,
+				  ss2sa(&ss), &slen);
+     if (ret)
+	 return ret;
+
+#if TARGET_OS_MAC
+#ifdef USE_CCAPI
+     v4creds->stk_type = cc_v4_stk_des;
+#endif
+     if (slen == sizeof(struct sockaddr_in)
+	 && ss2sa(&ss)->sa_family == AF_INET) {
+	 v4creds->address = ss2sin(&ss)->sin_addr.s_addr;
+     }
+     /* Otherwise, leave it set to all-zero.  */
+#endif
+
+     p = reply.data;
+     ret = ntohl(*((krb5_error_code *) p));
+     p += sizeof(krb5_int32);
+     reply.length -= sizeof(krb5_int32);
+     if (ret)
+	 goto fail;
+
+     v4creds->kvno = ntohl(*((krb5_error_code *) p));
+     p += sizeof(krb5_int32);
+     reply.length -= sizeof(krb5_int32);
+     ret = decode_v4tkt(&v4creds->ticket_st, p, &reply.length);
+
+fail:
+     if (reply.data) 
+	 free(reply.data);
+     reply.data = NULL;
+     return ret;
+}
+
+static krb5_error_code
+krb524_convert_creds_plain(context, v5creds, v4creds)
+     krb5_context context;
+     krb5_creds *v5creds;
+     CREDENTIALS *v4creds;
+{
+     int ret;
+     krb5_timestamp endtime;
+     char dummy[REALM_SZ];
+     memset((char *) v4creds, 0, sizeof(CREDENTIALS));
+
+     if ((ret = krb5_524_conv_principal(context, v5creds->client,
+					v4creds->pname, v4creds->pinst,
+					dummy)))
+	 return ret;
+     if ((ret = krb5_524_conv_principal(context, v5creds->server,
+					v4creds->service, v4creds->instance,
+					v4creds->realm)))
+	 return ret;
+
+     /* Check enctype too */
+     if (v5creds->keyblock.length != sizeof(C_Block)) {
+	  if (krb524_debug)
+	       fprintf(stderr, "v5 session keyblock length %d != C_Block size %d\n",
+		       v5creds->keyblock.length,
+		       (int) sizeof(C_Block));
+	  return KRB524_BADKEY;
+     } else
+	  memcpy(v4creds->session, (char *) v5creds->keyblock.contents,
+		 sizeof(C_Block));
+
+     /* V4 has no concept of authtime or renew_till, so ignore them */
+     v4creds->issue_date = v5creds->times.starttime;
+     v4creds->lifetime = krb5int_krb_time_to_life(v5creds->times.starttime,
+						  v5creds->times.endtime);
+     endtime = krb5int_krb_life_to_time(v4creds->issue_date,
+					v4creds->lifetime);
+     /*
+      * Adjust start time backwards to deal with rounding up in
+      * krb_time_to_life(), to match code on server side.
+      */
+     if (endtime > v5creds->times.endtime)
+	 v4creds->issue_date -= endtime - v5creds->times.endtime;
+
+     return 0;
+}
+
+/* this used to be krb524/encode.c, under same copyright as above */
+/*
+ * I'm sure that this is reinventing the wheel, but I don't know where
+ * the wheel is hidden.
+ */
+
+int  encode_v4tkt (KTEXT_ST *, char *, unsigned int *);
+static int encode_bytes (char **, int *, char *, unsigned int),
+    encode_int32 (char **, int *, krb5_int32 *);
+
+static int decode_bytes (char **, int *, char *, unsigned int),
+    decode_int32 (char **, int *, krb5_int32 *);
+
+static int encode_bytes(out, outlen, in, len)
+     char **out;
+     int *outlen;
+     char *in;
+     unsigned int len;
+{
+     if (len > *outlen)
+	  return KRB524_ENCFULL;
+     memcpy(*out, in, len);
+     *out += len;
+     *outlen -= len;
+     return 0;
+}
+
+static int encode_int32(out, outlen, v)
+     char **out;
+     int *outlen;
+     krb5_int32 *v;
+{
+     krb5_int32 nv; /* Must be 4 bytes */
+
+     nv = htonl(*v);
+     return encode_bytes(out, outlen, (char *) &nv, sizeof(nv));
+}
+
+int krb5int_encode_v4tkt(v4tkt, buf, encoded_len)
+     KTEXT_ST *v4tkt;
+     char *buf;
+     unsigned int *encoded_len;
+{
+     int buflen, ret;
+     krb5_int32 temp;
+
+     buflen = *encoded_len;
+
+     if (v4tkt->length < MAX_KTXT_LEN)
+	  memset(v4tkt->dat + v4tkt->length, 0, 
+		 (unsigned int) (MAX_KTXT_LEN - v4tkt->length));
+     temp = v4tkt->length;
+     if ((ret = encode_int32(&buf, &buflen, &temp)))
+	  return ret;
+     if ((ret = encode_bytes(&buf, &buflen, (char *)v4tkt->dat, MAX_KTXT_LEN)))
+	  return ret;
+     temp = v4tkt->mbz;
+     if ((ret = encode_int32(&buf, &buflen, &temp)))
+	  return ret;
+
+     *encoded_len -= buflen;
+     return 0;
+}
+
+/* decode functions */
+
+static int decode_bytes(out, outlen, in, len)
+     char **out;
+     int *outlen;
+     char *in; 
+     unsigned int len;
+{
+     if (len > *outlen)
+	  return KRB524_DECEMPTY;
+     memcpy(in, *out, len);
+     *out += len;
+     *outlen -= len;
+     return 0;
+}
+
+static int decode_int32(out, outlen, v)
+     char **out;
+     int *outlen;
+     krb5_int32 *v;
+{
+     int ret;
+     krb5_int32 nv; /* Must be four bytes */
+
+     if ((ret = decode_bytes(out, outlen, (char *) &nv, sizeof(nv))))
+	  return ret;
+     *v = ntohl(nv);
+     return 0;
+}
+
+static int decode_v4tkt(v4tkt, buf, encoded_len)
+     KTEXT_ST *v4tkt;
+     char *buf;
+     unsigned int *encoded_len;
+{
+     int buflen, ret;
+     krb5_int32 temp;
+
+     buflen = *encoded_len;
+     if ((ret = decode_int32(&buf, &buflen, &temp)))
+	  return ret;
+     v4tkt->length = temp;
+     if ((ret = decode_bytes(&buf, &buflen, (char *)v4tkt->dat, MAX_KTXT_LEN)))
+	  return ret;
+     if ((ret = decode_int32(&buf, &buflen, &temp)))
+	  return ret;
+     v4tkt->mbz = temp;
+     *encoded_len -= buflen;
+     return 0;
+}
+
+#else /* no krb4 compat */
+
+krb5_error_code KRB5_CALLCONV
+krb5_524_convert_creds(krb5_context context, krb5_creds *v5creds,
+		       struct credentials *v4creds)
+{
+    return KRB524_KRB4_DISABLED;
+}
+
+#endif
+
+/* These may be needed for object-level backwards compatibility on Mac
+   OS and UNIX, but Windows should be okay.  */
+#ifndef _WIN32
+#undef krb524_convert_creds_kdc
+#undef krb524_init_ets
+
+/* Declarations ahead of the definitions will suppress some gcc
+   warnings.  */
+void KRB5_CALLCONV krb524_init_ets (void);
+krb5_error_code KRB5_CALLCONV
+krb524_convert_creds_kdc(krb5_context context, krb5_creds *v5creds,
+			 struct credentials *v4creds);
+
+krb5_error_code KRB5_CALLCONV
+krb524_convert_creds_kdc(krb5_context context, krb5_creds *v5creds,
+			 struct credentials *v4creds)
+{
+    return krb5_524_convert_creds(context, v5creds, v4creds);
+}
+
+void KRB5_CALLCONV krb524_init_ets ()
+{
+}
+#endif
diff --git a/mechglue/src/lib/krb5/krb/conv_princ.c b/mechglue/src/lib/krb5/krb/conv_princ.c
new file mode 100644
index 000000000..885dc995a
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/conv_princ.c
@@ -0,0 +1,352 @@
+/*
+ * lib/krb5/krb/conv_princ.c
+ *
+ * Copyright 1992 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Build a principal from a V4 specification, or separate a V5
+ * principal into name, instance, and realm.
+ * 
+ * NOTE: This is highly site specific, and is only really necessary
+ * for sites who need to convert from V4 to V5.  It is used by both
+ * the KDC and the kdb5_convert program.  Since its use is highly
+ * specialized, the necesary information is just going to be
+ * hard-coded in this file.
+ */
+
+#include "k5-int.h"
+#include <string.h>
+#include <ctype.h>
+
+/* The maximum sizes for V4 aname, realm, sname, and instance +1 */
+/* Taken from krb.h */
+#define 	ANAME_SZ	40
+#define		REALM_SZ	40
+#define		SNAME_SZ	40
+#define		INST_SZ		40
+
+struct krb_convert {
+    char		*v4_str;
+    char		*v5_str;
+    unsigned int	flags : 8;
+    unsigned int	len : 8;
+};
+
+#define DO_REALM_CONVERSION 0x00000001
+
+/*
+ * Kadmin doesn't do realm conversion because it's currently
+ * kadmin/REALM.NAME.  Zephyr doesn't because it's just zephyr/zephyr.
+ *
+ * "Realm conversion" is a bit of a misnomer; really, the v5 name is
+ * using a FQDN or something that looks like it, where the v4 name is
+ * just using the first label.  Sometimes that second principal name
+ * component is a hostname, sometimes the realm name, sometimes it's
+ * neither.
+ *
+ * This list should probably be more configurable, and more than
+ * likely on a per-realm basis, so locally-defined services can be
+ * added, or not.
+ */
+static const struct krb_convert sconv_list[] = {
+    /* Realm conversion, Change service name */
+#define RC(V5NAME,V4NAME) { V5NAME, V4NAME, DO_REALM_CONVERSION, sizeof(V5NAME)-1 }
+    /* Realm conversion */
+#define R(NAME)		{ NAME, NAME, DO_REALM_CONVERSION, sizeof(NAME)-1 }
+    /* No Realm conversion */
+#define NR(NAME)	{ NAME, NAME, 0, sizeof(NAME)-1 }
+
+    NR("kadmin"),
+    RC("rcmd", "host"),
+    R("discuss"),
+    R("rvdsrv"),
+    R("sample"),
+    R("olc"),
+    R("pop"),
+    R("sis"),
+    R("rfs"),
+    R("imap"),
+    R("ftp"),
+    R("ecat"),
+    R("daemon"),
+    R("gnats"),
+    R("moira"),
+    R("prms"),
+    R("mandarin"),
+    R("register"),
+    R("changepw"),
+    R("sms"),
+    R("afpserver"),
+    R("gdss"),
+    R("news"),
+    R("abs"),
+    R("nfs"),
+    R("tftp"),
+    NR("zephyr"),
+    R("http"),
+    R("khttp"),
+    R("pgpsigner"),
+    R("irc"),
+    R("mandarin-agent"),
+    R("write"),
+    R("palladium"),
+    {0, 0, 0, 0},
+#undef R
+#undef RC
+#undef NR
+};
+
+/*
+ * char *strnchr(s, c, n)
+ *   char *s;
+ *   char c;
+ *   unsigned int n;
+ *
+ * returns a pointer to the first occurrence of character c in the
+ * string s, or a NULL pointer if c does not occur in in the string;
+ * however, at most the first n characters will be considered.
+ *
+ * This falls in the "should have been in the ANSI C library"
+ * category. :-)
+ */
+static char *strnchr(register char *s, register char c, 
+		     register unsigned int n)
+{
+     if (n < 1) 
+	  return 0;
+     
+     while (n-- && *s) {
+	  if (*s == c)
+	       return s;
+	  s++;
+     }
+     return 0;
+}
+
+
+/* XXX This calls for a new error code */
+#define KRB5_INVALID_PRINCIPAL KRB5_LNAME_BADFORMAT
+
+krb5_error_code KRB5_CALLCONV
+krb5_524_conv_principal(krb5_context context, krb5_const_principal princ,
+			char *name, char *inst, char *realm)
+{
+     const struct krb_convert *p;
+     const krb5_data *compo;
+     char *c, *tmp_realm, *tmp_prealm;
+     unsigned int tmp_realm_len;
+     int retval; 
+
+     *name = *inst = '\0';
+     switch (krb5_princ_size(context, princ)) {
+     case 2:
+	  /* Check if this principal is listed in the table */
+	  compo = krb5_princ_component(context, princ, 0);
+	  p = sconv_list;
+	  while (p->v4_str) {
+	       if (p->len == compo->length
+		   && memcmp(p->v5_str, compo->data, compo->length) == 0) {
+		   /*
+		    * It is, so set the new name now, and chop off
+		    * instance's domain name if requested.
+		    */
+		   if (strlen (p->v4_str) > ANAME_SZ - 1)
+		       return KRB5_INVALID_PRINCIPAL;
+		   strcpy(name, p->v4_str);
+		   if (p->flags & DO_REALM_CONVERSION) {
+		       compo = krb5_princ_component(context, princ, 1);
+		       c = strnchr(compo->data, '.', compo->length);
+		       if (!c || (c - compo->data) >= INST_SZ - 1)
+			   return KRB5_INVALID_PRINCIPAL;
+		       memcpy(inst, compo->data, (size_t) (c - compo->data));
+		       inst[c - compo->data] = '\0';
+		   }
+		   break;
+	       }
+	       p++;
+	  }
+	  /* If inst isn't set, the service isn't listed in the table, */
+	  /* so just copy it. */
+	  if (*inst == '\0') {
+	       compo = krb5_princ_component(context, princ, 1);
+	       if (compo->length >= INST_SZ - 1)
+		    return KRB5_INVALID_PRINCIPAL;
+	       memcpy(inst, compo->data, compo->length);
+	       inst[compo->length] = '\0';
+	  }
+	  /* fall through */
+     case 1:
+	  /* name may have been set above; otherwise, just copy it */
+	  if (*name == '\0') {
+	       compo = krb5_princ_component(context, princ, 0);
+	       if (compo->length >= ANAME_SZ)
+		    return KRB5_INVALID_PRINCIPAL;
+	       memcpy(name, compo->data, compo->length);
+	       name[compo->length] = '\0';
+	  }
+	  break;
+     default:
+	  return KRB5_INVALID_PRINCIPAL;
+     }
+
+     compo = krb5_princ_realm(context, princ);
+
+     tmp_prealm = malloc(compo->length + 1);
+     if (tmp_prealm == NULL)
+	 return ENOMEM;
+     strncpy(tmp_prealm, compo->data, compo->length);
+     tmp_prealm[compo->length] = '\0';
+
+     /* Ask for v4_realm corresponding to 
+	krb5 principal realm from krb5.conf realms stanza */
+
+     if (context->profile == 0)
+       return KRB5_CONFIG_CANTOPEN;
+     retval = profile_get_string(context->profile, "realms",
+				 tmp_prealm, "v4_realm", 0,
+				 &tmp_realm);
+     free(tmp_prealm);
+     if (retval) { 
+	 return retval;
+     } else {
+	 if (tmp_realm == 0) {
+	     if (compo->length > REALM_SZ - 1)
+		 return KRB5_INVALID_PRINCIPAL;
+	     strncpy(realm, compo->data, compo->length);
+	     realm[compo->length] = '\0';
+	 } else {
+	     tmp_realm_len =  strlen(tmp_realm);
+	     if (tmp_realm_len > REALM_SZ - 1)
+		 return KRB5_INVALID_PRINCIPAL;
+	     strncpy(realm, tmp_realm, tmp_realm_len);
+	     realm[tmp_realm_len] = '\0';
+	     profile_release_string(tmp_realm);
+	 }
+     }
+     return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_425_conv_principal(krb5_context context, const char *name, const char *instance, const char *realm, krb5_principal *princ)
+{
+     const struct krb_convert *p;
+     char buf[256];		/* V4 instances are limited to 40 characters */
+     krb5_error_code retval;
+     char *domain, *cp;
+     char **full_name = 0;
+     const char *names[5];
+     void*	iterator = NULL;
+     char** v4realms = NULL;
+     char* realm_name = NULL;
+     char* dummy_value = NULL;
+     
+     /* First, convert the realm, since the v4 realm is not necessarily the same as the v5 realm
+        To do that, iterate over all the realms in the config file, looking for a matching 
+        v4_realm line */
+     names [0] = "realms";
+     names [1] = NULL;
+     retval = profile_iterator_create (context -> profile, names, PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, &iterator);
+     while (retval == 0) {
+     	retval = profile_iterator (&iterator, &realm_name, &dummy_value);
+     	if ((retval == 0) && (realm_name != NULL)) {
+     		names [0] = "realms";
+     		names [1] = realm_name;
+     		names [2] = "v4_realm";
+     		names [3] = NULL;
+
+     		retval = profile_get_values (context -> profile, names, &v4realms);
+     		if ((retval == 0) && (v4realms != NULL) && (v4realms [0] != NULL) && (strcmp (v4realms [0], realm) == 0)) {
+     			realm = realm_name;
+     			break;
+     		} else if (retval == PROF_NO_RELATION) {
+     			/* If it's not found, just keep going */
+     			retval = 0;
+     		}
+     	} else if ((retval == 0) && (realm_name == NULL)) {
+     		break;
+     	}
+	if (v4realms != NULL) {
+	        profile_free_list(v4realms);
+		v4realms = NULL;
+	}
+     	if (realm_name != NULL) {
+     		profile_release_string (realm_name);
+     		realm_name = NULL;
+     	}
+     	if (dummy_value != NULL) {
+     		profile_release_string (dummy_value);
+     		dummy_value = NULL;
+     	}
+     }
+     
+     if (instance) {
+	  if (instance[0] == '\0') {
+	       instance = 0;
+	       goto not_service;
+	  }
+	  p = sconv_list;
+	  while (1) {
+	       if (!p->v4_str)
+		    goto not_service;
+	       if (!strcmp(p->v4_str, name))
+		    break;
+	       p++;
+	  }
+	  name = p->v5_str;
+	  if ((p->flags & DO_REALM_CONVERSION) && !strchr(instance, '.')) {
+	      names[0] = "realms";
+	      names[1] = realm;
+	      names[2] = "v4_instance_convert";
+	      names[3] = instance;
+	      names[4] = 0;
+	      retval = profile_get_values(context->profile, names, &full_name);
+	      if (retval == 0 && full_name && full_name[0]) {
+		  instance = full_name[0];
+	      } else {
+		  strncpy(buf, instance, sizeof(buf));
+		  buf[sizeof(buf) - 1] = '\0';
+		  retval = krb5_get_realm_domain(context, realm, &domain);
+		  if (retval)
+		      return retval;
+		  if (domain) {
+		      for (cp = domain; *cp; cp++)
+			  if (isupper((int) (*cp)))
+			      *cp = tolower((int) *cp);
+		      strncat(buf, ".", sizeof(buf) - 1 - strlen(buf));
+		      strncat(buf, domain, sizeof(buf) - 1 - strlen(buf));
+		      krb5_xfree(domain);
+		  }
+		  instance = buf;
+	      }
+	  }
+     }
+     
+not_service:	
+     retval = krb5_build_principal(context, princ, strlen(realm), realm, name,
+				   instance, NULL);
+     if (iterator) profile_iterator_free (&iterator);
+     if (full_name) profile_free_list(full_name);
+     if (v4realms) profile_free_list(v4realms);
+     if (realm_name) profile_release_string (realm_name);
+     if (dummy_value) profile_release_string (dummy_value);
+     return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/copy_addrs.c b/mechglue/src/lib/krb5/krb/copy_addrs.c
new file mode 100644
index 000000000..0e9ee702c
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_addrs.c
@@ -0,0 +1,143 @@
+/*
+ * lib/krb5/krb/copy_addrs.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_addresses()
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_copy_addr(krb5_context context, const krb5_address *inad, krb5_address **outad)
+{
+    krb5_address *tmpad;
+
+    if (!(tmpad = (krb5_address *)malloc(sizeof(*tmpad))))
+	return ENOMEM;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tmpad = *inad;
+#else
+    memcpy(tmpad, inad, sizeof(krb5_address));
+#endif
+    if (!(tmpad->contents = (krb5_octet *)malloc(inad->length))) {
+	krb5_xfree(tmpad);
+	return ENOMEM;
+    }
+    memcpy((char *)tmpad->contents, (char *)inad->contents, inad->length);
+    *outad = tmpad;
+    return 0;
+}
+
+/*
+ * Copy an address array, with fresh allocation.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_copy_addresses(krb5_context context, krb5_address *const *inaddr, krb5_address ***outaddr)
+{
+    krb5_error_code retval;
+    krb5_address ** tempaddr;
+    register unsigned int nelems = 0;
+
+    if (!inaddr) {
+	    *outaddr = 0;
+	    return 0;
+    }
+    
+    while (inaddr[nelems]) nelems++;
+
+    /* one more for a null terminated list */
+    if (!(tempaddr = (krb5_address **) calloc(nelems+1, sizeof(*tempaddr))))
+	return ENOMEM;
+
+    for (nelems = 0; inaddr[nelems]; nelems++) {
+	retval = krb5_copy_addr(context, inaddr[nelems], &tempaddr[nelems]);
+        if (retval) {
+	    krb5_free_addresses(context, tempaddr);
+	    return retval;
+	}
+    }
+
+    *outaddr = tempaddr;
+    return 0;
+}
+
+#if 0
+/*
+ * Append an address array, to another address array, with fresh allocation.
+ * Note that this function may change the value of *outaddr even if it
+ * returns failure, but it will not change the contents of the list.
+ */
+krb5_error_code
+krb5_append_addresses(context, inaddr, outaddr)
+    krb5_context context;
+	krb5_address * const * inaddr;
+	krb5_address ***outaddr;
+{
+    krb5_error_code retval;
+    krb5_address ** tempaddr;
+    krb5_address ** tempaddr2;
+    register unsigned int nelems = 0;
+    register int norigelems = 0;
+
+    if (!inaddr)
+	return 0;
+
+    tempaddr2 = *outaddr;
+
+    while (inaddr[nelems]) nelems++;
+    while (tempaddr2[norigelems]) norigelems++;
+
+    tempaddr = (krb5_address **) realloc((char *)*outaddr,
+		       (nelems + norigelems + 1) * sizeof(*tempaddr));
+    if (!tempaddr)
+	return ENOMEM;
+
+    /* The old storage has been freed.  */
+    *outaddr = tempaddr;
+
+
+    for (nelems = 0; inaddr[nelems]; nelems++) {
+	retval = krb5_copy_addr(context, inaddr[nelems],
+				&tempaddr[norigelems + nelems]);
+	if (retval)
+	    goto cleanup;
+    }
+
+    tempaddr[norigelems + nelems] = 0;
+    return 0;
+
+  cleanup:
+    while (--nelems >= 0)
+	krb5_free_address(context, tempaddr[norigelems + nelems]);
+
+    /* Try to allocate a smaller amount of memory for *outaddr.  */
+    tempaddr = (krb5_address **) realloc((char *)tempaddr,
+					 (norigelems + 1) * sizeof(*tempaddr));
+    if (tempaddr)
+	*outaddr = tempaddr;
+    return retval;
+}
+#endif
+
diff --git a/mechglue/src/lib/krb5/krb/copy_athctr.c b/mechglue/src/lib/krb5/krb/copy_athctr.c
new file mode 100644
index 000000000..4b852a435
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_athctr.c
@@ -0,0 +1,85 @@
+/*
+ * lib/krb5/krb/copy_athctr.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_authenticator()
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_copy_authenticator(krb5_context context, const krb5_authenticator *authfrom, krb5_authenticator **authto)
+{
+    krb5_error_code retval;
+    krb5_authenticator *tempto;
+
+    if (!(tempto = (krb5_authenticator *)malloc(sizeof(*tempto))))
+	return ENOMEM;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tempto = *authfrom;
+#else
+    memcpy(tempto, authfrom, sizeof(krb5_authenticator));
+#endif
+
+    retval = krb5_copy_principal(context, authfrom->client, &tempto->client);
+    if (retval) {
+	krb5_xfree(tempto);
+	return retval;
+    }
+    
+    if (authfrom->checksum &&
+	(retval = krb5_copy_checksum(context, authfrom->checksum, &tempto->checksum))) {
+	    krb5_free_principal(context, tempto->client);    
+	    krb5_xfree(tempto);
+	    return retval;
+    }
+    
+    if (authfrom->subkey) {
+	    retval = krb5_copy_keyblock(context, authfrom->subkey, &tempto->subkey);
+	    if (retval) {
+		    krb5_xfree(tempto->subkey);
+		    krb5_free_checksum(context, tempto->checksum);
+		    krb5_free_principal(context, tempto->client);    
+		    krb5_xfree(tempto);
+		    return retval;
+	    }
+    }
+    
+    if (authfrom->authorization_data) {
+		retval = krb5_copy_authdata(context, authfrom->authorization_data,
+				    &tempto->authorization_data);
+		if (retval) {
+		    krb5_xfree(tempto->subkey);
+		    krb5_free_checksum(context, tempto->checksum);
+		    krb5_free_principal(context, tempto->client);    
+		    krb5_free_authdata(context, tempto->authorization_data);
+		    krb5_xfree(tempto);
+		    return retval;
+		}
+    }
+
+    *authto = tempto;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/copy_auth.c b/mechglue/src/lib/krb5/krb/copy_auth.c
new file mode 100644
index 000000000..19e026411
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_auth.c
@@ -0,0 +1,86 @@
+/*
+ * lib/krb5/krb/copy_auth.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_authdata()
+ */
+
+#include "k5-int.h"
+
+static krb5_error_code
+krb5_copy_authdatum(krb5_context context, const krb5_authdata *inad, krb5_authdata **outad)
+{
+    krb5_authdata *tmpad;
+
+    if (!(tmpad = (krb5_authdata *)malloc(sizeof(*tmpad))))
+	return ENOMEM;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tmpad = *inad;
+#else
+    memcpy(tmpad, inad, sizeof(krb5_authdata));
+#endif
+    if (!(tmpad->contents = (krb5_octet *)malloc(inad->length))) {
+	krb5_xfree(tmpad);
+	return ENOMEM;
+    }
+    memcpy((char *)tmpad->contents, (char *)inad->contents, inad->length);
+    *outad = tmpad;
+    return 0;
+}
+
+/*
+ * Copy an authdata array, with fresh allocation.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_copy_authdata(krb5_context context, krb5_authdata *const *inauthdat, krb5_authdata ***outauthdat)
+{
+    krb5_error_code retval;
+    krb5_authdata ** tempauthdat;
+    register unsigned int nelems = 0;
+
+    if (!inauthdat) {
+	    *outauthdat = 0;
+	    return 0;
+    }
+
+    while (inauthdat[nelems]) nelems++;
+
+    /* one more for a null terminated list */
+    if (!(tempauthdat = (krb5_authdata **) calloc(nelems+1,
+						  sizeof(*tempauthdat))))
+	return ENOMEM;
+
+    for (nelems = 0; inauthdat[nelems]; nelems++) {
+	retval = krb5_copy_authdatum(context, inauthdat[nelems],
+				     &tempauthdat[nelems]);
+	if (retval) {
+	    krb5_free_authdata(context, tempauthdat);
+	    return retval;
+	}
+    }
+
+    *outauthdat = tempauthdat;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/copy_cksum.c b/mechglue/src/lib/krb5/krb/copy_cksum.c
new file mode 100644
index 000000000..38b267159
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_cksum.c
@@ -0,0 +1,55 @@
+/*
+ * lib/krb5/krb/copy_cksum.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_checksum()
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_copy_checksum(krb5_context context, const krb5_checksum *ckfrom, krb5_checksum **ckto)
+{
+    krb5_checksum *tempto;
+
+    if (!(tempto = (krb5_checksum *)malloc(sizeof(*tempto))))
+	return ENOMEM;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tempto = *ckfrom;
+#else
+    memcpy(tempto, ckfrom, sizeof(krb5_checksum));
+#endif
+
+    if (!(tempto->contents =
+	  (krb5_octet *)malloc(tempto->length))) {
+	krb5_xfree(tempto);
+	return ENOMEM;
+    }
+    memcpy((char *) tempto->contents, (char *) ckfrom->contents,
+	   ckfrom->length);
+
+    *ckto = tempto;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/copy_creds.c b/mechglue/src/lib/krb5/krb/copy_creds.c
new file mode 100644
index 000000000..2be195055
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_creds.c
@@ -0,0 +1,98 @@
+/*
+ * lib/krb5/krb/copy_creds.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_cred()
+ */
+
+#include "k5-int.h"
+
+/*
+ * Copy credentials, allocating fresh storage where needed.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_copy_creds(krb5_context context, const krb5_creds *incred, krb5_creds **outcred)
+{
+    krb5_creds *tempcred;
+    krb5_error_code retval;
+    krb5_data *scratch;
+
+    if (!(tempcred = (krb5_creds *)malloc(sizeof(*tempcred))))
+	return ENOMEM;
+
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tempcred = *incred;		/* copy everything quickly */
+#else
+    memcpy(tempcred, incred, sizeof(krb5_creds));
+#endif
+    retval = krb5_copy_principal(context, incred->client, &tempcred->client);
+    if (retval)
+	goto cleanlast;
+    retval = krb5_copy_principal(context, incred->server, &tempcred->server);
+    if (retval)
+	goto cleanclient;
+    retval = krb5_copy_keyblock_contents(context, &incred->keyblock,
+					 &tempcred->keyblock);
+    if (retval)
+	goto cleanserver;
+    retval = krb5_copy_addresses(context, incred->addresses, &tempcred->addresses);
+    if (retval)
+	goto cleanblock;
+    retval = krb5_copy_data(context, &incred->ticket, &scratch);
+    if (retval)
+	goto cleanaddrs;
+    tempcred->ticket = *scratch;
+    krb5_xfree(scratch);
+    retval = krb5_copy_data(context, &incred->second_ticket, &scratch);
+    if (retval)
+	goto cleanticket;
+
+    tempcred->second_ticket = *scratch;
+    krb5_xfree(scratch);
+
+    retval = krb5_copy_authdata(context, incred->authdata,&tempcred->authdata);
+    if (retval)
+        goto clearticket;
+
+    *outcred = tempcred;
+    return 0;
+
+ clearticket:    
+    memset(tempcred->ticket.data,0,tempcred->ticket.length);
+ cleanticket:
+    free(tempcred->ticket.data);
+ cleanaddrs:
+    krb5_free_addresses(context, tempcred->addresses);
+ cleanblock:
+    krb5_xfree(tempcred->keyblock.contents);
+ cleanserver:
+    krb5_free_principal(context, tempcred->server);
+ cleanclient:
+    krb5_free_principal(context, tempcred->client);
+ cleanlast:
+    krb5_xfree(tempcred);
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/copy_data.c b/mechglue/src/lib/krb5/krb/copy_data.c
new file mode 100644
index 000000000..1be2a2da5
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_data.c
@@ -0,0 +1,82 @@
+/*
+ * lib/krb5/krb/copy_data.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_data()
+ */
+
+#include "k5-int.h"
+
+/*
+ * Copy a data structure, with fresh allocation.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_copy_data(krb5_context context, const krb5_data *indata, krb5_data **outdata)
+{
+    krb5_data *tempdata;
+
+    if (!indata) {
+	*outdata = 0;
+	return 0;
+    }
+    
+    if (!(tempdata = (krb5_data *)malloc(sizeof(*tempdata))))
+	return ENOMEM;
+
+    tempdata->length = indata->length;
+    if (tempdata->length) {
+	if (!(tempdata->data = malloc(tempdata->length))) {
+	    krb5_xfree(tempdata);
+	    return ENOMEM;
+	}
+	memcpy((char *)tempdata->data, (char *)indata->data, tempdata->length);
+    } else
+	tempdata->data = 0;
+    tempdata->magic = KV5M_DATA;
+    *outdata = tempdata;
+    return 0;
+}
+
+krb5_error_code 
+krb5int_copy_data_contents(krb5_context context, const krb5_data *indata, krb5_data *outdata)
+{
+    if (!indata) {
+	return EINVAL;
+    }
+    
+
+    outdata->length = indata->length;
+    if (outdata->length) {
+	if (!(outdata->data = malloc(outdata->length))) {
+	    krb5_xfree(outdata);
+	    return ENOMEM;
+	}
+	memcpy((char *)outdata->data, (char *)indata->data, outdata->length);
+    } else
+	outdata->data = 0;
+    outdata->magic = KV5M_DATA;
+
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/copy_key.c b/mechglue/src/lib/krb5/krb/copy_key.c
new file mode 100644
index 000000000..d2640ed58
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_key.c
@@ -0,0 +1,55 @@
+/*
+ * lib/krb5/krb/copy_key.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_keyblock()
+ */
+
+#include "k5-int.h"
+
+/*
+ * Copy a keyblock, including alloc'ed storage.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_copy_keyblock(krb5_context context, const krb5_keyblock *from, krb5_keyblock **to)
+{
+	krb5_keyblock	*new_key;
+
+	if (!(new_key = (krb5_keyblock *) malloc(sizeof(krb5_keyblock))))
+		return ENOMEM;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+	*new_key = *from;
+#else
+	memcpy(new_key, from, sizeof(krb5_keyblock));
+#endif
+	if (!(new_key->contents = (krb5_octet *)malloc(new_key->length))) {
+		krb5_xfree(new_key);
+		return(ENOMEM);
+	}
+	memcpy((char *)new_key->contents, (char *)from->contents,
+	       new_key->length);
+	*to = new_key;
+	return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/copy_princ.c b/mechglue/src/lib/krb5/krb/copy_princ.c
new file mode 100644
index 000000000..f62323695
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_princ.c
@@ -0,0 +1,95 @@
+/*
+ * lib/krb5/krb/copy_princ.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_principal()
+ */
+
+#include "k5-int.h"
+
+/*
+ * Copy a principal structure, with fresh allocation.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_copy_principal(krb5_context context, krb5_const_principal inprinc, krb5_principal *outprinc)
+{
+    register krb5_principal tempprinc;
+    register int i, nelems;
+
+    tempprinc = (krb5_principal)malloc(sizeof(krb5_principal_data));
+
+    if (tempprinc == 0)
+	return ENOMEM;
+
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tempprinc = *inprinc;	/* Copy all of the non-allocated pieces */
+#else
+    memcpy(tempprinc, inprinc, sizeof(krb5_principal_data));
+#endif
+
+    nelems = (int) krb5_princ_size(context, inprinc);
+    tempprinc->data = malloc(nelems * sizeof(krb5_data));
+
+    if (tempprinc->data == 0) {
+	free((char *)tempprinc);
+	return ENOMEM;
+    }
+
+    for (i = 0; i < nelems; i++) {
+	unsigned int len = krb5_princ_component(context, inprinc, i)->length;
+	krb5_princ_component(context, tempprinc, i)->length = len;
+        if (len) {
+            if (((krb5_princ_component(context, tempprinc, i)->data =
+                   malloc(len)) == 0)) {
+                while (--i >= 0)
+                    free(krb5_princ_component(context, tempprinc, i)->data);
+                free (tempprinc->data);
+                free (tempprinc);
+                return ENOMEM;
+            }
+	    memcpy(krb5_princ_component(context, tempprinc, i)->data,
+		   krb5_princ_component(context, inprinc, i)->data, len);
+        } else
+            krb5_princ_component(context, tempprinc, i)->data = 0;
+    }
+
+    if (tempprinc->realm.length) {
+        tempprinc->realm.data =
+	    malloc(tempprinc->realm.length = inprinc->realm.length);
+        if (!tempprinc->realm.data) {
+	    for (i = 0; i < nelems; i++)
+                free(krb5_princ_component(context, tempprinc, i)->data);
+	    free(tempprinc->data);
+	    free(tempprinc);
+	    return ENOMEM;
+        }
+	memcpy(tempprinc->realm.data, inprinc->realm.data,
+	       inprinc->realm.length);
+    } else
+        tempprinc->realm.data = 0;
+
+    *outprinc = tempprinc;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/copy_tick.c b/mechglue/src/lib/krb5/krb/copy_tick.c
new file mode 100644
index 000000000..00f235d3c
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/copy_tick.c
@@ -0,0 +1,134 @@
+/*
+ * lib/krb5/krb/copy_tick.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_ticket()
+ */
+
+#include "k5-int.h"
+
+static krb5_error_code
+krb5_copy_enc_tkt_part(krb5_context context, const krb5_enc_tkt_part *partfrom, krb5_enc_tkt_part **partto)
+{
+    krb5_error_code retval;
+    krb5_enc_tkt_part *tempto;
+
+    if (!(tempto = (krb5_enc_tkt_part *)malloc(sizeof(*tempto))))
+	return ENOMEM;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tempto = *partfrom;
+#else
+    memcpy(tempto, partfrom, sizeof(krb5_enc_tkt_part));
+#endif
+    retval = krb5_copy_keyblock(context, partfrom->session,
+				&tempto->session);
+    if (retval) {
+	krb5_xfree(tempto);
+	return retval;
+    }
+    retval = krb5_copy_principal(context, partfrom->client, &tempto->client);
+    if (retval) {
+	krb5_free_keyblock(context, tempto->session);
+	krb5_xfree(tempto);
+	return retval;
+    }
+    tempto->transited = partfrom->transited;
+    if (tempto->transited.tr_contents.length == 0) {
+	tempto->transited.tr_contents.data = 0;
+    } else {
+	tempto->transited.tr_contents.data =
+	  malloc(partfrom->transited.tr_contents.length);
+	if (!tempto->transited.tr_contents.data) {
+	    krb5_free_principal(context, tempto->client);
+	    krb5_free_keyblock(context, tempto->session);
+	    krb5_xfree(tempto);
+	    return ENOMEM;
+	}
+	memcpy((char *)tempto->transited.tr_contents.data,
+	       (char *)partfrom->transited.tr_contents.data,
+	       partfrom->transited.tr_contents.length);
+    }
+
+    retval = krb5_copy_addresses(context, partfrom->caddrs, &tempto->caddrs);
+    if (retval) {
+	krb5_xfree(tempto->transited.tr_contents.data);
+	krb5_free_principal(context, tempto->client);
+	krb5_free_keyblock(context, tempto->session);
+	krb5_xfree(tempto);
+	return retval;
+    }
+    if (partfrom->authorization_data) {
+	retval = krb5_copy_authdata(context, partfrom->authorization_data,
+				    &tempto->authorization_data);
+	if (retval) {
+	    krb5_free_addresses(context, tempto->caddrs);
+	    krb5_xfree(tempto->transited.tr_contents.data);
+	    krb5_free_principal(context, tempto->client);
+	    krb5_free_keyblock(context, tempto->session);
+	    krb5_xfree(tempto);
+	    return retval;
+	}
+    }
+    *partto = tempto;
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_copy_ticket(krb5_context context, const krb5_ticket *from, krb5_ticket **pto)
+{
+    krb5_error_code retval;
+    krb5_ticket *tempto;
+    krb5_data *scratch;
+
+    if (!(tempto = (krb5_ticket *)malloc(sizeof(*tempto))))
+	return ENOMEM;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *tempto = *from;
+#else
+    memcpy(tempto, from, sizeof(krb5_ticket));
+#endif
+    retval = krb5_copy_principal(context, from->server, &tempto->server);
+    if (retval) {
+	krb5_xfree(tempto);
+	return retval;
+    }
+    retval = krb5_copy_data(context, &from->enc_part.ciphertext, &scratch);
+    if (retval) {
+	krb5_free_principal(context, tempto->server);
+	krb5_xfree(tempto);
+	return retval;
+    }
+    tempto->enc_part.ciphertext = *scratch;
+    krb5_xfree(scratch);
+    retval = krb5_copy_enc_tkt_part(context, from->enc_part2, &tempto->enc_part2);
+    if (retval) {
+	krb5_xfree(tempto->enc_part.ciphertext.data);
+	krb5_free_principal(context, tempto->server);
+	krb5_xfree(tempto);
+	return retval;
+    }	
+    *pto = tempto;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/cp_key_cnt.c b/mechglue/src/lib/krb5/krb/cp_key_cnt.c
new file mode 100644
index 000000000..150be0a57
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/cp_key_cnt.c
@@ -0,0 +1,47 @@
+/*
+ * lib/krb5/krb/cp_key_cnt.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_copy_keyblock()
+ */
+
+#include "k5-int.h"
+
+/*
+ * Copy a keyblock, including alloc'ed storage.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_copy_keyblock_contents(krb5_context context, const krb5_keyblock *from, krb5_keyblock *to)
+{
+    *to = *from;
+    if (to->length) {
+        to->contents = (krb5_octet *)malloc(to->length);
+        if (!to->contents)
+            return ENOMEM;
+        memcpy((char *)to->contents, (char *)from->contents, to->length);
+    } else 
+        to->contents = 0;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/decode_kdc.c b/mechglue/src/lib/krb5/krb/decode_kdc.c
new file mode 100644
index 000000000..cdfc4ffbd
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/decode_kdc.c
@@ -0,0 +1,77 @@
+/*
+ * lib/krb5/krb/decode_kdc.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_decode_kdc_rep() function.
+ */
+
+#include "k5-int.h"
+
+/*
+ Takes a KDC_REP message and decrypts encrypted part using etype and
+ *key, putting result in *rep.
+ dec_rep->client,ticket,session,last_req,server,caddrs
+ are all set to allocated storage which should be freed by the caller
+ when finished with the response.
+
+ If the response isn't a KDC_REP (tgs or as), it returns an error from
+ the decoding routines.
+
+ returns errors from encryption routines, system errors
+ */
+
+krb5_error_code
+krb5_decode_kdc_rep(krb5_context context, krb5_data *enc_rep, const krb5_keyblock *key, krb5_kdc_rep **dec_rep)
+{
+    krb5_error_code retval;
+    krb5_kdc_rep *local_dec_rep;
+    krb5_keyusage usage;
+
+    if (krb5_is_as_rep(enc_rep)) {
+	usage = KRB5_KEYUSAGE_AS_REP_ENCPART;
+	retval = decode_krb5_as_rep(enc_rep, &local_dec_rep);
+    } else if (krb5_is_tgs_rep(enc_rep)) {
+	usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY;
+	/* KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY would go here, except
+	   that this client code base doesn't ever put a subkey in the
+	   tgs_req authenticator, so the tgs_rep is never encrypted in
+	   one.  (Check send_tgs.c:krb5_send_tgs_basic(), near the top
+	   where authent.subkey is set to 0) */
+	retval = decode_krb5_tgs_rep(enc_rep, &local_dec_rep);
+    } else {
+	return KRB5KRB_AP_ERR_MSG_TYPE;
+    }
+
+    if (retval)
+	return retval;
+
+    if ((retval = krb5_kdc_rep_decrypt_proc(context, key, &usage,
+					    local_dec_rep))) 
+	krb5_free_kdc_rep(context, local_dec_rep);
+    else
+    	*dec_rep = local_dec_rep;
+    return(retval);
+}
+
diff --git a/mechglue/src/lib/krb5/krb/decrypt_tk.c b/mechglue/src/lib/krb5/krb/decrypt_tk.c
new file mode 100644
index 000000000..36ecbb45b
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/decrypt_tk.c
@@ -0,0 +1,73 @@
+/*
+ * lib/krb5/krb/decrypt_tk.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_decrypt_tkt_part() function.
+ */
+
+#include "k5-int.h"
+
+/*
+ Decrypts dec_ticket->enc_part
+ using *srv_key, and places result in dec_ticket->enc_part2.
+ The storage of dec_ticket->enc_part2 will be allocated before return.
+
+ returns errors from encryption routines, system errors
+
+*/
+
+krb5_error_code KRB5_CALLCONV
+krb5_decrypt_tkt_part(krb5_context context, const krb5_keyblock *srv_key, register krb5_ticket *ticket)
+{
+    krb5_enc_tkt_part *dec_tkt_part;
+    krb5_data scratch;
+    krb5_error_code retval;
+
+    if (!krb5_c_valid_enctype(ticket->enc_part.enctype))
+	return KRB5_PROG_ETYPE_NOSUPP;
+
+    scratch.length = ticket->enc_part.ciphertext.length;
+    if (!(scratch.data = malloc(ticket->enc_part.ciphertext.length)))
+	return(ENOMEM);
+
+    /* call the encryption routine */
+    if ((retval = krb5_c_decrypt(context, srv_key,
+				KRB5_KEYUSAGE_KDC_REP_TICKET, 0,
+				&ticket->enc_part, &scratch))) {
+	free(scratch.data);
+	return retval;
+    }
+
+#define clean_scratch() {memset(scratch.data, 0, scratch.length); \
+free(scratch.data);}
+
+    /*  now decode the decrypted stuff */
+    retval = decode_krb5_enc_tkt_part(&scratch, &dec_tkt_part);
+    if (!retval) {
+	ticket->enc_part2 = dec_tkt_part;
+    }
+    clean_scratch();
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/deltat.c b/mechglue/src/lib/krb5/krb/deltat.c
new file mode 100644
index 000000000..2541591f8
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/deltat.c
@@ -0,0 +1,1455 @@
+/* A Bison parser, made by GNU Bison 1.875d.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Written by Richard Stallman by simplifying the original so called
+   ``semantic'' parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     NUM = 258,
+     LONGNUM = 259,
+     OVERFLOW = 260,
+     tok_WS = 261
+   };
+#endif
+#define NUM 258
+#define LONGNUM 259
+#define OVERFLOW 260
+#define tok_WS 261
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 38 "x-deltat.y"
+
+
+#include <ctype.h>
+#include <errno.h>
+#include "k5-int.h"
+
+struct param {
+    krb5_int32 delta;
+    char *p;
+};
+
+#define YYPARSE_PARAM tmv
+
+#define MAX_TIME KRB5_INT32_MAX
+#define MIN_TIME KRB5_INT32_MIN
+
+#define DAY (24 * 3600)
+#define HOUR 3600
+
+#define MAX_DAY (MAX_TIME / DAY)
+#define MIN_DAY (MIN_TIME / DAY)
+#define MAX_HOUR (MAX_TIME / HOUR)
+#define MIN_HOUR (MIN_TIME / HOUR)
+#define MAX_MIN (MAX_TIME / 60)
+#define MIN_MIN (MIN_TIME / 60)
+
+/* An explanation of the tests being performed. 
+   We do not want to overflow a 32 bit integer with out manipulations, 
+   even for testing for overflow. Therefore we rely on the following:
+
+   The lex parser will not return a number > MAX_TIME (which is out 32
+   bit limit).
+
+   Therefore, seconds (s) will require 
+       MIN_TIME < s < MAX_TIME
+
+   For subsequent tests, the logic is as follows:
+
+      If A < MAX_TIME and  B < MAX_TIME
+
+      If we want to test if A+B < MAX_TIME, there are two cases
+        if (A > 0) 
+         then A + B < MAX_TIME if B < MAX_TIME - A
+	else A + B < MAX_TIME  always.
+
+      if we want to test if MIN_TIME < A + B
+          if A > 0 - then nothing to test
+          otherwise, we test if MIN_TIME - A < B.
+
+   We of course are testing for:
+          MIN_TIME < A + B < MAX_TIME
+*/
+
+
+#define DAY_NOT_OK(d) (d) > MAX_DAY || (d) < MIN_DAY
+#define HOUR_NOT_OK(h) (h) > MAX_HOUR || (h) < MIN_HOUR
+#define MIN_NOT_OK(m) (m) > MAX_MIN || (m) < MIN_MIN
+#define SUM_OK(a, b) (((a) > 0) ? ( (b) <= MAX_TIME - (a)) : (MIN_TIME - (a) <= (b)))
+#define DO_SUM(res, a, b) if (!SUM_OK((a), (b))) YYERROR; \
+                          res = (a) + (b)
+
+
+#define OUT_D ((struct param *)tmv)->delta 
+#define DO(D,H,M,S) \
+ { \
+     /* Overflow testing - this does not handle negative values well.. */ \
+     if (DAY_NOT_OK(D) || HOUR_NOT_OK(H) || MIN_NOT_OK(M)) YYERROR; \
+     OUT_D = D * DAY; \
+     DO_SUM(OUT_D, OUT_D, H * HOUR); \
+     DO_SUM(OUT_D, OUT_D, M * 60); \
+     DO_SUM(OUT_D, OUT_D, S); \
+ }
+
+static int mylex (int *, char **);
+#define YYLEX_PARAM (&((struct param *)tmv)->p)
+#undef yylex
+#define yylex(U, P)    mylex (&(U)->val, (P))
+
+#undef yyerror
+#define yyerror(MSG)
+
+static int yyparse (void *);
+
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 125 "x-deltat.y"
+typedef union YYSTYPE { int val; } YYSTYPE;
+/* Line 191 of yacc.c.  */
+#line 175 "deltat.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+
+
+/* Line 214 of yacc.c.  */
+#line 187 "deltat.c"
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+# ifndef YYFREE
+#  define YYFREE free
+# endif
+# ifndef YYMALLOC
+#  define YYMALLOC malloc
+# endif
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   define YYSTACK_ALLOC alloca
+#  endif
+# else
+#  if defined (alloca) || defined (_ALLOCA_H)
+#   define YYSTACK_ALLOC alloca
+#  else
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning. */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+#  if defined (__STDC__) || defined (__cplusplus)
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   define YYSIZE_T size_t
+#  endif
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+	 || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short int yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short int) + sizeof (YYSTYPE))			\
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined (__GNUC__) && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  register YYSIZE_T yyi;		\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)					\
+    do									\
+      {									\
+	YYSIZE_T yynewbytes;						\
+	YYCOPY (&yyptr->Stack, Stack, yysize);				\
+	Stack = &yyptr->Stack;						\
+	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+	yyptr += yynewbytes / sizeof (*yyptr);				\
+      }									\
+    while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+   typedef signed char yysigned_char;
+#else
+   typedef short int yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL  6
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   37
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS  13
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS  10
+/* YYNRULES -- Number of rules. */
+#define YYNRULES  24
+/* YYNRULES -- Number of states. */
+#define YYNSTATES  42
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   261
+
+#define YYTRANSLATE(YYX) 						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const unsigned char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     6,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     7,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       8,     2,     2,     2,     9,     2,     2,     2,     2,    10,
+       2,     2,     2,     2,     2,    11,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,    12
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const unsigned char yyprhs[] =
+{
+       0,     0,     3,     5,     7,     9,    11,    14,    15,    17,
+      20,    23,    27,    31,    35,    38,    46,    52,    56,    58,
+      60,    64,    66,    70,    72
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+      14,     0,    -1,    19,    -1,     3,    -1,     4,    -1,    15,
+      -1,     6,    15,    -1,    -1,    12,    -1,    17,    16,    -1,
+      17,     5,    -1,    18,     8,    20,    -1,    18,     9,    21,
+      -1,    18,    10,    22,    -1,    18,    11,    -1,    18,     6,
+       3,     7,     3,     7,     3,    -1,    18,     7,     3,     7,
+       3,    -1,    18,     7,     3,    -1,    18,    -1,    21,    -1,
+      18,     9,    21,    -1,    22,    -1,    18,    10,    22,    -1,
+      17,    -1,    18,    11,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const unsigned char yyrline[] =
+{
+       0,   136,   136,   137,   137,   138,   138,   139,   139,   140,
+     141,   143,   144,   145,   146,   147,   148,   149,   150,   154,
+     155,   158,   159,   162,   163
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "NUM", "LONGNUM", "OVERFLOW", "'-'",
+  "':'", "'d'", "'h'", "'m'", "'s'", "tok_WS", "$accept", "start",
+  "posnum", "num", "ws", "wsnum", "deltat", "opt_hms", "opt_ms", "opt_s", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const unsigned short int yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,    45,    58,   100,   104,
+     109,   115,   261
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const unsigned char yyr1[] =
+{
+       0,    13,    14,    15,    15,    16,    16,    17,    17,    18,
+      18,    19,    19,    19,    19,    19,    19,    19,    19,    20,
+      20,    21,    21,    22,    22
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const unsigned char yyr2[] =
+{
+       0,     2,     1,     1,     1,     1,     2,     0,     1,     2,
+       2,     3,     3,     3,     2,     7,     5,     3,     1,     1,
+       3,     1,     3,     1,     2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const unsigned char yydefact[] =
+{
+       7,     8,     0,     0,    18,     2,     1,     3,     4,    10,
+       0,     5,     9,     0,     0,     7,     7,     7,    14,     6,
+       0,    17,    23,     0,    11,    19,    21,     0,    12,     0,
+      13,     0,     0,     7,     7,    24,     0,    16,    20,    22,
+       0,    15
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+      -1,     2,    11,    12,    22,    27,     5,    24,    25,    26
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -16
+static const yysigned_char yypact[] =
+{
+     -10,   -16,    14,     7,    -2,   -16,   -16,   -16,   -16,   -16,
+      21,   -16,   -16,    13,    25,   -10,   -10,   -10,   -16,   -16,
+      22,    23,     7,    12,   -16,   -16,   -16,    16,   -16,     8,
+     -16,    28,    29,   -10,   -10,   -16,    26,   -16,   -16,   -16,
+      32,   -16
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yysigned_char yypgoto[] =
+{
+     -16,   -16,    27,   -16,    36,     0,   -16,   -16,   -15,   -14
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+       4,    28,     1,    30,    13,    14,    15,    16,    17,    18,
+       7,     8,     9,    10,     6,    23,    20,    29,    38,    35,
+      39,    33,    34,    35,     7,     8,    34,    35,    21,    31,
+      32,    36,    37,    40,    29,    41,     3,    19
+};
+
+static const unsigned char yycheck[] =
+{
+       0,    16,    12,    17,     6,     7,     8,     9,    10,    11,
+       3,     4,     5,     6,     0,    15,     3,    17,    33,    11,
+      34,     9,    10,    11,     3,     4,    10,    11,     3,     7,
+       7,     3,     3,     7,    34,     3,     0,    10
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const unsigned char yystos[] =
+{
+       0,    12,    14,    17,    18,    19,     0,     3,     4,     5,
+       6,    15,    16,     6,     7,     8,     9,    10,    11,    15,
+       3,     3,    17,    18,    20,    21,    22,    18,    21,    18,
+      22,     7,     7,     9,    10,    11,     3,     3,    21,    22,
+       7,     3
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { 								\
+      yyerror ("syntax error: cannot back up");\
+      YYERROR;							\
+    }								\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+   are run).  */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)		\
+   ((Current).first_line   = (Rhs)[1].first_line,	\
+    (Current).first_column = (Rhs)[1].first_column,	\
+    (Current).last_line    = (Rhs)[N].last_line,	\
+    (Current).last_column  = (Rhs)[N].last_column)
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (0)
+
+# define YYDSYMPRINT(Args)			\
+do {						\
+  if (yydebug)					\
+    yysymprint Args;				\
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location)		\
+do {								\
+  if (yydebug)							\
+    {								\
+      YYFPRINTF (stderr, "%s ", Title);				\
+      yysymprint (stderr, 					\
+                  Token, Value);	\
+      YYFPRINTF (stderr, "\n");					\
+    }								\
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short int *bottom, short int *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    short int *bottom;
+    short int *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (/* Nothing. */; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+    int yyrule;
+#endif
+{
+  int yyi;
+  unsigned int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+             yyrule - 1, yylno);
+  /* Print the symbols being reduced, and their result.  */
+  for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+    YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+  YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (Rule);		\
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  register const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  register char *yyd = yydest;
+  register const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (yytype < YYNTOKENS)
+    {
+      YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+      YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+    }
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+  YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  switch (yytype)
+    {
+
+      default:
+        break;
+    }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+  void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  /* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+  register int yystate;
+  register int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  short int yyssa[YYINITDEPTH];
+  short int *yyss = yyssa;
+  register short int *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule.  */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack. Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	YYSTYPE *yyvs1 = yyvs;
+	short int *yyss1 = yyss;
+
+
+	/* Each stack pointer address is followed by the size of the
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow ("parser stack overflow",
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyoverflowlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyoverflowlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	short int *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyoverflowlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+  YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 6:
+#line 138 "x-deltat.y"
+    { yyval.val = - yyvsp[0].val; ;}
+    break;
+
+  case 9:
+#line 140 "x-deltat.y"
+    { yyval.val = yyvsp[0].val; ;}
+    break;
+
+  case 10:
+#line 141 "x-deltat.y"
+    { YYERROR; ;}
+    break;
+
+  case 11:
+#line 143 "x-deltat.y"
+    { DO (yyvsp[-2].val,  0,  0, yyvsp[0].val); ;}
+    break;
+
+  case 12:
+#line 144 "x-deltat.y"
+    { DO ( 0, yyvsp[-2].val,  0, yyvsp[0].val); ;}
+    break;
+
+  case 13:
+#line 145 "x-deltat.y"
+    { DO ( 0,  0, yyvsp[-2].val, yyvsp[0].val); ;}
+    break;
+
+  case 14:
+#line 146 "x-deltat.y"
+    { DO ( 0,  0,  0, yyvsp[-1].val); ;}
+    break;
+
+  case 15:
+#line 147 "x-deltat.y"
+    { DO (yyvsp[-6].val, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val); ;}
+    break;
+
+  case 16:
+#line 148 "x-deltat.y"
+    { DO ( 0, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val); ;}
+    break;
+
+  case 17:
+#line 149 "x-deltat.y"
+    { DO ( 0, yyvsp[-2].val, yyvsp[0].val,  0); ;}
+    break;
+
+  case 18:
+#line 150 "x-deltat.y"
+    { DO ( 0,  0,  0, yyvsp[0].val); ;}
+    break;
+
+  case 20:
+#line 155 "x-deltat.y"
+    { if (HOUR_NOT_OK(yyvsp[-2].val)) YYERROR;
+	                                  DO_SUM(yyval.val, yyvsp[-2].val * 3600, yyvsp[0].val); ;}
+    break;
+
+  case 22:
+#line 159 "x-deltat.y"
+    { if (MIN_NOT_OK(yyvsp[-2].val)) YYERROR;
+	                                  DO_SUM(yyval.val, yyvsp[-2].val * 60, yyvsp[0].val); ;}
+    break;
+
+  case 23:
+#line 162 "x-deltat.y"
+    { yyval.val = 0; ;}
+    break;
+
+
+    }
+
+/* Line 1010 of yacc.c.  */
+#line 1164 "deltat.c"
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+
+
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (YYPACT_NINF < yyn && yyn < YYLAST)
+	{
+	  YYSIZE_T yysize = 0;
+	  int yytype = YYTRANSLATE (yychar);
+	  const char* yyprefix;
+	  char *yymsg;
+	  int yyx;
+
+	  /* Start YYX at -YYN if negative to avoid negative indexes in
+	     YYCHECK.  */
+	  int yyxbegin = yyn < 0 ? -yyn : 0;
+
+	  /* Stay within bounds of both yycheck and yytname.  */
+	  int yychecklim = YYLAST - yyn;
+	  int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+	  int yycount = 0;
+
+	  yyprefix = ", expecting ";
+	  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+	    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+	      {
+		yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+		yycount += 1;
+		if (yycount == 5)
+		  {
+		    yysize = 0;
+		    break;
+		  }
+	      }
+	  yysize += (sizeof ("syntax error, unexpected ")
+		     + yystrlen (yytname[yytype]));
+	  yymsg = (char *) YYSTACK_ALLOC (yysize);
+	  if (yymsg != 0)
+	    {
+	      char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+	      yyp = yystpcpy (yyp, yytname[yytype]);
+
+	      if (yycount < 5)
+		{
+		  yyprefix = ", expecting ";
+		  for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+		    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+		      {
+			yyp = yystpcpy (yyp, yyprefix);
+			yyp = yystpcpy (yyp, yytname[yyx]);
+			yyprefix = " or ";
+		      }
+		}
+	      yyerror (yymsg);
+	      YYSTACK_FREE (yymsg);
+	    }
+	  else
+	    yyerror ("syntax error; also virtual memory exhausted");
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror ("syntax error");
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+        {
+          /* If at end of input, pop the error token,
+	     then the rest of the stack, then return failure.  */
+	  if (yychar == YYEOF)
+	     for (;;)
+	       {
+		 YYPOPSTACK;
+		 if (yyssp == yyss)
+		   YYABORT;
+		 YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+		 yydestruct (yystos[*yyssp], yyvsp);
+	       }
+        }
+      else
+	{
+	  YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+	  yydestruct (yytoken, &yylval);
+	  yychar = YYEMPTY;
+
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+  /* Pacify GCC when the user code never invokes YYERROR and the label
+     yyerrorlab therefore never appears in user code.  */
+  if (0)
+     goto yyerrorlab;
+#endif
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+      yydestruct (yystos[yystate], yyvsp);
+      YYPOPSTACK;
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  YYDPRINTF ((stderr, "Shifting error token, "));
+
+  *++yyvsp = yylval;
+
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here.  |
+`----------------------------------------------*/
+yyoverflowlab:
+  yyerror ("parser stack overflow");
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+
+
+#line 165 "x-deltat.y"
+
+
+static int
+mylex (krb5_int32 *intp, char **pp)
+{
+    int num, c;
+#define P (*pp)
+    char *orig_p = P;
+
+#ifdef isascii
+    if (!isascii (*P))
+	return 0;
+#endif
+    switch (c = *P++) {
+    case '-':
+    case ':':
+    case 'd':
+    case 'h':
+    case 'm':
+    case 's':
+	return c;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+	/* XXX assumes ASCII */
+	num = c - '0';
+	while (isdigit ((int) *P)) {
+	  if (num > MAX_TIME / 10) 
+	    return OVERFLOW;
+	    num *= 10;
+	    if (num > MAX_TIME - (*P - '0')) 
+	      return OVERFLOW;
+	    num += *P++ - '0';
+	}
+	*intp = num;
+	return (P - orig_p > 2) ? LONGNUM : NUM;
+    case ' ':
+    case '\t':
+    case '\n':
+	while (isspace ((int) *P))
+	    P++;
+	return tok_WS;
+    default:
+	return YYEOF;
+    }
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_string_to_deltat(char *string, krb5_deltat *deltatp)
+{
+    struct param p;
+    p.delta = 0;
+    p.p = string;
+    if (yyparse (&p))
+	return KRB5_DELTAT_BADFORMAT;
+    *deltatp = p.delta;
+    return 0;
+}
+
+
diff --git a/mechglue/src/lib/krb5/krb/enc_helper.c b/mechglue/src/lib/krb5/krb/enc_helper.c
new file mode 100644
index 000000000..63e3495da
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/enc_helper.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+
+krb5_error_code
+krb5_encrypt_helper(krb5_context context, const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *plain, krb5_enc_data *cipher)
+{
+    krb5_error_code ret;
+    size_t enclen;
+
+    if ((ret = krb5_c_encrypt_length(context, key->enctype, plain->length,
+				     &enclen)))
+	return(ret);
+
+    cipher->ciphertext.length = enclen;
+    if ((cipher->ciphertext.data = (char *) malloc(enclen)) == NULL)
+	return(ret);
+    ret = krb5_c_encrypt(context, key, usage, 0, plain, cipher);
+    if (ret) {
+	free(cipher->ciphertext.data);
+	cipher->ciphertext.data = NULL;
+    }
+
+    return(ret);
+}
+	
diff --git a/mechglue/src/lib/krb5/krb/encode_kdc.c b/mechglue/src/lib/krb5/krb/encode_kdc.c
new file mode 100644
index 000000000..8b879c015
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/encode_kdc.c
@@ -0,0 +1,128 @@
+/*
+ * lib/krb5/krb/encode_kdc.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_encode_kdc_rep() function.
+ */
+
+#include "k5-int.h"
+
+/*
+ Takes KDC rep parts in *rep and *encpart, and formats it into *enc_rep,
+ using message type type and encryption key client_key and encryption type
+ etype.
+
+ The string *enc_rep will be allocated before formatting; the caller should
+ free when finished.
+
+ returns system errors
+
+ dec_rep->enc_part.ciphertext is allocated and filled in.
+*/
+/* due to argument promotion rules, we need to use the DECLARG/OLDDECLARG
+   stuff... */
+krb5_error_code
+krb5_encode_kdc_rep(krb5_context context, krb5_msgtype type,
+		    const krb5_enc_kdc_rep_part *encpart,
+		    int using_subkey, const krb5_keyblock *client_key,
+		    krb5_kdc_rep *dec_rep, krb5_data **enc_rep)
+{
+    krb5_data *scratch;
+    krb5_error_code retval;
+    krb5_enc_kdc_rep_part tmp_encpart;
+    krb5_keyusage usage;
+
+    if (!krb5_c_valid_enctype(dec_rep->enc_part.enctype))
+	return KRB5_PROG_ETYPE_NOSUPP;
+
+    switch (type) {
+    case KRB5_AS_REP:
+	usage = KRB5_KEYUSAGE_AS_REP_ENCPART;
+	break;
+    case KRB5_TGS_REP:
+	if (using_subkey)
+	    usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY;
+	else
+	    usage = KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY;
+	break;
+    default:
+	return KRB5_BADMSGTYPE;
+    }
+
+    /*
+     * We don't want to modify encpart, but we need to be able to pass
+     * in the message type to the encoder, so it can set the ASN.1
+     * type correct.
+     * 
+     * Although note that it may be doing nothing with the message
+     * type, to be compatible with old versions of Kerberos that always
+     * encode this as a TGS_REP regardly of what it really should be;
+     * also note that the reason why we are passing it in a structure
+     * instead of as an argument to encode_krb5_enc_kdc_rep_part (the
+     * way we should) is for compatibility with the ISODE version of
+     * this fuction.  Ah, compatibility....
+     */
+    tmp_encpart = *encpart;
+    tmp_encpart.msg_type = type;
+    retval = encode_krb5_enc_kdc_rep_part(&tmp_encpart, &scratch);
+    if (retval) {
+	return retval;
+    }
+    memset(&tmp_encpart, 0, sizeof(tmp_encpart));
+
+#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
+krb5_free_data(context, scratch); }
+
+    retval = krb5_encrypt_helper(context, client_key, usage, scratch,
+				 &dec_rep->enc_part);
+
+#define cleanup_encpart() { \
+(void) memset(dec_rep->enc_part.ciphertext.data, 0, \
+	     dec_rep->enc_part.ciphertext.length); \
+free(dec_rep->enc_part.ciphertext.data); \
+dec_rep->enc_part.ciphertext.length = 0; \
+dec_rep->enc_part.ciphertext.data = 0;}
+
+    cleanup_scratch();
+
+    if (retval)
+	return(retval);
+
+    /* now it's ready to be encoded for the wire! */
+
+    switch (type) {
+    case KRB5_AS_REP:
+	retval = encode_krb5_as_rep(dec_rep, enc_rep);
+	break;
+    case KRB5_TGS_REP:
+	retval = encode_krb5_tgs_rep(dec_rep, enc_rep);
+	break;
+    }
+
+    if (retval)
+	cleanup_encpart();
+
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/encrypt_tk.c b/mechglue/src/lib/krb5/krb/encrypt_tk.c
new file mode 100644
index 000000000..ed2b8c1b8
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/encrypt_tk.c
@@ -0,0 +1,67 @@
+/*
+ * lib/krb5/krb/encrypt_tk.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_encrypt_tkt_part() routine.
+ */
+
+#include "k5-int.h"
+
+/*
+ Takes unencrypted dec_ticket & dec_tkt_part, encrypts with
+ dec_ticket->enc_part.etype
+ using *srv_key, and places result in dec_ticket->enc_part.
+ The string dec_ticket->enc_part.ciphertext will be allocated before
+ formatting.
+
+ returns errors from encryption routines, system errors
+
+ enc_part->ciphertext.data allocated & filled in with encrypted stuff
+*/
+
+krb5_error_code
+krb5_encrypt_tkt_part(krb5_context context, const krb5_keyblock *srv_key, register krb5_ticket *dec_ticket)
+{
+    krb5_data *scratch;
+    krb5_error_code retval;
+    register krb5_enc_tkt_part *dec_tkt_part = dec_ticket->enc_part2;
+
+    /*  start by encoding the to-be-encrypted part. */
+    if ((retval = encode_krb5_enc_tkt_part(dec_tkt_part, &scratch))) {
+	return retval;
+    }
+
+#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \
+krb5_free_data(context, scratch); }
+
+    /* call the encryption routine */
+    retval = krb5_encrypt_helper(context, srv_key,
+				 KRB5_KEYUSAGE_KDC_REP_TICKET, scratch,
+				 &dec_ticket->enc_part);
+
+    cleanup_scratch();
+
+    return(retval);
+}
diff --git a/mechglue/src/lib/krb5/krb/free_rtree.c b/mechglue/src/lib/krb5/krb/free_rtree.c
new file mode 100644
index 000000000..7914d3f23
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/free_rtree.c
@@ -0,0 +1,41 @@
+/*
+ * lib/krb5/krb/free_rtree.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_free_realm_tree()
+ */
+
+#include "k5-int.h"
+
+void
+krb5_free_realm_tree(krb5_context context, krb5_principal *realms)
+{
+    register krb5_principal *nrealms = realms;
+    while (*nrealms) {
+	krb5_free_principal(context, *nrealms);
+	nrealms++;
+    }
+    krb5_xfree(realms);
+}
diff --git a/mechglue/src/lib/krb5/krb/fwd_tgt.c b/mechglue/src/lib/krb5/krb/fwd_tgt.c
new file mode 100644
index 000000000..2db2c9e00
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/fwd_tgt.c
@@ -0,0 +1,197 @@
+/*
+ * lib/krb5/krb/get_in_tkt.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* helper function: convert flags to necessary KDC options */
+#define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
+
+/* Get a TGT for use at the remote host */
+krb5_error_code KRB5_CALLCONV
+krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context, char *rhost, krb5_principal client, krb5_principal server, krb5_ccache cc, int forwardable, krb5_data *outbuf)
+                         
+                                   
+                
+                          
+                          
+                   
+                          /* Should forwarded TGT also be forwardable? */
+                      
+{
+    krb5_replay_data replaydata;
+    krb5_data * scratch = 0;
+    krb5_address **addrs = NULL;
+    krb5_error_code retval;
+    krb5_creds creds, tgt;
+    krb5_creds *pcreds;
+    krb5_flags kdcoptions;
+    int close_cc = 0;
+    int free_rhost = 0;
+    krb5_enctype enctype = 0;
+    krb5_keyblock *session_key;
+    krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes;
+
+    memset((char *)&creds, 0, sizeof(creds));
+    memset((char *)&tgt, 0, sizeof(creds));
+
+    if (cc == 0) {
+      if ((retval = krb5int_cc_default(context, &cc)))
+	goto errout;
+      close_cc = 1;
+    }
+    retval = krb5_auth_con_getkey (context, auth_context, &session_key);
+    if (retval)
+      goto errout;
+    if (session_key) {
+	enctype = session_key->enctype;
+	krb5_free_keyblock (context, session_key);
+	session_key = NULL;
+    } else if (server) { /* must server be non-NULL when rhost is given? */
+	/* Try getting credentials to see what the remote side supports.
+	   Not bulletproof, just a heuristic.  */
+	krb5_creds in, *out = 0;
+	memset (&in, 0, sizeof(in));
+
+	retval = krb5_copy_principal (context, server, &in.server);
+	if (retval)
+	    goto punt;
+	retval = krb5_copy_principal (context, client, &in.client);
+	if (retval)
+	    goto punt;
+	retval = krb5_get_credentials (context, 0, cc, &in, &out);
+	if (retval)
+	    goto punt;
+	/* Got the credentials.  Okay, now record the enctype and
+	   throw them away.  */
+	enctype = out->keyblock.enctype;
+	krb5_free_creds (context, out);
+    punt:
+	krb5_free_cred_contents (context, &in);
+    }
+
+    if ((retval = krb5_copy_principal(context, client, &creds.client)))
+	goto errout;
+    
+    if ((retval = krb5_build_principal_ext(context, &creds.server,
+					   client->realm.length,
+					   client->realm.data,
+					   KRB5_TGS_NAME_SIZE,
+					   KRB5_TGS_NAME,
+					   client->realm.length,
+					   client->realm.data,
+					   0)))
+	goto errout;
+	
+    /* fetch tgt directly from cache */
+    context->use_conf_ktypes = 1;
+    retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES,
+				    &creds, &tgt);
+    context->use_conf_ktypes = old_use_conf_ktypes;
+    if (retval)
+	goto errout;
+
+    /* tgt->client must be equal to creds.client */
+    if (!krb5_principal_compare(context, tgt.client, creds.client)) {
+	retval = KRB5_PRINC_NOMATCH;
+	goto errout;
+    }
+
+    if (!tgt.ticket.length) {
+	retval = KRB5_NO_TKT_SUPPLIED;
+	goto errout;
+    }
+    
+    if (tgt.addresses && *tgt.addresses) {
+      if (rhost == NULL) {
+	if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) {
+retval = KRB5_FWD_BAD_PRINCIPAL;
+ goto errout;
+	}
+
+	if (krb5_princ_size(context, server) < 2){
+	  retval = KRB5_CC_BADNAME;
+	  goto errout;
+	}
+	
+	rhost = malloc(server->data[1].length+1);
+	if (!rhost) {
+	  retval = ENOMEM;
+	  goto errout;
+	}
+	free_rhost = 1;
+	memcpy(rhost, server->data[1].data, server->data[1].length);
+	rhost[server->data[1].length] = '\0';
+      }
+
+	retval = krb5_os_hostaddr(context, rhost, &addrs);
+	if (retval)
+	    goto errout;
+    }
+    
+    creds.keyblock.enctype = enctype;
+    creds.times = tgt.times;
+    creds.times.starttime = 0;
+    kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED;
+
+    if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */
+      kdcoptions &= ~(KDC_OPT_FORWARDABLE);
+
+    if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
+					addrs, &creds, &pcreds))) {
+	if (enctype) {
+	    creds.keyblock.enctype = 0;
+	    if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
+						addrs, &creds, &pcreds))) 
+		goto errout;
+	}
+	else goto errout;
+    }
+    retval = krb5_mk_1cred(context, auth_context, pcreds,
+                           &scratch, &replaydata);
+    krb5_free_creds(context, pcreds);
+
+    if (retval) {
+	if (scratch)
+	    krb5_free_data(context, scratch);
+    } else {
+	*outbuf = *scratch;
+	krb5_xfree(scratch);
+    }
+        
+errout:
+    if (addrs)
+	krb5_free_addresses(context, addrs);
+    if (close_cc)
+	krb5_cc_close(context, cc);
+    if (free_rhost)
+	free(rhost);
+    krb5_free_cred_contents(context, &creds);
+    krb5_free_cred_contents(context, &tgt);
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/gc_frm_kdc.c b/mechglue/src/lib/krb5/krb/gc_frm_kdc.c
new file mode 100644
index 000000000..807b81a86
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/gc_frm_kdc.c
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 1994,2003,2005 by the Massachusetts Institute of Technology.
+ * Copyright (c) 1994 CyberSAFE Corporation
+ * Copyright (c) 1993 Open Computing Security Group
+ * Copyright (c) 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * Neither M.I.T., the Open Computing Security Group, nor 
+ * CyberSAFE Corporation make any representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * krb5_get_cred_from_kdc() and related functions:
+ *
+ * Get credentials from some KDC somewhere, possibly accumulating TGTs
+ * along the way.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include "int-proto.h"
+
+struct tr_state;
+
+/*
+ * Ring buffer abstraction for TGTs returned from a ccache; avoids
+ * lots of excess copying.
+ */
+
+#define NCC_TGTS 2
+struct cc_tgts {
+    krb5_creds cred[NCC_TGTS];
+    int dirty[NCC_TGTS];
+    unsigned int cur, nxt;
+};
+
+/* NOTE: This only checks if NXT_TGT is CUR_CC_TGT. */
+#define NXT_TGT_IS_CACHED(ts)			\
+	((ts)->nxt_tgt == (ts)->cur_cc_tgt)
+
+#define MARK_CUR_CC_TGT_CLEAN(ts)			\
+do {							\
+	(ts)->cc_tgts.dirty[(ts)->cc_tgts.cur] = 0;	\
+} while (0)
+
+static void init_cc_tgts(struct tr_state *);
+static void shift_cc_tgts(struct tr_state *);
+static void clean_cc_tgts(struct tr_state *);
+
+/*
+ * State struct for do_traversal() and helpers.
+ *
+ * CUR_TGT and NXT_TGT can each point either into CC_TGTS or into
+ * KDC_TGTS.
+ *
+ * CUR_TGT is the "working" TGT, which will be used to obtain new
+ * TGTs.  NXT_TGT will be CUR_TGT for the next iteration of the loop.
+ *
+ * Part of the baroqueness of this setup is to deal with annoying
+ * differences between krb5_cc_retrieve_cred() and
+ * krb5_get_cred_via_tkt(); krb5_cc_retrieve_cred() fills in a
+ * caller-allocated krb5_creds, while krb5_get_cred_via_tkt()
+ * allocates a krb5_creds for return.
+ */
+struct tr_state {
+    krb5_context ctx;
+    krb5_ccache ccache;
+    krb5_principal *kdc_list;
+    unsigned int nkdcs;
+    krb5_principal *cur_kdc;
+    krb5_principal *nxt_kdc;
+    krb5_principal *lst_kdc;
+    krb5_creds *cur_tgt;
+    krb5_creds *nxt_tgt;
+    krb5_creds **kdc_tgts;
+    struct cc_tgts cc_tgts;
+    krb5_creds *cur_cc_tgt;
+    krb5_creds *nxt_cc_tgt;
+    unsigned int ntgts;
+};
+
+/*
+ * Debug support
+ */
+#ifdef DEBUG_GC_FRM_KDC
+
+#define TR_DBG(ts, prog) tr_dbg(ts, prog)
+#define TR_DBG_RET(ts, prog, ret) tr_dbg_ret(ts, prog, ret)
+#define TR_DBG_RTREE(ts, prog, princ) tr_dbg_rtree(ts, prog, princ)
+
+static void tr_dbg(struct tr_state *, const char *);
+static void tr_dbg_ret(struct tr_state *, const char *, krb5_error_code);
+static void tr_dbg_rtree(struct tr_state *, const char *, krb5_principal);
+
+#else
+
+#define TR_DBG(ts, prog)
+#define TR_DBG_RET(ts, prog, ret)
+#define TR_DBG_RTREE(ts, prog, princ)
+
+#endif /* !DEBUG_GC_FRM_KDC */
+
+/* Convert ticket flags to necessary KDC options */
+#define FLAGS2OPTS(flags) (flags & KDC_TKT_COMMON_MASK)
+
+/*
+ * Certain krb5_cc_retrieve_cred() errors are soft errors when looking
+ * for a cross-realm TGT.
+ */
+#define HARD_CC_ERR(r) ((r) && (r) != KRB5_CC_NOTFOUND &&	\
+	(r) != KRB5_CC_NOT_KTYPE)
+
+/*
+ * Flags for ccache lookups of cross-realm TGTs.
+ *
+ * A cross-realm TGT may be issued by some other intermediate realm's
+ * KDC, so we use KRB5_TC_MATCH_SRV_NAMEONLY.
+ */
+#define RETR_FLAGS (KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES)
+
+/*
+ * Prototypes of helper functions
+ */
+static krb5_error_code tgt_mcred(krb5_context, krb5_principal,
+    krb5_principal, krb5_principal, krb5_creds *);
+static krb5_error_code retr_local_tgt(struct tr_state *, krb5_principal);
+static krb5_error_code try_ccache(struct tr_state *, krb5_creds *);
+static krb5_error_code find_nxt_kdc(struct tr_state *);
+static krb5_error_code try_kdc(struct tr_state *, krb5_creds *);
+static krb5_error_code kdc_mcred(struct tr_state *, krb5_principal,
+    krb5_creds *mcreds);
+static krb5_error_code next_closest_tgt(struct tr_state *, krb5_principal);
+static krb5_error_code init_rtree(struct tr_state *,
+    krb5_principal, krb5_principal);
+static krb5_error_code do_traversal(krb5_context ctx, krb5_ccache,
+    krb5_principal client, krb5_principal server,
+    krb5_creds *out_cc_tgt, krb5_creds **out_tgt,
+    krb5_creds ***out_kdc_tgts);
+static krb5_error_code krb5_get_cred_from_kdc_opt(krb5_context, krb5_ccache,
+    krb5_creds *, krb5_creds **, krb5_creds ***, int);
+
+/*
+ * init_cc_tgts()
+ *
+ * Initialize indices for cached-TGT ring buffer.  Caller must zero
+ * CC_TGTS, CC_TGT_DIRTY arrays prior to calling.
+ */
+static void
+init_cc_tgts(struct tr_state *ts)
+{
+
+    ts->cc_tgts.cur = 0;
+    ts->cc_tgts.nxt = 1;
+    ts->cur_cc_tgt = &ts->cc_tgts.cred[0];
+    ts->nxt_cc_tgt = &ts->cc_tgts.cred[1];
+}
+
+/*
+ * shift_cc_tgts()
+ *
+ * Given a fresh assignment to NXT_CC_TGT, mark NXT_CC_TGT as dirty,
+ * and shift indices so old NXT_CC_TGT becomes new CUR_CC_TGT.  Clean
+ * the new NXT_CC_TGT.
+ */
+static void
+shift_cc_tgts(struct tr_state *ts)
+{
+    unsigned int i;
+    struct cc_tgts *rb;
+
+    rb = &ts->cc_tgts;
+    i = rb->cur = rb->nxt;
+    rb->dirty[i] = 1;
+    ts->cur_cc_tgt = ts->nxt_cc_tgt;
+
+    i = (i + 1) % NCC_TGTS;
+
+    rb->nxt = i;
+    ts->nxt_cc_tgt = &rb->cred[i];
+    if (rb->dirty[i]) {
+	krb5_free_cred_contents(ts->ctx, &rb->cred[i]);
+	rb->dirty[i] = 0;
+    }
+}
+
+/*
+ * clean_cc_tgts()
+ *
+ * Free CC_TGTS which were dirty, then mark them clean.
+ */
+static void
+clean_cc_tgts(struct tr_state *ts)
+{
+    unsigned int i;
+    struct cc_tgts *rb;
+
+    rb = &ts->cc_tgts;
+    for (i = 0; i < NCC_TGTS; i++) {
+	if (rb->dirty[i]) {
+	    krb5_free_cred_contents(ts->ctx, &rb->cred[i]);
+	    rb->dirty[i] = 0;
+	}
+    }
+}
+
+/*
+ * Debug support
+ */
+#ifdef DEBUG_GC_FRM_KDC
+static void
+tr_dbg(struct tr_state *ts, const char *prog)
+{
+    krb5_error_code retval;
+    char *cur_tgt_str, *cur_kdc_str, *nxt_kdc_str;
+
+    cur_tgt_str = cur_kdc_str = nxt_kdc_str = NULL;
+    retval = krb5_unparse_name(ts->ctx, ts->cur_tgt->server, &cur_tgt_str);
+    if (retval) goto cleanup;
+    retval = krb5_unparse_name(ts->ctx, *ts->cur_kdc, &cur_kdc_str);
+    if (retval) goto cleanup;
+    retval = krb5_unparse_name(ts->ctx, *ts->nxt_kdc, &nxt_kdc_str);
+    if (retval) goto cleanup;
+    fprintf(stderr, "%s: cur_tgt %s\n", prog, cur_tgt_str);
+    fprintf(stderr, "%s: cur_kdc %s\n", prog, cur_kdc_str);
+    fprintf(stderr, "%s: nxt_kdc %s\n", prog, nxt_kdc_str);
+cleanup:
+    if (cur_tgt_str)
+	krb5_free_unparsed_name(ts->ctx, cur_tgt_str);
+    if (cur_kdc_str)
+	krb5_free_unparsed_name(ts->ctx, cur_kdc_str);
+    if (nxt_kdc_str)
+	krb5_free_unparsed_name(ts->ctx, nxt_kdc_str);
+}
+
+static void
+tr_dbg_ret(struct tr_state *ts, const char *prog, krb5_error_code ret)
+{
+    fprintf(stderr, "%s: return %d (%s)\n", prog, (int)ret,
+	    error_message(ret));
+}
+
+static void
+tr_dbg_rtree(struct tr_state *ts, const char *prog, krb5_principal princ)
+{
+    char *str;
+
+    if (krb5_unparse_name(ts->ctx, princ, &str))
+	return;
+    fprintf(stderr, "%s: %s\n", prog, str);
+    krb5_free_unparsed_name(ts->ctx, str);
+}
+#endif /* DEBUG_GC_FRM_KDC */
+
+/*
+ * tgt_mcred()
+ *
+ * Return MCREDS for use as a match criterion.
+ *
+ * Resulting credential has CLIENT as the client principal, and
+ * krbtgt/realm_of(DST)@realm_of(SRC) as the server principal.  Zeroes
+ * MCREDS first, does not allocate MCREDS, and cleans MCREDS on
+ * failure.  The peculiar ordering of DST and SRC args is for
+ * consistency with krb5_tgtname().
+ */
+static krb5_error_code
+tgt_mcred(krb5_context ctx, krb5_principal client,
+	  krb5_principal dst, krb5_principal src,
+	  krb5_creds *mcreds)
+{
+    krb5_error_code retval;
+
+    retval = 0;
+    memset(mcreds, 0, sizeof(*mcreds));
+
+    retval = krb5_copy_principal(ctx, client, &mcreds->client);
+    if (retval)
+	goto cleanup;
+
+    retval = krb5_tgtname(ctx, krb5_princ_realm(ctx, dst),
+			  krb5_princ_realm(ctx, src), &mcreds->server);
+    if (retval)
+	goto cleanup;
+
+cleanup:
+    if (retval)
+	krb5_free_cred_contents(ctx, mcreds);
+
+    return retval;
+}
+
+/*
+ * init_rtree()
+ *
+ * Populate KDC_LIST with the output of krb5_walk_realm_tree().
+ */
+static krb5_error_code
+init_rtree(struct tr_state *ts,
+	   krb5_principal client, krb5_principal server)
+{
+    krb5_error_code retval;
+
+    ts->kdc_list = NULL;
+    retval = krb5_walk_realm_tree(ts->ctx, krb5_princ_realm(ts->ctx, client),
+				  krb5_princ_realm(ts->ctx, server),
+				  &ts->kdc_list, KRB5_REALM_BRANCH_CHAR);
+    if (retval)
+	return retval;
+
+    for (ts->nkdcs = 0; ts->kdc_list[ts->nkdcs]; ts->nkdcs++) {
+	assert(krb5_princ_size(ts->ctx, ts->kdc_list[ts->nkdcs]) == 2);
+	TR_DBG_RTREE(ts, "init_rtree", ts->kdc_list[ts->nkdcs]);
+    }
+    assert(ts->nkdcs > 1);
+    ts->lst_kdc = ts->kdc_list + ts->nkdcs - 1;
+
+    ts->kdc_tgts = calloc(ts->nkdcs + 1, sizeof(krb5_creds));
+    if (ts->kdc_tgts == NULL)
+	return ENOMEM;
+
+    return 0;
+}
+
+/*
+ * retr_local_tgt()
+ *
+ * Prime CUR_TGT with the cached TGT of the client's local realm.
+ */
+static krb5_error_code
+retr_local_tgt(struct tr_state *ts, krb5_principal client)
+{
+    krb5_error_code retval;
+    krb5_creds tgtq;
+
+    memset(&tgtq, 0, sizeof(tgtq));
+    retval = tgt_mcred(ts->ctx, client, client, client, &tgtq);
+    if (retval)
+	return retval;
+
+    /* Match realm, unlike other ccache retrievals here. */
+    retval = krb5_cc_retrieve_cred(ts->ctx, ts->ccache,
+				   KRB5_TC_SUPPORTED_KTYPES,
+				   &tgtq, ts->nxt_cc_tgt);
+    krb5_free_cred_contents(ts->ctx, &tgtq);
+    if (!retval) {
+	shift_cc_tgts(ts);
+	ts->nxt_tgt = ts->cur_tgt = ts->cur_cc_tgt;
+    }
+    return retval;
+}
+
+/*
+ * try_ccache()
+ *
+ * Attempt to retrieve desired NXT_TGT from ccache.  Point NXT_TGT to
+ * it if successful.
+ */
+static krb5_error_code
+try_ccache(struct tr_state *ts, krb5_creds *tgtq)
+{
+    krb5_error_code retval;
+
+    TR_DBG(ts, "try_ccache");
+    retval = krb5_cc_retrieve_cred(ts->ctx, ts->ccache, RETR_FLAGS,
+				   tgtq, ts->nxt_cc_tgt);
+    if (!retval) {
+	shift_cc_tgts(ts);
+	ts->nxt_tgt = ts->cur_cc_tgt;
+    }
+    TR_DBG_RET(ts, "try_ccache", retval);
+    return retval;
+}
+
+/*
+ * find_nxt_kdc()
+ *
+ * A NXT_TGT gotten from an intermediate KDC might actually be a
+ * referral.  Search KDC_LIST forward starting from CUR_KDC, looking
+ * for the KDC with the same remote realm as NXT_TGT.  If we don't
+ * find it, the intermediate KDC is leading us off the transit path.
+ *
+ * Match on CUR_KDC's remote realm, not local realm, because, among
+ * other reasons, we can get a referral to the final realm; e.g.,
+ * given
+ *
+ *     KDC_LIST == { krbtgt/R1@R1, krbtgt/R2@R1, krbtgt/R3@R2,
+ *                   krbtgt/R4@R3, NULL }
+ *     CUR_TGT->SERVER == krbtgt/R2@R1
+ *     NXT_TGT->SERVER == krbtgt/R4@R2
+ *
+ * i.e., we got a ticket issued by R2 with remote realm R4, we want to
+ * find krbtgt/R4@R3, not krbtgt/R3@R2, even though we have no TGT
+ * with R3 as its local realm.
+ *
+ * Set up for next iteration of do_traversal() loop by pointing
+ * NXT_KDC to one entry forward of the match.
+ */
+static krb5_error_code
+find_nxt_kdc(struct tr_state *ts)
+{
+    krb5_data *r1, *r2;
+    krb5_principal *kdcptr;
+
+    TR_DBG(ts, "find_nxt_kdc");
+    assert(ts->nxt_tgt == ts->kdc_tgts[ts->ntgts-1]);
+    if (krb5_princ_size(ts->ctx, ts->nxt_tgt->server) != 2)
+	return KRB5_KDCREP_MODIFIED;
+
+    r1 = krb5_princ_component(ts->ctx, ts->nxt_tgt->server, 1);
+
+    for (kdcptr = ts->cur_kdc + 1; *kdcptr != NULL; kdcptr++) {
+
+	r2 = krb5_princ_component(ts->ctx, *kdcptr, 1);
+
+	if (r1 != NULL && r2 != NULL &&
+	    r1->length == r2->length &&
+	    !memcmp(r1->data, r2->data, r1->length)) {
+	    break;
+	}
+    }
+    if (*kdcptr == NULL) {
+	/*
+	 * Not found; we probably got an unexpected realm referral.
+	 * Don't touch NXT_KDC, thus allowing next_closest_tgt() to
+	 * continue looping backwards.
+	 */
+	if (ts->ntgts > 0) {
+	    /* Punt NXT_TGT from KDC_TGTS if bogus. */
+	    krb5_free_creds(ts->ctx, ts->kdc_tgts[--ts->ntgts]);
+	}
+	TR_DBG_RET(ts, "find_nxt_kdc", KRB5_KDCREP_MODIFIED);
+	return KRB5_KDCREP_MODIFIED;
+    }
+    ts->nxt_kdc = kdcptr;
+    TR_DBG_RET(ts, "find_nxt_kdc", 0);
+    return 0;
+}
+
+/*
+ * try_kdc()
+ *
+ * Using CUR_TGT, attempt to get desired NXT_TGT.  Update NXT_KDC if
+ * successful.
+ */
+static krb5_error_code
+try_kdc(struct tr_state *ts, krb5_creds *tgtq)
+{
+    krb5_error_code retval;
+    krb5_creds ltgtq;
+
+    TR_DBG(ts, "try_kdc");
+    /* This check should probably be in gc_via_tkt. */
+    if (!krb5_c_valid_enctype(ts->cur_tgt->keyblock.enctype))
+	return KRB5_PROG_ETYPE_NOSUPP;
+
+    ltgtq = *tgtq;
+    ltgtq.is_skey = FALSE;
+    ltgtq.ticket_flags = ts->cur_tgt->ticket_flags;
+    retval = krb5_get_cred_via_tkt(ts->ctx, ts->cur_tgt,
+				   FLAGS2OPTS(ltgtq.ticket_flags),
+				   ts->cur_tgt->addresses,
+				   <gtq, &ts->kdc_tgts[ts->ntgts++]);
+    if (retval) {
+	ts->ntgts--;
+	ts->nxt_tgt = ts->cur_tgt;
+	TR_DBG_RET(ts, "try_kdc", retval);
+	return retval;
+    }
+    ts->nxt_tgt = ts->kdc_tgts[ts->ntgts-1];
+    retval = find_nxt_kdc(ts);
+    TR_DBG_RET(ts, "try_kdc", retval);
+    return retval;
+}
+
+/*
+ * kdc_mcred()
+ *
+ * Return MCREDS for use as a match criterion.
+ *
+ * Resulting credential has CLIENT as the client principal, and
+ * krbtgt/remote_realm(NXT_KDC)@local_realm(CUR_KDC) as the server
+ * principal.  Zeroes MCREDS first, does not allocate MCREDS, and
+ * cleans MCREDS on failure.
+ */
+static krb5_error_code
+kdc_mcred(struct tr_state *ts, krb5_principal client, krb5_creds *mcreds)
+{
+    krb5_error_code retval;
+    krb5_data *rdst, *rsrc;
+
+    retval = 0;
+    memset(mcreds, 0, sizeof(*mcreds));
+
+    rdst = krb5_princ_component(ts->ctx, *ts->nxt_kdc, 1);
+    rsrc = krb5_princ_component(ts->ctx, *ts->cur_kdc, 1);
+    retval = krb5_copy_principal(ts->ctx, client, &mcreds->client);
+    if (retval)
+	goto cleanup;
+
+    retval = krb5_tgtname(ts->ctx, rdst, rsrc, &mcreds->server);
+    if (retval)
+	goto cleanup;
+
+cleanup:
+    if (retval)
+	krb5_free_cred_contents(ts->ctx, mcreds);
+
+    return retval;
+}
+
+/*
+ * next_closest_tgt()
+ *
+ * Using CUR_TGT, attempt to get the cross-realm TGT having its remote
+ * realm closest to the target principal's.  Update NXT_TGT, NXT_KDC
+ * accordingly.
+ */
+static krb5_error_code
+next_closest_tgt(struct tr_state *ts, krb5_principal client)
+{
+    krb5_error_code retval;
+    krb5_creds tgtq;
+
+    retval = 0;
+    memset(&tgtq, 0, sizeof(tgtq));
+
+    for (ts->nxt_kdc = ts->lst_kdc;
+	 ts->nxt_kdc > ts->cur_kdc;
+	 ts->nxt_kdc--) {
+
+	krb5_free_cred_contents(ts->ctx, &tgtq);
+	retval = kdc_mcred(ts, client, &tgtq);
+	if (retval)
+	    goto cleanup;
+	/* Don't waste time retrying ccache for direct path. */
+	if (ts->cur_kdc != ts->kdc_list || ts->nxt_kdc != ts->lst_kdc) {
+	    retval = try_ccache(ts, &tgtq);
+	    if (!retval)
+		break;
+	    if (HARD_CC_ERR(retval))
+		goto cleanup;
+	}
+	/* Not in the ccache, so talk to a KDC. */
+	retval = try_kdc(ts, &tgtq);
+	if (!retval) {
+	    break;
+	}
+	/*
+	 * Because try_kdc() validates referral TGTs, it can return an
+	 * error indicating a bogus referral.  The loop continues when
+	 * it gets a bogus referral, which is arguably the right
+	 * thing.  (Previous implementation unconditionally failed.)
+	 */
+    }
+    /*
+     * If we have a non-zero retval, we either have a hard error or we
+     * failed to find a closer TGT.
+     */
+cleanup:
+    krb5_free_cred_contents(ts->ctx, &tgtq);
+    return retval;
+}
+
+/*
+ * do_traversal()
+ *
+ * Find final TGT needed to get CLIENT a ticket for SERVER.  Point
+ * OUT_TGT at the desired TGT, which may be an existing cached TGT
+ * (copied into OUT_CC_TGT) or one of the newly obtained TGTs
+ * (collected in OUT_KDC_TGTS).
+ *
+ * Get comfortable; this is somewhat complicated.
+ *
+ * Nomenclature: Cross-realm TGS principal names have the form:
+ *
+ *     krbtgt/REMOTE@LOCAL
+ *
+ * krb5_walk_realm_tree() returns a list like:
+ *
+ *     krbtgt/R1@R1, krbtgt/R2@R1, krbtgt/R3@R2, ...
+ *
+ * These are prinicpal names, not realm names.  We only really use the
+ * remote parts of the TGT principal names.
+ *
+ * The do_traversal loop calls next_closest_tgt() to find the next
+ * closest TGT to the destination realm.  next_closest_tgt() updates
+ * NXT_KDC for the following iteration of the do_traversal() loop.
+ *
+ * At the beginning of any given iteration of the do_traversal() loop,
+ * CUR_KDC's remote realm is the remote realm of CUR_TGT->SERVER.  The
+ * local realms of CUR_KDC and CUR_TGT->SERVER may not match due to
+ * short-circuit paths provided by intermediate KDCs, e.g., CUR_KDC
+ * might be krbtgt/D@C, while CUR_TGT->SERVER is krbtgt/D@B.
+ *
+ * For example, given KDC_LIST of
+ *
+ * krbtgt/R1@R1, krbtgt/R2@R1, krbtgt/R3@R2, krbtgt/R4@R3,
+ * krbtgt/R5@R4
+ *
+ * The next_closest_tgt() loop moves NXT_KDC to the left starting from
+ * R5, stopping before it reaches CUR_KDC.  When next_closest_tgt()
+ * returns, the do_traversal() loop updates CUR_KDC to be NXT_KDC, and
+ * calls next_closest_tgt() again.
+ *
+ * next_closest_tgt() at start of its loop:
+ *
+ *      CUR                 NXT
+ *       |                   |
+ *       V                   V
+ *     +----+----+----+----+----+
+ *     | R1 | R2 | R3 | R4 | R5 |
+ *     +----+----+----+----+----+
+ *
+ * next_closest_tgt() returns after finding a ticket for krbtgt/R3@R1:
+ *
+ *      CUR       NXT
+ *       |         |
+ *       V         V
+ *     +----+----+----+----+----+
+ *     | R1 | R2 | R3 | R4 | R5 |
+ *     +----+----+----+----+----+
+ *
+ * do_traversal() updates CUR_KDC:
+ *
+ *                NXT
+ *                CUR
+ *                 |
+ *                 V
+ *     +----+----+----+----+----+
+ *     | R1 | R2 | R3 | R4 | R5 |
+ *     +----+----+----+----+----+
+ *
+ * next_closest_tgt() at start of its loop:
+ *
+ *                CUR       NXT
+ *                 |         |
+ *                 V         V
+ *     +----+----+----+----+----+
+ *     | R1 | R2 | R3 | R4 | R5 |
+ *     +----+----+----+----+----+
+ *
+ * etc.
+ *
+ * The algorithm executes in n*(n-1)/2 (the sum of integers from 1 to
+ * n-1) attempts in the worst case, i.e., each KDC only has a
+ * cross-realm ticket for the immediately following KDC in the transit
+ * path.  Typically, short-circuit paths will cause execution occur
+ * faster than this worst-case scenario.
+ *
+ * When next_closest_tgt() updates NXT_KDC, it may not perform a
+ * simple increment from CUR_KDC, in part because some KDC may
+ * short-circuit pieces of the transit path.
+ */
+static krb5_error_code
+do_traversal(krb5_context ctx,
+	     krb5_ccache ccache,
+	     krb5_principal client,
+	     krb5_principal server,
+	     krb5_creds *out_cc_tgt,
+	     krb5_creds **out_tgt,
+	     krb5_creds ***out_kdc_tgts)
+{
+    krb5_error_code retval;
+    struct tr_state state, *ts;
+
+    *out_tgt = NULL;
+    *out_kdc_tgts = NULL;
+    ts = &state;
+    memset(ts, 0, sizeof(*ts));
+    ts->ctx = ctx;
+    ts->ccache = ccache;
+    init_cc_tgts(ts);
+
+    retval = init_rtree(ts, client, server);
+    if (retval)
+	goto cleanup;
+
+    retval = retr_local_tgt(ts, client);
+    if (retval)
+	goto cleanup;
+
+    for (ts->cur_kdc = ts->kdc_list, ts->nxt_kdc = NULL;
+	 ts->cur_kdc != NULL && ts->cur_kdc < ts->lst_kdc;
+	 ts->cur_kdc = ts->nxt_kdc, ts->cur_tgt = ts->nxt_tgt) {
+
+	retval = next_closest_tgt(ts, client);
+	if (retval)
+	    goto cleanup;
+	assert(ts->cur_kdc != ts->nxt_kdc);
+    }
+
+    if (NXT_TGT_IS_CACHED(ts)) {
+	*out_cc_tgt = *ts->cur_cc_tgt;
+	*out_tgt = out_cc_tgt;
+	MARK_CUR_CC_TGT_CLEAN(ts);
+    } else {
+	/* CUR_TGT is somewhere in KDC_TGTS; no need to copy. */
+	*out_tgt = ts->nxt_tgt;
+    }
+
+cleanup:
+    clean_cc_tgts(ts);
+    if (ts->kdc_list != NULL)
+	krb5_free_realm_tree(ctx, ts->kdc_list);
+    if (ts->ntgts == 0) {
+	*out_kdc_tgts = NULL;
+	if (ts->kdc_tgts != NULL)
+	    free(ts->kdc_tgts);
+    } else
+	*out_kdc_tgts = ts->kdc_tgts;
+    return retval;
+}
+
+/*
+ * krb5_get_cred_from_kdc_opt()
+ * krb5_get_cred_from_kdc()
+ * krb5_get_cred_from_kdc_validate()
+ * krb5_get_cred_from_kdc_renew()
+ *
+ * Retrieve credentials for client IN_CRED->CLIENT, server
+ * IN_CRED->SERVER, ticket flags IN_CRED->TICKET_FLAGS, possibly
+ * second_ticket if needed.
+ *
+ * Request credentials from the KDC for the server's realm.  Point
+ * TGTS to an allocated array of pointers to krb5_creds, containing
+ * any intermediate credentials obtained in the process of contacting
+ * the server's KDC; if no intermediate credentials were obtained,
+ * TGTS is a null pointer.  Return intermediate credentials if
+ * intermediate KDCs provided credentials, even if no useful end
+ * ticket results.
+ *
+ * Caller must free TGTS, regardless of whether this function returns
+ * success.
+ *
+ * This function does NOT cache the intermediate TGTs.
+ *
+ * Do not call this routine if desired credentials are already cached.
+ *
+ * On success, OUT_CRED contains the desired credentials; the caller
+ * must free them.
+ *
+ * Returns errors, system errors.
+ */
+
+static krb5_error_code
+krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
+			   krb5_creds *in_cred, krb5_creds **out_cred,
+			   krb5_creds ***tgts, int kdcopt)
+{
+    krb5_error_code retval;
+    krb5_principal client, server;
+    krb5_creds tgtq, cc_tgt, *tgtptr;
+    krb5_boolean old_use_conf_ktypes;
+
+    client = in_cred->client;
+    server = in_cred->server;
+    memset(&cc_tgt, 0, sizeof(cc_tgt));
+    memset(&tgtq, 0, sizeof(tgtq));
+    tgtptr = NULL;
+    *tgts = NULL;
+    old_use_conf_ktypes = context->use_conf_ktypes;
+
+    /*
+     * Get a TGT for the target realm.
+     */
+
+    retval = tgt_mcred(context, client, server, client, &tgtq);
+    if (retval)
+	goto cleanup;
+
+    /* Fast path: Is it in the ccache? */
+    context->use_conf_ktypes = 1;
+    retval = krb5_cc_retrieve_cred(context, ccache, RETR_FLAGS,
+				   &tgtq, &cc_tgt);
+    if (!retval) {
+	tgtptr = &cc_tgt;
+    } else if (!HARD_CC_ERR(retval)) {
+	/* Not in ccache, so traverse the transit path. */
+	retval = do_traversal(context, ccache, client, server,
+			      &cc_tgt, &tgtptr, tgts);
+    }
+    if (retval)
+	goto cleanup;
+
+    /*
+     * Finally have TGT for target realm!  Try using it to get creds.
+     */
+
+    if (!krb5_c_valid_enctype(tgtptr->keyblock.enctype)) {
+	retval = KRB5_PROG_ETYPE_NOSUPP;
+	goto cleanup;
+    }
+
+    context->use_conf_ktypes = old_use_conf_ktypes;
+    retval = krb5_get_cred_via_tkt(context, tgtptr,
+				   FLAGS2OPTS(tgtptr->ticket_flags) |
+				   kdcopt |
+				   (in_cred->second_ticket.length ?
+				    KDC_OPT_ENC_TKT_IN_SKEY : 0),
+				   tgtptr->addresses, in_cred, out_cred);
+
+cleanup:
+    krb5_free_cred_contents(context, &tgtq);
+    if (tgtptr == &cc_tgt)
+	krb5_free_cred_contents(context, tgtptr);
+    context->use_conf_ktypes = old_use_conf_ktypes;
+
+    return retval;
+}
+
+krb5_error_code
+krb5_get_cred_from_kdc(krb5_context context, krb5_ccache ccache,
+		       krb5_creds *in_cred, krb5_creds **out_cred,
+		       krb5_creds ***tgts)
+{
+    return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
+				      0);
+}
+
+krb5_error_code
+krb5_get_cred_from_kdc_validate(krb5_context context, krb5_ccache ccache,
+				krb5_creds *in_cred, krb5_creds **out_cred,
+				krb5_creds ***tgts)
+{
+    return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
+				      KDC_OPT_VALIDATE);
+}
+
+krb5_error_code
+krb5_get_cred_from_kdc_renew(krb5_context context, krb5_ccache ccache,
+			     krb5_creds *in_cred, krb5_creds **out_cred,
+			     krb5_creds ***tgts)
+{
+    return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
+				      KDC_OPT_RENEW);
+}
diff --git a/mechglue/src/lib/krb5/krb/gc_via_tkt.c b/mechglue/src/lib/krb5/krb/gc_via_tkt.c
new file mode 100644
index 000000000..1008d1f92
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/gc_via_tkt.c
@@ -0,0 +1,244 @@
+/*
+ * lib/krb5/krb/gc_via_tgt.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Given a tkt, and a target cred, get it.
+ * Assumes that the kdc_rep has been decrypted.
+ */
+
+#include "k5-int.h"
+#include "int-proto.h"
+
+#define in_clock_skew(date, now) (labs((date)-(now)) < context->clockskew)
+
+static krb5_error_code
+krb5_kdcrep2creds(krb5_context context, krb5_kdc_rep *pkdcrep, krb5_address *const *address, krb5_data *psectkt, krb5_creds **ppcreds)
+{
+    krb5_error_code retval;  
+    krb5_data *pdata;
+  
+    if ((*ppcreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
+        return ENOMEM;
+    }
+
+    memset(*ppcreds, 0, sizeof(krb5_creds));
+
+    if ((retval = krb5_copy_principal(context, pkdcrep->client,
+                                     &(*ppcreds)->client)))
+        goto cleanup;
+
+    if ((retval = krb5_copy_principal(context, pkdcrep->enc_part2->server,
+                                     &(*ppcreds)->server)))
+        goto cleanup;
+
+    if ((retval = krb5_copy_keyblock_contents(context, 
+					      pkdcrep->enc_part2->session,
+					      &(*ppcreds)->keyblock)))
+        goto cleanup;
+
+    if ((retval = krb5_copy_data(context, psectkt, &pdata)))
+	goto cleanup;
+    (*ppcreds)->second_ticket = *pdata;
+    krb5_xfree(pdata);
+
+    (*ppcreds)->ticket_flags = pkdcrep->enc_part2->flags;
+    (*ppcreds)->times = pkdcrep->enc_part2->times;
+    (*ppcreds)->magic = KV5M_CREDS;
+
+    (*ppcreds)->authdata = NULL;   			/* not used */
+    (*ppcreds)->is_skey = psectkt->length != 0;
+
+    if (pkdcrep->enc_part2->caddrs) {
+	if ((retval = krb5_copy_addresses(context, pkdcrep->enc_part2->caddrs,
+					  &(*ppcreds)->addresses)))
+	    goto cleanup_keyblock;
+    } else {
+	/* no addresses in the list means we got what we had */
+	if ((retval = krb5_copy_addresses(context, address,
+					  &(*ppcreds)->addresses)))
+	    goto cleanup_keyblock;
+    }
+
+    if ((retval = encode_krb5_ticket(pkdcrep->ticket, &pdata)))
+	goto cleanup_keyblock;
+
+    (*ppcreds)->ticket = *pdata;
+    free(pdata);
+    return 0;
+
+cleanup_keyblock:
+    krb5_free_keyblock(context, &(*ppcreds)->keyblock);
+
+cleanup:
+    free (*ppcreds);
+    return retval;
+}
+ 
+krb5_error_code
+krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt,
+		       krb5_flags kdcoptions, krb5_address *const *address,
+		       krb5_creds *in_cred, krb5_creds **out_cred)
+{
+    krb5_error_code retval;
+    krb5_kdc_rep *dec_rep;
+    krb5_error *err_reply;
+    krb5_response tgsrep;
+    krb5_enctype *enctypes = 0;
+
+    /* tkt->client must be equal to in_cred->client */
+    if (!krb5_principal_compare(context, tkt->client, in_cred->client))
+	return KRB5_PRINC_NOMATCH;
+
+    if (!tkt->ticket.length)
+	return KRB5_NO_TKT_SUPPLIED;
+
+    if ((kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) && 
+	(!in_cred->second_ticket.length))
+        return(KRB5_NO_2ND_TKT);
+
+
+    /* check if we have the right TGT                    */
+    /* tkt->server must be equal to                      */
+    /* krbtgt/realmof(cred->server)@realmof(tgt->server) */
+/*
+    {
+    krb5_principal tempprinc;
+        if (retval = krb5_tgtname(context, 
+		     krb5_princ_realm(context, in_cred->server),
+		     krb5_princ_realm(context, tkt->server), &tempprinc))
+    	    return(retval);
+
+        if (!krb5_principal_compare(context, tempprinc, tkt->server)) {
+            krb5_free_principal(context, tempprinc);
+	    return (KRB5_PRINC_NOMATCH);
+        }
+    krb5_free_principal(context, tempprinc);
+    }
+*/
+
+    if (in_cred->keyblock.enctype) {
+	enctypes = (krb5_enctype *) malloc(sizeof(krb5_enctype)*2);
+	if (!enctypes)
+	    return ENOMEM;
+	enctypes[0] = in_cred->keyblock.enctype;
+	enctypes[1] = 0;
+    }
+    
+    retval = krb5_send_tgs(context, kdcoptions, &in_cred->times, enctypes, 
+			   in_cred->server, address, in_cred->authdata,
+			   0,		/* no padata */
+			   (kdcoptions & KDC_OPT_ENC_TKT_IN_SKEY) ? 
+			   &in_cred->second_ticket : NULL,
+			   tkt, &tgsrep);
+    if (enctypes)
+	free(enctypes);
+    if (retval)
+	return retval;
+
+    switch (tgsrep.message_type) {
+    case KRB5_TGS_REP:
+	break;
+    case KRB5_ERROR:
+    default:
+	if (krb5_is_krb_error(&tgsrep.response))
+	    retval = decode_krb5_error(&tgsrep.response, &err_reply);
+	else
+	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
+
+	if (retval) 			/* neither proper reply nor error! */
+	    goto error_4;
+
+	retval = (krb5_error_code) err_reply->error + ERROR_TABLE_BASE_krb5;
+
+	krb5_free_error(context, err_reply);
+	goto error_4;
+    }
+
+    if ((retval = krb5_decode_kdc_rep(context, &tgsrep.response,
+				      &tkt->keyblock, &dec_rep)))
+	goto error_4;
+
+    if (dec_rep->msg_type != KRB5_TGS_REP) {
+	retval = KRB5KRB_AP_ERR_MSG_TYPE;
+	goto error_3;
+    }
+   
+    /* make sure the response hasn't been tampered with..... */
+    retval = 0;
+
+    if (!krb5_principal_compare(context, dec_rep->client, tkt->client))
+	retval = KRB5_KDCREP_MODIFIED;
+
+    if (!krb5_principal_compare(context, dec_rep->enc_part2->server, in_cred->server))
+	retval = KRB5_KDCREP_MODIFIED;
+
+    if (!krb5_principal_compare(context, dec_rep->ticket->server, in_cred->server))
+	retval = KRB5_KDCREP_MODIFIED;
+
+    if (dec_rep->enc_part2->nonce != tgsrep.expected_nonce)
+	retval = KRB5_KDCREP_MODIFIED;
+
+    if ((kdcoptions & KDC_OPT_POSTDATED) &&
+	(in_cred->times.starttime != 0) &&
+    	(in_cred->times.starttime != dec_rep->enc_part2->times.starttime))
+	retval = KRB5_KDCREP_MODIFIED;
+
+    if ((in_cred->times.endtime != 0) &&
+	(dec_rep->enc_part2->times.endtime > in_cred->times.endtime))
+	retval = KRB5_KDCREP_MODIFIED;
+
+    if ((kdcoptions & KDC_OPT_RENEWABLE) &&
+	(in_cred->times.renew_till != 0) &&
+	(dec_rep->enc_part2->times.renew_till > in_cred->times.renew_till))
+	retval = KRB5_KDCREP_MODIFIED;
+
+    if ((kdcoptions & KDC_OPT_RENEWABLE_OK) &&
+	(dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) &&
+	(in_cred->times.endtime != 0) &&
+	(dec_rep->enc_part2->times.renew_till > in_cred->times.endtime))
+ 	retval = KRB5_KDCREP_MODIFIED;
+
+    if (retval != 0)
+    	goto error_3;
+
+    if (!in_cred->times.starttime &&
+	!in_clock_skew(dec_rep->enc_part2->times.starttime,
+		       tgsrep.request_time)) {
+	retval = KRB5_KDCREP_SKEW;
+	goto error_3;
+    }
+    
+    retval = krb5_kdcrep2creds(context, dec_rep, address, 
+			       &in_cred->second_ticket,  out_cred);
+
+error_3:;
+    memset(dec_rep->enc_part2->session->contents, 0,
+	   dec_rep->enc_part2->session->length);
+    krb5_free_kdc_rep(context, dec_rep);
+
+error_4:;
+    free(tgsrep.response.data);
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/gen_seqnum.c b/mechglue/src/lib/krb5/krb/gen_seqnum.c
new file mode 100644
index 000000000..373764097
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/gen_seqnum.c
@@ -0,0 +1,67 @@
+/*
+ * lib/krb5/krb/gen_seqnum.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Routine to automatically generate a starting sequence number.
+ * We do this by getting a random key and encrypting something with it,
+ * then taking the output and slicing it up.
+ */
+
+#include "k5-int.h"
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+krb5_error_code
+krb5_generate_seq_number(krb5_context context, const krb5_keyblock *key, krb5_ui_4 *seqno)
+{
+    krb5_data seed;
+    krb5_error_code retval;
+
+    seed.length = key->length;
+    seed.data = key->contents;
+    if ((retval = krb5_c_random_add_entropy(context, KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed)))
+	return(retval);
+
+    seed.length = sizeof(*seqno);
+    seed.data = (char *) seqno;
+    retval = krb5_c_random_make_octets(context, &seed);
+    if (retval)
+	return retval;
+    /*
+     * Work around implementation incompatibilities by not generating
+     * initial sequence numbers greater than 2^30.  Previous MIT
+     * implementations use signed sequence numbers, so initial
+     * sequence numbers 2^31 to 2^32-1 inclusive will be rejected.
+     * Letting the maximum initial sequence number be 2^30-1 allows
+     * for about 2^30 messages to be sent before wrapping into
+     * "negative" numbers.
+     */
+    *seqno &= 0x3fffffff;
+    if (*seqno == 0)
+	*seqno = 1;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/gen_subkey.c b/mechglue/src/lib/krb5/krb/gen_subkey.c
new file mode 100644
index 000000000..7ffc91f13
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/gen_subkey.c
@@ -0,0 +1,52 @@
+/*
+ * lib/krb5/krb/gen_subkey.c
+ *
+ * Copyright 1991, 2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Routine to automatically generate a subsession key based on an input key.
+ */
+
+#include "k5-int.h"
+
+krb5_error_code
+krb5_generate_subkey(krb5_context context, const krb5_keyblock *key, krb5_keyblock **subkey)
+{
+    krb5_error_code retval;
+    krb5_data seed;
+
+    seed.length = key->length;
+    seed.data = key->contents;
+    if ((retval = krb5_c_random_add_entropy(context, KRB5_C_RANDSOURCE_TRUSTEDPARTY, &seed)))
+	return(retval);
+
+    if ((*subkey = (krb5_keyblock *) malloc(sizeof(krb5_keyblock))) == NULL)
+	return(ENOMEM);
+
+    if ((retval = krb5_c_make_random_key(context, key->enctype, *subkey))) {
+	krb5_xfree(*subkey);
+	return(retval);
+    }
+
+    return(0);
+}
diff --git a/mechglue/src/lib/krb5/krb/get_creds.c b/mechglue/src/lib/krb5/krb/get_creds.c
new file mode 100644
index 000000000..7dd3ad6c9
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/get_creds.c
@@ -0,0 +1,333 @@
+/*
+ * lib/krb5/krb/get_creds.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_get_credentials()
+ */
+
+
+
+/*
+ Attempts to use the credentials cache or TGS exchange to get an additional
+ ticket for the
+ client identified by in_creds->client, the server identified by
+ in_creds->server, with options options, expiration date specified in
+ in_creds->times.endtime (0 means as long as possible), session key type
+ specified in in_creds->keyblock.enctype (if non-zero)
+
+ Any returned ticket and intermediate ticket-granting tickets are
+ stored in ccache.
+
+ returns errors from encryption routines, system errors
+ */
+
+#include "k5-int.h"
+
+static krb5_error_code
+krb5_get_credentials_core(krb5_context context, krb5_flags options,
+			  krb5_creds *in_creds, krb5_creds *mcreds,
+			  krb5_flags *fields)
+{
+    if (!in_creds || !in_creds->server || !in_creds->client)
+        return EINVAL;
+
+    memset((char *)mcreds, 0, sizeof(krb5_creds));
+    mcreds->magic = KV5M_CREDS;
+    if (in_creds->times.endtime != 0) {
+	mcreds->times.endtime = in_creds->times.endtime;
+    } else {
+	krb5_error_code retval;
+	retval = krb5_timeofday(context, &mcreds->times.endtime);
+	if (retval != 0) return retval;
+    }
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    mcreds->keyblock = in_creds->keyblock;
+#else
+    memcpy(&mcreds->keyblock, &in_creds->keyblock, sizeof(krb5_keyblock));
+#endif
+    mcreds->authdata = in_creds->authdata;
+    mcreds->server = in_creds->server;
+    mcreds->client = in_creds->client;
+    
+    *fields = KRB5_TC_MATCH_TIMES /*XXX |KRB5_TC_MATCH_SKEY_TYPE */
+	| KRB5_TC_MATCH_AUTHDATA
+	| KRB5_TC_SUPPORTED_KTYPES;
+    if (mcreds->keyblock.enctype) {
+	krb5_enctype *ktypes;
+	krb5_error_code ret;
+	int i;
+
+	*fields |= KRB5_TC_MATCH_KTYPE;
+	ret = krb5_get_tgs_ktypes (context, mcreds->server, &ktypes);
+	for (i = 0; ktypes[i]; i++)
+	    if (ktypes[i] == mcreds->keyblock.enctype)
+		break;
+	if (ktypes[i] == 0)
+	    ret = KRB5_CC_NOT_KTYPE;
+	free (ktypes);
+	if (ret)
+	    return ret;
+    }
+    if (options & KRB5_GC_USER_USER) {
+	/* also match on identical 2nd tkt and tkt encrypted in a
+	   session key */
+	*fields |= KRB5_TC_MATCH_2ND_TKT|KRB5_TC_MATCH_IS_SKEY;
+	mcreds->is_skey = TRUE;
+	mcreds->second_ticket = in_creds->second_ticket;
+	if (!in_creds->second_ticket.length)
+	    return KRB5_NO_2ND_TKT;
+    }
+
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials(krb5_context context, krb5_flags options,
+		     krb5_ccache ccache, krb5_creds *in_creds,
+		     krb5_creds **out_creds)
+{
+    krb5_error_code retval;
+    krb5_creds mcreds;
+    krb5_creds *ncreds;
+    krb5_creds **tgts;
+    krb5_flags fields;
+    int not_ktype;
+
+    retval = krb5_get_credentials_core(context, options,
+				       in_creds,
+				       &mcreds, &fields);
+
+    if (retval) return retval;
+
+    if ((ncreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL)
+	return ENOMEM;
+
+    memset((char *)ncreds, 0, sizeof(krb5_creds));
+    ncreds->magic = KV5M_CREDS;
+
+    /* The caller is now responsible for cleaning up in_creds */
+    if ((retval = krb5_cc_retrieve_cred(context, ccache, fields, &mcreds,
+					ncreds))) {
+	krb5_xfree(ncreds);
+	ncreds = in_creds;
+    } else {
+	*out_creds = ncreds;
+    }
+
+    if ((retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE)
+	|| options & KRB5_GC_CACHED)
+	return retval;
+
+    if (retval == KRB5_CC_NOT_KTYPE)
+	not_ktype = 1;
+    else
+	not_ktype = 0;
+
+    retval = krb5_get_cred_from_kdc(context, ccache, ncreds, out_creds, &tgts);
+    if (tgts) {
+	register int i = 0;
+	krb5_error_code rv2;
+	while (tgts[i]) {
+	    if ((rv2 = krb5_cc_store_cred(context, ccache, tgts[i]))) {
+		retval = rv2;
+		break;
+	    }
+	    i++;
+	}
+	krb5_free_tgt_creds(context, tgts);
+    }
+    /*
+     * Translate KRB5_CC_NOTFOUND if we previously got
+     * KRB5_CC_NOT_KTYPE from krb5_cc_retrieve_cred(), in order to
+     * handle the case where there is no TGT in the ccache and the
+     * input enctype didn't match.  This handling is necessary because
+     * some callers, such as GSSAPI, iterate through enctypes and
+     * KRB5_CC_NOTFOUND passed through from the
+     * krb5_get_cred_from_kdc() is semantically incorrect, since the
+     * actual failure was the non-existence of a ticket of the correct
+     * enctype rather than the missing TGT.
+     */
+    if ((retval == KRB5_CC_NOTFOUND || retval == KRB5_CC_NOT_KTYPE)
+	&& not_ktype)
+	retval = KRB5_CC_NOT_KTYPE;
+
+    if (!retval) {
+        /* the purpose of the krb5_get_credentials call is to 
+         * obtain a set of credentials for the caller.  the 
+         * krb5_cc_store_cred() call is to optimize performance
+         * for future calls.  Ignore any errors, since the credentials
+         * are still valid even if we fail to store them in the cache.
+         */
+	krb5_cc_store_cred(context, ccache, *out_creds);
+    }
+    return retval;
+}
+
+#define INT_GC_VALIDATE 1
+#define INT_GC_RENEW 2
+
+static krb5_error_code 
+krb5_get_credentials_val_renew_core(krb5_context context, krb5_flags options,
+				    krb5_ccache ccache, krb5_creds *in_creds,
+				    krb5_creds **out_creds, int which)
+{
+    krb5_error_code retval;
+    krb5_principal tmp;
+    krb5_creds **tgts = 0;
+
+    switch(which) {
+    case INT_GC_VALIDATE:
+	    retval = krb5_get_cred_from_kdc_validate(context, ccache, 
+					     in_creds, out_creds, &tgts);
+	    break;
+    case INT_GC_RENEW:
+	    retval = krb5_get_cred_from_kdc_renew(context, ccache, 
+					     in_creds, out_creds, &tgts);
+	    break;
+    default:
+	    /* Should never happen */
+	    retval = 255;
+	    break;
+    }
+    if (retval) return retval;
+    if (tgts) krb5_free_tgt_creds(context, tgts);
+
+    retval = krb5_cc_get_principal(context, ccache, &tmp);
+    if (retval) return retval;
+    
+    retval = krb5_cc_initialize(context, ccache, tmp);
+    if (retval) return retval;
+    
+    retval = krb5_cc_store_cred(context, ccache, *out_creds);
+    return retval;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_validate(krb5_context context, krb5_flags options,
+			      krb5_ccache ccache, krb5_creds *in_creds,
+			      krb5_creds **out_creds)
+{
+    return(krb5_get_credentials_val_renew_core(context, options, ccache, 
+					       in_creds, out_creds, 
+					       INT_GC_VALIDATE));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_credentials_renew(krb5_context context, krb5_flags options,
+			   krb5_ccache ccache, krb5_creds *in_creds,
+			   krb5_creds **out_creds)
+{
+
+    return(krb5_get_credentials_val_renew_core(context, options, ccache, 
+					       in_creds, out_creds, 
+					       INT_GC_RENEW));
+}
+
+static krb5_error_code
+krb5_validate_or_renew_creds(krb5_context context, krb5_creds *creds,
+			     krb5_principal client, krb5_ccache ccache,
+			     char *in_tkt_service, int validate)
+{
+    krb5_error_code ret;
+    krb5_creds in_creds; /* only client and server need to be filled in */
+    krb5_creds *out_creds = 0; /* for check before dereferencing below */
+    krb5_creds **tgts;
+
+    memset((char *)&in_creds, 0, sizeof(krb5_creds));
+
+    in_creds.server = NULL;
+    tgts = NULL;
+
+    in_creds.client = client;
+
+    if (in_tkt_service) {
+	/* this is ugly, because so are the data structures involved.  I'm
+	   in the library, so I'm going to manipulate the data structures
+	   directly, otherwise, it will be worse. */
+
+        if ((ret = krb5_parse_name(context, in_tkt_service, &in_creds.server)))
+	    goto cleanup;
+
+	/* stuff the client realm into the server principal.
+	   realloc if necessary */
+	if (in_creds.server->realm.length < in_creds.client->realm.length)
+	    if ((in_creds.server->realm.data =
+		 (char *) realloc(in_creds.server->realm.data,
+				  in_creds.client->realm.length)) == NULL) {
+		ret = ENOMEM;
+		goto cleanup;
+	    }
+
+	in_creds.server->realm.length = in_creds.client->realm.length;
+	memcpy(in_creds.server->realm.data, in_creds.client->realm.data,
+	       in_creds.client->realm.length);
+    } else {
+	if ((ret = krb5_build_principal_ext(context, &in_creds.server,
+					   in_creds.client->realm.length,
+					   in_creds.client->realm.data,
+					   KRB5_TGS_NAME_SIZE,
+					   KRB5_TGS_NAME,
+					   in_creds.client->realm.length,
+					   in_creds.client->realm.data,
+					    0)))
+	    goto cleanup;
+    }
+
+    if (validate)
+	ret = krb5_get_cred_from_kdc_validate(context, ccache, 
+					      &in_creds, &out_creds, &tgts);
+    else
+	ret = krb5_get_cred_from_kdc_renew(context, ccache, 
+					   &in_creds, &out_creds, &tgts);
+   
+    /* ick.  copy the struct contents, free the container */
+    if (out_creds) {
+	*creds = *out_creds;
+	krb5_xfree(out_creds);
+    }
+
+cleanup:
+
+    if (in_creds.server)
+	krb5_free_principal(context, in_creds.server);
+    if (tgts)
+	krb5_free_tgt_creds(context, tgts);
+
+    return(ret);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_validated_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *in_tkt_service)
+{
+    return(krb5_validate_or_renew_creds(context, creds, client, ccache,
+					in_tkt_service, 1));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_renewed_creds(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_ccache ccache, char *in_tkt_service)
+{
+    return(krb5_validate_or_renew_creds(context, creds, client, ccache,
+					in_tkt_service, 0));
+}
diff --git a/mechglue/src/lib/krb5/krb/get_in_tkt.c b/mechglue/src/lib/krb5/krb/get_in_tkt.c
new file mode 100644
index 000000000..462dc7c82
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/get_in_tkt.c
@@ -0,0 +1,1118 @@
+/*
+ * lib/krb5/krb/get_in_tkt.c
+ *
+ * Copyright 1990,1991, 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_get_in_tkt()
+ */
+
+#include <string.h>
+
+#include "k5-int.h"
+#include "int-proto.h"
+#include "os-proto.h"
+
+/*
+ All-purpose initial ticket routine, usually called via
+ krb5_get_in_tkt_with_password or krb5_get_in_tkt_with_skey.
+
+ Attempts to get an initial ticket for creds->client to use server
+ creds->server, (realm is taken from creds->client), with options
+ options, and using creds->times.starttime, creds->times.endtime,
+ creds->times.renew_till as from, till, and rtime.  
+ creds->times.renew_till is ignored unless the RENEWABLE option is requested.
+
+ key_proc is called to fill in the key to be used for decryption.
+ keyseed is passed on to key_proc.
+
+ decrypt_proc is called to perform the decryption of the response (the
+ encrypted part is in dec_rep->enc_part; the decrypted part should be
+ allocated and filled into dec_rep->enc_part2
+ arg is passed on to decrypt_proc.
+
+ If addrs is non-NULL, it is used for the addresses requested.  If it is
+ null, the system standard addresses are used.
+
+ A succesful call will place the ticket in the credentials cache ccache
+ and fill in creds with the ticket information used/returned..
+
+ returns system errors, encryption errors
+
+ */
+
+
+/* some typedef's for the function args to make things look a bit cleaner */
+
+typedef krb5_error_code (*git_key_proc) (krb5_context,
+						   const krb5_enctype,
+						   krb5_data *,
+						   krb5_const_pointer,
+						   krb5_keyblock **);
+
+typedef krb5_error_code (*git_decrypt_proc) (krb5_context,
+						       const krb5_keyblock *,
+						       krb5_const_pointer,
+						       krb5_kdc_rep * );
+
+static krb5_error_code make_preauth_list (krb5_context, 
+						    krb5_preauthtype *,
+						    int, krb5_pa_data ***);
+
+/*
+ * This function performs 32 bit bounded addition so we can generate
+ * lifetimes without overflowing krb5_int32
+ */
+static krb5_int32 krb5int_addint32 (krb5_int32 x, krb5_int32 y)
+{
+    if ((x > 0) && (y > (KRB5_INT32_MAX - x))) {
+        /* sum will be be greater than KRB5_INT32_MAX */
+        return KRB5_INT32_MAX;
+    } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) {
+        /* sum will be less than KRB5_INT32_MIN */
+        return KRB5_INT32_MIN;
+    }
+    
+    return x + y;
+}
+
+/*
+ * This function sends a request to the KDC, and gets back a response;
+ * the response is parsed into ret_err_reply or ret_as_reply if the
+ * reponse is a KRB_ERROR or a KRB_AS_REP packet.  If it is some other
+ * unexpected response, an error is returned.
+ */
+static krb5_error_code
+send_as_request(krb5_context 		context,
+		krb5_kdc_req		*request,
+		krb5_timestamp 		*time_now,
+		krb5_error ** 		ret_err_reply,
+		krb5_kdc_rep ** 	ret_as_reply,
+		int 			    *use_master)
+{
+    krb5_kdc_rep *as_reply = 0;
+    krb5_error_code retval;
+    krb5_data *packet = 0;
+    krb5_data reply;
+    char k4_version;		/* same type as *(krb5_data::data) */
+    int tcp_only = 0;
+
+    reply.data = 0;
+    
+    if ((retval = krb5_timeofday(context, time_now)))
+	goto cleanup;
+
+    /*
+     * XXX we know they are the same size... and we should do
+     * something better than just the current time
+     */
+    request->nonce = (krb5_int32) *time_now;
+
+    /* encode & send to KDC */
+    if ((retval = encode_krb5_as_req(request, &packet)) != 0)
+	goto cleanup;
+
+    k4_version = packet->data[0];
+send_again:
+    retval = krb5_sendto_kdc(context, packet, 
+			     krb5_princ_realm(context, request->client),
+			     &reply, use_master, tcp_only);
+    if (retval)
+	goto cleanup;
+
+    /* now decode the reply...could be error or as_rep */
+    if (krb5_is_krb_error(&reply)) {
+	krb5_error *err_reply;
+
+	if ((retval = decode_krb5_error(&reply, &err_reply)))
+	    /* some other error code--??? */	    
+	    goto cleanup;
+    
+	if (ret_err_reply) {
+	    if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG
+		&& tcp_only == 0) {
+		tcp_only = 1;
+		krb5_free_error(context, err_reply);
+		free(reply.data);
+		reply.data = 0;
+		goto send_again;
+	    }
+	    *ret_err_reply = err_reply;
+	} else
+	    krb5_free_error(context, err_reply);
+	goto cleanup;
+    }
+
+    /*
+     * Check to make sure it isn't a V4 reply.
+     */
+    if (!krb5_is_as_rep(&reply)) {
+/* these are in <kerberosIV/prot.h> as well but it isn't worth including. */
+#define V4_KRB_PROT_VERSION	4
+#define V4_AUTH_MSG_ERR_REPLY	(5<<1)
+	/* check here for V4 reply */
+	unsigned int t_switch;
+
+	/* From v4 g_in_tkt.c: This used to be
+	   switch (pkt_msg_type(rpkt) & ~1) {
+	   but SCO 3.2v4 cc compiled that incorrectly.  */
+	t_switch = reply.data[1];
+	t_switch &= ~1;
+
+	if (t_switch == V4_AUTH_MSG_ERR_REPLY
+	    && (reply.data[0] == V4_KRB_PROT_VERSION
+		|| reply.data[0] == k4_version)) {
+	    retval = KRB5KRB_AP_ERR_V4_REPLY;
+	} else {
+	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
+	}
+	goto cleanup;
+    }
+
+    /* It must be a KRB_AS_REP message, or an bad returned packet */
+    if ((retval = decode_krb5_as_rep(&reply, &as_reply)))
+	/* some other error code ??? */
+	goto cleanup;
+
+    if (as_reply->msg_type != KRB5_AS_REP) {
+	retval = KRB5KRB_AP_ERR_MSG_TYPE;
+	krb5_free_kdc_rep(context, as_reply);
+	goto cleanup;
+    }
+
+    if (ret_as_reply)
+	*ret_as_reply = as_reply;
+    else
+	krb5_free_kdc_rep(context, as_reply);
+
+cleanup:
+    if (packet)
+	krb5_free_data(context, packet);
+    if (reply.data)
+	free(reply.data);
+    return retval;
+}
+
+static krb5_error_code
+decrypt_as_reply(krb5_context 		context,
+		 krb5_kdc_req		*request,
+		 krb5_kdc_rep		*as_reply,
+		 git_key_proc 		key_proc,
+		 krb5_const_pointer 	keyseed,
+		 krb5_keyblock *	key,
+		 git_decrypt_proc 	decrypt_proc,
+		 krb5_const_pointer 	decryptarg)
+{
+    krb5_error_code		retval;
+    krb5_keyblock *		decrypt_key = 0;
+    krb5_data 			salt;
+    
+    if (as_reply->enc_part2)
+	return 0;
+
+    if (key)
+	    decrypt_key = key;
+    else {
+	if ((retval = krb5_principal2salt(context, request->client, &salt)))
+	    return(retval);
+    
+	retval = (*key_proc)(context, as_reply->enc_part.enctype,
+			     &salt, keyseed, &decrypt_key);
+	krb5_xfree(salt.data);
+	if (retval)
+	    goto cleanup;
+    }
+    
+    if ((retval = (*decrypt_proc)(context, decrypt_key, decryptarg, as_reply)))
+	goto cleanup;
+
+cleanup:
+    if (!key && decrypt_key)
+	krb5_free_keyblock(context, decrypt_key);
+    return (retval);
+}
+
+static krb5_error_code
+verify_as_reply(krb5_context 		context,
+		krb5_timestamp 		time_now,
+		krb5_kdc_req		*request,
+		krb5_kdc_rep		*as_reply)
+{
+    krb5_error_code		retval;
+    
+    /* check the contents for sanity: */
+    if (!as_reply->enc_part2->times.starttime)
+	as_reply->enc_part2->times.starttime =
+	    as_reply->enc_part2->times.authtime;
+    
+    if (!krb5_principal_compare(context, as_reply->client, request->client)
+	|| !krb5_principal_compare(context, as_reply->enc_part2->server, request->server)
+	|| !krb5_principal_compare(context, as_reply->ticket->server, request->server)
+	|| (request->nonce != as_reply->enc_part2->nonce)
+	/* XXX check for extraneous flags */
+	/* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */
+	|| ((request->kdc_options & KDC_OPT_POSTDATED) &&
+	    (request->from != 0) &&
+	    (request->from != as_reply->enc_part2->times.starttime))
+	|| ((request->till != 0) &&
+	    (as_reply->enc_part2->times.endtime > request->till))
+	|| ((request->kdc_options & KDC_OPT_RENEWABLE) &&
+	    (request->rtime != 0) &&
+	    (as_reply->enc_part2->times.renew_till > request->rtime))
+	|| ((request->kdc_options & KDC_OPT_RENEWABLE_OK) &&
+	    !(request->kdc_options & KDC_OPT_RENEWABLE) &&
+	    (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) &&
+	    (request->till != 0) &&
+	    (as_reply->enc_part2->times.renew_till > request->till))
+	)
+	return KRB5_KDCREP_MODIFIED;
+
+    if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) {
+	retval = krb5_set_real_time(context,
+				    as_reply->enc_part2->times.authtime, 0);
+	if (retval)
+	    return retval;
+    } else {
+	if ((request->from == 0) &&
+	    (labs(as_reply->enc_part2->times.starttime - time_now)
+	     > context->clockskew))
+	    return (KRB5_KDCREP_SKEW);
+    }
+    return 0;
+}
+
+static krb5_error_code
+stash_as_reply(krb5_context 		context,
+	       krb5_timestamp 		time_now,
+	       krb5_kdc_req		*request,
+	       krb5_kdc_rep		*as_reply,
+	       krb5_creds * 		creds,
+	       krb5_ccache 		ccache)
+{
+    krb5_error_code 		retval;
+    krb5_data *			packet;
+    krb5_principal		client;
+    krb5_principal		server;
+
+    client = NULL;
+    server = NULL;
+
+    if (!creds->client)
+        if ((retval = krb5_copy_principal(context, as_reply->client, &client)))
+	    goto cleanup;
+
+    if (!creds->server)
+	if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server,
+					  &server)))
+	    goto cleanup;
+
+    /* fill in the credentials */
+    if ((retval = krb5_copy_keyblock_contents(context, 
+					      as_reply->enc_part2->session,
+					      &creds->keyblock)))
+	goto cleanup;
+
+    creds->times = as_reply->enc_part2->times;
+    creds->is_skey = FALSE;		/* this is an AS_REQ, so cannot
+					   be encrypted in skey */
+    creds->ticket_flags = as_reply->enc_part2->flags;
+    if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs,
+				      &creds->addresses)))
+	goto cleanup;
+
+    creds->second_ticket.length = 0;
+    creds->second_ticket.data = 0;
+
+    if ((retval = encode_krb5_ticket(as_reply->ticket, &packet)))
+	goto cleanup;
+
+    creds->ticket = *packet;
+    krb5_xfree(packet);
+
+    /* store it in the ccache! */
+    if (ccache)
+	if ((retval = krb5_cc_store_cred(context, ccache, creds)))
+	    goto cleanup;
+
+    if (!creds->client)
+	creds->client = client;
+    if (!creds->server)
+	creds->server = server;
+
+cleanup:
+    if (retval) {
+	if (client)
+	    krb5_free_principal(context, client);
+	if (server)
+	    krb5_free_principal(context, server);
+	if (creds->keyblock.contents) {
+	    memset((char *)creds->keyblock.contents, 0,
+		   creds->keyblock.length);
+	    krb5_xfree(creds->keyblock.contents);
+	    creds->keyblock.contents = 0;
+	    creds->keyblock.length = 0;
+	}
+	if (creds->ticket.data) {
+	    krb5_xfree(creds->ticket.data);
+	    creds->ticket.data = 0;
+	}
+	if (creds->addresses) {
+	    krb5_free_addresses(context, creds->addresses);
+	    creds->addresses = 0;
+	}
+    }
+    return (retval);
+}
+
+static krb5_error_code
+make_preauth_list(krb5_context	context,
+		  krb5_preauthtype *	ptypes,
+		  int			nptypes,
+		  krb5_pa_data ***	ret_list)
+{
+    krb5_preauthtype *		ptypep;
+    krb5_pa_data **		preauthp;
+    int				i;
+
+    if (nptypes < 0) {
+ 	for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++)
+ 	    ;
+    }
+ 
+    /* allocate space for a NULL to terminate the list */
+ 
+    if ((preauthp =
+ 	 (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
+ 	return(ENOMEM);
+ 
+    for (i=0; i<nptypes; i++) {
+ 	if ((preauthp[i] =
+ 	     (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
+ 	    for (; i>=0; i++)
+ 		free(preauthp[i]);
+ 	    free(preauthp);
+	    return (ENOMEM);
+	}
+ 	preauthp[i]->magic = KV5M_PA_DATA;
+ 	preauthp[i]->pa_type = ptypes[i];
+ 	preauthp[i]->length = 0;
+ 	preauthp[i]->contents = 0;
+    }
+     
+    /* fill in the terminating NULL */
+ 
+    preauthp[nptypes] = NULL;
+ 
+    *ret_list = preauthp;
+    return 0;
+}
+
+#define MAX_IN_TKT_LOOPS 16
+static const krb5_enctype get_in_tkt_enctypes[] = {
+    ENCTYPE_DES3_CBC_SHA1,
+    ENCTYPE_ARCFOUR_HMAC,
+    ENCTYPE_DES_CBC_MD5,
+    ENCTYPE_DES_CBC_MD4,
+    ENCTYPE_DES_CBC_CRC,
+    0
+};
+
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_in_tkt(krb5_context context,
+		const krb5_flags options,
+		krb5_address * const * addrs,
+		krb5_enctype * ktypes,
+		krb5_preauthtype * ptypes,
+		git_key_proc key_proc,
+		krb5_const_pointer keyseed,
+		git_decrypt_proc decrypt_proc,
+		krb5_const_pointer decryptarg,
+		krb5_creds * creds,
+		krb5_ccache ccache,
+		krb5_kdc_rep ** ret_as_reply)
+{
+    krb5_error_code	retval;
+    krb5_timestamp	time_now;
+    krb5_keyblock *	decrypt_key = 0;
+    krb5_kdc_req	request;
+    krb5_pa_data	**padata = 0;
+    krb5_error *	err_reply;
+    krb5_kdc_rep *	as_reply = 0;
+    krb5_pa_data  **	preauth_to_use = 0;
+    int			loopcount = 0;
+    krb5_int32		do_more = 0;
+    int             use_master = 0;
+
+    if (! krb5_realm_compare(context, creds->client, creds->server))
+	return KRB5_IN_TKT_REALM_MISMATCH;
+
+    if (ret_as_reply)
+	*ret_as_reply = 0;
+    
+    /*
+     * Set up the basic request structure
+     */
+    request.magic = KV5M_KDC_REQ;
+    request.msg_type = KRB5_AS_REQ;
+    request.addresses = 0;
+    request.ktype = 0;
+    request.padata = 0;
+    if (addrs)
+	request.addresses = (krb5_address **) addrs;
+    else
+	if ((retval = krb5_os_localaddr(context, &request.addresses)))
+	    goto cleanup;
+    request.kdc_options = options;
+    request.client = creds->client;
+    request.server = creds->server;
+    request.from = creds->times.starttime;
+    request.till = creds->times.endtime;
+    request.rtime = creds->times.renew_till;
+
+    request.ktype = malloc (sizeof(get_in_tkt_enctypes));
+    if (request.ktype == NULL) {
+	retval = ENOMEM;
+	goto cleanup;
+    }
+    memcpy(request.ktype, get_in_tkt_enctypes, sizeof(get_in_tkt_enctypes));
+    for (request.nktypes = 0;request.ktype[request.nktypes];request.nktypes++);
+    if (ktypes) {
+	int i, req, next = 0;
+	for (req = 0; ktypes[req]; req++) {
+	    if (ktypes[req] == request.ktype[next]) {
+		next++;
+		continue;
+	    }
+	    for (i = next + 1; i < request.nktypes; i++)
+		if (ktypes[req] == request.ktype[i]) {
+		    /* Found the enctype we want, but not in the
+		       position we want.  Move it, but keep the old
+		       one from the desired slot around in case it's
+		       later in our requested-ktypes list.  */
+		    krb5_enctype t;
+		    t = request.ktype[next];
+		    request.ktype[next] = request.ktype[i];
+		    request.ktype[i] = t;
+		    next++;
+		    break;
+		}
+	    /* If we didn't find it, don't do anything special, just
+	       drop it.  */
+	}
+	request.ktype[next] = 0;
+	request.nktypes = next;
+    }
+    request.authorization_data.ciphertext.length = 0;
+    request.authorization_data.ciphertext.data = 0;
+    request.unenc_authdata = 0;
+    request.second_ticket = 0;
+
+    /*
+     * If a list of preauth types are passed in, convert it to a
+     * preauth_to_use list.
+     */
+    if (ptypes) {
+	retval = make_preauth_list(context, ptypes, -1, &preauth_to_use);
+	if (retval)
+	    goto cleanup;
+    }
+	    
+    while (1) {
+	if (loopcount++ > MAX_IN_TKT_LOOPS) {
+	    retval = KRB5_GET_IN_TKT_LOOP;
+	    goto cleanup;
+	}
+
+	if ((retval = krb5_obtain_padata(context, preauth_to_use, key_proc,
+					 keyseed, creds, &request)) != 0)
+	    goto cleanup;
+	if (preauth_to_use)
+	    krb5_free_pa_data(context, preauth_to_use);
+	preauth_to_use = 0;
+	
+	err_reply = 0;
+	as_reply = 0;
+	if ((retval = send_as_request(context, &request, &time_now, &err_reply,
+				      &as_reply, &use_master)))
+	    goto cleanup;
+
+	if (err_reply) {
+	    if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
+		err_reply->e_data.length > 0) {
+		retval = decode_krb5_padata_sequence(&err_reply->e_data,
+						     &preauth_to_use);
+		krb5_free_error(context, err_reply);
+		if (retval)
+		    goto cleanup;
+		continue;
+	    } else {
+		retval = (krb5_error_code) err_reply->error 
+		    + ERROR_TABLE_BASE_krb5;
+		krb5_free_error(context, err_reply);
+		goto cleanup;
+	    }
+	} else if (!as_reply) {
+	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
+	    goto cleanup;
+	}
+	if ((retval = krb5_process_padata(context, &request, as_reply,
+					  key_proc, keyseed, decrypt_proc, 
+					  &decrypt_key, creds,
+					  &do_more)) != 0)
+	    goto cleanup;
+
+	if (!do_more)
+	    break;
+    }
+    
+    if ((retval = decrypt_as_reply(context, &request, as_reply, key_proc,
+				   keyseed, decrypt_key, decrypt_proc,
+				   decryptarg)))
+	goto cleanup;
+
+    if ((retval = verify_as_reply(context, time_now, &request, as_reply)))
+	goto cleanup;
+
+    if ((retval = stash_as_reply(context, time_now, &request, as_reply,
+				 creds, ccache)))
+	goto cleanup;
+
+cleanup:
+    if (request.ktype)
+	free(request.ktype);
+    if (!addrs && request.addresses)
+	krb5_free_addresses(context, request.addresses);
+    if (request.padata)
+	krb5_free_pa_data(context, request.padata);
+    if (padata)
+	krb5_free_pa_data(context, padata);
+    if (preauth_to_use)
+	krb5_free_pa_data(context, preauth_to_use);
+    if (decrypt_key)
+    	krb5_free_keyblock(context, decrypt_key);
+    if (as_reply) {
+	if (ret_as_reply)
+	    *ret_as_reply = as_reply;
+	else
+	    krb5_free_kdc_rep(context, as_reply);
+    }
+    return (retval);
+}
+
+/* begin libdefaults parsing code.  This should almost certainly move
+   somewhere else, but I don't know where the correct somewhere else
+   is yet. */
+
+/* XXX Duplicating this is annoying; try to work on a better way.*/
+static const char *const conf_yes[] = {
+    "y", "yes", "true", "t", "1", "on",
+    0,
+};
+
+static const char *const conf_no[] = {
+    "n", "no", "false", "nil", "0", "off",
+    0,
+};
+
+int
+_krb5_conf_boolean(const char *s)
+{
+    const char *const *p;
+
+    for(p=conf_yes; *p; p++) {
+	if (!strcasecmp(*p,s))
+	    return 1;
+    }
+
+    for(p=conf_no; *p; p++) {
+	if (!strcasecmp(*p,s))
+	    return 0;
+    }
+
+    /* Default to "no" */
+    return 0;
+}
+
+static krb5_error_code
+krb5_libdefault_string(krb5_context context, const krb5_data *realm,
+		       const char *option, char **ret_value)
+{
+    profile_t profile;
+    const char *names[5];
+    char **nameval = NULL;
+    krb5_error_code retval;
+    char realmstr[1024];
+
+    if (realm->length > sizeof(realmstr)-1)
+	return(EINVAL);
+
+    strncpy(realmstr, realm->data, realm->length);
+    realmstr[realm->length] = '\0';
+
+    if (!context || (context->magic != KV5M_CONTEXT)) 
+	return KV5M_CONTEXT;
+
+    profile = context->profile;
+	    
+    names[0] = "libdefaults";
+
+    /*
+     * Try number one:
+     *
+     * [libdefaults]
+     *		REALM = {
+     *			option = <boolean>
+     *		}
+     */
+
+    names[1] = realmstr;
+    names[2] = option;
+    names[3] = 0;
+    retval = profile_get_values(profile, names, &nameval);
+    if (retval == 0 && nameval && nameval[0])
+	goto goodbye;
+
+    /*
+     * Try number two:
+     *
+     * [libdefaults]
+     *		option = <boolean>
+     */
+    
+    names[1] = option;
+    names[2] = 0;
+    retval = profile_get_values(profile, names, &nameval);
+    if (retval == 0 && nameval && nameval[0])
+	goto goodbye;
+
+goodbye:
+    if (!nameval) 
+	return(ENOENT);
+
+    if (!nameval[0]) {
+        retval = ENOENT;
+    } else {
+        *ret_value = malloc(strlen(nameval[0]) + 1);
+        if (!*ret_value)
+            retval = ENOMEM;
+        else
+            strcpy(*ret_value, nameval[0]);
+    }
+
+    profile_free_list(nameval);
+
+    return retval;
+}
+
+/* not static so verify_init_creds() can call it */
+/* as well as the DNS code */
+
+krb5_error_code
+krb5_libdefault_boolean(krb5_context context, const krb5_data *realm,
+			const char *option, int *ret_value)
+{
+    char *string = NULL;
+    krb5_error_code retval;
+
+    retval = krb5_libdefault_string(context, realm, option, &string);
+
+    if (retval)
+	return(retval);
+
+    *ret_value = _krb5_conf_boolean(string);
+    free(string);
+
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds(krb5_context context,
+		    krb5_creds *creds,
+		    krb5_principal client,
+		    krb5_prompter_fct prompter,
+		    void *prompter_data,
+		    krb5_deltat start_time,
+		    char *in_tkt_service,
+		    krb5_get_init_creds_opt *options,
+		    krb5_gic_get_as_key_fct gak_fct,
+		    void *gak_data,
+		    int  *use_master,
+		    krb5_kdc_rep **as_reply)
+{
+    krb5_error_code ret;
+    krb5_kdc_req request;
+    krb5_pa_data **padata;
+    int tempint;
+    char *tempstr;
+    krb5_deltat tkt_life;
+    krb5_deltat renew_life;
+    int loopcount;
+    krb5_data salt;
+    krb5_data s2kparams;
+    krb5_keyblock as_key;
+    krb5_error *err_reply;
+    krb5_kdc_rep *local_as_reply;
+    krb5_timestamp time_now;
+    krb5_enctype etype = 0;
+
+    /* initialize everything which will be freed at cleanup */
+
+    s2kparams.data = NULL;
+    s2kparams.length = 0;
+    request.server = NULL;
+    request.ktype = NULL;
+    request.addresses = NULL;
+    request.padata = NULL;
+    padata = NULL;
+    as_key.length = 0;
+    salt.length = 0;
+    salt.data = NULL;
+
+	local_as_reply = 0;
+
+    /*
+     * Set up the basic request structure
+     */
+    request.magic = KV5M_KDC_REQ;
+    request.msg_type = KRB5_AS_REQ;
+
+    /* request.padata is filled in later */
+
+    request.kdc_options = context->kdc_default_options;
+
+    /* forwardable */
+
+    if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE))
+	tempint = options->forwardable;
+    else if ((ret = krb5_libdefault_boolean(context, &client->realm,
+					    "forwardable", &tempint)) == 0)
+	    ;
+    else
+	tempint = 0;
+    if (tempint)
+	request.kdc_options |= KDC_OPT_FORWARDABLE;
+
+    /* proxiable */
+
+    if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE))
+	tempint = options->proxiable;
+    else if ((ret = krb5_libdefault_boolean(context, &client->realm,
+					    "proxiable", &tempint)) == 0)
+	    ;
+    else
+	tempint = 0;
+    if (tempint)
+	request.kdc_options |= KDC_OPT_PROXIABLE;
+
+    /* allow_postdate */
+    
+    if (start_time > 0)
+	request.kdc_options |= (KDC_OPT_ALLOW_POSTDATE|KDC_OPT_POSTDATED);
+    
+    /* ticket lifetime */
+    
+    if ((ret = krb5_timeofday(context, &request.from)))
+	goto cleanup;
+    request.from = krb5int_addint32(request.from, start_time);
+    
+    if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)) {
+        tkt_life = options->tkt_life;
+    } else if ((ret = krb5_libdefault_string(context, &client->realm,
+					     "ticket_lifetime", &tempstr))
+	       == 0) {
+	ret = krb5_string_to_deltat(tempstr, &tkt_life);
+	free(tempstr);
+	if (ret) {
+	    goto cleanup;
+	}
+    } else {
+	/* this used to be hardcoded in kinit.c */
+	tkt_life = 24*60*60;
+    }
+    request.till = krb5int_addint32(request.from, tkt_life);
+    
+    /* renewable lifetime */
+    
+    if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) {
+	renew_life = options->renew_life;
+    } else if ((ret = krb5_libdefault_string(context, &client->realm,
+					     "renew_lifetime", &tempstr))
+	       == 0) {
+	ret = krb5_string_to_deltat(tempstr, &renew_life);
+	free(tempstr);
+	if (ret) {
+	    goto cleanup;
+	}
+    } else {
+	renew_life = 0;
+    }
+    if (renew_life > 0)
+	request.kdc_options |= KDC_OPT_RENEWABLE;
+    
+    if (renew_life > 0) {
+	request.rtime = krb5int_addint32(request.from, renew_life);
+        if (request.rtime < request.till) {
+            /* don't ask for a smaller renewable time than the lifetime */
+            request.rtime = request.till;
+        }
+        /* we are already asking for renewable tickets so strip this option */
+	request.kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
+    } else {
+	request.rtime = 0;
+    }
+    
+    /* client */
+
+    request.client = client;
+
+    /* service */
+    
+    if (in_tkt_service) {
+	/* this is ugly, because so are the data structures involved.  I'm
+	   in the library, so I'm going to manipulate the data structures
+	   directly, otherwise, it will be worse. */
+
+        if ((ret = krb5_parse_name(context, in_tkt_service, &request.server)))
+	    goto cleanup;
+
+	/* stuff the client realm into the server principal.
+	   realloc if necessary */
+	if (request.server->realm.length < request.client->realm.length)
+	    if ((request.server->realm.data =
+		 (char *) realloc(request.server->realm.data,
+				  request.client->realm.length)) == NULL) {
+		ret = ENOMEM;
+		goto cleanup;
+	    }
+
+	request.server->realm.length = request.client->realm.length;
+	memcpy(request.server->realm.data, request.client->realm.data,
+	       request.client->realm.length);
+    } else {
+	if ((ret = krb5_build_principal_ext(context, &request.server,
+					   request.client->realm.length,
+					   request.client->realm.data,
+					   KRB5_TGS_NAME_SIZE,
+					   KRB5_TGS_NAME,
+					   request.client->realm.length,
+					   request.client->realm.data,
+					   0)))
+	    goto cleanup;
+    }
+
+    /* nonce is filled in by send_as_request */
+
+    if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)) {
+	request.ktype = options->etype_list;
+	request.nktypes = options->etype_list_length;
+    } else if ((ret = krb5_get_default_in_tkt_ktypes(context,
+						     &request.ktype)) == 0) {
+	for (request.nktypes = 0;
+	     request.ktype[request.nktypes];
+	     request.nktypes++)
+	    ;
+    } else {
+	/* there isn't any useful default here.  ret is set from above */
+	goto cleanup;
+    }
+
+    if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)) {
+	request.addresses = options->address_list;
+    }
+    /* it would be nice if this parsed out an address list, but
+       that would be work. */
+    else if (((ret = krb5_libdefault_boolean(context, &client->realm,
+					    "noaddresses", &tempint)) != 0)
+	     || (tempint == 1)) {
+	    ;
+    } else {
+	if ((ret = krb5_os_localaddr(context, &request.addresses)))
+	    goto cleanup;
+    }
+
+    request.authorization_data.ciphertext.length = 0;
+    request.authorization_data.ciphertext.data = 0;
+    request.unenc_authdata = 0;
+    request.second_ticket = 0;
+
+    /* set up the other state.  */
+
+    if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
+	if ((ret = make_preauth_list(context, options->preauth_list,
+				    options->preauth_list_length, 
+				     &padata)))
+	    goto cleanup;
+    }
+
+    /* the salt is allocated from somewhere, unless it is from the caller,
+       then it is a reference */
+
+    if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)) {
+	salt = *options->salt;
+    } else {
+	salt.length = SALT_TYPE_AFS_LENGTH;
+	salt.data = NULL;
+    }
+
+    /* now, loop processing preauth data and talking to the kdc */
+
+    for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) {
+	if (request.padata) {
+	    krb5_free_pa_data(context, request.padata);
+	    request.padata = NULL;
+	}
+
+	if ((ret = krb5_do_preauth(context, &request,
+				  padata, &request.padata,
+				  &salt, &s2kparams, &etype, &as_key, prompter,
+				   prompter_data, gak_fct, gak_data)))
+	    goto cleanup;
+
+	if (padata) {
+	    krb5_free_pa_data(context, padata);
+	    padata = 0;
+	}
+
+	err_reply = 0;
+	local_as_reply = 0;
+	if ((ret = send_as_request(context, &request, &time_now, &err_reply,
+				   &local_as_reply, use_master)))
+	    goto cleanup;
+
+	if (err_reply) {
+	    if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
+		err_reply->e_data.length > 0) {
+		ret = decode_krb5_padata_sequence(&err_reply->e_data,
+						  &padata);
+		krb5_free_error(context, err_reply);
+		if (ret)
+		    goto cleanup;
+	    } else {
+		ret = (krb5_error_code) err_reply->error 
+		    + ERROR_TABLE_BASE_krb5;
+		krb5_free_error(context, err_reply);
+		goto cleanup;
+	    }
+	} else if (local_as_reply) {
+	    break;
+	} else {
+	    ret = KRB5KRB_AP_ERR_MSG_TYPE;
+	    goto cleanup;
+	}
+    }
+
+    if (loopcount == MAX_IN_TKT_LOOPS) {
+	ret = KRB5_GET_IN_TKT_LOOP;
+	goto cleanup;
+    }
+
+    /* process any preauth data in the as_reply */
+
+    if ((ret = krb5_do_preauth(context, &request,
+			       local_as_reply->padata, &padata,
+			       &salt, &s2kparams, &etype, &as_key, prompter,
+			       prompter_data, gak_fct, gak_data)))
+	goto cleanup;
+
+    /* XXX if there's padata on output, something is wrong, but it's
+       not obviously an error */
+
+    /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
+       the AS_REP comes back encrypted in the user's longterm key
+       instead of in the SAD. If there was a SAM preauth, there
+       will be an as_key here which will be the SAD. If that fails,
+       use the gak_fct to get the password, and try again. */
+      
+    /* XXX because etypes are handled poorly (particularly wrt SAM,
+       where the etype is fixed by the kdc), we may want to try
+       decrypt_as_reply twice.  If there's an as_key available, try
+       it.  If decrypting the as_rep fails, or if there isn't an
+       as_key at all yet, then use the gak_fct to get one, and try
+       again.  */
+
+    if (as_key.length)
+	ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
+			       NULL, &as_key, krb5_kdc_rep_decrypt_proc,
+			       NULL);
+    else
+	ret = -1;
+	   
+    if (ret) {
+	/* if we haven't get gotten a key, get it now */
+
+	if ((ret = ((*gak_fct)(context, request.client,
+			       local_as_reply->enc_part.enctype,
+			       prompter, prompter_data, &salt, &s2kparams,
+			       &as_key, gak_data))))
+	    goto cleanup;
+
+	if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
+				    NULL, &as_key, krb5_kdc_rep_decrypt_proc,
+				    NULL)))
+	    goto cleanup;
+    }
+
+    if ((ret = verify_as_reply(context, time_now, &request, local_as_reply)))
+	goto cleanup;
+
+    /* XXX this should be inside stash_as_reply, but as long as
+       get_in_tkt is still around using that arg as an in/out, I can't
+       do that */
+    memset(creds, 0, sizeof(*creds));
+
+    if ((ret = stash_as_reply(context, time_now, &request, local_as_reply,
+			      creds, NULL)))
+	goto cleanup;
+
+    /* success */
+
+    ret = 0;
+
+cleanup:
+    if (request.server)
+	krb5_free_principal(context, request.server);
+    if (request.ktype &&
+	(!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))))
+	free(request.ktype);
+    if (request.addresses &&
+	(!(options &&
+	   (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST))))
+	krb5_free_addresses(context, request.addresses);
+    if (padata)
+	krb5_free_pa_data(context, padata);
+    if (request.padata)
+	krb5_free_pa_data(context, request.padata);
+    if (as_key.length)
+	krb5_free_keyblock_contents(context, &as_key);
+    if (salt.data &&
+	(!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT))))
+	krb5_xfree(salt.data);
+    krb5_free_data_contents(context, &s2kparams);
+    if (as_reply)
+	*as_reply = local_as_reply;
+    else if (local_as_reply)
+	krb5_free_kdc_rep(context, local_as_reply);
+
+    return(ret);
+}
diff --git a/mechglue/src/lib/krb5/krb/gic_keytab.c b/mechglue/src/lib/krb5/krb/gic_keytab.c
new file mode 100644
index 000000000..ba704e6be
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/gic_keytab.c
@@ -0,0 +1,201 @@
+/*
+ * lib/krb5/krb/gic_keytab.c
+ *
+ * Copyright (C) 2002, 2003 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+
+static krb5_error_code
+krb5_get_as_key_keytab(
+    krb5_context context,
+    krb5_principal client,
+    krb5_enctype etype,
+    krb5_prompter_fct prompter,
+    void *prompter_data,
+    krb5_data *salt,
+    krb5_data *params,
+    krb5_keyblock *as_key,
+    void *gak_data)
+{
+    krb5_keytab keytab = (krb5_keytab) gak_data;
+    krb5_error_code ret;
+    krb5_keytab_entry kt_ent;
+    krb5_keyblock *kt_key;
+
+    /* if there's already a key of the correct etype, we're done.
+       if the etype is wrong, free the existing key, and make
+       a new one. */
+
+    if (as_key->length) {
+	if (as_key->enctype == etype)
+	    return(0);
+
+	krb5_free_keyblock_contents(context, as_key);
+	as_key->length = 0;
+    }
+
+    if (!krb5_c_valid_enctype(etype))
+	return(KRB5_PROG_ETYPE_NOSUPP);
+
+    if ((ret = krb5_kt_get_entry(context, keytab, client,
+				 0, /* don't have vno available */
+				 etype, &kt_ent)))
+	return(ret);
+
+    ret = krb5_copy_keyblock(context, &kt_ent.key, &kt_key);
+
+    /* again, krb5's memory management is lame... */
+
+    *as_key = *kt_key;
+    krb5_xfree(kt_key);
+
+    (void) krb5_kt_free_entry(context, &kt_ent);
+
+    return(ret);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_keytab arg_keytab, krb5_deltat start_time, char *in_tkt_service, krb5_get_init_creds_opt *options)
+{
+   krb5_error_code ret, ret2;
+   int use_master;
+   krb5_keytab keytab;
+
+   if (arg_keytab == NULL) {
+       if ((ret = krb5_kt_default(context, &keytab)))
+	    return ret;
+   } else {
+       keytab = arg_keytab;
+   }
+
+   use_master = 0;
+
+   /* first try: get the requested tkt from any kdc */
+
+   ret = krb5_get_init_creds(context, creds, client, NULL, NULL,
+			     start_time, in_tkt_service, options,
+			     krb5_get_as_key_keytab, (void *) keytab,
+			     &use_master,NULL);
+
+   /* check for success */
+
+   if (ret == 0)
+      goto cleanup;
+
+   /* If all the kdc's are unavailable fail */
+
+   if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_REALM_CANT_RESOLVE))
+      goto cleanup;
+
+   /* if the reply did not come from the master kdc, try again with
+      the master kdc */
+
+   if (!use_master) {
+      use_master = 1;
+
+      ret2 = krb5_get_init_creds(context, creds, client, NULL, NULL,
+				 start_time, in_tkt_service, options,
+				 krb5_get_as_key_keytab, (void *) keytab,
+				 &use_master, NULL);
+      
+      if (ret2 == 0) {
+	 ret = 0;
+	 goto cleanup;
+      }
+
+      /* if the master is unreachable, return the error from the
+	 slave we were able to contact */
+
+      if ((ret2 == KRB5_KDC_UNREACH) ||
+	  (ret2 == KRB5_REALM_CANT_RESOLVE) ||
+	  (ret2 == KRB5_REALM_UNKNOWN))
+	 goto cleanup;
+
+      ret = ret2;
+   }
+
+   /* at this point, we have a response from the master.  Since we don't
+      do any prompting or changing for keytabs, that's it. */
+
+cleanup:
+   if (arg_keytab == NULL)
+       krb5_kt_close(context, keytab);
+
+   return(ret);
+}
+krb5_error_code KRB5_CALLCONV
+krb5_get_in_tkt_with_keytab(krb5_context context, krb5_flags options,
+			      krb5_address *const *addrs, krb5_enctype *ktypes,
+			      krb5_preauthtype *pre_auth_types,
+			      krb5_keytab arg_keytab, krb5_ccache ccache,
+			      krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
+{
+    krb5_error_code retval;
+    krb5_get_init_creds_opt opt;
+    char * server = NULL;
+    krb5_keytab keytab;
+    krb5_principal client_princ, server_princ;
+    int use_master = 0;
+    
+    krb5int_populate_gic_opt(context, &opt,
+			     options, addrs, ktypes,
+			     pre_auth_types, creds);
+    if (arg_keytab == NULL) {
+	retval = krb5_kt_default(context, &keytab);
+	if (retval)
+	    return retval;
+    }
+    else keytab = arg_keytab;
+    
+    retval = krb5_unparse_name( context, creds->server, &server);
+    if (retval)
+	goto cleanup;
+    server_princ = creds->server;
+    client_princ = creds->client;
+    retval = krb5_get_init_creds (context,
+				  creds, creds->client,  
+				  krb5_prompter_posix,  NULL,
+				  0, server, &opt,
+				  krb5_get_as_key_keytab, (void *)keytab,
+				  &use_master, ret_as_reply);
+    krb5_free_unparsed_name( context, server);
+    if (retval) {
+	goto cleanup;
+    }
+	if (creds->server)
+	    krb5_free_principal( context, creds->server);
+	if (creds->client)
+	    krb5_free_principal( context, creds->client);
+	creds->client = client_princ;
+	creds->server = server_princ;
+	
+    /* store it in the ccache! */
+    if (ccache)
+	if ((retval = krb5_cc_store_cred(context, ccache, creds)))
+	    goto cleanup;
+ cleanup:    if (arg_keytab == NULL)
+     krb5_kt_close(context, keytab);
+    return retval;
+}
+
diff --git a/mechglue/src/lib/krb5/krb/gic_opt.c b/mechglue/src/lib/krb5/krb/gic_opt.c
new file mode 100644
index 000000000..58d07b03d
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/gic_opt.c
@@ -0,0 +1,65 @@
+#include "k5-int.h"
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
+{
+   opt->flags = 0;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt, krb5_deltat tkt_life)
+{
+   opt->flags |= KRB5_GET_INIT_CREDS_OPT_TKT_LIFE;
+   opt->tkt_life = tkt_life;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt, krb5_deltat renew_life)
+{
+   opt->flags |= KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE;
+   opt->renew_life = renew_life;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt, int forwardable)
+{
+   opt->flags |= KRB5_GET_INIT_CREDS_OPT_FORWARDABLE;
+   opt->forwardable = forwardable;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt, int proxiable)
+{
+   opt->flags |= KRB5_GET_INIT_CREDS_OPT_PROXIABLE;
+   opt->proxiable = proxiable;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, krb5_enctype *etype_list, int etype_list_length)
+{
+   opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
+   opt->etype_list = etype_list;
+   opt->etype_list_length = etype_list_length;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt, krb5_address **addresses)
+{
+   opt->flags |= KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST;
+   opt->address_list = addresses;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt, krb5_preauthtype *preauth_list, int preauth_list_length)
+{
+   opt->flags |= KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST;
+   opt->preauth_list = preauth_list;
+   opt->preauth_list_length = preauth_list_length;
+}
+
+void KRB5_CALLCONV
+krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, krb5_data *salt)
+{
+   opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
+   opt->salt = salt;
+}
diff --git a/mechglue/src/lib/krb5/krb/gic_pwd.c b/mechglue/src/lib/krb5/krb/gic_pwd.c
new file mode 100644
index 000000000..f2837effb
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/gic_pwd.c
@@ -0,0 +1,487 @@
+#include "k5-int.h"
+#include "com_err.h"
+
+static krb5_error_code
+krb5_get_as_key_password(
+    krb5_context context,
+    krb5_principal client,
+    krb5_enctype etype,
+    krb5_prompter_fct prompter,
+    void *prompter_data,
+    krb5_data *salt,
+    krb5_data *params,
+    krb5_keyblock *as_key,
+    void *gak_data)
+{
+    krb5_data *password;
+    krb5_error_code ret;
+    krb5_data defsalt;
+    char *clientstr;
+    char promptstr[1024];
+    krb5_prompt prompt;
+    krb5_prompt_type prompt_type;
+
+    password = (krb5_data *) gak_data;
+
+    /* If there's already a key of the correct etype, we're done.
+       If the etype is wrong, free the existing key, and make
+       a new one.
+
+       XXX This was the old behavior, and was wrong in hw preauth
+       cases.  Is this new behavior -- always asking -- correct in all
+       cases?  */
+
+    if (as_key->length) {
+	if (as_key->enctype != etype) {
+	    krb5_free_keyblock_contents (context, as_key);
+	    as_key->length = 0;
+	}
+    }
+
+    if (password->data[0] == '\0') {
+	if (prompter == NULL)
+	    return(EIO);
+
+	if ((ret = krb5_unparse_name(context, client, &clientstr)))
+	  return(ret);
+
+	strcpy(promptstr, "Password for ");
+	strncat(promptstr, clientstr, sizeof(promptstr)-strlen(promptstr)-1);
+	promptstr[sizeof(promptstr)-1] = '\0';
+
+	free(clientstr);
+
+	prompt.prompt = promptstr;
+	prompt.hidden = 1;
+	prompt.reply = password;
+	prompt_type = KRB5_PROMPT_TYPE_PASSWORD;
+
+	/* PROMPTER_INVOCATION */
+	krb5int_set_prompt_types(context, &prompt_type);
+	if ((ret = (((*prompter)(context, prompter_data, NULL, NULL,
+				1, &prompt))))) {
+	    krb5int_set_prompt_types(context, 0);
+	    return(ret);
+	}
+	krb5int_set_prompt_types(context, 0);
+    }
+
+    if ((salt->length == -1 || salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
+	if ((ret = krb5_principal2salt(context, client, &defsalt)))
+	    return(ret);
+
+	salt = &defsalt;
+    } else {
+	defsalt.length = 0;
+    }
+
+    ret = krb5_c_string_to_key_with_params(context, etype, password, salt,
+					   params->data?params:NULL, as_key);
+
+    if (defsalt.length)
+	krb5_xfree(defsalt.data);
+
+    return(ret);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, krb5_principal client, char *password, krb5_prompter_fct prompter, void *data, krb5_deltat start_time, char *in_tkt_service, krb5_get_init_creds_opt *options)
+{
+   krb5_error_code ret, ret2;
+   int use_master;
+   krb5_kdc_rep *as_reply;
+   int tries;
+   krb5_creds chpw_creds;
+   krb5_get_init_creds_opt chpw_opts;
+   krb5_data pw0, pw1;
+   char banner[1024], pw0array[1024], pw1array[1024];
+   krb5_prompt prompt[2];
+   krb5_prompt_type prompt_types[sizeof(prompt)/sizeof(prompt[0])];
+
+   use_master = 0;
+   as_reply = NULL;
+   memset(&chpw_creds, 0, sizeof(chpw_creds));
+
+   pw0.data = pw0array;
+
+   if (password && password[0]) {
+      if ((pw0.length = strlen(password)) > sizeof(pw0array)) {
+	 ret = EINVAL;
+	 goto cleanup;
+      }
+      strcpy(pw0.data, password);
+   } else {
+      pw0.data[0] = '\0';
+      pw0.length = sizeof(pw0array);
+   }
+
+   pw1.data = pw1array;
+   pw1.data[0] = '\0';
+   pw1.length = sizeof(pw1array);
+
+   /* first try: get the requested tkt from any kdc */
+
+   ret = krb5_get_init_creds(context, creds, client, prompter, data,
+			     start_time, in_tkt_service, options,
+			     krb5_get_as_key_password, (void *) &pw0,
+			     &use_master, &as_reply);
+
+   /* check for success */
+
+   if (ret == 0)
+      goto cleanup;
+
+   /* If all the kdc's are unavailable, or if the error was due to a
+      user interrupt, or preauth errored out, fail */
+
+   if ((ret == KRB5_KDC_UNREACH) ||
+       (ret == KRB5_PREAUTH_FAILED) ||
+       (ret == KRB5_LIBOS_PWDINTR) ||
+	   (ret == KRB5_REALM_CANT_RESOLVE))
+      goto cleanup;
+
+   /* if the reply did not come from the master kdc, try again with
+      the master kdc */
+
+   if (!use_master) {
+      use_master = 1;
+
+      if (as_reply) {
+	  krb5_free_kdc_rep( context, as_reply);
+	  as_reply = NULL;
+      }
+      ret2 = krb5_get_init_creds(context, creds, client, prompter, data,
+				 start_time, in_tkt_service, options,
+				 krb5_get_as_key_password, (void *) &pw0,
+				 &use_master, &as_reply);
+      
+      if (ret2 == 0) {
+	 ret = 0;
+	 goto cleanup;
+      }
+
+      /* if the master is unreachable, return the error from the
+	 slave we were able to contact */
+
+      if ((ret2 == KRB5_KDC_UNREACH) ||
+	  (ret2 == KRB5_REALM_CANT_RESOLVE) ||
+	  (ret2 == KRB5_REALM_UNKNOWN))
+	 goto cleanup;
+
+      ret = ret2;
+   }
+
+#ifdef USE_LOGIN_LIBRARY
+	if (ret == KRB5KDC_ERR_KEY_EXP)
+		goto cleanup;	/* Login library will deal appropriately with this error */
+#endif
+
+   /* at this point, we have an error from the master.  if the error
+      is not password expired, or if it is but there's no prompter,
+      return this error */
+
+   if ((ret != KRB5KDC_ERR_KEY_EXP) ||
+       (prompter == NULL))
+      goto cleanup;
+
+   /* ok, we have an expired password.  Give the user a few chances
+      to change it */
+
+   /* use a minimal set of options */
+
+   krb5_get_init_creds_opt_init(&chpw_opts);
+   krb5_get_init_creds_opt_set_tkt_life(&chpw_opts, 5*60);
+   krb5_get_init_creds_opt_set_renew_life(&chpw_opts, 0);
+   krb5_get_init_creds_opt_set_forwardable(&chpw_opts, 0);
+   krb5_get_init_creds_opt_set_proxiable(&chpw_opts, 0);
+
+   if ((ret = krb5_get_init_creds(context, &chpw_creds, client,
+				  prompter, data,
+				  start_time, "kadmin/changepw", &chpw_opts,
+				  krb5_get_as_key_password, (void *) &pw0,
+				  &use_master, NULL)))
+      goto cleanup;
+
+   prompt[0].prompt = "Enter new password";
+   prompt[0].hidden = 1;
+   prompt[0].reply = &pw0;
+   prompt_types[0] = KRB5_PROMPT_TYPE_NEW_PASSWORD;
+
+   prompt[1].prompt = "Enter it again";
+   prompt[1].hidden = 1;
+   prompt[1].reply = &pw1;
+   prompt_types[1] = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
+
+   strcpy(banner, "Password expired.  You must change it now.");
+
+   for (tries = 3; tries; tries--) {
+      pw0.length = sizeof(pw0array);
+      pw1.length = sizeof(pw1array);
+
+      /* PROMPTER_INVOCATION */
+      krb5int_set_prompt_types(context, prompt_types);
+      if ((ret = ((*prompter)(context, data, 0, banner,
+			      sizeof(prompt)/sizeof(prompt[0]), prompt))))
+	 goto cleanup;
+      krb5int_set_prompt_types(context, 0);
+
+
+      if (strcmp(pw0.data, pw1.data) != 0) {
+	 ret = KRB5_LIBOS_BADPWDMATCH;
+	 sprintf(banner, "%s.  Please try again.", error_message(ret));
+      } else if (pw0.length == 0) {
+	 ret = KRB5_CHPW_PWDNULL;
+	 sprintf(banner, "%s.  Please try again.", error_message(ret));
+      } else {
+	 int result_code;
+	 krb5_data code_string;
+	 krb5_data result_string;
+
+	 if ((ret = krb5_change_password(context, &chpw_creds, pw0array,
+					 &result_code, &code_string,
+					 &result_string)))
+	    goto cleanup;
+
+	 /* the change succeeded.  go on */
+
+	 if (result_code == 0) {
+	    krb5_xfree(result_string.data);
+	    break;
+	 }
+
+	 /* set this in case the retry loop falls through */
+
+	 ret = KRB5_CHPW_FAIL;
+
+	 if (result_code != KRB5_KPASSWD_SOFTERROR) {
+	    krb5_xfree(result_string.data);
+	    goto cleanup;
+	 }
+
+	 /* the error was soft, so try again */
+
+	 /* 100 is I happen to know that no code_string will be longer
+	    than 100 chars */
+
+	 if (result_string.length > (sizeof(banner)-100))
+	    result_string.length = sizeof(banner)-100;
+
+	 sprintf(banner, "%.*s%s%.*s.  Please try again.\n",
+		 (int) code_string.length, code_string.data,
+		 result_string.length ? ": " : "",
+		 (int) result_string.length,
+		 result_string.data ? result_string.data : "");
+
+	 krb5_xfree(code_string.data);
+	 krb5_xfree(result_string.data);
+      }
+   }
+
+   if (ret)
+      goto cleanup;
+
+   /* the password change was successful.  Get an initial ticket
+      from the master.  this is the last try.  the return from this
+      is final.  */
+
+   ret = krb5_get_init_creds(context, creds, client, prompter, data,
+			     start_time, in_tkt_service, options,
+			     krb5_get_as_key_password, (void *) &pw0,
+			     &use_master, &as_reply);
+
+cleanup:
+   krb5int_set_prompt_types(context, 0);
+   /* if getting the password was successful, then check to see if the
+      password is about to expire, and warn if so */
+
+   if (ret == 0) {
+      krb5_timestamp now;
+      krb5_last_req_entry **last_req;
+      int hours;
+
+      /* XXX 7 days should be configurable.  This is all pretty ad hoc,
+	 and could probably be improved if I was willing to screw around
+	 with timezones, etc. */
+
+      if (prompter &&
+	  (!in_tkt_service ||
+	   (strcmp(in_tkt_service, "kadmin/changepw") != 0)) &&
+	  ((ret = krb5_timeofday(context, &now)) == 0) &&
+	  as_reply->enc_part2->key_exp &&
+	  ((hours = ((as_reply->enc_part2->key_exp-now)/(60*60))) <= 7*24) &&
+	  (hours >= 0)) {
+	 if (hours < 1)
+	    sprintf(banner,
+		    "Warning: Your password will expire in less than one hour.");
+	 else if (hours <= 48)
+	    sprintf(banner, "Warning: Your password will expire in %d hour%s.",
+		    hours, (hours == 1)?"":"s");
+	 else
+	    sprintf(banner, "Warning: Your password will expire in %d days.",
+		    hours/24);
+
+	 /* ignore an error here */
+         /* PROMPTER_INVOCATION */
+	 (*prompter)(context, data, 0, banner, 0, 0);
+      } else if (prompter &&
+		 (!in_tkt_service ||
+		  (strcmp(in_tkt_service, "kadmin/changepw") != 0)) &&
+		 as_reply->enc_part2 && as_reply->enc_part2->last_req) {
+	 /*
+	  * Check the last_req fields
+	  */
+
+	 for (last_req = as_reply->enc_part2->last_req; *last_req; last_req++)
+	    if ((*last_req)->lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
+		(*last_req)->lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
+	       krb5_deltat delta;
+	       char ts[256];
+
+	       if ((ret = krb5_timeofday(context, &now)))
+		  break;
+
+	       if ((ret = krb5_timestamp_to_string((*last_req)->value,
+						   ts, sizeof(ts))))
+		  break;
+
+	       delta = (*last_req)->value - now;
+
+	       if (delta < 3600)
+		  sprintf(banner,
+		    "Warning: Your password will expire in less than one "
+		     "hour on %s", ts);
+	       else if (delta < 86400*2)
+		  sprintf(banner,
+		     "Warning: Your password will expire in %d hour%s on %s",
+		     delta / 3600, delta < 7200 ? "" : "s", ts);
+	       else
+		  sprintf(banner,
+		     "Warning: Your password will expire in %d days on %s",
+		     delta / 86400, ts);
+	       /* ignore an error here */
+	       /* PROMPTER_INVOCATION */
+	       (*prompter)(context, data, 0, banner, 0, 0);
+	    }
+      }
+   }
+
+   memset(pw0array, 0, sizeof(pw0array));
+   memset(pw1array, 0, sizeof(pw1array));
+   krb5_free_cred_contents(context, &chpw_creds);
+   if (as_reply)
+      krb5_free_kdc_rep(context, as_reply);
+
+   return(ret);
+}
+void krb5int_populate_gic_opt (
+    krb5_context context, krb5_get_init_creds_opt *opt,
+    krb5_flags options, krb5_address * const *addrs, krb5_enctype *ktypes,
+    krb5_preauthtype *pre_auth_types, krb5_creds *creds)
+{
+  int i;
+  krb5_int32 starttime;
+
+    krb5_get_init_creds_opt_init(opt);
+    if (addrs)
+      krb5_get_init_creds_opt_set_address_list(opt, (krb5_address **) addrs);
+    if (ktypes) {
+	for (i=0; ktypes[i]; i++);
+	if (i)
+	    krb5_get_init_creds_opt_set_etype_list(opt, ktypes, i);
+    }
+    if (pre_auth_types) {
+	for (i=0; pre_auth_types[i]; i++);
+	if (i)
+	    krb5_get_init_creds_opt_set_preauth_list(opt, pre_auth_types, i);
+    }
+    if (options&KDC_OPT_FORWARDABLE)
+	krb5_get_init_creds_opt_set_forwardable(opt, 1);
+    else krb5_get_init_creds_opt_set_forwardable(opt, 0);
+    if (options&KDC_OPT_PROXIABLE)
+	krb5_get_init_creds_opt_set_proxiable(opt, 1);
+    else krb5_get_init_creds_opt_set_proxiable(opt, 0);
+    if (creds && creds->times.endtime) {
+        krb5_timeofday(context, &starttime);
+        if (creds->times.starttime) starttime = creds->times.starttime;
+        krb5_get_init_creds_opt_set_tkt_life(opt, creds->times.endtime - starttime);
+    }
+}
+
+/*
+  Rewrites get_in_tkt in terms of newer get_init_creds API.
+ Attempts to get an initial ticket for creds->client to use server
+ creds->server, (realm is taken from creds->client), with options
+ options, and using creds->times.starttime, creds->times.endtime,
+ creds->times.renew_till as from, till, and rtime.  
+ creds->times.renew_till is ignored unless the RENEWABLE option is requested.
+
+ If addrs is non-NULL, it is used for the addresses requested.  If it is
+ null, the system standard addresses are used.
+
+ If password is non-NULL, it is converted using the cryptosystem entry
+ point for a string conversion routine, seeded with the client's name.
+ If password is passed as NULL, the password is read from the terminal,
+ and then converted into a key.
+
+ A succesful call will place the ticket in the credentials cache ccache.
+
+ returns system errors, encryption errors
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_in_tkt_with_password(krb5_context context, krb5_flags options,
+			      krb5_address *const *addrs, krb5_enctype *ktypes,
+			      krb5_preauthtype *pre_auth_types,
+			      const char *password, krb5_ccache ccache,
+			      krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
+{
+    krb5_error_code retval;
+    krb5_data pw0;
+    char pw0array[1024];
+    krb5_get_init_creds_opt opt;
+    char * server;
+    krb5_principal server_princ, client_princ;
+    int use_master = 0;
+
+    pw0array[0] = '\0';
+    pw0.data = pw0array;
+    if (password) {
+	pw0.length = strlen(password);
+	if (pw0.length > sizeof(pw0array))
+	    return EINVAL;
+	strncpy(pw0.data, password, sizeof(pw0array));
+	if (pw0.length == 0)
+	    pw0.length = sizeof(pw0array);
+    } else {
+	pw0.length = sizeof(pw0array);
+    }
+    krb5int_populate_gic_opt(context, &opt,
+			     options, addrs, ktypes,
+			     pre_auth_types, creds);
+    retval = krb5_unparse_name( context, creds->server, &server);
+    if (retval)
+      return (retval);
+    server_princ = creds->server;
+    client_princ = creds->client;
+        retval = krb5_get_init_creds (context,
+					   creds, creds->client,  
+					   krb5_prompter_posix,  NULL,
+					   0, server, &opt,
+				      krb5_get_as_key_password, &pw0,
+				      &use_master, ret_as_reply);
+	  krb5_free_unparsed_name( context, server);
+	if (retval) {
+	  return (retval);
+	}
+	if (creds->server)
+	    krb5_free_principal( context, creds->server);
+	if (creds->client)
+	    krb5_free_principal( context, creds->client);
+	creds->client = client_princ;
+	creds->server = server_princ;
+	/* store it in the ccache! */
+	if (ccache)
+	  if ((retval = krb5_cc_store_cred(context, ccache, creds)))
+	    return (retval);
+	return retval;
+  }
+
diff --git a/mechglue/src/lib/krb5/krb/in_tkt_sky.c b/mechglue/src/lib/krb5/krb/in_tkt_sky.c
new file mode 100644
index 000000000..6de207550
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/in_tkt_sky.c
@@ -0,0 +1,112 @@
+/*
+ * lib/krb5/krb/in_tkt_sky.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_get_in_tkt_with_skey()
+ *	
+ */
+
+#include "k5-int.h"
+
+struct skey_keyproc_arg {
+    const krb5_keyblock *key;
+    krb5_principal client;		/* it's a pointer, really! */
+};
+
+/*
+ * Key-generator for in_tkt_skey, below.
+ * "keyseed" is actually a krb5_keyblock *, or NULL if we should fetch
+ * from system area.
+ */
+static krb5_error_code skey_keyproc
+    (krb5_context,
+               const krb5_enctype,
+               krb5_data *,
+               krb5_const_pointer,
+               krb5_keyblock **);
+
+static krb5_error_code
+skey_keyproc(krb5_context context, krb5_enctype type, krb5_data *salt,
+	     krb5_const_pointer keyseed, krb5_keyblock **key)
+{
+    krb5_keyblock *realkey;
+    krb5_error_code retval;
+    const krb5_keyblock * keyblock;
+
+    keyblock = (const krb5_keyblock *)keyseed;
+
+    if (!krb5_c_valid_enctype(type))
+	return KRB5_PROG_ETYPE_NOSUPP;
+
+    if ((retval = krb5_copy_keyblock(context, keyblock, &realkey)))
+	return retval;
+	
+    if (realkey->enctype != type) {
+	krb5_free_keyblock(context, realkey);
+	return KRB5_PROG_ETYPE_NOSUPP;
+    }	
+
+    *key = realkey;
+    return 0;
+}
+
+/*
+ Similar to krb5_get_in_tkt_with_password.
+
+ Attempts to get an initial ticket for creds->client to use server
+ creds->server, (realm is taken from creds->client), with options
+ options, and using creds->times.starttime, creds->times.endtime,
+ creds->times.renew_till as from, till, and rtime.  
+ creds->times.renew_till is ignored unless the RENEWABLE option is requested.
+
+ If addrs is non-NULL, it is used for the addresses requested.  If it is
+ null, the system standard addresses are used.
+
+ If keyblock is NULL, an appropriate key for creds->client is retrieved
+ from the system key store (e.g. /etc/srvtab).  If keyblock is non-NULL,
+ it is used as the decryption key.
+
+ A succesful call will place the ticket in the credentials cache ccache.
+
+ returns system errors, encryption errors
+
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_in_tkt_with_skey(krb5_context context, krb5_flags options,
+			  krb5_address *const *addrs, krb5_enctype *ktypes,
+			  krb5_preauthtype *pre_auth_types,
+			  const krb5_keyblock *key, krb5_ccache ccache,
+			  krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
+{
+    if (key) 
+    	return krb5_get_in_tkt(context, options, addrs, ktypes, pre_auth_types, 
+			       skey_keyproc, (krb5_const_pointer)key,
+			       krb5_kdc_rep_decrypt_proc, 0, creds,
+			       ccache, ret_as_reply);
+    else 
+	return krb5_get_in_tkt_with_keytab(context, options, addrs, ktypes,
+					   pre_auth_types, NULL, ccache,
+					   creds, ret_as_reply);
+}
diff --git a/mechglue/src/lib/krb5/krb/init_ctx.c b/mechglue/src/lib/krb5/krb/init_ctx.c
new file mode 100644
index 000000000..3cbf99e5b
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/init_ctx.c
@@ -0,0 +1,494 @@
+/*
+ * lib/krb5/krb/init_ctx.c
+ *
+ * Copyright 1994,1999,2000, 2002, 2003  by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * krb5_init_contex()
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include <ctype.h>
+#include "brand.c"
+/* There has to be a better way for windows... */
+#if defined(unix) || TARGET_OS_MAC
+#include "../krb5_libinit.h"
+#endif
+
+/* The des-mdX entries are last for now, because it's easy to
+   configure KDCs to issue TGTs with des-mdX keys and then not accept
+   them.  This'll be fixed, but for better compatibility, let's prefer
+   des-crc for now.  */
+#define DEFAULT_ETYPE_LIST	\
+	"aes256-cts-hmac-sha1-96 " \
+	"aes128-cts-hmac-sha1-96 " \
+	"des3-cbc-sha1 arcfour-hmac-md5 " \
+	"des-cbc-crc des-cbc-md5 des-cbc-md4 "
+
+/* Not included:
+	"aes128-cts-hmac-sha1-96 " \
+ */
+
+#if (defined(_WIN32))
+extern krb5_error_code krb5_vercheck();
+extern void krb5_win_ccdll_load(krb5_context context);
+#endif
+
+static krb5_error_code init_common (krb5_context *, krb5_boolean);
+
+krb5_error_code KRB5_CALLCONV
+krb5_init_context(krb5_context *context)
+{
+
+	return init_common (context, FALSE);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_init_secure_context(krb5_context *context)
+{
+
+        /* This is to make gcc -Wall happy */
+        if(0) krb5_brand[0] = krb5_brand[0];
+	return init_common (context, TRUE);
+}
+
+static krb5_error_code
+init_common (krb5_context *context, krb5_boolean secure)
+{
+	krb5_context ctx = 0;
+	krb5_error_code retval;
+	struct {
+	    krb5_int32 now, now_usec;
+	    long pid;
+	} seed_data;
+	krb5_data seed;
+	int tmp;
+
+	/* Verify some assumptions.  If the assumptions hold and the
+	   compiler is optimizing, this should result in no code being
+	   executed.  If we're guessing "unsigned long long" instead
+	   of using uint64_t, the possibility does exist that we're
+	   wrong.  */
+	{
+	    krb5_ui_8 i64;
+	    assert(sizeof(i64) == 8);
+	    i64 = 0, i64--, i64 >>= 62;
+	    assert(i64 == 3);
+	    i64 = 1, i64 <<= 31, i64 <<= 31, i64 <<= 1;
+	    assert(i64 != 0);
+	    i64 <<= 1;
+	    assert(i64 == 0);
+	}
+
+	retval = krb5int_initialize_library();
+	if (retval)
+	    return retval;
+
+#if (defined(_WIN32))
+	/* 
+	 * Load the krbcc32.dll if necessary.  We do this here so that
+	 * we know to use API: later on during initialization.
+	 * The context being NULL is ok.
+	 */
+	krb5_win_ccdll_load(ctx);
+
+	/*
+	 * krb5_vercheck() is defined in win_glue.c, and this is
+	 * where we handle the timebomb and version server checks.
+	 */
+	retval = krb5_vercheck();
+	if (retval)
+		return retval;
+#endif
+
+	*context = 0;
+
+	ctx = malloc(sizeof(struct _krb5_context));
+	if (!ctx)
+		return ENOMEM;
+	memset(ctx, 0, sizeof(struct _krb5_context));
+	ctx->magic = KV5M_CONTEXT;
+
+	ctx->profile_secure = secure;
+
+	/* Set the default encryption types, possible defined in krb5/conf */
+	if ((retval = krb5_set_default_in_tkt_ktypes(ctx, NULL)))
+		goto cleanup;
+
+	if ((retval = krb5_set_default_tgs_ktypes(ctx, NULL)))
+		goto cleanup;
+
+	ctx->conf_tgs_ktypes = calloc(ctx->tgs_ktype_count, sizeof(krb5_enctype));
+	if (ctx->conf_tgs_ktypes == NULL && ctx->tgs_ktype_count != 0)
+	    goto cleanup;
+	memcpy(ctx->conf_tgs_ktypes, ctx->tgs_ktypes,
+	       sizeof(krb5_enctype) * ctx->tgs_ktype_count);
+	ctx->conf_tgs_ktypes_count = ctx->tgs_ktype_count;
+
+	if ((retval = krb5_os_init_context(ctx)))
+		goto cleanup;
+
+	/* initialize the prng (not well, but passable) */
+	if ((retval = krb5_c_random_os_entropy( ctx, 0, NULL)) !=0)
+	  goto cleanup;
+	if ((retval = krb5_crypto_us_timeofday(&seed_data.now, &seed_data.now_usec)))
+		goto cleanup;
+	seed_data.pid = getpid ();
+	seed.length = sizeof(seed_data);
+	seed.data = (char *) &seed_data;
+	if ((retval = krb5_c_random_add_entropy(ctx, KRB5_C_RANDSOURCE_TIMING, &seed)))
+		goto cleanup;
+
+	ctx->default_realm = 0;
+	profile_get_integer(ctx->profile, "libdefaults", "clockskew",
+			    0, 5 * 60, &tmp);
+	ctx->clockskew = tmp;
+
+#if 0
+	/* Default ticket lifetime is currently not supported */
+	profile_get_integer(ctx->profile, "libdefaults", "tkt_lifetime",
+			    0, 10 * 60 * 60, &tmp);
+	ctx->tkt_lifetime = tmp;
+#endif
+
+	/* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2)  */
+	/* DCE add kdc_req_checksum_type = 2 to krb5.conf */
+	profile_get_integer(ctx->profile, "libdefaults",
+			    "kdc_req_checksum_type", 0, CKSUMTYPE_RSA_MD5, 
+			    &tmp);
+	ctx->kdc_req_sumtype = tmp;
+
+	profile_get_integer(ctx->profile, "libdefaults",
+			    "ap_req_checksum_type", 0, CKSUMTYPE_RSA_MD5,
+			    &tmp);
+	ctx->default_ap_req_sumtype = tmp;
+
+	profile_get_integer(ctx->profile, "libdefaults",
+			    "safe_checksum_type", 0,
+			    CKSUMTYPE_RSA_MD5_DES, &tmp);
+	ctx->default_safe_sumtype = tmp;
+
+	profile_get_integer(ctx->profile, "libdefaults",
+			    "kdc_default_options", 0,
+			    KDC_OPT_RENEWABLE_OK, &tmp);
+	ctx->kdc_default_options = tmp;
+#define DEFAULT_KDC_TIMESYNC 1
+	profile_get_integer(ctx->profile, "libdefaults",
+			    "kdc_timesync", 0, DEFAULT_KDC_TIMESYNC,
+			    &tmp);
+	ctx->library_options = tmp ? KRB5_LIBOPT_SYNC_KDCTIME : 0;
+
+	/*
+	 * We use a default file credentials cache of 3.  See
+	 * lib/krb5/krb/ccache/file/fcc.h for a description of the
+	 * credentials cache types.
+	 *
+	 * Note: DCE 1.0.3a only supports a cache type of 1
+	 * 	DCE 1.1 supports a cache type of 2.
+	 */
+#define DEFAULT_CCACHE_TYPE 4
+	profile_get_integer(ctx->profile, "libdefaults", "ccache_type",
+			    0, DEFAULT_CCACHE_TYPE, &tmp);
+	ctx->fcc_default_format = tmp + 0x0500;
+	ctx->scc_default_format = tmp + 0x0500;
+	ctx->prompt_types = 0;
+	ctx->use_conf_ktypes = 0;
+
+	ctx->udp_pref_limit = -1;
+	*context = ctx;
+	return 0;
+
+cleanup:
+	krb5_free_context(ctx);
+	return retval;
+}
+
+void KRB5_CALLCONV
+krb5_free_context(krb5_context ctx)
+{
+     krb5_os_free_context(ctx);
+
+     if (ctx->in_tkt_ktypes) {
+          free(ctx->in_tkt_ktypes);
+	  ctx->in_tkt_ktypes = 0;
+     }
+
+     if (ctx->tgs_ktypes) {
+          free(ctx->tgs_ktypes);
+	  ctx->tgs_ktypes = 0;
+     }
+
+     if (ctx->conf_tgs_ktypes) {
+	 free(ctx->conf_tgs_ktypes);
+	 ctx->conf_tgs_ktypes = 0;
+     }
+
+     if (ctx->default_realm) {
+	  free(ctx->default_realm);
+	  ctx->default_realm = 0;
+     }
+
+     if (ctx->ser_ctx_count && ctx->ser_ctx) {
+	  free(ctx->ser_ctx);
+	  ctx->ser_ctx = 0;
+     }
+
+     ctx->magic = 0;
+     free(ctx);
+}
+
+/*
+ * Set the desired default ktypes, making sure they are valid.
+ */
+krb5_error_code
+krb5_set_default_in_tkt_ktypes(krb5_context context, const krb5_enctype *ktypes)
+{
+    krb5_enctype * new_ktypes;
+    int i;
+
+    if (ktypes) {
+	for (i = 0; ktypes[i]; i++) {
+	    if (!krb5_c_valid_enctype(ktypes[i])) 
+		return KRB5_PROG_ETYPE_NOSUPP;
+	}
+
+	/* Now copy the default ktypes into the context pointer */
+	if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
+	    memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
+	else
+	    return ENOMEM;
+
+    } else {
+	i = 0;
+	new_ktypes = 0;
+    }
+
+    if (context->in_tkt_ktypes) 
+        free(context->in_tkt_ktypes);
+    context->in_tkt_ktypes = new_ktypes;
+    context->in_tkt_ktype_count = i;
+    return 0;
+}
+
+static krb5_error_code
+get_profile_etype_list(krb5_context context, krb5_enctype **ktypes, char *profstr,
+		       int ctx_count, krb5_enctype *ctx_list)
+{
+    krb5_enctype *old_ktypes;
+
+    if (ctx_count) {
+	/* application-set defaults */
+	if ((old_ktypes = 
+	     (krb5_enctype *)malloc(sizeof(krb5_enctype) *
+				    (ctx_count + 1)))) {
+	    memcpy(old_ktypes, ctx_list, sizeof(krb5_enctype) * ctx_count);
+	    old_ktypes[ctx_count] = 0;
+	} else {
+	    return ENOMEM;
+	}
+    } else {
+        /*
+	   XXX - For now, we only support libdefaults
+	   Perhaps this should be extended to allow for per-host / per-realm
+	   session key types.
+	 */
+
+	char *retval;
+	char *sp, *ep;
+	int i, j, count;
+	krb5_error_code code;
+
+	code = profile_get_string(context->profile, "libdefaults", profstr,
+				  NULL, DEFAULT_ETYPE_LIST, &retval);
+	if (code)
+	    return code;
+
+	count = 0;
+	sp = retval;
+	while (*sp) {
+	    for (ep = sp; *ep && (*ep != ',') && !isspace((int) (*ep)); ep++)
+		;
+	    if (*ep) {
+		*ep++ = '\0';
+		while (isspace((int) (*ep)) || *ep == ',')
+		    *ep++ = '\0';
+	    }
+	    count++;
+	    sp = ep;
+	}
+	
+	if ((old_ktypes =
+	     (krb5_enctype *)malloc(sizeof(krb5_enctype) * (count + 1))) ==
+	    (krb5_enctype *) NULL)
+	    return ENOMEM;
+	
+	sp = retval;
+	j = 0;
+	i = 1;
+	while (1) {
+	    if (! krb5_string_to_enctype(sp, &old_ktypes[j]))
+		j++;
+
+	    if (i++ >= count)
+		break;
+
+	    /* skip to next token */
+	    while (*sp) sp++;
+	    while (! *sp) sp++;
+	}
+
+	old_ktypes[j] = (krb5_enctype) 0;
+	profile_release_string(retval);
+    }
+
+    if (old_ktypes[0] == 0) {
+	free (old_ktypes);
+	*ktypes = 0;
+	return KRB5_CONFIG_ETYPE_NOSUPP;
+    }
+
+    *ktypes = old_ktypes;
+    return 0;
+}
+
+krb5_error_code
+krb5_get_default_in_tkt_ktypes(krb5_context context, krb5_enctype **ktypes)
+{
+    return(get_profile_etype_list(context, ktypes, "default_tkt_enctypes",
+				  context->in_tkt_ktype_count,
+				  context->in_tkt_ktypes));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_default_tgs_enctypes (krb5_context context, const krb5_enctype *ktypes)
+{
+    krb5_enctype * new_ktypes;
+    int i;
+
+    if (ktypes) {
+	for (i = 0; ktypes[i]; i++) {
+	    if (!krb5_c_valid_enctype(ktypes[i])) 
+		return KRB5_PROG_ETYPE_NOSUPP;
+	}
+
+	/* Now copy the default ktypes into the context pointer */
+	if ((new_ktypes = (krb5_enctype *)malloc(sizeof(krb5_enctype) * i)))
+	    memcpy(new_ktypes, ktypes, sizeof(krb5_enctype) * i);
+	else
+	    return ENOMEM;
+
+    } else {
+	i = 0;
+	new_ktypes = (krb5_enctype *)NULL;
+    }
+
+    if (context->tgs_ktypes) 
+        krb5_free_ktypes(context, context->tgs_ktypes);
+    context->tgs_ktypes = new_ktypes;
+    context->tgs_ktype_count = i;
+    return 0;
+}
+
+krb5_error_code krb5_set_default_tgs_ktypes
+(krb5_context context, const krb5_enctype *etypes)
+{
+  return (krb5_set_default_tgs_enctypes (context, etypes));
+}
+
+
+void
+KRB5_CALLCONV
+krb5_free_ktypes (krb5_context context, krb5_enctype *val)
+{
+    free (val);
+}
+
+krb5_error_code
+KRB5_CALLCONV
+krb5_get_tgs_ktypes(krb5_context context, krb5_const_principal princ, krb5_enctype **ktypes)
+{
+    if (context->use_conf_ktypes)
+	/* This one is set *only* by reading the config file; it's not
+	   set by the application.  */
+	return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
+				      context->conf_tgs_ktypes_count,
+				      context->conf_tgs_ktypes));
+    else
+	return(get_profile_etype_list(context, ktypes, "default_tgs_enctypes",
+				      context->tgs_ktype_count,
+				      context->tgs_ktypes));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_permitted_enctypes(krb5_context context, krb5_enctype **ktypes)
+{
+    return(get_profile_etype_list(context, ktypes, "permitted_enctypes",
+				  context->tgs_ktype_count,
+				  context->tgs_ktypes));
+}
+
+krb5_boolean
+krb5_is_permitted_enctype(krb5_context context, krb5_enctype etype)
+{
+    krb5_enctype *list, *ptr;
+    krb5_boolean ret;
+
+    if (krb5_get_permitted_enctypes(context, &list))
+	return(0);
+
+    
+    ret = 0;
+
+    for (ptr = list; *ptr; ptr++)
+	if (*ptr == etype)
+	    ret = 1;
+
+    krb5_free_ktypes (context, list);
+
+    return(ret);
+}
diff --git a/mechglue/src/lib/krb5/krb/init_keyblock.c b/mechglue/src/lib/krb5/krb/init_keyblock.c
new file mode 100644
index 000000000..3be842ac8
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/init_keyblock.c
@@ -0,0 +1,41 @@
+/*
+ * lib/krb5/krb/init_keyblock.c
+ *
+ * Copyright (C) 2002 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * 
+ *
+ * krb5_init_keyblock- a function to set up 
+ *  an empty keyblock
+ */
+
+
+#include "k5-int.h"
+#include <assert.h>
+
+krb5_error_code KRB5_CALLCONV  krb5_init_keyblock
+	(krb5_context context, krb5_enctype enctype,
+	 size_t length, krb5_keyblock **out)
+{
+  return krb5int_c_init_keyblock (context, enctype, length, out);
+}
diff --git a/mechglue/src/lib/krb5/krb/int-proto.h b/mechglue/src/lib/krb5/krb/int-proto.h
new file mode 100644
index 000000000..75ffa55f7
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/int-proto.h
@@ -0,0 +1,52 @@
+/*
+ * lib/krb5/krb/int-proto.h
+ *
+ * Copyright 1990,1991 the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Function prototypes for Kerberos V5 library internal functions.
+ */
+
+
+#ifndef KRB5_INT_FUNC_PROTO__
+#define KRB5_INT_FUNC_PROTO__
+
+krb5_error_code krb5_tgtname
+    	(krb5_context context,
+	           const krb5_data *,
+	           const krb5_data *,
+	           krb5_principal *);
+
+krb5_error_code krb5_libdefault_boolean
+        (krb5_context, const krb5_data *, const char *,
+			int *);
+
+krb5_error_code krb5_ser_authdata_init (krb5_context);
+krb5_error_code krb5_ser_address_init (krb5_context);
+krb5_error_code krb5_ser_authenticator_init (krb5_context);
+krb5_error_code krb5_ser_checksum_init (krb5_context);
+krb5_error_code krb5_ser_keyblock_init (krb5_context);
+krb5_error_code krb5_ser_principal_init (krb5_context);
+
+#endif /* KRB5_INT_FUNC_PROTO__ */
+
diff --git a/mechglue/src/lib/krb5/krb/kdc_rep_dc.c b/mechglue/src/lib/krb5/krb/kdc_rep_dc.c
new file mode 100644
index 000000000..42559b2f1
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/kdc_rep_dc.c
@@ -0,0 +1,80 @@
+/*
+ * lib/krb5/krb/kdc_rep_dc.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_kdc_rep_decrypt_proc()
+ */
+
+#include "k5-int.h"
+
+/*
+ * Decrypt the encrypted portion of the KDC_REP message, using the key
+ * passed.
+ *
+ */
+
+/*ARGSUSED*/
+krb5_error_code
+krb5_kdc_rep_decrypt_proc(krb5_context context, const krb5_keyblock *key, krb5_const_pointer decryptarg, krb5_kdc_rep *dec_rep)
+{
+    krb5_error_code retval;
+    krb5_data scratch;
+    krb5_enc_kdc_rep_part *local_encpart;
+    krb5_keyusage usage;
+
+    if (decryptarg) {
+	usage = *(const krb5_keyusage *) decryptarg;
+    } else {
+	usage = KRB5_KEYUSAGE_AS_REP_ENCPART;
+    }
+
+    /* set up scratch decrypt/decode area */
+
+    scratch.length = dec_rep->enc_part.ciphertext.length;
+    if (!(scratch.data = malloc(dec_rep->enc_part.ciphertext.length))) {
+	return(ENOMEM);
+    }
+
+    /*dec_rep->enc_part.enctype;*/
+
+    if ((retval = krb5_c_decrypt(context, key, usage, 0, &dec_rep->enc_part,
+				 &scratch))) {
+	free(scratch.data);
+	return(retval);
+    }
+
+#define clean_scratch() {memset(scratch.data, 0, scratch.length); \
+free(scratch.data);}
+
+    /* and do the decode */
+    retval = decode_krb5_enc_kdc_rep_part(&scratch, &local_encpart);
+    clean_scratch();
+    if (retval)
+	return retval;
+
+    dec_rep->enc_part2 = local_encpart;
+
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/kfree.c b/mechglue/src/lib/krb5/krb/kfree.c
new file mode 100644
index 000000000..39bb1f212
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/kfree.c
@@ -0,0 +1,715 @@
+/*
+ * lib/krb5/free/f_addr.c
+ *
+ * Copyright 1990-1998 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_free_address()
+ */
+
+#include "k5-int.h"
+
+void KRB5_CALLCONV
+krb5_free_address(krb5_context context, krb5_address *val)
+{
+    if (val->contents)
+	krb5_xfree(val->contents);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_addresses(krb5_context context, krb5_address **val)
+{
+    register krb5_address **temp;
+
+    for (temp = val; *temp; temp++) {
+	if ((*temp)->contents)
+	    krb5_xfree((*temp)->contents);
+	krb5_xfree(*temp);
+    }
+    krb5_xfree(val);
+}
+
+
+void KRB5_CALLCONV
+krb5_free_ap_rep(krb5_context context, register krb5_ap_rep *val)
+{
+    if (val->enc_part.ciphertext.data)
+	krb5_xfree(val->enc_part.ciphertext.data);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_ap_req(krb5_context context, register krb5_ap_req *val)
+{
+    if (val->ticket)
+	krb5_free_ticket(context, val->ticket);
+    if (val->authenticator.ciphertext.data)
+	krb5_xfree(val->authenticator.ciphertext.data);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_ap_rep_enc_part(krb5_context context, krb5_ap_rep_enc_part *val)
+{
+    if (val->subkey)
+	krb5_free_keyblock(context, val->subkey);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_authenticator_contents(krb5_context context, krb5_authenticator *val)
+{
+    if (val->checksum) {
+	krb5_free_checksum(context, val->checksum);
+	val->checksum = 0;
+    }
+    if (val->client) {
+	krb5_free_principal(context, val->client);
+	val->client = 0;
+    }
+    if (val->subkey) {
+	krb5_free_keyblock(context, val->subkey);
+	val->subkey = 0;
+    }
+    if (val->authorization_data) {
+	krb5_free_authdata(context, val->authorization_data);
+	val->authorization_data = 0;
+    }
+}
+
+void KRB5_CALLCONV
+krb5_free_authdata(krb5_context context, krb5_authdata **val)
+{
+    register krb5_authdata **temp;
+
+    for (temp = val; *temp; temp++) {
+	if ((*temp)->contents)
+	    krb5_xfree((*temp)->contents);
+	krb5_xfree(*temp);
+    }
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_authenticator(krb5_context context, krb5_authenticator *val)
+{
+    krb5_free_authenticator_contents(context, val);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_checksum(krb5_context context, register krb5_checksum *val)
+{
+    krb5_free_checksum_contents(context, val);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_checksum_contents(krb5_context context, register krb5_checksum *val)
+{
+    if (val->contents) {
+	krb5_xfree(val->contents);
+	val->contents = 0;
+    }
+}
+
+void KRB5_CALLCONV
+krb5_free_cred(krb5_context context, register krb5_cred *val)
+{
+    if (val->tickets)
+        krb5_free_tickets(context, val->tickets);
+    if (val->enc_part.ciphertext.data)
+	krb5_xfree(val->enc_part.ciphertext.data);
+    krb5_xfree(val);
+}
+
+/*
+ * krb5_free_cred_contents zeros out the session key, and then frees
+ * the credentials structures 
+ */
+
+void KRB5_CALLCONV
+krb5_free_cred_contents(krb5_context context, krb5_creds *val)
+{
+    if (val->client) {
+	krb5_free_principal(context, val->client);
+	val->client = 0;
+    }
+    if (val->server) {
+	krb5_free_principal(context, val->server);
+	val->server = 0;
+    }
+    if (val->keyblock.contents) {
+	memset((char *)val->keyblock.contents, 0, val->keyblock.length);
+	krb5_xfree(val->keyblock.contents);
+	val->keyblock.contents = 0;
+    }
+    if (val->ticket.data) {
+	krb5_xfree(val->ticket.data);
+	val->ticket.data = 0;
+    }
+    if (val->second_ticket.data) {
+	krb5_xfree(val->second_ticket.data);
+	val->second_ticket.data = 0;
+    }
+    if (val->addresses) {
+	krb5_free_addresses(context, val->addresses);
+	val->addresses = 0;
+    }
+    if (val->authdata) {
+	krb5_free_authdata(context, val->authdata);
+	val->authdata = 0;
+    }
+}
+
+void KRB5_CALLCONV 
+krb5_free_cred_enc_part(krb5_context context, register krb5_cred_enc_part *val)
+{
+    register krb5_cred_info **temp;
+    
+    if (val->r_address) {
+	krb5_free_address(context, val->r_address);
+	val->r_address = 0;
+    }
+    if (val->s_address) {
+	krb5_free_address(context, val->s_address);
+	val->s_address = 0;
+    }
+
+    if (val->ticket_info) {
+	for (temp = val->ticket_info; *temp; temp++) {
+	    if ((*temp)->session)
+		krb5_free_keyblock(context, (*temp)->session);
+	    if ((*temp)->client)
+		krb5_free_principal(context, (*temp)->client);
+	    if ((*temp)->server)
+		krb5_free_principal(context, (*temp)->server);
+	    if ((*temp)->caddrs)
+		krb5_free_addresses(context, (*temp)->caddrs);
+	    krb5_xfree((*temp));
+	}
+	krb5_xfree(val->ticket_info);
+	val->ticket_info = 0;
+    }
+}
+
+
+void KRB5_CALLCONV
+krb5_free_creds(krb5_context context, krb5_creds *val)
+{
+    krb5_free_cred_contents(context, val);
+    krb5_xfree(val);
+}
+
+
+void KRB5_CALLCONV
+krb5_free_data(krb5_context context, krb5_data *val)
+{
+    if (val->data)
+	krb5_xfree(val->data);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_data_contents(krb5_context context, krb5_data *val)
+{
+    if (val->data) {
+	krb5_xfree(val->data);
+	val->data = 0;
+    }
+}
+
+void krb5_free_etype_info(krb5_context context, krb5_etype_info info)
+{
+  int i;
+
+  for(i=0; info[i] != NULL; i++) {
+      if (info[i]->salt)
+	  free(info[i]->salt);
+      krb5_free_data_contents( context, &info[i]->s2kparams);
+      free(info[i]);
+  }
+  free(info);
+}
+    
+
+void KRB5_CALLCONV
+krb5_free_enc_kdc_rep_part(krb5_context context, register krb5_enc_kdc_rep_part *val)
+{
+    if (val->session)
+	krb5_free_keyblock(context, val->session);
+    if (val->last_req)
+	krb5_free_last_req(context, val->last_req);
+    if (val->server)
+	krb5_free_principal(context, val->server);
+    if (val->caddrs)
+	krb5_free_addresses(context, val->caddrs);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_enc_tkt_part(krb5_context context, krb5_enc_tkt_part *val)
+{
+    if (val->session)
+	krb5_free_keyblock(context, val->session);
+    if (val->client)
+	krb5_free_principal(context, val->client);
+    if (val->transited.tr_contents.data)
+	krb5_xfree(val->transited.tr_contents.data);
+    if (val->caddrs)
+	krb5_free_addresses(context, val->caddrs);
+    if (val->authorization_data)
+	krb5_free_authdata(context, val->authorization_data);
+    krb5_xfree(val);
+}
+
+
+void KRB5_CALLCONV
+krb5_free_error(krb5_context context, register krb5_error *val)
+{
+    if (val->client)
+	krb5_free_principal(context, val->client);
+    if (val->server)
+	krb5_free_principal(context, val->server);
+    if (val->text.data)
+	krb5_xfree(val->text.data);
+    if (val->e_data.data)
+	krb5_xfree(val->e_data.data);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_kdc_rep(krb5_context context, krb5_kdc_rep *val)
+{
+    if (val->padata)
+	krb5_free_pa_data(context, val->padata);
+    if (val->client)
+	krb5_free_principal(context, val->client);
+    if (val->ticket)
+	krb5_free_ticket(context, val->ticket);
+    if (val->enc_part.ciphertext.data)
+	krb5_xfree(val->enc_part.ciphertext.data);
+    if (val->enc_part2)
+	krb5_free_enc_kdc_rep_part(context, val->enc_part2);
+    krb5_xfree(val);
+}
+
+
+void KRB5_CALLCONV
+krb5_free_kdc_req(krb5_context context, krb5_kdc_req *val)
+{
+    if (val->padata)
+	krb5_free_pa_data(context, val->padata);
+    if (val->client)
+	krb5_free_principal(context, val->client);
+    if (val->server)
+	krb5_free_principal(context, val->server);
+    if (val->ktype)
+	krb5_xfree(val->ktype);
+    if (val->addresses)
+	krb5_free_addresses(context, val->addresses);
+    if (val->authorization_data.ciphertext.data)
+	krb5_xfree(val->authorization_data.ciphertext.data);
+    if (val->unenc_authdata)
+	krb5_free_authdata(context, val->unenc_authdata);
+    if (val->second_ticket)
+	krb5_free_tickets(context, val->second_ticket);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_keyblock_contents(krb5_context context, register krb5_keyblock *key)
+{
+    krb5int_c_free_keyblock_contents (context, key);
+}
+
+void KRB5_CALLCONV
+krb5_free_keyblock(krb5_context context, register krb5_keyblock *val)
+{
+    krb5int_c_free_keyblock (context, val);
+}
+
+
+
+void KRB5_CALLCONV
+krb5_free_last_req(krb5_context context, krb5_last_req_entry **val)
+{
+    register krb5_last_req_entry **temp;
+
+    for (temp = val; *temp; temp++)
+	krb5_xfree(*temp);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_pa_data(krb5_context context, krb5_pa_data **val)
+{
+    register krb5_pa_data **temp;
+
+    for (temp = val; *temp; temp++) {
+	if ((*temp)->contents)
+	    krb5_xfree((*temp)->contents);
+	krb5_xfree(*temp);
+    }
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_principal(krb5_context context, krb5_principal val)
+{
+    register krb5_int32 i;
+
+    if (!val)
+	return;
+    
+    if (val->data) {
+	i = krb5_princ_size(context, val);
+	while(--i >= 0)
+	    free(krb5_princ_component(context, val, i)->data);
+	krb5_xfree(val->data);
+    }
+    if (val->realm.data)
+	krb5_xfree(val->realm.data);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_priv(krb5_context context, register krb5_priv *val)
+{
+    if (val->enc_part.ciphertext.data)
+	krb5_xfree(val->enc_part.ciphertext.data);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_priv_enc_part(krb5_context context, register krb5_priv_enc_part *val)
+{
+    if (val->user_data.data)
+	krb5_xfree(val->user_data.data);
+    if (val->r_address)
+	krb5_free_address(context, val->r_address);
+    if (val->s_address)
+	krb5_free_address(context, val->s_address);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_pwd_data(krb5_context context, krb5_pwd_data *val)
+{
+    if (val->element)
+	krb5_free_pwd_sequences(context, val->element);
+    krb5_xfree(val);
+}
+
+
+void KRB5_CALLCONV
+krb5_free_pwd_sequences(krb5_context context, passwd_phrase_element **val)
+{
+    register passwd_phrase_element **temp;
+
+    for (temp = val; *temp; temp++) {
+	if ((*temp)->passwd) {
+	   krb5_free_data(context, (*temp)->passwd);
+	   (*temp)->passwd = 0;
+	}
+	if ((*temp)->phrase) {
+	   krb5_free_data(context, (*temp)->phrase);
+	   (*temp)->phrase = 0;
+	}
+	krb5_xfree(*temp);
+    }
+    krb5_xfree(val);
+}
+
+
+void KRB5_CALLCONV
+krb5_free_safe(krb5_context context, register krb5_safe *val)
+{
+    if (val->user_data.data)
+	krb5_xfree(val->user_data.data);
+    if (val->r_address)
+	krb5_free_address(context, val->r_address);
+    if (val->s_address)
+	krb5_free_address(context, val->s_address);
+    if (val->checksum)
+	krb5_free_checksum(context, val->checksum);
+    krb5_xfree(val);
+}
+
+
+void KRB5_CALLCONV
+krb5_free_ticket(krb5_context context, krb5_ticket *val)
+{
+    if (val->server)
+	krb5_free_principal(context, val->server);
+    if (val->enc_part.ciphertext.data)
+	krb5_xfree(val->enc_part.ciphertext.data);
+    if (val->enc_part2)
+	krb5_free_enc_tkt_part(context, val->enc_part2);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_tickets(krb5_context context, krb5_ticket **val)
+{
+    register krb5_ticket **temp;
+
+    for (temp = val; *temp; temp++)
+        krb5_free_ticket(context, *temp);
+    krb5_xfree(val);
+}
+
+
+void KRB5_CALLCONV
+krb5_free_tgt_creds(krb5_context context, krb5_creds **tgts)
+{
+    register krb5_creds **tgtpp;
+    for (tgtpp = tgts; *tgtpp; tgtpp++)
+	krb5_free_creds(context, *tgtpp);
+    krb5_xfree(tgts);
+}
+
+void KRB5_CALLCONV
+krb5_free_tkt_authent(krb5_context context, krb5_tkt_authent *val)
+{
+    if (val->ticket)
+	    krb5_free_ticket(context, val->ticket);
+    if (val->authenticator)
+	    krb5_free_authenticator(context, val->authenticator);
+    krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_unparsed_name(krb5_context context, char *val)
+{
+    if (val)
+	krb5_xfree(val);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_challenge(krb5_context ctx, krb5_sam_challenge *sc)
+{
+    if (!sc)
+	return;
+    krb5_free_sam_challenge_contents(ctx, sc);
+    krb5_xfree(sc);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_challenge_2(krb5_context ctx, krb5_sam_challenge_2 *sc2)
+{
+    if (!sc2)
+	return;
+    krb5_free_sam_challenge_2_contents(ctx, sc2);
+    krb5_xfree(sc2);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_challenge_contents(krb5_context ctx, krb5_sam_challenge *sc)
+{
+    if (!sc)
+	return;
+    if (sc->sam_type_name.data)
+	krb5_free_data_contents(ctx, &sc->sam_type_name);
+    if (sc->sam_track_id.data)
+	krb5_free_data_contents(ctx, &sc->sam_track_id);
+    if (sc->sam_challenge_label.data)
+	krb5_free_data_contents(ctx, &sc->sam_challenge_label);
+    if (sc->sam_challenge.data)
+	krb5_free_data_contents(ctx, &sc->sam_challenge);
+    if (sc->sam_response_prompt.data)
+	krb5_free_data_contents(ctx, &sc->sam_response_prompt);
+    if (sc->sam_pk_for_sad.data)
+	krb5_free_data_contents(ctx, &sc->sam_pk_for_sad);
+    if (sc->sam_cksum.contents) {
+	krb5_xfree(sc->sam_cksum.contents);
+	sc->sam_cksum.contents = 0;
+    }
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_challenge_2_contents(krb5_context ctx,
+				   krb5_sam_challenge_2 *sc2)
+{
+    krb5_checksum **cksump;
+
+    if (!sc2)
+	return;
+    if (sc2->sam_challenge_2_body.data)
+	krb5_free_data_contents(ctx, &sc2->sam_challenge_2_body);
+    if (sc2->sam_cksum) {
+	cksump = sc2->sam_cksum;
+	while (*cksump) {
+	    krb5_free_checksum(ctx, *cksump);
+	    cksump++;
+	}
+	krb5_xfree(sc2->sam_cksum);
+	sc2->sam_cksum = 0;
+    }
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_challenge_2_body(krb5_context ctx,
+			       krb5_sam_challenge_2_body *sc2)
+{
+    if (!sc2)
+	return;
+    krb5_free_sam_challenge_2_body_contents(ctx, sc2);
+    krb5_xfree(sc2);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_challenge_2_body_contents(krb5_context ctx,
+					krb5_sam_challenge_2_body *sc2)
+{
+    if (!sc2)
+	return;
+    if (sc2->sam_type_name.data) 
+	krb5_free_data_contents(ctx, &sc2->sam_type_name);
+    if (sc2->sam_track_id.data)
+	krb5_free_data_contents(ctx, &sc2->sam_track_id);
+    if (sc2->sam_challenge_label.data)
+	krb5_free_data_contents(ctx, &sc2->sam_challenge_label);
+    if (sc2->sam_challenge.data)
+	krb5_free_data_contents(ctx, &sc2->sam_challenge);
+    if (sc2->sam_response_prompt.data)
+	krb5_free_data_contents(ctx, &sc2->sam_response_prompt);
+    if (sc2->sam_pk_for_sad.data)
+	krb5_free_data_contents(ctx, &sc2->sam_pk_for_sad);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_response(krb5_context ctx, krb5_sam_response *sr)
+{
+    if (!sr)
+	return;
+    krb5_free_sam_response_contents(ctx, sr);
+    krb5_xfree(sr);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_response_2(krb5_context ctx, krb5_sam_response_2 *sr2)
+{
+    if (!sr2)
+	return;
+    krb5_free_sam_response_2_contents(ctx, sr2);
+    krb5_xfree(sr2);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_response_contents(krb5_context ctx, krb5_sam_response *sr)
+{
+    if (!sr)
+	return;
+    if (sr->sam_track_id.data)
+	krb5_free_data_contents(ctx, &sr->sam_track_id);
+    if (sr->sam_enc_key.ciphertext.data)
+	krb5_free_data_contents(ctx, &sr->sam_enc_key.ciphertext);
+    if (sr->sam_enc_nonce_or_ts.ciphertext.data)
+	krb5_free_data_contents(ctx, &sr->sam_enc_nonce_or_ts.ciphertext);
+}
+
+void KRB5_CALLCONV
+krb5_free_sam_response_2_contents(krb5_context ctx, krb5_sam_response_2 *sr2)
+{
+    if (!sr2)
+	return;
+    if (sr2->sam_track_id.data)
+	krb5_free_data_contents(ctx, &sr2->sam_track_id);
+    if (sr2->sam_enc_nonce_or_sad.ciphertext.data)
+	krb5_free_data_contents(ctx, &sr2->sam_enc_nonce_or_sad.ciphertext);
+}
+
+void KRB5_CALLCONV
+krb5_free_predicted_sam_response(krb5_context ctx,
+				 krb5_predicted_sam_response *psr)
+{
+    if (!psr)
+	return;
+    krb5_free_predicted_sam_response_contents(ctx, psr);
+    krb5_xfree(psr);
+}
+
+void KRB5_CALLCONV
+krb5_free_predicted_sam_response_contents(krb5_context ctx,
+				 krb5_predicted_sam_response *psr)
+{
+    if (!psr)
+	return;
+    if (psr->sam_key.contents)
+	krb5_free_keyblock_contents(ctx, &psr->sam_key);
+    if (psr->client) {
+	krb5_free_principal(ctx, psr->client);
+	psr->client = 0;
+    }
+    if (psr->msd.data)
+	krb5_free_data_contents(ctx, &psr->msd);
+}
+
+void KRB5_CALLCONV
+krb5_free_enc_sam_response_enc(krb5_context ctx,
+			       krb5_enc_sam_response_enc *esre)
+{
+    if (!esre)
+	return;
+    krb5_free_enc_sam_response_enc_contents(ctx, esre);
+    krb5_xfree(esre);
+}
+
+void KRB5_CALLCONV 
+krb5_free_enc_sam_response_enc_2(krb5_context ctx,
+				 krb5_enc_sam_response_enc_2 *esre2)
+{
+    if (!esre2)
+	return;
+    krb5_free_enc_sam_response_enc_2_contents(ctx, esre2);
+    krb5_xfree(esre2);
+}
+
+void KRB5_CALLCONV
+krb5_free_enc_sam_response_enc_contents(krb5_context ctx,
+			       krb5_enc_sam_response_enc *esre)
+{
+    if (!esre)
+	return;
+    if (esre->sam_sad.data)
+	krb5_free_data_contents(ctx, &esre->sam_sad);
+}
+
+void KRB5_CALLCONV
+krb5_free_enc_sam_response_enc_2_contents(krb5_context ctx,
+					  krb5_enc_sam_response_enc_2 *esre2)
+{
+    if (!esre2)
+	return;
+    if (esre2->sam_sad.data)
+	krb5_free_data_contents(ctx, &esre2->sam_sad);
+}
+
+void KRB5_CALLCONV
+krb5_free_pa_enc_ts(krb5_context ctx, krb5_pa_enc_ts *pa_enc_ts)
+{
+    if (!pa_enc_ts)
+	return;
+    krb5_xfree(pa_enc_ts);
+}
diff --git a/mechglue/src/lib/krb5/krb/mk_cred.c b/mechglue/src/lib/krb5/krb/mk_cred.c
new file mode 100644
index 000000000..04248c08d
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/mk_cred.c
@@ -0,0 +1,307 @@
+/* 
+ * NAME
+ *    cred.c
+ * 
+ * DESCRIPTION
+ *    Provide an interface to assemble and disassemble krb5_cred
+ *    structures.
+ *
+ */
+#include "k5-int.h"
+#include "cleanup.h"
+#include "auth_con.h"
+
+#include <stddef.h>           /* NULL */
+#include <stdlib.h>           /* malloc */
+#include <errno.h>            /* ENOMEM */
+
+/*-------------------- encrypt_credencpart --------------------*/
+
+/*
+ * encrypt the enc_part of krb5_cred
+ */
+static krb5_error_code 
+encrypt_credencpart(krb5_context context, krb5_cred_enc_part *pcredpart, krb5_keyblock *pkeyblock, krb5_enc_data *pencdata)
+{
+    krb5_error_code 	  retval;
+    krb5_data 		* scratch;
+
+    /* start by encoding to-be-encrypted part of the message */
+    if ((retval = encode_krb5_enc_cred_part(pcredpart, &scratch)))
+    	return retval;
+
+    /*
+     * If the keyblock is NULL, just copy the data from the encoded
+     * data to the ciphertext area.
+     */
+    if (pkeyblock == NULL) {
+	    pencdata->ciphertext.data = scratch->data;
+	    pencdata->ciphertext.length = scratch->length;
+	    krb5_xfree(scratch);
+	    return 0;
+    }
+
+    /* call the encryption routine */
+    retval = krb5_encrypt_helper(context, pkeyblock,
+				 KRB5_KEYUSAGE_KRB_CRED_ENCPART,
+				 scratch, pencdata);
+
+    if (retval) {
+    	memset(pencdata->ciphertext.data, 0, pencdata->ciphertext.length);
+        free(pencdata->ciphertext.data);
+        pencdata->ciphertext.length = 0;
+        pencdata->ciphertext.data = 0;
+    }
+
+    memset(scratch->data, 0, scratch->length); 
+    krb5_free_data(context, scratch);
+
+    return retval;
+}
+
+/*----------------------- krb5_mk_ncred_basic -----------------------*/
+
+static krb5_error_code
+krb5_mk_ncred_basic(krb5_context context, krb5_creds **ppcreds, krb5_int32 nppcreds, krb5_keyblock *keyblock, krb5_replay_data *replaydata, krb5_address *local_addr, krb5_address *remote_addr, krb5_cred *pcred)
+{
+    krb5_cred_enc_part 	  credenc;
+    krb5_error_code	  retval;
+    size_t		  size;
+    int			  i;
+
+    credenc.magic = KV5M_CRED_ENC_PART;
+
+    credenc.s_address = 0;
+    credenc.r_address = 0;
+    if (local_addr) krb5_copy_addr(context, local_addr, &credenc.s_address);
+    if (remote_addr) krb5_copy_addr(context, remote_addr, &credenc.r_address);
+
+    credenc.nonce = replaydata->seq;
+    credenc.usec = replaydata->usec;
+    credenc.timestamp = replaydata->timestamp;
+
+    /* Get memory for creds and initialize it */
+    size = sizeof(krb5_cred_info *) * (nppcreds + 1);
+    credenc.ticket_info = (krb5_cred_info **) malloc(size);
+    if (credenc.ticket_info == NULL)
+	return ENOMEM;
+    memset(credenc.ticket_info, 0, size);
+    
+    /*
+     * For each credential in the list, initialize a cred info
+     * structure and copy the ticket into the ticket list.
+     */
+    for (i = 0; i < nppcreds; i++) {
+    	credenc.ticket_info[i] = malloc(sizeof(krb5_cred_info));
+	if (credenc.ticket_info[i] == NULL) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+	credenc.ticket_info[i+1] = NULL;
+	
+        credenc.ticket_info[i]->magic = KV5M_CRED_INFO;
+        credenc.ticket_info[i]->times = ppcreds[i]->times;
+        credenc.ticket_info[i]->flags = ppcreds[i]->ticket_flags;
+
+    	if ((retval = decode_krb5_ticket(&ppcreds[i]->ticket, 
+					 &pcred->tickets[i])))
+	    goto cleanup;
+
+	if ((retval = krb5_copy_keyblock(context, &ppcreds[i]->keyblock,
+					 &credenc.ticket_info[i]->session)))
+            goto cleanup;
+
+        if ((retval = krb5_copy_principal(context, ppcreds[i]->client,
+					  &credenc.ticket_info[i]->client)))
+            goto cleanup;
+
+      	if ((retval = krb5_copy_principal(context, ppcreds[i]->server,
+					  &credenc.ticket_info[i]->server)))
+            goto cleanup;
+
+      	if ((retval = krb5_copy_addresses(context, ppcreds[i]->addresses,
+					  &credenc.ticket_info[i]->caddrs)))
+            goto cleanup;
+    }
+
+    /*
+     * NULL terminate the lists.
+     */
+    pcred->tickets[i] = NULL;
+
+    /* encrypt the credential encrypted part */
+    retval = encrypt_credencpart(context, &credenc, keyblock,
+				 &pcred->enc_part);
+
+cleanup:
+    krb5_free_cred_enc_part(context, &credenc);
+    return retval;
+}
+
+/*----------------------- krb5_mk_ncred -----------------------*/
+
+/*
+ * This functions takes as input an array of krb5_credentials, and
+ * outputs an encoded KRB_CRED message suitable for krb5_rd_cred
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mk_ncred(krb5_context context, krb5_auth_context auth_context, krb5_creds **ppcreds, krb5_data **ppdata, krb5_replay_data *outdata)
+{
+    krb5_address * premote_fulladdr = NULL;
+    krb5_address * plocal_fulladdr = NULL;
+    krb5_address remote_fulladdr;
+    krb5_address local_fulladdr;
+    krb5_error_code 	retval;
+    krb5_keyblock	 * keyblock;
+    krb5_replay_data    replaydata;
+    krb5_cred 		 * pcred;
+    krb5_int32		ncred;
+
+    local_fulladdr.contents = 0;
+    remote_fulladdr.contents = 0;
+    memset(&replaydata, 0, sizeof(krb5_replay_data));
+
+    if (ppcreds == NULL) {
+    	return KRB5KRB_AP_ERR_BADADDR;
+    }
+
+    /*
+     * Allocate memory for a NULL terminated list of tickets.
+     */
+    for (ncred = 0; ppcreds[ncred]; ncred++);
+
+    if ((pcred = (krb5_cred *)malloc(sizeof(krb5_cred))) == NULL) 
+        return ENOMEM;
+    memset(pcred, 0, sizeof(krb5_cred));
+
+    if ((pcred->tickets 
+      = (krb5_ticket **)malloc(sizeof(krb5_ticket *) * (ncred + 1))) == NULL) {
+	retval = ENOMEM;
+	free(pcred);
+    }
+    memset(pcred->tickets, 0, sizeof(krb5_ticket *) * (ncred +1));
+
+    /* Get keyblock */
+    if ((keyblock = auth_context->send_subkey) == NULL) 
+	keyblock = auth_context->keyblock;
+
+    /* Get replay info */
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
+      (auth_context->rcache == NULL))
+        return KRB5_RC_REQUIRED;
+
+    if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+      (outdata == NULL))
+        /* Need a better error */
+        return KRB5_RC_REQUIRED;
+
+    if ((retval = krb5_us_timeofday(context, &replaydata.timestamp,
+				    &replaydata.usec)))
+	return retval;
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) {
+	outdata->timestamp = replaydata.timestamp;
+	outdata->usec = replaydata.usec;
+    }
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
+        (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
+        replaydata.seq = auth_context->local_seq_number;
+        if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+            auth_context->local_seq_number++;
+        } else {
+            outdata->seq = replaydata.seq;
+        }
+    }
+
+    if (auth_context->local_addr) {
+    	if (auth_context->local_port) {
+            if ((retval = krb5_make_fulladdr(context, auth_context->local_addr,
+					     auth_context->local_port, 
+					     &local_fulladdr)))
+		goto error;
+	    plocal_fulladdr = &local_fulladdr;
+	} else {
+            plocal_fulladdr = auth_context->local_addr;
+        }
+    }
+
+    if (auth_context->remote_addr) {
+    	if (auth_context->remote_port) {
+            if ((retval = krb5_make_fulladdr(context,auth_context->remote_addr,
+                                 	      auth_context->remote_port, 
+					      &remote_fulladdr)))
+		goto error;
+	    premote_fulladdr = &remote_fulladdr;
+	} else {
+            premote_fulladdr = auth_context->remote_addr;
+        }
+    }
+
+    /* Setup creds structure */
+    if ((retval = krb5_mk_ncred_basic(context, ppcreds, ncred, keyblock,
+				      &replaydata, plocal_fulladdr, 
+				      premote_fulladdr, pcred))) {
+	goto error;
+    }
+
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+        krb5_donot_replay replay;
+
+        if ((retval = krb5_gen_replay_name(context, auth_context->local_addr,
+					   "_forw", &replay.client)))
+            goto error;
+
+        replay.server = "";             /* XXX */
+        replay.cusec = replaydata.usec;
+        replay.ctime = replaydata.timestamp;
+        if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
+            /* should we really error out here? XXX */
+            krb5_xfree(replay.client);
+            goto error;
+        }
+        krb5_xfree(replay.client);
+    }
+
+    /* Encode creds structure */
+    retval = encode_krb5_cred(pcred, ppdata);
+
+error:
+    if (local_fulladdr.contents)
+	free(local_fulladdr.contents);
+    if (remote_fulladdr.contents)
+	free(remote_fulladdr.contents);
+    krb5_free_cred(context, pcred);
+
+    if (retval) {
+	if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) 
+	 || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
+            auth_context->local_seq_number--;
+    }
+    return retval;
+}
+
+/*----------------------- krb5_mk_1cred -----------------------*/
+
+/*
+ * A convenience function that calls krb5_mk_ncred.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mk_1cred(krb5_context context, krb5_auth_context auth_context, krb5_creds *pcreds, krb5_data **ppdata, krb5_replay_data *outdata)
+{
+    krb5_error_code retval;
+    krb5_creds **ppcreds;
+
+    if ((ppcreds = (krb5_creds **)malloc(sizeof(*ppcreds) * 2)) == NULL) {
+	return ENOMEM;
+    }
+
+    ppcreds[0] = pcreds;
+    ppcreds[1] = NULL;
+
+    retval = krb5_mk_ncred(context, auth_context, ppcreds,
+			   ppdata, outdata);
+    
+    free(ppcreds);
+    return retval;
+}
+
diff --git a/mechglue/src/lib/krb5/krb/mk_error.c b/mechglue/src/lib/krb5/krb/mk_error.c
new file mode 100644
index 000000000..0444a5d17
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/mk_error.c
@@ -0,0 +1,51 @@
+/*
+ * lib/krb5/krb/mk_error.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_mk_error() routine.
+ */
+
+#include "k5-int.h"
+
+/*
+ formats the error structure *dec_err into an error buffer *enc_err.
+
+ The error buffer storage is allocated, and should be freed by the
+ caller when finished.
+
+ returns system errors
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_mk_error(krb5_context context, const krb5_error *dec_err, krb5_data *enc_err)
+{
+    krb5_error_code retval;
+    krb5_data *new_enc_err;
+
+    if ((retval = encode_krb5_error(dec_err, &new_enc_err)))
+	return(retval);
+    *enc_err = *new_enc_err;
+    krb5_xfree(new_enc_err);
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/mk_priv.c b/mechglue/src/lib/krb5/krb/mk_priv.c
new file mode 100644
index 000000000..efe254ac0
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/mk_priv.c
@@ -0,0 +1,233 @@
+/*
+ * lib/krb5/krb/mk_priv.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_mk_priv()
+ */
+
+#include "k5-int.h"
+#include "cleanup.h"
+#include "auth_con.h"
+
+static krb5_error_code
+krb5_mk_priv_basic(krb5_context context, const krb5_data *userdata, const krb5_keyblock *keyblock, krb5_replay_data *replaydata, krb5_address *local_addr, krb5_address *remote_addr, krb5_pointer i_vector, krb5_data *outbuf)
+{
+    krb5_error_code 	retval;
+    krb5_priv 		privmsg;
+    krb5_priv_enc_part 	privmsg_enc_part;
+    krb5_data 		*scratch1, *scratch2, ivdata;
+    size_t		blocksize, enclen;
+
+    privmsg.enc_part.kvno = 0;	/* XXX allow user-set? */
+    privmsg.enc_part.enctype = keyblock->enctype; 
+
+    privmsg_enc_part.user_data = *userdata;
+    privmsg_enc_part.s_address = local_addr;
+    privmsg_enc_part.r_address = remote_addr;
+
+    /* We should check too make sure one exists. */
+    privmsg_enc_part.timestamp  = replaydata->timestamp;
+    privmsg_enc_part.usec 	= replaydata->usec;
+    privmsg_enc_part.seq_number = replaydata->seq;
+
+    /* start by encoding to-be-encrypted part of the message */
+    if ((retval = encode_krb5_enc_priv_part(&privmsg_enc_part, &scratch1)))
+	return retval;
+
+    /* put together an eblock for this encryption */
+    if ((retval = krb5_c_encrypt_length(context, keyblock->enctype,
+					scratch1->length, &enclen)))
+	goto clean_scratch;
+
+    privmsg.enc_part.ciphertext.length = enclen;
+    if (!(privmsg.enc_part.ciphertext.data =
+	  malloc(privmsg.enc_part.ciphertext.length))) {
+        retval = ENOMEM;
+        goto clean_scratch;
+    }
+
+    /* call the encryption routine */
+    if (i_vector) {
+	if ((retval = krb5_c_block_size(context, keyblock->enctype,
+					&blocksize)))
+	    goto clean_encpart;
+
+	ivdata.length = blocksize;
+	ivdata.data = i_vector;
+    }
+
+    if ((retval = krb5_c_encrypt(context, keyblock,
+				 KRB5_KEYUSAGE_KRB_PRIV_ENCPART,
+				 i_vector?&ivdata:0,
+				 scratch1, &privmsg.enc_part)))
+	goto clean_encpart;
+
+    if ((retval = encode_krb5_priv(&privmsg, &scratch2)))
+        goto clean_encpart;
+
+    *outbuf = *scratch2;
+    krb5_xfree(scratch2);
+    retval = 0;
+
+clean_encpart:
+    memset(privmsg.enc_part.ciphertext.data, 0, 
+	   privmsg.enc_part.ciphertext.length); 
+    free(privmsg.enc_part.ciphertext.data); 
+    privmsg.enc_part.ciphertext.length = 0;
+    privmsg.enc_part.ciphertext.data = 0;
+
+clean_scratch:
+    memset(scratch1->data, 0, scratch1->length);
+    krb5_free_data(context, scratch1); 
+
+    return retval;
+}
+
+
+krb5_error_code KRB5_CALLCONV
+krb5_mk_priv(krb5_context context, krb5_auth_context auth_context,
+	     const krb5_data *userdata, krb5_data *outbuf,
+	     krb5_replay_data *outdata)
+{
+    krb5_error_code 	  retval;
+    krb5_keyblock       * keyblock;
+    krb5_replay_data      replaydata;
+
+    /* Clear replaydata block */
+    memset((char *) &replaydata, 0, sizeof(krb5_replay_data));
+
+    /* Get keyblock */
+    if ((keyblock = auth_context->send_subkey) == NULL)
+	keyblock = auth_context->keyblock;
+
+    /* Get replay info */
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
+      (auth_context->rcache == NULL))
+	return KRB5_RC_REQUIRED;
+
+    if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+      (outdata == NULL))
+	/* Need a better error */
+	return KRB5_RC_REQUIRED;
+
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) ||
+	(auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) {
+	if ((retval = krb5_us_timeofday(context, &replaydata.timestamp,
+					&replaydata.usec)))
+	    return retval;
+	if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) {
+    	    outdata->timestamp = replaydata.timestamp;
+    	    outdata->usec = replaydata.usec;
+	}
+    }
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
+	(auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
+	replaydata.seq = auth_context->local_seq_number;
+	if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+	    auth_context->local_seq_number++;
+	} else {
+    	    outdata->seq = replaydata.seq;
+	}
+    } 
+
+{
+    krb5_address * premote_fulladdr = NULL;
+    krb5_address * plocal_fulladdr = NULL;
+    krb5_address remote_fulladdr;
+    krb5_address local_fulladdr;
+    CLEANUP_INIT(2);
+
+    if (auth_context->local_addr) {
+	if (auth_context->local_port) {
+	    if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr,
+				  	      auth_context->local_port, 
+					      &local_fulladdr))) {
+	    	CLEANUP_PUSH(local_fulladdr.contents, free);
+	    	plocal_fulladdr = &local_fulladdr;
+            } else {
+    	    	goto error;
+            }
+	} else {
+	    plocal_fulladdr = auth_context->local_addr;
+	}
+    }
+
+    if (auth_context->remote_addr) {
+    	if (auth_context->remote_port) {
+	    if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr,
+				 	      auth_context->remote_port, 
+					      &remote_fulladdr))){
+	    	CLEANUP_PUSH(remote_fulladdr.contents, free);
+	    	premote_fulladdr = &remote_fulladdr;
+ 	    } else {
+	        CLEANUP_DONE();
+	        goto error;
+	    }
+	} else {
+	    premote_fulladdr = auth_context->remote_addr;
+	}
+    }
+
+    if ((retval = krb5_mk_priv_basic(context, userdata, keyblock, &replaydata, 
+				     plocal_fulladdr, premote_fulladdr,
+				     auth_context->i_vector, outbuf))) {
+	CLEANUP_DONE();
+	goto error;
+    }
+
+    CLEANUP_DONE();
+}
+
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+	krb5_donot_replay replay;
+
+	if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, 
+					   "_priv", &replay.client))) {
+    	    krb5_xfree(outbuf);
+	    goto error;
+	}
+
+	replay.server = "";		/* XXX */
+	replay.cusec = replaydata.usec;
+	replay.ctime = replaydata.timestamp;
+	if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
+	    /* should we really error out here? XXX */
+    	    krb5_xfree(replay.client);
+	    goto error;
+	}
+	krb5_xfree(replay.client);
+    }
+
+    return 0;
+
+error:
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
+	auth_context->local_seq_number--;
+
+    return retval;
+}
+
diff --git a/mechglue/src/lib/krb5/krb/mk_rep.c b/mechglue/src/lib/krb5/krb/mk_rep.c
new file mode 100644
index 000000000..393f634bb
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/mk_rep.c
@@ -0,0 +1,96 @@
+/*
+ * lib/krb5/krb/mk_rep.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_mk_rep()
+ */
+
+#include "k5-int.h"
+#include "auth_con.h"
+
+/*
+ Formats a KRB_AP_REP message into outbuf.
+
+ The outbuf buffer storage is allocated, and should be freed by the
+ caller when finished.
+
+ returns system errors
+*/
+
+krb5_error_code KRB5_CALLCONV
+krb5_mk_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *outbuf)
+{
+    krb5_error_code 	  retval;
+    krb5_ap_rep_enc_part  repl;
+    krb5_ap_rep 	  reply;
+    krb5_data 		* scratch;
+    krb5_data 		* toutbuf;
+
+    /* Make the reply */
+    if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
+	(auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+	(auth_context->local_seq_number == 0)) {
+	if ((retval = krb5_generate_seq_number(context, auth_context->keyblock,
+					       &auth_context->local_seq_number)))
+            return(retval);
+    }
+
+    repl.ctime = auth_context->authentp->ctime;    
+    repl.cusec = auth_context->authentp->cusec;    
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_USE_SUBKEY) {
+	retval = krb5int_generate_and_save_subkey (context, auth_context,
+						   auth_context->keyblock);
+	if (retval)
+	    return retval;
+	repl.subkey = auth_context->send_subkey;
+    } else
+	repl.subkey = auth_context->authentp->subkey;
+    repl.seq_number = auth_context->local_seq_number;
+
+    /* encode it before encrypting */
+    if ((retval = encode_krb5_ap_rep_enc_part(&repl, &scratch)))
+	return retval;
+
+    if ((retval = krb5_encrypt_helper(context, auth_context->keyblock,
+				      KRB5_KEYUSAGE_AP_REP_ENCPART,
+				      scratch, &reply.enc_part)))
+	goto cleanup_scratch;
+
+    if (!(retval = encode_krb5_ap_rep(&reply, &toutbuf))) {
+	*outbuf = *toutbuf;
+	krb5_xfree(toutbuf);
+    }
+
+    memset(reply.enc_part.ciphertext.data, 0, reply.enc_part.ciphertext.length);
+    free(reply.enc_part.ciphertext.data); 
+    reply.enc_part.ciphertext.length = 0; 
+    reply.enc_part.ciphertext.data = 0;
+
+cleanup_scratch:
+    memset(scratch->data, 0, scratch->length); 
+    krb5_free_data(context, scratch);
+
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/mk_req.c b/mechglue/src/lib/krb5/krb/mk_req.c
new file mode 100644
index 000000000..2935e41b3
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/mk_req.c
@@ -0,0 +1,91 @@
+/*
+ * lib/krb5/krb/mk_req.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_mk_req() routine.
+ */
+
+#include "k5-int.h"
+#include "auth_con.h"
+
+/*
+ Formats a KRB_AP_REQ message into outbuf.
+
+ server specifies the principal of the server to receive the message; if
+ credentials are not present in the credentials cache for this server, the
+ TGS request with default parameters is used in an attempt to obtain
+ such credentials, and they are stored in ccache.
+
+ kdc_options specifies the options requested for the 
+ ap_req_options specifies the KRB_AP_REQ options desired.
+
+ checksum specifies the checksum to be used in the authenticator.
+
+ The outbuf buffer storage is allocated, and should be freed by the
+ caller when finished.
+
+ returns system errors
+*/
+
+krb5_error_code KRB5_CALLCONV
+krb5_mk_req(krb5_context context, krb5_auth_context *auth_context,
+	    krb5_flags ap_req_options, char *service, char *hostname,
+	    krb5_data *in_data, krb5_ccache ccache, krb5_data *outbuf)
+{
+    krb5_error_code 	  retval;
+    krb5_principal	  server;
+    krb5_creds 		* credsp;
+    krb5_creds 		  creds;
+
+    retval = krb5_sname_to_principal(context, hostname, service, 
+				     KRB5_NT_SRV_HST, &server);
+    if (retval)
+      return retval;
+
+    /* obtain ticket & session key */
+    memset((char *)&creds, 0, sizeof(creds));
+    if ((retval = krb5_copy_principal(context, server, &creds.server)))
+	goto cleanup_princ;
+
+    if ((retval = krb5_cc_get_principal(context, ccache, &creds.client)))
+	goto cleanup_creds;
+
+    if ((retval = krb5_get_credentials(context, 0,
+				       ccache, &creds, &credsp)))
+	goto cleanup_creds;
+
+    retval = krb5_mk_req_extended(context, auth_context, ap_req_options, 
+				  in_data, credsp, outbuf);
+
+    krb5_free_creds(context, credsp);
+
+cleanup_creds:
+    krb5_free_cred_contents(context, &creds);
+
+cleanup_princ:
+    krb5_free_principal(context, server);
+
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/mk_req_ext.c b/mechglue/src/lib/krb5/krb/mk_req_ext.c
new file mode 100644
index 000000000..9066567ba
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/mk_req_ext.c
@@ -0,0 +1,281 @@
+/*
+ * lib/krb5/krb/mk_req_ext.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_mk_req_extended()
+ */
+
+
+#include "k5-int.h"
+#include "auth_con.h"
+
+/*
+ Formats a KRB_AP_REQ message into outbuf, with more complete options than
+ krb_mk_req.
+
+ outbuf, ap_req_options, checksum, and ccache are used in the
+ same fashion as for krb5_mk_req.
+
+ creds is used to supply the credentials (ticket and session key) needed
+ to form the request.
+
+ if creds->ticket has no data (length == 0), then a ticket is obtained
+ from either the cache or the TGS, passing creds to krb5_get_credentials().
+ kdc_options specifies the options requested for the ticket to be used.
+ If a ticket with appropriate flags is not found in the cache, then these
+ options are passed on in a request to an appropriate KDC.
+
+ ap_req_options specifies the KRB_AP_REQ options desired.
+
+ if ap_req_options specifies AP_OPTS_USE_SESSION_KEY, then creds->ticket
+ must contain the appropriate ENC-TKT-IN-SKEY ticket.
+
+ checksum specifies the checksum to be used in the authenticator.
+
+ The outbuf buffer storage is allocated, and should be freed by the
+ caller when finished.
+
+ On an error return, the credentials pointed to by creds might have been
+ augmented with additional fields from the obtained credentials; the entire
+ credentials should be released by calling krb5_free_creds().
+
+ returns system errors
+*/
+
+static krb5_error_code 
+krb5_generate_authenticator (krb5_context,
+				       krb5_authenticator *, krb5_principal,
+				       krb5_checksum *, krb5_keyblock *,
+				       krb5_ui_4, krb5_authdata ** );
+
+krb5_error_code
+krb5int_generate_and_save_subkey (krb5_context context,
+				  krb5_auth_context auth_context,
+				  krb5_keyblock *keyblock)
+{
+    /* Provide some more fodder for random number code.
+       This isn't strong cryptographically; the point here is not
+       to guarantee randomness, but to make it less likely that multiple
+       sessions could pick the same subkey.  */
+    struct {
+	krb5_int32 sec, usec;
+    } rnd_data;
+    krb5_data d;
+    krb5_error_code retval;
+
+    krb5_crypto_us_timeofday (&rnd_data.sec, &rnd_data.usec);
+    d.length = sizeof (rnd_data);
+    d.data = (char *) &rnd_data;
+    (void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_TIMING, &d);
+
+    if (auth_context->send_subkey)
+	krb5_free_keyblock(context, auth_context->send_subkey);
+    if ((retval = krb5_generate_subkey(context, keyblock, &auth_context->send_subkey)))
+	return retval;
+
+    if (auth_context->recv_subkey)
+	krb5_free_keyblock(context, auth_context->recv_subkey);
+    retval = krb5_copy_keyblock(context, auth_context->send_subkey,
+				&auth_context->recv_subkey);
+    if (retval) {
+	krb5_free_keyblock(context, auth_context->send_subkey);
+	auth_context->send_subkey = NULL;
+	return retval;
+    }
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context,
+		     krb5_flags ap_req_options, krb5_data *in_data,
+		     krb5_creds *in_creds, krb5_data *outbuf)
+{
+    krb5_error_code 	  retval;
+    krb5_checksum	  checksum;
+    krb5_checksum	  *checksump = 0;
+    krb5_auth_context	  new_auth_context;
+
+    krb5_ap_req request;
+    krb5_data *scratch = 0;
+    krb5_data *toutbuf;
+
+    request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
+    request.authenticator.ciphertext.data = 0;
+    request.ticket = 0;
+    
+    if (!in_creds->ticket.length) 
+	return(KRB5_NO_TKT_SUPPLIED);
+
+    /* we need a native ticket */
+    if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
+	return(retval);
+    
+    /* verify that the ticket is not expired */
+    if ((retval = krb5_validate_times(context, &in_creds->times)) != 0)
+	goto cleanup;
+
+    /* generate auth_context if needed */
+    if (*auth_context == NULL) {
+	if ((retval = krb5_auth_con_init(context, &new_auth_context)))
+	    goto cleanup;
+	*auth_context = new_auth_context;
+    }
+
+    if ((*auth_context)->keyblock != NULL) {
+	krb5_free_keyblock(context, (*auth_context)->keyblock);
+	(*auth_context)->keyblock = NULL;
+    }
+
+    /* set auth context keyblock */
+    if ((retval = krb5_copy_keyblock(context, &in_creds->keyblock, 
+				     &((*auth_context)->keyblock))))
+	goto cleanup;
+
+    /* generate seq number if needed */
+    if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
+     || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
+      && ((*auth_context)->local_seq_number == 0)) 
+	if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock,
+				     &(*auth_context)->local_seq_number)))
+	    goto cleanup;
+	
+
+    /* generate subkey if needed */
+    if (!in_data &&(*auth_context)->checksum_func) {
+	retval = (*auth_context)->checksum_func( context,
+						 *auth_context,
+						 (*auth_context)->checksum_func_data,
+						 &in_data);
+	if (retval)
+	    goto cleanup;
+    }
+
+    if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->send_subkey)) {
+	retval = krb5int_generate_and_save_subkey (context, *auth_context,
+						   &in_creds->keyblock);
+	if (retval)
+	    goto cleanup;
+    }
+
+
+    if (in_data) {
+
+      if ((*auth_context)->req_cksumtype == 0x8003) {
+	    /* XXX Special hack for GSSAPI */
+	    checksum.checksum_type = 0x8003;
+	    checksum.length = in_data->length;
+	    checksum.contents = (krb5_octet *) in_data->data;
+	} else {
+	    if ((retval = krb5_c_make_checksum(context, 
+					       (*auth_context)->req_cksumtype,
+					       (*auth_context)->keyblock,
+					       KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
+					       in_data, &checksum)))
+		goto cleanup_cksum;
+	}
+	checksump = &checksum;
+    }
+
+    /* Generate authenticator */
+    if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
+					krb5_authenticator))) == NULL) {
+	retval = ENOMEM;
+	goto cleanup_cksum;
+    }
+
+    if ((retval = krb5_generate_authenticator(context,
+					      (*auth_context)->authentp,
+					      (in_creds)->client, checksump,
+					      (*auth_context)->send_subkey,
+					      (*auth_context)->local_seq_number,
+					      (in_creds)->authdata)))
+	goto cleanup_cksum;
+	
+    /* encode the authenticator */
+    if ((retval = encode_krb5_authenticator((*auth_context)->authentp,
+					    &scratch)))
+	goto cleanup_cksum;
+    
+    /* Null out these fields, to prevent pointer sharing problems;
+     * they were supplied by the caller
+     */
+    (*auth_context)->authentp->client = NULL;
+    (*auth_context)->authentp->checksum = NULL;
+    (*auth_context)->authentp->authorization_data = NULL;
+
+    /* call the encryption routine */
+    if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
+				      KRB5_KEYUSAGE_AP_REQ_AUTH,
+				      scratch, &request.authenticator)))
+	goto cleanup_cksum;
+
+    if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
+	goto cleanup_cksum;
+#ifdef HAVE_C_STRUCTURE_ASSIGNMENT
+    *outbuf = *toutbuf;
+#else
+    memcpy(outbuf, toutbuf, sizeof(krb5_data));
+#endif
+
+    krb5_xfree(toutbuf);
+
+cleanup_cksum:
+    if (checksump && checksump->checksum_type != 0x8003)
+      free(checksump->contents);
+
+cleanup:
+    if (request.ticket)
+	krb5_free_ticket(context, request.ticket);
+    if (request.authenticator.ciphertext.data) {
+    	(void) memset(request.authenticator.ciphertext.data, 0,
+		      request.authenticator.ciphertext.length);
+	free(request.authenticator.ciphertext.data);
+    }
+    if (scratch) {
+	memset(scratch->data, 0, scratch->length);
+        krb5_xfree(scratch->data);
+	krb5_xfree(scratch);
+    }
+    return retval;
+}
+
+static krb5_error_code
+krb5_generate_authenticator(krb5_context context, krb5_authenticator *authent, krb5_principal client, krb5_checksum *cksum, krb5_keyblock *key, krb5_ui_4 seq_number, krb5_authdata **authorization)
+{
+    krb5_error_code retval;
+    
+    authent->client = client;
+    authent->checksum = cksum;
+    if (key) {
+	retval = krb5_copy_keyblock(context, key, &authent->subkey);
+	if (retval)
+	    return retval;
+    } else
+	authent->subkey = 0;
+    authent->seq_number = seq_number;
+    authent->authorization_data = authorization;
+
+    return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
+}
diff --git a/mechglue/src/lib/krb5/krb/mk_safe.c b/mechglue/src/lib/krb5/krb/mk_safe.c
new file mode 100644
index 000000000..eefcab7cd
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/mk_safe.c
@@ -0,0 +1,259 @@
+/*
+ * lib/krb5/krb/mk_safe.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_mk_safe()
+ */
+
+#include "k5-int.h"
+#include "cleanup.h"
+#include "auth_con.h"
+
+/*
+ Formats a KRB_SAFE message into outbuf.
+
+ userdata is formatted as the user data in the message.
+ sumtype specifies the encryption type; key specifies the key which
+ might be used to seed the checksum; sender_addr and recv_addr specify
+ the full addresses (host and port) of the sender and receiver.
+ The host portion of sender_addr is used to form the addresses used in the
+ KRB_SAFE message.
+
+ The outbuf buffer storage is allocated, and should be freed by the
+ caller when finished.
+
+ returns system errors
+*/
+static krb5_error_code
+krb5_mk_safe_basic(krb5_context context, const krb5_data *userdata,
+		   const krb5_keyblock *keyblock, krb5_replay_data *replaydata,
+		   krb5_address *local_addr, krb5_address *remote_addr,
+		   krb5_cksumtype sumtype, krb5_data *outbuf)
+{
+    krb5_error_code retval;
+    krb5_safe safemsg;
+    krb5_octet zero_octet = 0;
+    krb5_checksum safe_checksum;
+    krb5_data *scratch1, *scratch2;
+
+    if (!krb5_c_valid_cksumtype(sumtype))
+	return KRB5_PROG_SUMTYPE_NOSUPP;
+    if (!krb5_c_is_coll_proof_cksum(sumtype)
+	|| !krb5_c_is_keyed_cksum(sumtype))
+	return KRB5KRB_AP_ERR_INAPP_CKSUM;
+
+    safemsg.user_data = *userdata;
+    safemsg.s_address = (krb5_address *) local_addr;
+    safemsg.r_address = (krb5_address *) remote_addr;
+
+    /* We should check too make sure one exists. */
+    safemsg.timestamp  = replaydata->timestamp;
+    safemsg.usec       = replaydata->usec;
+    safemsg.seq_number = replaydata->seq;
+
+    /* 
+     * To do the checksum stuff, we need to encode the message with a
+     * zero-length zero-type checksum, then checksum the encoding, then
+     * re-encode with the checksum. 
+     */
+
+    safe_checksum.length = 0;
+    safe_checksum.checksum_type = 0;
+    safe_checksum.contents = &zero_octet;
+
+    safemsg.checksum = &safe_checksum;
+
+    if ((retval = encode_krb5_safe(&safemsg, &scratch1)))
+	return retval;
+
+    if ((retval = krb5_c_make_checksum(context, sumtype, keyblock,
+				       KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
+				       scratch1, &safe_checksum)))
+	goto cleanup_checksum;
+
+    safemsg.checksum = &safe_checksum;
+    if ((retval = encode_krb5_safe(&safemsg, &scratch2))) {
+	goto cleanup_checksum;
+    }
+    *outbuf = *scratch2;
+    krb5_xfree(scratch2);
+    retval = 0;
+
+cleanup_checksum:
+    krb5_xfree(safe_checksum.contents);
+
+    memset((char *)scratch1->data, 0, scratch1->length); 
+    krb5_free_data(context, scratch1);
+    return retval;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_mk_safe(krb5_context context, krb5_auth_context auth_context, const krb5_data *userdata, krb5_data *outbuf, krb5_replay_data *outdata)
+{
+    krb5_error_code 	  retval;
+    krb5_keyblock       * keyblock;
+    krb5_replay_data      replaydata;
+
+    /* Clear replaydata block */
+    memset((char *) &replaydata, 0, sizeof(krb5_replay_data));
+
+    /* Get keyblock */
+    if ((keyblock = auth_context->send_subkey) == NULL)
+	keyblock = auth_context->keyblock;
+
+    /* Get replay info */
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
+      (auth_context->rcache == NULL))
+	return KRB5_RC_REQUIRED;
+
+    if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+      (outdata == NULL))
+	/* Need a better error */
+	return KRB5_RC_REQUIRED;
+
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) ||
+	(auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) {
+	if ((retval = krb5_us_timeofday(context, &replaydata.timestamp,
+					&replaydata.usec)))
+	    return retval;
+	if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) {
+    	    outdata->timestamp = replaydata.timestamp;
+    	    outdata->usec = replaydata.usec;
+	}
+    }
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
+	(auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
+	replaydata.seq = auth_context->local_seq_number++;
+	if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE) {
+    	    outdata->seq = replaydata.seq;
+	}
+    } 
+
+{
+    krb5_address * premote_fulladdr = NULL;
+    krb5_address * plocal_fulladdr = NULL;
+    krb5_address remote_fulladdr;
+    krb5_address local_fulladdr;
+    krb5_cksumtype sumtype;
+
+    CLEANUP_INIT(2);
+
+    if (auth_context->local_addr) {
+    	if (auth_context->local_port) {
+            if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr,
+                                 	      auth_context->local_port, 
+					      &local_fulladdr))){
+            	CLEANUP_PUSH(local_fulladdr.contents, free);
+	    	plocal_fulladdr = &local_fulladdr;
+            } else {
+                goto error;
+            }
+	} else {
+            plocal_fulladdr = auth_context->local_addr;
+        }
+
+    }
+
+    if (auth_context->remote_addr) {
+    	if (auth_context->remote_port) {
+            if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr,
+                                 	      auth_context->remote_port, 
+					      &remote_fulladdr))){
+            	CLEANUP_PUSH(remote_fulladdr.contents, free);
+	    	premote_fulladdr = &remote_fulladdr;
+            } else {
+                CLEANUP_DONE();
+                goto error;
+            }
+	} else {
+            premote_fulladdr = auth_context->remote_addr;
+        }
+    }
+
+    {
+	unsigned int nsumtypes;
+	unsigned int i;
+	krb5_cksumtype *sumtypes;
+	retval = krb5_c_keyed_checksum_types (context, keyblock->enctype,
+					      &nsumtypes, &sumtypes);
+	if (retval) {
+	    CLEANUP_DONE ();
+	    goto error;
+	}
+	if (nsumtypes == 0) {
+		retval = KRB5_BAD_ENCTYPE;
+		krb5_free_cksumtypes (context, sumtypes);
+		CLEANUP_DONE ();
+		goto error;
+	}
+	for (i = 0; i < nsumtypes; i++)
+		if (auth_context->safe_cksumtype == sumtypes[i])
+			break;
+	if (i == nsumtypes)
+		i = 0;
+	sumtype = sumtypes[i];
+	krb5_free_cksumtypes (context, sumtypes);
+    }
+    if ((retval = krb5_mk_safe_basic(context, userdata, keyblock, &replaydata, 
+				     plocal_fulladdr, premote_fulladdr,
+				     sumtype, outbuf))) {
+	CLEANUP_DONE();
+	goto error;
+    }
+
+    CLEANUP_DONE();
+}
+
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+	krb5_donot_replay replay;
+
+	if ((retval = krb5_gen_replay_name(context, auth_context->local_addr, 
+					   "_safe", &replay.client))) {
+    	    krb5_xfree(outbuf);
+	    goto error;
+	}
+
+	replay.server = "";		/* XXX */
+	replay.cusec = replaydata.usec;
+	replay.ctime = replaydata.timestamp;
+	if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
+	    /* should we really error out here? XXX */
+    	    krb5_xfree(outbuf);
+	    goto error;
+	}
+	krb5_xfree(replay.client);
+    }
+
+    return 0;
+
+error:
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) 
+	auth_context->local_seq_number--;
+
+    return retval;
+}
+
diff --git a/mechglue/src/lib/krb5/krb/parse.c b/mechglue/src/lib/krb5/krb/parse.c
new file mode 100644
index 000000000..cd23d14d1
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/parse.c
@@ -0,0 +1,285 @@
+/*
+ * lib/krb5/krb/parse.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_parse_name() routine.
+ *
+ * Rewritten by Theodore Ts'o to properly handle arbitrary quoted
+ * characters in the principal name.
+ */
+
+#include "k5-int.h"
+
+/*
+ * converts a single-string representation of the name to the
+ * multi-part principal format used in the protocols.
+ *
+ * principal will point to allocated storage which should be freed by 
+ * the caller (using krb5_free_principal) after use.
+ * 
+ * Conventions:  / is used to separate components.  If @ is present in the
+ * string, then the rest of the string after it represents the realm name.
+ * Otherwise the local realm name is used.
+ * 
+ * error return:
+ *	KRB5_PARSE_MALFORMED	badly formatted string
+ *
+ * also returns system errors:
+ *	ENOMEM	malloc failed/out of memory
+ *
+ * get_default_realm() is called; it may return other errors.
+ */
+
+#define REALM_SEP	'@'
+#define	COMPONENT_SEP	'/'
+#define QUOTECHAR	'\\'
+
+#define FCOMPNUM	10
+
+
+/*
+ * May the fleas of a thousand camels infest the ISO, they who think
+ * that arbitrarily large multi-component names are a Good Thing.....
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_parse_name(krb5_context context, const char *name, krb5_principal *nprincipal)
+{
+	register const char	*cp;
+	register char	*q;
+	register int    i,c,size;
+	int		components = 0;
+	const char	*parsed_realm = NULL;
+	int		fcompsize[FCOMPNUM];
+	unsigned int	realmsize = 0;
+	char		*default_realm = NULL;
+	int		default_realm_size = 0;
+	char		*tmpdata;
+	krb5_principal	principal;
+	krb5_error_code retval;
+	
+	/*
+	 * Pass 1.  Find out how many components there are to the name,
+	 * and get string sizes for the first FCOMPNUM components.
+	 */
+	size = 0;
+	for (i=0,cp = name; (c = *cp); cp++) {
+		if (c == QUOTECHAR) {
+			cp++;
+			if (!(c = *cp))
+				/*
+				 * QUOTECHAR can't be at the last
+				 * character of the name!
+				 */
+				return(KRB5_PARSE_MALFORMED);
+			size++;
+			continue;
+		} else if (c == COMPONENT_SEP) {
+			if (parsed_realm)
+				/*
+				 * Shouldn't see a component separator
+				 * after we've parsed out the realm name!
+				 */
+				return(KRB5_PARSE_MALFORMED);
+			if (i < FCOMPNUM) {
+				fcompsize[i] = size;
+			}
+			size = 0;
+			i++;
+		} else if (c == REALM_SEP) {
+			if (parsed_realm || !*(cp+1)) 
+				/*
+				 * Multiple realm separaters or null
+				 * realm names are not allowed!
+				 */
+				return(KRB5_PARSE_MALFORMED);
+			parsed_realm = cp+1;
+			if (i < FCOMPNUM) {
+				fcompsize[i] = size;
+			}
+			size = 0;
+		} else
+			size++;
+	}
+	if (parsed_realm)
+		realmsize = size;
+	else if (i < FCOMPNUM) 
+		fcompsize[i] = size;
+	components = i + 1;
+	/*
+	 * Now, we allocate the principal structure and all of its
+	 * component pieces
+	 */
+	principal = (krb5_principal)malloc(sizeof(krb5_principal_data));
+	if (!principal) {
+		return(ENOMEM);
+	}
+	principal->data = (krb5_data *) malloc(sizeof(krb5_data) * components);
+	if (!principal->data) {
+	    free((char *)principal);
+	    return ENOMEM;
+	}
+	principal->length = components;
+	/*
+	 * If a realm was not found, then use the defualt realm....
+	 */
+	if (!parsed_realm) {
+	    if (!default_realm) {
+		retval = krb5_get_default_realm(context, &default_realm);
+		if (retval) {
+		    krb5_xfree(principal->data);
+		    krb5_xfree((char *)principal);
+		    return(retval);
+		}
+		default_realm_size = strlen(default_realm);
+	    }
+	    realmsize = default_realm_size;
+	}
+	/*
+	 * Pass 2.  Happens only if there were more than FCOMPNUM
+	 * component; if this happens, someone should be shot
+	 * immediately.  Nevertheless, we will attempt to handle said
+	 * case..... <martyred sigh>
+	 */
+	if (components >= FCOMPNUM) {
+		size = 0;
+		parsed_realm = NULL;
+		for (i=0,cp = name; (c = *cp); cp++) {
+			if (c == QUOTECHAR) {
+				cp++;
+				size++;
+			} else if (c == COMPONENT_SEP) {
+				if (krb5_princ_size(context, principal) > i)
+					krb5_princ_component(context, principal, i)->length = size;
+				size = 0;
+				i++;
+			} else if (c == REALM_SEP) {
+				if (krb5_princ_size(context, principal) > i)
+					krb5_princ_component(context, principal, i)->length = size;
+				size = 0;
+				parsed_realm = cp+1;
+			} else
+				size++;
+		}
+		if (parsed_realm)
+			krb5_princ_realm(context, principal)->length = size;
+		else
+			if (krb5_princ_size(context, principal) > i)
+				krb5_princ_component(context, principal, i)->length = size;
+		if (i + 1 != components) {
+#if !defined(_WIN32)
+		    fprintf(stderr,
+			    "Programming error in krb5_parse_name!");
+#endif
+		    assert(i + 1 == components);
+		    abort();
+		}
+	} else {
+		/*
+		 * If there were fewer than FCOMPSIZE components (the
+		 * usual case), then just copy the sizes to the
+		 * principal structure
+		 */
+		for (i=0; i < components; i++)
+			krb5_princ_component(context, principal, i)->length = fcompsize[i];
+	}
+	/*	
+	 * Now, we need to allocate the space for the strings themselves.....
+	 */
+	tmpdata = malloc(realmsize+1);
+	if (tmpdata == 0) {
+		krb5_xfree(principal->data);
+		krb5_xfree(principal);
+		krb5_xfree(default_realm);
+		return ENOMEM;
+	}
+	krb5_princ_set_realm_length(context, principal, realmsize);
+	krb5_princ_set_realm_data(context, principal, tmpdata);
+	for (i=0; i < components; i++) {
+		char *tmpdata2 =
+		  malloc(krb5_princ_component(context, principal, i)->length + 1);
+		if (!tmpdata2) {
+			for (i--; i >= 0; i--)
+				krb5_xfree(krb5_princ_component(context, principal, i)->data);
+			krb5_xfree(krb5_princ_realm(context, principal)->data);
+			krb5_xfree(principal->data);
+			krb5_xfree(principal);
+			krb5_xfree(default_realm);
+			return(ENOMEM);
+		}
+		krb5_princ_component(context, principal, i)->data = tmpdata2;
+		krb5_princ_component(context, principal, i)->magic = KV5M_DATA;
+	}
+	
+	/*
+	 * Pass 3.  Now we go through the string a *third* time, this
+	 * time filling in the krb5_principal structure which we just
+	 * allocated.
+	 */
+	q = krb5_princ_component(context, principal, 0)->data;
+	for (i=0,cp = name; (c = *cp); cp++) {
+		if (c == QUOTECHAR) {
+			cp++;
+			switch (c = *cp) {
+			case 'n':
+				*q++ = '\n';
+				break;
+			case 't':
+				*q++ = '\t';
+				break;
+			case 'b':
+				*q++ = '\b';
+				break;
+			case '0':
+				*q++ = '\0';
+				break;
+			default:
+				*q++ = c;
+			}
+		} else if ((c == COMPONENT_SEP) || (c == REALM_SEP)) {
+			i++;
+			*q++ = '\0';
+			if (c == COMPONENT_SEP) 
+				q = krb5_princ_component(context, principal, i)->data;
+			else
+				q = krb5_princ_realm(context, principal)->data;
+		} else
+			*q++ = c;
+	}
+	*q++ = '\0';
+	if (!parsed_realm)
+		strcpy(krb5_princ_realm(context, principal)->data, default_realm);
+	/*
+	 * Alright, we're done.  Now stuff a pointer to this monstrosity
+	 * into the return variable, and let's get out of here.
+	 */
+	krb5_princ_type(context, principal) = KRB5_NT_PRINCIPAL;
+	principal->magic = KV5M_PRINCIPAL;
+	principal->realm.magic = KV5M_DATA;
+	*nprincipal = principal;
+	krb5_xfree(default_realm);
+	return(0);
+}
+
+
diff --git a/mechglue/src/lib/krb5/krb/pr_to_salt.c b/mechglue/src/lib/krb5/krb/pr_to_salt.c
new file mode 100644
index 000000000..545d86fb1
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/pr_to_salt.c
@@ -0,0 +1,86 @@
+/*
+ * lib/krb5/krb/pr_to_salt.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_principal2salt()
+ */
+
+#include "k5-int.h"
+
+static krb5_error_code krb5_principal2salt_internal
+    (krb5_context, krb5_const_principal, krb5_data *ret, int);
+
+/*
+ * Convert a krb5_principal into the default salt for that principal.
+ */
+static krb5_error_code
+krb5_principal2salt_internal(krb5_context context, register krb5_const_principal pr, krb5_data *ret, int use_realm)
+{
+    unsigned int size = 0, offset=0;
+    krb5_int32 nelem;
+    register int i;
+
+    if (pr == 0) {
+	ret->length = 0;
+	ret->data = 0;
+	return 0;
+    }
+
+    nelem = krb5_princ_size(context, pr);
+
+    if (use_realm)
+	    size += krb5_princ_realm(context, pr)->length;
+
+    for (i = 0; i < (int) nelem; i++)
+	size += krb5_princ_component(context, pr, i)->length;
+
+    ret->length = size;
+    if (!(ret->data = malloc (size)))
+	return ENOMEM;
+
+    if (use_realm) {
+	    offset = krb5_princ_realm(context, pr)->length;
+	    memcpy(ret->data, krb5_princ_realm(context, pr)->data, offset);
+    }
+
+    for (i = 0; i < (int) nelem; i++) {
+	memcpy(&ret->data[offset], krb5_princ_component(context, pr, i)->data,
+	       krb5_princ_component(context, pr, i)->length);
+	offset += krb5_princ_component(context, pr, i)->length;
+    }
+    return 0;
+}
+
+krb5_error_code
+krb5_principal2salt(krb5_context context, register krb5_const_principal pr, krb5_data *ret)
+{
+	return krb5_principal2salt_internal(context, pr, ret, 1);
+}
+
+krb5_error_code
+krb5_principal2salt_norealm(krb5_context context, register krb5_const_principal pr, krb5_data *ret)
+{
+	return krb5_principal2salt_internal(context, pr, ret, 0);
+}
diff --git a/mechglue/src/lib/krb5/krb/preauth.c b/mechglue/src/lib/krb5/krb/preauth.c
new file mode 100644
index 000000000..0e7c279e1
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/preauth.c
@@ -0,0 +1,581 @@
+/*
+ * Copyright 1995 by the Massachusetts Institute of Technology.  All
+ * Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * This file contains routines for establishing, verifying, and any other
+ * necessary functions, for utilizing the pre-authentication field of the 
+ * kerberos kdc request, with various hardware/software verification devices.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include <time.h>
+
+static krb5_error_code obtain_enc_ts_padata
+	(krb5_context,
+	 krb5_pa_data *,
+	 krb5_etype_info,
+	 krb5_keyblock *,
+	 krb5_error_code ( * )(krb5_context,
+			       const krb5_enctype,
+			       krb5_data *,
+			       krb5_const_pointer,
+			       krb5_keyblock **),
+	 krb5_const_pointer,
+	 krb5_creds *,
+	 krb5_kdc_req *,
+	 krb5_pa_data **);
+
+static krb5_error_code process_pw_salt
+	(krb5_context,
+	 krb5_pa_data *,
+	 krb5_kdc_req *,
+	 krb5_kdc_rep *,
+	 krb5_error_code ( * )(krb5_context,
+			       const krb5_enctype,
+			       krb5_data *,
+			       krb5_const_pointer,
+			       krb5_keyblock **),
+	 krb5_const_pointer,
+	 krb5_error_code ( * )(krb5_context,
+			       const krb5_keyblock *,
+			       krb5_const_pointer,
+			       krb5_kdc_rep * ),
+	 krb5_keyblock **,
+	 krb5_creds *,
+	 krb5_int32 *,
+	 krb5_int32 *);
+
+static krb5_error_code obtain_sam_padata
+	(krb5_context,
+	 krb5_pa_data *,
+	 krb5_etype_info,
+	 krb5_keyblock *, 
+	 krb5_error_code ( * )(krb5_context,
+			       const krb5_enctype,
+			       krb5_data *,
+			       krb5_const_pointer,
+			       krb5_keyblock **),
+	 krb5_const_pointer,
+	 krb5_creds *,
+	 krb5_kdc_req *,
+	 krb5_pa_data **);
+
+static const krb5_preauth_ops preauth_systems[] = {
+    {
+	KV5M_PREAUTH_OPS,
+	KRB5_PADATA_ENC_TIMESTAMP,
+        0,
+        obtain_enc_ts_padata,
+        0,
+    },
+    {
+	KV5M_PREAUTH_OPS,
+	KRB5_PADATA_PW_SALT,
+        0,
+        0,
+        process_pw_salt,
+    },
+    {
+	KV5M_PREAUTH_OPS,
+	KRB5_PADATA_AFS3_SALT,
+        0,
+        0,
+        process_pw_salt,
+    },
+    {
+	KV5M_PREAUTH_OPS,
+	KRB5_PADATA_SAM_CHALLENGE,
+        0,
+        obtain_sam_padata,
+        0,
+    },
+    { KV5M_PREAUTH_OPS, -1 }
+};
+
+static krb5_error_code find_pa_system
+    (krb5_preauthtype type, const krb5_preauth_ops **Preauth_proc);
+
+/* some typedef's for the function args to make things look a bit cleaner */
+
+typedef krb5_error_code (*git_key_proc) (krb5_context,
+					 const krb5_enctype,
+					 krb5_data *,
+					 krb5_const_pointer,
+					 krb5_keyblock **);
+
+typedef krb5_error_code (*git_decrypt_proc) (krb5_context,
+					     const krb5_keyblock *,
+					     krb5_const_pointer,
+					     krb5_kdc_rep *);
+
+krb5_error_code krb5_obtain_padata(krb5_context context, krb5_pa_data **preauth_to_use, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request)
+{
+    krb5_error_code		retval;
+    krb5_etype_info	    	etype_info = 0;
+    krb5_pa_data **		pa;
+    krb5_pa_data **		send_pa_list;
+    krb5_pa_data **		send_pa;
+    const krb5_preauth_ops	*ops;
+    krb5_keyblock *		def_enc_key = 0;
+    krb5_enctype 		enctype;
+    krb5_data 			salt;
+    krb5_data			scratch;
+    int				size;
+    int				f_salt = 0;
+
+    if (preauth_to_use == NULL)
+	return 0;
+
+    for (pa = preauth_to_use, size=0; *pa; pa++, size++) {
+	if ((*pa)->pa_type == KRB5_PADATA_ETYPE_INFO) {
+	    /* XXX use the first one.  Is there another way to disambiguate? */
+	    if (etype_info)
+		continue;
+
+	    scratch.length = (*pa)->length;
+	    scratch.data = (char *) (*pa)->contents;
+	    retval = decode_krb5_etype_info(&scratch, &etype_info);
+	    if (retval)
+		return retval;
+	    if (etype_info[0] == NULL) {
+		krb5_free_etype_info(context, etype_info);
+		etype_info = NULL;
+	    }
+	}
+    }
+
+    if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
+	return ENOMEM;
+
+    send_pa = send_pa_list;
+    *send_pa = 0;
+
+    enctype = request->ktype[0];
+    salt.data = 0;
+    salt.length = SALT_TYPE_NO_LENGTH;
+    if (etype_info) {
+	enctype = etype_info[0]->etype;
+	salt.data = (char *) etype_info[0]->salt;
+	if(etype_info[0]->length == KRB5_ETYPE_NO_SALT) 
+	  salt.length = SALT_TYPE_NO_LENGTH; /* XXX */
+	else 
+	  salt.length = etype_info[0]->length;
+    }
+    if (salt.length == SALT_TYPE_NO_LENGTH) {
+        /*
+	 * This will set the salt length 
+	 */
+	if ((retval = krb5_principal2salt(context, request->client, &salt)))
+	    return(retval);
+	f_salt = 1;
+    }
+    
+    if ((retval = (*key_proc)(context, enctype, &salt, key_seed,
+			      &def_enc_key)))
+	goto cleanup;
+    
+
+    for (pa = preauth_to_use; *pa; pa++) {
+	if (find_pa_system((*pa)->pa_type, &ops))
+	    continue;
+
+	if (ops->obtain == 0)
+	    continue;
+	
+	retval = ((ops)->obtain)(context, *pa, etype_info, def_enc_key,
+				 key_proc, key_seed, creds,
+				 request, send_pa);
+	if (retval)
+	    goto cleanup;
+
+	if (*send_pa)
+	    send_pa++;
+	*send_pa = 0;
+    }
+
+    retval = 0;
+
+    if (send_pa_list[0]) {
+	request->padata = send_pa_list;
+	send_pa_list = 0;
+    }
+
+cleanup:
+    if (etype_info)
+	krb5_free_etype_info(context, etype_info);
+    if (f_salt)
+	krb5_xfree(salt.data);
+    if (send_pa_list)
+	krb5_free_pa_data(context, send_pa_list);
+    if (def_enc_key)
+	krb5_free_keyblock(context, def_enc_key);
+    return retval;
+    
+}
+
+krb5_error_code
+krb5_process_padata(krb5_context context, krb5_kdc_req *request, krb5_kdc_rep *as_reply, git_key_proc key_proc, krb5_const_pointer keyseed, git_decrypt_proc decrypt_proc, krb5_keyblock **decrypt_key, krb5_creds *creds, krb5_int32 *do_more)
+{
+    krb5_error_code		retval = 0;
+    const krb5_preauth_ops * 	ops;
+    krb5_pa_data **		pa;
+    krb5_int32			done = 0;
+    
+    *do_more = 0;		/* By default, we don't need to repeat... */
+    if (as_reply->padata == 0)
+	return 0;
+
+    for (pa = as_reply->padata; *pa; pa++) {
+	if (find_pa_system((*pa)->pa_type, &ops))
+	    continue;
+
+	if (ops->process == 0)
+	    continue;
+	
+	retval = ((ops)->process)(context, *pa, request, as_reply,
+				  key_proc, keyseed, decrypt_proc,
+				  decrypt_key, creds, do_more, &done);
+	if (retval)
+	    goto cleanup;
+	if (done)
+	    break;
+    }
+
+cleanup:
+    return retval;
+}
+
+/*
+ * This routine is the "obtain" function for the ENC_TIMESTAMP
+ * preauthentication type.  It take the current time and encrypts it
+ * in the user's key.
+ */
+static krb5_error_code
+obtain_enc_ts_padata(krb5_context context, krb5_pa_data *in_padata, krb5_etype_info etype_info, krb5_keyblock *def_enc_key, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request, krb5_pa_data **out_padata)
+{
+    krb5_pa_enc_ts		pa_enc;
+    krb5_error_code		retval;
+    krb5_data *			scratch;
+    krb5_enc_data 		enc_data;
+    krb5_pa_data *		pa;
+
+    retval = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec);
+    if (retval)
+	return retval;
+
+    if ((retval = encode_krb5_pa_enc_ts(&pa_enc, &scratch)) != 0)
+	return retval;
+
+    enc_data.ciphertext.data = 0;
+
+    if ((retval = krb5_encrypt_helper(context, def_enc_key,
+				      KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
+				      scratch, &enc_data)))
+	goto cleanup;
+
+    krb5_free_data(context, scratch);
+    scratch = 0;
+    
+    if ((retval = encode_krb5_enc_data(&enc_data, &scratch)) != 0)
+	goto cleanup;
+
+    if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) {
+	retval = ENOMEM;
+	goto cleanup;
+    }
+
+    pa->magic = KV5M_PA_DATA;
+    pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
+    pa->length = scratch->length;
+    pa->contents = (krb5_octet *) scratch->data;
+
+    *out_padata = pa;
+
+    krb5_xfree(scratch);
+    scratch = 0;
+
+    retval = 0;
+    
+cleanup:
+    if (scratch)
+	krb5_free_data(context, scratch);
+    if (enc_data.ciphertext.data)
+	krb5_xfree(enc_data.ciphertext.data);
+    return retval;
+}
+
+static krb5_error_code
+process_pw_salt(krb5_context context, krb5_pa_data *padata, krb5_kdc_req *request, krb5_kdc_rep *as_reply, git_key_proc key_proc, krb5_const_pointer keyseed, git_decrypt_proc decrypt_proc, krb5_keyblock **decrypt_key, krb5_creds *creds, krb5_int32 *do_more, krb5_int32 *done)
+{
+    krb5_error_code	retval;
+    krb5_data		salt;
+    
+    if (*decrypt_key != 0)
+	return 0;
+
+    salt.data = (char *) padata->contents;
+    salt.length = 
+      (padata->pa_type == KRB5_PADATA_AFS3_SALT)?(SALT_TYPE_AFS_LENGTH):(padata->length);
+    
+    if ((retval = (*key_proc)(context, as_reply->enc_part.enctype,
+			      &salt, keyseed, decrypt_key))) {
+	*decrypt_key = 0;
+	return retval;
+    }
+
+    return 0;
+}
+    
+static krb5_error_code
+find_pa_system(krb5_preauthtype type, const krb5_preauth_ops **preauth)
+{
+    const krb5_preauth_ops *ap = preauth_systems;
+    
+    while ((ap->type != -1) && (ap->type != type))
+	ap++;
+    if (ap->type == -1)
+	return(KRB5_PREAUTH_BAD_TYPE);
+    *preauth = ap;
+    return 0;
+} 
+
+
+extern const char *krb5_default_pwd_prompt1;
+
+static krb5_error_code
+sam_get_pass_from_user(krb5_context context, krb5_etype_info etype_info, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_kdc_req *request, krb5_keyblock **new_enc_key, const char *prompt)
+{
+    krb5_enctype 		enctype;
+    krb5_error_code		retval;
+    const char *oldprompt;
+
+    /* enctype = request->ktype[0]; */
+    enctype = ENCTYPE_DES_CBC_MD5;
+/* hack with this first! */
+    oldprompt = krb5_default_pwd_prompt1;
+    krb5_default_pwd_prompt1 = prompt;
+    {
+      krb5_data newpw;
+      newpw.data = 0; newpw.length = 0;
+      /* we don't keep the new password, just the key... */
+      retval = (*key_proc)(context, enctype, 0, 
+			   (krb5_const_pointer)&newpw, new_enc_key);
+      krb5_xfree(newpw.data);
+    }
+    krb5_default_pwd_prompt1 = oldprompt;
+    return retval;
+}
+static 
+char *handle_sam_labels(krb5_sam_challenge *sc)
+{
+    char *label = sc->sam_challenge_label.data;
+    unsigned int label_len = sc->sam_challenge_label.length;
+    char *prompt = sc->sam_response_prompt.data;
+    unsigned int prompt_len = sc->sam_response_prompt.length;
+    char *challenge = sc->sam_challenge.data;
+    unsigned int challenge_len = sc->sam_challenge.length;
+    char *prompt1, *p;
+    char *sep1 = ": [";
+    char *sep2 = "]\n";
+    char *sep3 = ": ";
+
+    if (sc->sam_cksum.length == 0) {
+      /* or invalid -- but lets just handle presence now XXX */
+      switch (sc->sam_type) {
+      case PA_SAM_TYPE_ENIGMA:	/* Enigma Logic */
+	label = "Challenge for Enigma Logic mechanism";
+	break;
+      case PA_SAM_TYPE_DIGI_PATH: /*  Digital Pathways */
+      case PA_SAM_TYPE_DIGI_PATH_HEX: /*  Digital Pathways */
+	label = "Challenge for Digital Pathways mechanism";
+	break;
+      case PA_SAM_TYPE_ACTIVCARD_DEC: /*  Digital Pathways */
+      case PA_SAM_TYPE_ACTIVCARD_HEX: /*  Digital Pathways */
+	label = "Challenge for Activcard mechanism";
+	break;
+      case PA_SAM_TYPE_SKEY_K0:	/*  S/key where  KDC has key 0 */
+	label = "Challenge for Enhanced S/Key mechanism";
+	break;
+      case PA_SAM_TYPE_SKEY:	/*  Traditional S/Key */
+	label = "Challenge for Traditional S/Key mechanism";
+	break;
+      case PA_SAM_TYPE_SECURID:	/*  Security Dynamics */
+	label = "Challenge for Security Dynamics mechanism";
+	break;
+      case PA_SAM_TYPE_SECURID_PREDICT:	/* predictive Security Dynamics */
+	label = "Challenge for Security Dynamics mechanism";
+	break;
+      }
+      prompt = "Passcode";
+      label_len = strlen(label);
+      prompt_len = strlen(prompt);
+    }
+
+    /* example:
+       Challenge for Digital Pathways mechanism: [134591]
+       Passcode: 
+     */
+    p = prompt1 = malloc(label_len + strlen(sep1) +
+			 challenge_len + strlen(sep2) +
+			 prompt_len+ strlen(sep3) + 1);
+    if (p == NULL)
+	return NULL;
+    if (challenge_len) {
+	strncpy(p, label, label_len); p += label_len;
+	strcpy(p, sep1); p += strlen(sep1);
+	strncpy(p, challenge, challenge_len); p += challenge_len;
+	strcpy(p, sep2); p += strlen(sep2);
+    }
+    strncpy(p, prompt, prompt_len); p += prompt_len;
+    strcpy(p, sep3); /* p += strlen(sep3); */
+    return prompt1;
+}
+
+/*
+ * This routine is the "obtain" function for the SAM_CHALLENGE
+ * preauthentication type.  It presents the challenge...
+ */
+static krb5_error_code
+obtain_sam_padata(krb5_context context, krb5_pa_data *in_padata, krb5_etype_info etype_info, krb5_keyblock *def_enc_key, git_key_proc key_proc, krb5_const_pointer key_seed, krb5_creds *creds, krb5_kdc_req *request, krb5_pa_data **out_padata)
+{
+    krb5_error_code		retval;
+    krb5_data *			scratch;
+    krb5_data			tmpsam;
+    krb5_pa_data *		pa;
+    krb5_sam_challenge		*sam_challenge = 0;
+    krb5_sam_response		sam_response;
+    /* these two get encrypted and stuffed in to sam_response */
+    krb5_enc_sam_response_enc	enc_sam_response_enc;
+    krb5_keyblock *		sam_use_key = 0;
+    char * prompt;
+
+    tmpsam.length = in_padata->length;
+    tmpsam.data = (char *) in_padata->contents;
+    retval = decode_krb5_sam_challenge(&tmpsam, &sam_challenge);
+    if (retval)
+      return retval;
+
+    if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
+      return KRB5_SAM_UNSUPPORTED;
+    }
+
+    enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
+    if (!sam_challenge->sam_nonce) {
+      retval = krb5_us_timeofday(context,
+                                 &enc_sam_response_enc.sam_timestamp,
+                                 &enc_sam_response_enc.sam_usec);
+      sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
+    }
+    if (retval)
+      return retval;
+    if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
+      /* encrypt passcode in key by stuffing it here */
+      unsigned int pcsize = 256;
+      char *passcode = malloc(pcsize+1);
+      if (passcode == NULL)
+	return ENOMEM;
+      prompt = handle_sam_labels(sam_challenge);
+      if (prompt == NULL) {
+	free(passcode);
+	return ENOMEM;
+      }
+      retval = krb5_read_password(context, prompt, 0, passcode, &pcsize);
+      free(prompt);
+
+      if (retval) {
+	free(passcode);
+	return retval;
+      }
+      enc_sam_response_enc.sam_sad.data = passcode;
+      enc_sam_response_enc.sam_sad.length = pcsize;
+    } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
+      prompt = handle_sam_labels(sam_challenge);
+      if (prompt == NULL)
+	return ENOMEM;
+      retval = sam_get_pass_from_user(context, etype_info, key_proc, 
+				      key_seed, request, &sam_use_key,
+				      prompt);
+      free(prompt);
+      if (retval)
+	return retval;      
+      enc_sam_response_enc.sam_sad.length = 0;
+    } else {
+      /* what *was* it? */
+      return KRB5_SAM_UNSUPPORTED;
+    }
+
+    /* so at this point, either sam_use_key is generated from the passcode
+     * or enc_sam_response_enc.sam_sad is set to it, and we use 
+     * def_enc_key instead. */
+    /* encode the encoded part of the response */
+    if ((retval = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
+						   &scratch)) != 0)
+      return retval;
+
+    if ((retval = krb5_encrypt_data(context, 
+				    sam_use_key?sam_use_key:def_enc_key, 
+				    0, scratch,
+				    &sam_response.sam_enc_nonce_or_ts)))
+      goto cleanup;
+
+    krb5_free_data(context, scratch);
+    scratch = 0;
+
+    /* sam_enc_key is reserved for future use */
+    sam_response.sam_enc_key.ciphertext.length = 0;
+
+    /* copy things from the challenge */
+    sam_response.sam_nonce = sam_challenge->sam_nonce;
+    sam_response.sam_flags = sam_challenge->sam_flags;
+    sam_response.sam_track_id = sam_challenge->sam_track_id;
+    sam_response.sam_type = sam_challenge->sam_type;
+    sam_response.magic = KV5M_SAM_RESPONSE;
+
+    if ((retval = encode_krb5_sam_response(&sam_response, &scratch)) != 0)
+	return retval;
+    
+    if ((pa = malloc(sizeof(krb5_pa_data))) == NULL) {
+	retval = ENOMEM;
+	goto cleanup;
+    }
+
+    pa->magic = KV5M_PA_DATA;
+    pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
+    pa->length = scratch->length;
+    pa->contents = (krb5_octet *) scratch->data;
+    scratch = 0;		/* so we don't free it! */
+
+    *out_padata = pa;
+
+    retval = 0;
+    
+cleanup:
+    if (scratch)
+	krb5_free_data(context, scratch);
+    if (sam_challenge)
+        krb5_xfree(sam_challenge);
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/preauth2.c b/mechglue/src/lib/krb5/krb/preauth2.c
new file mode 100644
index 000000000..e146c3d3a
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/preauth2.c
@@ -0,0 +1,1031 @@
+/*
+ * Copyright 1995, 2003 by the Massachusetts Institute of Technology.  All
+ * Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * This file contains routines for establishing, verifying, and any other
+ * necessary functions, for utilizing the pre-authentication field of the 
+ * kerberos kdc request, with various hardware/software verification devices.
+ */
+
+#include "k5-int.h"
+
+typedef krb5_error_code (*pa_function)(krb5_context,
+				       krb5_kdc_req *request,
+				       krb5_pa_data *in_padata,
+				       krb5_pa_data **out_padata,
+				       krb5_data *salt, krb5_data *s2kparams,
+				       krb5_enctype *etype,
+				       krb5_keyblock *as_key,
+				       krb5_prompter_fct prompter_fct,
+				       void *prompter_data,
+				       krb5_gic_get_as_key_fct gak_fct,
+				       void *gak_data);
+				 
+typedef struct _pa_types_t {
+    krb5_preauthtype type;
+    pa_function fct;
+    int flags;
+} pa_types_t;
+
+#define PA_REAL 0x0001
+#define PA_INFO 0x0002
+
+static
+krb5_error_code pa_salt(krb5_context context,
+			krb5_kdc_req *request,
+			krb5_pa_data *in_padata,
+			krb5_pa_data **out_padata,
+			krb5_data *salt, krb5_data *s2kparams,
+			krb5_enctype *etype,
+			krb5_keyblock *as_key,
+			krb5_prompter_fct prompter, void *prompter_data,
+			krb5_gic_get_as_key_fct gak_fct, void *gak_data)
+{
+    krb5_data tmp;
+
+    tmp.data = in_padata->contents;
+    tmp.length = in_padata->length;
+    krb5_free_data_contents(context, salt);
+    krb5int_copy_data_contents(context, &tmp, salt);
+    
+
+    if (in_padata->pa_type == KRB5_PADATA_AFS3_SALT)
+	salt->length = SALT_TYPE_AFS_LENGTH;
+
+    return(0);
+}
+
+static
+krb5_error_code pa_enc_timestamp(krb5_context context,
+				 krb5_kdc_req *request,
+				 krb5_pa_data *in_padata,
+				 krb5_pa_data **out_padata,
+				 krb5_data *salt,
+				 krb5_data *s2kparams,
+				 krb5_enctype *etype,
+				 krb5_keyblock *as_key,
+				 krb5_prompter_fct prompter,
+				 void *prompter_data,
+				 krb5_gic_get_as_key_fct gak_fct,
+				 void *gak_data)
+{
+    krb5_error_code ret;
+    krb5_pa_enc_ts pa_enc;
+    krb5_data *tmp;
+    krb5_enc_data enc_data;
+    krb5_pa_data *pa;
+   
+    if (as_key->length == 0) {
+#ifdef DEBUG
+	fprintf (stderr, "%s:%d: salt len=%d", __FILE__, __LINE__,
+		 salt->length);
+	if (salt->length > 0)
+	    fprintf (stderr, " '%*s'", salt->length, salt->data);
+	fprintf (stderr, "; *etype=%d request->ktype[0]=%d\n",
+		 *etype, request->ktype[0]);
+#endif
+       if ((ret = ((*gak_fct)(context, request->client,
+			      *etype ? *etype : request->ktype[0],
+			      prompter, prompter_data,
+			      salt, s2kparams, as_key, gak_data))))
+           return(ret);
+    }
+
+    /* now get the time of day, and encrypt it accordingly */
+
+    if ((ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec)))
+	return(ret);
+
+    if ((ret = encode_krb5_pa_enc_ts(&pa_enc, &tmp)))
+	return(ret);
+
+#ifdef DEBUG
+    fprintf (stderr, "key type %d bytes %02x %02x ...\n",
+	     as_key->enctype,
+	     as_key->contents[0], as_key->contents[1]);
+#endif
+    ret = krb5_encrypt_helper(context, as_key,
+			      KRB5_KEYUSAGE_AS_REQ_PA_ENC_TS,
+			      tmp, &enc_data);
+#ifdef DEBUG
+    fprintf (stderr, "enc data { type=%d kvno=%d data=%02x %02x ... }\n",
+	     enc_data.enctype, enc_data.kvno,
+	     0xff & enc_data.ciphertext.data[0],
+	     0xff & enc_data.ciphertext.data[1]);
+#endif
+
+    krb5_free_data(context, tmp);
+
+    if (ret) {
+	krb5_xfree(enc_data.ciphertext.data);
+	return(ret);
+    }
+
+    ret = encode_krb5_enc_data(&enc_data, &tmp);
+
+    krb5_xfree(enc_data.ciphertext.data);
+
+    if (ret)
+	return(ret);
+
+    if ((pa = (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) {
+	krb5_free_data(context, tmp);
+	return(ENOMEM);
+    }
+
+    pa->magic = KV5M_PA_DATA;
+    pa->pa_type = KRB5_PADATA_ENC_TIMESTAMP;
+    pa->length = tmp->length;
+    pa->contents = (krb5_octet *) tmp->data;
+
+    *out_padata = pa;
+
+    krb5_xfree(tmp);
+
+    return(0);
+}
+
+static 
+char *sam_challenge_banner(krb5_int32 sam_type)
+{
+    char *label;
+
+    switch (sam_type) {
+    case PA_SAM_TYPE_ENIGMA:	/* Enigma Logic */
+	label = "Challenge for Enigma Logic mechanism";
+	break;
+    case PA_SAM_TYPE_DIGI_PATH: /*  Digital Pathways */
+    case PA_SAM_TYPE_DIGI_PATH_HEX: /*  Digital Pathways */
+	label = "Challenge for Digital Pathways mechanism";
+	break;
+    case PA_SAM_TYPE_ACTIVCARD_DEC: /*  Digital Pathways */
+    case PA_SAM_TYPE_ACTIVCARD_HEX: /*  Digital Pathways */
+	label = "Challenge for Activcard mechanism";
+	break;
+    case PA_SAM_TYPE_SKEY_K0:	/*  S/key where  KDC has key 0 */
+	label = "Challenge for Enhanced S/Key mechanism";
+	break;
+    case PA_SAM_TYPE_SKEY:	/*  Traditional S/Key */
+	label = "Challenge for Traditional S/Key mechanism";
+	break;
+    case PA_SAM_TYPE_SECURID:	/*  Security Dynamics */
+	label = "Challenge for Security Dynamics mechanism";
+	break;
+    case PA_SAM_TYPE_SECURID_PREDICT:	/* predictive Security Dynamics */
+	label = "Challenge for Security Dynamics mechanism";
+	break;
+    default:
+	label = "Challenge from authentication server";
+	break;
+    }
+
+    return(label);
+}
+
+/* this macro expands to the int,ptr necessary for "%.*s" in an sprintf */
+
+#define SAMDATA(kdata, str, maxsize) \
+	(int)((kdata.length)? \
+	      ((((kdata.length)<=(maxsize))?(kdata.length):strlen(str))): \
+	      strlen(str)), \
+	(kdata.length)? \
+	((((kdata.length)<=(maxsize))?(kdata.data):(str))):(str)
+
+/* XXX Danger! This code is not in sync with the kerberos-password-02
+   draft.  This draft cannot be implemented as written.  This code is
+   compatible with earlier versions of mit krb5 and cygnus kerbnet. */
+
+static
+krb5_error_code pa_sam(krb5_context context,
+		       krb5_kdc_req *request,
+		       krb5_pa_data *in_padata,
+		       krb5_pa_data **out_padata,
+		       krb5_data *salt,
+		       krb5_data *s2kparams,
+		       krb5_enctype *etype,
+		       krb5_keyblock *as_key,
+		       krb5_prompter_fct prompter,
+		       void *prompter_data,
+		       krb5_gic_get_as_key_fct gak_fct,
+		       void *gak_data)
+{
+    krb5_error_code		ret;
+    krb5_data			tmpsam;
+    char			name[100], banner[100];
+    char			prompt[100], response[100];
+    krb5_data			response_data;
+    krb5_prompt			kprompt;
+    krb5_prompt_type		prompt_type;
+    krb5_data			defsalt;
+    krb5_sam_challenge		*sam_challenge = 0;
+    krb5_sam_response		sam_response;
+    /* these two get encrypted and stuffed in to sam_response */
+    krb5_enc_sam_response_enc	enc_sam_response_enc;
+    krb5_data *			scratch;
+    krb5_pa_data *		pa;
+
+    if (prompter == NULL)
+	return EIO;
+
+    tmpsam.length = in_padata->length;
+    tmpsam.data = (char *) in_padata->contents;
+    if ((ret = decode_krb5_sam_challenge(&tmpsam, &sam_challenge)))
+	return(ret);
+
+    if (sam_challenge->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
+	krb5_xfree(sam_challenge);
+	return(KRB5_SAM_UNSUPPORTED);
+    }
+
+    /* If we need the password from the user (USE_SAD_AS_KEY not set),	*/
+    /* then get it here.  Exception for "old" KDCs with CryptoCard 	*/
+    /* support which uses the USE_SAD_AS_KEY flag, but still needs pwd	*/ 
+
+    if (!(sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) ||
+	(sam_challenge->sam_type == PA_SAM_TYPE_CRYPTOCARD)) {
+
+	/* etype has either been set by caller or by KRB5_PADATA_ETYPE_INFO */
+	/* message from the KDC.  If it is not set, pick an enctype that we */
+	/* think the KDC will have for us.				    */
+
+	if (etype && *etype == 0)
+	   *etype = ENCTYPE_DES_CBC_CRC;
+
+	if ((ret = (gak_fct)(context, request->client, *etype, prompter,
+			prompter_data, salt, s2kparams, as_key, gak_data)))
+	   return(ret);
+    }
+    sprintf(name, "%.*s",
+	    SAMDATA(sam_challenge->sam_type_name, "SAM Authentication",
+		    sizeof(name) - 1));
+
+    sprintf(banner, "%.*s",
+	    SAMDATA(sam_challenge->sam_challenge_label,
+		    sam_challenge_banner(sam_challenge->sam_type),
+		    sizeof(banner)-1));
+
+    /* sprintf(prompt, "Challenge is [%s], %s: ", challenge, prompt); */
+    sprintf(prompt, "%s%.*s%s%.*s",
+	    sam_challenge->sam_challenge.length?"Challenge is [":"",
+	    SAMDATA(sam_challenge->sam_challenge, "", 20),
+	    sam_challenge->sam_challenge.length?"], ":"",
+	    SAMDATA(sam_challenge->sam_response_prompt, "passcode", 55));
+
+    response_data.data = response;
+    response_data.length = sizeof(response);
+
+    kprompt.prompt = prompt;
+    kprompt.hidden = 1;
+    kprompt.reply = &response_data;
+    prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
+
+    /* PROMPTER_INVOCATION */
+    krb5int_set_prompt_types(context, &prompt_type);
+    if ((ret = ((*prompter)(context, prompter_data, name,
+			   banner, 1, &kprompt)))) {
+	krb5_xfree(sam_challenge);
+	krb5int_set_prompt_types(context, 0);
+	return(ret);
+    }
+    krb5int_set_prompt_types(context, 0);
+
+    enc_sam_response_enc.sam_nonce = sam_challenge->sam_nonce;
+    if (sam_challenge->sam_nonce == 0) {
+	if ((ret = krb5_us_timeofday(context, 
+				&enc_sam_response_enc.sam_timestamp,
+				&enc_sam_response_enc.sam_usec))) {
+		krb5_xfree(sam_challenge);
+		return(ret);
+	}
+
+	sam_response.sam_patimestamp = enc_sam_response_enc.sam_timestamp;
+    }
+
+    /* XXX What if more than one flag is set?  */
+    if (sam_challenge->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
+
+	/* Most of this should be taken care of before we get here.  We	*/
+	/* will need the user's password and as_key to encrypt the SAD	*/
+	/* and we want to preserve ordering of user prompts (first	*/
+	/* password, then SAM data) so that user's won't be confused.	*/
+
+	if (as_key->length) {
+	    krb5_free_keyblock_contents(context, as_key);
+	    as_key->length = 0;
+	}
+
+	/* generate a salt using the requested principal */
+
+	if ((salt->length == -1 || salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
+	    if ((ret = krb5_principal2salt(context, request->client,
+					  &defsalt))) {
+		krb5_xfree(sam_challenge);
+		return(ret);
+	    }
+
+	    salt = &defsalt;
+	} else {
+	    defsalt.length = 0;
+	}
+
+	/* generate a key using the supplied password */
+
+	ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
+				   (krb5_data *)gak_data, salt, as_key);
+
+	if (defsalt.length)
+	    krb5_xfree(defsalt.data);
+
+	if (ret) {
+	    krb5_xfree(sam_challenge);
+	    return(ret);
+	}
+
+	/* encrypt the passcode with the key from above */
+
+	enc_sam_response_enc.sam_sad = response_data;
+    } else if (sam_challenge->sam_flags & KRB5_SAM_USE_SAD_AS_KEY) {
+
+	/* process the key as password */
+
+	if (as_key->length) {
+	    krb5_free_keyblock_contents(context, as_key);
+	    as_key->length = 0;
+	}
+
+#if 0
+	if ((salt->length == SALT_TYPE_AFS_LENGTH) && (salt->data == NULL)) {
+	    if (ret = krb5_principal2salt(context, request->client,
+					  &defsalt)) {
+		krb5_xfree(sam_challenge);
+		return(ret);
+	    }
+
+	    salt = &defsalt;
+	} else {
+	    defsalt.length = 0;
+	}
+#else
+	defsalt.length = 0;
+	salt = NULL;
+#endif
+	    
+	/* XXX As of the passwords-04 draft, no enctype is specified,
+	   the server uses ENCTYPE_DES_CBC_MD5. In the future the
+	   server should send a PA-SAM-ETYPE-INFO containing the enctype. */
+
+	ret = krb5_c_string_to_key(context, ENCTYPE_DES_CBC_MD5,
+				   &response_data, salt, as_key);
+
+	if (defsalt.length)
+	    krb5_xfree(defsalt.data);
+
+	if (ret) {
+	    krb5_xfree(sam_challenge);
+	    return(ret);
+	}
+
+	enc_sam_response_enc.sam_sad.length = 0;
+    } else {
+	/* Eventually, combine SAD with long-term key to get
+	   encryption key.  */
+	return KRB5_PREAUTH_BAD_TYPE;
+    }
+
+    /* copy things from the challenge */
+    sam_response.sam_nonce = sam_challenge->sam_nonce;
+    sam_response.sam_flags = sam_challenge->sam_flags;
+    sam_response.sam_track_id = sam_challenge->sam_track_id;
+    sam_response.sam_type = sam_challenge->sam_type;
+    sam_response.magic = KV5M_SAM_RESPONSE;
+
+    krb5_xfree(sam_challenge);
+
+    /* encode the encoded part of the response */
+    if ((ret = encode_krb5_enc_sam_response_enc(&enc_sam_response_enc,
+						&scratch)))
+	return(ret);
+
+    ret = krb5_encrypt_data(context, as_key, 0, scratch,
+			    &sam_response.sam_enc_nonce_or_ts);
+
+    krb5_free_data(context, scratch);
+
+    if (ret)
+	return(ret);
+
+    /* sam_enc_key is reserved for future use */
+    sam_response.sam_enc_key.ciphertext.length = 0;
+
+    if ((pa = malloc(sizeof(krb5_pa_data))) == NULL)
+	return(ENOMEM);
+
+    if ((ret = encode_krb5_sam_response(&sam_response, &scratch))) {
+	free(pa);
+	return(ret);
+    }
+
+    pa->magic = KV5M_PA_DATA;
+    pa->pa_type = KRB5_PADATA_SAM_RESPONSE;
+    pa->length = scratch->length;
+    pa->contents = (krb5_octet *) scratch->data;
+
+    *out_padata = pa;
+
+    return(0);
+}
+
+static
+krb5_error_code pa_sam_2(krb5_context context,
+				krb5_kdc_req *request,
+				krb5_pa_data *in_padata,
+				krb5_pa_data **out_padata,
+				krb5_data *salt,
+			 krb5_data *s2kparams,
+				krb5_enctype *etype,
+				krb5_keyblock *as_key,
+				krb5_prompter_fct prompter,
+				void *prompter_data,
+				krb5_gic_get_as_key_fct gak_fct,
+				void *gak_data) {
+
+   krb5_error_code retval;
+   krb5_sam_challenge_2 *sc2 = NULL;
+   krb5_sam_challenge_2_body *sc2b = NULL;
+   krb5_data tmp_data;
+   krb5_data response_data;
+   char name[100], banner[100], prompt[100], response[100];
+   krb5_prompt kprompt;
+   krb5_prompt_type prompt_type;
+   krb5_data defsalt;
+   krb5_checksum **cksum;
+   krb5_data *scratch = NULL;
+   krb5_boolean valid_cksum = 0;
+   krb5_enc_sam_response_enc_2 enc_sam_response_enc_2;
+   krb5_sam_response_2 sr2;
+   size_t ciph_len;
+   krb5_pa_data *sam_padata;
+
+   if (prompter == NULL)
+	return KRB5_LIBOS_CANTREADPWD;
+
+   tmp_data.length = in_padata->length;
+   tmp_data.data = (char *)in_padata->contents;
+
+   if ((retval = decode_krb5_sam_challenge_2(&tmp_data, &sc2)))
+	return(retval);
+
+   retval = decode_krb5_sam_challenge_2_body(&sc2->sam_challenge_2_body, &sc2b);
+
+   if (retval)
+	return(retval);
+
+   if (!sc2->sam_cksum || ! *sc2->sam_cksum) {
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	return(KRB5_SAM_NO_CHECKSUM);
+   }
+
+   if (sc2b->sam_flags & KRB5_SAM_MUST_PK_ENCRYPT_SAD) {
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	return(KRB5_SAM_UNSUPPORTED);
+   }
+
+   if (!valid_enctype(sc2b->sam_etype)) {
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	return(KRB5_SAM_INVALID_ETYPE);
+   }
+
+   /* All of the above error checks are KDC-specific, that is, they	*/
+   /* assume a failure in the KDC reply.  By returning anything other	*/
+   /* than KRB5_KDC_UNREACH, KRB5_PREAUTH_FAILED,		*/
+   /* KRB5_LIBOS_PWDINTR, or KRB5_REALM_CANT_RESOLVE, the client will	*/
+   /* most likely go on to try the AS_REQ against master KDC		*/
+
+   if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
+	/* We will need the password to obtain the key used for	*/
+	/* the checksum, and encryption of the sam_response.	*/
+	/* Go ahead and get it now, preserving the ordering of	*/
+	/* prompts for the user.				*/
+
+	retval = (gak_fct)(context, request->client,
+			sc2b->sam_etype, prompter,
+			prompter_data, salt, s2kparams, as_key, gak_data);
+	if (retval) {
+	   krb5_free_sam_challenge_2(context, sc2);
+	   krb5_free_sam_challenge_2_body(context, sc2b);
+	   return(retval);
+	}
+   }
+
+   sprintf(name, "%.*s",
+	SAMDATA(sc2b->sam_type_name, "SAM Authentication",
+	sizeof(name) - 1));
+
+   sprintf(banner, "%.*s",
+	SAMDATA(sc2b->sam_challenge_label,
+	sam_challenge_banner(sc2b->sam_type),
+	sizeof(banner)-1));
+
+   sprintf(prompt, "%s%.*s%s%.*s",
+	sc2b->sam_challenge.length?"Challenge is [":"",
+	SAMDATA(sc2b->sam_challenge, "", 20),
+	sc2b->sam_challenge.length?"], ":"",
+	SAMDATA(sc2b->sam_response_prompt, "passcode", 55));
+
+   response_data.data = response;
+   response_data.length = sizeof(response);
+   kprompt.prompt = prompt;
+   kprompt.hidden = 1;
+   kprompt.reply = &response_data;
+
+   prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
+   krb5int_set_prompt_types(context, &prompt_type);
+
+   if ((retval = ((*prompter)(context, prompter_data, name,
+				banner, 1, &kprompt)))) {
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	krb5int_set_prompt_types(context, 0);
+	return(retval);
+   }
+
+   krb5int_set_prompt_types(context, (krb5_prompt_type *)NULL);
+
+   /* Generate salt used by string_to_key() */
+   if ((salt->length == -1) && (salt->data == NULL)) {
+	if ((retval = 
+	     krb5_principal2salt(context, request->client, &defsalt))) {
+	   krb5_free_sam_challenge_2(context, sc2);
+	   krb5_free_sam_challenge_2_body(context, sc2b);
+	   return(retval);
+	}
+	salt = &defsalt;
+   } else {
+	defsalt.length = 0;
+   }
+
+   /* Get encryption key to be used for checksum and sam_response */
+   if (!(sc2b->sam_flags & KRB5_SAM_USE_SAD_AS_KEY)) {
+	/* as_key = string_to_key(password) */
+
+	if (as_key->length) {
+	   krb5_free_keyblock_contents(context, as_key);
+	   as_key->length = 0;
+	}
+
+	/* generate a key using the supplied password */
+	retval = krb5_c_string_to_key(context, sc2b->sam_etype,
+                                   (krb5_data *)gak_data, salt, as_key);
+
+	if (retval) {
+	   krb5_free_sam_challenge_2(context, sc2);
+	   krb5_free_sam_challenge_2_body(context, sc2b);
+	   if (defsalt.length) krb5_xfree(defsalt.data);
+	   return(retval);
+	}
+
+	if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD)) {
+	   /* as_key = combine_key (as_key, string_to_key(SAD)) */
+	   krb5_keyblock tmp_kb;
+
+	   retval = krb5_c_string_to_key(context, sc2b->sam_etype,
+				&response_data, salt, &tmp_kb);
+
+	   if (retval) {
+		krb5_free_sam_challenge_2(context, sc2);
+	        krb5_free_sam_challenge_2_body(context, sc2b);
+		if (defsalt.length) krb5_xfree(defsalt.data);
+		return(retval);
+	   }
+
+	   /* This should be a call to the crypto library some day */
+	   /* key types should already match the sam_etype */
+	   retval = krb5int_c_combine_keys(context, as_key, &tmp_kb, as_key);
+
+	   if (retval) {
+		krb5_free_sam_challenge_2(context, sc2);
+	        krb5_free_sam_challenge_2_body(context, sc2b);
+		if (defsalt.length) krb5_xfree(defsalt.data);
+		return(retval);
+	   }
+	   krb5_free_keyblock_contents(context, &tmp_kb);
+	}
+
+	if (defsalt.length)
+	   krb5_xfree(defsalt.data);
+
+   } else {
+	/* as_key = string_to_key(SAD) */
+
+	if (as_key->length) {
+	   krb5_free_keyblock_contents(context, as_key);
+	   as_key->length = 0;
+	}
+
+	/* generate a key using the supplied password */
+	retval = krb5_c_string_to_key(context, sc2b->sam_etype,
+				&response_data, salt, as_key);
+
+	if (defsalt.length)
+	   krb5_xfree(defsalt.data);
+
+	if (retval) {
+	   krb5_free_sam_challenge_2(context, sc2);
+	   krb5_free_sam_challenge_2_body(context, sc2b);
+	   return(retval);
+	}
+   }
+
+   /* Now we have a key, verify the checksum on the sam_challenge */
+
+   cksum = sc2->sam_cksum;
+   
+   while (*cksum) {
+	/* Check this cksum */
+	retval = krb5_c_verify_checksum(context, as_key,
+			KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM,
+			&sc2->sam_challenge_2_body,
+			*cksum, &valid_cksum);
+	if (retval) {
+	   krb5_free_data(context, scratch);
+	   krb5_free_sam_challenge_2(context, sc2);
+	   krb5_free_sam_challenge_2_body(context, sc2b);
+	   return(retval);
+	}
+	if (valid_cksum)
+	   break;
+	cksum++;
+   }
+
+   if (!valid_cksum) {
+
+	/* If KRB5_SAM_SEND_ENCRYPTED_SAD is set, then password is only	*/
+	/* source for checksum key.  Therefore, a bad checksum means a	*/
+	/* bad password.  Don't give that direct feedback to someone	*/
+	/* trying to brute-force passwords.				*/
+
+	if (!(sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD))
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	/*
+	 * Note: We return AP_ERR_BAD_INTEGRITY so upper-level applications
+	 * can interpret that as "password incorrect", which is probably
+	 * the best error we can return in this situation.
+	 */
+	return(KRB5KRB_AP_ERR_BAD_INTEGRITY);
+   }
+ 
+   /* fill in enc_sam_response_enc_2 */
+   enc_sam_response_enc_2.magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
+   enc_sam_response_enc_2.sam_nonce = sc2b->sam_nonce;
+   if (sc2b->sam_flags & KRB5_SAM_SEND_ENCRYPTED_SAD) {
+	enc_sam_response_enc_2.sam_sad = response_data;
+   } else {
+	enc_sam_response_enc_2.sam_sad.data = NULL;
+	enc_sam_response_enc_2.sam_sad.length = 0;
+   }
+
+   /* encode and encrypt enc_sam_response_enc_2 with as_key */
+   retval = encode_krb5_enc_sam_response_enc_2(&enc_sam_response_enc_2,
+		&scratch);
+   if (retval) {
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	return(retval);
+   }
+
+   /* Fill in sam_response_2 */
+   memset(&sr2, 0, sizeof(sr2));
+   sr2.sam_type = sc2b->sam_type;
+   sr2.sam_flags = sc2b->sam_flags;
+   sr2.sam_track_id = sc2b->sam_track_id;
+   sr2.sam_nonce = sc2b->sam_nonce;
+
+   /* Now take care of sr2.sam_enc_nonce_or_sad by encrypting encoded	*/
+   /* enc_sam_response_enc_2 from above */
+
+   retval = krb5_c_encrypt_length(context, as_key->enctype, scratch->length,
+				  &ciph_len);
+   if (retval) {
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	return(retval);
+   }
+   sr2.sam_enc_nonce_or_sad.ciphertext.length = ciph_len;
+
+   sr2.sam_enc_nonce_or_sad.ciphertext.data =
+	(char *)malloc(sr2.sam_enc_nonce_or_sad.ciphertext.length);
+
+   if (!sr2.sam_enc_nonce_or_sad.ciphertext.data) {
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	return(ENOMEM);
+   }
+
+   retval = krb5_c_encrypt(context, as_key, KRB5_KEYUSAGE_PA_SAM_RESPONSE,
+		NULL, scratch, &sr2.sam_enc_nonce_or_sad);
+   if (retval) {
+	krb5_free_sam_challenge_2(context, sc2);
+	krb5_free_sam_challenge_2_body(context, sc2b);
+	krb5_free_data(context, scratch);
+	krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
+	return(retval);
+   }
+   krb5_free_data(context, scratch);
+   scratch = NULL;
+
+   /* Encode the sam_response_2 */
+   retval = encode_krb5_sam_response_2(&sr2, &scratch);
+   krb5_free_sam_challenge_2(context, sc2);
+   krb5_free_sam_challenge_2_body(context, sc2b);
+   krb5_free_data_contents(context, &sr2.sam_enc_nonce_or_sad.ciphertext);
+
+   if (retval) {
+	return (retval);
+   }
+
+   /* Almost there, just need to make padata !  */
+   sam_padata = malloc(sizeof(krb5_pa_data));
+   if (sam_padata == NULL) {
+	krb5_free_data(context, scratch);
+	return(ENOMEM);
+   }
+
+   sam_padata->magic = KV5M_PA_DATA;
+   sam_padata->pa_type = KRB5_PADATA_SAM_RESPONSE_2;
+   sam_padata->length = scratch->length;
+   sam_padata->contents = (krb5_octet *) scratch->data;
+
+   *out_padata = sam_padata;
+
+   return(0);
+}
+
+static const pa_types_t pa_types[] = {
+    {
+	KRB5_PADATA_PW_SALT,
+	pa_salt,
+	PA_INFO,
+    },
+    {
+	KRB5_PADATA_AFS3_SALT,
+	pa_salt,
+	PA_INFO,
+    },
+    {
+	KRB5_PADATA_ENC_TIMESTAMP,
+	pa_enc_timestamp,
+	PA_REAL,
+    },
+    {
+	KRB5_PADATA_SAM_CHALLENGE_2,
+	pa_sam_2,
+	PA_REAL,
+    },
+    {
+	KRB5_PADATA_SAM_CHALLENGE,
+	pa_sam,
+	PA_REAL,
+    },
+    {
+	-1,
+	NULL,
+	0,
+    },
+};
+
+krb5_error_code
+krb5_do_preauth(krb5_context context,
+		krb5_kdc_req *request,
+		krb5_pa_data **in_padata, krb5_pa_data ***out_padata,
+		krb5_data *salt, krb5_data *s2kparams,
+		krb5_enctype *etype,
+		krb5_keyblock *as_key,
+		krb5_prompter_fct prompter, void *prompter_data,
+		krb5_gic_get_as_key_fct gak_fct, void *gak_data)
+{
+    int h, i, j, out_pa_list_size;
+    int seen_etype_info2 = 0;
+    krb5_pa_data *out_pa = NULL, **out_pa_list = NULL;
+    krb5_data scratch;
+    krb5_etype_info etype_info = NULL;
+    krb5_error_code ret;
+    static const int paorder[] = { PA_INFO, PA_REAL };
+    int realdone;
+
+    if (in_padata == NULL) {
+	*out_padata = NULL;
+	return(0);
+    }
+
+#ifdef DEBUG
+    fprintf (stderr, "salt len=%d", salt->length);
+    if (salt->length > 0)
+	fprintf (stderr, " '%*s'", salt->length, salt->data);
+    fprintf (stderr, "; preauth data types:");
+    for (i = 0; in_padata[i]; i++) {
+	fprintf (stderr, " %d", in_padata[i]->pa_type);
+    }
+    fprintf (stderr, "\n");
+#endif
+
+    out_pa_list = NULL;
+    out_pa_list_size = 0;
+
+    /* first do all the informational preauths, then the first real one */
+
+    for (h=0; h<(sizeof(paorder)/sizeof(paorder[0])); h++) {
+	realdone = 0;
+	for (i=0; in_padata[i] && !realdone; i++) {
+	    int k, l, etype_found, valid_etype_found;
+	    /*
+	     * This is really gross, but is necessary to prevent
+	     * lossge when talking to a 1.0.x KDC, which returns an
+	     * erroneous PA-PW-SALT when it returns a KRB-ERROR
+	     * requiring additional preauth.
+	     */
+	    switch (in_padata[i]->pa_type) {
+	    case KRB5_PADATA_ETYPE_INFO:
+	    case KRB5_PADATA_ETYPE_INFO2:
+	    {
+		krb5_preauthtype pa_type = in_padata[i]->pa_type;
+		if (etype_info) {
+		    if (seen_etype_info2 || pa_type != KRB5_PADATA_ETYPE_INFO2)
+			continue;
+		    if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
+			krb5_free_etype_info( context, etype_info);
+			etype_info = NULL;
+		    }
+		}
+
+		scratch.length = in_padata[i]->length;
+		scratch.data = (char *) in_padata[i]->contents;
+		if (pa_type == KRB5_PADATA_ETYPE_INFO2) {
+		    seen_etype_info2++;
+		    ret = decode_krb5_etype_info2(&scratch, &etype_info);
+		}
+		else ret = decode_krb5_etype_info(&scratch, &etype_info);
+		if (ret) {
+		    ret = 0; /*Ignore error and etype_info element*/
+		    if (etype_info) 
+		      krb5_free_etype_info( context, etype_info);
+		    etype_info = NULL;
+		    continue;
+		}
+		if (etype_info[0] == NULL) {
+		    krb5_free_etype_info(context, etype_info);
+		    etype_info = NULL;
+		    break;
+		}
+		/*
+		 * Select first etype in our request which is also in
+		 * etype-info (preferring client request ktype order).
+		 */
+		for (etype_found = 0, valid_etype_found = 0, k = 0;
+		     !etype_found && k < request->nktypes; k++) {
+		    for (l = 0; etype_info[l]; l++) {
+			if (etype_info[l]->etype == request->ktype[k]) {
+			    etype_found++;
+			    break;
+			}
+			/* check if program has support for this etype for more
+			 * precise error reporting.
+			 */
+			if (valid_enctype(etype_info[l]->etype))
+			    valid_etype_found++;
+		    }
+		}
+		if (!etype_found) {
+		  if (valid_etype_found) {
+			/* supported enctype but not requested */
+		    ret =  KRB5_CONFIG_ETYPE_NOSUPP;
+		    goto cleanup;
+		  }
+		  else {
+		    /* unsupported enctype */
+		    ret =  KRB5_PROG_ETYPE_NOSUPP;
+		    goto cleanup;
+		  }
+
+		}
+		scratch.data = (char *) etype_info[l]->salt;
+		scratch.length = etype_info[l]->length;
+		krb5_free_data_contents(context, salt);
+		if (scratch.length == KRB5_ETYPE_NO_SALT) 
+		  salt->data = NULL;
+		else
+		    if ((ret = krb5int_copy_data_contents( context, &scratch, salt)) != 0)
+		  goto cleanup;
+		*etype = etype_info[l]->etype;
+		krb5_free_data_contents(context, s2kparams);
+		if ((ret = krb5int_copy_data_contents(context,
+						      &etype_info[l]->s2kparams,
+						      s2kparams)) != 0)
+		  goto cleanup;
+#ifdef DEBUG
+		for (j = 0; etype_info[j]; j++) {
+		    krb5_etype_info_entry *e = etype_info[j];
+		    fprintf (stderr, "etype info %d: etype %d salt len=%d",
+			     j, e->etype, e->length);
+		    if (e->length > 0 && e->length != KRB5_ETYPE_NO_SALT)
+			fprintf (stderr, " '%*s'", e->length, e->salt);
+		    fprintf (stderr, "\n");
+		}
+#endif
+		break;
+	    }
+	    case KRB5_PADATA_PW_SALT:
+	    case KRB5_PADATA_AFS3_SALT:
+		if (etype_info)
+		    continue;
+		break;
+	    default:
+		;
+	    }
+	    for (j=0; pa_types[j].type >= 0; j++) {
+		if ((in_padata[i]->pa_type == pa_types[j].type) &&
+		    (pa_types[j].flags & paorder[h])) {
+		    out_pa = NULL;
+
+		    if ((ret = ((*pa_types[j].fct)(context, request,
+						   in_padata[i], &out_pa,
+						   salt, s2kparams, etype, as_key,
+						   prompter, prompter_data,
+						   gak_fct, gak_data)))) {
+		      goto cleanup;
+		    }
+
+		    if (out_pa) {
+			if (out_pa_list == NULL) {
+			    if ((out_pa_list =
+				 (krb5_pa_data **)
+				 malloc(2*sizeof(krb5_pa_data *)))
+				== NULL) {
+			      ret = ENOMEM;
+			      goto cleanup;
+			    }
+			} else {
+			    if ((out_pa_list =
+				 (krb5_pa_data **)
+				 realloc(out_pa_list,
+					 (out_pa_list_size+2)*
+					 sizeof(krb5_pa_data *)))
+				== NULL) {
+			      /* XXX this will leak the pointers which
+				   have already been allocated.  oh well. */
+			      ret = ENOMEM;
+			      goto cleanup;
+			    }
+			}
+			
+			out_pa_list[out_pa_list_size++] = out_pa;
+		    }
+		    if (paorder[h] == PA_REAL)
+			realdone = 1;
+		}
+	    }
+	}
+    }
+
+    if (out_pa_list)
+	out_pa_list[out_pa_list_size++] = NULL;
+
+    *out_padata = out_pa_list;
+    if (etype_info)
+      krb5_free_etype_info(context, etype_info);
+    
+    return(0);
+ cleanup:
+    if (out_pa_list) {
+      out_pa_list[out_pa_list_size++] = NULL;
+      krb5_free_pa_data(context, out_pa_list);
+    }
+    if (etype_info)
+      krb5_free_etype_info(context, etype_info);
+    return (ret);
+}
diff --git a/mechglue/src/lib/krb5/krb/princ_comp.c b/mechglue/src/lib/krb5/krb/princ_comp.c
new file mode 100644
index 000000000..b61f525f4
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/princ_comp.c
@@ -0,0 +1,67 @@
+/*
+ * lib/krb5/krb/princ_comp.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * compare two principals, returning a krb5_boolean true if equal, false if
+ * not.
+ */
+
+#include "k5-int.h"
+
+krb5_boolean KRB5_CALLCONV
+krb5_realm_compare(krb5_context context, krb5_const_principal princ1, krb5_const_principal princ2)
+{
+    if (krb5_princ_realm(context, princ1)->length != 
+	krb5_princ_realm(context, princ2)->length ||
+	memcmp (krb5_princ_realm(context, princ1)->data, 
+	 	krb5_princ_realm(context, princ2)->data,
+		krb5_princ_realm(context, princ2)->length))
+	return FALSE;
+
+    return TRUE;
+}
+
+krb5_boolean KRB5_CALLCONV
+krb5_principal_compare(krb5_context context, krb5_const_principal princ1, krb5_const_principal princ2)
+{
+    register int i;
+    krb5_int32 nelem;
+
+    nelem = krb5_princ_size(context, princ1);
+    if (nelem != krb5_princ_size(context, princ2))
+	return FALSE;
+
+    if (! krb5_realm_compare(context, princ1, princ2))
+	return FALSE;
+
+    for (i = 0; i < (int) nelem; i++) {
+	register const krb5_data *p1 = krb5_princ_component(context, princ1, i);
+	register const krb5_data *p2 = krb5_princ_component(context, princ2, i);
+	if (p1->length != p2->length ||
+	    memcmp(p1->data, p2->data, p1->length))
+	    return FALSE;
+    }
+    return TRUE;
+}
diff --git a/mechglue/src/lib/krb5/krb/rd_cred.c b/mechglue/src/lib/krb5/krb/rd_cred.c
new file mode 100644
index 000000000..a29eb0522
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/rd_cred.c
@@ -0,0 +1,247 @@
+#include "k5-int.h"
+#include "cleanup.h"
+#include "auth_con.h"
+
+#include <stddef.h>           /* NULL */
+#include <stdlib.h>           /* malloc */
+#include <errno.h>            /* ENOMEM */
+
+/*-------------------- decrypt_credencdata --------------------*/
+
+/*
+ * decrypt the enc_part of a krb5_cred
+ */
+static krb5_error_code 
+decrypt_credencdata(krb5_context context, krb5_cred *pcred, krb5_keyblock *pkeyblock, krb5_cred_enc_part *pcredenc)
+{
+    krb5_cred_enc_part  * ppart = NULL;
+    krb5_error_code 	  retval;
+    krb5_data 		  scratch;
+
+    scratch.length = pcred->enc_part.ciphertext.length;
+    if (!(scratch.data = (char *)malloc(scratch.length))) 
+	return ENOMEM;
+
+    if (pkeyblock != NULL) {
+	if ((retval = krb5_c_decrypt(context, pkeyblock,
+				     KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0,
+				     &pcred->enc_part, &scratch)))
+	    goto cleanup;
+    } else {
+	memcpy(scratch.data, pcred->enc_part.ciphertext.data, scratch.length);
+    }
+
+    /*  now decode the decrypted stuff */
+    if ((retval = decode_krb5_enc_cred_part(&scratch, &ppart)))
+    	goto cleanup;
+
+    *pcredenc = *ppart;
+    retval = 0;
+
+cleanup:
+    if (ppart != NULL) {
+	memset(ppart, 0, sizeof(*ppart));
+	krb5_xfree(ppart);
+    }
+    memset(scratch.data, 0, scratch.length);
+    krb5_xfree(scratch.data);
+
+    return retval;
+}
+/*----------------------- krb5_rd_cred_basic -----------------------*/
+
+static krb5_error_code 
+krb5_rd_cred_basic(krb5_context context, krb5_data *pcreddata, krb5_keyblock *pkeyblock, krb5_replay_data *replaydata, krb5_creds ***pppcreds)
+{
+    krb5_error_code       retval;
+    krb5_cred 		* pcred;
+    krb5_int32 		  ncreds;
+    krb5_int32 		  i = 0;
+    krb5_cred_enc_part 	  encpart;
+
+    /* decode cred message */
+    if ((retval = decode_krb5_cred(pcreddata, &pcred)))
+    	return retval;
+
+    memset(&encpart, 0, sizeof(encpart));
+
+    if ((retval = decrypt_credencdata(context, pcred, pkeyblock, &encpart)))
+	goto cleanup_cred;
+
+
+    replaydata->timestamp = encpart.timestamp;
+    replaydata->usec = encpart.usec;
+    replaydata->seq = encpart.nonce;
+
+   /*
+    * Allocate the list of creds.  The memory is allocated so that
+    * krb5_free_tgt_creds can be used to free the list.
+    */
+    for (ncreds = 0; pcred->tickets[ncreds]; ncreds++);
+	
+    if ((*pppcreds = 
+        (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) *
+				       (ncreds + 1)))) == NULL) {
+        retval = ENOMEM;
+        goto cleanup_cred;
+    }
+    (*pppcreds)[0] = NULL;
+
+    /*
+     * For each credential, create a strcture in the list of
+     * credentials and copy the information.
+     */
+    while (i < ncreds) {
+        krb5_cred_info 	* pinfo;
+        krb5_creds 	* pcur;
+	krb5_data	* pdata;
+
+        if ((pcur = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) {
+	    retval = ENOMEM;
+	    goto cleanup;
+        }
+
+        (*pppcreds)[i] = pcur;
+        (*pppcreds)[i+1] = 0;
+        pinfo = encpart.ticket_info[i++];
+        memset(pcur, 0, sizeof(krb5_creds));
+
+        if ((retval = krb5_copy_principal(context, pinfo->client,
+					  &pcur->client)))
+	    goto cleanup;
+
+        if ((retval = krb5_copy_principal(context, pinfo->server,
+					  &pcur->server)))
+	    goto cleanup;
+
+      	if ((retval = krb5_copy_keyblock_contents(context, pinfo->session,
+						  &pcur->keyblock)))
+	    goto cleanup;
+
+        if ((retval = krb5_copy_addresses(context, pinfo->caddrs, 
+					  &pcur->addresses)))
+	    goto cleanup;
+
+        if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata)))
+	    goto cleanup;
+
+	pcur->ticket = *pdata;
+	krb5_xfree(pdata);
+
+
+        pcur->is_skey = FALSE;
+        pcur->magic = KV5M_CREDS;
+        pcur->times = pinfo->times;
+        pcur->ticket_flags = pinfo->flags;
+        pcur->authdata = NULL;   /* not used */
+        memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket));
+    }
+
+    /*
+     * NULL terminate the list
+     */
+    (*pppcreds)[i] = NULL;
+
+cleanup:
+    if (retval)
+	krb5_free_tgt_creds(context, *pppcreds);
+
+cleanup_cred:
+    krb5_free_cred(context, pcred);
+    krb5_free_cred_enc_part(context, &encpart);
+
+    return retval;
+}
+
+/*----------------------- krb5_rd_cred -----------------------*/
+
+#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
+
+/*
+ * This functions takes as input an KRB_CRED message, validates it, and
+ * outputs the nonce and an array of the forwarded credentials.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_rd_cred(krb5_context context, krb5_auth_context auth_context, krb5_data *pcreddata, krb5_creds ***pppcreds, krb5_replay_data *outdata)
+{
+    krb5_error_code       retval;
+    krb5_keyblock       * keyblock;
+    krb5_replay_data      replaydata;
+
+    /* Get keyblock */
+    if ((keyblock = auth_context->recv_subkey) == NULL)
+	keyblock = auth_context->keyblock;
+
+    if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+      (outdata == NULL))
+        /* Need a better error */
+        return KRB5_RC_REQUIRED;
+
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
+      (auth_context->rcache == NULL))
+        return KRB5_RC_REQUIRED;
+
+
+/* If decrypting with the first keyblock we try fails, perhaps the
+ * credentials are stored in the session key so try decrypting with
+    * that.
+*/
+    if ((retval = krb5_rd_cred_basic(context, pcreddata, keyblock,
+				     &replaydata, pppcreds))) {
+	if ((retval = krb5_rd_cred_basic(context, pcreddata,
+					 auth_context->keyblock,
+					 &replaydata, pppcreds))) {
+	    return retval;
+    }
+    }
+    
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+        krb5_donot_replay replay;
+        krb5_timestamp currenttime;
+
+        if ((retval = krb5_timeofday(context, ¤ttime)))
+            goto error;
+
+        if (!in_clock_skew(replaydata.timestamp)) {
+            retval =  KRB5KRB_AP_ERR_SKEW;
+            goto error;
+        }
+
+        if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
+					   "_forw", &replay.client)))
+            goto error;
+
+        replay.server = "";             /* XXX */
+        replay.cusec = replaydata.usec;
+        replay.ctime = replaydata.timestamp;
+        if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
+            krb5_xfree(replay.client);
+            goto error;
+        }
+        krb5_xfree(replay.client);
+    }
+
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+        if (auth_context->remote_seq_number != replaydata.seq) {
+            retval =  KRB5KRB_AP_ERR_BADORDER;
+            goto error;
+        }
+        auth_context->remote_seq_number++;
+    }
+
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
+        outdata->timestamp = replaydata.timestamp;
+        outdata->usec = replaydata.usec;
+        outdata->seq = replaydata.seq;
+    }
+
+error:;
+    if (retval) {
+    	krb5_free_tgt_creds(context, *pppcreds);
+	*pppcreds = NULL;
+    }
+    return retval;
+}
+
diff --git a/mechglue/src/lib/krb5/krb/rd_error.c b/mechglue/src/lib/krb5/krb/rd_error.c
new file mode 100644
index 000000000..e81727c7c
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/rd_error.c
@@ -0,0 +1,49 @@
+/*
+ * lib/krb5/krb/rd_error.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_rd_error() routine
+ */
+
+#include "k5-int.h"
+
+/*
+ *  Parses an error message from enc_errbuf and returns an allocated
+ * structure which contain the error message.
+ *
+ *  Upon return dec_error will point to allocated storage which the
+ * caller should free when finished.
+ * 
+ *  returns system errors
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_rd_error(krb5_context context, const krb5_data *enc_errbuf, krb5_error **dec_error)
+{
+    if (!krb5_is_krb_error(enc_errbuf))
+	return KRB5KRB_AP_ERR_MSG_TYPE;
+    return(decode_krb5_error(enc_errbuf, dec_error));
+}
+
diff --git a/mechglue/src/lib/krb5/krb/rd_priv.c b/mechglue/src/lib/krb5/krb/rd_priv.c
new file mode 100644
index 000000000..cf7480779
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/rd_priv.c
@@ -0,0 +1,272 @@
+/*
+ * lib/krb5/krb/rd_priv.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_rd_priv()
+ */
+
+#include "k5-int.h"
+#include "cleanup.h"
+#include "auth_con.h"
+
+#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
+
+/*
+
+Parses a KRB_PRIV message from inbuf, placing the confidential user
+data in *outbuf.
+
+key specifies the key to be used for decryption of the message.
+ 
+remote_addr and local_addr specify the full
+addresses (host and port) of the sender and receiver.
+
+outbuf points to allocated storage which the caller should
+free when finished.
+
+i_vector is used as an initialization vector for the
+encryption, and if non-NULL its contents are replaced with the last
+block of the encrypted data upon exit.
+
+Returns system errors, integrity errors.
+
+*/
+
+static krb5_error_code
+krb5_rd_priv_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyblock *keyblock, const krb5_address *local_addr, const krb5_address *remote_addr, krb5_pointer i_vector, krb5_replay_data *replaydata, krb5_data *outbuf)
+{
+    krb5_error_code 	  retval;
+    krb5_priv 		* privmsg;
+    krb5_data 		  scratch;
+    krb5_priv_enc_part  * privmsg_enc_part;
+    size_t		  blocksize;
+    krb5_data		  ivdata;
+
+    if (!krb5_is_krb_priv(inbuf))
+	return KRB5KRB_AP_ERR_MSG_TYPE;
+
+    /* decode private message */
+    if ((retval = decode_krb5_priv(inbuf, &privmsg)))
+	return retval;
+    
+    if (i_vector) {
+	if ((retval = krb5_c_block_size(context, keyblock->enctype,
+					&blocksize)))
+	    goto cleanup_privmsg;
+
+	ivdata.length = blocksize;
+	ivdata.data = i_vector;
+    }
+
+    scratch.length = privmsg->enc_part.ciphertext.length;
+    if (!(scratch.data = malloc(scratch.length))) {
+	retval = ENOMEM;
+	goto cleanup_privmsg;
+    }
+
+    if ((retval = krb5_c_decrypt(context, keyblock,
+				 KRB5_KEYUSAGE_KRB_PRIV_ENCPART, 
+				 i_vector?&ivdata:0,
+				 &privmsg->enc_part, &scratch)))
+	goto cleanup_scratch;
+
+    /*  now decode the decrypted stuff */
+    if ((retval = decode_krb5_enc_priv_part(&scratch, &privmsg_enc_part)))
+        goto cleanup_scratch;
+
+    if (!krb5_address_compare(context,remote_addr,privmsg_enc_part->s_address)){
+	retval = KRB5KRB_AP_ERR_BADADDR;
+	goto cleanup_data;
+    }
+    
+    if (privmsg_enc_part->r_address) {
+	if (local_addr) {
+	    if (!krb5_address_compare(context, local_addr,
+				      privmsg_enc_part->r_address)) {
+		retval = KRB5KRB_AP_ERR_BADADDR;
+		goto cleanup_data;
+	    }
+	} else {
+	    krb5_address **our_addrs;
+	
+	    if ((retval = krb5_os_localaddr(context, &our_addrs))) {
+		goto cleanup_data;
+	    }
+	    if (!krb5_address_search(context, privmsg_enc_part->r_address, 
+				     our_addrs)) {
+		krb5_free_addresses(context, our_addrs);
+		retval =  KRB5KRB_AP_ERR_BADADDR;
+		goto cleanup_data;
+	    }
+	    krb5_free_addresses(context, our_addrs);
+	}
+    }
+
+    replaydata->timestamp = privmsg_enc_part->timestamp;
+    replaydata->usec = privmsg_enc_part->usec;
+    replaydata->seq = privmsg_enc_part->seq_number;
+
+    /* everything is ok - return data to the user */
+    *outbuf = privmsg_enc_part->user_data;
+    retval = 0;
+
+cleanup_data:;
+    if (retval == 0)
+	privmsg_enc_part->user_data.data = 0;
+    krb5_free_priv_enc_part(context, privmsg_enc_part);
+
+cleanup_scratch:;
+    memset(scratch.data, 0, scratch.length); 
+    krb5_xfree(scratch.data);
+
+cleanup_privmsg:;
+    krb5_xfree(privmsg->enc_part.ciphertext.data); 
+    krb5_xfree(privmsg);
+
+    return retval;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rd_priv(krb5_context context, krb5_auth_context auth_context, const krb5_data *inbuf, krb5_data *outbuf, krb5_replay_data *outdata)
+{
+    krb5_error_code 	  retval;
+    krb5_keyblock       * keyblock;
+    krb5_replay_data	  replaydata;
+
+    /* Get keyblock */
+    if ((keyblock = auth_context->recv_subkey) == NULL)
+	keyblock = auth_context->keyblock;
+
+    if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+      (outdata == NULL))
+	/* Need a better error */
+	return KRB5_RC_REQUIRED;
+
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
+      (auth_context->rcache == NULL))
+	return KRB5_RC_REQUIRED;
+
+{
+    krb5_address * premote_fulladdr = NULL;
+    krb5_address * plocal_fulladdr = NULL;
+    krb5_address remote_fulladdr;
+    krb5_address local_fulladdr;
+    CLEANUP_INIT(2);
+
+    if (auth_context->local_addr) {
+    	if (auth_context->local_port) {
+            if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr,
+                                 	      auth_context->local_port, 
+					      &local_fulladdr))){
+                CLEANUP_PUSH(local_fulladdr.contents, free);
+	        plocal_fulladdr = &local_fulladdr;
+            } else {
+	        return retval;
+            }
+	} else {
+            plocal_fulladdr = auth_context->local_addr;
+        }
+    }
+
+    if (auth_context->remote_addr) {
+    	if (auth_context->remote_port) {
+            if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr,
+                                 	      auth_context->remote_port, 
+					      &remote_fulladdr))){
+                CLEANUP_PUSH(remote_fulladdr.contents, free);
+	        premote_fulladdr = &remote_fulladdr;
+            } else {
+                CLEANUP_DONE();
+	        return retval;
+            }
+	} else {
+            premote_fulladdr = auth_context->remote_addr;
+        }
+    }
+
+    if ((retval = krb5_rd_priv_basic(context, inbuf, keyblock,
+				     plocal_fulladdr,
+				     premote_fulladdr,
+				     auth_context->i_vector,
+				     &replaydata, outbuf))) {
+	CLEANUP_DONE();
+	return retval;
+    }
+
+    CLEANUP_DONE();
+}
+
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+	krb5_donot_replay replay;
+    	krb5_timestamp currenttime;
+
+	if ((retval = krb5_timeofday(context, ¤ttime)))
+	    goto error;
+
+	if (!in_clock_skew(replaydata.timestamp)) {
+	    retval =  KRB5KRB_AP_ERR_SKEW;
+	    goto error;
+	}
+
+	if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, 
+					   "_priv", &replay.client)))
+	    goto error;
+
+	replay.server = "";		/* XXX */
+	replay.cusec = replaydata.usec;
+	replay.ctime = replaydata.timestamp;
+	if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
+	    krb5_xfree(replay.client);
+	    goto error;
+	}
+	krb5_xfree(replay.client);
+    }
+
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+	if (!krb5int_auth_con_chkseqnum(context, auth_context,
+					replaydata.seq)) {
+	    retval =  KRB5KRB_AP_ERR_BADORDER;
+	    goto error;
+	}
+	auth_context->remote_seq_number++;
+    }
+
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
+	outdata->timestamp = replaydata.timestamp;
+	outdata->usec = replaydata.usec;
+	outdata->seq = replaydata.seq;
+    }
+	
+    /* everything is ok - return data to the user */
+    return 0;
+
+error:;
+    krb5_xfree(outbuf->data);
+    return retval;
+
+}
+
diff --git a/mechglue/src/lib/krb5/krb/rd_rep.c b/mechglue/src/lib/krb5/krb/rd_rep.c
new file mode 100644
index 000000000..6742d8a03
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/rd_rep.c
@@ -0,0 +1,115 @@
+/*
+ * lib/krb5/krb/rd_rep.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_rd_rep()
+ */
+
+#include "k5-int.h"
+#include "auth_con.h"
+
+/*
+ *  Parses a KRB_AP_REP message, returning its contents.
+ * 
+ *  repl is filled in with with a pointer to allocated memory containing
+ * the fields from the encrypted response. 
+ * 
+ *  the key in kblock is used to decrypt the message.
+ * 
+ *  returns system errors, encryption errors, replay errors
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_rd_rep(krb5_context context, krb5_auth_context auth_context, const krb5_data *inbuf, krb5_ap_rep_enc_part **repl)
+{
+    krb5_error_code 	  retval;
+    krb5_ap_rep 	* reply;
+    krb5_data 	 	  scratch;
+
+    if (!krb5_is_ap_rep(inbuf))
+	return KRB5KRB_AP_ERR_MSG_TYPE;
+
+    /* decode it */
+
+    if ((retval = decode_krb5_ap_rep(inbuf, &reply)))
+	return retval;
+
+    /* put together an eblock for this encryption */
+
+    scratch.length = reply->enc_part.ciphertext.length;
+    if (!(scratch.data = malloc(scratch.length))) {
+	krb5_free_ap_rep(context, reply);
+	return(ENOMEM);
+    }
+
+    if ((retval = krb5_c_decrypt(context, auth_context->keyblock,
+				 KRB5_KEYUSAGE_AP_REP_ENCPART, 0,
+				 &reply->enc_part, &scratch)))
+	goto clean_scratch;
+
+    /* now decode the decrypted stuff */
+    retval = decode_krb5_ap_rep_enc_part(&scratch, repl);
+    if (retval)
+	goto clean_scratch;
+
+    /* Check reply fields */
+    if (((*repl)->ctime != auth_context->authentp->ctime) ||
+      ((*repl)->cusec != auth_context->authentp->cusec)) {
+	retval = KRB5_MUTUAL_FAILED;
+	goto clean_scratch;
+    }
+
+    /* Set auth subkey */
+    if ((*repl)->subkey) {
+	if (auth_context->recv_subkey) {
+	    krb5_free_keyblock(context, auth_context->recv_subkey);
+	    auth_context->recv_subkey = NULL;
+	}
+	retval = krb5_copy_keyblock(context, (*repl)->subkey,
+				    &auth_context->recv_subkey);
+	if (retval)
+	    goto clean_scratch;
+	if (auth_context->send_subkey) {
+	    krb5_free_keyblock(context, auth_context->send_subkey);
+	    auth_context->send_subkey = NULL;
+	}
+	retval = krb5_copy_keyblock(context, (*repl)->subkey,
+				    &auth_context->send_subkey);
+	if (retval) {
+	    krb5_free_keyblock(context, auth_context->send_subkey);
+	    auth_context->send_subkey = NULL;
+	}
+    }
+
+    /* Get remote sequence number */
+    auth_context->remote_seq_number = (*repl)->seq_number;
+
+clean_scratch:
+    memset(scratch.data, 0, scratch.length); 
+
+    krb5_free_ap_rep(context, reply);
+    free(scratch.data);
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/rd_req.c b/mechglue/src/lib/krb5/krb/rd_req.c
new file mode 100644
index 000000000..9a2f4589d
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/rd_req.c
@@ -0,0 +1,117 @@
+/*
+ * lib/krb5/krb/rd_req.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_rd_req()
+ */
+
+#include "k5-int.h"
+#include "auth_con.h"
+
+/*
+ *  Parses a KRB_AP_REQ message, returning its contents.
+ * 
+ *  server specifies the expected server's name for the ticket.
+ * 
+ *  keyproc specifies a procedure to generate a decryption key for the
+ *  ticket.  If keyproc is non-NULL, keyprocarg is passed to it, and the result
+ *  used as a decryption key. If keyproc is NULL, then fetchfrom is checked;
+ *  if it is non-NULL, it specifies a parameter name from which to retrieve the
+ *  decryption key.  If fetchfrom is NULL, then the default key store is
+ *  consulted.
+ * 
+ *  returns system errors, encryption errors, replay errors
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_rd_req(krb5_context context, krb5_auth_context *auth_context, const krb5_data *inbuf, krb5_const_principal server, krb5_keytab keytab, krb5_flags *ap_req_options, krb5_ticket **ticket)
+                 	          
+                                     
+                    	         
+                                 	/* XXX do we really need this */
+               		         
+              		                  
+               	           
+{
+    krb5_error_code 	  retval;
+    krb5_ap_req 	* request;
+    krb5_auth_context	  new_auth_context;
+    krb5_keytab           new_keytab = NULL;
+
+    if (!krb5_is_ap_req(inbuf))
+	return KRB5KRB_AP_ERR_MSG_TYPE;
+    if ((retval = decode_krb5_ap_req(inbuf, &request))) {
+    	switch (retval) {
+	case KRB5_BADMSGTYPE:
+	    return KRB5KRB_AP_ERR_BADVERSION; 
+	default:
+	    return(retval);
+	}
+    }
+
+    /* Get an auth context if necessary. */
+    new_auth_context = NULL;
+    if (*auth_context == NULL) {
+	if ((retval = krb5_auth_con_init(context, &new_auth_context)))
+	    goto cleanup_request;
+        *auth_context = new_auth_context;
+    }
+
+    if (!server) {
+	server = request->ticket->server;
+    }
+    /* Get an rcache if necessary. */
+    if (((*auth_context)->rcache == NULL)
+	&& ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME)
+&& server) {
+	if ((retval = krb5_get_server_rcache(context,
+     krb5_princ_component(context,server,0), &(*auth_context)->rcache)))
+	    goto cleanup_auth_context;
+    }
+
+    /* Get a keytab if necessary. */
+    if (keytab == NULL) {
+	if ((retval = krb5_kt_default(context, &new_keytab)))
+	    goto cleanup_auth_context;
+	keytab = new_keytab;
+    }
+
+    retval = krb5_rd_req_decoded(context, auth_context, request, server, 
+				 keytab, ap_req_options, ticket);
+
+    if (new_keytab != NULL)
+        (void) krb5_kt_close(context, new_keytab);
+
+cleanup_auth_context:
+    if (new_auth_context && retval) {
+	krb5_auth_con_free(context, new_auth_context);
+	*auth_context = NULL;
+    }
+
+cleanup_request:
+    krb5_free_ap_req(context, request);
+    return retval;
+}
+
diff --git a/mechglue/src/lib/krb5/krb/rd_req_dec.c b/mechglue/src/lib/krb5/krb/rd_req_dec.c
new file mode 100644
index 000000000..3c398aed1
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/rd_req_dec.c
@@ -0,0 +1,393 @@
+/*
+ * lib/krb5/krb/rd_req_dec.c
+ *
+ * Copyright (c) 1994 CyberSAFE Corporation.
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * Neither M.I.T., the Open Computing Security Group, nor
+ * CyberSAFE Corporation make any representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_rd_req_decoded()
+ */
+
+#include "k5-int.h"
+#include "auth_con.h"
+
+/*
+ * essentially the same as krb_rd_req, but uses a decoded AP_REQ as
+ * the input rather than an encoded input.
+ */
+/*
+ *  Parses a KRB_AP_REQ message, returning its contents.
+ * 
+ *  server specifies the expected server's name for the ticket; if NULL, then
+ *  any server will be accepted if the key can be found, and the caller should
+ *  verify that the principal is something it trusts.
+ * 
+ *  rcache specifies a replay detection cache used to store authenticators and
+ *  server names
+ * 
+ *  keyproc specifies a procedure to generate a decryption key for the
+ *  ticket.  If keyproc is non-NULL, keyprocarg is passed to it, and the result
+ *  used as a decryption key. If keyproc is NULL, then fetchfrom is checked;
+ *  if it is non-NULL, it specifies a parameter name from which to retrieve the
+ *  decryption key.  If fetchfrom is NULL, then the default key store is
+ *  consulted.
+ * 
+ *  authdat is set to point at allocated storage structures; the caller
+ *  should free them when finished. 
+ * 
+ *  returns system errors, encryption errors, replay errors
+ */
+
+static krb5_error_code decrypt_authenticator
+	(krb5_context, const krb5_ap_req *, krb5_authenticator **,
+		   int);
+
+#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
+
+static krb5_error_code
+krb5_rd_req_decrypt_tkt_part(krb5_context context, const krb5_ap_req *req, krb5_keytab keytab)
+{
+    krb5_error_code 	  retval;
+    krb5_enctype 	  enctype;
+    krb5_keytab_entry 	  ktent;
+
+    enctype = req->ticket->enc_part.enctype;
+
+    if ((retval = krb5_kt_get_entry(context, keytab, req->ticket->server,
+				    req->ticket->enc_part.kvno,
+				    enctype, &ktent)))
+	return retval;
+
+    retval = krb5_decrypt_tkt_part(context, &ktent.key, req->ticket);
+    /* Upon error, Free keytab entry first, then return */
+
+    (void) krb5_kt_free_entry(context, &ktent);
+    return retval;
+}
+
+static krb5_error_code
+krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context, const krb5_ap_req *req, krb5_const_principal server, krb5_keytab keytab, krb5_flags *ap_req_options, krb5_ticket **ticket, int check_valid_flag)
+{
+    krb5_error_code 	  retval = 0;
+    krb5_timestamp 	  currenttime;
+
+    if (server && !krb5_principal_compare(context, server, req->ticket->server))
+	return KRB5KRB_AP_WRONG_PRINC;
+
+    /* if (req->ap_options & AP_OPTS_USE_SESSION_KEY)
+       do we need special processing here ?	*/
+
+    /* decrypt the ticket */
+    if ((*auth_context)->keyblock) { /* User to User authentication */
+    	if ((retval = krb5_decrypt_tkt_part(context, (*auth_context)->keyblock,
+					    req->ticket)))
+	    return retval;
+	krb5_free_keyblock(context, (*auth_context)->keyblock);
+	(*auth_context)->keyblock = NULL;
+    } else {
+    	if ((retval = krb5_rd_req_decrypt_tkt_part(context, req, keytab)))
+	    return retval;
+    }
+
+    /* XXX this is an evil hack.  check_valid_flag is set iff the call
+       is not from inside the kdc.  we can use this to determine which
+       key usage to use */
+    if ((retval = decrypt_authenticator(context, req, 
+					&((*auth_context)->authentp),
+					check_valid_flag)))
+	goto cleanup;
+
+    if (!krb5_principal_compare(context, (*auth_context)->authentp->client,
+				req->ticket->enc_part2->client)) {
+	retval = KRB5KRB_AP_ERR_BADMATCH;
+	goto cleanup;
+    }
+
+    if ((*auth_context)->remote_addr && 
+      !krb5_address_search(context, (*auth_context)->remote_addr, 
+			   req->ticket->enc_part2->caddrs)) {
+	retval = KRB5KRB_AP_ERR_BADADDR;
+	goto cleanup;
+    }
+
+    /* okay, now check cross-realm policy */
+
+#if defined(_SINGLE_HOP_ONLY)
+
+    /* Single hop cross-realm tickets only */
+
+    { 
+	krb5_transited *trans = &(req->ticket->enc_part2->transited);
+
+      	/* If the transited list is empty, then we have at most one hop */
+      	if (trans->tr_contents.data && trans->tr_contents.data[0])
+            retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+    }
+
+#elif defined(_NO_CROSS_REALM)
+
+    /* No cross-realm tickets */
+
+    { 
+	char		* lrealm;
+      	krb5_data      	* realm;
+      	krb5_transited 	* trans;
+  
+	realm = krb5_princ_realm(context, req->ticket->enc_part2->client);
+	trans = &(req->ticket->enc_part2->transited);
+
+	/*
+      	 * If the transited list is empty, then we have at most one hop 
+      	 * So we also have to check that the client's realm is the local one 
+	 */
+      	krb5_get_default_realm(context, &lrealm);
+      	if ((trans->tr_contents.data && trans->tr_contents.data[0]) ||
+          strlen(lrealm) != realm->length ||
+          memcmp(lrealm, realm->data, strlen(lrealm))) {
+            retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
+      	}
+      	free(lrealm);
+    }
+
+#else
+
+    /* Hierarchical Cross-Realm */
+  
+    {
+      	krb5_data      * realm;
+      	krb5_transited * trans;
+  
+	realm = krb5_princ_realm(context, req->ticket->enc_part2->client);
+	trans = &(req->ticket->enc_part2->transited);
+
+	/*
+      	 * If the transited list is not empty, then check that all realms 
+      	 * transited are within the hierarchy between the client's realm  
+      	 * and the local realm.                                        
+  	 */
+	if (trans->tr_contents.data && trans->tr_contents.data[0]) {
+	    retval = krb5_check_transited_list(context, &(trans->tr_contents), 
+					       realm,
+					       krb5_princ_realm (context,
+								 server));
+      	}
+    }
+
+#endif
+
+    if (retval)  goto cleanup;
+
+    /* only check rcache if sender has provided one---some services
+       may not be able to use replay caches (such as datagram servers) */
+
+    if ((*auth_context)->rcache) {
+	krb5_donot_replay  rep;
+        krb5_tkt_authent   tktauthent;
+
+	tktauthent.ticket = req->ticket;	
+	tktauthent.authenticator = (*auth_context)->authentp;
+	if (!(retval = krb5_auth_to_rep(context, &tktauthent, &rep))) {
+	    retval = krb5_rc_store(context, (*auth_context)->rcache, &rep);
+	    krb5_xfree(rep.server);
+	    krb5_xfree(rep.client);
+	}
+
+	if (retval)
+	    goto cleanup;
+    }
+
+    retval = krb5_validate_times(context, &req->ticket->enc_part2->times);
+    if (retval != 0)
+	    goto cleanup;
+
+    if ((retval = krb5_timeofday(context, ¤ttime)))
+	goto cleanup;
+
+    if (!in_clock_skew((*auth_context)->authentp->ctime)) {
+	retval = KRB5KRB_AP_ERR_SKEW;
+	goto cleanup;
+    }
+
+    if (check_valid_flag) {
+      if (req->ticket->enc_part2->flags & TKT_FLG_INVALID) {
+	retval = KRB5KRB_AP_ERR_TKT_INVALID;
+	goto cleanup;
+      }
+    }
+
+    /* check if the various etypes are permitted */
+
+    if ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) {
+	/* no etype check needed */;
+    } else if ((*auth_context)->permitted_etypes == NULL) {
+	/* check against the default set */
+	if ((!krb5_is_permitted_enctype(context,
+					req->ticket->enc_part.enctype)) ||
+	    (!krb5_is_permitted_enctype(context,
+					req->ticket->enc_part2->session->enctype)) ||
+	    (((*auth_context)->authentp->subkey) &&
+	     !krb5_is_permitted_enctype(context,
+					(*auth_context)->authentp->subkey->enctype))) {
+	    retval = KRB5_NOPERM_ETYPE;
+	    goto cleanup;
+	}
+    } else {
+	/* check against the set in the auth_context */
+	int i;
+
+	for (i=0; (*auth_context)->permitted_etypes[i]; i++)
+	    if ((*auth_context)->permitted_etypes[i] ==
+		req->ticket->enc_part.enctype)
+		break;
+	if (!(*auth_context)->permitted_etypes[i]) {
+	    retval = KRB5_NOPERM_ETYPE;
+	    goto cleanup;
+	}
+	
+	for (i=0; (*auth_context)->permitted_etypes[i]; i++)
+	    if ((*auth_context)->permitted_etypes[i] ==
+		req->ticket->enc_part2->session->enctype)
+		break;
+	if (!(*auth_context)->permitted_etypes[i]) {
+	    retval = KRB5_NOPERM_ETYPE;
+	    goto cleanup;
+	}
+	
+	if ((*auth_context)->authentp->subkey) {
+	    for (i=0; (*auth_context)->permitted_etypes[i]; i++)
+		if ((*auth_context)->permitted_etypes[i] ==
+		    (*auth_context)->authentp->subkey->enctype)
+		    break;
+	    if (!(*auth_context)->permitted_etypes[i]) {
+		retval = KRB5_NOPERM_ETYPE;
+		goto cleanup;
+	    }
+	}
+    }
+
+    (*auth_context)->remote_seq_number = (*auth_context)->authentp->seq_number;
+    if ((*auth_context)->authentp->subkey) {
+	if ((retval = krb5_copy_keyblock(context,
+					 (*auth_context)->authentp->subkey,
+					 &((*auth_context)->recv_subkey))))
+	    goto cleanup;
+	retval = krb5_copy_keyblock(context, (*auth_context)->authentp->subkey,
+				    &((*auth_context)->send_subkey));
+	if (retval) {
+	    krb5_free_keyblock(context, (*auth_context)->recv_subkey);
+	    (*auth_context)->recv_subkey = NULL;
+	    goto cleanup;
+	}
+    } else {
+	(*auth_context)->recv_subkey = 0;
+	(*auth_context)->send_subkey = 0;
+    }
+
+    if ((retval = krb5_copy_keyblock(context, req->ticket->enc_part2->session,
+				     &((*auth_context)->keyblock))))
+	goto cleanup;
+
+    /*
+     * If not AP_OPTS_MUTUAL_REQUIRED then and sequence numbers are used 
+     * then the default sequence number is the one's complement of the
+     * sequence number sent ot us.
+     */
+    if ((!(req->ap_options & AP_OPTS_MUTUAL_REQUIRED)) && 
+      (*auth_context)->remote_seq_number) {
+	(*auth_context)->local_seq_number ^= 
+	  (*auth_context)->remote_seq_number;
+    }
+
+    if (ticket)
+   	if ((retval = krb5_copy_ticket(context, req->ticket, ticket)))
+	    goto cleanup;
+    if (ap_req_options)
+    	*ap_req_options = req->ap_options;
+    retval = 0;
+    
+cleanup:
+    if (retval) {
+	/* only free if we're erroring out...otherwise some
+	   applications will need the output. */
+        krb5_free_enc_tkt_part(context, req->ticket->enc_part2);
+	req->ticket->enc_part2 = NULL;
+    }
+    return retval;
+}
+
+krb5_error_code
+krb5_rd_req_decoded(krb5_context context, krb5_auth_context *auth_context, const krb5_ap_req *req, krb5_const_principal server, krb5_keytab keytab, krb5_flags *ap_req_options, krb5_ticket **ticket)
+{
+  krb5_error_code retval;
+  retval = krb5_rd_req_decoded_opt(context, auth_context,
+				   req, server, keytab, 
+				   ap_req_options, ticket,
+				   1); /* check_valid_flag */
+  return retval;
+}
+
+krb5_error_code
+krb5_rd_req_decoded_anyflag(krb5_context context, krb5_auth_context *auth_context, const krb5_ap_req *req, krb5_const_principal server, krb5_keytab keytab, krb5_flags *ap_req_options, krb5_ticket **ticket)
+{
+  krb5_error_code retval;
+  retval = krb5_rd_req_decoded_opt(context, auth_context,
+				   req, server, keytab, 
+				   ap_req_options, ticket,
+				   0); /* don't check_valid_flag */
+  return retval;
+}
+
+static krb5_error_code
+decrypt_authenticator(krb5_context context, const krb5_ap_req *request, krb5_authenticator **authpp, int is_ap_req)
+{
+    krb5_authenticator *local_auth;
+    krb5_error_code retval;
+    krb5_data scratch;
+    krb5_keyblock *sesskey;
+
+    sesskey = request->ticket->enc_part2->session;
+
+    scratch.length = request->authenticator.ciphertext.length;
+    if (!(scratch.data = malloc(scratch.length)))
+	return(ENOMEM);
+
+    if ((retval = krb5_c_decrypt(context, sesskey,
+				 is_ap_req?KRB5_KEYUSAGE_AP_REQ_AUTH:
+				 KRB5_KEYUSAGE_TGS_REQ_AUTH, 0,
+				 &request->authenticator, &scratch))) {
+	free(scratch.data);
+	return(retval);
+    }
+
+#define clean_scratch() {memset(scratch.data, 0, scratch.length); \
+free(scratch.data);}
+
+    /*  now decode the decrypted stuff */
+    if (!(retval = decode_krb5_authenticator(&scratch, &local_auth))) {
+	*authpp = local_auth;
+    }
+    clean_scratch();
+    return retval;
+}
+
diff --git a/mechglue/src/lib/krb5/krb/rd_safe.c b/mechglue/src/lib/krb5/krb/rd_safe.c
new file mode 100644
index 000000000..15dc6dccc
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/rd_safe.c
@@ -0,0 +1,275 @@
+/*
+ * lib/krb5/krb/rd_safe.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_rd_safe()
+ */
+
+#include "k5-int.h"
+#include "cleanup.h"
+#include "auth_con.h"
+
+#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
+
+/*
+ parses a KRB_SAFE message from inbuf, placing the integrity-protected user
+ data in *outbuf.
+
+ key specifies the key to be used for decryption of the message.
+ 
+ sender_addr and recv_addr specify the full addresses (host and port) of
+ the sender and receiver.
+
+ outbuf points to allocated storage which the caller should free when finished.
+
+ returns system errors, integrity errors
+ */
+static krb5_error_code
+krb5_rd_safe_basic(krb5_context context, const krb5_data *inbuf, const krb5_keyblock *keyblock, const krb5_address *recv_addr, const krb5_address *sender_addr, krb5_replay_data *replaydata, krb5_data *outbuf)
+{
+    krb5_error_code 	  retval;
+    krb5_safe 		* message;
+    krb5_data safe_body;
+    krb5_checksum our_cksum, *his_cksum;
+    krb5_octet zero_octet = 0;
+    krb5_data *scratch;
+    krb5_boolean valid;
+
+    if (!krb5_is_krb_safe(inbuf))
+	return KRB5KRB_AP_ERR_MSG_TYPE;
+
+    if ((retval = decode_krb5_safe_with_body(inbuf, &message, &safe_body)))
+	return retval;
+
+    if (!krb5_c_valid_cksumtype(message->checksum->checksum_type)) {
+	retval = KRB5_PROG_SUMTYPE_NOSUPP;
+	goto cleanup;
+    }
+    if (!krb5_c_is_coll_proof_cksum(message->checksum->checksum_type) ||
+	!krb5_c_is_keyed_cksum(message->checksum->checksum_type)) {
+	retval = KRB5KRB_AP_ERR_INAPP_CKSUM;
+	goto cleanup;
+    }
+
+    if (!krb5_address_compare(context, sender_addr, message->s_address)) {
+	retval = KRB5KRB_AP_ERR_BADADDR;
+	goto cleanup;
+    }
+
+    if (message->r_address) {
+	if (recv_addr) {
+	    if (!krb5_address_compare(context, recv_addr, message->r_address)) {
+		retval = KRB5KRB_AP_ERR_BADADDR;
+		goto cleanup;
+	    }
+	} else {
+	    krb5_address **our_addrs;
+	
+	    if ((retval = krb5_os_localaddr(context, &our_addrs)))
+		goto cleanup;
+	    
+	    if (!krb5_address_search(context, message->r_address, our_addrs)) {
+		krb5_free_addresses(context, our_addrs);
+		retval = KRB5KRB_AP_ERR_BADADDR;
+		goto cleanup;
+	    }
+	    krb5_free_addresses(context, our_addrs);
+	}
+    }
+
+    /* verify the checksum */
+    /*
+     * In order to recreate what was checksummed, we regenerate the message
+     * without checksum and then have the cryptographic subsystem verify
+     * the checksum for us.  This is because some checksum methods have
+     * a confounder encrypted as part of the checksum.
+     */
+    his_cksum = message->checksum;
+
+    our_cksum.length = 0;
+    our_cksum.checksum_type = 0;
+    our_cksum.contents = &zero_octet;
+
+    message->checksum = &our_cksum;
+
+    if ((retval = encode_krb5_safe_with_body(message, &safe_body, &scratch)))
+	goto cleanup;
+
+    message->checksum = his_cksum;
+			 
+    retval = krb5_c_verify_checksum(context, keyblock,
+				    KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
+				    scratch, his_cksum, &valid);
+
+    (void) memset((char *)scratch->data, 0, scratch->length);
+    krb5_free_data(context, scratch);
+    
+    if (!valid) {
+	/*
+	 * Checksum over only the KRB-SAFE-BODY, like RFC 1510 says, in
+	 * case someone actually implements it correctly.
+	 */
+	retval = krb5_c_verify_checksum(context, keyblock,
+					KRB5_KEYUSAGE_KRB_SAFE_CKSUM,
+					&safe_body, his_cksum, &valid);
+	if (!valid) {
+	    retval = KRB5KRB_AP_ERR_MODIFIED;
+	    goto cleanup;
+	}
+    }
+
+    replaydata->timestamp = message->timestamp;
+    replaydata->usec = message->usec;
+    replaydata->seq = message->seq_number;
+
+    *outbuf = message->user_data;
+    message->user_data.data = NULL;
+    retval = 0;
+    
+cleanup:
+    krb5_free_safe(context, message);
+    return retval;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rd_safe(krb5_context context, krb5_auth_context auth_context, const krb5_data *inbuf, krb5_data *outbuf, krb5_replay_data *outdata)
+{
+    krb5_error_code 	  retval;
+    krb5_keyblock	* keyblock;
+    krb5_replay_data	  replaydata;
+
+    if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
+      (outdata == NULL)) 
+	/* Need a better error */
+	return KRB5_RC_REQUIRED;
+
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
+      (auth_context->rcache == NULL)) 
+	return KRB5_RC_REQUIRED;
+
+    /* Get keyblock */
+    if ((keyblock = auth_context->recv_subkey) == NULL)
+	keyblock = auth_context->keyblock;
+
+{
+    krb5_address * premote_fulladdr = NULL;
+    krb5_address * plocal_fulladdr = NULL;
+    krb5_address remote_fulladdr;
+    krb5_address local_fulladdr;
+    CLEANUP_INIT(2);
+
+    if (auth_context->local_addr) {
+    	if (auth_context->local_port) {
+            if (!(retval = krb5_make_fulladdr(context, auth_context->local_addr,
+                                 	      auth_context->local_port, 
+					      &local_fulladdr))){
+                CLEANUP_PUSH(local_fulladdr.contents, free);
+	        plocal_fulladdr = &local_fulladdr;
+            } else {
+	        return retval;
+            }
+	} else {
+            plocal_fulladdr = auth_context->local_addr;
+        }
+    }
+
+    if (auth_context->remote_addr) {
+    	if (auth_context->remote_port) {
+            if (!(retval = krb5_make_fulladdr(context,auth_context->remote_addr,
+                                 	      auth_context->remote_port, 
+					      &remote_fulladdr))){
+                CLEANUP_PUSH(remote_fulladdr.contents, free);
+	        premote_fulladdr = &remote_fulladdr;
+            } else {
+	        return retval;
+            }
+	} else {
+            premote_fulladdr = auth_context->remote_addr;
+        }
+    }
+
+    if ((retval = krb5_rd_safe_basic(context, inbuf, keyblock,
+				     plocal_fulladdr, premote_fulladdr,
+				     &replaydata, outbuf))) {
+	CLEANUP_DONE();
+	return retval;
+    }
+
+    CLEANUP_DONE();
+}
+
+
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
+	krb5_donot_replay replay;
+    	krb5_timestamp currenttime;
+
+	if ((retval = krb5_timeofday(context, ¤ttime)))
+	    goto error;
+
+	if (!in_clock_skew(replaydata.timestamp)) {
+	    retval =  KRB5KRB_AP_ERR_SKEW;
+	    goto error;
+	}
+
+	if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr, 
+					   "_safe", &replay.client)))
+	    goto error;
+
+	replay.server = "";		/* XXX */
+	replay.cusec = replaydata.usec;
+	replay.ctime = replaydata.timestamp;
+	if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
+	    krb5_xfree(replay.client);
+	    goto error;
+	}
+	krb5_xfree(replay.client);
+    }
+
+    if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
+	if (!krb5int_auth_con_chkseqnum(context, auth_context,
+					replaydata.seq)) {
+	    retval =  KRB5KRB_AP_ERR_BADORDER;
+	    goto error;
+	}
+	auth_context->remote_seq_number++;
+    }
+
+    if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
+      (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
+	outdata->timestamp = replaydata.timestamp;
+	outdata->usec = replaydata.usec;
+	outdata->seq = replaydata.seq;
+    }
+	
+    /* everything is ok - return data to the user */
+    return 0;
+
+error:
+    krb5_xfree(outbuf->data);
+    return retval;
+
+}
+
diff --git a/mechglue/src/lib/krb5/krb/recvauth.c b/mechglue/src/lib/krb5/krb/recvauth.c
new file mode 100644
index 000000000..92bcad7a9
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/recvauth.c
@@ -0,0 +1,266 @@
+/*
+ * lib/krb5/krb/recvauth.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * convenience sendauth/recvauth functions
+ */
+
+#include "k5-int.h"
+#include "auth_con.h"
+#include "com_err.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static const char sendauth_version[] = "KRB5_SENDAUTH_V1.0";
+
+static krb5_error_code
+recvauth_common(krb5_context context,
+		krb5_auth_context * auth_context,
+		/* IN */
+		krb5_pointer fd,
+		char *appl_version,
+		krb5_principal server,
+		krb5_int32 flags,
+		krb5_keytab keytab,
+		/* OUT */
+		krb5_ticket ** ticket,
+		krb5_data *version)
+{
+    krb5_auth_context	  new_auth_context;
+    krb5_flags		  ap_option;
+    krb5_error_code	  retval, problem;
+    krb5_data		  inbuf;
+    krb5_data		  outbuf;
+    krb5_rcache 	  rcache = 0;
+    krb5_octet		  response;
+    krb5_data		  null_server;
+    int                   need_error_free = 0;
+    int			  local_rcache = 0, local_authcon = 0;
+	
+	/*
+	 * Zero out problem variable.  If problem is set at the end of
+	 * the intial version negotiation section, it means that we
+	 * need to send an error code back to the client application
+	 * and exit.
+	 */
+	problem = 0;
+
+	if (!(flags & KRB5_RECVAUTH_SKIP_VERSION)) {
+	    /*
+	     * First read the sendauth version string and check it.
+	     */
+	    if ((retval = krb5_read_message(context, fd, &inbuf)))
+		return(retval);
+	    if (strcmp(inbuf.data, sendauth_version)) {
+		problem = KRB5_SENDAUTH_BADAUTHVERS;
+	    }
+	    krb5_xfree(inbuf.data);
+	}
+	if (flags & KRB5_RECVAUTH_BADAUTHVERS)
+	    problem = KRB5_SENDAUTH_BADAUTHVERS;
+	
+	/*
+	 * Do the same thing for the application version string.
+	 */
+	if ((retval = krb5_read_message(context, fd, &inbuf)))
+		return(retval);
+	if (appl_version && strcmp(inbuf.data, appl_version)) {
+		if (!problem)
+			problem = KRB5_SENDAUTH_BADAPPLVERS;
+	}
+	if (version && !problem)
+	    *version = inbuf;
+	else
+	    krb5_xfree(inbuf.data);
+	/*
+	 * OK, now check the problem variable.  If it's zero, we're
+	 * fine and we can continue.  Otherwise, we have to signal an
+	 * error to the client side and bail out.
+	 */
+	switch (problem) {
+	case 0:
+		response = 0;
+		break;
+	case KRB5_SENDAUTH_BADAUTHVERS:
+		response = 1;
+		break;
+	case KRB5_SENDAUTH_BADAPPLVERS:
+		response = 2;
+		break;
+	default:
+		/*
+		 * Should never happen!
+		 */
+		response = 255;
+#ifdef SENDAUTH_DEBUG
+		fprintf(stderr, "Programming botch in recvauth!  problem = %d",
+			problem);
+		abort();
+#endif
+		break;
+	}
+	/*
+	 * Now we actually write the response.  If the response is non-zero,
+	 * exit with a return value of problem
+	 */
+	if ((krb5_net_write(context, *((int *)fd), (char *)&response, 1)) < 0) {
+		return(problem); /* We'll return the top-level problem */
+	}
+	if (problem)
+	    return(problem);
+
+    /* We are clear of errors here */
+
+    /*
+     * Now, let's read the AP_REQ message and decode it
+     */
+    if ((retval = krb5_read_message(context, fd, &inbuf)))
+        return retval;
+
+    if (*auth_context == NULL) {
+	problem = krb5_auth_con_init(context, &new_auth_context);
+	*auth_context = new_auth_context;
+	local_authcon = 1;
+    }
+    krb5_auth_con_getrcache(context, *auth_context, &rcache);
+    if ((!problem) && rcache == NULL) {
+        /*
+         * Setup the replay cache.
+         */
+        if (server) {
+            problem = krb5_get_server_rcache(context, 
+			krb5_princ_component(context, server, 0), &rcache);
+        } else {
+    	    null_server.length = 7;
+    	    null_server.data = "default";
+    	    problem = krb5_get_server_rcache(context, &null_server, &rcache);
+        }
+        if (!problem) 
+	    problem = krb5_auth_con_setrcache(context, *auth_context, rcache);
+	local_rcache = 1;
+    }
+    if (!problem) {
+	problem = krb5_rd_req(context, auth_context, &inbuf, server,
+			      keytab, &ap_option, ticket);
+	krb5_xfree(inbuf.data);
+    }
+	
+    /*
+     * If there was a problem, send back a krb5_error message,
+     * preceeded by the length of the krb5_error message.  If
+     * everything's ok, send back 0 for the length.
+     */
+    if (problem) {
+	krb5_error	error;
+	const	char *message;
+
+	memset((char *)&error, 0, sizeof(error));
+	krb5_us_timeofday(context, &error.stime, &error.susec);
+	if(server) 
+		error.server = server;
+	else {
+		/* If this fails - ie. ENOMEM we are hosed
+		   we cannot even send the error if we wanted to... */
+		(void) krb5_parse_name(context, "????", &error.server);
+		need_error_free = 1;
+	}
+
+	error.error = problem - ERROR_TABLE_BASE_krb5;
+	if (error.error > 127)
+		error.error = KRB_ERR_GENERIC;
+	message = error_message(problem);
+	error.text.length  = strlen(message) + 1;
+	if (!(error.text.data = malloc(error.text.length))) {
+	    retval = ENOMEM;
+	    goto cleanup;
+	}
+	strcpy(error.text.data, message);
+	if ((retval = krb5_mk_error(context, &error, &outbuf))) {
+	    free(error.text.data);
+	    goto cleanup;
+	}
+	free(error.text.data);
+	if(need_error_free) 
+		krb5_free_principal(context, error.server);
+
+    } else {
+	outbuf.length = 0;
+	outbuf.data = 0;
+    }
+
+    retval = krb5_write_message(context, fd, &outbuf);
+    if (outbuf.data) {
+	krb5_xfree(outbuf.data);
+    	/* We sent back an error, we need cleanup then return */
+    	retval = problem;
+    	goto cleanup;
+    }
+    if (retval)
+	goto cleanup;
+
+    /* Here lies the mutual authentication stuff... */
+    if ((ap_option & AP_OPTS_MUTUAL_REQUIRED)) {
+	if ((retval = krb5_mk_rep(context, *auth_context, &outbuf))) {
+	    return(retval);
+	}
+	retval = krb5_write_message(context, fd, &outbuf);
+	krb5_xfree(outbuf.data);
+    }
+
+cleanup:;
+    if (retval) {
+	if (local_authcon) {
+	    krb5_auth_con_free(context, *auth_context);
+	} else if (local_rcache && rcache != NULL) {
+	    krb5_rc_close(context, rcache);
+	    krb5_auth_con_setrcache(context, *auth_context, NULL);
+	}
+    }
+    return retval;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_recvauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fd, char *appl_version, krb5_principal server, krb5_int32 flags, krb5_keytab keytab, krb5_ticket **ticket)
+{
+    return recvauth_common (context, auth_context, fd, appl_version,
+			    server, flags, keytab, ticket, 0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_recvauth_version(krb5_context context,
+		      krb5_auth_context *auth_context,
+		      /* IN */
+		      krb5_pointer fd,
+		      krb5_principal server,
+		      krb5_int32 flags,
+		      krb5_keytab keytab,
+		      /* OUT */
+		      krb5_ticket **ticket,
+		      krb5_data *version)
+{
+    return recvauth_common (context, auth_context, fd, 0,
+			    server, flags, keytab, ticket, version);
+}
diff --git a/mechglue/src/lib/krb5/krb/send_tgs.c b/mechglue/src/lib/krb5/krb/send_tgs.c
new file mode 100644
index 000000000..8fc60212c
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/send_tgs.c
@@ -0,0 +1,309 @@
+/*
+ * lib/krb5/krb/send_tgs.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_send_tgs()
+ */
+
+#include "k5-int.h"
+
+/*
+ Sends a request to the TGS and waits for a response.
+ options is used for the options in the KRB_TGS_REQ.
+ timestruct values are used for from, till, rtime " " "
+ enctype is used for enctype " " ", and to encrypt the authorization data, 
+ sname is used for sname " " "
+ addrs, if non-NULL, is used for addresses " " "
+ authorization_dat, if non-NULL, is used for authorization_dat " " "
+ second_ticket, if required by options, is used for the 2nd ticket in the req.
+ in_cred is used for the ticket & session key in the KRB_AP_REQ header " " "
+ (the KDC realm is extracted from in_cred->server's realm)
+ 
+ The response is placed into *rep.
+ rep->response.data is set to point at allocated storage which should be
+ freed by the caller when finished.
+
+ returns system errors
+ */
+static krb5_error_code 
+krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cred, krb5_data *outbuf)
+{   
+    krb5_error_code       retval;
+    krb5_checksum         checksum;
+    krb5_authenticator 	  authent;
+    krb5_ap_req 	  request;
+    krb5_data		* scratch;
+    krb5_data           * toutbuf;
+
+    /* Generate checksum */
+    if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype,
+				       &in_cred->keyblock,
+				       KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
+				       in_data, &checksum))) {
+	free(checksum.contents);
+	return(retval);
+    }
+
+    /* gen authenticator */
+    authent.subkey = 0;
+    authent.seq_number = 0;
+    authent.checksum = &checksum;
+    authent.client = in_cred->client;
+    authent.authorization_data = in_cred->authdata;
+    if ((retval = krb5_us_timeofday(context, &authent.ctime,
+				    &authent.cusec))) {
+        free(checksum.contents);
+	return(retval);
+    }
+
+    /* encode the authenticator */
+    if ((retval = encode_krb5_authenticator(&authent, &scratch))) {
+        free(checksum.contents);
+	return(retval);
+    }
+
+    free(checksum.contents);
+
+    request.authenticator.ciphertext.data = 0;
+    request.authenticator.kvno = 0;
+    request.ap_options = 0;
+    request.ticket = 0;
+
+    if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket)))
+	/* Cleanup scratch and scratch data */
+        goto cleanup_data;
+
+    /* call the encryption routine */ 
+    if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
+				      KRB5_KEYUSAGE_TGS_REQ_AUTH,
+				      scratch, &request.authenticator)))
+	goto cleanup_ticket;
+
+    retval = encode_krb5_ap_req(&request, &toutbuf);
+    *outbuf = *toutbuf;
+    krb5_xfree(toutbuf);
+
+
+    memset(request.authenticator.ciphertext.data, 0,
+           request.authenticator.ciphertext.length);
+    free(request.authenticator.ciphertext.data);
+
+cleanup_ticket:
+    krb5_free_ticket(context, request.ticket);
+
+cleanup_data:
+    memset(scratch->data, 0, scratch->length);
+    free(scratch->data);
+
+    free(scratch);
+
+    return retval;
+}
+
+krb5_error_code
+krb5_send_tgs(krb5_context context, krb5_flags kdcoptions,
+	      const krb5_ticket_times *timestruct, const krb5_enctype *ktypes,
+	      krb5_const_principal sname, krb5_address *const *addrs,
+	      krb5_authdata *const *authorization_data,
+	      krb5_pa_data *const *padata, const krb5_data *second_ticket,
+	      krb5_creds *in_cred, krb5_response *rep)
+{
+    krb5_error_code retval;
+    krb5_kdc_req tgsreq;
+    krb5_data *scratch, scratch2;
+    krb5_ticket *sec_ticket = 0;
+    krb5_ticket *sec_ticket_arr[2];
+    krb5_timestamp time_now;
+    krb5_pa_data **combined_padata;
+    krb5_pa_data ap_req_padata;
+    int tcp_only = 0, use_master;
+
+    /* 
+     * in_creds MUST be a valid credential NOT just a partially filled in
+     * place holder for us to get credentials for the caller.
+     */
+    if (!in_cred->ticket.length)
+        return(KRB5_NO_TKT_SUPPLIED);
+
+    memset((char *)&tgsreq, 0, sizeof(tgsreq));
+
+    tgsreq.kdc_options = kdcoptions;
+    tgsreq.server = (krb5_principal) sname;
+
+    tgsreq.from = timestruct->starttime;
+    tgsreq.till = timestruct->endtime ? timestruct->endtime :
+	    in_cred->times.endtime;
+    tgsreq.rtime = timestruct->renew_till;
+    if ((retval = krb5_timeofday(context, &time_now)))
+	return(retval);
+    /* XXX we know they are the same size... */
+    rep->expected_nonce = tgsreq.nonce = (krb5_int32) time_now;
+    rep->request_time = time_now;
+
+    tgsreq.addresses = (krb5_address **) addrs;
+
+    if (authorization_data) {
+	/* need to encrypt it in the request */
+
+	if ((retval = encode_krb5_authdata((const krb5_authdata**)authorization_data,
+					   &scratch)))
+	    return(retval);
+
+	if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
+					  KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
+					  scratch,
+					  &tgsreq.authorization_data))) {
+	    krb5_xfree(tgsreq.authorization_data.ciphertext.data);
+	    krb5_free_data(context, scratch);
+	    return retval;
+	}
+
+	krb5_free_data(context, scratch);
+    }
+
+    /* Get the encryption types list */
+    if (ktypes) {
+	/* Check passed ktypes and make sure they're valid. */
+   	for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
+    	    if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes]))
+		return KRB5_PROG_ETYPE_NOSUPP;
+	}
+    	tgsreq.ktype = (krb5_enctype *)ktypes;
+    } else {
+        /* Get the default ktypes */
+        krb5_get_tgs_ktypes(context, sname, &(tgsreq.ktype));
+	for(tgsreq.nktypes = 0; tgsreq.ktype[tgsreq.nktypes]; tgsreq.nktypes++);
+    }
+
+    if (second_ticket) {
+	if ((retval = decode_krb5_ticket(second_ticket, &sec_ticket)))
+	    goto send_tgs_error_1;
+	sec_ticket_arr[0] = sec_ticket;
+	sec_ticket_arr[1] = 0;
+	tgsreq.second_ticket = sec_ticket_arr;
+    } else
+	tgsreq.second_ticket = 0;
+
+    /* encode the body; then checksum it */
+    if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch)))
+	goto send_tgs_error_2;
+
+    /*
+     * Get an ap_req.
+     */
+    if ((retval = krb5_send_tgs_basic(context, scratch, in_cred, &scratch2))) {
+        krb5_free_data(context, scratch);
+	goto send_tgs_error_2;
+    }
+    krb5_free_data(context, scratch);
+
+    ap_req_padata.pa_type = KRB5_PADATA_AP_REQ;
+    ap_req_padata.length = scratch2.length;
+    ap_req_padata.contents = (krb5_octet *)scratch2.data;
+
+    /* combine in any other supplied padata */
+    if (padata) {
+	krb5_pa_data * const * counter;
+	register unsigned int i = 0;
+	for (counter = padata; *counter; counter++, i++);
+	combined_padata = (krb5_pa_data **)malloc(i+2);
+	if (!combined_padata) {
+	    krb5_xfree(ap_req_padata.contents);
+	    retval = ENOMEM;
+	    goto send_tgs_error_2;
+	}
+	combined_padata[0] = &ap_req_padata;
+	for (i = 1, counter = padata; *counter; counter++, i++)
+	    combined_padata[i] = (krb5_pa_data *) *counter;
+	combined_padata[i] = 0;
+    } else {
+	combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata));
+	if (!combined_padata) {
+	    krb5_xfree(ap_req_padata.contents);
+	    retval = ENOMEM;
+	    goto send_tgs_error_2;
+	}
+	combined_padata[0] = &ap_req_padata;
+	combined_padata[1] = 0;
+    }
+    tgsreq.padata = combined_padata;
+
+    /* the TGS_REQ is assembled in tgsreq, so encode it */
+    if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) {
+	krb5_xfree(ap_req_padata.contents);
+	krb5_xfree(combined_padata);
+	goto send_tgs_error_2;
+    }
+    krb5_xfree(ap_req_padata.contents);
+    krb5_xfree(combined_padata);
+
+    /* now send request & get response from KDC */
+send_again:
+    use_master = 0;
+    retval = krb5_sendto_kdc(context, scratch, 
+			     krb5_princ_realm(context, sname),
+			     &rep->response, &use_master, tcp_only);
+    if (retval == 0) {
+	if (krb5_is_krb_error(&rep->response)) {
+	    if (!tcp_only) {
+		krb5_error *err_reply;
+		retval = decode_krb5_error(&rep->response, &err_reply);
+		if (retval)
+		    goto send_tgs_error_3;
+		if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) {
+		    tcp_only = 1;
+		    krb5_free_error(context, err_reply);
+		    free(rep->response.data);
+		    rep->response.data = 0;
+		    goto send_again;
+		}
+		krb5_free_error(context, err_reply);
+	    send_tgs_error_3:
+		;
+	    }
+	    rep->message_type = KRB5_ERROR;
+	} else if (krb5_is_tgs_rep(&rep->response))
+	    rep->message_type = KRB5_TGS_REP;
+        else /* XXX: assume it's an error */
+	    rep->message_type = KRB5_ERROR;
+    }
+
+    krb5_free_data(context, scratch);
+    
+send_tgs_error_2:;
+    if (sec_ticket) 
+	krb5_free_ticket(context, sec_ticket);
+
+send_tgs_error_1:;
+    if (ktypes == NULL)
+	krb5_xfree(tgsreq.ktype);
+    if (tgsreq.authorization_data.ciphertext.data) {
+	memset(tgsreq.authorization_data.ciphertext.data, 0,
+               tgsreq.authorization_data.ciphertext.length); 
+	krb5_xfree(tgsreq.authorization_data.ciphertext.data);
+    }
+
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/sendauth.c b/mechglue/src/lib/krb5/krb/sendauth.c
new file mode 100644
index 000000000..5b5634307
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/sendauth.c
@@ -0,0 +1,233 @@
+/*
+ * lib/krb5/krb/sendauth.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * convenience sendauth/recvauth functions
+ */
+
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "auth_con.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static const char sendauth_version[] = "KRB5_SENDAUTH_V1.0";
+
+krb5_error_code KRB5_CALLCONV
+krb5_sendauth(krb5_context context, krb5_auth_context *auth_context, krb5_pointer fd, char *appl_version, krb5_principal client, krb5_principal server, krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_ccache ccache, krb5_error **error, krb5_ap_rep_enc_part **rep_result, krb5_creds **out_creds)
+{
+	krb5_octet		result;
+	krb5_creds 		creds;
+	krb5_creds		 * credsp = NULL;
+	krb5_creds		 * credspout = NULL;
+	krb5_error_code		retval = 0;
+	krb5_data		inbuf, outbuf;
+	int			len;
+	krb5_ccache		use_ccache = 0;
+
+	if (error)
+	    *error = 0;
+
+	/*
+	 * First, send over the length of the sendauth version string;
+	 * then, we send over the sendauth version.  Next, we send
+	 * over the length of the application version strings followed
+	 * by the string itself.  
+	 */
+	outbuf.length = strlen(sendauth_version) + 1;
+	outbuf.data = (char *) sendauth_version;
+	if ((retval = krb5_write_message(context, fd, &outbuf)))
+		return(retval);
+	outbuf.length = strlen(appl_version) + 1;
+	outbuf.data = appl_version;
+	if ((retval = krb5_write_message(context, fd, &outbuf)))
+		return(retval);
+	/*
+	 * Now, read back a byte: 0 means no error, 1 means bad sendauth
+	 * version, 2 means bad application version
+	 */
+    if ((len = krb5_net_read(context, *((int *) fd), (char *)&result, 1)) != 1)
+	return((len < 0) ? errno : ECONNABORTED);
+    if (result == 1)
+	return(KRB5_SENDAUTH_BADAUTHVERS);
+    else if (result == 2)
+	return(KRB5_SENDAUTH_BADAPPLVERS);
+    else if (result != 0)
+	return(KRB5_SENDAUTH_BADRESPONSE);
+	/*
+	 * We're finished with the initial negotiations; let's get and
+	 * send over the authentication header.  (The AP_REQ message)
+	 */
+
+	/*
+	 * If no credentials were provided, try getting it from the
+	 * credentials cache.
+	 */
+	memset((char *)&creds, 0, sizeof(creds));
+
+	/*
+	 * See if we need to access the credentials cache
+	 */
+	if (!in_creds || !in_creds->ticket.length) {
+		if (ccache)
+			use_ccache = ccache;
+		else if ((retval = krb5int_cc_default(context, &use_ccache)))
+			goto error_return;
+	}
+	if (!in_creds) {
+		if ((retval = krb5_copy_principal(context, server,
+						  &creds.server)))
+			goto error_return;
+		if (client)
+			retval = krb5_copy_principal(context, client, 
+						     &creds.client);
+		else
+			retval = krb5_cc_get_principal(context, use_ccache,
+						       &creds.client);
+		if (retval) {
+			krb5_free_principal(context, creds.server);
+			goto error_return;
+		}
+		/* creds.times.endtime = 0; -- memset 0 takes care of this
+					zero means "as long as possible" */
+		/* creds.keyblock.enctype = 0; -- as well as this.
+					zero means no session enctype
+					preference */
+		in_creds = &creds;
+	}
+	if (!in_creds->ticket.length) {
+	    if ((retval = krb5_get_credentials(context, 0,
+					       use_ccache, in_creds, &credsp)))
+		    goto error_return;
+	    credspout = credsp;
+	} else {
+	    credsp = in_creds;
+	}
+
+	if (ap_req_options & AP_OPTS_USE_SUBKEY) {
+	    /* Provide some more fodder for random number code.
+	       This isn't strong cryptographically; the point here is
+	       not to guarantee randomness, but to make it less likely
+	       that multiple sessions could pick the same subkey.  */
+	    char rnd_data[1024];
+	    GETPEERNAME_ARG3_TYPE len2;
+	    krb5_data d;
+	    d.length = sizeof (rnd_data);
+	    d.data = rnd_data;
+	    len2 = sizeof (rnd_data);
+	    if (getpeername (*(int*)fd, (GETPEERNAME_ARG2_TYPE *) rnd_data, 
+			     &len2) == 0) {
+		d.length = len2;
+		(void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d);
+	    }
+	    len2 = sizeof (rnd_data);
+	    if (getsockname (*(int*)fd, (GETSOCKNAME_ARG2_TYPE *) rnd_data, 
+			     &len2) == 0) {
+		d.length = len2;
+		(void) krb5_c_random_add_entropy (context, KRB5_C_RANDSOURCE_EXTERNAL_PROTOCOL, &d);
+	    }
+	}
+
+	if ((retval = krb5_mk_req_extended(context, auth_context,
+					   ap_req_options, in_data, credsp,
+					   &outbuf)))
+	    goto error_return;
+
+	/*
+	 * First write the length of the AP_REQ message, then write
+	 * the message itself.
+	 */
+	retval = krb5_write_message(context, fd, &outbuf);
+	free(outbuf.data);
+	if (retval)
+	    goto error_return;
+
+	/*
+	 * Now, read back a message.  If it was a null message (the
+	 * length was zero) then there was no error.  If not, we the
+	 * authentication was rejected, and we need to return the
+	 * error structure.
+	 */
+	if ((retval = krb5_read_message(context, fd, &inbuf)))
+	    goto error_return;
+
+	if (inbuf.length) {
+		if (error) {
+		    if ((retval = krb5_rd_error(context, &inbuf, error))) {
+			krb5_xfree(inbuf.data);
+			goto error_return;
+		    }
+		}
+		retval = KRB5_SENDAUTH_REJECTED;
+		krb5_xfree(inbuf.data);
+		goto error_return;
+	}
+	
+	/*
+	 * If we asked for mutual authentication, we should now get a
+	 * length field, followed by a AP_REP message
+	 */
+	if ((ap_req_options & AP_OPTS_MUTUAL_REQUIRED)) {
+	    krb5_ap_rep_enc_part	*repl = 0;
+		
+	    if ((retval = krb5_read_message(context, fd, &inbuf)))
+		goto error_return;
+
+	    if ((retval = krb5_rd_rep(context, *auth_context, &inbuf,
+				      &repl))) {
+		if (repl)
+		    krb5_free_ap_rep_enc_part(context, repl);
+	        krb5_xfree(inbuf.data);
+		goto error_return;
+	    }
+
+	    krb5_xfree(inbuf.data);
+	    /*
+	     * If the user wants to look at the AP_REP message,
+	     * copy it for him
+	     */
+	    if (rep_result) 
+		*rep_result = repl;
+	    else
+		krb5_free_ap_rep_enc_part(context, repl);
+	}
+	retval = 0;		/* Normal return */
+	if (out_creds) {
+	    *out_creds = credsp;
+	    credspout = NULL;
+	}
+
+error_return:
+    krb5_free_cred_contents(context, &creds);
+    if (credspout != NULL)
+	krb5_free_creds(context, credspout); 
+    if (!ccache && use_ccache)
+	krb5_cc_close(context, use_ccache);
+    return(retval);
+}
+
+
diff --git a/mechglue/src/lib/krb5/krb/ser_actx.c b/mechglue/src/lib/krb5/krb/ser_actx.c
new file mode 100644
index 000000000..32519e19f
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_actx.c
@@ -0,0 +1,563 @@
+/*
+ * lib/krb5/krb/ser_actx.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_actx.c - Serialize krb5_auth_context structure.
+ */
+#include "k5-int.h"
+#include "int-proto.h"
+#include "auth_con.h"
+
+#define	TOKEN_RADDR	950916
+#define	TOKEN_RPORT	950917
+#define	TOKEN_LADDR	950918
+#define	TOKEN_LPORT	950919
+#define	TOKEN_KEYBLOCK	950920
+#define	TOKEN_LSKBLOCK	950921
+#define	TOKEN_RSKBLOCK	950922
+
+/*
+ * Routines to deal with externalizing the krb5_auth_context:
+ *	krb5_auth_context_size();
+ *	krb5_auth_context_externalize();
+ *	krb5_auth_context_internalize();
+ */
+static krb5_error_code krb5_auth_context_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_auth_context_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_auth_context_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/*
+ * Other metadata serialization initializers.
+ */
+
+/* Local data */
+static const krb5_ser_entry krb5_auth_context_ser_entry = {
+    KV5M_AUTH_CONTEXT,			/* Type			*/
+    krb5_auth_context_size,		/* Sizer routine	*/
+    krb5_auth_context_externalize,	/* Externalize routine	*/
+    krb5_auth_context_internalize	/* Internalize routine	*/
+};
+
+/*
+ * krb5_auth_context_size()	- Determine the size required to externalize
+ *				  the krb5_auth_context.
+ */
+static krb5_error_code
+krb5_auth_context_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_auth_context	auth_context;
+    size_t		required;
+
+    /*
+     * krb5_auth_context requires at minimum:
+     *	krb5_int32		for KV5M_AUTH_CONTEXT
+     *	krb5_int32		for auth_context_flags
+     *	krb5_int32		for remote_seq_number
+     *	krb5_int32		for local_seq_number
+     *	krb5_int32		for req_cksumtype
+     *	krb5_int32		for safe_cksumtype
+     *	krb5_int32		for size of i_vector
+     *	krb5_int32		for KV5M_AUTH_CONTEXT
+     */
+    kret = EINVAL;
+    if ((auth_context = (krb5_auth_context) arg)) {
+	kret = 0;
+
+	/* Calculate size required by i_vector - ptooey */
+	if (auth_context->i_vector && auth_context->keyblock) {
+	    kret = krb5_c_block_size(kcontext, auth_context->keyblock->enctype,
+				     &required);
+	} else {
+	    required = 0;
+	}
+
+	required += sizeof(krb5_int32)*8;
+
+	/* Calculate size required by remote_addr, if appropriate */
+	if (!kret && auth_context->remote_addr) {
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_ADDRESS,
+				    (krb5_pointer) auth_context->remote_addr,
+				    &required);
+	    if (!kret)
+		required += sizeof(krb5_int32);
+	}
+
+	/* Calculate size required by remote_port, if appropriate */
+	if (!kret && auth_context->remote_port) {
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_ADDRESS,
+				    (krb5_pointer) auth_context->remote_port,
+				    &required);
+	    if (!kret)
+		required += sizeof(krb5_int32);
+	}
+
+	/* Calculate size required by local_addr, if appropriate */
+	if (!kret && auth_context->local_addr) {
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_ADDRESS,
+				    (krb5_pointer) auth_context->local_addr,
+				    &required);
+	    if (!kret)
+		required += sizeof(krb5_int32);
+	}
+
+	/* Calculate size required by local_port, if appropriate */
+	if (!kret && auth_context->local_port) {
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_ADDRESS,
+				    (krb5_pointer) auth_context->local_port,
+				    &required);
+	    if (!kret)
+		required += sizeof(krb5_int32);
+	}
+
+	/* Calculate size required by keyblock, if appropriate */
+	if (!kret && auth_context->keyblock) {
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) auth_context->keyblock,
+				    &required);
+	    if (!kret)
+		required += sizeof(krb5_int32);
+	}
+
+	/* Calculate size required by send_subkey, if appropriate */
+	if (!kret && auth_context->send_subkey) {
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) auth_context->send_subkey,
+				    &required);
+	    if (!kret)
+		required += sizeof(krb5_int32);
+	}
+
+	/* Calculate size required by recv_subkey, if appropriate */
+	if (!kret && auth_context->recv_subkey) {
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) auth_context->recv_subkey,
+				    &required);
+	    if (!kret)
+		required += sizeof(krb5_int32);
+	}
+
+	/* Calculate size required by authentp, if appropriate */
+	if (!kret && auth_context->authentp)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_AUTHENTICATOR,
+				    (krb5_pointer) auth_context->authentp,
+				    &required);
+
+    }
+    if (!kret)
+	*sizep += required;
+    return(kret);
+}
+
+/*
+ * krb5_auth_context_externalize()	- Externalize the krb5_auth_context.
+ */
+static krb5_error_code
+krb5_auth_context_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_auth_context	auth_context;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+    size_t              obuf;
+    krb5_int32		obuf32;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((auth_context = (krb5_auth_context) arg)) {
+	kret = ENOMEM;
+	if (!krb5_auth_context_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+
+	    /* Write fixed portion */
+	    (void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
+	    (void) krb5_ser_pack_int32(auth_context->auth_context_flags,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32(auth_context->remote_seq_number,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32(auth_context->local_seq_number,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) auth_context->req_cksumtype,
+				       &bp, &remain);
+	    (void) krb5_ser_pack_int32((krb5_int32) auth_context->safe_cksumtype,
+				       &bp, &remain);
+
+	    kret = 0;
+
+	    /* Now figure out the number of bytes for i_vector and write it */
+	    if (auth_context->i_vector) {
+		kret = krb5_c_block_size(kcontext,
+					 auth_context->keyblock->enctype,
+					 &obuf);
+	    } else {
+		obuf = 0;
+	    }
+
+	    /* Convert to signed 32 bit integer */
+	    obuf32 = obuf;
+	    if (kret == 0 && obuf != obuf32)
+		kret = EINVAL;
+	    if (!kret)
+		(void) krb5_ser_pack_int32(obuf32, &bp, &remain);
+
+	    /* Now copy i_vector */
+	    if (!kret && auth_context->i_vector)
+		(void) krb5_ser_pack_bytes(auth_context->i_vector,
+					   obuf,
+					   &bp, &remain);
+
+	    /* Now handle remote_addr, if appropriate */
+	    if (!kret && auth_context->remote_addr) {
+		(void) krb5_ser_pack_int32(TOKEN_RADDR, &bp, &remain);
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_ADDRESS,
+					       (krb5_pointer)
+					       auth_context->remote_addr,
+					       &bp,
+					       &remain);
+	    }
+
+	    /* Now handle remote_port, if appropriate */
+	    if (!kret && auth_context->remote_port) {
+		(void) krb5_ser_pack_int32(TOKEN_RPORT, &bp, &remain);
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_ADDRESS,
+					       (krb5_pointer)
+					       auth_context->remote_addr,
+					       &bp,
+					       &remain);
+	    }
+
+	    /* Now handle local_addr, if appropriate */
+	    if (!kret && auth_context->local_addr) {
+		(void) krb5_ser_pack_int32(TOKEN_LADDR, &bp, &remain);
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_ADDRESS,
+					       (krb5_pointer)
+					       auth_context->local_addr,
+					       &bp,
+					       &remain);
+	    }
+
+	    /* Now handle local_port, if appropriate */
+	    if (!kret && auth_context->local_port) {
+		(void) krb5_ser_pack_int32(TOKEN_LPORT, &bp, &remain);
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_ADDRESS,
+					       (krb5_pointer)
+					       auth_context->local_addr,
+					       &bp,
+					       &remain);
+	    }
+
+	    /* Now handle keyblock, if appropriate */
+	    if (!kret && auth_context->keyblock) {
+		(void) krb5_ser_pack_int32(TOKEN_KEYBLOCK, &bp, &remain);
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer)
+					       auth_context->keyblock,
+					       &bp,
+					       &remain);
+	    }
+
+	    /* Now handle subkey, if appropriate */
+	    if (!kret && auth_context->send_subkey) {
+		(void) krb5_ser_pack_int32(TOKEN_LSKBLOCK, &bp, &remain);
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer)
+					       auth_context->send_subkey,
+					       &bp,
+					       &remain);
+	    }
+
+	    /* Now handle subkey, if appropriate */
+	    if (!kret && auth_context->recv_subkey) {
+		(void) krb5_ser_pack_int32(TOKEN_RSKBLOCK, &bp, &remain);
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer)
+					       auth_context->recv_subkey,
+					       &bp,
+					       &remain);
+	    }
+
+	    /* Now handle authentp, if appropriate */
+	    if (!kret && auth_context->authentp)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_AUTHENTICATOR,
+					       (krb5_pointer)
+					       auth_context->authentp,
+					       &bp,
+					       &remain);
+
+	    /*
+	     * If we were successful, write trailer then update the pointer and
+	     * remaining length;
+	     */
+	    if (!kret) {
+		/* Write our trailer */
+		(void) krb5_ser_pack_int32(KV5M_AUTH_CONTEXT, &bp, &remain);
+		*buffer = bp;
+		*lenremain = remain;
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_auth_context_internalize()	- Internalize the krb5_auth_context.
+ */
+static krb5_error_code
+krb5_auth_context_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_auth_context	auth_context;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    krb5_int32		ivlen;
+    krb5_int32		tag;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_AUTH_CONTEXT) {
+	kret = ENOMEM;
+
+	/* Get memory for the auth_context */
+	if ((remain >= (5*sizeof(krb5_int32))) &&
+	    (auth_context = (krb5_auth_context)
+	     malloc(sizeof(struct _krb5_auth_context)))) {
+	    memset(auth_context, 0, sizeof(struct _krb5_auth_context));
+
+	    /* Get auth_context_flags */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->auth_context_flags = ibuf;
+
+	    /* Get remote_seq_number */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->remote_seq_number = ibuf;
+
+	    /* Get local_seq_number */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->local_seq_number = ibuf;
+
+	    /* Get req_cksumtype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->req_cksumtype = (krb5_cksumtype) ibuf;
+
+	    /* Get safe_cksumtype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->safe_cksumtype = (krb5_cksumtype) ibuf;
+
+	    /* Get length of i_vector */
+	    (void) krb5_ser_unpack_int32(&ivlen, &bp, &remain);
+
+	    if (ivlen) {
+		if ((auth_context->i_vector =
+		     (krb5_pointer) malloc((size_t)ivlen)))
+		    kret = krb5_ser_unpack_bytes(auth_context->i_vector,
+						 (size_t) ivlen,
+						 &bp,
+						 &remain);
+		else
+		    kret = ENOMEM;
+	    }
+	    else
+		kret = 0;
+	    
+	    /* Peek at next token */
+	    tag = 0;
+	    if (!kret)
+		kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+
+	    /* This is the remote_addr */
+	    if (!kret && (tag == TOKEN_RADDR)) {
+		if (!(kret = krb5_internalize_opaque(kcontext,
+						     KV5M_ADDRESS,
+						     (krb5_pointer *)
+						     &auth_context->
+						     remote_addr,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the remote_port */
+	    if (!kret && (tag == TOKEN_RPORT)) {
+		if (!(kret = krb5_internalize_opaque(kcontext,
+						     KV5M_ADDRESS,
+						     (krb5_pointer *)
+						     &auth_context->
+						     remote_port,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the local_addr */
+	    if (!kret && (tag == TOKEN_LADDR)) {
+		if (!(kret = krb5_internalize_opaque(kcontext,
+						     KV5M_ADDRESS,
+						     (krb5_pointer *)
+						     &auth_context->
+						     local_addr,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the local_port */
+	    if (!kret && (tag == TOKEN_LPORT)) {
+		if (!(kret = krb5_internalize_opaque(kcontext,
+						     KV5M_ADDRESS,
+						     (krb5_pointer *)
+						     &auth_context->
+						     local_port,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the keyblock */
+	    if (!kret && (tag == TOKEN_KEYBLOCK)) {
+		if (!(kret = krb5_internalize_opaque(kcontext,
+						     KV5M_KEYBLOCK,
+						     (krb5_pointer *)
+						     &auth_context->keyblock,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the send_subkey */
+	    if (!kret && (tag == TOKEN_LSKBLOCK)) {
+		if (!(kret = krb5_internalize_opaque(kcontext,
+						     KV5M_KEYBLOCK,
+						     (krb5_pointer *)
+						     &auth_context->
+						     send_subkey,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the recv_subkey */
+	    if (!kret) {
+		if (tag == TOKEN_RSKBLOCK) {
+		    kret = krb5_internalize_opaque(kcontext,
+						   KV5M_KEYBLOCK,
+						   (krb5_pointer *)
+						   &auth_context->
+						   recv_subkey,
+						   &bp,
+						   &remain);
+		}
+		else {
+		    /*
+		     * We read the next tag, but it's not of any use here, so
+		     * we effectively 'unget' it here.
+		     */
+		    bp -= sizeof(krb5_int32);
+		    remain += sizeof(krb5_int32);
+		}
+	    }
+
+	    /* Now find the authentp */
+	    if (!kret) {
+		if ((kret = krb5_internalize_opaque(kcontext,
+						    KV5M_AUTHENTICATOR,
+						    (krb5_pointer *)
+						    &auth_context->authentp,
+						    &bp,
+						    &remain))) {
+		    if (kret == EINVAL)
+			kret = 0;
+		}
+	    }
+
+	    /* Finally, find the trailer */
+	    if (!kret) {
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		if (!kret && (ibuf != KV5M_AUTH_CONTEXT))
+		    kret = EINVAL;
+	    }
+	    if (!kret) {
+		*buffer = bp;
+		*lenremain = remain;
+		auth_context->magic = KV5M_AUTH_CONTEXT;
+		*argp = (krb5_pointer) auth_context;
+	    }
+	    else
+		krb5_auth_con_free(kcontext, auth_context);
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the auth_context serializer.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_auth_context_init(krb5_context kcontext)
+{
+    krb5_error_code	kret;
+    kret = krb5_register_serializer(kcontext, &krb5_auth_context_ser_entry);
+    if (!kret)
+	kret = krb5_ser_authdata_init(kcontext);
+    if (!kret)
+	kret = krb5_ser_address_init(kcontext);
+    if (!kret)
+	kret = krb5_ser_authenticator_init(kcontext);
+    if (!kret)
+	kret = krb5_ser_checksum_init(kcontext);
+    if (!kret)
+	kret = krb5_ser_keyblock_init(kcontext);
+    if (!kret)
+	kret = krb5_ser_principal_init(kcontext);
+    return(kret);
+}
diff --git a/mechglue/src/lib/krb5/krb/ser_adata.c b/mechglue/src/lib/krb5/krb/ser_adata.c
new file mode 100644
index 000000000..ebd4c3e10
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_adata.c
@@ -0,0 +1,199 @@
+/*
+ * lib/krb5/krb/ser_adata.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_adata.c - Serialize a krb5_authdata structure.
+ */
+#include "k5-int.h"
+#include "int-proto.h"
+
+/*
+ * Routines to deal with externalizing the krb5_authdata:
+ *	krb5_authdata_size();
+ *	krb5_authdata_externalize();
+ *	krb5_authdata_internalize();
+ */
+static krb5_error_code krb5_authdata_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_authdata_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_authdata_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/* Local data */
+static const krb5_ser_entry krb5_authdata_ser_entry = {
+    KV5M_AUTHDATA,			/* Type			*/
+    krb5_authdata_size,			/* Sizer routine	*/
+    krb5_authdata_externalize,		/* Externalize routine	*/
+    krb5_authdata_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_authdata_esize()	- Determine the size required to externalize
+ *				  the krb5_authdata.
+ */
+static krb5_error_code
+krb5_authdata_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_authdata	*authdata;
+
+    /*
+     * krb5_authdata requires:
+     *	krb5_int32		for KV5M_AUTHDATA
+     *	krb5_int32		for ad_type
+     *	krb5_int32		for length
+     *	authdata->length	for contents
+     *	krb5_int32		for KV5M_AUTHDATA
+     */
+    kret = EINVAL;
+    if ((authdata = (krb5_authdata *) arg)) {
+	*sizep += (sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   (size_t) authdata->length);
+	kret = 0;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_authdata_externalize()	- Externalize the krb5_authdata.
+ */
+static krb5_error_code
+krb5_authdata_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_authdata	*authdata;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((authdata = (krb5_authdata *) arg)) {
+	kret = ENOMEM;
+	if (!krb5_authdata_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KV5M_AUTHDATA, &bp, &remain);
+		
+	    /* Our ad_type */
+	    (void) krb5_ser_pack_int32((krb5_int32) authdata->ad_type,
+				       &bp, &remain);
+
+	    /* Our length */
+	    (void) krb5_ser_pack_int32((krb5_int32) authdata->length,
+				       &bp, &remain);
+
+	    /* Our contents */
+	    (void) krb5_ser_pack_bytes(authdata->contents,
+				       (size_t) authdata->length,
+				       &bp, &remain);
+
+	    /* Finally, our trailer */
+	    (void) krb5_ser_pack_int32(KV5M_AUTHDATA, &bp, &remain);
+	    kret = 0;
+	    *buffer = bp;
+	    *lenremain = remain;
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_authdata_internalize()	- Internalize the krb5_authdata.
+ */
+static krb5_error_code
+krb5_authdata_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_authdata	*authdata;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_AUTHDATA) {
+	kret = ENOMEM;
+
+	/* Get a authdata */
+	if ((remain >= (2*sizeof(krb5_int32))) &&
+	    (authdata = (krb5_authdata *) malloc(sizeof(krb5_authdata)))) {
+	    memset(authdata, 0, sizeof(krb5_authdata));
+
+	    /* Get the ad_type */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authdata->ad_type = (krb5_authdatatype) ibuf;
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authdata->length = (int) ibuf;
+
+	    /* Get the string */
+	    if ((authdata->contents = (krb5_octet *)
+		 malloc((size_t) (ibuf))) &&
+		!(kret = krb5_ser_unpack_bytes(authdata->contents,
+					       (size_t) ibuf,
+					       &bp, &remain))) {
+		if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+		    ibuf = 0;
+		if (ibuf == KV5M_AUTHDATA) {
+		    authdata->magic = KV5M_AUTHDATA;
+		    *buffer = bp;
+		    *lenremain = remain;
+		    *argp = (krb5_pointer) authdata;
+		}
+		else
+		    kret = EINVAL;
+	    }
+	    if (kret) {
+		if (authdata->contents)
+		    free(authdata->contents);
+		free(authdata);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the authdata serializer.
+ */
+krb5_error_code
+krb5_ser_authdata_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_authdata_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5/krb/ser_addr.c b/mechglue/src/lib/krb5/krb/ser_addr.c
new file mode 100644
index 000000000..079cc0fda
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_addr.c
@@ -0,0 +1,203 @@
+/*
+ * lib/krb5/krb/ser_addr.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_addr.c - Serialize a krb5_address structure.
+ */
+#include "k5-int.h"
+#include "int-proto.h"
+
+/*
+ * Routines to deal with externalizing the krb5_address:
+ *	krb5_address_size();
+ *	krb5_address_externalize();
+ *	krb5_address_internalize();
+ */
+static krb5_error_code krb5_address_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_address_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_address_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/* Local data */
+static const krb5_ser_entry krb5_address_ser_entry = {
+    KV5M_ADDRESS,			/* Type			*/
+    krb5_address_size,		/* Sizer routine	*/
+    krb5_address_externalize,		/* Externalize routine	*/
+    krb5_address_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_address_size()	- Determine the size required to externalize
+ *				  the krb5_address.
+ */
+static krb5_error_code
+krb5_address_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_address	*address;
+
+    /*
+     * krb5_address requires:
+     *	krb5_int32		for KV5M_ADDRESS
+     *	krb5_int32		for addrtype
+     *	krb5_int32		for length
+     *	address->length		for contents
+     *	krb5_int32		for KV5M_ADDRESS
+     */
+    kret = EINVAL;
+    if ((address = (krb5_address *) arg)) {
+	*sizep += (sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   (size_t) address->length);
+	kret = 0;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_address_externalize()	- Externalize the krb5_address.
+ */
+static krb5_error_code
+krb5_address_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_address	*address;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((address = (krb5_address *) arg)) {
+	kret = ENOMEM;
+	if (!krb5_address_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KV5M_ADDRESS, &bp, &remain);
+		
+	    /* Our addrtype */
+	    (void) krb5_ser_pack_int32((krb5_int32) address->addrtype,
+				       &bp, &remain);
+
+	    /* Our length */
+	    (void) krb5_ser_pack_int32((krb5_int32) address->length,
+				       &bp, &remain);
+
+	    /* Our contents */
+	    (void) krb5_ser_pack_bytes(address->contents,
+				       (size_t) address->length,
+				       &bp, &remain);
+
+	    /* Finally, our trailer */
+	    (void) krb5_ser_pack_int32(KV5M_ADDRESS, &bp, &remain);
+
+	    kret = 0;
+	    *buffer = bp;
+	    *lenremain = remain;
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_address_internalize()	- Internalize the krb5_address.
+ */
+static krb5_error_code
+krb5_address_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_address	*address;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_ADDRESS) {
+	kret = ENOMEM;
+
+	/* Get a address */
+	if ((remain >= (2*sizeof(krb5_int32))) &&
+	    (address = (krb5_address *) malloc(sizeof(krb5_address)))) {
+	    memset(address, 0, sizeof(krb5_address));
+
+	    address->magic = KV5M_ADDRESS;
+
+	    /* Get the addrtype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    address->addrtype = (krb5_addrtype) ibuf;
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    address->length = (int) ibuf;
+
+	    /* Get the string */
+	    if ((address->contents = (krb5_octet *) malloc((size_t) (ibuf))) &&
+		!(kret = krb5_ser_unpack_bytes(address->contents,
+					       (size_t) ibuf,
+					       &bp, &remain))) {
+		/* Get the trailer */
+		if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+		    ibuf = 0;
+
+		if (!kret && (ibuf == KV5M_ADDRESS)) {
+		    address->magic = KV5M_ADDRESS;
+		    *buffer = bp;
+		    *lenremain = remain;
+		    *argp = (krb5_pointer) address;
+		}
+		else
+		    kret = EINVAL;
+	    }
+	    if (kret) {
+		if (address->contents)
+		    free(address->contents);
+		free(address);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the address serializer.
+ */
+krb5_error_code
+krb5_ser_address_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_address_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5/krb/ser_auth.c b/mechglue/src/lib/krb5/krb/ser_auth.c
new file mode 100644
index 000000000..814028e27
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_auth.c
@@ -0,0 +1,350 @@
+/*
+ * lib/krb5/krb/ser_auth.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_auth.c - Serialize krb5_authenticator structure.
+ */
+#include "k5-int.h"
+#include "int-proto.h"
+
+/*
+ * Routines to deal with externalizing the krb5_authenticator:
+ *	krb5_authenticator_size();
+ *	krb5_authenticator_externalize();
+ *	krb5_authenticator_internalize();
+ */
+static krb5_error_code krb5_authenticator_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_authenticator_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_authenticator_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/* Local data */
+static const krb5_ser_entry krb5_authenticator_ser_entry = {
+    KV5M_AUTHENTICATOR,			/* Type			*/
+    krb5_authenticator_size,		/* Sizer routine	*/
+    krb5_authenticator_externalize,	/* Externalize routine	*/
+    krb5_authenticator_internalize	/* Internalize routine	*/
+};
+
+/*
+ * krb5_authenticator_size()	- Determine the size required to externalize
+ *				  the krb5_authenticator.
+ */
+static krb5_error_code
+krb5_authenticator_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_authenticator	*authenticator;
+    size_t		required;
+
+    /*
+     * krb5_authenticator requires at minimum:
+     *	krb5_int32		for KV5M_AUTHENTICATOR
+     *	krb5_int32		for seconds
+     *	krb5_int32		for cusec
+     *	krb5_int32		for seq_number
+     *	krb5_int32		for number in authorization_data array.
+     *	krb5_int32		for KV5M_AUTHENTICATOR
+     */
+    kret = EINVAL;
+    if ((authenticator = (krb5_authenticator *) arg)) {
+	required = sizeof(krb5_int32)*6;
+
+	/* Calculate size required by client, if appropriate */
+	if (authenticator->client)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_PRINCIPAL,
+				    (krb5_pointer) authenticator->client,
+				    &required);
+	else
+	    kret = 0;
+
+	/* Calculate size required by checksum, if appropriate */
+	if (!kret && authenticator->checksum)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_CHECKSUM,
+				    (krb5_pointer) authenticator->checksum,
+				    &required);
+
+	/* Calculate size required by subkey, if appropriate */
+	if (!kret && authenticator->subkey)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) authenticator->subkey,
+				    &required);
+
+	/* Calculate size required by authorization_data, if appropriate */
+	if (!kret && authenticator->authorization_data) {
+	    int i;
+
+	    for (i=0; !kret && authenticator->authorization_data[i]; i++) {
+		kret = krb5_size_opaque(kcontext,
+					KV5M_AUTHDATA,
+					(krb5_pointer) authenticator->
+					authorization_data[i],
+					&required);
+	    }
+	}
+    }
+    if (!kret)
+	*sizep += required;
+    return(kret);
+}
+
+/*
+ * krb5_authenticator_externalize()	- Externalize the krb5_authenticator.
+ */
+static krb5_error_code
+krb5_authenticator_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_authenticator	*authenticator;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+    int			i;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((authenticator = (krb5_authenticator *) arg)) {
+	kret = ENOMEM;
+	if (!krb5_authenticator_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* First write our magic number */
+	    (void) krb5_ser_pack_int32(KV5M_AUTHENTICATOR, &bp, &remain);
+	    
+	    /* Now ctime */
+	    (void) krb5_ser_pack_int32((krb5_int32) authenticator->ctime,
+				       &bp, &remain);
+
+	    /* Now cusec */
+	    (void) krb5_ser_pack_int32((krb5_int32) authenticator->cusec,
+				       &bp, &remain);
+
+	    /* Now seq_number */
+	    (void) krb5_ser_pack_int32(authenticator->seq_number,
+				       &bp, &remain);
+
+	    /* Now handle client, if appropriate */
+	    if (authenticator->client)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_PRINCIPAL,
+					       (krb5_pointer)
+					       authenticator->client,
+					       &bp,
+					       &remain);
+	    else
+		kret = 0;
+
+	    /* Now handle checksum, if appropriate */
+	    if (!kret && authenticator->checksum)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_CHECKSUM,
+					       (krb5_pointer)
+					       authenticator->checksum,
+					       &bp,
+					       &remain);
+
+	    /* Now handle subkey, if appropriate */
+	    if (!kret && authenticator->subkey)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer)
+					       authenticator->subkey,
+					       &bp,
+					       &remain);
+
+	    /* Now handle authorization_data, if appropriate */
+	    if (!kret) {
+		if (authenticator->authorization_data)
+		    for (i=0; authenticator->authorization_data[i]; i++);
+		else
+		    i = 0;
+		(void) krb5_ser_pack_int32((krb5_int32) i, &bp, &remain);
+
+		/* Now pound out the authorization_data */
+		if (authenticator->authorization_data) {
+		    for (i=0; !kret && authenticator->authorization_data[i];
+			 i++)
+			kret = krb5_externalize_opaque(kcontext,
+						       KV5M_AUTHDATA,
+						       (krb5_pointer)
+						       authenticator->
+						       authorization_data[i],
+						       &bp,
+						       &remain);
+		}
+	    }
+
+	    /*
+	     * If we were successful, write trailer then update the pointer and
+	     * remaining length;
+	     */
+	    if (!kret) {
+		/* Write our trailer */
+		(void) krb5_ser_pack_int32(KV5M_AUTHENTICATOR, &bp, &remain);
+		*buffer = bp;
+		*lenremain = remain;
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_authenticator_internalize()	- Internalize the krb5_authenticator.
+ */
+static krb5_error_code
+krb5_authenticator_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_authenticator	*authenticator;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    int			i;
+    krb5_int32		nadata;
+    size_t		len;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_AUTHENTICATOR) {
+	kret = ENOMEM;
+
+	/* Get memory for the authenticator */
+	if ((remain >= (3*sizeof(krb5_int32))) &&
+	    (authenticator = (krb5_authenticator *) 
+	     malloc(sizeof(krb5_authenticator)))) {
+	    memset(authenticator, 0, sizeof(krb5_authenticator));
+
+	    /* Get ctime */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authenticator->ctime = (krb5_timestamp) ibuf;
+
+	    /* Get cusec */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authenticator->cusec = ibuf;
+
+	    /* Get seq_number */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authenticator->seq_number = ibuf;
+	    
+	    kret = 0;
+
+	    /* Attempt to read in the client */
+	    kret = krb5_internalize_opaque(kcontext,
+					   KV5M_PRINCIPAL,
+					   (krb5_pointer *)
+					   &authenticator->client,
+					   &bp,
+					   &remain);
+	    if (kret == EINVAL)
+		kret = 0;
+
+	    /* Attempt to read in the checksum */
+	    if (!kret) {
+		kret = krb5_internalize_opaque(kcontext,
+					       KV5M_CHECKSUM,
+					       (krb5_pointer *)
+					       &authenticator->checksum,
+					       &bp,
+					       &remain);
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+
+	    /* Attempt to read in the subkey */
+	    if (!kret) {
+		kret = krb5_internalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer *)
+					       &authenticator->subkey,
+					       &bp,
+					       &remain);
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+
+	    /* Attempt to read in the authorization data count */
+	    if (!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) {
+		nadata = ibuf;
+		len = (size_t) (nadata + 1);
+
+		/* Get memory for the authorization data pointers */
+		if ((authenticator->authorization_data = (krb5_authdata **)
+		     malloc(sizeof(krb5_authdata *) * len))) {
+		    memset(authenticator->authorization_data, 0,
+			   sizeof(krb5_authdata *) * len);
+
+		    for (i=0; !kret && (i<nadata); i++) {
+			kret = krb5_internalize_opaque(kcontext,
+						       KV5M_AUTHDATA,
+						       (krb5_pointer *)
+						       &authenticator->
+						       authorization_data[i],
+						       &bp,
+						       &remain);
+		    }
+
+		    /* Finally, find the trailer */
+		    if (!kret) {
+			kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+			if (!kret && (ibuf == KV5M_AUTHENTICATOR))
+			    authenticator->magic = KV5M_AUTHENTICATOR;
+			else
+			    kret = EINVAL;
+		    }
+		}
+	    }
+	    if (!kret) {
+		*buffer = bp;
+		*lenremain = remain;
+		*argp = (krb5_pointer) authenticator;
+	    }
+	    else
+		krb5_free_authenticator(kcontext, authenticator);
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the authenticator serializer.
+ */
+krb5_error_code
+krb5_ser_authenticator_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_authenticator_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5/krb/ser_cksum.c b/mechglue/src/lib/krb5/krb/ser_cksum.c
new file mode 100644
index 000000000..8fb1a80da
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_cksum.c
@@ -0,0 +1,202 @@
+/*
+ * lib/krb5/krb/ser_cksum.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_cksum.c - Serialize a krb5_checksum structure.
+ */
+#include "k5-int.h"
+#include "int-proto.h"
+
+/*
+ * Routines to deal with externalizing the krb5_checksum:
+ *	krb5_checksum_esize();
+ *	krb5_checksum_externalize();
+ *	krb5_checksum_internalize();
+ */
+static krb5_error_code krb5_checksum_esize
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_checksum_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_checksum_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/* Local data */
+static const krb5_ser_entry krb5_checksum_ser_entry = {
+    KV5M_CHECKSUM,			/* Type			*/
+    krb5_checksum_esize,		/* Sizer routine	*/
+    krb5_checksum_externalize,		/* Externalize routine	*/
+    krb5_checksum_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_checksum_esize()	- Determine the size required to externalize
+ *				  the krb5_checksum.
+ */
+static krb5_error_code
+krb5_checksum_esize(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_checksum	*checksum;
+
+    /*
+     * krb5_checksum requires:
+     *	krb5_int32		for KV5M_CHECKSUM
+     *	krb5_int32		for checksum_type
+     *	krb5_int32		for length
+     *	krb5_int32		for KV5M_CHECKSUM
+     *	checksum->length	for contents
+     */
+    kret = EINVAL;
+    if ((checksum = (krb5_checksum *) arg)) {
+	*sizep += (sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   (size_t) checksum->length);
+	kret = 0;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_checksum_externalize()	- Externalize the krb5_checksum.
+ */
+static krb5_error_code
+krb5_checksum_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_checksum	*checksum;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((checksum = (krb5_checksum *) arg)) {
+	kret = ENOMEM;
+	if (!krb5_checksum_esize(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KV5M_CHECKSUM, &bp, &remain);
+		
+	    /* Our checksum_type */
+	    (void) krb5_ser_pack_int32((krb5_int32) checksum->checksum_type,
+				       &bp, &remain);
+
+	    /* Our length */
+	    (void) krb5_ser_pack_int32((krb5_int32) checksum->length,
+				       &bp, &remain);
+
+	    /* Our contents */
+	    (void) krb5_ser_pack_bytes(checksum->contents,
+				       (size_t) checksum->length,
+				       &bp, &remain);
+
+	    /* Finally, our trailer */
+	    (void) krb5_ser_pack_int32(KV5M_CHECKSUM, &bp, &remain);
+
+	    kret = 0;
+	    *buffer = bp;
+	    *lenremain = remain;
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_checksum_internalize()	- Internalize the krb5_checksum.
+ */
+static krb5_error_code
+krb5_checksum_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_checksum	*checksum;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_CHECKSUM) {
+	kret = ENOMEM;
+
+	/* Get a checksum */
+	if ((remain >= (2*sizeof(krb5_int32))) &&
+	    (checksum = (krb5_checksum *) malloc(sizeof(krb5_checksum)))) {
+	    memset(checksum, 0, sizeof(krb5_checksum));
+
+	    /* Get the checksum_type */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    checksum->checksum_type = (krb5_cksumtype) ibuf;
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    checksum->length = (int) ibuf;
+
+	    /* Get the string */
+	    if (!ibuf ||
+		((checksum->contents = (krb5_octet *)
+		  malloc((size_t) (ibuf))) &&
+		 !(kret = krb5_ser_unpack_bytes(checksum->contents,
+						(size_t) ibuf,
+						&bp, &remain)))) {
+
+		/* Get the trailer */
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		if (!kret && (ibuf == KV5M_CHECKSUM)) {
+		    checksum->magic = KV5M_CHECKSUM;
+		    *buffer = bp;
+		    *lenremain = remain;
+		    *argp = (krb5_pointer) checksum;
+		}
+		else
+		    kret = EINVAL;
+	    }
+	    if (kret) {
+		if (checksum->contents)
+		    free(checksum->contents);
+		free(checksum);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the checksum serializer.
+ */
+krb5_error_code
+krb5_ser_checksum_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_checksum_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5/krb/ser_ctx.c b/mechglue/src/lib/krb5/krb/ser_ctx.c
new file mode 100644
index 000000000..d48f61e83
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_ctx.c
@@ -0,0 +1,637 @@
+/*
+ * lib/krb5/krb/ser_ctx.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_ctx.c	- Routines to deal with serializing the krb5_context and
+ *		  krb5_os_context structures.
+ */
+#include "k5-int.h"
+
+/*
+ * Routines to deal with externalizing the krb5_context:
+ *	krb5_context_size();
+ *	krb5_context_externalize();
+ *	krb5_context_internalize();
+ * 
+ * Routines to deal with externalizing the krb5_os_context:
+ *	krb5_oscontext_size();
+ *	krb5_oscontext_externalize();
+ *	krb5_oscontext_internalize();
+ *
+ * Routines to deal with externalizing the profile.
+ *	profile_ser_size();
+ *	profile_ser_externalize();
+ *	profile_ser_internalize();
+ *
+ * Interface to initialize serializing of krb5_context and krb5_os_context:
+ *	krb5_ser_context_init();
+ */
+static krb5_error_code krb5_context_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_context_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_context_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+static krb5_error_code krb5_oscontext_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_oscontext_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_oscontext_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+krb5_error_code profile_ser_size
+	(krb5_context, krb5_pointer, size_t *);
+krb5_error_code profile_ser_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+krb5_error_code profile_ser_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/* Local data */
+static const krb5_ser_entry krb5_context_ser_entry = {
+    KV5M_CONTEXT,			/* Type 		*/
+    krb5_context_size,			/* Sizer routine	*/
+    krb5_context_externalize,		/* Externalize routine	*/
+    krb5_context_internalize		/* Internalize routine	*/
+};
+static const krb5_ser_entry krb5_oscontext_ser_entry = {
+    KV5M_OS_CONTEXT,			/* Type			*/
+    krb5_oscontext_size,		/* Sizer routine	*/
+    krb5_oscontext_externalize,		/* Externalize routine	*/
+    krb5_oscontext_internalize		/* Internalize routine	*/
+};
+static const krb5_ser_entry krb5_profile_ser_entry = {
+    PROF_MAGIC_PROFILE,			/* Type			*/
+    profile_ser_size,			/* Sizer routine	*/
+    profile_ser_externalize,		/* Externalize routine	*/
+    profile_ser_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_context_size()	- Determine the size required to externalize the
+ *			  krb5_context.
+ */
+static krb5_error_code
+krb5_context_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    size_t		required;
+    krb5_context	context;
+
+    /*
+     * The KRB5 context itself requires:
+     *	krb5_int32			for KV5M_CONTEXT
+     *	krb5_int32			for sizeof(default_realm)
+     *	strlen(default_realm)		for default_realm.
+     *	krb5_int32			for n_in_tkt_ktypes*sizeof(krb5_int32)
+     *	nktypes*sizeof(krb5_int32)	for in_tkt_ktypes.
+     *	krb5_int32			for n_tgs_ktypes*sizeof(krb5_int32)
+     *	nktypes*sizeof(krb5_int32)	for tgs_ktypes.
+     *  krb5_int32			for clockskew
+     *  krb5_int32			for kdc_req_sumtype
+     *  krb5_int32			for ap_req_sumtype
+     *  krb5_int32			for safe_sumtype
+     *  krb5_int32			for kdc_default_options
+     *  krb5_int32			for library_options
+     *  krb5_int32			for profile_secure
+     * 	krb5_int32			for fcc_default_format
+     *  krb5_int32			for scc_default_format
+     *    <>				for os_context
+     *    <>				for db_context
+     *    <>				for profile
+     *	krb5_int32			for trailer.
+     */
+    kret = EINVAL;
+    if ((context = (krb5_context) arg)) {
+	/* Calculate base length */
+	required = (14 * sizeof(krb5_int32) +
+		    (context->in_tkt_ktype_count * sizeof(krb5_int32)) +
+		    (context->tgs_ktype_count * sizeof(krb5_int32)));
+
+	if (context->default_realm)
+	    required += strlen(context->default_realm);
+	/* Calculate size required by os_context, if appropriate */
+	if (context->os_context)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_OS_CONTEXT,
+				    (krb5_pointer) context->os_context,
+				    &required);
+
+	/* Calculate size required by db_context, if appropriate */
+	if (!kret && context->db_context)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_DB_CONTEXT,
+				    (krb5_pointer) context->db_context,
+				    &required);
+
+	/* Finally, calculate size required by profile, if appropriate */
+	if (!kret && context->profile)
+	    kret = krb5_size_opaque(kcontext,
+				    PROF_MAGIC_PROFILE,
+				    (krb5_pointer) context->profile,
+				    &required);
+    }
+    if (!kret)
+	*sizep += required;
+    return(kret);
+}
+
+/*
+ * krb5_context_externalize()	- Externalize the krb5_context.
+ */
+static krb5_error_code
+krb5_context_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_context	context;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+    int			i;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    context = (krb5_context) arg;
+    if (!context)
+	    return (EINVAL);
+    KRB5_VERIFY_MAGIC(context, KV5M_CONTEXT);
+
+    if ((kret = krb5_context_size(kcontext, arg, &required)))
+	return (kret);
+
+    if (required > remain)
+	return (ENOMEM);
+    
+    /* First write our magic number */
+    kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain);
+    if (kret)
+	return (kret);
+    
+    /* Now sizeof default realm */
+    kret = krb5_ser_pack_int32((context->default_realm) ?
+			       (krb5_int32) strlen(context->default_realm) : 0,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+    
+    /* Now default_realm bytes */
+    if (context->default_realm) {
+	kret = krb5_ser_pack_bytes((krb5_octet *) context->default_realm,
+				   strlen(context->default_realm), 
+				   &bp, &remain);
+	if (kret)
+	    return (kret);
+    }
+
+    /* Now number of initial ticket ktypes */
+    kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktype_count,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+    
+    /* Now serialize ktypes */
+    for (i=0; i<context->in_tkt_ktype_count; i++) {
+	kret = krb5_ser_pack_int32((krb5_int32) context->in_tkt_ktypes[i],
+				   &bp, &remain);
+	if (kret)
+	    return (kret);
+    }
+    
+    /* Now number of default ktypes */
+    kret = krb5_ser_pack_int32((krb5_int32) context->tgs_ktype_count,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+	
+    /* Now serialize ktypes */
+    for (i=0; i<context->tgs_ktype_count; i++) {
+	kret = krb5_ser_pack_int32((krb5_int32) context->tgs_ktypes[i],
+				   &bp, &remain);
+	if (kret)
+	    return (kret);
+    }
+	
+    /* Now allowable clockskew */
+    kret = krb5_ser_pack_int32((krb5_int32) context->clockskew,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+	
+    /* Now kdc_req_sumtype */
+    kret = krb5_ser_pack_int32((krb5_int32) context->kdc_req_sumtype,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+	
+    /* Now default ap_req_sumtype */
+    kret = krb5_ser_pack_int32((krb5_int32) context->default_ap_req_sumtype,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+
+    /* Now default safe_sumtype */
+    kret = krb5_ser_pack_int32((krb5_int32) context->default_safe_sumtype,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+
+    /* Now kdc_default_options */
+    kret = krb5_ser_pack_int32((krb5_int32) context->kdc_default_options,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+
+    /* Now library_options */
+    kret = krb5_ser_pack_int32((krb5_int32) context->library_options,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+	
+    /* Now profile_secure */
+    kret = krb5_ser_pack_int32((krb5_int32) context->profile_secure,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+
+    /* Now fcc_default_format */
+    kret = krb5_ser_pack_int32((krb5_int32) context->fcc_default_format,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+
+    /* Now scc_default_format */
+    kret = krb5_ser_pack_int32((krb5_int32) context->scc_default_format,
+			       &bp, &remain);
+    if (kret)
+	return (kret);
+
+    /* Now handle os_context, if appropriate */
+    if (context->os_context) {
+	kret = krb5_externalize_opaque(kcontext, KV5M_OS_CONTEXT,
+				       (krb5_pointer) context->os_context,
+				       &bp, &remain);
+	if (kret)
+	    return (kret);
+    }
+	
+    /* Now handle database context, if appropriate */
+    if (context->db_context) {
+	kret = krb5_externalize_opaque(kcontext, KV5M_DB_CONTEXT,
+				       (krb5_pointer) context->db_context,
+				       &bp, &remain);
+	if (kret)
+	    return (kret);
+    }
+
+    /* Finally, handle profile, if appropriate */
+    if (context->profile) {
+	kret = krb5_externalize_opaque(kcontext, PROF_MAGIC_PROFILE,
+				       (krb5_pointer) context->profile,
+				       &bp, &remain);
+	if (kret)
+	    return (kret);
+    }
+	
+    /*
+     * If we were successful, write trailer then update the pointer and
+     * remaining length;
+     */
+    kret = krb5_ser_pack_int32(KV5M_CONTEXT, &bp, &remain);
+    if (kret)
+	return (kret);
+    
+    *buffer = bp;
+    *lenremain = remain;
+
+    return (0);
+}
+
+/*
+ * krb5_context_internalize()	- Internalize the krb5_context.
+ */
+static krb5_error_code
+krb5_context_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_context	context;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    int			i;
+
+    bp = *buffer;
+    remain = *lenremain;
+
+    /* Read our magic number */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	return (EINVAL);
+
+    if (ibuf != KV5M_CONTEXT)
+	return (EINVAL);
+
+    /* Get memory for the context */
+    context = (krb5_context) malloc(sizeof(struct _krb5_context));
+    if (!context)
+	return (ENOMEM);
+    memset(context, 0, sizeof(struct _krb5_context));
+
+    /* Get the size of the default realm */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+
+    if (ibuf) {
+	context->default_realm = (char *) malloc((size_t) ibuf+1);
+	if (!context->default_realm) {
+	    kret = ENOMEM;
+	    goto cleanup;
+	}
+
+	kret = krb5_ser_unpack_bytes((krb5_octet *) context->default_realm,
+				     (size_t) ibuf, &bp, &remain);
+	if (kret)
+	    goto cleanup;
+	
+	context->default_realm[ibuf] = '\0';
+    }
+	
+    /* Get the number of in_tkt_ktypes */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    
+    context->in_tkt_ktype_count = (int) ibuf;
+    context->in_tkt_ktypes = (krb5_enctype *) malloc(sizeof(krb5_enctype) *
+				     (context->in_tkt_ktype_count+1));
+    if (!context->in_tkt_ktypes) {
+	kret = ENOMEM;
+	goto cleanup;
+    }
+    memset(context->in_tkt_ktypes, 0, (sizeof(krb5_enctype) *
+				       (context->in_tkt_ktype_count + 1)));
+    
+    for (i=0; i<context->in_tkt_ktype_count; i++) {
+	if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	    goto cleanup;
+	context->in_tkt_ktypes[i] = (krb5_enctype) ibuf;
+    }
+
+    /* Get the number of tgs_ktypes */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    
+    context->tgs_ktype_count = (int) ibuf;
+    context->tgs_ktypes = (krb5_enctype *) malloc(sizeof(krb5_enctype) *
+				  (context->tgs_ktype_count+1));
+    if (!context->tgs_ktypes) {
+	kret = ENOMEM;
+	goto cleanup;
+    }
+    memset(context->tgs_ktypes, 0, (sizeof(krb5_enctype) *
+				    (context->tgs_ktype_count + 1)));
+    for (i=0; i<context->tgs_ktype_count; i++) {
+	if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	    goto cleanup;
+	context->tgs_ktypes[i] = (krb5_enctype) ibuf;
+    }
+
+    /* Allowable checksum */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->clockskew = (krb5_deltat) ibuf;
+    
+    /* kdc_req_sumtype */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->kdc_req_sumtype = (krb5_cksumtype) ibuf;
+    
+    /* default ap_req_sumtype */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->default_ap_req_sumtype = (krb5_cksumtype) ibuf;
+    
+    /* default_safe_sumtype */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->default_safe_sumtype = (krb5_cksumtype) ibuf;
+
+    /* kdc_default_options */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->kdc_default_options = (krb5_flags) ibuf;
+
+    /* library_options */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->library_options = (krb5_flags) ibuf;
+
+    /* profile_secure */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->profile_secure = (krb5_boolean) ibuf;
+
+    /* fcc_default_format */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->fcc_default_format = (int) ibuf;
+
+    /* scc_default_format */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+    context->scc_default_format = (int) ibuf;
+    
+    /* Attempt to read in the os_context.  It's an array now, but
+       we still treat it in most places as a separate object with
+       a pointer.  */
+    {
+	krb5_os_context osp = 0;
+	kret = krb5_internalize_opaque(kcontext, KV5M_OS_CONTEXT,
+				       (krb5_pointer *) &osp,
+				       &bp, &remain);
+	if (kret && (kret != EINVAL) && (kret != ENOENT))
+	    goto cleanup;
+	/* Put the newly allocated data into the krb5_context
+	   structure where we're really keeping it these days.  */
+	if (osp)
+	    *context->os_context = *osp;
+	free(osp);
+    }
+
+    /* Attempt to read in the db_context */
+    kret = krb5_internalize_opaque(kcontext, KV5M_DB_CONTEXT,
+				   (krb5_pointer *) &context->db_context,
+				   &bp, &remain);
+    if (kret && (kret != EINVAL) && (kret != ENOENT))
+	goto cleanup;
+    
+    /* Attempt to read in the profile */
+    kret = krb5_internalize_opaque(kcontext, PROF_MAGIC_PROFILE,
+				   (krb5_pointer *) &context->profile,
+				   &bp, &remain);
+    if (kret && (kret != EINVAL) && (kret != ENOENT))
+	goto cleanup;
+    
+    /* Finally, find the trailer */
+    if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	goto cleanup;
+
+    if (ibuf != KV5M_CONTEXT) {
+	kret = EINVAL;
+	goto cleanup;
+    }
+
+    context->magic = KV5M_CONTEXT;
+    *buffer = bp;
+    *lenremain = remain;
+    *argp = (krb5_pointer) context;
+
+    return 0;
+
+cleanup:
+    if (context)
+	krb5_free_context(context);
+    return(kret);
+}
+
+/*
+ * krb5_oscontext_size()	- Determine the size required to externalize
+ *				  the krb5_os_context.
+ */
+static krb5_error_code
+krb5_oscontext_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    /*
+     * We need five 32-bit integers:
+     *	two for header and trailer
+     *	one each for time_offset, usec_offset and os_flags
+     */
+    *sizep += (5*sizeof(krb5_int32));
+    return(0);
+}
+
+/*
+ * krb5_oscontext_externalize()	- Externalize the krb5_os_context.
+ */
+static krb5_error_code
+krb5_oscontext_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_os_context	os_ctx;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((os_ctx = (krb5_os_context) arg)) {
+	kret = ENOMEM;
+	if (!krb5_oscontext_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain);
+	    (void) krb5_ser_pack_int32(os_ctx->time_offset, &bp, &remain);
+	    (void) krb5_ser_pack_int32(os_ctx->usec_offset, &bp, &remain);
+	    (void) krb5_ser_pack_int32(os_ctx->os_flags, &bp, &remain);
+	    (void) krb5_ser_pack_int32(KV5M_OS_CONTEXT, &bp, &remain);
+
+	    /* Handle any other OS context here */
+	    kret = 0;
+	    if (!kret) {
+		*buffer = bp;
+		*lenremain = remain;
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_oscontext_internalize()	- Internalize the krb5_os_context.
+ */
+static krb5_error_code
+krb5_oscontext_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_os_context	os_ctx;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    os_ctx = (krb5_os_context) NULL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_OS_CONTEXT) {
+	kret = ENOMEM;
+
+	/* Get memory for the context */
+	if ((os_ctx = (krb5_os_context) 
+	     malloc(sizeof(struct _krb5_os_context))) &&
+	    (remain >= 4*sizeof(krb5_int32))) {
+	    memset(os_ctx, 0, sizeof(struct _krb5_os_context));
+	    os_ctx->magic = KV5M_OS_CONTEXT;
+
+	    /* Read out our context */
+	    (void) krb5_ser_unpack_int32(&os_ctx->time_offset, &bp, &remain);
+	    (void) krb5_ser_unpack_int32(&os_ctx->usec_offset, &bp, &remain);
+	    (void) krb5_ser_unpack_int32(&os_ctx->os_flags, &bp, &remain);
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+
+	    if (ibuf == KV5M_OS_CONTEXT) {
+		os_ctx->magic = KV5M_OS_CONTEXT;
+		kret = 0;
+		*buffer = bp;
+		*lenremain = remain;
+	    } else
+		kret = EINVAL;
+	}
+    }
+    if (!kret) {
+	*argp = (krb5_pointer) os_ctx;
+    }
+    else {
+	if (os_ctx)
+	    free(os_ctx);
+    }
+    return(kret);
+}
+
+/*
+ * Register the context serializers.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_context_init(krb5_context kcontext)
+{
+    krb5_error_code	kret;
+    kret = krb5_register_serializer(kcontext, &krb5_context_ser_entry);
+    if (!kret)
+	kret = krb5_register_serializer(kcontext, &krb5_oscontext_ser_entry);
+    if (!kret)
+	kret = krb5_register_serializer(kcontext, &krb5_profile_ser_entry);
+    return(kret);
+}
diff --git a/mechglue/src/lib/krb5/krb/ser_eblk.c b/mechglue/src/lib/krb5/krb/ser_eblk.c
new file mode 100644
index 000000000..aed806ce1
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_eblk.c
@@ -0,0 +1,258 @@
+/*
+ * lib/krb5/krb/ser_eblk.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#if 0 /* i don't believe this is used anywhere --marc */
+
+/*
+ * ser_eblk.c - Serialize a krb5_encblock structure.
+ */
+#include "k5-int.h"
+
+/*
+ * Routines to deal with externalizing the krb5_encrypt_block:
+ *	krb5_encrypt_block_size();
+ *	krb5_encrypt_block_externalize();
+ *	krb5_encrypt_block_internalize();
+ */
+static krb5_error_code krb5_encrypt_block_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_encrypt_block_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_encrypt_block_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/* Local data */
+static const krb5_ser_entry krb5_encrypt_block_ser_entry = {
+    KV5M_ENCRYPT_BLOCK,			/* Type			*/
+    krb5_encrypt_block_size,		/* Sizer routine	*/
+    krb5_encrypt_block_externalize,	/* Externalize routine	*/
+    krb5_encrypt_block_internalize	/* Internalize routine	*/
+};
+
+/*
+ * krb5_encrypt_block_size()	- Determine the size required to externalize
+ *				  the krb5_encrypt_block.
+ */
+static krb5_error_code
+krb5_encrypt_block_size(kcontext, arg, sizep)
+    krb5_context	kcontext;
+    krb5_pointer	arg;
+    size_t		*sizep;
+{
+    krb5_error_code	kret;
+    krb5_encrypt_block	*encrypt_block;
+    size_t		required;
+
+    /*
+     * NOTE: This ASSuMES that enctype are sufficient to recreate
+     * the _krb5_cryptosystem_entry.  If this is not true, then something else
+     * had better be encoded here.
+     * 
+     * krb5_encrypt_block base requirements:
+     *	krb5_int32			for KV5M_ENCRYPT_BLOCK
+     *	krb5_int32			for enctype
+     *	krb5_int32			for private length
+     *	encrypt_block->priv_size	for private contents
+     *	krb5_int32			for KV5M_ENCRYPT_BLOCK
+     */
+    kret = EINVAL;
+    if ((encrypt_block = (krb5_encrypt_block *) arg)) {
+	required = (sizeof(krb5_int32) +
+		    sizeof(krb5_int32) +
+		    sizeof(krb5_int32) +
+		    sizeof(krb5_int32) +
+		    sizeof(krb5_int32) +
+		    (size_t) encrypt_block->priv_size);
+	if (encrypt_block->key)
+	    kret = krb5_size_opaque(kcontext,
+				    KV5M_KEYBLOCK,
+				    (krb5_pointer) encrypt_block->key,
+				    &required);
+	else
+	    kret = 0;
+	if (!kret)
+	    *sizep += required;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_encrypt_block_externalize()	- Externalize the krb5_encrypt_block.
+ */
+static krb5_error_code
+krb5_encrypt_block_externalize(kcontext, arg, buffer, lenremain)
+    krb5_context	kcontext;
+    krb5_pointer	arg;
+    krb5_octet		**buffer;
+    size_t		*lenremain;
+{
+    krb5_error_code	kret;
+    krb5_encrypt_block	*encrypt_block;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((encrypt_block = (krb5_encrypt_block *) arg)) {
+	kret = ENOMEM;
+	if (!krb5_encrypt_block_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KV5M_ENCRYPT_BLOCK, &bp, &remain);
+		
+	    /* Our enctype */
+	    (void) krb5_ser_pack_int32((krb5_int32) encrypt_block->
+				       crypto_entry->proto_enctype,
+				       &bp, &remain);
+
+	    /* Our length */
+	    (void) krb5_ser_pack_int32((krb5_int32) encrypt_block->priv_size,
+				       &bp, &remain);
+
+	    /* Our private data */
+	    (void) krb5_ser_pack_bytes(encrypt_block->priv,
+				       (size_t) encrypt_block->priv_size,
+				       &bp, &remain);
+
+	    /* Finally, the key data */
+	    if (encrypt_block->key)
+		kret = krb5_externalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer)
+					       encrypt_block->key,
+					       &bp,
+					       &remain);
+	    else
+		kret = 0;
+
+	    if (!kret) {
+		/* Write trailer */
+		(void) krb5_ser_pack_int32(KV5M_ENCRYPT_BLOCK, &bp, &remain);
+		*buffer = bp;
+		*lenremain = remain;
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_encrypt_block_internalize()	- Internalize the krb5_encrypt_block.
+ */
+static krb5_error_code
+krb5_encrypt_block_internalize(kcontext, argp, buffer, lenremain)
+    krb5_context	kcontext;
+    krb5_pointer	*argp;
+    krb5_octet		**buffer;
+    size_t		*lenremain;
+{
+    krb5_error_code	kret;
+    krb5_encrypt_block	*encrypt_block;
+    krb5_int32		ibuf;
+    krb5_enctype	ktype;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_ENCRYPT_BLOCK) {
+	kret = ENOMEM;
+
+	/* Get an encrypt_block */
+	if ((remain >= (3*sizeof(krb5_int32))) &&
+	    (encrypt_block = (krb5_encrypt_block *)
+	     malloc(sizeof(krb5_encrypt_block)))) {
+	    memset(encrypt_block, 0, sizeof(krb5_encrypt_block));
+
+	    /* Get the enctype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ktype = (krb5_enctype) ibuf;
+
+	    /* Use the ktype to determine the crypto_system entry. */
+	    krb5_use_enctype(kcontext, encrypt_block, ktype);
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    encrypt_block->priv_size = (int) ibuf;
+
+	    /* Get the string */
+	    if (!ibuf ||
+		((encrypt_block->priv = (void *) malloc((size_t) (ibuf))) &&
+		 !(kret = krb5_ser_unpack_bytes((krb5_octet *)
+						encrypt_block->priv,
+						(size_t)
+						encrypt_block->priv_size,
+						&bp, &remain)))) {
+		kret = krb5_internalize_opaque(kcontext,
+					       KV5M_KEYBLOCK,
+					       (krb5_pointer *)
+					       &encrypt_block->key,
+					       &bp,
+					       &remain);
+		if (kret == EINVAL)
+		    kret = 0;
+
+		if (!kret) {
+		    kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		    if (!kret && (ibuf == KV5M_ENCRYPT_BLOCK)) {
+			*buffer = bp;
+			*lenremain = remain;
+			encrypt_block->magic = KV5M_ENCRYPT_BLOCK;
+			*argp = (krb5_pointer) encrypt_block;
+		    }
+		    else
+			kret = EINVAL;
+		}
+	    }
+	    if (kret) {
+		if (encrypt_block->priv)
+		    free(encrypt_block->priv);
+		free(encrypt_block);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the encblock serializer.
+ */
+krb5_error_code
+krb5_ser_encrypt_block_init(kcontext)
+    krb5_context	kcontext;
+{
+    return(krb5_register_serializer(kcontext, &krb5_encrypt_block_ser_entry));
+}
+
+#endif
diff --git a/mechglue/src/lib/krb5/krb/ser_key.c b/mechglue/src/lib/krb5/krb/ser_key.c
new file mode 100644
index 000000000..5249006fc
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_key.c
@@ -0,0 +1,200 @@
+/*
+ * lib/krb5/krb/ser_key.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_key.c - Serialize a krb5_keyblock structure.
+ */
+#include "k5-int.h"
+#include "int-proto.h"
+
+/*
+ * Routines to deal with externalizing the krb5_keyblock:
+ *	krb5_keyblock_size();
+ *	krb5_keyblock_externalize();
+ *	krb5_keyblock_internalize();
+ */
+static krb5_error_code krb5_keyblock_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_keyblock_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_keyblock_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/* Local data */
+static const krb5_ser_entry krb5_keyblock_ser_entry = {
+    KV5M_KEYBLOCK,			/* Type			*/
+    krb5_keyblock_size,			/* Sizer routine	*/
+    krb5_keyblock_externalize,		/* Externalize routine	*/
+    krb5_keyblock_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_keyblock_size()	- Determine the size required to externalize
+ *				  the krb5_keyblock.
+ */
+static krb5_error_code
+krb5_keyblock_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_keyblock	*keyblock;
+
+    /*
+     * krb5_keyblock requires:
+     *	krb5_int32			for KV5M_KEYBLOCK
+     *	krb5_int32			for enctype
+     *	krb5_int32			for length
+     *	keyblock->length		for contents
+     *	krb5_int32			for KV5M_KEYBLOCK
+     */
+    kret = EINVAL;
+    if ((keyblock = (krb5_keyblock *) arg)) {
+	*sizep += (sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   sizeof(krb5_int32) +
+		   (size_t) keyblock->length);
+	kret = 0;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_keyblock_externalize()	- Externalize the krb5_keyblock.
+ */
+static krb5_error_code
+krb5_keyblock_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_keyblock	*keyblock;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((keyblock = (krb5_keyblock *) arg)) {
+	kret = ENOMEM;
+	if (!krb5_keyblock_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KV5M_KEYBLOCK, &bp, &remain);
+		
+	    /* Our enctype */
+	    (void) krb5_ser_pack_int32((krb5_int32) keyblock->enctype,
+				       &bp, &remain);
+
+	    /* Our length */
+	    (void) krb5_ser_pack_int32((krb5_int32) keyblock->length,
+				       &bp, &remain);
+
+	    /* Our contents */
+	    (void) krb5_ser_pack_bytes(keyblock->contents,
+				       (size_t) keyblock->length,
+				       &bp, &remain);
+
+	    /* Finally, our trailer */
+	    (void) krb5_ser_pack_int32(KV5M_KEYBLOCK, &bp, &remain);
+
+	    kret = 0;
+	    *buffer = bp;
+	    *lenremain = remain;
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_keyblock_internalize()	- Internalize the krb5_keyblock.
+ */
+static krb5_error_code
+krb5_keyblock_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_keyblock	*keyblock;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_KEYBLOCK) {
+	kret = ENOMEM;
+
+	/* Get a keyblock */
+	if ((remain >= (3*sizeof(krb5_int32))) &&
+	    (keyblock = (krb5_keyblock *) malloc(sizeof(krb5_keyblock)))) {
+	    memset(keyblock, 0, sizeof(krb5_keyblock));
+
+	    /* Get the enctype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    keyblock->enctype = (krb5_enctype) ibuf;
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    keyblock->length = (int) ibuf;
+
+	    /* Get the string */
+	    if ((keyblock->contents = (krb5_octet *) malloc((size_t) (ibuf)))&&
+		!(kret = krb5_ser_unpack_bytes(keyblock->contents,
+					       (size_t) ibuf,
+					       &bp, &remain))) {
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		if (!kret && (ibuf == KV5M_KEYBLOCK)) {
+		    kret = 0;
+		    *buffer = bp;
+		    *lenremain = remain;
+		    keyblock->magic = KV5M_KEYBLOCK;
+		    *argp = (krb5_pointer) keyblock;
+		}
+		else
+		    kret = EINVAL;
+	    }
+	    if (kret) {
+		if (keyblock->contents)
+		    free(keyblock->contents);
+		free(keyblock);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the keyblock serializer.
+ */
+krb5_error_code
+krb5_ser_keyblock_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_keyblock_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5/krb/ser_princ.c b/mechglue/src/lib/krb5/krb/ser_princ.c
new file mode 100644
index 000000000..a4663c5f8
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/ser_princ.c
@@ -0,0 +1,181 @@
+/*
+ * lib/krb5/krb/ser_princ.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_princ.c - Serialize a krb5_principal structure.
+ */
+#include "k5-int.h"
+#include "int-proto.h"
+
+/*
+ * Routines to deal with externalizing the krb5_principal:
+ *	krb5_principal_size();
+ *	krb5_principal_externalize();
+ *	krb5_principal_internalize();
+ */
+static krb5_error_code krb5_principal_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_principal_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_principal_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/* Local data */
+static const krb5_ser_entry krb5_principal_ser_entry = {
+    KV5M_PRINCIPAL,			/* Type			*/
+    krb5_principal_size,		/* Sizer routine	*/
+    krb5_principal_externalize,		/* Externalize routine	*/
+    krb5_principal_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_principal_size()	- Determine the size required to externalize
+ *				  the krb5_principal.
+ */
+static krb5_error_code
+krb5_principal_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_principal	principal;
+    char		*fname;
+
+    /*
+     * krb5_principal requires:
+     *	krb5_int32			for KV5M_PRINCIPAL
+     *	krb5_int32			for flattened name size
+     *	strlen(name)			for name.
+     *	krb5_int32			for KV5M_PRINCIPAL
+     */
+    kret = EINVAL;
+    if ((principal = (krb5_principal) arg) &&
+	!(kret = krb5_unparse_name(kcontext, principal, &fname))) {
+	*sizep += (3*sizeof(krb5_int32)) + strlen(fname);
+	krb5_xfree(fname);
+    }
+    return(kret);
+}
+
+/*
+ * krb5_principal_externalize()	- Externalize the krb5_principal.
+ */
+static krb5_error_code
+krb5_principal_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_principal	principal;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+    char		*fname;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((principal = (krb5_principal) arg)) {
+	kret = ENOMEM;
+	if (!krb5_principal_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    if (!(kret = krb5_unparse_name(kcontext, principal, &fname))) {
+
+		(void) krb5_ser_pack_int32(KV5M_PRINCIPAL, &bp, &remain);
+		(void) krb5_ser_pack_int32((krb5_int32) strlen(fname),
+					   &bp, &remain);
+		(void) krb5_ser_pack_bytes((krb5_octet *) fname,
+					   strlen(fname), &bp, &remain);
+		(void) krb5_ser_pack_int32(KV5M_PRINCIPAL, &bp, &remain);
+		*buffer = bp;
+		*lenremain = remain;
+
+		krb5_xfree(fname);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_principal_internalize()	- Internalize the krb5_principal.
+ */
+static krb5_error_code
+krb5_principal_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_principal	principal;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    char		*tmpname;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_PRINCIPAL) {
+	kret = ENOMEM;
+
+	/* See if we have enough data for the length */
+	if (!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) {
+	    /* Get the string */
+	    if ((tmpname = (char *) malloc((size_t) (ibuf+1))) &&
+		!(kret = krb5_ser_unpack_bytes((krb5_octet *) tmpname,
+					       (size_t) ibuf,
+					       &bp, &remain))) {
+		tmpname[ibuf] = '\0';
+
+		/* Parse the name to a principal structure */
+		principal = (krb5_principal) NULL;
+		kret = krb5_parse_name(kcontext, tmpname, &principal);
+		if (!kret) {
+		    kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		    if (!kret && (ibuf == KV5M_PRINCIPAL)) {
+			*buffer = bp;
+			*lenremain = remain;
+			*argp = principal;
+		    }
+		    else
+			kret = EINVAL;
+		}
+		if (kret && principal)
+		    krb5_free_principal(kcontext, principal);
+		free(tmpname);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the context serializer.
+ */
+krb5_error_code
+krb5_ser_principal_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_principal_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5/krb/serialize.c b/mechglue/src/lib/krb5/krb/serialize.c
new file mode 100644
index 000000000..9cbcef78d
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/serialize.c
@@ -0,0 +1,278 @@
+/*
+ * lib/krb5/krb/serialize.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * Base routines to deal with serialization of Kerberos metadata.
+ */
+#include "k5-int.h"
+
+/*
+ * krb5_find_serializer()	- See if a particular type is registered.
+ */
+krb5_ser_handle
+krb5_find_serializer(krb5_context kcontext, krb5_magic odtype)
+{
+    krb5_ser_handle	res;
+    krb5_ser_handle	sctx;
+    int			i;
+
+    res = (krb5_ser_handle) NULL;
+    sctx = (krb5_ser_handle) kcontext->ser_ctx;
+    for (i=0; i<kcontext->ser_ctx_count; i++) {
+	if (sctx[i].odtype == odtype) {
+	    res = &sctx[i];
+	    break;
+	}
+    }
+    return(res);
+}
+
+/*
+ * krb5_register_serializer()	- Register a particular serializer.
+ */
+krb5_error_code
+krb5_register_serializer(krb5_context kcontext, const krb5_ser_entry *entry)
+{
+    krb5_error_code	kret;
+    krb5_ser_handle	stable;
+
+    kret = 0;
+    /* See if it's already there, if so, we're good to go. */
+    if (!(stable = krb5_find_serializer(kcontext, entry->odtype))) {
+	/*
+	 * Can't find our type.  Create a new entry.
+	 */
+	if ((stable = (krb5_ser_handle) malloc(sizeof(krb5_ser_entry) *
+					       (kcontext->ser_ctx_count+1)))) {
+	    /* Copy in old table */
+	    if (kcontext->ser_ctx_count)
+	         memcpy(stable, kcontext->ser_ctx,
+		        sizeof(krb5_ser_entry) * kcontext->ser_ctx_count);
+	    /* Copy in new entry */
+	    memcpy(&stable[kcontext->ser_ctx_count], entry,
+		   sizeof(krb5_ser_entry));
+	    if (kcontext->ser_ctx) krb5_xfree(kcontext->ser_ctx);
+	    kcontext->ser_ctx = (void *) stable;
+	    kcontext->ser_ctx_count++;
+	}
+	else
+	    kret = ENOMEM;
+    }
+    else
+	memcpy(stable, entry, sizeof(krb5_ser_entry));
+    return(kret);
+}
+
+/*
+ * krb5_size_opaque()	- Determine the size necessary to serialize a given
+ *			  piece of opaque data.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_size_opaque(krb5_context kcontext, krb5_magic odtype, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_ser_handle	shandle;
+
+    kret = ENOENT;
+    /* See if the type is supported, if so, do it */
+    if ((shandle = krb5_find_serializer(kcontext, odtype)))
+	kret = (shandle->sizer) ? (*shandle->sizer)(kcontext, arg, sizep) : 0;
+    return(kret);
+}
+
+/*
+ * krb5_externalize_opaque()	- Externalize a piece of opaque data.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_externalize_opaque(krb5_context kcontext, krb5_magic odtype, krb5_pointer arg, krb5_octet **bufpp, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_ser_handle	shandle;
+
+    kret = ENOENT;
+    /* See if the type is supported, if so, do it */
+    if ((shandle = krb5_find_serializer(kcontext, odtype)))
+	kret = (shandle->externalizer) ?
+	    (*shandle->externalizer)(kcontext, arg, bufpp, sizep) : 0;
+    return(kret);
+}
+
+/*
+ * Externalize a piece of arbitrary data.
+ */
+krb5_error_code
+krb5_externalize_data(krb5_context kcontext, krb5_pointer arg, krb5_octet **bufpp, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_magic		*mp;
+    krb5_octet		*buffer, *bp;
+    size_t		bufsize, bsize;
+
+    mp = (krb5_magic *) arg;
+    bufsize = 0;
+    if (!(kret = krb5_size_opaque(kcontext, *mp, arg, &bufsize))) {
+	if ((buffer = (krb5_octet *) malloc(bufsize))) {
+	    bp = buffer;
+	    bsize = bufsize;
+	    if (!(kret = krb5_externalize_opaque(kcontext,
+						 *mp,
+						 arg,
+						 &bp,
+						 &bsize))) {
+		if (bsize != 0)
+		    bufsize -= bsize;
+		*bufpp = buffer;
+		*sizep = bufsize;
+	    }
+	}
+	else
+	    kret = ENOMEM;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_internalize_opaque()	- Convert external representation into a data
+ *				  structure.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_internalize_opaque(krb5_context kcontext, krb5_magic odtype, krb5_pointer *argp, krb5_octet **bufpp, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_ser_handle	shandle;
+
+    kret = ENOENT;
+    /* See if the type is supported, if so, do it */
+    if ((shandle = krb5_find_serializer(kcontext, odtype)))
+	kret = (shandle->internalizer) ?
+	    (*shandle->internalizer)(kcontext, argp, bufpp, sizep) : 0;
+    return(kret);
+}
+
+/*
+ * krb5_ser_pack_int32()	- Pack a 4-byte integer if space is available.
+ *				  Update buffer pointer and remaining space.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_pack_int32(krb5_int32 iarg, krb5_octet **bufp, size_t *remainp)
+{
+    if (*remainp >= sizeof(krb5_int32)) {
+	(*bufp)[0] = (krb5_octet) ((iarg >> 24) & 0xff);
+	(*bufp)[1] = (krb5_octet) ((iarg >> 16) & 0xff);
+	(*bufp)[2] = (krb5_octet) ((iarg >> 8) & 0xff);
+	(*bufp)[3] = (krb5_octet) (iarg & 0xff);
+	*bufp += sizeof(krb5_int32);
+	*remainp -= sizeof(krb5_int32);
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
+
+/*
+ * krb5_ser_pack_int64()	- Pack an 8-byte integer if space is available.
+ *				  Update buffer pointer and remaining space.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_pack_int64(krb5_int64 iarg, krb5_octet **bufp, size_t *remainp)
+{
+    if (*remainp >= sizeof(krb5_int64)) {
+	store_64_be(iarg, (unsigned char *)*bufp);
+	*bufp += sizeof(krb5_int64);
+	*remainp -= sizeof(krb5_int64);
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
+
+/*
+ * krb5_ser_pack_bytes()	- Pack a string of bytes.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_pack_bytes(krb5_octet *ostring, size_t osize, krb5_octet **bufp, size_t *remainp)
+{
+    if (*remainp >= osize) {
+	memcpy(*bufp, ostring, osize);
+	*bufp += osize;
+	*remainp -= osize;
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
+
+/*
+ * krb5_ser_unpack_int32()	- Unpack a 4-byte integer if it's there.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_unpack_int32(krb5_int32 *intp, krb5_octet **bufp, size_t *remainp)
+{
+    if (*remainp >= sizeof(krb5_int32)) {
+	*intp = (((krb5_int32) ((unsigned char) (*bufp)[0]) << 24) |
+		 ((krb5_int32) ((unsigned char) (*bufp)[1]) << 16) |
+		 ((krb5_int32) ((unsigned char) (*bufp)[2]) << 8) |
+		 ((krb5_int32) ((unsigned char) (*bufp)[3])));
+	*bufp += sizeof(krb5_int32);
+	*remainp -= sizeof(krb5_int32);
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
+
+/*
+ * krb5_ser_unpack_int64()	- Unpack an 8-byte integer if it's there.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_unpack_int64(krb5_int64 *intp, krb5_octet **bufp, size_t *remainp)
+{
+    if (*remainp >= sizeof(krb5_int64)) {
+	*intp = load_64_be((unsigned char *)*bufp);
+	*bufp += sizeof(krb5_int64);
+	*remainp -= sizeof(krb5_int64);
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
+
+/*
+ * krb5_ser_unpack_bytes()	- Unpack a byte string if it's there.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_unpack_bytes(krb5_octet *istring, size_t isize, krb5_octet **bufp, size_t *remainp)
+{
+    if (*remainp >= isize) {
+	memcpy(istring, *bufp, isize);
+	*bufp += isize;
+	*remainp -= isize;
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
diff --git a/mechglue/src/lib/krb5/krb/set_realm.c b/mechglue/src/lib/krb5/krb/set_realm.c
new file mode 100644
index 000000000..16112a8da
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/set_realm.c
@@ -0,0 +1,52 @@
+/*
+ * lib/krb5/krb/set_realm.c
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_principal_realm(krb5_context context, krb5_principal principal, const char *realm)
+{
+	size_t	length;
+	char	*newrealm;
+	
+	if (!realm || !*realm)
+		return -EINVAL;
+
+	length = strlen(realm);
+	newrealm = malloc(length+1); /* Include room for the null */
+	if (!newrealm)
+		return -ENOMEM;
+	strcpy(newrealm, realm);
+	
+	(void) krb5_xfree(krb5_princ_realm(context,principal)->data);
+
+	krb5_princ_realm(context, principal)->length = length;
+	krb5_princ_realm(context, principal)->data = newrealm;
+
+	return 0;
+}
+
+
diff --git a/mechglue/src/lib/krb5/krb/srv_rcache.c b/mechglue/src/lib/krb5/krb/srv_rcache.c
new file mode 100644
index 000000000..898b3f687
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/srv_rcache.c
@@ -0,0 +1,132 @@
+/*
+ * lib/krb5/krb/srv_rcache.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Allocate & prepare a default replay cache for a server.
+ */
+
+#include "k5-int.h"
+#include <ctype.h>
+#include <stdio.h>
+
+/* Macro for valid RC name characters*/
+#define isvalidrcname(x) ((!ispunct(x))&&isgraph(x))
+krb5_error_code KRB5_CALLCONV
+krb5_get_server_rcache(krb5_context context, const krb5_data *piece,
+		       krb5_rcache *rcptr)
+{
+    krb5_rcache rcache = 0;
+    char *cachename = 0, *cachetype;
+    char tmp[4];
+    krb5_error_code retval;
+    int p, i;
+    unsigned int len;
+
+#ifdef HAVE_GETEUID
+    unsigned long tens;
+    unsigned long uid = geteuid();
+#endif
+    
+    if (piece == NULL)
+	return ENOMEM;
+    
+    cachetype = krb5_rc_default_type(context);
+
+    len = piece->length + 3 + 1;
+    for (i = 0; i < piece->length; i++) {
+	if (piece->data[i] == '-')
+	    len++;
+	else if (!isvalidrcname((int) piece->data[i]))
+	    len += 3;
+    }
+
+#ifdef HAVE_GETEUID
+    len += 2;	/* _<uid> */
+    for (tens = 1; (uid / tens) > 9 ; tens *= 10)
+	len++;
+#endif
+    
+    cachename = malloc(strlen(cachetype) + 5 + len);
+    if (!cachename) {
+	retval = ENOMEM;
+	goto cleanup;
+    }
+    strcpy(cachename, cachetype);
+
+    p = strlen(cachename);
+    cachename[p++] = ':';
+    for (i = 0; i < piece->length; i++) {
+	if (piece->data[i] == '-') {
+	    cachename[p++] = '-';
+	    cachename[p++] = '-';
+	    continue;
+	}
+	if (!isvalidrcname((int) piece->data[i])) {
+	    sprintf(tmp, "%03o", piece->data[i]);
+	    cachename[p++] = '-';
+	    cachename[p++] = tmp[0];
+	    cachename[p++] = tmp[1];
+	    cachename[p++] = tmp[2];
+	    continue;
+	}
+	cachename[p++] = piece->data[i];
+    }
+
+#ifdef HAVE_GETEUID
+    cachename[p++] = '_';
+    while (tens) {
+	cachename[p++] = '0' + ((uid / tens) % 10);
+	tens /= 10;
+    }
+#endif
+
+    cachename[p++] = '\0';
+
+    retval = krb5_rc_resolve_full(context, &rcache, cachename);
+    if (retval)
+	goto cleanup;
+
+    /*
+     * First try to recover the replay cache; if that doesn't work,
+     * initialize it.
+     */
+    retval = krb5_rc_recover_or_initialize(context, rcache, context->clockskew);
+    if (retval) {
+	krb5_rc_close(context, rcache);
+	rcache = 0;
+	goto cleanup;
+    }
+
+    *rcptr = rcache;
+    rcache = 0;
+    retval = 0;
+
+cleanup:
+    if (rcache)
+	krb5_xfree(rcache);
+    if (cachename)
+	krb5_xfree(cachename);
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/krb/str_conv.c b/mechglue/src/lib/krb5/krb/str_conv.c
new file mode 100644
index 000000000..60bb2f6f4
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/str_conv.c
@@ -0,0 +1,376 @@
+/*
+ * lib/kadm/str_conv.c
+ *
+ * Copyright 1995, 1999 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * str_conv.c - Convert between strings and Kerberos internal data.
+ */
+
+/*
+ * Table of contents:
+ *
+ * String decoding:
+ * ----------------
+ * krb5_string_to_salttype()	- Convert string to salttype (krb5_int32)
+ * krb5_string_to_timestamp()	- Convert string to krb5_timestamp.
+ * krb5_string_to_deltat()	- Convert string to krb5_deltat.
+ *
+ * String encoding:
+ * ----------------
+ * krb5_salttype_to_string()	- Convert salttype (krb5_int32) to string.
+ * krb5_timestamp_to_string()	- Convert krb5_timestamp to string.
+ * krb5_timestamp_to_sfstring()	- Convert krb5_timestamp to short filled string
+ * krb5_deltat_to_string()	- Convert krb5_deltat to string.
+ */
+
+#include "k5-int.h"
+#include <ctype.h>
+
+/* Salt type conversions */
+
+/*
+ * Local data structures.
+ */
+struct salttype_lookup_entry {
+    krb5_int32		stt_enctype;		/* Salt type		*/
+    const char *	stt_specifier;		/* How to recognize it	*/
+    const char *	stt_output;		/* How to spit it out	*/
+};
+
+/*
+ * Lookup tables.
+ */
+
+static const struct salttype_lookup_entry salttype_table[] = {
+/* salt type			input specifier	output string  */
+/*-----------------------------	--------------- ---------------*/
+{ KRB5_KDB_SALTTYPE_NORMAL,	"normal",	"Version 5"	  },
+{ KRB5_KDB_SALTTYPE_V4,		"v4",		"Version 4"	  },
+{ KRB5_KDB_SALTTYPE_NOREALM,	"norealm",	"Version 5 - No Realm" },
+{ KRB5_KDB_SALTTYPE_ONLYREALM,	"onlyrealm",	"Version 5 - Realm Only" },
+{ KRB5_KDB_SALTTYPE_SPECIAL,	"special",	"Special" },
+{ KRB5_KDB_SALTTYPE_AFS3,	"afs3",		"AFS version 3"    }
+};
+static const int salttype_table_nents = sizeof(salttype_table)/
+					sizeof(salttype_table[0]);
+
+krb5_error_code KRB5_CALLCONV
+krb5_string_to_salttype(char *string, krb5_int32 *salttypep)
+{
+    int i;
+    int found;
+
+    found = 0;
+    for (i=0; i<salttype_table_nents; i++) {
+	if (!strcasecmp(string, salttype_table[i].stt_specifier)) {
+	    found = 1;
+	    *salttypep = salttype_table[i].stt_enctype;
+	    break;
+	}
+    }
+    return((found) ? 0 : EINVAL);
+}
+
+/*
+ * Internal datatype to string routines.
+ *
+ * These routines return 0 for success, EINVAL for invalid parameter, ENOMEM
+ * if the supplied buffer/length will not contain the output.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_salttype_to_string(krb5_int32 salttype, char *buffer, size_t buflen)
+{
+    int i;
+    const char *out;
+
+    out = (char *) NULL;
+    for (i=0; i<salttype_table_nents; i++) {
+	if (salttype ==  salttype_table[i].stt_enctype) {
+	    out = salttype_table[i].stt_output;
+	    break;
+	}
+    }
+    if (out) {
+	if (buflen > strlen(out))
+	    strcpy(buffer, out);
+	else
+	    out = (char *) NULL;
+	return((out) ? 0 : ENOMEM);
+    }
+    else
+	return(EINVAL);
+}
+
+/* (absolute) time conversions */
+
+#ifndef HAVE_STRFTIME
+#undef strftime
+#define strftime my_strftime
+static size_t strftime (char *, size_t, const char *, const struct tm *);
+#endif
+
+#ifdef HAVE_STRPTIME
+#ifdef NEED_STRPTIME_PROTO
+extern char *strptime (const char *, const char *,
+			    struct tm *)
+#ifdef __cplusplus
+    throw()
+#endif
+    ;
+#endif
+#else /* HAVE_STRPTIME */
+#undef strptime
+#define strptime my_strptime
+static char *strptime (const char *, const char *, struct tm *);
+#endif
+
+krb5_error_code KRB5_CALLCONV
+krb5_string_to_timestamp(char *string, krb5_timestamp *timestampp)
+{
+    int i;
+    struct tm timebuf;
+    time_t now, ret_time;
+    char *s;
+    static const char * const atime_format_table[] = {
+	"%Y%m%d%H%M%S",		/* yyyymmddhhmmss		*/
+	"%Y.%m.%d.%H.%M.%S",	/* yyyy.mm.dd.hh.mm.ss		*/
+	"%y%m%d%H%M%S",		/* yymmddhhmmss			*/
+	"%y.%m.%d.%H.%M.%S",	/* yy.mm.dd.hh.mm.ss		*/
+	"%y%m%d%H%M",		/* yymmddhhmm			*/
+	"%H%M%S",		/* hhmmss			*/
+	"%H%M",			/* hhmm				*/
+	"%T",			/* hh:mm:ss			*/
+	"%R",			/* hh:mm			*/
+	/* The following not really supported unless native strptime present */
+	"%x:%X",		/* locale-dependent short format */
+	"%d-%b-%Y:%T",		/* dd-month-yyyy:hh:mm:ss	*/
+	"%d-%b-%Y:%R"		/* dd-month-yyyy:hh:mm		*/
+    };
+    static const int atime_format_table_nents =
+	sizeof(atime_format_table)/sizeof(atime_format_table[0]);
+
+
+    now = time((time_t *) NULL);
+    for (i=0; i<atime_format_table_nents; i++) {
+        /* We reset every time throughout the loop as the manual page
+	 * indicated that no guarantees are made as to preserving timebuf
+	 * when parsing fails
+	 */
+#ifdef HAVE_LOCALTIME_R
+	(void) localtime_r(&now, &timebuf);
+#else
+	memcpy(&timebuf, localtime(&now), sizeof(timebuf));
+#endif
+	if ((s = strptime(string, atime_format_table[i], &timebuf))
+	    && (s != string)) {
+ 	    /* See if at end of buffer - otherwise partial processing */
+	    while(*s != 0 && isspace((int) *s)) s++;
+	    if (*s != 0)
+	        continue;
+	    if (timebuf.tm_year <= 0)
+		continue;	/* clearly confused */
+	    ret_time = mktime(&timebuf);
+	    if (ret_time == (time_t) -1)
+		continue;	/* clearly confused */
+	    *timestampp = (krb5_timestamp) ret_time;
+	    return 0;
+	}
+    }
+    return(EINVAL);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_timestamp_to_string(krb5_timestamp timestamp, char *buffer, size_t buflen)
+{
+    int ret;
+    time_t timestamp2 = timestamp;
+    struct tm tmbuf;
+    const char *fmt = "%c"; /* This is to get around gcc -Wall warning that 
+			       the year returned might be two digits */
+
+#ifdef HAVE_LOCALTIME_R
+    (void) localtime_r(×tamp2, &tmbuf);
+#else
+    memcpy(&tmbuf, localtime(×tamp2), sizeof(tmbuf));
+#endif
+    ret = strftime(buffer, buflen, fmt, &tmbuf);
+    if (ret == 0 || ret == buflen)
+	return(ENOMEM);
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_timestamp_to_sfstring(krb5_timestamp timestamp, char *buffer, size_t buflen, char *pad)
+{
+    struct tm	*tmp;
+    size_t i;
+    size_t	ndone;
+    time_t timestamp2 = timestamp;
+    struct tm tmbuf;
+
+    static const char * const sftime_format_table[] = {
+	"%c",			/* Default locale-dependent date and time */
+	"%d %b %Y %T",		/* dd mon yyyy hh:mm:ss			*/
+	"%x %X",		/* locale-dependent short format	*/
+	"%d/%m/%Y %R"		/* dd/mm/yyyy hh:mm			*/
+    };
+    static const int sftime_format_table_nents =
+	sizeof(sftime_format_table)/sizeof(sftime_format_table[0]);
+
+#ifdef HAVE_LOCALTIME_R
+    tmp = localtime_r(×tamp2, &tmbuf);
+#else
+    memcpy((tmp = &tmbuf), localtime(×tamp2), sizeof(tmbuf));
+#endif
+    ndone = 0;
+    for (i=0; i<sftime_format_table_nents; i++) {
+	if ((ndone = strftime(buffer, buflen, sftime_format_table[i], tmp)))
+	    break;
+    }
+    if (!ndone) {
+#define sftime_default_len	2+1+2+1+4+1+2+1+2+1
+	if (buflen >= sftime_default_len) {
+	    sprintf(buffer, "%02d/%02d/%4d %02d:%02d",
+		    tmp->tm_mday, tmp->tm_mon+1, 1900+tmp->tm_year,
+		    tmp->tm_hour, tmp->tm_min);
+	    ndone = strlen(buffer);
+	}
+    }
+    if (ndone && pad) {
+	for (i=ndone; i<buflen-1; i++)
+	    buffer[i] = *pad;
+	buffer[buflen-1] = '\0';
+    }
+    return((ndone) ? 0 : ENOMEM);
+}
+
+/* relative time (delta-t) conversions */
+
+/* string->deltat is in deltat.y */
+
+krb5_error_code KRB5_CALLCONV
+krb5_deltat_to_string(krb5_deltat deltat, char *buffer, size_t buflen)
+{
+    int			days, hours, minutes, seconds;
+    krb5_deltat		dt;
+
+    /*
+     * We want something like ceil(log10(2**(nbits-1))) + 1.  That log
+     * value is log10(2)*(nbits-1) or log10(2**8)*(nbits-1)/8.  So,
+     * 2.4... is log10(256), rounded up.  Add one to handle leading
+     * minus, and one more to force int cast to round the value up.
+     * This doesn't include room for a trailing nul.
+     *
+     * This will break if bytes are more than 8 bits.
+     */
+#define MAX_CHARS_FOR_INT_TYPE(TYPE)	((int) (2 + 2.408241 * sizeof (TYPE)))
+    char tmpbuf[MAX_CHARS_FOR_INT_TYPE(int) * 4 + 8];
+
+    days = (int) (deltat / (24*3600L));
+    dt = deltat % (24*3600L);
+    hours = (int) (dt / 3600);
+    dt %= 3600;
+    minutes = (int) (dt / 60);
+    seconds = (int) (dt % 60);
+
+    memset (tmpbuf, 0, sizeof (tmpbuf));
+    if (days == 0)
+	sprintf(buffer, "%d:%02d:%02d", hours, minutes, seconds);
+    else if (hours || minutes || seconds)
+	sprintf(buffer, "%d %s %02d:%02d:%02d", days,
+		(days > 1) ? "days" : "day",
+		hours, minutes, seconds);
+    else
+	sprintf(buffer, "%d %s", days,
+		(days > 1) ? "days" : "day");
+    if (tmpbuf[sizeof(tmpbuf)-1] != 0)
+	/* Something must be very wrong with my math above, or the
+	   assumptions going into it...  */
+	abort ();
+    if (strlen (tmpbuf) > buflen)
+	return ENOMEM;
+    else
+	strncpy (buffer, tmpbuf, buflen);
+    return 0;
+}
+
+#undef __P
+#define __P(X) X
+
+#if !defined (HAVE_STRFTIME) || !defined (HAVE_STRPTIME)
+#undef _CurrentTimeLocale
+#define _CurrentTimeLocale (&dummy_locale_info)
+
+struct dummy_locale_info_t {
+    char d_t_fmt[15];
+    char t_fmt_ampm[12];
+    char t_fmt[9];
+    char d_fmt[9];
+    char day[7][10];
+    char abday[7][4];
+    char mon[12][10];
+    char abmon[12][4];
+    char am_pm[2][3];
+};
+static const struct dummy_locale_info_t dummy_locale_info = {
+    "%a %b %d %X %Y",		/* %c */
+    "%I:%M:%S %p",		/* %r */
+    "%H:%M:%S",			/* %X */
+    "%m/%d/%y",			/* %x */
+    { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
+      "Saturday" },
+    { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
+    { "January", "February", "March", "April", "May", "June",
+      "July", "August", "September", "October", "November", "December" },
+    { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" },
+    { "AM", "PM" },
+};
+#undef  TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif
+
+#ifndef HAVE_STRFTIME
+#undef  DAYSPERLYEAR
+#define DAYSPERLYEAR 366
+#undef  DAYSPERNYEAR
+#define DAYSPERNYEAR 365
+#undef  DAYSPERWEEK
+#define DAYSPERWEEK 7
+#undef  isleap
+#define isleap(N)	((N % 4) == 0 && (N % 100 != 0 || N % 400 == 0))
+#undef  tzname
+#define tzname my_tzname
+static const char *const tzname[2] = { 0, 0 };
+#undef  tzset
+#define tzset()
+
+#include "strftime.c"
+#endif
+
+#ifndef HAVE_STRPTIME
+#include "strptime.c"
+#endif
diff --git a/mechglue/src/lib/krb5/krb/strftime.c b/mechglue/src/lib/krb5/krb/strftime.c
new file mode 100644
index 000000000..f2a5cb719
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/strftime.c
@@ -0,0 +1,415 @@
+/*	$NetBSD: strftime.c,v 1.8 1999/02/07 17:33:30 augustss Exp $	*/
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char *sccsid = "@(#)strftime.c	5.11 (Berkeley) 2/24/91";
+#else
+__RCSID("$NetBSD: strftime.c,v 1.8 1999/02/07 17:33:30 augustss Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <string.h>
+#include <time.h>
+
+static	int _add __P((const char *, char **, const char *));
+static	int _conv __P((int, int, int, char **, const char *));
+static	int _secs __P((const struct tm *, char **, const char *));
+static	size_t _fmt __P((const char *, const struct tm *, char **,
+	    const char *));
+
+static size_t
+strftime(s, maxsize, format, t)
+	char *s;
+	size_t maxsize;
+	const char *format;
+	const struct tm *t;
+{
+	char *pt;
+
+	tzset();
+	if (maxsize < 1)
+		return (0);
+
+	pt = s;
+	if (_fmt(format, t, &pt, s + maxsize)) {
+		*pt = '\0';
+		return (pt - s);
+	} else
+		return (0);
+}
+
+#define SUN_WEEK(t)	(((t)->tm_yday + 7 - \
+				((t)->tm_wday)) / 7)
+#define MON_WEEK(t)	(((t)->tm_yday + 7 - \
+				((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7)
+
+static size_t
+_fmt(format, t, pt, ptlim)
+	const char *format;
+	const struct tm *t;
+	char **pt;
+	const char * const ptlim;
+{
+	for (; *format; ++format) {
+		if (*format == '%') {
+			++format;
+			if (*format == 'E') {
+				/* Alternate Era */
+				++format;
+			} else if (*format == 'O') {
+				/* Alternate numeric symbols */
+				++format;
+			}
+			switch (*format) {
+			case '\0':
+				--format;
+				break;
+			case 'A':
+				if (t->tm_wday < 0 || t->tm_wday > 6)
+					return (0);
+				if (!_add(_CurrentTimeLocale->day[t->tm_wday],
+				    pt, ptlim))
+					return (0);
+				continue;
+
+			case 'a':
+				if (t->tm_wday < 0 || t->tm_wday > 6)
+					return (0);
+				if (!_add(_CurrentTimeLocale->abday[t->tm_wday],
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'B':
+				if (t->tm_mon < 0 || t->tm_mon > 11)
+					return (0);
+				if (!_add(_CurrentTimeLocale->mon[t->tm_mon],
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'b':
+			case 'h':
+				if (t->tm_mon < 0 || t->tm_mon > 11)
+					return (0);
+				if (!_add(_CurrentTimeLocale->abmon[t->tm_mon],
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'C':
+				if (!_conv((t->tm_year + TM_YEAR_BASE) / 100,
+				    2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'c':
+				if (!_fmt(_CurrentTimeLocale->d_t_fmt, t, pt,
+				    ptlim))
+					return (0);
+				continue;
+			case 'D':
+				if (!_fmt("%m/%d/%y", t, pt, ptlim))
+					return (0);
+				continue;
+			case 'd':
+				if (!_conv(t->tm_mday, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'e':
+				if (!_conv(t->tm_mday, 2, ' ', pt, ptlim))
+					return (0);
+				continue;
+			case 'H':
+				if (!_conv(t->tm_hour, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'I':
+				if (!_conv(t->tm_hour % 12 ?
+				    t->tm_hour % 12 : 12, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'j':
+				if (!_conv(t->tm_yday + 1, 3, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'k':
+				if (!_conv(t->tm_hour, 2, ' ', pt, ptlim))
+					return (0);
+				continue;
+			case 'l':
+				if (!_conv(t->tm_hour % 12 ?
+				    t->tm_hour % 12: 12, 2, ' ', pt, ptlim))
+					return (0);
+				continue;
+			case 'M':
+				if (!_conv(t->tm_min, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'm':
+				if (!_conv(t->tm_mon + 1, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'n':
+				if (!_add("\n", pt, ptlim))
+					return (0);
+				continue;
+			case 'p':
+				if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour
+				    >= 12], pt, ptlim))
+					return (0);
+				continue;
+			case 'R':
+				if (!_fmt("%H:%M", t, pt, ptlim))
+					return (0);
+				continue;
+			case 'r':
+				if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t, pt,
+				    ptlim))
+					return (0);
+				continue;
+			case 'S':
+				if (!_conv(t->tm_sec, 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 's':
+				if (!_secs(t, pt, ptlim))
+					return (0);
+				continue;
+			case 'T':
+				if (!_fmt("%H:%M:%S", t, pt, ptlim))
+					return (0);
+				continue;
+			case 't':
+				if (!_add("\t", pt, ptlim))
+					return (0);
+				continue;
+			case 'U':
+				if (!_conv(SUN_WEEK(t), 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'u':
+				if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0',
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'V':	/* ISO 8601 week number */
+			case 'G':	/* ISO 8601 year (four digits) */
+			case 'g':	/* ISO 8601 year (two digits) */
+/*
+** From Arnold Robbins' strftime version 3.0:  "the week number of the
+** year (the first Monday as the first day of week 1) as a decimal number
+** (01-53)."
+** (ado, 1993-05-24)
+**
+** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
+** "Week 01 of a year is per definition the first week which has the
+** Thursday in this year, which is equivalent to the week which contains
+** the fourth day of January. In other words, the first week of a new year
+** is the week which has the majority of its days in the new year. Week 01
+** might also contain days from the previous year and the week before week
+** 01 of a year is the last week (52 or 53) of the previous year even if
+** it contains days from the new year. A week starts with Monday (day 1)
+** and ends with Sunday (day 7).  For example, the first week of the year
+** 1997 lasts from 1996-12-30 to 1997-01-05..."
+** (ado, 1996-01-02)
+*/
+				{
+					int	year;
+					int	yday;
+					int	wday;
+					int	w;
+
+					year = t->tm_year + TM_YEAR_BASE;
+					yday = t->tm_yday;
+					wday = t->tm_wday;
+					for ( ; ; ) {
+						int	len;
+						int	bot;
+						int	top;
+
+						len = isleap(year) ?
+							DAYSPERLYEAR :
+							DAYSPERNYEAR;
+						/*
+						** What yday (-3 ... 3) does
+						** the ISO year begin on?
+						*/
+						bot = ((yday + 11 - wday) %
+							DAYSPERWEEK) - 3;
+						/*
+						** What yday does the NEXT
+						** ISO year begin on?
+						*/
+						top = bot -
+							(len % DAYSPERWEEK);
+						if (top < -3)
+							top += DAYSPERWEEK;
+						top += len;
+						if (yday >= top) {
+							++year;
+							w = 1;
+							break;
+						}
+						if (yday >= bot) {
+							w = 1 + ((yday - bot) /
+								DAYSPERWEEK);
+							break;
+						}
+						--year;
+						yday += isleap(year) ?
+							DAYSPERLYEAR :
+							DAYSPERNYEAR;
+					}
+#ifdef XPG4_1994_04_09
+					if ((w == 52
+					     && t->tm_mon == TM_JANUARY)
+					    || (w == 1
+						&& t->tm_mon == TM_DECEMBER))
+						w = 53;
+#endif /* defined XPG4_1994_04_09 */
+					if (*format == 'V') {
+						if (!_conv(w, 2, '0',
+							pt, ptlim))
+							return (0);
+					} else if (*format == 'g') {
+						if (!_conv(year % 100, 2, '0',
+							pt, ptlim))
+							return (0);
+					} else	if (!_conv(year, 4, '0',
+							pt, ptlim))
+							return (0);
+				}
+				continue;
+			case 'W':
+				if (!_conv(MON_WEEK(t), 2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'w':
+				if (!_conv(t->tm_wday, 1, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'x':
+				if (!_fmt(_CurrentTimeLocale->d_fmt, t, pt,
+				    ptlim))
+					return (0);
+				continue;
+			case 'X':
+				if (!_fmt(_CurrentTimeLocale->t_fmt, t, pt,
+				    ptlim))
+					return (0);
+				continue;
+			case 'y':
+				if (!_conv((t->tm_year + TM_YEAR_BASE) % 100,
+				    2, '0', pt, ptlim))
+					return (0);
+				continue;
+			case 'Y':
+				if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0',
+				    pt, ptlim))
+					return (0);
+				continue;
+			case 'Z':
+				if (tzname[t->tm_isdst ? 1 : 0] &&
+				    !_add(tzname[t->tm_isdst ? 1 : 0], pt,
+				    ptlim))
+					return (0);
+				continue;
+			case '%':
+			/*
+			 * X311J/88-090 (4.12.3.5): if conversion char is
+			 * undefined, behavior is undefined.  Print out the
+			 * character itself as printf(3) does.
+			 */
+			default:
+				break;
+			}
+		}
+		if (*pt == ptlim)
+			return (0);
+		*(*pt)++ = *format;
+	}
+	return (ptlim - *pt);
+}
+
+static int
+_secs(t, pt, ptlim)
+	const struct tm *t;
+	char **pt;
+	const char * const ptlim;
+{
+	char buf[15];
+	time_t s;
+	char *p;
+	struct tm tmp;
+
+	buf[sizeof (buf) - 1] = '\0';
+	/* Make a copy, mktime(3) modifies the tm struct. */
+	tmp = *t;
+	s = mktime(&tmp);
+	for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10)
+		*p-- = (char)(s % 10 + '0');
+	return (_add(++p, pt, ptlim));
+}
+
+static int
+_conv(n, digits, pad, pt, ptlim)
+	int n, digits;
+	int pad;
+	char **pt;
+	const char * const ptlim;
+{
+	char buf[10];
+	char *p;
+
+	buf[sizeof (buf) - 1] = '\0';
+	for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
+		*p-- = n % 10 + '0';
+	while (p > buf && digits-- > 0)
+		*p-- = pad;
+	return (_add(++p, pt, ptlim));
+}
+
+static int
+_add(str, pt, ptlim)
+	const char *str;
+	char **pt;
+	const char * const ptlim;
+{
+
+	for (;; ++(*pt)) {
+		if (*pt == ptlim)
+			return (0);
+		if ((**pt = *str++) == '\0')
+			return (1);
+	}
+}
diff --git a/mechglue/src/lib/krb5/krb/strptime.c b/mechglue/src/lib/krb5/krb/strptime.c
new file mode 100644
index 000000000..ac52d5c22
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/strptime.c
@@ -0,0 +1,386 @@
+/*	$NetBSD: strptime.c,v 1.18 1999/04/29 02:58:30 tv Exp $	*/
+
+/*-
+ * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code was contributed to The NetBSD Foundation by Klaus Klein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: strptime.c,v 1.18 1999/04/29 02:58:30 tv Exp $");
+#endif
+
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+
+#undef _ctloc
+#define _ctloc(x)		_CurrentTimeLocale->x
+
+/*
+ * We do not implement alternate representations. However, we always
+ * check whether a given modifier is allowed for a certain conversion.
+ */
+#define ALT_E			0x01
+#define ALT_O			0x02
+#define	LEGAL_ALT(x)		{ if (alt_format & ~(x)) return (0); }
+
+
+static	int conv_num __P((const char **, int *, int, int));
+
+
+static char *
+strptime(buf, fmt, tm)
+	const char *buf, *fmt;
+	struct tm *tm;
+{
+	char c;
+	const char *bp;
+	size_t len = 0;
+	int alt_format, i, split_year = 0;
+
+	bp = buf;
+
+	while ((c = *fmt) != '\0') {
+		/* Clear `alternate' modifier prior to new conversion. */
+		alt_format = 0;
+
+		/* Eat up white-space. */
+		if (isspace(c)) {
+			while (isspace(*bp))
+				bp++;
+
+			fmt++;
+			continue;
+		}
+				
+		if ((c = *fmt++) != '%')
+			goto literal;
+
+
+again:		switch (c = *fmt++) {
+		case '%':	/* "%%" is converted to "%". */
+literal:
+			if (c != *bp++)
+				return (0);
+			break;
+
+		/*
+		 * "Alternative" modifiers. Just set the appropriate flag
+		 * and start over again.
+		 */
+		case 'E':	/* "%E?" alternative conversion modifier. */
+			LEGAL_ALT(0);
+			alt_format |= ALT_E;
+			goto again;
+
+		case 'O':	/* "%O?" alternative conversion modifier. */
+			LEGAL_ALT(0);
+			alt_format |= ALT_O;
+			goto again;
+			
+		/*
+		 * "Complex" conversion rules, implemented through recursion.
+		 */
+		case 'c':	/* Date and time, using the locale's format. */
+			LEGAL_ALT(ALT_E);
+			if (!(bp = strptime(bp, _ctloc(d_t_fmt), tm)))
+				return (0);
+			break;
+
+		case 'D':	/* The date as "%m/%d/%y". */
+			LEGAL_ALT(0);
+			if (!(bp = strptime(bp, "%m/%d/%y", tm)))
+				return (0);
+			break;
+
+		case 'R':	/* The time as "%H:%M". */
+			LEGAL_ALT(0);
+			if (!(bp = strptime(bp, "%H:%M", tm)))
+				return (0);
+			break;
+
+		case 'r':	/* The time in 12-hour clock representation. */
+			LEGAL_ALT(0);
+			if (!(bp = strptime(bp, _ctloc(t_fmt_ampm), tm)))
+				return (0);
+			break;
+
+		case 'T':	/* The time as "%H:%M:%S". */
+			LEGAL_ALT(0);
+			if (!(bp = strptime(bp, "%H:%M:%S", tm)))
+				return (0);
+			break;
+
+		case 'X':	/* The time, using the locale's format. */
+			LEGAL_ALT(ALT_E);
+			if (!(bp = strptime(bp, _ctloc(t_fmt), tm)))
+				return (0);
+			break;
+
+		case 'x':	/* The date, using the locale's format. */
+			LEGAL_ALT(ALT_E);
+			if (!(bp = strptime(bp, _ctloc(d_fmt), tm)))
+				return (0);
+			break;
+
+		/*
+		 * "Elementary" conversion rules.
+		 */
+		case 'A':	/* The day of week, using the locale's form. */
+		case 'a':
+			LEGAL_ALT(0);
+			for (i = 0; i < 7; i++) {
+				/* Full name. */
+				len = strlen(_ctloc(day[i]));
+				if (strncasecmp(_ctloc(day[i]), bp, len) == 0)
+					break;
+
+				/* Abbreviated name. */
+				len = strlen(_ctloc(abday[i]));
+				if (strncasecmp(_ctloc(abday[i]), bp, len) == 0)
+					break;
+			}
+
+			/* Nothing matched. */
+			if (i == 7)
+				return (0);
+
+			tm->tm_wday = i;
+			bp += len;
+			break;
+
+		case 'B':	/* The month, using the locale's form. */
+		case 'b':
+		case 'h':
+			LEGAL_ALT(0);
+			for (i = 0; i < 12; i++) {
+				/* Full name. */
+				len = strlen(_ctloc(mon[i]));
+				if (strncasecmp(_ctloc(mon[i]), bp, len) == 0)
+					break;
+
+				/* Abbreviated name. */
+				len = strlen(_ctloc(abmon[i]));
+				if (strncasecmp(_ctloc(abmon[i]), bp, len) == 0)
+					break;
+			}
+
+			/* Nothing matched. */
+			if (i == 12)
+				return (0);
+
+			tm->tm_mon = i;
+			bp += len;
+			break;
+
+		case 'C':	/* The century number. */
+			LEGAL_ALT(ALT_E);
+			if (!(conv_num(&bp, &i, 0, 99)))
+				return (0);
+
+			if (split_year) {
+				tm->tm_year = (tm->tm_year % 100) + (i * 100);
+			} else {
+				tm->tm_year = i * 100;
+				split_year = 1;
+			}
+			break;
+
+		case 'd':	/* The day of month. */
+		case 'e':
+			LEGAL_ALT(ALT_O);
+			if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
+				return (0);
+			break;
+
+		case 'k':	/* The hour (24-hour clock representation). */
+			LEGAL_ALT(0);
+			/* FALLTHROUGH */
+		case 'H':
+			LEGAL_ALT(ALT_O);
+			if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
+				return (0);
+			break;
+
+		case 'l':	/* The hour (12-hour clock representation). */
+			LEGAL_ALT(0);
+			/* FALLTHROUGH */
+		case 'I':
+			LEGAL_ALT(ALT_O);
+			if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
+				return (0);
+			if (tm->tm_hour == 12)
+				tm->tm_hour = 0;
+			break;
+
+		case 'j':	/* The day of year. */
+			LEGAL_ALT(0);
+			if (!(conv_num(&bp, &i, 1, 366)))
+				return (0);
+			tm->tm_yday = i - 1;
+			break;
+
+		case 'M':	/* The minute. */
+			LEGAL_ALT(ALT_O);
+			if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
+				return (0);
+			break;
+
+		case 'm':	/* The month. */
+			LEGAL_ALT(ALT_O);
+			if (!(conv_num(&bp, &i, 1, 12)))
+				return (0);
+			tm->tm_mon = i - 1;
+			break;
+
+		case 'p':	/* The locale's equivalent of AM/PM. */
+			LEGAL_ALT(0);
+			/* AM? */
+			if (strcasecmp(_ctloc(am_pm[0]), bp) == 0) {
+				if (tm->tm_hour > 11)
+					return (0);
+
+				bp += strlen(_ctloc(am_pm[0]));
+				break;
+			}
+			/* PM? */
+			else if (strcasecmp(_ctloc(am_pm[1]), bp) == 0) {
+				if (tm->tm_hour > 11)
+					return (0);
+
+				tm->tm_hour += 12;
+				bp += strlen(_ctloc(am_pm[1]));
+				break;
+			}
+
+			/* Nothing matched. */
+			return (0);
+
+		case 'S':	/* The seconds. */
+			LEGAL_ALT(ALT_O);
+			if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
+				return (0);
+			break;
+
+		case 'U':	/* The week of year, beginning on sunday. */
+		case 'W':	/* The week of year, beginning on monday. */
+			LEGAL_ALT(ALT_O);
+			/*
+			 * XXX This is bogus, as we can not assume any valid
+			 * information present in the tm structure at this
+			 * point to calculate a real value, so just check the
+			 * range for now.
+			 */
+			 if (!(conv_num(&bp, &i, 0, 53)))
+				return (0);
+			 break;
+
+		case 'w':	/* The day of week, beginning on sunday. */
+			LEGAL_ALT(ALT_O);
+			if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
+				return (0);
+			break;
+
+		case 'Y':	/* The year. */
+			LEGAL_ALT(ALT_E);
+			if (!(conv_num(&bp, &i, 0, 9999)))
+				return (0);
+
+			tm->tm_year = i - TM_YEAR_BASE;
+			break;
+
+		case 'y':	/* The year within 100 years of the epoch. */
+			LEGAL_ALT(ALT_E | ALT_O);
+			if (!(conv_num(&bp, &i, 0, 99)))
+				return (0);
+
+			if (split_year) {
+				tm->tm_year = ((tm->tm_year / 100) * 100) + i;
+				break;
+			}
+			split_year = 1;
+			if (i <= 68)
+				tm->tm_year = i + 2000 - TM_YEAR_BASE;
+			else
+				tm->tm_year = i + 1900 - TM_YEAR_BASE;
+			break;
+
+		/*
+		 * Miscellaneous conversions.
+		 */
+		case 'n':	/* Any kind of white-space. */
+		case 't':
+			LEGAL_ALT(0);
+			while (isspace(*bp))
+				bp++;
+			break;
+
+
+		default:	/* Unknown/unsupported conversion. */
+			return (0);
+		}
+
+
+	}
+
+	/* LINTED functional specification */
+	return ((char *)bp);
+}
+
+
+static int
+conv_num(buf, dest, llim, ulim)
+	const char **buf;
+	int *dest;
+	int llim, ulim;
+{
+	int result = 0;
+
+	/* The limit also determines the number of valid digits. */
+	int rulim = ulim;
+
+	if (**buf < '0' || **buf > '9')
+		return (0);
+
+	do {
+		result *= 10;
+		result += *(*buf)++ - '0';
+		rulim /= 10;
+	} while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
+
+	if (result < llim || result > ulim)
+		return (0);
+
+	*dest = result;
+	return (1);
+}
diff --git a/mechglue/src/lib/krb5/krb/t_deltat.c b/mechglue/src/lib/krb5/krb/t_deltat.c
new file mode 100644
index 000000000..a07ba4232
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/t_deltat.c
@@ -0,0 +1,158 @@
+/*
+ * lib/krb5/krb/t_deltat.c
+ *
+ * Copyright 1999 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "k5-int.h"
+
+int
+main (void)
+{
+    struct {
+	char *string;
+	krb5_deltat expected;
+	int is_error;
+#define GOOD(STR,VAL) { STR, VAL, 0 }
+#define BAD(STR) { STR, 0, 1 }
+#define DAY (24 * 3600)
+#define HOUR 3600
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN 60
+    } values[] = {
+	/* d-h-m-s patterns */
+	GOOD ("3d", 3*DAY),
+	GOOD ("3h", 3*HOUR),
+	GOOD ("3m", 3*MIN),
+	GOOD ("3s", 3),
+	BAD ("3dd"),
+	GOOD ("3d4m    42s", 3 * DAY + 4 * MIN + 42),
+	GOOD ("3d-1h", 3 * DAY - 1 * HOUR),
+	GOOD ("3d -1h", 3 * DAY - HOUR),
+	GOOD ("3d4h5m6s", 3 * DAY + 4 * HOUR + 5 * MIN + 6),
+	BAD ("3d4m5h"),
+	GOOD ("12345s", 12345),
+	GOOD ("1m 12345s", MIN + 12345),
+	GOOD ("1m12345s", MIN + 12345),
+	GOOD ("3d 0m", 3 * DAY),
+	GOOD ("3d 0m  ", 3 * DAY),
+	GOOD ("3d \n\t 0m  ", 3 * DAY),
+	/* colon patterns */
+	GOOD ("42-13:42:47", 42 * DAY + 13 * HOUR + 42 * MIN + 47),
+	BAD ("3: 4"),
+	BAD ("13:0003"),
+	GOOD ("12:34", 12 * HOUR + 34 * MIN),
+	GOOD ("1:02:03", 1 * HOUR + 2 * MIN + 3),
+	BAD ("3:-4"),
+	/* XX We might want to require exactly two digits after a colon?  */
+	GOOD ("3:4", 3 * HOUR + 4 * MIN),
+	/* misc */
+	GOOD ("42", 42),
+	BAD ("1-2"),
+	/* Test overflow limitations */
+	GOOD ("2147483647s", 2147483647),
+	BAD ("2147483648s"), 
+	GOOD ("24855d", 24855 * DAY),
+	BAD ("24856d"),
+	BAD ("24855d 100000000h"),
+	GOOD ("24855d 3h", 24855 * DAY + 3 * HOUR),
+	BAD ("24855d 4h"),
+	GOOD ("24855d 11647s", 24855 * DAY + 11647),
+	BAD ("24855d 11648s"),
+	GOOD ("24855d 194m 7s", 24855 * DAY + 194 * MIN + 7),
+	BAD ("24855d 194m 8s"),
+	BAD ("24855d 195m"),
+	BAD ("24855d 19500000000m"),
+	GOOD ("24855d 3h 14m 7s", 24855 * DAY + 3 * HOUR + 14 * MIN + 7),
+	BAD ("24855d 3h 14m 8s"),
+	GOOD ("596523h", 596523 * HOUR),
+	BAD ("596524h"),
+	GOOD ("596523h 847s", 596523 * HOUR + 847),
+	BAD ("596523h 848s"),
+	GOOD ("596523h 14m 7s", 596523 * HOUR + 14 * MIN + 7),
+	BAD ("596523h 14m 8s"),
+	GOOD ("35791394m", 35791394 * MIN),
+	GOOD ("35791394m7s", 35791394 * MIN + 7),
+	BAD ("35791394m8s"),
+	/* Test underflow */
+	GOOD ("-2147483647s", -2147483647),
+	/* This should be valid, but isn't */
+	/*BAD ("-2147483648s"),*/
+	GOOD ("-24855d", -24855 * DAY),
+	BAD ("-24856d"),
+	BAD ("-24855d -100000000h"),
+	GOOD ("-24855d -3h", -24855 * DAY - 3 * HOUR),
+	BAD ("-24855d -4h"),
+	GOOD ("-24855d -11647s", -24855 * DAY - 11647),
+	BAD ("-24855d -11649s"),
+	GOOD ("-24855d -194m -7s", -24855 * DAY - 194 * MIN - 7),
+	BAD ("-24855d -194m -9s"),
+	BAD ("-24855d -195m"),
+	BAD ("-24855d -19500000000m"),
+	GOOD ("-24855d -3h -14m -7s", -24855 * DAY - 3 * HOUR - 14 * MIN - 7),
+	BAD ("-24855d -3h -14m -9s"),
+	GOOD ("-596523h", -596523 * HOUR),
+	BAD ("-596524h"),
+	GOOD ("-596523h -847s", -596523 * HOUR - 847),
+	GOOD ("-596523h -848s", -596523 * HOUR - 848),
+	BAD ("-596523h -849s"),
+	GOOD ("-596523h -14m -8s", -596523 * HOUR - 14 * MIN - 8),
+	BAD ("-596523h -14m -9s"),
+	GOOD ("-35791394m", -35791394 * MIN),
+	GOOD ("-35791394m7s", -35791394 * MIN + 7),
+	BAD ("-35791394m-9s"),
+	
+    };
+    int fail = 0;
+    int i;
+
+    for (i = 0; i < sizeof(values)/sizeof(values[0]); i++) {
+	krb5_deltat result;
+	krb5_error_code code;
+
+	code = krb5_string_to_deltat (values[i].string, &result);
+	if (code && !values[i].is_error) {
+	    fprintf (stderr, "unexpected error for `%s'\n", values[i].string);
+	    fail++;
+	} else if (!code && values[i].is_error) {
+	    fprintf (stderr, "expected but didn't get error for `%s'\n",
+		     values[i].string);
+	    fail++;
+	} else if (code && values[i].is_error) {
+	    /* do nothing */
+	} else if (result != values[i].expected) {
+	    fprintf (stderr, "got %ld instead of expected %ld for `%s'\n",
+		     (long) result, (long) values[i].expected,
+		     values[i].string);
+	    fail++;
+	}
+    }
+    if (fail == 0)
+	printf ("Passed all %d tests.\n", i);
+    else
+	printf ("Failed %d of %d tests.\n", fail, i);
+    return fail;
+}
diff --git a/mechglue/src/lib/krb5/krb/t_expand.c b/mechglue/src/lib/krb5/krb/t_expand.c
new file mode 100644
index 000000000..a8b2757df
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/t_expand.c
@@ -0,0 +1,2 @@
+#define TEST
+#include "chk_trans.c"
diff --git a/mechglue/src/lib/krb5/krb/t_kerb.c b/mechglue/src/lib/krb5/krb/t_kerb.c
new file mode 100644
index 000000000..72c0a425b
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/t_kerb.c
@@ -0,0 +1,231 @@
+/*
+ * This driver routine is used to test many of the standard Kerberos library
+ * routines.
+ */
+
+#include "krb5.h"
+#ifdef KRB5_KRB4_COMPAT
+#include "kerberosIV/krb.h"
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "com_err.h"
+
+void test_string_to_timestamp (krb5_context, char *);
+void test_425_conv_principal (krb5_context, char *, char*, char *);
+void test_524_conv_principal (krb5_context, char *);
+void test_parse_name (krb5_context, const char *);
+void test_set_realm (krb5_context, const char *, const char *);
+void usage (char *);
+
+void test_string_to_timestamp(krb5_context ctx, char *ktime)
+{
+    krb5_timestamp	timestamp;
+    time_t		t;
+    krb5_error_code	retval;
+
+    retval = krb5_string_to_timestamp(ktime, ×tamp);
+    if (retval) {
+	com_err("krb5_string_to_timestamp", retval, 0);
+	return;
+    }
+    t = (time_t) timestamp;
+    printf("Parsed time was %s", ctime(&t));
+}
+
+void test_425_conv_principal(krb5_context ctx, char *name, char *inst, char *realm)
+{
+    krb5_error_code	retval;
+    krb5_principal	princ;
+    char		*out_name;
+
+    retval = krb5_425_conv_principal(ctx, name, inst, realm, &princ);
+    if (retval) {
+	com_err("krb5_425_conv_principal", retval, 0);
+	return;
+    }
+    retval = krb5_unparse_name(ctx, princ, &out_name);
+    if (retval) {
+	    com_err("krb5_unparse_name", retval, 0);
+	    return;
+    }
+    printf("425_converted principal(%s, %s, %s): '%s'\n",
+	   name, inst, realm, out_name);
+    free(out_name);
+    krb5_free_principal(ctx, princ);
+}
+
+void test_524_conv_principal(krb5_context ctx, char *name)
+{
+    krb5_principal princ = 0;
+    krb5_error_code retval;
+#ifndef KRB5_KRB4_COMPAT
+#define ANAME_SZ 40
+#define INST_SZ  40
+#define REALM_SZ  40
+#endif
+    char aname[ANAME_SZ+1], inst[INST_SZ+1], realm[REALM_SZ+1];
+
+    aname[ANAME_SZ] = inst[INST_SZ] = realm[REALM_SZ] = 0;
+    retval = krb5_parse_name(ctx, name, &princ);
+    if (retval) {
+	com_err("krb5_parse_name", retval, 0);
+	goto fail;
+    }
+    retval = krb5_524_conv_principal(ctx, princ, aname, inst, realm);
+    if (retval) {
+	com_err("krb5_524_conv_principal", retval, 0);
+	goto fail;
+    }
+    printf("524_converted_principal(%s): '%s' '%s' '%s'\n",
+	   name, aname, inst, realm);
+ fail:
+    if (princ)
+	krb5_free_principal (ctx, princ);
+}
+
+void test_parse_name(krb5_context ctx, const char *name)
+{
+	krb5_error_code	retval;
+	krb5_principal	princ = 0, princ2 = 0;
+	char		*outname = 0;
+
+	retval = krb5_parse_name(ctx, name, &princ);
+	if (retval) {
+		com_err("krb5_parse_name", retval, 0);
+		goto fail;
+	}
+	retval = krb5_copy_principal(ctx, princ, &princ2);
+	if (retval) {
+		com_err("krb5_copy_principal", retval, 0);
+		goto fail;
+	}
+	retval = krb5_unparse_name(ctx, princ2, &outname);
+	if (retval) {
+		com_err("krb5_unparse_name", retval, 0);
+		goto fail;
+	}
+	printf("parsed (and unparsed) principal(%s): ", name);
+	if (strcmp(name, outname) == 0)
+	    printf("MATCH\n");
+	else
+	    printf("'%s'\n", outname);
+fail:
+	if (outname)
+		free(outname);
+	if (princ)
+		krb5_free_principal(ctx, princ);
+	if (princ2)
+		krb5_free_principal(ctx, princ2);
+}
+
+void test_set_realm(krb5_context ctx, const char *name, const char *realm)
+{
+	krb5_error_code	retval;
+	krb5_principal	princ = 0;
+	char		*outname = 0;
+
+	retval = krb5_parse_name(ctx, name, &princ);
+	if (retval) {
+		com_err("krb5_parse_name", retval, 0);
+		goto fail;
+	}
+	retval = krb5_set_principal_realm(ctx, princ, realm);
+	if (retval) {
+		com_err("krb5_set_principal_realm", retval, 0);
+		goto fail;
+	}
+	retval = krb5_unparse_name(ctx, princ, &outname);
+	if (retval) {
+		com_err("krb5_unparse_name", retval, 0);
+		goto fail;
+	}
+	printf("old principal: %s, modified principal: %s\n", name,
+	       outname);
+fail:
+	if (outname)
+		free(outname);
+	if (princ)
+		krb5_free_principal(ctx, princ);
+}
+
+void usage(char *progname)
+{
+	fprintf(stderr, "%s: Usage: %s 425_conv_principal <name> <inst> <realm\n",
+		progname, progname);
+	fprintf(stderr, "\t%s 524_conv_principal <name>\n", progname);
+	fprintf(stderr, "\t%s parse_name <name>\n", progname);
+	fprintf(stderr, "\t%s set_realm <name> <realm>\n", progname);
+	fprintf(stderr, "\t%s string_to_timestamp <time>\n", progname);
+	exit(1);
+}
+
+int 
+main(int argc, char **argv)
+{
+    krb5_context ctx;
+    krb5_error_code retval;
+    char *progname;
+    char *name, *inst, *realm;
+
+    retval = krb5_init_context(&ctx);
+    if (retval) {
+	fprintf(stderr, "krb5_init_context returned error %ld\n",
+		(long) retval);
+	exit(1);
+    }
+    progname = argv[0];
+
+     /* Parse arguments. */
+     argc--; argv++;
+     while (argc) {
+	 if (strcmp(*argv, "425_conv_principal") == 0) {
+	     argc--; argv++;
+	     if (!argc) usage(progname);
+	     name = *argv;
+	     argc--; argv++;
+	     if (!argc) usage(progname);
+	     inst = *argv;
+	     argc--; argv++;
+	     if (!argc) usage(progname);
+	     realm = *argv;
+	     test_425_conv_principal(ctx, name, inst, realm);
+	  } else if (strcmp(*argv, "parse_name") == 0) {
+		  argc--; argv++;
+		  if (!argc) usage(progname);
+		  name = *argv;
+		  test_parse_name(ctx, name);
+	  } else if (strcmp(*argv, "set_realm") == 0) {
+		  argc--; argv++;
+		  if (!argc) usage(progname);
+		  name = *argv;
+		  argc--; argv++;
+		  if (!argc) usage(progname);
+		  realm = *argv;
+		  test_set_realm(ctx, name, realm);
+	  } else if (strcmp(*argv, "string_to_timestamp") == 0) {
+		  argc--; argv++;
+		  if (!argc) usage(progname);
+		  test_string_to_timestamp(ctx, *argv);
+	  } else if (strcmp(*argv, "524_conv_principal") == 0) {
+	      argc--; argv++;
+	      if (!argc) usage(progname);
+	      test_524_conv_principal(ctx, *argv);
+	  }
+	  else
+	      usage(progname);
+	  argc--; argv++;
+     }
+
+    krb5_free_context(ctx);
+
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/t_krb5.conf b/mechglue/src/lib/krb5/krb/t_krb5.conf
new file mode 100644
index 000000000..b25b1d38a
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/t_krb5.conf
@@ -0,0 +1,52 @@
+[libdefaults]
+	ticket_lifetime = 600
+	default_realm = ATHENA.MIT.EDU
+
+[realms]
+	ATHENA.MIT.EDU = {
+		kdc = KERBEROS-2.MIT.EDU:88
+		kdc = KERBEROS.MIT.EDU
+		kdc = KERBEROS-1.MIT.EDU
+		admin_server = KERBEROS.MIT.EDU
+		default_domain = MIT.EDU
+		v4_instance_convert = {
+			mit = mit.edu
+			lithium = lithium.lcs.mit.edu
+		}
+	}
+	CYGNUS.COM = {
+		kdc = KERBEROS-1.CYGNUS.COM
+		kdc = KERBEROS.CYGNUS.COM
+		admin_server = KERBEROS.MIT.EDU
+	}
+	stanford.edu = {
+		v4_realm = IR.STANFORD.EDU
+	}
+	LONGNAMES.COM = {
+		v4_realm = SOME-REALLY-LONG-REALM-NAME-V4-CANNOT-HANDLE.COM
+	}
+
+[capaths]
+	/COM/HP/APOLLO/FOO = {
+		/COM/DEC/CRL = /COM/DEC
+		/COM/DEC/CRL = /COM
+		/COM/DEC/CRL = /COM/HP
+		/COM/DEC/CRL = /COM/HP/APOLLO
+	}
+	ATHENA.MIT.EDU = {
+		KERBEROS.COM = .
+	}
+	LCS.MIT.EDU = {
+		KERBEROS.COM = ATHENA.MIT.EDU
+		ATHENA.MIT.EDU = .
+		KABLOOEY.KERBEROS.COM = ATHENA.MIT.EDU
+		KABLOOEY.KERBEROS.COM = KERBEROS.COM
+	}
+
+[domain_realm]
+	.mit.edu = ATHENA.MIT.EDU
+	mit.edu = ATHENA.MIT.EDU
+	.media.mit.edu = MEDIA-LAB.MIT.EDU
+	media.mit.edu = MEDIA-LAB.MIT.EDU
+	.ucsc.edu = CATS.UCSC.EDU
+
diff --git a/mechglue/src/lib/krb5/krb/t_ref_kerb.out b/mechglue/src/lib/krb5/krb/t_ref_kerb.out
new file mode 100644
index 000000000..08a53343f
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/t_ref_kerb.out
@@ -0,0 +1,19 @@
+parsed (and unparsed) principal(tytso): 'tytso@ATHENA.MIT.EDU'
+parsed (and unparsed) principal(tytso@SHAZAAM): MATCH
+parsed (and unparsed) principal(tytso/root@VEGGIE.COM): MATCH
+parsed (and unparsed) principal(tytso/tuber/carrot@VEGGIE.COM): MATCH
+parsed (and unparsed) principal(tytso/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t): 'tytso/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t@ATHENA.MIT.EDU'
+parsed (and unparsed) principal(tytso/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t@FOO): MATCH
+parsed (and unparsed) principal(tytso\\0/\0@B\n\t\\GAG): MATCH
+parsed (and unparsed) principal(tytso/\n/\b\t@B\0hacky-test): MATCH
+parsed (and unparsed) principal(\/slash/\@atsign/octa\/thorpe@\/slash\@at\/sign): MATCH
+425_converted principal(rcmd, e40-po, ATHENA.MIT.EDU): 'host/e40-po.mit.edu@ATHENA.MIT.EDU'
+425_converted principal(rcmd, mit, ATHENA.MIT.EDU): 'host/mit.edu@ATHENA.MIT.EDU'
+425_converted principal(rcmd, lithium, ATHENA.MIT.EDU): 'host/lithium.lcs.mit.edu@ATHENA.MIT.EDU'
+425_converted principal(rcmd, tweedledumb, CYGNUS.COM): 'host/tweedledumb.cygnus.com@CYGNUS.COM'
+425_converted principal(rcmd, uunet, UU.NET): 'host/uunet.uu.net@UU.NET'
+425_converted principal(zephyr, zephyr, ATHENA.MIT.EDU): 'zephyr/zephyr@ATHENA.MIT.EDU'
+425_converted principal(kadmin, ATHENA.MIT.EDU, ATHENA.MIT.EDU): 'kadmin/ATHENA.MIT.EDU@ATHENA.MIT.EDU'
+524_converted_principal(host/e40-po.mit.edu@ATHENA.MIT.EDU): 'rcmd' 'e40-po' 'ATHENA.MIT.EDU'
+524_converted_principal(host/foobar.stanford.edu@stanford.edu): 'rcmd' 'foobar' 'IR.STANFORD.EDU'
+old principal: marc@MIT.EDU, modified principal: marc@CYGNUS.COM
diff --git a/mechglue/src/lib/krb5/krb/t_ser.c b/mechglue/src/lib/krb5/krb/t_ser.c
new file mode 100644
index 000000000..8ddcff7c0
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/t_ser.c
@@ -0,0 +1,729 @@
+/*
+ * lib/krb5/krb/t_ser.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * t_ser.c - Test serialization.
+ */
+#include "k5-int.h"
+#include "com_err.h"
+#include "auth_con.h"
+
+#include <ctype.h>
+
+static const char stuff[]="You can't take a pointer to a function and convert \
+it to a pointer to char; ANSI doesn't say it'll work, and in fact on the HPPA \
+you can lose some bits of the function pointer, and get a pointer that you \
+can't safely dereference.  This test file used to make this mistake, often.";
+
+/*
+ * Dump an external representation.
+ */
+static void
+print_erep(krb5_octet *erep, size_t elen)
+{
+    int i, j;
+
+    for (i=0; i<elen; ) {
+	printf("%08d: ", i);
+	for (j=0; j<15; j++) {
+	    if ((i+j) < elen)
+		printf("%02x ", erep[i+j]);
+	    else
+		printf("-- ");
+	}
+	printf("\t");
+	for (j=0; j<15; j++) {
+	    if ((i+j) < elen) {
+		if (isprint(erep[i+j]) && (erep[i+j] != '\n'))
+		    printf("%c", erep[i+j]);
+		else
+		    printf(".");
+	    }
+	    else
+		printf("-");
+	}
+	printf("\n");
+	i += 15;
+    }
+}
+
+/*
+ * Do a serialization test.
+ */
+static krb5_error_code
+ser_data(int verbose, char *msg, krb5_pointer ctx, krb5_magic dtype)
+{
+    krb5_error_code	kret;
+    krb5_context	ser_ctx;
+    krb5_pointer	nctx;
+    krb5_octet		*outrep, *ibuf, *outrep2;
+    size_t		outlen, ilen, outlen2;
+
+    /* Initialize context and initialize all Kerberos serializers */
+    if ((kret = krb5_init_context(&ser_ctx))) {
+	    printf("Couldn't initialize krb5 library: %s\n",
+		   error_message(kret));
+	    exit(1);
+    }
+    krb5_ser_context_init(ser_ctx);
+    krb5_ser_auth_context_init(ser_ctx);
+    krb5_ser_ccache_init(ser_ctx);
+    krb5_ser_rcache_init(ser_ctx);
+    krb5_ser_keytab_init(ser_ctx);
+
+    /* Externalize the data */
+    kret = krb5_externalize_data(ser_ctx, ctx, &outrep, &outlen);
+    if (!kret) {
+	if (verbose) {
+	    printf("%s: externalized in %d bytes\n", msg, outlen);
+	    print_erep(outrep, outlen);
+	}
+
+	/* Now attempt to re-constitute it */
+	ibuf = outrep;
+	ilen = outlen;
+	kret = krb5_internalize_opaque(ser_ctx,
+				       dtype,
+				       (krb5_pointer *) &nctx,
+				       &ibuf,
+				       &ilen);
+	if (!kret) {
+	    if (ilen)
+		printf("%s: %d bytes left over after internalize\n",
+		       msg, ilen);
+	    /* Now attempt to re-externalize it */
+	    kret = krb5_externalize_data(ser_ctx, nctx, &outrep2, &outlen2);
+	    if (!kret) {
+		/* Compare the results. */
+		if ((outlen2 != outlen) ||
+		    memcmp(outrep, outrep2, outlen)) {
+		    printf("%s: comparison failed\n", msg);
+		    print_erep(outrep2, outlen2);
+		}
+		else {
+		    if (verbose)
+			printf("%s: compare succeeded\n", msg);
+		}
+		krb5_xfree(outrep2);
+	    }
+	    else
+		printf("%s: second externalize returned %d\n", msg, kret);
+
+	    /* Free the data */
+	    switch (dtype) {
+	    case KV5M_CONTEXT:
+		krb5_db_fini((krb5_context) nctx);
+		krb5_free_context((krb5_context) nctx);
+		break;
+	    case KV5M_AUTH_CONTEXT:
+		if (nctx) {
+		    krb5_auth_context	actx;
+
+		    actx = (krb5_auth_context) nctx;
+		    if (actx->i_vector)
+			krb5_xfree(actx->i_vector);
+		}
+		krb5_auth_con_free(ser_ctx, (krb5_auth_context) nctx);
+		break;
+	    case KV5M_CCACHE:
+		krb5_cc_close(ser_ctx, (krb5_ccache) nctx);
+		break;
+	    case KV5M_RCACHE:
+		krb5_rc_close(ser_ctx, (krb5_rcache) nctx);
+		break;
+	    case KV5M_KEYTAB:
+		krb5_kt_close(ser_ctx, (krb5_keytab) nctx);
+		break;
+	    case KV5M_ENCRYPT_BLOCK:
+		if (nctx) {
+		    krb5_encrypt_block *eblock;
+
+		    eblock = (krb5_encrypt_block *) nctx;
+#if 0
+		    if (eblock->priv && eblock->priv_size)
+			krb5_xfree(eblock->priv);
+#endif
+		    if (eblock->key)
+			krb5_free_keyblock(ser_ctx, eblock->key);
+		    krb5_xfree(eblock);
+		}
+		break;
+	    case KV5M_PRINCIPAL:
+		krb5_free_principal(ser_ctx, (krb5_principal) nctx);
+		break;
+	    case KV5M_CHECKSUM:
+		krb5_free_checksum(ser_ctx, (krb5_checksum *) nctx);
+		break;
+	    default:
+		printf("don't know how to free %d\n", dtype);
+		break;
+	    }
+	}
+	else
+	    printf("%s: internalize returned %d\n", msg, kret);
+	krb5_xfree(outrep);
+    }
+    else
+	printf("%s: externalize_data returned %d\n", msg, kret);
+    krb5_free_context(ser_ctx);
+    return(kret);
+}
+
+/*
+ * Serialize krb5_context.
+ */
+static krb5_error_code
+ser_kcontext_test(krb5_context kcontext, int verbose)
+{
+    krb5_error_code	kret;
+    profile_t		sprofile;
+    char		dbname[128];
+
+    sprintf(dbname, "temp_%d", (int) getpid());
+    sprofile = kcontext->profile;
+    kcontext->profile = (profile_t) NULL;
+    if (!(kret = ser_data(verbose, "> Context with no profile",
+			  (krb5_pointer) kcontext,
+			  KV5M_CONTEXT))) {
+	kcontext->profile = sprofile;
+	if (!(kret = ser_data(verbose, "> Context with no realm", 
+			      (krb5_pointer) kcontext,
+			      KV5M_CONTEXT)) &&
+	    !(kret = krb5_set_default_realm(kcontext, "this.is.a.test"))) {
+	    if (!(kret = ser_data(verbose, "> Context with default realm",
+				  (krb5_pointer) kcontext,
+				  KV5M_CONTEXT))) {
+		if (verbose)
+		    printf("* krb5_context test succeeded\n");
+	    }
+	}
+    }
+    if (kret)
+	printf("* krb5_context test failed\n");
+    return(kret);
+}
+
+/* 
+ * Serialize krb5_auth_context.
+ */
+static krb5_error_code
+ser_acontext_test(krb5_context kcontext, int verbose)
+{
+    krb5_error_code	kret;
+    krb5_auth_context	actx;
+    krb5_address	local_address;
+    krb5_address	remote_address;
+    krb5_octet		laddr_bytes[16];
+    krb5_octet		raddr_bytes[16];
+    krb5_keyblock	ukeyblock;
+    krb5_octet		keydata[8];
+    krb5_authenticator	aent;
+    char		clname[128];
+    krb5_authdata	*adatalist[3];
+    krb5_authdata	adataent;
+
+    actx = (krb5_auth_context) NULL;
+    if (!(kret = krb5_auth_con_init(kcontext, &actx)) &&
+	!(kret = ser_data(verbose, "> Vanilla auth context",
+			  (krb5_pointer) actx,
+			  KV5M_AUTH_CONTEXT))) {
+	memset(&local_address, 0, sizeof(local_address));
+	memset(&remote_address, 0, sizeof(remote_address));
+	memset(laddr_bytes, 0, sizeof(laddr_bytes));
+	memset(raddr_bytes, 0, sizeof(raddr_bytes));
+	local_address.addrtype = ADDRTYPE_INET;
+	local_address.length = sizeof(laddr_bytes);
+	local_address.contents = laddr_bytes;
+	laddr_bytes[0] = 6;
+	laddr_bytes[1] = 2;
+	laddr_bytes[2] = 69;
+	laddr_bytes[3] = 16;
+	laddr_bytes[4] = 1;
+	laddr_bytes[5] = 0;
+	laddr_bytes[6] = 0;
+	laddr_bytes[7] = 127;
+	remote_address.addrtype = ADDRTYPE_INET;
+	remote_address.length = sizeof(raddr_bytes);
+	remote_address.contents = raddr_bytes;
+	raddr_bytes[0] = 6;
+	raddr_bytes[1] = 2;
+	raddr_bytes[2] = 70;
+	raddr_bytes[3] = 16;
+	raddr_bytes[4] = 1;
+	raddr_bytes[5] = 0;
+	raddr_bytes[6] = 0;
+	raddr_bytes[7] = 127;
+	if (!(kret = krb5_auth_con_setaddrs(kcontext, actx,
+					    &local_address,
+					    &remote_address)) &&
+	    !(kret = krb5_auth_con_setports(kcontext, actx,
+					    &local_address,
+					    &remote_address)) &&
+	    !(kret = ser_data(verbose, "> Auth context with addrs/ports", 
+			      (krb5_pointer) actx,
+			      KV5M_AUTH_CONTEXT))) {
+	    memset(&ukeyblock, 0, sizeof(ukeyblock));
+	    memset(keydata, 0, sizeof(keydata));
+	    ukeyblock.enctype = ENCTYPE_DES_CBC_MD5;
+	    ukeyblock.length = sizeof(keydata);
+	    ukeyblock.contents = keydata;
+	    keydata[0] = 0xde;
+	    keydata[1] = 0xad;
+	    keydata[2] = 0xbe;
+	    keydata[3] = 0xef;
+	    keydata[4] = 0xfe;
+	    keydata[5] = 0xed;
+	    keydata[6] = 0xf0;
+	    keydata[7] = 0xd;
+	    if (!(kret = krb5_auth_con_setuseruserkey(kcontext, actx,
+						      &ukeyblock)) &&
+		!(kret = ser_data(verbose, "> Auth context with user key",
+				  (krb5_pointer) actx,
+				  KV5M_AUTH_CONTEXT)) &&
+		!(kret = krb5_auth_con_initivector(kcontext, actx)) &&
+		!(kret = ser_data(verbose, "> Auth context with new vector",
+				  (krb5_pointer) actx,
+				  KV5M_AUTH_CONTEXT)) &&
+		(krb5_xfree(actx->i_vector), actx->i_vector) &&
+		!(kret = krb5_auth_con_setivector(kcontext, actx,
+						  (krb5_pointer) print_erep)
+		  ) &&
+		!(kret = ser_data(verbose, "> Auth context with set vector",
+				  (krb5_pointer) actx,
+				  KV5M_AUTH_CONTEXT))) {
+		/*
+		 * Finally, add an authenticator.
+		 */
+		memset(&aent, 0, sizeof(aent));
+		aent.magic = KV5M_AUTHENTICATOR;
+		sprintf(clname, "help/me/%d@this.is.a.test", (int) getpid());
+		actx->authentp = &aent;
+		if (!(kret = krb5_parse_name(kcontext, clname,
+					     &aent.client)) &&
+		    !(kret = ser_data(verbose,
+				      "> Auth context with authenticator",
+				      (krb5_pointer) actx,
+				      KV5M_AUTH_CONTEXT))) {
+		    adataent.magic = KV5M_AUTHDATA;
+		    adataent.ad_type = 123;
+		    adataent.length = 128;
+		    adataent.contents = (krb5_octet *) stuff;
+		    adatalist[0] = &adataent;
+		    adatalist[1] = &adataent;
+		    adatalist[2] = (krb5_authdata *) NULL;
+		    aent.authorization_data = adatalist;
+		    if (!(kret = ser_data(verbose,
+					  "> Auth context with full auth",
+					  (krb5_pointer) actx,
+					  KV5M_AUTH_CONTEXT))) {
+			if (verbose)
+			    printf("* krb5_auth_context test succeeded\n");
+		    }
+		    krb5_free_principal(kcontext, aent.client);
+		}
+		actx->authentp = (krb5_authenticator *) NULL;
+	    }
+	}
+    }
+    if (actx)
+	krb5_auth_con_free(kcontext, actx);
+    if (kret)
+	printf("* krb5_auth_context test failed\n");
+    return(kret);
+}
+
+/*
+ * Serialize krb5_ccache
+ */
+static krb5_error_code
+ser_ccache_test(krb5_context kcontext, int verbose)
+{
+    krb5_error_code	kret;
+    char		ccname[128];
+    char		princname[256];
+    krb5_ccache		ccache;
+    krb5_principal	principal;
+
+    sprintf(ccname, "temp_cc_%d", (int) getpid());
+    sprintf(princname, "zowie%d/instance%d@this.is.a.test",
+	    (int) getpid(), (int) getpid());
+    if (!(kret = krb5_cc_resolve(kcontext, ccname, &ccache)) &&
+	!(kret = ser_data(verbose, "> Resolved default ccache",
+			  (krb5_pointer) ccache, KV5M_CCACHE)) &&
+	!(kret = krb5_parse_name(kcontext, princname, &principal)) &&
+	!(kret = krb5_cc_initialize(kcontext, ccache, principal)) &&
+	!(kret = ser_data(verbose, "> Initialized default ccache",
+			  (krb5_pointer) ccache, KV5M_CCACHE)) &&
+	!(kret = krb5_cc_destroy(kcontext, ccache))) {
+	krb5_free_principal(kcontext, principal);
+	sprintf(ccname, "FILE:temp_cc_%d", (int) getpid());
+	sprintf(princname, "xxx%d/i%d@this.is.a.test",
+		(int) getpid(), (int) getpid());
+	if (!(kret = krb5_cc_resolve(kcontext, ccname, &ccache)) &&
+	    !(kret = ser_data(verbose, "> Resolved FILE ccache",
+			      (krb5_pointer) ccache, KV5M_CCACHE)) &&
+	    !(kret = krb5_parse_name(kcontext, princname, &principal)) &&
+	    !(kret = krb5_cc_initialize(kcontext, ccache, principal)) &&
+	    !(kret = ser_data(verbose, "> Initialized FILE ccache",
+			      (krb5_pointer) ccache, KV5M_CCACHE)) &&
+	    !(kret = krb5_cc_destroy(kcontext, ccache))) {
+	    krb5_free_principal(kcontext, principal);
+
+	    if (verbose)
+		printf("* ccache test succeeded\n");
+	}
+    }
+    if (kret)
+	printf("* krb5_ccache test failed\n");
+    return(kret);
+}
+
+/*
+ * Serialize krb5_keytab.
+ */
+static krb5_error_code
+ser_keytab_test(krb5_context kcontext, int verbose)
+{
+    krb5_error_code	kret;
+    char		ccname[128];
+    krb5_keytab		keytab;
+    extern krb5_kt_ops	krb5_ktf_writable_ops;
+
+    sprintf(ccname, "temp_kt_%d", (int) getpid());
+    if (!(kret = krb5_kt_resolve(kcontext, ccname, &keytab)) &&
+	!(kret = ser_data(verbose, "> Resolved default keytab",
+			  (krb5_pointer) keytab, KV5M_KEYTAB)) &&
+	!(kret = krb5_kt_close(kcontext, keytab))) {
+	sprintf(ccname, "FILE:temp_kt_%d", (int) getpid());
+	if (!(kret = krb5_kt_resolve(kcontext, ccname, &keytab)) &&
+	    !(kret = ser_data(verbose, "> Resolved FILE keytab",
+			      (krb5_pointer) keytab, KV5M_KEYTAB)) &&
+	    !(kret = krb5_kt_close(kcontext, keytab))) {
+	    sprintf(ccname, "WRFILE:temp_kt_%d", (int) getpid());
+	    if ((kret = krb5_kt_resolve(kcontext, ccname, &keytab)))
+		kret = krb5_kt_register(kcontext, &krb5_ktf_writable_ops);
+	    else
+		kret = krb5_kt_close(kcontext, keytab);
+	    if (!kret &&
+		!(kret = krb5_kt_resolve(kcontext, ccname, &keytab)) &&
+		!(kret = ser_data(verbose, "> Resolved WRFILE keytab",
+				  (krb5_pointer) keytab, KV5M_KEYTAB)) &&
+		!(kret = krb5_kt_close(kcontext, keytab))) {
+		if (verbose)
+		    printf("* keytab test succeeded\n");
+	    }
+	}
+    }
+    if (kret)
+	printf("* krb5_keytab test failed\n");
+    return(kret);
+}
+
+/*
+ * Serialize krb5_rcache.
+ */
+static krb5_error_code
+ser_rcache_test(krb5_context kcontext, int verbose)
+{
+    krb5_error_code	kret;
+    char		rcname[128];
+    krb5_rcache		rcache;
+
+    sprintf(rcname, "dfl:temp_rc_%d", (int) getpid());
+    if (!(kret = krb5_rc_resolve_full(kcontext, &rcache, rcname)) &&
+	!(kret = ser_data(verbose, "> Resolved FILE rcache",
+			  (krb5_pointer) rcache, KV5M_RCACHE)) &&
+	!(kret = krb5_rc_initialize(kcontext, rcache, 3600*24)) &&
+	!(kret = ser_data(verbose, "> Initialized FILE rcache",
+			  (krb5_pointer) rcache, KV5M_RCACHE)) &&
+	!(kret = krb5_rc_destroy(kcontext, rcache))) {
+	if (verbose)
+	    printf("* rcache test succeeded\n");
+    }
+    if (kret)
+	printf("* krb5_rcache test failed\n");
+    return(kret);
+}
+
+#if 0
+/*
+ * Serialize krb5_encrypt_block.
+ */
+static krb5_error_code
+ser_eblock_test(kcontext, verbose)
+    krb5_context	kcontext;
+    int			verbose;
+{
+    krb5_error_code	kret;
+    krb5_encrypt_block	eblock;    
+    krb5_keyblock	ukeyblock;
+    krb5_octet		keydata[8];
+
+    memset(&eblock, 0, sizeof(krb5_encrypt_block));
+    eblock.magic = KV5M_ENCRYPT_BLOCK;
+    krb5_use_enctype(kcontext, &eblock, DEFAULT_KDC_ENCTYPE);
+    if (!(kret = ser_data(verbose, "> NULL eblock",
+			  (krb5_pointer) &eblock, KV5M_ENCRYPT_BLOCK))) {
+#if 0
+	eblock.priv = (krb5_pointer) stuff;
+	eblock.priv_size = 8;
+#endif
+	if (!(kret = ser_data(verbose, "> eblock with private data",
+			      (krb5_pointer) &eblock,
+			      KV5M_ENCRYPT_BLOCK))) {
+	    memset(&ukeyblock, 0, sizeof(ukeyblock));
+	    memset(keydata, 0, sizeof(keydata));
+	    ukeyblock.enctype = ENCTYPE_DES_CBC_MD5;
+	    ukeyblock.length = sizeof(keydata);
+	    ukeyblock.contents = keydata;
+	    keydata[0] = 0xde;
+	    keydata[1] = 0xad;
+	    keydata[2] = 0xbe;
+	    keydata[3] = 0xef;
+	    keydata[4] = 0xfe;
+	    keydata[5] = 0xed;
+	    keydata[6] = 0xf0;
+	    keydata[7] = 0xd;
+	    eblock.key = &ukeyblock;
+	    if (!(kret = ser_data(verbose, "> eblock with private key",
+				  (krb5_pointer) &eblock,
+				  KV5M_ENCRYPT_BLOCK))) {
+		if (verbose)
+		    printf("* eblock test succeeded\n");
+	    }
+	}
+    }
+    if (kret)
+	printf("* eblock test failed\n");
+    return(kret);
+}
+#endif
+
+/*
+ * Serialize krb5_principal
+ */
+static krb5_error_code
+ser_princ_test(krb5_context kcontext, int verbose)
+{
+    krb5_error_code	kret;
+    krb5_principal	princ;
+    char		pname[1024];
+
+    sprintf(pname, "the/quick/brown/fox/jumped/over/the/lazy/dog/%d@this.is.a.test", (int) getpid());
+    if (!(kret = krb5_parse_name(kcontext, pname, &princ))) {
+	if (!(kret = ser_data(verbose, "> Principal",
+			      (krb5_pointer) princ, KV5M_PRINCIPAL))) {
+	    if (verbose)
+		printf("* principal test succeeded\n");
+	}
+	krb5_free_principal(kcontext, princ);
+    }
+    if (kret)
+	printf("* principal test failed\n");
+    return(kret);
+}
+
+/*
+ * Serialize krb5_checksum.
+ */
+static krb5_error_code
+ser_cksum_test(krb5_context kcontext, int verbose)
+{
+    krb5_error_code	kret;
+    krb5_checksum	checksum;
+    krb5_octet		ckdata[24];
+
+    memset(&checksum, 0, sizeof(krb5_checksum));
+    checksum.magic = KV5M_CHECKSUM;
+    if (!(kret = ser_data(verbose, "> NULL checksum",
+			  (krb5_pointer) &checksum, KV5M_CHECKSUM))) {
+	checksum.checksum_type = 123;
+	checksum.length = sizeof(ckdata);
+	checksum.contents = ckdata;
+	memcpy(ckdata, (char *) &stuff, sizeof(ckdata)); 
+	if (!(kret = ser_data(verbose, "> checksum with data",
+			      (krb5_pointer) &checksum, KV5M_CHECKSUM))) {
+	    if (verbose)
+		printf("* checksum test succeeded\n");
+	}
+    }
+    if (kret)
+	printf("* checksum test failed\n");
+    return(kret);
+}
+
+/*
+ * Main procedure.
+ */
+int
+main(int argc, char **argv)
+{
+    krb5_error_code	kret;
+    krb5_context	kcontext;
+    int			do_atest, do_ctest, do_ktest, do_rtest, do_xtest;
+    int			do_etest, do_ptest, do_stest;
+    int			verbose;
+    int			option;
+    extern char		*optarg;
+    char		ch_err;
+
+    kret = 0;
+    verbose = 0;
+    do_atest = 1;
+    do_xtest = 1;
+    do_ctest = 1;
+    do_etest = 1;
+    do_ktest = 1;
+    do_ptest = 1;
+    do_rtest = 1;
+    do_stest = 1;
+    while ((option = getopt(argc, argv, "acekprsxvACEKPRSX")) != -1) {
+	switch (option) {
+	case 'a':
+	    do_atest = 0;
+	    break;
+	case 'c':
+	    do_ctest = 0;
+	    break;
+	case 'e':
+	    do_etest = 0;
+	    break;
+	case 'k':
+	    do_ktest = 0;
+	    break;
+	case 'p':
+	    do_ptest = 0;
+	    break;
+	case 'r':
+	    do_rtest = 0;
+	    break;
+	case 's':
+	    do_stest = 0;
+	    break;
+	case 'x':
+	    do_xtest = 0;
+	    break;
+	case 'v':
+	    verbose = 1;
+	    break;
+	case 'A':
+	    do_atest = 1;
+	    break;
+	case 'C':
+	    do_ctest = 1;
+	    break;
+#if 0
+	case 'E':
+	    do_etest = 1;
+	    break;
+#endif
+	case 'K':
+	    do_ktest = 1;
+	    break;
+	case 'P':
+	    do_ptest = 1;
+	    break;
+	case 'R':
+	    do_rtest = 1;
+	    break;
+	case 'S':
+	    do_stest = 1;
+	    break;
+	case 'X':
+	    do_xtest = 1;
+	    break;
+	default:
+	    fprintf(stderr,
+		    "%s: usage is %s [-acekprsxvACEKPRSX]\n",
+		    argv[0], argv[0]);
+	    exit(1);
+	    break;
+	}
+    }
+    if ((kret = krb5_init_context(&kcontext))) {
+	    com_err(argv[0], kret, "while initializing krb5");
+	    exit(1);
+    }
+    
+    if (do_xtest) {
+	    ch_err = 'x';
+	    kret = ser_kcontext_test(kcontext, verbose);
+	    if (kret)
+		    goto fail;
+    }
+    if (do_atest) {
+	    ch_err = 'a';
+	    kret = ser_acontext_test(kcontext, verbose);
+	    if (kret)
+		    goto fail;
+    }
+    if (do_ctest) {
+	    ch_err = 'c';
+	    kret = ser_ccache_test(kcontext, verbose);
+	    if (kret)
+		    goto fail;
+    }
+    if (do_ktest) {
+	    ch_err = 'k';
+	    kret = ser_keytab_test(kcontext, verbose);
+	    if (kret)
+		    goto fail;
+    }
+    if (do_rtest) {
+	    ch_err = 'r';
+	    kret = ser_rcache_test(kcontext, verbose);
+	    if (kret)
+		    goto fail;
+    }
+#if 0 /* code to be tested is currently disabled */
+    if (do_etest) {
+	    ch_err = 'e';
+	    kret = ser_eblock_test(kcontext, verbose);
+	    if (kret)
+		    goto fail;
+    }
+#endif
+    if (do_ptest) {
+	    ch_err = 'p';
+	    kret = ser_princ_test(kcontext, verbose);
+	    if (kret)
+		    goto fail;
+    }
+    if (do_stest) {
+	    ch_err = 's';
+	    kret = ser_cksum_test(kcontext, verbose);
+	    if (kret)
+		    goto fail;
+    }
+    krb5_free_context(kcontext);
+    
+    exit(0);
+fail:
+    com_err(argv[0], kret, "--- test %cfailed", ch_err);
+    krb5_free_context(kcontext);
+    exit(1);
+}
diff --git a/mechglue/src/lib/krb5/krb/t_walk_rtree.c b/mechglue/src/lib/krb5/krb/t_walk_rtree.c
new file mode 100644
index 000000000..466118667
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/t_walk_rtree.c
@@ -0,0 +1,58 @@
+/*
+ * t_walk_rtree.c --- test krb5_walk_realm_tree
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include "com_err.h"
+
+int
+main(int argc, char **argv)
+{
+	krb5_data client, server;
+	char	realm_branch_char = '.';
+	krb5_principal *tree, *p;
+	char *name;
+	krb5_error_code	retval;
+	krb5_context context;
+	
+	krb5_init_context(&context);
+	
+	if (argc < 3 || argc > 4) {
+		fprintf(stderr,
+			"Usage: %s client-realm server-realm [sep_char]\n",
+			argv[0]);
+		exit(99);
+	}
+	client.data = argv[1];
+	client.length = strlen(client.data);
+
+	server.data = argv[2];
+	server.length = strlen(server.data);
+
+	if (argc == 4)
+		realm_branch_char = argv[3][0];
+
+	retval = krb5_walk_realm_tree(context, &client, &server, &tree,
+				      realm_branch_char);
+	if (retval) {
+		com_err("krb5_walk_realm_tree", retval, " ");
+		exit(1);
+	}
+
+	for (p = tree; *p; p++) {
+		retval = krb5_unparse_name(context, *p, &name);
+		if (retval) {
+			com_err("krb5_unprase_name", retval, " ");
+			exit(2);
+		}
+		printf("%s\n", name);
+		free(name);
+	}
+
+	krb5_free_realm_tree(context, tree);
+	krb5_free_context(context);
+
+	exit(0);
+}
+
diff --git a/mechglue/src/lib/krb5/krb/tgtname.c b/mechglue/src/lib/krb5/krb/tgtname.c
new file mode 100644
index 000000000..4ca241623
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/tgtname.c
@@ -0,0 +1,42 @@
+/*
+ * lib/krb5/krb/tgtname.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_tgtname()
+ */
+
+#include "k5-int.h"
+#include "int-proto.h"
+
+/* This is an internal-only function, used by krb5_get_cred_from_kdc() */
+
+krb5_error_code
+krb5_tgtname(krb5_context context, const krb5_data *server, const krb5_data *client, krb5_principal *tgtprinc)
+{
+    return krb5_build_principal_ext(context, tgtprinc, client->length, client->data,
+				    KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, 
+				    server->length, server->data,
+				    0);
+}
diff --git a/mechglue/src/lib/krb5/krb/transit-tests b/mechglue/src/lib/krb5/krb/transit-tests
new file mode 100755
index 000000000..8ffb9c351
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/transit-tests
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# Test the chk_trans.c code.
+# BUG: Currently only tests expansion, not validation.
+
+trap "echo Failed. ; exit 1" 0
+
+check='echo Running test "($1) ($2) ($3)" ... ; ./t_expand -x >tmpout1 "$@" || exit 1 ; grep -v : <tmpout1 >tmpout2 && sort <tmpout2 >tmpout1 && echo Got: `cat tmpout1` && (for i in $expected ; do echo $i ; done) | sort > tmpout2 && echo Exp: `cat tmpout2` && echo "" && cmp >/dev/null 2>&1 tmpout1 tmpout2 || exit 1'
+checkerror='echo Running test "($1) ($2) ($3)", expecting error ... ; if ./t_expand -x >tmpout1 "$@" ; then echo Error was expected, but not reported. ; exit 1; else echo Expected error found. ; echo ""; fi'
+
+#
+# Note: Expected realm expansion order is not important; program output
+# and expected values will each be sorted before comparison.
+#
+
+set ATHENA.MIT.EDU HACK.FOOBAR.COM ,EDU,BLORT.COM,COM,
+expected="MIT.EDU EDU BLORT.COM COM FOOBAR.COM"
+eval $check
+
+set ATHENA.MIT.EDU EDU ,
+expected="MIT.EDU"
+eval $check
+
+set EDU ATHENA.MIT.EDU ,
+expected="MIT.EDU"
+eval $check
+
+set x x "/COM,/HP,/APOLLO, /COM/DEC"
+expected="/COM /COM/HP /COM/HP/APOLLO /COM/DEC"
+eval $check
+
+set x x EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.
+expected="EDU MIT.EDU ATHENA.MIT.EDU WASHINGTON.EDU CS.WASHINGTON.EDU"
+eval $check
+
+set ATHENA.MIT.EDU /COM/HP/APOLLO ,EDU,/COM,
+eval $checkerror
+
+set ATHENA.MIT.EDU /COM/HP/APOLLO ",EDU, /COM,"
+expected="EDU MIT.EDU /COM /COM/HP"
+eval $check
+
+set ATHENA.MIT.EDU CS.CMU.EDU ,EDU,
+expected="EDU MIT.EDU CMU.EDU"
+eval $check
+
+set XYZZY.ATHENA.MIT.EDU XYZZY.CS.CMU.EDU ,EDU,
+expected="EDU MIT.EDU ATHENA.MIT.EDU CMU.EDU CS.CMU.EDU"
+eval $check
+
+rm tmpout1 tmpout2
+trap "" 0
+echo Success.
+exit 0
diff --git a/mechglue/src/lib/krb5/krb/unparse.c b/mechglue/src/lib/krb5/krb/unparse.c
new file mode 100644
index 000000000..a67636641
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/unparse.c
@@ -0,0 +1,200 @@
+/*
+ * lib/krb5/krb/unparse.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_unparse_name() routine
+ *
+ * Rewritten by Theodore Ts'o to properly unparse principal names
+ * which have the component or realm separator as part of one of their
+ * components.
+ */
+
+
+#include "k5-int.h"
+#include <stdio.h>
+
+/*
+ * converts the multi-part principal format used in the protocols to a
+ * single-string representation of the name. 
+ *  
+ * The name returned is in allocated storage and should be freed by
+ * the caller when finished.
+ *
+ * Conventions: / is used to separate components; @ is used to
+ * separate the realm from the rest of the name.  If '/', '@', or '\0'
+ * appear in any the component, they will be representing using
+ * backslash encoding.  ("\/", "\@", or '\0', respectively)
+ *
+ * returns error
+ *	KRB_PARSE_MALFORMED	principal is invalid (does not contain
+ *				at least 2 components)
+ * also returns system errors
+ *	ENOMEM			unable to allocate memory for string
+ */
+
+#define REALM_SEP	'@'
+#define	COMPONENT_SEP	'/'
+
+krb5_error_code KRB5_CALLCONV
+krb5_unparse_name_ext(krb5_context context, krb5_const_principal principal, register char **name, unsigned int *size)
+{
+	register char *cp, *q;
+	register int i,j;
+	int	length;
+	krb5_int32 nelem;
+	register unsigned int totalsize = 0;
+
+	if (!principal || !name)
+		return KRB5_PARSE_MALFORMED;
+
+	cp = krb5_princ_realm(context, principal)->data;
+	length = krb5_princ_realm(context, principal)->length;
+	totalsize += length;
+	for (j = 0; j < length; j++,cp++)
+		if (*cp == REALM_SEP  || *cp == COMPONENT_SEP ||
+		    *cp == '\0' || *cp == '\\' || *cp == '\t' ||
+		    *cp == '\n' || *cp == '\b')
+			totalsize++;
+	totalsize++;		/* This is for the separator */
+
+	nelem = krb5_princ_size(context, principal);
+	for (i = 0; i < (int) nelem; i++) {
+		cp = krb5_princ_component(context, principal, i)->data;
+		length = krb5_princ_component(context, principal, i)->length;
+		totalsize += length;
+		for (j=0; j < length; j++,cp++)
+			if (*cp == REALM_SEP || *cp == COMPONENT_SEP ||
+			    *cp == '\0' || *cp == '\\' || *cp == '\t' ||
+			    *cp == '\n' || *cp == '\b')
+				totalsize++;
+		totalsize++;	/* This is for the separator */
+	}
+	if (nelem == 0)
+		totalsize++;
+
+	/*
+	 * Allocate space for the ascii string; if space has been
+	 * provided, use it, realloc'ing it if necessary.
+	 * 
+	 * We need only n-1 seperators for n components, but we need
+	 * an extra byte for the NULL at the end.
+	 */
+        if (size) {
+            if (*name && (*size < totalsize)) {
+                *name = realloc(*name, totalsize);
+            } else {
+                *name = malloc(totalsize);
+            }
+            *size = totalsize;
+        } else {
+            *name = malloc(totalsize);
+        }
+
+	if (!*name)
+		return ENOMEM;
+
+	q = *name;
+	
+	for (i = 0; i < (int) nelem; i++) {
+		cp = krb5_princ_component(context, principal, i)->data;
+		length = krb5_princ_component(context, principal, i)->length;
+		for (j=0; j < length; j++,cp++) {
+		    switch (*cp) {
+		    case COMPONENT_SEP:
+		    case REALM_SEP:
+		    case '\\':
+			*q++ = '\\';
+			*q++ = *cp;
+			break;
+		    case '\t':
+			*q++ = '\\';
+			*q++ = 't';
+			break;
+		    case '\n':
+			*q++ = '\\';
+			*q++ = 'n';
+			break;
+		    case '\b':
+			*q++ = '\\';
+			*q++ = 'b';
+			break;
+		    case '\0':
+			*q++ = '\\';
+			*q++ = '0';
+			break;
+		    default:
+			*q++ = *cp;
+		    }
+		}
+		*q++ = COMPONENT_SEP;
+	}
+
+	if (i > 0)
+	    q--;		/* Back up last component separator */
+	*q++ = REALM_SEP;
+	
+	cp = krb5_princ_realm(context, principal)->data;
+	length = krb5_princ_realm(context, principal)->length;
+	for (j=0; j < length; j++,cp++) {
+		switch (*cp) {
+		case COMPONENT_SEP:
+		case REALM_SEP:
+		case '\\':
+			*q++ = '\\';
+			*q++ = *cp;
+			break;
+		case '\t':
+			*q++ = '\\';
+			*q++ = 't';
+			break;
+		case '\n':
+			*q++ = '\\';
+			*q++ = 'n';
+			break;
+		case '\b':
+			*q++ = '\\';
+			*q++ = 'b';
+			break;
+		case '\0':
+			*q++ = '\\';
+			*q++ = '0';
+			break;
+		default:
+			*q++ = *cp;
+		}
+	}
+	*q++ = '\0';
+	
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_unparse_name(krb5_context context, krb5_const_principal principal, register char **name)
+{
+        if (name)                       /* name == NULL will return error from _ext */
+            *name = NULL;
+	return(krb5_unparse_name_ext(context, principal, name, NULL));
+}
+
diff --git a/mechglue/src/lib/krb5/krb/v4lifetime.c b/mechglue/src/lib/krb5/krb/v4lifetime.c
new file mode 100644
index 000000000..94bf5f6ab
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/v4lifetime.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2000, 2001, 2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include "k5-int.h"
+
+/*
+ * Only lifetime bytes values less than 128 are on a linear scale.
+ * The following table contains an exponential scale that covers the
+ * lifetime values 128 to 191 inclusive (a total of 64 values).
+ * Values greater than 191 get interpreted the same as 191, but they
+ * will never be generated by the functions in this file.
+ *
+ * The ratio is approximately 1.069144898 (actually exactly
+ * exp(log(67.5)/63), where 67.5 = 2592000/38400, and 259200 = 30
+ * days, and 38400 = 128*5 minutes.  This allows a lifetime byte of
+ * 191 to correspond to a ticket life of exactly 30 days and a
+ * lifetime byte of 128 to correspond to exactly 128*5 minutes, with
+ * the other values spread on an exponential curve fit in between
+ * them.  This table should correspond exactly to the set of extended
+ * ticket lifetime values used by AFS and CMU.
+ *
+ * The following awk script is sufficient to reproduce the table:
+ * BEGIN {
+ *     r = exp(log(2592000/38400)/63);
+ *     x = 38400;
+ *     for (i=0;i<64;i++) {
+ *         printf("%d\n",x+0.5);
+ *         x *= r;
+ *     }
+ * }
+ */
+#ifndef SHORT_LIFETIME
+#define NLIFETIMES 64
+static const krb5_int32 lifetimes[NLIFETIMES] = {
+    38400, 41055,		/* 00:10:40:00, 00:11:24:15 */
+    43894, 46929,		/* 00:12:11:34, 00:13:02:09 */
+    50174, 53643,		/* 00:13:56:14, 00:14:54:03 */
+    57352, 61318,		/* 00:15:55:52, 00:17:01:58 */
+    65558, 70091,		/* 00:18:12:38, 00:19:28:11 */
+    74937, 80119,		/* 00:20:48:57, 00:22:15:19 */
+    85658, 91581,		/* 00:23:47:38, 01:01:26:21 */
+    97914, 104684,		/* 01:03:11:54, 01:05:04:44 */
+    111922, 119661,		/* 01:07:05:22, 01:09:14:21 */
+    127935, 136781,		/* 01:11:32:15, 01:13:59:41 */
+    146239, 156350,		/* 01:16:37:19, 01:19:25:50 */
+    167161, 178720,		/* 01:22:26:01, 02:01:38:40 */
+    191077, 204289,		/* 02:05:04:37, 02:08:44:49 */
+    218415, 233517,		/* 02:12:40:15, 02:16:51:57 */
+    249664, 266926,		/* 02:21:21:04, 03:02:08:46 */
+    285383, 305116,		/* 03:07:16:23, 03:12:45:16 */
+    326213, 348769,		/* 03:18:36:53, 04:00:52:49 */
+    372885, 398668,		/* 04:07:34:45, 04:14:44:28 */
+    426234, 455705,		/* 04:22:23:54, 05:06:35:05 */
+    487215, 520904,		/* 05:15:20:15, 06:00:41:44 */
+    556921, 595430,		/* 06:10:42:01, 06:21:23:50 */
+    636601, 680618,		/* 07:08:50:01, 07:21:03:38 */
+    727680, 777995,		/* 08:10:08:00, 09:00:06:35 */
+    831789, 889303,		/* 09:15:03:09, 10:07:01:43 */
+    950794, 1016537,		/* 11:00:06:34, 11:18:22:17 */
+    1086825, 1161973,		/* 12:13:53:45, 13:10:46:13 */
+    1242318, 1328218,		/* 14:09:05:18, 15:08:56:58 */
+    1420057, 1518247,		/* 16:10:27:37, 17:13:44:07 */
+    1623226, 1735464,		/* 18:18:53:46, 20:02:04:24 */
+    1855462, 1983758,		/* 21:11:24:22, 22:23:02:38 */
+    2120925, 2267576,		/* 24:13:08:45, 26:05:52:56 */
+    2424367, 2592000		/* 28:01:26:07, 30:00:00:00 */
+};
+#define MINFIXED 0x80
+#define MAXFIXED (MINFIXED + NLIFETIMES - 1)
+#endif /* !SHORT_LIFETIME */
+
+/*
+ * krb_life_to_time
+ *
+ * Given a start date and a lifetime byte, compute the expiration
+ * date.
+ */
+krb5_int32
+krb5int_krb_life_to_time(krb5_int32 start, int life)
+{
+    if (life < 0 || life > 255)	/* possibly sign botch in caller */
+	return start;
+#ifndef SHORT_LIFETIME
+    if (life < MINFIXED)
+	return start + life * 5 * 60;
+    if (life > MAXFIXED)
+	return start + lifetimes[NLIFETIMES - 1];
+    return start + lifetimes[life - MINFIXED];
+#else  /* SHORT_LIFETIME */
+    return start + life * 5 * 60;
+#endif /* SHORT_LIFETIME */
+}
+
+/*
+ * krb_time_to_life
+ *
+ * Given the start date and the end date, compute the lifetime byte.
+ * Round up, since we can adjust the start date backwards if we are
+ * issuing the ticket to cause it to expire at the correct time.
+ */
+int
+krb5int_krb_time_to_life(krb5_int32 start, krb5_int32 end)
+{
+    krb5_int32 dt;
+#ifndef SHORT_LIFETIME
+    int i;
+#endif
+
+    dt = end - start;
+    if (dt <= 0)
+	return 0;
+#ifndef SHORT_LIFETIME
+    if (dt < lifetimes[0])
+	return (dt + 5 * 60 - 1) / (5 * 60);
+    /* This depends on the array being ordered. */
+    for (i = 0; i < NLIFETIMES; i++) {
+	if (lifetimes[i] >= dt)
+	    return i + MINFIXED;
+    }
+    return MAXFIXED;
+#else  /* SHORT_LIFETIME */
+    if (dt > 5 * 60 * 255)
+	return 255;
+    else
+	return (dt + 5 * 60 - 1) / (5 * 60);
+#endif /* SHORT_LIFETIME */
+}
diff --git a/mechglue/src/lib/krb5/krb/valid_times.c b/mechglue/src/lib/krb5/krb/valid_times.c
new file mode 100644
index 000000000..9c53d7d91
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/valid_times.c
@@ -0,0 +1,64 @@
+/*
+ * lib/krb5/krb/valid_times.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_validate_times()
+ */
+
+#include "k5-int.h"
+
+#define in_clock_skew(date) (labs((date)-currenttime) < context->clockskew)
+
+/*
+ * This is an internal routine which validates the krb5_timestamps
+ * field in a krb5_ticket.
+ */
+
+krb5_error_code
+krb5_validate_times(krb5_context context, krb5_ticket_times *times)
+{
+	krb5_timestamp 	  	currenttime, starttime;
+	krb5_error_code		retval;
+
+	if ((retval = krb5_timeofday(context, ¤ttime)))
+		return retval;
+
+	/* if starttime is not in ticket, then treat it as authtime */
+	if (times->starttime != 0)
+		starttime = times->starttime;
+	else
+		starttime = times->authtime;
+
+	if (starttime - currenttime > context->clockskew)
+		return KRB5KRB_AP_ERR_TKT_NYV;	/* ticket not yet valid */
+
+	if ((currenttime - times->endtime) > context->clockskew)
+		return KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */
+
+	return 0;
+}
+
+       
+
diff --git a/mechglue/src/lib/krb5/krb/vfy_increds.c b/mechglue/src/lib/krb5/krb/vfy_increds.c
new file mode 100644
index 000000000..62b535da9
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/vfy_increds.c
@@ -0,0 +1,222 @@
+#include "k5-int.h"
+#include "int-proto.h"
+
+static krb5_error_code
+krb5_cc_copy_creds_except(krb5_context context, krb5_ccache incc, krb5_ccache outcc, krb5_principal princ)
+{
+   krb5_error_code code;
+   krb5_flags flags;
+   krb5_cc_cursor cur;
+   krb5_creds creds;
+
+   flags = 0;				/* turns off OPENCLOSE mode */
+   if ((code = krb5_cc_set_flags(context, incc, flags)))
+      return(code);
+   if ((code = krb5_cc_set_flags(context, outcc, flags)))
+      return(code);
+
+   if ((code = krb5_cc_start_seq_get(context, incc, &cur)))
+      goto cleanup;
+
+   while (!(code = krb5_cc_next_cred(context, incc, &cur, &creds))) {
+      if (krb5_principal_compare(context, princ, creds.server))
+	 continue;
+
+      code = krb5_cc_store_cred(context, outcc, &creds);
+      krb5_free_cred_contents(context, &creds);
+      if (code)
+	 goto cleanup;
+   }
+
+   if (code != KRB5_CC_END)
+      goto cleanup;
+
+   code = 0;
+
+cleanup:
+   flags = KRB5_TC_OPENCLOSE;
+
+   if (code)
+      krb5_cc_set_flags(context, incc, flags);
+   else
+      code = krb5_cc_set_flags(context, incc, flags);
+
+   if (code)
+      krb5_cc_set_flags(context, outcc, flags);
+   else
+      code = krb5_cc_set_flags(context, outcc, flags);
+
+   return(code);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_verify_init_creds(krb5_context context,
+		       krb5_creds *creds,
+		       krb5_principal server_arg,
+		       krb5_keytab keytab_arg,
+		       krb5_ccache *ccache_arg,
+		       krb5_verify_init_creds_opt *options)
+{
+   krb5_error_code ret;
+   krb5_principal server;
+   krb5_keytab keytab;
+   krb5_ccache ccache;
+   krb5_keytab_entry kte;
+   krb5_creds in_creds, *out_creds;
+   krb5_auth_context authcon;
+   krb5_data ap_req;
+   
+   /* KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN */
+
+   server = NULL;
+   keytab = NULL;
+   ccache = NULL;
+   out_creds = NULL;
+   authcon = NULL;
+   ap_req.data = NULL;
+
+   if (server_arg) {
+      server = server_arg;
+   } else {
+      if ((ret = krb5_sname_to_principal(context, NULL, NULL, 
+					 KRB5_NT_SRV_HST, &server)))
+	 goto cleanup;
+   }
+      
+   /* first, check if the server is in the keytab.  If not, there's
+      no reason to continue.  rd_req does all this, but there's
+      no way to know that a given error is caused by a missing
+      keytab or key, and not by some other problem. */
+
+   if (keytab_arg) {
+      keytab = keytab_arg;
+   } else {
+     if ((ret = krb5_kt_default(context, &keytab)))
+	 goto cleanup;
+   }
+
+   if ((ret = krb5_kt_get_entry(context, keytab, server, 0, 0, &kte))) {
+       /* this means there is no keying material.  This is ok, as long as
+	  it is not prohibited by the configuration */
+
+       int nofail;
+
+       if (options &&
+	   (options->flags & KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL)) {
+	   if (options->ap_req_nofail)
+	       goto cleanup;
+       } else if (krb5_libdefault_boolean(context,
+					  &creds->client->realm,
+					  "verify_ap_req_nofail",
+					  &nofail)
+		  == 0) {
+	   if (nofail)
+	       goto cleanup;
+       }
+
+       ret = 0;
+       goto cleanup;
+   }
+
+   krb5_kt_free_entry(context, &kte);
+
+   /* If the creds are for the server principal, we're set, just do
+      a mk_req.	 Otherwise, do a get_credentials first. */
+
+   if (krb5_principal_compare(context, server, creds->server)) {
+      /* make an ap_req */
+      if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, creds,
+				      &ap_req)))
+	 goto cleanup;
+   } else {
+      /* this is unclean, but it's the easiest way without ripping the
+	 library into very small pieces.  store the client's initial cred
+	 in a memory ccache, then call the library.  Later, we'll copy
+	 everything except the initial cred into the ccache we return to
+	 the user.  A clean implementation would involve library
+	 internals with a coherent idea of "in" and "out". */
+
+      /* insert the initial cred into the ccache */
+
+      if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req", &ccache)))
+	 goto cleanup;
+
+      if ((ret = krb5_cc_initialize(context, ccache, creds->client)))
+	 goto cleanup;
+
+      if ((ret = krb5_cc_store_cred(context, ccache, creds)))
+	 goto cleanup;
+
+      /* set up for get_creds */
+      memset(&in_creds, 0, sizeof(in_creds));
+      in_creds.client = creds->client;
+      in_creds.server = server;
+      if ((ret = krb5_timeofday(context, &in_creds.times.endtime)))
+	 goto cleanup;
+      in_creds.times.endtime += 5*60;
+
+      if ((ret = krb5_get_credentials(context, 0, ccache, &in_creds,
+				      &out_creds)))
+	 goto cleanup;
+
+      /* make an ap_req */
+      if ((ret = krb5_mk_req_extended(context, &authcon, 0, NULL, out_creds,
+				      &ap_req)))
+	 goto cleanup;
+   }
+
+   /* wipe the auth context for mk_req */
+   if (authcon) {
+      krb5_auth_con_free(context, authcon);
+      authcon = NULL;
+   }
+
+   /* verify the ap_req */
+
+   if ((ret = krb5_rd_req(context, &authcon, &ap_req, server, keytab,
+			  NULL, NULL)))
+      goto cleanup;
+
+   /* if we get this far, then the verification succeeded.  We can
+      still fail if the library stuff here fails, but that's it */
+
+   if (ccache_arg && ccache) {
+       if (*ccache_arg == NULL) {
+	   krb5_ccache retcc;
+
+	   retcc = NULL;
+
+	   if ((ret = krb5_cc_resolve(context, "MEMORY:rd_req2", &retcc)) ||
+	       (ret = krb5_cc_initialize(context, retcc, creds->client)) ||
+	       (ret = krb5_cc_copy_creds_except(context, ccache, retcc,
+						creds->server))) {
+	       if (retcc)
+		   krb5_cc_destroy(context, retcc);
+	   } else {
+	       *ccache_arg = retcc;
+	   }
+       } else {
+	   ret = krb5_cc_copy_creds_except(context, ccache, *ccache_arg,
+					   server);
+       }
+   }
+
+   /* if any of the above paths returned an errors, then ret is set
+      accordingly.  either that, or it's zero, which is fine, too */
+
+cleanup:
+   if (!server_arg && server)
+      krb5_free_principal(context, server);
+   if (!keytab_arg && keytab)
+      krb5_kt_close(context, keytab);
+   if (ccache)
+      krb5_cc_destroy(context, ccache);
+   if (out_creds)
+      krb5_free_creds(context, out_creds);
+   if (authcon)
+      krb5_auth_con_free(context, authcon);
+   if (ap_req.data)
+      krb5_xfree(ap_req.data);
+
+   return(ret);
+}
diff --git a/mechglue/src/lib/krb5/krb/vic_opt.c b/mechglue/src/lib/krb5/krb/vic_opt.c
new file mode 100644
index 000000000..acdf49406
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/vic_opt.c
@@ -0,0 +1,14 @@
+#include "k5-int.h"
+
+void KRB5_CALLCONV
+krb5_verify_init_creds_opt_init(krb5_verify_init_creds_opt *opt)
+{
+   opt->flags = 0;
+}
+
+void KRB5_CALLCONV
+krb5_verify_init_creds_opt_set_ap_req_nofail(krb5_verify_init_creds_opt *opt, int ap_req_nofail)
+{
+   opt->flags |= KRB5_VERIFY_INIT_CREDS_OPT_AP_REQ_NOFAIL;
+   opt->ap_req_nofail = ap_req_nofail;
+}
diff --git a/mechglue/src/lib/krb5/krb/walk_rtree.c b/mechglue/src/lib/krb5/krb/walk_rtree.c
new file mode 100644
index 000000000..074c7e1d0
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/walk_rtree.c
@@ -0,0 +1,384 @@
+/*
+ * lib/krb5/krb/walk_rtree.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_walk_realm_tree()
+ */
+
+/* ANL - Modified to allow Configurable Authentication Paths.
+ * This modification removes the restriction on the choice of realm
+ * names, i.e. they nolonger have to be hierarchical. This
+ * is allowed by RFC 1510: "If a hierarchical orginization is not used
+ * it may be necessary to consult some database in order to construct
+ * an authentication path between realms."  The database is contained
+ * in the [capaths] section of the krb5.conf file.
+ * Client to server paths are defined. There are n**2 possible
+ * entries, but only those entries which are needed by the client
+ * or server need be present in its krb5.conf file. (n entries or 2*n
+ * entries if the same krb5.conf is used for clients and servers)
+ *
+ * for example: ESnet will be running a KDC which will share
+ * inter-realm keys with its many orginizations which include among
+ * other ANL, NERSC and PNL. Each of these orginizations wants to
+ * use its DNS name in the realm, ANL.GOV. In addition ANL wants
+ * to authenticatite to HAL.COM via a K5.MOON and K5.JUPITER
+ * A [capaths] section of the krb5.conf file for the ANL.GOV clients
+ * and servers would look like:
+ *
+ * [capaths]
+ * ANL.GOV = {
+ *		NERSC.GOV = ES.NET
+ *		PNL.GOV = ES.NET
+ *		ES.NET = .
+ * 		HAL.COM = K5.MOON
+ * 		HAL.COM = K5.JUPITER
+ * }
+ * NERSC.GOV = {
+ *		ANL.GOV = ES.NET
+ * }
+ * PNL.GOV = {
+ *		ANL.GOV = ES.NET
+ * }
+ * ES.NET = {
+ * 		ANL.GOV = .
+ * }
+ * HAL.COM = {
+ *		ANL.GOV = K5.JUPITER
+ *		ANL.GOV = K5.MOON
+ * }
+ *
+ * In the above a "." is used to mean directly connected since the
+ * the profile routines cannot handle a null entry.
+ *
+ * If no client-to-server path is found, the default hierarchical path
+ * is still generated.
+ *
+ * This version of the Configurable Authentication Path modification
+ * differs from the previous versions prior to K5 beta 5 in that
+ * the profile routines are used, and the explicite path from
+ * client's realm to server's realm must be given. The modifications
+ * will work together.
+ * DEE - 5/23/95
+ */
+#define CONFIGURABLE_AUTHENTICATION_PATH
+#include "k5-int.h"
+#include "int-proto.h"
+
+/* internal function, used by krb5_get_cred_from_kdc() */
+
+#ifndef min
+#define min(x,y) ((x) < (y) ? (x) : (y))
+#define max(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+/*
+ * xxx The following function is very confusing to read and probably
+ * is buggy.  It should be documented better.  Here is what I've
+ * learned about it doing a quick bug fixing walk through.  The
+ * function takes a client and server realm name and returns the set
+ * of realms (in a field called tree) that you need to get tickets in
+ * in order to get from the source realm to the destination realm.  It
+ * takes a realm separater character (normally ., but presumably there
+ * for all those X.500 realms) .  There are two modes it runs in: the
+ * ANL krb5.confmode and the hierarchy mode.  The ANL mode is
+ * fairly obvious.  The hierarchy mode looks for common components in
+ * both the client and server realms.  In general, the pointer scp and
+ * ccp are used to walk through the client and server realms.  The
+ * com_sdot and com_cdot pointers point to (I think) the beginning of
+ * the common part of the realm names.  I.E. strcmp(com_cdot,
+ * com_sdot) ==0 is roughly an invarient.  However, there are cases
+ * where com_sdot and com_cdot are set to point before the start of
+ * the client or server strings.  I think this only happens when there
+ * are no common components.  --hartmans 2002/03/14
+ */
+
+krb5_error_code
+krb5_walk_realm_tree(krb5_context context, const krb5_data *client, const krb5_data *server, krb5_principal **tree, int realm_branch_char)
+{
+    krb5_error_code retval;
+    krb5_principal *rettree;
+    register char *ccp, *scp;
+    register char *prevccp = 0, *prevscp = 0;
+    char *com_sdot = 0, *com_cdot = 0;
+    register int i, links = 0;
+    int clen, slen = -1;
+    krb5_data tmpcrealm, tmpsrealm;
+    int nocommon = 1;
+
+#ifdef CONFIGURABLE_AUTHENTICATION_PATH
+    const char *cap_names[4];
+    char *cap_client, *cap_server;
+    char **cap_nodes;
+    krb5_error_code cap_code;
+#endif
+    if (!(client->data &&server->data))
+      return KRB5_NO_TKT_IN_RLM;
+#ifdef CONFIGURABLE_AUTHENTICATION_PATH
+    if ((cap_client = (char *)malloc(client->length + 1)) == NULL)
+	return ENOMEM;
+    strncpy(cap_client, client->data, client->length);
+    cap_client[client->length] = '\0';
+    if ((cap_server = (char *)malloc(server->length + 1)) == NULL) {
+	krb5_xfree(cap_client);
+	return ENOMEM;
+    }
+    strncpy(cap_server, server->data, server->length);
+    cap_server[server->length] = '\0';
+    cap_names[0] = "capaths";
+    cap_names[1] = cap_client;
+    cap_names[2] = cap_server;
+    cap_names[3] = 0;
+    cap_code = profile_get_values(context->profile, cap_names, &cap_nodes);
+    krb5_xfree(cap_client);  /* done with client string */
+    cap_names[1] = 0;
+    if (cap_code == 0) {     /* found a path, so lets use it */
+	links = 0;
+	if (*cap_nodes[0] != '.') { /* a link of . means direct */
+	    while(cap_nodes[links]) {
+		links++;
+	    }
+	}
+	cap_nodes[links] = cap_server; /* put server on end of list */
+	/* this simplifies the code later and make */
+	/* cleanup eaiser as well */
+	links++;		/* count the null entry at end */
+    } else {			/* no path use hierarchical method */
+	krb5_xfree(cap_server); /* failed, don't need server string */
+	cap_names[2] = 0;
+#endif
+	clen = client->length;
+	slen = server->length;
+
+	for (com_cdot = ccp = client->data + clen - 1,
+		 com_sdot = scp = server->data + slen - 1;
+	     clen && slen && *ccp == *scp ;
+	     ccp--, scp--, 	clen--, slen--) {
+	    if (*ccp == realm_branch_char) {
+		com_cdot = ccp;
+		com_sdot = scp;
+		nocommon = 0;
+	    }
+	}
+
+	/* ccp, scp point to common root.
+	   com_cdot, com_sdot point to common components. */
+	/* handle case of one ran out */
+	if (!clen) {
+	    /* construct path from client to server, down the tree */
+	    if (!slen)
+		/* in the same realm--this means there is no ticket
+		   in this realm. */
+		return KRB5_NO_TKT_IN_RLM;
+	    if (*scp == realm_branch_char) {
+		/* one is a subdomain of the other */
+		com_cdot = client->data;
+		com_sdot = scp;
+		nocommon = 0;
+	    } /* else normal case of two sharing parents */
+	}
+	if (!slen) {
+	    /* construct path from client to server, up the tree */
+	    if (*ccp == realm_branch_char) {
+		/* one is a subdomain of the other */
+		com_sdot = server->data;
+		com_cdot = ccp;
+		nocommon = 0;
+	    } /* else normal case of two sharing parents */
+	}
+	/* determine #links to/from common ancestor */
+	if (nocommon)
+	    links = 1;
+	else
+	    links = 2;
+	/* if no common ancestor, artificially set up common root at the last
+	   component, then join with special code */
+	for (ccp = client->data; ccp < com_cdot; ccp++) {
+	    if (*ccp == realm_branch_char) {
+		links++;
+		if (nocommon)
+		    prevccp = ccp;
+	    }
+	}
+
+	for (scp = server->data; scp < com_sdot; scp++) {
+	    if (*scp == realm_branch_char) {
+		links++;
+		if (nocommon)
+		    prevscp = scp;
+	    }
+	}
+	if (nocommon) {
+	    if (prevccp)
+		com_cdot = prevccp;
+	    if (prevscp)
+		com_sdot = prevscp;
+
+	    if(com_cdot == client->data + client->length -1)
+		com_cdot = client->data - 1 ;
+	    if(com_sdot == server->data + server->length -1)
+		com_sdot = server->data - 1 ;
+	}
+#ifdef CONFIGURABLE_AUTHENTICATION_PATH
+    }		/* end of if use hierarchical method */
+#endif
+
+    if (!(rettree = (krb5_principal *)calloc(links+2,
+					     sizeof(krb5_principal)))) {
+	return ENOMEM;
+    }
+    i = 1;
+    if ((retval = krb5_tgtname(context, client, client, &rettree[0]))) {
+	krb5_xfree(rettree);
+	return retval;
+    }
+#ifdef CONFIGURABLE_AUTHENTICATION_PATH
+    links--;				/* dont count the null entry on end */
+    if (cap_code == 0) {    /* found a path above */
+	tmpcrealm.data = client->data;
+	tmpcrealm.length = client->length;
+	while( i-1 <= links) {
+			
+	    tmpsrealm.data = cap_nodes[i-1];
+	    /* don't count trailing whitespace from profile_get */
+	    tmpsrealm.length = strcspn(cap_nodes[i-1],"\t ");
+	    if ((retval = krb5_tgtname(context,
+				       &tmpsrealm,
+				       &tmpcrealm,
+				       &rettree[i]))) {
+		while (i) {
+		    krb5_free_principal(context, rettree[i-1]);
+		    i--;
+		}
+		krb5_xfree(rettree);
+				/* cleanup the cap_nodes from profile_get */
+		for (i = 0; i<=links; i++) {
+		    krb5_xfree(cap_nodes[i]);
+		}
+		krb5_xfree((char *)cap_nodes);
+		return retval;
+	    }
+	    tmpcrealm.data = tmpsrealm.data;	
+	    tmpcrealm.length = tmpsrealm.length;
+	    i++;
+	}
+	/* cleanup the cap_nodes from profile_get last one has server */
+	for (i = 0; i<=links; i++) {
+	    krb5_xfree(cap_nodes[i]);
+	}
+	krb5_xfree((char *)cap_nodes);
+    } else {  /* if not cap then use hierarchical method */
+#endif
+	for (prevccp = ccp = client->data;
+	     ccp <= com_cdot;
+	     ccp++) {
+	    if (*ccp != realm_branch_char)
+		continue;
+	    ++ccp;				/* advance past dot */
+	    tmpcrealm.data = prevccp;
+	    tmpcrealm.length = client->length -
+		(prevccp - client->data);
+	    tmpsrealm.data = ccp;
+	    tmpsrealm.length = client->length -
+		(ccp - client->data);
+	    if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
+				       &rettree[i]))) {
+		while (i) {
+		    krb5_free_principal(context, rettree[i-1]);
+		    i--;
+		}
+		krb5_xfree(rettree);
+		return retval;
+	    }
+	    prevccp = ccp;
+	    i++;
+	}
+	if (nocommon) {
+	    tmpcrealm.data = com_cdot + 1;
+	    tmpcrealm.length = client->length -
+		(com_cdot + 1 - client->data);
+	    tmpsrealm.data = com_sdot + 1;
+	    tmpsrealm.length = server->length -
+		(com_sdot + 1 - server->data);
+	    if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
+				       &rettree[i]))) {
+		while (i) {
+		    krb5_free_principal(context, rettree[i-1]);
+		    i--;
+		}
+		krb5_xfree(rettree);
+		return retval;
+	    }
+	    i++;
+	}
+
+	for (prevscp = com_sdot + 1, scp = com_sdot - 1;
+	     scp > server->data;
+	     scp--) {
+	    if (*scp != realm_branch_char)
+		continue;
+	    if (scp - 1 < server->data)
+		break;			/* XXX only if . starts realm? */
+	    tmpcrealm.data = prevscp;
+	    tmpcrealm.length = server->length -
+		(prevscp - server->data);
+	    tmpsrealm.data = scp + 1;
+	    tmpsrealm.length = server->length -
+		(scp + 1 - server->data);
+	    if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
+				       &rettree[i]))) {
+		while (i) {
+		    krb5_free_principal(context, rettree[i-1]);
+		    i--;
+		}
+		krb5_xfree(rettree);
+		return retval;
+	    }
+	    prevscp = scp + 1;
+	    i++;
+	}
+	if (slen && com_sdot >= server->data) {
+	    /* only necessary if building down tree from ancestor or client */
+	    /* however, we can get here if we have only one component
+	       in the server realm name, hence we make sure we found a component
+	       separator there... */
+	    tmpcrealm.data = prevscp;
+	    tmpcrealm.length = server->length -
+		(prevscp - server->data);
+	    if ((retval = krb5_tgtname(context, server, &tmpcrealm,
+				       &rettree[i]))) {
+		while (i) {
+		    krb5_free_principal(context, rettree[i-1]);
+		    i--;
+		}
+		krb5_xfree(rettree);
+		return retval;
+	    }
+	}
+#ifdef CONFIGURABLE_AUTHENTICATION_PATH
+    }
+#endif
+    *tree = rettree;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb/x-deltat.y b/mechglue/src/lib/krb5/krb/x-deltat.y
new file mode 100644
index 000000000..ccd956d10
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb/x-deltat.y
@@ -0,0 +1,229 @@
+/*
+ * lib/krb5/krb/deltat.y
+ *
+ * Copyright 1999 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_string_to_deltat()
+ */
+
+/* For a clean, thread-safe interface, we must use the "pure parser"
+   facility of GNU Bison.  Unfortunately, standard YACC has no such
+   option.  */
+
+/* N.B.: For simplicity in dealing with the distribution, the
+   Makefile.in listing for deltat.c does *not* normally list this
+   file.  If you change this file, tweak the Makefile so it'll rebuild
+   deltat.c, or do it manually.  */
+%{
+
+#include <ctype.h>
+#include <errno.h>
+#include "k5-int.h"
+
+struct param {
+    krb5_int32 delta;
+    char *p;
+};
+
+#define YYPARSE_PARAM tmv
+
+#define MAX_TIME KRB5_INT32_MAX
+#define MIN_TIME KRB5_INT32_MIN
+
+#define DAY (24 * 3600)
+#define HOUR 3600
+
+#define MAX_DAY (MAX_TIME / DAY)
+#define MIN_DAY (MIN_TIME / DAY)
+#define MAX_HOUR (MAX_TIME / HOUR)
+#define MIN_HOUR (MIN_TIME / HOUR)
+#define MAX_MIN (MAX_TIME / 60)
+#define MIN_MIN (MIN_TIME / 60)
+
+/* An explanation of the tests being performed. 
+   We do not want to overflow a 32 bit integer with out manipulations, 
+   even for testing for overflow. Therefore we rely on the following:
+
+   The lex parser will not return a number > MAX_TIME (which is out 32
+   bit limit).
+
+   Therefore, seconds (s) will require 
+       MIN_TIME < s < MAX_TIME
+
+   For subsequent tests, the logic is as follows:
+
+      If A < MAX_TIME and  B < MAX_TIME
+
+      If we want to test if A+B < MAX_TIME, there are two cases
+        if (A > 0) 
+         then A + B < MAX_TIME if B < MAX_TIME - A
+	else A + B < MAX_TIME  always.
+
+      if we want to test if MIN_TIME < A + B
+          if A > 0 - then nothing to test
+          otherwise, we test if MIN_TIME - A < B.
+
+   We of course are testing for:
+          MIN_TIME < A + B < MAX_TIME
+*/
+
+
+#define DAY_NOT_OK(d) (d) > MAX_DAY || (d) < MIN_DAY
+#define HOUR_NOT_OK(h) (h) > MAX_HOUR || (h) < MIN_HOUR
+#define MIN_NOT_OK(m) (m) > MAX_MIN || (m) < MIN_MIN
+#define SUM_OK(a, b) (((a) > 0) ? ( (b) <= MAX_TIME - (a)) : (MIN_TIME - (a) <= (b)))
+#define DO_SUM(res, a, b) if (!SUM_OK((a), (b))) YYERROR; \
+                          res = (a) + (b)
+
+
+#define OUT_D ((struct param *)tmv)->delta 
+#define DO(D,H,M,S) \
+ { \
+     /* Overflow testing - this does not handle negative values well.. */ \
+     if (DAY_NOT_OK(D) || HOUR_NOT_OK(H) || MIN_NOT_OK(M)) YYERROR; \
+     OUT_D = D * DAY; \
+     DO_SUM(OUT_D, OUT_D, H * HOUR); \
+     DO_SUM(OUT_D, OUT_D, M * 60); \
+     DO_SUM(OUT_D, OUT_D, S); \
+ }
+
+static int mylex (int *, char **);
+#define YYLEX_PARAM (&((struct param *)tmv)->p)
+#undef yylex
+#define yylex(U, P)    mylex (&(U)->val, (P))
+
+#undef yyerror
+#define yyerror(MSG)
+
+static int yyparse (void *);
+
+%}
+
+%pure_parser
+
+%union { int val; }
+
+%token <val> NUM LONGNUM OVERFLOW
+%token '-' ':' 'd' 'h' 'm' 's' tok_WS
+
+%type <val> num opt_hms opt_ms opt_s wsnum posnum
+
+%start start
+
+%%
+
+start: deltat;
+posnum: NUM | LONGNUM ;
+num: posnum | '-' posnum { $$ = - $2; } ;
+ws: /* nothing */ | tok_WS ;
+wsnum: ws num { $$ = $2; }
+        | ws OVERFLOW { YYERROR; };
+deltat:
+	  wsnum 'd' opt_hms		{ DO ($1,  0,  0, $3); }
+	| wsnum 'h' opt_ms		{ DO ( 0, $1,  0, $3); }
+	| wsnum 'm' opt_s		{ DO ( 0,  0, $1, $3); }
+	| wsnum 's'			{ DO ( 0,  0,  0, $1); }
+	| wsnum '-' NUM ':' NUM ':' NUM	{ DO ($1, $3, $5, $7); }
+	| wsnum ':' NUM ':' NUM		{ DO ( 0, $1, $3, $5); }
+	| wsnum ':' NUM			{ DO ( 0, $1, $3,  0); }
+	| wsnum 			{ DO ( 0,  0,  0, $1); } /* default to 's' */
+	;
+
+opt_hms:
+	  opt_ms
+	  | wsnum 'h' opt_ms		{ if (HOUR_NOT_OK($1)) YYERROR;
+	                                  DO_SUM($$, $1 * 3600, $3); }; 
+opt_ms:
+	  opt_s
+	| wsnum 'm' opt_s		{ if (MIN_NOT_OK($1)) YYERROR;
+	                                  DO_SUM($$, $1 * 60, $3); }; 
+opt_s:
+	  ws				{ $$ = 0; }
+	| wsnum 's' ;
+
+%%
+
+static int
+mylex (krb5_int32 *intp, char **pp)
+{
+    int num, c;
+#define P (*pp)
+    char *orig_p = P;
+
+#ifdef isascii
+    if (!isascii (*P))
+	return 0;
+#endif
+    switch (c = *P++) {
+    case '-':
+    case ':':
+    case 'd':
+    case 'h':
+    case 'm':
+    case 's':
+	return c;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+	/* XXX assumes ASCII */
+	num = c - '0';
+	while (isdigit ((int) *P)) {
+	  if (num > MAX_TIME / 10) 
+	    return OVERFLOW;
+	    num *= 10;
+	    if (num > MAX_TIME - (*P - '0')) 
+	      return OVERFLOW;
+	    num += *P++ - '0';
+	}
+	*intp = num;
+	return (P - orig_p > 2) ? LONGNUM : NUM;
+    case ' ':
+    case '\t':
+    case '\n':
+	while (isspace ((int) *P))
+	    P++;
+	return tok_WS;
+    default:
+	return YYEOF;
+    }
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_string_to_deltat(char *string, krb5_deltat *deltatp)
+{
+    struct param p;
+    p.delta = 0;
+    p.p = string;
+    if (yyparse (&p))
+	return KRB5_DELTAT_BADFORMAT;
+    *deltatp = p.delta;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/krb5_libinit.c b/mechglue/src/lib/krb5/krb5_libinit.c
new file mode 100644
index 000000000..6771776ce
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb5_libinit.c
@@ -0,0 +1,108 @@
+#include <assert.h>
+
+#include "autoconf.h"
+#include "com_err.h"
+#include "k5-int.h"
+#include "krb5_err.h"
+#include "kv5m_err.h"
+#include "asn1_err.h"
+#include "kdb5_err.h"
+
+#if defined(_WIN32) || defined(USE_CCAPI)
+#include "stdcc.h"
+#endif
+
+#include "krb5_libinit.h"
+#include "k5-platform.h"
+#include "cc-int.h"
+#include "kt-int.h"
+#include "rc-int.h"
+#include "os-proto.h"
+
+/*
+ * Initialize the Kerberos v5 library.
+ */
+
+MAKE_INIT_FUNCTION(krb5int_lib_init);
+MAKE_FINI_FUNCTION(krb5int_lib_fini);
+
+/* Possibly load-time initialization -- mutexes, etc.  */
+int krb5int_lib_init(void)
+{
+    int err;
+
+#ifdef SHOW_INITFINI_FUNCS
+    printf("krb5int_lib_init\n");
+#endif
+
+#if !USE_BUNDLE_ERROR_STRINGS
+    add_error_table(&et_krb5_error_table);
+    add_error_table(&et_kv5m_error_table);
+    add_error_table(&et_kdb5_error_table);
+    add_error_table(&et_asn1_error_table);
+    add_error_table(&et_k524_error_table);
+#endif
+
+    err = krb5int_rc_finish_init();
+    if (err)
+	return err;
+    err = krb5int_kt_initialize();
+    if (err)
+	return err;
+    err = krb5int_cc_initialize();
+    if (err)
+	return err;
+    err = k5_mutex_finish_init(&krb5int_us_time_mutex);
+    if (err)
+	return err;
+    return 0;
+}
+
+/* Always-delayed initialization -- error table linkage, etc.  */
+krb5_error_code krb5int_initialize_library (void)
+{
+    return CALL_INIT_FUNCTION(krb5int_lib_init);
+}
+
+/*
+ * Clean up the Kerberos v5 library state
+ */
+
+void krb5int_lib_fini(void)
+{
+    if (!INITIALIZER_RAN(krb5int_lib_init) || PROGRAM_EXITING()) {
+#ifdef SHOW_INITFINI_FUNCS
+	printf("krb5int_lib_fini: skipping\n");
+#endif
+	return;
+    }
+
+#ifdef SHOW_INITFINI_FUNCS
+    printf("krb5int_lib_fini\n");
+#endif
+
+    k5_mutex_destroy(&krb5int_us_time_mutex);
+
+    krb5int_cc_finalize();
+    krb5int_kt_finalize();
+    krb5int_rc_terminate();
+
+#if defined(_WIN32) || defined(USE_CCAPI)
+    krb5_stdcc_shutdown();
+#endif
+
+#if !USE_BUNDLE_ERROR_STRINGS
+    remove_error_table(&et_krb5_error_table);
+    remove_error_table(&et_kv5m_error_table);
+    remove_error_table(&et_kdb5_error_table);
+    remove_error_table(&et_asn1_error_table);
+    remove_error_table(&et_k524_error_table);
+#endif
+}
+
+/* Still exists because it went into the export list on Windows.  But
+   since the above function should be invoked at unload time, we don't
+   actually want to do anything here.  */
+void krb5int_cleanup_library (void)
+{
+}
diff --git a/mechglue/src/lib/krb5/krb5_libinit.h b/mechglue/src/lib/krb5/krb5_libinit.h
new file mode 100644
index 000000000..11d7248fe
--- /dev/null
+++ b/mechglue/src/lib/krb5/krb5_libinit.h
@@ -0,0 +1,9 @@
+#ifndef KRB5_LIBINIT_H
+#define KRB5_LIBINIT_H
+
+#include "krb5.h"
+
+krb5_error_code krb5int_initialize_library (void);
+void krb5int_cleanup_library (void);
+
+#endif /* KRB5_LIBINIT_H */
diff --git a/mechglue/src/lib/krb5/libkrb5.exports b/mechglue/src/lib/krb5/libkrb5.exports
new file mode 100644
index 000000000..f16b45cf8
--- /dev/null
+++ b/mechglue/src/lib/krb5/libkrb5.exports
@@ -0,0 +1,728 @@
+_krb5_conf_boolean
+_krb5_use_dns_kdc
+_krb5_use_dns_realm
+asn12krb5_buf
+asn1_decode_addrtype
+asn1_decode_ap_options
+asn1_decode_authdata_elt
+asn1_decode_authdatatype
+asn1_decode_authorization_data
+asn1_decode_charstring
+asn1_decode_checksum
+asn1_decode_cksumtype
+asn1_decode_enc_kdc_rep_part
+asn1_decode_enc_sam_key
+asn1_decode_enc_sam_response_enc
+asn1_decode_enc_sam_response_enc_2
+asn1_decode_encrypted_data
+asn1_decode_encryption_key
+asn1_decode_enctype
+asn1_decode_etype_info
+asn1_decode_etype_info2
+asn1_decode_generalstring
+asn1_decode_generaltime
+asn1_decode_host_address
+asn1_decode_host_addresses
+asn1_decode_ia5string
+asn1_decode_int
+asn1_decode_int32
+asn1_decode_integer
+asn1_decode_kdc_options
+asn1_decode_kdc_rep
+asn1_decode_kdc_req
+asn1_decode_kdc_req_body
+asn1_decode_kerberos_time
+asn1_decode_krb5_flags
+asn1_decode_krb_cred_info
+asn1_decode_krb_safe_body
+asn1_decode_kvno
+asn1_decode_last_req
+asn1_decode_last_req_entry
+asn1_decode_maybe_unsigned
+asn1_decode_msgtype
+asn1_decode_null
+asn1_decode_octet
+asn1_decode_octetstring
+asn1_decode_oid
+asn1_decode_pa_data
+asn1_decode_passwdsequence
+asn1_decode_predicted_sam_response
+asn1_decode_principal_name
+asn1_decode_printablestring
+asn1_decode_realm
+asn1_decode_sam_challenge
+asn1_decode_sam_challenge_2
+asn1_decode_sam_challenge_2_body
+asn1_decode_sam_flags
+asn1_decode_sam_response
+asn1_decode_sam_response_2
+asn1_decode_seqnum
+asn1_decode_sequence_of_checksum
+asn1_decode_sequence_of_enctype
+asn1_decode_sequence_of_krb_cred_info
+asn1_decode_sequence_of_pa_data
+asn1_decode_sequence_of_passwdsequence
+asn1_decode_sequence_of_ticket
+asn1_decode_ticket
+asn1_decode_ticket_flags
+asn1_decode_transited_encoding
+asn1_decode_ui_2
+asn1_decode_ui_4
+asn1_decode_unsigned_integer
+asn1_encode_ap_options
+asn1_encode_authorization_data
+asn1_encode_charstring
+asn1_encode_checksum
+asn1_encode_enc_kdc_rep_part
+asn1_encode_enc_sam_response_enc
+asn1_encode_enc_sam_response_enc_2
+asn1_encode_encrypted_data
+asn1_encode_encryption_key
+asn1_encode_enumerated
+asn1_encode_etype_info
+asn1_encode_etype_info_entry
+asn1_encode_generalstring
+asn1_encode_generaltime
+asn1_encode_host_address
+asn1_encode_host_addresses
+asn1_encode_ia5string
+asn1_encode_integer
+asn1_encode_kdc_options
+asn1_encode_kdc_rep
+asn1_encode_kdc_req
+asn1_encode_kdc_req_body
+asn1_encode_kerberos_time
+asn1_encode_krb5_authdata_elt
+asn1_encode_krb5_flags
+asn1_encode_krb_cred_info
+asn1_encode_krb_safe_body
+asn1_encode_krb_saved_safe_body
+asn1_encode_last_req
+asn1_encode_last_req_entry
+asn1_encode_null
+asn1_encode_octetstring
+asn1_encode_oid
+asn1_encode_pa_data
+asn1_encode_passwdsequence
+asn1_encode_predicted_sam_response
+asn1_encode_principal_name
+asn1_encode_printablestring
+asn1_encode_realm
+asn1_encode_sam_challenge
+asn1_encode_sam_challenge_2
+asn1_encode_sam_challenge_2_body
+asn1_encode_sam_flags
+asn1_encode_sam_key
+asn1_encode_sam_response
+asn1_encode_sam_response_2
+asn1_encode_sequence_of_checksum
+asn1_encode_sequence_of_enctype
+asn1_encode_sequence_of_krb_cred_info
+asn1_encode_sequence_of_pa_data
+asn1_encode_sequence_of_passwdsequence
+asn1_encode_sequence_of_ticket
+asn1_encode_ticket
+asn1_encode_ticket_flags
+asn1_encode_transited_encoding
+asn1_encode_ui_4
+asn1_encode_unsigned_integer
+asn1_get_sequence
+asn1_get_tag_2
+asn1_krb5_realm_copy
+asn1_make_etag
+asn1_make_id
+asn1_make_length
+asn1_make_sequence
+asn1_make_set
+asn1_make_string
+asn1_make_tag
+asn1buf_create
+asn1buf_destroy
+asn1buf_ensure_space
+asn1buf_expand
+asn1buf_free
+asn1buf_hex_unparse
+asn1buf_imbed
+asn1buf_insert_charstring
+asn1buf_insert_octet
+asn1buf_insert_octetstring
+asn1buf_len
+asn1buf_remains
+asn1buf_remove_charstring
+asn1buf_remove_octet
+asn1buf_remove_octetstring
+asn1buf_size
+asn1buf_skiptail
+asn1buf_sync
+asn1buf_unparse
+asn1buf_wrap_data
+decode_krb5_alt_method
+decode_krb5_ap_rep
+decode_krb5_ap_rep_enc_part
+decode_krb5_ap_req
+decode_krb5_as_rep
+decode_krb5_as_req
+decode_krb5_authdata
+decode_krb5_authenticator
+decode_krb5_cred
+decode_krb5_enc_cred_part
+decode_krb5_enc_data
+decode_krb5_enc_kdc_rep_part
+decode_krb5_enc_priv_part
+decode_krb5_enc_sam_key
+decode_krb5_enc_sam_response_enc
+decode_krb5_enc_sam_response_enc_2
+decode_krb5_enc_tkt_part
+decode_krb5_encryption_key
+decode_krb5_error
+decode_krb5_etype_info
+decode_krb5_etype_info2
+decode_krb5_kdc_req_body
+decode_krb5_pa_enc_ts
+decode_krb5_padata_sequence
+decode_krb5_predicted_sam_response
+decode_krb5_priv
+decode_krb5_pwd_data
+decode_krb5_pwd_sequence
+decode_krb5_safe
+decode_krb5_safe_with_body
+decode_krb5_sam_challenge
+decode_krb5_sam_challenge_2
+decode_krb5_sam_challenge_2_body
+decode_krb5_sam_response
+decode_krb5_sam_response_2
+decode_krb5_tgs_rep
+decode_krb5_tgs_req
+decode_krb5_ticket
+encode_krb5_alt_method
+encode_krb5_ap_rep
+encode_krb5_ap_rep_enc_part
+encode_krb5_ap_req
+encode_krb5_as_rep
+encode_krb5_as_req
+encode_krb5_authdata
+encode_krb5_authenticator
+encode_krb5_cred
+encode_krb5_enc_cred_part
+encode_krb5_enc_data
+encode_krb5_enc_kdc_rep_part
+encode_krb5_enc_priv_part
+encode_krb5_enc_sam_response_enc
+encode_krb5_enc_sam_response_enc_2
+encode_krb5_enc_tkt_part
+encode_krb5_encryption_key
+encode_krb5_error
+encode_krb5_etype_info
+encode_krb5_etype_info2
+encode_krb5_kdc_req_body
+encode_krb5_pa_enc_ts
+encode_krb5_padata_sequence
+encode_krb5_predicted_sam_response
+encode_krb5_priv
+encode_krb5_pwd_data
+encode_krb5_pwd_sequence
+encode_krb5_safe
+encode_krb5_safe_with_body
+encode_krb5_sam_challenge
+encode_krb5_sam_challenge_2
+encode_krb5_sam_challenge_2_body
+encode_krb5_sam_key
+encode_krb5_sam_response
+encode_krb5_sam_response_2
+encode_krb5_setpw_req
+encode_krb5_tgs_rep
+encode_krb5_tgs_req
+encode_krb5_ticket
+et_asn1_error_table
+et_k524_error_table
+et_kdb5_error_table
+et_krb5_error_table
+et_kv5m_error_table
+et_prof_error_table
+gmt_mktime
+initialize_asn1_error_table
+initialize_k524_error_table
+initialize_kdb5_error_table
+initialize_krb5_error_table
+initialize_kv5m_error_table
+initialize_prof_error_table
+krb524_convert_creds_kdc
+krb524_init_ets
+krb5_425_conv_principal
+krb5_524_conv_principal
+krb5_524_convert_creds
+krb5_address_compare
+krb5_address_order
+krb5_address_search
+krb5_aname_to_localname
+krb5_appdefault_boolean
+krb5_appdefault_string
+krb5_auth_con_free
+krb5_auth_con_genaddrs
+krb5_auth_con_get_checksum_func
+krb5_auth_con_getaddrs
+krb5_auth_con_getauthenticator
+krb5_auth_con_getflags
+krb5_auth_con_getivector
+krb5_auth_con_getkey
+krb5_auth_con_getlocalseqnumber
+krb5_auth_con_getlocalsubkey
+krb5_auth_con_getpermetypes
+krb5_auth_con_getrcache
+krb5_auth_con_getrecvsubkey
+krb5_auth_con_getremoteseqnumber
+krb5_auth_con_getremotesubkey
+krb5_auth_con_getsendsubkey
+krb5_auth_con_init
+krb5_auth_con_initivector
+krb5_auth_con_set_checksum_func
+krb5_auth_con_set_req_cksumtype
+krb5_auth_con_set_safe_cksumtype
+krb5_auth_con_setaddrs
+krb5_auth_con_setflags
+krb5_auth_con_setivector
+krb5_auth_con_setpermetypes
+krb5_auth_con_setports
+krb5_auth_con_setrcache
+krb5_auth_con_setrecvsubkey
+krb5_auth_con_setsendsubkey
+krb5_auth_con_setuseruserkey
+krb5_auth_to_rep
+krb5_build_principal
+krb5_build_principal_ext
+krb5_build_principal_va
+krb5_cc_close
+krb5_cc_copy_creds
+krb5_cc_default
+krb5_cc_default_name
+krb5_cc_destroy
+krb5_cc_dfl_ops
+krb5_cc_end_seq_get
+krb5_cc_file_ops
+krb5_cc_gen_new
+krb5_cc_get_name
+krb5_cc_get_principal
+krb5_cc_get_type
+krb5_cc_initialize
+krb5_cc_next_cred
+krb5_cc_register
+krb5_cc_remove_cred
+krb5_cc_resolve
+krb5_cc_retrieve_cred
+krb5_cc_retrieve_cred_default
+krb5_cc_set_default_name
+krb5_cc_set_flags
+krb5_cc_start_seq_get
+krb5_cc_store_cred
+krb5_change_cache
+krb5_change_password
+krb5_change_set_password
+krb5_check_transited_list
+krb5_chpw_result_code_string
+krb5_copy_addr
+krb5_copy_addresses
+krb5_copy_authdata
+krb5_copy_authenticator
+krb5_copy_checksum
+krb5_copy_creds
+krb5_copy_data
+krb5_copy_keyblock
+krb5_copy_keyblock_contents
+krb5_copy_principal
+krb5_copy_ticket
+krb5_create_secure_file
+krb5_crypto_us_timeofday
+krb5_decode_kdc_rep
+krb5_decode_ticket
+krb5_decrypt_tkt_part
+krb5_default_pwd_prompt1
+krb5_default_pwd_prompt2
+krb5_defkeyname
+krb5_deltat_to_string
+krb5_do_preauth
+krb5_encode_kdc_rep
+krb5_encrypt_helper
+krb5_encrypt_tkt_part
+krb5_externalize_data
+krb5_externalize_opaque
+krb5_fcc_ops
+krb5_find_serializer
+krb5_free_address
+krb5_free_addresses
+krb5_free_ap_rep
+krb5_free_ap_rep_enc_part
+krb5_free_ap_req
+krb5_free_authdata
+krb5_free_authenticator
+krb5_free_authenticator_contents
+krb5_free_checksum
+krb5_free_checksum_contents
+krb5_free_config_files
+krb5_free_context
+krb5_free_cred
+krb5_free_cred_contents
+krb5_free_cred_enc_part
+krb5_free_creds
+krb5_free_data
+krb5_free_data_contents
+krb5_free_default_realm
+krb5_free_enc_kdc_rep_part
+krb5_free_enc_sam_response_enc
+krb5_free_enc_sam_response_enc_2
+krb5_free_enc_sam_response_enc_2_contents
+krb5_free_enc_sam_response_enc_contents
+krb5_free_enc_tkt_part
+krb5_free_error
+krb5_free_etype_info
+krb5_free_host_realm
+krb5_free_kdc_rep
+krb5_free_kdc_req
+krb5_free_keyblock
+krb5_free_keyblock_contents
+krb5_free_keytab_entry_contents
+krb5_free_krbhst
+krb5_free_ktypes
+krb5_free_last_req
+krb5_free_pa_data
+krb5_free_pa_enc_ts
+krb5_free_predicted_sam_response
+krb5_free_predicted_sam_response_contents
+krb5_free_principal
+krb5_free_priv
+krb5_free_priv_enc_part
+krb5_free_pwd_data
+krb5_free_pwd_sequences
+krb5_free_realm_string
+krb5_free_realm_tree
+krb5_free_safe
+krb5_free_sam_challenge
+krb5_free_sam_challenge_2
+krb5_free_sam_challenge_2_body
+krb5_free_sam_challenge_2_body_contents
+krb5_free_sam_challenge_2_contents
+krb5_free_sam_challenge_contents
+krb5_free_sam_response
+krb5_free_sam_response_2
+krb5_free_sam_response_2_contents
+krb5_free_sam_response_contents
+krb5_free_tgt_creds
+krb5_free_ticket
+krb5_free_tickets
+krb5_free_tkt_authent
+krb5_free_unparsed_name
+krb5_fwd_tgt_creds
+krb5_gen_portaddr
+krb5_gen_replay_name
+krb5_generate_seq_number
+krb5_generate_subkey
+krb5_get_cred_from_kdc
+krb5_get_cred_from_kdc_renew
+krb5_get_cred_from_kdc_validate
+krb5_get_cred_via_tkt
+krb5_get_credentials
+krb5_get_credentials_renew
+krb5_get_credentials_validate
+krb5_get_default_config_files
+krb5_get_default_in_tkt_ktypes
+krb5_get_default_realm
+krb5_get_host_realm
+krb5_get_in_tkt
+krb5_get_in_tkt_with_keytab
+krb5_get_in_tkt_with_password
+krb5_get_in_tkt_with_skey
+krb5_get_init_creds
+krb5_get_init_creds_keytab
+krb5_get_init_creds_opt_init
+krb5_get_init_creds_opt_set_address_list
+krb5_get_init_creds_opt_set_etype_list
+krb5_get_init_creds_opt_set_forwardable
+krb5_get_init_creds_opt_set_preauth_list
+krb5_get_init_creds_opt_set_proxiable
+krb5_get_init_creds_opt_set_renew_life
+krb5_get_init_creds_opt_set_salt
+krb5_get_init_creds_opt_set_tkt_life
+krb5_get_init_creds_password
+krb5_get_krbhst
+krb5_get_notification_message
+krb5_get_permitted_enctypes
+krb5_get_profile
+krb5_get_prompt_types
+krb5_get_realm_domain
+krb5_get_renewed_creds
+krb5_get_server_rcache
+krb5_get_tgs_ktypes
+krb5_get_time_offsets
+krb5_get_validated_creds
+krb5_init_context
+krb5_init_keyblock
+krb5_init_secure_context
+krb5_internalize_opaque
+krb5_is_permitted_enctype
+krb5_is_thread_safe
+krb5_kdc_rep_decrypt_proc
+krb5_kt_add_entry
+krb5_kt_close
+krb5_kt_default
+krb5_kt_default_name
+krb5_kt_dfl_ops
+krb5_kt_end_seq_get
+krb5_kt_free_entry
+krb5_kt_get_entry
+krb5_kt_get_name
+krb5_kt_get_type
+krb5_kt_next_entry
+krb5_kt_read_service_key
+krb5_kt_register
+krb5_kt_remove_entry
+krb5_kt_resolve
+krb5_kt_start_seq_get
+krb5_ktf_ops
+krb5_ktf_writable_ops
+krb5_ktfile_add
+krb5_ktfile_close
+krb5_ktfile_end_get
+krb5_ktfile_get_entry
+krb5_ktfile_get_name
+krb5_ktfile_get_next
+krb5_ktfile_remove
+krb5_ktfile_resolve
+krb5_ktfile_ser_entry
+krb5_ktfile_start_seq_get
+krb5_ktfile_wresolve
+krb5_ktfileint_close
+krb5_ktfileint_delete_entry
+krb5_ktfileint_find_slot
+krb5_ktfileint_internal_read_entry
+krb5_ktfileint_openr
+krb5_ktfileint_openw
+krb5_ktfileint_read_entry
+krb5_ktfileint_size_entry
+krb5_ktfileint_write_entry
+krb5_kts_ops
+krb5_kuserok
+krb5_libdefault_boolean
+krb5_locate_kdc
+krb5_lock_file
+krb5_make_full_ipaddr
+krb5_make_fulladdr
+krb5_max_dgram_size
+krb5_max_skdc_timeout
+krb5_mcc_ops
+krb5_mk_1cred
+krb5_mk_error
+krb5_mk_ncred
+krb5_mk_priv
+krb5_mk_rep
+krb5_mk_req
+krb5_mk_req_extended
+krb5_mk_safe
+krb5_net_read
+krb5_net_write
+krb5_obtain_padata
+krb5_os_free_context
+krb5_os_hostaddr
+krb5_os_init_context
+krb5_os_localaddr
+krb5_overridekeyname
+krb5_parse_name
+krb5_principal2salt
+krb5_principal2salt_norealm
+krb5_principal_compare
+krb5_process_padata
+krb5_prompter_posix
+krb5_rc_close
+krb5_rc_default
+krb5_rc_default_name
+krb5_rc_default_type
+krb5_rc_destroy
+krb5_rc_dfl_close
+krb5_rc_dfl_close_no_free
+krb5_rc_dfl_destroy
+krb5_rc_dfl_expunge
+krb5_rc_dfl_get_name
+krb5_rc_dfl_get_span
+krb5_rc_dfl_init
+krb5_rc_dfl_ops
+krb5_rc_dfl_recover
+krb5_rc_dfl_resolve
+krb5_rc_dfl_store
+krb5_rc_expunge
+krb5_rc_free_entry
+krb5_rc_get_lifespan
+krb5_rc_get_name
+krb5_rc_get_type
+krb5_rc_initialize
+krb5_rc_io_close
+krb5_rc_io_creat
+krb5_rc_io_destroy
+krb5_rc_io_mark
+krb5_rc_io_move
+krb5_rc_io_open
+krb5_rc_io_read
+krb5_rc_io_size
+krb5_rc_io_sync
+krb5_rc_io_unmark
+krb5_rc_io_write
+krb5_rc_recover
+krb5_rc_register_type
+krb5_rc_resolve
+krb5_rc_resolve_full
+krb5_rc_resolve_type
+krb5_rc_store
+krb5_rd_cred
+krb5_rd_error
+krb5_rd_priv
+krb5_rd_rep
+krb5_rd_req
+krb5_rd_req_decoded
+krb5_rd_req_decoded_anyflag
+krb5_rd_safe
+krb5_read_message
+krb5_read_password
+krb5_realm_compare
+krb5_realm_iterator
+krb5_realm_iterator_create
+krb5_realm_iterator_free
+krb5_recvauth
+krb5_recvauth_version
+krb5_register_serializer
+krb5_salttype_to_string
+krb5_secure_config_files
+krb5_send_tgs
+krb5_sendauth
+krb5_sendto_kdc
+krb5_ser_address_init
+krb5_ser_auth_context_init
+krb5_ser_authdata_init
+krb5_ser_authenticator_init
+krb5_ser_ccache_init
+krb5_ser_checksum_init
+krb5_ser_context_init
+krb5_ser_keyblock_init
+krb5_ser_keytab_init
+krb5_ser_pack_bytes
+krb5_ser_pack_int32
+krb5_ser_pack_int64
+krb5_ser_principal_init
+krb5_ser_rcache_init
+krb5_ser_unpack_bytes
+krb5_ser_unpack_int32
+krb5_ser_unpack_int64
+krb5_set_config_files
+krb5_set_debugging_time
+krb5_set_default_in_tkt_ktypes
+krb5_set_default_realm
+krb5_set_default_tgs_enctypes
+krb5_set_default_tgs_ktypes
+krb5_set_password
+krb5_set_password_using_ccache
+krb5_set_principal_realm
+krb5_set_real_time
+krb5_set_time_offsets
+krb5_size_opaque
+krb5_skdc_timeout_1
+krb5_skdc_timeout_shift
+krb5_sname_to_principal
+krb5_string_to_deltat
+krb5_string_to_salttype
+krb5_string_to_timestamp
+krb5_sync_disk_file
+krb5_tgtname
+krb5_timeofday
+krb5_timestamp_to_sfstring
+krb5_timestamp_to_string
+krb5_try_realm_txt_rr
+krb5_unlock_file
+krb5_unpack_full_ipaddr
+krb5_unparse_name
+krb5_unparse_name_ext
+krb5_us_timeofday
+krb5_use_natural_time
+krb5_validate_times
+krb5_verify_init_creds
+krb5_verify_init_creds_opt_init
+krb5_verify_init_creds_opt_set_ap_req_nofail
+krb5_walk_realm_tree
+krb5_write_message
+krb5int_524_sendto_kdc
+krb5int_accessor
+krb5int_add_host_to_list
+krb5int_auth_con_chkseqnum
+krb5int_cc_creds_match_request
+krb5int_cc_default
+krb5int_cleanup_library
+krb5int_cm_call_select
+krb5int_copy_data_contents
+krb5int_foreach_localaddr
+krb5int_free_addrlist
+krb5int_free_srv_dns_data
+krb5int_generate_and_save_subkey
+krb5int_get_fq_local_hostname
+krb5int_grow_addrlist
+krb5int_initialize_library
+krb5int_krb_life_to_time
+krb5int_krb_time_to_life
+krb5int_local_addresses
+krb5int_locate_server
+krb5int_make_srv_query_realm
+krb5int_mk_chpw_req
+krb5int_mk_setpw_req
+krb5int_populate_gic_opt
+krb5int_rd_chpw_rep
+krb5int_rd_setpw_rep
+krb5int_sendto
+krb5int_sendtokdc_debug_handler
+krb5int_set_prompt_types
+krb5int_setpw_result_code_string
+krb5int_translate_gai_error
+os_get_default_config_files
+profile_abandon
+profile_add_node
+profile_add_relation
+profile_clear_relation
+profile_close_file
+profile_create_node
+profile_dereference_data
+profile_find_node
+profile_find_node_relation
+profile_find_node_subsection
+profile_flush
+profile_flush_file_data
+profile_free_file
+profile_free_list
+profile_free_node
+profile_get_boolean
+profile_get_integer
+profile_get_node_name
+profile_get_node_parent
+profile_get_node_value
+profile_get_relation_names
+profile_get_string
+profile_get_subsection_names
+profile_get_value
+profile_get_values
+profile_init
+profile_init_path
+profile_is_node_final
+profile_iterator
+profile_iterator_create
+profile_iterator_free
+profile_make_node_final
+profile_node_iterator
+profile_node_iterator_create
+profile_node_iterator_free
+profile_open_file
+profile_parse_file
+profile_release
+profile_release_string
+profile_remove_node
+profile_rename_node
+profile_rename_section
+profile_ser_externalize
+profile_ser_internalize
+profile_ser_size
+profile_set_relation_value
+profile_update_file_data
+profile_update_relation
+profile_verify_node
+profile_write_tree_file
diff --git a/mechglue/src/lib/krb5/os/.Sanitize b/mechglue/src/lib/krb5/os/.Sanitize
new file mode 100644
index 000000000..111d6789a
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/.Sanitize
@@ -0,0 +1,79 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+DNR.c
+Makefile.in
+an_to_ln.c
+ccdefname.c
+configure
+configure.in
+def_realm.c
+free_hstrl.c
+free_krbhs.c
+full_ipadr.c
+genaddrs.c
+gen_port.c
+gen_rname.c
+get_krbhst.c
+gmt_mktime.c
+hostaddr.c
+hst_realm.c
+init_os_ctx.c
+krbfileio.c
+ktdefname.c
+kuserok.c
+localaddr.c
+locate_kdc.c
+lock_file.c
+mk_faddr.c
+net_read.c
+net_write.c
+os-proto.h
+osconfig.c
+promptusr.c
+port2ip.c
+read_msg.c
+read_pwd.c
+realm_dom.c
+ref_std_conf.out
+send524.c
+sendto_kdc.c
+sn2princ.c
+timeofday.c
+t_std_conf.c
+t_an_to_ln.c
+td_krb5.conf
+toffset.c
+unlck_file.c
+ustime.c
+write_msg.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/os/ChangeLog b/mechglue/src/lib/krb5/os/ChangeLog
new file mode 100644
index 000000000..6e35592cb
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/ChangeLog
@@ -0,0 +1,3022 @@
+2005-11-14  Jeffrey Altman <jaltman@mit.edu>
+
+	* toffset.c:  (krb5_set_real_time, krb5_set_debugging_time, 
+                       krb5_get_time_offsets, krb5_set_time_offsets)
+        * timeofday.c:(krb5_timeofday)
+        * ustime.c:   (krb5_us_timeofday)
+
+        Change type of "seconds" parameter from krb5_int32 to krb5_timestamp
+        This does not alter the ABI on existing platforms but will provide
+        consistency when we need to consider changing krb5_timestamp to a
+        64-bit value.
+
+2005-09-16  Tom Yu  <tlyu@mit.edu>
+
+	* dnsglue.c (USE_RES_NINIT): Fix braino: define to 1, not empty
+	string.
+
+2005-09-08  Tom Yu  <tlyu@mit.edu>
+
+	* dnsglue.c: Implement better logic for choosing whether to use
+	res_ninit().  If res_ndestroy() doesn't exist, assume that
+	res_ninit() is broken and use res_init(), res_search(),
+	etc. instead, on the theory that the OS vendor has made the older
+	interfaces thread-safe.
+
+2005-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (service_fds): Don't create a select_state on the
+	stack; take an additional argument pointing to it.
+	(krb5int_sendto): Don't create a select_state on the stack;
+	instead, allocate two on the heap, passing the second as the new
+	argument to service_fds.
+
+2005-04-22  Jeffrey Altman <jaltman@mit.edu>
+
+        * init_os_ctx.c:  use krb5_init_ctx and krb5_free_ctx
+        to initialize and cleanup the winsock stack.  WSAStartup/
+        WSACleanup are only supposed to increment/decrement a 
+        reference counter if they have been previously called
+        within the application.
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* accessor.c (NEED_SOCKETS): Don't define.
+	* c_ustime.c (NEED_SOCKETS): Don't define.
+	* changepw.c (NEED_SOCKETS): Don't define.
+	* dnsglue.h (NEED_SOCKETS): Don't define.
+	* full_ipadr.c (NEED_SOCKETS): Don't define.
+	* gen_rname.c (NEED_SOCKETS): Don't define.
+	* genaddrs.c (NEED_SOCKETS): Don't define.
+	* hostaddr.c (NEED_SOCKETS): Don't define.
+	* hst_realm.c (NEED_SOCKETS): Don't define.
+	* krbfileio.c (NEED_LOWLEVEL_IO): Don't define.
+	* localaddr.c (NEED_SOCKETS): Don't define.
+	* locate_kdc.c (NEED_SOCKETS): Don't define.
+	* mk_faddr.c (NEED_SOCKETS): Don't define.
+	* net_read.c (NEED_SOCKETS, NEED_LOWLEVEL_IO): Don't define.
+	* net_write.c (NEED_SOCKETS, NEED_LOWLEVEL_IO): Don't define.
+	* port2ip.c (NEED_SOCKETS): Don't define.
+	* read_msg.c (NEED_SOCKETS): Don't define.
+	* send524.c (NEED_SOCKETS, NEED_LOWLEVEL_IO): Don't define.
+	* sendto_kdc.c (NEED_SOCKETS, NEED_LOWLEVEL_IO): Don't define.
+	* sn2princ.c (NEED_SOCKETS): Don't define.
+	* write_msg.c (NEED_SOCKETS): Don't define.
+
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* kuserok.c (krb5_kuserok): Use k5_getpwnam_r.
+
+2005-03-22  Tom Yu  <tlyu@mit.edu>
+
+	* dnsglue.h: Define ns_rr_class to ns_rr_cl if ns_rr_class doesn't
+	exist.
+
+2005-03-05  Jeffrey Altman <jaltman@mit.edu>
+
+        * sn2princ.c (krb5_sname_to_principal):
+          conditionalize the use of reverse dns lookups.  The default
+          is to use the existing behavior.  rdns can be disabled by
+          specifying [libdefaults] rdns=false
+
+2005-01-12  Tom Yu  <tlyu@mit.edu>
+
+	* dnsglue.c (krb5int_dns_fini): Reorder to make more correct.
+	(krb5int_dns_init): Rework error handling.  Call res_ndestroy() or
+	res_nclose() as appropriate to avoid leaking resources allocated
+	by res_ninit().
+
+2005-01-03  Jeffrey Altman <jaltman@mit.edu>
+
+        * thread_safe.c: (new file) krb5_is_thread_safe()
+
+2004-12-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* accessor.c (krb5int_accessor): Set new field use_dns_kdc.
+
+2004-12-06  Tom Yu  <tlyu@mit.edu>
+
+	* locate_kdc.c (krb5_locate_srv_dns_1): Don't compile if
+	KRB5_DNS_LOOKUP is not defined.
+
+2004-11-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (krb5int_add_host_to_list): If debugging, log the
+	requested family and socket type.  If AI_NUMERICSERV is defined,
+	set it in ai_flags.  If getaddrinfo returns an error with
+	debugging enabled, log the error.
+	(krb5_locate_srv_conf_1): When logging an error from
+	add_host_to_list, include the corresponding error string.
+
+	* t_locate_kdc.c: Include port-sockets.h, instead of sys/socket.h,
+	netdb.h, netinet/in.h, and arpa/inet.h.
+	* Makefile.in ($(OUTPRE)t_locate_kdc.exe): New target.
+
+2004-10-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c: Include stdarg.h.
+	(Tprintf): New function, prints to stderr or not depending on TEST
+	macro.
+	(add_addrinfo_to_list, krb5int_add_host_to_list,
+	krb5_locate_srv_conf_1, krb5_locate_srv_dns_1,
+	krb5int_locate_server): Call it instead of conditionally calling
+	fprintf.
+
+2004-10-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* dnssrv.c (krb5int_make_srv_query_realm): Append a dot to the
+	hostname, if there's room in the buffer, to avoid domain search
+	paths.
+
+2004-10-19  Tom Yu  <tlyu@mit.edu>
+
+	* dnsglue.c (initparse): Skip query type and class when we lack
+	ns_initparse().
+	(krb5int_dns_nextans) [!HAVE_NS_INITPARSE]: Pass correct pointer
+	to dn_skipname().  Actually skip the RR name.
+
+2004-10-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (TEST_PROGS): Add t_locate_kdc.
+	(check-unix): Run t_locate_kdc to test fetching DNS SRV records.
+	(EXTRADEPSRCS): Define.
+
+2004-10-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (foreach_localaddr): Be more careful not to walk
+	past the end of the ifreq array.
+	(get_ifreq_array): Return 0 in success case, not errno.
+	(print_addr): If getnameinfo returns EAI_SYSTEM, report what the
+	system error is.
+
+	* localaddr.c (get_ifreq_array): Split out from foreach_localaddr
+	general version.
+	(foreach_localaddr): Call it.
+
+2004-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (foreach_localaddr) [HAVE_STRUCT_IF_LADDRCONF && 0]:
+	Fix if_laddrreq.iflr_name field name not properly adjusted.  The
+	iflr_addr field is an HP-UX specific sockaddr_ext with sa_ field
+	name prefixes.
+
+2004-10-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (get_if_laddrconf, foreach_localaddr): New
+	implementation for HP-UX 11, based on Solaris support and
+	information from Doug Engert.  Disabled for now, until it can be
+	tested.
+
+2004-09-30  Jeffrey Altman <jaltman@mit.edu>
+
+        * hst_realm.c: provide definition for MAXDNAME if 
+          KRB5_DNS_LOOKUP is not defined.
+
+2004-09-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (T_STD_CONF_OBJS): Include dnsglue.o.
+
+2004-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* dnsglue.c: Conditionalize some stuff on ns_initparse() instead
+	of assuming that the presence of res_nsearch() means
+	ns_initparse() is available.
+
+2004-09-20  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Add dnsglue.c.
+
+	* dnsglue.c: New file.  Implement resolver glue layer to abstract
+	away the details of calling res_search or res_nsearch, and of
+	parsing the reply packet.
+
+	* dnsglue.h: New file.
+
+	* dnssrv.c (krb5int_make_srv_query_realm): Use dnsglue.  Use
+	MAXDNAME from dnsglue.h or resolv.h instead of MAX_DNS_NAMELEN.
+
+	* hst_realm.c (krb5_try_realm_txt_rr): Use dnsglue.  Use MAXDNAME
+	from dnsglue.h or resolv.h instead of MAX_DNS_NAMELEN.
+
+2004-09-13  Tom Yu  <tlyu@mit.edu>
+
+	* dnssrv.c: 
+	* hst_realm.c: 
+	* locate_kdc.c: Include netinet/in.h as a prerequisite for
+	resolv.h.
+
+2004-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (start_connection) [DEBUG]: Log the local socket
+	address.
+
+2004-08-12  Alexandra Ellwood  <lxs@mit.edu>
+
+        * ccdefname.c (krb5_cc_set_default_name, krb5_cc_default_name):
+        Look up the default ccache name in krb5_cc_default_name, not
+        krb5_cc_set_default_name so that krb5_init_context doesn't
+        have to do work it might never use.
+
+2004-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (get_lifconf): Define only if "struct lifconf" is
+	available.
+	(foreach_localaddr): Use get_lifconf only if "struct lifconf" is
+	available.
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* genaddrs.c, localaddr.c, lock_file.c, mk_faddr.c: Don't check
+	for macsock.h.
+
+2004-07-15  Alexandra Ellwood  <lxs@mit.edu>
+
+	* init_os_ctx.c (krb5_os_init_context, krb5_os_free_context) 
+          ccdefname.c (krb5_cc_set_default_name):
+        Removed default_ccprincipal field from krb5_context
+
+2004-07-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* dnssrv.c (krb5int_make_srv_query_realm) [HAVE_RES_NSEARCH]: Use
+	res_nsearch instead of res_search.
+	* hst_realm.c (krb5_try_realm_txt_rr) [HAVE_RES_NSEARCH]:
+	Likewise.
+
+2004-07-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* an_to_ln.c: Include string.h.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* an_to_ln.c (db_an_to_ln): Don't test macintosh.
+	* krbfileio.c (krb5_sync_disk_file): Likewise.
+	* kuserok.c: Likewise.
+	* prompter.c: Likewise.
+	* promptusr.c: Likewise.
+	* read_pwd.c: Likewise.
+
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* c_ustime.c: Include k5-thread.h.
+	(get_time_now): New function, holds system-dependent code.
+	(krb5int_us_time_mutex): New mutex.
+	(struct time_now): New type.
+	(last_time): New variable, replaces old last_tv, last_sec,
+	last_usec.
+	(krb5_crypto_us_timeofday): Rewrite.  Do locking around access to
+	previously returned value, and ensure that we don't return
+	duplicate values.
+	* os-proto.h: Include k5-thread.h.
+	(krb5int_us_time_mutex): Declare.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* kuserok.c (krb5_kuserok): Handle draft POSIX versions of
+	getpwnam_r.
+
+2004-06-02  Tom Yu  <tlyu@mit.edu>
+
+	* an_to_ln.c (do_replacement): Patch from Bill Dodd to fix missing
+	braces in previous security patch.
+
+2004-06-01  Sam Hartman  <hartmans@mit.edu>
+
+	* an_to_ln.c (rule_an_to_ln): Fix buffer overflow when parsing
+	principal names into components. 
+	(do_replacement): likewise
+	(aname_replacer): Support error return from do_replacement
+
+2004-05-07  Sam Hartman  <hartmans@mit.edu>
+
+	* an_to_ln.c: Patch from Matt Crawford  to allow matching on
+	realms of cross-realm principals.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c: Incorporate foreach_localaddr implementation.
+	Export it as krb5int_foreach_localaddr.  Include foreachaddr.h,
+	not foreachaddr.c.
+
+2004-03-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (krb5int_sendto): Initialize select_state.end_time.
+	(get_so_error): New function.
+	(service_tcp_fd): Call it for write fds as well as exception fds.
+
+2004-03-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* sendto_kdc.c (krb5_sendto_kdc): Change passing pointer to value of
+	use_master parameter to krb5_locate_kdc.
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* lock_file.c (krb5_lock_file): Initialize flock data on entry,
+	but don't bother with a static version to copy from.
+
+2004-02-26  Jeffrey Altman <jaltman@mit.edu>
+
+    * sendto_kdc.c, send524.c:
+      The use_master parameter of sendto_kdc is now an in/out 
+      parameter used to report to the caller whether or not
+      the responding KDC was in fact the master.  This is 
+      necessary to allow callers to prevent making an unnecessary
+      additional call to query the master if the original 
+      query did not explicitly state that the master should be 
+      queried.
+
+2004-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (start_connection): Close socket if connect() call
+	fails for an unexpected reason.
+
+2004-02-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* genaddrs.c: Don't specify defaults for
+	GET{PEER,SOCK}NAME_ARG{2,3}_TYPE macros.
+
+2004-02-09  Sam Hartman  <hartmans@mit.edu>
+
+	* changepw.c (krb5_locate_kpasswd): Run htons on the default port
+
+2003-12-22  Jeffrey Altman <jaltman@mit.edu>
+
+    * dnssrv.c:  wrap within #ifdef KRB5_DNS_LOOKUP to prevent references
+      to resolver functions when DNS support is not being compiled 
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* realm_iter.c (krb5_realm_iterator_create): Array NAMES is now
+	const.
+
+	* prompter.c (catch_signals, restore_signals): Take pointer to old
+	signal handler info as new argument.
+	(osiginfo): New typedef.
+	(setup_tty, restore_tty): Take pointer to old signal handler info
+	and old termios settings as new arguments.
+	(krb5_prompter_posix): Pass the extra arguments, addresses of new
+	automatic variables.
+	(osigint, saveparm): Variables deleted.
+
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Don't build promptusr.c.
+
+	* sendto_kdc.c (default_debug_handler, put, putstr): Define only
+	if DEBUG is defined.
+	(DEBUG): Don't define.
+	(krb5int_sendtokdc_debug_handler): Initialize to null if DEBUG is
+	not defined.
+
+2003-12-18  Jeffrey Altman <jaltman@mit.edu>
+
+    * accessor.c: Add new functions for use by gssapi
+
+2003-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* an_to_ln.c (krb5_aname_to_localname): Don't write one byte past
+	the end of a string.  Found by Christopher Nebergall.
+
+2003-10-27  Jeffrey Altman <jaltman@mit.edu>
+
+    * sendto_kdc.c: sockets must be closed with closesocket() and 
+      and not close() in order to ensure portability among different
+      operating systems.
+
+2003-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* dnssrv.c: New file; split out DNS SRV RR query support...
+	* locate_kdc.c: ...from here.  Always compile in the calls.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Add it.
+
+2003-07-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Always pass 0 to locate_server
+	as the get_masters argument.  Instead, if get_masters is set,
+	look up "master_kdc" in the config file instead of "kdc".
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-07-09  Alexandra Ellwood  <lxs@mit.edu>
+
+        * toffset.c: Export krb5_set_real_time for Samba.
+
+2003-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (struct srv_dns_entry): Moved to k5-int.h.
+	(krb5int_make_srv_query_realm): Renamed from make_srv_query_realm.
+	(krb5int_free_srv_dns_data): New function.
+	(krb5_locate_srv_dns_1): Use it.
+
+	* accessor.c (krb5int_accessor): Fill in make_srv_query_realm and
+	free_srv_dns_data fields.
+
+2003-06-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (make_srv_query_realm): Punt if strdup fails.
+	Always return what data we can, even if memory allocation or other
+	problems prevent us from returning more.
+	(krb5_locate_srv_dns_1): Always return what data we can.  Fix
+	memory leak.  Free up temporary storage as quickly as possible,
+	while building up address list to return.
+
+2003-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* accessor.c (krb5int_accessor): Initialize restored locate_server
+	field.
+
+	* locate_kdc.c (struct srv_dns_entry): Move to top level.
+	(make_srv_query_realm): Separate from krb5_locate_srv_dns_1; just
+	do query and return results.
+	(krb5_locate_srv_dns_1): Call it, and build addlist entries.
+	Check for one RR with a target of ".", and return an error.
+	(krb5_locate_srv_dns): Deleted.
+
+	* t_locate_kdc.c (main): Call krb5_locate_srv_dns_1.
+
+	* changepw.c (krb5_locate_kpasswd): Check specifically for certain
+	errors before using fallback heuristics.
+
+2003-06-03  Alexandra Ellwood  <lxs@mit.edu>
+
+        * init_os_ctx.c: Included header to get __KLAllowHomeDirectoryAccess().
+
+2003-05-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* send524.c (krb5int_524_sendto_kdc): Enable support on Windows
+	always.
+
+2003-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* send524.c: New file, moved from krb524/sendmsg.c.  Rename
+	function to have krb5int_ prefix.  If KRB5_KRB4_COMPAT not
+	defined, return an error.
+	* accessor.c (krb5int_accessor): Update for deleted and added
+	fields.  If KRB5_KRB4_COMPAT is not defined, just use null
+	pointers for the new fields.
+
+2003-05-06  Alexandra Ellwood  <lxs@mit.edu>
+
+        * init_os_ctx.c: Added support for KLL's __KLAllowHomeDirectoryAccess()
+        function so that krb4, krb5 and gssapi will not access the user's homedir
+        if the application forbids it.
+
+2003-04-28  Sam Hartman  <hartmans@mit.edu>
+
+	* changepw.c (krb5_change_set_password): Locate server in realm of
+	creds.server, not in realm of target principal because target
+	principal is null in the  changepw case.
+
+2003-04-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_os_ctx.c (krb5_os_init_context, krb5_os_free_context):
+	Don't allocate or free the os_context, since it's now a direct
+	member of the krb5_context, not separately allocated storage.
+
+2003-04-27  Sam Hartman  <hartmans@mit.edu>
+
+	* changepw.c (krb5_change_set_password): Call
+	krb5_setpw_result_code_string not krb5_setpw_result_code_string  
+
+2003-04-24  Sam Hartman  <hartmans@mit.edu>
+
+	* changepw.c (krb5_change_set_password): return error from
+	auth_con_setaddrs not last socket errno if auth_con_setaddrs fails 
+
+2003-04-15  Sam Hartman  <hartmans@mit.edu>
+
+	* changepw.c (krb5_change_set_password): Patches from Paul Nelson
+	to implement Microsoft set password protocol  
+	(krb5_set_password_using_ccache): Use kadmin/changepw in target realm, not local realm and use a two-component principal
+	(krb5_change_set_password): Find the kpasswd server for the realm
+	of the target principal not the client 
+
+2003-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* read_pwd.c (krb5_read_password): Always free temporary storage
+	used for verification version of password.
+
+2003-03-06  Alexandra Ellwood <lxs@mit.edu>
+
+    * c_ustime.c: Removed Mac OS 9 code.
+    
+    * ccdefname.c: Conditionalize on USE_CCAPI and not TARGET_OS_MAC
+    so Darwin builds work.
+    
+    * init_os_ctx.c: Modified to use DEFAULT_SECURE_PROFILE_PATH and
+    DEFAULT_PROFILE_PATH for KfM homedir-relative config files.
+    
+    * read_pwd.c: Cast to remove const warnings.
+    
+    * timeofday.c: Do the same thing on the Mac as on Unix.
+
+2003-03-04  Sam Hartman  <hartmans@mit.edu>
+
+	* sendto_kdc.c (service_tcp_fd): Don't call shutdown on end of write because some implementations cannot deal with half-closed TCP sockets.
+
+2003-02-08  Tom Yu  <tlyu@mit.edu>
+
+	* prompter.c (krb5_prompter_posix): Kill echo before printing
+	prompt to avoid possible race conditions in test suite.
+
+2003-02-06  Tom Yu  <tlyu@mit.edu>
+
+	* prompter.c (krb5_prompter_posix, setup_tty, restore_tty): Fix to
+	use the actual file descriptor we dup()'ed to in case tcsetattr()
+	doesn't actually change the underlying device modes and instead
+	only affects the specific file descriptor.
+
+2003-02-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (translate_ai_error): Handle EAI_ADDRFAMILY like
+	EAI_NONAME.
+	(krb5int_add_host_to_list): Translate errors returned from the
+	second getaddrinfo call.
+
+2003-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* prompter.c (krb5_prompter_posix): Rewrite to no longer use
+	longjmp(), as well as to get a non-buffered stdio stream on stdin
+	to avoid passwords staying around in stdio buffers.  This does
+	have the side effect of possibly losing pre-buffered input from an
+	application that reads from stdin using stdio functions prior to
+	calling the prompter, but hopefully those are rare.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (state_strings): Now const.
+
+2002-12-06  Tom Yu  <tlyu@mit.edu>
+
+	* accessor.c (krb5int_accessor): Add add_host_to_list.
+
+	* changepw.c (krb5_locate_kpasswd): Update calls to
+	krb5_locate_kdc().
+
+	* locate_kdc.c (add_host_to_list): Renamed to
+	krb5int_add_host_to_list(), with macro to deal with existing
+	callers in this file.  Now takes an argument to indicate protocol
+	family.  Callers updated accordingly to also take protocol family
+	arguments.
+
+	* os-proto.h: Update prototype of krb5_locate_kdc().
+
+	* sendto_kdc.c (krb5_sendto_kdc): Update calls to
+	krb5_locate_kdc().
+	(krb5int_sendto): UDP reply length is in.pos-in.buf, not
+	in.bufsize.
+
+	* t_locate_kdc.c (main): Update call to krb5_locate_kdc().
+
+	* t_std_conf.c (test_locate_kdc): Update call to krb5_locate_kdc().
+
+2002-11-14  Tom Yu  <tlyu@mit.edu>
+
+	* changepw.c: Remove reference to adm_err.h.
+
+2002-11-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_locate_kdc): Use normal CC_LINK rule for linking
+	test program.
+
+2002-10-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (print_addr) [TEST]: Don't mix size_t and socklen_t,
+	just assume socklen macro will return a socklen_t value.  Cast
+	buffer size to socklen_t in getnameinfo call.
+
+2002-10-22  Ezra Peisach  <epeisach@bu.edu>
+
+	* sendto_kdc.c (service_tcp_fd): If DEBUG defined, ensure that
+	initialization of variable not bypassed by goto.
+
+2002-10-15  Tom Yu  <tlyu@mit.edu>
+
+	* hst_realm.c (krb5_try_realm_txt_rr): Apply patch from Nalin
+	Dahyabhai to bounds-check return value from res_search().
+
+	* locate_kdc.c (krb5_locate_srv_dns_1): Apply patch from Nalin
+	Dahyabhai to bounds-check return value from res_search().
+
+2002-10-11  Tom Yu  <tlyu@mit.edu>
+
+	* read_pwd.c (krb5_read_password): Restore name of size_return.
+	Set *size_return after successful call to krb5_prompter_posix,
+	since some callers were actually checking, e.g. kadm5.
+
+2002-10-10  Sam Hartman  <hartmans@mit.edu>
+
+	* read_pwd.c (krb5_read_password): Reimplement in terms of krb5_prompter_posix for unix
+
+
+2002-09-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (krb5int_cm_call_select): Fix last change.
+
+
+2002-09-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (krb5int_cm_call_select): If timeout value has
+	tv_sec==0, treat it as meaning "no timeout".
+	(krb5int_debug_fprint): Handle null timeval pointer.
+
+2002-09-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c: Include cm.h.
+	(struct select_state, SSF_READ, SSF_WRITE, SSF_EXCEPTION): Moved
+	to cm.h.
+	(DEBUG): Define.
+	(krb5int_debug_sendto_kdc): Initialize to zero.
+	(default_debug_handler, put, putstr): New functions.
+	(krb5int_sendtokdc_debug_handler): New variable.
+	(krb5int_debug_fprint): Don't write to stderr; instead, pass
+	strings to the debug output handlers above.
+	(struct incoming_krb5_message): Broken out from struct
+	conn_state.
+	(krb5int_cm_call_select): Renamed from call_select; callers
+	updated.  Now extern.  Display max fd number in debugging call,
+	not nfds.
+
+2002-09-17  Sam Hartman  <hartmans@mit.edu>
+
+	* genaddrs.c (krb5_auth_con_genaddrs): Return errno if getpeername fails
+
+2002-09-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (service_fds): Fix bug in last change.
+	(krb5int_debug_fprint): Use 'out' consistently, minimize explicit
+	references to stderr.  Flush output before returning.
+	(dperror) [_WIN32]: Shorten message.
+	(start_connection, service_tcp_fd, service_fds, krb5int_sendto):
+	Use dprint instead of dfprintf.
+
+2002-09-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (struct conn_state): Add new function pointer field
+	'service' for the fd service routine.
+	(setup_connection): Initialize it.
+	(service_fd): Deleted.
+	(service_fds): Incorporate debug output from service_fd.  Call
+	service routine indicated in connection info.  Decrement select fd
+	count for each flag set for a file descriptor.  Ensure that the
+	index into the conns array doesn't run off the end.
+	(krb5int_debug_fprint): Fetch correct type for %E.
+
+2002-09-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (get_port): Skip service name lookup, just use the
+	supplied numbers.
+	(add_host_to_list): If a second port number is supplied, look up
+	AF_INET addresses only, and only for SOCK_DGRAM type entries.
+	Ignore errors in the second address lookup.
+	(krb5_locate_srv_conf_1) [TEST]: More debugging code.
+
+	* t_locate_kdc.c (main): Add new argument -m for looking up master
+	KDC addresses.
+
+
+2002-09-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* accessor.c, an_to_ln.c, c_ustime.c, ccdefname.c, changepw.c,
+	def_realm.c, free_hstrl.c, free_krbhs.c, full_ipadr.c, gen_port.c,
+	gen_rname.c, genaddrs.c, get_krbhst.c, gmt_mktime.c, hostaddr.c,
+	hst_realm.c, init_os_ctx.c, krbfileio.c, ktdefname.c, kuserok.c,
+	localaddr.c, locate_kdc.c, lock_file.c, mk_faddr.c, net_read.c,
+	net_write.c, port2ip.c, prompter.c, promptusr.c, read_msg.c,
+	read_pwd.c, realm_dom.c, realm_iter.c, sendto_kdc.c, sn2princ.c,
+	t_an_to_ln.c, t_gifconf.c, t_locate_kdc.c, t_realm_iter.c,
+	t_std_conf.c, timeofday.c, toffset.c, unlck_file.c, ustime.c,
+	write_msg.c: Use prototype-style function definitions.
+
+	* c_ustime.c, timeofday.c: Don't declare errno.
+	* hst_realm.c (krb5_try_realm_txt_rr), locate_kdc.c
+	(krb5_locate_srv_dns_1): Avoid variable name "class".
+	* sendto_kdc.c (enum conn_states): Define separately from
+	conn_state 'state' field declaration.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (merge_addrlists): Truncate source address list
+	after copying its data into the destination list.
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (krb5int_grow_addrlist): Renamed from grow_list,
+	now external.
+	(grow_list): New macro.
+	(krb5_locate_kdc): Don't look up kerberos-sec for TCP service.
+
+	* sendto_kdc.c (MAX_PASS, dprint): New macros.
+	(krb5int_debug_fprint, merge_addrlists): New function.
+	(krb5int_debug_sendto_kdc): New variable.
+	(krb5_sendto_kdc): Use dprint.  Call krb5int_locate_kdc in two
+	places, with socket type selection done separately.
+	(debug_log_connect): Function deleted; use dprint instead.
+	(dperror): Use dprint.
+	(print_fdsets): Function deleted; use dprint instead.
+	(struct conn_state): Use struct instead of union so incoming and
+	outgoing buffer pointers can co-exist.  Add INITIALIZING state.
+	(state_strings): Add INITIALIZING.
+	(krb5int_sendto_udp, krb5int_sendto_tcp): Functions integrated
+	into krb5int_sendto.
+	(call_select): Use dprint.
+	(setup_connection): New function, handles data structure
+	initialization.
+	(start_connection): Renamed from start_tcp_connection.  Don't do
+	data structure initialization, just start connection, and transmit
+	UDP datagrams.  Use dprint.
+	(maybe_send): Create socket for "INITIALIZING" connections;
+	transmit datagrams.
+	(kill_conn): New function split out from service_tcp_fd.
+	(SSF_READ, SSF_WRITE, SSF_EXCEPTION): New macros.
+	(service_tcp_fd): Accept a flag word rather than separate int
+	arguments for read, write, exception.  Use dprint.
+	(service_udp_fd): New function.
+	(service_fd): New function, calls one of the above two.
+	(service_fds): Call it.  Use a flag word instead of separate r/w/x
+	values.
+	* accessor.c (krb5int_accessor): Use krb5int_sendto instead of
+	krb5int_sendto_udp.
+
+2002-08-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (DEFAULT_UDP_PREF_LIMIT, HARD_UDP_LIMIT): New
+	macros.
+	(debug_log_connect): Look up "udp_preference_limit" in libdefaults
+	part of profile; try TCP before UDP if the packet size is larger
+	than specified.  Don't try UDP at all if the packet is over about
+	32K.
+
+2002-07-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* localaddr.c (get_localaddrs): Add prototype before being used
+	for static function.
+
+2002-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* sn2princ.c: Include fake-addrinfo.h.
+	(krb5_sname_to_principal): Use getaddrinfo and getnameinfo instead
+	of gethostbyname and gethostbyaddr.
+
+	* hst_realm.c (krb5_get_host_realm): Return KRB5_ERR_NUMERIC_REALM
+	if the hostname is a numeric-address form.
+
+2002-07-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (get_localaddrs): Split out main body of
+	krb5_os_localaddr, add an argument to indicate whether addresses
+	listed in the profile should be included.
+	(krb5_os_localaddr): Call it.
+	(krb5int_local_addresses): Call get_localaddrs but skip
+	profile-listed addresses.
+
+	* sendto_kdc.c (krb5int_sendto_udp): Accept new args for optional
+	location to store local address used to contact server.
+	(krb5_sendto_kdc): Update call to pass 0.
+
+2002-07-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c (service_tcp_fd): sockerrlen should have type
+	socklen_t.
+
+2002-07-03  Alexandra Ellwood <lxs@mit.edu>
+
+	* init_os_ctx.c: krb4 needs to get the os config files so it can use
+	the profile too.  Define these functions on Mac OS X now.
+
+	* init_os_ctx.c: Removed use of FSSpecs because these cause serious
+	performance problems on Mac OS X.  We now search paths the same way
+	the rest of the Unix platforms do.
+
+	[pullups from 1-2-2-branch]
+
+2002-06-22  Tom Yu  <tlyu@mit.edu>
+
+	* c_ustime.c: Remove various things missed in 1-2-2-branch MacOS
+	microseconds timer removal.
+
+2001-06-22  Miro Jurisic <meeroh@mit.edu>
+
+	* c_ustime.c: punted the accurate microseconds timing code because it
+	wasn't so accurate after all.
+	[pullup from 1-2-2-branch]
+
+2002-06-22  Alexandra Ellwood <lxs@mit.edu>
+
+	* init_os_ctx.c: Add CoreServices.h before k5-int.h so we don't get 
+	multiple definitions for FSSpec.  Also removed an unused variable in
+	Mac OS X code and added casts for Mac OS X code so FSSpecs are cast
+	to profile file types (code deals properly on the other side)
+
+	* timeofday.c: Added casts to remove warnings
+
+	* ccdefname.c, init_os_ctx.c, timeofday.c: Updated Mac OS X
+	headers to new framework layout and updated Mac OS macros
+
+	* read_pwd.c: Removed #defines for Mac OS X (__MACH__) because we 
+	now export krb5_read_password on Mac OS X
+
+	[pullups from 1-2-2-branch]
+
+2002-06-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_os_ctx.c: Don't include sys/ioctl.h or sys/filio.h.
+	(krb5_os_init_context): Drop /dev/[u]random support, the Yarrow
+	code will deal with that now.
+
+2002-06-18  Danilo Almeida  <dalmeida@mit.edu>
+
+	* toffset.c (krb5_get_time_offsets), an_to_ln.c
+	(krb5_aname_to_localname): Make KRB5_CALLCONV.
+	[pullup from 1-2-2-branch]
+
+2002-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* changepw.c (ECONNABORTED, ECONNREFUSED, EHOSTUNREACH,
+	ETIMEDOUT): Don't define here now that they're defined in
+	port-sockets.h.
+	* read_msg.c (ECONNABORTED): Ditto.
+
+	* sendto_kdc.c: Include sys/timeb.h on Windows.
+	(ENABLE_TCP): Macro deleted, always enable code.
+	(krb5_sendto_kdc): Don't try UDP if outgoing message is 1500
+	bytes or larger.  Print info on arguments if DEBUG defined.
+	(bogus_strerror) [_WIN32 && DEBUG]: New function.
+	(dperror, dfprintf): New macros.
+	(krb5int_sendto_udp): Use SOCKET_ERRNO where appropriate.  Log
+	more info if DEBUG defined; use dperror and dfprintf.
+	(struct conn_state): Use new scatter-gather definitions from
+	port-sockets.h.  Don't try to reuse data structures for both
+	input and output.
+	(struct select_state): Add exception fd set.
+	(print_fdsets) [DEBUG]: Print exception fd set; callers changed.
+	(getcurtime): New function.
+	(call_select): Call it.  Pass exception fd set to select.
+	(make_nonblocking, iov_advance): Deleted.
+	(start_tcp_connection): Expand non-blocking setting inline; set
+	linger period to zero.  Use new scatter-gather framework.  Log
+	more info if DEBUG defined.
+	(service_tcp_fd): New argument indicates exception; handle
+	exception fd set.  Print more info if DEBUG.  Use SOCKET_*
+	macros, scatter-gather support, SHUTDOWN_* macros.  Adjust for
+	new conn_state definitions.
+	(krb5int_sendto_tcp): Set up exception fd set.  Adjust for new
+	conn_state definitions.  Use new scatter-gather support.
+
+2002-06-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c: Include sys/ioctl.h and sys/filio.h only if
+	ENABLE_TCP is set and _WIN32 is not defined.
+
+2002-06-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* sendto_kdc.c: Include sys/ioctl.h and sys/filio.h if
+	available.  Define ENABLE_TCP as 0 on Windows, 1 otherwise.
+	(debug_log_connect): New function.
+	(dperror, dfprintf): New macros.
+	(krb5int_sendto_udp): Use dperror, dfprintf, and
+	debug_log_connect.
+	(state_strings): New variable.
+	(struct conn_state, struct select_state): New types.
+	(print_fdsets, call_select, make_nonblocking,
+	start_tcp_connection, iov_advance, service_tcp_fd, service_fds,
+	krb5int_sendto_tcp): New functions.
+	(krb5_sendto_kdc): New argument TCP_ONLY.  Try UDP first unless
+	told otherwise, then try TCP.
+
+	* t_std_conf.c: Include fake-addrinfo.h.
+	(test_locate_kdc): Update arg list to locate_kdc.  Print IPv6 as
+	well as IPv4 addresses.
+
+	* t_locate_kdc.c (main): Free storage allocated by library before
+	exiting.
+
+2002-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (krb5_locate_srv_conf_1): New argument socktype
+	indicates what type of addrinfo entries to add.
+	(krb5int_locate_server): Change argument is_stream to socktype.
+	Pass the value to krb5_locate_srv_conf_1.
+	(krb5_locate_kdc): New argument socktype.
+	* sendto_kdc.c (krb5int_sendto_udp): New function, containing most
+	of the network code from krb5_sendto_kdc.
+	(krb5_sendto_kdc): Call it.
+	* accessor.c (krb5int_accessor): Set new sendto_udp field.
+	* os-proto.h (krb5_locate_kdc): Update prototype.  Add forward
+	declaration for struct addrlist.
+	* t_locate_kdc.c (main): Update call to krb5_locate_kdc.
+
+	* locate_kdc.c: Include fake-addrinfo.h before k5-int.h.
+	(grow_list, krb5int_free_addrlist)
+	(add_addrinfo_to_list): Incorporate list-updating code from
+	add_sockaddr_to_list.  Store an addrinfo pointer, and set the
+	ai_next field to null.
+	(add_host_to_list): New arg SOCKTYPE.  Write port numbers into
+	buffers and let getaddrinfo fill in the sin*_port fields.  Call
+	getaddrinfo twice, and use two loops to add entries to the
+	addrlist structure.
+	(add_sockaddr_to_list, set_port_num): Deleted.
+	(krb5_locate_srv_conf_1, krb5_locate_srv_dns_1): Pass extra arg
+	to add_host_to_list.
+	(krb5int_locate_server): New value 2 for is_stream arg means
+	accept both UDP and TCP.
+	* changepw.c: Include fake-addrinfo.h.
+	(krb5_locate_passwd, krb5_change_password): Update for addrlist
+	changes.
+	* sendto_kdc.c: Include fake-addrinfo.h.
+	(krb5_sendto_kdc): Update for addrlist changes.  Skip any
+	addresses that are not SOCK_DGRAM.
+	* t_locate_kdc.c (stypename): New function.
+	(print_addrs): Update for addrlist changes.  Print socket type
+	with address and port.
+
+2002-04-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* lock_file.c (krb5_lock_file) [POSIX_FILE_LOCKS]: Make static
+	"zero" variable const.
+
+	* prompter.c (krb5_prompter_posix): Initialize 'i' and make it
+	volatile.
+
+	* locate_kdc.c (add_addrinfo_to_list) [TEST]: Print out socket
+	type before returning.
+	(add_host_to_list): Don't need to initialize err.  Supply
+	getaddrinfo hint to select datagram addresses only.  Delete AIX
+	bug workaround code.
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* locate_kdc.c (translate_ai_error), hst_realm.c
+	(krb5int_translate_gai_error): Test some EAI_ error definitions
+	so that we will also build correctly on Win32 (Winsock 2).
+
+2002-03-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* hostaddr.c (FAI_PREFIX): Delete.
+	* hst_realm.c (FAI_PREFIX): Delete.
+	* localaddr.c [TEST || DEBUG]: Include fake-addrinfo.h, not
+	fake-addrinfo.c.
+	(FAI_PREFIX) [TEST || DEBUG]: Delete.
+	* locate_kdc.c: Include fake-addrinfo.h, not fake-addrinfo.c.
+	(FAI_PREFIX): Delete.
+
+2002-02-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c: Include foreachaddr.c.
+	(printaddr, printifaddr, addr_eq, grow_or_free, get_ifconf,
+	get_lifconf, get_linux_ipv6_addrs, foreach_localaddr): Deleted.
+	* Makefile.in (localaddr.o): Update dependencies.
+
+2002-02-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (LINUX_IPV6_HACK) [__linux__&& KRB5_USE_INET6]:
+	Define macro.
+	(get_linux_ipv6_addrs) [LINUX_IPV6_HACK]: New function, reads
+	addresses from /proc/net/if_inet6.
+	(foreach_localaddr) [!HAVE_IFADDRS_H && !SIOCGLIFNUM &&
+	LINUX_IPV6_HACK]: Include ipv6 addresses.
+
+2002-01-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* hst_realm.c (EAFNOSUPPORT): On Windows, translate to
+	WSAEAFNOSUPPORT.
+
+2002-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* hst_realm.c (krb5int_get_fq_hostname): New function.  Use
+	getaddrinfo instead of gethostbyname.
+	(krb5int_get_fq_local_hostname): New function.
+	(krb5_get_host_realm): Call it.
+	* def_realm.c (krb5_get_default_realm): Call it.
+
+	* Makefile.in (t_localaddr): Link against $(LIBS).
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* sendto_kdc.c (krb5_sendto_kdc): Get rid of unecessary casts.
+
+2001-10-24  Sam Hartman  <hartmans@mit.edu>
+
+	* accessor.c (krb5int_accessor):  Add fields for struct version 4
+
+2001-10-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (add_host_to_list): If sa_len field exists and is
+	zero, try to fill it in.  Another AIX 4.3.3 bug workaround.
+
+	* sendto_kdc.c (krb5_sendto_kdc) [DEBUG]: More fprintf calls for
+	tracing through.
+
+2001-10-10  Ezra Peisach  <epeisach@mit.edu>
+
+	* localaddr.c (krb5_os_localaddr_profile): Cast argument to
+	isspace() to int.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* os-proto.h: Make prototypes unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* an_to_ln.c, c_ustime.c, ccdefname.c, init_os_ctx.c, ktdefname.c,
+	kuserok.c, localaddr.c, lock_file.c, prompter.c, promptusr.c,
+	read_pwd.c: Drop _MSDOS support.
+
+	* ccdefname.c, def_realm.c, free_hstrl.c, hst_realm.c,
+	ktdefname.c, localaddr.c, mk_faddr.c, read_pwd.c, sn2princ.c,
+	timeofday.c, ustime.c: Don't explicitly declare pointers FAR any
+	more.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* accessor.c, ccdefname.c, changepw.c, def_realm.c, free_hstrl.c,
+	genaddrs.c, hst_realm.c, init_os_ctx.c, ktdefname.c, localaddr.c,
+	prompter.c, realm_dom.c, realm_iter.c, sn2princ.c, timeofday.c,
+	ustime.c: Don't use KRB5_DLLIMP.
+
+2001-09-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (add_host_to_list): If address family in sockaddr
+	structure is zero, copy it in from the addrinfo structure.  Bug
+	workaround for AIX 4.3.3.
+
+2001-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c: Retrieve IPv6 addresses on Solaris 8.
+	(get_lifconf) [SIOCGLIFCONF]: New function.
+	(foreach_localaddr) [SIOCFLIGNUM]: New section, using new lifconf
+	and lifreq structures and related ioctls.
+	(Tprintf, Tperror): New macros.  Print stuff if TEST is defined,
+	otherwise be silent but cause same evaluations to happen.
+
+	* localaddr.c (TEST || DEBUG): Include fake-addrinfo.c, not
+	fake-addrinfo.h.
+
+2001-08-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* hostaddr.c (krb5_os_hostaddr): Don't use AI_DEFAULT.
+
+	* genaddrs.c (struct addrpair): New type.
+	(cvtaddr): New function.  Fills in krb5_address structures
+	referencing port and address parts of a sockaddr.  Converts
+	IPv4-mapped IPv6 addresses to plain IPv4 addresses.
+	(krb5_auth_con_genaddrs): Use sockaddr_storage for addresses.  Use
+	addrpairs to pass to cvtaddr, then set up pointers to the elements
+	as needed.
+
+2001-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c: Include fake-addrinfo.c instead of
+	fake-addrinfo.h.
+	(FAI_IMPLEMENTATION): Deleted.
+
+2001-08-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c: Include ctype.h.
+	[TEST || DEBUG]: Defined FAI_PREFIX and include fake-addrinfo.h.
+	(foreach_localaddr) [TEST]: Change whitespace in some debug
+	messages.
+	(print_addr) [TEST]: Delete non-getnameinfo version of code.
+	Change some messages.
+	(struct localaddr_data): New field CUR_SIZE.
+	(allocate): Grow existing storage, if already allocated.
+	(krb5_os_localaddr_profile): New function.  Looks up
+	"extra_addresses" in "libdefaults" section, separates on
+	whitespace, looks up addresses, adds them to the list.
+	(krb5_os_localaddr): Call krb5_os_localaddr_profile first; ignore
+	any errors it reports.
+	(krb5_os_localaddr) [DEBUG]: More debugging code.
+
+	* hostaddr.c (krb5_os_hostaddr): Only retry non-numeric lookup
+	after numeric lookup if AI_NUMERICHOST is nonzero.
+
+2001-07-31  Ezra Peisach  <epeisach@mit.edu>
+
+	* genaddrs.c: Use GETPEERNAME_ARG2_TYPE, GETPEERNAME_ARG3_TYPE
+	instead of assuming types. 
+
+	* changepw.c: Use GETSOCKNAME_ARG3_TYPE instead of int in casts.
+
+2001-07-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* gen_port.c (krb5_gen_portaddr): Add const to cast of
+	krb5_const_pointer to maintain const status.
+
+2001-07-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* sn2princ.c: Do not cast away const char * in call to strdup.
+
+2001-07-24  Jeffrey Altman <jaltman@columbia.edu>
+
+        * def_realm.c: 
+            krb5_get_default_realm() required a profile file
+            even when KRB5_DNS_LOOKUP was defined.  
+
+2001-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* hostaddr.c: Include fake-addrinfo.h.
+	(FAI_PREFIX): Define macro.
+	(krb5_os_hostaddr): Use getaddrinfo, to get ipv6 support and
+	thread safety.  Support numeric addresses as well.
+
+	* t_locate_kdc.c: New file.
+	* Makefile.in (t_locate_kdc.o, t_locate_kdc): New targets.
+
+	* locate_kdc.c: Include fake-addrinfo.h.
+	(FAI_PREFIX, FAI_IMPLEMENTATION): Define macros.
+	(get_port, add_sockaddr_to_list, add_host_to_list): Drop
+	gethostbyname/getservbyname support, always use getnameinfo, which
+	should be thread-safe.
+	(translate_ai_error, set_port_num): Now always defined.
+	(set_port_num): Only check for AF_INET6 if KRB5_USE_INET6.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* sn2princ.c (krb5_sname_to_principal): Cast tolower argument to int. 
+
+	* hst_realm.c (krb5_get_host_realm): Cast argument to toupper and
+	tolower to int.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_std_conf.c (test_locate_kdc): Get rid of unused variable.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_std_conf.c (test_locate_kdc): Update to new krb5_locate_kdc
+	interface.
+
+2001-06-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (struct addrlist, ADDRLIST_INIT): Moved to
+	k5-int.h.
+	(krb5int_free_addrlist): Renamed from free_list; no longer
+	static.
+	(krb5_locate_srv_conf, krb5_locate_srv_dns, krb5int_locate_server,
+	krb5_locate_kdc): Use addrlist in interface.
+
+	* sendto_kdc.c (krb5_sendto_kdc): Use new struct addrlist
+	interface.
+
+	* changepw.c (krb5_locate_kpasswd): Use addrlist structure in
+	interface and implementation.
+	(krb5_change_password): Likewise.
+
+	* accessor.c (krb5int_accessor): Fill in free_addrlist function
+	pointer field.
+
+	* os-proto.h (krb5_locate_kdc): Update prototype.
+
+2001-06-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* sn2princ.c, hst_realm.c, an_to_ln.c: Cast argument to
+	isupper()/isspace()/islower() to int.
+
+	* t_std_conf.c (test_locate_kdc): krb5_locate_kdc expects a struct
+	sockaddr *** as a third argument instead of sockaddr **.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* ktdefname.c (krb5_kt_default_name): Get rid of a variable that
+	was set in a conditional but never used.
+
+2001-05-08  Danilo Almeida  <dalmeida@mit.edu>
+
+	* locate_kdc.c (add_host_to_list): Initialize stack variable err
+	which would otherwise get returned without being set in certain
+	circumstances.
+
+2001-05-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (add_sockaddr_to_list) [TEST]: If getnameinfo is
+	available, use it instead of inet_ntoa to get the printable
+	address.
+	(add_host_to_list): Share declaration sections as much as
+	possible.  Propagate errors back correctly from gethostbyname
+	path.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* hst_realm.c (T_TXT): Define if not defined by header files.
+
+	* locate_kdc.c (krb5int_locate_server): New function, replaces
+	functionality of krb5_locate_srv_conf and _dns, including checking
+	whether DNS lookup is desired.
+	(krb5_locate_srv_conf, krb5_locate_srv_dns): Define only if macro
+	TEST is defined.  Added another level of indirection in the
+	address pointer argument.
+	(krb5_locate_srv_dns_1, krb5_locate_srv_conf_1,
+	translate_ai_error, get_port, struct addrlist, ADDRLIST_INIT,
+	grow_list, free_list, add_sockaddr_to_list, add_addrinfo_to_list,
+	set_port_num, add_host_to_list): New helper functions.
+	(krb5_locate_kdc): Added another level of indirection in the
+	address pointer argument.  Call krb5int_locate_server.
+	(KPASSWD_PORTNAME): Deleted.
+
+	* os-proto.h (krb5_locate_kdc): Updated prototype.
+
+	* sendto_kdc.c (krb5_sendto_kdc): Updates for change in
+	krb5_locate_kdc interface.
+
+	* changepw.c (krb5_locate_kpasswd): Call krb5int_locate_server.
+	Add another level of indirection in address pointer.  Now gives
+	preference to _kpasswd info from DNS over admin_server info in
+	config file, if kpasswd_server is not set.
+	(krb5_change_password): Use struct sockaddr_storage for all
+	automatic address variables.  Ignore any non-IPv4 addresses
+	returned from krb5_locate_kpasswd; return an error if all
+	addresses are non-IPv4.  Update for new krb5_locate_kpasswd
+	interface.
+
+	* accessor.c (krb5int_accessor): Set krb5_locate_server field.
+
+2001-04-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (socklen_t, socklen): Deleted; definitions now in
+	k5-int.h instead.
+	(foreach_localaddr): Use SIOCGIFNUM if it's available and
+	SIOCGSIZIFCONF is not (e.g., Solaris 7 and 8).
+	(print_addr) [!HAVE_GETNAMEINFO]: Only declare variable buf if
+	AF_INET6 is defined.
+
+2001-03-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_gifconf.c: New file.
+
+2001-03-10  Ezra Peisach  <epeisach@mit.edu>
+
+	* def_realm.c: Move prototype for krb5_try_realm_txt_rr() to
+	os-proto.h.
+
+	* init_os_ctx.c: Include os-proto.h
+
+	* changepw.c, locate_kdc.c: Do not shadow sin() with local
+	variable name.
+
+	* os-proto.h: Add prototypes for krb5_try_realm_txt_rr() and the
+	obsolete krb5_secure_config_files().
+
+2001-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (krb5_os_localaddr): Don't look for -1 return value
+	from foreach_localaddr.
+	(print_addr): Only process AF_INET6 addresses if AF_INET6 is
+	defined.
+
+	* gmt_mktime.c (gmt_mktime): Handle years earlier than 1970.
+	(main) [TEST_LEAP]: New routine, driver for testing.
+	* Makefile.in (t_mktime): New target.
+
+2001-03-05  Sam Hartman  <hartmans@mit.edu>
+
+	* kuserok.c: Set max_username to 65 not 10.  65 should be enough
+	for a null terminated string from most current Unixes usernames.
+	The previous limit of 10 was too low.  I don't know how the
+	previous limit was chosen nor why this is not a dynamic buffer.
+
+2001-03-05  Tom Yu  <tlyu@mit.edu>
+
+	* init_os_ctx.c: Get sys/ioctl.h for Solaris to get FIONBIO.
+
+2001-03-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_os_ctx.c: If not Mac or Windows, define USE_RANDOM_DEVICE
+	and include sys/ioctl.h.
+	(krb5_os_init_context) [USE_RANDOM_DEVICE]: Read some bytes from
+	/dev/urandom or /dev/random and use them to re-seed the PRNG.
+
+2001-02-05  Tom Yu  <tlyu@mit.edu>
+
+	* prompter.c (krb5_prompter_posix): Fix up terminal modes if we're
+	interrupted. [reported by Booker Bense]
+
+2000-12-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LCLINT, LCLINTOPTS): New variables.
+	(lclint-localaddr): New target.
+
+	* localaddr.c (grow_or_free, get_ifconf, make_addr): Split out
+	from foreach_localaddr and friends for simpler lclint analysis.
+	(socklen): New function.
+	(print_addr): Use getnameinfo if available.
+	(struct localaddr_data, count_addrs, allocate, add_addr,
+	make_addr): Define only if not testing.
+	(foreach_addr): Call new functions.  Annotate for lclint.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* changepw.c: Cast length argument to recvfrom/sendto to int.
+
+	* os-proto.h: Moved extern definition of krb5_max_dgram_size,
+	krb5_max_skdc_timeout, krb5_skdc_timeout_shift,
+	krb5_skdc_timeout_1 here.
+
+	* accessor.c: Definition for krb5_max_dgram_size,
+	krb5_max_skdc_timeout, krb5_skdc_timeout_shift,
+	krb5_skdc_timeout_1 moved to os-proto.h
+
+	* osconfig.c: Changed definition for krb5_max_dgram_size,
+	krb5_max_skdc_timeout, krb5_skdc_timeout_shift,
+	krb5_skdc_timeout_1 to unsigned int.
+
+	* get_krbhst.c, init_os_context.c, locate_kdc.c, prompter.c:
+	Unsigned/signed int cleanup.
+
+	* read_pwd.c (krb5_read_password): Change size_return to unsigned
+	int *.
+
+	* sendto_kdc.c: Remove definition for krb5_max_dgram_size,
+	krb5_max_skdc_timeout, krb5_skdc_timeout_shift,
+	krb5_skdc_timeout_1. (moved to os-proto.h). Cast arguments to int
+	for send() and recv().
+
+2000-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	Support for getifaddrs() interface added in BSD.
+	* localaddr.c (printaddr, printifaddr) [HAVE_IFADDRS_H && DEBUG]:
+	New functions for debugging new ifaddrs code.
+	(addr_eq) [HAVE_IFADDRS_H]: New function, for comparing addresses
+	found with getifaddrs.
+	(foreach_localaddr) [HAVE_IFADDRS_H]: New implementation, relies
+	on C library function to retrieve data.
+	(foreach_localaddr) [!HAVE_IFADDRS_H && TEST]: Print info about
+	each address and why it might not be used.
+	(print_addr, main) [TEST]: Print out the local addresses.
+	* Makefile.in (t_localaddr): New target.
+
+2000-09-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* an_to_ln.c: Unsigned vs signed int fixes.
+
+	* t_std_conf.c: Declare local functions static, do not shadow
+	sin() with local variable.
+
+2000-08-31  Jeffrey Altman <jaltman@columbia.edu>
+
+        * locate_kdc.c: krb5_locate_srv_dns() 
+          Ensure that res_search() is called with a query string
+          that is terminated by a '.' in order to disable the
+          expansion of dns-search lists.
+
+2000-07-22  Tom Yu  <tlyu@mit.edu>
+
+	* accessor.c: Add NEED_SOCKETS in order to get prototype for
+	krb5_locate_kdc().
+
+2000-07-19  Danilo Almeida  <dalmeida@mit.edu>
+
+	* accessor.c (krb5int_accessor): Add krb5int_accessor() to access
+	internal krb5 functions from outside the library (so that we don't
+	have to export them for the krb525 and gssapi libraries).  The
+	goal is to make this function eventually do nothing.
+
+	* Makefile.in: Compile accessor.c.
+
+2000-07-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* locate_kdc.c, hst_realm.c, def_realm.c, changepw.c: Include
+	os-proto.h for internal prototypes.
+
+	* os-proto.h: Prototypes for _krb5_use_dns_realm(),
+	_krb5_use_dns_kdc(), _krb5_conf_boolean().
+
+	* t_std_conf.c: Include k5-int.h for internal function prototypes.
+
+2000-06-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_an_to_ln.c: Include <stdio.h> for prototypes.
+
+	* locate_kdc.c (krb5_locate_srv_dns): Remove unused variable.
+
+	* changepw.c, sendto_kdc.c, sn2princ.c: Add parentheses around
+	assignment used as truth value.
+
+	* ccdefname.c (get_from_os): Cast return from getuid() to long and
+	indicate use of format in sprintf.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* def_realm.c: Add newline at end of file.
+
+	* gmt_mktime.c: Define days_in_month as type int.
+
+	* locate_kdc.c (krb5_locate_srv_dns): Cleanup unused variables.
+
+2000-06-23  Miro Jurisic  <meeroh@mit.edu>
+
+	* init_os_ctx.c (os_get_default_config_files): Return ENOENT when
+	file is not found on MacOS (not ENFILE).  Use Kerberos Preferences
+	library to locate the config files on Mac OS.  Eliminated some
+	dead code.
+
+2000-06-23  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* an_to_ln.c (do_replacement):  Don't overflow buffers "in" or "out".
+	* hst_realm.c (krb5_try_realm_txt_rr):  Don't overfill "host" when
+	malformed DNS responses are received.
+
+	* ccdefname.c (get_from_os): Don't overflow buffer "name_buf".
+	* kuserok.c (krb5_kuserok): Don't overflow buffer "pbuf".
+
+2000-06-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c: Include stddef.h.
+	(foreach_localaddr): Check each address against previously used
+	addresses, and skip duplicates, in case multiple interfaces have
+	the same address.  If called functions fail, drop out of loop and
+	return nonzero.  Use SIOCGSIZIFCONF ioctl if available to get the
+	buffer size needed for SIOCGIFCONF, and skip the silly heuristics
+	if it returns a reasonable value.
+	(krb5_os_localaddr): Increment count of addresses to include null
+	pointer terminator.  Delete check for zero count.
+
+	* locate_kdc.c (maybe_use_dns): Renamed from _krb5_use_dns.  Now
+	takes an arg to indicate a key to look up in krb5.conf, falling
+	back to "dns_fallback", and an arg indicating the default value if
+	no config file entries match.
+	(_krb5_use_dns_realm): New routine; use "dns_lookup_realm" and
+	KRB5_DNS_LOOKUP_REALM setting.
+	(_krb5_use_dns_kdc): New routine; use "dns_lookup_kdc" and
+	KRB5_DNS_LOOKUP_KDC.
+	(krb5_locate_kdc): Call _krb5_use_dns_kdc.
+	* changepw.c (krb5_locate_kpasswd): Call _krb5_use_dns_kdc.
+	* def_realm.c (krb5_get_default_realm): Call _krb5_use_dns_realm.
+	* hst_realm.c (krb5_get_host_realm): Call _krb5_use_dns_realm.
+
+2000-06-23	Alexandra Ellwood <lxs@mit.edu>
+
+	* ccdefname.c: Added support to store a krb5_principal in the os_context 
+	along with the default ccache name (if known, this principal is the same 
+	as the last time we looked at the ccache.
+
+2000-05-09	Alexandra Ellwood <lxs@mit.edu>
+
+	*localaddr.c: Fixed the local_addr_fallback_kludge so that it actually does something.
+	Before that the error code it was handling was blowing it away in cleanup.
+
+2000-04-29  Jeffrey Altman <jaltman@columbia.edu>
+
+        * hst_realm.c (krb5_get_host_realm)
+          remove the searchlist and defaultrealm _kerberos queries
+
+2000-04-18  Danilo Almeida  <dalmeida@mit.edu>
+
+	* prompter.c (krb5int_set_prompt_types): Set to actual value
+	intead of 0.
+
+2000-4-13	Alexandra Ellwood <lxs@mit.edu>
+
+	* init_os_ctx.c: Added support to store a krb5_principal in the os_context 
+	along with the default ccache name (if known, this principal is the same 
+	as the last time we looked at the ccache.
+
+2000-03-20  Miro Jurisic  <meeroh@mit.edu>
+
+	* def_realm.c (krb5_free_default_realm): Added, use to free
+	result of krb5_get_default_realm
+
+2000-03-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* prompter.c: Add krb5int_set_prompt_types() and
+	krb5_get_prompt_types().
+
+2000-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_os_ctx.c (os_get_default_config_files): Remove unused
+	variable.
+
+	* def_realm.c: Include netinet/in.h if available.
+
+2000-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (foreach_localaddr): Broken out from old
+	krb5_os_localaddr.  Iterates over all active interface addresses,
+	invoking callback functions; knows nothing about Kerberos.
+	(count_addrs, allocate, add_addr): New callback functions.
+	(krb5_os_localaddr): Use the above.
+	(allocate): Make room for NULL value at the end.
+
+2000-02-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (krb5_os_localaddr): Dynamically grow buffer used
+	for SIOCGIFCONF until it appears to have been big enough.
+	Dynamically grow internal address pointer array as needed.
+
+2000-02-11  Marshall Vale  <mjv@mit.edu>
+
+	* init_os_ctx.c (os_get_default_config_files.c): Added new
+	file name "Kerberos Preferences" to the of valid configuration
+	file names on Mac OS. The others will be removed at a later 
+	date.
+
+2000-02-08  Marshall Vale  <mjv@mit.edu>
+
+	* init_os_ctx.c (os_get_default_config_files.c): Added
+	Application Support folder to list of locations to look
+	for krb5 configuration file. Only looks at top level which
+	needs to be improved.
+	(GetMacProfileFileSpec): Added a parameter to declare which
+	folder constants to use for file spec creation. Previously it
+	had assumed just the Preferences folder.
+
+2000-02-07  Scott McGuire  <smcguire@mit.edu>
+
+    * changepw.c (krb5_locate_kpasswd): fixed memory trashing
+       caused by incorrect pointer arithmetic when assigning
+       DEFAULT_KPASSWD_PORT in DNS code also.
+
+2000-02-04  Scott McGuire  <smcguire@mit.edu>
+
+    * changepw.c (krb5_locate_kpasswd): fixed memory trashing
+       caused by incorrect pointer arithmetic when assigning
+       DEFAULT_KPASSWD_PORT in non-DNS code.
+   
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* changepw.c: Define ETIMEDOUT for Windows.
+
+1999-12-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_os_ctx.c (krb5_secure_config_files): Do define; always
+	return an error, but perform old functionality in case the error
+	is ignored.  Delete when we can make a major version number
+	change.
+
+1999-11-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* an_to_ln.c (default_an_to_ln): Avoid stomping byte after
+	supplied buffer.  Thanks to Matt Crawford.
+
+	* init_os_ctx.c (os_init_paths): Delete SECURE argument; read the
+	value from the profile structure instead.
+	(krb5_os_init_context, krb5_get_profile): Don't pass SECURE
+	argument.
+	(os_init_paths, krb5_get_profile): Cast first arg to
+	profile_init.
+	(krb5_secure_config_files): Don't define.
+
+1999-11-22  Miro Jurisic  <meeroh@mit.edu>
+
+	* ccdefname.c (get_from_os): Replaced Kerberos5GlobalsLib calls
+	with CCAPI v3 calls
+
+1999-11-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (krb5_os_localaddr): Conditionalize INET6 support on
+	new KRB5_USE_INET6 macro.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-10-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* prompter.c (krb5_prompter_posix): Make ointrfunc, fd, and
+	errcode volatile.
+	* promptusr.c (krb5_os_get_tty_uio): Make ointrfunc and retval
+	volatile.
+	* read_pwd.c (krb5_read_password): Make ointrfunc volatile.  Fix
+	volatile decl for readin_string (pointer is volatile, doesn't
+	point to volatile).
+
+	* changepw.c (krb5_change_password): Wait only two minutes, not
+	indefinitely, for a response from the kpasswd server.
+
+1999-10-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (krb5_os_localaddr): Don't bother trying to create
+	inet6 socket; any socket type will do.
+
+1999-10-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* localaddr.c (krb5_os_localaddr): Raise buffer size to 10K.
+	Handle INET6 addresses.  If INET6 support is built in but the
+	socket creation fails, fall back to INET.
+
+1999-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* changepw.c (krb5_locate_kpasswd): Declare local variable i even
+	when DNS code is not in use.
+	(krb5_locate_srv_conf, krb5_locate_srv_dns): Delete declarations.
+
+1999-09-21  Ken Raeburn  <raeburn@mit.edu>
+
+	Changes from Jeffrey Altman to look up kpasswd server using DNS.
+	* changepw.c: (krb5_locate_kpasswd): New function, split out from
+	krb5_change_password.  Calls krb5_locate_srv_dns if use of DNS is
+	desired, and krb5_locate_srv_conf to check config file.
+	(krb5_change_password): Call it to find the server.
+	* locate_kdc.c (krb5_locate_srv_conf): No longer static.  Choose
+	default port numbers based on service name rather than a single
+	hard-coded value.
+	(krb5_locate_srv_dns): No longer static.
+
+1999-09-17  Tom Yu  <tlyu@mit.edu>
+
+	* def_realm.c: Patch from jaltman@columbia.edu to allow compiling
+	under non-Windows platforms with DNS lookup enabled.
+
+1999-09-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* kuserok.c (krb5_kuserok): Fix improper negation in
+	non-Unix localname check.  Also fix calling convention
+	before this function is exported by the Windows DLL.
+
+	* localaddr.c (krb5_os_localaddr): Fix memset to clear
+	right address list.  (Thanks to jaltman@columbia.edu).
+
+1999-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_krbhst.c (krb5_get_krbhst): Fix double-indirection
+	confusion.  Do actually copy string contents to newly allocated
+	storage.
+
+1999-08-21  Danilo Almeida  <dalmeida@mit.edu>
+
+	* localaddr.c (krb5_os_localaddr): Use multiple addresses, if
+	present, on Mac and Windows.
+
+1999-08-10	Alexandra Ellwood	<lxs@mit.edu>
+
+	* changepw.c (krb5_change_password):
+		Reorganized code so that krb5_change_password actually frees
+		everything it allocated on error.  Also fixed some memory 
+		leaks which happened even without an error occurring.
+
+1999-08-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* prompter.c (krb5_prompter_posix): Provide Win32 implementation
+	so that kinit and such work under Win32.
+
+1999-08-06  Danilo Almeida  <dalmeida@mit.edu>
+
+	* def_realm.c (krb5_get_default_realm): 
+	* hst_realm.c (krb5_get_host_realm): Make sure we have FQDN
+	in the case where we use gethostname.
+
+	* def_realm.c (krb5_get_default_realm): Check that we have
+	a realm before trying to copy it (since profile_get_string
+	may return no error but not get anything).
+
+	* init_os_ctx.c (krb5_get_profile): Fix calling convention.
+
+1999-08-05  Danilo Almeida  <dalmeida@mit.edu>
+
+	* t_std_conf.c (test_get_krbhst): Use krb5_free_krbhst to
+	free buffers allocated by krb5_get_krbhst.
+
+	* locate_kdc.c (_krb5_use_dns): Add _krb_use_dns to abstract
+	away looking up of whether we use DNS or not in the profile.
+
+	* ktdefname.c (krb5_kt_default_name): Use profile_release_string
+	instead of free to free string allocated by profile_get_string.
+
+	* get_krbhst.c (krb5_get_krbhst): Copy results from profile_get_values
+	into malloc'ed buffers so we can safely free them later.  Also call
+	profile_free_list on the original values.
+
+	* locate_kdc.c (krb5_locate_kdc): 
+	* hst_realm.c (krb5_get_host_realm): 
+	* def_realm.c (krb5_get_default_realm): Use _krb5_use_dns to figure
+	out whether to use DNS or not instead of directly reading the 
+	profile in this routine.
+
+	* realm_dom.c (krb5_get_realm_domain): 
+	* hst_realm.c (krb5_get_host_realm): 
+	* def_realm.c (krb5_get_default_realm): Copy results of 
+	profile_get_string into malloc'ed buffer so it can safely be free'd
+	later.
+
+	* locate_kdc.c (krb5_locate_srv_conf):
+	* def_realm.c (krb5_get_default_realm): 
+	* changepw.c (krb5_change_password): 
+	* an_to_ln.c (krb5_aname_to_localname): Use profile_free_list
+	to free values allocated by profile_get_values.
+
+1999-08-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* init_os_ctx.c (os_init_paths): Wrap use of ctx->profile_in_memory
+	with KRB5_DNS_LOOKUP.  Use pointer value to determine whether to free 
+	files by checking the files value rather than depending on the 
+	return value.
+
+1999-07-27  Miro Jurisic  <meeroh@mit.edu>
+
+	* init_os_ctx.c (GetMacProfileFileSpec): removed bogus string conversion
+
+1999-07-26  Miro Jurisic  <meeroh@mit.edu>
+
+	* c_ustime.c (krb5_crypto_us_timeofday): Merged in changes from the
+	Mac_V2_0_derivatives branch -- microseconds support and guaranteed 
+	monotonically increasing microseconds on MacOS
+
+	* init_os_ctx.c (os_get_default_config_files): Merged in changes from the
+	Mac_V2_0_derivatives branch -- NRL config file name
+
+	* init_os_ctx.c (krb5_get_profile): added krb5_get_profile
+
+1999-07-22 Jeffrey Altman <jaltman@columbia.edu>
+
+        * init_os_ctx.c (os_init_paths)
+          If profile_init() is unable to open a profile and returns ENOENT,
+          remember in the context that the profile_in_memory and then 
+          call profile_init() with a NULL filespec.
+
+        * def_realm.c (krb5_get_default_realm)
+        * hst_realm.c (krb5_get_host_realm)
+        * locate_kdc.c (krb5_locate_kdc)
+          Use the profile entry [libdefaults] dns_fallback to determine
+          if DNS SRV and TXT records should be used to find realms and
+          servers if they are not found in the profile.
+   
+
+1999-07-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* init_os_ctx.c (os_get_default_config_files): Fix some typos and
+	missed name changes in the patch Miro just checked in but forgot
+	to mention here, in which Mac filespecs are used instead of
+	filenames.
+	(krb5_free_config_files): Ditto.
+
+1999-06-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Kerberos admin service name is
+	"kerberos-adm", not "kadmin", so look up "_kerberos-adm._tcp" in
+	DNS.
+
+1999-06-21  Ken Raeburn  <raeburn@mit.edu>
+	and Jeffrey Altman and Ken Hornstein
+
+	* def_realm.c (MAXHOSTNAMELEN) [KRB5_DNS_LOOKUP]: Define if not
+	already defined.
+	(MAX_DNS_NAMELEN) [KRB5_DNS_LOOKUP]: New macro.
+	(krb5_get_default_realm): Return an error if an empty realm name
+	is found.
+	(krb5_get_default_realm) [KRB5_DNS_LOOKUP]: Use
+	krb5_try_realm_txt_rr to determine the realm of the local host or
+	domain.
+
+	* hst_realm.c [KRB5_DNS_LOOKUP]: Pull in some extra header files
+	for resolver functionality.
+	(MAX_DNS_NAMELEN): New macro.
+	(krb5_try_realm_txt_rr) [KRB5_DNS_LOOKUP]: New function; looks up
+	a TXT record.
+	(krb5_get_host_realm): Use MAX_DNS_NAMELEN for buffer size.
+	(krb5_get_host_realm) [KRB5_DNS_LOOKUP]: Use DNS lookup if config
+	file doesn't contain a match.
+
+	* locate_kdc.c [KRB5_DNS_LOOKUP]: Pull in some extra header files
+	for resolver functionality.
+	(MAXHOSTNAMELEN) [KRB5_DNS_LOOKUP]: Define if not already
+	defined.
+	(MAX_DNS_NAMELEN) [KRB5_DNS_LOOKUP]: New macro.
+	(krb5_locate_srv_conf): Renamed from krb5_locate_kdc; now static;
+	extra char* argument replaces fixed "kdc" in array of names to
+	look up in profile.
+	(krb5_locate_srv_dns) [KRB5_DNS_LOOKUP]: New function; looks up
+	SRV records, and returns addresses sorted by priority.
+	(krb5_locate_kdc): New function, calls above routines.
+
+1999-06-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* ccdefname.c (get_from_registry_indirect, try_dir, get_from_os): 
+		Extra robustness to win32 code.
+
+	* init_os_ctx.c (krb5_get_config_files, krb5_free_config_files):
+		Add function to get config files being used for current 
+		context with corresponding free function.
+
+1999-06-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* init_os_ctx.c (os_init_paths): Enhance win32 heuristics to use 
+		environment variable (like Unix) and to use the registry
+		too.  Will try executable's dir before windows dir if 
+		not secure.
+
+	* ccdefname.c (get_from_os): Enhance win32 heuristics to use 
+		registry properly, default to API: properly,
+		and to use temp dirs before the windows dir.
+
+1999-06-11  Miro Jurisic  <meeroh@mit.edu>
+
+	* init_os_ctx.c (os_init_paths): added NRL config file name correctly
+		(thanks dalmeida)
+
+1999-06-09  Miro Jurisic  <meeroh@mit.edu>
+
+	* c_ustime.c (krb5_crypto_us_timeofday): fixed Mac PPC #ifdef
+
+1999-06-09  Miro Jurisic  <meeroh@mit.edu>
+
+	* c_ustime.c (krb5_crypto_us_timeofday): #ifdefed microseconds on Mac to be
+		PPC-only
+
+1999-06-09  Miro Jurisic  <meeroh@mit.edu>
+
+	* c_ustime.c (AbsoluteToSecsNanosecs): Fixed the UInt64 division
+	* c_ustime.c (krb5_crypto_us_timeofday): now returning the correct value
+
+1999-06-09  Miro Jurisic  <meeroh@mit.edu>
+
+	* c_ustime.c (AbsoluteToSecsNanosecs): Fixed the UInt64 comparison
+
+1999-06-09  Miro Jurisic  <meeroh@mit.edu>
+
+	* net_read.c, net_write.c: now setting errno on Mac too
+	
+1999-06-09  Miro Jurisic  <meeroh@mit.edu>
+
+	* c_ustime.c (krb5_crypto_us_timeofday, HaveAccurateTime,
+		AbsoluteToSecsNanosecs): Added support for microseconds or
+		better timers on the Mac when available
+
+	* c_ustime.c (krb5_crypto_us_timeofday): fixed usecs counting bug
+		(From Chas Williams)
+
+	* init_os_ctx.c (GetMacProfilePathname): removed hardcoded config file name
+		(From Chas Williams)
+	
+	* init_os_ctx.c (os_init_paths): added NRL config file name
+		(From Chas Williams)
+
+Tue Jun  8 15:26:21 1999  Alexandra Ellwood  <lxs@mit.edu>
+
+	* changepw.c: Changed errno to SOCKET_ERRNO/SOCKET_SET_ERRNO
+	    after socket operations to work with new Mac OT SocketsLib.
+	
+	* hst_realm.c: Changed errno to SOCKET_ERRNO/SOCKET_SET_ERRNO
+	    after socket operations to work with new Mac OT SocketsLib.
+	
+	* localaddr.c: Changed errno to SOCKET_ERRNO/SOCKET_SET_ERRNO
+	    after socket operations to work with new Mac OT SocketsLib.
+	
+	* net_read.c: Changed errno to SOCKET_ERRNO/SOCKET_SET_ERRNO
+	    after socket operations to work with new Mac OT SocketsLib.
+	
+	* net_write.c: Changed errno to SOCKET_ERRNO/SOCKET_SET_ERRNO
+	    after socket operations to work with new Mac OT SocketsLib.
+	
+	* sn2princ.c: Changed errno to SOCKET_ERRNO/SOCKET_SET_ERRNO
+	    after socket operations to work with new Mac OT SocketsLib.
+
+Mon May 10 15:26:20 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Fri May  7 18:04:48 1999  Danilo D Almeida  <dalmeida@mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Fixed typo.
+
+Fri May  7 14:39:08 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Return KRB5_REALM_UNKNOWN if
+ 		profile_get_values returns PROF_NO_RELATION or
+ 		PROF_NO_SECTION.
+
+1999-04-01  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* prompter.c (krb5_prompter_posix): Update to use new prompter
+		prototype which takes an extra argument for the window
+		titlebar name.  (From Frank Cusack) [krb5-kdc/662]
+
+Thu Mar 25 18:45:48 1999  Tom Yu  <tlyu@mit.edu>
+
+	* promptusr.c (krb5_os_get_tty_uio): getchar() returns int, not
+	char.
+
+1999-03-12  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* init_os_ctx.c (krb5_os_init_context, krb5_os_free_context):
+		Sample the ccdefault name at the time when we create the
+		context.  Free the ccdefault name when we free the os
+		context.
+
+	* ccdefname.c (krb5_cc_default_name, krb5_cc_set_default_name):
+		Check to make sure the context is valid and return an
+		error if it isn't.
+
+1999-03-11  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ccdefname.c (get_from_os): Add missing call to get_from_registry
+		under windows.
+
+Fri Feb 19 20:49:18 1999  Tom Yu  <tlyu@mit.edu>
+
+	* ccdefname.c (get_from_os): Add missing close-paren; also replace
+	#elif just in case.
+
+Fri Feb  5 01:05:43 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ccdefname.c (get_from_os): On the Windows platform,
+		automatically generate the correct default cache name
+		based on what krb5_cc_dfl_ops is set to.
+
+	* realm_dom.c (krb5_get_realm_domain): Add modifiers so that this
+		function can get exported in a Windows DLL.
+
+Tue Feb  2 16:01:58 1999  Tom Yu  <tlyu@mit.edu>
+
+	* read_pwd.c: Remove reference to CPP symbol "unix".
+
+1999-01-29  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ccdefname.c: Add a new function krb5_cc_set_default_name(),
+		which is used set the default ccname stored in the
+		krb5_context.  All of the OS-specific functions to
+		determine the default ccname is moved to this function.
+		The krb5_cc_default_name() function now just reads the
+		default ccname from the os_context, and will call
+		krb5_cc_set_default_name() to set the default ccname if
+		necessary.
+
+	* t_std_conf: Added functions to test krb5_cc_default_name and
+		krb5_cc_set_default_name().  Fixed the call to
+		krb5_locate_kdc to support the new variables added by
+		the Cygnus initial ticket API merge.
+
+1999-01-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* localaddr.c: On the macintosh, check to see if getmyipaddr
+		returns NULL, and return an error in that case.
+
+Tue Jan  5 00:11:49 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* sn2princ.c (krb5_sname_to_principal): Windows NT5's broken
+ 	 	 resolver gratuitously tacks on a trailing period to the
+ 	 	 hostname (at least it does in Beta2).  Deal with this
+ 	 	 brain-damage.
+
+Tue Dec 22 01:22:24 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* changepw.c: Add a test for _WIN16 as well as _WIN32 for sockets
+ 		workaround (in case we do want to build the 16 bit library
+ 		again someday)
+
+Sat Dec  5 01:12:25 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* localaddr.c: Added missing KRB5_DLLIMP and KRB5_CALLCONF macros
+		from the function definition.
+
+1998-12-04  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* realm_iter.c: New function which iterators over the realms in
+		the krb5.conf file.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+	* lock_file.c (krb5_lock_file): Fix bug where if the fcntl-style
+		lock succeeded, we should return immediately instead of
+		trying to do flock-style locking.  Also check for
+		HAVE_FCNTL_H and defined(F_SETLKW) and
+		defined(F_RDLCK) instead of POSIX_FILE_LOCKS (so we
+		can get rid of a non-standard autoconf symbol.)
+
+1998-10-31  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* lock_file.c (krb5_lock_file): Move the flock() fallback code
+		from fcc_maybe.c into krb5_lock_file().  This works around
+		the bug that certain lossy operating systems (mainly from
+		our good friends at SunSoft) do not support
+		POSIX_FILE_LOCKS on all filesystems (namely tmpfs) but do
+		support flock on those filesystems.
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* c_ustime.c, localaddr.c: moved here from lib/crypto
+
+	* ktdefname.c (krb5_kt_default_name): there is code in the tree
+	(notably, the admin server code) which uses globals to set the
+	keytab which will be used by gssapi.  this is gross, and we need a
+	better answer.  However, even that didn't work if there was an env
+	var or krb5.conf variable, since those override krb5_defkeyname.
+	Add a new global, krb5_overridekeyname, which really does override
+	all the other keytab locators.  While I'm at it, make the buffer
+	overflow checks sane.
+
+Fri Sep 25 22:32:16 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ccdefname.c: We shouldn't try to use the CCache API on Unix
+		systems.  (The maze of #ifdef's was confusing.)
+
+Tue Sep  1 15:44:11 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* ccdefname.c (krb5_cc_default_name): Changed the PC version to
+ 		use the CCache API by default.  Removed the old Macintosh
+ 		code that had been commented out.  (If we need to
+ 		ressurect it, we'll get it from CVS.)
+
+Fri Aug 21 17:37:00 1998  Miro Jurisic  <meeroh@mit.edu>
+
+	* ccdefname.c.c (krb5_cc_default_name): Changed the Mac
+			version to use CCache API by default.
+
+Thu Jul 16 09:59:34 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* changepw.c (krb5_change_password): Changes casts from char * to
+         	krb5_octet * to match krb5_address structure elements.
+
+Wed Jul  1 17:54:56 1998  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* macsock.c(inet_ntoa): Fix obvious bug where we were returning a
+ 		pointer to an automatic variable which should have been a
+ 		static.  Fortunately nothing in the Mac tree was using
+ 		inet_ntoa()....
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* t_std_conf.c (main): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Wed Sep 24 12:10:29 1997 Marshall Vale <mjv@mit.edu> (Checked in 1/13/98)
+
+	* init_os_ctx.c: Changed all PBGetCatInfo to PBGetCatInfoSync for new
+		Universal Headers.
+		
+	* ccdefname.c: Changed all PBGetCatInfo to PBGetCatInfoSync for new
+		Universal Headers.
+
+Fri Feb 27 18:03:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/krb5
+ 		directory, since we've moved the configure.in tests in
+ 		this directory to the toplevel lib/krb5 configure.in
+
+Wed Feb 18 16:24:39 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:19 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jan 30 15:56:15 1998  Tom Yu  <tlyu@mit.edu>
+
+	* changepw.c (krb5_change_password): KRB5_USE_INET ->
+	HAVE_NETINET_IN_H.
+
+Fri Jan  2 21:28:56 1998  Tom Yu  <tlyu@mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Check return of
+	malloc. [krb5-libs/518]
+
+	* changepw.c (krb5_change_password): Check return of
+	malloc. [krb5-libs/518]
+
+Tue Dec 16 11:00:18 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Free hostlist array elements
+		when finished with them.
+
+Sat Dec  6 23:12:23 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Get rid of extra krb5_xfree
+	which caused freeing of memory twice.
+
+Sat Dec  6 02:34:50 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add changepw.c, prompter.c.
+
+	* changepw.c: New file; Cygnus password changing protocol.
+
+	* locate_kdc.c: Add parameter to indicate master KDC.
+
+	* os-proto.h: Reflect changes to locate_kdc.
+
+	* prompter.c: New file; Cygnus initial creds.
+
+	* sendto_kdc.c: Add parameter to indicate master KDC.
+
+Mon Oct  6 11:40:11 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* t_std_conf.c (main): Call krb5_free_context when done.
+
+Wed Oct  1 04:58:34 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Punt some things that are otherwise gotten from
+	include/krb5/configure.in.
+
+	* gmt_mktime.c: Get k5-int.h to get some autoconf symbols.
+
+Tue Sep 30 19:57:27 1997  Tom Yu  <tlyu@mit.edu>
+
+	* timeofday.c: Replaace erroneously named POSIX_TYPES and timetype
+	with plain old time_t, since we're using AC_CHECK_TYPE now to
+	handle it.
+
+Thu Sep 25 21:24:54 1997  Tom Yu  <tlyu@mit.edu>
+
+	* mk_faddr.c: Replace KRB5_USE_INET with something more sane.
+
+	* port2ip.c: Replace KRB5_USE_INET with something more sane.
+
+	* os-proto.h: Replace KRB5_USE_INET with something more sane.
+
+	* locate_kdc.c: Replace KRB5_USE_INET with something more sane.
+
+	* genaddrs.c (krb5_auth_con_genaddrs): Replace KRB5_USE_INET with
+	something more sane.
+
+	* gen_port.c (krb5_gen_portaddr): Replace KRB5_USE_INET with
+	something more sane.
+
+	* full_ipadr.c: Replace KRB5_USE_INET with something more sane.
+
+Thu Sep 18 17:56:00 1997  Tom Yu  <tlyu@mit.edu>
+
+	* hst_realm.c: Replace USE_STRING_H with something more sane.
+
+Mon Sep 15 15:21:12 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* ccdefname.c (krb5_cc_default_name): Returns a const char *.
+
+Sat Aug 16 10:11:20 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gmt_mktime.c (days_in_month): Now const.
+	  Originally by raeburn@cygnus.com from the Kerbnet release
+
+Tue Feb 25 00:29:33 1997  Richard Basch  <basch@lehman.com>
+
+	* read_pwd.c: Define Windows interface for krb5_read_password
+	* win-pwd.rc: Resource file for Windows password dialog box
+	* win-pwd.h: Support definitions for Windows krb5_read_password
+
+Sat Feb 22 22:41:02 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Fri Feb 21 20:06:55 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* def_realm.c: Remove extern declaration of un-used krb5_config_file.
+
+Fri Feb  7 11:11:18 1997  Richard Basch  <basch@lehman.com>
+
+	* mk_faddr.c (krb5_make_fulladdr): Add FAR declarations (win16)
+
+Thu Nov 21 11:55:16 EST 1996	Richard Basch	<basch@lehman.com>
+
+	* Makefile.in: win32 build
+
+	* ccdefname.c, def_realm.c, free_hstrl.c, genaddrs.c, hst_realm.c,
+	init_os_ctx.c, ktdefname.c, localaddr.c, sn2princ.c, timeofday.c,
+	ustime.c
+		DLL export several more common functions (see lib/krb5.def
+		for the full list of functions exported)
+
+Thu Feb  6 15:46:24 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Jan  2 17:19:11 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Update to new library build procedure.
+
+Wed Nov 13 02:53:31 1996  Tom Yu  <tlyu@mit.edu>
+
+	* osconfig.c: Add warning re: global variables.
+
+	* ktdefname.c, osconfig.c: Revert previous kt_default_name
+	changes.
+
+	* ktdefname.c (krb5_kt_default_name): Fix a few memory-leak type
+	problems in previous changes.
+
+Tue Nov 12 22:07:55 1996  Tom Yu  <tlyu@mit.edu>
+
+	* osconfig.c: Remove krb5_defkeyname to catch other things that
+	may break.
+
+	* ktdefname.c (krb5_kt_default_name): Change logic to no longer
+	use a global variable; also add krb5_kt_set_default_name() to
+	allow for the changing of the default keytab name in the context.
+
+Wed Nov  6 16:24:56 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* init_os_ctx.c (os_init_paths): Don't ignore errors found from
+		parsing the config file.  Currently, we return an error if
+		the profile isn't found.  In the future we can maybe do
+		something better with intelligent defaulting if krb5.conf
+		doesn't exist, but we don't have this today.
+
+Thu Aug 22 15:19:47 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* an_to_ln.c (db_an_to_ln): Remove references to dead BERK_DB_DBM
+	 	code.
+
+Tue Jul 30 19:15:55 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (check-unix): Comment out an_2_ln tests that use
+        database.
+
+	* an_to_ln.c (krb5_aname_to_localname): Make the db lookup verison
+        of aname_2_localname optional.
+
+Sun Jul 28 22:39:12 1996  Tom Yu  <tlyu@mit.edu>
+
+	* an_to_ln.c (aname_do_match): #elif HAVE_REGEXP_H should have
+		been HAVE_REGEXPR_H
+
+Fri Jul 26 15:58:32 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in, an_to_ln.c (do_replacement, aname_do_match): use
+ 	the compile() function in -lgen on solaris.  Check for the
+ 	relevant stuff at configure-time
+
+Fri Jul 12 21:38:15 1996  Marc Horowitz  <marc@mit.edu>
+
+	* ktdefname.c (krb5_kt_default_name): allow the default keytab name
+	to be specified in the config file.
+
+Wed Jun 12 01:12:32 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* net_read.c (krb5_net_read):
+	* net_write.c (krb5_net_write): In case of an error, on Windows
+		machines, set errno from SOCKET_ERRNO, since the interface
+		assumes the error is passed back the errno global
+		varaible.  This really needs to be fixed sometime...
+
+	* read_msg.c: If ECONNABORTED is not defined, try using the
+		Winsock version of the error code (WSAECONNABORTED).
+
+Mon Jun 10 21:48:45 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* read_pwd.c:
+	* promptusr.c:
+	* lock_file.c:
+	* kuserok.c:
+	* ktdefname.c (krb5_kt_default_name): 
+	* init_os_ctx.c (os_init_paths): 
+	* ccdefname.c: 
+	* an_to_ln.c (db_an_to_ln): Change _WINDOWS to _MSDOS, and add
+	 	check for _WIN32.
+
+Thu Apr 18 16:24:44 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* macsock.c (getsockname, getpeername): Correctly implement
+ 		getsockname(), so it does getsockname(), not
+ 		getpeername(), and add the function getpeername().
+
+Sat May 11 10:08:15 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Need to include sys/types.h before regexp.h in
+		test to see if regcomp works.
+		Add V5_USE_SHARED_LIB for the tests that are built.
+
+Tue Apr 30 17:51:47 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Test that regcomp actually works.
+
+	* Makefile.in (check-unix): Use $(RM).
+
+	* t_an_to_ln.c (main): Print principal name when an error is
+	detected.
+
+Thu Apr 11 22:15:44 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* ustime.c (krb5_us_timeofday): When doing the time offset
+		adjustments, make sure the microseconds field doesn't go
+		negative.
+
+Thu Mar 28 17:20:12 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* DNR.c: Replace eight-year-old version of this file with the
+		latest version from the Code Warrior MacTCP files.  
+
+	* macsock.c: Use new MacTCP header files.
+
+Wed Mar 27 18:31:44 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* macsock.c (gethostbyname, gethostbyaddr): Use universal
+		procedure pointers (UPP), which are required on the Mac
+		Power PC.
+
+Mon Mar 18 21:49:39 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add KRB5_RUN_FLAGS
+
+	* Makefile.in: Use runtime flags.
+
+Mon Mar 18 17:30:54 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* sn2princ.c (krb5_sname_to_principal): Add casting to avoid warnings.
+
+Mon Mar 18 14:18:58 EST 1996  Richard Basch  <basch@lehman.com>
+
+	* sn2princ.c: Do not try to re-assign const variables.
+
+Sun Mar 17 20:42:17 1996  Ezra Peisach  <epeisach@mit.edu>
+
+        * configure.in: Add USE_ANAME, KRB5_LIBRARIES
+
+	* Makefile.in: Properly use libraries as specified by configure
+
+Wed Mar 13 13:11:49 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* t_std_conf.c: Include string.h
+
+Thu Feb 29 16:14:46 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sendto_kdc.c (krb5_sendto_kdc): Take out calls to
+		SOCKET_INITIALIZE and SOCKET_CLEANUP.  This gets done in
+		win_glue.c, and we only need to do this once.  (XXX What
+		about Macintosh?)
+
+Tue Feb 27 18:48:03 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* hostaddr.c (krb5_os_hostaddr): Use #define NEED_SOCKETS instead
+		of #including <netdb.h>  (this breaks under windows).
+
+Mon Feb 26 17:04:26 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* promptusr.c: Don't compile promptusr for Windows or Macintosh.
+
+Sat Feb 24 18:57:56 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* ktdefname.c (krb5_kt_default_name): Under Windows, assume that
+		the keytab file is located in the Windows directory.
+
+Thu Feb 22 13:16:16 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (check-unix): Set LD_LIBRARY_PATH for kdb5_anadd.
+
+	* hostaddr.c (krb5_os_hostaddr): Set magic number in structure.
+
+	* full_ipadr.c (krb5_make_full_ipaddr): Set magic number in structure.
+
+Sat Feb 17 00:05:38 1996  Theodore Y. Ts'o  <tytso@pao.MIT.EDU>
+
+	* def_realm.c (krb5_get_default_realm): If the configuration file
+		does not exist (context->profile == NULL) return
+		KRB5_CONFIG_CANTOPEN; if the default realm is not defined
+		in the configuration file, return an error message saying
+		so.   These changes just make the diagnostic error
+		messages more clear.
+
+Thu Jan 11 18:32:54 1996  Ezra Peisach  (epeisach@paris)
+
+	* Makefile.in (check-unix): Ultrix test does not support -x.
+
+Fri Jan  5 09:00:47 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Add parrentheses for assignment
+		in conditional. (gcc -Wall)
+
+	* init_os_ctx.c (krb5_os_init_context): Remove unused variables
+
+	* an_to_ln.c (aname_do_match): Initialize local variable before
+		referenced. 
+
+Thu Jan  4 22:23:04 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* hostaddr.c (krb5_os_hostaddr): New function which takes a
+		hostname and returns a list of krb5 addresses.  (This is
+		basically a glue routine that converts the result of
+		gethostbyname() to krb5 addresses.)
+
+Thu Dec 21 17:51:58 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (t_an_to_ln): Use $(LD) instead of $(CC) to link
+		final executables, so that we can more easily use purify.
+
+	* hst_realm.c (krb5_get_host_realm): Eliminate memory leak; realm
+		was already being allocated by the profile library; no
+		reason to reallocate it again.
+
+Wed Nov 15 10:53:16 1995    <tytso@rsts-11.mit.edu>
+
+	* promptusr.c: New function for doing generic tty input and output.
+		Eventually read_password should use this function.
+
+Wed Nov 15 20:40:03 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* lock_file.c (krb5_lock_file): initialize lock_arg to a copy of a
+ 	static (thus zero) struct flock, to avoid panic'ing sunos 4.1.4.
+
+Sun Nov 12 05:31:21 1995  Mark W. Eichin  <eichin@cygnus.com>
+
+	* def_realm.c (krb5_get_default_realm): check for PROF_NO_PROFILE
+	and return KRB5_CONFIG_CANTOPEN instead of BADFORMAT so that the
+	user in the end knows what is going on.
+
+Mon Oct  9 19:05:24 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ktdefname.c (krb5_kt_default_name): If profile_secure flag is
+		set in the context then do not allow changing the location
+		of the default keytab with an environment variable.
+
+Fri Oct  6 22:04:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Thu Oct  5 07:49:26 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* init_os_ctx.c (krb5_secure_config_files): New function that 
+		will set flag and path to prevent user from overriding
+		configuration files with environment variables.
+
+Mon Oct  2 17:36:38 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* init_os_ctx.c (krb5_os_init_context): Put back in the
+		KRB5_CONFIG environment before setting to default.
+
+Tue Sep 26 22:46:01 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* init_os_ctx.c (krb5_os_init_context): use profile_init_path for
+	unix, and DEFAULT_PROFILE_PATH.
+
+Fri Sep 29 16:31:47 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* osconfig.c: Remove krb5_lname_file; it's not used any more.
+
+Mon Sep 25 16:58:17 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Fri Sep 22 15:57:33 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* write_msg.c (krb5_write_message): check the real length
+	variable, not the net version.
+
+Wed Sep 20 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* macsock.c:  Added TCP streams to the emulation package.  gethostname
+		now no longer returns true cannonical hostnames.
+
+Wed Sep 13 11:01:18 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: had to define away DBFLAGS for the PC.
+
+Mon Sep 11 17:46:18 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* genaddrs.c (krb5_auth_con_genaddrs): Replace function
+		declaration back to int instead of SOCKET due to prototype
+		mismatching. 
+
+Sun Sep 10 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* ustime.c: use the version of getTimeZoneOffset in :os:crypto: for
+		_MACINTOSH.
+
+Wed Sep  6 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* localaddr.c changed name to oslocaladdr.c for metrowerks project
+		file management.
+
+	* ustime.c:  changed mac version of krb5_crypto_us_timeofday to compile
+		with contemporary header files for metrowerks
+
+	* macsock.c:  added tcp stream support to suppliment the udp.  Added
+		getsockname.  Fixed gethostname to stop appending '.' to the
+		end of a connonical hostname.
+
+	* net_write.c:  need to cast file descriptors to SOCKETs
+
+	* net_read.c:  need to cast file descriptors to SOCKETs
+
+	* krbfileio.c:  mac doesn't support fsync, define the usage out
+
+	* init_os_cxt.c:  move the default location of the krb conf file to
+		the preferences folder.  Added some routines to take a 
+		mac FSSpec and turn it into a mac pathname string.
+
+	* hst_realm.c:  assign a NULL to retrealms to clean up a warning.
+
+	* genaddrs.c:  support getsockname from macsock
+
+	* ccdefname.c:  move the cred cache to the preferneces folder for mac
+
+	* an_to_ln.c:  turn functions off because I don't have a dbm library
+
+	* timeofday.c:  make krb5_timeofday use krb5_crypto_us_timeofday to 
+		incorperate the epoch difference between mac and unix.
+
+Fri Sep  1 00:47:27 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (check-unix): Add a test case to make sure
+		krb5_get_host_realm does something sane when passed in a
+		hostname which doesn't have a default domain.
+
+	* hst_realm.c (krb5_get_host_realm): If an hostname does not have
+		a domain, don't try to get a domain default (which
+		results in a strange error being returned).
+
+	* toffset.c: Added new file which implements the abstract
+		interfaces for manipulating the time offset fields in the
+		os context.
+
+	* ustime.c (krb5_us_timeofday): Add support for using the time
+		offset fields in the os context.
+
+	* timeofday.c (krb5_timeofday): Add support for using the time
+		offset fields in the os context.
+
+	* init_os_ctx.c (krb5_os_init_context): Initialize the time offset
+		and flags fields in the os context.
+
+Thu Aug 31 17:24:48 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* t_an_to_ln.c - Translate until error and return status.
+	* Makefile.in - Test aname_to_lname under check-unix.
+
+Thu Aug 24 18:56:35 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list.
+
+Wed Aug 16 02:45:19 1995  Chris Provenzano <proven@mit.edu>
+
+        * lock_file.c (krb5_lock_file()), unlck_file.c (krb5_unlock_file()):
+		Pass the fd in instead of converting it from FILE *.
+
+Fri Aug  4 22:51:15 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* kuserok.c (krb5_kuserok): Add parens to shut up gcc -Wall
+
+	* genaddrs.c (krb5_auth_con_genaddrs): Add parens to shut up gcc
+		-Wall
+
+	* an_to_ln.c: Include ctype.h to get some prototypes; also add
+		parens to shut up gcc -Wall
+
+Fri Jul 28 23:28:11 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* sn2princ.c (krb5_sname_to_principal): GDon't use default realm
+        just because we are on local machine. Instead, go through normal
+        translations.
+
+Fri Jul 7 16:32:41 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Find com_err in TOPLIBD.
+
+Thu Jul  6 17:26:03 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* localaddr.c: moved to lib/crypto/os; just a stub here.
+
+	* ustime.c: moved to lib/crypto/os; just a stub here.
+
+Thu Jul  6 09:56:56 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean): Remove t_an_to_ln.o
+
+Wed July  5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* an_to_ln.c added _MACINTOSH conditions
+	* genaddrs.c added HAS_MACSOCK_H conditions
+	* krbfileio.c added THREEPARAMOPEN
+	* kuserok.c added THREEPARAMOPEN
+	* macsock.c added stub for gethostnameA
+	* mk_faddr.c added HAS_MACSOCK_H conditions
+	* read_pwd.c added _MACINTOSH condition
+	* sys_log.c added _MACINTOSH condition
+
+Fri Jun 30 14:44:17 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* an_to_ln.c - Add profile logic to aname_to_lname.  We can now
+		specify databases, rules and explicit mappings to convert
+		between auth name and local name.
+	* t_an_to_ln.c - Rudimentary test procedure.  Needs work to be automatic
+	* configure.in - Add --with-aname-dbm to select between Berkeley and
+		DBM aname database format.
+	* Makefile.in - Add definitions to select aname rules.
+
+Tue Jun 27 15:48:41 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* read_pwd.c(intr_routine) - Add signal name argument to signal handler
+		to conform to prototype.
+
+Sat Jun 10 23:07:27 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* genaddrs.c: krb5_auth_context redefinitions
+
+Fri Jun  9 22:08:33 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gmt_mktime.c (gmt_mktime): Change assertion to check to make
+		sure that the day of the month is >= 1, not 0.
+
+Fri Jun  9 19:34:29 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed Jun  7 14:43:56 1995    <tytso@rsx-11.mit.edu>
+
+	* def_realm.c (krb5_get_default_realm), get_krbhst.c
+		(krb5_get_krbhst), hst_realm.c (krb5_get_host_realm), 
+		init_os_ctx.c (krb5_os_init_context), osconfig.c, 
+		realm_dom.c (krb5_get_realm_domain): Remove old ifdef'ed
+		code which read in krb.conf and krb.realms.
+
+	* read_pwd.c (krb5_read_password): Remove old #ifdef notdef code.
+		Significantly simplified and cleaned up function.
+		Removed BSD 4.3 compatibility code.  (If we ever need
+		to make this work on a non-POSIX system, we'll supply
+		POSIX termios emulation functions in src/lib/krb5/posix.)
+
+Fri Jun 2 17:54:12 1995 Keith Vetter (keithv@fusion.com)
+
+	* net_read.c, net_write.c: made to work with sockets.
+
+Fri May 26 20:20:58 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for building shared libraries.
+
+Thu May 25 15:33:45 1995 Keith Vetter (keithv@fusion.com)
+
+	* os-proto.h: moved prototype for krb5_make_fulladdr to
+	   los-proto.h since it's needed by the krb directory.
+	* ktdefnam.c: fixed signed/unsigned mismatch.
+	* read_pwd.c: pc stub didn't track changes to the real routines
+	   parameter list (const was added).
+
+Tue May 23 16:29:24 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* t_std_conf.c, timeofday.c, unlck_file.c: Rearrange #include
+		files so that krb5.h gets included first, so that the
+		debugging information can be more efficiently collapsed
+		since the type numbers will be the same.
+
+Tue May 16 10:33:03 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gmt_mktime.c	- Use the actual year instead of the number of years
+			  since 1900 when determining if a year has a leapday.
+			  Makes dates after February in the year 2000 correct.
+
+Mon May 15 05:08:05 1995    <tytso@rsx-11.mit.edu>
+
+	* ktdefname.c (krb5_kt_default_name): Use the KRB5_KTNAME
+		environment variable to override the default location of
+		the keytab.
+
+Mon May  8 22:19:23 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* read_pwd.c (krb5_read_password): use volatile on all
+		systems. Let configure define volatile to nothing on
+		systems without. 
+
+	* configure.in: Add HAS_ANSI_VOLATILE
+
+	* mk_faddr.c (krb5_make_fulladdr): Allocate enough memory for
+		raddr contents.
+
+	* read_pwd.c (krb5_read_password): Make arguments prompt and
+		prompt2 const char * for convenience to callers.
+
+Mon May  1 17:05:21 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* init_os_ctx.c (krb5_set_config_files): Added required const to
+		function declaration to be compatbile with call to
+		profile_init. 
+
+Mon May 01 15:56:32 1995  Chris Provenzano (proven@mit.edu)
+
+        * genaddrs.c (krb5_auth_con_genaddrs()),
+	* mk_faddr.c (krb5_make_fulladdr()), os-proto.h :
+                Changes to auth_context to better support full addresses.
+
+Sun Apr 30 16:03:59 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* osconfig.c: Global variables krb5_config_file and
+		krb5_trans_file conditionalized on OLD_CONFIG_FILES.
+
+Sat Apr 29 07:07:22 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* init_os_ctx.c (krb5_set_config_files): New function.  Provides a
+		way to set a new set of config files for a particular OS
+		context.
+
+	* init_os_ctx.c (krb5_os_init_context): Don't return an error if 
+		profile_init() returns an error.
+
+Fri Apr 28 09:58:31 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	Move adm_conn.c from libkrb5 to libkadm.
+
+Thu Apr 27 17:50:14 1995 Keith Vetter (keithv@fusion.com)
+
+	* adm_conn.c: added constant to pull in needed PC code, and
+	   removed two unused variables.
+	* genaddrs.c: needed casts on getsockname and getpeername calls.
+	* mk_faddr.c: the int->byte code needed explicit casts.
+	* os-proto.h: added missing prototype for krb5_make_fulladdr.
+
+Wed Apr 26 16:00:52 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* Add adm_conn.c - module to provide a connection to an administrative
+	  (kpasswd/kadmin) server.
+
+Wed Apr 27 11:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* osconfig.c: krb5_find_config_files only used for OLD_CONFIG_FILES.
+	* init_os_.c: Get config file location via windows ini files.
+
+Thu Apr 27 13:04:54 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean): Remove t_std_conf.o 
+
+Tue Apr 25 21:58:23 1995  Chris Procenzano (proven@mit.edu)
+
+	* Makefile.in : Added source files mk_faddr.c and genaddrs.c.
+	* mk_faddr.c (krb5_mk_fulladdr()): Makes a full address from
+		a struct sockaddr_in.
+	* genaddrs.c (krb5_auth_con_genaddrs()) : Generate a full address
+		from the active file descriptor and place it in the 
+		auth_context for the calls mk_safe(), mk_priv(), mk_safe(), 
+		rd_cred(), rd_priv(), and rd_safe().
+	* gen_rname.c (krb5_gen_replay_name()) : Fixed to take any type of
+		krb5_address and generate a rcache name.
+	* os-proto.h (krb5_make_full_ipaddr()) : Removed prototype.
+
+Tue Apr 25 14:09:26 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* t_std_conf.c (main): Add declaration of optarg.
+
+Tue Apr 25 04:50:13 1995  Chris Procenzano (proven@mit.edu)
+
+	* locate_kdc.c (krb5_locate_kdc()): Pass a NUL terminated realm
+		to profile_get_values(). 
+
+Mon Apr 24 17:20:14 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* locate_kdc.c (krb5_locate_kdc): Don't deref NULL pointer
+	returned from profile_get_values if profile is not set.
+
+Sat Apr 22 00:11:12 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in, configure.in, t_std_conf.c: Add test program to
+		test the standard configuration krb5 routines.
+
+	* osconfig.c: Don't define krb5_kdc_udp_portname and
+		krb5_kdc_sec_portname any more.	 There's no real point...
+
+	* hst_realm.c (krb5_get_krbhst): Strip off the trailing dot from
+		the hostname if present.
+
+	* locate_kdc.c (krb5_locate_kdc): Use the profile code to get the
+		list of Kerberos servers (plus port numbers) for a
+		particular realm from [realms]/<realm>/kdc
+
+Fri Apr 21 11:38:45 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* def_realm.c (krb5_get_default_realm): Use the profile code to
+		get the default realm from [libdefaults]/default_realm.
+
+	* get_krbhst.c (krb5_get_krbhst): Use the profile code to get the
+		list of Kerberos servers for a particular realm from 
+		[realms]/<realm>/kdc
+
+	* realm_dom.c (krb5_get_realm_domain):	Use the profile code to
+		get the default domain postfix for a realm (used only to
+		convert V4 -> V5 principals) from 
+		[realms]/<realm>/default_domain
+
+	* hst_realm.c (krb5_get_host_realm): Use the profile code to get
+		the default realm given a particular host from
+		[domain_realm]/<host|domain>
+
+	* init_os_ctx.c (krb5_os_init_context): When the OS context is
+		initialized, also initialize the profile file.	This loads
+		in the /etc/krb5.conf file.
+
+Wed Apr 19 13:50:19 1995  Ezra Peisach	(epeisach@kangaroo.mit.edu)
+
+	* def_realm.c: (krb5_get_default_realm) - remove global default realm.
+		Moved into the context. (krb5_set_default_realm) added.
+
+Fri Apr 14 22:15:00 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* an_to_ln.c (dbm_an_to_ln): Don't compile dbm_an_to_ln() if
+		USE_DBM_LNAME isn't defined.
+
+Fri Apr 14 15:15:48 1995    <tytso@rsx-11.mit.edu>
+
+	* hst_realm.c (krb5_get_host_realm): Eliminate memory leak in the
+		unlikely case that gethostname fails.
+
+		If the krb.realms file isn't available, use the default
+		realm of the host.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+	* read_pwd.c: __STDC__ conditional also checks the _WINDOWS define.
+
+Fri Apr 7 15:32:04 1995 Keith Vetter (keithv@fusion.com)
+
+	* ccdefname.c: 
+	   changed windows stored filename syntax--dropped the 'FILE:' part.
+	   changed buffer from malloc to static since we don't want it 
+	    ever to fail, and nobody checks it for errors.
+
+Wed Apr 5 16:32:07 1995 Keith Vetter (keithv@fusion.com)
+
+	* get_krbh.c: better error handling--old return values were 
+	   being overwritten.
+	* locate_kdc.c: added new error code KRB5_REALM_CANT_RESOLVE for
+	   when we have realm names but can't find their addresses.
+	   Also, fixed up indenting of an if clause.
+	* sendto_kdc.c: added winsock init/destroy calls because some
+	    PC tcp/ip stacks seem to need it.
+
+Fri Mar 31 16:30:03 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* realm_dom.c (krb5_get_realm_domain): Don't indent #ifdef's!
+
+	* hst_realm.c (krb5_get_host_realm): Don't indent #ifdef's!
+
+Thu Mar 30 15:54:54 1995 Keith Vetter (keithv@fusion.com)
+
+	* localaddr.c: in Windows/Mac code, fixed bug due to wrong level
+	   of indirection on memcpy call.
+
+Tue Mar 28 19:22:28 1995 Keith Vetter (keithv@fusion.com)
+
+	For Windows, added calls to get the default config, realms and
+	ccache files out of a windows ini file.
+	* ccdefname.c: does this for the credential cache.
+	* osconfig.c: does this for the config and realms files.
+	* get_krbh.c, realm_do.c, hst_real.c, def_real.c: added calls to
+	   set the default values.
+
+Tue Mar 28 18:35:20 1995  John Gilmore	(gnu at toad.com)
+
+	* DNR.c:  Add Apple MacTCP source file for domain name resolution.
+	* macsock.c:  Add fake socket support routines for MacTCP.
+	* Makefile.in (OBJS, SRCS):  Add DNR and macsock.
+	* ccdefname.c:	On Mac, default cred cache is "STDIO:krb5cc" for now.
+	FIXME, this needs to find the Preferences folder and use that.
+	FIXME, shouldn't be conditioned on HAVE_MACSOCK_H.
+	* gmt_mktime.c:	 Use HAVE_SYS_TYPES_H.
+	* krbfileio.c:	Remove <sys/types.h>.
+	* localaddr.c, sendto_kdc.c:  Convert to more generic socket
+	support.  Use closesocket instead of close, SOCKET_ERRNO rather
+	than errno, SOCKET rather than int, etc.
+	* localaddr.c:	Use getmyipaddr() from macsock.c, if on Mac.
+	Add FIXME for multiple local addresses.
+	* lock_file.c:	Provide a dummy version for MacOS.
+	* read_pwd.c (ECHO_PASSWORD):  Add #ifdef's to avoid all the ioctls
+	and other stuff that turn off echoing.	This is useful for debugging
+	on MacOS.  FIXME:  ECHO_PASSWORD needs to be added to configure.in.
+	* ustime.c:  Bring in Mac-specific time-and-timezone code.  It
+	probably isn't hooked up correctly, yet.
+
+Mon Mar 27 14:16:39 1995  John Gilmore	(gnu at toad.com)
+
+	* full_ipadr.c, gen_rname.c, port2ip.c, read_msg.c, write_msg.c:
+	Remove explicit includes of socket files.
+	* locate_kdc.c:	 Remove <sys/types.h> and "os-proto.h".
+
+	* macsock.c (connect, send, recv):  Add for K5 compatability.
+	(getmyipaddr):	Add for use in K5.
+
+	* macsock.c:  Add Mac socket support file, verbatim from K4 release.
+
+Fri Mar 24 17:58:15 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* locate_kdc.c: Don't include sys/socket.h, netdb.h, netinet/in.h,
+		since these files are already included by k5-config.h
+	
+	* sendto_kdc.c: Don't include sys/socket.h, since it is already
+		included by k5-config.h
+
+	* sn2princ.c: Don't include netdb.h, since it is already included
+		by k5-config.h
+
+Thu Mar 23 23:11:36 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* realm_dom.c (krb5_get_realm_domain): Don't indent preprocessor
+		directives.  (Not portable).
+
+	* hst_realm.c (krb5_get_host_realm): Don't indent preprocessor
+		directives.  Removed excess close paren introduced by
+		Keith.
+
+Wed Mar 22 18:59:47 1995 Keith Vetter (keithv@fusion.com)
+
+	* hst_realm.c, realm_dom.c: windows DLL can't use fscanf so had
+	   to write a couple of routines to read what we need from the file.
+
+Wed Mar 22 13:30:35 1995 Keith Vetter (keithv@fusion.com)
+
+	* an_to_ln.c, kuserok.c: last two os routines ported to the PC.
+
+Fri Mar 17 19:56:39 1995  John Gilmore	(gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Eliminate, duplicates config/pre.in.
+	* localaddr.c:	Remove socket include files now handled in k5-int.h.
+
+Wed Mar 15 12:19:47 1995 Keith Vetter (keithv@fusion.com)
+
+	* sendto_kdc.c: made to work on the PC.
+
+Tue Mar	 7 22:15:00 1995 Keith Vetter <keithv@fusion.com>
+
+	* sendto_kdc.c: stubbed on the PC for now.
+
+Tue Mar	 7 19:54:17 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: take out ISODE_DEFS, ISODE_INCLUDE.
+
+Tue Mar 7 13:35:21 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.c: ported all the c files except an_to_ln, kuserok, and
+	  sendto_kdc which have windows stubs.
+	* Makefile.in: reflects above changes.
+
+Wed Mar 1 17:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work on the PC
+	* ustime.c: added section for time on the PC
+	* localaddr.c: added section for the PC--returns local IP address
+	N.B. not sure how we're going to handle different machine dependent
+	code changes. For now it's just added to the end of the file. Later,
+	we have to decide on a solution for all.
+
+Tue Feb 28 01:07:37 1995  John Gilmore	(gnu at toad.com)
+
+	* *.c:	Avoid <krb5/...> includes.
+
+Fri Feb	 3 08:24:18 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* gmt_mktime.c (gmt_mktime): Don't double count the leap day in a
+		leap year.
+
+Sun Jan 22 18:23:37 1995  John Gilmore	(gnu@cygnus.com)
+
+	* get_krbhst.c (krb5_get_krbhst):  Declare realm argument const,
+	to match prototype.
+
+Wed Jan 18 11:08:59 1995    <tytso@rsx-11.mit.edu>
+
+	* sendto_kdc.c (krb5_sendto_kdc): Fix use of connected sockets;
+		previously krb5_sendto_kdc only used one socket per
+		address family.	 This doesn't work; it now uses one
+		socket per address. (krb5-bugs #938)
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+	* Actually move the file init_ctx.c to init_os_ctx.c in the CVS
+		repository and also rename the routine	krb5_free_os_context()
+		to krb5_os_free_context().
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+	* Moved init_ctx.c to init_os_ctx.c because a library cannot
+		have more than on file with the same name. See krb/init_ctx.c
+
+Mon Dec 19 15:20:35 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* init_ctx.c: New file.	 Initializes and frees the krb5_os_context
+	  structure. 
+
+	* realm_dom.c (krb5_get_realm_domain): Fixed minor bug where the
+		length of the returned domain was calculated incorrectly.
+
+Mon Oct 31 17:04:08 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* lock_file.c: Back out POSIX_FILE_LOCKS change.  (Should be
+		depending on autoconf.h to supply this #define if
+		necessary.) 
+
+Thu Oct 13 17:24:31 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* configure.in: Add ISODE_DEFS
+
+Fri Oct	 7 13:23:18 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add test for unistd.h
+
+	* lock_file.c: Use POSIX_FILE_LOCKS if _POSIX_VERSION is defined
+		in unistd.h
+
+Thu Sep 22 20:46:08 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Put in correct dependency order of configure.in
+		lines.
+
+Wed Jul	 6 13:26:59 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* gmt_mktime.c (gmt_mktime): New file, new function. Similar to
+	POSIX mktime, but always works in GMT.
+	configure.in, Makefile.in: build gmt_mktime.
+
+Wed Jun 22 15:49:30 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* locate_kdc.c (krb5_locate_kdc): Fixed default port numbers so
+	they are loaded in network byte order instead of host byte order.
+
+
diff --git a/mechglue/src/lib/krb5/os/Makefile.in b/mechglue/src/lib/krb5/os/Makefile.in
new file mode 100644
index 000000000..49690e41f
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/Makefile.in
@@ -0,0 +1,557 @@
+thisconfigdir=./..
+myfulldir=lib/krb5/os
+mydir=os
+BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=os
+##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
+
+STLIBOBJS= \
+	accessor.o	\
+	an_to_ln.o	\
+	c_ustime.o	\
+	def_realm.o	\
+	ccdefname.o	\
+	changepw.o	\
+	dnsglue.o	\
+	dnssrv.o	\
+	free_krbhs.o	\
+	free_hstrl.o	\
+	full_ipadr.o	\
+	get_krbhst.o	\
+	gen_port.o	\
+	genaddrs.o	\
+	gen_rname.o	\
+	gmt_mktime.o	\
+	hostaddr.o	\
+	hst_realm.o	\
+	init_os_ctx.o	\
+	krbfileio.o	\
+	ktdefname.o	\
+	kuserok.o	\
+	mk_faddr.o	\
+	localaddr.o	\
+	locate_kdc.o	\
+	lock_file.o	\
+	net_read.o	\
+	net_write.o	\
+	osconfig.o	\
+	port2ip.o	\
+	prompter.o	\
+	read_msg.o	\
+	read_pwd.o	\
+	realm_dom.o	\
+	realm_iter.o	\
+	send524.o	\
+	sendto_kdc.o	\
+	sn2princ.o	\
+        thread_safe.o   \
+	timeofday.o	\
+	toffset.o	\
+	unlck_file.o	\
+	ustime.o	\
+	write_msg.o
+
+OBJS= \
+	$(OUTPRE)accessor.$(OBJEXT)	\
+	$(OUTPRE)an_to_ln.$(OBJEXT)	\
+	$(OUTPRE)c_ustime.$(OBJEXT)	\
+	$(OUTPRE)def_realm.$(OBJEXT)	\
+	$(OUTPRE)ccdefname.$(OBJEXT)	\
+	$(OUTPRE)changepw.$(OBJEXT)	\
+	$(OUTPRE)dnsglue.$(OBJEXT)	\
+	$(OUTPRE)dnssrv.$(OBJEXT)	\
+	$(OUTPRE)free_krbhs.$(OBJEXT)	\
+	$(OUTPRE)free_hstrl.$(OBJEXT)	\
+	$(OUTPRE)full_ipadr.$(OBJEXT)	\
+	$(OUTPRE)get_krbhst.$(OBJEXT)	\
+	$(OUTPRE)gen_port.$(OBJEXT)	\
+	$(OUTPRE)genaddrs.$(OBJEXT)	\
+	$(OUTPRE)gen_rname.$(OBJEXT)	\
+	$(OUTPRE)gmt_mktime.$(OBJEXT)	\
+	$(OUTPRE)hostaddr.$(OBJEXT)	\
+	$(OUTPRE)hst_realm.$(OBJEXT)	\
+	$(OUTPRE)init_os_ctx.$(OBJEXT)	\
+	$(OUTPRE)krbfileio.$(OBJEXT)	\
+	$(OUTPRE)ktdefname.$(OBJEXT)	\
+	$(OUTPRE)kuserok.$(OBJEXT)	\
+	$(OUTPRE)mk_faddr.$(OBJEXT)	\
+	$(OUTPRE)localaddr.$(OBJEXT)	\
+	$(OUTPRE)locate_kdc.$(OBJEXT)	\
+	$(OUTPRE)lock_file.$(OBJEXT)	\
+	$(OUTPRE)net_read.$(OBJEXT)	\
+	$(OUTPRE)net_write.$(OBJEXT)	\
+	$(OUTPRE)osconfig.$(OBJEXT)	\
+	$(OUTPRE)port2ip.$(OBJEXT)	\
+	$(OUTPRE)prompter.$(OBJEXT)	\
+	$(OUTPRE)read_msg.$(OBJEXT)	\
+	$(OUTPRE)read_pwd.$(OBJEXT)	\
+	$(OUTPRE)realm_dom.$(OBJEXT)	\
+	$(OUTPRE)realm_iter.$(OBJEXT)	\
+	$(OUTPRE)send524.$(OBJEXT)	\
+	$(OUTPRE)sendto_kdc.$(OBJEXT)	\
+	$(OUTPRE)sn2princ.$(OBJEXT)	\
+        $(OUTPRE)thread_safe.$(OBJEXT)  \
+	$(OUTPRE)timeofday.$(OBJEXT)	\
+	$(OUTPRE)toffset.$(OBJEXT)	\
+	$(OUTPRE)unlck_file.$(OBJEXT)	\
+	$(OUTPRE)ustime.$(OBJEXT)	\
+	$(OUTPRE)write_msg.$(OBJEXT)
+
+SRCS= \
+	$(srcdir)/accessor.c    \
+	$(srcdir)/an_to_ln.c	\
+	$(srcdir)/c_ustime.c	\
+	$(srcdir)/def_realm.c	\
+	$(srcdir)/ccdefname.c	\
+	$(srcdir)/changepw.c	\
+	$(srcdir)/dnsglue.c	\
+	$(srcdir)/dnssrv.c	\
+	$(srcdir)/free_krbhs.c	\
+	$(srcdir)/free_hstrl.c	\
+	$(srcdir)/full_ipadr.c	\
+	$(srcdir)/get_krbhst.c	\
+	$(srcdir)/gen_port.c	\
+	$(srcdir)/genaddrs.c	\
+	$(srcdir)/gen_rname.c	\
+	$(srcdir)/gmt_mktime.c	\
+	$(srcdir)/hostaddr.c	\
+	$(srcdir)/hst_realm.c	\
+	$(srcdir)/init_os_ctx.c	\
+	$(srcdir)/krbfileio.c	\
+	$(srcdir)/ktdefname.c	\
+	$(srcdir)/kuserok.c	\
+	$(srcdir)/mk_faddr.c	\
+	$(srcdir)/localaddr.c	\
+	$(srcdir)/locate_kdc.c	\
+	$(srcdir)/lock_file.c	\
+	$(srcdir)/net_read.c	\
+	$(srcdir)/net_write.c	\
+	$(srcdir)/osconfig.c	\
+	$(srcdir)/prompter.c	\
+	$(srcdir)/read_msg.c	\
+	$(srcdir)/read_pwd.c	\
+	$(srcdir)/realm_dom.c	\
+	$(srcdir)/realm_iter.c	\
+	$(srcdir)/port2ip.c	\
+	$(srcdir)/send524.c	\
+	$(srcdir)/sendto_kdc.c	\
+	$(srcdir)/sn2princ.c	\
+        $(srcdir)/thread_safe.c \
+	$(srcdir)/timeofday.c	\
+	$(srcdir)/toffset.c	\
+	$(srcdir)/unlck_file.c	\
+	$(srcdir)/ustime.c	\
+	$(srcdir)/write_msg.c
+
+EXTRADEPSRCS = \
+	t_an_to_ln.c t_gifconf.c t_locate_kdc.c t_realm_iter.c \
+	t_std_conf.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+
+shared:
+	mkdir shared
+
+TEST_PROGS= t_std_conf t_an_to_ln t_locate_kdc
+
+T_STD_CONF_OBJS= t_std_conf.o def_realm.o get_krbhst.o realm_dom.o \
+		hst_realm.o init_os_ctx.o locate_kdc.o dnsglue.o 
+
+T_AN_TO_LN_OBJS = t_an_to_ln.o an_to_ln.o 
+
+T_REALM_ITER_OBJS = t_realm_iter.o realm_iter.o
+
+t_std_conf: $(T_STD_CONF_OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_std_conf $(T_STD_CONF_OBJS) $(KRB5_BASE_LIBS)
+
+t_an_to_ln: $(T_AN_TO_LN_OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_an_to_ln $(T_AN_TO_LN_OBJS) $(KRB5_BASE_LIBS)
+
+t_realm_iter: $(T_REALM_ITER_OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_realm_iter $(T_REALM_ITER_OBJS) $(KRB5_BASE_LIBS)
+
+t_mktime: gmt_mktime.c
+	$(CC) $(ALL_CFLAGS) -DTEST_LEAP -o t_mktime $(srcdir)/gmt_mktime.c
+
+t_localaddr: localaddr.c
+	$(CC_LINK) $(ALL_CFLAGS) -DTEST -o t_localaddr $(srcdir)/localaddr.c $(KRB5_BASE_LIBS) $(LIBS)
+
+t_locate_kdc: t_locate_kdc.o
+	$(CC_LINK) $(ALL_CFLAGS) -o t_locate_kdc t_locate_kdc.o \
+		$(KRB5_BASE_LIBS)
+t_locate_kdc.o: t_locate_kdc.c locate_kdc.c
+$(OUTPRE)t_locate_kdc.exe: $(OUTPRE)t_locate_kdc.obj \
+		$(OUTPRE)dnssrv.obj $(OUTPRE)dnsglue.obj \
+		$(KLIB) $(PLIB) $(CLIB) $(SLIB)
+	link $(EXE_LINKOPTS) -out:$@ $** ws2_32.lib $(DNSLIBS)
+
+LCLINT=lclint
+LCLINTOPTS= -warnposix \
+	-usedef +charintliteral +ignoresigns -predboolint +boolint \
+	-exportlocal -retvalint \
+	+mod-uncon +modinternalstrict +modfilesys
+lclint-localaddr: localaddr.c
+	$(LCLINT) $(LCLINTOPTS) $(CPPFLAGS) $(LOCALINCLUDES) $(DEFS) \
+		-DTEST $(srcdir)/localaddr.c
+
+check-unix:: $(TEST_PROGS)
+	KRB5_CONFIG=$(srcdir)/td_krb5.conf ; export KRB5_CONFIG ;\
+	$(KRB5_RUN_ENV) ./t_std_conf  -d -s NEW.DEFAULT.REALM -d \
+		-k IGGY.ORG -k DEFAULT_REALM.TST \
+		-D DEFAULT_REALM.TST -r bad.idea -r itar.bad.idea \
+		-r really.BAD.IDEA. -r clipper.bad.idea -r KeYEsCrOW.BaD.IDea \
+		-r pgp.good.idea -r no_domain > test.out
+	cmp test.out $(srcdir)/ref_std_conf.out
+	$(RM) test.out
+	KRB5_CONFIG=$(srcdir)/td_krb5.conf ; export KRB5_CONFIG ;\
+	$(KRB5_RUN_ENV) ./t_locate_kdc ATHENA.MIT.EDU
+
+#
+# Do some aname-to-lname testing.
+#
+check-unix::
+	echo '[libdefaults]' > ./t_an.conf
+	echo '	default_realm = r' >> ./t_an.conf
+	echo '[realms]' >> ./t_an.conf
+	echo 'r = {' >> ./t_an.conf
+#	if test -r ../../../admin/aname/kdb5_anadd ; then \
+#		$(KRB5_RUN_ENV) ../../../admin/aname/kdb5_anadd -a -n ./t_an p/i/i/i@r piii; \
+#		../../../admin/aname/kdb5_anadd -a -n ./t_an p/a/b/c@r pabc; \
+#		echo 'auth_to_local = DB:./t_an' >> ./t_an.conf; \
+#	fi
+	echo 'auth_to_local = RULE:[3:$$1$$3$$2](rule.*)s/rule//g' \
+		>> ./t_an.conf
+	echo 'auth_to_local = DEFAULT' >> ./t_an.conf
+	echo '}' >> ./t_an.conf
+#	if test -r ../../../admin/aname/kdb5_anadd ; then \
+#		KRB5_CONFIG=./t_an.conf ; export KRB5_CONFIG ; \
+#		$(KRB5_RUN_ENV) ./t_an_to_ln p/i/i/i@r p/a/b/c@r; \
+#	fi
+	KRB5_CONFIG=./t_an.conf ; export KRB5_CONFIG ; \
+	$(KRB5_RUN_ENV) ./t_an_to_ln rul/helpme/e@r ru/123/le@r
+	KRB5_CONFIG=./t_an.conf ; export KRB5_CONFIG ; \
+	$(KRB5_RUN_ENV) ./t_an_to_ln fred/r@r barney/r@r
+	$(RM) ./t_an.*
+
+clean:: 
+	$(RM) $(TEST_PROGS) test.out t_std_conf.o t_an_to_ln.o
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+accessor.so accessor.po $(OUTPRE)accessor.$(OBJEXT): \
+  accessor.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+an_to_ln.so an_to_ln.po $(OUTPRE)an_to_ln.$(OBJEXT): \
+  an_to_ln.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+c_ustime.so c_ustime.po $(OUTPRE)c_ustime.$(OBJEXT): \
+  c_ustime.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+def_realm.so def_realm.po $(OUTPRE)def_realm.$(OBJEXT): \
+  def_realm.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+ccdefname.so ccdefname.po $(OUTPRE)ccdefname.$(OBJEXT): \
+  ccdefname.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+changepw.so changepw.po $(OUTPRE)changepw.$(OBJEXT): \
+  changepw.c $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/krb5/kdb.h os-proto.h
+dnsglue.so dnsglue.po $(OUTPRE)dnsglue.$(OBJEXT): dnsglue.c \
+  dnsglue.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+dnssrv.so dnssrv.po $(OUTPRE)dnssrv.$(OBJEXT): dnssrv.c \
+  dnsglue.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+free_krbhs.so free_krbhs.po $(OUTPRE)free_krbhs.$(OBJEXT): \
+  free_krbhs.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+free_hstrl.so free_hstrl.po $(OUTPRE)free_hstrl.$(OBJEXT): \
+  free_hstrl.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+full_ipadr.so full_ipadr.po $(OUTPRE)full_ipadr.$(OBJEXT): \
+  full_ipadr.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+get_krbhst.so get_krbhst.po $(OUTPRE)get_krbhst.$(OBJEXT): \
+  get_krbhst.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+gen_port.so gen_port.po $(OUTPRE)gen_port.$(OBJEXT): \
+  gen_port.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+genaddrs.so genaddrs.po $(OUTPRE)genaddrs.$(OBJEXT): \
+  genaddrs.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+gen_rname.so gen_rname.po $(OUTPRE)gen_rname.$(OBJEXT): \
+  gen_rname.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+gmt_mktime.so gmt_mktime.po $(OUTPRE)gmt_mktime.$(OBJEXT): \
+  gmt_mktime.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+hostaddr.so hostaddr.po $(OUTPRE)hostaddr.$(OBJEXT): \
+  hostaddr.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/fake-addrinfo.h
+hst_realm.so hst_realm.po $(OUTPRE)hst_realm.$(OBJEXT): \
+  hst_realm.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h $(SRCTOP)/include/fake-addrinfo.h dnsglue.h
+init_os_ctx.so init_os_ctx.po $(OUTPRE)init_os_ctx.$(OBJEXT): \
+  init_os_ctx.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+krbfileio.so krbfileio.po $(OUTPRE)krbfileio.$(OBJEXT): \
+  krbfileio.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ktdefname.so ktdefname.po $(OUTPRE)ktdefname.$(OBJEXT): \
+  ktdefname.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+kuserok.so kuserok.po $(OUTPRE)kuserok.$(OBJEXT): kuserok.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+mk_faddr.so mk_faddr.po $(OUTPRE)mk_faddr.$(OBJEXT): \
+  mk_faddr.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+localaddr.so localaddr.po $(OUTPRE)localaddr.$(OBJEXT): \
+  localaddr.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/foreachaddr.h
+locate_kdc.so locate_kdc.po $(OUTPRE)locate_kdc.$(OBJEXT): \
+  locate_kdc.c $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/krb5/kdb.h os-proto.h
+lock_file.so lock_file.po $(OUTPRE)lock_file.$(OBJEXT): \
+  lock_file.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+net_read.so net_read.po $(OUTPRE)net_read.$(OBJEXT): \
+  net_read.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+net_write.so net_write.po $(OUTPRE)net_write.$(OBJEXT): \
+  net_write.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+osconfig.so osconfig.po $(OUTPRE)osconfig.$(OBJEXT): \
+  osconfig.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+prompter.so prompter.po $(OUTPRE)prompter.$(OBJEXT): \
+  prompter.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+read_msg.so read_msg.po $(OUTPRE)read_msg.$(OBJEXT): \
+  read_msg.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+read_pwd.so read_pwd.po $(OUTPRE)read_pwd.$(OBJEXT): \
+  read_pwd.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+realm_dom.so realm_dom.po $(OUTPRE)realm_dom.$(OBJEXT): \
+  realm_dom.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+realm_iter.so realm_iter.po $(OUTPRE)realm_iter.$(OBJEXT): \
+  realm_iter.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+port2ip.so port2ip.po $(OUTPRE)port2ip.$(OBJEXT): port2ip.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+send524.so send524.po $(OUTPRE)send524.$(OBJEXT): send524.c \
+  $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/krb5/kdb.h os-proto.h
+sendto_kdc.so sendto_kdc.po $(OUTPRE)sendto_kdc.$(OBJEXT): \
+  sendto_kdc.c $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/krb5/kdb.h os-proto.h $(SRCTOP)/include/cm.h
+sn2princ.so sn2princ.po $(OUTPRE)sn2princ.$(OBJEXT): \
+  sn2princ.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/include/fake-addrinfo.h
+thread_safe.so thread_safe.po $(OUTPRE)thread_safe.$(OBJEXT): \
+  thread_safe.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+timeofday.so timeofday.po $(OUTPRE)timeofday.$(OBJEXT): \
+  timeofday.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+toffset.so toffset.po $(OUTPRE)toffset.$(OBJEXT): toffset.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+unlck_file.so unlck_file.po $(OUTPRE)unlck_file.$(OBJEXT): \
+  unlck_file.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ustime.so ustime.po $(OUTPRE)ustime.$(OBJEXT): ustime.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+write_msg.so write_msg.po $(OUTPRE)write_msg.$(OBJEXT): \
+  write_msg.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+t_an_to_ln.so t_an_to_ln.po $(OUTPRE)t_an_to_ln.$(OBJEXT): \
+  t_an_to_ln.c $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS)
+t_gifconf.so t_gifconf.po $(OUTPRE)t_gifconf.$(OBJEXT): \
+  t_gifconf.c
+t_locate_kdc.so t_locate_kdc.po $(OUTPRE)t_locate_kdc.$(OBJEXT): \
+  t_locate_kdc.c $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(COM_ERR_DEPS) locate_kdc.c $(SRCTOP)/include/fake-addrinfo.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5.h \
+  $(BUILDTOP)/include/profile.h $(SRCTOP)/include/krb5/kdb.h \
+  os-proto.h
+t_realm_iter.so t_realm_iter.po $(OUTPRE)t_realm_iter.$(OBJEXT): \
+  t_realm_iter.c $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS)
+t_std_conf.so t_std_conf.po $(OUTPRE)t_std_conf.$(OBJEXT): \
+  t_std_conf.c $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/krb5/kdb.h os-proto.h
diff --git a/mechglue/src/lib/krb5/os/accessor.c b/mechglue/src/lib/krb5/os/accessor.c
new file mode 100644
index 000000000..f16a6e3e6
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/accessor.c
@@ -0,0 +1,69 @@
+/*
+ * lib/krb5/os/accessor.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+*/
+
+#include "k5-int.h"
+#include "os-proto.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5int_accessor(krb5int_access *internals, krb5_int32 version)
+{
+  if (version == KRB5INT_ACCESS_VERSION)
+  {
+    krb5int_access internals_temp;
+    internals_temp.free_addrlist = krb5int_free_addrlist;
+    internals_temp.krb5_hmac = krb5_hmac;
+    internals_temp.md5_hash_provider = &krb5int_hash_md5;
+    internals_temp.arcfour_enc_provider = &krb5int_enc_arcfour;
+    internals_temp.locate_server = &krb5int_locate_server;
+    internals_temp.sendto_udp = &krb5int_sendto;
+    internals_temp.add_host_to_list = krb5int_add_host_to_list;
+#ifdef KRB5_DNS_LOOKUP
+    internals_temp.make_srv_query_realm = krb5int_make_srv_query_realm;
+    internals_temp.free_srv_dns_data = krb5int_free_srv_dns_data;
+    internals_temp.use_dns_kdc = _krb5_use_dns_kdc;
+#else
+    internals_temp.make_srv_query_realm = 0;
+    internals_temp.free_srv_dns_data = 0;
+    internals_temp.use_dns_kdc = 0;
+#endif
+#ifdef KRB5_KRB4_COMPAT
+    internals_temp.krb_life_to_time = krb5int_krb_life_to_time;
+    internals_temp.krb_time_to_life = krb5int_krb_time_to_life;
+    internals_temp.krb524_encode_v4tkt = krb5int_encode_v4tkt;
+#else
+    internals_temp.krb_life_to_time = 0;
+    internals_temp.krb_time_to_life = 0;
+    internals_temp.krb524_encode_v4tkt = 0;
+#endif
+    internals_temp.krb5int_c_mandatory_cksumtype = krb5int_c_mandatory_cksumtype;
+    internals_temp.krb5_ser_pack_int64 = krb5_ser_pack_int64;
+    internals_temp.krb5_ser_unpack_int64 = krb5_ser_unpack_int64;
+    *internals = internals_temp;
+    return 0;
+  }
+  return KRB5_OBSOLETE_FN;
+}
diff --git a/mechglue/src/lib/krb5/os/an_to_ln.c b/mechglue/src/lib/krb5/os/an_to_ln.c
new file mode 100644
index 000000000..73465d66c
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/an_to_ln.c
@@ -0,0 +1,831 @@
+/*
+ * lib/krb5/os/an_to_ln.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_aname_to_localname()
+ */
+
+/*
+ * We're only to AN_TO_LN rules at this point, and not doing the
+ * database lookup  (moved from configure script)
+ */
+#define AN_TO_LN_RULES
+
+#include "k5-int.h"
+#include <ctype.h>
+#if	HAVE_REGEX_H
+#include <regex.h>
+#endif	/* HAVE_REGEX_H */
+#include <string.h>
+/*
+ * Use compile(3) if no regcomp present.
+ */
+#if	!defined(HAVE_REGCOMP) && defined(HAVE_REGEXPR_H) && defined(HAVE_COMPILE)
+#define	RE_BUF_SIZE	1024
+#include <regexpr.h>
+#endif	/* !HAVE_REGCOMP && HAVE_REGEXP_H && HAVE_COMPILE */
+
+#define	MAX_FORMAT_BUFFER	1024
+#ifndef	min
+#define	min(a,b)	((a>b) ? b : a)
+#endif	/* min */
+#ifdef ANAME_DB
+/*
+ * Use standard DBM code.
+ */
+#define	KDBM_OPEN(db, fl, mo)	dbm_open(db, fl, mo)
+#define	KDBM_CLOSE(db)		dbm_close(db)
+#define	KDBM_FETCH(db, key)	dbm_fetch(db, key)
+#endif /*ANAME_DB*/
+
+/*
+ * Find the portion of the flattened principal name that we use for mapping.
+ */
+static char *
+aname_full_to_mapping_name(char *fprincname)
+{
+    char	*atp;
+    size_t	mlen;
+    char	*mname;
+
+    mname = (char *) NULL;
+    if (fprincname) {
+	atp = strrchr(fprincname, '@');
+	if (!atp)
+	    atp = &fprincname[strlen(fprincname)];
+	mlen = (size_t) (atp - fprincname);
+	
+	if ((mname = (char *) malloc(mlen+1))) {
+	    strncpy(mname, fprincname, mlen);
+	    mname[mlen] = '\0';
+	}
+    }
+    return(mname);
+}
+
+#ifdef ANAME_DB
+/*
+ * Implementation:  This version uses a DBM database, indexed by aname,
+ * to generate a lname.
+ *
+ * The entries in the database are normal C strings, and include the trailing
+ * null in the DBM datum.size.
+ */
+static krb5_error_code
+db_an_to_ln(context, dbname, aname, lnsize, lname)
+    krb5_context context;
+    char *dbname;
+    krb5_const_principal aname;
+    const unsigned int lnsize;
+    char *lname;
+{
+#if !defined(_WIN32)
+    DBM *db;
+    krb5_error_code retval;
+    datum key, contents;
+    char *princ_name;
+
+    if ((retval = krb5_unparse_name(context, aname, &princ_name)))
+	return(retval);
+    key.dptr = princ_name;
+    key.dsize = strlen(princ_name)+1;	/* need to store the NULL for
+					   decoding */
+
+    db = KDBM_OPEN(dbname, O_RDONLY, 0600);
+    if (!db) {
+	krb5_xfree(princ_name);
+	return KRB5_LNAME_CANTOPEN;
+    }
+
+    contents = KDBM_FETCH(db, key);
+
+    krb5_xfree(princ_name);
+
+    if (contents.dptr == NULL) {
+	retval = KRB5_LNAME_NOTRANS;
+    } else {
+	strncpy(lname, contents.dptr, lnsize);
+	if (lnsize < contents.dsize)
+	    retval = KRB5_CONFIG_NOTENUFSPACE;
+	else if (lname[contents.dsize-1] != '\0')
+	    retval = KRB5_LNAME_BADFORMAT;
+	else
+	    retval = 0;
+    }
+    /* can't close until we copy the contents. */
+    (void) KDBM_CLOSE(db);
+    return retval;
+#else	/* !_WIN32 && !MACINTOSH */
+    /*
+     * If we don't have support for a database mechanism, then we can't
+     * translate this now, can we?
+     */
+    return KRB5_LNAME_NOTRANS;
+#endif	/* !_WIN32 && !MACINTOSH */
+}
+#endif /*ANAME_DB*/
+
+#ifdef	AN_TO_LN_RULES
+/*
+ * Format and transform a principal name to a local name.  This is particularly
+ * useful when Kerberos principals and local user names are formatted to
+ * some particular convention.
+ *
+ * There are three parts to each rule:
+ * First part - formulate the string to perform operations on:  If not present
+ * then the string defaults to the fully flattened principal minus the realm
+ * name.  Otherwise the syntax is as follows:
+ *	"[" <ncomps> ":" <format> "]"
+ *		Where:
+ *			<ncomps> is the number of expected components for this
+ *			rule.  If the particular principal does not have this
+ *			many components, then this rule does not apply.
+ *
+ *			<format> is a string of <component> or verbatim
+ *			characters to be inserted.
+ *
+ *			<component> is of the form "$"<number> to select the
+ *			<number>th component.  <number> begins from 1.
+ *
+ * Second part - select rule validity:  If not present, then this rule may
+ * apply to all selections.  Otherwise the syntax is as follows:
+ *	"(" <regexp> ")"
+ *		Where:	<regexp> is a selector regular expression.  If this
+ *			regular expression matches the whole pattern generated
+ *			from the first part, then this rule still applies.
+ *
+ * Last part - Transform rule:  If not present, then the selection string
+ * is passed verbatim and is matched.  Otherwise, the syntax is as follows:
+ *	<rule> ...
+ *		Where:	<rule> is of the form:
+ *			"s/" <regexp> "/" <text> "/" ["g"]
+ * 
+ * In order to be able to select rule validity, the native system must support
+ * one of compile(3), re_comp(3) or regcomp(3).  In order to be able to
+ * transform (e.g. substitute), the native system must support regcomp(3) or
+ * compile(3).
+ */
+
+/*
+ * aname_do_match() 	- Does our name match the parenthesized regular
+ *			  expression?
+ * 
+ * Chew up the match portion of the regular expression and update *contextp.
+ * If no re_comp() or regcomp(), then always return a match.
+ */
+static krb5_error_code
+aname_do_match(char *string, char **contextp)
+{
+    krb5_error_code	kret;
+    char		*regexp, *startp, *endp = 0;
+    size_t		regexlen;
+#if	HAVE_REGCOMP
+    regex_t		match_exp;
+    regmatch_t		match_match;
+#elif	HAVE_REGEXPR_H
+    char		regexp_buffer[RE_BUF_SIZE];
+#endif	/* HAVE_REGEXP_H */
+
+    kret = 0;
+    /*
+     * Is this a match expression?
+     */
+    if (**contextp == '(') {
+	kret = KRB5_CONFIG_BADFORMAT;
+	startp = (*contextp) + 1;
+	endp = strchr(startp, ')');
+	/* Find the end of the match expression. */
+	if (endp) {
+	    regexlen = (size_t) (endp - startp);
+	    regexp = (char *) malloc((size_t) regexlen+1);
+	    kret = ENOMEM;
+	    if (regexp) {
+		strncpy(regexp, startp, regexlen);
+		regexp[regexlen] = '\0';
+		kret = KRB5_LNAME_NOTRANS;
+		/*
+		 * Perform the match.
+		 */
+#if	HAVE_REGCOMP
+		if (!regcomp(&match_exp, regexp, REG_EXTENDED) &&
+		    !regexec(&match_exp, string, 1, &match_match, 0)) {
+		    if ((match_match.rm_so == 0) &&
+			(match_match.rm_eo == strlen(string)))
+			kret = 0;
+		}
+		regfree(&match_exp);
+#elif	HAVE_REGEXPR_H
+		compile(regexp,
+			regexp_buffer,
+			®exp_buffer[RE_BUF_SIZE]);
+		if (step(string, regexp_buffer)) {
+		    if ((loc1 == string) &&
+			(loc2 == &string[strlen(string)]))
+			kret = 0;
+		}
+#elif	HAVE_RE_COMP
+		if (!re_comp(regexp) && re_exec(string))
+		    kret = 0;
+#else	/* HAVE_RE_COMP */
+		kret = 0;
+#endif	/* HAVE_RE_COMP */
+		free(regexp);
+	    }
+	    endp++;
+	}
+	else
+	    endp = startp;
+    }
+    *contextp = endp;
+    return(kret);
+}
+
+/*
+ * do_replacement()	- Replace the regular expression with the specified
+ * 			  replacement.
+ *
+ * If "doall" is set, it's a global replacement, otherwise, just a oneshot
+ * deal.
+ * If no regcomp() then just return the input string verbatim in the output
+ * string.
+ */
+#define use_bytes(x) \
+    out_used += (x); \
+    if (out_used > MAX_FORMAT_BUFFER) goto mem_err
+
+static int
+do_replacement(char *regexp, char *repl, int doall, char *in, char *out)
+{
+    size_t out_used = 0;
+#if	HAVE_REGCOMP
+    regex_t	match_exp;
+    regmatch_t	match_match;
+    int		matched;
+    char	*cp;
+    char	*op;
+
+    if (!regcomp(&match_exp, regexp, REG_EXTENDED)) {
+	cp = in;
+	op = out;
+	matched = 0;
+	do {
+	    if (!regexec(&match_exp, cp, 1, &match_match, 0)) {
+		if (match_match.rm_so) {
+		    use_bytes(match_match.rm_so);
+		    strncpy(op, cp, match_match.rm_so);
+		    op += match_match.rm_so;
+		}
+		use_bytes(strlen(repl));
+		strncpy(op, repl, MAX_FORMAT_BUFFER - 1 - (op - out));
+		op += strlen(op);
+		cp += match_match.rm_eo;
+		if (!doall) {
+		    use_bytes(strlen(cp));
+		    strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out));
+		}
+		matched = 1;
+	    }
+	    else {
+		use_bytes(strlen(cp));
+		strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out));
+		matched = 0;
+	    }
+	} while (doall && matched);
+	regfree(&match_exp);
+    }
+#elif	HAVE_REGEXPR_H
+    int		matched;
+    char	*cp;
+    char	*op;
+    char	regexp_buffer[RE_BUF_SIZE];
+    size_t	sdispl, edispl;
+
+    compile(regexp,
+	    regexp_buffer,
+	    ®exp_buffer[RE_BUF_SIZE]);
+    cp = in;
+    op = out;
+    matched = 0;
+    do {
+	if (step(cp, regexp_buffer)) {
+	    sdispl = (size_t) (loc1 - cp);
+	    edispl = (size_t) (loc2 - cp);
+	    if (sdispl) {
+		use_bytes(sdispl);
+		strncpy(op, cp, sdispl);
+		op += sdispl;
+	    }
+	    use_bytes(strlen(repl));
+	    strncpy(op, repl, MAX_FORMAT_BUFFER - 1 - (op - out));
+	    op += strlen(repl);
+	    cp += edispl;
+	    if (!doall) {
+		use_bytes(strlen(cp));
+		strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out));
+	    }
+	    matched = 1;
+	}
+	else {
+	    use_bytes(strlen(cp));
+	    strncpy(op, cp, MAX_FORMAT_BUFFER - 1 - (op - out));
+	    matched = 0;
+	}
+    } while (doall && matched);
+#else	/* HAVE_REGEXP_H */
+    memcpy(out, in, MAX_FORMAT_BUFFER);
+#endif	/* HAVE_REGCOMP */
+    return 1;
+ mem_err:
+#ifdef HAVE_REGCMP
+    	regfree(&match_exp);
+#endif
+	return 0;
+	
+}
+#undef use_bytes
+
+/*
+ * aname_replacer()	- Perform the specified substitutions on the input
+ *			  string and return the result.
+ *
+ * This routine enforces the "s/<pattern>/<replacement>/[g]" syntax.
+ */
+static krb5_error_code
+aname_replacer(char *string, char **contextp, char **result)
+{
+    krb5_error_code	kret;
+    char		*in;
+    char		*out;
+    char		*cp, *ep, *tp;
+    char		*rule, *repl;
+    size_t		rule_size, repl_size;
+    int			doglobal;
+
+    kret = ENOMEM;
+    *result = (char *) NULL;
+    /* Allocate the formatting buffers */
+    if ((in = (char *) malloc(MAX_FORMAT_BUFFER)) &&
+	(out = (char *) malloc(MAX_FORMAT_BUFFER))) {
+	/*
+	 * Prime the buffers.  Copy input string to "out" to simulate it
+	 * being the result of an initial iteration.
+	 */
+	strncpy(out, string, MAX_FORMAT_BUFFER - 1);
+	out[MAX_FORMAT_BUFFER - 1] = '\0';
+	in[0] = '\0';
+	kret = 0;
+	/*
+	 * Pound through the expression until we're done.
+	 */
+	for (cp = *contextp; *cp; ) {
+	    /* Skip leading whitespace */
+	    while (isspace((int) (*cp)))
+		cp++;
+
+	    /*
+	     * Find our separators.  First two characters must be "s/"
+	     * We must also find another "/" followed by another "/".
+	     */
+	    if ((cp[0] == 's') &&
+		(cp[1] == '/') &&
+		(ep = strchr(&cp[2], '/')) &&
+		(tp = strchr(&ep[1], '/'))) {
+
+		/* Figure out sizes of strings and allocate them */
+		rule_size = (size_t) (ep - &cp[2]);
+		repl_size = (size_t) (tp - &ep[1]);
+		if ((rule = (char *) malloc(rule_size+1)) &&
+		    (repl = (char *) malloc(repl_size+1))) {
+
+		    /* Copy the strings */
+		    strncpy(rule, &cp[2], rule_size);
+		    strncpy(repl, &ep[1], repl_size);
+		    rule[rule_size] = repl[repl_size] = '\0';
+
+		    /* Check for trailing "g" */
+		    doglobal = (tp[1] == 'g') ? 1 : 0;
+		    if (doglobal)
+			tp++;
+
+		    /* Swap previous in and out buffers */
+		    ep = in;
+		    in = out;
+		    out = ep;
+
+		    /* Do the replacemenbt */
+		    memset(out, '\0', MAX_FORMAT_BUFFER);
+		    if (!do_replacement(rule, repl, doglobal, in, out)) {
+			free(rule);
+		    free(repl);
+			kret = KRB5_LNAME_NOTRANS;
+			break;
+		    }
+		    free(rule);
+		    free(repl);
+
+		    /* If we have no output buffer left, this can't be good */
+		    if (strlen(out) == 0) {
+			kret = KRB5_LNAME_NOTRANS;
+			break;
+		    }
+		}
+		else {
+		    /* No memory for copies */
+		    kret = ENOMEM;
+		    break;
+		}
+	    }
+	    else {
+		/* Bad syntax */
+		kret = KRB5_CONFIG_BADFORMAT;
+		break;
+	    }
+	    /* Advance past trailer */
+	    cp = &tp[1];
+	}
+	free(in);
+	if (!kret)
+	    *result = out;
+	else
+	    free(out);
+    }
+    return(kret);
+}
+
+/*
+ * rule_an_to_ln()	- Handle aname to lname translations for RULE rules.
+ *
+ * The initial part of this routine handles the formulation of the strings from
+ * the principal name.
+ */
+static krb5_error_code
+rule_an_to_ln(krb5_context context, char *rule, krb5_const_principal aname, const unsigned int lnsize, char *lname)
+{
+    krb5_error_code	kret;
+    char		*current;
+    char		*fprincname;
+    char		*selstring = 0;
+    int			num_comps, compind;
+    size_t selstring_used;
+    char		*cout;
+    krb5_const krb5_data *datap;
+    char		*outstring;
+
+    /*
+     * First flatten the name.
+     */
+    current = rule;
+    if (!(kret = krb5_unparse_name(context, aname, &fprincname))) {
+	/*
+	 * First part.
+	 */
+	if (*current == '[') {
+	    if (sscanf(current+1,"%d:", &num_comps) == 1) {
+		if (num_comps == aname->length) {
+		    /*
+		     * We have a match based on the number of components.
+		     */
+		    current = strchr(current, ':');
+		    selstring = (char *) malloc(MAX_FORMAT_BUFFER);
+		    selstring_used = 0;
+		    if (current && selstring) {
+			current++;
+			cout = selstring;
+			/*
+			 * Plow through the string.
+			 */
+			while ((*current != ']') &&
+			       (*current != '\0')) {
+			    /*
+			     * Expand to a component.
+			     */
+			    if (*current == '$') {
+				if ((sscanf(current+1, "%d", &compind) == 1) &&
+				    (compind <= num_comps) &&
+				    (datap =
+				     (compind > 0)
+				     ? krb5_princ_component(context, aname,
+							    compind-1)
+				     : krb5_princ_realm(context, aname))
+				    ) {
+				    if ((datap->length < MAX_FORMAT_BUFFER)
+					&&  (selstring_used+datap->length
+					     < MAX_FORMAT_BUFFER)) {
+					selstring_used += datap->length;
+				    } else {
+					kret = ENOMEM;
+					goto errout;
+				    }
+				    strncpy(cout,
+					    datap->data,
+					    (unsigned) datap->length);
+				    cout += datap->length;
+				    *cout = '\0';
+				    current++;
+				    /* Point past number */
+				    while (isdigit((int) (*current)))
+					current++;
+				}
+				else
+				    kret = KRB5_CONFIG_BADFORMAT;
+			    }
+			    else {
+				/* Copy in verbatim. */
+				*cout = *current;
+				cout++;
+				*cout = '\0';
+				current++;
+			    }
+			}
+
+			/*
+			 * Advance past separator if appropriate.
+			 */
+			if (*current == ']')
+			    current++;
+			else
+			    kret = KRB5_CONFIG_BADFORMAT;
+
+			errout: if (kret)
+			    free(selstring);
+		    }
+		}
+		else
+		    kret = KRB5_LNAME_NOTRANS;
+	    }
+	    else
+		kret = KRB5_CONFIG_BADFORMAT;
+	}
+	else {
+	    if (!(selstring = aname_full_to_mapping_name(fprincname)))
+		kret = ENOMEM;
+	}
+	krb5_xfree(fprincname);
+    }
+    if (!kret) {
+	/*
+	 * Second part
+	 */
+	if (*current == '(')
+	    kret = aname_do_match(selstring, ¤t);
+
+	/*
+	 * Third part.
+	 */
+	if (!kret) {
+	    outstring = (char *) NULL;
+	    kret = aname_replacer(selstring, ¤t, &outstring);
+	    if (outstring) {
+		/* Copy out the value if there's enough room */
+		if (strlen(outstring)+1 <= (size_t) lnsize)
+		    strcpy(lname, outstring);
+		else
+		    kret = KRB5_CONFIG_NOTENUFSPACE;
+		free(outstring);
+	    }
+	}
+	free(selstring);
+    }
+
+    return(kret);
+}
+#endif	/* AN_TO_LN_RULES */
+
+/*
+ * Implementation:  This version checks the realm to see if it is the local
+ * realm; if so, and there is exactly one non-realm component to the name,
+ * that name is returned as the lname.
+ */
+static krb5_error_code
+default_an_to_ln(krb5_context context, krb5_const_principal aname, const unsigned int lnsize, char *lname)
+{
+    krb5_error_code retval;
+    char *def_realm;
+    unsigned int realm_length;
+
+    realm_length = krb5_princ_realm(context, aname)->length;
+    
+    if ((retval = krb5_get_default_realm(context, &def_realm))) {
+	return(retval);
+    }
+    if (((size_t) realm_length != strlen(def_realm)) ||
+        (memcmp(def_realm, krb5_princ_realm(context, aname)->data, realm_length))) {
+        free(def_realm);
+        return KRB5_LNAME_NOTRANS;
+    }
+
+    if (krb5_princ_size(context, aname) != 1) {
+        if (krb5_princ_size(context, aname) == 2 ) {
+           /* Check to see if 2nd component is the local realm. */
+           if ( strncmp(krb5_princ_component(context, aname,1)->data,def_realm,
+                        realm_length) ||
+                realm_length != krb5_princ_component(context, aname,1)->length)
+                return KRB5_LNAME_NOTRANS;
+        }
+        else
+           /* no components or more than one component to non-realm part of name
+           --no translation. */
+            return KRB5_LNAME_NOTRANS;
+    }
+
+    free(def_realm);
+    strncpy(lname, krb5_princ_component(context, aname,0)->data, 
+	    min(krb5_princ_component(context, aname,0)->length,lnsize));
+    if (lnsize <= krb5_princ_component(context, aname,0)->length ) {
+	retval = KRB5_CONFIG_NOTENUFSPACE;
+    } else {
+	lname[krb5_princ_component(context, aname,0)->length] = '\0';
+	retval = 0;
+    }
+    return retval;
+}
+
+/*
+ Converts an authentication name to a local name suitable for use by
+ programs wishing a translation to an environment-specific name (e.g.
+ user account name).
+
+ lnsize specifies the maximum length name that is to be filled into
+ lname.
+ The translation will be null terminated in all non-error returns.
+
+ returns system errors, NOT_ENOUGH_SPACE
+*/
+
+krb5_error_code KRB5_CALLCONV
+krb5_aname_to_localname(krb5_context context, krb5_const_principal aname, const int lnsize_in, char *lname)
+{
+    krb5_error_code	kret;
+    char		*realm;
+    char		*pname;
+    char		*mname;
+    const char		*hierarchy[5];
+    char		**mapping_values;
+    int			i, nvalid;
+    char		*cp, *s;
+    char		*typep, *argp;
+    unsigned int        lnsize;
+
+    if (lnsize_in < 0)
+      return KRB5_CONFIG_NOTENUFSPACE;
+
+    lnsize = lnsize_in; /* Unsigned */
+
+    /*
+     * First get the default realm.
+     */
+    if (!(kret = krb5_get_default_realm(context, &realm))) {
+	/* Flatten the name */
+	if (!(kret = krb5_unparse_name(context, aname, &pname))) {
+	    if ((mname = aname_full_to_mapping_name(pname))) {
+		/*
+		 * Search first for explicit mappings of the form:
+		 *
+		 * [realms]->realm->"auth_to_local_names"->mapping_name
+		 */
+		hierarchy[0] = "realms";
+		hierarchy[1] = realm;
+		hierarchy[2] = "auth_to_local_names";
+		hierarchy[3] = mname;
+		hierarchy[4] = (char *) NULL;
+		if (!(kret = profile_get_values(context->profile,
+						hierarchy,
+						&mapping_values))) {
+		    /* We found one or more explicit mappings. */
+		    for (nvalid=0; mapping_values[nvalid]; nvalid++);
+
+		    /* Just use the last one. */
+		    /* Trim the value. */
+		    s = mapping_values[nvalid-1];
+		    cp = s + strlen(s);
+		    while (cp > s) {
+			cp--;
+			if (!isspace((int)(*cp)))
+			    break;
+			*cp = '\0';
+		    }
+
+		    /* Copy out the value if there's enough room */
+		    if (strlen(mapping_values[nvalid-1])+1 <= (size_t) lnsize)
+			strcpy(lname, mapping_values[nvalid-1]);
+		    else
+			kret = KRB5_CONFIG_NOTENUFSPACE;
+
+		    /* Free residue */
+		    profile_free_list(mapping_values);
+		}
+		else {
+		    /*
+		     * OK - There's no explicit mapping.  Now check for
+		     * general auth_to_local rules of the form:
+		     *
+		     * [realms]->realm->"auth_to_local"
+		     *
+		     * This can have one or more of the following kinds of
+		     * values:
+		     *	DB:<filename>	- Look up principal in aname database.
+		     *	RULE:<sed-exp>	- Formulate lname from sed-exp.
+		     *	DEFAULT		- Use default rule.
+		     * The first rule to find a match is used.
+		     */
+		    hierarchy[0] = "realms";
+		    hierarchy[1] = realm;
+		    hierarchy[2] = "auth_to_local";
+		    hierarchy[3] = (char *) NULL;
+		    if (!(kret = profile_get_values(context->profile,
+						    hierarchy,
+						    &mapping_values))) {
+			/*
+			 * Loop through all the mapping values.
+			 */
+			for (i=0; mapping_values[i]; i++) {
+			    typep = mapping_values[i];
+			    argp = strchr(typep, ':');
+			    if (argp) {
+				*argp = '\0';
+				argp++;
+			    }
+#ifdef ANAME_DB
+			    if (!strcmp(typep, "DB") && argp) {
+				kret = db_an_to_ln(context,
+						   argp,
+						   aname,
+						   lnsize,
+						   lname);
+				if (kret != KRB5_LNAME_NOTRANS)
+				    break;
+			    }
+			    else
+#endif
+#ifdef	AN_TO_LN_RULES
+			    if (!strcmp(typep, "RULE") && argp) {
+				kret = rule_an_to_ln(context,
+						     argp,
+						     aname,
+						     lnsize,
+						     lname);
+				if (kret != KRB5_LNAME_NOTRANS)
+				    break;
+			    }
+			    else
+#endif	/* AN_TO_LN_RULES */
+			    if (!strcmp(typep, "DEFAULT") && !argp) {
+				kret = default_an_to_ln(context,
+							aname,
+							lnsize,
+							lname);
+				if (kret != KRB5_LNAME_NOTRANS)
+				    break;
+			    }
+			    else {
+				kret = KRB5_CONFIG_BADFORMAT;
+				break;
+			    }
+			}
+
+			/* We're done, clean up the droppings. */
+			profile_free_list(mapping_values);
+		    }
+		    else {
+			/*
+			 * No profile relation found, try default mapping.
+			 */
+			kret = default_an_to_ln(context,
+						aname,
+						lnsize,
+						lname);
+		    }
+		}
+		free(mname);
+	    }
+	    else
+		kret = ENOMEM;
+	    krb5_xfree(pname);
+	}
+	krb5_xfree(realm);
+    }
+    return(kret);
+}
+
diff --git a/mechglue/src/lib/krb5/os/c_ustime.c b/mechglue/src/lib/krb5/os/c_ustime.c
new file mode 100644
index 000000000..c752a4ade
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/c_ustime.c
@@ -0,0 +1,117 @@
+/*
+ * lib/crypto/os/c_ustime.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_mstimeofday for BSD 4.3
+ */
+ 
+#include "k5-int.h"
+#include "k5-thread.h"
+
+k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+
+struct time_now { krb5_int32 sec, usec; };
+
+#if defined(_WIN32)
+
+   /* Microsoft Windows NT and 95   (32bit)  */
+   /* This one works for WOW (Windows on Windows, ntvdm on Win-NT) */
+
+#include <time.h>
+#include <sys/timeb.h>
+#include <string.h>
+
+static krb5_error_code
+get_time_now(struct time_now *n)
+{
+    struct _timeb timeptr;
+    _ftime(&timeptr);
+    n->sec = timeptr.time;
+    n->usec = timeptr.millitm * 1000;
+    return 0;
+}
+
+#else
+
+/* Everybody else is UNIX, right?  POSIX 1996 doesn't give us
+   gettimeofday, but what real OS doesn't?  */
+
+static krb5_error_code
+get_time_now(struct time_now *n)
+{
+    struct timeval tv;
+
+    if (gettimeofday(&tv, (struct timezone *)0) == -1)
+	return errno;
+
+    n->sec = tv.tv_sec;
+    n->usec = tv.tv_usec;
+    return 0;
+}
+
+#endif
+
+static struct time_now last_time;
+
+krb5_error_code
+krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds)
+{
+    struct time_now now;
+    krb5_error_code err;
+
+    err = get_time_now(&now);
+    if (err)
+	return err;
+
+    err = k5_mutex_lock(&krb5int_us_time_mutex);
+    if (err)
+	return err;
+    /* Just guessing: If the number of seconds hasn't changed, yet the
+       microseconds are moving backwards, we probably just got a third
+       instance of returning the same clock value from the system, so
+       the saved value was artificially incremented.
+
+       On Windows, where we get millisecond accuracy currently, that's
+       quite likely.  On UNIX, it appears that we always get new
+       microsecond values, so this case should never trigger.  */
+    if ((now.sec == last_time.sec) && (now.usec <= last_time.usec)) {
+	/* Same as last time??? */
+	now.usec = ++last_time.usec;
+	if (now.usec >= 1000000) {
+	    ++now.sec;
+	    now.usec = 0;
+	}
+	/* For now, we're not worrying about the case of enough
+	   returns of the same value that we roll over now.sec, and
+	   the next call still gets the previous now.sec value.  */
+    }
+    last_time.sec = now.sec;	/* Remember for next time */
+    last_time.usec = now.usec;
+    k5_mutex_unlock(&krb5int_us_time_mutex);
+
+    *seconds = now.sec;
+    *microseconds = now.usec;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/os/ccdefname.c b/mechglue/src/lib/krb5/os/ccdefname.c
new file mode 100644
index 000000000..f9ddecce4
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/ccdefname.c
@@ -0,0 +1,299 @@
+/*
+ * lib/krb5/os/ccdefname.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Return default cred. cache name.
+ */
+
+#define NEED_WINDOWS
+#include "k5-int.h"
+#include <stdio.h>
+
+#if defined(USE_CCAPI)
+#include <CredentialsCache.h>
+#endif
+
+#if defined(_WIN32)
+static int get_from_registry_indirect(char *name_buf, int name_size)
+{
+	/* If the RegKRB5CCNAME variable is set, it will point to
+	 * the registry key that has the name of the cache to use.
+	 * The Gradient PC-DCE sets the registry key
+	 * [HKEY_CURRENT_USER\Software\Gradient\DCE\Default\KRB5CCNAME]
+	 * to point at the cache file name (including the FILE: prefix).
+	 * By indirecting with the RegKRB5CCNAME entry in kerberos.ini,
+	 * we can accomodate other versions that might set a registry
+	 * variable.
+	 */
+	char newkey[256];
+	    
+	LONG name_buf_size;
+	HKEY hkey;
+	int found = 0;
+	char *cp;
+
+        newkey[0] = 0;
+	GetPrivateProfileString(INI_FILES, "RegKRB5CCNAME", "", 
+				newkey, sizeof(newkey), KERBEROS_INI);
+	if (!newkey[0])
+		return 0;
+	
+        newkey[sizeof(newkey)-1] = 0;
+	cp = strrchr(newkey,'\\');
+	if (cp) {
+		*cp = '\0'; /* split the string */
+		cp++;
+	} else
+		cp = "";
+	
+	if (RegOpenKeyEx(HKEY_CURRENT_USER, newkey, 0,
+			 KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS)
+		return 0;
+	
+	name_buf_size = name_size;
+	if (RegQueryValueEx(hkey, cp, 0, 0, 
+			    name_buf, &name_buf_size) != ERROR_SUCCESS)
+	{
+		RegCloseKey(hkey);
+		return 0;
+	}
+
+	RegCloseKey(hkey);
+	return 1;
+}
+
+/*
+ * get_from_registry
+ *
+ * This will find the ccname in the registry.  Returns 0 on error, non-zero
+ * on success.
+ */
+
+static int
+get_from_registry(
+    HKEY hBaseKey,
+    char *name_buf, 
+    int name_size
+    )
+{
+    HKEY hKey;
+    DWORD name_buf_size = (DWORD)name_size;
+    const char *key_path = "Software\\MIT\\Kerberos5";
+    const char *value_name = "ccname";
+
+    if (RegOpenKeyEx(hBaseKey, key_path, 0, KEY_QUERY_VALUE, 
+                     &hKey) != ERROR_SUCCESS)
+        return 0;
+    if (RegQueryValueEx(hKey, value_name, 0, 0, 
+                        name_buf, &name_buf_size) != ERROR_SUCCESS)
+    {
+        RegCloseKey(hKey);
+        return 0;
+    }
+    RegCloseKey(hKey);
+    return 1;
+}
+
+#define APPEND_KRB5CC "\\krb5cc"
+
+static int
+try_dir(
+    char* dir,
+    char* buffer,
+    int buf_len
+    )
+{
+    struct _stat s;
+    if (!dir)
+        return 0;
+    if (_stat(dir, &s))
+        return 0;
+    if (!(s.st_mode & _S_IFDIR))
+        return 0;
+    if (buffer != dir) {
+        strncpy(buffer, dir, buf_len);
+        buffer[buf_len-1]='\0';
+    }
+    strncat(buffer, APPEND_KRB5CC, buf_len-strlen(buffer));
+    buffer[buf_len-1] = '\0';
+    return 1;
+}
+#endif
+
+#if defined(_WIN32)
+static krb5_error_code get_from_os(char *name_buf, int name_size)
+{
+	char *prefix = krb5_cc_dfl_ops->prefix;
+        int size;
+        char *p;
+
+	if (get_from_registry(HKEY_CURRENT_USER,
+                              name_buf, name_size) != 0)
+		return 0;
+
+	if (get_from_registry(HKEY_LOCAL_MACHINE,
+                              name_buf, name_size) != 0)
+		return 0;
+
+	if (get_from_registry_indirect(name_buf, name_size) != 0)
+		return 0;
+
+        strncpy(name_buf, prefix, name_size - 1);
+        name_buf[name_size - 1] = 0;
+        size = name_size - strlen(prefix);
+        if (size > 0)
+            strcat(name_buf, ":");
+        size--;
+        p = name_buf + name_size - size;
+	if (!strcmp(prefix, "API")) {
+		strncpy(p, "krb5cc", size);
+	} else if (!strcmp(prefix, "FILE") || !strcmp(prefix, "STDIO")) {
+		if (!try_dir(getenv("TEMP"), p, size) &&
+		    !try_dir(getenv("TMP"), p, size))
+		{
+                    int len = GetWindowsDirectory(p, size);
+                    name_buf[name_size - 1] = 0;
+                    if (len < size - sizeof(APPEND_KRB5CC))
+			strcat(p, APPEND_KRB5CC);
+		}
+	} else {
+		strncpy(p, "default_cache_name", size);
+	}
+	name_buf[name_size - 1] = 0;
+	return 0;
+}
+#endif
+
+#if defined(USE_CCAPI)
+
+static krb5_error_code get_from_os(char *name_buf, int name_size)
+{
+	krb5_error_code result = 0;
+	cc_context_t cc_context = NULL;
+	cc_string_t default_name = NULL;
+
+	cc_int32 ccerr = cc_initialize (&cc_context, ccapi_version_3, NULL, NULL);
+	if (ccerr == ccNoError) {
+		ccerr = cc_context_get_default_ccache_name (cc_context, &default_name);
+	}
+	
+	if (ccerr == ccNoError) {
+		if (strlen (default_name -> data) + 5 > name_size) {
+			result = ENOMEM;
+			goto cleanup;
+		} else {
+			sprintf (name_buf, "API:%s", default_name -> data);
+		}
+	}
+	
+cleanup:
+	if (cc_context != NULL) {
+		cc_context_release (cc_context);
+	}
+	
+	if (default_name != NULL) {
+		cc_string_release (default_name);
+	}
+	
+	return result;
+}
+
+#else
+#if !(defined(_WIN32))
+static krb5_error_code get_from_os(char *name_buf, int name_size)
+{
+	sprintf(name_buf, "FILE:/tmp/krb5cc_%ld", (long) getuid());
+	return 0;
+}
+#endif
+#endif
+
+krb5_error_code KRB5_CALLCONV
+krb5_cc_set_default_name(krb5_context context, const char *name)
+{
+    krb5_error_code err = 0;
+    char *new_ccname = NULL;
+    
+    if (!context || context->magic != KV5M_CONTEXT) { err = KV5M_CONTEXT; }
+    
+    if (name != NULL) {
+        if (!err) {
+            /* If the name isn't NULL, make a copy of it */
+            new_ccname = malloc (strlen (name) + 1);
+            if (new_ccname == NULL) { err = ENOMEM; }
+        }
+        
+        if (!err) {
+            strcpy (new_ccname, name);
+        }
+    }
+    
+    if (!err) {
+        /* free the old ccname and store the new one */
+        krb5_os_context os_ctx = context->os_context;
+        if (os_ctx->default_ccname) { free (os_ctx->default_ccname); }
+        os_ctx->default_ccname = new_ccname;
+        new_ccname = NULL;  /* don't free */
+    }
+    
+    if (new_ccname != NULL) { free (new_ccname); }
+    
+    return err;
+}
+
+	
+const char * KRB5_CALLCONV
+krb5_cc_default_name(krb5_context context)
+{
+    krb5_error_code err = 0;
+    krb5_os_context os_ctx = NULL;
+    
+    if (!context || context->magic != KV5M_CONTEXT) { err = KV5M_CONTEXT; }
+    
+    if (!err) {
+        os_ctx = context->os_context;
+        
+        if (os_ctx->default_ccname == NULL) {
+            /* Default ccache name has not been set yet */
+            char *new_ccname = NULL;
+            char new_ccbuf[1024];
+            
+            /* try the environment variable first */
+            new_ccname = getenv(KRB5_ENV_CCNAME);
+            
+            if (new_ccname == NULL) {
+                /* fall back on the default ccache name for the OS */
+                new_ccname = new_ccbuf;
+                err = get_from_os (new_ccbuf, sizeof (new_ccbuf));
+            }
+            
+            if (!err) {
+                err = krb5_cc_set_default_name (context, new_ccname);
+            }
+        }
+    }
+    
+    return err ? NULL : os_ctx->default_ccname;
+}
diff --git a/mechglue/src/lib/krb5/os/changepw.c b/mechglue/src/lib/krb5/os/changepw.c
new file mode 100644
index 000000000..1d4e1d3ad
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/changepw.c
@@ -0,0 +1,429 @@
+/*
+ * lib/krb5/os/changepw.c
+ *
+ * Copyright 1990,1999,2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+/*
+ * krb5_set_password - Implements set password per RFC 3244
+ * Added by Paul W. Nelson, Thursby Software Systems, Inc.
+ */
+
+#include "fake-addrinfo.h"
+#include "k5-int.h"
+#include "os-proto.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef GETSOCKNAME_ARG3_TYPE
+#define GETSOCKNAME_ARG3_TYPE int
+#endif
+
+/*
+ * Wrapper function for the two backends
+ */
+
+static krb5_error_code
+krb5_locate_kpasswd(krb5_context context, const krb5_data *realm,
+		    struct addrlist *addrlist)
+{
+    krb5_error_code code;
+
+    code = krb5int_locate_server (context, realm, addrlist, 0,
+				  "kpasswd_server", "_kpasswd", 0,
+				  htons(DEFAULT_KPASSWD_PORT), 0, 0);
+    if (code == KRB5_REALM_CANT_RESOLVE || code == KRB5_REALM_UNKNOWN) {
+	code = krb5int_locate_server (context, realm, addrlist, 0,
+				      "admin_server", "_kerberos-adm", 1,
+				      DEFAULT_KPASSWD_PORT, 0, 0);
+	if (!code) {
+	    /* Success with admin_server but now we need to change the
+	       port number to use DEFAULT_KPASSWD_PORT.  */
+	    int i;
+	    for ( i=0;i<addrlist->naddrs;i++ ) {
+		struct addrinfo *a = addrlist->addrs[i];
+		if (a->ai_family == AF_INET)
+		    sa2sin (a->ai_addr)->sin_port = htons(DEFAULT_KPASSWD_PORT);
+	    }
+	}
+    }
+    return (code);
+}
+
+
+/*
+** The logic for setting and changing a password is mostly the same
+** krb5_change_set_password handles both cases 
+**	if set_password_for is NULL, then a password change is performed,
+**  otherwise, the password is set for the principal indicated in set_password_for
+*/
+krb5_error_code KRB5_CALLCONV
+krb5_change_set_password(
+	krb5_context context, krb5_creds *creds, char *newpw, krb5_principal set_password_for,
+	int *result_code, krb5_data *result_code_string, krb5_data *result_string)
+{
+    krb5_auth_context auth_context;
+    krb5_data ap_req, chpw_req, chpw_rep;
+    krb5_address local_kaddr, remote_kaddr;
+    char *code_string;
+    krb5_error_code code = 0;
+    int i;
+    GETSOCKNAME_ARG3_TYPE addrlen;
+    struct sockaddr_storage local_addr, remote_addr, tmp_addr;
+    int cc, local_result_code;
+    /* platforms seem to be consistant and use the same types */
+    GETSOCKNAME_ARG3_TYPE tmp_len; 
+    SOCKET s1 = INVALID_SOCKET, s2 = INVALID_SOCKET;
+    int tried_one = 0;
+    struct addrlist al = ADDRLIST_INIT;
+
+
+    /* Initialize values so that cleanup call can safely check for NULL */
+    auth_context = NULL;
+    memset(&chpw_req, 0, sizeof(krb5_data));
+    memset(&chpw_rep, 0, sizeof(krb5_data));
+    memset(&ap_req, 0, sizeof(krb5_data));
+
+    /* initialize auth_context so that we know we have to free it */
+    if ((code = krb5_auth_con_init(context, &auth_context)))
+	  goto cleanup;
+
+    if ((code = krb5_mk_req_extended(context, &auth_context,
+				     AP_OPTS_USE_SUBKEY,
+				     NULL, creds, &ap_req)))
+	  goto cleanup;
+
+    if ((code = krb5_locate_kpasswd(context,
+                                    krb5_princ_realm(context, creds->server),
+				    &al)))
+        goto cleanup;
+
+    /* this is really obscure.  s1 is used for all communications.  it
+       is left unconnected in case the server is multihomed and routes
+       are asymmetric.  s2 is connected to resolve routes and get
+       addresses.  this is the *only* way to get proper addresses for
+       multihomed hosts if routing is asymmetric.
+
+       A related problem in the server, but not the client, is that
+       many os's have no way to disconnect a connected udp socket, so
+       the s2 socket needs to be closed and recreated for each
+       request.  The s1 socket must not be closed, or else queued
+       requests will be lost.
+
+       A "naive" client implementation (one socket, no connect,
+       hostname resolution to get the local ip addr) will work and
+       interoperate if the client is single-homed. */
+
+    if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
+	code = SOCKET_ERRNO;
+	goto cleanup;
+    }
+
+    if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
+	code = SOCKET_ERRNO;
+	goto cleanup;
+    }
+
+    /*
+     * This really should try fallback addresses in cases of timeouts.
+     * For now, where the MIT KDC implementation only supports one
+     * kpasswd server machine anyways, we'll only try the first IPv4
+     * address we can connect() to.  This isn't right for multi-homed
+     * servers; oh well.
+     */
+    for (i=0; i<al.naddrs; i++) {
+	fd_set fdset;
+	struct timeval timeout;
+
+	/* XXX Now the locate_ functions can return IPv6 addresses.  */
+	if (al.addrs[i]->ai_family != AF_INET)
+	    continue;
+
+	tried_one = 1;
+	if (connect(s2, al.addrs[i]->ai_addr, al.addrs[i]->ai_addrlen) == SOCKET_ERROR) {
+	    if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+		continue; /* try the next addr */
+
+	    code = SOCKET_ERRNO;
+	    goto cleanup;
+	}
+
+        addrlen = sizeof(local_addr);
+
+	if (getsockname(s2, ss2sa(&local_addr), &addrlen) < 0) {
+	    if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+		continue; /* try the next addr */
+
+	    code = SOCKET_ERRNO;
+	    goto cleanup;
+	}
+
+	/* some brain-dead OS's don't return useful information from
+	 * the getsockname call.  Namely, windows and solaris.  */
+
+	if (ss2sin(&local_addr)->sin_addr.s_addr != 0) {
+	    local_kaddr.addrtype = ADDRTYPE_INET;
+	    local_kaddr.length = sizeof(ss2sin(&local_addr)->sin_addr);
+	    local_kaddr.contents = (krb5_octet *) &ss2sin(&local_addr)->sin_addr;
+	} else {
+	    krb5_address **addrs;
+
+	    krb5_os_localaddr(context, &addrs);
+
+	    local_kaddr.magic = addrs[0]->magic;
+	    local_kaddr.addrtype = addrs[0]->addrtype;
+	    local_kaddr.length = addrs[0]->length;
+	    local_kaddr.contents = malloc(addrs[0]->length);
+	    memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
+
+	    krb5_free_addresses(context, addrs);
+	}
+
+	addrlen = sizeof(remote_addr);
+	if (getpeername(s2, ss2sa(&remote_addr), &addrlen) < 0) {
+	    if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+		continue; /* try the next addr */
+
+	    code = SOCKET_ERRNO;
+	    goto cleanup;
+	}
+
+	remote_kaddr.addrtype = ADDRTYPE_INET;
+	remote_kaddr.length = sizeof(ss2sin(&remote_addr)->sin_addr);
+	remote_kaddr.contents = (krb5_octet *) &ss2sin(&remote_addr)->sin_addr;
+
+	/* mk_priv requires that the local address be set.
+	   getsockname is used for this.  rd_priv requires that the
+	   remote address be set.  recvfrom is used for this.  If
+	   rd_priv is given a local address, and the message has the
+	   recipient addr in it, this will be checked.  However, there
+	   is simply no way to know ahead of time what address the
+	   message will be delivered *to*.  Therefore, it is important
+	   that either no recipient address is in the messages when
+	   mk_priv is called, or that no local address is passed to
+	   rd_priv.  Both is a better idea, and I have done that.  In
+	   summary, when mk_priv is called, *only* a local address is
+	   specified.  when rd_priv is called, *only* a remote address
+	   is specified.  Are we having fun yet?  */
+
+	if ((code = krb5_auth_con_setaddrs(context, auth_context,
+					   &local_kaddr, NULL))) {
+	  goto cleanup;
+	}
+
+	if( set_password_for )
+		code = krb5int_mk_setpw_req(context, auth_context, &ap_req, set_password_for, newpw, &chpw_req);
+	else
+		code = krb5int_mk_chpw_req(context, auth_context, &ap_req, newpw, &chpw_req);
+	if (code)
+	{
+	    goto cleanup;
+	}
+
+	if ((cc = sendto(s1, chpw_req.data, 
+			 (GETSOCKNAME_ARG3_TYPE) chpw_req.length, 0,
+			 al.addrs[i]->ai_addr, al.addrs[i]->ai_addrlen)) != chpw_req.length)
+	{
+	    if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) ||
+			     (SOCKET_ERRNO == EHOSTUNREACH)))
+		continue; /* try the next addr */
+
+	    code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED;
+	    goto cleanup;
+	}
+
+	chpw_rep.length = 1500;
+	chpw_rep.data = (char *) malloc(chpw_rep.length);
+
+	/* XXX need a timeout/retry loop here */
+	FD_ZERO (&fdset);
+	FD_SET (s1, &fdset);
+	timeout.tv_sec = 120;
+	timeout.tv_usec = 0;
+	switch (select (s1 + 1, &fdset, 0, 0, &timeout)) {
+	case -1:
+	    code = SOCKET_ERRNO;
+	    goto cleanup;
+	case 0:
+	    code = ETIMEDOUT;
+	    goto cleanup;
+	default:
+	    /* fall through */
+	    ;
+	}
+
+	/* "recv" would be good enough here... except that Windows/NT
+	   commits the atrocity of returning -1 to indicate failure,
+	   but leaving errno set to 0.
+
+	   "recvfrom(...,NULL,NULL)" would seem to be a good enough
+	   alternative, and it works on NT, but it doesn't work on
+	   SunOS 4.1.4 or Irix 5.3.  Thus we must actually accept the
+	   value and discard it. */
+	tmp_len = sizeof(tmp_addr);
+	if ((cc = recvfrom(s1, chpw_rep.data, 
+			   (GETSOCKNAME_ARG3_TYPE) chpw_rep.length,
+			   0, ss2sa(&tmp_addr), &tmp_len)) < 0)
+	{
+	    code = SOCKET_ERRNO;
+	    goto cleanup;
+	}
+
+	closesocket(s1);
+	s1 = INVALID_SOCKET;
+	closesocket(s2);
+	s2 = INVALID_SOCKET;
+
+	chpw_rep.length = cc;
+
+	if ((code = krb5_auth_con_setaddrs(context, auth_context,
+					   NULL, &remote_kaddr)))
+	    goto cleanup;
+
+	if( set_password_for )
+		code = krb5int_rd_setpw_rep(context, auth_context, &chpw_rep, &local_result_code, result_string);
+	else
+		code = krb5int_rd_chpw_rep(context, auth_context, &chpw_rep, &local_result_code, result_string);
+	if (code)
+		goto cleanup;
+
+	if (result_code)
+	    *result_code = local_result_code;
+
+	if (result_code_string) {
+		if( set_password_for )
+	    	code = krb5int_setpw_result_code_string(context, local_result_code, (const char **)&code_string);
+		else
+	    	code = krb5_chpw_result_code_string(context, local_result_code, &code_string);
+		if(code)
+			goto cleanup;
+
+	    result_code_string->length = strlen(code_string);
+	    result_code_string->data = malloc(result_code_string->length);
+	    if (result_code_string->data == NULL) {
+		code = ENOMEM;
+		goto cleanup;
+	    }
+	    strncpy(result_code_string->data, code_string, result_code_string->length);
+	}
+
+	code = 0;
+	goto cleanup;
+    }
+
+    if (tried_one)
+	/* Got some non-fatal errors, but didn't get any successes.  */
+	code = SOCKET_ERRNO;
+    else
+	/* Had some addresses, but didn't try any because they weren't
+	   AF_INET addresses and we don't support AF_INET6 addresses
+	   here yet.  */
+	code = EHOSTUNREACH;
+
+cleanup:
+    if (auth_context != NULL)
+	krb5_auth_con_free(context, auth_context);
+
+    krb5int_free_addrlist (&al);
+
+    if (s1 != INVALID_SOCKET)
+	closesocket(s1);
+
+    if (s2 != INVALID_SOCKET)
+	closesocket(s2);
+
+    krb5_free_data_contents(context, &chpw_req);
+    krb5_free_data_contents(context, &chpw_rep);
+    krb5_free_data_contents(context, &ap_req);
+
+    return(code);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_change_password(krb5_context context, krb5_creds *creds, char *newpw, int *result_code, krb5_data *result_code_string, krb5_data *result_string)
+{
+	return krb5_change_set_password(
+		context, creds, newpw, NULL, result_code, result_code_string, result_string );
+}
+
+/*
+ * krb5_set_password - Implements set password per RFC 3244
+ *
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_password(
+	krb5_context context,
+	krb5_creds *creds,
+	char *newpw,
+	krb5_principal change_password_for,
+	int *result_code, krb5_data *result_code_string, krb5_data *result_string
+	)
+{
+	return krb5_change_set_password(
+		context, creds, newpw, change_password_for, result_code, result_code_string, result_string );
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_password_using_ccache(
+	krb5_context context,
+	krb5_ccache ccache,
+	char *newpw,
+	krb5_principal change_password_for,
+	int *result_code, krb5_data *result_code_string, krb5_data *result_string
+	)
+{
+	krb5_creds		creds;
+	krb5_creds		*credsp;
+	krb5_error_code	code;
+
+/*
+** get the proper creds for use with krb5_set_password -
+*/
+	memset( &creds, 0, sizeof(creds) );
+/*
+** first get the principal for the password service -
+*/
+	code = krb5_cc_get_principal( context, ccache, &creds.client );
+	if( !code )
+	{
+		code = krb5_build_principal( context, &creds.server, 
+				krb5_princ_realm(context, change_password_for)->length,
+				krb5_princ_realm(context, change_password_for)->data,
+				"kadmin", "changepw", NULL );
+		if(!code)
+		{
+			code = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
+			if( ! code )
+			{
+				code = krb5_set_password(context, credsp, newpw, change_password_for,
+					result_code, result_code_string,
+					result_string);
+				krb5_free_creds(context, credsp);
+			}
+		}
+		krb5_free_cred_contents(context, &creds);
+	}
+	return code;
+}
diff --git a/mechglue/src/lib/krb5/os/def_realm.c b/mechglue/src/lib/krb5/os/def_realm.c
new file mode 100644
index 000000000..d63f1af63
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/def_realm.c
@@ -0,0 +1,193 @@
+/*
+ * lib/krb5/os/def_realm.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_get_default_realm(), krb5_set_default_realm(),
+ * krb5_free_default_realm() functions.
+ */
+
+#include "k5-int.h"
+#include "os-proto.h"
+#include <stdio.h>
+
+#ifdef KRB5_DNS_LOOKUP	     
+#ifdef WSHELPER
+#include <wshelper.h>
+#else /* WSHELPER */
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+#endif /* WSHELPER */
+
+/* for old Unixes and friends ... */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
+
+#endif /* KRB5_DNS_LOOKUP */
+
+/*
+ * Retrieves the default realm to be used if no user-specified realm is
+ *  available.  [e.g. to interpret a user-typed principal name with the
+ *  realm omitted for convenience]
+ * 
+ *  returns system errors, NOT_ENOUGH_SPACE, KV5M_CONTEXT
+*/
+
+/*
+ * Implementation:  the default realm is stored in a configuration file,
+ * named by krb5_config_file;  the first token in this file is taken as
+ * the default local realm name.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_default_realm(krb5_context context, char **lrealm)
+{
+    char *realm = 0;
+    char *cp;
+    krb5_error_code retval;
+
+    if (!context || (context->magic != KV5M_CONTEXT)) 
+	    return KV5M_CONTEXT;
+
+    if (!context->default_realm) {
+        /*
+         * XXX should try to figure out a reasonable default based
+         * on the host's DNS domain.
+         */
+        context->default_realm = 0;
+        if (context->profile != 0) {
+            retval = profile_get_string(context->profile, "libdefaults",
+                                        "default_realm", 0, 0,
+                                        &realm);
+
+            if (!retval && realm) {
+                context->default_realm = malloc(strlen(realm) + 1);
+                if (!context->default_realm) {
+                    profile_release_string(realm);
+                    return ENOMEM;
+                }
+                strcpy(context->default_realm, realm);
+                profile_release_string(realm);
+            }
+        }
+#ifndef KRB5_DNS_LOOKUP
+        else 
+            return KRB5_CONFIG_CANTOPEN;
+#else /* KRB5_DNS_LOOKUP */
+        if (context->default_realm == 0) {
+            int use_dns =  _krb5_use_dns_realm(context);
+            if ( use_dns ) {
+		/*
+		 * Since this didn't appear in our config file, try looking
+		 * it up via DNS.  Look for a TXT records of the form:
+		 *
+		 * _kerberos.<localhost>
+		 * _kerberos.<domainname>
+		 * _kerberos.<searchlist>
+		 *
+		 */
+		char localhost[MAX_DNS_NAMELEN+1];
+		char * p;
+
+		krb5int_get_fq_local_hostname (localhost, sizeof(localhost));
+
+		if ( localhost[0] ) {
+		    p = localhost;
+		    do {
+			retval = krb5_try_realm_txt_rr("_kerberos", p, 
+						       &context->default_realm);
+			p = strchr(p,'.');
+			if (p)
+			    p++;
+		    } while (retval && p && p[0]);
+
+		    if (retval)
+			retval = krb5_try_realm_txt_rr("_kerberos", "", 
+						       &context->default_realm);
+		} else {
+		    retval = krb5_try_realm_txt_rr("_kerberos", "", 
+						   &context->default_realm);
+		}
+		if (retval) {
+		    return(KRB5_CONFIG_NODEFREALM);
+		}
+            }
+        }
+#endif /* KRB5_DNS_LOOKUP */
+    }
+
+    if (context->default_realm == 0)
+	return(KRB5_CONFIG_NODEFREALM);
+    if (context->default_realm[0] == 0) {
+        free (context->default_realm);
+        context->default_realm = 0;
+        return KRB5_CONFIG_NODEFREALM;
+    }
+
+    realm = context->default_realm;
+    
+    if (!(*lrealm = cp = malloc((unsigned int) strlen(realm) + 1)))
+        return ENOMEM;
+    strcpy(cp, realm);
+    return(0);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_set_default_realm(krb5_context context, const char *lrealm)
+{
+    if (!context || (context->magic != KV5M_CONTEXT)) 
+	    return KV5M_CONTEXT;
+
+    if (context->default_realm) {
+	    free(context->default_realm);
+	    context->default_realm = 0;
+    }
+
+    /* Allow the user to clear the default realm setting by passing in 
+       NULL */
+    if (!lrealm) return 0;
+
+    context->default_realm = malloc(strlen (lrealm) + 1);
+
+    if (!context->default_realm)
+	    return ENOMEM;
+
+    strcpy(context->default_realm, lrealm);
+    return(0);
+
+}
+
+void KRB5_CALLCONV
+krb5_free_default_realm(krb5_context context, char *lrealm)
+{
+	free (lrealm);
+}
diff --git a/mechglue/src/lib/krb5/os/dnsglue.c b/mechglue/src/lib/krb5/os/dnsglue.c
new file mode 100644
index 000000000..bd1eed7db
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/dnsglue.c
@@ -0,0 +1,333 @@
+/*
+ * lib/krb5/os/dnsglue.c
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+#ifdef KRB5_DNS_LOOKUP
+
+#include "dnsglue.h"
+
+/*
+ * Only use res_ninit() if there's also a res_ndestroy(), to avoid
+ * memory leaks (Linux & Solaris) and outright corruption (AIX 4.x,
+ * 5.x).  While we're at it, make sure res_nsearch() is there too.
+ *
+ * In any case, it is probable that platforms having broken
+ * res_ninit() will have thread safety hacks for res_init() and _res.
+ */
+#if HAVE_RES_NINIT && HAVE_RES_NDESTROY && HAVE_RES_NSEARCH
+#define USE_RES_NINIT 1
+#endif
+
+/*
+ * Opaque handle
+ */
+struct krb5int_dns_state {
+    int nclass;
+    int ntype;
+    void *ansp;
+    int anslen;
+    int ansmax;
+#if HAVE_NS_INITPARSE
+    int cur_ans;
+    ns_msg msg;
+#else
+    unsigned char *ptr;
+    unsigned short nanswers;
+#endif
+};
+
+#if !HAVE_NS_INITPARSE
+static int initparse(struct krb5int_dns_state *);
+#endif
+
+/*
+ * krb5int_dns_init()
+ *
+ * Initialize an opaque handle.  Do name lookup and initial parsing of
+ * reply, skipping question section.  Prepare to iterate over answer
+ * section.  Returns -1 on error, 0 on success.
+ */
+int
+krb5int_dns_init(struct krb5int_dns_state **dsp,
+		 char *host, int nclass, int ntype)
+{
+#if USE_RES_NINIT
+    struct __res_state statbuf;
+#endif
+    struct krb5int_dns_state *ds;
+    int len, ret;
+    size_t nextincr, maxincr;
+    unsigned char *p;
+
+    *dsp = ds = malloc(sizeof(*ds));
+    if (ds == NULL)
+	return -1;
+
+    ret = -1;
+    ds->nclass = nclass;
+    ds->ntype = ntype;
+    ds->ansp = NULL;
+    ds->anslen = 0;
+    ds->ansmax = 0;
+    nextincr = 2048;
+    maxincr = INT_MAX;
+
+#if HAVE_NS_INITPARSE
+    ds->cur_ans = 0;
+#endif
+
+#if USE_RES_NINIT
+    ret = res_ninit(&statbuf);
+#else
+    ret = res_init();
+#endif
+    if (ret < 0)
+	return -1;
+
+    do {
+	p = (ds->ansp == NULL)
+	    ? malloc(nextincr) : realloc(ds->ansp, nextincr);
+
+	if (p == NULL && ds->ansp != NULL) {
+	    ret = -1;
+	    goto errout;
+	}
+	ds->ansp = p;
+	ds->ansmax = nextincr;
+
+#if USE_RES_NINIT
+	len = res_nsearch(&statbuf, host, ds->nclass, ds->ntype,
+			  ds->ansp, ds->ansmax);
+#else
+	len = res_search(host, ds->nclass, ds->ntype,
+			 ds->ansp, ds->ansmax);
+#endif
+	if (len > maxincr) {
+	    ret = -1;
+	    goto errout;
+	}
+	while (nextincr < len)
+	    nextincr *= 2;
+	if (len < 0 || nextincr > maxincr) {
+	    ret = -1;
+	    goto errout;
+	}
+    } while (len > ds->ansmax);
+
+    ds->anslen = len;
+#if HAVE_NS_INITPARSE
+    ret = ns_initparse(ds->ansp, ds->anslen, &ds->msg);
+#else
+    ret = initparse(ds);
+#endif
+    if (ret < 0)
+	goto errout;
+
+    ret = 0;
+
+errout:
+#if USE_RES_NINIT
+    res_ndestroy(&statbuf);
+#endif
+    if (ret < 0) {
+	if (ds->ansp != NULL) {
+	    free(ds->ansp);
+	    ds->ansp = NULL;
+	}
+    }
+
+    return ret;
+}
+
+#if HAVE_NS_INITPARSE
+/*
+ * krb5int_dns_nextans - get next matching answer record
+ *
+ * Sets pp to NULL if no more records.  Returns -1 on error, 0 on
+ * success.
+ */
+int
+krb5int_dns_nextans(struct krb5int_dns_state *ds,
+		    const unsigned char **pp, int *lenp)
+{
+    int len;
+    ns_rr rr;
+
+    *pp = NULL;
+    *lenp = 0;
+    while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) {
+	len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr);
+	if (len < 0)
+	    return -1;
+	ds->cur_ans++;
+	if (ds->nclass == ns_rr_class(rr)
+	    && ds->ntype == ns_rr_type(rr)) {
+	    *pp = ns_rr_rdata(rr);
+	    *lenp = ns_rr_rdlen(rr);
+	    return 0;
+	}
+    }
+    return 0;
+}
+#endif
+
+/*
+ * krb5int_dns_expand - wrapper for dn_expand()
+ */
+int krb5int_dns_expand(struct krb5int_dns_state *ds,
+		       const unsigned char *p,
+		       char *buf, int len)
+{
+
+#if HAVE_NS_NAME_UNCOMPRESS
+    return ns_name_uncompress(ds->ansp,
+			      (unsigned char *)ds->ansp + ds->anslen,
+			      p, buf, (size_t)len);
+#else
+    return dn_expand(ds->ansp,
+		     (unsigned char *)ds->ansp + ds->anslen,
+		     p, buf, len);
+#endif
+}
+
+/*
+ * Free stuff.
+ */
+void
+krb5int_dns_fini(struct krb5int_dns_state *ds)
+{
+    if (ds == NULL)
+	return;
+    if (ds->ansp != NULL)
+	free(ds->ansp);
+    free(ds);
+}
+
+/*
+ * Compat routines for BIND 4
+ */
+#if !HAVE_NS_INITPARSE
+
+/*
+ * initparse
+ *
+ * Skip header and question section of reply.  Set a pointer to the
+ * beginning of the answer section, and prepare to iterate over
+ * answer records.
+ */
+static int
+initparse(struct krb5int_dns_state *ds)
+{
+    HEADER *hdr;
+    unsigned char *p;
+    unsigned short nqueries, nanswers;
+    int len;
+#if !HAVE_DN_SKIPNAME
+    char host[MAXDNAME];
+#endif
+
+    if (ds->anslen < sizeof(HEADER))
+	return -1;
+
+    hdr = (HEADER *)ds->ansp;
+    p = ds->ansp;
+    nqueries = ntohs((unsigned short)hdr->qdcount);
+    nanswers = ntohs((unsigned short)hdr->ancount);
+    p += sizeof(HEADER);
+
+    /*
+     * Skip query records.
+     */
+    while (nqueries--) {
+#if HAVE_DN_SKIPNAME
+	len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
+#else
+	len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
+			p, host, sizeof(host));
+#endif
+	if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len + 4))
+	    return -1;
+	p += len + 4;
+    }
+    ds->ptr = p;
+    ds->nanswers = nanswers;
+    return 0;
+}
+
+/*
+ * krb5int_dns_nextans() - get next answer record
+ *
+ * Sets pp to NULL if no more records.
+ */
+int
+krb5int_dns_nextans(struct krb5int_dns_state *ds,
+		    const unsigned char **pp, int *lenp)
+{
+    int len;
+    unsigned char *p;
+    unsigned short ntype, nclass, rdlen;
+#if !HAVE_DN_SKIPNAME
+    char host[MAXDNAME];
+#endif
+
+    *pp = NULL;
+    *lenp = 0;
+    p = ds->ptr;
+
+    while (ds->nanswers--) {
+#if HAVE_DN_SKIPNAME
+	len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
+#else
+	len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
+			p, host, sizeof(host));
+#endif
+	if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len))
+	    return -1;
+	p += len;
+	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out);
+	/* Also skip 4 bytes of TTL */
+	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out);
+	SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out);
+
+	if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen))
+	    return -1;
+	if (rdlen > INT_MAX)
+	    return -1;
+	if (nclass == ds->nclass && ntype == ds->ntype) {
+	    *pp = p;
+	    *lenp = rdlen;
+	    ds->ptr = p + rdlen;
+	    return 0;
+	}
+	p += rdlen;
+    }
+    return 0;
+out:
+    return -1;
+}
+
+#endif
+
+#endif /* KRB5_DNS_LOOKUP */
diff --git a/mechglue/src/lib/krb5/os/dnsglue.h b/mechglue/src/lib/krb5/os/dnsglue.h
new file mode 100644
index 000000000..4164b9a46
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/dnsglue.h
@@ -0,0 +1,156 @@
+/*
+ * lib/krb5/os/dnsglue.h
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Glue layer for DNS resolver, to make parsing of replies easier
+ * whether we are using BIND 4, 8, or 9.
+ */
+
+/*
+ * BIND 4 doesn't have the ns_initparse() API, so we need to do some
+ * manual parsing via the HEADER struct.  BIND 8 does have
+ * ns_initparse(), but has enums for the various protocol constants
+ * rather than the BIND 4 macros.  BIND 9 (at least on Mac OS X
+ * Panther) appears to disable res_nsearch() if BIND_8_COMPAT is
+ * defined (which is necessary to obtain the HEADER struct).
+ *
+ * We use ns_initparse() if available at all, and never define
+ * BIND_8_COMPAT.  If there is no ns_initparse(), we do manual parsing
+ * by using the HEADER struct.
+ */
+
+#ifndef KRB5_DNSGLUE_H
+#define KRB5_DNSGLUE_H
+
+#ifdef KRB5_DNS_LOOKUP
+
+#include "k5-int.h"
+#include "os-proto.h"
+#ifdef WSHELPER
+#include <wshelper.h>
+#else /* WSHELPER */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+#endif /* WSHELPER */
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>		/* for MAXHOSTNAMELEN */
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64	/* if we can't find it elswhere */
+#endif
+
+#ifndef MAXDNAME
+
+#ifdef NS_MAXDNAME
+#define MAXDNAME NS_MAXDNAME
+#else
+#ifdef MAXLABEL
+#define MAXDNAME (16 * MAXLABEL)
+#else
+#define MAXDNAME (16 * MAXHOSTNAMELEN)
+#endif
+#endif
+
+#endif
+
+#if HAVE_NS_INITPARSE
+/*
+ * Solaris 7 has ns_rr_cl rather than ns_rr_class.
+ */
+#if !defined(ns_rr_class) && defined(ns_rr_cl)
+#define ns_rr_class ns_rr_cl
+#endif
+#endif
+
+#if HAVE_RES_NSEARCH
+/*
+ * Some BIND 8 / BIND 9 implementations disable the BIND 4 style
+ * constants.
+ */
+#ifndef C_IN
+#define C_IN ns_c_in
+#endif
+#ifndef T_SRV
+#define T_SRV ns_t_srv
+#endif
+#ifndef T_TXT
+#define T_TXT ns_t_txt
+#endif
+
+#else  /* !HAVE_RES_NSEARCH */
+
+/*
+ * Some BIND implementations might be old enough to lack these.
+ */
+#ifndef T_TXT
+#define T_TXT 15
+#endif
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+
+#endif /* HAVE_RES_NSEARCH */
+
+/*
+ * INCR_OK
+ *
+ * Given moving pointer PTR offset from BASE, return true if adding
+ * INCR to PTR doesn't move it PTR than MAX bytes from BASE.
+ */
+#define INCR_OK(base, max, ptr, incr)				\
+    ((incr) <= (max) - ((const unsigned char *)(ptr)		\
+			- (const unsigned char *)(base)))
+
+/*
+ * SAFE_GETUINT16
+ *
+ * Given PTR offset from BASE, if at least INCR bytes are safe to
+ * read, get network byte order uint16 into S, and increment PTR.  On
+ * failure, goto LABEL.
+ */
+
+#define SAFE_GETUINT16(base, max, ptr, incr, s, label)	\
+    do {						\
+	if (!INCR_OK(base, max, ptr, incr)) goto label;	\
+	(s) = (unsigned short)(p)[0] << 8		\
+	    | (unsigned short)(p)[1];			\
+	(p) += (incr);					\
+    } while (0)
+
+struct krb5int_dns_state;
+
+int krb5int_dns_init(struct krb5int_dns_state **, char *, int, int);
+int krb5int_dns_nextans(struct krb5int_dns_state *,
+			const unsigned char **, int *);
+int krb5int_dns_expand(struct krb5int_dns_state *,
+		       const unsigned char *, char *, int);
+void krb5int_dns_fini(struct krb5int_dns_state *);
+
+#endif /* KRB5_DNS_LOOKUP */
+#endif /* !defined(KRB5_DNSGLUE_H) */
diff --git a/mechglue/src/lib/krb5/os/dnssrv.c b/mechglue/src/lib/krb5/os/dnssrv.c
new file mode 100644
index 000000000..dffdc8d07
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/dnssrv.c
@@ -0,0 +1,184 @@
+/*
+ * lib/krb5/os/dnssrv.c
+ *
+ * Copyright 1990,2000,2001,2002,2003 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * do DNS SRV RR queries
+ */
+
+#ifdef KRB5_DNS_LOOKUP
+
+#include "dnsglue.h"
+
+/*
+ * Lookup a KDC via DNS SRV records
+ */
+
+void krb5int_free_srv_dns_data (struct srv_dns_entry *p)
+{
+    struct srv_dns_entry *next;
+    while (p) {
+	next = p->next;
+	free(p->host);
+	free(p);
+	p = next;
+    }
+}
+
+/* Do DNS SRV query, return results in *answers.
+
+   Make best effort to return all the data we can.  On memory or
+   decoding errors, just return what we've got.  Always return 0,
+   currently.  */
+
+krb5_error_code
+krb5int_make_srv_query_realm(const krb5_data *realm,
+			     const char *service,
+			     const char *protocol,
+			     struct srv_dns_entry **answers)
+{
+    const unsigned char *p = NULL, *base = NULL;
+    char host[MAXDNAME], *h;
+    int size, ret, rdlen, nlen;
+    unsigned short priority, weight, port;
+    struct krb5int_dns_state *ds = NULL;
+
+    struct srv_dns_entry *head = NULL;
+    struct srv_dns_entry *srv = NULL, *entry = NULL;
+
+    /*
+     * First off, build a query of the form:
+     *
+     * service.protocol.realm
+     *
+     * which will most likely be something like:
+     *
+     * _kerberos._udp.REALM
+     *
+     */
+
+    if (memchr(realm->data, 0, realm->length))
+	return 0;
+    if ( strlen(service) + strlen(protocol) + realm->length + 6 
+         > MAXDNAME )
+	return 0;
+    sprintf(host, "%s.%s.%.*s", service, protocol, (int) realm->length,
+	    realm->data);
+
+    /* Realm names don't (normally) end with ".", but if the query
+       doesn't end with "." and doesn't get an answer as is, the
+       resolv code will try appending the local domain.  Since the
+       realm names are absolutes, let's stop that.  
+
+       But only if a name has been specified.  If we are performing
+       a search on the prefix alone then the intention is to allow
+       the local domain or domain search lists to be expanded.  */
+
+    h = host + strlen (host);
+    if ((h[-1] != '.') && ((h - host + 1) < sizeof(host)))
+        strcpy (h, ".");
+
+#ifdef TEST
+    fprintf (stderr, "sending DNS SRV query for %s\n", host);
+#endif
+
+    size = krb5int_dns_init(&ds, host, C_IN, T_SRV);
+    if (size < 0)
+	goto out;
+
+    for (;;) {
+	ret = krb5int_dns_nextans(ds, &base, &rdlen);
+	if (ret < 0 || base == NULL)
+	    goto out;
+
+	p = base;
+
+	SAFE_GETUINT16(base, rdlen, p, 2, priority, out);
+	SAFE_GETUINT16(base, rdlen, p, 2, weight, out);
+	SAFE_GETUINT16(base, rdlen, p, 2, port, out);
+
+	/*
+	 * RFC 2782 says the target is never compressed in the reply;
+	 * do we believe that?  We need to flatten it anyway, though.
+	 */
+	nlen = krb5int_dns_expand(ds, p, host, sizeof(host));
+	if (nlen < 0 || !INCR_OK(base, rdlen, p, nlen))
+	    goto out;
+
+	/*
+	 * We got everything!  Insert it into our list, but make sure
+	 * it's in the right order.  Right now we don't do anything
+	 * with the weight field
+	 */
+
+	srv = (struct srv_dns_entry *) malloc(sizeof(struct srv_dns_entry));
+	if (srv == NULL)
+	    goto out;
+	
+	srv->priority = priority;
+	srv->weight = weight;
+	srv->port = port;
+	/* The returned names are fully qualified.  Don't let the
+	   local resolver code do domain search path stuff.  */
+	if (strlen(host) + 2 < sizeof(host))
+	    strcat(host, ".");
+	srv->host = strdup(host);
+	if (srv->host == NULL) {
+	    free(srv);
+	    goto out;
+	}
+
+	if (head == NULL || head->priority > srv->priority) {
+	    srv->next = head;
+	    head = srv;
+	} else {
+	    /*
+	     * This is confusing.  Only insert an entry into this
+	     * spot if:
+	     * The next person has a higher priority (lower priorities
+	     * are preferred).
+	     * Or
+	     * There is no next entry (we're at the end)
+	     */
+	    for (entry = head; entry != NULL; entry = entry->next) {
+		if ((entry->next &&
+		     entry->next->priority > srv->priority) ||
+		    entry->next == NULL) {
+		    srv->next = entry->next;
+		    entry->next = srv;
+		    break;
+		}
+	    }
+	}
+    }
+
+out:
+    if (ds != NULL) {
+	krb5int_dns_fini(ds);
+	ds = NULL;
+    }
+    *answers = head;
+    return 0;
+}
+#endif
diff --git a/mechglue/src/lib/krb5/os/free_hstrl.c b/mechglue/src/lib/krb5/os/free_hstrl.c
new file mode 100644
index 000000000..4900fce9b
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/free_hstrl.c
@@ -0,0 +1,42 @@
+/*
+ * lib/krb5/os/free_hstrl.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_free_host_realm()
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+
+/*
+ Frees the storage taken by a realm list returned by krb5_get_host_realm.
+ */
+
+krb5_error_code KRB5_CALLCONV
+krb5_free_host_realm(krb5_context context, char *const *realmlist)
+{
+    /* same format, so why duplicate code? */
+    return krb5_free_krbhst(context, realmlist);
+}
diff --git a/mechglue/src/lib/krb5/os/free_krbhs.c b/mechglue/src/lib/krb5/os/free_krbhs.c
new file mode 100644
index 000000000..a10db910c
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/free_krbhs.c
@@ -0,0 +1,45 @@
+/*
+ * lib/krb5/os/free_krbhs.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_free_krbhst() function
+ */
+
+#include "k5-int.h"
+
+/*
+ Frees the storage taken by a host list returned by krb5_get_krbhst.
+ */
+
+krb5_error_code
+krb5_free_krbhst(krb5_context context, char *const *hostlist)
+{
+    register char * const *cp;
+
+    for (cp = hostlist; *cp; cp++)
+	free(*cp);
+    krb5_xfree(hostlist);
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/os/full_ipadr.c b/mechglue/src/lib/krb5/os/full_ipadr.c
new file mode 100644
index 000000000..c72daa8c9
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/full_ipadr.c
@@ -0,0 +1,86 @@
+/*
+ * lib/krb5/os/full_ipadr.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Take an IP addr & port and generate a full IP address.
+ */
+
+#include "k5-int.h"
+
+#ifdef HAVE_NETINET_IN_H
+
+#include "os-proto.h"
+
+krb5_error_code
+krb5_make_full_ipaddr(krb5_context context, krb5_int32 adr,
+		      /*krb5_int16*/int port, krb5_address **outaddr)
+{
+    unsigned long smushaddr = (unsigned long) adr; /* already in net order */
+    unsigned short smushport = (unsigned short) port; /* ditto */
+    register krb5_address *retaddr;
+    register krb5_octet *marshal;
+    krb5_addrtype temptype;
+    krb5_int32 templength;
+
+    if (!(retaddr = (krb5_address *)malloc(sizeof(*retaddr)))) {
+	return ENOMEM;
+    }
+    retaddr->magic = KV5M_ADDRESS;
+    retaddr->addrtype = ADDRTYPE_ADDRPORT;
+    retaddr->length = sizeof(smushaddr)+ sizeof(smushport) +
+	2*sizeof(temptype) + 2*sizeof(templength);
+
+    if (!(retaddr->contents = (krb5_octet *)malloc(retaddr->length))) {
+	krb5_xfree(retaddr);
+	return ENOMEM;
+    }
+    marshal = retaddr->contents;
+
+    temptype = htons(ADDRTYPE_INET);
+    (void) memcpy((char *)marshal, (char *)&temptype, sizeof(temptype));
+    marshal += sizeof(temptype);
+
+    templength = htonl(sizeof(smushaddr));
+    (void) memcpy((char *)marshal, (char *)&templength, sizeof(templength));
+    marshal += sizeof(templength);
+
+    (void) memcpy((char *)marshal, (char *)&smushaddr, sizeof(smushaddr));
+    marshal += sizeof(smushaddr);
+
+    temptype = htons(ADDRTYPE_IPPORT);
+    (void) memcpy((char *)marshal, (char *)&temptype, sizeof(temptype));
+    marshal += sizeof(temptype);
+
+    templength = htonl(sizeof(smushport));
+    (void) memcpy((char *)marshal, (char *)&templength, sizeof(templength));
+    marshal += sizeof(templength);
+
+    (void) memcpy((char *)marshal, (char *)&smushport, sizeof(smushport));
+    marshal += sizeof(smushport);
+
+    *outaddr = retaddr;
+    return 0;
+}
+#endif
diff --git a/mechglue/src/lib/krb5/os/gen_port.c b/mechglue/src/lib/krb5/os/gen_port.c
new file mode 100644
index 000000000..4832cec19
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/gen_port.c
@@ -0,0 +1,49 @@
+/*
+ * lib/krb5/os/gen_port.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Take an IP addr & port and generate a full IP address.
+ */
+
+#include "k5-int.h"
+#include "os-proto.h"
+
+krb5_error_code
+krb5_gen_portaddr(krb5_context context, const krb5_address *addr, krb5_const_pointer ptr, krb5_address **outaddr)
+{
+#ifdef HAVE_NETINET_IN_H
+    krb5_int32 adr;
+    krb5_int16 port;
+
+    if (addr->addrtype != ADDRTYPE_INET)
+	return KRB5_PROG_ATYPE_NOSUPP;
+    port = *(const krb5_int16 *)ptr;
+    
+    memcpy((char *)&adr, (char *)addr->contents, sizeof(adr));
+    return krb5_make_full_ipaddr(context, adr, port, outaddr);
+#else
+    return KRB5_PROG_ATYPE_NOSUPP;
+#endif
+}
diff --git a/mechglue/src/lib/krb5/os/gen_rname.c b/mechglue/src/lib/krb5/os/gen_rname.c
new file mode 100644
index 000000000..7978a5dbc
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/gen_rname.c
@@ -0,0 +1,50 @@
+/*
+ * lib/krb5/os/gen_rname.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * take a port-style address and unique string, and return
+ * a replay cache tag string.
+ */
+
+#include "k5-int.h"
+#include "os-proto.h"
+
+krb5_error_code
+krb5_gen_replay_name(krb5_context context, const krb5_address *address, const char *uniq, char **string)
+{
+    char * tmp;
+    int i;
+
+    if ((*string = malloc(strlen(uniq) + (address->length * 2) + 1)) == NULL)
+	return ENOMEM;
+
+    sprintf(*string, "%s", uniq);
+    tmp = (*string) + strlen(uniq);
+    for (i = 0; i < address->length; i++) {
+	sprintf(tmp, "%.2x", address->contents[i] & 0xff);
+	tmp += 2;
+    }
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/os/genaddrs.c b/mechglue/src/lib/krb5/os/genaddrs.c
new file mode 100644
index 000000000..f3e86a504
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/genaddrs.c
@@ -0,0 +1,130 @@
+/*
+ * lib/krb5/os/genaddrs.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Take an IP addr & port and generate a full IP address.
+ */
+
+#include "k5-int.h"
+#include "os-proto.h"
+
+#if !defined(_WINSOCKAPI_)
+#include <netinet/in.h>
+#endif
+
+struct addrpair {
+    krb5_address addr, port;
+};
+
+#define SET(TARG, THING, TYPE) \
+	((TARG).contents = (krb5_octet *) &(THING),	\
+	 (TARG).length = sizeof (THING),		\
+	 (TARG).addrtype = (TYPE))
+
+static void *cvtaddr (struct sockaddr_storage *a, struct addrpair *ap)
+{
+    switch (ss2sa(a)->sa_family) {
+    case AF_INET:
+	SET (ap->port, ss2sin(a)->sin_port, ADDRTYPE_IPPORT);
+	SET (ap->addr, ss2sin(a)->sin_addr, ADDRTYPE_INET);
+	return a;
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+	SET (ap->port, ss2sin6(a)->sin6_port, ADDRTYPE_IPPORT);
+	if (IN6_IS_ADDR_V4MAPPED (&ss2sin6(a)->sin6_addr)) {
+	    ap->addr.addrtype = ADDRTYPE_INET;
+	    ap->addr.contents = 12 + (krb5_octet *) &ss2sin6(a)->sin6_addr;
+	    ap->addr.length = 4;
+	} else
+	    SET (ap->addr, ss2sin6(a)->sin6_addr, ADDRTYPE_INET6);
+	return a;
+#endif
+    default:
+	return 0;
+    }
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_auth_con_genaddrs(krb5_context context, krb5_auth_context auth_context, int infd, int flags)
+{
+    krb5_error_code 	  retval;
+    krb5_address	* laddr;
+    krb5_address	* lport;
+    krb5_address	* raddr;
+    krb5_address	* rport;
+    SOCKET		fd = (SOCKET) infd;
+    struct addrpair laddrs, raddrs;
+
+#ifdef HAVE_NETINET_IN_H
+    struct sockaddr_storage lsaddr, rsaddr;
+    GETSOCKNAME_ARG3_TYPE ssize;
+
+    ssize = sizeof(struct sockaddr_storage);
+    if ((flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR) ||
+	(flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR)) {
+    	if ((retval = getsockname(fd, (GETSOCKNAME_ARG2_TYPE *) &lsaddr, 
+				  &ssize)))
+	    return retval;
+
+	if (cvtaddr (&lsaddr, &laddrs)) {
+	    laddr = &laddrs.addr;
+	    if (flags & KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR)
+		lport = &laddrs.port;
+	    else
+		lport = 0;
+	} else
+	    return KRB5_PROG_ATYPE_NOSUPP;
+    } else {
+	laddr = NULL;
+	lport = NULL;
+    }
+
+    ssize = sizeof(struct sockaddr_storage);
+    if ((flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) ||
+	(flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_ADDR)) {
+        if ((retval = getpeername(fd, (GETPEERNAME_ARG2_TYPE *) &rsaddr, 
+				  &ssize)))
+	    return errno;
+
+	if (cvtaddr (&rsaddr, &raddrs)) {
+	    raddr = &raddrs.addr;
+	    if (flags & KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)
+		rport = &raddrs.port;
+	    else
+		rport = 0;
+	} else
+	    return KRB5_PROG_ATYPE_NOSUPP;
+    } else {
+	raddr = NULL;
+	rport = NULL;
+    }
+
+    if (!(retval = krb5_auth_con_setaddrs(context, auth_context, laddr, raddr)))
+    	return (krb5_auth_con_setports(context, auth_context, lport, rport));
+    return retval;
+#else
+    return KRB5_PROG_ATYPE_NOSUPP;
+#endif
+}
diff --git a/mechglue/src/lib/krb5/os/get_krbhst.c b/mechglue/src/lib/krb5/os/get_krbhst.c
new file mode 100644
index 000000000..31c77af6f
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/get_krbhst.c
@@ -0,0 +1,128 @@
+/*
+ * lib/krb5/os/get_krbhst.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_get_krbhst() function.
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+#include <ctype.h>
+
+/*
+ Figures out the Kerberos server names for the given realm, filling in a
+ pointer to an argv[] style list of names, terminated with a null pointer.
+ 
+ If the realm is unknown, the filled-in pointer is set to NULL.
+
+ The pointer array and strings pointed to are all in allocated storage,
+ and should be freed by the caller when finished.
+
+ returns system errors
+*/
+
+/*
+ * Implementation:  the server names for given realms are stored in a
+ * configuration file, 
+ * named by krb5_config_file;  the first token (on the first line) in
+ * this file is taken as the default local realm name.
+ * 
+ * Each succeeding line has a realm name as the first token, and a server name
+ * as a second token.  Additional tokens may be present on the line, but
+ * are ignored by this function.
+ *
+ * All lines which begin with the desired realm name will have the
+ * hostname added to the list returned.
+ */
+
+krb5_error_code
+krb5_get_krbhst(krb5_context context, const krb5_data *realm, char ***hostlist)
+{
+    char	**values, **cpp, *cp;
+    const char	*realm_kdc_names[4];
+    krb5_error_code	retval;
+    int	i, count;
+    char **rethosts;
+
+    rethosts = 0;
+
+    realm_kdc_names[0] = "realms";
+    realm_kdc_names[1] = realm->data;
+    realm_kdc_names[2] = "kdc";
+    realm_kdc_names[3] = 0;
+
+    if (context->profile == 0)
+	return KRB5_CONFIG_CANTOPEN;
+
+    retval = profile_get_values(context->profile, realm_kdc_names, &values);
+    if (retval == PROF_NO_SECTION)
+	return KRB5_REALM_UNKNOWN;
+    if (retval == PROF_NO_RELATION)
+	return KRB5_CONFIG_BADFORMAT;
+    if (retval)
+	return retval;
+
+    /*
+     * Do cleanup over the list.  We allow for some extra field to be
+     * added to the kdc line later (maybe the port number)
+     */
+    for (cpp = values; *cpp; cpp++) {
+	cp = strchr(*cpp, ' ');
+	if (cp)
+	    *cp = 0;
+	cp = strchr(*cpp, '\t');
+	if (cp)
+	    *cp = 0;
+	cp = strchr(*cpp, ':');
+	if (cp)
+	    *cp = 0;
+    }
+    count = cpp - values;
+    rethosts = malloc(sizeof(char *) * (count + 1));
+    if (!rethosts) {
+        retval = ENOMEM;
+        goto cleanup;
+    }
+    for (i = 0; i < count; i++) {
+	unsigned int len = strlen (values[i]) + 1;
+        rethosts[i] = malloc(len);
+        if (!rethosts[i]) {
+            retval = ENOMEM;
+            goto cleanup;
+        }
+	memcpy (rethosts[i], values[i], len);
+    }
+    rethosts[count] = 0;
+ cleanup:
+    if (retval && rethosts) {
+        for (cpp = rethosts; *cpp; cpp++)
+            free(*cpp);
+        free(rethosts);
+	rethosts = 0;
+    }
+    profile_free_list(values);
+    *hostlist = rethosts;
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/os/gmt_mktime.c b/mechglue/src/lib/krb5/os/gmt_mktime.c
new file mode 100644
index 000000000..3d10e1a4e
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/gmt_mktime.c
@@ -0,0 +1,127 @@
+/* This code placed in the public domain by Mark W. Eichin */
+
+#include <stdio.h>
+#include "k5-int.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#include <time.h>
+#endif
+
+/* take a struct tm, return seconds from GMT epoch */
+/* like mktime, this ignores tm_wday and tm_yday. */
+/* unlike mktime, this does not set them... it only passes a return value. */
+
+static const int days_in_month[12] = {
+0,				/* jan 31 */
+31,				/* feb 28 */
+59,				/* mar 31 */
+90,				/* apr 30 */
+120,				/* may 31 */
+151,				/* jun 30 */
+181,				/* jul 31 */
+212,				/* aug 31 */
+243,				/* sep 30 */
+273,				/* oct 31 */
+304,				/* nov 30 */
+334				/* dec 31 */
+};
+
+#define hasleapday(year) (year%400?(year%100?(year%4?0:1):0):1)
+
+time_t gmt_mktime(struct tm *t)
+{
+  time_t accum;
+
+#define assert_time(cnd) if(!(cnd)) return (time_t) -1
+
+  /*
+   * For 32-bit signed time_t centered on 1/1/1970, the range is:
+   * time 0x80000000 -> Fri Dec 13 16:45:52 1901
+   * time 0x7fffffff -> Mon Jan 18 22:14:07 2038
+   *
+   * So years 1901 and 2038 are allowable, but we can't encode all
+   * dates in those years, and we're not doing overflow/underflow
+   * checking for such cases.
+   */
+  assert_time(t->tm_year>=1);
+  assert_time(t->tm_year<=138);
+
+  assert_time(t->tm_mon>=0);
+  assert_time(t->tm_mon<=11);
+  assert_time(t->tm_mday>=1);
+  assert_time(t->tm_mday<=31);
+  assert_time(t->tm_hour>=0);
+  assert_time(t->tm_hour<=23);
+  assert_time(t->tm_min>=0);
+  assert_time(t->tm_min<=59);
+  assert_time(t->tm_sec>=0);
+  assert_time(t->tm_sec<=62);
+
+#undef assert_time
+
+
+  accum = t->tm_year - 70;
+  accum *= 365;			/* 365 days/normal year */
+
+  /* add in leap day for all previous years */
+  if (t->tm_year >= 70)
+    accum += (t->tm_year - 69) / 4;
+  else
+    accum -= (72 - t->tm_year) / 4;
+  /* add in leap day for this year */
+  if(t->tm_mon >= 2)		/* march or later */
+    if(hasleapday((t->tm_year + 1900))) accum += 1;
+
+  accum += days_in_month[t->tm_mon];
+  accum += t->tm_mday-1;	/* days of month are the only 1-based field */
+  accum *= 24;			/* 24 hour/day */
+  accum += t->tm_hour;
+  accum *= 60;			/* 60 minute/hour */
+  accum += t->tm_min;
+  accum *= 60;			/* 60 seconds/minute */
+  accum += t->tm_sec;
+
+  return accum;
+}
+
+#ifdef TEST_LEAP
+int
+main (int argc, char *argv[])
+{
+  int yr;
+  time_t t;
+  struct tm tm = {
+    .tm_mon = 0, .tm_mday = 1,
+    .tm_hour = 0, .tm_min = 0, .tm_sec = 0,
+  };
+  for (yr = 60; yr <= 104; yr++)
+    {
+      printf ("1/1/%d%c -> ", 1900 + yr, hasleapday((1900+yr)) ? '*' : ' ');
+      tm.tm_year = yr;
+      t = gmt_mktime (&tm);
+      if (t == (time_t) -1)
+	printf ("-1\n");
+      else
+	{
+	  long u;
+	  if (t % (24 * 60 * 60))
+	    printf ("(not integral multiple of days) ");
+	  u = t / (24 * 60 * 60);
+	  printf ("%3ld*365%+ld\t0x%08lx\n",
+		  (long) (u / 365), (long) (u % 365),
+		  (long) t);
+	}
+    }
+  t = 0x80000000, printf ("time 0x%lx -> %s", t, ctime (&t));
+  t = 0x7fffffff, printf ("time 0x%lx -> %s", t, ctime (&t));
+  return 0;
+}
+#endif
diff --git a/mechglue/src/lib/krb5/os/hostaddr.c b/mechglue/src/lib/krb5/os/hostaddr.c
new file mode 100644
index 000000000..76eb1273d
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/hostaddr.c
@@ -0,0 +1,137 @@
+/*
+ * lib/krb5/os/hostaddr.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * This routine returns a list of krb5 addresses given a hostname.
+ *
+ */
+
+#include "k5-int.h"
+
+#include "fake-addrinfo.h"
+
+krb5_error_code
+krb5_os_hostaddr(krb5_context context, const char *name, krb5_address ***ret_addrs)
+{
+    krb5_error_code 	retval;
+    krb5_address 	**addrs;
+    int			i, j, r;
+    struct addrinfo hints, *ai, *aip;
+
+    if (!name)
+	return KRB5_ERR_BAD_HOSTNAME;
+
+    memset (&hints, 0, sizeof (hints));
+    hints.ai_flags = AI_NUMERICHOST;
+    /* We don't care what kind at this point, really, but without
+       this, we can get back multiple sockaddrs per address, for
+       SOCK_DGRAM, SOCK_STREAM, and SOCK_RAW.  I haven't checked if
+       that's what the spec indicates.  */
+    hints.ai_socktype = SOCK_DGRAM;
+
+    r = getaddrinfo (name, 0, &hints, &ai);
+    if (r && AI_NUMERICHOST != 0) {
+	hints.ai_flags &= ~AI_NUMERICHOST;
+	r = getaddrinfo (name, 0, &hints, &ai);
+    }
+    if (r)
+	return KRB5_ERR_BAD_HOSTNAME;
+
+    for (i = 0, aip = ai; aip; aip = aip->ai_next) {
+	switch (aip->ai_addr->sa_family) {
+	case AF_INET:
+#ifdef KRB5_USE_INET6
+	case AF_INET6:
+#endif
+	    i++;
+	default:
+	    /* Ignore addresses of unknown families.  */
+	    ;
+	}
+    }
+
+    addrs = malloc ((i+1) * sizeof(*addrs));
+    if (!addrs)
+	return errno;
+
+    for (j = 0; j < i + 1; j++)
+	addrs[j] = 0;
+
+    for (i = 0, aip = ai; aip; aip = aip->ai_next) {
+	void *ptr;
+	size_t addrlen;
+	int atype;
+
+	switch (aip->ai_addr->sa_family) {
+	case AF_INET:
+	    addrlen = sizeof (struct in_addr);
+	    ptr = &((struct sockaddr_in *)aip->ai_addr)->sin_addr;
+	    atype = ADDRTYPE_INET;
+	    break;
+#ifdef KRB5_USE_INET6
+	case AF_INET6:
+	    addrlen = sizeof (struct in6_addr);
+	    ptr = &((struct sockaddr_in6 *)aip->ai_addr)->sin6_addr;
+	    atype = ADDRTYPE_INET6;
+	    break;
+#endif
+	default:
+	    continue;
+	}
+	addrs[i] = (krb5_address *) malloc(sizeof(krb5_address));
+	if (!addrs[i]) {
+	    retval = ENOMEM;
+	    goto errout;
+	}
+	addrs[i]->magic = KV5M_ADDRESS;
+	addrs[i]->addrtype = atype;
+	addrs[i]->length = addrlen;
+	addrs[i]->contents = malloc(addrs[i]->length);
+	if (!addrs[i]->contents) {
+	    retval = ENOMEM;
+	    goto errout;
+	}
+	memcpy (addrs[i]->contents, ptr, addrs[i]->length);
+	i++;
+    }
+
+    *ret_addrs = addrs;
+    if (ai)
+	freeaddrinfo(ai);
+    return 0;
+
+errout:
+    if (addrs) {
+	for (i = 0; addrs[i]; i++) {
+	    free (addrs[i]->contents);
+	    free (addrs[i]);
+	}
+	krb5_free_addresses(context, addrs);
+    }
+    if (ai)
+	freeaddrinfo(ai);
+    return retval;
+	
+}
+
diff --git a/mechglue/src/lib/krb5/os/hst_realm.c b/mechglue/src/lib/krb5/os/hst_realm.c
new file mode 100644
index 000000000..b5c8f66ff
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/hst_realm.c
@@ -0,0 +1,385 @@
+/*
+ * lib/krb5/os/hst_realm.c
+ *
+ * Copyright 1990,1991,2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_get_host_realm()
+ */
+
+
+/*
+ Figures out the Kerberos realm names for host, filling in a
+ pointer to an argv[] style list of names, terminated with a null pointer.
+ 
+ If host is NULL, the local host's realms are determined.
+
+ If there are no known realms for the host, the filled-in pointer is set
+ to NULL.
+
+ The pointer array and strings pointed to are all in allocated storage,
+ and should be freed by the caller when finished.
+
+ returns system errors
+*/
+
+/*
+ * Implementation notes:
+ *
+ * this implementation only provides one realm per host, using the same
+ * mapping file used in kerberos v4.
+
+ * Given a fully-qualified domain-style primary host name,
+ * return the name of the Kerberos realm for the host.
+ * If the hostname contains no discernable domain, or an error occurs,
+ * return the local realm name, as supplied by krb5_get_default_realm().
+ * If the hostname contains a domain, but no translation is found,
+ * the hostname's domain is converted to upper-case and returned.
+ *
+ * The format of each line of the translation file is:
+ * domain_name kerberos_realm
+ * -or-
+ * host_name kerberos_realm
+ *
+ * domain_name should be of the form .XXX.YYY (e.g. .LCS.MIT.EDU)
+ * host names should be in the usual form (e.g. FOO.BAR.BAZ)
+ */
+
+
+#include "k5-int.h"
+#include "os-proto.h"
+#include <ctype.h>
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include "fake-addrinfo.h"
+
+#ifdef KRB5_DNS_LOOKUP
+
+#include "dnsglue.h"
+/*
+ * Try to look up a TXT record pointing to a Kerberos realm
+ */
+
+krb5_error_code
+krb5_try_realm_txt_rr(const char *prefix, const char *name, char **realm)
+{
+    krb5_error_code retval = KRB5_ERR_HOST_REALM_UNKNOWN;
+    const unsigned char *p, *base;
+    char host[MAXDNAME], *h;
+    int ret, rdlen, len;
+    struct krb5int_dns_state *ds = NULL;
+
+    /*
+     * Form our query, and send it via DNS
+     */
+
+    if (name == NULL || name[0] == '\0') {
+	if (strlen (prefix) >= sizeof(host)-1)
+	    return KRB5_ERR_HOST_REALM_UNKNOWN;
+        strcpy(host,prefix);
+    } else {
+        if ( strlen(prefix) + strlen(name) + 3 > MAXDNAME )
+            return KRB5_ERR_HOST_REALM_UNKNOWN;
+        sprintf(host,"%s.%s", prefix, name);
+
+        /* Realm names don't (normally) end with ".", but if the query
+           doesn't end with "." and doesn't get an answer as is, the
+           resolv code will try appending the local domain.  Since the
+           realm names are absolutes, let's stop that.  
+
+           But only if a name has been specified.  If we are performing
+           a search on the prefix alone then the intention is to allow
+           the local domain or domain search lists to be expanded.
+        */
+
+        h = host + strlen (host);
+        if ((h > host) && (h[-1] != '.') && ((h - host + 1) < sizeof(host)))
+            strcpy (h, ".");
+    }
+    ret = krb5int_dns_init(&ds, host, C_IN, T_TXT);
+    if (ret < 0)
+	goto errout;
+
+    ret = krb5int_dns_nextans(ds, &base, &rdlen);
+    if (ret < 0 || base == NULL)
+	goto errout;
+
+    p = base;
+    if (!INCR_OK(base, rdlen, p, 1))
+	goto errout;
+    len = *p++;
+    *realm = malloc((size_t)len + 1);
+    if (*realm == NULL) {
+	retval = ENOMEM;
+	goto errout;
+    }
+    strncpy(*realm, (const char *)p, (size_t)len);
+    (*realm)[len] = '\0';
+    /* Avoid a common error. */
+    if ( (*realm)[len-1] == '.' )
+	(*realm)[len-1] = '\0';
+    retval = 0;
+
+errout:
+    if (ds != NULL) {
+	krb5int_dns_fini(ds);
+	ds = NULL;
+    }
+    return retval;
+}
+#else /* KRB5_DNS_LOOKUP */
+#ifndef MAXDNAME
+#define MAXDNAME (16 * MAXHOSTNAMELEN)
+#endif /* MAXDNAME */
+#endif /* KRB5_DNS_LOOKUP */
+
+krb5_error_code krb5int_translate_gai_error (int);
+
+static krb5_error_code
+krb5int_get_fq_hostname (char *buf, size_t bufsize, const char *name)
+{
+    struct addrinfo *ai, hints;
+    int err;
+
+    memset (&hints, 0, sizeof (hints));
+    hints.ai_flags = AI_CANONNAME;
+    err = getaddrinfo (name, 0, &hints, &ai);
+    if (err)
+	return krb5int_translate_gai_error (err);
+    if (ai->ai_canonname == 0)
+	return KRB5_EAI_FAIL;
+    strncpy (buf, ai->ai_canonname, bufsize);
+    buf[bufsize-1] = 0;
+    freeaddrinfo (ai);
+    return 0;
+}
+
+/* Get the local host name, try to make it fully-qualified.
+   Always return a null-terminated string.
+   Might return an error if gethostname fails.  */
+krb5_error_code
+krb5int_get_fq_local_hostname (char *buf, size_t bufsiz)
+{
+    buf[0] = 0;
+    if (gethostname (buf, bufsiz) == -1)
+	return SOCKET_ERRNO;
+    buf[bufsiz - 1] = 0;
+    return krb5int_get_fq_hostname (buf, bufsiz, buf);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_host_realm(krb5_context context, const char *host, char ***realmsp)
+{
+    char **retrealms;
+    char *default_realm, *realm, *cp, *temp_realm;
+    krb5_error_code retval;
+    int l;
+    char local_host[MAXDNAME+1];
+
+    if (host) {
+	/* Filter out numeric addresses if the caller utterly failed to
+	   convert them to names.  */
+	/* IPv4 - dotted quads only */
+	if (strspn(host, "01234567890.") == strlen(host)) {
+	    /* All numbers and dots... if it's three dots, it's an
+	       IP address, and we reject it.  But "12345" could be
+	       a local hostname, couldn't it?  We'll just assume
+	       that a name with three dots is not meant to be an
+	       all-numeric hostname three all-numeric domains down
+	       from the current domain.  */
+	    int ndots = 0;
+	    const char *p;
+	    for (p = host; *p; p++)
+		if (*p == '.')
+		    ndots++;
+	    if (ndots == 3)
+		return KRB5_ERR_NUMERIC_REALM;
+	}
+	if (strchr(host, ':'))
+	    /* IPv6 numeric address form?  Bye bye.  */
+	    return KRB5_ERR_NUMERIC_REALM;
+
+	/* Should probably error out if strlen(host) > MAXDNAME.  */
+	strncpy(local_host, host, sizeof(local_host));
+	local_host[sizeof(local_host) - 1] = '\0';
+    } else {
+	retval = krb5int_get_fq_local_hostname (local_host,
+						sizeof (local_host));
+	if (retval)
+	    return retval;
+    }
+
+    for (cp = local_host; *cp; cp++) {
+	if (isupper((int) (*cp)))
+	    *cp = tolower((int) *cp);
+    }
+    l = strlen(local_host);
+    /* strip off trailing dot */
+    if (l && local_host[l-1] == '.')
+	    local_host[l-1] = 0;
+
+    /*
+       Search for the best match for the host or domain.
+       Example: Given a host a.b.c.d, try to match on:
+         1) A.B.C.D
+	 2) .B.C.D
+	 3) B.C.D
+	 4) .C.D
+	 5) C.D
+	 6) .D
+	 7) D
+     */
+
+    cp = local_host;
+    realm = default_realm = (char *)NULL;
+    temp_realm = 0;
+    while (cp) {
+	retval = profile_get_string(context->profile, "domain_realm", cp,
+				    0, (char *)NULL, &temp_realm);
+	if (retval)
+	    return retval;
+	if (temp_realm != (char *)NULL)
+	    break;	/* Match found */
+
+	/* Setup for another test */
+	if (*cp == '.') {
+	    cp++;
+	    if (default_realm == (char *)NULL) {
+		/* If nothing else works, use the host's domain */
+		default_realm = cp;
+	    }
+	} else {
+	    cp = strchr(cp, '.');
+	}
+    }
+    if (temp_realm) {
+        realm = malloc(strlen(temp_realm) + 1);
+        if (!realm) {
+            profile_release_string(temp_realm);
+            return ENOMEM;
+        }
+        strcpy(realm, temp_realm);
+        profile_release_string(temp_realm);
+    }
+
+#ifdef KRB5_DNS_LOOKUP
+    if (realm == (char *)NULL) {
+        int use_dns = _krb5_use_dns_realm(context);
+        if ( use_dns ) {
+            /*
+             * Since this didn't appear in our config file, try looking
+             * it up via DNS.  Look for a TXT records of the form:
+             *
+             * _kerberos.<hostname>
+             *
+             */
+            cp = local_host;
+            do {
+                retval = krb5_try_realm_txt_rr("_kerberos", cp, &realm);
+                cp = strchr(cp,'.');
+                if (cp) 
+                    cp++;
+            } while (retval && cp && cp[0]);
+        }
+    }
+#endif /* KRB5_DNS_LOOKUP */
+    if (realm == (char *)NULL) {
+        if (default_realm != (char *)NULL) {
+            /* We are defaulting to the realm of the host */
+            if (!(cp = (char *)malloc(strlen(default_realm)+1)))
+                return ENOMEM;
+            strcpy(cp, default_realm);
+            realm = cp;
+
+            /* Assume the realm name is upper case */
+            for (cp = realm; *cp; cp++)
+                if (islower((int) (*cp)))
+                    *cp = toupper((int) *cp);
+        } else {    
+            /* We are defaulting to the local realm */
+            retval = krb5_get_default_realm(context, &realm);
+            if (retval) {
+                return retval;
+            }
+        }
+    }
+    if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) {
+	if (realm != (char *)NULL)
+	    free(realm);
+	return ENOMEM;
+    }
+
+    retrealms[0] = realm;
+    retrealms[1] = 0;
+    
+    *realmsp = retrealms;
+    return 0;
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN32__)
+# ifndef EAFNOSUPPORT
+#  define EAFNOSUPPORT WSAEAFNOSUPPORT
+# endif
+#endif
+
+krb5_error_code
+krb5int_translate_gai_error (int num)
+{
+    switch (num) {
+#ifdef EAI_ADDRFAMILY
+    case EAI_ADDRFAMILY:
+	return EAFNOSUPPORT;
+#endif
+    case EAI_AGAIN:
+	return EAGAIN;
+    case EAI_BADFLAGS:
+	return EINVAL;
+    case EAI_FAIL:
+	return KRB5_EAI_FAIL;
+    case EAI_FAMILY:
+	return EAFNOSUPPORT;
+    case EAI_MEMORY:
+	return ENOMEM;
+#if EAI_NODATA != EAI_NONAME
+    case EAI_NODATA:
+	return KRB5_EAI_NODATA;
+#endif
+    case EAI_NONAME:
+	return KRB5_EAI_NONAME;
+    case EAI_SERVICE:
+	return KRB5_EAI_SERVICE;
+    case EAI_SOCKTYPE:
+	return EINVAL;
+#ifdef EAI_SYSTEM
+    case EAI_SYSTEM:
+	return errno;
+#endif
+    }
+    abort ();
+    return -1;
+}
diff --git a/mechglue/src/lib/krb5/os/init_os_ctx.c b/mechglue/src/lib/krb5/os/init_os_ctx.c
new file mode 100644
index 000000000..f4f9b690a
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/init_os_ctx.c
@@ -0,0 +1,484 @@
+/*
+ * lib/krb5/os/init_ctx.c
+ *
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * krb5_init_contex()
+ */
+
+#define NEED_WINDOWS
+
+#include "k5-int.h"
+#include "os-proto.h"
+
+#ifdef USE_LOGIN_LIBRARY
+#include "KerberosLoginPrivate.h"
+#endif
+
+#if defined(_WIN32)
+#include <winsock.h>
+
+static krb5_error_code
+get_from_windows_dir(
+    char **pname
+    )
+{
+    UINT size = GetWindowsDirectory(0, 0);
+    *pname = malloc(size + 1 +
+                    strlen(DEFAULT_PROFILE_FILENAME) + 1);
+    if (*pname)
+    {
+        GetWindowsDirectory(*pname, size);
+        strcat(*pname, "\\");
+        strcat(*pname, DEFAULT_PROFILE_FILENAME);
+        return 0;
+    } else {
+        return KRB5_CONFIG_CANTOPEN;
+    }
+}
+
+static krb5_error_code
+get_from_module_dir(
+    char **pname
+    )
+{
+    const DWORD size = 1024; /* fixed buffer */
+    int found = 0;
+    char *p;
+    char *name;
+    struct _stat s;
+
+    *pname = 0;
+
+    name = malloc(size);
+    if (!name)
+        return ENOMEM;
+
+    if (!GetModuleFileName(GetModuleHandle("krb5_32"), name, size))
+        goto cleanup;
+
+    p = name + strlen(name);
+    while ((p >= name) && (*p != '\\') && (*p != '/')) p--;
+    if (p < name)
+        goto cleanup;
+    p++;
+    strncpy(p, DEFAULT_PROFILE_FILENAME, size - (p - name));
+    name[size - 1] = 0;
+    found = !_stat(name, &s);
+
+ cleanup:
+    if (found)
+        *pname = name;
+    else
+        if (name) free(name);
+    return 0;
+}
+
+/*
+ * get_from_registry
+ *
+ * This will find a profile in the registry.  *pbuffer != 0 if we
+ * found something.  Make sure to free(*pbuffer) when done.  It will
+ * return an error code if there is an error the user should know
+ * about.  We maintain the invariant: return value != 0 => 
+ * *pbuffer == 0.
+ */
+static krb5_error_code
+get_from_registry(
+    char** pbuffer,
+    HKEY hBaseKey
+    )
+{
+    HKEY hKey = 0;
+    LONG rc = 0;
+    DWORD size = 0;
+    krb5_error_code retval = 0;
+    const char *key_path = "Software\\MIT\\Kerberos5";
+    const char *value_name = "config";
+
+    /* a wannabe assertion */
+    if (!pbuffer)
+    {
+        /*
+         * We have a programming error!  For now, we segfault :)
+         * There is no good mechanism to deal.
+         */
+    }
+    *pbuffer = 0;
+
+    if ((rc = RegOpenKeyEx(hBaseKey, key_path, 0, KEY_QUERY_VALUE, 
+                           &hKey)) != ERROR_SUCCESS)
+    {
+        /* not a real error */
+        goto cleanup;
+    }
+    rc = RegQueryValueEx(hKey, value_name, 0, 0, 0, &size);
+    if ((rc != ERROR_SUCCESS) &&  (rc != ERROR_MORE_DATA))
+    {
+        /* not a real error */
+        goto cleanup;
+    }
+    *pbuffer = malloc(size);
+    if (!*pbuffer)
+    {
+        retval = ENOMEM;
+        goto cleanup;
+    }
+    if ((rc = RegQueryValueEx(hKey, value_name, 0, 0, *pbuffer, &size)) != 
+        ERROR_SUCCESS)
+    {
+        /*
+         * Let's not call it a real error in case it disappears, but
+         * we need to free so that we say we did not find anything.
+         */
+        free(*pbuffer);
+        *pbuffer = 0;
+        goto cleanup;
+    }
+ cleanup:
+    if (hKey)
+        RegCloseKey(hKey);
+    if (retval && *pbuffer)
+    {
+        free(*pbuffer);
+        /* Let's say we did not find anything: */
+        *pbuffer = 0;
+    }
+    return retval;
+}
+
+#endif /* _WIN32 */
+
+static void
+free_filespecs(profile_filespec_t *files)
+{
+    char **cp;
+
+    if (files == 0)
+        return;
+    
+    for (cp = files; *cp; cp++)
+	free(*cp);
+    free(files);
+}
+
+/* This function is needed by KfM's KerberosPreferences API 
+ * because it needs to be able to specify "secure" */
+krb5_error_code
+os_get_default_config_files(profile_filespec_t **pfiles, krb5_boolean secure)
+{
+    profile_filespec_t* files;
+#if defined(_WIN32)
+    krb5_error_code retval = 0;
+    char *name = 0;
+
+    if (!secure)
+    {
+        char *env = getenv("KRB5_CONFIG");
+        if (env)
+        {
+            name = malloc(strlen(env) + 1);
+            if (!name) return ENOMEM;
+            strcpy(name, env);
+        }
+    }
+    if (!name && !secure)
+    {
+        /* HKCU */
+        retval = get_from_registry(&name, HKEY_CURRENT_USER);
+        if (retval) return retval;
+    }
+    if (!name)
+    {
+        /* HKLM */
+        retval = get_from_registry(&name, HKEY_LOCAL_MACHINE);
+        if (retval) return retval;
+    }
+    if (!name && !secure)
+    {
+        /* module dir */
+        retval = get_from_module_dir(&name);
+        if (retval) return retval;
+    }
+    if (!name)
+    {
+        /* windows dir */
+        retval = get_from_windows_dir(&name);
+    }
+    if (retval)
+        return retval;
+    if (!name)
+        return KRB5_CONFIG_CANTOPEN; /* should never happen */
+    
+    files = malloc(2 * sizeof(char *));
+    files[0] = name;
+    files[1] = 0;
+#else /* !_WIN32 */
+    char* filepath = 0;
+    int n_entries, i;
+    unsigned int ent_len;
+    const char *s, *t;
+
+#ifdef USE_LOGIN_LIBRARY
+    /* If __KLAllowHomeDirectoryAccess() == FALSE, we are probably
+        trying to authenticate to a fileserver for the user's homedir. */
+    if (secure || !__KLAllowHomeDirectoryAccess ()) {
+#else
+    if (secure) {
+#endif
+            filepath = DEFAULT_SECURE_PROFILE_PATH;
+    } else { 
+        filepath = getenv("KRB5_CONFIG");
+        if (!filepath) filepath = DEFAULT_PROFILE_PATH;
+    }
+
+    /* count the distinct filename components */
+    for(s = filepath, n_entries = 1; *s; s++) {
+        if (*s == ':')
+            n_entries++;
+    }
+
+    /* the array is NULL terminated */
+    files = (char**) malloc((n_entries+1) * sizeof(char*));
+    if (files == 0)
+        return ENOMEM;
+
+    /* measure, copy, and skip each one */
+    for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++)
+    {
+        ent_len = t-s;
+        files[i] = (char*) malloc(ent_len + 1);
+        if (files[i] == 0) {
+            /* if malloc fails, free the ones that worked */
+            while(--i >= 0) free(files[i]);
+            free(files);
+            return ENOMEM;
+        }
+        strncpy(files[i], s, ent_len);
+        files[i][ent_len] = 0;
+        if (*t == 0) {
+            i++;
+            break;
+        }
+    }
+    /* cap the array */
+    files[i] = 0;
+#endif /* !_WIN32 */
+    *pfiles = (profile_filespec_t *)files;
+    return 0;
+}
+
+
+/* Set the profile paths in the context. If secure is set to TRUE then 
+   do not include user paths (from environment variables, etc.)
+*/
+static krb5_error_code
+os_init_paths(krb5_context ctx)
+{
+    krb5_error_code	retval = 0;
+    profile_filespec_t *files = 0;
+    krb5_boolean secure = ctx->profile_secure;
+
+#ifdef KRB5_DNS_LOOKUP
+    ctx->profile_in_memory = 0;
+#endif /* KRB5_DNS_LOOKUP */
+
+    retval = os_get_default_config_files(&files, secure);
+
+    if (!retval) {
+        retval = profile_init((const_profile_filespec_t *) files,
+			      &ctx->profile);
+
+#ifdef KRB5_DNS_LOOKUP
+        /* if none of the filenames can be opened use an empty profile */
+        if (retval == ENOENT) {
+            retval = profile_init(NULL, &ctx->profile);
+            if (!retval)
+                ctx->profile_in_memory = 1;
+        }   
+#endif /* KRB5_DNS_LOOKUP */
+    }
+
+    if (files)
+        free_filespecs(files);
+
+    if (retval)
+        ctx->profile = 0;
+
+    if (retval == ENOENT)
+        return KRB5_CONFIG_CANTOPEN;
+
+    if ((retval == PROF_SECTION_NOTOP) ||
+        (retval == PROF_SECTION_SYNTAX) ||
+        (retval == PROF_RELATION_SYNTAX) ||
+        (retval == PROF_EXTRA_CBRACE) ||
+        (retval == PROF_MISSING_OBRACE))
+        return KRB5_CONFIG_BADFORMAT;
+
+    return retval;
+}
+
+krb5_error_code
+krb5_os_init_context(krb5_context ctx)
+{
+	krb5_os_context os_ctx;
+	krb5_error_code	retval = 0;
+#ifdef _WIN32
+    WORD wVersionRequested;
+    WSADATA wsaData;
+#endif /* _WIN32 */
+
+	os_ctx = ctx->os_context;
+	os_ctx->magic = KV5M_OS_CONTEXT;
+	os_ctx->time_offset = 0;
+	os_ctx->usec_offset = 0;
+	os_ctx->os_flags = 0;
+	os_ctx->default_ccname = 0;
+
+	retval = os_init_paths(ctx);
+	/*
+	 * If there's an error in the profile, return an error.  Just
+	 * ignoring the error is a Bad Thing (tm).
+	 */
+     
+        if (!retval) {
+                krb5_cc_set_default_name(ctx, NULL);
+
+#ifdef _WIN32
+                /* We initialize winsock to version 1.1 but 
+                 * we do not care if we succeed or fail.
+                 */
+                wVersionRequested = 0x0101;
+                WSAStartup (wVersionRequested, &wsaData);
+#endif /* _WIN32 */
+        }
+	return retval;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_profile (krb5_context ctx, profile_t *profile)
+{
+    krb5_error_code	retval = 0;
+    profile_filespec_t *files = 0;
+
+    retval = os_get_default_config_files(&files, ctx->profile_secure);
+
+    if (!retval) {
+        retval = profile_init((const_profile_filespec_t *) files,
+			      profile);
+    }
+
+    if (files)
+        free_filespecs(files);
+
+    if (retval == ENOENT)
+        return KRB5_CONFIG_CANTOPEN;
+
+    if ((retval == PROF_SECTION_NOTOP) ||
+        (retval == PROF_SECTION_SYNTAX) ||
+        (retval == PROF_RELATION_SYNTAX) ||
+        (retval == PROF_EXTRA_CBRACE) ||
+        (retval == PROF_MISSING_OBRACE))
+        return KRB5_CONFIG_BADFORMAT;
+
+    return retval;
+}	
+
+
+krb5_error_code
+krb5_set_config_files(krb5_context ctx, const char **filenames)
+{
+	krb5_error_code retval;
+	profile_t	profile;
+	
+	retval = profile_init(filenames, &profile);
+	if (retval)
+		return retval;
+
+	if (ctx->profile)
+		profile_release(ctx->profile);
+	ctx->profile = profile;
+
+	return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_default_config_files(char ***pfilenames)
+{
+    if (!pfilenames)
+        return EINVAL;
+    return os_get_default_config_files(pfilenames, FALSE);
+}
+
+void KRB5_CALLCONV
+krb5_free_config_files(char **filenames)
+{
+    free_filespecs(filenames);
+}
+
+
+krb5_error_code
+krb5_secure_config_files(krb5_context ctx)
+{
+	/* Obsolete interface; always return an error.
+
+	   This function should be removed next time a major version
+	   number change happens.  */
+	krb5_error_code retval;
+	
+	if (ctx->profile) {
+		profile_release(ctx->profile);
+		ctx->profile = 0;
+	}
+
+	ctx->profile_secure = TRUE;
+	retval = os_init_paths(ctx);
+	if (retval)
+		return retval;
+
+	return KRB5_OBSOLETE_FN;
+}
+
+void
+krb5_os_free_context(krb5_context ctx)
+{
+	krb5_os_context os_ctx;
+
+	os_ctx = ctx->os_context;
+	
+	if (os_ctx->default_ccname) {
+		free(os_ctx->default_ccname);
+                os_ctx->default_ccname = 0;
+        }
+
+	os_ctx->magic = 0;
+
+	if (ctx->profile) {
+		profile_release(ctx->profile);
+	    ctx->profile = 0;
+	}
+
+#ifdef _WIN32
+        WSACleanup();
+#endif /* _WIN32 */
+}
diff --git a/mechglue/src/lib/krb5/os/krbfileio.c b/mechglue/src/lib/krb5/os/krbfileio.c
new file mode 100644
index 000000000..6ef16ebd0
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/krbfileio.c
@@ -0,0 +1,103 @@
+/*
+ * lib/krb5/os/krbfileio.c
+ *
+ * Copyright (c) Hewlett-Packard Company 1991
+ * Released to the Massachusetts Institute of Technology for inclusion
+ * in the Kerberos source code distribution.
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_create_secure_file
+ * krb5_sync_disk_file
+ */
+
+#ifdef MODULE_VERSION_ID
+static char *VersionID = "@(#)krbfileio.c	2 - 08/22/91";
+#endif
+
+
+#include "k5-int.h"
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#include <fcntl.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifdef apollo
+#   define OPEN_MODE_NOT_TRUSTWORTHY
+#endif
+
+krb5_error_code
+krb5_create_secure_file(krb5_context context, const char *pathname)
+{
+    int fd;
+
+    /*
+     * Create the file with access restricted to the owner
+     */
+    fd = THREEPARAMOPEN(pathname, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+
+#ifdef OPEN_MODE_NOT_TRUSTWORTHY
+    /*
+     * Some systems that support default acl inheritance do not 
+     * apply ownership information from the process - force the file
+     * to have the proper info.
+     */
+    if (fd > -1) {
+        uid_t   uid;
+        gid_t   gid;
+
+        uid = getuid();
+        gid = getgid();
+
+        fchown(fd, uid, gid);
+
+        fchmod(fd, 0600);
+    }
+#endif /* OPEN_MODE_NOT_TRUSTWORTHY */
+
+    if (fd > -1) {
+        close(fd);
+        return 0;
+    } else {
+        return errno;
+    }
+}
+
+krb5_error_code
+krb5_sync_disk_file(krb5_context context, FILE *fp)
+{
+    fflush(fp);
+#if !defined(MSDOS_FILESYSTEM)
+    if (fsync(fileno(fp))) {
+        return errno;
+    }
+#endif
+
+    return 0;
+}
+
diff --git a/mechglue/src/lib/krb5/os/ktdefname.c b/mechglue/src/lib/krb5/os/ktdefname.c
new file mode 100644
index 000000000..62465f102
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/ktdefname.c
@@ -0,0 +1,83 @@
+/*
+ * lib/krb5/os/ktdefname.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Return default keytab file name.
+ */
+
+#define NEED_WINDOWS
+
+#include "k5-int.h"
+
+extern char *krb5_defkeyname;
+
+/* this is a an exceedinly gross thing. */
+char *krb5_overridekeyname = NULL;
+
+krb5_error_code KRB5_CALLCONV
+krb5_kt_default_name(krb5_context context, char *name, int namesize)
+{
+    char *cp = 0;
+    char *retval;
+
+    if (krb5_overridekeyname) {
+	if ((size_t) namesize < (strlen(krb5_overridekeyname)+1))
+	    return KRB5_CONFIG_NOTENUFSPACE;
+	strcpy(name, krb5_overridekeyname);
+    } else if ((context->profile_secure == FALSE) &&
+	(cp = getenv("KRB5_KTNAME"))) {
+	if ((size_t) namesize < (strlen(cp)+1))
+	    return KRB5_CONFIG_NOTENUFSPACE;
+	strcpy(name, cp);
+    } else if ((profile_get_string(context->profile,
+				   "libdefaults",
+				   "default_keytab_name", NULL, 
+				   NULL, &retval) == 0) &&
+	       retval) {
+	if ((size_t) namesize < (strlen(retval)+1))
+	    return KRB5_CONFIG_NOTENUFSPACE;
+	strcpy(name, retval);
+	profile_release_string(retval);
+    } else {
+#if defined(_WIN32)
+	{
+	    char    defname[160];
+	    int     len;
+
+	    len= GetWindowsDirectory( defname, sizeof(defname)-2 );
+	    defname[len]= '\0';
+	    if ( (len + strlen(krb5_defkeyname) + 1) > namesize )
+		return KRB5_CONFIG_NOTENUFSPACE;
+	    sprintf(name, krb5_defkeyname, defname);
+	}
+#else
+	if ((size_t) namesize < (strlen(krb5_defkeyname)+1))
+	    return KRB5_CONFIG_NOTENUFSPACE;
+	strcpy(name, krb5_defkeyname);
+#endif
+    }
+    return 0;
+}
+    
diff --git a/mechglue/src/lib/krb5/os/kuserok.c b/mechglue/src/lib/krb5/os/kuserok.c
new file mode 100644
index 000000000..356b98706
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/kuserok.c
@@ -0,0 +1,164 @@
+/*
+ * lib/krb5/os/kuserok.c
+ *
+ * Copyright 1990,1993 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_kuserok()
+ */
+
+#include "k5-int.h"
+#if !defined(_WIN32)		/* Not yet for Windows */
+#include <stdio.h>
+#include <pwd.h>
+
+#if defined(_AIX) && defined(_IBMR2)
+#include <sys/access.h>
+/* xlc has a bug with "const" */
+#define getpwnam(user) getpwnam((char *)user)
+#endif
+
+#define MAX_USERNAME 65
+
+/*
+ * Given a Kerberos principal "principal", and a local username "luser",
+ * determine whether user is authorized to login according to the
+ * authorization file ("~luser/.k5login" by default).  Returns TRUE
+ * if authorized, FALSE if not authorized.
+ *
+ * If there is no account for "luser" on the local machine, returns
+ * FALSE.  If there is no authorization file, and the given Kerberos
+ * name "server" translates to the same name as "luser" (using
+ * krb5_aname_to_lname()), returns TRUE.  Otherwise, if the authorization file
+ * can't be accessed, returns FALSE.  Otherwise, the file is read for
+ * a matching principal name, instance, and realm.  If one is found,
+ * returns TRUE, if none is found, returns FALSE.
+ *
+ * The file entries are in the format produced by krb5_unparse_name(),
+ * one entry per line.
+ *
+ */
+
+krb5_boolean KRB5_CALLCONV
+krb5_kuserok(krb5_context context, krb5_principal principal, const char *luser)
+{
+    struct stat sbuf;
+    struct passwd *pwd;
+    char pbuf[MAXPATHLEN];
+    krb5_boolean isok = FALSE;
+    FILE *fp;
+    char kuser[MAX_USERNAME];
+    char *princname;
+    char linebuf[BUFSIZ];
+    char *newline;
+    int gobble;
+
+    /* no account => no access */
+    char pwbuf[BUFSIZ];
+    struct passwd pwx;
+    if (k5_getpwnam_r(luser, &pwx, pwbuf, sizeof(pwbuf), &pwd) != 0)
+	return(FALSE);
+    (void) strncpy(pbuf, pwd->pw_dir, sizeof(pbuf) - 1);
+    pbuf[sizeof(pbuf) - 1] = '\0';
+    (void) strncat(pbuf, "/.k5login", sizeof(pbuf) - 1 - strlen(pbuf));
+
+    if (access(pbuf, F_OK)) {	 /* not accessible */
+	/*
+	 * if he's trying to log in as himself, and there is no .k5login file,
+	 * let him.  To find out, call
+	 * krb5_aname_to_localname to convert the principal to a name
+	 * which we can string compare. 
+	 */
+	if (!(krb5_aname_to_localname(context, principal,
+				      sizeof(kuser), kuser))
+	    && (strcmp(kuser, luser) == 0)) {
+	    return(TRUE);
+	}
+    }
+    if (krb5_unparse_name(context, principal, &princname))
+	return(FALSE);			/* no hope of matching */
+
+    /* open ~/.k5login */
+    if ((fp = fopen(pbuf, "r")) == NULL) {
+	free(princname);
+	return(FALSE);
+    }
+    /*
+     * For security reasons, the .k5login file must be owned either by
+     * the user himself, or by root.  Otherwise, don't grant access.
+     */
+    if (fstat(fileno(fp), &sbuf)) {
+	fclose(fp);
+	free(princname);
+	return(FALSE);
+    }
+    if ((sbuf.st_uid != pwd->pw_uid) && sbuf.st_uid) {
+	fclose(fp);
+	free(princname);
+	return(FALSE);
+    }
+
+    /* check each line */
+    while (!isok && (fgets(linebuf, BUFSIZ, fp) != NULL)) {
+	/* null-terminate the input string */
+	linebuf[BUFSIZ-1] = '\0';
+	newline = NULL;
+	/* nuke the newline if it exists */
+	if ((newline = strchr(linebuf, '\n')))
+	    *newline = '\0';
+	if (!strcmp(linebuf, princname)) {
+	    isok = TRUE;
+	    continue;
+	}
+	/* clean up the rest of the line if necessary */
+	if (!newline)
+	    while (((gobble = getc(fp)) != EOF) && gobble != '\n');
+    }
+    free(princname);
+    fclose(fp);
+    return(isok);
+}
+
+#else /* _WIN32 */
+
+/*
+ * If the given Kerberos name "server" translates to the same name as "luser"
+ * (using * krb5_aname_to_lname()), returns TRUE.
+ */
+krb5_boolean KRB5_CALLCONV
+krb5_kuserok(context, principal, luser)
+    krb5_context context;
+    krb5_principal principal;
+    const char *luser;
+{
+    char kuser[50];
+
+    if (krb5_aname_to_localname(context, principal, sizeof(kuser), kuser))
+        return FALSE;
+
+    if (strcmp(kuser, luser) == 0)
+	    return TRUE;
+
+    return FALSE;
+}
+#endif /* _WIN32 */
diff --git a/mechglue/src/lib/krb5/os/localaddr.c b/mechglue/src/lib/krb5/os/localaddr.c
new file mode 100644
index 000000000..75953b1f3
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/localaddr.c
@@ -0,0 +1,1565 @@
+/*
+ * lib/krb5/os/localaddr.c
+ *
+ * Copyright 1990,1991,2000,2001,2002,2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Return the protocol addresses supported by this host.
+ * Exports from this file:
+ *   krb5int_foreach_localaddr (does callbacks)
+ *   krb5int_local_addresses (includes krb5.conf extra_addresses)
+ *   krb5_os_localaddr (doesn't)
+ *
+ * XNS support is untested, but "Should just work".  (Hah!)
+ */
+
+#include "k5-int.h"
+
+#if !defined(_WIN32)
+
+/* needed for solaris, harmless elsewhere... */
+#define BSD_COMP
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <stddef.h>
+#include <ctype.h>
+
+#if defined(TEST) || defined(DEBUG)
+# include "fake-addrinfo.h"
+#endif
+
+#include "foreachaddr.h"
+
+/* Note: foreach_localaddr is exported from the library through
+   krb5int_accessor, for the KDC to use.
+
+   This function iterates over all the addresses it can find for the
+   local system, in one or two passes.  In each pass, and between the
+   two, it can invoke callback functions supplied by the caller.  The
+   two passes should operate on the same information, though not
+   necessarily in the same order each time.  Duplicate and local
+   addresses should be eliminated.  Storage passed to callback
+   functions should not be assumed to be valid after foreach_localaddr
+   returns.
+
+   The int return value is an errno value (XXX or krb5_error_code
+   returned for a socket error) if something internal to
+   foreach_localaddr fails.  If one of the callback functions wants to
+   indicate an error, it should store something via the 'data' handle.
+   If any callback function returns a non-zero value,
+   foreach_localaddr will clean up and return immediately.
+
+   Multiple definitions are provided below, dependent on various
+   system facilities for extracting the necessary information.  */
+
+/* Now, on to the implementations, and heaps of debugging code.  */
+
+#ifdef TEST
+# define Tprintf(X) printf X
+# define Tperror(X) perror(X)
+#else
+# define Tprintf(X) (void) X
+# define Tperror(X) (void)(X)
+#endif
+
+/*
+ * The SIOCGIF* ioctls require a socket.
+ * It doesn't matter *what* kind of socket they use, but it has to be
+ * a socket.
+ *
+ * Of course, you can't just ask the kernel for a socket of arbitrary
+ * type; you have to ask for one with a valid type.
+ *
+ */
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#ifndef USE_AF
+#define USE_AF AF_INET
+#define USE_TYPE SOCK_DGRAM
+#define USE_PROTO 0
+#endif
+#endif
+
+#ifdef KRB5_USE_NS
+#include <netns/ns.h>
+#ifndef USE_AF
+#define USE_AF AF_NS
+#define USE_TYPE SOCK_DGRAM
+#define USE_PROTO 0		/* guess */
+#endif
+#endif
+/*
+ * Add more address families here.
+ */
+
+
+#if defined(__linux__) && defined(KRB5_USE_INET6) && !defined(HAVE_IFADDRS_H)
+#define LINUX_IPV6_HACK
+#endif
+
+#include <errno.h>
+
+/*
+ * Return all the protocol addresses of this host.
+ *
+ * We could kludge up something to return all addresses, assuming that
+ * they're valid kerberos protocol addresses, but we wouldn't know the
+ * real size of the sockaddr or know which part of it was actually the
+ * host part.
+ *
+ * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
+ */
+
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is 
+ * just sizeof(struct ifreq).
+ */
+#ifdef HAVE_SA_LEN
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+     sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN*/
+
+#if defined(DEBUG) || defined(TEST)
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include "socket-utils.h"
+#include "fake-addrinfo.h"
+
+void printaddr (struct sockaddr *);
+
+void printaddr (struct sockaddr *sa)
+    /*@modifies fileSystem@*/
+{
+    char buf[NI_MAXHOST];
+    int err;
+
+    printf ("%p ", (void *) sa);
+    err = getnameinfo (sa, socklen (sa), buf, sizeof (buf), 0, 0,
+		       NI_NUMERICHOST);
+    if (err)
+	printf ("<getnameinfo error %d: %s> family=%d",
+		err, gai_strerror (err),
+		sa->sa_family);
+    else
+	printf ("%s", buf);
+}
+#endif
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+
+#ifdef DEBUG
+void printifaddr (struct ifaddrs *ifp)
+{
+    printf ("%p={\n", ifp);
+/*  printf ("\tnext=%p\n", ifp->ifa_next); */
+    printf ("\tname=%s\n", ifp->ifa_name);
+    printf ("\tflags=");
+    {
+	int ch, flags = ifp->ifa_flags;
+	printf ("%x", flags);
+	ch = '<';
+#define X(F) if (flags & IFF_##F) { printf ("%c%s", ch, #F); flags &= ~IFF_##F; ch = ','; }
+	X (UP); X (BROADCAST); X (DEBUG); X (LOOPBACK); X (POINTOPOINT);
+	X (NOTRAILERS); X (RUNNING); X (NOARP); X (PROMISC); X (ALLMULTI);
+#ifdef IFF_OACTIVE
+	X (OACTIVE);
+#endif
+#ifdef IFF_SIMPLE
+	X (SIMPLEX);
+#endif
+	X (MULTICAST);
+	printf (">");
+#undef X
+    }
+    if (ifp->ifa_addr)
+	printf ("\n\taddr="), printaddr (ifp->ifa_addr);
+    if (ifp->ifa_netmask)
+	printf ("\n\tnetmask="), printaddr (ifp->ifa_netmask);
+    if (ifp->ifa_broadaddr)
+	printf ("\n\tbroadaddr="), printaddr (ifp->ifa_broadaddr);
+    if (ifp->ifa_dstaddr)
+	printf ("\n\tdstaddr="), printaddr (ifp->ifa_dstaddr);
+    if (ifp->ifa_data)
+	printf ("\n\tdata=%p", ifp->ifa_data);
+    printf ("\n}\n");
+}
+#endif /* DEBUG */
+
+#include <string.h>
+#include <stdlib.h>
+
+static int
+addr_eq (const struct sockaddr *s1, const struct sockaddr *s2)
+{
+    if (s1->sa_family != s2->sa_family)
+	return 0;
+#ifdef HAVE_SA_LEN
+    if (s1->sa_len != s2->sa_len)
+	return 0;
+    return !memcmp (s1, s2, s1->sa_len);
+#else
+#define CMPTYPE(T,F) (!memcmp(&((const T*)s1)->F,&((const T*)s2)->F,sizeof(((const T*)s1)->F)))
+    switch (s1->sa_family) {
+    case AF_INET:
+	return CMPTYPE (struct sockaddr_in, sin_addr);
+    case AF_INET6:
+	return CMPTYPE (struct sockaddr_in6, sin6_addr);
+    default:
+	/* Err on side of duplicate listings.  */
+	return 0;
+    }
+#endif
+}
+#endif
+
+#ifndef HAVE_IFADDRS_H
+/*@-usereleased@*/ /* lclint doesn't understand realloc */
+static /*@null@*/ void *
+grow_or_free (/*@only@*/ void *ptr, size_t newsize)
+     /*@*/
+{
+    void *newptr;
+    newptr = realloc (ptr, newsize);
+    if (newptr == NULL && newsize != 0) {
+	free (ptr);		/* lclint complains but this is right */
+	return NULL;
+    }
+    return newptr;
+}
+/*@=usereleased@*/
+
+static int
+get_ifconf (int s, size_t *lenp, /*@out@*/ char *buf)
+    /*@modifies *buf,*lenp@*/
+{
+    int ret;
+    struct ifconf ifc;
+
+    /*@+matchanyintegral@*/
+    ifc.ifc_len = *lenp;
+    /*@=matchanyintegral@*/
+    ifc.ifc_buf = buf;
+    memset(buf, 0, *lenp);
+    /*@-moduncon@*/
+    ret = ioctl (s, SIOCGIFCONF, (char *)&ifc);
+    /*@=moduncon@*/
+    /*@+matchanyintegral@*/
+    *lenp = ifc.ifc_len;
+    /*@=matchanyintegral@*/
+    return ret;
+}
+
+/* Solaris uses SIOCGLIFCONF to return struct lifconf which is just
+   an extended version of struct ifconf.
+
+   HP-UX 11 also appears to have SIOCGLIFCONF, but uses struct
+   if_laddrconf, and struct if_laddrreq to be used with
+   SIOCGLIFADDR.  */
+#if defined(SIOCGLIFCONF) && defined(HAVE_STRUCT_LIFCONF)
+static int
+get_lifconf (int af, int s, size_t *lenp, /*@out@*/ char *buf)
+    /*@modifies *buf,*lenp@*/
+{
+    int ret;
+    struct lifconf lifc;
+
+    lifc.lifc_family = af;
+    lifc.lifc_flags = 0;
+    /*@+matchanyintegral@*/
+    lifc.lifc_len = *lenp;
+    /*@=matchanyintegral@*/
+    lifc.lifc_buf = buf;
+    memset(buf, 0, *lenp);
+    /*@-moduncon@*/
+    ret = ioctl (s, SIOCGLIFCONF, (char *)&lifc);
+    if (ret)
+	Tperror ("SIOCGLIFCONF");
+    /*@=moduncon@*/
+    /*@+matchanyintegral@*/
+    *lenp = lifc.lifc_len;
+    /*@=matchanyintegral@*/
+    return ret;
+}
+#endif
+#if defined(SIOCGLIFCONF) && defined(HAVE_STRUCT_IF_LADDRCONF) && 0
+/* I'm not sure if this is needed or if net/if.h will pull it in.  */
+/* #include <net/if6.h> */
+static int
+get_if_laddrconf (int af, int s, size_t *lenp, /*@out@*/ char *buf)
+    /*@modifies *buf,*lenp@*/
+{
+    int ret;
+    struct if_laddrconf iflc;
+
+    /*@+matchanyintegral@*/
+    iflc.iflc_len = *lenp;
+    /*@=matchanyintegral@*/
+    iflc.iflc_buf = buf;
+    memset(buf, 0, *lenp);
+    /*@-moduncon@*/
+    ret = ioctl (s, SIOCGLIFCONF, (char *)&iflc);
+    if (ret)
+	Tperror ("SIOCGLIFCONF");
+    /*@=moduncon@*/
+    /*@+matchanyintegral@*/
+    *lenp = iflc.iflc_len;
+    /*@=matchanyintegral@*/
+    return ret;
+}
+#endif
+#endif /* ! HAVE_IFADDRS_H */
+
+#ifdef LINUX_IPV6_HACK
+#include <stdio.h>
+/* Read IPv6 addresses out of /proc/net/if_inet6, since there isn't
+   (currently) any ioctl to return them.  */
+struct linux_ipv6_addr_list {
+    struct sockaddr_in6 addr;
+    struct linux_ipv6_addr_list *next;
+};
+static struct linux_ipv6_addr_list *
+get_linux_ipv6_addrs ()
+{
+    struct linux_ipv6_addr_list *lst = 0;
+    FILE *f;
+
+    /* _PATH_PROCNET_IFINET6 */
+    f = fopen("/proc/net/if_inet6", "r");
+    if (f) {
+	char ifname[21];
+	unsigned int idx, pfxlen, scope, dadstat;
+	struct in6_addr a6;
+	struct linux_ipv6_addr_list *nw;
+	int i;
+	unsigned int addrbyte[16];
+
+	while (fscanf(f,
+		      "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x"
+		      " %2x %2x %2x %2x %20s\n",
+		      &addrbyte[0], &addrbyte[1], &addrbyte[2], &addrbyte[3],
+		      &addrbyte[4], &addrbyte[5], &addrbyte[6], &addrbyte[7],
+		      &addrbyte[8], &addrbyte[9], &addrbyte[10], &addrbyte[11],
+		      &addrbyte[12], &addrbyte[13], &addrbyte[14],
+		      &addrbyte[15],
+		      &idx, &pfxlen, &scope, &dadstat, ifname) != EOF) {
+	    for (i = 0; i < 16; i++)
+		a6.s6_addr[i] = addrbyte[i];
+	    if (scope != 0)
+		continue;
+#if 0 /* These symbol names are as used by ifconfig, but none of the
+	 system header files export them.  Dig up the kernel versions
+	 someday and see if they're exported.  */
+	    switch (scope) {
+	    case 0:
+	    default:
+		break;
+	    case IPV6_ADDR_LINKLOCAL:
+	    case IPV6_ADDR_SITELOCAL:
+	    case IPV6_ADDR_COMPATv4:
+	    case IPV6_ADDR_LOOPBACK:
+		continue;
+	    }
+#endif
+	    nw = malloc (sizeof (struct linux_ipv6_addr_list));
+	    if (nw == 0)
+		continue;
+	    memset (nw, 0, sizeof (*nw));
+	    nw->addr.sin6_addr = a6;
+	    nw->addr.sin6_family = AF_INET6;
+	    /* Ignore other fields, we don't actually use them here.  */
+	    nw->next = lst;
+	    lst = nw;
+	}
+	fclose (f);
+    }
+    return lst;
+}
+#endif
+
+/* Return value is errno if internal stuff failed, otherwise zero,
+   even in the case where a called function terminated the iteration.
+
+   If one of the callback functions wants to pass back an error
+   indication, it should do it via some field pointed to by the DATA
+   argument.  */
+
+#ifdef HAVE_IFADDRS_H
+
+int
+foreach_localaddr (/*@null@*/ void *data,
+		   int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
+		   /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
+		   /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
+					      struct sockaddr *) /*@*/)
+#if defined(DEBUG) || defined(TEST)
+     /*@modifies fileSystem@*/
+#endif
+{
+    struct ifaddrs *ifp_head, *ifp, *ifp2;
+    int match;
+
+    if (getifaddrs (&ifp_head) < 0)
+	return errno;
+    for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
+#ifdef DEBUG
+	printifaddr (ifp);
+#endif
+	if ((ifp->ifa_flags & IFF_UP) == 0)
+	    continue;
+	if (ifp->ifa_flags & IFF_LOOPBACK) {
+	    /* Pretend it's not up, so the second pass will skip
+	       it.  */
+	    ifp->ifa_flags &= ~IFF_UP;
+	    continue;
+	}
+	if (ifp->ifa_addr == NULL) {
+	    /* Can't use an interface without an address.  Linux
+	       apparently does this sometimes.  [RT ticket 1770 from
+	       Maurice Massar, also Debian bug 206851, shows the
+	       problem with a PPP link on a newer kernel than I'm
+	       running.]
+
+	       Pretend it's not up, so the second pass will skip
+	       it.  */
+	    ifp->ifa_flags &= ~IFF_UP;
+	    continue;
+	}
+	/* If this address is a duplicate, punt.  */
+	match = 0;
+	for (ifp2 = ifp_head; ifp2 && ifp2 != ifp; ifp2 = ifp2->ifa_next) {
+	    if ((ifp2->ifa_flags & IFF_UP) == 0)
+		continue;
+	    if (ifp2->ifa_flags & IFF_LOOPBACK)
+		continue;
+	    if (addr_eq (ifp->ifa_addr, ifp2->ifa_addr)) {
+		match = 1;
+		ifp->ifa_flags &= ~IFF_UP;
+		break;
+	    }
+	}
+	if (match)
+	    continue;
+	if ((*pass1fn) (data, ifp->ifa_addr))
+	    goto punt;
+    }
+    if (betweenfn && (*betweenfn)(data))
+	goto punt;
+    if (pass2fn)
+	for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
+	    if (ifp->ifa_flags & IFF_UP)
+		if ((*pass2fn) (data, ifp->ifa_addr))
+		    goto punt;
+	}
+ punt:
+    freeifaddrs (ifp_head);
+    return 0;
+}
+
+#elif defined (SIOCGLIFNUM) && defined(HAVE_STRUCT_LIFCONF) /* Solaris 8 and later; Sol 7? */
+
+int
+foreach_localaddr (/*@null@*/ void *data,
+		   int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
+		   /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
+		   /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
+					      struct sockaddr *) /*@*/)
+#if defined(DEBUG) || defined(TEST)
+     /*@modifies fileSystem@*/
+#endif
+{
+    /* Okay, this is kind of odd.  We have to use each of the address
+       families we care about, because with an AF_INET socket, extra
+       interfaces like hme0:1 that have only AF_INET6 addresses will
+       cause errors.  Similarly, if hme0 has more AF_INET addresses
+       than AF_INET6 addresses, we won't be able to retrieve all of
+       the AF_INET addresses if we use an AF_INET6 socket.  Since
+       neither family is guaranteed to have the greater number of
+       addresses, we should use both.
+
+       If it weren't for this little quirk, we could use one socket of
+       any type, and ask for addresses of all types.  At least, it
+       seems to work that way.  */
+
+    static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
+#define N_AFS (sizeof (afs) / sizeof (afs[0]))
+    struct {
+	int af;
+	int sock;
+	void *buf;
+	size_t buf_size;
+	struct lifnum lifnum;
+    } afp[N_AFS];
+    int code, i, j;
+    int retval = 0, afidx;
+    krb5_error_code sock_err = 0;
+    struct lifreq *lifr, lifreq, *lifr2;
+
+#define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
+#define P (afp[afidx])
+
+    /* init */
+    FOREACH_AF () {
+	P.af = afs[afidx];
+	P.sock = -1;
+	P.buf = 0;
+    }
+
+    /* first pass: get raw data, discard uninteresting addresses, callback */
+    FOREACH_AF () {
+	Tprintf (("trying af %d...\n", P.af));
+	P.sock = socket (P.af, USE_TYPE, USE_PROTO);
+	if (P.sock < 0) {
+	    sock_err = SOCKET_ERROR;
+	    Tperror ("socket");
+	    continue;
+	}
+
+	P.lifnum.lifn_family = P.af;
+	P.lifnum.lifn_flags = 0;
+	P.lifnum.lifn_count = 0;
+	code = ioctl (P.sock, SIOCGLIFNUM, &P.lifnum);
+	if (code) {
+	    Tperror ("ioctl(SIOCGLIFNUM)");
+	    retval = errno;
+	    goto punt;
+	}
+
+	P.buf_size = P.lifnum.lifn_count * sizeof (struct lifreq) * 2;
+	P.buf = malloc (P.buf_size);
+	if (P.buf == NULL) {
+	    retval = errno;
+	    goto punt;
+	}
+
+	code = get_lifconf (P.af, P.sock, &P.buf_size, P.buf);
+	if (code < 0) {
+	    retval = errno;
+	    goto punt;
+	}
+
+	for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
+	    lifr = (struct lifreq *)((caddr_t) P.buf+i);
+
+	    strncpy(lifreq.lifr_name, lifr->lifr_name,
+		    sizeof (lifreq.lifr_name));
+	    Tprintf (("interface %s\n", lifreq.lifr_name));
+	    /*@-moduncon@*/ /* ioctl unknown to lclint */
+	    if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
+		Tperror ("ioctl(SIOCGLIFFLAGS)");
+	    skip:
+		/* mark for next pass */
+		lifr->lifr_name[0] = '\0';
+		continue;
+	    }
+	    /*@=moduncon@*/
+
+#ifdef IFF_LOOPBACK
+	    /* None of the current callers want loopback addresses.  */
+	    if (lifreq.lifr_flags & IFF_LOOPBACK) {
+		Tprintf (("  loopback\n"));
+		goto skip;
+	    }
+#endif
+	    /* Ignore interfaces that are down.  */
+	    if ((lifreq.lifr_flags & IFF_UP) == 0) {
+		Tprintf (("  down\n"));
+		goto skip;
+	    }
+
+	    /* Make sure we didn't process this address already.  */
+	    for (j = 0; j < i; j += sizeof (*lifr2)) {
+		lifr2 = (struct lifreq *)((caddr_t) P.buf+j);
+		if (lifr2->lifr_name[0] == '\0')
+		    continue;
+		if (lifr2->lifr_addr.ss_family == lifr->lifr_addr.ss_family
+		    /* Compare address info.  If this isn't good enough --
+		       i.e., if random padding bytes turn out to differ
+		       when the addresses are the same -- then we'll have
+		       to do it on a per address family basis.  */
+		    && !memcmp (&lifr2->lifr_addr, &lifr->lifr_addr,
+				sizeof (*lifr))) {
+		    Tprintf (("  duplicate addr\n"));
+		    goto skip;
+		}
+	    }
+
+	    /*@-moduncon@*/
+	    if ((*pass1fn) (data, ss2sa (&lifr->lifr_addr)))
+		goto punt;
+	    /*@=moduncon@*/
+	}
+    }
+
+    /* Did we actually get any working sockets?  */
+    FOREACH_AF ()
+	if (P.sock != -1)
+	    goto have_working_socket;
+    retval = sock_err;
+    goto punt;
+have_working_socket:
+
+    /*@-moduncon@*/
+    if (betweenfn != NULL && (*betweenfn)(data))
+	goto punt;
+    /*@=moduncon@*/
+
+    if (pass2fn)
+	FOREACH_AF ()
+	    if (P.sock >= 0) {
+		for (i = 0; i + sizeof (*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
+		    lifr = (struct lifreq *)((caddr_t) P.buf+i);
+
+		    if (lifr->lifr_name[0] == '\0')
+			/* Marked in first pass to be ignored.  */
+			continue;
+
+		    /*@-moduncon@*/
+		    if ((*pass2fn) (data, ss2sa (&lifr->lifr_addr)))
+			goto punt;
+		    /*@=moduncon@*/
+		}
+	    }
+punt:
+    FOREACH_AF () {
+	/*@-moduncon@*/
+	closesocket(P.sock);
+	/*@=moduncon@*/
+	free (P.buf);
+    }
+
+    return retval;
+}
+
+#elif defined (SIOCGLIFNUM) && defined(HAVE_STRUCT_IF_LADDRCONF) && 0 /* HP-UX 11 support being debugged */
+
+int
+foreach_localaddr (/*@null@*/ void *data,
+		   int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
+		   /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
+		   /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
+					      struct sockaddr *) /*@*/)
+#if defined(DEBUG) || defined(TEST)
+     /*@modifies fileSystem@*/
+#endif
+{
+    /* Okay, this is kind of odd.  We have to use each of the address
+       families we care about, because with an AF_INET socket, extra
+       interfaces like hme0:1 that have only AF_INET6 addresses will
+       cause errors.  Similarly, if hme0 has more AF_INET addresses
+       than AF_INET6 addresses, we won't be able to retrieve all of
+       the AF_INET addresses if we use an AF_INET6 socket.  Since
+       neither family is guaranteed to have the greater number of
+       addresses, we should use both.
+
+       If it weren't for this little quirk, we could use one socket of
+       any type, and ask for addresses of all types.  At least, it
+       seems to work that way.  */
+
+    static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
+#define N_AFS (sizeof (afs) / sizeof (afs[0]))
+    struct {
+	int af;
+	int sock;
+	void *buf;
+	size_t buf_size;
+	int if_num;
+    } afp[N_AFS];
+    int code, i, j;
+    int retval = 0, afidx;
+    krb5_error_code sock_err = 0;
+    struct if_laddrreq *lifr, lifreq, *lifr2;
+
+#define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
+#define P (afp[afidx])
+
+    /* init */
+    FOREACH_AF () {
+	P.af = afs[afidx];
+	P.sock = -1;
+	P.buf = 0;
+    }
+
+    /* first pass: get raw data, discard uninteresting addresses, callback */
+    FOREACH_AF () {
+	Tprintf (("trying af %d...\n", P.af));
+	P.sock = socket (P.af, USE_TYPE, USE_PROTO);
+	if (P.sock < 0) {
+	    sock_err = SOCKET_ERROR;
+	    Tperror ("socket");
+	    continue;
+	}
+
+	code = ioctl (P.sock, SIOCGLIFNUM, &P.if_num);
+	if (code) {
+	    Tperror ("ioctl(SIOCGLIFNUM)");
+	    retval = errno;
+	    goto punt;
+	}
+
+	P.buf_size = P.if_num * sizeof (struct if_laddrreq) * 2;
+	P.buf = malloc (P.buf_size);
+	if (P.buf == NULL) {
+	    retval = errno;
+	    goto punt;
+	}
+
+	code = get_if_laddrconf (P.af, P.sock, &P.buf_size, P.buf);
+	if (code < 0) {
+	    retval = errno;
+	    goto punt;
+	}
+
+	for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
+	    lifr = (struct if_laddrreq *)((caddr_t) P.buf+i);
+
+	    strncpy(lifreq.iflr_name, lifr->iflr_name,
+		    sizeof (lifreq.iflr_name));
+	    Tprintf (("interface %s\n", lifreq.iflr_name));
+	    /*@-moduncon@*/ /* ioctl unknown to lclint */
+	    if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
+		Tperror ("ioctl(SIOCGLIFFLAGS)");
+	    skip:
+		/* mark for next pass */
+		lifr->iflr_name[0] = '\0';
+		continue;
+	    }
+	    /*@=moduncon@*/
+
+#ifdef IFF_LOOPBACK
+	    /* None of the current callers want loopback addresses.  */
+	    if (lifreq.iflr_flags & IFF_LOOPBACK) {
+		Tprintf (("  loopback\n"));
+		goto skip;
+	    }
+#endif
+	    /* Ignore interfaces that are down.  */
+	    if ((lifreq.iflr_flags & IFF_UP) == 0) {
+		Tprintf (("  down\n"));
+		goto skip;
+	    }
+
+	    /* Make sure we didn't process this address already.  */
+	    for (j = 0; j < i; j += sizeof (*lifr2)) {
+		lifr2 = (struct if_laddrreq *)((caddr_t) P.buf+j);
+		if (lifr2->iflr_name[0] == '\0')
+		    continue;
+		if (lifr2->iflr_addr.sa_family == lifr->iflr_addr.sa_family
+		    /* Compare address info.  If this isn't good enough --
+		       i.e., if random padding bytes turn out to differ
+		       when the addresses are the same -- then we'll have
+		       to do it on a per address family basis.  */
+		    && !memcmp (&lifr2->iflr_addr, &lifr->iflr_addr,
+				sizeof (*lifr))) {
+		    Tprintf (("  duplicate addr\n"));
+		    goto skip;
+		}
+	    }
+
+	    /*@-moduncon@*/
+	    if ((*pass1fn) (data, ss2sa (&lifr->iflr_addr)))
+		goto punt;
+	    /*@=moduncon@*/
+	}
+    }
+
+    /* Did we actually get any working sockets?  */
+    FOREACH_AF ()
+	if (P.sock != -1)
+	    goto have_working_socket;
+    retval = sock_err;
+    goto punt;
+have_working_socket:
+
+    /*@-moduncon@*/
+    if (betweenfn != NULL && (*betweenfn)(data))
+	goto punt;
+    /*@=moduncon@*/
+
+    if (pass2fn)
+	FOREACH_AF ()
+	    if (P.sock >= 0) {
+		for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
+		    lifr = (struct if_laddrreq *)((caddr_t) P.buf+i);
+
+		    if (lifr->iflr_name[0] == '\0')
+			/* Marked in first pass to be ignored.  */
+			continue;
+
+		    /*@-moduncon@*/
+		    if ((*pass2fn) (data, ss2sa (&lifr->iflr_addr)))
+			goto punt;
+		    /*@=moduncon@*/
+		}
+	    }
+punt:
+    FOREACH_AF () {
+	/*@-moduncon@*/
+	closesocket(P.sock);
+	/*@=moduncon@*/
+	free (P.buf);
+    }
+
+    return retval;
+}
+
+#else /* not defined (SIOCGLIFNUM) */
+
+#define SLOP (sizeof (struct ifreq) + 128)
+
+static int
+get_ifreq_array(char **bufp, size_t *np, int s)
+{
+    int code;
+    int est_if_count = 8;
+    size_t est_ifreq_size;
+    char *buf = 0;
+    size_t current_buf_size = 0, size, n;
+#ifdef SIOCGSIZIFCONF
+    int ifconfsize = -1;
+#endif
+#ifdef SIOCGIFNUM
+    int numifs = -1;
+#endif
+
+    /* At least on NetBSD, an ifreq can hold an IPv4 address, but
+       isn't big enough for an IPv6 or ethernet address.  So add a
+       little more space.  */
+    est_ifreq_size = sizeof (struct ifreq) + 8;
+#ifdef SIOCGSIZIFCONF
+    code = ioctl (s, SIOCGSIZIFCONF, &ifconfsize);
+    if (!code) {
+	current_buf_size = ifconfsize;
+	est_if_count = ifconfsize / est_ifreq_size;
+    }
+#elif defined (SIOCGIFNUM)
+    code = ioctl (s, SIOCGIFNUM, &numifs);
+    if (!code && numifs > 0)
+	est_if_count = numifs;
+#endif
+    if (current_buf_size == 0)
+	current_buf_size = est_ifreq_size * est_if_count + SLOP;
+    buf = malloc (current_buf_size);
+    if (buf == NULL)
+	return errno;
+
+ask_again:
+    size = current_buf_size;
+    code = get_ifconf (s, &size, buf);
+    if (code < 0) {
+	code = errno;
+	free (buf);
+	return code;
+    }
+    /* Test that the buffer was big enough that another ifreq could've
+       fit easily, if the OS wanted to provide one.  That seems to be
+       the only indication we get, complicated by the fact that the
+       associated address may make the required storage a little
+       bigger than the size of an ifreq.  */
+    if (current_buf_size - size < SLOP
+#ifdef SIOCGSIZIFCONF
+	/* Unless we hear SIOCGSIZIFCONF is broken somewhere, let's
+	   trust the value it returns.  */
+	&& ifconfsize <= 0
+#elif defined (SIOCGIFNUM)
+	&& numifs <= 0
+#endif
+	/* And we need *some* sort of bounds.  */
+	&& current_buf_size <= 100000
+	) {
+	size_t new_size;
+
+	est_if_count *= 2;
+	new_size = est_ifreq_size * est_if_count + SLOP;
+	buf = grow_or_free (buf, new_size);
+	if (buf == 0)
+	    return errno;
+	current_buf_size = new_size;
+	goto ask_again;
+    }
+
+    n = size;
+    if (n > current_buf_size)
+	n = current_buf_size;
+
+    *bufp = buf;
+    *np = n;
+    return 0;
+}
+
+int
+foreach_localaddr (/*@null@*/ void *data,
+		   int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
+		   /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
+		   /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
+					      struct sockaddr *) /*@*/)
+#if defined(DEBUG) || defined(TEST)
+     /*@modifies fileSystem@*/
+#endif
+{
+    struct ifreq *ifr, ifreq, *ifr2;
+    int s, code;
+    char *buf = 0;
+    size_t size, n, i, j;
+    int retval = 0;
+#ifdef LINUX_IPV6_HACK
+    struct linux_ipv6_addr_list *linux_ipv6_addrs = get_linux_ipv6_addrs ();
+    struct linux_ipv6_addr_list *lx_v6;
+#endif
+
+    s = socket (USE_AF, USE_TYPE, USE_PROTO);
+    if (s < 0)
+	return SOCKET_ERRNO;
+
+    retval = get_ifreq_array(&buf, &n, s);
+    if (retval) {
+	/*@-moduncon@*/ /* close() unknown to lclint */
+	closesocket(s);
+	/*@=moduncon@*/
+	return retval;
+    }
+
+    /* Note: Apparently some systems put the size (used or wanted?)
+       into the start of the buffer, just none that I'm actually
+       using.  Fix this when there's such a test system available.
+       The Samba mailing list archives mention that NTP looks for the
+       size on these systems: *-fujitsu-uxp* *-ncr-sysv4*
+       *-univel-sysv*.  */
+    for (i = 0; i + sizeof(struct ifreq) <= n; i+= ifreq_size(*ifr) ) {
+	ifr = (struct ifreq *)((caddr_t) buf+i);
+	/* In case ifreq_size is more than sizeof().  */
+	if (i + ifreq_size(*ifr) > n)
+	  break;
+
+	strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
+	Tprintf (("interface %s\n", ifreq.ifr_name));
+	/*@-moduncon@*/ /* ioctl unknown to lclint */
+	if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+	skip:
+	    /* mark for next pass */
+	    ifr->ifr_name[0] = '\0';
+	    continue;
+	}
+	/*@=moduncon@*/
+
+#ifdef IFF_LOOPBACK
+	/* None of the current callers want loopback addresses.  */
+	if (ifreq.ifr_flags & IFF_LOOPBACK) {
+	    Tprintf (("  loopback\n"));
+	    goto skip;
+	}
+#endif
+	/* Ignore interfaces that are down.  */
+	if ((ifreq.ifr_flags & IFF_UP) == 0) {
+	    Tprintf (("  down\n"));
+	    goto skip;
+	}
+
+	/* Make sure we didn't process this address already.  */
+	for (j = 0; j < i; j += ifreq_size(*ifr2)) {
+	    ifr2 = (struct ifreq *)((caddr_t) buf+j);
+	    if (ifr2->ifr_name[0] == '\0')
+		continue;
+	    if (ifr2->ifr_addr.sa_family == ifr->ifr_addr.sa_family
+		&& ifreq_size (*ifr) == ifreq_size (*ifr2)
+		/* Compare address info.  If this isn't good enough --
+		   i.e., if random padding bytes turn out to differ
+		   when the addresses are the same -- then we'll have
+		   to do it on a per address family basis.  */
+		&& !memcmp (&ifr2->ifr_addr.sa_data, &ifr->ifr_addr.sa_data,
+			    (ifreq_size (*ifr)
+			     - offsetof (struct ifreq, ifr_addr.sa_data)))) {
+		Tprintf (("  duplicate addr\n"));
+		goto skip;
+	    }
+	}
+
+	/*@-moduncon@*/
+	if ((*pass1fn) (data, &ifr->ifr_addr))
+	    goto punt;
+	/*@=moduncon@*/
+    }
+
+#ifdef LINUX_IPV6_HACK
+    for (lx_v6 = linux_ipv6_addrs; lx_v6; lx_v6 = lx_v6->next)
+	if ((*pass1fn) (data, (struct sockaddr *) &lx_v6->addr))
+	    goto punt;
+#endif
+
+    /*@-moduncon@*/
+    if (betweenfn != NULL && (*betweenfn)(data))
+	goto punt;
+    /*@=moduncon@*/
+
+    if (pass2fn) {
+	for (i = 0; i + sizeof(struct ifreq) <= n; i+= ifreq_size(*ifr) ) {
+	    ifr = (struct ifreq *)((caddr_t) buf+i);
+
+	    if (ifr->ifr_name[0] == '\0')
+		/* Marked in first pass to be ignored.  */
+		continue;
+
+	    /*@-moduncon@*/
+	    if ((*pass2fn) (data, &ifr->ifr_addr))
+		goto punt;
+	    /*@=moduncon@*/
+	}
+#ifdef LINUX_IPV6_HACK
+	for (lx_v6 = linux_ipv6_addrs; lx_v6; lx_v6 = lx_v6->next)
+	    if ((*pass2fn) (data, (struct sockaddr *) &lx_v6->addr))
+		goto punt;
+#endif
+    }
+ punt:
+    /*@-moduncon@*/
+    closesocket(s);
+    /*@=moduncon@*/
+    free (buf);
+#ifdef LINUX_IPV6_HACK
+    while (linux_ipv6_addrs) {
+	lx_v6 = linux_ipv6_addrs->next;
+	free (linux_ipv6_addrs);
+	linux_ipv6_addrs = lx_v6;
+    }
+#endif
+
+    return retval;
+}
+
+#endif /* not HAVE_IFADDRS_H and not SIOCGLIFNUM */
+
+static krb5_error_code
+get_localaddrs (krb5_context context, krb5_address ***addr, int use_profile);
+
+#ifdef TEST
+
+static int print_addr (/*@unused@*/ void *dataptr, struct sockaddr *sa)
+     /*@modifies fileSystem@*/
+{
+    char hostbuf[NI_MAXHOST];
+    int err;
+    socklen_t len;
+
+    printf ("  --> family %2d ", sa->sa_family);
+    len = socklen (sa);
+    err = getnameinfo (sa, len, hostbuf, (socklen_t) sizeof (hostbuf),
+		       (char *) NULL, 0, NI_NUMERICHOST);
+    if (err) {
+	int e = errno;
+	printf ("<getnameinfo error %d: %s>\n", err, gai_strerror (err));
+	if (err == EAI_SYSTEM)
+	    printf ("\t\t<errno is %d: %s>\n", e, strerror(e));
+    } else
+	printf ("addr %s\n", hostbuf);
+    return 0;
+}
+
+int main ()
+{
+    int r;
+
+    (void) setvbuf (stdout, (char *)NULL, _IONBF, 0);
+    r = foreach_localaddr (0, print_addr, NULL, NULL);
+    printf ("return value = %d\n", r);
+    return 0;
+}
+
+#else /* not TESTing */
+
+struct localaddr_data {
+    int count, mem_err, cur_idx, cur_size;
+    krb5_address **addr_temp;
+};
+
+static int
+count_addrs (void *P_data, struct sockaddr *a)
+     /*@*/
+{
+    struct localaddr_data *data = P_data;
+    switch (a->sa_family) {
+    case AF_INET:
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+#endif
+#ifdef KRB5_USE_NS
+    case AF_XNS:
+#endif
+	data->count++;
+	break;
+    default:
+	break;
+    }
+    return 0;
+}
+
+static int
+allocate (void *P_data)
+     /*@*/
+{
+    struct localaddr_data *data = P_data;
+    int i;
+    void *n;
+
+    n = realloc (data->addr_temp,
+		 (1 + data->count + data->cur_idx) * sizeof (krb5_address *));
+    if (n == 0) {
+	data->mem_err++;
+	return 1;
+    }
+    data->addr_temp = n;
+    data->cur_size = 1 + data->count + data->cur_idx;
+    for (i = data->cur_idx; i <= data->count + data->cur_idx; i++)
+	data->addr_temp[i] = 0;
+    return 0;
+}
+
+static /*@null@*/ krb5_address *
+make_addr (int type, size_t length, const void *contents)
+    /*@*/
+{
+    krb5_address *a;
+    void *data;
+
+    data = malloc (length);
+    if (data == NULL)
+	return NULL;
+    a = malloc (sizeof (krb5_address));
+    if (a == NULL) {
+	free (data);
+	return NULL;
+    }
+    memcpy (data, contents, length);
+    a->magic = KV5M_ADDRESS;
+    a->addrtype = type;
+    a->length = length;
+    a->contents = data;
+    return a;
+}
+
+static int
+add_addr (void *P_data, struct sockaddr *a)
+     /*@modifies *P_data@*/
+{
+    struct localaddr_data *data = P_data;
+    /*@null@*/ krb5_address *address = 0;
+
+    switch (a->sa_family) {
+#ifdef HAVE_NETINET_IN_H
+    case AF_INET:
+	address = make_addr (ADDRTYPE_INET, sizeof (struct in_addr),
+			     &((const struct sockaddr_in *) a)->sin_addr);
+	if (address == NULL)
+	    data->mem_err++;
+	break;
+
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+    {
+	const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) a;
+	
+	if (IN6_IS_ADDR_LINKLOCAL (&in->sin6_addr))
+	    break;
+
+	address = make_addr (ADDRTYPE_INET6, sizeof (struct in6_addr),
+			     &in->sin6_addr);
+	if (address == NULL)
+	    data->mem_err++;
+	break;
+    }
+#endif /* KRB5_USE_INET6 */
+#endif /* netinet/in.h */
+
+#ifdef KRB5_USE_NS
+    case AF_XNS:
+	address = make_addr (ADDRTYPE_XNS, sizeof (struct ns_addr),
+			     &((const struct sockaddr_ns *)a)->sns_addr);
+	if (address == NULL)
+	    data->mem_err++;
+	break;
+#endif
+
+#ifdef AF_LINK
+	/* Some BSD-based systems (e.g. NetBSD 1.5) and AIX will
+	   include the ethernet address, but we don't want that, at
+	   least for now.  */
+    case AF_LINK:
+	break;
+#endif
+    /*
+     * Add more address families here..
+     */
+    default:
+	break;
+    }
+#ifdef __LCLINT__
+    /* Redundant but unconditional store un-confuses lclint.  */
+    data->addr_temp[data->cur_idx] = address;
+#endif
+    if (address) {
+	data->addr_temp[data->cur_idx++] = address;
+    }
+
+    return data->mem_err;
+}
+
+static krb5_error_code
+krb5_os_localaddr_profile (krb5_context context, struct localaddr_data *datap)
+{
+    krb5_error_code err;
+    static const char *const profile_name[] = {
+	"libdefaults", "extra_addresses", 0
+    };
+    char **values;
+    char **iter;
+    krb5_address **newaddrs;
+
+#ifdef DEBUG
+    fprintf (stderr, "looking up extra_addresses foo\n");
+#endif
+
+    err = profile_get_values (context->profile, profile_name, &values);
+    /* Ignore all errors for now?  */
+    if (err)
+	return 0;
+
+    for (iter = values; *iter; iter++) {
+	char *cp = *iter, *next, *current;
+	int i, count;
+
+#ifdef DEBUG
+	fprintf (stderr, "  found line: '%s'\n", cp);
+#endif
+
+	for (cp = *iter, next = 0; *cp; cp = next) {
+	    while (isspace ((int) *cp) || *cp == ',')
+		cp++;
+	    if (*cp == 0)
+		break;
+	    /* Start of an address.  */
+#ifdef DEBUG
+	    fprintf (stderr, "    addr found in '%s'\n", cp);
+#endif
+	    current = cp;
+	    while (*cp != 0 && !isspace((int) *cp) && *cp != ',')
+		cp++;
+	    if (*cp != 0) {
+		next = cp + 1;
+		*cp = 0;
+	    } else
+		next = cp;
+	    /* Got a single address, process it.  */
+#ifdef DEBUG
+	    fprintf (stderr, "    processing '%s'\n", current);
+#endif
+	    newaddrs = 0;
+	    err = krb5_os_hostaddr (context, current, &newaddrs);
+	    if (err)
+		continue;
+	    for (i = 0; newaddrs[i]; i++) {
+#ifdef DEBUG
+		fprintf (stderr, "    %d: family %d", i,
+			 newaddrs[i]->addrtype);
+		fprintf (stderr, "\n");
+#endif
+	    }
+	    count = i;
+#ifdef DEBUG
+	    fprintf (stderr, "    %d addresses\n", count);
+#endif
+	    if (datap->cur_idx + count >= datap->cur_size) {
+		krb5_address **bigger;
+		bigger = realloc (datap->addr_temp,
+				  sizeof (krb5_address *) * (datap->cur_idx + count));
+		if (bigger) {
+		    datap->addr_temp = bigger;
+		    datap->cur_size = datap->cur_idx + count;
+		}
+	    }
+	    for (i = 0; i < count; i++) {
+		if (datap->cur_idx < datap->cur_size)
+		    datap->addr_temp[datap->cur_idx++] = newaddrs[i];
+		else
+		    free (newaddrs[i]->contents), free (newaddrs[i]);
+	    }
+	    free (newaddrs);
+	}
+    }
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_os_localaddr(krb5_context context, krb5_address ***addr)
+{
+    return get_localaddrs(context, addr, 1);
+}
+
+krb5_error_code
+krb5int_local_addresses(krb5_context context, krb5_address ***addr)
+{
+    return get_localaddrs(context, addr, 0);
+}
+
+static krb5_error_code
+get_localaddrs (krb5_context context, krb5_address ***addr, int use_profile)
+{
+    struct localaddr_data data = { 0 };
+    int r;
+    krb5_error_code err;
+
+    if (use_profile) {
+	err = krb5_os_localaddr_profile (context, &data);
+	/* ignore err for now */
+    }
+
+    r = foreach_localaddr (&data, count_addrs, allocate, add_addr);
+    if (r != 0) {
+	int i;
+	if (data.addr_temp) {
+	    for (i = 0; i < data.count; i++)
+		krb5_xfree (data.addr_temp[i]);
+	    free (data.addr_temp);
+	}
+	if (data.mem_err)
+	    return ENOMEM;
+	else
+	    return r;
+    }
+
+    data.cur_idx++; /* null termination */
+    if (data.mem_err)
+	return ENOMEM;
+    else if (data.cur_idx == data.count)
+	*addr = data.addr_temp;
+    else {
+	/* This can easily happen if we have IPv6 link-local
+	   addresses.  Just shorten the array.  */
+	*addr = (krb5_address **) realloc (data.addr_temp,
+					   (sizeof (krb5_address *)
+					    * data.cur_idx));
+	if (*addr == 0)
+	    /* Okay, shortening failed, but the original should still
+	       be intact.  */
+	    *addr = data.addr_temp;
+    }
+
+#ifdef DEBUG
+    {
+	int j;
+	fprintf (stderr, "addresses:\n");
+	for (j = 0; addr[0][j]; j++) {
+	    struct sockaddr_storage ss;
+	    int err2;
+	    char namebuf[NI_MAXHOST];
+	    void *addrp = 0;
+
+	    fprintf (stderr, "%2d: ", j);
+	    fprintf (stderr, "addrtype %2d, length %2d", addr[0][j]->addrtype,
+		     addr[0][j]->length);
+	    memset (&ss, 0, sizeof (ss));
+	    switch (addr[0][j]->addrtype) {
+	    case ADDRTYPE_INET:
+	    {
+		struct sockaddr_in *sinp = ss2sin (&ss);
+		sinp->sin_family = AF_INET;
+		addrp = &sinp->sin_addr;
+#ifdef HAVE_SA_LEN
+		sinp->sin_len = sizeof (struct sockaddr_in);
+#endif
+		break;
+	    }
+#ifdef KRB5_USE_INET6
+	    case ADDRTYPE_INET6:
+	    {
+		struct sockaddr_in6 *sin6p = ss2sin6 (&ss);
+		sin6p->sin6_family = AF_INET6;
+		addrp = &sin6p->sin6_addr;
+#ifdef HAVE_SA_LEN
+		sin6p->sin6_len = sizeof (struct sockaddr_in6);
+#endif
+		break;
+	    }
+#endif
+	    default:
+		ss2sa(&ss)->sa_family = 0;
+		break;
+	    }
+	    if (addrp)
+		memcpy (addrp, addr[0][j]->contents, addr[0][j]->length);
+	    err2 = getnameinfo (ss2sa(&ss), socklen (ss2sa (&ss)),
+				namebuf, sizeof (namebuf), 0, 0,
+				NI_NUMERICHOST);
+	    if (err2 == 0)
+		fprintf (stderr, ": addr %s\n", namebuf);
+	    else
+		fprintf (stderr, ": getnameinfo error %d\n", err2);
+	}
+    }
+#endif
+
+    return 0;
+}
+
+#endif /* not TESTing */
+
+#else /* Windows/Mac version */
+
+/*
+ * Hold on to your lunch!  Backup kludge method of obtaining your
+ * local IP address, courtesy of Windows Socket Network Programming,
+ * by Robert Quinn
+ */
+#if defined(_WIN32)
+static struct hostent *local_addr_fallback_kludge()
+{
+	static struct hostent	host;
+	static SOCKADDR_IN	addr;
+	static char *		ip_ptrs[2];
+	SOCKET			sock;
+	int			size = sizeof(SOCKADDR);
+	int			err;
+
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock == INVALID_SOCKET)
+		return NULL;
+
+	/* connect to arbitrary port and address (NOT loopback) */
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(IPPORT_ECHO);
+	addr.sin_addr.s_addr = inet_addr("204.137.220.51");
+
+	err = connect(sock, (LPSOCKADDR) &addr, sizeof(SOCKADDR));
+	if (err == SOCKET_ERROR)
+		return NULL;
+
+	err = getsockname(sock, (LPSOCKADDR) &addr, (int *) size);
+	if (err == SOCKET_ERROR)
+		return NULL;
+
+	closesocket(sock);
+
+	host.h_name = 0;
+	host.h_aliases = 0;
+	host.h_addrtype = AF_INET;
+	host.h_length = 4;
+	host.h_addr_list = ip_ptrs;
+	ip_ptrs[0] = (char *) &addr.sin_addr.s_addr;
+	ip_ptrs[1] = NULL;
+
+	return &host;
+}
+#endif
+
+/* No ioctls in winsock so we just assume there is only one networking 
+ * card per machine, so gethostent is good enough. 
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_os_localaddr (krb5_context context, krb5_address ***addr) {
+    char host[64];                              /* Name of local machine */
+    struct hostent *hostrec;
+    int err, count, i;
+    krb5_address ** paddr;
+
+    *addr = 0;
+    paddr = 0;
+    err = 0;
+    
+    if (gethostname (host, sizeof(host))) {
+        err = SOCKET_ERRNO;
+    }
+
+    if (!err) {
+	    hostrec = gethostbyname (host);
+	    if (hostrec == NULL) {
+		    err = SOCKET_ERRNO;
+	    }
+    }
+
+    if (err) {
+	    hostrec = local_addr_fallback_kludge();
+	    if (!hostrec)
+		    return err;
+		else
+			err = 0;  /* otherwise we will die at cleanup */
+    }
+
+    for (count = 0; hostrec->h_addr_list[count]; count++);
+
+
+    paddr = (krb5_address **)malloc(sizeof(krb5_address *) * (count+1));
+    if (!paddr) {
+        err = ENOMEM;
+        goto cleanup;
+    }
+
+    memset(paddr, 0, sizeof(krb5_address *) * (count+1));
+
+    for (i = 0; i < count; i++)
+    {
+        paddr[i] = (krb5_address *)malloc(sizeof(krb5_address));
+        if (paddr[i] == NULL) {
+            err = ENOMEM;
+            goto cleanup;
+        }
+
+        paddr[i]->magic = KV5M_ADDRESS;
+        paddr[i]->addrtype = hostrec->h_addrtype;
+        paddr[i]->length = hostrec->h_length;
+        paddr[i]->contents = (unsigned char *)malloc(paddr[i]->length);
+        if (!paddr[i]->contents) {
+            err = ENOMEM;
+            goto cleanup;
+        }
+        memcpy(paddr[i]->contents,
+               hostrec->h_addr_list[i],
+               paddr[i]->length);
+    }
+
+ cleanup:
+    if (err) {
+        if (paddr) {
+            for (i = 0; i < count; i++)
+            {
+                if (paddr[i]) {
+                    if (paddr[i]->contents)
+                        free(paddr[i]->contents);
+                    free(paddr[i]);
+                }
+            }
+            free(paddr);
+        }
+    }
+    else
+        *addr = paddr;
+
+    return(err);
+}
+#endif
diff --git a/mechglue/src/lib/krb5/os/locate_kdc.c b/mechglue/src/lib/krb5/os/locate_kdc.c
new file mode 100644
index 000000000..484c8e8e9
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/locate_kdc.c
@@ -0,0 +1,653 @@
+/*
+ * lib/krb5/os/locate_kdc.c
+ *
+ * Copyright 1990,2000,2001,2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * get socket addresses for KDC.
+ */
+
+#include "fake-addrinfo.h"
+#include "k5-int.h"
+#include "os-proto.h"
+#include <stdio.h>
+#ifdef KRB5_DNS_LOOKUP
+#ifdef WSHELPER
+#include <wshelper.h>
+#else /* WSHELPER */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+#endif /* WSHELPER */
+#ifndef T_SRV
+#define T_SRV 33
+#endif /* T_SRV */
+
+/* for old Unixes and friends ... */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
+
+#if KRB5_DNS_LOOKUP_KDC
+#define DEFAULT_LOOKUP_KDC 1
+#else
+#define DEFAULT_LOOKUP_KDC 0
+#endif
+#if KRB5_DNS_LOOKUP_REALM
+#define DEFAULT_LOOKUP_REALM 1
+#else
+#define DEFAULT_LOOKUP_REALM 0
+#endif
+
+static int
+maybe_use_dns (krb5_context context, const char *name, int defalt)
+{
+    krb5_error_code code;
+    char * value = NULL;
+    int use_dns = 0;
+
+    code = profile_get_string(context->profile, "libdefaults",
+                              name, 0, 0, &value);
+    if (value == 0 && code == 0)
+	code = profile_get_string(context->profile, "libdefaults",
+				  "dns_fallback", 0, 0, &value);
+    if (code)
+        return defalt;
+
+    if (value == 0)
+	return defalt;
+
+    use_dns = _krb5_conf_boolean(value);
+    profile_release_string(value);
+    return use_dns;
+}
+
+int
+_krb5_use_dns_kdc(krb5_context context)
+{
+    return maybe_use_dns (context, "dns_lookup_kdc", DEFAULT_LOOKUP_KDC);
+}
+
+int
+_krb5_use_dns_realm(krb5_context context)
+{
+    return maybe_use_dns (context, "dns_lookup_realm", DEFAULT_LOOKUP_REALM);
+}
+
+#endif /* KRB5_DNS_LOOKUP */
+
+static int get_port (const char *service, int stream, int defalt)
+{
+#if 0 /* Only used for "kerberos" and "kerberos-sec", and we want the
+	 right port numbers even on the OSes that botch the entries in
+	 /etc/services.  So don't bother with the lookup, except maybe
+	 to produce a warning.  */
+    struct addrinfo hints = { 0 };
+    struct addrinfo *ai;
+    int err;
+
+    hints.ai_family = PF_INET;
+    hints.ai_socktype = stream ? SOCK_STREAM : SOCK_DGRAM;
+    err = getaddrinfo (NULL, service, &hints, &ai);
+    if (err == 0 && ai != 0) {
+	if (ai->ai_addr->sa_family == AF_INET) {
+	    int port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
+	    freeaddrinfo (ai);
+	    return port;
+	}
+	freeaddrinfo (ai);
+    }
+#endif
+    /* Any error - don't complain, just use default.  */
+    return htons (defalt);
+}
+
+int
+krb5int_grow_addrlist (struct addrlist *lp, int nmore)
+{
+    int i;
+    int newspace = lp->space + nmore;
+    size_t newsize = newspace * sizeof (struct addrlist);
+    struct addrinfo **newaddrs;
+
+    /* NULL check a concession to SunOS4 compatibility for now; not
+       required for pure ANSI support.  */
+    if (lp->addrs)
+	newaddrs = realloc (lp->addrs, newsize);
+    else
+	newaddrs = malloc (newsize);
+
+    if (newaddrs == NULL)
+	return errno;
+    for (i = lp->space; i < newspace; i++)
+	newaddrs[i] = NULL;
+    lp->addrs = newaddrs;
+    lp->space = newspace;
+    return 0;
+}
+#define grow_list krb5int_grow_addrlist
+
+/* Free up everything pointed to by the addrlist structure, but don't
+   free the structure itself.  */
+void
+krb5int_free_addrlist (struct addrlist *lp)
+{
+    int i;
+    for (i = 0; i < lp->naddrs; i++)
+	freeaddrinfo (lp->addrs[i]);
+    free (lp->addrs);
+    lp->addrs = NULL;
+    lp->naddrs = lp->space = 0;
+}
+#define free_list krb5int_free_addrlist
+
+static int translate_ai_error (int err)
+{
+    switch (err) {
+    case 0:
+	return 0;
+    case EAI_BADFLAGS:
+    case EAI_FAMILY:
+    case EAI_SOCKTYPE:
+    case EAI_SERVICE:
+	/* All of these indicate bad inputs to getaddrinfo.  */
+	return EINVAL;
+    case EAI_AGAIN:
+	/* Translate to standard errno code.  */
+	return EAGAIN;
+    case EAI_MEMORY:
+	/* Translate to standard errno code.  */
+	return ENOMEM;
+#ifdef EAI_ADDRFAMILY
+    case EAI_ADDRFAMILY:
+#endif
+#if EAI_NODATA != EAI_NONAME
+    case EAI_NODATA:
+#endif
+    case EAI_NONAME:
+	/* Name not known or no address data, but no error.  Do
+	   nothing more.  */
+	return 0;
+#ifdef EAI_SYSTEM
+    case EAI_SYSTEM:
+	/* System error, obviously.  */
+	return errno;
+#endif
+    default:
+	/* An error code we haven't handled?  */
+	return EINVAL;
+    }
+}
+
+#include <stdarg.h>
+static inline void Tprintf(const char *fmt, ...)
+{
+#ifdef TEST
+    va_list ap;
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+#endif
+}
+
+static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a)
+{
+    int err;
+
+    switch (a->ai_socktype) {
+    case SOCK_DGRAM:
+	Tprintf("\tdgram\n");
+	break;
+    case SOCK_STREAM:
+	Tprintf("\tstream\n");
+	break;
+    case SOCK_RAW:
+	Tprintf("\traw\n");
+	break;
+    case 0:
+	break;
+    default:
+	Tprintf("\tsocket type %d\n", a->ai_socktype);
+	break;
+    }
+
+    if (lp->naddrs == lp->space) {
+	err = grow_list (lp, 1);
+	if (err) {
+	    Tprintf ("grow_list failed %d\n", err);
+	    return err;
+	}
+    }
+    lp->addrs[lp->naddrs++] = a;
+    a->ai_next = 0;
+    Tprintf ("count is now %d\n", lp->naddrs);
+    return 0;
+}
+
+#define add_host_to_list krb5int_add_host_to_list
+
+int
+krb5int_add_host_to_list (struct addrlist *lp, const char *hostname,
+			  int port, int secport,
+			  int socktype, int family)
+{
+    struct addrinfo *addrs, *a, *anext, hint;
+    int err;
+    char portbuf[10], secportbuf[10];
+
+    Tprintf ("adding hostname %s, ports %d,%d, family %d, socktype %d\n",
+	     hostname, ntohs (port), ntohs (secport),
+	     family, socktype);
+
+    memset(&hint, 0, sizeof(hint));
+    hint.ai_family = family;
+    hint.ai_socktype = socktype;
+#ifdef AI_NUMERICSERV
+    hint.ai_flags = AI_NUMERICSERV;
+#endif
+    sprintf(portbuf, "%d", ntohs(port));
+    sprintf(secportbuf, "%d", ntohs(secport));
+    err = getaddrinfo (hostname, portbuf, &hint, &addrs);
+    if (err) {
+	Tprintf ("\tgetaddrinfo(\"%s\", \"%s\", ...)\n\treturns %d: %s\n",
+		 hostname, portbuf, err, gai_strerror (err));
+	return translate_ai_error (err);
+    }
+    anext = 0;
+    for (a = addrs; a != 0 && err == 0; a = anext) {
+	anext = a->ai_next;
+	err = add_addrinfo_to_list (lp, a);
+    }
+    if (err || secport == 0)
+	goto egress;
+    if (socktype == 0)
+	socktype = SOCK_DGRAM;
+    else if (socktype != SOCK_DGRAM)
+	goto egress;
+    hint.ai_family = AF_INET;
+    err = getaddrinfo (hostname, secportbuf, &hint, &addrs);
+    if (err) {
+	err = translate_ai_error (err);
+	goto egress;
+    }
+    for (a = addrs; a != 0 && err == 0; a = anext) {
+	anext = a->ai_next;
+	err = add_addrinfo_to_list (lp, a);
+    }
+egress:
+    if (anext)
+	freeaddrinfo (anext);
+    return err;
+}
+
+/*
+ * returns count of number of addresses found
+ * if master is non-NULL, it is filled in with the index of
+ * the master kdc
+ */
+
+static krb5_error_code
+krb5_locate_srv_conf_1(krb5_context context, const krb5_data *realm,
+		       const char * name, struct addrlist *addrlist,
+		       int get_masters, int socktype,
+		       int udpport, int sec_udpport, int family)
+{
+    const char	*realm_srv_names[4];
+    char **masterlist, **hostlist, *host, *port, *cp;
+    krb5_error_code code;
+    int i, j, count, ismaster;
+
+    Tprintf ("looking in krb5.conf for realm %s entry %s; ports %d,%d\n",
+	     realm->data, name, ntohs (udpport), ntohs (sec_udpport));
+
+    if ((host = malloc(realm->length + 1)) == NULL) 
+	return ENOMEM;
+
+    strncpy(host, realm->data, realm->length);
+    host[realm->length] = '\0';
+    hostlist = 0;
+
+    masterlist = NULL;
+
+    realm_srv_names[0] = "realms";
+    realm_srv_names[1] = host;
+    realm_srv_names[2] = name;
+    realm_srv_names[3] = 0;
+
+    code = profile_get_values(context->profile, realm_srv_names, &hostlist);
+
+    if (code) {
+	Tprintf ("config file lookup failed: %s\n",
+		 error_message(code));
+        if (code == PROF_NO_SECTION || code == PROF_NO_RELATION)
+	    code = KRB5_REALM_UNKNOWN;
+ 	krb5_xfree(host);
+  	return code;
+     }
+
+    count = 0;
+    while (hostlist && hostlist[count])
+	    count++;
+    Tprintf ("found %d entries under 'kdc'\n", count);
+    
+    if (count == 0) {
+        profile_free_list(hostlist);
+	krb5_xfree(host);
+	addrlist->naddrs = 0;
+	return 0;
+    }
+    
+    if (get_masters) {
+	realm_srv_names[0] = "realms";
+	realm_srv_names[1] = host;
+	realm_srv_names[2] = "admin_server";
+	realm_srv_names[3] = 0;
+
+	code = profile_get_values(context->profile, realm_srv_names,
+				  &masterlist);
+
+	krb5_xfree(host);
+
+	if (code == 0) {
+	    for (i=0; masterlist[i]; i++) {
+		host = masterlist[i];
+
+		/*
+		 * Strip off excess whitespace
+		 */
+		cp = strchr(host, ' ');
+		if (cp)
+		    *cp = 0;
+		cp = strchr(host, '\t');
+		if (cp)
+		    *cp = 0;
+		cp = strchr(host, ':');
+		if (cp)
+		    *cp = 0;
+	    }
+	}
+    } else {
+	krb5_xfree(host);
+    }
+
+    /* at this point, if master is non-NULL, then either the master kdc
+       is required, and there is one, or the master kdc is not required,
+       and there may or may not be one. */
+
+#ifdef HAVE_NETINET_IN_H
+    if (sec_udpport)
+	    count = count * 2;
+#endif
+
+    for (i=0; hostlist[i]; i++) {
+	int p1, p2;
+
+	host = hostlist[i];
+	Tprintf ("entry %d is '%s'\n", i, host);
+	/*
+	 * Strip off excess whitespace
+	 */
+	cp = strchr(host, ' ');
+	if (cp)
+	    *cp = 0;
+	cp = strchr(host, '\t');
+	if (cp)
+	    *cp = 0;
+	port = strchr(host, ':');
+	if (port) {
+	    *port = 0;
+	    port++;
+	}
+
+	ismaster = 0;
+	if (masterlist) {
+	    for (j=0; masterlist[j]; j++) {
+		if (strcasecmp(hostlist[i], masterlist[j]) == 0) {
+		    ismaster = 1;
+		}
+	    }
+	}
+
+	if (get_masters && !ismaster)
+	    continue;
+
+	if (port) {
+	    unsigned long l;
+#ifdef HAVE_STROUL
+	    char *endptr;
+	    l = strtoul (port, &endptr, 10);
+	    if (endptr == NULL || *endptr != 0)
+		return EINVAL;
+#else
+	    l = atoi (port);
+#endif
+	    /* L is unsigned, don't need to check <0.  */
+	    if (l > 65535)
+		return EINVAL;
+	    p1 = htons (l);
+	    p2 = 0;
+	} else {
+	    p1 = udpport;
+	    p2 = sec_udpport;
+	}
+
+	if (socktype != 0)
+	    code = add_host_to_list (addrlist, hostlist[i], p1, p2,
+				     socktype, family);
+	else {
+	    code = add_host_to_list (addrlist, hostlist[i], p1, p2,
+				     SOCK_DGRAM, family);
+	    if (code == 0)
+		code = add_host_to_list (addrlist, hostlist[i], p1, p2,
+					 SOCK_STREAM, family);
+	}
+	if (code) {
+	    Tprintf ("error %d (%s) returned from add_host_to_list\n", code,
+		     error_message (code));
+	    if (hostlist)
+		profile_free_list (hostlist);
+	    if (masterlist)
+		profile_free_list (masterlist);
+	    return code;
+	}
+    }
+
+    if (hostlist)
+        profile_free_list(hostlist);
+    if (masterlist)
+        profile_free_list(masterlist);
+
+    return 0;
+}
+
+#ifdef TEST
+static krb5_error_code
+krb5_locate_srv_conf(krb5_context context, const krb5_data *realm,
+		     const char *name, struct addrlist *al, int get_masters,
+		     int udpport, int sec_udpport)
+{
+    krb5_error_code ret;
+
+    ret = krb5_locate_srv_conf_1 (context, realm, name, al,
+				  get_masters, 0, udpport, sec_udpport, 0);
+    if (ret)
+	return ret;
+    if (al->naddrs == 0)	/* Couldn't resolve any KDC names */
+	return KRB5_REALM_CANT_RESOLVE;
+    return 0;
+}
+#endif
+
+#ifdef KRB5_DNS_LOOKUP
+static krb5_error_code
+krb5_locate_srv_dns_1 (const krb5_data *realm,
+		       const char *service,
+		       const char *protocol,
+		       struct addrlist *addrlist,
+		       int family)
+{
+    struct srv_dns_entry *head = NULL;
+    struct srv_dns_entry *entry = NULL, *next;
+    krb5_error_code code = 0;
+
+    code = krb5int_make_srv_query_realm(realm, service, protocol, &head);
+    if (code)
+	return 0;
+
+    /*
+     * Okay!  Now we've got a linked list of entries sorted by
+     * priority.  Start looking up A records and returning
+     * addresses.
+     */
+
+    if (head == NULL)
+	return 0;
+
+    /* Check for the "." case indicating no support.  */
+    if (head->next == 0 && head->host[0] == 0) {
+	free(head->host);
+	free(head);
+	return KRB5_ERR_NO_SERVICE;
+    }
+
+    Tprintf ("walking answer list:\n");
+    for (entry = head; entry != NULL; entry = next) {
+	Tprintf ("\tport=%d host=%s\n", entry->port, entry->host);
+	next = entry->next;
+	code = add_host_to_list (addrlist, entry->host, htons (entry->port), 0,
+				 (strcmp("_tcp", protocol)
+				  ? SOCK_DGRAM
+				  : SOCK_STREAM), family);
+	if (code) {
+	    break;
+	}
+	if (entry == head) {
+	    free(entry->host);
+	    free(entry);
+	    head = next;
+	    entry = 0;
+	}
+    }
+    Tprintf ("[end]\n");
+
+    krb5int_free_srv_dns_data(head);
+    return code;
+}
+#endif
+
+/*
+ * Wrapper function for the two backends
+ */
+
+krb5_error_code
+krb5int_locate_server (krb5_context context, const krb5_data *realm,
+		       struct addrlist *addrlist,
+		       int get_masters,
+		       const char *profname, const char *dnsname,
+		       int socktype,
+		       /* network order port numbers! */
+		       int dflport1, int dflport2,
+		       int family)
+{
+    krb5_error_code code;
+    struct addrlist al = ADDRLIST_INIT;
+
+    *addrlist = al;
+
+    /*
+     * We always try the local file first
+     */
+
+    code = krb5_locate_srv_conf_1(context, realm, profname, &al, get_masters,
+				  socktype, dflport1, dflport2, family);
+
+#ifdef KRB5_DNS_LOOKUP
+    if (code && dnsname != 0) {
+	int use_dns = _krb5_use_dns_kdc(context);
+	if (use_dns) {
+	    code = 0;
+	    if (socktype == SOCK_DGRAM || socktype == 0) {
+		code = krb5_locate_srv_dns_1(realm, dnsname, "_udp",
+					     &al, family);
+		if (code)
+		    Tprintf("dns udp lookup returned error %d\n", code);
+	    }
+	    if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) {
+		code = krb5_locate_srv_dns_1(realm, dnsname, "_tcp",
+					     &al, family);
+		if (code)
+		    Tprintf("dns tcp lookup returned error %d\n", code);
+	    }
+	}
+    }
+#endif /* KRB5_DNS_LOOKUP */
+    if (code == 0)
+	Tprintf ("krb5int_locate_server found %d addresses\n",
+		 al.naddrs);
+    else
+	Tprintf ("krb5int_locate_server returning error code %d\n",
+		 code);
+    if (code != 0) {
+	if (al.space)
+	    free_list (&al);
+	return code;
+    }
+    if (al.naddrs == 0) {	/* No good servers */
+	if (al.space)
+	    free_list (&al);
+	return KRB5_REALM_CANT_RESOLVE;
+    }
+    *addrlist = al;
+    return 0;
+}
+
+krb5_error_code
+krb5_locate_kdc(krb5_context context, const krb5_data *realm,
+		struct addrlist *addrlist,
+		int get_masters, int socktype, int family)
+{
+    int udpport, sec_udpport;
+
+    udpport = get_port (KDC_PORTNAME, 0, KRB5_DEFAULT_PORT);
+    if (socktype == SOCK_STREAM)
+	sec_udpport = 0;
+    else {
+	sec_udpport = get_port (KDC_SECONDARY_PORTNAME, 0,
+				(udpport == htons (KRB5_DEFAULT_PORT)
+				 ? KRB5_DEFAULT_SEC_PORT
+				 : KRB5_DEFAULT_PORT));
+	if (sec_udpport == udpport)
+	    sec_udpport = 0;
+    }
+
+    return krb5int_locate_server(context, realm, addrlist, 0,
+				 get_masters ? "master_kdc" : "kdc",
+				 (get_masters
+				  ? "_kerberos-master"
+				  : "_kerberos"),
+				 socktype, udpport, sec_udpport, family);
+}
diff --git a/mechglue/src/lib/krb5/os/lock_file.c b/mechglue/src/lib/krb5/os/lock_file.c
new file mode 100644
index 000000000..7bbd3e9d6
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/lock_file.c
@@ -0,0 +1,139 @@
+/*
+ * lib/krb5/os/lock_file.c
+ *
+ * Copyright 1990, 1998 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * libos: krb5_lock_file routine
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+
+#if !defined(_WIN32)
+
+/* Unix version...  */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <errno.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#if defined(HAVE_FCNTL_H) && defined(F_SETLKW) && defined(F_RDLCK)
+#define POSIX_FILE_LOCKS
+#endif
+
+#ifdef HAVE_FLOCK
+#ifndef sysvimp
+#include <sys/file.h>
+#endif
+#else
+#ifndef LOCK_SH
+#define LOCK_SH 0
+#define LOCK_EX 0
+#define LOCK_UN 0
+#endif
+#endif
+
+/*ARGSUSED*/
+krb5_error_code
+krb5_lock_file(krb5_context context, int fd, int mode)
+{
+    int 		lock_flag = -1;
+    krb5_error_code	retval = 0;
+#ifdef POSIX_FILE_LOCKS
+    int lock_cmd = F_SETLKW;
+    struct flock lock_arg = { 0 };
+#endif
+
+    switch (mode & ~KRB5_LOCKMODE_DONTBLOCK) {
+    case KRB5_LOCKMODE_SHARED:
+#ifdef POSIX_FILE_LOCKS
+	lock_arg.l_type = F_RDLCK;
+#endif
+	lock_flag = LOCK_SH;
+	break;
+    case KRB5_LOCKMODE_EXCLUSIVE:
+#ifdef POSIX_FILE_LOCKS
+	lock_arg.l_type = F_WRLCK;
+#endif
+	lock_flag = LOCK_EX;
+	break;
+    case KRB5_LOCKMODE_UNLOCK:
+#ifdef POSIX_FILE_LOCKS
+	lock_arg.l_type = F_UNLCK;
+#endif
+	lock_flag = LOCK_UN;
+	break;
+    }
+
+    if (lock_flag == -1)
+	return(KRB5_LIBOS_BADLOCKFLAG);
+
+    if (mode & KRB5_LOCKMODE_DONTBLOCK) {
+#ifdef POSIX_FILE_LOCKS
+	lock_cmd = F_SETLK;
+#endif
+#ifdef HAVE_FLOCK
+	lock_flag |= LOCK_NB;
+#endif
+    }
+
+#ifdef POSIX_FILE_LOCKS
+    lock_arg.l_whence = 0;
+    lock_arg.l_start = 0;
+    lock_arg.l_len = 0;
+    if (fcntl(fd, lock_cmd, &lock_arg) == -1) {
+	if (errno == EACCES || errno == EAGAIN)	/* see POSIX/IEEE 1003.1-1988,
+						   6.5.2.4 */
+	    return(EAGAIN);
+	if (errno != EINVAL)	/* Fall back to flock if we get EINVAL */
+	    return(errno);
+	retval = errno;
+    } else
+	    return 0;		/* We succeeded.  Yay. */
+#endif
+    
+#ifdef HAVE_FLOCK
+    if (flock(fd, lock_flag) == -1)
+	retval = errno;
+#endif
+    
+    return retval;
+}
+#else   /* Windows or Macintosh */
+
+krb5_error_code
+krb5_lock_file(context, fd, mode)
+    krb5_context context;
+    int fd;
+    int mode;
+{
+    return 0;
+}
+#endif
diff --git a/mechglue/src/lib/krb5/os/mk_faddr.c b/mechglue/src/lib/krb5/os/mk_faddr.c
new file mode 100644
index 000000000..2184f7220
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/mk_faddr.c
@@ -0,0 +1,88 @@
+/*
+ * lib/krb5/os/full_ipadr.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Take an IP addr & port and generate a full IP address.
+ */
+
+#include "k5-int.h"
+
+#ifdef HAVE_NETINET_IN_H
+   
+#include "os-proto.h"
+#if !defined(_WINSOCKAPI_)
+
+#include <netinet/in.h>
+#endif
+
+krb5_error_code
+krb5_make_fulladdr(krb5_context context, krb5_address *kaddr, krb5_address *kport, krb5_address *raddr)
+{
+    register krb5_octet * marshal;
+    krb5_int32 tmp32;
+    krb5_int16 tmp16;
+
+    if ((kport == NULL) || (kport == NULL)) 
+	return EINVAL;
+
+    raddr->length = kaddr->length + kport->length + (4 * sizeof(krb5_int32));
+    if (!(raddr->contents = (krb5_octet *)malloc(raddr->length)))
+	return ENOMEM;
+
+    raddr->addrtype = ADDRTYPE_ADDRPORT;
+    marshal = raddr->contents;
+
+    tmp16 = kaddr->addrtype;
+    *marshal++ = 0x00;
+    *marshal++ = 0x00;
+    *marshal++ = (krb5_octet) (tmp16 & 0xff);
+    *marshal++ = (krb5_octet) ((tmp16 >> 8) & 0xff);
+
+    tmp32 = kaddr->length;
+    *marshal++ = (krb5_octet) (tmp32 & 0xff);
+    *marshal++ = (krb5_octet) ((tmp32 >> 8) & 0xff);
+    *marshal++ = (krb5_octet) ((tmp32 >> 16) & 0xff);
+    *marshal++ = (krb5_octet) ((tmp32 >> 24) & 0xff);
+
+    (void) memcpy((char *)marshal, (char *)(kaddr->contents), kaddr->length);
+    marshal += kaddr->length;
+
+    tmp16 = kport->addrtype;
+    *marshal++ = 0x00;
+    *marshal++ = 0x00;
+    *marshal++ = (krb5_octet) (tmp16 & 0xff);
+    *marshal++ = (krb5_octet) ((tmp16 >> 8) & 0xff);
+
+    tmp32 = kport->length;
+    *marshal++ = (krb5_octet) (tmp32 & 0xff);
+    *marshal++ = (krb5_octet) ((tmp32 >> 8) & 0xff);
+    *marshal++ = (krb5_octet) ((tmp32 >> 16) & 0xff);
+    *marshal++ = (krb5_octet) ((tmp32 >> 24) & 0xff);
+
+    (void) memcpy((char *)marshal, (char *)(kport->contents), kport->length);
+    marshal += kport->length;
+    return 0;
+}
+#endif
diff --git a/mechglue/src/lib/krb5/os/net_read.c b/mechglue/src/lib/krb5/os/net_read.c
new file mode 100644
index 000000000..1d07a95d9
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/net_read.c
@@ -0,0 +1,65 @@
+/*
+ * lib/krb5/os/net_read.c
+ *
+ * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "k5-int.h"
+
+/*
+ * krb5_net_read() reads from the file descriptor "fd" to the buffer
+ * "buf", until either 1) "len" bytes have been read or 2) cannot
+ * read anymore from "fd".  It returns the number of bytes read
+ * or a read() error.  (The calling interface is identical to
+ * read(2).)
+ *
+ * XXX must not use non-blocking I/O
+ */
+
+int
+krb5_net_read(krb5_context context, int fd, register char *buf, register int len)
+{
+    int cc, len2 = 0;
+
+    do {
+	cc = SOCKET_READ((SOCKET)fd, buf, len);
+	if (cc < 0) {
+	    if (SOCKET_ERRNO == SOCKET_EINTR)
+		continue;
+		
+		/* XXX this interface sucks! */
+        errno = SOCKET_ERRNO;    
+               
+	    return(cc);		 /* errno is already set */
+	}		
+	else if (cc == 0) {
+	    return(len2);
+	} else {
+	    buf += cc;
+	    len2 += cc;
+	    len -= cc;
+	}
+    } while (len > 0);
+    return(len2);
+}
diff --git a/mechglue/src/lib/krb5/os/net_write.c b/mechglue/src/lib/krb5/os/net_write.c
new file mode 100644
index 000000000..e4981543a
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/net_write.c
@@ -0,0 +1,61 @@
+/*
+ * lib/krb5/os/net_write.c
+ *
+ * Copyright 1987, 1988, 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "k5-int.h"
+
+/*
+ * krb5_net_write() writes "len" bytes from "buf" to the file
+ * descriptor "fd".  It returns the number of bytes written or
+ * a write() error.  (The calling interface is identical to
+ * write(2).)
+ *
+ * XXX must not use non-blocking I/O
+ */
+
+int
+krb5_net_write(krb5_context context, int fd, register const char *buf, int len)
+{
+    int cc;
+    register int wrlen = len;
+    do {
+	cc = SOCKET_WRITE((SOCKET)fd, buf, wrlen);
+	if (cc < 0) {
+	    if (SOCKET_ERRNO == SOCKET_EINTR)
+		continue;
+
+		/* XXX this interface sucks! */
+        errno = SOCKET_ERRNO;           
+
+	    return(cc);
+	}
+	else {
+	    buf += cc;
+	    wrlen -= cc;
+	}
+    } while (wrlen > 0);
+    return(len);
+}
diff --git a/mechglue/src/lib/krb5/os/os-proto.h b/mechglue/src/lib/krb5/os/os-proto.h
new file mode 100644
index 000000000..2e270d5c5
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/os-proto.h
@@ -0,0 +1,72 @@
+/*
+ * lib/krb5/os/os-proto.h
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * LIBOS internal function prototypes.
+ */
+
+#ifndef KRB5_LIBOS_INT_PROTO__
+#define KRB5_LIBOS_INT_PROTO__
+
+struct addrlist;
+krb5_error_code krb5_locate_kdc
+    (krb5_context, const krb5_data *, struct addrlist *, int, int, int);
+
+#ifdef HAVE_NETINET_IN_H
+krb5_error_code krb5_unpack_full_ipaddr
+	      (krb5_context,
+	       const krb5_address *,
+	       krb5_int32 *,
+	       krb5_int16 *);
+
+krb5_error_code krb5_make_full_ipaddr
+              (krb5_context,
+	       krb5_int32,
+	       int,			/* unsigned short promotes to signed
+					   int */
+	       krb5_address **);
+
+#endif /* HAVE_NETINET_IN_H */
+
+krb5_error_code krb5_try_realm_txt_rr(const char *, const char *, 
+				      char **realm);
+
+/* Obsolete interface - leave prototype here until code removed */
+krb5_error_code krb5_secure_config_files(krb5_context ctx);
+
+int _krb5_use_dns_realm (krb5_context);
+int _krb5_use_dns_kdc (krb5_context);
+int _krb5_conf_boolean (const char *);
+
+#include "k5-thread.h"
+extern k5_mutex_t krb5int_us_time_mutex;
+
+extern unsigned int krb5_max_skdc_timeout;
+extern unsigned int krb5_skdc_timeout_shift;
+extern unsigned int krb5_skdc_timeout_1;
+extern unsigned int krb5_max_dgram_size;
+
+
+#endif /* KRB5_LIBOS_INT_PROTO__ */
diff --git a/mechglue/src/lib/krb5/os/osconfig.c b/mechglue/src/lib/krb5/os/osconfig.c
new file mode 100644
index 000000000..dec5cac77
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/osconfig.c
@@ -0,0 +1,46 @@
+/*
+ * lib/krb5/os/osconfig.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Definition of default configuration parameters.
+ *
+ * ***** WARNING *****
+ * These globals are internal library interfaces and are not
+ * supported.  Do not use them in any production code, as they will be
+ * removed from the library in the future.
+ */
+
+#include "k5-int.h"
+
+char *krb5_defkeyname  = DEFAULT_KEYTAB_NAME;
+
+unsigned int krb5_max_dgram_size = MAX_DGRAM_SIZE;
+unsigned int krb5_max_skdc_timeout = MAX_SKDC_TIMEOUT;
+unsigned int krb5_skdc_timeout_shift = SKDC_TIMEOUT_SHIFT;
+unsigned int krb5_skdc_timeout_1 = SKDC_TIMEOUT_1;
+
+char *krb5_default_pwd_prompt1 = DEFAULT_PWD_STRING1;
+char *krb5_default_pwd_prompt2 = DEFAULT_PWD_STRING2;
+
diff --git a/mechglue/src/lib/krb5/os/port2ip.c b/mechglue/src/lib/krb5/os/port2ip.c
new file mode 100644
index 000000000..6b5838b85
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/port2ip.c
@@ -0,0 +1,84 @@
+/*
+ * lib/krb5/os/port2ip.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Take an ADDRPORT address and split into IP addr & port.
+ */
+
+#include "k5-int.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include "os-proto.h"
+
+krb5_error_code
+krb5_unpack_full_ipaddr(krb5_context context, const krb5_address *inaddr, krb5_int32 *adr, krb5_int16 *port)
+{
+    unsigned long smushaddr;
+    unsigned short smushport;
+    register krb5_octet *marshal;
+    krb5_addrtype temptype;
+    krb5_ui_4 templength;
+
+    if (inaddr->addrtype != ADDRTYPE_ADDRPORT)
+	return KRB5_PROG_ATYPE_NOSUPP;
+
+    if (inaddr->length != sizeof(smushaddr)+ sizeof(smushport) +
+	2*sizeof(temptype) + 2*sizeof(templength))
+	return KRB5_PROG_ATYPE_NOSUPP;
+
+    marshal = inaddr->contents;
+
+    (void) memcpy((char *)&temptype, (char *)marshal, sizeof(temptype));
+    marshal += sizeof(temptype);
+    if (temptype != htons(ADDRTYPE_INET))
+	return KRB5_PROG_ATYPE_NOSUPP;
+
+    (void) memcpy((char *)&templength, (char *)marshal, sizeof(templength));
+    marshal += sizeof(templength);
+    if (templength != htonl(sizeof(smushaddr)))
+	return KRB5_PROG_ATYPE_NOSUPP;
+
+    (void) memcpy((char *)&smushaddr, (char *)marshal, sizeof(smushaddr));
+    /* leave in net order */
+    marshal += sizeof(smushaddr);
+
+    (void) memcpy((char *)&temptype, (char *)marshal, sizeof(temptype));
+    marshal += sizeof(temptype);
+    if (temptype != htons(ADDRTYPE_IPPORT))
+	return KRB5_PROG_ATYPE_NOSUPP;
+
+    (void) memcpy((char *)&templength, (char *)marshal, sizeof(templength));
+    marshal += sizeof(templength);
+    if (templength != htonl(sizeof(smushport)))
+	return KRB5_PROG_ATYPE_NOSUPP;
+
+    (void) memcpy((char *)&smushport, (char *)marshal, sizeof(smushport));
+    /* leave in net order */
+
+    *adr = (krb5_int32) smushaddr;
+    *port = (krb5_int16) smushport;
+    return 0;
+}
+#endif
diff --git a/mechglue/src/lib/krb5/os/prompter.c b/mechglue/src/lib/krb5/os/prompter.c
new file mode 100644
index 000000000..739c8c747
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/prompter.c
@@ -0,0 +1,327 @@
+#include "k5-int.h"
+#if !defined(_WIN32) || (defined(_WIN32) && defined(__CYGWIN32__))
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <limits.h>
+/* Is vxworks broken w.r.t. termios? --tlyu */
+#ifdef __vxworks
+#define ECHO_PASSWORD
+#endif
+
+#include <termios.h>
+
+#ifdef POSIX_SIGNALS
+typedef struct sigaction osiginfo;
+#else
+typedef struct krb5_sigtype (*osiginfo)();
+#endif
+
+static void	catch_signals(osiginfo *);
+static void	restore_signals(osiginfo *);
+static krb5_sigtype	intrfunc(int sig);
+
+static krb5_error_code	setup_tty(FILE*, int, struct termios *, osiginfo *);
+static krb5_error_code	restore_tty(FILE*, struct termios *, osiginfo *);
+
+static volatile int got_int;	/* should be sig_atomic_t */
+
+krb5_error_code KRB5_CALLCONV
+krb5_prompter_posix(
+    krb5_context	context,
+    void		*data,
+    const char		*name,
+    const char		*banner,
+    int			num_prompts,
+    krb5_prompt		prompts[])
+{
+    int		fd, i, scratchchar;
+    FILE	*fp;
+    char	*retp;
+    krb5_error_code	errcode;
+    struct termios saveparm;
+    osiginfo osigint;
+
+    errcode = KRB5_LIBOS_CANTREADPWD;
+
+    if (name) {
+	fputs(name, stdout);
+	fputs("\n", stdout);
+    }
+    if (banner) {
+       fputs(banner, stdout);
+       fputs("\n", stdout);
+    }
+
+    /*
+     * Get a non-buffered stream on stdin.
+     */
+    fp = NULL;
+    fd = dup(STDIN_FILENO);
+    if (fd < 0)
+	return KRB5_LIBOS_CANTREADPWD;
+    fp = fdopen(fd, "r");
+    if (fp == NULL)
+	goto cleanup;
+    if (setvbuf(fp, NULL, _IONBF, 0))
+	goto cleanup;
+
+    for (i = 0; i < num_prompts; i++) {
+	errcode = KRB5_LIBOS_CANTREADPWD;
+	/* fgets() takes int, but krb5_data.length is unsigned. */
+	if (prompts[i].reply->length > INT_MAX)
+	    goto cleanup;
+
+	errcode = setup_tty(fp, prompts[i].hidden, &saveparm, &osigint);
+	if (errcode)
+	    break;
+
+	/* put out the prompt */
+	(void)fputs(prompts[i].prompt, stdout);
+	(void)fputs(": ", stdout);
+	(void)fflush(stdout);
+	(void)memset(prompts[i].reply->data, 0, prompts[i].reply->length);
+
+	got_int = 0;
+	retp = fgets(prompts[i].reply->data, (int)prompts[i].reply->length,
+		     fp);
+	if (prompts[i].hidden)
+	    putchar('\n');
+	if (retp == NULL) {
+	    if (got_int)
+		errcode = KRB5_LIBOS_PWDINTR;
+	    else
+		errcode = KRB5_LIBOS_CANTREADPWD;
+	    restore_tty(fp, &saveparm, &osigint);
+	    break;
+	}
+
+	/* replace newline with null */
+	retp = strchr(prompts[i].reply->data, '\n');
+	if (retp != NULL)
+	    *retp = '\0';
+	else {
+	    /* flush rest of input line */
+	    do {
+		scratchchar = getc(fp);
+	    } while (scratchchar != EOF && scratchchar != '\n');
+	}
+
+	errcode = restore_tty(fp, &saveparm, &osigint);
+	if (errcode)
+	    break;
+	prompts[i].reply->length = strlen(prompts[i].reply->data);
+    }
+cleanup:
+    if (fp != NULL)
+	fclose(fp);
+    else if (fd >= 0)
+	close(fd);
+
+    return errcode;
+}
+
+static krb5_sigtype intrfunc(int sig)
+{
+    got_int = 1;
+}
+
+static void
+catch_signals(osiginfo *osigint)
+{
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = intrfunc;
+    sigaction(SIGINT, &sa, osigint);
+#else
+    *osigint = signal(SIGINT, intrfunc);
+#endif
+}
+
+static void
+restore_signals(osiginfo *osigint)
+{
+#ifdef POSIX_SIGNALS
+    sigaction(SIGINT, osigint, NULL);
+#else
+    signal(SIGINT, *osigint);
+#endif
+}
+
+static krb5_error_code
+setup_tty(FILE *fp, int hidden, struct termios *saveparm, osiginfo *osigint)
+{
+    krb5_error_code	ret;
+    int			fd;
+    struct termios	tparm;
+
+    ret = KRB5_LIBOS_CANTREADPWD;
+    catch_signals(osigint);
+    fd = fileno(fp);
+    do {
+	if (!isatty(fd)) {
+	    ret = 0;
+	    break;
+	}
+	if (tcgetattr(fd, &tparm) < 0)
+	    break;
+	*saveparm = tparm;
+#ifndef ECHO_PASSWORD
+	if (hidden)
+	    tparm.c_lflag &= ~(ECHO|ECHONL);
+#endif
+	tparm.c_lflag |= ISIG|ICANON;
+	if (tcsetattr(STDIN_FILENO, TCSANOW, &tparm) < 0)
+	    break;
+	ret = 0;
+    } while (0);
+    /* If we're losing, restore signal handlers. */
+    if (ret)
+	restore_signals(osigint);
+    return ret;
+}
+
+static krb5_error_code
+restore_tty(FILE* fp, struct termios *saveparm, osiginfo *osigint)
+{
+    int ret, fd;
+
+    ret = 0;
+    fd = fileno(fp);
+    if (isatty(fd)) {
+	ret = tcsetattr(fd, TCSANOW, saveparm);
+	if (ret < 0)
+	    ret = KRB5_LIBOS_CANTREADPWD;
+	else
+	    ret = 0;
+    }
+    restore_signals(osigint);
+    return ret;
+}
+
+#else /* non-Cygwin Windows, or Mac */
+
+#if defined(_WIN32)
+
+#include <io.h>
+
+krb5_error_code KRB5_CALLCONV
+krb5_prompter_posix(krb5_context context,
+		    void *data,
+		    const char *name,
+		    const char *banner,
+		    int num_prompts,
+		    krb5_prompt prompts[])
+{
+    HANDLE		handle;
+    DWORD		old_mode, new_mode;
+    char		*ptr;
+    int			scratchchar;
+    krb5_error_code	errcode = 0;
+    int			i;
+
+    handle = GetStdHandle(STD_INPUT_HANDLE);
+    if (handle == INVALID_HANDLE_VALUE)
+	return ENOTTY;
+    if (!GetConsoleMode(handle, &old_mode))
+	return ENOTTY;
+
+    new_mode = old_mode;
+    new_mode |=  ( ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT );
+    new_mode &= ~( ENABLE_ECHO_INPUT );
+
+    if (!SetConsoleMode(handle, new_mode))
+	return ENOTTY;
+
+    if (!SetConsoleMode(handle, old_mode))
+	return ENOTTY;
+
+    if (name) {
+	fputs(name, stdout);
+	fputs("\n", stdout);
+    }
+
+    if (banner) {
+       fputs(banner, stdout);
+       fputs("\n", stdout);
+    }
+
+    for (i = 0; i < num_prompts; i++) {
+	if (prompts[i].hidden) {
+	    if (!SetConsoleMode(handle, new_mode)) {
+		errcode = ENOTTY;
+		goto cleanup;
+	    }
+	}
+
+	fputs(prompts[i].prompt,stdout);
+	fputs(": ", stdout);
+	fflush(stdout);
+	memset(prompts[i].reply->data, 0, prompts[i].reply->length);
+
+	if (fgets(prompts[i].reply->data, prompts[i].reply->length, stdin)
+	    == NULL) {
+	    if (prompts[i].hidden)
+		putchar('\n');
+	    errcode = KRB5_LIBOS_CANTREADPWD;
+	    goto cleanup;
+	}
+	if (prompts[i].hidden)
+	    putchar('\n');
+	/* fgets always null-terminates the returned string */
+
+	/* replace newline with null */
+	if ((ptr = strchr(prompts[i].reply->data, '\n')))
+	    *ptr = '\0';
+	else /* flush rest of input line */
+	    do {
+		scratchchar = getchar();
+	    } while (scratchchar != EOF && scratchchar != '\n');
+    
+	prompts[i].reply->length = strlen(prompts[i].reply->data);
+
+	if (!SetConsoleMode(handle, old_mode)) {
+	    errcode = ENOTTY;
+	    goto cleanup;
+	}
+    }
+
+ cleanup:
+    if (errcode) {
+	for (i = 0; i < num_prompts; i++) {
+	    memset(prompts[i].reply->data, 0, prompts[i].reply->length);
+	}
+    }
+    return errcode;
+}
+
+#else /* !_WIN32 */
+
+krb5_error_code KRB5_CALLCONV
+krb5_prompter_posix(krb5_context context,
+		    void *data,
+		    const char *name,
+		    const char *banner,
+		    int num_prompts,
+		    krb5_prompt prompts[])
+{
+    return(EINVAL);
+}
+#endif /* !_WIN32 */
+#endif /* Windows or Mac */
+
+void
+krb5int_set_prompt_types(krb5_context context, krb5_prompt_type *types)
+{
+    context->prompt_types = types;
+}
+
+krb5_prompt_type*
+KRB5_CALLCONV
+krb5_get_prompt_types(krb5_context context)
+{
+    return context->prompt_types;
+}
diff --git a/mechglue/src/lib/krb5/os/promptusr.c b/mechglue/src/lib/krb5/os/promptusr.c
new file mode 100644
index 000000000..68f8b14a0
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/promptusr.c
@@ -0,0 +1,160 @@
+/*
+ * promptusr.c --- prompt user for input/output
+ */
+
+#include "k5-int.h"
+#if !defined(_WIN32)
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <termios.h>
+#include <signal.h>
+#include <setjmp.h>
+
+typedef struct _krb5_uio {
+    krb5_magic		magic;
+    int 		flags;
+    char *		prompt;
+    char *		response;
+    struct _krb5_uio	*next;
+} *krb5_uio;
+
+#define KRB5_UIO_GETRESPONSE	0x0001
+#define KRB5_UIO_ECHORESPONSE	0x0002
+#define KRB5_UIO_FREE_PROMPT	0x0004
+
+static jmp_buf pwd_jump;
+
+static krb5_sigtype
+intr_routine(int signo)
+{
+    longjmp(pwd_jump, 1);
+    /*NOTREACHED*/
+}
+
+krb5_error_code
+krb5_os_get_tty_uio(krb5_context context, krb5_uio uio)
+{
+    volatile krb5_error_code 	retval;
+    krb5_sigtype	(*volatile ointrfunc)();
+    krb5_uio		p;
+    struct termios 	echo_control, save_control;
+    int 		fd;
+    char		read_string[BUFSIZ];
+    char		*cp;
+    int			ch;
+
+    /* get the file descriptor associated with stdin */
+    fd=fileno(stdin);
+
+    if (tcgetattr(fd, &echo_control) == -1)
+	return errno;
+
+    save_control = echo_control;
+    echo_control.c_lflag &= ~(ECHO|ECHONL);
+
+    if (setjmp(pwd_jump)) {
+	retval = KRB5_LIBOS_PWDINTR; 	/* we were interrupted... */
+	goto cleanup;
+    }
+    /* save intrfunc */
+    ointrfunc = signal(SIGINT, intr_routine);
+    
+    for (p = uio; p; p = p->next) {
+	if (p->prompt) {
+	    fputs(p->prompt, stdout);
+	    fflush(stdout);
+	}
+	if ((p->flags & KRB5_UIO_GETRESPONSE) == 0)
+	    continue;
+
+	if ((p->flags & KRB5_UIO_ECHORESPONSE) == 0) 
+	    if (tcsetattr(fd, TCSANOW, &echo_control) == -1)
+		return errno;
+
+	if (fgets(read_string, sizeof(read_string), stdin) == NULL) {
+	    (void) putchar('\n');
+	    retval = KRB5_LIBOS_CANTREADPWD;
+	    goto cleanup;
+	}
+	
+	/* replace newline with null */
+	if ((cp = strchr(read_string, '\n')))
+	    *cp = '\0';
+	else /* flush rest of input line */
+	    do {
+		ch = getchar();
+	    } while (ch != EOF && ch != '\n');
+	read_string[sizeof(read_string)-1] = 0;
+
+	if ((p->response = malloc(strlen(read_string)+1)) == NULL) {
+	    errno = ENOMEM;
+	    goto cleanup;
+	}
+	strcpy(p->response, read_string);
+
+	if ((p->flags & KRB5_UIO_ECHORESPONSE) == 0) {
+	    (void) putchar('\n');
+	    if (tcsetattr(fd, TCSANOW, &save_control) == -1) {
+		retval = errno;
+		goto cleanup;
+	    }
+	}
+    }
+    retval = 0;
+    
+ cleanup:
+    (void) signal(SIGINT, ointrfunc);
+    if (retval) {
+	for (p = uio; p; p = p->next) {
+	    if (p->response) {
+		memset(p->response, 0, strlen(p->response));
+		free(p->response);
+		p->response = 0;
+	    }
+	}
+    }
+    memset(read_string, 0, sizeof(read_string));
+    tcsetattr(fd, TCSANOW, &save_control);
+    return retval;
+}
+
+void
+krb5_free_uio(krb5_context context, krb5_uio uio)
+{
+    krb5_uio		p, next;
+
+    for (p = uio; p; p = next) {
+	next = p->next;
+	if (p->prompt && (p->flags & KRB5_UIO_FREE_PROMPT))
+	    free(p->prompt);
+	if (p->response)
+	    free(p->response);
+	free(p);
+    }
+}
+
+#ifdef TEST_DRIVER
+
+struct _krb5_uio uio_a = { 0, KRB5_UIO_GETRESPONSE, "Password 1: " };
+struct _krb5_uio uio_b = { 0, KRB5_UIO_GETRESPONSE |
+			       KRB5_UIO_ECHORESPONSE, "Password 2: " };
+struct _krb5_uio uio_c = { 0, KRB5_UIO_GETRESPONSE, "Password 3: " };
+
+
+void
+main(int argc, char **argv)
+{
+    uio_a.next = &uio_b;
+    uio_b.next = &uio_c;
+
+    krb5_os_get_tty_uio(0, &uio_a);
+    exit(0);
+}
+
+#endif
+	
+#endif /* !_MSODS */
diff --git a/mechglue/src/lib/krb5/os/read_msg.c b/mechglue/src/lib/krb5/os/read_msg.c
new file mode 100644
index 000000000..776502c6d
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/read_msg.c
@@ -0,0 +1,63 @@
+/*
+ * lib/krb5/os/read_msg.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Write a message to the network
+ */
+
+#include "k5-int.h"
+#include <errno.h>
+
+krb5_error_code
+krb5_read_message(krb5_context context, krb5_pointer fdp, krb5_data *inbuf)
+{
+	krb5_int32	len;
+	int		len2, ilen;
+	char		*buf = NULL;
+	int		fd = *( (int *) fdp);
+	
+	if ((len2 = krb5_net_read(context, fd, (char *)&len, 4)) != 4)
+		return((len2 < 0) ? errno : ECONNABORTED);
+	len = ntohl(len);
+
+	if ((len & VALID_UINT_BITS) != len)  /* Overflow size_t??? */
+		return ENOMEM;
+
+	inbuf->length = ilen = (int) len;
+	if (ilen) {
+		/*
+		 * We may want to include a sanity check here someday....
+		 */
+		if (!(buf = malloc(ilen))) {
+			return(ENOMEM);
+		}
+		if ((len2 = krb5_net_read(context, fd, buf, ilen)) != ilen) {
+			krb5_xfree(buf);
+			return((len2 < 0) ? errno : ECONNABORTED);
+		}
+	}
+	inbuf->data = buf;
+	return(0);
+}
diff --git a/mechglue/src/lib/krb5/os/read_pwd.c b/mechglue/src/lib/krb5/os/read_pwd.c
new file mode 100644
index 000000000..0e3d53ef9
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/read_pwd.c
@@ -0,0 +1,297 @@
+/*
+ * lib/krb5/os/read_pwd.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * libos: krb5_read_password for BSD 4.3
+ */
+
+#include "k5-int.h"
+
+#if !defined(_WIN32)
+#define DEFINED_KRB5_READ_PASSWORD
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <setjmp.h>
+
+#ifndef ECHO_PASSWORD
+#include <termios.h>
+#endif /* ECHO_PASSWORD */
+
+krb5_error_code
+krb5_read_password(krb5_context context, const char *prompt, const char *prompt2, char *return_pwd, unsigned int *size_return)
+{
+    krb5_data reply_data;      
+    krb5_prompt k5prompt;
+    krb5_error_code retval;
+    reply_data.length = *size_return; /* NB: size_return is also an input */
+    reply_data.data = return_pwd;
+    k5prompt.prompt = (char *)prompt;
+    k5prompt.hidden = 1;
+    k5prompt.reply = &reply_data;
+    retval =  krb5_prompter_posix(NULL,
+				  NULL, NULL, NULL, 1, &k5prompt);
+
+    if ((retval==0) && prompt2) {
+	krb5_data verify_data;
+	verify_data.data = malloc(*size_return);
+	verify_data.length = *size_return;
+	k5prompt.prompt = (char *)prompt2;
+	k5prompt.reply = &verify_data;
+	if (!verify_data.data)
+	    return ENOMEM;
+	retval = krb5_prompter_posix(NULL,
+				     NULL,NULL, NULL, 1, &k5prompt);
+	if (retval == 0) {
+	    /* compare */
+	    if (strncmp(return_pwd, (char *)verify_data.data, *size_return))
+		retval = KRB5_LIBOS_BADPWDMATCH;
+	}
+	free(verify_data.data);
+    }
+    if (!retval)
+	*size_return = k5prompt.reply->length;
+    else
+	memset(return_pwd, 0, *size_return);
+    return retval;
+}
+#endif
+
+#if defined(_WIN32)
+#define DEFINED_KRB5_READ_PASSWORD
+
+#include <io.h>
+
+typedef struct {
+    char *pwd_prompt;
+    char *pwd_prompt2;
+    char *pwd_return_pwd;
+    int  *pwd_size_return;
+} pwd_params;
+
+void center_dialog(HWND hwnd)
+{
+    int scrwidth, scrheight;
+    int dlgwidth, dlgheight;
+    RECT r;
+    HDC hdc;
+    
+    if (hwnd == NULL)
+	return;
+    
+    GetWindowRect(hwnd, &r);
+    dlgwidth = r.right  - r.left;
+    dlgheight = r.bottom - r.top ;
+    hdc = GetDC(NULL);
+    scrwidth = GetDeviceCaps(hdc, HORZRES);
+    scrheight = GetDeviceCaps(hdc, VERTRES);
+    ReleaseDC(NULL, hdc);
+    r.left = (scrwidth - dlgwidth) / 2;
+    r.top  = (scrheight - dlgheight) / 2;
+    MoveWindow(hwnd, r.left, r.top, dlgwidth, dlgheight, TRUE);
+}
+
+#ifdef _WIN32
+static krb5_error_code
+read_console_password(
+    krb5_context	context,
+    const char		* prompt,
+    const char		* prompt2,
+    char		* password,
+    int			* pwsize)
+{
+    HANDLE		handle;
+    DWORD		old_mode, new_mode;
+    char		*tmpstr = 0;
+    char		*ptr;
+    int			scratchchar;
+    krb5_error_code	errcode = 0;
+
+    handle = GetStdHandle(STD_INPUT_HANDLE);
+    if (handle == INVALID_HANDLE_VALUE)
+	return ENOTTY;
+    if (!GetConsoleMode(handle, &old_mode))
+	return ENOTTY;
+
+    new_mode = old_mode;
+    new_mode |=  ( ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT );
+    new_mode &= ~( ENABLE_ECHO_INPUT );
+
+    if (!SetConsoleMode(handle, new_mode))
+	return ENOTTY;
+
+    (void) fputs(prompt, stdout);
+    (void) fflush(stdout);
+    (void) memset(password, 0, *pwsize);
+
+    if (fgets(password, *pwsize, stdin) == NULL) {
+	(void) putchar('\n');
+	errcode = KRB5_LIBOS_CANTREADPWD;
+	goto cleanup;
+    }
+    (void) putchar('\n');
+
+    if ((ptr = strchr(password, '\n')))
+	*ptr = '\0';
+    else /* need to flush */
+	do {
+	    scratchchar = getchar();
+	} while (scratchchar != EOF && scratchchar != '\n');
+
+    if (prompt2) {
+	if (! (tmpstr = (char *)malloc(*pwsize))) {
+	    errcode = ENOMEM;
+	    goto cleanup;
+	}
+	(void) fputs(prompt2, stdout);
+	(void) fflush(stdout);
+	if (fgets(tmpstr, *pwsize, stdin) == NULL) {
+	    (void) putchar('\n');
+	    errcode = KRB5_LIBOS_CANTREADPWD;
+	    goto cleanup;
+	}
+	(void) putchar('\n');
+
+	if ((ptr = strchr(tmpstr, '\n')))
+	    *ptr = '\0';
+	else /* need to flush */
+	    do {
+		scratchchar = getchar();
+	    } while (scratchchar != EOF && scratchchar != '\n');
+
+	if (strncmp(password, tmpstr, *pwsize)) {
+	    errcode = KRB5_LIBOS_BADPWDMATCH;
+	    goto cleanup;
+	}
+    }
+
+cleanup:
+    (void) SetConsoleMode(handle, old_mode);
+    if (tmpstr) {
+	(void) memset(tmpstr, 0, *pwsize);
+	(void) free(tmpstr);
+    }
+    if (errcode)
+	(void) memset(password, 0, *pwsize);
+    else
+	*pwsize = strlen(password);
+    return errcode;
+}
+#endif
+
+static int CALLBACK
+read_pwd_proc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    pwd_params *dp;
+    
+    switch(msg) {
+    case WM_INITDIALOG:
+	dp = (pwd_params *) lParam;
+	SetWindowLong(hdlg, DWL_USER, lParam);
+	SetDlgItemText(hdlg, ID_READ_PWD_PROMPT, dp->pwd_prompt);
+	SetDlgItemText(hdlg, ID_READ_PWD_PROMPT2, dp->pwd_prompt2);
+	SetDlgItemText(hdlg, ID_READ_PWD_PWD, "");
+	center_dialog(hdlg);
+	return TRUE;
+
+    case WM_COMMAND:
+	dp = (pwd_params *) GetWindowLong(hdlg, DWL_USER);
+        switch (wParam) {
+	case IDOK:
+	    *(dp->pwd_size_return) =
+		GetDlgItemText(hdlg, ID_READ_PWD_PWD, 
+			       dp->pwd_return_pwd, *(dp->pwd_size_return));
+	    EndDialog(hdlg, TRUE);
+	    break;
+	    
+	case IDCANCEL:
+	    memset(dp->pwd_return_pwd, 0 , *(dp->pwd_size_return));
+	    *(dp->pwd_size_return) = 0;
+	    EndDialog(hdlg, FALSE);
+	    break;
+        }
+        return TRUE;
+ 
+    default:
+        return FALSE;
+    }
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_read_password(context, prompt, prompt2, return_pwd, size_return)
+    krb5_context context;
+    const char *prompt;
+    const char *prompt2;
+    char *return_pwd;
+    int *size_return;
+{
+    DLGPROC dlgproc;
+    HINSTANCE hinst;
+    pwd_params dps;
+    int rc;
+
+#ifdef _WIN32
+    if (_isatty(_fileno(stdin)))
+	return(read_console_password
+	       (context, prompt, prompt2, return_pwd, size_return));
+#endif
+
+    dps.pwd_prompt = prompt;
+    dps.pwd_prompt2 = prompt2;
+    dps.pwd_return_pwd = return_pwd;
+    dps.pwd_size_return = size_return;
+
+    hinst = get_lib_instance();
+#ifdef _WIN32
+    dlgproc = read_pwd_proc;
+#else
+    dlgproc = (FARPROC) MakeProcInstance(read_pwd_proc, hinst);
+#endif
+    rc = DialogBoxParam(hinst, MAKEINTRESOURCE(ID_READ_PWD_DIALOG), 0,
+			dlgproc, (LPARAM) &dps);
+#ifndef _WIN32
+    FreeProcInstance ((FARPROC) dlgproc);
+#endif
+    return 0;
+}
+#endif
+
+#ifndef DEFINED_KRB5_READ_PASSWORD
+#define DEFINED_KRB5_READ_PASSWORD
+/*
+ * Don't expect to be called, just define it for sanity and the linker.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_read_password(context, prompt, prompt2, return_pwd, size_return)
+    krb5_context context;
+    const char *prompt;
+    const char *prompt2;
+    char *return_pwd;
+    int *size_return;
+{
+   *size_return = 0;
+   return KRB5_LIBOS_CANTREADPWD;
+}
+#endif
diff --git a/mechglue/src/lib/krb5/os/realm_dom.c b/mechglue/src/lib/krb5/os/realm_dom.c
new file mode 100644
index 000000000..d7a4be7db
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/realm_dom.c
@@ -0,0 +1,67 @@
+/*
+ * lib/krb5/os/realm_dom.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_get_realm_domain()
+ */
+
+
+/*
+ * Determines the proper domain name for a realm.  This is mainly so that
+ * a krb4 principal can be converted properly into a krb5 principal.
+ * Currently, the same style of mapping file used in krb4.
+ *
+ * If realm is NULL, this function will assume the default realm
+ * of the local host.
+ *
+ * The returned domain is allocated, and must be freed by the caller.
+ *
+ * This was hacked together from krb5_get_host_realm().
+ */
+
+#include "k5-int.h"
+#include <ctype.h>
+#include <stdio.h>
+
+krb5_error_code KRB5_CALLCONV
+krb5_get_realm_domain(krb5_context context, const char *realm, char **domain)
+{
+    krb5_error_code retval;
+    char *temp_domain = 0;
+
+    retval = profile_get_string(context->profile, "realms", realm,
+			       "default_domain", realm, &temp_domain);
+    if (!retval && temp_domain)
+    {
+        *domain = malloc(strlen(temp_domain) + 1);
+        if (!*domain) {
+            retval = ENOMEM;
+        } else {
+            strcpy(*domain, temp_domain);
+        }
+        profile_release_string(temp_domain);
+    }
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/os/realm_iter.c b/mechglue/src/lib/krb5/os/realm_iter.c
new file mode 100644
index 000000000..0beaa2f46
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/realm_iter.c
@@ -0,0 +1,60 @@
+/*
+ * lib/krb5/os/realm_init.c
+ *
+ * Copyright 1998 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * krb5_realm_iterate()
+ */
+
+#include "k5-int.h"
+#include <ctype.h>
+#include <stdio.h>
+
+krb5_error_code KRB5_CALLCONV
+krb5_realm_iterator_create(krb5_context context, void **iter_p)
+{
+    static const char *const names[] = { "realms", 0 };
+	
+    return profile_iterator_create(context->profile, names,
+				   PROFILE_ITER_LIST_SECTION |
+				   PROFILE_ITER_SECTIONS_ONLY,
+				   iter_p);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_realm_iterator(krb5_context context, void **iter_p, char **ret_realm)
+{
+    return profile_iterator(iter_p, ret_realm, 0);
+}
+
+void KRB5_CALLCONV
+krb5_realm_iterator_free(krb5_context context, void **iter_p)
+{
+    profile_iterator_free(iter_p);
+}
+
+void KRB5_CALLCONV
+krb5_free_realm_string(krb5_context context, char *str)
+{
+    profile_release_string(str);
+}
diff --git a/mechglue/src/lib/krb5/os/ref_std_conf.out b/mechglue/src/lib/krb5/os/ref_std_conf.out
new file mode 100644
index 000000000..273a7664b
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/ref_std_conf.out
@@ -0,0 +1,13 @@
+krb5_get_default_realm() returned 'DEFAULT.REALM.TST'
+krb5_set_default_realm(NEW.DEFAULT.REALM)
+krb5_get_default_realm() returned 'NEW.DEFAULT.REALM'
+krb_get_krbhst(IGGY.ORG) returned: 'KERBEROS.IGGY.ORG' 'KERBEROS-B.IGGY.ORG'
+krb_get_krbhst(DEFAULT_REALM.TST) returned: 'FIRST.KDC.HOST' 'SECOND.KDC.HOST'
+krb5_get_realm_domain(DEFAULT_REALM.TST) returned 'MIT.EDU'
+krb_get_host_realm(bad.idea) returned: 'US.GOV'
+krb_get_host_realm(itar.bad.idea) returned: 'NSA.GOV'
+krb_get_host_realm(really.BAD.IDEA.) returned: 'NSA.GOV'
+krb_get_host_realm(clipper.bad.idea) returned: 'NIST.GOV'
+krb_get_host_realm(KeYEsCrOW.BaD.IDea) returned: 'NSA.GOV'
+krb_get_host_realm(pgp.good.idea) returned: 'GOOD.IDEA'
+krb_get_host_realm(no_domain) returned: 'NEW.DEFAULT.REALM'
diff --git a/mechglue/src/lib/krb5/os/send524.c b/mechglue/src/lib/krb5/os/send524.c
new file mode 100644
index 000000000..004d80348
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/send524.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1990,1991,1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Send a packet to a service and await a reply, using an exponential
+ * backoff retry algorithm.  This is based on krb5_sendto_kdc.
+ */
+
+/* Grab socket stuff.  This might want to go away later. */
+#include "fake-addrinfo.h" /* for custom addrinfo if needed */
+#include "k5-int.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "os-proto.h"
+
+/*
+ * krb524_sendto_kdc:
+ *
+ * A slightly modified version of krb5_sendto_kdc.
+ *
+ * send the formatted request 'message' to a KDC for realm 'realm' and
+ * return the response (if any) in 'reply'.
+ *
+ * If the message is sent and a response is received, 0 is returned,
+ * otherwise an error code is returned.
+ *
+ * The storage for 'reply' is allocated and should be freed by the caller
+ * when finished.
+ */
+
+krb5_error_code
+krb5int_524_sendto_kdc (context, message, realm, reply, addr, addrlen)
+    krb5_context context;
+    const krb5_data * message;
+    const krb5_data * realm;
+    krb5_data * reply;
+    struct sockaddr *addr;
+    socklen_t *addrlen;
+{
+#if defined(KRB5_KRB4_COMPAT) || defined(_WIN32) /* yuck! */
+    int i;
+    struct addrlist al = ADDRLIST_INIT;
+    struct servent *serv;
+    krb5_error_code retval;
+    int port;
+
+    /*
+     * find KDC location(s) for realm
+     */
+
+    serv = getservbyname(KRB524_SERVICE, "udp");
+    port = serv ? serv->s_port : htons (KRB524_PORT);
+
+    retval = krb5int_locate_server(context, realm, &al, 0,
+				   "krb524_server", "_krb524",
+				   SOCK_DGRAM, port,
+				   0, PF_INET);
+    if (retval == KRB5_REALM_CANT_RESOLVE || retval == KRB5_REALM_UNKNOWN) {
+	/* Fallback heuristic: Assume krb524 port on every KDC might
+	   work.  */
+	retval = krb5_locate_kdc(context, realm, &al, 0, SOCK_DGRAM, PF_INET);
+	/*
+	 * Bash the ports numbers.
+	 */
+	if (retval == 0)
+	    for (i = 0; i < al.naddrs; i++) {
+		al.addrs[i]->ai_socktype = SOCK_DGRAM;
+		if (al.addrs[i]->ai_family == AF_INET)
+		    sa2sin (al.addrs[i]->ai_addr)->sin_port = port;
+	    }
+    }
+    if (retval)
+	return retval;
+    if (al.naddrs == 0)
+	return KRB5_REALM_UNKNOWN;
+
+    retval = krb5int_sendto (context, message, &al, reply, addr, addrlen, NULL);
+    krb5int_free_addrlist (&al);
+    return retval;
+#else
+    return KRB524_KRB4_DISABLED;
+#endif
+}
diff --git a/mechglue/src/lib/krb5/os/sendto_kdc.c b/mechglue/src/lib/krb5/os/sendto_kdc.c
new file mode 100644
index 000000000..e35c337d3
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/sendto_kdc.c
@@ -0,0 +1,1163 @@
+/*
+ * lib/krb5/os/sendto_kdc.c
+ *
+ * Copyright 1990,1991,2001,2002,2004,2005 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Send packet to KDC for realm; wait for response, retransmitting
+ * as necessary.
+ */
+
+#include "fake-addrinfo.h"
+#include "k5-int.h"
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#include "os-proto.h"
+#ifdef _WIN32
+#include <sys/timeb.h>
+#endif
+
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+
+#ifndef _WIN32
+/* For FIONBIO.  */
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+#endif
+
+#define MAX_PASS		    3
+#define DEFAULT_UDP_PREF_LIMIT	 1465
+#define HARD_UDP_LIMIT		32700 /* could probably do 64K-epsilon ? */
+
+#undef DEBUG
+
+#ifdef DEBUG
+int krb5int_debug_sendto_kdc = 0;
+#define debug krb5int_debug_sendto_kdc
+
+static void default_debug_handler (const void *data, size_t len)
+{
+#if 0
+    FILE *logfile;
+    logfile = fopen("/tmp/sendto_kdc.log", "a");
+    if (logfile == NULL)
+	return;
+    fwrite(data, 1, len, logfile);
+    fclose(logfile);
+#else
+    fwrite(data, 1, len, stderr);
+    /* stderr is unbuffered */
+#endif
+}
+
+void (*krb5int_sendtokdc_debug_handler) (const void *, size_t) = default_debug_handler;
+
+static void put(const void *ptr, size_t len)
+{
+    (*krb5int_sendtokdc_debug_handler)(ptr, len);
+}
+static void putstr(const char *str)
+{
+    put(str, strlen(str));
+}
+#else
+void (*krb5int_sendtokdc_debug_handler) (const void *, size_t) = 0;
+#endif
+
+#define dprint krb5int_debug_fprint
+static void
+krb5int_debug_fprint (const char *fmt, ...)
+{
+#ifdef DEBUG
+    va_list args;
+
+    /* Temporaries for variable arguments, etc.  */
+    krb5_error_code kerr;
+    int err;
+    fd_set *rfds, *wfds, *xfds;
+    int i;
+    int maxfd;
+    struct timeval *tv;
+    struct addrinfo *ai;
+    const krb5_data *d;
+    char addrbuf[NI_MAXHOST], portbuf[NI_MAXSERV];
+    const char *p;
+    char tmpbuf[NI_MAXHOST + NI_MAXSERV + 30];
+
+    if (!krb5int_debug_sendto_kdc)
+	return;
+
+    va_start(args, fmt);
+
+#define putf(FMT,X)	(sprintf(tmpbuf,FMT,X),putstr(tmpbuf))
+
+    for (; *fmt; fmt++) {
+	if (*fmt != '%') {
+	    /* Possible optimization: Look for % and print all chars
+	       up to it in one call.  */
+	    put(fmt, 1);
+	    continue;
+	}
+	/* After this, always processing a '%' sequence.  */
+	fmt++;
+	switch (*fmt) {
+	case 0:
+	default:
+	    abort();
+	case 'E':
+	    /* %E => krb5_error_code */
+	    kerr = va_arg(args, krb5_error_code);
+	    sprintf(tmpbuf, "%lu/", (unsigned long) kerr);
+	    putstr(tmpbuf);
+	    p = error_message(kerr);
+	    putstr(p);
+	    break;
+	case 'm':
+	    /* %m => errno value (int) */
+	    /* Like syslog's %m except the errno value is passed in
+	       rather than the current value.  */
+	    err = va_arg(args, int);
+	    putf("%d/", err);
+	    p = strerror(err);
+	    putstr(p);
+	    break;
+	case 'F':
+	    /* %F => fd_set *, fd_set *, fd_set *, int */
+	    rfds = va_arg(args, fd_set *);
+	    wfds = va_arg(args, fd_set *);
+	    xfds = va_arg(args, fd_set *);
+	    maxfd = va_arg(args, int);
+
+	    for (i = 0; i < maxfd; i++) {
+		int r = FD_ISSET(i, rfds);
+		int w = wfds && FD_ISSET(i, wfds);
+		int x = xfds && FD_ISSET(i, xfds);
+		if (r || w || x) {
+		    putf(" %d", i);
+		    if (r)
+			putstr("r");
+		    if (w)
+			putstr("w");
+		    if (x)
+			putstr("x");
+		}
+	    }
+	    putstr(" ");
+	    break;
+	case 's':
+	    /* %s => char * */
+	    p = va_arg(args, const char *);
+	    putstr(p);
+	    break;
+	case 't':
+	    /* %t => struct timeval * */
+	    tv = va_arg(args, struct timeval *);
+	    if (tv) {
+		sprintf(tmpbuf, "%ld.%06ld",
+			(long) tv->tv_sec, (long) tv->tv_usec);
+		putstr(tmpbuf);
+	    } else
+		putstr("never");
+	    break;
+	case 'd':
+	    /* %d => int */
+	    putf("%d", va_arg(args, int));
+	    break;
+	case 'p':
+	    /* %p => pointer */
+	    putf("%p", va_arg(args, void*));
+	    break;
+	case 'A':
+	    /* %A => addrinfo */
+	    ai = va_arg(args, struct addrinfo *);
+	    if (0 != getnameinfo (ai->ai_addr, ai->ai_addrlen,
+				  addrbuf, sizeof (addrbuf),
+				  portbuf, sizeof (portbuf),
+				  NI_NUMERICHOST | NI_NUMERICSERV))
+		strcpy (addrbuf, "??"), strcpy (portbuf, "??");
+	    sprintf(tmpbuf, "%s %s.%s",
+		    (ai->ai_socktype == SOCK_DGRAM
+		     ? "udp"
+		     : ai->ai_socktype == SOCK_STREAM
+		     ? "tcp"
+		     : "???"),
+		    addrbuf, portbuf);
+	    putstr(tmpbuf);
+	    break;
+	case 'D':
+	    /* %D => krb5_data * */
+	    d = va_arg(args, krb5_data *);
+	    /* may not be nul-terminated */
+	    put(d->data, d->length);
+	    break;
+	}
+    }
+    va_end(args);
+#endif
+}
+
+static int
+merge_addrlists (struct addrlist *dest, struct addrlist *src)
+{
+    int err, i;
+
+    dprint("merging addrlists:\n\tlist1: ");
+    for (i = 0; i < dest->naddrs; i++)
+	dprint(" %A", dest->addrs[i]);
+    dprint("\n\tlist2: ");
+    for (i = 0; i < src->naddrs; i++)
+	dprint(" %A", src->addrs[i]);
+    dprint("\n");
+
+    err = krb5int_grow_addrlist (dest, src->naddrs);
+    if (err)
+	return err;
+    for (i = 0; i < src->naddrs; i++) {
+	dest->addrs[dest->naddrs + i] = src->addrs[i];
+	src->addrs[i] = 0;
+    }
+    dest->naddrs += i;
+    src->naddrs = 0;
+
+    dprint("\tout:   ");
+    for (i = 0; i < dest->naddrs; i++)
+	dprint(" %A", dest->addrs[i]);
+    dprint("\n");
+
+    return 0;
+}
+
+/*
+ * send the formatted request 'message' to a KDC for realm 'realm' and
+ * return the response (if any) in 'reply'.
+ *
+ * If the message is sent and a response is received, 0 is returned,
+ * otherwise an error code is returned.
+ *
+ * The storage for 'reply' is allocated and should be freed by the caller
+ * when finished.
+ */
+
+krb5_error_code
+krb5_sendto_kdc (krb5_context context, const krb5_data *message,
+		 const krb5_data *realm, krb5_data *reply,
+		 int *use_master, int tcp_only)
+{
+    krb5_error_code retval;
+    struct addrlist addrs;
+    int socktype1 = 0, socktype2 = 0, addr_used;
+
+    /*
+     * find KDC location(s) for realm
+     */
+
+    /*
+     * BUG: This code won't return "interesting" errors (e.g., out of mem,
+     * bad config file) from locate_kdc.  KRB5_REALM_CANT_RESOLVE can be
+     * ignored from one query of two, but if only one query is done, or
+     * both return that error, it should be returned to the caller.  Also,
+     * "interesting" errors (not KRB5_KDC_UNREACH) from sendto_{udp,tcp}
+     * should probably be returned as well.
+     */
+
+    dprint("krb5_sendto_kdc(%d@%p, \"%D\", use_master=%d, tcp_only=%d)\n",
+	   message->length, message->data, realm, *use_master, tcp_only);
+
+    if (!tcp_only && context->udp_pref_limit < 0) {
+	int tmp;
+	retval = profile_get_integer(context->profile,
+				     "libdefaults", "udp_preference_limit", 0,
+				     DEFAULT_UDP_PREF_LIMIT, &tmp);
+	if (retval)
+	    return retval;
+	if (tmp < 0)
+	    tmp = DEFAULT_UDP_PREF_LIMIT;
+	else if (tmp > HARD_UDP_LIMIT)
+	    /* In the unlikely case that a *really* big value is
+	       given, let 'em use as big as we think we can
+	       support.  */
+	    tmp = HARD_UDP_LIMIT;
+	context->udp_pref_limit = tmp;
+    }
+
+    retval = (*use_master ? KRB5_KDC_UNREACH : KRB5_REALM_UNKNOWN);
+
+    if (tcp_only)
+	socktype1 = SOCK_STREAM, socktype2 = 0;
+    else if (message->length <= context->udp_pref_limit)
+	socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM;
+    else
+	socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM;
+
+    retval = krb5_locate_kdc(context, realm, &addrs, *use_master, socktype1, 0);
+    if (socktype2) {
+	struct addrlist addrs2;
+
+	retval = krb5_locate_kdc(context, realm, &addrs2, *use_master,
+				 socktype2, 0);
+	if (retval == 0) {
+	    (void) merge_addrlists(&addrs, &addrs2);
+	    krb5int_free_addrlist(&addrs2);
+	}
+    }
+
+    if (addrs.naddrs > 0) {
+        retval = krb5int_sendto (context, message, &addrs, reply, 0, 0,
+                                 &addr_used);
+        if (retval == 0) {
+            /*
+             * Set use_master to 1 if we ended up talking to a master when
+             * we didn't explicitly request to
+             */
+            if (*use_master == 0) {
+                struct addrlist addrs3;
+                retval = krb5_locate_kdc(context, realm, &addrs3, 1, 
+                                         addrs.addrs[addr_used]->ai_socktype,
+                                         addrs.addrs[addr_used]->ai_family);
+                if (retval == 0) {
+                    int i;
+                    for (i = 0; i < addrs3.naddrs; i++) {
+                        if (addrs.addrs[addr_used]->ai_addrlen ==
+                            addrs3.addrs[i]->ai_addrlen &&
+                            memcmp(addrs.addrs[addr_used]->ai_addr,
+                                   addrs3.addrs[i]->ai_addr,
+                                   addrs.addrs[addr_used]->ai_addrlen) == 0) {
+                            *use_master = 1;
+                            break;
+                        }
+                    }
+                    krb5int_free_addrlist (&addrs3);
+                }
+            }
+            krb5int_free_addrlist (&addrs);
+            return 0;
+        }
+        krb5int_free_addrlist (&addrs);
+    }
+    return retval;
+}
+
+#if defined(_WIN32) && defined(DEBUG)
+static char *bogus_strerror (int xerr)
+{
+    static char buf[30];
+    sprintf(buf, "[err%d]", xerr);
+    return buf;
+}
+#define strerror(S) bogus_strerror(S)
+#endif
+
+#ifdef DEBUG
+
+#ifdef _WIN32
+#define dperror(MSG) \
+	 dprint("%s: an error occurred ... "			\
+		"\tline=%d errno=%m socketerrno=%m\n",		\
+		(MSG), __LINE__, errno, SOCKET_ERRNO)
+#else
+#define dperror(MSG) dprint("%s: %m\n", MSG, errno)
+#endif
+#define dfprintf(ARGLIST) (debug ? fprintf ARGLIST : 0)
+
+#else /* ! DEBUG */
+
+#define dperror(MSG) ((void)(MSG))
+#define dfprintf(ARGLIST) ((void)0)
+
+#endif
+
+/*
+ * Notes:
+ *
+ * Getting "connection refused" on a connected UDP socket causes
+ * select to indicate write capability on UNIX, but only shows up
+ * as an exception on Windows.  (I don't think any UNIX system flags
+ * the error as an exception.)  So we check for both, or make it
+ * system-specific.
+ *
+ * Always watch for responses from *any* of the servers.  Eventually
+ * fix the UDP code to do the same.
+ *
+ * To do:
+ * - TCP NOPUSH/CORK socket options?
+ * - error codes that don't suck
+ * - getsockopt(SO_ERROR) to check connect status
+ * - handle error RESPONSE_TOO_BIG from UDP server and use TCP
+ *   connections already in progress
+ */
+
+#include "cm.h"
+
+static const char *const state_strings[] = {
+    "INITIALIZING", "CONNECTING", "WRITING", "READING", "FAILED"
+};
+enum conn_states { INITIALIZING, CONNECTING, WRITING, READING, FAILED };
+struct incoming_krb5_message {
+    size_t bufsizebytes_read;
+    size_t bufsize;
+    char *buf;
+    char *pos;
+    unsigned char bufsizebytes[4];
+    size_t n_left;
+};
+struct conn_state {
+    SOCKET fd;
+    krb5_error_code err;
+    enum conn_states state;
+    unsigned int is_udp : 1;
+    int (*service)(struct conn_state *, struct select_state *, int);
+    struct addrinfo *addr;
+    struct {
+	struct {
+	    sg_buf sgbuf[2];
+	    sg_buf *sgp;
+	    int sg_count;
+	} out;
+	struct incoming_krb5_message in;
+    } x;
+};
+
+static int getcurtime (struct timeval *tvp)
+{
+#ifdef _WIN32
+    struct _timeb tb;
+    _ftime(&tb);
+    tvp->tv_sec = tb.time;
+    tvp->tv_usec = tb.millitm * 1000;
+    /* Can _ftime fail?  */
+    return 0;
+#else
+    if (gettimeofday(tvp, 0)) {
+	dperror("gettimeofday");
+	return errno;
+    }
+    return 0;
+#endif
+}
+
+/*
+ * Call select and return results.
+ * Input: interesting file descriptors and absolute timeout
+ * Output: select return value (-1 or num fds ready) and fd_sets
+ * Return: 0 (for i/o available or timeout) or error code.
+ */
+krb5_error_code
+krb5int_cm_call_select (const struct select_state *in,
+			struct select_state *out, int *sret)
+{
+    struct timeval now, *timo;
+    krb5_error_code e;
+
+    *out = *in;
+    e = getcurtime(&now);
+    if (e)
+	return e;
+    if (out->end_time.tv_sec == 0)
+	timo = 0;
+    else {
+	timo = &out->end_time;
+	out->end_time.tv_sec -= now.tv_sec;
+	out->end_time.tv_usec -= now.tv_usec;
+	if (out->end_time.tv_usec < 0) {
+	    out->end_time.tv_usec += 1000000;
+	    out->end_time.tv_sec--;
+	}
+	if (out->end_time.tv_sec < 0) {
+	    *sret = 0;
+	    return 0;
+	}
+    }
+    dprint("selecting on max=%d sockets [%F] timeout %t\n",
+	   out->max,
+	   &out->rfds, &out->wfds, &out->xfds, out->max,
+	   timo);
+    *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, timo);
+    e = SOCKET_ERRNO;
+
+    dprint("select returns %d", *sret);
+    if (*sret < 0)
+	dprint(", error = %E\n", e);
+    else if (*sret == 0)
+	dprint(" (timeout)\n");
+    else
+	dprint(":%F\n", &out->rfds, &out->wfds, &out->xfds, out->max);
+
+    if (*sret < 0)
+	return e;
+    return 0;
+}
+
+static int service_tcp_fd (struct conn_state *conn,
+			   struct select_state *selstate, int ssflags);
+static int service_udp_fd (struct conn_state *conn,
+			   struct select_state *selstate, int ssflags);
+
+
+static int
+setup_connection (struct conn_state *state, struct addrinfo *ai,
+		  const krb5_data *message, unsigned char *message_len_buf,
+		  char **udpbufp)
+{
+    state->state = INITIALIZING;
+    state->err = 0;
+    state->x.out.sgp = state->x.out.sgbuf;
+    state->addr = ai;
+    state->fd = INVALID_SOCKET;
+    SG_SET(&state->x.out.sgbuf[1], 0, 0);
+    if (ai->ai_socktype == SOCK_STREAM) {
+	SG_SET(&state->x.out.sgbuf[0], message_len_buf, 4);
+	SG_SET(&state->x.out.sgbuf[1], message->data, message->length);
+	state->x.out.sg_count = 2;
+	state->is_udp = 0;
+	state->service = service_tcp_fd;
+    } else {
+	SG_SET(&state->x.out.sgbuf[0], message->data, message->length);
+	SG_SET(&state->x.out.sgbuf[1], 0, 0);
+	state->x.out.sg_count = 1;
+	state->is_udp = 1;
+	state->service = service_udp_fd;
+
+	if (*udpbufp == 0) {
+	    *udpbufp = malloc(krb5_max_dgram_size);
+	    if (*udpbufp == 0) {
+		dperror("malloc(krb5_max_dgram_size)");
+		(void) closesocket(state->fd);
+		state->fd = INVALID_SOCKET;
+		state->state = FAILED;
+		return 1;
+	    }
+	}
+	state->x.in.buf = *udpbufp;
+	state->x.in.bufsize = krb5_max_dgram_size;
+    }
+    return 0;
+}
+
+static int
+start_connection (struct conn_state *state, struct select_state *selstate)
+{
+    int fd, e;
+    struct addrinfo *ai = state->addr;
+
+    dprint("start_connection(@%p)\ngetting %s socket in family %d...", state,
+	   ai->ai_socktype == SOCK_STREAM ? "stream" : "dgram", ai->ai_family);
+    fd = socket(ai->ai_family, ai->ai_socktype, 0);
+    if (fd == INVALID_SOCKET) {
+	state->err = SOCKET_ERRNO;
+	dprint("socket: %m creating with af %d\n", state->err, ai->ai_family);
+	return -1;		/* try other hosts */
+    }
+    /* Make it non-blocking.  */
+    if (ai->ai_socktype == SOCK_STREAM) {
+	static const int one = 1;
+	static const struct linger lopt = { 0, 0 };
+
+	if (ioctlsocket(fd, FIONBIO, (const void *) &one))
+	    dperror("sendto_kdc: ioctl(FIONBIO)");
+	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt)))
+	    dperror("sendto_kdc: setsockopt(SO_LINGER)");
+    }
+
+    /* Start connecting to KDC.  */
+    dprint(" fd %d; connecting to %A...\n", fd, ai);
+    e = connect(fd, ai->ai_addr, ai->ai_addrlen);
+    if (e != 0) {
+	/*
+	 * This is the path that should be followed for non-blocking
+	 * connections.
+	 */
+	if (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EWOULDBLOCK) {
+	    state->state = CONNECTING;
+	} else {
+	    dprint("connect failed: %m\n", SOCKET_ERRNO);
+	    (void) closesocket(fd);
+	    state->err = SOCKET_ERRNO;
+	    state->state = FAILED;
+	    return -2;
+	}
+    } else {
+	/*
+	 * Connect returned zero even though we tried to make it
+	 * non-blocking, which should have caused it to return before
+	 * finishing the connection.  Oh well.  Someone's network
+	 * stack is broken, but if they gave us a connection, use it.
+	 */
+	state->state = WRITING;
+    }
+    dprint("new state = %s\n", state_strings[state->state]);
+
+    state->fd = fd;
+
+    if (ai->ai_socktype == SOCK_DGRAM) {
+	/* Send it now.  */
+	int ret;
+	sg_buf *sg = &state->x.out.sgbuf[0];
+
+	dprint("sending %d bytes on fd %d\n", SG_LEN(sg), state->fd);
+	ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0);
+	if (ret != SG_LEN(sg)) {
+	    dperror("sendto");
+	    (void) closesocket(state->fd);
+	    state->fd = INVALID_SOCKET;
+	    state->state = FAILED;
+	    return -3;
+	} else {
+	    state->state = READING;
+	}
+    }
+#ifdef DEBUG
+    if (debug) {
+	struct sockaddr_storage ss;
+	socklen_t sslen = sizeof(ss);
+	if (getsockname(state->fd, (struct sockaddr *)&ss, &sslen) == 0) {
+	    struct addrinfo hack_ai;
+	    memset(&hack_ai, 0, sizeof(hack_ai));
+	    hack_ai.ai_addr = (struct sockaddr *) &ss;
+	    hack_ai.ai_addrlen = sslen;
+	    hack_ai.ai_socktype = SOCK_DGRAM;
+	    hack_ai.ai_family = ai->ai_family;
+	    dprint("local socket address is %A\n", &hack_ai);
+	}
+    }
+#endif
+    FD_SET(state->fd, &selstate->rfds);
+    if (state->state == CONNECTING || state->state == WRITING)
+	FD_SET(state->fd, &selstate->wfds);
+    FD_SET(state->fd, &selstate->xfds);
+    if (selstate->max <= state->fd)
+	selstate->max = state->fd + 1;
+    selstate->nfds++;
+
+    dprint("new select vectors: %F\n",
+	   &selstate->rfds, &selstate->wfds, &selstate->xfds, selstate->max);
+
+    return 0;
+}
+
+/* Return 0 if we sent something, non-0 otherwise.
+   If 0 is returned, the caller should delay waiting for a response.
+   Otherwise, the caller should immediately move on to process the
+   next connection.  */
+static int
+maybe_send (struct conn_state *conn, struct select_state *selstate)
+{
+    sg_buf *sg;
+
+    dprint("maybe_send(@%p) state=%s type=%s\n", conn,
+	   state_strings[conn->state],
+	   conn->is_udp ? "udp" : "tcp");
+    if (conn->state == INITIALIZING)
+	return start_connection(conn, selstate);
+
+    /* Did we already shut down this channel?  */
+    if (conn->state == FAILED) {
+	dprint("connection already closed\n");
+	return -1;
+    }
+
+    if (conn->addr->ai_socktype == SOCK_STREAM) {
+	dprint("skipping stream socket\n");
+	/* The select callback will handle flushing any data we
+	   haven't written yet, and we only write it once.  */
+	return -1;
+    }
+
+    /* UDP - Send message, possibly for the first time, possibly a
+       retransmit if a previous attempt timed out.  */
+    sg = &conn->x.out.sgbuf[0];
+    dprint("sending %d bytes on fd %d\n", SG_LEN(sg), conn->fd);
+    if (send(conn->fd, SG_BUF(sg), SG_LEN(sg), 0) != SG_LEN(sg)) {
+	dperror("send");
+	/* Keep connection alive, we'll try again next pass.
+
+	   Is this likely to catch any errors we didn't get from the
+	   select callbacks?  */
+	return -1;
+    }
+    /* Yay, it worked.  */
+    return 0;
+}
+
+static void
+kill_conn(struct conn_state *conn, struct select_state *selstate, int err)
+{
+    conn->state = FAILED;
+    shutdown(conn->fd, SHUTDOWN_BOTH);
+    FD_CLR(conn->fd, &selstate->rfds);
+    FD_CLR(conn->fd, &selstate->wfds);
+    FD_CLR(conn->fd, &selstate->xfds);
+    conn->err = err;
+    dprint("abandoning connection %d: %m\n", conn->fd, err);
+    /* Fix up max fd for next select call.  */
+    if (selstate->max == 1 + conn->fd) {
+	while (selstate->max > 0
+	       && ! FD_ISSET(selstate->max-1, &selstate->rfds)
+	       && ! FD_ISSET(selstate->max-1, &selstate->wfds)
+	       && ! FD_ISSET(selstate->max-1, &selstate->xfds))
+	    selstate->max--;
+	dprint("new max_fd + 1 is %d\n", selstate->max);
+    }
+    selstate->nfds--;
+}
+
+/* Check socket for error.  */
+static int
+get_so_error(int fd)
+{
+    int e, sockerr;
+    socklen_t sockerrlen;
+
+    sockerr = 0;
+    sockerrlen = sizeof(sockerr);
+    e = getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerrlen);
+    if (e != 0) {
+	/* What to do now?  */
+	e = SOCKET_ERRNO;
+	dprint("getsockopt(SO_ERROR) on fd failed: %m\n", e);
+	return e;
+    }
+    return sockerr;
+}
+
+/* Return nonzero only if we're finished and the caller should exit
+   its loop.  This happens in two cases: We have a complete message,
+   or the socket has closed and no others are open.  */
+
+static int
+service_tcp_fd (struct conn_state *conn, struct select_state *selstate,
+		int ssflags)
+{
+    krb5_error_code e = 0;
+    int nwritten, nread;
+
+    if (!(ssflags & (SSF_READ|SSF_WRITE|SSF_EXCEPTION)))
+	abort();
+    switch (conn->state) {
+	SOCKET_WRITEV_TEMP tmp;
+
+    case CONNECTING:
+	if (ssflags & SSF_READ) {
+	    /* Bad -- the KDC shouldn't be sending to us first.  */
+	    e = EINVAL /* ?? */;
+	kill_conn:
+	    kill_conn(conn, selstate, e);
+	    if (e == EINVAL) {
+		closesocket(conn->fd);
+		conn->fd = INVALID_SOCKET;
+	    }
+	    return e == 0;
+	}
+	if (ssflags & SSF_EXCEPTION) {
+	handle_exception:
+	    e = get_so_error(conn->fd);
+	    if (e)
+		dprint("socket error on exception fd: %m", e);
+	    else
+		dprint("no socket error info available on exception fd");
+	    goto kill_conn;
+	}
+
+	/*
+	 * Connect finished -- but did it succeed or fail?
+	 * UNIX sets can_write if failed.
+	 * Call getsockopt to see if error pending.
+	 *
+	 * (For most UNIX systems it works to just try writing the
+	 * first time and detect an error.  But Bill Dodd at IBM
+	 * reports that some version of AIX, SIGPIPE can result.)
+	 */
+	e = get_so_error(conn->fd);
+	if (e) {
+	    dprint("socket error on write fd: %m", e);
+	    goto kill_conn;
+	}
+	conn->state = WRITING;
+	goto try_writing;
+
+    case WRITING:
+	if (ssflags & SSF_READ) {
+	    e = E2BIG;
+	    /* Bad -- the KDC shouldn't be sending anything yet.  */
+	    goto kill_conn;
+	}
+	if (ssflags & SSF_EXCEPTION)
+	    goto handle_exception;
+
+    try_writing:
+	dprint("trying to writev %d (%d bytes) to fd %d\n",
+	       conn->x.out.sg_count,
+	       ((conn->x.out.sg_count == 2 ? SG_LEN(&conn->x.out.sgp[1]) : 0)
+		+ SG_LEN(&conn->x.out.sgp[0])),
+	       conn->fd);
+	nwritten = SOCKET_WRITEV(conn->fd, conn->x.out.sgp,
+				 conn->x.out.sg_count, tmp);
+	if (nwritten < 0) {
+	    e = SOCKET_ERRNO;
+	    dprint("failed: %m\n", e);
+	    goto kill_conn;
+	}
+	dprint("wrote %d bytes\n", nwritten);
+	while (nwritten) {
+	    sg_buf *sgp = conn->x.out.sgp;
+	    if (nwritten < SG_LEN(sgp)) {
+		SG_ADVANCE(sgp, nwritten);
+		nwritten = 0;
+	    } else {
+		nwritten -= SG_LEN(conn->x.out.sgp);
+		conn->x.out.sgp++;
+		conn->x.out.sg_count--;
+		if (conn->x.out.sg_count == 0 && nwritten != 0)
+		    /* Wrote more than we wanted to?  */
+		    abort();
+	    }
+	}
+	if (conn->x.out.sg_count == 0) {
+	    /* Done writing, switch to reading.  */
+	    /* Don't call shutdown at this point because
+	     * some implementations cannot deal with half-closed connections.*/
+	    FD_CLR(conn->fd, &selstate->wfds);
+	    /* Q: How do we detect failures to send the remaining data
+	       to the remote side, since we're in non-blocking mode?
+	       Will we always get errors on the reading side?  */
+	    dprint("switching fd %d to READING\n", conn->fd);
+	    conn->state = READING;
+	    conn->x.in.bufsizebytes_read = 0;
+	    conn->x.in.bufsize = 0;
+	    conn->x.in.buf = 0;
+	    conn->x.in.pos = 0;
+	    conn->x.in.n_left = 0;
+	}
+	return 0;
+
+    case READING:
+	if (ssflags & SSF_EXCEPTION) {
+	    if (conn->x.in.buf) {
+		free(conn->x.in.buf);
+		conn->x.in.buf = 0;
+	    }
+	    goto handle_exception;
+	}
+
+	if (conn->x.in.bufsizebytes_read == 4) {
+	    /* Reading data.  */
+	    dprint("reading %d bytes of data from fd %d\n",
+		   (int) conn->x.in.n_left, conn->fd);
+	    nread = SOCKET_READ(conn->fd, conn->x.in.pos, conn->x.in.n_left);
+	    if (nread <= 0) {
+		e = nread ? SOCKET_ERRNO : ECONNRESET;
+		free(conn->x.in.buf);
+		conn->x.in.buf = 0;
+		goto kill_conn;
+	    }
+	    conn->x.in.n_left -= nread;
+	    conn->x.in.pos += nread;
+	    if (conn->x.in.n_left <= 0) {
+		/* We win!  */
+		return 1;
+	    }
+	} else {
+	    /* Reading length.  */
+	    nread = SOCKET_READ(conn->fd,
+				conn->x.in.bufsizebytes + conn->x.in.bufsizebytes_read,
+				4 - conn->x.in.bufsizebytes_read);
+	    if (nread < 0) {
+		e = SOCKET_ERRNO;
+		goto kill_conn;
+	    }
+	    conn->x.in.bufsizebytes_read += nread;
+	    if (conn->x.in.bufsizebytes_read == 4) {
+		unsigned long len;
+		len = conn->x.in.bufsizebytes[0];
+		len = (len << 8) + conn->x.in.bufsizebytes[1];
+		len = (len << 8) + conn->x.in.bufsizebytes[2];
+		len = (len << 8) + conn->x.in.bufsizebytes[3];
+		dprint("received length on fd %d is %d\n", conn->fd, (int)len);
+		/* Arbitrary 1M cap.  */
+		if (len > 1 * 1024 * 1024) {
+		    e = E2BIG;
+		    goto kill_conn;
+		}
+		conn->x.in.bufsize = conn->x.in.n_left = len;
+		conn->x.in.buf = conn->x.in.pos = malloc(len);
+		dprint("allocated %d byte buffer at %p\n", (int) len,
+		       conn->x.in.buf);
+		if (conn->x.in.buf == 0) {
+		    /* allocation failure */
+		    e = errno;
+		    goto kill_conn;
+		}
+	    }
+	}
+	break;
+
+    default:
+	abort();
+    }
+    return 0;
+}
+
+static int
+service_udp_fd(struct conn_state *conn, struct select_state *selstate,
+	       int ssflags)
+{
+    int nread;
+
+    if (!(ssflags & (SSF_READ|SSF_EXCEPTION)))
+	abort();
+    if (conn->state != READING)
+	abort();
+
+    nread = recv(conn->fd, conn->x.in.buf, conn->x.in.bufsize, 0);
+    if (nread < 0) {
+	kill_conn(conn, selstate, SOCKET_ERRNO);
+	return 0;
+    }
+    conn->x.in.pos = conn->x.in.buf + nread;
+    return 1;
+}
+
+static int
+service_fds (struct select_state *selstate,
+	     struct conn_state *conns, size_t n_conns, int *winning_conn,
+	     struct select_state *seltemp)
+{
+    int e, selret;
+
+    e = 0;
+    while (selstate->nfds > 0
+	   && (e = krb5int_cm_call_select(selstate, seltemp, &selret)) == 0) {
+	int i;
+
+	dprint("service_fds examining results, selret=%d\n", selret);
+
+	if (selret == 0)
+	    /* Timeout, return to caller.  */
+	    return 0;
+
+	/* Got something on a socket, process it.  */
+	for (i = 0; i <= selstate->max && selret > 0 && i < n_conns; i++) {
+	    int ssflags;
+
+	    if (conns[i].fd == INVALID_SOCKET)
+		continue;
+	    ssflags = 0;
+	    if (FD_ISSET(conns[i].fd, &seltemp->rfds))
+		ssflags |= SSF_READ, selret--;
+	    if (FD_ISSET(conns[i].fd, &seltemp->wfds))
+		ssflags |= SSF_WRITE, selret--;
+	    if (FD_ISSET(conns[i].fd, &seltemp->xfds))
+		ssflags |= SSF_EXCEPTION, selret--;
+	    if (!ssflags)
+		continue;
+
+	    dprint("handling flags '%s%s%s' on fd %d (%A) in state %s\n",
+		   (ssflags & SSF_READ) ? "r" : "",
+		   (ssflags & SSF_WRITE) ? "w" : "",
+		   (ssflags & SSF_EXCEPTION) ? "x" : "",
+		   conns[i].fd, conns[i].addr,
+		   state_strings[(int) conns[i].state]);
+
+	    if (conns[i].service (&conns[i], selstate, ssflags)) {
+		dprint("fd service routine says we're done\n");
+		*winning_conn = i;
+		return 1;
+	    }
+	}
+    }
+    if (e != 0) {
+	dprint("select returned %m\n", e);
+	*winning_conn = -1;
+	return 1;
+    }
+    return 0;
+}
+
+/*
+ * Current worst-case timeout behavior:
+ *
+ * First pass, 1s per udp or tcp server, plus 2s at end.
+ * Second pass, 1s per udp server, plus 4s.
+ * Third pass, 1s per udp server, plus 8s.
+ * Fourth => 16s, etc.
+ *
+ * Restated:
+ * Per UDP server, 1s per pass.
+ * Per TCP server, 1s.
+ * Backoff delay, 2**(P+1) - 2, where P is total number of passes.
+ *
+ * Total = 2**(P+1) + U*P + T - 2.
+ *
+ * If P=3, Total = 3*U + T + 14.
+ * If P=4, Total = 4*U + T + 30.
+ *
+ * Note that if you try to reach two ports (e.g., both 88 and 750) on
+ * one server, it counts as two.
+ */
+
+krb5_error_code
+krb5int_sendto (krb5_context context, const krb5_data *message,
+                const struct addrlist *addrs, krb5_data *reply,
+                struct sockaddr *localaddr, socklen_t *localaddrlen,
+                int *addr_used)
+{
+    int i, pass;
+    int delay_this_pass = 2;
+    krb5_error_code retval;
+    struct conn_state *conns;
+    size_t n_conns, host;
+    struct select_state *sel_state;
+    struct timeval now;
+    int winning_conn = -1, e = 0;
+    unsigned char message_len_buf[4];
+    char *udpbuf = 0;
+
+    dprint("krb5int_sendto(message=%d@%p)\n", message->length, message->data);
+
+    reply->data = 0;
+    reply->length = 0;
+
+    n_conns = addrs->naddrs;
+    conns = malloc(n_conns * sizeof(struct conn_state));
+    if (conns == NULL) {
+	return ENOMEM;
+    }
+    memset(conns, 0, n_conns * sizeof(conns[i]));
+    for (i = 0; i < n_conns; i++) {
+	conns[i].fd = INVALID_SOCKET;
+    }
+
+    /* One for use here, listing all our fds in use, and one for
+       temporary use in service_fds, for the fds of interest.  */
+    sel_state = malloc(2 * sizeof(*sel_state));
+    if (sel_state == NULL) {
+	free(conns);
+	return ENOMEM;
+    }
+    sel_state->max = 0;
+    sel_state->nfds = 0;
+    sel_state->end_time.tv_sec = sel_state->end_time.tv_usec = 0;
+    FD_ZERO(&sel_state->rfds);
+    FD_ZERO(&sel_state->wfds);
+    FD_ZERO(&sel_state->xfds);
+
+    message_len_buf[0] = (message->length >> 24) & 0xff;
+    message_len_buf[1] = (message->length >> 16) & 0xff;
+    message_len_buf[2] = (message->length >>  8) & 0xff;
+    message_len_buf[3] =  message->length        & 0xff;
+
+    /* Set up connections.  */
+    for (host = 0; host < n_conns; host++) {
+	retval = setup_connection (&conns[host], addrs->addrs[host],
+				   message, message_len_buf, &udpbuf);
+	if (retval)
+	    continue;
+    }
+    for (pass = 0; pass < MAX_PASS; pass++) {
+	/* Possible optimization: Make only one pass if TCP only.
+	   Stop making passes if all UDP ports are closed down.  */
+	dprint("pass %d delay=%d\n", pass, delay_this_pass);
+	for (host = 0; host < n_conns; host++) {
+	    dprint("host %d\n", host);
+
+	    /* Send to the host, wait for a response, then move on. */
+	    if (maybe_send(&conns[host], sel_state))
+		continue;
+
+	    retval = getcurtime(&now);
+	    if (retval)
+		goto egress;
+	    sel_state->end_time = now;
+	    sel_state->end_time.tv_sec += 1;
+	    e = service_fds(sel_state, conns, host+1, &winning_conn,
+			    sel_state+1);
+	    if (e)
+		break;
+	    if (pass > 0 && sel_state->nfds == 0)
+		/*
+		 * After the first pass, if we close all fds, break
+		 * out right away.  During the first pass, it's okay,
+		 * we're probably about to open another connection.
+		 */
+		break;
+	}
+	if (e)
+	    break;
+	retval = getcurtime(&now);
+	if (retval)
+	    goto egress;
+	/* Possible optimization: Find a way to integrate this select
+	   call with the last one from the above loop, if the loop
+	   actually calls select.  */
+	sel_state->end_time.tv_sec += delay_this_pass;
+	e = service_fds(sel_state, conns, host+1, &winning_conn, sel_state+1);
+	if (e)
+	    break;
+	if (sel_state->nfds == 0)
+	    break;
+	delay_this_pass *= 2;
+    }
+
+    if (sel_state->nfds == 0) {
+	/* No addresses?  */
+	retval = KRB5_KDC_UNREACH;
+	goto egress;
+    }
+    if (e == 0 || winning_conn < 0) {
+	retval = KRB5_KDC_UNREACH;
+	goto egress;
+    }
+    /* Success!  */
+    reply->data = conns[winning_conn].x.in.buf;
+    reply->length = (conns[winning_conn].x.in.pos
+		     - conns[winning_conn].x.in.buf);
+    dprint("returning %d bytes in buffer %p\n",
+	   (int) reply->length, reply->data);
+    retval = 0;
+    conns[winning_conn].x.in.buf = 0;
+    if (addr_used)
+        *addr_used = winning_conn;
+    if (localaddr != 0 && localaddrlen != 0 && *localaddrlen > 0)
+	(void) getsockname(conns[winning_conn].fd, localaddr, localaddrlen);
+egress:
+    for (i = 0; i < n_conns; i++) {
+	if (conns[i].fd != INVALID_SOCKET)
+	    closesocket(conns[i].fd);
+	if (conns[i].state == READING
+	    && conns[i].x.in.buf != 0
+	    && conns[i].x.in.buf != udpbuf)
+	    free(conns[i].x.in.buf);
+    }
+    free(conns);
+    if (reply->data != udpbuf)
+	free(udpbuf);
+    free(sel_state);
+    return retval;
+}
diff --git a/mechglue/src/lib/krb5/os/sn2princ.c b/mechglue/src/lib/krb5/os/sn2princ.c
new file mode 100644
index 000000000..65678c829
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/sn2princ.c
@@ -0,0 +1,191 @@
+/*
+ * lib/krb5/os/sn2princ.c
+ *
+ * Copyright 1991,2002 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Convert a hostname and service name to a principal in the "standard"
+ * form.
+ */
+
+#include "k5-int.h"
+#include "fake-addrinfo.h"
+#include <ctype.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if !defined(DEFAULT_RDNS_LOOKUP)
+#define DEFAULT_RDNS_LOOKUP 1
+#endif
+
+static int
+maybe_use_reverse_dns (krb5_context context, int defalt)
+{
+    krb5_error_code code;
+    char * value = NULL;
+    int use_rdns = 0;
+
+    code = profile_get_string(context->profile, "libdefaults",
+                              "rdns", 0, 0, &value);
+    if (code)
+        return defalt;
+
+    if (value == 0)
+	return defalt;
+
+    use_rdns = _krb5_conf_boolean(value);
+    profile_release_string(value);
+    return use_rdns;
+}
+
+
+krb5_error_code KRB5_CALLCONV
+krb5_sname_to_principal(krb5_context context, const char *hostname, const char *sname, krb5_int32 type, krb5_principal *ret_princ)
+{
+    char **hrealms, *realm, *remote_host;
+    krb5_error_code retval;
+    register char *cp;
+    char localname[MAXHOSTNAMELEN];
+
+
+    if ((type == KRB5_NT_UNKNOWN) ||
+	(type == KRB5_NT_SRV_HST)) {
+
+	/* if hostname is NULL, use local hostname */
+	if (! hostname) {
+	    if (gethostname(localname, MAXHOSTNAMELEN))
+		return SOCKET_ERRNO;
+	    hostname = localname;
+	}
+
+	/* if sname is NULL, use "host" */
+	if (! sname)
+	    sname = "host";
+
+	/* copy the hostname into non-volatile storage */
+
+	if (type == KRB5_NT_SRV_HST) {
+	    struct addrinfo *ai, hints;
+	    int err;
+	    char hnamebuf[NI_MAXHOST];
+
+	    /* Note that the old code would accept numeric addresses,
+	       and if the gethostbyaddr step could convert them to
+	       real hostnames, you could actually get reasonable
+	       results.  If the mapping failed, you'd get dotted
+	       triples as realm names.  *sigh*
+
+	       The latter has been fixed in hst_realm.c, but we should
+	       keep supporting numeric addresses if they do have
+	       hostnames associated.  */
+
+	    memset(&hints, 0, sizeof(hints));
+	    hints.ai_family = AF_INET;
+	try_getaddrinfo_again:
+	    err = getaddrinfo(hostname, 0, &hints, &ai);
+	    if (err) {
+		if (hints.ai_family == AF_INET) {
+		    /* Just in case it's an IPv6-only name.  */
+		    hints.ai_family = 0;
+		    goto try_getaddrinfo_again;
+		}
+		return KRB5_ERR_BAD_HOSTNAME;
+	    }
+	    remote_host = strdup(ai->ai_canonname ? ai->ai_canonname : hostname);
+	    if (!remote_host) {
+		freeaddrinfo(ai);
+		return ENOMEM;
+	    }
+
+            if (maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) {
+                /*
+                 * Do a reverse resolution to get the full name, just in
+                 * case there's some funny business going on.  If there
+                 * isn't an in-addr record, give up.
+                 */
+                /* XXX: This is *so* bogus.  There are several cases where
+                   this won't get us the canonical name of the host, but
+                   this is what we've trained people to expect.  We'll
+                   probably fix it at some point, but let's try to
+                   preserve the current behavior and only shake things up
+                   once when it comes time to fix this lossage.  */
+                err = getnameinfo(ai->ai_addr, ai->ai_addrlen,
+                                   hnamebuf, sizeof(hnamebuf), 0, 0, NI_NAMEREQD);
+                freeaddrinfo(ai);
+                if (err == 0) {
+                    free(remote_host);
+                    remote_host = strdup(hnamebuf);
+                    if (!remote_host)
+                        return ENOMEM;
+                }
+            }
+	} else /* type == KRB5_NT_UNKNOWN */ {
+	    remote_host = strdup(hostname);
+	}
+	if (!remote_host)
+	    return ENOMEM;
+
+	if (type == KRB5_NT_SRV_HST)
+	    for (cp = remote_host; *cp; cp++)
+		if (isupper((int) (*cp)))
+		    *cp = tolower((int) (*cp));
+
+	/*
+	 * Windows NT5's broken resolver gratuitously tacks on a
+	 * trailing period to the hostname (at least it does in
+	 * Beta2).  Find and remove it.
+	 */
+	if (remote_host[0]) {
+		cp = remote_host + strlen(remote_host)-1;
+		if (*cp == '.')
+			*cp = 0;
+	}
+	
+
+	if ((retval = krb5_get_host_realm(context, remote_host, &hrealms))) {
+	    free(remote_host);
+	    return retval;
+	}
+	if (!hrealms[0]) {
+	    free(remote_host);
+	    krb5_xfree(hrealms);
+	    return KRB5_ERR_HOST_REALM_UNKNOWN;
+	}
+	realm = hrealms[0];
+
+	retval = krb5_build_principal(context, ret_princ, strlen(realm),
+				      realm, sname, remote_host,
+				      (char *)0);
+
+	krb5_princ_type(context, *ret_princ) = type;
+
+	free(remote_host);
+
+	krb5_free_host_realm(context, hrealms);
+	return retval;
+    } else {
+	return KRB5_SNAME_UNSUPP_NAMETYPE;
+    }
+}
+
diff --git a/mechglue/src/lib/krb5/os/t_an_to_ln.c b/mechglue/src/lib/krb5/os/t_an_to_ln.c
new file mode 100644
index 000000000..93933a477
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/t_an_to_ln.c
@@ -0,0 +1,41 @@
+#include "krb5.h"
+
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+    krb5_error_code	kret;
+    krb5_context	kcontext;
+    krb5_principal	principal;
+    char		*programname;
+    int			i;
+    char		sbuf[1024];
+
+    programname = argv[0];
+    krb5_init_context(&kcontext);
+    for (i=1; i < argc; i++) {
+	if (!(kret = krb5_parse_name(kcontext, argv[i], &principal))) {
+	    if (!(kret = krb5_aname_to_localname(kcontext,
+						 principal,
+						 1024,
+						 sbuf))) {
+		printf("%s: aname_to_lname maps %s -> <%s>\n",
+		       programname, argv[i], sbuf);
+	    }
+	    else {
+		printf("%s: aname to lname returns %s for %s\n", programname,
+		       error_message(kret), argv[i]);
+	    }
+	    krb5_free_principal(kcontext, principal);
+	}
+	else {
+	    printf("%s: parse_name returns %s\n", programname,
+		   error_message(kret));
+	}
+	if (kret)
+	    break;
+    }
+    krb5_free_context(kcontext);
+    return((kret) ? 1 : 0);
+}
diff --git a/mechglue/src/lib/krb5/os/t_gifconf.c b/mechglue/src/lib/krb5/os/t_gifconf.c
new file mode 100644
index 000000000..92a49123a
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/t_gifconf.c
@@ -0,0 +1,134 @@
+/* SIOCGIFCONF:
+
+   The behavior of this ioctl varies across systems.
+
+   The "largest gap" values are the largest number of bytes I've seen
+   left unused at the end of the supplied buffer when there were more
+   entries to return.  These values may of coures be dependent on the
+   configurations of the particular systems I was testing with.
+
+   NetBSD 1.5-alpha: The returned ifc_len is the desired amount of
+   space, always.  The returned list may be truncated if there isn't
+   enough room; no overrun.  Largest gap: 43.  (NetBSD now has
+   getifaddrs.)
+
+   BSD/OS 4.0.1 (courtesy djm): The returned ifc_len is equal to or
+   less than the supplied ifc_len.  Sometimes the entire buffer is
+   used; sometimes N-1 bytes; occasionally, the buffer must have quite
+   a bit of extra room before the next structure will be added.
+   Largest gap: 39.
+
+   Solaris 7,8: Return EINVAL if the buffer space is too small for all
+   the data to be returned, including ifc_len==0.  Solaris is the only
+   system I've found so far that actually returns an error.  No gap.
+   However, SIOCGIFNUM may be used to query the number of interfaces.
+
+   Linux 2.2.12 (RH 6.1 dist, x86): The buffer is filled in with as
+   many entries as will fit, and the size used is returned in ifc_len.
+   The list is truncated if needed, with no indication.  Largest gap: 31.
+
+   IRIX 6.5: The buffer is filled in with as many entries as will fit
+   in N-1 bytes, and the size used is returned in ifc_len.  Providing
+   exactly the desired number of bytes is inadequate; the buffer must
+   be *bigger* than needed.  (E.g., 32->0, 33->32.)  The returned
+   ifc_len is always less than the supplied one.  Largest gap: 32.
+
+   AIX 4.3.3: Sometimes the returned ifc_len is bigger than the
+   supplied one, but it may not be big enough for *all* the
+   interfaces.  Sometimes it's smaller than the supplied value, even
+   if the returned list is truncated.  The list is filled in with as
+   many entries as will fit; no overrun.  Largest gap: 143.
+
+   Older AIX: We're told by W. David Shambroom <DShambroom@gte.com> in
+   PR krb5-kdc/919 that older versions of AIX have a bug in the
+   SIOCGIFCONF ioctl which can cause them to overrun the supplied
+   buffer.  However, we don't yet have details as to which version,
+   whether the overrun amount was bounded (e.g., one ifreq's worth) or
+   not, whether it's a real buffer overrun or someone assuming it was
+   because ifc_len was increased, etc.  Once we've got details, we can
+   try to work around the problem.
+
+   Digital UNIX 4.0F: If input ifc_len is zero, return an ifc_len
+   that's big enough to include all entries.  (Actually, on our
+   system, it appears to be larger than that by 32.)  If input ifc_len
+   is nonzero, fill in as many entries as will fit, and set ifc_len
+   accordingly.  (Tested only with INIT of zero.)
+
+   So... if the returned ifc_len is bigger than the supplied one,
+   we'll need at least that much space -- but possibly more -- to hold
+   all the results.  If the returned value is smaller or the same, we
+   may still need more space.
+
+   Using this ioctl is going to be messy.  Let's just hope that
+   getifaddrs() catches on quickly....  */
+
+#include <errno.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#if (defined(sun) || defined(__sun__)) && !defined(SIOCGIFCONF)
+/* Sun puts socket ioctls in another file.  */
+#include <sys/sockio.h>
+#endif
+
+#define INIT 0xc3
+
+int main (void) {
+    char buffer[2048];
+    int i, sock, t, olen = -9, omod = -9;
+    struct ifconf ifc;
+    int gap = -1, lastgap = -1;
+
+    sock = socket (AF_INET, SOCK_DGRAM, 0);
+    if (sock < 0) {
+	perror ("socket");
+	exit (1);
+    }
+    printf ("sizeof(struct if_req)=%d\n", sizeof (struct ifreq));
+    for (t = 0; t < sizeof (buffer); t++) {
+	ifc.ifc_len = t;
+	ifc.ifc_buf = buffer;
+	memset (buffer, INIT, sizeof (buffer));
+	i = ioctl (sock, SIOCGIFCONF, (char *) &ifc);
+	if (i < 0) {
+	    /* Solaris returns "Invalid argument" if the buffer is too
+	       small.  AIX and Linux return no error indication.  */
+	    int e = errno;
+	    sprintf (buffer, "SIOCGIFCONF(%d)", t);
+	    errno = e;
+	    perror (buffer);
+	    if (e == EINVAL)
+		continue;
+	    fprintf (stderr, "exiting on unexpected error\n");
+	    exit (1);
+	}
+	i = sizeof (buffer) - 1;
+	while (buffer[i] == ((char)INIT) && i >= 0)
+	    i--;
+	if (omod != i) {
+	    /* Okay... the gap computed on the *last* iteration is the
+	       largest for that particular size of returned data.
+	       Save it, and then start computing gaps for the next
+	       bigger size of returned data.  If we never get anything
+	       bigger back, we discard the newer value and only keep
+	       LASTGAP because all we care about is how much slop we
+	       need to "prove" that there really weren't any more
+	       entries to be returned.  */
+	    if (gap > lastgap)
+		lastgap = gap;
+	}
+	gap = t - i - 1;
+	if (olen != ifc.ifc_len || omod != i) {
+	    printf ("ifc_len in = %4d, ifc_len out = %4d, last mod = %4d\n",
+		    t, ifc.ifc_len, i);
+	    olen = ifc.ifc_len;
+	    omod = i;
+	}
+    }
+    printf ("finished at ifc_len %d\n", t);
+    printf ("largest gap = %d\n", lastgap);
+    exit (0);
+}
diff --git a/mechglue/src/lib/krb5/os/t_locate_kdc.c b/mechglue/src/lib/krb5/os/t_locate_kdc.c
new file mode 100644
index 000000000..7d5d554fa
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/t_locate_kdc.c
@@ -0,0 +1,129 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "port-sockets.h"
+#include <com_err.h>
+
+#define TEST
+#include "locate_kdc.c"
+
+enum {
+    LOOKUP_CONF = 3,
+    LOOKUP_DNS,
+    LOOKUP_WHATEVER
+} how = LOOKUP_WHATEVER;
+
+const char *prog;
+
+struct addrlist al;
+
+void kfatal (krb5_error_code err)
+{
+    com_err (prog, err, "- exiting");
+    exit (1);
+}
+
+const char *stypename (int stype)
+{
+    static char buf[20];
+    switch (stype) {
+    case SOCK_STREAM:
+	return "stream";
+    case SOCK_DGRAM:
+	return "dgram";
+    case SOCK_RAW:
+	return "raw";
+    default:
+	sprintf(buf, "?%d", stype);
+	return buf;
+    }
+}
+
+void print_addrs (void)
+{
+    int i;
+
+    struct addrinfo **addrs = al.addrs;
+    int naddrs = al.naddrs;
+
+    printf ("%d addresses:\n", naddrs);
+    for (i = 0; i < naddrs; i++) {
+	int err;
+	char hostbuf[NI_MAXHOST], srvbuf[NI_MAXSERV];
+	err = getnameinfo (addrs[i]->ai_addr, addrs[i]->ai_addrlen,
+			   hostbuf, sizeof (hostbuf),
+			   srvbuf, sizeof (srvbuf),
+			   NI_NUMERICHOST | NI_NUMERICSERV);
+	if (err)
+	    printf ("%2d: getnameinfo returns error %d=%s\n",
+		    i, err, gai_strerror (err));
+	else
+	    printf ("%2d: address %s\t%s\tport %s\n", i, hostbuf,
+		    stypename (addrs[i]->ai_socktype), srvbuf);
+    }
+}
+
+int main (int argc, char *argv[])
+{
+    char *p, *realmname;
+    krb5_data realm;
+    krb5_context ctx;
+    krb5_error_code err;
+    int master = 0;
+
+    p = strrchr (argv[0], '/');
+    if (p)
+	prog = p+1;
+    else
+	prog = argv[0];
+
+    switch (argc) {
+    case 2:
+	/* foo $realm */
+	realmname = argv[1];
+	break;
+    case 3:
+	if (!strcmp (argv[1], "-c"))
+	    how = LOOKUP_CONF;
+	else if (!strcmp (argv[1], "-d"))
+	    how = LOOKUP_DNS;
+	else if (!strcmp (argv[1], "-m"))
+	    master = 1;
+	else
+	    goto usage;
+	realmname = argv[2];
+	break;
+    default:
+    usage:
+	fprintf (stderr, "%s: usage: %s [-c | -d | -m] realm\n", prog, prog);
+	return 1;
+    }
+
+    err = krb5_init_context (&ctx);
+    if (err)
+	kfatal (err);
+
+    realm.data = realmname;
+    realm.length = strlen (realmname);
+
+    switch (how) {
+    case LOOKUP_CONF:
+	err = krb5_locate_srv_conf (ctx, &realm, "kdc", &al, 0,
+				    htons (88), htons (750));
+	break;
+
+    case LOOKUP_DNS:
+	err = krb5_locate_srv_dns_1 (&realm, "_kerberos", "_udp", &al, 0);
+	break;
+
+    case LOOKUP_WHATEVER:
+	err = krb5_locate_kdc (ctx, &realm, &al, master, 0, 0);
+	break;
+    }
+    if (err) kfatal (err);
+    print_addrs ();
+
+    krb5int_free_addrlist (&al);
+    krb5_free_context (ctx);
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/os/t_realm_iter.c b/mechglue/src/lib/krb5/os/t_realm_iter.c
new file mode 100644
index 000000000..b39693594
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/t_realm_iter.c
@@ -0,0 +1,44 @@
+#include "krb5.h"
+
+#include <stdio.h>
+
+void test_realm_iterator(int ctx)
+{
+    krb5_error_code retval;
+    char *realm;
+    void *iter;
+
+    if ((retval = krb5_realm_iterator_create(ctx, &iter))) {
+	com_err("krb5_realm_iterator_create", retval, 0);
+	return;
+    }
+    while (iter) {
+	if ((retval = krb5_realm_iterator(ctx, &iter, &realm))) {
+	    com_err("krb5_realm_iterator", retval, 0);
+	    krb5_realm_iterator_free(ctx, &iter);
+	    return;
+	}
+	if (realm) {
+	    printf("Realm: '%s'\n", realm);
+	    krb5_free_realm_string(ctx, realm);
+	}
+    }
+}
+
+int main(int argc, char **argv)
+{
+    krb5_context ctx;
+    krb5_error_code retval;
+
+    retval = krb5_init_context(&ctx);
+    if (retval) {
+	fprintf(stderr, "krb5_init_context returned error %ld\n",
+		retval);
+	exit(1);
+    }
+
+    test_realm_iterator(ctx);
+
+    krb5_free_context(ctx);
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/os/t_std_conf.c b/mechglue/src/lib/krb5/os/t_std_conf.c
new file mode 100644
index 000000000..adaf6893d
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/t_std_conf.c
@@ -0,0 +1,247 @@
+/*
+ * t_std_conf.c --- This program tests standard Krb5 routines which pull 
+ * 	values from the krb5 config file(s).
+ */
+
+#include "fake-addrinfo.h"
+#include "k5-int.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "os-proto.h"
+
+static void test_get_default_realm(krb5_context ctx)
+{
+	char	*realm;
+	krb5_error_code	retval;
+	
+	retval = krb5_get_default_realm(ctx, &realm);
+	if (retval) {
+		com_err("krb5_get_default_realm", retval, 0);
+		return;
+	}
+	printf("krb5_get_default_realm() returned '%s'\n", realm);
+	free(realm);
+}
+
+static void test_set_default_realm(krb5_context ctx, char *realm)
+{
+	krb5_error_code	retval;
+	
+	retval = krb5_set_default_realm(ctx, realm);
+	if (retval) {
+		com_err("krb5_set_default_realm", retval, 0);
+		return;
+	}
+	printf("krb5_set_default_realm(%s)\n", realm);
+}
+
+static void test_get_default_ccname(krb5_context ctx)
+{
+	const char	*ccname;
+
+	ccname = krb5_cc_default_name(ctx);
+	if (ccname)
+		printf("krb5_cc_default_name() returned '%s'\n", ccname);
+	else
+		printf("krb5_cc_default_name() returned NULL\n");
+}
+
+static void test_set_default_ccname(krb5_context ctx, char *ccname)
+{
+	krb5_error_code	retval;
+	
+	retval = krb5_cc_set_default_name(ctx, ccname);
+	if (retval) {
+		com_err("krb5_set_default_ccname", retval, 0);
+		return;
+	}
+	printf("krb5_set_default_ccname(%s)\n", ccname);
+}
+
+static void test_get_krbhst(krb5_context ctx, char *realm)
+{
+	char **hostlist, **cpp;
+	krb5_data rlm;
+	krb5_error_code	retval;
+
+	rlm.data = realm;
+	rlm.length = strlen(realm);
+	retval = krb5_get_krbhst(ctx, &rlm, &hostlist);
+	if (retval) {
+		com_err("krb5_get_krbhst", retval, 0);
+		return;
+	}
+	printf("krb_get_krbhst(%s) returned:", realm);
+	if (hostlist == 0) {
+		printf(" (null)\n");
+		return;
+	}
+	if (hostlist[0] == 0) {
+		printf(" (none)\n");
+		krb5_free_krbhst(ctx, hostlist);
+		return;
+	}
+	for (cpp = hostlist; *cpp; cpp++) {
+		printf(" '%s'", *cpp);
+	}
+	krb5_free_krbhst(ctx, hostlist);
+	printf("\n");
+}
+
+static void test_locate_kdc(krb5_context ctx, char *realm)
+{
+    	struct addrlist addrs;
+	int	i;
+	int	get_masters=0;
+	krb5_data rlm;
+	krb5_error_code	retval;
+
+	rlm.data = realm;
+	rlm.length = strlen(realm);
+	retval = krb5_locate_kdc(ctx, &rlm, &addrs, get_masters, 0, 0);
+	if (retval) {
+		com_err("krb5_locate_kdc", retval, 0);
+		return;
+	}
+	printf("krb_locate_kdc(%s) returned:", realm);
+	for (i=0; i < addrs.naddrs; i++) {
+	    struct addrinfo *ai = addrs.addrs[i];
+	    switch (ai->ai_family) {
+	    case AF_INET:
+	    {
+		struct sockaddr_in *s_sin;
+		s_sin = (struct sockaddr_in *) ai->ai_addr;
+		printf(" inet:%s/%d", inet_ntoa(s_sin->sin_addr), 
+		       ntohs(s_sin->sin_port));
+	    }
+	    break;
+#ifdef KRB5_USE_INET6
+	    case AF_INET6:
+	    {
+		struct sockaddr_in6 *s_sin6;
+		int j;
+		s_sin6 = (struct sockaddr_in6 *) ai->ai_addr;
+		printf(" inet6");
+		for (j = 0; j < 8; j++)
+		    printf(":%x",
+			   (s_sin6->sin6_addr.s6_addr[2*j] * 256
+			    + s_sin6->sin6_addr.s6_addr[2*j+1]));
+		printf("/%d", ntohs(s_sin6->sin6_port));
+		break;
+	    }
+#endif
+	    default:
+		printf(" unknown-af-%d", ai->ai_family);
+		break;
+	    }
+	}
+	krb5int_free_addrlist(&addrs);
+	printf("\n");
+}
+
+static void test_get_host_realm(krb5_context ctx, char *host)
+{
+	char **realms, **cpp;
+	krb5_error_code retval;
+
+	retval = krb5_get_host_realm(ctx, host, &realms);
+	if (retval) {
+		com_err("krb5_get_host_realm", retval, 0);
+		return;
+	}
+	printf("krb_get_host_realm(%s) returned:", host);
+	if (realms == 0) {
+		printf(" (null)\n");
+		return;
+	}
+	if (realms[0] == 0) {
+		printf(" (none)\n");
+		free(realms);
+		return;
+	}
+	for (cpp = realms; *cpp; cpp++) {
+		printf(" '%s'", *cpp);
+		free(*cpp);
+	}
+	free(realms);
+	printf("\n");
+}
+
+static void test_get_realm_domain(krb5_context ctx, char *realm)
+{
+	krb5_error_code	retval;
+	char	*domain;
+	
+	retval = krb5_get_realm_domain(ctx, realm, &domain);
+	if (retval) {
+		com_err("krb5_get_realm_domain", retval, 0);
+		return;
+	}
+	printf("krb5_get_realm_domain(%s) returned '%s'\n", realm, domain);
+	free(domain);
+}
+
+static void usage(char *progname)
+{
+	fprintf(stderr, "%s: Usage: %s [-dc] [-k realm] [-r host] [-C ccname] [-D realm]\n",
+		progname, progname);
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	int	c;
+	krb5_context	ctx;
+	krb5_error_code	retval;
+	extern char *optarg;
+
+	retval = krb5_init_context(&ctx);
+	if (retval) {
+		fprintf(stderr, "krb5_init_context returned error %u\n",
+			retval);
+		exit(1);
+	}
+
+	while ((c = getopt(argc, argv, "cdk:r:C:D:l:s:")) != -1) {
+	    switch (c) {
+	    case 'c':		/* Get default ccname */
+		test_get_default_ccname(ctx);
+		break;
+	    case 'd': /* Get default realm */
+		test_get_default_realm(ctx);
+		break;
+	    case 'k': /* Get list of KDC's */
+		test_get_krbhst(ctx, optarg);
+		break;
+	    case 'l':
+		test_locate_kdc(ctx, optarg);
+		break;
+	    case 'r':
+		test_get_host_realm(ctx, optarg);
+		break;
+	    case 's':
+		test_set_default_realm(ctx, optarg);
+		break;
+	    case 'C':
+		test_set_default_ccname(ctx, optarg);
+		break;
+	    case 'D':
+		test_get_realm_domain(ctx, optarg);
+		break;
+	    default:
+		usage(argv[0]);
+	    }
+	}
+
+
+	krb5_free_context(ctx);
+	exit(0);
+}
diff --git a/mechglue/src/lib/krb5/os/td_krb5.conf b/mechglue/src/lib/krb5/os/td_krb5.conf
new file mode 100644
index 000000000..cdee60945
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/td_krb5.conf
@@ -0,0 +1,19 @@
+[libdefaults]
+	default_realm = DEFAULT.REALM.TST
+
+[realms]
+	DEFAULT_REALM.TST = {
+		kdc = FIRST.KDC.HOST:750
+		kdc = SECOND.KDC.HOST:88
+		admin_server = FIRST.KDC.HOST
+		default_domain = MIT.EDU
+	}
+	IGGY.ORG = {
+		kdc = KERBEROS.IGGY.ORG
+		kdc = KERBEROS-B.IGGY.ORG
+	}
+
+[domain_realm]
+	bad.idea = US.GOV
+	.bad.idea = NSA.GOV
+	clipper.bad.idea = NIST.GOV
diff --git a/mechglue/src/lib/krb5/os/thread_safe.c b/mechglue/src/lib/krb5/os/thread_safe.c
new file mode 100644
index 000000000..faac234f9
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/thread_safe.c
@@ -0,0 +1,40 @@
+/*
+ * lib/krb5/os/thread_safec
+ *
+ * Copyright 2005 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * krb5_is_thread_safe() function.
+ */
+
+#include "k5-int.h"
+
+krb5_boolean KRB5_CALLCONV
+krb5_is_thread_safe(void)
+{
+#if defined(ENABLE_THREADS)
+    return 1;
+#else
+    return 0;
+#endif
+}
diff --git a/mechglue/src/lib/krb5/os/timeofday.c b/mechglue/src/lib/krb5/os/timeofday.c
new file mode 100644
index 000000000..dcc75f566
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/timeofday.c
@@ -0,0 +1,52 @@
+/*
+ * lib/krb5/os/timeofday.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * libos: krb5_timeofday function for BSD 4.3 
+ */
+
+
+#include "k5-int.h"
+
+#include <time.h>
+
+krb5_error_code KRB5_CALLCONV
+krb5_timeofday(krb5_context context, register krb5_timestamp *timeret)
+{
+    krb5_os_context os_ctx = context->os_context;
+    time_t tval;
+
+    if (os_ctx->os_flags & KRB5_OS_TOFFSET_TIME) {
+	    *timeret = os_ctx->time_offset;
+	    return 0;
+    }
+    tval = time(0);
+    if (tval == (time_t) -1)
+	return (krb5_error_code) errno;
+    if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)
+	    tval += os_ctx->time_offset;
+    *timeret = tval;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/os/toffset.c b/mechglue/src/lib/krb5/os/toffset.c
new file mode 100644
index 000000000..967b9d62b
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/toffset.c
@@ -0,0 +1,115 @@
+/*
+ * lib/krb5/os/toffset.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * These routines manipulates the time offset fields in the os context.
+ */
+
+#include "k5-int.h"
+
+/*
+ * This routine takes the "real time" as input, and sets the time
+ * offset field in the context structure so that the krb5 time
+ * routines will return the correct time as corrected by difference
+ * between the system time and the "real time" as passed to this
+ * routine
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_set_real_time(krb5_context context, krb5_timestamp seconds, krb5_int32 microseconds)
+{
+    krb5_os_context os_ctx = context->os_context;
+    krb5_int32 sec, usec;
+    krb5_error_code retval;
+
+    retval = krb5_crypto_us_timeofday(&sec, &usec);
+    if (retval)
+	    return retval;
+    os_ctx->time_offset = seconds - sec;
+    os_ctx->usec_offset = microseconds - usec;
+    os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
+			KRB5_OS_TOFFSET_VALID);
+    return 0;
+}
+
+/*
+ * This routine sets the krb5 time routines so that they will return
+ * the seconds and microseconds value as input to this function.  This
+ * is useful for running the krb5 routines through test suites
+ */
+krb5_error_code 
+krb5_set_debugging_time(krb5_context context, krb5_timestamp seconds, krb5_int32 microseconds)
+{
+    krb5_os_context os_ctx = context->os_context;
+
+    os_ctx->time_offset = seconds;
+    os_ctx->usec_offset = microseconds;
+    os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_VALID) |
+			KRB5_OS_TOFFSET_TIME);
+    return 0;
+}
+
+/*
+ * This routine turns off the time correction fields, so that the krb5
+ * routines return the "natural" time.
+ */
+krb5_error_code 
+krb5_use_natural_time(krb5_context context)
+{
+    krb5_os_context os_ctx = context->os_context;
+
+    os_ctx->os_flags &= ~(KRB5_OS_TOFFSET_VALID|KRB5_OS_TOFFSET_TIME);
+
+    return 0;
+}
+
+/*
+ * This routine returns the current time offsets in use.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_get_time_offsets(krb5_context context, krb5_timestamp *seconds, krb5_int32 *microseconds)
+{
+    krb5_os_context os_ctx = context->os_context;
+
+    if (seconds)
+	*seconds = os_ctx->time_offset;
+    if (microseconds)
+	*microseconds = os_ctx->usec_offset;
+    return 0;
+}
+
+
+/*
+ * This routine sets the time offsets directly.
+ */
+krb5_error_code 
+krb5_set_time_offsets(krb5_context context, krb5_timestamp seconds, krb5_int32 microseconds)
+{
+    krb5_os_context os_ctx = context->os_context;
+
+    os_ctx->time_offset = seconds;
+    os_ctx->usec_offset = microseconds;
+    os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
+			KRB5_OS_TOFFSET_VALID);
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/os/unlck_file.c b/mechglue/src/lib/krb5/os/unlck_file.c
new file mode 100644
index 000000000..0bbf7ce31
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/unlck_file.c
@@ -0,0 +1,37 @@
+/*
+ * lib/krb5/os/unlck_file.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * libos: krb5_lock_file routine
+ */
+
+#include "k5-int.h"
+#include <stdio.h>
+
+krb5_error_code
+krb5_unlock_file(krb5_context context, int fd)
+{
+    return krb5_lock_file(context, fd, KRB5_LOCKMODE_UNLOCK);
+}
diff --git a/mechglue/src/lib/krb5/os/ustime.c b/mechglue/src/lib/krb5/os/ustime.c
new file mode 100644
index 000000000..ef923d387
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/ustime.c
@@ -0,0 +1,66 @@
+/*
+ * lib/krb5/os/ustime.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * krb5_crypto_us_timeofday() does all of the real work; however, we
+ * handle the time offset adjustment here, since this is context
+ * specific, and the crypto version of this call doesn't have access
+ * to the context variable.  Fortunately the only user of
+ * krb5_crypto_us_timeofday in the crypto library doesn't require that
+ * this time adjustment be done.
+ */
+
+#include "k5-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_us_timeofday(krb5_context context, krb5_timestamp *seconds, krb5_int32 *microseconds)
+{
+    krb5_os_context os_ctx = context->os_context;
+    krb5_int32 sec, usec;
+    krb5_error_code retval;
+    
+    if (os_ctx->os_flags & KRB5_OS_TOFFSET_TIME) {
+	    *seconds = os_ctx->time_offset;
+	    *microseconds = os_ctx->usec_offset;
+	    return 0;
+    }
+    retval = krb5_crypto_us_timeofday(&sec, &usec);
+    if (retval)
+	    return retval;
+    if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
+	    usec += os_ctx->usec_offset;
+	    if (usec > 1000000) {
+		    usec -= 1000000;
+		    sec++;
+	    }
+	    if (usec < 0) {
+		usec += 1000000;
+		sec--;
+	    }
+	    sec += os_ctx->time_offset;
+    }
+    *seconds = sec;
+    *microseconds = usec;
+    return 0;
+}
diff --git a/mechglue/src/lib/krb5/os/write_msg.c b/mechglue/src/lib/krb5/os/write_msg.c
new file mode 100644
index 000000000..d75a32796
--- /dev/null
+++ b/mechglue/src/lib/krb5/os/write_msg.c
@@ -0,0 +1,47 @@
+/*
+ * lib/krb5/os/write_msg.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * convenience sendauth/recvauth functions
+ */
+
+#include "k5-int.h"
+#include <errno.h>
+
+krb5_error_code
+krb5_write_message(krb5_context context, krb5_pointer fdp, krb5_data *outbuf)
+{
+	krb5_int32	len;
+	int		fd = *( (int *) fdp);
+
+	len = htonl(outbuf->length);
+	if (krb5_net_write(context, fd, (char *)&len, 4) < 0) {
+		return(errno);
+	}
+	if (outbuf->length && (krb5_net_write(context, fd, outbuf->data, outbuf->length) < 0)) {
+		return(errno);
+	}
+	return(0);
+}
diff --git a/mechglue/src/lib/krb5/posix/.Sanitize b/mechglue/src/lib/krb5/posix/.Sanitize
new file mode 100644
index 000000000..584c5fbe1
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/.Sanitize
@@ -0,0 +1,47 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+daemon.c
+getuid.c
+memmove.c
+setenv.c
+sscanf.c
+strcasecmp.c
+strdup.c
+strerror.c
+syslog.c
+vfprintf.c
+vsprintf.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/posix/ChangeLog b/mechglue/src/lib/krb5/posix/ChangeLog
new file mode 100644
index 000000000..452457b7b
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/ChangeLog
@@ -0,0 +1,264 @@
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* getuid.c: Don't test __MWERKS__.
+	* syslog.c: Don't test macintosh.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MACSRCS): Don't set.
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* daemon.c: Moved to util/apputils.
+
+2003-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (STLIBOBJS, OBJS): Empty.
+
+2003-08-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (OBJS, STLIBOBJS): Drop setenv.o.
+	* setenv.c: Deleted.
+	* pos-obsolete.h: Deleted.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME, LIBOJS) [##WIN16##]: Don't define.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* syslog.c (vsyslog): Remove declaration of errno
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* syslog.c: Include syslog.h instead of sys/syslog.h.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* syslog.c: Drop _MSDOS support.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* sscanf.c: Don't use KRB5_DLLIMP.
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* setenv.c: Include pos-obsolete.h
+
+	* pos-obsolete.h: Add for obsolete functions until they can be
+	removed from the library. Contains setenv functions.
+
+2000-06-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* setenv.c: Do not provide prototype for static function unless
+	defined.
+
+2000-04-28  Ken Raeburn  <raeburn@mit.edu>
+	    Nalin Dahyabhai  <nalin@redhat.com>
+
+	* syslog.c (vsyslog): Use strncpy and strncat instead of strcpy
+	and strcat when adding to buffer "tbuf".  If calling vsprintf,
+	abort if it appears to have overrun the buffer.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Mon May 10 15:26:38 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Feb 27 18:03:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/krb5
+ 		directory, since we've moved the configure.in tests in
+ 		this directory to the toplevel lib/krb5 configure.in
+
+Fri Feb 27 11:55:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* daemon.c: Change use of HAS_PATHS_H to be HAVE_PATHS_H.
+		Change use of HAS_SETSID to be HAVE_SETSID.
+
+Wed Feb 18 16:25:07 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:02:00 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Sep 18 17:56:29 1997  Tom Yu  <tlyu@mit.edu>
+
+	* strcasecmp.c: Replace USE_STRING_H with something more sane.
+
+	* memmove.c: Replace USE_STRING_H with something more sane.
+
+Sat Feb 22 22:42:10 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Tue Feb  4 15:54:11 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Only build sscanf for Win16
+	* sscanf.c: Export sscanf in Windows DLL
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+Thu Jan  2 17:20:30 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Mon Jun 10 21:51:35 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* syslog.c: Change _WINDOWS to _MSDOS, and add check for _WIN32.
+
+Wed Feb  7 00:23:18 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Wed Jan  3 22:25:52 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Check for presense of setenv(), unsetenv(), and
+		getenv() from the C library.
+	
+	* Makefile.in: New file: setenv.c --- provides routines for
+		setting the environment.
+
+Tue Dec 19 17:29:21 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Don't drag in syslog.c if vsyslog() is not
+		defined.  Only drag it in if syslog() isn't available.
+
+Fri Oct  6 22:05:16 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:58:28 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 13 11:02:21 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: PC needs sscanf.c.
+	* sscanf.c: cleanup to compile cleanly on the PC, mostly fixing
+		signed/unsigned mismatches.
+
+Mon Sep 11 20:20:39 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* sscanf.c (sscanf): Initial version of a sscanf() replacement,
+		for those platforms (like Macroloss) that don't have
+		sscanf().
+
+Wed Sep  6 12:00:00 1995  James Mattly  <mattly@fusion.com>
+
+	* getuid.c:  turn off getuid for metrowerks which has one (which
+		is also a farce), but leave it on for MPW.
+
+Wed July  5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* vfprintf.c included <stdio.h>
+
+Fri Jun  9 19:34:34 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Fri May 26 20:21:09 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for building shared libraries.
+
+Tue May 23 16:30:03 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* daemon.c: Rearrange #include files so that krb5.h gets included
+		first, so that the debugging information can be more
+		efficiently collapsed since the type numbers will be the
+		same.
+
+Fri Apr 28 08:37:58 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* daemon.c (daemon): Lint cleanup; explicitly declare that
+		daemon() returns an int.
+
+Thu Apr 13 16:44:55 1995 Keith Vetter (keithv@fusion.com)
+
+	* syslog.c: __STDC__ conditional also checks the _WINDOWS define.
+
+Tue Mar 28 18:46:55 1995  John Gilmore  (gnu at toad.com)
+
+	* configure.in (AC_REPLACE_FUNCS):  Add getuid to the list.
+	* getuid.c:  Simple getuid() to fake out single-user systems.
+	* strcasecmp.c:  Remove duplicated <sys/types.h> and u_char.
+
+Fri Mar 17 20:24:51 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Zap duplicate.
+	(all-mac):  Add.
+
+Tue Mar  7 19:57:50 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: take out ISODE_INCLUDE.
+
+Tue Mar 7 12:30:45 1995 Keith Vetter (keithv@fusion.com)
+
+	* syslog.c: a disabled stub provided for satisfying the linker
+           on the pc.
+        * Makefile.in: made to work on the pc but only for syslog.c
+
+Tue Feb 28 01:05:42 1995  John Gilmore  (gnu at toad.com)
+
+	* daemon.c, memmove.c, strcasecmp.c, strdup.c:  Avoid <krb5/...>
+	includes.
+	* memmove.c:  Use HAS_SYS_TYPES_H.
+
+Thu Dec 22 16:33:02 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: 
+	* strcasecmp.c: Add strcasecmp replacement if necessary.
+
+	* daemon.c:
+	* memmove.c: Add #include for <sys/types.h>
+
+Wed Dec  7 00:01:59 1994    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Add check for HAS_SETSID test for daemon.c
+
+Sat Jul 16 01:24:01 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* daemon.c: <fcntl.h>, not <sys/fcntl.h>
+
+Tue Jun 21 00:52:24 1994  Mark W. Eichin  (eichin at mit.edu)
+
+	* configure.in: add AC_CONST for v*printf.
+
+Mon Jun 20 19:37:38 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* memmove.c: #include <krb5/config.h> so that build works using imake.
+
diff --git a/mechglue/src/lib/krb5/posix/Makefile.in b/mechglue/src/lib/krb5/posix/Makefile.in
new file mode 100644
index 000000000..085ae34d1
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/Makefile.in
@@ -0,0 +1,17 @@
+thisconfigdir=./..
+myfulldir=lib/krb5/posix
+mydir=posix
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=posix
+##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
+
+STLIBOBJS= # empty... @LIBOBJS@
+OBJS = # empty... @LIBOBJS@
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+
+##WIN32##LIBOBJS = $(OUTPRE)syslog.obj
+# @libobj_frag@
diff --git a/mechglue/src/lib/krb5/posix/getuid.c b/mechglue/src/lib/krb5/posix/getuid.c
new file mode 100644
index 000000000..2923331ad
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/getuid.c
@@ -0,0 +1,6 @@
+/* Very simple getuid() for systems that don't have one.  */
+int
+getuid()
+{
+	return 42;
+}
diff --git a/mechglue/src/lib/krb5/posix/memmove.c b/mechglue/src/lib/krb5/posix/memmove.c
new file mode 100644
index 000000000..3650c3d5a
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/memmove.c
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define MEMMOVE
+
+/* based on @(#)bcopy.c	5.11 (Berkeley) 6/21/91 */
+
+#include "k5-int.h"
+#ifdef HAS_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * sizeof(word) MUST BE A POWER OF TWO
+ * SO THAT wmask BELOW IS ALL ONES
+ */
+typedef	int word;		/* "word" used for optimal copy speed */
+
+#define	wsize	sizeof(word)
+#define	wmask	(wsize - 1)
+
+/*
+ * Copy a block of memory, handling overlap.
+ * This is the routine that actually implements
+ * (the portable versions of) bcopy, memcpy, and memmove.
+ */
+#ifdef MEMCOPY
+void *
+memcpy(dst0, src0, length)
+#else
+#ifdef MEMMOVE
+void *
+memmove(dst0, src0, length)
+#else
+void
+bcopy(src0, dst0, length)
+#endif
+#endif
+	void *dst0;
+	const void *src0;
+	register size_t length;
+{
+	register char *dst = dst0;
+	register const char *src = src0;
+	register size_t t;
+
+	if (length == 0 || dst == src)		/* nothing to do */
+		goto done;
+
+	/*
+	 * Macros: loop-t-times; and loop-t-times, t>0
+	 */
+#define	TLOOP(s) if (t) TLOOP1(s)
+#define	TLOOP1(s) do { s; } while (--t)
+
+	if ((unsigned long)dst < (unsigned long)src) {
+		/*
+		 * Copy forward.
+		 */
+		t = (int)src;	/* only need low bits */
+		if ((t | (int)dst) & wmask) {
+			/*
+			 * Try to align operands.  This cannot be done
+			 * unless the low bits match.
+			 */
+			if ((t ^ (int)dst) & wmask || length < wsize)
+				t = length;
+			else
+				t = wsize - (t & wmask);
+			length -= t;
+			TLOOP1(*dst++ = *src++);
+		}
+		/*
+		 * Copy whole words, then mop up any trailing bytes.
+		 */
+		t = length / wsize;
+		TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
+		t = length & wmask;
+		TLOOP(*dst++ = *src++);
+	} else {
+		/*
+		 * Copy backwards.  Otherwise essentially the same.
+		 * Alignment works as before, except that it takes
+		 * (t&wmask) bytes to align, not wsize-(t&wmask).
+		 */
+		src += length;
+		dst += length;
+		t = (int)src;
+		if ((t | (int)dst) & wmask) {
+			if ((t ^ (int)dst) & wmask || length <= wsize)
+				t = length;
+			else
+				t &= wmask;
+			length -= t;
+			TLOOP1(*--dst = *--src);
+		}
+		t = length / wsize;
+		TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
+		t = length & wmask;
+		TLOOP(*--dst = *--src);
+	}
+done:
+#if defined(MEMCOPY) || defined(MEMMOVE)
+	return (dst0);
+#else
+	return;
+#endif
+}
diff --git a/mechglue/src/lib/krb5/posix/sscanf.c b/mechglue/src/lib/krb5/posix/sscanf.c
new file mode 100644
index 000000000..32ce77cd8
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/sscanf.c
@@ -0,0 +1,788 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * Copyright (c) 1995 Massachusetts Institute of Technology.
+ *
+ * Modified by Theodore Ts'o from:
+ *
+ * 	@(#)vfscanf.c	5.7 (Berkeley) 12/14/92
+ *
+ * To be a stand-alone sscanf function.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "k5-int.h"
+
+#if 0
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "local.h"
+
+#define FLOATING_POINT
+
+#include "floatio.h"
+#endif
+#define	BUF		513	/* Maximum length of numeric string. */
+
+/*
+ * Flags used during conversion.
+ */
+#define	LONG		0x01	/* l: long or double */
+#define	LONGDBL		0x02	/* L: long double; unimplemented */
+#define	SHORT		0x04	/* h: short */
+#define	SUPPRESS	0x08	/* suppress assignment */
+#define	POINTER		0x10	/* weird %p pointer (`fake hex') */
+#define	NOSKIP		0x20	/* do not skip blanks */
+
+/*
+ * The following are used in numeric conversions only:
+ * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+ */
+#define	SIGNOK		0x40	/* +/- is (still) legal */
+#define	NDIGITS		0x80	/* no digits detected */
+
+#define	DPTOK		0x100	/* (float) decimal point is still legal */
+#define	EXPOK		0x200	/* (float) exponent (e+3, etc) still legal */
+
+#define	PFXOK		0x100	/* 0x prefix is (still) legal */
+#define	NZDIGITS	0x200	/* no zero digits detected */
+
+/*
+ * Conversion types.
+ */
+#define	CT_CHAR		0	/* %c conversion */
+#define	CT_CCL		1	/* %[...] conversion */
+#define	CT_STRING	2	/* %s conversion */
+#define	CT_INT		3	/* integer, i.e., strtol or strtoul */
+#define	CT_FLOAT	4	/* floating, i.e., strtod */
+
+#define u_char unsigned char
+#define u_long unsigned long
+
+static u_char *__sccl(char *tab, u_char *fmt);
+
+/*
+ * sscanf
+ */
+int KRB5_CALLCONV_C
+sscanf(char *str, char const *fmt0, ...)
+{
+	va_list ap;
+	register u_char *fmt = (u_char *)fmt0;
+	register int c;		/* character from format, or conversion */
+	register size_t width;	/* field width, or 0 */
+	register char *p;	/* points into all kinds of strings */
+	register int n;		/* handy integer */
+	register int flags;	/* flags as defined above */
+	register char *p0;	/* saves original value of p when necessary */
+	int nassigned;		/* number of fields assigned */
+	int nread;		/* number of characters consumed from string */
+	int base;		/* base argument to strtol/strtoul */
+	u_long (*ccfn)();	/* conversion function (strtol/strtoul) */
+	char ccltab[256];	/* character class table for %[...] */
+	char buf[BUF];		/* buffer for numeric conversions */
+
+	int chars_left;
+	char *char_ptr;
+	
+	/* `basefix' is used to avoid `if' tests in the integer scanner */
+	static short basefix[17] =
+		{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+	chars_left = strlen(str);
+	char_ptr = str;
+	va_start(ap, fmt0);
+	
+	nassigned = 0;
+	nread = 0;
+	base = 0;		/* XXX just to keep gcc happy */
+	ccfn = NULL;		/* XXX just to keep gcc happy */
+	for (;;) {
+		c = *fmt++;
+		if (c == 0) {
+			va_end(ap);
+			return (nassigned);
+		}
+		if (isspace(c)) {
+			for (;;) {
+				if (chars_left <= 0) {
+					va_end(ap);
+					return (nassigned);
+				}
+				if (!isspace(*char_ptr))
+					break;
+				nread++, chars_left--, char_ptr++;
+			}
+			continue;
+		}
+		if (c != '%')
+			goto literal;
+		width = 0;
+		flags = 0;
+		/*
+		 * switch on the format.  continue if done;
+		 * break once format type is derived.
+		 */
+again:		c = *fmt++;
+		switch (c) {
+		case '%':
+literal:
+			if (chars_left <= 0)
+				goto input_failure;
+			if (*char_ptr != c)
+				goto match_failure;
+			chars_left--, char_ptr++;
+			nread++;
+			continue;
+
+		case '*':
+			flags |= SUPPRESS;
+			goto again;
+		case 'l':
+			flags |= LONG;
+			goto again;
+		case 'L':
+			flags |= LONGDBL;
+			goto again;
+		case 'h':
+			flags |= SHORT;
+			goto again;
+
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			width = width * 10 + c - '0';
+			goto again;
+
+		/*
+		 * Conversions.
+		 * Those marked `compat' are for 4.[123]BSD compatibility.
+		 *
+		 * (According to ANSI, E and X formats are supposed
+		 * to the same as e and x.  Sorry about that.)
+		 */
+		case 'D':	/* compat */
+			flags |= LONG;
+			/* FALLTHROUGH */
+		case 'd':
+			c = CT_INT;
+			ccfn = (u_long (*)())strtol;
+			base = 10;
+			break;
+
+		case 'i':
+			c = CT_INT;
+			ccfn = (u_long (*)())strtol;
+			base = 0;
+			break;
+
+		case 'O':	/* compat */
+			flags |= LONG;
+			/* FALLTHROUGH */
+		case 'o':
+			c = CT_INT;
+			ccfn = strtoul;
+			base = 8;
+			break;
+
+		case 'u':
+			c = CT_INT;
+			ccfn = strtoul;
+			base = 10;
+			break;
+
+		case 'X':	/* compat   XXX */
+			flags |= LONG;
+			/* FALLTHROUGH */
+		case 'x':
+			flags |= PFXOK;	/* enable 0x prefixing */
+			c = CT_INT;
+			ccfn = strtoul;
+			base = 16;
+			break;
+
+#ifdef FLOATING_POINT
+		case 'E':	/* compat   XXX */
+		case 'F':	/* compat */
+			flags |= LONG;
+			/* FALLTHROUGH */
+		case 'e': case 'f': case 'g':
+			c = CT_FLOAT;
+			break;
+#endif
+
+		case 's':
+			c = CT_STRING;
+			break;
+
+		case '[':
+			fmt = __sccl(ccltab, fmt);
+			flags |= NOSKIP;
+			c = CT_CCL;
+			break;
+
+		case 'c':
+			flags |= NOSKIP;
+			c = CT_CHAR;
+			break;
+
+		case 'p':	/* pointer format is like hex */
+			flags |= POINTER | PFXOK;
+			c = CT_INT;
+			ccfn = strtoul;
+			base = 16;
+			break;
+
+		case 'n':
+			if (flags & SUPPRESS)	/* ??? */
+				continue;
+			if (flags & SHORT)
+				*va_arg(ap, short *) = nread;
+			else if (flags & LONG)
+				*va_arg(ap, long *) = nread;
+			else
+				*va_arg(ap, int *) = nread;
+			continue;
+
+		/*
+		 * Disgusting backwards compatibility hacks.	XXX
+		 */
+		case '\0':	/* compat */
+			va_end(ap);
+			return (EOF);
+
+		default:	/* compat */
+			if (isupper(c))
+				flags |= LONG;
+			c = CT_INT;
+			ccfn = (u_long (*)())strtol;
+			base = 10;
+			break;
+		}
+
+		/*
+		 * We have a conversion that requires input.
+		 */
+		if (chars_left <= 0)
+			goto input_failure;
+
+		/*
+		 * Consume leading white space, except for formats
+		 * that suppress this.
+		 */
+		if ((flags & NOSKIP) == 0) {
+			while (isspace(*char_ptr)) {
+				nread++;
+				if (--chars_left > 0)
+					char_ptr++;
+				else 
+					goto input_failure;
+			}
+			/*
+			 * Note that there is at least one character in
+			 * the buffer, so conversions that do not set NOSKIP
+			 * ca no longer result in an input failure.
+			 */
+		}
+
+		/*
+		 * Do the conversion.
+		 */
+		switch (c) {
+
+		case CT_CHAR:
+			/* scan arbitrary characters (sets NOSKIP) */
+			if (width == 0)
+				width = 1;
+			if (flags & SUPPRESS) {
+				size_t sum = 0;
+				for (;;) {
+					if ((size_t) (n = chars_left) < width) {
+						sum += n;
+						width -= n;
+						char_ptr += n;
+						if (sum == 0)
+						    goto input_failure;
+					} else {
+						sum += width;
+						chars_left -= width;
+						char_ptr += width;
+						break;
+					}
+				}
+				nread += sum;
+			} else {
+				size_t r;
+				char *dest;
+
+				dest = (char *)va_arg(ap, char *);
+				r = width;
+				if (r > (size_t) chars_left)
+					r = chars_left;
+				strncpy(dest, char_ptr, width);
+				
+				if (r == 0)
+					goto input_failure;
+				nread += r;
+				nassigned++;
+			}
+			break;
+
+		case CT_CCL:
+			/* scan a (nonempty) character class (sets NOSKIP) */
+			if (width == 0)
+				width = (size_t) ~0;	/* `infinity' */
+			/* take only those things in the class */
+			if (flags & SUPPRESS) {
+				n = 0;
+				while (ccltab[*char_ptr]) {
+					n++, chars_left--, char_ptr++;
+					if (--width == 0)
+						break;
+					if (chars_left <= 0) {
+						if (n == 0)
+							goto input_failure;
+						break;
+					}
+				}
+				if (n == 0)
+					goto match_failure;
+			} else {
+				p0 = p = va_arg(ap, char *);
+				while (ccltab[*char_ptr]) {
+					chars_left--;
+					*p++ = *char_ptr++;
+					if (--width == 0)
+						break;
+					if (chars_left <= 0) {
+						if (p == p0)
+							goto input_failure;
+						break;
+					}
+				}
+				n = p - p0;
+				if (n == 0)
+					goto match_failure;
+				*p = 0;
+				nassigned++;
+			}
+			nread += n;
+			break;
+
+		case CT_STRING:
+			/* like CCL, but zero-length string OK, & no NOSKIP */
+			if (width == 0)
+				width = (size_t) ~0;
+			if (flags & SUPPRESS) {
+				n = 0;
+				while (!isspace(*char_ptr)) {
+					n++, chars_left--, char_ptr++;
+					if (--width == 0)
+						break;
+					if (chars_left <= 0)
+						break;
+				}
+				nread += n;
+			} else {
+				p0 = p = va_arg(ap, char *);
+				while (!isspace(*char_ptr)) {
+					chars_left--;
+					*p++ = *char_ptr++;
+					if (--width == 0)
+						break;
+					if (chars_left <= 0)
+						break;
+				}
+				*p = 0;
+				nread += p - p0;
+				nassigned++;
+			}
+			continue;
+
+		case CT_INT:
+			/* scan an integer as if by strtol/strtoul */
+#ifdef hardway
+			if (width == 0 || width > sizeof(buf) - 1)
+				width = sizeof(buf) - 1;
+#else
+			/* size_t is unsigned, hence this optimisation */
+			if (--width > sizeof(buf) - 2)
+				width = sizeof(buf) - 2;
+			width++;
+#endif
+			flags |= SIGNOK | NDIGITS | NZDIGITS;
+			for (p = buf; width; width--) {
+				c = *char_ptr;
+				/*
+				 * Switch on the character; `goto ok'
+				 * if we accept it as a part of number.
+				 */
+				switch (c) {
+
+				/*
+				 * The digit 0 is always legal, but is
+				 * special.  For %i conversions, if no
+				 * digits (zero or nonzero) have been
+				 * scanned (only signs), we will have
+				 * base==0.  In that case, we should set
+				 * it to 8 and enable 0x prefixing.
+				 * Also, if we have not scanned zero digits
+				 * before this, do not turn off prefixing
+				 * (someone else will turn it off if we
+				 * have scanned any nonzero digits).
+				 */
+				case '0':
+					if (base == 0) {
+						base = 8;
+						flags |= PFXOK;
+					}
+					if (flags & NZDIGITS)
+					    flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
+					else
+					    flags &= ~(SIGNOK|PFXOK|NDIGITS);
+					goto ok;
+
+				/* 1 through 7 always legal */
+				case '1': case '2': case '3':
+				case '4': case '5': case '6': case '7':
+					base = basefix[base];
+					flags &= ~(SIGNOK | PFXOK | NDIGITS);
+					goto ok;
+
+				/* digits 8 and 9 ok iff decimal or hex */
+				case '8': case '9':
+					base = basefix[base];
+					if (base <= 8)
+						break;	/* not legal here */
+					flags &= ~(SIGNOK | PFXOK | NDIGITS);
+					goto ok;
+
+				/* letters ok iff hex */
+				case 'A': case 'B': case 'C':
+				case 'D': case 'E': case 'F':
+				case 'a': case 'b': case 'c':
+				case 'd': case 'e': case 'f':
+					/* no need to fix base here */
+					if (base <= 10)
+						break;	/* not legal here */
+					flags &= ~(SIGNOK | PFXOK | NDIGITS);
+					goto ok;
+
+				/* sign ok only as first character */
+				case '+': case '-':
+					if (flags & SIGNOK) {
+						flags &= ~SIGNOK;
+						goto ok;
+					}
+					break;
+
+				/* x ok iff flag still set & 2nd char */
+				case 'x': case 'X':
+					if (flags & PFXOK && p == buf + 1) {
+						base = 16;	/* if %i */
+						flags &= ~PFXOK;
+						goto ok;
+					}
+					break;
+				}
+
+				/*
+				 * If we got here, c is not a legal character
+				 * for a number.  Stop accumulating digits.
+				 */
+				break;
+		ok:
+				/*
+				 * c is legal: store it and look at the next.
+				 */
+				*p++ = c;
+				if (--chars_left > 0)
+					char_ptr++;
+				else 
+					break;		/* EOF */
+			}
+			/*
+			 * If we had only a sign, it is no good; push
+			 * back the sign.  If the number ends in `x',
+			 * it was [sign] '0' 'x', so push back the x
+			 * and treat it as [sign] '0'.
+			 */
+			if (flags & NDIGITS) {
+				if (p > buf) {
+					chars_left++;
+					char_ptr--;
+					*char_ptr = *(u_char *)--p;
+				}
+				goto match_failure;
+			}
+			c = ((u_char *)p)[-1];
+			if (c == 'x' || c == 'X') {
+				--p;
+				chars_left++;
+				char_ptr--;
+				*char_ptr = c;
+			}
+			if ((flags & SUPPRESS) == 0) {
+				u_long res;
+
+				*p = 0;
+				res = (*ccfn)(buf, (char **)NULL, base);
+				if (flags & POINTER)
+					*va_arg(ap, void **) = (void *)res;
+				else if (flags & SHORT)
+					*va_arg(ap, short *) = (short) res;
+				else if (flags & LONG)
+					*va_arg(ap, long *) = res;
+				else
+					*va_arg(ap, int *) = (int) res;
+				nassigned++;
+			}
+			nread += p - buf;
+			break;
+
+#ifdef FLOATING_POINT
+		case CT_FLOAT:
+			/* scan a floating point number as if by strtod */
+#ifdef hardway
+			if (width == 0 || width > sizeof(buf) - 1)
+				width = sizeof(buf) - 1;
+#else
+			/* size_t is unsigned, hence this optimisation */
+			if (--width > sizeof(buf) - 2)
+				width = sizeof(buf) - 2;
+			width++;
+#endif
+			flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
+			for (p = buf; width; width--) {
+				c = *char_ptr;
+				/*
+				 * This code mimicks the integer conversion
+				 * code, but is much simpler.
+				 */
+				switch (c) {
+
+				case '0': case '1': case '2': case '3':
+				case '4': case '5': case '6': case '7':
+				case '8': case '9':
+					flags &= ~(SIGNOK | NDIGITS);
+					goto fok;
+
+				case '+': case '-':
+					if (flags & SIGNOK) {
+						flags &= ~SIGNOK;
+						goto fok;
+					}
+					break;
+				case '.':
+					if (flags & DPTOK) {
+						flags &= ~(SIGNOK | DPTOK);
+						goto fok;
+					}
+					break;
+				case 'e': case 'E':
+					/* no exponent without some digits */
+					if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
+						flags =
+						    (flags & ~(EXPOK|DPTOK)) |
+						    SIGNOK | NDIGITS;
+						goto fok;
+					}
+					break;
+				}
+				break;
+		fok:
+				*p++ = c;
+				if (--chars_left > 0)
+					char_ptr++;
+				else 
+					break;	/* EOF */
+			}
+			/*
+			 * If no digits, might be missing exponent digits
+			 * (just give back the exponent) or might be missing
+			 * regular digits, but had sign and/or decimal point.
+			 */
+			if (flags & NDIGITS) {
+				if (flags & EXPOK) {
+					/* no digits at all */
+					while (p > buf) {
+						chars_left++;
+						char_ptr--;
+						*char_ptr = *(u_char *)--p;
+					}
+					goto match_failure;
+				}
+				/* just a bad exponent (e and maybe sign) */
+				c = *(u_char *)--p;
+				if (c != 'e' && c != 'E') {
+					chars_left++;
+					char_ptr--;
+					*char_ptr = c; /* sign */
+					c = *(u_char *)--p;
+				}
+				chars_left++;
+				char_ptr--;
+				*char_ptr = c;
+			}
+			if ((flags & SUPPRESS) == 0) {
+				double res;
+
+				*p = 0;
+				res = strtod(buf,(char **) NULL);
+				if (flags & LONG)
+					*va_arg(ap, double *) = res;
+				else
+					*va_arg(ap, float *) = res;
+				nassigned++;
+			}
+			nread += p - buf;
+			break;
+#endif /* FLOATING_POINT */
+		}
+	}
+input_failure:
+	va_end(ap);
+	return (nassigned ? nassigned : -1);
+match_failure:
+	va_end(ap);
+	return (nassigned);
+}
+
+/*
+ * Fill in the given table from the scanset at the given format
+ * (just after `[').  Return a pointer to the character past the
+ * closing `]'.  The table has a 1 wherever characters should be
+ * considered part of the scanset.
+ */
+static u_char *
+__sccl(tab, fmt)
+	register char *tab;
+	register u_char *fmt;
+{
+	register int c, n, v;
+
+	/* first `clear' the whole table */
+	c = *fmt++;		/* first char hat => negated scanset */
+	if (c == '^') {
+		v = 1;		/* default => accept */
+		c = *fmt++;	/* get new first char */
+	} else
+		v = 0;		/* default => reject */
+	/* should probably use memset here */
+	for (n = 0; n < 256; n++)
+		tab[n] = v;
+	if (c == 0)
+		return (fmt - 1);/* format ended before closing ] */
+
+	/*
+	 * Now set the entries corresponding to the actual scanset
+	 * to the opposite of the above.
+	 *
+	 * The first character may be ']' (or '-') without being special;
+	 * the last character may be '-'.
+	 */
+	v = 1 - v;
+	for (;;) {
+		tab[c] = v;		/* take character c */
+doswitch:
+		n = *fmt++;		/* and examine the next */
+		switch (n) {
+
+		case 0:			/* format ended too soon */
+			return (fmt - 1);
+
+		case '-':
+			/*
+			 * A scanset of the form
+			 *	[01+-]
+			 * is defined as `the digit 0, the digit 1,
+			 * the character +, the character -', but
+			 * the effect of a scanset such as
+			 *	[a-zA-Z0-9]
+			 * is implementation defined.  The V7 Unix
+			 * scanf treats `a-z' as `the letters a through
+			 * z', but treats `a-a' as `the letter a, the
+			 * character -, and the letter a'.
+			 *
+			 * For compatibility, the `-' is not considerd
+			 * to define a range if the character following
+			 * it is either a close bracket (required by ANSI)
+			 * or is not numerically greater than the character
+			 * we just stored in the table (c).
+			 */
+			n = *fmt;
+			if (n == ']' || n < c) {
+				c = '-';
+				break;	/* resume the for(;;) */
+			}
+			fmt++;
+			do {		/* fill in the range */
+				tab[++c] = v;
+			} while (c < n);
+#if 1	/* XXX another disgusting compatibility hack */
+			/*
+			 * Alas, the V7 Unix scanf also treats formats
+			 * such as [a-c-e] as `the letters a through e'.
+			 * This too is permitted by the standard....
+			 */
+			goto doswitch;
+#else
+			c = *fmt++;
+			if (c == 0)
+				return (fmt - 1);
+			if (c == ']')
+				return (fmt);
+#endif
+			break;
+
+		case ']':		/* end of scanset */
+			return (fmt);
+
+		default:		/* just another character */
+			c = n;
+			break;
+		}
+	}
+	/* NOTREACHED */
+}
diff --git a/mechglue/src/lib/krb5/posix/strcasecmp.c b/mechglue/src/lib/krb5/posix/strcasecmp.c
new file mode 100644
index 000000000..dda10ea31
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/strcasecmp.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* based on @(#)strcasecmp.c	5.10 (Berkeley) 1/26/91 */
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static const u_char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+	'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
+	'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
+	'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(s1, s2)
+	const char *s1, *s2;
+{
+	register const u_char *cm = charmap,
+			*us1 = (const u_char *)s1,
+			*us2 = (const u_char *)s2;
+
+	while (cm[*us1] == cm[*us2++])
+		if (*us1++ == '\0')
+			return (0);
+	return (cm[*us1] - cm[*--us2]);
+}
+
+int
+strncasecmp(s1, s2, n)
+	const char *s1, *s2;
+	register size_t n;
+{
+	if (n != 0) {
+		register const u_char *cm = charmap,
+				*us1 = (const u_char *)s1,
+				*us2 = (const u_char *)s2;
+
+		do {
+			if (cm[*us1] != cm[*us2++])
+				return (cm[*us1] - cm[*--us2]);
+			if (*us1++ == '\0')
+				break;
+		} while (--n != 0);
+	}
+	return (0);
+}
diff --git a/mechglue/src/lib/krb5/posix/strdup.c b/mechglue/src/lib/krb5/posix/strdup.c
new file mode 100644
index 000000000..c4b52bf19
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/strdup.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)strdup.c	5.3 (Berkeley) 6/1/90 */
+
+#include "k5-int.h"		/* For "const" */
+
+char *
+strdup(str)
+	const char *str;
+{
+	int len;
+	char *copy;
+
+	if (!str)
+		return((char *)0);
+	len = strlen(str) + 1;
+	if (!(copy = malloc((u_int)len)))
+		return((char *)0);
+	memcpy(copy, str, len);
+	return(copy);
+}
diff --git a/mechglue/src/lib/krb5/posix/strerror.c b/mechglue/src/lib/krb5/posix/strerror.c
new file mode 100644
index 000000000..55927236c
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/strerror.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)strerror.c	5.6 (Berkeley) 5/4/91 */
+
+#include <string.h>
+
+char *
+strerror(num)
+	int num;
+{
+	extern int sys_nerr;
+	extern char *sys_errlist[];
+#define	UPREFIX	"Unknown error: "
+	static char ebuf[40] = UPREFIX;		/* 64-bit number + slop */
+	register unsigned int errnum;
+	register char *p, *t;
+	char tmp[40];
+
+	errnum = num;				/* convert to unsigned */
+	if (errnum < sys_nerr)
+		return(sys_errlist[errnum]);
+
+	/* Do this by hand, so we don't include stdio(3). */
+	t = tmp;
+	do {
+		*t++ = "0123456789"[errnum % 10];
+	} while (errnum /= 10);
+	for (p = ebuf + sizeof(UPREFIX) - 1;;) {
+		*p++ = *--t;
+		if (t <= tmp)
+			break;
+	}
+	return(ebuf);
+}
diff --git a/mechglue/src/lib/krb5/posix/syslog.c b/mechglue/src/lib/krb5/posix/syslog.c
new file mode 100644
index 000000000..97abe4221
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/syslog.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)syslog.c	5.20 (Berkeley) 1/19/89 */
+
+/*
+ * SYSLOG -- print message on log file
+ *
+ * This routine looks a lot like printf, except that it outputs to the
+ * log file instead of the standard output.  Also:
+ *	adds a timestamp,
+ *	prints the module name in front of the message,
+ *	has some other formatting types (or will sometime),
+ *	adds a newline on the end of the message.
+ *
+ * The output of this routine is intended to be read by syslogd(8).
+ *
+ * Author: Eric Allman
+ * Modified to use UNIX domain IPC by Ralph Campbell
+ */
+
+#if !defined(_WIN32)
+
+#if defined(__STDC__) || defined(_WIN32)
+#include <stdarg.h>
+#else
+#define const
+#include <varargs.h>
+#endif
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <sys/signal.h>
+#include <syslog.h>
+#include <sys/wait.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdio.h>
+
+#define	LOGNAME	"/dev/log"
+#define	CONSOLE	"/dev/console"
+
+static int	LogFile = -1;		/* fd for log */
+static int	connected;		/* have done connect */
+static int	LogStat = 0;		/* status bits, set by openlog() */
+static const char *LogTag = "syslog";	/* string to tag the entry with */
+static int	LogFacility = LOG_USER;	/* default facility code */
+
+
+void
+#if defined(__STDC__) || defined(_WIN32)
+syslog(int pri, const char *fmt, ...)
+#else
+syslog(pri, fmt, va_alist)
+	int pri;
+	char *fmt;
+	va_dcl
+#endif
+{
+    va_list pvar;
+    void vsyslog();
+#if defined(__STDC__) || defined(_WIN32)
+    va_start(pvar, fmt);
+#else
+    va_start(pvar);
+#endif
+    vsyslog(pri, fmt, pvar);
+    va_end(pvar);
+}
+
+void
+vsyslog(pri, fmt, ap)
+	int pri;
+	const register char *fmt;
+	va_list ap;
+{
+	register int cnt;
+	register char *p;
+	time_t now, time();
+	int pid, saved_errno;
+	char tbuf[2048], fmt_cpy[1024], *ctime();
+	void openlog();
+
+	saved_errno = errno;
+
+	/* see if we should just throw out this message */
+	if ((u_int)LOG_FAC(pri) >= LOG_NFACILITIES ||
+	    !LOG_MASK(LOG_PRI(pri)) || (pri &~ (LOG_PRIMASK|LOG_FACMASK)))
+		return;
+	if (LogFile < 0 || !connected)
+		openlog(LogTag, LogStat | LOG_NDELAY, 0);
+
+	/* set default facility if none specified */
+	if ((pri & LOG_FACMASK) == 0)
+		pri |= LogFacility;
+
+	/* build the message */
+	(void)time(&now);
+	(void)sprintf(tbuf, "<%d>%.15s ", pri, ctime(&now) + 4);
+	for (p = tbuf; *p; ++p);
+	if (LogTag) {
+		(void)strncpy(p, LogTag, sizeof(tbuf) - 1 - (p - tbuf));
+		for (; *p; ++p);
+	}
+	if (LogStat & LOG_PID) {
+		(void)sprintf(p, "[%d]", getpid());
+		for (; *p; ++p);
+	}
+	if (LogTag) {
+		*p++ = ':';
+		*p++ = ' ';
+	}
+
+	/* substitute error message for %m */
+	{
+		register char ch, *t1, *t2;
+#ifndef strerror
+		extern char *strerror();
+#endif
+		
+		for (t1 = fmt_cpy; ch = *fmt; ++fmt)
+			if (ch == '%' && fmt[1] == 'm') {
+				++fmt;
+				for (t2 = strerror(saved_errno);
+				    *t1 = *t2++; ++t1);
+			}
+			else
+				*t1++ = ch;
+		*t1 = '\0';
+	}
+
+	(void)vsprintf(p, fmt_cpy, ap);
+	/* Bounds checking??  If a system doesn't have syslog, we
+	   probably can't rely on it having vsnprintf either.  Try not
+	   to let a buffer overrun be exploited.  */
+	if (strlen (tbuf) >= sizeof (tbuf))
+	  abort ();
+
+	/* output the message to the local logger */
+	if (send(LogFile, tbuf, cnt = strlen(tbuf), 0) >= 0 ||
+	    !(LogStat&LOG_CONS))
+		return;
+
+	/* output the message to the console */
+#if defined(SYSV) || defined(_AIX)
+	pid = fork();
+#else
+	pid = vfork();
+#endif
+	if (pid == -1)
+		return;
+	if (pid == 0) {
+		int fd;
+
+		(void)signal(SIGALRM, SIG_DFL);
+		sigsetmask((long)~sigmask(SIGALRM));
+		(void)alarm((u_int)5);
+		if ((fd = open(CONSOLE, O_WRONLY, 0)) < 0)
+			return;
+		(void)alarm((u_int)0);
+		tbuf[sizeof(tbuf) - 1] = '\0';
+		(void)strncat(tbuf, "\r", sizeof(tbuf) - 1 - strlen(tbuf));
+		p = strchr(tbuf, '>') + 1;
+		(void)write(fd, p, cnt + 1 - (p - tbuf));
+		(void)close(fd);
+		_exit(0);
+	}
+#if defined(SYSV) || defined(_AIX) || defined(_POSIX_SOURCE)
+#define	cast int *
+#else
+#define cast union wait *
+#endif
+	if (!(LogStat & LOG_NOWAIT))
+		while ((cnt = wait((cast)0)) > 0 && cnt != pid);
+#undef cast
+}
+
+static struct sockaddr SyslogAddr;	/* AF_UNIX address of local logger */
+/*
+ * OPENLOG -- open system log
+ */
+void
+openlog(ident, logstat, logfac)
+	const char *ident;
+	int logstat, logfac;
+{
+	if (ident != NULL)
+		LogTag = ident;
+	LogStat = logstat;
+	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
+		LogFacility = logfac;
+	if (LogFile == -1) {
+		SyslogAddr.sa_family = AF_UNIX;
+		strncpy(SyslogAddr.sa_data, LOGNAME, sizeof SyslogAddr.sa_data);
+		if (LogStat & LOG_NDELAY) {
+			LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
+			fcntl(LogFile, F_SETFD, 1);
+		}
+	}
+	if (LogFile != -1 && !connected &&
+	    connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) != -1)
+		connected = 1;
+}
+
+/*
+ * CLOSELOG -- close the system log
+ */
+void
+closelog()
+{
+	(void) close(LogFile);
+	LogFile = -1;
+	connected = 0;
+}
+
+static int	LogMask = 0xff;		/* mask of priorities to be logged */
+/*
+ * SETLOGMASK -- set the log mask level
+ */
+int
+setlogmask(pmask)
+	int pmask;
+{
+	int omask;
+
+	omask = LogMask;
+	if (pmask != 0)
+		LogMask = pmask;
+	return (omask);
+}
+#else /* Windows or Mac */
+
+/* Windows doesn't have the concept of a system log, so just
+** do nothing here.
+*/
+void
+syslog(int pri, const char *fmt, ...)
+{
+   return;
+}
+#endif
diff --git a/mechglue/src/lib/krb5/posix/vfprintf.c b/mechglue/src/lib/krb5/posix/vfprintf.c
new file mode 100644
index 000000000..dc76b2b04
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/vfprintf.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)vfprintf.c	5.2 (Berkeley) 6/27/88 */
+
+#include <varargs.h>
+
+int
+vfprintf(iop, fmt, ap)
+	FILE *iop;
+	const char *fmt;
+	va_list ap;
+{
+	int len;
+	char localbuf[BUFSIZ];
+
+	if (iop->_flag & _IONBF) {
+		iop->_flag &= ~_IONBF;
+		iop->_ptr = iop->_base = localbuf;
+		len = _doprnt(fmt, ap, iop);
+		(void) fflush(iop);
+		iop->_flag |= _IONBF;
+		iop->_base = NULL;
+		iop->_bufsiz = 0;
+		iop->_cnt = 0;
+	} else
+		len = _doprnt(fmt, ap, iop);
+
+	return (ferror(iop) ? EOF : len);
+}
diff --git a/mechglue/src/lib/krb5/posix/vsprintf.c b/mechglue/src/lib/krb5/posix/vsprintf.c
new file mode 100644
index 000000000..dab8a3f1e
--- /dev/null
+++ b/mechglue/src/lib/krb5/posix/vsprintf.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)vsprintf.c	5.2 (Berkeley) 6/27/88 */
+
+#include <stdio.h>
+#include <varargs.h>
+
+int
+vsprintf(str, fmt, ap)
+	char *str;
+        const char *fmt;
+	va_list ap;
+{
+	FILE f;
+	int len;
+
+	f._flag = _IOWRT+_IOSTRG;
+	f._ptr = str;
+	f._cnt = 32767;
+	len = _doprnt(fmt, ap, &f);
+	*f._ptr = 0;
+	return (len);
+}
diff --git a/mechglue/src/lib/krb5/rcache/.Sanitize b/mechglue/src/lib/krb5/rcache/.Sanitize
new file mode 100644
index 000000000..83e629405
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/.Sanitize
@@ -0,0 +1,48 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+.rconf
+ChangeLog
+Makefile.in
+README
+RELEASE
+configure
+configure.in
+rc_base.c
+rc_base.h
+rc_conv.c
+rc_dfl.c
+rc_dfl.h
+rc_io.c
+rc_io.h
+rcdef.c
+ser_rc.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/lib/krb5/rcache/.rconf b/mechglue/src/lib/krb5/rcache/.rconf
new file mode 100644
index 000000000..54e912bdd
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/.rconf
@@ -0,0 +1,2 @@
+ignore README
+ignore RELEASE
diff --git a/mechglue/src/lib/krb5/rcache/ChangeLog b/mechglue/src/lib/krb5/rcache/ChangeLog
new file mode 100644
index 000000000..1d0e8234e
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/ChangeLog
@@ -0,0 +1,505 @@
+2005-11-14  Jeffrey Altman <jaltman@mit.edu>
+
+	* rc_io.c: include k5-int.h instead of krb5.h
+
+2005-04-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_io.c (NEED_SOCKETS, NEED_LOWLEVEL_IO): Don't define.
+
+2005-01-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * rc_dfl.c: Move the extraction of the struct dfl_data
+          from the krb5_rcache after obtaining the lock, not before.
+
+2004-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc-int.h (struct _krb5_rc_ops): Add new member,
+	recover_or_init.
+	* rc_dfl.c (krb5_rc_dfl_init_locked): New function, with most of
+	the content of old krb5_rc_dfl_init.
+	(krb5_rc_dfl_init): Call it.
+	(krb5_rc_dfl_recover_or_init): New function.
+	* rc_dfl.h (krb5_rc_dfl_recover_or_init): Declare.
+	* rcdef.c (krb5_rc_dfl_ops): Initialize new field.
+	* rc_none.c (krb5_rc_none_recover_or_init): New macro.
+	(krb5_rc_none_ops): Initialize new field.
+	* rcfns.c (krb5_rc_recover_or_initialize): New function.
+
+2004-07-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_none.c: New file.
+	* Makefile.in (SRCS, STLIBOBJS, OBJS): Build it.
+	* rc-int.h (krb5_rc_none_ops): Declare.
+	* rc_base.c (none): New variable.
+	(krb5_rc_typelist_dfl): Add it into the linked list.
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_io.c: Don't check for macsock.h.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_io.c (krb5_rc_io_move, krb5_rc_io_sync): Don't test
+	macintosh.
+
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_io.c (dir, dirlen): Top-level variables deleted.
+	(getdir): Now returns the pointer, doesn't set top-level
+	variables.
+	(GETDIR): Set local variables dir and dirlen using the function's
+	return value.
+	(krb5_rc_io_creat, krb5_rc_io_open_internal): Add the new local
+	variables.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc-int.h (struct krb5_rc_st, struct _krb5_rc_ops, krb5_rc_ops):
+	Move type definitions here from k5-int.h.
+	(krb5_rc_register_type, krb5_rc_dfl_ops): Move declarations here
+	from k5-int.h.
+	* rc_dfl.c, rcdef.c, rcfns.c: Include rc-int.h.
+
+2004-05-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* rc_base.c: Include rc-int.h
+
+	* rc-int.h: Create file with prototypes for krb5int_rc_finish_init and 
+	krb5int_rc_terminate.
+
+2004-05-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* rc_io.c (krb5_rc_io_open_internal): If file could not be open,
+	do not invoke close negative argument.
+
+2004-05-03  Kenneth Raeburn  <raeburn@mit.edu>
+
+	* rc_dfl.c (krb5_rc_dfl_expunge_locked): Declare before use.
+
+2004-04-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_base.c (krb5_rc_resolve_type): Initialize the mutex in the
+	replay cache structure.
+	(krb5_rc_default, krb5_rc_resolve_full): Destroy it if creation of
+	the replay cache fails.
+	* rc_dfl.c (krb5_rc_dfl_get_span, krb5_rc_dfl_init): Lock the
+	mutex while operating on the replay cache object.
+	(krb5_rc_dfl_expunge_locked): Renamed from krb5_rc_dfl_expunge and
+	made static.  Call krb5_rc_dfl_recover_locked.
+	(krb5_rc_dfl_expunge): New wrapper function, locks the mutex.
+	(krb5_rc_dfl_recover_locked): Renamed from krb5_rc_dfl_recover and
+	made static.  Call krb5_rc_dfl_expunge_locked.
+	(krb5_rc_dfl_recover): New wrapper function, locks the mutex.
+	(krb5_rc_dfl_store): Lock the mutex.  Call _expunge_locked.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_base.c (rc_typelist_lock): Use new partial initializer.
+	(krb5int_rc_finish_init): New function, finish the mutex
+	initialization.
+	(krb5int_rc_terminate): New function, destroy the mutex and free
+	storage associated with registered types.
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_base.c: Include k5-thread.h.
+	(rc_typelist_lock): New mutex var.
+	(krb5_rc_register_type, krb5_rc_resolve_type): Lock it while
+	working with the type list.
+
+2004-03-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_base.c: Delete unused and untested semaphore support.
+
+2003-08-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_dfl.c (alive): Take a timestamp argument instead of the
+	context, and don't check the current time here.  All callers
+	changed to pass in the current time.
+	(rc_store): Take a timestamp argument.  All callers changed to
+	pass in the current time.
+
+2003-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBNAME) [##WIN16##]: Don't define.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_base.c (struct krb5_rc_typelist): Field "ops" now points to
+	const.
+	(krb5_rc_register_type): Likewise for "ops" argument.
+	* rcdef.c (krb5_rc_dfl_ops): Now const.
+	* rc_dfl.h (krb5_rc_dfl_ops): Declaration deleted.
+
+2002-09-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_io.c (krb5_rc_io_move): Missed a variable name change.
+
+2002-09-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_base.c, rc_conv.c, rc_io.c, ser_rc.c: Use prototype style
+	function definitions.
+
+	* rc_io.c (errno): Don't declare.
+	(krb5_rc_io_move): Avoid variable name "new".
+	* rc_dfl.c (cmp, alive): Avoid variable name "new".
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-14  Miro Jurisic  <meeroh@mit.edu>
+
+	* rc_io.c, rc_dfl.c: use "" includes for krb5.h and k5-int.h
+	[pullup from 1-2-2-branch]
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_dfl.h, rc_io.h, ser_rc.c: Make prototypes unconditional.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_io.c: Drop _MSDOS support.
+
+	* rcfns.c: Don't explicitly declare pointers FAR any more.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* ser_rc.c: Don't use KRB5_DLLIMP.
+
+2001-07-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* rc_dfl.c (krb5_rc_io_fetch): Once length element read from
+	cache, and verified to be positive, put into unsigned int variable
+	for passing to other functions that expect such.
+
+2001-07-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* rc_io.c: Declare krb5_rc_io_open_internal static.
+
+2001-06-21  Danilo Almeida  <dalmeida@mit.edu>
+
+	* rc_io.c (krb5_rc_io_creat): Make cleanup code easier to read.
+	(krb5_rc_io_open_internal): Include code previously in
+	krb5_rc_open().  Add a new full pathname parameter so that a file
+	can be opened by its full pathname.  Make cleanup code easier to
+	read.
+	(krb5_rc_io_open): Call krb5_rc_io_open_internal().
+	(krb5_rc_io_move): Fix Windows implementation so that it works
+	where it is used (only called by krb5_rc_dfl_expunge()).
+	(krb5_rc_io_sync): Fix function header to comply with coding
+	standard.  Add implementation for Windows.
+	(krb5_rc_io_close): Close file descriptor only if it is not -1.
+	Set file descriptor to -1 if it is successfully closed.
+
+	* rc_dfl.c (krb5_rc_dfl_close_no_free): Leave file descriptor
+	check for krb5_rc_io_close().
+	(krb5_rc_dfl_expunge): Do better resource cleanup on error.
+
+2001-06-20  Danilo Almeida  <dalmeida@mit.edu>
+
+	* rc_dfl.c, rc_io.c: More compliance with coding standards: use
+	ANSI function declarations, use curly braces to fix up #ifdef
+	reindenting under Emacs, reindent code, strip trailing whitespace,
+	wrap lines, fix commans.  Not finished: fix indenting of curly
+	braces in control structures.
+
+2001-01-23  Tom Yu  <tlyu@mit.edu>
+
+	* rc_io.c (getdir): Subtract one from dirlen, since sizeof
+	includes the terminating NUL character.  Avoid redundant path
+	separators.
+	(krb5_rc_io_move): When renaming OLD to NEW, don't copy the
+	filename.  This was causing temporary files to get leaked.
+	(krb5_rc_io_close): Don't FREE if d->fn is NULL.
+
+2001-01-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* rcfns.c: New file, with function versions of former dispatch
+	macros from krb5.h.
+	* Makefile.in (STLIBOBJS, OBJS, SRCS): Add it.
+
+2000-09-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* rc_io.h (struct krb5_rc_iostuff): Internal structure - change
+	position in file from long to off_t (as argument for lseek). 
+
+	* rc_io.c (krb5_rc_io_read, krb5_rc_io_write): Unsigned vs signed
+	warnings cleanup.
+
+	* rc_dfl.c (alive): Do not shadow time() with variable named for same. 
+
+	* rc_base.c (krb5_rc_resolve_full): Cleanup unsigned vs. signed
+	warnings.
+
+	
+2000-06-29  Ezra Peisach  <epeisach@engrailed.mit.edu>
+
+	* rc_io.c (krb5_rc_io_creat): Cast getpid() to int.
+	(Use of a long might overflow buffer if pid_t is 64 bits */
+
+2000-04-28  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* rc_io.c (getdir): Don't check dirlen again, the call sites
+	always do.  Fix dirlen calculation.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* rc_dfl.c (krb5_rc_io_fetch): Set client and server fields to
+	NULL after freeing them in the error case.
+
+Mon May 10 15:26:53 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Tue Apr  6 16:10:44 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* rc_io.c (krb5_rc_io_move): Workaround the fact that Windows has
+		really poor emulation of POSIX functions such as rename.
+		(In fact, it has completely different semantics for this
+		call!)  Fix supplied by Tom Sanfilippo (txn# 2184 in krb5dev)
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Fri Feb 27 18:03:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Changed thisconfigdir to point at the lib/krb5
+ 		directory, since we've moved the configure.in tests in
+ 		this directory to the toplevel lib/krb5 configure.in
+
+Wed Feb 18 16:25:34 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 17:01:50 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Sep 25 21:28:41 1997  Tom Yu  <tlyu@mit.edu>
+
+	* rc_io.c: Replace KRB5_USE_INET with something more sane.
+
+Tue Mar 25 01:15:39 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* rc_io.c (krb5_rc_io_open): rcache owner should be checked against
+		the effective uid, not the real uid.  [krb5-libs/366]
+
+Sat Feb 22 22:44:15 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use some of the new library list build rules in
+		win-post.in
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+
+	* rc_dfl.c, rc_dfl.h: Win32/DLL calling conventions for rcache
+		functions.  (Most rcache routines are still not exported
+		pending an API review).
+
+Thu Jan  2 17:21:44 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Mon Nov 18 15:25:51 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* rc_dfl.c: Apply jik's fix to allow the expunging of the replay
+		cache to happen correctly. [174,132]
+
+Mon Jun 10 21:52:38 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* rc_io.c: Change _WINDOWS to _MSDOS, and add check for _WIN32.
+
+Sat Feb 24 18:53:33 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rc_io.c (krb5_rc_io_creat, krb5_rc_io_open): Use Windows path
+		separator, if appropriate.  Under Windows also use the
+		environment variables TEMP and TMP for the replay cache.
+
+Fri Dec  1 17:07:24 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* rc_io.c (krb5_rc_io_creat): In case of permission problems,
+		don't unlink the old replay cache; make it a hard
+		(repeatable) error.  This also reduces the chance we
+		accidentally delete valuable data.
+
+Mon Nov 27 14:52:23 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* rc_dfl.c (krb5_rc_dfl_init): default lifespan to
+		context->clockskew in case some app can't get at the
+		internals of the context struct.
+
+Fri Oct  6 22:05:31 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Sep 25 16:58:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep  6 12:00:00 1995  James Mattly  <mattly@fusion.com>
+	* rc_io.c:  turn off a call to fsync which MACINTOSH doesn't support
+
+
+Thu Aug 31 14:13:21 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* rc_base.c - Set magic number in rcache structure after successfully
+		resolving the replay cache.
+
+
+Tue Aug 29 14:19:54 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in, .Sanitize, ser_rc.c - Add routines to serialize rcache.
+
+Fri Aug  4 22:07:46 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* rc_conv.c (krb5_auth_to_rep): Add parens to shut up gcc -Wall
+
+	* rc_io.c: Add parens to shut up gcc -Wall
+
+	* rc_dfl.c: Add parens to shut up gcc -Wall
+
+	* rc_base.c: Add parens to shut up gcc -Wall
+
+Thu Jul 20 22:34:47 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* rc_dfl.c (rc_store): rename from store() to avoid conflict with
+	dbm function of same name (and different prototype.)
+
+Wed July  5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* rc_io.c added HAVE_MACSOCK_H, change open to THREEPARAMOPEN
+
+Fri Jun  9 19:34:38 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Fri May 26 20:21:19 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for building shared libraries.
+
+Tue May 23 16:30:29 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rc_io.c: Rearrange #include files so that krb5.h gets included
+		first, so that the debugging information can be more
+		efficiently collapsed since the type numbers will be the
+		same.
+
+Mon May  1 23:10:26 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rc_dfl.c (krb5_rc_dfl_recover): Fix memory leaks in this
+		function.  The krb5_donot_replay structure was not being
+		freed properly.
+
+Thu Apr 13 15:49:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.[ch]: removed unneeded INTERFACE from non-api functions.
+
+Fri Mar 31 16:44:34 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rc_dfl.c (krb5_rc_dfl_expunage): Close the old, temporary reply
+		cache after we're done expunging it.
+
+	* rc_io.c (krb5_rc_io_move): Make duplicate copies of the filename
+		and the file descriptor (via malloc/strcpy and dup), so
+		that the old rc_io object can be cleanly closed without
+		affecting the new rc_io object.
+
+Fri Mar 17 20:27:41 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (LDFLAGS):  Eliminate duplicate of config/pre.in.
+
+Tue Mar 7 21:40:18 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: changed library name for the PC.
+
+Tue Mar  7 19:54:32 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: take out ISODE_DEFS, ISODE_INCLUDE.
+
+Tue Mar 7 12:33:29 1995 Keith Vetter (keithv@fusion.com)
+
+	* rc_io.c: moved the enabling defines for low-level io, e.g. read,
+           write, lseek, etc., out of here and into k5-config.h.
+
+Thu Mar 2 11:55:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* rc_io.c: changed NEED_WINSOCK_H to NEED_SOCKETS
+
+Wed Mar 1 12:03:30 1995 Keith Vetter (keithv@fusion.com)
+
+	* *.c, *.h Added windows INTERFACE keyword
+	* Makefile.in: made to work on the PC.
+        * rc_dfl.c: Some int/long changes for the PC
+        * rc_io.c: hack to get Microsoft C in std-c mode to allow
+           low-level i/o routines. Probably not a permanent solution
+           but keep until we decide on a better method.
+        * rc_io.h: added 2 missing prototypes
+        * rc_dfl.h: added 2 missing prototypes
+
+Tue Feb 28 01:03:34 1995  John Gilmore  (gnu at toad.com)
+
+	* *.c:  Avoid <krb5/...> includes.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Thu Dec 22 15:44:50 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add test for uid_t.
+
+Fri Oct 14 23:12:00 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add ISODE_DEFS rule.
+
+Mon Oct  3 19:32:59 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rc_def.c (krb5_rc_dfl_recover): krb5_rc_io_size was being called
+		(still) with the wrong type argument.  Should have been &t->d.
+
+Fri Sep 30 21:59:08 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rc_def.c (krb5_rc_dfl_ops): Add placeholder for magic number
+
+Thu Sep 29 22:11:20 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* rc_dfl.c (krb5_rc_dfl_recover): krb5_rc_io_size was being called
+		with the wrong type argument.  I have no idea how it was
+
+
+Thu Sep  8 23:34:53 1994  Theodore Y. Ts'o  (tytso@pinata)
+
+	* rc_io.c: The variables dirlen and dir were declared global, and
+		didn't need to be; changed to be static.
+
+Sat Aug 20 00:09:37 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* rc_dfl.c (krb5_rc_dfl_expunge): name (t->name) was getting freed
+	and we tried to use it.  Clear t->name to stop it from being
+	freed, and then free it later.
+
+Mon Jun 20 19:37:13 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* rc_base.h: #include <krb5/osconf.h> so that build works using	imake. 
+
diff --git a/mechglue/src/lib/krb5/rcache/Makefile.in b/mechglue/src/lib/krb5/rcache/Makefile.in
new file mode 100644
index 000000000..f3ba36ee6
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/Makefile.in
@@ -0,0 +1,106 @@
+thisconfigdir=./..
+myfulldir=lib/krb5/rcache
+mydir=rcache
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+##DOS##BUILDTOP = ..\..\..
+##DOS##PREFIXDIR=rcache
+##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
+
+STLIBOBJS = \
+	rc_base.o	\
+	rc_dfl.o 	\
+	rc_io.o		\
+	rcdef.o		\
+	rc_none.o	\
+	rc_conv.o	\
+	ser_rc.o	\
+	rcfns.o
+
+OBJS=	\
+	$(OUTPRE)rc_base.$(OBJEXT)	\
+	$(OUTPRE)rc_dfl.$(OBJEXT) 	\
+	$(OUTPRE)rc_io.$(OBJEXT)	\
+	$(OUTPRE)rcdef.$(OBJEXT)	\
+	$(OUTPRE)rc_none.$(OBJEXT)	\
+	$(OUTPRE)rc_conv.$(OBJEXT)	\
+	$(OUTPRE)ser_rc.$(OBJEXT)	\
+	$(OUTPRE)rcfns.$(OBJEXT)
+
+SRCS=	\
+	$(srcdir)/rc_base.c	\
+	$(srcdir)/rc_dfl.c 	\
+	$(srcdir)/rc_io.c	\
+	$(srcdir)/rcdef.c	\
+	$(srcdir)/rc_none.c	\
+	$(srcdir)/rc_conv.c	\
+	$(srcdir)/ser_rc.c	\
+	$(srcdir)/rcfns.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+rc_base.so rc_base.po $(OUTPRE)rc_base.$(OBJEXT): rc_base.c \
+  rc_base.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  rc-int.h
+rc_dfl.so rc_dfl.po $(OUTPRE)rc_dfl.$(OBJEXT): rc_dfl.c \
+  rc_base.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  rc_dfl.h rc_io.h rc-int.h
+rc_io.so rc_io.po $(OUTPRE)rc_io.$(OBJEXT): rc_io.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  rc_base.h rc_dfl.h rc_io.h
+rcdef.so rcdef.po $(OUTPRE)rcdef.$(OBJEXT): rcdef.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  rc-int.h rc_dfl.h
+rc_none.so rc_none.po $(OUTPRE)rc_none.$(OBJEXT): rc_none.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  rc-int.h
+rc_conv.so rc_conv.po $(OUTPRE)rc_conv.$(OBJEXT): rc_conv.c \
+  rc_base.h $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+ser_rc.so ser_rc.po $(OUTPRE)ser_rc.$(OBJEXT): ser_rc.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  rc-int.h
+rcfns.so rcfns.po $(OUTPRE)rcfns.$(OBJEXT): rcfns.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  rc-int.h
diff --git a/mechglue/src/lib/krb5/rcache/README b/mechglue/src/lib/krb5/rcache/README
new file mode 100644
index 000000000..13a45a1d8
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/README
@@ -0,0 +1,82 @@
+/*
+Copyright 1990, Daniel J. Bernstein. All rights reserved.
+
+Please address any questions or comments to the author at brnstnd@acf10.nyu.edu.
+*/
+
+The #include's should be rewritten.
+
+All functions return 0 on success.
+
+Environment variables: KRB5RCACHETYPE, KRB5RCACHENAME, KRB5RCACHEDIR,
+and TMPDIR. Obsolete: KRB5RCACHE.
+
+All header files are both ANSI-compatible and K&R-compatible. The .c files
+are only ANSI compatible. Everything passes gcc -Wall -ansi -pedantic.
+
+Strings are freed using FREE(), which is defined in terms of free(). 
+
+The error header files should be redone.
+
+The header files don't use __ because that's reserved.
+
+Each .c file assumes <malloc.h>. rc_io.c assumes fsync() and a gaggle of
+error codes. These assumptions are not as portable as the code itself.
+
+
+rcache.c:
+
+The rcache.c compatibility interface's type registration is a no-op; it
+simply passes the type name on to rc_base.h. rcache.h is obsolete; use
+rc_base.h if possible.
+
+There are some slight differences between rcache.c and the prototypes I
+saw in krb/func-proto.h. Don't look at me, it's your interface.
+
+rcache.c's get_name doesn't fill with zeros unless strncpy does.
+
+
+rc_base.c:
+
+It doesn't take linker magic to preregister types. Just change the
+typehead initialization in rc_base.c, with an appropriate include file
+setting the ops.
+
+
+rc_dfl.c:
+
+If NOIOSTUFF is defined when rc_dfl.c is compiled, all dfl rcaches will
+be per-process. This is untested.
+
+Provided that separate threads use separate rcaches, rc_dfl.c is safe
+for multithreading.
+
+Getting the name of a cache is only valid after it is created and before
+it is closed. Recovering a cache is only valid after it has been created.
+
+krb5_unparse_name had better produce a zero-terminated string.
+
+rc_dfl.c isn't smart enough to try expunge/retry upon a malloc error.
+Then again, such an error indicates that the whole system's about to die;
+without real memory management there's no good solution.
+
+HASHSIZE can be defined at compile time. It defaults to 997 in rc_dfl.c.
+EXCESSREPS can be defined at compile time. It defaults to 30 in rc_dfl.c.
+
+Hopefully adding a deltat to a time to compare to another time cannot
+overflow.
+
+In rc_dfl's struct dfl_data, the name field is never freed, even though
+it may be malloced by io_creat on a generate-name call. This should not
+be a problem: a single process should not be opening and closing many
+rcaches. One fix would be another field to indicate whether the string
+was malloced or not; normally this is an unstated characteristic of a
+char pointer, but here it would have to be explicit.
+
+
+rc_io.c:
+
+rc_io.c assumes that siginterrupt() is not set. If siginterrupt() is set
+and a signal occurs during, say, close(), then the close will fail.
+
+On a machine without fsync() you might as well not use the disk at all.
diff --git a/mechglue/src/lib/krb5/rcache/RELEASE b/mechglue/src/lib/krb5/rcache/RELEASE
new file mode 100644
index 000000000..21a462472
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/RELEASE
@@ -0,0 +1,17 @@
+Text of Mr. Bernstein's release:
+
+"I" henceforth refers to Daniel J. Bernstein.
+
+"rcshar" henceforth refers to the attached document, as sent from Daniel
+J. Bernstein to Project Athena on 11 March 1990
+
+I am the author of and sole copyright holder upon rcshar.
+
+I hereby waive copyright upon rcshar.  rcshar is hereby public domain.
+
+I hereby also waive copyright upon any works that are (1) derived from
+rcshar and (2) prepared between 11 March 1990 and 1 January 1991.
+
+Daniel J. Bernstein
+
+<signature>, dated 7 July 1990
diff --git a/mechglue/src/lib/krb5/rcache/rc-int.h b/mechglue/src/lib/krb5/rcache/rc-int.h
new file mode 100644
index 000000000..2f09d239a
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc-int.h
@@ -0,0 +1,77 @@
+/*
+ * lib/krb5/keytab/rc-int.h
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * This file contains constant and function declarations used in the
+ * file-based replay cache routines.
+ */
+
+#ifndef __KRB5_RCACHE_INT_H__
+#define __KRB5_RCACHE_INT_H__
+
+int krb5int_rc_finish_init(void);
+
+void krb5int_rc_terminate(void);
+
+struct krb5_rc_st {
+    krb5_magic magic;
+    const struct _krb5_rc_ops *ops;
+    krb5_pointer data;
+    k5_mutex_t lock;
+};
+
+struct _krb5_rc_ops {
+    krb5_magic magic;
+    char *type;
+    krb5_error_code (KRB5_CALLCONV *init)
+	(krb5_context, krb5_rcache,krb5_deltat); /* create */
+    krb5_error_code (KRB5_CALLCONV *recover)
+	(krb5_context, krb5_rcache); /* open */
+    krb5_error_code (KRB5_CALLCONV *recover_or_init)
+	(krb5_context, krb5_rcache,krb5_deltat);
+    krb5_error_code (KRB5_CALLCONV *destroy)
+	(krb5_context, krb5_rcache);
+    krb5_error_code (KRB5_CALLCONV *close)
+	(krb5_context, krb5_rcache);
+    krb5_error_code (KRB5_CALLCONV *store)
+	(krb5_context, krb5_rcache,krb5_donot_replay *);
+    krb5_error_code (KRB5_CALLCONV *expunge)
+	(krb5_context, krb5_rcache);
+    krb5_error_code (KRB5_CALLCONV *get_span)
+	(krb5_context, krb5_rcache,krb5_deltat *);
+    char *(KRB5_CALLCONV *get_name)
+	(krb5_context, krb5_rcache);
+    krb5_error_code (KRB5_CALLCONV *resolve)
+	(krb5_context, krb5_rcache, char *);
+};
+
+typedef struct _krb5_rc_ops krb5_rc_ops;
+
+krb5_error_code krb5_rc_register_type (krb5_context, const krb5_rc_ops *);
+
+extern const krb5_rc_ops krb5_rc_dfl_ops;
+extern const krb5_rc_ops krb5_rc_none_ops;
+
+#endif /* __KRB5_RCACHE_INT_H__ */
diff --git a/mechglue/src/lib/krb5/rcache/rc_base.c b/mechglue/src/lib/krb5/rcache/rc_base.c
new file mode 100644
index 000000000..e9f9505c5
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc_base.c
@@ -0,0 +1,173 @@
+/*
+ * lib/krb5/rcache/rc_base.c
+ *
+ * This file of the Kerberos V5 software is derived from public-domain code
+ * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
+ *
+ */
+
+
+/*
+ * Base "glue" functions for the replay cache.
+ */
+
+#include "rc_base.h"
+#include "rc-int.h"
+#include "k5-thread.h"
+
+#define FREE(x) ((void) free((char *) (x)))
+
+struct krb5_rc_typelist {
+    const krb5_rc_ops *ops;
+    struct krb5_rc_typelist *next;
+};
+static struct krb5_rc_typelist none = { &krb5_rc_none_ops, 0 };
+static struct krb5_rc_typelist krb5_rc_typelist_dfl = { &krb5_rc_dfl_ops, &none };
+static struct krb5_rc_typelist *typehead = &krb5_rc_typelist_dfl;
+static k5_mutex_t rc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+int krb5int_rc_finish_init(void)
+{
+    return k5_mutex_finish_init(&rc_typelist_lock);
+}
+void krb5int_rc_terminate(void)
+{
+    struct krb5_rc_typelist *t, *t_next;
+    k5_mutex_destroy(&rc_typelist_lock);
+    for (t = typehead; t != &krb5_rc_typelist_dfl; t = t_next) {
+	t_next = t->next;
+	free(t);
+    }
+}
+
+krb5_error_code krb5_rc_register_type(krb5_context context,
+				      const krb5_rc_ops *ops)
+{
+    struct krb5_rc_typelist *t;
+    krb5_error_code err;
+    err = k5_mutex_lock(&rc_typelist_lock);
+    if (err)
+	return err;
+    for (t = typehead;t && strcmp(t->ops->type,ops->type);t = t->next)
+	;
+    if (t) {
+	k5_mutex_unlock(&rc_typelist_lock);
+	return KRB5_RC_TYPE_EXISTS;
+    }
+    t = (struct krb5_rc_typelist *) malloc(sizeof(struct krb5_rc_typelist));
+    if (t == NULL) {
+	k5_mutex_unlock(&rc_typelist_lock);
+	return KRB5_RC_MALLOC;
+    }
+    t->next = typehead;
+    t->ops = ops;
+    typehead = t;
+    k5_mutex_unlock(&rc_typelist_lock);
+    return 0;
+}
+
+krb5_error_code krb5_rc_resolve_type(krb5_context context, krb5_rcache *id,
+				     char *type)
+{
+    struct krb5_rc_typelist *t;
+    krb5_error_code err;
+    err = k5_mutex_lock(&rc_typelist_lock);
+    if (err)
+	return err;
+    for (t = typehead;t && strcmp(t->ops->type,type);t = t->next)
+	;
+    if (!t) {
+	k5_mutex_unlock(&rc_typelist_lock);
+	return KRB5_RC_TYPE_NOTFOUND;
+    }
+    /* allocate *id? nah */
+    (*id)->ops = t->ops;
+    k5_mutex_unlock(&rc_typelist_lock);
+    return k5_mutex_init(&(*id)->lock);
+}
+
+char * krb5_rc_get_type(krb5_context context, krb5_rcache id)
+{
+    return id->ops->type;
+}
+
+char * krb5_rc_default_type(krb5_context context)
+{
+    char *s;
+    if ((s = getenv("KRB5RCACHETYPE")))
+	return s;
+    else
+	return "dfl";
+}
+
+char * krb5_rc_default_name(krb5_context context)
+{
+    char *s;
+    if ((s = getenv("KRB5RCACHENAME")))
+	return s;
+    else
+	return (char *) 0;
+}
+
+krb5_error_code
+krb5_rc_default(krb5_context context, krb5_rcache *id)
+{
+    krb5_error_code retval;
+
+    if (!(*id = (krb5_rcache )malloc(sizeof(**id))))
+	return KRB5_RC_MALLOC;
+
+    if ((retval = krb5_rc_resolve_type(context, id, 
+				       krb5_rc_default_type(context)))) {
+	k5_mutex_destroy(&(*id)->lock);
+	FREE(*id);
+	return retval;
+    }
+    if ((retval = krb5_rc_resolve(context, *id, 
+				  krb5_rc_default_name(context)))) {
+	k5_mutex_destroy(&(*id)->lock);
+	FREE(*id);
+	return retval;
+    }
+    (*id)->magic = KV5M_RCACHE;
+    return retval;
+}
+
+
+krb5_error_code krb5_rc_resolve_full(krb5_context context, krb5_rcache *id, char *string_name)
+{
+    char *type;
+    char *residual;
+    krb5_error_code retval;
+    unsigned int diff;
+
+    if (!(residual = strchr(string_name,':')))
+	return KRB5_RC_PARSE;
+ 
+    diff = residual - string_name;
+    if (!(type = malloc(diff + 1)))
+	return KRB5_RC_MALLOC;
+    (void) strncpy(type, string_name, diff);
+    type[residual - string_name] = '\0';
+
+    if (!(*id = (krb5_rcache) malloc(sizeof(**id)))) {
+	FREE(type);
+	return KRB5_RC_MALLOC;
+    }
+
+    if ((retval = krb5_rc_resolve_type(context, id,type))) {
+	FREE(type);
+	k5_mutex_destroy(&(*id)->lock);
+	FREE(*id);
+	return retval;
+    }
+    FREE(type);
+    if ((retval = krb5_rc_resolve(context, *id,residual + 1))) {
+	k5_mutex_destroy(&(*id)->lock);
+	FREE(*id);
+	return retval;
+    }
+    (*id)->magic = KV5M_RCACHE;
+    return retval;
+}
+
diff --git a/mechglue/src/lib/krb5/rcache/rc_base.h b/mechglue/src/lib/krb5/rcache/rc_base.h
new file mode 100644
index 000000000..e2e27677e
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc_base.h
@@ -0,0 +1,15 @@
+/*
+ * lib/krb5/rcache/rc_base.h
+ *
+ * This file of the Kerberos V5 software is derived from public-domain code
+ * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
+ *
+ */
+
+#ifndef KRB5_RC_H
+#define KRB5_RC_H
+#include "k5-int.h"
+
+/* all the stuff that was here is now in rcache.h, included by krb5/krb5.h */
+
+#endif
diff --git a/mechglue/src/lib/krb5/rcache/rc_conv.c b/mechglue/src/lib/krb5/rcache/rc_conv.c
new file mode 100644
index 000000000..8eb73ccbe
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc_conv.c
@@ -0,0 +1,38 @@
+/*
+ * lib/krb5/rcache/rc_conv.c
+ *
+ * This file of the Kerberos V5 software is derived from public-domain code
+ * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
+ *
+ */
+
+
+/*
+ * An implementation for the default replay cache type.
+ */
+
+#define FREE(x) ((void) free((char *) (x)))
+
+#include "rc_base.h"
+
+/*
+Local stuff:
+ krb5_auth_to_replay(context, krb5_tkt_authent *auth,krb5_donot_replay *rep)
+  given auth, take important information and make rep; return -1 if failed
+*/
+
+krb5_error_code
+krb5_auth_to_rep(krb5_context context, krb5_tkt_authent *auth, krb5_donot_replay *rep)
+{
+ krb5_error_code retval;
+ rep->cusec = auth->authenticator->cusec;
+ rep->ctime = auth->authenticator->ctime;
+ if ((retval = krb5_unparse_name(context, auth->ticket->server, &rep->server)))
+   return retval; /* shouldn't happen */
+ if ((retval = krb5_unparse_name(context, auth->authenticator->client,
+				 &rep->client))) {
+     FREE(rep->server);
+     return retval; /* shouldn't happen. */
+ }
+ return 0;
+}
diff --git a/mechglue/src/lib/krb5/rcache/rc_dfl.c b/mechglue/src/lib/krb5/rcache/rc_dfl.c
new file mode 100644
index 000000000..a334002e0
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc_dfl.c
@@ -0,0 +1,711 @@
+/*
+ * lib/krb5/rcache/rc_dfl.c
+ *
+ * This file of the Kerberos V5 software is derived from public-domain code
+ * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
+ *
+ */
+
+
+/*
+ * An implementation for the default replay cache type.
+ */
+#define FREE(x) ((void) free((char *) (x)))
+#include "rc_base.h"
+#include "rc_dfl.h"
+#include "rc_io.h"
+#include "k5-int.h"
+#include "rc-int.h"
+
+/*
+ * If NOIOSTUFF is defined at compile time, dfl rcaches will be per-process.
+ */
+
+/*
+Local stuff:
+
+static int hash(krb5_donot_replay *rep, int hsize)
+  returns hash value of *rep, between 0 and hsize - 1
+HASHSIZE
+  size of hash table (constant), can be preset
+static int cmp(krb5_donot_replay *old, krb5_donot_replay *new, krb5_deltat t)
+  compare old and new; return CMP_REPLAY or CMP_HOHUM
+static int alive(krb5_context, krb5_donot_replay *new, krb5_deltat t)
+  see if new is still alive; return CMP_EXPIRED or CMP_HOHUM
+CMP_MALLOC, CMP_EXPIRED, CMP_REPLAY, CMP_HOHUM
+  return codes from cmp(), alive(), and store()
+struct dfl_data
+  data stored in this cache type, namely "dfl"
+struct authlist
+  multilinked list of reps
+static int rc_store(context, krb5_rcache id, krb5_donot_replay *rep)
+  store rep in cache id; return CMP_REPLAY if replay, else CMP_MALLOC/CMP_HOHUM
+
+*/
+
+#ifndef HASHSIZE
+#define HASHSIZE 997 /* a convenient prime */
+#endif
+
+#ifndef EXCESSREPS
+#define EXCESSREPS 30
+#endif
+
+/*
+ * The rcache will be automatically expunged when the number of
+ * expired krb5_donot_replays encountered incidentally in searching
+ * exceeds the number of live krb5_donot_replays by EXCESSREPS. With
+ * the defaults here, a typical cache might build up some 10K of
+ * expired krb5_donot_replays before an automatic expunge, with the
+ * waste basically independent of the number of stores per minute.
+ *
+ * The rcache will also automatically be expunged when it encounters
+ * more than EXCESSREPS expired entries when recovering a cache in
+ * dfl_recover.
+ */
+
+static int
+hash(krb5_donot_replay *rep, int hsize)
+{
+    return (int) ((((rep->cusec + rep->ctime + *rep->server + *rep->client)
+		    % hsize) + hsize) % hsize);
+    /* We take this opportunity to once again complain about C's idiotic %. */
+}
+
+#define CMP_MALLOC -3
+#define CMP_EXPIRED -2
+#define CMP_REPLAY -1
+#define CMP_HOHUM 0
+
+/*ARGSUSED*/
+static int
+cmp(krb5_donot_replay *old, krb5_donot_replay *new1, krb5_deltat t)
+{
+    if ((old->cusec == new1->cusec) && /* most likely to distinguish */
+	(old->ctime == new1->ctime) &&
+	(strcmp(old->client, new1->client) == 0) &&
+	(strcmp(old->server, new1->server) == 0)) /* always true */
+	return CMP_REPLAY;
+    return CMP_HOHUM;
+}
+
+static int
+alive(krb5_int32 mytime, krb5_donot_replay *new1, krb5_deltat t)
+{
+    if (mytime == 0)
+	return CMP_HOHUM; /* who cares? */
+    /* I hope we don't have to worry about overflow */
+    if (new1->ctime + t < mytime)
+	return CMP_EXPIRED;
+    return CMP_HOHUM;
+}
+
+struct dfl_data
+{
+    char *name;
+    krb5_deltat lifespan;
+    int hsize;
+    int numhits;
+    int nummisses;
+    struct authlist **h;
+    struct authlist *a;
+#ifndef NOIOSTUFF
+    krb5_rc_iostuff d;
+#endif
+    char recovering;
+};
+
+struct authlist
+{
+    krb5_donot_replay rep;
+    struct authlist *na;
+    struct authlist *nh;
+};
+
+/* of course, list is backwards from file */
+/* hash could be forwards since we have to search on match, but naaaah */
+
+static int
+rc_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep,
+	 krb5_int32 now)
+{
+    struct dfl_data *t = (struct dfl_data *)id->data;
+    int rephash;
+    struct authlist *ta;
+
+    rephash = hash(rep, t->hsize);
+
+    for (ta = t->h[rephash]; ta; ta = ta->nh) {
+	switch(cmp(&ta->rep, rep, t->lifespan))
+	{
+	case CMP_REPLAY:
+	    return CMP_REPLAY;
+	case CMP_HOHUM:
+	    if (alive(now, &ta->rep, t->lifespan) == CMP_EXPIRED)
+		t->nummisses++;
+	    else
+		t->numhits++;
+	    break;
+	default:
+	    ; /* wtf? */
+	}
+    }
+
+    if (!(ta = (struct authlist *) malloc(sizeof(struct authlist))))
+	return CMP_MALLOC;
+    ta->na = t->a; t->a = ta;
+    ta->nh = t->h[rephash]; t->h[rephash] = ta;
+    ta->rep = *rep;
+    if (!(ta->rep.client = strdup(rep->client))) {
+	FREE(ta);
+	return CMP_MALLOC;
+    }
+    if (!(ta->rep.server = strdup(rep->server))) {
+	FREE(ta->rep.client);
+	FREE(ta);
+	return CMP_MALLOC;
+    }
+
+    return CMP_HOHUM;
+}
+
+char * KRB5_CALLCONV
+krb5_rc_dfl_get_name(krb5_context context, krb5_rcache id)
+{
+    return ((struct dfl_data *) (id->data))->name;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_get_span(krb5_context context, krb5_rcache id,
+		     krb5_deltat *lifespan)
+{
+    krb5_error_code err;
+    struct dfl_data *t;
+
+    err = k5_mutex_lock(&id->lock);
+    if (err)
+	return err;
+    t = (struct dfl_data *) id->data;
+    *lifespan = t->lifespan;
+    k5_mutex_unlock(&id->lock);
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_init_locked(krb5_context context, krb5_rcache id, krb5_deltat lifespan)
+{
+    struct dfl_data *t = (struct dfl_data *)id->data;
+    krb5_error_code retval;
+
+    t->lifespan = lifespan ? lifespan : context->clockskew;
+    /* default to clockskew from the context */
+#ifndef NOIOSTUFF
+    if ((retval = krb5_rc_io_creat(context, &t->d, &t->name))) {
+	return retval;
+    }
+    if ((krb5_rc_io_write(context, &t->d,
+			  (krb5_pointer) &t->lifespan, sizeof(t->lifespan))
+	 || krb5_rc_io_sync(context, &t->d))) {
+	return KRB5_RC_IO;
+    }
+#endif
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_init(krb5_context context, krb5_rcache id, krb5_deltat lifespan)
+{
+    krb5_error_code retval;
+
+    retval = k5_mutex_lock(&id->lock);
+    if (retval)
+	return retval;
+    retval = krb5_rc_dfl_init_locked(context, id, lifespan);
+    k5_mutex_unlock(&id->lock);
+    return retval;
+}
+
+/* Called with the mutex already locked.  */
+krb5_error_code
+krb5_rc_dfl_close_no_free(krb5_context context, krb5_rcache id)
+{
+    struct dfl_data *t = (struct dfl_data *)id->data;
+    struct authlist *q;
+
+    FREE(t->h);
+    if (t->name)
+	FREE(t->name);
+    while ((q = t->a))
+    {
+	t->a = q->na;
+	FREE(q->rep.client);
+	FREE(q->rep.server);
+	FREE(q);
+    }
+#ifndef NOIOSTUFF
+    (void) krb5_rc_io_close(context, &t->d);
+#endif
+    FREE(t);
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_close(krb5_context context, krb5_rcache id)
+{
+    krb5_error_code retval;
+    retval = k5_mutex_lock(&id->lock);
+    if (retval)
+	return retval;
+    krb5_rc_dfl_close_no_free(context, id);
+    k5_mutex_unlock(&id->lock);
+    k5_mutex_destroy(&id->lock);
+    free(id);
+    return 0;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_destroy(krb5_context context, krb5_rcache id)
+{
+#ifndef NOIOSTUFF
+    if (krb5_rc_io_destroy(context, &((struct dfl_data *) (id->data))->d))
+	return KRB5_RC_IO;
+#endif
+    return krb5_rc_dfl_close(context, id);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_resolve(krb5_context context, krb5_rcache id, char *name)
+{
+    struct dfl_data *t = 0;
+    krb5_error_code retval;
+
+    /* allocate id? no */
+    if (!(t = (struct dfl_data *) malloc(sizeof(struct dfl_data))))
+	return KRB5_RC_MALLOC;
+    id->data = (krb5_pointer) t;
+    memset(t, 0, sizeof(struct dfl_data));
+    if (name) {
+	t->name = malloc(strlen(name)+1);
+	if (!t->name) {
+	    retval = KRB5_RC_MALLOC;
+	    goto cleanup;
+	}
+	strcpy(t->name, name);
+    } else
+	t->name = 0;
+    t->numhits = t->nummisses = 0;
+    t->hsize = HASHSIZE; /* no need to store---it's memory-only */
+    t->h = (struct authlist **) malloc(t->hsize*sizeof(struct authlist *));
+    if (!t->h) {
+	retval = KRB5_RC_MALLOC;
+	goto cleanup;
+    }
+    memset(t->h, 0, t->hsize*sizeof(struct authlist *));
+    t->a = (struct authlist *) 0;
+#ifndef NOIOSTUFF
+    t->d.fd = -1;
+#endif
+    t->recovering = 0;
+    return 0;
+
+cleanup:
+    if (t) {
+	if (t->name)
+	    krb5_xfree(t->name);
+	if (t->h)
+	    krb5_xfree(t->h);
+	krb5_xfree(t);
+    }
+    return retval;
+}
+
+void
+krb5_rc_free_entry(krb5_context context, krb5_donot_replay **rep)
+{
+    krb5_donot_replay *rp = *rep;
+
+    *rep = NULL;
+    if (rp)
+    {
+	if (rp->client)
+	    free(rp->client);
+
+	if (rp->server)
+	    free(rp->server);
+	rp->client = NULL;
+	rp->server = NULL;
+	free(rp);
+    }
+}
+
+static krb5_error_code
+krb5_rc_io_fetch(krb5_context context, struct dfl_data *t,
+		 krb5_donot_replay *rep, int maxlen)
+{
+    int len2;
+    unsigned int len;
+    krb5_error_code retval;
+
+    rep->client = rep->server = 0;
+
+    retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len2,
+			     sizeof(len2));
+    if (retval)
+	return retval;
+
+    if ((len2 <= 0) || (len2 >= maxlen))
+	return KRB5_RC_IO_EOF;
+
+    len = len2;
+    rep->client = malloc (len);
+    if (!rep->client)
+	return KRB5_RC_MALLOC;
+
+    retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) rep->client, len);
+    if (retval)
+	goto errout;
+
+    retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &len2, 
+			     sizeof(len2));
+    if (retval)
+	goto errout;
+
+    if ((len2 <= 0) || (len2 >= maxlen)) {
+	retval = KRB5_RC_IO_EOF;
+	goto errout;
+    }
+    len = len2;
+
+    rep->server = malloc (len);
+    if (!rep->server) {
+	retval = KRB5_RC_MALLOC;
+	goto errout;
+    }
+
+    retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) rep->server, len);
+    if (retval)
+	goto errout;
+
+    retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &rep->cusec,
+			     sizeof(rep->cusec));
+    if (retval)
+	goto errout;
+
+    retval = krb5_rc_io_read(context, &t->d, (krb5_pointer) &rep->ctime,
+			     sizeof(rep->ctime));
+    if (retval)
+	goto errout;
+
+    return 0;
+
+errout:
+    if (rep->client)
+	krb5_xfree(rep->client);
+    if (rep->server)
+	krb5_xfree(rep->server);
+    rep->client = rep->server = 0;
+    return retval;
+}
+
+
+static krb5_error_code
+krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id);
+
+static krb5_error_code
+krb5_rc_dfl_recover_locked(krb5_context context, krb5_rcache id)
+{
+#ifdef NOIOSTUFF
+    return KRB5_RC_NOIO;
+#else
+
+    struct dfl_data *t = (struct dfl_data *)id->data;
+    krb5_donot_replay *rep = 0;
+    krb5_error_code retval;
+    long max_size;
+    int expired_entries = 0;
+    krb5_int32 now;
+
+    if ((retval = krb5_rc_io_open(context, &t->d, t->name))) {
+	return retval;
+    }
+
+    t->recovering = 1;
+
+    max_size = krb5_rc_io_size(context, &t->d);
+
+    rep = NULL;
+    if (krb5_rc_io_read(context, &t->d, (krb5_pointer) &t->lifespan,
+			sizeof(t->lifespan))) {
+	retval = KRB5_RC_IO;
+	goto io_fail;
+    }
+
+    if (!(rep = (krb5_donot_replay *) malloc(sizeof(krb5_donot_replay)))) {
+	retval = KRB5_RC_MALLOC;
+	goto io_fail;
+    }
+    rep->client = NULL;
+    rep->server = NULL;
+
+    if (krb5_timeofday(context, &now))
+	now = 0;
+
+    /* now read in each auth_replay and insert into table */
+    for (;;) {
+	if (krb5_rc_io_mark(context, &t->d)) {
+	    retval = KRB5_RC_IO;
+	    goto io_fail;
+	}
+
+	retval = krb5_rc_io_fetch(context, t, rep, (int) max_size);
+
+	if (retval == KRB5_RC_IO_EOF)
+	    break;
+	else if (retval != 0)
+	    goto io_fail;
+
+
+	if (alive(now, rep, t->lifespan) != CMP_EXPIRED) {
+	    if (rc_store(context, id, rep, now) == CMP_MALLOC) {
+		retval = KRB5_RC_MALLOC; goto io_fail;
+	    }
+	} else {
+	    expired_entries++;
+	}
+	/*
+	 *  free fields allocated by rc_io_fetch
+	 */
+	FREE(rep->server);
+	FREE(rep->client);
+	rep->server = 0;
+	rep->client = 0;
+    }
+    retval = 0;
+    krb5_rc_io_unmark(context, &t->d);
+    /*
+     *  An automatic expunge here could remove the need for
+     *  mark/unmark but that would be inefficient.
+     */
+io_fail:
+    krb5_rc_free_entry(context, &rep);
+    if (retval)
+	krb5_rc_io_close(context, &t->d);
+    else if (expired_entries > EXCESSREPS)
+	retval = krb5_rc_dfl_expunge_locked(context, id);
+    t->recovering = 0;
+    return retval;
+
+#endif
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_recover(krb5_context context, krb5_rcache id)
+{
+    krb5_error_code ret;
+    ret = k5_mutex_lock(&id->lock);
+    if (ret)
+	return ret;
+    ret = krb5_rc_dfl_recover_locked(context, id);
+    k5_mutex_unlock(&id->lock);
+    return ret;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_recover_or_init(krb5_context context, krb5_rcache id,
+			    krb5_deltat lifespan)
+{
+    krb5_error_code retval;
+
+    retval = k5_mutex_lock(&id->lock);
+    if (retval)
+	return retval;
+    retval = krb5_rc_dfl_recover_locked(context, id);
+    if (retval)
+	retval = krb5_rc_dfl_init_locked(context, id, lifespan);
+    k5_mutex_unlock(&id->lock);
+    return retval;
+}
+
+static krb5_error_code
+krb5_rc_io_store(krb5_context context, struct dfl_data *t,
+		 krb5_donot_replay *rep)
+{
+    unsigned int clientlen, serverlen, len;
+    char *buf, *ptr;
+    krb5_error_code ret;
+
+    clientlen = strlen(rep->client) + 1;
+    serverlen = strlen(rep->server) + 1;
+    len = sizeof(clientlen) + clientlen + sizeof(serverlen) + serverlen +
+	sizeof(rep->cusec) + sizeof(rep->ctime);
+    buf = malloc(len);
+    if (buf == 0)
+	return KRB5_RC_MALLOC;
+    ptr = buf;
+    memcpy(ptr, &clientlen, sizeof(clientlen)); ptr += sizeof(clientlen);
+    memcpy(ptr, rep->client, clientlen); ptr += clientlen;
+    memcpy(ptr, &serverlen, sizeof(serverlen)); ptr += sizeof(serverlen);
+    memcpy(ptr, rep->server, serverlen); ptr += serverlen;
+    memcpy(ptr, &rep->cusec, sizeof(rep->cusec)); ptr += sizeof(rep->cusec);
+    memcpy(ptr, &rep->ctime, sizeof(rep->ctime)); ptr += sizeof(rep->ctime);
+
+    ret = krb5_rc_io_write(context, &t->d, buf, len);
+    free(buf);
+    return ret;
+}
+
+static krb5_error_code krb5_rc_dfl_expunge_locked(krb5_context, krb5_rcache);
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_store(krb5_context context, krb5_rcache id, krb5_donot_replay *rep)
+{
+    krb5_error_code ret;
+    struct dfl_data *t;
+    krb5_int32 now;
+
+    ret = krb5_timeofday(context, &now);
+    if (ret)
+	return ret;
+
+    ret = k5_mutex_lock(&id->lock);
+    if (ret)
+	return ret;
+
+    switch(rc_store(context, id, rep, now)) {
+    case CMP_MALLOC:
+	k5_mutex_unlock(&id->lock);
+	return KRB5_RC_MALLOC;
+    case CMP_REPLAY:
+	k5_mutex_unlock(&id->lock);
+	return KRB5KRB_AP_ERR_REPEAT;
+    case 0: break;
+    default: /* wtf? */ ;
+    }
+    t = (struct dfl_data *)id->data;
+#ifndef NOIOSTUFF
+    ret = krb5_rc_io_store(context, t, rep);
+    if (ret) {
+	k5_mutex_unlock(&id->lock);
+	return ret;
+    }
+#endif
+    /* Shall we automatically expunge? */
+    if (t->nummisses > t->numhits + EXCESSREPS)
+    {
+	ret = krb5_rc_dfl_expunge_locked(context, id);
+	k5_mutex_unlock(&id->lock);
+	return ret;
+    }
+#ifndef NOIOSTUFF
+    else
+    {
+	if (krb5_rc_io_sync(context, &t->d)) {
+	    k5_mutex_unlock(&id->lock);
+	    return KRB5_RC_IO;
+	}
+    }
+#endif
+    k5_mutex_unlock(&id->lock);
+    return 0;
+}
+
+static krb5_error_code
+krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id)
+{
+    struct dfl_data *t = (struct dfl_data *)id->data;
+#ifdef NOIOSTUFF
+    int i;
+    struct authlist **q;
+    struct authlist **qt;
+    struct authlist *r;
+    struct authlist *rt;
+    krb5_int32 now;
+
+    if (krb5_timestamp(context, &now))
+	now = 0;
+
+    for (q = &t->a; *q; q = qt) {
+	qt = &(*q)->na;
+	if (alive(now, &(*q)->rep, t->lifespan) == CMP_EXPIRED) {
+	    FREE((*q)->rep.client);
+	    FREE((*q)->rep.server);
+	    FREE(*q);
+	    *q = *qt; /* why doesn't this feel right? */
+	}
+    }
+    for (i = 0; i < t->hsize; i++)
+	t->h[i] = (struct authlist *) 0;
+    for (r = t->a; r; r = r->na) {
+	i = hash(&r->rep, t->hsize);
+	rt = t->h[i];
+	t->h[i] = r;
+	r->nh = rt;
+    }
+    return 0;
+#else
+    struct authlist *q;
+    char *name;
+    krb5_error_code retval = 0;
+    krb5_rcache tmp;
+    krb5_deltat lifespan = t->lifespan;  /* save original lifespan */
+
+    if (! t->recovering) {
+	name = t->name;
+	t->name = 0;		/* Clear name so it isn't freed */
+	(void) krb5_rc_dfl_close_no_free(context, id);
+	retval = krb5_rc_dfl_resolve(context, id, name);
+	free(name);
+	if (retval)
+	    return retval;
+	retval = krb5_rc_dfl_recover_locked(context, id);
+	if (retval)
+	    return retval;
+	t = (struct dfl_data *)id->data; /* point to recovered cache */
+    }
+
+    tmp = (krb5_rcache) malloc(sizeof(*tmp));
+    if (!tmp)
+	return ENOMEM;
+    retval = krb5_rc_resolve_type(context, &tmp, "dfl");
+    if (retval) {
+        free(tmp);
+        return retval;
+    }
+    retval = krb5_rc_resolve(context, tmp, 0);
+    if (retval)
+        goto cleanup;
+    retval = krb5_rc_initialize(context, tmp, lifespan);
+    if (retval)
+        goto cleanup;
+    for (q = t->a; q; q = q->na) {
+	if (krb5_rc_io_store(context, (struct dfl_data *)tmp->data, &q->rep)) {
+            retval = KRB5_RC_IO;
+            goto cleanup;
+        }
+    }
+    /* NOTE: We set retval in case we have an error */
+    retval = KRB5_RC_IO;
+    if (krb5_rc_io_sync(context, &((struct dfl_data *)tmp->data)->d))
+        goto cleanup;
+    if (krb5_rc_io_sync(context, &t->d))
+        goto cleanup;
+    if (krb5_rc_io_move(context, &t->d, &((struct dfl_data *)tmp->data)->d))
+        goto cleanup;
+    retval = 0;
+ cleanup:
+    (void) krb5_rc_dfl_close(context, tmp);
+    return retval;
+#endif
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_dfl_expunge(krb5_context context, krb5_rcache id)
+{
+    krb5_error_code ret;
+    ret = k5_mutex_lock(&id->lock);
+    if (ret)
+	return ret;
+    ret = krb5_rc_dfl_expunge_locked(context, id);
+    k5_mutex_unlock(&id->lock);
+    return ret;
+}
diff --git a/mechglue/src/lib/krb5/rcache/rc_dfl.h b/mechglue/src/lib/krb5/rcache/rc_dfl.h
new file mode 100644
index 000000000..d5fdd1a69
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc_dfl.h
@@ -0,0 +1,56 @@
+/*
+ * lib/krb5/rcache/rc_dfl.h
+ *
+ * This file of the Kerberos V5 software is derived from public-domain code
+ * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
+ *
+ */
+
+/*
+ * Declarations for the default replay cache implementation.
+ */
+
+#ifndef KRB5_RC_DFL_H
+#define KRB5_RC_DFL_H
+
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_init 
+    	(krb5_context,
+		   krb5_rcache,
+		   krb5_deltat);
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_recover 
+	(krb5_context,
+		   krb5_rcache); 
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_recover_or_init
+    	(krb5_context, krb5_rcache, krb5_deltat);
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_destroy 
+	(krb5_context,
+		   krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_close 
+	(krb5_context,
+		   krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_store 
+	(krb5_context,
+		   krb5_rcache,
+		   krb5_donot_replay *);
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_expunge 
+	(krb5_context,
+		   krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_get_span 
+	(krb5_context,
+		   krb5_rcache,
+		   krb5_deltat *);
+char * KRB5_CALLCONV krb5_rc_dfl_get_name 
+	(krb5_context,
+		   krb5_rcache);
+krb5_error_code KRB5_CALLCONV krb5_rc_dfl_resolve 
+	(krb5_context,
+		   krb5_rcache,
+		   char *);
+krb5_error_code krb5_rc_dfl_close_no_free
+	(krb5_context,
+		   krb5_rcache);
+void krb5_rc_free_entry 
+	(krb5_context,
+		   krb5_donot_replay **);
+#endif
+
diff --git a/mechglue/src/lib/krb5/rcache/rc_io.c b/mechglue/src/lib/krb5/rcache/rc_io.c
new file mode 100644
index 000000000..52b57e44f
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc_io.c
@@ -0,0 +1,453 @@
+/*
+ * lib/krb5/rcache/rc_io.c
+ *
+ * This file of the Kerberos V5 software is derived from public-domain code
+ * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
+ *
+ */
+
+
+/*
+ * I/O functions for the replay cache default implementation.
+ */
+
+#if defined(_WIN32)
+#  define PATH_SEPARATOR "\\"
+#else
+#  define PATH_SEPARATOR "/"
+#endif
+
+#define KRB5_RC_VNO	0x0501		/* krb5, rcache v 1 */
+
+#include "k5-int.h"
+#include <stdio.h> /* for P_tmpdir */
+#include "rc_base.h"
+#include "rc_dfl.h"
+#include "rc_io.h"
+
+#ifndef O_BINARY
+#define O_BINARY    0
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#if !defined(_WINSOCKAPI_)
+#include <netinet/in.h>
+#endif
+#else
+#error find some way to use net-byte-order file version numbers.
+#endif
+
+#define FREE(x) ((void) free((char *) (x)))
+#define UNIQUE getpid() /* hopefully unique number */
+
+#define GETDIR (dir = getdir(), dirlen = strlen(dir) + sizeof(PATH_SEPARATOR) - 1)
+
+static char *
+getdir(void)
+{
+    char *dir;
+
+    if (!(dir = getenv("KRB5RCACHEDIR"))) {
+#if defined(_WIN32)
+	if (!(dir = getenv("TEMP")))
+	    if (!(dir = getenv("TMP")))
+		dir = "C:";
+#else
+	if (!(dir = getenv("TMPDIR"))) {
+#ifdef RCTMPDIR
+	    dir = RCTMPDIR;
+#else
+	    dir = "/tmp";
+#endif
+	}
+#endif
+    }
+    return dir;
+}
+
+krb5_error_code
+krb5_rc_io_creat(krb5_context context, krb5_rc_iostuff *d, char **fn)
+{
+    char *c;
+    krb5_int16 rc_vno = htons(KRB5_RC_VNO);
+    krb5_error_code retval = 0;
+    int do_not_unlink = 0;
+    char *dir;
+    size_t dirlen;
+
+    GETDIR;
+    if (fn && *fn)
+    {
+	if (!(d->fn = malloc(strlen(*fn) + dirlen + 1)))
+	    return KRB5_RC_IO_MALLOC;
+	(void) strcpy(d->fn, dir);
+	(void) strcat(d->fn, PATH_SEPARATOR);
+	(void) strcat(d->fn, *fn);
+	d->fd = THREEPARAMOPEN(d->fn, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL |
+			       O_BINARY, 0600);
+    }
+    else
+    {
+	/* %d is max 11 digits (-, 10 digits of 32-bit number)
+	 * 11 + /krb5_RC + aaa = 24, +6 for slop */
+	if (!(d->fn = malloc(30 + dirlen)))
+	    return KRB5_RC_IO_MALLOC;
+	if (fn)
+	    if (!(*fn = malloc(35))) {
+		FREE(d->fn);
+		return KRB5_RC_IO_MALLOC;
+	    }
+	(void) sprintf(d->fn, "%s%skrb5_RC%d", dir, PATH_SEPARATOR,
+		       (int) UNIQUE);
+	c = d->fn + strlen(d->fn);
+	(void) strcpy(c, "aaa");
+	while ((d->fd = THREEPARAMOPEN(d->fn, O_WRONLY | O_CREAT | O_TRUNC |
+				       O_EXCL | O_BINARY, 0600)) == -1)
+	{
+	    if ((c[2]++) == 'z')
+	    {
+		c[2] = 'a';
+		if ((c[1]++) == 'z')
+		{
+		    c[1] = 'a';
+		    if ((c[0]++) == 'z')
+			break; /* sigh */
+		}
+	    }
+	}
+	if (fn)
+	    (void) strcpy(*fn, d->fn + dirlen);
+    }
+    if (d->fd == -1)
+    {
+	switch(errno)
+	{
+	case EFBIG:
+#ifdef EDQUOT
+	case EDQUOT:
+#endif
+	case ENOSPC:
+	    retval = KRB5_RC_IO_SPACE;
+	    goto cleanup;
+
+	case EIO:
+	    retval = KRB5_RC_IO_IO;
+	    goto cleanup;
+
+	case EPERM:
+	case EACCES:
+	case EROFS:
+	case EEXIST:
+	    retval = KRB5_RC_IO_PERM;
+	    do_not_unlink = 1;
+	    goto cleanup;
+
+	default:
+	    retval = KRB5_RC_IO_UNKNOWN;
+	    goto cleanup;
+	}
+    }
+    retval = krb5_rc_io_write(context, d, (krb5_pointer)&rc_vno,
+			      sizeof(rc_vno));
+    if (retval)
+	goto cleanup;
+
+    retval = krb5_rc_io_sync(context, d);
+
+ cleanup:
+    if (retval) {
+	if (d->fn) {
+	    if (!do_not_unlink)
+		(void) unlink(d->fn);
+	    FREE(d->fn);
+	    d->fn = NULL;
+	}
+	(void) close(d->fd);
+    }
+    return retval;
+}
+
+static krb5_error_code
+krb5_rc_io_open_internal(krb5_context context, krb5_rc_iostuff *d, char *fn,
+			 char* full_pathname)
+{
+    krb5_int16 rc_vno;
+    krb5_error_code retval = 0;
+    int do_not_unlink = 1;
+#ifndef NO_USERID
+    struct stat statb;
+#endif
+    char *dir;
+    size_t dirlen;
+
+    GETDIR;
+    if (full_pathname) {
+	if (!(d->fn = malloc(strlen(full_pathname) + 1)))
+	    return KRB5_RC_IO_MALLOC;
+	(void) strcpy(d->fn, full_pathname);
+    } else {
+	if (!(d->fn = malloc(strlen(fn) + dirlen + 1)))
+	    return KRB5_RC_IO_MALLOC;
+	(void) strcpy(d->fn, dir);
+	(void) strcat(d->fn, PATH_SEPARATOR);
+	(void) strcat(d->fn, fn);
+    }
+
+#ifdef NO_USERID
+    d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
+#else
+    if ((d->fd = stat(d->fn, &statb)) != -1) {
+	uid_t me;
+
+	me = geteuid();
+	/* must be owned by this user, to prevent some security problems with
+	 * other users modifying replay cache stufff */
+	if ((statb.st_uid != me) || ((statb.st_mode & S_IFMT) != S_IFREG)) {
+	    FREE(d->fn);
+	    return KRB5_RC_IO_PERM;
+	}
+	d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600);
+    }
+#endif
+    if (d->fd == -1) {
+	switch(errno)
+	{
+	case EFBIG:
+#ifdef EDQUOT
+	case EDQUOT:
+#endif
+	case ENOSPC:
+	    retval = KRB5_RC_IO_SPACE;
+	    goto cleanup;
+
+	case EIO:
+	    retval = KRB5_RC_IO_IO;
+	    goto cleanup;
+
+	case EPERM:
+	case EACCES:
+	case EROFS:
+	    retval = KRB5_RC_IO_PERM;
+	    goto cleanup;
+
+	default:
+	    retval = KRB5_RC_IO_UNKNOWN;
+	    goto cleanup;
+	}
+    }
+
+    do_not_unlink = 0;
+    retval = krb5_rc_io_read(context, d, (krb5_pointer) &rc_vno,
+			     sizeof(rc_vno));
+    if (retval)
+	goto cleanup;
+
+    if (ntohs(rc_vno) != KRB5_RC_VNO)
+	retval = KRB5_RCACHE_BADVNO;
+
+ cleanup:
+    if (retval) {
+	if (d->fn) {
+	    if (!do_not_unlink)
+		(void) unlink(d->fn);
+	    FREE(d->fn);
+	    d->fn = NULL;
+	}
+	if (d->fd >= 0) 
+	     (void) close(d->fd);
+    }
+    return retval;
+}
+
+krb5_error_code
+krb5_rc_io_open(krb5_context context, krb5_rc_iostuff *d, char *fn)
+{
+    return krb5_rc_io_open_internal(context, d, fn, NULL);
+}
+
+krb5_error_code
+krb5_rc_io_move(krb5_context context, krb5_rc_iostuff *new1,
+		krb5_rc_iostuff *old)
+{
+#if defined(_WIN32)
+    char *new_fn = NULL;
+    char *old_fn = NULL;
+    off_t offset = 0;
+    krb5_error_code retval = 0;
+    /*
+     * Initial work around provided by Tom Sanfilippo to work around
+     * poor Windows emulation of POSIX functions.  Rename and dup has
+     * different semantics!
+     *
+     * Additional fixes and explanation provided by dalmeida@mit.edu:
+     *
+     * First, we save the offset of "old".  Then, we close and remove
+     * the "new" file so we can do the rename.  We also close "old" to
+     * make sure the rename succeeds (though that might not be
+     * necessary on some systems).
+     *
+     * Next, we do the rename.  If all goes well, we seek the "new"
+     * file to the position "old" was at.
+     *
+     * --- WARNING!!! ---
+     *
+     * Since "old" is now gone, we mourn its disappearance, but we
+     * cannot emulate that Unix behavior...  THIS BEHAVIOR IS
+     * DIFFERENT FROM UNIX.  However, it is ok because this function
+     * gets called such that "old" gets closed right afterwards.
+     */
+    offset = lseek(old->fd, 0, SEEK_CUR);
+
+    new_fn = new1->fn;
+    new1->fn = NULL;
+    close(new1->fd);
+    new1->fd = -1;
+
+    unlink(new_fn);
+
+    old_fn = old->fn;
+    old->fn = NULL;
+    close(old->fd);
+    old->fd = -1;
+
+    if (rename(old_fn, new_fn) == -1) { /* MUST be atomic! */
+	retval = KRB5_RC_IO_UNKNOWN;
+	goto cleanup;
+    }
+
+    retval = krb5_rc_io_open_internal(context, new1, 0, new_fn);
+    if (retval)
+	goto cleanup;
+
+    if (lseek(new1->fd, offset, SEEK_SET) == -1) {
+	retval = KRB5_RC_IO_UNKNOWN;
+	goto cleanup;
+    }
+
+ cleanup:
+    free(new_fn);
+    free(old_fn);
+    return retval;
+#else
+    char *fn = NULL;
+    if (rename(old->fn, new1->fn) == -1) /* MUST be atomic! */
+	return KRB5_RC_IO_UNKNOWN;
+    fn = new1->fn;
+    new1->fn = NULL;		/* avoid clobbering */
+    (void) krb5_rc_io_close(context, new1);
+    new1->fn = fn;
+    new1->fd = dup(old->fd);
+    return 0;
+#endif
+}
+
+krb5_error_code
+krb5_rc_io_write(krb5_context context, krb5_rc_iostuff *d, krb5_pointer buf,
+		 unsigned int num)
+{
+    if (write(d->fd, (char *) buf, num) == -1)
+	switch(errno)
+	{
+	case EBADF: return KRB5_RC_IO_UNKNOWN;
+	case EFBIG: return KRB5_RC_IO_SPACE;
+#ifdef EDQUOT
+	case EDQUOT: return KRB5_RC_IO_SPACE;
+#endif
+	case ENOSPC: return KRB5_RC_IO_SPACE;
+	case EIO: return KRB5_RC_IO_IO;
+	default: return KRB5_RC_IO_UNKNOWN;
+	}
+    return 0;
+}
+
+krb5_error_code
+krb5_rc_io_sync(krb5_context context, krb5_rc_iostuff *d)
+{
+#if defined(_WIN32)
+#ifndef fsync
+#define fsync _commit
+#endif
+#endif
+    if (fsync(d->fd) == -1) {
+	switch(errno)
+	{
+	case EBADF: return KRB5_RC_IO_UNKNOWN;
+	case EIO: return KRB5_RC_IO_IO;
+	default: return KRB5_RC_IO_UNKNOWN;
+	}
+    }
+    return 0;
+}
+
+krb5_error_code
+krb5_rc_io_read(krb5_context context, krb5_rc_iostuff *d, krb5_pointer buf,
+		unsigned int num)
+{
+    int count;
+    if ((count = read(d->fd, (char *) buf, num)) == -1)
+	switch(errno)
+	{
+	case EBADF: return KRB5_RC_IO_UNKNOWN;
+	case EIO: return KRB5_RC_IO_IO;
+	default: return KRB5_RC_IO_UNKNOWN;
+	}
+    if (count == 0)
+	return KRB5_RC_IO_EOF;
+    return 0;
+}
+
+krb5_error_code
+krb5_rc_io_close(krb5_context context, krb5_rc_iostuff *d)
+{
+    if (d->fn != NULL) {
+	FREE(d->fn);
+	d->fn = NULL;
+    }
+    if (d->fd != -1) {
+	if (close(d->fd) == -1) /* can't happen */
+	    return KRB5_RC_IO_UNKNOWN;
+	d->fd = -1;
+    }
+    return 0;
+}
+
+krb5_error_code
+krb5_rc_io_destroy(krb5_context context, krb5_rc_iostuff *d)
+{
+    if (unlink(d->fn) == -1)
+	switch(errno)
+	{
+	case EBADF: return KRB5_RC_IO_UNKNOWN;
+	case EIO: return KRB5_RC_IO_IO;
+	case EPERM: return KRB5_RC_IO_PERM;
+	case EBUSY: return KRB5_RC_IO_PERM;
+	case EROFS: return KRB5_RC_IO_PERM;
+	default: return KRB5_RC_IO_UNKNOWN;
+	}
+    return 0;
+}
+
+krb5_error_code
+krb5_rc_io_mark(krb5_context context, krb5_rc_iostuff *d)
+{
+    d->mark = lseek(d->fd, (off_t) 0, SEEK_CUR); /* can't fail */
+    return 0;
+}
+
+krb5_error_code
+krb5_rc_io_unmark(krb5_context context, krb5_rc_iostuff *d)
+{
+    (void) lseek(d->fd, d->mark, SEEK_SET); /* if it fails, tough luck */
+    return 0;
+}
+
+long
+krb5_rc_io_size(krb5_context context, krb5_rc_iostuff *d)
+{
+    struct stat statb;
+
+    if (fstat(d->fd, &statb) == 0)
+	return statb.st_size;
+    else
+	return 0;
+}
diff --git a/mechglue/src/lib/krb5/rcache/rc_io.h b/mechglue/src/lib/krb5/rcache/rc_io.h
new file mode 100644
index 000000000..77eb34f0b
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc_io.h
@@ -0,0 +1,70 @@
+/*
+ * lib/krb5/rcache/rc_io.h
+ *
+ * This file of the Kerberos V5 software is derived from public-domain code
+ * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
+ *
+ */
+
+/*
+ * Declarations for the I/O sub-package of the replay cache
+ */
+
+#ifndef KRB5_RC_IO_H
+#define KRB5_RC_IO_H
+
+typedef struct krb5_rc_iostuff
+ {
+  int fd;
+#ifdef MSDOS_FILESYSTEM
+  long mark;
+#else
+  off_t mark; /* on newer systems, should be pos_t */
+#endif
+  char *fn;
+ }
+krb5_rc_iostuff;
+
+/* first argument is always iostuff for result file */
+
+krb5_error_code krb5_rc_io_creat 
+	(krb5_context,
+		   krb5_rc_iostuff *,
+		   char **);
+krb5_error_code krb5_rc_io_open 
+	(krb5_context,
+		   krb5_rc_iostuff *,
+		   char *);
+krb5_error_code krb5_rc_io_move 
+	(krb5_context,
+		   krb5_rc_iostuff *,
+		   krb5_rc_iostuff *);
+krb5_error_code krb5_rc_io_write 
+	(krb5_context,
+		   krb5_rc_iostuff *,
+		   krb5_pointer,
+		   unsigned int);
+krb5_error_code krb5_rc_io_read 
+	(krb5_context,
+		   krb5_rc_iostuff *,
+		   krb5_pointer,
+		   unsigned int);
+krb5_error_code krb5_rc_io_close 
+	(krb5_context,
+		   krb5_rc_iostuff *);
+krb5_error_code krb5_rc_io_destroy 
+	(krb5_context,
+		   krb5_rc_iostuff *);
+krb5_error_code krb5_rc_io_mark 
+	(krb5_context,
+		   krb5_rc_iostuff *);
+krb5_error_code krb5_rc_io_unmark 
+	(krb5_context,
+		   krb5_rc_iostuff *);
+krb5_error_code krb5_rc_io_sync
+	(krb5_context,
+		   krb5_rc_iostuff *);
+long krb5_rc_io_size
+	(krb5_context,
+		   krb5_rc_iostuff *);
+#endif
diff --git a/mechglue/src/lib/krb5/rcache/rc_none.c b/mechglue/src/lib/krb5/rcache/rc_none.c
new file mode 100644
index 000000000..a306f86fe
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rc_none.c
@@ -0,0 +1,88 @@
+/*
+ * lib/krb5/rcache/rc_none.c
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * replay cache no-op implementation
+ */
+
+#include "k5-int.h"
+#include "rc-int.h"
+
+static krb5_error_code KRB5_CALLCONV
+krb5_rc_none_init(krb5_context ctx, krb5_rcache rc, krb5_deltat d)
+{
+    return 0;
+}
+#define krb5_rc_none_recover_or_init krb5_rc_none_init
+
+static krb5_error_code KRB5_CALLCONV
+krb5_rc_none_noargs(krb5_context ctx, krb5_rcache rc)
+{
+    return 0;
+}
+#define krb5_rc_none_recover	krb5_rc_none_noargs
+#define krb5_rc_none_destroy	krb5_rc_none_noargs
+#define krb5_rc_none_close	krb5_rc_none_noargs
+#define krb5_rc_none_expunge	krb5_rc_none_noargs
+
+static krb5_error_code KRB5_CALLCONV
+krb5_rc_none_store(krb5_context ctx, krb5_rcache rc, krb5_donot_replay *r)
+{
+    return 0;
+}
+
+static krb5_error_code KRB5_CALLCONV
+krb5_rc_none_get_span(krb5_context ctx, krb5_rcache rc, krb5_deltat *d)
+{
+    return 0;
+}
+
+static char * KRB5_CALLCONV
+krb5_rc_none_get_name(krb5_context ctx, krb5_rcache rc)
+{
+    return "";
+}
+
+static krb5_error_code KRB5_CALLCONV
+krb5_rc_none_resolve(krb5_context ctx, krb5_rcache rc, char *name)
+{
+    rc->data = "none";
+    return 0;
+}
+
+const krb5_rc_ops krb5_rc_none_ops = {
+    0,
+    "none",
+    krb5_rc_none_init,
+    krb5_rc_none_recover,
+    krb5_rc_none_recover_or_init,
+    krb5_rc_none_destroy,
+    krb5_rc_none_close,
+    krb5_rc_none_store,
+    krb5_rc_none_expunge,
+    krb5_rc_none_get_span,
+    krb5_rc_none_get_name,
+    krb5_rc_none_resolve
+};
diff --git a/mechglue/src/lib/krb5/rcache/rcdef.c b/mechglue/src/lib/krb5/rcache/rcdef.c
new file mode 100644
index 000000000..0aa334fa8
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rcdef.c
@@ -0,0 +1,49 @@
+/*
+ * lib/krb5/rcache/rcdef.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * replay cache default operations vector.
+ */
+
+#include "k5-int.h"
+#include "rc-int.h"
+#include "rc_dfl.h"
+
+const krb5_rc_ops krb5_rc_dfl_ops =
+ {
+  0,
+  "dfl",
+  krb5_rc_dfl_init,
+  krb5_rc_dfl_recover,
+  krb5_rc_dfl_recover_or_init,
+  krb5_rc_dfl_destroy,
+  krb5_rc_dfl_close,
+  krb5_rc_dfl_store,
+  krb5_rc_dfl_expunge,
+  krb5_rc_dfl_get_span,
+  krb5_rc_dfl_get_name,
+  krb5_rc_dfl_resolve
+ }
+;
diff --git a/mechglue/src/lib/krb5/rcache/rcfns.c b/mechglue/src/lib/krb5/rcache/rcfns.c
new file mode 100644
index 000000000..bcbcaf4be
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/rcfns.c
@@ -0,0 +1,95 @@
+/*
+ * lib/krb5/rcache/rcfns.c
+ *
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * Dispatch methods for replay cache code.
+ */
+
+#include "k5-int.h"
+#include "rc-int.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_initialize (krb5_context context, krb5_rcache id, krb5_deltat span)
+{
+    return krb5_x(id->ops->init,(context, id, span));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_recover_or_initialize (krb5_context context, krb5_rcache id,
+			       krb5_deltat span)
+{
+    return krb5_x(id->ops->recover_or_init,(context, id, span));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_recover (krb5_context context, krb5_rcache id)
+{
+    return krb5_x((id)->ops->recover,(context, id));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_destroy (krb5_context context, krb5_rcache id)
+{
+    return krb5_x((id)->ops->destroy,(context, id));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_close (krb5_context context, krb5_rcache id)
+{
+    return krb5_x((id)->ops->close,(context, id));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_store (krb5_context context, krb5_rcache id,
+	       krb5_donot_replay *dontreplay)
+{
+    return krb5_x((id)->ops->store,(context, id, dontreplay));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_expunge (krb5_context context, krb5_rcache id)
+{
+    return krb5_x((id)->ops->expunge,(context, id));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_get_lifespan (krb5_context context, krb5_rcache id,
+		      krb5_deltat *spanp)
+{
+    return krb5_x((id)->ops->get_span,(context, id, spanp));
+}
+
+char *KRB5_CALLCONV
+krb5_rc_get_name (krb5_context context, krb5_rcache id)
+{
+    return krb5_xc((id)->ops->get_name,(context, id));
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_rc_resolve (krb5_context context, krb5_rcache id, char *name)
+{
+    return krb5_x((id)->ops->resolve,(context, id, name));
+}
diff --git a/mechglue/src/lib/krb5/rcache/ser_rc.c b/mechglue/src/lib/krb5/rcache/ser_rc.c
new file mode 100644
index 000000000..0b3d098a8
--- /dev/null
+++ b/mechglue/src/lib/krb5/rcache/ser_rc.c
@@ -0,0 +1,208 @@
+/*
+ * lib/krb5/rcache/ser_rc.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * ser_rcdfl.c - Serialize replay cache context.
+ */
+#include "k5-int.h"
+#include "rc-int.h"
+
+/*
+ * Routines to deal with externalizing krb5_rcache.
+ *	krb5_rcache_size();
+ *	krb5_rcache_externalize();
+ *	krb5_rcache_internalize();
+ */
+static krb5_error_code krb5_rcache_size
+	(krb5_context, krb5_pointer, size_t *);
+static krb5_error_code krb5_rcache_externalize
+	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
+static krb5_error_code krb5_rcache_internalize
+	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
+
+/*
+ * Serialization entry for this type.
+ */
+static const krb5_ser_entry krb5_rcache_ser_entry = {
+    KV5M_RCACHE,			/* Type			*/
+    krb5_rcache_size,			/* Sizer routine	*/
+    krb5_rcache_externalize,		/* Externalize routine	*/
+    krb5_rcache_internalize		/* Internalize routine	*/
+};
+
+/*
+ * krb5_rcache_size()	- Determine the size required to externalize
+ *				  this krb5_rcache variant.
+ */
+static krb5_error_code
+krb5_rcache_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
+{
+    krb5_error_code	kret;
+    krb5_rcache		rcache;
+    size_t		required;
+
+    kret = EINVAL;
+    if ((rcache = (krb5_rcache) arg)) {
+	/*
+	 * Saving FILE: variants of krb5_rcache requires at minimum:
+	 *	krb5_int32	for KV5M_RCACHE
+	 *	krb5_int32	for length of rcache name.
+	 *	krb5_int32	for KV5M_RCACHE
+	 */
+	required = sizeof(krb5_int32) * 3;
+	if (rcache->ops && rcache->ops->type)
+	    required += (strlen(rcache->ops->type)+1);
+
+	/*
+	 * The rcache name is formed as follows:
+	 *	<type>:<name>
+	 */
+	required += strlen(krb5_rc_get_name(kcontext, rcache));
+
+	kret = 0;
+	*sizep += required;
+    }
+    return(kret);
+}
+
+/*
+ * krb5_rcache_externalize()	- Externalize the krb5_rcache.
+ */
+static krb5_error_code
+krb5_rcache_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_rcache		rcache;
+    size_t		required;
+    krb5_octet		*bp;
+    size_t		remain;
+    char		*rcname;
+    size_t		namelen;
+    char		*fnamep;
+
+    required = 0;
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    if ((rcache = (krb5_rcache) arg)) {
+	kret = ENOMEM;
+	if (!krb5_rcache_size(kcontext, arg, &required) &&
+	    (required <= remain)) {
+	    /* Our identifier */
+	    (void) krb5_ser_pack_int32(KV5M_RCACHE, &bp, &remain);
+
+	    /* Calculate the length of the name */
+	    namelen = (rcache->ops && rcache->ops->type) ?
+		strlen(rcache->ops->type)+1 : 0;
+	    fnamep = krb5_rc_get_name(kcontext, rcache);
+	    namelen += (strlen(fnamep)+1);
+
+	    if ((rcname = (char *) malloc(namelen))) {
+		/* Format the rcache name. */
+		if (rcache->ops && rcache->ops->type)
+		    sprintf(rcname, "%s:%s", rcache->ops->type, fnamep);
+		else
+		    strcpy(rcname, fnamep);
+
+		/* Put the length of the file name */
+		(void) krb5_ser_pack_int32((krb5_int32) strlen(rcname),
+					   &bp, &remain);
+		
+		/* Put the name */
+		(void) krb5_ser_pack_bytes((krb5_octet *) rcname,
+					   strlen(rcname),
+					   &bp, &remain);
+
+		/* Put the trailer */
+		(void) krb5_ser_pack_int32(KV5M_RCACHE, &bp, &remain);
+		kret = 0;
+		*buffer = bp;
+		*lenremain = remain;
+		free(rcname);
+	    }
+	}
+    }
+    return(kret);
+}
+
+/*
+ * krb5_rcache_internalize()	- Internalize the krb5_rcache.
+ */
+static krb5_error_code
+krb5_rcache_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
+{
+    krb5_error_code	kret;
+    krb5_rcache		rcache;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    char		*rcname;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_RCACHE) {
+	kret = ENOMEM;
+
+	/* Get the length of the rcache name */
+	kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+
+	if (!kret &&
+	    (rcname = (char *) malloc((size_t) (ibuf+1))) &&
+	    !(kret = krb5_ser_unpack_bytes((krb5_octet *) rcname,
+					   (size_t) ibuf,
+					   &bp, &remain))) {
+	    rcname[ibuf] = '\0';
+	    if (!(kret = krb5_rc_resolve_full(kcontext, &rcache, rcname))) {
+		(void) krb5_rc_recover(kcontext, rcache);
+		if (!kret && 
+		    !(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) &&
+		    (ibuf == KV5M_RCACHE)) {
+		    *buffer = bp;
+		    *lenremain = remain;
+		    *argp = (krb5_pointer) rcache;
+		}
+		else
+		    krb5_rc_close(kcontext, rcache);
+	    }
+	    free(rcname);
+	}
+    }
+    return(kret);
+}
+
+/*
+ * Register the rcache serializer.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_ser_rcache_init(krb5_context kcontext)
+{
+    return(krb5_register_serializer(kcontext, &krb5_rcache_ser_entry));
+}
diff --git a/mechglue/src/lib/krb5_32.def b/mechglue/src/lib/krb5_32.def
new file mode 100644
index 000000000..012d6f7bf
--- /dev/null
+++ b/mechglue/src/lib/krb5_32.def
@@ -0,0 +1,285 @@
+;----------------------------------------------------
+;   KRB5.DEF - KRB5.DLL module definition file
+;----------------------------------------------------
+
+; ****************************************************************************
+; Do not add any function to this file until you make sure the calling
+; convention for the exported function is KRB5_CALLCONV
+; ****************************************************************************
+
+; Key:
+;
+; PRIVATE   - Private entrypoint.  It should not be called by anything other
+;             than gssapi32.dll or krb4_32.dll.
+; GSSAPI    - Private entrypoint used by gssapi32.dll.
+; KRB4      - Private entrypoint used by krb4_32.dll.
+; KRB5_CALLCONV_WRONG - entrypoint that should have used KRB5_CALLCONV, but
+;                       did not due to developer error
+
+EXPORTS
+
+	krb5_425_conv_principal
+	krb5_524_conv_principal
+	krb5_address_compare
+	krb5_address_order
+	krb5_address_search			; KRB5_CALLCONV_WRONG
+	krb5_aname_to_localname
+	krb5_appdefault_boolean
+	krb5_appdefault_string
+	krb5_auth_con_free
+	krb5_auth_con_genaddrs
+	krb5_auth_con_getaddrs
+	krb5_auth_con_getauthenticator
+	krb5_auth_con_get_checksum_func
+	krb5_auth_con_getflags
+	krb5_auth_con_getkey
+	krb5_auth_con_getlocalseqnumber
+	krb5_auth_con_getlocalsubkey
+	krb5_auth_con_getrcache			; KRB5_CALLCONV_WRONG
+	krb5_auth_con_getrecvsubkey
+	krb5_auth_con_getremoteseqnumber
+	krb5_auth_con_getremotesubkey
+	krb5_auth_con_getsendsubkey
+	krb5_auth_con_init
+	krb5_auth_con_initivector		; DEPRECATED
+	krb5_auth_con_setaddrs			; KRB5_CALLCONV_WRONG
+	krb5_auth_con_set_checksum_func
+	krb5_auth_con_setflags
+	krb5_auth_con_setports
+	krb5_auth_con_setrcache
+	krb5_auth_con_setrecvsubkey
+	krb5_auth_con_setsendsubkey
+	krb5_auth_con_setuseruserkey
+	krb5_build_principal
+	krb5_build_principal_ext
+	krb5_build_principal_va
+	krb5_c_block_size
+	krb5_c_checksum_length
+	krb5_c_decrypt
+	krb5_c_encrypt
+	krb5_c_encrypt_length
+	krb5_c_enctype_compare
+	krb5_c_is_coll_proof_cksum
+	krb5_c_is_keyed_cksum
+	krb5_c_keyed_checksum_types
+	krb5_c_make_checksum
+	krb5_c_make_random_key
+krb5_c_prf
+krb5_c_prf_length
+	krb5_c_random_make_octets
+	krb5_c_random_seed
+	krb5_c_string_to_key
+krb5_c_string_to_key_with_params
+	krb5_c_valid_cksumtype
+	krb5_c_valid_enctype
+	krb5_c_verify_checksum
+	krb5_calculate_checksum
+	krb5_cc_close
+	krb5_cc_copy_creds
+	krb5_cc_default
+	krb5_cc_default_name
+	krb5_cc_destroy
+	krb5_cc_end_seq_get
+	krb5_cc_gen_new
+	krb5_cc_get_name
+	krb5_cc_get_principal
+	krb5_cc_get_type
+	krb5_cc_initialize
+	krb5_cc_next_cred
+	krb5_cc_remove_cred
+	krb5_cc_resolve
+	krb5_cc_retrieve_cred
+	krb5_cc_set_default_name
+	krb5_cc_set_flags
+	krb5_cc_start_seq_get
+	krb5_cc_store_cred
+	krb5_change_password
+	krb5_checksum_size
+	krb5_cksumtype_to_string
+	krb5_copy_addresses
+	krb5_copy_authdata
+	krb5_copy_authenticator
+	krb5_copy_checksum
+	krb5_copy_creds
+	krb5_copy_data
+	krb5_copy_keyblock
+	krb5_copy_keyblock_contents
+	krb5_copy_principal
+	krb5_copy_ticket
+	krb5_decode_ticket
+	krb5_decrypt
+	krb5_deltat_to_string
+	krb5_eblock_enctype
+	krb5_encrypt
+	krb5_encrypt_size
+	krb5_enctype_to_string
+	krb5_finish_key
+	krb5_finish_random_key
+	krb5_free_addresses
+	krb5_free_ap_rep_enc_part
+	krb5_free_authdata
+	krb5_free_authenticator
+	krb5_free_checksum
+	krb5_free_checksum_contents
+	krb5_free_cksumtypes
+	krb5_free_config_files
+	krb5_free_context
+	krb5_free_cred_contents
+	krb5_free_creds
+	krb5_free_data
+	krb5_free_data_contents
+	krb5_free_default_realm
+	krb5_free_error
+	krb5_free_host_realm
+	krb5_free_keyblock
+	krb5_free_keyblock_contents
+	krb5_free_keytab_entry_contents
+	krb5_free_principal
+	krb5_free_tgt_creds
+	krb5_free_ticket
+	krb5_free_unparsed_name
+	krb5_fwd_tgt_creds
+	krb5_get_credentials
+	krb5_get_credentials_renew
+	krb5_get_credentials_validate
+	krb5_get_default_config_files
+	krb5_get_default_realm
+	krb5_get_host_realm
+	krb5_get_in_tkt				; DEPRECATED
+	krb5_get_in_tkt_with_keytab		; DEPRECATED
+	krb5_get_in_tkt_with_password		; DEPRECATED
+	krb5_get_in_tkt_with_skey		; DEPRECATED
+	krb5_get_init_creds_keytab
+	krb5_get_init_creds_opt_init
+	krb5_get_init_creds_opt_set_address_list
+	krb5_get_init_creds_opt_set_etype_list
+	krb5_get_init_creds_opt_set_forwardable
+	krb5_get_init_creds_opt_set_preauth_list
+	krb5_get_init_creds_opt_set_proxiable
+	krb5_get_init_creds_opt_set_renew_life
+	krb5_get_init_creds_opt_set_salt
+	krb5_get_init_creds_opt_set_tkt_life
+	krb5_get_init_creds_password
+	krb5_get_permitted_enctypes
+	krb5_get_prompt_types
+	krb5_get_renewed_creds
+	krb5_get_server_rcache
+	krb5_get_time_offsets
+	krb5_get_validated_creds
+	krb5_init_context
+	krb5_init_keyblock
+	krb5_init_random_key
+	krb5_init_secure_context
+        krb5_is_thread_safe
+	krb5_kt_add_entry
+	krb5_kt_close
+	krb5_kt_default
+	krb5_kt_default_name
+	krb5_kt_end_seq_get
+	krb5_kt_get_entry
+	krb5_kt_get_name
+	krb5_kt_get_type
+	krb5_kt_next_entry
+	krb5_kt_read_service_key
+	krb5_kt_remove_entry
+	krb5_kt_resolve
+	krb5_kt_start_seq_get
+	krb5_kuserok
+	krb5_mk_1cred
+	krb5_mk_error
+	krb5_mk_ncred
+	krb5_mk_priv
+	krb5_mk_rep
+	krb5_mk_req
+	krb5_mk_req_extended
+	krb5_mk_safe
+	krb5_os_localaddr
+	krb5_parse_name
+	krb5_principal_compare
+	krb5_principal2salt                     ; KRB5_CALLCONV_WRONG
+	krb5_process_key
+	krb5_prompter_posix
+	krb5_random_key
+	krb5_rd_cred
+	krb5_rd_error
+	krb5_rd_priv
+	krb5_rd_rep
+	krb5_rd_req
+	krb5_rd_safe
+	krb5_read_password
+	krb5_realm_compare
+	krb5_recvauth
+	krb5_recvauth_version
+	krb5_salttype_to_string
+	krb5_sendauth
+	krb5_set_default_realm
+	krb5_set_default_tgs_enctypes
+        krb5_set_password
+        krb5_set_password_using_ccache
+	krb5_set_principal_realm
+	krb5_set_real_time
+	krb5_sname_to_principal
+	krb5_string_to_cksumtype
+	krb5_string_to_deltat
+	krb5_string_to_enctype
+	krb5_string_to_key
+	krb5_string_to_salttype
+	krb5_string_to_timestamp
+	krb5_timeofday
+	krb5_timestamp_to_sfstring
+	krb5_timestamp_to_string
+	krb5_unparse_name
+	krb5_unparse_name_ext
+	krb5_us_timeofday
+	krb5_use_enctype
+	krb5_verify_checksum
+	krb5_verify_init_creds
+	krb5_verify_init_creds_opt_init
+	krb5_verify_init_creds_opt_set_ap_req_nofail
+
+	krb5_524_convert_creds
+; Don't add krb524_convert_creds_kdc or krb524_init_ets here;
+; they've never been exported by this library, and are deprecated. -KR
+
+	krb5int_accessor	; INTERNAL (to end all internals)
+
+; To Add (exported on Mac OS X):
+;	krb5_get_profile
+
+; Temporary exports (DO NOT USE)
+
+; DO NOT USE -- Currently required for krb4_32.dll
+	des_ecb_encrypt				; PRIVATE KRB4
+	des_new_random_key			; PRIVATE KRB4
+	des_key_sched				; PRIVATE KRB4
+	des_pcbc_encrypt			; PRIVATE KRB4
+	des_quad_cksum				; PRIVATE KRB4
+	des_string_to_key			; PRIVATE KRB4
+	des_init_random_number_generator	; PRIVATE KRB4
+	afs_string_to_key			; PRIVATE KRB4
+
+; DO NOT USE -- Currently required to implement gssapi32.dll
+	decode_krb5_ap_req			; PRIVATE GSSAPI k5-int.h KRB5_CALLCONV_WRONG
+	krb5_externalize_opaque			; PRIVATE GSSAPI k5-int.h
+	krb5_internalize_opaque			; PRIVATE GSSAPI k5-int.h
+	krb5_ser_auth_context_init		; PRIVATE GSSAPI k5-int.h
+	krb5_ser_ccache_init			; PRIVATE GSSAPI k5-int.h
+	krb5_ser_context_init			; PRIVATE GSSAPI k5-int.h
+	krb5_ser_keytab_init			; PRIVATE GSSAPI k5-int.h
+	krb5_ser_pack_bytes			; PRIVATE GSSAPI k5-int.h
+	krb5_ser_pack_int32			; PRIVATE GSSAPI k5-int.h
+	krb5_ser_rcache_init			; PRIVATE GSSAPI k5-int.h
+	krb5_ser_unpack_bytes			; PRIVATE GSSAPI k5-int.h
+	krb5_ser_unpack_int32			; PRIVATE GSSAPI k5-int.h
+	krb5_size_opaque			; PRIVATE GSSAPI k5-int.h
+	krb5int_cc_default			; PRIVATE GSSAPI k5-int.h
+
+	krb5_free_ap_req			; PRIVATE GSSAPI krb5.hin
+	krb5_free_ktypes			; PRIVATE GSSAPI krb5.hin
+	krb5_get_tgs_ktypes			; PRIVATE GSSAPI krb5.hin
+	krb5_auth_con_set_req_cksumtype		; PRIVATE GSSAPI krb5.hin
+	krb5_kt_free_entry			; PRIVATE GSSAPI krb5.hin
+	krb5_rc_close				; PRIVATE GSSAPI krb5.hin
+	krb5_free_enc_tkt_part			; PRIVATE GSSAPI krb5.hin
+	krb5_decrypt_tkt_part			; PRIVATE GSSAPI krb5.hin
+    
\ No newline at end of file
diff --git a/mechglue/src/lib/rpc/ChangeLog b/mechglue/src/lib/rpc/ChangeLog
new file mode 100644
index 000000000..914730b5a
--- /dev/null
+++ b/mechglue/src/lib/rpc/ChangeLog
@@ -0,0 +1,1342 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (check-unix): Don't run dyntest automatically.
+
+2005-01-14  Tom Yu  <tlyu@mit.edu>
+
+	* xdr.c (xdr_bytes): Revert previous; the problem was actually in
+	xdr_rpc_gss_buf.
+
+	* authgss_prot.c (xdr_rpc_gss_wrap_data): Use xdr_alloc to avoid
+	size limit issues.  Use (unsigned int)-1 instead of MAX_NETOBJ_SZ.
+	(xdr_rpc_gss_unwrap_data): Use (unsigned int)-1 instead of
+	MAX_NETOBJ_SZ.
+	(xdr_rpc_gss_buf): Set tmplen even if doing XDR_FREE.
+
+	* xdr.c (xdr_bytes): Don't assign from *sizep if XDR_FREE, since
+	it'll be uninitialized then.  Shuts up Purify.
+
+2004-11-18  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-unix): Install into KRB5_INCDIR/gssrpc,
+	rather than just KRB5_INCDIR.
+
+2004-10-25  Tom Yu  <tlyu@mit.edu>
+
+	* auth_gss.c (authgss_get_private_data): New function.
+	(authgss_refresh): Remove explicit OID checks.
+	(authgss_create): Copy initiator name.
+	(authgss_destroy): Release copied initiator name.
+	(print_rpc_gss_sec): Explicitly code OID stringification.
+
+	* auth_gss.h: Add cred and req_flags to struct rpc_gss_sec.  New
+	structure authgss_private_data so kernel implementations can
+	retrieve context state.
+
+	* auth_gss.h, libgssrpc.exports, rename.h: Add
+	authgss_get_private_data.
+
+2004-10-18  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-unix): Install headers.
+
+2004-09-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* xdr_rec.c (LAST_FRAG): Use 1L in case int is small.
+
+2004-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* libgssrpc.exports: Export svc_maxfd.
+
+2004-09-21  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Check for sockaddr_in.sin_len and
+	sockaddr.sa_len.  Check for sys/param.h in case we need NBBY
+	somewhere.
+
+	* auth.h, svc_auth.h: Namespace cleanup.
+
+	* svc.h, rpc_commondata.c: New global svc_maxfd.
+
+	* svc.c (svc_getreqset): Break inner part of loop out into
+	local function svc_do_xprt().  Don't use rpc_dtablesize();
+	instead, use svc_maxfd.
+
+	* svc_run.c: Don't use rpc_dtablesize().
+
+	* clnt_generic.c, clnt_simple.c, getrpcport.c:
+	* svc_tcp.c, svc_udp.c: Set sockaddr_in.sin_len when available.
+
+2004-09-17  Tom Yu  <tlyu@mit.edu>
+
+	* libgssrpc.exports: Don't export internals.
+
+	* svc.c (svc_getreqset):
+	* svc_tcp.c (readtcp): Don't intersperse preprocessor
+	conditionals with braces.
+
+	* auth_gssapi.c, auth_gssapi_misc.c, auth_none.c:
+	* auth_unix.c, authunix_prot.c, bindresvport.c:
+	* clnt_generic.c, clnt_perror.c, clnt_raw.c
+	* clnt_simple.c, clnt_tcp.c, clnt_udp.c, get_myaddress.c:
+	* getrpcent.c, getrpcport.c, pmap_clnt.c:
+	* pmap_getmaps.c, pmap_getport.c, pmap_prot.c, pmap_prot2.c:
+	* pmap_rmt.c, rpc_callmsg.c, rpc_prot.c:
+	* svc.c, svc_auth.c, svc_auth_gss.c:
+	* svc_auth_gssapi.c, svc_auth_unix.c, svc_raw.c:
+	* svc_run.c, svc_simple.c, svc_tcp.c:
+	* svc_udp.c, xdr.c, xdr_alloc.c, xdr_array.c:
+	* xdr_float.c, xdr_mem.c, xdr_rec.c, xdr_reference.c:
+	* xdr_stdio.c: Protoize, to avoid potential problems when
+	fixed-width types are not ints on some platforms.
+
+2004-08-26  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Look for uint32_t, not int32_t, since some BSD-ish
+	sys/types.h headers have int32_t and u_int32_t, but only have
+	uint32_t in stdint.h.
+
+	* types.hin: Change int32_t checks to uint32_t checks.
+
+2004-08-17  Tom Yu  <tlyu@mit.edu>
+
+	* svc.c (svc_getreqset): Allocate cred and verf memory to
+	temporary pointers, and free the temporary pointers on exit.
+	Freeing the actual cred and verf pointers can cause corruption
+	because auth mechanisms can reassign the pointers.
+
+2004-08-16  Tom Yu  <tlyu@mit.edu>
+
+	* svc_auth_gss.c (gssrpc__svcauth_gss): Add some debug messages.
+
+	* svc.c (svc_getreqset): Don't allocate either raw or cooked
+	credentials on the stack using the cred_area char array; use
+	mem_alloc() instead.  This avoids alignment problems.
+
+2004-06-28  Tom Yu  <tlyu@mit.edu>
+
+	* auth_gss.c (g_OID_equal): Fix signedness.
+	(rpc_gss_data): Fix width of WIN.
+	(authgss_validate): Fix width of NUM and QOP_STATE.
+	(authgss_refresh): Fix width of SEQ and QOP_STATE.
+
+	* auth_gssapi.c (auth_gssapi_create): Save clnt->cl_auth early
+	enough to avoid unref use.
+
+	* authgss_prot.c (xdr_rpc_gss_buf): Cast (void **) to (char **)
+	in call to xdr_bytes.
+	(xdr_rpc_gss_wrap_data): Fix signedness.
+	(xdr_rpc_gss_unwrap_data): Fix signedness.  Fix width of SEQ_NUM.
+
+	* clnt_udp.c (clntudp_bufcreate, clntudp_call, clntudp_call):
+	Fix up some argument casting for socket calls.
+
+	* pmap_prot.c (xdr_pmap): Use appropriate xdr macros for the
+	typedefs instead of xdr_u_int32.
+
+	* rpc_prot.c (xdr_accepted_reply, xdr_rejected_reply)
+	(xdr_callhdr): Use appropriate xdr macros for the typedefs instead
+	of xdr_u_int32.
+
+	* svc_auth_unix.c (gssrpc__svcauth_unix): Fix signedness on call
+	to XDR_INLINE.
+
+	* xdr.c (xdr_int, xdr_long, xdr_short): Improve value checks.
+
+	* xdr.h: Make the IXDR macros more paranoid about signedness.  Add
+	macros for xdr_rpcprog, xdr_rpcvers, xdr_rpcprot, xdr_rpcproc,
+	xdr_rpcport.
+
+	* xdr_mem.c (xdrmem_getlong): Cast return value of ntohl to
+	int32_t prior to casting it to long.
+
+	* xdr_rec.c (xdrrec_getlong): Cast return value of ntohl to
+	int32_t prior to casting it to long.
+	(xdrrec_putlong): Make arithmetic more paranoid.
+	(xdrrec_inline): Signedness fixes.  Arithmetic paranoia.
+	(set_input_fragment): Don't cast return value of ntohl which is
+	being assigned to uint32_t.
+
+2004-06-25  Tom Yu  <tlyu@mit.edu>
+
+	* types.hin: Delete rpc_int32, rpc_u_int32 aliases.
+
+2004-06-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Fix typo in setting
+	krb5_cv_header_sys_param_h_maxhostnamelen.
+
+2004-06-18  Tom Yu  <tlyu@mit.edu>
+
+	* auth_gss.h: Add prototype for xdr_rpc_gss_buf.
+
+	* authgss_prot.c (xdr_rpc_gss_buf): New function.
+	(xdr_rpc_gss_cred, xdr_rpc_gss_init_args, xdr_rpc_gss_init_res):
+	(xdr_rpc_gss_wrap_data, xdr_rpc_gss_unwrap_data): Use
+	xdr_rpc_gss_buf, to avoid passing a (size_t *) to a xdr_bytes(),
+	which expects (u_int *).
+	(xdr_rpc_gss_wrap_data): Use tmplen to avoid passing (size_t *) to
+	xdr_u_int.
+
+	* libgssrpc.exports:
+	* rename.h: Add xdr_rpc_gss_buf.
+
+	* xdr.c (xdr_enum): Fix (kind of) for 64-bit.  Still inherently
+	bogus, due to casting of (enum foo *) to (enum_t *) by callers.
+
+2004-06-17  Tom Yu  <tlyu@mit.edu>
+
+	* libgssrpc.exports: Update.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (clean-mac): Target deleted.
+
+2004-06-16  Tom Yu  <tlyu@mit.edu>
+
+	* auth_gss.h: Conditionalize log_debug, log_status, log_hexdump
+	prototypes on GSSRPC__IMPL.
+
+	* rename.h: More namespace fixes.
+
+2004-06-15  Tom Yu  <tlyu@mit.edu>
+
+	* auth_gss.c (print_rpc_gss_sec): Use gss_oid_to_str().
+	(rpc_gss_data): Add field "established" to indicate whether
+	context establishment is in progress; this prevents recursive
+	failures when auth_refresh() calls clnt_call().  If clnt_call()
+	called from auth_refresh() gets an error condition, the
+	clnt_call() logic will attempt a refresh, which can cause the
+	cl_auth to get destroyed multiple times, corrupting memory.
+	(authgss_validate, authgss_refresh): Use gd->established.
+	(authgss_refresh): Release gd->gc_wire_verf.
+	(authgss_destroy_context): Log clnt_call() failures.
+
+	* auth_gssapi.h: Add prototypes for svcauth_gss_set_log_*_func.
+
+	* authgss_prot.c (log_status): Correctly reset msg_ctx between
+	different types of calls to gss_display_status().
+
+	* svc.c: Don't reset xp_auth prior to authenticating message.
+
+	* svc.h (svc_req): Remove rq_svcname; application can get it from
+	rq_svccred anyway.
+
+	* svc_auth_gss.c: Include auth_gssapi.h to get typedefs for
+	logging callback functions.  Enable logging callbacks.  Replace
+	SVCAUTH_PRIVATE_LVALUE() kludge.  Fix up namespace somewhat to not
+	use reserved names.
+	(svcauth_gss_accept_sec_context): Free rpc_gss_init_args to avoid
+	leak.  Release gr->gr_token on error conditions.
+	(svcauth_gss_nextverf, svcauth_gss_accept_sec_context):
+	(gssrpc__svcauth_gss): Use gd->checksum.
+	(gssrpc__svcauth_gss): Use macro ret_freegc() to ensure freeing of
+	gc.  On destroy, set *no_dispatch=TRUE and explicitly send reply
+	to avoid application sending a NULLPROC reply with an invalid
+	verifier.
+
+	* svc_auth_gssapi.c (gssrpc__svcauth_gssapi): Set xp_auth to NULL
+	upon destroy.
+	(svc_auth_gssapi_destroy): New function so SVCAUTH_DESTROY() will
+	work.
+
+	* svc_tcp.c (svctcp_create, makefd_xprt): Initialize xp_auth to
+	NULL.
+	(svctcp_destroy): Call SVCAUTH_DESTROY() if appropriate.
+
+	* svc_udp.c (svcudp_bufcreate, svcudp_destroy): Initialize xp_auth
+	to NULL.
+	(svcudp_destroy): Only close xp_sock if it's not -1.  Call
+	SVCAUTH_DESTROY() if appropriate.
+
+	* xdr_rec.c (xdrrec_getpos): Add CITI's fix to return position for
+	non-flushed buffers.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-05-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* clnt_tcp.c: Include string.h.
+
+2004-05-27  Tom Yu  <tlyu@mit.edu>
+
+	* auth_any.c, svc_auth_any.c: Removed.
+
+	* auth_gss.h: New file, was CITI's auth_ssapi.h.
+
+	* auth_gss.c, authgss_prot.c, svc_auth_gssapi.c, svc_auth_none.c:
+	New files.
+
+	* rename.h: New file containing renaming macros for external
+	names.
+
+	* Makefile.in (DEFINES): Add -DGSSRPC__IMPL for accessing
+	internals.
+	(LIBMAJOR): Bump due to ABI changes; this ABI is still subject to
+	change without future version bumps until released.
+	(SRCS, OBJS, STLIBOBJS, HDRS, SRC_HDRS): Adjust for new files
+
+	* types.hin: Check for 8-bit bytes, two's-complement integers.
+	Use configure-determined inclusions of various headers instead of
+	depending on HAVE_*.  Rearrange logic of sys/select.h,
+	netinet/in.h, etc. inclusions.  Include rename.h.  Add typedefs
+	for rpcprog_t, rpcvers_t, rpcprot_t, rpcproc_t, rpcport_t,
+	rpc_inline_t.
+	(GSSRPC__BEGIN_DECLS, GSSRPC__END_DECLS): New macros for C++
+	compatibility.
+	[GSSRPC__FAKE_INT32]: Fake up a fixed-width 32-bit integer if the
+	system doesn't provide one in its headers.
+	[GSSRPC__BSD_TYPEALIASES]: Add typedefs for BSD-style type
+	aliases, e.g., u_char.  Can be overridden at compile-time.
+
+	* auth.h, auth_gssapi.h, auth_unix.h, clnt.h, pmax_clnt.h:
+	* pmap_prot.h, pmap_rmt.h, rpc.h, rpc_msg.h, svc.h, svc_auth.h:
+	* xdr.h: Fix inclusion protection.  Use GSSRPC__{BEGIN,END}_DECLS
+	for declarations.  "unsigned int" -> "u_int", etc.  "rpc_int32" ->
+	"int32_t", etc.  Move renaming to rename.h.  Move some external
+	names out of implementation namespace.  Make struct tags identical
+	to typedef names, mostly.  Use rpcprog_t and friends as
+	appropriate.
+
+	* auth.h: Add RPCSEC_GSS errors.  Add RPCSEC_GSS flavor.  Disable
+	AUTH_GSSAPI_COMPAT flavor.  "AUTH_wrap" -> "auth_wrap",
+	"AUTH_unwrap" -> "auth_unwrap".
+
+	* svc_auth.h: Hide individual flavors of authenticators under
+	GSSRPC__IMPL.  Adjust for "svc_auth_any" -> "svc_auth_none".
+	(SVCAUTH_DESTROY): New macro.
+
+	* rpc.h: Prototype gssrpc__rpc_dtablesize().
+
+	* svc.h (svc_req): Add rq_clntname, rq_svcname.
+
+	* xdr.h (MAX_NETOBJ_SZ): Adjust to 2048.
+
+	* auth_gssapi.c, auth_gssapi_misc.c, auth_none.c, auth_unix.c:
+	* bindresvport.c, clnt_generic.c, clnt_perror.c, clnt_raw.c:
+	* clnt_simple.c, clnt_tcp.c, clnt_udp.c, get_myaddress.c:
+	* getrpcent.c, getrpcport.c, pmax_clnt.c, pmap_getport.c:
+	* pmap_prot2.c, pmap_rmt.c, rpc_callmsg.c, rpc_commondata.c:
+	* rpc_dtablesize.c, rpc_port.c, svc.c, svc_auth.c:
+	* svc_auth_gssapi.c, svc_auth_unix.c, svc_run.c, svc_simple.c:
+	* svc_tcp.c, svc_udp.c, xdr.c, xdr_alloc.c, xdr_array.c:
+	* xdr_float.c, xdr_mem.c, xdr_rec.c, xdr_reference.c, xdr_stdio.c:
+	* xdr_stdio.c: Lots of type renaming, including BSD typealiases,
+	use of int32_t and uint32_t, rpc*_t for protocol constants.  Fixed
+	namespace issues, moving renaming out of individual files.  Moved
+	symbols out of implementation namespace.
+
+	* xdr.c: Add checks on integer values, in order to return errors
+	when an attempt is made to encode an integer that won't fit in 4
+	bytes, or to decode an integer that won't fit into its target
+	type.
+
+	* auth_none.c: Use authnone_wrap instead of authany_wrap.
+	(authnone_wrap): New function.
+
+	* auth_unix.c: Use authunix_wrap instead of authany_wrap.
+	(authunix_wrap): New function.
+
+	* xdr_mem.c, xdr_rec.c: Fix some sizeof vs BYTES_PER_XDR_UNIT
+	issues.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libgssrpc.exports: New file.
+
+2004-04-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* svc_auth_gssapi.c (destroy_client): Don't call purify_watch_n
+	even if PURIFY is defined.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* bindresvport.c: Include errno.h.
+	(gssrpc_bindresvport): Don't declare errno.
+	* clnt_tcp.c: Don't declare errno.
+	* svc.c: Don't declare errno.  Include errno.h.
+
+2003-03-24  Tom Yu  <tlyu@mit.edu>
+
+	* xdr_mem.c (xdrmem_create): Perform some additional size checks.
+	(xdrmem_getlong, xdrmem_putlong, xdrmem_getbytes): Check x_handy
+	prior to decrementing it.
+
+2003-01-12  Ezra Peisach  <epeisach@bu.edu>
+
+	* svc_auth_gssapi.c (_svcauth_gssapi_unset_names): If invoked more
+	than once, do not double free memory.
+
+	* clnt_perror.c (clnt_sperror): Do not write past end of allocated
+	buffer.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_ARCHIVE,
+	AC_PROG_ARCHIVE_ADD, AC_PROG_RANLIB, AC_PROG_INSTALL.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* svc_run.c svc_udp.c : Remove declaration of errno
+
+	* clnt_udp.c pmap_getmaps.c pmap_rmt.c svc_auth_gssapi.c: Remove
+	declaration of errno 
+
+2002-12-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* auth_gssapi_misc.c (xdr_gss_buf, auth_gssapi_wrap_data,
+	auth_gssapi_unwrap_data): Use temporary variables rather than
+	pointer casts when dealing with integral types of different
+	sizes.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-prerecurse): Change double colons to single
+	colons.
+
+2002-11-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* get_myaddress.c (get_myaddress): Local array buf size should be
+	counted in ifreq structs, not ifconf structs.
+
+2002-10-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* xdr_alloc.c (xdralloc_putlong): Coerce value pointed to by
+	argument to 32 bits, rather than reading only 32 bits from the
+	supplied address.
+
+2002-09-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(HDRS)): Depend on includes.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-12  Tom Yu  <tlyu@mit.edu>
+
+	* xdr.c (xdr_string): Fix off-by-one error; we're not vulnerable,
+	since we don't call it.
+
+2002-08-02  Tom Yu  <tlyu@mit.edu>
+
+	* xdr_array.c (xdr_array): Account for elsize when checking
+	encoded array count.
+
+2002-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* dyn.c: New file, combining contents of old util/dyn library,
+	with unused functions omitted, and memmove assumed.
+	* dyn.h: Moved from util/dyn/dyn.h, symbol renaming macros added.
+	Changed element size to size_t.  Include stdlib.h.
+	* dynP.h: Moved from util/dyn/dynP.h, symbol renaming macros
+	added.
+	* dyntest.c: Moved from util/dyn/test.c.
+	* Makefile.in (SHLIB_EXPDEPS, SHLIB_EXPLIBS): Omit libdyn
+	references.
+	(SRCS, OBJS, STLIBOBJS): Build dyn.c.
+	(dyntest, run-dyntest, clean-dyntest): New targets.
+	(check-unix): Depend on run-dyntest.
+	(clean-unix): Depend on clean-dyntest.
+	(LCLINT, LCLINTOPTS): Moved from util/dyn/Makefile.in.
+	(do-dyn-lclint): New target, untested.
+	* xdr_alloc.c: Include "dyn.h" instead of <dyn.h>.
+
+2001-12-14  Ezra Peisach  <epeisach@mit.edu>
+
+	* svc_auth_gssapi.c (_gssrpc_svcauth_gssapi): Local return
+	variable declared enum auth_stat instead of int.
+
+2001-12-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* clnt_raw, clnt_tcp.c, clnt_udp.c: Use a union structure to
+	ensure argument alignment.
+
+	* pmap_clnt.c, pmap_clnt.h (pmap_set): Change port argument to int
+	to avoid width warnings.
+
+	* rpc_callmsg.c (xdr_callmsg): Cast argument to XDR_INLINE to
+	avoid signed vs. unsigned warning.
+
+	* svc.c: Cast assignment to avoid signed warning.
+
+	* xdr.c (xdr_u_short, xdr_u_long): cast pointers to long * in
+	invocation of XDR_PUTLONG.
+
+	* xdr_alloc.c (xdralloc_putbytes): Cast argument to DynInsert to
+	avoid signed/unsigned warning.
+
+	* auth_gssapi.c, svc_auth_gssapi, xdr_rec.c: Cast arguments to
+	avoid alignment warnings.
+
+	* svc_tcp.c, xdr_stdio.c: Cast argument to fread/fwrite/read/write.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* auth_gssapi.h, auth_gssapi_misc.c, getrpcent.c,
+	svc_auth_gssapi.c, xdr.h: Make prototypes unconditional.  Don't
+	define PROTOTYPE.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* auth_gssapi.h, getrpcent.c, xdr.h: Drop _MSDOS support.
+
+2001-08-10    <epeisach@mit.edu>
+
+	* clnt_udp.c (clntudp_call): Do not assume that select will not
+	change the timeout struct timeval. Under Linux, this reflects the
+	time left available - which might result in 0 in the case of a
+	timeout. When attempting to resend a request, this may results in
+	a timeout of zero - flooding the server with replay requests.
+	
+	* clnt_tcp.c (readtcp): Same.
+	* pmap_rmt.c (clnt_broadcast): Same
+	* svc_tcp.c (readtcp): Same
+
+2001-07-26  Ezra Peisach  <epeisach@home>
+
+	* xdr_reference.c (xdr_reference): Remove cast in argument to memset.
+
+	* svc_auth_gssapi.c: In call to gss_accept_sec_context, pass
+	OM_uint32 * instead of int *;
+
+	* pmap_clnt.h, pmap_getport.c (pmap_getport): Prototype changed
+ 	for protocol from unsigned int to rpc_u_int32 to match struct
+ 	pmap.
+
+	* getrpcport.c (gssrpc_getrpcport): Update to reflect proper
+	calling conventions.
+
+	* rpc.h (callrpc): Change prototype from expecting ints for
+	prognum, versnum and procnum to rpc_u_int32 for consistancy.
+	(getrpcport): Update arguments in similar fashion.
+	
+	* clnt_simple.c (gssrpc_callrpc): Update to reflect prototype change.
+
+	* auth_gssapi_misc.c (auth_gssapi_display_status_1): Local
+	variable msg_ctx should be OM_uint32 instead of int as argument to
+	gss_display_status.
+
+2001-07-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* auth_gssapi.c (auth_gssapi_create): Change calling convention
+	from passing ints as arguments to OM_uint32 to match spec for
+	gss_init_sec_context.
+
+	* auth_gssapi.h: Update prototype for auth_gssapi_create.
+	
+	* svc.h (struct svc_req): The rq_clntcred and rq_svccred elements
+	are now void *.
+
+2001-07-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* xdr_mem.c: Do not assume that XDR x_private field is char *.
+
+	* auth.h: AUTH ah_private structure element changed to void *. 
+
+	* clnt.h: CLIENT cl_private structure element changed to type void *. 
+
+	* svc.h: SVCXRPT elements xp_p1 and xp_p2 changed to void * from
+	caddr_t.
+
+	* svc_udp.c: su_cache element of svcudp_data from caddr_t to void *.
+
+	* clnt_tcp.c, svc_tcp.c (writetcp, readtcp): Cleanup alignment
+	warning in casts.
+
+	* types.hin (mem_alloc): Do not cast type of malloc to char *.
+
+	* xdr.h: Change type of x_private of XDR from caddr_t to void *.
+
+2001-07-09  Ezra Peisach  <epeisach@mit.edu>
+
+	* pmap_rmt.c, svc.c, svc_simple.c, svc_udp.c, svc_tcp.c,
+	xdr_array.c, xdr_reference.c : Include string.h for memset and
+	memcmp prototypes.
+
+	* auth_gssapi.c, auth_gssapi_misc.c, svc_auth_gssapi.c: Cast
+	argment to PRINTF to match format.
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* svc.c (xprt_register): If svc_fdset has not been initilized, 
+	FD_ZERO it.
+	
+	* rpc_commondata.c: Do not assume what the structure of an fd_set
+	looks like. Add variable gssrpc_svc_fdset_init to determine if
+	initialized. 
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* auth_unix.c: In case GETGROUPS_T is not defined, default to int.
+
+2001-07-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add AC_TYPE_GETGROUPS to determine argument to
+	getgroups.
+
+	* auth_unix.c (authunix_create_default): Use GETGROUPS_T array in
+	call to getgroups. Copy into array of int for call to
+	authunix_create. Note: If auth_unix protection ever used with this
+	code, we will need to cleanup assumptions in int being 32 bits in
+	OTW transfer of gids.
+
+	* clnt_tcp.c, svc_tcp.c: Change writetcp and readtcp to take char
+	as first argument to be compatible with xdrrec_create.
+
+	* xdr.c (xdr_opaque): Cast argument in call to XDR_GETBYTES.
+
+	* svc.h: Add prototype for gssrpc_svcudp_enablecache.
+
+	* svc_auth_gssapi.c (_gssrpc_svcauth_gssapi): Change
+	_svcauth_gssapi to _gssrpc_svcauth_gssapi for consistancy.
+
+	* svc_auth.c: Move prototypes for _gssrpc_svcauth_{unix, null,
+	short, gssapi} to:
+	* svc_auth.h: here.
+
+	* svc_auth_unix.c: Update _gssrpc_svcauth_short and
+	_gssrpc_svcauth_unix to match prototype.
+
+2001-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* auth.h: Provide full prototype for xdr_des_block.
+
+	* auth_gssapi.h: Complete prototypes for
+	_svcauth_gssapi_unset_names().
+
+	* clnt.h: Prototype dispatch functions and all functions.
+
+	* clnt_perror.c: Prototype static auth_errmsg().
+
+	* clnt_raw.h clnt_tcp.c, clnt_udp.c: Provide prototypes to static
+	functions and match dispatch table prototypes. control function
+	takes void * instead of caddr_t.
+
+	* pmap_rmt.c: Move prototype for resultproc_t to pmap_clnt.h.
+
+	* rpc.h: get_myaddress returns int. Add prototypes for callrpc and
+	getrpcport.
+
+	* rpc_commondata.c (rpc_createerr): When initializing rpc_creaerr
+	use RPC_SUCCESS instead of 0. 
+
+	* get_myaddress.c, rpc_dtablesize.c: Include gssrpc/rpc.h for
+	prototype.
+
+	* pmap_clnt.h, pmap_prot.h, pmap_rmt.h, rpc_msg.h: Full prototypes
+	for all functions.
+
+	* svc.c: Provide full prototype for static function.
+
+	* svc.h: Prototypes for dispatch functions added. Flushed out
+	prototypes for all functions missing prototypes. Added prototype
+	for svcfd_create.
+
+	* svc_auth.c: Prototypes for all functions referenced.
+
+	* svc_auth.h: Prototype dispatch functions to svc_auth_ops.
+
+	* svc_auth_any.c: Replace use of authany_wrap() with a new local
+	function that matches svc_auth_ops dispatch table.
+
+	* svc_simple.c: Provide prototype for static function
+	universal. Fill in missing types of parameters to
+	gssrpc_registerrpc.
+
+	* svc_raw.c svc_tcp.c, svc_udp.c: Provide prototypes for static
+	functions and match prototypes in dispatch table. Change getargs
+	and freeargs argument to void * from caddr_t.
+
+	* xdr.c (xdr_void): Function to match prototype of arguments given.
+
+	* xdr.h: Provide full prototypes for xdr_ops dispatch table and
+	xdr_void().
+
+	* svc_auth_gssapi.c, xdr_alloc.c, xdr_mem.c, xdr_rec.c,
+	xdr_stdio.c: Provide protypes for static functions and match
+	dispatch tables.
+
+2001-06-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* bindresvport.c: Include gssrpc/rpc.h for prototype.
+
+	* auth_unix.h: Expand prototype for xdr_authunix_params to include
+	arguments.
+
+	* auth_gssapi.h: Give full prototypes for xdr_gss_buf,
+	xdr_authgssapi_creds, xdr_authgssapi_init_arg and
+	xdr_authgssapi_init_res.
+
+	* auth_gssapi.c, auth_none.c, auth_unix.c: For struct AUTH
+	disptach functions, provide full prototypes and ensure consistant
+	usage in functions
+
+	* auth.h: Provide prototypes dispatch functions in struct
+	AUTH. Give a forward declaration of struct rpc_msg. Change
+	duplicate definitions of AUTH_WRAP and AUTH_UNWRAP into auth_wrap
+	and auth_unwrap. Give full prototype for authany_wrap.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* svc_simple.c (universal): Change transp to s_transp to not
+	shadow filewide static definition of name.
+	Move file wide definition of "pl" into respective functions.
+
+	* pmap_rmt.c: Change sin->sockin and socket->sock.
+
+	* pmap_getmaps.c, pmap_getport.c: Change socket to sock to not
+ 	shadow network function.
+
+	* bindresvport.c, clnt_generic.c: Change sin to sockin to not
+ 	shadow function declaration.
+
+2001-06-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* pmap_prot2.c (xdr_pmaplist): Ensure variable set before use. 
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* auth_gssapi.c (auth_gssapi_create): Cast const gss_OID to
+	gss_OID for gssapi functions.
+
+	* xdr.c (xdr_u_int, xdr_int32, xdr_u_int32): If enumerated
+	operation is not XDR_ENCODE, XDR_DECODE or XDR_FREE - return FALSE
+	instead falling off end of function.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* auth_gssapi.h: Rename prototypes from _svcauth_set_log_XXX_func to 
+	_svcauth_gssapi_set_log_XXX_func to match code.
+
+2001-06-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* clnt_perror.c (clnt_spcreateerror): Enumerate missing cases in
+	switch.
+
+	* getrpcport.c: Include string.h for memmove() prototype and
+	pmap_clnt.h for pmap_getport() prototype.
+
+	* rpc_dtablesize.c (_gssrpc_rpc_dtablesize): Declare as returning int.
+	* get_myaddress.c (gssrpc_get_myaddress): Likewise.
+
+	* rpc_prot.c (gssrpc_xdr_accepted_reply, sunrpc_seterr_reply):
+	Enumerate missing cases for switch.
+	(rejected): Fix typo: RPC_VERMISMATCH -> RPC_MISMATCH for
+	enumerated switch.
+
+  	* svc_auth.c: Add braces to svcauthsw[] initialization.
+
+	* svc_simple.c: Include pmap_clnt.h for pmap_unset prototype.
+
+	* bindresvport.c, clnt_simple.c, clnt_tcp.c, clnt_udp.c, pmap_clnt.c,
+	pmap_getmaps.c, pmap_gtport.c, pmap_rmt.c, svc_tcp.c, svc_udp.c:
+	Include unistd.h for close() prototype.
+
+	* xdr.c (xdr_opaque): Specify internal buffer as ints.
+	(xdr_u_int32): Declare as returning bool_t.
+
+	* clnt_generic.c, rpc_callmsg.c, svc_auth_unix.c, xdr_mem.c:
+	Include string.h for memmove() prototype.
+
+	* xdr_rec.c: Include string.h for memmove() prototype. Add dummy
+	XDR_FREE cases for switches.
+
+	* xdr_reference.c (xdr_reference): Add XDR_ENCODE case. (gcc warning). 
+	* xdr_array.c (xdr_array): Likewise.
+
+	* auth.h: Include gssrpc/xdr.h and provide prototype for
+	gssrpc_xdr_opaque_auth().
+
+	* auth_gssapi.h: Add prototypes for auth_gssapi_seal_seq() and
+	auth_gssapi_unseal_seq().
+
+	* clnt.h: Add prototype for _gssrpc_rpc_dtablesize(). 
+
+	* rpc.h: Add prototypes for gssrpc_get_myaddress() and
+	gssrpc_bindresvport().
+
+2001-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for strerror.
+	* clnt_perror.c (strerror) [!HAVE_STRERROR]: Define, with
+	out-of-range check using sys_nerr.
+	(sys_nerr) [!HAVE_STRERROR]: Declare at top level instead of in
+	clnt_spcreateerror.
+	(clnt_sperror, clnt_spcreateerror): Use strerror always.  Skip
+	range check.
+
+Sun Feb 18 17:48:35 2001  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* xdr.h: Flush out prototypes for xdrmem_create(),
+        xdrstdio_create(), xdrrec_create(), xdralloc_create(),
+        xdralloc_release(), xdrrec_endofrecord(), xdrrec_skiprecord(),
+        xdrrec_eof(), xdralloc_getdata(). Add prototype for
+        gssrpc_xdr_fre().
+
+	* xdr.c: Argument to gssrpc_xdr_free(0 changed from char * to void
+        *. xdr_u_char() changed to take unsigned char * instead of char *.
+
+	* auth_unix.c: Include unistd.h and string.h for
+        prototypes. Declare marshal_new_auth() as static void instead of
+        static bool_t based on usage.
+
+	* auth.h, svc_auth.h: Provide full prototypes for a number of
+        functions.
+
+2000-06-21  Tom Yu  <tlyu@mit.edu>
+
+	* svc_auth_gssapi.c (_svcauth_gssapi): Missed a rename.  From
+	Nathan Neulinger.
+
+2000-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* pmap_rmt.c (GIFCONF_BUFSIZE): New macro.
+	(getbroadcastnets): Use it for buffer size.
+	(clnt_broadcast): Make buffer at least that big.
+
+	* get_myaddress.c (get_myaddress): Increase buffer size.
+
+2000-05-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* auth_gssapi_misc.c (auth_gssapi_display_status_1): Don't pass a
+	gss_buffer_desc to fprintf.
+
+	* clnt_tcp.c (clnttcp_create): Initialize "ct".
+	* clnt_udp.c (clntudp_bufcreate): Initialize "cu".
+
+	* svc_auth_gssapi.c (_svcauth_gssapi, create_client,
+	destroy_client, dump_db, clean_client): Use %p format for
+	displaying pointers.  Remove unused variables.
+
+2000-05-17  Ken Raeburn  <raeburn@mit.edu>
+            Nalin Dahyabhai  <nalin@redhat.com>
+
+	* clnt_perror.c (clnt_sperror): Don't overflow buffer "str" beyond
+	known allocation size.
+	* clnt_simple.c (gssrpc_callrpc): Don't overfill buffer "crp->oldhost".
+
+2000-05-03  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* clnt_perror.c (_buf): Use bigger buffer.
+	(clnt_spcreateerror): Don't overflow buffer "buf" beyond known
+	allocation size.
+
+2000-02-22  Donn Cave  <donn@u.washington.edu>
+
+	* Makefile.in (includes): Extract basename of header file to be
+	installed, since Digital UNIX 4.0 native make substitutes the
+	VPATH-derived pathname here.
+
+2000-02-17  Tom Yu  <tlyu@mit.edu>
+
+	* svc_auth_gssapi.c (_svcauth_gssapi): Don't explicitly free
+	call_arg on error, since svc_getargs should do that now.
+
+	* svc_udp.c (svcudp_getargs): Free args on xdr decode error to
+	avoid leaks.
+
+	* svc_tcp.c (svctcp_getargs): Free args on xdr decode error to
+	avoid leaks.
+
+	* svc_raw.c (svcraw_getargs): Free args on xdr decode error to
+	avoid leaks.
+
+	* auth_gssapi.c (auth_gssapi_create): Don't explicitly free
+	call_res anymore, since clnt_call should deal now.
+
+	* clnt_udp.c (clntudp_call): Free stuff on error from
+	xdr_replymsg() to prevent leaking.
+
+	* clnt_tcp.c (clnttcp_call): Free stuff on error from
+	xdr_replymsg() to avoid leaking.
+
+	* clnt_raw.c (clntraw_call): Free stuff on error from
+	xdr_replymsg() to avoid leaking.
+
+2000-02-16  Tom Yu  <tlyu@mit.edu>
+
+	* auth_gssapi.c (auth_gssapi_create): Free call_res because
+	xdr_authgssapi_init_res can potentially allocate memory.  Perhaps
+	clnt_call should really deal with this, though.  It is not at all
+	clear whether clnt_call or svc_getargs should actually end up
+	freeing allocated memory themselves.
+
+2000-02-15  Tom Yu  <tlyu@mit.edu>
+
+	* svc_auth_gssapi.c (_svcauth_gssapi): Call gssrpc_xdr_free() if
+	xdr_authgssapi_creds() or xdr_authgssapi_init_arg() fails.
+
+	* auth_gssapi_misc.c (xdr_authgssapi_creds):
+	(xdr_authgssapi_init_arg):
+	(xdr_authgssapi_init_res): Revert prior change.  The caller should
+	be the one dealing.  Additionally, it was probably wrong to
+	unconditionally free the object regardless of whether the mode is
+	XDR_DECODE.
+	(auth_gssapi_unwrap_data): Use temp_xdrs rather than in_xdrs to
+	force XDR_FREE operation.
+
+2000-02-14  Tom Yu  <tlyu@mit.edu>
+
+	* svc.c (xprt_register): Zero out xports after allocating.
+
+	* auth_gssapi_misc.c (xdr_authgssapi_creds):
+	(xdr_authgssapi_init_arg): 
+	(xdr_authgssapi_init_res): 
+	(auth_gssapi_unwrap_data): If xdr_gss_buf or xdr_bytes fails, call
+	again with XDR_FREE set so that allocated memory doesn't leak.
+
+2000-01-24  Tom Yu  <tlyu@mit.edu>
+
+	* get_myaddress.c (gssrpc_get_myaddress): Copy in from NetBSD;
+	use loopback address only.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Fri Apr 23 20:05:38 1999  Tom Yu  <tlyu@mit.edu>
+
+	* svc.c: Fix to reference the correct xprt because we're no longer
+	calling ffs(); also remove some unused variables.
+
+Wed Apr 21 16:22:32 1999  Tom Yu  <tlyu@mit.edu>
+
+	* svc.c (xprt_unregister): Fix typo.
+
+1999-04-14    <tytso@rsts-11.mit.edu>
+
+	* svc.c (svc_getreq, svc_getreqset): Avoid using internal, private
+		fd_set structure elements (Needed for Linux/glibc 2.1)
+
+Thu Apr  1 19:11:50 1999  Tom Yu  <tlyu@mit.edu>
+
+	* rpc_commondata.c: Add initializers to prevent lossage on systems
+	that don't deal with common blocks in libraries.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* svc_auth_gssapi.c, auth_gssapi.h: fix the set_name prototype,
+	add a new unset_names function
+
+Sun Jul 26 18:13:39 1998  Sam Hartman  <hartmans@utwig.mesas.com>
+
+	* Makefile.in (LIBMAJOR): bump libmajor
+
+Wed Apr 15 18:07:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): 
+	(SHLIB_EXPLIBS): Rename libcrypto -> libk5crypto.
+
+Mon Apr  6 19:44:51 1998  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in (includes): Don't mkdir unless the directory doesn't
+ 	exist yet.
+
+Wed Feb 18 16:26:19 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 20:57:49 1998  Tom Yu  <tlyu@mit.edu>
+
+	* auth.h: Renames.
+	* auth_any.c: Update header locations.
+	* auth_gssapi.c: Punt naughty RCS keywords.  Update header
+	locations.  Remove explicit extern decl of rpc_createrr (clnt.h
+	gets it).  Renames.
+	* auth_gssapi.h: Punt naughty RCS keywords.
+	* auth_gssapi_misc.c: Punt naught RCS keywords.  Update header
+	locations.
+	* auth_none.c: Update header locations.  Renames.
+	* auth_unix.c: Update header locations.  Renames.
+	* auth_unix.h: Renames.
+	* authunix_prot.c: Update header locations.
+	* bindresvport.c: Renames.
+	* clnt.h: Renames.
+	* clnt_generic.c: Update header locations.
+	* clnt_perror.c: Update header locations.
+	* clnt_raw.c: Update header locations.  Renames.
+	* clnt_simple.c: Update header locations.  Renames.
+	* clnt_tcp.c: Update header locations.  Renames.
+	* clnt_udp.c: Upate header loations.  Renames.
+	* get_myaddress.c: Update header locations.  Renames.
+	* getrpcent.c: Update header locations.
+	* getrpcport.c: Update header locations. Renames.
+	* netdb.h: Update header locations.
+	* pmap_clnt.c: Update header locations.  Renames.
+	* pmap_clnt.h: Renames.
+	* pmap_getmaps.c: Update header locations.
+	* pmap_getport.c: Update header locations.
+	* pmap_prot.c: Update header locations.
+	* pmap_prot.h: Renames.
+	* pmap_prot2.c: Update header locations.
+	* pmap_rmt.c: Update header locations.  Renames.
+	* pmap_rmt.h: Renames.
+	* rpc.h: Update header locations.  No longer include rpc/netdb.h.
+	* rpc_callmsg.c: Update header locations.  Renames.
+	* rpc_commondata.c: Update header locations.
+	* rpc_dtablesize.c: Renames.
+	* rpc_msg.h: Renames.
+	* rpc_prot.c: Update header locations.  Renames.
+	* svc.c: Update header locations.  Renames.
+	* svc.h: Renames.
+	* svc_auth.c: Update header locations.  Renames.
+	* svc_auth.h: Renames.
+	* svc_auth_any.c: Update header locations.
+	* svc_auth_gssapi.c: Punt naughty RCS keywords.  Update header
+	locations.  Renames.
+	* svc_auth_unix.c: Renames.
+	* svc_raw.c: Update header locations.
+	* svc_run.c: Update header locations.  Renames.
+	* svc_simple.c: Update header locations.  Renames.  Make pl
+	static.
+	* svc_tcp.c: Update header locations.  Renames.
+	* svc_udp.c: Update header locations.  Renames.
+	* xdr.c: Update header locations.  Renames.
+	* xdr.h: Renames.
+	* xdr_alloc.c: Punt naughty RCS keywords.  Update header
+	locations.
+	* xdr_array.c: Update header locations.
+	* xdr_float.c: Update header locations.
+	* xdr_mem.c: Update header locations.
+	* xdr_rec.c: Update header locations.
+	* xdr_reference.c: Update header locations.
+	* xdr_stdio.c: Update header locations.
+
+	* Makefile.in: Bump major version due to changes.  Don't build
+	getrpcent.o, since we don't use it, and dealing with the
+	rpc/netdb.h lossage was a major pain.  Also, rename HDRDIR to
+	$(BUILDTOP)/gssrpc in order to avoid problems with system headers
+	including rpc/*.h.
+
+Thu Feb 12 16:18:22 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented out AC_OUTPUT to force autoreconf to
+	rebuild the configure script.
+
+Mon Feb  2 17:00:16 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* configure.in, Makefile.in: Remove CopySrcHeader and CopyHeader 
+		from configure.in and move equivalent functionality to
+		Makefile.in 
+
+Wed Jan 21 15:06:00 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* bindresvport.c: Include string.h for memset prototype.
+
+Tue Dec 16 11:22:13 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* svc_auth_gssapi.c (_svcauth_gssapi): When looping over services,
+		free previous output_tokens.
+
+Fri Nov 21 00:37:14 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (types.h): Add rules to generate file by running
+ 	config.status. Remove on make clean.
+
+Tue Oct 21 14:31:33 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* svc_auth_gssapi.c (destroy_client): Fix to not lose entries in
+        the chain linked list.
+
+Mon Aug 18 09:48:06 1997  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* get_myaddress.c: Include string.h for memcpy prototype.
+
+Sat Feb 22 01:34:19 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (SHLIB_EXPDEPS): s/.so/$(SHLIBEXT)
+
+Mon Feb 10 11:10:02 1997  Ezra Peisach  <epeisach@quest.rose.brandeis.edu>
+
+	* configure.in: Check for sys/uio.h.
+
+	* svc_udp.c: Include sys/uio.h is available for struct iovec.
+
+Mon Feb 10 00:04:36 1997  Tom Yu  <tlyu@mit.edu>
+
+	* svc_udp.c (svcudp_recv): Avoid coredumps under Solaris (and
+	possibly other systems) by passing in a non-NULL iovec to
+	recvmsg().
+
+Thu Jan 16 19:02:22 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-prerecurse): Update to use double-colon rules.
+
+Tue Jan 14 19:22:42 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Wed Dec  4 12:42:49 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Various changes to allow channel bindings to work with both UDP
+ 	and TCP cleanly [krb5-libs/180]:
+
+	* auth_gssapi.c: remove the special-case exception to channel
+ 	bindings failure added in the previous revision, since we now
+ 	solve the problem by making channel bindings not fail
+
+	* clnt_udp.c: use a connected socket so that the client can
+ 	determine its own source address with getsockname
+
+	* svc.h: add xp_laddr and xp_laddrlen fields to SVCXPRT structure
+
+	* svc_tcp.c: set xp_laddr and xp_laddrlen when a connection is
+ 	established
+
+	* svc_udp.c (svcudp_recv): use recvmsg with MSG_PEEK followed by
+ 	recvfrom in order to determine both source and dest address on
+ 	unconnected UDP socket, set xp_laddr and xp_laddrlen
+
+Fri Nov 22 15:50:42 1996  unknown  <bjaspan@mit.edu>
+
+	* get_myaddress.c (get_myaddress): use krb5_os_localaddr instead
+ 	of ioctl() to get local IP addresses [krb5-libs/227]
+
+	* clnt_generic.c, clnt_simple.c, getrpcport.c: use sizeof instead
+ 	of h_length to determine number of bytes of addr to copy from DNS
+ 	response [krb5-misc/211]
+
+Fri Nov 22 11:49:43 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* types.hin: Include stdlib.h if found at config time [203]
+
+	* configure.in: Substitute STDLIB_INCLUDE into types.h. [203]
+
+Tue Nov 12 16:27:27 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* auth_gssapi.c (auth_gssapi_create): handle channel bindings
+ 	failure so UDP connections can work [krb5-libs/180]
+
+Tue Nov  5 18:43:46 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Revert removal of CopySrcHeader, etc., for now.
+
+	* Makefile.in (OBJS): Remove dependency of $(OBJS) on shared, also
+	remove dependency of $(HDRS) on $(HDRDIR).  Both of these to avoid
+	unecessary copying.
+
+Wed Oct 30 13:18:34 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* xdr_stdio.c: Remove the #ifndef mc68000 cruft.  I'm not sure
+ 	what it was supposed to accomplish, but in both places it appeared
+ 	it was unquestionably wrong.  I suspect that the ifdef was put in
+ 	originally to optimize byte-alignment code that wasn't necessary
+ 	on the 68000.  Who knows?  Someone will complain if this isn't
+ 	right. [krb5-libs/47]
+  
+Tue Oct 29 13:03:50 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* auth_gssapi.c (auth_gssapi_create): #ifdef GSSAPI_KRB5, a null
+ 	mech_type implies gss_mech_krb5, so include that in the version 3
+ 	fallback test.  This change, along with the other changes for rpc
+ 	version 4, complete the fix for [krb5-libs/106].
+
+Wed Oct 23 00:08:27 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* pmap_rmt.c:
+	* clnt_udp.c: Change #ifdef sparc to #ifdef sun for more portability.
+		[fixes PR#123]
+
+Mon Oct 21 21:22:42 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in, configure.in: Fixes to work with new directory
+ 	recursion method.
+
+Wed Oct 16 16:12:07 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* svc_auth_gssapi.c (_svcauth_gssapi): accept add call_arg version
+ 	4
+
+Tue Oct 15 17:04:09 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.in (CFLAGS): compile with -DGSSAPI_KRB5
+
+	* svc_auth_gssapi.c: add #ifdef GSSAPI_KRB5 for krb5 specific code
+
+	* auth_gssapi.c (auth_gssapi_create): add call_arg version 4, make
+ 	version 3 use using gss_mech_krb5_old (under #ifdef GSSAPI_KRB5)
+
+	* configure.in: add DO_SUBDIRS so make will descend into unit-test
+
+Wed Oct  9 14:15:34 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-unix): Force $(OBJS) to depend on includes,
+	fixing incompatibilty with makes that don't evaluate dependencies
+	l-r.
+
+Tue Sep  3 23:10:58 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* auth_gssapi.c: Remove $LOG$, including "unprofessional" comment
+		which OV requested that we lose....
+
+Sat Aug 31 01:46:45 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* pmap_rmt.c (getbroadcastnets): Tweak conditional layout to make
+	emacs indentation code happier.
+
+	* netdb.h: Comment fix.
+
+	Tue Aug  6 18:52:47 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in, getrpcent.c: Use configure to the return types of
+	setrpcent() and getrpcent().  Also, check for struct rpcent in the
+	system <netdb.h>, and only define the structure in rpc/netdb.h if
+	it's not in the system file.
+
+Tue Aug 13 15:18:16 1996  Tom Yu  <tlyu@mit.edu>
+
+	* getrpcent.c: Add PROTOTYPE and conditionalize function
+		prototypes.
+
+	* xdr.h: Add PROTOTYPE and conditionalize function prototypes.
+
+	* svc_auth_gssapi.c: Remove ANSI string concatenation, de-ANSI-fy
+ 		function definitions.
+
+	* auth_gssapi_misc.c (auth_gssapi_display_status_1): Remove ANSI
+		string concatenation, de-ANSI-fy function definitions.
+
+	* auth_gssapi.h: Add PROTOTYPE and conditionalize function
+		prototypes.
+
+	* auth_gssapi.c (auth_gssapi_create): remove ANSI-ish string
+		concatenation, de-ANSI-fy function definitions.
+
+Thu Aug  8 15:30:01 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in, types.hin: Change search for struct rpcent yet
+		again, this time compile-checking both netdb.h and
+		rpc/netdb.h and taking action appropriately.  See the
+		comments in configure.in for details.
+
+Mon Aug  5 16:46:48 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in (CFLAGS): Change DEBUG_GSSAPI to 0 to avoid printing
+		excess stuff to stderr.
+
+Wed Jul 31 20:36:34 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* getrpcent.c: Shuffle inclusion order somewhat.
+
+	* configure.in: Fix test for STRUCT_RPCENT_ALREADY_PROVIDED if
+		there happens to be a /usr/include/rpc/netdb.h.  This
+		causes /usr/include/netdb.h to include netdb.h from our
+		tree rather from /usr/include/rpc, which of course results
+		in massive damage.  Basically, if /usr/include/netdb.h
+		contains rpcent declaration and /usr/include/rpc/netdb.h
+		exists, then assume that there is no struct rpcent in the
+		system include files.  It's really unfortunate that we
+		need to do this at all, but it's all we can do short of
+		renaming a bunch of include files or directories.
+
+	* Makefile.in: Punt -I$(srcdir)/..; it was gross and not needed
+		because headers get installed in build tree before
+		building the library anyway.
+
+Wed Jul 31 16:54:29 1996  Tom Yu  <tlyu@mit.edu>
+
+	* types.hin: Remove #include <netdb.h> because it appears the only
+		reason for doing so was to get struct rpcent, and we're
+		getting that via <rpc/netdb.h>.
+
+	* clnt_generic.c, clnt_simple.c, clnt_tcp.c, clnt_udp.c,
+ 		getrpcent.c, getrpcport.c, pmap_getmaps.c, svc_simple.c:
+		Revert prior change due to netdb.h shuffling.
+
+Tue Jul 30 18:59:17 1996  Tom Yu  <tlyu@mit.edu>
+
+	* rpc.h: Don't include netdb.h (rpc/types.h already includes it)
+
+	* svc_auth_gssapi.c: #include <rpc/rpc.h> before <sys/stat.h> (to
+		get sys/types.h.
+
+	* clnt_generic.c, clnt_simple.c, clnt_tcp.c, clnt_udp.c,
+ 		getrpcent.c, getrpcport.c, pmap_getmaps.c, svc_simple.c:
+ 		Remove #include <netdb.h>; it's already included in
+ 		rpc/types.h.
+
+Mon Jul 29 22:02:47 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Determine whether netdb.h defines struct rpcent.
+
+	* types.hin: Expand rpcent_define to be a null string or a #define
+        on Linux.
+
+	* netdb.h: Include rpc/types.h and only define struct rpcent if
+        needed.
+
+Wed Jul 24 07:58:38 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* pmap_rmt.c (clnt_broadcast): Use memset insetad of bzero.
+
+	* Makefile.in (DEPLIBS): Use correct version number for
+		gssapi_krb5 dependency. 
+
+Tue Jul 23 23:49:47 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* clnt_perror.c: Don't declare strcpy.
+
+Tue Jul 23 11:24:32 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* xdr.c: Do not declare malloc().
+
+	* Makefile.in (SHLIB_LIBS): Link with gssapi_krb5 when creating
+		shared library.
+
+
+Mon Jul 22 21:46:48 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* clnt_perror.c: Include errno.h.
+
+Fri Jul 12 15:33:50 1996  Marc Horowitz  <marc@mit.edu>
+
+	* rpc_dtablesize.c (_rpc_dtablesize): put in a few checks to make
+ 	sure that the return value is never larger than FD_SETSIZE, since
+ 	this function's purpose is to be used as the first arg to
+ 	select().
+
+Tue Jul  9 17:56:54 1996  Marc Horowitz  <marc@mit.edu>
+
+	* rpc.h, netdb.h, getrpcent.c: Our build can (and will) require
+ 	that the rpc header files shipped with kerberos be used if the
+ 	library shipped with kerberos is used.  Thus, some simplifying
+ 	assumptions can be made, mostly having to do with the declaration
+ 	of struct rpcent and the related functions.
+	* clnt_perror.c: made usage of sys_errlist conditional on
+ 	NEED_SYS_ERRLIST
+	* configure.in (DECLARE_SYS_ERRLIST): added
+ 	* Makefile.in (DONE): added a few rules and variable so shared
+ 	library creation would work
+
diff --git a/mechglue/src/lib/rpc/Makefile.in b/mechglue/src/lib/rpc/Makefile.in
new file mode 100644
index 000000000..6c3f56c25
--- /dev/null
+++ b/mechglue/src/lib/rpc/Makefile.in
@@ -0,0 +1,567 @@
+thisconfigdir=.
+myfulldir=lib/rpc
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+DEFINES = -DGSSAPI_KRB5 -DDEBUG_GSSAPI=0 -DGSSRPC__IMPL
+
+##DOSBUILDTOP = ..\..
+##DOSLIBNAME=libgssrpc.lib
+
+LIBBASE=gssrpc
+LIBMAJOR=4
+LIBMINOR=0
+STOBJLISTS=OBJS.ST
+SHLIB_EXPDEPS= \
+	$(TOPLIBD)/libgssapi_krb5$(SHLIBEXT) \
+	$(TOPLIBD)/libkrb5$(SHLIBEXT) \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(COM_ERR_DEPLIB)
+SHLIB_EXPLIBS=-lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+RELDIR=rpc
+
+SRCS = $(srcdir)/auth_none.c \
+	$(srcdir)/auth_unix.c \
+	$(srcdir)/authgss_prot.c \
+	$(srcdir)/authunix_prot.c \
+	$(srcdir)/auth_gss.c \
+	$(srcdir)/auth_gssapi.c \
+	$(srcdir)/auth_gssapi_misc.c \
+	$(srcdir)/bindresvport.c \
+	$(srcdir)/clnt_generic.c \
+	$(srcdir)/clnt_perror.c \
+	$(srcdir)/clnt_raw.c \
+	$(srcdir)/clnt_simple.c \
+	$(srcdir)/clnt_tcp.c \
+	$(srcdir)/clnt_udp.c \
+	$(srcdir)/dyn.c \
+	$(srcdir)/rpc_dtablesize.c \
+	$(srcdir)/get_myaddress.c \
+	$(srcdir)/getrpcport.c \
+	$(srcdir)/pmap_clnt.c \
+	$(srcdir)/pmap_getmaps.c \
+	$(srcdir)/pmap_getport.c \
+	$(srcdir)/pmap_prot.c \
+	$(srcdir)/pmap_prot2.c \
+	$(srcdir)/pmap_rmt.c \
+	$(srcdir)/rpc_prot.c \
+	$(srcdir)/rpc_commondata.c \
+	$(srcdir)/rpc_callmsg.c \
+	$(srcdir)/svc.c \
+	$(srcdir)/svc_auth.c \
+	$(srcdir)/svc_auth_gss.c \
+	$(srcdir)/svc_auth_none.c \
+	$(srcdir)/svc_auth_unix.c \
+	$(srcdir)/svc_auth_gssapi.c \
+	$(srcdir)/svc_raw.c \
+	$(srcdir)/svc_run.c \
+	$(srcdir)/svc_simple.c \
+	$(srcdir)/svc_tcp.c \
+	$(srcdir)/svc_udp.c \
+	$(srcdir)/xdr.c \
+	$(srcdir)/xdr_array.c \
+	$(srcdir)/xdr_float.c \
+	$(srcdir)/xdr_mem.c \
+	$(srcdir)/xdr_rec.c \
+	$(srcdir)/xdr_reference.c \
+	$(srcdir)/xdr_stdio.c \
+	$(srcdir)/xdr_alloc.c
+
+OBJS = auth_none.$(OBJEXT) \
+	auth_unix.$(OBJEXT) \
+	authunix_prot.$(OBJEXT) \
+	authgss_prot.$(OBJEXT) \
+	auth_gss.$(OBJEXT) \
+	auth_gssapi.$(OBJEXT) \
+	auth_gssapi_misc.$(OBJEXT) \
+	bindresvport.$(OBJEXT) \
+	clnt_generic.$(OBJEXT) \
+	clnt_perror.$(OBJEXT) \
+	clnt_raw.$(OBJEXT) \
+	clnt_simple.$(OBJEXT) \
+	clnt_tcp.$(OBJEXT) \
+	clnt_udp.$(OBJEXT) \
+	dyn.$(OBJEXT) \
+	rpc_dtablesize.$(OBJEXT) \
+	get_myaddress.$(OBJEXT) \
+	getrpcport.$(OBJEXT) \
+	pmap_clnt.$(OBJEXT) \
+	pmap_getmaps.$(OBJEXT) \
+	pmap_getport.$(OBJEXT) \
+	pmap_prot.$(OBJEXT) \
+	pmap_prot2.$(OBJEXT) \
+	pmap_rmt.$(OBJEXT) \
+	rpc_prot.$(OBJEXT) \
+	rpc_commondata.$(OBJEXT) \
+	rpc_callmsg.$(OBJEXT) \
+	svc.$(OBJEXT) \
+	svc_auth.$(OBJEXT) \
+	svc_auth_gss.$(OBJEXT) \
+	svc_auth_none.$(OBJEXT) \
+	svc_auth_unix.$(OBJEXT) \
+	svc_auth_gssapi.$(OBJEXT) \
+	svc_raw.$(OBJEXT) \
+	svc_run.$(OBJEXT) \
+	svc_simple.$(OBJEXT) \
+	svc_tcp.$(OBJEXT) \
+	svc_udp.$(OBJEXT) \
+	xdr.$(OBJEXT) \
+	xdr_array.$(OBJEXT) \
+	xdr_float.$(OBJEXT) \
+	xdr_mem.$(OBJEXT) \
+	xdr_rec.$(OBJEXT) \
+	xdr_reference.$(OBJEXT) \
+	xdr_stdio.$(OBJEXT) \
+	xdr_alloc.$(OBJEXT)
+
+STLIBOBJS = \
+	auth_none.o \
+	auth_unix.o \
+	authgss_prot.o \
+	authunix_prot.o \
+	auth_gss.o \
+	auth_gssapi.o \
+	auth_gssapi_misc.o \
+	bindresvport.o \
+	clnt_generic.o \
+	clnt_perror.o \
+	clnt_raw.o \
+	clnt_simple.o \
+	clnt_tcp.o \
+	clnt_udp.o \
+	dyn.o \
+	rpc_dtablesize.o \
+	get_myaddress.o \
+	getrpcport.o \
+	pmap_clnt.o \
+	pmap_getmaps.o \
+	pmap_getport.o \
+	pmap_prot.o \
+	pmap_prot2.o \
+	pmap_rmt.o \
+	rpc_prot.o \
+	rpc_commondata.o \
+	rpc_callmsg.o \
+	svc.o \
+	svc_auth.o \
+	svc_auth_gss.o \
+	svc_auth_gssapi.o \
+	svc_auth_none.o \
+	svc_auth_unix.o \
+	svc_raw.o \
+	svc_run.o \
+	svc_simple.o \
+	svc_tcp.o \
+	svc_udp.o \
+	xdr.o \
+	xdr_array.o \
+	xdr_float.o \
+	xdr_mem.o \
+	xdr_rec.o \
+	xdr_reference.o \
+	xdr_stdio.o \
+	xdr_alloc.o
+
+HDRDIR=$(BUILDTOP)/include/gssrpc
+
+HDRS=	$(HDRDIR)/auth.h \
+	$(HDRDIR)/auth_gss.h \
+	$(HDRDIR)/auth_gssapi.h \
+	$(HDRDIR)/auth_unix.h \
+	$(HDRDIR)/clnt.h \
+	$(HDRDIR)/netdb.h \
+	$(HDRDIR)/pmap_clnt.h \
+	$(HDRDIR)/pmap_prot.h \
+	$(HDRDIR)/pmap_rmt.h \
+	$(HDRDIR)/rename.h \
+	$(HDRDIR)/rpc.h \
+	$(HDRDIR)/rpc_msg.h \
+	$(HDRDIR)/svc.h \
+	$(HDRDIR)/svc_auth.h \
+	$(HDRDIR)/types.h \
+	$(HDRDIR)/xdr.h
+
+all-prerecurse: includes
+all-prerecurse: all-liblinks
+
+all-windows:: $(OBJS)
+
+install-unix:: install-libs
+
+install-unix::
+	for i in $(SRC_HDRS); do \
+		(set -x; $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(KRB5_INCDIR)$(S)gssrpc$(S)$$i) ; \
+	done
+	for i in $(BUILD_HDRS); do \
+		(set -x; $(INSTALL_DATA) $$i $(DESTDIR)$(KRB5_INCDIR)$(S)gssrpc$(S)$$i) ; \
+	done
+
+BUILD_HDRS = types.h
+SRC_HDRS = auth.h auth_gss.h auth_gssapi.h auth_unix.h clnt.h \
+	netdb.h pmap_clnt.h pmap_prot.h pmap_rmt.h rename.h \
+	rpc.h rpc_msg.h svc.h svc_auth.h xdr.h
+
+includes:: $(SRC_HDRS) $(BUILD_HDRS)
+	if [ -d $(HDRDIR) ]; then :; else mkdir -p $(HDRDIR); fi
+	for i in $(SRC_HDRS) ; do \
+		i=`basename $$i`; \
+		if cmp $(srcdir)/$$i $(HDRDIR)/$$i >/dev/null 2>&1; then :; \
+		else \
+			(set -x; $(RM) $(HDRDIR)/$$i; \
+			 $(CP) $(srcdir)/$$i $(HDRDIR)/$$i) ; \
+		fi ; \
+	done
+	for i in $(BUILD_HDRS) ; do \
+		i=`basename $$i`; \
+		if cmp $$i $(HDRDIR)/$$i >/dev/null 2>&1; then :; \
+		else \
+			(set -x; $(RM) $(HDRDIR)/$$i; \
+			 $(CP) $$i $(HDRDIR)/$$i) ; \
+		fi ; \
+	done
+
+clean-unix::
+	$(RM) $(HDRS)
+	for i in $(SRC_HDRS) $(BUILD_HDRS) ; do \
+		$(RM) $(HDRDIR)/$$i ; \
+	done
+
+check-windows::
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+clean-windows::
+
+# stuff picked up from old "dyn" library
+#check-unix:: run-dyntest
+run-dyntest: dyntest
+	./dyntest
+dyntest: dyntest.o dyn.o
+	$(CC) -o dyntest dyntest.o dyn.o
+clean-unix:: clean-dyntest
+clean-dyntest:
+	$(RM) dyntest dyntest.o
+
+LCLINT=		lclint
+# +posixlib     gets more complete errno list than ansilib
+# -usedef       turns off bogus warnings from poor dataflow analysis (should be
+#               redundant with gcc warnings anyways)
+# -warnposix
+# +charintliteral
+# +ignoresigns
+# -predboolint
+# -exportlocal
+# -retvalint    allow ignoring of int return values (e.g., fputs)
+LCLINTOPTS=+posixlib \
+        +ignoresigns -predboolint \
+        +mod-uncon +modinternalstrict +modfilesys \
+        -expect 2
+do-dyn-lclint::
+	$(LCLINT) $(LCLINTOPTS) $(LOCALINCLUDES) $(DEFS) dyn.c dyntest.c
+
+# Should only rebuild types.h here (use CONFIG_FILES=), but the weird krb5
+# makefile post-processing is unconditional and would trash the makefile.
+types.h: types.stamp
+types.stamp: $(srcdir)/types.hin config.status
+	$(SHELL) config.status
+	touch types.stamp
+
+clean-unix::
+	$(RM) types.h types.stamp
+clean-windows::
+	$(RM) types.h types.stamp
+
+$(HDRS): includes
+
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+auth_none.so auth_none.po $(OUTPRE)auth_none.$(OBJEXT): \
+  auth_none.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h
+auth_unix.so auth_unix.po $(OUTPRE)auth_unix.$(OBJEXT): \
+  auth_unix.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h
+authgss_prot.so authgss_prot.po $(OUTPRE)authgss_prot.$(OBJEXT): \
+  authgss_prot.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+authunix_prot.so authunix_prot.po $(OUTPRE)authunix_prot.$(OBJEXT): \
+  authunix_prot.c $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/auth_unix.h
+auth_gss.so auth_gss.po $(OUTPRE)auth_gss.$(OBJEXT): \
+  auth_gss.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssapi/gssapi_generic.h
+auth_gssapi.so auth_gssapi.po $(OUTPRE)auth_gssapi.$(OBJEXT): \
+  auth_gssapi.c $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi_krb5.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/gssrpc/auth_gssapi.h
+auth_gssapi_misc.so auth_gssapi_misc.po $(OUTPRE)auth_gssapi_misc.$(OBJEXT): \
+  auth_gssapi_misc.c $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/gssrpc/auth_gssapi.h
+bindresvport.so bindresvport.po $(OUTPRE)bindresvport.$(OBJEXT): \
+  bindresvport.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+clnt_generic.so clnt_generic.po $(OUTPRE)clnt_generic.$(OBJEXT): \
+  clnt_generic.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+clnt_perror.so clnt_perror.po $(OUTPRE)clnt_perror.$(OBJEXT): \
+  clnt_perror.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h
+clnt_raw.so clnt_raw.po $(OUTPRE)clnt_raw.$(OBJEXT): \
+  clnt_raw.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+clnt_simple.so clnt_simple.po $(OUTPRE)clnt_simple.$(OBJEXT): \
+  clnt_simple.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+clnt_tcp.so clnt_tcp.po $(OUTPRE)clnt_tcp.$(OBJEXT): \
+  clnt_tcp.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/pmap_clnt.h
+clnt_udp.so clnt_udp.po $(OUTPRE)clnt_udp.$(OBJEXT): \
+  clnt_udp.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/pmap_clnt.h
+dyn.so dyn.po $(OUTPRE)dyn.$(OBJEXT): dyn.c dynP.h \
+  dyn.h
+rpc_dtablesize.so rpc_dtablesize.po $(OUTPRE)rpc_dtablesize.$(OBJEXT): \
+  rpc_dtablesize.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+get_myaddress.so get_myaddress.po $(OUTPRE)get_myaddress.$(OBJEXT): \
+  get_myaddress.c $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/gssrpc/pmap_prot.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS)
+getrpcport.so getrpcport.po $(OUTPRE)getrpcport.$(OBJEXT): \
+  getrpcport.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/pmap_clnt.h
+pmap_clnt.so pmap_clnt.po $(OUTPRE)pmap_clnt.$(OBJEXT): \
+  pmap_clnt.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/pmap_prot.h $(BUILDTOP)/include/gssrpc/pmap_clnt.h
+pmap_getmaps.so pmap_getmaps.po $(OUTPRE)pmap_getmaps.$(OBJEXT): \
+  pmap_getmaps.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/pmap_prot.h $(BUILDTOP)/include/gssrpc/pmap_clnt.h
+pmap_getport.so pmap_getport.po $(OUTPRE)pmap_getport.$(OBJEXT): \
+  pmap_getport.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/pmap_prot.h $(BUILDTOP)/include/gssrpc/pmap_clnt.h
+pmap_prot.so pmap_prot.po $(OUTPRE)pmap_prot.$(OBJEXT): \
+  pmap_prot.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/pmap_prot.h
+pmap_prot2.so pmap_prot2.po $(OUTPRE)pmap_prot2.$(OBJEXT): \
+  pmap_prot2.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/pmap_prot.h
+pmap_rmt.so pmap_rmt.po $(OUTPRE)pmap_rmt.$(OBJEXT): \
+  pmap_rmt.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/pmap_prot.h $(BUILDTOP)/include/gssrpc/pmap_clnt.h \
+  $(BUILDTOP)/include/gssrpc/pmap_rmt.h
+rpc_prot.so rpc_prot.po $(OUTPRE)rpc_prot.$(OBJEXT): \
+  rpc_prot.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+rpc_commondata.so rpc_commondata.po $(OUTPRE)rpc_commondata.$(OBJEXT): \
+  rpc_commondata.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+rpc_callmsg.so rpc_callmsg.po $(OUTPRE)rpc_callmsg.$(OBJEXT): \
+  rpc_callmsg.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+svc.so svc.po $(OUTPRE)svc.$(OBJEXT): svc.c $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/gssrpc/pmap_clnt.h
+svc_auth.so svc_auth.po $(OUTPRE)svc_auth.$(OBJEXT): \
+  svc_auth.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+svc_auth_gss.so svc_auth_gss.po $(OUTPRE)svc_auth_gss.$(OBJEXT): \
+  svc_auth_gss.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/auth_gssapi.h $(BUILDTOP)/include/gssapi/gssapi_generic.h
+svc_auth_none.so svc_auth_none.po $(OUTPRE)svc_auth_none.$(OBJEXT): \
+  svc_auth_none.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+svc_auth_unix.so svc_auth_unix.po $(OUTPRE)svc_auth_unix.$(OBJEXT): \
+  svc_auth_unix.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+svc_auth_gssapi.so svc_auth_gssapi.po $(OUTPRE)svc_auth_gssapi.$(OBJEXT): \
+  svc_auth_gssapi.c $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  $(BUILDTOP)/include/gssrpc/auth_gssapi.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS)
+svc_raw.so svc_raw.po $(OUTPRE)svc_raw.$(OBJEXT): svc_raw.c \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+svc_run.so svc_run.po $(OUTPRE)svc_run.$(OBJEXT): svc_run.c \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+svc_simple.so svc_simple.po $(OUTPRE)svc_simple.$(OBJEXT): \
+  svc_simple.c $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h \
+  $(BUILDTOP)/include/gssrpc/pmap_clnt.h
+svc_tcp.so svc_tcp.po $(OUTPRE)svc_tcp.$(OBJEXT): svc_tcp.c \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+svc_udp.so svc_udp.po $(OUTPRE)svc_udp.$(OBJEXT): svc_udp.c \
+  $(BUILDTOP)/include/gssrpc/rpc.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/include/gssrpc/auth.h $(BUILDTOP)/include/gssrpc/clnt.h \
+  $(BUILDTOP)/include/gssrpc/rpc_msg.h $(BUILDTOP)/include/gssrpc/auth_unix.h \
+  $(BUILDTOP)/include/gssrpc/auth_gss.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssrpc/svc_auth.h $(BUILDTOP)/include/gssrpc/svc.h
+xdr.so xdr.po $(OUTPRE)xdr.$(OBJEXT): xdr.c $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h
+xdr_array.so xdr_array.po $(OUTPRE)xdr_array.$(OBJEXT): \
+  xdr_array.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h
+xdr_float.so xdr_float.po $(OUTPRE)xdr_float.$(OBJEXT): \
+  xdr_float.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h
+xdr_mem.so xdr_mem.po $(OUTPRE)xdr_mem.$(OBJEXT): xdr_mem.c \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h
+xdr_rec.so xdr_rec.po $(OUTPRE)xdr_rec.$(OBJEXT): xdr_rec.c \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h
+xdr_reference.so xdr_reference.po $(OUTPRE)xdr_reference.$(OBJEXT): \
+  xdr_reference.c $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h
+xdr_stdio.so xdr_stdio.po $(OUTPRE)xdr_stdio.$(OBJEXT): \
+  xdr_stdio.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h
+xdr_alloc.so xdr_alloc.po $(OUTPRE)xdr_alloc.$(OBJEXT): \
+  xdr_alloc.c $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h dyn.h
diff --git a/mechglue/src/lib/rpc/auth.h b/mechglue/src/lib/rpc/auth.h
new file mode 100644
index 000000000..cc3de9764
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth.h
@@ -0,0 +1,219 @@
+/* @(#)auth.h	2.3 88/08/07 4.0 RPCSRC; from 1.17 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * auth.h, Authentication interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The data structures are completely opaque to the client.  The client
+ * is required to pass a AUTH * to routines that create rpc
+ * "sessions".
+ */
+#ifndef GSSRPC_AUTH_H
+#define GSSRPC_AUTH_H
+
+#include <gssrpc/xdr.h>
+
+GSSRPC__BEGIN_DECLS
+
+#define MAX_AUTH_BYTES	400
+#define MAXNETNAMELEN	255	/* maximum length of network user's name */
+
+/*
+ * Status returned from authentication check
+ */
+enum auth_stat {
+	AUTH_OK=0,
+	/*
+	 * failed at remote end
+	 */
+	AUTH_BADCRED=1,			/* bogus credentials (seal broken) */
+	AUTH_REJECTEDCRED=2,		/* client should begin new session */
+	AUTH_BADVERF=3,			/* bogus verifier (seal broken) */
+	AUTH_REJECTEDVERF=4,		/* verifier expired or was replayed */
+	AUTH_TOOWEAK=5,			/* rejected due to security reasons */
+	/*
+	 * failed locally
+	*/
+	AUTH_INVALIDRESP=6,		/* bogus response verifier */
+	AUTH_FAILED=7,			/* some unknown reason */
+	/*
+	 * RPCSEC_GSS errors
+	 */
+	RPCSEC_GSS_CREDPROBLEM = 13,
+	RPCSEC_GSS_CTXPROBLEM = 14
+};
+
+union des_block {
+#if 0 /* XXX nothing uses this, anyway */
+	struct {
+		uint32_t high;
+		uint32_t low;
+	} key;
+#endif
+	char c[8];
+};
+typedef union des_block des_block;
+extern bool_t	xdr_des_block(XDR *, des_block *);
+
+/*
+ * Authentication info.  Opaque to client.
+ */
+struct opaque_auth {
+	enum_t	oa_flavor;		/* flavor of auth */
+	caddr_t	oa_base;		/* address of more auth stuff */
+	u_int	oa_length;		/* not to exceed MAX_AUTH_BYTES */
+};
+
+
+/*
+ * Auth handle, interface to client side authenticators.
+ */
+struct rpc_msg;
+
+typedef struct AUTH {
+	struct	opaque_auth	ah_cred;
+	struct	opaque_auth	ah_verf;
+	union	des_block	ah_key;
+	struct auth_ops {
+		void	(*ah_nextverf)(struct AUTH *);
+	        /* nextverf & serialize */
+		int	(*ah_marshal)(struct AUTH *, XDR *);
+	        /* validate varifier */
+		int	(*ah_validate)(struct AUTH *,
+				       struct opaque_auth *);
+	        /* refresh credentials */
+		int	(*ah_refresh)(struct AUTH *, struct rpc_msg *);
+	        /* destroy this structure */
+		void	(*ah_destroy)(struct AUTH *);
+		/* encode data for wire */
+		int     (*ah_wrap)(struct AUTH *, XDR *, 
+				   xdrproc_t, caddr_t);
+	        /* decode data from wire */
+  	        int	(*ah_unwrap)(struct AUTH *, XDR *, 
+				     xdrproc_t, caddr_t);	
+	} *ah_ops;
+	void *ah_private;
+} AUTH;
+
+
+/*
+ * Authentication ops.
+ * The ops and the auth handle provide the interface to the authenticators.
+ *
+ * AUTH	*auth;
+ * XDR	*xdrs;
+ * struct opaque_auth verf;
+ */
+#define AUTH_NEXTVERF(auth)		\
+		((*((auth)->ah_ops->ah_nextverf))(auth))
+#define auth_nextverf(auth)		\
+		((*((auth)->ah_ops->ah_nextverf))(auth))
+
+#define AUTH_MARSHALL(auth, xdrs)	\
+		((*((auth)->ah_ops->ah_marshal))(auth, xdrs))
+#define auth_marshall(auth, xdrs)	\
+		((*((auth)->ah_ops->ah_marshal))(auth, xdrs))
+
+#define AUTH_VALIDATE(auth, verfp)	\
+		((*((auth)->ah_ops->ah_validate))((auth), verfp))
+#define auth_validate(auth, verfp)	\
+		((*((auth)->ah_ops->ah_validate))((auth), verfp))
+
+#define AUTH_REFRESH(auth, msg)		\
+		((*((auth)->ah_ops->ah_refresh))(auth, msg))
+#define auth_refresh(auth, msg)		\
+		((*((auth)->ah_ops->ah_refresh))(auth, msg))
+
+#define AUTH_WRAP(auth, xdrs, xfunc, xwhere)		\
+		((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \
+					      xfunc, xwhere))
+#define auth_wrap(auth, xdrs, xfunc, xwhere)		\
+		((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \
+					      xfunc, xwhere))
+#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere)		\
+		((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \
+					      xfunc, xwhere))
+#define auth_unwrap(auth, xdrs, xfunc, xwhere)		\
+		((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \
+					      xfunc, xwhere))
+
+#define AUTH_DESTROY(auth)		\
+		((*((auth)->ah_ops->ah_destroy))(auth))
+#define auth_destroy(auth)		\
+		((*((auth)->ah_ops->ah_destroy))(auth))
+
+
+#ifdef GSSRPC__IMPL
+/* RENAMED: should be _null_auth if we can use reserved namespace. */
+extern struct opaque_auth gssrpc__null_auth;
+#endif
+
+/*
+ * These are the various implementations of client side authenticators.
+ */
+
+/*
+ * Unix style authentication
+ * AUTH *authunix_create(machname, uid, gid, len, aup_gids)
+ *	char *machname;
+ *	int uid;
+ *	int gid;
+ *	int len;
+ *	int *aup_gids;
+ */
+extern AUTH *authunix_create(char *machname, int uid, int gid, int len,
+			     int *aup_gids);
+extern AUTH *authunix_create_default(void);	/* takes no parameters */
+extern AUTH *authnone_create(void);		/* takes no parameters */
+extern AUTH *authdes_create();
+extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
+
+#define AUTH_NONE	0		/* no authentication */
+#define	AUTH_NULL	0		/* backward compatibility */
+#define	AUTH_UNIX	1		/* unix style (uid, gids) */
+#define	AUTH_SHORT	2		/* short hand unix style */
+#define AUTH_DES	3		/* des style (encrypted timestamps) */
+#define AUTH_GSSAPI	300001		/* GSS-API style */
+#define RPCSEC_GSS	6		/* RPCSEC_GSS */
+
+#if 0
+/*
+ * BACKWARDS COMPATIBILIY!  OpenV*Secure 1.0 had AUTH_GSSAPI == 4.  We
+ * need to accept this value until 1.0 is dead.
+ */
+/* This conflicts with AUTH_KERB (Solaris). */
+#define AUTH_GSSAPI_COMPAT		4
+#endif
+
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_AUTH_H) */
diff --git a/mechglue/src/lib/rpc/auth_gss.c b/mechglue/src/lib/rpc/auth_gss.c
new file mode 100644
index 000000000..4e92699e1
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth_gss.c
@@ -0,0 +1,632 @@
+/*
+  auth_gss.c
+
+  RPCSEC_GSS client routines.
+  
+  Copyright (c) 2000 The Regents of the University of Michigan.
+  All rights reserved.
+
+  Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+  All rights reserved, all wrongs reversed.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. Neither the name of the University nor the names of its
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Id: auth_gss.c,v 1.35 2002/10/15 21:25:25 kwc Exp
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <gssrpc/auth.h>
+#include <gssrpc/auth_gss.h>
+#include <gssrpc/clnt.h>
+#include <netinet/in.h>
+#ifdef HAVE_HEIMDAL
+#include <gssapi.h>
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#else
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#endif
+
+#ifdef DEBUG_GSSAPI
+int auth_debug_gss = DEBUG_GSSAPI;
+int misc_debug_gss = DEBUG_GSSAPI;
+#endif
+
+static void	authgss_nextverf(AUTH *);
+static bool_t	authgss_marshal(AUTH *, XDR *);
+static bool_t	authgss_refresh(AUTH *, struct rpc_msg *);
+static bool_t	authgss_validate(AUTH *, struct opaque_auth *);
+static void	authgss_destroy(AUTH *);
+static void	authgss_destroy_context(AUTH *);
+static bool_t	authgss_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);
+static bool_t	authgss_unwrap(AUTH *, XDR *, xdrproc_t, caddr_t);
+
+
+/*
+ * from mit-krb5-1.2.1 mechglue/mglueP.h:
+ * Array of context IDs typed by mechanism OID
+ */
+typedef struct gss_union_ctx_id_t {
+  gss_OID     mech_type;
+  gss_ctx_id_t    internal_ctx_id;
+} gss_union_ctx_id_desc, *gss_union_ctx_id_t;
+
+static struct auth_ops authgss_ops = {
+	authgss_nextverf,
+	authgss_marshal,
+	authgss_validate,
+	authgss_refresh,
+	authgss_destroy,
+	authgss_wrap,
+	authgss_unwrap
+};
+
+#ifdef DEBUG
+
+/* useful as i add more mechanisms */
+void
+print_rpc_gss_sec(struct rpc_gss_sec *ptr)
+{
+	int i;
+	char *p;
+
+	log_debug("rpc_gss_sec:");
+	if(ptr->mech == NULL)
+		log_debug("NULL gss_OID mech");
+	else {
+		fprintf(stderr, "     mechanism_OID: {");
+		p = (char *)ptr->mech->elements;
+		for (i=0; i < ptr->mech->length; i++)
+			/* First byte of OIDs encoded to save a byte */
+			if (i == 0) {
+				int first, second;
+				if (*p < 40) {
+					first = 0;
+					second = *p;
+				}
+				else if (40 <= *p && *p < 80) {
+					first = 1;
+					second = *p - 40;
+				}
+				else if (80 <= *p && *p < 127) {
+					first = 2;
+					second = *p - 80;
+				}
+				else {
+					/* Invalid value! */
+					first = -1;
+					second = -1;
+				}
+				fprintf(stderr, " %u %u", first, second);
+				p++;
+			}
+			else {
+				fprintf(stderr, " %u", (unsigned char)*p++);
+			}
+		fprintf(stderr, " }\n");
+	}
+	fprintf(stderr, "     qop: %d\n", ptr->qop);
+	fprintf(stderr, "     service: %d\n", ptr->svc);
+	fprintf(stderr, "     cred: %p\n", ptr->cred);
+	fprintf(stderr, "     req_flags: 0x%08x", ptr->req_flags);
+}
+#endif /*DEBUG*/
+
+struct rpc_gss_data {
+	bool_t			 established;	/* context established */
+	bool_t			 inprogress;
+  gss_buffer_desc      gc_wire_verf; /* save GSS_S_COMPLETE NULL RPC verfier 
+                                   * to process at end of context negotiation*/
+	CLIENT			*clnt;		/* client handle */
+	gss_name_t		 name;		/* service name */
+	struct rpc_gss_sec	 sec;		/* security tuple */
+	gss_ctx_id_t		 ctx;		/* context id */
+	struct rpc_gss_cred	 gc;		/* client credentials */
+	uint32_t		 win;		/* sequence window */
+};
+
+#define	AUTH_PRIVATE(auth)	((struct rpc_gss_data *)auth->ah_private)
+
+static struct timeval AUTH_TIMEOUT = { 25, 0 };
+
+AUTH *
+authgss_create(CLIENT *clnt, gss_name_t name, struct rpc_gss_sec *sec)
+{
+	AUTH			*auth, *save_auth;
+	struct rpc_gss_data	*gd;
+	OM_uint32		min_stat = 0;
+
+	log_debug("in authgss_create()");
+	
+	memset(&rpc_createerr, 0, sizeof(rpc_createerr));
+	
+	if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
+		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+		rpc_createerr.cf_error.re_errno = ENOMEM;
+		return (NULL);
+	}
+	if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
+		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+		rpc_createerr.cf_error.re_errno = ENOMEM;
+		free(auth);
+		return (NULL);
+	}
+	if (name != GSS_C_NO_NAME) {
+		if (gss_duplicate_name(&min_stat, name, &gd->name)
+						!= GSS_S_COMPLETE) {
+			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+			rpc_createerr.cf_error.re_errno = ENOMEM;
+			free(auth);
+			return (NULL);
+		}
+	}
+	else
+		gd->name = name;
+
+	gd->clnt = clnt;
+	gd->ctx = GSS_C_NO_CONTEXT;
+	gd->sec = *sec;
+
+	gd->gc.gc_v = RPCSEC_GSS_VERSION;
+	gd->gc.gc_proc = RPCSEC_GSS_INIT;
+	gd->gc.gc_svc = gd->sec.svc;
+	
+	auth->ah_ops = &authgss_ops;
+	auth->ah_private = (caddr_t)gd;
+	
+	save_auth = clnt->cl_auth;
+	clnt->cl_auth = auth;
+
+	if (!authgss_refresh(auth, NULL))
+		auth = NULL;
+	
+	clnt->cl_auth = save_auth;
+	
+	log_debug("authgss_create returning auth 0x%08x", auth);
+	return (auth);
+}
+
+AUTH *
+authgss_create_default(CLIENT *clnt, char *service, struct rpc_gss_sec *sec)
+{
+	AUTH			*auth;
+	OM_uint32		 maj_stat = 0, min_stat = 0;
+	gss_buffer_desc		 sname;
+	gss_name_t		 name;
+
+	log_debug("in authgss_create_default()");
+	
+
+	sname.value = service;
+	sname.length = strlen(service);
+	
+	maj_stat = gss_import_name(&min_stat, &sname,
+		(gss_OID)gss_nt_service_name,
+		&name);
+
+	if (maj_stat != GSS_S_COMPLETE) {
+		log_status("gss_import_name", maj_stat, min_stat);
+		rpc_createerr.cf_stat = RPC_AUTHERROR;
+		return (NULL);
+	}
+
+	auth = authgss_create(clnt, name, sec);
+	
+ 	if (name != GSS_C_NO_NAME)
+ 		gss_release_name(&min_stat, &name);
+	
+	log_debug("authgss_create_default returning auth 0x%08x", auth);
+	return (auth);
+}
+
+bool_t
+authgss_get_private_data(AUTH *auth, struct authgss_private_data *pd)
+{
+	struct rpc_gss_data	*gd;
+
+	log_debug("in authgss_get_private_data()");
+
+	if (!auth || !pd)
+		return (FALSE);
+
+	gd = AUTH_PRIVATE(auth);
+
+	if (!gd || !gd->established)
+		return (FALSE);
+
+	pd->pd_ctx = gd->ctx;
+	pd->pd_ctx_hndl = gd->gc.gc_ctx;
+	pd->pd_seq_win = gd->win;
+
+	return (TRUE);
+}
+
+static void
+authgss_nextverf(AUTH *auth)
+{
+	log_debug("in authgss_nextverf()\n");
+	/* no action necessary */
+}
+
+static bool_t
+authgss_marshal(AUTH *auth, XDR *xdrs)
+{
+	XDR			 tmpxdrs;
+	char			 tmp[MAX_AUTH_BYTES];
+	struct rpc_gss_data	*gd;
+	gss_buffer_desc		 rpcbuf, checksum;
+	OM_uint32		 maj_stat, min_stat;
+	bool_t			 xdr_stat;
+	
+	log_debug("in authgss_marshal()");
+	
+	gd = AUTH_PRIVATE(auth);
+
+	if (gd->established)
+		gd->gc.gc_seq++;
+	
+	xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE);
+	
+	if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) {
+		XDR_DESTROY(&tmpxdrs);
+		return (FALSE);
+	}
+	auth->ah_cred.oa_flavor = RPCSEC_GSS;
+	auth->ah_cred.oa_base = tmp;
+	auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs);
+	
+	XDR_DESTROY(&tmpxdrs);
+	
+	if (!xdr_opaque_auth(xdrs, &auth->ah_cred))
+		return (FALSE);
+	
+	if (gd->gc.gc_proc == RPCSEC_GSS_INIT ||
+	    gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
+		return (xdr_opaque_auth(xdrs, &gssrpc__null_auth));
+	}
+	/* Checksum serialized RPC header, up to and including credential. */
+	rpcbuf.length = XDR_GETPOS(xdrs);
+	XDR_SETPOS(xdrs, 0);
+	rpcbuf.value = XDR_INLINE(xdrs, (int)rpcbuf.length);
+	
+	maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop,
+			    &rpcbuf, &checksum);
+
+	if (maj_stat != GSS_S_COMPLETE) {
+		log_status("gss_get_mic", maj_stat, min_stat);
+		if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
+			gd->established = FALSE;
+			authgss_destroy_context(auth);
+		}
+		return (FALSE);
+	}
+	auth->ah_verf.oa_flavor = RPCSEC_GSS;
+	auth->ah_verf.oa_base = checksum.value;
+	auth->ah_verf.oa_length = checksum.length;
+	
+	xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf);
+	gss_release_buffer(&min_stat, &checksum);
+	
+	return (xdr_stat);
+}
+
+static bool_t
+authgss_validate(AUTH *auth, struct opaque_auth *verf)
+{
+	struct rpc_gss_data	*gd;
+	uint32_t		 num;
+	gss_qop_t		 qop_state;
+	gss_buffer_desc		 signbuf, checksum;
+	OM_uint32		 maj_stat, min_stat;
+
+	log_debug("in authgss_validate()");
+	
+	gd = AUTH_PRIVATE(auth);
+
+	if (gd->established == FALSE) {
+		/* would like to do this only on NULL rpc - gc->established is good enough.
+		 * save the on the wire verifier to validate last INIT phase packet
+		 * after decode if the major status is GSS_S_COMPLETE 
+		 */
+		if ((gd->gc_wire_verf.value = mem_alloc(verf->oa_length)) == NULL) {
+			fprintf(stderr, "gss_validate: out of memory\n");
+			return (FALSE);
+		}
+		memcpy(gd->gc_wire_verf.value, verf->oa_base, verf->oa_length);
+		gd->gc_wire_verf.length = verf->oa_length;
+		return (TRUE);
+  	}
+
+	if (gd->gc.gc_proc == RPCSEC_GSS_INIT ||
+	    gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
+		num = htonl(gd->win);
+	}
+	else num = htonl(gd->gc.gc_seq);
+	
+	signbuf.value = #
+	signbuf.length = sizeof(num);
+	
+	checksum.value = verf->oa_base;
+	checksum.length = verf->oa_length;
+	
+	maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf,
+				  &checksum, &qop_state);
+	if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) {
+		log_status("gss_verify_mic", maj_stat, min_stat);
+		if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
+			gd->established = FALSE;
+			authgss_destroy_context(auth);
+		}
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+static bool_t
+authgss_refresh(AUTH *auth, struct rpc_msg *msg)
+{
+	struct rpc_gss_data	*gd;
+	struct rpc_gss_init_res	 gr;
+	gss_buffer_desc		*recv_tokenp, send_token;
+	OM_uint32		 maj_stat, min_stat, call_stat, ret_flags, req_flags=0;
+
+	log_debug("in authgss_refresh()");
+	
+	gd = AUTH_PRIVATE(auth);
+	
+	if (gd->established || gd->inprogress)
+		return (TRUE);
+	
+	/* GSS context establishment loop. */
+	memset(&gr, 0, sizeof(gr));
+	recv_tokenp = GSS_C_NO_BUFFER;
+	
+#ifdef DEBUG
+	print_rpc_gss_sec(&gd->sec);
+#endif /*DEBUG*/
+
+	for (;;) {
+		gd->inprogress = TRUE;
+		maj_stat = gss_init_sec_context(&min_stat,
+						gd->sec.cred,
+						&gd->ctx,
+						gd->name,
+						gd->sec.mech,
+						gd->sec.req_flags,
+						0,		/* time req */
+						NULL,		/* channel */
+						recv_tokenp,
+						NULL,		/* used mech */
+						&send_token,
+						&ret_flags,
+						NULL);		/* time rec */
+		
+		log_status("gss_init_sec_context", maj_stat, min_stat);
+		if (recv_tokenp != GSS_C_NO_BUFFER) {
+			gss_release_buffer(&min_stat, &gr.gr_token);
+			recv_tokenp = GSS_C_NO_BUFFER;
+		}
+		if (maj_stat != GSS_S_COMPLETE &&
+		    maj_stat != GSS_S_CONTINUE_NEEDED) {
+			log_status("gss_init_sec_context (error)", maj_stat, min_stat);
+			break;
+		}
+		if (send_token.length != 0) {
+			memset(&gr, 0, sizeof(gr));
+			
+			call_stat = clnt_call(gd->clnt, NULLPROC,
+					      xdr_rpc_gss_init_args,
+					      &send_token,
+					      xdr_rpc_gss_init_res,
+					      (caddr_t)&gr, AUTH_TIMEOUT);
+			
+			gss_release_buffer(&min_stat, &send_token);
+
+			log_debug("authgss_refresh: call_stat=%d", call_stat);
+			log_debug("%s", clnt_sperror(gd->clnt, "authgss_refresh"));
+			if (call_stat != RPC_SUCCESS ||
+			    (gr.gr_major != GSS_S_COMPLETE &&
+			     gr.gr_major != GSS_S_CONTINUE_NEEDED))
+				break;
+			
+			if (gr.gr_ctx.length != 0) {
+				if (gd->gc.gc_ctx.value)
+					gss_release_buffer(&min_stat,
+							   &gd->gc.gc_ctx);
+				gd->gc.gc_ctx = gr.gr_ctx;
+			}
+			if (gr.gr_token.length != 0) {
+				if (maj_stat != GSS_S_CONTINUE_NEEDED)
+					break;
+				recv_tokenp = &gr.gr_token;
+			}
+			gd->gc.gc_proc = RPCSEC_GSS_CONTINUE_INIT;
+		}
+		
+		/* GSS_S_COMPLETE => check gss header verifier, usually checked in
+		 * gss_validate
+		 */
+		if (maj_stat == GSS_S_COMPLETE) {
+			gss_buffer_desc   bufin;
+			gss_buffer_desc   bufout;
+			uint32_t seq;
+			gss_qop_t qop_state = 0;
+
+			seq = htonl(gr.gr_win);
+			bufin.value = (u_char *)&seq;
+			bufin.length = sizeof(seq);
+			bufout.value = (u_char *)gd->gc_wire_verf.value;
+			bufout.length = gd->gc_wire_verf.length;
+
+			log_debug("authgss_refresh: GSS_S_COMPLETE: calling verify_mic");
+			maj_stat = gss_verify_mic(&min_stat,gd->ctx,
+				&bufin, &bufout, &qop_state);
+
+			if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) {
+				log_status("gss_verify_mic", maj_stat, min_stat);
+				gss_release_buffer(&min_stat, &gd->gc_wire_verf);
+				if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
+					gd->established = FALSE;
+					authgss_destroy_context(auth);
+				}
+				return (FALSE);
+			}
+			gss_release_buffer(&min_stat, &gd->gc_wire_verf);
+			gd->established = TRUE;
+			gd->inprogress = FALSE;
+			gd->gc.gc_proc = RPCSEC_GSS_DATA;
+			gd->gc.gc_seq = 0;
+			gd->win = gr.gr_win;
+			break;
+		}
+	}
+	log_status("authgss_refresh: at end of context negotiation", maj_stat, min_stat);
+	/* End context negotiation loop. */
+	if (gd->gc.gc_proc != RPCSEC_GSS_DATA) {
+		log_debug("authgss_refresh: returning ERROR (gc_proc %d)", gd->gc.gc_proc);
+		if (gr.gr_token.length != 0)
+			gss_release_buffer(&min_stat, &gr.gr_token);
+		
+		authgss_destroy(auth);
+		auth = NULL;
+		rpc_createerr.cf_stat = RPC_AUTHERROR;
+		
+		return (FALSE);
+	}
+	log_debug("authgss_refresh: returning SUCCESS");
+	return (TRUE);
+}
+
+bool_t
+authgss_service(AUTH *auth, int svc)
+{
+	struct rpc_gss_data	*gd;
+
+	log_debug("in authgss_service()");
+
+	if (!auth)
+		return(FALSE);
+	gd = AUTH_PRIVATE(auth);
+	if (!gd || !gd->established)
+		return (FALSE);
+	gd->sec.svc = svc;
+	gd->gc.gc_svc = svc;
+	return (TRUE);
+}
+
+static void
+authgss_destroy_context(AUTH *auth)
+{
+	struct rpc_gss_data	*gd;
+	OM_uint32		 min_stat;
+	enum clnt_stat		 callstat;
+
+	log_debug("in authgss_destroy_context()");
+	
+	gd = AUTH_PRIVATE(auth);
+	
+	if (gd->gc.gc_ctx.length != 0) {
+		if (gd->established) {
+			gd->gc.gc_proc = RPCSEC_GSS_DESTROY;
+			callstat = clnt_call(gd->clnt, NULLPROC,
+					     xdr_void, NULL,
+					     xdr_void, NULL,
+					     AUTH_TIMEOUT);
+			log_debug("%s",
+				  clnt_sperror(gd->clnt,
+					       "authgss_destroy_context"));
+		}
+		gss_release_buffer(&min_stat, &gd->gc.gc_ctx);
+		/* XXX ANDROS check size of context  - should be 8 */
+		memset(&gd->gc.gc_ctx, 0, sizeof(gd->gc.gc_ctx));
+	}
+	if (gd->ctx != GSS_C_NO_CONTEXT) {
+		gss_delete_sec_context(&min_stat, &gd->ctx, NULL);
+		gd->ctx = GSS_C_NO_CONTEXT;
+	}
+	gd->established = FALSE;
+
+	log_debug("finished authgss_destroy_context()");
+}
+
+static void
+authgss_destroy(AUTH *auth)
+{
+	struct rpc_gss_data	*gd;
+	OM_uint32		 min_stat;
+	
+	log_debug("in authgss_destroy()");
+	
+	gd = AUTH_PRIVATE(auth);
+	
+	authgss_destroy_context(auth);
+	
+	if (gd->name != GSS_C_NO_NAME)
+		gss_release_name(&min_stat, &gd->name);
+
+	free(gd);
+	free(auth);
+}
+
+bool_t
+authgss_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+	struct rpc_gss_data	*gd;
+
+	log_debug("in authgss_wrap()");
+	
+	gd = AUTH_PRIVATE(auth);
+
+	if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
+		return ((*xdr_func)(xdrs, xdr_ptr));
+	}
+	return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
+				 gd->ctx, gd->sec.qop,
+				 gd->sec.svc, gd->gc.gc_seq));
+}
+
+bool_t
+authgss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+	struct rpc_gss_data	*gd;
+
+	log_debug("in authgss_unwrap()");
+	
+	gd = AUTH_PRIVATE(auth);
+	
+	if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
+		return ((*xdr_func)(xdrs, xdr_ptr));
+	}
+	return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
+				 gd->ctx, gd->sec.qop,
+				 gd->sec.svc, gd->gc.gc_seq));
+}
diff --git a/mechglue/src/lib/rpc/auth_gss.h b/mechglue/src/lib/rpc/auth_gss.h
new file mode 100644
index 000000000..ea5db92b9
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth_gss.h
@@ -0,0 +1,149 @@
+/*
+  auth_gssapi.h
+  
+  Copyright (c) 2000 The Regents of the University of Michigan.
+  All rights reserved.
+  
+  Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+  All rights reserved, all wrongs reversed.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. Neither the name of the University nor the names of its
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Id: auth_gss.h,v 1.13 2002/05/08 16:54:33 andros Exp
+*/
+
+#ifndef GSSRPC_AUTH_GSS_H
+#define GSSRPC_AUTH_GSS_H
+
+#include <gssrpc/rpc.h>
+#include <gssrpc/clnt.h>
+#ifdef HAVE_HEIMDAL
+#include <gssapi.h>
+#else
+#include <gssapi/gssapi.h>
+#endif
+
+GSSRPC__BEGIN_DECLS
+
+/* RPCSEC_GSS control procedures. */
+typedef enum {
+	RPCSEC_GSS_DATA = 0,
+	RPCSEC_GSS_INIT = 1,
+	RPCSEC_GSS_CONTINUE_INIT = 2,
+	RPCSEC_GSS_DESTROY = 3
+} rpc_gss_proc_t;
+
+/* RPCSEC_GSS services. */
+typedef enum {
+	RPCSEC_GSS_SVC_NONE = 1,
+	RPCSEC_GSS_SVC_INTEGRITY = 2,
+	RPCSEC_GSS_SVC_PRIVACY = 3
+} rpc_gss_svc_t;
+
+#define RPCSEC_GSS_VERSION	1
+
+/* RPCSEC_GSS security triple. */
+struct rpc_gss_sec {
+	gss_OID		mech;		/* mechanism */
+	gss_qop_t	qop;		/* quality of protection */
+	rpc_gss_svc_t	svc;		/* service */
+	gss_cred_id_t   cred;		/* cred handle */
+	uint32_t	req_flags;	/* req flags for init_sec_context */
+};
+
+/* Private data required for kernel implementation */
+struct authgss_private_data {
+	gss_ctx_id_t	pd_ctx;		/* Session context handle */
+	gss_buffer_desc	pd_ctx_hndl;	/* Credentials context handle */
+	uint32_t	pd_seq_win;	/* Sequence window */
+};
+
+/* Krb 5 default mechanism 
+#define KRB5OID  "1.2.840.113554.1.2.2"
+
+gss_OID_desc krb5oid = {
+	20, KRB5OID 
+};
+ */
+
+/*
+struct rpc_gss_sec krb5mech = { 
+	(gss_OID)&krb5oid,
+	GSS_QOP_DEFAULT,
+	RPCSEC_GSS_SVC_NONE
+}; 
+*/
+
+/* Credentials. */
+struct rpc_gss_cred {
+	u_int		gc_v;		/* version */
+	rpc_gss_proc_t	gc_proc;	/* control procedure */
+	uint32_t	gc_seq;		/* sequence number */
+	rpc_gss_svc_t	gc_svc;		/* service */
+	gss_buffer_desc	gc_ctx;		/* context handle */
+};
+
+/* Context creation response. */
+struct rpc_gss_init_res {
+	gss_buffer_desc		gr_ctx;		/* context handle */
+	uint32_t		gr_major;	/* major status */
+	uint32_t		gr_minor;	/* minor status */
+	uint32_t		gr_win;		/* sequence window */
+	gss_buffer_desc		gr_token;	/* token */
+};
+
+/* Maximum sequence number value. */
+#define MAXSEQ		0x80000000
+
+/* Prototypes. */
+bool_t	xdr_rpc_gss_buf		(XDR *xdrs, gss_buffer_t, u_int maxsize);
+bool_t	xdr_rpc_gss_cred	(XDR *xdrs, struct rpc_gss_cred *p);
+bool_t	xdr_rpc_gss_init_args	(XDR *xdrs, gss_buffer_desc *p);
+bool_t	xdr_rpc_gss_init_res	(XDR *xdrs, struct rpc_gss_init_res *p);
+bool_t	xdr_rpc_gss_data	(XDR *xdrs, xdrproc_t xdr_func,
+				 caddr_t xdr_ptr, gss_ctx_id_t ctx,
+				 gss_qop_t qop, rpc_gss_svc_t svc,
+				 uint32_t seq);
+bool_t	xdr_rpc_gss_wrap_data	(XDR *xdrs, xdrproc_t xdr_func, caddr_t
+				 xdr_ptr, gss_ctx_id_t ctx, gss_qop_t qop,
+				 rpc_gss_svc_t svc, uint32_t seq);
+bool_t	xdr_rpc_gss_unwrap_data	(XDR *xdrs, xdrproc_t xdr_func, caddr_t
+				 xdr_ptr, gss_ctx_id_t ctx, gss_qop_t qop,
+				 rpc_gss_svc_t svc, uint32_t seq);
+
+AUTH   *authgss_create		(CLIENT *, gss_name_t, struct rpc_gss_sec *);
+AUTH   *authgss_create_default	(CLIENT *, char *, struct rpc_gss_sec *);
+bool_t authgss_service		(AUTH *auth, int svc);
+bool_t authgss_get_private_data (AUTH *auth, struct authgss_private_data *);
+
+#ifdef GSSRPC__IMPL
+void	log_debug		(const char *fmt, ...);
+void	log_status		(char *m, OM_uint32 major, OM_uint32 minor);
+void	log_hexdump		(const u_char *buf, int len, int offset);
+#endif
+
+GSSRPC__END_DECLS
+#endif /* !defined(GSSRPC_AUTH_GSS_H) */
diff --git a/mechglue/src/lib/rpc/auth_gssapi.c b/mechglue/src/lib/rpc/auth_gssapi.c
new file mode 100644
index 000000000..3d6e6fe63
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth_gssapi.c
@@ -0,0 +1,812 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#ifdef GSSAPI_KRB5
+#include <gssapi/gssapi_krb5.h>
+#endif
+
+#include <gssrpc/rpc.h>
+#include <gssrpc/auth_gssapi.h>
+
+#ifdef __CODECENTER__
+#define DEBUG_GSSAPI 1
+#endif
+
+#ifdef DEBUG_GSSAPI
+int auth_debug_gssapi = DEBUG_GSSAPI;
+#define L_PRINTF(l,args) if (auth_debug_gssapi >= l) printf args
+#define PRINTF(args) L_PRINTF(99, args)
+#define AUTH_GSSAPI_DISPLAY_STATUS(args) \
+	if (auth_debug_gssapi) auth_gssapi_display_status args
+#else
+#define PRINTF(args)
+#define L_PRINTF(l, args)
+#define AUTH_GSSAPI_DISPLAY_STATUS(args)
+#endif
+   
+static void 	auth_gssapi_nextverf(AUTH *);
+static bool_t 	auth_gssapi_marshall(AUTH *, XDR *);
+static bool_t	auth_gssapi_validate(AUTH *, struct opaque_auth *);
+static bool_t	auth_gssapi_refresh(AUTH *, struct rpc_msg *);
+static bool_t	auth_gssapi_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);
+static bool_t	auth_gssapi_unwrap(AUTH *, XDR *, xdrproc_t, caddr_t);
+static void	auth_gssapi_destroy(AUTH *);
+   
+static bool_t	marshall_new_creds(AUTH *, bool_t, gss_buffer_t);
+
+static struct auth_ops auth_gssapi_ops = {
+     auth_gssapi_nextverf,
+     auth_gssapi_marshall,
+     auth_gssapi_validate,
+     auth_gssapi_refresh,
+     auth_gssapi_destroy,
+     auth_gssapi_wrap,
+     auth_gssapi_unwrap,
+};
+
+/*
+ * the ah_private data structure for an auth_handle
+ */
+struct auth_gssapi_data {
+     bool_t established;
+     CLIENT *clnt;
+     gss_ctx_id_t context;
+     gss_buffer_desc client_handle;
+     uint32_t seq_num;
+     int def_cred;
+     
+     /* pre-serialized ah_cred */
+     unsigned char cred_buf[MAX_AUTH_BYTES];
+     uint32_t cred_len;
+};
+#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private)
+
+/*
+ * Function: auth_gssapi_create_default
+ *
+ * Purpose:  Create a GSS-API style authenticator, with default
+ * options, and return the handle.
+ *
+ * Effects: See design document, section XXX.
+ */
+AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name)
+{
+     AUTH *auth;
+     OM_uint32 gssstat, minor_stat;
+     gss_buffer_desc input_name;
+     gss_name_t target_name;
+     
+     input_name.value = service_name;
+     input_name.length = strlen(service_name) + 1;
+     
+     gssstat = gss_import_name(&minor_stat, &input_name, 
+			       gss_nt_service_name, &target_name);
+     if (gssstat != GSS_S_COMPLETE) {
+	  AUTH_GSSAPI_DISPLAY_STATUS(("parsing name", gssstat,
+				      minor_stat));
+	  rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+	  rpc_createerr.cf_error.re_errno = ENOMEM;
+	  return NULL;
+     }
+     
+     auth = auth_gssapi_create(clnt,
+			       &gssstat,
+			       &minor_stat,
+			       GSS_C_NO_CREDENTIAL,
+			       target_name,
+			       GSS_C_NULL_OID,
+			       GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+			       0,
+			       NULL,
+			       NULL,
+			       NULL);
+     
+     gss_release_name(&minor_stat, &target_name);
+     return auth;
+}
+
+/*
+ * Function: auth_gssapi_create
+ *
+ * Purpose: Create a GSS-API style authenticator, with all the
+ * options, and return the handle.
+ *
+ * Effects: See design document, section XXX.
+ */
+AUTH *auth_gssapi_create(
+     CLIENT *clnt,
+     OM_uint32 *gssstat,
+     OM_uint32 *minor_stat,
+     gss_cred_id_t claimant_cred_handle,
+     gss_name_t target_name,
+     gss_OID mech_type,
+     OM_uint32 req_flags,
+     OM_uint32 time_req,
+     gss_OID *actual_mech_type,
+     OM_uint32 *ret_flags,
+     OM_uint32 *time_rec)
+{
+     AUTH *auth, *save_auth;
+     struct auth_gssapi_data *pdata;
+     struct gss_channel_bindings_struct bindings, *bindp;
+     struct sockaddr_in laddr, raddr;
+     enum clnt_stat callstat;
+     struct timeval timeout;
+     int bindings_failed;
+     rpcproc_t init_func;
+     
+     auth_gssapi_init_arg call_arg;
+     auth_gssapi_init_res call_res;
+     gss_buffer_desc *input_token, isn_buf;
+     
+     memset(&rpc_createerr, 0, sizeof(rpc_createerr));
+     
+     /* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */
+     /* has not already been called.. therefore, we can just pick */
+     /* something reasonable-sounding.. */
+     timeout.tv_sec = 30;
+     timeout.tv_usec = 0;
+     
+     auth = NULL;
+     pdata = NULL;
+     
+     /* don't assume the caller will want to change clnt->cl_auth */
+     save_auth = clnt->cl_auth;
+
+     auth = (AUTH *) malloc(sizeof(*auth));
+     pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata));
+     if (auth == NULL || pdata == NULL) {
+	  rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+	  rpc_createerr.cf_error.re_errno = ENOMEM;
+	  goto cleanup;
+     }
+     memset((char *) auth, 0, sizeof(*auth));
+     memset((char *) pdata, 0, sizeof(*pdata));
+     
+     auth->ah_ops = &auth_gssapi_ops;
+     auth->ah_private = (caddr_t) pdata;
+     
+     /* initial creds are auth_msg TRUE and no handle */
+     marshall_new_creds(auth, TRUE, NULL);
+     
+     /* initial verifier is empty */
+     auth->ah_verf.oa_flavor = AUTH_GSSAPI;
+     auth->ah_verf.oa_base = NULL;
+     auth->ah_verf.oa_length = 0;
+     
+     AUTH_PRIVATE(auth)->established = FALSE;
+     AUTH_PRIVATE(auth)->clnt = clnt;
+     AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle ==
+				     GSS_C_NO_CREDENTIAL);
+     
+     clnt->cl_auth = auth;
+
+     /* start by trying latest version */
+     call_arg.version = 4;
+     bindings_failed = 0;
+
+try_new_version:
+     /* set state for initial call to init_sec_context */
+     input_token = GSS_C_NO_BUFFER;
+     AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT;
+     init_func = AUTH_GSSAPI_INIT;
+
+#ifdef GSSAPI_KRB5
+     /*
+      * OV servers up to version 3 used the old mech id.  Beta 7
+      * servers used version 3 with the new mech id; however, the beta
+      * 7 gss-api accept_sec_context accepts either mech id.  Thus, if
+      * any server rejects version 4, we fall back to version 3 with
+      * the old mech id; for the OV server it will be right, and for
+      * the beta 7 server it will be accepted.  Not ideal, but it
+      * works.
+      */
+     if (call_arg.version < 4 && (mech_type == gss_mech_krb5 ||
+				  mech_type == GSS_C_NULL_OID))
+	  mech_type = (gss_OID) gss_mech_krb5_old;
+#endif
+
+     if (!bindings_failed && call_arg.version >= 3) {
+	  if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) {
+	       PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed"));
+	       goto cleanup;
+	  }
+	  if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) {
+	       PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed"));
+	       goto cleanup;
+	  }
+
+	  memset(&bindings, 0, sizeof(bindings));
+	  bindings.application_data.length = 0;
+	  bindings.initiator_addrtype = GSS_C_AF_INET;
+	  bindings.initiator_address.length = 4;
+	  bindings.initiator_address.value = &laddr.sin_addr.s_addr;
+	  
+	  bindings.acceptor_addrtype = GSS_C_AF_INET;
+	  bindings.acceptor_address.length = 4;
+	  bindings.acceptor_address.value = &raddr.sin_addr.s_addr;
+	  bindp = &bindings;
+     } else {
+	  bindp = NULL;
+     }
+     
+     memset((char *) &call_res, 0, sizeof(call_res));
+     
+next_token:
+     *gssstat = gss_init_sec_context(minor_stat,
+				     claimant_cred_handle,
+				     &AUTH_PRIVATE(auth)->context,
+				     target_name,
+				     mech_type,
+				     req_flags,
+				     time_req,
+				     bindp,
+				     input_token,
+				     actual_mech_type,
+				     &call_arg.token,
+				     ret_flags,
+				     time_rec);
+     
+     if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) {
+	  AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat,
+				      *minor_stat));
+	  goto cleanup;
+     }
+     
+     /* if we got a token, pass it on */
+     if (call_arg.token.length != 0) {
+	  
+	  /*
+	   * sanity check: if we received a signed isn in the last
+	   * response then there *cannot* be another token to send
+	   */
+	  if (call_res.signed_isn.length != 0) {
+	       PRINTF(("gssapi_create: unexpected token from init_sec\n"));
+	       goto cleanup;
+	  }
+	  
+	  PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func));
+	  
+	  memset((char *) &call_res, 0, sizeof(call_res));
+	  callstat = clnt_call(clnt, init_func,
+			       xdr_authgssapi_init_arg, &call_arg,
+			       xdr_authgssapi_init_res, &call_res,
+			       timeout);
+	  gss_release_buffer(minor_stat, &call_arg.token);
+	  
+	  if (callstat != RPC_SUCCESS) {
+	       struct rpc_err err;
+
+	       clnt_geterr(clnt, &err);
+	       if (callstat == RPC_AUTHERROR &&
+		   (err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED)
+		   && call_arg.version >= 1) {
+		    L_PRINTF(1,
+			     ("call_arg protocol version %d rejected, trying %d.\n",
+			    call_arg.version, call_arg.version-1));
+		    call_arg.version--;
+		    goto try_new_version;
+	       } else {
+		    PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n",
+			    init_func, callstat));
+	       }
+	       
+	       goto cleanup;
+	  } else if (call_res.version != call_arg.version &&
+		     !(call_arg.version == 2 && call_res.version == 1)) {
+	       /*
+		* The Secure 1.1 servers always respond with version
+		* 1.  Thus, if we just tried a version >=3, fall all
+		* the way back to version 1 since that is all they
+		* understand
+		*/
+	       if (call_arg.version > 2 && call_res.version == 1) {
+		    L_PRINTF(1,
+			     ("Talking to Secure 1.1 server, using version 1.\n"));
+		    call_arg.version = 1;
+		    goto try_new_version;
+	       }
+
+	       PRINTF(("gssapi_create: invalid call_res vers %d\n",
+		       call_res.version));
+	       goto cleanup;
+	  } else if (call_res.gss_major != GSS_S_COMPLETE) {
+	       AUTH_GSSAPI_DISPLAY_STATUS(("in response from server",
+					   call_res.gss_major,
+					   call_res.gss_minor));
+	       goto cleanup;
+	  }
+	  
+	  PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func));
+	  init_func = AUTH_GSSAPI_CONTINUE_INIT;
+	  
+	  /* check for client_handle */
+	  if (AUTH_PRIVATE(auth)->client_handle.length == 0) {
+	       if (call_res.client_handle.length == 0) {
+		    PRINTF(("gssapi_create: expected client_handle\n"));
+		    goto cleanup;
+	       } else {
+		    PRINTF(("gssapi_create: got client_handle %d\n",
+			    *((uint32_t *)call_res.client_handle.value)));
+		    
+		    GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle,
+				   call_res.client_handle);
+		    
+		    /* auth_msg is TRUE; there may be more tokens */
+		    marshall_new_creds(auth, TRUE,
+				       &AUTH_PRIVATE(auth)->client_handle); 
+	       }
+	  } else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle,
+					call_res.client_handle)) {
+	       PRINTF(("gssapi_create: got different client_handle\n"));
+	       goto cleanup;
+	  }
+	  
+	  /* check for token */
+	  if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) {
+	       PRINTF(("gssapi_create: expected token\n"));
+	       goto cleanup;
+	  } else if (call_res.token.length != 0) {
+	       if (*gssstat == GSS_S_COMPLETE) {
+		    PRINTF(("gssapi_create: got unexpected token\n"));
+		    goto cleanup;
+	       } else {
+		    /* assumes call_res is safe until init_sec_context */
+		    input_token = &call_res.token;
+		    PRINTF(("gssapi_create: got new token\n"));
+	       }
+	  }
+     }
+     
+     /* check for isn */
+     if (*gssstat == GSS_S_COMPLETE) {
+	  if (call_res.signed_isn.length == 0) {
+	       PRINTF(("gssapi_created: expected signed isn\n"));
+	       goto cleanup;
+	  } else {
+	       PRINTF(("gssapi_create: processing signed isn\n"));
+	       
+	       /* don't check conf (integ only) or qop (accpet default) */
+	       *gssstat = gss_unseal(minor_stat,
+				     AUTH_PRIVATE(auth)->context,
+				     &call_res.signed_isn,
+				     &isn_buf, NULL, NULL);
+	       
+	       if (*gssstat != GSS_S_COMPLETE) {
+		    AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn",
+						*gssstat, *minor_stat)); 
+		    goto cleanup;
+	       } else if (isn_buf.length != sizeof(uint32_t)) {
+		    PRINTF(("gssapi_create: gss_unseal gave %d bytes\n",
+			    (int) isn_buf.length));
+		    goto cleanup;
+	       }
+	       
+	       AUTH_PRIVATE(auth)->seq_num = (uint32_t)
+		    ntohl(*((uint32_t*)isn_buf.value)); 
+	       *gssstat = gss_release_buffer(minor_stat, &isn_buf);
+	       if (*gssstat != GSS_S_COMPLETE) {
+		    AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn",
+						*gssstat, *minor_stat));
+		    goto cleanup;
+	       }
+	       
+	       PRINTF(("gssapi_create: isn is %d\n",
+		       AUTH_PRIVATE(auth)->seq_num));
+	       
+	       /* we no longer need these results.. */
+	       xdr_free(xdr_authgssapi_init_res, &call_res);
+	  }
+     } else if (call_res.signed_isn.length != 0) {
+	  PRINTF(("gssapi_create: got signed isn, can't check yet\n"));
+     }
+     
+     /* results were okay.. continue if necessary */
+     if (*gssstat == GSS_S_CONTINUE_NEEDED) {
+	  PRINTF(("gssapi_create: not done, continuing\n"));
+	  goto next_token;
+     }
+     
+     /*
+      * Done!  Context is established, we have client_handle and isn.
+      */
+     AUTH_PRIVATE(auth)->established = TRUE;
+     
+     marshall_new_creds(auth, FALSE,
+			&AUTH_PRIVATE(auth)->client_handle); 
+     
+     PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n",
+	     *((uint32_t *)AUTH_PRIVATE(auth)->client_handle.value),
+	     AUTH_PRIVATE(auth)->seq_num));
+     
+     /* don't assume the caller will want to change clnt->cl_auth */
+     clnt->cl_auth = save_auth;
+     
+     return auth;
+     
+     /******************************************************************/
+     
+cleanup:
+     PRINTF(("gssapi_create: bailing\n\n"));
+     
+     if (AUTH_PRIVATE(auth))
+	  auth_gssapi_destroy(auth);
+     else if (auth)
+	  free(auth);
+     auth = NULL;
+     
+     /* don't assume the caller will want to change clnt->cl_auth */
+     clnt->cl_auth = save_auth;
+     
+     if (rpc_createerr.cf_stat == 0)
+	  rpc_createerr.cf_stat = RPC_AUTHERROR;
+     
+     return auth;
+}
+
+/*
+ * Function: marshall_new_creds
+ *
+ * Purpose: (pre-)serialize auth_msg and client_handle fields of
+ * auth_gssapi_creds into auth->cred_buf
+ *
+ * Arguments:
+ *
+ * 	auth		(r/w) the AUTH structure to modify
+ * 	auth_msg	(r) the auth_msg field to serialize
+ * 	client_handle	(r) the client_handle field to serialize, or
+ * 			NULL
+ *
+ * Returns: TRUE if successful, FALSE if not
+ *
+ * Requires: auth must point to a valid GSS-API auth structure, auth_msg
+ * must be TRUE or FALSE, client_handle must be a gss_buffer_t with a valid
+ * value and length field or NULL.
+ * 
+ * Effects: auth->ah_cred is set to the serialized auth_gssapi_creds
+ * version 2 structure (stored in the cred_buf field of private data)
+ * containing version, auth_msg and client_handle.
+ * auth->ah_cred.oa_flavor is set to AUTH_GSSAPI.  If cliend_handle is
+ * NULL, it is treated as if it had a length of 0 and a value of NULL.
+ *
+ * Modifies: auth
+ */
+static bool_t marshall_new_creds(
+     AUTH *auth,
+     bool_t auth_msg,
+     gss_buffer_t client_handle)
+{
+     auth_gssapi_creds creds;
+     XDR xdrs;
+     
+     PRINTF(("marshall_new_creds: starting\n"));
+
+     creds.version = 2;
+     
+     creds.auth_msg = auth_msg;
+     if (client_handle)
+	  GSS_COPY_BUFFER(creds.client_handle, *client_handle)
+     else {
+	  creds.client_handle.length = 0;
+	  creds.client_handle.value = NULL;
+     }
+     
+     xdrmem_create(&xdrs, (caddr_t) AUTH_PRIVATE(auth)->cred_buf,
+		   MAX_AUTH_BYTES, XDR_ENCODE);
+     if (! xdr_authgssapi_creds(&xdrs, &creds)) {
+	  PRINTF(("marshall_new_creds: failed encoding auth_gssapi_creds\n"));
+	  XDR_DESTROY(&xdrs);
+	  return FALSE;
+     }
+     AUTH_PRIVATE(auth)->cred_len = xdr_getpos(&xdrs);
+     XDR_DESTROY(&xdrs);
+     
+     PRINTF(("marshall_new_creds: auth_gssapi_creds is %d bytes\n",
+	     AUTH_PRIVATE(auth)->cred_len));
+     
+     auth->ah_cred.oa_flavor = AUTH_GSSAPI;
+     auth->ah_cred.oa_base = (char *) AUTH_PRIVATE(auth)->cred_buf;
+     auth->ah_cred.oa_length = AUTH_PRIVATE(auth)->cred_len;
+     
+     PRINTF(("marshall_new_creds: succeeding\n"));
+     
+     return TRUE;
+}
+
+
+/*
+ * Function: auth_gssapi_nextverf
+ *
+ * Purpose: None.
+ *
+ * Effects: None.  Never called.
+ */
+static void auth_gssapi_nextverf(AUTH *auth)
+{
+}
+
+/*
+ * Function: auth_gssapi_marhsall
+ *
+ * Purpose: Marshall RPC credentials and verifier onto xdr stream.
+ *
+ * Arguments:
+ *
+ * 	auth		(r/w) AUTH structure for client
+ * 	xdrs		(r/w) XDR stream to marshall to
+ *
+ * Returns: boolean indicating success/failure
+ *
+ * Effects:
+ * 
+ * The pre-serialized credentials in cred_buf are serialized.  If the
+ * context is established, the sealed sequence number is serialized as
+ * the verifier.  If the context is not established, an empty verifier
+ * is serialized.  The sequence number is *not* incremented, because
+ * this function is called multiple times if retransmission is required.
+ * 
+ * If this took all the header fields as arguments, it could sign
+ * them.
+ */
+static bool_t auth_gssapi_marshall(
+     AUTH *auth,
+     XDR *xdrs)
+{
+     OM_uint32 minor_stat;
+     gss_buffer_desc out_buf;
+     uint32_t seq_num;
+     
+     if (AUTH_PRIVATE(auth)->established == TRUE)  {
+	  PRINTF(("gssapi_marshall: starting\n"));
+	  
+	  seq_num = AUTH_PRIVATE(auth)->seq_num + 1;
+	  
+	  PRINTF(("gssapi_marshall: sending seq_num %d\n", seq_num));
+	  
+	  if (auth_gssapi_seal_seq(AUTH_PRIVATE(auth)->context, seq_num,
+				   &out_buf) == FALSE) {
+	       PRINTF(("gssapi_marhshall: seal failed\n"));
+	  }
+	  
+	  auth->ah_verf.oa_base = out_buf.value;
+	  auth->ah_verf.oa_length = out_buf.length;
+	  
+	  if (! xdr_opaque_auth(xdrs, &auth->ah_cred) ||
+	      ! xdr_opaque_auth(xdrs, &auth->ah_verf)) {
+	       (void) gss_release_buffer(&minor_stat, &out_buf);
+	       return FALSE;
+	  }
+	  (void) gss_release_buffer(&minor_stat, &out_buf);
+     } else {
+	  PRINTF(("gssapi_marshall: not established, sending null verf\n"));
+	  
+	  auth->ah_verf.oa_base = NULL;
+	  auth->ah_verf.oa_length = 0;
+	  
+	  if (! xdr_opaque_auth(xdrs, &auth->ah_cred) ||
+	      ! xdr_opaque_auth(xdrs, &auth->ah_verf)) {
+	       return FALSE;
+	  }
+     }
+     
+     return TRUE;
+}
+
+/*
+ * Function: auth_gssapi_validate
+ *
+ * Purpose: Validate RPC response verifier from server.
+ *
+ * Effects: See design document, section XXX.
+ */
+static bool_t auth_gssapi_validate(
+     AUTH *auth,
+     struct opaque_auth *verf)
+{
+     gss_buffer_desc in_buf;
+     uint32_t seq_num;
+     
+     if (AUTH_PRIVATE(auth)->established == FALSE) {
+	  PRINTF(("gssapi_validate: not established, noop\n"));
+	  return TRUE;
+     }
+     
+     PRINTF(("gssapi_validate: starting\n"));
+     
+     in_buf.length = verf->oa_length;
+     in_buf.value = verf->oa_base;
+     if (auth_gssapi_unseal_seq(AUTH_PRIVATE(auth)->context, &in_buf,
+				&seq_num) == FALSE) {
+	  PRINTF(("gssapi_validate: failed unsealing verifier\n"));
+	  return FALSE;
+     }
+     
+     /* we sent seq_num+1, so we should get back seq_num+2 */
+     if (AUTH_PRIVATE(auth)->seq_num+2 != seq_num) {
+	  PRINTF(("gssapi_validate: expecting seq_num %d, got %d (%#x)\n",
+		  AUTH_PRIVATE(auth)->seq_num + 2, seq_num, seq_num));
+	  return FALSE;
+     }
+     PRINTF(("gssapi_validate: seq_num %d okay\n", seq_num));
+     
+     /* +1 for successful transmission, +1 for successful validation */
+     AUTH_PRIVATE(auth)->seq_num += 2;
+     
+     PRINTF(("gssapi_validate: succeeding\n"));
+     
+     return TRUE;
+}
+
+/*
+ * Function: auth_gssapi_refresh
+ *
+ * Purpose: Attempts to resyncrhonize the sequence number.
+ *
+ * Effects:
+ * 
+ * When the server receives a properly authenticated RPC call, it
+ * increments the sequence number it is expecting from the client.
+ * But if the server's response is lost for any reason, the client
+ * can't know whether the server ever received it, assumes it didn't,
+ * and does *not* increment its sequence number.  Thus, the client's
+ * next call will fail with AUTH_REJECTEDCRED because the server will
+ * think it is a replay attack.
+ *
+ * When an AUTH_REJECTEDCRED error arrives, this function attempts to
+ * resyncrhonize by incrementing the client's sequence number and
+ * returning TRUE.  If any other error arrives, it returns FALSE.
+ */
+static bool_t auth_gssapi_refresh(
+     AUTH *auth,
+     struct rpc_msg *msg)
+{
+     if (msg->rm_reply.rp_rjct.rj_stat == AUTH_ERROR &&
+	 msg->rm_reply.rp_rjct.rj_why == AUTH_REJECTEDVERF) {
+	  PRINTF(("gssapi_refresh: rejected verifier, incrementing\n"));
+	  AUTH_PRIVATE(auth)->seq_num++;
+	  return TRUE;
+     } else {
+	  PRINTF(("gssapi_refresh: failing\n"));
+	  return FALSE;
+     }
+}
+
+/*
+ * Function: auth_gssapi_destroy
+ *
+ * Purpose: Destroy a GSS-API authentication structure.
+ *
+ * Effects:  This function destroys the GSS-API authentication
+ * context, and sends a message to the server instructing it to
+ * invokte gss_process_token() and thereby destroy its corresponding
+ * context.  Since the client doesn't really care whether the server
+ * gets this message, no failures are reported.
+ */
+static void auth_gssapi_destroy(AUTH *auth)
+{
+     struct timeval timeout;
+     OM_uint32 gssstat, minor_stat;
+     gss_cred_id_t cred;
+     int callstat;
+     
+     if (AUTH_PRIVATE(auth)->client_handle.length == 0) {
+	  PRINTF(("gssapi_destroy: no client_handle, not calling destroy\n"));
+	  goto skip_call;
+     }
+     
+     PRINTF(("gssapi_destroy: marshalling new creds\n"));
+     if (!marshall_new_creds(auth, TRUE, &AUTH_PRIVATE(auth)->client_handle)) {
+	  PRINTF(("gssapi_destroy: marshall_new_creds failed\n"));
+	  goto skip_call;
+     }
+     
+     PRINTF(("gssapi_destroy: calling GSSAPI_DESTROY\n"));
+     timeout.tv_sec = 1;
+     timeout.tv_usec = 0;
+     callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_DESTROY,
+			  xdr_void, NULL, xdr_void, NULL, timeout);
+     if (callstat != RPC_SUCCESS)
+	  clnt_sperror(AUTH_PRIVATE(auth)->clnt,
+		       "gssapi_destroy: GSSAPI_DESTROY failed");
+     
+skip_call:
+     PRINTF(("gssapi_destroy: deleting context\n"));
+     gssstat = gss_delete_sec_context(&minor_stat,
+				      &AUTH_PRIVATE(auth)->context,
+				      NULL);
+     if (gssstat != GSS_S_COMPLETE)
+	  AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat,
+				      minor_stat));
+     if (AUTH_PRIVATE(auth)->def_cred) {
+	  cred = GSS_C_NO_CREDENTIAL;
+	  gssstat = gss_release_cred(&minor_stat, &cred);
+	  if (gssstat != GSS_S_COMPLETE)
+	       AUTH_GSSAPI_DISPLAY_STATUS(("deleting default credential",
+					   gssstat, minor_stat));
+     }
+     
+     if (AUTH_PRIVATE(auth)->client_handle.length != 0)
+	  gss_release_buffer(&minor_stat,
+			     &AUTH_PRIVATE(auth)->client_handle);
+     
+#if 0
+     PRINTF(("gssapi_destroy: calling GSSAPI_EXIT\n"));
+     AUTH_PRIVATE(auth)->established = FALSE;
+     callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_EXIT,
+			  xdr_void, NULL, xdr_void, NULL, timeout);
+#endif
+     
+     free(auth->ah_private);
+     free(auth);
+     PRINTF(("gssapi_destroy: done\n"));
+}
+
+/*
+ * Function: auth_gssapi_wrap
+ *
+ * Purpose: encrypt the serialized arguments from xdr_func applied to
+ * xdr_ptr and write the result to xdrs.
+ *
+ * Effects: See design doc, section XXX.
+ */
+static bool_t auth_gssapi_wrap(
+     AUTH *auth,
+     XDR *out_xdrs,
+     bool_t (*xdr_func)(),
+     caddr_t xdr_ptr)
+{
+     OM_uint32 gssstat, minor_stat;
+     
+     if (! AUTH_PRIVATE(auth)->established) {
+	  PRINTF(("gssapi_wrap: context not established, noop\n"));
+	  return (*xdr_func)(out_xdrs, xdr_ptr);
+     } else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat,
+					AUTH_PRIVATE(auth)->context,
+					AUTH_PRIVATE(auth)->seq_num+1,
+					out_xdrs, xdr_func, xdr_ptr)) {
+	  if (gssstat != GSS_S_COMPLETE)
+	       AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments",
+					   gssstat, minor_stat));
+	  return FALSE;
+     } else
+	  return TRUE;
+}
+
+/*
+ * Function: auth_gssapi_unwrap
+ *
+ * Purpose: read encrypted arguments from xdrs, decrypt, and
+ * deserialize with xdr_func into xdr_ptr.
+ *
+ * Effects: See design doc, section XXX.
+ */
+static bool_t auth_gssapi_unwrap(
+     AUTH *auth,
+     XDR *in_xdrs,
+     bool_t (*xdr_func)(),
+     caddr_t xdr_ptr)
+{
+     OM_uint32 gssstat, minor_stat;
+     
+     if (! AUTH_PRIVATE(auth)->established) {
+	  PRINTF(("gssapi_unwrap: context not established, noop\n"));
+	  return (*xdr_func)(in_xdrs, xdr_ptr);
+     } else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat,
+					  AUTH_PRIVATE(auth)->context,
+					  AUTH_PRIVATE(auth)->seq_num,
+					  in_xdrs, xdr_func, xdr_ptr)) {
+	  if (gssstat != GSS_S_COMPLETE)
+	       AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments",
+					   gssstat, minor_stat));
+	  return FALSE;
+     } else
+	  return TRUE;
+}
diff --git a/mechglue/src/lib/rpc/auth_gssapi.h b/mechglue/src/lib/rpc/auth_gssapi.h
new file mode 100644
index 000000000..73a2f0b16
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth_gssapi.h
@@ -0,0 +1,153 @@
+/*
+ * auth_gssapi.h, Protocol for GSS-API style authentication parameters for RPC
+ * 
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ *
+ */
+
+#ifndef GSSRPC_AUTH_GSSAPI_H
+#define GSSRPC_AUTH_GSSAPI_H
+
+GSSRPC__BEGIN_DECLS
+
+#define AUTH_GSSAPI_EXIT		0
+#define AUTH_GSSAPI_INIT 		1
+#define AUTH_GSSAPI_CONTINUE_INIT 	2
+#define AUTH_GSSAPI_MSG 		3
+#define AUTH_GSSAPI_DESTROY 		4
+
+/*
+ * Yuck.  Some sys/types.h files leak symbols
+ */
+#ifdef major
+#undef major
+#endif
+#ifdef minor
+#undef minor
+#endif
+
+typedef struct _auth_gssapi_name {
+     char *name;
+     gss_OID type;
+} auth_gssapi_name;
+
+typedef struct _auth_gssapi_creds {
+     uint32_t version;
+     bool_t auth_msg;
+     gss_buffer_desc client_handle;
+} auth_gssapi_creds;
+
+typedef struct _auth_gssapi_init_arg {
+     uint32_t version;
+     gss_buffer_desc token;
+} auth_gssapi_init_arg;
+
+typedef struct _auth_gssapi_init_res {
+     uint32_t version;
+     gss_buffer_desc client_handle;
+     OM_uint32 gss_major, gss_minor;
+     gss_buffer_desc token;
+     gss_buffer_desc signed_isn;
+} auth_gssapi_init_res;
+
+typedef void (*auth_gssapi_log_badauth_func)
+     (OM_uint32 major,
+		OM_uint32 minor,
+		struct sockaddr_in *raddr,
+		caddr_t data);
+   
+typedef void (*auth_gssapi_log_badverf_func)
+     (gss_name_t client,
+		gss_name_t server,
+		struct svc_req *rqst,
+		struct rpc_msg *msg,
+		caddr_t data);
+
+typedef void (*auth_gssapi_log_miscerr_func)
+     (struct svc_req *rqst,
+		struct rpc_msg *msg,
+		char *error,
+		caddr_t data);
+
+bool_t xdr_gss_buf(XDR *, gss_buffer_t);
+bool_t xdr_authgssapi_creds(XDR *, auth_gssapi_creds *);
+bool_t xdr_authgssapi_init_arg(XDR *, auth_gssapi_init_arg *);
+bool_t xdr_authgssapi_init_res(XDR *, auth_gssapi_init_res *);
+
+bool_t auth_gssapi_wrap_data
+(OM_uint32 *major, OM_uint32 *minor,
+	   gss_ctx_id_t context, uint32_t seq_num, XDR
+	   *out_xdrs, bool_t (*xdr_func)(), caddr_t
+	   xdr_ptr);
+bool_t auth_gssapi_unwrap_data
+(OM_uint32 *major, OM_uint32 *minor,
+	   gss_ctx_id_t context, uint32_t seq_num, XDR
+	   *in_xdrs, bool_t (*xdr_func)(), caddr_t
+	   xdr_ptr);
+
+AUTH *auth_gssapi_create
+(CLIENT *clnt,
+	   OM_uint32 *major_status,
+	   OM_uint32 *minor_status,
+	   gss_cred_id_t claimant_cred_handle,
+	   gss_name_t target_name,
+	   gss_OID mech_type,
+	   OM_uint32 req_flags,
+	   OM_uint32 time_req,
+	   gss_OID *actual_mech_type,
+	   OM_uint32 *ret_flags,
+	   OM_uint32 *time_rec);
+
+AUTH *auth_gssapi_create_default
+(CLIENT *clnt, char *service_name);
+
+void auth_gssapi_display_status
+(char *msg, OM_uint32 major,
+	   OM_uint32 minor); 
+
+bool_t auth_gssapi_seal_seq
+(gss_ctx_id_t context, uint32_t seq_num, gss_buffer_t out_buf);
+
+bool_t auth_gssapi_unseal_seq
+(gss_ctx_id_t context, gss_buffer_t in_buf, uint32_t *seq_num);
+
+bool_t svcauth_gssapi_set_names
+(auth_gssapi_name *names, int num);
+void svcauth_gssapi_unset_names
+(void);
+
+void svcauth_gssapi_set_log_badauth_func
+(auth_gssapi_log_badauth_func func,
+	   caddr_t data);
+void svcauth_gssapi_set_log_badverf_func
+(auth_gssapi_log_badverf_func func,
+	   caddr_t data);
+void svcauth_gssapi_set_log_miscerr_func
+(auth_gssapi_log_miscerr_func func,
+	   caddr_t data);
+
+void svcauth_gss_set_log_badauth_func(auth_gssapi_log_badauth_func,
+				      caddr_t);
+void svcauth_gss_set_log_badverf_func(auth_gssapi_log_badverf_func,
+				      caddr_t);
+void svcauth_gss_set_log_miscerr_func(auth_gssapi_log_miscerr_func,
+				      caddr_t data);
+
+#define GSS_COPY_BUFFER(dest, src) { \
+     (dest).length = (src).length; \
+     (dest).value = (src).value; }
+
+#define GSS_DUP_BUFFER(dest, src) { \
+     (dest).length = (src).length; \
+     (dest).value = (void *) malloc((dest).length); \
+     memcpy((dest).value, (src).value, (dest).length); }
+
+#define GSS_BUFFERS_EQUAL(b1, b2) (((b1).length == (b2).length) && \
+				   !memcmp((b1).value,(b2).value,(b1.length)))
+
+
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_AUTH_GSSAPI_H) */
diff --git a/mechglue/src/lib/rpc/auth_gssapi_misc.c b/mechglue/src/lib/rpc/auth_gssapi_misc.c
new file mode 100644
index 000000000..3e878206b
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth_gssapi_misc.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ */
+
+#include <gssrpc/rpc.h>
+#include <stdio.h>
+
+#include <gssapi/gssapi.h>
+#include <gssrpc/auth_gssapi.h>
+
+#ifdef __CODECENTER__
+#define DEBUG_GSSAPI 1
+#endif
+
+#ifdef DEBUG_GSSAPI
+int misc_debug_gssapi = DEBUG_GSSAPI;
+#define L_PRINTF(l,args) if (misc_debug_gssapi >= l) printf args
+#define PRINTF(args) L_PRINTF(99, args)
+#define AUTH_GSSAPI_DISPLAY_STATUS(args) \
+	if (misc_debug_gssapi) auth_gssapi_display_status args
+#else
+#define PRINTF(args)
+#define L_PRINTF(l, args)
+#define AUTH_GSSAPI_DISPLAY_STATUS(args)
+#endif
+   
+static void auth_gssapi_display_status_1
+	(char *, OM_uint32, int, int);
+   
+bool_t xdr_gss_buf(
+     XDR *xdrs,
+     gss_buffer_t buf)
+{
+     /*
+      * On decode, xdr_bytes will only allocate buf->value if the
+      * length read in is < maxsize (last arg).  This is dumb, because
+      * the whole point of allocating memory is so that I don't *have*
+      * to know the maximum length.  -1 effectively disables this
+      * braindamage.
+      */
+     bool_t result;
+     /* Fix type mismatches between APIs.  */
+     unsigned int length = buf->length;
+     result = xdr_bytes(xdrs, (char **) &buf->value, &length,
+			(xdrs->x_op == XDR_DECODE && buf->value == NULL)
+			? (unsigned int) -1 : (unsigned int) buf->length);
+     buf->length = length;
+     return result;
+}
+
+bool_t xdr_authgssapi_creds(
+     XDR *xdrs,
+     auth_gssapi_creds *creds)
+{
+     if (! xdr_u_int32(xdrs, &creds->version) ||
+	 ! xdr_bool(xdrs, &creds->auth_msg) ||
+	 ! xdr_gss_buf(xdrs, &creds->client_handle))
+       return FALSE;
+     return TRUE;
+}
+
+bool_t xdr_authgssapi_init_arg(
+     XDR *xdrs,
+     auth_gssapi_init_arg *init_arg)
+{
+     if (! xdr_u_int32(xdrs, &init_arg->version) ||
+	 ! xdr_gss_buf(xdrs, &init_arg->token))
+	  return FALSE;
+     return TRUE;
+}
+
+bool_t xdr_authgssapi_init_res(
+     XDR *xdrs,
+     auth_gssapi_init_res *init_res)
+{
+     if (! xdr_u_int32(xdrs, &init_res->version) ||
+	 ! xdr_gss_buf(xdrs, &init_res->client_handle) ||
+	 ! xdr_u_int32(xdrs, &init_res->gss_major) ||
+	 ! xdr_u_int32(xdrs, &init_res->gss_minor) ||
+	 ! xdr_gss_buf(xdrs, &init_res->token) ||
+	 ! xdr_gss_buf(xdrs, &init_res->signed_isn))
+	  return FALSE;
+     return TRUE;
+}
+
+bool_t auth_gssapi_seal_seq(
+     gss_ctx_id_t context,
+     uint32_t seq_num,
+     gss_buffer_t out_buf)
+{
+     gss_buffer_desc in_buf;
+     OM_uint32 gssstat, minor_stat;
+     uint32_t nl_seq_num;
+     
+     nl_seq_num = htonl(seq_num);
+     
+     in_buf.length = sizeof(uint32_t);
+     in_buf.value = (char *) &nl_seq_num;
+     gssstat = gss_seal(&minor_stat, context, 0, GSS_C_QOP_DEFAULT,
+			&in_buf, NULL, out_buf);
+     if (gssstat != GSS_S_COMPLETE) {
+	  PRINTF(("gssapi_seal_seq: failed\n"));
+	  AUTH_GSSAPI_DISPLAY_STATUS(("sealing sequence number",
+				      gssstat, minor_stat));
+	  return FALSE;
+     }
+     return TRUE;
+}
+
+bool_t auth_gssapi_unseal_seq(
+     gss_ctx_id_t context,
+     gss_buffer_t in_buf,
+     uint32_t *seq_num)
+{
+     gss_buffer_desc out_buf;
+     OM_uint32 gssstat, minor_stat;
+     uint32_t nl_seq_num;
+     
+     gssstat = gss_unseal(&minor_stat, context, in_buf, &out_buf,
+			  NULL, NULL);
+     if (gssstat != GSS_S_COMPLETE) {
+	  PRINTF(("gssapi_unseal_seq: failed\n"));
+	  AUTH_GSSAPI_DISPLAY_STATUS(("unsealing sequence number",
+				      gssstat, minor_stat)); 
+	  return FALSE;
+     } else if (out_buf.length != sizeof(uint32_t)) {
+	  PRINTF(("gssapi_unseal_seq: unseal gave %d bytes\n",
+		  (int) out_buf.length));
+	  gss_release_buffer(&minor_stat, &out_buf);
+	  return FALSE;
+     }
+     
+     nl_seq_num = *((uint32_t *) out_buf.value);
+     *seq_num = (uint32_t) ntohl(nl_seq_num);
+     gss_release_buffer(&minor_stat, &out_buf);
+     
+     return TRUE;
+}
+
+void auth_gssapi_display_status(
+     char *msg,
+     OM_uint32 major,
+     OM_uint32 minor)
+{
+     auth_gssapi_display_status_1(msg, major, GSS_C_GSS_CODE, 0);
+     auth_gssapi_display_status_1(msg, minor, GSS_C_MECH_CODE, 0);
+}
+
+static void auth_gssapi_display_status_1(
+     char *m,
+     OM_uint32 code,
+     int type,
+     int rec)
+{
+     OM_uint32 gssstat, minor_stat;
+     gss_buffer_desc msg;
+     OM_uint32 msg_ctx;
+     
+     msg_ctx = 0;
+     while (1) {
+	  gssstat = gss_display_status(&minor_stat, code,
+				       type, GSS_C_NULL_OID,
+				       &msg_ctx, &msg);
+	  if (gssstat != GSS_S_COMPLETE) {
+ 	       if (!rec) {
+		    auth_gssapi_display_status_1(m,gssstat,GSS_C_GSS_CODE,1); 
+		    auth_gssapi_display_status_1(m, minor_stat,
+						 GSS_C_MECH_CODE, 1);
+	       } else {
+		   fputs ("GSS-API authentication error ", stderr);
+		   fwrite (msg.value, msg.length, 1, stderr);
+		   fputs (": recursive failure!\n", stderr);
+	       }
+	       return;
+	  }
+
+	  fprintf (stderr, "GSS-API authentication error %s: ", m);
+	  fwrite (msg.value, msg.length, 1, stderr);
+	  putc ('\n', stderr);
+	  (void) gss_release_buffer(&minor_stat, &msg);
+	  
+	  if (!msg_ctx)
+	       break;
+     }
+}
+
+bool_t auth_gssapi_wrap_data(
+     OM_uint32 *major,
+     OM_uint32 *minor,
+     gss_ctx_id_t context,
+     uint32_t seq_num,
+     XDR *out_xdrs,
+     bool_t (*xdr_func)(),
+     caddr_t xdr_ptr)
+{
+     gss_buffer_desc in_buf, out_buf;
+     XDR temp_xdrs;
+     int conf_state;
+     unsigned int length;
+     
+     PRINTF(("gssapi_wrap_data: starting\n"));
+     
+     *major = GSS_S_COMPLETE;
+     *minor = 0; /* assumption */
+     
+     xdralloc_create(&temp_xdrs, XDR_ENCODE);
+     
+     /* serialize the sequence number into local memory */
+     PRINTF(("gssapi_wrap_data: encoding seq_num %d\n", seq_num));
+     if (! xdr_u_int32(&temp_xdrs, &seq_num)) {
+	  PRINTF(("gssapi_wrap_data: serializing seq_num failed\n"));
+	  XDR_DESTROY(&temp_xdrs);
+	  return FALSE;
+     }
+     
+     /* serialize the arguments into local memory */
+     if (!(*xdr_func)(&temp_xdrs, xdr_ptr)) {
+	  PRINTF(("gssapi_wrap_data: serializing arguments failed\n"));
+	  XDR_DESTROY(&temp_xdrs);
+	  return FALSE;
+     }
+     
+     in_buf.length = xdr_getpos(&temp_xdrs);
+     in_buf.value = xdralloc_getdata(&temp_xdrs);
+     
+     *major = gss_seal(minor, context, 1,
+		       GSS_C_QOP_DEFAULT, &in_buf, &conf_state,
+		       &out_buf);
+     if (*major != GSS_S_COMPLETE) {
+	  XDR_DESTROY(&temp_xdrs);
+	  return FALSE;
+     }
+     
+     PRINTF(("gssapi_wrap_data: %d bytes data, %d bytes sealed\n",
+	     (int) in_buf.length, (int) out_buf.length));
+     
+     /* write the token */
+     length = out_buf.length;
+     if (! xdr_bytes(out_xdrs, (char **) &out_buf.value, 
+		     (unsigned int *) &length,
+		     out_buf.length)) {
+	  PRINTF(("gssapi_wrap_data: serializing encrypted data failed\n"));
+	  XDR_DESTROY(&temp_xdrs);
+	  return FALSE;
+     }
+     
+     *major = gss_release_buffer(minor, &out_buf);
+     
+     PRINTF(("gssapi_wrap_data: succeeding\n\n"));
+     XDR_DESTROY(&temp_xdrs);
+     return TRUE;
+}
+
+bool_t auth_gssapi_unwrap_data(
+     OM_uint32 *major,
+     OM_uint32 *minor,
+     gss_ctx_id_t context,
+     uint32_t seq_num,
+     XDR *in_xdrs,
+     bool_t (*xdr_func)(),
+     caddr_t xdr_ptr)
+{
+     gss_buffer_desc in_buf, out_buf;
+     XDR temp_xdrs;
+     uint32_t verf_seq_num;
+     int conf, qop;
+     unsigned int length;
+     
+     PRINTF(("gssapi_unwrap_data: starting\n"));
+     
+     *major = GSS_S_COMPLETE;
+     *minor = 0; /* assumption */
+     
+     in_buf.value = NULL;
+     out_buf.value = NULL;
+     if (! xdr_bytes(in_xdrs, (char **) &in_buf.value,
+		     &length, (unsigned int) -1)) {
+	 PRINTF(("gssapi_unwrap_data: deserializing encrypted data failed\n"));
+	 temp_xdrs.x_op = XDR_FREE;
+	 (void)xdr_bytes(&temp_xdrs, (char **) &in_buf.value, &length,
+			 (unsigned int) -1);
+	 return FALSE;
+     }
+     in_buf.length = length;
+     
+     *major = gss_unseal(minor, context, &in_buf, &out_buf, &conf,
+			 &qop);
+     free(in_buf.value);
+     if (*major != GSS_S_COMPLETE)
+	  return FALSE;
+     
+     PRINTF(("gssapi_unwrap_data: %d bytes data, %d bytes sealed\n",
+	     out_buf.length, in_buf.length));
+     
+     xdrmem_create(&temp_xdrs, out_buf.value, out_buf.length, XDR_DECODE);
+     
+     /* deserialize the sequence number */
+     if (! xdr_u_int32(&temp_xdrs, &verf_seq_num)) {
+	  PRINTF(("gssapi_unwrap_data: deserializing verf_seq_num failed\n"));
+	  gss_release_buffer(minor, &out_buf);
+	  XDR_DESTROY(&temp_xdrs);
+	  return FALSE;
+     }
+     if (verf_seq_num != seq_num) {
+	  PRINTF(("gssapi_unwrap_data: seq %d specified, read %d\n",
+		  seq_num, verf_seq_num));
+	  gss_release_buffer(minor, &out_buf);
+	  XDR_DESTROY(&temp_xdrs);
+	  return FALSE;
+     }
+     PRINTF(("gssapi_unwrap_data: unwrap seq_num %d okay\n", verf_seq_num));
+     
+     /* deserialize the arguments into xdr_ptr */
+     if (! (*xdr_func)(&temp_xdrs, xdr_ptr)) {
+	  PRINTF(("gssapi_unwrap_data: deserializing arguments failed\n"));
+	  gss_release_buffer(minor, &out_buf);
+	  xdr_free(xdr_func, xdr_ptr);
+	  XDR_DESTROY(&temp_xdrs);
+	  return FALSE;
+     }
+     
+     PRINTF(("gssapi_unwrap_data: succeeding\n\n"));
+     
+     gss_release_buffer(minor, &out_buf);
+     XDR_DESTROY(&temp_xdrs);
+     return TRUE;
+}
diff --git a/mechglue/src/lib/rpc/auth_none.c b/mechglue/src/lib/rpc/auth_none.c
new file mode 100644
index 000000000..f4869aa6a
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth_none.c
@@ -0,0 +1,145 @@
+/* @(#)auth_none.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * auth_none.c
+ * Creates a client authentication handle for passing "null" 
+ * credentials and verifiers to remote systems. 
+ * 
+ * Copyright (C) 1984, Sun Microsystems, Inc. 
+ */
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <gssrpc/auth.h>
+#include <stdlib.h>
+#define MAX_MARSHEL_SIZE 20
+
+/*
+ * Authenticator operations routines
+ */
+static void	authnone_verf(AUTH *);
+static void	authnone_destroy(AUTH *);
+static bool_t	authnone_marshal(AUTH *, XDR *);
+static bool_t	authnone_validate(AUTH *, struct opaque_auth *);
+static bool_t	authnone_refresh(AUTH *, struct rpc_msg *);
+static bool_t	authnone_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);
+
+static struct auth_ops ops = {
+	authnone_verf,
+	authnone_marshal,
+	authnone_validate,
+	authnone_refresh,
+	authnone_destroy,
+	authnone_wrap,
+	authnone_wrap
+};
+
+static struct authnone_private {
+	AUTH	no_client;
+	char	marshalled_client[MAX_MARSHEL_SIZE];
+	u_int	mcnt;
+} *authnone_private;
+
+AUTH *
+authnone_create(void)
+{
+	register struct authnone_private *ap = authnone_private;
+	XDR xdr_stream;
+	register XDR *xdrs;
+
+	if (ap == 0) {
+		ap = (struct authnone_private *)calloc(1, sizeof (*ap));
+		if (ap == 0)
+			return (0);
+		authnone_private = ap;
+	}
+	if (!ap->mcnt) {
+		ap->no_client.ah_cred = ap->no_client.ah_verf = gssrpc__null_auth;
+		ap->no_client.ah_ops = &ops;
+		xdrs = &xdr_stream;
+		xdrmem_create(xdrs, ap->marshalled_client, (u_int)MAX_MARSHEL_SIZE,
+		    XDR_ENCODE);
+		(void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred);
+		(void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf);
+		ap->mcnt = XDR_GETPOS(xdrs);
+		XDR_DESTROY(xdrs);
+	}
+	return (&ap->no_client);
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_marshal(AUTH *client, XDR *xdrs)
+{
+	register struct authnone_private *ap = authnone_private;
+
+	if (ap == 0)
+		return (0);
+	return ((*xdrs->x_ops->x_putbytes)(xdrs,
+	    ap->marshalled_client, ap->mcnt));
+}
+
+/*ARGSUSED*/
+static void 
+authnone_verf(AUTH *auth)
+{
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_validate(AUTH *auth, struct opaque_auth *verf)
+{
+
+	return (TRUE);
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_refresh(AUTH *auth, struct rpc_msg *msg)
+{
+
+	return (FALSE);
+}
+
+/*ARGSUSED*/
+static void
+authnone_destroy(AUTH *auth)
+{
+}
+
+static bool_t
+authnone_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere)
+{
+	return ((*xfunc)(xdrs, xwhere));
+}
diff --git a/mechglue/src/lib/rpc/auth_unix.c b/mechglue/src/lib/rpc/auth_unix.c
new file mode 100644
index 000000000..4af3bc4c7
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth_unix.c
@@ -0,0 +1,330 @@
+/* @(#)auth_unix.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * auth_unix.c, Implements UNIX style authentication parameters. 
+ *  
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The system is very weak.  The client uses no encryption for it's
+ * credentials and only sends null verifiers.  The server sends backs
+ * null verifiers or optionally a verifier that suggests a new short hand
+ * for the credentials.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <gssrpc/auth.h>
+#include <gssrpc/auth_unix.h>
+
+#ifndef GETGROUPS_T
+#define GETGROUPS_T int
+#endif
+
+/*
+ * Unix authenticator operations vector
+ */
+static void	authunix_nextverf(AUTH *);
+static bool_t	authunix_marshal(AUTH *, XDR *);
+static bool_t	authunix_validate(AUTH *, struct opaque_auth *);
+static bool_t	authunix_refresh(AUTH *, struct rpc_msg *);
+static void	authunix_destroy(AUTH *);
+static bool_t	authunix_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);
+
+static struct auth_ops auth_unix_ops = {
+	authunix_nextverf,
+	authunix_marshal,
+	authunix_validate,
+	authunix_refresh,
+	authunix_destroy,
+	authunix_wrap,
+	authunix_wrap
+};
+
+/*
+ * This struct is pointed to by the ah_private field of an auth_handle.
+ */
+struct audata {
+	struct opaque_auth	au_origcred;	/* original credentials */
+	struct opaque_auth	au_shcred;	/* short hand cred */
+	uint32_t		au_shfaults;	/* short hand cache faults */
+	char			au_marshed[MAX_AUTH_BYTES];
+	u_int			au_mpos;	/* xdr pos at end of marshed */
+};
+#define	AUTH_PRIVATE(auth)	((struct audata *)auth->ah_private)
+
+static void marshal_new_auth(AUTH *);
+
+
+/*
+ * Create a unix style authenticator.
+ * Returns an auth handle with the given stuff in it.
+ */
+AUTH *
+authunix_create(
+	char *machname,
+	int uid,
+	int gid,
+	register int len,
+	int *aup_gids)
+{
+	struct authunix_parms aup;
+	char mymem[MAX_AUTH_BYTES];
+	struct timeval now;
+	XDR xdrs;
+	register AUTH *auth;
+	register struct audata *au;
+
+	/*
+	 * Allocate and set up auth handle
+	 */
+	auth = (AUTH *)mem_alloc(sizeof(*auth));
+#ifndef KERNEL
+	if (auth == NULL) {
+		(void)fprintf(stderr, "authunix_create: out of memory\n");
+		return (NULL);
+	}
+#endif
+	au = (struct audata *)mem_alloc(sizeof(*au));
+#ifndef KERNEL
+	if (au == NULL) {
+		(void)fprintf(stderr, "authunix_create: out of memory\n");
+		return (NULL);
+	}
+#endif
+	auth->ah_ops = &auth_unix_ops;
+	auth->ah_private = (caddr_t)au;
+	auth->ah_verf = au->au_shcred = gssrpc__null_auth;
+	au->au_shfaults = 0;
+
+	/*
+	 * fill in param struct from the given params
+	 */
+	(void)gettimeofday(&now,  (struct timezone *)0);
+	aup.aup_time = now.tv_sec;
+	aup.aup_machname = machname;
+	aup.aup_uid = uid;
+	aup.aup_gid = gid;
+	aup.aup_len = (u_int)len;
+	aup.aup_gids = aup_gids;
+
+	/*
+	 * Serialize the parameters into origcred
+	 */
+	xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
+	if (! xdr_authunix_parms(&xdrs, &aup)) 
+		abort();
+	au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
+	au->au_origcred.oa_flavor = AUTH_UNIX;
+#ifdef KERNEL
+	au->au_origcred.oa_base = mem_alloc((u_int) len);
+#else
+	if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL) {
+		(void)fprintf(stderr, "authunix_create: out of memory\n");
+		return (NULL);
+	}
+#endif
+	memmove(au->au_origcred.oa_base, mymem, (u_int)len);
+
+	/*
+	 * set auth handle to reflect new cred.
+	 */
+	auth->ah_cred = au->au_origcred;
+	marshal_new_auth(auth);
+	return (auth);
+}
+
+/*
+ * Returns an auth handle with parameters determined by doing lots of
+ * syscalls.
+ */
+AUTH *
+authunix_create_default(void)
+{
+	register int len;
+	char machname[MAX_MACHINE_NAME + 1];
+	register int uid;
+	register int gid;
+	GETGROUPS_T gids[NGRPS];
+	int igids[NGRPS], i;
+
+	if (gethostname(machname, MAX_MACHINE_NAME) == -1)
+		abort();
+	machname[MAX_MACHINE_NAME] = 0;
+	uid = geteuid();
+	gid = getegid();
+	if ((len = getgroups(NGRPS, gids)) < 0)
+		abort();
+	for(i = 0; i < NGRPS; i++) {
+	        igids[i] = gids[i];
+	}
+	return (authunix_create(machname, uid, gid, len, igids));
+}
+
+/*
+ * authunix operations
+ */
+
+static void
+authunix_nextverf(AUTH *auth)
+{
+	/* no action necessary */
+}
+
+static bool_t
+authunix_marshal(AUTH *auth, XDR *xdrs)
+{
+	register struct audata *au = AUTH_PRIVATE(auth);
+
+	return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
+}
+
+static bool_t
+authunix_validate(register AUTH *auth, struct opaque_auth *verf)
+{
+	register struct audata *au;
+	XDR xdrs;
+
+	if (verf->oa_flavor == AUTH_SHORT) {
+		au = AUTH_PRIVATE(auth);
+		xdrmem_create(&xdrs, verf->oa_base, verf->oa_length, XDR_DECODE);
+
+		if (au->au_shcred.oa_base != NULL) {
+			mem_free(au->au_shcred.oa_base,
+			    au->au_shcred.oa_length);
+			au->au_shcred.oa_base = NULL;
+		}
+		if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
+			auth->ah_cred = au->au_shcred;
+		} else {
+			xdrs.x_op = XDR_FREE;
+			(void)xdr_opaque_auth(&xdrs, &au->au_shcred);
+			au->au_shcred.oa_base = NULL;
+			auth->ah_cred = au->au_origcred;
+		}
+		marshal_new_auth(auth);
+	}
+	return (TRUE);
+}
+
+static bool_t
+authunix_refresh(register AUTH *auth, struct rpc_msg *msg)
+{
+	register struct audata *au = AUTH_PRIVATE(auth);
+	struct authunix_parms aup;
+	struct timeval now;
+	XDR xdrs;
+	register int stat;
+
+	if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
+		/* there is no hope.  Punt */
+		return (FALSE);
+	}
+	au->au_shfaults ++;
+
+	/* first deserialize the creds back into a struct authunix_parms */
+	aup.aup_machname = NULL;
+	aup.aup_gids = (int *)NULL;
+	xdrmem_create(&xdrs, au->au_origcred.oa_base,
+	    au->au_origcred.oa_length, XDR_DECODE);
+	stat = xdr_authunix_parms(&xdrs, &aup);
+	if (! stat) 
+		goto done;
+
+	/* update the time and serialize in place */
+	(void)gettimeofday(&now, (struct timezone *)0);
+	aup.aup_time = now.tv_sec;
+	xdrs.x_op = XDR_ENCODE;
+	XDR_SETPOS(&xdrs, 0);
+	stat = xdr_authunix_parms(&xdrs, &aup);
+	if (! stat)
+		goto done;
+	auth->ah_cred = au->au_origcred;
+	marshal_new_auth(auth);
+done:
+	/* free the struct authunix_parms created by deserializing */
+	xdrs.x_op = XDR_FREE;
+	(void)xdr_authunix_parms(&xdrs, &aup);
+	XDR_DESTROY(&xdrs);
+	return (stat);
+}
+
+static void
+authunix_destroy(register AUTH *auth)
+{
+	register struct audata *au = AUTH_PRIVATE(auth);
+
+	mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
+
+	if (au->au_shcred.oa_base != NULL)
+		mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
+
+	mem_free(auth->ah_private, sizeof(struct audata));
+
+	if (auth->ah_verf.oa_base != NULL)
+		mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
+
+	mem_free((caddr_t)auth, sizeof(*auth));
+}
+
+/*
+ * Marshals (pre-serializes) an auth struct.
+ * sets private data, au_marshed and au_mpos
+ */
+static void
+marshal_new_auth(register AUTH *auth)
+{
+	XDR		xdr_stream;
+	register XDR	*xdrs = &xdr_stream;
+	register struct audata *au = AUTH_PRIVATE(auth);
+
+	xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
+	if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
+	    (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) {
+		perror("auth_none.c - Fatal marshalling problem");
+	} else {
+		au->au_mpos = XDR_GETPOS(xdrs);
+	}
+	XDR_DESTROY(xdrs);
+}
+
+static bool_t
+authunix_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere)
+{
+	return ((*xfunc)(xdrs, xwhere));
+}
diff --git a/mechglue/src/lib/rpc/auth_unix.h b/mechglue/src/lib/rpc/auth_unix.h
new file mode 100644
index 000000000..9be442278
--- /dev/null
+++ b/mechglue/src/lib/rpc/auth_unix.h
@@ -0,0 +1,80 @@
+/* @(#)auth_unix.h	2.2 88/07/29 4.0 RPCSRC; from 1.8 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)auth_unix.h 1.5 86/07/16 SMI      */
+
+/*
+ * auth_unix.h, Protocol for UNIX style authentication parameters for RPC
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef GSSRPC_AUTH_UNIX_H
+#define GSSRPC_AUTH_UNIX_H
+
+GSSRPC__BEGIN_DECLS
+/*
+ * The system is very weak.  The client uses no encryption for  it
+ * credentials and only sends null verifiers.  The server sends backs
+ * null verifiers or optionally a verifier that suggests a new short hand
+ * for the credentials.
+ */
+
+/* The machine name is part of a credential; it may not exceed 255 bytes */
+#define MAX_MACHINE_NAME 255
+
+/* gids compose part of a credential; there may not be more than 16 of them */
+#define NGRPS 16
+
+/*
+ * Unix style credentials.
+ */
+struct authunix_parms {
+	uint32_t	 aup_time;
+	char	*aup_machname;
+	int	 aup_uid;
+	int	 aup_gid;
+	u_int	 aup_len;
+	int	*aup_gids;
+};
+
+extern bool_t xdr_authunix_parms(XDR *, struct authunix_parms *);
+
+/* 
+ * If a response verifier has flavor AUTH_SHORT, 
+ * then the body of the response verifier encapsulates the following structure;
+ * again it is serialized in the obvious fashion.
+ */
+struct short_hand_verf {
+	struct opaque_auth new_cred;
+};
+
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_AUTH_UNIX_H) */
diff --git a/mechglue/src/lib/rpc/authgss_prot.c b/mechglue/src/lib/rpc/authgss_prot.c
new file mode 100644
index 000000000..ab6e7fea0
--- /dev/null
+++ b/mechglue/src/lib/rpc/authgss_prot.c
@@ -0,0 +1,366 @@
+/*
+  authgss_prot.c
+  
+  Copyright (c) 2000 The Regents of the University of Michigan.
+  All rights reserved.
+  
+  Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+  All rights reserved, all wrongs reversed.
+  
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. Neither the name of the University nor the names of its
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Id: authgss_prot.c,v 1.18 2000/09/01 04:14:03 dugsong Exp
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <gssrpc/rpc.h>
+#ifdef HAVE_HEIMDAL
+#include <gssapi.h>
+#else
+#include <gssapi/gssapi.h>
+#endif
+
+bool_t
+xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize)
+{
+	bool_t xdr_stat;
+	u_int tmplen;
+
+	if (xdrs->x_op != XDR_DECODE) {
+		if (buf->length > UINT_MAX)
+			return (FALSE);
+		else
+			tmplen = buf->length;
+	}
+	xdr_stat = xdr_bytes(xdrs, (char **)&buf->value, &tmplen, maxsize);
+
+	if (xdr_stat && xdrs->x_op == XDR_DECODE)
+		buf->length = tmplen;
+
+	return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p)
+{
+	bool_t xdr_stat;
+
+	xdr_stat = (xdr_u_int(xdrs, &p->gc_v) &&
+		    xdr_enum(xdrs, (enum_t *)&p->gc_proc) &&
+		    xdr_u_int32(xdrs, &p->gc_seq) &&
+		    xdr_enum(xdrs, (enum_t *)&p->gc_svc) &&
+		    xdr_rpc_gss_buf(xdrs, &p->gc_ctx, MAX_AUTH_BYTES));
+
+	log_debug("xdr_rpc_gss_cred: %s %s "
+		  "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)",
+		  (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
+		  (xdr_stat == TRUE) ? "success" : "failure",
+		  p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc,
+		  p->gc_ctx.value, p->gc_ctx.length);
+
+	return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p)
+{
+	bool_t xdr_stat;
+
+	xdr_stat = xdr_rpc_gss_buf(xdrs, p, MAX_NETOBJ_SZ);
+
+	log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)",
+		  (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
+		  (xdr_stat == TRUE) ? "success" : "failure",
+		  p->value, p->length);
+	
+	return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p)
+{
+	bool_t xdr_stat;
+
+	xdr_stat = (xdr_rpc_gss_buf(xdrs, &p->gr_ctx, MAX_NETOBJ_SZ) &&
+		    xdr_u_int32(xdrs, &p->gr_major) &&
+		    xdr_u_int32(xdrs, &p->gr_minor) &&
+		    xdr_u_int32(xdrs, &p->gr_win) &&
+		    xdr_rpc_gss_buf(xdrs, &p->gr_token, MAX_NETOBJ_SZ));
+
+	log_debug("xdr_rpc_gss_init_res %s %s "
+		  "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)",
+		  (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
+		  (xdr_stat == TRUE) ? "success" : "failure",
+		  p->gr_ctx.value, p->gr_ctx.length,
+		  p->gr_major, p->gr_minor, p->gr_win,
+		  p->gr_token.value, p->gr_token.length);
+	
+	return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
+		      gss_ctx_id_t ctx, gss_qop_t qop,
+		      rpc_gss_svc_t svc, uint32_t seq)
+{
+	XDR		tmpxdrs;
+	gss_buffer_desc	databuf, wrapbuf;
+	OM_uint32	maj_stat, min_stat;
+	int		conf_state;
+	bool_t		xdr_stat;
+
+	xdralloc_create(&tmpxdrs, XDR_ENCODE);
+
+	xdr_stat = FALSE;
+	
+	/* Marshal rpc_gss_data_t (sequence number + arguments). */
+	if (!xdr_u_int32(&tmpxdrs, &seq) || !(*xdr_func)(&tmpxdrs, xdr_ptr))
+		goto errout;
+
+	/* Set databuf to marshalled rpc_gss_data_t. */
+	databuf.length = xdr_getpos(&tmpxdrs);
+	databuf.value = xdralloc_getdata(&tmpxdrs);
+
+	if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
+		if (!xdr_rpc_gss_buf(xdrs, &databuf, (unsigned int)-1))
+			goto errout;
+
+		/* Checksum rpc_gss_data_t. */
+		maj_stat = gss_get_mic(&min_stat, ctx, qop,
+				       &databuf, &wrapbuf);
+		if (maj_stat != GSS_S_COMPLETE) {
+			log_debug("gss_get_mic failed");
+			goto errout;
+		}
+		/* Marshal checksum. */
+		xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1);
+		gss_release_buffer(&min_stat, &wrapbuf);
+	}		
+	else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
+		/* Encrypt rpc_gss_data_t. */
+		maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
+				    &conf_state, &wrapbuf);
+		if (maj_stat != GSS_S_COMPLETE) {
+			log_status("gss_wrap", maj_stat, min_stat);
+			goto errout;
+		}
+		/* Marshal databody_priv. */
+		xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1);
+		gss_release_buffer(&min_stat, &wrapbuf);
+	}
+errout:
+	xdr_destroy(&tmpxdrs);
+	return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
+			gss_ctx_id_t ctx, gss_qop_t qop,
+			rpc_gss_svc_t svc, uint32_t seq)
+{
+	XDR		tmpxdrs;
+	gss_buffer_desc	databuf, wrapbuf;
+	OM_uint32	maj_stat, min_stat;
+	uint32_t	seq_num;
+	int		conf_state;
+	gss_qop_t	qop_state;
+	bool_t		xdr_stat;
+
+	if (xdr_func == xdr_void || xdr_ptr == NULL)
+		return (TRUE);
+	
+	memset(&databuf, 0, sizeof(databuf));
+	memset(&wrapbuf, 0, sizeof(wrapbuf));
+	
+	if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
+		/* Decode databody_integ. */
+		if (!xdr_rpc_gss_buf(xdrs, &databuf, (unsigned int)-1)) {
+			log_debug("xdr decode databody_integ failed");
+			return (FALSE);
+		}
+		/* Decode checksum. */
+		if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1)) {
+			gss_release_buffer(&min_stat, &databuf);
+			log_debug("xdr decode checksum failed");
+			return (FALSE);
+		}
+		/* Verify checksum and QOP. */
+		maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
+					  &wrapbuf, &qop_state);
+		gss_release_buffer(&min_stat, &wrapbuf);
+		
+		if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
+			gss_release_buffer(&min_stat, &databuf);
+			log_status("gss_verify_mic", maj_stat, min_stat);
+			return (FALSE);
+		}
+	}
+	else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
+		/* Decode databody_priv. */
+		if (!xdr_rpc_gss_buf(xdrs, &wrapbuf, (unsigned int)-1)) {
+			log_debug("xdr decode databody_priv failed");
+			return (FALSE);
+		}
+		/* Decrypt databody. */
+		maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
+				      &conf_state, &qop_state);
+		
+		gss_release_buffer(&min_stat, &wrapbuf);
+		
+		/* Verify encryption and QOP. */
+		if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
+			conf_state != TRUE) {
+			gss_release_buffer(&min_stat, &databuf);
+			log_status("gss_unwrap", maj_stat, min_stat);
+			return (FALSE);
+		}
+	}
+	/* Decode rpc_gss_data_t (sequence number + arguments). */
+	xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
+	xdr_stat = (xdr_u_int32(&tmpxdrs, &seq_num) &&
+		    (*xdr_func)(&tmpxdrs, xdr_ptr));
+	XDR_DESTROY(&tmpxdrs);
+	gss_release_buffer(&min_stat, &databuf);
+	
+	/* Verify sequence number. */
+	if (xdr_stat == TRUE && seq_num != seq) {
+		log_debug("wrong sequence number in databody");
+		return (FALSE);
+	}
+	return (xdr_stat);
+}
+
+bool_t
+xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
+		 gss_ctx_id_t ctx, gss_qop_t qop,
+		 rpc_gss_svc_t svc, uint32_t seq)
+{
+	switch (xdrs->x_op) {
+		
+	case XDR_ENCODE:
+		return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr,
+					      ctx, qop, svc, seq));
+	case XDR_DECODE:
+		return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr,
+						ctx, qop,svc, seq));
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+#ifdef DEBUG
+#include <ctype.h>
+
+void
+log_debug(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	fprintf(stderr, "rpcsec_gss: ");
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+void
+log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
+{
+	OM_uint32 min, msg_ctx;
+	gss_buffer_desc msgg, msgm;
+
+	msg_ctx = 0;
+	gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID,
+			   &msg_ctx, &msgg);
+	msg_ctx = 0;
+	gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID,
+			   &msg_ctx, &msgm);
+
+	log_debug("%s: %.*s - %.*s\n", m,
+		  msgg.length, (char *)msgg.value,
+		  msgm.length, (char *)msgm.value);
+
+	gss_release_buffer(&min, &msgg);
+	gss_release_buffer(&min, &msgm);
+}
+
+void
+log_hexdump(const u_char *buf, int len, int offset)
+{
+	u_int i, j, jm;
+	int c;
+	
+	fprintf(stderr, "\n");
+	for (i = 0; i < len; i += 0x10) {
+		fprintf(stderr, "  %04x: ", (u_int)(i + offset));
+		jm = len - i;
+		jm = jm > 16 ? 16 : jm;
+		
+		for (j = 0; j < jm; j++) {
+			if ((j % 2) == 1)
+				fprintf(stderr, "%02x ", (u_int) buf[i+j]);
+			else
+				fprintf(stderr, "%02x", (u_int) buf[i+j]);
+		}
+		for (; j < 16; j++) {
+			if ((j % 2) == 1) printf("   ");
+			else fprintf(stderr, "  ");
+		}
+		fprintf(stderr, " ");
+		
+		for (j = 0; j < jm; j++) {
+			c = buf[i+j];
+			c = isprint(c) ? c : '.';
+			fprintf(stderr, "%c", c);
+		}
+		fprintf(stderr, "\n");
+	}
+}
+
+#else
+
+void
+log_debug(const char *fmt, ...)
+{
+}
+
+void
+log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat)
+{
+}
+
+void
+log_hexdump(const u_char *buf, int len, int offset)
+{
+}
+
+#endif
+
+
diff --git a/mechglue/src/lib/rpc/authunix_prot.c b/mechglue/src/lib/rpc/authunix_prot.c
new file mode 100644
index 000000000..7eb47a4b4
--- /dev/null
+++ b/mechglue/src/lib/rpc/authunix_prot.c
@@ -0,0 +1,64 @@
+/* @(#)authunix_prot.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * authunix_prot.c
+ * XDR for UNIX style authentication parameters for RPC
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <gssrpc/auth.h>
+#include <gssrpc/auth_unix.h>
+
+/*
+ * XDR for unix authentication parameters.
+ */
+bool_t
+xdr_authunix_parms(register XDR *xdrs, register struct authunix_parms *p)
+{
+
+	if (xdr_u_int32(xdrs, &(p->aup_time))
+	    && xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME)
+	    && xdr_int(xdrs, &(p->aup_uid))
+	    && xdr_int(xdrs, &(p->aup_gid))
+	    && xdr_array(xdrs, (caddr_t *)&(p->aup_gids),
+		    &(p->aup_len), NGRPS, sizeof(int), xdr_int) ) {
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
diff --git a/mechglue/src/lib/rpc/bindresvport.c b/mechglue/src/lib/rpc/bindresvport.c
new file mode 100644
index 000000000..d1ec65452
--- /dev/null
+++ b/mechglue/src/lib/rpc/bindresvport.c
@@ -0,0 +1,83 @@
+#if !defined(lint) && defined(SCCSIDS)
+static  char sccsid[] = "@(#)bindresvport.c	2.2 88/07/29 4.0 RPCSRC 1.8 88/02/08 SMI";
+#endif
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Copyright (c) 1987 by Sun Microsystems, Inc.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <gssrpc/rpc.h>
+#include <errno.h>
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport(int sd, struct sockaddr_in *sockin)
+{
+	int res;
+	static short port;
+	struct sockaddr_in myaddr;
+	int i;
+
+#define STARTPORT 600
+#define ENDPORT (IPPORT_RESERVED - 1)
+#define NPORTS	(ENDPORT - STARTPORT + 1)
+
+	if (sockin == (struct sockaddr_in *)0) {
+		sockin = &myaddr;
+		memset(sockin, 0, sizeof (*sockin));
+		sockin->sin_family = AF_INET;
+	} else if (sockin->sin_family != AF_INET) {
+		errno = EPFNOSUPPORT;
+		return (-1);
+	}
+	if (port == 0) {
+		port = (getpid() % NPORTS) + STARTPORT;
+	}
+	res = -1;
+	errno = EADDRINUSE;
+	for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; i++) {
+		sockin->sin_port = htons(port++);
+		if (port > ENDPORT) {
+			port = STARTPORT;
+		}
+		res = bind(sd, (struct sockaddr *) sockin,
+			   sizeof(struct sockaddr_in));
+	}
+	return (res);
+}
diff --git a/mechglue/src/lib/rpc/clnt.h b/mechglue/src/lib/rpc/clnt.h
new file mode 100644
index 000000000..95450a241
--- /dev/null
+++ b/mechglue/src/lib/rpc/clnt.h
@@ -0,0 +1,344 @@
+/* @(#)clnt.h	2.1 88/07/29 4.0 RPCSRC; from 1.31 88/02/08 SMI*/
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * clnt.h - Client side remote procedure call interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef GSSRPC_CLNT_H
+#define GSSRPC_CLNT_H
+
+GSSRPC__BEGIN_DECLS
+/*
+ * Rpc calls return an enum clnt_stat.  This should be looked at more,
+ * since each implementation is required to live with this (implementation
+ * independent) list of errors.
+ */
+enum clnt_stat {
+	RPC_SUCCESS=0,			/* call succeeded */
+	/*
+	 * local errors
+	 */
+	RPC_CANTENCODEARGS=1,		/* can't encode arguments */
+	RPC_CANTDECODERES=2,		/* can't decode results */
+	RPC_CANTSEND=3,			/* failure in sending call */
+	RPC_CANTRECV=4,			/* failure in receiving result */
+	RPC_TIMEDOUT=5,			/* call timed out */
+	/*
+	 * remote errors
+	 */
+	RPC_VERSMISMATCH=6,		/* rpc versions not compatible */
+	RPC_AUTHERROR=7,		/* authentication error */
+	RPC_PROGUNAVAIL=8,		/* program not available */
+	RPC_PROGVERSMISMATCH=9,		/* program version mismatched */
+	RPC_PROCUNAVAIL=10,		/* procedure unavailable */
+	RPC_CANTDECODEARGS=11,		/* decode arguments error */
+	RPC_SYSTEMERROR=12,		/* generic "other problem" */
+
+	/*
+	 * callrpc & clnt_create errors
+	 */
+	RPC_UNKNOWNHOST=13,		/* unknown host name */
+	RPC_UNKNOWNPROTO=17,		/* unkown protocol */
+
+	/*
+	 * _ create errors
+	 */
+	RPC_PMAPFAILURE=14,		/* the pmapper failed in its call */
+	RPC_PROGNOTREGISTERED=15,	/* remote program is not registered */
+	/*
+	 * unspecified error
+	 */
+	RPC_FAILED=16
+};
+
+
+/*
+ * Error info.
+ */
+struct rpc_err {
+	enum clnt_stat re_status;
+	union {
+		int RE_errno;		/* realated system error */
+		enum auth_stat RE_why;	/* why the auth error occurred */
+		struct {
+			rpcvers_t low;	/* lowest verion supported */
+			rpcvers_t high;	/* highest verion supported */
+		} RE_vers;
+		struct {		/* maybe meaningful if RPC_FAILED */
+			int32_t s1;
+			int32_t s2;
+		} RE_lb;		/* life boot & debugging only */
+	} ru;
+#define	re_errno	ru.RE_errno
+#define	re_why		ru.RE_why
+#define	re_vers		ru.RE_vers
+#define	re_lb		ru.RE_lb
+};
+
+
+/*
+ * Client rpc handle.
+ * Created by individual implementations, see e.g. rpc_udp.c.
+ * Client is responsible for initializing auth, see e.g. auth_none.c.
+ */
+typedef struct CLIENT {
+	AUTH	*cl_auth;			/* authenticator */
+	struct clnt_ops {
+	        /* call remote procedure */
+	        enum clnt_stat	(*cl_call)(struct CLIENT *,
+					   rpcproc_t, xdrproc_t, void *,
+					   xdrproc_t, void *, 
+					   struct timeval);	
+                /* abort a call */
+		void		(*cl_abort)(struct CLIENT *);	
+                /* get specific error code */
+		void		(*cl_geterr)(struct CLIENT *, 
+					     struct rpc_err *);	
+                /* frees results */
+		bool_t		(*cl_freeres)(struct CLIENT *,
+					      xdrproc_t, void *);
+                /* destroy this structure */
+		void		(*cl_destroy)(struct CLIENT *);
+                /* the ioctl() of rpc */
+		/* XXX CITI makes 2nd arg take u_int */
+		bool_t          (*cl_control)(struct CLIENT *, int,
+					      void *);
+	} *cl_ops;
+	void			*cl_private;	/* private stuff */
+} CLIENT;
+
+
+/*
+ * client side rpc interface ops
+ *
+ * Parameter types are:
+ *
+ */
+
+/*
+ * enum clnt_stat
+ * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout)
+ * 	CLIENT *rh;
+ *	rpcproc_t proc;
+ *	xdrproc_t xargs;
+ *	caddr_t argsp;
+ *	xdrproc_t xres;
+ *	caddr_t resp;
+ *	struct timeval timeout;
+ */
+#define	CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs)	\
+	((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs))
+#define	clnt_call(rh, proc, xargs, argsp, xres, resp, secs)	\
+	((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs))
+
+/*
+ * void
+ * CLNT_ABORT(rh);
+ * 	CLIENT *rh;
+ */
+#define	CLNT_ABORT(rh)	((*(rh)->cl_ops->cl_abort)(rh))
+#define	clnt_abort(rh)	((*(rh)->cl_ops->cl_abort)(rh))
+
+/*
+ * struct rpc_err
+ * CLNT_GETERR(rh);
+ * 	CLIENT *rh;
+ */
+#define	CLNT_GETERR(rh,errp)	((*(rh)->cl_ops->cl_geterr)(rh, errp))
+#define	clnt_geterr(rh,errp)	((*(rh)->cl_ops->cl_geterr)(rh, errp))
+
+
+/*
+ * bool_t
+ * CLNT_FREERES(rh, xres, resp);
+ * 	CLIENT *rh;
+ *	xdrproc_t xres;
+ *	caddr_t resp;
+ */
+#define	CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
+#define	clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
+
+/*
+ * bool_t
+ * CLNT_CONTROL(cl, request, info)
+ *      CLIENT *cl;
+ *      u_int request;
+ *      char *info;
+ */
+#define	CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
+#define	clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
+
+/*
+ * control operations that apply to both udp and tcp transports
+ */
+#define CLSET_TIMEOUT       1   /* set timeout (timeval) */
+#define CLGET_TIMEOUT       2   /* get timeout (timeval) */
+#define CLGET_SERVER_ADDR   3   /* get server's address (sockaddr) */
+/*
+ * udp only control operations
+ */
+#define CLSET_RETRY_TIMEOUT 4   /* set retry timeout (timeval) */
+#define CLGET_RETRY_TIMEOUT 5   /* get retry timeout (timeval) */
+/*
+ * new control operations
+ */
+#define CLGET_LOCAL_ADDR    6	/* get local address (sockaddr, getsockname)*/
+
+/*
+ * void
+ * CLNT_DESTROY(rh);
+ * 	CLIENT *rh;
+ */
+#define	CLNT_DESTROY(rh)	((*(rh)->cl_ops->cl_destroy)(rh))
+#define	clnt_destroy(rh)	((*(rh)->cl_ops->cl_destroy)(rh))
+
+
+/*
+ * RPCTEST is a test program which is accessable on every rpc
+ * transport/port.  It is used for testing, performance evaluation,
+ * and network administration.
+ */
+
+#define RPCTEST_PROGRAM		((rpcprog_t)1)
+#define RPCTEST_VERSION		((rpcvers_t)1)
+#define RPCTEST_NULL_PROC	((rpcproc_t)2)
+#define RPCTEST_NULL_BATCH_PROC	((rpcproc_t)3)
+
+/*
+ * By convention, procedure 0 takes null arguments and returns them
+ */
+
+#define NULLPROC ((rpcproc_t)0)
+
+/*
+ * Below are the client handle creation routines for the various
+ * implementations of client side rpc.  They can return NULL if a 
+ * creation failure occurs.
+ */
+
+/*
+ * Memory based rpc (for speed check and testing)
+ * CLIENT *
+ * clntraw_create(prog, vers)
+ *	rpcprog_t prog;
+ *	rpcvers_t vers;
+ */
+extern CLIENT *clntraw_create(rpcprog_t, rpcvers_t);
+
+/*
+ * Generic client creation routine. Supported protocols are "udp" and "tcp"
+ */
+extern CLIENT *clnt_create(char *, rpcprog_t, rpcvers_t, char *);
+
+
+/*
+ * TCP based rpc
+ * CLIENT *
+ * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
+ *	struct sockaddr_in *raddr;
+ *	rpcprog_t prog;
+ *	rpcvers_t version;
+ *	register int *sockp;
+ *	u_int sendsz;
+ *	u_int recvsz;
+ */
+extern CLIENT *clnttcp_create(struct sockaddr_in *, rpcprog_t, rpcvers_t,
+			      int *, u_int, u_int);
+
+/*
+ * UDP based rpc.
+ * CLIENT *
+ * clntudp_create(raddr, program, version, wait, sockp)
+ *	struct sockaddr_in *raddr;
+ *	rpcprog_t program;
+ *	rpcvers_t version;
+ *	struct timeval wait;
+ *	int *sockp;
+ *
+ * Same as above, but you specify max packet sizes.
+ * CLIENT *
+ * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
+ *	struct sockaddr_in *raddr;
+ *	rpcprog_t program;
+ *	rpcvers_t version;
+ *	struct timeval wait;
+ *	int *sockp;
+ *	u_int sendsz;
+ *	u_int recvsz;
+ */
+extern CLIENT *clntudp_create(struct sockaddr_in *, rpcprog_t,
+			      rpcvers_t, struct timeval, int *);
+extern CLIENT *clntudp_bufcreate(struct sockaddr_in *, rpcprog_t,
+				 rpcvers_t, struct timeval, int *,
+				 u_int, u_int);
+
+/*
+ * Print why creation failed
+ */
+void clnt_pcreateerror(char *);	/* stderr */
+char *clnt_spcreateerror(char *);	/* string */
+
+/*
+ * Like clnt_perror(), but is more verbose in its output
+ */ 
+void clnt_perrno(enum clnt_stat);	/* stderr */
+
+/*
+ * Print an English error message, given the client error code
+ */
+void clnt_perror(CLIENT *, char *); 	/* stderr */
+char *clnt_sperror(CLIENT *, char *);	/* string */
+
+/* 
+ * If a creation fails, the following allows the user to figure out why.
+ */
+struct rpc_createerr {
+	enum clnt_stat cf_stat;
+	struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */
+};
+
+extern struct rpc_createerr rpc_createerr;
+
+
+
+/*
+ * Copy error message to buffer.
+ */
+char *clnt_sperrno(enum clnt_stat num);	/* string */
+
+#define UDPMSGSIZE	8800	/* rpc imposed limit on udp msg size */
+#define RPCSMALLMSGSIZE	400	/* a more reasonable packet size */
+
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_CLNT_H) */
diff --git a/mechglue/src/lib/rpc/clnt_generic.c b/mechglue/src/lib/rpc/clnt_generic.c
new file mode 100644
index 000000000..225ab9432
--- /dev/null
+++ b/mechglue/src/lib/rpc/clnt_generic.c
@@ -0,0 +1,114 @@
+/* @(#)clnt_generic.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";
+#endif
+/*
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+#include <string.h>
+#include <gssrpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <netdb.h>
+
+/*
+ * Generic client creation: takes (hostname, program-number, protocol) and
+ * returns client handle. Default options are set, which the user can 
+ * change using the rpc equivalent of ioctl()'s.
+ */
+CLIENT *
+clnt_create(
+	char *hostname,
+	rpcprog_t prog,
+	rpcvers_t vers,
+	char *proto)
+{
+	struct hostent *h;
+	struct protoent *p;
+	struct sockaddr_in sockin;
+	int sock;
+	struct timeval tv;
+	CLIENT *client;
+
+	h = gethostbyname(hostname);
+	if (h == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
+		return (NULL);
+	}
+	if (h->h_addrtype != AF_INET) {
+		/*
+		 * Only support INET for now
+		 */
+		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+		rpc_createerr.cf_error.re_errno = EAFNOSUPPORT; 
+		return (NULL);
+	}
+	memset(&sockin, 0, sizeof(sockin));
+#if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+	sockin.sin_len = sizeof(sockin);
+#endif
+	sockin.sin_family = h->h_addrtype;
+	sockin.sin_port = 0;
+	memmove((char*)&sockin.sin_addr, h->h_addr, sizeof(sockin.sin_addr));
+	p = getprotobyname(proto);
+	if (p == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+		rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; 
+		return (NULL);
+	}
+	sock = RPC_ANYSOCK;
+	switch (p->p_proto) {
+	case IPPROTO_UDP:
+		tv.tv_sec = 5;
+		tv.tv_usec = 0;
+		client = clntudp_create(&sockin, prog, vers, tv, &sock);
+		if (client == NULL) {
+			return (NULL);
+		}
+		tv.tv_sec = 25;
+		clnt_control(client, CLSET_TIMEOUT, &tv);
+		break;
+	case IPPROTO_TCP:
+		client = clnttcp_create(&sockin, prog, vers, &sock, 0, 0);
+		if (client == NULL) {
+			return (NULL);
+		}
+		tv.tv_sec = 25;
+		tv.tv_usec = 0;
+		clnt_control(client, CLSET_TIMEOUT, &tv);
+		break;
+	default:
+		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+		rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; 
+		return (NULL);
+	}
+	return (client);
+}
diff --git a/mechglue/src/lib/rpc/clnt_perror.c b/mechglue/src/lib/rpc/clnt_perror.c
new file mode 100644
index 000000000..4f159c3b0
--- /dev/null
+++ b/mechglue/src/lib/rpc/clnt_perror.c
@@ -0,0 +1,343 @@
+/* @(#)clnt_perror.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_perror.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <gssrpc/types.h>
+#include <gssrpc/auth.h>
+#include <gssrpc/clnt.h>
+
+#ifndef HAVE_STRERROR
+#ifdef NEED_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+extern int sys_nerr;
+#undef strerror
+#define strerror(N) (((N) > 0 && (N) < sys_nerr) ? sys_errlist[N] : (char *)0)
+#endif /* HAVE_STRERROR */
+static char *auth_errmsg(enum auth_stat);
+
+
+
+static char *buf;
+
+static char *
+get_buf(void)
+{
+	if (buf == NULL)
+		buf = (char *)malloc(BUFSIZ);
+	return (buf);
+}
+
+/*
+ * Print reply error info
+ */
+char *
+clnt_sperror(CLIENT *rpch, char *s)
+{
+	struct rpc_err e;
+	void clnt_perrno();
+	char *err;
+	char *bufstart = get_buf();
+	char *str = bufstart;
+	char *strstart = str;
+
+	if (str == 0)
+		return (0);
+	CLNT_GETERR(rpch, &e);
+
+	strncpy (str, s, BUFSIZ - 1);
+	str[BUFSIZ - 1] = 0;
+	strncat (str, ": ", BUFSIZ - 1 - strlen (bufstart));
+	str += strlen(str);
+	strncat (str, clnt_sperrno(e.re_status), BUFSIZ - 1 - strlen (bufstart));
+	strstart[BUFSIZ - 1] = '\0';
+	str += strlen(str);
+
+	switch (e.re_status) {
+	case RPC_SUCCESS:
+	case RPC_CANTENCODEARGS:
+	case RPC_CANTDECODERES:
+	case RPC_TIMEDOUT:     
+	case RPC_PROGUNAVAIL:
+	case RPC_PROCUNAVAIL:
+	case RPC_CANTDECODEARGS:
+	case RPC_SYSTEMERROR:
+	case RPC_UNKNOWNHOST:
+	case RPC_UNKNOWNPROTO:
+	case RPC_PMAPFAILURE:
+	case RPC_PROGNOTREGISTERED:
+	case RPC_FAILED:
+		break;
+
+	case RPC_CANTSEND:
+	case RPC_CANTRECV:
+		/* 10 for the string */
+		if(str - bufstart + 10 + strlen(strerror(e.re_errno)) < BUFSIZ)
+		    (void) sprintf(str, "; errno = %s",
+				   strerror(e.re_errno)); 
+		str += strlen(str);
+		break;
+
+	case RPC_VERSMISMATCH:
+		/* 33 for the string, 22 for the numbers */
+		if(str - bufstart + 33 + 22 < BUFSIZ)
+		    (void) sprintf(str,
+				   "; low version = %lu, high version = %lu", 
+				   (u_long) e.re_vers.low,
+				   (u_long) e.re_vers.high);
+		str += strlen(str);
+		break;
+
+	case RPC_AUTHERROR:
+		err = auth_errmsg(e.re_why);
+		/* 8 for the string */
+		if(str - bufstart + 8 < BUFSIZ)
+		    (void) sprintf(str,"; why = ");
+		str += strlen(str);
+		if (err != NULL) {
+			if(str - bufstart + strlen(err) < BUFSIZ)
+			    (void) sprintf(str, "%s",err);
+		} else {
+		    /* 33 for the string, 11 for the number */
+		    if(str - bufstart + 33 + 11 < BUFSIZ)
+			(void) sprintf(str,
+				       "(unknown authentication error - %d)",
+				       (int) e.re_why);
+		}
+		str += strlen(str);
+		break;
+
+	case RPC_PROGVERSMISMATCH:
+		/* 33 for the string, 22 for the numbers */
+		if(str - bufstart + 33 + 22 < BUFSIZ)
+		    (void) sprintf(str,
+				   "; low version = %lu, high version = %lu",
+				   (u_long) e.re_vers.low,
+				   (u_long) e.re_vers.high);
+		str += strlen(str);
+		break;
+
+	default:	/* unknown */
+		/* 14 for the string, 22 for the numbers */
+		if(str - bufstart + 14 + 22 < BUFSIZ)
+		    (void) sprintf(str,
+				   "; s1 = %lu, s2 = %lu",
+				   (u_long) e.re_lb.s1,
+				   (u_long) e.re_lb.s2);
+		str += strlen(str);
+		break;
+	}
+	if(str - bufstart + 1 < BUFSIZ)
+	    (void) sprintf(str, "\n");
+	return(strstart) ;
+}
+
+void
+clnt_perror(CLIENT *rpch, char *s)
+{
+	(void) fprintf(stderr,"%s",clnt_sperror(rpch,s));
+}
+
+
+struct rpc_errtab {
+	enum clnt_stat status;
+	char *message;
+};
+
+static struct rpc_errtab  rpc_errlist[] = {
+	{ RPC_SUCCESS, 
+		"RPC: Success" }, 
+	{ RPC_CANTENCODEARGS, 
+		"RPC: Can't encode arguments" },
+	{ RPC_CANTDECODERES, 
+		"RPC: Can't decode result" },
+	{ RPC_CANTSEND, 
+		"RPC: Unable to send" },
+	{ RPC_CANTRECV, 
+		"RPC: Unable to receive" },
+	{ RPC_TIMEDOUT, 
+		"RPC: Timed out" },
+	{ RPC_VERSMISMATCH, 
+		"RPC: Incompatible versions of RPC" },
+	{ RPC_AUTHERROR, 
+		"RPC: Authentication error" },
+	{ RPC_PROGUNAVAIL, 
+		"RPC: Program unavailable" },
+	{ RPC_PROGVERSMISMATCH, 
+		"RPC: Program/version mismatch" },
+	{ RPC_PROCUNAVAIL, 
+		"RPC: Procedure unavailable" },
+	{ RPC_CANTDECODEARGS, 
+		"RPC: Server can't decode arguments" },
+	{ RPC_SYSTEMERROR, 
+		"RPC: Remote system error" },
+	{ RPC_UNKNOWNHOST, 
+		"RPC: Unknown host" },
+	{ RPC_UNKNOWNPROTO,
+		"RPC: Unknown protocol" },
+	{ RPC_PMAPFAILURE, 
+		"RPC: Port mapper failure" },
+	{ RPC_PROGNOTREGISTERED, 
+		"RPC: Program not registered"},
+	{ RPC_FAILED, 
+		"RPC: Failed (unspecified error)"}
+};
+
+
+/*
+ * This interface for use by clntrpc
+ */
+char *
+clnt_sperrno(enum clnt_stat stat)
+{
+	int i;
+
+	for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) {
+		if (rpc_errlist[i].status == stat) {
+			return (rpc_errlist[i].message);
+		}
+	}
+	return ("RPC: (unknown error code)");
+}
+
+void
+clnt_perrno(enum clnt_stat num)
+{
+	(void) fprintf(stderr,"%s",clnt_sperrno(num));
+}
+
+
+char *
+clnt_spcreateerror(char *s)
+{
+	char *str = get_buf();
+
+	if (str == 0)
+		return(0);
+	(void) sprintf(str, "%s: ", s);
+	str[BUFSIZ - 1] = '\0';
+	(void) strncat(str, clnt_sperrno(rpc_createerr.cf_stat), BUFSIZ - 1);
+	switch (rpc_createerr.cf_stat) {
+	case RPC_PMAPFAILURE:
+		(void) strncat(str, " - ", BUFSIZ - 1 - strlen(str));
+		(void) strncat(str,
+		    clnt_sperrno(rpc_createerr.cf_error.re_status),
+		    BUFSIZ - 1 - strlen(str));
+		break;
+
+	case RPC_SYSTEMERROR:
+		(void) strncat(str, " - ", BUFSIZ - 1 - strlen(str));
+		{
+		    const char *m = strerror(rpc_createerr.cf_error.re_errno);
+		    if (m)
+			(void) strncat(str, m, BUFSIZ - 1 - strlen(str));
+		    else
+			(void) sprintf(&str[strlen(str)], "Error %d",
+				       rpc_createerr.cf_error.re_errno);
+		}
+		break;
+
+	case RPC_CANTSEND:
+	case RPC_CANTDECODERES:
+	case RPC_CANTENCODEARGS:
+	case RPC_SUCCESS:
+	case RPC_UNKNOWNPROTO:
+	case RPC_PROGNOTREGISTERED:
+	case RPC_FAILED:
+	case RPC_UNKNOWNHOST:
+	case RPC_CANTDECODEARGS:
+	case RPC_PROCUNAVAIL:
+	case RPC_PROGVERSMISMATCH:
+	case RPC_PROGUNAVAIL:
+	case RPC_AUTHERROR:
+	case RPC_VERSMISMATCH:
+	case RPC_TIMEDOUT:
+	case RPC_CANTRECV:
+	default:
+	    break;
+	}
+	(void) strncat(str, "\n", BUFSIZ - 1 - strlen(str));
+	return (str);
+}
+
+void
+clnt_pcreateerror(char *s)
+{
+	(void) fprintf(stderr,"%s",clnt_spcreateerror(s));
+}
+
+struct auth_errtab {
+	enum auth_stat status;	
+	char *message;
+};
+
+static struct auth_errtab auth_errlist[] = {
+	{ AUTH_OK,
+		"Authentication OK" },
+	{ AUTH_BADCRED,
+		"Invalid client credential" },
+	{ AUTH_REJECTEDCRED,
+		"Server rejected credential" },
+	{ AUTH_BADVERF,
+		"Invalid client verifier" },
+	{ AUTH_REJECTEDVERF,
+		"Server rejected verifier" },
+	{ AUTH_TOOWEAK,
+		"Client credential too weak" },
+	{ AUTH_INVALIDRESP,
+		"Invalid server verifier" },
+	{ AUTH_FAILED,
+		"Failed (unspecified error)" },
+};
+
+static char *
+auth_errmsg(enum auth_stat stat)
+{
+	int i;
+
+	for (i = 0; i < sizeof(auth_errlist)/sizeof(struct auth_errtab); i++) {
+		if (auth_errlist[i].status == stat) {
+			return(auth_errlist[i].message);
+		}
+	}
+	return(NULL);
+}
diff --git a/mechglue/src/lib/rpc/clnt_raw.c b/mechglue/src/lib/rpc/clnt_raw.c
new file mode 100644
index 000000000..06b078e99
--- /dev/null
+++ b/mechglue/src/lib/rpc/clnt_raw.c
@@ -0,0 +1,268 @@
+/* @(#)clnt_raw.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_raw.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * Memory based rpc for simple testing and timing.
+ * Interface to create an rpc client and server in the same process.
+ * This lets us similate rpc and get round trip overhead, without
+ * any interference from the kernal.
+ */
+
+#include <gssrpc/rpc.h>
+
+#define MCALL_MSG_SIZE 24
+
+/*
+ * This is the "network" we will be moving stuff over.
+ */
+static struct clntraw_private {
+	CLIENT	client_object;
+	XDR	xdr_stream;
+	char	_raw_buf[UDPMSGSIZE];
+        union {
+	  struct rpc_msg    mashl_rpcmsg;
+	  char	            mashl_callmsg[MCALL_MSG_SIZE];
+	} u;
+	u_int	mcnt;
+} *clntraw_private;
+
+static enum clnt_stat	clntraw_call(CLIENT *, rpcproc_t, xdrproc_t, 
+				     void *, xdrproc_t, void *, 
+				     struct timeval);
+static void		clntraw_abort(CLIENT *);
+static void		clntraw_geterr(CLIENT *, struct rpc_err *);
+static bool_t		clntraw_freeres(CLIENT *, xdrproc_t, void *);
+static bool_t		clntraw_control(CLIENT *, int, void *);
+static void		clntraw_destroy(CLIENT *);
+
+static struct clnt_ops client_ops = {
+	clntraw_call,
+	clntraw_abort,
+	clntraw_geterr,
+	clntraw_freeres,
+	clntraw_destroy,
+	clntraw_control
+};
+
+void	svc_getreq();
+
+/*
+ * Create a client handle for memory based rpc.
+ */
+CLIENT *
+clntraw_create(
+	rpcprog_t prog,
+	rpcvers_t vers)
+{
+	register struct clntraw_private *clp = clntraw_private;
+	struct rpc_msg call_msg;
+	XDR *xdrs = &clp->xdr_stream;
+	CLIENT	*client = &clp->client_object;
+
+	if (clp == 0) {
+		clp = (struct clntraw_private *)calloc(1, sizeof (*clp));
+		if (clp == 0)
+			return (0);
+		clntraw_private = clp;
+	}
+	/*
+	 * pre-serialize the staic part of the call msg and stash it away
+	 */
+	call_msg.rm_direction = CALL;
+	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+	call_msg.rm_call.cb_prog = prog;
+	call_msg.rm_call.cb_vers = vers;
+	xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); 
+	if (! xdr_callhdr(xdrs, &call_msg)) {
+		perror("clnt_raw.c - Fatal header serialization error.");
+	}
+	clp->mcnt = XDR_GETPOS(xdrs);
+	XDR_DESTROY(xdrs);
+
+	/*
+	 * Set xdrmem for client/server shared buffer
+	 */
+	xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE);
+
+	/*
+	 * create client handle
+	 */
+	client->cl_ops = &client_ops;
+	client->cl_auth = authnone_create();
+	return (client);
+}
+
+static enum clnt_stat 
+clntraw_call(
+	CLIENT *h,
+	rpcproc_t proc,
+	xdrproc_t xargs,
+	void * argsp,
+	xdrproc_t xresults,
+	void * resultsp,
+	struct timeval timeout)
+{
+	register struct clntraw_private *clp = clntraw_private;
+	register XDR *xdrs = &clp->xdr_stream;
+	struct rpc_msg msg;
+	enum clnt_stat status;
+	struct rpc_err error;
+	long procl = proc;
+
+	if (clp == 0)
+		return (RPC_FAILED);
+call_again:
+	/*
+	 * send request
+	 */
+	xdrs->x_op = XDR_ENCODE;
+	XDR_SETPOS(xdrs, 0);
+	clp->u.mashl_rpcmsg.rm_xid ++ ;
+	if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) ||
+	    (! XDR_PUTLONG(xdrs, &procl)) ||
+	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
+	    (! (*xargs)(xdrs, argsp))) {
+		return (RPC_CANTENCODEARGS);
+	}
+	(void)XDR_GETPOS(xdrs);  /* called just to cause overhead */
+
+	/*
+	 * We have to call server input routine here because this is
+	 * all going on in one process. Yuk.
+	 */
+	svc_getreq(1);
+
+	/*
+	 * get results
+	 */
+	xdrs->x_op = XDR_DECODE;
+	XDR_SETPOS(xdrs, 0);
+	msg.acpted_rply.ar_verf = gssrpc__null_auth;
+	msg.acpted_rply.ar_results.where = resultsp;
+	msg.acpted_rply.ar_results.proc = xresults;
+	if (! xdr_replymsg(xdrs, &msg)) {
+		/*
+		 * It's possible for xdr_replymsg() to fail partway
+		 * through its attempt to decode the result from the
+		 * server. If this happens, it will leave the reply
+		 * structure partially populated with dynamically
+		 * allocated memory. (This can happen if someone uses
+		 * clntudp_bufcreate() to create a CLIENT handle and
+		 * specifies a receive buffer size that is too small.)
+		 * This memory must be free()ed to avoid a leak.
+		 */
+		enum xdr_op op = xdrs->x_op;
+		xdrs->x_op = XDR_FREE;
+		xdr_replymsg(xdrs, &msg);
+		xdrs->x_op = op;
+		return (RPC_CANTDECODERES);
+	}
+	gssrpc__seterr_reply(&msg, &error);
+	status = error.re_status;
+
+	if (status == RPC_SUCCESS) {
+		if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
+			status = RPC_AUTHERROR;
+		}
+	}  /* end successful completion */
+	else {
+		if (AUTH_REFRESH(h->cl_auth, &msg))
+			goto call_again;
+	}  /* end of unsuccessful completion */
+
+	if (status == RPC_SUCCESS) {
+		if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
+			status = RPC_AUTHERROR;
+		}
+		if (msg.acpted_rply.ar_verf.oa_base != NULL) {
+			xdrs->x_op = XDR_FREE;
+			(void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf));
+		}
+	}
+
+	return (status);
+}
+
+/*ARGSUSED*/
+static void
+clntraw_geterr(
+	CLIENT *cl,
+	struct rpc_err *err)
+{
+}
+
+
+static bool_t
+clntraw_freeres(
+	CLIENT *cl,
+	xdrproc_t xdr_res,
+	void *res_ptr)
+{
+	register struct clntraw_private *clp = clntraw_private;
+	register XDR *xdrs = &clp->xdr_stream;
+	bool_t rval;
+
+	if (clp == 0)
+	{
+		rval = (bool_t) RPC_FAILED;
+		return (rval);
+	}
+	xdrs->x_op = XDR_FREE;
+	return ((*xdr_res)(xdrs, res_ptr));
+}
+
+/*ARGSUSED*/
+static void
+clntraw_abort(CLIENT *cl)
+{
+}
+
+/*ARGSUSED*/
+static bool_t
+clntraw_control(
+	CLIENT *cl,
+	int request,
+	void *info)
+{
+	return (FALSE);
+}
+
+/*ARGSUSED*/
+static void
+clntraw_destroy(CLIENT *cl)
+{
+}
diff --git a/mechglue/src/lib/rpc/clnt_simple.c b/mechglue/src/lib/rpc/clnt_simple.c
new file mode 100644
index 000000000..317fbe5dd
--- /dev/null
+++ b/mechglue/src/lib/rpc/clnt_simple.c
@@ -0,0 +1,128 @@
+/* @(#)clnt_simple.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/* 
+ * clnt_simple.c
+ * Simplified front end to rpc.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+/* for close() */
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+
+static struct callrpc_private {
+	CLIENT	*client;
+	int	socket;
+	int	oldprognum, oldversnum, valid;
+	char	*oldhost;
+} *callrpc_private;
+
+int
+callrpc(
+	char *host,
+	rpcprog_t prognum,
+	rpcvers_t versnum,
+	rpcproc_t procnum,
+	xdrproc_t inproc,
+	char *in,
+	xdrproc_t outproc,
+	char *out)
+{
+	register struct callrpc_private *crp = callrpc_private;
+	struct sockaddr_in server_addr;
+	enum clnt_stat clnt_stat;
+	struct hostent *hp;
+	struct timeval timeout, tottimeout;
+
+	if (crp == 0) {
+		crp = (struct callrpc_private *)calloc(1, sizeof (*crp));
+		if (crp == 0)
+			return (0);
+		callrpc_private = crp;
+	}
+	if (crp->oldhost == NULL) {
+		crp->oldhost = mem_alloc(256);
+		if (crp->oldhost == 0)
+		    return 0;
+		crp->oldhost[0] = 0;
+		crp->socket = RPC_ANYSOCK;
+	}
+	if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum
+		&& strcmp(crp->oldhost, host) == 0) {
+		/* reuse old client */		
+	} else {
+		crp->valid = 0;
+		(void)close(crp->socket);
+		crp->socket = RPC_ANYSOCK;
+		if (crp->client) {
+			clnt_destroy(crp->client);
+			crp->client = NULL;
+		}
+		if ((hp = gethostbyname(host)) == NULL)
+			return ((int) RPC_UNKNOWNHOST);
+		timeout.tv_usec = 0;
+		timeout.tv_sec = 5;
+		memset(&server_addr, 0, sizeof(server_addr));
+		memmove((char *)&server_addr.sin_addr, hp->h_addr, 
+			sizeof(server_addr.sin_addr));
+#if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+		server_addr.sin_len = sizeof(server_addr);
+#endif
+		server_addr.sin_family = AF_INET;
+		server_addr.sin_port =  0;
+		if ((crp->client = clntudp_create(&server_addr, prognum,
+		    versnum, timeout, &crp->socket)) == NULL)
+			return ((int) rpc_createerr.cf_stat);
+		crp->valid = 1;
+		crp->oldprognum = prognum;
+		crp->oldversnum = versnum;
+		(void) strncpy(crp->oldhost, host, 255);
+		crp->oldhost[255] = '\0';
+	}
+	tottimeout.tv_sec = 25;
+	tottimeout.tv_usec = 0;
+	clnt_stat = clnt_call(crp->client, procnum, inproc, in,
+	    outproc, out, tottimeout);
+	/* 
+	 * if call failed, empty cache
+	 */
+	if (clnt_stat != RPC_SUCCESS)
+		crp->valid = 0;
+	return ((int) clnt_stat);
+}
diff --git a/mechglue/src/lib/rpc/clnt_tcp.c b/mechglue/src/lib/rpc/clnt_tcp.c
new file mode 100644
index 000000000..1f8de8276
--- /dev/null
+++ b/mechglue/src/lib/rpc/clnt_tcp.c
@@ -0,0 +1,496 @@
+/* @(#)clnt_tcp.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
+#endif
+ 
+/*
+ * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer.  The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message.  Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+#include <gssrpc/pmap_clnt.h>
+/* FD_ZERO may need memset declaration (e.g., Solaris 9) */
+#include <string.h>
+
+#define MCALL_MSG_SIZE 24
+
+static enum clnt_stat	clnttcp_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
+				     xdrproc_t, void *, struct timeval);
+static void		clnttcp_abort(CLIENT *);
+static void		clnttcp_geterr(CLIENT *, struct rpc_err *);
+static bool_t		clnttcp_freeres(CLIENT *, xdrproc_t, void *);
+static bool_t           clnttcp_control(CLIENT *, int, void *);
+static void		clnttcp_destroy(CLIENT *);
+
+static struct clnt_ops tcp_ops = {
+	clnttcp_call,
+	clnttcp_abort,
+	clnttcp_geterr,
+	clnttcp_freeres,
+	clnttcp_destroy,
+	clnttcp_control
+};
+
+struct ct_data {
+	int		ct_sock;
+	bool_t		ct_closeit;
+	struct timeval	ct_wait;
+	bool_t          ct_waitset;       /* wait set by clnt_control? */
+	struct sockaddr_in ct_addr; 
+	struct rpc_err	ct_error;
+	union {
+	  char		ct_mcall[MCALL_MSG_SIZE];	/* marshalled callmsg */
+	  uint32_t   ct_mcalli;
+	} ct_u;
+	u_int		ct_mpos;			/* pos after marshal */
+	XDR		ct_xdrs;
+};
+
+static int	readtcp(char *, caddr_t, int);
+static int	writetcp(char *, caddr_t, int);
+
+
+/*
+ * Create a client handle for a tcp/ip connection.
+ * If *sockp<0, *sockp is set to a newly created TCP socket and it is
+ * connected to raddr.  If *sockp non-negative then
+ * raddr is ignored.  The rpc/tcp package does buffering
+ * similar to stdio, so the client must pick send and receive buffer sizes,];
+ * 0 => use the default.
+ * If raddr->sin_port is 0, then a binder on the remote machine is
+ * consulted for the right port number.
+ * NB: *sockp is copied into a private area.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
+ * something more useful.
+ */
+CLIENT *
+clnttcp_create(
+	struct sockaddr_in *raddr,
+	rpcprog_t prog,
+	rpcvers_t vers,
+	register int *sockp,
+	u_int sendsz,
+	u_int recvsz)
+{
+	CLIENT *h;
+	register struct ct_data *ct = 0;
+	struct timeval now;
+	struct rpc_msg call_msg;
+
+	h  = (CLIENT *)mem_alloc(sizeof(*h));
+	if (h == NULL) {
+		(void)fprintf(stderr, "clnttcp_create: out of memory\n");
+		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+		rpc_createerr.cf_error.re_errno = errno;
+		goto fooy;
+	}
+	ct = (struct ct_data *)mem_alloc(sizeof(*ct));
+	if (ct == NULL) {
+		(void)fprintf(stderr, "clnttcp_create: out of memory\n");
+		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+		rpc_createerr.cf_error.re_errno = errno;
+		goto fooy;
+	}
+
+	/*
+	 * If no port number given ask the pmap for one
+	 */
+	if (raddr->sin_port == 0) {
+		u_short port;
+		if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
+			mem_free((caddr_t)ct, sizeof(struct ct_data));
+			mem_free((caddr_t)h, sizeof(CLIENT));
+			return ((CLIENT *)NULL);
+		}
+		raddr->sin_port = htons(port);
+	}
+
+	/*
+	 * If no socket given, open one
+	 */
+	if (*sockp < 0) {
+		*sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+		(void)bindresvport(*sockp, (struct sockaddr_in *)0);
+		if ((*sockp < 0)
+		    || (connect(*sockp, (struct sockaddr *)raddr,
+		    sizeof(*raddr)) < 0)) {
+			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+			rpc_createerr.cf_error.re_errno = errno;
+			(void)close(*sockp);
+			goto fooy;
+		}
+		ct->ct_closeit = TRUE;
+	} else {
+		ct->ct_closeit = FALSE;
+	}
+
+	/*
+	 * Set up private data struct
+	 */
+	ct->ct_sock = *sockp;
+	ct->ct_wait.tv_usec = 0;
+	ct->ct_waitset = FALSE;
+	ct->ct_addr = *raddr;
+
+	/*
+	 * Initialize call message
+	 */
+	(void)gettimeofday(&now, (struct timezone *)0);
+	call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+	call_msg.rm_direction = CALL;
+	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+	call_msg.rm_call.cb_prog = prog;
+	call_msg.rm_call.cb_vers = vers;
+
+	/*
+	 * pre-serialize the staic part of the call msg and stash it away
+	 */
+	xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcall, MCALL_MSG_SIZE,
+	    XDR_ENCODE);
+	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
+		if (ct->ct_closeit) {
+			(void)close(*sockp);
+		}
+		goto fooy;
+	}
+	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
+	XDR_DESTROY(&(ct->ct_xdrs));
+
+	/*
+	 * Create a client handle which uses xdrrec for serialization
+	 * and authnone for authentication.
+	 */
+	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
+	    (caddr_t)ct, readtcp, writetcp);
+	h->cl_ops = &tcp_ops;
+	h->cl_private = (caddr_t) ct;
+	h->cl_auth = authnone_create();
+	return (h);
+
+fooy:
+	/*
+	 * Something goofed, free stuff and barf
+	 */
+	mem_free((caddr_t)ct, sizeof(struct ct_data));
+	mem_free((caddr_t)h, sizeof(CLIENT));
+	return ((CLIENT *)NULL);
+}
+
+static enum clnt_stat
+clnttcp_call(
+	register CLIENT *h,
+	rpcproc_t proc,
+	xdrproc_t xdr_args,
+	void * args_ptr,
+	xdrproc_t xdr_results,
+	void * results_ptr,
+	struct timeval timeout)
+{
+	register struct ct_data *ct = (struct ct_data *) h->cl_private;
+	register XDR *xdrs = &(ct->ct_xdrs);
+	struct rpc_msg reply_msg;
+	uint32_t x_id;
+	uint32_t *msg_x_id = &ct->ct_u.ct_mcalli;	/* yuk */
+	register bool_t shipnow;
+	int refreshes = 2;
+	long procl = proc;
+
+	if (!ct->ct_waitset) {
+		ct->ct_wait = timeout;
+	}
+
+	shipnow =
+	    (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
+	    && timeout.tv_usec == 0) ? FALSE : TRUE;
+
+call_again:
+	xdrs->x_op = XDR_ENCODE;
+	ct->ct_error.re_status = RPC_SUCCESS;
+	x_id = ntohl(--(*msg_x_id));
+	if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcall, ct->ct_mpos)) ||
+	    (! XDR_PUTLONG(xdrs, &procl)) ||
+	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
+	    (! AUTH_WRAP(h->cl_auth, xdrs, xdr_args, args_ptr))) {
+		if (ct->ct_error.re_status == RPC_SUCCESS)
+			ct->ct_error.re_status = RPC_CANTENCODEARGS;
+		(void)xdrrec_endofrecord(xdrs, TRUE);
+		return (ct->ct_error.re_status);
+	}
+	if (! xdrrec_endofrecord(xdrs, shipnow))
+		return (ct->ct_error.re_status = RPC_CANTSEND);
+	if (! shipnow)
+		return (RPC_SUCCESS);
+	/*
+	 * Hack to provide rpc-based message passing
+	 */
+	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+		return(ct->ct_error.re_status = RPC_TIMEDOUT);
+	}
+
+
+	/*
+	 * Keep receiving until we get a valid transaction id
+	 */
+	xdrs->x_op = XDR_DECODE;
+	while (TRUE) {
+		reply_msg.acpted_rply.ar_verf = gssrpc__null_auth;
+		reply_msg.acpted_rply.ar_results.where = NULL;
+		reply_msg.acpted_rply.ar_results.proc = xdr_void;
+		if (! xdrrec_skiprecord(xdrs))
+			return (ct->ct_error.re_status);
+		/* now decode and validate the response header */
+		if (! xdr_replymsg(xdrs, &reply_msg)) {
+			/*
+			 * Free some stuff allocated by xdr_replymsg()
+			 * to avoid leaks, since it may allocate
+			 * memory from partially successful decodes.
+			 */
+			enum xdr_op op = xdrs->x_op;
+			xdrs->x_op = XDR_FREE;
+			xdr_replymsg(xdrs, &reply_msg);
+			xdrs->x_op = op;
+			if (ct->ct_error.re_status == RPC_SUCCESS)
+				continue;
+			return (ct->ct_error.re_status);
+		}
+		if (reply_msg.rm_xid == x_id)
+			break;
+	}
+
+	/*
+	 * process header
+	 */
+	gssrpc__seterr_reply(&reply_msg, &(ct->ct_error));
+	if (ct->ct_error.re_status == RPC_SUCCESS) {
+		if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
+			ct->ct_error.re_status = RPC_AUTHERROR;
+			ct->ct_error.re_why = AUTH_INVALIDRESP;
+		} else if (! AUTH_UNWRAP(h->cl_auth, xdrs,
+					 xdr_results, results_ptr)) {
+			if (ct->ct_error.re_status == RPC_SUCCESS)
+				ct->ct_error.re_status = RPC_CANTDECODERES;
+		}
+	}  /* end successful completion */
+	else {
+		/* maybe our credentials need to be refreshed ... */
+		if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg))
+			goto call_again;
+	}  /* end of unsuccessful completion */
+	/* free verifier ... */
+	if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+	    (reply_msg.acpted_rply.ar_verf.oa_base != NULL)) {
+	    xdrs->x_op = XDR_FREE;
+	    (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
+	}
+	return (ct->ct_error.re_status);
+}
+
+static void
+clnttcp_geterr(
+	CLIENT *h,
+	struct rpc_err *errp)
+{
+	register struct ct_data *ct =
+	    (struct ct_data *) h->cl_private;
+
+	*errp = ct->ct_error;
+}
+
+static bool_t
+clnttcp_freeres(
+	CLIENT *cl,
+	xdrproc_t xdr_res,
+	void * res_ptr)
+{
+	register struct ct_data *ct = (struct ct_data *)cl->cl_private;
+	register XDR *xdrs = &(ct->ct_xdrs);
+
+	xdrs->x_op = XDR_FREE;
+	return ((*xdr_res)(xdrs, res_ptr));
+}
+
+/*ARGSUSED*/
+static void
+clnttcp_abort(CLIENT *cl)
+{
+}
+
+static bool_t
+clnttcp_control(
+	CLIENT *cl,
+	int request,
+	void *info)
+{
+	register struct ct_data *ct = (struct ct_data *)cl->cl_private;
+	int len;
+	
+	switch (request) {
+	case CLSET_TIMEOUT:
+		ct->ct_wait = *(struct timeval *)info;
+		ct->ct_waitset = TRUE;
+		break;
+	case CLGET_TIMEOUT:
+		*(struct timeval *)info = ct->ct_wait;
+		break;
+	case CLGET_SERVER_ADDR:
+		*(struct sockaddr_in *)info = ct->ct_addr;
+		break;
+	case CLGET_LOCAL_ADDR:
+		len = sizeof(struct sockaddr);
+		if (getsockname(ct->ct_sock, (struct sockaddr*)info, &len) < 0)
+		     return FALSE;
+		else
+		     return TRUE;
+	default:
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+
+static void
+clnttcp_destroy(CLIENT *h)
+{
+	register struct ct_data *ct =
+	    (struct ct_data *) h->cl_private;
+
+	if (ct->ct_closeit) {
+		(void)close(ct->ct_sock);
+	}
+	XDR_DESTROY(&(ct->ct_xdrs));
+	mem_free((caddr_t)ct, sizeof(struct ct_data));
+	mem_free((caddr_t)h, sizeof(CLIENT));
+}
+
+/*
+ * Interface between xdr serializer and tcp connection.
+ * Behaves like the system calls, read & write, but keeps some error state
+ * around for the rpc level.
+ */
+static int
+readtcp(
+        char *ctptr,
+	caddr_t buf,
+	register int len)
+{
+  register struct ct_data *ct = (struct ct_data *)(void *)ctptr;
+  struct timeval tout;
+#ifdef FD_SETSIZE
+	fd_set mask;
+	fd_set readfds;
+
+	if (len == 0)
+		return (0);
+	FD_ZERO(&mask);
+	FD_SET(ct->ct_sock, &mask);
+#else
+	register int mask = 1 << (ct->ct_sock);
+	int readfds;
+
+	if (len == 0)
+		return (0);
+
+#endif /* def FD_SETSIZE */
+	while (TRUE) {
+		readfds = mask;
+		tout = ct->ct_wait;
+		switch (select(gssrpc__rpc_dtablesize(), &readfds, (fd_set*)NULL, (fd_set*)NULL,
+			       &tout)) {
+		case 0:
+			ct->ct_error.re_status = RPC_TIMEDOUT;
+			return (-1);
+
+		case -1:
+			if (errno == EINTR)
+				continue;
+			ct->ct_error.re_status = RPC_CANTRECV;
+			ct->ct_error.re_errno = errno;
+			return (-1);
+		}
+		break;
+	}
+	switch (len = read(ct->ct_sock, buf, (size_t) len)) {
+
+	case 0:
+		/* premature eof */
+		ct->ct_error.re_errno = ECONNRESET;
+		ct->ct_error.re_status = RPC_CANTRECV;
+		len = -1;  /* it's really an error */
+		break;
+
+	case -1:
+		ct->ct_error.re_errno = errno;
+		ct->ct_error.re_status = RPC_CANTRECV;
+		break;
+	}
+	return (len);
+}
+
+static int
+writetcp(
+        char *ctptr,
+	caddr_t buf,
+	int len)
+{
+	struct ct_data *ct = (struct ct_data *)(void *)ctptr;
+	register int i, cnt;
+
+	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
+		if ((i = write(ct->ct_sock, buf, (size_t) cnt)) == -1) {
+			ct->ct_error.re_errno = errno;
+			ct->ct_error.re_status = RPC_CANTSEND;
+			return (-1);
+		}
+	}
+	return (len);
+}
diff --git a/mechglue/src/lib/rpc/clnt_udp.c b/mechglue/src/lib/rpc/clnt_udp.c
new file mode 100644
index 000000000..a8b59563f
--- /dev/null
+++ b/mechglue/src/lib/rpc/clnt_udp.c
@@ -0,0 +1,484 @@
+/* @(#)clnt_udp.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_udp.c, Implements a UDP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#if defined(sun)
+#include <sys/filio.h>
+#endif
+#include <netdb.h>
+#include <errno.h>
+#include <string.h>
+#include <gssrpc/pmap_clnt.h>
+#include <errno.h>
+
+
+/*
+ * UDP bases client side rpc operations
+ */
+static enum clnt_stat	clntudp_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
+				     xdrproc_t, void *, struct timeval);
+static void		clntudp_abort(CLIENT *);
+static void		clntudp_geterr(CLIENT *, struct rpc_err *);
+static bool_t		clntudp_freeres(CLIENT *, xdrproc_t, void *);
+static bool_t           clntudp_control(CLIENT *, int, void *);
+static void		clntudp_destroy(CLIENT *);
+
+static struct clnt_ops udp_ops = {
+	clntudp_call,
+	clntudp_abort,
+	clntudp_geterr,
+	clntudp_freeres,
+	clntudp_destroy,
+	clntudp_control
+};
+
+/* 
+ * Private data kept per client handle
+ */
+struct cu_data {
+	int		   cu_sock;
+	bool_t		   cu_closeit;
+	struct sockaddr_in cu_raddr;
+	int		   cu_rlen;
+	struct sockaddr_in cu_laddr;
+	int		   cu_llen;
+	struct timeval	   cu_wait;
+	struct timeval     cu_total;
+	struct rpc_err	   cu_error;
+	XDR		   cu_outxdrs;
+	u_int		   cu_xdrpos;
+	u_int		   cu_sendsz;
+	char		   *cu_outbuf;
+	u_int		   cu_recvsz;
+	char		   cu_inbuf[1];
+};
+
+/*
+ * Create a UDP based client handle.
+ * If *sockp<0, *sockp is set to a newly created UPD socket.
+ * If raddr->sin_port is 0 a binder on the remote machine
+ * is consulted for the correct port number.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is initialized to null authentication.
+ *     Caller may wish to set this something more useful.
+ *
+ * wait is the amount of time used between retransmitting a call if
+ * no response has been heard;  retransmition occurs until the actual
+ * rpc call times out.
+ *
+ * sendsz and recvsz are the maximum allowable packet sizes that can be
+ * sent and received.
+ */
+CLIENT *
+clntudp_bufcreate(
+	struct sockaddr_in *raddr,
+	rpcprog_t program,
+	rpcvers_t version,
+	struct timeval wait,
+	register int *sockp,
+	u_int sendsz,
+	u_int recvsz)
+{
+	CLIENT *cl;
+	register struct cu_data *cu = 0;
+	struct timeval now;
+	struct rpc_msg call_msg;
+
+	cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
+	if (cl == NULL) {
+		(void) fprintf(stderr, "clntudp_create: out of memory\n");
+		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+		rpc_createerr.cf_error.re_errno = errno;
+		goto fooy;
+	}
+	sendsz = ((sendsz + 3) / 4) * 4;
+	recvsz = ((recvsz + 3) / 4) * 4;
+	cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
+	if (cu == NULL) {
+		(void) fprintf(stderr, "clntudp_create: out of memory\n");
+		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+		rpc_createerr.cf_error.re_errno = errno;
+		goto fooy;
+	}
+	cu->cu_outbuf = &cu->cu_inbuf[recvsz];
+
+	(void)gettimeofday(&now, (struct timezone *)0);
+	if (raddr->sin_port == 0) {
+		u_short port;
+		if ((port =
+		    pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
+			goto fooy;
+		}
+		raddr->sin_port = htons(port);
+	}
+	cl->cl_ops = &udp_ops;
+	cl->cl_private = (caddr_t)cu;
+	cu->cu_raddr = *raddr;
+	cu->cu_rlen = sizeof (cu->cu_raddr);
+	cu->cu_wait = wait;
+	cu->cu_total.tv_sec = -1;
+	cu->cu_total.tv_usec = -1;
+	cu->cu_sendsz = sendsz;
+	cu->cu_recvsz = recvsz;
+	call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
+	call_msg.rm_direction = CALL;
+	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+	call_msg.rm_call.cb_prog = program;
+	call_msg.rm_call.cb_vers = version;
+	xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
+	    sendsz, XDR_ENCODE);
+	if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
+		goto fooy;
+	}
+	cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
+	if (*sockp < 0) {
+		int dontblock = 1;
+
+		*sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+		if (*sockp < 0) {
+			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+			rpc_createerr.cf_error.re_errno = errno;
+			goto fooy;
+		}
+		/* attempt to bind to prov port */
+		(void)bindresvport(*sockp, (struct sockaddr_in *)0);
+		/* the sockets rpc controls are non-blocking */
+		(void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
+		cu->cu_closeit = TRUE;
+	} else {
+		cu->cu_closeit = FALSE;
+	}
+	if (connect(*sockp, (struct sockaddr *)raddr, sizeof(*raddr)) < 0)
+	     goto fooy;
+	     cu->cu_llen = sizeof(cu->cu_laddr);
+	if (getsockname(*sockp, (struct sockaddr *)&cu->cu_laddr, &cu->cu_llen) < 0)
+	     goto fooy;
+	
+	cu->cu_sock = *sockp;
+	cl->cl_auth = authnone_create();
+	return (cl);
+fooy:
+	if (cu)
+		mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
+	if (cl)
+		mem_free((caddr_t)cl, sizeof(CLIENT));
+	return ((CLIENT *)NULL);
+}
+
+CLIENT *
+clntudp_create(
+	struct sockaddr_in *raddr,
+	rpcprog_t program,
+	rpcvers_t version,
+	struct timeval wait,
+	register int *sockp)
+{
+
+	return(clntudp_bufcreate(raddr, program, version, wait, sockp,
+	    UDPMSGSIZE, UDPMSGSIZE));
+}
+
+static enum clnt_stat 
+clntudp_call(
+	register CLIENT	*cl,		/* client handle */
+	rpcproc_t	proc,		/* procedure number */
+	xdrproc_t	xargs,		/* xdr routine for args */
+	void *		argsp,		/* pointer to args */
+	xdrproc_t	xresults,	/* xdr routine for results */
+	void *		resultsp,	/* pointer to results */
+	struct timeval	utimeout	/* seconds to wait before
+					 * giving up */
+	)
+{
+	register struct cu_data *cu = (struct cu_data *)cl->cl_private;
+	register XDR *xdrs;
+	register int outlen;
+	register int inlen;
+	int fromlen;
+#ifdef FD_SETSIZE
+	fd_set readfds;
+	fd_set mask;
+#else
+	int readfds;
+	register int mask;
+#endif /* def FD_SETSIZE */
+	struct sockaddr_in from;
+	struct rpc_msg reply_msg;
+	XDR reply_xdrs;
+	struct timeval time_waited, seltimeout;
+	bool_t ok;
+	int nrefreshes = 2;	/* number of times to refresh cred */
+	struct timeval timeout;
+	long procl = proc;
+
+	if (cu->cu_total.tv_usec == -1) {
+		timeout = utimeout;     /* use supplied timeout */
+	} else {
+		timeout = cu->cu_total; /* use default timeout */
+	}
+
+	time_waited.tv_sec = 0;
+	time_waited.tv_usec = 0;
+call_again:
+	xdrs = &(cu->cu_outxdrs);
+	xdrs->x_op = XDR_ENCODE;
+	XDR_SETPOS(xdrs, cu->cu_xdrpos);
+	/*
+	 * the transaction is the first thing in the out buffer
+	 */
+	(*(uint32_t *)(void *)(cu->cu_outbuf))++;
+	if ((! XDR_PUTLONG(xdrs, &procl)) ||
+	    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
+	    (! AUTH_WRAP(cl->cl_auth, xdrs, xargs, argsp)))
+		return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
+	outlen = (int)XDR_GETPOS(xdrs);
+
+send_again:
+	if (send(cu->cu_sock, cu->cu_outbuf, (u_int)outlen, 0) != outlen) {
+		cu->cu_error.re_errno = errno;
+		return (cu->cu_error.re_status = RPC_CANTSEND);
+	}
+
+	/*
+	 * Hack to provide rpc-based message passing
+	 */
+	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+		return (cu->cu_error.re_status = RPC_TIMEDOUT);
+	}
+	/*
+	 * sub-optimal code appears here because we have
+	 * some clock time to spare while the packets are in flight.
+	 * (We assume that this is actually only executed once.)
+	 */
+	reply_msg.acpted_rply.ar_verf = gssrpc__null_auth;
+	reply_msg.acpted_rply.ar_results.where = NULL;
+	reply_msg.acpted_rply.ar_results.proc = xdr_void;
+#ifdef FD_SETSIZE
+	FD_ZERO(&mask);
+	FD_SET(cu->cu_sock, &mask);
+#else
+	mask = 1 << cu->cu_sock;
+#endif /* def FD_SETSIZE */
+	for (;;) {
+		readfds = mask;
+		seltimeout = cu->cu_wait;
+		switch (select(gssrpc__rpc_dtablesize(), &readfds, (fd_set *)NULL, 
+			       (fd_set *)NULL, &seltimeout)) {
+
+		case 0:
+			time_waited.tv_sec += cu->cu_wait.tv_sec;
+			time_waited.tv_usec += cu->cu_wait.tv_usec;
+			while (time_waited.tv_usec >= 1000000) {
+				time_waited.tv_sec++;
+				time_waited.tv_usec -= 1000000;
+			}
+			if ((time_waited.tv_sec < timeout.tv_sec) ||
+				((time_waited.tv_sec == timeout.tv_sec) &&
+				(time_waited.tv_usec < timeout.tv_usec)))
+				goto send_again;	
+			return (cu->cu_error.re_status = RPC_TIMEDOUT);
+
+		/*
+		 * buggy in other cases because time_waited is not being
+		 * updated.
+		 */
+		case -1:
+			if (errno == EINTR)
+				continue;	
+			cu->cu_error.re_errno = errno;
+			return (cu->cu_error.re_status = RPC_CANTRECV);
+		}
+		do {
+			fromlen = sizeof(struct sockaddr);
+			inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
+				cu->cu_recvsz, 0,
+				(struct sockaddr *)&from, &fromlen);
+		} while (inlen < 0 && errno == EINTR);
+		if (inlen < 0) {
+			if (errno == EWOULDBLOCK)
+				continue;	
+			cu->cu_error.re_errno = errno;
+			return (cu->cu_error.re_status = RPC_CANTRECV);
+		}
+		if (inlen < sizeof(uint32_t))
+			continue;	
+		/* see if reply transaction id matches sent id */
+		if (*((uint32_t *)(void *)(cu->cu_inbuf)) != 
+		    *((uint32_t *)(void *)(cu->cu_outbuf)))
+			continue;	
+		/* we now assume we have the proper reply */
+		break;
+	}
+
+	/*
+	 * now decode and validate the response
+	 */
+	xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
+	ok = xdr_replymsg(&reply_xdrs, &reply_msg);
+	/* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
+	if (ok) {
+		gssrpc__seterr_reply(&reply_msg, &(cu->cu_error));
+		if (cu->cu_error.re_status == RPC_SUCCESS) {
+			if (! AUTH_VALIDATE(cl->cl_auth,
+				&reply_msg.acpted_rply.ar_verf)) {
+				cu->cu_error.re_status = RPC_AUTHERROR;
+				cu->cu_error.re_why = AUTH_INVALIDRESP;
+			} else if (! AUTH_UNWRAP(cl->cl_auth, &reply_xdrs,
+						 xresults, resultsp)) {
+			     if (cu->cu_error.re_status == RPC_SUCCESS)
+				  cu->cu_error.re_status = RPC_CANTDECODERES;
+			}
+		}  /* end successful completion */
+		else {
+			/* maybe our credentials need to be refreshed ... */
+			if (nrefreshes > 0 &&
+			    AUTH_REFRESH(cl->cl_auth, &reply_msg)) {
+				nrefreshes--;
+				goto call_again;
+			}
+		}  /* end of unsuccessful completion */
+		/* free verifier */
+		if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+		    (reply_msg.acpted_rply.ar_verf.oa_base != NULL)) {
+		    xdrs->x_op = XDR_FREE;
+		    (void)xdr_opaque_auth(xdrs,
+					  &(reply_msg.acpted_rply.ar_verf));
+		} 
+	}  /* end of valid reply message */
+	else {
+		/*
+		 * It's possible for xdr_replymsg() to fail partway
+		 * through its attempt to decode the result from the
+		 * server. If this happens, it will leave the reply
+		 * structure partially populated with dynamically
+		 * allocated memory. (This can happen if someone uses
+		 * clntudp_bufcreate() to create a CLIENT handle and
+		 * specifies a receive buffer size that is too small.)
+		 * This memory must be free()ed to avoid a leak.
+		 */
+		enum xdr_op op = reply_xdrs.x_op;
+		reply_xdrs.x_op = XDR_FREE;
+		xdr_replymsg(&reply_xdrs, &reply_msg);
+		reply_xdrs.x_op = op;
+		return (RPC_CANTDECODERES);
+		cu->cu_error.re_status = RPC_CANTDECODERES;
+	}
+	return (cu->cu_error.re_status);
+}
+
+static void
+clntudp_geterr(
+	CLIENT *cl,
+	struct rpc_err *errp)
+{
+	register struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+	*errp = cu->cu_error;
+}
+
+
+static bool_t
+clntudp_freeres(
+	CLIENT *cl,
+	xdrproc_t xdr_res,
+	void *res_ptr)
+{
+	register struct cu_data *cu = (struct cu_data *)cl->cl_private;
+	register XDR *xdrs = &(cu->cu_outxdrs);
+
+	xdrs->x_op = XDR_FREE;
+	return ((*xdr_res)(xdrs, res_ptr));
+}
+
+
+/*ARGSUSED*/
+static void 
+clntudp_abort(CLIENT *h)
+{
+}
+
+static bool_t
+clntudp_control(
+	CLIENT *cl,
+	int request,
+	void *info)
+{
+	register struct cu_data *cu = (struct cu_data *)cl->cl_private;
+	
+	switch (request) {
+	case CLSET_TIMEOUT:
+		cu->cu_total = *(struct timeval *)info;
+		break;
+	case CLGET_TIMEOUT:
+		*(struct timeval *)info = cu->cu_total;
+		break;
+	case CLSET_RETRY_TIMEOUT:
+		cu->cu_wait = *(struct timeval *)info;
+		break;
+	case CLGET_RETRY_TIMEOUT:
+		*(struct timeval *)info = cu->cu_wait;
+		break;
+	case CLGET_SERVER_ADDR:
+		*(struct sockaddr_in *)info = cu->cu_raddr;
+		break;
+	case CLGET_LOCAL_ADDR:
+		*(struct sockaddr_in *)info = cu->cu_laddr;
+		break;
+	default:
+		return (FALSE);
+	}
+	return (TRUE);
+}
+	
+static void
+clntudp_destroy(CLIENT *cl)
+{
+	register struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+	if (cu->cu_closeit) {
+		(void)close(cu->cu_sock);
+	}
+	XDR_DESTROY(&(cu->cu_outxdrs));
+	mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
+	mem_free((caddr_t)cl, sizeof(CLIENT));
+}
diff --git a/mechglue/src/lib/rpc/configure.in b/mechglue/src/lib/rpc/configure.in
new file mode 100644
index 000000000..30edd50b7
--- /dev/null
+++ b/mechglue/src/lib/rpc/configure.in
@@ -0,0 +1,175 @@
+K5_AC_INIT(auth_gssapi.c)
+CONFIG_RULES
+AC_CONFIG_SUBDIRS(unit-test)
+AC_CHECK_HEADERS(sys/uio.h sys/param.h)
+AC_TYPE_GETGROUPS
+### Check where struct rpcent is declared.
+#
+# This is necessary to determine:
+# 1. If /usr/include/netdb.h declares struct rpcent
+# 2. If /usr/include/rpc/netdb.h declares struct rpcent
+#
+# We have our own rpc/netdb.h, and if /usr/include/netdb.h includes
+# rpc/netdb.h, then nastiness could happen.
+#
+# Logic: If /usr/include/netdb.h declares struct rpcent, then check
+# rpc/netdb.h.  If /usr/include/rpc/netdb.h declares struct rpcent,
+# then define STRUCT_RPCENT_IN_RPC_NETDB_H, otherwise do not.  If
+# neither netdb.h nor rpc/netdb.h declares struct rpcent, then define
+# STRUCT_RPCENT_IN_RPC_NETDB_H anyway.
+#
+AC_MSG_CHECKING([where struct rpcent is declared])
+AC_TRY_COMPILE([#include <netdb.h>],
+[struct rpcent e;
+char c = e.r_name[0];
+int i = e.r_number;],
+[AC_TRY_COMPILE([#include <rpc/netdb.h>],
+[struct rpcent e;
+char c = e.r_name[0];
+int i = e.r_number;],
+[AC_MSG_RESULT([rpc/netdb.h])
+rpcent_define='#define STRUCT_RPCENT_IN_RPC_NETDB_H'],
+[AC_MSG_RESULT([netdb.h])])],
+[AC_MSG_RESULT([nowhere])
+rpcent_define='#define STRUCT_RPCENT_IN_RPC_NETDB_H'])
+AC_SUBST(rpcent_define)
+
+AC_CHECK_HEADERS(sys/select.h sys/time.h unistd.h)
+if test $ac_cv_header_sys_select_h = yes; then
+  GSSRPC__SYS_SELECT_H='#include <sys/select.h>'
+else
+  GSSRPC__SYS_SELECT_H='/* #include <sys/select.h> */'
+fi
+AC_SUBST(GSSRPC__SYS_SELECT_H)
+if test $ac_cv_header_sys_time_h = yes; then
+  GSSRPC__SYS_TIME_H='#include <sys/time.h>'
+else
+  GSSRPC__SYS_TIME_H='/* #include <sys/time.h> */'
+fi
+AC_SUBST(GSSRPC__SYS_TIME_H)
+if test $ac_cv_header_unistd_h = yes; then
+  GSSRPC__UNISTD_H='#include <unistd.h>'
+else
+  GSSRPC__UNISTD_H='/* #include <unistd.h> */'
+fi
+AC_SUBST(GSSRPC__UNISTD_H)
+
+AC_CACHE_CHECK([for MAXHOSTNAMELEN in sys/param.h],
+  [krb5_cv_header_sys_param_h_maxhostnamelen],
+  [AC_TRY_COMPILE([#include <sys/param.h>],
+    [int i = MAXHOSTNAMELEN;],
+    [krb5_cv_header_sys_param_h_maxhostnamelen=yes],
+    [krb5_cv_header_sys_param_h_maxhostnamelen=no])])
+AC_CACHE_CHECK([for MAXHOSTNAMELEN in netdb.h],
+  [krb5_cv_header_netdb_h_maxhostnamelen],
+  [AC_TRY_COMPILE([#include <netdb.h>],
+    [int i = MAXHOSTNAMELEN;],
+    [krb5_cv_header_netdb_h_maxhostnamelen=yes],
+    [krb5_cv_header_netdb_h_maxhostnamelen=no])])
+
+GSSRPC__SYS_PARAM_H='/* #include <sys/param.h> */'
+GSSRPC__NETDB_H='/* #include <netdb.h> */'
+if test $krb5_cv_header_sys_param_h_maxhostnamelen = yes; then
+  GSSRPC__SYS_PARAM_H='#include <sys/param.h>'
+else
+  if test $krb5_cv_header_netdb_h_maxhostnamelen = yes; then
+    GSSRPC__NETDB_H='#include <netdb.h>'
+  else
+    AC_MSG_WARN([can't find MAXHOSTNAMELEN definition; faking it])
+  fi
+fi
+AC_SUBST(GSSRPC__SYS_PARAM_H)
+AC_SUBST(GSSRPC__NETDB_H)
+
+AC_CACHE_CHECK([for uint32_t in sys/types.h],
+  [krb5_cv_header_sys_types_h_uint32_t],
+  [AC_TRY_COMPILE([#include <sys/types.h>],
+      [uint32_t i = 0;],
+      [krb5_cv_header_sys_types_h_uint32_t=yes],
+      [krb5_cv_header_sys_types_h_uint32_t=no])])
+AC_CACHE_CHECK([for uint32_t in stdint.h],
+  [krb5_cv_header_stdint_h_uint32_t],
+  [AC_TRY_COMPILE([#include <stdint.h>],
+      [uint32_t i = 0;],
+      [krb5_cv_header_stdint_h_uint32_t=yes],
+      [krb5_cv_header_stdint_h_uint32_t=no])])
+AC_CACHE_CHECK([for uint32_t in inttypes.h],
+  [krb5_cv_header_inttypes_h_uint32_t],
+  [AC_TRY_COMPILE([#include <inttypes.h>],
+      [uint32_t i = 0;],
+      [krb5_cv_header_inttypes_h_uint32_t=yes],
+      [krb5_cv_header_inttypes_h_uint32_t=no])])
+GSSRPC__STDINT_H='/* #include <stdint.h> */'
+GSSRPC__INTTYPES_H='/* #include <inttypes.h> */'
+GSSRPC__FAKE_UINT32='/* #undef GSSRPC__FAKE_INT32 */'
+if test $krb5_cv_header_sys_types_h_uint32_t = yes; then
+  : # already included sys/types.h
+else
+  if test $krb5_cv_header_stdint_h_uint32_t = yes; then
+    GSSRPC__STDINT_H='#include <stdint.h>'
+  else
+    if test $krb5_cv_header_inttypes_h_uint32_t = yes; then
+      GSSRPC__INTTYPES_H='#include <inttypes.h>'
+    else
+      AC_MSG_WARN([can't find a fixed-width 32-bit type anywhere; faking it])
+      GSSRPC__FAKE_UINT32='#define GSSRPC__FAKE_UINT32 1'
+    fi
+  fi
+fi
+AC_SUBST(GSSRPC__STDINT_H)
+AC_SUBST(GSSRPC__INTTYPES_H)
+AC_SUBST(GSSRPC__FAKE_UINT32)
+
+AC_CACHE_CHECK([for BSD type aliases], [krb5_cv_type_bsdaliases],
+  [AC_TRY_COMPILE(
+    [#include <sys/types.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif],
+    [u_char c;
+u_int i;
+u_long l;], [krb5_cv_type_bsdaliases=yes], [krb5_cv_type_bsdaliases=no])])
+if test $krb5_cv_type_bsdaliases = yes; then
+  GSSRPC__BSD_TYPEALIASES='/* #undef GSSRPC__BSD_TYPEALIASES */'
+else
+  GSSRPC__BSD_TYPEALIASES='#define GSSRPC__BSD_TYPEALIASES 1'
+fi
+AC_SUBST(GSSRPC__BSD_TYPEALIASES)
+
+AC_CHECK_FUNCS(strerror)
+#
+# sockaddr length field checks
+#
+AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], , ,
+  [#include <sys/types.h>
+@%:@include <netinet/in.h>])
+AC_CHECK_MEMBERS([struct sockaddr.sa_len], , ,
+  [#include <sys/types.h>
+@%:@include <sys/socket.h>])
+
+AC_MSG_CHECKING([return type of setrpcent])
+AC_CACHE_VAL(k5_cv_type_setrpcent,
+[AC_TRY_COMPILE([#include <netdb.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+extern void setrpcent();],
+[int i;], k5_cv_type_setrpcent=void, k5_cv_type_setrpcent=int)])dnl
+AC_MSG_RESULT($k5_cv_type_setrpcent)
+AC_DEFINE_UNQUOTED(SETRPCENT_TYPE, $k5_cv_type_setrpcent)
+dnl
+AC_MSG_CHECKING([return type of endrpcent])
+AC_CACHE_VAL(k5_cv_type_endrpcent,
+[AC_TRY_COMPILE([#include <netdb.h>
+#ifdef __cplusplus
+extern "C"
+#endif
+extern void endrpcent();],
+[int i;], k5_cv_type_endrpcent=void, k5_cv_type_endrpcent=int)])dnl
+AC_MSG_RESULT($k5_cv_type_endrpcent)
+AC_DEFINE_UNQUOTED(ENDRPCENT_TYPE, $k5_cv_type_endrpcent)
+DECLARE_SYS_ERRLIST
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+K5_GEN_FILE(types.h:types.hin)
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/lib/rpc/dyn.c b/mechglue/src/lib/rpc/dyn.c
new file mode 100644
index 000000000..0b5bd0f27
--- /dev/null
+++ b/mechglue/src/lib/rpc/dyn.c
@@ -0,0 +1,577 @@
+/*
+ * This file is the collected implementation of libdyn.a, the C
+ * Dynamic Object library.  It contains everything.
+ *
+ * There are no restrictions on this code; however, if you make any
+ * changes, I request that you document them so that I do not get
+ * credit or blame for your modifications.
+ *
+ * Written by Barr3y Jaspan, Student Information Processing Board (SIPB)
+ * and MIT-Project Athena, 1989.
+ *
+ * 2002-07-17 Collected full implementation into one source file for
+ *            easy inclusion into the one library still dependent on
+ *            libdyn.  Assume memmove.  Old ChangeLog appended.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dynP.h"
+
+#define HAVE_MEMMOVE 1
+
+
+/* old dyn_append.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the function DynAppend().
+ */
+
+/*
+ * Made obsolete by DynInsert, now just a convenience function.
+ */
+int DynAppend(obj, els, num)
+   DynObjectP obj;
+   DynPtr els;
+   int num;
+{
+     return DynInsert(obj, DynSize(obj), els, num);
+}
+
+
+/* old dyn_create.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the functions DynCreate() and
+ * DynDestroy().
+ */
+
+#ifndef DEFAULT_INC
+#define DEFAULT_INC	100
+#endif
+
+static int default_increment = DEFAULT_INC;
+
+DynObjectP DynCreate(el_size, inc)
+   int	el_size, inc;
+{
+     DynObjectP obj;
+
+     obj = (DynObjectP) malloc(sizeof(DynObjectRecP));
+     if (obj == NULL)
+	  return NULL;
+
+     obj->array = (DynPtr) malloc(1);
+     if (obj->array == NULL) {
+	 free(obj);
+	 return NULL;
+     }
+     obj->array[0] = '\0';
+
+     obj->el_size = el_size;
+     obj->num_el = obj->size = 0;
+     obj->debug = obj->paranoid = 0;
+     obj->inc = (inc) ? inc : default_increment;
+     obj->initzero = 0;
+
+     return obj;
+}
+
+DynObjectP DynCopy(obj)
+   DynObjectP obj;
+{
+     DynObjectP obj1;
+     
+     obj1 = (DynObjectP) malloc(sizeof(DynObjectRecP));
+     if (obj1 == NULL)
+	  return NULL;
+
+     obj1->el_size = obj->el_size;
+     obj1->num_el = obj->num_el;
+     obj1->size = obj->size;
+     obj1->inc = obj->inc;
+     obj1->debug = obj->debug;
+     obj1->paranoid = obj->paranoid;
+     obj1->initzero = obj->initzero;
+     obj1->array = (char *) malloc((size_t) (obj1->el_size * obj1->size));
+     if (obj1->array == NULL) {
+	  free(obj1);
+	  return NULL;
+     }
+     memcpy(obj1->array, obj->array, 
+	    (size_t) (obj1->el_size * obj1->size));
+
+     return obj1;
+}
+
+int DynDestroy(obj)
+     /*@only@*/DynObjectP obj;
+{
+     if (obj->paranoid) {
+	  if (obj->debug)
+	       fprintf(stderr, "dyn: destroy: zeroing %d bytes from %p.\n",
+		       obj->el_size * obj->size, obj->array);
+	  memset(obj->array, 0, (size_t) (obj->el_size * obj->size));
+     }
+     free(obj->array);
+     free(obj);
+     return DYN_OK;
+}
+
+int DynRelease(obj)
+   DynObjectP obj;
+{
+     if (obj->debug)
+	  fprintf(stderr, "dyn: release: freeing object structure.\n");
+     free(obj);
+     return DYN_OK;
+}
+
+
+/* old dyn_debug.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the function DynDebug().
+ */
+
+int DynDebug(obj, state)
+   DynObjectP obj;
+   int state;
+{
+     obj->debug = state;
+
+     fprintf(stderr, "dyn: debug: Debug state set to %d.\n", state);
+     return DYN_OK;
+}
+
+
+/* old dyn_delete.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the function DynDelete().
+ */
+
+/*
+ * Checkers!  Get away from that "hard disk erase" button!
+ *    (Stupid dog.  He almost did it to me again ...)
+ */                                 
+int DynDelete(obj, idx)
+   DynObjectP obj;
+   int idx;
+{
+     if (idx < 0) {
+	  if (obj->debug)
+	       fprintf(stderr, "dyn: delete: bad index %d\n", idx);
+	  return DYN_BADINDEX;
+     }
+     
+     if (idx >= obj->num_el) {
+	  if (obj->debug)
+	       fprintf(stderr, "dyn: delete: Highest index is %d.\n",
+		       obj->num_el);
+	  return DYN_BADINDEX;
+     }
+
+     if (idx == obj->num_el-1) {
+	  if (obj->paranoid) {
+	       if (obj->debug)
+		    fprintf(stderr, "dyn: delete: last element, zeroing.\n");
+	       memset(obj->array + idx*obj->el_size, 0, (size_t) obj->el_size);
+	  }
+	  else {
+	       if (obj->debug)
+		    fprintf(stderr, "dyn: delete: last element, punting.\n");
+	  }
+     }	  
+     else {
+	  if (obj->debug)
+	       fprintf(stderr,
+		       "dyn: delete: copying %d bytes from %p + %d to + %d.\n",
+		       obj->el_size*(obj->num_el - idx), obj->array,
+		       (idx+1)*obj->el_size, idx*obj->el_size);
+	  
+#ifdef HAVE_MEMMOVE
+	  memmove(obj->array + idx*obj->el_size,
+		  obj->array + (idx+1)*obj->el_size,
+		  (size_t) obj->el_size*(obj->num_el - idx));
+#else
+	  bcopy(obj->array + (idx+1)*obj->el_size,
+		  obj->array + idx*obj->el_size,
+		  obj->el_size*(obj->num_el - idx));
+#endif
+	  if (obj->paranoid) {
+	       if (obj->debug)
+		    fprintf(stderr,
+			    "dyn: delete: zeroing %d bytes from %p + %d\n",
+			    obj->el_size, obj->array,
+			    obj->el_size*(obj->num_el - 1));
+	       memset(obj->array + obj->el_size*(obj->num_el - 1), 0,
+		     (size_t) obj->el_size);
+	  }
+     }
+     
+     --obj->num_el;
+     
+     if (obj->debug)
+	  fprintf(stderr, "dyn: delete: done.\n");
+
+     return DYN_OK;
+}
+
+
+/* old dyn_initzero.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the function DynInitZero().
+ */
+
+int DynInitzero(obj, state)
+   DynObjectP obj;
+   int state;
+{
+     obj->initzero = state;
+
+     if (obj->debug)
+	  fprintf(stderr, "dyn: initzero: initzero set to %d.\n", state);
+     return DYN_OK;
+}
+
+
+/* old dyn_insert.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the function DynInsert().
+ */
+
+int DynInsert(obj, idx, els_in, num)
+   DynObjectP obj;
+   void *els_in;
+   int idx, num;
+{
+     DynPtr els = (DynPtr) els_in;
+     int ret;
+     
+     if (idx < 0 || idx > obj->num_el) {
+	  if (obj->debug)
+	       fprintf(stderr, "dyn: insert: index %d is not in [0,%d]\n",
+		       idx, obj->num_el);
+	  return DYN_BADINDEX;
+     }
+
+     if (num < 1) {
+	  if (obj->debug)
+	       fprintf(stderr, "dyn: insert: cannot insert %d elements\n",
+		       num);
+	  return DYN_BADVALUE;
+     }
+
+     if (obj->debug)
+	  fprintf(stderr,"dyn: insert: Moving %d bytes from %p + %d to + %d\n",
+		  (obj->num_el-idx)*obj->el_size, obj->array,
+		  obj->el_size*idx, obj->el_size*(idx+num));
+
+     if ((ret = _DynResize(obj, obj->num_el + num)) != DYN_OK)
+	  return ret;
+#ifdef HAVE_MEMMOVE
+     memmove(obj->array + obj->el_size*(idx + num),
+	     obj->array + obj->el_size*idx,
+	     (size_t) ((obj->num_el-idx)*obj->el_size));
+#else
+     bcopy(obj->array + obj->el_size*idx,
+	   obj->array + obj->el_size*(idx + num), 
+	   (obj->num_el-idx)*obj->el_size);
+#endif	     
+
+     if (obj->debug)
+	  fprintf(stderr, "dyn: insert: Copying %d bytes from %p to %p + %d\n",
+		  obj->el_size*num, els, obj->array, obj->el_size*idx);
+
+#ifdef HAVE_MEMMOVE
+     memmove(obj->array + obj->el_size*idx, els, (size_t) (obj->el_size*num));
+#else
+     bcopy(els, obj->array + obj->el_size*idx, obj->el_size*num);
+#endif     
+     obj->num_el += num;
+
+     if (obj->debug)
+	  fprintf(stderr, "dyn: insert: done.\n");
+
+     return DYN_OK;
+}
+
+
+/* old dyn_paranoid.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the function DynDebug().
+ */
+
+int DynParanoid(obj, state)
+   DynObjectP obj;
+   int state;
+{
+     obj->paranoid = state;
+
+     if (obj->debug)
+	  fprintf(stderr, "dyn: paranoid: Paranoia set to %d.\n", state);
+     return DYN_OK;
+}
+
+
+/* old dyn_put.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the functions DynGet() and DynAdd().
+ */
+
+DynPtr DynArray(obj)
+   DynObjectP obj;
+{
+     if (obj->debug)
+	  fprintf(stderr, "dyn: array: returning array pointer %p.\n",
+		  obj->array);
+
+     return obj->array;
+}
+
+DynPtr DynGet(obj, num)
+   DynObjectP obj;
+   int num;
+{
+     if (num < 0) {
+	  if (obj->debug)
+	       fprintf(stderr, "dyn: get: bad index %d\n", num);
+	  return NULL;
+     }
+     
+     if (num >= obj->num_el) {
+	  if (obj->debug)
+	       fprintf(stderr, "dyn: get: highest element is %d.\n",
+		       obj->num_el);
+	  return NULL;
+     }
+     
+     if (obj->debug)
+	  fprintf(stderr, "dyn: get: Returning address %p + %d.\n",
+		  obj->array, obj->el_size*num);
+     
+     return (DynPtr) obj->array + obj->el_size*num;
+}
+
+int DynAdd(obj, el)
+   DynObjectP obj;
+   void *el;
+{
+     int	ret;
+     
+     ret = DynPut(obj, el, obj->num_el);
+     if (ret != DYN_OK)
+	  return ret;
+
+     ++obj->num_el;
+     return ret;
+}
+
+/*
+ * WARNING!  There is a reason this function is not documented in the
+ * man page.  If DynPut used to mutate already existing elements,
+ * everything will go fine.  If it is used to add new elements
+ * directly, however, the state within the object (such as
+ * obj->num_el) will not be updated properly and many other functions
+ * in the library will lose.  Have a nice day.
+ */
+int DynPut(obj, el_in, idx)
+   DynObjectP obj;
+   void *el_in;
+   int idx;
+{
+     DynPtr el = (DynPtr) el_in;
+     int ret;
+     
+     if (obj->debug)
+	  fprintf(stderr, "dyn: put: Writing %d bytes from %p to %p + %d\n",
+		  obj->el_size, el, obj->array, idx*obj->el_size);
+
+     if ((ret = _DynResize(obj, idx)) != DYN_OK)
+	  return ret;
+
+#ifdef HAVE_MEMMOVE
+     memmove(obj->array + idx*obj->el_size, el, (size_t) obj->el_size);
+#else
+     bcopy(el, obj->array + idx*obj->el_size, obj->el_size);
+#endif     
+
+     if (obj->debug)
+	  fprintf(stderr, "dyn: put: done.\n");
+     
+     return DYN_OK;
+}
+
+
+/* old dyn_realloc.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the internal function _DynRealloc().
+ */
+
+/*
+ * Resize the array so that element req exists.
+ */
+int _DynResize(obj, req)
+   DynObjectP obj;
+   int req;
+{
+     int size;
+     
+     if (obj->size > req)
+	  return DYN_OK;
+     else if (obj->inc > 0)
+	  return _DynRealloc(obj, (req - obj->size) / obj->inc + 1);
+     else {
+	  if (obj->size == 0)
+	       size = -obj->inc;
+	  else 
+	       size = obj->size;
+	  
+	  /*@-shiftsigned@*/
+	  while (size <= req)
+	       size <<= 1;
+	  /*@=shiftsigned@*/
+
+	  return _DynRealloc(obj, size);
+     }
+}
+
+/*
+ * Resize the array by num_incs units.  If obj->inc is positive, this
+ * means make it obj->inc*num_incs elements larger.  If obj->inc is
+ * negative, this means make the array num_incs elements long.
+ * 
+ * Ideally, this function should not be called from outside the
+ * library.  However, nothing will break if it is.
+ */
+int _DynRealloc(obj, num_incs)
+   DynObjectP obj;
+   int num_incs;
+{
+     DynPtr temp;
+     int new_size_in_bytes;
+
+     if (obj->inc > 0)
+	  new_size_in_bytes = obj->el_size*(obj->size + obj->inc*num_incs);
+     else
+	  new_size_in_bytes = obj->el_size*num_incs;
+     
+     if (obj->debug)
+	  fprintf(stderr,
+		  "dyn: alloc: Increasing object by %d bytes (%d incs).\n",
+		  new_size_in_bytes - obj->el_size*obj->size,
+		  num_incs);
+     
+     temp = (DynPtr) realloc(obj->array, (size_t) new_size_in_bytes);
+     if (temp == NULL) {
+	  if (obj->debug)
+	       fprintf(stderr, "dyn: alloc: Out of memory.\n");
+	  return DYN_NOMEM;
+     }
+     else {
+	  obj->array = temp;
+	  if (obj->inc > 0)
+	       obj->size += obj->inc*num_incs;
+	  else
+	       obj->size = num_incs;
+     }
+
+     if (obj->debug)
+	  fprintf(stderr, "dyn: alloc: done.\n");
+	  
+     return DYN_OK;
+}
+
+
+/* old dyn_size.c */
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the source code for the function DynSize().
+ */
+
+int DynSize(obj)
+   DynObjectP obj;
+{
+     if (obj->debug)
+	  fprintf(stderr, "dyn: size: returning size %d.\n", obj->num_el);
+
+     return obj->num_el;
+}
+
+int DynCapacity(obj)
+   DynObjectP obj;
+{
+     if (obj->debug)
+	  fprintf(stderr, "dyn: capacity: returning cap of %d.\n", obj->size);
+
+     return obj->size;
+}
+
+/* Old change log, as it relates to source code; build system stuff
+   discarded.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* dyn.h, dynP.h: Make prototypes unconditional.  Don't define
+	P().
+
+2001-04-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* dyn.h: Lclint annotate functions.
+
+	* dyn_create.c (DynCreate): Do not assume that malloc(0) is valid
+	and returns a valid pointer. Fix memory leak if malloc fails.
+
+	* dyn_realloc.c (_DynResize): Turn off warning of shifting a
+	signed variable.
+
+Thu Nov  9 15:31:31 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* dyn_create.c (DynCopy): Arguments to memcpy were reversed. Found
+ 	while playing with lclint.
+
+2000-11-09  Ezra Peisach  <epeisach@mit.edu>
+
+	* dyn_create.c, dyn_delete.c, dyn_insert.c, dyn_put.c,
+	dyn_realloc.c: Cast arguments to malloc(), realloc(), memmove() to
+	size_t.
+
+	* dynP.h: Provide full prototypes for _DynRealloc() and _DynResize().
+
+	* dyn.h: Add prototype for DynAppend.
+
+2000-06-29  Ezra Peisach  <epeisach@mit.edu>
+
+	* dyn_insert.c, dyn_put.c: Include string.h for memmove prototype.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* dyn_create.c, dyn_delete.c, dyn_insert.c, dyn_put.c: Use %p
+	format for displaying pointers.
+
+2000-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* dyn_realloc.c: Remove unused variable.
+
+Sat Dec  6 22:50:03 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* dyn_delete.c: Include <string.h>
+
+Mon Jul 22 21:37:52 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* dyn.h: If __STDC__ is not defined, generate prototypes implying
+		functions and not variables. 
+
+Mon Jul 22 04:20:48 1996  Marc Horowitz  <marc@mit.edu>
+
+	* dyn_insert.c (DynInsert): what used to be #ifdef POSIX, should
+ 	be #ifdef HAVE_MEMMOVE
+*/
diff --git a/mechglue/src/lib/rpc/dyn.h b/mechglue/src/lib/rpc/dyn.h
new file mode 100644
index 000000000..a888b1d7b
--- /dev/null
+++ b/mechglue/src/lib/rpc/dyn.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the public header file.
+ *
+ * There are no restrictions on this code; however, if you make any
+ * changes, I request that you document them so that I do not get
+ * credit or blame for your modifications.
+ *
+ * Written by Barr3y Jaspan, Student Information Processing Board (SIPB)
+ * and MIT-Project Athena, 1989.
+ *
+ * 2002-07-17 Moved here from util/dyn; for old changes see dyn.c.
+ *            Added macros to rename exposed symbols.  For newer changes
+ *            see ChangeLog in the current directory.
+ */
+
+
+/*
+ * dyn.h -- header file to be included by programs linking against
+ * libdyn.a.
+ */
+
+#ifndef _Dyn_h
+#define _Dyn_h
+
+typedef char *DynPtr;
+typedef struct _DynObject {
+     DynPtr	array;
+     int	el_size, num_el, size, inc;
+     int	debug, paranoid, initzero;
+} DynObjectRec, *DynObject;
+
+/* Function macros */
+#define DynHigh(obj)	(DynSize(obj) - 1)
+#define DynLow(obj)	(0)
+
+/* Return status codes */
+#define DYN_OK		-1000
+#define DYN_NOMEM	-1001
+#define DYN_BADINDEX	-1002
+#define DYN_BADVALUE	-1003
+     
+#define DynCreate	gssrpcint_DynCreate
+#define DynDestroy	gssrpcint_DynDestroy
+#define DynRelease	gssrpcint_DynRelease
+#define DynAdd		gssrpcint_DynAdd
+#define DynPut		gssrpcint_DynPut
+#define DynInsert	gssrpcint_DynInsert
+#define DynGet		gssrpcint_DynGet
+#define DynArray	gssrpcint_DynArray
+#define DynSize		gssrpcint_DynSize
+#define DynCopy		gssrpcint_DynCopy
+#define DynDelete	gssrpcint_DynDelete
+#define DynDebug	gssrpcint_DynDebug
+#define DynParanoid	gssrpcint_DynParanoid
+#define DynInitzero	gssrpcint_DynInitzero
+#define DynCapacity	gssrpcint_DynCapacity
+#define DynAppend	gssrpcint_DynAppend
+
+/*@null@*//*@only@*/ DynObject DynCreate (int el_size, int inc);
+/*@null@*//*@only@*/ DynObject DynCopy (DynObject obj);
+int DynDestroy (/*@only@*/DynObject obj), DynRelease (DynObject obj);
+int DynAdd (DynObject obj, void *el);
+int DynPut (DynObject obj, void *el, int idx);
+int DynInsert (DynObject obj, int idx, /*@observer@*/void *els, int num);
+int DynDelete (DynObject obj, int idx);
+/*@dependent@*//*@null@*/ DynPtr DynGet (DynObject obj, int num);
+/*@observer@*/ DynPtr DynArray (DynObject obj);
+int DynDebug (DynObject obj, int state);
+int DynParanoid (DynObject obj, int state);
+int DynInitzero (DynObject obj, int state);
+int DynSize (DynObject obj);
+int DynCapacity (DynObject obj);
+int DynAppend (DynObject obj, DynPtr els, int num);
+
+#undef P
+
+#endif /* _Dyn_h */
+/* DO NOT ADD ANYTHING AFTER THIS #endif */
diff --git a/mechglue/src/lib/rpc/dynP.h b/mechglue/src/lib/rpc/dynP.h
new file mode 100644
index 000000000..f2e1c3e88
--- /dev/null
+++ b/mechglue/src/lib/rpc/dynP.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of libdyn.a, the C Dynamic Object library.  It
+ * contains the private header file.
+ *
+ * There are no restrictions on this code; however, if you make any
+ * changes, I request that you document them so that I do not get
+ * credit or blame for your modifications.
+ *
+ * Written by Barr3y Jaspan, Student Information Processing Board (SIPB)
+ * and MIT-Project Athena, 1989.
+ */
+
+
+/*
+ * dynP.h -- private header file included by source files for libdyn.a.
+ */
+
+#ifndef _DynP_h
+#define _DynP_h
+
+#include "dyn.h"
+#ifdef USE_DBMALLOC
+#include <sys/stdtypes.h>
+#include <malloc.h>
+#endif
+
+/*
+ * Rep invariant:
+ * 1) el_size is the number of bytes per element in the object
+ * 2) num_el is the number of elements currently in the object.  It is
+ * one higher than the highest index at which an element lives.
+ * 3) size is the number of elements the object can hold without
+ * resizing.  num_el <= index.
+ * 4) inc is a multiple of the number of elements the object grows by
+ * each time it is reallocated.
+ */
+
+typedef struct _DynObject DynObjectRecP, *DynObjectP;
+
+#define _DynRealloc	gssrpcint_DynRealloc
+#define _DynResize	gssrpcint_DynResize
+
+/* Internal functions */
+int _DynRealloc (DynObjectP obj, int req), 
+  _DynResize (DynObjectP obj, int req);
+
+#undef P
+
+#endif /* _DynP_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/mechglue/src/lib/rpc/dyntest.c b/mechglue/src/lib/rpc/dyntest.c
new file mode 100644
index 000000000..2a80b4fa9
--- /dev/null
+++ b/mechglue/src/lib/rpc/dyntest.c
@@ -0,0 +1,216 @@
+/*
+ * This file is a (rather silly) demonstration of the use of the
+ * C Dynamic Object library.  It is a also reasonably thorough test
+ * of the library (except that it only tests it with one data size).
+ *
+ * There are no restrictions on this code; however, if you make any
+ * changes, I request that you document them so that I do not get
+ * credit or blame for your modifications.
+ *
+ * Written by Barr3y Jaspan, Student Information Processing Board (SIPB)
+ * and MIT-Project Athena, 1989.
+ *
+ * 2002-07-17 Moved here from util/dyn/test.c.  Older changes described
+ *            at end of file; for newer changes see ChangeLog.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef USE_DBMALLOC
+#include <sys/stdtypes.h>
+#include <malloc.h>
+#endif
+#include <stdlib.h>
+
+#include "dyn.h"
+
+static char random_string[] = "This is a random string.";
+static char insert1[] = "This will be put at the beginning.";
+static char insert2[] = "(parenthetical remark!) ";
+static char insert3[] = "  This follows the random string.";
+
+int
+main(argc, argv)
+/*@unused@*/int argc;
+/*@unused@*/char **argv;
+{
+     /*@-exitarg@*/
+     DynObject	obj;
+     int	i, s;
+     char	d, *data;
+
+#ifdef _DEBUG_MALLOC_INC
+     union dbmalloptarg arg;
+     unsigned long hist1, hist2, o_size, c_size;
+#endif
+
+#ifdef _DEBUG_MALLOC_INC
+     arg.i = 0;
+     dbmallopt(MALLOC_ZERO, &arg);
+     dbmallopt(MALLOC_REUSE, &arg);
+
+     o_size = malloc_inuse(&hist1);
+#endif 
+
+     /*@+matchanyintegral@*/
+     obj = DynCreate(sizeof(char), -8);
+     if (! obj) {
+	  fprintf(stderr, "test: create failed.\n");
+	  exit(1);
+     }
+     
+     if(DynDebug(obj, 1) != DYN_OK) {
+	  fprintf(stderr, "test: setting paranoid failed.\n");
+	  exit(1);
+     }
+     if(DynParanoid(obj, 1) != DYN_OK) {
+	  fprintf(stderr, "test: setting paranoid failed.\n");
+	  exit(1);
+     }
+       
+
+     if ((DynGet(obj, -5) != NULL) || 
+	 (DynGet(obj, 0) != NULL) || (DynGet(obj, 1000) != NULL)) {
+	  fprintf(stderr, "test: Get did not fail when it should have.\n");
+	  exit(1);
+     }
+
+     if (DynDelete(obj, -1) != DYN_BADINDEX ||
+	 DynDelete(obj, 0) != DYN_BADINDEX ||
+	 DynDelete(obj, 100) != DYN_BADINDEX) {
+	  fprintf(stderr, "test: Delete did not fail when it should have.\n");
+	  exit(1);
+     }
+
+     printf("Size of empty object: %d\n", DynSize(obj));
+
+     for (i=0; i<14; i++) {
+	  d = (char) i;
+	  if (DynAdd(obj, &d) != DYN_OK) {
+	       fprintf(stderr, "test: Adding %d failed.\n", i);
+	       exit(1);
+	  }
+     }
+
+     if (DynAppend(obj, random_string, strlen(random_string)+1) != DYN_OK) {
+	  fprintf(stderr, "test: appending array failed.\n");
+	  exit(1);
+     }
+     
+     if (DynDelete(obj, DynHigh(obj) / 2) != DYN_OK) {
+	  fprintf(stderr, "test: deleting element failed.\n");
+	  exit(1);
+     }
+
+     if (DynDelete(obj, DynHigh(obj) * 2) == DYN_OK) {
+	  fprintf(stderr, "test: delete should have failed here.\n");
+	  exit(1);
+     }
+
+     d = '\200';
+     if (DynAdd(obj, &d) != DYN_OK) {
+	  fprintf(stderr, "test: Adding %d failed.\n", i);
+	  exit(1);
+     }
+
+     data = (char *) DynGet(obj, 0);
+     if(data == NULL) {
+	 fprintf(stderr, "test: getting object 0 failed.\n");
+	 exit(1);
+     }
+     s = DynSize(obj);
+     for (i=0; i < s; i++)
+	  printf("Element %d is %d.\n", i, (int) data[i]);
+
+     data = (char *) DynGet(obj, 13);
+     if(data == NULL) {
+	 fprintf(stderr, "test: getting element 13 failed.\n");
+	 exit(1);
+     }
+     printf("Element 13 is %d.\n", (int) *data);
+
+     data = (char *) DynGet(obj, DynSize(obj));
+     if (data) {
+	  fprintf(stderr, "DynGet did not return NULL when it should have.\n");
+	  exit(1);
+     }
+
+     data = DynGet(obj, 14);
+     if(data == NULL) {
+	 fprintf(stderr, "test: getting element 13 failed.\n");
+	 exit(1);
+     }
+     printf("This should be the random string: \"%s\"\n", data);
+
+     if (DynInsert(obj, -1, "foo", 4) != DYN_BADINDEX ||
+	 DynInsert(obj, DynSize(obj) + 1, "foo", 4) != DYN_BADINDEX ||
+	 DynInsert(obj, 0, "foo", -1) != DYN_BADVALUE) {
+	  fprintf(stderr, "DynInsert did not fail when it should have.\n");
+	  exit(1);
+     }
+
+     if (DynInsert(obj, DynSize(obj) - 2, insert3, strlen(insert3) +
+		   1) != DYN_OK) {
+	  fprintf(stderr, "DynInsert to end failed.\n");
+	  exit(1);
+     }  
+
+     if (DynInsert(obj, 19, insert2, strlen(insert2)) != DYN_OK) {
+	  fprintf(stderr, "DynInsert to middle failed.\n");
+	  exit(1);
+     }
+     
+     if (DynInsert(obj, 0, insert1, strlen(insert1)+1) != DYN_OK) {
+	  fprintf(stderr, "DynInsert to start failed.\n");
+	  exit(1);
+     }	
+
+     data = DynGet(obj, 14 + strlen(insert1) + 1);
+     if (data == NULL) {
+	  fprintf(stderr, "DynGet of 14+strelen(insert1) failed.\n");
+	  exit(1);
+
+     }
+     printf("A new random string: \"%s\"\n", data);
+
+     data = DynGet(obj, 0);
+     if (data == NULL) {
+	  fprintf(stderr, "DynGet of 0 failed.\n");
+	  exit(1);
+
+     }
+     printf("This was put at the beginning: \"%s\"\n", data);
+
+     if(DynDestroy(obj) != DYN_OK) {
+	  fprintf(stderr, "test: destroy failed.\n");
+	  exit(1);
+     }
+
+#ifdef _DEBUG_MALLOC_INC
+     c_size = malloc_inuse(&hist2);
+     if (o_size != c_size) {
+	  printf("\n\nIgnore a single unfreed malloc segment "
+		 "(stdout buffer).\n\n");
+	  malloc_list(2, hist1, hist2);
+     }
+#endif
+     
+     printf("All tests pass\n");
+
+     return 0;
+}
+
+/* Old change log, as it relates to source code; build system stuff
+   discarded.
+
+2001-04-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* test.c: Always include stdlib.h
+
+	* test.c: Check the return values of all library calls.
+
+2000-11-09  Ezra Peisach  <epeisach@mit.edu>
+
+	* test.c: Include string,h, stdlib.h.
+
+*/
diff --git a/mechglue/src/lib/rpc/get_myaddress.c b/mechglue/src/lib/rpc/get_myaddress.c
new file mode 100644
index 000000000..871c8fcb1
--- /dev/null
+++ b/mechglue/src/lib/rpc/get_myaddress.c
@@ -0,0 +1,116 @@
+/* @(#)get_myaddress.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)get_myaddress.c 1.4 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * get_myaddress.c
+ *
+ * Get client's IP address via ioctl.  This avoids using the yellowpages.
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifdef GSSAPI_KRB5
+#include <string.h>
+#include <gssrpc/types.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_prot.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <krb5.h>
+/* 
+ * don't use gethostbyname, which would invoke yellow pages
+ */
+int
+get_myaddress(struct sockaddr_in *addr)
+{
+	memset((void *) addr, 0, sizeof(*addr));
+	addr->sin_family = AF_INET;
+	addr->sin_port = htons(PMAPPORT);
+	addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	return (0);
+}
+#else /* !GSSAPI_KRB5 */
+#include <gssrpc/types.h>
+#include <gssrpc/pmap_prot.h>
+#include <sys/socket.h>
+#if defined(sun)
+#include <sys/sockio.h>
+#endif
+#include <stdio.h>
+#ifdef OSF1
+#include <net/route.h>
+#include <sys/mbuf.h>
+#endif
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+/* 
+ * don't use gethostbyname, which would invoke yellow pages
+ */
+get_myaddress(struct sockaddr_in *addr)
+{
+	int s;
+	char buf[256 * sizeof (struct ifreq)];
+	struct ifconf ifc;
+	struct ifreq ifreq, *ifr;
+	int len;
+
+	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	    perror("get_myaddress: socket");
+	    exit(1);
+	}
+	ifc.ifc_len = sizeof (buf);
+	ifc.ifc_buf = buf;
+	if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+		perror("get_myaddress: ioctl (get interface configuration)");
+		exit(1);
+	}
+	ifr = ifc.ifc_req;
+	for (len = ifc.ifc_len; len; len -= sizeof ifreq) {
+		ifreq = *ifr;
+		if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+			perror("get_myaddress: ioctl");
+			exit(1);
+		}
+		if ((ifreq.ifr_flags & IFF_UP) &&
+		    ifr->ifr_addr.sa_family == AF_INET) {
+			*addr = *((struct sockaddr_in *)&ifr->ifr_addr);
+			addr->sin_port = htons(PMAPPORT);
+			break;
+		}
+		ifr++;
+	}
+	(void) close(s);
+}
+#endif /* !GSSAPI_KRB5 */
diff --git a/mechglue/src/lib/rpc/getrpcent.c b/mechglue/src/lib/rpc/getrpcent.c
new file mode 100644
index 000000000..a91a7a5bb
--- /dev/null
+++ b/mechglue/src/lib/rpc/getrpcent.c
@@ -0,0 +1,236 @@
+/* @(#)getrpcent.c	2.2 88/07/29 4.0 RPCSRC */
+#if !defined(lint) && defined(SCCSIDS)
+static  char sccsid[] = "@(#)getrpcent.c 1.9 87/08/11  Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <gssrpc/rpc.h>
+#include <string.h>
+#include <sys/socket.h>
+
+SETRPCENT_TYPE setrpcent (int);
+ENDRPCENT_TYPE endrpcent (void);
+
+/*
+ * Internet version.
+ */
+struct rpcdata {
+	FILE	*rpcf;
+	char	*current;
+	int	currentlen;
+	int	stayopen;
+#define	MAXALIASES	35
+	char	*rpc_aliases[MAXALIASES];
+	struct	rpcent rpc;
+	char	line[BUFSIZ+1];
+	char	*domain;
+} *rpcdata;
+static struct rpcdata *get_rpcdata();
+
+static	struct rpcent *interpret();
+struct	hostent *gethostent();
+char	*inet_ntoa();
+
+static char RPCDB[] = "/etc/rpc";
+
+static struct rpcdata *
+get_rpcdata(void)
+{
+	register struct rpcdata *d = rpcdata;
+
+	if (d == 0) {
+		d = (struct rpcdata *)calloc(1, sizeof (struct rpcdata));
+		rpcdata = d;
+	}
+	return (d);
+}
+
+struct rpcent *
+getrpcbynumber(register int number)
+{
+	register struct rpcdata *d = get_rpcdata();
+	register struct rpcent *p;
+	int reason;
+	char adrstr[16], *val = NULL;
+	int vallen;
+
+	if (d == 0)
+		return (0);
+	setrpcent(0);
+	while (p = getrpcent()) {
+		if (p->r_number == number)
+			break;
+	}
+	endrpcent();
+	return (p);
+}
+
+struct rpcent *
+getrpcbyname(const char *name)
+{
+	struct rpcent *rpc;
+	char **rp;
+
+	setrpcent(0);
+	while(rpc = getrpcent()) {
+		if (strcmp(rpc->r_name, name) == 0)
+			return (rpc);
+		for (rp = rpc->r_aliases; *rp != NULL; rp++) {
+			if (strcmp(*rp, name) == 0)
+				return (rpc);
+		}
+	}
+	endrpcent();
+	return (NULL);
+}
+
+SETRPCENT_TYPE setrpcent(int f)
+{
+	register struct rpcdata *d = _rpcdata();
+
+	if (d == 0)
+		return;
+	if (d->rpcf == NULL)
+		d->rpcf = fopen(RPCDB, "r");
+	else
+		rewind(d->rpcf);
+	if (d->current)
+		free(d->current);
+	d->current = NULL;
+	d->stayopen |= f;
+}
+
+ENDRPCENT_TYPE endrpcent(void)
+{
+	register struct rpcdata *d = _rpcdata();
+
+	if (d == 0)
+		return;
+	if (d->current && !d->stayopen) {
+		free(d->current);
+		d->current = NULL;
+	}
+	if (d->rpcf && !d->stayopen) {
+		fclose(d->rpcf);
+		d->rpcf = NULL;
+	}
+}
+
+struct rpcent *
+getrpcent(void)
+{
+	struct rpcent *hp;
+	int reason;
+	char *key = NULL, *val = NULL;
+	int keylen, vallen;
+	register struct rpcdata *d = _rpcdata();
+
+	if (d == 0)
+		return(NULL);
+	if (d->rpcf == NULL && (d->rpcf = fopen(RPCDB, "r")) == NULL)
+		return (NULL);
+    if (fgets(d->line, BUFSIZ, d->rpcf) == NULL)
+		return (NULL);
+	return interpret(d->line, strlen(d->line));
+}
+
+static struct rpcent *
+interpret(char *val, int len)
+{
+	register struct rpcdata *d = _rpcdata();
+	char *p;
+	register char *cp, **q;
+
+	if (d == 0)
+		return;
+	strncpy(d->line, val, len);
+	p = d->line;
+	d->line[len] = '\n';
+	if (*p == '#')
+		return (getrpcent());
+	cp = strchr(p, '#');
+	if (cp == NULL)
+    {
+		cp = strchr(p, '\n');
+		if (cp == NULL)
+			return (getrpcent());
+	}
+	*cp = '\0';
+	cp = strchr(p, ' ');
+	if (cp == NULL)
+    {
+		cp = strchr(p, '\t');
+		if (cp == NULL)
+			return (getrpcent());
+	}
+	*cp++ = '\0';
+	/* THIS STUFF IS INTERNET SPECIFIC */
+	d->rpc.r_name = d->line;
+	while (*cp == ' ' || *cp == '\t')
+		cp++;
+	d->rpc.r_number = atoi(cp);
+	q = d->rpc.r_aliases = d->rpc_aliases;
+	cp = strchr(p, ' ');
+	if (cp != NULL)
+		*cp++ = '\0';
+	else
+    {
+		cp = strchr(p, '\t');
+		if (cp != NULL)
+			*cp++ = '\0';
+	}
+	while (cp && *cp) {
+		if (*cp == ' ' || *cp == '\t') {
+			cp++;
+			continue;
+		}
+		if (q < &(d->rpc_aliases[MAXALIASES - 1]))
+			*q++ = cp;
+		cp = strchr(p, ' ');
+		if (cp != NULL)
+			*cp++ = '\0';
+		else
+	    {
+			cp = strchr(p, '\t');
+			if (cp != NULL)
+				*cp++ = '\0';
+		}
+	}
+	*q = NULL;
+	return (&d->rpc);
+}
diff --git a/mechglue/src/lib/rpc/getrpcport.c b/mechglue/src/lib/rpc/getrpcport.c
new file mode 100644
index 000000000..4890d582c
--- /dev/null
+++ b/mechglue/src/lib/rpc/getrpcport.c
@@ -0,0 +1,65 @@
+/* @(#)getrpcport.c	2.1 88/07/29 4.0 RPCSRC */
+#if !defined(lint) && defined(SCCSIDS)
+static  char sccsid[] = "@(#)getrpcport.c 1.3 87/08/11 SMI";
+#endif
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_clnt.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
+int
+gssrpc_getrpcport(
+	char *host,
+	rpcprog_t prognum,
+	rpcvers_t versnum,
+	rpcprot_t proto)
+{
+	struct sockaddr_in addr;
+	struct hostent *hp;
+
+	if ((hp = gethostbyname(host)) == NULL)
+		return (0);
+	memset(&addr, 0, sizeof(addr));
+	memmove((char *) &addr.sin_addr, hp->h_addr, sizeof(addr.sin_addr));
+#if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+	addr.sin_len = sizeof(addr);
+#endif
+	addr.sin_family = AF_INET;
+	addr.sin_port =  0;
+	return (pmap_getport(&addr, prognum, versnum, proto));
+}
diff --git a/mechglue/src/lib/rpc/libgssrpc.exports b/mechglue/src/lib/rpc/libgssrpc.exports
new file mode 100644
index 000000000..1437b9661
--- /dev/null
+++ b/mechglue/src/lib/rpc/libgssrpc.exports
@@ -0,0 +1,141 @@
+gssrpc_auth_debug_gss
+gssrpc_auth_debug_gssapi
+gssrpc_auth_gssapi_create
+gssrpc_auth_gssapi_create_default
+gssrpc_auth_gssapi_display_status
+gssrpc_auth_gssapi_seal_seq
+gssrpc_auth_gssapi_unseal_seq
+gssrpc_auth_gssapi_unwrap_data
+gssrpc_auth_gssapi_wrap_data
+gssrpc_authgss_create
+gssrpc_authgss_create_default
+gssrpc_authgss_get_private_data
+gssrpc_authgss_service
+gssrpc_authnone_create
+gssrpc_authunix_create
+gssrpc_authunix_create_default
+gssrpc_bindresvport
+gssrpc_callrpc
+gssrpc_clnt_broadcast
+gssrpc_clnt_create
+gssrpc_clnt_pcreateerror
+gssrpc_clnt_perrno
+gssrpc_clnt_perror
+gssrpc_clnt_spcreateerror
+gssrpc_clnt_sperrno
+gssrpc_clnt_sperror
+gssrpc_clntraw_create
+gssrpc_clnttcp_create
+gssrpc_clntudp_bufcreate
+gssrpc_clntudp_create
+gssrpc_get_myaddress
+gssrpc_getrpcport
+gssrpc_log_debug
+gssrpc_log_hexdump
+gssrpc_log_status
+gssrpc_misc_debug_gss
+gssrpc_misc_debug_gssapi
+gssrpc_pmap_getmaps
+gssrpc_pmap_getport
+gssrpc_pmap_rmtcall
+gssrpc_pmap_set
+gssrpc_pmap_unset
+gssrpc_registerrpc
+gssrpc_rpc_createrr
+gssrpc_svc_auth_gss_creds
+gssrpc_svc_auth_gss_ops
+gssrpc_svc_auth_gssapi_ops
+gssrpc_svc_auth_none
+gssrpc_svc_auth_none_ops
+gssrpc_svc_debug_gss
+gssrpc_svc_debug_gssapi
+gssrpc_svc_fdset
+gssrpc_svc_fdset_init
+gssrpc_svc_getreq
+gssrpc_svc_getreqset
+gssrpc_svc_maxfd
+gssrpc_svc_register
+gssrpc_svc_run
+gssrpc_svc_sendreply
+gssrpc_svc_unregister
+gssrpc_svcauth_gss_get_principal
+gssrpc_svcauth_gss_set_log_badauth_func
+gssrpc_svcauth_gss_set_log_badverf_func
+gssrpc_svcauth_gss_set_log_miscerr_func
+gssrpc_svcauth_gss_set_svc_name
+gssrpc_svcauth_gssapi_set_log_badauth_func
+gssrpc_svcauth_gssapi_set_log_badverf_func
+gssrpc_svcauth_gssapi_set_log_miscerr_func
+gssrpc_svcauth_gssapi_set_names
+gssrpc_svcauth_gssapi_unset_names
+gssrpc_svcerr_auth
+gssrpc_svcerr_decode
+gssrpc_svcerr_noproc
+gssrpc_svcerr_noprog
+gssrpc_svcerr_progvers
+gssrpc_svcerr_systemerr
+gssrpc_svcerr_weakauth
+gssrpc_svcfd_create
+gssrpc_svcraw_create
+gssrpc_svctcp_create
+gssrpc_svcudp_bufcreate
+gssrpc_svcudp_create
+gssrpc_svcudp_enablecache
+gssrpc_xdr_accepted_reply
+gssrpc_xdr_array
+gssrpc_xdr_authgssapi_creds
+gssrpc_xdr_authgssapi_init_arg
+gssrpc_xdr_authgssapi_init_res
+gssrpc_xdr_authunix_parms
+gssrpc_xdr_bool
+gssrpc_xdr_bytes
+gssrpc_xdr_callhdr
+gssrpc_xdr_callmsg
+gssrpc_xdr_char
+gssrpc_xdr_des_block
+gssrpc_xdr_enum
+gssrpc_xdr_free
+gssrpc_xdr_gss_buf
+gssrpc_xdr_int
+gssrpc_xdr_int32
+gssrpc_xdr_long
+gssrpc_xdr_netobj
+gssrpc_xdr_opaque
+gssrpc_xdr_opaque_auth
+gssrpc_xdr_pmap
+gssrpc_xdr_pmaplist
+gssrpc_xdr_pointer
+gssrpc_xdr_reference
+gssrpc_xdr_rejected_reply
+gssrpc_xdr_replymsg
+gssrpc_xdr_rmtcall_args
+gssrpc_xdr_rmtcallres
+gssrpc_xdr_rpc_gss_buf
+gssrpc_xdr_rpc_gss_cred
+gssrpc_xdr_rpc_gss_data
+gssrpc_xdr_rpc_gss_init_args
+gssrpc_xdr_rpc_gss_init_res
+gssrpc_xdr_rpc_gss_unwrap_data
+gssrpc_xdr_rpc_gss_wrap_data
+gssrpc_xdr_short
+gssrpc_xdr_string
+gssrpc_xdr_u_char
+gssrpc_xdr_u_int
+gssrpc_xdr_u_int32
+gssrpc_xdr_u_long
+gssrpc_xdr_u_short
+gssrpc_xdr_union
+gssrpc_xdr_vector
+gssrpc_xdr_void
+gssrpc_xdr_wrapstring
+gssrpc_xdralloc_create
+gssrpc_xdralloc_getdata
+gssrpc_xdralloc_release
+gssrpc_xdrmem_create
+gssrpc_xdrrec_create
+gssrpc_xdrrec_endofrecord
+gssrpc_xdrrec_eof
+gssrpc_xdrrec_skiprecord
+gssrpc_xdrstdio_create
+gssrpc_xprt_register
+gssrpc_xprt_unregister
diff --git a/mechglue/src/lib/rpc/netdb.h b/mechglue/src/lib/rpc/netdb.h
new file mode 100644
index 000000000..69267874e
--- /dev/null
+++ b/mechglue/src/lib/rpc/netdb.h
@@ -0,0 +1,51 @@
+#ifndef RPC_NETDB_H
+#define RPC_NETDB_H
+
+/* @(#)netdb.h	2.1 88/07/29 3.9 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*	@(#)rpc.h 1.8 87/07/24 SMI	*/
+#include <gssrpc/types.h>
+/* since the gssrpc library requires that any application using it be
+built with these header files, I am making the decision that any app
+which uses the rpcent routines must use this header file, or something
+compatible (which most <netdb.h> are) --marc */
+
+/* Really belongs in <netdb.h> */
+#ifdef STRUCT_RPCENT_IN_RPC_NETDB_H
+struct rpcent {
+      char    *r_name;        /* name of server for this rpc program */
+      char    **r_aliases;    /* alias list */
+      int     r_number;       /* rpc program number */
+};
+#endif /*STRUCT_RPCENT_IN_RPC_NETDB_H*/
+
+struct rpcent *getrpcbyname(), *getrpcbynumber(), *getrpcent();
+
+#endif
diff --git a/mechglue/src/lib/rpc/pmap_clnt.c b/mechglue/src/lib/rpc/pmap_clnt.c
new file mode 100644
index 000000000..7951d2ea0
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_clnt.c
@@ -0,0 +1,115 @@
+/* @(#)pmap_clnt.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_clnt.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_prot.h>
+#include <gssrpc/pmap_clnt.h>
+
+static struct timeval timeout = { 5, 0 };
+static struct timeval tottimeout = { 60, 0 };
+
+void clnt_perror();
+
+/*
+ * Set a mapping between program,version and port.
+ * Calls the pmap service remotely to do the mapping.
+ */
+bool_t
+pmap_set(
+	rpcprog_t program,
+	rpcvers_t version,
+	rpcprot_t protocol,
+	u_int port)
+{
+	struct sockaddr_in myaddress;
+	int socket = -1;
+	register CLIENT *client;
+	struct pmap parms;
+	bool_t rslt;
+
+	get_myaddress(&myaddress);
+	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
+	    timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+	if (client == (CLIENT *)NULL)
+		return (FALSE);
+	parms.pm_prog = program;
+	parms.pm_vers = version;
+	parms.pm_prot = protocol;
+	parms.pm_port = port;
+	if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt,
+	    tottimeout) != RPC_SUCCESS) {
+		clnt_perror(client, "Cannot register service");
+		return (FALSE);
+	}
+	CLNT_DESTROY(client);
+	(void)close(socket);
+	return (rslt);
+}
+
+/*
+ * Remove the mapping between program,version and port.
+ * Calls the pmap service remotely to do the un-mapping.
+ */
+bool_t
+pmap_unset(
+	rpcprog_t program,
+	rpcvers_t version)
+{
+	struct sockaddr_in myaddress;
+	int socket = -1;
+	register CLIENT *client;
+	struct pmap parms;
+	bool_t rslt;
+
+	get_myaddress(&myaddress);
+	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
+	    timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+	if (client == (CLIENT *)NULL)
+		return (FALSE);
+	parms.pm_prog = program;
+	parms.pm_vers = version;
+	parms.pm_port = parms.pm_prot = 0;
+	CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt,
+	    tottimeout);
+	CLNT_DESTROY(client);
+	(void)close(socket);
+	return (rslt);
+}
diff --git a/mechglue/src/lib/rpc/pmap_clnt.h b/mechglue/src/lib/rpc/pmap_clnt.h
new file mode 100644
index 000000000..808306865
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_clnt.h
@@ -0,0 +1,81 @@
+/* @(#)pmap_clnt.h	2.1 88/07/29 4.0 RPCSRC; from 1.11 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * pmap_clnt.h
+ * Supplies C routines to get to portmap services.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef GSSRPC_PMAP_CLNT_H
+#define GSSRPC_PMAP_CLNT_H
+
+/*
+ * Usage:
+ *	success = pmap_set(program, version, protocol, port);
+ *	success = pmap_unset(program, version);
+ *	port = pmap_getport(address, program, version, protocol);
+ *	head = pmap_getmaps(address);
+ *	clnt_stat = pmap_rmtcall(address, program, version, procedure,
+ *		xdrargs, argsp, xdrres, resp, tout, port_ptr)
+ *		(works for udp only.) 
+ * 	clnt_stat = clnt_broadcast(program, version, procedure,
+ *		xdrargs, argsp,	xdrres, resp, eachresult)
+ *		(like pmap_rmtcall, except the call is broadcasted to all
+ *		locally connected nets.  For each valid response received,
+ *		the procedure eachresult is called.  Its form is:
+ *	done = eachresult(resp, raddr)
+ *		bool_t done;
+ *		caddr_t resp;
+ *		struct sockaddr_in raddr;
+ *		where resp points to the results of the call and raddr is the
+ *		address if the responder to the broadcast.
+ */
+
+GSSRPC__BEGIN_DECLS
+extern bool_t		pmap_set(rpcprog_t, rpcvers_t, rpcprot_t, u_int);
+extern bool_t		pmap_unset(rpcprog_t, rpcvers_t);
+extern struct pmaplist	*pmap_getmaps(struct sockaddr_in *);
+enum clnt_stat		pmap_rmtcall(struct sockaddr_in *, rpcprog_t, 
+				     rpcvers_t, rpcproc_t, xdrproc_t, 
+				     caddr_t, xdrproc_t, caddr_t, 
+				     struct timeval, rpcport_t *);
+
+typedef bool_t (*resultproc_t)(caddr_t, struct sockaddr_in *);
+
+enum clnt_stat		clnt_broadcast(rpcprog_t, rpcvers_t, rpcproc_t,
+				       xdrproc_t, caddr_t, xdrproc_t,
+				       caddr_t, resultproc_t);
+extern u_short		pmap_getport(struct sockaddr_in *, 
+				     rpcprog_t, 
+				     rpcvers_t, rpcprot_t);
+GSSRPC__END_DECLS
+#endif /* !defined(GSSRPC_PMAP_CLNT_H) */
diff --git a/mechglue/src/lib/rpc/pmap_getmaps.c b/mechglue/src/lib/rpc/pmap_getmaps.c
new file mode 100644
index 000000000..36997c22a
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_getmaps.c
@@ -0,0 +1,87 @@
+/* @(#)pmap_getmaps.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_getmap.c
+ * Client interface to pmap rpc service.
+ * contains pmap_getmaps, which is only tcp service involved
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_prot.h>
+#include <gssrpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef OSF1
+#include <net/route.h>
+#include <sys/mbuf.h>
+#endif
+#include <net/if.h>
+#include <sys/ioctl.h>
+#define NAMELEN 255
+#define MAX_BROADCAST_SIZE 1400
+
+
+/*
+ * Get a copy of the current port maps.
+ * Calls the pmap service remotely to do get the maps.
+ */
+struct pmaplist *
+pmap_getmaps(struct sockaddr_in *address)
+{
+	struct pmaplist *head = (struct pmaplist *)NULL;
+	int sock = -1;
+	struct timeval minutetimeout;
+	register CLIENT *client;
+
+	minutetimeout.tv_sec = 60;
+	minutetimeout.tv_usec = 0;
+	address->sin_port = htons(PMAPPORT);
+	client = clnttcp_create(address, PMAPPROG,
+	    PMAPVERS, &sock, 50, 500);
+	if (client != (CLIENT *)NULL) {
+		if (CLNT_CALL(client, PMAPPROC_DUMP, xdr_void, NULL, xdr_pmaplist,
+		    &head, minutetimeout) != RPC_SUCCESS) {
+			clnt_perror(client, "pmap_getmaps rpc problem");
+		}
+		CLNT_DESTROY(client);
+	}
+	(void)close(sock);
+	address->sin_port = 0;
+	return (head);
+}
diff --git a/mechglue/src/lib/rpc/pmap_getport.c b/mechglue/src/lib/rpc/pmap_getport.c
new file mode 100644
index 000000000..998a08199
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_getport.c
@@ -0,0 +1,92 @@
+/* @(#)pmap_getport.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_getport.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_prot.h>
+#include <gssrpc/pmap_clnt.h>
+#include <sys/socket.h>
+#ifdef OSF1
+#include <net/route.h>
+#include <sys/mbuf.h>
+#endif
+#include <net/if.h>
+
+static struct timeval timeout = { 5, 0 };
+static struct timeval tottimeout = { 60, 0 };
+
+/*
+ * Find the mapped port for program,version.
+ * Calls the pmap service remotely to do the lookup.
+ * Returns 0 if no map exists.
+ */
+u_short
+pmap_getport(
+	struct sockaddr_in *address,
+	rpcprog_t program,
+	rpcvers_t version,
+	rpcprot_t protocol)
+{
+	unsigned short port = 0;
+	int sock = -1;
+	register CLIENT *client;
+	struct pmap parms;
+
+	address->sin_port = htons(PMAPPORT);
+	client = clntudp_bufcreate(address, PMAPPROG,
+	    PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+	if (client != (CLIENT *)NULL) {
+		parms.pm_prog = program;
+		parms.pm_vers = version;
+		parms.pm_prot = protocol;
+		parms.pm_port = 0;  /* not needed or used */
+		if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms,
+		    xdr_u_short, &port, tottimeout) != RPC_SUCCESS){
+			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+			clnt_geterr(client, &rpc_createerr.cf_error);
+		} else if (port == 0) {
+			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+		}
+		CLNT_DESTROY(client);
+	}
+	(void)close(sock);
+	address->sin_port = 0;
+	return (port);
+}
diff --git a/mechglue/src/lib/rpc/pmap_prot.c b/mechglue/src/lib/rpc/pmap_prot.c
new file mode 100644
index 000000000..0f39f91a4
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_prot.c
@@ -0,0 +1,55 @@
+/* @(#)pmap_prot.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_prot.c
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <gssrpc/pmap_prot.h>
+
+
+bool_t
+xdr_pmap(XDR *xdrs, struct pmap *regs)
+{
+
+	if (xdr_rpcprog(xdrs, ®s->pm_prog) && 
+		xdr_rpcvers(xdrs, ®s->pm_vers) && 
+		xdr_rpcprot(xdrs, ®s->pm_prot))
+		return (xdr_rpcport(xdrs, ®s->pm_port));
+	return (FALSE);
+}
diff --git a/mechglue/src/lib/rpc/pmap_prot.h b/mechglue/src/lib/rpc/pmap_prot.h
new file mode 100644
index 000000000..8a8802b05
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_prot.h
@@ -0,0 +1,101 @@
+/* @(#)pmap_prot.h	2.1 88/07/29 4.0 RPCSRC; from 1.14 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * pmap_prot.h
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The following procedures are supported by the protocol:
+ *
+ * PMAPPROC_NULL() returns ()
+ * 	takes nothing, returns nothing
+ *
+ * PMAPPROC_SET(struct pmap) returns (bool_t)
+ * 	TRUE is success, FALSE is failure.  Registers the tuple
+ *	[prog, vers, prot, port].
+ *
+ * PMAPPROC_UNSET(struct pmap) returns (bool_t)
+ *	TRUE is success, FALSE is failure.  Un-registers pair
+ *	[prog, vers].  prot and port are ignored.
+ *
+ * PMAPPROC_GETPORT(struct pmap) returns (u_short).
+ *	0 is failure.  Otherwise returns the port number where the pair
+ *	[prog, vers] is registered.  It may lie!
+ *
+ * PMAPPROC_DUMP() RETURNS (struct pmaplist *)
+ *
+ * PMAPPROC_CALLIT(rpcprog_t, rpcvers_t, rpcproc_t, string<>)
+ * 	RETURNS (port, string<>);
+ * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs);
+ * 	Calls the procedure on the local machine.  If it is not registered,
+ *	this procedure is quite; ie it does not return error information!!!
+ *	This procedure only is supported on rpc/udp and calls via
+ *	rpc/udp.  This routine only passes null authentication parameters.
+ *	This file has no interface to xdr routines for PMAPPROC_CALLIT.
+ *
+ * The service supports remote procedure calls on udp/ip or tcp/ip socket 111.
+ */
+
+#ifndef GSSRPC_PMAP_PROT_H
+#define GSSRPC_PMAP_PROT_H
+GSSRPC__BEGIN_DECLS
+
+#define PMAPPORT		((u_short)111)
+#define PMAPPROG		((rpcprog_t)100000)
+#define PMAPVERS		((rpcvers_t)2)
+#define PMAPVERS_PROTO		((rpcprot_t)2)
+#define PMAPVERS_ORIG		((rpcvers_t)1)
+#define PMAPPROC_NULL		((rpcproc_t)0)
+#define PMAPPROC_SET		((rpcproc_t)1)
+#define PMAPPROC_UNSET		((rpcproc_t)2)
+#define PMAPPROC_GETPORT	((rpcproc_t)3)
+#define PMAPPROC_DUMP		((rpcproc_t)4)
+#define PMAPPROC_CALLIT		((rpcproc_t)5)
+
+struct pmap {
+	rpcprog_t pm_prog;
+	rpcvers_t pm_vers;
+	rpcprot_t pm_prot;
+	rpcport_t pm_port;
+};
+
+extern bool_t xdr_pmap(XDR *, struct pmap *);
+
+struct pmaplist {
+	struct pmap	pml_map;
+	struct pmaplist *pml_next;
+};
+
+extern bool_t xdr_pmaplist(XDR *, struct pmaplist **);
+
+GSSRPC__END_DECLS
+#endif /* !defined(GSSRPC_PMAP_PROT_H) */
diff --git a/mechglue/src/lib/rpc/pmap_prot2.c b/mechglue/src/lib/rpc/pmap_prot2.c
new file mode 100644
index 000000000..13dc1afb6
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_prot2.c
@@ -0,0 +1,114 @@
+/* @(#)pmap_prot2.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_prot2.c
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <gssrpc/pmap_prot.h>
+
+
+/* 
+ * What is going on with linked lists? (!)
+ * First recall the link list declaration from pmap_prot.h:
+ *
+ * struct pmaplist {
+ *	struct pmap pml_map;
+ *	struct pmaplist *pml_map;
+ * };
+ *
+ * Compare that declaration with a corresponding xdr declaration that 
+ * is (a) pointer-less, and (b) recursive:
+ *
+ * typedef union switch (bool_t) {
+ * 
+ *	case TRUE: struct {
+ *		struct pmap;
+ * 		pmaplist_t foo;
+ *	};
+ *
+ *	case FALSE: struct {};
+ * } pmaplist_t;
+ *
+ * Notice that the xdr declaration has no nxt pointer while
+ * the C declaration has no bool_t variable.  The bool_t can be
+ * interpreted as ``more data follows me''; if FALSE then nothing
+ * follows this bool_t; if TRUE then the bool_t is followed by
+ * an actual struct pmap, and then (recursively) by the 
+ * xdr union, pamplist_t.  
+ *
+ * This could be implemented via the xdr_union primitive, though this
+ * would cause a one recursive call per element in the list.  Rather than do
+ * that we can ``unwind'' the recursion
+ * into a while loop and do the union arms in-place.
+ *
+ * The head of the list is what the C programmer wishes to past around
+ * the net, yet is the data that the pointer points to which is interesting;
+ * this sounds like a job for xdr_reference!
+ */
+bool_t
+xdr_pmaplist(register XDR *xdrs, register struct pmaplist **rp)
+{
+	/*
+	 * more_elements is pre-computed in case the direction is
+	 * XDR_ENCODE or XDR_FREE.  more_elements is overwritten by
+	 * xdr_bool when the direction is XDR_DECODE.
+	 */
+	bool_t more_elements;
+	register int freeing = (xdrs->x_op == XDR_FREE);
+	register struct pmaplist **next = NULL;
+
+	while (TRUE) {
+		more_elements = (bool_t)(*rp != NULL);
+		if (! xdr_bool(xdrs, &more_elements))
+			return (FALSE);
+		if (! more_elements)
+			return (TRUE);  /* we are done */
+		/*
+		 * the unfortunate side effect of non-recursion is that in
+		 * the case of freeing we must remember the next object
+		 * before we free the current object ...
+		 */
+		if (freeing)
+			next = &((*rp)->pml_next); 
+		if (! xdr_reference(xdrs, (caddr_t *)rp,
+		    (u_int)sizeof(struct pmaplist), xdr_pmap))
+			return (FALSE);
+		rp = (freeing) ? next : &((*rp)->pml_next);
+	}
+}
diff --git a/mechglue/src/lib/rpc/pmap_rmt.c b/mechglue/src/lib/rpc/pmap_rmt.c
new file mode 100644
index 000000000..062a5e19f
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_rmt.c
@@ -0,0 +1,417 @@
+/* @(#)pmap_rmt.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_rmt.c
+ * Client interface to pmap rpc service.
+ * remote call and broadcast service
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_prot.h>
+#include <gssrpc/pmap_clnt.h>
+#include <gssrpc/pmap_rmt.h>
+#include <sys/socket.h>
+#ifdef sun
+#include <sys/sockio.h>
+#endif
+#include <stdio.h>
+#include <errno.h>
+#ifdef OSF1
+#include <net/route.h>
+#include <sys/mbuf.h>
+#endif
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#define MAX_BROADCAST_SIZE 1400
+#include <string.h>
+
+static struct timeval timeout = { 3, 0 };
+
+
+/*
+ * pmapper remote-call-service interface.
+ * This routine is used to call the pmapper remote call service
+ * which will look up a service program in the port maps, and then
+ * remotely call that routine with the given parameters.  This allows
+ * programs to do a lookup and call in one step.
+*/
+enum clnt_stat
+pmap_rmtcall(
+	struct sockaddr_in *addr,
+	rpcprog_t prog,
+	rpcvers_t vers,
+	rpcproc_t proc,
+	xdrproc_t xdrargs,
+	caddr_t argsp,
+	xdrproc_t xdrres,
+	caddr_t resp,
+	struct timeval tout,
+	rpcport_t *port_ptr)
+{
+	int sock = -1;
+	register CLIENT *client;
+	struct rmtcallargs a;
+	struct rmtcallres r;
+	enum clnt_stat stat;
+
+	addr->sin_port = htons(PMAPPORT);
+	client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock);
+	if (client != (CLIENT *)NULL) {
+		a.prog = prog;
+		a.vers = vers;
+		a.proc = proc;
+		a.args_ptr = argsp;
+		a.xdr_args = xdrargs;
+		r.port_ptr = port_ptr;
+		r.results_ptr = resp;
+		r.xdr_results = xdrres;
+		stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
+		    xdr_rmtcallres, &r, tout);
+		CLNT_DESTROY(client);
+	} else {
+		stat = RPC_FAILED;
+	}
+	(void)close(sock);
+	addr->sin_port = 0;
+	return (stat);
+}
+
+
+/*
+ * XDR remote call arguments
+ * written for XDR_ENCODE direction only
+ */
+bool_t
+xdr_rmtcall_args(
+	register XDR *xdrs,
+	register struct rmtcallargs *cap)
+{
+	u_int lenposition, argposition, position;
+
+	if (xdr_u_int32(xdrs, &(cap->prog)) &&
+	    xdr_u_int32(xdrs, &(cap->vers)) &&
+	    xdr_u_int32(xdrs, &(cap->proc))) {
+		lenposition = XDR_GETPOS(xdrs);
+		if (! xdr_u_int32(xdrs, &(cap->arglen)))
+		    return (FALSE);
+		argposition = XDR_GETPOS(xdrs);
+		if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
+		    return (FALSE);
+		position = XDR_GETPOS(xdrs);
+		cap->arglen = (uint32_t)position - (uint32_t)argposition;
+		XDR_SETPOS(xdrs, lenposition);
+		if (! xdr_u_int32(xdrs, &(cap->arglen)))
+		    return (FALSE);
+		XDR_SETPOS(xdrs, position);
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
+ * XDR remote call results
+ * written for XDR_DECODE direction only
+ */
+bool_t
+xdr_rmtcallres(
+	register XDR *xdrs,
+	register struct rmtcallres *crp)
+{
+	caddr_t port_ptr;
+
+	port_ptr = (caddr_t)(void *)crp->port_ptr;
+	if (xdr_reference(xdrs, &port_ptr, sizeof (uint32_t),
+	    xdr_u_int32) && xdr_u_int32(xdrs, &crp->resultslen)) {
+		crp->port_ptr = (uint32_t *)(void *)port_ptr;
+		return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
+	}
+	return (FALSE);
+}
+
+
+/*
+ * The following is kludged-up support for simple rpc broadcasts.
+ * Someday a large, complicated system will replace these trivial 
+ * routines which only support udp/ip .
+ */
+
+#define GIFCONF_BUFSIZE (256 * sizeof (struct ifconf))
+
+static int
+getbroadcastnets(
+	struct in_addr *addrs,
+	int sock,  /* any valid socket will do */
+	char *buf  /* why allocxate more when we can use existing... */
+	)
+{
+	struct ifconf ifc;
+        struct ifreq ifreq, *ifr;
+	struct sockaddr_in *sockin;
+        int n, i;
+
+        ifc.ifc_len = GIFCONF_BUFSIZE;
+        ifc.ifc_buf = buf;
+	memset (buf, 0, GIFCONF_BUFSIZE);
+        if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
+                perror("broadcast: ioctl (get interface configuration)");
+                return (0);
+        }
+        ifr = ifc.ifc_req;
+        for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) {
+                ifreq = *ifr;
+                if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+                        perror("broadcast: ioctl (get interface flags)");
+                        continue;
+                }
+                if ((ifreq.ifr_flags & IFF_BROADCAST) &&
+		    (ifreq.ifr_flags & IFF_UP) &&
+		    ifr->ifr_addr.sa_family == AF_INET) {
+			sockin = (struct sockaddr_in *)&ifr->ifr_addr;
+#ifdef SIOCGIFBRDADDR   /* 4.3BSD */
+			if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+				addrs[i++].s_addr = INADDR_ANY;
+#if 0 /* this is uuuuugly */
+				addrs[i++] = inet_makeaddr(inet_netof
+#if defined(hpux) || (defined(sun) && defined(__svr4__)) || defined(linux) || (defined(__osf__) && defined(__alpha__))
+							   (sockin->sin_addr),
+#else /* hpux or solaris */
+							   (sockin->sin_addr.s_addr),
+#endif				
+							   INADDR_ANY);
+#endif
+			} else {
+				addrs[i++] = ((struct sockaddr_in*)
+				  &ifreq.ifr_addr)->sin_addr;
+			}
+#else /* 4.2 BSD */
+			addrs[i++] = inet_makeaddr(inet_netof
+			  (sockin->sin_addr.s_addr), INADDR_ANY);
+#endif
+		}
+	}
+	return (i);
+}
+
+enum clnt_stat 
+clnt_broadcast(
+	rpcprog_t	prog,		/* program number */
+	rpcvers_t	vers,		/* version number */
+	rpcproc_t	proc,		/* procedure number */
+	xdrproc_t	xargs,		/* xdr routine for args */
+	caddr_t		argsp,		/* pointer to args */
+	xdrproc_t	xresults,	/* xdr routine for results */
+	caddr_t		resultsp,	/* pointer to results */
+	resultproc_t	eachresult	/* call with each result obtained */
+	)
+{
+	enum clnt_stat stat;
+	AUTH *unix_auth = authunix_create_default();
+	XDR xdr_stream;
+	register XDR *xdrs = &xdr_stream;
+	int outlen, inlen, fromlen, nets;
+	register int sock;
+	int on = 1;
+#ifdef FD_SETSIZE
+	fd_set mask;
+	fd_set readfds;
+#else
+	int readfds;
+	register int mask;
+#endif /* def FD_SETSIZE */
+	register int i;
+	bool_t done = FALSE;
+	register uint32_t xid;
+	rpcport_t port;
+	struct in_addr addrs[20];
+	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
+	struct rmtcallargs a;
+	struct rmtcallres r;
+	struct rpc_msg msg;
+	struct timeval t, t2; 
+	char outbuf[MAX_BROADCAST_SIZE];
+#ifndef MAX
+#define MAX(A,B) ((A)<(B)?(B):(A))
+#endif
+	char inbuf[MAX (UDPMSGSIZE, GIFCONF_BUFSIZE)];
+
+	/*
+	 * initialization: create a socket, a broadcast address, and
+	 * preserialize the arguments into a send buffer.
+	 */
+	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+		perror("Cannot create socket for broadcast rpc");
+		stat = RPC_CANTSEND;
+		goto done_broad;
+	}
+#ifdef SO_BROADCAST
+	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &on,
+		       sizeof (on)) < 0) {
+		perror("Cannot set socket option SO_BROADCAST");
+		stat = RPC_CANTSEND;
+		goto done_broad;
+	}
+#endif /* def SO_BROADCAST */
+#ifdef FD_SETSIZE
+	FD_ZERO(&mask);
+	FD_SET(sock, &mask);
+#else
+	mask = (1 << sock);
+#endif /* def FD_SETSIZE */
+	nets = getbroadcastnets(addrs, sock, inbuf);
+	memset(&baddr, 0, sizeof (baddr));
+	baddr.sin_family = AF_INET;
+	baddr.sin_port = htons(PMAPPORT);
+	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
+/*	baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
+	(void)gettimeofday(&t, (struct timezone *)0);
+	msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
+	t.tv_usec = 0;
+	msg.rm_direction = CALL;
+	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+	msg.rm_call.cb_prog = PMAPPROG;
+	msg.rm_call.cb_vers = PMAPVERS;
+	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
+	msg.rm_call.cb_cred = unix_auth->ah_cred;
+	msg.rm_call.cb_verf = unix_auth->ah_verf;
+	a.prog = prog;
+	a.vers = vers;
+	a.proc = proc;
+	a.xdr_args = xargs;
+	a.args_ptr = argsp;
+	r.port_ptr = &port;
+	r.xdr_results = xresults;
+	r.results_ptr = resultsp;
+	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
+	if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
+		stat = RPC_CANTENCODEARGS;
+		goto done_broad;
+	}
+	outlen = (int)xdr_getpos(xdrs);
+	xdr_destroy(xdrs);
+	/*
+	 * Basic loop: broadcast a packet and wait a while for response(s).
+	 * The response timeout grows larger per iteration.
+	 */
+	for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
+		for (i = 0; i < nets; i++) {
+			baddr.sin_addr = addrs[i];
+			if (sendto(sock, outbuf, outlen, 0,
+				(struct sockaddr *)&baddr,
+				sizeof (struct sockaddr)) != outlen) {
+				perror("Cannot send broadcast packet");
+				stat = RPC_CANTSEND;
+				goto done_broad;
+			}
+		}
+		if (eachresult == NULL) {
+			stat = RPC_SUCCESS;
+			goto done_broad;
+		}
+	recv_again:
+		msg.acpted_rply.ar_verf = gssrpc__null_auth;
+		msg.acpted_rply.ar_results.where = (caddr_t)&r;
+                msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
+		readfds = mask;
+		t2 = t;
+		switch (select(gssrpc__rpc_dtablesize(), &readfds, (fd_set *)NULL, 
+			       (fd_set *)NULL, &t2)) {
+
+		case 0:  /* timed out */
+			stat = RPC_TIMEDOUT;
+			continue;
+
+		case -1:  /* some kind of error */
+			if (errno == EINTR)
+				goto recv_again;
+			perror("Broadcast select problem");
+			stat = RPC_CANTRECV;
+			goto done_broad;
+
+		}  /* end of select results switch */
+	try_again:
+		fromlen = sizeof(struct sockaddr);
+		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
+			(struct sockaddr *)&raddr, &fromlen);
+		if (inlen < 0) {
+			if (errno == EINTR)
+				goto try_again;
+			perror("Cannot receive reply to broadcast");
+			stat = RPC_CANTRECV;
+			goto done_broad;
+		}
+		if (inlen < sizeof(uint32_t))
+			goto recv_again;
+		/*
+		 * see if reply transaction id matches sent id.
+		 * If so, decode the results.
+		 */
+		xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
+		if (xdr_replymsg(xdrs, &msg)) {
+			if ((msg.rm_xid == xid) &&
+				(msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+				(msg.acpted_rply.ar_stat == SUCCESS)) {
+				raddr.sin_port = htons((u_short)port);
+				done = (*eachresult)(resultsp, &raddr);
+			}
+			/* otherwise, we just ignore the errors ... */
+		} else {
+#ifdef notdef
+			/* some kind of deserialization problem ... */
+			if (msg.rm_xid == xid)
+				fprintf(stderr, "Broadcast deserialization problem");
+			/* otherwise, just random garbage */
+#endif
+		}
+		xdrs->x_op = XDR_FREE;
+		msg.acpted_rply.ar_results.proc = xdr_void;
+		(void)xdr_replymsg(xdrs, &msg);
+		(void)(*xresults)(xdrs, resultsp);
+		xdr_destroy(xdrs);
+		if (done) {
+			stat = RPC_SUCCESS;
+			goto done_broad;
+		} else {
+			goto recv_again;
+		}
+	}
+done_broad:
+	(void)close(sock);
+	AUTH_DESTROY(unix_auth);
+	return (stat);
+}
+
diff --git a/mechglue/src/lib/rpc/pmap_rmt.h b/mechglue/src/lib/rpc/pmap_rmt.h
new file mode 100644
index 000000000..48789b453
--- /dev/null
+++ b/mechglue/src/lib/rpc/pmap_rmt.h
@@ -0,0 +1,63 @@
+/* @(#)pmap_rmt.h	2.1 88/07/29 4.0 RPCSRC; from 1.2 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Structures and XDR routines for parameters to and replies from
+ * the portmapper remote-call-service.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+#ifndef GSSRPC_PMAP_RMT_H
+#define GSSRPC_PMAP_RMT_H
+GSSRPC__BEGIN_DECLS
+
+struct rmtcallargs {
+	rpcprog_t prog;
+	rpcvers_t vers;
+	rpcproc_t proc;
+	uint32_t arglen;
+	caddr_t args_ptr;
+	xdrproc_t xdr_args;
+};
+
+bool_t xdr_rmtcall_args(XDR *, struct rmtcallargs *);
+
+struct rmtcallres {
+	rpcport_t *port_ptr;
+	uint32_t resultslen;
+	caddr_t results_ptr;
+	xdrproc_t xdr_results;
+};
+
+bool_t xdr_rmtcallres(XDR *, struct rmtcallres *);
+
+GSSRPC__END_DECLS
+#endif /* !defined(GSSRPC_PMAP_RMT_H) */
diff --git a/mechglue/src/lib/rpc/rename.h b/mechglue/src/lib/rpc/rename.h
new file mode 100644
index 000000000..b28ae9145
--- /dev/null
+++ b/mechglue/src/lib/rpc/rename.h
@@ -0,0 +1,307 @@
+/*
+ * lib/rpc/rename.h
+ *
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Namespace mangling for various purposes.
+ *
+ * Symbols in the object code need to be renamed to not conflict with
+ * an OS-provided RPC implementation.  Without renaming, the conflicts
+ * can cause problems with things like RPC-enabled NSS
+ * implementations.
+ *
+ * Symbols in headers should not conflict with implementation-reserved
+ * namespace (prefixes "_[A-Z_]" for any purpose; prefix "_"
+ * for file scope identifiers and tag names), or unnecessarily impinge
+ * on user namespace.
+ *
+ * The renaming of the header directory is done to avoid problems when
+ * the OS header files include <rpc/foo.h> and might get ours instead.
+ * OS vendors should replace all the <gssrpc/foo.h> inclusions with
+ * <rpc/foo.h> inclusions, as appropriate.  Additionally, vendors
+ * should probably put some symbols into the implementation namespace.
+ *
+ * For example, inclusion protection should change from "GSSRPC_*_H"
+ * to "_RPC_*_H", struct tags should get "__" prefixes, etc.
+ *
+ * This implementation reserves the object code prefix "gssrpc_".
+ * External names in the RPC API not beginning with "_" get renamed
+ * with the prefix "gssrpc_" via #define, e.g., "foo" -> "gssrpc_foo".
+ * External names in the RPC API beginning with "_" get textually
+ * rewritten, with "#if 0"-disabled #defines mapping them back to
+ * their original forms, e.g., "_foo" is rewrittten to "gssrpc__foo"
+ * in the original files, with an unused "#define gssrpc__foo _foo"
+ * here.
+ */
+
+#ifndef GSSRPC_RENAME_H
+#define GSSRPC_RENAME_H
+
+/* auth.h */
+
+#define xdr_des_block		gssrpc_xdr_des_block
+
+#define authany_wrap		gssrpc_authany_wrap
+#define authany_unwrap		gssrpc_authany_unwrap
+
+#define authunix_create		gssrpc_authunix_create
+#define authunix_create_default	gssrpc_authunix_create_default
+#define authnone_create		gssrpc_authnone_create
+#define authdes_create		gssrpc_authdes_create
+#define xdr_opaque_auth		gssrpc_xdr_opaque_auth
+
+#if 0
+#define gssrpc__null_auth	_null_auth
+#endif
+
+/* auth_gss.c */
+
+#define auth_debug_gss		gssrpc_auth_debug_gss
+#define misc_debug_gss		gssrpc_misc_debug_gss
+
+/* auth_gss.h */
+
+#define xdr_rpc_gss_buf		gssrpc_xdr_rpc_gss_buf
+#define xdr_rpc_gss_cred	gssrpc_xdr_rpc_gss_cred
+#define xdr_rpc_gss_init_args	gssrpc_xdr_rpc_gss_init_args
+#define xdr_rpc_gss_init_res	gssrpc_xdr_rpc_gss_init_res
+#define xdr_rpc_gss_data	gssrpc_xdr_rpc_gss_data
+#define xdr_rpc_gss_wrap_data	gssrpc_xdr_rpc_gss_wrap_data
+#define xdr_rpc_gss_unwrap_data	gssrpc_xdr_rpc_gss_unwrap_data
+
+#define authgss_create		gssrpc_authgss_create
+#define authgss_create_default	gssrpc_authgss_create_default
+#define authgss_get_private_data	gssrpc_authgss_get_private_data
+#define authgss_service		gssrpc_authgss_service
+
+#ifdef GSSRPC__IMPL
+#define log_debug		gssrpc_log_debug
+#define log_status		gssrpc_log_status
+#define	log_hexdump		gssrpc_log_hexdump
+#endif
+
+/* auth_gssapi.c */
+
+#define auth_debug_gssapi	gssrpc_auth_debug_gssapi
+#define misc_debug_gssapi	gssrpc_misc_debug_gssapi
+
+/* auth_gssapi.h */
+
+#define xdr_gss_buf		gssrpc_xdr_gss_buf
+#define xdr_authgssapi_creds	gssrpc_xdr_authgssapi_creds
+#define xdr_authgssapi_init_arg	gssrpc_xdr_authgssapi_init_arg
+#define xdr_authgssapi_init_res	gssrpc_xdr_authgssapi_init_res
+
+#define auth_gssapi_wrap_data	gssrpc_auth_gssapi_wrap_data
+#define auth_gssapi_unwrap_data	gssrpc_auth_gssapi_unwrap_data
+#define auth_gssapi_create	gssrpc_auth_gssapi_create
+#define auth_gssapi_create_default	gssrpc_auth_gssapi_create_default
+#define auth_gssapi_display_status	gssrpc_auth_gssapi_display_status
+#define auth_gssapi_seal_seq	gssrpc_auth_gssapi_seal_seq
+#define auth_gssapi_unseal_seq	gssrpc_auth_gssapi_unseal_seq
+
+#define svcauth_gssapi_set_names	gssrpc_svcauth_gssapi_set_names
+#define svcauth_gssapi_unset_names	gssrpc_svcauth_gssapi_unset_names
+#define svcauth_gssapi_set_log_badauth_func	gssrpc_svcauth_gssapi_set_log_badauth_func
+#define svcauth_gssapi_set_log_badverf_func	gssrpc_svcauth_gssapi_set_log_badverf_func
+#define svcauth_gssapi_set_log_miscerr_func	gssrpc_svcauth_gssapi_set_log_miscerr_func
+
+#define svcauth_gss_set_log_badauth_func	gssrpc_svcauth_gss_set_log_badauth_func
+#define svcauth_gss_set_log_badverf_func	gssrpc_svcauth_gss_set_log_badverf_func
+#define svcauth_gss_set_log_miscerr_func	gssrpc_svcauth_gss_set_log_miscerr_func
+
+/* auth_unix.h */
+
+#define xdr_authunix_parms	gssrpc_xdr_authunix_parms
+
+/* clnt.h */
+
+#define clntraw_create		gssrpc_clntraw_create
+#define clnt_create		gssrpc_clnt_create
+#define clnttcp_create		gssrpc_clnttcp_create
+#define clntudp_create		gssrpc_clntudp_create
+#define clntudp_bufcreate	gssrpc_clntudp_bufcreate
+#define clnt_pcreateerror	gssrpc_clnt_pcreateerror
+#define clnt_spcreateerror	gssrpc_clnt_spcreateerror
+#define clnt_perrno		gssrpc_clnt_perrno
+#define clnt_perror		gssrpc_clnt_perror
+#define clnt_sperror		gssrpc_clnt_sperror
+/* XXX do we need to rename the struct? */
+#define rpc_createerr		gssrpc_rpc_createrr
+#define clnt_sperrno		gssrpc_clnt_sperrno
+
+/* pmap_clnt.h */
+
+#define pmap_set		gssrpc_pmap_set
+#define pmap_unset		gssrpc_pmap_unset
+#define pmap_getmaps		gssrpc_pmap_getmaps
+#define pmap_rmtcall		gssrpc_pmap_rmtcall
+#define clnt_broadcast		gssrpc_clnt_broadcast
+#define pmap_getport		gssrpc_pmap_getport
+
+/* pmap_prot.h */
+
+#define xdr_pmap		gssrpc_xdr_pmap
+#define xdr_pmaplist		gssrpc_xdr_pmaplist
+
+/* pmap_rmt.h */
+
+#define xdr_rmtcall_args	gssrpc_xdr_rmtcall_args
+#define xdr_rmtcallres		gssrpc_xdr_rmtcallres
+
+/* rpc.h */
+
+#define get_myaddress		gssrpc_get_myaddress
+#define bindresvport		gssrpc_bindresvport
+#define callrpc			gssrpc_callrpc
+#define getrpcport		gssrpc_getrpcport
+
+#if 0
+#define gssrpc__rpc_getdtablesize	_rpc_getdtablesize
+#endif
+
+/* rpc_msg.h */
+
+#define xdr_callmsg		gssrpc_xdr_callmsg
+#define xdr_callhdr		gssrpc_xdr_callhdr
+#define xdr_replymsg		gssrpc_xdr_replymsg
+#define xdr_accepted_reply	gssrpc_xdr_accepted_reply
+#define xdr_rejected_reply	gssrpc_xdr_rejected_reply
+
+#if 0
+#define gssrpc__seterr_reply	_seterr_reply
+#endif
+
+/* svc.h */
+
+#define svc_register		gssrpc_svc_register
+#define registerrpc             gssrpc_registerrpc
+#define svc_unregister		gssrpc_svc_unregister
+#define xprt_register		gssrpc_xprt_register
+#define xprt_unregister		gssrpc_xprt_unregister
+
+#define svc_sendreply		gssrpc_svc_sendreply
+#define svcerr_decode		gssrpc_svcerr_decode
+#define svcerr_weakauth		gssrpc_svcerr_weakauth
+#define svcerr_noproc		gssrpc_svcerr_noproc
+#define svcerr_progvers		gssrpc_svcerr_progvers
+#define svcerr_auth		gssrpc_svcerr_auth
+#define svcerr_noprog		gssrpc_svcerr_noprog
+#define svcerr_systemerr	gssrpc_svcerr_systemerr
+
+#define svc_maxfd		gssrpc_svc_maxfd
+#define svc_fdset		gssrpc_svc_fdset
+#define svc_fds			gssrpc_svc_fds
+
+#define rpctest_service		gssrpc_rpctest_service
+
+#define svc_getreq		gssrpc_svc_getreq
+#define svc_getreqset		gssrpc_svc_getreqset
+#define svc_getreqset2		gssrpc_svc_getreqset2
+#define svc_run			gssrpc_svc_run
+
+#define svcraw_create		gssrpc_svcraw_create
+
+#define svcudp_create		gssrpc_svcudp_create
+#define svcudp_bufcreate	gssrpc_svcudp_bufcreate
+#define svcudp_enablecache	gssrpc_svcudp_enablecache
+
+#define svctcp_create		gssrpc_svctcp_create
+
+#define svcfd_create            gssrpc_svcfd_create
+
+/* svc_auth.h */
+
+#define svc_auth_none_ops	gssrpc_svc_auth_none_ops
+#define svc_auth_gssapi_ops	gssrpc_svc_auth_gssapi_ops
+#define svc_auth_gss_ops	gssrpc_svc_auth_gss_ops
+
+#define svcauth_gss_set_svc_name	gssrpc_svcauth_gss_set_svc_name
+#define svcauth_gss_get_principal	gssrpc_svcauth_gss_get_principal
+
+#if 0
+#define gssrpc__authenticate	_authenticate
+#define gssrpc__svcauth_none	_svcauth_none
+#define gssrpc__svcauth_unix	_svcauth_unix
+#define gssrpc__svcauth_short	_svcauth_short
+#define gssrpc__svcauth_gssapi	_svcauth_gssapi
+#define gssrpc__svcauth_gss	_svcauth_gss
+#endif
+
+/* svc_auth_gss.c */
+
+#define svc_debug_gss		gssrpc_svc_debug_gss
+
+#define svcauth_gss_creds	gssrpc_svc_auth_gss_creds
+
+/* svc_auth_gssapi.c */
+
+#define svc_debug_gssapi	gssrpc_svc_debug_gssapi
+
+/* svc_auth_none.c */
+
+#define svc_auth_none		gssrpc_svc_auth_none
+
+/* xdr.h */
+
+#define xdr_void	gssrpc_xdr_void
+#define xdr_int		gssrpc_xdr_int
+#define xdr_u_int	gssrpc_xdr_u_int
+#define xdr_long	gssrpc_xdr_long
+#define xdr_u_long	gssrpc_xdr_u_long
+#define xdr_short	gssrpc_xdr_short
+#define xdr_u_short	gssrpc_xdr_u_short
+#define xdr_bool	gssrpc_xdr_bool
+#define xdr_enum	gssrpc_xdr_enum
+#define xdr_array	gssrpc_xdr_array
+#define xdr_bytes	gssrpc_xdr_bytes
+#define xdr_opaque	gssrpc_xdr_opaque
+#define xdr_string	gssrpc_xdr_string
+#define xdr_union	gssrpc_xdr_union
+#define xdr_char	gssrpc_xdr_char
+#define xdr_u_char	gssrpc_xdr_u_char
+#define xdr_vector	gssrpc_xdr_vector
+#define xdr_float	gssrpc_xdr_float
+#define xdr_double	gssrpc_xdr_double
+#define xdr_reference	gssrpc_xdr_reference
+#define xdr_pointer	gssrpc_xdr_pointer
+#define xdr_wrapstring	gssrpc_xdr_wrapstring
+#define xdr_free	gssrpc_xdr_free
+
+#define xdr_netobj	gssrpc_xdr_netobj
+#define xdr_int32	gssrpc_xdr_int32
+#define xdr_u_int32	gssrpc_xdr_u_int32
+
+#define xdralloc_create		gssrpc_xdralloc_create
+#define xdralloc_release	gssrpc_xdralloc_release
+#define xdralloc_getdata	gssrpc_xdralloc_getdata
+
+#define xdrmem_create		gssrpc_xdrmem_create
+#define xdrstdio_create		gssrpc_xdrstdio_create
+#define xdrrec_create		gssrpc_xdrrec_create
+#define xdrrec_endofrecord	gssrpc_xdrrec_endofrecord
+#define xdrrec_skiprecord	gssrpc_xdrrec_skiprecord
+#define xdrrec_eof		gssrpc_xdrrec_eof
+
+#endif /* !defined(GSSRPC_RENAME_H) */
diff --git a/mechglue/src/lib/rpc/rpc.h b/mechglue/src/lib/rpc/rpc.h
new file mode 100644
index 000000000..0f1730d18
--- /dev/null
+++ b/mechglue/src/lib/rpc/rpc.h
@@ -0,0 +1,99 @@
+/* @(#)rpc.h	2.3 88/08/10 4.0 RPCSRC; from 1.9 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * rpc.h, Just includes the billions of rpc header files necessary to
+ * do remote procedure calling.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+#ifndef GSSRPC_RPC_H
+#define GSSRPC_RPC_H
+
+#include <gssrpc/types.h>		/* some typedefs */
+#include <netinet/in.h>
+
+/* external data representation interfaces */
+#include <gssrpc/xdr.h>		/* generic (de)serializer */
+
+/* Client side only authentication */
+#include <gssrpc/auth.h>		/* generic authenticator (client side) */
+
+/* Client side (mostly) remote procedure call */
+#include <gssrpc/clnt.h>		/* generic rpc stuff */
+
+/* semi-private protocol headers */
+#include <gssrpc/rpc_msg.h>	/* protocol for rpc messages */
+#include <gssrpc/auth_unix.h>	/* protocol for unix style cred */
+#include <gssrpc/auth_gss.h>	/* RPCSEC_GSS */
+/*
+ *  Uncomment-out the next line if you are building the rpc library with    
+ *  DES Authentication (see the README file in the secure_rpc/ directory).
+ */
+#if 0
+#include <gssrpc/auth_des.h>	protocol for des style cred
+#endif
+
+/* Server side only remote procedure callee */
+#include <gssrpc/svc_auth.h>	/* service side authenticator */
+#include <gssrpc/svc.h>		/* service manager and multiplexer */
+
+/*
+ * Punt the rpc/netdb.h everywhere because it just makes things much more
+ * difficult.  We don't use the *rpcent functions anyway.
+ */
+#if 0
+/*
+ * COMMENT OUT THE NEXT INCLUDE IF RUNNING ON SUN OS OR ON A VERSION
+ * OF UNIX BASED ON NFSSRC.  These systems will already have the structures
+ * defined by <rpc/netdb.h> included in <netdb.h>.
+ */
+/* routines for parsing /etc/rpc */
+#if 0 /* netdb.h already included in rpc/types.h */
+#include <netdb.h>
+#endif
+
+#include <gssrpc/netdb.h>	/* structures and routines to parse /etc/rpc */
+#endif
+
+/*
+ * get the local host's IP address without consulting
+ * name service library functions
+ */
+GSSRPC__BEGIN_DECLS
+extern int get_myaddress(struct sockaddr_in *);
+extern int bindresvport(int, struct sockaddr_in *);
+extern int callrpc(char *, rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
+		   char *, xdrproc_t , char *);
+extern int getrpcport(char *, rpcprog_t, rpcvers_t, rpcprot_t);
+extern int gssrpc__rpc_dtablesize(void);
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_RPC_H) */
diff --git a/mechglue/src/lib/rpc/rpc_callmsg.c b/mechglue/src/lib/rpc/rpc_callmsg.c
new file mode 100644
index 000000000..2e4789abb
--- /dev/null
+++ b/mechglue/src/lib/rpc/rpc_callmsg.c
@@ -0,0 +1,194 @@
+/* @(#)rpc_callmsg.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * rpc_callmsg.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+
+#include <sys/param.h>
+#include <string.h>
+#include <gssrpc/rpc.h>
+
+/*
+ * XDR a call message
+ */
+bool_t
+xdr_callmsg(register XDR *xdrs, register struct rpc_msg *cmsg)
+{
+	register rpc_inline_t *buf;
+	register struct opaque_auth *oa;
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) {
+			return (FALSE);
+		}
+		if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) {
+			return (FALSE);
+		}
+		buf = (rpc_inline_t *) XDR_INLINE(xdrs, (int) (
+		        8 * BYTES_PER_XDR_UNIT
+			+ RNDUP(cmsg->rm_call.cb_cred.oa_length)
+			+ 2 * BYTES_PER_XDR_UNIT
+			+ RNDUP(cmsg->rm_call.cb_verf.oa_length)));
+		if (buf != NULL) {
+			IXDR_PUT_LONG(buf, cmsg->rm_xid);
+			IXDR_PUT_ENUM(buf, cmsg->rm_direction);
+			if (cmsg->rm_direction != CALL) {
+				return (FALSE);
+			}
+			IXDR_PUT_LONG(buf, cmsg->rm_call.cb_rpcvers);
+			if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
+				return (FALSE);
+			}
+			IXDR_PUT_LONG(buf, cmsg->rm_call.cb_prog);
+			IXDR_PUT_LONG(buf, cmsg->rm_call.cb_vers);
+			IXDR_PUT_LONG(buf, cmsg->rm_call.cb_proc);
+			oa = &cmsg->rm_call.cb_cred;
+			IXDR_PUT_ENUM(buf, oa->oa_flavor);
+			IXDR_PUT_LONG(buf, oa->oa_length);
+			if (oa->oa_length) {
+				memmove((caddr_t)buf, oa->oa_base,
+					oa->oa_length);
+				buf += RNDUP(oa->oa_length) / BYTES_PER_XDR_UNIT;
+			}
+			oa = &cmsg->rm_call.cb_verf;
+			IXDR_PUT_ENUM(buf, oa->oa_flavor);
+			IXDR_PUT_LONG(buf, oa->oa_length);
+			if (oa->oa_length) {
+				memmove((caddr_t)buf, oa->oa_base,
+					oa->oa_length);
+				/* no real need....
+				buf += RNDUP(oa->oa_length) / BYTES_PER_XDR_UNIT;
+				*/
+			}
+			return (TRUE);
+		}
+	}
+	if (xdrs->x_op == XDR_DECODE) {
+		buf = (rpc_inline_t *) XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
+		if (buf != NULL) {
+			cmsg->rm_xid = IXDR_GET_LONG(buf);
+			cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
+			if (cmsg->rm_direction != CALL) {
+				return (FALSE);
+			}
+			cmsg->rm_call.cb_rpcvers = IXDR_GET_LONG(buf);
+			if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
+				return (FALSE);
+			}
+			cmsg->rm_call.cb_prog = IXDR_GET_LONG(buf);
+			cmsg->rm_call.cb_vers = IXDR_GET_LONG(buf);
+			cmsg->rm_call.cb_proc = IXDR_GET_LONG(buf);
+			oa = &cmsg->rm_call.cb_cred;
+			oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
+			oa->oa_length = IXDR_GET_LONG(buf);
+			if (oa->oa_length) {
+				if (oa->oa_length > MAX_AUTH_BYTES) {
+					return (FALSE);
+				}
+				if (oa->oa_base == NULL) {
+					oa->oa_base = (caddr_t)
+						mem_alloc(oa->oa_length);
+				}
+				buf = (rpc_inline_t *)
+				   XDR_INLINE(xdrs, (int)RNDUP(oa->oa_length));
+				if (buf == NULL) {
+					if (xdr_opaque(xdrs, oa->oa_base,
+					    oa->oa_length) == FALSE) {
+						return (FALSE);
+					}
+				} else {
+					memmove(oa->oa_base, (caddr_t)buf, 
+						oa->oa_length);
+					/* no real need....
+					buf += RNDUP(oa->oa_length) /
+						BYTES_PER_XDR_UNIT;
+					*/
+				}
+			}
+			oa = &cmsg->rm_call.cb_verf;
+			buf = (rpc_inline_t *)
+			   XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
+			if (buf == NULL) {
+				if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
+				    xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
+					return (FALSE);
+				}
+			} else {
+				oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
+				oa->oa_length = IXDR_GET_LONG(buf);
+			}
+			if (oa->oa_length) {
+				if (oa->oa_length > MAX_AUTH_BYTES) {
+					return (FALSE);
+				}
+				if (oa->oa_base == NULL) {
+					oa->oa_base = (caddr_t)
+						mem_alloc(oa->oa_length);
+				}
+				buf = (rpc_inline_t *)
+				   XDR_INLINE(xdrs, (int)RNDUP(oa->oa_length));
+				if (buf == NULL) {
+					if (xdr_opaque(xdrs, oa->oa_base,
+					    oa->oa_length) == FALSE) {
+						return (FALSE);
+					}
+				} else {
+					memmove(oa->oa_base, (caddr_t) buf, 
+					    oa->oa_length);
+					/* no real need...
+					buf += RNDUP(oa->oa_length) /
+						BYTES_PER_XDR_UNIT;
+					*/
+				}
+			}
+			return (TRUE);
+		}
+	}
+	if (
+	    xdr_u_int32(xdrs, &(cmsg->rm_xid)) &&
+	    xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
+	    (cmsg->rm_direction == CALL) &&
+	    xdr_u_int32(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+	    (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
+	    xdr_u_int32(xdrs, &(cmsg->rm_call.cb_prog)) &&
+	    xdr_u_int32(xdrs, &(cmsg->rm_call.cb_vers)) &&
+	    xdr_u_int32(xdrs, &(cmsg->rm_call.cb_proc)) &&
+	    xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) )
+	    return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf)));
+	return (FALSE);
+}
+
diff --git a/mechglue/src/lib/rpc/rpc_commondata.c b/mechglue/src/lib/rpc/rpc_commondata.c
new file mode 100644
index 000000000..882b6a4ea
--- /dev/null
+++ b/mechglue/src/lib/rpc/rpc_commondata.c
@@ -0,0 +1,47 @@
+/* @(#)rpc_commondata.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#include <gssrpc/rpc.h>
+/*
+ * This file should only contain common data (global data) that is exported
+ * by public interfaces.
+ *
+ * Actually initialized to prevent creation of common blocks, which
+ * can be problematic on some architectures.
+ */
+/* RENAMED: should be _null_auth */
+struct opaque_auth gssrpc__null_auth = {0};
+#ifdef FD_SETSIZE
+fd_set svc_fdset; /* Will be zeroed in data segment */
+int gssrpc_svc_fdset_init = 0;
+#else
+int svc_fds = 0;
+#endif /* def FD_SETSIZE */
+struct rpc_createerr rpc_createerr = {RPC_SUCCESS};
+int svc_maxfd = -1;
diff --git a/mechglue/src/lib/rpc/rpc_dtablesize.c b/mechglue/src/lib/rpc/rpc_dtablesize.c
new file mode 100644
index 000000000..c7d23296f
--- /dev/null
+++ b/mechglue/src/lib/rpc/rpc_dtablesize.c
@@ -0,0 +1,62 @@
+/* @(#)rpc_dtablesize.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro";
+#endif
+
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+
+/*
+ * Cache the result of getdtablesize(), so we don't have to do an
+ * expensive system call every time.
+ */
+int 
+gssrpc__rpc_dtablesize(void)
+{
+	static int size;
+	
+	if (size == 0) {
+#ifdef _SC_OPEN_MAX
+	    size = (int) sysconf(_SC_OPEN_MAX);
+#else	    
+	    size = getdtablesize();
+#endif	    
+
+/* sysconf() can return a number larger than what will fit in an
+   fd_set.  we can't use fd's larger than this, anyway. */
+
+#ifdef FD_SETSIZE
+	    if (size >= FD_SETSIZE)
+		size = FD_SETSIZE-1;
+#endif
+	}
+	return (size);
+}
diff --git a/mechglue/src/lib/rpc/rpc_msg.h b/mechglue/src/lib/rpc/rpc_msg.h
new file mode 100644
index 000000000..62d632967
--- /dev/null
+++ b/mechglue/src/lib/rpc/rpc_msg.h
@@ -0,0 +1,205 @@
+/* @(#)rpc_msg.h	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)rpc_msg.h 1.7 86/07/16 SMI      */
+
+/*
+ * rpc_msg.h
+ * rpc message definition
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef GSSRPC_RPC_MSG_H
+#define GSSRPC_RPC_MSG_H
+
+GSSRPC__BEGIN_DECLS
+
+#define RPC_MSG_VERSION		((uint32_t) 2)
+#define RPC_SERVICE_PORT	((u_short) 2048)
+
+/*
+ * Bottom up definition of an rpc message.
+ * NOTE: call and reply use the same overall stuct but
+ * different parts of unions within it.
+ */
+
+enum msg_type {
+	CALL=0,
+	REPLY=1
+};
+
+enum reply_stat {
+	MSG_ACCEPTED=0,
+	MSG_DENIED=1
+};
+
+enum accept_stat {
+	SUCCESS=0,
+	PROG_UNAVAIL=1,
+	PROG_MISMATCH=2,
+	PROC_UNAVAIL=3,
+	GARBAGE_ARGS=4,
+	SYSTEM_ERR=5
+};
+
+enum reject_stat {
+	RPC_MISMATCH=0,
+	AUTH_ERROR=1
+};
+
+/*
+ * Reply part of an rpc exchange
+ */
+
+/*
+ * Reply to an rpc request that was accepted by the server.
+ * Note: there could be an error even though the request was
+ * accepted.
+ */
+struct accepted_reply {
+	struct opaque_auth	ar_verf;
+	enum accept_stat	ar_stat;
+	union {
+		struct {
+			rpcvers_t	low;
+			rpcvers_t	high;
+		} AR_versions;
+		struct {
+			caddr_t	where;
+			xdrproc_t proc;
+		} AR_results;
+		/* and many other null cases */
+	} ru;
+#define	ar_results	ru.AR_results
+#define	ar_vers		ru.AR_versions
+};
+
+/*
+ * Reply to an rpc request that was rejected by the server.
+ */
+struct rejected_reply {
+	enum reject_stat rj_stat;
+	union {
+		struct {
+			rpcvers_t low;
+			rpcvers_t high;
+		} RJ_versions;
+		enum auth_stat RJ_why;  /* why authentication did not work */
+	} ru;
+#define	rj_vers	ru.RJ_versions
+#define	rj_why	ru.RJ_why
+};
+
+/*
+ * Body of a reply to an rpc request.
+ */
+struct reply_body {
+	enum reply_stat rp_stat;
+	union {
+		struct accepted_reply RP_ar;
+		struct rejected_reply RP_dr;
+	} ru;
+#define	rp_acpt	ru.RP_ar
+#define	rp_rjct	ru.RP_dr
+};
+
+/*
+ * Body of an rpc request call.
+ */
+struct call_body {
+	rpcvers_t cb_rpcvers;	/* must be equal to two */
+	rpcprog_t cb_prog;
+	rpcvers_t cb_vers;
+	rpcproc_t cb_proc;
+	struct opaque_auth cb_cred;
+	struct opaque_auth cb_verf; /* protocol specific - provided by client */
+};
+
+/*
+ * The rpc message
+ */
+struct rpc_msg {
+	uint32_t		rm_xid;
+	enum msg_type		rm_direction;
+	union {
+		struct call_body RM_cmb;
+		struct reply_body RM_rmb;
+	} ru;
+#define	rm_call		ru.RM_cmb
+#define	rm_reply	ru.RM_rmb
+};
+#define	acpted_rply	ru.RM_rmb.ru.RP_ar
+#define	rjcted_rply	ru.RM_rmb.ru.RP_dr
+
+
+/*
+ * XDR routine to handle a rpc message.
+ * xdr_callmsg(xdrs, cmsg)
+ * 	XDR *xdrs;
+ * 	struct rpc_msg *cmsg;
+ */
+extern bool_t	xdr_callmsg(XDR *, struct rpc_msg *);
+
+/*
+ * XDR routine to pre-serialize the static part of a rpc message.
+ * xdr_callhdr(xdrs, cmsg)
+ * 	XDR *xdrs;
+ * 	struct rpc_msg *cmsg;
+ */
+extern bool_t	xdr_callhdr(XDR *, struct rpc_msg *);
+
+/*
+ * XDR routine to handle a rpc reply.
+ * xdr_replymsg(xdrs, rmsg)
+ * 	XDR *xdrs;
+ * 	struct rpc_msg *rmsg;
+ */
+extern bool_t	xdr_replymsg(XDR *, struct rpc_msg *);
+
+/*
+ * Fills in the error part of a reply message.
+ * _seterr_reply(msg, error)
+ * 	struct rpc_msg *msg;
+ * 	struct rpc_err *error;
+ */
+/*
+ * RENAMED: should be _seterr_reply or __seterr_reply if we can use
+ * reserved namespace.
+ */
+extern void	gssrpc__seterr_reply(struct rpc_msg *, struct rpc_err *);
+
+/* XDR the MSG_ACCEPTED part of a reply message union */
+extern bool_t	xdr_accepted_reply(XDR *, struct accepted_reply *);
+
+/* XDR the MSG_DENIED part of a reply message union */
+extern bool_t	xdr_rejected_reply(XDR *, struct rejected_reply *);
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_RPC_MSG_H) */
diff --git a/mechglue/src/lib/rpc/rpc_prot.c b/mechglue/src/lib/rpc/rpc_prot.c
new file mode 100644
index 000000000..17e26b101
--- /dev/null
+++ b/mechglue/src/lib/rpc/rpc_prot.c
@@ -0,0 +1,293 @@
+/* @(#)rpc_prot.c	2.3 88/08/07 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * rpc_prot.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * This set of routines implements the rpc message definition,
+ * its serializer and some common rpc utility routines.
+ * The routines are meant for various implementations of rpc -
+ * they are NOT for the rpc client or rpc service implementations!
+ * Because authentication stuff is easy and is part of rpc, the opaque
+ * routines are also in this program.
+ */
+
+#include <sys/param.h>
+
+#include <gssrpc/rpc.h>
+
+/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
+
+/*
+ * XDR an opaque authentication struct
+ * (see auth.h)
+ */
+bool_t
+xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap)
+{
+
+	if (xdr_enum(xdrs, &(ap->oa_flavor)))
+		return (xdr_bytes(xdrs, &ap->oa_base,
+			&ap->oa_length, MAX_AUTH_BYTES));
+	return (FALSE);
+}
+
+/*
+ * XDR a DES block
+ */
+bool_t
+xdr_des_block(XDR *xdrs, des_block *blkp)
+{
+	return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof(des_block)));
+}
+
+/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
+
+/*
+ * XDR the MSG_ACCEPTED part of a reply message union
+ */
+bool_t 
+xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar)
+{
+
+	/* personalized union, rather than calling xdr_union */
+	if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
+		return (FALSE);
+	if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat)))
+		return (FALSE);
+	switch (ar->ar_stat) {
+
+	case SUCCESS:
+		return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where));
+
+	case PROG_MISMATCH:
+		if (! xdr_rpcvers(xdrs, &(ar->ar_vers.low)))
+			return (FALSE);
+		return (xdr_rpcvers(xdrs, &(ar->ar_vers.high)));
+
+	case GARBAGE_ARGS:
+	case SYSTEM_ERR:
+	case PROC_UNAVAIL:
+	case PROG_UNAVAIL:
+		break;
+	}
+	return (TRUE);  /* TRUE => open ended set of problems */
+}
+
+/*
+ * XDR the MSG_DENIED part of a reply message union
+ */
+bool_t 
+xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr)
+{
+
+	/* personalized union, rather than calling xdr_union */
+	if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat)))
+		return (FALSE);
+	switch (rr->rj_stat) {
+
+	case RPC_MISMATCH:
+		if (! xdr_rpcvers(xdrs, &(rr->rj_vers.low)))
+			return (FALSE);
+		return (xdr_rpcvers(xdrs, &(rr->rj_vers.high)));
+
+	case AUTH_ERROR:
+		return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why)));
+	}
+	return (FALSE);
+}
+
+static struct xdr_discrim reply_dscrm[3] = {
+	{ (int)MSG_ACCEPTED, xdr_accepted_reply },
+	{ (int)MSG_DENIED, xdr_rejected_reply },
+	{ __dontcare__, NULL_xdrproc_t } };
+
+/*
+ * XDR a reply message
+ */
+bool_t
+xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg)
+{
+	if (
+	    xdr_u_int32(xdrs, &(rmsg->rm_xid)) && 
+	    xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) &&
+	    (rmsg->rm_direction == REPLY) )
+		return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat),
+		   (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t));
+	return (FALSE);
+}
+
+
+/*
+ * Serializes the "static part" of a call message header.
+ * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
+ * The rm_xid is not really static, but the user can easily munge on the fly.
+ */
+bool_t
+xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg)
+{
+
+	cmsg->rm_direction = CALL;
+	cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+	if (
+	    (xdrs->x_op == XDR_ENCODE) &&
+	    xdr_u_int32(xdrs, &(cmsg->rm_xid)) &&
+	    xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) &&
+	    xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+	    xdr_rpcprog(xdrs, &(cmsg->rm_call.cb_prog)) )
+	    return (xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_vers)));
+	return (FALSE);
+}
+
+/* ************************** Client utility routine ************* */
+
+static void
+accepted(enum accept_stat acpt_stat, struct rpc_err *error)
+{
+
+	switch (acpt_stat) {
+
+	case PROG_UNAVAIL:
+		error->re_status = RPC_PROGUNAVAIL;
+		return;
+
+	case PROG_MISMATCH:
+		error->re_status = RPC_PROGVERSMISMATCH;
+		return;
+
+	case PROC_UNAVAIL:
+		error->re_status = RPC_PROCUNAVAIL;
+		return;
+
+	case GARBAGE_ARGS:
+		error->re_status = RPC_CANTDECODEARGS;
+		return;
+
+	case SYSTEM_ERR:
+		error->re_status = RPC_SYSTEMERROR;
+		return;
+
+	case SUCCESS:
+		error->re_status = RPC_SUCCESS;
+		return;
+	}
+	/* something's wrong, but we don't know what ... */
+	error->re_status = RPC_FAILED;
+	error->re_lb.s1 = (int32_t)MSG_ACCEPTED;
+	error->re_lb.s2 = (int32_t)acpt_stat;
+}
+
+static void 
+rejected(enum reject_stat rjct_stat, struct rpc_err *error)
+{
+
+	switch (rjct_stat) {
+
+	case RPC_MISMATCH:
+		error->re_status = RPC_VERSMISMATCH;
+		return;
+
+	case AUTH_ERROR:
+		error->re_status = RPC_AUTHERROR;
+		return;
+	}
+	/* something's wrong, but we don't know what ... */
+	error->re_status = RPC_FAILED;
+	error->re_lb.s1 = (int32_t)MSG_DENIED;
+	error->re_lb.s2 = (int32_t)rjct_stat;
+}
+
+/*
+ * given a reply message, fills in the error
+ */
+void
+gssrpc__seterr_reply(struct rpc_msg *msg, struct rpc_err *error)
+{
+
+	/* optimized for normal, SUCCESSful case */
+	switch (msg->rm_reply.rp_stat) {
+
+	case MSG_ACCEPTED:
+		if (msg->acpted_rply.ar_stat == SUCCESS) {
+			error->re_status = RPC_SUCCESS;
+			return;
+		};
+		accepted(msg->acpted_rply.ar_stat, error);
+		break;
+
+	case MSG_DENIED:
+		rejected(msg->rjcted_rply.rj_stat, error);
+		break;
+
+	default:
+		error->re_status = RPC_FAILED;
+		error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat);
+		break;
+	}
+	switch (error->re_status) {
+
+	case RPC_VERSMISMATCH:
+		error->re_vers.low = msg->rjcted_rply.rj_vers.low;
+		error->re_vers.high = msg->rjcted_rply.rj_vers.high;
+		break;
+
+	case RPC_AUTHERROR:
+		error->re_why = msg->rjcted_rply.rj_why;
+		break;
+
+	case RPC_PROGVERSMISMATCH:
+		error->re_vers.low = msg->acpted_rply.ar_vers.low;
+		error->re_vers.high = msg->acpted_rply.ar_vers.high;
+		break;
+
+	case RPC_FAILED:
+	case RPC_SUCCESS:
+	case RPC_PROGNOTREGISTERED:
+	case RPC_PMAPFAILURE:
+	case RPC_UNKNOWNPROTO:
+	case RPC_UNKNOWNHOST:
+	case RPC_SYSTEMERROR:
+	case RPC_CANTDECODEARGS:
+	case RPC_PROCUNAVAIL:
+	case RPC_PROGUNAVAIL:
+	case RPC_TIMEDOUT:
+	case RPC_CANTRECV:
+	case RPC_CANTSEND:
+	case RPC_CANTDECODERES:
+	case RPC_CANTENCODEARGS:
+	default:
+		break;
+	}
+}
diff --git a/mechglue/src/lib/rpc/svc.c b/mechglue/src/lib/rpc/svc.c
new file mode 100644
index 000000000..7d2be1c1a
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc.c
@@ -0,0 +1,526 @@
+/* @(#)svc.c	2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc.c, Server-side remote procedure call interface.
+ *
+ * There are two sets of procedures here.  The xprt routines are
+ * for handling transport handles.  The svc routines handle the
+ * list of service routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_clnt.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef FD_SETSIZE
+static SVCXPRT **xports;
+extern int gssrpc_svc_fdset_init;
+#else
+
+#ifdef NBBY
+#define NOFILE (sizeof(int) * NBBY)
+#else
+#define NOFILE (sizeof(int) * 8)
+#endif
+
+static SVCXPRT *xports[NOFILE];
+#endif /* def FD_SETSIZE */
+
+#define NULL_SVC ((struct svc_callout *)0)
+#define	RQCRED_SIZE	1024		/* this size is excessive */
+
+/*
+ * The services list
+ * Each entry represents a set of procedures (an rpc program).
+ * The dispatch routine takes request structs and runs the
+ * apropriate procedure.
+ */
+static struct svc_callout {
+	struct svc_callout *sc_next;
+	rpcprog_t		    sc_prog;
+	rpcprog_t		    sc_vers;
+	void		    (*sc_dispatch)();
+} *svc_head;
+
+static struct svc_callout *svc_find(rpcprog_t, rpcvers_t,
+				    struct svc_callout **);
+
+static void svc_do_xprt(SVCXPRT *xprt);
+
+/* ***************  SVCXPRT related stuff **************** */
+
+/*
+ * Activate a transport handle.
+ */
+void
+xprt_register(SVCXPRT *xprt)
+{
+	register int sock = xprt->xp_sock;
+
+#ifdef FD_SETSIZE
+	if (gssrpc_svc_fdset_init == 0) {
+		FD_ZERO(&svc_fdset);
+		gssrpc_svc_fdset_init++;
+	}
+	if (xports == NULL) {
+		xports = (SVCXPRT **)
+			mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
+		memset(xports, 0, FD_SETSIZE * sizeof(SVCXPRT *));
+	}
+	if (sock < FD_SETSIZE) {
+		xports[sock] = xprt;
+		FD_SET(sock, &svc_fdset);
+	}
+#else
+	if (sock < NOFILE) {
+		xports[sock] = xprt;
+		svc_fds |= (1 << sock);
+	}
+#endif /* def FD_SETSIZE */
+	if (sock > svc_maxfd)
+		svc_maxfd = sock;
+}
+
+/*
+ * De-activate a transport handle. 
+ */
+void
+xprt_unregister(SVCXPRT *xprt)
+{ 
+	register int sock = xprt->xp_sock;
+
+#ifdef FD_SETSIZE
+	if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) {
+		xports[sock] = (SVCXPRT *)0;
+		FD_CLR(sock, &svc_fdset);
+	}
+#else
+	if ((sock < NOFILE) && (xports[sock] == xprt)) {
+		xports[sock] = (SVCXPRT *)0;
+		svc_fds &= ~(1 << sock);
+	}
+#endif /* def FD_SETSIZE */
+	if (svc_maxfd <= sock) {
+		while ((svc_maxfd > 0) && xports[svc_maxfd] == 0)
+			svc_maxfd--;
+	}
+}
+
+
+/* ********************** CALLOUT list related stuff ************* */
+
+/*
+ * Add a service program to the callout list.
+ * The dispatch routine will be called when a rpc request for this
+ * program number comes in.
+ */
+bool_t
+svc_register(
+	SVCXPRT *xprt,
+	rpcprog_t prog,
+	rpcvers_t vers,
+	void (*dispatch)(),
+	int protocol)
+{
+	struct svc_callout *prev;
+	register struct svc_callout *s;
+
+	if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) {
+		if (s->sc_dispatch == dispatch)
+			goto pmap_it;  /* he is registering another xptr */
+		return (FALSE);
+	}
+	s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
+	if (s == (struct svc_callout *)0) {
+		return (FALSE);
+	}
+	s->sc_prog = prog;
+	s->sc_vers = vers;
+	s->sc_dispatch = dispatch;
+	s->sc_next = svc_head;
+	svc_head = s;
+pmap_it:
+	/* now register the information with the local binder service */
+	if (protocol) {
+		return (pmap_set(prog, vers, protocol, xprt->xp_port));
+	}
+	return (TRUE);
+}
+
+/*
+ * Remove a service program from the callout list.
+ */
+void
+svc_unregister(
+	rpcprog_t prog,
+	rpcvers_t vers)
+{
+	struct svc_callout *prev;
+	register struct svc_callout *s;
+
+	if ((s = svc_find(prog, vers, &prev)) == NULL_SVC)
+		return;
+	if (prev == NULL_SVC) {
+		svc_head = s->sc_next;
+	} else {
+		prev->sc_next = s->sc_next;
+	}
+	s->sc_next = NULL_SVC;
+	mem_free((char *) s, (u_int) sizeof(struct svc_callout));
+	/* now unregister the information with the local binder service */
+	(void)pmap_unset(prog, vers);
+}
+
+/*
+ * Search the callout list for a program number, return the callout
+ * struct.
+ */
+static struct svc_callout *
+svc_find(
+	rpcprog_t prog,
+	rpcvers_t vers,
+	struct svc_callout **prev)
+{
+	register struct svc_callout *s, *p;
+
+	p = NULL_SVC;
+	for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
+		if ((s->sc_prog == prog) && (s->sc_vers == vers))
+			goto done;
+		p = s;
+	}
+done:
+	*prev = p;
+	return (s);
+}
+
+/* ******************* REPLY GENERATION ROUTINES  ************ */
+
+/*
+ * Send a reply to an rpc request
+ */
+bool_t
+svc_sendreply(
+	register SVCXPRT *xprt,
+	xdrproc_t xdr_results,
+	caddr_t xdr_location)
+{
+	struct rpc_msg rply; 
+
+	rply.rm_direction = REPLY;  
+	rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+	rply.acpted_rply.ar_verf = xprt->xp_verf; 
+	rply.acpted_rply.ar_stat = SUCCESS;
+	rply.acpted_rply.ar_results.where = xdr_location;
+	rply.acpted_rply.ar_results.proc = xdr_results;
+	return (SVC_REPLY(xprt, &rply)); 
+}
+
+/*
+ * No procedure error reply
+ */
+void
+svcerr_noproc(register SVCXPRT *xprt)
+{
+	struct rpc_msg rply;
+
+	rply.rm_direction = REPLY;
+	rply.rm_reply.rp_stat = MSG_ACCEPTED;
+	rply.acpted_rply.ar_verf = xprt->xp_verf;
+	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
+	SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Can't decode args error reply
+ */
+void
+svcerr_decode(register SVCXPRT *xprt)
+{
+	struct rpc_msg rply; 
+
+	rply.rm_direction = REPLY; 
+	rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+	rply.acpted_rply.ar_verf = xprt->xp_verf;
+	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
+	SVC_REPLY(xprt, &rply); 
+}
+
+/*
+ * Some system error
+ */
+void
+svcerr_systemerr(register SVCXPRT *xprt)
+{
+	struct rpc_msg rply; 
+
+	rply.rm_direction = REPLY; 
+	rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+	rply.acpted_rply.ar_verf = xprt->xp_verf;
+	rply.acpted_rply.ar_stat = SYSTEM_ERR;
+	SVC_REPLY(xprt, &rply); 
+}
+
+/*
+ * Authentication error reply
+ */
+void
+svcerr_auth(
+	SVCXPRT *xprt,
+	enum auth_stat why)
+{
+	struct rpc_msg rply;
+
+	rply.rm_direction = REPLY;
+	rply.rm_reply.rp_stat = MSG_DENIED;
+	rply.rjcted_rply.rj_stat = AUTH_ERROR;
+	rply.rjcted_rply.rj_why = why;
+	SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Auth too weak error reply
+ */
+void
+svcerr_weakauth(SVCXPRT *xprt)
+{
+
+	svcerr_auth(xprt, AUTH_TOOWEAK);
+}
+
+/*
+ * Program unavailable error reply
+ */
+void 
+svcerr_noprog(register SVCXPRT *xprt)
+{
+	struct rpc_msg rply;  
+
+	rply.rm_direction = REPLY;   
+	rply.rm_reply.rp_stat = MSG_ACCEPTED;  
+	rply.acpted_rply.ar_verf = xprt->xp_verf;  
+	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
+	SVC_REPLY(xprt, &rply);
+}
+
+/*
+ * Program version mismatch error reply
+ */
+void  
+svcerr_progvers(
+	register SVCXPRT *xprt,
+	rpcvers_t low_vers,
+	rpcvers_t high_vers)
+{
+	struct rpc_msg rply;
+
+	rply.rm_direction = REPLY;
+	rply.rm_reply.rp_stat = MSG_ACCEPTED;
+	rply.acpted_rply.ar_verf = xprt->xp_verf;
+	rply.acpted_rply.ar_stat = PROG_MISMATCH;
+	rply.acpted_rply.ar_vers.low = low_vers;
+	rply.acpted_rply.ar_vers.high = high_vers;
+	SVC_REPLY(xprt, &rply);
+}
+
+/* ******************* SERVER INPUT STUFF ******************* */
+
+/*
+ * Get server side input from some transport.
+ *
+ * Statement of authentication parameters management:
+ * This function owns and manages all authentication parameters, specifically
+ * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
+ * the "cooked" credentials (rqst->rq_clntcred).
+ * However, this function does not know the structure of the cooked
+ * credentials, so it make the following assumptions: 
+ *   a) the structure is contiguous (no pointers), and
+ *   b) the cred structure size does not exceed RQCRED_SIZE bytes. 
+ * In all events, all three parameters are freed upon exit from this routine.
+ * The storage is trivially management on the call stack in user land, but
+ * is mallocated in kernel land.
+ */
+
+void
+svc_getreq(int rdfds)
+{
+#ifdef FD_SETSIZE
+	fd_set readfds;
+	int	i, mask;
+
+	FD_ZERO(&readfds);
+	for (i=0, mask=1; rdfds; i++, mask <<=1) {
+		if (rdfds & mask)
+			FD_SET(i, &readfds);
+		rdfds &= ~mask;
+	}
+	svc_getreqset(&readfds);
+#else
+	int readfds = rdfds & svc_fds;
+
+	svc_getreqset(&readfds);
+#endif /* def FD_SETSIZE */
+}
+
+#ifdef FD_SETSIZE
+#define FDSET_TYPE fd_set
+#else
+#define FDSET_TYPE int
+#endif
+
+void
+svc_getreqset(FDSET_TYPE *readfds)
+{
+#ifndef FD_SETSIZE
+	int readfds_local = *readfds;
+#endif
+	register SVCXPRT *xprt;
+	register int sock;
+
+#ifdef FD_SETSIZE
+	for (sock = 0; sock <= svc_maxfd; sock++) {
+		if (!FD_ISSET(sock, readfds))
+			continue;
+		/* sock has input waiting */
+		xprt = xports[sock];
+		/* now receive msgs from xprtprt (support batch calls) */
+		svc_do_xprt(xprt);
+	}
+#else
+	for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) {
+		if ((readfds_local & 1) == 0)
+			continue;
+		/* sock has input waiting */
+		xprt = xports[sock];
+		/* now receive msgs from xprtprt (support batch calls) */
+		svc_do_xprt(xprt);
+	}
+#endif
+}
+
+static void
+svc_do_xprt(SVCXPRT *xprt)
+{
+	caddr_t rawcred, rawverf, cookedcred;
+	struct rpc_msg msg;
+	struct svc_req r;
+        bool_t no_dispatch;
+	int prog_found;
+	rpcvers_t low_vers;
+	rpcvers_t high_vers;
+	enum xprt_stat stat;
+
+	rawcred = mem_alloc(MAX_AUTH_BYTES);
+	rawverf = mem_alloc(MAX_AUTH_BYTES);
+	cookedcred = mem_alloc(RQCRED_SIZE);
+
+	if (rawcred == NULL || rawverf == NULL || cookedcred == NULL)
+		return;
+
+	msg.rm_call.cb_cred.oa_base = rawcred;
+	msg.rm_call.cb_verf.oa_base = rawverf;
+	r.rq_clntcred = cookedcred;
+
+	do {
+		register struct svc_callout *s;
+		enum auth_stat why;
+
+		if (!SVC_RECV(xprt, &msg))
+			goto call_done;
+
+		/* now find the exported program and call it */
+
+		r.rq_xprt = xprt;
+		r.rq_prog = msg.rm_call.cb_prog;
+		r.rq_vers = msg.rm_call.cb_vers;
+		r.rq_proc = msg.rm_call.cb_proc;
+		r.rq_cred = msg.rm_call.cb_cred;
+
+		no_dispatch = FALSE;
+
+		/* first authenticate the message */
+		why = gssrpc__authenticate(&r, &msg, &no_dispatch);
+		if (why != AUTH_OK) {
+			svcerr_auth(xprt, why);
+			goto call_done;
+		} else if (no_dispatch) {
+			goto call_done;
+		}
+
+		/* now match message with a registered service*/
+		prog_found = FALSE;
+		low_vers = (rpcvers_t) -1L;
+		high_vers = 0;
+		for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
+			if (s->sc_prog == r.rq_prog) {
+				if (s->sc_vers == r.rq_vers) {
+					(*s->sc_dispatch)(&r, xprt);
+					goto call_done;
+				}  /* found correct version */
+				prog_found = TRUE;
+				if (s->sc_vers < low_vers)
+					low_vers = s->sc_vers;
+				if (s->sc_vers > high_vers)
+					high_vers = s->sc_vers;
+			}   /* found correct program */
+		}
+		/*
+		 * if we got here, the program or version
+		 * is not served ...
+		 */
+		if (prog_found)
+			svcerr_progvers(xprt,
+					low_vers, high_vers);
+		else
+			svcerr_noprog(xprt);
+		/* Fall through to ... */
+
+	call_done:
+		if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
+			SVC_DESTROY(xprt);
+			break;
+		}
+	} while (stat == XPRT_MOREREQS);
+
+	mem_free(rawcred, MAX_AUTH_BYTES);
+	mem_free(rawverf, MAX_AUTH_BYTES);
+	mem_free(cookedcred, RQCRED_SIZE);
+}
diff --git a/mechglue/src/lib/rpc/svc.h b/mechglue/src/lib/rpc/svc.h
new file mode 100644
index 000000000..b66353540
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc.h
@@ -0,0 +1,337 @@
+/* @(#)svc.h	2.2 88/07/29 4.0 RPCSRC; from 1.20 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * svc.h, Server-side remote procedure call interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef GSSRPC_SVC_H
+#define GSSRPC_SVC_H
+
+#include <gssrpc/svc_auth.h>
+
+GSSRPC__BEGIN_DECLS
+/*
+ * This interface must manage two items concerning remote procedure calling:
+ *
+ * 1) An arbitrary number of transport connections upon which rpc requests
+ * are received.  The two most notable transports are TCP and UDP;  they are
+ * created and registered by routines in svc_tcp.c and svc_udp.c, respectively;
+ * they in turn call xprt_register and xprt_unregister.
+ *
+ * 2) An arbitrary number of locally registered services.  Services are
+ * described by the following four data: program number, version number,
+ * "service dispatch" function, a transport handle, and a boolean that
+ * indicates whether or not the exported program should be registered with a
+ * local binder service;  if true the program's number and version and the
+ * port number from the transport handle are registered with the binder.
+ * These data are registered with the rpc svc system via svc_register.
+ *
+ * A service's dispatch function is called whenever an rpc request comes in
+ * on a transport.  The request's program and version numbers must match
+ * those of the registered service.  The dispatch function is passed two
+ * parameters, struct svc_req * and SVCXPRT *, defined below.
+ */
+
+enum xprt_stat {
+	XPRT_DIED,
+	XPRT_MOREREQS,
+	XPRT_IDLE
+};
+
+/*
+ * Server side transport handle
+ */
+typedef struct SVCXPRT {
+	int		xp_sock;
+	u_short		xp_port;	 /* associated port number */
+	struct xp_ops {
+	    /* receive incomming requests */
+	    bool_t	(*xp_recv)(struct SVCXPRT *, struct rpc_msg *);
+	    /* get transport status */
+	    enum xprt_stat (*xp_stat)(struct SVCXPRT *); 
+	    /* get arguments */
+	    bool_t	(*xp_getargs)(struct SVCXPRT *, xdrproc_t,
+				      void *);
+	    /* send reply */
+	    bool_t	(*xp_reply)(struct SVCXPRT *,
+				    struct rpc_msg *);	 
+            /* free mem allocated for args */
+	    bool_t	(*xp_freeargs)(struct SVCXPRT *, xdrproc_t,
+				       void *);
+	    /* destroy this struct */
+	    void	(*xp_destroy)(struct SVCXPRT *); 
+	} *xp_ops;
+	int		xp_addrlen;	 /* length of remote address */
+	struct sockaddr_in xp_raddr;	 /* remote address */
+	struct opaque_auth xp_verf;	 /* raw response verifier */
+	SVCAUTH		*xp_auth;	 /* auth flavor of current req */
+	void		*xp_p1;		 /* private */
+	void		*xp_p2;		 /* private */
+	int		xp_laddrlen;	 /* lenght of local address */
+	struct sockaddr_in xp_laddr;	 /* local address */
+} SVCXPRT;
+
+/*
+ *  Approved way of getting address of caller
+ */
+#define svc_getcaller(x) (&(x)->xp_raddr)
+
+/*
+ * Operations defined on an SVCXPRT handle
+ *
+ * SVCXPRT		*xprt;
+ * struct rpc_msg	*msg;
+ * xdrproc_t		 xargs;
+ * caddr_t		 argsp;
+ */
+#define SVC_RECV(xprt, msg)				\
+	(*(xprt)->xp_ops->xp_recv)((xprt), (msg))
+#define svc_recv(xprt, msg)				\
+	(*(xprt)->xp_ops->xp_recv)((xprt), (msg))
+
+#define SVC_STAT(xprt)					\
+	(*(xprt)->xp_ops->xp_stat)(xprt)
+#define svc_stat(xprt)					\
+	(*(xprt)->xp_ops->xp_stat)(xprt)
+
+#define SVC_GETARGS(xprt, xargs, argsp)			\
+	(*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
+#define svc_getargs(xprt, xargs, argsp)			\
+	(*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
+
+#define SVC_GETARGS_REQ(xprt, req, xargs, argsp)	\
+	(*(xprt)->xp_ops->xp_getargs_req)((xprt), (req), (xargs), (argsp))
+#define svc_getargs_req(xprt, req, xargs, argsp)	\
+	(*(xprt)->xp_ops->xp_getargs_req)((xprt), (req), (xargs), (argsp))
+
+#define SVC_REPLY(xprt, msg)				\
+	(*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
+#define svc_reply(xprt, msg)				\
+	(*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
+
+#define SVC_REPLY_REQ(xprt, req, msg)			\
+	(*(xprt)->xp_ops->xp_reply_req) ((xprt), (req), (msg))
+#define svc_reply_req(xprt, msg)			\
+	(*(xprt)->xp_ops->xp_reply_req) ((xprt), (req), (msg))
+
+#define SVC_FREEARGS(xprt, xargs, argsp)		\
+	(*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
+#define svc_freeargs(xprt, xargs, argsp)		\
+	(*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
+
+#define SVC_DESTROY(xprt)				\
+	(*(xprt)->xp_ops->xp_destroy)(xprt)
+#define svc_destroy(xprt)				\
+	(*(xprt)->xp_ops->xp_destroy)(xprt)
+
+
+/*
+ * Service request
+ */
+struct svc_req {
+	rpcprog_t		rq_prog;	/* service program number */
+	rpcvers_t		rq_vers;	/* service protocol version */
+	rpcproc_t		rq_proc;	/* the desired procedure */
+	struct opaque_auth rq_cred;	/* raw creds from the wire */
+	void *		rq_clntcred;	/* read only cooked client cred */
+	void *		rq_svccred;	/* read only svc cred/context */
+	void *		rq_clntname;	/* read only client name */
+	SVCXPRT		*rq_xprt;	/* associated transport */
+	/* The request's auth flavor *should* be here, but the svc_req 	*/
+	/* isn't passed around everywhere it is necessary.  The 	*/
+	/* transport *is* passed around, so the auth flavor it stored 	*/
+	/* there.  This means that the transport must be single 	*/
+	/* threaded, but other parts of SunRPC already require that. 	*/
+	/*SVCAUTH		*rq_auth;	 associated auth flavor */
+};
+
+
+/*
+ * Service registration
+ *
+ * svc_register(xprt, prog, vers, dispatch, protocol)
+ *	SVCXPRT *xprt;
+ *	rpcprog_t prog;
+ *	rpcvers_t vers;
+ *	void (*dispatch)();
+ *	int protocol;  like TCP or UDP, zero means do not register 
+ *
+ * registerrpc(prog, vers, proc, routine, inproc, outproc)
+ * 	returns 0 upon success, -1 if error.
+ */
+extern bool_t	svc_register(SVCXPRT *, rpcprog_t, rpcvers_t,
+			     void (*)(struct svc_req *, SVCXPRT *), int);
+
+extern int registerrpc(rpcprog_t, rpcvers_t, rpcproc_t,
+		       char *(*)(void *),
+		       xdrproc_t, xdrproc_t);
+
+/*
+ * Service un-registration
+ *
+ * svc_unregister(prog, vers)
+ *	rpcprog_t prog;
+ *	rpcvers_t vers;
+ */
+extern void	svc_unregister(rpcprog_t, rpcvers_t);
+
+/*
+ * Transport registration.
+ *
+ * xprt_register(xprt)
+ *	SVCXPRT *xprt;
+ */
+extern void	xprt_register(SVCXPRT *);
+
+/*
+ * Transport un-register
+ *
+ * xprt_unregister(xprt)
+ *	SVCXPRT *xprt;
+ */
+extern void	xprt_unregister(SVCXPRT *);
+
+
+/*
+ * When the service routine is called, it must first check to see if
+ * it knows about the procedure; if not, it should call svcerr_noproc
+ * and return.  If so, it should deserialize its arguments via
+ * SVC_GETARGS or the new SVC_GETARGS_REQ (both defined above).  If
+ * the deserialization does not work, svcerr_decode should be called
+ * followed by a return.  Successful decoding of the arguments should
+ * be followed the execution of the procedure's code and a call to
+ * svc_sendreply or the new svc_sendreply_req.
+ *
+ * Also, if the service refuses to execute the procedure due to too-
+ * weak authentication parameters, svcerr_weakauth should be called.
+ * Note: do not confuse access-control failure with weak authentication!
+ *
+ * NB: In pure implementations of rpc, the caller always waits for a reply
+ * msg.  This message is sent when svc_sendreply is called.  
+ * Therefore pure service implementations should always call
+ * svc_sendreply even if the function logically returns void;  use
+ * xdr.h - xdr_void for the xdr routine.  HOWEVER, tcp based rpc allows
+ * for the abuse of pure rpc via batched calling or pipelining.  In the
+ * case of a batched call, svc_sendreply should NOT be called since
+ * this would send a return message, which is what batching tries to avoid.
+ * It is the service/protocol writer's responsibility to know which calls are
+ * batched and which are not.  Warning: responding to batch calls may
+ * deadlock the caller and server processes!
+ */
+
+extern bool_t	svc_sendreply(SVCXPRT *, xdrproc_t, caddr_t);
+extern void	svcerr_decode(SVCXPRT *);
+extern void	svcerr_weakauth(SVCXPRT *);
+extern void	svcerr_noproc(SVCXPRT *);
+extern void	svcerr_progvers(SVCXPRT *, rpcvers_t, rpcvers_t);
+extern void	svcerr_auth(SVCXPRT *, enum auth_stat);
+extern void	svcerr_noprog(SVCXPRT *);
+extern void	svcerr_systemerr(SVCXPRT *);
+
+/*
+ * Lowest level dispatching -OR- who owns this process anyway.
+ * Somebody has to wait for incoming requests and then call the correct
+ * service routine.  The routine svc_run does infinite waiting; i.e.,
+ * svc_run never returns.
+ * Since another (co-existant) package may wish to selectively wait for
+ * incoming calls or other events outside of the rpc architecture, the
+ * routine svc_getreq is provided.  It must be passed readfds, the
+ * "in-place" results of a select system call (see select, section 2).
+ */
+
+/*
+ * Global keeper of rpc service descriptors in use
+ * dynamic; must be inspected before each call to select 
+ */
+extern int svc_maxfd;
+#ifdef FD_SETSIZE
+extern fd_set svc_fdset;
+/* RENAMED */
+#define gssrpc_svc_fds gsssrpc_svc_fdset.fds_bits[0]	/* compatibility */
+#else
+extern int svc_fds;
+#endif /* def FD_SETSIZE */
+extern int svc_maxfd;
+
+/*
+ * a small program implemented by the svc_rpc implementation itself;
+ * also see clnt.h for protocol numbers.
+ */
+extern void rpctest_service();
+
+extern void	svc_getreq(int);
+#ifdef FD_SETSIZE
+extern void	svc_getreqset(fd_set *);/* takes fdset instead of int */
+extern void	svc_getreqset2(fd_set *, int);
+#else
+extern void	svc_getreqset(int *);
+#endif
+extern void	svc_run(void); 	 /* never returns */
+
+/*
+ * Socket to use on svcxxx_create call to get default socket
+ */
+#define	RPC_ANYSOCK	-1
+
+/*
+ * These are the existing service side transport implementations
+ */
+
+/*
+ * Memory based rpc for testing and timing.
+ */
+extern SVCXPRT *svcraw_create(void);
+
+/*
+ * Udp based rpc.
+ */
+extern SVCXPRT *svcudp_create(int);
+extern SVCXPRT *svcudp_bufcreate(int, u_int, u_int);
+extern int svcudp_enablecache(SVCXPRT *, uint32_t);
+
+/*
+ * Tcp based rpc.
+ */
+extern SVCXPRT *svctcp_create(int, u_int, u_int);
+
+/*
+ * Like svtcp_create(), except the routine takes any *open* UNIX file
+ * descriptor as its first input.
+ */
+extern SVCXPRT *svcfd_create(int, u_int, u_int);
+
+/* XXX add auth_gsapi_log_*? */
+
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_SVC_H) */
diff --git a/mechglue/src/lib/rpc/svc_auth.c b/mechglue/src/lib/rpc/svc_auth.c
new file mode 100644
index 000000000..8732619cb
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_auth.c
@@ -0,0 +1,109 @@
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_auth.c	2.1 88/08/07 4.0 RPCSRC; from 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * svc_auth_nodes.c, Server-side rpc authenticator interface,
+ * *WITHOUT* DES authentication.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <gssrpc/rpc.h>
+
+/*
+ * Server side authenticators are called from authenticate by
+ * using the client auth struct flavor field to index into svcauthsw.
+ * The server auth flavors must implement a routine that looks  
+ * like: 
+ * 
+ *	enum auth_stat
+ *	flavorx_auth(rqst, msg)
+ *		register struct svc_req *rqst; 
+ *		register struct rpc_msg *msg;
+ *
+ */
+
+static struct svcauthsw_type {
+     u_int flavor;
+     enum auth_stat (*authenticator)(struct svc_req *, struct rpc_msg *,
+				     bool_t *);
+} svcauthsw[] = {
+     {AUTH_GSSAPI, gssrpc__svcauth_gssapi},	/* AUTH_GSSAPI */
+     {AUTH_NONE, gssrpc__svcauth_none},		/* AUTH_NONE */
+#if 0
+     {AUTH_GSSAPI_COMPAT, gssrpc__svcauth_gssapi}, /* AUTH_GSSAPI_COMPAT */
+#endif
+     {AUTH_UNIX, gssrpc__svcauth_unix},		/* AUTH_UNIX */
+     {AUTH_SHORT, gssrpc__svcauth_short},	/* AUTH_SHORT */
+     {RPCSEC_GSS, gssrpc__svcauth_gss}		/* RPCSEC_GSS */
+};
+static int svcauthnum = sizeof(svcauthsw) / sizeof(struct svcauthsw_type);
+
+/*
+ * The call rpc message, msg has been obtained from the wire.  The msg contains
+ * the raw form of credentials and verifiers.  authenticate returns AUTH_OK
+ * if the msg is successfully authenticated.  If AUTH_OK then the routine also
+ * does the following things:
+ * set rqst->rq_xprt->verf to the appropriate response verifier;
+ * sets rqst->rq_client_cred to the "cooked" form of the credentials.
+ *
+ * NB: rqst->rq_cxprt->verf must be pre-alloctaed;
+ * its length is set appropriately.
+ *
+ * The caller still owns and is responsible for msg->u.cmb.cred and
+ * msg->u.cmb.verf.  The authentication system retains ownership of
+ * rqst->rq_client_cred, the cooked credentials.
+ */
+enum auth_stat
+gssrpc__authenticate(
+	register struct svc_req *rqst,
+	struct rpc_msg *msg,
+	bool_t *no_dispatch)
+{
+	register int cred_flavor, i;
+
+	rqst->rq_cred = msg->rm_call.cb_cred;
+	rqst->rq_xprt->xp_verf.oa_flavor = gssrpc__null_auth.oa_flavor;
+	rqst->rq_xprt->xp_verf.oa_length = 0;
+	cred_flavor = rqst->rq_cred.oa_flavor;
+	*no_dispatch = FALSE;
+	for (i = 0; i < svcauthnum; i++) {
+	     if (cred_flavor == svcauthsw[i].flavor &&
+		 svcauthsw[i].authenticator != NULL) {
+		  return ((*(svcauthsw[i].authenticator))(rqst,
+							  msg,
+							  no_dispatch));
+	     }
+	}
+	
+	return (AUTH_REJECTEDCRED);
+}
diff --git a/mechglue/src/lib/rpc/svc_auth.h b/mechglue/src/lib/rpc/svc_auth.h
new file mode 100644
index 000000000..541aa4514
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_auth.h
@@ -0,0 +1,117 @@
+/* @(#)svc_auth.h	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)svc_auth.h 1.6 86/07/16 SMI      */
+
+/*
+ * svc_auth.h, Service side of rpc authentication.
+ * 
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+/*
+ * Interface to server-side authentication flavors.
+ */
+
+#ifndef GSSRPC_SVC_AUTH_H
+#define GSSRPC_SVC_AUTH_H
+
+#include <gssapi/gssapi.h>
+
+GSSRPC__BEGIN_DECLS
+
+struct svc_req;
+
+typedef struct SVCAUTH {
+	struct svc_auth_ops {
+		int	(*svc_ah_wrap)(struct SVCAUTH *, XDR *, xdrproc_t,
+				       caddr_t);
+		int	(*svc_ah_unwrap)(struct SVCAUTH *, XDR *, xdrproc_t,
+					 caddr_t);
+		int	(*svc_ah_destroy)(struct SVCAUTH *);
+	} *svc_ah_ops;
+	void * svc_ah_private;
+} SVCAUTH;
+
+#ifdef GSSRPC__IMPL
+
+extern SVCAUTH svc_auth_none;
+
+extern struct svc_auth_ops svc_auth_none_ops;
+extern struct svc_auth_ops svc_auth_gssapi_ops;
+extern struct svc_auth_ops svc_auth_gss_ops;
+
+/*
+ * Server side authenticator
+ */
+/* RENAMED: should be _authenticate. */
+extern enum auth_stat gssrpc__authenticate(struct svc_req *rqst,
+	struct rpc_msg *msg, bool_t *no_dispatch);
+
+#define SVCAUTH_WRAP(auth, xdrs, xfunc, xwhere) \
+     ((*((auth)->svc_ah_ops->svc_ah_wrap))(auth, xdrs, xfunc, xwhere))
+#define SVCAUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \
+     ((*((auth)->svc_ah_ops->svc_ah_unwrap))(auth, xdrs, xfunc, xwhere))
+#define SVCAUTH_DESTROY(auth) \
+     ((*((auth)->svc_ah_ops->svc_ah_destroy))(auth))
+
+/* no authentication */
+/* RENAMED: should be _svcauth_none. */
+enum auth_stat gssrpc__svcauth_none(struct svc_req *,
+	struct rpc_msg *, bool_t *);
+/* unix style (uid, gids) */
+/* RENAMED: shoudl be _svcauth_unix. */
+enum auth_stat gssrpc__svcauth_unix(struct svc_req *,
+	struct rpc_msg *, bool_t *);
+/* short hand unix style */
+/* RENAMED: should be _svcauth_short. */
+enum auth_stat gssrpc__svcauth_short(struct svc_req *,
+	struct rpc_msg *, bool_t *);
+/* GSS-API style */
+/* RENAMED: should be _svcauth_gssapi. */
+enum auth_stat gssrpc__svcauth_gssapi(struct svc_req *,
+	struct rpc_msg *, bool_t *);
+/* RPCSEC_GSS */
+enum auth_stat gssrpc__svcauth_gss(struct svc_req *,
+	struct rpc_msg *, bool_t *);
+
+#endif /* defined(GSSRPC__IMPL) */
+
+/*
+ * Approved way of getting principal of caller
+ */
+char *svcauth_gss_get_principal(SVCAUTH *auth);
+/*
+ * Approved way of setting server principal
+ */
+bool_t svcauth_gss_set_svc_name(gss_name_t name);
+
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_SVC_AUTH_H) */
diff --git a/mechglue/src/lib/rpc/svc_auth_gss.c b/mechglue/src/lib/rpc/svc_auth_gss.c
new file mode 100644
index 000000000..78da340cb
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_auth_gss.c
@@ -0,0 +1,724 @@
+/*
+  svc_auth_gss.c
+  
+  Copyright (c) 2000 The Regents of the University of Michigan.
+  All rights reserved.
+
+  Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+  All rights reserved, all wrongs reversed.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. Neither the name of the University nor the names of its
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Id: svc_auth_gss.c,v 1.28 2002/10/15 21:29:36 kwc Exp
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/auth_gssapi.h>
+#ifdef HAVE_HEIMDAL
+#include <gssapi.h>
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#else
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#endif
+
+#ifdef DEBUG_GSSAPI
+int svc_debug_gss = DEBUG_GSSAPI;
+#endif
+
+#ifdef SPKM
+
+#ifndef OID_EQ
+#define g_OID_equal(o1,o2) \
+   (((o1)->length == (o2)->length) && \
+    ((o1)->elements != 0) && ((o2)->elements != 0) && \
+    (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
+#define OID_EQ 1
+#endif /* OID_EQ */
+
+extern const gss_OID_desc * const gss_mech_spkm3;
+
+#endif /* SPKM */
+
+extern SVCAUTH svc_auth_none;
+
+/*
+ * from mit-krb5-1.2.1 mechglue/mglueP.h:
+ * Array of context IDs typed by mechanism OID
+ */
+typedef struct gss_union_ctx_id_t {
+  gss_OID     mech_type;
+  gss_ctx_id_t    internal_ctx_id;
+} gss_union_ctx_id_desc, *gss_union_ctx_id_t;
+
+
+static auth_gssapi_log_badauth_func log_badauth = NULL;
+static caddr_t log_badauth_data = NULL;
+static auth_gssapi_log_badverf_func log_badverf = NULL;
+static caddr_t log_badverf_data = NULL;
+static auth_gssapi_log_miscerr_func log_miscerr = NULL;
+static caddr_t log_miscerr_data = NULL;
+
+#define LOG_MISCERR(arg) if (log_miscerr) \
+        (*log_miscerr)(rqst, msg, arg, log_miscerr_data)
+
+static bool_t	svcauth_gss_destroy(SVCAUTH *);
+static bool_t   svcauth_gss_wrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
+static bool_t   svcauth_gss_unwrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
+
+static bool_t	svcauth_gss_nextverf(struct svc_req *, u_int);
+
+struct svc_auth_ops svc_auth_gss_ops = {
+	svcauth_gss_wrap,
+	svcauth_gss_unwrap,
+	svcauth_gss_destroy
+};
+
+struct svc_rpc_gss_data {
+	bool_t			established;	/* context established */
+	gss_ctx_id_t		ctx;		/* context id */
+	struct rpc_gss_sec	sec;		/* security triple */
+	gss_buffer_desc		cname;		/* GSS client name */
+	u_int			seq;		/* sequence number */
+	u_int			win;		/* sequence window */
+	u_int			seqlast;	/* last sequence number */
+	uint32_t		seqmask;	/* bitmask of seqnums */
+	gss_name_t		client_name;	/* unparsed name string */
+	gss_buffer_desc		checksum;	/* so we can free it */
+};
+
+#define SVCAUTH_PRIVATE(auth) \
+	(*(struct svc_rpc_gss_data **)&(auth)->svc_ah_private)
+
+/* Global server credentials. */
+gss_cred_id_t		svcauth_gss_creds;
+static gss_name_t	svcauth_gss_name = NULL;
+
+bool_t
+svcauth_gss_set_svc_name(gss_name_t name)
+{
+	OM_uint32	maj_stat, min_stat;
+
+	log_debug("in svcauth_gss_set_svc_name()");
+
+	if (svcauth_gss_name != NULL) {
+		maj_stat = gss_release_name(&min_stat, &svcauth_gss_name);
+
+		if (maj_stat != GSS_S_COMPLETE) {
+			log_status("gss_release_name", maj_stat, min_stat);
+			return (FALSE);
+		}
+		svcauth_gss_name = NULL;
+	}
+	if (svcauth_gss_name == GSS_C_NO_NAME)
+		return (TRUE);
+
+	maj_stat = gss_duplicate_name(&min_stat, name, &svcauth_gss_name);
+
+	if (maj_stat != GSS_S_COMPLETE) {
+		log_status("gss_duplicate_name", maj_stat, min_stat);
+		return (FALSE);
+	}
+
+	return (TRUE);
+}
+
+static bool_t
+svcauth_gss_import_name(char *service)
+{
+	gss_name_t	name;
+	gss_buffer_desc	namebuf;
+	OM_uint32	maj_stat, min_stat;
+
+	log_debug("in svcauth_gss_import_name()");
+
+	namebuf.value = service;
+	namebuf.length = strlen(service);
+
+	maj_stat = gss_import_name(&min_stat, &namebuf,
+				   (gss_OID)gss_nt_service_name, &name);
+
+	if (maj_stat != GSS_S_COMPLETE) {
+		log_status("gss_import_name", maj_stat, min_stat);
+		return (FALSE);
+	}
+	if (svcauth_gss_set_svc_name(name) != TRUE) {
+		gss_release_name(&min_stat, &name);
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+static bool_t
+svcauth_gss_acquire_cred(void)
+{
+	OM_uint32	maj_stat, min_stat;
+
+	log_debug("in svcauth_gss_acquire_cred()");
+
+	maj_stat = gss_acquire_cred(&min_stat, svcauth_gss_name, 0,
+				    GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+				    &svcauth_gss_creds, NULL, NULL);
+	
+	if (maj_stat != GSS_S_COMPLETE) {
+		log_status("gss_acquire_cred", maj_stat, min_stat);
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+static bool_t
+svcauth_gss_release_cred(void)
+{
+	OM_uint32	maj_stat, min_stat;
+	
+	log_debug("in svcauth_gss_release_cred()");
+	
+	maj_stat = gss_release_cred(&min_stat, &svcauth_gss_creds);
+	
+	if (maj_stat != GSS_S_COMPLETE) {
+		log_status("gss_release_cred", maj_stat, min_stat);
+		return (FALSE);
+	}
+	
+	svcauth_gss_creds = NULL;
+	
+	return (TRUE);
+}
+
+static bool_t
+svcauth_gss_accept_sec_context(struct svc_req *rqst,
+			       struct rpc_gss_init_res *gr)
+{
+	struct svc_rpc_gss_data	*gd;
+	struct rpc_gss_cred	*gc;
+	gss_buffer_desc		 recv_tok, seqbuf;
+	gss_OID			 mech;
+	OM_uint32		 maj_stat = 0, min_stat = 0, ret_flags, seq;
+
+	log_debug("in svcauth_gss_accept_context()");
+	
+	gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
+	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
+	memset(gr, 0, sizeof(*gr));
+
+	/* Deserialize arguments. */
+	memset(&recv_tok, 0, sizeof(recv_tok));
+	
+	if (!svc_getargs(rqst->rq_xprt, xdr_rpc_gss_init_args,
+			 (caddr_t)&recv_tok))
+		return (FALSE);
+
+	gr->gr_major = gss_accept_sec_context(&gr->gr_minor,
+					      &gd->ctx,
+					      svcauth_gss_creds,
+					      &recv_tok,
+					      GSS_C_NO_CHANNEL_BINDINGS,
+					      &gd->client_name,
+					      &mech,
+					      &gr->gr_token,
+					      &ret_flags,
+					      NULL,
+					      NULL);
+
+	svc_freeargs(rqst->rq_xprt, xdr_rpc_gss_init_args, (caddr_t)&recv_tok);
+
+	log_status("accept_sec_context", gr->gr_major, gr->gr_minor);
+	if (gr->gr_major != GSS_S_COMPLETE &&
+	    gr->gr_major != GSS_S_CONTINUE_NEEDED) {
+		if (log_badauth != NULL) {
+			(*log_badauth)(gr->gr_major,
+				       gr->gr_minor,
+				       &rqst->rq_xprt->xp_raddr,
+				       log_badauth_data);
+		}
+		gd->ctx = GSS_C_NO_CONTEXT;
+		goto errout;
+	}
+	/*
+	 * ANDROS: krb5 mechglue returns ctx of size 8 - two pointers, 
+	 * one to the mechanism oid, one to the internal_ctx_id
+	 */
+	if ((gr->gr_ctx.value = mem_alloc(sizeof(gss_union_ctx_id_desc))) == NULL) {
+		fprintf(stderr, "svcauth_gss_accept_context: out of memory\n");
+		goto errout;
+	}
+	memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc));
+	gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc);
+
+	/* gr->gr_win = 0x00000005; ANDROS: for debugging linux kernel version...  */
+	gr->gr_win = sizeof(gd->seqmask) * 8;
+	
+	/* Save client info. */
+	gd->sec.mech = mech;
+	gd->sec.qop = GSS_C_QOP_DEFAULT;
+	gd->sec.svc = gc->gc_svc;
+	gd->seq = gc->gc_seq;
+	gd->win = gr->gr_win;
+
+	if (gr->gr_major == GSS_S_COMPLETE) {
+#ifdef SPKM
+		/* spkm3: no src_name (anonymous) */
+		if(!g_OID_equal(gss_mech_spkm3, mech)) {
+#endif
+		    maj_stat = gss_display_name(&min_stat, gd->client_name,
+					    &gd->cname, &gd->sec.mech);
+#ifdef SPKM
+		}	
+#endif
+		if (maj_stat != GSS_S_COMPLETE) {
+			log_status("display_name", maj_stat, min_stat);
+			goto errout;
+		}
+#ifdef DEBUG
+#ifdef HAVE_HEIMDAL
+		log_debug("accepted context for %.*s with "
+			  "<mech {}, qop %d, svc %d>",
+			  gd->cname.length, (char *)gd->cname.value,
+			  gd->sec.qop, gd->sec.svc);
+#else
+		{
+			gss_buffer_desc mechname;
+
+			gss_oid_to_str(&min_stat, mech, &mechname);
+			
+			log_debug("accepted context for %.*s with "
+				  "<mech %.*s, qop %d, svc %d>",
+				  gd->cname.length, (char *)gd->cname.value,
+				  mechname.length, (char *)mechname.value,
+				  gd->sec.qop, gd->sec.svc);
+
+			gss_release_buffer(&min_stat, &mechname);
+		}
+#endif
+#endif /* DEBUG */
+		seq = htonl(gr->gr_win);
+		seqbuf.value = &seq;
+		seqbuf.length = sizeof(seq);
+
+		gss_release_buffer(&min_stat, &gd->checksum);
+		maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT,
+				    &seqbuf, &gd->checksum);
+
+		if (maj_stat != GSS_S_COMPLETE) {
+			goto errout;
+		}
+		
+		
+		rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
+		rqst->rq_xprt->xp_verf.oa_base = gd->checksum.value;
+		rqst->rq_xprt->xp_verf.oa_length = gd->checksum.length;
+	}
+	return (TRUE);
+errout:
+	gss_release_buffer(&min_stat, &gr->gr_token);
+	return (FALSE);
+}
+
+static bool_t
+svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd, struct rpc_msg *msg)
+{
+	struct opaque_auth	*oa;
+	gss_buffer_desc		 rpcbuf, checksum;
+	OM_uint32		 maj_stat, min_stat, qop_state;
+	u_char			 rpchdr[128];
+	int32_t			*buf;
+
+	log_debug("in svcauth_gss_validate()");
+	
+	memset(rpchdr, 0, sizeof(rpchdr));
+
+	/* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */
+	buf = (int32_t *)(void *)rpchdr;
+	IXDR_PUT_LONG(buf, msg->rm_xid);
+	IXDR_PUT_ENUM(buf, msg->rm_direction);
+	IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
+	IXDR_PUT_LONG(buf, msg->rm_call.cb_prog);
+	IXDR_PUT_LONG(buf, msg->rm_call.cb_vers);
+	IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
+	oa = &msg->rm_call.cb_cred;
+	IXDR_PUT_ENUM(buf, oa->oa_flavor);
+	IXDR_PUT_LONG(buf, oa->oa_length);
+	if (oa->oa_length) {
+		memcpy((caddr_t)buf, oa->oa_base, oa->oa_length);
+		buf += RNDUP(oa->oa_length) / sizeof(int32_t);
+	}
+	rpcbuf.value = rpchdr;
+	rpcbuf.length = (u_char *)buf - rpchdr;
+
+	checksum.value = msg->rm_call.cb_verf.oa_base;
+	checksum.length = msg->rm_call.cb_verf.oa_length;
+	
+	maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum,
+				  &qop_state);
+	
+	if (maj_stat != GSS_S_COMPLETE) {
+		log_status("gss_verify_mic", maj_stat, min_stat);
+		if (log_badverf != NULL)
+			(*log_badverf)(gd->client_name,
+			       svcauth_gss_name,
+			       rqst, msg, log_badverf_data);
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+static bool_t
+svcauth_gss_nextverf(struct svc_req *rqst, u_int num)
+{
+	struct svc_rpc_gss_data	*gd;
+	gss_buffer_desc		 signbuf;
+	OM_uint32		 maj_stat, min_stat;
+
+	log_debug("in svcauth_gss_nextverf()");
+
+	if (rqst->rq_xprt->xp_auth == NULL)
+		return (FALSE);
+	
+	gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
+
+	gss_release_buffer(&min_stat, &gd->checksum);
+
+	signbuf.value = #
+	signbuf.length = sizeof(num);
+
+	maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop,
+			       &signbuf, &gd->checksum);
+
+	if (maj_stat != GSS_S_COMPLETE) {
+		log_status("gss_get_mic", maj_stat, min_stat);
+		return (FALSE);
+	}
+	rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
+	rqst->rq_xprt->xp_verf.oa_base = (caddr_t)gd->checksum.value;
+	rqst->rq_xprt->xp_verf.oa_length = (u_int)gd->checksum.length;
+	
+	return (TRUE);
+}
+
+enum auth_stat
+gssrpc__svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg,
+	bool_t *no_dispatch)
+{
+	enum auth_stat		 retstat;
+	XDR	 		 xdrs;
+	SVCAUTH			*auth;
+	struct svc_rpc_gss_data	*gd;
+	struct rpc_gss_cred	*gc;
+	struct rpc_gss_init_res	 gr;
+	int			 call_stat, offset;
+	OM_uint32		 min_stat;
+
+	log_debug("in svcauth_gss()");
+	
+	/* Initialize reply. */
+	rqst->rq_xprt->xp_verf = gssrpc__null_auth;
+
+	/* Allocate and set up server auth handle. */
+	if (rqst->rq_xprt->xp_auth == NULL ||
+	    rqst->rq_xprt->xp_auth == &svc_auth_none) {
+		if ((auth = calloc(sizeof(*auth), 1)) == NULL) {
+			fprintf(stderr, "svcauth_gss: out_of_memory\n");
+			return (AUTH_FAILED);
+		}
+		if ((gd = calloc(sizeof(*gd), 1)) == NULL) {
+			fprintf(stderr, "svcauth_gss: out_of_memory\n");
+			return (AUTH_FAILED);
+		}
+		auth->svc_ah_ops = &svc_auth_gss_ops;
+		SVCAUTH_PRIVATE(auth) = gd;
+		rqst->rq_xprt->xp_auth = auth;
+	}
+	else gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
+
+	log_debug("xp_auth=%p, gd=%p", rqst->rq_xprt->xp_auth, gd);
+
+	/* Deserialize client credentials. */
+	if (rqst->rq_cred.oa_length <= 0)
+		return (AUTH_BADCRED);
+	
+	gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
+	memset(gc, 0, sizeof(*gc));
+
+	log_debug("calling xdrmem_create()");
+	log_debug("oa_base=%p, oa_length=%u", rqst->rq_cred.oa_base,
+		  rqst->rq_cred.oa_length);
+	xdrmem_create(&xdrs, rqst->rq_cred.oa_base,
+		      rqst->rq_cred.oa_length, XDR_DECODE);
+	log_debug("xdrmem_create() returned");
+	
+	if (!xdr_rpc_gss_cred(&xdrs, gc)) {
+		log_debug("xdr_rpc_gss_cred() failed");
+		XDR_DESTROY(&xdrs);
+		return (AUTH_BADCRED);
+	}
+	XDR_DESTROY(&xdrs);
+
+	retstat = AUTH_FAILED;
+
+#define ret_freegc(code) do { retstat = code; goto freegc; } while (0)
+
+	/* Check version. */
+	if (gc->gc_v != RPCSEC_GSS_VERSION)
+		ret_freegc (AUTH_BADCRED);
+
+	/* Check RPCSEC_GSS service. */
+	if (gc->gc_svc != RPCSEC_GSS_SVC_NONE &&
+	    gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY &&
+	    gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY)
+		ret_freegc (AUTH_BADCRED);
+
+	/* Check sequence number. */
+	if (gd->established) {
+		if (gc->gc_seq > MAXSEQ)
+			ret_freegc (RPCSEC_GSS_CTXPROBLEM);
+
+		if ((offset = gd->seqlast - gc->gc_seq) < 0) {
+			gd->seqlast = gc->gc_seq;
+			offset = 0 - offset;
+			gd->seqmask <<= offset;
+			offset = 0;
+		}
+		else if (offset >= gd->win || (gd->seqmask & (1 << offset))) {
+			*no_dispatch = 1;
+			ret_freegc (RPCSEC_GSS_CTXPROBLEM);
+		}
+		gd->seq = gc->gc_seq;
+		gd->seqmask |= (1 << offset);
+	}
+	
+	if (gd->established) {
+		rqst->rq_clntname = (char *)gd->client_name;
+		rqst->rq_svccred = (char *)gd->ctx;
+	}
+
+	/* Handle RPCSEC_GSS control procedure. */
+	switch (gc->gc_proc) {
+
+	case RPCSEC_GSS_INIT:
+	case RPCSEC_GSS_CONTINUE_INIT:
+		if (rqst->rq_proc != NULLPROC)
+			ret_freegc (AUTH_FAILED);		/* XXX ? */
+
+		if (!svcauth_gss_acquire_cred())
+			ret_freegc (AUTH_FAILED);
+		
+		if (!svcauth_gss_accept_sec_context(rqst, &gr))
+			ret_freegc (AUTH_REJECTEDCRED);
+
+		if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) {
+			gss_release_buffer(&min_stat, &gr.gr_token);
+			mem_free(gr.gr_ctx.value,
+				 sizeof(gss_union_ctx_id_desc));
+			ret_freegc (AUTH_FAILED);
+		}
+		*no_dispatch = TRUE;
+		
+		call_stat = svc_sendreply(rqst->rq_xprt, xdr_rpc_gss_init_res,
+					  (caddr_t)&gr);
+
+		gss_release_buffer(&min_stat, &gr.gr_token);
+		gss_release_buffer(&min_stat, &gd->checksum);
+		mem_free(gr.gr_ctx.value, sizeof(gss_union_ctx_id_desc));
+		if (!call_stat)
+			ret_freegc (AUTH_FAILED);
+
+		if (gr.gr_major == GSS_S_COMPLETE)
+			gd->established = TRUE;
+		
+		break;
+		
+	case RPCSEC_GSS_DATA:
+		if (!svcauth_gss_validate(rqst, gd, msg))
+			ret_freegc (RPCSEC_GSS_CREDPROBLEM);
+		
+		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
+ 			ret_freegc (AUTH_FAILED);
+		break;
+		
+	case RPCSEC_GSS_DESTROY:
+		if (rqst->rq_proc != NULLPROC)
+			ret_freegc (AUTH_FAILED);		/* XXX ? */
+
+		if (!svcauth_gss_validate(rqst, gd, msg))
+			ret_freegc (RPCSEC_GSS_CREDPROBLEM);
+		
+		if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
+			ret_freegc (AUTH_FAILED);
+
+		*no_dispatch = TRUE;
+
+		call_stat = svc_sendreply(rqst->rq_xprt,
+					  xdr_void, (caddr_t)NULL);
+
+		log_debug("sendreply in destroy: %d", call_stat);
+
+		if (!svcauth_gss_release_cred())
+			ret_freegc (AUTH_FAILED);
+			
+		SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth);
+		rqst->rq_xprt->xp_auth = &svc_auth_none;
+
+		break;
+
+	default:
+		ret_freegc (AUTH_REJECTEDCRED);
+		break;
+	}
+	retstat = AUTH_OK;
+freegc:
+	xdr_free(xdr_rpc_gss_cred, gc);
+	log_debug("returning %d from svcauth_gss()", retstat);
+	return (retstat);
+}
+
+static bool_t
+svcauth_gss_destroy(SVCAUTH *auth)
+{
+	struct svc_rpc_gss_data	*gd;
+	OM_uint32		 min_stat;
+
+	log_debug("in svcauth_gss_destroy()");
+	
+	gd = SVCAUTH_PRIVATE(auth);
+	
+	gss_delete_sec_context(&min_stat, &gd->ctx, GSS_C_NO_BUFFER);
+	gss_release_buffer(&min_stat, &gd->cname);
+	gss_release_buffer(&min_stat, &gd->checksum);
+
+	if (gd->client_name)
+		gss_release_name(&min_stat, &gd->client_name);
+
+	mem_free(gd, sizeof(*gd));
+	mem_free(auth, sizeof(*auth));
+	
+	return (TRUE);
+}
+
+static bool_t
+svcauth_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+	struct svc_rpc_gss_data	*gd;
+	
+	log_debug("in svcauth_gss_wrap()");
+
+	gd = SVCAUTH_PRIVATE(auth);
+	
+	if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
+		return ((*xdr_func)(xdrs, xdr_ptr));
+	}
+	return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
+				 gd->ctx, gd->sec.qop,
+				 gd->sec.svc, gd->seq));
+}
+
+static bool_t
+svcauth_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
+{
+	struct svc_rpc_gss_data	*gd;
+
+	log_debug("in svcauth_gss_unwrap()");
+	
+	gd = SVCAUTH_PRIVATE(auth);
+
+	if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) {
+		return ((*xdr_func)(xdrs, xdr_ptr));
+	}
+	return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
+				 gd->ctx, gd->sec.qop,
+				 gd->sec.svc, gd->seq));
+}
+
+char *
+svcauth_gss_get_principal(SVCAUTH *auth)
+{
+	struct svc_rpc_gss_data *gd;
+	char *pname;
+
+	gd = SVCAUTH_PRIVATE(auth);
+
+	if (gd->cname.length == 0)
+		return (NULL);
+
+	if ((pname = malloc(gd->cname.length + 1)) == NULL)
+		return (NULL);
+
+	memcpy(pname, gd->cname.value, gd->cname.length);
+	pname[gd->cname.length] = '\0';
+
+	return (pname);
+}
+
+/*
+ * Function: svcauth_gss_set_log_badauth_func
+ *
+ * Purpose: sets the logging function called when an invalid RPC call
+ * arrives
+ *
+ * See functional specifications.
+ */
+void svcauth_gss_set_log_badauth_func(
+	auth_gssapi_log_badauth_func func,
+	caddr_t data)
+{
+	log_badauth = func;
+	log_badauth_data = data;
+}
+
+/*
+ * Function: svcauth_gss_set_log_badverf_func
+ *
+ * Purpose: sets the logging function called when an invalid RPC call
+ * arrives
+ *
+ * See functional specifications.
+ */
+void svcauth_gss_set_log_badverf_func(
+	auth_gssapi_log_badverf_func func,
+	caddr_t data)
+{
+	log_badverf = func;
+	log_badverf_data = data;
+}
+
+/*
+ * Function: svcauth_gss_set_log_miscerr_func
+ *
+ * Purpose: sets the logging function called when a miscellaneous
+ * AUTH_GSSAPI error occurs
+ *
+ * See functional specifications.
+ */
+void svcauth_gss_set_log_miscerr_func(
+	auth_gssapi_log_miscerr_func func,
+	caddr_t data)
+{
+	log_miscerr = func;
+	log_miscerr_data = data;
+}
diff --git a/mechglue/src/lib/rpc/svc_auth_gssapi.c b/mechglue/src/lib/rpc/svc_auth_gssapi.c
new file mode 100644
index 000000000..7ddefe5e8
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_auth_gssapi.c
@@ -0,0 +1,1094 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ *
+ */
+
+/*
+ * svc_auth_gssapi.c
+ * Handles the GSS-API flavor authentication parameters on the service
+ * side of RPC.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <gssrpc/rpc.h>
+#include <sys/stat.h>
+
+#include <gssapi/gssapi_generic.h>
+#include <gssrpc/auth_gssapi.h>
+
+#ifdef GSS_BACKWARD_HACK
+#include <gssapi/gssapi_krb5.h>
+#endif
+
+#ifdef GSSAPI_KRB5
+/* This is here for the krb5_error_code typedef and the
+   KRB5KRB_AP_WRONG_PRINC #define.*/
+#include <krb5.h>
+#endif
+
+#include <sys/file.h>
+#include <fcntl.h>
+
+#define INITIATION_TIMEOUT 60*15 /* seconds until partially created */
+				 /* context is destroed */
+#define INDEF_EXPIRE 60*60*24	/* seconds until an context with no */
+                                /* expiration time is expired */
+
+#ifdef __CODECENTER__
+#define DEBUG_GSSAPI 1
+#endif
+
+#ifdef DEBUG_GSSAPI
+int svc_debug_gssapi = DEBUG_GSSAPI;
+#define L_PRINTF(l,args) if (svc_debug_gssapi >= l) printf args
+#define PRINTF(args) L_PRINTF(99, args)
+#define AUTH_GSSAPI_DISPLAY_STATUS(args) \
+	if (svc_debug_gssapi) auth_gssapi_display_status args
+#else
+#define PRINTF(args)
+#define L_PRINTF(l, args)
+#define AUTH_GSSAPI_DISPLAY_STATUS(args)
+#endif
+
+typedef struct _svc_auth_gssapi_data {
+     bool_t established;
+
+     gss_ctx_id_t context;
+     gss_name_t client_name, server_name;
+     gss_cred_id_t server_creds;
+
+     uint32_t expiration;
+     uint32_t seq_num;
+     uint32_t key;
+
+     SVCAUTH svcauth;
+
+     /* kludge to free verifiers on next call */
+     gss_buffer_desc prev_verf;
+} svc_auth_gssapi_data;
+
+#define SVCAUTH_PRIVATE(auth) \
+     ((svc_auth_gssapi_data *)(auth)->svc_ah_private)
+
+static bool_t	svc_auth_gssapi_wrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
+static bool_t	svc_auth_gssapi_unwrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
+static bool_t	svc_auth_gssapi_destroy(SVCAUTH *);
+
+static svc_auth_gssapi_data *create_client(void);
+static svc_auth_gssapi_data *get_client
+       (gss_buffer_t client_handle);
+static void destroy_client
+       (svc_auth_gssapi_data *client_data);
+static void clean_client(void), cleanup(void);
+static void client_expire
+       (svc_auth_gssapi_data *client_data, uint32_t exp);
+static void dump_db (char *msg);
+
+struct svc_auth_ops svc_auth_gssapi_ops = {
+     svc_auth_gssapi_wrap,
+     svc_auth_gssapi_unwrap,
+     svc_auth_gssapi_destroy
+};
+
+/*
+ * Globals!  Eeek!  Run for the hills!
+ */
+static gss_cred_id_t *server_creds_list = NULL;
+static gss_name_t *server_name_list = NULL;
+static int server_creds_count = 0;
+
+static auth_gssapi_log_badauth_func log_badauth = NULL;
+static caddr_t log_badauth_data = NULL;
+static auth_gssapi_log_badverf_func log_badverf = NULL;
+static caddr_t log_badverf_data = NULL;
+static auth_gssapi_log_miscerr_func log_miscerr = NULL;
+static caddr_t log_miscerr_data = NULL;
+
+#define LOG_MISCERR(arg) if (log_miscerr) \
+	(*log_miscerr)(rqst, msg, arg, log_miscerr_data)
+
+typedef struct _client_list {
+     svc_auth_gssapi_data *client;
+     struct _client_list *next;
+} client_list;
+
+static client_list *clients = NULL;
+
+
+enum auth_stat gssrpc__svcauth_gssapi(
+     register struct svc_req *rqst,
+     register struct rpc_msg *msg,
+     bool_t *no_dispatch)
+{
+     XDR xdrs;
+     auth_gssapi_creds creds;
+     auth_gssapi_init_arg call_arg;
+     auth_gssapi_init_res call_res;
+     gss_buffer_desc output_token, in_buf, out_buf;
+     gss_cred_id_t server_creds;
+     struct gss_channel_bindings_struct bindings, *bindp;
+     OM_uint32 gssstat, minor_stat, time_rec;
+     struct opaque_auth *cred, *verf;
+     svc_auth_gssapi_data *client_data;
+     int i;
+     enum auth_stat ret;
+     OM_uint32 ret_flags;
+     uint32_t seq_num;
+
+     PRINTF(("svcauth_gssapi: starting\n"));
+     
+     /* clean up expired entries */
+     clean_client();
+
+     /* use AUTH_NONE until there is a client_handle */
+     rqst->rq_xprt->xp_auth = &svc_auth_none;
+     
+     memset((char *) &call_res, 0, sizeof(call_res));
+     
+     cred = &msg->rm_call.cb_cred;
+     verf = &msg->rm_call.cb_verf;
+     
+     if (cred->oa_length == 0) {
+	  PRINTF(("svcauth_gssapi: empty creds, failing\n"));
+	  LOG_MISCERR("empty client credentials");
+	  ret = AUTH_BADCRED;
+	  goto error;
+     }
+
+     PRINTF(("svcauth_gssapi: decoding credentials\n"));
+     xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); 
+     memset((char *) &creds, 0, sizeof(creds));
+     if (! xdr_authgssapi_creds(&xdrs, &creds)) {
+	  PRINTF(("svcauth_gssapi: failed decoding creds\n"));
+	  LOG_MISCERR("protocol error in client credentials");
+	  xdr_free(xdr_authgssapi_creds, &creds);
+	  XDR_DESTROY(&xdrs);
+	  ret = AUTH_BADCRED;
+	  goto error;
+     }
+     XDR_DESTROY(&xdrs);
+
+     PRINTF(("svcauth_gssapi: got credentials, version %d, client_handle len %d\n",
+	     creds.version, (int) creds.client_handle.length));
+
+     if (creds.version != 2) {
+ 	  PRINTF(("svcauth_gssapi: bad credential version\n"));
+ 	  LOG_MISCERR("unsupported client credentials version");
+ 	  ret = AUTH_BADCRED;
+ 	  goto error;
+     }
+
+#ifdef DEBUG_GSSAPI
+     if (svc_debug_gssapi) {
+	  if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_EXIT) {
+	       PRINTF(("svcauth_gssapi: GSSAPI_EXIT, cleaning up\n"));
+	       svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
+	       xdr_free(xdr_authgssapi_creds, &creds);
+	       cleanup();
+	       exit(0);
+	  }
+     }
+#endif
+	  
+     /*
+      * If this is an auth_msg and proc is GSSAPI_INIT, then create a
+      * client handle for this client.  Otherwise, look up the
+      * existing handle.
+      */
+     if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_INIT) {
+	  if (creds.client_handle.length != 0) {
+	       PRINTF(("svcauth_gssapi: non-empty handle on GSSAPI_INIT\n"));
+	       LOG_MISCERR("protocol error in client handle");
+	       ret = AUTH_FAILED;
+	       goto error;
+	  }
+	       
+	  PRINTF(("svcauth_gssapi: GSSAPI_INIT, creating client.\n"));
+	  
+	  client_data = create_client();
+	  if (client_data == NULL) {
+	       PRINTF(("svcauth_gssapi: create_client failed\n"));
+	       LOG_MISCERR("internal error creating client record");
+	       ret = AUTH_FAILED;
+	       goto error;
+	  }
+     } else {
+	  if (creds.client_handle.length == 0) {
+	       PRINTF(("svcauth_gssapi: expected non-empty creds\n"));
+	       LOG_MISCERR("protocol error in client credentials");
+	       ret = AUTH_FAILED;
+	       goto error;
+	  }
+	  
+	  PRINTF(("svcauth_gssapi: incoming client_handle %d, len %d\n", 
+		  *((uint32_t *) creds.client_handle.value),
+		  (int) creds.client_handle.length));
+
+	  client_data = get_client(&creds.client_handle);
+	  if (client_data == NULL) {
+	       PRINTF(("svcauth_gssapi: client_handle lookup failed\n"));
+	       LOG_MISCERR("invalid client handle received");
+	       ret = AUTH_BADCRED;
+	       goto error;
+	  }
+	  PRINTF(("svcauth_gssapi: client_handle lookup succeeded\n"));
+     }
+
+     /* any response we send will use client_handle, so set it now */
+     call_res.client_handle.length = sizeof(client_data->key);
+     call_res.client_handle.value = (char *) &client_data->key;
+     
+     /* mark this call as using AUTH_GSSAPI via client_data's SVCAUTH */
+     rqst->rq_xprt->xp_auth = &client_data->svcauth;
+
+     if (client_data->established == FALSE) {
+	  PRINTF(("svcauth_gssapi: context is not established\n"));
+
+	  if (creds.auth_msg == FALSE) {
+	       PRINTF(("svcauth_gssapi: expected auth_msg TRUE\n"));
+	       LOG_MISCERR("protocol error on incomplete connection");
+	       ret = AUTH_REJECTEDCRED;
+	       goto error;
+	  }
+
+	  /*
+	   * If the context is not established, then only GSSAPI_INIT
+	   * and _CONTINUE requests are valid.
+	   */
+	  if (rqst->rq_proc != AUTH_GSSAPI_INIT && rqst->rq_proc !=
+	      AUTH_GSSAPI_CONTINUE_INIT) {
+	       PRINTF(("svcauth_gssapi: unacceptable procedure %d\n",
+		       rqst->rq_proc));
+	       LOG_MISCERR("protocol error on incomplete connection");
+	       ret = AUTH_FAILED;
+	       goto error;
+	  }
+
+	  /* call is for us, deserialize arguments */
+	  memset(&call_arg, 0, sizeof(call_arg));
+	  if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg,
+			    &call_arg)) {
+	       PRINTF(("svcauth_gssapi: cannot decode args\n"));
+	       LOG_MISCERR("protocol error in procedure arguments");
+	       ret = AUTH_BADCRED;
+	       goto error;
+	  }
+
+	  /*
+	   * Process the call arg version number.
+	   * 
+	   * Set the krb5_gss backwards-compatibility mode based on client
+	   * version.  This controls whether the AP_REP message is
+	   * encrypted with the session key (version 2+, correct) or the
+	   * session subkey (version 1, incorrect).  This function can
+	   * never fail, so we don't bother checking its return value.
+	   */
+	  switch (call_arg.version) {
+	  case 1:
+	  case 2:
+	       LOG_MISCERR("Warning: Accepted old RPC protocol request");
+	       call_res.version = 1;
+	       break;
+	  case 3:
+	  case 4:
+	       /* 3 and 4 are essentially the same, don't bother warning */
+	       call_res.version = call_arg.version;
+	       break;
+	  default:
+	       PRINTF(("svcauth_gssapi: bad GSSAPI_INIT version\n"));
+	       LOG_MISCERR("unsupported GSSAPI_INIT version");
+	       ret = AUTH_BADCRED;
+	       goto error;
+	  }
+
+#ifdef GSS_BACKWARD_HACK
+	  krb5_gss_set_backward_mode(&minor_stat, call_arg.version == 1);
+#endif
+
+	  if (call_arg.version >= 3) {
+	       memset(&bindings, 0, sizeof(bindings));
+	       bindings.application_data.length = 0;
+	       bindings.initiator_addrtype = GSS_C_AF_INET;
+	       bindings.initiator_address.length = 4;
+	       bindings.initiator_address.value =
+		    &svc_getcaller(rqst->rq_xprt)->sin_addr.s_addr;
+
+	       if (rqst->rq_xprt->xp_laddrlen > 0) {
+		    bindings.acceptor_addrtype = GSS_C_AF_INET;
+		    bindings.acceptor_address.length = 4;
+		    bindings.acceptor_address.value =
+			 &rqst->rq_xprt->xp_laddr.sin_addr.s_addr;
+	       } else {
+		    LOG_MISCERR("cannot get local address");
+		    ret = AUTH_FAILED;
+		    goto error;
+	       }
+
+
+	       bindp = &bindings;
+	  } else {
+	       bindp = GSS_C_NO_CHANNEL_BINDINGS;
+	  }
+
+	  /*
+	   * If the client's server_creds is already set, use it.
+	   * Otherwise, try each credential in server_creds_list until
+	   * one of them succeedes, then set the client server_creds
+	   * to that.  If all fail, the client's server_creds isn't
+	   * set (which is fine, because the client will be gc'ed
+	   * anyway).
+	   *
+	   * If accept_sec_context returns something other than
+	   * success and GSS_S_FAILURE, then assume different
+	   * credentials won't help and stop looping.
+	   * 
+	   * Note that there are really two cases here: (1) the client
+	   * has a server_creds already, and (2) it does not.  They
+	   * are both written in the same loop so that there is only
+	   * one textual call to gss_accept_sec_context; in fact, in
+	   * case (1), the loop is executed exactly once.
+	   */
+	  for (i = 0; i < server_creds_count; i++) {
+	       if (client_data->server_creds != NULL) {
+		    PRINTF(("svcauth_gssapi: using's clients server_creds\n"));
+		    server_creds = client_data->server_creds;
+	       } else {
+		    PRINTF(("svcauth_gssapi: trying creds %d\n", i));
+		    server_creds = server_creds_list[i];
+	       }
+	       
+	       /* Free previous output_token from loop */
+	       if(i != 0) gss_release_buffer(&minor_stat, &output_token);
+
+	       call_res.gss_major =
+		    gss_accept_sec_context(&call_res.gss_minor,
+					   &client_data->context,
+					   server_creds,
+					   &call_arg.token,
+					   bindp,
+					   &client_data->client_name,
+					   NULL,
+					   &output_token,
+					   &ret_flags,
+					   &time_rec,
+					   NULL);
+
+	       if (server_creds == client_data->server_creds)
+		    break;
+
+	       if (call_res.gss_major == GSS_S_COMPLETE ||
+		   call_res.gss_major == GSS_S_CONTINUE_NEEDED) {
+		    /* server_creds was right, set it! */
+		    PRINTF(("svcauth_gssapi: creds are correct, storing\n"));
+		    client_data->server_creds = server_creds;
+		    client_data->server_name = server_name_list[i];
+		    break;
+	       } else if (call_res.gss_major != GSS_S_FAILURE
+#ifdef GSSAPI_KRB5
+			  /*
+			   * hard-coded because there is no other way
+			   * to prevent all GSS_S_FAILURES from
+			   * returning a "wrong principal in request"
+			   * error
+			   */
+			  || ((krb5_error_code) call_res.gss_minor !=
+			      (krb5_error_code) KRB5KRB_AP_WRONG_PRINC)
+#endif
+			  ) {
+		    break;
+	       }
+	  }
+	  
+	  gssstat = call_res.gss_major;
+	  minor_stat = call_res.gss_minor;
+
+	  /* done with call args */
+	  xdr_free(xdr_authgssapi_init_arg, &call_arg);
+
+	  PRINTF(("svcauth_gssapi: accept_sec_context returned %#x\n",
+		  call_res.gss_major));
+	  if (call_res.gss_major != GSS_S_COMPLETE &&
+	      call_res.gss_major != GSS_S_CONTINUE_NEEDED) {
+	       AUTH_GSSAPI_DISPLAY_STATUS(("accepting context",
+					   call_res.gss_major,
+					   call_res.gss_minor));
+
+	       if (log_badauth != NULL)
+		    (*log_badauth)(call_res.gss_major,
+				   call_res.gss_minor,
+				   &rqst->rq_xprt->xp_raddr,
+				   log_badauth_data);
+	       
+	       gss_release_buffer(&minor_stat, &output_token);
+	       svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res,
+			     (caddr_t) &call_res);
+	       *no_dispatch = TRUE;
+	       ret = AUTH_OK;
+	       goto error;
+	  }
+	      
+	  if (output_token.length != 0) {
+	       PRINTF(("svcauth_gssapi: got new output token\n"));
+	       GSS_COPY_BUFFER(call_res.token, output_token);
+	  }
+
+	  if (gssstat == GSS_S_COMPLETE) {
+	       client_data->seq_num = rand();
+	       client_expire(client_data,
+			     (time_rec == GSS_C_INDEFINITE ?
+			      INDEF_EXPIRE : time_rec) + time(0));
+
+	       PRINTF(("svcauth_gssapi: context established, isn %d\n", 
+		       client_data->seq_num));
+
+	       if (auth_gssapi_seal_seq(client_data->context,
+					client_data->seq_num,
+					&call_res.signed_isn) ==
+		   FALSE) {
+		    ret = AUTH_FAILED;
+		    LOG_MISCERR("internal error sealing sequence number");
+		    gss_release_buffer(&minor_stat, &output_token);
+		    goto error;
+	       }
+	  }
+
+	  PRINTF(("svcauth_gssapi: sending reply\n"));
+	  svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res,
+			(caddr_t) &call_res);
+	  *no_dispatch = TRUE;
+
+	  /*
+	   * If appropriate, set established to TRUE *after* sending
+	   * response (otherwise, the client will receive the final
+	   * token encrypted)
+	   */
+	  if (gssstat == GSS_S_COMPLETE) {
+	       gss_release_buffer(&minor_stat, &call_res.signed_isn);
+	       client_data->established = TRUE;
+	  }
+	  gss_release_buffer(&minor_stat, &output_token);
+     } else {
+	  PRINTF(("svcauth_gssapi: context is established\n"));
+
+	  /* check the verifier */
+	  PRINTF(("svcauth_gssapi: checking verifier, len %d\n",
+		  verf->oa_length));
+	  
+	  in_buf.length = verf->oa_length;
+	  in_buf.value = verf->oa_base;
+	  
+	  if (auth_gssapi_unseal_seq(client_data->context, &in_buf,
+				     &seq_num) == FALSE) {
+	       ret = AUTH_BADVERF;
+	       LOG_MISCERR("internal error unsealing sequence number");
+	       goto error;
+	  }
+	  
+	  if (seq_num != client_data->seq_num + 1) {
+	       PRINTF(("svcauth_gssapi: expected isn %d, got %d\n",
+		       client_data->seq_num + 1, seq_num));
+	       if (log_badverf != NULL)
+		    (*log_badverf)(client_data->client_name,
+				   client_data->server_name,
+				   rqst, msg, log_badverf_data);
+	       
+	       ret = AUTH_REJECTEDVERF;
+	       goto error;
+	  }
+	  client_data->seq_num++;
+	  
+	  PRINTF(("svcauth_gssapi: seq_num %d okay\n", seq_num));
+
+	  /* free previous response verifier, if any */
+	  if (client_data->prev_verf.length != 0) {
+	       gss_release_buffer(&minor_stat, &client_data->prev_verf);
+	       client_data->prev_verf.length = 0;
+	  }
+	  
+	  /* prepare response verifier */
+	  seq_num = client_data->seq_num + 1;
+	  if (auth_gssapi_seal_seq(client_data->context, seq_num,
+				   &out_buf) == FALSE) {
+	       ret = AUTH_FAILED;
+	       LOG_MISCERR("internal error sealing sequence number");
+	       goto error;
+	  }
+	  
+	  client_data->seq_num++;
+	  
+	  PRINTF(("svcauth_gssapi; response seq_num %d\n", seq_num));
+	  
+	  rqst->rq_xprt->xp_verf.oa_flavor = AUTH_GSSAPI;
+	  rqst->rq_xprt->xp_verf.oa_base = out_buf.value; 
+	  rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
+
+	  /* save verifier so it can be freed next time */
+	  client_data->prev_verf.value = out_buf.value; 
+	  client_data->prev_verf.length = out_buf.length;
+
+	  /*
+	   * Message is authentic.  If auth_msg if true, process the
+	   * call; otherwise, return AUTH_OK so it will be dispatched
+	   * to the application server.
+	   */
+
+	  if (creds.auth_msg == TRUE) {
+	       /*
+		* If process_token fails, then the token probably came
+		* from an attacker.  No response (error or otherwise)
+		* should be returned to the client, since it won't be
+		* accepting one.
+		*/
+
+	       switch (rqst->rq_proc) {
+	       case AUTH_GSSAPI_MSG:
+		    PRINTF(("svcauth_gssapi: GSSAPI_MSG, getting args\n"));
+		    memset(&call_arg, 0, sizeof(call_arg));
+		    if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg,
+				      &call_arg)) {
+			 PRINTF(("svcauth_gssapi: cannot decode args\n"));
+			 LOG_MISCERR("protocol error in call arguments");
+			 xdr_free(xdr_authgssapi_init_arg, &call_arg);
+			 ret = AUTH_BADCRED;
+			 goto error;
+		    }
+
+		    PRINTF(("svcauth_gssapi: processing token\n"));
+		    gssstat = gss_process_context_token(&minor_stat,
+							client_data->context,
+							&call_arg.token);
+
+		    /* done with call args */
+		    xdr_free(xdr_authgssapi_init_arg, &call_arg);
+		    
+		    if (gssstat != GSS_S_COMPLETE) {
+			 AUTH_GSSAPI_DISPLAY_STATUS(("processing token",
+						     gssstat, minor_stat));
+			 ret = AUTH_FAILED;
+			 goto error;
+		    }
+
+		    svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
+		    *no_dispatch = TRUE;
+		    break;
+
+	       case AUTH_GSSAPI_DESTROY:
+		    PRINTF(("svcauth_gssapi: GSSAPI_DESTROY\n"));
+		    
+		    PRINTF(("svcauth_gssapi: sending reply\n"));
+		    svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
+		    *no_dispatch = TRUE;
+
+		    destroy_client(client_data);
+		    rqst->rq_xprt->xp_auth = NULL;
+		    break;
+
+	       default:
+		    PRINTF(("svcauth_gssapi: unacceptable procedure %d\n",
+			    rqst->rq_proc));
+		    LOG_MISCERR("invalid call procedure number");
+		    ret = AUTH_FAILED;
+		    goto error;
+	       }
+	  } else {
+	       /* set credentials for app server; comment in svc.c */
+	       /* seems to imply this is incorrect, but I don't see */
+	       /* any problem with it... */
+	       rqst->rq_clntcred = (char *)client_data->client_name;
+	       rqst->rq_svccred = (char *)client_data->context;
+	  }
+     }
+
+     if (creds.client_handle.length != 0) {
+	  PRINTF(("svcauth_gssapi: freeing client_handle len %d\n",
+		  (int) creds.client_handle.length));
+	  xdr_free(xdr_authgssapi_creds, &creds);
+     }
+     
+     PRINTF(("\n"));
+     return AUTH_OK;
+
+error:
+     if (creds.client_handle.length != 0) {
+	  PRINTF(("svcauth_gssapi: freeing client_handle len %d\n",
+		  (int) creds.client_handle.length));
+	  xdr_free(xdr_authgssapi_creds, &creds);
+     }
+     
+     PRINTF(("\n"));
+     return ret;
+}
+
+static void cleanup(void)
+{
+     client_list *c, *c2;
+
+     PRINTF(("cleanup_and_exit: starting\n"));
+
+     c = clients;
+     while (c) {
+	  c2 = c;
+	  c = c->next;
+	  destroy_client(c2->client);
+	  free(c2);
+     }
+
+     exit(0);
+}     
+
+/*
+ * Function: create_client
+ *
+ * Purpose: Creates an new client_data structure and stores it in the
+ * database.
+ *
+ * Returns: the new client_data structure, or NULL on failure.
+ *
+ * Effects:
+ * 
+ * A new client_data is created and stored in the hash table and
+ * b-tree.  A new key that is unique in the current database is
+ * chosen; this key should be used as the client's client_handle.
+ */
+static svc_auth_gssapi_data *create_client(void)
+{
+     client_list *c;
+     svc_auth_gssapi_data *client_data;
+     static int client_key = 1;
+     
+     PRINTF(("svcauth_gssapi: empty creds, creating\n"));
+
+     client_data = (svc_auth_gssapi_data *) malloc(sizeof(*client_data));
+     if (client_data == NULL)
+	  return NULL;
+     memset((char *) client_data, 0, sizeof(*client_data));
+     L_PRINTF(2, ("create_client: new client_data = %p\n", 
+		  (void *) client_data));
+     
+     /* set up client data structure */
+     client_data->established = 0;
+     client_data->context = GSS_C_NO_CONTEXT;
+     client_data->expiration = time(0) + INITIATION_TIMEOUT;
+     
+     /* set up psycho-recursive SVCAUTH hack */
+     client_data->svcauth.svc_ah_ops = &svc_auth_gssapi_ops;
+     client_data->svcauth.svc_ah_private = (caddr_t) client_data;
+
+     client_data->key = client_key++;
+     
+     c = (client_list *) malloc(sizeof(client_list));
+     if (c == NULL)
+	  return NULL;
+     c->client = client_data;
+     c->next = NULL;
+     
+     
+     if (clients == NULL)
+	  clients = c;
+     else {
+	  c->next = clients;
+	  clients = c;
+     }
+     
+     PRINTF(("svcauth_gssapi: new handle %d\n", client_data->key));
+     L_PRINTF(2, ("create_client: done\n"));
+
+     return client_data;
+}
+
+/*
+ * Function: client_expire
+ *
+ * Purpose: change the expiration time of a client in the database
+ *
+ * Arguments:
+ *
+ * 	client_data	(r) the client_data to expire
+ * 	exp		(r) the new expiration time
+ *
+ * Effects:
+ *
+ * client_data->expiration = exp
+ *
+ * This function used to remove client_data from the database, change
+ * its expiration time, and re-add it, which was necessary because the
+ * database was sorted by expiration time so a simple modification
+ * would break the rep invariant.  Now the database is an unsorted
+ * linked list, so it doesn't matter.
+ */
+static void client_expire(
+     svc_auth_gssapi_data *client_data,
+     uint32_t exp)
+{
+     client_data->expiration = exp;
+}
+
+/*
+ * Function get_client
+ *
+ * Purpose: retrieve a client_data structure from the database based
+ * on its client handle (key)
+ *
+ * Arguments:
+ *
+ *	client_handle	(r) the handle (key) to retrieve
+ *
+ * Effects:
+ *
+ * Searches the list and returns the client_data whose key field
+ * matches the contents of client_handle, or returns NULL if none was
+ * found.
+ */
+static svc_auth_gssapi_data *get_client(gss_buffer_t client_handle)
+{
+     client_list *c;
+     uint32_t handle;
+     
+     memcpy(&handle, client_handle->value, 4);
+     
+     L_PRINTF(2, ("get_client: looking for client %d\n", handle));
+     
+     c = clients;
+     while (c) {
+	  if (c->client->key == handle)
+	       return c->client;
+	  c = c->next;
+     }
+     
+     L_PRINTF(2, ("get_client: client_handle lookup failed\n"));
+     return NULL;
+}
+
+/*
+ * Function: destroy_client
+ *
+ * Purpose: destroys a client entry and removes it from the database
+ *
+ * Arguments:
+ *
+ *	client_data	(r) the client to be destroyed
+ *
+ * Effects:
+ *
+ * client_data->context is deleted with gss_delete_sec_context.
+ * client_data's entry in the database is destroyed.  client_data is
+ * freed.
+ */
+static void destroy_client(svc_auth_gssapi_data *client_data)
+{
+     OM_uint32 gssstat, minor_stat;
+     gss_buffer_desc out_buf;
+     client_list *c, *c2;
+
+     PRINTF(("destroy_client: destroying client_data\n"));
+     L_PRINTF(2, ("destroy_client: client_data = %p\n", (void *) client_data));
+
+#ifdef DEBUG_GSSAPI
+     if (svc_debug_gssapi >= 3)
+	  dump_db("before frees");
+#endif
+
+     /* destroy client struct even if error occurs */
+
+     gssstat = gss_delete_sec_context(&minor_stat, &client_data->context,
+				      &out_buf);
+     if (gssstat != GSS_S_COMPLETE)
+	  AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat,
+				      minor_stat));
+     
+     gss_release_buffer(&minor_stat, &out_buf);
+     gss_release_name(&minor_stat, &client_data->client_name);
+     if (client_data->prev_verf.length != 0)
+	  gss_release_buffer(&minor_stat, &client_data->prev_verf);
+
+     if (clients == NULL) {
+	  PRINTF(("destroy_client: called on empty database\n"));
+	  abort();
+     } else if (clients->client == client_data) {
+	  c = clients;
+	  clients = clients->next;
+	  free(c);
+     } else {
+	  c2 = clients;
+	  c = clients->next;
+	  while (c) {
+	       if (c->client == client_data) {
+		    c2->next = c->next;
+		    free(c);
+		    goto done;
+	       } else {
+		    c2 = c;
+		    c = c->next;
+	       }
+	  }
+	  PRINTF(("destroy_client: client_handle delete failed\n"));
+	  abort();
+     }
+     
+done:
+     
+     L_PRINTF(2, ("destroy_client: client %d destroyed\n", client_data->key));
+     
+     free(client_data);
+     
+#if 0 /*ifdef PURIFY*/
+     purify_watch_n(client_data, sizeof(*client_data), "rw");
+#endif
+}
+
+static void dump_db(char *msg)
+{
+     svc_auth_gssapi_data *client_data;
+     client_list *c;
+
+     L_PRINTF(3, ("dump_db: %s:\n", msg));
+
+     c = clients;
+     while (c) {
+	  client_data = c->client;
+	  L_PRINTF(3, ("\tclient_data = %p, exp = %d\n",
+		       (void *) client_data, client_data->expiration));
+	  c = c->next;
+     }
+
+     L_PRINTF(3, ("\n"));
+}
+
+static void clean_client(void)
+{
+     svc_auth_gssapi_data *client_data;
+     client_list *c;
+
+     PRINTF(("clean_client: starting\n"));
+
+     c = clients;
+     while (c) {
+	  client_data = c->client;
+	  
+	  L_PRINTF(2, ("clean_client: client_data = %p\n",
+		       (void *) client_data));
+	  
+	  if (client_data->expiration < time(0)) {
+	       PRINTF(("clean_client: client %d expired\n",
+		       client_data->key));
+	       destroy_client(client_data);
+	       c = clients; /* start over, just to be safe */
+	  } else {
+	       c = c->next;
+	  }
+     }
+
+     PRINTF(("clean_client: done\n"));
+}
+
+/*
+ * Function: svcauth_gssapi_set_names
+ *
+ * Purpose: Sets the list of service names for which incoming
+ * authentication requests should be honored.
+ *
+ * See functional specifications.
+ */
+bool_t svcauth_gssapi_set_names(
+     auth_gssapi_name *names,
+     int num)
+{
+     OM_uint32 gssstat, minor_stat;
+     gss_buffer_desc in_buf;
+     int i;
+     
+     if (num == 0)
+	  for (; names[num].name != NULL; num++)
+	       ;
+
+     server_creds_list = NULL;
+     server_name_list = NULL;
+     
+     server_creds_list = (gss_cred_id_t *) malloc(num*sizeof(gss_cred_id_t));
+     if (server_creds_list == NULL)
+	  goto fail;
+     server_name_list = (gss_name_t *) malloc(num*sizeof(gss_name_t));
+     if (server_name_list == NULL)
+	  goto fail;
+     
+     for (i = 0; i < num; i++) {
+	  server_name_list[i] = 0;
+	  server_creds_list[i] = 0;
+     }
+
+     server_creds_count = num;
+     
+     for (i = 0; i < num; i++) {
+	  in_buf.value = names[i].name;
+	  in_buf.length = strlen(in_buf.value) + 1;
+
+	  PRINTF(("svcauth_gssapi_set_names: importing %s\n", in_buf.value));
+
+	  gssstat = gss_import_name(&minor_stat, &in_buf, names[i].type,
+				    &server_name_list[i]); 
+     
+	  if (gssstat != GSS_S_COMPLETE) {
+	       AUTH_GSSAPI_DISPLAY_STATUS(("importing name", gssstat,
+					   minor_stat));
+	       goto fail;
+	  }
+
+	  gssstat = gss_acquire_cred(&minor_stat, server_name_list[i], 0,
+				     GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+				     &server_creds_list[i], NULL, NULL);
+	  if (gssstat != GSS_S_COMPLETE) {
+	       AUTH_GSSAPI_DISPLAY_STATUS(("acquiring credentials",
+					   gssstat, minor_stat));
+	       goto fail;
+	  }
+     }
+
+     return TRUE;
+
+fail:
+     svcauth_gssapi_unset_names();
+
+     return FALSE;
+}
+
+/* Function: svcauth_gssapi_unset_names
+ *
+ * Purpose: releases the names and credentials allocated by
+ * svcauth_gssapi_set_names
+ */
+
+void svcauth_gssapi_unset_names(void)
+{
+     int i;
+     OM_uint32 minor_stat;
+
+     if (server_creds_list) {
+	  for (i = 0; i < server_creds_count; i++)
+	       if (server_creds_list[i])
+		    gss_release_cred(&minor_stat, &server_creds_list[i]);
+	  free(server_creds_list);
+	  server_creds_list = NULL;
+	  server_creds_count = 0;
+     }
+
+     if (server_name_list) {
+	  for (i = 0; i < server_creds_count; i++)
+	       if (server_name_list[i])
+		    gss_release_name(&minor_stat, &server_name_list[i]);
+	  free(server_name_list);
+	  server_name_list = NULL;
+	  server_creds_count = 0;
+     }
+}
+
+
+/*
+ * Function: svcauth_gssapi_set_log_badauth_func
+ *
+ * Purpose: sets the logging function called when an invalid RPC call
+ * arrives
+ *
+ * See functional specifications.
+ */
+void svcauth_gssapi_set_log_badauth_func(
+     auth_gssapi_log_badauth_func func,
+     caddr_t data)
+{
+     log_badauth = func;
+     log_badauth_data = data;
+}
+
+/*
+ * Function: svcauth_gssapi_set_log_badverf_func
+ *
+ * Purpose: sets the logging function called when an invalid RPC call
+ * arrives
+ *
+ * See functional specifications.
+ */
+void svcauth_gssapi_set_log_badverf_func(
+     auth_gssapi_log_badverf_func func,
+     caddr_t data)
+{
+     log_badverf = func;
+     log_badverf_data = data;
+}
+
+/*
+ * Function: svcauth_gssapi_set_log_miscerr_func
+ *
+ * Purpose: sets the logging function called when a miscellaneous
+ * AUTH_GSSAPI error occurs
+ *
+ * See functional specifications.
+ */
+void svcauth_gssapi_set_log_miscerr_func(
+     auth_gssapi_log_miscerr_func func,
+     caddr_t data)
+{
+     log_miscerr = func;
+     log_miscerr_data = data;
+}
+
+/*
+ * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
+ * and write the result to xdrs.
+ */
+static bool_t svc_auth_gssapi_wrap(
+     SVCAUTH *auth,
+     XDR *out_xdrs,
+     bool_t (*xdr_func)(),
+     caddr_t xdr_ptr)
+{
+     OM_uint32 gssstat, minor_stat;
+
+     if (! SVCAUTH_PRIVATE(auth)->established) {
+	  PRINTF(("svc_gssapi_wrap: not established, noop\n"));
+	  return (*xdr_func)(out_xdrs, xdr_ptr);
+     } else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat,
+					SVCAUTH_PRIVATE(auth)->context,
+					SVCAUTH_PRIVATE(auth)->seq_num,
+					out_xdrs, xdr_func, xdr_ptr)) {
+	  if (gssstat != GSS_S_COMPLETE)
+	       AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments",
+					   gssstat, minor_stat));
+	  return FALSE;
+     } else
+	  return TRUE;
+}
+
+static bool_t svc_auth_gssapi_unwrap(
+     SVCAUTH *auth,
+     XDR *in_xdrs,
+     bool_t (*xdr_func)(),
+     caddr_t xdr_ptr)
+{
+     svc_auth_gssapi_data *client_data = SVCAUTH_PRIVATE(auth);
+     OM_uint32 gssstat, minor_stat;
+
+     if (! client_data->established) {
+	  PRINTF(("svc_gssapi_unwrap: not established, noop\n"));
+	  return (*xdr_func)(in_xdrs, (auth_gssapi_init_arg *)(void *) xdr_ptr);
+     } else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat,
+					  client_data->context,
+					  client_data->seq_num-1,
+					  in_xdrs, xdr_func, xdr_ptr)) {
+	  if (gssstat != GSS_S_COMPLETE)
+	       AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments",
+					   gssstat, minor_stat));
+	  return FALSE;
+     } else
+	  return TRUE;
+}
+
+static bool_t svc_auth_gssapi_destroy(SVCAUTH *auth)
+{
+     svc_auth_gssapi_data *client_data = SVCAUTH_PRIVATE(auth);
+
+     destroy_client(client_data);
+     return TRUE;
+}
diff --git a/mechglue/src/lib/rpc/svc_auth_none.c b/mechglue/src/lib/rpc/svc_auth_none.c
new file mode 100644
index 000000000..2df9580a5
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_auth_none.c
@@ -0,0 +1,75 @@
+/*
+  svc_auth_none.c
+  
+  Copyright (c) 2000 The Regents of the University of Michigan.
+  All rights reserved.
+
+  Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+  All rights reserved, all wrongs reversed.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. Neither the name of the University nor the names of its
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Id: svc_auth_none.c,v 1.1 2000/08/24 20:51:34 dugsong Exp
+ */
+
+#include <gssrpc/rpc.h>
+
+static bool_t	svcauth_none_destroy(SVCAUTH *);
+static bool_t   svcauth_none_wrap(SVCAUTH *, XDR *, xdrproc_t,
+				  caddr_t);
+
+struct svc_auth_ops svc_auth_none_ops = {
+	svcauth_none_wrap,
+	svcauth_none_wrap,
+	svcauth_none_destroy
+};
+
+SVCAUTH svc_auth_none = {
+	&svc_auth_none_ops,
+	NULL,
+};
+
+static bool_t
+svcauth_none_destroy(SVCAUTH *auth)
+{
+	return (TRUE);
+}
+
+static bool_t
+svcauth_none_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func,
+		  caddr_t xdr_ptr)
+{
+	return ((*xdr_func)(xdrs, xdr_ptr));
+}
+
+enum auth_stat
+gssrpc__svcauth_none(struct svc_req *rqst, struct rpc_msg *msg,
+		     bool_t *no_dispatch)
+{
+	rqst->rq_xprt->xp_auth = &svc_auth_none;
+	
+	return (AUTH_OK);
+}
diff --git a/mechglue/src/lib/rpc/svc_auth_unix.c b/mechglue/src/lib/rpc/svc_auth_unix.c
new file mode 100644
index 000000000..480ee7a9e
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_auth_unix.c
@@ -0,0 +1,140 @@
+/* @(#)svc_auth_unix.c	2.3 88/08/01 4.0 RPCSRC; from 1.28 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_auth_unix.c
+ * Handles UNIX flavor authentication parameters on the service side of rpc.
+ * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT.
+ * _svcauth_unix does full blown unix style uid,gid+gids auth,
+ * _svcauth_short uses a shorthand auth to index into a cache of longhand auths.
+ * Note: the shorthand has been gutted for efficiency.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <gssrpc/rpc.h>
+
+/*
+ * Unix longhand authenticator
+ */
+enum auth_stat
+gssrpc__svcauth_unix(
+	register struct svc_req *rqst,
+	register struct rpc_msg *msg,
+	bool_t *dispatch)
+{
+	register enum auth_stat stat;
+	XDR xdrs;
+	register struct authunix_parms *aup;
+	register rpc_inline_t *buf;
+	struct area {
+		struct authunix_parms area_aup;
+		char area_machname[MAX_MACHINE_NAME+1];
+		int area_gids[NGRPS];
+	} *area;
+	u_int auth_len;
+	int str_len, gid_len;
+	register int i;
+
+	rqst->rq_xprt->xp_auth = &svc_auth_none;
+	
+	area = (struct area *) rqst->rq_clntcred;
+	aup = &area->area_aup;
+	aup->aup_machname = area->area_machname;
+	aup->aup_gids = area->area_gids;
+	auth_len = (u_int)msg->rm_call.cb_cred.oa_length;
+	xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE);
+	buf = XDR_INLINE(&xdrs, (int)auth_len);
+	if (buf != NULL) {
+		aup->aup_time = IXDR_GET_LONG(buf);
+		str_len = IXDR_GET_U_LONG(buf);
+		if (str_len > MAX_MACHINE_NAME) {
+			stat = AUTH_BADCRED;
+			goto done;
+		}
+		memmove(aup->aup_machname, (caddr_t)buf, (u_int)str_len);
+		aup->aup_machname[str_len] = 0;
+		str_len = RNDUP(str_len);
+		buf += str_len / BYTES_PER_XDR_UNIT;
+		aup->aup_uid = IXDR_GET_LONG(buf);
+		aup->aup_gid = IXDR_GET_LONG(buf);
+		gid_len = IXDR_GET_U_LONG(buf);
+		if (gid_len > NGRPS) {
+			stat = AUTH_BADCRED;
+			goto done;
+		}
+		aup->aup_len = gid_len;
+		for (i = 0; i < gid_len; i++) {
+			aup->aup_gids[i] = IXDR_GET_LONG(buf);
+		}
+		/*
+		 * five is the smallest unix credentials structure -
+		 * timestamp, hostname len (0), uid, gid, and gids len (0).
+		 */
+		if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) {
+			(void) printf("bad auth_len gid %d str %d auth %d\n",
+			    gid_len, str_len, auth_len);
+			stat = AUTH_BADCRED;
+			goto done;
+		}
+	} else if (! xdr_authunix_parms(&xdrs, aup)) {
+		xdrs.x_op = XDR_FREE;
+		(void)xdr_authunix_parms(&xdrs, aup);
+		stat = AUTH_BADCRED;
+		goto done;
+	}
+	rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
+	rqst->rq_xprt->xp_verf.oa_length = 0;
+	stat = AUTH_OK;
+done:
+	XDR_DESTROY(&xdrs);
+	return (stat);
+}
+
+
+/*
+ * Shorthand unix authenticator
+ * Looks up longhand in a cache.
+ */
+/*ARGSUSED*/
+enum auth_stat 
+gssrpc__svcauth_short(
+	struct svc_req *rqst,
+	struct rpc_msg *msg,
+	bool_t *dispatch)
+{
+	rqst->rq_xprt->xp_auth = &svc_auth_none;
+	return (AUTH_REJECTEDCRED);
+}
diff --git a/mechglue/src/lib/rpc/svc_raw.c b/mechglue/src/lib/rpc/svc_raw.c
new file mode 100644
index 000000000..d2507ae8d
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_raw.c
@@ -0,0 +1,160 @@
+/* @(#)svc_raw.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_raw.c 1.15 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_raw.c,   This a toy for simple testing and timing.
+ * Interface to create an rpc client and server in the same UNIX process.
+ * This lets us similate rpc and get rpc (round trip) overhead, without
+ * any interference from the kernal.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <gssrpc/rpc.h>
+
+
+/*
+ * This is the "network" that we will be moving data over
+ */
+static struct svcraw_private {
+	char	_raw_buf[UDPMSGSIZE];
+	SVCXPRT	server;
+	XDR	xdr_stream;
+	char	verf_body[MAX_AUTH_BYTES];
+} *svcraw_private;
+
+static bool_t		svcraw_recv(SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat 	svcraw_stat(SVCXPRT *);
+static bool_t		svcraw_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t		svcraw_reply(SVCXPRT *, struct rpc_msg *);
+static bool_t		svcraw_freeargs(SVCXPRT *, xdrproc_t, void *);
+static void		svcraw_destroy(SVCXPRT *);
+
+static struct xp_ops server_ops = {
+	svcraw_recv,
+	svcraw_stat,
+	svcraw_getargs,
+	svcraw_reply,
+	svcraw_freeargs,
+	svcraw_destroy
+};
+
+SVCXPRT *
+svcraw_create(void)
+{
+	register struct svcraw_private *srp = svcraw_private;
+
+	if (srp == 0) {
+		srp = (struct svcraw_private *)calloc(1, sizeof (*srp));
+		if (srp == 0)
+			return (0);
+	}
+	srp->server.xp_sock = 0;
+	srp->server.xp_port = 0;
+	srp->server.xp_ops = &server_ops;
+	srp->server.xp_verf.oa_base = srp->verf_body;
+	xdrmem_create(&srp->xdr_stream, srp->_raw_buf, UDPMSGSIZE, XDR_FREE);
+	return (&srp->server);
+}
+
+static enum xprt_stat
+svcraw_stat(SVCXPRT *xprt)
+{
+
+	return (XPRT_IDLE);
+}
+
+static bool_t
+svcraw_recv(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+	register struct svcraw_private *srp = svcraw_private;
+	register XDR *xdrs;
+
+	if (srp == 0)
+		return (0);
+	xdrs = &srp->xdr_stream;
+	xdrs->x_op = XDR_DECODE;
+	XDR_SETPOS(xdrs, 0);
+	if (! xdr_callmsg(xdrs, msg))
+	       return (FALSE);
+	return (TRUE);
+}
+
+static bool_t
+svcraw_reply(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+	register struct svcraw_private *srp = svcraw_private;
+	register XDR *xdrs;
+
+	if (srp == 0)
+		return (FALSE);
+	xdrs = &srp->xdr_stream;
+	xdrs->x_op = XDR_ENCODE;
+	XDR_SETPOS(xdrs, 0);
+	if (! xdr_replymsg(xdrs, msg))
+	       return (FALSE);
+	(void)XDR_GETPOS(xdrs);  /* called just for overhead */
+	return (TRUE);
+}
+
+static bool_t
+svcraw_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{
+	register struct svcraw_private *srp = svcraw_private;
+
+	if (srp == 0)
+		return (FALSE);
+	if (! (*xdr_args)(&srp->xdr_stream, args_ptr)) {
+		(void)svcraw_freeargs(xprt, xdr_args, args_ptr);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static bool_t
+svcraw_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
+{ 
+	register struct svcraw_private *srp = svcraw_private;
+	register XDR *xdrs;
+
+	if (srp == 0)
+		return (FALSE);
+	xdrs = &srp->xdr_stream;
+	xdrs->x_op = XDR_FREE;
+	return ((*xdr_args)(xdrs, args_ptr));
+} 
+
+static void
+svcraw_destroy(SVCXPRT *xprt)
+{
+}
diff --git a/mechglue/src/lib/rpc/svc_run.c b/mechglue/src/lib/rpc/svc_run.c
new file mode 100644
index 000000000..b661f88b3
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_run.c
@@ -0,0 +1,74 @@
+/* @(#)svc_run.c	2.1 88/07/29 4.0 RPCSRC */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * This is the rpc server side idle loop
+ * Wait for input, call server program.
+ */
+
+#include <gssrpc/rpc.h>
+#include <errno.h>
+
+extern int svc_maxfd;
+
+void
+svc_run(void)
+{
+#ifdef FD_SETSIZE
+	fd_set readfds;
+#else
+	int readfds;
+#endif /* def FD_SETSIZE */
+
+	for (;;) {
+#ifdef FD_SETSIZE
+		readfds = svc_fdset;
+#else
+		readfds = svc_fds;
+#endif /* def FD_SETSIZE */
+		switch (select(svc_maxfd + 1, &readfds, (fd_set *)0,
+			       (fd_set *)0, (struct timeval *)0)) {
+		case -1:
+			if (errno == EINTR) {
+				continue;
+			}
+			perror("svc_run: - select failed");
+			return;
+		case 0:
+			continue;
+		default:
+			svc_getreqset(&readfds);
+		}
+	}
+}
diff --git a/mechglue/src/lib/rpc/svc_simple.c b/mechglue/src/lib/rpc/svc_simple.c
new file mode 100644
index 000000000..6ae85ce52
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_simple.c
@@ -0,0 +1,149 @@
+/* @(#)svc_simple.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/* 
+ * svc_simple.c
+ * Simplified front end to rpc.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+static struct proglst {
+	char *(*p_progname)();
+	int  p_prognum;
+	int  p_procnum;
+	xdrproc_t p_inproc, p_outproc;
+	struct proglst *p_nxt;
+} *proglst;
+static void universal(struct svc_req *, SVCXPRT *);
+static SVCXPRT *transp;
+
+int
+registerrpc(
+	rpcprog_t prognum,
+	rpcvers_t versnum,
+	rpcproc_t procnum,
+	char *(*progname)(),
+	xdrproc_t inproc,
+	xdrproc_t outproc)
+{
+        struct proglst *pl;
+	
+	if (procnum == NULLPROC) {
+		(void) fprintf(stderr,
+		    "can't reassign procedure number %d\n", NULLPROC);
+		return (-1);
+	}
+	if (transp == 0) {
+		transp = svcudp_create(RPC_ANYSOCK);
+		if (transp == NULL) {
+			(void) fprintf(stderr, "couldn't create an rpc server\n");
+			return (-1);
+		}
+	}
+	(void) pmap_unset(prognum, versnum);
+	if (!svc_register(transp, prognum, versnum, universal, IPPROTO_UDP)) {
+	    	(void) fprintf(stderr, "couldn't register prog %d vers %d\n",
+		    prognum, versnum);
+		return (-1);
+	}
+	pl = (struct proglst *)malloc(sizeof(struct proglst));
+	if (pl == NULL) {
+		(void) fprintf(stderr, "registerrpc: out of memory\n");
+		return (-1);
+	}
+	pl->p_progname = progname;
+	pl->p_prognum = prognum;
+	pl->p_procnum = procnum;
+	pl->p_inproc = inproc;
+	pl->p_outproc = outproc;
+	pl->p_nxt = proglst;
+	proglst = pl;
+	return (0);
+}
+
+static void
+universal(
+	struct svc_req *rqstp,
+	SVCXPRT *s_transp)
+{
+	int prog, proc;
+	char *outdata;
+	char xdrbuf[UDPMSGSIZE];
+	struct proglst *pl;
+
+	/* 
+	 * enforce "procnum 0 is echo" convention
+	 */
+	if (rqstp->rq_proc == NULLPROC) {
+		if (svc_sendreply(s_transp, xdr_void, (char *)NULL) == FALSE) {
+			(void) fprintf(stderr, "xxx\n");
+			exit(1);
+		}
+		return;
+	}
+	prog = rqstp->rq_prog;
+	proc = rqstp->rq_proc;
+	for (pl = proglst; pl != NULL; pl = pl->p_nxt)
+		if (pl->p_prognum == prog && pl->p_procnum == proc) {
+			/* decode arguments into a CLEAN buffer */
+			memset(xdrbuf, 0, sizeof(xdrbuf)); /* required ! */
+			if (!svc_getargs(s_transp, pl->p_inproc, xdrbuf)) {
+				svcerr_decode(s_transp);
+				return;
+			}
+			outdata = (*(pl->p_progname))(xdrbuf);
+			if (outdata == NULL && pl->p_outproc != xdr_void)
+				/* there was an error */
+				return;
+			if (!svc_sendreply(s_transp, pl->p_outproc, outdata)) {
+				(void) fprintf(stderr,
+				    "trouble replying to prog %d\n",
+				    pl->p_prognum);
+				exit(1);
+			}
+			/* free the decoded arguments */
+			(void)svc_freeargs(s_transp, pl->p_inproc, xdrbuf);
+			return;
+		}
+	(void) fprintf(stderr, "never registered prog %d\n", prog);
+	exit(1);
+}
+
diff --git a/mechglue/src/lib/rpc/svc_tcp.c b/mechglue/src/lib/rpc/svc_tcp.c
new file mode 100644
index 000000000..ce9bb35af
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_tcp.c
@@ -0,0 +1,503 @@
+/* @(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_tcp.c, Server side for TCP/IP based RPC. 
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * Actually implements two flavors of transporter -
+ * a tcp rendezvouser (a listner and connection establisher)
+ * and a record/tcp stream.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <stdlib.h>
+/*extern bool_t abort();
+extern errno;
+*/
+
+/*
+ * Ops vector for TCP/IP based rpc service handle
+ */
+static bool_t		svctcp_recv(SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat	svctcp_stat(SVCXPRT *);
+static bool_t		svctcp_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t		svctcp_reply(SVCXPRT *, struct rpc_msg *);
+static bool_t		svctcp_freeargs(SVCXPRT *, xdrproc_t, void *);
+static void		svctcp_destroy(SVCXPRT *);
+
+static struct xp_ops svctcp_op = {
+	svctcp_recv,
+	svctcp_stat,
+	svctcp_getargs,
+	svctcp_reply,
+	svctcp_freeargs,
+	svctcp_destroy
+};
+
+/*
+ * Ops vector for TCP/IP rendezvous handler
+ */
+static bool_t		rendezvous_request(SVCXPRT *, struct rpc_msg *);
+static bool_t		abortx(void);
+static bool_t		abortx_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t		abortx_reply(SVCXPRT *, struct rpc_msg *);
+static bool_t		abortx_freeargs(SVCXPRT *, xdrproc_t, void *);
+static enum xprt_stat	rendezvous_stat(SVCXPRT *);
+
+static struct xp_ops svctcp_rendezvous_op = {
+	rendezvous_request,
+	rendezvous_stat,
+	abortx_getargs,
+	abortx_reply,
+	abortx_freeargs,
+	svctcp_destroy
+};
+
+static int readtcp(char *, caddr_t, int), writetcp(char *, caddr_t, int);
+static SVCXPRT *makefd_xprt(int, u_int, u_int);
+
+struct tcp_rendezvous { /* kept in xprt->xp_p1 */
+	u_int sendsize;
+	u_int recvsize;
+};
+
+struct tcp_conn {  /* kept in xprt->xp_p1 */
+	enum xprt_stat strm_stat;
+	uint32_t x_id;
+	XDR xdrs;
+	char verf_body[MAX_AUTH_BYTES];
+};
+
+/*
+ * Usage:
+ *	xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
+ *
+ * Creates, registers, and returns a (rpc) tcp based transporter.
+ * Once *xprt is initialized, it is registered as a transporter
+ * see (svc.h, xprt_register).  This routine returns
+ * a NULL if a problem occurred.
+ *
+ * If sock<0 then a socket is created, else sock is used.
+ * If the socket, sock is not bound to a port then svctcp_create
+ * binds it to an arbitrary port.  The routine then starts a tcp
+ * listener on the socket's associated port.  In any (successful) case,
+ * xprt->xp_sock is the registered socket number and xprt->xp_port is the
+ * associated port number.
+ *
+ * Since tcp streams do buffered io similar to stdio, the caller can specify
+ * how big the send and receive buffers are via the second and third parms;
+ * 0 => use the system default.
+ */
+SVCXPRT *
+svctcp_create(
+	register int sock,
+	u_int sendsize,
+	u_int recvsize)
+{
+	bool_t madesock = FALSE;
+	register SVCXPRT *xprt;
+	register struct tcp_rendezvous *r;
+	struct sockaddr_in addr;
+	int len = sizeof(struct sockaddr_in);
+
+	if (sock == RPC_ANYSOCK) {
+		if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+			perror("svctcp_.c - udp socket creation problem");
+			return ((SVCXPRT *)NULL);
+		}
+		madesock = TRUE;
+	}
+	memset((char *)&addr, 0, sizeof (addr));
+#if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+	addr.sin_len = sizeof(addr);
+#endif
+	addr.sin_family = AF_INET;
+	if (bindresvport(sock, &addr)) {
+		addr.sin_port = 0;
+		(void)bind(sock, (struct sockaddr *)&addr, len);
+	}
+	if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
+		perror("svc_tcp.c - cannot getsockname");
+		if (madesock)
+			(void) close(sock);
+		return ((SVCXPRT *)NULL);
+	}
+	if (listen(sock, 2) != 0) {
+		perror("svctcp_.c - cannot listen");
+		if (madesock)
+			(void)close(sock);
+		return ((SVCXPRT *)NULL);
+	}
+	r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
+	if (r == NULL) {
+		(void) fprintf(stderr, "svctcp_create: out of memory\n");
+		return (NULL);
+	}
+	r->sendsize = sendsize;
+	r->recvsize = recvsize;
+	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
+	if (xprt == NULL) {
+		(void) fprintf(stderr, "svctcp_create: out of memory\n");
+		return (NULL);
+	}
+	xprt->xp_p2 = NULL;
+	xprt->xp_p1 = (caddr_t)r;
+	xprt->xp_auth = NULL;
+	xprt->xp_verf = gssrpc__null_auth;
+	xprt->xp_ops = &svctcp_rendezvous_op;
+	xprt->xp_port = ntohs(addr.sin_port);
+	xprt->xp_sock = sock;
+	xprt->xp_laddrlen = 0;
+	xprt_register(xprt);
+	return (xprt);
+}
+
+/*
+ * Like svtcp_create(), except the routine takes any *open* UNIX file
+ * descriptor as its first input.
+ */
+SVCXPRT *
+svcfd_create(
+	int fd,
+	u_int sendsize,
+	u_int recvsize)
+{
+
+	return (makefd_xprt(fd, sendsize, recvsize));
+}
+
+static SVCXPRT *
+makefd_xprt(
+	int fd,
+	u_int sendsize,
+	u_int recvsize)
+{
+	register SVCXPRT *xprt;
+	register struct tcp_conn *cd;
+ 
+	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
+	if (xprt == (SVCXPRT *)NULL) {
+		(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
+		goto done;
+	}
+	cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn));
+	if (cd == (struct tcp_conn *)NULL) {
+		(void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
+		mem_free((char *) xprt, sizeof(SVCXPRT));
+		xprt = (SVCXPRT *)NULL;
+		goto done;
+	}
+	cd->strm_stat = XPRT_IDLE;
+	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
+	    (caddr_t)xprt, readtcp, writetcp);
+	xprt->xp_p2 = NULL;
+	xprt->xp_p1 = (caddr_t)cd;
+	xprt->xp_auth = NULL;
+	xprt->xp_verf.oa_base = cd->verf_body;
+	xprt->xp_addrlen = 0;
+	xprt->xp_laddrlen = 0;
+	xprt->xp_ops = &svctcp_op;  /* truely deals with calls */
+	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
+	xprt->xp_sock = fd;
+	xprt_register(xprt);
+    done:
+	return (xprt);
+}
+
+static bool_t
+rendezvous_request(
+	register SVCXPRT *xprt,
+	struct rpc_msg *msg)
+{
+	int sock;
+	struct tcp_rendezvous *r;
+	struct sockaddr_in addr, laddr;
+	int len, llen;
+
+	r = (struct tcp_rendezvous *)xprt->xp_p1;
+    again:
+	len = llen = sizeof(struct sockaddr_in);
+	if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
+	    &len)) < 0) {
+		if (errno == EINTR)
+			goto again;
+	       return (FALSE);
+	}
+	if (getsockname(sock, &laddr, &llen) < 0)
+	     return (FALSE);
+	
+	/*
+	 * make a new transporter (re-uses xprt)
+	 */
+	xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
+	xprt->xp_raddr = addr;
+	xprt->xp_addrlen = len;
+	xprt->xp_laddr = laddr;
+	xprt->xp_laddrlen = llen;
+	return (FALSE); /* there is never an rpc msg to be processed */
+}
+
+static enum xprt_stat
+rendezvous_stat(register SVCXPRT *xprt)
+{
+
+	return (XPRT_IDLE);
+}
+
+static void
+svctcp_destroy(register SVCXPRT *xprt)
+{
+	register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
+
+	xprt_unregister(xprt);
+	(void)close(xprt->xp_sock);
+	if (xprt->xp_port != 0) {
+		/* a rendezvouser socket */
+		xprt->xp_port = 0;
+	} else {
+		/* an actual connection socket */
+		XDR_DESTROY(&(cd->xdrs));
+	}
+	if (xprt->xp_auth != NULL) {
+		SVCAUTH_DESTROY(xprt->xp_auth);
+		xprt->xp_auth = NULL;
+	}
+	mem_free((caddr_t)cd, sizeof(struct tcp_conn));
+	mem_free((caddr_t)xprt, sizeof(SVCXPRT));
+}
+
+/*
+ * All read operations timeout after 35 seconds.
+ * A timeout is fatal for the connection.
+ */
+static struct timeval wait_per_try = { 35, 0 };
+
+/*
+ * reads data from the tcp conection.
+ * any error is fatal and the connection is closed.
+ * (And a read of zero bytes is a half closed stream => error.)
+ */
+static int
+readtcp(
+        char *xprtptr,
+	caddr_t buf,
+	register int len)
+{
+	register SVCXPRT *xprt = (SVCXPRT *)(void *)xprtptr;
+	register int sock = xprt->xp_sock;
+	struct timeval tout;
+#ifdef FD_SETSIZE
+	fd_set mask;
+	fd_set readfds;
+
+	FD_ZERO(&mask);
+	FD_SET(sock, &mask);
+#else
+	register int mask = 1 << sock;
+	int readfds;
+#endif /* def FD_SETSIZE */
+#ifdef FD_SETSIZE
+#define loopcond (!FD_ISSET(sock, &readfds))
+#else
+#define loopcond (readfds != mask)
+#endif
+	do {
+		readfds = mask;
+		tout = wait_per_try;
+		if (select(sock + 1, &readfds, (fd_set*)NULL,
+			   (fd_set*)NULL, &tout) <= 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			goto fatal_err;
+		}
+	} while (loopcond);
+	if ((len = read(sock, buf, (size_t) len)) > 0) {
+		return (len);
+	}
+fatal_err:
+	((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
+	return (-1);
+}
+
+/*
+ * writes data to the tcp connection.
+ * Any error is fatal and the connection is closed.
+ */
+static int
+writetcp(
+	char *xprtptr,
+	caddr_t buf,
+	int len)
+{
+	register SVCXPRT *xprt = (SVCXPRT *)(void *) xprtptr;
+	register int i, cnt;
+
+	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
+		if ((i = write(xprt->xp_sock, buf, (size_t) cnt)) < 0) {
+			((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
+			    XPRT_DIED;
+			return (-1);
+		}
+	}
+	return (len);
+}
+
+static enum xprt_stat
+svctcp_stat(SVCXPRT *xprt)
+{
+	register struct tcp_conn *cd =
+	    (struct tcp_conn *)(xprt->xp_p1);
+
+	if (cd->strm_stat == XPRT_DIED)
+		return (XPRT_DIED);
+	if (! xdrrec_eof(&(cd->xdrs)))
+		return (XPRT_MOREREQS);
+	return (XPRT_IDLE);
+}
+
+static bool_t
+svctcp_recv(
+	SVCXPRT *xprt,
+	register struct rpc_msg *msg)
+{
+	register struct tcp_conn *cd =
+	    (struct tcp_conn *)(xprt->xp_p1);
+	register XDR *xdrs = &(cd->xdrs);
+
+	xdrs->x_op = XDR_DECODE;
+	(void)xdrrec_skiprecord(xdrs);
+	if (xdr_callmsg(xdrs, msg)) {
+		cd->x_id = msg->rm_xid;
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+static bool_t
+svctcp_getargs(
+	SVCXPRT *xprt,
+	xdrproc_t xdr_args,
+	void *args_ptr)
+{
+	if (! SVCAUTH_UNWRAP(xprt->xp_auth,
+			     &(((struct tcp_conn *)(xprt->xp_p1))->xdrs),
+			     xdr_args, args_ptr)) {
+		(void)svctcp_freeargs(xprt, xdr_args, args_ptr);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static bool_t
+svctcp_freeargs(
+	SVCXPRT *xprt,
+	xdrproc_t xdr_args,
+	void * args_ptr)
+{
+	register XDR *xdrs =
+	    &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
+
+	xdrs->x_op = XDR_FREE;
+	return ((*xdr_args)(xdrs, args_ptr));
+}
+
+static bool_t svctcp_reply(
+	SVCXPRT *xprt,
+	register struct rpc_msg *msg)
+{
+	register struct tcp_conn *cd =
+		(struct tcp_conn *)(xprt->xp_p1);
+	register XDR *xdrs = &(cd->xdrs);
+	register bool_t stat;
+     
+	xdrproc_t xdr_results;
+	caddr_t xdr_location;
+	bool_t has_args;
+
+	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+		has_args = TRUE;
+		xdr_results = msg->acpted_rply.ar_results.proc;
+		xdr_location = msg->acpted_rply.ar_results.where;
+	  
+		msg->acpted_rply.ar_results.proc = xdr_void;
+		msg->acpted_rply.ar_results.where = NULL;
+	} else
+		has_args = FALSE;
+     
+	xdrs->x_op = XDR_ENCODE;
+	msg->rm_xid = cd->x_id;
+	stat = FALSE;
+	if (xdr_replymsg(xdrs, msg) &&
+	    (!has_args ||
+	     (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) {
+		stat = TRUE;
+	}
+	(void)xdrrec_endofrecord(xdrs, TRUE);
+	return (stat);
+}
+
+static bool_t abortx(void)
+{
+	abort();
+	return 1;
+}
+
+static bool_t abortx_getargs(
+	SVCXPRT *xprt,
+	xdrproc_t proc,
+	void *info)
+{
+	return abortx();
+}
+
+static bool_t abortx_reply(SVCXPRT *xprt, struct rpc_msg *msg)
+{
+	return abortx();
+}
+
+static bool_t abortx_freeargs(
+	SVCXPRT *xprt, xdrproc_t proc,
+	void * info)
+{
+	return abortx();
+}
+
diff --git a/mechglue/src/lib/rpc/svc_udp.c b/mechglue/src/lib/rpc/svc_udp.c
new file mode 100644
index 000000000..16eb5f01a
--- /dev/null
+++ b/mechglue/src/lib/rpc/svc_udp.c
@@ -0,0 +1,530 @@
+/* @(#)svc_udp.c	2.2 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_udp.c,
+ * Server side for UDP/IP based RPC.  (Does some caching in the hopes of
+ * achieving execute-at-most-once semantics.)
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <gssrpc/rpc.h>
+#include <sys/socket.h>
+#include <errno.h>
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+
+#define rpc_buffer(xprt) ((xprt)->xp_p1)
+#ifndef MAX
+#define MAX(a, b)     ((a > b) ? a : b)
+#endif
+
+static bool_t		svcudp_recv(SVCXPRT *, struct rpc_msg *);
+static bool_t		svcudp_reply(SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat	svcudp_stat(SVCXPRT *);
+static bool_t		svcudp_getargs(SVCXPRT *, xdrproc_t, void *);
+static bool_t		svcudp_freeargs(SVCXPRT *, xdrproc_t, void *);
+static void		svcudp_destroy(SVCXPRT *);
+
+static void cache_set(SVCXPRT *, uint32_t);
+static int cache_get(SVCXPRT *, struct rpc_msg *, char **, uint32_t *);
+
+static struct xp_ops svcudp_op = {
+	svcudp_recv,
+	svcudp_stat,
+	svcudp_getargs,
+	svcudp_reply,
+	svcudp_freeargs,
+	svcudp_destroy
+};
+
+
+/*
+ * kept in xprt->xp_p2
+ */
+struct svcudp_data {
+	u_int   su_iosz;	/* byte size of send.recv buffer */
+	uint32_t	su_xid;		/* transaction id */
+	XDR	su_xdrs;	/* XDR handle */
+	char	su_verfbody[MAX_AUTH_BYTES];	/* verifier body */
+	void * 	su_cache;	/* cached data, NULL if no cache */
+};
+#define	su_data(xprt)	((struct svcudp_data *)(xprt->xp_p2))
+
+/*
+ * Usage:
+ *	xprt = svcudp_create(sock);
+ *
+ * If sock<0 then a socket is created, else sock is used.
+ * If the socket, sock is not bound to a port then svcudp_create
+ * binds it to an arbitrary port.  In any (successful) case,
+ * xprt->xp_sock is the registered socket number and xprt->xp_port is the
+ * associated port number.
+ * Once *xprt is initialized, it is registered as a transporter;
+ * see (svc.h, xprt_register).
+ * The routines returns NULL if a problem occurred.
+ */
+SVCXPRT *
+svcudp_bufcreate(
+	register int sock,
+	u_int sendsz,
+	u_int recvsz)
+{
+	bool_t madesock = FALSE;
+	register SVCXPRT *xprt;
+	register struct svcudp_data *su;
+	struct sockaddr_in addr;
+	int len = sizeof(struct sockaddr_in);
+
+	if (sock == RPC_ANYSOCK) {
+		if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+			perror("svcudp_create: socket creation problem");
+			return ((SVCXPRT *)NULL);
+		}
+		madesock = TRUE;
+	}
+	memset((char *)&addr, 0, sizeof (addr));
+#if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+	addr.sin_len = sizeof(addr);
+#endif
+	addr.sin_family = AF_INET;
+	if (bindresvport(sock, &addr)) {
+		addr.sin_port = 0;
+		(void)bind(sock, (struct sockaddr *)&addr, len);
+	}
+	if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
+		perror("svcudp_create - cannot getsockname");
+		if (madesock)
+			(void)close(sock);
+		return ((SVCXPRT *)NULL);
+	}
+	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
+	if (xprt == NULL) {
+		(void)fprintf(stderr, "svcudp_create: out of memory\n");
+		return (NULL);
+	}
+	su = (struct svcudp_data *)mem_alloc(sizeof(*su));
+	if (su == NULL) {
+		(void)fprintf(stderr, "svcudp_create: out of memory\n");
+		return (NULL);
+	}
+	su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
+	if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) {
+		(void)fprintf(stderr, "svcudp_create: out of memory\n");
+		return (NULL);
+	}
+	xdrmem_create(
+	    &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE);
+	su->su_cache = NULL;
+	xprt->xp_p2 = (caddr_t)su;
+	xprt->xp_auth = NULL;
+	xprt->xp_verf.oa_base = su->su_verfbody;
+	xprt->xp_ops = &svcudp_op;
+	xprt->xp_port = ntohs(addr.sin_port);
+	xprt->xp_sock = sock;
+	xprt_register(xprt);
+	return (xprt);
+}
+
+SVCXPRT *
+svcudp_create(int sock)
+{
+
+	return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE));
+}
+
+static enum xprt_stat
+svcudp_stat(SVCXPRT *xprt)
+{
+
+	return (XPRT_IDLE); 
+}
+
+static bool_t
+svcudp_recv(
+	register SVCXPRT *xprt,
+	struct rpc_msg *msg)
+{
+        struct msghdr dummy;
+	struct iovec dummy_iov[1];
+	register struct svcudp_data *su = su_data(xprt);
+	register XDR *xdrs = &(su->su_xdrs);
+	register int rlen;
+	char *reply;
+	uint32_t replylen;
+
+    again:
+	memset((char *) &dummy, 0, sizeof(dummy));
+	dummy_iov[0].iov_base = rpc_buffer(xprt);
+	dummy_iov[0].iov_len = (int) su->su_iosz;
+	dummy.msg_iov = dummy_iov;
+	dummy.msg_iovlen = 1;
+	dummy.msg_namelen = xprt->xp_laddrlen = sizeof(struct sockaddr_in);
+	dummy.msg_name = (char *) &xprt->xp_laddr;
+	rlen = recvmsg(xprt->xp_sock, &dummy, MSG_PEEK);
+	if (rlen == -1) {
+	     if (errno == EINTR)
+		  goto again;
+	     else
+		  return (FALSE);
+	}
+	
+	xprt->xp_addrlen = sizeof(struct sockaddr_in);
+	rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz,
+	    0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen));
+	if (rlen == -1 && errno == EINTR)
+		goto again;
+	if (rlen < (int) 4*sizeof(uint32_t))
+		return (FALSE);
+	xdrs->x_op = XDR_DECODE;
+	XDR_SETPOS(xdrs, 0);
+	if (! xdr_callmsg(xdrs, msg))
+		return (FALSE);
+	su->su_xid = msg->rm_xid;
+	if (su->su_cache != NULL) {
+		if (cache_get(xprt, msg, &reply, &replylen)) {
+			(void) sendto(xprt->xp_sock, reply, (int) replylen, 0,
+			  (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen);
+			return (TRUE);
+		}
+	}
+	return (TRUE);
+}
+
+static bool_t svcudp_reply(
+	register SVCXPRT *xprt,
+	struct rpc_msg *msg)
+{
+     register struct svcudp_data *su = su_data(xprt);
+     register XDR *xdrs = &(su->su_xdrs);
+     register int slen;
+     register bool_t stat = FALSE;
+     
+     xdrproc_t xdr_results;
+     caddr_t xdr_location;
+     bool_t has_args;
+
+     if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+	 msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+	  has_args = TRUE;
+	  xdr_results = msg->acpted_rply.ar_results.proc;
+	  xdr_location = msg->acpted_rply.ar_results.where;
+	  
+	  msg->acpted_rply.ar_results.proc = xdr_void;
+	  msg->acpted_rply.ar_results.where = NULL;
+     } else
+	  has_args = FALSE;
+	  
+     xdrs->x_op = XDR_ENCODE;
+     XDR_SETPOS(xdrs, 0);
+     msg->rm_xid = su->su_xid;
+     if (xdr_replymsg(xdrs, msg) &&
+	 (!has_args ||
+	  (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) {
+	  slen = (int)XDR_GETPOS(xdrs);
+	  if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0,
+		     (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen)
+	      == slen) {
+	       stat = TRUE;
+	       if (su->su_cache && slen >= 0) {
+		    cache_set(xprt, (uint32_t) slen);
+	       }
+	  }
+     }
+     return (stat);
+}
+
+static bool_t
+svcudp_getargs(
+	SVCXPRT *xprt,
+	xdrproc_t xdr_args,
+	void * args_ptr)
+{
+	if (! SVCAUTH_UNWRAP(xprt->xp_auth, &(su_data(xprt)->su_xdrs),
+			     xdr_args, args_ptr)) {
+		(void)svcudp_freeargs(xprt, xdr_args, args_ptr);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static bool_t
+svcudp_freeargs(
+	SVCXPRT *xprt,
+	xdrproc_t xdr_args,
+	void * args_ptr)
+{
+	register XDR *xdrs = &(su_data(xprt)->su_xdrs);
+
+	xdrs->x_op = XDR_FREE;
+	return ((*xdr_args)(xdrs, args_ptr));
+}
+
+static void
+svcudp_destroy(register SVCXPRT *xprt)
+{
+	register struct svcudp_data *su = su_data(xprt);
+
+	xprt_unregister(xprt);
+	if (xprt->xp_sock != -1)
+		(void)close(xprt->xp_sock);
+	xprt->xp_sock = -1;
+	if (xprt->xp_auth != NULL) {
+		SVCAUTH_DESTROY(xprt->xp_auth);
+		xprt->xp_auth = NULL;
+	}
+	XDR_DESTROY(&(su->su_xdrs));
+	mem_free(rpc_buffer(xprt), su->su_iosz);
+	mem_free((caddr_t)su, sizeof(struct svcudp_data));
+	mem_free((caddr_t)xprt, sizeof(SVCXPRT));
+}
+
+
+/***********this could be a separate file*********************/
+
+/*
+ * Fifo cache for udp server
+ * Copies pointers to reply buffers into fifo cache
+ * Buffers are sent again if retransmissions are detected.
+ */
+
+#define SPARSENESS 4	/* 75% sparse */
+
+#define CACHE_PERROR(msg)	\
+	(void) fprintf(stderr,"%s\n", msg)
+
+#define ALLOC(type, size)	\
+	(type *) mem_alloc((unsigned) (sizeof(type) * (size)))
+
+#define BZERO(addr, type, size)	 \
+	memset((char *) addr, 0, sizeof(type) * (int) (size)) 
+
+/*
+ * An entry in the cache
+ */
+typedef struct cache_node *cache_ptr;
+struct cache_node {
+	/*
+	 * Index into cache is xid, proc, vers, prog and address
+	 */
+	uint32_t cache_xid;
+	rpcproc_t cache_proc;
+	rpcvers_t cache_vers;
+	rpcprog_t cache_prog;
+	struct sockaddr_in cache_addr;
+	/*
+	 * The cached reply and length
+	 */
+	char * cache_reply;
+	uint32_t cache_replylen;
+	/*
+ 	 * Next node on the list, if there is a collision
+	 */
+	cache_ptr cache_next;	
+};
+
+
+
+/*
+ * The entire cache
+ */
+struct udp_cache {
+	uint32_t uc_size;		/* size of cache */
+	cache_ptr *uc_entries;	/* hash table of entries in cache */
+	cache_ptr *uc_fifo;	/* fifo list of entries in cache */
+	uint32_t uc_nextvictim;	/* points to next victim in fifo list */
+	rpcprog_t uc_prog;		/* saved program number */
+	rpcvers_t uc_vers;		/* saved version number */
+	rpcproc_t uc_proc;		/* saved procedure number */
+	struct sockaddr_in uc_addr; /* saved caller's address */
+};
+
+
+/*
+ * the hashing function
+ */
+#define CACHE_LOC(transp, xid)	\
+ (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))	
+
+
+/*
+ * Enable use of the cache. 
+ * Note: there is no disable.
+ */
+int
+svcudp_enablecache(
+	SVCXPRT *transp,
+	uint32_t size)
+{
+	struct svcudp_data *su = su_data(transp);
+	struct udp_cache *uc;
+
+	if (su->su_cache != NULL) {
+		CACHE_PERROR("enablecache: cache already enabled");
+		return(0);	
+	}
+	uc = ALLOC(struct udp_cache, 1);
+	if (uc == NULL) {
+		CACHE_PERROR("enablecache: could not allocate cache");
+		return(0);
+	}
+	uc->uc_size = size;
+	uc->uc_nextvictim = 0;
+	uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS);
+	if (uc->uc_entries == NULL) {
+		CACHE_PERROR("enablecache: could not allocate cache data");
+		return(0);
+	}
+	BZERO(uc->uc_entries, cache_ptr, size * SPARSENESS);
+	uc->uc_fifo = ALLOC(cache_ptr, size);
+	if (uc->uc_fifo == NULL) {
+		CACHE_PERROR("enablecache: could not allocate cache fifo");
+		return(0);
+	}
+	BZERO(uc->uc_fifo, cache_ptr, size);
+	su->su_cache = (char *) uc;
+	return(1);
+}
+
+
+/*
+ * Set an entry in the cache
+ */
+static void
+cache_set(
+	SVCXPRT *xprt,
+	uint32_t replylen)
+{
+	register cache_ptr victim;	
+	register cache_ptr *vicp;
+	register struct svcudp_data *su = su_data(xprt);
+	struct udp_cache *uc = (struct udp_cache *) su->su_cache;
+	u_int loc;
+	char *newbuf;
+
+	/*
+ 	 * Find space for the new entry, either by
+	 * reusing an old entry, or by mallocing a new one
+	 */
+	victim = uc->uc_fifo[uc->uc_nextvictim];
+	if (victim != NULL) {
+		loc = CACHE_LOC(xprt, victim->cache_xid);
+		for (vicp = &uc->uc_entries[loc]; 
+		  *vicp != NULL && *vicp != victim; 
+		  vicp = &(*vicp)->cache_next) 
+				;
+		if (*vicp == NULL) {
+			CACHE_PERROR("cache_set: victim not found");
+			return;
+		}
+		*vicp = victim->cache_next;	/* remote from cache */
+		newbuf = victim->cache_reply;
+	} else {
+		victim = ALLOC(struct cache_node, 1);
+		if (victim == NULL) {
+			CACHE_PERROR("cache_set: victim alloc failed");
+			return;
+		}
+		newbuf = mem_alloc(su->su_iosz);
+		if (newbuf == NULL) {
+			CACHE_PERROR("cache_set: could not allocate new rpc_buffer");
+			return;
+		}
+	}
+
+	/*
+	 * Store it away
+	 */
+	victim->cache_replylen = replylen;
+	victim->cache_reply = rpc_buffer(xprt);
+	rpc_buffer(xprt) = newbuf;
+	xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_ENCODE);
+	victim->cache_xid = su->su_xid;
+	victim->cache_proc = uc->uc_proc;
+	victim->cache_vers = uc->uc_vers;
+	victim->cache_prog = uc->uc_prog;
+	victim->cache_addr = uc->uc_addr;
+	loc = CACHE_LOC(xprt, victim->cache_xid);
+	victim->cache_next = uc->uc_entries[loc];	
+	uc->uc_entries[loc] = victim;
+	uc->uc_fifo[uc->uc_nextvictim++] = victim;
+	uc->uc_nextvictim %= uc->uc_size;
+}
+
+/*
+ * Try to get an entry from the cache
+ * return 1 if found, 0 if not found
+ */
+static int
+cache_get(
+	SVCXPRT *xprt,
+	struct rpc_msg *msg,
+	char **replyp,
+	uint32_t *replylenp)
+{
+	u_int loc;
+	register cache_ptr ent;
+	register struct svcudp_data *su = su_data(xprt);
+	register struct udp_cache *uc = (struct udp_cache *) su->su_cache;
+
+#	define EQADDR(a1, a2) (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0)
+
+	loc = CACHE_LOC(xprt, su->su_xid);
+	for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
+		if (ent->cache_xid == su->su_xid &&
+		  ent->cache_proc == uc->uc_proc &&
+		  ent->cache_vers == uc->uc_vers &&
+		  ent->cache_prog == uc->uc_prog &&
+		  EQADDR(ent->cache_addr, uc->uc_addr)) {
+			*replyp = ent->cache_reply;
+			*replylenp = ent->cache_replylen;
+			return(1);
+		}
+	}
+	/*
+	 * Failed to find entry
+	 * Remember a few things so we can do a set later
+	 */
+	uc->uc_proc = msg->rm_call.cb_proc;
+	uc->uc_vers = msg->rm_call.cb_vers;
+	uc->uc_prog = msg->rm_call.cb_prog;
+	uc->uc_addr = xprt->xp_raddr;
+	return(0);
+}
+
diff --git a/mechglue/src/lib/rpc/types.hin b/mechglue/src/lib/rpc/types.hin
new file mode 100644
index 000000000..ed612f1f5
--- /dev/null
+++ b/mechglue/src/lib/rpc/types.hin
@@ -0,0 +1,175 @@
+/* @(#)types.h	2.3 88/08/15 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)types.h 1.18 87/07/24 SMI      */
+
+/*
+ * Rpc additions to <sys/types.h>
+ */
+#ifndef GSSRPC_TYPES_H
+#define GSSRPC_TYPES_H
+
+#include <sys/types.h>
+
+@GSSRPC__SYS_SELECT_H@
+@GSSRPC__SYS_TIME_H@
+@GSSRPC__UNISTD_H@
+
+/*
+ * Try to get MAXHOSTNAMELEN from somewhere.
+ */
+@GSSRPC__SYS_PARAM_H@
+@GSSRPC__NETDB_H@
+
+/* Get htonl(), ntohl(), etc. */
+#include <netinet/in.h>
+
+#include <stdlib.h>
+
+/*
+ * Pull in typedefs for fixed-width integers somehow, if they weren't
+ * in sys/types.h.
+ */
+@GSSRPC__STDINT_H@
+@GSSRPC__INTTYPES_H@
+/* Define if there is no uint32_t in system headers. */
+@GSSRPC__FAKE_UINT32@
+
+#include <limits.h>
+
+#ifndef GSSRPC__BEGIN_DECLS
+#ifdef __cplusplus
+#define GSSRPC__BEGIN_DECLS	extern "C" {
+#define GSSRPC__END_DECLS	}
+#else
+#define GSSRPC__BEGIN_DECLS
+#define GSSRPC__END_DECLS
+#endif
+#endif
+
+GSSRPC__BEGIN_DECLS
+
+#if defined(CHAR_BIT) && CHAR_BIT != 8
+#error "Bytes must be exactly 8 bits."
+#endif
+
+/*
+ * If no uint32_t in system headers, fake it by looking for a 32-bit
+ * two's-complement type.  Yes, this stomps on POSIX namespace, but if
+ * we get here, we're on a system that's far from being
+ * POSIX-compliant anyway.
+ */
+#if GSSRPC__FAKE_UINT32
+#if (UINT_MAX == 0xffffffffUL) && (INT_MAX == 0x7fffffffL) \
+	&& (INT_MIN == -INT_MAX-1)
+typedef int		int32_t;
+typedef unsigned int	uint32_t;
+#else
+#if (ULONG_MAX == 0xffffffffUL) && (LONG_MAX == 0x7fffffffL) \
+	&& (LONG_MIN == -LONG_MAX-1)
+typedef long		int32_t;
+typedef unsigned long	uint32_t;
+#else
+#if (USHRT_MAX == 0xffffffffUL) && (SHRT_MAX == 0x7fffffffL) \
+	&& (SHRT_MIN == -SHRT_MAX-1)
+typedef short		int32_t;
+typedef unsigned short	uint32_t;
+#else
+#error "Can't fake up uint32_t."
+#endif
+#endif
+#endif
+#endif /* GSSRPC__FAKE_UINT32 */
+
+#if (LONG_MIN != -LONG_MAX-1) || (INT_MIN != -INT_MAX-1) \
+	|| (SHRT_MIN != -SHRT_MAX-1)
+#error "Integer types must be two's-complement."
+#endif
+
+/* Define if we need to fake up some BSD type aliases. */
+#ifndef GSSRPC__BSD_TYPEALIASES	/* Allow application to override. */
+@GSSRPC__BSD_TYPEALIASES@
+#endif
+#if GSSRPC__BSD_TYPEALIASES
+typedef unsigned char	u_char;
+typedef unsigned short	u_short;
+typedef unsigned int	u_int;
+typedef unsigned long	u_long;
+#endif
+
+typedef uint32_t	rpcprog_t;
+typedef uint32_t	rpcvers_t;
+typedef uint32_t	rpcprot_t;
+typedef uint32_t	rpcproc_t;
+typedef uint32_t	rpcport_t;
+typedef int32_t		rpc_inline_t;
+
+/* This is for rpc/netdb.h */
+@rpcent_define@
+
+#define	bool_t	int
+#define	enum_t	int
+#ifndef FALSE
+#	define	FALSE	(0)
+#endif
+#ifndef TRUE
+#	define	TRUE	(1)
+#endif
+/* XXX namespace */
+#define __dontcare__	-1
+#ifndef NULL
+#	define NULL 0
+#endif
+
+/*
+ * The below should probably be internal-only, but seem to be
+ * traditionally exported in RPC implementations.
+ */
+#define mem_alloc(bsize)	malloc(bsize)
+#define mem_free(ptr, bsize)	free(ptr)
+
+#if 0
+#include <netdb.h> /* XXX This should not have to be here.
+		    * I got sick of seeing the warnings for MAXHOSTNAMELEN
+		    * and the two values were different. -- shanzer 
+		    */
+#endif
+
+#ifndef INADDR_LOOPBACK
+#define       INADDR_LOOPBACK         (uint32_t)0x7F000001
+#endif
+#ifndef MAXHOSTNAMELEN
+#define        MAXHOSTNAMELEN  64
+#endif
+
+GSSRPC__END_DECLS
+
+#include <gssrpc/rename.h>
+
+#endif /* !defined(GSSRPC_TYPES_H) */
diff --git a/mechglue/src/lib/rpc/unit-test/ChangeLog b/mechglue/src/lib/rpc/unit-test/ChangeLog
new file mode 100644
index 000000000..f97c77fc5
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/ChangeLog
@@ -0,0 +1,337 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2004-05-27  Tom Yu  <tlyu@mit.edu>
+
+	* client.c: rpcint_32 -> int32_t.
+
+	* server.c: Update names of AUTH_GSSAPI functions.
+
+2004-04-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib/helpers.exp (expect_kadm_ok): Check for "ERROR" messages and
+	report them.
+
+2004-02-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib/helpers.exp (expect_kadm_ok): Check for eof and report a
+	specific error for that case.
+
+2004-02-13  Tom Yu  <tlyu@mit.edu>
+
+	* config/unix.exp (PRIOCNTL_HACK): Use "==" instead of "eq", which
+	is not present in tcl-8.3.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Invoke KRB5_AC_PRIOCNTL_HACK.
+
+	* config/unix.exp (PRIOCNTL_HACK): Wrap "spawn" to do priocntl
+	things to work around Solaris 9 pty-close bug.
+
+2003-12-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib/helpers.exp (expect_kadm_ok, eof_client): Accept and ignore
+	debugging messages starting "marshall_new_creds" or "gssapi_", and
+	blank lines.
+
+2003-01-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.ov: Deleted.
+
+2002-11-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unit-test-ok): Depend only on unit-test-body.
+	(unit-test-body): Remove krb5cc_rpc_test_* on entry and on
+	successful exit.  On error exit, let the trap handler do all the
+	cleanup.  Incorporate old unit-test-setup commands.
+	(unit-test-setup, unit-test-cleanup): Targets deleted.
+	* lib/helpers.exp (start_client, wait_client): Set KRB5CCNAME to
+	something in the current directory.
+
+2002-11-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unit-test-body): Set RPC_TEST_SRVTAB based on
+	process-id.  Set trap handler to delete it before returning an
+	exit status.
+	(unit-test-cleanup): Don't delete files here.
+
+2002-11-07  Tom Yu  <tlyu@mit.edu>
+
+	* rpc_test.0/expire.exp (overlap): Add another call to
+	flush_server to make a race condition a little less likely.  There
+	really should be better synchronization, as this test suite is
+	just full of race conditions waiting to happen.
+
+2002-09-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib/helpers.exp (setup_database): Use "!=" instead of "ne" for
+	string comparisons.
+
+2002-09-15  Tom Yu  <tlyu@mit.edu>
+
+	* lib/helpers.exp (expect_tcl_prompt): Use the "-re" flag, and
+	match end of output.
+	(expect_kadm_ok): s/error/perror.
+	(setup_database): Work around tcl 8.4's (incorrect?) output EOL
+	translation.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-26  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Use $krb5_cv_host instead of $host. 
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-06-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* config/unix.exp (top level): Load helpers.exp here, to make
+	sure database setup happens properly.
+
+2002-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* lib/helpers.exp (set_from_env, expect_tcl_prompt,
+	send_tcl_cmd_await_echo, expect_kadm_ok, setup_database): New
+	procs.
+	(top level): Do database setup here...
+	* Makefile.in (unit-test-setup): ...not here.
+
+2001-07-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* client.c: Change local variable count from int to unsigned int.
+
+	* server.c (log_badauth_display_status_1): Argument to
+	gss_display_status should be OM_uint32 * instead of int *.
+
+2001-07-09  Ezra Peisach  <epeisach@mit.edu>
+
+	* rpc_test_clnt.c, rpc_test_svc.c: Include string.h for memset
+	prototype.
+
+2001-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* rpc_test_svc.c: Change rpc_test_prog_1 to
+	rpc_test_prog_1_svc.
+
+	* rpc_test.h: Create prototypes for rpc_test_echo_1_svc and
+	rpc_test_prog_1_svc.
+
+	* server.c: Declare usage and handlesig static.  Change
+	rpc_test_echo_1 to rpc_test_echo_1_svc and rpc_test_prog_1 to
+	rpc_test_prog_1_svc.
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* client.c: Include unistd.h for getopt() prototype. 
+
+	* configure.in: Check for unistd.h.
+
+	* server.c: Include unistd.h for getopt() prototype. Fix
+	rpc_test_badauth() prototype to be consistant with error
+	handler. Declare main as returning int. If POSIX_SIGNALS is
+	defined, the handler expects an argument.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* server.c (log_badauth_display_status_1): Do not assume that
+	gss_buffer_desc strings are '\0' terminated.
+
+2001-06-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* server.c (log_badauth_display_status_1): Need value element of
+	gss_buffer_desc for printf.
+
+	* client.c (main): Missing arguments to printf fixed.
+
+2001-04-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* client.c (main): Ensure that end of string is NULL terminated
+ 	instead of assuming buffer initialized to 0. Include <string.h>
+ 	for memset prototype.
+
+2000-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unit-test-body): Combine -tcp and -udp versions,
+	setting PASS instead of PROT.
+	* configure.in: Set and substitute PASS instead of UDP_TEST.
+	* config/unix.exp: Don't invoke rpc_test_start.  Set MULTIPASS,
+	including a setting for PROT and a dummy to trigger rpc_test_start
+	invocation.
+	(rpc_test_start): If a server has already been started, call
+	rpc_test_exit to verify that it's still running.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* server.c: Include gssrpc/pmap_clnt.h in order to get renaming of
+	pmap_unset().  From Nathan Neulinger.
+
+2000-06-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* rpc_test_setup.sh: Error out if server_handle doesn't get set in
+	the Tcl script.
+
+2000-06-08  Tom Yu  <tlyu@mit.edu>
+
+	* lib/helpers.exp (kinit): Move "expect eof" into the commands
+	that send the prompt.  Don't "expect eof" outside of the main
+	expect, as the main expect may have already read eof.
+
+2000-02-15  Tom Yu  <tlyu@mit.edu>
+
+	* server.c: Add code to set a signal handler for SIGHUP and a few
+	others so that purify will actually generate memory leak reports.
+
+	* configure.in: Add CHECK_SIGNALS.
+
+2000-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* config/unix.exp: Call send_error instead of fail to prevent
+	referencing variables not yet set up by the test framework.
+
+	* lib/helpers.exp: Call kinit and kdestroy with the -5 flag to
+	deal with new program behavior.  Also call perror rather than
+	error to avoid spewing a stack trace.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unit-test-body-tcp, unit-test-body-udp): Pass
+	$(RUNTESTFLAGS) to runtest.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+	* configure.in: Use K5_AC_OUTPUT instead of K5_OUTPUT_FILES.
+
+Fri Feb 13 21:28:18 1998  Tom Yu  <tlyu@mit.edu>
+
+	* client.c: Update header locations.  Rename of xdr_free.
+
+	* rpc_test.h: Update header locations.
+
+	* server.c: Update header locations.
+
+Thu Feb 12 16:39:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* client.c (main): Tweak the kludge variable
+	krb5_gss_dbg_clietn_expcreds so we can send expired creds to the
+	server.
+
+Mon Feb  2 16:59:48 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Thu Oct  9 20:58:35 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in, Makefile.in: Add test to disable udp test under
+ 	Solaris 2.0 thru 2.5; a getsockname() bug prevents channel
+	bindings from working.
+
+Thu Feb  6 15:58:52 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Wed Nov 20 16:00:21 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.in (unit-test-): warn more loudly about unrun tests
+
+Thu Nov 14 22:27:05 1996  Tom Yu  <tlyu@mit.edu>
+
+	* server.c (main): Add declaration of optind for systems that
+	don't have it in stdio.h or the like.
+
+Thu Nov 14 15:27:05 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* rpc_test_setup.sh: VERBOSE is now inherited from env-setup.sh
+
+Wed Nov 13 10:00:05 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean): Remove test programs and objects.
+
+Tue Nov 12 16:27:51 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* lib/helpers.exp, client.c, server.c, config/unix.exp,
+ 	Makefile.in: test GSS-RPC with both TCP and UDP transport layers
+ 	[krb5-libs/180]
+
+Tue Nov 12 14:58:20 1996  Tom Yu  <tlyu@mit.edu>
+
+	* rpc_test_setup.sh: Fix test of $VERBOSE_TEST so that $VERBOSE
+	only gets set if $VERBOSE_TEST is not empty.
+
+Mon Nov 11 20:52:27 1996  Tom Yu  <tlyu@mit.edu>
+
+	* rpc_test_setup.sh: Use a temp file rather than a here document
+	feeding into eval because Ultrix sh doesn't deal.
+
+	* configure.in: Add AC_CANONICAL_HOST to deal with new pre.in.
+
+Mon Nov 11 14:22:30 1996  Tom Yu  <chaoself@avalanche-breakdown.mit.edu>
+
+	* Makefile.in (client.o, server.o): client.o and server.o, not
+	client.c and server.c, depend on rpc_test.h.
+
+Thu Nov  7 16:16:38 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Remove spurious KRB_INCLUDE and WITH_CCOPTS.
+
+	* Makefile.in (server.o): Fix typo in previous checkin.
+
+Wed Nov  6 16:12:26 1996  Tom Yu <tlyu@mit.edu>
+	* Makefile.in: Add dependencies on $(srcdir)/foo.c so that some
+	makes can deal with VPATH properly (e.g. NetBSD pmake)
+
+Mon Nov  4 23:12:06 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* server.c: We don't need the special case for linux anymore,
+ 		since we're including the output from rpcgen in the source
+ 		tree now.
+
+Thu Oct 31 13:14:45 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (client,server): Use $(LD) instead of $(CC) in link
+		stage. 
+
+Thu Oct 31 08:47:47 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Only run tests if required programs, libraries
+		available.  
+
+	* configure.in: Check for runtest, Perl, and tcl before making checks. 
+
+
+Thu Oct 24 17:20:11 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.in, rpc_test_clnt.c, rpc_test_svc.c, rpc_test.h:
+ 	distribute generated rpc_test_* files instead of running rpcgen on
+ 	rpc_text.x [krb5-admin/133]
+
+Wed Oct 16 16:13:13 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* rpc_test.0/expire.exp: add test for expired credentials
+	[krb5-admin/17]
+	
+	* server.c (log_miscerr): add log_miscerr
+
+	* Makefile.in: don't delete rpc_test.x, we might be in souce tree
+
+Tue Oct 15 16:12:04 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* initial changes to make rpc unit tests work with new build/test
+ 	system
+
diff --git a/mechglue/src/lib/rpc/unit-test/Makefile.in b/mechglue/src/lib/rpc/unit-test/Makefile.in
new file mode 100644
index 000000000..a4c2fc52d
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/Makefile.in
@@ -0,0 +1,69 @@
+thisconfigdir=.
+myfulldir=lib/rpc/unit-test
+mydir=.
+BUILDTOP=$(REL)..$(S)..$(S)..
+LOCALINCLUDES = -I.
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+OBJS= client.o rpc_test_clnt.o rpc_test_svc.o server.o
+
+all:: client server
+
+client: client.o rpc_test_clnt.o $(GSSRPC_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o client client.o rpc_test_clnt.o \
+		$(GSSRPC_LIBS) $(KRB5_BASE_LIBS)
+
+server: server.o rpc_test_svc.o $(GSSRPC_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o server server.o rpc_test_svc.o \
+		$(GSSRPC_LIBS) $(KRB5_BASE_LIBS)
+
+client.o server.o: rpc_test.h
+
+# If rpc_test.h and rpc_test_*.c do not work on your system, you can
+# try using rpcgen by uncommenting these lines (be sure to uncomment
+# then in the generated not Makefile.in).
+# rpc_test.h rpc_test_clnt.c rpc_test_svc.c: rpc_test.x
+# 	-rm -f rpc_test_clnt.c rpc_test_svc.c rpc_test.h
+# 	-ln -s $(srcdir)/rpc_test.x .
+# 	rpcgen -l rpc_test.x -o rpc_test_clnt.c
+# 	rpcgen -m rpc_test.x -o rpc_test_svc.c
+# 	rpcgen -h rpc_test.x -o rpc_test.h
+# 
+# clean::
+# 	rm -f rpc_test.h rpc_test_clnt.c rpc_test_svc.c
+# 
+
+check unit-test:: unit-test-@DO_TEST@
+
+unit-test-:
+	@echo "+++"
+	@echo "+++ WARNING: lib/rpc unit tests not run."
+	@echo "+++ Either tcl, runtest, or Perl is unavailable."
+	@echo "+++"
+
+unit-test-ok:: unit-test-body
+
+PASS=@PASS@
+unit-test-body:
+	$(RM) krb5cc_rpc_test_*
+	$(ENV_SETUP) $(START_SERVERS)
+	RPC_TEST_SRVTAB=/tmp/rpc_test_v5srvtab.$$$$ ; export RPC_TEST_SRVTAB ; \
+	trap "echo Failed, cleaning up... ; rm -f $$RPC_TEST_SRVTAB ; $(ENV_SETUP) $(STOP_SERVERS) ; trap '' 0 ; exit 1" 0 1 2 3 14 15 ; \
+	if $(ENV_SETUP) \
+		$(RUNTEST) SERVER=./server CLIENT=./client \
+		KINIT=$(BUILDTOP)/clients/kinit/kinit \
+		KDESTROY=$(BUILDTOP)/clients/kdestroy/kdestroy \
+		PRIOCNTL_HACK=@PRIOCNTL_HACK@ \
+		PASS="$(PASS)" --tool rpc_test $(RUNTESTFLAGS) ; \
+	then \
+		echo Cleaning up... ; \
+		rm -f $$RPC_TEST_SRVTAB krb5cc_rpc_test_* ; \
+		$(ENV_SETUP) $(STOP_SERVERS) ; \
+		trap 0 ; exit 0 ; \
+	else exit 1 ; fi
+
+clean::
+	$(RM) server client
+	$(RM) dbg.log rpc_test.log rpc_test.sum
+
diff --git a/mechglue/src/lib/rpc/unit-test/client.c b/mechglue/src/lib/rpc/unit-test/client.c
new file mode 100644
index 000000000..ffe6739cb
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/client.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ *
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <gssrpc/rpc.h>
+#include <gssapi/gssapi.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/auth_gssapi.h>
+#include "rpc_test.h"
+
+#define BIG_BUF 4096
+/* copied from auth_gssapi.c for hackery */
+struct auth_gssapi_data {
+     bool_t established;
+     CLIENT *clnt;
+     gss_ctx_id_t context;
+     gss_buffer_desc client_handle;
+     OM_uint32 seq_num;
+     int def_cred;
+
+     /* pre-serialized ah_cred */
+     u_char cred_buf[MAX_AUTH_BYTES];
+     int32_t cred_len;
+};
+#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private)
+
+extern int auth_debug_gssapi;
+char *whoami;
+
+static void usage()
+{
+     fprintf(stderr, "usage: %s {-t|-u} [-a] [-s num] [-m num] host service [count]\n",
+	     whoami);
+     exit(1);
+}
+
+int
+main(argc, argv)
+   int argc;
+   char **argv;
+{
+     char        *host, *target, *echo_arg, **echo_resp, buf[BIG_BUF];
+     char	 *prot;
+     CLIENT      *clnt;
+     AUTH	 *tmp_auth;
+     struct rpc_err e;
+     int i, auth_once;
+     unsigned int count;
+     extern int optind;
+     extern char *optarg;
+     extern int svc_debug_gssapi, misc_debug_gssapi, auth_debug_gssapi;
+     int c;
+
+     extern int krb5_gss_dbg_client_expcreds;
+     krb5_gss_dbg_client_expcreds = 1;
+
+     whoami = argv[0];
+     count = 1026;
+     auth_once = 0;
+     prot = NULL;
+     
+     while ((c = getopt(argc, argv, "a:m:os:tu")) != -1) {
+	  switch (c) {
+	  case 'a':
+	       auth_debug_gssapi = atoi(optarg);
+	       break;
+	  case 'm':
+	       misc_debug_gssapi = atoi(optarg);
+	       break;
+	  case 'o':
+	       auth_once++;
+	       break;
+	  case 's':
+	       svc_debug_gssapi = atoi(optarg);
+	       break;
+	  case 't':
+	       prot = "tcp";
+	       break;
+	  case 'u':
+	       prot = "udp";
+	       break;
+	  case '?':
+	       usage();
+	       break;
+	  }
+     }
+     if (prot == NULL)
+	  usage();
+
+     argv += optind;
+     argc -= optind;
+
+     switch (argc) {
+     case 3:
+	  count = atoi(argv[2]);
+	  if (count > BIG_BUF-1) {
+	    fprintf(stderr, "Test count cannot exceed %d.\n", BIG_BUF-1);
+	    usage();
+	  }
+     case 2:
+	  host = argv[0];
+	  target = argv[1];
+	  break;
+     default:
+	  usage();
+     }
+     
+     /* client handle to rstat */
+     clnt = clnt_create(host, RPC_TEST_PROG, RPC_TEST_VERS_1, prot);
+     if (clnt == NULL) {
+	  clnt_pcreateerror(whoami);
+	  exit(1);
+     }
+     
+     clnt->cl_auth = auth_gssapi_create_default(clnt, target);
+     if (clnt->cl_auth == NULL) {
+	  clnt_pcreateerror(whoami);
+	  exit(2);
+     }
+     
+     /*
+      * Call the echo service multiple times.
+      */
+     echo_arg = buf;
+     for (i = 0; i < 3; i++) {
+	  sprintf(buf, "testing %d\n", i);
+
+	  echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+	  if (echo_resp == NULL) {
+	       fprintf(stderr, "RPC_TEST_ECHO call %d%s", i,
+		       clnt_sperror(clnt, ""));
+	  }
+	  if (strncmp(*echo_resp, "Echo: ", 6) &&
+	      strcmp(echo_arg, (*echo_resp) + 6) != 0)
+	       fprintf(stderr, "RPC_TEST_ECHO call %d response wrong: "
+		       "arg = %s, resp = %s\n", i, echo_arg, *echo_resp);
+	  gssrpc_xdr_free(xdr_wrapstring, echo_resp);
+     }
+
+     /*
+      * Make a call with an invalid verifier and check for error;
+      * server should log error message.  It is important to
+      *increment* seq_num here, since a decrement would be fixed (see
+      * below).  Note that seq_num will be incremented (by
+      * authg_gssapi_refresh) twice, so we need to decrement by three
+      * to reset.
+      */
+     AUTH_PRIVATE(clnt->cl_auth)->seq_num++;
+
+     echo_arg = "testing with bad verf";
+
+     echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+     if (echo_resp == NULL) {
+	  CLNT_GETERR(clnt, &e);
+	  if (e.re_status != RPC_AUTHERROR || e.re_why != AUTH_REJECTEDVERF)
+	       clnt_perror(clnt, whoami);
+     } else {
+	  fprintf(stderr, "bad seq didn't cause failure\n");
+     }
+
+     AUTH_PRIVATE(clnt->cl_auth)->seq_num -= 3;
+
+     /*
+      * Make sure we're resyncronized.
+      */
+     echo_arg = "testing for reset";
+     echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+     if (echo_resp == NULL)
+	  clnt_perror(clnt, "Sequence number improperly reset");
+     
+     /*
+      * Now simulate a lost server response, and see if
+      * auth_gssapi_refresh recovers.
+      */
+     AUTH_PRIVATE(clnt->cl_auth)->seq_num--;
+     echo_arg = "forcing auto-resynchronization";
+     echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+     if (echo_resp == NULL)
+	  clnt_perror(clnt, "Auto-resynchronization failed");
+     
+     /*
+      * Now make sure auto-resyncrhonization actually worked
+      */
+     echo_arg = "testing for resynchronization";
+     echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+     if (echo_resp == NULL)
+	  clnt_perror(clnt, "Auto-resynchronization did not work");
+
+     /*
+      * Test fix for secure-rpc/586, part 1: btree keys must be
+      * unique.  Create another context from the same credentials; it
+      * should have the same expiration time and will cause the server
+      * to abort if the clients are not differentiated.
+      * 
+      * Test fix for secure-rpc/586, part 2: btree keys cannot be
+      * mutated in place.  To test this: a second client, *with a
+      * later expiration time*, must be run.  The second client should
+      * destroy itself *after* the first one; if the key-mutating bug
+      * is not fixed, the second client_data will be in the btree
+      * before the first, but its key will be larger; thus, when the
+      * first client calls AUTH_DESTROY, the server won't find it in
+      * the btree and call abort.
+      *
+      * For unknown reasons, running just a second client didn't
+      * tickle the bug; the btree code seemed to guess which node to
+      * look at first.  Running a total of three clients does ticket
+      * the bug.  Thus, the full test sequence looks like this:
+      *
+      * 	kinit -l 20m user && client server test@ddn 200
+      * 	sleep 1
+      * 	kini -l 30m user && client server test@ddn 300
+      * 	sleep 1
+      * 	kinit -l 40m user && client server test@ddn 400
+      */
+     if (! auth_once) {
+	  tmp_auth = clnt->cl_auth;
+	  clnt->cl_auth = auth_gssapi_create_default(clnt, target);
+	  if (clnt->cl_auth == NULL) {
+	       clnt_pcreateerror(whoami);
+	       exit(2);
+	  }
+	  AUTH_DESTROY(clnt->cl_auth);
+	  clnt->cl_auth = tmp_auth;
+     }
+     
+     /*
+      * Try RPC calls with argument/result lengths [0, 1025].  Do
+      * this last, since it takes a while..
+      */
+     echo_arg = buf;
+     memset(buf, 0, count+1);
+     for (i = 0; i < count; i++) {
+	  echo_resp = rpc_test_echo_1(&echo_arg, clnt);
+	  if (echo_resp == NULL) {
+	       fprintf(stderr, "RPC_TEST_LENGTHS call %d%s", i,
+		       clnt_sperror(clnt, ""));
+	       break;
+	  } else {
+	       if (strncmp(*echo_resp, "Echo: ", 6) &&
+		   strcmp(echo_arg, (*echo_resp) + 6) != 0)
+		    fprintf(stderr,
+			    "RPC_TEST_LENGTHS call %d response wrong\n", i);
+	       gssrpc_xdr_free(xdr_wrapstring, echo_resp);
+	  }
+	  
+	  /* cycle from 1 to 255 */
+	  buf[i] = (i % 255) + 1;
+
+	  if (i % 100 == 0) {
+	       fputc('.', stdout);
+	       fflush(stdout);
+	  }
+     }
+     fputc('\n', stdout);
+
+     AUTH_DESTROY(clnt->cl_auth);
+     CLNT_DESTROY(clnt);
+     exit(0);
+}
+
diff --git a/mechglue/src/lib/rpc/unit-test/config/unix.exp b/mechglue/src/lib/rpc/unit-test/config/unix.exp
new file mode 100644
index 000000000..495472e67
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/config/unix.exp
@@ -0,0 +1,125 @@
+#
+# $Id$
+#
+
+set kill /bin/kill
+set sleep /bin/sleep
+set kinit $KINIT
+set kdestroy $KDESTROY
+
+set hostname [exec hostname]
+
+# Hack around Solaris 9 kernel race condition that causes last output
+# from a pty to get dropped.
+if { $PRIOCNTL_HACK } {
+    catch {exec priocntl -s -c FX -m 30 -p 30 -i pid [getpid]}
+    rename spawn oldspawn
+    proc spawn { args } {
+	upvar 1 spawn_id spawn_id
+	set newargs {}
+	set inflags 1
+	set eatnext 0
+	foreach arg $args {
+	    if { $arg == "-ignore" \
+		     || $arg == "-open" \
+		     || $arg == "-leaveopen" } {
+		lappend newargs $arg
+		set eatnext 1
+		continue
+	    }
+	    if [string match "-*" $arg] {
+		lappend newargs $arg
+		continue
+	    }
+	    if { $eatnext } {
+		set eatnext 0
+		lappend newargs $arg
+		continue
+	    }
+	    if { $inflags } {
+		set inflags 0
+		set newargs [concat $newargs {priocntl -e -c FX -p 0}]
+	    }
+	    lappend newargs $arg
+	}
+	set pid [eval oldspawn $newargs]
+	return $pid
+    }
+}
+
+# this will initialize the database and keytab
+load_lib "helpers.exp"
+
+proc rpc_test_version {} {
+	global CLIENT
+	global SERVER
+
+	clone_output "$CLIENT version <unknown>"
+	clone_output "$SERVER version <unknown>"
+}
+
+proc rpc_test_load {} {
+	#
+}
+
+# rpc_test_exit -- clean up and exit
+proc rpc_test_exit {} {
+	global server_id
+	global server_pid
+	global server_started
+	global kill
+
+ 	if {[catch {
+		expect {
+			-i $server_id
+			eof { 
+				fail "server exited!"
+				verbose $expect_out(buffer) 1
+			}
+			timeout { pass "server survived" }
+		}
+	} tmp]} {
+		fail "server exited! (expect failed)"
+	}
+}
+
+#
+# rpc_test_start -- start the rpc_test server running
+#
+proc rpc_test_start { } {
+ 	global SERVER PROT
+	global server_id
+	global server_pid
+	global server_started
+	global env
+
+	if [info exists server_pid] { rpc_test_exit }
+
+	set env(KRB5_KTNAME) FILE:$env(RPC_TEST_SRVTAB)
+
+ 	verbose "% $SERVER" 1
+	set server_pid [spawn $SERVER $PROT]
+	set server_id $spawn_id
+
+	unset env(KRB5_KTNAME)
+
+	set timeout 30
+
+	expect {
+		"running" { }
+		eof { 
+			send_error "server exited!"
+			verbose $expect_out(buffer) 1
+		}
+		timeout { 
+			send_error "server didn't start in $timeout seconds"
+			verbose $expect_out(buffer) 1
+		}
+	}
+
+}
+
+set MULTIPASS {
+    {tcp PROT=-t dummy=[rpc_test_start]}
+    {udp PROT=-u dummy=[rpc_test_start]}
+}
diff --git a/mechglue/src/lib/rpc/unit-test/configure.in b/mechglue/src/lib/rpc/unit-test/configure.in
new file mode 100644
index 000000000..6a6bcf1f6
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/configure.in
@@ -0,0 +1,29 @@
+K5_AC_INIT(client.c)
+CONFIG_RULES
+dnl sets $(krb5_cv_host)
+KRB5_BUILD_PROGRAM
+dnl
+AC_CHECK_HEADERS(unistd.h)
+dnl The following are tests for the presence of programs required for testing 
+AC_CHECK_PROG(RUNTEST,runtest,runtest)
+AC_CHECK_PROG(PERL,perl,perl)
+AC_KRB5_TCL	
+if test "$PERL" = perl -a "$RUNTEST" = runtest -a "$TCL_LIBS" != ""; then
+ 	DO_TEST=ok
+fi
+AC_SUBST(DO_TEST)
+changequote(<<, >>)
+case "$krb5_cv_host" in
+*-*-solaris2.[012345]*)
+	PASS=tcp
+	;;
+*)
+	PASS="tcp udp"
+	;;
+esac
+changequote([, ])
+AC_SUBST(PASS)
+dnl
+CHECK_SIGNALS
+KRB5_AC_PRIOCNTL_HACK
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/lib/rpc/unit-test/lib/helpers.exp b/mechglue/src/lib/rpc/unit-test/lib/helpers.exp
new file mode 100644
index 000000000..b69be5b6b
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/lib/helpers.exp
@@ -0,0 +1,236 @@
+if {[info commands exp_version] != {}} {
+	set exp_version_4 [regexp {^4} [exp_version]]
+} else {
+	set exp_version_4 [regexp {^4} [expect_version]]
+}
+
+# Backward compatibility until we're using expect 5 everywhere
+if {$exp_version_4} {
+	global wait_error_index wait_errno_index wait_status_index
+	set wait_error_index 0
+	set wait_errno_index 1
+	set wait_status_index 1
+} else {
+	set wait_error_index 2
+	set wait_errno_index 3
+	set wait_status_index 3
+}
+				
+proc set_from_env {varname default_value} {
+    global env
+    upvar $varname v
+
+    if [info exists env($varname)] {
+	set v $env($varname)
+    } else {
+	set v $default_value
+    }
+}
+proc expect_tcl_prompt {} {
+    global kadmin_tcl_spawn_id
+    expect {
+	-i $kadmin_tcl_spawn_id
+	-re "^% $" { }
+	-re . { perror "unexpected output {$expect_out(buffer)} from subprocess, expecting tcl prompt" }
+	timeout { perror "timeout waiting for tcl prompt" }
+	eof { perror "eof from subprocess when expecting tcl prompt" }
+    }
+}
+proc send_tcl_cmd_await_echo {cmd} {
+    global kadmin_tcl_spawn_id
+    send -i $kadmin_tcl_spawn_id "$cmd\n"
+    expect {
+	-i $kadmin_tcl_spawn_id
+	-ex "$cmd\r\n" { }
+	timeout { perror "timeout waiting for tcl subprocess to echo input" }
+	eof { perror "eof waiting for tcl subprocess to echo input" }
+    }
+}
+proc expect_kadm_ok {} {
+    global kadmin_tcl_spawn_id
+    expect {
+	-i $kadmin_tcl_spawn_id
+	-re "^OK OVSEC_KADM_OK \[^\n\]*\n" {}
+	-re "^ERROR \[^\n\]*\n" { perror "kadmin tcl subprocess reported unexpected error" }
+	-re "^marshall_new_creds: \[^\n\]*\n" { exp_continue }
+	-re "^gssapi_\[^\n\]*\n" { exp_continue }
+	-re "^\r?\n" { exp_continue }
+	eof	{ perror "kadmin tcl subprocess died" }
+	default { perror "didn't get ok back" }
+    }
+}
+# trying to translate rpc_test_setup.sh into inline tcl...
+proc setup_database {} {
+    global env spawn_id kadmin_tcl_spawn_id TESTDIR MAKE_KEYTAB CANON_HOST
+
+    # XXXXX
+    set_from_env TOP {/x/x/x/x/x}
+    send_user "TOP=$TOP\n"
+
+    set_from_env TESTDIR $env(TOP)/testing
+    set_from_env CLNTTCL $TESTDIR/util/ovsec_kadm_clnt_tcl
+    set_from_env TCLUTIL $TESTDIR/tcl/util.t
+    set env(TCLUTIL) $TCLUTIL
+    set_from_env MAKE_KEYTAB $TESTDIR/scripts/make-host-keytab.pl
+    set env(PATH) "$TOP/install/admin:$env(PATH)"
+
+    # $VERBOSE ?
+
+    if [info exists spawn_id] { set x $spawn_id }
+    spawn $CLNTTCL
+    set kadmin_tcl_spawn_id $spawn_id
+    if [info exists x] { set spawn_id $x }
+
+    expect_tcl_prompt
+    # tcl 8.4 for some reason screws up autodetection of output EOL
+    # translation.  Work around it for now.
+    send_tcl_cmd_await_echo "if { \[info commands fconfigure\] != \"\" } { fconfigure stdout -translation lf }"
+    expect_tcl_prompt
+    send_tcl_cmd_await_echo "source {$TCLUTIL}"
+    expect_tcl_prompt
+    send_tcl_cmd_await_echo "set h {$CANON_HOST}"
+    expect {
+	-ex "$CANON_HOST\r\n" { }
+	timeout { perror "timeout waiting for subprocess" }
+	eof { perror "eof from subprocess" }
+    }
+    expect_tcl_prompt
+
+    send_tcl_cmd_await_echo {ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle}
+    expect_kadm_ok
+    expect "^% "
+    send_tcl_cmd_await_echo {ovsec_kadm_create_principal $server_handle [simple_principal server/$h] {OVSEC_KADM_PRINCIPAL} admin}
+    expect_kadm_ok
+    expect "^% "
+    send_tcl_cmd_await_echo {ovsec_kadm_randkey_principal $server_handle server/$h key}
+    expect_kadm_ok
+    expect "^% "
+    send_tcl_cmd_await_echo {ovsec_kadm_create_principal $server_handle [simple_principal notserver/$h] {OVSEC_KADM_PRINCIPAL} admin}
+    expect_kadm_ok
+    expect "^% "
+    send_tcl_cmd_await_echo {ovsec_kadm_randkey_principal $server_handle notserver/$h key}
+    expect_kadm_ok
+    expect "^% "
+    send_tcl_cmd_await_echo {ovsec_kadm_destroy $server_handle}
+    expect_kadm_ok
+    expect "^% "
+    wait -nowait -i $spawn_id
+    close -i $spawn_id
+}
+
+if ![info exists CANON_HOST] {
+    set CANON_HOST [exec $env(QUALNAME)]
+    setup_database
+    file delete $env(RPC_TEST_SRVTAB)
+    exec $env(MAKE_KEYTAB) -princ "server/$CANON_HOST" $env(RPC_TEST_SRVTAB)
+}
+
+
+proc kinit {princ pass lifetime} {
+	global kinit
+	global wait_error_index wait_errno_index wait_status_index
+
+	spawn -noecho $kinit -5 -l $lifetime $princ
+	expect {
+		-re "Password for $princ.*: " { send "$pass\n"; expect eof }
+		timeout { perror "Timeout waiting for kinit"; close }
+		eof
+	}
+
+	set ret [wait]
+	if {[lindex $ret $wait_error_index] == -1} {
+	 	perror \
+	    "wait(kinit $princ) returned error [lindex $ret $wait_errno_index]"
+	} else {
+		if {[lindex $ret $wait_status_index] != 0} {
+			perror \
+		    "kinit $princ failed with [lindex $ret $wait_status_index]"
+		}
+	}
+}
+
+proc flush_server {} {
+	global server_id
+	global expect_out
+
+	verbose "flushing server output" 1
+
+	while {1} {
+		set timeout 5
+
+		expect {
+			-i $server_id
+			-re "^.+$" {
+			    verbose "server output: $expect_out(buffer)"
+			}
+			timeout { break }
+		}
+	}
+}
+
+proc start_client {testname ccname user password lifetime count
+		  {target ""}} {
+	global env CLIENT PROT hostname spawn_id verbose
+
+	if {$target == ""} {
+		set target "server@$hostname"
+	}
+
+	set env(KRB5CCNAME) FILE:[pwd]/krb5cc_rpc_test_$ccname
+	kinit $user $password $lifetime
+
+	if {$verbose > 0} {
+		spawn $CLIENT -a 1 -s 1 -m 1 $PROT $hostname $target $count
+	} else {
+		spawn $CLIENT $PROT $hostname $target $count
+	}
+
+	verbose "$testname: client $ccname started"
+
+	unset env(KRB5CCNAME)
+}
+
+proc eof_client {testname ccname id status} {
+	verbose "$testname: eof'ing for client $ccname" 1
+
+	expect {
+		-i $id
+		-re "^marshall_new_creds\[^\n\]*\n" { exp_continue }
+		-re "^gssapi_\[^\n\]*\n" { exp_continue }
+		-re "^\r?\n" { exp_continue }
+		eof { verbose $expect_out(buffer) 1 }
+		timeout { 
+			fail "$testname: timeout waiting for client $ccname to exit"
+		}
+	}
+	wait_client $testname $ccname $id $status
+}
+
+
+proc wait_client {testname ccname id status} {
+	global env
+	global kill
+	global kdestroy
+	global wait_error_index wait_errno_index wait_status_index
+
+	verbose "$testname: waiting for client $ccname" 1
+
+	set ret [wait -i $id]
+	if {[lindex $ret $wait_error_index] == -1} {
+		fail \
+       "$testname: wait $ccname returned error [lindex $ret $wait_errno_index]"
+	} else {
+		if {[lindex $ret $wait_status_index] == $status} {
+			pass "$testname: client $ccname"
+		} else {
+			fail "$testname: client $ccname: unexpected return status [lindex $ret $wait_status_index], should be $status."
+		}
+	}
+
+	set env(KRB5CCNAME) FILE:[pwd]/krb5cc_rpc_test_$ccname
+ 	if {[catch "exec $kdestroy -5"] != 0} {
+ 		perror "$testname: cannot destroy client $ccname ccache"
+ 	}
+
+	unset env(KRB5CCNAME)
+}
diff --git a/mechglue/src/lib/rpc/unit-test/rpc_test.0/expire.exp b/mechglue/src/lib/rpc/unit-test/rpc_test.0/expire.exp
new file mode 100644
index 000000000..5c33ffde5
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/rpc_test.0/expire.exp
@@ -0,0 +1,46 @@
+set timeout 40
+
+load_lib "helpers.exp"
+
+global spawn_id
+
+proc expired {} {
+    global spawn_id server_id
+
+    start_client expired expired testuser notathena -1m 100
+    eof_client expired expired $spawn_id 2
+
+    expect {
+	-i $server_id
+	-re "rpc_test server: Authen.*failed: .* referenced credentials have expired" { pass "expired" }
+	timeout { fail "expired: timeout waiting for expired creds error" }
+    }
+
+    flush_server
+}
+expired
+
+proc overlap {} {
+    global spawn_id
+
+    start_client expire 1 testuser notathena 20m 100
+    set client1_id $spawn_id
+    flush_server
+    
+    start_client expire 2 testuser notathena 40m 300
+    set client2_id $spawn_id
+    flush_server
+    
+    start_client expire 3 testuser notathena 60m 500
+    set client3_id $spawn_id
+    flush_server
+    
+    eof_client expire 1 $client1_id 0
+    eof_client expire 2 $client2_id 0
+    eof_client expire 3 $client3_id 0
+
+    flush_server
+}
+overlap
+
+
diff --git a/mechglue/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp b/mechglue/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
new file mode 100644
index 000000000..7cdda8af1
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
@@ -0,0 +1,95 @@
+set timeout 120
+
+load_lib "helpers.exp"
+
+global spawn_id
+global server_id
+
+# Start the client and do a full run
+start_client "full run" fullrun testuser notathena 8h 1026
+set client_id $spawn_id
+
+#
+# test: did we get 11 dots?
+#
+verbose "Starting RPC echo test.  This will take about 50 seconds.\n"
+
+set ver_line "rpc_test server: bad verifier\[^\r\n\]*\[\r\n]+"
+
+set dots 0
+set server_lines 0
+while {1} {
+	set oldtimeout $timeout
+	set timeout 5
+	while {1} {
+		expect {
+			-i $server_id
+			-re $ver_line {
+				verbose "Got line from server."
+				incr server_lines
+			}
+			default {
+				break
+			}
+		}
+	}
+	set timeout $oldtimeout
+	expect {
+		-i $client_id
+		. { 
+			incr dots
+			verbose "$expect_out(buffer)" 1
+			if ($dots==11) { break }
+		}
+		eof {
+			#
+			# test: was the exit status right?
+			#
+			wait_client "full run" fullrun $client_id 0
+			break
+		}
+
+		timeout { 
+			verbose "Timeout waiting for dot\n" 1
+			fail "full run: timeout waiting for dot"
+			break
+		}
+
+	}
+}
+if {$dots==11} {
+	pass "fullrun: echo test"
+} else {
+	fail "fullrun: echo test: expected 11 dots, got $dots"
+}
+
+#
+# test: server logged four bad verifiers?
+#
+verbose "full run: checking server output"
+
+# Small timeout, since the server should have already printed everything
+set timeout 5
+
+while {$server_lines < 4} {
+	expect {
+		-i $server_id
+		-re $ver_line {
+			incr server_lines
+		}
+		-re ".+\r\n" {
+			verbose "Unexpected server output: $expect_out(buffer)"
+		}
+		default {
+			break
+		}
+	}
+}
+
+if {$server_lines == 4} {
+	pass "fullrun: bad verifiers"
+} else {
+	fail "fullrun: expected four bad verifiers, got $server_lines"
+}
+
+flush_server
diff --git a/mechglue/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp b/mechglue/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
new file mode 100644
index 000000000..2bb936ab5
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
@@ -0,0 +1,27 @@
+set timeout 30
+
+load_lib "helpers.exp"
+
+global spawn_id
+global server_id
+global hostname
+
+start_client "gss err" gsserr testuser notathena 8h 1026 notserver@$hostname
+
+eof_client "gss err" gsserr $spawn_id 2
+
+#
+# test: server logged an authentication attempted failed?
+#
+verbose "gss err: checking server output"
+
+expect {
+	-i $server_id
+	-re "rpc_test server: Authent.*failed: .* Wrong princ" {
+		pass "gss err: server logged auth error"
+	}
+	eof { fail "gss err: server exited" }
+	timeout { fail "gss err: timeout waiting for server output" }
+}
+
+flush_server
diff --git a/mechglue/src/lib/rpc/unit-test/rpc_test.h b/mechglue/src/lib/rpc/unit-test/rpc_test.h
new file mode 100644
index 000000000..2ad039955
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/rpc_test.h
@@ -0,0 +1,13 @@
+#ifndef _RPC_TEST_H_RPCGEN
+#define	_RPC_TEST_H_RPCGEN
+
+#include <gssrpc/rpc.h>
+
+#define	RPC_TEST_PROG ((unsigned long)(1000001))
+#define	RPC_TEST_VERS_1 ((unsigned long)(1))
+#define	RPC_TEST_ECHO ((unsigned long)(1))
+extern char ** rpc_test_echo_1_svc(char **, struct svc_req *);
+extern char ** rpc_test_echo_1(char **, CLIENT *);
+extern void rpc_test_prog_1_svc(struct svc_req *, SVCXPRT *);
+
+#endif /* !_RPC_TEST_H_RPCGEN */
diff --git a/mechglue/src/lib/rpc/unit-test/rpc_test.x b/mechglue/src/lib/rpc/unit-test/rpc_test.x
new file mode 100644
index 000000000..e9ae27c97
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/rpc_test.x
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ * 
+ * $Log$
+ * Revision 1.2  1996/07/22 20:41:42  marc
+ * this commit includes all the changes on the OV_9510_INTEGRATION and
+ * OV_MERGE branches.  This includes, but is not limited to, the new openvision
+ * admin system, and major changes to gssapi to add functionality, and bring
+ * the implementation in line with rfc1964.  before committing, the
+ * code was built and tested for netbsd and solaris.
+ *
+ * Revision 1.1.4.1  1996/07/18 04:20:04  marc
+ * merged in changes from OV_9510_BP to OV_9510_FINAL1
+ *
+# Revision 1.1.2.1  1996/06/20  23:42:06  marc
+# File added to the repository on a branch
+#
+# Revision 1.1  1993/11/03  23:53:58  bjaspan
+# Initial revision
+#
+ */
+
+program RPC_TEST_PROG {
+	version RPC_TEST_VERS_1 {
+		string RPC_TEST_ECHO(string) = 1;
+	} = 1;
+} = 1000001;
diff --git a/mechglue/src/lib/rpc/unit-test/rpc_test_clnt.c b/mechglue/src/lib/rpc/unit-test/rpc_test_clnt.c
new file mode 100644
index 000000000..736392551
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/rpc_test_clnt.c
@@ -0,0 +1,22 @@
+#include "rpc_test.h"
+#include <string.h>
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+char **
+rpc_test_echo_1(argp, clnt)
+	char **argp;
+	CLIENT *clnt;
+{
+	static char *clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof (clnt_res));
+	if (clnt_call(clnt, RPC_TEST_ECHO,
+		(xdrproc_t) xdr_wrapstring, (caddr_t) argp,
+		(xdrproc_t) xdr_wrapstring, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
diff --git a/mechglue/src/lib/rpc/unit-test/rpc_test_setup.sh b/mechglue/src/lib/rpc/unit-test/rpc_test_setup.sh
new file mode 100755
index 000000000..0f8ca9d93
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/rpc_test_setup.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# This script performs additional setup for the RPC unit test.  It
+# assumes that gmake has put TOP and RPC_TEST_SRVTAB into the
+# environment. 
+#
+# $Id$
+# $Source$
+
+DUMMY=${TESTDIR=$TOP/testing}
+DUMMY=${CLNTTCL=$TESTDIR/util/ovsec_kadm_clnt_tcl}
+DUMMY=${TCLUTIL=$TESTDIR/tcl/util.t}; export TCLUTIL
+DUMMY=${MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl}
+
+if $VERBOSE; then
+	REDIRECT=
+else
+	REDIRECT='>/dev/null'
+fi
+
+PATH=$TOP/install/admin:$PATH; export PATH
+
+CANON_HOST=`$QUALNAME`
+export CANON_HOST
+
+cat - > /tmp/rpc_test_setup$$ <<\EOF
+source $env(TCLUTIL)
+set h $env(CANON_HOST)
+puts stdout [ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle]
+if ![info exists server_handle] { exit 1 }
+puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal server/$h] {OVSEC_KADM_PRINCIPAL} admin]
+puts stdout [ovsec_kadm_randkey_principal $server_handle server/$h key]
+puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal notserver/$h] {OVSEC_KADM_PRINCIPAL} admin]
+puts stdout [ovsec_kadm_randkey_principal $server_handle notserver/$h key]
+puts stdout [ovsec_kadm_destroy $server_handle]
+EOF
+eval "$CLNTTCL $REDIRECT < /tmp/rpc_test_setup$$"
+if test $? != 0 ; then
+    rm /tmp/rpc_test_setup$$
+    echo 1>&2 error setting up database for tests
+    exit 1
+fi
+rm /tmp/rpc_test_setup$$
+
+rm -f $RPC_TEST_SRVTAB
+
+eval $MAKE_KEYTAB -princ server/$CANON_HOST $RPC_TEST_SRVTAB $REDIRECT
+
+# grep -s "$CANON_HOST SECURE-TEST.OV.COM" /etc/krb.realms
+# if [ $? != 0 ]; then
+# 	eval echo \"Adding \$CANON_HOST SECURE-TEST.OV.COM to /etc/krb.realms\" $REDIRECT
+# 	ed /etc/krb.realms <<EOF >/dev/null
+# 1i
+# $CANON_HOST SECURE-TEST.OV.COM
+# .
+# w
+# q
+# EOF
+# fi
diff --git a/mechglue/src/lib/rpc/unit-test/rpc_test_svc.c b/mechglue/src/lib/rpc/unit-test/rpc_test_svc.c
new file mode 100644
index 000000000..4200d955c
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/rpc_test_svc.c
@@ -0,0 +1,74 @@
+#include "rpc_test.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h> /* getenv, exit */
+#include <sys/types.h>
+#include <syslog.h>
+
+/* States a server can be in wrt request */
+
+#define	_IDLE 0
+#define	_SERVED 1
+
+static int _rpcsvcstate = _IDLE;	/* Set when a request is serviced */
+static int _rpcsvccount = 0;		/* Number of requests being serviced */
+
+static
+void _msgout(msg)
+	char *msg;
+{
+	syslog(LOG_ERR, msg);
+}
+
+void
+rpc_test_prog_1_svc(rqstp, transp)
+	struct svc_req *rqstp;
+	register SVCXPRT *transp;
+{
+	union {
+		char *rpc_test_echo_1_arg;
+	} argument;
+	char *result;
+	bool_t (*xdr_argument)(), (*xdr_result)();
+	char *(*local)();
+
+	_rpcsvccount++;
+	switch (rqstp->rq_proc) {
+	case NULLPROC:
+		(void) svc_sendreply(transp, xdr_void,
+			(char *)NULL);
+		_rpcsvccount--;
+		_rpcsvcstate = _SERVED;
+		return;
+
+	case RPC_TEST_ECHO:
+		xdr_argument = xdr_wrapstring;
+		xdr_result = xdr_wrapstring;
+		local = (char *(*)()) rpc_test_echo_1_svc;
+		break;
+
+	default:
+		svcerr_noproc(transp);
+		_rpcsvccount--;
+		_rpcsvcstate = _SERVED;
+		return;
+	}
+	(void) memset((char *)&argument, 0, sizeof (argument));
+	if (!svc_getargs(transp, xdr_argument, &argument)) {
+		svcerr_decode(transp);
+		_rpcsvccount--;
+		_rpcsvcstate = _SERVED;
+		return;
+	}
+	result = (*local)(&argument, rqstp);
+	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+		svcerr_systemerr(transp);
+	}
+	if (!svc_freeargs(transp, xdr_argument, &argument)) {
+		_msgout("unable to free arguments");
+		exit(1);
+	}
+	_rpcsvccount--;
+	_rpcsvcstate = _SERVED;
+	return;
+}
diff --git a/mechglue/src/lib/rpc/unit-test/server.c b/mechglue/src/lib/rpc/unit-test/server.c
new file mode 100644
index 000000000..df8f4c993
--- /dev/null
+++ b/mechglue/src/lib/rpc/unit-test/server.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <signal.h>
+#include <gssrpc/rpc.h>
+#include <gssrpc/pmap_clnt.h>
+#include <arpa/inet.h>  /* inet_ntoa */
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#include <gssrpc/auth_gssapi.h>
+#include <sys/param.h>	/* MAXHOSTNAMELEN */
+#include "rpc_test.h"
+
+extern int svc_debug_gssapi, misc_debug_gssapi;
+
+void rpc_test_badauth(OM_uint32 major, OM_uint32 minor,
+		 struct sockaddr_in *addr, caddr_t data);
+void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg, char
+		 *error, char *data);
+void log_badauth_display_status(OM_uint32 major, OM_uint32 minor);
+void log_badauth_display_status_1(OM_uint32 code, int type, int rec);
+static void rpc_test_badverf(gss_name_t client, gss_name_t server,
+			     struct svc_req *rqst, struct rpc_msg *msg,
+			     caddr_t data);
+
+#ifndef SERVICE_NAME
+#define SERVICE_NAME "server"
+#endif
+
+static void usage()
+{
+     fprintf(stderr, "Usage: server {-t|-u} [svc-debug] [misc-debug]\n");
+     exit(1);
+}
+
+#ifdef POSIX_SIGNALS
+static void handlesig(int dummy)
+#else
+static void handlesig(void)
+#endif
+{
+    exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+     int c, prot;
+     auth_gssapi_name names[2];
+     register SVCXPRT *transp;
+     extern int optind;
+#ifdef POSIX_SIGNALS
+     struct sigaction sa;
+#endif     
+
+     names[0].name = SERVICE_NAME;
+     names[0].type = (gss_OID) gss_nt_service_name;
+     names[1].name = 0;
+     names[1].type = 0;
+
+     prot = 0;
+     while ((c = getopt(argc, argv, "tu")) != -1) {
+	  switch (c) {
+	  case 't':
+	       prot = IPPROTO_TCP;
+	       break;
+	  case 'u':
+	       prot = IPPROTO_UDP;
+	       break;
+	  case '?':
+	       usage();
+	       break;
+	  }
+     }
+     if (prot == 0)
+	  usage();
+
+     argv += optind;
+     argc -= optind;
+
+     switch (argc) {
+     case 2:
+	  misc_debug_gssapi = atoi(argv[1]);
+     case 1:
+	  svc_debug_gssapi = atoi(argv[0]);
+     case 0:
+	  break;
+     default:
+	  usage();
+	  exit(1);
+     }
+
+     (void) pmap_unset(RPC_TEST_PROG, RPC_TEST_VERS_1);
+
+     if (prot == IPPROTO_TCP)
+	  transp = svctcp_create(RPC_ANYSOCK, 0, 0);
+     else
+	  transp = svcudp_create(RPC_ANYSOCK);
+     if (transp == NULL) {
+	  fprintf(stderr, "cannot create tcp service.");
+	  exit(1);
+     }
+     if (!svc_register(transp, RPC_TEST_PROG, RPC_TEST_VERS_1,
+		       rpc_test_prog_1_svc, prot)) { 
+	  fprintf(stderr,
+		  "unable to register (RPC_TEST_PROG, RPC_TEST_VERS_1, %s).",
+		  prot == IPPROTO_TCP ? "tcp" : "udp");
+	  exit(1);
+     }
+     
+     if (svcauth_gssapi_set_names(names, 0) == FALSE) {
+	  fprintf(stderr, "unable to set gssapi names\n");
+	  exit(1);
+     }
+
+     svcauth_gssapi_set_log_badauth_func(rpc_test_badauth, NULL);
+     svcauth_gssapi_set_log_badverf_func(rpc_test_badverf, NULL);
+     svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL);
+
+#ifdef POSIX_SIGNALS
+     (void) sigemptyset(&sa.sa_mask);
+     sa.sa_flags = 0;
+     sa.sa_handler = handlesig;
+     (void) sigaction(SIGHUP, &sa, NULL);
+     (void) sigaction(SIGINT, &sa, NULL);
+     (void) sigaction(SIGTERM, &sa, NULL);
+#else
+     signal(SIGHUP, handlesig);
+     signal(SIGINT, handlesig);
+     signal(SIGTERM, handlesig);
+#endif
+     printf("running\n");
+     
+     svc_run();
+     fprintf(stderr, "svc_run returned");
+     exit(1);
+     /* NOTREACHED */
+}
+
+char **rpc_test_echo_1_svc(char **arg, struct svc_req *h)
+{
+     static char *res = NULL;
+
+     if (res)
+	  free(res);
+     res = (char *) malloc(strlen(*arg) + strlen("Echo: ") + 1);
+     sprintf(res, "Echo: %s", *arg);
+     return &res;
+}
+
+static void rpc_test_badverf(gss_name_t client, gss_name_t server,
+			     struct svc_req *rqst, struct rpc_msg *msg,
+			     caddr_t data)
+{
+     OM_uint32 minor_stat;
+     gss_OID type;
+     gss_buffer_desc client_name, server_name;
+
+     (void) gss_display_name(&minor_stat, client, &client_name, &type);
+     (void) gss_display_name(&minor_stat, server, &server_name, &type);
+
+     printf("rpc_test server: bad verifier from %.*s at %s:%d for %.*s\n",
+	    (int) client_name.length, (char *) client_name.value,
+	    inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr), 
+	    ntohs(rqst->rq_xprt->xp_raddr.sin_port),
+	    (int) server_name.length, (char *) server_name.value);
+
+     (void) gss_release_buffer(&minor_stat, &client_name);
+     (void) gss_release_buffer(&minor_stat, &server_name);
+}
+
+/*
+ * Function: log_badauth
+ *
+ * Purpose: Callback from GSS-API Sun RPC for authentication
+ * failures/errors.
+ *
+ * Arguments:
+ * 	major 		(r) GSS-API major status
+ * 	minor		(r) GSS-API minor status
+ * 	addr		(r) originating address
+ * 	data		(r) arbitrary data (NULL), not used
+ *
+ * Effects:
+ *
+ * Logs the GSS-API error to stdout.
+ */
+void rpc_test_badauth(OM_uint32 major, OM_uint32 minor,
+		 struct sockaddr_in *addr, caddr_t data)
+{
+     char *a;
+     
+     /* Authentication attempt failed: <IP address>, <GSS-API error */
+     /* strings> */
+
+     a = inet_ntoa(addr->sin_addr);
+
+     printf("rpc_test server: Authentication attempt failed: %s", a);
+     log_badauth_display_status(major, minor);
+     printf("\n");
+}
+
+void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
+		 char *error, char *data)
+{
+     char *a;
+     
+     a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
+     printf("Miscellaneous RPC error: %s, %s\n", a, error);
+}
+
+void log_badauth_display_status(OM_uint32 major, OM_uint32 minor)
+{
+     log_badauth_display_status_1(major, GSS_C_GSS_CODE, 0);
+     log_badauth_display_status_1(minor, GSS_C_MECH_CODE, 0);
+}
+
+void log_badauth_display_status_1(OM_uint32 code, int type, int rec)
+{
+     OM_uint32 gssstat, minor_stat, msg_ctx;
+     gss_buffer_desc msg;
+
+     msg_ctx = 0;
+     while (1) {
+	  gssstat = gss_display_status(&minor_stat, code,
+				       type, GSS_C_NULL_OID,
+				       &msg_ctx, &msg);
+	  if (gssstat != GSS_S_COMPLETE) {
+ 	       if (!rec) {
+		    log_badauth_display_status_1(gssstat,GSS_C_GSS_CODE,1); 
+		    log_badauth_display_status_1(minor_stat,
+						 GSS_C_MECH_CODE, 1);
+	       } else
+		    printf("GSS-API authentication error %.*s: "
+			   "recursive failure!\n", (int) msg.length, 
+			   (char *)msg.value);
+	       return;
+	  }
+	  
+	  printf(", %.*s", (int) msg.length, (char *)msg.value); 
+	  (void) gss_release_buffer(&minor_stat, &msg);
+	  
+	  if (!msg_ctx)
+	       break;
+     }
+}
+
+
+#if 0
+
+/* this hack is no longer necessary, since the library supports it
+   internally */
+
+/* This is a hack to change the default keytab name */
+
+#include <krb5/krb5.h>
+extern char *krb5_defkeyname;
+
+krb5_error_code
+krb5_kt_default_name(char *name, int namesize)
+{
+   char *ktname;
+
+   if ((ktname = getenv("KRB5KTNAME")) == NULL)
+      ktname = krb5_defkeyname;
+
+   if (namesize < strlen(ktname)+1)
+      return(KRB5_CONFIG_NOTENUFSPACE);
+
+   strcpy(name, ktname);
+
+   return(0);
+}
+
+#endif
diff --git a/mechglue/src/lib/rpc/xdr.c b/mechglue/src/lib/rpc/xdr.c
new file mode 100644
index 000000000..ec0d27717
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr.c
@@ -0,0 +1,637 @@
+/* @(#)xdr.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr.c 1.35 87/08/12";
+#endif
+
+/*
+ * xdr.c, Generic XDR routines implementation.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ *
+ * These are the "generic" xdr routines used to serialize and de-serialize
+ * most common data items.  See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+
+/*
+ * constants specific to the xdr "protocol"
+ */
+#define XDR_FALSE	((long) 0)
+#define XDR_TRUE	((long) 1)
+#define LASTUNSIGNED	((u_int) 0-1)
+
+/*
+ * for unit alignment
+ */
+static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
+
+/*
+ * Free a data structure using XDR
+ * Not a filter, but a convenient utility nonetheless
+ */
+void
+xdr_free(xdrproc_t proc, void *objp)
+{
+	XDR x;
+	
+	x.x_op = XDR_FREE;
+	(*proc)(&x, objp);
+}
+
+/*
+ * XDR nothing
+ */
+bool_t
+xdr_void(XDR *xdrs, void *addr)
+{
+
+	return (TRUE);
+}
+
+/*
+ * XDR integers
+ */
+bool_t
+xdr_int(XDR *xdrs, int *ip)
+{
+	long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		if (*ip > 0x7fffffffL || *ip < -0x7fffffffL - 1L)
+			return (FALSE);
+
+		l = (long) *ip;
+		return (XDR_PUTLONG(xdrs, &l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, &l))
+			return (FALSE);
+
+		if (l > INT_MAX || l < INT_MIN)
+			return (FALSE);
+
+		*ip = (int) l;
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/*NOTREACHED*/
+	return(FALSE);
+}
+
+/*
+ * XDR unsigned integers
+ */
+bool_t
+xdr_u_int(XDR *xdrs, u_int *up)
+{
+	u_long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		if (*up > 0xffffffffUL)
+			return (FALSE);
+
+		l = (u_long)*up;
+		return (XDR_PUTLONG(xdrs, (long *) &l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, (long *) &l))
+			return (FALSE);
+
+		if (l > UINT_MAX)
+			return (FALSE);
+
+		*up = (u_int) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/*NOTREACHED*/
+	return(FALSE);
+}
+
+/*
+ * XDR long integers
+ */
+bool_t
+xdr_long(XDR *xdrs, long *lp)
+{
+
+	switch (xdrs->x_op) {
+	case XDR_ENCODE:
+		if (*lp > 0x7fffffffL || *lp < -0x7fffffffL - 1L)
+			return (FALSE);
+
+		return (XDR_PUTLONG(xdrs, lp));
+
+	case XDR_DECODE:
+		return (XDR_GETLONG(xdrs, lp));
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
+ * XDR unsigned long integers
+ */
+bool_t
+xdr_u_long(XDR *xdrs, u_long *ulp)
+{
+
+	switch (xdrs->x_op) {
+	case XDR_ENCODE:
+		if (*ulp > 0xffffffffUL)
+			return (FALSE);
+
+		return (XDR_PUTLONG(xdrs, (long *) ulp));
+
+	case XDR_DECODE:
+		return (XDR_GETLONG(xdrs, (long *) ulp));
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
+ * XDR short integers
+ */
+bool_t
+xdr_short(register XDR *xdrs, short *sp)
+{
+	long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (long) *sp;
+		return (XDR_PUTLONG(xdrs, &l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, &l)) {
+			return (FALSE);
+		}
+		if (l > SHRT_MAX || l < SHRT_MIN)
+			return (FALSE);
+
+		*sp = (short) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
+ * XDR unsigned short integers
+ */
+bool_t
+xdr_u_short(register XDR *xdrs, u_short *usp)
+{
+	u_long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (u_long) *usp;
+		return (XDR_PUTLONG(xdrs, (long *) &l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, (long *) &l)) {
+			return (FALSE);
+		}
+		*usp = (u_short) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+
+/*
+ * XDR a char
+ */
+bool_t
+xdr_char(XDR *xdrs, char *cp)
+{
+	int i;
+
+	i = (*cp);
+	if (!xdr_int(xdrs, &i)) {
+		return (FALSE);
+	}
+	*cp = i;
+	return (TRUE);
+}
+
+/*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char(XDR *xdrs, u_char *cp)
+{
+	u_int u;
+
+	u = (*cp);
+	if (!xdr_u_int(xdrs, &u)) {
+		return (FALSE);
+	}
+	*cp = u;
+	return (TRUE);
+}
+
+/*
+ * XDR booleans
+ */
+bool_t
+xdr_bool(register XDR *xdrs, bool_t *bp)
+{
+	long lb;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		lb = *bp ? XDR_TRUE : XDR_FALSE;
+		return (XDR_PUTLONG(xdrs, &lb));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, &lb)) {
+			return (FALSE);
+		}
+		*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
+ * XDR enumerations
+ */
+bool_t
+xdr_enum(XDR *xdrs, enum_t *ep)
+{
+#ifndef lint
+	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
+
+	/*
+	 * enums are treated as ints
+	 */
+	if (sizeof (enum sizecheck) == sizeof (long)) {
+		return (xdr_long(xdrs, (long *)ep));
+	} else if (sizeof (enum sizecheck) == sizeof (int)) {
+		return (xdr_int(xdrs, (int *)ep));
+	} else if (sizeof (enum sizecheck) == sizeof (short)) {
+		return (xdr_short(xdrs, (short *)ep));
+	} else {
+		return (FALSE);
+	}
+#else
+	(void) (xdr_short(xdrs, (short *)ep));
+	return (xdr_long(xdrs, (long *)ep));
+#endif
+}
+
+/*
+ * XDR opaque data
+ * Allows the specification of a fixed size sequence of opaque bytes.
+ * cp points to the opaque object and cnt gives the byte length.
+ */
+bool_t
+xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
+{
+	register u_int rndup;
+	static int crud[BYTES_PER_XDR_UNIT];
+
+	/*
+	 * if no data we are done
+	 */
+	if (cnt == 0)
+		return (TRUE);
+
+	/*
+	 * round byte count to full xdr units
+	 */
+	rndup = cnt % BYTES_PER_XDR_UNIT;
+	if (rndup > 0)
+		rndup = BYTES_PER_XDR_UNIT - rndup;
+
+	if (xdrs->x_op == XDR_DECODE) {
+		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
+			return (FALSE);
+		}
+		if (rndup == 0)
+			return (TRUE);
+		return (XDR_GETBYTES(xdrs, (caddr_t) (void *)crud, rndup));
+	}
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
+			return (FALSE);
+		}
+		if (rndup == 0)
+			return (TRUE);
+		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
+	}
+
+	if (xdrs->x_op == XDR_FREE) {
+		return (TRUE);
+	}
+
+	return (FALSE);
+}
+
+/*
+ * XDR counted bytes
+ * *cpp is a pointer to the bytes, *sizep is the count.
+ * If *cpp is NULL maxsize bytes are allocated
+ */
+bool_t
+xdr_bytes(
+	XDR *xdrs,
+	char **cpp,
+	u_int *sizep,
+	u_int maxsize)
+{
+	register char *sp = *cpp;  /* sp is the actual string pointer */
+	register u_int nodesize;
+
+	/*
+	 * first deal with the length since xdr bytes are counted
+	 */
+	if (! xdr_u_int(xdrs, sizep)) {
+		return (FALSE);
+	}
+	nodesize = *sizep;
+	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
+		return (FALSE);
+	}
+
+	/*
+	 * now deal with the actual bytes
+	 */
+	switch (xdrs->x_op) {
+
+	case XDR_DECODE:
+		if (nodesize == 0) {
+			return (TRUE);
+		}
+		if (sp == NULL) {
+			*cpp = sp = (char *)mem_alloc(nodesize);
+		}
+		if (sp == NULL) {
+			(void) fprintf(stderr, "xdr_bytes: out of memory\n");
+			return (FALSE);
+		}
+		/* fall into ... */
+
+	case XDR_ENCODE:
+		return (xdr_opaque(xdrs, sp, nodesize));
+
+	case XDR_FREE:
+		if (sp != NULL) {
+			mem_free(sp, nodesize);
+			*cpp = NULL;
+		}
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
+ * Implemented here due to commonality of the object.
+ */
+bool_t
+xdr_netobj(XDR *xdrs, struct netobj *np)
+{
+
+	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
+}
+
+bool_t
+xdr_int32(XDR *xdrs, int32_t *ip)
+{
+	long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = *ip;
+		return (xdr_long(xdrs, &l));    
+
+	case XDR_DECODE:
+		if (!xdr_long(xdrs, &l)) {
+			return (FALSE);
+		}
+		*ip = l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);    
+	}
+	return (FALSE);
+}
+
+bool_t
+xdr_u_int32(XDR *xdrs, uint32_t *up)
+{
+	u_long ul;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		ul = *up;
+		return (xdr_u_long(xdrs, &ul));    
+
+	case XDR_DECODE:
+		if (!xdr_u_long(xdrs, &ul)) {
+			return (FALSE);
+		}
+		*up = ul;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);    
+	}
+	return (FALSE);
+}
+
+/*
+ * XDR a descriminated union
+ * Support routine for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * an entry with a null procedure pointer.  The routine gets
+ * the discriminant value and then searches the array of xdrdiscrims
+ * looking for that value.  It calls the procedure given in the xdrdiscrim
+ * to handle the discriminant.  If there is no specific routine a default
+ * routine may be called.
+ * If there is no specific or default routine an error is returned.
+ */
+bool_t
+xdr_union(
+	XDR *xdrs,
+	enum_t *dscmp,		/* enum to decide which arm to work on */
+	char *unp,		/* the union itself */
+	struct xdr_discrim *choices,	/* [value, xdr proc] for each arm */
+	xdrproc_t dfault	/* default xdr routine */
+	)
+{
+	register enum_t dscm;
+
+	/*
+	 * we deal with the discriminator;  it's an enum
+	 */
+	if (! xdr_enum(xdrs, dscmp)) {
+		return (FALSE);
+	}
+	dscm = *dscmp;
+
+	/*
+	 * search choices for a value that matches the discriminator.
+	 * if we find one, execute the xdr routine for that value.
+	 */
+	for (; choices->proc != NULL_xdrproc_t; choices++) {
+		if (choices->value == dscm)
+			return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
+	}
+
+	/*
+	 * no match - execute the default xdr routine if there is one
+	 */
+	return ((dfault == NULL_xdrproc_t) ? FALSE :
+	    (*dfault)(xdrs, unp, LASTUNSIGNED));
+}
+
+
+/*
+ * Non-portable xdr primitives.
+ * Care should be taken when moving these routines to new architectures.
+ */
+
+
+/*
+ * XDR null terminated ASCII strings
+ * xdr_string deals with "C strings" - arrays of bytes that are
+ * terminated by a NULL character.  The parameter cpp references a
+ * pointer to storage; If the pointer is null, then the necessary
+ * storage is allocated.  The last parameter is the max allowed length
+ * of the string as specified by a protocol.
+ */
+bool_t
+xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
+{
+	register char *sp = *cpp;  /* sp is the actual string pointer */
+	u_int size;
+	u_int nodesize;
+
+	/*
+	 * first deal with the length since xdr strings are counted-strings
+	 */
+	switch (xdrs->x_op) {
+	case XDR_FREE:
+		if (sp == NULL) {
+			return(TRUE);	/* already free */
+		}
+		/* fall through... */
+	case XDR_ENCODE:
+		size = strlen(sp);
+		break;
+	case XDR_DECODE:
+		break;
+	}
+	if (! xdr_u_int(xdrs, &size)) {
+		return (FALSE);
+	}
+	if (size >= maxsize) {
+		return (FALSE);
+	}
+	nodesize = size + 1;
+
+	/*
+	 * now deal with the actual bytes
+	 */
+	switch (xdrs->x_op) {
+
+	case XDR_DECODE:
+		if (nodesize == 0) {
+			return (TRUE);
+		}
+		if (sp == NULL)
+			*cpp = sp = (char *)mem_alloc(nodesize);
+		if (sp == NULL) {
+			(void) fprintf(stderr, "xdr_string: out of memory\n");
+			return (FALSE);
+		}
+		sp[size] = 0;
+		/* fall into ... */
+
+	case XDR_ENCODE:
+		return (xdr_opaque(xdrs, sp, size));
+
+	case XDR_FREE:
+		mem_free(sp, nodesize);
+		*cpp = NULL;
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/* 
+ * Wrapper for xdr_string that can be called directly from 
+ * routines like clnt_call
+ */
+bool_t
+xdr_wrapstring(XDR *xdrs, char **cpp)
+{
+	if (xdr_string(xdrs, cpp, LASTUNSIGNED)) {
+		return (TRUE);
+	}
+	return (FALSE);
+}
diff --git a/mechglue/src/lib/rpc/xdr.h b/mechglue/src/lib/rpc/xdr.h
new file mode 100644
index 000000000..943e39e2a
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr.h
@@ -0,0 +1,334 @@
+/* @(#)xdr.h	2.2 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*      @(#)xdr.h 1.19 87/04/22 SMI      */
+
+/*
+ * xdr.h, External Data Representation Serialization Routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef GSSRPC_XDR_H
+#define GSSRPC_XDR_H
+
+#include <stdio.h>		/* for FILE */
+
+GSSRPC__BEGIN_DECLS
+/*
+ * XDR provides a conventional way for converting between C data
+ * types and an external bit-string representation.  Library supplied
+ * routines provide for the conversion on built-in C data types.  These
+ * routines and utility routines defined here are used to help implement
+ * a type encode/decode routine for each user-defined type.
+ *
+ * Each data type provides a single procedure which takes two arguments:
+ *
+ *	bool_t
+ *	xdrproc(xdrs, argresp)
+ *		XDR *xdrs;
+ *		<type> *argresp;
+ *
+ * xdrs is an instance of a XDR handle, to which or from which the data
+ * type is to be converted.  argresp is a pointer to the structure to be
+ * converted.  The XDR handle contains an operation field which indicates
+ * which of the operations (ENCODE, DECODE * or FREE) is to be performed.
+ *
+ * XDR_DECODE may allocate space if the pointer argresp is null.  This
+ * data can be freed with the XDR_FREE operation.
+ *
+ * We write only one procedure per data type to make it easy
+ * to keep the encode and decode procedures for a data type consistent.
+ * In many cases the same code performs all operations on a user defined type,
+ * because all the hard work is done in the component type routines.
+ * decode as a series of calls on the nested data types.
+ */
+
+/*
+ * Xdr operations.  XDR_ENCODE causes the type to be encoded into the
+ * stream.  XDR_DECODE causes the type to be extracted from the stream.
+ * XDR_FREE can be used to release the space allocated by an XDR_DECODE
+ * request.
+ */
+enum xdr_op {
+	XDR_ENCODE=0,
+	XDR_DECODE=1,
+	XDR_FREE=2
+};
+
+/*
+ * This is the number of bytes per unit of external data.
+ */
+#define BYTES_PER_XDR_UNIT	(4)
+#define RNDUP(x)  ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \
+		    * BYTES_PER_XDR_UNIT)
+
+/*
+ * A xdrproc_t exists for each data type which is to be encoded or decoded.
+ *
+ * The second argument to the xdrproc_t is a pointer to an opaque pointer.
+ * The opaque pointer generally points to a structure of the data type
+ * to be decoded.  If this pointer is 0, then the type routines should
+ * allocate dynamic storage of the appropriate size and return it.
+ * bool_t	(*xdrproc_t)(XDR *, caddr_t *);
+ *
+ * XXX can't actually prototype it, because some take three args!!!
+ */
+typedef	bool_t (*xdrproc_t)();
+
+/*
+ * The XDR handle.
+ * Contains operation which is being applied to the stream,
+ * an operations vector for the paticular implementation (e.g. see xdr_mem.c),
+ * and two private fields for the use of the particular impelementation.
+ */
+typedef struct XDR {
+	enum xdr_op	x_op;		/* operation; fast additional param */
+	struct xdr_ops {
+		/* get a long from underlying stream */
+		bool_t	(*x_getlong)(struct XDR *, long *);
+
+		/* put a long to underlying stream */
+		bool_t	(*x_putlong)(struct XDR *, long *);
+
+		/* get some bytes from underlying stream */
+		bool_t	(*x_getbytes)(struct XDR *, caddr_t, u_int);
+
+		/* put some bytes to underlying stream */
+		bool_t	(*x_putbytes)(struct XDR *, caddr_t, u_int);
+
+		/* returns bytes off from beginning */
+		u_int	(*x_getpostn)(struct XDR *);
+
+		/* lets you reposition the stream */
+		bool_t	(*x_setpostn)(struct XDR *, u_int);
+
+		/* buf quick ptr to buffered data */
+		rpc_inline_t *(*x_inline)(struct XDR *, int);
+
+		/* free privates of this xdr_stream */
+		void	(*x_destroy)(struct XDR *);
+	} *x_ops;
+	caddr_t 	x_public;	/* users' data */
+	void *		x_private;	/* pointer to private data */
+	caddr_t 	x_base;		/* private used for position info */
+	int		x_handy;	/* extra private word */
+} XDR;
+
+/*
+ * Operations defined on a XDR handle
+ *
+ * XDR		*xdrs;
+ * int32_t	*longp;
+ * caddr_t	 addr;
+ * u_int	 len;
+ * u_int	 pos;
+ */
+#define XDR_GETLONG(xdrs, longp)			\
+	(*(xdrs)->x_ops->x_getlong)(xdrs, longp)
+#define xdr_getlong(xdrs, longp)			\
+	(*(xdrs)->x_ops->x_getlong)(xdrs, longp)
+
+#define XDR_PUTLONG(xdrs, longp)			\
+	(*(xdrs)->x_ops->x_putlong)(xdrs, longp)
+#define xdr_putlong(xdrs, longp)			\
+	(*(xdrs)->x_ops->x_putlong)(xdrs, longp)
+
+#define XDR_GETBYTES(xdrs, addr, len)			\
+	(*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
+#define xdr_getbytes(xdrs, addr, len)			\
+	(*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
+
+#define XDR_PUTBYTES(xdrs, addr, len)			\
+	(*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
+#define xdr_putbytes(xdrs, addr, len)			\
+	(*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
+
+#define XDR_GETPOS(xdrs)				\
+	(*(xdrs)->x_ops->x_getpostn)(xdrs)
+#define xdr_getpos(xdrs)				\
+	(*(xdrs)->x_ops->x_getpostn)(xdrs)
+
+#define XDR_SETPOS(xdrs, pos)				\
+	(*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
+#define xdr_setpos(xdrs, pos)				\
+	(*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
+
+#define	XDR_INLINE(xdrs, len)				\
+	(*(xdrs)->x_ops->x_inline)(xdrs, len)
+#define	xdr_inline(xdrs, len)				\
+	(*(xdrs)->x_ops->x_inline)(xdrs, len)
+
+#define	XDR_DESTROY(xdrs)				\
+	if ((xdrs)->x_ops->x_destroy) 			\
+		(*(xdrs)->x_ops->x_destroy)(xdrs)
+#define	xdr_destroy(xdrs)				\
+	if ((xdrs)->x_ops->x_destroy) 			\
+		(*(xdrs)->x_ops->x_destroy)(xdrs)
+
+/*
+ * Support struct for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * a entry with a null procedure pointer.  The xdr_union routine gets
+ * the discriminant value and then searches the array of structures
+ * for a matching value.  If a match is found the associated xdr routine
+ * is called to handle that part of the union.  If there is
+ * no match, then a default routine may be called.
+ * If there is no match and no default routine it is an error.
+ */
+#define NULL_xdrproc_t ((xdrproc_t)0)
+struct xdr_discrim {
+	int	value;
+	xdrproc_t proc;
+};
+
+/*
+ * In-line routines for fast encode/decode of primitve data types.
+ * Caveat emptor: these use single memory cycles to get the
+ * data from the underlying buffer, and will fail to operate
+ * properly if the data is not aligned.  The standard way to use these
+ * is to say:
+ *	if ((buf = XDR_INLINE(xdrs, count)) == NULL)
+ *		return (FALSE);
+ *	<<< macro calls >>>
+ * where ``count'' is the number of bytes of data occupied
+ * by the primitive data types.
+ *
+ * N.B. and frozen for all time: each data type here uses 4 bytes
+ * of external representation.
+ */
+#define IXDR_GET_INT32(buf)		((int32_t)IXDR_GET_U_INT32(buf))
+#define IXDR_PUT_INT32(buf, v)		IXDR_PUT_U_INT32((buf),((uint32_t)(v)))
+#define IXDR_GET_U_INT32(buf)		(ntohl((uint32_t)*(buf)++))
+#define IXDR_PUT_U_INT32(buf, v)	(*(buf)++ = (int32_t)htonl((v)))
+
+#define IXDR_GET_LONG(buf)		((long)IXDR_GET_INT32(buf))
+#define IXDR_PUT_LONG(buf, v)		IXDR_PUT_U_INT32((buf),((uint32_t)(v)))
+
+#define IXDR_GET_BOOL(buf)		((bool_t)IXDR_GET_LONG(buf))
+#define IXDR_GET_ENUM(buf, t)		((t)IXDR_GET_INT32(buf))
+#define IXDR_GET_U_LONG(buf)		((u_long)IXDR_GET_U_INT32(buf))
+#define IXDR_GET_SHORT(buf)		((short)IXDR_GET_INT32(buf))
+#define IXDR_GET_U_SHORT(buf)		((u_short)IXDR_GET_U_INT32(buf))
+
+#define IXDR_PUT_BOOL(buf, v)		IXDR_PUT_INT32((buf),((int32_t)(v)))
+#define IXDR_PUT_ENUM(buf, v)		IXDR_PUT_INT32((buf),((int32_t)(v)))
+#define IXDR_PUT_U_LONG(buf, v)		IXDR_PUT_U_INT32((buf),((uint32_t)(v)))
+#define IXDR_PUT_SHORT(buf, v)		IXDR_PUT_INT32((buf),((int32_t)(v)))
+#define IXDR_PUT_U_SHORT(buf, v)	IXDR_PUT_U_INT32((buf),((uint32_t)(v)))
+
+/*
+ * These are the "generic" xdr routines.
+ */
+extern bool_t	xdr_void(XDR *, void *);
+extern bool_t	xdr_int(XDR *, int *);
+extern bool_t	xdr_u_int(XDR *, u_int *);
+extern bool_t	xdr_long(XDR *, long *);
+extern bool_t	xdr_u_long(XDR *, u_long *);
+extern bool_t	xdr_short(XDR *, short *);
+extern bool_t	xdr_u_short(XDR *, u_short *);
+extern bool_t	xdr_bool(XDR *, bool_t *);
+extern bool_t	xdr_enum(XDR *, enum_t *);
+extern bool_t	xdr_array(XDR *, caddr_t *, u_int *,
+			u_int, u_int, xdrproc_t);
+extern bool_t	xdr_bytes(XDR *, char **, u_int *, u_int);
+extern bool_t	xdr_opaque(XDR *, caddr_t, u_int);
+extern bool_t	xdr_string(XDR *, char **, u_int);
+extern bool_t	xdr_union(XDR *, enum_t *, char *, struct xdr_discrim *,
+			xdrproc_t);
+extern bool_t	xdr_char(XDR *, char *);
+extern bool_t	xdr_u_char(XDR *, u_char *);
+extern bool_t	xdr_vector(XDR *, char *, u_int, u_int, xdrproc_t);
+extern bool_t	xdr_float(XDR *, float *);
+extern bool_t	xdr_double(XDR *, double *);
+extern bool_t	xdr_reference(XDR *, caddr_t *, u_int, xdrproc_t);
+extern bool_t	xdr_pointer(XDR *, char **, u_int, xdrproc_t);
+extern bool_t	xdr_wrapstring(XDR *, char **);
+
+#define xdr_rpcprog	xdr_u_int32
+#define xdr_rpcvers	xdr_u_int32
+#define xdr_rpcprot	xdr_u_int32
+#define xdr_rpcproc	xdr_u_int32
+#define xdr_rpcport	xdr_u_int32
+
+/*
+ * Common opaque bytes objects used by many rpc protocols;
+ * declared here due to commonality.
+ */
+#define MAX_NETOBJ_SZ 2048
+struct netobj {
+	u_int	n_len;
+	char	*n_bytes;
+};
+typedef struct netobj netobj;
+
+extern bool_t   xdr_netobj(XDR *, struct netobj *);
+
+extern bool_t	xdr_int32(XDR *, int32_t *);
+extern bool_t	xdr_u_int32(XDR *, uint32_t *);
+
+/*
+ * These are the public routines for the various implementations of
+ * xdr streams.
+ */
+
+/* XDR allocating memory buffer */
+extern void	xdralloc_create(XDR *, enum xdr_op);
+
+/* destroy xdralloc, save buf */
+extern void	xdralloc_release(XDR *);
+
+/* get buffer from xdralloc */
+extern caddr_t	xdralloc_getdata(XDR *);
+
+/* XDR using memory buffers */
+extern void	xdrmem_create(XDR *, caddr_t, u_int, enum xdr_op);
+
+/* XDR using stdio library */
+extern void	xdrstdio_create(XDR *, FILE *, enum xdr_op);
+
+/* XDR pseudo records for tcp */
+extern void	xdrrec_create(XDR *xdrs, u_int, u_int, caddr_t,
+			int (*) (caddr_t, caddr_t, int),
+			int (*) (caddr_t, caddr_t, int));
+
+/* make end of xdr record */
+extern bool_t	xdrrec_endofrecord(XDR *, bool_t);
+
+/* move to beginning of next record */
+extern bool_t	xdrrec_skiprecord (XDR *xdrs);
+
+/* true if no more input */
+extern bool_t	xdrrec_eof (XDR *xdrs);
+
+/* free memory buffers for xdr */
+extern void	xdr_free (xdrproc_t, void *);
+GSSRPC__END_DECLS
+
+#endif /* !defined(GSSRPC_XDR_H) */
diff --git a/mechglue/src/lib/rpc/xdr_alloc.c b/mechglue/src/lib/rpc/xdr_alloc.c
new file mode 100644
index 000000000..b0aa032c6
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr_alloc.c
@@ -0,0 +1,151 @@
+/* @(#)xdr_mem.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ */
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include "dyn.h"
+
+static bool_t	xdralloc_putlong(XDR *, long *);
+static bool_t	xdralloc_putbytes(XDR *, caddr_t, unsigned int);
+static unsigned int	xdralloc_getpos(XDR *);
+static rpc_inline_t *	xdralloc_inline(XDR *, int);
+static void	xdralloc_destroy(XDR *);
+static bool_t	xdralloc_notsup_getlong(XDR *, long *);
+static bool_t	xdralloc_notsup_getbytes(XDR *, caddr_t, unsigned int);
+static bool_t	xdralloc_notsup_setpos(XDR *, unsigned int);
+static struct	xdr_ops xdralloc_ops = {
+     xdralloc_notsup_getlong,
+     xdralloc_putlong,
+     xdralloc_notsup_getbytes,
+     xdralloc_putbytes,
+     xdralloc_getpos,
+     xdralloc_notsup_setpos,
+     xdralloc_inline,
+     xdralloc_destroy,
+};
+
+/*
+ * The procedure xdralloc_create initializes a stream descriptor for a
+ * memory buffer.  
+ */
+void xdralloc_create(XDR *xdrs, enum xdr_op op)
+{
+     xdrs->x_op = op;
+     xdrs->x_ops = &xdralloc_ops;
+     xdrs->x_private = (caddr_t) DynCreate(sizeof(char), -4);
+     /* not allowed to fail */
+}
+
+caddr_t xdralloc_getdata(XDR *xdrs)
+{
+     return (caddr_t) DynGet((DynObject) xdrs->x_private, 0);
+}
+
+void xdralloc_release(XDR *xdrs)
+{
+     DynRelease((DynObject) xdrs->x_private);
+}
+
+static void xdralloc_destroy(XDR *xdrs)
+{
+     DynDestroy((DynObject) xdrs->x_private);
+}
+
+static bool_t xdralloc_notsup_getlong(
+     register XDR *xdrs,
+     long *lp)
+{
+     return FALSE;
+}
+
+static bool_t xdralloc_putlong(
+     register XDR *xdrs,
+     long *lp)
+{
+     int l = htonl((uint32_t) *lp); /* XXX need bounds checking */
+
+     /* XXX assumes sizeof(int)==4 */
+     if (DynInsert((DynObject) xdrs->x_private,
+		   DynSize((DynObject) xdrs->x_private), &l,
+		   sizeof(int)) != DYN_OK)
+	  return FALSE;
+     return (TRUE);
+}
+
+
+static bool_t xdralloc_notsup_getbytes(
+     register XDR *xdrs,
+     caddr_t addr,
+     register unsigned int len)
+{
+     return FALSE;
+}
+
+
+static bool_t xdralloc_putbytes(
+     register XDR *xdrs,
+     caddr_t addr,
+     register unsigned int len)
+{
+     if (DynInsert((DynObject) xdrs->x_private,
+		   DynSize((DynObject) xdrs->x_private),
+		   addr, (int) len) != DYN_OK)
+	  return FALSE;
+     return TRUE;
+}
+
+static unsigned int xdralloc_getpos(XDR *xdrs)
+{
+     return DynSize((DynObject) xdrs->x_private);
+}
+
+static bool_t xdralloc_notsup_setpos(
+     register XDR *xdrs,
+     unsigned int lp)
+{
+     return FALSE;
+}
+
+
+
+static rpc_inline_t *xdralloc_inline(
+     register XDR *xdrs,
+     int len)
+{
+     return (rpc_inline_t *) 0;
+}
diff --git a/mechglue/src/lib/rpc/xdr_array.c b/mechglue/src/lib/rpc/xdr_array.c
new file mode 100644
index 000000000..7d5745d4e
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr_array.c
@@ -0,0 +1,158 @@
+/* @(#)xdr_array.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_array.c, Generic XDR routines impelmentation.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * arrays.  See xdr.h for more info on the interface to xdr.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+
+#define LASTUNSIGNED	((u_int)0-1)
+
+
+/*
+ * XDR an array of arbitrary elements
+ * *addrp is a pointer to the array, *sizep is the number of elements.
+ * If addrp is NULL (*sizep * elsize) bytes are allocated.
+ * elsize is the size (in bytes) of each element, and elproc is the
+ * xdr procedure to call to handle each element of the array.
+ */
+bool_t
+xdr_array(
+	register XDR *xdrs,
+	caddr_t *addrp,		/* array pointer */
+	u_int *sizep,		/* number of elements */
+	u_int maxsize,		/* max numberof elements */
+	u_int elsize,		/* size in bytes of each element */
+	xdrproc_t elproc	/* xdr routine to handle each element */
+	)
+{
+	register u_int i;
+	register caddr_t target = *addrp;
+	register u_int c;  /* the actual element count */
+	register bool_t stat = TRUE;
+	register u_int nodesize;
+
+	/* like strings, arrays are really counted arrays */
+	if (! xdr_u_int(xdrs, sizep)) {
+		return (FALSE);
+	}
+	c = *sizep;
+	if ((c > maxsize || c > LASTUNSIGNED / elsize)
+	    && (xdrs->x_op != XDR_FREE)) {
+		return (FALSE);
+	}
+	nodesize = c * elsize;
+
+	/*
+	 * if we are deserializing, we may need to allocate an array.
+	 * We also save time by checking for a null array if we are freeing.
+	 */
+	if (target == NULL)
+		switch (xdrs->x_op) {
+		case XDR_DECODE:
+			if (c == 0)
+				return (TRUE);
+			*addrp = target = mem_alloc(nodesize);
+			if (target == NULL) {
+				(void) fprintf(stderr, 
+					"xdr_array: out of memory\n");
+				return (FALSE);
+			}
+			memset(target, 0, nodesize);
+			break;
+
+		case XDR_FREE:
+			return (TRUE);
+
+		case XDR_ENCODE:
+			break;
+	}
+	
+	/*
+	 * now we xdr each element of array
+	 */
+	for (i = 0; (i < c) && stat; i++) {
+		stat = (*elproc)(xdrs, target, LASTUNSIGNED);
+		target += elsize;
+	}
+
+	/*
+	 * the array may need freeing
+	 */
+	if (xdrs->x_op == XDR_FREE) {
+		mem_free(*addrp, nodesize);
+		*addrp = NULL;
+	}
+	return (stat);
+}
+
+/*
+ * xdr_vector():
+ *
+ * XDR a fixed length array. Unlike variable-length arrays,
+ * the storage of fixed length arrays is static and unfreeable.
+ * > basep: base of the array
+ * > size: size of the array
+ * > elemsize: size of each element
+ * > xdr_elem: routine to XDR each element
+ */
+bool_t
+xdr_vector(
+	register XDR *xdrs,
+	register char *basep,
+	register u_int nelem,
+	register u_int elemsize,
+	register xdrproc_t xdr_elem)
+{
+	register u_int i;
+	register char *elptr;
+
+	elptr = basep;
+	for (i = 0; i < nelem; i++) {
+		if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) {
+			return(FALSE);
+		}
+		elptr += elemsize;
+	}
+	return(TRUE);	
+}
+
diff --git a/mechglue/src/lib/rpc/xdr_float.c b/mechglue/src/lib/rpc/xdr_float.c
new file mode 100644
index 000000000..3e4805d97
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr_float.c
@@ -0,0 +1,289 @@
+/* @(#)xdr_float.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_float.c, Generic XDR routines impelmentation.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These are the "floating point" xdr routines used to (de)serialize
+ * most common data items.  See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#include <stdio.h>
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+
+/*
+ * NB: Not portable.
+ * This routine works on Suns (Sky / 68000's) and Vaxen.
+ */
+#ifdef IGNORE
+
+#ifdef vax
+
+/* What IEEE single precision floating point looks like on a Vax */
+struct	ieee_single {
+	unsigned int	mantissa: 23;
+	unsigned int	exp     : 8;
+	unsigned int	sign    : 1;
+};
+
+/* Vax single precision floating point */
+struct	vax_single {
+	unsigned int	mantissa1 : 7;
+	unsigned int	exp       : 8;
+	unsigned int	sign      : 1;
+	unsigned int	mantissa2 : 16;
+};
+
+#define VAX_SNG_BIAS	0x81
+#define IEEE_SNG_BIAS	0x7f
+
+static struct sgl_limits {
+	struct vax_single s;
+	struct ieee_single ieee;
+} sgl_limits[2] = {
+	{{ 0x7f, 0xff, 0x0, 0xffff },	/* Max Vax */
+	{ 0x0, 0xff, 0x0 }},		/* Max IEEE */
+	{{ 0x0, 0x0, 0x0, 0x0 },	/* Min Vax */
+	{ 0x0, 0x0, 0x0 }}		/* Min IEEE */
+};
+#endif /* vax */
+
+bool_t
+xdr_float(XDR *xdrs, float *fp)
+{
+#if defined(vax)
+	struct ieee_single is;
+	struct vax_single vs, *vsp;
+	struct sgl_limits *lim;
+	int i;
+#endif
+	long lg;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+#if !defined(vax)
+	        lg = * (int_32 *) fp;
+		return (XDR_PUTLONG(xdrs, &lg));
+#else
+		vs = *((struct vax_single *)fp);
+		for (i = 0, lim = sgl_limits;
+			i < sizeof(sgl_limits)/sizeof(struct sgl_limits);
+			i++, lim++) {
+			if ((vs.mantissa2 == lim->s.mantissa2) &&
+				(vs.exp == lim->s.exp) &&
+				(vs.mantissa1 == lim->s.mantissa1)) {
+				is = lim->ieee;
+				goto shipit;
+			}
+		}
+		is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
+		is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
+	shipit:
+		is.sign = vs.sign;
+		return (XDR_PUTLONG(xdrs, (int32_t *)&is));
+#endif
+
+	case XDR_DECODE:
+#if !defined(vax)
+	        if (!(XDR_GETLONG(xdrs, &lg))) {
+	                return (FALSE);
+		}
+		*fp = (float) ((int) lg);
+		return (TRUE);
+#else
+		vsp = (struct vax_single *)fp;
+		if (!XDR_GETLONG(xdrs, (int32_t *)&is))
+			return (FALSE);
+		for (i = 0, lim = sgl_limits;
+			i < sizeof(sgl_limits)/sizeof(struct sgl_limits);
+			i++, lim++) {
+			if ((is.exp == lim->ieee.exp) &&
+				(is.mantissa == lim->ieee.mantissa)) {
+				*vsp = lim->s;
+				goto doneit;
+			}
+		}
+		vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
+		vsp->mantissa2 = is.mantissa;
+		vsp->mantissa1 = (is.mantissa >> 16);
+	doneit:
+		vsp->sign = is.sign;
+		return (TRUE);
+#endif
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
+ * This routine works on Suns (Sky / 68000's) and Vaxen.
+ */
+
+#ifdef vax
+/* What IEEE double precision floating point looks like on a Vax */
+struct	ieee_double {
+	unsigned int	mantissa1 : 20;
+	unsigned int	exp       : 11;
+	unsigned int	sign      : 1;
+	unsigned int	mantissa2 : 32;
+};
+
+/* Vax double precision floating point */
+struct  vax_double {
+	unsigned int	mantissa1 : 7;
+	unsigned int	exp       : 8;
+	unsigned int	sign      : 1;
+	unsigned int	mantissa2 : 16;
+	unsigned int	mantissa3 : 16;
+	unsigned int	mantissa4 : 16;
+};
+
+#define VAX_DBL_BIAS	0x81
+#define IEEE_DBL_BIAS	0x3ff
+#define MASK(nbits)	((1 << nbits) - 1)
+
+static struct dbl_limits {
+	struct	vax_double d;
+	struct	ieee_double ieee;
+} dbl_limits[2] = {
+	{{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff },	/* Max Vax */
+	{ 0x0, 0x7ff, 0x0, 0x0 }},			/* Max IEEE */
+	{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},		/* Min Vax */
+	{ 0x0, 0x0, 0x0, 0x0 }}				/* Min IEEE */
+};
+
+#endif /* vax */
+
+
+bool_t
+xdr_double(XDR *xdrs, double *dp)
+{
+	register int32_t *lp;
+#if defined(vax)
+	struct	ieee_double id;
+	struct	vax_double vd;
+	register struct dbl_limits *lim;
+	int i;
+#endif
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+#if !defined(vax)
+		lp = (int32_t *)dp;
+		if (sizeof(int32_t) == sizeof(long)) {
+		  return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp));
+		} else {
+		  long lg1 = *lp++;;
+		  long lg2 = *lp;
+		  return (XDR_PUTLONG(xdrs, &lg1) && XDR_PUTLONG(xdrs, &lg2));
+		}
+#else
+		vd = *((struct vax_double *)dp);
+		for (i = 0, lim = dbl_limits;
+			i < sizeof(dbl_limits)/sizeof(struct dbl_limits);
+			i++, lim++) {
+			if ((vd.mantissa4 == lim->d.mantissa4) &&
+				(vd.mantissa3 == lim->d.mantissa3) &&
+				(vd.mantissa2 == lim->d.mantissa2) &&
+				(vd.mantissa1 == lim->d.mantissa1) &&
+				(vd.exp == lim->d.exp)) {
+				id = lim->ieee;
+				goto shipit;
+			}
+		}
+		id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
+		id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
+		id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
+				(vd.mantissa3 << 13) |
+				((vd.mantissa4 >> 3) & MASK(13));
+	shipit:
+		id.sign = vd.sign;
+		lp = (int32_t *)&id;
+		return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp));
+#endif
+
+	case XDR_DECODE:
+#if !defined(vax)
+		lp = (int32_t *)dp;
+		if (sizeof(int32_t) == sizeof(long)) {
+		  return (XDR_GETLONG(xdrs, lp++) && XDR_GETLONG(xdrs, lp));
+		} else {
+		  long lg1, lg2;
+		  bool_t flag =
+		   (XDR_GETLONG(xdrs, &lg1) && XDR_GETLONG(xdrs, &lg2));
+		  *lp++ = lg1;
+		  *lp = lg2;
+		  return flag;
+		}
+#else
+		lp = (int32_t *)&id;
+		if (!XDR_GETLONG(xdrs, lp++) || !XDR_GETLONG(xdrs, lp))
+			return (FALSE);
+		for (i = 0, lim = dbl_limits;
+			i < sizeof(dbl_limits)/sizeof(struct dbl_limits);
+			i++, lim++) {
+			if ((id.mantissa2 == lim->ieee.mantissa2) &&
+				(id.mantissa1 == lim->ieee.mantissa1) &&
+				(id.exp == lim->ieee.exp)) {
+				vd = lim->d;
+				goto doneit;
+			}
+		}
+		vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
+		vd.mantissa1 = (id.mantissa1 >> 13);
+		vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
+				(id.mantissa2 >> 29);
+		vd.mantissa3 = (id.mantissa2 >> 13);
+		vd.mantissa4 = (id.mantissa2 << 3);
+	doneit:
+		vd.sign = id.sign;
+		*dp = *((double *)&vd);
+		return (TRUE);
+#endif
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+#endif /* IGNORE */
diff --git a/mechglue/src/lib/rpc/xdr_mem.c b/mechglue/src/lib/rpc/xdr_mem.c
new file mode 100644
index 000000000..6908aa8a3
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr_mem.c
@@ -0,0 +1,182 @@
+/* @(#)xdr_mem.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_mem.h, XDR implementation using memory buffers.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * If you have some data to be interpreted as external data representation
+ * or to be converted to external data representation in a memory buffer,
+ * then this is the package for you.
+ *
+ */
+
+
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+static bool_t	xdrmem_getlong(XDR *, long *);
+static bool_t	xdrmem_putlong(XDR *, long *);
+static bool_t	xdrmem_getbytes(XDR *, caddr_t, u_int);
+static bool_t	xdrmem_putbytes(XDR *, caddr_t, u_int);
+static u_int	xdrmem_getpos(XDR *);
+static bool_t	xdrmem_setpos(XDR *, u_int);
+static rpc_inline_t *	xdrmem_inline(XDR *, int);
+static void	xdrmem_destroy(XDR *);
+
+static struct	xdr_ops xdrmem_ops = {
+	xdrmem_getlong,
+	xdrmem_putlong,
+	xdrmem_getbytes,
+	xdrmem_putbytes,
+	xdrmem_getpos,
+	xdrmem_setpos,
+	xdrmem_inline,
+	xdrmem_destroy
+};
+
+/*
+ * The procedure xdrmem_create initializes a stream descriptor for a
+ * memory buffer.  
+ */
+void
+xdrmem_create(
+	XDR *xdrs,
+	caddr_t addr,
+	u_int size,
+	enum xdr_op op)
+{
+
+	xdrs->x_op = op;
+	xdrs->x_ops = &xdrmem_ops;
+	xdrs->x_private = xdrs->x_base = addr;
+	xdrs->x_handy = (size > INT_MAX) ? INT_MAX : size; /* XXX */
+}
+
+static void
+xdrmem_destroy(XDR *xdrs)
+{
+}
+
+static bool_t
+xdrmem_getlong(XDR *xdrs, long *lp)
+{
+
+	if (xdrs->x_handy < BYTES_PER_XDR_UNIT)
+		return (FALSE);
+	else
+		xdrs->x_handy -= BYTES_PER_XDR_UNIT;
+	*lp = (long)(int32_t)ntohl(*((uint32_t *)(xdrs->x_private)));
+	xdrs->x_private = (char *)xdrs->x_private + BYTES_PER_XDR_UNIT;
+	return (TRUE);
+}
+
+static bool_t
+xdrmem_putlong(XDR *xdrs, long *lp)
+{
+
+	if (xdrs->x_handy < BYTES_PER_XDR_UNIT)
+		return (FALSE);
+	else
+		xdrs->x_handy -= BYTES_PER_XDR_UNIT;
+	*(int32_t *)xdrs->x_private = (int32_t)htonl((uint32_t)(*lp));
+	xdrs->x_private = (char *)xdrs->x_private + BYTES_PER_XDR_UNIT;
+	return (TRUE);
+}
+
+static bool_t
+xdrmem_getbytes(XDR *xdrs, caddr_t addr, u_int len)
+{
+
+	if (xdrs->x_handy < len)
+		return (FALSE);
+	else
+		xdrs->x_handy -= len;
+	memmove(addr, xdrs->x_private, len);
+	xdrs->x_private = (char *)xdrs->x_private + len;
+	return (TRUE);
+}
+
+static bool_t
+xdrmem_putbytes(XDR *xdrs, caddr_t addr, u_int len)
+{
+
+	if (xdrs->x_handy < len)
+		return (FALSE);
+	else
+		xdrs->x_handy -= len;
+	memmove(xdrs->x_private, addr, len);
+	xdrs->x_private = (char *)xdrs->x_private + len;
+	return (TRUE);
+}
+
+static u_int
+xdrmem_getpos(XDR *xdrs)
+{
+/*
+ * 11/3/95 - JRG - Rather than recast everything for 64 bit, just convert
+ * pointers to longs, then cast to int.
+ */
+	return (u_int)((u_long)xdrs->x_private - (u_long)xdrs->x_base);
+}
+
+static bool_t
+xdrmem_setpos(XDR *xdrs, u_int pos)
+{
+	register caddr_t newaddr = xdrs->x_base + pos;
+	register caddr_t lastaddr = (char *) xdrs->x_private + xdrs->x_handy;
+
+	if ((long)newaddr > (long)lastaddr)
+		return (FALSE);
+	xdrs->x_private = newaddr;
+	xdrs->x_handy = (int)((long)lastaddr - (long)newaddr);
+	return (TRUE);
+}
+
+static rpc_inline_t *
+xdrmem_inline(XDR *xdrs, int len)
+{
+	rpc_inline_t *buf = 0;
+
+	if (len >= 0 && xdrs->x_handy >= len) {
+		xdrs->x_handy -= len;
+		buf = (rpc_inline_t *) xdrs->x_private;
+		xdrs->x_private = (char *)xdrs->x_private + len;
+	}
+	return (buf);
+}
diff --git a/mechglue/src/lib/rpc/xdr_rec.c b/mechglue/src/lib/rpc/xdr_rec.c
new file mode 100644
index 000000000..38e1f6323
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr_rec.c
@@ -0,0 +1,570 @@
+/* @(#)xdr_rec.c	2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
+ * layer above tcp (for rpc's use).
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These routines interface XDRSTREAMS to a tcp/ip connection.
+ * There is a record marking layer between the xdr stream
+ * and the tcp transport level.  A record is composed on one or more
+ * record fragments.  A record fragment is a thirty-two bit header followed
+ * by n bytes of data, where n is contained in the header.  The header
+ * is represented as a htonl(uint32_t).  Thegh order bit encodes
+ * whether or not the fragment is the last fragment of the record
+ * (1 => fragment is last, 0 => more fragments to follow. 
+ * The other 31 bits encode the byte length of the fragment.
+ */
+
+#include <stdio.h>
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <netinet/in.h>
+
+#include <unistd.h>
+#include <string.h>
+
+static bool_t	xdrrec_getlong(XDR *, long *);
+static bool_t	xdrrec_putlong(XDR *, long *);
+static bool_t	xdrrec_getbytes(XDR *, caddr_t, u_int);
+static bool_t	xdrrec_putbytes(XDR *, caddr_t, u_int);
+static u_int	xdrrec_getpos(XDR *);
+static bool_t	xdrrec_setpos(XDR *, u_int);
+static rpc_inline_t *	xdrrec_inline(XDR *, int);
+static void	xdrrec_destroy(XDR *);
+
+static struct  xdr_ops xdrrec_ops = {
+	xdrrec_getlong,
+	xdrrec_putlong,
+	xdrrec_getbytes,
+	xdrrec_putbytes,
+	xdrrec_getpos,
+	xdrrec_setpos,
+	xdrrec_inline,
+	xdrrec_destroy
+};
+
+/*
+ * A record is composed of one or more record fragments.
+ * A record fragment is a four-byte header followed by zero to
+ * 2**31-1 bytes.  The header is treated as an unsigned 32 bit integer and is
+ * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
+ * are a byte count of the fragment.  The highest order bit is a boolean:
+ * 1 => this fragment is the last fragment of the record,
+ * 0 => this fragment is followed by more fragment(s).
+ *
+ * The fragment/record machinery is not general;  it is constructed to
+ * meet the needs of xdr and rpc based on tcp.
+ */
+
+#define LAST_FRAG ((uint32_t)(1L << 31))
+
+typedef struct rec_strm {
+	caddr_t tcp_handle;
+	caddr_t the_buffer;
+	/*
+	 * out-goung bits
+	 */
+	int (*writeit)();
+	caddr_t out_base;	/* output buffer (points to frag header) */
+	caddr_t out_finger;	/* next output position */
+	caddr_t out_boundry;	/* data cannot up to this address */
+	uint32_t *frag_header;	/* beginning of curren fragment */
+	bool_t frag_sent;	/* true if buffer sent in middle of record */
+	/*
+	 * in-coming bits
+	 */
+	int (*readit)();
+	uint32_t in_size;	/* fixed size of the input buffer */
+	caddr_t in_base;
+	caddr_t in_finger;	/* location of next byte to be had */
+	caddr_t in_boundry;	/* can read up to this location */
+	int32_t fbtbc;		/* fragment bytes to be consumed */
+	bool_t last_frag;
+	u_int sendsize;
+	u_int recvsize;
+} RECSTREAM;
+
+static u_int	fix_buf_size(u_int);
+static bool_t   flush_out(RECSTREAM *, bool_t);
+static bool_t   get_input_bytes(RECSTREAM *, caddr_t, int);
+static bool_t   set_input_fragment(RECSTREAM *);
+static bool_t   skip_input_bytes(RECSTREAM *, int32_t);
+
+/*
+ * Create an xdr handle for xdrrec
+ * xdrrec_create fills in xdrs.  Sendsize and recvsize are
+ * send and recv buffer sizes (0 => use default).
+ * tcp_handle is an opaque handle that is passed as the first parameter to
+ * the procedures readit and writeit.  Readit and writeit are read and
+ * write respectively.   They are like the system
+ * calls expect that they take an opaque handle rather than an fd.
+ */
+void
+xdrrec_create(
+	XDR *xdrs,
+	u_int sendsize,
+	u_int recvsize,
+	caddr_t tcp_handle,
+	int (*readit)(), /* like read, but pass it a tcp_handle, not sock */
+	int (*writeit)() /* like write, but pass it a tcp_handle, not sock */
+	)
+{
+	register RECSTREAM *rstrm =
+		(RECSTREAM *)mem_alloc(sizeof(RECSTREAM));
+
+	if (rstrm == NULL) {
+		(void)fprintf(stderr, "xdrrec_create: out of memory\n");
+		/* 
+		 *  This is bad.  Should rework xdrrec_create to 
+		 *  return a handle, and in this case return NULL
+		 */
+		return;
+	}
+	/*
+	 * adjust sizes and allocate buffer quad byte aligned
+	 */
+	rstrm->sendsize = sendsize = fix_buf_size(sendsize);
+	rstrm->recvsize = recvsize = fix_buf_size(recvsize);
+	rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT);
+	if (rstrm->the_buffer == NULL) {
+		(void)fprintf(stderr, "xdrrec_create: out of memory\n");
+		return;
+	}
+	for (rstrm->out_base = rstrm->the_buffer;
+	     /* Pointer arithmetic - long cast allowed... */
+		(u_long)rstrm->out_base % BYTES_PER_XDR_UNIT != 0;
+		rstrm->out_base++);
+	rstrm->in_base = rstrm->out_base + sendsize;
+	/*
+	 * now the rest ...
+	 */
+	xdrs->x_ops = &xdrrec_ops;
+	xdrs->x_private = (caddr_t)rstrm;
+	rstrm->tcp_handle = tcp_handle;
+	rstrm->readit = readit;
+	rstrm->writeit = writeit;
+	rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
+	rstrm->frag_header = (uint32_t *)(void *)rstrm->out_base;
+	rstrm->out_finger += BYTES_PER_XDR_UNIT;
+	rstrm->out_boundry += sendsize;
+	rstrm->frag_sent = FALSE;
+	rstrm->in_size = recvsize;
+	rstrm->in_boundry = rstrm->in_base;
+	rstrm->in_finger = (rstrm->in_boundry += recvsize);
+	rstrm->fbtbc = 0;
+	rstrm->last_frag = TRUE;
+}
+
+
+/*
+ * The reoutines defined below are the xdr ops which will go into the
+ * xdr handle filled in by xdrrec_create.
+ */
+
+static bool_t
+xdrrec_getlong(XDR *xdrs, long *lp)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+	register int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger);
+	uint32_t mylong;
+
+	/* first try the inline, fast case */
+	if ((rstrm->fbtbc >= BYTES_PER_XDR_UNIT) &&
+		(((long)rstrm->in_boundry - (long)buflp) >=
+		 BYTES_PER_XDR_UNIT)) {
+		*lp = (long)ntohl((uint32_t)(*buflp));
+		rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
+		rstrm->in_finger += BYTES_PER_XDR_UNIT;
+	} else {
+		if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong,
+				      BYTES_PER_XDR_UNIT))
+			return (FALSE);
+		*lp = (long)(int32_t)ntohl(mylong);
+	}
+	return (TRUE);
+}
+
+static bool_t
+xdrrec_putlong(XDR *xdrs, long *lp)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+	register int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
+
+	if (rstrm->out_boundry - rstrm->out_finger < BYTES_PER_XDR_UNIT) {
+		/*
+		 * this case should almost never happen so the code is
+		 * inefficient
+		 */
+		rstrm->frag_sent = TRUE;
+		if (! flush_out(rstrm, FALSE))
+			return (FALSE);
+		dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
+	}
+	rstrm->out_finger += BYTES_PER_XDR_UNIT;
+	*dest_lp = (int32_t)htonl((uint32_t)(*lp));
+	return (TRUE);
+}
+
+static bool_t  /* must manage buffers, fragments, and records */
+xdrrec_getbytes(XDR *xdrs, caddr_t addr, u_int len)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+	register int current;
+
+	while (len > 0) {
+		current = rstrm->fbtbc;
+		if (current == 0) {
+			if (rstrm->last_frag)
+				return (FALSE);
+			if (! set_input_fragment(rstrm))
+				return (FALSE);
+			continue;
+		}
+		current = (len < current) ? len : current;
+		if (! get_input_bytes(rstrm, addr, current))
+			return (FALSE);
+		addr += current; 
+		rstrm->fbtbc -= current;
+		len -= current;
+	}
+	return (TRUE);
+}
+
+static bool_t
+xdrrec_putbytes(XDR *xdrs, caddr_t addr, u_int len)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+	register size_t current;
+
+	while (len > 0) {
+		current = (size_t) ((long)rstrm->out_boundry - 
+				 (long)rstrm->out_finger);
+		current = (len < current) ? len : current;
+		memmove(rstrm->out_finger, addr, current);
+		rstrm->out_finger += current;
+		addr += current;
+		len -= current;
+		if (rstrm->out_finger == rstrm->out_boundry) {
+			rstrm->frag_sent = TRUE;
+			if (! flush_out(rstrm, FALSE))
+				return (FALSE);
+		}
+	}
+	return (TRUE);
+}
+
+static u_int
+xdrrec_getpos(XDR *xdrs)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+	register int pos;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		pos = rstrm->out_finger - rstrm->out_base
+			- BYTES_PER_XDR_UNIT;
+		break;
+
+	case XDR_DECODE:
+		pos = rstrm->in_boundry - rstrm->in_finger
+			- BYTES_PER_XDR_UNIT;
+		break;
+
+	default:
+		pos = -1;
+		break;
+	}
+	return ((u_int) pos);
+}
+
+static bool_t
+xdrrec_setpos(XDR *xdrs, u_int pos)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+	u_int currpos = xdrrec_getpos(xdrs);
+	int delta = currpos - pos;
+	caddr_t newpos;
+
+	if ((int)currpos != -1)
+		switch (xdrs->x_op) {
+
+		case XDR_ENCODE:
+			newpos = rstrm->out_finger - delta;
+			if ((newpos > (caddr_t)(rstrm->frag_header)) &&
+				(newpos < rstrm->out_boundry)) {
+				rstrm->out_finger = newpos;
+				return (TRUE);
+			}
+			break;
+
+		case XDR_DECODE:
+			newpos = rstrm->in_finger - delta;
+			if ((delta < (int)(rstrm->fbtbc)) &&
+				(newpos <= rstrm->in_boundry) &&
+				(newpos >= rstrm->in_base)) {
+				rstrm->in_finger = newpos;
+				rstrm->fbtbc -= delta;
+				return (TRUE);
+			}
+			break;
+
+		case XDR_FREE:
+			break;
+		}
+	return (FALSE);
+}
+
+static rpc_inline_t *
+xdrrec_inline(XDR *xdrs, int len)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+	rpc_inline_t * buf = NULL;
+
+	if (len < 0)
+		return (FALSE);
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		if (len <= (rstrm->out_boundry - rstrm->out_finger)) {
+			buf = (rpc_inline_t *)(void *) rstrm->out_finger;
+			rstrm->out_finger += len;
+		}
+		break;
+
+	case XDR_DECODE:
+		if ((len <= rstrm->fbtbc) &&
+			(len <= (rstrm->in_boundry - rstrm->in_finger))) {
+			buf = (rpc_inline_t *)(void *) rstrm->in_finger;
+			rstrm->fbtbc -= len;
+			rstrm->in_finger += len;
+		}
+		break;
+
+	case XDR_FREE:
+	        break;
+	}
+	return (buf);
+}
+
+static void
+xdrrec_destroy(XDR *xdrs)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
+
+	mem_free(rstrm->the_buffer,
+		rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
+	mem_free((caddr_t)rstrm, sizeof(RECSTREAM));
+}
+
+
+/*
+ * Exported routines to manage xdr records
+ */
+
+/*
+ * Before reading (deserializing from the stream, one should always call
+ * this procedure to guarantee proper record alignment.
+ */
+bool_t
+xdrrec_skiprecord(XDR *xdrs)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+
+	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
+		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
+			return (FALSE);
+		rstrm->fbtbc = 0;
+		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
+			return (FALSE);
+	}
+	rstrm->last_frag = FALSE;
+	return (TRUE);
+}
+
+/*
+ * Look ahead fuction.
+ * Returns TRUE iff there is no more input in the buffer 
+ * after consuming the rest of the current record.
+ */
+bool_t
+xdrrec_eof(XDR *xdrs)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+
+	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
+		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
+			return (TRUE);
+		rstrm->fbtbc = 0;
+		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
+			return (TRUE);
+	}
+	if (rstrm->in_finger == rstrm->in_boundry)
+		return (TRUE);
+	return (FALSE);
+}
+
+/*
+ * The client must tell the package when an end-of-record has occurred.
+ * The second paraemters tells whether the record should be flushed to the
+ * (output) tcp stream.  (This let's the package support batched or
+ * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
+ */
+bool_t
+xdrrec_endofrecord(XDR *xdrs, bool_t sendnow)
+{
+	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
+	register uint32_t len;  /* fragment length */
+
+	if (sendnow || rstrm->frag_sent ||
+		((long)rstrm->out_finger + BYTES_PER_XDR_UNIT >=
+		(long)rstrm->out_boundry)) {
+		rstrm->frag_sent = FALSE;
+		return (flush_out(rstrm, TRUE));
+	}
+	len = (long)(rstrm->out_finger) - (long)(rstrm->frag_header) -
+	   BYTES_PER_XDR_UNIT;
+	*(rstrm->frag_header) = htonl((uint32_t)len | LAST_FRAG);
+	rstrm->frag_header = (uint32_t *)(void *)rstrm->out_finger;
+	rstrm->out_finger += BYTES_PER_XDR_UNIT;
+	return (TRUE);
+}
+
+
+/*
+ * Internal useful routines
+ */
+static bool_t
+flush_out(RECSTREAM *rstrm, bool_t eor)
+{
+	register uint32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
+	register uint32_t len = (u_long)(rstrm->out_finger) - 
+		(u_long)(rstrm->frag_header) - BYTES_PER_XDR_UNIT;
+
+	*(rstrm->frag_header) = htonl(len | eormask);
+	len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->out_base);
+	if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
+		!= (int)len)
+		return (FALSE);
+	rstrm->frag_header = (uint32_t *)(void *)rstrm->out_base;
+	rstrm->out_finger = (caddr_t)rstrm->out_base + BYTES_PER_XDR_UNIT;
+	return (TRUE);
+}
+
+static bool_t  /* knows nothing about records!  Only about input buffers */
+fill_input_buf(RECSTREAM *rstrm)
+{
+	register caddr_t where;
+	u_int i;
+	register int len;
+
+	where = rstrm->in_base;
+	i = (u_int)((u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT);
+	where += i;
+	len = rstrm->in_size - i;
+	if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
+		return (FALSE);
+	rstrm->in_finger = where;
+	where += len;
+	rstrm->in_boundry = where;
+	return (TRUE);
+}
+
+static bool_t  /* knows nothing about records!  Only about input buffers */
+get_input_bytes(RECSTREAM *rstrm, caddr_t addr, int len)
+{
+	register size_t current;
+
+	while (len > 0) {
+		current = (size_t)((long)rstrm->in_boundry - 
+				(long)rstrm->in_finger);
+		if (current == 0) {
+			if (! fill_input_buf(rstrm))
+				return (FALSE);
+			continue;
+		}
+		current = (len < current) ? len : current;
+		memmove(addr, rstrm->in_finger, current);
+		rstrm->in_finger += current;
+		addr += current;
+		len -= current;
+	}
+	return (TRUE);
+}
+
+static bool_t  /* next four bytes of input stream are treated as a header */
+set_input_fragment(rstrm)
+	register RECSTREAM *rstrm;
+{
+	uint32_t header;
+
+	if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header)))
+		return (FALSE);
+	header = ntohl(header);
+	rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
+	rstrm->fbtbc = header & (~LAST_FRAG);
+	return (TRUE);
+}
+
+static bool_t  /* consumes input bytes; knows nothing about records! */
+skip_input_bytes(RECSTREAM *rstrm, int32_t cnt)
+{
+	register int current;
+
+	while (cnt > 0) {
+		current = (int)((long)rstrm->in_boundry - 
+				(long)rstrm->in_finger);
+		if (current == 0) {
+			if (! fill_input_buf(rstrm))
+				return (FALSE);
+			continue;
+		}
+		current = (cnt < current) ? cnt : current;
+		rstrm->in_finger += current;
+		cnt -= current;
+	}
+	return (TRUE);
+}
+
+static u_int
+fix_buf_size(u_int s)
+{
+
+	if (s < 100)
+		s = 4000;
+	return (RNDUP(s));
+}
diff --git a/mechglue/src/lib/rpc/xdr_reference.c b/mechglue/src/lib/rpc/xdr_reference.c
new file mode 100644
index 000000000..50a4fe4ae
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr_reference.c
@@ -0,0 +1,137 @@
+/* @(#)xdr_reference.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_reference.c 1.11 87/08/11 SMI";
+#endif
+
+/*
+ * xdr_reference.c, Generic XDR routines impelmentation.
+ *
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * "pointers".  See xdr.h for more info on the interface to xdr.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+
+#define LASTUNSIGNED	((u_int)0-1)
+
+/*
+ * XDR an indirect pointer
+ * xdr_reference is for recursively translating a structure that is
+ * referenced by a pointer inside the structure that is currently being
+ * translated.  pp references a pointer to storage. If *pp is null
+ * the  necessary storage is allocated.
+ * size is the sizeof the referneced structure.
+ * proc is the routine to handle the referenced structure.
+ */
+bool_t
+xdr_reference(
+	XDR *xdrs,
+	caddr_t *pp,		/* the pointer to work on */
+	u_int size,		/* size of the object pointed to */
+	xdrproc_t proc		/* xdr routine to handle the object */
+	)
+{
+	register caddr_t loc = *pp;
+	register bool_t stat;
+
+	if (loc == NULL)
+		switch (xdrs->x_op) {
+		case XDR_FREE:
+			return (TRUE);
+
+		case XDR_DECODE:
+			*pp = loc = (caddr_t) mem_alloc(size);
+			if (loc == NULL) {
+				(void) fprintf(stderr,
+				    "xdr_reference: out of memory\n");
+				return (FALSE);
+			}
+			memset(loc, 0, size);
+			break;
+
+		case XDR_ENCODE:
+			break;
+	}
+
+	stat = (*proc)(xdrs, loc, LASTUNSIGNED);
+
+	if (xdrs->x_op == XDR_FREE) {
+		mem_free(loc, size);
+		*pp = NULL;
+	}
+	return (stat);
+}
+
+
+/*
+ * xdr_pointer():
+ *
+ * XDR a pointer to a possibly recursive data structure. This
+ * differs with xdr_reference in that it can serialize/deserialiaze
+ * trees correctly.
+ *
+ *  What's sent is actually a union:
+ *
+ *  union object_pointer switch (boolean b) {
+ *  case TRUE: object_data data;
+ *  case FALSE: void nothing;
+ *  }
+ *
+ * > objpp: Pointer to the pointer to the object.
+ * > obj_size: size of the object.
+ * > xdr_obj: routine to XDR an object.
+ *
+ */
+bool_t
+xdr_pointer(
+	XDR *xdrs,
+	char **objpp,
+	u_int obj_size,
+	xdrproc_t xdr_obj)
+{
+
+	bool_t more_data;
+
+	more_data = (*objpp != NULL);
+	if (! xdr_bool(xdrs,&more_data)) {
+		return (FALSE);
+	}
+	if (! more_data) {
+		*objpp = NULL;
+		return (TRUE);
+	}
+	return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
+}
diff --git a/mechglue/src/lib/rpc/xdr_stdio.c b/mechglue/src/lib/rpc/xdr_stdio.c
new file mode 100644
index 000000000..471d9f2ee
--- /dev/null
+++ b/mechglue/src/lib/rpc/xdr_stdio.c
@@ -0,0 +1,170 @@
+/* @(#)xdr_stdio.c	2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "@(#)xdr_stdio.c 1.16 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_stdio.c, XDR implementation on standard i/o file.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * This set of routines implements a XDR on a stdio stream.
+ * XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes
+ * from the stream.
+ */
+
+#include <gssrpc/types.h>
+#include <stdio.h>
+#include <gssrpc/xdr.h>
+
+static bool_t	xdrstdio_getlong(XDR *, long *);
+static bool_t	xdrstdio_putlong(XDR *, long *);
+static bool_t	xdrstdio_getbytes(XDR *, caddr_t, u_int);
+static bool_t	xdrstdio_putbytes(XDR *, caddr_t, u_int);
+static u_int	xdrstdio_getpos(XDR *);
+static bool_t	xdrstdio_setpos(XDR *, u_int);
+static rpc_inline_t *	xdrstdio_inline(XDR *, int);
+static void	xdrstdio_destroy(XDR *);
+
+/*
+ * Ops vector for stdio type XDR
+ */
+static struct xdr_ops	xdrstdio_ops = {
+	xdrstdio_getlong,	/* deseraialize a long int */
+	xdrstdio_putlong,	/* seraialize a long int */
+	xdrstdio_getbytes,	/* deserialize counted bytes */
+	xdrstdio_putbytes,	/* serialize counted bytes */
+	xdrstdio_getpos,	/* get offset in the stream */
+	xdrstdio_setpos,	/* set offset in the stream */
+	xdrstdio_inline,	/* prime stream for inline macros */
+	xdrstdio_destroy	/* destroy stream */
+};
+
+/*
+ * Initialize a stdio xdr stream.
+ * Sets the xdr stream handle xdrs for use on the stream file.
+ * Operation flag is set to op.
+ */
+void
+xdrstdio_create(XDR *xdrs, FILE *file, enum xdr_op op)
+{
+
+	xdrs->x_op = op;
+	xdrs->x_ops = &xdrstdio_ops;
+	xdrs->x_private = (caddr_t)file;
+	xdrs->x_handy = 0;
+	xdrs->x_base = 0;
+}
+
+/*
+ * Destroy a stdio xdr stream.
+ * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create.
+ */
+static void
+xdrstdio_destroy(XDR *xdrs)
+{
+	(void)fflush((FILE *)xdrs->x_private);
+	/* xx should we close the file ?? */
+}
+
+static bool_t
+xdrstdio_getlong(XDR *xdrs, long *lp)
+{
+        uint32_t tmp;
+	if (fread((caddr_t)&tmp,
+		  sizeof(uint32_t), 1, (FILE *)xdrs->x_private) != 1)
+		return (FALSE);
+
+	*lp = (long)ntohl(tmp);
+
+	return (TRUE);
+}
+
+static bool_t
+xdrstdio_putlong(XDR *xdrs, long *lp)
+{
+	uint32_t mycopy = htonl((uint32_t)*lp);
+
+	if (fwrite((caddr_t)&mycopy, sizeof(uint32_t), 1, (FILE *)xdrs->x_private) != 1)
+		return (FALSE);
+	return (TRUE);
+}
+
+static bool_t
+xdrstdio_getbytes(XDR *xdrs, caddr_t addr, u_int len)
+{
+
+	if ((len != 0) && (fread(addr, (size_t)len, 1, 
+				 (FILE *)xdrs->x_private) != 1))
+		return (FALSE);
+	return (TRUE);
+}
+
+static bool_t
+xdrstdio_putbytes(XDR *xdrs, caddr_t addr, u_int len)
+{
+
+	if ((len != 0) && (fwrite(addr, (size_t)len, 1, 
+			   (FILE *)xdrs->x_private) != 1))
+		return (FALSE);
+	return (TRUE);
+}
+
+static u_int
+xdrstdio_getpos(XDR *xdrs)
+{
+
+	return ((u_int) ftell((FILE *)xdrs->x_private));
+}
+
+static bool_t
+xdrstdio_setpos(XDR *xdrs, u_int pos)
+{ 
+
+	return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ?
+		FALSE : TRUE);
+}
+
+static rpc_inline_t *
+xdrstdio_inline(XDR *xdrs, int len)
+{
+
+	/*
+	 * Must do some work to implement this: must insure
+	 * enough data in the underlying stdio buffer,
+	 * that the buffer is aligned so that we can indirect through a
+	 * long *, and stuff this pointer in xdrs->x_buf.  Doing
+	 * a fread or fwrite to a scratch buffer would defeat
+	 * most of the gains to be had here and require storage
+	 * management on this buffer, so we don't do this.
+	 */
+	return (NULL);
+}
diff --git a/mechglue/src/lib/win_glue.c b/mechglue/src/lib/win_glue.c
new file mode 100644
index 000000000..3b2cbc599
--- /dev/null
+++ b/mechglue/src/lib/win_glue.c
@@ -0,0 +1,489 @@
+#ifdef KRB4
+#include <kerberosIV/krb.h>
+#endif
+#include "k5-int.h"
+
+#ifdef KRB4
+#include <kerberosIV/krb_err.h>
+#include <kerberosIV/kadm_err.h>
+#endif
+#ifdef KRB5
+#include "krb5_err.h"
+#include "kv5m_err.h"
+#include "asn1_err.h"
+#include "kdb5_err.h"
+#include "profile.h"
+extern void krb5_stdcc_shutdown();
+#endif
+#ifdef GSSAPI
+#include "gssapi/generic/gssapi_err_generic.h"
+#include "gssapi/krb5/gssapi_err_krb5.h"
+#endif
+
+
+/*
+ * #defines for MIT-specific time-based timebombs and/or version
+ * server for the Kerberos DLL.
+ */
+
+#ifdef SAP_TIMEBOMB
+#define TIMEBOMB 865141200	/* 1-Jun-97 */
+#define TIMEBOMB_PRODUCT "SAPGUI"
+#define TIMEBOMB_WARN  15
+#define TIMEBOMB_INFO "  Please see the web page at:\nhttp://web.mit.edu/reeng/www/saphelp for more information"
+#define TIMEBOMB_ERROR KRB5_APPL_EXPIRED
+#endif
+
+#ifdef KRB_TIMEBOMB
+#define TIMEBOMB 865141200	/* 1-Jun-97 */
+#define TIMEBOMB_PRODUCT "Kerberos V5"
+#define TIMEBOMB_WARN 15
+#define TIMEBOMB_INFO "  Please see the web page at:\nhttp://web.mit.edu/reeng/www/saphelp for more information"
+#define TIMEBOMB_ERROR KRB5_LIB_EXPIRED
+#endif
+
+/*
+ * #defines for using MIT's version server DLL
+ */
+#ifdef SAP_VERSERV
+#define APP_TITLE "KRB5-SAP"
+#define APP_VER "3.0f"
+#define APP_INI "krb5sap.ini"
+#define VERSERV_ERROR 	KRB5_APPL_EXPIRED
+#endif
+
+#ifdef VERSERV
+#define WINDOWS
+#include <ver.h>
+#include <vs.h>
+#include <v.h>
+
+
+/*
+ * This function will get the version resource information from the
+ * application using the DLL.  This allows us to Version Serve
+ * arbitrary third party applications.  If there is an error, or we
+ * decide that we should not version check the calling application
+ * then VSflag will be FALSE when the function returns.
+ *
+ * The buffers passed into this function must be at least
+ * APPVERINFO_SIZE bytes long.
+ */
+
+#define APPVERINFO_SIZE 256
+
+void GetCallingAppVerInfo( char *AppTitle, char *AppVer, char *AppIni,
+			  BOOL *VSflag)
+{
+	char CallerFilename[_MAX_PATH];
+	LONG *lpLangInfo;
+	DWORD hVersionInfoID, size;
+	GLOBALHANDLE hVersionInfo;
+	LPSTR lpVersionInfo;
+	int dumint, retval;
+	char *cp;
+	char *revAppTitle;
+	char szVerQ[90];
+	LPBYTE locAppTitle;
+	LPBYTE locAppVer;
+	char locAppIni[_MAX_PATH];
+#ifndef _WIN32
+	WORD wStackSeg;
+#endif /* !_WIN32 */
+
+	/* first we need to get the calling module's filename */
+#ifndef _WIN32
+	_asm {
+		mov wStackSeg, ss
+	};
+	retval = GetModuleFileName((HMODULE)wStackSeg, CallerFilename,
+		_MAX_PATH);
+#else
+	/*
+	 * Note: this may only work for single threaded applications,
+	 * we'll live and learn ...
+	 */
+        retval = GetModuleFileName( NULL, CallerFilename, _MAX_PATH);
+#endif
+
+	if ( retval == 0 ) {
+		VSflag = FALSE;
+		return;
+	}
+
+	size = GetFileVersionInfoSize( CallerFilename, &hVersionInfoID);
+
+	if( size == 0 ) {
+		/*
+		 * hey , I bet we don't have a version resource, let's
+		 * punt
+		 */
+#if 0
+		/* let's see what we have? (1813 means no resource) */
+		size = GetLastError(); 		/*  WIN32 only */
+#endif
+		*VSflag = FALSE;
+		return;
+	}
+
+	hVersionInfo = GlobalAlloc(GHND, size);
+	lpVersionInfo = GlobalLock(hVersionInfo);
+
+	retval = GetFileVersionInfo( CallerFilename, hVersionInfoID, size,
+				    lpVersionInfo);
+
+	retval = VerQueryValue(lpVersionInfo, "\\VarFileInfo\\Translation",
+			       (LPSTR *)&lpLangInfo, &dumint);
+	wsprintf(szVerQ,
+		 "\\StringFileInfo\\%04x%04x\\",
+		 LOWORD(*lpLangInfo), HIWORD(*lpLangInfo));
+	
+	cp = szVerQ + lstrlen(szVerQ);
+
+	lstrcpy(cp, "ProductName");
+
+
+	/* try a localAppTitle and then a strcpy 4/2/97 */
+
+	locAppTitle = 0;
+	locAppVer = 0;
+
+	retval = VerQueryValue(lpVersionInfo, szVerQ, &locAppTitle,
+			       &dumint);
+
+	lstrcpy(cp, "ProductVersion");
+
+
+	retval = VerQueryValue(lpVersionInfo, szVerQ, &locAppVer,
+			       &dumint);
+
+	if (!locAppTitle || !locAppVer) {
+	  	/* Punt, we don't have the right version resource records */
+		*VSflag = FALSE;
+		return;
+	}
+
+	/*
+	 * We don't have a way to determine that INI file of the
+	 * application at the moment so let's just use krb5.ini
+	 */
+	strncpy( locAppIni, KERBEROS_INI, sizeof(locAppIni) - 1 );
+	locAppIni[ sizeof(locAppIni) - 1 ] = '\0';
+
+	strncpy( AppTitle, locAppTitle, APPVERINFO_SIZE);
+	AppTitle[APPVERINFO_SIZE - 1] = '\0';
+	strncpy( AppVer, locAppVer, APPVERINFO_SIZE);
+	AppVer[APPVERINFO_SIZE - 1] = '\0';
+	strncpy( AppIni, locAppIni, APPVERINFO_SIZE);
+	AppIni[APPVERINFO_SIZE - 1] = '\0';
+
+	/*
+	 * We also need to determine if we want to suppress version
+	 * checking of this application.  Does the tail of the
+	 * AppTitle end in a "-v" ?
+	 */
+	revAppTitle = _strrev( _strdup(AppTitle));
+	if( revAppTitle[0] == 'v' || revAppTitle[0] == 'V'  &&
+	   revAppTitle[1] == '-' ) {
+		VSflag = FALSE;
+	}
+	return;
+}
+
+
+/*
+ * Use the version server to give us some control on distribution and usage
+ * We're going to test track as well
+ */
+static int CallVersionServer(app_title, app_version, app_ini, code_cover)
+	char *app_title;
+	char *app_version;
+	char *app_ini;
+	char *code_cover;
+{
+	VS_Request vrequest;
+	VS_Status  vstatus;
+
+	SetCursor(LoadCursor(NULL, IDC_WAIT));
+
+	/*
+	 * We should be able to pass in code_cover below, but things
+	 * are breaking under Windows 16 for no good reason.
+	 */
+	vrequest = VSFormRequest((LPSTR) app_title, (LPSTR) app_version,
+				 (LPSTR) app_ini,
+				 NULL /* code_cover */, NULL,
+				 V_CHECK_AND_LOG);
+
+	SetCursor(LoadCursor(NULL, IDC_ARROW));
+	/*
+	 * If the user presses cancel when registering the test
+	 * tracker, we'll let them continue.
+	 */
+	if (ReqStatus(vrequest) == V_E_CANCEL) {
+		VSDestroyRequest(vrequest);
+		return 0;
+	}
+	vstatus = VSProcessRequest(vrequest);
+	/*
+	 * Only complain periodically, if the test tracker isn't
+	 * working... 
+	 */
+	if (v_complain(vstatus, app_ini)) {
+		WinVSReportRequest(vrequest, NULL, 
+				   "Version Server Status Report");
+	}                                                         
+	if (vstatus == V_REQUIRED) {
+		SetCursor(LoadCursor(NULL, IDC_WAIT));
+		VSDestroyRequest(vrequest);
+		return( -1 );
+	}
+	VSDestroyRequest(vrequest);
+	return (0);
+}   
+#endif
+
+#ifdef TIMEBOMB
+static krb5_error_code do_timebomb()
+{
+	char buf[1024];
+	long timeleft;
+	static first_time = 1;
+
+	timeleft = TIMEBOMB - time(0);
+	if (timeleft <= 0) {
+		if (first_time) {
+			sprintf(buf, "Your version of %s has expired.\n",
+				TIMEBOMB_PRODUCT);
+			buf[sizeof(buf) - 1] = '\0';
+			strncat(buf, "Please upgrade it.", sizeof(buf) - 1 - strlen(buf));
+#ifdef TIMEBOMB_INFO
+			strncat(buf, TIMEBOMB_INFO, sizeof(buf) - 1 - strlen(buf));
+#endif
+			MessageBox(NULL, buf, "", MB_OK);
+			first_time = 0;
+		}
+		return TIMEBOMB_ERROR;
+	}
+	timeleft = timeleft / ((long) 60*60*24);
+	if (timeleft < TIMEBOMB_WARN) {
+		if (first_time) {
+			sprintf(buf, "Your version of %s will expire in %ld days.\n",
+				TIMEBOMB_PRODUCT, timeleft);
+			strncat(buf, "Please upgrade it soon.", sizeof(buf) - 1 - strlen(buf));
+#ifdef TIMEBOMB_INFO
+			strncat(buf, TIMEBOMB_INFO, sizeof(buf) - 1 - strlen(buf));
+#endif
+			MessageBox(NULL, buf, "", MB_OK);
+			first_time = 0;
+		}
+	}
+	return 0;
+}
+#endif
+
+/*
+ * This was originally called from LibMain; unfortunately, Windows 3.1
+ * doesn't allow you to make messaging calls from LibMain.  So, we now
+ * do the timebomb/version server stuff from krb5_init_context().
+ */
+krb5_error_code krb5_vercheck()
+{
+	static int verchecked = 0;
+	if (verchecked)
+		return 0;
+#ifdef TIMEBOMB
+	krb5_error_code retval = do_timebomb();
+	if (retval)
+		return retval;
+#endif
+#ifdef VERSERV
+#if 0
+	/* Check library ? */
+	if (CallVersionServer(APP_TITLE, APP_VER, APP_INI, NULL))
+		return KRB5_LIB_EXPIRED;
+#endif
+	{
+#ifdef APP_TITLE
+		if (CallVersionServer(APP_TITLE, APP_VER, APP_INI, NULL))
+			return VERSERV_ERROR;
+#else
+		char AppTitle[APPVERINFO_SIZE];
+		char AppVer[APPVERINFO_SIZE];
+		char AppIni[APPVERINFO_SIZE];
+		BOOL VSflag=TRUE;
+
+		GetCallingAppVerInfo( AppTitle, AppVer, AppIni, &VSflag);
+
+		if (VSflag) {
+			if (CallVersionServer(AppTitle, AppVer, AppIni, NULL))
+				return KRB5_APPL_EXPIRED;
+		}
+#endif
+		
+	}
+#endif
+        verchecked = 1;
+	return 0;
+}
+
+
+static HINSTANCE hlibinstance;
+
+HINSTANCE get_lib_instance()
+{
+    return hlibinstance;
+}
+
+#define DLL_STARTUP 0
+#define DLL_SHUTDOWN 1
+
+static int
+control(int mode)
+{
+    switch(mode) {
+    case DLL_STARTUP:
+	break;
+
+    case DLL_SHUTDOWN:
+#ifdef KRB5
+	krb5_stdcc_shutdown();
+#endif
+	break;
+
+#if defined(ENABLE_THREADS) && defined(SUPPORTLIB)
+    case DLL_THREAD_DETACH:
+	krb5int_thread_detach_hook();
+	return 0;
+#endif
+
+    default:
+	return -1;
+    }
+
+#if defined KRB5
+    switch (mode) {
+    case DLL_STARTUP:
+	profile_library_initializer__auxinit();
+	cryptoint_initialize_library__auxinit();
+	krb5int_lib_init__auxinit();
+	break;
+    case DLL_SHUTDOWN:
+	krb5int_lib_fini();
+	cryptoint_cleanup_library();
+	profile_library_finalizer();
+	break;
+    }
+#elif defined KRB4
+    switch (mode){ 
+    case DLL_STARTUP:
+      add_error_table(&et_krb_error_table);
+      add_error_table(&et_kadm_error_table);
+      break;
+    case DLL_SHUTDOWN:
+      remove_error_table(&et_krb_error_table);
+      remove_error_table(&et_kadm_error_table);
+      break;
+    }
+#elif defined GSSAPI
+    switch (mode) {
+    case DLL_STARTUP:
+	gssint_lib_init__auxinit();
+	break;
+    case DLL_SHUTDOWN:
+	gssint_lib_fini();
+	break;
+    }
+#elif defined COMERR
+    switch (mode) {
+    case DLL_STARTUP:
+	com_err_initialize__auxinit();
+	break;
+    case DLL_SHUTDOWN:
+	com_err_terminate();
+	break;
+    }
+#elif defined PROFILELIB
+    switch (mode) {
+    case DLL_STARTUP:
+	profile_library_initializer__auxinit();
+	break;
+    case DLL_SHUTDOWN:
+	profile_library_finalizer();
+	break;
+    }
+#elif defined SUPPORTLIB
+    switch (mode) {
+    case DLL_STARTUP:
+      krb5int_thread_support_init__auxinit();
+      break;
+    case DLL_SHUTDOWN:
+      krb5int_thread_support_fini();
+      break;
+    }
+#else
+# error "Don't know the init/fini functions for this library."
+#endif
+
+    return 0;
+}
+
+#ifdef _WIN32
+
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+	    hlibinstance = (HINSTANCE) hModule;
+	    if (control(DLL_STARTUP))
+		return FALSE;
+	    break;
+
+        case DLL_THREAD_ATTACH:
+	    break;
+
+        case DLL_THREAD_DETACH:
+	    if (control(DLL_THREAD_DETACH))
+		return FALSE;
+	    break;
+
+        case DLL_PROCESS_DETACH:
+	    if (control(DLL_SHUTDOWN))
+		return FALSE;
+	    break;
+
+        default:
+	    return FALSE;
+    }
+ 
+    return TRUE;   // successful DLL_PROCESS_ATTACH
+}
+
+#else
+
+BOOL CALLBACK
+LibMain (hInst, wDataSeg, cbHeap, CmdLine)
+HINSTANCE hInst;
+WORD wDataSeg;
+WORD cbHeap;
+LPSTR CmdLine;
+{
+    hlibinstance = hInst;
+    if (control(DLL_STARTUP))
+	return 0;
+    else 
+	return 1;
+}
+
+int CALLBACK __export
+WEP(nParam)
+	int nParam;
+{
+    if (control(DLL_SHUTDOWN))
+	return 0;
+    else
+	return 1;
+}
+
+#endif
diff --git a/mechglue/src/lib/xpprof32.def b/mechglue/src/lib/xpprof32.def
new file mode 100644
index 000000000..a14cd0a31
--- /dev/null
+++ b/mechglue/src/lib/xpprof32.def
@@ -0,0 +1,28 @@
+;----------------------------------------------------
+;   XPPROF32.DEF - XPPROF32.DLL 
+;----------------------------------------------------
+
+;LIBRARY		XPPROF32.DLL
+DESCRIPTION	'Cross Platform Profile DLL'
+HEAPSIZE	8192
+
+EXPORTS
+	profile_init
+	profile_init_path
+	profile_flush
+	profile_release
+	profile_abandon
+	profile_get_values
+	profile_free_list
+	profile_get_string
+	profile_get_integer
+	profile_get_relation_names
+	profile_get_subsection_names
+	profile_iterator_create
+	profile_iterator_free
+	profile_iterator
+	profile_release_string
+	profile_update_relation
+	profile_clear_relation
+	profile_rename_section
+	profile_add_relation
diff --git a/mechglue/src/patchlevel.h b/mechglue/src/patchlevel.h
new file mode 100644
index 000000000..7d0bf1c23
--- /dev/null
+++ b/mechglue/src/patchlevel.h
@@ -0,0 +1,58 @@
+/*
+ * patchlevel.h
+ *
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*
+ * This is the master file for version stamping purposes.  The
+ * checked-in version will contain the correct version information at
+ * all times.  Prior to an official release x.y.z,
+ * KRB5_MAJOR_RELEASE=x, KRB5_MINOR_RELEASE=y, and KRB5_PATCHLEVEL=z.
+ * KRB5_RELTAIL will reflect the release state.  It will be
+ * "prerelease" for unreleased code either on the trunk or on a
+ * release branch.  It will be undefined for a final release.
+ *
+ * Immediately following a final release, the release version numbers
+ * will be incremented, and KRB5_RELTAIL will revert to "prerelease".
+ *
+ * KRB5_RELTAG contains the CVS tag name corresponding to the release.
+ * KRB5_RELDATE identifies the date of the release.  They should
+ * normally be undefined for checked-in code.
+ */
+
+/*
+ * ==========
+ * IMPORTANT:
+ * ==========
+ *
+ * If you are a vendor supplying modified code derived from MIT
+ * Kerberos, you SHOULD update KRB5_RELTAIL to identify your
+ * organization.
+ */
+#define KRB5_MAJOR_RELEASE 1
+#define KRB5_MINOR_RELEASE 5
+#define KRB5_PATCHLEVEL 0
+#define KRB5_RELTAIL "prerelease"
+/* #undef KRB5_RELDATE */
+/* #undef KRB5_RELTAG */
diff --git a/mechglue/src/plugins/kdb/db2/ChangeLog b/mechglue/src/plugins/kdb/db2/ChangeLog
new file mode 100644
index 000000000..e88e25d73
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/ChangeLog
@@ -0,0 +1,142 @@
+2005-12-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (myfulldir, RELDIR): Updated for directory rename.
+
+2005-11-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* policy_db.h: Include db.h after gssrpc/types.h, to fix
+	compilation on Tru64.
+
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* policy_db.h: Include errno.h and krb5.h instead of k5-int.h.
+
+2005-10-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Set build_dynobj=yes.
+
+	* Makefile.in (DYNOBJ_LOADER_PROG, DYNOBJ_EXPLIBS_WITH_LOADER,
+	DYNOBJ_EXPDEPS_WITH_LOADER): New variables.
+
+2005-10-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Revert 10-04 change; add support
+	library.
+
+2005-10-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (DBSHOBJLISTS): New variable.
+	($(DBOBJLISTS-k5), $(DBSHOBJLISTS)): Depend on recursion step.
+
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* libdb2: Directory moved from util/db2.
+	* configure.in: Configure it, unless a system version is to be
+	used.
+	* Makefile.in (DBDIR): Updated.
+	($(DB_DEPS)): Depend on all-recurse.
+	(DB_VERSION, DB_DEPS, DB_DEPS-sys, DB_DEPS-k5, DB_DEPS-redirect,
+	DB_LIB, KDB5_DB_LIB, DB_DEPLIB, DB_DEPLIB-k5, DB_DEPLIB-sys):
+	Variable definitions moved here from config/pre.in.
+	(.depend-verify-db, depend-verify-db-k5, depend-verify-db-sys):
+	New targets, moved from config/post.in.
+	(.d): Depend on .depend-verify-db.
+
+	* Makefile.in (SHLIB_EXPLIBS): Only use gssrpc and KDB5_DB_LIB.
+	* configure.in: Set enable_shared=yes.
+
+	* kdb_xdr.c (krb5_dbe_create_key_data, krb5_dbe_update_tl_data,
+	krb5_dbe_lookup_tl_data, krb5_dbe_update_last_pwd_change,
+	krb5_dbe_lookup_last_pwd_change, krb5_dbe_update_mod_princ_data,
+	krb5_dbe_lookup_mod_princ_data, krb5_dbe_search_enctype,
+	krb5_dbe_find_enctype): Unused functions deleted.
+	(safe_realloc): Unused macro deleted.
+
+2005-09-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* Directory moved from lib/kdb/kdb_db2 to modules/kdb/db2.
+	* Makefile.in (myfulldir, LOCALINCLUDES, RELDIR): Updated.
+	* db2_exp.c, kdb_db2.c: Include kdb5.h instead of ../kdb5.h.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-08-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_db2.c (MAX_LOCK_TRIES): New macro.
+	(krb5_db2_db_lock): Always make non-blocking attempts to acquire
+	the lock.  Retry up to MAX_LOCK_TRIES times on failure.
+
+2005-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Change to db2.
+	(LIBMAJOR): Change to 0.
+	(all): Deleted explicit dependency.
+	(all-unix): Added here, without "lib" prefix.
+	(clean-unix): Drop clean-liblinks.
+	* db2_exp.c: (krb5_db_vftabl_db2): Renamed from ..._kdb_db2.
+	* db2.exports: Rename from libkdb_db2.exports, update for symbol
+	name change.
+
+2005-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_db2.c: Reindent.  Use ISO C function decl style.  Delete
+	functions inside "#if 0".
+
+2005-06-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Use libnover_frag.
+	(LIB): Variable deleted, uses replaced with LIBBASE.
+	(SHLIB_EXPDEPS, SHLIB_EXPLIBS): Add gssrpc library and
+	depedencies.
+	(all-unix): Don't depend on all-liblinks.
+	(lib$(LIBBASE)$(SO_EXT)): Rule deleted.
+	(t_kdb, check, clean): Delete t_kdb references.
+
+2005-06-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb_db2.c: Don't use C++-style comments.
+	(krb5_db2_db_get_principal): Don't use variables named "try".
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	Novell merge.
+	* Makefile.in:
+	* adb_openclose.c: Moved from lib/kadm5/srv.  Include k5-int.h,
+	policy_db.h, db.h; don't include adb.h.
+	(osa_adb_create_db, osa_adb_destroy_db, osa_adb_rename_db,
+	osa_adb_init_db, osa_adb_fini_db, osa_adb_get_lock,
+	osa_adb_release_lock, osa_adb_open_and_lock,
+	osa_adb_close_and_unlock): Return krb5_error_code instead of
+	osa_adb_ret_t.
+	(osa_adb_rename_db, osa_adb_fini_db, osa_adb_get_lock,
+	osa_adb_release_lock): Change OSA_ADB_* lock flags to
+	KRB5_DB_LOCKMODE_* flags.
+	(osa_adb_get_lock): Initialize return variable.
+	* adb_policy.c: Moved from lib/kadm5/srv.  Include policy_db.h;
+	don't include adb.h.
+	(osa_adb_create_policy_db, osa_adb_rename_policy_db,
+	osa_adb_destroy_policy_db, osa_adb_open_policy,
+	osa_adb_close_policy): Functions deleted.
+	(osa_adb_create_policy, osa_adb_destroy_policy,
+	osa_adb_get_policy, osa_adb_put_policy, osa_adb_iter_policy):
+	Return krb5_error_code instead of osa_adb_ret_t.  Change OSA_ADB_*
+	lock flags to KRB5_DB_LOCKMODE_* flags.
+	(osa_adb_get_policy): Change policy name argument from
+	kadm5_policy_t to char*.  Add int* argument for returning count of
+	entries.  If no entries found, return success and zero count.
+	(osa_free_policy_ent): Moved here from old
+	lib/kadm5/srv/adb_free.c.
+	* configure.in:
+	* db2_exp.c:
+	* kdb_compat.h:
+	* kdb_db2.c:
+	* kdb_db2.h:
+	* kdb_xdr.c:
+	* kdb_xdr.h:
+	* libkdb_db2.exports: New file.  Export only the virtual function
+	table.
+	* pol_xdr.c:
+	* policy_db.h:
+
diff --git a/mechglue/src/plugins/kdb/db2/Makefile.in b/mechglue/src/plugins/kdb/db2/Makefile.in
new file mode 100644
index 000000000..6935bd467
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/Makefile.in
@@ -0,0 +1,147 @@
+thisconfigdir=.
+myfulldir=plugins/kdb/db2
+mydir=.
+BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ;
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+LOCALINCLUDES = -I../../../lib/kdb -I$(srcdir)/../../../lib/kdb
+
+DB_VERSION	= @DB_VERSION@
+DB_DEPS		= $(DB_DEPS-@DB_HEADER_VERSION@)
+DB_DEPS-sys	=
+DB_DEPS-k5	= $(BUILDTOP)/include/db.h $(BUILDTOP)/include/db-config.h
+DB_DEPS-redirect = $(BUILDTOP)/include/db.h
+DB_LIB		= @DB_LIB@
+KDB5_DB_LIB	= @KDB5_DB_LIB@
+DB_DEPLIB	= $(DB_DEPLIB-@DB_VERSION@)
+DB_DEPLIB-k5	= $(TOPLIBD)/libdb$(DEPLIBEXT)
+DB_DEPLIB-sys	=
+
+LIBBASE=db2
+LIBMAJOR=0
+LIBMINOR=0
+SO_EXT=.so
+RELDIR=../plugins/kdb/db2
+# Depends on libk5crypto and libkrb5
+# Also on gssrpc, for xdr stuff.
+SHLIB_EXPDEPS = \
+	$(GSSRPC_DEPLIBS) \
+	$(TOPLIBD)/libk5crypto$(SHLIBEXT) \
+	$(TOPLIBD)/libkrb5$(SHLIBEXT)
+SHLIB_EXPLIBS= $(GSSRPC_LIBS) -lkrb5 -lcom_err -lk5crypto $(KDB5_DB_LIB) $(SUPPORT_LIB) $(LIBS)
+# -lgssrpc $(KDB5_DB_LIB)
+
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+DBDIR = libdb2
+DBOBJLISTS = $(DBOBJLISTS-@DB_VERSION@)
+DBOBJLISTS-sys =
+DBOBJLISTS-k5 = $(DBDIR)/hash/OBJS.ST $(DBDIR)/btree/OBJS.ST \
+	$(DBDIR)/db/OBJS.ST $(DBDIR)/mpool/OBJS.ST $(DBDIR)/recno/OBJS.ST \
+	$(DBDIR)/clib/OBJS.ST
+DBSHOBJLISTS = $(DBOBJLISTS:.ST=.SH)
+
+SRCS= \
+	$(srcdir)/kdb_xdr.c \
+	$(srcdir)/adb_openclose.c \
+	$(srcdir)/adb_policy.c \
+	$(srcdir)/kdb_db2.c \
+	$(srcdir)/pol_xdr.c \
+	$(srcdir)/db2_exp.c
+
+STOBJLISTS=OBJS.ST $(DBOBJLISTS)
+STLIBOBJS= \
+	kdb_xdr.o \
+	adb_openclose.o \
+	adb_policy.o \
+	kdb_db2.o \
+	pol_xdr.o \
+	db2_exp.o
+
+DYNOBJ_LOADER_PROG = $(BUILDTOP)/kdc/krb5kdc
+DYNOBJ_EXPLIBS_WITH_LOADER = -lgssrpc $(KDB5_DB_LIB)
+DYNOBJ_EXPDEPS_WITH_LOADER = $(GSSRPC_DEPLIBS)
+
+all-unix:: $(LIBBASE)$(SO_EXT)
+install-unix:: install-libs
+clean-unix:: clean-libs clean-libobjs
+
+$(DB_DEPS) $(DBOBJLISTS-k5) $(DBSHOBJLISTS): all-recurse
+
+#lib$(LIBBASE)$(SO_EXT): db2_exp.o
+#	$(CC) -shared -o $@ -L$(TOPLIBD) $^ -ldb $(SHLIB_EXPLIBS)
+
+clean::
+	$(RM) lib$(LIBBASE)$(SO_EXT) db2_exp.o
+
+# @libnover_frag@
+# @libobj_frag@
+
+.depend-verify-db: depend-verify-db-$(DB_VERSION)
+depend-verify-db-k5:
+	@if test -r .depend-verify-db; then :; \
+		else (set -x; touch .depend-verify-db); fi
+depend-verify-db-sys:
+	@echo 1>&2 error: cannot build dependencies using system db package
+	@exit 1
+
+.d: .depend-verify-db
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+kdb_xdr.so kdb_xdr.po $(OUTPRE)kdb_xdr.$(OBJEXT): kdb_xdr.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  kdb_xdr.h
+adb_openclose.so adb_openclose.po $(OUTPRE)adb_openclose.$(OBJEXT): \
+  adb_openclose.c $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  policy_db.h $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(DB_DEPS) $(BUILDTOP)/lib/kdb/adb_err.h
+adb_policy.so adb_policy.po $(OUTPRE)adb_policy.$(OBJEXT): \
+  adb_policy.c policy_db.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/kdb.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(DB_DEPS) $(BUILDTOP)/lib/kdb/adb_err.h
+kdb_db2.so kdb_db2.po $(OUTPRE)kdb_db2.$(OBJEXT): kdb_db2.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(DB_DEPS) $(SRCTOP)/lib/kdb/kdb5.h $(SRCTOP)/lib/kdb/err_handle.h \
+  kdb_db2.h policy_db.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/lib/kdb/adb_err.h kdb_xdr.h kdb_compat.h
+pol_xdr.so pol_xdr.po $(OUTPRE)pol_xdr.$(OBJEXT): pol_xdr.c \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/gssrpc/rpc.h \
+  $(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/gssrpc/rename.h \
+  $(BUILDTOP)/include/gssrpc/xdr.h $(BUILDTOP)/include/gssrpc/auth.h \
+  $(BUILDTOP)/include/gssrpc/clnt.h $(BUILDTOP)/include/gssrpc/rpc_msg.h \
+  $(BUILDTOP)/include/gssrpc/auth_unix.h $(BUILDTOP)/include/gssrpc/auth_gss.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/svc_auth.h \
+  $(BUILDTOP)/include/gssrpc/svc.h $(SRCTOP)/include/krb5/kdb.h \
+  policy_db.h $(DB_DEPS) $(BUILDTOP)/lib/kdb/adb_err.h
+db2_exp.so db2_exp.po $(OUTPRE)db2_exp.$(OBJEXT): db2_exp.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(DB_DEPS) $(SRCTOP)/lib/kdb/kdb5.h $(SRCTOP)/lib/kdb/err_handle.h \
+  kdb_db2.h policy_db.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/gssrpc/rename.h $(BUILDTOP)/include/gssrpc/xdr.h \
+  $(BUILDTOP)/lib/kdb/adb_err.h kdb_xdr.h
diff --git a/mechglue/src/plugins/kdb/db2/adb_openclose.c b/mechglue/src/plugins/kdb/db2/adb_openclose.c
new file mode 100644
index 000000000..97ce1123b
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/adb_openclose.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$ 
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include	<sys/file.h>
+#include	<fcntl.h>
+#include	<unistd.h>
+#include        <k5-int.h>
+#include	"policy_db.h"
+#include	<stdlib.h>
+#include        <db.h>
+
+#define MAX_LOCK_TRIES 5
+
+struct _locklist {
+     osa_adb_lock_ent lockinfo;
+     struct _locklist *next;
+};
+
+krb5_error_code osa_adb_create_db(char *filename, char *lockfilename,
+				  int magic)
+{
+     int lf;
+     DB *db;
+     BTREEINFO btinfo;
+     
+     memset(&btinfo, 0, sizeof(btinfo));
+     btinfo.flags = 0;
+     btinfo.cachesize = 0;
+     btinfo.psize = 4096;
+     btinfo.lorder = 0;
+     btinfo.minkeypage = 0;
+     btinfo.compare = NULL;
+     btinfo.prefix = NULL;
+     db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_BTREE, &btinfo);
+     if (db == NULL)
+	  return errno;
+     if (db->close(db) < 0)
+	  return errno;
+
+     /* only create the lock file if we successfully created the db */
+     lf = THREEPARAMOPEN(lockfilename, O_RDWR | O_CREAT | O_EXCL, 0600);
+     if (lf == -1)
+	  return errno;
+     (void) close(lf);
+     
+     return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_destroy_db(char *filename, char *lockfilename,
+				 int magic)
+{
+     /* the admin databases do not contain security-critical data */
+     if (unlink(filename) < 0 ||
+	 unlink(lockfilename) < 0)
+	  return errno;
+     return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_rename_db(char *filefrom, char *lockfrom,
+				char *fileto, char *lockto, int magic)
+{
+     osa_adb_db_t fromdb, todb;
+     krb5_error_code ret;
+
+     /* make sure todb exists */
+     if ((ret = osa_adb_create_db(fileto, lockto, magic)) &&
+	 ret != EEXIST)
+	  return ret;
+
+     if ((ret = osa_adb_init_db(&fromdb, filefrom, lockfrom, magic)))
+	  return ret;
+     if ((ret = osa_adb_init_db(&todb, fileto, lockto, magic))) {
+	  (void) osa_adb_fini_db(fromdb, magic);
+	  return ret;
+     }
+     if ((ret = osa_adb_get_lock(fromdb, KRB5_DB_LOCKMODE_PERMANENT))) {
+	  (void) osa_adb_fini_db(fromdb, magic);
+	  (void) osa_adb_fini_db(todb, magic);
+	  return ret;
+     }
+     if ((ret = osa_adb_get_lock(todb, KRB5_DB_LOCKMODE_PERMANENT))) {
+	  (void) osa_adb_fini_db(fromdb, magic);
+	  (void) osa_adb_fini_db(todb, magic);
+	  return ret;
+     }
+     if ((rename(filefrom, fileto) < 0)) {
+	  (void) osa_adb_fini_db(fromdb, magic);
+	  (void) osa_adb_fini_db(todb, magic);
+	  return errno;
+     }
+     /*
+      * Do not release the lock on fromdb because it is being renamed
+      * out of existence; no one can ever use it again.
+      */
+     if ((ret = osa_adb_release_lock(todb))) {
+	  (void) osa_adb_fini_db(fromdb, magic);
+	  (void) osa_adb_fini_db(todb, magic);
+	  return ret;
+     }
+	  
+     (void) osa_adb_fini_db(fromdb, magic);
+     (void) osa_adb_fini_db(todb, magic);
+     return 0;
+}
+
+krb5_error_code osa_adb_init_db(osa_adb_db_t *dbp, char *filename,
+			      char *lockfilename, int magic)
+{
+     osa_adb_db_t db;
+     static struct _locklist *locklist = NULL;
+     struct _locklist *lockp;
+     krb5_error_code code;
+     
+     if (dbp == NULL || filename == NULL)
+	  return EINVAL;
+
+     db = (osa_adb_princ_t) malloc(sizeof(osa_adb_db_ent));
+     if (db == NULL)
+	  return ENOMEM;
+
+     memset(db, 0, sizeof(*db));
+     db->info.hash = NULL;
+     db->info.bsize = 256;
+     db->info.ffactor = 8;
+     db->info.nelem = 25000;
+     db->info.lorder = 0;
+
+     db->btinfo.flags = 0;
+     db->btinfo.cachesize = 0;
+     db->btinfo.psize = 4096;
+     db->btinfo.lorder = 0;
+     db->btinfo.minkeypage = 0;
+     db->btinfo.compare = NULL;
+     db->btinfo.prefix = NULL;
+     /*
+      * A process is allowed to open the same database multiple times
+      * and access it via different handles.  If the handles use
+      * distinct lockinfo structures, things get confused: lock(A),
+      * lock(B), release(B) will result in the kernel unlocking the
+      * lock file but handle A will still think the file is locked.
+      * Therefore, all handles using the same lock file must share a
+      * single lockinfo structure.
+      *
+      * It is not sufficient to have a single lockinfo structure,
+      * however, because a single process may also wish to open
+      * multiple different databases simultaneously, with different
+      * lock files.  This code used to use a single static lockinfo
+      * structure, which means that the second database opened used
+      * the first database's lock file.  This was Bad.
+      *
+      * We now maintain a linked list of lockinfo structures, keyed by
+      * lockfilename.  An entry is added when this function is called
+      * with a new lockfilename, and all subsequent calls with that
+      * lockfilename use the existing entry, updating the refcnt.
+      * When the database is closed with fini_db(), the refcnt is
+      * decremented, and when it is zero the lockinfo structure is
+      * freed and reset.  The entry in the linked list, however, is
+      * never removed; it will just be reinitialized the next time
+      * init_db is called with the right lockfilename.
+      */
+
+     /* find or create the lockinfo structure for lockfilename */
+     lockp = locklist;
+     while (lockp) {
+	  if (strcmp(lockp->lockinfo.filename, lockfilename) == 0)
+	       break;
+	  else
+	       lockp = lockp->next;
+     }
+     if (lockp == NULL) {
+	  /* doesn't exist, create it, add to list */
+	  lockp = (struct _locklist *) malloc(sizeof(*lockp));
+	  if (lockp == NULL) {
+	       free(db);
+	       return ENOMEM;
+	  }
+	  memset(lockp, 0, sizeof(*lockp));
+	  lockp->next = locklist;
+	  locklist = lockp;
+     }
+
+     /* now initialize lockp->lockinfo if necessary */
+     if (lockp->lockinfo.lockfile == NULL) {
+	  if ((code = krb5_init_context(&lockp->lockinfo.context))) {
+	       free(db);
+	       return((krb5_error_code) code);
+	  }
+
+	  /*
+	   * needs be open read/write so that write locking can work with
+	   * POSIX systems
+	   */
+	  lockp->lockinfo.filename = strdup(lockfilename);
+	  if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) {
+	       /*
+		* maybe someone took away write permission so we could only
+		* get shared locks?
+		*/
+	       if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r"))
+		   == NULL) {
+		    free(db);
+		    return OSA_ADB_NOLOCKFILE;
+	       }
+	  }
+	  lockp->lockinfo.lockmode = lockp->lockinfo.lockcnt = 0;
+     }
+
+     /* lockp is set, lockinfo is initialized, update the reference count */
+     db->lock = &lockp->lockinfo;
+     db->lock->refcnt++;
+
+     db->opencnt = 0;
+     db->filename = strdup(filename);
+     db->magic = magic;
+
+     *dbp = db;
+     
+     return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_fini_db(osa_adb_db_t db, int magic)
+{
+     if (db->magic != magic)
+	  return EINVAL;
+     if (db->lock->refcnt == 0) {
+	  /* barry says this can't happen */
+	  return OSA_ADB_FAILURE;
+     } else {
+	  db->lock->refcnt--;
+     }
+
+     if (db->lock->refcnt == 0) {
+	  /*
+	   * Don't free db->lock->filename, it is used as a key to
+	   * find the lockinfo entry in the linked list.  If the
+	   * lockfile doesn't exist, we must be closing the database
+	   * after trashing it.  This has to be allowed, so don't
+	   * generate an error.
+	   */
+	  if (db->lock->lockmode != KRB5_DB_LOCKMODE_PERMANENT)
+	       (void) fclose(db->lock->lockfile);
+	  db->lock->lockfile = NULL;
+	  krb5_free_context(db->lock->context);
+     }
+
+     db->magic = 0;
+     free(db->filename);
+     free(db);
+     return OSA_ADB_OK;
+}     
+     
+krb5_error_code osa_adb_get_lock(osa_adb_db_t db, int mode)
+{
+     int tries, gotlock, perm, krb5_mode, ret = 0;
+
+     if (db->lock->lockmode >= mode) {
+	  /* No need to upgrade lock, just incr refcnt and return */
+	  db->lock->lockcnt++;
+	  return(OSA_ADB_OK);
+     }
+
+     perm = 0;
+     switch (mode) {
+	case KRB5_DB_LOCKMODE_PERMANENT:
+	  perm = 1;
+	case KRB5_DB_LOCKMODE_EXCLUSIVE:
+	  krb5_mode = KRB5_LOCKMODE_EXCLUSIVE;
+	  break;
+	case KRB5_DB_LOCKMODE_SHARED:
+	  krb5_mode = KRB5_LOCKMODE_SHARED;
+	  break;
+	default:
+	  return(EINVAL);
+     }
+
+     for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
+	  if ((ret = krb5_lock_file(db->lock->context,
+				    fileno(db->lock->lockfile),
+				    krb5_mode|KRB5_LOCKMODE_DONTBLOCK)) == 0) {
+	       gotlock++;
+	       break;
+	  } else if (ret == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
+	       /* tried to exclusive-lock something we don't have */
+	       /* write access to */
+	       return OSA_ADB_NOEXCL_PERM;
+
+	  sleep(1);
+     }
+
+     /* test for all the likely "can't get lock" error codes */
+     if (ret == EACCES || ret == EAGAIN || ret == EWOULDBLOCK)
+	  return OSA_ADB_CANTLOCK_DB;
+     else if (ret != 0)
+	  return ret;
+
+     /*
+      * If the file no longer exists, someone acquired a permanent
+      * lock.  If that process terminates its exclusive lock is lost,
+      * but if we already had the file open we can (probably) lock it
+      * even though it has been unlinked.  So we need to insist that
+      * it exist.
+      */
+     if (access(db->lock->filename, F_OK) < 0) {
+	  (void) krb5_lock_file(db->lock->context,
+				fileno(db->lock->lockfile),
+				KRB5_LOCKMODE_UNLOCK);
+	  return OSA_ADB_NOLOCKFILE;
+     }
+     
+     /* we have the shared/exclusive lock */
+     
+     if (perm) {
+	  if (unlink(db->lock->filename) < 0) {
+	       /* somehow we can't delete the file, but we already */
+	       /* have the lock, so release it and return */
+
+	       ret = errno;
+	       (void) krb5_lock_file(db->lock->context,
+				     fileno(db->lock->lockfile),
+				     KRB5_LOCKMODE_UNLOCK);
+	       
+	       /* maybe we should return CANTLOCK_DB.. but that would */
+	       /* look just like the db was already locked */
+	       return ret;
+	  }
+
+	  /* this releases our exclusive lock.. which is okay because */
+	  /* now no one else can get one either */
+	  (void) fclose(db->lock->lockfile);
+     }
+     
+     db->lock->lockmode = mode;
+     db->lock->lockcnt++;
+     return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_release_lock(osa_adb_db_t db)
+{
+     int ret, fd;
+     
+     if (!db->lock->lockcnt)		/* lock already unlocked */
+	  return OSA_ADB_NOTLOCKED;
+
+     if (--db->lock->lockcnt == 0) {
+	  if (db->lock->lockmode == KRB5_DB_LOCKMODE_PERMANENT) {
+	       /* now we need to create the file since it does not exist */
+               fd = THREEPARAMOPEN(db->lock->filename,O_RDWR | O_CREAT | O_EXCL,
+                                   0600);
+	       if ((db->lock->lockfile = fdopen(fd, "w+")) == NULL)
+		    return OSA_ADB_NOLOCKFILE;
+	  } else if ((ret = krb5_lock_file(db->lock->context,
+					  fileno(db->lock->lockfile),
+					  KRB5_LOCKMODE_UNLOCK)))
+	       return ret;
+	  
+	  db->lock->lockmode = 0;
+     }
+     return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_open_and_lock(osa_adb_princ_t db, int locktype)
+{
+     int ret;
+
+     ret = osa_adb_get_lock(db, locktype);
+     if (ret != OSA_ADB_OK)
+	  return ret;
+     if (db->opencnt)
+	  goto open_ok;
+
+     db->db = dbopen(db->filename, O_RDWR, 0600, DB_BTREE, &db->btinfo);
+     if (db->db != NULL)
+	 goto open_ok;
+     switch (errno) {
+#ifdef EFTYPE
+     case EFTYPE:
+#endif
+     case EINVAL:
+	  db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info);
+	  if (db->db != NULL)
+	       goto open_ok;
+     default:
+	  (void) osa_adb_release_lock(db);
+	  if (errno == EINVAL)
+	       return OSA_ADB_BAD_DB;
+	  return errno;
+     }
+open_ok:
+     db->opencnt++;
+     return OSA_ADB_OK;
+}
+
+krb5_error_code osa_adb_close_and_unlock(osa_adb_princ_t db)
+{
+     if (--db->opencnt)
+	  return osa_adb_release_lock(db);
+     if(db->db != NULL && db->db->close(db->db) == -1) {
+	  (void) osa_adb_release_lock(db);
+	  return OSA_ADB_FAILURE;
+     }
+
+     db->db = NULL;
+
+     return(osa_adb_release_lock(db));
+}
diff --git a/mechglue/src/plugins/kdb/db2/adb_policy.c b/mechglue/src/plugins/kdb/db2/adb_policy.c
new file mode 100644
index 000000000..e338cbbd0
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/adb_policy.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ * $Header$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include	<sys/file.h>
+#include	<fcntl.h>
+#include	"policy_db.h"
+#include	<stdlib.h>
+#include	<string.h>
+#include <errno.h>
+
+#define OPENLOCK(db, mode) \
+{ \
+       int olret; \
+	    if (db == NULL) \
+		 return EINVAL; \
+	    else if (db->magic != OSA_ADB_POLICY_DB_MAGIC) \
+		 return OSA_ADB_DBINIT; \
+	    else if ((olret = osa_adb_open_and_lock(db, mode)) != OSA_ADB_OK) \
+		 return olret; \
+	    }
+
+#define CLOSELOCK(db) \
+{ \
+     int cl_ret; \
+     if ((cl_ret = osa_adb_close_and_unlock(db)) != OSA_ADB_OK) \
+	  return cl_ret; \
+}
+
+
+/*
+ * Function: osa_adb_create_policy
+ * 
+ * Purpose: create a policy entry in the policy db.
+ *
+ * Arguments:
+ *	entry		(input) pointer to the entry to be added
+ * 	<return value>	OSA_ADB_OK on success, else error code.
+ *
+ * Requires:
+ *	entry have a valid name.
+ * 
+ * Effects:
+ *	creates the entry in the db
+ *
+ * Modifies:
+ *	the policy db.
+ * 
+ */
+krb5_error_code
+osa_adb_create_policy(osa_adb_policy_t db, osa_policy_ent_t entry)
+{
+    DBT			dbkey;
+    DBT			dbdata;
+    XDR			xdrs;
+    int			ret;
+
+    OPENLOCK(db, KRB5_DB_LOCKMODE_EXCLUSIVE);
+
+    if(entry->name == NULL) {
+	 ret = EINVAL;
+	 goto error;
+    }
+    dbkey.data = entry->name;
+    dbkey.size = (strlen(entry->name) + 1);
+		
+    switch(db->db->get(db->db, &dbkey, &dbdata, 0)) {
+    case 0:
+	 ret = OSA_ADB_DUP;
+	 goto error;
+    case 1:
+	break;
+    default:
+	 ret = errno;
+	 goto error;
+    }
+    xdralloc_create(&xdrs, XDR_ENCODE);
+    if(!xdr_osa_policy_ent_rec(&xdrs, entry)) {
+	xdr_destroy(&xdrs);
+	ret = OSA_ADB_XDR_FAILURE;
+	goto error;
+    }
+    dbdata.data = xdralloc_getdata(&xdrs);
+    dbdata.size = xdr_getpos(&xdrs);
+    switch(db->db->put(db->db, &dbkey, &dbdata, R_NOOVERWRITE)) {
+    case 0:
+	if((db->db->sync(db->db, 0)) == -1)
+	    ret = OSA_ADB_FAILURE;
+	ret = OSA_ADB_OK;
+	break;
+    case 1:
+	ret = OSA_ADB_DUP;
+	break;
+    default:
+	ret = OSA_ADB_FAILURE;
+	break;
+    }
+    xdr_destroy(&xdrs);
+
+error:
+    CLOSELOCK(db);
+    return ret;
+}
+
+/*
+ * Function: osa_adb_destroy_policy
+ * 
+ * Purpose: destroy a policy entry
+ *
+ * Arguments:
+ *	db		(input) database handle
+ *	name		(input) name of policy
+ * 	<return value>	OSA_ADB_OK on success, or error code.
+ *
+ * Requires:
+ *	db being valid.
+ *	name being non-null.
+ * Effects:
+ *	deletes policy from db.
+ *
+ * Modifies:
+ *	policy db.
+ * 
+ */
+krb5_error_code
+osa_adb_destroy_policy(osa_adb_policy_t db, char *name)
+{
+    DBT	    dbkey;
+    int	    status, ret;
+
+    OPENLOCK(db, KRB5_DB_LOCKMODE_EXCLUSIVE);
+    
+    if(name == NULL) {
+	 ret = EINVAL;
+	 goto error;
+    }
+    dbkey.data = name;
+    dbkey.size = (strlen(name) + 1);
+
+    status = db->db->del(db->db, &dbkey, 0);
+    switch(status) {
+    case 1:
+	 ret = OSA_ADB_NOENT;
+	 goto error;
+    case 0:
+	 if ((db->db->sync(db->db, 0)) == -1) {
+	      ret = OSA_ADB_FAILURE;
+	      goto error;
+	 }
+	 ret = OSA_ADB_OK;
+	 break;
+    default:
+	 ret = OSA_ADB_FAILURE;
+	 goto error;
+    }
+
+error:
+    CLOSELOCK(db);
+    return ret;
+}
+
+/*
+ * Function: osa_adb_get_policy
+ * 
+ * Purpose: retrieve policy
+ *
+ * Arguments:
+ *	db		(input) db handle
+ *	name		(input) name of policy
+ *	entry		(output) policy entry
+ *      cnt             (inout) Number of entries
+ * 	<return value>	0 on success, error code on failure.
+ *
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+krb5_error_code
+osa_adb_get_policy(osa_adb_policy_t db, char *name,
+		   osa_policy_ent_t *entry, int *cnt)
+{
+    DBT			dbkey;
+    DBT			dbdata;
+    XDR			xdrs;
+    int			ret;
+    char		*aligned_data;
+
+    OPENLOCK(db, KRB5_DB_LOCKMODE_SHARED);
+
+    *cnt = 1;
+
+    if(name == NULL) {
+	 ret = EINVAL;
+	 goto error;
+    }
+    dbkey.data = name;
+    dbkey.size = (strlen(dbkey.data) + 1);
+    dbdata.data = NULL;
+    dbdata.size = 0;
+    switch((db->db->get(db->db, &dbkey, &dbdata, 0))) {
+    case 1:
+	 ret = 0;
+	 *cnt = 0;
+	 goto error;
+    case 0:
+	break;
+    default:
+	 ret = OSA_ADB_FAILURE;
+	 goto error;
+    }
+    if (!(*(entry) = (osa_policy_ent_t)malloc(sizeof(osa_policy_ent_rec)))) {
+	 ret = ENOMEM;
+	 goto error;
+    }
+    if (!(aligned_data = (char *) malloc(dbdata.size))) {
+	 ret = ENOMEM;
+	 goto error;
+    }
+    memcpy(aligned_data, dbdata.data, dbdata.size);	
+    memset(*entry, 0, sizeof(osa_policy_ent_rec));
+    xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE);
+    if (!xdr_osa_policy_ent_rec(&xdrs, *entry)) 
+	ret =  OSA_ADB_FAILURE;
+    else ret = OSA_ADB_OK;
+    xdr_destroy(&xdrs);
+    free(aligned_data);
+
+error:
+    CLOSELOCK(db);
+    return ret;
+}
+
+/*
+ * Function: osa_adb_put_policy
+ * 
+ * Purpose: update a policy in the dababase
+ *
+ * Arguments:
+ *	db		(input) db handle
+ *	entry		(input) policy entry
+ * 	<return value>	0 on success error code on failure.
+ *
+ * Requires:
+ *	[requires]
+ * 
+ * Effects:
+ *	[effects]
+ *
+ * Modifies:
+ *	[modifies]
+ * 
+ */
+krb5_error_code
+osa_adb_put_policy(osa_adb_policy_t db, osa_policy_ent_t entry)
+{
+    DBT			dbkey;
+    DBT			dbdata;
+    DBT			tmpdb;
+    XDR			xdrs;
+    int			ret;
+
+    OPENLOCK(db, KRB5_DB_LOCKMODE_EXCLUSIVE);
+    
+    if(entry->name == NULL) {
+	 ret = EINVAL;
+	 goto error;
+    }
+    dbkey.data = entry->name;
+    dbkey.size = (strlen(entry->name) + 1);
+    switch(db->db->get(db->db, &dbkey, &tmpdb, 0)) {
+    case 0:
+	break;
+    case 1:
+	ret = OSA_ADB_NOENT;
+	goto error;
+    default:
+	ret = OSA_ADB_FAILURE;
+	goto error;
+    }
+    xdralloc_create(&xdrs, XDR_ENCODE);
+    if(!xdr_osa_policy_ent_rec(&xdrs, entry)) {
+	xdr_destroy(&xdrs);
+	ret = OSA_ADB_XDR_FAILURE;
+	goto error;
+    }
+    dbdata.data = xdralloc_getdata(&xdrs);
+    dbdata.size = xdr_getpos(&xdrs);
+    switch(db->db->put(db->db, &dbkey, &dbdata, 0)) {
+    case 0:
+	if((db->db->sync(db->db, 0)) == -1)
+	    ret = OSA_ADB_FAILURE;
+	ret = OSA_ADB_OK;
+	break;
+    default:
+	ret = OSA_ADB_FAILURE;
+	break;
+    }
+    xdr_destroy(&xdrs);
+
+error:
+    CLOSELOCK(db);
+    return ret;
+}
+
+/*
+ * Function: osa_adb_iter_policy
+ * 
+ * Purpose: iterate over the policy database.
+ *
+ * Arguments:
+ *	db		(input) db handle
+ *	func		(input) fucntion pointer to call
+ *	data		opaque data type
+ * 	<return value>	0 on success error code on failure
+ *
+ * Requires:
+ * Effects:
+ * Modifies:
+ */
+krb5_error_code
+osa_adb_iter_policy(osa_adb_policy_t db, osa_adb_iter_policy_func func,
+		    void *data)
+{
+    DBT			    dbkey,
+			    dbdata;
+    XDR			    xdrs;
+    int			    ret;
+    osa_policy_ent_t	    entry;
+    char		    *aligned_data;
+
+    OPENLOCK(db, KRB5_DB_LOCKMODE_EXCLUSIVE); /* hmmm */
+
+    if((ret = db->db->seq(db->db, &dbkey, &dbdata, R_FIRST)) == -1) {
+	 ret = errno;
+	 goto error;
+    }
+
+    while (ret == 0) {
+	if (!(entry = (osa_policy_ent_t) malloc(sizeof(osa_policy_ent_rec)))) {
+	     ret = ENOMEM;
+	     goto error;
+	}
+
+	if(!(aligned_data = (char *) malloc(dbdata.size))) {
+	     ret = ENOMEM;
+	     goto error;
+	}
+	memcpy(aligned_data, dbdata.data, dbdata.size);
+	
+	memset(entry, 0, sizeof(osa_policy_ent_rec));
+	xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE);
+	if(!xdr_osa_policy_ent_rec(&xdrs, entry)) {
+	    xdr_destroy(&xdrs);
+	    free(aligned_data);
+	    ret = OSA_ADB_FAILURE;
+	    goto error;
+	}
+	(*func)(data, entry);
+	xdr_destroy(&xdrs);
+	free(aligned_data);	
+	osa_free_policy_ent(entry);
+	ret = db->db->seq(db->db, &dbkey, &dbdata, R_NEXT);
+    }
+    if(ret == -1)
+	 ret = errno;
+    else ret = OSA_ADB_OK;
+
+error:
+    CLOSELOCK(db);
+    return ret;
+}
+
+void
+osa_free_policy_ent(osa_policy_ent_t val)
+{
+  XDR xdrs;
+
+  xdrmem_create(&xdrs, NULL, 0, XDR_FREE);
+
+  xdr_osa_policy_ent_rec(&xdrs, val);
+
+  free(val);
+}
diff --git a/mechglue/src/plugins/kdb/db2/configure.in b/mechglue/src/plugins/kdb/db2/configure.in
new file mode 100644
index 000000000..9f958db12
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/configure.in
@@ -0,0 +1,27 @@
+K5_AC_INIT(configure.in)
+enable_shared=yes
+build_dynobj=yes
+CONFIG_RULES
+AC_CHECK_HEADERS(unistd.h)
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+
+AC_CHECK_FUNCS(srand48 srand srandom umask)
+
+dnl AIX is unusual in that it wants all symbols resolved at link time
+dnl  Fortunately, it will allow us to link the kdb library now, even if
+dnl it is linked again later.
+case $krb5_cv_host in
+*-*-aix*)
+	LIBS="$LIBS -ldb"
+	;;
+esac
+KRB5_RUN_FLAGS
+dnl The following is for check...
+KRB5_BUILD_PROGRAM
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+if test "$DB_VERSION" = k5 ; then
+  AC_CONFIG_SUBDIRS(libdb2)
+fi
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/plugins/kdb/db2/db2.exports b/mechglue/src/plugins/kdb/db2/db2.exports
new file mode 100644
index 000000000..25320ff72
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/db2.exports
@@ -0,0 +1 @@
+krb5_db_vftabl_db2
diff --git a/mechglue/src/plugins/kdb/db2/db2_exp.c b/mechglue/src/plugins/kdb/db2/db2_exp.c
new file mode 100644
index 000000000..f119de3de
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/db2_exp.c
@@ -0,0 +1,64 @@
+/**********************************************************************
+*
+*	C %name:		db2_exp.c %
+*	Instance:		idc_sec_2
+*	Description:	
+*	%created_by:	spradeep %
+*	%date_created:	Tue Apr  5 11:44:00 2005 %
+*
+**********************************************************************/
+#ifndef lint
+static char *_csrc = "@(#) %filespec: db2_exp.c~5 %  (%full_filespec: db2_exp.c~5:csrc:idc_sec#2 %)";
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "k5-int.h"
+#include <db.h>
+#include <stdio.h>
+#include <errno.h>
+#include <utime.h>
+#include "kdb5.h"
+#include "kdb_db2.h"
+#include "kdb_xdr.h"
+#include "policy_db.h"
+
+/*
+ *      Exposed API
+ */
+
+kdb_vftabl krb5_db_vftabl_db2 = {
+  1,                                      /* major version number 1 */
+  0,                                      /* minor version number 0 */
+  0,                                      /* TBD. Not sure whether thread safe. For now, its not */
+  /* init_library */			       krb5_db2_lib_init,
+  /* fini_library */			       krb5_db2_lib_cleanup,
+  /* init_module */			       krb5_db2_open,
+  /* fini_module */			       krb5_db2_db_fini,
+  /* db_create */			       krb5_db2_create,
+  /* db_destroy */			       krb5_db2_destroy,
+  /* db_get_age */                             krb5_db2_db_get_age,
+  /* db_set_option */			       krb5_db2_db_set_option,
+  /* db_lock */				       krb5_db2_db_lock,
+  /* db_unlock */			       krb5_db2_db_unlock,
+  /* db_get_principal */		       krb5_db2_db_get_principal,
+  /* db_free_principal */		       krb5_db2_db_free_principal,
+  /* db_put_principal */		       krb5_db2_db_put_principal,
+  /* db_delete_principal */		       krb5_db2_db_delete_principal,
+  /* db_iterate */			       krb5_db2_db_iterate,
+  /* db_create_policy */                       krb5_db2_create_policy,
+  /* db_get_policy */                          krb5_db2_get_policy,
+  /* db_put_policy */                          krb5_db2_put_policy,
+  /* db_iter_policy */                         krb5_db2_iter_policy,
+  /* db_delete_policy */                       krb5_db2_delete_policy,
+  /* db_free_policy */                         krb5_db2_free_policy,
+  /* db_supported_realms */		       NULL,
+  /* db_free_supported_realms */	       NULL,
+  /* errcode_2_string */                       NULL,
+  /* db_alloc */                               krb5_db2_alloc,
+  /* db_free */                                krb5_db2_free,
+  /* set_master_key */			       krb5_db2_set_master_key_ext,
+  /* get_master_key */			       krb5_db2_db_get_mkey
+};
diff --git a/mechglue/src/plugins/kdb/db2/kdb_compat.h b/mechglue/src/plugins/kdb/db2/kdb_compat.h
new file mode 100644
index 000000000..540d4a249
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/kdb_compat.h
@@ -0,0 +1,81 @@
+/*
+ * lib/kdb/kdb_compat.h
+ *
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * KDC Database interface definitions.
+ */
+
+
+typedef struct _old_krb5_encrypted_keyblock {
+    krb5_enctype enctype;
+    int length;
+    krb5_octet *contents;
+} old_krb5_encrypted_keyblock;
+
+typedef struct old_krb5_principal_data {
+    krb5_magic magic;
+    krb5_data realm;
+    krb5_data *data;		/* An array of strings */
+    krb5_int32 length;
+    krb5_int32 type;
+} old_krb5_principal_data;
+
+typedef	old_krb5_principal_data *old_krb5_principal;
+
+
+/*
+ * Note --- this structure cannot be modified without changing the
+ * database version number in libkdb.a
+ */
+typedef struct _old_krb5_db_entry {
+    old_krb5_principal principal;
+    old_krb5_encrypted_keyblock key;
+    krb5_kvno kvno;
+    krb5_deltat	max_life;
+    krb5_deltat	max_renewable_life;
+    krb5_kvno mkvno;			/* master encryption key vno */
+    
+    krb5_timestamp expiration;		/* This is when the client expires */
+    krb5_timestamp pw_expiration; 	/* This is when its password does */
+    krb5_timestamp last_pwd_change; 	/* Last time of password change  */
+    krb5_timestamp last_success;	/* Last successful password */
+    
+    krb5_timestamp last_failed;		/* Last failed password attempt */
+    krb5_kvno fail_auth_count; 		/* # of failed password attempts */
+    
+    old_krb5_principal mod_name;
+    krb5_timestamp mod_date;
+    krb5_flags attributes;
+    krb5_int32 salt_type:8,
+ 	       salt_length:24;
+    krb5_octet *salt;
+    old_krb5_encrypted_keyblock alt_key;
+    krb5_int32 alt_salt_type:8,
+ 	       alt_salt_length:24;
+    krb5_octet *alt_salt;
+    
+    krb5_int32 expansion[8];
+} old_krb5_db_entry;
+
diff --git a/mechglue/src/plugins/kdb/db2/kdb_db2.c b/mechglue/src/plugins/kdb/db2/kdb_db2.c
new file mode 100644
index 000000000..f3950eecc
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/kdb_db2.c
@@ -0,0 +1,1561 @@
+/*
+ * lib/kdb/kdb_db2.c
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "k5-int.h"
+#include <db.h>
+#include <stdio.h>
+#include <errno.h>
+#include <utime.h>
+#include "kdb5.h"
+#include "kdb_db2.h"
+#include "kdb_xdr.h"
+#include "policy_db.h"
+
+#define KDB_DB2_DATABASE_NAME "database_name"
+
+#define OLD_COMPAT_VERSION_1
+
+#ifdef OLD_COMPAT_VERSION_1
+#include "kdb_compat.h"
+#endif
+
+#include "kdb_db2.h"
+
+static char *gen_dbsuffix(char *, char *);
+
+static krb5_error_code krb5_db2_db_start_update(krb5_context);
+static krb5_error_code krb5_db2_db_end_update(krb5_context);
+
+krb5_error_code krb5_db2_db_set_name(krb5_context, char *);
+
+krb5_error_code krb5_db2_db_lock(krb5_context, int);
+
+static krb5_error_code krb5_db2_db_set_hashfirst(krb5_context, int);
+
+static char default_db_name[] = DEFAULT_KDB_FILE;
+krb5_set_err_func_t krb5_db2_dal_err_funcp = NULL;
+
+/*
+ * Locking:
+ *
+ * There are two distinct locking protocols used.  One is designed to
+ * lock against processes (the admin_server, for one) which make
+ * incremental changes to the database; the other is designed to lock
+ * against utilities (kdb5_edit, kpropd, kdb5_convert) which replace the
+ * entire database in one fell swoop.
+ *
+ * The first locking protocol is implemented using flock() in the
+ * krb_dbl_lock() and krb_dbl_unlock routines.
+ *
+ * The second locking protocol is necessary because DBM "files" are
+ * actually implemented as two separate files, and it is impossible to
+ * atomically rename two files simultaneously.  It assumes that the
+ * database is replaced only very infrequently in comparison to the time
+ * needed to do a database read operation.
+ *
+ * A third file is used as a "version" semaphore; the modification
+ * time of this file is the "version number" of the database.
+ * At the start of a read operation, the reader checks the version
+ * number; at the end of the read operation, it checks again.  If the
+ * version number changed, or if the semaphore was nonexistant at
+ * either time, the reader sleeps for a second to let things
+ * stabilize, and then tries again; if it does not succeed after
+ * KRB5_DBM_MAX_RETRY attempts, it gives up.
+ *
+ * On update, the semaphore file is deleted (if it exists) before any
+ * update takes place; at the end of the update, it is replaced, with
+ * a version number strictly greater than the version number which
+ * existed at the start of the update.
+ *
+ * If the system crashes in the middle of an update, the semaphore
+ * file is not automatically created on reboot; this is a feature, not
+ * a bug, since the database may be inconsistant.  Note that the
+ * absence of a semaphore file does not prevent another _update_ from
+ * taking place later.  Database replacements take place automatically
+ * only on slave servers; a crash in the middle of an update will be
+ * fixed by the next slave propagation.  A crash in the middle of an
+ * update on the master would be somewhat more serious, but this would
+ * likely be noticed by an administrator, who could fix the problem and
+ * retry the operation.
+ */
+
+#define free_dbsuffix(name) free(name)
+
+/*
+ * Routines to deal with context.
+ */
+#define	k5db2_inited(c)	(c && c->db_context \
+			 && ((kdb5_dal_handle*)c->db_context)->db_context \
+                         && ((krb5_db2_context *) ((kdb5_dal_handle*)c->db_context)->db_context)->db_inited)
+
+static krb5_error_code
+krb5_db2_get_db_opt(char *input, char **opt, char **val)
+{
+    char   *pos = strchr(input, '=');
+    if (pos == NULL) {
+	*opt = NULL;
+	*val = strdup(input);
+	if (*val == NULL) {
+	    return ENOMEM;
+	}
+    } else {
+	*opt = malloc((pos - input) + 1);
+	*val = strdup(pos + 1);
+	if (!*opt || !*val) {
+	    return ENOMEM;
+	}
+	memcpy(*opt, input, pos - input);
+	(*opt)[pos - input] = '\0';
+    }
+    return (0);
+
+}
+
+/*
+ * Restore the default context.
+ */
+static void
+k5db2_clear_context(krb5_db2_context *dbctx)
+{
+    /*
+     * Free any dynamically allocated memory.  File descriptors and locks
+     * are the caller's problem.
+     */
+    if (dbctx->db_lf_name)
+	free(dbctx->db_lf_name);
+    if (dbctx->db_name && (dbctx->db_name != default_db_name))
+	free(dbctx->db_name);
+    /*
+     * Clear the structure and reset the defaults.
+     */
+    memset((char *) dbctx, 0, sizeof(krb5_db2_context));
+    dbctx->db_name = default_db_name;
+    dbctx->db_nb_locks = FALSE;
+}
+
+static krb5_error_code
+k5db2_init_context(krb5_context context)
+{
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+
+    if (dal_handle->db_context == NULL) {
+	db_ctx = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
+	if (db_ctx == NULL)
+	    return ENOMEM;
+	else {
+	    memset((char *) db_ctx, 0, sizeof(krb5_db2_context));
+	    k5db2_clear_context((krb5_db2_context *) db_ctx);
+	    dal_handle->db_context = (void *) db_ctx;
+	}
+    }
+    return (0);
+}
+
+/*
+ * Utility routine: generate name of database file.
+ */
+
+static char *
+gen_dbsuffix(char *db_name, char *sfx)
+{
+    char   *dbsuffix;
+
+    if (sfx == NULL)
+	return ((char *) NULL);
+
+    dbsuffix = malloc(strlen(db_name) + strlen(sfx) + 1);
+    if (!dbsuffix)
+	return (0);
+    (void) strcpy(dbsuffix, db_name);
+    (void) strcat(dbsuffix, sfx);
+    return dbsuffix;
+}
+
+static DB *
+k5db2_dbopen(krb5_db2_context *dbc, char *fname, int flags, int mode)
+{
+    DB     *db;
+    BTREEINFO bti;
+    HASHINFO hashi;
+
+    bti.flags = 0;
+    bti.cachesize = 0;
+    bti.psize = 4096;
+    bti.lorder = 0;
+    bti.minkeypage = 0;
+    bti.compare = NULL;
+    bti.prefix = NULL;
+
+    hashi.bsize = 4096;
+    hashi.cachesize = 0;
+    hashi.ffactor = 40;
+    hashi.hash = NULL;
+    hashi.lorder = 0;
+    hashi.nelem = 1;
+
+    db = dbopen(fname, flags, mode,
+		dbc->hashfirst ? DB_HASH : DB_BTREE,
+		dbc->hashfirst ? (void *) &hashi : (void *) &bti);
+    if (db != NULL)
+	return db;
+    switch (errno) {
+#ifdef EFTYPE
+    case EFTYPE:
+#endif
+    case EINVAL:
+	db = dbopen(fname, flags, mode,
+		    dbc->hashfirst ? DB_BTREE : DB_HASH,
+		    dbc->hashfirst ? (void *) &bti : (void *) &hashi);
+	if (db != NULL)
+	    dbc->hashfirst = !dbc->hashfirst;
+    default:
+	return db;
+    }
+}
+
+static krb5_error_code
+krb5_db2_db_set_hashfirst(krb5_context context, int hashfirst)
+{
+    krb5_db2_context *dbc;
+    kdb5_dal_handle *dal_handle;
+
+    if (k5db2_inited(context))
+	return KRB5_KDB_DBNOTINITED;
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    dbc = (krb5_db2_context *) dal_handle->db_context;
+    dbc->hashfirst = hashfirst;
+    return 0;
+}
+
+/*
+ * initialization for data base routines.
+ */
+
+krb5_error_code
+krb5_db2_db_init(krb5_context context)
+{
+    char   *filename = NULL;
+    krb5_db2_context *db_ctx;
+    krb5_error_code retval;
+    kdb5_dal_handle *dal_handle;
+    char    policy_db_name[1024], policy_lock_name[1024];
+
+    if (k5db2_inited(context))
+	return 0;
+
+    /* Check for presence of our context, if not present, allocate one. */
+    if ((retval = k5db2_init_context(context)))
+	return (retval);
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = dal_handle->db_context;
+    db_ctx->db = NULL;
+
+    if (!(filename = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT)))
+	return ENOMEM;
+    db_ctx->db_lf_name = filename;	/* so it gets freed by clear_context */
+
+    /*
+     * should be opened read/write so that write locking can work with
+     * POSIX systems
+     */
+    if ((db_ctx->db_lf_file = open(filename, O_RDWR, 0666)) < 0) {
+	if ((db_ctx->db_lf_file = open(filename, O_RDONLY, 0666)) < 0) {
+	    retval = errno;
+	    goto err_out;
+	}
+    }
+    db_ctx->db_inited++;
+
+    if ((retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time)))
+	goto err_out;
+
+    sprintf(policy_db_name, "%s.kadm5", db_ctx->db_name);
+    sprintf(policy_lock_name, "%s.lock", policy_db_name);
+
+    if ((retval = osa_adb_init_db(&db_ctx->policy_db, policy_db_name,
+				  policy_lock_name, OSA_ADB_POLICY_DB_MAGIC)))
+    {
+	goto err_out;
+    }
+    return 0;
+
+  err_out:
+    db_ctx->db = NULL;
+    k5db2_clear_context(db_ctx);
+    return (retval);
+}
+
+/*
+ * gracefully shut down database--must be called by ANY program that does
+ * a krb5_db2_db_init
+ */
+krb5_error_code
+krb5_db2_db_fini(krb5_context context)
+{
+    krb5_error_code retval = 0;
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    if (dal_handle == NULL) {
+	return 0;
+    }
+
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+
+    if (k5db2_inited(context)) {
+	if (close(db_ctx->db_lf_file))
+	    retval = errno;
+	else
+	    retval = 0;
+    }
+    if (db_ctx) {
+	if (db_ctx->policy_db) {
+	    retval =
+		osa_adb_fini_db(db_ctx->policy_db, OSA_ADB_POLICY_DB_MAGIC);
+	    if (retval)
+		return retval;
+	}
+
+	k5db2_clear_context(db_ctx);
+	/*      free(dal_handle->db_context); */
+	dal_handle->db_context = NULL;
+    }
+    return retval;
+}
+
+/*
+ * Set/Get the master key associated with the database
+ */
+krb5_error_code
+krb5_db2_db_set_mkey(krb5_context context, krb5_keyblock *key)
+{
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+
+    if (!k5db2_inited(context))
+	return (KRB5_KDB_DBNOTINITED);
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = dal_handle->db_context;
+    db_ctx->db_master_key = key;
+    return 0;
+}
+
+krb5_error_code
+krb5_db2_db_get_mkey(krb5_context context, krb5_keyblock **key)
+{
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+
+    if (!k5db2_inited(context))
+	return (KRB5_KDB_DBNOTINITED);
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = dal_handle->db_context;
+    *key = db_ctx->db_master_key;
+
+    return 0;
+}
+
+/*
+ * Set the "name" of the current database to some alternate value.
+ *
+ * Passing a null pointer as "name" will set back to the default.
+ * If the alternate database doesn't exist, nothing is changed.
+ *
+ * XXX rethink this
+ */
+
+krb5_error_code
+krb5_db2_db_set_name(krb5_context context, char *name)
+{
+    DB     *db;
+    krb5_db2_context *db_ctx;
+    krb5_error_code kret;
+    kdb5_dal_handle *dal_handle;
+
+    if (k5db2_inited(context))
+	return KRB5_KDB_DBINITED;
+
+    /* Check for presence of our context, if not present, allocate one. */
+    if ((kret = k5db2_init_context(context)))
+	return (kret);
+
+    if (name == NULL)
+	name = default_db_name;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = dal_handle->db_context;
+    db = k5db2_dbopen(db_ctx, name, O_RDONLY, 0);
+    if (db == NULL)
+	return errno;
+
+    db_ctx->db_name = strdup(name);
+    (*db->close) (db);
+    return 0;
+}
+
+/*
+ * Return the last modification time of the database.
+ *
+ * Think about using fstat.
+ */
+
+krb5_error_code
+krb5_db2_db_get_age(krb5_context context, char *db_name, time_t *age)
+{
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+    struct stat st;
+
+    if (!k5db2_inited(context))
+	return (KRB5_KDB_DBNOTINITED);
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+
+    if (fstat(db_ctx->db_lf_file, &st) < 0)
+	*age = -1;
+    else
+	*age = st.st_mtime;
+    return 0;
+}
+
+/*
+ * Remove the semaphore file; indicates that database is currently
+ * under renovation.
+ *
+ * This is only for use when moving the database out from underneath
+ * the server (for example, during slave updates).
+ */
+
+static krb5_error_code
+krb5_db2_db_start_update(krb5_context context)
+{
+    return 0;
+}
+
+static krb5_error_code
+krb5_db2_db_end_update(krb5_context context)
+{
+    krb5_error_code retval;
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+    struct stat st;
+    time_t  now;
+    struct utimbuf utbuf;
+
+    if (!k5db2_inited(context))
+	return (KRB5_KDB_DBNOTINITED);
+
+    retval = 0;
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = dal_handle->db_context;
+    now = time((time_t *) NULL);
+    if (fstat(db_ctx->db_lf_file, &st) == 0) {
+	if (st.st_mtime >= now) {
+	    utbuf.actime = st.st_mtime + 1;
+	    utbuf.modtime = st.st_mtime + 1;
+	    if (utime(db_ctx->db_lf_name, &utbuf))
+		retval = errno;
+	} else {
+	    if (utime(db_ctx->db_lf_name, (struct utimbuf *) NULL))
+		retval = errno;
+	}
+    } else
+	retval = errno;
+    if (!retval) {
+	if (fstat(db_ctx->db_lf_file, &st) == 0)
+	    db_ctx->db_lf_time = st.st_mtime;
+	else
+	    retval = errno;
+    }
+    return (retval);
+}
+
+#define MAX_LOCK_TRIES 5
+
+krb5_error_code
+krb5_db2_db_lock(krb5_context context, int in_mode)
+{
+    krb5_db2_context *db_ctx;
+    int     krb5_lock_mode;
+    DB     *db;
+    krb5_error_code retval;
+    time_t  mod_time;
+    kdb5_dal_handle *dal_handle;
+    int     mode, gotlock, tries;
+
+    switch (in_mode) {
+    case KRB5_DB_LOCKMODE_PERMANENT:
+	mode = KRB5_DB_LOCKMODE_EXCLUSIVE;
+	break;
+    case KRB5_DB_LOCKMODE_EXCLUSIVE:
+	mode = KRB5_LOCKMODE_EXCLUSIVE;
+	break;
+
+    case KRB5_DB_LOCKMODE_SHARED:
+	mode = KRB5_LOCKMODE_SHARED;
+	break;
+    default:
+	return EINVAL;
+    }
+
+    if (!k5db2_inited(context))
+	return KRB5_KDB_DBNOTINITED;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+    if (db_ctx->db_locks_held && (db_ctx->db_lock_mode >= mode)) {
+	/* No need to upgrade lock, just return */
+	db_ctx->db_locks_held++;
+	goto policy_lock;
+    }
+
+    if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE))
+	return KRB5_KDB_BADLOCKMODE;
+
+    krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK;
+    for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
+	retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode);
+	if (retval == 0) {
+	    gotlock++;
+	    break;
+	} else if (retval == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
+	    /* tried to exclusive-lock something we don't have */
+	    /* write access to */
+	    return KRB5_KDB_CANTLOCK_DB;
+	sleep(1);
+    }
+    if (retval == EACCES)
+	return KRB5_KDB_CANTLOCK_DB;
+    else if (retval == EAGAIN || retval == EWOULDBLOCK)
+	return OSA_ADB_CANTLOCK_DB;
+    else if (retval != 0)
+	return retval;
+
+    if ((retval = krb5_db2_db_get_age(context, NULL, &mod_time)))
+	goto lock_error;
+
+    db = k5db2_dbopen(db_ctx, db_ctx->db_name,
+		      mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR, 0600);
+    if (db) {
+	db_ctx->db_lf_time = mod_time;
+	db_ctx->db = db;
+    } else {
+	retval = errno;
+	db_ctx->db = NULL;
+	goto lock_error;
+    }
+
+    db_ctx->db_lock_mode = mode;
+    db_ctx->db_locks_held++;
+
+  policy_lock:
+    if ((retval = osa_adb_get_lock(db_ctx->policy_db, in_mode))) {
+	krb5_db2_db_unlock(context);
+    }
+    return retval;
+
+  lock_error:;
+    db_ctx->db_lock_mode = 0;
+    db_ctx->db_locks_held = 0;
+    krb5_db2_db_unlock(context);
+    return retval;
+}
+
+krb5_error_code
+krb5_db2_db_unlock(krb5_context context)
+{
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+    DB     *db;
+    krb5_error_code retval;
+
+    if (!k5db2_inited(context))
+	return KRB5_KDB_DBNOTINITED;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+
+    if ((retval = osa_adb_release_lock(db_ctx->policy_db))) {
+	return retval;
+    }
+
+    if (!db_ctx->db_locks_held)	/* lock already unlocked */
+	return KRB5_KDB_NOTLOCKED;
+    db = db_ctx->db;
+    if (--(db_ctx->db_locks_held) == 0) {
+	(*db->close) (db);
+	db_ctx->db = NULL;
+
+	retval = krb5_lock_file(context, db_ctx->db_lf_file,
+				KRB5_LOCKMODE_UNLOCK);
+	db_ctx->db_lock_mode = 0;
+	return (retval);
+    }
+    return 0;
+}
+
+/*
+ * Create the database, assuming it's not there.
+ */
+krb5_error_code
+krb5_db2_db_create(krb5_context context, char *db_name, krb5_int32 flags)
+{
+    register krb5_error_code retval = 0;
+    kdb5_dal_handle *dal_handle;
+    char   *okname;
+    int     fd;
+    krb5_db2_context *db_ctx;
+    DB     *db;
+    char    policy_db_name[1024], policy_lock_name[1024];
+
+    if ((retval = k5db2_init_context(context)))
+	return (retval);
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+    switch (flags) {
+    case KRB5_KDB_CREATE_HASH:
+	if ((retval = krb5_db2_db_set_hashfirst(context, TRUE)))
+	    return retval;
+	break;
+    case KRB5_KDB_CREATE_BTREE:
+    case 0:
+	if ((retval = krb5_db2_db_set_hashfirst(context, FALSE)))
+	    return retval;
+	break;
+    default:
+	return KRB5_KDB_BAD_CREATEFLAGS;
+    }
+    db = k5db2_dbopen(db_ctx, db_name, O_RDWR | O_CREAT | O_EXCL, 0600);
+    if (db == NULL)
+	retval = errno;
+    else
+	(*db->close) (db);
+    if (retval == 0) {
+	okname = gen_dbsuffix(db_name, KDB2_LOCK_EXT);
+	if (!okname)
+	    retval = ENOMEM;
+	else {
+	    fd = open(okname, O_CREAT | O_RDWR | O_TRUNC, 0600);
+	    if (fd < 0)
+		retval = errno;
+	    else
+		close(fd);
+	    free_dbsuffix(okname);
+	}
+    }
+
+    sprintf(policy_db_name, "%s.kadm5", db_name);
+    sprintf(policy_lock_name, "%s.lock", policy_db_name);
+
+    retval = osa_adb_create_db(policy_db_name,
+			       policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
+
+    return retval;
+}
+
+/*
+ * Destroy the database.  Zero's out all of the files, just to be sure.
+ */
+static krb5_error_code
+destroy_file_suffix(char *dbname, char *suffix)
+{
+    char   *filename;
+    struct stat statb;
+    int     nb, fd;
+    unsigned int j;
+    off_t   pos;
+    char    buf[BUFSIZ];
+    char    zbuf[BUFSIZ];
+    int     dowrite;
+
+    filename = gen_dbsuffix(dbname, suffix);
+    if (filename == 0)
+	return ENOMEM;
+    if ((fd = open(filename, O_RDWR, 0)) < 0) {
+	free(filename);
+	return errno;
+    }
+    /* fstat() will probably not fail unless using a remote filesystem
+     * (which is inappropriate for the kerberos database) so this check
+     * is mostly paranoia.  */
+    if (fstat(fd, &statb) == -1) {
+	int     retval = errno;
+	free(filename);
+	return retval;
+    }
+    /*
+     * Stroll through the file, reading in BUFSIZ chunks.  If everything
+     * is zero, then we're done for that block, otherwise, zero the block.
+     * We would like to just blast through everything, but some DB
+     * implementations make holey files and writing data to the holes
+     * causes actual blocks to be allocated which is no good, since
+     * we're just about to unlink it anyways.
+     */
+    memset(zbuf, 0, BUFSIZ);
+    pos = 0;
+    while (pos < statb.st_size) {
+	dowrite = 0;
+	nb = read(fd, buf, BUFSIZ);
+	if (nb < 0) {
+	    int     retval = errno;
+	    free(filename);
+	    return retval;
+	}
+	for (j = 0; j < nb; j++) {
+	    if (buf[j] != '\0') {
+		dowrite = 1;
+		break;
+	    }
+	}
+	/* For signedness */
+	j = nb;
+	if (dowrite) {
+	    lseek(fd, pos, SEEK_SET);
+	    nb = write(fd, zbuf, j);
+	    if (nb < 0) {
+		int     retval = errno;
+		free(filename);
+		return retval;
+	    }
+	}
+	pos += nb;
+    }
+    /* ??? Is fsync really needed?  I don't know of any non-networked
+     * filesystem which will discard queued writes to disk if a file
+     * is deleted after it is closed.  --jfc */
+#ifndef NOFSYNC
+    fsync(fd);
+#endif
+    close(fd);
+
+    if (unlink(filename)) {
+	free(filename);
+	return (errno);
+    }
+    free(filename);
+    return (0);
+}
+
+/*
+ * Since the destroy operation happens outside the init/fini bracket, we
+ * have some tomfoolery to undergo here.  If we're operating under no
+ * database context, then we initialize with the default.  If the caller
+ * wishes a different context (e.g. different dispatch table), it's their
+ * responsibility to call kdb5_db_set_dbops() before this call.  That will
+ * set up the right dispatch table values (e.g. name extensions).
+ *
+ * Not quite valid due to ripping out of dbops...
+ */
+krb5_error_code
+krb5_db2_db_destroy(krb5_context context, char *dbname)
+{
+    krb5_error_code retval1, retval2;
+    krb5_boolean tmpcontext;
+    char    policy_db_name[1024], policy_lock_name[1024];
+
+    tmpcontext = 0;
+    if (!context->db_context
+	|| !((kdb5_dal_handle *) context->db_context)->db_context) {
+	tmpcontext = 1;
+	if ((retval1 = k5db2_init_context(context)))
+	    return (retval1);
+    }
+
+    retval1 = retval2 = 0;
+    retval1 = destroy_file_suffix(dbname, "");
+    retval2 = destroy_file_suffix(dbname, KDB2_LOCK_EXT);
+
+    if (tmpcontext) {
+	k5db2_clear_context((krb5_db2_context *) ((kdb5_dal_handle *) context->
+						  db_context)->db_context);
+	free(((kdb5_dal_handle *) context->db_context)->db_context);
+	((kdb5_dal_handle *) context->db_context)->db_context = NULL;
+    }
+
+    if (retval1 || retval2)
+	return (retval1 ? retval1 : retval2);
+
+    sprintf(policy_db_name, "%s.kadm5", dbname);
+    sprintf(policy_lock_name, "%s.lock", policy_db_name);
+
+    retval1 = osa_adb_destroy_db(policy_db_name,
+				 policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
+
+    return retval1;
+}
+
+/*
+ * look up a principal in the data base.
+ * returns number of entries found, and whether there were
+ * more than requested.
+ */
+
+krb5_error_code
+krb5_db2_db_get_principal(krb5_context context,
+			  krb5_const_principal searchfor,
+			  krb5_db_entry *entries, /* filled in */
+			  int *nentries, /* how much room/how many found */
+			  krb5_boolean *more) /* are there more? */
+{
+    krb5_db2_context *db_ctx;
+    krb5_error_code retval;
+    DB     *db;
+    DBT     key, contents;
+    krb5_data keydata, contdata;
+    int     trynum, dbret;
+    kdb5_dal_handle *dal_handle;
+
+    *more = FALSE;
+    *nentries = 0;
+
+    if (!k5db2_inited(context))
+	return KRB5_KDB_DBNOTINITED;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+
+    for (trynum = 0; trynum < KRB5_DB2_MAX_RETRY; trynum++) {
+	if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED))) {
+	    if (db_ctx->db_nb_locks)
+		return (retval);
+	    sleep(1);
+	    continue;
+	}
+	break;
+    }
+    if (trynum == KRB5_DB2_MAX_RETRY)
+	return KRB5_KDB_DB_INUSE;
+
+    /* XXX deal with wildcard lookups */
+    retval = krb5_encode_princ_dbkey(context, &keydata, searchfor);
+    if (retval)
+	goto cleanup;
+    key.data = keydata.data;
+    key.size = keydata.length;
+
+    db = db_ctx->db;
+    dbret = (*db->get) (db, &key, &contents, 0);
+    retval = errno;
+    krb5_free_data_contents(context, &keydata);
+    switch (dbret) {
+    case 1:
+	retval = 0;
+    case -1:
+    default:
+	*nentries = 0;
+	goto cleanup;
+    case 0:
+	contdata.data = contents.data;
+	contdata.length = contents.size;
+	retval = krb5_decode_princ_contents(context, &contdata, entries);
+	if (!retval)
+	    *nentries = 1;
+	break;
+    }
+
+  cleanup:
+    (void) krb5_db2_db_unlock(context);	/* unlock read lock */
+    return retval;
+}
+
+/*
+  Free stuff returned by krb5_db2_db_get_principal.
+ */
+krb5_error_code
+krb5_db2_db_free_principal(krb5_context context, krb5_db_entry *entries,
+			   int nentries)
+{
+    register int i;
+    for (i = 0; i < nentries; i++)
+	krb5_dbe_free_contents(context, &entries[i]);
+    return 0;
+}
+
+/*
+  Stores the *"nentries" entry structures pointed to by "entries" in the
+  database.
+
+  *"nentries" is updated upon return to reflect the number of records
+  acutally stored; the first *"nstored" records will have been stored in the
+  database (even if an error occurs).
+
+ */
+
+krb5_error_code
+krb5_db2_db_put_principal(krb5_context context,
+			  krb5_db_entry *entries,
+			  int *nentries, /* number of entry structs to update */
+			  char **db_args)
+{
+    int     i, n, dbret;
+    DB     *db;
+    DBT     key, contents;
+    krb5_data contdata, keydata;
+    krb5_error_code retval;
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+
+    if (db_args) {
+	/* DB2 does not support db_args DB arguments for principal */
+	char    buf[KRB5_MAX_ERR_STR];
+	sprintf(buf, "Unsupported argument \"%s\" for db2", db_args[0]);
+	krb5_db2_dal_err_funcp(context, krb5_err_have_str, EINVAL, buf);
+	return EINVAL;
+    }
+
+    n = *nentries;
+    *nentries = 0;
+    if (!k5db2_inited(context))
+	return KRB5_KDB_DBNOTINITED;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+    if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+	return retval;
+
+    db = db_ctx->db;
+    if ((retval = krb5_db2_db_start_update(context))) {
+	(void) krb5_db2_db_unlock(context);
+	return retval;
+    }
+
+    /* for each one, stuff temps, and do replace/append */
+    for (i = 0; i < n; i++) {
+	retval = krb5_encode_princ_contents(context, &contdata, entries);
+	if (retval)
+	    break;
+	contents.data = contdata.data;
+	contents.size = contdata.length;
+	retval = krb5_encode_princ_dbkey(context, &keydata, entries->princ);
+	if (retval) {
+	    krb5_free_data_contents(context, &contdata);
+	    break;
+	}
+
+	key.data = keydata.data;
+	key.size = keydata.length;
+	dbret = (*db->put) (db, &key, &contents, 0);
+	retval = dbret ? errno : 0;
+	krb5_free_data_contents(context, &keydata);
+	krb5_free_data_contents(context, &contdata);
+	if (retval)
+	    break;
+	entries++;		/* bump to next struct */
+    }
+
+    (void) krb5_db2_db_end_update(context);
+    (void) krb5_db2_db_unlock(context);	/* unlock database */
+    *nentries = i;
+    return (retval);
+}
+
+/*
+ * delete a principal from the data base.
+ * returns number of entries removed
+ */
+
+krb5_error_code
+krb5_db2_db_delete_principal(krb5_context context,
+			     krb5_const_principal searchfor,
+			     int *nentries) /* how many found & deleted */
+{
+    krb5_error_code retval;
+    krb5_db_entry entry;
+    krb5_db2_context *db_ctx;
+    DB     *db;
+    DBT     key, contents;
+    krb5_data keydata, contdata;
+    int     i, dbret;
+    kdb5_dal_handle *dal_handle;
+
+    if (!k5db2_inited(context))
+	return KRB5_KDB_DBNOTINITED;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+    if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+	return (retval);
+
+    if ((retval = krb5_db2_db_start_update(context))) {
+	(void) krb5_db2_db_unlock(context);	/* unlock write lock */
+	return (retval);
+    }
+
+    if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor)))
+	goto cleanup;
+    key.data = keydata.data;
+    key.size = keydata.length;
+
+    db = db_ctx->db;
+    dbret = (*db->get) (db, &key, &contents, 0);
+    retval = errno;
+    switch (dbret) {
+    case 1:
+	retval = KRB5_KDB_NOENTRY;
+    case -1:
+    default:
+	*nentries = 0;
+	goto cleankey;
+    case 0:
+	;
+    }
+    memset((char *) &entry, 0, sizeof(entry));
+    contdata.data = contents.data;
+    contdata.length = contents.size;
+    retval = krb5_decode_princ_contents(context, &contdata, &entry);
+    if (retval)
+	goto cleankey;
+    *nentries = 1;
+
+    /* Clear encrypted key contents */
+    for (i = 0; i < entry.n_key_data; i++) {
+	if (entry.key_data[i].key_data_length[0]) {
+	    memset((char *) entry.key_data[i].key_data_contents[0], 0,
+		   (unsigned) entry.key_data[i].key_data_length[0]);
+	}
+    }
+
+    retval = krb5_encode_princ_contents(context, &contdata, &entry);
+    krb5_dbe_free_contents(context, &entry);
+    if (retval)
+	goto cleankey;
+
+    contents.data = contdata.data;
+    contents.size = contdata.length;
+    dbret = (*db->put) (db, &key, &contents, 0);
+    retval = dbret ? errno : 0;
+    krb5_free_data_contents(context, &contdata);
+    if (retval)
+	goto cleankey;
+    dbret = (*db->del) (db, &key, 0);
+    retval = dbret ? errno : 0;
+  cleankey:
+    krb5_free_data_contents(context, &keydata);
+
+  cleanup:
+    (void) krb5_db2_db_end_update(context);
+    (void) krb5_db2_db_unlock(context);	/* unlock write lock */
+    return retval;
+}
+
+krb5_error_code
+krb5_db2_db_iterate_ext(krb5_context context,
+			krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
+			krb5_pointer func_arg,
+			int backwards, int recursive)
+{
+    krb5_db2_context *db_ctx;
+    DB     *db;
+    DBT     key, contents;
+    krb5_data contdata;
+    krb5_db_entry entries;
+    krb5_error_code retval;
+    kdb5_dal_handle *dal_handle;
+    int     dbret;
+    void   *cookie;
+
+    cookie = NULL;
+    if (!k5db2_inited(context))
+	return KRB5_KDB_DBNOTINITED;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    db_ctx = (krb5_db2_context *) dal_handle->db_context;
+    retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED);
+
+    if (retval)
+	return retval;
+
+    db = db_ctx->db;
+    if (recursive && db->type != DB_BTREE) {
+	(void) krb5_db2_db_unlock(context);
+	return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
+    }
+
+    if (!recursive) {
+	dbret = (*db->seq) (db, &key, &contents, backwards ? R_LAST : R_FIRST);
+    } else {
+#ifdef HAVE_BT_RSEQ
+	dbret = bt_rseq(db, &key, &contents, &cookie,
+			backwards ? R_LAST : R_FIRST);
+#else
+	(void) krb5_db2_db_unlock(context);
+	return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
+#endif
+    }
+    while (dbret == 0) {
+	contdata.data = contents.data;
+	contdata.length = contents.size;
+	retval = krb5_decode_princ_contents(context, &contdata, &entries);
+	if (retval)
+	    break;
+	retval = (*func) (func_arg, &entries);
+	krb5_dbe_free_contents(context, &entries);
+	if (retval)
+	    break;
+	if (!recursive) {
+	    dbret = (*db->seq) (db, &key, &contents,
+				backwards ? R_PREV : R_NEXT);
+	} else {
+#ifdef HAVE_BT_RSEQ
+	    dbret = bt_rseq(db, &key, &contents, &cookie,
+			    backwards ? R_PREV : R_NEXT);
+#else
+	    (void) krb5_db2_db_unlock(context);
+	    return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
+#endif
+	}
+    }
+    switch (dbret) {
+    case 1:
+    case 0:
+	break;
+    case -1:
+    default:
+	retval = errno;
+    }
+    (void) krb5_db2_db_unlock(context);
+    return retval;
+}
+
+krb5_error_code
+krb5_db2_db_iterate(krb5_context context,
+		    char *match_expr,
+		    krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
+		    krb5_pointer func_arg)
+{
+    return krb5_db2_db_iterate_ext(context, func, func_arg, 0, 0);
+}
+
+krb5_boolean
+krb5_db2_db_set_lockmode(krb5_context context, krb5_boolean mode)
+{
+    krb5_boolean old;
+    krb5_db2_context *db_ctx;
+    kdb5_dal_handle *dal_handle;
+
+    dal_handle = (kdb5_dal_handle *) context->db_context;
+    old = mode;
+    if (dal_handle && (db_ctx = (krb5_db2_context *) dal_handle->db_context)) {
+	old = db_ctx->db_nb_locks;
+	db_ctx->db_nb_locks = mode;
+    }
+    return old;
+}
+
+/*
+ *     DAL API functions
+ */
+krb5_error_code
+krb5_db2_lib_init(krb5_set_err_func_t set_err)
+{
+    krb5_db2_dal_err_funcp = set_err;
+    return 0;
+}
+
+krb5_error_code
+krb5_db2_lib_cleanup()
+{
+    /* right now, no cleanup required */
+    return 0;
+}
+
+krb5_error_code
+krb5_db2_open(krb5_context kcontext,
+	      char *conf_section, char **db_args, int mode)
+{
+    krb5_error_code status = 0;
+    char  **t_ptr = db_args;
+    char    db_name_set = 0;
+
+    if (k5db2_inited(kcontext))
+	return 0;
+
+    while (t_ptr && *t_ptr) {
+	char   *opt = NULL, *val = NULL;
+
+	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
+	if (opt && !strcmp(opt, "dbname")) {
+	    status = krb5_db2_db_set_name(kcontext, val);
+	    if (status) {
+		free(opt);
+		free(val);
+		goto clean_n_exit;
+	    }
+	    db_name_set = 1;
+	}
+	/* ignore hash argument. Might have been passed from create */
+	else if (!opt || strcmp(opt, "hash")) {
+	    char    buf[KRB5_MAX_ERR_STR];
+	    sprintf(buf, "Unsupported argument \"%s\" for db2",
+		    opt ? opt : val);
+	    krb5_db2_dal_err_funcp(kcontext, krb5_err_have_str, EINVAL, buf);
+	    free(opt);
+	    free(val);
+	    return EINVAL;
+	}
+
+	free(opt);
+	free(val);
+	t_ptr++;
+    }
+
+    if (!db_name_set) {
+	char   *value = NULL;
+	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION, conf_section, KDB_DB2_DATABASE_NAME,	/* under given conf section */
+				    NULL, &value);
+
+	if (value == NULL) {
+	    /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
+	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION, KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME,	/* under given realm */
+					default_db_name, &value);
+	    if (status) {
+		goto clean_n_exit;
+	    }
+	}
+
+	status = krb5_db2_db_set_name(kcontext, value);
+	profile_release_string(value);
+	if (status) {
+	    goto clean_n_exit;
+	}
+
+    }
+
+    status = krb5_db2_db_init(kcontext);
+
+  clean_n_exit:
+    return status;
+}
+
+krb5_error_code
+krb5_db2_create(krb5_context kcontext, char *conf_section, char **db_args)
+{
+    krb5_error_code status = 0;
+    char  **t_ptr = db_args;
+    char    db_name_set = 0;
+    krb5_int32 flags = KRB5_KDB_CREATE_BTREE;
+    char   *db_name = NULL;
+
+    if (k5db2_inited(kcontext))
+	return 0;
+
+    while (t_ptr && *t_ptr) {
+	char   *opt = NULL, *val = NULL;
+
+	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
+	if (opt && !strcmp(opt, "dbname")) {
+	    db_name = strdup(val);
+	    status = krb5_db2_db_set_name(kcontext, val);
+	    if (!status) {
+		status = EEXIST;
+		free(opt);
+		free(val);
+		goto clean_n_exit;
+	    }
+	    db_name_set = 1;
+	}
+	/* ignore hash argument. Might have been passed from create */
+	else if (opt && !strcmp(opt, "hash")) {
+	    flags = KRB5_KDB_CREATE_HASH;
+	} else {
+	    char    buf[KRB5_MAX_ERR_STR];
+	    sprintf(buf, "Unsupported argument \"%s\" for db2",
+		    opt ? opt : val);
+	    krb5_db2_dal_err_funcp(kcontext, krb5_err_have_str, EINVAL, buf);
+	    free(opt);
+	    free(val);
+	    return EINVAL;
+	}
+
+	free(opt);
+	free(val);
+	t_ptr++;
+    }
+
+    if (!db_name_set) {
+	char   *value = NULL;
+	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext),
+				    KDB_MODULE_SECTION, conf_section,
+				    /* under given conf section */
+				    KDB_DB2_DATABASE_NAME, NULL, &value);
+
+	if (value == NULL) {
+	    /* Special case for db2.  We might actually be looking at
+	     * old type config file where database is specified as
+	     * part of realm.  */
+	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext),
+					KDB_REALM_SECTION,
+					KRB5_DB_GET_REALM(kcontext),
+					/* under given realm */
+					KDB_DB2_DATABASE_NAME,
+					default_db_name, &value);
+	    if (status) {
+		goto clean_n_exit;
+	    }
+	}
+
+	db_name = strdup(value);
+	status = krb5_db2_db_set_name(kcontext, value);
+	profile_release_string(value);
+	if (!status) {
+	    status = EEXIST;
+	    goto clean_n_exit;
+	}
+
+    }
+
+    status = krb5_db2_db_create(kcontext, db_name, flags);
+    if (status)
+	goto clean_n_exit;
+    /* db2 has a problem of needing to close and open the database again. This removes that need */
+    status = krb5_db2_db_fini(kcontext);
+    if (status)
+	goto clean_n_exit;
+
+    status = krb5_db2_open(kcontext, conf_section, db_args, KRB5_KDB_OPEN_RW);
+
+  clean_n_exit:
+    if (db_name)
+	free(db_name);
+    return status;
+}
+
+krb5_error_code
+krb5_db2_destroy(krb5_context kcontext, char *conf_section, char **db_args)
+{
+    krb5_error_code status = 0;
+    char  **t_ptr = db_args;
+    char    db_name_set = 0;
+    char   *db_name = NULL;
+
+    while (t_ptr && *t_ptr) {
+	char   *opt = NULL, *val = NULL;
+
+	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
+	if (opt && !strcmp(opt, "dbname")) {
+	    db_name = strdup(val);
+	    status = krb5_db2_db_set_name(kcontext, val);
+	    if (status) {
+		free(opt);
+		free(val);
+		goto clean_n_exit;
+	    }
+	    db_name_set = 1;
+	}
+	/* ignore hash argument. Might have been passed from create */
+	else if (!opt || strcmp(opt, "hash")) {
+	    free(opt);
+	    free(val);
+	    return EINVAL;
+	}
+
+	free(opt);
+	free(val);
+	t_ptr++;
+    }
+
+    if (!db_name_set) {
+	char   *value = NULL;
+	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION, conf_section, KDB_DB2_DATABASE_NAME,	/* under given conf section */
+				    NULL, &value);
+
+	if (value == NULL) {
+	    /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
+	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION, KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME,	/* under given realm */
+					default_db_name, &value);
+	    if (status) {
+		goto clean_n_exit;
+	    }
+	}
+
+	db_name = strdup(value);
+	status = krb5_db2_db_set_name(kcontext, value);
+	profile_release_string(value);
+	if (status) {
+	    goto clean_n_exit;
+	}
+
+    }
+
+    status = krb5_db2_db_destroy(kcontext, db_name);
+
+  clean_n_exit:
+    if (db_name)
+	free(db_name);
+    return status;
+}
+
+krb5_error_code
+krb5_db2_set_master_key_ext(krb5_context kcontext,
+			    char *pwd, krb5_keyblock * key)
+{
+    return krb5_db2_db_set_mkey(kcontext, key);
+}
+
+krb5_error_code
+krb5_db2_db_set_option(krb5_context kcontext, int option, void *value)
+{
+    krb5_error_code status = 0;
+    krb5_boolean oldval;
+
+    switch (option) {
+    case KRB5_KDB_OPT_SET_DB_NAME:
+	status = krb5_db2_db_set_name(kcontext, (char *) value);
+	break;
+
+    case KRB5_KDB_OPT_SET_LOCK_MODE:
+	oldval = krb5_db2_db_set_lockmode(kcontext, *((krb5_boolean *) value));
+	*((krb5_boolean *) value) = oldval;
+	break;
+
+    default:
+	status = -1;		/* TBD */
+	break;
+    }
+
+    return status;
+}
+
+void   *
+krb5_db2_alloc(krb5_context kcontext, void *ptr, size_t size)
+{
+    return realloc(ptr, size);
+}
+
+void
+krb5_db2_free(krb5_context kcontext, void *ptr)
+{
+    free(ptr);
+}
+
+/* policy functions */
+krb5_error_code
+krb5_db2_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
+{
+    kdb5_dal_handle *dal_handle;
+    krb5_db2_context *dbc;
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    dbc = (krb5_db2_context *) dal_handle->db_context;
+
+    return osa_adb_create_policy(dbc->policy_db, policy);
+}
+
+krb5_error_code
+krb5_db2_get_policy(krb5_context kcontext,
+		    char *name, osa_policy_ent_t * policy, int *cnt)
+{
+    kdb5_dal_handle *dal_handle;
+    krb5_db2_context *dbc;
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    dbc = (krb5_db2_context *) dal_handle->db_context;
+
+    return osa_adb_get_policy(dbc->policy_db, name, policy, cnt);
+}
+
+krb5_error_code
+krb5_db2_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
+{
+    kdb5_dal_handle *dal_handle;
+    krb5_db2_context *dbc;
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    dbc = (krb5_db2_context *) dal_handle->db_context;
+
+    return osa_adb_put_policy(dbc->policy_db, policy);
+}
+
+krb5_error_code
+krb5_db2_iter_policy(krb5_context kcontext,
+		     char *match_entry,
+		     osa_adb_iter_policy_func func, void *data)
+{
+    kdb5_dal_handle *dal_handle;
+    krb5_db2_context *dbc;
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    dbc = (krb5_db2_context *) dal_handle->db_context;
+
+    return osa_adb_iter_policy(dbc->policy_db, func, data);
+}
+
+krb5_error_code
+krb5_db2_delete_policy(krb5_context kcontext, char *policy)
+{
+    kdb5_dal_handle *dal_handle;
+    krb5_db2_context *dbc;
+
+    dal_handle = (kdb5_dal_handle *) kcontext->db_context;
+    dbc = (krb5_db2_context *) dal_handle->db_context;
+
+    return osa_adb_destroy_policy(dbc->policy_db, policy);
+}
+
+void
+krb5_db2_free_policy(krb5_context kcontext, osa_policy_ent_t entry)
+{
+    osa_free_policy_ent(entry);
+}
diff --git a/mechglue/src/plugins/kdb/db2/kdb_db2.h b/mechglue/src/plugins/kdb/db2/kdb_db2.h
new file mode 100644
index 000000000..ba03ea36f
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/kdb_db2.h
@@ -0,0 +1,216 @@
+/*
+ * lib/kdb/kdb_db2.h
+ *
+ * Copyright 1997 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * KDC Database backend definitions for Berkely DB.
+ */
+#ifndef KRB5_KDB_DB2_H
+#define KRB5_KDB_DB2_H
+
+#include "policy_db.h"
+
+typedef struct _krb5_db2_context {
+    krb5_boolean        db_inited;      /* Context initialized          */
+    char *              db_name;        /* Name of database             */
+    DB *		db;		/* DB handle			*/
+    krb5_boolean	hashfirst;	/* Try hash database type first	*/
+    char *              db_lf_name;     /* Name of lock file            */
+    int                 db_lf_file;     /* File descriptor of lock file */
+    time_t              db_lf_time;     /* Time last updated            */
+    int                 db_locks_held;  /* Number of times locked       */
+    int                 db_lock_mode;   /* Last lock mode, e.g. greatest*/
+    krb5_boolean        db_nb_locks;    /* [Non]Blocking lock modes     */
+    krb5_keyblock      *db_master_key;  /* Master key of database       */
+    osa_adb_policy_t    policy_db;
+} krb5_db2_context;
+
+#define KRB5_DB2_MAX_RETRY 5
+
+#define KDB2_LOCK_EXT ".ok"
+
+krb5_error_code krb5_db2_db_set_name 
+	(krb5_context,
+		   char * );
+krb5_error_code krb5_db2_db_init 
+	(krb5_context);
+krb5_error_code krb5_db2_db_fini 
+	(krb5_context);
+krb5_error_code krb5_db2_db_get_age 
+	(krb5_context,
+		   char *,
+		   time_t * );
+krb5_error_code krb5_db2_db_create 
+	(krb5_context,
+		   char *,
+		   krb5_int32);
+krb5_error_code krb5_db2_db_destroy 
+	(krb5_context,
+		   char * );
+krb5_error_code krb5_db2_db_rename 
+	(krb5_context,
+		   char *,
+		   char * );
+krb5_error_code krb5_db2_db_get_principal 
+	(krb5_context,
+		   krb5_const_principal,
+		   krb5_db_entry *,
+		   int *,
+		   krb5_boolean * );
+krb5_error_code krb5_db2_db_free_principal 
+	(krb5_context,
+		   krb5_db_entry *,
+		   int );
+krb5_error_code krb5_db2_db_put_principal 
+	(krb5_context,
+	 krb5_db_entry *,
+	 int *,
+	 char **db_args
+	 );
+krb5_error_code krb5_db2_db_iterate_ext
+    	(krb5_context,
+		   krb5_error_code (*) (krb5_pointer,
+					          krb5_db_entry *),
+	           krb5_pointer, int, int );
+krb5_error_code krb5_db2_db_iterate
+(krb5_context,char *,
+		   krb5_error_code (*) (krb5_pointer,
+					          krb5_db_entry *),
+	           krb5_pointer );
+krb5_error_code krb5_db2_db_set_nonblocking 
+	(krb5_context,
+		   krb5_boolean,
+		   krb5_boolean * );
+krb5_boolean krb5_db2_db_set_lockmode
+	(krb5_context,
+		   krb5_boolean );
+krb5_error_code krb5_db2_db_open_database 
+	(krb5_context);
+krb5_error_code krb5_db2_db_close_database 
+	(krb5_context);
+
+krb5_error_code 
+krb5_db2_set_master_key_ext ( krb5_context kcontext, 
+			      char *pwd, 
+			      krb5_keyblock *key);
+
+krb5_error_code
+krb5_db2_db_set_mkey( krb5_context context,
+		      krb5_keyblock *key);
+
+krb5_error_code
+krb5_db2_db_get_mkey( krb5_context context,
+		      krb5_keyblock **key);
+
+krb5_error_code
+krb5_db2_db_put_principal( krb5_context context,
+			   krb5_db_entry *entries,
+			   register int *nentries,
+			   char **db_args);
+
+krb5_error_code
+krb5_db2_db_delete_principal(krb5_context context,
+			     krb5_const_principal searchfor,
+			     int *nentries);
+
+krb5_error_code krb5_db2_lib_init(krb5_set_err_func_t);
+
+krb5_error_code krb5_db2_lib_cleanup(void);
+
+krb5_error_code 
+krb5_db2_db_unlock(krb5_context);
+
+krb5_error_code 
+krb5_db2_db_set_option ( krb5_context kcontext, 
+			 int option, 
+			 void *value );
+
+krb5_error_code
+krb5_db2_db_lock( krb5_context 	  context,
+		  int 	 	  in_mode);
+
+
+krb5_error_code 
+krb5_db2_open( krb5_context kcontext,
+			       char *conf_section,
+			       char **db_args,
+			       int mode );
+
+krb5_error_code krb5_db2_create( krb5_context kcontext,
+				 char *conf_section,
+				 char **db_args );
+
+krb5_error_code krb5_db2_destroy( krb5_context kcontext,
+				  char *conf_section,
+				  char **db_args );
+
+const char * krb5_db2_err2str( krb5_context kcontext,
+			       long err_code );
+
+void * 
+krb5_db2_alloc( krb5_context kcontext,  
+		void *ptr, 
+		size_t size );
+
+void 
+krb5_db2_free( krb5_context kcontext, 
+		    void *ptr );
+
+
+
+
+
+/* policy management functions */
+krb5_error_code
+krb5_db2_create_policy(krb5_context context, osa_policy_ent_t entry);
+
+krb5_error_code krb5_db2_get_policy ( krb5_context kcontext,
+				      char *name,
+				      osa_policy_ent_t *policy,
+				      int *cnt);
+
+krb5_error_code krb5_db2_get_policy ( krb5_context kcontext,
+				      char *name,
+				      osa_policy_ent_t *policy,
+				      int *cnt);
+
+krb5_error_code krb5_db2_put_policy ( krb5_context kcontext,
+				      osa_policy_ent_t policy );
+
+krb5_error_code krb5_db2_iter_policy ( krb5_context kcontext,
+				       char *match_entry,
+				       osa_adb_iter_policy_func func,
+				       void *data );
+
+krb5_error_code krb5_db2_delete_policy ( krb5_context kcontext,
+					 char *policy );
+
+void krb5_db2_free_policy( krb5_context kcontext,
+			   osa_policy_ent_t entry );
+
+
+
+extern krb5_set_err_func_t krb5_db2_dal_err_funcp;
+
+#endif /* KRB5_KDB_DB2_H */
diff --git a/mechglue/src/plugins/kdb/db2/kdb_xdr.c b/mechglue/src/plugins/kdb/db2/kdb_xdr.c
new file mode 100644
index 000000000..396350d76
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/kdb_xdr.c
@@ -0,0 +1,493 @@
+/*
+ * lib/kdb/kdb_xdr.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology. 
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+#include "k5-int.h"
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include "kdb_xdr.h"
+
+krb5_error_code
+krb5_encode_princ_dbkey(context, key, principal)
+    krb5_context context;
+    krb5_data  *key;
+    krb5_const_principal principal;
+{
+    char *princ_name;
+    krb5_error_code retval;
+
+    if (!(retval = krb5_unparse_name(context, principal, &princ_name))) {
+        /* need to store the NULL for decoding */
+        key->length = strlen(princ_name)+1;	
+        key->data = princ_name;
+    }
+    return(retval);
+}
+
+void
+krb5_free_princ_dbkey(context, key)
+    krb5_context context;
+    krb5_data  *key;
+{
+    (void) krb5_free_data_contents(context, key);
+}
+
+krb5_error_code
+krb5_encode_princ_contents(context, content, entry)
+    krb5_context 	  context;
+    krb5_data  		* content;
+    krb5_db_entry 	* entry;
+{
+    int 		  i, j;
+    unsigned int	  unparse_princ_size;
+    char 		* unparse_princ;
+    char		* nextloc;
+    krb5_tl_data	* tl_data;
+    krb5_error_code 	  retval;
+    krb5_int16		  psize16;
+
+    /*
+     * Generate one lump of data from the krb5_db_entry.
+     * This data must be independent of byte order of the machine,
+     * compact and extensible.
+     */
+
+    /* 
+     * First allocate enough space for all the data. 
+     * Need  2 bytes for the length of the base structure
+     * then 36 [ 8 * 4 + 2 * 2] bytes for the base information
+     *         [ attributes, max_life, max_renewable_life, expiration,
+     *	  	 pw_expiration, last_success, last_failed, fail_auth_count ]
+     *         [ n_key_data, n_tl_data ]
+     * then XX bytes [ e_length ] for the extra data [ e_data ]
+     * then XX bytes [ 2 for length + length for string ] for the principal,
+     * then (4 [type + length] + tl_data_length) bytes per tl_data
+     * then (4 + (4 + key_data_length) per key_data_contents) bytes per key_data
+     */
+    content->length = entry->len + entry->e_length;
+
+    if ((retval = krb5_unparse_name(context, entry->princ, &unparse_princ)))
+	return(retval);
+
+    unparse_princ_size = strlen(unparse_princ) + 1;
+    content->length += unparse_princ_size;
+    content->length += 2;		
+
+    i = 0;
+    /* tl_data is a linked list */
+    for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
+	content->length += tl_data->tl_data_length;
+	content->length += 4; /* type, length */
+	i++;
+    }
+
+    if (i != entry->n_tl_data) {
+	retval = KRB5_KDB_TRUNCATED_RECORD;
+	goto epc_error;
+    }
+
+    /* key_data is an array */
+    for (i = 0; i < entry->n_key_data; i++) {
+	content->length += 4; /* Version, KVNO */
+	for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
+	    content->length += entry->key_data[i].key_data_length[j];
+	    content->length += 4; /* type + length */
+	}
+    }
+	
+    if ((content->data = malloc(content->length)) == NULL) {
+	retval = ENOMEM;
+	goto epc_error;
+    }
+
+    /* 
+     * Now we go through entry again, this time copying data 
+     * These first entries are always saved regardless of version
+     */
+    nextloc = content->data;
+
+	/* Base Length */
+    krb5_kdb_encode_int16(entry->len, nextloc);
+    nextloc += 2;
+
+	/* Attributes */
+    krb5_kdb_encode_int32(entry->attributes, nextloc);
+    nextloc += 4;
+  
+	/* Max Life */
+    krb5_kdb_encode_int32(entry->max_life, nextloc);
+    nextloc += 4;
+  
+	/* Max Renewable Life */
+    krb5_kdb_encode_int32(entry->max_renewable_life, nextloc);
+    nextloc += 4;
+  
+	/* When the client expires */
+    krb5_kdb_encode_int32(entry->expiration, nextloc);
+    nextloc += 4;
+  
+	/* When its passwd expires */
+    krb5_kdb_encode_int32(entry->pw_expiration, nextloc);
+    nextloc += 4;
+  
+	/* Last successful passwd */
+    krb5_kdb_encode_int32(entry->last_success, nextloc);
+    nextloc += 4;
+  
+	/* Last failed passwd attempt */
+    krb5_kdb_encode_int32(entry->last_failed, nextloc);
+    nextloc += 4;
+  
+	/* # of failed passwd attempt */
+    krb5_kdb_encode_int32(entry->fail_auth_count, nextloc);
+    nextloc += 4;
+
+	/* # tl_data strutures */
+    krb5_kdb_encode_int16(entry->n_tl_data, nextloc);
+    nextloc += 2;
+  
+	/* # key_data strutures */
+    krb5_kdb_encode_int16(entry->n_key_data, nextloc);
+    nextloc += 2;
+  
+    	/* Put extended fields here */
+    if (entry->len != KRB5_KDB_V1_BASE_LENGTH)
+	abort();
+
+	/* Any extra data that this version doesn't understand. */
+    if (entry->e_length) {
+	memcpy(nextloc, entry->e_data, entry->e_length);
+	nextloc += entry->e_length;
+    }
+  
+	/* 
+	 * Now we get to the principal.
+	 * To squeze a few extra bytes out it is always assumed to come
+	 * after the base type.
+	 */
+    psize16 = (krb5_int16) unparse_princ_size;
+    krb5_kdb_encode_int16(psize16, nextloc);
+    nextloc += 2;
+    (void) memcpy(nextloc, unparse_princ, unparse_princ_size);
+    nextloc += unparse_princ_size;
+
+    	/* tl_data is a linked list, of type, legth, contents */
+    for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
+	krb5_kdb_encode_int16(tl_data->tl_data_type, nextloc);
+	nextloc += 2;
+	krb5_kdb_encode_int16(tl_data->tl_data_length, nextloc);
+	nextloc += 2;
+
+	memcpy(nextloc, tl_data->tl_data_contents, tl_data->tl_data_length);
+	nextloc += tl_data->tl_data_length;
+    }
+
+    	/* key_data is an array */
+    for (i = 0; i < entry->n_key_data; i++) {
+	krb5_kdb_encode_int16(entry->key_data[i].key_data_ver, nextloc);
+	nextloc += 2;
+	krb5_kdb_encode_int16(entry->key_data[i].key_data_kvno, nextloc);
+	nextloc += 2;
+
+	for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
+	    krb5_int16 type = entry->key_data[i].key_data_type[j];
+	    krb5_ui_2  length = entry->key_data[i].key_data_length[j];
+
+    	    krb5_kdb_encode_int16(type, nextloc);
+	    nextloc += 2;
+    	    krb5_kdb_encode_int16(length, nextloc);
+	    nextloc += 2;
+
+	    if (length) {
+	        memcpy(nextloc, entry->key_data[i].key_data_contents[j],length);
+	        nextloc += length;
+	    }
+	}
+    }
+	
+epc_error:;
+    free(unparse_princ);
+    return retval;
+}
+
+void
+krb5_free_princ_contents(context, contents)
+    krb5_context 	  context;
+    krb5_data *contents;
+{
+    krb5_free_data_contents(context, contents);
+    return;
+}
+
+krb5_error_code
+krb5_decode_princ_contents(context, content, entry)
+    krb5_context 	  context;
+    krb5_data  		* content;
+    krb5_db_entry 	* entry;
+{
+    int			  sizeleft, i;
+    char 		* nextloc;
+    krb5_tl_data       ** tl_data;
+    krb5_int16		  i16;
+
+    krb5_error_code retval;
+
+    /* Zero out entry and NULL pointers */
+    memset(entry, 0, sizeof(krb5_db_entry));
+
+    /*
+     * undo the effects of encode_princ_contents.
+     *
+     * The first part is decoding the base type. If the base type is
+     * bigger than the original base type then the additional fields
+     * need to be filled in. If the base type is larger than any
+     * known base type the additional data goes in e_data.
+     */
+
+    /* First do the easy stuff */
+    nextloc = content->data;
+    sizeleft = content->length;
+    if ((sizeleft -= KRB5_KDB_V1_BASE_LENGTH) < 0) 
+	return KRB5_KDB_TRUNCATED_RECORD;
+
+	/* Base Length */
+    krb5_kdb_decode_int16(nextloc, entry->len);
+    nextloc += 2;
+
+	/* Attributes */
+    krb5_kdb_decode_int32(nextloc, entry->attributes);
+    nextloc += 4;
+
+	/* Max Life */
+    krb5_kdb_decode_int32(nextloc, entry->max_life);
+    nextloc += 4;
+
+	/* Max Renewable Life */
+    krb5_kdb_decode_int32(nextloc, entry->max_renewable_life);
+    nextloc += 4;
+
+	/* When the client expires */
+    krb5_kdb_decode_int32(nextloc, entry->expiration);
+    nextloc += 4;
+
+	/* When its passwd expires */
+    krb5_kdb_decode_int32(nextloc, entry->pw_expiration);
+    nextloc += 4;
+
+	/* Last successful passwd */
+    krb5_kdb_decode_int32(nextloc, entry->last_success);
+    nextloc += 4;
+
+	/* Last failed passwd attempt */
+    krb5_kdb_decode_int32(nextloc, entry->last_failed);
+    nextloc += 4;
+
+	/* # of failed passwd attempt */
+    krb5_kdb_decode_int32(nextloc, entry->fail_auth_count);
+    nextloc += 4;
+
+	/* # tl_data strutures */
+    krb5_kdb_decode_int16(nextloc, entry->n_tl_data);
+    nextloc += 2;
+
+    if (entry->n_tl_data < 0)
+	return KRB5_KDB_TRUNCATED_RECORD;
+
+	/* # key_data strutures */
+    krb5_kdb_decode_int16(nextloc, entry->n_key_data);
+    nextloc += 2;
+
+    if (entry->n_key_data < 0)
+	return KRB5_KDB_TRUNCATED_RECORD;
+
+	/* Check for extra data */
+    if (entry->len > KRB5_KDB_V1_BASE_LENGTH) {
+	entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH;
+	if ((entry->e_data = (krb5_octet *)malloc(entry->e_length))) {
+	    memcpy(entry->e_data, nextloc, entry->e_length);
+	    nextloc += entry->e_length;
+	} else {
+	    return ENOMEM;
+	}
+    }
+
+    /*
+     * Get the principal name for the entry 
+     * (stored as a string which gets unparsed.)
+     */
+    if ((sizeleft -= 2) < 0) {
+	retval = KRB5_KDB_TRUNCATED_RECORD;
+	goto error_out;
+    }
+
+    i = 0;
+    krb5_kdb_decode_int16(nextloc, i16);
+    i = (int) i16;
+    nextloc += 2;
+
+    if ((retval = krb5_parse_name(context, nextloc, &(entry->princ))))
+	goto error_out;
+    if (((size_t) i != (strlen(nextloc) + 1)) || (sizeleft < i)) {
+	retval = KRB5_KDB_TRUNCATED_RECORD;
+	goto error_out;
+    }
+    sizeleft -= i;
+    nextloc += i;
+
+    	/* tl_data is a linked list */
+    tl_data = &entry->tl_data;
+    for (i = 0; i < entry->n_tl_data; i++) {
+    	if ((sizeleft -= 4) < 0) {
+	    retval = KRB5_KDB_TRUNCATED_RECORD;
+	    goto error_out;
+	}
+	if ((*tl_data = (krb5_tl_data *)
+	  malloc(sizeof(krb5_tl_data))) == NULL) {
+	    retval = ENOMEM;
+	    goto error_out;
+	}
+	(*tl_data)->tl_data_next = NULL;
+	(*tl_data)->tl_data_contents = NULL;
+	krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type);
+	nextloc += 2;
+	krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length);
+	nextloc += 2;
+
+    	if ((sizeleft -= (*tl_data)->tl_data_length) < 0) {
+	    retval = KRB5_KDB_TRUNCATED_RECORD;
+	    goto error_out;
+	}
+	if (((*tl_data)->tl_data_contents = (krb5_octet *)
+	  malloc((*tl_data)->tl_data_length)) == NULL) {
+	    retval = ENOMEM;
+	    goto error_out;
+	}
+	memcpy((*tl_data)->tl_data_contents,nextloc,(*tl_data)->tl_data_length);
+	nextloc += (*tl_data)->tl_data_length;
+	tl_data = &((*tl_data)->tl_data_next);
+    }
+
+    	/* key_data is an array */
+    if (entry->n_key_data && ((entry->key_data = (krb5_key_data *)
+      malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) {
+        retval = ENOMEM;
+	goto error_out;
+    }
+    for (i = 0; i < entry->n_key_data; i++) {
+	krb5_key_data * key_data;
+        int j;
+
+    	if ((sizeleft -= 4) < 0) {
+	    retval = KRB5_KDB_TRUNCATED_RECORD;
+	    goto error_out;
+	}
+	key_data = entry->key_data + i;
+	memset(key_data, 0, sizeof(krb5_key_data));
+	krb5_kdb_decode_int16(nextloc, key_data->key_data_ver);
+	nextloc += 2;
+	krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno);
+	nextloc += 2;
+
+	/* key_data_ver determins number of elements and how to unparse them. */
+	if (key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) {
+	    for (j = 0; j < key_data->key_data_ver; j++) {
+    	        if ((sizeleft -= 4) < 0) {
+	            retval = KRB5_KDB_TRUNCATED_RECORD;
+	            goto error_out;
+	        }
+		krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]);
+		nextloc += 2;
+		krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]);
+		nextloc += 2;
+
+    	        if ((sizeleft -= key_data->key_data_length[j]) < 0) {
+	            retval = KRB5_KDB_TRUNCATED_RECORD;
+	            goto error_out;
+	        }
+	        if (key_data->key_data_length[j]) {
+	    	    if ((key_data->key_data_contents[j] = (krb5_octet *)
+	    	      malloc(key_data->key_data_length[j])) == NULL) {
+	                retval = ENOMEM;
+	                goto error_out;
+	            }
+	            memcpy(key_data->key_data_contents[j], nextloc, 
+		           key_data->key_data_length[j]);
+	            nextloc += key_data->key_data_length[j];
+		}
+	    }
+	} else {
+	    /* This isn't right. I'll fix it later */
+	    abort();
+	}
+    }
+    return 0;
+
+error_out:;
+    krb5_dbe_free_contents(context, entry);
+    return retval;
+}
+	    
+void
+krb5_dbe_free_contents(context, entry)
+     krb5_context 	  context; 
+     krb5_db_entry 	* entry;
+{
+    krb5_tl_data 	* tl_data_next;
+    krb5_tl_data 	* tl_data;
+    int i, j;
+
+    if (entry->e_data)
+	free(entry->e_data);
+    if (entry->princ)
+	krb5_free_principal(context, entry->princ);
+    for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) {
+	tl_data_next = tl_data->tl_data_next;
+	if (tl_data->tl_data_contents)
+	    free(tl_data->tl_data_contents);
+	free(tl_data);
+    }
+    if (entry->key_data) {
+    	for (i = 0; i < entry->n_key_data; i++) {
+	    for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
+	    	if (entry->key_data[i].key_data_length[j]) {
+		    if (entry->key_data[i].key_data_contents[j]) {
+		        memset(entry->key_data[i].key_data_contents[j], 
+			       0, 
+			       (unsigned) entry->key_data[i].key_data_length[j]);
+		    	free (entry->key_data[i].key_data_contents[j]);
+		    }
+		}
+		entry->key_data[i].key_data_contents[j] = NULL;
+		entry->key_data[i].key_data_length[j] = 0;
+		entry->key_data[i].key_data_type[j] = 0;
+	    }
+	}
+	free(entry->key_data);
+    }
+    memset(entry, 0, sizeof(*entry));
+    return;
+}
diff --git a/mechglue/src/plugins/kdb/db2/kdb_xdr.h b/mechglue/src/plugins/kdb/db2/kdb_xdr.h
new file mode 100644
index 000000000..2ee068fbd
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/kdb_xdr.h
@@ -0,0 +1,32 @@
+#ifndef _KDB2_XDR_H
+#define _KDB2_XDR_H
+
+krb5_error_code
+krb5_encode_princ_dbkey( krb5_context context,
+			 krb5_data  *key,
+			 krb5_const_principal principal);
+
+krb5_error_code
+krb5_decode_princ_contents( krb5_context 	  context,
+			    krb5_data  		* content,
+			    krb5_db_entry 	* entry);
+
+void
+krb5_dbe_free_contents( krb5_context 	  context,
+			krb5_db_entry 	* entry);
+
+krb5_error_code
+krb5_encode_princ_contents( krb5_context 	  context,
+			    krb5_data  		* content,
+			    krb5_db_entry 	* entry);
+
+
+void
+krb5_free_princ_dbkey( krb5_context context,
+		       krb5_data  *key);
+
+void
+krb5_free_princ_contents( krb5_context context,
+			  krb5_data *contents);
+
+#endif
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/CHANGELOG.db2 b/mechglue/src/plugins/kdb/db2/libdb2/CHANGELOG.db2
new file mode 100644
index 000000000..abd05f95d
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/CHANGELOG.db2
@@ -0,0 +1,123 @@
+db2-alpha.0 -> db2-alpha.1
+		This fixes a number of bugs in the alpha release.
+		1. 64-bit functionality.  The test suite now runs on alphas.
+		Memory leak fixed.
+		Pairs no longer disappear when pages are exactly full.
+		Flush meta-data correctly on sync.
+1.86 -> db2-alpha.0
+		This is an interim release.  We are in the process of
+		adding logging, locking, and transaction support to all
+		the db access methods.  This will necessitate database
+		format changes, interface changes, and major upheaval.
+		In the meantime, this PRELIMINARY release is to correct
+		some known bugs in the hash pacakge.  This release uses
+		a different page format from 1.86, so you will need to
+		dump and reload any existing databases if you upgrade
+		to this (and may have to do it again when 2.0 becomes
+		available.
+1.85 -> 1.86
+	btree:	Fix to split code for single large record at the end of a
+		page.
+1.84 -> 1.85
+	recno:	#ifdef out use of mmap, it's not portable enough.
+
+1.83 -> 1.84	Thu Aug 18 15:46:07 EDT 1994
+	recno:	Rework fixed-length records so that closing and reopening
+		the file now works.  Pad short records on input.  Never do
+		signed comparison in recno input reading functions.
+
+1.82 -> 1.83	Tue Jul 26 15:33:44 EDT 1994
+	btree:	Rework cursor deletion code yet again; bugs with
+		deleting empty pages that only contained the cursor
+		record.
+
+1.81 -> 1.82	Sat Jul 16 11:01:50 EDT 1994
+	btree:	Fix bugs introduced by new cursor/deletion code.
+		Replace return kbuf/dbuf with real DBT's.
+
+1.80 -> 1.81
+	btree:	Fix bugs introduced by new cursor/deletion code.
+	all:	Add #defines for Purify.
+
+1.79 -> 1.80	Wed Jul 13 22:41:54 EDT 1994
+	btree	Change deletion to coalesce empty pages.  This is a major
+		change, cursors and duplicate pages all had to be reworked.
+		Return to a fixed stack.
+	recno:	Affected by cursor changes.  New cursor structures should
+		permit multiple cursors in the future.
+
+1.78 -> 1.79	Mon Jun 20 17:36:47 EDT 1994
+	all:	Minor cleanups of 1.78 for porting reasons; only
+		major change was inlining check of NULL pointer
+		so that __fix_realloc goes away.
+
+1.77 -> 1.78	Thu Jun 16 19:06:43 EDT 1994
+	all:	Move "standard" size typedef's into db.h.
+
+1.76 -> 1.77	Thu Jun 16 16:48:38 EDT 1994
+	hash:	Delete __init_ routine, has special meaning to OSF 2.0.
+
+1.74 -> 1.76
+	all:	Finish up the port to the Alpha.
+
+1.73 -> 1.74
+	recno:	Don't put the record if rec_search fails, in rec_rdelete.
+		Create fixed-length intermediate records past "end" of DB
+		correctly.
+		Realloc bug when reading in fixed records.
+	all:	First cut at port to Alpha (64-bit architecture) using
+		4.4BSD basic integral types typedef's.
+		Cast allocation pointers to shut up old compilers.
+		Rework PORT directory into OS/machine directories.
+
+1.72 -> 1.73
+	btree:	If enough duplicate records were inserted and then deleted
+		that internal pages had references to empty pages of the
+		duplicate keys, the search function ended up on the wrong
+		page.
+
+1.7  -> 1.72	12 Oct 1993
+	hash:	Support NET/2 hash formats.
+
+1.7  -> 1.71	16 Sep 1993
+	btree/recno:
+		Fix bug in internal search routines that caused
+		return of invalid pointers.
+
+1.6  -> 1.7	07 Sep 1993
+	hash:	Fixed big key overflow bugs.
+	test:	Portability hacks, rewrite test script, Makefile.
+	btree/recno:
+		Stop copying non-overflow key/data pairs.
+	PORT:	Break PORT directory up into per architecture/OS
+		subdirectories.
+
+1.5  -> 1.6	06 Jun 1993
+	hash:	In PAIRFITS, the first comparison should look at (P)[2].
+		The hash_realloc function was walking off the end of memory.
+		The overflow page number was wrong when bumping splitpoint.
+
+1.4  -> 1.5	23 May 1993
+	hash:	Set hash default fill factor dynamically.
+	recno:	Fixed bug in sorted page splits.
+		Add page size parameter support.
+		Allow recno to specify the name of the underlying btree;
+			used for vi recovery.
+	btree/recno:
+		Support 64K pages.
+	btree/hash/recno:
+		Provide access to an underlying file descriptor.
+		Change sync routines to take a flag argument, recno
+			uses this to sync out the underlying btree.
+
+1.3  -> 1.4	10 May 1993
+	recno:	Delete the R_CURSORLOG flag from the recno interface.
+		Zero-length record fix for non-mmap reads.
+		Try and make SIZE_T_MAX test in open portable.
+
+1.2  -> 1.3	01 May 1993
+	btree:	Ignore user byte-order setting when reading already
+		existing database.  Fixes to byte-order conversions.
+
+1.1  -> 1.2	15 Apr 1993
+		No bug fixes, only compatibility hacks.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/ChangeLog b/mechglue/src/plugins/kdb/db2/libdb2/ChangeLog
new file mode 100644
index 000000000..3c6bc71e5
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/ChangeLog
@@ -0,0 +1,513 @@
+2005-12-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-unix): Do depend on all-libs.
+	(myfulldir, RELDIR): Updated for directory rename.
+	* hash/Makefile.in (myfulldir): Likewise.
+	* db/Makefile.in (myfulldir): Likewise.
+	* mpool/Makefile.in (myfulldir): Likewise.
+	* btree/Makefile.in (myfulldir): Likewise.
+	* recno/Makefile.in (myfulldir): Likewise.
+	* clib/Makefile.in (myfulldir): Likewise.
+
+2005-10-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Set build_dynobj=yes.
+
+	* Makefile.in (all-unix, clean-unix): Drop liblinks dependencies.
+
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Directory moved from util/db2 to modules/kdb/db2/libdb2.
+	* Makefile.in (myfulldir, RELTOP, BUILDTOP): Updated for directory
+	move.
+	* btree/Makefile.in (myfulldir, BUILDTOP): Likewise.
+	* hash/Makefile.in (myfulldir, BUILDTOP): Likewise.
+	* db/Makefile.in (myfulldir, BUILDTOP): Likewise.
+	* mpool/Makefile.in (myfulldir, BUILDTOP): Likewise.
+	* recno/Makefile.in (myfulldir, BUILDTOP): Likewise.
+	* clib/Makefile.in (myfulldir, BUILDTOP): Likewise.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* mpool/mpool.c (mpool_get, mpool_write): Check that the offset
+	calculation didn't overflow.
+
+2004-06-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (include/generated.stmp): New intermediate target
+	file, to prevent repeated generation of unchanging header files.
+	(include/config.h, include/db-config.h): Depend on it.
+	($(srcdir)/include/autoconf.stmp, $(srcdir)/include/config.h.in):
+	Likewise.
+	(clean-includes): Delete the new intermediate target files.
+	* configure.in: Generate include/generated.stmp when config.status
+	is run.
+
+2004-06-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(srcdir)/include/config.h.in): Always use
+	--include, never try --localdir.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for sys/param.h too.
+
+2004-05-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for machine/endian.h too.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-prerecurse): Make sure headers generated by
+	config.status are up to date.
+	(include/config.h, $(srcdir)/include/config.h.in,
+	include/db-config.h): New rules.
+	* configure.in: Don't check byte order here.  Check for endian.h.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libdb.exports: New file.
+
+2004-04-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* btree/bt_seq.c: Include string.h.
+
+2003-04-01  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (install-unix): Delete install-libs.  We don't want
+	to install our in-tree libdb.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_INSTALL.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag.
+	* btree/Makefile.in, clib/Makefile.in, db/Makefile.in,
+	hash/Makefile.in, mpool/Makefile.in, recno/Makefile.in: Add
+	AC_SUBST_FILE marker for libobj_frag.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* clib/mkstemp.c (_gettemp): Remove declaration of errno
+
+2002-09-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for stdint.h and inttypes.h.
+
+2002-09-03  Ezra Peisach  <epeisach@bu.edu>
+
+	* acconfig.h: Remove file. All handled by configure.in now.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in, btree/Makefile.in, clib/Makefile.in,
+	db/Makefile.in, hash/Makefile.in, mpool/Makefile.in,
+	recno/Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-28  Tom Yu  <tlyu@mit.edu>
+
+	* btree/bt_split.c (bt_psplit): Correctly account for
+	sizeof(indx_t) when computing space used in a page by an item.
+	[patch from www.sleepycat.com]
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in, btree/Makefile.in, clib/Makefile.in,
+	db/Makefile.in, hash/Makefile.in, mpool/Makefile.in,
+	recno/Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-23  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (LIBMINOR): Bump due to addition of bt_rseq().
+
+	* hash/hash_debug.c: Remove inclusion of compat.h, as we don't
+	have it in our build system.
+
+	* btree/extern.h: Add missing prototypes/renames for
+	__bt_dmpage().  Add renames for bt_rseq() support functions.
+
+	* btree/bt_seq.c (bt_rseq): New function; like __bt_seq() but does
+	recursive descent rather than using the prev/next pointers.  This
+	will catch some pages that might be missed if the database is
+	inconsistent.  Added support functions for bt_rseq() as well.
+
+	* btree/bt_page.c (__bt_free): Set B_METADIRTY when updating free
+	list.
+	(__bt_new): Set B_METADIRTY when updating free list.
+	[patch from www.sleepycat.com]
+
+	* btree/bt_debug.c (__bt_dump): Bound loop by number of pages
+	actually in file to avoid getting a nigh-infinite number of
+	all-zeroes pages.
+	(__bt_dmpage): Print a newline after dumping the meta page.
+	(__bt_dpage): Add DB* parameter; use this to get pagesize in order
+	to limit dumping of page contents, in case NEXTINDEX(h) happens to
+	be bogus.
+	(__bt_stat): Bound loop by number of pages actually in file so as
+	to stop counting pages after the actual end of file.
+
+	* btree/bt_close.c (__bt_sync): Apply a Kerbnet fix from long ago;
+	don't return prematurely when B_METADIRTY is set but B_MODIFIED is
+	clear.
+
+2002-08-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SUBDIROBJLISTS): New variable.
+
+2002-01-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* btree/bt_put.c (__bt_put): Correctly handle writing out the key
+	or data size on a big-endian 64-bit platform.
+
+2001-10-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add optional argument to AC_DEFINE to provide
+	comment in generated header file.
+
+	* acconfig.h: Remove int32_t and u_int32_t, handled by configure.in
+
+2001-07-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* hash/hash_func.c (hash4): Declare first argument const.
+
+	* hash/hash.h: struct HTAB fname element now const.
+
+	* hash/hash.c: Declare third argument to hash_access and init_hash
+ 	const.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* hash/dbm.c: Include db-dbm.h for prototypes.
+
+2001-07-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* hash/hash_log2.c: Include hash.h, page.h and extern.h for prototype.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* test/dbtest.c: Cast argument to isspace() to int. Do not shadow
+	global variables type and flags.
+
+	* btree/bt_search.c, btree/bt_seq.c, recno/rec_search.c: Change
+	local variable index to idx.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* btree/bt_delete.c, btree/bt_put.c, recno/rec_delete.c,
+ 	recno/rec_put.c: Change local variable index to idx.
+
+	* hash/hash_page.c: Change local variable stat to status to
+	prevent shadowing system function.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in (AC_COMPILE_TYPE): Declare with AC_DEFUN() instead
+	of define() as newer versions of autoconf check for AC_REQUIRE use
+	outside of AC_DEFUN.
+
+Thu Aug 10 23:21:01 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add AC_PROG_INSTALL for installation of library.
+
+2000-07-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* test/dbtest.c: Cleanup gcc -Wall complaints with printf format
+	strings.
+
+2000-07-02  Ezra Peisach  <epeisach@engrailed.mit.edu>
+
+	* recno/rec_seq.c: Include unused sccsid when LIBC_SCCS defined.
+
+	* recno/rec_close.c (__rec_close): Explicit braces to avoid
+	ambiguous `else'
+
+	* btree/bt_split.c (bt_psplit): Parenthesis about && and ||
+	conditional.
+
+	* btree/bt_put.c (__bt_put): Extra {} to make nested if/else
+	unambiguous.
+
+	* btree/bt_open.c (__bt_open): Add parenthesis to ensure
+	precedence ordering.
+
+	* hash/dbm.c (kdb2_dbm_firstkey): Conditionalize defintion of
+	variables based on use.
+
+	* hash/hash_func.c: Ifdef out unused static hash functions.
+
+	* hash/hash.c (init_htab): Remove unused variable.
+
+2000-07-01  Tom Yu  <tlyu@mit.edu>
+
+	* clib/strerror.c: #include config.h.
+
+	* clib/mkstemp.c: #include config.h.
+
+	* clib/memmove.c: #include config.h.
+
+	* clib/Makefile.in (LOCALINCLUDES): Add -I../include to get
+	config.h.
+
+	* configure.in: Generate two config headers, one for internal use
+	and one for external use.  Rework clib replacement code to use
+	AC_DEFINE rather than ADD_DEF.
+
+	* Makefile.in (STOBJLISTS): Add clib.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Rework to use krb5 build system.
+
+	* Makefile.in: Rework to use krb5 build system.
+
+	* btree/Makefile.in: New file.
+
+	* clib/Makefile.in: New file.
+
+	* db/Makefile.in: New file.
+
+	* mpool/Makefile.in: New file.
+
+	* recno/Makefile.in: New file.
+
+	* test/Makefile.in: New file.
+
+2000-06-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* btree/bt_put.c (__bt_put): Initialize "e".
+
+2000-05-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* hash/dbm.c (kdb2_dbm_open): Don't overflow buffer "path".
+
+1999-08-15  Tom Yu  <tlyu@mit.edu>
+
+	* README.NOT.SLEEPYCAT.DB: New file; pointer to README to
+	hopefully unconfuse people.
+
+	* README: Add notice to the effect that this is not Berkeley or
+	Sleepycat DB.
+
+	* README.db2: Renamed from README.
+
+Fri Feb 13 14:37:47 1998  Tom Yu  <tlyu@mit.edu>
+
+	* recno/extern.h: Additional renaming.
+
+	* hash/extern.h: Additional renaming.
+
+	* hash/hash_page.c (page_to_oaddr): 
+	(is_bitmap_pgno): Declare static to avoid leaking symbols.
+
+	* hash/search.h: Additional renaming.
+
+	* hash/hash_log2.c (__log2): Rename explicitly.
+
+	* mpool/mpool.h: Additional renaming.
+
+	* btree/extern.h: Additional renaming.
+
+	* hash/hash.c (__kdb2_hash_open): Rename to avoid potential
+ 	collision with NetBSD libc.
+
+	* hash/dbm.c: Rename lots of functions to avoid colliding with
+	native dbm implementations.
+
+	* db/db.c (kdb2_dbopen): Rename to avoid colliding with NetBSD
+	libc.
+
+Wed Jan 21 10:17:34 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* btree/bt_open.c: Added O_BINARY for __CYGWIN32__.
+	* clib/mkstemp.c: Added O_BINARY for __CYGWIN32__.
+	* db/db.c: Added O_BINARY for __CYGWIN32__.
+	* hash/dbm.c: Added O_BINARY for __CYGWIN32__.
+	* hash/hash.c: Added O_BINARY for __CYGWIN32__.
+	* hash/hsearch.c: Added O_BINARY for __CYGWIN32__.
+	* include/db-int.h: Added O_BINARY for __CYGWIN32__.
+	* recno/rec_open.c: Added O_BINARY for __CYGWIN32__.
+	* test/dbtest.c: Added O_BINARY for __CYGWIN32__.
+	* test/SEQ_TEST/t.c: Added O_BINARY for __CYGWIN32__.
+	* test/btree.tests/main.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash1.tests/driver2.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash1.tests/tcreat3.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash1.tests/tdel.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash1.tests/thash4.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash1.tests/tread2.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash1.tests/tseq.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash1.tests/tverify.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash2.tests/bigtest.c: Added O_BINARY for __CYGWIN32__.
+	* test/hash2.tests/passtest.c: Added O_BINARY for __CYGWIN32__.
+	Changes originally by Jeremy Allison (jra@cygnus.com)
+
+Thu Jan 15 11:34:13 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* hash/hash_bigkey.c (collect_key, collect_data): Cast malloc
+	return value to correct types. (raeburn@cygnus.com)
+
+	* obj/Makefile.in (check): Set srcdir in environment.
+	(raeburn@cygnus.com)
+
+	* configure.in (AC_COMPILE_TYPE): replacment for AC_CHECK_TYPE
+	that uses AC_TRY_COMPILE instead of AC_EGREP_CPP.  For now, only
+	use it for the int32 types (where AC_CHECK_TYPE gets the wrong
+	result on __CYGWIN32__) and plan that AC_CHECK_TYPE itself gets
+	repaired. (Fix by eichin@cygnus.com)
+
+
+Sun Dec 21 18:33:14 1997  Tom Yu  <tlyu@mit.edu>
+
+	* hash/dbm.c: Rename the errno member of HTAB.
+
+	* hash/hash.h: Rename the errno member of HTAB to local_errno to
+	avoid a collision with a glibc macro.
+
+	* hash/hash.c: Rename the errno member of HTAB to local_errno to
+	avoid a collision with a glibc macro.
+
+Mon Nov 11 17:01:29 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* db2: overflow_page fixes, __P redef
+	* db2 tests: better alternate dictionary support
+
+	Tue Oct  8 22:55:01 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* hash/hash.h (DEF_BUCKET_SIZE, DEF_SEGSIZE): now derived from
+ 	DEF_BUCKET_SHIFT and DEF_SEGSIZE_SHIFT respectively, for
+	consistency.
+
+	Tue Oct  8 22:43:26 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* hash/hash_page.c (__add_ovflpage, __add_bigpage): overflow_page
+ 	can return a 0 indicating a failure -- callers must check it
+	instead of corrupting the database.
+	(overflow_page): document apparent error return.
+
+	Fri Aug 30 20:05:57 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* test/dictionary: New file, list of garbage words.
+	* test/run.test (main): Use it if no other dictionary can be
+	found.  Set dictsize with size of dictionary.
+	(test12, test20): Skip if dictionary is too small.
+
+Wed Aug 28 17:25:10 1996  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add check for SIZEOF_INT.
+
+	* include/db.h: Check SIZEOF_INT rather than UINT_MAX; it's broken
+		under Ultrix.
+
+Thu Aug 22 23:13:32 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Add dummy rule for Makefiles.
+
+Wed Jul 31 03:35:47 1996  Tom Yu  <tlyu@mit.edu>
+
+	* obj/Makefile.in: Add -Dfoo=my_foo when compiling replacement
+		functions (so that the redefinitions in db-int.h take
+		effect).
+
+Mon Jul 29 23:24:22 1996  Tom Yu  <tlyu@mit.edu>
+
+	* hash/hash.c, hash/hash_func.c, hash/hash_page.c: Add "static" to
+ 		some function defn's that need them; they were prototyped
+ 		as static but not defined as static.
+
+Fri Jul 26 00:41:45 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (install): Add a blank install target to keep the
+		top-level "make install" happy.
+
+Tue Jul 23 16:08:43 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* hash/dbm.c: Copy elements from the datum to an internal
+	DBT. Handles case of differences in size of size fields.
+
+Fri Jun 21 00:07:57 1996  Marc Horowitz  <marc@mit.edu>
+
+	* hash/dbm.c (delete, store): dbm_rdonly() doesn't exist on some
+ 	systems.  In addition, the handle is really a DB handle, so it
+ 	would break if it did exist.  Remove calls to it.
+
+Wed Apr 10 21:39:54 1996  Marc Horowitz  <marc@mit.edu>
+
+	* hash/hash_page.c (__addel): It is possible to damage a page if a
+ 	bigpair is added and there's not enough room.  Check to make sure
+	there's enough room before adding anything.
+
+	* hash/hash.c (hdestroy, cursor_delete): there were still a few
+ 	things in the hashp which weren't being freed, causing a small
+ 	memory leak.
+
+Sun Apr  7 01:40:54 1996  Marc Horowitz  <marc@mit.edu>
+
+	* clib/mk{,s}temp.c: renamed to accurately reflect the function
+        being provided (ultrix 4.2 has one, but not the other).
+
+	* [way too many files to list here]: rename pgno_t to db_pgno_t,
+        since this symbol is defined in <sys/types> on at least one OS to
+        a non-compatible type (irix 5.2 defines it as long; db wants it to
+        be u_int32_t).
+
+	* hash/dbm.c, include/db-ndbm.h: use and reference the compat
+        ndbm.h file
+
+	* btree/bt_open.c, hash/hash.c, hash/hash_page.c,
+        include/db-int.h, include/db.h: build fixes - use configure to set
+        db internal cpp symbols for endianness stuff, move __P definition
+        from db-int.h to db.h.
+
+	* configure.in, acconfig.h, Makefile.in, obj/configure.in,
+        obj/acconfig.in, obj/Makefile.in: rearrange the configure inputs
+        to deal properly with configure at the top level, and with a
+        multiarchitecture build using VPATH
+
+Sat Apr  6 16:43:26 1996  Marc Horowitz  <marc@mit.edu>
+
+	* obj/Makefile.in: random cleanup
+
+	* btree/*.c db/db.c hash/*.c mpool/mpool.c recno/*.c
+        test/SEQ_TEST/t.c test/dbtest.c test/*/*.c: use "db-int.h" instead
+        of "db.h".
+
+	* include/db.h, include/db-int.h: rototilled to be portable and
+        sensible, using configure whenever possible.
+
+	* btree/*.c db/db.c hash/*.c mpool/mpool.c recno/*.c
+        test/SEQ_TEST/t.c test/dbtest.c test/*/*.c: use "db.h" instead of
+        <db.h>.
+
+	* hash/hash.h, btree/btree.h, mpool/mpool.c: #include "mpool.h"
+        instead of <mpool.h>.
+
+	* test/hash1.tests/thash4.c: remove unused and nonportable
+        <sys/timeb.h>
+
+	* test/hash2.tests/bigtest.c: replace <malloc.h> with <stdlib.h>
+
+	* clib/memmove.c: remove <sys/cdefs.h>
+
+	* mpool/mpool.c, mpool/mpool.h, hash/hash.h, include/db-queue.h:
+        include "db-queue.h" instead of <sys/queue.h>, since it's not part
+        of any OS standard.
+
+	* obj/*: first attempt at autoconfiscation
+
+	* test/hash1.tests/driver2.c (main), test/hash1.tests/tseq.c
+        (main): replace berkeley memoryisms with ansi ones.
+
+	* btree/bt_open.c (tmp): use sprintf instead of snprintf().
+	conditionalize signal stuff on SIG_BLOCK instead of using special
+	magic in a header file.
+
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/Makefile.in b/mechglue/src/plugins/kdb/db2/libdb2/Makefile.in
new file mode 100644
index 000000000..5e53de423
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/Makefile.in
@@ -0,0 +1,41 @@
+thisconfigdir=.
+myfulldir=plugins/kdb/db2/libdb2
+mydir=.
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
+LOCAL_SUBDIRS=hash btree db mpool recno clib test
+
+LIBBASE=db
+LIBMAJOR=1
+LIBMINOR=1
+STOBJLISTS=hash/OBJS.ST btree/OBJS.ST db/OBJS.ST mpool/OBJS.ST \
+	recno/OBJS.ST clib/OBJS.ST
+SUBDIROBJLISTS=$(STOBJLISTS)
+RELDIR=../plugins/kdb/db2/libdb2
+
+HDRDIR=$(BUILDTOP)/include
+HDRS =	$(HDRDIR)/db.h $(HDRDIR)/db-config.h $(HDRDIR)/db-ndbm.h
+
+all-unix:: includes all-libs
+all-prerecurse: include/config.h include/db-config.h
+clean-unix:: clean-libs clean-includes
+
+includes:: $(HDRS)
+
+$(HDRDIR)/db.h: $(srcdir)/include/db.h
+	$(CP) $(srcdir)/include/db.h $@
+$(HDRDIR)/db-config.h: include/db-config.h
+	$(CP) include/db-config.h $@
+$(HDRDIR)/db-ndbm.h: $(srcdir)/include/db-ndbm.h
+	$(CP) $(srcdir)/include/db-ndbm.h $@
+
+include/config.h include/db-config.h: include/generated.stmp
+include/generated.stmp: $(srcdir)/include/config.h.in $(srcdir)/include/db-config.h.in
+	cd $(thisconfigdir) && $(SHELL) config.status
+$(srcdir)/include/config.h.in: @MAINT@ $(srcdir)/include/autoconf.stmp
+$(srcdir)/include/autoconf.stmp: $(srcdir)/configure.in $(SRCTOP)/aclocal.m4
+	cd $(srcdir) && $(AUTOHEADER) --include=$(CONFIG_RELTOPDIR) $(AUTOHEADERFLAGS)
+	touch $(srcdir)/include/autoconf.stmp
+
+clean-includes::
+	$(RM) $(HDRS) include/*.stmp
+# @lib_frag@
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/Makefile.inc b/mechglue/src/plugins/kdb/db2/libdb2/Makefile.inc
new file mode 100644
index 000000000..77af9c512
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/Makefile.inc
@@ -0,0 +1,10 @@
+#	@(#)Makefile.inc	8.2 (Berkeley) 2/21/94
+#
+CFLAGS+=-D__DBINTERFACE_PRIVATE
+
+.include "${.CURDIR}/db/btree/Makefile.inc"
+.include "${.CURDIR}/db/db/Makefile.inc"
+.include "${.CURDIR}/db/hash/Makefile.inc"
+.include "${.CURDIR}/db/man/Makefile.inc"
+.include "${.CURDIR}/db/mpool/Makefile.inc"
+.include "${.CURDIR}/db/recno/Makefile.inc"
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/README b/mechglue/src/plugins/kdb/db2/libdb2/README
new file mode 100644
index 000000000..70118bef5
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/README
@@ -0,0 +1,17 @@
+			  IMPORTANT NOTICE:
+
+This directory contains code of somewhat unknown origin that is
+INCOMPATIBLE with both Berkeley DB 1.85 and Sleepycat DB 2.x.  Do NOT
+contact Sleepycat regarding bugs in code found here; they do not
+appreciate it.  All bug reports about this code should go to the MIT
+Kerberos team via krb5-send-pr or email to krb5-bugs@mit.edu, as
+usual.
+
+It is believed that this "db" code originated from Berkeley DB 1.85
+and was further modified by Cygnus and the MIT Kerberos team.  Some
+significant changes to the hash code occured at some point.
+
+The file README.db2 contains the README file provided with the
+2.0-alpha release of Berkeley/Sleepycat DB, which may contain
+marginally useful information.  It is not known at this time how well
+this code matches that of the 2.0-alpha release.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/README.NOT.SLEEPYCAT.DB b/mechglue/src/plugins/kdb/db2/libdb2/README.NOT.SLEEPYCAT.DB
new file mode 100644
index 000000000..112454e94
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/README.NOT.SLEEPYCAT.DB
@@ -0,0 +1,2 @@
+THIS IS NOT THE SLEEPYCAT DB.
+Please see the README file for more information.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/README.db2 b/mechglue/src/plugins/kdb/db2/libdb2/README.db2
new file mode 100644
index 000000000..5700b7393
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/README.db2
@@ -0,0 +1,41 @@
+#	@(#)README	8.28 (Berkeley) 11/2/95
+
+This is version 2.0-ALPHA of the Berkeley DB code.
+THIS IS A PRELIMINARY RELEASE.
+
+For information on compiling and installing this software, see the file
+PORT/README.
+
+Newer versions of this software will periodically be made available by
+anonymous ftp from ftp.cs.berkeley.edu:ucb/4bsd/db.tar.{Z,gz} and from
+ftp.harvard.edu:margo/db.tar.{Z,gz}.  If you want to receive announcements
+of future releases of this software, send email to the contact address
+below.
+
+Email questions may be addressed to dbinfo@eecs.harvard.edu.
+
+============================================
+Distribution contents:
+
+README		This file.
+CHANGELOG	List of changes, per version.
+btree		B+tree access method.
+db		The db_open interface routine.
+docs		Various USENIX papers, and the formatted manual pages.
+hash		Extended linear hashing access method.
+lock		Lock manager.
+log		Log manager.
+man		The unformatted manual pages.
+mpool		The buffer manager support.
+mutex		Mutex support.
+recno		The fixed/variable length record access method.
+test		Test package.
+txn		Transaction support.
+
+============================================
+Debugging:
+
+If you're running a memory checker (e.g. Purify) on DB, make sure that
+you recompile it with "-DPURIFY" in the CFLAGS, first.  By default,
+allocated pages are not initialized by the DB code, and they will show
+up as reads of uninitialized memory in the buffer write routines.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/Makefile.in b/mechglue/src/plugins/kdb/db2/libdb2/btree/Makefile.in
new file mode 100644
index 000000000..52243b460
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/Makefile.in
@@ -0,0 +1,14 @@
+thisconfigdir=./..
+myfulldir=plugins/kdb/db2/libdb2/btree
+mydir=btree
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..$(S)..
+STLIBOBJS=	bt_close.o bt_conv.o bt_debug.o bt_delete.o bt_get.o \
+		bt_open.o bt_overflow.o bt_page.o bt_put.o bt_search.o \
+		bt_seq.o bt_split.o bt_utils.o
+
+LOCALINCLUDES=	-I. -I$(srcdir)/../include -I../include -I$(srcdir)/../mpool \
+		-I$(srcdir)/../db
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+# @libobj_frag@
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/Makefile.inc b/mechglue/src/plugins/kdb/db2/libdb2/btree/Makefile.inc
new file mode 100644
index 000000000..8ed76494a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/Makefile.inc
@@ -0,0 +1,7 @@
+#	@(#)Makefile.inc	8.2 (Berkeley) 7/14/94
+
+.PATH: ${.CURDIR}/db/btree
+
+SRCS+=	bt_close.c bt_conv.c bt_debug.c bt_delete.c bt_get.c bt_open.c \
+	bt_overflow.c bt_page.c bt_put.c bt_search.c bt_seq.c bt_split.c \
+	bt_utils.c
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_close.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_close.c
new file mode 100644
index 000000000..11be13411
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_close.c
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_close.c	8.7 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+static int bt_meta __P((BTREE *));
+
+/*
+ * BT_CLOSE -- Close a btree.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__bt_close(dbp)
+	DB *dbp;
+{
+	BTREE *t;
+	int fd;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/* Sync the tree. */
+	if (__bt_sync(dbp, 0) == RET_ERROR)
+		return (RET_ERROR);
+
+	/* Close the memory pool. */
+	if (mpool_close(t->bt_mp) == RET_ERROR)
+		return (RET_ERROR);
+
+	/* Free random memory. */
+	if (t->bt_cursor.key.data != NULL) {
+		free(t->bt_cursor.key.data);
+		t->bt_cursor.key.size = 0;
+		t->bt_cursor.key.data = NULL;
+	}
+	if (t->bt_rkey.data) {
+		free(t->bt_rkey.data);
+		t->bt_rkey.size = 0;
+		t->bt_rkey.data = NULL;
+	}
+	if (t->bt_rdata.data) {
+		free(t->bt_rdata.data);
+		t->bt_rdata.size = 0;
+		t->bt_rdata.data = NULL;
+	}
+
+	fd = t->bt_fd;
+	free(t);
+	free(dbp);
+	return (close(fd) ? RET_ERROR : RET_SUCCESS);
+}
+
+/*
+ * BT_SYNC -- sync the btree to disk.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_sync(dbp, flags)
+	const DB *dbp;
+	u_int flags;
+{
+	BTREE *t;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/* Sync doesn't currently take any flags. */
+	if (flags != 0) {
+		errno = EINVAL;
+		return (RET_ERROR);
+	}
+
+	if (F_ISSET(t, B_INMEM | B_RDONLY)
+	    || !F_ISSET(t, B_MODIFIED | B_METADIRTY))
+		return (RET_SUCCESS);
+
+	if (F_ISSET(t, B_METADIRTY) && bt_meta(t) == RET_ERROR)
+		return (RET_ERROR);
+
+	if ((status = mpool_sync(t->bt_mp)) == RET_SUCCESS)
+		F_CLR(t, B_MODIFIED);
+
+	return (status);
+}
+
+/*
+ * BT_META -- write the tree meta data to disk.
+ *
+ * Parameters:
+ *	t:	tree
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_meta(t)
+	BTREE *t;
+{
+	BTMETA m;
+	void *p;
+
+	if ((p = mpool_get(t->bt_mp, P_META, 0)) == NULL)
+		return (RET_ERROR);
+
+	/* Fill in metadata. */
+	m.magic = BTREEMAGIC;
+	m.version = BTREEVERSION;
+	m.psize = t->bt_psize;
+	m.free = t->bt_free;
+	m.nrecs = t->bt_nrecs;
+	m.flags = F_ISSET(t, SAVEMETA);
+
+	memmove(p, &m, sizeof(BTMETA));
+	mpool_put(t->bt_mp, p, MPOOL_DIRTY);
+	return (RET_SUCCESS);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_conv.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_conv.c
new file mode 100644
index 000000000..6cfa216ca
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_conv.c
@@ -0,0 +1,221 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_conv.c	8.5 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+static void mswap __P((PAGE *));
+
+/*
+ * __BT_BPGIN, __BT_BPGOUT --
+ *	Convert host-specific number layout to/from the host-independent
+ *	format stored on disk.
+ *
+ * Parameters:
+ *	t:	tree
+ *	pg:	page number
+ *	h:	page to convert
+ */
+void
+__bt_pgin(t, pg, pp)
+	void *t;
+	db_pgno_t pg;
+	void *pp;
+{
+	PAGE *h;
+	indx_t i, top;
+	u_char flags;
+	char *p;
+
+	if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
+		return;
+	if (pg == P_META) {
+		mswap(pp);
+		return;
+	}
+
+	h = pp;
+	M_32_SWAP(h->pgno);
+	M_32_SWAP(h->prevpg);
+	M_32_SWAP(h->nextpg);
+	M_32_SWAP(h->flags);
+	M_16_SWAP(h->lower);
+	M_16_SWAP(h->upper);
+
+	top = NEXTINDEX(h);
+	if ((h->flags & P_TYPE) == P_BINTERNAL)
+		for (i = 0; i < top; i++) {
+			M_16_SWAP(h->linp[i]);
+			p = (char *)GETBINTERNAL(h, i);
+			P_32_SWAP(p);
+			p += sizeof(u_int32_t);
+			P_32_SWAP(p);
+			p += sizeof(db_pgno_t);
+			if (*(u_char *)p & P_BIGKEY) {
+				p += sizeof(u_char);
+				P_32_SWAP(p);
+				p += sizeof(db_pgno_t);
+				P_32_SWAP(p);
+			}
+		}
+	else if ((h->flags & P_TYPE) == P_BLEAF)
+		for (i = 0; i < top; i++) {
+			M_16_SWAP(h->linp[i]);
+			p = (char *)GETBLEAF(h, i);
+			P_32_SWAP(p);
+			p += sizeof(u_int32_t);
+			P_32_SWAP(p);
+			p += sizeof(u_int32_t);
+			flags = *(u_char *)p;
+			if (flags & (P_BIGKEY | P_BIGDATA)) {
+				p += sizeof(u_char);
+				if (flags & P_BIGKEY) {
+					P_32_SWAP(p);
+					p += sizeof(db_pgno_t);
+					P_32_SWAP(p);
+				}
+				if (flags & P_BIGDATA) {
+					p += sizeof(u_int32_t);
+					P_32_SWAP(p);
+					p += sizeof(db_pgno_t);
+					P_32_SWAP(p);
+				}
+			}
+		}
+}
+
+void
+__bt_pgout(t, pg, pp)
+	void *t;
+	db_pgno_t pg;
+	void *pp;
+{
+	PAGE *h;
+	indx_t i, top;
+	u_char flags;
+	char *p;
+
+	if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
+		return;
+	if (pg == P_META) {
+		mswap(pp);
+		return;
+	}
+
+	h = pp;
+	top = NEXTINDEX(h);
+	if ((h->flags & P_TYPE) == P_BINTERNAL)
+		for (i = 0; i < top; i++) {
+			p = (char *)GETBINTERNAL(h, i);
+			P_32_SWAP(p);
+			p += sizeof(u_int32_t);
+			P_32_SWAP(p);
+			p += sizeof(db_pgno_t);
+			if (*(u_char *)p & P_BIGKEY) {
+				p += sizeof(u_char);
+				P_32_SWAP(p);
+				p += sizeof(db_pgno_t);
+				P_32_SWAP(p);
+			}
+			M_16_SWAP(h->linp[i]);
+		}
+	else if ((h->flags & P_TYPE) == P_BLEAF)
+		for (i = 0; i < top; i++) {
+			p = (char *)GETBLEAF(h, i);
+			P_32_SWAP(p);
+			p += sizeof(u_int32_t);
+			P_32_SWAP(p);
+			p += sizeof(u_int32_t);
+			flags = *(u_char *)p;
+			if (flags & (P_BIGKEY | P_BIGDATA)) {
+				p += sizeof(u_char);
+				if (flags & P_BIGKEY) {
+					P_32_SWAP(p);
+					p += sizeof(db_pgno_t);
+					P_32_SWAP(p);
+				}
+				if (flags & P_BIGDATA) {
+					p += sizeof(u_int32_t);
+					P_32_SWAP(p);
+					p += sizeof(db_pgno_t);
+					P_32_SWAP(p);
+				}
+			}
+			M_16_SWAP(h->linp[i]);
+		}
+
+	M_32_SWAP(h->pgno);
+	M_32_SWAP(h->prevpg);
+	M_32_SWAP(h->nextpg);
+	M_32_SWAP(h->flags);
+	M_16_SWAP(h->lower);
+	M_16_SWAP(h->upper);
+}
+
+/*
+ * MSWAP -- Actually swap the bytes on the meta page.
+ *
+ * Parameters:
+ *	p:	page to convert
+ */
+static void
+mswap(pg)
+	PAGE *pg;
+{
+	char *p;
+
+	p = (char *)pg;
+	P_32_SWAP(p);		/* magic */
+	p += sizeof(u_int32_t);
+	P_32_SWAP(p);		/* version */
+	p += sizeof(u_int32_t);
+	P_32_SWAP(p);		/* psize */
+	p += sizeof(u_int32_t);
+	P_32_SWAP(p);		/* free */
+	p += sizeof(u_int32_t);
+	P_32_SWAP(p);		/* nrecs */
+	p += sizeof(u_int32_t);
+	P_32_SWAP(p);		/* flags */
+	p += sizeof(u_int32_t);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_debug.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_debug.c
new file mode 100644
index 000000000..d36256b3a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_debug.c
@@ -0,0 +1,377 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994, 1995
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_debug.c	8.6 (Berkeley) 1/9/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+#if defined(DEBUG) || defined(STATISTICS)
+
+static FILE *tracefp;
+
+/*
+ * __bt_dinit --
+ *	initialize debugging.
+ */
+static void
+__bt_dinit()
+{
+	static int first = 1;
+	char buf[1024];
+
+	if (!first)
+		return;
+	first = 0;
+
+#ifndef TRACE_TO_STDERR
+	if ((tracefp = fopen("/tmp/__bt_debug", "w")) != NULL)
+		return;
+#endif
+	tracefp = stderr;
+}
+#endif
+
+#ifdef DEBUG
+/*
+ * __bt_dump --
+ *	dump the tree
+ *
+ * Parameters:
+ *	dbp:	pointer to the DB
+ */
+int
+__bt_dump(dbp)
+	DB *dbp;
+{
+	BTREE *t;
+	PAGE *h;
+	db_pgno_t i;
+	char *sep;
+
+	__bt_dinit();
+
+	t = dbp->internal;
+	(void)fprintf(tracefp, "%s: pgsz %d",
+	    F_ISSET(t, B_INMEM) ? "memory" : "disk", t->bt_psize);
+	if (F_ISSET(t, R_RECNO))
+		(void)fprintf(tracefp, " keys %lu", t->bt_nrecs);
+#undef X
+#define	X(flag, name) \
+	if (F_ISSET(t, flag)) { \
+		(void)fprintf(tracefp, "%s%s", sep, name); \
+		sep = ", "; \
+	}
+	if (t->flags != 0) {
+		sep = " flags (";
+		X(R_FIXLEN,	"FIXLEN");
+		X(B_INMEM,	"INMEM");
+		X(B_NODUPS,	"NODUPS");
+		X(B_RDONLY,	"RDONLY");
+		X(R_RECNO,	"RECNO");
+		X(B_METADIRTY,"METADIRTY");
+		(void)fprintf(tracefp, ")\n");
+	}
+#undef X
+	for (i = P_ROOT; i < t->bt_mp->npages &&
+	    (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i)
+		__bt_dpage(dbp, h);
+	(void)fflush(tracefp);
+	return (0);
+}
+
+/*
+ * BT_DMPAGE -- Dump the meta page
+ *
+ * Parameters:
+ *	h:	pointer to the PAGE
+ */
+int
+__bt_dmpage(h)
+	PAGE *h;
+{
+	BTMETA *m;
+	char *sep;
+
+	__bt_dinit();
+
+	m = (BTMETA *)h;
+	(void)fprintf(tracefp, "magic %lx\n", m->magic);
+	(void)fprintf(tracefp, "version %lu\n", m->version);
+	(void)fprintf(tracefp, "psize %lu\n", m->psize);
+	(void)fprintf(tracefp, "free %lu\n", m->free);
+	(void)fprintf(tracefp, "nrecs %lu\n", m->nrecs);
+	(void)fprintf(tracefp, "flags %lu", m->flags);
+#undef X
+#define	X(flag, name) \
+	if (m->flags & flag) { \
+		(void)fprintf(tracefp, "%s%s", sep, name); \
+		sep = ", "; \
+	}
+	if (m->flags) {
+		sep = " (";
+		X(B_NODUPS,	"NODUPS");
+		X(R_RECNO,	"RECNO");
+		(void)fprintf(tracefp, ")");
+	}
+	(void)fprintf(tracefp, "\n");
+	(void)fflush(tracefp);
+	return (0);
+}
+
+/*
+ * BT_DNPAGE -- Dump the page
+ *
+ * Parameters:
+ *	n:	page number to dump.
+ */
+int
+__bt_dnpage(dbp, pgno)
+	DB *dbp;
+	db_pgno_t pgno;
+{
+	BTREE *t;
+	PAGE *h;
+
+	__bt_dinit();
+
+	t = dbp->internal;
+	if ((h = mpool_get(t->bt_mp, pgno, MPOOL_IGNOREPIN)) != NULL)
+		__bt_dpage(dbp, h);
+	(void)fflush(tracefp);
+	return (0);
+}
+
+/*
+ * BT_DPAGE -- Dump the page
+ *
+ * Parameters:
+ *	h:	pointer to the PAGE
+ */
+int
+__bt_dpage(dbp, h)
+	DB *dbp;
+	PAGE *h;
+{
+	BINTERNAL *bi;
+	BLEAF *bl;
+	RINTERNAL *ri;
+	RLEAF *rl;
+	u_long pgsize;
+	indx_t cur, top, lim;
+	char *sep;
+
+	__bt_dinit();
+
+	(void)fprintf(tracefp, "    page %d: (", h->pgno);
+#undef X
+#define	X(flag, name)							\
+	if (h->flags & flag) {						\
+		(void)fprintf(tracefp, "%s%s", sep, name);		\
+		sep = ", ";						\
+	}
+	sep = "";
+	X(P_BINTERNAL,	"BINTERNAL")		/* types */
+	X(P_BLEAF,	"BLEAF")
+	X(P_RINTERNAL,	"RINTERNAL")		/* types */
+	X(P_RLEAF,	"RLEAF")
+	X(P_OVERFLOW,	"OVERFLOW")
+	X(P_PRESERVE,	"PRESERVE");
+	(void)fprintf(tracefp, ")\n");
+#undef X
+
+	(void)fprintf(tracefp, "\tprev %2d next %2d", h->prevpg, h->nextpg);
+	if (h->flags & P_OVERFLOW)
+		return;
+
+	pgsize = ((BTREE *)dbp->internal)->bt_mp->pagesize;
+	lim = (pgsize - BTDATAOFF) / sizeof(indx_t);
+	top = NEXTINDEX(h);
+	lim = top > lim ? lim : top;
+	(void)fprintf(tracefp, " lower %3d upper %3d nextind %d\n",
+	    h->lower, h->upper, top);
+	for (cur = 0; cur < lim; cur++) {
+		(void)fprintf(tracefp, "\t[%03d] %4d ", cur, h->linp[cur]);
+		switch (h->flags & P_TYPE) {
+		case P_BINTERNAL:
+			bi = GETBINTERNAL(h, cur);
+			(void)fprintf(tracefp,
+			    "size %03d pgno %03d", bi->ksize, bi->pgno);
+			if (bi->flags & P_BIGKEY)
+				(void)fprintf(tracefp, " (indirect)");
+			else if (bi->ksize)
+				(void)fprintf(tracefp,
+				    " {%.*s}", (int)bi->ksize, bi->bytes);
+			break;
+		case P_RINTERNAL:
+			ri = GETRINTERNAL(h, cur);
+			(void)fprintf(tracefp, "entries %03d pgno %03d",
+				ri->nrecs, ri->pgno);
+			break;
+		case P_BLEAF:
+			bl = GETBLEAF(h, cur);
+			if (bl->flags & P_BIGKEY)
+				(void)fprintf(tracefp,
+				    "big key page %lu size %u/",
+				    *(db_pgno_t *)bl->bytes,
+				    *(u_int32_t *)(bl->bytes + sizeof(db_pgno_t)));
+			else if (bl->ksize)
+				(void)fprintf(tracefp, "%s/", bl->bytes);
+			if (bl->flags & P_BIGDATA)
+				(void)fprintf(tracefp,
+				    "big data page %lu size %u",
+				    *(db_pgno_t *)(bl->bytes + bl->ksize),
+				    *(u_int32_t *)(bl->bytes + bl->ksize +
+				    sizeof(db_pgno_t)));
+			else if (bl->dsize)
+				(void)fprintf(tracefp, "%.*s",
+				    (int)bl->dsize, bl->bytes + bl->ksize);
+			break;
+		case P_RLEAF:
+			rl = GETRLEAF(h, cur);
+			if (rl->flags & P_BIGDATA)
+				(void)fprintf(tracefp,
+				    "big data page %lu size %u",
+				    *(db_pgno_t *)rl->bytes,
+				    *(u_int32_t *)(rl->bytes + sizeof(db_pgno_t)));
+			else if (rl->dsize)
+				(void)fprintf(tracefp,
+				    "%.*s", (int)rl->dsize, rl->bytes);
+			break;
+		}
+		(void)fprintf(tracefp, "\n");
+	}
+	(void)fflush(tracefp);
+	return (0);
+}
+#endif
+
+#ifdef STATISTICS
+/*
+ * bt_stat --
+ *	Gather/print the tree statistics
+ *
+ * Parameters:
+ *	dbp:	pointer to the DB
+ */
+int
+__bt_stat(dbp)
+	DB *dbp;
+{
+	extern u_long bt_cache_hit, bt_cache_miss, bt_pfxsaved, bt_rootsplit;
+	extern u_long bt_sortsplit, bt_split;
+	BTREE *t;
+	PAGE *h;
+	db_pgno_t i, pcont, pinternal, pleaf;
+	u_long ifree, lfree, nkeys;
+	int levels;
+
+	__bt_dinit();
+
+	t = dbp->internal;
+	pcont = pinternal = pleaf = 0;
+	nkeys = ifree = lfree = 0;
+	for (i = P_ROOT; i < t->bt_mp->npages &&
+	    (h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i)
+		switch (h->flags & P_TYPE) {
+		case P_BINTERNAL:
+		case P_RINTERNAL:
+			++pinternal;
+			ifree += h->upper - h->lower;
+			break;
+		case P_BLEAF:
+		case P_RLEAF:
+			++pleaf;
+			lfree += h->upper - h->lower;
+			nkeys += NEXTINDEX(h);
+			break;
+		case P_OVERFLOW:
+			++pcont;
+			break;
+		}
+
+	/* Count the levels of the tree. */
+	for (i = P_ROOT, levels = 0 ;; ++levels) {
+		h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN);
+		if (h->flags & (P_BLEAF|P_RLEAF)) {
+			if (levels == 0)
+				levels = 1;
+			break;
+		}
+		i = F_ISSET(t, R_RECNO) ?
+		    GETRINTERNAL(h, 0)->pgno :
+		    GETBINTERNAL(h, 0)->pgno;
+	}
+
+	(void)fprintf(tracefp, "%d level%s with %ld keys",
+	    levels, levels == 1 ? "" : "s", nkeys);
+	if (F_ISSET(t, R_RECNO))
+		(void)fprintf(tracefp, " (%ld header count)", t->bt_nrecs);
+	(void)fprintf(tracefp,
+	    "\n%lu pages (leaf %ld, internal %ld, overflow %ld)\n",
+	    pinternal + pleaf + pcont, pleaf, pinternal, pcont);
+	(void)fprintf(tracefp, "%ld cache hits, %ld cache misses\n",
+	    bt_cache_hit, bt_cache_miss);
+	(void)fprintf(tracefp,
+	    "%ld splits (%ld root splits, %ld sort splits)\n",
+	    bt_split, bt_rootsplit, bt_sortsplit);
+	pleaf *= t->bt_psize - BTDATAOFF;
+	if (pleaf)
+		(void)fprintf(tracefp,
+		    "%.0f%% leaf fill (%ld bytes used, %ld bytes free)\n",
+		    ((double)(pleaf - lfree) / pleaf) * 100,
+		    pleaf - lfree, lfree);
+	pinternal *= t->bt_psize - BTDATAOFF;
+	if (pinternal)
+		(void)fprintf(tracefp,
+		    "%.0f%% internal fill (%ld bytes used, %ld bytes free\n",
+		    ((double)(pinternal - ifree) / pinternal) * 100,
+		    pinternal - ifree, ifree);
+	if (bt_pfxsaved)
+		(void)fprintf(tracefp, "prefix checking removed %lu bytes.\n",
+		    bt_pfxsaved);
+	(void)fflush(tracefp);
+	return (0);
+}
+#endif
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_delete.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_delete.c
new file mode 100644
index 000000000..d002a66ed
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_delete.c
@@ -0,0 +1,657 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_delete.c	8.13 (Berkeley) 7/28/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+static int __bt_bdelete __P((BTREE *, const DBT *));
+static int __bt_curdel __P((BTREE *, const DBT *, PAGE *, u_int));
+static int __bt_pdelete __P((BTREE *, PAGE *));
+static int __bt_relink __P((BTREE *, PAGE *));
+static int __bt_stkacq __P((BTREE *, PAGE **, CURSOR *));
+
+/*
+ * __bt_delete
+ *	Delete the item(s) referenced by a key.
+ *
+ * Return RET_SPECIAL if the key is not found.
+ */
+int
+__bt_delete(dbp, key, flags)
+	const DB *dbp;
+	const DBT *key;
+	u_int flags;
+{
+	BTREE *t;
+	CURSOR *c;
+	PAGE *h;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/* Check for change to a read-only tree. */
+	if (F_ISSET(t, B_RDONLY)) {
+		errno = EPERM;
+		return (RET_ERROR);
+	}
+
+	switch (flags) {
+	case 0:
+		status = __bt_bdelete(t, key);
+		break;
+	case R_CURSOR:
+		/*
+		 * If flags is R_CURSOR, delete the cursor.  Must already
+		 * have started a scan and not have already deleted it.
+		 */
+		c = &t->bt_cursor;
+		if (F_ISSET(c, CURS_INIT)) {
+			if (F_ISSET(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
+				return (RET_SPECIAL);
+			if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+				return (RET_ERROR);
+
+			/*
+			 * If the page is about to be emptied, we'll need to
+			 * delete it, which means we have to acquire a stack.
+			 */
+			if (NEXTINDEX(h) == 1)
+				if (__bt_stkacq(t, &h, &t->bt_cursor))
+					return (RET_ERROR);
+
+			status = __bt_dleaf(t, NULL, h, c->pg.index);
+
+			if (NEXTINDEX(h) == 0 && status == RET_SUCCESS) {
+				if (__bt_pdelete(t, h))
+					return (RET_ERROR);
+			} else
+				mpool_put(t->bt_mp,
+				    h, status == RET_SUCCESS ? MPOOL_DIRTY : 0);
+			break;
+		}
+		/* FALLTHROUGH */
+	default:
+		errno = EINVAL;
+		return (RET_ERROR);
+	}
+	if (status == RET_SUCCESS)
+		F_SET(t, B_MODIFIED);
+	return (status);
+}
+
+/*
+ * __bt_stkacq --
+ *	Acquire a stack so we can delete a cursor entry.
+ *
+ * Parameters:
+ *	  t:	tree
+ *	 hp:	pointer to current, pinned PAGE pointer
+ *	  c:	pointer to the cursor
+ *
+ * Returns:
+ *	0 on success, 1 on failure
+ */
+static int
+__bt_stkacq(t, hp, c)
+	BTREE *t;
+	PAGE **hp;
+	CURSOR *c;
+{
+	BINTERNAL *bi;
+	EPG *e;
+	EPGNO *parent;
+	PAGE *h;
+	indx_t idx;
+	db_pgno_t pgno;
+	recno_t nextpg, prevpg;
+	int exact, level;
+	
+	/*
+	 * Find the first occurrence of the key in the tree.  Toss the
+	 * currently locked page so we don't hit an already-locked page.
+	 */
+	h = *hp;
+	mpool_put(t->bt_mp, h, 0);
+	if ((e = __bt_search(t, &c->key, &exact)) == NULL)
+		return (1);
+	h = e->page;
+
+	/* See if we got it in one shot. */
+	if (h->pgno == c->pg.pgno)
+		goto ret;
+
+	/*
+	 * Move right, looking for the page.  At each move we have to move
+	 * up the stack until we don't have to move to the next page.  If
+	 * we have to change pages at an internal level, we have to fix the
+	 * stack back up.
+	 */
+	while (h->pgno != c->pg.pgno) {
+		if ((nextpg = h->nextpg) == P_INVALID)
+			break;
+		mpool_put(t->bt_mp, h, 0);
+
+		/* Move up the stack. */
+		for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
+			/* Get the parent page. */
+			if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+				return (1);
+
+			/* Move to the next index. */
+			if (parent->index != NEXTINDEX(h) - 1) {
+				idx = parent->index + 1;
+				BT_PUSH(t, h->pgno, idx);
+				break;
+			}
+			mpool_put(t->bt_mp, h, 0);
+		}
+
+		/* Restore the stack. */
+		while (level--) {
+			/* Push the next level down onto the stack. */
+			bi = GETBINTERNAL(h, idx);
+			pgno = bi->pgno;
+			BT_PUSH(t, pgno, 0);
+
+			/* Lose the currently pinned page. */
+			mpool_put(t->bt_mp, h, 0);
+
+			/* Get the next level down. */
+			if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
+				return (1);
+			idx = 0;
+		}
+		mpool_put(t->bt_mp, h, 0);
+		if ((h = mpool_get(t->bt_mp, nextpg, 0)) == NULL)
+			return (1);
+	}
+
+	if (h->pgno == c->pg.pgno)
+		goto ret;
+
+	/* Reacquire the original stack. */
+	mpool_put(t->bt_mp, h, 0);
+	if ((e = __bt_search(t, &c->key, &exact)) == NULL)
+		return (1);
+	h = e->page;
+
+	/*
+	 * Move left, looking for the page.  At each move we have to move
+	 * up the stack until we don't have to change pages to move to the
+	 * next page.  If we have to change pages at an internal level, we
+	 * have to fix the stack back up.
+	 */
+	while (h->pgno != c->pg.pgno) {
+		if ((prevpg = h->prevpg) == P_INVALID)
+			break;
+		mpool_put(t->bt_mp, h, 0);
+
+		/* Move up the stack. */
+		for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
+			/* Get the parent page. */
+			if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+				return (1);
+
+			/* Move to the next index. */
+			if (parent->index != 0) {
+				idx = parent->index - 1;
+				BT_PUSH(t, h->pgno, idx);
+				break;
+			}
+			mpool_put(t->bt_mp, h, 0);
+		}
+
+		/* Restore the stack. */
+		while (level--) {
+			/* Push the next level down onto the stack. */
+			bi = GETBINTERNAL(h, idx);
+			pgno = bi->pgno;
+
+			/* Lose the currently pinned page. */
+			mpool_put(t->bt_mp, h, 0);
+
+			/* Get the next level down. */
+			if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
+				return (1);
+
+			idx = NEXTINDEX(h) - 1;
+			BT_PUSH(t, pgno, idx);
+		}
+		mpool_put(t->bt_mp, h, 0);
+		if ((h = mpool_get(t->bt_mp, prevpg, 0)) == NULL)
+			return (1);
+	}
+	
+
+ret:	mpool_put(t->bt_mp, h, 0);
+	return ((*hp = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL);
+}
+
+/*
+ * __bt_bdelete --
+ *	Delete all key/data pairs matching the specified key.
+ *
+ * Parameters:
+ *	  t:	tree
+ *	key:	key to delete
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+static int
+__bt_bdelete(t, key)
+	BTREE *t;
+	const DBT *key;
+{
+	EPG *e;
+	PAGE *h;
+	int deleted, exact, redo;
+
+	deleted = 0;
+
+	/* Find any matching record; __bt_search pins the page. */
+loop:	if ((e = __bt_search(t, key, &exact)) == NULL)
+		return (deleted ? RET_SUCCESS : RET_ERROR);
+	if (!exact) {
+		mpool_put(t->bt_mp, e->page, 0);
+		return (deleted ? RET_SUCCESS : RET_SPECIAL);
+	}
+
+	/*
+	 * Delete forward, then delete backward, from the found key.  If
+	 * there are duplicates and we reach either side of the page, do
+	 * the key search again, so that we get them all.
+	 */
+	redo = 0;
+	h = e->page;
+	do {
+		if (__bt_dleaf(t, key, h, e->index)) {
+			mpool_put(t->bt_mp, h, 0);
+			return (RET_ERROR);
+		}
+		if (F_ISSET(t, B_NODUPS)) {
+			if (NEXTINDEX(h) == 0) {
+				if (__bt_pdelete(t, h))
+					return (RET_ERROR);
+			} else
+				mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+			return (RET_SUCCESS);
+		}
+		deleted = 1;
+	} while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
+
+	/* Check for right-hand edge of the page. */
+	if (e->index == NEXTINDEX(h))
+		redo = 1;
+
+	/* Delete from the key to the beginning of the page. */
+	while (e->index-- > 0) {
+		if (__bt_cmp(t, key, e) != 0)
+			break;
+		if (__bt_dleaf(t, key, h, e->index) == RET_ERROR) {
+			mpool_put(t->bt_mp, h, 0);
+			return (RET_ERROR);
+		}
+		if (e->index == 0)
+			redo = 1;
+	}
+
+	/* Check for an empty page. */
+	if (NEXTINDEX(h) == 0) {
+		if (__bt_pdelete(t, h))
+			return (RET_ERROR);
+		goto loop;
+	}
+
+	/* Put the page. */
+	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+	if (redo)
+		goto loop;
+	return (RET_SUCCESS);
+}
+
+/*
+ * __bt_pdelete --
+ *	Delete a single page from the tree.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	leaf page
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ *
+ * Side-effects:
+ *	mpool_put's the page
+ */
+static int
+__bt_pdelete(t, h)
+	BTREE *t;
+	PAGE *h;
+{
+	BINTERNAL *bi;
+	PAGE *pg;
+	EPGNO *parent;
+	indx_t cnt, idx, *ip, offset;
+	u_int32_t nksize;
+	char *from;
+
+	/*
+	 * Walk the parent page stack -- a LIFO stack of the pages that were
+	 * traversed when we searched for the page where the delete occurred.
+	 * Each stack entry is a page number and a page index offset.  The
+	 * offset is for the page traversed on the search.  We've just deleted
+	 * a page, so we have to delete the key from the parent page.
+	 *
+	 * If the delete from the parent page makes it empty, this process may
+	 * continue all the way up the tree.  We stop if we reach the root page
+	 * (which is never deleted, it's just not worth the effort) or if the
+	 * delete does not empty the page.
+	 */
+	while ((parent = BT_POP(t)) != NULL) {
+		/* Get the parent page. */
+		if ((pg = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+			return (RET_ERROR);
+		
+		idx = parent->index;
+		bi = GETBINTERNAL(pg, idx);
+
+		/* Free any overflow pages. */
+		if (bi->flags & P_BIGKEY &&
+		    __ovfl_delete(t, bi->bytes) == RET_ERROR) {
+			mpool_put(t->bt_mp, pg, 0);
+			return (RET_ERROR);
+		}
+
+		/*
+		 * Free the parent if it has only the one key and it's not the
+		 * root page. If it's the rootpage, turn it back into an empty
+		 * leaf page.
+		 */
+		if (NEXTINDEX(pg) == 1)
+			if (pg->pgno == P_ROOT) {
+				pg->lower = BTDATAOFF;
+				pg->upper = t->bt_psize;
+				pg->flags = P_BLEAF;
+			} else {
+				if (__bt_relink(t, pg) || __bt_free(t, pg))
+					return (RET_ERROR);
+				continue;
+			}
+		else {
+			/* Pack remaining key items at the end of the page. */
+			nksize = NBINTERNAL(bi->ksize);
+			from = (char *)pg + pg->upper;
+			memmove(from + nksize, from, (char *)bi - from);
+			pg->upper += nksize;
+
+			/* Adjust indices' offsets, shift the indices down. */
+			offset = pg->linp[idx];
+			for (cnt = idx, ip = &pg->linp[0]; cnt--; ++ip)
+				if (ip[0] < offset)
+					ip[0] += nksize;
+			for (cnt = NEXTINDEX(pg) - idx; --cnt; ++ip)
+				ip[0] = ip[1] < offset ? ip[1] + nksize : ip[1];
+			pg->lower -= sizeof(indx_t);
+		}
+
+		mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+		break;
+	}
+
+	/* Free the leaf page, as long as it wasn't the root. */
+	if (h->pgno == P_ROOT) {
+		mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+		return (RET_SUCCESS);
+	}
+	return (__bt_relink(t, h) || __bt_free(t, h));
+}
+
+/*
+ * __bt_dleaf --
+ *	Delete a single record from a leaf page.
+ *
+ * Parameters:
+ *	t:	tree
+ *    key:	referenced key
+ *	h:	page
+ *	idx:	index on page to delete
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_dleaf(t, key, h, idx)
+	BTREE *t;
+	const DBT *key;
+	PAGE *h;
+	u_int idx;
+{
+	BLEAF *bl;
+	indx_t cnt, *ip, offset;
+	u_int32_t nbytes;
+	void *to;
+	char *from;
+
+	/* If this record is referenced by the cursor, delete the cursor. */
+	if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+	    !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+	    t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index == idx &&
+	    __bt_curdel(t, key, h, idx))
+		return (RET_ERROR);
+
+	/* If the entry uses overflow pages, make them available for reuse. */
+	to = bl = GETBLEAF(h, idx);
+	if (bl->flags & P_BIGKEY && __ovfl_delete(t, bl->bytes) == RET_ERROR)
+		return (RET_ERROR);
+	if (bl->flags & P_BIGDATA &&
+	    __ovfl_delete(t, bl->bytes + bl->ksize) == RET_ERROR)
+		return (RET_ERROR);
+
+	/* Pack the remaining key/data items at the end of the page. */
+	nbytes = NBLEAF(bl);
+	from = (char *)h + h->upper;
+	memmove(from + nbytes, from, (char *)to - from);
+	h->upper += nbytes;
+
+	/* Adjust the indices' offsets, shift the indices down. */
+	offset = h->linp[idx];
+	for (cnt = idx, ip = &h->linp[0]; cnt--; ++ip)
+		if (ip[0] < offset)
+			ip[0] += nbytes;
+	for (cnt = NEXTINDEX(h) - idx; --cnt; ++ip)
+		ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
+	h->lower -= sizeof(indx_t);
+
+	/* If the cursor is on this page, adjust it as necessary. */
+	if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+	    !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+	    t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index > idx)
+		--t->bt_cursor.pg.index;
+
+	return (RET_SUCCESS);
+}
+
+/*
+ * __bt_curdel --
+ *	Delete the cursor.
+ *
+ * Parameters:
+ *	t:	tree
+ *    key:	referenced key (or NULL)
+ *	h:	page
+ *  idx:	idx on page to delete
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ */
+static int
+__bt_curdel(t, key, h, idx)
+	BTREE *t;
+	const DBT *key;
+	PAGE *h;
+	u_int idx;
+{
+	CURSOR *c;
+	EPG e;
+	PAGE *pg;
+	int curcopy, status;
+
+	/*
+	 * If there are duplicates, move forward or backward to one.
+	 * Otherwise, copy the key into the cursor area.
+	 */
+	c = &t->bt_cursor;
+	F_CLR(c, CURS_AFTER | CURS_BEFORE | CURS_ACQUIRE);
+
+	curcopy = 0;
+	if (!F_ISSET(t, B_NODUPS)) {
+		/*
+		 * We're going to have to do comparisons.  If we weren't
+		 * provided a copy of the key, i.e. the user is deleting
+		 * the current cursor position, get one.
+		 */
+		if (key == NULL) {
+			e.page = h;
+			e.index = idx;
+			if ((status = __bt_ret(t, &e,
+			    &c->key, &c->key, NULL, NULL, 1)) != RET_SUCCESS)
+				return (status);
+			curcopy = 1;
+			key = &c->key;
+		}
+		/* Check previous key, if not at the beginning of the page. */
+		if (idx > 0) { 
+			e.page = h;
+			e.index = idx - 1;
+			if (__bt_cmp(t, key, &e) == 0) {
+				F_SET(c, CURS_BEFORE);
+				goto dup2;
+			}
+		}
+		/* Check next key, if not at the end of the page. */
+		if (idx < NEXTINDEX(h) - 1) {
+			e.page = h;
+			e.index = idx + 1;
+			if (__bt_cmp(t, key, &e) == 0) {
+				F_SET(c, CURS_AFTER);
+				goto dup2;
+			}
+		}
+		/* Check previous key if at the beginning of the page. */
+		if (idx == 0 && h->prevpg != P_INVALID) {
+			if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+				return (RET_ERROR);
+			e.page = pg;
+			e.index = NEXTINDEX(pg) - 1;
+			if (__bt_cmp(t, key, &e) == 0) {
+				F_SET(c, CURS_BEFORE);
+				goto dup1;
+			}
+			mpool_put(t->bt_mp, pg, 0);
+		}
+		/* Check next key if at the end of the page. */
+		if (idx == NEXTINDEX(h) - 1 && h->nextpg != P_INVALID) {
+			if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+				return (RET_ERROR);
+			e.page = pg;
+			e.index = 0;
+			if (__bt_cmp(t, key, &e) == 0) {
+				F_SET(c, CURS_AFTER);
+dup1:				mpool_put(t->bt_mp, pg, 0);
+dup2:				c->pg.pgno = e.page->pgno;
+				c->pg.index = e.index;
+				return (RET_SUCCESS);
+			}
+			mpool_put(t->bt_mp, pg, 0);
+		}
+	}
+	e.page = h;
+	e.index = idx;
+	if (curcopy || (status =
+	    __bt_ret(t, &e, &c->key, &c->key, NULL, NULL, 1)) == RET_SUCCESS) {
+		F_SET(c, CURS_ACQUIRE);
+		return (RET_SUCCESS);
+	}
+	return (status);
+}
+
+/*
+ * __bt_relink --
+ *	Link around a deleted page.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	page to be deleted
+ */
+static int
+__bt_relink(t, h)
+	BTREE *t;
+	PAGE *h;
+{
+	PAGE *pg;
+
+	if (h->nextpg != P_INVALID) {
+		if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+			return (RET_ERROR);
+		pg->prevpg = h->prevpg;
+		mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+	}
+	if (h->prevpg != P_INVALID) {
+		if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+			return (RET_ERROR);
+		pg->nextpg = h->nextpg;
+		mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+	}
+	return (0);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_get.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_get.c
new file mode 100644
index 000000000..b6318211a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_get.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_get.c	8.6 (Berkeley) 7/20/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+/*
+ * __BT_GET -- Get a record from the btree.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *	key:	key to find
+ *	data:	data to return
+ *	flag:	currently unused
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+int
+__bt_get(dbp, key, data, flags)
+	const DB *dbp;
+	const DBT *key;
+	DBT *data;
+	u_int flags;
+{
+	BTREE *t;
+	EPG *e;
+	int exact, status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/* Get currently doesn't take any flags. */
+	if (flags) {
+		errno = EINVAL;
+		return (RET_ERROR);
+	}
+
+	if ((e = __bt_search(t, key, &exact)) == NULL)
+		return (RET_ERROR);
+	if (!exact) {
+		mpool_put(t->bt_mp, e->page, 0);
+		return (RET_SPECIAL);
+	}
+
+	status = __bt_ret(t, e, NULL, NULL, data, &t->bt_rdata, 0);
+
+	/*
+	 * If the user is doing concurrent access, we copied the
+	 * key/data, toss the page.
+	 */
+	if (F_ISSET(t, B_DB_LOCK))
+		mpool_put(t->bt_mp, e->page, 0);
+	else
+		t->bt_pinned = e->page;
+	return (status);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_open.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_open.c
new file mode 100644
index 000000000..3e4c67a4b
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_open.c
@@ -0,0 +1,476 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_open.c	8.11 (Berkeley) 11/2/95";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Implementation of btree access method for 4.4BSD.
+ *
+ * The design here was originally based on that of the btree access method
+ * used in the Postgres database system at UC Berkeley.  This implementation
+ * is wholly independent of the Postgres code.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+#ifdef DEBUG
+#undef	MINPSIZE
+#define	MINPSIZE	128
+#endif
+
+static int byteorder __P((void));
+static int nroot __P((BTREE *));
+static int tmp __P((void));
+
+/*
+ * __BT_OPEN -- Open a btree.
+ *
+ * Creates and fills a DB struct, and calls the routine that actually
+ * opens the btree.
+ *
+ * Parameters:
+ *	fname:	filename (NULL for in-memory trees)
+ *	flags:	open flag bits
+ *	mode:	open permission bits
+ *	b:	BTREEINFO pointer
+ *
+ * Returns:
+ *	NULL on failure, pointer to DB on success.
+ *
+ */
+DB *
+__bt_open(fname, flags, mode, openinfo, dflags)
+	const char *fname;
+	int flags, mode, dflags;
+	const BTREEINFO *openinfo;
+{
+	struct stat sb;
+	BTMETA m;
+	BTREE *t;
+	BTREEINFO b;
+	DB *dbp;
+	db_pgno_t ncache;
+	ssize_t nr;
+	int machine_lorder;
+
+	t = NULL;
+
+	/*
+	 * Intention is to make sure all of the user's selections are okay
+	 * here and then use them without checking.  Can't be complete, since
+	 * we don't know the right page size, lorder or flags until the backing
+	 * file is opened.  Also, the file's page size can cause the cachesize
+	 * to change.
+	 */
+	machine_lorder = byteorder();
+	if (openinfo) {
+		b = *openinfo;
+
+		/* Flags: R_DUP. */
+		if (b.flags & ~(R_DUP))
+			goto einval;
+
+		/*
+		 * Page size must be indx_t aligned and >= MINPSIZE.  Default
+		 * page size is set farther on, based on the underlying file
+		 * transfer size.
+		 */
+		if (b.psize &&
+		    (b.psize < MINPSIZE || b.psize > MAX_PAGE_OFFSET + 1 ||
+		    b.psize & (sizeof(indx_t) - 1)))
+			goto einval;
+
+		/* Minimum number of keys per page; absolute minimum is 2. */
+		if (b.minkeypage) {
+			if (b.minkeypage < 2)
+				goto einval;
+		} else
+			b.minkeypage = DEFMINKEYPAGE;
+
+		/* If no comparison, use default comparison and prefix. */
+		if (b.compare == NULL) {
+			b.compare = __bt_defcmp;
+			if (b.prefix == NULL)
+				b.prefix = __bt_defpfx;
+		}
+
+		if (b.lorder == 0)
+			b.lorder = machine_lorder;
+	} else {
+		b.compare = __bt_defcmp;
+		b.cachesize = 0;
+		b.flags = 0;
+		b.lorder = machine_lorder;
+		b.minkeypage = DEFMINKEYPAGE;
+		b.prefix = __bt_defpfx;
+		b.psize = 0;
+	}
+
+	/* Check for the ubiquitous PDP-11. */
+	if (b.lorder != DB_BIG_ENDIAN && b.lorder != DB_LITTLE_ENDIAN)
+		goto einval;
+
+	/* Allocate and initialize DB and BTREE structures. */
+	if ((t = (BTREE *)malloc(sizeof(BTREE))) == NULL)
+		goto err;
+	memset(t, 0, sizeof(BTREE));
+	t->bt_fd = -1;			/* Don't close unopened fd on error. */
+	t->bt_lorder = b.lorder;
+	t->bt_order = NOT;
+	t->bt_cmp = b.compare;
+	t->bt_pfx = b.prefix;
+	t->bt_rfd = -1;
+
+	if ((t->bt_dbp = dbp = (DB *)malloc(sizeof(DB))) == NULL)
+		goto err;
+	memset(t->bt_dbp, 0, sizeof(DB));
+	if (t->bt_lorder != machine_lorder)
+		F_SET(t, B_NEEDSWAP);
+
+	dbp->type = DB_BTREE;
+	dbp->internal = t;
+	dbp->close = __bt_close;
+	dbp->del = __bt_delete;
+	dbp->fd = __bt_fd;
+	dbp->get = __bt_get;
+	dbp->put = __bt_put;
+	dbp->seq = __bt_seq;
+	dbp->sync = __bt_sync;
+
+	/*
+	 * If no file name was supplied, this is an in-memory btree and we
+	 * open a backing temporary file.  Otherwise, it's a disk-based tree.
+	 */
+	if (fname) {
+		switch (flags & O_ACCMODE) {
+		case O_RDONLY:
+			F_SET(t, B_RDONLY);
+			break;
+		case O_RDWR:
+			break;
+		case O_WRONLY:
+		default:
+			goto einval;
+		}
+		
+		if ((t->bt_fd = open(fname, flags | O_BINARY, mode)) < 0)
+			goto err;
+
+	} else {
+		if ((flags & O_ACCMODE) != O_RDWR)
+			goto einval;
+		if ((t->bt_fd = tmp()) == -1)
+			goto err;
+		F_SET(t, B_INMEM);
+	}
+
+	if (fcntl(t->bt_fd, F_SETFD, 1) == -1)
+		goto err;
+
+	if (fstat(t->bt_fd, &sb))
+		goto err;
+	if (sb.st_size) {
+		if ((nr = read(t->bt_fd, &m, sizeof(BTMETA))) < 0)
+			goto err;
+		if (nr != sizeof(BTMETA))
+			goto eftype;
+
+		/*
+		 * Read in the meta-data.  This can change the notion of what
+		 * the lorder, page size and flags are, and, when the page size
+		 * changes, the cachesize value can change too.  If the user
+		 * specified the wrong byte order for an existing database, we
+		 * don't bother to return an error, we just clear the NEEDSWAP
+		 * bit.
+		 */
+		if (m.magic == BTREEMAGIC)
+			F_CLR(t, B_NEEDSWAP);
+		else {
+			F_SET(t, B_NEEDSWAP);
+			M_32_SWAP(m.magic);
+			M_32_SWAP(m.version);
+			M_32_SWAP(m.psize);
+			M_32_SWAP(m.free);
+			M_32_SWAP(m.nrecs);
+			M_32_SWAP(m.flags);
+		}
+		if (m.magic != BTREEMAGIC || m.version != BTREEVERSION)
+			goto eftype;
+		if (m.psize < MINPSIZE || m.psize > MAX_PAGE_OFFSET + 1 ||
+		    m.psize & (sizeof(indx_t) - 1))
+			goto eftype;
+		if (m.flags & ~SAVEMETA)
+			goto eftype;
+		b.psize = m.psize;
+		F_SET(t, m.flags);
+		t->bt_free = m.free;
+		t->bt_nrecs = m.nrecs;
+	} else {
+		/*
+		 * Set the page size to the best value for I/O to this file.
+		 * Don't overflow the page offset type.
+		 */
+		if (b.psize == 0) {
+			b.psize = sb.st_blksize;
+			if (b.psize < MINPSIZE)
+				b.psize = MINPSIZE;
+			if (b.psize > MAX_PAGE_OFFSET + 1)
+				b.psize = MAX_PAGE_OFFSET + 1;
+		}
+
+		/* Set flag if duplicates permitted. */
+		if (!(b.flags & R_DUP))
+			F_SET(t, B_NODUPS);
+
+		t->bt_free = P_INVALID;
+		t->bt_nrecs = 0;
+		F_SET(t, B_METADIRTY);
+	}
+
+	t->bt_psize = b.psize;
+
+	/* Set the cache size; must be a multiple of the page size. */
+	if (b.cachesize && b.cachesize & (b.psize - 1))
+		b.cachesize += (~b.cachesize & (b.psize - 1)) + 1;
+	if (b.cachesize < b.psize * MINCACHE)
+		b.cachesize = b.psize * MINCACHE;
+
+	/* Calculate number of pages to cache. */
+	ncache = (b.cachesize + t->bt_psize - 1) / t->bt_psize;
+
+	/*
+	 * The btree data structure requires that at least two keys can fit on
+	 * a page, but other than that there's no fixed requirement.  The user
+	 * specified a minimum number per page, and we translated that into the
+	 * number of bytes a key/data pair can use before being placed on an
+	 * overflow page.  This calculation includes the page header, the size
+	 * of the index referencing the leaf item and the size of the leaf item
+	 * structure.  Also, don't let the user specify a minkeypage such that
+	 * a key/data pair won't fit even if both key and data are on overflow
+	 * pages.
+	 */
+	t->bt_ovflsize = (t->bt_psize - BTDATAOFF) / b.minkeypage -
+	    (sizeof(indx_t) + NBLEAFDBT(0, 0));
+	if (t->bt_ovflsize < NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t))
+		t->bt_ovflsize =
+		    NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t);
+
+	/* Initialize the buffer pool. */
+	if ((t->bt_mp =
+	    mpool_open(NULL, t->bt_fd, t->bt_psize, ncache)) == NULL)
+		goto err;
+	if (!F_ISSET(t, B_INMEM))
+		mpool_filter(t->bt_mp, __bt_pgin, __bt_pgout, t);
+
+	/* Create a root page if new tree. */
+	if (nroot(t) == RET_ERROR)
+		goto err;
+
+	/* Global flags. */
+	if (dflags & DB_LOCK)
+		F_SET(t, B_DB_LOCK);
+	if (dflags & DB_SHMEM)
+		F_SET(t, B_DB_SHMEM);
+	if (dflags & DB_TXN)
+		F_SET(t, B_DB_TXN);
+
+	return (dbp);
+
+einval:	errno = EINVAL;
+	goto err;
+
+eftype:	errno = EFTYPE;
+	goto err;
+
+err:	if (t) {
+		if (t->bt_dbp)
+			free(t->bt_dbp);
+		if (t->bt_fd != -1)
+			(void)close(t->bt_fd);
+		free(t);
+	}
+	return (NULL);
+}
+
+/*
+ * NROOT -- Create the root of a new tree.
+ *
+ * Parameters:
+ *	t:	tree
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+static int
+nroot(t)
+	BTREE *t;
+{
+	PAGE *meta, *root;
+	db_pgno_t npg;
+
+	if ((root = mpool_get(t->bt_mp, 1, 0)) != NULL) {
+		if (root->lower == 0 &&
+		    root->pgno == 0 &&
+		    root->linp[0] == 0) {
+			mpool_delete(t->bt_mp, root);
+			errno = EINVAL;
+		} else {
+			mpool_put(t->bt_mp, root, 0);
+			return (RET_SUCCESS);
+		}
+	}
+	if (errno != EINVAL)		/* It's OK to not exist. */
+		return (RET_ERROR);
+	errno = 0;
+
+	if ((meta = mpool_new(t->bt_mp, &npg, MPOOL_PAGE_NEXT)) == NULL)
+		return (RET_ERROR);
+
+	if ((root = mpool_new(t->bt_mp, &npg, MPOOL_PAGE_NEXT)) == NULL)
+		return (RET_ERROR);
+
+	if (npg != P_ROOT)
+		return (RET_ERROR);
+	root->pgno = npg;
+	root->prevpg = root->nextpg = P_INVALID;
+	root->lower = BTDATAOFF;
+	root->upper = t->bt_psize;
+	root->flags = P_BLEAF;
+	memset(meta, 0, t->bt_psize);
+	mpool_put(t->bt_mp, meta, MPOOL_DIRTY);
+	mpool_put(t->bt_mp, root, MPOOL_DIRTY);
+	return (RET_SUCCESS);
+}
+
+static int
+tmp()
+{
+#ifdef SIG_BLOCK
+	sigset_t set, oset;
+#else
+	int oset;
+#endif
+	int fd;
+	char *envtmp;
+	char path[MAXPATHLEN];
+	static char fn[] = "/bt.XXXXXX";
+
+	envtmp = getenv("TMPDIR");
+
+	/* this used to be done with snprintf(), but since snprintf
+	   isn't in most operating systems, and overflow checking in
+	   this case is easy, this is what is done */
+
+	if (envtmp && ((strlen(envtmp)+sizeof(fn)+1) > sizeof(path)))
+	    return(-1);
+
+	(void)sprintf(path, "%s%s", (envtmp ? envtmp : "/tmp"), fn);
+
+#ifdef SIG_BLOCK
+	(void)sigfillset(&set);
+	(void)sigprocmask(SIG_BLOCK, &set, &oset);
+#else
+	oset = sigblock(~0);
+#endif
+	if ((fd = mkstemp(path)) != -1)
+		(void)unlink(path);
+#ifdef SIG_BLOCK
+	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
+#else
+	sigsetmask(oset);
+#endif
+#ifdef __CYGWIN32__
+      /* Ensure the fd is in binary mode. */
+      setmode(fd, O_BINARY);
+#endif /* __CYGWIN32__ */
+
+	return(fd);
+}
+
+static int
+byteorder()
+{
+	u_int32_t x;
+	u_char *p;
+
+	x = 0x01020304;
+	p = (u_char *)&x;
+	switch (*p) {
+	case 1:
+		return (DB_BIG_ENDIAN);
+	case 4:
+		return (DB_LITTLE_ENDIAN);
+	default:
+		return (0);
+	}
+}
+
+int
+__bt_fd(dbp)
+        const DB *dbp;
+{
+	BTREE *t;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/* In-memory database can't have a file descriptor. */
+	if (F_ISSET(t, B_INMEM)) {
+		errno = ENOENT;
+		return (-1);
+	}
+	return (t->bt_fd);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_overflow.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_overflow.c
new file mode 100644
index 000000000..8b1f59791
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_overflow.c
@@ -0,0 +1,228 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_overflow.c	8.5 (Berkeley) 7/16/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+/*
+ * Big key/data code.
+ *
+ * Big key and data entries are stored on linked lists of pages.  The initial
+ * reference is byte string stored with the key or data and is the page number
+ * and size.  The actual record is stored in a chain of pages linked by the
+ * nextpg field of the PAGE header.
+ *
+ * The first page of the chain has a special property.  If the record is used
+ * by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
+ * in the header.
+ *
+ * XXX
+ * A single DBT is written to each chain, so a lot of space on the last page
+ * is wasted.  This is a fairly major bug for some data sets.
+ */
+
+/*
+ * __OVFL_GET -- Get an overflow key/data item.
+ *
+ * Parameters:
+ *	t:	tree
+ *	p:	pointer to { db_pgno_t, u_int32_t }
+ *	buf:	storage address
+ *	bufsz:	storage size
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_get(t, p, ssz, buf, bufsz)
+	BTREE *t;
+	void *p;
+	size_t *ssz;
+	void **buf;
+	size_t *bufsz;
+{
+	PAGE *h;
+	db_pgno_t pg;
+	size_t nb, plen;
+	u_int32_t sz;
+
+	memmove(&pg, p, sizeof(db_pgno_t));
+	memmove(&sz, (char *)p + sizeof(db_pgno_t), sizeof(u_int32_t));
+	*ssz = sz;
+
+#ifdef DEBUG
+	if (pg == P_INVALID || sz == 0)
+		abort();
+#endif
+	/* Make the buffer bigger as necessary. */
+	if (*bufsz < sz) {
+		*buf = (char *)(*buf == NULL ? malloc(sz) : realloc(*buf, sz));
+		if (*buf == NULL)
+			return (RET_ERROR);
+		*bufsz = sz;
+	}
+
+	/*
+	 * Step through the linked list of pages, copying the data on each one
+	 * into the buffer.  Never copy more than the data's length.
+	 */
+	plen = t->bt_psize - BTDATAOFF;
+	for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
+		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+			return (RET_ERROR);
+
+		nb = MIN(sz, plen);
+		memmove(p, (char *)h + BTDATAOFF, nb);
+		mpool_put(t->bt_mp, h, 0);
+
+		if ((sz -= nb) == 0)
+			break;
+	}
+	return (RET_SUCCESS);
+}
+
+/*
+ * __OVFL_PUT -- Store an overflow key/data item.
+ *
+ * Parameters:
+ *	t:	tree
+ *	data:	DBT to store
+ *	pgno:	storage page number
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_put(t, dbt, pg)
+	BTREE *t;
+	const DBT *dbt;
+	db_pgno_t *pg;
+{
+	PAGE *h, *last;
+	void *p;
+	db_pgno_t npg;
+	size_t nb, plen;
+	u_int32_t sz;
+
+	/*
+	 * Allocate pages and copy the key/data record into them.  Store the
+	 * number of the first page in the chain.
+	 */
+	plen = t->bt_psize - BTDATAOFF;
+	for (last = NULL, p = dbt->data, sz = dbt->size;;
+	    p = (char *)p + plen, last = h) {
+		if ((h = __bt_new(t, &npg)) == NULL)
+			return (RET_ERROR);
+
+		h->pgno = npg;
+		h->nextpg = h->prevpg = P_INVALID;
+		h->flags = P_OVERFLOW;
+		h->lower = h->upper = 0;
+
+		nb = MIN(sz, plen);
+		memmove((char *)h + BTDATAOFF, p, nb);
+
+		if (last) {
+			last->nextpg = h->pgno;
+			mpool_put(t->bt_mp, last, MPOOL_DIRTY);
+		} else
+			*pg = h->pgno;
+
+		if ((sz -= nb) == 0) {
+			mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+			break;
+		}
+	}
+	return (RET_SUCCESS);
+}
+
+/*
+ * __OVFL_DELETE -- Delete an overflow chain.
+ *
+ * Parameters:
+ *	t:	tree
+ *	p:	pointer to { db_pgno_t, u_int32_t }
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_delete(t, p)
+	BTREE *t;
+	void *p;
+{
+	PAGE *h;
+	db_pgno_t pg;
+	size_t plen;
+	u_int32_t sz;
+
+	memmove(&pg, p, sizeof(db_pgno_t));
+	memmove(&sz, (char *)p + sizeof(db_pgno_t), sizeof(u_int32_t));
+
+#ifdef DEBUG
+	if (pg == P_INVALID || sz == 0)
+		abort();
+#endif
+	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+		return (RET_ERROR);
+
+	/* Don't delete chains used by internal pages. */
+	if (h->flags & P_PRESERVE) {
+		mpool_put(t->bt_mp, h, 0);
+		return (RET_SUCCESS);
+	}
+
+	/* Step through the chain, calling the free routine for each page. */
+	for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) {
+		pg = h->nextpg;
+		__bt_free(t, h);
+		if (sz <= plen)
+			break;
+		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+			return (RET_ERROR);
+	}
+	return (RET_SUCCESS);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_page.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_page.c
new file mode 100644
index 000000000..3663cf7f9
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_page.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_page.c	8.4 (Berkeley) 11/2/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+/*
+ * __bt_free --
+ *	Put a page on the freelist.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	page to free
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ *
+ * Side-effect:
+ *	mpool_put's the page.
+ */
+int
+__bt_free(t, h)
+	BTREE *t;
+	PAGE *h;
+{
+	/* Insert the page at the head of the free list. */
+	h->prevpg = P_INVALID;
+	h->nextpg = t->bt_free;
+	t->bt_free = h->pgno;
+	F_SET(t, B_METADIRTY);
+
+	/* Make sure the page gets written back. */
+	return (mpool_put(t->bt_mp, h, MPOOL_DIRTY));
+}
+
+/*
+ * __bt_new --
+ *	Get a new page, preferably from the freelist.
+ *
+ * Parameters:
+ *	t:	tree
+ *	npg:	storage for page number.
+ *
+ * Returns:
+ *	Pointer to a page, NULL on error.
+ */
+PAGE *
+__bt_new(t, npg)
+	BTREE *t;
+	db_pgno_t *npg;
+{
+	PAGE *h;
+
+	if (t->bt_free != P_INVALID &&
+	    (h = mpool_get(t->bt_mp, t->bt_free, 0)) != NULL) {
+		*npg = t->bt_free;
+		t->bt_free = h->nextpg;
+		F_SET(t, B_METADIRTY);
+		return (h);
+	}
+	return (mpool_new(t->bt_mp, npg, MPOOL_PAGE_NEXT));
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_put.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_put.c
new file mode 100644
index 000000000..f75ca9295
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_put.c
@@ -0,0 +1,328 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_put.c	8.8 (Berkeley) 7/26/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *));
+
+/*
+ * __BT_PUT -- Add a btree item to the tree.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *	key:	key
+ *	data:	data
+ *	flag:	R_NOOVERWRITE
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
+ *	tree and R_NOOVERWRITE specified.
+ */
+int
+__bt_put(dbp, key, data, flags)
+	const DB *dbp;
+	DBT *key;
+	const DBT *data;
+	u_int flags;
+{
+	BTREE *t;
+	DBT tkey, tdata;
+	EPG *e = 0;
+	PAGE *h;
+	indx_t idx, nxtindex;
+	db_pgno_t pg;
+	u_int32_t nbytes;
+	int dflags, exact, status;
+	char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/* Check for change to a read-only tree. */
+	if (F_ISSET(t, B_RDONLY)) {
+		errno = EPERM;
+		return (RET_ERROR);
+	}
+
+	switch (flags) {
+	case 0:
+	case R_NOOVERWRITE:
+		break;
+	case R_CURSOR:
+		/*
+		 * If flags is R_CURSOR, put the cursor.  Must already
+		 * have started a scan and not have already deleted it.
+		 */
+		if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+		    !F_ISSET(&t->bt_cursor,
+		        CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
+			break;
+		/* FALLTHROUGH */
+	default:
+		errno = EINVAL;
+		return (RET_ERROR);
+	}
+
+	/*
+	 * If the key/data pair won't fit on a page, store it on overflow
+	 * pages.  Only put the key on the overflow page if the pair are
+	 * still too big after moving the data to an overflow page.
+	 *
+	 * XXX
+	 * If the insert fails later on, the overflow pages aren't recovered.
+	 */
+	dflags = 0;
+	if (key->size + data->size > t->bt_ovflsize) {
+		if (key->size > t->bt_ovflsize) {
+			u_int32_t yuck_this_is_gross_code;
+storekey:		if (__ovfl_put(t, key, &pg) == RET_ERROR)
+				return (RET_ERROR);
+			tkey.data = kb;
+			tkey.size = NOVFLSIZE;
+			memmove(kb, &pg, sizeof(db_pgno_t));
+			yuck_this_is_gross_code = key->size;
+			if (yuck_this_is_gross_code != key->size)
+				abort ();
+			memmove(kb + sizeof(db_pgno_t),
+				&yuck_this_is_gross_code, sizeof(u_int32_t));
+			dflags |= P_BIGKEY;
+			key = &tkey;
+		}
+		if (key->size + data->size > t->bt_ovflsize) {
+			u_int32_t yuck_this_is_gross_code = data->size;
+			if (__ovfl_put(t, data, &pg) == RET_ERROR)
+				return (RET_ERROR);
+			tdata.data = db;
+			tdata.size = NOVFLSIZE;
+			memmove(db, &pg, sizeof(db_pgno_t));
+			if (yuck_this_is_gross_code != data->size)
+				abort ();
+			memmove(db + sizeof(db_pgno_t),
+				&yuck_this_is_gross_code, sizeof(u_int32_t));
+			dflags |= P_BIGDATA;
+			data = &tdata;
+		}
+		if (key->size + data->size > t->bt_ovflsize)
+			goto storekey;
+	}
+
+	/* Replace the cursor. */
+	if (flags == R_CURSOR) {
+		if ((h = mpool_get(t->bt_mp, t->bt_cursor.pg.pgno, 0)) == NULL)
+			return (RET_ERROR);
+		idx = t->bt_cursor.pg.index;
+		goto delete;
+	}
+
+	/*
+	 * Find the key to delete, or, the location at which to insert.
+	 * Bt_fast and __bt_search both pin the returned page.
+	 */
+	if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
+		if ((e = __bt_search(t, key, &exact)) == NULL)
+			return (RET_ERROR);
+	h = e->page;
+	idx = e->index;
+
+	/*
+	 * Add the key/data pair to the tree.  If an identical key is already
+	 * in the tree, and R_NOOVERWRITE is set, an error is returned.  If
+	 * R_NOOVERWRITE is not set, the key is either added (if duplicates are
+	 * permitted) or an error is returned.
+	 */
+	switch (flags) {
+	case R_NOOVERWRITE:
+		if (!exact)
+			break;
+		mpool_put(t->bt_mp, h, 0);
+		return (RET_SPECIAL);
+	default:
+		if (!exact || !F_ISSET(t, B_NODUPS))
+			break;
+		/*
+		 * !!!
+		 * Note, the delete may empty the page, so we need to put a
+		 * new entry into the page immediately.
+		 */
+delete:		if (__bt_dleaf(t, key, h, idx) == RET_ERROR) {
+			mpool_put(t->bt_mp, h, 0);
+			return (RET_ERROR);
+		}
+		break;
+	}
+
+	/*
+	 * If not enough room, or the user has put a ceiling on the number of
+	 * keys permitted in the page, split the page.  The split code will
+	 * insert the key and data and unpin the current page.  If inserting
+	 * into the offset array, shift the pointers up.
+	 */
+	nbytes = NBLEAFDBT(key->size, data->size);
+	if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
+		if ((status = __bt_split(t, h, key,
+		    data, dflags, nbytes, idx)) != RET_SUCCESS)
+			return (status);
+		goto success;
+	}
+
+	if (idx < (nxtindex = NEXTINDEX(h)))
+		memmove(h->linp + idx + 1, h->linp + idx,
+		    (nxtindex - idx) * sizeof(indx_t));
+	h->lower += sizeof(indx_t);
+
+	h->linp[idx] = h->upper -= nbytes;
+	dest = (char *)h + h->upper;
+	WR_BLEAF(dest, key, data, dflags);
+
+	/* If the cursor is on this page, adjust it as necessary. */
+	if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+	    !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+	    t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index >= idx)
+		++t->bt_cursor.pg.index;
+
+	if (t->bt_order == NOT) {
+		if (h->nextpg == P_INVALID) {
+			if (idx == NEXTINDEX(h) - 1) {
+				t->bt_order = FORWARD;
+				t->bt_last.index = idx;
+				t->bt_last.pgno = h->pgno;
+			}
+		} else if (h->prevpg == P_INVALID) {
+			if (idx == 0) {
+				t->bt_order = BACK;
+				t->bt_last.index = 0;
+				t->bt_last.pgno = h->pgno;
+			}
+		}
+	}
+
+	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+success:
+	if (flags == R_SETCURSOR)
+		__bt_setcur(t, e->page->pgno, e->index);
+
+	F_SET(t, B_MODIFIED);
+	return (RET_SUCCESS);
+}
+
+#ifdef STATISTICS
+u_long bt_cache_hit, bt_cache_miss;
+#endif
+
+/*
+ * BT_FAST -- Do a quick check for sorted data.
+ *
+ * Parameters:
+ *	t:	tree
+ *	key:	key to insert
+ *
+ * Returns:
+ * 	EPG for new record or NULL if not found.
+ */
+static EPG *
+bt_fast(t, key, data, exactp)
+	BTREE *t;
+	const DBT *key, *data;
+	int *exactp;
+{
+	PAGE *h;
+	u_int32_t nbytes;
+	int cmp;
+
+	if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
+		t->bt_order = NOT;
+		return (NULL);
+	}
+	t->bt_cur.page = h;
+	t->bt_cur.index = t->bt_last.index;
+
+	/*
+	 * If won't fit in this page or have too many keys in this page,
+	 * have to search to get split stack.
+	 */
+	nbytes = NBLEAFDBT(key->size, data->size);
+	if (h->upper - h->lower < nbytes + sizeof(indx_t))
+		goto miss;
+
+	if (t->bt_order == FORWARD) {
+		if (t->bt_cur.page->nextpg != P_INVALID)
+			goto miss;
+		if (t->bt_cur.index != NEXTINDEX(h) - 1)
+			goto miss;
+		if ((cmp = __bt_cmp(t, key, &t->bt_cur)) < 0)
+			goto miss;
+		t->bt_last.index = cmp ? ++t->bt_cur.index : t->bt_cur.index;
+	} else {
+		if (t->bt_cur.page->prevpg != P_INVALID)
+			goto miss;
+		if (t->bt_cur.index != 0)
+			goto miss;
+		if ((cmp = __bt_cmp(t, key, &t->bt_cur)) > 0)
+			goto miss;
+		t->bt_last.index = 0;
+	}
+	*exactp = cmp == 0;
+#ifdef STATISTICS
+	++bt_cache_hit;
+#endif
+	return (&t->bt_cur);
+
+miss:
+#ifdef STATISTICS
+	++bt_cache_miss;
+#endif
+	t->bt_order = NOT;
+	mpool_put(t->bt_mp, h, 0);
+	return (NULL);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_search.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_search.c
new file mode 100644
index 000000000..de7ab126f
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_search.c
@@ -0,0 +1,297 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_search.c	8.9 (Berkeley) 10/26/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+static int __bt_snext __P((BTREE *, PAGE *, const DBT *, int *));
+static int __bt_sprev __P((BTREE *, PAGE *, const DBT *, int *));
+
+/*
+ * __bt_search --
+ *	Search a btree for a key.
+ *
+ * Parameters:
+ *	t:	tree to search
+ *	key:	key to find
+ *	exactp:	pointer to exact match flag
+ *
+ * Returns:
+ *	The EPG for matching record, if any, or the EPG for the location
+ *	of the key, if it were inserted into the tree, is entered into
+ *	the bt_cur field of the tree.  A pointer to the field is returned.
+ */
+EPG *
+__bt_search(t, key, exactp)
+	BTREE *t;
+	const DBT *key;
+	int *exactp;
+{
+	PAGE *h;
+	indx_t base, idx, lim;
+	db_pgno_t pg;
+	int cmp;
+
+	BT_CLR(t);
+	for (pg = P_ROOT;;) {
+		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+			return (NULL);
+
+		/* Do a binary search on the current page. */
+		t->bt_cur.page = h;
+		for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
+			t->bt_cur.index = idx = base + (lim >> 1);
+			if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
+				if (h->flags & P_BLEAF) {
+					*exactp = 1;
+					return (&t->bt_cur);
+				}
+				goto next;
+			}
+			if (cmp > 0) {
+				base = idx + 1;
+				--lim;
+			}
+		}
+
+		/*
+		 * If it's a leaf page, we're almost done.  If no duplicates
+		 * are allowed, or we have an exact match, we're done.  Else,
+		 * it's possible that there were matching keys on this page,
+		 * which later deleted, and we're on a page with no matches
+		 * while there are matches on other pages.  If at the start or
+		 * end of a page, check the adjacent page.
+		 */
+		if (h->flags & P_BLEAF) {
+			if (!F_ISSET(t, B_NODUPS)) {
+				if (base == 0 &&
+				    h->prevpg != P_INVALID &&
+				    __bt_sprev(t, h, key, exactp))
+					return (&t->bt_cur);
+				if (base == NEXTINDEX(h) &&
+				    h->nextpg != P_INVALID &&
+				    __bt_snext(t, h, key, exactp))
+					return (&t->bt_cur);
+			}
+			*exactp = 0;
+			t->bt_cur.index = base;
+			return (&t->bt_cur);
+		}
+
+		/*
+		 * No match found.  Base is the smallest index greater than
+		 * key and may be zero or a last + 1 index.  If it's non-zero,
+		 * decrement by one, and record the internal page which should
+		 * be a parent page for the key.  If a split later occurs, the
+		 * inserted page will be to the right of the saved page.
+		 */
+		idx = base ? base - 1 : base;
+
+next:		BT_PUSH(t, h->pgno, idx);
+		pg = GETBINTERNAL(h, idx)->pgno;
+		mpool_put(t->bt_mp, h, 0);
+	}
+}
+
+/*
+ * __bt_snext --
+ *	Check for an exact match after the key.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	current page
+ *	key:	key
+ *	exactp:	pointer to exact match flag
+ *
+ * Returns:
+ *	If an exact match found.
+ */
+static int
+__bt_snext(t, h, key, exactp)
+	BTREE *t;
+	PAGE *h;
+	const DBT *key;
+	int *exactp;
+{
+	BINTERNAL *bi;
+	EPG e;
+	EPGNO *parent;
+	indx_t idx;
+	db_pgno_t pgno;
+	int level;
+
+	/*
+	 * Get the next page.  The key is either an exact
+	 * match, or not as good as the one we already have.
+	 */
+	if ((e.page = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+		return (0);
+	e.index = 0;
+	if (__bt_cmp(t, key, &e) != 0) {
+		mpool_put(t->bt_mp, e.page, 0);
+		return (0);
+	}
+	mpool_put(t->bt_mp, h, 0);
+	t->bt_cur = e;
+	*exactp = 1;
+
+	/*
+	 * Adjust the stack for the movement.
+	 *
+	 * Move up the stack.
+	 */
+	for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
+		/* Get the parent page. */
+		if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+			return (0);
+
+		/* Move to the next index. */
+		if (parent->index != NEXTINDEX(h) - 1) {
+			idx = parent->index + 1;
+			BT_PUSH(t, h->pgno, idx);
+			break;
+		}
+		mpool_put(t->bt_mp, h, 0);
+	}
+
+	/* Restore the stack. */
+	while (level--) {
+		/* Push the next level down onto the stack. */
+		bi = GETBINTERNAL(h, idx);
+		pgno = bi->pgno;
+		BT_PUSH(t, pgno, 0);
+
+		/* Lose the currently pinned page. */
+		mpool_put(t->bt_mp, h, 0);
+
+		/* Get the next level down. */
+		if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
+			return (0);
+		idx = 0;
+	}
+	mpool_put(t->bt_mp, h, 0);
+	return (1);
+}
+
+/*
+ * __bt_sprev --
+ *	Check for an exact match before the key.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	current page
+ *	key:	key
+ *	exactp:	pointer to exact match flag
+ *
+ * Returns:
+ *	If an exact match found.
+ */
+static int
+__bt_sprev(t, h, key, exactp)
+	BTREE *t;
+	PAGE *h;
+	const DBT *key;
+	int *exactp;
+{
+	BINTERNAL *bi;
+	EPG e;
+	EPGNO *parent;
+	indx_t idx;
+	db_pgno_t pgno;
+	int level;
+
+	/*
+	 * Get the previous page.  The key is either an exact
+	 * match, or not as good as the one we already have.
+	 */
+	if ((e.page = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+		return (0);
+	e.index = NEXTINDEX(e.page) - 1;
+	if (__bt_cmp(t, key, &e) != 0) {
+		mpool_put(t->bt_mp, e.page, 0);
+		return (0);
+	}
+
+	mpool_put(t->bt_mp, h, 0);
+	t->bt_cur = e;
+	*exactp = 1;
+
+	/*
+	 * Adjust the stack for the movement.
+	 *
+	 * Move up the stack.
+	 */
+	for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
+		/* Get the parent page. */
+		if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+			return (1);
+
+		/* Move to the next index. */
+		if (parent->index != 0) {
+			idx = parent->index - 1;
+			BT_PUSH(t, h->pgno, idx);
+			break;
+		}
+		mpool_put(t->bt_mp, h, 0);
+	}
+
+	/* Restore the stack. */
+	while (level--) {
+		/* Push the next level down onto the stack. */
+		bi = GETBINTERNAL(h, idx);
+		pgno = bi->pgno;
+
+		/* Lose the currently pinned page. */
+		mpool_put(t->bt_mp, h, 0);
+
+		/* Get the next level down. */
+		if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
+			return (1);
+
+		idx = NEXTINDEX(h) - 1;
+		BT_PUSH(t, pgno, idx);
+	}
+	mpool_put(t->bt_mp, h, 0);
+	return (1);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_seq.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_seq.c
new file mode 100644
index 000000000..bbfb9c6c6
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_seq.c
@@ -0,0 +1,901 @@
+/*
+ * Copyright (C) 2002 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_seq.c	8.9 (Berkeley) 6/20/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+static int __bt_first __P((BTREE *, const DBT *, EPG *, int *));
+static int __bt_seqadv __P((BTREE *, EPG *, int));
+static int __bt_seqset __P((BTREE *, EPG *, DBT *, int));
+
+/*
+ * Sequential scan support.
+ *
+ * The tree can be scanned sequentially, starting from either end of the
+ * tree or from any specific key.  A scan request before any scanning is
+ * done is initialized as starting from the least node.
+ */
+
+/*
+ * __bt_seq --
+ *	Btree sequential scan interface.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *	key:	key for positioning and return value
+ *	data:	data return value
+ *	flags:	R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+int
+__bt_seq(dbp, key, data, flags)
+	const DB *dbp;
+	DBT *key, *data;
+	u_int flags;
+{
+	BTREE *t;
+	EPG e;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/*
+	 * If scan unitialized as yet, or starting at a specific record, set
+	 * the scan to a specific key.  Both __bt_seqset and __bt_seqadv pin
+	 * the page the cursor references if they're successful.
+	 */
+	switch (flags) {
+	case R_NEXT:
+	case R_PREV:
+		if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
+			status = __bt_seqadv(t, &e, flags);
+			break;
+		}
+		/* FALLTHROUGH */
+	case R_FIRST:
+	case R_LAST:
+	case R_CURSOR:
+		status = __bt_seqset(t, &e, key, flags);
+		break;
+	default:
+		errno = EINVAL;
+		return (RET_ERROR);
+	}
+
+	if (status == RET_SUCCESS) {
+		__bt_setcur(t, e.page->pgno, e.index);
+
+		status =
+		    __bt_ret(t, &e, key, &t->bt_rkey, data, &t->bt_rdata, 0);
+
+		/*
+		 * If the user is doing concurrent access, we copied the
+		 * key/data, toss the page.
+		 */
+		if (F_ISSET(t, B_DB_LOCK))
+			mpool_put(t->bt_mp, e.page, 0);
+		else
+			t->bt_pinned = e.page;
+	}
+	return (status);
+}
+
+/*
+ * __bt_seqset --
+ *	Set the sequential scan to a specific key.
+ *
+ * Parameters:
+ *	t:	tree
+ *	ep:	storage for returned key
+ *	key:	key for initial scan position
+ *	flags:	R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
+ *
+ * Side effects:
+ *	Pins the page the cursor references.
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+static int
+__bt_seqset(t, ep, key, flags)
+	BTREE *t;
+	EPG *ep;
+	DBT *key;
+	int flags;
+{
+	PAGE *h;
+	db_pgno_t pg;
+	int exact;
+
+	/*
+	 * Find the first, last or specific key in the tree and point the
+	 * cursor at it.  The cursor may not be moved until a new key has
+	 * been found.
+	 */
+	switch (flags) {
+	case R_CURSOR:				/* Keyed scan. */
+		/*
+		 * Find the first instance of the key or the smallest key
+		 * which is greater than or equal to the specified key.
+		 */
+		if (key->data == NULL || key->size == 0) {
+			errno = EINVAL;
+			return (RET_ERROR);
+		}
+		return (__bt_first(t, key, ep, &exact));
+	case R_FIRST:				/* First record. */
+	case R_NEXT:
+		/* Walk down the left-hand side of the tree. */
+		for (pg = P_ROOT;;) {
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+
+			/* Check for an empty tree. */
+			if (NEXTINDEX(h) == 0) {
+				mpool_put(t->bt_mp, h, 0);
+				return (RET_SPECIAL);
+			}
+
+			if (h->flags & (P_BLEAF | P_RLEAF))
+				break;
+			pg = GETBINTERNAL(h, 0)->pgno;
+			mpool_put(t->bt_mp, h, 0);
+		}
+		ep->page = h;
+		ep->index = 0;
+		break;
+	case R_LAST:				/* Last record. */
+	case R_PREV:
+		/* Walk down the right-hand side of the tree. */
+		for (pg = P_ROOT;;) {
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+
+			/* Check for an empty tree. */
+			if (NEXTINDEX(h) == 0) {
+				mpool_put(t->bt_mp, h, 0);
+				return (RET_SPECIAL);
+			}
+
+			if (h->flags & (P_BLEAF | P_RLEAF))
+				break;
+			pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
+			mpool_put(t->bt_mp, h, 0);
+		}
+
+		ep->page = h;
+		ep->index = NEXTINDEX(h) - 1;
+		break;
+	}
+	return (RET_SUCCESS);
+}
+
+/*
+ * __bt_seqadvance --
+ *	Advance the sequential scan.
+ *
+ * Parameters:
+ *	t:	tree
+ *	flags:	R_NEXT, R_PREV
+ *
+ * Side effects:
+ *	Pins the page the new key/data record is on.
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+static int
+__bt_seqadv(t, ep, flags)
+	BTREE *t;
+	EPG *ep;
+	int flags;
+{
+	CURSOR *c;
+	PAGE *h;
+	indx_t idx;
+	db_pgno_t pg;
+	int exact, rval;
+
+	/*
+	 * There are a couple of states that we can be in.  The cursor has
+	 * been initialized by the time we get here, but that's all we know.
+	 */
+	c = &t->bt_cursor;
+
+	/*
+	 * The cursor was deleted and there weren't any duplicate records,
+	 * so the cursor's key was saved.  Find out where that key would
+	 * be in the current tree.  If the returned key is an exact match,
+	 * it means that a key/data pair was inserted into the tree after
+	 * the delete.  We could reasonably return the key, but the problem
+	 * is that this is the access pattern we'll see if the user is
+	 * doing seq(..., R_NEXT)/put(..., 0) pairs, i.e. the put deletes
+	 * the cursor record and then replaces it, so the cursor was saved,
+	 * and we'll simply return the same "new" record until the user
+	 * notices and doesn't do a put() of it.  Since the key is an exact
+	 * match, we could as easily put the new record before the cursor,
+	 * and we've made no guarantee to return it.  So, move forward or
+	 * back a record if it's an exact match.
+	 *
+	 * XXX
+	 * In the current implementation, put's to the cursor are done with
+	 * delete/add pairs.  This has two consequences.  First, it means
+	 * that seq(..., R_NEXT)/put(..., R_CURSOR) pairs are going to exhibit
+	 * the same behavior as above.  Second, you can return the same key
+	 * twice if you have duplicate records.  The scenario is that the
+	 * cursor record is deleted, moving the cursor forward or backward
+	 * to a duplicate.  The add then inserts the new record at a location
+	 * ahead of the cursor because duplicates aren't sorted in any way,
+	 * and the new record is later returned.  This has to be fixed at some
+	 * point.
+	 */
+	if (F_ISSET(c, CURS_ACQUIRE)) {
+		if ((rval = __bt_first(t, &c->key, ep, &exact)) == RET_ERROR)
+			return (RET_ERROR);
+		if (!exact)
+			return (rval);
+		/*
+		 * XXX
+		 * Kluge -- get, release, get the page.
+		 */
+		c->pg.pgno = ep->page->pgno;
+		c->pg.index = ep->index;
+		mpool_put(t->bt_mp, ep->page, 0);
+	}
+
+	/* Get the page referenced by the cursor. */
+	if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+		return (RET_ERROR);
+
+	/*
+ 	 * Find the next/previous record in the tree and point the cursor at
+	 * it.  The cursor may not be moved until a new key has been found.
+	 */
+	switch (flags) {
+	case R_NEXT:			/* Next record. */
+		/*
+		 * The cursor was deleted in duplicate records, and moved
+		 * forward to a record that has yet to be returned.  Clear
+		 * that flag, and return the record.
+		 */
+		if (F_ISSET(c, CURS_AFTER))
+			goto usecurrent;
+		idx = c->pg.index;
+		if (++idx == NEXTINDEX(h)) {
+			pg = h->nextpg;
+			mpool_put(t->bt_mp, h, 0);
+			if (pg == P_INVALID)
+				return (RET_SPECIAL);
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+			idx = 0;
+		}
+		break;
+	case R_PREV:			/* Previous record. */
+		/*
+		 * The cursor was deleted in duplicate records, and moved
+		 * backward to a record that has yet to be returned.  Clear
+		 * that flag, and return the record.
+		 */
+		if (F_ISSET(c, CURS_BEFORE)) {
+usecurrent:		F_CLR(c, CURS_AFTER | CURS_BEFORE);
+			ep->page = h;
+			ep->index = c->pg.index;
+			return (RET_SUCCESS);
+		}
+		idx = c->pg.index;
+		if (idx == 0) {
+			pg = h->prevpg;
+			mpool_put(t->bt_mp, h, 0);
+			if (pg == P_INVALID)
+				return (RET_SPECIAL);
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+			idx = NEXTINDEX(h) - 1;
+		} else
+			--idx;
+		break;
+	}
+
+	ep->page = h;
+	ep->index = idx;
+	return (RET_SUCCESS);
+}
+
+/*
+ * __bt_first --
+ *	Find the first entry.
+ *
+ * Parameters:
+ *	t:	the tree
+ *    key:	the key
+ *  erval:	return EPG
+ * exactp:	pointer to exact match flag
+ *
+ * Returns:
+ *	The first entry in the tree greater than or equal to key,
+ *	or RET_SPECIAL if no such key exists.
+ */
+static int
+__bt_first(t, key, erval, exactp)
+	BTREE *t;
+	const DBT *key;
+	EPG *erval;
+	int *exactp;
+{
+	PAGE *h;
+	EPG *ep, save;
+	db_pgno_t pg;
+
+	/*
+	 * Find any matching record; __bt_search pins the page.
+	 *
+	 * If it's an exact match and duplicates are possible, walk backwards
+	 * in the tree until we find the first one.  Otherwise, make sure it's
+	 * a valid key (__bt_search may return an index just past the end of a
+	 * page) and return it.
+	 */
+	if ((ep = __bt_search(t, key, exactp)) == NULL)
+		return (RET_SPECIAL);
+	if (*exactp) {
+		if (F_ISSET(t, B_NODUPS)) {
+			*erval = *ep;
+			return (RET_SUCCESS);
+		}
+			
+		/*
+		 * Walk backwards, as long as the entry matches and there are
+		 * keys left in the tree.  Save a copy of each match in case
+		 * we go too far.
+		 */
+		save = *ep;
+		h = ep->page;
+		do {
+			if (save.page->pgno != ep->page->pgno) {
+				mpool_put(t->bt_mp, save.page, 0);
+				save = *ep;
+			} else
+				save.index = ep->index;
+
+			/*
+			 * Don't unpin the page the last (or original) match
+			 * was on, but make sure it's unpinned if an error
+			 * occurs.
+			 */
+			if (ep->index == 0) {
+				if (h->prevpg == P_INVALID)
+					break;
+				if (h->pgno != save.page->pgno)
+					mpool_put(t->bt_mp, h, 0);
+				if ((h = mpool_get(t->bt_mp,
+				    h->prevpg, 0)) == NULL) {
+					if (h->pgno == save.page->pgno)
+						mpool_put(t->bt_mp,
+						    save.page, 0);
+					return (RET_ERROR);
+				}
+				ep->page = h;
+				ep->index = NEXTINDEX(h);
+			}
+			--ep->index;
+		} while (__bt_cmp(t, key, ep) == 0);
+
+		/*
+		 * Reach here with the last page that was looked at pinned,
+		 * which may or may not be the same as the last (or original)
+		 * match page.  If it's not useful, release it.
+		 */
+		if (h->pgno != save.page->pgno)
+			mpool_put(t->bt_mp, h, 0);
+
+		*erval = save;
+		return (RET_SUCCESS);
+	}
+
+	/* If at the end of a page, find the next entry. */
+	if (ep->index == NEXTINDEX(ep->page)) {
+		h = ep->page;
+		pg = h->nextpg;
+		mpool_put(t->bt_mp, h, 0);
+		if (pg == P_INVALID)
+			return (RET_SPECIAL);
+		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+			return (RET_ERROR);
+		ep->index = 0;
+		ep->page = h;
+	}
+	*erval = *ep;
+	return (RET_SUCCESS);
+}
+
+/*
+ * __bt_setcur --
+ *	Set the cursor to an entry in the tree.
+ *
+ * Parameters:
+ *	t:	the tree
+ *   pgno:	page number
+ *  index:	page index
+ */
+void
+__bt_setcur(t, pgno, idx)
+	BTREE *t;
+	db_pgno_t pgno;
+	u_int idx;
+{
+	/* Lose any already deleted key. */
+	if (t->bt_cursor.key.data != NULL) {
+		free(t->bt_cursor.key.data);
+		t->bt_cursor.key.size = 0;
+		t->bt_cursor.key.data = NULL;
+	}
+	F_CLR(&t->bt_cursor, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE);
+
+	/* Update the cursor. */
+	t->bt_cursor.pg.pgno = pgno;
+	t->bt_cursor.pg.index = idx;
+	F_SET(&t->bt_cursor, CURS_INIT);
+}
+
+/* Recursive descent cursor. */
+typedef struct rcursor_ {
+	CURSOR	cursor;
+	size_t	ssize;
+	EPGNO	*stack;
+	EPGNO	*sp;
+} RCURSOR;
+#define RCURSOR_MINSS	64
+
+static int	 bt_rcinit(void **);
+static void	 bt_rcdestroy(void **);
+static int	 bt_rcpush(RCURSOR *, db_pgno_t, u_int);
+static EPGNO	*bt_rcpop(RCURSOR *);
+static void	 bt_rcclr(RCURSOR *);
+static int	 bt_rcgrowstk(RCURSOR *);
+static int	 bt_rseqset(BTREE *, EPG *, DBT *, RCURSOR *, int);
+static int	 bt_rseqadv(BTREE *, EPG *, RCURSOR *, int);
+
+static int
+bt_rcinit(curs)
+	void **curs;
+{
+	RCURSOR *rc;
+
+	rc = *curs = malloc(sizeof(RCURSOR));
+	if (rc == NULL) {
+		errno = ENOMEM;
+		return RET_ERROR;
+	}
+	memset(rc, 0, sizeof(*rc));
+
+	rc->ssize = RCURSOR_MINSS;
+	rc->stack = malloc(rc->ssize * sizeof(EPGNO));
+	if (rc->stack == NULL) {
+		free(rc);
+		errno = ENOMEM;
+		return RET_ERROR;
+	}
+	bt_rcclr(rc);
+	return RET_SUCCESS;
+}
+
+static void
+bt_rcdestroy(curs)
+	void **curs;
+{
+	RCURSOR *rc;
+
+	rc = *curs;
+	free(rc->stack);
+	free(rc);
+	*curs = NULL;
+}
+
+static int
+bt_rcpush(rc, p, i)
+	RCURSOR *rc;
+	db_pgno_t p;
+	u_int i;
+{
+	int status;
+
+	rc->sp->pgno = p;
+	rc->sp->index = i;
+	if (++rc->sp > rc->stack + rc->ssize) {
+		status = bt_rcgrowstk(rc);
+		if (status != RET_SUCCESS)
+			return status;
+	}
+	return RET_SUCCESS;
+}
+
+static EPGNO *
+bt_rcpop(rc)
+	RCURSOR *rc;
+{
+	return (rc->sp == rc->stack) ? NULL : --rc->sp;
+}
+
+static void
+bt_rcclr(rc)
+	RCURSOR *rc;
+{
+	rc->sp = rc->stack;
+}
+
+static int
+bt_rcgrowstk(rc)
+	RCURSOR *rc;
+{
+	size_t osize;
+	EPGNO *e;
+
+	osize = rc->ssize;
+	rc->ssize *= 2;
+	e = realloc(rc->stack, rc->ssize * sizeof(EPGNO));
+	if (e == NULL) {
+		rc->ssize = osize;
+		errno = ENOMEM;
+		return RET_ERROR;
+	}
+	rc->stack = e;
+	return RET_SUCCESS;
+}
+
+/*
+ * bt_rseq --
+ *	Like __bt_seq but does recursive descent tree traversal
+ *	instead of using the prev/next pointers.
+ */
+int
+bt_rseq(dbp, key, data, curs, flags)
+	const DB *dbp;
+	DBT *key, *data;
+	void **curs;
+	u_int flags;
+{
+	RCURSOR *rc;
+	BTREE *t;
+	EPG e;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	if (curs == NULL) {
+		errno = EINVAL;
+		return RET_ERROR;
+	}
+	if (*curs == NULL) {
+		status = bt_rcinit(curs);
+		if (status != RET_SUCCESS)
+			return RET_ERROR;
+	}
+	rc = *curs;
+
+	/*
+	 * If scan unitialized as yet, or starting at a specific record, set
+	 * the scan to a specific key.  Both bt_rseqset and bt_rseqadv pin
+	 * the page the cursor references if they're successful.
+	 */
+	switch (flags) {
+	case R_NEXT:
+	case R_PREV:
+		if (F_ISSET(&rc->cursor, CURS_INIT)) {
+			status = bt_rseqadv(t, &e, rc, flags);
+			break;
+		}
+		/* FALLTHROUGH */
+	case R_FIRST:
+	case R_LAST:
+	case R_CURSOR:
+		status = bt_rseqset(t, &e, key, rc, flags);
+		break;
+	default:
+		errno = EINVAL;
+		return (RET_ERROR);
+	}
+
+	if (status == RET_SUCCESS) {
+		status =
+		    __bt_ret(t, &e, key, &t->bt_rkey, data, &t->bt_rdata, 0);
+
+		/*
+		 * If the user is doing concurrent access, we copied the
+		 * key/data, toss the page.
+		 */
+		if (F_ISSET(t, B_DB_LOCK))
+			mpool_put(t->bt_mp, e.page, 0);
+		else
+			t->bt_pinned = e.page;
+	} else if (status == RET_SPECIAL)
+		bt_rcdestroy(curs);
+	return (status);
+}
+
+/*
+ * bt_rseqset --
+ *	Set the sequential scan to a specific key.
+ *
+ * Parameters:
+ *	t:	tree
+ *	ep:	storage for returned key
+ *	key:	key for initial scan position
+ *	rc:	recursion cursor
+ *	flags:	R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
+ *
+ * Side effects:
+ *	Pins the page the cursor references.
+ *	Updates rc's stack and cursor.
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+static int
+bt_rseqset(t, ep, key, rc, flags)
+	BTREE *t;
+	EPG *ep;
+	DBT *key;
+	RCURSOR *rc;
+	int flags;
+{
+	PAGE *h;
+	db_pgno_t pg;
+	int status;
+
+	/*
+	 * Find the first, last or specific key in the tree and point the
+	 * cursor at it.  The cursor may not be moved until a new key has
+	 * been found.
+	 */
+	switch (flags) {
+	case R_CURSOR:		/* Not implemented. */
+		errno = EINVAL;
+		return RET_ERROR;
+	case R_FIRST:				/* First record. */
+	case R_NEXT:
+		bt_rcclr(rc);
+		/* Walk down the left-hand side of the tree. */
+		for (pg = P_ROOT;;) {
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+
+			/* Check for an empty tree. */
+			if (NEXTINDEX(h) == 0) {
+				mpool_put(t->bt_mp, h, 0);
+				return (RET_SPECIAL);
+			}
+
+			if (h->flags & (P_BLEAF | P_RLEAF))
+				break;
+			pg = GETBINTERNAL(h, 0)->pgno;
+			status = bt_rcpush(rc, h->pgno, 0);
+			mpool_put(t->bt_mp, h, 0);
+			if (status != RET_SUCCESS)
+				return status;
+		}
+		ep->page = h;
+		ep->index = 0;
+		break;
+	case R_LAST:				/* Last record. */
+	case R_PREV:
+		bt_rcclr(rc);
+		/* Walk down the right-hand side of the tree. */
+		for (pg = P_ROOT;;) {
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+
+			/* Check for an empty tree. */
+			if (NEXTINDEX(h) == 0) {
+				mpool_put(t->bt_mp, h, 0);
+				return (RET_SPECIAL);
+			}
+
+			if (h->flags & (P_BLEAF | P_RLEAF))
+				break;
+			pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
+			status = bt_rcpush(rc, h->pgno, NEXTINDEX(h) - 1);
+			mpool_put(t->bt_mp, h, 0);
+			if (status != RET_SUCCESS)
+				return status;
+		}
+		ep->page = h;
+		ep->index = NEXTINDEX(h) - 1;
+		break;
+	}
+	rc->cursor.pg.pgno = ep->page->pgno;
+	rc->cursor.pg.index = ep->index;
+	F_CLR(&rc->cursor, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE);
+	F_SET(&rc->cursor, CURS_INIT);
+	return (RET_SUCCESS);
+}
+
+/*
+ * bt_rseqadvance --
+ *	Advance the sequential scan.
+ *
+ * Parameters:
+ *	t:	tree
+ *	ep:	return page
+ *	rc:	recursion cursor
+ *	flags:	R_NEXT, R_PREV
+ *
+ * Side effects:
+ *	Pins the page the new key/data record is on.
+ *	Updates rc's stack and cursor.
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+static int
+bt_rseqadv(t, ep, rc, flags)
+	BTREE *t;
+	EPG *ep;
+	RCURSOR *rc;
+	int flags;
+{
+	CURSOR *c;
+	PAGE *h;
+	indx_t idx;
+	db_pgno_t pg;
+	int status;
+	EPGNO *e;
+
+	/*
+	 * There are a couple of states that we can be in.  The cursor has
+	 * been initialized by the time we get here, but that's all we know.
+	 */
+	c = &rc->cursor;
+
+	/* Get the page referenced by the cursor. */
+	if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+		return (RET_ERROR);
+
+	/*
+ 	 * Find the next/previous record in the tree and point the cursor at
+	 * it.  The cursor may not be moved until a new key has been found.
+	 */
+	switch (flags) {
+	case R_NEXT:			/* Next record. */
+		idx = c->pg.index;
+		while (++idx == NEXTINDEX(h)) {
+			/* Crawl up if we hit the right edge. */
+			e = bt_rcpop(rc);
+			mpool_put(t->bt_mp, h, 0);
+			if (e == NULL) /* Hit the right edge of root. */
+				return RET_SPECIAL;
+			idx = e->index;
+			pg = e->pgno;
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+		}
+		while (!(h->flags & (P_BLEAF | P_RLEAF))) {
+			/* Crawl down the left until we hit a leaf. */
+			status = bt_rcpush(rc, h->pgno, idx);
+			pg = GETBINTERNAL(h, idx)->pgno;
+			mpool_put(t->bt_mp, h, 0);
+			if (status != RET_SUCCESS)
+				return status;
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+			idx = 0;
+		}
+		break;
+	case R_PREV:			/* Previous record. */
+		idx = c->pg.index;
+		while (!idx) {
+			/* Crawl up if we hit the left edge. */
+			e = bt_rcpop(rc);
+			mpool_put(t->bt_mp, h, 0);
+			if (e == NULL) /* Hit the left edge of root. */
+				return RET_SPECIAL;
+			idx = e->index;
+			pg = e->pgno;
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+		}
+		idx--;
+		while (!(h->flags & (P_BLEAF | P_RLEAF))) {
+			/* Crawl down the right until we hit a leaf. */
+			status = bt_rcpush(rc, h->pgno, idx);
+			pg = GETBINTERNAL(h, idx)->pgno;
+			mpool_put(t->bt_mp, h, 0);
+			if (status != RET_SUCCESS)
+				return status;
+			if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+				return (RET_ERROR);
+			idx = NEXTINDEX(h) - 1;
+		}
+		break;
+	}
+
+	ep->page = h;
+	ep->index = idx;
+	c->pg.pgno = h->pgno;
+	c->pg.index = idx;
+	F_CLR(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE);
+	F_SET(c, CURS_INIT);
+	return (RET_SUCCESS);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_split.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_split.c
new file mode 100644
index 000000000..0cc6cf09b
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_split.c
@@ -0,0 +1,828 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_split.c	8.10 (Berkeley) 1/9/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+static int	 bt_broot __P((BTREE *, PAGE *, PAGE *, PAGE *));
+static PAGE	*bt_page
+		    __P((BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t));
+static int	 bt_preserve __P((BTREE *, db_pgno_t));
+static PAGE	*bt_psplit
+		    __P((BTREE *, PAGE *, PAGE *, PAGE *, indx_t *, size_t));
+static PAGE	*bt_root
+		    __P((BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t));
+static int	 bt_rroot __P((BTREE *, PAGE *, PAGE *, PAGE *));
+static recno_t	 rec_total __P((PAGE *));
+
+#ifdef STATISTICS
+u_long	bt_rootsplit, bt_split, bt_sortsplit, bt_pfxsaved;
+#endif
+
+/*
+ * __BT_SPLIT -- Split the tree.
+ *
+ * Parameters:
+ *	t:	tree
+ *	sp:	page to split
+ *	key:	key to insert
+ *	data:	data to insert
+ *	flags:	BIGKEY/BIGDATA flags
+ *	ilen:	insert length
+ *	skip:	index to leave open
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__bt_split(t, sp, key, data, flags, ilen, argskip)
+	BTREE *t;
+	PAGE *sp;
+	const DBT *key, *data;
+	int flags;
+	size_t ilen;
+	u_int32_t argskip;
+{
+	BINTERNAL *bi;
+	BLEAF *bl, *tbl;
+	DBT a, b;
+	EPGNO *parent;
+	PAGE *h, *l, *r, *lchild, *rchild;
+	indx_t nxtindex;
+	u_int16_t skip;
+	u_int32_t n, nbytes, nksize;
+	int parentsplit;
+	char *dest;
+
+	/*
+	 * Split the page into two pages, l and r.  The split routines return
+	 * a pointer to the page into which the key should be inserted and with
+	 * skip set to the offset which should be used.  Additionally, l and r
+	 * are pinned.
+	 */
+	skip = argskip;
+	h = sp->pgno == P_ROOT ?
+	    bt_root(t, sp, &l, &r, &skip, ilen) :
+	    bt_page(t, sp, &l, &r, &skip, ilen);
+	if (h == NULL)
+		return (RET_ERROR);
+
+	/*
+	 * Insert the new key/data pair into the leaf page.  (Key inserts
+	 * always cause a leaf page to split first.)
+	 */
+	h->linp[skip] = h->upper -= ilen;
+	dest = (char *)h + h->upper;
+	if (F_ISSET(t, R_RECNO))
+		WR_RLEAF(dest, data, flags)
+	else
+		WR_BLEAF(dest, key, data, flags)
+
+	/* If the root page was split, make it look right. */
+	if (sp->pgno == P_ROOT &&
+	    (F_ISSET(t, R_RECNO) ?
+	    bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
+		goto err2;
+
+	/*
+	 * Now we walk the parent page stack -- a LIFO stack of the pages that
+	 * were traversed when we searched for the page that split.  Each stack
+	 * entry is a page number and a page index offset.  The offset is for
+	 * the page traversed on the search.  We've just split a page, so we
+	 * have to insert a new key into the parent page.
+	 *
+	 * If the insert into the parent page causes it to split, may have to
+	 * continue splitting all the way up the tree.  We stop if the root
+	 * splits or the page inserted into didn't have to split to hold the
+	 * new key.  Some algorithms replace the key for the old page as well
+	 * as the new page.  We don't, as there's no reason to believe that the
+	 * first key on the old page is any better than the key we have, and,
+	 * in the case of a key being placed at index 0 causing the split, the
+	 * key is unavailable.
+	 *
+	 * There are a maximum of 5 pages pinned at any time.  We keep the left
+	 * and right pages pinned while working on the parent.   The 5 are the
+	 * two children, left parent and right parent (when the parent splits)
+	 * and the root page or the overflow key page when calling bt_preserve.
+	 * This code must make sure that all pins are released other than the
+	 * root page or overflow page which is unlocked elsewhere.
+	 */
+	while ((parent = BT_POP(t)) != NULL) {
+		lchild = l;
+		rchild = r;
+
+		/* Get the parent page. */
+		if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+			goto err2;
+
+	 	/*
+		 * The new key goes ONE AFTER the index, because the split
+		 * was to the right.
+		 */
+		skip = parent->index + 1;
+
+		/*
+		 * Calculate the space needed on the parent page.
+		 *
+		 * Prefix trees: space hack when inserting into BINTERNAL
+		 * pages.  Retain only what's needed to distinguish between
+		 * the new entry and the LAST entry on the page to its left.
+		 * If the keys compare equal, retain the entire key.  Note,
+		 * we don't touch overflow keys, and the entire key must be
+		 * retained for the next-to-left most key on the leftmost
+		 * page of each level, or the search will fail.  Applicable
+		 * ONLY to internal pages that have leaf pages as children.
+		 * Further reduction of the key between pairs of internal
+		 * pages loses too much information.
+		 */
+		switch (rchild->flags & P_TYPE) {
+		case P_BINTERNAL:
+			bi = GETBINTERNAL(rchild, 0);
+			nbytes = NBINTERNAL(bi->ksize);
+			break;
+		case P_BLEAF:
+			bl = GETBLEAF(rchild, 0);
+			nbytes = NBINTERNAL(bl->ksize);
+			if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
+			    (h->prevpg != P_INVALID || skip > 1)) {
+				tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
+				a.size = tbl->ksize;
+				a.data = tbl->bytes;
+				b.size = bl->ksize;
+				b.data = bl->bytes;
+				nksize = t->bt_pfx(&a, &b);
+				n = NBINTERNAL(nksize);
+				if (n < nbytes) {
+#ifdef STATISTICS
+					bt_pfxsaved += nbytes - n;
+#endif
+					nbytes = n;
+				} else
+					nksize = 0;
+			} else
+				nksize = 0;
+			break;
+		case P_RINTERNAL:
+		case P_RLEAF:
+			nbytes = NRINTERNAL;
+			break;
+		default:
+			abort();
+		}
+
+		/* Split the parent page if necessary or shift the indices. */
+		if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
+			sp = h;
+			h = h->pgno == P_ROOT ?
+			    bt_root(t, h, &l, &r, &skip, nbytes) :
+			    bt_page(t, h, &l, &r, &skip, nbytes);
+			if (h == NULL)
+				goto err1;
+			parentsplit = 1;
+		} else {
+			if (skip < (nxtindex = NEXTINDEX(h)))
+				memmove(h->linp + skip + 1, h->linp + skip,
+				    (nxtindex - skip) * sizeof(indx_t));
+			h->lower += sizeof(indx_t);
+			parentsplit = 0;
+		}
+
+		/* Insert the key into the parent page. */
+		switch (rchild->flags & P_TYPE) {
+		case P_BINTERNAL:
+			h->linp[skip] = h->upper -= nbytes;
+			dest = (char *)h + h->linp[skip];
+			memmove(dest, bi, nbytes);
+			((BINTERNAL *)dest)->pgno = rchild->pgno;
+			break;
+		case P_BLEAF:
+			h->linp[skip] = h->upper -= nbytes;
+			dest = (char *)h + h->linp[skip];
+			WR_BINTERNAL(dest, nksize ? nksize : bl->ksize,
+			    rchild->pgno, bl->flags & P_BIGKEY);
+			memmove(dest, bl->bytes, nksize ? nksize : bl->ksize);
+			if (bl->flags & P_BIGKEY &&
+			    bt_preserve(t, *(db_pgno_t *)bl->bytes) == RET_ERROR)
+				goto err1;
+			break;
+		case P_RINTERNAL:
+			/*
+			 * Update the left page count.  If split
+			 * added at index 0, fix the correct page.
+			 */
+			if (skip > 0)
+				dest = (char *)h + h->linp[skip - 1];
+			else
+				dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
+			((RINTERNAL *)dest)->nrecs = rec_total(lchild);
+			((RINTERNAL *)dest)->pgno = lchild->pgno;
+
+			/* Update the right page count. */
+			h->linp[skip] = h->upper -= nbytes;
+			dest = (char *)h + h->linp[skip];
+			((RINTERNAL *)dest)->nrecs = rec_total(rchild);
+			((RINTERNAL *)dest)->pgno = rchild->pgno;
+			break;
+		case P_RLEAF:
+			/*
+			 * Update the left page count.  If split
+			 * added at index 0, fix the correct page.
+			 */
+			if (skip > 0)
+				dest = (char *)h + h->linp[skip - 1];
+			else
+				dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
+			((RINTERNAL *)dest)->nrecs = NEXTINDEX(lchild);
+			((RINTERNAL *)dest)->pgno = lchild->pgno;
+
+			/* Update the right page count. */
+			h->linp[skip] = h->upper -= nbytes;
+			dest = (char *)h + h->linp[skip];
+			((RINTERNAL *)dest)->nrecs = NEXTINDEX(rchild);
+			((RINTERNAL *)dest)->pgno = rchild->pgno;
+			break;
+		default:
+			abort();
+		}
+
+		/* Unpin the held pages. */
+		if (!parentsplit) {
+			mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+			break;
+		}
+
+		/* If the root page was split, make it look right. */
+		if (sp->pgno == P_ROOT &&
+		    (F_ISSET(t, R_RECNO) ?
+		    bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
+			goto err1;
+
+		mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
+		mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
+	}
+
+	/* Unpin the held pages. */
+	mpool_put(t->bt_mp, l, MPOOL_DIRTY);
+	mpool_put(t->bt_mp, r, MPOOL_DIRTY);
+
+	/* Clear any pages left on the stack. */
+	return (RET_SUCCESS);
+
+	/*
+	 * If something fails in the above loop we were already walking back
+	 * up the tree and the tree is now inconsistent.  Nothing much we can
+	 * do about it but release any memory we're holding.
+	 */
+err1:	mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
+	mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
+
+err2:	mpool_put(t->bt_mp, l, 0);
+	mpool_put(t->bt_mp, r, 0);
+	__dbpanic(t->bt_dbp);
+	return (RET_ERROR);
+}
+
+/*
+ * BT_PAGE -- Split a non-root page of a btree.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	root page
+ *	lp:	pointer to left page pointer
+ *	rp:	pointer to right page pointer
+ *	skip:	pointer to index to leave open
+ *	ilen:	insert length
+ *
+ * Returns:
+ *	Pointer to page in which to insert or NULL on error.
+ */
+static PAGE *
+bt_page(t, h, lp, rp, skip, ilen)
+	BTREE *t;
+	PAGE *h, **lp, **rp;
+	indx_t *skip;
+	size_t ilen;
+{
+	PAGE *l, *r, *tp;
+	db_pgno_t npg;
+
+#ifdef STATISTICS
+	++bt_split;
+#endif
+	/* Put the new right page for the split into place. */
+	if ((r = __bt_new(t, &npg)) == NULL)
+		return (NULL);
+	r->pgno = npg;
+	r->lower = BTDATAOFF;
+	r->upper = t->bt_psize;
+	r->nextpg = h->nextpg;
+	r->prevpg = h->pgno;
+	r->flags = h->flags & P_TYPE;
+
+	/*
+	 * If we're splitting the last page on a level because we're appending
+	 * a key to it (skip is NEXTINDEX()), it's likely that the data is
+	 * sorted.  Adding an empty page on the side of the level is less work
+	 * and can push the fill factor much higher than normal.  If we're
+	 * wrong it's no big deal, we'll just do the split the right way next
+	 * time.  It may look like it's equally easy to do a similar hack for
+	 * reverse sorted data, that is, split the tree left, but it's not.
+	 * Don't even try.
+	 */
+	if (h->nextpg == P_INVALID && *skip == NEXTINDEX(h)) {
+#ifdef STATISTICS
+		++bt_sortsplit;
+#endif
+		h->nextpg = r->pgno;
+		r->lower = BTDATAOFF + sizeof(indx_t);
+		*skip = 0;
+		*lp = h;
+		*rp = r;
+		return (r);
+	}
+
+	/* Put the new left page for the split into place. */
+	if ((l = (PAGE *)malloc(t->bt_psize)) == NULL) {
+		mpool_put(t->bt_mp, r, 0);
+		return (NULL);
+	}
+#ifdef PURIFY
+	memset(l, 0xff, t->bt_psize);
+#endif
+	l->pgno = h->pgno;
+	l->nextpg = r->pgno;
+	l->prevpg = h->prevpg;
+	l->lower = BTDATAOFF;
+	l->upper = t->bt_psize;
+	l->flags = h->flags & P_TYPE;
+
+	/* Fix up the previous pointer of the page after the split page. */
+	if (h->nextpg != P_INVALID) {
+		if ((tp = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL) {
+			free(l);
+			/* XXX mpool_free(t->bt_mp, r->pgno); */
+			return (NULL);
+		}
+		tp->prevpg = r->pgno;
+		mpool_put(t->bt_mp, tp, MPOOL_DIRTY);
+	}
+
+	/*
+	 * Split right.  The key/data pairs aren't sorted in the btree page so
+	 * it's simpler to copy the data from the split page onto two new pages
+	 * instead of copying half the data to the right page and compacting
+	 * the left page in place.  Since the left page can't change, we have
+	 * to swap the original and the allocated left page after the split.
+	 */
+	tp = bt_psplit(t, h, l, r, skip, ilen);
+
+	/* Move the new left page onto the old left page. */
+	memmove(h, l, t->bt_psize);
+	if (tp == l)
+		tp = h;
+	free(l);
+
+	*lp = h;
+	*rp = r;
+	return (tp);
+}
+
+/*
+ * BT_ROOT -- Split the root page of a btree.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	root page
+ *	lp:	pointer to left page pointer
+ *	rp:	pointer to right page pointer
+ *	skip:	pointer to index to leave open
+ *	ilen:	insert length
+ *
+ * Returns:
+ *	Pointer to page in which to insert or NULL on error.
+ */
+static PAGE *
+bt_root(t, h, lp, rp, skip, ilen)
+	BTREE *t;
+	PAGE *h, **lp, **rp;
+	indx_t *skip;
+	size_t ilen;
+{
+	PAGE *l, *r, *tp;
+	db_pgno_t lnpg, rnpg;
+
+#ifdef STATISTICS
+	++bt_split;
+	++bt_rootsplit;
+#endif
+	/* Put the new left and right pages for the split into place. */
+	if ((l = __bt_new(t, &lnpg)) == NULL ||
+	    (r = __bt_new(t, &rnpg)) == NULL)
+		return (NULL);
+	l->pgno = lnpg;
+	r->pgno = rnpg;
+	l->nextpg = r->pgno;
+	r->prevpg = l->pgno;
+	l->prevpg = r->nextpg = P_INVALID;
+	l->lower = r->lower = BTDATAOFF;
+	l->upper = r->upper = t->bt_psize;
+	l->flags = r->flags = h->flags & P_TYPE;
+
+	/* Split the root page. */
+	tp = bt_psplit(t, h, l, r, skip, ilen);
+
+	*lp = l;
+	*rp = r;
+	return (tp);
+}
+
+/*
+ * BT_RROOT -- Fix up the recno root page after it has been split.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	root page
+ *	l:	left page
+ *	r:	right page
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_rroot(t, h, l, r)
+	BTREE *t;
+	PAGE *h, *l, *r;
+{
+	char *dest;
+
+	/* Insert the left and right keys, set the header information. */
+	h->linp[0] = h->upper = t->bt_psize - NRINTERNAL;
+	dest = (char *)h + h->upper;
+	WR_RINTERNAL(dest,
+	    l->flags & P_RLEAF ? NEXTINDEX(l) : rec_total(l), l->pgno);
+
+	h->linp[1] = h->upper -= NRINTERNAL;
+	dest = (char *)h + h->upper;
+	WR_RINTERNAL(dest,
+	    r->flags & P_RLEAF ? NEXTINDEX(r) : rec_total(r), r->pgno);
+
+	h->lower = BTDATAOFF + 2 * sizeof(indx_t);
+
+	/* Unpin the root page, set to recno internal page. */
+	h->flags &= ~P_TYPE;
+	h->flags |= P_RINTERNAL;
+	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+	return (RET_SUCCESS);
+}
+
+/*
+ * BT_BROOT -- Fix up the btree root page after it has been split.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	root page
+ *	l:	left page
+ *	r:	right page
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_broot(t, h, l, r)
+	BTREE *t;
+	PAGE *h, *l, *r;
+{
+	BINTERNAL *bi;
+	BLEAF *bl;
+	u_int32_t nbytes;
+	char *dest;
+
+	/*
+	 * If the root page was a leaf page, change it into an internal page.
+	 * We copy the key we split on (but not the key's data, in the case of
+	 * a leaf page) to the new root page.
+	 *
+	 * The btree comparison code guarantees that the left-most key on any
+	 * level of the tree is never used, so it doesn't need to be filled in.
+	 */
+	nbytes = NBINTERNAL(0);
+	h->linp[0] = h->upper = t->bt_psize - nbytes;
+	dest = (char *)h + h->upper;
+	WR_BINTERNAL(dest, 0, l->pgno, 0);
+
+	switch (h->flags & P_TYPE) {
+	case P_BLEAF:
+		bl = GETBLEAF(r, 0);
+		nbytes = NBINTERNAL(bl->ksize);
+		h->linp[1] = h->upper -= nbytes;
+		dest = (char *)h + h->upper;
+		WR_BINTERNAL(dest, bl->ksize, r->pgno, 0);
+		memmove(dest, bl->bytes, bl->ksize);
+
+		/*
+		 * If the key is on an overflow page, mark the overflow chain
+		 * so it isn't deleted when the leaf copy of the key is deleted.
+		 */
+		if (bl->flags & P_BIGKEY &&
+		    bt_preserve(t, *(db_pgno_t *)bl->bytes) == RET_ERROR)
+			return (RET_ERROR);
+		break;
+	case P_BINTERNAL:
+		bi = GETBINTERNAL(r, 0);
+		nbytes = NBINTERNAL(bi->ksize);
+		h->linp[1] = h->upper -= nbytes;
+		dest = (char *)h + h->upper;
+		memmove(dest, bi, nbytes);
+		((BINTERNAL *)dest)->pgno = r->pgno;
+		break;
+	default:
+		abort();
+	}
+
+	/* There are two keys on the page. */
+	h->lower = BTDATAOFF + 2 * sizeof(indx_t);
+
+	/* Unpin the root page, set to btree internal page. */
+	h->flags &= ~P_TYPE;
+	h->flags |= P_BINTERNAL;
+	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+	return (RET_SUCCESS);
+}
+
+/*
+ * BT_PSPLIT -- Do the real work of splitting the page.
+ *
+ * Parameters:
+ *	t:	tree
+ *	h:	page to be split
+ *	l:	page to put lower half of data
+ *	r:	page to put upper half of data
+ *	pskip:	pointer to index to leave open
+ *	ilen:	insert length
+ *
+ * Returns:
+ *	Pointer to page in which to insert.
+ */
+static PAGE *
+bt_psplit(t, h, l, r, pskip, ilen)
+	BTREE *t;
+	PAGE *h, *l, *r;
+	indx_t *pskip;
+	size_t ilen;
+{
+	BINTERNAL *bi;
+	BLEAF *bl;
+	CURSOR *c;
+	RLEAF *rl;
+	PAGE *rval;
+	void *src;
+	indx_t full, half, nxt, off, skip, top, used;
+	u_int32_t nbytes;
+	int bigkeycnt, isbigkey;
+
+	/*
+	 * Split the data to the left and right pages.  Leave the skip index
+	 * open.  Additionally, make some effort not to split on an overflow
+	 * key.  This makes internal page processing faster and can save
+	 * space as overflow keys used by internal pages are never deleted.
+	 */
+	bigkeycnt = 0;
+	skip = *pskip;
+	full = t->bt_psize - BTDATAOFF;
+	half = full / 2;
+	used = 0;
+	for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
+		if (skip == off) {
+			nbytes = ilen;
+			isbigkey = 0;		/* XXX: not really known. */
+		} else
+			switch (h->flags & P_TYPE) {
+			case P_BINTERNAL:
+				src = bi = GETBINTERNAL(h, nxt);
+				nbytes = NBINTERNAL(bi->ksize);
+				isbigkey = bi->flags & P_BIGKEY;
+				break;
+			case P_BLEAF:
+				src = bl = GETBLEAF(h, nxt);
+				nbytes = NBLEAF(bl);
+				isbigkey = bl->flags & P_BIGKEY;
+				break;
+			case P_RINTERNAL:
+				src = GETRINTERNAL(h, nxt);
+				nbytes = NRINTERNAL;
+				isbigkey = 0;
+				break;
+			case P_RLEAF:
+				src = rl = GETRLEAF(h, nxt);
+				nbytes = NRLEAF(rl);
+				isbigkey = 0;
+				break;
+			default:
+				abort();
+			}
+
+		/*
+		 * If the key/data pairs are substantial fractions of the max
+		 * possible size for the page, it's possible to get situations
+		 * where we decide to try and copy too much onto the left page.
+		 * Make sure that doesn't happen.
+		 */
+		if ((skip <= off && used + nbytes + sizeof(indx_t) >= full)
+		    || nxt == top - 1) {
+			--off;
+			break;
+		}
+
+		/* Copy the key/data pair, if not the skipped index. */
+		if (skip != off) {
+			++nxt;
+
+			l->linp[off] = l->upper -= nbytes;
+			memmove((char *)l + l->upper, src, nbytes);
+		}
+
+		used += nbytes + sizeof(indx_t);
+		if (used >= half) {
+			if (!isbigkey || bigkeycnt == 3)
+				break;
+			else
+				++bigkeycnt;
+		}
+	}
+
+	/*
+	 * Off is the last offset that's valid for the left page.
+	 * Nxt is the first offset to be placed on the right page.
+	 */
+	l->lower += (off + 1) * sizeof(indx_t);
+
+	/*
+	 * If splitting the page that the cursor was on, the cursor has to be
+	 * adjusted to point to the same record as before the split.  If the
+	 * cursor is at or past the skipped slot, the cursor is incremented by
+	 * one.  If the cursor is on the right page, it is decremented by the
+	 * number of records split to the left page.
+	 */
+	c = &t->bt_cursor;
+	if (F_ISSET(c, CURS_INIT) && c->pg.pgno == h->pgno) {
+		if (c->pg.index >= skip)
+			++c->pg.index;
+		if (c->pg.index < nxt)			/* Left page. */
+			c->pg.pgno = l->pgno;
+		else {					/* Right page. */
+			c->pg.pgno = r->pgno;
+			c->pg.index -= nxt;
+		}
+	}
+
+	/*
+	 * If the skipped index was on the left page, just return that page.
+	 * Otherwise, adjust the skip index to reflect the new position on
+	 * the right page.
+	 */
+	if (skip <= off) {
+		skip = 0;
+		rval = l;
+	} else {
+		rval = r;
+		*pskip -= nxt;
+	}
+
+	for (off = 0; nxt < top; ++off) {
+		if (skip == nxt) {
+			++off;
+			skip = 0;
+		}
+		switch (h->flags & P_TYPE) {
+		case P_BINTERNAL:
+			src = bi = GETBINTERNAL(h, nxt);
+			nbytes = NBINTERNAL(bi->ksize);
+			break;
+		case P_BLEAF:
+			src = bl = GETBLEAF(h, nxt);
+			nbytes = NBLEAF(bl);
+			break;
+		case P_RINTERNAL:
+			src = GETRINTERNAL(h, nxt);
+			nbytes = NRINTERNAL;
+			break;
+		case P_RLEAF:
+			src = rl = GETRLEAF(h, nxt);
+			nbytes = NRLEAF(rl);
+			break;
+		default:
+			abort();
+		}
+		++nxt;
+		r->linp[off] = r->upper -= nbytes;
+		memmove((char *)r + r->upper, src, nbytes);
+	}
+	r->lower += off * sizeof(indx_t);
+
+	/* If the key is being appended to the page, adjust the index. */
+	if (skip == top)
+		r->lower += sizeof(indx_t);
+
+	return (rval);
+}
+
+/*
+ * BT_PRESERVE -- Mark a chain of pages as used by an internal node.
+ *
+ * Chains of indirect blocks pointed to by leaf nodes get reclaimed when the
+ * record that references them gets deleted.  Chains pointed to by internal
+ * pages never get deleted.  This routine marks a chain as pointed to by an
+ * internal page.
+ *
+ * Parameters:
+ *	t:	tree
+ *	pg:	page number of first page in the chain.
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ */
+static int
+bt_preserve(t, pg)
+	BTREE *t;
+	db_pgno_t pg;
+{
+	PAGE *h;
+
+	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+		return (RET_ERROR);
+	h->flags |= P_PRESERVE;
+	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+	return (RET_SUCCESS);
+}
+
+/*
+ * REC_TOTAL -- Return the number of recno entries below a page.
+ *
+ * Parameters:
+ *	h:	page
+ *
+ * Returns:
+ *	The number of recno entries below a page.
+ *
+ * XXX
+ * These values could be set by the bt_psplit routine.  The problem is that the
+ * entry has to be popped off of the stack etc. or the values have to be passed
+ * all the way back to bt_split/bt_rroot and it's not very clean.
+ */
+static recno_t
+rec_total(h)
+	PAGE *h;
+{
+	recno_t recs;
+	indx_t nxt, top;
+
+	for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)
+		recs += GETRINTERNAL(h, nxt)->nrecs;
+	return (recs);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_utils.c b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_utils.c
new file mode 100644
index 000000000..1a34598ad
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/bt_utils.c
@@ -0,0 +1,260 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_utils.c	8.8 (Berkeley) 7/20/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "btree.h"
+
+/*
+ * __bt_ret --
+ *	Build return key/data pair.
+ *
+ * Parameters:
+ *	t:	tree
+ *	e:	key/data pair to be returned
+ *	key:	user's key structure (NULL if not to be filled in)
+ *	rkey:	memory area to hold key
+ *	data:	user's data structure (NULL if not to be filled in)
+ *	rdata:	memory area to hold data
+ *       copy:	always copy the key/data item
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_ret(t, e, key, rkey, data, rdata, copy)
+	BTREE *t;
+	EPG *e;
+	DBT *key, *rkey, *data, *rdata;
+	int copy;
+{
+	BLEAF *bl;
+	void *p;
+
+	bl = GETBLEAF(e->page, e->index);
+
+	/*
+	 * We must copy big keys/data to make them contigous.  Otherwise,
+	 * leave the page pinned and don't copy unless the user specified
+	 * concurrent access.
+	 */
+	if (key == NULL)
+		goto dataonly;
+
+	if (bl->flags & P_BIGKEY) {
+		if (__ovfl_get(t, bl->bytes,
+		    &key->size, &rkey->data, &rkey->size))
+			return (RET_ERROR);
+		key->data = rkey->data;
+	} else if (copy || F_ISSET(t, B_DB_LOCK)) {
+		if (bl->ksize > rkey->size) {
+			p = (void *)(rkey->data == NULL ?
+			    malloc(bl->ksize) : realloc(rkey->data, bl->ksize));
+			if (p == NULL)
+				return (RET_ERROR);
+			rkey->data = p;
+			rkey->size = bl->ksize;
+		}
+		memmove(rkey->data, bl->bytes, bl->ksize);
+		key->size = bl->ksize;
+		key->data = rkey->data;
+	} else {
+		key->size = bl->ksize;
+		key->data = bl->bytes;
+	}
+
+dataonly:
+	if (data == NULL)
+		return (RET_SUCCESS);
+
+	if (bl->flags & P_BIGDATA) {
+		if (__ovfl_get(t, bl->bytes + bl->ksize,
+		    &data->size, &rdata->data, &rdata->size))
+			return (RET_ERROR);
+		data->data = rdata->data;
+	} else if (copy || F_ISSET(t, B_DB_LOCK)) {
+		/* Use +1 in case the first record retrieved is 0 length. */
+		if (bl->dsize + 1 > rdata->size) {
+			p = (void *)(rdata->data == NULL ?
+			    malloc(bl->dsize + 1) :
+			    realloc(rdata->data, bl->dsize + 1));
+			if (p == NULL)
+				return (RET_ERROR);
+			rdata->data = p;
+			rdata->size = bl->dsize + 1;
+		}
+		memmove(rdata->data, bl->bytes + bl->ksize, bl->dsize);
+		data->size = bl->dsize;
+		data->data = rdata->data;
+	} else {
+		data->size = bl->dsize;
+		data->data = bl->bytes + bl->ksize;
+	}
+
+	return (RET_SUCCESS);
+}
+
+/*
+ * __BT_CMP -- Compare a key to a given record.
+ *
+ * Parameters:
+ *	t:	tree
+ *	k1:	DBT pointer of first arg to comparison
+ *	e:	pointer to EPG for comparison
+ *
+ * Returns:
+ *	< 0 if k1 is < record
+ *	= 0 if k1 is = record
+ *	> 0 if k1 is > record
+ */
+int
+__bt_cmp(t, k1, e)
+	BTREE *t;
+	const DBT *k1;
+	EPG *e;
+{
+	BINTERNAL *bi;
+	BLEAF *bl;
+	DBT k2;
+	PAGE *h;
+	void *bigkey;
+
+	/*
+	 * The left-most key on internal pages, at any level of the tree, is
+	 * guaranteed by the following code to be less than any user key.
+	 * This saves us from having to update the leftmost key on an internal
+	 * page when the user inserts a new key in the tree smaller than
+	 * anything we've yet seen.
+	 */
+	h = e->page;
+	if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & P_BLEAF))
+		return (1);
+
+	bigkey = NULL;
+	if (h->flags & P_BLEAF) {
+		bl = GETBLEAF(h, e->index);
+		if (bl->flags & P_BIGKEY)
+			bigkey = bl->bytes;
+		else {
+			k2.data = bl->bytes;
+			k2.size = bl->ksize;
+		}
+	} else {
+		bi = GETBINTERNAL(h, e->index);
+		if (bi->flags & P_BIGKEY)
+			bigkey = bi->bytes;
+		else {
+			k2.data = bi->bytes;
+			k2.size = bi->ksize;
+		}
+	}
+
+	if (bigkey) {
+		if (__ovfl_get(t, bigkey,
+		    &k2.size, &t->bt_rdata.data, &t->bt_rdata.size))
+			return (RET_ERROR);
+		k2.data = t->bt_rdata.data;
+	}
+	return ((*t->bt_cmp)(k1, &k2));
+}
+
+/*
+ * __BT_DEFCMP -- Default comparison routine.
+ *
+ * Parameters:
+ *	a:	DBT #1
+ *	b: 	DBT #2
+ *
+ * Returns:
+ *	< 0 if a is < b
+ *	= 0 if a is = b
+ *	> 0 if a is > b
+ */
+int
+__bt_defcmp(a, b)
+	const DBT *a, *b;
+{
+	register size_t len;
+	register u_char *p1, *p2;
+
+	/*
+	 * XXX
+	 * If a size_t doesn't fit in an int, this routine can lose.
+	 * What we need is a integral type which is guaranteed to be
+	 * larger than a size_t, and there is no such thing.
+	 */
+	len = MIN(a->size, b->size);
+	for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2)
+		if (*p1 != *p2)
+			return ((int)*p1 - (int)*p2);
+	return ((int)a->size - (int)b->size);
+}
+
+/*
+ * __BT_DEFPFX -- Default prefix routine.
+ *
+ * Parameters:
+ *	a:	DBT #1
+ *	b: 	DBT #2
+ *
+ * Returns:
+ *	Number of bytes needed to distinguish b from a.
+ */
+size_t
+__bt_defpfx(a, b)
+	const DBT *a, *b;
+{
+	register u_char *p1, *p2;
+	register size_t cnt, len;
+
+	cnt = 1;
+	len = MIN(a->size, b->size);
+	for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2, ++cnt)
+		if (*p1 != *p2)
+			return (cnt);
+
+	/* a->size must be <= b->size, or they wouldn't be in this order. */
+	return (a->size < b->size ? a->size + 1 : a->size);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/btree.h b/mechglue/src/plugins/kdb/db2/libdb2/btree/btree.h
new file mode 100644
index 000000000..171712749
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/btree.h
@@ -0,0 +1,383 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)btree.h	8.11 (Berkeley) 8/17/94
+ */
+
+/* Macros to set/clear/test flags. */
+#define	F_SET(p, f)	(p)->flags |= (f)
+#define	F_CLR(p, f)	(p)->flags &= ~(f)
+#define	F_ISSET(p, f)	((p)->flags & (f))
+
+#include "mpool.h"
+
+#define	DEFMINKEYPAGE	(2)		/* Minimum keys per page */
+#define	MINCACHE	(5)		/* Minimum cached pages */
+#define	MINPSIZE	(512)		/* Minimum page size */
+
+/*
+ * Page 0 of a btree file contains a copy of the meta-data.  This page is also
+ * used as an out-of-band page, i.e. page pointers that point to nowhere point
+ * to page 0.  Page 1 is the root of the btree.
+ */
+#define	P_INVALID	 0		/* Invalid tree page number. */
+#define	P_META		 0		/* Tree metadata page number. */
+#define	P_ROOT		 1		/* Tree root page number. */
+
+/*
+ * There are five page layouts in the btree: btree internal pages (BINTERNAL),
+ * btree leaf pages (BLEAF), recno internal pages (RINTERNAL), recno leaf pages
+ * (RLEAF) and overflow pages.  All five page types have a page header (PAGE).
+ * This implementation requires that values within structures NOT be padded.
+ * (ANSI C permits random padding.)  If your compiler pads randomly you'll have
+ * to do some work to get this package to run.
+ */
+typedef struct _page {
+	db_pgno_t	pgno;			/* this page's page number */
+	db_pgno_t	prevpg;			/* left sibling */
+	db_pgno_t	nextpg;			/* right sibling */
+
+#define	P_BINTERNAL	0x01		/* btree internal page */
+#define	P_BLEAF		0x02		/* leaf page */
+#define	P_OVERFLOW	0x04		/* overflow page */
+#define	P_RINTERNAL	0x08		/* recno internal page */
+#define	P_RLEAF		0x10		/* leaf page */
+#define P_TYPE		0x1f		/* type mask */
+#define	P_PRESERVE	0x20		/* never delete this chain of pages */
+	u_int32_t flags;
+
+	indx_t	lower;			/* lower bound of free space on page */
+	indx_t	upper;			/* upper bound of free space on page */
+	indx_t	linp[1];		/* indx_t-aligned VAR. LENGTH DATA */
+} PAGE;
+
+/* First and next index. */
+#define	BTDATAOFF							\
+	(sizeof(db_pgno_t) + sizeof(db_pgno_t) + sizeof(db_pgno_t) +		\
+	    sizeof(u_int32_t) + sizeof(indx_t) + sizeof(indx_t))
+#define	NEXTINDEX(p)	(((p)->lower - BTDATAOFF) / sizeof(indx_t))
+
+/*
+ * For pages other than overflow pages, there is an array of offsets into the
+ * rest of the page immediately following the page header.  Each offset is to
+ * an item which is unique to the type of page.  The h_lower offset is just
+ * past the last filled-in index.  The h_upper offset is the first item on the
+ * page.  Offsets are from the beginning of the page.
+ *
+ * If an item is too big to store on a single page, a flag is set and the item
+ * is a { page, size } pair such that the page is the first page of an overflow
+ * chain with size bytes of item.  Overflow pages are simply bytes without any
+ * external structure.
+ *
+ * The page number and size fields in the items are db_pgno_t-aligned so they can
+ * be manipulated without copying.  (This presumes that 32 bit items can be
+ * manipulated on this system.)
+ */
+#define	LALIGN(n)	(((n) + sizeof(db_pgno_t) - 1) & ~(sizeof(db_pgno_t) - 1))
+#define	NOVFLSIZE	(sizeof(db_pgno_t) + sizeof(u_int32_t))
+
+/*
+ * For the btree internal pages, the item is a key.  BINTERNALs are {key, pgno}
+ * pairs, such that the key compares less than or equal to all of the records
+ * on that page.  For a tree without duplicate keys, an internal page with two
+ * consecutive keys, a and b, will have all records greater than or equal to a
+ * and less than b stored on the page associated with a.  Duplicate keys are
+ * somewhat special and can cause duplicate internal and leaf page records and
+ * some minor modifications of the above rule.
+ */
+typedef struct _binternal {
+	u_int32_t ksize;		/* key size */
+	db_pgno_t	pgno;			/* page number stored on */
+#define	P_BIGDATA	0x01		/* overflow data */
+#define	P_BIGKEY	0x02		/* overflow key */
+	u_char	flags;
+	char	bytes[1];		/* data */
+} BINTERNAL;
+
+/* Get the page's BINTERNAL structure at index indx. */
+#define	GETBINTERNAL(pg, indx)						\
+	((BINTERNAL *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NBINTERNAL(len)							\
+	LALIGN(sizeof(u_int32_t) + sizeof(db_pgno_t) + sizeof(u_char) + (len))
+
+/* Copy a BINTERNAL entry to the page. */
+#define	WR_BINTERNAL(p, size, pgno, flags) {				\
+	*(u_int32_t *)p = size;						\
+	p += sizeof(u_int32_t);						\
+	*(db_pgno_t *)p = pgno;						\
+	p += sizeof(db_pgno_t);						\
+	*(u_char *)p = flags;						\
+	p += sizeof(u_char);						\
+}
+
+/*
+ * For the recno internal pages, the item is a page number with the number of
+ * keys found on that page and below.
+ */
+typedef struct _rinternal {
+	recno_t	nrecs;			/* number of records */
+	db_pgno_t	pgno;			/* page number stored below */
+} RINTERNAL;
+
+/* Get the page's RINTERNAL structure at index indx. */
+#define	GETRINTERNAL(pg, indx)						\
+	((RINTERNAL *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NRINTERNAL							\
+	LALIGN(sizeof(recno_t) + sizeof(db_pgno_t))
+
+/* Copy a RINTERAL entry to the page. */
+#define	WR_RINTERNAL(p, nrecs, pgno) {					\
+	*(recno_t *)p = nrecs;						\
+	p += sizeof(recno_t);						\
+	*(db_pgno_t *)p = pgno;						\
+}
+
+/* For the btree leaf pages, the item is a key and data pair. */
+typedef struct _bleaf {
+	u_int32_t	ksize;		/* size of key */
+	u_int32_t	dsize;		/* size of data */
+	u_char	flags;			/* P_BIGDATA, P_BIGKEY */
+	char	bytes[1];		/* data */
+} BLEAF;
+
+/* Get the page's BLEAF structure at index indx. */
+#define	GETBLEAF(pg, indx)						\
+	((BLEAF *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NBLEAF(p)	NBLEAFDBT((p)->ksize, (p)->dsize)
+
+/* Get the number of bytes in the user's key/data pair. */
+#define NBLEAFDBT(ksize, dsize)						\
+	LALIGN(sizeof(u_int32_t) + sizeof(u_int32_t) + sizeof(u_char) +	\
+	    (ksize) + (dsize))
+
+/* Copy a BLEAF entry to the page. */
+#define	WR_BLEAF(p, key, data, flags) {					\
+	*(u_int32_t *)p = key->size;					\
+	p += sizeof(u_int32_t);						\
+	*(u_int32_t *)p = data->size;					\
+	p += sizeof(u_int32_t);						\
+	*(u_char *)p = flags;						\
+	p += sizeof(u_char);						\
+	memmove(p, key->data, key->size);				\
+	p += key->size;							\
+	memmove(p, data->data, data->size);				\
+}
+
+/* For the recno leaf pages, the item is a data entry. */
+typedef struct _rleaf {
+	u_int32_t	dsize;		/* size of data */
+	u_char	flags;			/* P_BIGDATA */
+	char	bytes[1];
+} RLEAF;
+
+/* Get the page's RLEAF structure at index indx. */
+#define	GETRLEAF(pg, indx)						\
+	((RLEAF *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NRLEAF(p)	NRLEAFDBT((p)->dsize)
+
+/* Get the number of bytes from the user's data. */
+#define	NRLEAFDBT(dsize)						\
+	LALIGN(sizeof(u_int32_t) + sizeof(u_char) + (dsize))
+
+/* Copy a RLEAF entry to the page. */
+#define	WR_RLEAF(p, data, flags) {					\
+	*(u_int32_t *)p = data->size;					\
+	p += sizeof(u_int32_t);						\
+	*(u_char *)p = flags;						\
+	p += sizeof(u_char);						\
+	memmove(p, data->data, data->size);				\
+}
+
+/*
+ * A record in the tree is either a pointer to a page and an index in the page
+ * or a page number and an index.  These structures are used as a cursor, stack
+ * entry and search returns as well as to pass records to other routines.
+ *
+ * One comment about searches.  Internal page searches must find the largest
+ * record less than key in the tree so that descents work.  Leaf page searches
+ * must find the smallest record greater than key so that the returned index
+ * is the record's correct position for insertion.
+ */
+typedef struct _epgno {
+	db_pgno_t	pgno;			/* the page number */
+	indx_t	index;			/* the index on the page */
+} EPGNO;
+
+typedef struct _epg {
+	PAGE	*page;			/* the (pinned) page */
+	indx_t	 index;			/* the index on the page */
+} EPG;
+
+/*
+ * About cursors.  The cursor (and the page that contained the key/data pair
+ * that it referenced) can be deleted, which makes things a bit tricky.  If
+ * there are no duplicates of the cursor key in the tree (i.e. B_NODUPS is set
+ * or there simply aren't any duplicates of the key) we copy the key that it
+ * referenced when it's deleted, and reacquire a new cursor key if the cursor
+ * is used again.  If there are duplicates keys, we move to the next/previous
+ * key, and set a flag so that we know what happened.  NOTE: if duplicate (to
+ * the cursor) keys are added to the tree during this process, it is undefined
+ * if they will be returned or not in a cursor scan.
+ *
+ * The flags determine the possible states of the cursor:
+ *
+ * CURS_INIT	The cursor references *something*.
+ * CURS_ACQUIRE	The cursor was deleted, and a key has been saved so that
+ *		we can reacquire the right position in the tree.
+ * CURS_AFTER, CURS_BEFORE
+ *		The cursor was deleted, and now references a key/data pair
+ *		that has not yet been returned, either before or after the
+ *		deleted key/data pair.
+ * XXX
+ * This structure is broken out so that we can eventually offer multiple
+ * cursors as part of the DB interface.
+ */
+typedef struct _cursor {
+	EPGNO	 pg;			/* B: Saved tree reference. */
+	DBT	 key;			/* B: Saved key, or key.data == NULL. */
+	recno_t	 rcursor;		/* R: recno cursor (1-based) */
+
+#define	CURS_ACQUIRE	0x01		/*  B: Cursor needs to be reacquired. */
+#define	CURS_AFTER	0x02		/*  B: Unreturned cursor after key. */
+#define	CURS_BEFORE	0x04		/*  B: Unreturned cursor before key. */
+#define	CURS_INIT	0x08		/* RB: Cursor initialized. */
+	u_int8_t flags;
+} CURSOR;
+
+/*
+ * The metadata of the tree.  The nrecs field is used only by the RECNO code.
+ * This is because the btree doesn't really need it and it requires that every
+ * put or delete call modify the metadata.
+ */
+typedef struct _btmeta {
+	u_int32_t	magic;		/* magic number */
+	u_int32_t	version;	/* version */
+	u_int32_t	psize;		/* page size */
+	u_int32_t	free;		/* page number of first free page */
+	u_int32_t	nrecs;		/* R: number of records */
+
+#define	SAVEMETA	(B_NODUPS | R_RECNO)
+	u_int32_t	flags;		/* bt_flags & SAVEMETA */
+} BTMETA;
+
+/* The in-memory btree/recno data structure. */
+typedef struct _btree {
+	MPOOL	 *bt_mp;		/* memory pool cookie */
+
+	DB	 *bt_dbp;		/* pointer to enclosing DB */
+
+	EPG	  bt_cur;		/* current (pinned) page */
+	PAGE	 *bt_pinned;		/* page pinned across calls */
+
+	CURSOR	  bt_cursor;		/* cursor */
+
+#define	BT_PUSH(t, p, i) {						\
+	t->bt_sp->pgno = p; 						\
+	t->bt_sp->index = i; 						\
+	++t->bt_sp;							\
+}
+#define	BT_POP(t)	(t->bt_sp == t->bt_stack ? NULL : --t->bt_sp)
+#define	BT_CLR(t)	(t->bt_sp = t->bt_stack)
+	EPGNO	  bt_stack[50];		/* stack of parent pages */
+	EPGNO	 *bt_sp;		/* current stack pointer */
+
+	DBT	  bt_rkey;		/* returned key */
+	DBT	  bt_rdata;		/* returned data */
+
+	int	  bt_fd;		/* tree file descriptor */
+
+	db_pgno_t	  bt_free;		/* next free page */
+	u_int32_t bt_psize;		/* page size */
+	indx_t	  bt_ovflsize;		/* cut-off for key/data overflow */
+	int	  bt_lorder;		/* byte order */
+					/* sorted order */
+	enum { NOT, BACK, FORWARD } bt_order;
+	EPGNO	  bt_last;		/* last insert */
+
+					/* B: key comparison function */
+	int	(*bt_cmp) __P((const DBT *, const DBT *));
+					/* B: prefix comparison function */
+	size_t	(*bt_pfx) __P((const DBT *, const DBT *));
+					/* R: recno input function */
+	int	(*bt_irec) __P((struct _btree *, recno_t));
+
+	FILE	 *bt_rfp;		/* R: record FILE pointer */
+	int	  bt_rfd;		/* R: record file descriptor */
+
+	caddr_t	  bt_cmap;		/* R: current point in mapped space */
+	caddr_t	  bt_smap;		/* R: start of mapped space */
+	caddr_t   bt_emap;		/* R: end of mapped space */
+	size_t	  bt_msize;		/* R: size of mapped region. */
+
+	recno_t	  bt_nrecs;		/* R: number of records */
+	size_t	  bt_reclen;		/* R: fixed record length */
+	u_char	  bt_bval;		/* R: delimiting byte/pad character */
+
+/*
+ * NB:
+ * B_NODUPS and R_RECNO are stored on disk, and may not be changed.
+ */
+#define	B_INMEM		0x00001		/* in-memory tree */
+#define	B_METADIRTY	0x00002		/* need to write metadata */
+#define	B_MODIFIED	0x00004		/* tree modified */
+#define	B_NEEDSWAP	0x00008		/* if byte order requires swapping */
+#define	B_RDONLY	0x00010		/* read-only tree */
+
+#define	B_NODUPS	0x00020		/* no duplicate keys permitted */
+#define	R_RECNO		0x00080		/* record oriented tree */
+
+#define	R_CLOSEFP	0x00040		/* opened a file pointer */
+#define	R_EOF		0x00100		/* end of input file reached. */
+#define	R_FIXLEN	0x00200		/* fixed length records */
+#define	R_MEMMAPPED	0x00400		/* memory mapped file. */
+#define	R_INMEM		0x00800		/* in-memory file */
+#define	R_MODIFIED	0x01000		/* modified file */
+#define	R_RDONLY	0x02000		/* read-only file */
+
+#define	B_DB_LOCK	0x04000		/* DB_LOCK specified. */
+#define	B_DB_SHMEM	0x08000		/* DB_SHMEM specified. */
+#define	B_DB_TXN	0x10000		/* DB_TXN specified. */
+	u_int32_t flags;
+} BTREE;
+
+#include "extern.h"
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/btree/extern.h b/mechglue/src/plugins/kdb/db2/libdb2/btree/extern.h
new file mode 100644
index 000000000..3aa88417e
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/btree/extern.h
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.11 (Berkeley) 1/9/95
+ */
+
+#define __bt_close	__kdb2_bt_close
+#define __bt_cmp	__kdb2_bt_cmp
+#define __bt_crsrdel	__kdb2_bt_crsrdel
+#define __bt_defcmp	__kdb2_bt_defcmp
+#define __bt_defpfx	__kdb2_bt_defpfx
+#define __bt_delete	__kdb2_bt_delete
+#define __bt_dleaf	__kdb2_bt_deleaf
+#define __bt_fd		__kdb2_bt_fd
+#define __bt_free	__kdb2_bt_free
+#define __bt_get	__kdb2_bt_get
+#define __bt_new	__kdb2_bt_new
+#define __bt_pgin	__kdb2_bt_pgin
+#define __bt_pgout	__kdb2_bt_pgout
+#define __bt_push	__kdb2_bt_push
+#define __bt_put	__kdb2_bt_put
+#define __bt_ret	__kdb2_bt_ret
+#define __bt_search	__kdb2_bt_search
+#define __bt_seq	__kdb2_bt_seq
+#define __bt_setcur	__kdb2_bt_setcur
+#define __bt_split	__kdb2_bt_split
+#define __bt_sync	__kdb2_bt_sync
+#define __ovfl_delete	__kdb2_ovfl_delete
+#define __ovfl_get	__kdb2_ovfl_get
+#define __ovfl_put	__kdb2_ovfl_put
+#define __bt_dnpage	__kdb2_bt_dnpage
+#define __bt_dmpage	__kdb2_bt_dmpage
+#define __bt_dpage	__kdb2_bt_dpage
+#define __bt_dump	__kdb2_bt_dump
+#define __bt_stat	__kdb2_bt_stat
+
+#define bt_rcinit	kdb2_bt_rcinit
+#define bt_rcdestroy	kdb2_bt_rcdestroy
+#define bt_rcpush	kdb2_bt_rcpush
+#define bt_rcpop	kdb2_bt_rcpop
+#define bt_rcclr	kdb2_bt_rcclr
+#define bt_rcgrowstk	kdb2_bt_rcgrowstk
+#define bt_rseqset	kdb2_bt_rseqset
+#define bt_rseqadv	kdb2_bt_rseqadv
+
+int	 __bt_close __P((DB *));
+int	 __bt_cmp __P((BTREE *, const DBT *, EPG *));
+int	 __bt_crsrdel __P((BTREE *, EPGNO *));
+int	 __bt_defcmp __P((const DBT *, const DBT *));
+size_t	 __bt_defpfx __P((const DBT *, const DBT *));
+int	 __bt_delete __P((const DB *, const DBT *, u_int));
+int	 __bt_dleaf __P((BTREE *, const DBT *, PAGE *, u_int));
+int	 __bt_fd __P((const DB *));
+int	 __bt_free __P((BTREE *, PAGE *));
+int	 __bt_get __P((const DB *, const DBT *, DBT *, u_int));
+PAGE	*__bt_new __P((BTREE *, db_pgno_t *));
+void	 __bt_pgin __P((void *, db_pgno_t, void *));
+void	 __bt_pgout __P((void *, db_pgno_t, void *));
+int	 __bt_push __P((BTREE *, db_pgno_t, int));
+int	 __bt_put __P((const DB *dbp, DBT *, const DBT *, u_int));
+int	 __bt_ret __P((BTREE *, EPG *, DBT *, DBT *, DBT *, DBT *, int));
+EPG	*__bt_search __P((BTREE *, const DBT *, int *));
+int	 __bt_seq __P((const DB *, DBT *, DBT *, u_int));
+void	 __bt_setcur __P((BTREE *, db_pgno_t, u_int));
+int	 __bt_split __P((BTREE *, PAGE *,
+	    const DBT *, const DBT *, int, size_t, u_int32_t));
+int	 __bt_sync __P((const DB *, u_int));
+
+int	 __ovfl_delete __P((BTREE *, void *));
+int	 __ovfl_get __P((BTREE *, void *, size_t *, void **, size_t *));
+int	 __ovfl_put __P((BTREE *, const DBT *, db_pgno_t *));
+
+#ifdef DEBUG
+int	 __bt_dnpage __P((DB *, db_pgno_t));
+int	 __bt_dpage __P((DB *, PAGE *));
+int	 __bt_dmpage __P((PAGE *));
+int	 __bt_dump __P((DB *));
+#endif
+#ifdef STATISTICS
+int	 __bt_stat __P((DB *));
+#endif
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/clib/Makefile.in b/mechglue/src/plugins/kdb/db2/libdb2/clib/Makefile.in
new file mode 100644
index 000000000..09f808967
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/clib/Makefile.in
@@ -0,0 +1,11 @@
+thisconfigdir=./..
+myfulldir=plugins/kdb/db2/libdb2/clib
+mydir=clib
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..$(S)..
+STLIBOBJS=@MEMMOVE_OBJ@ @MKSTEMP_OBJ@ @STRERROR_OBJ@
+
+LOCALINCLUDES=-I../include
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+# @libobj_frag@
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/clib/memmove.c b/mechglue/src/plugins/kdb/db2/libdb2/clib/memmove.c
new file mode 100644
index 000000000..f9bf650a3
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/clib/memmove.c
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bcopy.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+/*
+ * sizeof(word) MUST BE A POWER OF TWO
+ * SO THAT wmask BELOW IS ALL ONES
+ */
+typedef	int word;		/* "word" used for optimal copy speed */
+
+#define	wsize	sizeof(word)
+#define	wmask	(wsize - 1)
+
+/*
+ * Copy a block of memory, handling overlap.
+ * This is the routine that actually implements
+ * (the portable versions of) bcopy, memcpy, and memmove.
+ */
+#ifdef MEMCOPY
+void *
+memcpy(dst0, src0, length)
+#else
+#ifdef MEMMOVE
+void *
+memmove(dst0, src0, length)
+#else
+void
+bcopy(src0, dst0, length)
+#endif
+#endif
+	void *dst0;
+	const void *src0;
+	register size_t length;
+{
+	register char *dst = dst0;
+	register const char *src = src0;
+	register size_t t;
+
+	if (length == 0 || dst == src)		/* nothing to do */
+		goto done;
+
+	/*
+	 * Macros: loop-t-times; and loop-t-times, t>0
+	 */
+#define	TLOOP(s) if (t) TLOOP1(s)
+#define	TLOOP1(s) do { s; } while (--t)
+
+	if ((unsigned long)dst < (unsigned long)src) {
+		/*
+		 * Copy forward.
+		 */
+		t = (int)src;	/* only need low bits */
+		if ((t | (int)dst) & wmask) {
+			/*
+			 * Try to align operands.  This cannot be done
+			 * unless the low bits match.
+			 */
+			if ((t ^ (int)dst) & wmask || length < wsize)
+				t = length;
+			else
+				t = wsize - (t & wmask);
+			length -= t;
+			TLOOP1(*dst++ = *src++);
+		}
+		/*
+		 * Copy whole words, then mop up any trailing bytes.
+		 */
+		t = length / wsize;
+		TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
+		t = length & wmask;
+		TLOOP(*dst++ = *src++);
+	} else {
+		/*
+		 * Copy backwards.  Otherwise essentially the same.
+		 * Alignment works as before, except that it takes
+		 * (t&wmask) bytes to align, not wsize-(t&wmask).
+		 */
+		src += length;
+		dst += length;
+		t = (int)src;
+		if ((t | (int)dst) & wmask) {
+			if ((t ^ (int)dst) & wmask || length <= wsize)
+				t = length;
+			else
+				t &= wmask;
+			length -= t;
+			TLOOP1(*--dst = *--src);
+		}
+		t = length / wsize;
+		TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
+		t = length & wmask;
+		TLOOP(*--dst = *--src);
+	}
+done:
+#if defined(MEMCOPY) || defined(MEMMOVE)
+	return (dst0);
+#else
+	return;
+#endif
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/clib/mkstemp.c b/mechglue/src/plugins/kdb/db2/libdb2/clib/mkstemp.c
new file mode 100644
index 000000000..71dc7d17a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/clib/mkstemp.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1987, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mktemp.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static int _gettemp();
+
+mkstemp(path)
+	char *path;
+{
+	int fd;
+
+	return (_gettemp(path, &fd) ? fd : -1);
+}
+
+static
+_gettemp(path, doopen)
+	char *path;
+	register int *doopen;
+{
+	register char *start, *trv;
+	struct stat sbuf;
+	u_int pid;
+
+	pid = getpid();
+	for (trv = path; *trv; ++trv);		/* extra X's get set to 0's */
+	while (*--trv == 'X') {
+		*trv = (pid % 10) + '0';
+		pid /= 10;
+	}
+
+	/*
+	 * check the target directory; if you have six X's and it
+	 * doesn't exist this runs for a *very* long time.
+	 */
+	for (start = trv + 1;; --trv) {
+		if (trv <= path)
+			break;
+		if (*trv == '/') {
+			*trv = '\0';
+			if (stat(path, &sbuf))
+				return(0);
+			if (!S_ISDIR(sbuf.st_mode)) {
+				errno = ENOTDIR;
+				return(0);
+			}
+			*trv = '/';
+			break;
+		}
+	}
+
+	for (;;) {
+		if (doopen) {
+			if ((*doopen =
+			    open(path, O_CREAT|O_EXCL|O_RDWR|O_BINARY, 0600)) >= 0)
+				return(1);
+			if (errno != EEXIST)
+				return(0);
+		}
+		else if (stat(path, &sbuf))
+			return(errno == ENOENT ? 1 : 0);
+
+		/* tricky little algorithm for backward compatibility */
+		for (trv = start;;) {
+			if (!*trv)
+				return(0);
+			if (*trv == 'z')
+				*trv++ = 'a';
+			else {
+				if (isdigit(*trv))
+					*trv = 'a';
+				else
+					++*trv;
+				break;
+			}
+		}
+	}
+	/*NOTREACHED*/
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/clib/strerror.c b/mechglue/src/plugins/kdb/db2/libdb2/clib/strerror.c
new file mode 100644
index 000000000..0a509f79f
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/clib/strerror.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strerror.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+char *
+strerror(num)
+	int num;
+{
+	extern int sys_nerr;
+	extern char *sys_errlist[];
+#define	UPREFIX	"Unknown error: "
+	static char ebuf[40] = UPREFIX;		/* 64-bit number + slop */
+	register unsigned int errnum;
+	register char *p, *t;
+	char tmp[40];
+
+	errnum = num;				/* convert to unsigned */
+	if (errnum < sys_nerr)
+		return(sys_errlist[errnum]);
+
+	/* Do this by hand, so we don't include stdio(3). */
+	t = tmp;
+	do {
+		*t++ = "0123456789"[errnum % 10];
+	} while (errnum /= 10);
+	for (p = ebuf + sizeof(UPREFIX) - 1;;) {
+		*p++ = *--t;
+		if (t <= tmp)
+			break;
+	}
+	return(ebuf);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/configure.in b/mechglue/src/plugins/kdb/db2/libdb2/configure.in
new file mode 100644
index 000000000..9a339b0bb
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/configure.in
@@ -0,0 +1,97 @@
+dnl Process this file with autoconf to produce a configure script.
+K5_AC_INIT(db/db.c)
+AC_CONFIG_HEADER(include/config.h include/db-config.h)
+build_dynobj=yes
+CONFIG_RULES
+
+AC_PATH_PROG(FALSE,false,:)
+AC_PATH_PROG(SH,sh,$FALSE)
+AC_PATH_PROG(SH5,sh5,$FALSE)
+AC_PATH_PROG(BASH,bash,$FALSE)
+
+AC_CACHE_CHECK([checking for shell with functions],local_cv_program_fctsh,
+[if $SH -c 'foo() { true; }; foo' > /dev/null 2>&1; then
+	local_cv_program_fctsh=$SH
+else
+	if $SH5 -c 'foo() { true; }; foo' > /dev/null 2>&1; then
+		local_cv_program_fctsh=$SH5
+	else
+		if $BASH -c 'foo() { true; }; foo' > /dev/null 2>&1; then
+			local_cv_program_fctsh=$BASH
+		else
+			local_cv_program_fctsh=$FALSE
+		fi
+	fi
+fi])
+
+FCTSH=$local_cv_program_fctsh
+AC_SUBST(FCTSH)
+
+dnl checks for libraries
+dnl checks for header files
+AC_CHECK_HEADERS(unistd.h stdint.h inttypes.h)
+dnl checks for typedefs
+AC_TYPE_SIZE_T
+
+dnl AC_COMPILE_TYPE(TYPE, DEFAULT)
+AC_DEFUN(AC_COMPILE_TYPE,
+[AC_REQUIRE([AC_HEADER_STDC])dnl
+AC_MSG_CHECKING(for $1)
+AC_CACHE_VAL(ac_cv_type_$1,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif], [$1 test_variable;], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl
+AC_MSG_RESULT($ac_cv_type_$1)
+if test $ac_cv_type_$1 = no; then
+  AC_DEFINE($1, $2, [Define to \`$2' if not defined on system])
+fi
+])
+
+
+AC_CHECK_TYPE(ssize_t, int)
+
+AC_CHECK_TYPE(u_char, unsigned char)
+AC_CHECK_TYPE(u_int, unsigned int)
+AC_CHECK_TYPE(u_long, unsigned long)
+
+AC_CHECK_TYPE(int8_t, signed char)
+AC_CHECK_TYPE(u_int8_t, unsigned char)
+AC_CHECK_TYPE(int16_t, short)
+AC_CHECK_TYPE(u_int16_t, unsigned short)
+AC_COMPILE_TYPE(int32_t, int)
+AC_COMPILE_TYPE(u_int32_t, unsigned int)
+
+dnl checks for structures
+dnl checks for compiler characteristics
+dnl AC_C_BIGENDIAN - No, check at compile time; Darwin can build for multiple
+dnl                  targets in one tree.
+AC_CHECK_HEADERS(endian.h machine/endian.h sys/param.h)
+dnl sys/param.h for AIX 4.3.3 (actually sys/machine.h)
+dnl There's also sys/endian.h on IRIX, but we already check _MIPSE{L,B}.
+AC_C_CONST
+AC_CHECK_SIZEOF(int)
+
+dnl checks for library functions
+AC_CHECK_FUNC(memmove, ,
+[MEMMOVE_OBJ=memmove.o
+AC_DEFINE(memmove, kdb2__memmove,[Define to kdb2__memmove to provide private memmove function])
+AC_DEFINE(MEMMOVE,1,[Define if memmove.o is compiled in])])
+AC_SUBST(MEMMOVE_OBJ)
+
+AC_CHECK_FUNC(mkstemp, ,
+[MKSTEMP_OBJ=mkstemp.o
+AC_DEFINE(mkstemp, kdb2__mkstemp,[Define to \`kdb2__mkstemp' to provide private mkstemp function])])
+AC_SUBST(MKSTEMP_OBJ)
+
+AC_CHECK_FUNC(strerror, ,
+[STRERROR_OBJ=strerror.o
+AC_DEFINE(strerror, kdb2__strerror,[Define to \`kdb2__strerror' to provide private strerror function])])
+AC_SUBST(STRERROR_OBJ)
+
+KRB5_BUILD_LIBRARY
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_PROGRAM
+KRB5_RUN_FLAGS
+AC_CONFIG_FILES(include/generated.stmp:Makefile.in)
+V5_AC_OUTPUT_MAKEFILE(. hash btree db mpool recno clib test)
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/db/Makefile.in b/mechglue/src/plugins/kdb/db2/libdb2/db/Makefile.in
new file mode 100644
index 000000000..074bb7f32
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/db/Makefile.in
@@ -0,0 +1,11 @@
+thisconfigdir=./..
+myfulldir=plugins/kdb/db2/libdb2/db
+mydir=db
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..$(S)..
+STLIBOBJS=db.o
+
+LOCALINCLUDES=	-I. -I$(srcdir)/../include -I../include -I$(srcdir)/../mpool
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+# @libobj_frag@
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/db/Makefile.inc b/mechglue/src/plugins/kdb/db2/libdb2/db/Makefile.inc
new file mode 100644
index 000000000..59478ba19
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/db/Makefile.inc
@@ -0,0 +1,5 @@
+#       @(#)Makefile.inc	8.1 (Berkeley) 6/4/93
+
+.PATH: ${.CURDIR}/db/db
+
+SRCS+=	db.c
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/db/db.c b/mechglue/src/plugins/kdb/db2/libdb2/db/db.c
new file mode 100644
index 000000000..fba779534
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/db/db.c
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)db.c	8.4 (Berkeley) 2/21/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include "db-int.h"
+
+DB *
+kdb2_dbopen(fname, flags, mode, type, openinfo)
+	const char *fname;
+	int flags, mode;
+	DBTYPE type;
+	const void *openinfo;
+{
+
+#define	DB_FLAGS	(DB_LOCK | DB_SHMEM | DB_TXN)
+#define	USE_OPEN_FLAGS							\
+	(O_CREAT | O_EXCL | O_EXLOCK | O_NONBLOCK | O_RDONLY |		\
+	 O_RDWR | O_SHLOCK | O_TRUNC | O_BINARY)
+
+	if ((flags & ~(USE_OPEN_FLAGS | DB_FLAGS)) == 0)
+		switch (type) {
+		case DB_BTREE:
+			return (__bt_open(fname, flags & USE_OPEN_FLAGS,
+			    mode, openinfo, flags & DB_FLAGS));
+		case DB_HASH:
+			return (__hash_open(fname, flags & USE_OPEN_FLAGS,
+			    mode, openinfo, flags & DB_FLAGS));
+		case DB_RECNO:
+			return (__rec_open(fname, flags & USE_OPEN_FLAGS,
+			    mode, openinfo, flags & DB_FLAGS));
+		}
+	errno = EINVAL;
+	return (NULL);
+}
+
+static int
+__dberr()
+{
+	return (RET_ERROR);
+}
+
+/*
+ * __DBPANIC -- Stop.
+ *
+ * Parameters:
+ *	dbp:	pointer to the DB structure.
+ */
+void
+__dbpanic(dbp)
+	DB *dbp;
+{
+	/* The only thing that can succeed is a close. */
+	dbp->del = (int (*)())__dberr;
+	dbp->fd = (int (*)())__dberr;
+	dbp->get = (int (*)())__dberr;
+	dbp->put = (int (*)())__dberr;
+	dbp->seq = (int (*)())__dberr;
+	dbp->sync = (int (*)())__dberr;
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/docs/btree.3.ps b/mechglue/src/plugins/kdb/db2/libdb2/docs/btree.3.ps
new file mode 100644
index 000000000..c79c97232
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/docs/btree.3.ps
@@ -0,0 +1,366 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 2
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll 
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 132.34(BTREE\(3\) BSD)72 48 R(Programmer')2.5 E 2.5(sM)
+-.55 G 132.34(anual BTREE\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72 84 S
+(ME).18 E F0(btree \255 btree database access method)108 96 Q F1(SYNOPSIS)72
+112.8 Q/F2 10/Times-Bold@0 SF(#include <sys/types.h>)108 124.8 Q(#include <db)
+108 136.8 Q(.h>)-.4 E F1(DESCRIPTION)72 153.6 Q F0 .198(The routine)108 165.6 R
+/F3 10/Times-Italic@0 SF(dbopen)2.698 E F0 .198(is the library interf)2.698 F
+.198(ace to database \214les.)-.1 F .198
+(One of the supported \214le formats is btree \214les.)5.198 F .974
+(The general description of the database access methods is in)108 177.6 R F3
+(dbopen)3.475 E F0 .975(\(3\), this manual page describes only).24 F
+(the btree speci\214c information.)108 189.6 Q(The btree data structure is a s\
+orted, balanced tree structure storing associated k)108 206.4 Q -.15(ey)-.1 G
+(/data pairs.).15 E .504(The btree access method speci\214c data structure pro)
+108 223.2 R .504(vided to)-.15 F F3(dbopen)3.004 E F0 .503
+(is de\214ned in the <db)3.003 F .503(.h> include \214le as)-.4 F(follo)108
+235.2 Q(ws:)-.25 E(typedef struct {)108 252 Q(u_long \215ags;)144 264 Q
+(u_int cachesize;)144 276 Q(inde)144 288 Q(x_t psize;)-.15 E(int lorder;)144
+300 Q(int mink)144 312 Q -.15(ey)-.1 G(page;).15 E
+(int \(*compare\)\(const DBT *k)144 324 Q -.15(ey)-.1 G(1, const DBT *k).15 E
+-.15(ey)-.1 G(2\);).15 E(int \(*pre\214x\)\(const DBT *k)144 336 Q -.15(ey)-.1
+G(1, const DBT *k).15 E -.15(ey)-.1 G(2\);).15 E 2.5(}B)108 348 S(TREEINFO;)
+121.97 348 Q(The elements of this structure are as follo)108 364.8 Q(ws:)-.25 E
+14.61(\215ags The)108 381.6 R(\215ag v)2.5 E(alue is speci\214ed by)-.25 E F3
+(or)2.5 E F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)313.2 381.6 S(he follo)321.81
+381.6 Q(wing v)-.25 E(alues:)-.25 E(R_DUP)144 398.4 Q 1.296(Permit duplicate k)
+180 410.4 R -.15(ey)-.1 G 3.796(si).15 G 3.796(nt)275.578 410.4 S 1.296
+(he tree, i.e. permit insertion if the k)287.154 410.4 R 1.596 -.15(ey t)-.1 H
+3.796(ob).15 G 3.796(ei)466.878 410.4 S 1.296(nserted already)477.894 410.4 R
+-.15(ex)180 422.4 S 1.935(ists in the tree.).15 F 1.935(The def)6.935 F 1.935
+(ault beha)-.1 F(vior)-.2 E 4.435(,a)-.4 G 4.435(sd)358.215 422.4 S 1.935
+(escribed in)371.54 422.4 R F3(dbopen)4.435 E F0 1.935(\(3\), is to o).24 F
+-.15(ve)-.15 G 1.935(rwrite a).15 F .148(matching k)180 434.4 R .448 -.15(ey w)
+-.1 H .148(hen inserting a ne).15 F 2.649(wk)-.25 G .449 -.15(ey o)329.709
+434.4 T 2.649(rt).15 G 2.649(of)355.407 434.4 S .149(ail if the R_NOO)366.286
+434.4 R(VER)-.5 E .149(WRITE \215ag is speci-)-.55 F 5.972(\214ed. The)180
+446.4 R 3.472(R_DUP \215ag is o)5.972 F -.15(ve)-.15 G 3.472
+(rridden by the R_NOO).15 F(VER)-.5 E 3.471(WRITE \215ag, and if the)-.55 F
+(R_NOO)180 458.4 Q(VER)-.5 E .781
+(WRITE \215ag is speci\214ed, attempts to insert duplicate k)-.55 F -.15(ey)-.1
+G 3.282(si).15 G .782(nto the tree will)474.604 458.4 R -.1(fa)180 470.4 S(il.)
+.1 E 1.13(If the database contains duplicate k)180 487.2 R -.15(ey)-.1 G 1.129
+(s, the order of retrie).15 F -.25(va)-.25 G 3.629(lo).25 G 3.629(fk)439.644
+487.2 S -.15(ey)451.503 487.2 S 1.129(/data pairs is unde-).15 F .837
+(\214ned if the)180 499.2 R F3 -.1(ge)3.337 G(t).1 E F0 .837
+(routine is used, ho)3.337 F(we)-.25 E -.15(ve)-.25 G -.4(r,).15 G F3(seq)3.737
+E F0 .838(routine calls with the R_CURSOR \215ag set)3.337 F(will al)180 511.2
+Q -.1(wa)-.1 G(ys return the logical `).1 E(`\214rst')-.74 E 2.5('o)-.74 G 2.5
+(fa)333.85 511.2 S .3 -.15(ny g)344.12 511.2 T(roup of duplicate k).15 E -.15
+(ey)-.1 G(s.).15 E(cachesize)108 528 Q 3.056(As)144 540 S .556
+(uggested maximum size \(in bytes\) of the memory cache.)158.166 540 R .555
+(This v)5.556 F .555(alue is)-.25 F F2(only)3.055 E F0(advisory)3.055 E 3.055
+(,a)-.65 G .555(nd the)514.725 540 R .759
+(access method will allocate more memory rather than f)144 552 R 3.259
+(ail. Since)-.1 F -2.15 -.25(ev e)3.259 H .76(ry search e).25 F .76
+(xamines the root)-.15 F .055
+(page of the tree, caching the most recently used pages substantially impro)144
+564 R -.15(ve)-.15 G 2.554(sa).15 G .054(ccess time.)459.578 564 R .054
+(In addi-)5.054 F .661(tion, ph)144 576 R .662(ysical writes are delayed as lo\
+ng as possible, so a moderate cache can reduce the number)-.05 F .601
+(of I/O operations signi\214cantly)144 588 R 5.601(.O)-.65 G -.15(bv)280.744
+588 S(iously).15 E 3.101(,u)-.65 G .601(sing a cache increases \(b)324.995 588
+R .6(ut only increases\) the lik)-.2 F(eli-)-.1 E .19(hood of corruption or lo\
+st data if the system crashes while a tree is being modi\214ed.)144 600 R(If)
+5.191 E F3(cac)2.691 E(hesize)-.15 E F0(is)2.691 E 2.5(0\()144 612 S
+(no size is speci\214ed\) a def)154.83 612 Q(ault cache is used.)-.1 E 12.95
+(psize P)108 628.8 R .45
+(age size is the size \(in bytes\) of the pages used for nodes in the tree.)
+-.15 F .449(The minimum page size is)5.449 F .442
+(512 bytes and the maximum page size is 64K.)144 640.8 R(If)5.442 E F3(psize)
+2.942 E F0 .442(is 0 \(no page size is speci\214ed\) a page size)2.942 F
+(is chosen based on the underlying \214le system I/O block size.)144 652.8 Q
+9.62(lorder The)108 669.6 R 1.597(byte order for inte)4.097 F 1.596
+(gers in the stored database metadata.)-.15 F 1.596
+(The number should represent the)6.596 F .688(order as an inte)144 681.6 R .689
+(ger; for e)-.15 F .689(xample, big endian order w)-.15 F .689
+(ould be the number 4,321.)-.1 F(If)5.689 E F3(lor)3.189 E(der)-.37 E F0 .689
+(is 0 \(no)3.189 F(order is speci\214ed\) the current host order is used.)144
+693.6 Q 174.135(4.4BSD June)72 732 R(4, 1993)2.5 E(1)535 732 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 132.34(BTREE\(3\) BSD)72 48 R(Programmer')2.5 E 2.5(sM)
+-.55 G 132.34(anual BTREE\(3\))340.17 48 R(mink)108 84 Q -.15(ey)-.1 G(page).15
+E 1.423(The minimum number of k)144 96 R -.15(ey)-.1 G 3.923(sw).15 G 1.422
+(hich will be stored on an)282.245 96 R 3.922(ys)-.15 G 1.422(ingle page.)
+400.618 96 R 1.422(This v)6.422 F 1.422(alue is used to)-.25 F .257
+(determine which k)144 108 R -.15(ey)-.1 G 2.757(sw).15 G .257
+(ill be stored on o)242.001 108 R -.15(ve)-.15 G(r\215o).15 E 2.757(wp)-.25 G
+.257(ages, i.e. if a k)348.006 108 R .558 -.15(ey o)-.1 H 2.758(rd).15 G .258
+(ata item is longer than the)435.11 108 R 1.102(pagesize di)144 120 R 1.102
+(vided by the mink)-.25 F -.15(ey)-.1 G 1.102(page v).15 F 1.102
+(alue, it will be stored on o)-.25 F -.15(ve)-.15 G(r\215o).15 E 3.602(wp)-.25
+G 1.102(ages instead of in the)451.164 120 R(page itself.)144 132 Q(If)5 E/F1
+10/Times-Italic@0 SF(mink)2.5 E -.3(ey)-.1 G(pa).3 E -.1(ge)-.1 G F0
+(is 0 \(no minimum number of k)2.6 E -.15(ey)-.1 G 2.5(si).15 G 2.5(ss)392.84
+132 S(peci\214ed\) a v)403.12 132 Q(alue of 2 is used.)-.25 E(compare)108 148.8
+Q .751(Compare is the k)144 160.8 R 1.051 -.15(ey c)-.1 H .751
+(omparison function.).15 F .751(It must return an inte)5.751 F .752
+(ger less than, equal to, or greater)-.15 F .913(than zero if the \214rst k)144
+172.8 R 1.213 -.15(ey a)-.1 H -.18(rg).15 G .913
+(ument is considered to be respecti).18 F -.15(ve)-.25 G .913
+(ly less than, equal to, or greater).15 F .352(than the second k)144 184.8 R
+.652 -.15(ey a)-.1 H -.18(rg).15 G 2.852(ument. The).18 F .353
+(same comparison function must be used on a gi)2.852 F -.15(ve)-.25 G 2.853(nt)
+.15 G .353(ree e)503.127 184.8 R -.15(ve)-.25 G(ry).15 E .817
+(time it is opened.)144 196.8 R(If)5.817 E F1(compar)3.317 E(e)-.37 E F0 .817
+(is NULL \(no comparison function is speci\214ed\), the k)3.317 F -.15(ey)-.1 G
+3.316(sa).15 G .816(re com-)508.364 196.8 R(pared le)144 208.8 Q(xically)-.15 E
+2.5(,w)-.65 G(ith shorter k)214.57 208.8 Q -.15(ey)-.1 G 2.5(sc).15 G
+(onsidered less than longer k)282.92 208.8 Q -.15(ey)-.1 G(s.).15 E 10.17
+(pre\214x Pre\214x)108 225.6 R .291(is the pre\214x comparison function.)2.791
+F .292(If speci\214ed, this routine must return the number of bytes)5.291 F
+.937(of the second k)144 237.6 R 1.237 -.15(ey a)-.1 H -.18(rg).15 G .937
+(ument which are necessary to determine that it is greater than the \214rst k)
+.18 F -.15(ey)-.1 G(ar)144 249.6 Q 3.477(gument. If)-.18 F .977(the k)3.477 F
+-.15(ey)-.1 G 3.477(sa).15 G .977(re equal, the k)241.898 249.6 R 1.277 -.15
+(ey l)-.1 H .978(ength should be returned.).15 F .978
+(Note, the usefulness of this)5.978 F .558(routine is v)144 261.6 R .558
+(ery data dependent, b)-.15 F .558
+(ut, in some data sets can produce signi\214cantly reduced tree sizes)-.2 F
+.354(and search times.)144 273.6 R(If)5.354 E F1(pr)2.854 E(e\214x)-.37 E F0
+.354(is NULL \(no pre\214x function is speci\214ed\),)2.854 F/F2 10
+/Times-Bold@0 SF(and)2.854 E F0 .354(no comparison function)2.854 F .193
+(is speci\214ed, a def)144 285.6 R .193(ault le)-.1 F .193
+(xical comparison routine is used.)-.15 F(If)5.192 E F1(pr)2.692 E(e\214x)-.37
+E F0 .192(is NULL and a comparison rou-)2.692 F
+(tine is speci\214ed, no pre\214x comparison is done.)144 297.6 Q .79
+(If the \214le already e)108 314.4 R .79(xists \(and the O_TR)-.15 F .79
+(UNC \215ag is not speci\214ed\), the v)-.4 F .79
+(alues speci\214ed for the parameters)-.25 F
+(\215ags, lorder and psize are ignored in f)108 326.4 Q -.2(avo)-.1 G 2.5(ro).2
+G 2.5(ft)284.4 326.4 S(he v)293.01 326.4 Q(alues used when the tree w)-.25 E
+(as created.)-.1 E -.15(Fo)108 343.2 S(rw).15 E
+(ard sequential scans of a tree are from the least k)-.1 E .3 -.15(ey t)-.1 H
+2.5(ot).15 G(he greatest.)348.55 343.2 Q 1.043(Space freed up by deleting k)108
+360 R -.15(ey)-.1 G 1.043(/data pairs from the tree is ne).15 F -.15(ve)-.25 G
+3.543(rr).15 G 1.043(eclaimed, although it is normally made)378.686 360 R -.2
+(av)108 372 S 1.394(ailable for reuse.)-.05 F 1.394
+(This means that the btree storage structure is gro)6.394 F(w-only)-.25 E 6.395
+(.T)-.65 G 1.395(he only solutions are to)441.09 372 R -.2(avo)108 384 S(id e)
+.2 E(xcessi)-.15 E .3 -.15(ve d)-.25 H
+(eletions, or to create a fresh tree periodically from a scan of an e).15 E
+(xisting one.)-.15 E .344(Searches, insertions, and deletions in a btree will \
+all complete in O lg base N where base is the a)108 400.8 R -.15(ve)-.2 G .343
+(rage \214ll).15 F -.1(fa)108 412.8 S(ctor).1 E 5.798(.O)-.55 G .799
+(ften, inserting ordered data into btrees results in a lo)146.188 412.8 R 3.299
+<778c>-.25 G .799(ll f)377.505 412.8 R(actor)-.1 E 5.799(.T)-.55 G .799
+(his implementation has been)423.443 412.8 R(modi\214ed to mak)108 424.8 Q 2.5
+(eo)-.1 G(rdered insertion the best case, resulting in a much better than norm\
+al page \214ll f)185.4 424.8 Q(actor)-.1 E(.)-.55 E/F3 9/Times-Bold@0 SF
+(SEE ALSO)72 441.6 Q F1(dbopen)108 453.6 Q F0(\(3\),).24 E F1(hash)2.5 E F0
+(\(3\),).28 E F1(mpool)2.5 E F0(\(3\),).51 E F1 -.37(re)2.5 G(cno).37 E F0
+(\(3\)).18 E F1(The Ubiquitous B-tr)108 477.6 Q(ee)-.37 E F0 2.5(,D).18 G
+(ouglas Comer)209.47 477.6 Q 2.5(,A)-.4 G(CM Comput. Surv)276.72 477.6 Q 2.5
+(.1)-.65 G(1, 2 \(June 1979\), 121-138.)360.25 477.6 Q F1(Pr)108 501.6 Q 1.588
+(e\214x B-tr)-.37 F(ees)-.37 E F0 4.088(,B).27 G 1.587(ayer and Unterauer)
+177.636 501.6 R 4.087(,A)-.4 G 1.587(CM T)270.447 501.6 R 1.587
+(ransactions on Database Systems, V)-.35 F 1.587(ol. 2, 1 \(March 1977\),)-1.29
+F(11-26.)108 513.6 Q F1(The Art of Computer Pr)108 537.6 Q -.1(og)-.45 G -.15
+(ra).1 G(mming V).15 E(ol. 3: Sorting and Sear)-1.11 E -.15(ch)-.37 G(ing).15 E
+F0 2.5(,D).22 G(.E. Knuth, 1968, pp 471-480.)382 537.6 Q F3 -.09(BU)72 554.4 S
+(GS).09 E F0(Only big and little endian byte order is supported.)108 566.4 Q
+174.135(4.4BSD June)72 732 R(4, 1993)2.5 E(2)535 732 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/docs/dbopen.3.ps b/mechglue/src/plugins/kdb/db2/libdb2/docs/dbopen.3.ps
new file mode 100644
index 000000000..c621bef97
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/docs/dbopen.3.ps
@@ -0,0 +1,508 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 4
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll 
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.01(DBOPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.01(anual DBOPEN\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72
+84 S(ME).18 E F0(dbopen \255 database access methods)108 96 Q F1(SYNOPSIS)72
+112.8 Q/F2 10/Times-Bold@0 SF(#include <sys/types.h>)108 124.8 Q
+(#include <limits.h>)108 136.8 Q(#include <db)108 148.8 Q(.h>)-.4 E(DB *)108
+172.8 Q(dbopen\(const char *\214le, int \215ags, int mode, DBTYPE type,)108
+184.8 Q(const v)158 196.8 Q(oid *openinf)-.1 E(o\);)-.25 E F1(DESCRIPTION)72
+213.6 Q/F3 10/Times-Italic@0 SF(Dbopen)108 225.6 Q F0 .032
+(is the library interf)2.532 F .031(ace to database \214les.)-.1 F .031
+(The supported \214le formats are btree, hashed and UNIX \214le)5.031 F 2.82
+(oriented. The)108 237.6 R .32
+(btree format is a representation of a sorted, balanced tree structure.)2.82 F
+.321(The hashed format is an)5.321 F -.15(ex)108 249.6 S .424
+(tensible, dynamic hashing scheme.).15 F .423
+(The \215at-\214le format is a byte stream \214le with \214x)5.423 F .423
+(ed or v)-.15 F .423(ariable length)-.25 F 2.906(records. The)108 261.6 R .407
+(formats and \214le format speci\214c information are described in detail in t\
+heir respecti)2.906 F .707 -.15(ve m)-.25 H(anual).15 E(pages)108 273.6 Q F3
+(btr)2.5 E(ee)-.37 E F0(\(3\),).18 E F3(hash)2.5 E F0(\(3\) and).28 E F3 -.37
+(re)2.5 G(cno).37 E F0(\(3\).).18 E .433(Dbopen opens)108 290.4 R F3(\214le)
+2.933 E F0 .433(for reading and/or writing.)2.933 F .433(Files ne)5.433 F -.15
+(ve)-.25 G 2.933(ri).15 G .433(ntended to be preserv)346.737 290.4 R .433
+(ed on disk may be created)-.15 F(by setting the \214le parameter to NULL.)108
+302.4 Q(The)108 319.2 Q F3<8d61>4.661 E(gs)-.1 E F0(and)4.661 E F3 2.161
+(mode ar)4.661 F(guments)-.37 E F0 2.161(are as speci\214ed to the)4.661 F F3
+(open)4.661 E F0 2.162(\(2\) routine, ho).24 F(we)-.25 E -.15(ve)-.25 G 2.962
+-.4(r, o).15 H 2.162(nly the O_CREA).4 F -.74(T,)-1.11 G .128
+(O_EXCL, O_EXLOCK, O_NONBLOCK, O_RDONL)108 331.2 R 2.708 -1.29(Y, O)-1 H(_RD)
+1.29 E .128(WR, O_SHLOCK and O_TR)-.3 F .127(UNC \215ags are)-.4 F 2.5
+(meaningful. \(Note,)108 343.2 R(opening a database \214le O_WR)2.5 E(ONL)-.4 E
+2.5(Yi)-1 G 2.5(sn)342.67 343.2 S(ot possible.\))354.06 343.2 Q(The)108 360 Q
+F3(type)5.337 E F0(ar)5.337 E 2.837
+(gument is of type DBTYPE \(as de\214ned in the <db)-.18 F 2.838
+(.h> include \214le\) and may be set to)-.4 F(DB_BTREE, DB_HASH or DB_RECNO.)
+108 372 Q(The)108 388.8 Q F3(openinfo)2.85 E F0(ar)2.85 E .349(gument is a poi\
+nter to an access method speci\214c structure described in the access method')
+-.18 F(s)-.55 E .03(manual page.)108 400.8 R(If)5.03 E F3(openinfo)2.53 E F0
+.031(is NULL, each access method will use def)2.53 F .031
+(aults appropriate for the system and the)-.1 F(access method.)108 412.8 Q F3
+(Dbopen)108 429.6 Q F0 .416
+(returns a pointer to a DB structure on success and NULL on error)2.917 F 5.416
+(.T)-.55 G .416(he DB structure is de\214ned in)423.21 429.6 R(the <db)108
+441.6 Q(.h> include \214le, and contains at least the follo)-.4 E
+(wing \214elds:)-.25 E(typedef struct {)108 465.6 Q(DBTYPE type;)144 477.6 Q
+(int \(*close\)\(const DB *db\);)144 489.6 Q
+(int \(*del\)\(const DB *db, const DBT *k)144 501.6 Q -.15(ey)-.1 G 2.5(,u)-.5
+G(_int \215ags\);)318.92 501.6 Q(int \(*fd\)\(const DB *db\);)144 513.6 Q
+(int \(*get\)\(const DB *db, DBT *k)144 525.6 Q -.15(ey)-.1 G 2.5(,D)-.5 G
+(BT *data, u_int \215ags\);)297.53 525.6 Q(int \(*put\)\(const DB *db, DBT *k)
+144 537.6 Q -.15(ey)-.1 G 2.5(,c)-.5 G(onst DBT *data,)295.31 537.6 Q
+(u_int \215ags\);)194 549.6 Q(int \(*sync\)\(const DB *db, u_int \215ags\);)144
+561.6 Q(int \(*seq\)\(const DB *db, DBT *k)144 573.6 Q -.15(ey)-.1 G 2.5(,D)-.5
+G(BT *data, u_int \215ags\);)298.64 573.6 Q 2.5(}D)108 585.6 S(B;)122.52 585.6
+Q .101
+(These elements describe a database type and a set of functions performing v)
+108 602.4 R .101(arious actions.)-.25 F .101(These functions)5.101 F(tak)108
+614.4 Q 3.039(eap)-.1 G .539(ointer to a structure as returned by)140.078 614.4
+R F3(dbopen)3.038 E F0 3.038(,a).24 G .538
+(nd sometimes one or more pointers to k)323.196 614.4 R -.15(ey)-.1 G .538
+(/data struc-).15 F(tures and a \215ag v)108 626.4 Q(alue.)-.25 E 16.28
+(type The)108 643.2 R
+(type of the underlying access method \(and \214le format\).)2.5 E 12.95
+(close A)108 660 R .988(pointer to a routine to \215ush an)3.488 F 3.489(yc)
+-.15 G .989(ached information to disk, free an)293.968 660 R 3.489(ya)-.15 G
+.989(llocated resources, and)446.662 660 R .112
+(close the underlying \214le\(s\).)144 672 R .111(Since k)5.112 F -.15(ey)-.1 G
+.111(/data pairs may be cached in memory).15 F 2.611(,f)-.65 G .111
+(ailing to sync the \214le)455.666 672 R .494(with a)144 684 R F3(close)2.994 E
+F0(or)2.994 E F3(sync)2.994 E F0 .495
+(function may result in inconsistent or lost information.)2.994 F F3(Close)
+5.495 E F0 .495(routines return)2.995 F(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15
+G(istrib)132.57 732 Q 89.875(ution September)-.2 F(13, 1993)2.5 E(1)535 732 Q
+EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.01(DBOPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.01(anual DBOPEN\(3\))340.17 48 R(-1 on error \(setting)144 84 Q
+/F1 10/Times-Italic@0 SF(errno)2.5 E F0 2.5(\)a).18 G(nd 0 on success.)254.43
+84 Q 21.28(del A)108 100.8 R(pointer to a routine to remo)2.5 E .3 -.15(ve k)
+-.15 H -.15(ey).05 G(/data pairs from the database.).15 E(The parameter)144
+117.6 Q F1<8d61>2.5 E(g)-.1 E F0(may be set to the follo)2.5 E(wing v)-.25 E
+(alue:)-.25 E(R_CURSOR)144 134.4 Q .289
+(Delete the record referenced by the cursor)180 146.4 R 5.288(.T)-.55 G .288
+(he cursor must ha)363.342 146.4 R .588 -.15(ve p)-.2 H(re).15 E .288
+(viously been initial-)-.25 F(ized.)180 158.4 Q F1(Delete)144 175.2 Q F0 .03
+(routines return -1 on error \(setting)2.53 F F1(errno)2.53 E F0 .03
+(\), 0 on success, and 1 if the speci\214ed).18 F F1 -.1(ke)2.53 G(y)-.2 E F0
+-.1(wa)2.53 G 2.53(sn).1 G .03(ot in)521.91 175.2 R(the \214le.)144 187.2 Q
+25.17(fd A)108 204 R .451
+(pointer to a routine which returns a \214le descriptor representati)2.951 F
+.75 -.15(ve o)-.25 H 2.95(ft).15 G .45(he underlying database.)431.73 204 R(A)
+5.45 E .942(\214le descriptor referencing the same \214le will be returned to \
+all processes which call)144 216 R F1(dbopen)3.442 E F0(with)3.442 E 1.629
+(the same)144 228 R F1(\214le)4.129 E F0 4.129(name. This)4.129 F 1.628
+(\214le descriptor may be safely used as a ar)4.128 F 1.628(gument to the)-.18
+F F1(fcntl)4.128 E F0 1.628(\(2\) and).51 F F1(\215oc)144 240 Q(k)-.2 E F0 .425
+(\(2\) locking functions.).67 F .425
+(The \214le descriptor is not necessarily associated with an)5.425 F 2.925(yo)
+-.15 G 2.925(ft)492.7 240 S .425(he under)501.735 240 R(-)-.2 E .198
+(lying \214les used by the access method.)144 252 R .198
+(No \214le descriptor is a)5.198 F -.25(va)-.2 G .198
+(ilable for in memory databases.).25 F F1(Fd)5.198 E F0
+(routines return -1 on error \(setting)144 264 Q F1(errno)2.5 E F0
+(\), and the \214le descriptor on success.).18 E 21.28(get A)108 280.8 R
+(pointer to a routine which is the interf)2.5 E .001(ace for k)-.1 F -.15(ey)
+-.1 G .001(ed retrie).15 F -.25(va)-.25 G 2.501(lf).25 G .001
+(rom the database.)399.755 280.8 R .001(The address and)5.001 F .061
+(length of the data associated with the speci\214ed)144 292.8 R F1 -.1(ke)2.561
+G(y)-.2 E F0 .06(are returned in the structure referenced by)2.561 F F1(data)
+2.56 E F0(.).26 E F1(Get)144 304.8 Q F0(routines return -1 on error \(setting)
+2.5 E F1(errno)2.5 E F0(\), 0 on success, and 1 if the).18 E F1 -.1(ke)2.5 G(y)
+-.2 E F0 -.1(wa)2.5 G 2.5(sn).1 G(ot in the \214le.)471.66 304.8 Q 20.72(put A)
+108 321.6 R(pointer to a routine to store k)2.5 E -.15(ey)-.1 G
+(/data pairs in the database.).15 E(The parameter)144 338.4 Q F1<8d61>2.5 E(g)
+-.1 E F0(may be set to one of the follo)2.5 E(wing v)-.25 E(alues:)-.25 E
+(R_CURSOR)144 355.2 Q .051(Replace the k)180 367.2 R -.15(ey)-.1 G .051
+(/data pair referenced by the cursor).15 F 5.052(.T)-.55 G .052
+(he cursor must ha)393.98 367.2 R .352 -.15(ve p)-.2 H(re).15 E .052
+(viously been)-.25 F(initialized.)180 379.2 Q(R_IAFTER)144 396 Q 1.165
+(Append the data immediately after the data referenced by)180 408 R F1 -.1(ke)
+3.664 G(y)-.2 E F0 3.664(,c).32 G 1.164(reating a ne)446.758 408 R 3.664(wk)
+-.25 G -.15(ey)511.27 408 S(/data).15 E(pair)180 420 Q 6.065(.T)-.55 G 1.065
+(he record number of the appended k)209.675 420 R -.15(ey)-.1 G 1.065
+(/data pair is returned in the).15 F F1 -.1(ke)3.565 G(y)-.2 E F0(structure.)
+3.565 E(\(Applicable only to the DB_RECNO access method.\))180 432 Q(R_IBEFORE)
+144 448.8 Q 1.293(Insert the data immediately before the data referenced by)180
+460.8 R F1 -.1(ke)3.793 G(y)-.2 E F0 3.793(,c).32 G 1.293(reating a ne)446.371
+460.8 R 3.793(wk)-.25 G -.15(ey)511.27 460.8 S(/data).15 E(pair)180 472.8 Q
+6.54(.T)-.55 G 1.54(he record number of the inserted k)210.15 472.8 R -.15(ey)
+-.1 G 1.541(/data pair is returned in the).15 F F1 -.1(ke)4.041 G(y)-.2 E F0
+(structure.)4.041 E(\(Applicable only to the DB_RECNO access method.\))180
+484.8 Q(R_NOO)144 501.6 Q(VER)-.5 E(WRITE)-.55 E(Enter the ne)180 513.6 Q 2.5
+(wk)-.25 G -.15(ey)242.69 513.6 S(/data pair only if the k).15 E .3 -.15(ey d)
+-.1 H(oes not pre).15 E(viously e)-.25 E(xist.)-.15 E(R_SETCURSOR)144 530.4 Q
+1.36(Store the k)180 542.4 R -.15(ey)-.1 G 1.36(/data pair).15 F 3.86(,s)-.4 G
+1.359(etting or initializing the position of the cursor to reference it.)283.94
+542.4 R(\(Applicable only to the DB_BTREE and DB_RECNO access methods.\))180
+554.4 Q .563(R_SETCURSOR is a)144 571.2 R -.25(va)-.2 G .564
+(ilable only for the DB_BTREE and DB_RECNO access methods because).25 F
+(it implies that the k)144 583.2 Q -.15(ey)-.1 G 2.5(sh).15 G -2.25 -.2(av e)
+241.81 583.2 T(an inherent order which does not change.)2.7 E .416
+(R_IAFTER and R_IBEFORE are a)144 600 R -.25(va)-.2 G .416
+(ilable only for the DB_RECNO access method because the).25 F(y)-.15 E 1.221
+(each imply that the access method is able to create ne)144 612 R 3.722(wk)-.25
+G -.15(ey)385.644 612 S 3.722(s. This).15 F 1.222(is only true if the k)3.722 F
+-.15(ey)-.1 G 3.722(sa).15 G(re)532.23 612 Q
+(ordered and independent, record numbers for e)144 624 Q(xample.)-.15 E .289
+(The def)144 640.8 R .289(ault beha)-.1 F .289(vior of the)-.2 F F1(put)2.789 E
+F0 .289(routines is to enter the ne)2.789 F 2.789(wk)-.25 G -.15(ey)388.998
+640.8 S .288(/data pair).15 F 2.788(,r)-.4 G .288(eplacing an)444.284 640.8 R
+2.788(yp)-.15 G(re)503.03 640.8 Q(viously)-.25 E -.15(ex)144 652.8 S(isting k)
+.15 E -.15(ey)-.1 G(.)-.5 E F1(Put)144 669.6 Q F0 .37
+(routines return -1 on error \(setting)2.87 F F1(errno)2.87 E F0 .37
+(\), 0 on success, and 1 if the R_NOO).18 F(VER)-.5 E(WRITE)-.55 E F1<8d61>2.87
+E(g)-.1 E F0 -.1(wa)144 681.6 S 2.5(ss).1 G(et and the k)165.84 681.6 Q .3 -.15
+(ey a)-.1 H(lready e).15 E(xists in the \214le.)-.15 E(4.4 Berk)72 732 Q(ele)
+-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 89.875(ution September)-.2 F(13, 1993)
+2.5 E(2)535 732 Q EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.01(DBOPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.01(anual DBOPEN\(3\))340.17 48 R 20.17(seq A)108 84 R .002
+(pointer to a routine which is the interf)2.502 F .002
+(ace for sequential retrie)-.1 F -.25(va)-.25 G 2.502(lf).25 G .002
+(rom the database.)416.694 84 R .001(The address)5.001 F .219
+(and length of the k)144 96 R .519 -.15(ey a)-.1 H .219
+(re returned in the structure referenced by).15 F/F1 10/Times-Italic@0 SF -.1
+(ke)2.72 G(y)-.2 E F0 2.72(,a).32 G .22(nd the address and length of)426.42 96
+R(the data are returned in the structure referenced by)144 108 Q F1(data)2.5 E
+F0(.).26 E .937(Sequential k)144 124.8 R -.15(ey)-.1 G .937(/data pair retrie)
+.15 F -.25(va)-.25 G 3.437(lm).25 G .936(ay be)289.748 124.8 R .936(gin at an)
+-.15 F 3.436(yt)-.15 G .936(ime, and the position of the `)359.292 124.8 R
+(`cursor')-.74 E 3.436('i)-.74 G 3.436(sn)519.894 124.8 S(ot)532.22 124.8 Q(af)
+144 136.8 Q 1.585(fected by calls to the)-.25 F F1(del)4.085 E F0(,).51 E F1
+-.1(ge)4.085 G(t).1 E F0(,).68 E F1(put)4.086 E F0 4.086(,o).68 G(r)308.452
+136.8 Q F1(sync)4.086 E F0 4.086(routines. Modi\214cations)4.086 F 1.586
+(to the database during a)4.086 F 1.404(sequential scan will be re\215ected in\
+ the scan, i.e. records inserted behind the cursor will not be)144 148.8 R
+(returned while records inserted in front of the cursor will be returned.)144
+160.8 Q(The \215ag v)144 177.6 Q(alue)-.25 E/F2 10/Times-Bold@0 SF(must)2.5 E
+F0(be set to one of the follo)2.5 E(wing v)-.25 E(alues:)-.25 E(R_CURSOR)144
+194.4 Q .523(The data associated with the speci\214ed k)180 206.4 R .824 -.15
+(ey i)-.1 H 3.024(sr).15 G 3.024(eturned. This)367.236 206.4 R(dif)3.024 E .524
+(fers from the)-.25 F F1 -.1(ge)3.024 G(t).1 E F0(routines)3.024 E 1.143
+(in that it sets or initializes the cursor to the location of the k)180 218.4 R
+1.443 -.15(ey a)-.1 H 3.642(sw).15 G 3.642(ell. \(Note,)464.924 218.4 R 1.142
+(for the)3.642 F 1.275(DB_BTREE access method, the returned k)180 230.4 R 1.575
+-.15(ey i)-.1 H 3.775(sn).15 G 1.276(ot necessarily an e)386.425 230.4 R 1.276
+(xact match for the)-.15 F .598(speci\214ed k)180 242.4 R -.15(ey)-.1 G 5.598
+(.T)-.5 G .598(he returned k)246.396 242.4 R .898 -.15(ey i)-.1 H 3.098(st).15
+G .598(he smallest k)325.188 242.4 R .898 -.15(ey g)-.1 H .598
+(reater than or equal to the speci\214ed).15 F -.1(ke)180 254.4 S 1.3 -.65
+(y, p)-.05 H(ermitting partial k).65 E .3 -.15(ey m)-.1 H
+(atches and range searches.\)).15 E(R_FIRST)144 271.2 Q 1.043(The \214rst k)180
+283.2 R -.15(ey)-.1 G 1.044(/data pair of the database is returned, and the cu\
+rsor is set or initialized to).15 F(reference it.)180 295.2 Q(R_LAST)144 312 Q
+.085(The last k)180 324 R -.15(ey)-.1 G .085(/data pair of the database is ret\
+urned, and the cursor is set or initialized to ref-).15 F(erence it.)180 336 Q
+(\(Applicable only to the DB_BTREE and DB_RECNO access methods.\))5 E(R_NEXT)
+144 352.8 Q(Retrie)180 364.8 Q .604 -.15(ve t)-.25 H .304(he k).15 F -.15(ey)
+-.1 G .304(/data pair immediately after the cursor).15 F 5.304(.I)-.55 G 2.804
+(ft)410.622 364.8 S .305(he cursor is not yet set, this is)419.536 364.8 R
+(the same as the R_FIRST \215ag.)180 376.8 Q(R_PREV)144 393.6 Q(Retrie)180
+405.6 Q .755 -.15(ve t)-.25 H .455(he k).15 F -.15(ey)-.1 G .455
+(/data pair immediately before the cursor).15 F 5.455(.I)-.55 G 2.955(ft)419.05
+405.6 S .454(he cursor is not yet set, this)428.115 405.6 R .62
+(is the same as the R_LAST \215ag.)180 417.6 R .621
+(\(Applicable only to the DB_BTREE and DB_RECNO)5.621 F(access methods.\))180
+429.6 Q .911(R_LAST and R_PREV are a)144 446.4 R -.25(va)-.2 G .911
+(ilable only for the DB_BTREE and DB_RECNO access methods).25 F(because the)144
+458.4 Q 2.5(ye)-.15 G(ach imply that the k)202.16 458.4 Q -.15(ey)-.1 G 2.5(sh)
+.15 G -2.25 -.2(av e)302.18 458.4 T(an inherent order which does not change.)
+2.7 E F1(Seq)144 475.2 Q F0 .061(routines return -1 on error \(setting)2.561 F
+F1(errno)2.561 E F0 .061(\), 0 on success and 1 if there are no k).18 F -.15
+(ey)-.1 G .061(/data pairs less).15 F .35
+(than or greater than the speci\214ed or current k)144 487.2 R -.15(ey)-.1 G
+5.349(.I)-.5 G 2.849(ft)346.467 487.2 S .349
+(he DB_RECNO access method is being used,)355.426 487.2 R .025
+(and if the database \214le is a character special \214le and no complete k)144
+499.2 R -.15(ey)-.1 G .025(/data pairs are currently a).15 F -.25(va)-.2 G(il-)
+.25 E(able, the)144 511.2 Q F1(seq)2.5 E F0(routines return 2.)2.5 E 15.17
+(sync A)108 528 R .458(pointer to a routine to \215ush an)2.958 F 2.957(yc)-.15
+G .457(ached information to disk.)289.72 528 R .457
+(If the database is in memory only)5.457 F(,)-.65 E(the)144 540 Q F1(sync)2.5 E
+F0(routine has no ef)2.5 E(fect and will al)-.25 E -.1(wa)-.1 G(ys succeed.).1
+E(The \215ag v)144 556.8 Q(alue may be set to the follo)-.25 E(wing v)-.25 E
+(alue:)-.25 E(R_RECNOSYNC)144 573.6 Q .077(If the DB_RECNO access method is be\
+ing used, this \215ag causes the sync routine to apply)180 585.6 R .75(to the \
+btree \214le which underlies the recno \214le, not the recno \214le itself.)180
+597.6 R .75(\(See the)5.75 F F1(bfname)3.25 E F0(\214eld of the)180 609.6 Q F1
+-.37(re)2.5 G(cno).37 E F0(\(3\) manual page for more information.\)).18 E F1
+(Sync)144 626.4 Q F0(routines return -1 on error \(setting)2.5 E F1(errno)2.5 E
+F0 2.5(\)a).18 G(nd 0 on success.)336.91 626.4 Q/F3 9/Times-Bold@0 SF(KEY/D)72
+643.2 Q -1.35 -.855(AT A)-.315 H -.666(PA)3.105 G(IRS).666 E F0 .134
+(Access to all \214le types is based on k)108 655.2 R -.15(ey)-.1 G .134
+(/data pairs.).15 F .134(Both k)5.134 F -.15(ey)-.1 G 2.634(sa).15 G .134
+(nd data are represented by the follo)359.078 655.2 R .135(wing data)-.25 F
+(structure:)108 667.2 Q(typedef struct {)108 684 Q(4.4 Berk)72 732 Q(ele)-.1 E
+2.5(yD)-.15 G(istrib)132.57 732 Q 89.875(ution September)-.2 F(13, 1993)2.5 E
+(3)535 732 Q EP
+%%Page: 4 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.01(DBOPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.01(anual DBOPEN\(3\))340.17 48 R -.2(vo)144 84 S(id *data;).2 E
+(size_t size;)144 96 Q 2.5(}D)108 108 S(BT)122.52 108 Q(;)-.55 E
+(The elements of the DBT structure are de\214ned as follo)108 124.8 Q(ws:)-.25
+E 16.84(data A)108 141.6 R(pointer to a byte string.)2.5 E 17.95(size The)108
+158.4 R(length of the byte string.)2.5 E -2.15 -.25(Ke y)108 175.2 T .829(and \
+data byte strings may reference strings of essentially unlimited length althou\
+gh an)3.579 F 3.328(yt)-.15 G 1.028 -.1(wo o)492.894 175.2 T 3.328(ft).1 G(hem)
+522.78 175.2 Q 1.133(must \214t into a)108 187.2 R -.25(va)-.2 G 1.134
+(ilable memory at the same time.).25 F 1.134
+(It should be noted that the access methods pro)6.134 F 1.134(vide no)-.15 F
+(guarantees about byte string alignment.)108 199.2 Q/F1 9/Times-Bold@0 SF(ERR)
+72 216 Q(ORS)-.27 E F0(The)108 228 Q/F2 10/Times-Italic@0 SF(dbopen)3.389 E F0
+.889(routine may f)3.389 F .889(ail and set)-.1 F F2(errno)3.388 E F0 .888
+(for an)3.388 F 3.388(yo)-.15 G 3.388(ft)324.376 228 S .888
+(he errors speci\214ed for the library routines)333.874 228 R F2(open)3.388 E
+F0(\(2\)).24 E(and)108 240 Q F2(malloc)2.5 E F0(\(3\) or the follo).31 E(wing:)
+-.25 E([EFTYPE])108 256.8 Q 2.5<418c>144 268.8 S(le is incorrectly formatted.)
+159.28 268.8 Q([EINV)108 285.6 Q(AL])-1.35 E 2.812(Ap)144 297.6 S .313(aramete\
+r has been speci\214ed \(hash function, pad byte etc.\) that is incompatible w\
+ith the current)159.032 297.6 R .406
+(\214le speci\214cation or which is not meaningful for the function \(for e)144
+309.6 R .405(xample, use of the cursor with-)-.15 F .099
+(out prior initialization\) or there is a mismatch between the v)144 321.6 R .1
+(ersion number of \214le and the softw)-.15 F(are.)-.1 E(The)108 338.4 Q F2
+(close)3.469 E F0 .969(routines may f)3.469 F .969(ail and set)-.1 F F2(errno)
+3.469 E F0 .969(for an)3.469 F 3.469(yo)-.15 G 3.469(ft)320.18 338.4 S .969
+(he errors speci\214ed for the library routines)329.759 338.4 R F2(close)3.468
+E F0(\(2\),).18 E F2 -.37(re)108 350.4 S(ad).37 E F0(\(2\),).77 E F2(write)2.5
+E F0(\(2\),).18 E F2(fr)2.5 E(ee)-.37 E F0(\(3\), or).18 E F2(fsync)2.5 E F0
+(\(2\).).31 E(The)108 367.2 Q F2(del)2.969 E F0(,).51 E F2 -.1(ge)2.969 G(t).1
+E F0(,).68 E F2(put)2.969 E F0(and)2.969 E F2(seq)2.969 E F0 .469
+(routines may f)2.969 F .469(ail and set)-.1 F F2(errno)2.97 E F0 .47(for an)
+2.97 F 2.97(yo)-.15 G 2.97(ft)377.59 367.2 S .47
+(he errors speci\214ed for the library rou-)386.67 367.2 R(tines)108 379.2 Q F2
+-.37(re)2.5 G(ad).37 E F0(\(2\),).77 E F2(write)2.5 E F0(\(2\),).18 E F2(fr)2.5
+E(ee)-.37 E F0(\(3\) or).18 E F2(malloc)2.5 E F0(\(3\).).31 E(The)108 396 Q F2
+(fd)2.5 E F0(routines will f)2.5 E(ail and set)-.1 E F2(errno)2.5 E F0
+(to ENOENT for in memory databases.)2.5 E(The)108 412.8 Q F2(sync)2.5 E F0
+(routines may f)2.5 E(ail and set)-.1 E F2(errno)2.5 E F0(for an)2.5 E 2.5(yo)
+-.15 G 2.5(ft)307.71 412.8 S(he errors speci\214ed for the library routine)
+316.32 412.8 Q F2(fsync)2.5 E F0(\(2\).).31 E F1(SEE ALSO)72 429.6 Q F2(btr)108
+441.6 Q(ee)-.37 E F0(\(3\),).18 E F2(hash)2.5 E F0(\(3\),).28 E F2(mpool)2.5 E
+F0(\(3\),).51 E F2 -.37(re)2.5 G(cno).37 E F0(\(3\)).18 E F2 .904(LIBTP: P)108
+465.6 R(ortable)-.8 E 3.404(,M)-.1 G .904(odular T)189.738 465.6 R -.15(ra)-.55
+G .904(nsactions for UNIX).15 F F0 3.404(,M).94 G(ar)328.884 465.6 Q .904
+(go Seltzer)-.18 F 3.403(,M)-.4 G .903(ichael Olson, USENIX proceedings,)
+392.041 465.6 R -.4(Wi)108 477.6 S(nter 1992.).4 E F1 -.09(BU)72 494.4 S(GS).09
+E F0 .399(The typedef DBT is a mnemonic for `)108 506.4 R .399
+(`data base thang')-.74 F .399(', and w)-.74 F .399
+(as used because noone could think of a rea-)-.1 F(sonable name that w)108
+518.4 Q(asn')-.1 E 2.5(ta)-.18 G(lready used.)216.03 518.4 Q
+(The \214le descriptor interf)108 535.2 Q
+(ace is a kluge and will be deleted in a future v)-.1 E(ersion of the interf)
+-.15 E(ace.)-.1 E(None of the access methods pro)108 552 Q(vide an)-.15 E 2.5
+(yf)-.15 G(orm of concurrent access, locking, or transactions.)275.16 552 Q
+(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 89.875
+(ution September)-.2 F(13, 1993)2.5 E(4)535 732 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/docs/hash.3.ps b/mechglue/src/plugins/kdb/db2/libdb2/docs/hash.3.ps
new file mode 100644
index 000000000..18303cfb7
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/docs/hash.3.ps
@@ -0,0 +1,292 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 2
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll 
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 136.79(HASH\(3\) BSD)72 48 R(Programmer')2.5 E 2.5(sM)
+-.55 G 136.79(anual HASH\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72 84 S
+(ME).18 E F0(hash \255 hash database access method)108 96 Q F1(SYNOPSIS)72
+112.8 Q/F2 10/Times-Bold@0 SF(#include <sys/types.h>)108 124.8 Q(#include <db)
+108 136.8 Q(.h>)-.4 E F1(DESCRIPTION)72 153.6 Q F0 .29(The routine)108 165.6 R
+/F3 10/Times-Italic@0 SF(dbopen)2.79 E F0 .29(is the library interf)2.79 F .29
+(ace to database \214les.)-.1 F .29
+(One of the supported \214le formats is hash \214les.)5.29 F .974
+(The general description of the database access methods is in)108 177.6 R F3
+(dbopen)3.475 E F0 .975(\(3\), this manual page describes only).24 F
+(the hash speci\214c information.)108 189.6 Q(The hash data structure is an e)
+108 206.4 Q(xtensible, dynamic hashing scheme.)-.15 E .83
+(The access method speci\214c data structure pro)108 223.2 R .83(vided to)-.15
+F F3(dbopen)3.33 E F0 .83(is de\214ned in the <db)3.33 F .83
+(.h> include \214le as fol-)-.4 F(lo)108 235.2 Q(ws:)-.25 E(typedef struct {)
+108 259.2 Q(int bsize;)144 271.2 Q(int cachesize;)144 283.2 Q(int f)144 295.2 Q
+-.1(fa)-.25 G(ctor;).1 E(u_long \(*hash\)\(const v)144 307.2 Q
+(oid *, size_t\);)-.2 E(int lorder;)144 319.2 Q(int nelem;)144 331.2 Q 2.5(}H)
+108 343.2 S(ASHINFO;)122.52 343.2 Q
+(The elements of this structure are as follo)108 360 Q(ws:)-.25 E(bsize)108
+376.8 Q F3(Bsize)144 376.8 Q F0 1.393(de\214nes the hash table b)3.893 F(uck)
+-.2 E 1.393(et size, and is, by def)-.1 F 1.394(ault, 256 bytes.)-.1 F 1.394
+(It may be preferable to)6.394 F
+(increase the page size for disk-resident tables and tables with lar)144 388.8
+Q(ge data items.)-.18 E(cachesize)108 405.6 Q 3.16(As)144 417.6 S .66
+(uggested maximum size, in bytes, of the memory cache.)158.27 417.6 R .659
+(This v)5.659 F .659(alue is)-.25 F F2(only)3.159 E F0(advisory)3.159 E 3.159
+(,a)-.65 G .659(nd the)514.621 417.6 R
+(access method will allocate more memory rather than f)144 429.6 Q(ail.)-.1 E
+-2.1 -.25(ff a)108 446.4 T(ctor).25 E F3(Ffactor)9.7 E F0 .482
+(indicates a desired density within the hash table.)2.981 F .482
+(It is an approximation of the number of)5.482 F -.1(ke)144 458.4 S .429
+(ys allo)-.05 F .429(wed to accumulate in an)-.25 F 2.929(yo)-.15 G .429(ne b)
+291.454 458.4 R(uck)-.2 E .429(et, determining when the hash table gro)-.1 F
+.428(ws or shrinks.)-.25 F(The def)144 470.4 Q(ault v)-.1 E(alue is 8.)-.25 E
+(hash)108 487.2 Q F3(Hash)144 487.2 Q F0 .1(is a user de\214ned hash function.)
+2.6 F .1(Since no hash function performs equally well on all possible)5.1 F
+.924(data, the user may \214nd that the b)144 499.2 R .923
+(uilt-in hash function does poorly on a particular data set.)-.2 F(User)5.923 E
+1.408(speci\214ed hash functions must tak)144 511.2 R 3.909(et)-.1 G 1.609 -.1
+(wo a)293.431 511.2 T -.18(rg).1 G 1.409
+(uments \(a pointer to a byte string and a length\) and).18 F
+(return an u_long to be used as the hash v)144 523.2 Q(alue.)-.25 E 9.62
+(lorder The)108 540 R 1.597(byte order for inte)4.097 F 1.596
+(gers in the stored database metadata.)-.15 F 1.596
+(The number should represent the)6.596 F .688(order as an inte)144 552 R .689
+(ger; for e)-.15 F .689(xample, big endian order w)-.15 F .689
+(ould be the number 4,321.)-.1 F(If)5.689 E F3(lor)3.189 E(der)-.37 E F0 .689
+(is 0 \(no)3.189 F .822(order is speci\214ed\) the current host order is used.)
+144 564 R .822(If the)5.822 F .822(\214le already e)5.822 F .821
+(xists, the speci\214ed v)-.15 F .821(alue is)-.25 F(ignored and the v)144 576
+Q(alue speci\214ed when the tree w)-.25 E(as created is used.)-.1 E(nelem)108
+592.8 Q F3(Nelem)144 592.8 Q F0 .701
+(is an estimate of the \214nal size of the hash table.)3.2 F .701
+(If not set or set too lo)5.701 F 2.001 -.65(w, h)-.25 H .701(ash tables will)
+.65 F -.15(ex)144 604.8 S .448(pand gracefully as k).15 F -.15(ey)-.1 G 2.948
+(sa).15 G .448(re entered, although a slight performance de)255.912 604.8 R
+.447(gradation may be noticed.)-.15 F(The def)144 616.8 Q(ault v)-.1 E
+(alue is 1.)-.25 E .79(If the \214le already e)108 633.6 R .79
+(xists \(and the O_TR)-.15 F .79(UNC \215ag is not speci\214ed\), the v)-.4 F
+.79(alues speci\214ed for the parameters)-.25 F(bsize, f)108 645.6 Q -.1(fa)
+-.25 G(ctor).1 E 2.5(,l)-.4 G(order and nelem are ignored and the v)167.23
+645.6 Q(alues speci\214ed when the tree w)-.25 E(as created are used.)-.1 E
+1.232(If a hash function is speci\214ed,)108 662.4 R F3(hash_open)3.731 E F0
+1.231(will attempt to determine if the hash function speci\214ed is the)3.731 F
+(same as the one with which the database w)108 674.4 Q(as created, and will f)
+-.1 E(ail if it is not.)-.1 E(Backw)108 691.2 Q .861(ard compatible interf)-.1
+F .861(aces to the routines described in)-.1 F F3(dbm)3.362 E F0 .862
+(\(3\), and).32 F F3(ndbm)3.362 E F0 .862(\(3\) are pro).32 F .862(vided, ho)
+-.15 F(we)-.25 E -.15(ve)-.25 G -.4(r,).15 G(4.4 Berk)72 732 Q(ele)-.1 E 2.5
+(yD)-.15 G(istrib)132.57 732 Q 96.815(ution August)-.2 F(17, 1993)2.5 E(1)535
+732 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 136.79(HASH\(3\) BSD)72 48 R(Programmer')2.5 E 2.5(sM)
+-.55 G 136.79(anual HASH\(3\))340.17 48 R(these interf)108 84 Q
+(aces are not compatible with pre)-.1 E(vious \214le formats.)-.25 E/F1 9
+/Times-Bold@0 SF(SEE ALSO)72 100.8 Q/F2 10/Times-Italic@0 SF(btr)108 112.8 Q
+(ee)-.37 E F0(\(3\),).18 E F2(dbopen)2.5 E F0(\(3\),).24 E F2(mpool)2.5 E F0
+(\(3\),).51 E F2 -.37(re)2.5 G(cno).37 E F0(\(3\)).18 E F2(Dynamic Hash T)108
+136.8 Q(ables)-.92 E F0 2.5(,P).27 G(er)206.79 136.8 Q(-Ak)-.2 E 2.5(eL)-.1 G
+(arson, Communications of the A)242.86 136.8 Q(CM, April 1988.)-.4 E F2 2.5(AN)
+108 160.8 S .3 -.15(ew H)123.28 160.8 T(ash P).15 E(ac)-.8 E(ka)-.2 E .2 -.1
+(ge f)-.1 H(or UNIX).1 E F0 2.5(,M).94 G(ar)248.41 160.8 Q(go Seltzer)-.18 E
+2.5(,U)-.4 G(SENIX Proceedings, W)308.09 160.8 Q(inter 1991.)-.4 E F1 -.09(BU)
+72 177.6 S(GS).09 E F0(Only big and little endian byte order is supported.)108
+189.6 Q(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 96.815
+(ution August)-.2 F(17, 1993)2.5 E(2)535 732 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/docs/hash.usenix.ps b/mechglue/src/plugins/kdb/db2/libdb2/docs/hash.usenix.ps
new file mode 100644
index 000000000..acdea0992
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/docs/hash.usenix.ps
@@ -0,0 +1,12209 @@
+%!PS-Adobe-1.0
+%%Creator: utopia:margo (& Seltzer,608-13E,8072,)
+%%Title: stdin (ditroff)
+%%CreationDate: Tue Dec 11 15:06:45 1990
+%%EndComments
+%	@(#)psdit.pro	1.3 4/15/88
+% lib/psdit.pro -- prolog for psdit (ditroff) files
+% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved.
+% last edit: shore Sat Nov 23 20:28:03 1985
+% RCSID: $Header$
+
+% Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics,
+% 17 Feb, 87.
+
+/$DITroff 140 dict def $DITroff begin
+/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def
+/xi{0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto
+ /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F
+ /pagesave save def}def
+/PB{save /psv exch def currentpoint translate 
+ resolution 72 div dup neg scale 0 0 moveto}def
+/PE{psv restore}def
+/arctoobig 90 def /arctoosmall .05 def
+/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def
+/tan{dup sin exch cos div}def
+/point{resolution 72 div mul}def
+/dround	{transform round exch round exch itransform}def
+/xT{/devname exch def}def
+/xr{/mh exch def /my exch def /resolution exch def}def
+/xp{}def
+/xs{docsave restore end}def
+/xt{}def
+/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not
+ {fonts slotno fontname findfont put fontnames slotno fontname put}if}def
+/xH{/fontheight exch def F}def
+/xS{/fontslant exch def F}def
+/s{/fontsize exch def /fontheight fontsize def F}def
+/f{/fontnum exch def F}def
+/F{fontheight 0 le{/fontheight fontsize def}if
+ fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore
+ fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if
+ makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def
+/X{exch currentpoint exch pop moveto show}def
+/N{3 1 roll moveto show}def
+/Y{exch currentpoint pop exch moveto show}def
+/S{show}def
+/ditpush{}def/ditpop{}def
+/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def
+/AN{4 2 roll moveto 0 exch ashow}def
+/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def
+/AS{0 exch ashow}def
+/MX{currentpoint exch pop moveto}def
+/MY{currentpoint pop exch moveto}def
+/MXY{moveto}def
+/cb{pop}def	% action on unknown char -- nothing for now
+/n{}def/w{}def
+/p{pop showpage pagesave restore /pagesave save def}def
+/Dt{/Dlinewidth exch def}def 1 Dt
+/Ds{/Ddash exch def}def -1 Ds
+/Di{/Dstipple exch def}def 1 Di
+/Dsetlinewidth{2 Dlinewidth mul setlinewidth}def
+/Dsetdash{Ddash 4 eq{[8 12]}{Ddash 16 eq{[32 36]}
+ {Ddash 20 eq{[32 12 8 12]}{[]}ifelse}ifelse}ifelse 0 setdash}def
+/Dstroke{gsave Dsetlinewidth Dsetdash 1 setlinecap stroke grestore
+ currentpoint newpath moveto}def
+/Dl{rlineto Dstroke}def
+/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop
+ currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def
+ currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def
+/Dc{dup arcellipse Dstroke}def
+/De{arcellipse Dstroke}def
+/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def
+ /cradius centerv centerv mul centerh centerh mul add sqrt def
+ /eradius endv endv mul endh endh mul add sqrt def
+ /endang endv endh atan def
+ /startang centerv neg centerh neg atan def
+ /sweep startang endang sub dup 0 lt{360 add}if def
+ sweep arctoobig gt
+ {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def
+  /midh midang cos midrad mul def /midv midang sin midrad mul def
+  midh neg midv neg endh endv centerh centerv midh midv Da
+  Da}
+ {sweep arctoosmall ge
+  {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def
+   centerv neg controldelt mul centerh controldelt mul
+   endv neg controldelt mul centerh add endh add
+   endh controldelt mul centerv add endv add
+   centerh endh add centerv endv add rcurveto Dstroke}
+  {centerh endh add centerv endv add rlineto Dstroke}
+  ifelse}
+ ifelse}def
+/Dpatterns[
+[%cf[widthbits]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000103810000000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000001038100000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0042660000246600>]
+[8<0000990000990000>]
+[8<0804020180402010>]
+[8<2418814242811824>]
+[8<6699996666999966>]
+[8<8000000008000000>]
+[8<00001c3e363e1c00>]
+[8<0000000000000000>]
+[32<00000040000000c00000004000000040000000e0000000000000000000000000>]
+[32<00000000000060000000900000002000000040000000f0000000000000000000>]
+[32<000000000000000000e0000000100000006000000010000000e0000000000000>]
+[32<00000000000000002000000060000000a0000000f00000002000000000000000>]
+[32<0000000e0000000000000000000000000000000f000000080000000e00000001>]
+[32<0000090000000600000000000000000000000000000007000000080000000e00>]
+[32<00010000000200000004000000040000000000000000000000000000000f0000>]
+[32<0900000006000000090000000600000000000000000000000000000006000000>]]
+[%ug
+[8<0000020000000000>]
+[8<0000020000002000>]
+[8<0004020000002000>]
+[8<0004020000402000>]
+[8<0004060000402000>]
+[8<0004060000406000>]
+[8<0006060000406000>]
+[8<0006060000606000>]
+[8<00060e0000606000>]
+[8<00060e000060e000>]
+[8<00070e000060e000>]
+[8<00070e000070e000>]
+[8<00070e020070e000>]
+[8<00070e020070e020>]
+[8<04070e020070e020>]
+[8<04070e024070e020>]
+[8<04070e064070e020>]
+[8<04070e064070e060>]
+[8<06070e064070e060>]
+[8<06070e066070e060>]
+[8<06070f066070e060>]
+[8<06070f066070f060>]
+[8<060f0f066070f060>]
+[8<060f0f0660f0f060>]
+[8<060f0f0760f0f060>]
+[8<060f0f0760f0f070>]
+[8<0e0f0f0760f0f070>]
+[8<0e0f0f07e0f0f070>]
+[8<0e0f0f0fe0f0f070>]
+[8<0e0f0f0fe0f0f0f0>]
+[8<0f0f0f0fe0f0f0f0>]
+[8<0f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f1f9>]
+[8<bf8f1f9ff9f8f1f9>]
+[8<bf8f1f9ffbf8f1f9>]
+[8<bf8f1fdffbf8f1f9>]
+[8<bf8f1fdffbf8f1fd>]
+[8<ff8f1fdffbf8f1fd>]
+[8<ff8f1fdffff8f1fd>]
+[8<ff8f1ffffff8f1fd>]
+[8<ff8f1ffffff8f1ff>]
+[8<ff9f1ffffff8f1ff>]
+[8<ff9f1ffffff9f1ff>]
+[8<ff9f9ffffff9f1ff>]
+[8<ff9f9ffffff9f9ff>]
+[8<ffbf9ffffff9f9ff>]
+[8<ffbf9ffffffbf9ff>]
+[8<ffbfdffffffbf9ff>]
+[8<ffbfdffffffbfdff>]
+[8<ffffdffffffbfdff>]
+[8<ffffdffffffffdff>]
+[8<fffffffffffffdff>]
+[8<ffffffffffffffff>]]
+[%mg
+[8<8000000000000000>]
+[8<0822080080228000>]
+[8<0204081020408001>]
+[8<40e0400000000000>]
+[8<66999966>]
+[8<8001000010080000>]
+[8<81c36666c3810000>]
+[8<f0e0c08000000000>]
+[16<07c00f801f003e007c00f800f001e003c007800f001f003e007c00f801f003e0>]
+[16<1f000f8007c003e001f000f8007c003e001f800fc007e003f001f8007c003e00>]
+[8<c3c300000000c3c3>]
+[16<0040008001000200040008001000200040008000000100020004000800100020>]
+[16<0040002000100008000400020001800040002000100008000400020001000080>]
+[16<1fc03fe07df0f8f8f07de03fc01f800fc01fe03ff07df8f87df03fe01fc00f80>]
+[8<80>]
+[8<8040201000000000>]
+[8<84cc000048cc0000>]
+[8<9900009900000000>]
+[8<08040201804020100800020180002010>]
+[8<2418814242811824>]
+[8<66999966>]
+[8<8000000008000000>]
+[8<70f8d8f870000000>]
+[8<0814224180402010>]
+[8<aa00440a11a04400>]
+[8<018245aa45820100>]
+[8<221c224180808041>]
+[8<88000000>]
+[8<0855800080550800>]
+[8<2844004482440044>]
+[8<0810204080412214>]
+[8<00>]]]def
+/Dfill{
+ transform /maxy exch def /maxx exch def
+ transform /miny exch def /minx exch def
+ minx maxx gt{/minx maxx /maxx minx def def}if
+ miny maxy gt{/miny maxy /maxy miny def def}if
+ Dpatterns Dstipple 1 sub get exch 1 sub get
+ aload pop /stip exch def /stipw exch def /stiph 128 def
+ /imatrix[stipw 0 0 stiph 0 0]def
+ /tmatrix[stipw 0 0 stiph 0 0]def
+ /minx minx cvi stiph idiv stiph mul def
+ /miny miny cvi stipw idiv stipw mul def
+ gsave eoclip 0 setgray
+ miny stiph maxy{
+  tmatrix exch 5 exch put
+  minx stipw maxx{
+   tmatrix exch 4 exch put tmatrix setmatrix
+   stipw stiph true imatrix {stip} imagemask
+  }for
+ }for
+ grestore
+}def
+/Dp{Dfill Dstroke}def
+/DP{Dfill currentpoint newpath moveto}def
+end
+
+/ditstart{$DITroff begin
+ /nfonts 60 def			% NFONTS makedev/ditroff dependent!
+ /fonts[nfonts{0}repeat]def
+ /fontnames[nfonts{()}repeat]def
+/docsave save def
+}def
+
+% character outcalls
+/oc{
+ /pswid exch def /cc exch def /name exch def
+ /ditwid pswid fontsize mul resolution mul 72000 div def
+ /ditsiz fontsize resolution mul 72 div def
+ ocprocs name known{ocprocs name get exec}{name cb}ifelse
+}def
+/fractm [.65 0 0 .6 0 0] def
+/fraction{
+ /fden exch def /fnum exch def gsave /cf currentfont def
+ cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto
+ fnum show rmoveto currentfont cf setfont(\244)show setfont fden show 
+ grestore ditwid 0 rmoveto
+}def
+/oce{grestore ditwid 0 rmoveto}def
+/dm{ditsiz mul}def
+/ocprocs 50 dict def ocprocs begin
+(14){(1)(4)fraction}def
+(12){(1)(2)fraction}def
+(34){(3)(4)fraction}def
+(13){(1)(3)fraction}def
+(23){(2)(3)fraction}def
+(18){(1)(8)fraction}def
+(38){(3)(8)fraction}def
+(58){(5)(8)fraction}def
+(78){(7)(8)fraction}def
+(sr){gsave 0 .06 dm rmoveto(\326)show oce}def
+(is){gsave 0 .15 dm rmoveto(\362)show oce}def
+(->){gsave 0 .02 dm rmoveto(\256)show oce}def
+(<-){gsave 0 .02 dm rmoveto(\254)show oce}def
+(==){gsave 0 .05 dm rmoveto(\272)show oce}def
+(uc){gsave currentpoint 400 .009 dm mul add translate
+     8 -8 scale ucseal oce}def
+end
+
+% an attempt at a PostScript FONT to implement ditroff special chars
+% this will enable us to 
+%	cache the little buggers
+%	generate faster, more compact PS out of psdit
+%	confuse everyone (including myself)!
+50 dict dup begin
+/FontType 3 def
+/FontName /DIThacks def
+/FontMatrix [.001 0 0 .001 0 0] def
+/FontBBox [-260 -260 900 900] def% a lie but ...
+/Encoding 256 array def
+0 1 255{Encoding exch /.notdef put}for
+Encoding
+ dup 8#040/space put %space
+ dup 8#110/rc put %right ceil
+ dup 8#111/lt put %left  top curl
+ dup 8#112/bv put %bold vert
+ dup 8#113/lk put %left  mid curl
+ dup 8#114/lb put %left  bot curl
+ dup 8#115/rt put %right top curl
+ dup 8#116/rk put %right mid curl
+ dup 8#117/rb put %right bot curl
+ dup 8#120/rf put %right floor
+ dup 8#121/lf put %left  floor
+ dup 8#122/lc put %left  ceil
+ dup 8#140/sq put %square
+ dup 8#141/bx put %box
+ dup 8#142/ci put %circle
+ dup 8#143/br put %box rule
+ dup 8#144/rn put %root extender
+ dup 8#145/vr put %vertical rule
+ dup 8#146/ob put %outline bullet
+ dup 8#147/bu put %bullet
+ dup 8#150/ru put %rule
+ dup 8#151/ul put %underline
+ pop
+/DITfd 100 dict def
+/BuildChar{0 begin
+ /cc exch def /fd exch def
+ /charname fd /Encoding get cc get def
+ /charwid fd /Metrics get charname get def
+ /charproc fd /CharProcs get charname get def
+ charwid 0 fd /FontBBox get aload pop setcachedevice
+ 2 setlinejoin 40 setlinewidth
+ newpath 0 0 moveto gsave charproc grestore
+ end}def
+/BuildChar load 0 DITfd put
+/CharProcs 50 dict def
+CharProcs begin
+/space{}def
+/.notdef{}def
+/ru{500 0 rls}def
+/rn{0 840 moveto 500 0 rls}def
+/vr{0 800 moveto 0 -770 rls}def
+/bv{0 800 moveto 0 -1000 rls}def
+/br{0 840 moveto 0 -1000 rls}def
+/ul{0 -140 moveto 500 0 rls}def
+/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def
+/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def
+/sq{80 0 rmoveto currentpoint dround newpath moveto
+    640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def
+/bx{80 0 rmoveto currentpoint dround newpath moveto
+    640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def
+/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc
+    50 setlinewidth stroke}def
+
+/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def
+/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def
+/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def
+/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def
+/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub
+    0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub
+    0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def
+/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def
+/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def
+/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def
+end
+
+/Metrics 50 dict def Metrics begin
+/.notdef 0 def
+/space 500 def
+/ru 500 def
+/br 0 def
+/lt 416 def
+/lb 416 def
+/rt 416 def
+/rb 416 def
+/lk 416 def
+/rk 416 def
+/rc 416 def
+/lc 416 def
+/rf 416 def
+/lf 416 def
+/bv 416 def
+/ob 350 def
+/bu 350 def
+/ci 750 def
+/bx 750 def
+/sq 750 def
+/rn 500 def
+/ul 500 def
+/vr 0 def
+end
+
+DITfd begin
+/s2 500 def /s4 250 def /s3 333 def
+/a4p{arcto pop pop pop pop}def
+/2cx{2 copy exch}def
+/rls{rlineto stroke}def
+/currx{currentpoint pop}def
+/dround{transform round exch round exch itransform} def
+end
+end
+/DIThacks exch definefont pop
+ditstart
+(psc)xT
+576 1 1 xr
+1(Times-Roman)xf 1 f
+2(Times-Italic)xf 2 f
+3(Times-Bold)xf 3 f
+4(Times-BoldItalic)xf 4 f
+5(Helvetica)xf 5 f
+6(Helvetica-Bold)xf 6 f
+7(Courier)xf 7 f
+8(Courier-Bold)xf 8 f
+9(Symbol)xf 9 f
+10(DIThacks)xf 10 f
+10 s
+1 f
+xi
+%%EndProlog
+
+%%Page: 1 1
+10 s 10 xH 0 xS 1 f
+3 f
+22 s
+1249 626(A)N
+1420(N)X
+1547(ew)X
+1796(H)X
+1933(ashing)X
+2467(P)X
+2574(ackage)X
+3136(for)X
+3405(U)X
+3532(N)X
+3659(IX)X
+2 f
+20 s
+3855 562(1)N
+1 f
+12 s
+1607 779(Margo)N
+1887(Seltzer)X
+9 f
+2179(-)X
+1 f
+2256(University)X
+2686(of)X
+2790(California,)X
+3229(Berkeley)X
+2015 875(Ozan)N
+2242(Yigit)X
+9 f
+2464(-)X
+1 f
+2541(York)X
+2762(University)X
+3 f
+2331 1086(ABSTRACT)N
+1 f
+10 s
+1152 1222(UNIX)N
+1385(support)X
+1657(of)X
+1756(disk)X
+1921(oriented)X
+2216(hashing)X
+2497(was)X
+2654(originally)X
+2997(provided)X
+3314(by)X
+2 f
+3426(dbm)X
+1 f
+3595([ATT79])X
+3916(and)X
+1152 1310(subsequently)N
+1595(improved)X
+1927(upon)X
+2112(in)X
+2 f
+2199(ndbm)X
+1 f
+2402([BSD86].)X
+2735(In)X
+2826(AT&T)X
+3068(System)X
+3327(V,)X
+3429(in-memory)X
+3809(hashed)X
+1152 1398(storage)N
+1420(and)X
+1572(access)X
+1814(support)X
+2090(was)X
+2251(added)X
+2479(in)X
+2577(the)X
+2 f
+2711(hsearch)X
+1 f
+3000(library)X
+3249(routines)X
+3542([ATT85].)X
+3907(The)X
+1152 1486(result)N
+1367(is)X
+1457(a)X
+1530(system)X
+1789(with)X
+1968(two)X
+2125(incompatible)X
+2580(hashing)X
+2865(schemes,)X
+3193(each)X
+3377(with)X
+3555(its)X
+3666(own)X
+3840(set)X
+3965(of)X
+1152 1574(shortcomings.)N
+1152 1688(This)N
+1316(paper)X
+1517(presents)X
+1802(the)X
+1922(design)X
+2152(and)X
+2289(performance)X
+2717(characteristics)X
+3198(of)X
+3286(a)X
+3343(new)X
+3498(hashing)X
+3768(package)X
+1152 1776(providing)N
+1483(a)X
+1539(superset)X
+1822(of)X
+1909(the)X
+2027(functionality)X
+2456(provided)X
+2761(by)X
+2 f
+2861(dbm)X
+1 f
+3019(and)X
+2 f
+3155(hsearch)X
+1 f
+3409(.)X
+3469(The)X
+3614(new)X
+3768(package)X
+1152 1864(uses)N
+1322(linear)X
+1537(hashing)X
+1818(to)X
+1912(provide)X
+2189(ef\256cient)X
+2484(support)X
+2755(of)X
+2853(both)X
+3026(memory)X
+3324(based)X
+3538(and)X
+3685(disk)X
+3849(based)X
+1152 1952(hash)N
+1319(tables)X
+1526(with)X
+1688(performance)X
+2115(superior)X
+2398(to)X
+2480(both)X
+2 f
+2642(dbm)X
+1 f
+2800(and)X
+2 f
+2936(hsearch)X
+1 f
+3210(under)X
+3413(most)X
+3588(conditions.)X
+3 f
+1380 2128(Introduction)N
+1 f
+892 2260(Current)N
+1196(UNIX)X
+1456(systems)X
+1768(offer)X
+1984(two)X
+2163(forms)X
+2409(of)X
+720 2348(hashed)N
+973(data)X
+1137(access.)X
+2 f
+1413(Dbm)X
+1 f
+1599(and)X
+1745(its)X
+1850(derivatives)X
+2231(provide)X
+720 2436(keyed)N
+939(access)X
+1171(to)X
+1259(disk)X
+1418(resident)X
+1698(data)X
+1858(while)X
+2 f
+2062(hsearch)X
+1 f
+2342(pro-)X
+720 2524(vides)N
+929(access)X
+1175(for)X
+1309(memory)X
+1616(resident)X
+1910(data.)X
+2124(These)X
+2356(two)X
+720 2612(access)N
+979(methods)X
+1302(are)X
+1453(incompatible)X
+1923(in)X
+2037(that)X
+2209(memory)X
+720 2700(resident)N
+1011(hash)X
+1195(tables)X
+1419(may)X
+1593(not)X
+1731(be)X
+1843(stored)X
+2075(on)X
+2191(disk)X
+2360(and)X
+720 2788(disk)N
+884(resident)X
+1169(tables)X
+1387(cannot)X
+1632(be)X
+1739(read)X
+1909(into)X
+2063(memory)X
+2360(and)X
+720 2876(accessed)N
+1022(using)X
+1215(the)X
+1333(in-memory)X
+1709(routines.)X
+2 f
+892 2990(Dbm)N
+1 f
+1091(has)X
+1241(several)X
+1512(shortcomings.)X
+2026(Since)X
+2247(data)X
+2423(is)X
+720 3078(assumed)N
+1032(to)X
+1130(be)X
+1242(disk)X
+1411(resident,)X
+1721(each)X
+1905(access)X
+2146(requires)X
+2440(a)X
+720 3166(system)N
+963(call,)X
+1120(and)X
+1257(almost)X
+1491(certainly,)X
+1813(a)X
+1869(disk)X
+2022(operation.)X
+2365(For)X
+720 3254(extremely)N
+1072(large)X
+1264(databases,)X
+1623(where)X
+1851(caching)X
+2131(is)X
+2214(unlikely)X
+720 3342(to)N
+810(be)X
+914(effective,)X
+1244(this)X
+1386(is)X
+1466(acceptable,)X
+1853(however,)X
+2177(when)X
+2378(the)X
+720 3430(database)N
+1022(is)X
+1100(small)X
+1298(\(i.e.)X
+1447(the)X
+1569(password)X
+1896(\256le\),)X
+2069(performance)X
+720 3518(improvements)N
+1204(can)X
+1342(be)X
+1443(obtained)X
+1744(through)X
+2018(caching)X
+2293(pages)X
+720 3606(of)N
+818(the)X
+947(database)X
+1255(in)X
+1348(memory.)X
+1685(In)X
+1782(addition,)X
+2 f
+2094(dbm)X
+1 f
+2262(cannot)X
+720 3694(store)N
+902(data)X
+1062(items)X
+1261(whose)X
+1492(total)X
+1660(key)X
+1802(and)X
+1943(data)X
+2102(size)X
+2252(exceed)X
+720 3782(the)N
+850(page)X
+1034(size)X
+1191(of)X
+1290(the)X
+1420(hash)X
+1599(table.)X
+1827(Similarly,)X
+2176(if)X
+2257(two)X
+2409(or)X
+720 3870(more)N
+907(keys)X
+1076(produce)X
+1357(the)X
+1477(same)X
+1664(hash)X
+1833(value)X
+2029(and)X
+2166(their)X
+2334(total)X
+720 3958(size)N
+876(exceeds)X
+1162(the)X
+1291(page)X
+1474(size,)X
+1650(the)X
+1779(table)X
+1966(cannot)X
+2210(store)X
+2396(all)X
+720 4046(the)N
+838(colliding)X
+1142(keys.)X
+892 4160(The)N
+1050(in-memory)X
+2 f
+1439(hsearch)X
+1 f
+1725(routines)X
+2015(have)X
+2199(different)X
+720 4248(shortcomings.)N
+1219(First,)X
+1413(the)X
+1539(notion)X
+1771(of)X
+1865(a)X
+1928(single)X
+2146(hash)X
+2320(table)X
+720 4336(is)N
+807(embedded)X
+1171(in)X
+1266(the)X
+1397(interface,)X
+1732(preventing)X
+2108(an)X
+2217(applica-)X
+720 4424(tion)N
+902(from)X
+1116(accessing)X
+1482(multiple)X
+1806(tables)X
+2050(concurrently.)X
+720 4512(Secondly,)N
+1063(the)X
+1186(routine)X
+1438(to)X
+1525(create)X
+1743(a)X
+1804(hash)X
+1976(table)X
+2157(requires)X
+2440(a)X
+720 4600(parameter)N
+1066(which)X
+1286(declares)X
+1573(the)X
+1694(size)X
+1842(of)X
+1932(the)X
+2053(hash)X
+2223(table.)X
+2422(If)X
+720 4688(this)N
+856(size)X
+1001(is)X
+1074(set)X
+1183(too)X
+1305(low,)X
+1465(performance)X
+1892(degradation)X
+2291(or)X
+2378(the)X
+720 4776(inability)N
+1008(to)X
+1092(add)X
+1230(items)X
+1425(to)X
+1509(the)X
+1628(table)X
+1805(may)X
+1964(result.)X
+2223(In)X
+2311(addi-)X
+720 4864(tion,)N
+2 f
+910(hsearch)X
+1 f
+1210(requires)X
+1515(that)X
+1681(the)X
+1825(application)X
+2226(allocate)X
+720 4952(memory)N
+1037(for)X
+1181(the)X
+1329(key)X
+1495(and)X
+1661(data)X
+1845(items.)X
+2108(Lastly,)X
+2378(the)X
+2 f
+720 5040(hsearch)N
+1 f
+1013(routines)X
+1310(provide)X
+1594(no)X
+1713(interface)X
+2034(to)X
+2135(store)X
+2329(hash)X
+720 5128(tables)N
+927(on)X
+1027(disk.)X
+16 s
+720 5593 MXY
+864 0 Dl
+2 f
+8 s
+760 5648(1)N
+1 f
+9 s
+5673(UNIX)Y
+990(is)X
+1056(a)X
+1106(registered)X
+1408(trademark)X
+1718(of)X
+1796(AT&T.)X
+10 s
+2878 2128(The)N
+3032(goal)X
+3199(of)X
+3295(our)X
+3431(work)X
+3625(was)X
+3779(to)X
+3870(design)X
+4108(and)X
+4253(imple-)X
+2706 2216(ment)N
+2900(a)X
+2970(new)X
+3138(package)X
+3436(that)X
+3590(provides)X
+3899(a)X
+3968(superset)X
+4264(of)X
+4364(the)X
+2706 2304(functionality)N
+3144(of)X
+3240(both)X
+2 f
+3411(dbm)X
+1 f
+3578(and)X
+2 f
+3723(hsearch)X
+1 f
+3977(.)X
+4045(The)X
+4198(package)X
+2706 2392(had)N
+2871(to)X
+2982(overcome)X
+3348(the)X
+3495(interface)X
+3826(shortcomings)X
+4306(cited)X
+2706 2480(above)N
+2930(and)X
+3078(its)X
+3185(implementation)X
+3719(had)X
+3867(to)X
+3961(provide)X
+4238(perfor-)X
+2706 2568(mance)N
+2942(equal)X
+3142(or)X
+3235(superior)X
+3524(to)X
+3612(that)X
+3758(of)X
+3851(the)X
+3975(existing)X
+4253(imple-)X
+2706 2656(mentations.)N
+3152(In)X
+3274(order)X
+3498(to)X
+3614(provide)X
+3913(a)X
+4003(compact)X
+4329(disk)X
+2706 2744(representation,)N
+3224(graceful)X
+3531(table)X
+3729(growth,)X
+4018(and)X
+4176(expected)X
+2706 2832(constant)N
+3033(time)X
+3234(performance,)X
+3720(we)X
+3873(selected)X
+4191(Litwin's)X
+2706 2920(linear)N
+2923(hashing)X
+3206(algorithm)X
+3551([LAR88,)X
+3872(LIT80].)X
+4178(We)X
+4324(then)X
+2706 3008(enhanced)N
+3037(the)X
+3161(algorithm)X
+3498(to)X
+3586(handle)X
+3826(page)X
+4004(over\257ows)X
+4346(and)X
+2706 3096(large)N
+2900(key)X
+3049(handling)X
+3362(with)X
+3537(a)X
+3606(single)X
+3830(mechanism,)X
+4248(named)X
+2706 3184(buddy-in-waiting.)N
+3 f
+2975 3338(Existing)N
+3274(UNIX)X
+3499(Hashing)X
+3802(Techniques)X
+1 f
+2878 3470(Over)N
+3076(the)X
+3210(last)X
+3357(decade,)X
+3637(several)X
+3901(dynamic)X
+4213(hashing)X
+2706 3558(schemes)N
+3000(have)X
+3174(been)X
+3348(developed)X
+3700(for)X
+3816(the)X
+3936(UNIX)X
+4159(timeshar-)X
+2706 3646(ing)N
+2856(system,)X
+3146(starting)X
+3433(with)X
+3622(the)X
+3767(inclusion)X
+4107(of)X
+2 f
+4221(dbm)X
+1 f
+4359(,)X
+4426(a)X
+2706 3734(minimal)N
+3008(database)X
+3321(library)X
+3571(written)X
+3834(by)X
+3950(Ken)X
+4120(Thompson)X
+2706 3822([THOM90],)N
+3141(in)X
+3248(the)X
+3391(Seventh)X
+3694(Edition)X
+3974(UNIX)X
+4220(system.)X
+2706 3910(Since)N
+2916(then,)X
+3106(an)X
+3214(extended)X
+3536(version)X
+3804(of)X
+3903(the)X
+4032(same)X
+4228(library,)X
+2 f
+2706 3998(ndbm)N
+1 f
+2884(,)X
+2933(and)X
+3078(a)X
+3142(public-domain)X
+3637(clone)X
+3839(of)X
+3934(the)X
+4060(latter,)X
+2 f
+4273(sdbm)X
+1 f
+4442(,)X
+2706 4086(have)N
+2902(been)X
+3098(developed.)X
+3491(Another)X
+3797 0.1645(interface-compatible)AX
+2706 4174(library)N
+2 f
+2950(gdbm)X
+1 f
+3128(,)X
+3178(was)X
+3333(recently)X
+3622(made)X
+3826(available)X
+4145(as)X
+4241(part)X
+4395(of)X
+2706 4262(the)N
+2829(Free)X
+2997(Software)X
+3312(Foundation's)X
+3759(\(FSF\))X
+3970(software)X
+4271(distri-)X
+2706 4350(bution.)N
+2878 4464(All)N
+3017(of)X
+3121(these)X
+3323(implementations)X
+3893(are)X
+4029(based)X
+4248(on)X
+4364(the)X
+2706 4552(idea)N
+2871(of)X
+2969(revealing)X
+3299(just)X
+3445(enough)X
+3711(bits)X
+3856(of)X
+3953(a)X
+4019(hash)X
+4196(value)X
+4400(to)X
+2706 4640(locate)N
+2920(a)X
+2978(page)X
+3151(in)X
+3234(a)X
+3291(single)X
+3503(access.)X
+3770(While)X
+2 f
+3987(dbm/ndbm)X
+1 f
+4346(and)X
+2 f
+2706 4728(sdbm)N
+1 f
+2908(map)X
+3079(the)X
+3210(hash)X
+3390(value)X
+3597(directly)X
+3874(to)X
+3968(a)X
+4036(disk)X
+4201(address,)X
+2 f
+2706 4816(gdbm)N
+1 f
+2921(uses)X
+3096(the)X
+3231(hash)X
+3414(value)X
+3624(to)X
+3722(index)X
+3936(into)X
+4096(a)X
+2 f
+4168(directory)X
+1 f
+2706 4904([ENB88])N
+3020(containing)X
+3378(disk)X
+3531(addresses.)X
+2878 5018(The)N
+2 f
+3033(hsearch)X
+1 f
+3317(routines)X
+3605(in)X
+3697(System)X
+3962(V)X
+4049(are)X
+4177(designed)X
+2706 5106(to)N
+2804(provide)X
+3085(memory-resident)X
+3669(hash)X
+3852(tables.)X
+4115(Since)X
+4328(data)X
+2706 5194(access)N
+2948(does)X
+3131(not)X
+3269(require)X
+3533(disk)X
+3702(access,)X
+3964(simple)X
+4213(hashing)X
+2706 5282(schemes)N
+3010(which)X
+3238(may)X
+3408(require)X
+3667(multiple)X
+3964(probes)X
+4209(into)X
+4364(the)X
+2706 5370(table)N
+2889(are)X
+3015(used.)X
+3209(A)X
+3294(more)X
+3486(interesting)X
+3851(version)X
+4114(of)X
+2 f
+4208(hsearch)X
+1 f
+2706 5458(is)N
+2784(a)X
+2845(public)X
+3070(domain)X
+3335(library,)X
+2 f
+3594(dynahash)X
+1 f
+3901(,)X
+3945(that)X
+4089(implements)X
+2706 5546(Larson's)N
+3036(in-memory)X
+3440(adaptation)X
+3822([LAR88])X
+4164(of)X
+4279(linear)X
+2706 5634(hashing)N
+2975([LIT80].)X
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+1 f
+4424(1)X
+
+2 p
+%%Page: 2 2
+10 s 10 xH 0 xS 1 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+2 f
+1074 538(dbm)N
+1 f
+1232(and)X
+2 f
+1368(ndbm)X
+1 f
+604 670(The)N
+2 f
+760(dbm)X
+1 f
+928(and)X
+2 f
+1074(ndbm)X
+1 f
+1282(library)X
+1526(implementations)X
+2089(are)X
+432 758(based)N
+667(on)X
+799(the)X
+949(same)X
+1166(algorithm)X
+1529(by)X
+1661(Ken)X
+1846(Thompson)X
+432 846([THOM90,)N
+824(TOR88,)X
+1113(WAL84],)X
+1452(but)X
+1582(differ)X
+1789(in)X
+1879(their)X
+2054(pro-)X
+432 934(grammatic)N
+801(interfaces.)X
+1160(The)X
+1311(latter)X
+1502(is)X
+1581(a)X
+1643(modi\256ed)X
+1952(version)X
+432 1022(of)N
+533(the)X
+665(former)X
+918(which)X
+1148(adds)X
+1328(support)X
+1601(for)X
+1728(multiple)X
+2027(data-)X
+432 1110(bases)N
+634(to)X
+724(be)X
+828(open)X
+1011(concurrently.)X
+1484(The)X
+1636(discussion)X
+1996(of)X
+2090(the)X
+432 1198(algorithm)N
+774(that)X
+925(follows)X
+1196(is)X
+1280(applicable)X
+1640(to)X
+1732(both)X
+2 f
+1904(dbm)X
+1 f
+2072(and)X
+2 f
+432 1286(ndbm)N
+1 f
+610(.)X
+604 1400(The)N
+760(basic)X
+956(structure)X
+1268(of)X
+2 f
+1366(dbm)X
+1 f
+1535(calls)X
+1712(for)X
+1836(\256xed-sized)X
+432 1488(disk)N
+612(blocks)X
+868(\(buckets\))X
+1214(and)X
+1377(an)X
+2 f
+1499(access)X
+1 f
+1755(function)X
+2068(that)X
+432 1576(maps)N
+623(a)X
+681(key)X
+819(to)X
+902(a)X
+959(bucket.)X
+1234(The)X
+1380(interface)X
+1683(routines)X
+1962(use)X
+2090(the)X
+2 f
+432 1664(access)N
+1 f
+673(function)X
+970(to)X
+1062(obtain)X
+1292(the)X
+1420(appropriate)X
+1816(bucket)X
+2060(in)X
+2152(a)X
+432 1752(single)N
+643(disk)X
+796(access.)X
+604 1866(Within)N
+869(the)X
+2 f
+1010(access)X
+1 f
+1263(function,)X
+1593(a)X
+1672(bit-randomizing)X
+432 1954(hash)N
+610(function)X
+2 f
+8 s
+877 1929(2)N
+1 f
+10 s
+940 1954(is)N
+1024(used)X
+1202(to)X
+1294(convert)X
+1565(a)X
+1631(key)X
+1777(into)X
+1931(a)X
+1997(32-bit)X
+432 2042(hash)N
+605(value.)X
+825(Out)X
+971(of)X
+1064(these)X
+1254(32)X
+1359(bits,)X
+1519(only)X
+1686(as)X
+1778(many)X
+1981(bits)X
+2121(as)X
+432 2130(necessary)N
+773(are)X
+900(used)X
+1075(to)X
+1165(determine)X
+1514(the)X
+1639(particular)X
+1974(bucket)X
+432 2218(on)N
+533(which)X
+750(a)X
+807(key)X
+944(resides.)X
+1228(An)X
+1347(in-memory)X
+1724(bitmap)X
+1967(is)X
+2041(used)X
+432 2306(to)N
+533(determine)X
+893(how)X
+1070(many)X
+1287(bits)X
+1441(are)X
+1579(required.)X
+1905(Each)X
+2104(bit)X
+432 2394(indicates)N
+746(whether)X
+1033(its)X
+1136(associated)X
+1494(bucket)X
+1736(has)X
+1871(been)X
+2051(split)X
+432 2482(yet)N
+562(\(a)X
+657(0)X
+728(indicating)X
+1079(that)X
+1230(the)X
+1359(bucket)X
+1604(has)X
+1742(not)X
+1875(yet)X
+2004(split\).)X
+432 2570(The)N
+590(use)X
+730(of)X
+830(the)X
+961(hash)X
+1141(function)X
+1441(and)X
+1590(the)X
+1720(bitmap)X
+1974(is)X
+2059(best)X
+432 2658(described)N
+769(by)X
+878(stepping)X
+1177(through)X
+1454(database)X
+1759(creation)X
+2046(with)X
+432 2746(multiple)N
+718(invocations)X
+1107(of)X
+1194(a)X
+2 f
+1250(store)X
+1 f
+1430(operation.)X
+604 2860(Initially,)N
+906(the)X
+1033(hash)X
+1209(table)X
+1394(contains)X
+1690(a)X
+1755(single)X
+1974(bucket)X
+432 2948(\(bucket)N
+711(0\),)X
+836(the)X
+972(bit)X
+1094(map)X
+1270(contains)X
+1575(a)X
+1649(single)X
+1878(bit)X
+2000(\(bit)X
+2148(0)X
+432 3036(corresponding)N
+913(to)X
+997(bucket)X
+1233(0\),)X
+1342(and)X
+1480(0)X
+1542(bits)X
+1699(of)X
+1788(a)X
+1846(hash)X
+2014(value)X
+432 3124(are)N
+560(examined)X
+901(to)X
+992(determine)X
+1342(where)X
+1568(a)X
+1633(key)X
+1778(is)X
+1860(placed)X
+2099(\(in)X
+432 3212(bucket)N
+670(0\).)X
+801(When)X
+1017(bucket)X
+1255(0)X
+1319(is)X
+1396(full,)X
+1551(its)X
+1650(bit)X
+1758(in)X
+1844(the)X
+1966(bitmap)X
+432 3300(\(bit)N
+564(0\))X
+652(is)X
+726(set,)X
+856(and)X
+993(its)X
+1089(contents)X
+1377(are)X
+1497(split)X
+1655(between)X
+1943(buckets)X
+432 3388(0)N
+499(and)X
+641(1,)X
+727(by)X
+833(considering)X
+1233(the)X
+1357(0)X
+2 f
+7 s
+3356(th)Y
+10 s
+1 f
+1480 3388(bit)N
+1590(\(the)X
+1741(lowest)X
+1976(bit)X
+2086(not)X
+432 3476(previously)N
+800(examined\))X
+1169(of)X
+1266(the)X
+1393(hash)X
+1569(value)X
+1772(for)X
+1895(each)X
+2072(key)X
+432 3564(within)N
+668(the)X
+798(bucket.)X
+1064(Given)X
+1292(a)X
+1359(well-designed)X
+1840(hash)X
+2018(func-)X
+432 3652(tion,)N
+613(approximately)X
+1112(half)X
+1273(of)X
+1376(the)X
+1510(keys)X
+1693(will)X
+1853(have)X
+2041(hash)X
+432 3740(values)N
+666(with)X
+837(the)X
+964(0)X
+2 f
+7 s
+3708(th)Y
+10 s
+1 f
+1090 3740(bit)N
+1203(set.)X
+1341(All)X
+1471(such)X
+1646(keys)X
+1821(and)X
+1965(associ-)X
+432 3828(ated)N
+586(data)X
+740(are)X
+859(moved)X
+1097(to)X
+1179(bucket)X
+1413(1,)X
+1493(and)X
+1629(the)X
+1747(rest)X
+1883(remain)X
+2126(in)X
+432 3916(bucket)N
+666(0.)X
+604 4030(After)N
+804(this)X
+949(split,)X
+1135(the)X
+1262(\256le)X
+1393(now)X
+1560(contains)X
+1856(two)X
+2005(buck-)X
+432 4118(ets,)N
+562(and)X
+699(the)X
+818(bitmap)X
+1061(contains)X
+1349(three)X
+1530(bits:)X
+1687(the)X
+1805(0)X
+2 f
+7 s
+4086(th)Y
+10 s
+1 f
+1922 4118(bit)N
+2026(is)X
+2099(set)X
+432 4206(to)N
+525(indicate)X
+810(a)X
+876(bucket)X
+1120(0)X
+1190(split)X
+1357(when)X
+1561(no)X
+1671(bits)X
+1816(of)X
+1913(the)X
+2041(hash)X
+432 4294(value)N
+648(are)X
+789(considered,)X
+1199(and)X
+1357(two)X
+1519(more)X
+1726(unset)X
+1937(bits)X
+2094(for)X
+432 4382(buckets)N
+706(0)X
+775(and)X
+920(1.)X
+1029(The)X
+1183(placement)X
+1542(of)X
+1638(an)X
+1742(incoming)X
+2072(key)X
+432 4470(now)N
+604(requires)X
+897(examination)X
+1327(of)X
+1428(the)X
+1560(0)X
+2 f
+7 s
+4438(th)Y
+10 s
+1 f
+1691 4470(bit)N
+1809(of)X
+1910(the)X
+2041(hash)X
+432 4558(value,)N
+667(and)X
+824(the)X
+963(key)X
+1119(is)X
+1212(placed)X
+1462(either)X
+1685(in)X
+1787(bucket)X
+2041(0)X
+2121(or)X
+432 4646(bucket)N
+674(1.)X
+782(If)X
+864(either)X
+1075(bucket)X
+1317(0)X
+1385(or)X
+1480(bucket)X
+1722(1)X
+1790(\256lls)X
+1937(up,)X
+2064(it)X
+2135(is)X
+432 4734(split)N
+598(as)X
+693(before,)X
+947(its)X
+1050(bit)X
+1162(is)X
+1243(set)X
+1360(in)X
+1450(the)X
+1576(bitmap,)X
+1846(and)X
+1990(a)X
+2054(new)X
+432 4822(set)N
+541(of)X
+628(unset)X
+817(bits)X
+952(are)X
+1071(added)X
+1283(to)X
+1365(the)X
+1483(bitmap.)X
+604 4936(Each)N
+791(time)X
+959(we)X
+1079(consider)X
+1376(a)X
+1437(new)X
+1596(bit)X
+1705(\(bit)X
+1841(n\),)X
+1953(we)X
+2072(add)X
+432 5024(2)N
+2 f
+7 s
+4992(n)Y
+9 f
+509(+)X
+1 f
+540(1)X
+10 s
+595 5024(bits)N
+737(to)X
+826(the)X
+951(bitmap)X
+1199(and)X
+1341(obtain)X
+1567(2)X
+2 f
+7 s
+4992(n)Y
+9 f
+1644(+)X
+1 f
+1675(1)X
+10 s
+1729 5024(more)N
+1920(address-)X
+432 5112(able)N
+595(buckets)X
+869(in)X
+960(the)X
+1087(\256le.)X
+1258(As)X
+1376(a)X
+1441(result,)X
+1668(the)X
+1795(bitmap)X
+2045(con-)X
+432 5200(tains)N
+618(the)X
+751(previous)X
+1062(2)X
+2 f
+7 s
+5168(n)Y
+9 f
+1139(+)X
+1 f
+1170(1)X
+2 f
+10 s
+9 f
+5200(-)Y
+1 f
+1242(1)X
+1317(bits)X
+1467(\(1)X
+2 f
+9 f
+1534(+)X
+1 f
+1578(2)X
+2 f
+9 f
+(+)S
+1 f
+1662(4)X
+2 f
+9 f
+(+)S
+1 f
+1746(...)X
+2 f
+9 f
+(+)S
+1 f
+1850(2)X
+2 f
+7 s
+5168(n)Y
+10 s
+1 f
+1931 5200(\))N
+1992(which)X
+432 5288(trace)N
+649(the)X
+807(entire)X
+2 f
+1050(split)X
+1247(history)X
+1 f
+1529(of)X
+1656(the)X
+1813(addressable)X
+16 s
+432 5433 MXY
+864 0 Dl
+2 f
+8 s
+472 5488(2)N
+1 f
+9 s
+523 5513(This)N
+670(bit-randomizing)X
+1153(property)X
+1416(is)X
+1482(important)X
+1780(to)X
+1854(obtain)X
+2052(radi-)X
+432 5593(cally)N
+599(different)X
+874(hash)X
+1033(values)X
+1244(for)X
+1355(nearly)X
+1562(identical)X
+1836(keys,)X
+2012(which)X
+432 5673(in)N
+506(turn)X
+640(avoids)X
+846(clustering)X
+1148(of)X
+1226(such)X
+1376(keys)X
+1526(in)X
+1600(a)X
+1650(single)X
+1840(bucket.)X
+10 s
+2418 538(buckets.)N
+2590 652(Given)N
+2809(a)X
+2868(key)X
+3007(and)X
+3146(the)X
+3267(bitmap)X
+3512(created)X
+3768(by)X
+3871(this)X
+4009(algo-)X
+2418 740(rithm,)N
+2638(we)X
+2759(\256rst)X
+2910(examine)X
+3209(bit)X
+3320(0)X
+3386(of)X
+3479(the)X
+3603(bitmap)X
+3851(\(the)X
+4002(bit)X
+4112(to)X
+2418 828(consult)N
+2673(when)X
+2871(0)X
+2934(bits)X
+3072(of)X
+3162(the)X
+3283(hash)X
+3453(value)X
+3650(are)X
+3772(being)X
+3973(exam-)X
+2418 916(ined\).)N
+2631(If)X
+2713(it)X
+2785(is)X
+2866(set)X
+2982(\(indicating)X
+3356(that)X
+3503(the)X
+3628(bucket)X
+3869(split\),)X
+4080(we)X
+2418 1004(begin)N
+2617(considering)X
+3012(the)X
+3131(bits)X
+3267(of)X
+3355(the)X
+3473(32-bit)X
+3684(hash)X
+3851(value.)X
+4085(As)X
+2418 1092(bit)N
+2525(n)X
+2587(is)X
+2662(revealed,)X
+2977(a)X
+3035(mask)X
+3226(equal)X
+3422(to)X
+3506(2)X
+2 f
+7 s
+1060(n)Y
+9 f
+3583(+)X
+1 f
+3614(1)X
+2 f
+10 s
+9 f
+1092(-)Y
+1 f
+3686(1)X
+3748(will)X
+3894(yield)X
+4076(the)X
+2418 1180(current)N
+2675(bucket)X
+2918(address.)X
+3228(Adding)X
+3496(2)X
+2 f
+7 s
+1148(n)Y
+9 f
+3573(+)X
+1 f
+3604(1)X
+2 f
+10 s
+9 f
+1180(-)Y
+1 f
+3676(1)X
+3744(to)X
+3834(the)X
+3960(bucket)X
+2418 1268(address)N
+2701(identi\256es)X
+3035(which)X
+3272(bit)X
+3397(in)X
+3500(the)X
+3639(bitmap)X
+3902(must)X
+4098(be)X
+2418 1356(checked.)N
+2743(We)X
+2876(continue)X
+3173(revealing)X
+3493(bits)X
+3628(of)X
+3715(the)X
+3833(hash)X
+4000(value)X
+2418 1444(until)N
+2591(all)X
+2698(set)X
+2814(bits)X
+2955(in)X
+3043(the)X
+3167(bitmap)X
+3415(are)X
+3540(exhausted.)X
+3907(The)X
+4058(fol-)X
+2418 1532(lowing)N
+2682(algorithm,)X
+3055(a)X
+3133(simpli\256cation)X
+3614(of)X
+3723(the)X
+3863(algorithm)X
+2418 1620(due)N
+2565(to)X
+2658(Ken)X
+2823(Thompson)X
+3196([THOM90,)X
+3590(TOR88],)X
+3908(uses)X
+4076(the)X
+2418 1708(hash)N
+2625(value)X
+2839(and)X
+2995(the)X
+3133(bitmap)X
+3395(to)X
+3497(calculate)X
+3823(the)X
+3960(bucket)X
+2418 1796(address)N
+2679(as)X
+2766(discussed)X
+3093(above.)X
+0(Courier)xf 0 f
+1 f
+0 f
+8 s
+2418 2095(hash)N
+2608(=)X
+2684 -0.4038(calchash\(key\);)AX
+2418 2183(mask)N
+2608(=)X
+2684(0;)X
+2418 2271(while)N
+2646 -0.4018(\(isbitset\(\(hash)AX
+3254(&)X
+3330(mask\))X
+3558(+)X
+3634(mask\)\))X
+2706 2359(mask)N
+2896(=)X
+2972(\(mask)X
+3200(<<)X
+3314(1\))X
+3428(+)X
+3504(1;)X
+2418 2447(bucket)N
+2684(=)X
+2760(hash)X
+2950(&)X
+3026(mask;)X
+2 f
+10 s
+3211 2812(sdbm)N
+1 f
+2590 2944(The)N
+2 f
+2738(sdbm)X
+1 f
+2930(library)X
+3167(is)X
+3243(a)X
+3302(public-domain)X
+3791(clone)X
+3987(of)X
+4076(the)X
+2 f
+2418 3032(ndbm)N
+1 f
+2638(library,)X
+2914(developed)X
+3286(by)X
+3408(Ozan)X
+3620(Yigit)X
+3826(to)X
+3929(provide)X
+2 f
+2418 3120(ndbm)N
+1 f
+2596('s)X
+2692(functionality)X
+3139(under)X
+3359(some)X
+3565(versions)X
+3869(of)X
+3973(UNIX)X
+2418 3208(that)N
+2559(exclude)X
+2830(it)X
+2894(for)X
+3008(licensing)X
+3317(reasons)X
+3578([YIG89].)X
+3895(The)X
+4040(pro-)X
+2418 3296(grammer)N
+2735(interface,)X
+3064(and)X
+3207(the)X
+3332(basic)X
+3524(structure)X
+3832(of)X
+2 f
+3926(sdbm)X
+1 f
+4121(is)X
+2418 3384(identical)N
+2733(to)X
+2 f
+2834(ndbm)X
+1 f
+3051(but)X
+3192(internal)X
+3476(details)X
+3723(of)X
+3828(the)X
+2 f
+3964(access)X
+1 f
+2418 3472(function,)N
+2726(such)X
+2894(as)X
+2982(the)X
+3101(calculation)X
+3474(of)X
+3561(the)X
+3679(bucket)X
+3913(address,)X
+2418 3560(and)N
+2563(the)X
+2690(use)X
+2825(of)X
+2920(different)X
+3225(hash)X
+3400(functions)X
+3726(make)X
+3928(the)X
+4054(two)X
+2418 3648(incompatible)N
+2856(at)X
+2934(the)X
+3052(database)X
+3349(level.)X
+2590 3762(The)N
+2 f
+2740(sdbm)X
+1 f
+2934(library)X
+3173(is)X
+3251(based)X
+3458(on)X
+3562(a)X
+3622(simpli\256ed)X
+3965(imple-)X
+2418 3850(mentation)N
+2778(of)X
+2885(Larson's)X
+3206(1978)X
+2 f
+3406(dynamic)X
+3717(hashing)X
+1 f
+4009(algo-)X
+2418 3938(rithm)N
+2616(including)X
+2943(the)X
+2 f
+3066(re\256nements)X
+3461(and)X
+3605(variations)X
+1 f
+3953(of)X
+4044(sec-)X
+2418 4026(tion)N
+2562(5)X
+2622([LAR78].)X
+2956(Larson's)X
+3257(original)X
+3526(algorithm)X
+3857(calls)X
+4024(for)X
+4138(a)X
+2418 4114(forest)N
+2635(of)X
+2736(binary)X
+2975(hash)X
+3156(trees)X
+3341(that)X
+3494(are)X
+3626(accessed)X
+3941(by)X
+4054(two)X
+2418 4202(hash)N
+2586(functions.)X
+2925(The)X
+3071(\256rst)X
+3216(hash)X
+3384(function)X
+3672(selects)X
+3907(a)X
+3964(partic-)X
+2418 4290(ular)N
+2571(tree)X
+2720(within)X
+2952(the)X
+3078(forest.)X
+3309(The)X
+3462(second)X
+3713(hash)X
+3887(function,)X
+2418 4378(which)N
+2659(is)X
+2757(required)X
+3070(to)X
+3177(be)X
+3297(a)X
+3377(boolean)X
+3675(pseudo-random)X
+2418 4466(number)N
+2687(generator)X
+3015(that)X
+3159(is)X
+3236(seeded)X
+3479(by)X
+3583(the)X
+3705(key,)X
+3865(is)X
+3942(used)X
+4112(to)X
+2418 4554(traverse)N
+2733(the)X
+2890(tree)X
+3070(until)X
+3275(internal)X
+3579(\(split\))X
+3829(nodes)X
+4075(are)X
+2418 4642(exhausted)N
+2763(and)X
+2903(an)X
+3003(external)X
+3286(\(non-split\))X
+3648(node)X
+3827(is)X
+3903(reached.)X
+2418 4730(The)N
+2571(bucket)X
+2813(addresses)X
+3149(are)X
+3276(stored)X
+3500(directly)X
+3772(in)X
+3861(the)X
+3986(exter-)X
+2418 4818(nal)N
+2536(nodes.)X
+2590 4932(Larson's)N
+2903(re\256nements)X
+3309(are)X
+3440(based)X
+3655(on)X
+3767(the)X
+3897(observa-)X
+2418 5020(tion)N
+2570(that)X
+2718(the)X
+2844(nodes)X
+3059(can)X
+3199(be)X
+3303(represented)X
+3702(by)X
+3809(a)X
+3872(single)X
+4090(bit)X
+2418 5108(that)N
+2569(is)X
+2653(set)X
+2773(for)X
+2898(internal)X
+3174(nodes)X
+3392(and)X
+3539(not)X
+3672(set)X
+3791(for)X
+3915(external)X
+2418 5196(nodes,)N
+2652(resulting)X
+2959(in)X
+3048(a)X
+3111(radix)X
+3303(search)X
+3536(trie.)X
+3709(Figure)X
+3944(1)X
+4010(illus-)X
+2418 5284(trates)N
+2621(this.)X
+2804(Nodes)X
+3037(A)X
+3123(and)X
+3267(B)X
+3348(are)X
+3475(internal)X
+3748(\(split\))X
+3967(nodes,)X
+2418 5372(thus)N
+2573(having)X
+2813(no)X
+2915(bucket)X
+3151(addresses)X
+3480(associated)X
+3831(with)X
+3994(them.)X
+2418 5460(Instead,)N
+2693(the)X
+2814(external)X
+3096(nodes)X
+3306(\(C,)X
+3429(D,)X
+3530(and)X
+3669(E\))X
+3768(each)X
+3938(need)X
+4112(to)X
+2418 5548(refer)N
+2594(to)X
+2679(a)X
+2738(bucket)X
+2975(address.)X
+3279(These)X
+3494(bucket)X
+3731(addresses)X
+4062(can)X
+2418 5636(be)N
+2529(stored)X
+2760(in)X
+2857(the)X
+2990(trie)X
+3132(itself)X
+3327(where)X
+3559(the)X
+3691(subtries)X
+3974(would)X
+3 f
+432 5960(2)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+3 p
+%%Page: 3 3
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+720 538(live)N
+862(if)X
+933(they)X
+1092(existed)X
+1340([KNU68].)X
+1709(For)X
+1841(example,)X
+2154(if)X
+2224(nodes)X
+2432(F)X
+720 626(and)N
+858(G)X
+938(were)X
+1117(the)X
+1237(children)X
+1522(of)X
+1610(node)X
+1787(C,)X
+1881(the)X
+2000(bucket)X
+2235(address)X
+720 714(L00)N
+886(could)X
+1101(reside)X
+1330(in)X
+1429(the)X
+1563(bits)X
+1714(that)X
+1870(will)X
+2030(eventually)X
+2400(be)X
+720 802(used)N
+887(to)X
+969(store)X
+1145(nodes)X
+1352(F)X
+1416(and)X
+1552(G)X
+1630(and)X
+1766(all)X
+1866(their)X
+2033(children.)X
+10 f
+720 890 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+1894 2247(L1)N
+784 1925(A)N
+1431(E)X
+1106 2247(D)N
+1428 1281(C)N
+1109 1603(B)N
+1884 1930(L01)N
+1879 1286(L00)N
+1221 1814(1)N
+903 2131(1)N
+1221 1402(0)N
+903 1714(0)N
+1 Dt
+1397 1821 MXY
+-8 -32 Dl
+-5 19 Dl
+-20 6 Dl
+33 7 Dl
+-187 -182 Dl
+1397 1322 MXY
+-33 7 Dl
+20 6 Dl
+5 19 Dl
+8 -32 Dl
+-187 182 Dl
+1069 1639 MXY
+-32 7 Dl
+20 6 Dl
+5 19 Dl
+7 -32 Dl
+-186 182 Dl
+1374 1891 MXY
+185 Dc
+1779 2133 MXY
+0 161 Dl
+322 0 Dl
+0 -161 Dl
+-322 0 Dl
+1811 MY
+0 161 Dl
+322 0 Dl
+0 -161 Dl
+-322 0 Dl
+1166 MY
+0 161 Dl
+322 0 Dl
+0 -161 Dl
+-322 0 Dl
+1052 2213 MXY
+185 Dc
+1569 MY
+185 Dc
+720 1881 MXY
+185 Dc
+1779 2213 MXY
+-28 -17 Dl
+10 17 Dl
+-10 18 Dl
+28 -18 Dl
+-543 0 Dl
+1769 1891 MXY
+-28 -18 Dl
+10 18 Dl
+-10 18 Dl
+28 -18 Dl
+-201 0 Dl
+1364 1247 MXY
+185 Dc
+1769 MX
+-28 -18 Dl
+10 18 Dl
+-10 18 Dl
+28 -18 Dl
+-201 0 Dl
+1064 2143 MXY
+-7 -32 Dl
+-5 19 Dl
+-20 6 Dl
+32 7 Dl
+-181 -181 Dl
+3 Dt
+-1 Ds
+8 s
+720 2482(Figure)N
+925(1:)X
+1 f
+1002(Radix)X
+1179(search)X
+1365(trie)X
+1474(with)X
+1612(internal)X
+1831(nodes)X
+2004(A)X
+2074(and)X
+2189(B,)X
+2271(external)X
+720 2570(nodes)N
+891(C,)X
+972(D,)X
+1056(and)X
+1170(E,)X
+1247(and)X
+1361(bucket)X
+1553(addresses)X
+1819(stored)X
+1997(in)X
+2069(the)X
+2168(unused)X
+2370(por-)X
+720 2658(tion)N
+836(of)X
+905(the)X
+999(trie.)X
+10 s
+10 f
+720 2922 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 f
+892 3124(Further)N
+1153(simpli\256cations)X
+1647(of)X
+1738(the)X
+1860(above)X
+2076([YIG89])X
+2377(are)X
+720 3212(possible.)N
+1038(Using)X
+1265(a)X
+1337(single)X
+1564(radix)X
+1765(trie)X
+1908(to)X
+2006(avoid)X
+2219(the)X
+2352(\256rst)X
+720 3300(hash)N
+904(function,)X
+1227(replacing)X
+1562(the)X
+1696(pseudo-random)X
+2231(number)X
+720 3388(generator)N
+1052(with)X
+1222(a)X
+1286(well)X
+1452(designed,)X
+1785(bit-randomizing)X
+2329(hash)X
+720 3476(function,)N
+1053(and)X
+1215(using)X
+1434(the)X
+1578(portion)X
+1855(of)X
+1967(the)X
+2110(hash)X
+2302(value)X
+720 3564(exposed)N
+1021(during)X
+1268(the)X
+1404(trie)X
+1549(traversal)X
+1864(as)X
+1969(a)X
+2042(direct)X
+2262(bucket)X
+720 3652(address)N
+990(results)X
+1228(in)X
+1319(an)X
+2 f
+1424(access)X
+1 f
+1663(function)X
+1959(that)X
+2108(works)X
+2333(very)X
+720 3740(similar)N
+974(to)X
+1068(Thompson's)X
+1499(algorithm)X
+1841(above.)X
+2084(The)X
+2240(follow-)X
+720 3828(ing)N
+847(algorithm)X
+1183(uses)X
+1346(the)X
+1469(hash)X
+1641(value)X
+1840(to)X
+1927(traverse)X
+2206(a)X
+2266(linear-)X
+720 3916(ized)N
+874(radix)X
+1059(trie)X
+2 f
+8 s
+1166 3891(3)N
+1 f
+10 s
+1218 3916(starting)N
+1478(at)X
+1556(the)X
+1674(0)X
+2 f
+7 s
+3884(th)Y
+10 s
+1 f
+1791 3916(bit.)N
+0 f
+8 s
+720 4215(tbit)N
+910(=)X
+986(0;)X
+1296(/*)X
+1410(radix)X
+1638(trie)X
+1828(index)X
+2056(*/)X
+720 4303(hbit)N
+910(=)X
+986(0;)X
+1296(/*)X
+1410(hash)X
+1600(bit)X
+1752(index)X
+2056(*/)X
+720 4391(mask)N
+910(=)X
+986(0;)X
+720 4479(hash)N
+910(=)X
+986 -0.4038(calchash\(key\);)AX
+720 4655(for)N
+872(\(mask)X
+1100(=)X
+1176(0;)X
+910 4743 -0.4018(isbitset\(tbit\);)AN
+910 4831(mask)N
+1100(=)X
+1176(\(mask)X
+1404(<<)X
+1518(1\))X
+1632(+)X
+1708(1\))X
+1008 4919(if)N
+1122(\(hash)X
+1350(&)X
+1426(\(1)X
+1540(<<)X
+1654 -0.4219(hbit++\)\)\))AX
+1160 5007(/*)N
+1274(right)X
+1502(son)X
+1692(*/)X
+1160 5095(tbit)N
+1350(=)X
+1426(2)X
+1502(*)X
+1578(tbit)X
+1768(+)X
+1844(2;)X
+1008 5183(else)N
+1 f
+16 s
+720 5353 MXY
+864 0 Dl
+2 f
+8 s
+760 5408(3)N
+1 f
+9 s
+818 5433(A)N
+896(linearized)X
+1206(radix)X
+1380(trie)X
+1502(is)X
+1576(merely)X
+1802(an)X
+1895(array)X
+2068(representation)X
+720 5513(of)N
+800(the)X
+908(radix)X
+1076(search)X
+1280(trie)X
+1396(described)X
+1692(above.)X
+1920(The)X
+2052(children)X
+2308(of)X
+2388(the)X
+720 5593(node)N
+885(with)X
+1038(index)X
+1223(i)X
+1267(can)X
+1391(be)X
+1483(found)X
+1675(at)X
+1751(the)X
+1863(nodes)X
+2055(indexed)X
+2307(2*i+1)X
+720 5673(and)N
+842(2*i+2.)X
+0 f
+8 s
+3146 538(/*)N
+3260(left)X
+3450(son)X
+3678(*/)X
+3146 626(tbit)N
+3336(=)X
+3412(2)X
+3488(*)X
+3564(tbit)X
+3754(+)X
+3830(1;)X
+2706 802(bucket)N
+2972(=)X
+3048(hash)X
+3238(&)X
+3314(mask;)X
+2 f
+10 s
+3495 1167(gdbm)N
+1 f
+2878 1299(The)N
+3027(gdbm)X
+3233(\(GNU)X
+3458(data)X
+3616(base)X
+3783(manager\))X
+4111(library)X
+4349(is)X
+4426(a)X
+2706 1387(UNIX)N
+2933(database)X
+3236(manager)X
+3539(written)X
+3792(by)X
+3897(Philip)X
+4112(A.)X
+4215(Nelson,)X
+2706 1475(and)N
+2848(made)X
+3048(available)X
+3364(as)X
+3457(a)X
+3518(part)X
+3668(of)X
+3760(the)X
+3883(FSF)X
+4040(software)X
+4342(dis-)X
+2706 1563(tribution.)N
+3052(The)X
+3207(gdbm)X
+3419(library)X
+3663(provides)X
+3969(the)X
+4097(same)X
+4292(func-)X
+2706 1651(tionality)N
+3028(of)X
+3151(the)X
+2 f
+3304(dbm)X
+1 f
+3442(/)X
+2 f
+3464(ndbm)X
+1 f
+3697(libraries)X
+4015([NEL90])X
+4360(but)X
+2706 1739(attempts)N
+3018(to)X
+3121(avoid)X
+3340(some)X
+3550(of)X
+3658(their)X
+3846(shortcomings.)X
+4337(The)X
+2706 1827(gdbm)N
+2918(library)X
+3162(allows)X
+3401(for)X
+3525(arbitrary-length)X
+4059(data,)X
+4242(and)X
+4387(its)X
+2706 1915(database)N
+3027(is)X
+3124(a)X
+3203(singular,)X
+3524(non-sparse)X
+2 f
+8 s
+3872 1890(4)N
+1 f
+10 s
+3947 1915(\256le.)N
+4112(The)X
+4280(gdbm)X
+2706 2003(library)N
+2947(also)X
+3103(includes)X
+2 f
+3396(dbm)X
+1 f
+3560(and)X
+2 f
+3702(ndbm)X
+1 f
+3906(compatible)X
+4288(inter-)X
+2706 2091(faces.)N
+2878 2205(The)N
+3025(gdbm)X
+3229(library)X
+3465(is)X
+3540(based)X
+3745(on)X
+2 f
+3847(extensible)X
+4189(hashing)X
+1 f
+4442(,)X
+2706 2293(a)N
+2766(dynamic)X
+3066(hashing)X
+3339(algorithm)X
+3674(by)X
+3778(Fagin)X
+3984(et)X
+4066(al)X
+4148([FAG79].)X
+2706 2381(This)N
+2881(algorithm)X
+3225(differs)X
+3467(from)X
+3655(the)X
+3785(previously)X
+4155(discussed)X
+2706 2469(algorithms)N
+3069(in)X
+3152(that)X
+3293(it)X
+3358(uses)X
+3517(a)X
+2 f
+3574(directory)X
+1 f
+3889(that)X
+4030(is)X
+4103(a)X
+4159(collapsed)X
+2706 2557(representation)N
+3192([ENB88])X
+3517(of)X
+3615(the)X
+3744(radix)X
+3940(search)X
+4177(trie)X
+4315(used)X
+2706 2645(by)N
+2 f
+2806(sdbm)X
+1 f
+2975(.)X
+10 f
+2706 2733 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+7 s
+3572 3761(L1)N
+1 Dt
+3485 3738 MXY
+-20 -13 Dl
+7 13 Dl
+-7 13 Dl
+20 -13 Dl
+-400 0 Dl
+3180 3027 MXY
+136 Dc
+2706 3494 MXY
+136 Dc
+2950 3264 MXY
+136 Dc
+3738 MY
+136 Dc
+3485 2968 MXY
+0 118 Dl
+238 0 Dl
+0 -118 Dl
+-238 0 Dl
+3442 MY
+0 119 Dl
+238 0 Dl
+0 -119 Dl
+-238 0 Dl
+3679 MY
+0 119 Dl
+238 0 Dl
+0 -119 Dl
+-238 0 Dl
+3187 3501 MXY
+136 Dc
+2963 3316 MXY
+-24 5 Dl
+15 4 Dl
+4 15 Dl
+5 -24 Dl
+-137 134 Dl
+3204 3083 MXY
+-24 5 Dl
+15 4 Dl
+3 14 Dl
+6 -23 Dl
+-137 133 Dl
+3204 3450 MXY
+-6 -24 Dl
+-3 14 Dl
+-15 5 Dl
+24 5 Dl
+-137 -134 Dl
+2842 3369(0)N
+3075 3139(0)N
+2842 3676(1)N
+3075 3443(1)N
+3562 3054(L00)N
+3565 3528(L01)N
+4197 2968 MXY
+0 118 Dl
+237 0 Dl
+0 -118 Dl
+-237 0 Dl
+3205 MY
+0 119 Dl
+237 0 Dl
+0 -119 Dl
+-237 0 Dl
+3561 MY
+0 118 Dl
+237 0 Dl
+0 -118 Dl
+-237 0 Dl
+3960 2909 MXY
+0 237 Dl
+118 0 Dl
+0 -237 Dl
+-118 0 Dl
+3146 MY
+0 237 Dl
+118 0 Dl
+0 -237 Dl
+-118 0 Dl
+3383 MY
+0 237 Dl
+118 0 Dl
+0 -237 Dl
+-118 0 Dl
+3620 MY
+0 237 Dl
+118 0 Dl
+0 -237 Dl
+-118 0 Dl
+4197 3027 MXY
+-21 -13 Dl
+8 13 Dl
+-8 13 Dl
+21 -13 Dl
+-119 0 Dl
+4197 3264 MXY
+-21 -13 Dl
+8 13 Dl
+-8 13 Dl
+21 -13 Dl
+-119 0 Dl
+3501 MY
+59 0 Dl
+0 89 Dl
+4078 3738 MXY
+59 0 Dl
+0 -88 Dl
+4197 3590 MXY
+-21 -13 Dl
+8 13 Dl
+-8 13 Dl
+21 -13 Dl
+-60 0 Dl
+4197 3650 MXY
+-21 -13 Dl
+8 13 Dl
+-8 13 Dl
+21 -13 Dl
+-60 0 Dl
+3991 3050(00)N
+3991 3287(01)N
+3991 3524(10)N
+3991 3761(11)N
+4269 3050(L00)N
+4269 3287(L01)N
+4283 3643(L1)N
+3485 3501 MXY
+-20 -13 Dl
+7 13 Dl
+-7 13 Dl
+20 -13 Dl
+-155 0 Dl
+3485 3027 MXY
+-20 -13 Dl
+7 13 Dl
+-7 13 Dl
+20 -13 Dl
+-163 0 Dl
+2967 3687 MXY
+-5 -24 Dl
+-4 14 Dl
+-15 4 Dl
+24 6 Dl
+-141 -141 Dl
+3 Dt
+-1 Ds
+8 s
+2706 4033(Figure)N
+2903(2:)X
+1 f
+2972(A)X
+3034(radix)X
+3181(search)X
+3359(trie)X
+3460(and)X
+3568(a)X
+3612(directory)X
+3858(representing)X
+4189(the)X
+4283(trie.)X
+10 s
+10 f
+2706 4209 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 f
+2878 4411(In)N
+2968(this)X
+3106(algorithm,)X
+3460(a)X
+3519(directory)X
+3832(consists)X
+4108(of)X
+4198(a)X
+4256(search)X
+2706 4499(trie)N
+2847(of)X
+2947(depth)X
+2 f
+3158(n)X
+1 f
+3211(,)X
+3264(containing)X
+3635(2)X
+2 f
+7 s
+4467(n)Y
+10 s
+1 f
+3749 4499(bucket)N
+3996(addresses)X
+4337(\(i.e.)X
+2706 4587(each)N
+2897(element)X
+3194(of)X
+3304(the)X
+3445(trie)X
+3594(is)X
+3689(a)X
+3767(bucket)X
+4023(address\).)X
+4373(To)X
+2706 4675(access)N
+2935(the)X
+3056(hash)X
+3226(table,)X
+3425(a)X
+3483(32-bit)X
+3696(hash)X
+3865(value)X
+4061(is)X
+4136(calculated)X
+2706 4763(and)N
+2 f
+2861(n)X
+1 f
+2953(bits)X
+3107(of)X
+3213(the)X
+3350(value)X
+3563(are)X
+3701(used)X
+3886(to)X
+3986(index)X
+4202(into)X
+4364(the)X
+2706 4851(directory)N
+3018(to)X
+3102(obtain)X
+3324(a)X
+3382(bucket)X
+3618(address.)X
+3921(It)X
+3992(is)X
+4067(important)X
+4400(to)X
+2706 4939(note)N
+2866(that)X
+3008(multiple)X
+3296(entries)X
+3532(of)X
+3620(this)X
+3756(directory)X
+4067(may)X
+4226(contain)X
+2706 5027(the)N
+2833(same)X
+3026(bucket)X
+3268(address)X
+3537(as)X
+3632(a)X
+3696(result)X
+3902(of)X
+3997(directory)X
+4315(dou-)X
+2706 5115(bling)N
+2903(during)X
+3145(bucket)X
+3392(splitting.)X
+3706(Figure)X
+3948(2)X
+4021(illustrates)X
+4364(the)X
+2706 5203(relationship)N
+3126(between)X
+3436(a)X
+3513(typical)X
+3772(\(skewed\))X
+4108(search)X
+4355(trie)X
+2706 5291(and)N
+2850(its)X
+2953(directory)X
+3271(representation.)X
+3774(The)X
+3927(formation)X
+4270(of)X
+4364(the)X
+2706 5379(directory)N
+3016(shown)X
+3245(in)X
+3327(the)X
+3445(\256gure)X
+3652(is)X
+3725(as)X
+3812(follows.)X
+16 s
+2706 5593 MXY
+864 0 Dl
+2 f
+8 s
+2746 5648(4)N
+1 f
+9 s
+2796 5673(It)N
+2858(does)X
+3008(not)X
+3118(contain)X
+3348(holes.)X
+3 f
+10 s
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4424(3)X
+
+4 p
+%%Page: 4 4
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+1 f
+604 538(Initially,)N
+937(there)X
+1158(is)X
+1271(one)X
+1446(slot)X
+1620(in)X
+1741(the)X
+1898(directory)X
+432 626(addressing)N
+802(a)X
+865(single)X
+1083(bucket.)X
+1364(The)X
+1515(depth)X
+1719(of)X
+1812(the)X
+1936(trie)X
+2069(is)X
+2148(0)X
+432 714(and)N
+577(0)X
+646(bits)X
+790(of)X
+886(each)X
+1063(hash)X
+1239(value)X
+1442(are)X
+1570(examined)X
+1910(to)X
+2000(deter-)X
+432 802(mine)N
+624(in)X
+718(which)X
+946(bucket)X
+1192(to)X
+1286(place)X
+1488(a)X
+1556(key;)X
+1726(all)X
+1837(keys)X
+2015(go)X
+2126(in)X
+432 890(bucket)N
+682(0.)X
+797(When)X
+1024(this)X
+1174(bucket)X
+1423(is)X
+1511(full,)X
+1677(its)X
+1787(contents)X
+2089(are)X
+432 978(divided)N
+698(between)X
+992(L0)X
+1107(and)X
+1249(L1)X
+1363(as)X
+1455(was)X
+1605(done)X
+1786(in)X
+1873(the)X
+1996(previ-)X
+432 1066(ously)N
+664(discussed)X
+1030(algorithms.)X
+1471(After)X
+1700(this)X
+1874(split,)X
+2090(the)X
+432 1154(address)N
+710(of)X
+814(the)X
+948(second)X
+1207(bucket)X
+1457(must)X
+1648(be)X
+1760(stored)X
+1992(in)X
+2090(the)X
+432 1242(directory.)N
+796(To)X
+939(accommodate)X
+1438(the)X
+1589(new)X
+1776(address,)X
+2090(the)X
+432 1330(directory)N
+752(is)X
+835(split)X
+2 f
+8 s
+972 1305(5)N
+1 f
+10 s
+1330(,)Y
+1054(by)X
+1163(doubling)X
+1476(it,)X
+1569(thus)X
+1731(increasing)X
+2090(the)X
+432 1418(depth)N
+630(of)X
+717(the)X
+835(directory)X
+1145(by)X
+1245(one.)X
+604 1532(After)N
+813(this)X
+967(split,)X
+1163(a)X
+1237(single)X
+1466(bit)X
+1588(of)X
+1693(the)X
+1829(hash)X
+2014(value)X
+432 1620(needs)N
+663(to)X
+773(be)X
+896(examined)X
+1255(to)X
+1364(decide)X
+1621(whether)X
+1927(the)X
+2072(key)X
+432 1708(belongs)N
+711(to)X
+803(L0)X
+922(or)X
+1019(L1.)X
+1158(Once)X
+1358(one)X
+1504(of)X
+1601(these)X
+1795(buckets)X
+2069(\256lls)X
+432 1796(\(L0)N
+578(for)X
+702(example\),)X
+1051(it)X
+1125(is)X
+1208(split)X
+1375(as)X
+1472(before,)X
+1728(and)X
+1873(the)X
+2000(direc-)X
+432 1884(tory)N
+585(is)X
+662(split)X
+823(again)X
+1021(to)X
+1107(make)X
+1305(room)X
+1498(for)X
+1615(the)X
+1736(address)X
+2000(of)X
+2090(the)X
+432 1972(third)N
+618(bucket.)X
+927(This)X
+1104(splitting)X
+1400(causes)X
+1645(the)X
+1778(addresses)X
+2121(of)X
+432 2060(the)N
+567(non-splitting)X
+1012(bucket)X
+1263(\(L1\))X
+1443(to)X
+1541(be)X
+1653(duplicated.)X
+2063(The)X
+432 2148(directory)N
+766(now)X
+948(has)X
+1099(four)X
+1277(entries,)X
+1555(a)X
+1635(depth)X
+1857(of)X
+1968(2,)X
+2072(and)X
+432 2236(indexes)N
+700(the)X
+821(buckets)X
+1089(L00,)X
+1261(L01)X
+1413(and)X
+1552(L1,)X
+1684(as)X
+1774(shown)X
+2006(in)X
+2090(the)X
+432 2324(Figure)N
+661(2.)X
+604 2438(The)N
+756(crucial)X
+1002(part)X
+1154(of)X
+1247(the)X
+1371(algorithm)X
+1708(is)X
+1787(the)X
+1911(observa-)X
+432 2526(tion)N
+580(that)X
+724(L1)X
+837(is)X
+914(addressed)X
+1255(twice)X
+1453(in)X
+1539(the)X
+1661(directory.)X
+1995(If)X
+2073(this)X
+432 2614(bucket)N
+679(were)X
+869(to)X
+964(split)X
+1134(now,)X
+1324(the)X
+1454(directory)X
+1776(already)X
+2045(con-)X
+432 2702(tains)N
+611(room)X
+808(to)X
+898(hold)X
+1067(the)X
+1192(address)X
+1460(of)X
+1554(the)X
+1679(new)X
+1840(bucket.)X
+2121(In)X
+432 2790(general,)N
+711(the)X
+831(relationship)X
+1231(between)X
+1521(the)X
+1641(directory)X
+1953(and)X
+2090(the)X
+432 2878(number)N
+704(of)X
+798(bucket)X
+1039(addresses)X
+1374(contained)X
+1713(therein)X
+1962(is)X
+2041(used)X
+432 2966(to)N
+517(decide)X
+750(when)X
+947(to)X
+1031(split)X
+1190(the)X
+1310(directory.)X
+1662(Each)X
+1845(bucket)X
+2081(has)X
+432 3054(a)N
+505(depth,)X
+740(\()X
+2 f
+767(n)X
+7 s
+3070(b)Y
+10 s
+1 f
+848 3054(\),)N
+932(associated)X
+1299(with)X
+1478(it)X
+1558(and)X
+1710(appears)X
+1992(in)X
+2090(the)X
+432 3142(directory)N
+744(exactly)X
+998(2)X
+2 f
+7 s
+3106(n)Y
+9 f
+1075(-)X
+2 f
+1106(n)X
+4 s
+3110(b)Y
+7 s
+1 f
+10 s
+1181 3142(times.)N
+1396(When)X
+1610(a)X
+1668(bucket)X
+1904(splits,)X
+2113(its)X
+432 3230(depth)N
+638(increases)X
+961(by)X
+1069(one.)X
+1253(The)X
+1406(directory)X
+1724(must)X
+1907(split)X
+2072(any)X
+432 3318(time)N
+602(a)X
+665(bucket's)X
+964(depth)X
+1169(exceeds)X
+1451(the)X
+1576(depth)X
+1781(of)X
+1875(the)X
+2000(direc-)X
+432 3406(tory.)N
+630(The)X
+784(following)X
+1123(code)X
+1303(fragment)X
+1621(helps)X
+1818(to)X
+1908(illustrate)X
+432 3494(the)N
+554(extendible)X
+912(hashing)X
+1185(algorithm)X
+1520([FAG79])X
+1838(for)X
+1955(access-)X
+432 3582(ing)N
+554(individual)X
+898(buckets)X
+1163(and)X
+1299(maintaining)X
+1701(the)X
+1819(directory.)X
+0 f
+8 s
+432 3881(hash)N
+622(=)X
+698 -0.4038(calchash\(key\);)AX
+432 3969(mask)N
+622(=)X
+698 -0.4018(maskvec[depth];)AX
+432 4145(bucket)N
+698(=)X
+774 -0.4038(directory[hash)AX
+1344(&)X
+1420(mask];)X
+432 4321(/*)N
+546(Key)X
+698 -0.4219(Insertion)AX
+1078(*/)X
+432 4409(if)N
+546 -0.4038(\(store\(bucket,)AX
+1116(key,)X
+1306(data\))X
+1534(==)X
+1648(FAIL\))X
+1876({)X
+720 4497(newbl)N
+948(=)X
+1024 -0.4167(getpage\(\);)AX
+720 4585 -0.4000(bucket->depth++;)AN
+720 4673 -0.4091(newbl->depth)AN
+1214(=)X
+1290 -0.4038(bucket->depth;)AX
+720 4761(if)N
+834 -0.4038(\(bucket->depth)AX
+1404(>)X
+1480(depth\))X
+1746({)X
+1008 4849(/*)N
+1122(double)X
+1388 -0.4219(directory)AX
+1768(*/)X
+1008 4937(depth++;)N
+1 f
+16 s
+432 5033 MXY
+864 0 Dl
+2 f
+8 s
+472 5088(5)N
+1 f
+9 s
+534 5113(This)N
+692(decision)X
+962(to)X
+1048(split)X
+1202(the)X
+1319(directory)X
+1608(is)X
+1685(based)X
+1878(on)X
+1979(a)X
+2040(com-)X
+432 5193(parison)N
+666(of)X
+748(the)X
+858(depth)X
+1040(of)X
+1121(the)X
+1230(page)X
+1387(being)X
+1568(split)X
+1713(and)X
+1838(the)X
+1947(depth)X
+2128(of)X
+432 5273(the)N
+543(trie.)X
+698(In)X
+781(Figure)X
+992(2,)X
+1069(the)X
+1180(depths)X
+1390(of)X
+1472(both)X
+1622(L00)X
+1760(and)X
+1886(L01)X
+2024(are)X
+2134(2,)X
+432 5353(whereas)N
+689(the)X
+798(depth)X
+979(of)X
+1060(L1)X
+1161(is)X
+1230(1.)X
+1323(Therefore,)X
+1646(if)X
+1710(L1)X
+1810(were)X
+1970(to)X
+2046(split,)X
+432 5433(the)N
+543(directory)X
+826(would)X
+1029(not)X
+1144(need)X
+1303(to)X
+1382(split.)X
+1565(In)X
+1648(reality,)X
+1872(a)X
+1926(bucket)X
+2140(is)X
+432 5513(allocated)N
+727(for)X
+846(the)X
+969(directory)X
+1264(at)X
+1351(the)X
+1474(time)X
+1637(of)X
+1732(\256le)X
+1858(creation)X
+2124(so)X
+432 5593(although)N
+707(the)X
+818(directory)X
+1100(splits)X
+1274(logically,)X
+1566(physical)X
+1828(splits)X
+2002(do)X
+2096(not)X
+432 5673(occur)N
+610(until)X
+760(the)X
+866(\256le)X
+976(becomes)X
+1246(quite)X
+1408(large.)X
+0 f
+8 s
+2994 538 -0.4219(directory)AN
+3374(=)X
+3450 -0.3971(double\(directory\);)AX
+2706 626(})N
+2706 714 -0.3958(splitbucket\(bucket,)AN
+3466(newbl\))X
+2706 802(...)N
+2418 890(})N
+2 f
+10 s
+3169 1255(hsearch)N
+1 f
+2590 1387(Since)N
+2 f
+2807(hsearch)X
+1 f
+3100(does)X
+3286(not)X
+3427(have)X
+3617(to)X
+3717(translate)X
+4027(hash)X
+2418 1475(values)N
+2659(into)X
+2819(disk)X
+2988(addresses,)X
+3352(it)X
+3432(can)X
+3579(use)X
+3721(much)X
+3934(simpler)X
+2418 1563(algorithms)N
+2808(than)X
+2994(those)X
+3211(de\256ned)X
+3495(above.)X
+3775(System)X
+4058(V's)X
+2 f
+2418 1651(hsearch)N
+1 f
+2708(constructs)X
+3069(a)X
+3141(\256xed-size)X
+3489(hash)X
+3671(table)X
+3862(\(speci\256ed)X
+2418 1739(by)N
+2519(the)X
+2637(user)X
+2791(at)X
+2869(table)X
+3045(creation\).)X
+3391(By)X
+3504(default,)X
+3767(a)X
+3823(multiplica-)X
+2418 1827(tive)N
+2570(hash)X
+2748(function)X
+3046(based)X
+3260(on)X
+3371(that)X
+3522(described)X
+3861(in)X
+3954(Knuth,)X
+2418 1915(Volume)N
+2710(3,)X
+2804(section)X
+3065(6.4)X
+3199([KNU68])X
+3541(is)X
+3628(used)X
+3809(to)X
+3905(obtain)X
+4138(a)X
+2418 2003(primary)N
+2694(bucket)X
+2930(address.)X
+3233(If)X
+3309(this)X
+3446(bucket)X
+3681(is)X
+3755(full,)X
+3907(a)X
+3964(secon-)X
+2418 2091(dary)N
+2593(multiplicative)X
+3069(hash)X
+3248(value)X
+3454(is)X
+3538(computed)X
+3885(to)X
+3978(de\256ne)X
+2418 2179(the)N
+2542(probe)X
+2751(interval.)X
+3062(The)X
+3213(probe)X
+3422(interval)X
+3693(is)X
+3772(added)X
+3989(to)X
+4076(the)X
+2418 2267(original)N
+2712(bucket)X
+2971(address)X
+3257(\(modulo)X
+3573(the)X
+3716(table)X
+3916(size\))X
+4112(to)X
+2418 2355(obtain)N
+2658(a)X
+2734(new)X
+2908(bucket)X
+3162(address.)X
+3483(This)X
+3665(process)X
+3946(repeats)X
+2418 2443(until)N
+2588(an)X
+2688(empty)X
+2911(bucket)X
+3148(is)X
+3224(found.)X
+3474(If)X
+3551(no)X
+3654(bucket)X
+3891(is)X
+3967(found,)X
+2418 2531(an)N
+2514(insertion)X
+2814(fails)X
+2972(with)X
+3134(a)X
+3190(``table)X
+3420(full'')X
+3605(condition.)X
+2590 2645(The)N
+2768(basic)X
+2986(algorithm)X
+3350(may)X
+3541(be)X
+3670(modi\256ed)X
+4006(by)X
+4138(a)X
+2418 2733(number)N
+2705(of)X
+2813(compile)X
+3112(time)X
+3295(options)X
+3571(available)X
+3902(to)X
+4005(those)X
+2418 2821(users)N
+2604(with)X
+2767(AT&T)X
+3006(source)X
+3237(code.)X
+3450(First,)X
+3637(the)X
+3756(package)X
+4040(pro-)X
+2418 2909(vides)N
+2638(two)X
+2809(options)X
+3094(for)X
+3238(hash)X
+3435(functions.)X
+3803(Users)X
+4036(may)X
+2418 2997(specify)N
+2690(their)X
+2877(own)X
+3055(hash)X
+3242(function)X
+3549(by)X
+3669(compiling)X
+4032(with)X
+2418 3085(``USCR'')N
+2757(de\256ned)X
+3016(and)X
+3155(declaring)X
+3477(and)X
+3616(de\256ning)X
+3901(the)X
+4022(vari-)X
+2418 3173(able)N
+2 f
+2578(hcompar)X
+1 f
+2863(,)X
+2909(a)X
+2971(function)X
+3263(taking)X
+3488(two)X
+3633(string)X
+3840(arguments)X
+2418 3261(and)N
+2560(returning)X
+2880(an)X
+2982(integer.)X
+3271(Users)X
+3480(may)X
+3643(also)X
+3797(request)X
+4054(that)X
+2418 3349(hash)N
+2587(values)X
+2814(be)X
+2912(computed)X
+3250(simply)X
+3489(by)X
+3590(taking)X
+3811(the)X
+3930(modulo)X
+2418 3437(of)N
+2521(key)X
+2673(\(using)X
+2909(division)X
+3201(rather)X
+3424(than)X
+3597(multiplication)X
+4080(for)X
+2418 3525(hash)N
+2589(value)X
+2787(calculation\).)X
+3230(If)X
+3308(this)X
+3447(technique)X
+3783(is)X
+3859(used,)X
+4049(col-)X
+2418 3613(lisions)N
+2651(are)X
+2775(resolved)X
+3072(by)X
+3176(scanning)X
+3485(sequentially)X
+3896(from)X
+4076(the)X
+2418 3701(selected)N
+2702(bucket)X
+2941(\(linear)X
+3176(probing\).)X
+3517(This)X
+3684(option)X
+3913(is)X
+3991(avail-)X
+2418 3789(able)N
+2572(by)X
+2672(de\256ning)X
+2954(the)X
+3072(variable)X
+3351(``DIV'')X
+3622(at)X
+3700(compile)X
+3978(time.)X
+2590 3903(A)N
+2720(second)X
+3015(option,)X
+3311(based)X
+3565(on)X
+3716(an)X
+3863(algorithm)X
+2418 3991(discovered)N
+2787(by)X
+2888(Richard)X
+3163(P.)X
+3248(Brent,)X
+3466(rearranges)X
+3822(the)X
+3940(table)X
+4116(at)X
+2418 4079(the)N
+2549(time)X
+2724(of)X
+2824(insertion)X
+3137(in)X
+3232(order)X
+3434(to)X
+3528(speed)X
+3743(up)X
+3855(retrievals.)X
+2418 4167(The)N
+2571(basic)X
+2764(idea)X
+2926(is)X
+3007(to)X
+3097(shorten)X
+3361(long)X
+3531(probe)X
+3741(sequences)X
+4094(by)X
+2418 4255(lengthening)N
+2833(short)X
+3030(probe)X
+3249(sequences.)X
+3651(Once)X
+3857(the)X
+3991(probe)X
+2418 4343(chain)N
+2613(has)X
+2741(exceeded)X
+3062(some)X
+3252(threshold)X
+3571(\(Brent)X
+3796(suggests)X
+4087(2\),)X
+2418 4431(we)N
+2541(attempt)X
+2809(to)X
+2899(shuf\257e)X
+3145(any)X
+3289(colliding)X
+3601(keys)X
+3776(\(keys)X
+3978(which)X
+2418 4519(appeared)N
+2734(in)X
+2821(the)X
+2944(probe)X
+3152(sequence)X
+3471(of)X
+3562(the)X
+3684(new)X
+3842(key\).)X
+4049(The)X
+2418 4607(details)N
+2652(of)X
+2744(this)X
+2884(key)X
+3025(shuf\257ing)X
+3333(can)X
+3469(be)X
+3569(found)X
+3780(in)X
+3866([KNU68])X
+2418 4695(and)N
+2576([BRE73].)X
+2946(This)X
+3129(algorithm)X
+3481(may)X
+3660(be)X
+3777(obtained)X
+4094(by)X
+2418 4783(de\256ning)N
+2700(the)X
+2818(variable)X
+3097(``BRENT'')X
+3487(at)X
+3565(compile)X
+3843(time.)X
+2590 4897(A)N
+2698(third)X
+2899(set)X
+3038(of)X
+3154(options,)X
+3458(obtained)X
+3783(by)X
+3912(de\256ning)X
+2418 4985(``CHAINED'',)N
+2943(use)X
+3086(linked)X
+3321(lists)X
+3484(to)X
+3581(resolve)X
+3848(collisions.)X
+2418 5073(Either)N
+2647(of)X
+2747(the)X
+2878(primary)X
+3164(hash)X
+3343(function)X
+3642(described)X
+3982(above)X
+2418 5161(may)N
+2584(be)X
+2688(used,)X
+2882(but)X
+3011(all)X
+3118(collisions)X
+3451(are)X
+3577(resolved)X
+3876(by)X
+3983(build-)X
+2418 5249(ing)N
+2554(a)X
+2623(linked)X
+2856(list)X
+2986(of)X
+3086(entries)X
+3333(from)X
+3522(the)X
+3653(primary)X
+3940(bucket.)X
+2418 5337(By)N
+2542(default,)X
+2816(new)X
+2981(entries)X
+3226(will)X
+3381(be)X
+3488(added)X
+3711(to)X
+3804(a)X
+3871(bucket)X
+4116(at)X
+2418 5425(the)N
+2541(beginning)X
+2886(of)X
+2978(the)X
+3101(bucket)X
+3339(chain.)X
+3577(However,)X
+3916(compile)X
+2418 5513(options)N
+2706(``SORTUP'')X
+3173(or)X
+3293(``SORTDOWN'')X
+3908(may)X
+4098(be)X
+2418 5601(speci\256ed)N
+2723(to)X
+2805(order)X
+2995(the)X
+3113(hash)X
+3280(chains)X
+3505(within)X
+3729(each)X
+3897(bucket.)X
+3 f
+432 5960(4)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+5 p
+%%Page: 5 5
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+2 f
+1444 538(dynahash)N
+1 f
+892 670(The)N
+2 f
+1054(dynahash)X
+1 f
+1398(library,)X
+1669(written)X
+1932(by)X
+2048(Esmond)X
+2346(Pitt,)X
+720 758(implements)N
+1183(Larson's)X
+1554(linear)X
+1827(hashing)X
+2165(algorithm)X
+720 846([LAR88])N
+1097(with)X
+1302(an)X
+2 f
+1440(hsearch)X
+1 f
+1756(compatible)X
+2174(interface.)X
+720 934(Intuitively,)N
+1099(a)X
+1161(hash)X
+1334(table)X
+1516(begins)X
+1751(as)X
+1844(a)X
+1905(single)X
+2121(bucket)X
+2360(and)X
+720 1022(grows)N
+941(in)X
+1028(generations,)X
+1443(where)X
+1665(a)X
+1725(generation)X
+2088(corresponds)X
+720 1110(to)N
+815(a)X
+884(doubling)X
+1201(in)X
+1296(the)X
+1427(size)X
+1585(of)X
+1685(the)X
+1815(hash)X
+1994(table.)X
+2222(The)X
+2379(0)X
+2 f
+7 s
+1078(th)Y
+10 s
+1 f
+720 1198(generation)N
+1085(occurs)X
+1321(as)X
+1414(the)X
+1538(table)X
+1719(grows)X
+1940(from)X
+2121(one)X
+2262(bucket)X
+720 1286(to)N
+814(two.)X
+1006(In)X
+1105(the)X
+1235(next)X
+1405(generation)X
+1776(the)X
+1906(table)X
+2093(grows)X
+2320(from)X
+720 1374(two)N
+862(to)X
+946(four.)X
+1122(During)X
+1371(each)X
+1541(generation,)X
+1921(every)X
+2121(bucket)X
+2356(that)X
+720 1462(existed)N
+967(at)X
+1045(the)X
+1163(beginning)X
+1503(of)X
+1590(the)X
+1708(generation)X
+2067(is)X
+2140(split.)X
+892 1576(The)N
+1041(table)X
+1221(starts)X
+1414(as)X
+1505(a)X
+1565(single)X
+1780(bucket)X
+2018(\(numbered)X
+2389(0\),)X
+720 1664(the)N
+839(current)X
+1088(split)X
+1245(bucket)X
+1479(is)X
+1552(set)X
+1661(to)X
+1743(bucket)X
+1977(0,)X
+2057(and)X
+2193(the)X
+2311(max-)X
+720 1752(imum)N
+933(split)X
+1097(point)X
+1288(is)X
+1368(set)X
+1483(to)X
+1571(twice)X
+1771(the)X
+1895(current)X
+2149(split)X
+2312(point)X
+720 1840(\(0\).)N
+863(When)X
+1084(it)X
+1157(is)X
+1239(time)X
+1410(for)X
+1532(a)X
+1596(bucket)X
+1838(to)X
+1928(split,)X
+2113(the)X
+2239(keys)X
+2414(in)X
+720 1928(the)N
+872(current)X
+1154(split)X
+1345(bucket)X
+1612(are)X
+1764(divided)X
+2057(between)X
+2378(the)X
+720 2016(current)N
+981(split)X
+1151(bucket)X
+1397(and)X
+1545(a)X
+1613(new)X
+1779(bucket)X
+2025(whose)X
+2262(bucket)X
+720 2104(number)N
+1000(is)X
+1088(equal)X
+1297(to)X
+1394(1)X
+1469(+)X
+1549(current)X
+1812(split)X
+1984(bucket)X
+2232(+)X
+2311(max-)X
+720 2192(imum)N
+927(split)X
+1085(point.)X
+1310(We)X
+1442(can)X
+1574(determine)X
+1915(which)X
+2131(keys)X
+2298(move)X
+720 2280(to)N
+807(the)X
+929(new)X
+1087(bucket)X
+1325(by)X
+1429(examining)X
+1791(the)X
+2 f
+1913(n)X
+7 s
+1962 2248(th)N
+10 s
+1 f
+2043 2280(bit)N
+2151(of)X
+2242(a)X
+2302(key's)X
+720 2368(hash)N
+899(value)X
+1105(where)X
+1334(n)X
+1406(is)X
+1491(the)X
+1620(generation)X
+1990(number.)X
+2306(After)X
+720 2456(the)N
+846(bucket)X
+1088(at)X
+1174(the)X
+1300(maximum)X
+1651(split)X
+1815(point)X
+2006(has)X
+2140(been)X
+2319(split,)X
+720 2544(the)N
+839(generation)X
+1198(number)X
+1463(is)X
+1536(incremented,)X
+1973(the)X
+2091(current)X
+2339(split)X
+720 2632(point)N
+908(is)X
+985(set)X
+1098(back)X
+1274(to)X
+1360(zero,)X
+1543(and)X
+1683(the)X
+1805(maximum)X
+2152(split)X
+2312(point)X
+720 2720(is)N
+815(set)X
+946(to)X
+1050(the)X
+1190(number)X
+1477(of)X
+1586(the)X
+1725(last)X
+1877(bucket)X
+2132(in)X
+2235(the)X
+2374(\256le)X
+720 2808(\(which)N
+971(is)X
+1052(equal)X
+1253(to)X
+1342(twice)X
+1543(the)X
+1668(old)X
+1797(maximum)X
+2148(split)X
+2312(point)X
+720 2896(plus)N
+873(1\).)X
+892 3010(To)N
+1031(facilitate)X
+1361(locating)X
+1668(keys,)X
+1884(we)X
+2027(maintain)X
+2356(two)X
+720 3098(masks.)N
+989(The)X
+1143(low)X
+1291(mask)X
+1488(is)X
+1569(equal)X
+1771(to)X
+1861(the)X
+1987(maximum)X
+2339(split)X
+720 3186(bucket)N
+967(and)X
+1116(the)X
+1247(high)X
+1422(mask)X
+1624(is)X
+1710(equal)X
+1917(to)X
+2011(the)X
+2141(next)X
+2311(max-)X
+720 3274(imum)N
+931(split)X
+1093(bucket.)X
+1372(To)X
+1486(locate)X
+1703(a)X
+1764(speci\256c)X
+2033(key,)X
+2193(we)X
+2311(com-)X
+720 3362(pute)N
+881(a)X
+940(32-bit)X
+1154(hash)X
+1324(value)X
+1520(using)X
+1715(a)X
+1773(bit-randomizing)X
+2311(algo-)X
+720 3450(rithm)N
+932(such)X
+1118(as)X
+1224(the)X
+1361(one)X
+1516(described)X
+1862(in)X
+1962([LAR88].)X
+2334(This)X
+720 3538(hash)N
+893(value)X
+1093(is)X
+1172(then)X
+1336(masked)X
+1607(with)X
+1775(the)X
+1898(high)X
+2065(mask.)X
+2299(If)X
+2378(the)X
+720 3626(resulting)N
+1026(number)X
+1297(is)X
+1376(greater)X
+1626(than)X
+1790(the)X
+1913(maximum)X
+2262(bucket)X
+720 3714(in)N
+823(the)X
+962(table)X
+1159(\(current)X
+1455(split)X
+1633(bucket)X
+1888(+)X
+1974(maximum)X
+2339(split)X
+720 3802(point\),)N
+962(the)X
+1091(hash)X
+1269(value)X
+1474(is)X
+1558(masked)X
+1834(with)X
+2007(the)X
+2136(low)X
+2287(mask.)X
+720 3890(In)N
+825(either)X
+1046(case,)X
+1242(the)X
+1377(result)X
+1592(of)X
+1696(the)X
+1831(mask)X
+2037(is)X
+2127(the)X
+2262(bucket)X
+720 3978(number)N
+989(for)X
+1107(the)X
+1229(given)X
+1431(key.)X
+1611(The)X
+1759(algorithm)X
+2093(below)X
+2312(illus-)X
+720 4066(trates)N
+914(this)X
+1049(process.)X
+0 f
+8 s
+720 4365(h)N
+796(=)X
+872 -0.4038(calchash\(key\);)AX
+720 4453(bucket)N
+986(=)X
+1062(h)X
+1138(&)X
+1214 -0.4167(high_mask;)AX
+720 4541(if)N
+834(\()X
+910(bucket)X
+1176(>)X
+1252 -0.4167(max_bucket)AX
+1670(\))X
+1008 4629(bucket)N
+1274(=)X
+1350(h)X
+1426(&)X
+1502 -0.4219(low_mask;)AX
+720 4717 -0.4018(return\(bucket\);)AN
+1 f
+10 s
+892 5042(In)N
+1013(order)X
+1237(to)X
+1353(decide)X
+1617(when)X
+1845(to)X
+1961(split)X
+2152(a)X
+2242(bucket,)X
+2 f
+720 5130(dynahash)N
+1 f
+1050(uses)X
+2 f
+1210(controlled)X
+1561(splitting)X
+1 f
+1822(.)X
+1884(A)X
+1964(hash)X
+2133(table)X
+2311(has)X
+2440(a)X
+720 5218(\256ll)N
+837(factor)X
+1054(which)X
+1279(is)X
+1361(expressed)X
+1707(in)X
+1798(terms)X
+2004(of)X
+2099(the)X
+2225(average)X
+720 5306(number)N
+990(of)X
+1082(keys)X
+1253(in)X
+1339(each)X
+1511(bucket.)X
+1789(Each)X
+1974(time)X
+2140(the)X
+2262(table's)X
+720 5394(total)N
+885(number)X
+1153(of)X
+1243(keys)X
+1413(divided)X
+1676(by)X
+1778(its)X
+1875(number)X
+2142(of)X
+2231(buckets)X
+720 5482(exceeds)N
+995(this)X
+1130(\256ll)X
+1238(factor,)X
+1466(a)X
+1522(bucket)X
+1756(is)X
+1829(split.)X
+2878 538(Since)N
+3079(the)X
+2 f
+3200(hsearch)X
+1 f
+3477(create)X
+3693(interface)X
+3998(\()X
+2 f
+4025(hcreate)X
+1 f
+4266(\))X
+4315(calls)X
+2706 626(for)N
+2842(an)X
+2960(estimate)X
+3269(of)X
+3378(the)X
+3518(\256nal)X
+3702(size)X
+3869(of)X
+3978(the)X
+4118(hash)X
+4306(table)X
+2706 714(\()N
+2 f
+2733(nelem)X
+1 f
+2925(\),)X
+2 f
+3007(dynahash)X
+1 f
+3349(uses)X
+3522(this)X
+3672(information)X
+4085(to)X
+4182(initialize)X
+2706 802(the)N
+2848(table.)X
+3088(The)X
+3257(initial)X
+3486(number)X
+3774(of)X
+3884(buckets)X
+4172(is)X
+4268(set)X
+4400(to)X
+2 f
+2706 890(nelem)N
+1 f
+2926(rounded)X
+3217(to)X
+3306(the)X
+3431(next)X
+3596(higher)X
+3828(power)X
+4056(of)X
+4150(two.)X
+4337(The)X
+2706 978(current)N
+2958(split)X
+3118(point)X
+3305(is)X
+3381(set)X
+3493(to)X
+3578(0)X
+3641(and)X
+3780(the)X
+3901(maximum)X
+4248(bucket)X
+2706 1066(and)N
+2842(maximum)X
+3186(split)X
+3343(point)X
+3527(are)X
+3646(set)X
+3755(to)X
+3837(this)X
+3972(rounded)X
+4255(value.)X
+3 f
+3148 1220(The)N
+3301(New)X
+3473(Implementation)X
+1 f
+2878 1352(Our)N
+3042(implementation)X
+3583(is)X
+3675(also)X
+3842(based)X
+4063(on)X
+4181(Larson's)X
+2706 1440(linear)N
+2939(hashing)X
+3238([LAR88])X
+3582(algorithm)X
+3943(as)X
+4060(well)X
+4248(as)X
+4364(the)X
+2 f
+2706 1528(dynahash)N
+1 f
+3047(implementation.)X
+3623(The)X
+2 f
+3782(dbm)X
+1 f
+3954(family)X
+4197(of)X
+4297(algo-)X
+2706 1616(rithms)N
+2942(decide)X
+3184(dynamically)X
+3612(which)X
+3840(bucket)X
+4085(to)X
+4178(split)X
+4346(and)X
+2706 1704(when)N
+2914(to)X
+3010(split)X
+3180(it)X
+3257(\(when)X
+3491(it)X
+3568(over\257ows\))X
+3944(while)X
+2 f
+4155(dynahash)X
+1 f
+2706 1792(splits)N
+2933(in)X
+3054(a)X
+3149(prede\256ned)X
+3547(order)X
+3776(\(linearly\))X
+4134(and)X
+4309(at)X
+4426(a)X
+2706 1880(prede\256ned)N
+3116(time)X
+3328(\(when)X
+3599(the)X
+3767(table)X
+3993(\256ll)X
+4151(factor)X
+4409(is)X
+2706 1968(exceeded\).)N
+3121(We)X
+3280(use)X
+3434(a)X
+3517(hybrid)X
+3773(of)X
+3887(these)X
+4099(techniques.)X
+2706 2056(Splits)N
+2913(occur)X
+3118(in)X
+3206(the)X
+3330(prede\256ned)X
+3695(order)X
+3891(of)X
+3984(linear)X
+4193(hashing,)X
+2706 2144(but)N
+2845(the)X
+2980(time)X
+3159(at)X
+3253(which)X
+3485(pages)X
+3704(are)X
+3839(split)X
+4012(is)X
+4101(determined)X
+2706 2232(both)N
+2869(by)X
+2970(page)X
+3143(over\257ows)X
+3480(\()X
+2 f
+3507(uncontrolled)X
+3937(splitting)X
+1 f
+4198(\))X
+4246(and)X
+4382(by)X
+2706 2320(exceeding)N
+3052(the)X
+3170(\256ll)X
+3278(factor)X
+3486(\()X
+2 f
+3513(controlled)X
+3862(splitting)X
+1 f
+4123(\))X
+2878 2434(A)N
+2962(hash)X
+3135(table)X
+3317(is)X
+3395(parameterized)X
+3876(by)X
+3981(both)X
+4148(its)X
+4248(bucket)X
+2706 2522(size)N
+2904(\()X
+2 f
+2931(bsize)X
+1 f
+(\))S
+3191(and)X
+3380(\256ll)X
+3541(factor)X
+3801(\()X
+2 f
+3828(ffactor)X
+1 f
+4041(\).)X
+4180(Whereas)X
+2 f
+2706 2610(dynahash's)N
+1 f
+3095(buckets)X
+3364(can)X
+3500(be)X
+3599(represented)X
+3993(as)X
+4083(a)X
+4142(linked)X
+4365(list)X
+2706 2698(of)N
+2798(elements)X
+3108(in)X
+3195(memory,)X
+3507(our)X
+3639(package)X
+3928(needs)X
+4136(to)X
+4222(support)X
+2706 2786(disk)N
+2874(access,)X
+3135(and)X
+3286(must)X
+3476(represent)X
+3806(buckets)X
+4086(in)X
+4183(terms)X
+4395(of)X
+2706 2874(pages.)N
+2955(The)X
+2 f
+3106(bsize)X
+1 f
+3291(is)X
+3369(the)X
+3492(size)X
+3642(\(in)X
+3756(bytes\))X
+3977(of)X
+4069(these)X
+4259(pages.)X
+2706 2962(As)N
+2833(in)X
+2933(linear)X
+3154(hashing,)X
+3461(the)X
+3597(number)X
+3879(of)X
+3983(buckets)X
+4265(in)X
+4364(the)X
+2706 3050(table)N
+2906(is)X
+3003(equal)X
+3221(to)X
+3327(the)X
+3469(number)X
+3758(of)X
+3869(keys)X
+4060(in)X
+4165(the)X
+4306(table)X
+2706 3138(divided)N
+2988(by)X
+2 f
+3110(ffactor)X
+1 f
+3323(.)X
+2 f
+8 s
+3113(6)Y
+1 f
+10 s
+3417 3138(The)N
+3584(controlled)X
+3950(splitting)X
+4252(occurs)X
+2706 3226(each)N
+2878(time)X
+3044(the)X
+3166(number)X
+3435(of)X
+3526(keys)X
+3697(in)X
+3783(the)X
+3905(table)X
+4085(exceeds)X
+4364(the)X
+2706 3314(\256ll)N
+2814(factor)X
+3022(multiplied)X
+3370(by)X
+3470(the)X
+3588(number)X
+3853(of)X
+3940(buckets.)X
+2878 3428(Inserting)N
+3187(keys)X
+3358(and)X
+3498(splitting)X
+3783(buckets)X
+4051(is)X
+4127(performed)X
+2706 3516(precisely)N
+3018(as)X
+3107(described)X
+3437(previously)X
+3796(for)X
+2 f
+3911(dynahash)X
+1 f
+4218(.)X
+4279(How-)X
+2706 3604(ever,)N
+2897(since)X
+3094(buckets)X
+3371(are)X
+3502(now)X
+3671(comprised)X
+4036(of)X
+4134(pages,)X
+4368(we)X
+2706 3692(must)N
+2883(be)X
+2981(prepared)X
+3284(to)X
+3367(handle)X
+3602(cases)X
+3793(where)X
+4011(the)X
+4130(size)X
+4276(of)X
+4364(the)X
+2706 3780(keys)N
+2873(and)X
+3009(data)X
+3163(in)X
+3245(a)X
+3301(bucket)X
+3535(exceed)X
+3779(the)X
+3897(bucket)X
+4131(size.)X
+3 f
+3318 3934(Over\257ow)N
+3654(Pages)X
+1 f
+2878 4066(There)N
+3095(are)X
+3223(two)X
+3372(cases)X
+3571(where)X
+3797(a)X
+3862(key)X
+4007(may)X
+4174(not)X
+4305(\256t)X
+4400(in)X
+2706 4154(its)N
+2802(designated)X
+3166(bucket.)X
+3441(In)X
+3529(the)X
+3647(\256rst)X
+3791(case,)X
+3970(the)X
+4088(total)X
+4250(size)X
+4395(of)X
+2706 4242(the)N
+2833(key)X
+2978(and)X
+3123(data)X
+3286(may)X
+3453(exceed)X
+3706(the)X
+3833(bucket)X
+4076(size.)X
+4269(In)X
+4364(the)X
+2706 4330(second,)N
+3008(addition)X
+3328(of)X
+3453(a)X
+3547(new)X
+3739(key)X
+3913(could)X
+4149(cause)X
+4386(an)X
+2706 4418(over\257ow,)N
+3068(but)X
+3227(the)X
+3382(bucket)X
+3652(in)X
+3770(question)X
+4097(is)X
+4206(not)X
+4364(yet)X
+2706 4506(scheduled)N
+3049(to)X
+3133(be)X
+3230(split.)X
+3428(In)X
+3516(existing)X
+3790(implementations,)X
+4364(the)X
+2706 4594(second)N
+2953(case)X
+3115(never)X
+3317(arises)X
+3523(\(since)X
+3738(buckets)X
+4006(are)X
+4128(split)X
+4288(when)X
+2706 4682(they)N
+2871(over\257ow\))X
+3210(and)X
+3352(the)X
+3476(\256rst)X
+3626(case)X
+3791(is)X
+3870(not)X
+3998(handled)X
+4278(at)X
+4362(all.)X
+2706 4770(Although)N
+3036(large)X
+3225(key/data)X
+3525(pair)X
+3678(handling)X
+3986(is)X
+4066(dif\256cult)X
+4346(and)X
+2706 4858(expensive,)N
+3083(it)X
+3163(is)X
+3252(essential.)X
+3604(In)X
+3706(a)X
+3777(linear)X
+3995(hashed)X
+4253(imple-)X
+2706 4946(mentation,)N
+3087(over\257ow)X
+3413(pages)X
+3636(are)X
+3775(required)X
+4083(for)X
+4217(buckets)X
+2706 5034(which)N
+2935(over\257ow)X
+3253(before)X
+3492(they)X
+3662(are)X
+3793(split,)X
+3982(so)X
+4085(we)X
+4211(can)X
+4355(use)X
+2706 5122(the)N
+2833(same)X
+3027(mechanism)X
+3421(for)X
+3544(large)X
+3734(key/data)X
+4035(pairs)X
+4220(that)X
+4368(we)X
+2706 5210(use)N
+2837(for)X
+2955(over\257ow)X
+3264(pages.)X
+3511(Logically,)X
+3862(we)X
+3980(chain)X
+4177(over\257ow)X
+16 s
+2706 5353 MXY
+864 0 Dl
+2 f
+8 s
+2746 5408(6)N
+1 f
+9 s
+2801 5433(This)N
+2952(is)X
+3023(not)X
+3138(strictly)X
+3361(true.)X
+3532(The)X
+3667(\256le)X
+3782(does)X
+3937(not)X
+4052(contract)X
+4306(when)X
+2706 5513(keys)N
+2861(are)X
+2972(deleted,)X
+3221(so)X
+3308(the)X
+3419(number)X
+3662(of)X
+3744(buckets)X
+3986(is)X
+4056(actually)X
+4306(equal)X
+2706 5593(to)N
+2782(the)X
+2890(maximum)X
+3202(number)X
+3441(of)X
+3520(keys)X
+3671(ever)X
+3814(present)X
+4041(in)X
+4116(the)X
+4223(table)X
+4382(di-)X
+2706 5673(vided)N
+2884(by)X
+2974(the)X
+3080(\256ll)X
+3178(factor.)X
+3 f
+10 s
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4424(5)X
+
+6 p
+%%Page: 6 6
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+1 f
+432 538(pages)N
+639(to)X
+725(the)X
+847(buckets)X
+1116(\(also)X
+1296(called)X
+1512(primary)X
+1789(pages\).)X
+2062(In)X
+2152(a)X
+432 626(memory)N
+730(based)X
+943(representation,)X
+1448(over\257ow)X
+1763(pages)X
+1976(do)X
+2086(not)X
+432 714(pose)N
+628(any)X
+792(special)X
+1063(problems)X
+1409(because)X
+1712(we)X
+1854(can)X
+2014(chain)X
+432 802(over\257ow)N
+776(pages)X
+1017(to)X
+1137(primary)X
+1449(pages)X
+1690(using)X
+1921(memory)X
+432 890(pointers.)N
+776(However,)X
+1137(mapping)X
+1463(these)X
+1674(over\257ow)X
+2005(pages)X
+432 978(into)N
+584(a)X
+648(disk)X
+809(\256le)X
+939(is)X
+1019(more)X
+1211(of)X
+1305(a)X
+1368(challenge,)X
+1723(since)X
+1915(we)X
+2036(need)X
+432 1066(to)N
+547(be)X
+675(able)X
+861(to)X
+975(address)X
+1268(both)X
+1462(bucket)X
+1728(pages,)X
+1983(whose)X
+432 1154(numbers)N
+729(are)X
+849(growing)X
+1137(linearly,)X
+1422(and)X
+1558(some)X
+1747(indeterminate)X
+432 1242(number)N
+715(of)X
+820(over\257ow)X
+1143(pages)X
+1364(without)X
+1646(reorganizing)X
+2090(the)X
+432 1330(\256le.)N
+604 1444(One)N
+789(simple)X
+1053(solution)X
+1361(would)X
+1612(be)X
+1739(to)X
+1852(allocate)X
+2152(a)X
+432 1532(separate)N
+737(\256le)X
+880(for)X
+1015(over\257ow)X
+1341(pages.)X
+1604(The)X
+1769(disadvantage)X
+432 1620(with)N
+605(such)X
+783(a)X
+850(technique)X
+1193(is)X
+1276(that)X
+1426(it)X
+1500(requires)X
+1789(an)X
+1895(extra)X
+2086(\256le)X
+432 1708(descriptor,)N
+794(an)X
+891(extra)X
+1073(system)X
+1316(call)X
+1453(on)X
+1554(open)X
+1731(and)X
+1867(close,)X
+2072(and)X
+432 1796(logically)N
+739(associating)X
+1122(two)X
+1269(independent)X
+1687(\256les.)X
+1886(For)X
+2023(these)X
+432 1884(reasons,)N
+728(we)X
+857(wanted)X
+1123(to)X
+1219(map)X
+1391(both)X
+1567(primary)X
+1855(pages)X
+2072(and)X
+432 1972(over\257ow)N
+737(pages)X
+940(into)X
+1084(the)X
+1202(same)X
+1387(\256le)X
+1509(space.)X
+604 2086(The)N
+799(buddy-in-waiting)X
+1425(algorithm)X
+1806(provides)X
+2152(a)X
+432 2174(mechanism)N
+851(to)X
+966(support)X
+1259(multiple)X
+1578(pages)X
+1814(per)X
+1970(logical)X
+432 2262(bucket)N
+685(while)X
+902(retaining)X
+1226(the)X
+1362(simple)X
+1613(split)X
+1788(sequence)X
+2121(of)X
+432 2350(linear)N
+681(hashing.)X
+1015(Over\257ow)X
+1383(pages)X
+1631(are)X
+1795(preallocated)X
+432 2438(between)N
+781(generations)X
+1232(of)X
+1379(primary)X
+1713(pages.)X
+1996(These)X
+432 2526(over\257ow)N
+759(pages)X
+984(are)X
+1125(used)X
+1314(by)X
+1436(any)X
+1594(bucket)X
+1850(containing)X
+432 2614(more)N
+646(keys)X
+842(than)X
+1029(\256t)X
+1144(on)X
+1273(the)X
+1420(primary)X
+1723(page)X
+1924(and)X
+2089(are)X
+432 2702(reclaimed,)N
+808(if)X
+896(possible,)X
+1217(when)X
+1430(the)X
+1567(bucket)X
+1819(later)X
+2000(splits.)X
+432 2790(Figure)N
+687(3)X
+773(depicts)X
+1045(the)X
+1188(layout)X
+1433(of)X
+1545(primary)X
+1844(pages)X
+2072(and)X
+432 2878(over\257ow)N
+752(pages)X
+970(within)X
+1209(the)X
+1342(same)X
+1542(\256le.)X
+1699(Over\257ow)X
+2036(page)X
+432 2966(use)N
+586(information)X
+1011(is)X
+1111(recorded)X
+1440(in)X
+1548(bitmaps)X
+1847(which)X
+2089(are)X
+432 3054(themselves)N
+819(stored)X
+1046(on)X
+1157(over\257ow)X
+1472(pages.)X
+1725(The)X
+1880(addresses)X
+432 3142(of)N
+520(the)X
+639(bitmap)X
+882(pages)X
+1086(and)X
+1223(the)X
+1342(number)X
+1608(of)X
+1695(pages)X
+1898(allocated)X
+432 3230(at)N
+515(each)X
+688(split)X
+850(point)X
+1039(are)X
+1163(stored)X
+1384(in)X
+1470(the)X
+1592(\256le)X
+1718(header.)X
+1997(Using)X
+432 3318(this)N
+577(information,)X
+1005(both)X
+1177(over\257ow)X
+1492(addresses)X
+1829(and)X
+1974(bucket)X
+432 3406(addresses)N
+764(can)X
+900(be)X
+999(mapped)X
+1276(to)X
+1361(disk)X
+1517(addresses)X
+1848(by)X
+1951(the)X
+2072(fol-)X
+432 3494(lowing)N
+674(calculation:)X
+0 f
+8 s
+432 3793(int)N
+736(bucket;)X
+1192(/*)X
+1306(bucket)X
+1572(address)X
+1876(*/)X
+432 3881(u_short)N
+736(oaddr;)X
+1192(/*)X
+1306(OVERFLOW)X
+1648(address)X
+1952(*/)X
+432 3969(int)N
+736 -0.4125(nhdr_pages;)AX
+1192(/*)X
+1306(npages)X
+1572(in)X
+1686 -112.4062(\256le)AX
+1838(header)X
+2104(*/)X
+432 4057(int)N
+736 -0.4125(spares[32];)AX
+1192(/*)X
+1306(npages)X
+1572(at)X
+1686(each)X
+1876(split)X
+2104(*/)X
+432 4145(int)N
+736(log2\(\);)X
+1198(/*)X
+1312(ceil\(log)X
+1654(base)X
+1844(2\))X
+1958(*/)X
+432 4321(#DEFINE)N
+736 -0.3929(BUCKET_TO_PAGE\(bucket\))AX
+1610(\\)X
+584 4409(bucket)N
+850(+)X
+926 -0.4167(nhdr_pages)AX
+1344(+)X
+1420(\\)X
+584 4497 -0.3894(\(bucket?spares[logs2\(bucket)AN
+1648(+)X
+1724(1\)-1]:0\))X
+432 4673(#DEFINE)N
+736 -0.3947(OADDR_TO_PAGE\(oaddr\))AX
+1534(\\)X
+584 4761 -0.3984(BUCKET_TO_PAGE\(\(1)AN
+1268(<<)X
+1382 -0.4091(\(oaddr>>11\)\))AX
+1876(-)X
+1952(1\))X
+2066(+)X
+2142(\\)X
+584 4849(oaddr)N
+812(&)X
+888(0x7ff;)X
+1 f
+10 s
+604 5262(An)N
+728(over\257ow)X
+1039(page)X
+1217(is)X
+1295(addressed)X
+1637(by)X
+1742(its)X
+1842(split)X
+2004(point,)X
+432 5350(identifying)N
+858(the)X
+1031(generations)X
+1476(between)X
+1819(which)X
+2090(the)X
+432 5438(over\257ow)N
+740(page)X
+915(is)X
+991(allocated,)X
+1324(and)X
+1463(its)X
+1561(page)X
+1736(number,)X
+2023(iden-)X
+432 5526(tifying)N
+665(the)X
+783(particular)X
+1111(page)X
+1283(within)X
+1507(the)X
+1625(split)X
+1782(point.)X
+1986(In)X
+2073(this)X
+432 5614(implementation,)N
+983(offsets)X
+1225(within)X
+1457(pages)X
+1668(are)X
+1795(16)X
+1903(bits)X
+2046(long)X
+432 5702(\(limiting)N
+732(the)X
+851(maximum)X
+1196(page)X
+1368(size)X
+1513(to)X
+1595(32K\),)X
+1800(so)X
+1891(we)X
+2005(select)X
+2418 538(an)N
+2535(over\257ow)X
+2860(page)X
+3052(addressing)X
+3435(algorithm)X
+3786(that)X
+3946(can)X
+4098(be)X
+2418 626(expressed)N
+2760(in)X
+2847(16)X
+2952(bits)X
+3091(and)X
+3231(which)X
+3451(allows)X
+3684(quick)X
+3886(retrieval.)X
+2418 714(The)N
+2568(top)X
+2695(\256ve)X
+2840(bits)X
+2980(indicate)X
+3258(the)X
+3380(split)X
+3541(point)X
+3729(and)X
+3869(the)X
+3991(lower)X
+2418 802(eleven)N
+2650(indicate)X
+2926(the)X
+3046(page)X
+3220(number)X
+3487(within)X
+3713(the)X
+3832(split)X
+3990(point.)X
+2418 890(Since)N
+2633(\256ve)X
+2789(bits)X
+2940(are)X
+3075(reserved)X
+3384(for)X
+3514(the)X
+3648(split)X
+3821(point,)X
+4041(\256les)X
+2418 978(may)N
+2578(split)X
+2737(32)X
+2839(times)X
+3034(yielding)X
+3318(a)X
+3376(maximum)X
+3721(\256le)X
+3844(size)X
+3990(of)X
+4078(2)X
+7 s
+946(32)Y
+10 s
+2418 1066(buckets)N
+2698(and)X
+2849(32)X
+2 f
+(*)S
+1 f
+2982(2)X
+7 s
+1034(11)Y
+10 s
+3113 1066(over\257ow)N
+3433(pages.)X
+3691(The)X
+3850(maximum)X
+2418 1154(page)N
+2597(size)X
+2749(is)X
+2829(2)X
+7 s
+1122(15)Y
+10 s
+1154(,)Y
+2971(yielding)X
+3259(a)X
+3321(maximum)X
+3671(\256le)X
+3799(size)X
+3950(greater)X
+2418 1242(than)N
+2601(131,000)X
+2906(GB)X
+3061(\(on)X
+3212(\256le)X
+3358(systems)X
+3655(supporting)X
+4041(\256les)X
+2418 1330(larger)N
+2626(than)X
+2784(4GB\).)X
+10 f
+2418 1418 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 Dt
+4014 2275 MXY
+0 133 Dl
+3881 2275 MXY
+0 133 Dl
+3748 2275 MXY
+0 133 Dl
+3083 2275 MXY
+0 133 Dl
+5 s
+1 f
+3523 2475(2/3)N
+3390(2/2)X
+3257(2/1)X
+2859(1/2)X
+2726(1/1)X
+5 Dt
+3814 1743 MXY
+0 133 Dl
+3282 1743 MXY
+0 133 Dl
+3017 1743 MXY
+0 133 Dl
+2884 1743 MXY
+0 133 Dl
+1 Dt
+3681 1743 MXY
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3548 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3415 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3282 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3150 MX
+0 133 Dl
+132 0 Dl
+0 -133 Dl
+-132 0 Dl
+3017 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+2884 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3 f
+8 s
+3017 2601(Over\257ow)N
+3285(Addresses)X
+3515 2833(Over\257ow)N
+3783(Pages)X
+2850(Buckets)X
+1 Di
+3349 2740 MXY
+ 3349 2740 lineto
+ 3482 2740 lineto
+ 3482 2873 lineto
+ 3349 2873 lineto
+ 3349 2740 lineto
+closepath 3 3349 2740 3482 2873 Dp
+2684 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+5 Dt
+4146 2275 MXY
+0 133 Dl
+3216 2275 MXY
+0 133 Dl
+2684 2275 MXY
+0 133 Dl
+2551 2275 MXY
+0 133 Dl
+1 f
+3798 1963(3)N
+3266 1980(2)N
+3001(1)X
+2868(0)X
+1 Dt
+2751 1743 MXY
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3548 2275 MXY
+-15 -22 Dl
+2 16 Dl
+-13 11 Dl
+26 -5 Dl
+-282 -117 Dl
+3432 2275 MXY
+-10 -25 Dl
+-2 16 Dl
+-15 8 Dl
+27 1 Dl
+-166 -117 Dl
+3282 2275 MXY
+12 -25 Dl
+-14 10 Dl
+-15 -6 Dl
+17 21 Dl
+-16 -117 Dl
+2884 2275 MXY
+26 7 Dl
+-12 -12 Dl
+3 -16 Dl
+-17 21 Dl
+382 -117 Dl
+2751 2275 MXY
+25 9 Dl
+-11 -12 Dl
+5 -17 Dl
+-19 20 Dl
+515 -117 Dl
+3 f
+3070 2152(Over\257ow)N
+3338(Pages)X
+3482 2275 MXY
+ 3482 2275 lineto
+ 3615 2275 lineto
+ 3615 2408 lineto
+ 3482 2408 lineto
+ 3482 2275 lineto
+closepath 3 3482 2275 3615 2408 Dp
+3349 MX
+ 3349 2275 lineto
+ 3482 2275 lineto
+ 3482 2408 lineto
+ 3349 2408 lineto
+ 3349 2275 lineto
+closepath 3 3349 2275 3482 2408 Dp
+3216 MX
+ 3216 2275 lineto
+ 3349 2275 lineto
+ 3349 2408 lineto
+ 3216 2408 lineto
+ 3216 2275 lineto
+closepath 3 3216 2275 3349 2408 Dp
+2817 MX
+ 2817 2275 lineto
+ 2950 2275 lineto
+ 2950 2408 lineto
+ 2817 2408 lineto
+ 2817 2275 lineto
+closepath 3 2817 2275 2950 2408 Dp
+2684 MX
+ 2684 2275 lineto
+ 2817 2275 lineto
+ 2817 2408 lineto
+ 2684 2408 lineto
+ 2684 2275 lineto
+closepath 3 2684 2275 2817 2408 Dp
+3615 MX
+0 133 Dl
+531 0 Dl
+0 -133 Dl
+-531 0 Dl
+2950 MX
+0 133 Dl
+266 0 Dl
+0 -133 Dl
+-266 0 Dl
+2551 MX
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3798 1726 MXY
+-21 -18 Dl
+6 16 Dl
+-10 13 Dl
+25 -11 Dl
+-599 -99 Dl
+3266 1726 MXY
+-1 -27 Dl
+-7 15 Dl
+-17 1 Dl
+25 11 Dl
+-67 -99 Dl
+3033 1726 MXY
+27 1 Dl
+-14 -8 Dl
+-1 -17 Dl
+-12 24 Dl
+166 -99 Dl
+2900 1726 MXY
+27 7 Dl
+-13 -11 Dl
+3 -17 Dl
+-17 21 Dl
+299 -99 Dl
+3058 1621(Split)N
+3203(Points)X
+2418 2275 MXY
+0 133 Dl
+133 0 Dl
+0 -133 Dl
+-133 0 Dl
+3 Dt
+-1 Ds
+3137(Figure)Y
+2619(3:)X
+1 f
+2691(Split)X
+2832(points)X
+3008(occur)X
+3168(between)X
+3399(generations)X
+3712(and)X
+3823(are)X
+3919(numbered)X
+2418 3225(from)N
+2560(0.)X
+2642(In)X
+2713(this)X
+2824(\256gure)X
+2991(there)X
+3136(are)X
+3231(two)X
+3345(over\257ow)X
+3590(pages)X
+3753(allocated)X
+4000(at)X
+4063(split)X
+2418 3313(point)N
+2566(1)X
+2614(and)X
+2722(three)X
+2865(allocated)X
+3111(at)X
+3173(split)X
+3300(point)X
+3448(2.)X
+10 s
+10 f
+2418 3489 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+2949 3731(Buffer)N
+3192(Management)X
+1 f
+2590 3863(The)N
+2744(hash)X
+2920(table)X
+3105(is)X
+3187(stored)X
+3412(in)X
+3502(memory)X
+3797(as)X
+3892(a)X
+3956(logical)X
+2418 3951(array)N
+2633(of)X
+2749(bucket)X
+3012(pointers.)X
+3359(Physically,)X
+3761(the)X
+3907(array)X
+4121(is)X
+2418 4039(arranged)N
+2728(in)X
+2818(segments)X
+3144(of)X
+3239(256)X
+3387(pointers.)X
+3713(Initially,)X
+4013(there)X
+2418 4127(is)N
+2530(space)X
+2767(to)X
+2887(allocate)X
+3195(256)X
+3373(segments.)X
+3769(Reallocation)X
+2418 4215(occurs)N
+2651(when)X
+2847(the)X
+2967(number)X
+3234(of)X
+3323(buckets)X
+3590(exceeds)X
+3867(32K)X
+4027(\(256)X
+2418 4303(*)N
+2508(256\).)X
+2745(Primary)X
+3053(pages)X
+3286(may)X
+3473(be)X
+3598(accessed)X
+3929(directly)X
+2418 4391(through)N
+2711(the)X
+2853(array)X
+3062(by)X
+3185(bucket)X
+3442(number)X
+3730(and)X
+3889(over\257ow)X
+2418 4479(pages)N
+2628(are)X
+2754 0.4028(referenced)AX
+3122(logically)X
+3429(by)X
+3536(their)X
+3710(over\257ow)X
+4022(page)X
+2418 4567(address.)N
+2726(For)X
+2864(small)X
+3063(hash)X
+3236(tables,)X
+3469(it)X
+3539(is)X
+3618(desirable)X
+3934(to)X
+4022(keep)X
+2418 4655(all)N
+2525(pages)X
+2735(in)X
+2823(main)X
+3009(memory)X
+3302(while)X
+3506(on)X
+3612(larger)X
+3826(tables,)X
+4059(this)X
+2418 4743(is)N
+2523(probably)X
+2860(impossible.)X
+3298(To)X
+3438(satisfy)X
+3698(both)X
+3891(of)X
+4009(these)X
+2418 4831(requirements,)N
+2900(the)X
+3041(package)X
+3348(includes)X
+3658(buffer)X
+3897(manage-)X
+2418 4919(ment)N
+2598(with)X
+2760(LRU)X
+2940(\(least)X
+3134(recently)X
+3413(used\))X
+3607(replacement.)X
+2590 5033(By)N
+2730(default,)X
+3020(the)X
+3165(package)X
+3475(allocates)X
+3802(up)X
+3928(to)X
+4036(64K)X
+2418 5121(bytes)N
+2616(of)X
+2712(buffered)X
+3014(pages.)X
+3246(All)X
+3377(pages)X
+3589(in)X
+3680(the)X
+3807(buffer)X
+4032(pool)X
+2418 5209(are)N
+2542(linked)X
+2766(in)X
+2852(LRU)X
+3036(order)X
+3230(to)X
+3316(facilitate)X
+3621(fast)X
+3761(replacement.)X
+2418 5297(Whereas)N
+2724(ef\256cient)X
+3011(access)X
+3241(to)X
+3327(primary)X
+3605(pages)X
+3812(is)X
+3889(provided)X
+2418 5385(by)N
+2521(the)X
+2642(bucket)X
+2879(array,)X
+3087(ef\256cient)X
+3372(access)X
+3600(to)X
+3684(over\257ow)X
+3991(pages)X
+2418 5473(is)N
+2501(provided)X
+2816(by)X
+2926(linking)X
+3182(over\257ow)X
+3497(page)X
+3679(buffers)X
+3936(to)X
+4027(their)X
+2418 5561(predecessor)N
+2827(page)X
+3008(\(either)X
+3247(the)X
+3374(primary)X
+3657(page)X
+3838(or)X
+3933(another)X
+2418 5649(over\257ow)N
+2742(page\).)X
+3000(This)X
+3181(means)X
+3425(that)X
+3584(an)X
+3699(over\257ow)X
+4022(page)X
+3 f
+432 5960(6)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+7 p
+%%Page: 7 7
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+720 538(cannot)N
+955(be)X
+1052(present)X
+1305(in)X
+1388(the)X
+1507(buffer)X
+1724(pool)X
+1886(if)X
+1955(its)X
+2050(primary)X
+2324(page)X
+720 626(is)N
+804(not)X
+937(present.)X
+1240(This)X
+1413(does)X
+1591(not)X
+1724(impact)X
+1972(performance)X
+2409(or)X
+720 714(functionality,)N
+1209(because)X
+1524(an)X
+1660(over\257ow)X
+2005(page)X
+2217(will)X
+2400(be)X
+720 802(accessed)N
+1048(only)X
+1236(after)X
+1430(its)X
+1550(predecessor)X
+1975(page)X
+2172(has)X
+2324(been)X
+720 890(accessed.)N
+1068(Figure)X
+1303(4)X
+1369(depicts)X
+1622(the)X
+1746(data)X
+1905(structures)X
+2242(used)X
+2414(to)X
+720 978(manage)N
+990(the)X
+1108(buffer)X
+1325(pool.)X
+892 1092(The)N
+1040(in-memory)X
+1419(bucket)X
+1656(array)X
+1845(contains)X
+2134(pointers)X
+2414(to)X
+720 1180(buffer)N
+975(header)X
+1248(structures)X
+1617(which)X
+1870(represent)X
+2222(primary)X
+720 1268(pages.)N
+968(Buffer)X
+1203(headers)X
+1474(contain)X
+1735(modi\256ed)X
+2043(bits,)X
+2202(the)X
+2324(page)X
+720 1356(address)N
+995(of)X
+1096(the)X
+1228(buffer,)X
+1479(a)X
+1548(pointer)X
+1808(to)X
+1903(the)X
+2034(actual)X
+2259(buffer,)X
+720 1444(and)N
+875(a)X
+950(pointer)X
+1216(to)X
+1317(the)X
+1454(buffer)X
+1690(header)X
+1944(for)X
+2077(an)X
+2191(over\257ow)X
+720 1532(page)N
+901(if)X
+979(it)X
+1052(exists,)X
+1283(in)X
+1374(addition)X
+1665(to)X
+1756(the)X
+1883(LRU)X
+2072(links.)X
+2296(If)X
+2378(the)X
+720 1620(buffer)N
+950(corresponding)X
+1442(to)X
+1537(a)X
+1606(particular)X
+1947(bucket)X
+2194(is)X
+2280(not)X
+2414(in)X
+720 1708(memory,)N
+1048(its)X
+1164(pointer)X
+1432(is)X
+1526(NULL.)X
+1801(In)X
+1909(effect,)X
+2154(pages)X
+2377(are)X
+720 1796(linked)N
+950(in)X
+1042(three)X
+1233(ways.)X
+1468(Using)X
+1689(the)X
+1817(buffer)X
+2043(headers,)X
+2338(they)X
+720 1884(are)N
+851(linked)X
+1083(physically)X
+1444(through)X
+1725(the)X
+1854(LRU)X
+2045(links)X
+2231(and)X
+2378(the)X
+720 1972(over\257ow)N
+1036(links.)X
+1241(Using)X
+1462(the)X
+1590(pages)X
+1803(themselves,)X
+2209(they)X
+2377(are)X
+720 2060(linked)N
+943(logically)X
+1246(through)X
+1518(the)X
+1639(over\257ow)X
+1946(addresses)X
+2276(on)X
+2378(the)X
+720 2148(page.)N
+948(Since)X
+1162(over\257ow)X
+1482(pages)X
+1700(are)X
+1834(accessed)X
+2151(only)X
+2328(after)X
+720 2236(their)N
+904(predecessor)X
+1321(pages,)X
+1560(they)X
+1734(are)X
+1869(removed)X
+2186(from)X
+2378(the)X
+720 2324(buffer)N
+937(pool)X
+1099(when)X
+1293(their)X
+1460(primary)X
+1734(is)X
+1807(removed.)X
+10 f
+720 2412 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 Dt
+2309 3177 MXY
+24 15 Dl
+-8 -15 Dl
+8 -15 Dl
+-24 15 Dl
+52 0 Dl
+789 3160 MXY
+-35 0 Dl
+0 -156 Dl
+1607 0 Dl
+0 173 Dl
+789 3091 MXY
+-24 -15 Dl
+9 15 Dl
+-9 15 Dl
+24 -15 Dl
+-69 0 Dl
+2309 3125 MXY
+104 0 Dl
+0 -155 Dl
+-1693 0 Dl
+0 121 Dl
+927 3160 MXY
+24 15 Dl
+-9 -15 Dl
+9 -15 Dl
+-24 15 Dl
+553 0 Dl
+1618 3177 MXY
+8 27 Dl
+4 -17 Dl
+16 -6 Dl
+-28 -4 Dl
+138 121 Dl
+1895 3315 MXY
+28 3 Dl
+-15 -9 Dl
+1 -18 Dl
+-14 24 Dl
+276 -138 Dl
+3108 MY
+-28 -3 Dl
+15 10 Dl
+-1 17 Dl
+14 -24 Dl
+-276 138 Dl
+1756 3229 MXY
+-8 -27 Dl
+-3 17 Dl
+-16 6 Dl
+27 4 Dl
+-138 -121 Dl
+1480 MX
+-24 -15 Dl
+9 15 Dl
+-9 15 Dl
+24 -15 Dl
+-553 0 Dl
+3 f
+5 s
+1083 3073(LRU)N
+1178(chain)X
+4 Ds
+1402 3851 MXY
+ 1402 3851 lineto
+ 1471 3851 lineto
+ 1471 3920 lineto
+ 1402 3920 lineto
+ 1402 3851 lineto
+closepath 19 1402 3851 1471 3920 Dp
+1445 3747(Over\257ow)N
+1613(Address)X
+1549 3609 MXY
+0 69 Dl
+1756 MX
+-23 -15 Dl
+8 15 Dl
+-8 15 Dl
+23 -15 Dl
+-207 0 Dl
+-1 Ds
+3 Dt
+1756 3419 MXY
+-6 -28 Dl
+-4 17 Dl
+-17 5 Dl
+27 6 Dl
+-138 -138 Dl
+2240 3471 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+1826 3609 MXY
+15 -24 Dl
+-15 9 Dl
+-16 -9 Dl
+16 24 Dl
+0 -138 Dl
+1549 MX
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+858 3471 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+2240 3056 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+1549 3056 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+858 3056 MXY
+15 -24 Dl
+-15 9 Dl
+-15 -9 Dl
+15 24 Dl
+0 -138 Dl
+1 Dt
+2171 3471 MXY
+ 2171 3471 lineto
+ 2448 3471 lineto
+ 2448 3609 lineto
+ 2171 3609 lineto
+ 2171 3471 lineto
+closepath 19 2171 3471 2448 3609 Dp
+1756 3609 MXY
+ 1756 3609 lineto
+ 2033 3609 lineto
+ 2033 3747 lineto
+ 1756 3747 lineto
+ 1756 3609 lineto
+closepath 3 1756 3609 2033 3747 Dp
+1480 3471 MXY
+ 1480 3471 lineto
+ 1756 3471 lineto
+ 1756 3609 lineto
+ 1480 3609 lineto
+ 1480 3471 lineto
+closepath 19 1480 3471 1756 3609 Dp
+789 MX
+ 789 3471 lineto
+ 1065 3471 lineto
+ 1065 3609 lineto
+ 789 3609 lineto
+ 789 3471 lineto
+closepath 19 789 3471 1065 3609 Dp
+962 3903(Buffer)N
+1083(Header)X
+849 3851 MXY
+ 849 3851 lineto
+ 918 3851 lineto
+ 918 3920 lineto
+ 849 3920 lineto
+ 849 3851 lineto
+closepath 14 849 3851 918 3920 Dp
+1756 3194 MXY
+ 1756 3194 lineto
+ 1895 3194 lineto
+ 1895 3471 lineto
+ 1756 3471 lineto
+ 1756 3194 lineto
+closepath 14 1756 3194 1895 3471 Dp
+2171 3056 MXY
+ 2171 3056 lineto
+ 2309 3056 lineto
+ 2309 3333 lineto
+ 2171 3333 lineto
+ 2171 3056 lineto
+closepath 14 2171 3056 2309 3333 Dp
+1480 MX
+ 1480 3056 lineto
+ 1618 3056 lineto
+ 1618 3333 lineto
+ 1480 3333 lineto
+ 1480 3056 lineto
+closepath 14 1480 3056 1618 3333 Dp
+789 MX
+ 789 3056 lineto
+ 927 3056 lineto
+ 927 3333 lineto
+ 789 3333 lineto
+ 789 3056 lineto
+closepath 14 789 3056 927 3333 Dp
+2780 MY
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+927 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1065 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1203 MX
+0 138 Dl
+139 0 Dl
+0 -138 Dl
+-139 0 Dl
+1342 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1480 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1618 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+1756 MX
+0 138 Dl
+139 0 Dl
+0 -138 Dl
+-139 0 Dl
+1895 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+2033 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+2171 MX
+0 138 Dl
+138 0 Dl
+0 -138 Dl
+-138 0 Dl
+2309 MX
+0 138 Dl
+139 0 Dl
+0 -138 Dl
+-139 0 Dl
+13 s
+1048 2720(In)N
+1173(Memory)X
+1580(Bucket)X
+1918(Array)X
+867 3584(B0)N
+1558(B5)X
+2223(B10)X
+1788 3722(O1/1)N
+5 s
+1515 3903(Primay)N
+1651(Buffer)X
+4 Ds
+1990 3851 MXY
+ 1990 3851 lineto
+ 2059 3851 lineto
+ 2059 3920 lineto
+ 1990 3920 lineto
+ 1990 3851 lineto
+closepath 3 1990 3851 2059 3920 Dp
+2102 3903(Over\257ow)N
+2270(Buffer)X
+3 Dt
+-1 Ds
+8 s
+720 4184(Figure)N
+922(4:)X
+1 f
+996(Three)X
+1164(primary)X
+1386(pages)X
+1551(\(B0,)X
+1683(B5,)X
+1794(B10\))X
+1942(are)X
+2039(accessed)X
+2281(directly)X
+720 4272(from)N
+862(the)X
+958(bucket)X
+1146(array.)X
+1326(The)X
+1443(one)X
+1553(over\257ow)X
+1798(page)X
+1935(\(O1/1\))X
+2122(is)X
+2182(linked)X
+2359(phy-)X
+720 4360(sically)N
+915(from)X
+1067(its)X
+1155(primary)X
+1384(page's)X
+1577(buffer)X
+1759(header)X
+1955(as)X
+2035(well)X
+2172(as)X
+2252(logically)X
+720 4448(from)N
+860(its)X
+937(predecessor)X
+1253(page)X
+1389(buffer)X
+1560(\(B5\).)X
+10 s
+10 f
+720 4624 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+1191 4954(Table)N
+1406(Parameterization)X
+1 f
+892 5086(When)N
+1107(a)X
+1166(hash)X
+1336(table)X
+1515(is)X
+1590(created,)X
+1865(the)X
+1985(bucket)X
+2221(size,)X
+2388(\256ll)X
+720 5174(factor,)N
+953(initial)X
+1164(number)X
+1434(of)X
+1526(elements,)X
+1856(number)X
+2125(of)X
+2216(bytes)X
+2409(of)X
+720 5262(main)N
+919(memory)X
+1225(used)X
+1411(for)X
+1543(caching,)X
+1851(and)X
+2005(a)X
+2079(user-de\256ned)X
+720 5350(hash)N
+892(function)X
+1184(may)X
+1347(be)X
+1448(speci\256ed.)X
+1797(The)X
+1946(bucket)X
+2184(size)X
+2333(\(and)X
+720 5438(page)N
+906(size)X
+1064(for)X
+1191(over\257ow)X
+1509(pages\))X
+1752(defaults)X
+2039(to)X
+2134(256)X
+2287(bytes.)X
+720 5526(For)N
+858(tables)X
+1072(with)X
+1241(large)X
+1429(data)X
+1590(items,)X
+1810(it)X
+1881(may)X
+2046(be)X
+2149(preferable)X
+720 5614(to)N
+803(increase)X
+1088(the)X
+1207(page)X
+1380(size,)X
+1545(and,)X
+1701(conversely,)X
+2089(applications)X
+720 5702(storing)N
+1002(small)X
+1235(items)X
+1467(exclusively)X
+1891(in)X
+2012(memory)X
+2338(may)X
+2706 538(bene\256t)N
+2966(from)X
+3164(a)X
+3242(smaller)X
+3520(bucket)X
+3776(size.)X
+3983(A)X
+4082(bucket)X
+4337(size)X
+2706 626(smaller)N
+2962(than)X
+3120(64)X
+3220(bytes)X
+3409(is)X
+3482(not)X
+3604(recommended.)X
+2878 740(The)N
+3031(\256ll)X
+3147(factor)X
+3363(indicates)X
+3676(a)X
+3740(desired)X
+4000(density)X
+4258(within)X
+2706 828(the)N
+2833(hash)X
+3009(table.)X
+3234(It)X
+3312(is)X
+3394(an)X
+3499(approximation)X
+3995(of)X
+4091(the)X
+4217(number)X
+2706 916(of)N
+2815(keys)X
+3004(allowed)X
+3300(to)X
+3404(accumulate)X
+3811(in)X
+3914(any)X
+4071(one)X
+4228(bucket,)X
+2706 1004(determining)N
+3119(when)X
+3319(the)X
+3442(hash)X
+3614(table)X
+3795(grows.)X
+4056(Its)X
+4161(default)X
+4409(is)X
+2706 1092(eight.)N
+2953(If)X
+3054(the)X
+3199(user)X
+3380(knows)X
+3636(the)X
+3781(average)X
+4079(size)X
+4251(of)X
+4364(the)X
+2706 1180(key/data)N
+3008(pairs)X
+3194(being)X
+3402(stored)X
+3627(in)X
+3718(the)X
+3845(table,)X
+4050(near)X
+4218(optimal)X
+2706 1268(bucket)N
+2943(sizes)X
+3122(and)X
+3261(\256ll)X
+3372(factors)X
+3614(may)X
+3775(be)X
+3874(selected)X
+4155(by)X
+4257(apply-)X
+2706 1356(ing)N
+2828(the)X
+2946(equation:)X
+0 f
+8 s
+2706 1655(\(1\))N
+2994 -0.3938(\(\(average_pair_length)AX
+3830(+)X
+3906(4\))X
+4020(*)X
+3032 1743(ffactor\))N
+3374(>=)X
+3488(bsize)X
+1 f
+10 s
+2706 2042(For)N
+2859(highly)X
+3104(time)X
+3287(critical)X
+3551(applications,)X
+3999(experimenting)X
+2706 2130(with)N
+2919(different)X
+3266(bucket)X
+3550(sizes)X
+3776(and)X
+3962(\256ll)X
+4120(factors)X
+4409(is)X
+2706 2218(encouraged.)N
+2878 2332(Figures)N
+3144(5a,b,)X
+3326(and)X
+3468(c)X
+3530(illustrate)X
+3836(the)X
+3960(effects)X
+4200(of)X
+4292(vary-)X
+2706 2420(ing)N
+2841(page)X
+3026(sizes)X
+3215(and)X
+3363(\256ll)X
+3483(factors)X
+3734(for)X
+3860(the)X
+3990(same)X
+4187(data)X
+4353(set.)X
+2706 2508(The)N
+2864(data)X
+3031(set)X
+3152(consisted)X
+3482(of)X
+3581(24474)X
+3813(keys)X
+3992(taken)X
+4198(from)X
+4386(an)X
+2706 2596(online)N
+2931(dictionary.)X
+3301(The)X
+3451(data)X
+3609(value)X
+3807(for)X
+3925(each)X
+4097(key)X
+4237(was)X
+4386(an)X
+2706 2684(ASCII)N
+2938(string)X
+3143(for)X
+3260(an)X
+3359(integer)X
+3605(from)X
+3784(1)X
+3847(to)X
+3931(24474)X
+4153(inclusive.)X
+2706 2772(The)N
+2867(test)X
+3013(run)X
+3155(consisted)X
+3488(of)X
+3590(creating)X
+3884(a)X
+3955(new)X
+4124(hash)X
+4306(table)X
+2706 2860(\(where)N
+2966(the)X
+3100(ultimate)X
+3398(size)X
+3559(of)X
+3662(the)X
+3796(table)X
+3987(was)X
+4147(known)X
+4400(in)X
+2706 2948(advance\),)N
+3054(entering)X
+3354(each)X
+3539(key/data)X
+3848(pair)X
+4010(into)X
+4171(the)X
+4306(table)X
+2706 3036(and)N
+2849(then)X
+3014(retrieving)X
+3353(each)X
+3528(key/data)X
+3827(pair)X
+3979(from)X
+4162(the)X
+4286(table.)X
+2706 3124(Each)N
+2898(of)X
+2996(the)X
+3125(graphs)X
+3369(shows)X
+3599(the)X
+3727(timings)X
+3996(resulting)X
+4306(from)X
+2706 3212(varying)N
+2973(the)X
+3093(pagesize)X
+3392(from)X
+3570(128)X
+3712(bytes)X
+3903(to)X
+3986(1M)X
+4118(and)X
+4255(the)X
+4374(\256ll)X
+2706 3300(factor)N
+2929(from)X
+3120(1)X
+3195(to)X
+3292(128.)X
+3486(For)X
+3631(each)X
+3813(run,)X
+3974(the)X
+4106(buffer)X
+4337(size)X
+2706 3388(was)N
+2874(set)X
+3006(at)X
+3106(1M.)X
+3299(The)X
+3466(tests)X
+3650(were)X
+3849(all)X
+3971(run)X
+4120(on)X
+4242(an)X
+4360(HP)X
+2706 3476(9000/370)N
+3077(\(33.3)X
+3312(Mhz)X
+3527(MC68030\),)X
+3966(with)X
+4176(16M)X
+4395(of)X
+2706 3564(memory,)N
+3042(64K)X
+3228(physically)X
+3605(addressed)X
+3970(cache,)X
+4222(and)X
+4386(an)X
+2706 3652(HP7959S)N
+3055(disk)X
+3231(drive,)X
+3459(running)X
+3751(4.3BSD-Reno)X
+4244(single-)X
+2706 3740(user.)N
+2878 3854(Both)N
+3066(system)X
+3321(time)X
+3496(\(Figure)X
+3764(5a\))X
+3899(and)X
+4047(elapsed)X
+4320(time)X
+2706 3942(\(Figure)N
+2966(5b\))X
+3097(show)X
+3290(that)X
+3434(for)X
+3552(all)X
+3655(bucket)X
+3892(sizes,)X
+4091(the)X
+4212(greatest)X
+2706 4030(performance)N
+3137(gains)X
+3329(are)X
+3451(made)X
+3648(by)X
+3751(increasing)X
+4104(the)X
+4225(\256ll)X
+4336(fac-)X
+2706 4118(tor)N
+2822(until)X
+2995(equation)X
+3298(1)X
+3365(is)X
+3445(satis\256ed.)X
+3774(The)X
+3925(user)X
+4085(time)X
+4253(shown)X
+2706 4206(in)N
+2791(Figure)X
+3023(5c)X
+3122(gives)X
+3314(a)X
+3373(more)X
+3561(detailed)X
+3838(picture)X
+4083(of)X
+4172(how)X
+4332(per-)X
+2706 4294(formance)N
+3054(varies.)X
+3330(The)X
+3499(smaller)X
+3778(bucket)X
+4035(sizes)X
+4234(require)X
+2706 4382(fewer)N
+2921(keys)X
+3099(per)X
+3233(page)X
+3416(to)X
+3509(satisfy)X
+3749(equation)X
+4056(1)X
+4127(and)X
+4274(there-)X
+2706 4470(fore)N
+2860(incur)X
+3049(fewer)X
+3257(collisions.)X
+3607(However,)X
+3946(when)X
+4144(the)X
+4265(buffer)X
+2706 4558(pool)N
+2884(size)X
+3045(is)X
+3134(\256xed,)X
+3349(smaller)X
+3620(pages)X
+3838(imply)X
+4059(more)X
+4259(pages.)X
+2706 4646(An)N
+2830(increased)X
+3160(number)X
+3430(of)X
+3522(pages)X
+3730(means)X
+3960(more)X
+2 f
+4150(malloc\(3\))X
+1 f
+2706 4734(calls)N
+2879(and)X
+3021(more)X
+3212(overhead)X
+3533(in)X
+3621(the)X
+3745(hash)X
+3918(package's)X
+4265(buffer)X
+2706 4822(manager)N
+3003(to)X
+3085(manage)X
+3355(the)X
+3473(additional)X
+3813(pages.)X
+2878 4936(The)N
+3028(tradeoff)X
+3308(works)X
+3529(out)X
+3655(most)X
+3834(favorably)X
+4166(when)X
+4364(the)X
+2706 5024(page)N
+2886(size)X
+3039(is)X
+3120(256)X
+3268(and)X
+3412(the)X
+3538(\256ll)X
+3654(factor)X
+3870(is)X
+3950(8.)X
+4057(Similar)X
+4319(con-)X
+2706 5112(clusions)N
+3009(were)X
+3207(obtained)X
+3524(if)X
+3614(the)X
+3753(test)X
+3905(was)X
+4071(run)X
+4218(without)X
+2706 5200(knowing)N
+3007(the)X
+3126(\256nal)X
+3289(table)X
+3466(size)X
+3612(in)X
+3695(advance.)X
+4020(If)X
+4095(the)X
+4214(\256le)X
+4337(was)X
+2706 5288(closed)N
+2942(and)X
+3088(written)X
+3345(to)X
+3437(disk,)X
+3620(the)X
+3748(conclusions)X
+4156(were)X
+4343(still)X
+2706 5376(the)N
+2832(same.)X
+3065(However,)X
+3408(rereading)X
+3740(the)X
+3865(\256le)X
+3994(from)X
+4177(disk)X
+4337(was)X
+2706 5464(slightly)N
+2983(faster)X
+3199(if)X
+3285(a)X
+3358(larger)X
+3583(bucket)X
+3834(size)X
+3996(and)X
+4149(\256ll)X
+4274(factor)X
+2706 5552(were)N
+2898(used)X
+3079(\(1K)X
+3238(bucket)X
+3486(size)X
+3645(and)X
+3795(32)X
+3909(\256ll)X
+4031(factor\).)X
+4320(This)X
+2706 5640(follows)N
+2987(intuitively)X
+3356(from)X
+3553(the)X
+3691(improved)X
+4038(ef\256ciency)X
+4395(of)X
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4424(7)X
+
+8 p
+%%Page: 8 8
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+1 f
+432 538(performing)N
+830(1K)X
+965(reads)X
+1172(from)X
+1365(the)X
+1500(disk)X
+1670(rather)X
+1894(than)X
+2068(256)X
+432 626(byte)N
+609(reads.)X
+857(In)X
+962(general,)X
+1257(performance)X
+1702(for)X
+1834(disk)X
+2005(based)X
+432 714(tables)N
+639(is)X
+712(best)X
+861(when)X
+1055(the)X
+1173(page)X
+1345(size)X
+1490(is)X
+1563(approximately)X
+2046(1K.)X
+10 f
+432 802 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+619 2380 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+629 2437 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+648 2504 MXY
+-12 25 Dl
+24 0 Dl
+-12 -25 Dl
+686 2515 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+762 2516 MXY
+-12 24 Dl
+25 0 Dl
+-13 -24 Dl
+916 2515 MXY
+-13 24 Dl
+25 0 Dl
+-12 -24 Dl
+1222 2516 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+1834 2515 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+1 Dt
+619 2392 MXY
+10 57 Dl
+19 67 Dl
+38 11 Dl
+76 1 Dl
+154 -1 Dl
+306 1 Dl
+612 -1 Dl
+8 s
+1 f
+1628 2522(128)N
+3 Dt
+607 2245 MXY
+24 Dc
+617 2375 MXY
+23 Dc
+635 2442 MXY
+24 Dc
+674 2525 MXY
+23 Dc
+750 2529 MXY
+24 Dc
+904 2527 MXY
+23 Dc
+1210 MX
+23 Dc
+1822 2528 MXY
+23 Dc
+20 Ds
+1 Dt
+619 2245 MXY
+10 130 Dl
+19 67 Dl
+38 83 Dl
+76 4 Dl
+154 -2 Dl
+306 0 Dl
+612 1 Dl
+678 2482(256)N
+-1 Ds
+3 Dt
+619 2127 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+629 2191 MXY
+0 25 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+648 2334 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+686 2409 MXY
+0 25 Dl
+0 -13 Dl
+12 0 Dl
+-24 0 Dl
+762 2516 MXY
+0 25 Dl
+0 -12 Dl
+13 0 Dl
+-25 0 Dl
+916 2516 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-25 0 Dl
+1222 2515 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1834 2515 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+5 Dt
+619 2139 MXY
+10 65 Dl
+19 142 Dl
+38 75 Dl
+76 108 Dl
+154 -1 Dl
+306 -1 Dl
+612 0 Dl
+694 2401(512)N
+3 Dt
+631 2064 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+641 2077 MXY
+-24 25 Dl
+12 -12 Dl
+-12 -13 Dl
+24 25 Dl
+660 2132 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+698 2292 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+775 2382 MXY
+-25 24 Dl
+12 -12 Dl
+-12 -12 Dl
+25 24 Dl
+928 2516 MXY
+-25 24 Dl
+13 -12 Dl
+-13 -12 Dl
+25 24 Dl
+1234 2516 MXY
+-24 25 Dl
+12 -12 Dl
+-12 -13 Dl
+24 25 Dl
+1846 2516 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+16 Ds
+1 Dt
+619 2076 MXY
+10 14 Dl
+19 54 Dl
+38 160 Dl
+76 90 Dl
+154 134 Dl
+306 1 Dl
+612 -1 Dl
+694 2257(1024)N
+-1 Ds
+3 Dt
+619 1877 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+629 1855 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+648 1838 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+686 1860 MXY
+12 -25 Dl
+-24 0 Dl
+12 25 Dl
+762 1923 MXY
+13 -24 Dl
+-25 0 Dl
+12 24 Dl
+916 2087 MXY
+12 -24 Dl
+-25 0 Dl
+13 24 Dl
+1222 2256 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+1834 2541 MXY
+12 -25 Dl
+-24 0 Dl
+12 25 Dl
+619 1865 MXY
+10 -22 Dl
+19 -17 Dl
+38 21 Dl
+76 64 Dl
+154 164 Dl
+306 169 Dl
+612 285 Dl
+1645 2427(4096)N
+619 1243 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+629 1196 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+648 1146 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+686 1174 MXY
+0 25 Dl
+0 -13 Dl
+12 0 Dl
+-24 0 Dl
+762 1249 MXY
+0 24 Dl
+0 -12 Dl
+13 0 Dl
+-25 0 Dl
+916 1371 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-25 0 Dl
+1222 1680 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1834 1999 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+619 1255 MXY
+10 -47 Dl
+19 -50 Dl
+38 28 Dl
+76 75 Dl
+154 122 Dl
+306 309 Dl
+612 319 Dl
+1741 1934(8192)N
+5 Dt
+609 2531 MXY
+1225 0 Dl
+609 MX
+0 -1553 Dl
+2531 MY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+593 2625(0)N
+-1 Ds
+5 Dt
+916 2531 MXY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+884 2625(32)N
+-1 Ds
+5 Dt
+1222 2531 MXY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+1190 2625(64)N
+-1 Ds
+5 Dt
+1528 2531 MXY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+1496 2625(96)N
+-1 Ds
+5 Dt
+1834 2531 MXY
+0 16 Dl
+4 Ds
+1 Dt
+2531 MY
+0 -1553 Dl
+1786 2625(128)N
+-1 Ds
+5 Dt
+609 2531 MXY
+-16 0 Dl
+4 Ds
+1 Dt
+609 MX
+1225 0 Dl
+545 2558(0)N
+-1 Ds
+5 Dt
+609 2013 MXY
+-16 0 Dl
+4 Ds
+1 Dt
+609 MX
+1225 0 Dl
+481 2040(100)N
+-1 Ds
+5 Dt
+609 1496 MXY
+-16 0 Dl
+4 Ds
+1 Dt
+609 MX
+1225 0 Dl
+481 1523(200)N
+-1 Ds
+5 Dt
+609 978 MXY
+-16 0 Dl
+4 Ds
+1 Dt
+609 MX
+1225 0 Dl
+481 1005(300)N
+1088 2724(Fill)N
+1194(Factor)X
+422 1611(S)N
+426 1667(e)N
+426 1724(c)N
+424 1780(o)N
+424 1837(n)N
+424 1893(d)N
+428 1949(s)N
+3 Dt
+-1 Ds
+3 f
+432 2882(Figure)N
+636(5a:)X
+1 f
+744(System)X
+956(Time)X
+1113(for)X
+1209(dictionary)X
+1490(data)X
+1618(set)X
+1711(with)X
+1847(1M)X
+1958(of)X
+2033(buffer)X
+432 2970(space)N
+594(and)X
+707(varying)X
+923(bucket)X
+1114(sizes)X
+1259(and)X
+1372(\256ll)X
+1465(factors.)X
+1675(Each)X
+1823(line)X
+1940(is)X
+2004(labeled)X
+432 3058(with)N
+562(its)X
+639(bucket)X
+825(size.)X
+10 s
+10 f
+432 3234 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+8 s
+1 f
+428 4381(s)N
+424 4325(d)N
+424 4269(n)N
+424 4212(o)N
+426 4156(c)N
+426 4099(e)N
+422 4043(S)N
+1116 5156(Fill)N
+1222(Factor)X
+506 3437(3200)N
+4 Ds
+1 Dt
+666 3410 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+506 3825(2400)N
+4 Ds
+1 Dt
+666 3799 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+506 4214(1600)N
+4 Ds
+1 Dt
+666 4186 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+538 4602(800)N
+4 Ds
+1 Dt
+666 4575 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+602 4990(0)N
+4 Ds
+1 Dt
+666 4963 MXY
+1168 0 Dl
+-1 Ds
+5 Dt
+666 MX
+-16 0 Dl
+1786 5057(128)N
+4 Ds
+1 Dt
+1834 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+1510 5057(96)N
+4 Ds
+1 Dt
+1542 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+1218 5057(64)N
+4 Ds
+1 Dt
+1250 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+926 5057(32)N
+4 Ds
+1 Dt
+958 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+650 5057(0)N
+4 Ds
+1 Dt
+666 4963 MXY
+0 -1553 Dl
+-1 Ds
+5 Dt
+4963 MY
+0 16 Dl
+4963 MY
+0 -1553 Dl
+4963 MY
+1168 0 Dl
+1741 4752(8192)N
+3 Dt
+675 3732 MXY
+9 -172 Dl
+18 -118 Dl
+37 128 Dl
+73 -121 Dl
+146 623 Dl
+292 497 Dl
+584 245 Dl
+4802 MY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1250 4557 MXY
+0 25 Dl
+0 -13 Dl
+12 0 Dl
+-24 0 Dl
+958 4060 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+812 3437 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+739 3558 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+702 3430 MXY
+0 25 Dl
+0 -13 Dl
+13 0 Dl
+-25 0 Dl
+684 3548 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+675 3720 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1637 4912(4096)N
+675 4307 MXY
+9 -58 Dl
+18 30 Dl
+37 89 Dl
+73 144 Dl
+146 235 Dl
+292 122 Dl
+584 89 Dl
+4970 MY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+1250 4881 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+958 4759 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+812 4524 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+739 4380 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+702 4291 MXY
+13 -24 Dl
+-25 0 Dl
+12 24 Dl
+684 4261 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+675 4319 MXY
+12 -24 Dl
+-24 0 Dl
+12 24 Dl
+734 4662(1024)N
+16 Ds
+1 Dt
+675 4352 MXY
+9 60 Dl
+18 134 Dl
+37 266 Dl
+73 117 Dl
+146 30 Dl
+292 0 Dl
+584 -1 Dl
+-1 Ds
+3 Dt
+1846 4946 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+1262 4946 MXY
+-24 25 Dl
+12 -12 Dl
+-12 -13 Dl
+24 25 Dl
+970 4947 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+824 4917 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+751 4800 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+715 4534 MXY
+-25 25 Dl
+12 -13 Dl
+-12 -12 Dl
+25 25 Dl
+696 4400 MXY
+-24 24 Dl
+12 -12 Dl
+-12 -12 Dl
+24 24 Dl
+687 4339 MXY
+-24 25 Dl
+12 -12 Dl
+-12 -13 Dl
+24 25 Dl
+718 4792(512)N
+5 Dt
+675 4422 MXY
+9 137 Dl
+18 278 Dl
+37 105 Dl
+73 18 Dl
+146 -1 Dl
+292 0 Dl
+584 -1 Dl
+3 Dt
+4946 MY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+1250 4946 MXY
+0 25 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+958 4947 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+812 4948 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+739 4930 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+702 4824 MXY
+0 25 Dl
+0 -12 Dl
+13 0 Dl
+-25 0 Dl
+684 4547 MXY
+0 24 Dl
+0 -12 Dl
+12 0 Dl
+-24 0 Dl
+675 4410 MXY
+0 25 Dl
+0 -13 Dl
+12 0 Dl
+-24 0 Dl
+750 4921(256)N
+20 Ds
+1 Dt
+675 4597 MXY
+9 246 Dl
+18 106 Dl
+37 10 Dl
+73 0 Dl
+146 0 Dl
+292 0 Dl
+584 -1 Dl
+-1 Ds
+3 Dt
+1822 MX
+23 Dc
+1238 4959 MXY
+23 Dc
+946 MX
+23 Dc
+800 MX
+23 Dc
+727 MX
+23 Dc
+691 4949 MXY
+23 Dc
+672 4843 MXY
+24 Dc
+663 4597 MXY
+24 Dc
+1395 4961(128)N
+1 Dt
+675 4855 MXY
+9 93 Dl
+18 10 Dl
+37 1 Dl
+73 0 Dl
+146 -1 Dl
+292 0 Dl
+584 0 Dl
+3 Dt
+4946 MY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+1250 MX
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+958 MX
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+812 MX
+-12 25 Dl
+24 0 Dl
+-12 -25 Dl
+739 4947 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+702 4946 MXY
+-12 24 Dl
+25 0 Dl
+-13 -24 Dl
+684 4936 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+675 4843 MXY
+-12 24 Dl
+24 0 Dl
+-12 -24 Dl
+3 Dt
+-1 Ds
+3 f
+432 5314(Figure)N
+634(5b:)X
+1 f
+744(Elapsed)X
+967(Time)X
+1123(for)X
+1218(dictionary)X
+1498(data)X
+1625(set)X
+1717(with)X
+1851(1M)X
+1960(of)X
+2033(buffer)X
+432 5402(space)N
+593(and)X
+705(varying)X
+920(bucket)X
+1110(sizes)X
+1254(and)X
+1366(\256ll)X
+1457(factors.)X
+1681(Each)X
+1827(line)X
+1942(is)X
+2004(labeled)X
+432 5490(with)N
+562(its)X
+639(bucket)X
+825(size.)X
+10 s
+2590 538(If)N
+2677(an)X
+2785(approximation)X
+3284(of)X
+3383(the)X
+3513(number)X
+3790(of)X
+3889(elements)X
+2418 626(ultimately)N
+2773(to)X
+2866(be)X
+2973(stored)X
+3200(in)X
+3293(the)X
+3422(hash)X
+3599(table)X
+3785(is)X
+3868(known)X
+4116(at)X
+2418 714(the)N
+2564(time)X
+2754(of)X
+2869(creation,)X
+3196(the)X
+3342(hash)X
+3536(package)X
+3847(takes)X
+4059(this)X
+2418 802(number)N
+2688(as)X
+2779(a)X
+2839(parameter)X
+3185(and)X
+3325(uses)X
+3487(it)X
+3555(to)X
+3641(hash)X
+3812(entries)X
+4050(into)X
+2418 890(the)N
+2541(full)X
+2677(sized)X
+2867(table)X
+3048(rather)X
+3261(than)X
+3424(growing)X
+3716(the)X
+3838(table)X
+4018(from)X
+2418 978(a)N
+2477(single)X
+2691(bucket.)X
+2968(If)X
+3044(this)X
+3181(number)X
+3448(is)X
+3523(not)X
+3647(known,)X
+3907(the)X
+4027(hash)X
+2418 1066(table)N
+2632(starts)X
+2859(with)X
+3059(a)X
+3153(single)X
+3402(bucket)X
+3674(and)X
+3848(gracefully)X
+2418 1154(expands)N
+2707(as)X
+2800(elements)X
+3111(are)X
+3236(added,)X
+3474(although)X
+3780(a)X
+3842(slight)X
+4044(per-)X
+2418 1242(formance)N
+2747(degradation)X
+3151(may)X
+3313(be)X
+3413(noticed.)X
+3713(Figure)X
+3946(6)X
+4010(illus-)X
+2418 1330(trates)N
+2625(the)X
+2756(difference)X
+3116(in)X
+3211(performance)X
+3651(between)X
+3952(storing)X
+2418 1418(keys)N
+2588(in)X
+2673(a)X
+2732(\256le)X
+2857(when)X
+3054(the)X
+3174(ultimate)X
+3458(size)X
+3605(is)X
+3680(known)X
+3920(\(the)X
+4067(left)X
+2418 1506(bars)N
+2581(in)X
+2672(each)X
+2849(set\),)X
+3014(compared)X
+3360(to)X
+3450(building)X
+3744(the)X
+3870(\256le)X
+4000(when)X
+2418 1594(the)N
+2550(ultimate)X
+2846(size)X
+3005(is)X
+3091(unknown)X
+3422(\(the)X
+3580(right)X
+3764(bars)X
+3931(in)X
+4026(each)X
+2418 1682(set\).)N
+2609(Once)X
+2814(the)X
+2947(\256ll)X
+3069(factor)X
+3291(is)X
+3378(suf\256ciently)X
+3772(high)X
+3948(for)X
+4076(the)X
+2418 1770(page)N
+2596(size)X
+2747(\(8\),)X
+2887(growing)X
+3180(the)X
+3304(table)X
+3486(dynamically)X
+3908(does)X
+4081(lit-)X
+2418 1858(tle)N
+2518(to)X
+2600(degrade)X
+2875(performance.)X
+10 f
+2418 1946 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+9 s
+1 f
+2413 3238(s)N
+2409 3173(d)N
+2409 3108(n)N
+2409 3043(o)N
+2411 2979(c)N
+2411 2914(e)N
+2407 2849(S)N
+3143 4129(Fill)N
+3261(Factor)X
+2448 2152(15)N
+4 Ds
+1 Dt
+2557 2122 MXY
+1473 0 Dl
+-1 Ds
+5 Dt
+2557 MX
+-19 0 Dl
+2448 2747(10)N
+4 Ds
+1 Dt
+2557 2717 MXY
+1473 0 Dl
+-1 Ds
+5 Dt
+2557 MX
+-19 0 Dl
+2484 3343(5)N
+4 Ds
+1 Dt
+2557 3313 MXY
+1473 0 Dl
+-1 Ds
+5 Dt
+2557 MX
+-19 0 Dl
+2484 3938(0)N
+4 Ds
+1 Dt
+2557 3908 MXY
+1473 0 Dl
+-1 Ds
+5 Dt
+2557 MX
+-19 0 Dl
+3976 4015(128)N
+4 Ds
+1 Dt
+4030 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+3626 4015(96)N
+4 Ds
+1 Dt
+3662 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+3258 4015(64)N
+4 Ds
+1 Dt
+3294 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+2889 4015(32)N
+4 Ds
+1 Dt
+2925 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+2539 4015(0)N
+4 Ds
+1 Dt
+2557 3908 MXY
+0 -1786 Dl
+-1 Ds
+5 Dt
+3908 MY
+0 19 Dl
+3908 MY
+0 -1786 Dl
+3908 MY
+1473 0 Dl
+4053 2378(8192)N
+3 Dt
+2569 2277 MXY
+11 0 Dl
+23 48 Dl
+46 -167 Dl
+92 35 Dl
+184 12 Dl
+369 143 Dl
+736 0 Dl
+2334 MY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+3294 2334 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+2925 2192 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2741 2180 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2649 2144 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2603 2311 MXY
+0 27 Dl
+0 -13 Dl
+14 0 Dl
+-28 0 Dl
+2580 2263 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2569 2263 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+4053 2591(4096)N
+2569 2348 MXY
+11 -11 Dl
+23 -96 Dl
+46 71 Dl
+92 72 Dl
+184 226 Dl
+369 48 Dl
+736 -60 Dl
+2612 MY
+14 -28 Dl
+-28 0 Dl
+14 28 Dl
+3294 2672 MXY
+13 -28 Dl
+-27 0 Dl
+14 28 Dl
+2925 2624 MXY
+14 -28 Dl
+-28 0 Dl
+14 28 Dl
+2741 2398 MXY
+14 -28 Dl
+-28 0 Dl
+14 28 Dl
+2649 2326 MXY
+14 -27 Dl
+-28 0 Dl
+14 27 Dl
+2603 2255 MXY
+14 -28 Dl
+-28 0 Dl
+14 28 Dl
+2580 2350 MXY
+14 -27 Dl
+-28 0 Dl
+14 27 Dl
+2569 2362 MXY
+13 -28 Dl
+-27 0 Dl
+14 28 Dl
+4053 2681(1024)N
+16 Ds
+1 Dt
+2569 2300 MXY
+11 48 Dl
+23 96 Dl
+46 95 Dl
+92 274 Dl
+184 202 Dl
+369 -155 Dl
+736 -190 Dl
+-1 Ds
+3 Dt
+4044 2656 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+3307 2846 MXY
+-27 28 Dl
+14 -14 Dl
+-14 -14 Dl
+27 28 Dl
+2939 3001 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2755 2799 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2663 2525 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2617 2430 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2594 2334 MXY
+-28 28 Dl
+14 -14 Dl
+-14 -14 Dl
+28 28 Dl
+2582 2287 MXY
+-27 27 Dl
+14 -14 Dl
+-14 -13 Dl
+27 27 Dl
+4053 2851(512)N
+5 Dt
+2569 2372 MXY
+11 -24 Dl
+23 405 Dl
+46 83 Dl
+92 227 Dl
+184 -72 Dl
+369 -119 Dl
+736 -107 Dl
+3 Dt
+2751 MY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+3294 2858 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+2925 2977 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2741 3049 MXY
+0 27 Dl
+0 -13 Dl
+14 0 Dl
+-28 0 Dl
+2649 2823 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2603 2739 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2580 2334 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2569 2358 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+4053 2795(256)N
+20 Ds
+1 Dt
+2569 2456 MXY
+11 285 Dl
+23 95 Dl
+46 251 Dl
+92 -60 Dl
+184 -84 Dl
+369 -107 Dl
+736 -71 Dl
+-1 Ds
+3 Dt
+4016 MX
+27 Dc
+3280 2836 MXY
+27 Dc
+2912 2943 MXY
+27 Dc
+2728 3027 MXY
+27 Dc
+2635 3087 MXY
+28 Dc
+2589 2836 MXY
+28 Dc
+2566 2741 MXY
+27 Dc
+2554 2456 MXY
+28 Dc
+4053 2741(128)N
+1 Dt
+2569 2729 MXY
+11 203 Dl
+23 131 Dl
+46 -60 Dl
+92 -119 Dl
+184 -60 Dl
+369 -83 Dl
+736 -12 Dl
+3 Dt
+2716 MY
+-14 27 Dl
+28 0 Dl
+-14 -27 Dl
+3294 2727 MXY
+-14 28 Dl
+27 0 Dl
+-13 -28 Dl
+2925 2811 MXY
+-14 27 Dl
+28 0 Dl
+-14 -27 Dl
+2741 2870 MXY
+-14 28 Dl
+28 0 Dl
+-14 -28 Dl
+2649 2989 MXY
+-14 28 Dl
+28 0 Dl
+-14 -28 Dl
+2603 3049 MXY
+-14 27 Dl
+28 0 Dl
+-14 -27 Dl
+2580 2918 MXY
+-14 28 Dl
+28 0 Dl
+-14 -28 Dl
+2569 2716 MXY
+-14 27 Dl
+27 0 Dl
+-13 -27 Dl
+3 Dt
+-1 Ds
+3 f
+8 s
+2418 4286(Figure)N
+2628(5c:)X
+1 f
+2738(User)X
+2887(Time)X
+3051(for)X
+3154(dictionary)X
+3442(data)X
+3577(set)X
+3677(with)X
+3820(1M)X
+3938(of)X
+4019(buffer)X
+2418 4374(space)N
+2579(and)X
+2691(varying)X
+2906(bucket)X
+3096(sizes)X
+3240(and)X
+3352(\256ll)X
+3443(factors.)X
+3667(Each)X
+3813(line)X
+3928(is)X
+3990(labeled)X
+2418 4462(with)N
+2548(its)X
+2625(bucket)X
+2811(size.)X
+10 s
+10 f
+2418 4638 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 f
+2590 4840(Since)N
+2796(no)X
+2904(known)X
+3150(hash)X
+3325(function)X
+3620(performs)X
+3938(equally)X
+2418 4928(well)N
+2589(on)X
+2702(all)X
+2815(possible)X
+3110(data,)X
+3297(the)X
+3428(user)X
+3595(may)X
+3766(\256nd)X
+3923(that)X
+4076(the)X
+2418 5016(built-in)N
+2678(hash)X
+2849(function)X
+3140(does)X
+3311(poorly)X
+3544(on)X
+3648(a)X
+3708(particular)X
+4040(data)X
+2418 5104(set.)N
+2548(In)X
+2636(this)X
+2771(case,)X
+2950(a)X
+3006(hash)X
+3173(function,)X
+3480(taking)X
+3700(two)X
+3840(arguments)X
+2418 5192(\(a)N
+2507(pointer)X
+2760(to)X
+2848(a)X
+2910(byte)X
+3074(string)X
+3282(and)X
+3424(a)X
+3486(length\))X
+3739(and)X
+3880(returning)X
+2418 5280(an)N
+2517(unsigned)X
+2829(long)X
+2993(to)X
+3077(be)X
+3175(used)X
+3344(as)X
+3433(the)X
+3553(hash)X
+3722(value,)X
+3938(may)X
+4098(be)X
+2418 5368(speci\256ed)N
+2731(at)X
+2817(hash)X
+2992(table)X
+3176(creation)X
+3463(time.)X
+3673(When)X
+3893(an)X
+3996(exist-)X
+2418 5456(ing)N
+2570(hash)X
+2767(table)X
+2973(is)X
+3076(opened)X
+3358(and)X
+3524(a)X
+3609(hash)X
+3805(function)X
+4121(is)X
+2418 5544(speci\256ed,)N
+2752(the)X
+2879(hash)X
+3054(package)X
+3346(will)X
+3498(try)X
+3615(to)X
+3705(determine)X
+4054(that)X
+2418 5632(the)N
+2546(hash)X
+2723(function)X
+3020(supplied)X
+3321(is)X
+3404(the)X
+3532(one)X
+3678(with)X
+3850(which)X
+4076(the)X
+2418 5720(table)N
+2630(was)X
+2811(created.)X
+3139(There)X
+3382(are)X
+3536(a)X
+3627(variety)X
+3905(of)X
+4027(hash)X
+3 f
+432 5960(8)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+9 p
+%%Page: 9 9
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+720 538(functions)N
+1065(provided)X
+1397(with)X
+1586(the)X
+1731(package.)X
+2082(The)X
+2253(default)X
+720 626(function)N
+1014(for)X
+1135(the)X
+1260(package)X
+1551(is)X
+1631(the)X
+1755(one)X
+1897(which)X
+2119(offered)X
+2378(the)X
+720 714(best)N
+875(performance)X
+1308(in)X
+1396(terms)X
+1600(of)X
+1693(cycles)X
+1920(executed)X
+2232(per)X
+2360(call)X
+720 802(\(it)N
+827(did)X
+965(not)X
+1103(produce)X
+1398(the)X
+1531(fewest)X
+1776(collisions)X
+2117(although)X
+2432(it)X
+720 890(was)N
+866(within)X
+1091(a)X
+1148(small)X
+1341(percentage)X
+1710(of)X
+1797(the)X
+1915(function)X
+2202(that)X
+2342(pro-)X
+720 978(duced)N
+947(the)X
+1080(fewest)X
+1324(collisions\).)X
+1731(Again,)X
+1981(in)X
+2077(time)X
+2253(critical)X
+720 1066(applications,)N
+1152(users)X
+1342(are)X
+1466(encouraged)X
+1862(to)X
+1949(experiment)X
+2334(with)X
+720 1154(a)N
+783(variety)X
+1032(of)X
+1125(hash)X
+1298(functions)X
+1622(to)X
+1710(achieve)X
+1982(optimal)X
+2252(perfor-)X
+720 1242(mance.)N
+10 f
+720 1330 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+7 s
+1038 2925(Full)N
+1149(size)X
+1251(table)X
+1384(\(left\))X
+1547 2718(Fill)N
+1643(Factor)X
+2268 2662(64)N
+1964(32)X
+1674(16)X
+1384(8)X
+1093(4)X
+4 Ds
+1 Dt
+900 2280 MXY
+1548 0 Dl
+900 1879 MXY
+1548 0 Dl
+900 1506 MXY
+1548 0 Dl
+1563 2902 MXY
+111 0 Dl
+-1 Ds
+900 MX
+110 0 Dl
+1425 2828(System)N
+983(User)X
+1895 2778 MXY
+ 1895 2778 lineto
+ 1950 2778 lineto
+ 1950 2833 lineto
+ 1895 2833 lineto
+ 1895 2778 lineto
+closepath 21 1895 2778 1950 2833 Dp
+1342 MX
+ 1342 2778 lineto
+ 1397 2778 lineto
+ 1397 2833 lineto
+ 1342 2833 lineto
+ 1342 2778 lineto
+closepath 14 1342 2778 1397 2833 Dp
+900 MX
+ 900 2778 lineto
+ 955 2778 lineto
+ 955 2833 lineto
+ 900 2833 lineto
+ 900 2778 lineto
+closepath 3 900 2778 955 2833 Dp
+5 Dt
+2283 2211 MXY
+96 0 Dl
+1992 MX
+97 0 Dl
+1702 MX
+97 0 Dl
+1411 2252 MXY
+97 0 Dl
+4 Ds
+1 Dt
+2283 2211 MXY
+ 2283 2211 lineto
+ 2379 2211 lineto
+ 2379 2252 lineto
+ 2283 2252 lineto
+ 2283 2211 lineto
+closepath 14 2283 2211 2379 2252 Dp
+1992 MX
+ 1992 2211 lineto
+ 2089 2211 lineto
+ 2089 2252 lineto
+ 1992 2252 lineto
+ 1992 2211 lineto
+closepath 14 1992 2211 2089 2252 Dp
+1702 MX
+ 1702 2211 lineto
+ 1799 2211 lineto
+ 1799 2252 lineto
+ 1702 2252 lineto
+ 1702 2211 lineto
+closepath 14 1702 2211 1799 2252 Dp
+1411 2252 MXY
+ 1411 2252 lineto
+ 1508 2252 lineto
+ 1508 2294 lineto
+ 1411 2294 lineto
+ 1411 2252 lineto
+closepath 14 1411 2252 1508 2294 Dp
+2283 MX
+ 2283 2252 lineto
+ 2379 2252 lineto
+ 2379 2612 lineto
+ 2283 2612 lineto
+ 2283 2252 lineto
+closepath 3 2283 2252 2379 2612 Dp
+1992 MX
+ 1992 2252 lineto
+ 2089 2252 lineto
+ 2089 2612 lineto
+ 1992 2612 lineto
+ 1992 2252 lineto
+closepath 3 1992 2252 2089 2612 Dp
+1702 MX
+ 1702 2252 lineto
+ 1799 2252 lineto
+ 1799 2612 lineto
+ 1702 2612 lineto
+ 1702 2252 lineto
+closepath 3 1702 2252 1799 2612 Dp
+1411 2294 MXY
+ 1411 2294 lineto
+ 1508 2294 lineto
+ 1508 2612 lineto
+ 1411 2612 lineto
+ 1411 2294 lineto
+closepath 3 1411 2294 1508 2612 Dp
+-1 Ds
+2158 2238 MXY
+ 2158 2238 lineto
+ 2255 2238 lineto
+ 2255 2252 lineto
+ 2158 2252 lineto
+ 2158 2238 lineto
+closepath 21 2158 2238 2255 2252 Dp
+1868 MX
+ 1868 2238 lineto
+ 1965 2238 lineto
+ 1965 2280 lineto
+ 1868 2280 lineto
+ 1868 2238 lineto
+closepath 21 1868 2238 1965 2280 Dp
+1577 MX
+ 1577 2238 lineto
+ 1674 2238 lineto
+ 1674 2308 lineto
+ 1577 2308 lineto
+ 1577 2238 lineto
+closepath 21 1577 2238 1674 2308 Dp
+1287 2308 MXY
+ 1287 2308 lineto
+ 1287 2280 lineto
+ 1384 2280 lineto
+ 1384 2308 lineto
+ 1287 2308 lineto
+closepath 21 1287 2280 1384 2308 Dp
+2158 2280 MXY
+ 2158 2280 lineto
+ 2158 2252 lineto
+ 2255 2252 lineto
+ 2255 2280 lineto
+ 2158 2280 lineto
+closepath 14 2158 2252 2255 2280 Dp
+1868 2308 MXY
+ 1868 2308 lineto
+ 1868 2280 lineto
+ 1965 2280 lineto
+ 1965 2308 lineto
+ 1868 2308 lineto
+closepath 14 1868 2280 1965 2308 Dp
+1577 2335 MXY
+ 1577 2335 lineto
+ 1577 2308 lineto
+ 1674 2308 lineto
+ 1674 2335 lineto
+ 1577 2335 lineto
+closepath 14 1577 2308 1674 2335 Dp
+1287 2363 MXY
+ 1287 2363 lineto
+ 1287 2308 lineto
+ 1384 2308 lineto
+ 1384 2363 lineto
+ 1287 2363 lineto
+closepath 14 1287 2308 1384 2363 Dp
+2158 2280 MXY
+ 2158 2280 lineto
+ 2255 2280 lineto
+ 2255 2612 lineto
+ 2158 2612 lineto
+ 2158 2280 lineto
+closepath 3 2158 2280 2255 2612 Dp
+1868 2308 MXY
+ 1868 2308 lineto
+ 1965 2308 lineto
+ 1965 2612 lineto
+ 1868 2612 lineto
+ 1868 2308 lineto
+closepath 3 1868 2308 1965 2612 Dp
+1577 2335 MXY
+ 1577 2335 lineto
+ 1674 2335 lineto
+ 1674 2612 lineto
+ 1577 2612 lineto
+ 1577 2335 lineto
+closepath 3 1577 2335 1674 2612 Dp
+1287 2363 MXY
+ 1287 2363 lineto
+ 1384 2363 lineto
+ 1384 2612 lineto
+ 1287 2612 lineto
+ 1287 2363 lineto
+closepath 3 1287 2363 1384 2612 Dp
+4 Ds
+1121 2066 MXY
+ 1121 2066 lineto
+ 1218 2066 lineto
+ 1224 2080 lineto
+ 1127 2080 lineto
+ 1121 2066 lineto
+closepath 21 1121 2066 1224 2080 Dp
+2080 MY
+ 1121 2080 lineto
+ 1218 2080 lineto
+ 1218 2273 lineto
+ 1121 2273 lineto
+ 1121 2080 lineto
+closepath 14 1121 2080 1218 2273 Dp
+2273 MY
+ 1121 2273 lineto
+ 1218 2273 lineto
+ 1218 2612 lineto
+ 1121 2612 lineto
+ 1121 2273 lineto
+closepath 3 1121 2273 1218 2612 Dp
+-1 Ds
+997 1589 MXY
+ 997 1589 lineto
+ 1093 1589 lineto
+ 1093 1644 lineto
+ 997 1644 lineto
+ 997 1589 lineto
+closepath 21 997 1589 1093 1644 Dp
+1644 MY
+ 997 1644 lineto
+ 1093 1644 lineto
+ 1093 2280 lineto
+ 997 2280 lineto
+ 997 1644 lineto
+closepath 14 997 1644 1093 2280 Dp
+2280 MY
+ 997 2280 lineto
+ 1093 2280 lineto
+ 1093 2612 lineto
+ 997 2612 lineto
+ 997 2280 lineto
+closepath 3 997 2280 1093 2612 Dp
+10 s
+719 2093(s)N
+712 2037(d)N
+712 1982(n)N
+714 1927(o)N
+716 1872(c)N
+716 1816(e)N
+712 1761(S)N
+804 2286(10)N
+804 1899(20)N
+804 1540(30)N
+3 Dt
+900 1506 MXY
+0 1106 Dl
+1548 0 Dl
+7 s
+1978 2828(Elapsed)N
+1701 2925(Dynamically)N
+2018(grown)X
+2184(table)X
+2317(\(right\))X
+3 Dt
+-1 Ds
+8 s
+720 3180(Figure)N
+934(6:)X
+1 f
+1020(The)X
+1152(total)X
+1299(regions)X
+1520(indicate)X
+1755(the)X
+1865(difference)X
+2154(between)X
+2398(the)X
+720 3268(elapsed)N
+931(time)X
+1065(and)X
+1177(the)X
+1275(sum)X
+1402(of)X
+1475(the)X
+1573(system)X
+1771(and)X
+1883(user)X
+2008(time.)X
+2173(The)X
+2291(left)X
+2395(bar)X
+720 3356(of)N
+798(each)X
+939(set)X
+1035(depicts)X
+1241(the)X
+1344(timing)X
+1537(of)X
+1615(the)X
+1718(test)X
+1831(run)X
+1940(when)X
+2102(the)X
+2204(number)X
+2423(of)X
+720 3444(entries)N
+910(is)X
+973(known)X
+1167(in)X
+1237(advance.)X
+1496(The)X
+1614(right)X
+1754(bars)X
+1879(depict)X
+2054(the)X
+2151(timing)X
+2338(when)X
+720 3532(the)N
+814(\256le)X
+912(is)X
+971(grown)X
+1150(from)X
+1290(a)X
+1334(single)X
+1503(bucket.)X
+10 s
+10 f
+720 3708 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+1 f
+892 3910(Since)N
+1131(this)X
+1307(hashing)X
+1617(package)X
+1942(provides)X
+2279(buffer)X
+720 3998(management,)N
+1188(the)X
+1323(amount)X
+1600(of)X
+1704(space)X
+1920(allocated)X
+2247(for)X
+2378(the)X
+720 4086(buffer)N
+948(pool)X
+1121(may)X
+1290(be)X
+1397(speci\256ed)X
+1713(by)X
+1824(the)X
+1953(user.)X
+2157(Using)X
+2378(the)X
+720 4174(same)N
+910(data)X
+1069(set)X
+1183(and)X
+1324(test)X
+1459(procedure)X
+1805(as)X
+1896(used)X
+2067(to)X
+2153(derive)X
+2378(the)X
+720 4262(graphs)N
+962(in)X
+1052(Figures)X
+1320(5a-c,)X
+1507(Figure)X
+1744(7)X
+1812(shows)X
+2039(the)X
+2164(impact)X
+2409(of)X
+720 4350(varying)N
+997(the)X
+1126(size)X
+1282(of)X
+1380(the)X
+1509(buffer)X
+1737(pool.)X
+1950(The)X
+2106(bucket)X
+2351(size)X
+720 4438(was)N
+873(set)X
+989(to)X
+1078(256)X
+1225(bytes)X
+1421(and)X
+1564(the)X
+1689(\256ll)X
+1804(factor)X
+2019(was)X
+2171(set)X
+2287(to)X
+2376(16.)X
+720 4526(The)N
+869(buffer)X
+1090(pool)X
+1256(size)X
+1404(was)X
+1552(varied)X
+1776(from)X
+1955(0)X
+2018(\(the)X
+2166(minimum)X
+720 4614(number)N
+986(of)X
+1074(pages)X
+1277(required)X
+1565(to)X
+1647(be)X
+1743(buffered\))X
+2063(to)X
+2145(1M.)X
+2316(With)X
+720 4702(1M)N
+854(of)X
+944(buffer)X
+1164(space,)X
+1386(the)X
+1507(package)X
+1794(performed)X
+2151(no)X
+2253(I/O)X
+2382(for)X
+720 4790(this)N
+871(data)X
+1040(set.)X
+1204(As)X
+1328(Figure)X
+1572(7)X
+1647(illustrates,)X
+2013(increasing)X
+2378(the)X
+720 4878(buffer)N
+944(pool)X
+1113(size)X
+1265(can)X
+1404(have)X
+1583(a)X
+1646(dramatic)X
+1954(affect)X
+2165(on)X
+2271(result-)X
+720 4966(ing)N
+842(performance.)X
+2 f
+8 s
+1269 4941(7)N
+1 f
+16 s
+720 5353 MXY
+864 0 Dl
+2 f
+8 s
+760 5408(7)N
+1 f
+9 s
+826 5433(Some)N
+1024(allocators)X
+1338(are)X
+1460(extremely)X
+1782(inef\256cient)X
+2107(at)X
+2192(allocating)X
+720 5513(memory.)N
+1029(If)X
+1110(you)X
+1251(\256nd)X
+1396(that)X
+1536(applications)X
+1916(are)X
+2036(running)X
+2292(out)X
+2416(of)X
+720 5593(memory)N
+1005(before)X
+1234(you)X
+1386(think)X
+1578(they)X
+1746(should,)X
+2000(try)X
+2124(varying)X
+2388(the)X
+720 5673(pagesize)N
+986(to)X
+1060(get)X
+1166(better)X
+1348(utilization)X
+1658(from)X
+1816(the)X
+1922(memory)X
+2180(allocator.)X
+10 s
+2830 1975 MXY
+0 -28 Dl
+28 0 Dl
+0 28 Dl
+-28 0 Dl
+2853 2004 MXY
+0 -27 Dl
+28 0 Dl
+0 27 Dl
+-28 0 Dl
+2876 2016 MXY
+0 -27 Dl
+27 0 Dl
+0 27 Dl
+-27 0 Dl
+2922 1998 MXY
+0 -27 Dl
+27 0 Dl
+0 27 Dl
+-27 0 Dl
+2967 2025 MXY
+0 -28 Dl
+28 0 Dl
+0 28 Dl
+-28 0 Dl
+3013 2031 MXY
+0 -28 Dl
+28 0 Dl
+0 28 Dl
+-28 0 Dl
+3059 MX
+0 -28 Dl
+27 0 Dl
+0 28 Dl
+-27 0 Dl
+3196 2052 MXY
+0 -28 Dl
+27 0 Dl
+0 28 Dl
+-27 0 Dl
+3561 2102 MXY
+0 -28 Dl
+28 0 Dl
+0 28 Dl
+-28 0 Dl
+4292 2105 MXY
+0 -28 Dl
+27 0 Dl
+0 28 Dl
+-27 0 Dl
+4 Ds
+1 Dt
+2844 1961 MXY
+23 30 Dl
+23 12 Dl
+45 -18 Dl
+46 26 Dl
+46 6 Dl
+45 0 Dl
+137 21 Dl
+366 50 Dl
+730 3 Dl
+9 s
+4227 2158(User)N
+-1 Ds
+3 Dt
+2830 1211 MXY
+27 Dc
+2853 1261 MXY
+27 Dc
+2876 1267 MXY
+27 Dc
+2921 1341 MXY
+27 Dc
+2967 1385 MXY
+27 Dc
+3013 1450 MXY
+27 Dc
+3059 1497 MXY
+27 Dc
+3196 1686 MXY
+27 Dc
+3561 2109 MXY
+27 Dc
+4292 2295 MXY
+27 Dc
+20 Ds
+1 Dt
+2844 1211 MXY
+23 50 Dl
+23 6 Dl
+45 74 Dl
+46 44 Dl
+46 65 Dl
+45 47 Dl
+137 189 Dl
+366 423 Dl
+730 186 Dl
+4181 2270(System)N
+-1 Ds
+3 Dt
+2844 583 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2867 672 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+2890 701 MXY
+0 28 Dl
+0 -14 Dl
+13 0 Dl
+-27 0 Dl
+2935 819 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-27 0 Dl
+2981 849 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+3027 908 MXY
+0 27 Dl
+0 -13 Dl
+14 0 Dl
+-28 0 Dl
+3072 1026 MXY
+0 27 Dl
+0 -13 Dl
+14 0 Dl
+-27 0 Dl
+3209 1292 MXY
+0 27 Dl
+0 -14 Dl
+14 0 Dl
+-27 0 Dl
+3575 1823 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-28 0 Dl
+4305 2059 MXY
+0 28 Dl
+0 -14 Dl
+14 0 Dl
+-27 0 Dl
+5 Dt
+2844 597 MXY
+23 88 Dl
+23 30 Dl
+45 118 Dl
+46 30 Dl
+46 59 Dl
+45 118 Dl
+137 265 Dl
+366 532 Dl
+730 236 Dl
+4328 2103(Total)N
+2844 2310 MXY
+1461 0 Dl
+2844 MX
+0 -1772 Dl
+2310 MY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+2826 2416(0)N
+-1 Ds
+5 Dt
+3209 2310 MXY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+3155 2416(256)N
+-1 Ds
+5 Dt
+3575 2310 MXY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+3521 2416(512)N
+-1 Ds
+5 Dt
+3940 2310 MXY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+3886 2416(768)N
+-1 Ds
+5 Dt
+4305 2310 MXY
+0 18 Dl
+4 Ds
+1 Dt
+2310 MY
+0 -1772 Dl
+4233 2416(1024)N
+-1 Ds
+5 Dt
+2844 2310 MXY
+-18 0 Dl
+4 Ds
+1 Dt
+2844 MX
+1461 0 Dl
+2771 2340(0)N
+-1 Ds
+5 Dt
+2844 2014 MXY
+-18 0 Dl
+2844 1719 MXY
+-18 0 Dl
+4 Ds
+1 Dt
+2844 MX
+1461 0 Dl
+2735 1749(20)N
+-1 Ds
+5 Dt
+2844 1423 MXY
+-18 0 Dl
+2844 1128 MXY
+-18 0 Dl
+4 Ds
+1 Dt
+2844 MX
+1461 0 Dl
+2735 1158(40)N
+-1 Ds
+5 Dt
+2844 833 MXY
+-18 0 Dl
+2844 538 MXY
+-18 0 Dl
+4 Ds
+1 Dt
+2844 MX
+1461 0 Dl
+2735 568(60)N
+3239 2529(Buffer)N
+3445(Pool)X
+3595(Size)X
+3737(\(in)X
+3835(K\))X
+2695 1259(S)N
+2699 1324(e)N
+2699 1388(c)N
+2697 1452(o)N
+2697 1517(n)N
+2697 1581(d)N
+2701 1645(s)N
+3 Dt
+-1 Ds
+3 f
+8 s
+2706 2773(Figure)N
+2908(7:)X
+1 f
+2982(User)X
+3123(time)X
+3258(is)X
+3322(virtually)X
+3560(insensitive)X
+3854(to)X
+3924(the)X
+4022(amount)X
+4234(of)X
+4307(buffer)X
+2706 2861(pool)N
+2852(available,)X
+3130(however,)X
+3396(both)X
+3541(system)X
+3750(time)X
+3895(and)X
+4018(elapsed)X
+4240(time)X
+4385(are)X
+2706 2949(inversely)N
+2960(proportional)X
+3296(to)X
+3366(the)X
+3464(size)X
+3583(of)X
+3656(the)X
+3753(buffer)X
+3927(pool.)X
+4092(Even)X
+4242(for)X
+4335(large)X
+2706 3037(data)N
+2831(sets)X
+2946(where)X
+3120(one)X
+3230(expects)X
+3439(few)X
+3552(collisions,)X
+3832(specifying)X
+4116(a)X
+4162(large)X
+4307(buffer)X
+2706 3125(pool)N
+2836(dramatically)X
+3171(improves)X
+3425(performance.)X
+10 s
+10 f
+2706 3301 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+3175 3543(Enhanced)N
+3536(Functionality)X
+1 f
+2878 3675(This)N
+3046(hashing)X
+3320(package)X
+3609(provides)X
+3910(a)X
+3971(set)X
+4085(of)X
+4177(compati-)X
+2706 3763(bility)N
+2895(routines)X
+3174(to)X
+3257(implement)X
+3620(the)X
+2 f
+3739(ndbm)X
+1 f
+3937(interface.)X
+4279(How-)X
+2706 3851(ever,)N
+2893(when)X
+3095(the)X
+3220(native)X
+3443(interface)X
+3752(is)X
+3832(used,)X
+4026(the)X
+4151(following)X
+2706 3939(additional)N
+3046(functionality)X
+3475(is)X
+3548(provided:)X
+10 f
+2798 4071(g)N
+1 f
+2946(Inserts)X
+3197(never)X
+3413(fail)X
+3556(because)X
+3847(too)X
+3985(many)X
+4199(keys)X
+2946 4159(hash)N
+3113(to)X
+3195(the)X
+3313(same)X
+3498(value.)X
+10 f
+2798 4247(g)N
+1 f
+2946(Inserts)X
+3187(never)X
+3393(fail)X
+3527(because)X
+3808(key)X
+3950(and/or)X
+4181(asso-)X
+2946 4335(ciated)N
+3158(data)X
+3312(is)X
+3385(too)X
+3507(large)X
+10 f
+2798 4423(g)N
+1 f
+2946(Hash)X
+3131(functions)X
+3449(may)X
+3607(be)X
+3703(user-speci\256ed.)X
+10 f
+2798 4511(g)N
+1 f
+2946(Multiple)X
+3268(pages)X
+3498(may)X
+3683(be)X
+3806(cached)X
+4077(in)X
+4186(main)X
+2946 4599(memory.)N
+2706 4731(It)N
+2801(also)X
+2976(provides)X
+3298(a)X
+3380(set)X
+3514(of)X
+3626(compatibility)X
+4097(routines)X
+4400(to)X
+2706 4819(implement)N
+3087(the)X
+2 f
+3224(hsearch)X
+1 f
+3516(interface.)X
+3876(Again,)X
+4130(the)X
+4266(native)X
+2706 4907(interface)N
+3008(offers)X
+3216(enhanced)X
+3540(functionality:)X
+10 f
+2798 5039(g)N
+1 f
+2946(Files)X
+3121(may)X
+3279(grow)X
+3464(beyond)X
+2 f
+3720(nelem)X
+1 f
+3932(elements.)X
+10 f
+2798 5127(g)N
+1 f
+2946(Multiple)X
+3247(hash)X
+3420(tables)X
+3632(may)X
+3795(be)X
+3896(accessed)X
+4203(con-)X
+2946 5215(currently.)N
+10 f
+2798 5303(g)N
+1 f
+2946(Hash)X
+3134(tables)X
+3344(may)X
+3505(be)X
+3604(stored)X
+3823(and)X
+3962(accessed)X
+4266(on)X
+2946 5391(disk.)N
+10 f
+2798 5479(g)N
+1 f
+2946(Hash)X
+3155(functions)X
+3497(may)X
+3679(be)X
+3799(user-speci\256ed)X
+4288(at)X
+2946 5567(runtime.)N
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4424(9)X
+
+10 p
+%%Page: 10 10
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+459 538(Relative)N
+760(Performance)X
+1227(of)X
+1314(the)X
+1441(New)X
+1613(Implementation)X
+1 f
+604 670(The)N
+761(performance)X
+1200(testing)X
+1445(of)X
+1544(the)X
+1674(new)X
+1840(package)X
+2135(is)X
+432 758(divided)N
+711(into)X
+874(two)X
+1033(test)X
+1183(suites.)X
+1424(The)X
+1588(\256rst)X
+1751(suite)X
+1941(of)X
+2046(tests)X
+432 846(requires)N
+727(that)X
+882(the)X
+1015(tables)X
+1237(be)X
+1348(read)X
+1522(from)X
+1713(and)X
+1864(written)X
+2126(to)X
+432 934(disk.)N
+640(In)X
+742(these)X
+942(tests,)X
+1139(the)X
+1272(basis)X
+1467(for)X
+1595(comparison)X
+2003(is)X
+2090(the)X
+432 1022(4.3BSD-Reno)N
+908(version)X
+1169(of)X
+2 f
+1260(ndbm)X
+1 f
+1438(.)X
+1502(Based)X
+1722(on)X
+1826(the)X
+1948(designs)X
+432 1110(of)N
+2 f
+521(sdbm)X
+1 f
+712(and)X
+2 f
+850(gdbm)X
+1 f
+1028(,)X
+1070(they)X
+1230(are)X
+1351(expected)X
+1659(to)X
+1743(perform)X
+2024(simi-)X
+432 1198(larly)N
+605(to)X
+2 f
+693(ndbm)X
+1 f
+871(,)X
+917(and)X
+1059(we)X
+1179(do)X
+1285(not)X
+1413(show)X
+1608(their)X
+1781(performance)X
+432 1286(numbers.)N
+800(The)X
+977(second)X
+1252(suite)X
+1454(contains)X
+1772(the)X
+1921(memory)X
+432 1374(resident)N
+712(test)X
+849(which)X
+1071(does)X
+1243(not)X
+1370(require)X
+1623(that)X
+1768(the)X
+1891(\256les)X
+2049(ever)X
+432 1462(be)N
+533(written)X
+784(to)X
+870(disk,)X
+1047(only)X
+1213(that)X
+1357(hash)X
+1528(tables)X
+1739(may)X
+1901(be)X
+2001(mani-)X
+432 1550(pulated)N
+692(in)X
+778(main)X
+961(memory.)X
+1291(In)X
+1381(this)X
+1519(test,)X
+1673(we)X
+1790(compare)X
+2090(the)X
+432 1638(performance)N
+859(to)X
+941(that)X
+1081(of)X
+1168(the)X
+2 f
+1286(hsearch)X
+1 f
+1560(routines.)X
+604 1752(For)N
+760(both)X
+947(suites,)X
+1194(two)X
+1358(different)X
+1679(databases)X
+2031(were)X
+432 1840(used.)N
+656(The)X
+818(\256rst)X
+979(is)X
+1069(the)X
+1204(dictionary)X
+1566(database)X
+1880(described)X
+432 1928(previously.)N
+836(The)X
+987(second)X
+1236(was)X
+1386(constructed)X
+1781(from)X
+1962(a)X
+2023(pass-)X
+432 2016(word)N
+647(\256le)X
+799(with)X
+990(approximately)X
+1502(300)X
+1671(accounts.)X
+2041(Two)X
+432 2104(records)N
+700(were)X
+887(constructed)X
+1287(for)X
+1411(each)X
+1589(account.)X
+1909(The)X
+2064(\256rst)X
+432 2192(used)N
+604(the)X
+727(logname)X
+1028(as)X
+1120(the)X
+1243(key)X
+1384(and)X
+1525(the)X
+1648(remainder)X
+1999(of)X
+2090(the)X
+432 2280(password)N
+768(entry)X
+965(for)X
+1091(the)X
+1221(data.)X
+1427(The)X
+1584(second)X
+1839(was)X
+1996(keyed)X
+432 2368(by)N
+541(uid)X
+672(and)X
+817(contained)X
+1157(the)X
+1283(entire)X
+1494(password)X
+1825(entry)X
+2018(as)X
+2113(its)X
+432 2456(data)N
+589(\256eld.)X
+794(The)X
+942(tests)X
+1107(were)X
+1287(all)X
+1389(run)X
+1518(on)X
+1620(the)X
+1740(HP)X
+1864(9000)X
+2046(with)X
+432 2544(the)N
+574(same)X
+783(con\256guration)X
+1254(previously)X
+1636(described.)X
+2027(Each)X
+432 2632(test)N
+576(was)X
+734(run)X
+874(\256ve)X
+1027(times)X
+1232(and)X
+1380(the)X
+1510(timing)X
+1750(results)X
+1991(of)X
+2090(the)X
+432 2720(runs)N
+602(were)X
+791(averaged.)X
+1154(The)X
+1311(variance)X
+1616(across)X
+1849(the)X
+1979(5)X
+2050(runs)X
+432 2808(was)N
+591(approximately)X
+1088(1%)X
+1229(of)X
+1330(the)X
+1462(average)X
+1746(yielding)X
+2041(95%)X
+432 2896(con\256dence)N
+800(intervals)X
+1096(of)X
+1183(approximately)X
+1666(2%.)X
+3 f
+1021 3050(Disk)N
+1196(Based)X
+1420(Tests)X
+1 f
+604 3182(In)N
+693(these)X
+880(tests,)X
+1064(we)X
+1180(use)X
+1308(a)X
+1365(bucket)X
+1600(size)X
+1746(of)X
+1834(1024)X
+2015(and)X
+2152(a)X
+432 3270(\256ll)N
+540(factor)X
+748(of)X
+835(32.)X
+3 f
+432 3384(create)N
+663(test)X
+1 f
+547 3498(The)N
+703(keys)X
+881(are)X
+1011(entered)X
+1279(into)X
+1433(the)X
+1561(hash)X
+1738(table,)X
+1944(and)X
+2090(the)X
+547 3586(\256le)N
+669(is)X
+742(\257ushed)X
+993(to)X
+1075(disk.)X
+3 f
+432 3700(read)N
+608(test)X
+1 f
+547 3814(A)N
+640(lookup)X
+897(is)X
+984(performed)X
+1353(for)X
+1481(each)X
+1663(key)X
+1813(in)X
+1909(the)X
+2041(hash)X
+547 3902(table.)N
+3 f
+432 4016(verify)N
+653(test)X
+1 f
+547 4130(A)N
+640(lookup)X
+897(is)X
+984(performed)X
+1353(for)X
+1481(each)X
+1663(key)X
+1813(in)X
+1909(the)X
+2041(hash)X
+547 4218(table,)N
+759(and)X
+911(the)X
+1045(data)X
+1215(returned)X
+1519(is)X
+1608(compared)X
+1961(against)X
+547 4306(that)N
+687(originally)X
+1018(stored)X
+1234(in)X
+1316(the)X
+1434(hash)X
+1601(table.)X
+3 f
+432 4420(sequential)N
+798(retrieve)X
+1 f
+547 4534(All)N
+674(keys)X
+846(are)X
+970(retrieved)X
+1281(in)X
+1367(sequential)X
+1716(order)X
+1910(from)X
+2090(the)X
+547 4622(hash)N
+724(table.)X
+950(The)X
+2 f
+1105(ndbm)X
+1 f
+1313(interface)X
+1625(allows)X
+1863(sequential)X
+547 4710(retrieval)N
+848(of)X
+948(the)X
+1079(keys)X
+1259(from)X
+1448(the)X
+1578(database,)X
+1907(but)X
+2041(does)X
+547 4798(not)N
+701(return)X
+945(the)X
+1094(data)X
+1279(associated)X
+1660(with)X
+1853(each)X
+2052(key.)X
+547 4886(Therefore,)N
+929(we)X
+1067(compare)X
+1388(the)X
+1530(performance)X
+1980(of)X
+2090(the)X
+547 4974(new)N
+703(package)X
+989(to)X
+1073(two)X
+1215(different)X
+1514(runs)X
+1674(of)X
+2 f
+1763(ndbm)X
+1 f
+1941(.)X
+2002(In)X
+2090(the)X
+547 5062(\256rst)N
+697(case,)X
+2 f
+882(ndbm)X
+1 f
+1086(returns)X
+1335(only)X
+1503(the)X
+1627(keys)X
+1800(while)X
+2003(in)X
+2090(the)X
+547 5150(second,)N
+2 f
+823(ndbm)X
+1 f
+1034(returns)X
+1290(both)X
+1465(the)X
+1596(keys)X
+1776(and)X
+1924(the)X
+2054(data)X
+547 5238(\(requiring)N
+894(a)X
+956(second)X
+1204(call)X
+1345(to)X
+1432(the)X
+1555(library\).)X
+1861(There)X
+2074(is)X
+2152(a)X
+547 5326(single)N
+764(run)X
+897(for)X
+1017(the)X
+1141(new)X
+1300(library)X
+1539(since)X
+1729(it)X
+1798(returns)X
+2046(both)X
+547 5414(the)N
+665(key)X
+801(and)X
+937(the)X
+1055(data.)X
+3 f
+3014 538(In-Memory)N
+3431(Test)X
+1 f
+2590 670(This)N
+2757(test)X
+2892(uses)X
+3054(a)X
+3114(bucket)X
+3352(size)X
+3501(of)X
+3592(256)X
+3736(and)X
+3876(a)X
+3936(\256ll)X
+4048(fac-)X
+2418 758(tor)N
+2527(of)X
+2614(8.)X
+3 f
+2418 872(create/read)N
+2827(test)X
+1 f
+2533 986(In)N
+2627(this)X
+2769(test,)X
+2927(a)X
+2989(hash)X
+3162(table)X
+3344(is)X
+3423(created)X
+3682(by)X
+3788(inserting)X
+4094(all)X
+2533 1074(the)N
+2660(key/data)X
+2961(pairs.)X
+3186(Then)X
+3380(a)X
+3445(keyed)X
+3666(retrieval)X
+3963(is)X
+4044(per-)X
+2533 1162(formed)N
+2801(for)X
+2931(each)X
+3115(pair,)X
+3295(and)X
+3446(the)X
+3579(hash)X
+3761(table)X
+3952(is)X
+4040(des-)X
+2533 1250(troyed.)N
+3 f
+2938 1404(Performance)N
+3405(Results)X
+1 f
+2590 1536(Figures)N
+2866(8a)X
+2978(and)X
+3130(8b)X
+3246(show)X
+3451(the)X
+3585(user)X
+3755(time,)X
+3952(system)X
+2418 1624(time,)N
+2608(and)X
+2752(elapsed)X
+3021(time)X
+3191(for)X
+3312(each)X
+3487(test)X
+3625(for)X
+3746(both)X
+3915(the)X
+4040(new)X
+2418 1712(implementation)N
+2951(and)X
+3098(the)X
+3227(old)X
+3360(implementation)X
+3893(\()X
+2 f
+3920(hsearch)X
+1 f
+2418 1800(or)N
+2 f
+2528(ndbm)X
+1 f
+2706(,)X
+2769(whichever)X
+3147(is)X
+3243(appropriate\))X
+3678(as)X
+3787(well)X
+3967(as)X
+4076(the)X
+2418 1888(improvement.)N
+2929(The)X
+3098(improvement)X
+3569(is)X
+3666(expressed)X
+4027(as)X
+4138(a)X
+2418 1976(percentage)N
+2787(of)X
+2874(the)X
+2992(old)X
+3114(running)X
+3383(time:)X
+0 f
+8 s
+2418 2275(%)N
+2494(=)X
+2570(100)X
+2722(*)X
+2798 -0.4219(\(old_time)AX
+3178(-)X
+3254 -0.4219(new_time\))AX
+3634(/)X
+3710(old_time)X
+1 f
+10 s
+2590 2600(In)N
+2700(nearly)X
+2944(all)X
+3067(cases,)X
+3299(the)X
+3439(new)X
+3615(routines)X
+3915(perform)X
+2418 2688(better)N
+2628(than)X
+2793(the)X
+2918(old)X
+3047(routines)X
+3332(\(both)X
+2 f
+3527(hsearch)X
+1 f
+3807(and)X
+2 f
+3949(ndbm)X
+1 f
+4127(\).)X
+2418 2776(Although)N
+2755(the)X
+3 f
+2888(create)X
+1 f
+3134(tests)X
+3311(exhibit)X
+3567(superior)X
+3864(user)X
+4032(time)X
+2418 2864(performance,)N
+2869(the)X
+2991(test)X
+3126(time)X
+3292(is)X
+3369(dominated)X
+3731(by)X
+3834(the)X
+3955(cost)X
+4107(of)X
+2418 2952(writing)N
+2677(the)X
+2803(actual)X
+3023(\256le)X
+3153(to)X
+3243(disk.)X
+3444(For)X
+3583(the)X
+3709(large)X
+3897(database)X
+2418 3040(\(the)N
+2564(dictionary\),)X
+2957(this)X
+3093(completely)X
+3470(overwhelmed)X
+3927(the)X
+4045(sys-)X
+2418 3128(tem)N
+2570(time.)X
+2783(However,)X
+3129(for)X
+3254(the)X
+3383(small)X
+3587(data)X
+3752(base,)X
+3946(we)X
+4071(see)X
+2418 3216(that)N
+2569(differences)X
+2958(in)X
+3051(both)X
+3224(user)X
+3389(and)X
+3536(system)X
+3788(time)X
+3960(contri-)X
+2418 3304(bute)N
+2576(to)X
+2658(the)X
+2776(superior)X
+3059(performance)X
+3486(of)X
+3573(the)X
+3691(new)X
+3845(package.)X
+2590 3418(The)N
+3 f
+2764(read)X
+1 f
+2920(,)X
+3 f
+2989(verify)X
+1 f
+3190(,)X
+3259(and)X
+3 f
+3424(sequential)X
+1 f
+3818(results)X
+4075(are)X
+2418 3506(deceptive)N
+2758(for)X
+2883(the)X
+3012(small)X
+3216(database)X
+3524(since)X
+3720(the)X
+3849(entire)X
+4063(test)X
+2418 3594(ran)N
+2551(in)X
+2643(under)X
+2856(a)X
+2922(second.)X
+3215(However,)X
+3560(on)X
+3669(the)X
+3796(larger)X
+4013(data-)X
+2418 3682(base)N
+2590(the)X
+3 f
+2716(read)X
+1 f
+2900(and)X
+3 f
+3044(verify)X
+1 f
+3273(tests)X
+3443(bene\256t)X
+3689(from)X
+3873(the)X
+3999(cach-)X
+2418 3770(ing)N
+2546(of)X
+2639(buckets)X
+2910(in)X
+2998(the)X
+3122(new)X
+3282(package)X
+3571(to)X
+3658(improve)X
+3950(perfor-)X
+2418 3858(mance)N
+2666(by)X
+2784(over)X
+2965(80%.)X
+3169(Since)X
+3384(the)X
+3519(\256rst)X
+3 f
+3680(sequential)X
+1 f
+4063(test)X
+2418 3946(does)N
+2598(not)X
+2733(require)X
+2 f
+2994(ndbm)X
+1 f
+3205(to)X
+3299(return)X
+3523(the)X
+3653(data)X
+3819(values,)X
+4076(the)X
+2418 4034(user)N
+2573(time)X
+2735(is)X
+2808(lower)X
+3011(than)X
+3169(for)X
+3283(the)X
+3401(new)X
+3555(package.)X
+3879(However)X
+2418 4122(when)N
+2613(we)X
+2728(require)X
+2977(both)X
+3139(packages)X
+3454(to)X
+3536(return)X
+3748(data,)X
+3922(the)X
+4040(new)X
+2418 4210(package)N
+2702(excels)X
+2923(in)X
+3005(all)X
+3105(three)X
+3286(timings.)X
+2590 4324(The)N
+2773(small)X
+3003(database)X
+3337(runs)X
+3532(so)X
+3660(quickly)X
+3957(in)X
+4076(the)X
+2418 4412(memory-resident)N
+3000(case)X
+3173(that)X
+3326(the)X
+3457(results)X
+3699(are)X
+3831(uninterest-)X
+2418 4500(ing.)N
+2589(However,)X
+2933(for)X
+3056(the)X
+3183(larger)X
+3400(database)X
+3706(the)X
+3833(new)X
+3995(pack-)X
+2418 4588(age)N
+2567(pays)X
+2751(a)X
+2824(small)X
+3033(penalty)X
+3305(in)X
+3403(system)X
+3661(time)X
+3839(because)X
+4130(it)X
+2418 4676(limits)N
+2636(its)X
+2748(main)X
+2944(memory)X
+3247(utilization)X
+3607(and)X
+3759(swaps)X
+3991(pages)X
+2418 4764(out)N
+2550(to)X
+2642(temporary)X
+3002(storage)X
+3264(in)X
+3356(the)X
+3484(\256le)X
+3616(system)X
+3868(while)X
+4076(the)X
+2 f
+2418 4852(hsearch)N
+1 f
+2698(package)X
+2988(requires)X
+3273(that)X
+3419(the)X
+3543(application)X
+3924(allocate)X
+2418 4940(enough)N
+2692(space)X
+2909(for)X
+3041(all)X
+3159(key/data)X
+3468(pair.)X
+3670(However,)X
+4022(even)X
+2418 5028(with)N
+2600(the)X
+2738(system)X
+3000(time)X
+3182(penalty,)X
+3477(the)X
+3614(resulting)X
+3933(elapsed)X
+2418 5116(time)N
+2580(improves)X
+2898(by)X
+2998(over)X
+3161(50%.)X
+3 f
+432 5960(10)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+11 p
+%%Page: 11 11
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+10 f
+908 454(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+1379 546(hash)N
+1652(ndbm)X
+1950(%change)X
+1 f
+10 f
+908 550(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 642(CREATE)N
+10 f
+908 646(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 738(user)N
+1424(6.4)X
+1671(12.2)X
+2073(48)X
+1157 826(sys)N
+1384(32.5)X
+1671(34.7)X
+2113(6)X
+3 f
+1006 914(elapsed)N
+10 f
+1310 922(c)N
+890(c)Y
+810(c)Y
+730(c)Y
+3 f
+1384 914(90.4)N
+10 f
+1581 922(c)N
+890(c)Y
+810(c)Y
+730(c)Y
+3 f
+1671 914(99.6)N
+10 f
+1883 922(c)N
+890(c)Y
+810(c)Y
+730(c)Y
+3 f
+2113 914(9)N
+1 f
+10 f
+908 910(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+908 926(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 1010(READ)N
+10 f
+908 1014(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 1106(user)N
+1424(3.4)X
+1711(6.1)X
+2073(44)X
+1157 1194(sys)N
+1424(1.2)X
+1671(15.3)X
+2073(92)X
+3 f
+1006 1282(elapsed)N
+10 f
+1310 1290(c)N
+1258(c)Y
+1178(c)Y
+1098(c)Y
+3 f
+1424 1282(4.0)N
+10 f
+1581 1290(c)N
+1258(c)Y
+1178(c)Y
+1098(c)Y
+3 f
+1671 1282(21.2)N
+10 f
+1883 1290(c)N
+1258(c)Y
+1178(c)Y
+1098(c)Y
+3 f
+2073 1282(81)N
+1 f
+10 f
+908 1278(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+908 1294(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 1378(VERIFY)N
+10 f
+908 1382(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 1474(user)N
+1424(3.5)X
+1711(6.3)X
+2073(44)X
+1157 1562(sys)N
+1424(1.2)X
+1671(15.3)X
+2073(92)X
+3 f
+1006 1650(elapsed)N
+10 f
+1310 1658(c)N
+1626(c)Y
+1546(c)Y
+1466(c)Y
+3 f
+1424 1650(4.0)N
+10 f
+1581 1658(c)N
+1626(c)Y
+1546(c)Y
+1466(c)Y
+3 f
+1671 1650(21.2)N
+10 f
+1883 1658(c)N
+1626(c)Y
+1546(c)Y
+1466(c)Y
+3 f
+2073 1650(81)N
+1 f
+10 f
+908 1646(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+908 1662(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 1746(SEQUENTIAL)N
+10 f
+908 1750(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 1842(user)N
+1424(2.7)X
+1711(1.9)X
+2046(-42)X
+1157 1930(sys)N
+1424(0.7)X
+1711(3.9)X
+2073(82)X
+3 f
+1006 2018(elapsed)N
+10 f
+1310 2026(c)N
+1994(c)Y
+1914(c)Y
+1834(c)Y
+3 f
+1424 2018(3.0)N
+10 f
+1581 2026(c)N
+1994(c)Y
+1914(c)Y
+1834(c)Y
+3 f
+1711 2018(5.0)N
+10 f
+1883 2026(c)N
+1994(c)Y
+1914(c)Y
+1834(c)Y
+3 f
+2073 2018(40)N
+1 f
+10 f
+908 2014(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+908 2030(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+948 2114(SEQUENTIAL)N
+1467(\(with)X
+1656(data)X
+1810(retrieval\))X
+10 f
+908 2118(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1125 2210(user)N
+1424(2.7)X
+1711(8.2)X
+2073(67)X
+1157 2298(sys)N
+1424(0.7)X
+1711(4.3)X
+2073(84)X
+3 f
+1006 2386(elapsed)N
+1424(3.0)X
+1671(12.0)X
+2073(75)X
+1 f
+10 f
+908 2390(i)N
+927(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+899 2394(c)N
+2378(c)Y
+2298(c)Y
+2218(c)Y
+2138(c)Y
+2058(c)Y
+1978(c)Y
+1898(c)Y
+1818(c)Y
+1738(c)Y
+1658(c)Y
+1578(c)Y
+1498(c)Y
+1418(c)Y
+1338(c)Y
+1258(c)Y
+1178(c)Y
+1098(c)Y
+1018(c)Y
+938(c)Y
+858(c)Y
+778(c)Y
+698(c)Y
+618(c)Y
+538(c)Y
+1310 2394(c)N
+2362(c)Y
+2282(c)Y
+2202(c)Y
+1581 2394(c)N
+2362(c)Y
+2282(c)Y
+2202(c)Y
+1883 2394(c)N
+2362(c)Y
+2282(c)Y
+2202(c)Y
+2278 2394(c)N
+2378(c)Y
+2298(c)Y
+2218(c)Y
+2138(c)Y
+2058(c)Y
+1978(c)Y
+1898(c)Y
+1818(c)Y
+1738(c)Y
+1658(c)Y
+1578(c)Y
+1498(c)Y
+1418(c)Y
+1338(c)Y
+1258(c)Y
+1178(c)Y
+1098(c)Y
+1018(c)Y
+938(c)Y
+858(c)Y
+778(c)Y
+698(c)Y
+618(c)Y
+538(c)Y
+905 2574(i)N
+930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+1318 2666(hash)N
+1585(hsearch)X
+1953(%change)X
+1 f
+10 f
+905 2670(i)N
+930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+945 2762(CREATE/READ)N
+10 f
+905 2766(i)N
+930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+1064 2858(user)N
+1343(6.6)X
+1642(17.2)X
+2096(62)X
+1096 2946(sys)N
+1343(1.1)X
+1682(0.3)X
+2029(-266)X
+3 f
+945 3034(elapsed)N
+1343(7.8)X
+1642(17.0)X
+2096(54)X
+1 f
+10 f
+905 3038(i)N
+930(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+896 3050(c)N
+2978(c)Y
+2898(c)Y
+2818(c)Y
+2738(c)Y
+2658(c)Y
+1249 3034(c)N
+3010(c)Y
+2930(c)Y
+2850(c)Y
+1520 3034(c)N
+3010(c)Y
+2930(c)Y
+2850(c)Y
+1886 3034(c)N
+3010(c)Y
+2930(c)Y
+2850(c)Y
+2281 3050(c)N
+2978(c)Y
+2898(c)Y
+2818(c)Y
+2738(c)Y
+2658(c)Y
+3 f
+720 3174(Figure)N
+967(8a:)X
+1 f
+1094(Timing)X
+1349(results)X
+1578(for)X
+1692(the)X
+1810(dictionary)X
+2155(database.)X
+10 f
+720 3262 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+1407 3504(Conclusion)N
+1 f
+892 3636(This)N
+1063(paper)X
+1271(has)X
+1407(presented)X
+1744(the)X
+1871(design,)X
+2129(implemen-)X
+720 3724(tation)N
+928(and)X
+1070(performance)X
+1503(of)X
+1596(a)X
+1658(new)X
+1818(hashing)X
+2093(package)X
+2382(for)X
+720 3812(UNIX.)N
+993(The)X
+1150(new)X
+1316(package)X
+1612(provides)X
+1919(a)X
+1986(superset)X
+2280(of)X
+2378(the)X
+720 3900(functionality)N
+1159(of)X
+1255(existing)X
+1537(hashing)X
+1815(packages)X
+2139(and)X
+2284(incor-)X
+720 3988(porates)N
+975(additional)X
+1318(features)X
+1596(such)X
+1766(as)X
+1855(large)X
+2038(key)X
+2176(handling,)X
+720 4076(user)N
+876(de\256ned)X
+1134(hash)X
+1302(functions,)X
+1641(multiple)X
+1928(hash)X
+2096(tables,)X
+2324(vari-)X
+720 4164(able)N
+894(sized)X
+1099(pages,)X
+1342(and)X
+1498(linear)X
+1721(hashing.)X
+2050(In)X
+2156(nearly)X
+2396(all)X
+720 4252(cases,)N
+954(the)X
+1096(new)X
+1274(package)X
+1582(provides)X
+1902(improved)X
+2252(perfor-)X
+720 4340(mance)N
+974(on)X
+1098(the)X
+1240(order)X
+1454(of)X
+1565(50-80%)X
+1863(for)X
+2001(the)X
+2142(workloads)X
+720 4428(shown.)N
+990(Applications)X
+1420(such)X
+1588(as)X
+1676(the)X
+1794(loader,)X
+2035(compiler,)X
+2360(and)X
+720 4516(mail,)N
+921(which)X
+1156(currently)X
+1485(implement)X
+1866(their)X
+2051(own)X
+2227(hashing)X
+720 4604(routines,)N
+1032(should)X
+1279(be)X
+1389(modi\256ed)X
+1706(to)X
+1801(use)X
+1941(the)X
+2072(generic)X
+2342(rou-)X
+720 4692(tines.)N
+892 4806(This)N
+1087(hashing)X
+1389(package)X
+1705(is)X
+1810(one)X
+1978(access)X
+2236(method)X
+720 4894(which)N
+953(is)X
+1043(part)X
+1205(of)X
+1309(a)X
+1382(generic)X
+1656(database)X
+1970(access)X
+2212(package)X
+720 4982(being)N
+955(developed)X
+1342(at)X
+1457(the)X
+1612(University)X
+2007(of)X
+2131(California,)X
+720 5070(Berkeley.)N
+1089(It)X
+1177(will)X
+1340(include)X
+1614(a)X
+1688(btree)X
+1887(access)X
+2131(method)X
+2409(as)X
+720 5158(well)N
+916(as)X
+1041(\256xed)X
+1259(and)X
+1433(variable)X
+1750(length)X
+2007(record)X
+2270(access)X
+720 5246(methods)N
+1024(in)X
+1119(addition)X
+1414(to)X
+1509(the)X
+1640(hashed)X
+1896(support)X
+2168(presented)X
+720 5334(here.)N
+948(All)X
+1099(of)X
+1215(the)X
+1361(access)X
+1615(methods)X
+1934(are)X
+2081(based)X
+2312(on)X
+2440(a)X
+720 5422(key/data)N
+1037(pair)X
+1207(interface)X
+1533(and)X
+1693(appear)X
+1952(identical)X
+2272(to)X
+2378(the)X
+720 5510(application)N
+1121(layer,)X
+1347(allowing)X
+1671(application)X
+2071(implementa-)X
+720 5598(tions)N
+906(to)X
+999(be)X
+1106(largely)X
+1360(independent)X
+1783(of)X
+1881(the)X
+2010(database)X
+2318(type.)X
+720 5686(The)N
+873(package)X
+1165(is)X
+1246(expected)X
+1560(to)X
+1650(be)X
+1754(an)X
+1858(integral)X
+2131(part)X
+2284(of)X
+2378(the)X
+2706 538(4.4BSD)N
+3006(system,)X
+3293(with)X
+3479(various)X
+3759(standard)X
+4075(applications)X
+2706 626(such)N
+2879(as)X
+2972(more\(1\),)X
+3277(sort\(1\))X
+3517(and)X
+3659(vi\(1\))X
+3841(based)X
+4050(on)X
+4156(it.)X
+4266(While)X
+2706 714(the)N
+2833(current)X
+3089(design)X
+3326(does)X
+3501(not)X
+3631(support)X
+3899(multi-user)X
+4256(access)X
+2706 802(or)N
+2804(transactions,)X
+3238(they)X
+3407(could)X
+3616(be)X
+3723(incorporated)X
+4159(relatively)X
+2706 890(easily.)N
+10 f
+2894 938(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+3365 1030(hash)N
+3638(ndbm)X
+3936(%change)X
+1 f
+10 f
+2894 1034(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 1126(CREATE)N
+10 f
+2894 1130(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 1222(user)N
+3390(0.2)X
+3677(0.4)X
+4079(50)X
+3143 1310(sys)N
+3390(0.1)X
+3677(1.0)X
+4079(90)X
+3 f
+2992 1398(elapsed)N
+10 f
+3296 1406(c)N
+1374(c)Y
+1294(c)Y
+1214(c)Y
+3 f
+3390 1398(0)N
+10 f
+3567 1406(c)N
+1374(c)Y
+1294(c)Y
+1214(c)Y
+3 f
+3677 1398(3.2)N
+10 f
+3869 1406(c)N
+1374(c)Y
+1294(c)Y
+1214(c)Y
+3 f
+4039 1398(100)N
+1 f
+10 f
+2894 1394(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2894 1410(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 1494(READ)N
+10 f
+2894 1498(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 1590(user)N
+3390(0.1)X
+3677(0.1)X
+4119(0)X
+3143 1678(sys)N
+3390(0.1)X
+3677(0.4)X
+4079(75)X
+3 f
+2992 1766(elapsed)N
+10 f
+3296 1774(c)N
+1742(c)Y
+1662(c)Y
+1582(c)Y
+3 f
+3390 1766(0.0)N
+10 f
+3567 1774(c)N
+1742(c)Y
+1662(c)Y
+1582(c)Y
+3 f
+3677 1766(0.0)N
+10 f
+3869 1774(c)N
+1742(c)Y
+1662(c)Y
+1582(c)Y
+3 f
+4119 1766(0)N
+1 f
+10 f
+2894 1762(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2894 1778(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 1862(VERIFY)N
+10 f
+2894 1866(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 1958(user)N
+3390(0.1)X
+3677(0.2)X
+4079(50)X
+3143 2046(sys)N
+3390(0.1)X
+3677(0.3)X
+4079(67)X
+3 f
+2992 2134(elapsed)N
+10 f
+3296 2142(c)N
+2110(c)Y
+2030(c)Y
+1950(c)Y
+3 f
+3390 2134(0.0)N
+10 f
+3567 2142(c)N
+2110(c)Y
+2030(c)Y
+1950(c)Y
+3 f
+3677 2134(0.0)N
+10 f
+3869 2142(c)N
+2110(c)Y
+2030(c)Y
+1950(c)Y
+3 f
+4119 2134(0)N
+1 f
+10 f
+2894 2130(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2894 2146(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 2230(SEQUENTIAL)N
+10 f
+2894 2234(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 2326(user)N
+3390(0.1)X
+3677(0.0)X
+4012(-100)X
+3143 2414(sys)N
+3390(0.1)X
+3677(0.1)X
+4119(0)X
+3 f
+2992 2502(elapsed)N
+10 f
+3296 2510(c)N
+2478(c)Y
+2398(c)Y
+2318(c)Y
+3 f
+3390 2502(0.0)N
+10 f
+3567 2510(c)N
+2478(c)Y
+2398(c)Y
+2318(c)Y
+3 f
+3677 2502(0.0)N
+10 f
+3869 2510(c)N
+2478(c)Y
+2398(c)Y
+2318(c)Y
+3 f
+4119 2502(0)N
+1 f
+10 f
+2894 2498(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2894 2514(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2934 2598(SEQUENTIAL)N
+3453(\(with)X
+3642(data)X
+3796(retrieval\))X
+10 f
+2894 2602(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3111 2694(user)N
+3390(0.1)X
+3677(0.1)X
+4119(0)X
+3143 2782(sys)N
+3390(0.1)X
+3677(0.1)X
+4119(0)X
+3 f
+2992 2870(elapsed)N
+3390(0.0)X
+3677(0.0)X
+4119(0)X
+1 f
+10 f
+2894 2874(i)N
+2913(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2885 2878(c)N
+2862(c)Y
+2782(c)Y
+2702(c)Y
+2622(c)Y
+2542(c)Y
+2462(c)Y
+2382(c)Y
+2302(c)Y
+2222(c)Y
+2142(c)Y
+2062(c)Y
+1982(c)Y
+1902(c)Y
+1822(c)Y
+1742(c)Y
+1662(c)Y
+1582(c)Y
+1502(c)Y
+1422(c)Y
+1342(c)Y
+1262(c)Y
+1182(c)Y
+1102(c)Y
+1022(c)Y
+3296 2878(c)N
+2846(c)Y
+2766(c)Y
+2686(c)Y
+3567 2878(c)N
+2846(c)Y
+2766(c)Y
+2686(c)Y
+3869 2878(c)N
+2846(c)Y
+2766(c)Y
+2686(c)Y
+4264 2878(c)N
+2862(c)Y
+2782(c)Y
+2702(c)Y
+2622(c)Y
+2542(c)Y
+2462(c)Y
+2382(c)Y
+2302(c)Y
+2222(c)Y
+2142(c)Y
+2062(c)Y
+1982(c)Y
+1902(c)Y
+1822(c)Y
+1742(c)Y
+1662(c)Y
+1582(c)Y
+1502(c)Y
+1422(c)Y
+1342(c)Y
+1262(c)Y
+1182(c)Y
+1102(c)Y
+1022(c)Y
+2891 3058(i)N
+2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+3304 3150(hash)N
+3571(hsearch)X
+3939(%change)X
+1 f
+10 f
+2891 3154(i)N
+2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2931 3246(CREATE/READ)N
+10 f
+2891 3250(i)N
+2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+3050 3342(user)N
+3329(0.3)X
+3648(0.4)X
+4048(25)X
+3082 3430(sys)N
+3329(0.0)X
+3648(0.0)X
+4088(0)X
+3 f
+2931 3518(elapsed)N
+3329(0.0)X
+3648(0.0)X
+4088(0)X
+1 f
+10 f
+2891 3522(i)N
+2916(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2882 3534(c)N
+3462(c)Y
+3382(c)Y
+3302(c)Y
+3222(c)Y
+3142(c)Y
+3235 3518(c)N
+3494(c)Y
+3414(c)Y
+3334(c)Y
+3506 3518(c)N
+3494(c)Y
+3414(c)Y
+3334(c)Y
+3872 3518(c)N
+3494(c)Y
+3414(c)Y
+3334(c)Y
+4267 3534(c)N
+3462(c)Y
+3382(c)Y
+3302(c)Y
+3222(c)Y
+3142(c)Y
+3 f
+2706 3658(Figure)N
+2953(8b:)X
+1 f
+3084(Timing)X
+3339(results)X
+3568(for)X
+3682(the)X
+3800(password)X
+4123(database.)X
+10 f
+2706 3746 -0.0930(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)AN
+3 f
+3396 3988(References)N
+1 f
+2706 4120([ATT79])N
+3058(AT&T,)X
+3358(DBM\(3X\),)X
+2 f
+3773(Unix)X
+3990(Programmer's)X
+2878 4208(Manual,)N
+3194(Seventh)X
+3491(Edition,)X
+3793(Volume)X
+4085(1)X
+1 f
+(,)S
+4192(January,)X
+2878 4296(1979.)N
+2706 4472([ATT85])N
+3027(AT&T,)X
+3296(HSEARCH\(BA_LIB\),)X
+2 f
+4053(Unix)X
+4239(System)X
+2878 4560(User's)N
+3112(Manual,)X
+3401(System)X
+3644(V.3)X
+1 f
+3753(,)X
+3793(pp.)X
+3913(506-508,)X
+4220(1985.)X
+2706 4736([BRE73])N
+3025(Brent,)X
+3253(Richard)X
+3537(P.,)X
+3651(``Reducing)X
+4041(the)X
+4168(Retrieval)X
+2878 4824(Time)N
+3071(of)X
+3162(Scatter)X
+3409(Storage)X
+3678(Techniques'',)X
+2 f
+4146(Commun-)X
+2878 4912(ications)N
+3175(of)X
+3281(the)X
+3422(ACM)X
+1 f
+3591(,)X
+3654(Volume)X
+3955(16,)X
+4098(No.)X
+4259(2,)X
+4362(pp.)X
+2878 5000(105-109,)N
+3185(February,)X
+3515(1973.)X
+2706 5176([BSD86])N
+3055(NDBM\(3\),)X
+2 f
+3469(4.3BSD)X
+3775(Unix)X
+3990(Programmer's)X
+2878 5264(Manual)N
+3155(Reference)X
+3505(Guide)X
+1 f
+3701(,)X
+3749(University)X
+4114(of)X
+4208(Califor-)X
+2878 5352(nia,)N
+3016(Berkeley,)X
+3346(1986.)X
+2706 5528([ENB88])N
+3025(Enbody,)X
+3319(R.)X
+3417(J.,)X
+3533(Du,)X
+3676(H.)X
+3779(C.,)X
+3897(``Dynamic)X
+4270(Hash-)X
+2878 5616(ing)N
+3034(Schemes'',)X
+2 f
+3427(ACM)X
+3630(Computing)X
+4019(Surveys)X
+1 f
+4269(,)X
+4322(Vol.)X
+2878 5704(20,)N
+2998(No.)X
+3136(2,)X
+3216(pp.)X
+3336(85-113,)X
+3603(June)X
+3770(1988.)X
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4384(11)X
+
+12 p
+%%Page: 12 12
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 258(A)N
+510(New)X
+682(Hashing)X
+985(Package)X
+1290(for)X
+1413(UNIX)X
+3663(Seltzer)X
+3920(&)X
+4007(Yigit)X
+1 f
+432 538([FAG79])N
+776(Ronald)X
+1057(Fagin,)X
+1308(Jurg)X
+1495(Nievergelt,)X
+1903(Nicholas)X
+604 626(Pippenger,)N
+1003(H.)X
+1135(Raymond)X
+1500(Strong,)X
+1787(``Extendible)X
+604 714(Hashing)N
+901(--)X
+985(A)X
+1073(Fast)X
+1236(Access)X
+1493(Method)X
+1771(for)X
+1894(Dynamic)X
+604 802(Files'',)N
+2 f
+855(ACM)X
+1046(Transactions)X
+1485(on)X
+1586(Database)X
+1914(Systems)X
+1 f
+2168(,)X
+604 890(Volume)N
+882(4,)X
+962(No.)X
+1100(3.,)X
+1200(September)X
+1563(1979,)X
+1763(pp)X
+1863(315-34)X
+432 1066([KNU68],)N
+802(Knuth,)X
+1064(D.E.,)X
+2 f
+1273(The)X
+1434(Art)X
+1577(of)X
+1680(Computer)X
+2041(Pro-)X
+604 1154(gramming)N
+971(Vol.)X
+1140(3:)X
+1245(Sorting)X
+1518(and)X
+1676(Searching)X
+1 f
+2001(,)X
+2058(sec-)X
+604 1242(tions)N
+779(6.3-6.4,)X
+1046(pp)X
+1146(481-550.)X
+432 1418([LAR78])N
+747(Larson,)X
+1011(Per-Ake,)X
+1319(``Dynamic)X
+1687(Hashing'',)X
+2 f
+2048(BIT)X
+1 f
+(,)S
+604 1506(Vol.)N
+764(18,)X
+884(1978,)X
+1084(pp.)X
+1204(184-201.)X
+432 1682([LAR88])N
+752(Larson,)X
+1021(Per-Ake,)X
+1335(``Dynamic)X
+1709(Hash)X
+1900(Tables'',)X
+2 f
+604 1770(Communications)N
+1183(of)X
+1281(the)X
+1415(ACM)X
+1 f
+1584(,)X
+1640(Volume)X
+1934(31,)X
+2070(No.)X
+604 1858(4.,)N
+704(April)X
+893(1988,)X
+1093(pp)X
+1193(446-457.)X
+432 2034([LIT80])N
+731(Witold,)X
+1013(Litwin,)X
+1286(``Linear)X
+1590(Hashing:)X
+1939(A)X
+2036(New)X
+604 2122(Tool)N
+786(for)X
+911(File)X
+1065(and)X
+1211(Table)X
+1424(Addressing'',)X
+2 f
+1893(Proceed-)X
+604 2210(ings)N
+761(of)X
+847(the)X
+969(6th)X
+1095(International)X
+1540(Conference)X
+1933(on)X
+2036(Very)X
+604 2298(Large)N
+815(Databases)X
+1 f
+1153(,)X
+1193(1980.)X
+432 2474([NEL90])N
+743(Nelson,)X
+1011(Philip)X
+1222(A.,)X
+2 f
+1341(Gdbm)X
+1558(1.4)X
+1679(source)X
+1913(distribu-)X
+604 2562(tion)N
+748(and)X
+888(README)X
+1 f
+1209(,)X
+1249(August)X
+1500(1990.)X
+432 2738([THOM90])N
+840(Ken)X
+1011(Thompson,)X
+1410(private)X
+1670(communication,)X
+604 2826(Nov.)N
+782(1990.)X
+432 3002([TOR87])N
+790(Torek,)X
+1066(C.,)X
+1222(``Re:)X
+1470(dbm.a)X
+1751(and)X
+1950(ndbm.a)X
+604 3090(archives'',)N
+2 f
+966(USENET)X
+1279(newsgroup)X
+1650(comp.unix)X
+1 f
+2002(1987.)X
+432 3266([TOR88])N
+760(Torek,)X
+1006(C.,)X
+1133(``Re:)X
+1351(questions)X
+1686(regarding)X
+2027(data-)X
+604 3354(bases)N
+826(created)X
+1106(with)X
+1295(dbm)X
+1484(and)X
+1647(ndbm)X
+1876(routines'')X
+2 f
+604 3442(USENET)N
+937(newsgroup)X
+1328(comp.unix.questions)X
+1 f
+1982(,)X
+2041(June)X
+604 3530(1988.)N
+432 3706([WAL84])N
+773(Wales,)X
+1018(R.,)X
+1135(``Discussion)X
+1564(of)X
+1655("dbm")X
+1887(data)X
+2045(base)X
+604 3794(system'',)N
+2 f
+973(USENET)X
+1339(newsgroup)X
+1762(unix.wizards)X
+1 f
+2168(,)X
+604 3882(January,)N
+894(1984.)X
+432 4058([YIG89])N
+751(Ozan)X
+963(S.)X
+1069(Yigit,)X
+1294(``How)X
+1545(to)X
+1648(Roll)X
+1826(Your)X
+2032(Own)X
+604 4146(Dbm/Ndbm'',)N
+2 f
+1087(unpublished)X
+1504(manuscript)X
+1 f
+(,)S
+1910(Toronto,)X
+604 4234(July,)N
+777(1989)X
+3 f
+432 5960(12)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+13 p
+%%Page: 13 13
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+720 258(Seltzer)N
+977(&)X
+1064(Yigit)X
+3278(A)X
+3356(New)X
+3528(Hashing)X
+3831(Package)X
+4136(for)X
+4259(UNIX)X
+1 f
+720 538(Margo)N
+960(I.)X
+1033(Seltzer)X
+1282(is)X
+1361(a)X
+1423(Ph.D.)X
+1631(student)X
+1887(in)X
+1974(the)X
+2097(Department)X
+720 626(of)N
+823(Electrical)X
+1167(Engineering)X
+1595(and)X
+1747(Computer)X
+2102(Sciences)X
+2418(at)X
+720 714(the)N
+850(University)X
+1220(of)X
+1318(California,)X
+1694(Berkeley.)X
+2055(Her)X
+2207(research)X
+720 802(interests)N
+1017(include)X
+1283(\256le)X
+1415(systems,)X
+1718(databases,)X
+2076(and)X
+2221(transac-)X
+720 890(tion)N
+896(processing)X
+1291(systems.)X
+1636(She)X
+1807(spent)X
+2027(several)X
+2306(years)X
+720 978(working)N
+1026(at)X
+1123(startup)X
+1380(companies)X
+1762(designing)X
+2112(and)X
+2267(imple-)X
+720 1066(menting)N
+1048(\256le)X
+1216(systems)X
+1535(and)X
+1716(transaction)X
+2133(processing)X
+720 1154(software)N
+1026(and)X
+1170(designing)X
+1509(microprocessors.)X
+2103(Ms.)X
+2253(Seltzer)X
+720 1242(received)N
+1057(her)X
+1223(AB)X
+1397(in)X
+1522(Applied)X
+1843(Mathematics)X
+2320(from)X
+720 1330 0.1953(Harvard/Radcliffe)AN
+1325(College)X
+1594(in)X
+1676(1983.)X
+720 1444(In)N
+810(her)X
+936(spare)X
+1129(time,)X
+1313(Margo)X
+1549(can)X
+1683(usually)X
+1936(be)X
+2034(found)X
+2243(prepar-)X
+720 1532(ing)N
+868(massive)X
+1171(quantities)X
+1527(of)X
+1639(food)X
+1831(for)X
+1970(hungry)X
+2242(hoards,)X
+720 1620(studying)N
+1022(Japanese,)X
+1355(or)X
+1449(playing)X
+1716(soccer)X
+1948(with)X
+2116(an)X
+2218(exciting)X
+720 1708(Bay)N
+912(Area)X
+1132(Women's)X
+1507(Soccer)X
+1788(team,)X
+2026(the)X
+2186(Berkeley)X
+720 1796(Bruisers.)N
+720 1910(Ozan)N
+915(\()X
+3 f
+942(Oz)X
+1 f
+1040(\))X
+1092(Yigit)X
+1281(is)X
+1358(currently)X
+1672(a)X
+1732(software)X
+2033(engineer)X
+2334(with)X
+720 1998(the)N
+886(Communications)X
+1499(Research)X
+1861(and)X
+2044(Development)X
+720 2086(group,)N
+948(Computing)X
+1328(Services,)X
+1641(York)X
+1826(University.)X
+2224(His)X
+2355(for-)X
+720 2174(mative)N
+967(years)X
+1166(were)X
+1352(also)X
+1510(spent)X
+1708(at)X
+1795(York,)X
+2009(where)X
+2234(he)X
+2338(held)X
+720 2262(system)N
+985(programmer)X
+1425(and)X
+1583(administrator)X
+2052(positions)X
+2382(for)X
+720 2350(various)N
+995(mixtures)X
+1314(of)X
+1420(of)X
+1526(UNIX)X
+1765(systems)X
+2056(starting)X
+2334(with)X
+720 2438(Berkeley)N
+1031(4.1)X
+1151(in)X
+1233(1982,)X
+1433(while)X
+1631(at)X
+1709(the)X
+1827(same)X
+2012(time)X
+2174(obtaining)X
+720 2526(a)N
+776(degree)X
+1011(in)X
+1093(Computer)X
+1433(Science.)X
+720 2640(In)N
+813(his)X
+931(copious)X
+1205(free)X
+1356(time,)X
+1543(Oz)X
+1662(enjoys)X
+1896(working)X
+2188(on)X
+2293(what-)X
+720 2728(ever)N
+890(software)X
+1197(looks)X
+1400(interesting,)X
+1788(which)X
+2014(often)X
+2209(includes)X
+720 2816(language)N
+1044(interpreters,)X
+1464(preprocessors,)X
+1960(and)X
+2110(lately,)X
+2342(pro-)X
+720 2904(gram)N
+905(generators)X
+1260(and)X
+1396(expert)X
+1617(systems.)X
+720 3018(Oz)N
+836(has)X
+964(authored)X
+1266(several)X
+1515(public-domain)X
+2003(software)X
+2301(tools,)X
+720 3106(including)N
+1069(an)X
+1191(nroff-like)X
+1545(text)X
+1711(formatter)X
+2 f
+2056(proff)X
+1 f
+2257(that)X
+2423(is)X
+720 3194(apparently)N
+1083(still)X
+1226(used)X
+1397(in)X
+1483(some)X
+1676(basement)X
+2002(PCs.)X
+2173(His)X
+2307(latest)X
+720 3282(obsessions)N
+1143(include)X
+1460(the)X
+1639(incredible)X
+2040(programming)X
+720 3370(language)N
+1030(Scheme,)X
+1324(and)X
+1460(Chinese)X
+1738(Brush)X
+1949(painting.)X
+3 f
+720 5960(USENIX)N
+9 f
+1042(-)X
+3 f
+1106(Winter)X
+1371('91)X
+9 f
+1498(-)X
+3 f
+1562(Dallas,)X
+1815(TX)X
+4384(13)X
+
+14 p
+%%Page: 14 14
+0(Courier)xf 0 f
+10 s 10 xH 0 xS 0 f
+3 f
+432 5960(14)N
+2970(USENIX)X
+9 f
+3292(-)X
+3 f
+3356(Winter)X
+3621('91)X
+9 f
+3748(-)X
+3 f
+3812(Dallas,)X
+4065(TX)X
+
+14 p
+%%Trailer
+xt
+
+xs
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/docs/libtp.usenix.ps b/mechglue/src/plugins/kdb/db2/libdb2/docs/libtp.usenix.ps
new file mode 100644
index 000000000..5b5ba6e1b
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/docs/libtp.usenix.ps
@@ -0,0 +1,12340 @@
+%!PS-Adobe-1.0
+%%Creator: utopia:margo (& Seltzer,608-13E,8072,)
+%%Title: stdin (ditroff)
+%%CreationDate: Thu Dec 12 15:32:11 1991
+%%EndComments
+%	@(#)psdit.pro	1.3 4/15/88
+% lib/psdit.pro -- prolog for psdit (ditroff) files
+% Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved.
+% last edit: shore Sat Nov 23 20:28:03 1985
+% RCSID: $Header$
+
+% Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics,
+% 17 Feb, 87.
+
+/$DITroff 140 dict def $DITroff begin
+/fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def
+/xi{0 72 11 mul translate 72 resolution div dup neg scale 0 0 moveto
+ /fontnum 1 def /fontsize 10 def /fontheight 10 def /fontslant 0 def F
+ /pagesave save def}def
+/PB{save /psv exch def currentpoint translate 
+ resolution 72 div dup neg scale 0 0 moveto}def
+/PE{psv restore}def
+/arctoobig 90 def /arctoosmall .05 def
+/m1 matrix def /m2 matrix def /m3 matrix def /oldmat matrix def
+/tan{dup sin exch cos div}def
+/point{resolution 72 div mul}def
+/dround	{transform round exch round exch itransform}def
+/xT{/devname exch def}def
+/xr{/mh exch def /my exch def /resolution exch def}def
+/xp{}def
+/xs{docsave restore end}def
+/xt{}def
+/xf{/fontname exch def /slotno exch def fontnames slotno get fontname eq not
+ {fonts slotno fontname findfont put fontnames slotno fontname put}if}def
+/xH{/fontheight exch def F}def
+/xS{/fontslant exch def F}def
+/s{/fontsize exch def /fontheight fontsize def F}def
+/f{/fontnum exch def F}def
+/F{fontheight 0 le{/fontheight fontsize def}if
+ fonts fontnum get fontsize point 0 0 fontheight point neg 0 0 m1 astore
+ fontslant 0 ne{1 0 fontslant tan 1 0 0 m2 astore m3 concatmatrix}if
+ makefont setfont .04 fontsize point mul 0 dround pop setlinewidth}def
+/X{exch currentpoint exch pop moveto show}def
+/N{3 1 roll moveto show}def
+/Y{exch currentpoint pop exch moveto show}def
+/S{show}def
+/ditpush{}def/ditpop{}def
+/AX{3 -1 roll currentpoint exch pop moveto 0 exch ashow}def
+/AN{4 2 roll moveto 0 exch ashow}def
+/AY{3 -1 roll currentpoint pop exch moveto 0 exch ashow}def
+/AS{0 exch ashow}def
+/MX{currentpoint exch pop moveto}def
+/MY{currentpoint pop exch moveto}def
+/MXY{moveto}def
+/cb{pop}def	% action on unknown char -- nothing for now
+/n{}def/w{}def
+/p{pop showpage pagesave restore /pagesave save def}def
+/Dt{/Dlinewidth exch def}def 1 Dt
+/Ds{/Ddash exch def}def -1 Ds
+/Di{/Dstipple exch def}def 1 Di
+/Dsetlinewidth{2 Dlinewidth mul setlinewidth}def
+/Dsetdash{Ddash 4 eq{[8 12]}{Ddash 16 eq{[32 36]}
+ {Ddash 20 eq{[32 12 8 12]}{[]}ifelse}ifelse}ifelse 0 setdash}def
+/Dstroke{gsave Dsetlinewidth Dsetdash 1 setlinecap stroke grestore
+ currentpoint newpath moveto}def
+/Dl{rlineto Dstroke}def
+/arcellipse{/diamv exch def /diamh exch def oldmat currentmatrix pop
+ currentpoint translate 1 diamv diamh div scale /rad diamh 2 div def
+ currentpoint exch rad add exch rad -180 180 arc oldmat setmatrix}def
+/Dc{dup arcellipse Dstroke}def
+/De{arcellipse Dstroke}def
+/Da{/endv exch def /endh exch def /centerv exch def /centerh exch def
+ /cradius centerv centerv mul centerh centerh mul add sqrt def
+ /eradius endv endv mul endh endh mul add sqrt def
+ /endang endv endh atan def
+ /startang centerv neg centerh neg atan def
+ /sweep startang endang sub dup 0 lt{360 add}if def
+ sweep arctoobig gt
+ {/midang startang sweep 2 div sub def /midrad cradius eradius add 2 div def
+  /midh midang cos midrad mul def /midv midang sin midrad mul def
+  midh neg midv neg endh endv centerh centerv midh midv Da
+  Da}
+ {sweep arctoosmall ge
+  {/controldelt 1 sweep 2 div cos sub 3 sweep 2 div sin mul div 4 mul def
+   centerv neg controldelt mul centerh controldelt mul
+   endv neg controldelt mul centerh add endh add
+   endh controldelt mul centerv add endv add
+   centerh endh add centerv endv add rcurveto Dstroke}
+  {centerh endh add centerv endv add rlineto Dstroke}
+  ifelse}
+ ifelse}def
+/Dpatterns[
+[%cf[widthbits]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000103810000000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0000000000000010>]
+[8<0411040040114000>]
+[8<0204081020408001>]
+[8<0000001038100000>]
+[8<6699996666999966>]
+[8<0000800100001008>]
+[8<81c36666c3810000>]
+[8<0f0e0c0800000000>]
+[8<0042660000246600>]
+[8<0000990000990000>]
+[8<0804020180402010>]
+[8<2418814242811824>]
+[8<6699996666999966>]
+[8<8000000008000000>]
+[8<00001c3e363e1c00>]
+[8<0000000000000000>]
+[32<00000040000000c00000004000000040000000e0000000000000000000000000>]
+[32<00000000000060000000900000002000000040000000f0000000000000000000>]
+[32<000000000000000000e0000000100000006000000010000000e0000000000000>]
+[32<00000000000000002000000060000000a0000000f00000002000000000000000>]
+[32<0000000e0000000000000000000000000000000f000000080000000e00000001>]
+[32<0000090000000600000000000000000000000000000007000000080000000e00>]
+[32<00010000000200000004000000040000000000000000000000000000000f0000>]
+[32<0900000006000000090000000600000000000000000000000000000006000000>]]
+[%ug
+[8<0000020000000000>]
+[8<0000020000002000>]
+[8<0004020000002000>]
+[8<0004020000402000>]
+[8<0004060000402000>]
+[8<0004060000406000>]
+[8<0006060000406000>]
+[8<0006060000606000>]
+[8<00060e0000606000>]
+[8<00060e000060e000>]
+[8<00070e000060e000>]
+[8<00070e000070e000>]
+[8<00070e020070e000>]
+[8<00070e020070e020>]
+[8<04070e020070e020>]
+[8<04070e024070e020>]
+[8<04070e064070e020>]
+[8<04070e064070e060>]
+[8<06070e064070e060>]
+[8<06070e066070e060>]
+[8<06070f066070e060>]
+[8<06070f066070f060>]
+[8<060f0f066070f060>]
+[8<060f0f0660f0f060>]
+[8<060f0f0760f0f060>]
+[8<060f0f0760f0f070>]
+[8<0e0f0f0760f0f070>]
+[8<0e0f0f07e0f0f070>]
+[8<0e0f0f0fe0f0f070>]
+[8<0e0f0f0fe0f0f0f0>]
+[8<0f0f0f0fe0f0f0f0>]
+[8<0f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff0f0f0f0>]
+[8<1f0f0f0ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f0>]
+[8<1f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff1f0f0f8>]
+[8<9f0f0f8ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f8>]
+[8<9f0f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f0f0f9>]
+[8<9f8f0f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f0f9>]
+[8<9f8f1f9ff9f8f1f9>]
+[8<bf8f1f9ff9f8f1f9>]
+[8<bf8f1f9ffbf8f1f9>]
+[8<bf8f1fdffbf8f1f9>]
+[8<bf8f1fdffbf8f1fd>]
+[8<ff8f1fdffbf8f1fd>]
+[8<ff8f1fdffff8f1fd>]
+[8<ff8f1ffffff8f1fd>]
+[8<ff8f1ffffff8f1ff>]
+[8<ff9f1ffffff8f1ff>]
+[8<ff9f1ffffff9f1ff>]
+[8<ff9f9ffffff9f1ff>]
+[8<ff9f9ffffff9f9ff>]
+[8<ffbf9ffffff9f9ff>]
+[8<ffbf9ffffffbf9ff>]
+[8<ffbfdffffffbf9ff>]
+[8<ffbfdffffffbfdff>]
+[8<ffffdffffffbfdff>]
+[8<ffffdffffffffdff>]
+[8<fffffffffffffdff>]
+[8<ffffffffffffffff>]]
+[%mg
+[8<8000000000000000>]
+[8<0822080080228000>]
+[8<0204081020408001>]
+[8<40e0400000000000>]
+[8<66999966>]
+[8<8001000010080000>]
+[8<81c36666c3810000>]
+[8<f0e0c08000000000>]
+[16<07c00f801f003e007c00f800f001e003c007800f001f003e007c00f801f003e0>]
+[16<1f000f8007c003e001f000f8007c003e001f800fc007e003f001f8007c003e00>]
+[8<c3c300000000c3c3>]
+[16<0040008001000200040008001000200040008000000100020004000800100020>]
+[16<0040002000100008000400020001800040002000100008000400020001000080>]
+[16<1fc03fe07df0f8f8f07de03fc01f800fc01fe03ff07df8f87df03fe01fc00f80>]
+[8<80>]
+[8<8040201000000000>]
+[8<84cc000048cc0000>]
+[8<9900009900000000>]
+[8<08040201804020100800020180002010>]
+[8<2418814242811824>]
+[8<66999966>]
+[8<8000000008000000>]
+[8<70f8d8f870000000>]
+[8<0814224180402010>]
+[8<aa00440a11a04400>]
+[8<018245aa45820100>]
+[8<221c224180808041>]
+[8<88000000>]
+[8<0855800080550800>]
+[8<2844004482440044>]
+[8<0810204080412214>]
+[8<00>]]]def
+/Dfill{
+ transform /maxy exch def /maxx exch def
+ transform /miny exch def /minx exch def
+ minx maxx gt{/minx maxx /maxx minx def def}if
+ miny maxy gt{/miny maxy /maxy miny def def}if
+ Dpatterns Dstipple 1 sub get exch 1 sub get
+ aload pop /stip exch def /stipw exch def /stiph 128 def
+ /imatrix[stipw 0 0 stiph 0 0]def
+ /tmatrix[stipw 0 0 stiph 0 0]def
+ /minx minx cvi stiph idiv stiph mul def
+ /miny miny cvi stipw idiv stipw mul def
+ gsave eoclip 0 setgray
+ miny stiph maxy{
+  tmatrix exch 5 exch put
+  minx stipw maxx{
+   tmatrix exch 4 exch put tmatrix setmatrix
+   stipw stiph true imatrix {stip} imagemask
+  }for
+ }for
+ grestore
+}def
+/Dp{Dfill Dstroke}def
+/DP{Dfill currentpoint newpath moveto}def
+end
+
+/ditstart{$DITroff begin
+ /nfonts 60 def			% NFONTS makedev/ditroff dependent!
+ /fonts[nfonts{0}repeat]def
+ /fontnames[nfonts{()}repeat]def
+/docsave save def
+}def
+
+% character outcalls
+/oc{
+ /pswid exch def /cc exch def /name exch def
+ /ditwid pswid fontsize mul resolution mul 72000 div def
+ /ditsiz fontsize resolution mul 72 div def
+ ocprocs name known{ocprocs name get exec}{name cb}ifelse
+}def
+/fractm [.65 0 0 .6 0 0] def
+/fraction{
+ /fden exch def /fnum exch def gsave /cf currentfont def
+ cf fractm makefont setfont 0 .3 dm 2 copy neg rmoveto
+ fnum show rmoveto currentfont cf setfont(\244)show setfont fden show 
+ grestore ditwid 0 rmoveto
+}def
+/oce{grestore ditwid 0 rmoveto}def
+/dm{ditsiz mul}def
+/ocprocs 50 dict def ocprocs begin
+(14){(1)(4)fraction}def
+(12){(1)(2)fraction}def
+(34){(3)(4)fraction}def
+(13){(1)(3)fraction}def
+(23){(2)(3)fraction}def
+(18){(1)(8)fraction}def
+(38){(3)(8)fraction}def
+(58){(5)(8)fraction}def
+(78){(7)(8)fraction}def
+(sr){gsave 0 .06 dm rmoveto(\326)show oce}def
+(is){gsave 0 .15 dm rmoveto(\362)show oce}def
+(->){gsave 0 .02 dm rmoveto(\256)show oce}def
+(<-){gsave 0 .02 dm rmoveto(\254)show oce}def
+(==){gsave 0 .05 dm rmoveto(\272)show oce}def
+(uc){gsave currentpoint 400 .009 dm mul add translate
+     8 -8 scale ucseal oce}def
+end
+
+% an attempt at a PostScript FONT to implement ditroff special chars
+% this will enable us to 
+%	cache the little buggers
+%	generate faster, more compact PS out of psdit
+%	confuse everyone (including myself)!
+50 dict dup begin
+/FontType 3 def
+/FontName /DIThacks def
+/FontMatrix [.001 0 0 .001 0 0] def
+/FontBBox [-260 -260 900 900] def% a lie but ...
+/Encoding 256 array def
+0 1 255{Encoding exch /.notdef put}for
+Encoding
+ dup 8#040/space put %space
+ dup 8#110/rc put %right ceil
+ dup 8#111/lt put %left  top curl
+ dup 8#112/bv put %bold vert
+ dup 8#113/lk put %left  mid curl
+ dup 8#114/lb put %left  bot curl
+ dup 8#115/rt put %right top curl
+ dup 8#116/rk put %right mid curl
+ dup 8#117/rb put %right bot curl
+ dup 8#120/rf put %right floor
+ dup 8#121/lf put %left  floor
+ dup 8#122/lc put %left  ceil
+ dup 8#140/sq put %square
+ dup 8#141/bx put %box
+ dup 8#142/ci put %circle
+ dup 8#143/br put %box rule
+ dup 8#144/rn put %root extender
+ dup 8#145/vr put %vertical rule
+ dup 8#146/ob put %outline bullet
+ dup 8#147/bu put %bullet
+ dup 8#150/ru put %rule
+ dup 8#151/ul put %underline
+ pop
+/DITfd 100 dict def
+/BuildChar{0 begin
+ /cc exch def /fd exch def
+ /charname fd /Encoding get cc get def
+ /charwid fd /Metrics get charname get def
+ /charproc fd /CharProcs get charname get def
+ charwid 0 fd /FontBBox get aload pop setcachedevice
+ 2 setlinejoin 40 setlinewidth
+ newpath 0 0 moveto gsave charproc grestore
+ end}def
+/BuildChar load 0 DITfd put
+/CharProcs 50 dict def
+CharProcs begin
+/space{}def
+/.notdef{}def
+/ru{500 0 rls}def
+/rn{0 840 moveto 500 0 rls}def
+/vr{0 800 moveto 0 -770 rls}def
+/bv{0 800 moveto 0 -1000 rls}def
+/br{0 840 moveto 0 -1000 rls}def
+/ul{0 -140 moveto 500 0 rls}def
+/ob{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath stroke}def
+/bu{200 250 rmoveto currentpoint newpath 200 0 360 arc closepath fill}def
+/sq{80 0 rmoveto currentpoint dround newpath moveto
+    640 0 rlineto 0 640 rlineto -640 0 rlineto closepath stroke}def
+/bx{80 0 rmoveto currentpoint dround newpath moveto
+    640 0 rlineto 0 640 rlineto -640 0 rlineto closepath fill}def
+/ci{500 360 rmoveto currentpoint newpath 333 0 360 arc
+    50 setlinewidth stroke}def
+
+/lt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 add exch s4 a4p stroke}def
+/lb{0 800 moveto 0 -550 rlineto currx -200 2cx s4 add exch s4 a4p stroke}def
+/rt{0 -200 moveto 0 550 rlineto currx 800 2cx s4 sub exch s4 a4p stroke}def
+/rb{0 800 moveto 0 -500 rlineto currx -200 2cx s4 sub exch s4 a4p stroke}def
+/lk{0 800 moveto 0 300 -300 300 s4 arcto pop pop 1000 sub
+    0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/rk{0 800 moveto 0 300 s2 300 s4 arcto pop pop 1000 sub
+    0 300 4 2 roll s4 a4p 0 -200 lineto stroke}def
+/lf{0 800 moveto 0 -1000 rlineto s4 0 rls}def
+/rf{0 800 moveto 0 -1000 rlineto s4 neg 0 rls}def
+/lc{0 -200 moveto 0 1000 rlineto s4 0 rls}def
+/rc{0 -200 moveto 0 1000 rlineto s4 neg 0 rls}def
+end
+
+/Metrics 50 dict def Metrics begin
+/.notdef 0 def
+/space 500 def
+/ru 500 def
+/br 0 def
+/lt 416 def
+/lb 416 def
+/rt 416 def
+/rb 416 def
+/lk 416 def
+/rk 416 def
+/rc 416 def
+/lc 416 def
+/rf 416 def
+/lf 416 def
+/bv 416 def
+/ob 350 def
+/bu 350 def
+/ci 750 def
+/bx 750 def
+/sq 750 def
+/rn 500 def
+/ul 500 def
+/vr 0 def
+end
+
+DITfd begin
+/s2 500 def /s4 250 def /s3 333 def
+/a4p{arcto pop pop pop pop}def
+/2cx{2 copy exch}def
+/rls{rlineto stroke}def
+/currx{currentpoint pop}def
+/dround{transform round exch round exch itransform} def
+end
+end
+/DIThacks exch definefont pop
+ditstart
+(psc)xT
+576 1 1 xr
+1(Times-Roman)xf 1 f
+2(Times-Italic)xf 2 f
+3(Times-Bold)xf 3 f
+4(Times-BoldItalic)xf 4 f
+5(Helvetica)xf 5 f
+6(Helvetica-Bold)xf 6 f
+7(Courier)xf 7 f
+8(Courier-Bold)xf 8 f
+9(Symbol)xf 9 f
+10(DIThacks)xf 10 f
+10 s
+1 f
+xi
+%%EndProlog
+
+%%Page: 1 1
+10 s 10 xH 0 xS 1 f
+3 f
+14 s
+1205 1206(LIBTP:)N
+1633(Portable,)X
+2100(M)X
+2206(odular)X
+2551(Transactions)X
+3202(for)X
+3374(UNIX)X
+1 f
+11 s
+3661 1162(1)N
+2 f
+12 s
+2182 1398(Margo)N
+2467(Seltzer)X
+2171 1494(Michael)N
+2511(Olson)X
+1800 1590(University)N
+2225(of)X
+2324(California,)X
+2773(Berkeley)X
+3 f
+2277 1878(Abstract)N
+1 f
+10 s
+755 2001(Transactions)N
+1198(provide)X
+1475(a)X
+1543(useful)X
+1771(programming)X
+2239(paradigm)X
+2574(for)X
+2700(maintaining)X
+3114(logical)X
+3364(consistency,)X
+3790(arbitrating)X
+4156(con-)X
+555 2091(current)N
+808(access,)X
+1059(and)X
+1200(managing)X
+1540(recovery.)X
+1886(In)X
+1977(traditional)X
+2330(UNIX)X
+2555(systems,)X
+2852(the)X
+2974(only)X
+3140(easy)X
+3307(way)X
+3465(of)X
+3556(using)X
+3753(transactions)X
+4160(is)X
+4237(to)X
+555 2181(purchase)N
+876(a)X
+947(database)X
+1258(system.)X
+1554(Such)X
+1748(systems)X
+2035(are)X
+2168(often)X
+2367(slow,)X
+2572(costly,)X
+2817(and)X
+2967(may)X
+3139(not)X
+3275(provide)X
+3554(the)X
+3686(exact)X
+3890(functionality)X
+555 2271(desired.)N
+848(This)X
+1011(paper)X
+1210(presents)X
+1493(the)X
+1611(design,)X
+1860(implementation,)X
+2402(and)X
+2538(performance)X
+2965(of)X
+3052(LIBTP,)X
+3314(a)X
+3370(simple,)X
+3623(non-proprietary)X
+4147(tran-)X
+555 2361(saction)N
+809(library)X
+1050(using)X
+1249(the)X
+1373(4.4BSD)X
+1654(database)X
+1957(access)X
+2189(routines)X
+2473(\()X
+3 f
+2500(db)X
+1 f
+2588(\(3\)\).)X
+2775(On)X
+2899(a)X
+2961(conventional)X
+3401(transaction)X
+3779(processing)X
+4148(style)X
+555 2451(benchmark,)N
+959(its)X
+1061(performance)X
+1495(is)X
+1575(approximately)X
+2065(85%)X
+2239(that)X
+2386(of)X
+2480(the)X
+2604(database)X
+2907(access)X
+3139(routines)X
+3423(without)X
+3693(transaction)X
+4071(protec-)X
+555 2541(tion,)N
+725(200%)X
+938(that)X
+1084(of)X
+1177(using)X
+3 f
+1376(fsync)X
+1 f
+1554(\(2\))X
+1674(to)X
+1761(commit)X
+2030(modi\256cations)X
+2490(to)X
+2577(disk,)X
+2755(and)X
+2896(125%)X
+3108(that)X
+3253(of)X
+3345(a)X
+3406(commercial)X
+3810(relational)X
+4138(data-)X
+555 2631(base)N
+718(system.)X
+3 f
+555 2817(1.)N
+655(Introduction)X
+1 f
+755 2940(Transactions)N
+1186(are)X
+1306(used)X
+1474(in)X
+1557(database)X
+1855(systems)X
+2129(to)X
+2212(enable)X
+2443(concurrent)X
+2807(users)X
+2992(to)X
+3074(apply)X
+3272(multi-operation)X
+3790(updates)X
+4055(without)X
+555 3030(violating)N
+863(the)X
+985(integrity)X
+1280(of)X
+1371(the)X
+1493(database.)X
+1814(They)X
+2003(provide)X
+2271(the)X
+2392(properties)X
+2736(of)X
+2826(atomicity,)X
+3171(consistency,)X
+3588(isolation,)X
+3906(and)X
+4045(durabil-)X
+555 3120(ity.)N
+701(By)X
+816(atomicity,)X
+1160(we)X
+1276(mean)X
+1472(that)X
+1614(the)X
+1734(set)X
+1845(of)X
+1934(updates)X
+2200(comprising)X
+2581(a)X
+2638(transaction)X
+3011(must)X
+3187(be)X
+3284(applied)X
+3541(as)X
+3629(a)X
+3686(single)X
+3898(unit;)X
+4085(that)X
+4226(is,)X
+555 3210(they)N
+714(must)X
+890(either)X
+1094(all)X
+1195(be)X
+1292(applied)X
+1549(to)X
+1632(the)X
+1751(database)X
+2049(or)X
+2137(all)X
+2238(be)X
+2335(absent.)X
+2601(Consistency)X
+3013(requires)X
+3293(that)X
+3434(a)X
+3491(transaction)X
+3864(take)X
+4019(the)X
+4138(data-)X
+555 3300(base)N
+725(from)X
+908(one)X
+1051(logically)X
+1358(consistent)X
+1704(state)X
+1877(to)X
+1965(another.)X
+2272(The)X
+2423(property)X
+2721(of)X
+2814(isolation)X
+3115(requires)X
+3400(that)X
+3546(concurrent)X
+3916(transactions)X
+555 3390(yield)N
+750(results)X
+994(which)X
+1225(are)X
+1358(indistinguishable)X
+1938(from)X
+2128(the)X
+2260(results)X
+2503(which)X
+2733(would)X
+2967(be)X
+3077(obtained)X
+3387(by)X
+3501(running)X
+3784(the)X
+3916(transactions)X
+555 3480(sequentially.)N
+1002(Finally,)X
+1268(durability)X
+1599(requires)X
+1878(that)X
+2018(once)X
+2190(transactions)X
+2593(have)X
+2765(been)X
+2937(committed,)X
+3319(their)X
+3486(results)X
+3715(must)X
+3890(be)X
+3986(preserved)X
+555 3570(across)N
+776(system)X
+1018(failures)X
+1279([TPCB90].)X
+755 3693(Although)N
+1080(these)X
+1268(properties)X
+1612(are)X
+1734(most)X
+1912(frequently)X
+2265(discussed)X
+2595(in)X
+2680(the)X
+2801(context)X
+3060(of)X
+3150(databases,)X
+3501(they)X
+3661(are)X
+3782(useful)X
+4000(program-)X
+555 3783(ming)N
+750(paradigms)X
+1114(for)X
+1238(more)X
+1433(general)X
+1700(purpose)X
+1984(applications.)X
+2441(There)X
+2659(are)X
+2788(several)X
+3046(different)X
+3353(situations)X
+3689(where)X
+3916(transactions)X
+555 3873(can)N
+687(be)X
+783(used)X
+950(to)X
+1032(replace)X
+1285(current)X
+1533(ad-hoc)X
+1772(mechanisms.)X
+755 3996(One)N
+910(situation)X
+1206(is)X
+1280(when)X
+1475(multiple)X
+1762(\256les)X
+1916(or)X
+2004(parts)X
+2181(of)X
+2269(\256les)X
+2422(need)X
+2594(to)X
+2676(be)X
+2772(updated)X
+3046(in)X
+3128(an)X
+3224(atomic)X
+3462(fashion.)X
+3758(For)X
+3889(example,)X
+4201(the)X
+555 4086(traditional)N
+907(UNIX)X
+1131(\256le)X
+1256(system)X
+1501(uses)X
+1661(ordering)X
+1955(constraints)X
+2324(to)X
+2408(achieve)X
+2676(recoverability)X
+3144(in)X
+3228(the)X
+3348(face)X
+3505(of)X
+3594(crashes.)X
+3893(When)X
+4107(a)X
+4165(new)X
+555 4176(\256le)N
+678(is)X
+752(created,)X
+1026(its)X
+1122(inode)X
+1321(is)X
+1395(written)X
+1642(to)X
+1724(disk)X
+1877(before)X
+2103(the)X
+2221(new)X
+2375(\256le)X
+2497(is)X
+2570(added)X
+2782(to)X
+2864(the)X
+2982(directory)X
+3292(structure.)X
+3633(This)X
+3795(guarantees)X
+4159(that,)X
+555 4266(if)N
+627(the)X
+748(system)X
+993(crashes)X
+1253(between)X
+1544(the)X
+1665(two)X
+1808(I/O's,)X
+2016(the)X
+2137(directory)X
+2450(does)X
+2620(not)X
+2744(contain)X
+3002(a)X
+3060 0.4531(reference)AX
+3383(to)X
+3467(an)X
+3565(invalid)X
+3809(inode.)X
+4049(In)X
+4138(actu-)X
+555 4356(ality,)N
+741(the)X
+863(desired)X
+1119(effect)X
+1326(is)X
+1402(that)X
+1545(these)X
+1733(two)X
+1876(updates)X
+2144(have)X
+2319(the)X
+2440(transactional)X
+2873(property)X
+3168(of)X
+3258(atomicity)X
+3583(\(either)X
+3816(both)X
+3981(writes)X
+4200(are)X
+555 4446(visible)N
+790(or)X
+879(neither)X
+1124(is\).)X
+1266(Rather)X
+1501(than)X
+1660(building)X
+1947(special)X
+2191(purpose)X
+2466(recovery)X
+2769(mechanisms)X
+3186(into)X
+3331(the)X
+3450(\256le)X
+3573(system)X
+3816(or)X
+3904(related)X
+4144(tools)X
+555 4536(\()N
+2 f
+582(e.g.)X
+3 f
+726(fsck)X
+1 f
+864(\(8\)\),)X
+1033(one)X
+1177(could)X
+1383(use)X
+1518(general)X
+1783(purpose)X
+2064(transaction)X
+2443(recovery)X
+2752(protocols)X
+3077(after)X
+3252(system)X
+3501(failure.)X
+3778(Any)X
+3943(application)X
+555 4626(that)N
+705(needs)X
+918(to)X
+1010(keep)X
+1192(multiple,)X
+1508(related)X
+1757(\256les)X
+1920(\(or)X
+2044(directories\))X
+2440(consistent)X
+2790(should)X
+3032(do)X
+3141(so)X
+3241(using)X
+3443(transactions.)X
+3895(Source)X
+4147(code)X
+555 4716(control)N
+805(systems,)X
+1101(such)X
+1271(as)X
+1361(RCS)X
+1534(and)X
+1673(SCCS,)X
+1910(should)X
+2146(use)X
+2276(transaction)X
+2651(semantics)X
+2990(to)X
+3075(allow)X
+3276(the)X
+3397(``checking)X
+3764(in'')X
+3903(of)X
+3992(groups)X
+4232(of)X
+555 4806(related)N
+801(\256les.)X
+1001(In)X
+1095(this)X
+1237(way,)X
+1418(if)X
+1493(the)X
+1617 0.2841(``check-in'')AX
+2028(fails,)X
+2212(the)X
+2336(transaction)X
+2714(may)X
+2878(be)X
+2980(aborted,)X
+3267(backing)X
+3547(out)X
+3675(the)X
+3799(partial)X
+4030(``check-)X
+555 4896(in'')N
+691(leaving)X
+947(the)X
+1065(source)X
+1295(repository)X
+1640(in)X
+1722(a)X
+1778(consistent)X
+2118(state.)X
+755 5019(A)N
+842(second)X
+1094(situation)X
+1398(where)X
+1624(transactions)X
+2036(can)X
+2177(be)X
+2282(used)X
+2458(to)X
+2549(replace)X
+2811(current)X
+3068(ad-hoc)X
+3316(mechanisms)X
+3741(is)X
+3822(in)X
+3912(applications)X
+555 5109(where)N
+776(concurrent)X
+1144(updates)X
+1413(to)X
+1499(a)X
+1559(shared)X
+1793(\256le)X
+1919(are)X
+2042(desired,)X
+2318(but)X
+2444(there)X
+2629(is)X
+2706(logical)X
+2948(consistency)X
+3345(of)X
+3435(the)X
+3556(data)X
+3713(which)X
+3932(needs)X
+4138(to)X
+4223(be)X
+555 5199(preserved.)N
+928(For)X
+1059(example,)X
+1371(when)X
+1565(the)X
+1683(password)X
+2006(\256le)X
+2128(is)X
+2201(updated,)X
+2495(\256le)X
+2617(locking)X
+2877(is)X
+2950(used)X
+3117(to)X
+3199(disallow)X
+3490(concurrent)X
+3854(access.)X
+4120(Tran-)X
+555 5289(saction)N
+804(semantics)X
+1142(on)X
+1244(the)X
+1364(password)X
+1689(\256les)X
+1844(would)X
+2066(allow)X
+2266(concurrent)X
+2632(updates,)X
+2919(while)X
+3119(preserving)X
+3479(the)X
+3598(logical)X
+3837(consistency)X
+4232(of)X
+555 5379(the)N
+681(password)X
+1012(database.)X
+1357(Similarly,)X
+1702(UNIX)X
+1930(utilities)X
+2196(which)X
+2419(rewrite)X
+2674(\256les)X
+2834(face)X
+2996(a)X
+3059(potential)X
+3366(race)X
+3528(condition)X
+3857(between)X
+4152(their)X
+555 5469(rewriting)N
+871(a)X
+929(\256le)X
+1053(and)X
+1191(another)X
+1453(process)X
+1715(reading)X
+1977(the)X
+2096(\256le.)X
+2259(For)X
+2391(example,)X
+2704(the)X
+2823(compiler)X
+3129(\(more)X
+3342(precisely,)X
+3673(the)X
+3792(assembler\))X
+4161(may)X
+8 s
+10 f
+555 5541(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5619(1)N
+8 s
+763 5644(To)N
+850(appear)X
+1035(in)X
+1101(the)X
+2 f
+1195(Proceedings)X
+1530(of)X
+1596(the)X
+1690(1992)X
+1834(Winter)X
+2024(Usenix)X
+1 f
+2201(,)X
+2233(San)X
+2345(Francisco,)X
+2625(CA,)X
+2746(January)X
+2960(1992.)X
+
+2 p
+%%Page: 2 2
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+555 630(have)N
+737(to)X
+829(rewrite)X
+1087(a)X
+1152(\256le)X
+1283(to)X
+1374(which)X
+1599(it)X
+1672(has)X
+1808(write)X
+2002(permission)X
+2382(in)X
+2473(a)X
+2538(directory)X
+2857(to)X
+2948(which)X
+3173(it)X
+3246(does)X
+3422(not)X
+3553(have)X
+3734(write)X
+3928(permission.)X
+555 720(While)N
+779(the)X
+904(``.o'')X
+1099(\256le)X
+1228(is)X
+1308(being)X
+1513(written,)X
+1787(another)X
+2055(utility)X
+2272(such)X
+2446(as)X
+3 f
+2540(nm)X
+1 f
+2651(\(1\))X
+2772(or)X
+3 f
+2866(ar)X
+1 f
+2942(\(1\))X
+3063(may)X
+3228(read)X
+3394(the)X
+3519(\256le)X
+3648(and)X
+3791(produce)X
+4077(invalid)X
+555 810(results)N
+790(since)X
+981(the)X
+1105(\256le)X
+1233(has)X
+1366(not)X
+1494(been)X
+1672(completely)X
+2054(written.)X
+2347(Currently,)X
+2700(some)X
+2895(utilities)X
+3160(use)X
+3293(special)X
+3542(purpose)X
+3821(code)X
+3998(to)X
+4085(handle)X
+555 900(such)N
+722(cases)X
+912(while)X
+1110(others)X
+1326(ignore)X
+1551(the)X
+1669(problem)X
+1956(and)X
+2092(force)X
+2278(users)X
+2463(to)X
+2545(live)X
+2685(with)X
+2847(the)X
+2965(consequences.)X
+755 1023(In)N
+845(this)X
+983(paper,)X
+1205(we)X
+1322(present)X
+1577(a)X
+1635(simple)X
+1870(library)X
+2106(which)X
+2324(provides)X
+2622(transaction)X
+2996(semantics)X
+3334(\(atomicity,)X
+3705(consistency,)X
+4121(isola-)X
+555 1113(tion,)N
+720(and)X
+857(durability\).)X
+1236(The)X
+1382(4.4BSD)X
+1658(database)X
+1956(access)X
+2182(methods)X
+2473(have)X
+2645(been)X
+2817(modi\256ed)X
+3121(to)X
+3203(use)X
+3330(this)X
+3465(library,)X
+3719(optionally)X
+4063(provid-)X
+555 1203(ing)N
+682(shared)X
+917(buffer)X
+1139(management)X
+1574(between)X
+1867(applications,)X
+2298(locking,)X
+2582(and)X
+2722(transaction)X
+3098(semantics.)X
+3478(Any)X
+3640(UNIX)X
+3865(program)X
+4161(may)X
+555 1293(transaction)N
+930(protect)X
+1176(its)X
+1274(data)X
+1430(by)X
+1532(requesting)X
+1888(transaction)X
+2262(protection)X
+2609(with)X
+2773(the)X
+3 f
+2893(db)X
+1 f
+2981(\(3\))X
+3097(library)X
+3333(or)X
+3422(by)X
+3524(adding)X
+3764(appropriate)X
+4152(calls)X
+555 1383(to)N
+646(the)X
+773(transaction)X
+1154(manager,)X
+1480(buffer)X
+1706(manager,)X
+2032(lock)X
+2199(manager,)X
+2525(and)X
+2670(log)X
+2801(manager.)X
+3147(The)X
+3301(library)X
+3543(routines)X
+3829(may)X
+3995(be)X
+4099(linked)X
+555 1473(into)N
+708(the)X
+834(host)X
+995(application)X
+1379(and)X
+1523(called)X
+1743(by)X
+1851(subroutine)X
+2217(interface,)X
+2547(or)X
+2642(they)X
+2808(may)X
+2974(reside)X
+3194(in)X
+3284(a)X
+3348(separate)X
+3640(server)X
+3865(process.)X
+4174(The)X
+555 1563(server)N
+772(architecture)X
+1172(provides)X
+1468(for)X
+1582(network)X
+1865(access)X
+2091(and)X
+2227(better)X
+2430(protection)X
+2775(mechanisms.)X
+3 f
+555 1749(2.)N
+655(Related)X
+938(Work)X
+1 f
+755 1872(There)N
+1000(has)X
+1164(been)X
+1373(much)X
+1608(discussion)X
+1998(in)X
+2117(recent)X
+2371(years)X
+2597(about)X
+2831(new)X
+3021(transaction)X
+3429(models)X
+3716(and)X
+3888(architectures)X
+555 1962 0.1172([SPEC88][NODI90][CHEN91][MOHA91].)AN
+2009(Much)X
+2220(of)X
+2310(this)X
+2448(work)X
+2636(focuses)X
+2900(on)X
+3003(new)X
+3160(ways)X
+3348(to)X
+3433(model)X
+3656(transactions)X
+4062(and)X
+4201(the)X
+555 2052(interactions)N
+953(between)X
+1245(them,)X
+1449(while)X
+1651(the)X
+1772(work)X
+1960(presented)X
+2291(here)X
+2453(focuses)X
+2717(on)X
+2820(the)X
+2941(implementation)X
+3466(and)X
+3605(performance)X
+4035(of)X
+4125(tradi-)X
+555 2142(tional)N
+757(transaction)X
+1129(techniques)X
+1492(\(write-ahead)X
+1919(logging)X
+2183(and)X
+2319(two-phase)X
+2669(locking\))X
+2956(on)X
+3056(a)X
+3112(standard)X
+3404(operating)X
+3727(system)X
+3969(\(UNIX\).)X
+755 2265(Such)N
+947(traditional)X
+1308(operating)X
+1643(systems)X
+1928(are)X
+2059(often)X
+2256(criticized)X
+2587(for)X
+2713(their)X
+2892(inability)X
+3190(to)X
+3283(perform)X
+3573(transaction)X
+3956(processing)X
+555 2355(adequately.)N
+971([STON81])X
+1342(cites)X
+1517(three)X
+1706(main)X
+1894(areas)X
+2088(of)X
+2183(inadequate)X
+2559(support:)X
+2849(buffer)X
+3074(management,)X
+3532(the)X
+3658(\256le)X
+3788(system,)X
+4058(and)X
+4201(the)X
+555 2445(process)N
+823(structure.)X
+1191(These)X
+1410(arguments)X
+1771(are)X
+1897(summarized)X
+2316(in)X
+2405(table)X
+2587(one.)X
+2769(Fortunately,)X
+3184(much)X
+3388(has)X
+3521(changed)X
+3815(since)X
+4006(1981.)X
+4232(In)X
+555 2535(the)N
+683(area)X
+848(of)X
+945(buffer)X
+1172(management,)X
+1632(most)X
+1817(UNIX)X
+2048(systems)X
+2331(provide)X
+2606(the)X
+2734(ability)X
+2968(to)X
+3060(memory)X
+3357(map)X
+3525(\256les,)X
+3708(thus)X
+3870(obviating)X
+4201(the)X
+555 2625(need)N
+734(for)X
+855(a)X
+918(copy)X
+1101(between)X
+1396(kernel)X
+1624(and)X
+1766(user)X
+1926(space.)X
+2171(If)X
+2251(a)X
+2313(database)X
+2616(system)X
+2864(is)X
+2943(going)X
+3151(to)X
+3239(use)X
+3372(the)X
+3496(\256le)X
+3624(system)X
+3872(buffer)X
+4095(cache,)X
+555 2715(then)N
+719(a)X
+781(system)X
+1029(call)X
+1171(is)X
+1250(required.)X
+1584(However,)X
+1924(if)X
+1998(buffering)X
+2322(is)X
+2400(provided)X
+2710(at)X
+2793(user)X
+2952(level)X
+3133(using)X
+3331(shared)X
+3566(memory,)X
+3878(as)X
+3970(in)X
+4057(LIBTP,)X
+555 2805(buffer)N
+776(management)X
+1210(is)X
+1287(only)X
+1452(as)X
+1542(slow)X
+1716(as)X
+1806(access)X
+2035(to)X
+2120(shared)X
+2353(memory)X
+2643(and)X
+2782(any)X
+2921(replacement)X
+3337(algorithm)X
+3671(may)X
+3832(be)X
+3931(used.)X
+4121(Since)X
+555 2895(multiple)N
+849(processes)X
+1185(can)X
+1325(access)X
+1559(the)X
+1685(shared)X
+1923(data,)X
+2105(prefetching)X
+2499(may)X
+2665(be)X
+2769(accomplished)X
+3238(by)X
+3346(separate)X
+3638(processes)X
+3973(or)X
+4067(threads)X
+555 2985(whose)N
+782(sole)X
+932(purpose)X
+1207(is)X
+1281(to)X
+1364(prefetch)X
+1649(pages)X
+1853(and)X
+1990(wait)X
+2149(on)X
+2250(them.)X
+2471(There)X
+2680(is)X
+2754(still)X
+2894(no)X
+2995(way)X
+3150(to)X
+3233(enforce)X
+3496(write)X
+3682(ordering)X
+3975(other)X
+4161(than)X
+555 3075(keeping)N
+829(pages)X
+1032(in)X
+1114(user)X
+1268(memory)X
+1555(and)X
+1691(using)X
+1884(the)X
+3 f
+2002(fsync)X
+1 f
+2180(\(3\))X
+2294(system)X
+2536(call)X
+2672(to)X
+2754(perform)X
+3033(synchronous)X
+3458(writes.)X
+755 3198(In)N
+845(the)X
+966(area)X
+1124(of)X
+1214(\256le)X
+1339(systems,)X
+1635(the)X
+1756(fast)X
+1895(\256le)X
+2020(system)X
+2265(\(FFS\))X
+2474([MCKU84])X
+2871(allows)X
+3103(allocation)X
+3442(in)X
+3527(units)X
+3704(up)X
+3806(to)X
+3890(64KBytes)X
+4232(as)X
+555 3288(opposed)N
+846(to)X
+932(the)X
+1054(4KByte)X
+1327(and)X
+1466(8KByte)X
+1738(\256gures)X
+1979(quoted)X
+2220(in)X
+2305([STON81].)X
+2711(The)X
+2859(measurements)X
+3341(in)X
+3426(this)X
+3564(paper)X
+3766(were)X
+3946(taken)X
+4143(from)X
+555 3378(an)N
+655(8KByte)X
+928(FFS,)X
+1104(but)X
+1230(as)X
+1320(LIBTP)X
+1565(runs)X
+1726(exclusively)X
+2114(in)X
+2199(user)X
+2356(space,)X
+2578(there)X
+2762(is)X
+2838(nothing)X
+3105(to)X
+3190(prevent)X
+3454(it)X
+3521(from)X
+3700(being)X
+3901(run)X
+4031(on)X
+4134(other)X
+555 3468(UNIX)N
+776(compatible)X
+1152(\256le)X
+1274(systems)X
+1547(\(e.g.)X
+1710(log-structured)X
+2180([ROSE91],)X
+2558(extent-based,)X
+3004(or)X
+3091(multi-block)X
+3484([SELT91]\).)X
+755 3591(Finally,)N
+1029(with)X
+1199(regard)X
+1433(to)X
+1523(the)X
+1648(process)X
+1916(structure,)X
+2244(neither)X
+2494(context)X
+2757(switch)X
+2993(time)X
+3162(nor)X
+3296(scheduling)X
+3670(around)X
+3920(semaphores)X
+555 3681(seems)N
+785(to)X
+881(affect)X
+1099(the)X
+1231(system)X
+1487(performance.)X
+1968(However,)X
+2317(the)X
+2449(implementation)X
+2984(of)X
+3084(semaphores)X
+3496(can)X
+3641(impact)X
+3892(performance)X
+555 3771(tremendously.)N
+1051(This)X
+1213(is)X
+1286(discussed)X
+1613(in)X
+1695(more)X
+1880(detail)X
+2078(in)X
+2160(section)X
+2407(4.3.)X
+755 3894(The)N
+908(Tuxedo)X
+1181(system)X
+1431(from)X
+1615(AT&T)X
+1861(is)X
+1941(a)X
+2004(transaction)X
+2383(manager)X
+2687(which)X
+2910(coordinates)X
+3307(distributed)X
+3676(transaction)X
+4055(commit)X
+555 3984(from)N
+738(a)X
+801(variety)X
+1051(of)X
+1145(different)X
+1449(local)X
+1632(transaction)X
+2011(managers.)X
+2386(At)X
+2493(this)X
+2634(time,)X
+2822(LIBTP)X
+3070(does)X
+3243(not)X
+3371(have)X
+3549(its)X
+3650(own)X
+3814(mechanism)X
+4205(for)X
+555 4074(distributed)N
+942(commit)X
+1231(processing,)X
+1639(but)X
+1786(could)X
+2009(be)X
+2130(used)X
+2322(as)X
+2434(a)X
+2515(local)X
+2716(transaction)X
+3113(agent)X
+3331(by)X
+3455(systems)X
+3752(such)X
+3943(as)X
+4054(Tuxedo)X
+555 4164([ANDR89].)N
+10 f
+863 4393(i)N
+870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+903 4483(Buffer)N
+1133(Management)X
+10 f
+1672(g)X
+1 f
+1720(Data)X
+1892(must)X
+2067(be)X
+2163(copied)X
+2397(between)X
+2685(kernel)X
+2906(space)X
+3105(and)X
+3241(user)X
+3395(space.)X
+10 f
+1672 4573(g)N
+1 f
+1720(Buffer)X
+1950(pool)X
+2112(access)X
+2338(is)X
+2411(too)X
+2533(slow.)X
+10 f
+1672 4663(g)N
+1 f
+1720(There)X
+1928(is)X
+2001(no)X
+2101(way)X
+2255(to)X
+2337(request)X
+2589(prefetch.)X
+10 f
+1672 4753(g)N
+1 f
+1720(Replacement)X
+2159(is)X
+2232(usually)X
+2483(LRU)X
+2663(which)X
+2879(may)X
+3037(be)X
+3133(suboptimal)X
+3508(for)X
+3622(databases.)X
+10 f
+1672 4843(g)N
+1 f
+1720(There)X
+1928(is)X
+2001(no)X
+2101(way)X
+2255(to)X
+2337(guarantee)X
+2670(write)X
+2855(ordering.)X
+10 f
+863 4853(i)N
+870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+903 4943(File)N
+1047(System)X
+10 f
+1672(g)X
+1 f
+1720(Allocation)X
+2078(is)X
+2151(done)X
+2327(in)X
+2409(small)X
+2602(blocks)X
+2831(\(usually)X
+3109(4K)X
+3227(or)X
+3314(8K\).)X
+10 f
+1672 5033(g)N
+1 f
+1720(Logical)X
+1985(organization)X
+2406(of)X
+2493(\256les)X
+2646(is)X
+2719(redundantly)X
+3122(expressed.)X
+10 f
+863 5043(i)N
+870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+903 5133(Process)N
+1168(Structure)X
+10 f
+1672(g)X
+1 f
+1720(Context)X
+1993(switching)X
+2324(and)X
+2460(message)X
+2752(passing)X
+3012(are)X
+3131(too)X
+3253(slow.)X
+10 f
+1672 5223(g)N
+1 f
+1720(A)X
+1798(process)X
+2059(may)X
+2217(be)X
+2313(descheduled)X
+2730(while)X
+2928(holding)X
+3192(a)X
+3248(semaphore.)X
+10 f
+863 5233(i)N
+870(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+863(c)X
+5193(c)Y
+5113(c)Y
+5033(c)Y
+4953(c)Y
+4873(c)Y
+4793(c)Y
+4713(c)Y
+4633(c)Y
+4553(c)Y
+4473(c)Y
+3990 5233(c)N
+5193(c)Y
+5113(c)Y
+5033(c)Y
+4953(c)Y
+4873(c)Y
+4793(c)Y
+4713(c)Y
+4633(c)Y
+4553(c)Y
+4473(c)Y
+3 f
+1156 5446(Table)N
+1371(One:)X
+1560(Shortcomings)X
+2051(of)X
+2138(UNIX)X
+2363(transaction)X
+2770(support)X
+3056(cited)X
+3241(in)X
+3327([STON81].)X
+
+3 p
+%%Page: 3 3
+10 s 10 xH 0 xS 3 f
+1 f
+755 630(The)N
+901(transaction)X
+1274(architecture)X
+1675(presented)X
+2004(in)X
+2087([YOUN91])X
+2474(is)X
+2548(very)X
+2712(similar)X
+2955(to)X
+3038(that)X
+3179(implemented)X
+3618(in)X
+3701(the)X
+3820(LIBTP.)X
+4103(While)X
+555 720([YOUN91])N
+947(presents)X
+1236(a)X
+1298(model)X
+1524(for)X
+1644(providing)X
+1981(transaction)X
+2359(services,)X
+2663(this)X
+2803(paper)X
+3007(focuses)X
+3273(on)X
+3378(the)X
+3501(implementation)X
+4028(and)X
+4169(per-)X
+555 810(formance)N
+881(of)X
+970(a)X
+1028(particular)X
+1358(system.)X
+1642(In)X
+1731(addition,)X
+2034(we)X
+2149(provide)X
+2415(detailed)X
+2690(comparisons)X
+3116(with)X
+3279(alternative)X
+3639(solutions:)X
+3970(traditional)X
+555 900(UNIX)N
+776(services)X
+1055(and)X
+1191(commercial)X
+1590(database)X
+1887(management)X
+2317(systems.)X
+3 f
+555 1086(3.)N
+655(Architecture)X
+1 f
+755 1209(The)N
+906(library)X
+1146(is)X
+1224(designed)X
+1534(to)X
+1621(provide)X
+1891(well)X
+2054(de\256ned)X
+2315(interfaces)X
+2653(to)X
+2740(the)X
+2863(services)X
+3147(required)X
+3440(for)X
+3559(transaction)X
+3936(processing.)X
+555 1299(These)N
+777(services)X
+1066(are)X
+1195(recovery,)X
+1527(concurrency)X
+1955(control,)X
+2232(and)X
+2378(the)X
+2506(management)X
+2946(of)X
+3043(shared)X
+3283(data.)X
+3487(First)X
+3663(we)X
+3787(will)X
+3941(discuss)X
+4201(the)X
+555 1389(design)N
+795(tradeoffs)X
+1112(in)X
+1205(the)X
+1334(selection)X
+1650(of)X
+1748(recovery,)X
+2081(concurrency)X
+2510(control,)X
+2787(and)X
+2933(buffer)X
+3160(management)X
+3600(implementations,)X
+4183(and)X
+555 1479(then)N
+713(we)X
+827(will)X
+971(present)X
+1223(the)X
+1341(overall)X
+1584(library)X
+1818(architecture)X
+2218(and)X
+2354(module)X
+2614(descriptions.)X
+3 f
+555 1665(3.1.)N
+715(Design)X
+966(Tradeoffs)X
+1 f
+3 f
+555 1851(3.1.1.)N
+775(Crash)X
+1004(Recovery)X
+1 f
+755 1974(The)N
+909(recovery)X
+1220(protocol)X
+1516(is)X
+1598(responsible)X
+1992(for)X
+2115(providing)X
+2455(the)X
+2582(transaction)X
+2963(semantics)X
+3308(discussed)X
+3644(earlier.)X
+3919(There)X
+4136(are)X
+4263(a)X
+555 2064(wide)N
+739(range)X
+946(of)X
+1041(recovery)X
+1351(protocols)X
+1677(available)X
+1995([HAER83],)X
+2395(but)X
+2525(we)X
+2647(can)X
+2786(crudely)X
+3054(divide)X
+3281(them)X
+3468(into)X
+3619(two)X
+3766(main)X
+3953(categories.)X
+555 2154(The)N
+706(\256rst)X
+856(category)X
+1159(records)X
+1422(all)X
+1528(modi\256cations)X
+1989(to)X
+2077(the)X
+2201(database)X
+2504(in)X
+2592(a)X
+2653(separate)X
+2942(\256le,)X
+3089(and)X
+3230(uses)X
+3393(this)X
+3533(\256le)X
+3660(\(log\))X
+3841(to)X
+3928(back)X
+4105(out)X
+4232(or)X
+555 2244(reapply)N
+825(these)X
+1019(modi\256cations)X
+1483(if)X
+1561(a)X
+1626(transaction)X
+2007(aborts)X
+2232(or)X
+2328(the)X
+2455(system)X
+2706(crashes.)X
+3012(We)X
+3153(call)X
+3298(this)X
+3442(set)X
+3560(the)X
+3 f
+3687(logging)X
+3963(protocols)X
+1 f
+4279(.)X
+555 2334(The)N
+703(second)X
+949(category)X
+1249(avoids)X
+1481(the)X
+1602(use)X
+1732(of)X
+1822(a)X
+1881(log)X
+2006(by)X
+2109(carefully)X
+2418(controlling)X
+2792(when)X
+2989(data)X
+3146(are)X
+3268(written)X
+3518(to)X
+3603(disk.)X
+3799(We)X
+3934(call)X
+4073(this)X
+4210(set)X
+555 2424(the)N
+3 f
+673(non-logging)X
+1096(protocols)X
+1 f
+1412(.)X
+755 2547(Non-logging)N
+1185(protocols)X
+1504(hold)X
+1666(dirty)X
+1837(buffers)X
+2085(in)X
+2167(main)X
+2347(memory)X
+2634(or)X
+2721(temporary)X
+3071(\256les)X
+3224(until)X
+3390(commit)X
+3654(and)X
+3790(then)X
+3948(force)X
+4134(these)X
+555 2637(pages)N
+769(to)X
+862(disk)X
+1026(at)X
+1115(transaction)X
+1498(commit.)X
+1813(While)X
+2040(we)X
+2165(can)X
+2308(use)X
+2446(temporary)X
+2807(\256les)X
+2971(to)X
+3064(hold)X
+3237(dirty)X
+3418(pages)X
+3631(that)X
+3781(may)X
+3949(need)X
+4131(to)X
+4223(be)X
+555 2727(evicted)N
+810(from)X
+988(memory)X
+1277(during)X
+1508(a)X
+1566(long-running)X
+2006(transaction,)X
+2400(the)X
+2520(only)X
+2684(user-level)X
+3023(mechanism)X
+3410(to)X
+3494(force)X
+3682(pages)X
+3887(to)X
+3971(disk)X
+4126(is)X
+4201(the)X
+3 f
+555 2817(fsync)N
+1 f
+733(\(2\))X
+850(system)X
+1095(call.)X
+1274(Unfortunately,)X
+3 f
+1767(fsync)X
+1 f
+1945(\(2\))X
+2062(is)X
+2138(an)X
+2237(expensive)X
+2581(system)X
+2826(call)X
+2965(in)X
+3050(that)X
+3193(it)X
+3260(forces)X
+3480(all)X
+3583(pages)X
+3789(of)X
+3879(a)X
+3938(\256le)X
+4062(to)X
+4146(disk,)X
+555 2907(and)N
+691(transactions)X
+1094(that)X
+1234(manage)X
+1504(more)X
+1689(than)X
+1847(one)X
+1983(\256le)X
+2105(must)X
+2280(issue)X
+2460(one)X
+2596(call)X
+2732(per)X
+2855(\256le.)X
+755 3030(In)N
+853(addition,)X
+3 f
+1166(fsync)X
+1 f
+1344(\(2\))X
+1469(provides)X
+1776(no)X
+1887(way)X
+2051(to)X
+2143(control)X
+2400(the)X
+2528(order)X
+2728(in)X
+2820(which)X
+3046(dirty)X
+3227(pages)X
+3440(are)X
+3569(written)X
+3826(to)X
+3918(disk.)X
+4121(Since)X
+555 3120(non-logging)N
+976(protocols)X
+1304(must)X
+1489(sometimes)X
+1861(order)X
+2061(writes)X
+2287(carefully)X
+2603([SULL92],)X
+2987(they)X
+3155(are)X
+3284(dif\256cult)X
+3567(to)X
+3659(implement)X
+4030(on)X
+4139(Unix)X
+555 3210(systems.)N
+868(As)X
+977(a)X
+1033(result,)X
+1251(we)X
+1365(have)X
+1537(chosen)X
+1780(to)X
+1862(implement)X
+2224(a)X
+2280(logging)X
+2544(protocol.)X
+755 3333(Logging)N
+1050(protocols)X
+1372(may)X
+1534(be)X
+1634(categorized)X
+2029(based)X
+2236(on)X
+2340(how)X
+2502(information)X
+2904(is)X
+2981(logged)X
+3223(\(physically)X
+3602(or)X
+3692(logically\))X
+4022(and)X
+4161(how)X
+555 3423(much)N
+767(is)X
+854(logged)X
+1106(\(before)X
+1373(images,)X
+1654(after)X
+1836(images)X
+2097(or)X
+2198(both\).)X
+2441(In)X
+3 f
+2542(physical)X
+2855(logging)X
+1 f
+3103(,)X
+3157(images)X
+3417(of)X
+3517(complete)X
+3844(physical)X
+4144(units)X
+555 3513(\(pages)N
+786(or)X
+874(buffers\))X
+1150(are)X
+1270(recorded,)X
+1593(while)X
+1792(in)X
+3 f
+1875(logical)X
+2118(logging)X
+1 f
+2387(a)X
+2444(description)X
+2820(of)X
+2907(the)X
+3025(operation)X
+3348(is)X
+3421(recorded.)X
+3763(Therefore,)X
+4121(while)X
+555 3603(we)N
+675(may)X
+839(record)X
+1071(entire)X
+1280(pages)X
+1489(in)X
+1577(a)X
+1639(physical)X
+1932(log,)X
+2080(we)X
+2200(need)X
+2378(only)X
+2546(record)X
+2777(the)X
+2900(records)X
+3162(being)X
+3365(modi\256ed)X
+3674(in)X
+3761(a)X
+3822(logical)X
+4065(log.)X
+4232(In)X
+555 3693(fact,)N
+718(physical)X
+1006(logging)X
+1271(can)X
+1404(be)X
+1501(thought)X
+1766(of)X
+1854(as)X
+1942(a)X
+1999(special)X
+2243(case)X
+2403(of)X
+2491(logical)X
+2730(logging,)X
+3015(since)X
+3201(the)X
+3320 0.3125(``records'')AX
+3686(that)X
+3827(we)X
+3942(log)X
+4065(in)X
+4148(logi-)X
+555 3783(cal)N
+673(logging)X
+941(might)X
+1151(be)X
+1251(physical)X
+1542(pages.)X
+1789(Since)X
+1991(logical)X
+2233(logging)X
+2501(is)X
+2578(both)X
+2743(more)X
+2931(space-ef\256cient)X
+3423(and)X
+3562(more)X
+3750(general,)X
+4030(we)X
+4147(have)X
+555 3873(chosen)N
+798(it)X
+862(for)X
+976(our)X
+1103(logging)X
+1367(protocol.)X
+755 3996(In)N
+3 f
+843(before-image)X
+1315(logging)X
+1 f
+1563(,)X
+1604(we)X
+1719(log)X
+1842(a)X
+1899(copy)X
+2076(of)X
+2164(the)X
+2283(data)X
+2438(before)X
+2665(the)X
+2784(update,)X
+3039(while)X
+3238(in)X
+3 f
+3321(after-image)X
+3739(logging)X
+1 f
+3987(,)X
+4027(we)X
+4141(log)X
+4263(a)X
+555 4086(copy)N
+740(of)X
+836(the)X
+963(data)X
+1126(after)X
+1303(the)X
+1429(update.)X
+1711(If)X
+1793(we)X
+1915(log)X
+2045(only)X
+2215(before-images,)X
+2723(then)X
+2889(there)X
+3078(is)X
+3159(suf\256cient)X
+3485(information)X
+3891(in)X
+3981(the)X
+4107(log)X
+4237(to)X
+555 4176(allow)N
+761(us)X
+860(to)X
+3 f
+950(undo)X
+1 f
+1150(the)X
+1276(transaction)X
+1656(\(go)X
+1791(back)X
+1971(to)X
+2061(the)X
+2187(state)X
+2361(represented)X
+2759(by)X
+2866(the)X
+2991(before-image\).)X
+3514(However,)X
+3876(if)X
+3952(the)X
+4077(system)X
+555 4266(crashes)N
+814(and)X
+952(a)X
+1010(committed)X
+1374(transaction's)X
+1806(changes)X
+2087(have)X
+2261(not)X
+2385(reached)X
+2658(the)X
+2778(disk,)X
+2953(we)X
+3068(have)X
+3241(no)X
+3342(means)X
+3568(to)X
+3 f
+3651(redo)X
+1 f
+3828(the)X
+3947(transaction)X
+555 4356(\(reapply)N
+849(the)X
+973(updates\).)X
+1311(Therefore,)X
+1675(logging)X
+1945(only)X
+2113(before-images)X
+2599(necessitates)X
+3004(forcing)X
+3262(dirty)X
+3439(pages)X
+3648(at)X
+3732(commit)X
+4002(time.)X
+4210(As)X
+555 4446(mentioned)N
+913(above,)X
+1145(forcing)X
+1397(pages)X
+1600(at)X
+1678(commit)X
+1942(is)X
+2015(considered)X
+2383(too)X
+2505(costly.)X
+755 4569(If)N
+834(we)X
+953(log)X
+1080(only)X
+1247(after-images,)X
+1694(then)X
+1857(there)X
+2043(is)X
+2121(suf\256cient)X
+2444(information)X
+2847(in)X
+2934(the)X
+3057(log)X
+3184(to)X
+3271(allow)X
+3474(us)X
+3570(to)X
+3657(redo)X
+3825(the)X
+3947(transaction)X
+555 4659(\(go)N
+687(forward)X
+967(to)X
+1054(the)X
+1177(state)X
+1348(represented)X
+1743(by)X
+1847(the)X
+1969(after-image\),)X
+2411(but)X
+2537(we)X
+2655(do)X
+2759(not)X
+2885(have)X
+3061(the)X
+3183(information)X
+3585(required)X
+3877(to)X
+3963(undo)X
+4147(tran-)X
+555 4749(sactions)N
+845(which)X
+1073(aborted)X
+1346(after)X
+1526(dirty)X
+1709(pages)X
+1924(were)X
+2113(written)X
+2372(to)X
+2466(disk.)X
+2670(Therefore,)X
+3039(logging)X
+3314(only)X
+3487(after-images)X
+3920(necessitates)X
+555 4839(holding)N
+819(all)X
+919(dirty)X
+1090(buffers)X
+1338(in)X
+1420(main)X
+1600(memory)X
+1887(until)X
+2053(commit)X
+2317(or)X
+2404(writing)X
+2655(them)X
+2835(to)X
+2917(a)X
+2973(temporary)X
+3323(\256le.)X
+755 4962(Since)N
+956(neither)X
+1202(constraint)X
+1541(\(forcing)X
+1823(pages)X
+2029(on)X
+2132(commit)X
+2399(or)X
+2489(buffering)X
+2811(pages)X
+3016(until)X
+3184(commit\))X
+3477(was)X
+3624(feasible,)X
+3916(we)X
+4032(chose)X
+4237(to)X
+555 5052(log)N
+683(both)X
+851(before)X
+1083(and)X
+1225(after)X
+1399(images.)X
+1672(The)X
+1823(only)X
+1991(remaining)X
+2342(consideration)X
+2800(is)X
+2879(when)X
+3079(changes)X
+3363(get)X
+3486(written)X
+3738(to)X
+3825(disk.)X
+4023(Changes)X
+555 5142(affect)N
+764(both)X
+931(data)X
+1090(pages)X
+1298(and)X
+1438(the)X
+1560(log.)X
+1726(If)X
+1804(the)X
+1926(changed)X
+2218(data)X
+2376(page)X
+2552(is)X
+2629(written)X
+2880(before)X
+3110(the)X
+3232(log)X
+3358(page,)X
+3554(and)X
+3694(the)X
+3816(system)X
+4062(crashes)X
+555 5232(before)N
+787(the)X
+911(log)X
+1039(page)X
+1217(is)X
+1296(written,)X
+1569(the)X
+1693(log)X
+1820(will)X
+1969(contain)X
+2230(insuf\256cient)X
+2615(information)X
+3018(to)X
+3105(undo)X
+3290(the)X
+3413(change.)X
+3706(This)X
+3873(violates)X
+4147(tran-)X
+555 5322(saction)N
+803(semantics,)X
+1160(since)X
+1346(some)X
+1536(changed)X
+1825(data)X
+1980(pages)X
+2184(may)X
+2343(not)X
+2466(have)X
+2638(been)X
+2810(written,)X
+3077(and)X
+3213(the)X
+3331(database)X
+3628(cannot)X
+3862(be)X
+3958(restored)X
+4237(to)X
+555 5412(its)N
+650(pre-transaction)X
+1152(state.)X
+755 5535(The)N
+914(log)X
+1050(record)X
+1290(describing)X
+1658(an)X
+1768(update)X
+2016(must)X
+2205(be)X
+2315(written)X
+2576(to)X
+2672(stable)X
+2893(storage)X
+3159(before)X
+3398(the)X
+3529(modi\256ed)X
+3846(page.)X
+4071(This)X
+4246(is)X
+3 f
+555 5625(write-ahead)N
+992(logging)X
+1 f
+1240(.)X
+1307(If)X
+1388(log)X
+1517(records)X
+1781(are)X
+1907(safely)X
+2126(written)X
+2380(to)X
+2469(disk,)X
+2649(data)X
+2810(pages)X
+3020(may)X
+3185(be)X
+3288(written)X
+3542(at)X
+3627(any)X
+3770(time)X
+3939(afterwards.)X
+555 5715(This)N
+721(means)X
+950(that)X
+1094(the)X
+1216(only)X
+1382(\256le)X
+1508(that)X
+1652(ever)X
+1815(needs)X
+2022(to)X
+2108(be)X
+2208(forced)X
+2438(to)X
+2524(disk)X
+2681(is)X
+2758(the)X
+2880(log.)X
+3046(Since)X
+3248(the)X
+3370(log)X
+3495(is)X
+3571(append-only,)X
+4015(modi\256ed)X
+
+4 p
+%%Page: 4 4
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+555 630(pages)N
+760(always)X
+1005(appear)X
+1242(at)X
+1322(the)X
+1442(end)X
+1580(and)X
+1718(may)X
+1878(be)X
+1976(written)X
+2224(to)X
+2307(disk)X
+2461(ef\256ciently)X
+2807(in)X
+2890(any)X
+3027(\256le)X
+3150(system)X
+3393(that)X
+3534(favors)X
+3756(sequential)X
+4102(order-)X
+555 720(ing)N
+677(\()X
+2 f
+704(e.g.)X
+1 f
+820(,)X
+860(FFS,)X
+1032(log-structured)X
+1502(\256le)X
+1624(system,)X
+1886(or)X
+1973(an)X
+2069(extent-based)X
+2495(system\).)X
+3 f
+555 906(3.1.2.)N
+775(Concurrency)X
+1245(Control)X
+1 f
+755 1029(The)N
+918(concurrency)X
+1354(control)X
+1619(protocol)X
+1923(is)X
+2013(responsible)X
+2415(for)X
+2546(maintaining)X
+2965(consistency)X
+3376(in)X
+3475(the)X
+3610(presence)X
+3929(of)X
+4033(multiple)X
+555 1119(accesses.)N
+897(There)X
+1114(are)X
+1242(several)X
+1499(alternative)X
+1867(solutions)X
+2183(such)X
+2358(as)X
+2453(locking,)X
+2741(optimistic)X
+3088(concurrency)X
+3514(control)X
+3769([KUNG81],)X
+4183(and)X
+555 1209(timestamp)N
+912(ordering)X
+1208([BERN80].)X
+1619(Since)X
+1821(optimistic)X
+2164(methods)X
+2459(and)X
+2599(timestamp)X
+2956(ordering)X
+3252(are)X
+3374(generally)X
+3696(more)X
+3884(complex)X
+4183(and)X
+555 1299(restrict)N
+804(concurrency)X
+1228(without)X
+1498(eliminating)X
+1888(starvation)X
+2230(or)X
+2323(deadlocks,)X
+2690(we)X
+2810(chose)X
+3018(two-phase)X
+3373(locking)X
+3638(\(2PL\).)X
+3890(Strict)X
+4088(2PL)X
+4246(is)X
+555 1389(suboptimal)N
+935(for)X
+1054(certain)X
+1297(data)X
+1455(structures)X
+1791(such)X
+1962(as)X
+2053(B-trees)X
+2309(because)X
+2588(it)X
+2656(can)X
+2792(limit)X
+2966(concurrency,)X
+3408(so)X
+3503(we)X
+3621(use)X
+3752(a)X
+3812(special)X
+4059(locking)X
+555 1479(protocol)N
+842(based)X
+1045(on)X
+1145(one)X
+1281(described)X
+1609(in)X
+1691([LEHM81].)X
+755 1602(The)N
+901(B-tree)X
+1123(locking)X
+1384(protocol)X
+1672(we)X
+1787(implemented)X
+2226(releases)X
+2502(locks)X
+2691(at)X
+2769(internal)X
+3034(nodes)X
+3241(in)X
+3323(the)X
+3441(tree)X
+3582(as)X
+3669(it)X
+3733(descends.)X
+4083(A)X
+4161(lock)X
+555 1692(on)N
+658(an)X
+757(internal)X
+1025(page)X
+1200(is)X
+1276(always)X
+1522(released)X
+1808(before)X
+2036(a)X
+2094(lock)X
+2254(on)X
+2356(its)X
+2453(child)X
+2635(is)X
+2710(obtained)X
+3008(\(that)X
+3177(is,)X
+3272(locks)X
+3463(are)X
+3584(not)X
+3 f
+3708(coupled)X
+1 f
+3996([BAY77])X
+555 1782(during)N
+786(descent\).)X
+1116(When)X
+1330(a)X
+1388(leaf)X
+1531(\(or)X
+1647(internal\))X
+1941(page)X
+2115(is)X
+2190(split,)X
+2369(a)X
+2427(write)X
+2614(lock)X
+2774(is)X
+2849(acquired)X
+3148(on)X
+3250(the)X
+3370(parent)X
+3593(before)X
+3821(the)X
+3941(lock)X
+4100(on)X
+4201(the)X
+555 1872(just-split)N
+855(page)X
+1028(is)X
+1102(released)X
+1387(\(locks)X
+1604(are)X
+3 f
+1724(coupled)X
+1 f
+2011(during)X
+2241(ascent\).)X
+2530(Write)X
+2734(locks)X
+2924(on)X
+3025(internal)X
+3291(pages)X
+3495(are)X
+3615(released)X
+3899(immediately)X
+555 1962(after)N
+723(the)X
+841(page)X
+1013(is)X
+1086(updated,)X
+1380(but)X
+1502(locks)X
+1691(on)X
+1791(leaf)X
+1932(pages)X
+2135(are)X
+2254(held)X
+2412(until)X
+2578(the)X
+2696(end)X
+2832(of)X
+2919(the)X
+3037(transaction.)X
+755 2085(Since)N
+964(locks)X
+1164(are)X
+1294(released)X
+1589(during)X
+1828(descent,)X
+2119(the)X
+2247(structure)X
+2558(of)X
+2655(the)X
+2783(tree)X
+2934(may)X
+3102(change)X
+3360(above)X
+3582(a)X
+3648(node)X
+3834(being)X
+4042(used)X
+4219(by)X
+555 2175(some)N
+752(process.)X
+1061(If)X
+1143(that)X
+1291(process)X
+1560(must)X
+1743(later)X
+1914(ascend)X
+2161(the)X
+2287(tree)X
+2435(because)X
+2717(of)X
+2811(a)X
+2874(page)X
+3053(split,)X
+3237(any)X
+3380(such)X
+3554(change)X
+3809(must)X
+3991(not)X
+4120(cause)X
+555 2265(confusion.)N
+938(We)X
+1077(use)X
+1211(the)X
+1336(technique)X
+1675(described)X
+2010(in)X
+2099([LEHM81])X
+2487(which)X
+2710(exploits)X
+2989(the)X
+3113(ordering)X
+3411(of)X
+3504(data)X
+3664(on)X
+3770(a)X
+3832(B-tree)X
+4059(page)X
+4237(to)X
+555 2355(guarantee)N
+888(that)X
+1028(no)X
+1128(process)X
+1389(ever)X
+1548(gets)X
+1697(lost)X
+1832(as)X
+1919(a)X
+1975(result)X
+2173(of)X
+2260(internal)X
+2525(page)X
+2697(updates)X
+2962(made)X
+3156(by)X
+3256(other)X
+3441(processes.)X
+755 2478(If)N
+836(a)X
+899(transaction)X
+1278(that)X
+1425(updates)X
+1697(a)X
+1760(B-tree)X
+1988(aborts,)X
+2231(the)X
+2356(user-visible)X
+2757(changes)X
+3043(to)X
+3131(the)X
+3255(tree)X
+3402(must)X
+3583(be)X
+3685(rolled)X
+3898(back.)X
+4116(How-)X
+555 2568(ever,)N
+735(changes)X
+1015(to)X
+1097(the)X
+1215(internal)X
+1480(nodes)X
+1687(of)X
+1774(the)X
+1892(tree)X
+2033(need)X
+2205(not)X
+2327(be)X
+2423(rolled)X
+2630(back,)X
+2822(since)X
+3007(these)X
+3192(pages)X
+3395(contain)X
+3651(no)X
+3751(user-visible)X
+4145(data.)X
+555 2658(When)N
+771(rolling)X
+1008(back)X
+1184(a)X
+1244(transaction,)X
+1640(we)X
+1758(roll)X
+1893(back)X
+2069(all)X
+2173(leaf)X
+2318(page)X
+2494(updates,)X
+2783(but)X
+2909(no)X
+3013(internal)X
+3281(insertions)X
+3615(or)X
+3705(page)X
+3880(splits.)X
+4111(In)X
+4201(the)X
+555 2748(worst)N
+759(case,)X
+944(this)X
+1085(will)X
+1235(leave)X
+1431(a)X
+1493(leaf)X
+1640(page)X
+1818(less)X
+1964(than)X
+2128(half)X
+2279(full.)X
+2456(This)X
+2624(may)X
+2788(cause)X
+2993(poor)X
+3166(space)X
+3371(utilization,)X
+3741(but)X
+3869(does)X
+4042(not)X
+4170(lose)X
+555 2838(user)N
+709(data.)X
+755 2961(Holding)N
+1038(locks)X
+1228(on)X
+1329(leaf)X
+1471(pages)X
+1675(until)X
+1842(transaction)X
+2215(commit)X
+2480(guarantees)X
+2845(that)X
+2986(no)X
+3087(other)X
+3273(process)X
+3535(can)X
+3668(insert)X
+3866(or)X
+3953(delete)X
+4165(data)X
+555 3051(that)N
+711(has)X
+854(been)X
+1042(touched)X
+1332(by)X
+1448(this)X
+1598(process.)X
+1914(Rolling)X
+2188(back)X
+2375(insertions)X
+2721(and)X
+2872(deletions)X
+3196(on)X
+3311(leaf)X
+3467(pages)X
+3685(guarantees)X
+4064(that)X
+4219(no)X
+555 3141(aborted)N
+819(updates)X
+1087(are)X
+1209(ever)X
+1371(visible)X
+1607(to)X
+1692(other)X
+1880(transactions.)X
+2326(Leaving)X
+2612(page)X
+2787(splits)X
+2978(intact)X
+3179(permits)X
+3442(us)X
+3536(to)X
+3621(release)X
+3867(internal)X
+4134(write)X
+555 3231(locks)N
+744(early.)X
+965(Thus)X
+1145(transaction)X
+1517(semantics)X
+1853(are)X
+1972(preserved,)X
+2325(and)X
+2461(locks)X
+2650(are)X
+2769(held)X
+2927(for)X
+3041(shorter)X
+3284(periods.)X
+755 3354(The)N
+901(extra)X
+1083(complexity)X
+1464(introduced)X
+1828(by)X
+1929(this)X
+2065(locking)X
+2326(protocol)X
+2614(appears)X
+2881(substantial,)X
+3264(but)X
+3387(it)X
+3452(is)X
+3525(important)X
+3856(for)X
+3970(multi-user)X
+555 3444(execution.)N
+950(The)X
+1118(bene\256ts)X
+1410(of)X
+1520(non-two-phase)X
+2040(locking)X
+2323(on)X
+2446(B-trees)X
+2721(are)X
+2863(well)X
+3044(established)X
+3443(in)X
+3548(the)X
+3689(database)X
+4009(literature)X
+555 3534([BAY77],)N
+899([LEHM81].)X
+1320(If)X
+1394(a)X
+1450(process)X
+1711(held)X
+1869(locks)X
+2058(until)X
+2224(it)X
+2288(committed,)X
+2670(then)X
+2828(a)X
+2884(long-running)X
+3322(update)X
+3556(could)X
+3754(lock)X
+3912(out)X
+4034(all)X
+4134(other)X
+555 3624(transactions)N
+967(by)X
+1076(preventing)X
+1448(any)X
+1593(other)X
+1787(process)X
+2057(from)X
+2241(locking)X
+2509(the)X
+2635(root)X
+2792(page)X
+2972(of)X
+3067(the)X
+3193(tree.)X
+3382(The)X
+3535(B-tree)X
+3764(locking)X
+4032(protocol)X
+555 3714(described)N
+884(above)X
+1096(guarantees)X
+1460(that)X
+1600(locks)X
+1789(on)X
+1889(internal)X
+2154(pages)X
+2357(are)X
+2476(held)X
+2634(for)X
+2748(extremely)X
+3089(short)X
+3269(periods,)X
+3545(thereby)X
+3806(increasing)X
+4156(con-)X
+555 3804(currency.)N
+3 f
+555 3990(3.1.3.)N
+775(Management)X
+1245(of)X
+1332(Shared)X
+1596(Data)X
+1 f
+755 4113(Database)N
+1075(systems)X
+1353(permit)X
+1587(many)X
+1790(users)X
+1980(to)X
+2067(examine)X
+2364(and)X
+2505(update)X
+2744(the)X
+2866(same)X
+3055(data)X
+3213(concurrently.)X
+3683(In)X
+3774(order)X
+3968(to)X
+4054(provide)X
+555 4203(this)N
+702(concurrent)X
+1078(access)X
+1316(and)X
+1464(enforce)X
+1738(the)X
+1868(write-ahead)X
+2280(logging)X
+2556(protocol)X
+2855(described)X
+3195(in)X
+3289(section)X
+3548(3.1.1,)X
+3759(we)X
+3884(use)X
+4022(a)X
+4089(shared)X
+555 4293(memory)N
+848(buffer)X
+1071(manager.)X
+1414(Not)X
+1559(only)X
+1726(does)X
+1898(this)X
+2038(provide)X
+2308(the)X
+2431(guarantees)X
+2800(we)X
+2919(require,)X
+3192(but)X
+3319(a)X
+3380(user-level)X
+3722(buffer)X
+3944(manager)X
+4246(is)X
+555 4383(frequently)N
+916(faster)X
+1126(than)X
+1295(using)X
+1498(the)X
+1626(\256le)X
+1758(system)X
+2010(buffer)X
+2237(cache.)X
+2491(Reads)X
+2717(or)X
+2814(writes)X
+3040(involving)X
+3376(the)X
+3504(\256le)X
+3636(system)X
+3888(buffer)X
+4115(cache)X
+555 4473(often)N
+746(require)X
+1000(copying)X
+1284(data)X
+1444(between)X
+1738(user)X
+1898(and)X
+2040(kernel)X
+2266(space)X
+2470(while)X
+2673(a)X
+2734(user-level)X
+3076(buffer)X
+3298(manager)X
+3600(can)X
+3737(return)X
+3954(pointers)X
+4237(to)X
+555 4563(data)N
+709(pages)X
+912(directly.)X
+1217(Additionally,)X
+1661(if)X
+1730(more)X
+1915(than)X
+2073(one)X
+2209(process)X
+2470(uses)X
+2628(the)X
+2746(same)X
+2931(page,)X
+3123(then)X
+3281(fewer)X
+3485(copies)X
+3710(may)X
+3868(be)X
+3964(required.)X
+3 f
+555 4749(3.2.)N
+715(Module)X
+997(Architecture)X
+1 f
+755 4872(The)N
+913(preceding)X
+1262(sections)X
+1552(described)X
+1892(modules)X
+2195(for)X
+2321(managing)X
+2669(the)X
+2799(transaction)X
+3183(log,)X
+3337(locks,)X
+3558(and)X
+3706(a)X
+3774(cache)X
+3990(of)X
+4089(shared)X
+555 4962(buffers.)N
+847(In)X
+938(addition,)X
+1244(we)X
+1362(need)X
+1538(to)X
+1624(provide)X
+1893(functionality)X
+2326(for)X
+2444(transaction)X
+2 f
+2819(begin)X
+1 f
+2997(,)X
+2 f
+3040(commit)X
+1 f
+3276(,)X
+3319(and)X
+2 f
+3458(abort)X
+1 f
+3654(processing,)X
+4040(necessi-)X
+555 5052(tating)N
+769(a)X
+837(transaction)X
+1221(manager.)X
+1570(In)X
+1669(order)X
+1871(to)X
+1965(arbitrate)X
+2265(concurrent)X
+2641(access)X
+2879(to)X
+2973(locks)X
+3173(and)X
+3320(buffers,)X
+3599(we)X
+3724(include)X
+3991(a)X
+4058(process)X
+555 5142(management)N
+995(module)X
+1264(which)X
+1489(manages)X
+1799(a)X
+1864(collection)X
+2209(of)X
+2305(semaphores)X
+2713(used)X
+2889(to)X
+2980(block)X
+3187(and)X
+3332(release)X
+3585(processes.)X
+3962(Finally,)X
+4237(in)X
+555 5232(order)N
+752(to)X
+841(provide)X
+1113(a)X
+1176(simple,)X
+1436(standard)X
+1735(interface)X
+2044(we)X
+2165(have)X
+2344(modi\256ed)X
+2655(the)X
+2780(database)X
+3084(access)X
+3317(routines)X
+3602(\()X
+3 f
+3629(db)X
+1 f
+3717(\(3\)\).)X
+3904(For)X
+4041(the)X
+4165(pur-)X
+555 5322(poses)N
+758(of)X
+850(this)X
+990(paper)X
+1194(we)X
+1313(call)X
+1453(the)X
+1575(modi\256ed)X
+1883(package)X
+2171(the)X
+3 f
+2293(Record)X
+2567(Manager)X
+1 f
+2879(.)X
+2943(Figure)X
+3176(one)X
+3316(shows)X
+3540(the)X
+3662(main)X
+3846(interfaces)X
+4183(and)X
+555 5412(architecture)N
+955(of)X
+1042(LIBTP.)X
+
+5 p
+%%Page: 5 5
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+11 s
+1851 1520(log_commit)N
+2764 2077(buf_unpin)N
+2764 1987(buf_get)N
+3633 1408(buf_unpin)N
+3633 1319(buf_pin)N
+3633 1230(buf_get)N
+3 f
+17 s
+1163 960(Txn)N
+1430(M)X
+1559(anager)X
+2582(Record)X
+3040(M)X
+3169(anager)X
+1 Dt
+2363 726 MXY
+0 355 Dl
+1426 0 Dl
+0 -355 Dl
+-1426 0 Dl
+3255 1616 MXY
+0 535 Dl
+534 0 Dl
+0 -535 Dl
+-534 0 Dl
+2185 MX
+0 535 Dl
+535 0 Dl
+0 -535 Dl
+-535 0 Dl
+1116 MX
+0 535 Dl
+534 0 Dl
+0 -535 Dl
+-534 0 Dl
+726 MY
+0 355 Dl
+891 0 Dl
+0 -355 Dl
+-891 0 Dl
+1 f
+11 s
+2207 1297(lock)N
+2564 1386(log)N
+865(unlock_all)X
+1851 1609(log_unroll)N
+1650 2508 MXY
+0 178 Dl
+1605 0 Dl
+0 -178 Dl
+-1605 0 Dl
+1294 1616 MXY
+19 -30 Dl
+-19 11 Dl
+-20 -11 Dl
+20 30 Dl
+0 -535 Dl
+2319 2508 MXY
+-22 -30 Dl
+4 23 Dl
+-18 14 Dl
+36 -7 Dl
+-936 -357 Dl
+3277 2455(sleep_on)N
+1405 1616 MXY
+36 4 Dl
+-18 -13 Dl
+1 -22 Dl
+-19 31 Dl
+1070 -535 Dl
+2631 2508 MXY
+36 6 Dl
+-18 -14 Dl
+3 -22 Dl
+-21 30 Dl
+891 -357 Dl
+1426 2455(sleep_on)N
+3255 1884 MXY
+-31 -20 Dl
+11 20 Dl
+-11 19 Dl
+31 -19 Dl
+-535 0 Dl
+1554 2366(wake)N
+3277(wake)X
+2185 1884 MXY
+-31 -20 Dl
+12 20 Dl
+-12 19 Dl
+31 -19 Dl
+-356 0 Dl
+0 -803 Dl
+3 f
+17 s
+1236 1851(Lock)N
+1118 2030(M)N
+1247(anager)X
+2339 1851(Log)N
+2187 2030(M)N
+2316(anager)X
+3333 1851(Buffer)N
+3257 2030(M)N
+3386(anager)X
+3522 1616 MXY
+20 -30 Dl
+-20 11 Dl
+-20 -11 Dl
+20 30 Dl
+0 -535 Dl
+1950 2654(Process)N
+2424(M)X
+2553(anager)X
+2542 1616 MXY
+19 -30 Dl
+-19 11 Dl
+-20 -11 Dl
+20 30 Dl
+0 -535 Dl
+1 f
+11 s
+2207 1364(unlock)N
+2452 2508 MXY
+20 -31 Dl
+-20 11 Dl
+-19 -11 Dl
+19 31 Dl
+0 -357 Dl
+2497 2322(sleep_on)N
+2497 2233(wake)N
+3 Dt
+-1 Ds
+3 f
+10 s
+1790 2830(Figure)N
+2037(1:)X
+2144(Library)X
+2435(module)X
+2708(interfaces.)X
+1 f
+10 f
+555 3010(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+3 f
+555 3286(3.2.1.)N
+775(The)X
+928(Log)X
+1081(Manager)X
+1 f
+755 3409(The)N
+3 f
+907(Log)X
+1067(Manager)X
+1 f
+1406(enforces)X
+1706(the)X
+1831(write-ahead)X
+2238(logging)X
+2509(protocol.)X
+2843(Its)X
+2949(primitive)X
+3268(operations)X
+3628(are)X
+2 f
+3753(log)X
+1 f
+3855(,)X
+2 f
+3901(log_commit)X
+1 f
+4279(,)X
+2 f
+555 3499(log_read)N
+1 f
+844(,)X
+2 f
+889(log_roll)X
+1 f
+1171(and)X
+2 f
+1312(log_unroll)X
+1 f
+1649(.)X
+1714(The)X
+2 f
+1864(log)X
+1 f
+1991(call)X
+2132(performs)X
+2447(a)X
+2508(buffered)X
+2806(write)X
+2996(of)X
+3088(the)X
+3211(speci\256ed)X
+3520(log)X
+3646(record)X
+3876(and)X
+4016(returns)X
+4263(a)X
+555 3589(unique)N
+809(log)X
+947(sequence)X
+1278(number)X
+1559(\(LSN\).)X
+1840(This)X
+2017(LSN)X
+2203(may)X
+2376(then)X
+2549(be)X
+2660(used)X
+2842(to)X
+2939(retrieve)X
+3220(a)X
+3291(record)X
+3532(from)X
+3723(the)X
+3856(log)X
+3993(using)X
+4201(the)X
+2 f
+555 3679(log_read)N
+1 f
+865(call.)X
+1042(The)X
+2 f
+1188(log)X
+1 f
+1311(interface)X
+1614(knows)X
+1844(very)X
+2008(little)X
+2175(about)X
+2374(the)X
+2493(internal)X
+2759(format)X
+2993(of)X
+3080(the)X
+3198(log)X
+3320(records)X
+3577(it)X
+3641(receives.)X
+3965(Rather,)X
+4219(all)X
+555 3769(log)N
+681(records)X
+942(are)X
+1065 0.4028(referenced)AX
+1430(by)X
+1534(a)X
+1594(header)X
+1833(structure,)X
+2158(a)X
+2218(log)X
+2344(record)X
+2574(type,)X
+2756(and)X
+2896(a)X
+2956(character)X
+3276(buffer)X
+3497(containing)X
+3859(the)X
+3981(data)X
+4138(to)X
+4223(be)X
+555 3859(logged.)N
+834(The)X
+980(log)X
+1103(record)X
+1330(type)X
+1489(is)X
+1563(used)X
+1731(to)X
+1814(call)X
+1951(the)X
+2070(appropriate)X
+2457(redo)X
+2621(and)X
+2758(undo)X
+2939(routines)X
+3217(during)X
+2 f
+3446(abort)X
+1 f
+3639(and)X
+2 f
+3775(commit)X
+1 f
+4031(process-)X
+555 3949(ing.)N
+721(While)X
+941(we)X
+1059(have)X
+1235(used)X
+1406(the)X
+3 f
+1528(Log)X
+1684(Manager)X
+1 f
+2019(to)X
+2104(provide)X
+2372(before)X
+2601(and)X
+2740(after)X
+2911(image)X
+3130(logging,)X
+3417(it)X
+3484(may)X
+3645(also)X
+3797(be)X
+3896(used)X
+4066(for)X
+4183(any)X
+555 4039(of)N
+642(the)X
+760(logging)X
+1024(algorithms)X
+1386(discussed.)X
+755 4162(The)N
+2 f
+905(log_commit)X
+1 f
+1308(operation)X
+1636(behaves)X
+1920(exactly)X
+2177(like)X
+2322(the)X
+2 f
+2445(log)X
+1 f
+2572(operation)X
+2900(but)X
+3026(guarantees)X
+3394(that)X
+3538(the)X
+3660(log)X
+3786(has)X
+3917(been)X
+4093(forced)X
+555 4252(to)N
+643(disk)X
+802(before)X
+1034(returning.)X
+1394(A)X
+1478(discussion)X
+1837(of)X
+1930(our)X
+2063(commit)X
+2333(strategy)X
+2613(appears)X
+2884(in)X
+2971(the)X
+3094(implementation)X
+3621(section)X
+3873(\(section)X
+4152(4.2\).)X
+2 f
+555 4342(Log_unroll)N
+1 f
+935(reads)X
+1126(log)X
+1249(records)X
+1507(from)X
+1684(the)X
+1803(log,)X
+1946(following)X
+2278(backward)X
+2611(transaction)X
+2983(pointers)X
+3261(and)X
+3397(calling)X
+3635(the)X
+3753(appropriate)X
+4139(undo)X
+555 4432(routines)N
+839(to)X
+927(implement)X
+1295(transaction)X
+1673(abort.)X
+1904(In)X
+1997(a)X
+2059(similar)X
+2307(manner,)X
+2 f
+2594(log_roll)X
+1 f
+2877(reads)X
+3073(log)X
+3201(records)X
+3464(sequentially)X
+3877(forward,)X
+4178(cal-)X
+555 4522(ling)N
+699(the)X
+817(appropriate)X
+1203(redo)X
+1366(routines)X
+1644(to)X
+1726(recover)X
+1988(committed)X
+2350(transactions)X
+2753(after)X
+2921(a)X
+2977(system)X
+3219(crash.)X
+3 f
+555 4708(3.2.2.)N
+775(The)X
+928(Buffer)X
+1171(Manager)X
+1 f
+755 4831(The)N
+3 f
+912(Buffer)X
+1167(Manager)X
+1 f
+1511(uses)X
+1681(a)X
+1749(pool)X
+1923(of)X
+2022(shared)X
+2264(memory)X
+2563(to)X
+2657(provide)X
+2934(a)X
+3002(least-recently-used)X
+3641(\(LRU\))X
+3886(block)X
+4095(cache.)X
+555 4921(Although)N
+886(the)X
+1013(current)X
+1270(library)X
+1513(provides)X
+1818(an)X
+1923(LRU)X
+2112(cache,)X
+2345(it)X
+2418(would)X
+2647(be)X
+2752(simple)X
+2994(to)X
+3085(add)X
+3229(alternate)X
+3534(replacement)X
+3955(policies)X
+4232(as)X
+555 5011(suggested)N
+903(by)X
+1015([CHOU85])X
+1408(or)X
+1507(to)X
+1601(provide)X
+1878(multiple)X
+2176(buffer)X
+2405(pools)X
+2610(with)X
+2784(different)X
+3092(policies.)X
+3412(Transactions)X
+3853(request)X
+4116(pages)X
+555 5101(from)N
+736(the)X
+859(buffer)X
+1081(manager)X
+1383(and)X
+1524(keep)X
+1701(them)X
+3 f
+1886(pinned)X
+1 f
+2145(to)X
+2232(ensure)X
+2466(that)X
+2610(they)X
+2772(are)X
+2895(not)X
+3021(written)X
+3272(to)X
+3358(disk)X
+3515(while)X
+3717(they)X
+3879(are)X
+4002(in)X
+4088(a)X
+4148(logi-)X
+555 5191(cally)N
+732(inconsistent)X
+1135(state.)X
+1343(When)X
+1556(page)X
+1729(replacement)X
+2143(is)X
+2217(necessary,)X
+2571(the)X
+3 f
+2689(Buffer)X
+2932(Manager)X
+1 f
+3264(\256nds)X
+3439(an)X
+3535(unpinned)X
+3853(page)X
+4025(and)X
+4161(then)X
+555 5281(checks)N
+794(with)X
+956(the)X
+3 f
+1074(Log)X
+1227(Manager)X
+1 f
+1559(to)X
+1641(ensure)X
+1871(that)X
+2011(the)X
+2129(write-ahead)X
+2529(protocol)X
+2816(is)X
+2889(enforced.)X
+3 f
+555 5467(3.2.3.)N
+775(The)X
+928(Lock)X
+1121(Manager)X
+1 f
+755 5590(The)N
+3 f
+901(Lock)X
+1095(Manager)X
+1 f
+1428(supports)X
+1720(general)X
+1978(purpose)X
+2253(locking)X
+2514(\(single)X
+2753(writer,)X
+2986(multiple)X
+3273(readers\))X
+3553(which)X
+3769(is)X
+3842(currently)X
+4152(used)X
+555 5680(to)N
+638(provide)X
+904(two-phase)X
+1254(locking)X
+1514(and)X
+1650(high)X
+1812(concurrency)X
+2230(B-tree)X
+2451(locking.)X
+2751(However,)X
+3086(the)X
+3204(general)X
+3461(purpose)X
+3735(nature)X
+3956(of)X
+4043(the)X
+4161(lock)X
+
+6 p
+%%Page: 6 6
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+555 630(manager)N
+857(provides)X
+1158(the)X
+1281(ability)X
+1510(to)X
+1597(support)X
+1862(a)X
+1923(variety)X
+2171(of)X
+2263(locking)X
+2528(protocols.)X
+2890(Currently,)X
+3241(all)X
+3345(locks)X
+3538(are)X
+3661(issued)X
+3885(at)X
+3967(the)X
+4089(granu-)X
+555 720(larity)N
+747(of)X
+837(a)X
+896(page)X
+1071(\(the)X
+1219(size)X
+1367(of)X
+1457(a)X
+1516(buffer)X
+1736(in)X
+1821(the)X
+1942(buffer)X
+2161(pool\))X
+2352(which)X
+2570(is)X
+2645(identi\256ed)X
+2969(by)X
+3071(two)X
+3213(4-byte)X
+3440(integers)X
+3716(\(a)X
+3801(\256le)X
+3925(id)X
+4009(and)X
+4147(page)X
+555 810(number\).)N
+898(This)X
+1071(provides)X
+1378(the)X
+1507(necessary)X
+1851(information)X
+2259(to)X
+2351(extend)X
+2595(the)X
+3 f
+2723(Lock)X
+2926(Manager)X
+1 f
+3268(to)X
+3360(perform)X
+3649(hierarchical)X
+4059(locking)X
+555 900([GRAY76].)N
+982(The)X
+1133(current)X
+1387(implementation)X
+1915(does)X
+2088(not)X
+2216(support)X
+2482(locks)X
+2677(at)X
+2760(other)X
+2950(granularities)X
+3376(and)X
+3517(does)X
+3689(not)X
+3816(promote)X
+4108(locks;)X
+555 990(these)N
+740(are)X
+859(obvious)X
+1132(future)X
+1344(additions)X
+1657(to)X
+1739(the)X
+1857(system.)X
+755 1113(If)N
+831(an)X
+929(incoming)X
+1253(lock)X
+1413(request)X
+1667(cannot)X
+1903(be)X
+2001(granted,)X
+2284(the)X
+2404(requesting)X
+2760(process)X
+3023(is)X
+3098(queued)X
+3352(for)X
+3467(the)X
+3586(lock)X
+3745(and)X
+3882(descheduled.)X
+555 1203(When)N
+769(a)X
+827(lock)X
+987(is)X
+1062(released,)X
+1368(the)X
+1488(wait)X
+1647(queue)X
+1860(is)X
+1934(traversed)X
+2250(and)X
+2387(any)X
+2524(newly)X
+2741(compatible)X
+3118(locks)X
+3308(are)X
+3428(granted.)X
+3730(Locks)X
+3947(are)X
+4067(located)X
+555 1293(via)N
+680(a)X
+743(\256le)X
+872(and)X
+1015(page)X
+1194(hash)X
+1368(table)X
+1551(and)X
+1694(are)X
+1820(chained)X
+2097(both)X
+2266(by)X
+2373(object)X
+2595(and)X
+2737(by)X
+2843(transaction,)X
+3241(facilitating)X
+3614(rapid)X
+3805(traversal)X
+4108(of)X
+4201(the)X
+555 1383(lock)N
+713(table)X
+889(during)X
+1118(transaction)X
+1490(commit)X
+1754(and)X
+1890(abort.)X
+755 1506(The)N
+907(primary)X
+1188(interfaces)X
+1528(to)X
+1617(the)X
+1742(lock)X
+1907(manager)X
+2211(are)X
+2 f
+2337(lock)X
+1 f
+2471(,)X
+2 f
+2518(unlock)X
+1 f
+2732(,)X
+2779(and)X
+2 f
+2922(lock_unlock_all)X
+1 f
+3434(.)X
+2 f
+3500(Lock)X
+1 f
+3682(obtains)X
+3939(a)X
+4001(new)X
+4161(lock)X
+555 1596(for)N
+680(a)X
+747(speci\256c)X
+1023(object.)X
+1290(There)X
+1509(are)X
+1638(also)X
+1797(two)X
+1947(variants)X
+2231(of)X
+2328(the)X
+2 f
+2456(lock)X
+1 f
+2620(request,)X
+2 f
+2902(lock_upgrade)X
+1 f
+3373(and)X
+2 f
+3519(lock_downgrade)X
+1 f
+4053(,)X
+4103(which)X
+555 1686(allow)N
+755(the)X
+875(caller)X
+1076(to)X
+1160(atomically)X
+1519(trade)X
+1701(a)X
+1758(lock)X
+1917(of)X
+2005(one)X
+2142(type)X
+2301(for)X
+2416(a)X
+2473(lock)X
+2632(of)X
+2720(another.)X
+2 f
+3022(Unlock)X
+1 f
+3275(releases)X
+3551(a)X
+3608(speci\256c)X
+3874(mode)X
+4073(of)X
+4161(lock)X
+555 1776(on)N
+655(a)X
+711(speci\256c)X
+976(object.)X
+2 f
+1232(Lock_unlock_all)X
+1 f
+1786(releases)X
+2061(all)X
+2161(the)X
+2279(locks)X
+2468(associated)X
+2818(with)X
+2980(a)X
+3036(speci\256c)X
+3301(transaction.)X
+3 f
+555 1962(3.2.4.)N
+775(The)X
+928(Process)X
+1207(Manager)X
+1 f
+755 2085(The)N
+3 f
+900(Process)X
+1179(Manager)X
+1 f
+1511(acts)X
+1656(as)X
+1743(a)X
+1799(user-level)X
+2136(scheduler)X
+2464(to)X
+2546(make)X
+2740(processes)X
+3068(wait)X
+3226(on)X
+3326(unavailable)X
+3716(locks)X
+3905(and)X
+4041(pending)X
+555 2175(buffer)N
+778(cache)X
+988(I/O.)X
+1161(For)X
+1297(each)X
+1470(process,)X
+1756(a)X
+1817(semaphore)X
+2190(is)X
+2268(maintained)X
+2649(upon)X
+2834(which)X
+3055(that)X
+3200(process)X
+3466(waits)X
+3660(when)X
+3859(it)X
+3928(needs)X
+4136(to)X
+4223(be)X
+555 2265(descheduled.)N
+1014(When)X
+1228(a)X
+1286(process)X
+1549(needs)X
+1754(to)X
+1838(be)X
+1936(run,)X
+2084(its)X
+2180(semaphore)X
+2549(is)X
+2623(cleared,)X
+2897(and)X
+3034(the)X
+3153(operating)X
+3477(system)X
+3720(reschedules)X
+4116(it.)X
+4201(No)X
+555 2355(sophisticated)N
+1002(scheduling)X
+1378(algorithm)X
+1718(is)X
+1799(applied;)X
+2085(if)X
+2162(the)X
+2288(lock)X
+2454(for)X
+2576(which)X
+2800(a)X
+2864(process)X
+3133(was)X
+3286(waiting)X
+3554(becomes)X
+3863(available,)X
+4201(the)X
+555 2445(process)N
+824(is)X
+905(made)X
+1107(runnable.)X
+1456(It)X
+1533(would)X
+1761(have)X
+1941(been)X
+2121(possible)X
+2411(to)X
+2501(change)X
+2757(the)X
+2883(kernel's)X
+3170(process)X
+3439(scheduler)X
+3775(to)X
+3865(interact)X
+4134(more)X
+555 2535(ef\256ciently)N
+900(with)X
+1062(the)X
+1180(lock)X
+1338(manager,)X
+1655(but)X
+1777(doing)X
+1979(so)X
+2070(would)X
+2290(have)X
+2462(compromised)X
+2918(our)X
+3045(commitment)X
+3469(to)X
+3551(a)X
+3607(user-level)X
+3944(package.)X
+3 f
+555 2721(3.2.5.)N
+775(The)X
+928(Transaction)X
+1361(Manager)X
+1 f
+755 2844(The)N
+3 f
+901(Transaction)X
+1335(Manager)X
+1 f
+1668(provides)X
+1965(the)X
+2084(standard)X
+2377(interface)X
+2680(of)X
+2 f
+2768(txn_begin)X
+1 f
+3084(,)X
+2 f
+3125(txn_commit)X
+1 f
+3499(,)X
+3540(and)X
+2 f
+3676(txn_abort)X
+1 f
+3987(.)X
+4047(It)X
+4116(keeps)X
+555 2934(track)N
+742(of)X
+835(all)X
+941(active)X
+1159(transactions,)X
+1588(assigns)X
+1845(unique)X
+2089(transaction)X
+2467(identi\256ers,)X
+2833(and)X
+2974(directs)X
+3213(the)X
+3336(abort)X
+3526(and)X
+3667(commit)X
+3936(processing.)X
+555 3024(When)N
+772(a)X
+2 f
+833(txn_begin)X
+1 f
+1174(is)X
+1252(issued,)X
+1497(the)X
+3 f
+1620(Transaction)X
+2058(Manager)X
+1 f
+2395(assigns)X
+2651(the)X
+2773(next)X
+2935(available)X
+3249(transaction)X
+3625(identi\256er,)X
+3958(allocates)X
+4263(a)X
+555 3114(per-process)N
+948(transaction)X
+1322(structure)X
+1625(in)X
+1709(shared)X
+1941(memory,)X
+2249(increments)X
+2622(the)X
+2741(count)X
+2940(of)X
+3028(active)X
+3241(transactions,)X
+3665(and)X
+3802(returns)X
+4046(the)X
+4165(new)X
+555 3204(transaction)N
+937(identi\256er)X
+1256(to)X
+1348(the)X
+1476(calling)X
+1724(process.)X
+2034(The)X
+2188(in-memory)X
+2573(transaction)X
+2954(structure)X
+3264(contains)X
+3560(a)X
+3625(pointer)X
+3881(into)X
+4034(the)X
+4161(lock)X
+555 3294(table)N
+734(for)X
+851(locks)X
+1043(held)X
+1204(by)X
+1307(this)X
+1445(transaction,)X
+1840(the)X
+1961(last)X
+2095(log)X
+2220(sequence)X
+2538(number,)X
+2826(a)X
+2885(transaction)X
+3260(state)X
+3430(\()X
+2 f
+3457(idle)X
+1 f
+(,)S
+2 f
+3620(running)X
+1 f
+3873(,)X
+2 f
+3915(aborting)X
+1 f
+4190(,)X
+4232(or)X
+2 f
+555 3384(committing\))N
+1 f
+942(,)X
+982(an)X
+1078(error)X
+1255(code,)X
+1447(and)X
+1583(a)X
+1639(semaphore)X
+2007(identi\256er.)X
+755 3507(At)N
+859(commit,)X
+1147(the)X
+3 f
+1269(Transaction)X
+1706(Manager)X
+1 f
+2042(calls)X
+2 f
+2213(log_commit)X
+1 f
+2615(to)X
+2700(record)X
+2929(the)X
+3050(end)X
+3189(of)X
+3279(transaction)X
+3654(and)X
+3793(to)X
+3878(\257ush)X
+4056(the)X
+4177(log.)X
+555 3597(Then)N
+743(it)X
+810(directs)X
+1047(the)X
+3 f
+1168(Lock)X
+1364(Manager)X
+1 f
+1699(to)X
+1784(release)X
+2031(all)X
+2134(locks)X
+2325(associated)X
+2677(with)X
+2841(the)X
+2961(given)X
+3161(transaction.)X
+3575(If)X
+3651(a)X
+3709(transaction)X
+4083(aborts,)X
+555 3687(the)N
+3 f
+680(Transaction)X
+1120(Manager)X
+1 f
+1459(calls)X
+1633(on)X
+2 f
+1739(log_unroll)X
+1 f
+2102(to)X
+2190(read)X
+2355(the)X
+2479(transaction's)X
+2915(log)X
+3043(records)X
+3306(and)X
+3448(undo)X
+3634(any)X
+3776(modi\256cations)X
+4237(to)X
+555 3777(the)N
+673(database.)X
+1010(As)X
+1119(in)X
+1201(the)X
+1319(commit)X
+1583(case,)X
+1762(it)X
+1826(then)X
+1984(calls)X
+2 f
+2151(lock_unlock_all)X
+1 f
+2683(to)X
+2765(release)X
+3009(the)X
+3127(transaction's)X
+3557(locks.)X
+3 f
+555 3963(3.2.6.)N
+775(The)X
+928(Record)X
+1198(Manager)X
+1 f
+755 4086(The)N
+3 f
+919(Record)X
+1208(Manager)X
+1 f
+1559(supports)X
+1869(the)X
+2006(abstraction)X
+2397(of)X
+2503(reading)X
+2783(and)X
+2938(writing)X
+3208(records)X
+3484(to)X
+3585(a)X
+3660(database.)X
+3996(We)X
+4147(have)X
+555 4176(modi\256ed)N
+861(the)X
+981(the)X
+1101(database)X
+1399(access)X
+1626(routines)X
+3 f
+1905(db)X
+1 f
+1993(\(3\))X
+2108([BSD91])X
+2418(to)X
+2501(call)X
+2638(the)X
+2757(log,)X
+2900(lock,)X
+3079(and)X
+3216(buffer)X
+3434(managers.)X
+3803(In)X
+3891(order)X
+4082(to)X
+4165(pro-)X
+555 4266(vide)N
+718(functionality)X
+1152(to)X
+1239(perform)X
+1523(undo)X
+1708(and)X
+1849(redo,)X
+2037(the)X
+3 f
+2160(Record)X
+2434(Manager)X
+1 f
+2770(de\256nes)X
+3021(a)X
+3081(collection)X
+3421(of)X
+3512(log)X
+3638(record)X
+3868(types)X
+4061(and)X
+4201(the)X
+555 4356(associated)N
+920(undo)X
+1115(and)X
+1266(redo)X
+1444(routines.)X
+1777(The)X
+3 f
+1937(Log)X
+2105(Manager)X
+1 f
+2452(performs)X
+2777(a)X
+2848(table)X
+3039(lookup)X
+3296(on)X
+3411(the)X
+3543(record)X
+3783(type)X
+3955(to)X
+4051(call)X
+4201(the)X
+555 4446(appropriate)N
+951(routines.)X
+1299(For)X
+1440(example,)X
+1762(the)X
+1890(B-tree)X
+2121(access)X
+2356(method)X
+2625(requires)X
+2913(two)X
+3062(log)X
+3193(record)X
+3428(types:)X
+3648(insert)X
+3855(and)X
+4000(delete.)X
+4241(A)X
+555 4536(replace)N
+808(operation)X
+1131(is)X
+1204(implemented)X
+1642(as)X
+1729(a)X
+1785(delete)X
+1997(followed)X
+2302(by)X
+2402(an)X
+2498(insert)X
+2696(and)X
+2832(is)X
+2905(logged)X
+3143(accordingly.)X
+3 f
+555 4722(3.3.)N
+715(Application)X
+1134(Architectures)X
+1 f
+755 4845(The)N
+907(structure)X
+1215(of)X
+1309(LIBTP)X
+1558(allows)X
+1794(application)X
+2177(designers)X
+2507(to)X
+2596(trade)X
+2784(off)X
+2905(performance)X
+3339(and)X
+3481(protection.)X
+3872(Since)X
+4076(a)X
+4138(large)X
+555 4935(portion)N
+810(of)X
+901(LIBTP's)X
+1205(functionality)X
+1638(is)X
+1715(provided)X
+2024(by)X
+2128(managing)X
+2468(structures)X
+2804(in)X
+2889(shared)X
+3122(memory,)X
+3432(its)X
+3530(structures)X
+3865(are)X
+3987(subject)X
+4237(to)X
+555 5025(corruption)N
+926(by)X
+1043(applications)X
+1467(when)X
+1678(the)X
+1813(library)X
+2064(is)X
+2154(linked)X
+2391(directly)X
+2673(with)X
+2852(the)X
+2987(application.)X
+3420(For)X
+3568(this)X
+3720(reason,)X
+3987(LIBTP)X
+4246(is)X
+555 5115(designed)N
+864(to)X
+950(allow)X
+1152(compilation)X
+1558(into)X
+1706(a)X
+1766(separate)X
+2053(server)X
+2273(process)X
+2537(which)X
+2756(may)X
+2917(be)X
+3016(accessed)X
+3321(via)X
+3442(a)X
+3501(socket)X
+3729(interface.)X
+4094(In)X
+4184(this)X
+555 5205(way)N
+712(LIBTP's)X
+1015(data)X
+1172(structures)X
+1507(are)X
+1629(protected)X
+1951(from)X
+2130(application)X
+2509(code,)X
+2704(but)X
+2829(communication)X
+3349(overhead)X
+3666(is)X
+3741(increased.)X
+4107(When)X
+555 5295(applications)N
+975(are)X
+1107(trusted,)X
+1377(LIBTP)X
+1631(may)X
+1801(be)X
+1909(compiled)X
+2239(directly)X
+2516(into)X
+2672(the)X
+2802(application)X
+3190(providing)X
+3533(improved)X
+3872(performance.)X
+555 5385(Figures)N
+815(two)X
+955(and)X
+1091(three)X
+1272(show)X
+1461(the)X
+1579(two)X
+1719(alternate)X
+2016(application)X
+2392(architectures.)X
+755 5508(There)N
+964(are)X
+1084(potentially)X
+1447(two)X
+1588(modes)X
+1818(in)X
+1901(which)X
+2118(one)X
+2255(might)X
+2462(use)X
+2590(LIBTP)X
+2833(in)X
+2916(a)X
+2972(server)X
+3189(based)X
+3392(architecture.)X
+3832(In)X
+3919(the)X
+4037(\256rst,)X
+4201(the)X
+555 5598(server)N
+778(would)X
+1004(provide)X
+1275(the)X
+1399(capability)X
+1741(to)X
+1829(respond)X
+2109(to)X
+2197(requests)X
+2486(to)X
+2574(each)X
+2747(of)X
+2839(the)X
+2962(low)X
+3107(level)X
+3288(modules)X
+3584(\(lock,)X
+3794(log,)X
+3941(buffer,)X
+4183(and)X
+555 5688(transaction)N
+944(managers\).)X
+1356(Unfortunately,)X
+1863(the)X
+1998(performance)X
+2442(of)X
+2546(such)X
+2730(a)X
+2803(system)X
+3062(is)X
+3152(likely)X
+3371(to)X
+3470(be)X
+3583(blindingly)X
+3947(slow)X
+4134(since)X
+
+7 p
+%%Page: 7 7
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+1 Dt
+1864 1125 MXY
+15 -26 Dl
+-15 10 Dl
+-14 -10 Dl
+14 26 Dl
+0 -266 Dl
+1315 1125 MXY
+15 -26 Dl
+-15 10 Dl
+-14 -10 Dl
+14 26 Dl
+0 -266 Dl
+3 Dt
+1133 1125 MXY
+0 798 Dl
+931 0 Dl
+0 -798 Dl
+-931 0 Dl
+1 Dt
+1266 1257 MXY
+0 133 Dl
+665 0 Dl
+0 -133 Dl
+-665 0 Dl
+3 f
+8 s
+1513 1351(driver)N
+1502 1617(LIBTP)N
+1266 1390 MXY
+0 400 Dl
+665 0 Dl
+0 -400 Dl
+-665 0 Dl
+3 Dt
+1133 726 MXY
+0 133 Dl
+931 0 Dl
+0 -133 Dl
+-931 0 Dl
+1 f
+1029 1098(txn_abort)N
+964 1015(txn_commit)N
+1018 932(txn_begin)N
+1910 1015(db_ops)N
+3 f
+1308 820(Application)N
+1645(Program)X
+1398 1218(Server)N
+1594(Process)X
+1 f
+1390 986(socket)N
+1569(interface)X
+1 Dt
+1848 967 MXY
+-23 -14 Dl
+8 14 Dl
+-8 15 Dl
+23 -15 Dl
+-50 0 Dl
+1324 MX
+23 15 Dl
+-9 -15 Dl
+9 -14 Dl
+-23 14 Dl
+50 0 Dl
+3 Dt
+2862 859 MXY
+0 1064 Dl
+932 0 Dl
+0 -1064 Dl
+-932 0 Dl
+1 Dt
+3178 1390 MXY
+24 -12 Dl
+-17 0 Dl
+-8 -15 Dl
+1 27 Dl
+150 -265 Dl
+3494 1390 MXY
+0 -27 Dl
+-8 15 Dl
+-16 1 Dl
+24 11 Dl
+-166 -265 Dl
+3 f
+3232 1617(LIBTP)N
+2995 1390 MXY
+0 400 Dl
+666 0 Dl
+0 -400 Dl
+-666 0 Dl
+992 MY
+0 133 Dl
+666 0 Dl
+0 -133 Dl
+-666 0 Dl
+3168 1086(Application)N
+1 f
+2939 1201(txn_begin)N
+2885 1284(txn_commit)N
+2950 1368(txn_abort)N
+3465 1284(db_ops)N
+3 f
+3155 766(Single)N
+3339(Process)X
+3 Dt
+-1 Ds
+811 2100(Figure)N
+1023(2:)X
+1107(Server)X
+1318(Architecture.)X
+1 f
+1727(In)X
+1811(this)X
+1934(con\256guration,)X
+811 2190(the)N
+916(library)X
+1113(is)X
+1183(loaded)X
+1380(into)X
+1507(a)X
+1562(server)X
+1744(process)X
+1962(which)X
+2145(is)X
+2214(ac-)X
+811 2280(cessed)N
+993(via)X
+1087(a)X
+1131(socket)X
+1310(interface.)X
+3 f
+2563 2100(Figure)N
+2803(3:)X
+2914(Single)X
+3140(Process)X
+3403(Architecture.)X
+1 f
+3839(In)X
+3950(this)X
+2563 2190(con\256guration,)N
+2948(the)X
+3053(library)X
+3250(routines)X
+3483(are)X
+3587(loaded)X
+3784(as)X
+3864(part)X
+3990(of)X
+2563 2280(the)N
+2657(application)X
+2957(and)X
+3065(accessed)X
+3303(via)X
+3397(a)X
+3441(subroutine)X
+3727(interface.)X
+10 s
+10 f
+555 2403(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+1 f
+555 2679(modifying)N
+909(a)X
+966(piece)X
+1157(of)X
+1245(data)X
+1400(would)X
+1621(require)X
+1870(three)X
+2051(or)X
+2138(possibly)X
+2424(four)X
+2578(separate)X
+2862(communications:)X
+3433(one)X
+3569(to)X
+3651(lock)X
+3809(the)X
+3927(data,)X
+4101(one)X
+4237(to)X
+555 2769(obtain)N
+781(the)X
+905(data,)X
+1085(one)X
+1227(to)X
+1315(log)X
+1443(the)X
+1567(modi\256cation,)X
+2017(and)X
+2159(possibly)X
+2451(one)X
+2593(to)X
+2681(transmit)X
+2969(the)X
+3093(modi\256ed)X
+3403(data.)X
+3583(Figure)X
+3817(four)X
+3976(shows)X
+4201(the)X
+555 2859(relative)N
+826(performance)X
+1263(for)X
+1387(retrieving)X
+1728(a)X
+1793(single)X
+2013(record)X
+2248(using)X
+2450(the)X
+2577(record)X
+2812(level)X
+2997(call)X
+3142(versus)X
+3376(using)X
+3578(the)X
+3705(lower)X
+3917(level)X
+4102(buffer)X
+555 2949(management)N
+987(and)X
+1125(locking)X
+1387(calls.)X
+1616(The)X
+1763(2:1)X
+1887(ratio)X
+2056(observed)X
+2367(in)X
+2450(the)X
+2569(single)X
+2781(process)X
+3043(case)X
+3203(re\257ects)X
+3456(the)X
+3575(additional)X
+3916(overhead)X
+4232(of)X
+555 3039(parsing)N
+819(eight)X
+1006(commands)X
+1380(rather)X
+1595(than)X
+1760(one)X
+1903(while)X
+2108(the)X
+2233(3:1)X
+2362(ratio)X
+2536(observed)X
+2853(in)X
+2942(the)X
+3067(client/server)X
+3491(architecture)X
+3898(re\257ects)X
+4157(both)X
+555 3129(the)N
+679(parsing)X
+941(and)X
+1083(the)X
+1207(communication)X
+1731(overheard.)X
+2118(Although)X
+2445(there)X
+2631(may)X
+2794(be)X
+2895(applications)X
+3307(which)X
+3528(could)X
+3731(tolerate)X
+3997(such)X
+4169(per-)X
+555 3219(formance,)N
+904(it)X
+973(seems)X
+1194(far)X
+1309(more)X
+1499(feasible)X
+1774(to)X
+1861(support)X
+2126(a)X
+2187(higher)X
+2417(level)X
+2597(interface,)X
+2923(such)X
+3094(as)X
+3185(that)X
+3329(provided)X
+3638(by)X
+3742(a)X
+3802(query)X
+4009(language)X
+555 3309(\()N
+2 f
+582(e.g.)X
+1 f
+718(SQL)X
+889([SQL86]\).)X
+755 3432(Although)N
+1081(LIBTP)X
+1327(does)X
+1498(not)X
+1624(have)X
+1800(an)X
+1900(SQL)X
+2075(parser,)X
+2316(we)X
+2433(have)X
+2608(built)X
+2777(a)X
+2836(server)X
+3056(application)X
+3435(using)X
+3631(the)X
+3752(toolkit)X
+3983(command)X
+555 3522(language)N
+882(\(TCL\))X
+1124([OUST90].)X
+1544(The)X
+1706(server)X
+1940(supports)X
+2248(a)X
+2321(command)X
+2674(line)X
+2831(interface)X
+3150(similar)X
+3409(to)X
+3508(the)X
+3643(subroutine)X
+4017(interface)X
+555 3612(de\256ned)N
+811(in)X
+3 f
+893(db)X
+1 f
+981(\(3\).)X
+1135(Since)X
+1333(it)X
+1397(is)X
+1470(based)X
+1673(on)X
+1773(TCL,)X
+1964(it)X
+2028(provides)X
+2324(control)X
+2571(structures)X
+2903(as)X
+2990(well.)X
+3 f
+555 3798(4.)N
+655(Implementation)X
+1 f
+3 f
+555 3984(4.1.)N
+715(Locking)X
+1014(and)X
+1162(Deadlock)X
+1502(Detection)X
+1 f
+755 4107(LIBTP)N
+1007(uses)X
+1175(two-phase)X
+1535(locking)X
+1805(for)X
+1929(user)X
+2093(data.)X
+2297(Strictly)X
+2562(speaking,)X
+2897(the)X
+3024(two)X
+3173(phases)X
+3416(in)X
+3507(two-phase)X
+3866(locking)X
+4135(are)X
+4263(a)X
+3 f
+555 4197(grow)N
+1 f
+756(phase,)X
+986(during)X
+1221(which)X
+1443(locks)X
+1638(are)X
+1763(acquired,)X
+2086(and)X
+2228(a)X
+3 f
+2290(shrink)X
+1 f
+2537(phase,)X
+2766(during)X
+3001(which)X
+3223(locks)X
+3418(are)X
+3543(released.)X
+3873(No)X
+3997(lock)X
+4161(may)X
+555 4287(ever)N
+720(be)X
+822(acquired)X
+1124(during)X
+1358(the)X
+1481(shrink)X
+1706(phase.)X
+1954(The)X
+2104(grow)X
+2294(phase)X
+2502(lasts)X
+2669(until)X
+2840(the)X
+2963(\256rst)X
+3112(release,)X
+3381(which)X
+3602(marks)X
+3823(the)X
+3946(start)X
+4109(of)X
+4201(the)X
+555 4377(shrink)N
+780(phase.)X
+1028(In)X
+1120(practice,)X
+1420(the)X
+1543(grow)X
+1733(phase)X
+1941(lasts)X
+2108(for)X
+2227(the)X
+2350(duration)X
+2642(of)X
+2734(a)X
+2795(transaction)X
+3172(in)X
+3259(LIBTP)X
+3506(and)X
+3647(in)X
+3734(commercial)X
+4138(data-)X
+555 4467(base)N
+721(systems.)X
+1037(The)X
+1184(shrink)X
+1406(phase)X
+1611(takes)X
+1798(place)X
+1990(during)X
+2221(transaction)X
+2595(commit)X
+2861(or)X
+2950(abort.)X
+3177(This)X
+3341(means)X
+3568(that)X
+3710(locks)X
+3901(are)X
+4022(acquired)X
+555 4557(on)N
+655(demand)X
+929(during)X
+1158(the)X
+1276(lifetime)X
+1545(of)X
+1632(a)X
+1688(transaction,)X
+2080(and)X
+2216(held)X
+2374(until)X
+2540(commit)X
+2804(time,)X
+2986(at)X
+3064(which)X
+3280(point)X
+3464(all)X
+3564(locks)X
+3753(are)X
+3872(released.)X
+755 4680(If)N
+832(multiple)X
+1121(transactions)X
+1527(are)X
+1649(active)X
+1864(concurrently,)X
+2313(deadlocks)X
+2657(can)X
+2792(occur)X
+2994(and)X
+3133(must)X
+3311(be)X
+3410(detected)X
+3701(and)X
+3840(resolved.)X
+4174(The)X
+555 4770(lock)N
+715(table)X
+893(can)X
+1027(be)X
+1125(thought)X
+1391(of)X
+1480(as)X
+1569(a)X
+1627(representation)X
+2104(of)X
+2193(a)X
+2251(directed)X
+2532(graph.)X
+2777(The)X
+2924(nodes)X
+3133(in)X
+3216(the)X
+3335(graph)X
+3539(are)X
+3659(transactions.)X
+4103(Edges)X
+555 4860(represent)N
+878(the)X
+3 f
+1004(waits-for)X
+1 f
+1340(relation)X
+1613(between)X
+1909(transactions;)X
+2342(if)X
+2419(transaction)X
+2 f
+2799(A)X
+1 f
+2876(is)X
+2957(waiting)X
+3225(for)X
+3347(a)X
+3411(lock)X
+3577(held)X
+3743(by)X
+3851(transaction)X
+2 f
+4230(B)X
+1 f
+4279(,)X
+555 4950(then)N
+716(a)X
+775(directed)X
+1057(edge)X
+1232(exists)X
+1437(from)X
+2 f
+1616(A)X
+1 f
+1687(to)X
+2 f
+1771(B)X
+1 f
+1842(in)X
+1926(the)X
+2046(graph.)X
+2291(A)X
+2371(deadlock)X
+2683(exists)X
+2887(if)X
+2958(a)X
+3016(cycle)X
+3208(appears)X
+3476(in)X
+3560(the)X
+3680(graph.)X
+3925(By)X
+4040(conven-)X
+555 5040(tion,)N
+719(no)X
+819(transaction)X
+1191(ever)X
+1350(waits)X
+1539(for)X
+1653(a)X
+1709(lock)X
+1867(it)X
+1931(already)X
+2188(holds,)X
+2401(so)X
+2492(re\257exive)X
+2793(edges)X
+2996(are)X
+3115(impossible.)X
+755 5163(A)N
+836(distinguished)X
+1285(process)X
+1549(monitors)X
+1856(the)X
+1977(lock)X
+2138(table,)X
+2337(searching)X
+2668(for)X
+2785(cycles.)X
+3048(The)X
+3195(frequency)X
+3539(with)X
+3703(which)X
+3921(this)X
+4058(process)X
+555 5253(runs)N
+716(is)X
+792(user-settable;)X
+1243(for)X
+1360(the)X
+1481(multi-user)X
+1833(tests)X
+1998(discussed)X
+2328(in)X
+2413(section)X
+2663(5.1.2,)X
+2866(it)X
+2933(has)X
+3063(been)X
+3238(set)X
+3350(to)X
+3435(wake)X
+3628(up)X
+3731(every)X
+3932(second,)X
+4197(but)X
+555 5343(more)N
+742(sophisticated)X
+1182(schedules)X
+1516(are)X
+1636(certainly)X
+1938(possible.)X
+2261(When)X
+2474(a)X
+2531(cycle)X
+2722(is)X
+2796(detected,)X
+3105(one)X
+3242(of)X
+3330(the)X
+3449(transactions)X
+3853(in)X
+3936(the)X
+4055(cycle)X
+4246(is)X
+555 5433(nominated)N
+917(and)X
+1057(aborted.)X
+1362(When)X
+1578(the)X
+1700(transaction)X
+2076(aborts,)X
+2315(it)X
+2382(rolls)X
+2547(back)X
+2722(its)X
+2820(changes)X
+3102(and)X
+3241(releases)X
+3519(its)X
+3617(locks,)X
+3829(thereby)X
+4093(break-)X
+555 5523(ing)N
+677(the)X
+795(cycle)X
+985(in)X
+1067(the)X
+1185(graph.)X
+
+8 p
+%%Page: 8 8
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+4 Ds
+1 Dt
+1866 865 MXY
+1338 0 Dl
+1866 1031 MXY
+1338 0 Dl
+1866 1199 MXY
+1338 0 Dl
+1866 1366 MXY
+1338 0 Dl
+1866 1533 MXY
+1338 0 Dl
+1866 1701 MXY
+1338 0 Dl
+-1 Ds
+5 Dt
+1866 1868 MXY
+1338 0 Dl
+1 Dt
+1 Di
+2981 MX
+ 2981 1868 lineto
+ 2981 1575 lineto
+ 3092 1575 lineto
+ 3092 1868 lineto
+ 2981 1868 lineto
+closepath 21 2981 1575 3092 1868 Dp
+2646 MX
+ 2646 1868 lineto
+ 2646 949 lineto
+ 2758 949 lineto
+ 2758 1868 lineto
+ 2646 1868 lineto
+closepath 14 2646 949 2758 1868 Dp
+2312 MX
+ 2312 1868 lineto
+ 2312 1701 lineto
+ 2423 1701 lineto
+ 2423 1868 lineto
+ 2312 1868 lineto
+closepath 3 2312 1701 2423 1868 Dp
+1977 MX
+ 1977 1868 lineto
+ 1977 1512 lineto
+ 2089 1512 lineto
+ 2089 1868 lineto
+ 1977 1868 lineto
+closepath 19 1977 1512 2089 1868 Dp
+3 f
+2640 2047(Client/Server)N
+1957(Single)X
+2185(Process)X
+7 s
+2957 1957(record)N
+2570(component)X
+2289(record)X
+1890(components)X
+1733 1724(.1)N
+1733 1556(.2)N
+1733 1389(.3)N
+1733 1222(.4)N
+1733 1055(.5)N
+1733 889(.6)N
+1590 726(Elapsed)N
+1794(Time)X
+1613 782(\(in)N
+1693(seconds\))X
+3 Dt
+-1 Ds
+8 s
+555 2255(Figure)N
+756(4:)X
+829(Comparison)X
+1187(of)X
+1260(High)X
+1416(and)X
+1540(Low)X
+1681(Level)X
+1850(Interfaces.)X
+1 f
+2174(Elapsed)X
+2395(time)X
+2528(in)X
+2597(seconds)X
+2818(to)X
+2887(perform)X
+3111(a)X
+3158(single)X
+3330(record)X
+3511(retrieval)X
+3742(from)X
+3885(a)X
+3932(command)X
+4203(line)X
+555 2345(\(rather)N
+751(than)X
+888(a)X
+943(procedural)X
+1241(interface\))X
+1510(is)X
+1579(shown)X
+1772(on)X
+1862(the)X
+1966(y)X
+2024(axis.)X
+2185(The)X
+2310(``component'')X
+2704(numbers)X
+2950(re\257ect)X
+3135(the)X
+3239(timings)X
+3458(when)X
+3622(the)X
+3726(record)X
+3914(is)X
+3983(retrieved)X
+4235(by)X
+555 2435(separate)N
+785(calls)X
+924(to)X
+996(the)X
+1096(lock)X
+1228(manager)X
+1469(and)X
+1583(buffer)X
+1760(manager)X
+2001(while)X
+2165(the)X
+2264(``record'')X
+2531(timings)X
+2745(were)X
+2889(obtained)X
+3130(by)X
+3215(using)X
+3375(a)X
+3424(single)X
+3598(call)X
+3711(to)X
+3782(the)X
+3881(record)X
+4064(manager.)X
+555 2525(The)N
+674(2:1)X
+776(ratio)X
+913(observed)X
+1163(for)X
+1257(the)X
+1355(single)X
+1528(process)X
+1739(case)X
+1868(is)X
+1930(a)X
+1977(re\257ection)X
+2237(of)X
+2309(the)X
+2406(parsing)X
+2613(overhead)X
+2865(for)X
+2958(executing)X
+3225(eight)X
+3372(separate)X
+3599(commands)X
+3895(rather)X
+4062(than)X
+4191(one.)X
+555 2615(The)N
+673(additional)X
+948(factor)X
+1115(of)X
+1187(one)X
+1298(re\257ected)X
+1536(in)X
+1605(the)X
+1702(3:1)X
+1803(ratio)X
+1939(for)X
+2031(the)X
+2127(client/server)X
+2460(architecture)X
+2794(is)X
+2855(due)X
+2965(to)X
+3033(the)X
+3129(communication)X
+3545(overhead.)X
+3828(The)X
+3945(true)X
+4062(ratios)X
+4222(are)X
+555 2705(actually)N
+775(worse)X
+945(since)X
+1094(the)X
+1190(component)X
+1492(timings)X
+1703(do)X
+1785(not)X
+1884(re\257ect)X
+2060(the)X
+2155(search)X
+2334(times)X
+2490(within)X
+2671(each)X
+2804(page)X
+2941(or)X
+3011(the)X
+3106(time)X
+3237(required)X
+3466(to)X
+3533(transmit)X
+3760(the)X
+3855(page)X
+3992(between)X
+4221(the)X
+555 2795(two)N
+667(processes.)X
+10 s
+10 f
+555 2885(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+3 f
+555 3161(4.2.)N
+715(Group)X
+961(Commit)X
+1 f
+755 3284(Since)N
+959(the)X
+1083(log)X
+1211(must)X
+1392(be)X
+1494(\257ushed)X
+1751(to)X
+1839(disk)X
+1997(at)X
+2080(commit)X
+2349(time,)X
+2536(disk)X
+2694(bandwidth)X
+3057(fundamentally)X
+3545(limits)X
+3751(the)X
+3874(rate)X
+4020(at)X
+4103(which)X
+555 3374(transactions)N
+959(complete.)X
+1314(Since)X
+1513(most)X
+1688(transactions)X
+2091(write)X
+2276(only)X
+2438(a)X
+2494(few)X
+2635(small)X
+2828(records)X
+3085(to)X
+3167(the)X
+3285(log,)X
+3427(the)X
+3545(last)X
+3676(page)X
+3848(of)X
+3935(the)X
+4053(log)X
+4175(will)X
+555 3464(be)N
+658(\257ushed)X
+916(once)X
+1095(by)X
+1202(every)X
+1408(transaction)X
+1787(which)X
+2010(writes)X
+2233(to)X
+2322(it.)X
+2433(In)X
+2527(the)X
+2652(naive)X
+2853(implementation,)X
+3402(these)X
+3593(\257ushes)X
+3841(would)X
+4067(happen)X
+555 3554(serially.)N
+755 3677(LIBTP)N
+1008(uses)X
+3 f
+1177(group)X
+1412(commit)X
+1 f
+1702([DEWI84])X
+2077(in)X
+2170(order)X
+2371(to)X
+2464(amortize)X
+2775(the)X
+2903(cost)X
+3062(of)X
+3159(one)X
+3305(synchronous)X
+3740(disk)X
+3903(write)X
+4098(across)X
+555 3767(multiple)N
+851(transactions.)X
+1304(Group)X
+1539(commit)X
+1812(provides)X
+2117(a)X
+2182(way)X
+2345(for)X
+2468(a)X
+2533(group)X
+2749(of)X
+2845(transactions)X
+3257(to)X
+3348(commit)X
+3621(simultaneously.)X
+4174(The)X
+555 3857(\256rst)N
+709(several)X
+967(transactions)X
+1380(to)X
+1472(commit)X
+1745(write)X
+1939(their)X
+2115(changes)X
+2403(to)X
+2494(the)X
+2621(in-memory)X
+3006(log)X
+3137(page,)X
+3338(then)X
+3505(sleep)X
+3699(on)X
+3808(a)X
+3873(distinguished)X
+555 3947(semaphore.)N
+966(Later,)X
+1179(a)X
+1238(committing)X
+1629(transaction)X
+2004(\257ushes)X
+2249(the)X
+2370(page)X
+2545(to)X
+2630(disk,)X
+2805(and)X
+2943(wakes)X
+3166(up)X
+3268(all)X
+3370(its)X
+3467(sleeping)X
+3756(peers.)X
+3988(The)X
+4135(point)X
+555 4037(at)N
+635(which)X
+853(changes)X
+1134(are)X
+1255(actually)X
+1531(written)X
+1780(is)X
+1855(determined)X
+2238(by)X
+2340(three)X
+2523(thresholds.)X
+2914(The)X
+3061(\256rst)X
+3207(is)X
+3281(the)X
+2 f
+3400(group)X
+3612(threshold)X
+1 f
+3935(and)X
+4072(de\256nes)X
+555 4127(the)N
+674(minimum)X
+1005(number)X
+1271(of)X
+1359(transactions)X
+1763(which)X
+1979(must)X
+2154(be)X
+2250(active)X
+2462(in)X
+2544(the)X
+2662(system)X
+2904(before)X
+3130(transactions)X
+3533(are)X
+3652(forced)X
+3878(to)X
+3960(participate)X
+555 4217(in)N
+646(a)X
+711(group)X
+927(commit.)X
+1240(The)X
+1394(second)X
+1646(is)X
+1728(the)X
+2 f
+1855(wait)X
+2021(threshold)X
+1 f
+2352(which)X
+2577(is)X
+2658(expressed)X
+3003(as)X
+3098(the)X
+3224(percentage)X
+3601(of)X
+3696(active)X
+3916(transactions)X
+555 4307(waiting)N
+826(to)X
+919(be)X
+1026(committed.)X
+1439(The)X
+1595(last)X
+1737(is)X
+1821(the)X
+2 f
+1950(logdelay)X
+2257(threshold)X
+1 f
+2590(which)X
+2816(indicates)X
+3131(how)X
+3299(much)X
+3507(un\257ushed)X
+3848(log)X
+3980(should)X
+4223(be)X
+555 4397(allowed)N
+829(to)X
+911(accumulate)X
+1297(before)X
+1523(a)X
+1579(waiting)X
+1839(transaction's)X
+2289(commit)X
+2553(record)X
+2779(is)X
+2852(\257ushed.)X
+755 4520(Group)N
+981(commit)X
+1246(can)X
+1379(substantially)X
+1803(improve)X
+2090(performance)X
+2517(for)X
+2631(high-concurrency)X
+3218(environments.)X
+3714(If)X
+3788(only)X
+3950(a)X
+4006(few)X
+4147(tran-)X
+555 4610(sactions)N
+836(are)X
+957(running,)X
+1248(it)X
+1314(is)X
+1389(unlikely)X
+1673(to)X
+1757(improve)X
+2046(things)X
+2263(at)X
+2343(all.)X
+2485(The)X
+2632(crossover)X
+2962(point)X
+3148(is)X
+3223(the)X
+3343(point)X
+3529(at)X
+3609(which)X
+3827(the)X
+3947(transaction)X
+555 4700(commit)N
+823(rate)X
+968(is)X
+1045(limited)X
+1295(by)X
+1399(the)X
+1521(bandwidth)X
+1883(of)X
+1974(the)X
+2096(device)X
+2330(on)X
+2434(which)X
+2654(the)X
+2776(log)X
+2902(resides.)X
+3189(If)X
+3267(processes)X
+3599(are)X
+3722(trying)X
+3937(to)X
+4023(\257ush)X
+4201(the)X
+555 4790(log)N
+677(faster)X
+876(than)X
+1034(the)X
+1152(log)X
+1274(disk)X
+1427(can)X
+1559(accept)X
+1785(data,)X
+1959(then)X
+2117(group)X
+2324(commit)X
+2588(will)X
+2732(increase)X
+3016(the)X
+3134(commit)X
+3398(rate.)X
+3 f
+555 4976(4.3.)N
+715(Kernel)X
+971(Intervention)X
+1418(for)X
+1541(Synchronization)X
+1 f
+755 5099(Since)N
+954(LIBTP)X
+1197(uses)X
+1356(data)X
+1511(in)X
+1594(shared)X
+1825(memory)X
+2113(\()X
+2 f
+2140(e.g.)X
+1 f
+2277(the)X
+2395(lock)X
+2553(table)X
+2729(and)X
+2865(buffer)X
+3082(pool\))X
+3271(it)X
+3335(must)X
+3510(be)X
+3606(possible)X
+3888(for)X
+4002(a)X
+4058(process)X
+555 5189(to)N
+640(acquire)X
+900(exclusive)X
+1226(access)X
+1454(to)X
+1538(shared)X
+1770(data)X
+1926(in)X
+2010(order)X
+2202(to)X
+2286(prevent)X
+2549(corruption.)X
+2945(In)X
+3034(addition,)X
+3338(the)X
+3458(process)X
+3721(manager)X
+4020(must)X
+4197(put)X
+555 5279(processes)N
+886(to)X
+971(sleep)X
+1159(when)X
+1356(the)X
+1477(lock)X
+1638(or)X
+1728(buffer)X
+1948(they)X
+2109(request)X
+2364(is)X
+2440(in)X
+2525(use)X
+2655(by)X
+2758(some)X
+2950(other)X
+3138(process.)X
+3441(In)X
+3530(the)X
+3650(LIBTP)X
+3894(implementa-)X
+555 5385(tion)N
+705(under)X
+914(Ultrix)X
+1131(4.0)X
+7 s
+5353(2)Y
+10 s
+5385(,)Y
+1305(we)X
+1424(use)X
+1556(System)X
+1816(V)X
+1899(semaphores)X
+2303(to)X
+2390(provide)X
+2660(this)X
+2800(synchronization.)X
+3377(Semaphores)X
+3794(implemented)X
+4237(in)X
+555 5475(this)N
+701(fashion)X
+968(turn)X
+1128(out)X
+1261(to)X
+1354(be)X
+1461(an)X
+1568(expensive)X
+1920(choice)X
+2161(for)X
+2285(synchronization,)X
+2847(because)X
+3132(each)X
+3310(access)X
+3546(traps)X
+3732(to)X
+3824(the)X
+3952(kernel)X
+4183(and)X
+8 s
+10 f
+555 5547(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5625(2)N
+8 s
+763 5650(Ultrix)N
+932(and)X
+1040(DEC)X
+1184(are)X
+1277(trademarks)X
+1576(of)X
+1645(Digital)X
+1839(Equipment)X
+2136(Corporation.)X
+
+9 p
+%%Page: 9 9
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+555 630(executes)N
+852(atomically)X
+1210(there.)X
+755 753(On)N
+878(architectures)X
+1314(that)X
+1459(support)X
+1724(atomic)X
+1967(test-and-set,)X
+2382(a)X
+2443(much)X
+2646(better)X
+2854(choice)X
+3089(would)X
+3314(be)X
+3415(to)X
+3502(attempt)X
+3767(to)X
+3854(obtain)X
+4079(a)X
+4139(spin-)X
+555 843(lock)N
+714(with)X
+877(a)X
+934(test-and-set,)X
+1345(and)X
+1482(issue)X
+1663(a)X
+1720(system)X
+1963(call)X
+2100(only)X
+2263(if)X
+2333(the)X
+2452(spinlock)X
+2744(is)X
+2818(unavailable.)X
+3249(Since)X
+3447(virtually)X
+3738(all)X
+3838(semaphores)X
+4237(in)X
+555 933(LIBTP)N
+801(are)X
+924(uncontested)X
+1330(and)X
+1469(are)X
+1591(held)X
+1752(for)X
+1869(very)X
+2035(short)X
+2218(periods)X
+2477(of)X
+2567(time,)X
+2752(this)X
+2890(would)X
+3113(improve)X
+3403(performance.)X
+3873(For)X
+4007(example,)X
+555 1023(processes)N
+885(must)X
+1062(acquire)X
+1321(exclusive)X
+1646(access)X
+1874(to)X
+1958(buffer)X
+2177(pool)X
+2341(metadata)X
+2653(in)X
+2737(order)X
+2929(to)X
+3013(\256nd)X
+3159(and)X
+3297(pin)X
+3421(a)X
+3479(buffer)X
+3698(in)X
+3781(shared)X
+4012(memory.)X
+555 1113(This)N
+721(semaphore)X
+1093(is)X
+1170(requested)X
+1502(most)X
+1681(frequently)X
+2034(in)X
+2119(LIBTP.)X
+2404(However,)X
+2742(once)X
+2917(it)X
+2984(is)X
+3060(acquired,)X
+3380(only)X
+3545(a)X
+3604(few)X
+3748(instructions)X
+4144(must)X
+555 1203(be)N
+656(executed)X
+966(before)X
+1196(it)X
+1264(is)X
+1341(released.)X
+1669(On)X
+1791(one)X
+1931(architecture)X
+2335(for)X
+2453(which)X
+2673(we)X
+2791(were)X
+2972(able)X
+3130(to)X
+3216(gather)X
+3441(detailed)X
+3719(pro\256ling)X
+4018(informa-)X
+555 1293(tion,)N
+729(the)X
+857(cost)X
+1015(of)X
+1111(the)X
+1238(semaphore)X
+1615(calls)X
+1791(accounted)X
+2146(for)X
+2269(25%)X
+2445(of)X
+2541(the)X
+2668(total)X
+2839(time)X
+3010(spent)X
+3208(updating)X
+3517(the)X
+3644(metadata.)X
+4003(This)X
+4174(was)X
+555 1383(fairly)N
+749(consistent)X
+1089(across)X
+1310(most)X
+1485(of)X
+1572(the)X
+1690(critical)X
+1933(sections.)X
+755 1506(In)N
+848(an)X
+950(attempt)X
+1216(to)X
+1304(quantify)X
+1597(the)X
+1720(overhead)X
+2040(of)X
+2132(kernel)X
+2358(synchronization,)X
+2915(we)X
+3034(ran)X
+3162(tests)X
+3329(on)X
+3434(a)X
+3495(version)X
+3756(of)X
+3848(4.3BSD-Reno)X
+555 1596(which)N
+786(had)X
+937(been)X
+1123(modi\256ed)X
+1441(to)X
+1537(support)X
+1811(binary)X
+2050(semaphore)X
+2432(facilities)X
+2742(similar)X
+2998(to)X
+3094(those)X
+3297(described)X
+3639(in)X
+3735([POSIX91].)X
+4174(The)X
+555 1686(hardware)N
+880(platform)X
+1181(consisted)X
+1504(of)X
+1595(an)X
+1695(HP300)X
+1941(\(33MHz)X
+2237(MC68030\))X
+2612(workstation)X
+3014(with)X
+3180(16MBytes)X
+3537(of)X
+3628(main)X
+3812(memory,)X
+4123(and)X
+4263(a)X
+555 1776(600MByte)N
+920(HP7959)X
+1205(SCSI)X
+1396(disk)X
+1552(\(17)X
+1682(ms)X
+1798(average)X
+2072(seek)X
+2237(time\).)X
+2468(We)X
+2602(ran)X
+2727(three)X
+2910(sets)X
+3052(of)X
+3141(comparisons)X
+3568(which)X
+3786(are)X
+3907(summarized)X
+555 1866(in)N
+645(\256gure)X
+860(\256ve.)X
+1028(In)X
+1123(each)X
+1299(comparison)X
+1701(we)X
+1823(ran)X
+1954(two)X
+2102(tests,)X
+2292(one)X
+2436(using)X
+2637(hardware)X
+2965(spinlocks)X
+3295(and)X
+3438(the)X
+3563(other)X
+3755(using)X
+3955(kernel)X
+4183(call)X
+555 1956(synchronization.)N
+1135(Since)X
+1341(the)X
+1467(test)X
+1606(was)X
+1758(run)X
+1892(single-user,)X
+2291(none)X
+2474(of)X
+2568(the)X
+2693(the)X
+2818(locks)X
+3014(were)X
+3198(contested.)X
+3568(In)X
+3662(the)X
+3787(\256rst)X
+3938(two)X
+4085(sets)X
+4232(of)X
+555 2046(tests,)N
+743(we)X
+863(ran)X
+992(the)X
+1116(full)X
+1253(transaction)X
+1631(processing)X
+2000(benchmark)X
+2383(described)X
+2717(in)X
+2805(section)X
+3058(5.1.)X
+3223(In)X
+3315(one)X
+3456(case)X
+3620(we)X
+3739(ran)X
+3867(with)X
+4034(both)X
+4201(the)X
+555 2136(database)N
+854(and)X
+992(log)X
+1116(on)X
+1218(the)X
+1338(same)X
+1525(disk)X
+1680(\(1)X
+1769(Disk\))X
+1969(and)X
+2107(in)X
+2191(the)X
+2311(second,)X
+2576(we)X
+2692(ran)X
+2817(with)X
+2981(the)X
+3101(database)X
+3400(and)X
+3538(log)X
+3661(on)X
+3762(separate)X
+4047(disks)X
+4232(\(2)X
+555 2226(Disk\).)N
+800(In)X
+894(the)X
+1019(last)X
+1157(test,)X
+1315(we)X
+1436(wanted)X
+1695(to)X
+1784(create)X
+2004(a)X
+2067(CPU)X
+2249(bound)X
+2476(environment,)X
+2928(so)X
+3026(we)X
+3146(used)X
+3319(a)X
+3381(database)X
+3684(small)X
+3883(enough)X
+4145(to)X
+4233(\256t)X
+555 2316(completely)N
+941(in)X
+1033(the)X
+1161(cache)X
+1375(and)X
+1521(issued)X
+1751(read-only)X
+2089(transactions.)X
+2541(The)X
+2695(results)X
+2933(in)X
+3024(\256gure)X
+3240(\256ve)X
+3389(express)X
+3659(the)X
+3786(kernel)X
+4016(call)X
+4161(syn-)X
+555 2406(chronization)N
+980(performance)X
+1411(as)X
+1502(a)X
+1562(percentage)X
+1935(of)X
+2026(the)X
+2148(spinlock)X
+2443(performance.)X
+2914(For)X
+3049(example,)X
+3365(in)X
+3451(the)X
+3573(1)X
+3637(disk)X
+3794(case,)X
+3977(the)X
+4098(kernel)X
+555 2496(call)N
+697(implementation)X
+1225(achieved)X
+1537(4.4)X
+1662(TPS)X
+1824(\(transactions)X
+2259(per)X
+2387(second\))X
+2662(while)X
+2865(the)X
+2988(semaphore)X
+3361(implementation)X
+3888(achieved)X
+4199(4.6)X
+555 2586(TPS,)N
+735(and)X
+874(the)X
+995(relative)X
+1259(performance)X
+1689(of)X
+1779(the)X
+1900(kernel)X
+2123(synchronization)X
+2657(is)X
+2732(96%)X
+2901(that)X
+3043(of)X
+3132(the)X
+3252(spinlock)X
+3545(\(100)X
+3714(*)X
+3776(4.4)X
+3898(/)X
+3942(4.6\).)X
+4111(There)X
+555 2676(are)N
+674(two)X
+814(striking)X
+1078(observations)X
+1503(from)X
+1679(these)X
+1864(results:)X
+10 f
+635 2799(g)N
+1 f
+755(even)X
+927(when)X
+1121(the)X
+1239(system)X
+1481(is)X
+1554(disk)X
+1707(bound,)X
+1947(the)X
+2065(CPU)X
+2240(cost)X
+2389(of)X
+2476(synchronization)X
+3008(is)X
+3081(noticeable,)X
+3451(and)X
+10 f
+635 2922(g)N
+1 f
+755(when)X
+949(we)X
+1063(are)X
+1182(CPU)X
+1357(bound,)X
+1597(the)X
+1715(difference)X
+2062(is)X
+2135(dramatic)X
+2436(\(67%\).)X
+3 f
+555 3108(4.4.)N
+715(Transaction)X
+1148(Protected)X
+1499(Access)X
+1747(Methods)X
+1 f
+755 3231(The)N
+903(B-tree)X
+1127(and)X
+1266(\256xed)X
+1449(length)X
+1671(recno)X
+1872(\(record)X
+2127(number\))X
+2421(access)X
+2649(methods)X
+2942(have)X
+3116(been)X
+3290(modi\256ed)X
+3596(to)X
+3680(provide)X
+3947(transaction)X
+555 3321(protection.)N
+941(Whereas)X
+1244(the)X
+1363(previously)X
+1722(published)X
+2054(interface)X
+2357(to)X
+2440(the)X
+2559(access)X
+2786(routines)X
+3065(had)X
+3202(separate)X
+3487(open)X
+3664(calls)X
+3832(for)X
+3946(each)X
+4114(of)X
+4201(the)X
+10 f
+555 3507(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+1 Dt
+2978 5036 MXY
+ 2978 5036 lineto
+ 2978 4662 lineto
+ 3093 4662 lineto
+ 3093 5036 lineto
+ 2978 5036 lineto
+closepath 21 2978 4662 3093 5036 Dp
+2518 MX
+ 2518 5036 lineto
+ 2518 3960 lineto
+ 2633 3960 lineto
+ 2633 5036 lineto
+ 2518 5036 lineto
+closepath 3 2518 3960 2633 5036 Dp
+2059 MX
+ 2059 5036 lineto
+ 2059 3946 lineto
+ 2174 3946 lineto
+ 2174 5036 lineto
+ 2059 5036 lineto
+closepath 1 2059 3946 2174 5036 Dp
+3 f
+7 s
+2912 5141(Read-only)N
+1426 3767(of)N
+1487(Spinlock)X
+1710(Throughput)X
+1480 3710(Throughput)N
+1786(as)X
+1850(a)X
+1892(%)X
+11 s
+1670 4843(20)N
+1670 4614(40)N
+1670 4384(60)N
+1670 4155(80)N
+1648 3925(100)N
+7 s
+2041 5141(1)N
+2083(Disk)X
+2490(2)X
+2532(Disks)X
+5 Dt
+1829 5036 MXY
+1494 0 Dl
+4 Ds
+1 Dt
+1829 4806 MXY
+1494 0 Dl
+1829 4577 MXY
+1494 0 Dl
+1829 4347 MXY
+1494 0 Dl
+1829 4118 MXY
+1494 0 Dl
+1829 3888 MXY
+1494 0 Dl
+3 Dt
+-1 Ds
+8 s
+555 5360(Figure)N
+753(5:)X
+823(Kernel)X
+1028(Overhead)X
+1315(for)X
+1413(System)X
+1625(Call)X
+1756(Synchronization.)X
+1 f
+2254(The)X
+2370(performance)X
+2708(of)X
+2778(the)X
+2873(kernel)X
+3049(call)X
+3158(synchronization)X
+3583(is)X
+3643(expressed)X
+3911(as)X
+3980(a)X
+4024(percentage)X
+555 5450(of)N
+625(the)X
+720(spinlock)X
+954(synchronization)X
+1379(performance.)X
+1749(In)X
+1819(disk)X
+1943(bound)X
+2120(cases)X
+2271(\(1)X
+2341(Disk)X
+2479(and)X
+2588(2)X
+2637(Disks\),)X
+2837(we)X
+2928(see)X
+3026(that)X
+3139(4-6%)X
+3294(of)X
+3364(the)X
+3459(performance)X
+3797(is)X
+3857(lost)X
+3966(due)X
+4074(to)X
+4140(kernel)X
+555 5540(calls)N
+688(while)X
+846(in)X
+912(the)X
+1006(CPU)X
+1147(bound)X
+1323(case,)X
+1464(we)X
+1554(have)X
+1690(lost)X
+1799(67%)X
+1932(of)X
+2001(the)X
+2095(performance)X
+2432(due)X
+2540(to)X
+2606(kernel)X
+2781(calls.)X
+
+10 p
+%%Page: 10 10
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+555 630(access)N
+781(methods,)X
+1092(we)X
+1206(now)X
+1364(have)X
+1536(an)X
+1632(integrated)X
+1973(open)X
+2149(call)X
+2285(with)X
+2447(the)X
+2565(following)X
+2896(calling)X
+3134(conventions:)X
+7 f
+715 753(DB)N
+859(*dbopen)X
+1243(\(const)X
+1579(char)X
+1819(*file,)X
+2155(int)X
+2347(flags,)X
+2683(int)X
+2875(mode,)X
+3163(DBTYPE)X
+3499(type,)X
+1291 843(int)N
+1483(dbflags,)X
+1915(const)X
+2203(void)X
+2443(*openinfo\))X
+1 f
+555 966(where)N
+2 f
+774(\256le)X
+1 f
+894(is)X
+969(the)X
+1089(name)X
+1285(of)X
+1374(the)X
+1494(\256le)X
+1618(being)X
+1818(opened,)X
+2 f
+2092(\257ags)X
+1 f
+2265(and)X
+2 f
+2402(mode)X
+1 f
+2597(are)X
+2717(the)X
+2836(standard)X
+3129(arguments)X
+3484(to)X
+3 f
+3567(open)X
+1 f
+3731(\(2\),)X
+2 f
+3866(type)X
+1 f
+4021(is)X
+4095(one)X
+4232(of)X
+555 1056(the)N
+680(access)X
+913(method)X
+1180(types,)X
+2 f
+1396(db\257ags)X
+1 f
+1654(indicates)X
+1966(the)X
+2091(mode)X
+2296(of)X
+2390(the)X
+2515(buffer)X
+2739(pool)X
+2907(and)X
+3049(transaction)X
+3427(protection,)X
+3798(and)X
+2 f
+3940(openinfo)X
+1 f
+4246(is)X
+555 1146(the)N
+681(access)X
+915(method)X
+1183(speci\256c)X
+1456(information.)X
+1902(Currently,)X
+2257(the)X
+2383(possible)X
+2673(values)X
+2906(for)X
+2 f
+3028(db\257ags)X
+1 f
+3287(are)X
+3414(DB_SHARED)X
+3912(and)X
+4055(DB_TP)X
+555 1236(indicating)N
+895(that)X
+1035(buffers)X
+1283(should)X
+1516(be)X
+1612(kept)X
+1770(in)X
+1852(a)X
+1908(shared)X
+2138(buffer)X
+2355(pool)X
+2517(and)X
+2653(that)X
+2793(the)X
+2911(\256le)X
+3033(should)X
+3266(be)X
+3362(transaction)X
+3734(protected.)X
+755 1359(The)N
+900(modi\256cations)X
+1355(required)X
+1643(to)X
+1725(add)X
+1861(transaction)X
+2233(protection)X
+2578(to)X
+2660(an)X
+2756(access)X
+2982(method)X
+3242(are)X
+3361(quite)X
+3541(simple)X
+3774(and)X
+3910(localized.)X
+715 1482(1.)N
+795(Replace)X
+1074(\256le)X
+2 f
+1196(open)X
+1 f
+1372(with)X
+2 f
+1534(buf_open)X
+1 f
+1832(.)X
+715 1572(2.)N
+795(Replace)X
+1074(\256le)X
+2 f
+1196(read)X
+1 f
+1363(and)X
+2 f
+1499(write)X
+1 f
+1683(calls)X
+1850(with)X
+2012(buffer)X
+2229(manager)X
+2526(calls)X
+2693(\()X
+2 f
+2720(buf_get)X
+1 f
+(,)S
+2 f
+3000(buf_unpin)X
+1 f
+3324(\).)X
+715 1662(3.)N
+795(Precede)X
+1070(buffer)X
+1287(manager)X
+1584(calls)X
+1751(with)X
+1913(an)X
+2009(appropriate)X
+2395(\(read)X
+2581(or)X
+2668(write\))X
+2880(lock)X
+3038(call.)X
+715 1752(4.)N
+795(Before)X
+1034(updates,)X
+1319(issue)X
+1499(a)X
+1555(logging)X
+1819(operation.)X
+715 1842(5.)N
+795(After)X
+985(data)X
+1139(have)X
+1311(been)X
+1483(accessed,)X
+1805(release)X
+2049(the)X
+2167(buffer)X
+2384(manager)X
+2681(pin.)X
+715 1932(6.)N
+795(Provide)X
+1064(undo/redo)X
+1409(code)X
+1581(for)X
+1695(each)X
+1863(type)X
+2021(of)X
+2108(log)X
+2230(record)X
+2456(de\256ned.)X
+555 2071(The)N
+702(following)X
+1035(code)X
+1209(fragments)X
+1552(show)X
+1743(how)X
+1903(to)X
+1987(transaction)X
+2361(protect)X
+2606(several)X
+2856(updates)X
+3123(to)X
+3206(a)X
+3263(B-tree.)X
+7 s
+3484 2039(3)N
+10 s
+3533 2071(In)N
+3621(the)X
+3740(unprotected)X
+4140(case,)X
+555 2161(an)N
+652(open)X
+829(call)X
+966(is)X
+1040(followed)X
+1346(by)X
+1447(a)X
+1504(read)X
+1664(call)X
+1801(to)X
+1884(obtain)X
+2105(the)X
+2224(meta-data)X
+2562(for)X
+2677(the)X
+2796(B-tree.)X
+3058(Instead,)X
+3331(we)X
+3446(issue)X
+3627(an)X
+3724(open)X
+3901(to)X
+3984(the)X
+4102(buffer)X
+555 2251(manager)N
+852(to)X
+934(obtain)X
+1154(a)X
+1210(\256le)X
+1332(id)X
+1414(and)X
+1550(a)X
+1606(buffer)X
+1823(request)X
+2075(to)X
+2157(obtain)X
+2377(the)X
+2495(meta-data)X
+2832(as)X
+2919(shown)X
+3148(below.)X
+7 f
+715 2374(char)N
+955(*path;)X
+715 2464(int)N
+907(fid,)X
+1147(flags,)X
+1483(len,)X
+1723(mode;)X
+715 2644(/*)N
+859(Obtain)X
+1195(a)X
+1291(file)X
+1531(id)X
+1675(with)X
+1915(which)X
+2203(to)X
+2347(access)X
+2683(the)X
+2875(buffer)X
+3211(pool)X
+3451(*/)X
+715 2734(fid)N
+907(=)X
+1003(buf_open\(path,)X
+1723(flags,)X
+2059(mode\);)X
+715 2914(/*)N
+859(Read)X
+1099(the)X
+1291(meta)X
+1531(data)X
+1771(\(page)X
+2059(0\))X
+2203(for)X
+2395(the)X
+2587(B-tree)X
+2923(*/)X
+715 3004(if)N
+859(\(tp_lock\(fid,)X
+1531(0,)X
+1675(READ_LOCK\)\))X
+1003 3094(return)N
+1339(error;)X
+715 3184(meta_data_ptr)N
+1387(=)X
+1483(buf_get\(fid,)X
+2107(0,)X
+2251(BF_PIN,)X
+2635(&len\);)X
+1 f
+555 3307(The)N
+714(BF_PIN)X
+1014(argument)X
+1350(to)X
+2 f
+1445(buf_get)X
+1 f
+1718(indicates)X
+2036(that)X
+2189(we)X
+2316(wish)X
+2500(to)X
+2595(leave)X
+2798(this)X
+2946(page)X
+3131(pinned)X
+3382(in)X
+3477(memory)X
+3777(so)X
+3881(that)X
+4034(it)X
+4111(is)X
+4197(not)X
+555 3397(swapped)N
+862(out)X
+990(while)X
+1194(we)X
+1314(are)X
+1439(accessing)X
+1772(it.)X
+1881(The)X
+2031(last)X
+2167(argument)X
+2495(to)X
+2 f
+2582(buf_get)X
+1 f
+2847(returns)X
+3095(the)X
+3218(number)X
+3488(of)X
+3580(bytes)X
+3774(on)X
+3879(the)X
+4002(page)X
+4179(that)X
+555 3487(were)N
+732(valid)X
+912(so)X
+1003(that)X
+1143(the)X
+1261(access)X
+1487(method)X
+1747(may)X
+1905(initialize)X
+2205(the)X
+2323(page)X
+2495(if)X
+2564(necessary.)X
+755 3610(Next,)N
+955(consider)X
+1251(inserting)X
+1555(a)X
+1615(record)X
+1845(on)X
+1949(a)X
+2009(particular)X
+2341(page)X
+2517(of)X
+2608(a)X
+2668(B-tree.)X
+2932(In)X
+3022(the)X
+3143(unprotected)X
+3545(case,)X
+3727(we)X
+3844(read)X
+4006(the)X
+4127(page,)X
+555 3700(call)N
+2 f
+693(_bt_insertat)X
+1 f
+1079(,)X
+1121(and)X
+1258(write)X
+1444(the)X
+1563(page.)X
+1776(Instead,)X
+2049(we)X
+2164(lock)X
+2323(the)X
+2442(page,)X
+2635(request)X
+2888(the)X
+3007(buffer,)X
+3245(log)X
+3368(the)X
+3487(change,)X
+3756(modify)X
+4008(the)X
+4127(page,)X
+555 3790(and)N
+691(release)X
+935(the)X
+1053(buffer.)X
+7 f
+715 3913(int)N
+907(fid,)X
+1147(len,)X
+1387(pageno;)X
+1867(/*)X
+2011(Identifies)X
+2539(the)X
+2731(buffer)X
+3067(*/)X
+715 4003(int)N
+907(index;)X
+1867(/*)X
+2011(Location)X
+2443(at)X
+2587(which)X
+2875(to)X
+3019(insert)X
+3355(the)X
+3547(new)X
+3739(pair)X
+3979(*/)X
+715 4093(DBT)N
+907(*keyp,)X
+1243(*datap;)X
+1867(/*)X
+2011(Key/Data)X
+2443(pair)X
+2683(to)X
+2827(be)X
+2971(inserted)X
+3403(*/)X
+715 4183(DATUM)N
+1003(*d;)X
+1867(/*)X
+2011(Key/data)X
+2443(structure)X
+2923(to)X
+3067(insert)X
+3403(*/)X
+715 4363(/*)N
+859(Lock)X
+1099(and)X
+1291(request)X
+1675(the)X
+1867(buffer)X
+2203(*/)X
+715 4453(if)N
+859(\(tp_lock\(fid,)X
+1531(pageno,)X
+1915(WRITE_LOCK\)\))X
+1003 4543(return)N
+1339(error;)X
+715 4633(buffer_ptr)N
+1243(=)X
+1339(buf_get\(fid,)X
+1963(pageno,)X
+2347(BF_PIN,)X
+2731(&len\);)X
+715 4813(/*)N
+859(Log)X
+1051(and)X
+1243(perform)X
+1627(the)X
+1819(update)X
+2155(*/)X
+715 4903(log_insdel\(BTREE_INSERT,)N
+1915(fid,)X
+2155(pageno,)X
+2539(keyp,)X
+2827(datap\);)X
+715 4993(_bt_insertat\(buffer_ptr,)N
+1915(d,)X
+2059(index\);)X
+715 5083(buf_unpin\(buffer_ptr\);)N
+1 f
+555 5206(Succinctly,)N
+942(the)X
+1068(algorithm)X
+1407(for)X
+1529(turning)X
+1788(unprotected)X
+2195(code)X
+2375(into)X
+2527(protected)X
+2854(code)X
+3034(is)X
+3115(to)X
+3205(replace)X
+3466(read)X
+3633(operations)X
+3995(with)X
+2 f
+4165(lock)X
+1 f
+555 5296(and)N
+2 f
+691(buf_get)X
+1 f
+951(operations)X
+1305(and)X
+1441(write)X
+1626(operations)X
+1980(with)X
+2 f
+2142(log)X
+1 f
+2264(and)X
+2 f
+2400(buf_unpin)X
+1 f
+2744(operations.)X
+8 s
+10 f
+555 5458(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5536(3)N
+8 s
+766 5561(The)N
+884(following)X
+1152(code)X
+1291(fragments)X
+1565(are)X
+1661(examples,)X
+1937(but)X
+2038(do)X
+2120(not)X
+2220(de\256ne)X
+2394(the)X
+2490(\256nal)X
+2622(interface.)X
+2894(The)X
+3011(\256nal)X
+3143(interface)X
+3383(will)X
+3501(be)X
+3579(determined)X
+3884(after)X
+4018(LIBTP)X
+4214(has)X
+555 5633(been)N
+691(fully)X
+828(integrated)X
+1099(with)X
+1229(the)X
+1323(most)X
+1464(recent)X
+3 f
+1635(db)X
+1 f
+1707(\(3\))X
+1797(release)X
+1989(from)X
+2129(the)X
+2223(Computer)X
+2495(Systems)X
+2725(Research)X
+2974(Group)X
+3153(at)X
+3215(University)X
+3501(of)X
+3570(California,)X
+3861(Berkeley.)X
+
+11 p
+%%Page: 11 11
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+555 630(5.)N
+655(Performance)X
+1 f
+755 753(In)N
+845(this)X
+983(section,)X
+1253(we)X
+1370(present)X
+1625(the)X
+1746(results)X
+1978(of)X
+2067(two)X
+2209(very)X
+2374(different)X
+2673(benchmarks.)X
+3103(The)X
+3250(\256rst)X
+3396(is)X
+3471(an)X
+3569(online)X
+3791(transaction)X
+4165(pro-)X
+555 843(cessing)N
+824(benchmark,)X
+1234(similar)X
+1489(to)X
+1584(the)X
+1715(standard)X
+2020(TPCB,)X
+2272(but)X
+2407(has)X
+2547(been)X
+2732(adapted)X
+3015(to)X
+3110(run)X
+3250(in)X
+3345(a)X
+3414(desktop)X
+3696(environment.)X
+4174(The)X
+555 933(second)N
+798(emulates)X
+1103(a)X
+1159(computer-aided)X
+1683(design)X
+1912(environment)X
+2337(and)X
+2473(provides)X
+2769(more)X
+2954(complex)X
+3250(query)X
+3453(processing.)X
+3 f
+555 1119(5.1.)N
+715(Transaction)X
+1148(Processing)X
+1533(Benchmark)X
+1 f
+755 1242(For)N
+887(this)X
+1023(section,)X
+1291(all)X
+1392(performance)X
+1820(numbers)X
+2117(shown)X
+2346(except)X
+2576(for)X
+2690(the)X
+2808(commercial)X
+3207(database)X
+3504(system)X
+3746(were)X
+3923(obtained)X
+4219(on)X
+555 1332(a)N
+614(DECstation)X
+1009(5000/200)X
+1333(with)X
+1497(32MBytes)X
+1852(of)X
+1941(memory)X
+2230(running)X
+2501(Ultrix)X
+2714(V4.0,)X
+2914(accessing)X
+3244(a)X
+3302(DEC)X
+3484(RZ57)X
+3688(1GByte)X
+3959(disk)X
+4114(drive.)X
+555 1422(The)N
+720(commercial)X
+1139(relational)X
+1482(database)X
+1799(system)X
+2061(tests)X
+2242(were)X
+2438(run)X
+2584(on)X
+2703(a)X
+2778(comparable)X
+3192(machine,)X
+3523(a)X
+3598(Sparcstation)X
+4033(1+)X
+4157(with)X
+555 1512(32MBytes)N
+915(memory)X
+1209(and)X
+1352(a)X
+1415(1GByte)X
+1691(external)X
+1976(disk)X
+2135(drive.)X
+2366(The)X
+2517(database,)X
+2840(binaries)X
+3120(and)X
+3262(log)X
+3390(resided)X
+3648(on)X
+3754(the)X
+3878(same)X
+4069(device.)X
+555 1602(Reported)N
+869(times)X
+1062(are)X
+1181(the)X
+1299(means)X
+1524(of)X
+1611(\256ve)X
+1751(tests)X
+1913(and)X
+2049(have)X
+2221(standard)X
+2513(deviations)X
+2862(within)X
+3086(two)X
+3226(percent)X
+3483(of)X
+3570(the)X
+3688(mean.)X
+755 1725(The)N
+905(test)X
+1041(database)X
+1343(was)X
+1493(con\256gured)X
+1861(according)X
+2203(to)X
+2290(the)X
+2413(TPCB)X
+2637(scaling)X
+2889(rules)X
+3070(for)X
+3189(a)X
+3250(10)X
+3355(transaction)X
+3732(per)X
+3860(second)X
+4108(\(TPS\))X
+555 1815(system)N
+817(with)X
+999(1,000,000)X
+1359(account)X
+1649(records,)X
+1946(100)X
+2106(teller)X
+2311(records,)X
+2607(and)X
+2762(10)X
+2881(branch)X
+3139(records.)X
+3455(Where)X
+3709(TPS)X
+3885(numbers)X
+4200(are)X
+555 1905(reported,)N
+865(we)X
+981(are)X
+1102(running)X
+1373(a)X
+1431(modi\256ed)X
+1737(version)X
+1995(of)X
+2084(the)X
+2203(industry)X
+2486(standard)X
+2779(transaction)X
+3152(processing)X
+3516(benchmark,)X
+3914(TPCB.)X
+4174(The)X
+555 1995(TPCB)N
+780(benchmark)X
+1163(simulates)X
+1491(a)X
+1553(withdrawal)X
+1940(performed)X
+2301(by)X
+2407(a)X
+2469(hypothetical)X
+2891(teller)X
+3082(at)X
+3166(a)X
+3228(hypothetical)X
+3650(bank.)X
+3872(The)X
+4022(database)X
+555 2085(consists)N
+831(of)X
+921(relations)X
+1220(\(\256les\))X
+1430(for)X
+1547(accounts,)X
+1871(branches,)X
+2200(tellers,)X
+2439(and)X
+2578(history.)X
+2863(For)X
+2997(each)X
+3168(transaction,)X
+3563(the)X
+3684(account,)X
+3976(teller,)X
+4183(and)X
+555 2175(branch)N
+795(balances)X
+1093(must)X
+1269(be)X
+1366(updated)X
+1641(to)X
+1724(re\257ect)X
+1946(the)X
+2065(withdrawal)X
+2447(and)X
+2584(a)X
+2640(history)X
+2882(record)X
+3108(is)X
+3181(written)X
+3428(which)X
+3644(contains)X
+3931(the)X
+4049(account)X
+555 2265(id,)N
+657(branch)X
+896(id,)X
+998(teller)X
+1183(id,)X
+1285(and)X
+1421(the)X
+1539(amount)X
+1799(of)X
+1886(the)X
+2004(withdrawal)X
+2385([TPCB90].)X
+755 2388(Our)N
+914(implementation)X
+1450(of)X
+1551(the)X
+1683(benchmark)X
+2074(differs)X
+2317(from)X
+2506(the)X
+2637(speci\256cation)X
+3075(in)X
+3170(several)X
+3431(aspects.)X
+3736(The)X
+3894(speci\256cation)X
+555 2478(requires)N
+840(that)X
+985(the)X
+1108(database)X
+1410(keep)X
+1587(redundant)X
+1933(logs)X
+2091(on)X
+2196(different)X
+2498(devices,)X
+2784(but)X
+2911(we)X
+3030(use)X
+3162(a)X
+3223(single)X
+3439(log.)X
+3606(Furthermore,)X
+4052(all)X
+4157(tests)X
+555 2568(were)N
+734(run)X
+863(on)X
+965(a)X
+1023(single,)X
+1256(centralized)X
+1631(system)X
+1875(so)X
+1968(there)X
+2151(is)X
+2226(no)X
+2328(notion)X
+2553(of)X
+2641(remote)X
+2885(accesses.)X
+3219(Finally,)X
+3486(we)X
+3601(calculated)X
+3948(throughput)X
+555 2658(by)N
+662(dividing)X
+955(the)X
+1080(total)X
+1249(elapsed)X
+1517(time)X
+1686(by)X
+1793(the)X
+1918(number)X
+2190(of)X
+2284(transactions)X
+2694(processed)X
+3038(rather)X
+3253(than)X
+3418(by)X
+3525(computing)X
+3894(the)X
+4018(response)X
+555 2748(time)N
+717(for)X
+831(each)X
+999(transaction.)X
+755 2871(The)N
+912(performance)X
+1351(comparisons)X
+1788(focus)X
+1993(on)X
+2104(traditional)X
+2464(Unix)X
+2655(techniques)X
+3029(\(unprotected,)X
+3486(using)X
+3 f
+3690(\257ock)X
+1 f
+3854(\(2\))X
+3979(and)X
+4126(using)X
+3 f
+555 2961(fsync)N
+1 f
+733(\(2\)\))X
+884(and)X
+1030(a)X
+1096(commercial)X
+1504(relational)X
+1836(database)X
+2142(system.)X
+2433(Well-behaved)X
+2913(applications)X
+3329(using)X
+3 f
+3531(\257ock)X
+1 f
+3695(\(2\))X
+3818(are)X
+3946(guaranteed)X
+555 3051(that)N
+704(concurrent)X
+1077(processes')X
+1441(updates)X
+1715(do)X
+1824(not)X
+1955(interact)X
+2225(with)X
+2396(one)X
+2541(another,)X
+2831(but)X
+2962(no)X
+3070(guarantees)X
+3442(about)X
+3648(atomicity)X
+3978(are)X
+4105(made.)X
+555 3141(That)N
+731(is,)X
+833(if)X
+911(the)X
+1038(system)X
+1289(crashes)X
+1555(in)X
+1646(mid-transaction,)X
+2198(only)X
+2369(parts)X
+2554(of)X
+2649(that)X
+2797(transaction)X
+3177(will)X
+3329(be)X
+3433(re\257ected)X
+3738(in)X
+3828(the)X
+3954 0.3125(after-crash)AX
+555 3231(state)N
+725(of)X
+815(the)X
+936(database.)X
+1276(The)X
+1424(use)X
+1554(of)X
+3 f
+1643(fsync)X
+1 f
+1821(\(2\))X
+1937(at)X
+2017(transaction)X
+2391(commit)X
+2657(time)X
+2821(provides)X
+3119(guarantees)X
+3485(of)X
+3574(durability)X
+3907(after)X
+4077(system)X
+555 3321(failure.)N
+825(However,)X
+1160(there)X
+1341(is)X
+1414(no)X
+1514(mechanism)X
+1899(to)X
+1981(perform)X
+2260(transaction)X
+2632(abort.)X
+3 f
+555 3507(5.1.1.)N
+775(Single-User)X
+1191(Tests)X
+1 f
+755 3630(These)N
+978(tests)X
+1151(compare)X
+1459(LIBTP)X
+1712(in)X
+1804(a)X
+1870(variety)X
+2123(of)X
+2220(con\256gurations)X
+2708(to)X
+2800(traditional)X
+3159(UNIX)X
+3390(solutions)X
+3708(and)X
+3854(a)X
+3920(commercial)X
+555 3720(relational)N
+884(database)X
+1187(system)X
+1435(\(RDBMS\).)X
+1814(To)X
+1929(demonstrate)X
+2347(the)X
+2471(server)X
+2694(architecture)X
+3100(we)X
+3220(built)X
+3392(a)X
+3454(front)X
+3636(end)X
+3777(test)X
+3913(process)X
+4179(that)X
+555 3810(uses)N
+732(TCL)X
+922([OUST90])X
+1304(to)X
+1405(parse)X
+1614(database)X
+1930(access)X
+2175(commands)X
+2561(and)X
+2716(call)X
+2870(the)X
+3006(database)X
+3321(access)X
+3565(routines.)X
+3901(In)X
+4006(one)X
+4160(case)X
+555 3900(\(SERVER\),)N
+956(frontend)X
+1249(and)X
+1386(backend)X
+1675(processes)X
+2004(were)X
+2181(created)X
+2434(which)X
+2650(communicated)X
+3142(via)X
+3260(an)X
+3356(IP)X
+3447(socket.)X
+3712(In)X
+3799(the)X
+3917(second)X
+4160(case)X
+555 3990(\(TCL\),)N
+802(a)X
+860(single)X
+1073(process)X
+1336(read)X
+1497(queries)X
+1751(from)X
+1929(standard)X
+2223(input,)X
+2429(parsed)X
+2660(them,)X
+2861(and)X
+2998(called)X
+3211(the)X
+3330(database)X
+3628(access)X
+3855(routines.)X
+4174(The)X
+555 4080(performance)N
+987(difference)X
+1338(between)X
+1630(the)X
+1752(TCL)X
+1927(and)X
+2067(SERVER)X
+2397(tests)X
+2563(quanti\256es)X
+2898(the)X
+3020(communication)X
+3542(overhead)X
+3861(of)X
+3952(the)X
+4074(socket.)X
+555 4170(The)N
+732(RDBMS)X
+1063(implementation)X
+1617(used)X
+1816(embedded)X
+2198(SQL)X
+2401(in)X
+2515(C)X
+2620(with)X
+2814(stored)X
+3062(database)X
+3391(procedures.)X
+3835(Therefore,)X
+4224(its)X
+555 4260(con\256guration)N
+1003(is)X
+1076(a)X
+1132(hybrid)X
+1361(of)X
+1448(the)X
+1566(single)X
+1777(process)X
+2038(architecture)X
+2438(and)X
+2574(the)X
+2692(server)X
+2909(architecture.)X
+3349(The)X
+3494(graph)X
+3697(in)X
+3779(\256gure)X
+3986(six)X
+4099(shows)X
+555 4350(a)N
+611(comparison)X
+1005(of)X
+1092(the)X
+1210(following)X
+1541(six)X
+1654(con\256gurations:)X
+1126 4506(LIBTP)N
+1552(Uses)X
+1728(the)X
+1846(LIBTP)X
+2088(library)X
+2322(in)X
+2404(a)X
+2460(single)X
+2671(application.)X
+1126 4596(TCL)N
+1552(Uses)X
+1728(the)X
+1846(LIBTP)X
+2088(library)X
+2322(in)X
+2404(a)X
+2460(single)X
+2671(application,)X
+3067(requires)X
+3346(query)X
+3549(parsing.)X
+1126 4686(SERVER)N
+1552(Uses)X
+1728(the)X
+1846(LIBTP)X
+2088(library)X
+2322(in)X
+2404(a)X
+2460(server)X
+2677(con\256guration,)X
+3144(requires)X
+3423(query)X
+3626(parsing.)X
+1126 4776(NOTP)N
+1552(Uses)X
+1728(no)X
+1828(locking,)X
+2108(logging,)X
+2392(or)X
+2479(concurrency)X
+2897(control.)X
+1126 4866(FLOCK)N
+1552(Uses)X
+3 f
+1728(\257ock)X
+1 f
+1892(\(2\))X
+2006(for)X
+2120(concurrency)X
+2538(control)X
+2785(and)X
+2921(nothing)X
+3185(for)X
+3299(durability.)X
+1126 4956(FSYNC)N
+1552(Uses)X
+3 f
+1728(fsync)X
+1 f
+1906(\(2\))X
+2020(for)X
+2134(durability)X
+2465(and)X
+2601(nothing)X
+2865(for)X
+2979(concurrency)X
+3397(control.)X
+1126 5046(RDBMS)N
+1552(Uses)X
+1728(a)X
+1784(commercial)X
+2183(relational)X
+2506(database)X
+2803(system.)X
+755 5235(The)N
+902(results)X
+1133(show)X
+1324(that)X
+1466(LIBTP,)X
+1730(both)X
+1894(in)X
+1978(the)X
+2098(procedural)X
+2464(and)X
+2602(parsed)X
+2834(environments,)X
+3312(is)X
+3387(competitive)X
+3787(with)X
+3951(a)X
+4009(commer-)X
+555 5325(cial)N
+692(system)X
+935(\(comparing)X
+1326(LIBTP,)X
+1589(TCL,)X
+1781(and)X
+1917(RDBMS\).)X
+2263(Compared)X
+2617(to)X
+2699(existing)X
+2972(UNIX)X
+3193(solutions,)X
+3521(LIBTP)X
+3763(is)X
+3836(approximately)X
+555 5415(15%)N
+738(slower)X
+988(than)X
+1162(using)X
+3 f
+1371(\257ock)X
+1 f
+1535(\(2\))X
+1665(or)X
+1768(no)X
+1884(protection)X
+2245(but)X
+2383(over)X
+2562(80%)X
+2745(better)X
+2964(than)X
+3137(using)X
+3 f
+3345(fsync)X
+1 f
+3523(\(2\))X
+3652(\(comparing)X
+4057(LIBTP,)X
+555 5505(FLOCK,)N
+857(NOTP,)X
+1106(and)X
+1242(FSYNC\).)X
+
+12 p
+%%Page: 12 12
+10 s 10 xH 0 xS 1 f
+3 f
+8 s
+3500 2184(RDBMS)N
+1 Dt
+3553 2085 MXY
+ 3553 2085 lineto
+ 3676 2085 lineto
+ 3676 1351 lineto
+ 3553 1351 lineto
+ 3553 2085 lineto
+closepath 16 3553 1351 3676 2085 Dp
+2018 2184(SERVER)N
+1720 1168 MXY
+0 917 Dl
+122 0 Dl
+0 -917 Dl
+-122 0 Dl
+1715 2184(TCL)N
+2087 1534 MXY
+ 2087 1534 lineto
+ 2209 1534 lineto
+ 2209 2085 lineto
+ 2087 2085 lineto
+ 2087 1534 lineto
+closepath 12 2087 1534 2209 2085 Dp
+3187 MX
+ 3187 1534 lineto
+ 3309 1534 lineto
+ 3309 2085 lineto
+ 3187 2085 lineto
+ 3187 1534 lineto
+closepath 19 3187 1534 3309 2085 Dp
+3142 2184(FSYNC)N
+2425(NOTP)X
+2453 955 MXY
+ 2453 955 lineto
+ 2576 955 lineto
+ 2576 2085 lineto
+ 2453 2085 lineto
+ 2453 955 lineto
+closepath 21 2453 955 2576 2085 Dp
+2820 1000 MXY
+ 2820 1000 lineto
+ 2942 1000 lineto
+ 2942 2085 lineto
+ 2820 2085 lineto
+ 2820 1000 lineto
+closepath 14 2820 1000 2942 2085 Dp
+5 Dt
+1231 2085 MXY
+2567 0 Dl
+4 Ds
+1 Dt
+1231 1840 MXY
+2567 0 Dl
+1231 1596 MXY
+2567 0 Dl
+1231 1351 MXY
+2567 0 Dl
+1231 1108 MXY
+2567 0 Dl
+1231 863 MXY
+2567 0 Dl
+11 s
+1087 1877(2)N
+1087 1633(4)N
+1087 1388(6)N
+1087 1145(8)N
+1065 900(10)N
+1028 763(TPS)N
+-1 Ds
+1353 2085 MXY
+ 1353 2085 lineto
+ 1353 1151 lineto
+ 1476 1151 lineto
+ 1476 2085 lineto
+ 1353 2085 lineto
+closepath 3 1353 1151 1476 2085 Dp
+8 s
+1318 2184(LIBTP)N
+2767(FLOCK)X
+3 Dt
+-1 Ds
+10 s
+1597 2399(Figure)N
+1844(6:)X
+1931(Single-User)X
+2347(Performance)X
+2814(Comparison.)X
+1 f
+10 f
+555 2579(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+3 f
+555 2855(5.1.2.)N
+775(Multi-User)X
+1174(Tests)X
+1 f
+755 2978(While)N
+975(the)X
+1097(single-user)X
+1473(tests)X
+1639(form)X
+1819(a)X
+1878(basis)X
+2061(for)X
+2178(comparing)X
+2544(LIBTP)X
+2789(to)X
+2874(other)X
+3062(systems,)X
+3358(our)X
+3488(goal)X
+3649(in)X
+3734(multi-user)X
+4086(testing)X
+555 3068(was)N
+714(to)X
+810(analyze)X
+1089(its)X
+1197(scalability.)X
+1579(To)X
+1701(this)X
+1849(end,)X
+2018(we)X
+2145(have)X
+2330(run)X
+2470(the)X
+2601(benchmark)X
+2991(in)X
+3086(three)X
+3280(modes,)X
+3542(the)X
+3673(normal)X
+3933(disk)X
+4099(bound)X
+555 3158(con\256guration)N
+1010(\(\256gure)X
+1252(seven\),)X
+1510(a)X
+1573(CPU)X
+1755(bound)X
+1982(con\256guration)X
+2436(\(\256gure)X
+2677(eight,)X
+2884(READ-ONLY\),)X
+3426(and)X
+3569(lock)X
+3734(contention)X
+4099(bound)X
+555 3248(\(\256gure)N
+796(eight,)X
+1003(NO_FSYNC\).)X
+1510(Since)X
+1715(the)X
+1840(normal)X
+2094(con\256guration)X
+2548(is)X
+2628(completely)X
+3011(disk)X
+3171(bound)X
+3398(\(each)X
+3600(transaction)X
+3978(requires)X
+4263(a)X
+555 3354(random)N
+823(read,)X
+1005(a)X
+1064(random)X
+1332(write,)X
+1540(and)X
+1679(a)X
+1738(sequential)X
+2086(write)X
+7 s
+2251 3322(4)N
+10 s
+3354(\))Y
+2329(we)X
+2446(expect)X
+2679(to)X
+2764(see)X
+2890(little)X
+3059(performance)X
+3489(improvement)X
+3939(as)X
+4028(the)X
+4148(mul-)X
+555 3444(tiprogramming)N
+1064(level)X
+1249(increases.)X
+1613(In)X
+1709(fact,)X
+1879(\256gure)X
+2095(seven)X
+2307(reveals)X
+2564(that)X
+2713(we)X
+2836(are)X
+2964(able)X
+3127(to)X
+3218(overlap)X
+3487(CPU)X
+3670(and)X
+3814(disk)X
+3975(utilization)X
+555 3534(slightly)N
+825(producing)X
+1181(approximately)X
+1674(a)X
+1740(10%)X
+1917(performance)X
+2354(improvement)X
+2811(with)X
+2983(two)X
+3133(processes.)X
+3511(After)X
+3711(that)X
+3861(point,)X
+4075(perfor-)X
+555 3624(mance)N
+785(drops)X
+983(off,)X
+1117(and)X
+1253(at)X
+1331(a)X
+1387(multi-programming)X
+2038(level)X
+2214(of)X
+2301(4,)X
+2381(we)X
+2495(are)X
+2614(performing)X
+2995(worse)X
+3207(than)X
+3365(in)X
+3447(the)X
+3565(single)X
+3776(process)X
+4037(case.)X
+755 3747(Similar)N
+1021(behavior)X
+1333(was)X
+1489(reported)X
+1787(on)X
+1897(the)X
+2025(commercial)X
+2434(relational)X
+2767(database)X
+3074(system)X
+3326(using)X
+3529(the)X
+3657(same)X
+3852(con\256guration.)X
+555 3837(The)N
+707(important)X
+1045(conclusion)X
+1419(to)X
+1508(draw)X
+1696(from)X
+1879(this)X
+2021(is)X
+2101(that)X
+2248(you)X
+2395(cannot)X
+2636(attain)X
+2841(good)X
+3028(multi-user)X
+3384(scaling)X
+3638(on)X
+3745(a)X
+3808(badly)X
+4013(balanced)X
+555 3927(system.)N
+839(If)X
+915(multi-user)X
+1266(performance)X
+1695(on)X
+1797(applications)X
+2205(of)X
+2293(this)X
+2429(sort)X
+2570(is)X
+2644(important,)X
+2996(one)X
+3133(must)X
+3309(have)X
+3482(a)X
+3539(separate)X
+3824(logging)X
+4089(device)X
+555 4017(and)N
+697(horizontally)X
+1110(partition)X
+1407(the)X
+1531(database)X
+1834(to)X
+1921(allow)X
+2124(a)X
+2185(suf\256ciently)X
+2570(high)X
+2737(degree)X
+2977(of)X
+3069(multiprogramming)X
+3698(that)X
+3843(group)X
+4055(commit)X
+555 4107(can)N
+687(amortize)X
+988(the)X
+1106(cost)X
+1255(of)X
+1342(log)X
+1464(\257ushing.)X
+755 4230(By)N
+871(using)X
+1067(a)X
+1126(very)X
+1292(small)X
+1488(database)X
+1788(\(one)X
+1954(that)X
+2097(can)X
+2232(be)X
+2331(entirely)X
+2599(cached)X
+2846(in)X
+2930(main)X
+3112(memory\))X
+3428(and)X
+3566(read-only)X
+3896(transactions,)X
+555 4320(we)N
+670(generated)X
+1004(a)X
+1061(CPU)X
+1236(bound)X
+1456(environment.)X
+1921(By)X
+2034(using)X
+2227(the)X
+2345(same)X
+2530(small)X
+2723(database,)X
+3040(the)X
+3158(complete)X
+3472(TPCB)X
+3691(transaction,)X
+4083(and)X
+4219(no)X
+3 f
+555 4410(fsync)N
+1 f
+733(\(2\))X
+862(on)X
+977(the)X
+1110(log)X
+1247(at)X
+1340(commit,)X
+1639(we)X
+1768(created)X
+2036(a)X
+2107(lock)X
+2280(contention)X
+2652(bound)X
+2886(environment.)X
+3365(The)X
+3524(small)X
+3731(database)X
+4042(used)X
+4223(an)X
+555 4500(account)N
+828(\256le)X
+953(containing)X
+1314(only)X
+1479(1000)X
+1662(records)X
+1922(rather)X
+2133(than)X
+2294(the)X
+2415(full)X
+2549(1,000,000)X
+2891(records)X
+3150(and)X
+3288(ran)X
+3413(enough)X
+3671(transactions)X
+4076(to)X
+4160(read)X
+555 4590(the)N
+677(entire)X
+883(database)X
+1183(into)X
+1330(the)X
+1451(buffer)X
+1671(pool)X
+1836(\(2000\))X
+2073(before)X
+2302(beginning)X
+2645(measurements.)X
+3147(The)X
+3295(read-only)X
+3626(transaction)X
+4001(consisted)X
+555 4680(of)N
+646(three)X
+831(database)X
+1132(reads)X
+1326(\(from)X
+1533(the)X
+1655(1000)X
+1839(record)X
+2069(account)X
+2343(\256le,)X
+2489(the)X
+2611(100)X
+2754(record)X
+2983(teller)X
+3171(\256le,)X
+3316(and)X
+3455(the)X
+3576(10)X
+3679(record)X
+3908(branch)X
+4150(\256le\).)X
+555 4770(Since)N
+759(no)X
+865(data)X
+1025(were)X
+1208(modi\256ed)X
+1518(and)X
+1660(no)X
+1766(history)X
+2014(records)X
+2277(were)X
+2460(written,)X
+2733(no)X
+2839(log)X
+2966(records)X
+3228(were)X
+3410(written.)X
+3702(For)X
+3838(the)X
+3961(contention)X
+555 4860(bound)N
+780(con\256guration,)X
+1252(we)X
+1371(used)X
+1543(the)X
+1666(normal)X
+1918(TPCB)X
+2142(transaction)X
+2519(\(against)X
+2798(the)X
+2920(small)X
+3117(database\))X
+3445(and)X
+3585(disabled)X
+3876(the)X
+3998(log)X
+4124(\257ush.)X
+555 4950(Figure)N
+784(eight)X
+964(shows)X
+1184(both)X
+1346(of)X
+1433(these)X
+1618(results.)X
+755 5073(The)N
+902(read-only)X
+1231(test)X
+1363(indicates)X
+1669(that)X
+1810(we)X
+1925(barely)X
+2147(scale)X
+2329(at)X
+2408(all)X
+2509(in)X
+2592(the)X
+2711(CPU)X
+2887(bound)X
+3108(case.)X
+3308(The)X
+3454(explanation)X
+3849(for)X
+3964(that)X
+4105(is)X
+4179(that)X
+555 5163(even)N
+735(with)X
+905(a)X
+969(single)X
+1188(process,)X
+1477(we)X
+1599(are)X
+1726(able)X
+1888(to)X
+1978(drive)X
+2171(the)X
+2297(CPU)X
+2480(utilization)X
+2832(to)X
+2922(96%.)X
+3137(As)X
+3254(a)X
+3317(result,)X
+3542(that)X
+3689(gives)X
+3885(us)X
+3983(very)X
+4153(little)X
+555 5253(room)N
+753(for)X
+876(improvement,)X
+1352(and)X
+1497(it)X
+1570(takes)X
+1764(a)X
+1829(multiprogramming)X
+2462(level)X
+2647(of)X
+2743(four)X
+2906(to)X
+2997(approach)X
+3321(100%)X
+3537(CPU)X
+3721(saturation.)X
+4106(In)X
+4201(the)X
+555 5343(case)N
+718(where)X
+939(we)X
+1057(do)X
+1161(perform)X
+1444(writes,)X
+1684(we)X
+1802(are)X
+1925(interested)X
+2261(in)X
+2347(detecting)X
+2665(when)X
+2863(lock)X
+3025(contention)X
+3387(becomes)X
+3691(a)X
+3750(dominant)X
+4075(perfor-)X
+555 5433(mance)N
+787(factor.)X
+1037(Contention)X
+1414(will)X
+1560(cause)X
+1761(two)X
+1903(phenomena;)X
+2317(we)X
+2433(will)X
+2579(see)X
+2704(transactions)X
+3109(queueing)X
+3425(behind)X
+3665(frequently)X
+4017(accessed)X
+555 5523(data,)N
+731(and)X
+869(we)X
+985(will)X
+1131(see)X
+1256(transaction)X
+1629(abort)X
+1815(rates)X
+1988(increasing)X
+2339(due)X
+2476(to)X
+2559(deadlock.)X
+2910(Given)X
+3127(that)X
+3268(the)X
+3387(branch)X
+3627(\256le)X
+3750(contains)X
+4038(only)X
+4201(ten)X
+8 s
+10 f
+555 5595(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5673(4)N
+8 s
+763 5698(Although)N
+1021(the)X
+1115(log)X
+1213(is)X
+1272(written)X
+1469(sequentially,)X
+1810(we)X
+1900(do)X
+1980(not)X
+2078(get)X
+2172(the)X
+2266(bene\256t)X
+2456(of)X
+2525(sequentiality)X
+2868(since)X
+3015(the)X
+3109(log)X
+3207(and)X
+3315(database)X
+3550(reside)X
+3718(on)X
+3798(the)X
+3892(same)X
+4039(disk.)X
+
+13 p
+%%Page: 13 13
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+3187 2051 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3286 2028 MXY
+0 17 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3384 1926 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3483 1910 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3581 1910 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3680 1832 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3778 1909 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3877 1883 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3975 1679 MXY
+0 17 Dl
+0 -8 Dl
+9 0 Dl
+-18 0 Dl
+4074 1487 MXY
+0 17 Dl
+0 -8 Dl
+9 0 Dl
+-18 0 Dl
+5 Dt
+3187 2060 MXY
+99 -24 Dl
+98 -101 Dl
+99 -16 Dl
+98 0 Dl
+99 -78 Dl
+98 77 Dl
+99 -26 Dl
+98 -204 Dl
+99 -192 Dl
+3 f
+6 s
+4088 1516(SMALL)N
+3 Dt
+3187 2051 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3286 2051 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3384 2041 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3483 1990 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3581 1843 MXY
+0 17 Dl
+0 -8 Dl
+9 0 Dl
+-18 0 Dl
+3680 1578 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3778 1496 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3877 1430 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+3975 1269 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+4074 1070 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1 Dt
+3187 2060 MXY
+99 0 Dl
+98 -10 Dl
+99 -51 Dl
+98 -147 Dl
+99 -265 Dl
+98 -82 Dl
+99 -66 Dl
+98 -161 Dl
+99 -199 Dl
+4088 1099(LARGE)N
+5 Dt
+3089 2060 MXY
+985 0 Dl
+3089 MX
+0 -1174 Dl
+4 Ds
+1 Dt
+3581 2060 MXY
+0 -1174 Dl
+4074 2060 MXY
+0 -1174 Dl
+3089 1825 MXY
+985 0 Dl
+9 s
+2993 1855(25)N
+3089 1591 MXY
+985 0 Dl
+2993 1621(50)N
+3089 1356 MXY
+985 0 Dl
+2993 1386(75)N
+3089 1121 MXY
+985 0 Dl
+2957 1151(100)N
+3089 886 MXY
+985 0 Dl
+2957 916(125)N
+3281 2199(Multiprogramming)N
+3071 2152(0)N
+3569(5)X
+4038(10)X
+2859 787(Aborts)N
+3089(per)X
+3211(500)X
+2901 847(transactions)N
+-1 Ds
+3 Dt
+2037 1342 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2125 1358 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2213 1341 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2301 1191 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2388 1124 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-17 0 Dl
+2476 1157 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2564 1157 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2652 1161 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2740 1153 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2828 1150 MXY
+0 18 Dl
+0 -9 Dl
+8 0 Dl
+-17 0 Dl
+5 Dt
+2037 1351 MXY
+88 16 Dl
+88 -17 Dl
+88 -150 Dl
+87 -67 Dl
+88 33 Dl
+88 0 Dl
+88 4 Dl
+88 -8 Dl
+88 -3 Dl
+6 s
+2685 1234(READ-ONLY)N
+3 Dt
+2037 1464 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2125 1640 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2213 1854 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2301 1872 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2388 1871 MXY
+0 17 Dl
+0 -9 Dl
+9 0 Dl
+-17 0 Dl
+2476 1933 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2564 1914 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2652 1903 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2740 1980 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+2828 2004 MXY
+0 18 Dl
+0 -9 Dl
+8 0 Dl
+-17 0 Dl
+1 Dt
+2037 1473 MXY
+88 176 Dl
+88 214 Dl
+88 18 Dl
+87 -2 Dl
+88 63 Dl
+88 -19 Dl
+88 -11 Dl
+88 77 Dl
+88 24 Dl
+2759 1997(NO-FSYNC)N
+5 Dt
+1949 2060 MXY
+879 0 Dl
+1949 MX
+0 -1174 Dl
+4 Ds
+1 Dt
+2388 2060 MXY
+0 -1174 Dl
+2828 2060 MXY
+0 -1174 Dl
+1949 1825 MXY
+879 0 Dl
+9 s
+1842 1855(40)N
+1949 1591 MXY
+879 0 Dl
+1842 1621(80)N
+1949 1356 MXY
+879 0 Dl
+1806 1386(120)N
+1949 1121 MXY
+879 0 Dl
+1806 1151(160)N
+1949 886 MXY
+879 0 Dl
+1806 916(200)N
+2088 2199(Multiprogramming)N
+1844 863(in)N
+1922(TPS)X
+1761 792(Throughput)N
+1931 2121(0)N
+2370 2133(5)N
+2792(10)X
+6 s
+1679 1833(LIBTP)N
+-1 Ds
+3 Dt
+837 1019 MXY
+0 17 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+929 878 MXY
+0 17 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1021 939 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1113 1043 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1205 1314 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1297 1567 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1389 1665 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1481 1699 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1573 1828 MXY
+0 18 Dl
+0 -9 Dl
+9 0 Dl
+-18 0 Dl
+1665 1804 MXY
+0 18 Dl
+0 -9 Dl
+8 0 Dl
+-17 0 Dl
+5 Dt
+837 1027 MXY
+92 -141 Dl
+92 62 Dl
+92 104 Dl
+92 271 Dl
+92 253 Dl
+92 98 Dl
+92 34 Dl
+92 129 Dl
+92 -24 Dl
+745 2060 MXY
+920 0 Dl
+745 MX
+0 -1174 Dl
+4 Ds
+1 Dt
+1205 2060 MXY
+0 -1174 Dl
+1665 2060 MXY
+0 -1174 Dl
+745 1766 MXY
+920 0 Dl
+9 s
+673 1796(3)N
+745 1473 MXY
+920 0 Dl
+673 1503(5)N
+745 1180 MXY
+920 0 Dl
+673 1210(8)N
+745 886 MXY
+920 0 Dl
+637 916(10)N
+905 2199(Multiprogramming)N
+622 851(in)N
+700(TPS)X
+575 792(Throughput)N
+733 2152(0)N
+1196(5)X
+1629(10)X
+3 Dt
+-1 Ds
+8 s
+655 2441(Figure)N
+872(7:)X
+960(Multi-user)X
+1286(Performance.)X
+1 f
+655 2531(Since)N
+825(the)X
+931(con\256guration)X
+1300(is)X
+1371(completely)X
+655 2621(disk)N
+790(bound,)X
+994(we)X
+1096(see)X
+1204(only)X
+1345(a)X
+1400(small)X
+1566(im-)X
+655 2711(provement)N
+964(by)X
+1064(adding)X
+1274(a)X
+1337(second)X
+1549(pro-)X
+655 2801(cess.)N
+849(Adding)X
+1081(any)X
+1213(more)X
+1383(concurrent)X
+655 2891(processes)N
+935(causes)X
+1137(performance)X
+1493(degra-)X
+655 2981(dation.)N
+3 f
+1927 2441(Figure)N
+2149(8:)X
+2243(Multi-user)X
+2574(Performance)X
+1927 2531(on)N
+2021(a)X
+2079(small)X
+2251(database.)X
+1 f
+2551(With)X
+2704(one)X
+2821(pro-)X
+1927 2621(cess,)N
+2075(we)X
+2174(are)X
+2276(driving)X
+2486(the)X
+2589(CPU)X
+2739(at)X
+2810(96%)X
+1927 2711(utilization)N
+2215(leaving)X
+2430(little)X
+2575(room)X
+2737(for)X
+2838(im-)X
+1927 2801(provement)N
+2238(as)X
+2328(the)X
+2443(multiprogramming)X
+1927 2891(level)N
+2091(increases.)X
+2396(In)X
+2489(the)X
+2607(NO-FSYNC)X
+1927 2981(case,)N
+2076(lock)X
+2209(contention)X
+2502(degrades)X
+2751(perfor-)X
+1927 3071(mance)N
+2117(as)X
+2194(soon)X
+2339(as)X
+2416(a)X
+2468(second)X
+2669(process)X
+2884(is)X
+1927 3161(added.)N
+3 f
+3199 2441(Figure)N
+3405(9:)X
+3482(Abort)X
+3669(rates)X
+3827(on)X
+3919(the)X
+4028(TPCB)X
+3199 2531(Benchmark.)N
+1 f
+3589(The)X
+3726(abort)X
+3895(rate)X
+4028(climbs)X
+3199 2621(more)N
+3366(quickly)X
+3594(for)X
+3704(the)X
+3818(large)X
+3980(database)X
+3199 2711(test)N
+3324(since)X
+3491(processes)X
+3771(are)X
+3884(descheduled)X
+3199 2801(more)N
+3409(frequently,)X
+3766(allowing)X
+4068(more)X
+3199 2891(processes)N
+3459(to)X
+3525(vie)X
+3619(for)X
+3709(the)X
+3803(same)X
+3950(locks.)X
+10 s
+10 f
+555 3284(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+1 f
+555 3560(records,)N
+835(we)X
+952(expect)X
+1185(contention)X
+1546(to)X
+1631(become)X
+1904(a)X
+1963(factor)X
+2174(quickly)X
+2437(and)X
+2576(the)X
+2697(NO-FSYNC)X
+3120(line)X
+3263(in)X
+3348(\256gure)X
+3557(eight)X
+3739(demonstrates)X
+4184(this)X
+555 3650(dramatically.)N
+1022(Each)X
+1209(additional)X
+1555(process)X
+1822(causes)X
+2058(both)X
+2226(more)X
+2417(waiting)X
+2682(and)X
+2823(more)X
+3013(deadlocking.)X
+3470(Figure)X
+3704(nine)X
+3867(shows)X
+4092(that)X
+4237(in)X
+555 3740(the)N
+681(small)X
+882(database)X
+1187(case)X
+1353(\(SMALL\),)X
+1725(waiting)X
+1992(is)X
+2072(the)X
+2197(dominant)X
+2526(cause)X
+2732(of)X
+2826(declining)X
+3151(performance)X
+3585(\(the)X
+3737(number)X
+4009(of)X
+4103(aborts)X
+555 3830(increases)N
+878(less)X
+1026(steeply)X
+1281(than)X
+1447(the)X
+1573(performance)X
+2008(drops)X
+2214(off)X
+2336(in)X
+2426(\256gure)X
+2641(eight\),)X
+2876(while)X
+3082(in)X
+3172(the)X
+3298(large)X
+3487(database)X
+3792(case)X
+3958(\(LARGE\),)X
+555 3920(deadlocking)N
+967(contributes)X
+1343(more)X
+1528(to)X
+1610(the)X
+1728(declining)X
+2046(performance.)X
+755 4043(Deadlocks)N
+1116(are)X
+1237(more)X
+1424(likely)X
+1628(to)X
+1712(occur)X
+1913(in)X
+1997(the)X
+2116(LARGE)X
+2404(test)X
+2536(than)X
+2695(in)X
+2778(the)X
+2897(SMALL)X
+3189(test)X
+3321(because)X
+3597(there)X
+3779(are)X
+3899(more)X
+4085(oppor-)X
+555 4133(tunities)N
+814(to)X
+900(wait.)X
+1082(In)X
+1173(the)X
+1295(SMALL)X
+1590(case,)X
+1773(processes)X
+2105(never)X
+2307(do)X
+2410(I/O)X
+2540(and)X
+2679(are)X
+2801(less)X
+2944(likely)X
+3149(to)X
+3234(be)X
+3333(descheduled)X
+3753(during)X
+3985(a)X
+4044(transac-)X
+555 4223(tion.)N
+740(In)X
+828(the)X
+947(LARGE)X
+1235(case,)X
+1415(processes)X
+1744(will)X
+1889(frequently)X
+2240(be)X
+2337(descheduled)X
+2755(since)X
+2941(they)X
+3100(have)X
+3273(to)X
+3356(perform)X
+3636(I/O.)X
+3804(This)X
+3967(provides)X
+4263(a)X
+555 4313(window)N
+837(where)X
+1058(a)X
+1118(second)X
+1365(process)X
+1630(can)X
+1766(request)X
+2022(locks)X
+2215(on)X
+2318(already)X
+2578(locked)X
+2815(pages,)X
+3041(thus)X
+3197(increasing)X
+3550(the)X
+3671(likelihood)X
+4018(of)X
+4108(build-)X
+555 4403(ing)N
+677(up)X
+777(long)X
+939(chains)X
+1164(of)X
+1251(waiting)X
+1511(processes.)X
+1879(Eventually,)X
+2266(this)X
+2401(leads)X
+2586(to)X
+2668(deadlock.)X
+3 f
+555 4589(5.2.)N
+715(The)X
+868(OO1)X
+1052(Benchmark)X
+1 f
+755 4712(The)N
+903(TPCB)X
+1125(benchmark)X
+1505(described)X
+1836(in)X
+1921(the)X
+2042(previous)X
+2341(section)X
+2591(measures)X
+2913(performance)X
+3343(under)X
+3549(a)X
+3608(conventional)X
+4044(transac-)X
+555 4802(tion)N
+706(processing)X
+1076(workload.)X
+1446(Other)X
+1656(application)X
+2039(domains,)X
+2357(such)X
+2531(as)X
+2625(computer-aided)X
+3156(design,)X
+3412(have)X
+3591(substantially)X
+4022(different)X
+555 4892(access)N
+786(patterns.)X
+1105(In)X
+1197(order)X
+1392(to)X
+1479(measure)X
+1772(the)X
+1895(performance)X
+2327(of)X
+2418(LIBTP)X
+2664(under)X
+2871(workloads)X
+3229(of)X
+3320(this)X
+3459(type,)X
+3641(we)X
+3759(implemented)X
+4201(the)X
+555 4982(OO1)N
+731(benchmark)X
+1108(described)X
+1436(in)X
+1518([CATT91].)X
+755 5105(The)N
+908(database)X
+1213(models)X
+1472(a)X
+1535(set)X
+1651(of)X
+1745(electronics)X
+2120(components)X
+2534(with)X
+2703(connections)X
+3113(among)X
+3358(them.)X
+3585(One)X
+3746(table)X
+3929(stores)X
+4143(parts)X
+555 5195(and)N
+696(another)X
+962(stores)X
+1174(connections.)X
+1622(There)X
+1835(are)X
+1959(three)X
+2145(connections)X
+2552(originating)X
+2927(at)X
+3009(any)X
+3149(given)X
+3351(part.)X
+3540(Ninety)X
+3782(percent)X
+4043(of)X
+4134(these)X
+555 5285(connections)N
+960(are)X
+1081(to)X
+1165(nearby)X
+1406(parts)X
+1584(\(those)X
+1802(with)X
+1966(nearby)X
+2 f
+2207(ids)X
+1 f
+2300(\))X
+2348(to)X
+2431(model)X
+2652(the)X
+2771(spatial)X
+3001(locality)X
+3262(often)X
+3448(exhibited)X
+3767(in)X
+3850(CAD)X
+4040(applica-)X
+555 5375(tions.)N
+779(Ten)X
+933(percent)X
+1198(of)X
+1293(the)X
+1419(connections)X
+1830(are)X
+1957(randomly)X
+2292(distributed)X
+2662(among)X
+2908(all)X
+3016(other)X
+3209(parts)X
+3393(in)X
+3483(the)X
+3609(database.)X
+3954(Every)X
+4174(part)X
+555 5465(appears)N
+829(exactly)X
+1089(three)X
+1278(times)X
+1479(in)X
+1569(the)X
+2 f
+1695(from)X
+1 f
+1874(\256eld)X
+2043(of)X
+2137(a)X
+2200(connection)X
+2579(record,)X
+2832(and)X
+2975(zero)X
+3141(or)X
+3235(more)X
+3427(times)X
+3627(in)X
+3716(the)X
+2 f
+3841(to)X
+1 f
+3930(\256eld.)X
+4139(Parts)X
+555 5555(have)N
+2 f
+727(x)X
+1 f
+783(and)X
+2 f
+919(y)X
+1 f
+975(locations)X
+1284(set)X
+1393(randomly)X
+1720(in)X
+1802(an)X
+1898(appropriate)X
+2284(range.)X
+
+14 p
+%%Page: 14 14
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+755 630(The)N
+900(intent)X
+1102(of)X
+1189(OO1)X
+1365(is)X
+1438(to)X
+1520(measure)X
+1808(the)X
+1926(overall)X
+2169(cost)X
+2318(of)X
+2405(a)X
+2461(query)X
+2664(mix)X
+2808(characteristic)X
+3257(of)X
+3344(engineering)X
+3743(database)X
+4040(applica-)X
+555 720(tions.)N
+770(There)X
+978(are)X
+1097(three)X
+1278(tests:)X
+10 f
+635 843(g)N
+2 f
+755(Lookup)X
+1 f
+1022(generates)X
+1353(1,000)X
+1560(random)X
+1832(part)X
+2 f
+1984(ids)X
+1 f
+2077(,)X
+2124(fetches)X
+2378(the)X
+2502(corresponding)X
+2987(parts)X
+3169(from)X
+3351(the)X
+3475(database,)X
+3798(and)X
+3940(calls)X
+4113(a)X
+4175(null)X
+755 933(procedure)N
+1097(in)X
+1179(the)X
+1297(host)X
+1450(programming)X
+1906(language)X
+2216(with)X
+2378(the)X
+2496(parts')X
+2 f
+2699(x)X
+1 f
+2755(and)X
+2 f
+2891(y)X
+1 f
+2947(positions.)X
+10 f
+635 1056(g)N
+2 f
+755(Traverse)X
+1 f
+1067(retrieves)X
+1371(a)X
+1434(random)X
+1706(part)X
+1858(from)X
+2041(the)X
+2166(database)X
+2470(and)X
+2613(follows)X
+2880(connections)X
+3290(from)X
+3473(it)X
+3544(to)X
+3632(other)X
+3823(parts.)X
+4045(Each)X
+4232(of)X
+755 1146(those)N
+947(parts)X
+1126(is)X
+1202(retrieved,)X
+1531(and)X
+1670(all)X
+1773(connections)X
+2179(from)X
+2358(it)X
+2424(followed.)X
+2771(This)X
+2935(procedure)X
+3279(is)X
+3354(repeated)X
+3649(depth-\256rst)X
+4000(for)X
+4116(seven)X
+755 1236(hops)N
+930(from)X
+1110(the)X
+1232(original)X
+1505(part,)X
+1674(for)X
+1792(a)X
+1852(total)X
+2018(of)X
+2109(3280)X
+2293(parts.)X
+2513(Backward)X
+2862(traversal)X
+3162(also)X
+3314(exists,)X
+3539(and)X
+3678(follows)X
+3941(all)X
+4044(connec-)X
+755 1326(tions)N
+930(into)X
+1074(a)X
+1130(given)X
+1328(part)X
+1473(to)X
+1555(their)X
+1722(origin.)X
+10 f
+635 1449(g)N
+2 f
+755(Insert)X
+1 f
+962(adds)X
+1129(100)X
+1269(new)X
+1423(parts)X
+1599(and)X
+1735(their)X
+1902(connections.)X
+755 1572(The)N
+913(benchmark)X
+1303(is)X
+1389(single-user,)X
+1794(but)X
+1929(multi-user)X
+2291(access)X
+2530(controls)X
+2821(\(locking)X
+3120(and)X
+3268(transaction)X
+3652(protection\))X
+4036(must)X
+4223(be)X
+555 1662(enforced.)N
+898(It)X
+968(is)X
+1042(designed)X
+1348(to)X
+1431(be)X
+1528(run)X
+1656(on)X
+1757(a)X
+1814(database)X
+2112(with)X
+2275(20,000)X
+2516(parts,)X
+2713(and)X
+2850(on)X
+2951(one)X
+3087(with)X
+3249(200,000)X
+3529(parts.)X
+3745(Because)X
+4033(we)X
+4147(have)X
+555 1752(insuf\256cient)N
+935(disk)X
+1088(space)X
+1287(for)X
+1401(the)X
+1519(larger)X
+1727(database,)X
+2044(we)X
+2158(report)X
+2370(results)X
+2599(only)X
+2761(for)X
+2875(the)X
+2993(20,000)X
+3233(part)X
+3378(database.)X
+3 f
+555 1938(5.2.1.)N
+775(Implementation)X
+1 f
+755 2061(The)N
+920(LIBTP)X
+1182(implementation)X
+1724(of)X
+1831(OO1)X
+2027(uses)X
+2205(the)X
+2342(TCL)X
+2532([OUST90])X
+2914(interface)X
+3235(described)X
+3582(earlier.)X
+3867(The)X
+4031(backend)X
+555 2151(accepts)N
+813(commands)X
+1181(over)X
+1345(an)X
+1442(IP)X
+1534(socket)X
+1760(and)X
+1897(performs)X
+2208(the)X
+2327(requested)X
+2656(database)X
+2954(actions.)X
+3242(The)X
+3387(frontend)X
+3679(opens)X
+3886(and)X
+4022(executes)X
+555 2241(a)N
+618(TCL)X
+796(script.)X
+1041(This)X
+1210(script)X
+1415(contains)X
+1709(database)X
+2013(accesses)X
+2313(interleaved)X
+2697(with)X
+2866(ordinary)X
+3165(program)X
+3463(control)X
+3716(statements.)X
+4120(Data-)X
+555 2331(base)N
+718(commands)X
+1085(are)X
+1204(submitted)X
+1539(to)X
+1621(the)X
+1739(backend)X
+2027(and)X
+2163(results)X
+2392(are)X
+2511(bound)X
+2731(to)X
+2813(program)X
+3105(variables.)X
+755 2454(The)N
+903(parts)X
+1082(table)X
+1261(was)X
+1409(stored)X
+1628(as)X
+1718(a)X
+1776(B-tree)X
+1999(indexed)X
+2275(by)X
+2 f
+2377(id)X
+1 f
+2439(.)X
+2501(The)X
+2648(connection)X
+3022(table)X
+3200(was)X
+3347(stored)X
+3565(as)X
+3654(a)X
+3712(set)X
+3823(of)X
+3912(\256xed-length)X
+555 2544(records)N
+824(using)X
+1029(the)X
+1159(4.4BSD)X
+1446(recno)X
+1657(access)X
+1895(method.)X
+2207(In)X
+2306(addition,)X
+2620(two)X
+2771(B-tree)X
+3003(indices)X
+3261(were)X
+3449(maintained)X
+3836(on)X
+3947(connection)X
+555 2634(table)N
+732(entries.)X
+1007(One)X
+1162(index)X
+1360(mapped)X
+1634(the)X
+2 f
+1752(from)X
+1 f
+1923(\256eld)X
+2085(to)X
+2167(a)X
+2223(connection)X
+2595(record)X
+2821(number,)X
+3106(and)X
+3242(the)X
+3360(other)X
+3545(mapped)X
+3819(the)X
+2 f
+3937(to)X
+1 f
+4019(\256eld)X
+4181(to)X
+4263(a)X
+555 2724(connection)N
+932(record)X
+1163(number.)X
+1473(These)X
+1690(indices)X
+1941(support)X
+2205(fast)X
+2345(lookups)X
+2622(on)X
+2726(connections)X
+3133(in)X
+3219(both)X
+3385(directions.)X
+3765(For)X
+3900(the)X
+4022(traversal)X
+555 2814(tests,)N
+743(the)X
+867(frontend)X
+1165(does)X
+1338(an)X
+1439(index)X
+1642(lookup)X
+1889(to)X
+1976(discover)X
+2273(the)X
+2396(connected)X
+2747(part's)X
+2 f
+2955(id)X
+1 f
+3017(,)X
+3062(and)X
+3203(then)X
+3366(does)X
+3538(another)X
+3804(lookup)X
+4051(to)X
+4138(fetch)X
+555 2904(the)N
+673(part)X
+818(itself.)X
+3 f
+555 3090(5.2.2.)N
+775(Performance)X
+1242(Measurements)X
+1766(for)X
+1889(OO1)X
+1 f
+755 3213(We)N
+888(compare)X
+1186(LIBTP's)X
+1487(OO1)X
+1664(performance)X
+2092(to)X
+2174(that)X
+2314(reported)X
+2602(in)X
+2684([CATT91].)X
+3087(Those)X
+3303(results)X
+3532(were)X
+3709(collected)X
+4019(on)X
+4119(a)X
+4175(Sun)X
+555 3303(3/280)N
+759(\(25)X
+888(MHz)X
+1075(MC68020\))X
+1448(with)X
+1612(16)X
+1714(MBytes)X
+1989(of)X
+2078(memory)X
+2367(and)X
+2505(two)X
+2647(Hitachi)X
+2904(892MByte)X
+3267(disks)X
+3452(\(15)X
+3580(ms)X
+3694(average)X
+3966(seek)X
+4130(time\))X
+555 3393(behind)N
+793(an)X
+889(SMD-4)X
+1149(controller.)X
+1521(Frontends)X
+1861(ran)X
+1984(on)X
+2084(an)X
+2180(8MByte)X
+2462(Sun)X
+2606(3/260.)X
+755 3516(In)N
+844(order)X
+1036(to)X
+1120(measure)X
+1410(performance)X
+1839(on)X
+1941(a)X
+1999(machine)X
+2293(of)X
+2382(roughly)X
+2653(equivalent)X
+3009(processor)X
+3339(power,)X
+3582(we)X
+3698(ran)X
+3822(one)X
+3959(set)X
+4069(of)X
+4157(tests)X
+555 3606(on)N
+666(a)X
+733(standalone)X
+1107(MC68030-based)X
+1671(HP300)X
+1923(\(33MHz)X
+2225(MC68030\).)X
+2646(The)X
+2801(database)X
+3108(was)X
+3263(stored)X
+3489(on)X
+3599(a)X
+3665(300MByte)X
+4037(HP7959)X
+555 3696(SCSI)N
+744(disk)X
+898(\(17)X
+1026(ms)X
+1139(average)X
+1410(seek)X
+1573(time\).)X
+1802(Since)X
+2000(this)X
+2135(machine)X
+2427(is)X
+2500(not)X
+2622(connected)X
+2968(to)X
+3050(a)X
+3106(network,)X
+3409(we)X
+3523(ran)X
+3646(local)X
+3822(tests)X
+3984(where)X
+4201(the)X
+555 3786(frontend)N
+855(and)X
+999(backend)X
+1295(run)X
+1430(on)X
+1538(the)X
+1664(same)X
+1856(machine.)X
+2195(We)X
+2334(compare)X
+2638(these)X
+2830(measurements)X
+3316(with)X
+3485(Cattell's)X
+3783(local)X
+3966(Sun)X
+4117(3/280)X
+555 3876(numbers.)N
+755 3999(Because)N
+1051(the)X
+1177(benchmark)X
+1562(requires)X
+1849(remote)X
+2100(access,)X
+2354(we)X
+2476(ran)X
+2607(another)X
+2876(set)X
+2993(of)X
+3088(tests)X
+3258(on)X
+3365(a)X
+3428(DECstation)X
+3828(5000/200)X
+4157(with)X
+555 4089(32M)N
+732(of)X
+825(memory)X
+1118(running)X
+1393(Ultrix)X
+1610(V4.0)X
+1794(and)X
+1936(a)X
+1998(DEC)X
+2184(1GByte)X
+2459(RZ57)X
+2666(SCSI)X
+2859(disk.)X
+3057(We)X
+3194(compare)X
+3496(the)X
+3619(local)X
+3800(performance)X
+4232(of)X
+555 4179(OO1)N
+734(on)X
+837(the)X
+958(DECstation)X
+1354(to)X
+1439(its)X
+1536(remote)X
+1781(performance.)X
+2250(For)X
+2383(the)X
+2503(remote)X
+2748(case,)X
+2929(we)X
+3045(ran)X
+3170(the)X
+3290(frontend)X
+3584(on)X
+3686(a)X
+3744(DECstation)X
+4139(3100)X
+555 4269(with)N
+717(16)X
+817(MBytes)X
+1090(of)X
+1177(main)X
+1357(memory.)X
+755 4392(The)N
+900(databases)X
+1228(tested)X
+1435(in)X
+1517([CATT91])X
+1880(are)X
+10 f
+635 4515(g)N
+1 f
+755(INDEX,)X
+1045(a)X
+1101(highly-optimized)X
+1672(access)X
+1898(method)X
+2158(package)X
+2442(developed)X
+2792(at)X
+2870(Sun)X
+3014(Microsystems.)X
+10 f
+635 4638(g)N
+1 f
+755(OODBMS,)X
+1137(a)X
+1193(beta)X
+1347(release)X
+1591(of)X
+1678(a)X
+1734(commercial)X
+2133(object-oriented)X
+2639(database)X
+2936(management)X
+3366(system.)X
+10 f
+635 4761(g)N
+1 f
+755(RDBMS,)X
+1076(a)X
+1133(UNIX-based)X
+1565(commercial)X
+1965(relational)X
+2289(data)X
+2444(manager)X
+2742(at)X
+2821(production)X
+3189(release.)X
+3474(The)X
+3620(OO1)X
+3797(implementation)X
+755 4851(used)N
+922(embedded)X
+1272(SQL)X
+1443(in)X
+1525(C.)X
+1638(Stored)X
+1867(procedures)X
+2240(were)X
+2417(de\256ned)X
+2673(to)X
+2755(reduce)X
+2990(client-server)X
+3412(traf\256c.)X
+755 4974(Table)N
+974(two)X
+1130(shows)X
+1366(the)X
+1500(measurements)X
+1995(from)X
+2187([CATT91])X
+2566(and)X
+2718(LIBTP)X
+2976(for)X
+3106(a)X
+3178(local)X
+3370(test)X
+3517(on)X
+3632(the)X
+3765(MC680x0-based)X
+555 5064(hardware.)N
+915(All)X
+1037(caches)X
+1272(are)X
+1391(cleared)X
+1644(before)X
+1870(each)X
+2038(test.)X
+2209(All)X
+2331(times)X
+2524(are)X
+2643(in)X
+2725(seconds.)X
+755 5187(Table)N
+960(two)X
+1102(shows)X
+1324(that)X
+1466(LIBTP)X
+1710(outperforms)X
+2123(the)X
+2242(commercial)X
+2642(relational)X
+2966(system,)X
+3229(but)X
+3352(is)X
+3426(slower)X
+3661(than)X
+3820(OODBMS)X
+4183(and)X
+555 5277(INDEX.)N
+872(Since)X
+1077(the)X
+1202(caches)X
+1444(were)X
+1628(cleared)X
+1888(at)X
+1973(the)X
+2098(start)X
+2263(of)X
+2356(each)X
+2530(test,)X
+2687(disk)X
+2846(throughput)X
+3223(is)X
+3302(critical)X
+3551(in)X
+3639(this)X
+3780(test.)X
+3957(The)X
+4108(single)X
+555 5367(SCSI)N
+749(HP)X
+877(drive)X
+1068(used)X
+1241(by)X
+1347(LIBTP)X
+1595(is)X
+1674(approximately)X
+2163(13%)X
+2336(slower)X
+2576(than)X
+2739(the)X
+2862(disks)X
+3051(used)X
+3223(in)X
+3310([CATT91])X
+3678(which)X
+3899(accounts)X
+4205(for)X
+555 5457(part)N
+700(of)X
+787(the)X
+905(difference.)X
+755 5580(OODBMS)N
+1118(and)X
+1255(INDEX)X
+1525(outperform)X
+1906(LIBTP)X
+2148(most)X
+2323(dramatically)X
+2744(on)X
+2844(traversal.)X
+3181(This)X
+3343(is)X
+3416(because)X
+3691(we)X
+3805(use)X
+3932(index)X
+4130(look-)X
+555 5670(ups)N
+689(to)X
+774(\256nd)X
+921(connections,)X
+1347(whereas)X
+1634(the)X
+1755(other)X
+1942(two)X
+2084(systems)X
+2359(use)X
+2488(a)X
+2546(link)X
+2692(access)X
+2920(method.)X
+3222(The)X
+3369(index)X
+3569(requires)X
+3850(us)X
+3943(to)X
+4027(examine)X
+
+15 p
+%%Page: 15 15
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+10 f
+555 679(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N
+2 f
+606 769(Measure)N
+1 f
+1019(INDEX)X
+1389(OODBMS)X
+1851(RDBMS)X
+2250(LIBTP)X
+10 f
+555 771(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N
+555 787(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N
+1 f
+595 869(Lookup)N
+1114(5.4)X
+1490(12.9)X
+1950(27)X
+2291(27.2)X
+595 959(Traversal)N
+1074(13)X
+1530(9.8)X
+1950(90)X
+2291(47.3)X
+595 1049(Insert)N
+1114(7.4)X
+1530(1.5)X
+1950(22)X
+2331(9.7)X
+10 f
+555 1059(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)N
+555(c)X
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+959 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+1329 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+1791 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+2190 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+2512 1059(c)N
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+2618 679(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2 f
+2829 769(Measure)N
+3401(Cache)X
+3726(Local)X
+4028(Remote)X
+1 f
+10 f
+2618 771(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2618 787(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2658 869(Lookup)N
+3401(cold)X
+3747(15.7)X
+4078(20.6)X
+3401 959(warm)N
+3787(7.8)X
+4078(12.4)X
+10 f
+2618 969(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2658 1059(Forward)N
+2950(traversal)X
+3401(cold)X
+3747(28.4)X
+4078(52.6)X
+3401 1149(warm)N
+3747(23.5)X
+4078(47.4)X
+10 f
+2618 1159(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2658 1249(Backward)N
+3004(traversal)X
+3401(cold)X
+3747(24.2)X
+4078(47.4)X
+3401 1339(warm)N
+3747(24.3)X
+4078(47.6)X
+10 f
+2618 1349(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+1 f
+2658 1439(Insert)N
+3401(cold)X
+3787(7.5)X
+4078(10.3)X
+3401 1529(warm)N
+3787(6.7)X
+4078(10.9)X
+10 f
+2618 1539(i)N
+2629(iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii)X
+2618(c)X
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+3341 1539(c)N
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+3666 1539(c)N
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+3968 1539(c)N
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+4309 1539(c)N
+1479(c)Y
+1399(c)Y
+1319(c)Y
+1239(c)Y
+1159(c)Y
+1079(c)Y
+999(c)Y
+919(c)Y
+839(c)Y
+759(c)Y
+3 f
+587 1785(Table)N
+823(2:)X
+931(Local)X
+1163(MC680x0)X
+1538(Performance)X
+2026(of)X
+2133(Several)X
+587 1875(Systems)N
+883(on)X
+987(OO1.)X
+2667 1785(Table)N
+2909(3:)X
+3023(Local)X
+3260(vs.)X
+3397(Remote)X
+3707(Performance)X
+4200(of)X
+2667 1875(LIBTP)N
+2926(on)X
+3030(OO1.)X
+1 f
+10 f
+555 1998(h)N
+579(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)X
+1 f
+555 2274(two)N
+696(disk)X
+850(pages,)X
+1074(but)X
+1197(the)X
+1316(links)X
+1492(require)X
+1741(only)X
+1904(one,)X
+2061(regardless)X
+2408(of)X
+2496(database)X
+2794(size.)X
+2980(Cattell)X
+3214(reports)X
+3458(that)X
+3599(lookups)X
+3873(using)X
+4067(B-trees)X
+555 2364(instead)N
+808(of)X
+901(links)X
+1082(makes)X
+1313(traversal)X
+1616(take)X
+1776(twice)X
+1976(as)X
+2069(long)X
+2237(in)X
+2325(INDEX.)X
+2641(Adding)X
+2907(a)X
+2969(link)X
+3119(access)X
+3351(method)X
+3617(to)X
+3 f
+3704(db)X
+1 f
+3792(\(3\))X
+3911(or)X
+4003(using)X
+4201(the)X
+555 2454(existing)N
+828(hash)X
+995(method)X
+1255(would)X
+1475(apparently)X
+1834(be)X
+1930(a)X
+1986(good)X
+2166(idea.)X
+755 2577(Both)N
+936(OODBMS)X
+1304(and)X
+1446(INDEX)X
+1722(issue)X
+1908 0.1944(coarser-granularity)AX
+2545(locks)X
+2739(than)X
+2902(LIBTP.)X
+3189(This)X
+3356(limits)X
+3562(concurrency)X
+3985(for)X
+4104(multi-)X
+555 2667(user)N
+711(applications,)X
+1140(but)X
+1264(helps)X
+1455(single-user)X
+1829(applications.)X
+2278(In)X
+2367(addition,)X
+2671(the)X
+2791(fact)X
+2934(that)X
+3076(LIBTP)X
+3319(releases)X
+3595(B-tree)X
+3817(locks)X
+4007(early)X
+4189(is)X
+4263(a)X
+555 2757(drawback)N
+896(in)X
+986(OO1.)X
+1210(Since)X
+1416(there)X
+1605(is)X
+1686(no)X
+1793(concurrency)X
+2218(in)X
+2307(the)X
+2432(benchmark,)X
+2836(high-concurrency)X
+3430(strategies)X
+3760(only)X
+3929(show)X
+4125(up)X
+4232(as)X
+555 2847(increased)N
+882(locking)X
+1145(overhead.)X
+1503(Finally,)X
+1772(the)X
+1892(architecture)X
+2294(of)X
+2383(the)X
+2503(LIBTP)X
+2747(implementation)X
+3271(was)X
+3418(substantially)X
+3844(different)X
+4143(from)X
+555 2937(that)N
+702(of)X
+796(either)X
+1006(OODBMS)X
+1375(or)X
+1469(INDEX.)X
+1786(Both)X
+1968(of)X
+2062(those)X
+2258(systems)X
+2538(do)X
+2645(the)X
+2770(searches)X
+3070(in)X
+3159(the)X
+3284(user's)X
+3503(address)X
+3771(space,)X
+3997(and)X
+4139(issue)X
+555 3027(requests)N
+844(for)X
+964(pages)X
+1173(to)X
+1260(the)X
+1383(server)X
+1605(process.)X
+1911(Pages)X
+2123(are)X
+2247(cached)X
+2496(in)X
+2583(the)X
+2706(client,)X
+2929(and)X
+3070(many)X
+3273(queries)X
+3530(can)X
+3667(be)X
+3768(satis\256ed)X
+4055(without)X
+555 3117(contacting)N
+910(the)X
+1029(server)X
+1247(at)X
+1326(all.)X
+1467(LIBTP)X
+1710(submits)X
+1979(all)X
+2080(the)X
+2199(queries)X
+2452(to)X
+2535(the)X
+2653(server)X
+2870(process,)X
+3151(and)X
+3287(receives)X
+3571(database)X
+3868(records)X
+4125(back;)X
+555 3207(it)N
+619(does)X
+786(no)X
+886(client)X
+1084(caching.)X
+755 3330(The)N
+911(RDBMS)X
+1221(architecture)X
+1632(is)X
+1716(much)X
+1925(closer)X
+2148(to)X
+2241(that)X
+2392(of)X
+2490(LIBTP.)X
+2783(A)X
+2872(server)X
+3100(process)X
+3372(receives)X
+3667(queries)X
+3930(and)X
+4076(returns)X
+555 3420(results)N
+786(to)X
+870(a)X
+928(client.)X
+1168(The)X
+1315(timing)X
+1545(results)X
+1776(in)X
+1860(table)X
+2038(two)X
+2180(clearly)X
+2421(show)X
+2612(that)X
+2754(the)X
+2874(conventional)X
+3309(database)X
+3607(client/server)X
+4025(model)X
+4246(is)X
+555 3510(expensive.)N
+941(LIBTP)X
+1188(outperforms)X
+1605(the)X
+1728(RDBMS)X
+2032(on)X
+2136(traversal)X
+2437(and)X
+2577(insertion.)X
+2921(We)X
+3057(speculate)X
+3380(that)X
+3524(this)X
+3663(is)X
+3740(due)X
+3880(in)X
+3966(part)X
+4115(to)X
+4201(the)X
+555 3600(overhead)N
+870(of)X
+957(query)X
+1160(parsing,)X
+1436(optimization,)X
+1880(and)X
+2016(repeated)X
+2309(interpretation)X
+2761(of)X
+2848(the)X
+2966(plan)X
+3124(tree)X
+3265(in)X
+3347(the)X
+3465(RDBMS')X
+3791(query)X
+3994(executor.)X
+755 3723(Table)N
+962(three)X
+1147(shows)X
+1371(the)X
+1492(differences)X
+1873(between)X
+2164(local)X
+2343(and)X
+2482(remote)X
+2728(execution)X
+3063(of)X
+3153(LIBTP's)X
+3456(OO1)X
+3635(implementation)X
+4160(on)X
+4263(a)X
+555 3813(DECstation.)N
+989(We)X
+1122(measured)X
+1451(performance)X
+1879(with)X
+2042(a)X
+2099(populated)X
+2436(\(warm\))X
+2694(cache)X
+2899(and)X
+3036(an)X
+3133(empty)X
+3354(\(cold\))X
+3567(cache.)X
+3812(Reported)X
+4126(times)X
+555 3903(are)N
+681(the)X
+806(means)X
+1037(of)X
+1130(twenty)X
+1374(tests,)X
+1562(and)X
+1704(are)X
+1829(in)X
+1917(seconds.)X
+2237(Standard)X
+2548(deviations)X
+2903(were)X
+3086(within)X
+3316(seven)X
+3525(percent)X
+3788(of)X
+3881(the)X
+4005(mean)X
+4205(for)X
+555 3993(remote,)N
+818(and)X
+954(two)X
+1094(percent)X
+1351(of)X
+1438(the)X
+1556(mean)X
+1750(for)X
+1864(local.)X
+755 4116(The)N
+914(20ms)X
+1121(overhead)X
+1450(of)X
+1551(TCP/IP)X
+1824(on)X
+1938(an)X
+2048(Ethernet)X
+2354(entirely)X
+2633(accounts)X
+2948(for)X
+3076(the)X
+3207(difference)X
+3567(in)X
+3662(speed.)X
+3918(The)X
+4076(remote)X
+555 4206(traversal)N
+857(times)X
+1055(are)X
+1179(nearly)X
+1405(double)X
+1648(the)X
+1771(local)X
+1952(times)X
+2150(because)X
+2430(we)X
+2549(do)X
+2653(index)X
+2855(lookups)X
+3132(and)X
+3272(part)X
+3421(fetches)X
+3673(in)X
+3759(separate)X
+4047(queries.)X
+555 4296(It)N
+629(would)X
+854(make)X
+1053(sense)X
+1252(to)X
+1339(do)X
+1444(indexed)X
+1723(searches)X
+2021(on)X
+2126(the)X
+2248(server,)X
+2489(but)X
+2615(we)X
+2733(were)X
+2914(unwilling)X
+3244(to)X
+3330(hard-code)X
+3676(knowledge)X
+4052(of)X
+4143(OO1)X
+555 4386(indices)N
+803(into)X
+948(our)X
+1075(LIBTP)X
+1317(TCL)X
+1488(server.)X
+1745(Cold)X
+1920(and)X
+2056(warm)X
+2259(insertion)X
+2559(times)X
+2752(are)X
+2871(identical)X
+3167(since)X
+3352(insertions)X
+3683(do)X
+3783(not)X
+3905(bene\256t)X
+4143(from)X
+555 4476(caching.)N
+755 4599(One)N
+915(interesting)X
+1279(difference)X
+1632(shown)X
+1867(by)X
+1973(table)X
+2155(three)X
+2342(is)X
+2421(the)X
+2545(cost)X
+2700(of)X
+2793(forward)X
+3074(versus)X
+3305(backward)X
+3644(traversal.)X
+3987(When)X
+4205(we)X
+555 4689(built)N
+725(the)X
+847(database,)X
+1168(we)X
+1285(inserted)X
+1562(parts)X
+1741(in)X
+1826(part)X
+2 f
+1974(id)X
+1 f
+2059(order.)X
+2292(We)X
+2427(built)X
+2596(the)X
+2717(indices)X
+2967(at)X
+3048(the)X
+3169(same)X
+3357(time.)X
+3562(Therefore,)X
+3923(the)X
+4044(forward)X
+555 4779(index)N
+757(had)X
+897(keys)X
+1068(inserted)X
+1346(in)X
+1432(order,)X
+1646(while)X
+1848(the)X
+1970(backward)X
+2307(index)X
+2509(had)X
+2649(keys)X
+2820(inserted)X
+3098(more)X
+3286(randomly.)X
+3656(In-order)X
+3943(insertion)X
+4246(is)X
+555 4885(pessimal)N
+858(for)X
+975(B-tree)X
+1199(indices,)X
+1469(so)X
+1563(the)X
+1684(forward)X
+1962(index)X
+2163(is)X
+2239(much)X
+2440(larger)X
+2651(than)X
+2812(the)X
+2933(backward)X
+3269(one)X
+7 s
+3385 4853(5)N
+10 s
+4885(.)Y
+3476(This)X
+3640(larger)X
+3850(size)X
+3997(shows)X
+4219(up)X
+555 4975(as)N
+642(extra)X
+823(disk)X
+976(reads)X
+1166(in)X
+1248(the)X
+1366(cold)X
+1524(benchmark.)X
+3 f
+555 5161(6.)N
+655(Conclusions)X
+1 f
+755 5284(LIBTP)N
+1006(provides)X
+1311(the)X
+1438(basic)X
+1632(building)X
+1927(blocks)X
+2165(to)X
+2256(support)X
+2525(transaction)X
+2906(protection.)X
+3300(In)X
+3396(comparison)X
+3799(with)X
+3970(traditional)X
+555 5374(Unix)N
+746(libraries)X
+1040(and)X
+1187(commercial)X
+1597(systems,)X
+1900(it)X
+1974(offers)X
+2192(a)X
+2258(variety)X
+2511(of)X
+2608(tradeoffs.)X
+2964(Using)X
+3185(complete)X
+3509(transaction)X
+3891(protection)X
+4246(is)X
+555 5464(more)N
+747(complicated)X
+1166(than)X
+1331(simply)X
+1575(adding)X
+3 f
+1820(fsync)X
+1 f
+1998(\(2\))X
+2119(and)X
+3 f
+2262(\257ock)X
+1 f
+2426(\(2\))X
+2547(calls)X
+2721(to)X
+2810(code,)X
+3008(but)X
+3136(it)X
+3206(is)X
+3285(faster)X
+3490(in)X
+3578(some)X
+3773(cases)X
+3969(and)X
+4111(offers)X
+8 s
+10 f
+555 5536(hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh)N
+5 s
+1 f
+727 5614(5)N
+8 s
+763 5639(The)N
+878(next)X
+1004(release)X
+1196(of)X
+1265(the)X
+1359(4.4BSD)X
+1580(access)X
+1758(method)X
+1966(will)X
+2082(automatically)X
+2446(detect)X
+2614(and)X
+2722(compensate)X
+3039(for)X
+3129(in-order)X
+3350(insertion,)X
+3606(eliminating)X
+3914(this)X
+4023(problem.)X
+
+16 p
+%%Page: 16 16
+8 s 8 xH 0 xS 1 f
+10 s
+3 f
+1 f
+555 630(stricter)N
+801(guarantees)X
+1168(\(atomicity,)X
+1540(consistency,)X
+1957(isolation,)X
+2275(and)X
+2414(durability\).)X
+2815(If)X
+2892(the)X
+3013(data)X
+3170(to)X
+3255(be)X
+3354(protected)X
+3676(are)X
+3798(already)X
+4058(format-)X
+555 720(ted)N
+675(\()X
+2 f
+702(i.e.)X
+1 f
+821(use)X
+949(one)X
+1086(of)X
+1174(the)X
+1293(database)X
+1591(access)X
+1818(methods\),)X
+2157(then)X
+2316(adding)X
+2555(transaction)X
+2928(protection)X
+3274(requires)X
+3554(no)X
+3655(additional)X
+3996(complex-)X
+555 810(ity,)N
+679(but)X
+801(incurs)X
+1017(a)X
+1073(performance)X
+1500(penalty)X
+1756(of)X
+1843(approximately)X
+2326(15%.)X
+755 933(In)N
+844(comparison)X
+1240(with)X
+1404(commercial)X
+1805(database)X
+2104(systems,)X
+2399(the)X
+2519(tradeoffs)X
+2827(are)X
+2948(more)X
+3135(complex.)X
+3473(LIBTP)X
+3717(does)X
+3886(not)X
+4009(currently)X
+555 1023(support)N
+825(a)X
+891(standard)X
+1193(query)X
+1406(language.)X
+1766(The)X
+1921(TCL-based)X
+2312(server)X
+2539(process)X
+2810(allows)X
+3049(a)X
+3115(certain)X
+3364(ease)X
+3533(of)X
+3630(use)X
+3767(which)X
+3993(would)X
+4223(be)X
+555 1113(enhanced)N
+882(with)X
+1047(a)X
+1106(more)X
+1294(user-friendly)X
+1732(interface)X
+2037(\()X
+2 f
+2064(e.g.)X
+1 f
+2203(a)X
+2261(windows)X
+2572(based)X
+2777(query-by-form)X
+3272(application\),)X
+3697(for)X
+3813(which)X
+4031(we)X
+4147(have)X
+555 1203(a)N
+620(working)X
+916(prototype.)X
+1292(When)X
+1513(accesses)X
+1815(do)X
+1924(not)X
+2055(require)X
+2312(sophisticated)X
+2758(query)X
+2969(processing,)X
+3360(the)X
+3486(TCL)X
+3665(interface)X
+3975(is)X
+4056(an)X
+4160(ade-)X
+555 1293(quate)N
+756(solution.)X
+1080(What)X
+1281(LIBTP)X
+1529(fails)X
+1693(to)X
+1781(provide)X
+2052(in)X
+2140(functionality,)X
+2595(it)X
+2665(makes)X
+2896(up)X
+3002(for)X
+3122(in)X
+3210(performance)X
+3643(and)X
+3785(\257exibility.)X
+4161(Any)X
+555 1383(application)N
+931(may)X
+1089(make)X
+1283(use)X
+1410(of)X
+1497(its)X
+1592(record)X
+1818(interface)X
+2120(or)X
+2207(the)X
+2325(more)X
+2510(primitive)X
+2823(log,)X
+2965(lock,)X
+3143(and)X
+3279(buffer)X
+3496(calls.)X
+755 1506(Future)N
+987(work)X
+1175(will)X
+1322(focus)X
+1519(on)X
+1621(overcoming)X
+2026(some)X
+2217(of)X
+2306(the)X
+2426(areas)X
+2614(in)X
+2698(which)X
+2916(LIBTP)X
+3160(is)X
+3235(currently)X
+3547(de\256cient)X
+3845(and)X
+3983(extending)X
+555 1596(its)N
+652(transaction)X
+1026(model.)X
+1288(The)X
+1435(addition)X
+1719(of)X
+1808(an)X
+1905(SQL)X
+2077(parser)X
+2295(and)X
+2432(forms)X
+2640(front)X
+2817(end)X
+2954(will)X
+3099(improve)X
+3387(the)X
+3506(system's)X
+3807(ease)X
+3967(of)X
+4055(use)X
+4183(and)X
+555 1686(make)N
+750(it)X
+815(more)X
+1001(competitive)X
+1400(with)X
+1563(commercial)X
+1963(systems.)X
+2277(In)X
+2365(the)X
+2484(long)X
+2647(term,)X
+2835(we)X
+2950(would)X
+3170(like)X
+3310(to)X
+3392(add)X
+3528(generalized)X
+3919(hierarchical)X
+555 1776(locking,)N
+836(nested)X
+1062(transactions,)X
+1486(parallel)X
+1748(transactions,)X
+2171(passing)X
+2431(of)X
+2518(transactions)X
+2921(between)X
+3209(processes,)X
+3557(and)X
+3693(distributed)X
+4055(commit)X
+555 1866(handling.)N
+900(In)X
+992(the)X
+1115(short)X
+1300(term,)X
+1492(the)X
+1614(next)X
+1776(step)X
+1929(is)X
+2006(to)X
+2092(integrate)X
+2397(LIBTP)X
+2643(with)X
+2809(the)X
+2931(most)X
+3110(recent)X
+3331(release)X
+3579(of)X
+3670(the)X
+3792(database)X
+4093(access)X
+555 1956(routines)N
+833(and)X
+969(make)X
+1163(it)X
+1227(freely)X
+1435(available)X
+1745(via)X
+1863(anonymous)X
+2252(ftp.)X
+3 f
+555 2142(7.)N
+655(Acknowledgements)X
+1 f
+755 2265(We)N
+888(would)X
+1109(like)X
+1250(to)X
+1332(thank)X
+1530(John)X
+1701(Wilkes)X
+1948(and)X
+2084(Carl)X
+2242(Staelin)X
+2484(of)X
+2571(Hewlett-Packard)X
+3131(Laboratories)X
+3557(and)X
+3693(Jon)X
+3824(Krueger.)X
+4148(John)X
+555 2355(and)N
+694(Carl)X
+855(provided)X
+1162(us)X
+1255(with)X
+1419(an)X
+1517(extra)X
+1700(disk)X
+1855(for)X
+1971(the)X
+2091(HP)X
+2215(testbed)X
+2464(less)X
+2606(than)X
+2766(24)X
+2868(hours)X
+3068(after)X
+3238(we)X
+3354(requested)X
+3684(it.)X
+3770(Jon)X
+3903(spent)X
+4094(count-)X
+555 2445(less)N
+699(hours)X
+901(helping)X
+1164(us)X
+1258(understand)X
+1633(the)X
+1754(intricacies)X
+2107(of)X
+2197(commercial)X
+2599(database)X
+2899(products)X
+3198(and)X
+3337(their)X
+3507(behavior)X
+3811(under)X
+4017(a)X
+4076(variety)X
+555 2535(of)N
+642(system)X
+884(con\256gurations.)X
+3 f
+555 2721(8.)N
+655(References)X
+1 f
+555 2901([ANDR89])N
+942(Andrade,)X
+1265(J.,)X
+1361(Carges,)X
+1629(M.,)X
+1765(Kovach,)X
+2060(K.,)X
+2183(``Building)X
+2541(an)X
+2642(On-Line)X
+2939(Transaction)X
+3343(Processing)X
+3715(System)X
+3975(On)X
+4098(UNIX)X
+727 2991(System)N
+982(V'',)X
+2 f
+1134(CommUNIXations)X
+1 f
+1725(,)X
+1765 0.2188(November/December)AX
+2477(1989.)X
+555 3171([BAY77])N
+878(Bayer,)X
+1110(R.,)X
+1223(Schkolnick,)X
+1623(M.,)X
+1754(``Concurrency)X
+2243(of)X
+2330(Operations)X
+2702(on)X
+2802(B-Trees'',)X
+2 f
+3155(Acta)X
+3322(Informatica)X
+1 f
+3700(,)X
+3740(1977.)X
+555 3351([BERN80])N
+936(Bernstein,)X
+1297(P.,)X
+1415(Goodman,)X
+1785(N.,)X
+1917(``Timestamp)X
+2365(Based)X
+2595(Algorithms)X
+2992(for)X
+3119(Concurrency)X
+3567(Control)X
+3844(in)X
+3939(Distributed)X
+727 3441(Database)N
+1042(Systems'',)X
+2 f
+1402(Proceedings)X
+1823(6th)X
+1945(International)X
+2387(Conference)X
+2777(on)X
+2877(Very)X
+3049(Large)X
+3260(Data)X
+3440(Bases)X
+1 f
+3627(,)X
+3667(October)X
+3946(1980.)X
+555 3621([BSD91])N
+864(DB\(3\),)X
+2 f
+1109(4.4BSD)X
+1376(Unix)X
+1552(Programmer's)X
+2044(Manual)X
+2313(Reference)X
+2655(Guide)X
+1 f
+2851(,)X
+2891(University)X
+3249(of)X
+3336(California,)X
+3701(Berkeley,)X
+4031(1991.)X
+555 3801([CATT91])N
+923(Cattell,)X
+1181(R.G.G.,)X
+1455(``An)X
+1632(Engineering)X
+2049(Database)X
+2369(Benchmark'',)X
+2 f
+2838(The)X
+2983(Benchmark)X
+3373(Handbook)X
+3731(for)X
+3848(Database)X
+4179(and)X
+727 3891(Transaction)N
+1133(Processing)X
+1509(Systems)X
+1 f
+1763(,)X
+1803(J.)X
+1874(Gray,)X
+2075(editor,)X
+2302(Morgan)X
+2576(Kaufman)X
+2895(1991.)X
+555 4071([CHEN91])N
+929(Cheng,)X
+1180(E.,)X
+1291(Chang,)X
+1542(E.,)X
+1653(Klein,)X
+1872(J.,)X
+1964(Lee,)X
+2126(D.,)X
+2245(Lu,)X
+2375(E.,)X
+2485(Lutgardo,)X
+2820(A.,)X
+2939(Obermarck,)X
+3342(R.,)X
+3456(``An)X
+3629(Open)X
+3824(and)X
+3961(Extensible)X
+727 4161(Event-Based)N
+1157(Transaction)X
+1556(Manager'',)X
+2 f
+1936(Proceedings)X
+2357(1991)X
+2537(Summer)X
+2820(Usenix)X
+1 f
+3043(,)X
+3083(Nashville,)X
+3430(TN,)X
+3577(June)X
+3744(1991.)X
+555 4341([CHOU85])N
+943(Chou,)X
+1163(H.,)X
+1288(DeWitt,)X
+1570(D.,)X
+1694(``An)X
+1872(Evaluation)X
+2245(of)X
+2338(Buffer)X
+2574(Management)X
+3019(Strategies)X
+3361(for)X
+3481(Relational)X
+3836(Database)X
+4157(Sys-)X
+727 4431(tems'',)N
+2 f
+972(Proceedings)X
+1393(of)X
+1475(the)X
+1593(11th)X
+1755(International)X
+2197(Conference)X
+2587(on)X
+2687(Very)X
+2859(Large)X
+3070(Databases)X
+1 f
+3408(,)X
+3448(1985.)X
+555 4611([DEWI84])N
+925(DeWitt,)X
+1207(D.,)X
+1331(Katz,)X
+1529(R.,)X
+1648(Olken,)X
+1890(F.,)X
+2000(Shapiro,)X
+2295(L.,)X
+2410(Stonebraker,)X
+2843(M.,)X
+2979(Wood,)X
+3220(D.,)X
+3343(``Implementation)X
+3929(Techniques)X
+727 4701(for)N
+841(Main)X
+1030(Memory)X
+1326(Database)X
+1641(Systems'',)X
+2 f
+2001(Proceedings)X
+2422(of)X
+2504(SIGMOD)X
+1 f
+2812(,)X
+2852(pp.)X
+2972(1-8,)X
+3119(June)X
+3286(1984.)X
+555 4881([GRAY76])N
+944(Gray,)X
+1153(J.,)X
+1252(Lorie,)X
+1474(R.,)X
+1595(Putzolu,)X
+1887(F.,)X
+1999(and)X
+2143(Traiger,)X
+2428(I.,)X
+2522(``Granularity)X
+2973(of)X
+3067(locks)X
+3263(and)X
+3406(degrees)X
+3679(of)X
+3773(consistency)X
+4174(in)X
+4263(a)X
+727 4971(large)N
+909(shared)X
+1140(data)X
+1295(base'',)X
+2 f
+1533(Modeling)X
+1861(in)X
+1944(Data)X
+2125(Base)X
+2301(Management)X
+2740(Systems)X
+1 f
+2994(,)X
+3034(Elsevier)X
+3317(North)X
+3524(Holland,)X
+3822(New)X
+3994(York,)X
+4199(pp.)X
+727 5061(365-394.)N
+555 5241([HAER83])N
+931(Haerder,)X
+1235(T.)X
+1348(Reuter,)X
+1606(A.)X
+1728(``Principles)X
+2126(of)X
+2217(Transaction-Oriented)X
+2928(Database)X
+3246(Recovery'',)X
+2 f
+3651(Computing)X
+4029(Surveys)X
+1 f
+4279(,)X
+727 5331(15\(4\);)N
+943(237-318,)X
+1250(1983.)X
+555 5511([KUNG81])N
+943(Kung,)X
+1162(H.)X
+1261(T.,)X
+1371(Richardson,)X
+1777(J.,)X
+1869(``On)X
+2042(Optimistic)X
+2400(Methods)X
+2701(for)X
+2816(Concurrency)X
+3252(Control'',)X
+2 f
+3591(ACM)X
+3781(Transactions)X
+4219(on)X
+727 5601(Database)N
+1054(Systems)X
+1 f
+1328(6\(2\);)X
+1504(213-226,)X
+1811(1981.)X
+
+17 p
+%%Page: 17 17
+10 s 10 xH 0 xS 1 f
+3 f
+1 f
+555 630([LEHM81])N
+939(Lehman,)X
+1245(P.,)X
+1352(Yao,)X
+1529(S.,)X
+1636(``Ef\256cient)X
+1989(Locking)X
+2279(for)X
+2396(Concurrent)X
+2780(Operations)X
+3155(on)X
+3258(B-trees'',)X
+2 f
+3587(ACM)X
+3779(Transactions)X
+4219(on)X
+727 720(Database)N
+1054(Systems)X
+1 f
+1308(,)X
+1348(6\(4\),)X
+1522(December)X
+1873(1981.)X
+555 900([MOHA91])N
+964(Mohan,)X
+1241(C.,)X
+1364(Pirahesh,)X
+1690(H.,)X
+1818(``ARIES-RRH:)X
+2366(Restricted)X
+2721(Repeating)X
+3076(of)X
+3173(History)X
+3442(in)X
+3533(the)X
+3660(ARIES)X
+3920(Transaction)X
+727 990(Recovery)N
+1055(Method'',)X
+2 f
+1398(Proceedings)X
+1819(7th)X
+1941(International)X
+2383(Conference)X
+2773(on)X
+2873(Data)X
+3053(Engineering)X
+1 f
+3449(,)X
+3489(Kobe,)X
+3703(Japan,)X
+3926(April)X
+4115(1991.)X
+555 1170([NODI90])N
+914(Nodine,)X
+1194(M.,)X
+1328(Zdonik,)X
+1602(S.,)X
+1709(``Cooperative)X
+2178(Transaction)X
+2580(Hierarchies:)X
+2996(A)X
+3077(Transaction)X
+3479(Model)X
+3711(to)X
+3796(Support)X
+4072(Design)X
+727 1260(Applications'',)N
+2 f
+1242(Proceedings)X
+1675(16th)X
+1849(International)X
+2303(Conference)X
+2704(on)X
+2815(Very)X
+2998(Large)X
+3220(Data)X
+3411(Bases)X
+1 f
+3598(,)X
+3649(Brisbane,)X
+3985(Australia,)X
+727 1350(August)N
+978(1990.)X
+555 1530([OUST90])N
+923(Ousterhout,)X
+1324(J.,)X
+1420(``Tcl:)X
+1648(An)X
+1771(Embeddable)X
+2197(Command)X
+2555(Language'',)X
+2 f
+2971(Proceedings)X
+3396(1990)X
+3580(Winter)X
+3822(Usenix)X
+1 f
+4045(,)X
+4089(Wash-)X
+727 1620(ington,)N
+971(D.C.,)X
+1162(January)X
+1432(1990.)X
+555 1800([POSIX91])N
+955(``Unapproved)X
+1441(Draft)X
+1645(for)X
+1773(Realtime)X
+2096(Extension)X
+2450(for)X
+2578(Portable)X
+2879(Operating)X
+3234(Systems'',)X
+3608(Draft)X
+3812(11,)X
+3946(October)X
+4239(7,)X
+727 1890(1991,)N
+927(IEEE)X
+1121(Computer)X
+1461(Society.)X
+555 2070([ROSE91])N
+925(Rosenblum,)X
+1341(M.,)X
+1484(Ousterhout,)X
+1892(J.,)X
+1995(``The)X
+2206(Design)X
+2464(and)X
+2611(Implementation)X
+3149(of)X
+3247(a)X
+3314(Log-Structured)X
+3835(File)X
+3990(System'',)X
+2 f
+727 2160(Proceedings)N
+1148(of)X
+1230(the)X
+1348(13th)X
+1510(Symposium)X
+1895(on)X
+1995(Operating)X
+2344(Systems)X
+2618(Principles)X
+1 f
+2947(,)X
+2987(1991.)X
+555 2340([SELT91])N
+904(Seltzer,)X
+1171(M.,)X
+1306(Stonebraker,)X
+1738(M.,)X
+1873(``Read)X
+2116(Optimized)X
+2478(File)X
+2626(Systems:)X
+2938(A)X
+3020(Performance)X
+3454(Evaluation'',)X
+2 f
+3898(Proceedings)X
+727 2430(7th)N
+849(Annual)X
+1100(International)X
+1542(Conference)X
+1932(on)X
+2032(Data)X
+2212(Engineering)X
+1 f
+2608(,)X
+2648(Kobe,)X
+2862(Japan,)X
+3085(April)X
+3274(1991.)X
+555 2610([SPEC88])N
+907(Spector,)X
+1200(Rausch,)X
+1484(Bruell,)X
+1732(``Camelot:)X
+2107(A)X
+2192(Flexible,)X
+2501(Distributed)X
+2888(Transaction)X
+3294(Processing)X
+3668(System'',)X
+2 f
+4004(Proceed-)X
+727 2700(ings)N
+880(of)X
+962(Spring)X
+1195(COMPCON)X
+1606(1988)X
+1 f
+(,)S
+1806(February)X
+2116(1988.)X
+555 2880([SQL86])N
+862(American)X
+1201(National)X
+1499(Standards)X
+1836(Institute,)X
+2139(``Database)X
+2509(Language)X
+2847(SQL'',)X
+3093(ANSI)X
+3301(X3.135-1986)X
+3747(\(ISO)X
+3924(9075\),)X
+4152(May)X
+727 2970(1986.)N
+555 3150([STON81])N
+919(Stonebraker,)X
+1348(M.,)X
+1480(``Operating)X
+1876(System)X
+2132(Support)X
+2406(for)X
+2520(Database)X
+2835(Management'',)X
+2 f
+3348(Communications)X
+3910(of)X
+3992(the)X
+4110(ACM)X
+1 f
+4279(,)X
+727 3240(1981.)N
+555 3420([SULL92])N
+925(Sullivan,)X
+1247(M.,)X
+1394(Olson,)X
+1641(M.,)X
+1788(``An)X
+1976(Index)X
+2195(Implementation)X
+2737(Supporting)X
+3127(Fast)X
+3295(Recovery)X
+3638(for)X
+3767(the)X
+3900(POSTGRES)X
+727 3510(Storage)N
+1014(System'',)X
+1365(to)X
+1469(appear)X
+1726(in)X
+2 f
+1830(Proceedings)X
+2272(8th)X
+2415(Annual)X
+2687(International)X
+3150(Conference)X
+3561(on)X
+3682(Data)X
+3883(Engineering)X
+1 f
+4279(,)X
+727 3600(Tempe,)N
+990(Arizona,)X
+1289(February)X
+1599(1992.)X
+555 3780([TPCB90])N
+914(Transaction)X
+1319(Processing)X
+1692(Performance)X
+2129(Council,)X
+2428(``TPC)X
+2653(Benchmark)X
+3048(B'',)X
+3200(Standard)X
+3510(Speci\256cation,)X
+3973(Waterside)X
+727 3870(Associates,)N
+1110(Fremont,)X
+1421(CA.,)X
+1592(1990.)X
+555 4050([YOUN91])N
+947(Young,)X
+1211(M.)X
+1328(W.,)X
+1470(Thompson,)X
+1858(D.)X
+1962(S.,)X
+2072(Jaffe,)X
+2274(E.,)X
+2388(``A)X
+2525(Modular)X
+2826(Architecture)X
+3253(for)X
+3372(Distributed)X
+3757(Transaction)X
+4161(Pro-)X
+727 4140(cessing'',)N
+2 f
+1057(Proceedings)X
+1478(1991)X
+1658(Winter)X
+1896(Usenix)X
+1 f
+2119(,)X
+2159(Dallas,)X
+2404(TX,)X
+2551(January)X
+2821(1991.)X
+3 f
+755 4263(Margo)N
+1008(I.)X
+1080(Seltzer)X
+1 f
+1338(is)X
+1411(a)X
+1467(Ph.D.)X
+1669(student)X
+1920(in)X
+2002(the)X
+2120(Department)X
+2519(of)X
+2606(Electrical)X
+2934(Engineering)X
+3346(and)X
+3482(Computer)X
+3822(Sciences)X
+4123(at)X
+4201(the)X
+555 4353(University)N
+919(of)X
+1012(California,)X
+1383(Berkeley.)X
+1739(Her)X
+1886(research)X
+2181(interests)X
+2474(include)X
+2735(\256le)X
+2862(systems,)X
+3160(databases,)X
+3513(and)X
+3654(transaction)X
+4031(process-)X
+555 4443(ing)N
+686(systems.)X
+1008(She)X
+1157(spent)X
+1355(several)X
+1612(years)X
+1811(working)X
+2107(at)X
+2194(startup)X
+2441(companies)X
+2813(designing)X
+3153(and)X
+3298(implementing)X
+3771(\256le)X
+3902(systems)X
+4183(and)X
+555 4533(transaction)N
+929(processing)X
+1294(software)X
+1592(and)X
+1729(designing)X
+2061(microprocessors.)X
+2648(Ms.)X
+2791(Seltzer)X
+3035(received)X
+3329(her)X
+3453(AB)X
+3585(in)X
+3668(Applied)X
+3947(Mathemat-)X
+555 4623(ics)N
+664(from)X
+840 0.1953(Harvard/Radcliffe)AX
+1445(College)X
+1714(in)X
+1796(1983.)X
+755 4746(In)N
+845(her)X
+971(spare)X
+1163(time,)X
+1347(Margo)X
+1583(can)X
+1717(usually)X
+1970(be)X
+2068(found)X
+2277(preparing)X
+2607(massive)X
+2887(quantities)X
+3220(of)X
+3309(food)X
+3478(for)X
+3594(hungry)X
+3843(hordes,)X
+4099(study-)X
+555 4836(ing)N
+677(Japanese,)X
+1003(or)X
+1090(playing)X
+1350(soccer)X
+1576(with)X
+1738(an)X
+1834(exciting)X
+2112(Bay)X
+2261(Area)X
+2438(Women's)X
+2770(Soccer)X
+3009(team,)X
+3205(the)X
+3323(Berkeley)X
+3633(Bruisers.)X
+3 f
+755 5049(Michael)N
+1056(A.)X
+1159(Olson)X
+1 f
+1383(is)X
+1461(a)X
+1522(Master's)X
+1828(student)X
+2084(in)X
+2170(the)X
+2292(Department)X
+2695(of)X
+2786(Electrical)X
+3118(Engineering)X
+3534(and)X
+3674(Computer)X
+4018(Sciences)X
+555 5139(at)N
+645(the)X
+774(University)X
+1143(of)X
+1241(California,)X
+1617(Berkeley.)X
+1978(His)X
+2120(primary)X
+2405(interests)X
+2703(are)X
+2833(database)X
+3141(systems)X
+3425(and)X
+3572(mass)X
+3763(storage)X
+4026(systems.)X
+555 5229(Mike)N
+759(spent)X
+963(two)X
+1118(years)X
+1323(working)X
+1625(for)X
+1754(a)X
+1825(commercial)X
+2239(database)X
+2551(system)X
+2808(vendor)X
+3066(before)X
+3307(joining)X
+3567(the)X
+3699(Postgres)X
+4004(Research)X
+555 5319(Group)N
+780(at)X
+858(Berkeley)X
+1168(in)X
+1250(1988.)X
+1470(He)X
+1584(received)X
+1877(his)X
+1990(B.A.)X
+2161(in)X
+2243(Computer)X
+2583(Science)X
+2853(from)X
+3029(Berkeley)X
+3339(in)X
+3421(May)X
+3588(1991.)X
+755 5442(Mike)N
+945(only)X
+1108(recently)X
+1388(transferred)X
+1758(into)X
+1903(Sin)X
+2030(City,)X
+2208(but)X
+2330(is)X
+2403(rapidly)X
+2650(adopting)X
+2950(local)X
+3126(customs)X
+3408(and)X
+3544(coloration.)X
+3929(In)X
+4016(his)X
+4129(spare)X
+555 5532(time,)N
+742(he)X
+843(organizes)X
+1176(informal)X
+1477(Friday)X
+1711(afternoon)X
+2043(study)X
+2240(groups)X
+2482(to)X
+2568(discuss)X
+2823(recent)X
+3044(technical)X
+3358(and)X
+3498(economic)X
+3834(developments.)X
+555 5622(Among)N
+815(his)X
+928(hobbies)X
+1197(are)X
+1316(Charles)X
+1581(Dickens,)X
+1884(Red)X
+2033(Rock,)X
+2242(and)X
+2378(speaking)X
+2683(Dutch)X
+2899(to)X
+2981(anyone)X
+3233(who)X
+3391(will)X
+3535(permit)X
+3764(it.)X
+
+17 p
+%%Trailer
+xt
+
+xs
+
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/docs/mpool.3.ps b/mechglue/src/plugins/kdb/db2/libdb2/docs/mpool.3.ps
new file mode 100644
index 000000000..816c9243c
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/docs/mpool.3.ps
@@ -0,0 +1,320 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 2
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll 
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 129.01(MPOOL\(3\) BSD)72 48 R(Programmer')2.5 E 2.5(sM)
+-.55 G 129.01(anual MPOOL\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72 84 S
+(ME).18 E F0(mpool \255 shared memory b)108 96 Q(uf)-.2 E(fer pool)-.25 E F1
+(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF(#include <db)108 124.8 Q(.h>)-.4 E
+(#include <mpool.h>)108 136.8 Q(MPOOL *)108 160.8 Q(mpool_open \(DBT *k)108
+172.8 Q(ey)-.1 E 2.5(,i)-.55 G(nt fd, pgno_t pagesize, pgno_t maxcache\);)
+216.25 172.8 Q -.1(vo)108 196.8 S(id).1 E(mpool_\214lter \(MPOOL *mp, v)108
+208.8 Q(oid \(*pgin\)\(v)-.1 E(oid *, pgno_t, v)-.1 E(oid *\),)-.1 E -.1(vo)158
+220.8 S(id \(*pgout\)\(v).1 E(oid *, pgno_t, v)-.1 E(oid *\), v)-.1 E
+(oid *pgcookie\);)-.1 E -.1(vo)108 244.8 S(id *).1 E
+(mpool_new \(MPOOL *mp, pgno_t *pgnoaddr\);)108 256.8 Q -.1(vo)108 280.8 S
+(id *).1 E(mpool_get \(MPOOL *mp, pgno_t pgno, u_int \215ags\);)108 292.8 Q
+(int)108 316.8 Q(mpool_put \(MPOOL *mp, v)108 328.8 Q(oid *pgaddr)-.1 E 2.5(,u)
+-.92 G(_int \215ags\);)290.62 328.8 Q(int)108 352.8 Q
+(mpool_sync \(MPOOL *mp\);)108 364.8 Q(int)108 388.8 Q
+(mpool_close \(MPOOL *mp\);)108 400.8 Q F1(DESCRIPTION)72 417.6 Q/F3 10
+/Times-Italic@0 SF(Mpool)108 429.6 Q F0 1.013(is the library interf)3.513 F
+1.013(ace intended to pro)-.1 F 1.013(vide page oriented b)-.15 F(uf)-.2 E
+1.012(fer management of \214les.)-.25 F 1.012(The b)6.012 F(uf)-.2 E(fers)-.25
+E(may be shared between processes.)108 441.6 Q .416(The function)108 458.4 R F3
+(mpool_open)2.916 E F0 .417(initializes a memory pool.)2.917 F(The)5.417 E F3
+-.1(ke)2.917 G(y)-.2 E F0(ar)2.917 E .417(gument is the byte string used to ne)
+-.18 F(gotiate)-.15 E .697(between multiple processes wishing to share b)108
+470.4 R(uf)-.2 E 3.196(fers. If)-.25 F .696(the \214le b)3.196 F(uf)-.2 E .696
+(fers are mapped in shared memory)-.25 F 3.196(,a)-.65 G(ll)534.44 470.4 Q .894
+(processes using the same k)108 482.4 R 1.194 -.15(ey w)-.1 H .894
+(ill share the b).15 F(uf)-.2 E 3.394(fers. If)-.25 F F3 -.1(ke)3.394 G(y)-.2 E
+F0 .895(is NULL, the b)3.395 F(uf)-.2 E .895(fers are mapped into pri)-.25 F
+-.25(va)-.25 G(te).25 E(memory)108 494.4 Q 5.116(.T)-.65 G(he)154.406 494.4 Q
+F3(fd)2.616 E F0(ar)2.616 E .115(gument is a \214le descriptor for the underly\
+ing \214le, which must be seekable.)-.18 F(If)5.115 E F3 -.1(ke)2.615 G(y)-.2 E
+F0 .115(is non-)2.615 F(NULL and matches a \214le already being mapped, the)108
+506.4 Q F3(fd)2.5 E F0(ar)2.5 E(gument is ignored.)-.18 E(The)108 523.2 Q F3
+(pa)3.328 E -.1(ge)-.1 G(size).1 E F0(ar)3.329 E .829
+(gument is the size, in bytes, of the pages into which the \214le is brok)-.18
+F .829(en up.)-.1 F(The)5.829 E F3(maxcac)3.329 E(he)-.15 E F0(ar)108 535.2 Q
+.153(gument is the maximum number of pages from the underlying \214le to cache\
+ at an)-.18 F 2.653(yo)-.15 G .153(ne time.)451.308 535.2 R .153(This v)5.153 F
+.153(alue is)-.25 F .099(not relati)108 547.2 R .399 -.15(ve t)-.25 H 2.599(ot)
+.15 G .099(he number of processes which share a \214le')168.727 547.2 R 2.6(sb)
+-.55 G(uf)350.39 547.2 Q .1(fers, b)-.25 F .1(ut will be the lar)-.2 F .1
+(gest v)-.18 F .1(alue speci\214ed by)-.25 F(an)108 559.2 Q 2.5(yo)-.15 G 2.5
+(ft)129.79 559.2 S(he processes sharing the \214le.)138.4 559.2 Q(The)108 576 Q
+F3(mpool_\214lter)3.254 E F0 .754(function is intended to mak)3.254 F 3.254(et)
+-.1 G .754(ransparent input and output processing of the pages possi-)301.778
+576 R 3.095(ble. If)108 588 R(the)3.095 E F3(pgin)3.095 E F0 .596
+(function is speci\214ed, it is called each time a b)3.095 F(uf)-.2 E .596
+(fer is read into the memory pool from the)-.25 F .125(backing \214le.)108 600
+R .125(If the)5.125 F F3(pgout)2.625 E F0 .125
+(function is speci\214ed, it is called each time a b)2.625 F(uf)-.2 E .125
+(fer is written into the backing \214le.)-.25 F .276
+(Both functions are are called with the)108 612 R F3(pgcookie)2.777 E F0
+(pointer)2.777 E 2.777(,t)-.4 G .277
+(he page number and a pointer to the page to being)337.27 612 R
+(read or written.)108 624 Q .124(The function)108 640.8 R F3(mpool_ne)2.624 E
+(w)-.15 E F0(tak)2.624 E .123(es an MPOOL pointer and an address as ar)-.1 F
+2.623(guments. If)-.18 F 2.623(an)2.623 G .623 -.25(ew p)457.568 640.8 T .123
+(age can be allo-).25 F .944(cated, a pointer to the page is returned and the \
+page number is stored into the)108 652.8 R F3(pgnoaddr)3.445 E F0 3.445
+(address. Other)3.445 F(-)-.2 E(wise, NULL is returned and errno is set.)108
+664.8 Q 1.167(The function)108 681.6 R F3(mpool_g)3.667 E(et)-.1 E F0(tak)3.667
+E 1.167(es a MPOOL pointer and a page number as ar)-.1 F 3.666(guments. If)-.18
+F 1.166(the page e)3.666 F 1.166(xists, a)-.15 F .686
+(pointer to the page is returned.)108 693.6 R .687
+(Otherwise, NULL is returned and errno is set.)5.686 F .687
+(The \215ags parameter is not)5.687 F(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G
+(istrib)132.57 732 Q 104.595(ution June)-.2 F(4, 1993)2.5 E(1)535 732 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 129.01(MPOOL\(3\) BSD)72 48 R(Programmer')2.5 E 2.5(sM)
+-.55 G 129.01(anual MPOOL\(3\))340.17 48 R(currently used.)108 84 Q 1.463
+(The function)108 100.8 R/F1 10/Times-Italic@0 SF(mpool_put)3.963 E F0 1.462
+(unpins the page referenced by)3.962 F F1(pgaddr)3.962 E F0(.).73 E F1(Pgaddr)
+6.462 E F0 1.462(must be an address pre)3.962 F(viously)-.25 E(returned by)108
+112.8 Q F1(mpool_g)2.5 E(et)-.1 E F0(or)2.5 E F1(mpool_ne)2.5 E(w)-.15 E F0 5
+(.T).31 G(he \215ag v)271.65 112.8 Q(alue is speci\214ed by)-.25 E F1(or)2.5 E
+F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)434.74 112.8 S(he follo)443.35 112.8 Q
+(wing v)-.25 E(alues:)-.25 E(MPOOL_DIR)108 129.6 Q(TY)-.6 E
+(The page has been modi\214ed and needs to be written to the backing \214le.)
+144 141.6 Q F1(Mpool_put)108 158.4 Q F0
+(returns 0 on success and -1 if an error occurs.)2.5 E .247(The function)108
+175.2 R F1(mpool_sync)2.747 E F0 .247(writes all modi\214ed pages associated w\
+ith the MPOOL pointer to the backing \214le.)2.747 F F1(Mpool_sync)108 187.2 Q
+F0(returns 0 on success and -1 if an error occurs.)2.5 E(The)108 204 Q F1
+(mpool_close)2.698 E F0 .198(function free')2.698 F 2.698(su)-.55 G 2.698(pa)
+245.432 204 S .498 -.15(ny a)257.57 204 T .198
+(llocated memory associated with the memory pool cookie.).15 F(Modi-)5.197 E
+(\214ed pages are)108 216 Q/F2 10/Times-Bold@0 SF(not)2.5 E F0
+(written to the backing \214le.)2.5 E F1(Mpool_close)5 E F0
+(returns 0 on success and -1 if an error occurs.)2.5 E/F3 9/Times-Bold@0 SF
+(ERR)72 232.8 Q(ORS)-.27 E F0(The)108 244.8 Q F1(mpool_open)2.938 E F0 .438
+(function may f)2.938 F .438(ail and set)-.1 F F1(errno)2.938 E F0 .438(for an)
+2.938 F 2.938(yo)-.15 G 2.938(ft)344.87 244.8 S .439
+(he errors speci\214ed for the library routine)353.918 244.8 R F1(mal-)2.939 E
+(loc)108 256.8 Q F0(\(3\).).31 E(The)108 273.6 Q F1(mpool_g)2.5 E(et)-.1 E F0
+(function may f)2.5 E(ail and set)-.1 E F1(errno)2.5 E F0(for the follo)2.5 E
+(wing:)-.25 E([EINV)108 290.4 Q 29.98(AL] The)-1.35 F(requested record doesn')
+2.5 E 2.5(te)-.18 G(xist.)305.96 290.4 Q(The)108 307.2 Q F1(mpool_ne)4.073 E(w)
+-.15 E F0(and)4.073 E F1(mpool_g)4.073 E(et)-.1 E F0 1.573(functions may f)
+4.073 F 1.573(ail and set)-.1 F F1(errno)4.073 E F0 1.573(for an)4.073 F 4.073
+(yo)-.15 G 4.073(ft)421.336 307.2 S 1.573(he errors speci\214ed for the)431.519
+307.2 R(library routines)108 319.2 Q F1 -.37(re)2.5 G(ad).37 E F0(\(2\)).77 E
+F1 2.5(,w).54 G(rite)214.48 319.2 Q F0(\(2\)).18 E F1(,).54 E F0(and)2.5 E F1
+(malloc)2.5 E F0(\(3\).).31 E(The)108 336 Q F1(mpool_sync)4.287 E F0 1.787
+(function may f)4.287 F 1.787(ail and set)-.1 F F1(errno)4.288 E F0 1.788
+(for an)4.288 F 4.288(yo)-.15 G 4.288(ft)356.694 336 S 1.788
+(he errors speci\214ed for the library routine)367.092 336 R F1(write)108 348 Q
+F0(\(2\).).18 E(The)108 364.8 Q F1(mpool_close)4.125 E F0 1.624(function may f)
+4.125 F 1.624(ail and set)-.1 F F1(errno)4.124 E F0 1.624(for an)4.124 F 4.124
+(yo)-.15 G 4.124(ft)357.842 364.8 S 1.624
+(he errors speci\214ed for the library routine)368.076 364.8 R F1(fr)108 376.8
+Q(ee)-.37 E F0(\(3\).).18 E F3(SEE ALSO)72 393.6 Q F1(dbopen)108 405.6 Q F0
+(\(3\),).24 E F1(btr)2.5 E(ee)-.37 E F0(\(3\),).18 E F1(hash)2.5 E F0(\(3\),)
+.28 E F1 -.37(re)2.5 G(cno).37 E F0(\(3\)).18 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5
+(yD)-.15 G(istrib)132.57 732 Q 104.595(ution June)-.2 F(4, 1993)2.5 E(2)535 732
+Q EP
+%%Trailer
+end
+%%EOF
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/docs/recno.3.ps b/mechglue/src/plugins/kdb/db2/libdb2/docs/recno.3.ps
new file mode 100644
index 000000000..8ffccfca9
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/docs/recno.3.ps
@@ -0,0 +1,341 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 2
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll 
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 130.12(RECNO\(3\) BSD)72 48 R(Programmer')2.5 E 2.5(sM)
+-.55 G 130.12(anual RECNO\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72 84 S
+(ME).18 E F0(recno \255 record number database access method)108 96 Q F1
+(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF(#include <sys/types.h>)108 124.8 Q
+(#include <db)108 136.8 Q(.h>)-.4 E F1(DESCRIPTION)72 153.6 Q F0 1.158
+(The routine)108 165.6 R/F3 10/Times-Italic@0 SF(dbopen)3.658 E F0 1.158
+(is the library interf)3.658 F 1.158(ace to database \214les.)-.1 F 1.157
+(One of the supported \214le formats is record)6.158 F 1.159(number \214les.)
+108 177.6 R 1.159(The general description of the database access methods is in)
+6.159 F F3(dbopen)3.66 E F0 1.16(\(3\), this manual page).24 F
+(describes only the recno speci\214c information.)108 189.6 Q 1.944
+(The record number data structure is either v)108 206.4 R 1.944
+(ariable or \214x)-.25 F 1.944
+(ed-length records stored in a \215at-\214le format,)-.15 F 2.04
+(accessed by the logical record number)108 218.4 R 7.04(.T)-.55 G 2.04(he e)
+286.31 218.4 R 2.04(xistence of record number \214v)-.15 F 4.54(ei)-.15 G 2.04
+(mplies the e)442.1 218.4 R 2.04(xistence of)-.15 F .876
+(records one through four)108 230.4 R 3.376(,a)-.4 G .875
+(nd the deletion of record number one causes record number \214v)219.684 230.4
+R 3.375(et)-.15 G 3.375(ob)489.93 230.4 S 3.375(er)503.305 230.4 S(enum-)514.45
+230.4 Q .282(bered to record number four)108 242.4 R 2.782(,a)-.4 G 2.782(sw)
+231.19 242.4 S .283(ell as the cursor)245.082 242.4 R 2.783(,i)-.4 G 2.783(fp)
+316.633 242.4 S .283(ositioned after record number one, to shift do)327.746
+242.4 R .283(wn one)-.25 F(record.)108 254.4 Q .373
+(The recno access method speci\214c data structure pro)108 271.2 R .373
+(vided to)-.15 F F3(dbopen)2.873 E F0 .373(is de\214ned in the <db)2.873 F .373
+(.h> include \214le as)-.4 F(follo)108 283.2 Q(ws:)-.25 E(typedef struct {)108
+300 Q(u_long \215ags;)144 312 Q(u_int cachesize;)144 324 Q(u_int psize;)144 336
+Q(int lorder;)144 348 Q(size_t reclen;)144 360 Q(u_char b)144 372 Q -.25(va)
+-.15 G(l;).25 E(char *bfname;)144 384 Q 2.5(}R)108 396 S(ECNOINFO;)121.97 396 Q
+(The elements of this structure are de\214ned as follo)108 412.8 Q(ws:)-.25 E
+14.61(\215ags The)108 429.6 R(\215ag v)2.5 E(alue is speci\214ed by)-.25 E F3
+(or)2.5 E F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)313.2 429.6 S(he follo)321.81
+429.6 Q(wing v)-.25 E(alues:)-.25 E(R_FIXEDLEN)144 446.4 Q .962
+(The records are \214x)180 458.4 R .963(ed-length, not byte delimited.)-.15 F
+.963(The structure element)5.963 F F3 -.37(re)3.463 G(clen).37 E F0
+(speci\214es)3.463 E .345(the length of the record, and the structure element)
+180 470.4 R F3(bval)2.844 E F0 .344(is used as the pad character)2.844 F 5.344
+(.A)-.55 G -.15(ny)530.15 470.4 S .739
+(records, inserted into the database, that are less than)180 482.4 R F3 -.37
+(re)3.239 G(clen).37 E F0 .74(bytes long are automatically)3.239 F(padded.)180
+494.4 Q(R_NOKEY)144 511.2 Q 2.34(In the interf)180 523.2 R 2.34
+(ace speci\214ed by)-.1 F F3(dbopen)4.84 E F0 4.84(,t).24 G 2.34
+(he sequential record retrie)344.98 523.2 R -.25(va)-.25 G 4.84<6c8c>.25 G 2.34
+(lls in both the)478.25 523.2 R(caller')180 535.2 Q 3.556(sk)-.55 G 1.357 -.15
+(ey a)217.336 535.2 T 1.057(nd data structures.).15 F 1.057
+(If the R_NOKEY \215ag is speci\214ed, the)6.057 F F3(cur)3.557 E(sor)-.1 E F0
+(routines)3.557 E .029(are not required to \214ll in the k)180 547.2 R .329
+-.15(ey s)-.1 H 2.529(tructure. This).15 F .028(permits applications to retrie)
+2.529 F .328 -.15(ve r)-.25 H .028(ecords at).15 F
+(the end of \214les without reading all of the interv)180 559.2 Q
+(ening records.)-.15 E(R_SN)144 576 Q(APSHO)-.35 E(T)-.4 E .964
+(This \215ag requires that a snapshot of the \214le be tak)180 588 R .965
+(en when)-.1 F F3(dbopen)3.465 E F0 .965(is called, instead of)3.465 F
+(permitting an)180 600 Q 2.5(yu)-.15 G
+(nmodi\214ed records to be read from the original \214le.)245.96 600 Q
+(cachesize)108 616.8 Q 3.16(As)144 628.8 S .66
+(uggested maximum size, in bytes, of the memory cache.)158.27 628.8 R .659
+(This v)5.659 F .659(alue is)-.25 F F2(only)3.159 E F0(advisory)3.159 E 3.159
+(,a)-.65 G .659(nd the)514.621 628.8 R .046
+(access method will allocate more memory rather than f)144 640.8 R 2.546
+(ail. If)-.1 F F3(cac)2.546 E(hesize)-.15 E F0 2.546(is 0)2.546 F .046
+(\(no size is speci\214ed\) a)2.546 F(def)144 652.8 Q(ault cache is used.)-.1 E
+12.95(psize The)108 669.6 R .715
+(recno access method stores the in-memory copies of its records in a btree.)
+3.216 F .715(This v)5.715 F .715(alue is the)-.25 F .805
+(size \(in bytes\) of the pages used for nodes in that tree.)144 681.6 R(If)
+5.805 E F3(psize)3.305 E F0 .806(is 0 \(no page size is speci\214ed\) a)3.305 F
+1.468
+(page size is chosen based on the underlying \214le system I/O block size.)144
+693.6 R(See)6.467 E F3(btr)3.967 E(ee)-.37 E F0 1.467(\(3\) for more).18 F
+(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 96.815
+(ution August)-.2 F(18, 1994)2.5 E(1)535 732 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 130.12(RECNO\(3\) BSD)72 48 R(Programmer')2.5 E 2.5(sM)
+-.55 G 130.12(anual RECNO\(3\))340.17 48 R(information.)144 84 Q 9.62
+(lorder The)108 100.8 R 1.596(byte order for inte)4.096 F 1.596
+(gers in the stored database metadata.)-.15 F 1.597
+(The number should represent the)6.597 F .689(order as an inte)144 112.8 R .689
+(ger; for e)-.15 F .689(xample, big endian order w)-.15 F .689
+(ould be the number 4,321.)-.1 F(If)5.689 E/F1 10/Times-Italic@0 SF(lor)3.189 E
+(der)-.37 E F0 .688(is 0 \(no)3.189 F
+(order is speci\214ed\) the current host order is used.)144 124.8 Q 9.07
+(reclen The)108 141.6 R(length of a \214x)2.5 E(ed-length record.)-.15 E -.15
+(bv)108 158.4 S 16.68(al The)-.1 F .182
+(delimiting byte to be used to mark the end of a record for v)2.682 F .183
+(ariable-length records, and the pad)-.25 F .809(character for \214x)144 170.4
+R .809(ed-length records.)-.15 F .809(If no v)5.809 F .809
+(alue is speci\214ed, ne)-.25 F .809(wlines \(`)-.25 F(`\\n')-.74 E .808
+('\) are used to mark the)-.74 F(end of v)144 182.4 Q
+(ariable-length records and \214x)-.25 E
+(ed-length records are padded with spaces.)-.15 E 3.51(bfname The)108 199.2 R
+.505
+(recno access method stores the in-memory copies of its records in a btree.)
+3.005 F .506(If bfname is non-)5.506 F .065(NULL, it speci\214es the name of t\
+he btree \214le, as if speci\214ed as the \214le name for a dbopen of a btree)
+144 211.2 R(\214le.)144 223.2 Q .971(The data part of the k)108 240 R -.15(ey)
+-.1 G .972(/data pair used by the recno access method is the same as other acc\
+ess methods.).15 F .199(The k)108 252 R .499 -.15(ey i)-.1 H 2.699(sd).15 G(if)
+157.507 252 Q 2.699(ferent. The)-.25 F F1(data)2.699 E F0 .199
+(\214eld of the k)2.699 F .499 -.15(ey s)-.1 H .198
+(hould be a pointer to a memory location of type).15 F F1 -.37(re)2.698 G
+(cno_t).37 E F0 2.698(,a).68 G(s)536.11 252 Q .505(de\214ned in the <db)108 264
+R .506(.h> include \214le.)-.4 F .506(This type is normally the lar)5.506 F
+.506(gest unsigned inte)-.18 F .506(gral type a)-.15 F -.25(va)-.2 G .506
+(ilable to the).25 F 2.5(implementation. The)108 276 R F1(size)2.5 E F0
+(\214eld of the k)2.5 E .3 -.15(ey s)-.1 H(hould be the size of that type.).15
+E .706(Because there can be no meta-data associated with the underlying recno \
+access method \214les, an)108 292.8 R 3.206(yc)-.15 G(hanges)512.23 292.8 Q
+1.262(made to the def)108 304.8 R 1.262(ault v)-.1 F 1.262(alues \(e.g. \214x)
+-.25 F 1.263(ed record length or byte separator v)-.15 F 1.263
+(alue\) must be e)-.25 F 1.263(xplicitly speci\214ed)-.15 F
+(each time the \214le is opened.)108 316.8 Q .065(In the interf)108 333.6 R
+.065(ace speci\214ed by)-.1 F F1(dbopen)2.564 E F0 2.564(,u).24 G .064
+(sing the)261.548 333.6 R F1(put)2.564 E F0(interf)2.564 E .064
+(ace to create a ne)-.1 F 2.564(wr)-.25 G .064
+(ecord will cause the creation of)414.44 333.6 R .755(multiple, empty records \
+if the record number is more than one greater than the lar)108 345.6 R .755
+(gest record currently in)-.18 F(the database.)108 357.6 Q/F2 9/Times-Bold@0 SF
+(ERR)72 374.4 Q(ORS)-.27 E F0(The)108 386.4 Q F1 -.37(re)2.922 G(cno).37 E F0
+.421(access method routines may f)2.921 F .421(ail and set)-.1 F F1(errno)2.921
+E F0 .421(for an)2.921 F 2.921(yo)-.15 G 2.921(ft)377.933 386.4 S .421
+(he errors speci\214ed for the library rou-)386.964 386.4 R(tine)108 398.4 Q F1
+(dbopen)2.5 E F0(\(3\) or the follo).24 E(wing:)-.25 E([EINV)108 415.2 Q(AL])
+-1.35 E(An attempt w)144 427.2 Q(as made to add a record to a \214x)-.1 E
+(ed-length database that w)-.15 E(as too lar)-.1 E(ge to \214t.)-.18 E F2
+(SEE ALSO)72 444 Q F1(btr)108 456 Q(ee)-.37 E F0(\(3\)).18 E F1(dbopen)2.5 E F0
+(\(3\),).24 E F1(hash)2.5 E F0(\(3\),).28 E F1(mpool)2.5 E F0(\(3\),).51 E F1
+2.754(Document Pr)108 480 R 2.754(ocessing in a Relational Database System)-.45
+F F0 5.255(,M).32 G 2.755(ichael Stonebrak)362.13 480 R(er)-.1 E 5.255(,H)-.4 G
+2.755(eidi Stettner)454.06 480 R 5.255(,J)-.4 G(oseph)516.67 480 Q
+(Kalash, Antonin Guttman, Nadene L)108 492 Q
+(ynn, Memorandum No. UCB/ERL M82/32, May 1982.)-.55 E F2 -.09(BU)72 508.8 S(GS)
+.09 E F0(Only big and little endian byte order is supported.)108 520.8 Q
+(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 96.815
+(ution August)-.2 F(18, 1994)2.5 E(2)535 732 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/Makefile.in b/mechglue/src/plugins/kdb/db2/libdb2/hash/Makefile.in
new file mode 100644
index 000000000..1e60e9a18
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/Makefile.in
@@ -0,0 +1,13 @@
+thisconfigdir=./..
+myfulldir=plugins/kdb/db2/libdb2/hash
+mydir=hash
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..$(S)..
+STLIBOBJS=	hash.o hash_bigkey.o hash_debug.o hash_func.o hash_log2.o \
+		hash_page.o hsearch.o dbm.o
+
+LOCALINCLUDES=	-I. -I$(srcdir)/../include -I../include -I$(srcdir)/../mpool \
+		-I$(srcdir)/../db
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+# @libobj_frag@
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/Makefile.inc b/mechglue/src/plugins/kdb/db2/libdb2/hash/Makefile.inc
new file mode 100644
index 000000000..87746f721
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/Makefile.inc
@@ -0,0 +1,6 @@
+#       @(#)Makefile.inc	8.2 (Berkeley) 11/7/95
+
+.PATH: ${.CURDIR}/db/hash
+
+SRCS+=	hash.c hash_bigkey.c hash_buf.c hash_func.c hash_log2.c \
+	hash_page.c hsearch.c dbm.c
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/dbm.c b/mechglue/src/plugins/kdb/db2/libdb2/hash/dbm.c
new file mode 100644
index 000000000..58c9df738
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/dbm.c
@@ -0,0 +1,356 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)dbm.c	8.6 (Berkeley) 11/7/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include "db-int.h"
+
+#include <sys/param.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "db-ndbm.h"
+#include "db-dbm.h"
+#include "hash.h"
+
+/* If the two size fields of datum and DBMT are not equal, then
+ * casting between structures will result in stack garbage being
+ * transfered. Has been observed for DEC Alpha OSF, but will handle
+ *  the general case.
+ */
+
+#define NEED_COPY
+
+/*
+ *
+ * This package provides dbm and ndbm compatible interfaces to DB.
+ * First are the DBM routines, which call the NDBM routines, and
+ * the NDBM routines, which call the DB routines.
+ */
+static DBM *__cur_db;
+
+static void no_open_db __P((void));
+
+int
+kdb2_dbminit(file)
+	char *file;
+{
+	if (__cur_db != NULL)
+		(void)kdb2_dbm_close(__cur_db);
+	if ((__cur_db = kdb2_dbm_open(file, O_RDWR|O_BINARY, 0)) != NULL)
+		return (0);
+	if ((__cur_db = kdb2_dbm_open(file, O_RDONLY|O_BINARY, 0)) != NULL)
+		return (0);
+	return (-1);
+}
+
+datum
+kdb2_fetch(key)
+	datum key;
+{
+	datum item;
+
+	if (__cur_db == NULL) {
+		no_open_db();
+		item.dptr = 0;
+		return (item);
+	}
+	return (kdb2_dbm_fetch(__cur_db, key));
+}
+
+datum
+kdb2_firstkey()
+{
+	datum item;
+
+	if (__cur_db == NULL) {
+		no_open_db();
+		item.dptr = 0;
+		return (item);
+	}
+	return (kdb2_dbm_firstkey(__cur_db));
+}
+
+datum
+kdb2_nextkey(key)
+	datum key;
+{
+	datum item;
+
+	if (__cur_db == NULL) {
+		no_open_db();
+		item.dptr = 0;
+		return (item);
+	}
+	return (kdb2_dbm_nextkey(__cur_db));
+}
+
+int
+kdb2_delete(key)
+	datum key;
+{
+	if (__cur_db == NULL) {
+		no_open_db();
+		return (-1);
+	}
+	return (kdb2_dbm_delete(__cur_db, key));
+}
+
+int
+kdb2_store(key, dat)
+	datum key, dat;
+{
+	if (__cur_db == NULL) {
+		no_open_db();
+		return (-1);
+	}
+	return (kdb2_dbm_store(__cur_db, key, dat, DBM_REPLACE));
+}
+
+static void
+no_open_db()
+{
+	(void)fprintf(stderr, "dbm: no open database.\n");
+}
+
+/*
+ * Returns:
+ * 	*DBM on success
+ *	 NULL on failure
+ */
+DBM *
+kdb2_dbm_open(file, flags, mode)
+	const char *file;
+	int flags, mode;
+{
+	HASHINFO info;
+	char path[MAXPATHLEN];
+
+	info.bsize = 4096;
+	info.ffactor = 40;
+	info.nelem = 1;
+	info.cachesize = 0;
+	info.hash = NULL;
+	info.lorder = 0;
+	(void)strncpy(path, file, sizeof(path) - 1);
+	path[sizeof(path) - 1] = '\0';
+	(void)strncat(path, DBM_SUFFIX, sizeof(path) - 1 - strlen(path));
+	return ((DBM *)__hash_open(path, flags, mode, &info, 0));
+}
+
+/*
+ * Returns:
+ *	Nothing.
+ */
+void
+kdb2_dbm_close(db)
+	DBM *db;
+{
+	(void)(db->close)(db);
+}
+
+/*
+ * Returns:
+ *	DATUM on success
+ *	NULL on failure
+ */
+datum
+kdb2_dbm_fetch(db, key)
+	DBM *db;
+	datum key;
+{
+	datum retval;
+	int status;
+
+#ifdef NEED_COPY
+	DBT k, r;
+
+	k.data = key.dptr;
+	k.size = key.dsize;
+	status = (db->get)(db, &k, &r, 0);
+	retval.dptr = r.data;
+	retval.dsize = r.size;
+#else
+	status = (db->get)(db, (DBT *)&key, (DBT *)&retval, 0);
+#endif
+	if (status) {
+		retval.dptr = NULL;
+		retval.dsize = 0;
+	}
+	return (retval);
+}
+
+/*
+ * Returns:
+ *	DATUM on success
+ *	NULL on failure
+ */
+datum
+kdb2_dbm_firstkey(db)
+	DBM *db;
+{
+	int status;
+	datum retkey;
+
+#ifdef NEED_COPY
+	DBT k, r;
+
+	status = (db->seq)(db, &k, &r, R_FIRST);
+	retkey.dptr = k.data;
+	retkey.dsize = k.size;
+#else
+	datum retdata;
+
+	status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_FIRST);
+#endif
+	if (status)
+		retkey.dptr = NULL;
+	return (retkey);
+}
+
+/*
+ * Returns:
+ *	DATUM on success
+ *	NULL on failure
+ */
+datum
+kdb2_dbm_nextkey(db)
+	DBM *db;
+{
+	int status;
+	datum retkey;
+
+#ifdef NEED_COPY
+	DBT k, r;
+
+	status = (db->seq)(db, &k, &r, R_NEXT);
+	retkey.dptr = k.data;
+	retkey.dsize = k.size;
+#else
+	datum retdata;
+
+	status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_NEXT);
+#endif
+	if (status)
+		retkey.dptr = NULL;
+	return (retkey);
+}
+
+/*
+ * Returns:
+ *	 0 on success
+ *	<0 failure
+ */
+int
+kdb2_dbm_delete(db, key)
+	DBM *db;
+	datum key;
+{
+	int status;
+
+#ifdef NEED_COPY
+	DBT k;
+
+	k.data = key.dptr;
+	k.size = key.dsize;
+	status = (db->del)(db, &k, 0);
+#else
+	status = (db->del)(db, (DBT *)&key, 0);
+#endif
+	if (status)
+		return (-1);
+	else
+		return (0);
+}
+
+/*
+ * Returns:
+ *	 0 on success
+ *	<0 failure
+ *	 1 if DBM_INSERT and entry exists
+ */
+int
+kdb2_dbm_store(db, key, content, flags)
+	DBM *db;
+	datum key, content;
+	int flags;
+{
+#ifdef NEED_COPY
+	DBT k, c;
+
+	k.data = key.dptr;
+	k.size = key.dsize;
+	c.data = content.dptr;
+	c.size = content.dsize;
+	return ((db->put)(db, &k, &c,
+	    (flags == DBM_INSERT) ? R_NOOVERWRITE : 0));
+#else
+	return ((db->put)(db, (DBT *)&key, (DBT *)&content,
+	    (flags == DBM_INSERT) ? R_NOOVERWRITE : 0));
+#endif
+}
+
+int
+kdb2_dbm_error(db)
+	DBM *db;
+{
+	HTAB *hp;
+
+	hp = (HTAB *)db->internal;
+	return (hp->local_errno);
+}
+
+int
+kdb2_dbm_clearerr(db)
+	DBM *db;
+{
+	HTAB *hp;
+
+	hp = (HTAB *)db->internal;
+	hp->local_errno = 0;
+	return (0);
+}
+
+int
+kdb2_dbm_dirfno(db)
+	DBM *db;
+{
+	return(((HTAB *)db->internal)->fp);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/extern.h b/mechglue/src/plugins/kdb/db2/libdb2/hash/extern.h
new file mode 100644
index 000000000..872b6b0fe
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/extern.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.8 (Berkeley) 11/7/95
+ */
+
+#define __add_bigpage		__kdb2_add_bigpage
+#define __add_ovflpage		__kdb2_add_ovflpage
+#define __addel			__kdb2_addel
+#define __alloc_tmp		__kdb2_alloc_tmp
+#define __big_delete		__kdb2_big_delete
+#define __big_insert		__kdb2_big_insert
+#define __big_keydata		__kdb2_big_keydata
+#define __big_return		__kdb2_big_return
+#define __call_hash		__kdb2_call_hash
+#define __cursor_creat		__kdb2_cursor_creat
+#define __delete_page		__kdb2_delete_page
+#define __delpair		__kdb2_delpair
+#define __expand_table		__kdb2_expand_table
+#define __find_bigpair		__kdb2_find_bigpair
+#define __free_ovflpage		__kdb2_free_ovflpage
+#define __get_bigkey		__kdb2_get_bigkey
+#define __get_buf		__kdb2_get_buf
+#define __get_item		__kdb2_get_item
+#define __get_item_done		__kdb2_get_item_done
+#define __get_item_first	__kdb2_get_item_first
+#define __get_item_next		__kdb2_get_item_next
+#define __get_item_reset	__kdb2_get_item_reset
+#define __get_page		__kdb2_get_page
+#define __ibitmap		__kdb2_ibitmap
+#define __log2			__kdb2_log2
+#define __new_page		__kdb2_new_page
+#define __pgin_routine		__kdb2_pgin_routine
+#define __pgout_routine		__kdb2_pgout_routine
+#define __put_buf		__kdb2_put_buf
+#define __put_page		__kdb2_put_page
+#define __reclaim_tmp		__kdb2_reclaim_tmp
+#define __split_page		__kdb2_split_page
+
+PAGE16	 *__add_bigpage __P((HTAB *, PAGE16 *, indx_t, const u_int8_t));
+PAGE16	 *__add_ovflpage __P((HTAB *, PAGE16 *));
+int32_t	  __addel __P((HTAB *, ITEM_INFO *,
+		const DBT *, const DBT *, u_int32_t, const u_int8_t));
+u_int32_t __alloc_tmp __P((HTAB*));
+int32_t	  __big_delete __P((HTAB *, PAGE16 *, indx_t));
+int32_t	  __big_insert __P((HTAB *, PAGE16 *, const DBT *, const DBT *));
+int32_t	  __big_keydata __P((HTAB *, PAGE16 *, DBT *, DBT *, int32_t));
+int32_t	  __big_return __P((HTAB *, ITEM_INFO *, DBT *, int32_t));
+u_int32_t __call_hash __P((HTAB *, int8_t *, int32_t));
+CURSOR	 *__cursor_creat __P((const DB *));
+int32_t	  __delete_page __P((HTAB *, PAGE16 *, int32_t));
+int32_t	  __delpair __P((HTAB *, CURSOR *, ITEM_INFO *));
+int32_t	  __expand_table __P((HTAB *));
+int32_t	  __find_bigpair __P((HTAB *, CURSOR *, int8_t *, int32_t));
+void	  __free_ovflpage __P((HTAB *, PAGE16 *));
+int32_t	  __get_bigkey __P((HTAB *, PAGE16 *, indx_t, DBT *));
+PAGE16	 *__get_buf __P((HTAB *, u_int32_t, int32_t));
+u_int32_t __get_item __P((HTAB *, CURSOR *, DBT *, DBT *, ITEM_INFO *));
+u_int32_t __get_item_done __P((HTAB *, CURSOR *));
+u_int32_t __get_item_first __P((HTAB *, CURSOR *, DBT *, DBT *, ITEM_INFO *));
+u_int32_t __get_item_next __P((HTAB *, CURSOR *, DBT *, DBT *, ITEM_INFO *));
+u_int32_t __get_item_reset __P((HTAB *, CURSOR *));
+PAGE16	 *__get_page __P((HTAB *, u_int32_t, int32_t));
+int32_t	  __ibitmap __P((HTAB *, int32_t, int32_t, int32_t));
+u_int32_t __log2 __P((u_int32_t));
+int32_t	  __new_page __P((HTAB *, u_int32_t, int32_t));
+void	  __pgin_routine __P((void *, db_pgno_t, void *));
+void	  __pgout_routine __P((void *, db_pgno_t, void *));
+u_int32_t __put_buf __P((HTAB *, PAGE16 *, u_int32_t));
+int32_t	  __put_page __P((HTAB *, PAGE16 *, int32_t, int32_t));
+void	  __reclaim_tmp __P((HTAB *));
+int32_t	  __split_page __P((HTAB *, u_int32_t, u_int32_t));
+
+/* Default hash routine. */
+extern u_int32_t (*__default_hash) __P((const void *, size_t));
+
+#ifdef HASH_STATISTICS
+extern long hash_accesses, hash_bigpages, hash_collisions, hash_expansions;
+extern long hash_overflow;
+#endif
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.c b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.c
new file mode 100644
index 000000000..0e254938e
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.c
@@ -0,0 +1,1068 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash.c	8.12 (Berkeley) 11/7/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef DEBUG
+#include <assert.h>
+#endif
+
+#include "db-int.h"
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static int32_t flush_meta __P((HTAB *));
+static int32_t hash_access __P((HTAB *, ACTION, const DBT *, DBT *));
+static int32_t hash_close __P((DB *));
+static int32_t hash_delete __P((const DB *, const DBT *, u_int32_t));
+static int32_t hash_fd __P((const DB *));
+static int32_t hash_get __P((const DB *, const DBT *, DBT *, u_int32_t));
+static int32_t hash_put __P((const DB *, DBT *, const DBT *, u_int32_t));
+static int32_t hash_seq __P((const DB *, DBT *, DBT *, u_int32_t));
+static int32_t hash_sync __P((const DB *, u_int32_t));
+static int32_t hdestroy __P((HTAB *));
+static int32_t cursor_get __P((const DB *, CURSOR *, DBT *, DBT *, \
+	u_int32_t));
+static int32_t cursor_delete __P((const DB *, CURSOR *, u_int32_t));
+static HTAB *init_hash __P((HTAB *, const char *, const HASHINFO *));
+static int32_t init_htab __P((HTAB *, int32_t));
+#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
+static void swap_header __P((HTAB *));
+static void swap_header_copy __P((HASHHDR *, HASHHDR *));
+#endif
+static u_int32_t hget_header __P((HTAB *, u_int32_t));
+static void hput_header __P((HTAB *));
+
+#define RETURN_ERROR(ERR, LOC)	{ save_errno = ERR; goto LOC; }
+
+/* Return values */
+#define	SUCCESS	 (0)
+#define	ERROR	(-1)
+#define	ABNORMAL (1)
+
+#ifdef HASH_STATISTICS
+u_int32_t hash_accesses, hash_collisions, hash_expansions, hash_overflows,
+	hash_bigpages;
+#endif
+
+/************************** INTERFACE ROUTINES ***************************/
+/* OPEN/CLOSE */
+
+extern DB *
+__kdb2_hash_open(file, flags, mode, info, dflags)
+	const char *file;
+	int32_t flags, mode, dflags;
+	const HASHINFO *info;	/* Special directives for create */
+{
+	struct stat statbuf;
+	DB *dbp;
+	DBT mpool_key;
+	HTAB *hashp;
+	int32_t bpages, csize, new_table, save_errno, specified_file;
+
+	if ((flags & O_ACCMODE) == O_WRONLY) {
+		errno = EINVAL;
+		return (NULL);
+	}
+	if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
+		return (NULL);
+	hashp->fp = -1;
+
+	/* set this now, before file goes away... */
+	specified_file = (file != NULL);
+	if (!file) {
+		file = tmpnam(NULL);
+		/* store the file name so that we can unlink it later */
+		hashp->fname = file;
+#ifdef DEBUG
+		fprintf(stderr, "Using file name %s.\n", file);
+#endif
+	}
+	/*
+	 * Even if user wants write only, we need to be able to read
+	 * the actual file, so we need to open it read/write. But, the
+	 * field in the hashp structure needs to be accurate so that
+	 * we can check accesses.
+	 */
+	hashp->flags = flags;
+	hashp->save_file = specified_file && (hashp->flags & O_RDWR);
+
+	new_table = 0;
+	if (!file || (flags & O_TRUNC) ||
+	    (stat(file, &statbuf) && (errno == ENOENT))) {
+		if (errno == ENOENT)
+			errno = 0;	/* In case someone looks at errno. */
+		new_table = 1;
+	}
+	if (file) {
+		if ((hashp->fp = open(file, flags|O_BINARY, mode)) == -1)
+			RETURN_ERROR(errno, error0);
+		(void)fcntl(hashp->fp, F_SETFD, 1);
+	}
+
+	/* Process arguments to set up hash table header. */
+	if (new_table) {
+		if (!(hashp = init_hash(hashp, file, info)))
+			RETURN_ERROR(errno, error1);
+	} else {
+		/* Table already exists */
+		if (info && info->hash)
+			hashp->hash = info->hash;
+		else
+			hashp->hash = __default_hash;
+
+		/* copy metadata from page into header */
+		if (hget_header(hashp,
+		    (info && info->bsize ? info->bsize : DEF_BUCKET_SIZE)) !=
+		    sizeof(HASHHDR))
+			RETURN_ERROR(EFTYPE, error1);
+
+		/* Verify file type, versions and hash function */
+		if (hashp->hdr.magic != HASHMAGIC)
+			RETURN_ERROR(EFTYPE, error1);
+#define	OLDHASHVERSION	1
+		if (hashp->hdr.version != HASHVERSION &&
+		    hashp->hdr.version != OLDHASHVERSION)
+			RETURN_ERROR(EFTYPE, error1);
+		if (hashp->hash(CHARKEY, sizeof(CHARKEY))
+		    != hashp->hdr.h_charkey)
+			RETURN_ERROR(EFTYPE, error1);
+		/*
+		 * Figure out how many segments we need.  Max_Bucket is the
+		 * maximum bucket number, so the number of buckets is
+		 * max_bucket + 1.
+		 */
+
+		/* Read in bitmaps */
+		bpages = (hashp->hdr.spares[hashp->hdr.ovfl_point] +
+		    (hashp->hdr.bsize << BYTE_SHIFT) - 1) >>
+		    (hashp->hdr.bshift + BYTE_SHIFT);
+
+		hashp->nmaps = bpages;
+		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
+	}
+
+	/* start up mpool */
+	mpool_key.data = (u_int8_t *)file;
+	mpool_key.size = strlen(file);
+
+	if (info && info->cachesize)
+		csize = info->cachesize / hashp->hdr.bsize;
+	else
+		csize = DEF_CACHESIZE / hashp->hdr.bsize;
+	hashp->mp = mpool_open(&mpool_key, hashp->fp, hashp->hdr.bsize, csize);
+
+	if (!hashp->mp)
+		RETURN_ERROR(errno, error1);
+	mpool_filter(hashp->mp, __pgin_routine, __pgout_routine, hashp);
+
+	/*
+	 * For a new table, set up the bitmaps.
+	 */
+	if (new_table &&
+	   init_htab(hashp, info && info->nelem ? info->nelem : 1))
+		goto error2;
+
+	/* initialize the cursor queue */
+	TAILQ_INIT(&hashp->curs_queue);
+	hashp->seq_cursor = NULL;
+
+
+	/* get a chunk of memory for our split buffer */
+	hashp->split_buf = (PAGE16 *)malloc(hashp->hdr.bsize);
+	if (!hashp->split_buf)
+		goto error2;
+
+	hashp->new_file = new_table;
+
+	if (!(dbp = (DB *)malloc(sizeof(DB))))
+		goto error2;
+
+	dbp->internal = hashp;
+	dbp->close = hash_close;
+	dbp->del = hash_delete;
+	dbp->fd = hash_fd;
+	dbp->get = hash_get;
+	dbp->put = hash_put;
+	dbp->seq = hash_seq;
+	dbp->sync = hash_sync;
+	dbp->type = DB_HASH;
+
+#ifdef DEBUG
+	(void)fprintf(stderr,
+	    "%s\n%s%lx\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
+	    "init_htab:",
+	    "TABLE POINTER   ", (void *)hashp,
+	    "BUCKET SIZE     ", hashp->hdr.bsize,
+	    "BUCKET SHIFT    ", hashp->hdr.bshift,
+	    "FILL FACTOR     ", hashp->hdr.ffactor,
+	    "MAX BUCKET      ", hashp->hdr.max_bucket,
+	    "OVFL POINT      ", hashp->hdr.ovfl_point,
+	    "LAST FREED      ", hashp->hdr.last_freed,
+	    "HIGH MASK       ", hashp->hdr.high_mask,
+	    "LOW  MASK       ", hashp->hdr.low_mask,
+	    "NKEYS           ", hashp->hdr.nkeys);
+#endif
+#ifdef HASH_STATISTICS
+	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
+	hash_bigpages = 0;
+#endif
+	return (dbp);
+
+error2:
+	save_errno = errno;
+	hdestroy(hashp);
+	errno = save_errno;
+	return (NULL);
+
+error1:
+	if (hashp != NULL)
+		(void)close(hashp->fp);
+
+error0:
+	free(hashp);
+	errno = save_errno;
+	return (NULL);
+}
+
+static int32_t
+hash_close(dbp)
+	DB *dbp;
+{
+	HTAB *hashp;
+	int32_t retval;
+
+	if (!dbp)
+		return (ERROR);
+
+	hashp = (HTAB *)dbp->internal;
+	retval = hdestroy(hashp);
+	free(dbp);
+	return (retval);
+}
+
+static int32_t
+hash_fd(dbp)
+	const DB *dbp;
+{
+	HTAB *hashp;
+
+	if (!dbp)
+		return (ERROR);
+
+	hashp = (HTAB *)dbp->internal;
+	if (hashp->fp == -1) {
+		errno = ENOENT;
+		return (-1);
+	}
+	return (hashp->fp);
+}
+
+/************************** LOCAL CREATION ROUTINES **********************/
+static HTAB *
+init_hash(hashp, file, info)
+	HTAB *hashp;
+	const char *file;
+	const HASHINFO *info;
+{
+	struct stat statbuf;
+	int32_t nelem;
+
+	nelem = 1;
+	hashp->hdr.nkeys = 0;
+	hashp->hdr.lorder = DB_BYTE_ORDER;
+	hashp->hdr.bsize = DEF_BUCKET_SIZE;
+	hashp->hdr.bshift = DEF_BUCKET_SHIFT;
+	hashp->hdr.ffactor = DEF_FFACTOR;
+	hashp->hash = __default_hash;
+	memset(hashp->hdr.spares, 0, sizeof(hashp->hdr.spares));
+	memset(hashp->hdr.bitmaps, 0, sizeof(hashp->hdr.bitmaps));
+
+	/* Fix bucket size to be optimal for file system */
+	if (file != NULL) {
+		if (stat(file, &statbuf))
+			return (NULL);
+		hashp->hdr.bsize = statbuf.st_blksize;
+		hashp->hdr.bshift = __log2(hashp->hdr.bsize);
+	}
+	if (info) {
+		if (info->bsize) {
+			/* Round pagesize up to power of 2 */
+			hashp->hdr.bshift = __log2(info->bsize);
+			hashp->hdr.bsize = 1 << hashp->hdr.bshift;
+			if (hashp->hdr.bsize > MAX_BSIZE) {
+				errno = EINVAL;
+				return (NULL);
+			}
+		}
+		if (info->ffactor)
+			hashp->hdr.ffactor = info->ffactor;
+		if (info->hash)
+			hashp->hash = info->hash;
+		if (info->lorder) {
+			if ((info->lorder != DB_BIG_ENDIAN) &&
+			    (info->lorder != DB_LITTLE_ENDIAN)) {
+				errno = EINVAL;
+				return (NULL);
+			}
+			hashp->hdr.lorder = info->lorder;
+		}
+	}
+	return (hashp);
+}
+
+/*
+ * Returns 0 on No Error
+ */
+static int32_t
+init_htab(hashp, nelem)
+	HTAB *hashp;
+	int32_t nelem;
+{
+	int32_t l2, nbuckets;
+
+	/*
+	 * Divide number of elements by the fill factor and determine a
+	 * desired number of buckets.  Allocate space for the next greater
+	 * power of two number of buckets.
+	 */
+	nelem = (nelem - 1) / hashp->hdr.ffactor + 1;
+
+	l2 = __log2(MAX(nelem, 2));
+	nbuckets = 1 << l2;
+
+	hashp->hdr.spares[l2] = l2 + 1;
+	hashp->hdr.spares[l2 + 1] = l2 + 1;
+	hashp->hdr.ovfl_point = l2;
+	hashp->hdr.last_freed = 2;
+
+	hashp->hdr.max_bucket = hashp->hdr.low_mask = nbuckets - 1;
+	hashp->hdr.high_mask = (nbuckets << 1) - 1;
+
+	/*
+	 * The number of header pages is the size of the header divided by
+	 * the amount of freespace on header pages (the page size - the
+	 * size of 1 integer where the length of the header info on that
+	 * page is stored) plus another page if it didn't divide evenly.
+	 */
+	hashp->hdr.hdrpages =
+	    (sizeof(HASHHDR) / (hashp->hdr.bsize - HEADER_OVERHEAD)) +
+	    (((sizeof(HASHHDR) % (hashp->hdr.bsize - HEADER_OVERHEAD)) == 0)
+	    ? 0 : 1);
+
+	/* Create pages for these buckets */
+	/*
+	for (i = 0; i <= hashp->hdr.max_bucket; i++) {
+		if (__new_page(hashp, (u_int32_t)i, A_BUCKET) != 0)
+			return (-1);
+	}
+	*/
+
+	/* First bitmap page is at: splitpoint l2 page offset 1 */
+	if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
+		return (-1);
+
+	return (0);
+}
+
+/*
+ * Functions to get/put hash header.  We access the file directly.
+ */
+static u_int32_t
+hget_header(hashp, page_size)
+	HTAB *hashp;
+	u_int32_t page_size;
+{
+	u_int32_t num_copied, i;
+	u_int8_t *hdr_dest;
+
+	num_copied = 0;
+	i = 0;
+
+	hdr_dest = (u_int8_t *)&hashp->hdr;
+
+	/* 
+	 * XXX
+	 * This should not be printing to stderr on a "normal" error case.
+	 */
+	lseek(hashp->fp, 0, SEEK_SET);
+	num_copied = read(hashp->fp, hdr_dest, sizeof(HASHHDR));
+	if (num_copied != sizeof(HASHHDR)) {
+		fprintf(stderr, "hash: could not retrieve header");
+		return (0);
+	}
+#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
+	swap_header(hashp);
+#endif
+	return (num_copied);
+}
+
+static void
+hput_header(hashp)
+	HTAB *hashp;
+{
+	HASHHDR *whdrp;
+#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
+	HASHHDR whdr;
+#endif
+	u_int32_t num_copied, i;
+
+	num_copied = i = 0;
+
+	whdrp = &hashp->hdr;
+#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
+	whdrp = &whdr;
+	swap_header_copy(&hashp->hdr, whdrp);
+#endif
+
+	lseek(hashp->fp, 0, SEEK_SET);
+	num_copied = write(hashp->fp, whdrp, sizeof(HASHHDR));
+	if (num_copied != sizeof(HASHHDR))
+		(void)fprintf(stderr, "hash: could not write hash header");
+	return;
+}
+
+/********************** DESTROY/CLOSE ROUTINES ************************/
+
+/*
+ * Flushes any changes to the file if necessary and destroys the hashp
+ * structure, freeing all allocated space.
+ */
+static int32_t
+hdestroy(hashp)
+	HTAB *hashp;
+{
+	int32_t save_errno;
+
+	save_errno = 0;
+
+#ifdef HASH_STATISTICS
+	{ int i;
+	(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
+	    hash_accesses, hash_collisions);
+	(void)fprintf(stderr,
+	    "hdestroy: expansions %ld\n", hash_expansions);
+	(void)fprintf(stderr,
+	    "hdestroy: overflows %ld\n", hash_overflows);
+	(void)fprintf(stderr,
+	    "hdestroy: big key/data pages %ld\n", hash_bigpages);
+	(void)fprintf(stderr,
+	    "keys %ld maxp %d\n", hashp->hdr.nkeys, hashp->hdr.max_bucket);
+
+	for (i = 0; i < NCACHED; i++)
+		(void)fprintf(stderr,
+		    "spares[%d] = %d\n", i, hashp->hdr.spares[i]);
+	}
+#endif
+
+	if (flush_meta(hashp) && !save_errno)
+		save_errno = errno;
+
+	/* Free the split page */
+	if (hashp->split_buf)
+		free(hashp->split_buf);
+
+	/* Free the big key and big data returns */
+	if (hashp->bigkey_buf)
+		free(hashp->bigkey_buf);
+	if (hashp->bigdata_buf)
+		free(hashp->bigdata_buf);
+ 
+	/* XXX This should really iterate over the cursor queue, but
+	   it's not clear how to do that, and the only cursor a hash
+	   table ever creates is the one used by hash_seq().  Passing
+	   NULL as the first arg is also a kludge, but I know that
+	   it's never used, so I do it.  The intent is to plug the
+	   memory leak.  Correctness can come later. */
+ 
+	if (hashp->seq_cursor)
+		hashp->seq_cursor->delete(NULL, hashp->seq_cursor, 0);
+
+	/* shut down mpool */
+	mpool_sync(hashp->mp);
+	mpool_close(hashp->mp);
+
+	if (hashp->fp != -1)
+		(void)close(hashp->fp);
+
+	/* 
+	 * *** This may cause problems if hashp->fname is set in any case
+	 * other than the case that we are generating a temporary file name.
+	 * Note that the new version of mpool should support temporary
+	 * files within mpool itself.
+	 */
+	if (hashp->fname && !hashp->save_file) {
+#ifdef DEBUG
+		fprintf(stderr, "Unlinking file %s.\n", hashp->fname);
+#endif
+		/* we need to chmod the file to allow it to be deleted... */
+		chmod(hashp->fname, 0700);
+		unlink(hashp->fname);
+		/* destroy the temporary name */
+		tmpnam(NULL);
+	}
+	free(hashp);
+
+	if (save_errno) {
+		errno = save_errno;
+		return (ERROR);
+	}
+	return (SUCCESS);
+}
+
+/*
+ * Write modified pages to disk
+ *
+ * Returns:
+ *	 0 == OK
+ *	-1 ERROR
+ */
+static int32_t
+hash_sync(dbp, flags)
+	const DB *dbp;
+	u_int32_t flags;
+{
+	HTAB *hashp;
+
+	hashp = (HTAB *)dbp->internal;
+
+	/*
+	 * XXX
+	 * Check success/failure conditions.
+	 */
+	return (flush_meta(hashp) || mpool_sync(hashp->mp));
+}
+
+/*
+ * Returns:
+ *	 0 == OK
+ *	-1 indicates that errno should be set
+ */
+static int32_t
+flush_meta(hashp)
+	HTAB *hashp;
+{
+	int32_t i;
+
+	if (!hashp->save_file)
+		return (0);
+	hashp->hdr.magic = HASHMAGIC;
+	hashp->hdr.version = HASHVERSION;
+	hashp->hdr.h_charkey = hashp->hash(CHARKEY, sizeof(CHARKEY));
+
+	/* write out metadata */
+	hput_header(hashp);
+
+	for (i = 0; i < NCACHED; i++)
+		if (hashp->mapp[i]) {
+			if (__put_page(hashp,
+			    (PAGE16 *)hashp->mapp[i], A_BITMAP, 1))
+				return (-1);
+			hashp->mapp[i] = NULL;
+		}
+	return (0);
+}
+
+/*******************************SEARCH ROUTINES *****************************/
+/*
+ * All the access routines return
+ *
+ * Returns:
+ *	 0 on SUCCESS
+ *	 1 to indicate an external ERROR (i.e. key not found, etc)
+ *	-1 to indicate an internal ERROR (i.e. out of memory, etc)
+ */
+
+/* *** make sure this is true! */
+
+static int32_t
+hash_get(dbp, key, data, flag)
+	const DB *dbp;
+	const DBT *key;
+	DBT *data;
+	u_int32_t flag;
+{
+	HTAB *hashp;
+
+	hashp = (HTAB *)dbp->internal;
+	if (flag) {
+		hashp->local_errno = errno = EINVAL;
+		return (ERROR);
+	}
+	return (hash_access(hashp, HASH_GET, key, data));
+}
+
+static int32_t
+hash_put(dbp, key, data, flag)
+	const DB *dbp;
+	DBT *key;
+	const DBT *data;
+	u_int32_t flag;
+{
+	HTAB *hashp;
+
+	hashp = (HTAB *)dbp->internal;
+	if (flag && flag != R_NOOVERWRITE) {
+		hashp->local_errno = errno = EINVAL;
+		return (ERROR);
+	}
+	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+		hashp->local_errno = errno = EPERM;
+		return (ERROR);
+	}
+	return (hash_access(hashp, flag == R_NOOVERWRITE ?
+		HASH_PUTNEW : HASH_PUT, key, (DBT *)data));
+}
+
+static int32_t
+hash_delete(dbp, key, flag)
+	const DB *dbp;
+	const DBT *key;
+	u_int32_t flag;		/* Ignored */
+{
+	HTAB *hashp;
+
+	hashp = (HTAB *)dbp->internal;
+	if (flag) {
+		hashp->local_errno = errno = EINVAL;
+		return (ERROR);
+	}
+	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+		hashp->local_errno = errno = EPERM;
+		return (ERROR);
+	}
+
+	return (hash_access(hashp, HASH_DELETE, key, NULL));
+}
+
+/*
+ * Assume that hashp has been set in wrapper routine.
+ */
+static int32_t
+hash_access(hashp, action, key, val)
+	HTAB *hashp;
+	ACTION action;
+	const DBT *key;
+	DBT *val;
+{
+	DBT page_key, page_val;
+	CURSOR cursor;
+	ITEM_INFO item_info;
+	u_int32_t bucket;
+	u_int32_t num_items;
+
+#ifdef HASH_STATISTICS
+	hash_accesses++;
+#endif
+
+	num_items = 0;
+
+	/* 
+	 * Set up item_info so that we're looking for space to add an item
+	 * as we cycle through the pages looking for the key.
+	 */
+	if (action == HASH_PUT || action == HASH_PUTNEW) {
+		if (ISBIG(key->size + val->size, hashp))
+			item_info.seek_size = PAIR_OVERHEAD;
+		else
+			item_info.seek_size = key->size + val->size;
+	} else
+		item_info.seek_size = 0;
+	item_info.seek_found_page = 0;
+
+	bucket = __call_hash(hashp, (int8_t *)key->data, key->size);
+
+	cursor.pagep = NULL;
+	__get_item_reset(hashp, &cursor);
+
+	cursor.bucket = bucket;
+	while (1) {
+		__get_item_next(hashp, &cursor, &page_key, &page_val, &item_info);
+		if (item_info.status == ITEM_ERROR)
+			return (ABNORMAL);
+		if (item_info.status == ITEM_NO_MORE)
+			break;
+		num_items++;
+		if (item_info.key_off == BIGPAIR) {
+			/*
+			 * !!!
+			 * 0 is a valid index.
+			 */
+			if (__find_bigpair(hashp, &cursor, (int8_t *)key->data,
+			    key->size) > 0)
+				goto found;
+		} else if (key->size == page_key.size &&
+		    !memcmp(key->data, page_key.data, key->size))
+			goto found;
+	}
+#ifdef HASH_STATISTICS
+	hash_collisions++;
+#endif
+	__get_item_done(hashp, &cursor);
+
+	/*
+	 * At this point, item_info will list either the last page in
+	 * the chain, or the last page in the chain plus a pgno for where
+	 * to find the first page in the chain with space for the
+	 * item we wish to add.
+	 */
+
+	/* Not found */
+	switch (action) {
+	case HASH_PUT:
+	case HASH_PUTNEW:
+		if (__addel(hashp, &item_info, key, val, num_items, 0))
+			return (ERROR);
+		break;
+	case HASH_GET:
+	case HASH_DELETE:
+	default:
+		return (ABNORMAL);
+	}
+
+	if (item_info.caused_expand)
+		__expand_table(hashp);
+	return (SUCCESS);
+
+found:	__get_item_done(hashp, &cursor);
+
+	switch (action) {
+	case HASH_PUTNEW:
+		/* mpool_put(hashp->mp, pagep, 0); */
+		return (ABNORMAL);
+	case HASH_GET:
+		if (item_info.key_off == BIGPAIR) {
+			if (__big_return(hashp, &item_info, val, 0))
+				return (ERROR);
+		} else {
+			val->data = page_val.data;
+			val->size = page_val.size;
+		}
+		/* *** data may not be available! */
+		break;
+	case HASH_PUT:
+		if (__delpair(hashp, &cursor, &item_info) ||
+		    __addel(hashp, &item_info, key, val, UNKNOWN, 0))
+			return (ERROR);
+		__get_item_done(hashp, &cursor);
+		if (item_info.caused_expand)
+			__expand_table(hashp);
+		break;
+	case HASH_DELETE:
+		if (__delpair(hashp, &cursor, &item_info))
+			return (ERROR);
+		break;
+	default:
+		abort();
+	}
+	return (SUCCESS);
+}
+
+/* ****************** CURSORS ********************************** */
+CURSOR *
+__cursor_creat(dbp)
+	const DB *dbp;
+{
+	CURSOR *new_curs;
+	HTAB *hashp;
+
+	new_curs = (CURSOR *)malloc(sizeof(struct cursor_t));
+	if (!new_curs)
+		return NULL;
+	new_curs->internal =
+	    (struct item_info *)malloc(sizeof(struct item_info));
+	if (!new_curs->internal) {
+		free(new_curs);
+		return NULL;
+	}
+	new_curs->get = cursor_get;
+	new_curs->delete = cursor_delete;
+
+	new_curs->bucket = 0;
+	new_curs->pgno = INVALID_PGNO;
+	new_curs->ndx = 0;
+	new_curs->pgndx = 0;
+	new_curs->pagep = NULL;
+
+	/* place onto queue of cursors */
+	hashp = (HTAB *)dbp->internal;
+	TAILQ_INSERT_TAIL(&hashp->curs_queue, new_curs, queue);
+
+	return new_curs;
+}
+
+static int32_t
+cursor_get(dbp, cursorp, key, val, flags)
+	const DB *dbp;
+	CURSOR *cursorp;
+	DBT *key, *val;
+	u_int32_t flags;
+{
+	HTAB *hashp;
+	ITEM_INFO item_info;
+
+	hashp = (HTAB *)dbp->internal;
+
+	if (flags && flags != R_FIRST && flags != R_NEXT) {
+		hashp->local_errno = errno = EINVAL;
+		return (ERROR);
+	}
+#ifdef HASH_STATISTICS
+	hash_accesses++;
+#endif
+
+	item_info.seek_size = 0;
+
+	if (flags == R_FIRST)
+		__get_item_first(hashp, cursorp, key, val, &item_info);
+	else
+		__get_item_next(hashp, cursorp, key, val, &item_info);
+
+	/*
+	 * This needs to be changed around.  As is, get_item_next advances
+	 * the pointers on the page but this function actually advances
+	 * bucket pointers.  This works, since the only other place we 
+	 * use get_item_next is in hash_access which only deals with one
+	 * bucket at a time.  However, there is the problem that certain other
+	 * functions (such as find_bigpair and delpair) depend on the
+	 * pgndx member of the cursor.  Right now, they are using pngdx - 1
+	 * since indices refer to the __next__ item that is to be fetched
+	 * from the page.  This is ugly, as you may have noticed, whoever
+	 * you are.  The best solution would be to depend on item_infos to
+	 * deal with _current_ information, and have the cursors only
+	 * deal with _next_ information.  In that scheme, get_item_next
+	 * would also advance buckets.  Version 3...
+	 */
+
+
+	/*
+	 * Must always enter this loop to do error handling and
+	 * check for big key/data pair.
+	 */
+	while (1) {
+		if (item_info.status == ITEM_OK) {
+			if (item_info.key_off == BIGPAIR &&
+			    __big_keydata(hashp, cursorp->pagep, key, val,
+			    item_info.pgndx))
+				return (ABNORMAL);
+
+			break;
+		} else if (item_info.status != ITEM_NO_MORE)
+			return (ABNORMAL);
+
+		__put_page(hashp, cursorp->pagep, A_RAW, 0);
+		cursorp->ndx = cursorp->pgndx = 0;
+		cursorp->bucket++;
+		cursorp->pgno = INVALID_PGNO;
+		cursorp->pagep = NULL;
+		if (cursorp->bucket > hashp->hdr.max_bucket)
+			return (ABNORMAL);
+		__get_item_next(hashp, cursorp, key, val, &item_info);
+	}
+
+	__get_item_done(hashp, cursorp);
+	return (0);
+}
+
+static int32_t
+cursor_delete(dbp, cursor, flags)
+	const DB *dbp;
+	CURSOR *cursor;
+	u_int32_t flags;
+{
+	/* XXX this is empirically determined, so it might not be completely
+	   correct, but it seems to work.  At the very least it fixes
+	   a memory leak */
+ 
+	free(cursor->internal);
+	free(cursor);
+
+	return (0);
+}
+
+static int32_t
+hash_seq(dbp, key, val, flag)
+	const DB *dbp;
+	DBT *key, *val;
+	u_int32_t flag;
+{
+	HTAB *hashp;
+
+	/*
+	 * Seq just uses the default cursor to go sequecing through the
+	 * database.  Note that the default cursor is the first in the list. 
+	 */
+
+	hashp = (HTAB *)dbp->internal;
+	if (!hashp->seq_cursor)
+		hashp->seq_cursor = __cursor_creat(dbp);
+
+	return (hashp->seq_cursor->get(dbp, hashp->seq_cursor, key, val, flag));
+}
+
+/********************************* UTILITIES ************************/
+
+/*
+ * Returns:
+ *	 0 ==> OK
+ *	-1 ==> Error
+ */
+int32_t
+__expand_table(hashp)
+	HTAB *hashp;
+{
+	u_int32_t old_bucket, new_bucket;
+	int32_t spare_ndx;
+
+#ifdef HASH_STATISTICS
+	hash_expansions++;
+#endif
+	new_bucket = ++hashp->hdr.max_bucket;
+	old_bucket = (hashp->hdr.max_bucket & hashp->hdr.low_mask);
+
+	/* Get a page for this new bucket */
+	if (__new_page(hashp, new_bucket, A_BUCKET) != 0)
+		return (-1);
+
+	/*
+	 * If the split point is increasing (hdr.max_bucket's log base 2
+	 * increases), we need to copy the current contents of the spare
+	 * split bucket to the next bucket.
+	 */
+	spare_ndx = __log2(hashp->hdr.max_bucket + 1);
+	if (spare_ndx > hashp->hdr.ovfl_point) {
+		hashp->hdr.spares[spare_ndx] = hashp->hdr.spares[hashp->hdr.ovfl_point];
+		hashp->hdr.ovfl_point = spare_ndx;
+	}
+	if (new_bucket > hashp->hdr.high_mask) {
+		/* Starting a new doubling */
+		hashp->hdr.low_mask = hashp->hdr.high_mask;
+		hashp->hdr.high_mask = new_bucket | hashp->hdr.low_mask;
+	}
+	if (BUCKET_TO_PAGE(new_bucket) > MAX_PAGES(hashp)) {
+		fprintf(stderr, "hash: Cannot allocate new bucket.  Pages exhausted.\n");
+		return (-1);
+	}
+	/* Relocate records to the new bucket */
+	return (__split_page(hashp, old_bucket, new_bucket));
+}
+
+u_int32_t
+__call_hash(hashp, k, len)
+	HTAB *hashp;
+	int8_t *k;
+	int32_t len;
+{
+	int32_t n, bucket;
+
+	n = hashp->hash(k, len);
+	bucket = n & hashp->hdr.high_mask;
+	if (bucket > hashp->hdr.max_bucket)
+		bucket = bucket & hashp->hdr.low_mask;
+	return (bucket);
+}
+
+#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
+/*
+ * Hashp->hdr needs to be byteswapped.
+ */
+static void
+swap_header_copy(srcp, destp)
+	HASHHDR *srcp, *destp;
+{
+	int32_t i;
+
+	P_32_COPY(srcp->magic, destp->magic);
+	P_32_COPY(srcp->version, destp->version);
+	P_32_COPY(srcp->lorder, destp->lorder);
+	P_32_COPY(srcp->bsize, destp->bsize);
+	P_32_COPY(srcp->bshift, destp->bshift);
+	P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
+	P_32_COPY(srcp->last_freed, destp->last_freed);
+	P_32_COPY(srcp->max_bucket, destp->max_bucket);
+	P_32_COPY(srcp->high_mask, destp->high_mask);
+	P_32_COPY(srcp->low_mask, destp->low_mask);
+	P_32_COPY(srcp->ffactor, destp->ffactor);
+	P_32_COPY(srcp->nkeys, destp->nkeys);
+	P_32_COPY(srcp->hdrpages, destp->hdrpages);
+	P_32_COPY(srcp->h_charkey, destp->h_charkey);
+	for (i = 0; i < NCACHED; i++) {
+		P_32_COPY(srcp->spares[i], destp->spares[i]);
+		P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
+	}
+}
+
+static void
+swap_header(hashp)
+	HTAB *hashp;
+{
+	HASHHDR *hdrp;
+	int32_t i;
+
+	hdrp = &hashp->hdr;
+
+	M_32_SWAP(hdrp->magic);
+	M_32_SWAP(hdrp->version);
+	M_32_SWAP(hdrp->lorder);
+	M_32_SWAP(hdrp->bsize);
+	M_32_SWAP(hdrp->bshift);
+	M_32_SWAP(hdrp->ovfl_point);
+	M_32_SWAP(hdrp->last_freed);
+	M_32_SWAP(hdrp->max_bucket);
+	M_32_SWAP(hdrp->high_mask);
+	M_32_SWAP(hdrp->low_mask);
+	M_32_SWAP(hdrp->ffactor);
+	M_32_SWAP(hdrp->nkeys);
+	M_32_SWAP(hdrp->hdrpages);
+	M_32_SWAP(hdrp->h_charkey);
+	for (i = 0; i < NCACHED; i++) {
+		M_32_SWAP(hdrp->spares[i]);
+		M_16_SWAP(hdrp->bitmaps[i]);
+	}
+}
+#endif /* DB_BYTE_ORDER == DB_LITTLE_ENDIAN */
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.c.patch b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.c.patch
new file mode 100644
index 000000000..b72cc0d26
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.c.patch
@@ -0,0 +1,109 @@
+*** /tmp/,RCSt1a21714	Wed Apr  3 11:49:15 1996
+--- hash.c	Wed Apr  3 08:43:04 1996
+***************
+*** 399,405
+  	/* Create pages for these buckets */
+  	/*
+  	for (i = 0; i <= hashp->hdr.max_bucket; i++) {
+! 		if (__new_page(hashp, i, A_BUCKET) != 0)
+  			return (-1);
+  	}
+  	*/
+
+--- 399,405 -----
+  	/* Create pages for these buckets */
+  	/*
+  	for (i = 0; i <= hashp->hdr.max_bucket; i++) {
+! 		if (__new_page(hashp, (u_int32_t)i, A_BUCKET) != 0)
+  			return (-1);
+  	}
+  	*/
+***************
+*** 560,567
+  	 * XXX
+  	 * Check success/failure conditions.
+  	 */
+! 	mpool_sync(hashp->mp);
+! 	return (0);
+  }
+  
+  /*
+
+--- 560,566 -----
+  	 * XXX
+  	 * Check success/failure conditions.
+  	 */
+! 	return (flush_meta(hashp) || mpool_sync(hashp->mp));
+  }
+  
+  /*
+***************
+*** 585,591
+  	hput_header(hashp);
+  
+  	for (i = 0; i < NCACHED; i++)
+! 		if (hashp->mapp[i])
+  			if (__put_page(hashp,
+  			    (PAGE16 *)hashp->mapp[i], A_BITMAP, 1))
+  				return (-1);
+
+--- 584,590 -----
+  	hput_header(hashp);
+  
+  	for (i = 0; i < NCACHED; i++)
+! 		if (hashp->mapp[i]) {
+  			if (__put_page(hashp,
+  			    (PAGE16 *)hashp->mapp[i], A_BITMAP, 1))
+  				return (-1);
+***************
+*** 589,594
+  			if (__put_page(hashp,
+  			    (PAGE16 *)hashp->mapp[i], A_BITMAP, 1))
+  				return (-1);
+  	return (0);
+  }
+  
+
+--- 588,595 -----
+  			if (__put_page(hashp,
+  			    (PAGE16 *)hashp->mapp[i], A_BITMAP, 1))
+  				return (-1);
++ 			hashp->mapp[i] = NULL;
++ 		}
+  	return (0);
+  }
+  
+***************
+*** 726,732
+  #ifdef HASH_STATISTICS
+  	hash_collisions++;
+  #endif
+- 
+  	__get_item_done(hashp, &cursor);
+  
+  	/*
+
+--- 727,732 -----
+  #ifdef HASH_STATISTICS
+  	hash_collisions++;
+  #endif
+  	__get_item_done(hashp, &cursor);
+  
+  	/*
+***************
+*** 773,778
+  		if (__delpair(hashp, &cursor, &item_info) ||
+  		    __addel(hashp, &item_info, key, val, UNKNOWN, 0))
+  			return (ERROR);
+  		if (item_info.caused_expand)
+  			__expand_table(hashp);
+  		break;
+
+--- 773,779 -----
+  		if (__delpair(hashp, &cursor, &item_info) ||
+  		    __addel(hashp, &item_info, key, val, UNKNOWN, 0))
+  			return (ERROR);
++ 		__get_item_done(hashp, &cursor);
+  		if (item_info.caused_expand)
+  			__expand_table(hashp);
+  		break;
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.h b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.h
new file mode 100644
index 000000000..b202fc9f2
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash.h
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)hash.h	8.4 (Berkeley) 11/2/95
+ */
+
+#include "mpool.h"
+#include "db-queue.h"
+
+/* Operations */
+typedef enum {
+	HASH_GET, HASH_PUT, HASH_PUTNEW, HASH_DELETE, HASH_FIRST, HASH_NEXT
+} ACTION;
+
+/* cursor structure */
+typedef struct cursor_t {
+	TAILQ_ENTRY(cursor_t) queue;
+	int (*get)	__P((const DB *, struct cursor_t *, DBT *, DBT *, \
+			     u_int32_t));
+	int (*delete) __P((const DB *, struct cursor_t *, u_int32_t));
+	db_pgno_t	bucket;
+	db_pgno_t	pgno;
+	indx_t	ndx;
+	indx_t	pgndx;
+	u_int16_t *pagep;
+	void *internal;
+} CURSOR;
+
+
+#define IS_BUCKET(X)	((X) & BUF_BUCKET)
+#define IS_VALID(X)     (!((X) & BUF_INVALID))
+
+/* Hash Table Information */
+typedef struct hashhdr {	/* Disk resident portion */
+	int32_t	magic;		/* Magic NO for hash tables */
+	int32_t	version;	/* Version ID */
+	int32_t	lorder;		/* Byte Order */
+	int32_t	bsize;		/* Bucket/Page Size */
+	int32_t	bshift;		/* Bucket shift */
+	int32_t	ovfl_point;	/* Where overflow pages are being allocated */
+	int32_t	last_freed;	/* Last overflow page freed */
+	int32_t	max_bucket;	/* ID of Maximum bucket in use */
+	int32_t	high_mask;	/* Mask to modulo into entire table */
+	int32_t	low_mask;	/* Mask to modulo into lower half of table */
+	int32_t	ffactor;	/* Fill factor */
+	int32_t	nkeys;		/* Number of keys in hash table */
+	int32_t	hdrpages;	/* Size of table header */
+	int32_t	h_charkey;	/* value of hash(CHARKEY) */
+#define NCACHED	32		/* number of bit maps and spare points */
+	int32_t	spares[NCACHED];/* spare pages for overflow */
+	u_int16_t	bitmaps[NCACHED];	/* address of overflow page bitmaps */
+} HASHHDR;
+
+typedef struct htab {		/* Memory resident data structure */
+	TAILQ_HEAD(_cursor_queue, cursor_t) curs_queue;
+	HASHHDR hdr;		/* Header */
+	u_int32_t (*hash) __P((const void *, size_t)); /* Hash Function */
+	int32_t	flags;		/* Flag values */
+	int32_t	fp;		/* File pointer */
+	const char *fname;        	/* File path */
+	u_int8_t *bigdata_buf;	/* Temporary Buffer for BIG data */
+	u_int8_t *bigkey_buf;	/* Temporary Buffer for BIG keys */
+	u_int16_t  *split_buf;	/* Temporary buffer for splits */
+	CURSOR	*seq_cursor;	/* Cursor used for hash_seq */
+	int32_t	local_errno;	/* Error Number -- for DBM compatability */
+	int32_t	new_file;	/* Indicates if fd is backing store or no */
+	int32_t	save_file;	/* Indicates whether we need to flush file at
+				 * exit */
+	u_int32_t *mapp[NCACHED];/* Pointers to page maps */
+	int32_t	nmaps;		/* Initial number of bitmaps */
+	MPOOL	*mp;		/* mpool for buffer management */
+} HTAB;
+
+/*
+ * Constants
+ */
+#define	MAX_BSIZE		65536		/* 2^16 */
+#define MIN_BUFFERS		6
+#define MINHDRSIZE		512
+#define DEF_CACHESIZE	65536
+#define DEF_BUCKET_SHIFT	12		/* log2(BUCKET) */
+#define DEF_BUCKET_SIZE		(1<<DEF_BUCKET_SHIFT)
+#define DEF_SEGSIZE_SHIFT	8		/* log2(SEGSIZE)	 */
+#define DEF_SEGSIZE		(1<<DEF_SEGSIZE_SHIFT)
+#define DEF_DIRSIZE		256
+#define DEF_FFACTOR		65536
+#define MIN_FFACTOR		4
+#define SPLTMAX			8
+#define CHARKEY			"%$sniglet^&"
+#define NUMKEY			1038583
+#define BYTE_SHIFT		3
+#define INT32_T_TO_BYTE		2
+#define INT32_T_BYTE_SHIFT		5
+#define ALL_SET			((u_int32_t)0xFFFFFFFF)
+#define ALL_CLEAR		0
+
+#define PTROF(X)	((BUFHEAD *)((ptr_t)(X)&~0x3))
+#define ISMOD(X)	((ptr_t)(X)&0x1)
+#define DOMOD(X)	((X) = (int8_t *)((ptr_t)(X)|0x1))
+#define ISDISK(X)	((ptr_t)(X)&0x2)
+#define DODISK(X)	((X) = (int8_t *)((ptr_t)(X)|0x2))
+
+#define BITS_PER_MAP	32
+
+/* Given the address of the beginning of a big map, clear/set the nth bit */
+#define CLRBIT(A, N)	((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))
+#define SETBIT(A, N)	((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))
+#define ISSET(A, N)	((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))
+
+/* Overflow management */
+/*
+ * Overflow page numbers are allocated per split point.  At each doubling of
+ * the table, we can allocate extra pages.  So, an overflow page number has
+ * the top 5 bits indicate which split point and the lower 11 bits indicate
+ * which page at that split point is indicated (pages within split points are
+ * numberered starting with 1).
+ */
+
+#define SPLITSHIFT	11
+#define SPLITMASK	0x7FF
+#define SPLITNUM(N)	(((u_int32_t)(N)) >> SPLITSHIFT)
+#define OPAGENUM(N)	((N) & SPLITMASK)
+#define	OADDR_OF(S,O)	((u_int32_t)((u_int32_t)(S) << SPLITSHIFT) + (O))
+
+#define BUCKET_TO_PAGE(B) \
+	((B) + hashp->hdr.hdrpages + ((B) \
+	    ? hashp->hdr.spares[__log2((B)+1)-1] : 0))
+#define OADDR_TO_PAGE(B) 	\
+	(BUCKET_TO_PAGE ( (1 << SPLITNUM((B))) -1 ) + OPAGENUM((B)))
+
+#define POW2(N)  (1 << (N))
+
+#define MAX_PAGES(H) (DB_OFF_T_MAX / (H)->hdr.bsize)
+
+/* Shorthands for accessing structure */
+#define METADATA_PGNO 0
+#define SPLIT_PGNO 0xFFFF
+
+typedef struct item_info {
+	db_pgno_t 		pgno;
+	db_pgno_t		bucket;
+	indx_t		ndx;
+	indx_t		pgndx;
+	u_int8_t	status;
+	int32_t		seek_size;
+	db_pgno_t		seek_found_page;
+	indx_t		key_off;
+	indx_t		data_off;
+	u_int8_t	caused_expand;
+} ITEM_INFO;
+
+
+#define	ITEM_ERROR	0
+#define	ITEM_OK		1
+#define	ITEM_NO_MORE	2
+
+#define	ITEM_GET_FIRST	0
+#define	ITEM_GET_NEXT	1
+#define	ITEM_GET_RESET	2
+#define	ITEM_GET_DONE	3
+#define	ITEM_GET_N	4
+
+#define	UNKNOWN		0xffffffff		/* for num_items */
+#define	NO_EXPAND	0xfffffffe 
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c
new file mode 100644
index 000000000..06210a57c
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_bigkey.c
@@ -0,0 +1,483 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_bigkey.c	8.5 (Berkeley) 11/2/95";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * PACKAGE: hash
+ * DESCRIPTION:
+ *	Big key/data handling for the hashing package.
+ *
+ * ROUTINES:
+ * External
+ *	__big_keydata
+ *	__big_split
+ *	__big_insert
+ *	__big_return
+ *	__big_delete
+ *	__find_last_page
+ * Internal
+ *	collect_key
+ *	collect_data
+ */
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DEBUG
+#include <assert.h>
+#endif
+
+#include "db-int.h"
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static int32_t collect_key __P((HTAB *, PAGE16 *, int32_t, db_pgno_t *));
+static int32_t collect_data __P((HTAB *, PAGE16 *, int32_t));
+
+/*
+ * Big_insert
+ *
+ * You need to do an insert and the key/data pair is greater than 
+ * MINFILL * the bucket size
+ *
+ * Returns:
+ *	 0 ==> OK
+ *	-1 ==> ERROR
+ */
+int32_t
+__big_insert(hashp, pagep, key, val)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	const DBT *key, *val;
+{
+	size_t  key_size, val_size;
+	indx_t  key_move_bytes, val_move_bytes;
+	int8_t *key_data, *val_data, base_page;
+
+	key_data = (int8_t *)key->data;
+	key_size = key->size;
+	val_data = (int8_t *)val->data;
+	val_size = val->size;
+
+	NUM_ENT(pagep) = NUM_ENT(pagep) + 1;
+
+	for (base_page = 1; key_size + val_size;) {
+		/* Add a page! */
+		pagep =
+		    __add_bigpage(hashp, pagep, NUM_ENT(pagep) - 1, base_page);
+		if (!pagep)
+			return (-1);
+
+		/* There's just going to be one entry on this page. */
+		NUM_ENT(pagep) = 1;
+
+		/* Move the key's data. */
+		key_move_bytes = MIN(FREESPACE(pagep), key_size);
+		/* Mark the page as to how much key & data is on this page. */
+		BIGKEYLEN(pagep) = key_move_bytes;
+		val_move_bytes =
+		    MIN(FREESPACE(pagep) - key_move_bytes, val_size);
+		BIGDATALEN(pagep) = val_move_bytes;
+
+		/* Note big pages build beginning --> end, not vice versa. */
+		if (key_move_bytes)
+			memmove(BIGKEY(pagep), key_data, key_move_bytes);
+		if (val_move_bytes)
+			memmove(BIGDATA(pagep), val_data, val_move_bytes);
+
+		key_size -= key_move_bytes;
+		key_data += key_move_bytes;
+		val_size -= val_move_bytes;
+		val_data += val_move_bytes;
+
+		base_page = 0;
+	}
+	__put_page(hashp, pagep, A_RAW, 1);
+	return (0);
+}
+
+/*
+ * Called when we need to delete a big pair.
+ *
+ * Returns:
+ *	 0 => OK
+ *	-1 => ERROR
+ */
+int32_t
+#ifdef __STDC__
+__big_delete(HTAB *hashp, PAGE16 *pagep, indx_t ndx)
+#else
+__big_delete(hashp, pagep, ndx)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	u_int32_t ndx;		/* Index of big pair on base page. */
+#endif
+{
+	PAGE16 *last_pagep;
+
+	/* Get first page with big key/data. */
+	pagep = __get_page(hashp, OADDR_TO_PAGE(DATA_OFF(pagep, ndx)), A_RAW);
+	if (!pagep)
+		return (-1);
+
+	/*
+	 * Traverse through the pages, freeing the previous one (except
+	 * the first) at each new page.
+	 */
+	while (NEXT_PGNO(pagep) != INVALID_PGNO) {
+		last_pagep = pagep;
+		pagep = __get_page(hashp, NEXT_PGNO(pagep), A_RAW);
+		if (!pagep)
+			return (-1);
+		__delete_page(hashp, last_pagep, A_OVFL);
+	}
+
+	/* Free the last page in the chain. */
+	__delete_page(hashp, pagep, A_OVFL);
+	return (0);
+}
+
+/*
+ * Given a key, indicates whether the big key at cursorp matches the
+ * given key.
+ *
+ * Returns:
+ *	 1 = Found!
+ *	 0 = Key not found
+ *	-1 error
+ */
+int32_t
+__find_bigpair(hashp, cursorp, key, size)
+	HTAB *hashp;
+	CURSOR *cursorp;
+	int8_t *key;
+	int32_t size;
+{
+	PAGE16 *pagep, *hold_pagep;
+	db_pgno_t  next_pgno;
+	int32_t ksize;
+	u_int16_t bytes;
+	int8_t *kkey;
+
+	ksize = size;
+	kkey = key;
+	bytes = 0;
+
+	hold_pagep = NULL;
+	/* Chances are, hashp->cpage is the base page. */
+	if (cursorp->pagep)
+		pagep = hold_pagep = cursorp->pagep;
+	else {
+		pagep = __get_page(hashp, cursorp->pgno, A_RAW);
+		if (!pagep)
+			return (-1);
+	}
+
+	/*
+	 * Now, get the first page with the big stuff on it.
+	 *
+	 * XXX
+	 * KLUDGE: we know that cursor is looking at the _next_ item, so
+	 * we have to look at pgndx - 1.
+	 */
+	next_pgno = OADDR_TO_PAGE(DATA_OFF(pagep, (cursorp->pgndx - 1)));
+	if (!hold_pagep)
+		__put_page(hashp, pagep, A_RAW, 0);
+	pagep = __get_page(hashp, next_pgno, A_RAW);
+	if (!pagep)
+		return (-1);
+
+	/* While there are both keys to compare. */
+	while ((ksize > 0) && (BIGKEYLEN(pagep))) {
+		if (ksize < KEY_OFF(pagep, 0) ||
+		    memcmp(BIGKEY(pagep), kkey, BIGKEYLEN(pagep))) {
+			__put_page(hashp, pagep, A_RAW, 0);
+			return (0);
+		}
+		kkey += BIGKEYLEN(pagep);
+		ksize -= BIGKEYLEN(pagep);
+		if (NEXT_PGNO(pagep) != INVALID_PGNO) {
+			next_pgno = NEXT_PGNO(pagep);
+			__put_page(hashp, pagep, A_RAW, 0);
+			pagep = __get_page(hashp, next_pgno, A_RAW);
+			if (!pagep)
+				return (-1);
+		}
+	}
+	__put_page(hashp, pagep, A_RAW, 0);
+#ifdef DEBUG
+	assert(ksize >= 0);
+#endif
+	if (ksize != 0) {
+#ifdef HASH_STATISTICS
+		++hash_collisions;
+#endif
+		return (0);
+	} else
+		return (1);
+}
+
+/*
+ * Fill in the key and data for this big pair.
+ */
+int32_t
+__big_keydata(hashp, pagep, key, val, ndx)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	DBT *key, *val;
+	int32_t ndx;
+{
+	ITEM_INFO ii;
+	PAGE16 *key_pagep;
+	db_pgno_t last_page;
+
+	key_pagep =
+	    __get_page(hashp, OADDR_TO_PAGE(DATA_OFF(pagep, ndx)), A_RAW);
+	if (!key_pagep)
+		return (-1);
+	key->size = collect_key(hashp, key_pagep, 0, &last_page);
+	key->data = hashp->bigkey_buf;
+	__put_page(hashp, key_pagep, A_RAW, 0);
+
+	if (key->size == -1)
+		return (-1);
+
+	/* Create an item_info to direct __big_return to the beginning pgno. */
+	ii.pgno = last_page;
+	return (__big_return(hashp, &ii, val, 1));
+}
+
+/*
+ * Return the big key on page, ndx.
+ */
+int32_t
+#ifdef __STDC__
+__get_bigkey(HTAB *hashp, PAGE16 *pagep, indx_t ndx, DBT *key)
+#else
+__get_bigkey(hashp, pagep, ndx, key)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	u_int32_t ndx;
+	DBT *key;
+#endif
+{
+	PAGE16 *key_pagep;
+
+	key_pagep =
+	    __get_page(hashp, OADDR_TO_PAGE(DATA_OFF(pagep, ndx)), A_RAW);
+	if (!pagep)
+		return (-1);
+	key->size = collect_key(hashp, key_pagep, 0, NULL);
+	key->data = hashp->bigkey_buf;
+
+	__put_page(hashp, key_pagep, A_RAW, 0);
+
+	return (0);
+}
+
+/*
+ * Return the big key and data indicated in item_info.
+ */
+int32_t
+__big_return(hashp, item_info, val, on_bigkey_page)
+	HTAB *hashp;
+	ITEM_INFO *item_info;
+	DBT *val;
+	int32_t on_bigkey_page;
+{
+	PAGE16 *pagep;
+	db_pgno_t next_pgno;
+
+	if (!on_bigkey_page) {
+		/* Get first page with big pair on it. */
+		pagep = __get_page(hashp,
+		    OADDR_TO_PAGE(item_info->data_off), A_RAW);
+		if (!pagep)
+			return (-1);
+	} else {
+		pagep = __get_page(hashp, item_info->pgno, A_RAW);
+		if (!pagep)
+			return (-1);
+	}
+
+	/* Traverse through the bigkey pages until a page with data is found. */
+	while (!BIGDATALEN(pagep)) {
+		next_pgno = NEXT_PGNO(pagep);
+		__put_page(hashp, pagep, A_RAW, 0);
+		pagep = __get_page(hashp, next_pgno, A_RAW);
+		if (!pagep)
+			return (-1);
+	}
+
+	val->size = collect_data(hashp, pagep, 0);
+	if (val->size < 1)
+		return (-1);
+	val->data = (void *)hashp->bigdata_buf;
+
+	__put_page(hashp, pagep, A_RAW, 0);
+	return (0);
+}
+
+/*
+ * Given a page with a big key on it, traverse through the pages counting data
+ * length, and collect all of the data on the way up.  Store the key in
+ * hashp->bigkey_buf.  last_page indicates to the calling function what the
+ * last page with key on it is; this will help if you later want to retrieve
+ * the data portion.
+ *
+ * Does the work for __get_bigkey.
+ *
+ * Return total length of data; -1 if error.
+ */
+static int32_t
+collect_key(hashp, pagep, len, last_page)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	int32_t len;
+	db_pgno_t *last_page;
+{
+	PAGE16 *next_pagep;
+	int32_t totlen, retval;
+	db_pgno_t next_pgno;
+#ifdef DEBUG
+	db_pgno_t save_addr;
+#endif
+
+	/* If this is the last page with key. */
+	if (BIGDATALEN(pagep)) {
+		totlen = len + BIGKEYLEN(pagep);
+		if (hashp->bigkey_buf)
+			free(hashp->bigkey_buf);
+		hashp->bigkey_buf = (u_int8_t *)malloc(totlen);
+		if (!hashp->bigkey_buf)
+			return (-1);
+		memcpy(hashp->bigkey_buf + len,
+		    BIGKEY(pagep), BIGKEYLEN(pagep));
+		if (last_page)
+			*last_page = ADDR(pagep);
+		return (totlen);
+	}
+
+	/* Key filled up all of last key page, so we've gone 1 too far. */
+	if (BIGKEYLEN(pagep) == 0) {
+		if (hashp->bigkey_buf)
+			free(hashp->bigkey_buf);
+		hashp->bigkey_buf = (u_int8_t *)malloc(len);
+		return (hashp->bigkey_buf ? len : -1);
+	}
+	totlen = len + BIGKEYLEN(pagep);
+
+	/* Set pagep to the next page in the chain. */
+	if (last_page)
+		*last_page = ADDR(pagep);
+	next_pgno = NEXT_PGNO(pagep);
+	next_pagep = __get_page(hashp, next_pgno, A_RAW);
+	if (!next_pagep)
+		return (-1);
+#ifdef DEBUG
+	save_addr = ADDR(pagep);
+#endif
+	retval = collect_key(hashp, next_pagep, totlen, last_page);
+
+#ifdef DEBUG
+	assert(save_addr == ADDR(pagep));
+#endif
+	memcpy(hashp->bigkey_buf + len, BIGKEY(pagep), BIGKEYLEN(pagep));
+	__put_page(hashp, next_pagep, A_RAW, 0);
+
+	return (retval);
+}
+
+/*
+ * Given a page with big data on it, recur through the pages counting data
+ * length, and collect all of the data on the way up.  Store the data in
+ * hashp->bigdata_buf.
+ *
+ * Does the work for __big_return.
+ *
+ * Return total length of data; -1 if error.
+ */
+static int32_t
+collect_data(hashp, pagep, len)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	int32_t len;
+{
+	PAGE16 *next_pagep;
+	int32_t totlen, retval;
+	db_pgno_t next_pgno;
+#ifdef DEBUG
+	db_pgno_t save_addr;
+#endif
+
+	/* If there is no next page. */
+	if (NEXT_PGNO(pagep) == INVALID_PGNO) {
+		if (hashp->bigdata_buf)
+			free(hashp->bigdata_buf);
+		totlen = len + BIGDATALEN(pagep);
+		hashp->bigdata_buf = (u_int8_t *)malloc(totlen);
+		if (!hashp->bigdata_buf)
+			return (-1);
+		memcpy(hashp->bigdata_buf + totlen - BIGDATALEN(pagep),
+		    BIGDATA(pagep), BIGDATALEN(pagep));
+		return (totlen);
+	}
+	totlen = len + BIGDATALEN(pagep);
+
+	/* Set pagep to the next page in the chain. */
+	next_pgno = NEXT_PGNO(pagep);
+	next_pagep = __get_page(hashp, next_pgno, A_RAW);
+	if (!next_pagep)
+		return (-1);
+
+#ifdef DEBUG
+	save_addr = ADDR(pagep);
+#endif
+	retval = collect_data(hashp, next_pagep, totlen);
+#ifdef DEBUG
+	assert(save_addr == ADDR(pagep));
+#endif
+	memcpy(hashp->bigdata_buf + totlen - BIGDATALEN(pagep),
+	    BIGDATA(pagep), BIGDATALEN(pagep));
+	__put_page(hashp, next_pagep, A_RAW, 0);
+
+	return (retval);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_debug.c b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_debug.c
new file mode 100644
index 000000000..69229fc8d
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_debug.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1995
+ *	The President and Fellows of Harvard University
+ *
+ * This code is derived from software contributed to Harvard by
+ * Jeremy Rassen.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_debug.c	8.4 (Berkeley) 11/7/95";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef DEBUG
+/*
+ * PACKAGE:  hashing
+ *
+ * DESCRIPTION:
+ *	Debug routines.
+ *
+ * ROUTINES:
+ *
+ * External
+ *	__dump_bucket
+ */
+#include <stdio.h>
+
+#include "db-int.h"
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+void
+__dump_bucket(hashp, bucket)
+	HTAB *hashp;
+	u_int32_t bucket;
+{
+	CURSOR cursor;
+	DBT key, val;
+	ITEM_INFO item_info;
+	int var;
+	char *cp;
+
+	cursor.pagep = NULL;
+	item_info.seek_size = 0;
+	item_info.seek_found_page = 0;
+
+	__get_item_reset(hashp, &cursor);
+
+	cursor.bucket = bucket;
+	for (;;) {
+		__get_item_next(hashp, &cursor, &key, &val, &item_info);
+		if (item_info.status == ITEM_ERROR) {
+			(void)printf("get_item_next returned error\n");
+			break;
+		} else if (item_info.status == ITEM_NO_MORE)
+			break;
+
+		if (item_info.key_off == BIGPAIR) {
+			if (__big_keydata(hashp, cursor.pagep, &key, &val,
+			    item_info.pgndx)) {
+				(void)printf("__big_keydata returned error\n");
+				break;
+			}
+		}
+
+		if (key.size == sizeof(int)) {
+			memcpy(&var, key.data, sizeof(int));
+			(void)printf("%d\n", var);
+		} else {
+			for (cp = (char *)key.data; key.size--; cp++)
+				(void)printf("%c", *cp);
+			(void)printf("\n");
+		}
+	}
+	__get_item_done(hashp, &cursor);
+}
+#endif /* DEBUG */
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_func.c b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_func.c
new file mode 100644
index 000000000..1dee69460
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_func.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_func.c	8.4 (Berkeley) 11/7/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include "db-int.h"
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+#if 0
+static u_int32_t hash1 __P((const void *, size_t));
+static u_int32_t hash2 __P((const void *, size_t));
+static u_int32_t hash3 __P((const void *, size_t));
+#endif
+static u_int32_t hash4 __P((const void *, size_t));
+
+/* Default hash function. */
+u_int32_t (*__default_hash) __P((const void *, size_t)) = hash4;
+
+/*
+ * Assume that we've already split the bucket to which this key hashes,
+ * calculate that bucket, and check that in fact we did already split it.
+ *
+ * EJB's original hsearch hash.
+ */
+#define PRIME1		37
+#define PRIME2		1048583
+
+#if 0
+static u_int32_t
+hash1(key, len)
+	const void *key;
+	size_t len;
+{
+	u_int32_t h;
+	u_int8_t *k;
+
+	h = 0;
+	k = (u_int8_t *)key;
+	/* Convert string to integer */
+	while (len--)
+		h = h * PRIME1 ^ (*k++ - ' ');
+	h %= PRIME2;
+	return (h);
+}
+
+/*
+ * Phong Vo's linear congruential hash
+ */
+#define dcharhash(h, c)	((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
+
+static u_int32_t
+hash2(key, len)
+	const void *key;
+	size_t len;
+{
+	u_int32_t h;
+	u_int8_t *e, c, *k;
+
+	k = (u_int8_t *)key;
+	e = k + len;
+	for (h = 0; k != e;) {
+		c = *k++;
+		if (!c && k > e)
+			break;
+		dcharhash(h, c);
+	}
+	return (h);
+}
+
+/*
+ * This is INCREDIBLY ugly, but fast.  We break the string up into 8 byte
+ * units.  On the first time through the loop we get the "leftover bytes"
+ * (strlen % 8).  On every other iteration, we perform 8 HASHC's so we handle
+ * all 8 bytes.  Essentially, this saves us 7 cmp & branch instructions.  If
+ * this routine is heavily used enough, it's worth the ugly coding.
+ *
+ * Ozan Yigit's original sdbm hash.
+ */
+static u_int32_t
+hash3(key, len)
+	const void *key;
+	size_t len;
+{
+	u_int32_t n, loop;
+	u_int8_t *k;
+
+#define HASHC   n = *k++ + 65599 * n
+
+	n = 0;
+	k = (u_int8_t *)key;
+	if (len > 0) {
+		loop = (len + 8 - 1) >> 3;
+
+		switch (len & (8 - 1)) {
+		case 0:
+			do {	/* All fall throughs */
+				HASHC;
+		case 7:
+				HASHC;
+		case 6:
+				HASHC;
+		case 5:
+				HASHC;
+		case 4:
+				HASHC;
+		case 3:
+				HASHC;
+		case 2:
+				HASHC;
+		case 1:
+				HASHC;
+			} while (--loop);
+		}
+
+	}
+	return (n);
+}
+#endif
+
+
+/* Chris Torek's hash function. */
+static u_int32_t
+hash4(key, len)
+	const void *key;
+	size_t len;
+{
+	u_int32_t h, loop;
+	const u_int8_t *k;
+
+#define HASH4a   h = (h << 5) - h + *k++;
+#define HASH4b   h = (h << 5) + h + *k++;
+#define HASH4 HASH4b
+
+	h = 0;
+	k = (const u_int8_t *)key;
+	if (len > 0) {
+		loop = (len + 8 - 1) >> 3;
+
+		switch (len & (8 - 1)) {
+		case 0:
+			do {	/* All fall throughs */
+				HASH4;
+		case 7:
+				HASH4;
+		case 6:
+				HASH4;
+		case 5:
+				HASH4;
+		case 4:
+				HASH4;
+		case 3:
+				HASH4;
+		case 2:
+				HASH4;
+		case 1:
+				HASH4;
+			} while (--loop);
+		}
+
+	}
+	return (h);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_log2.c b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_log2.c
new file mode 100644
index 000000000..8c710e5d2
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_log2.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_log2.c	8.4 (Berkeley) 11/7/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include "db-int.h"
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+u_int32_t
+__kdb2_log2(num)
+	u_int32_t num;
+{
+	u_int32_t i, limit;
+
+	limit = 1;
+	for (i = 0; limit < num; limit = limit << 1, i++);
+	return (i);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_page.c b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_page.c
new file mode 100644
index 000000000..e25115d3f
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hash_page.c
@@ -0,0 +1,1387 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hash_page.c	8.11 (Berkeley) 11/7/95";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * PACKAGE:  hashing
+ *
+ * DESCRIPTION:
+ *      Page manipulation for hashing package.
+ *
+ * ROUTINES:
+ *
+ * External
+ *      __get_page
+ *      __add_ovflpage
+ * Internal
+ *      overflow_page
+ *      open_temp
+ */
+
+#include <sys/types.h>
+
+#ifdef DEBUG
+#include <assert.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "db-int.h"
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static int32_t	 add_bigptr __P((HTAB *, ITEM_INFO *, indx_t));
+static u_int32_t *fetch_bitmap __P((HTAB *, int32_t));
+static u_int32_t first_free __P((u_int32_t));
+static indx_t	 next_realkey __P((PAGE16 *, indx_t));
+static u_int16_t overflow_page __P((HTAB *));
+static void	 page_init __P((HTAB *, PAGE16 *, db_pgno_t, u_int8_t));
+static indx_t	 prev_realkey __P((PAGE16 *, indx_t));
+static void	 putpair __P((PAGE8 *, const DBT *, const DBT *));
+static void	 swap_page_header_in __P((PAGE16 *));
+static void	 swap_page_header_out __P((PAGE16 *));
+
+#ifdef DEBUG_SLOW
+static void	 account_page(HTAB *, db_pgno_t, int);
+#endif
+
+u_int32_t
+__get_item(hashp, cursorp, key, val, item_info)
+	HTAB *hashp;
+	CURSOR *cursorp;
+	DBT *key, *val;
+	ITEM_INFO *item_info;
+{
+	db_pgno_t next_pgno;
+	int32_t i;
+
+	/* Check if we need to get a page. */
+	if (!cursorp->pagep) {
+		if (cursorp->pgno == INVALID_PGNO) {
+			cursorp->pagep =
+			    __get_page(hashp, cursorp->bucket, A_BUCKET);
+			cursorp->pgno = ADDR(cursorp->pagep);
+			cursorp->ndx = 0;
+			cursorp->pgndx = 0;
+		} else 
+			cursorp->pagep =
+			    __get_page(hashp, cursorp->pgno, A_RAW);
+		if (!cursorp->pagep) {
+			item_info->status = ITEM_ERROR;
+			return (-1);
+		}
+	}
+	if (item_info->seek_size &&
+	    FREESPACE(cursorp->pagep) > item_info->seek_size)
+		item_info->seek_found_page = cursorp->pgno;
+
+	if (cursorp->pgndx == NUM_ENT(cursorp->pagep)) {
+		/* Fetch next page. */
+		if (NEXT_PGNO(cursorp->pagep) == INVALID_PGNO) {
+			item_info->status = ITEM_NO_MORE;
+			return (-1);
+		}
+		next_pgno = NEXT_PGNO(cursorp->pagep);
+		cursorp->pgndx = 0;
+		__put_page(hashp, cursorp->pagep, A_RAW, 0);
+		cursorp->pagep = __get_page(hashp, next_pgno, A_RAW);
+		if (!cursorp->pagep) {
+			item_info->status = ITEM_ERROR;
+			return (-1);
+		}
+		cursorp->pgno = next_pgno;
+	}
+	if (KEY_OFF(cursorp->pagep, cursorp->pgndx) != BIGPAIR) {
+		if ((i = prev_realkey(cursorp->pagep, cursorp->pgndx)) ==
+		    cursorp->pgndx)
+			key->size = hashp->hdr.bsize -
+			    KEY_OFF(cursorp->pagep, cursorp->pgndx);
+		else
+			key->size = DATA_OFF(cursorp->pagep, i) -
+			    KEY_OFF(cursorp->pagep, cursorp->pgndx);
+	}
+
+	/* 
+	 * All of this information will be set incorrectly for big keys, but
+	 * it will be ignored anyway.
+	 */
+	val->size = KEY_OFF(cursorp->pagep, cursorp->pgndx) -
+	    DATA_OFF(cursorp->pagep, cursorp->pgndx);
+	key->data = KEY(cursorp->pagep, cursorp->pgndx);
+	val->data = DATA(cursorp->pagep, cursorp->pgndx);
+	item_info->pgno = cursorp->pgno;
+	item_info->bucket = cursorp->bucket;
+	item_info->ndx = cursorp->ndx;
+	item_info->pgndx = cursorp->pgndx;
+	item_info->key_off = KEY_OFF(cursorp->pagep, cursorp->pgndx);
+	item_info->data_off = DATA_OFF(cursorp->pagep, cursorp->pgndx);
+	item_info->status = ITEM_OK;
+
+	return (0);
+}
+
+u_int32_t
+__get_item_reset(hashp, cursorp)
+	HTAB *hashp;
+	CURSOR *cursorp;
+{
+	if (cursorp->pagep)
+		__put_page(hashp, cursorp->pagep, A_RAW, 0);
+	cursorp->pagep = NULL;
+	cursorp->bucket = -1;
+	cursorp->ndx = 0;
+	cursorp->pgndx = 0;
+	cursorp->pgno = INVALID_PGNO;
+	return (0);
+}
+
+u_int32_t
+__get_item_done(hashp, cursorp)
+	HTAB *hashp;
+	CURSOR *cursorp;
+{
+	if (cursorp->pagep)
+		__put_page(hashp, cursorp->pagep, A_RAW, 0);
+	cursorp->pagep = NULL;
+
+	/* 
+	 * We don't throw out the page number since we might want to
+	 * continue getting on this page.
+	 */
+	return (0);
+}
+
+u_int32_t
+__get_item_first(hashp, cursorp, key, val, item_info)
+	HTAB *hashp;
+	CURSOR *cursorp;
+	DBT *key, *val;
+	ITEM_INFO *item_info;
+{
+	__get_item_reset(hashp, cursorp);
+	cursorp->bucket = 0;
+	return (__get_item_next(hashp, cursorp, key, val, item_info));
+}
+
+/*
+ * Returns a pointer to key/data pair on a page.  In the case of bigkeys,
+ * just returns the page number and index of the bigkey pointer pair.
+ */
+u_int32_t
+__get_item_next(hashp, cursorp, key, val, item_info)
+	HTAB *hashp;
+	CURSOR *cursorp;
+	DBT *key, *val;
+	ITEM_INFO *item_info;
+{
+	int status;
+
+	status = __get_item(hashp, cursorp, key, val, item_info);
+	cursorp->ndx++;
+	cursorp->pgndx++;
+	return (status);
+}
+
+/*
+ * Put a non-big pair on a page.
+ */
+static void
+putpair(p, key, val)
+	PAGE8 *p;
+	const DBT *key, *val;
+{
+	u_int16_t *pagep, n, off;
+
+	pagep = (PAGE16 *)p;
+
+	/* Items on the page are 0-indexed. */
+	n = NUM_ENT(pagep);
+	off = OFFSET(pagep) - key->size + 1;
+	memmove(p + off, key->data, key->size);
+	KEY_OFF(pagep, n) = off;
+
+	off -= val->size;
+	memmove(p + off, val->data, val->size);
+	DATA_OFF(pagep, n) = off;
+
+	/* Adjust page info. */
+	NUM_ENT(pagep) = n + 1;
+	OFFSET(pagep) = off - 1;
+}
+
+/*
+ * Returns the index of the next non-bigkey pair after n on the page.
+ * Returns -1 if there are no more non-big things on the page.
+ */
+static indx_t
+#ifdef __STDC__
+next_realkey(PAGE16 * pagep, indx_t n)
+#else
+next_realkey(pagep, n)
+	PAGE16 *pagep;
+	u_int32_t n;
+#endif
+{
+	indx_t i;
+
+	for (i = n + 1; i < NUM_ENT(pagep); i++)
+		if (KEY_OFF(pagep, i) != BIGPAIR)
+			return (i);
+	return (-1);
+}
+
+/*
+ * Returns the index of the previous non-bigkey pair after n on the page.
+ * Returns n if there are no previous non-big things on the page.
+ */
+static indx_t
+#ifdef __STDC__
+prev_realkey(PAGE16 * pagep, indx_t n)
+#else
+prev_realkey(pagep, n)
+	PAGE16 *pagep;
+	u_int32_t n;
+#endif
+{
+	int32_t i;
+
+	/* Need a signed value to do the compare properly. */
+	for (i = n - 1; i > -1; i--)
+		if (KEY_OFF(pagep, i) != BIGPAIR)
+			return (i);
+	return (n);
+}
+
+/*
+ * Returns:
+ *       0 OK
+ *      -1 error
+ */
+extern int32_t
+__delpair(hashp, cursorp, item_info)
+	HTAB *hashp;
+	CURSOR *cursorp;
+	ITEM_INFO *item_info;
+{
+	PAGE16 *pagep;
+	indx_t ndx;
+	short check_ndx;
+	int16_t delta, len, next_key;
+	int32_t n;
+	u_int8_t *src, *dest;
+
+	ndx = cursorp->pgndx;
+	if (!cursorp->pagep) {
+		pagep = __get_page(hashp, cursorp->pgno, A_RAW);
+		if (!pagep)
+			return (-1);
+		/*
+		 * KLUGE: pgndx has gone one too far, because cursor points
+		 * to the _next_ item.  Use pgndx - 1.
+		 */
+		--ndx;
+	} else
+		pagep = cursorp->pagep;
+#ifdef DEBUG
+	assert(ADDR(pagep) == cursorp->pgno);
+#endif
+
+	if (KEY_OFF(pagep, ndx) == BIGPAIR) {
+		delta = 0;
+		__big_delete(hashp, pagep, ndx);
+	} else {
+		/*
+		 * Compute "delta", the amount we have to shift all of the
+		 * offsets.  To find the delta, we need to make sure that
+		 * we aren't looking at the DATA_OFF of a big/keydata pair.
+		 */
+		for (check_ndx = (short)(ndx - 1);
+		    check_ndx >= 0 && KEY_OFF(pagep, check_ndx) == BIGPAIR;
+		    check_ndx--);
+		if (check_ndx < 0)
+			delta = hashp->hdr.bsize - DATA_OFF(pagep, ndx);
+		else
+			delta =
+			    DATA_OFF(pagep, check_ndx) - DATA_OFF(pagep, ndx);
+
+		/*
+		 * The hard case: we want to remove something other than
+		 * the last item on the page.  We need to shift data and
+		 * offsets down.
+		 */
+		if (ndx != NUM_ENT(pagep) - 1) {
+			/*
+			 * Move the data: src is the address of the last data
+			 * item on the page.
+			 */
+			src = (u_int8_t *)pagep + OFFSET(pagep) + 1;
+			/* 
+			 * Length is the distance between where to start
+			 * deleting and end of the data on the page.
+			 */
+			len = DATA_OFF(pagep, ndx) - (OFFSET(pagep) + 1);
+			/*
+			 * Dest is the location of the to-be-deleted item
+			 * occupied - length.
+			 */
+			if (check_ndx < 0)
+				dest =
+				    (u_int8_t *)pagep + hashp->hdr.bsize - len;
+			else
+				dest = (u_int8_t *)pagep +
+				    DATA_OFF(pagep, (check_ndx)) - len;
+			memmove(dest, src, len);
+		}
+	}
+
+	/* Adjust the offsets. */
+	for (n = ndx; n < NUM_ENT(pagep) - 1; n++)
+		if (KEY_OFF(pagep, (n + 1)) != BIGPAIR) {
+			next_key = next_realkey(pagep, n);
+#ifdef DEBUG
+			assert(next_key != -1);
+#endif
+			KEY_OFF(pagep, n) = KEY_OFF(pagep, (n + 1)) + delta;
+			DATA_OFF(pagep, n) = DATA_OFF(pagep, (n + 1)) + delta;
+		} else {
+			KEY_OFF(pagep, n) = KEY_OFF(pagep, (n + 1));
+			DATA_OFF(pagep, n) = DATA_OFF(pagep, (n + 1));
+		}
+
+	/* Adjust page metadata. */
+	OFFSET(pagep) = OFFSET(pagep) + delta;
+	NUM_ENT(pagep) = NUM_ENT(pagep) - 1;
+
+	--hashp->hdr.nkeys;
+
+	/* Is this page now an empty overflow page?  If so, free it. */
+	if (TYPE(pagep) == HASH_OVFLPAGE && NUM_ENT(pagep) == 0) {
+		PAGE16 *empty_page;
+		db_pgno_t to_find, next_pgno, link_page;
+
+		/*
+		 * We need to go back to the first page in the chain and 
+		 * look for this page so that we can update the previous
+		 * page's NEXT_PGNO field.
+		 */
+		to_find = ADDR(pagep);
+		empty_page = pagep;
+		link_page = NEXT_PGNO(empty_page);
+		pagep = __get_page(hashp, item_info->bucket, A_BUCKET);
+		if (!pagep)
+			return (-1);
+		while (NEXT_PGNO(pagep) != to_find) {
+			next_pgno = NEXT_PGNO(pagep);
+#ifdef DEBUG
+			assert(next_pgno != INVALID_PGNO);
+#endif
+			__put_page(hashp, pagep, A_RAW, 0);
+			pagep = __get_page(hashp, next_pgno, A_RAW);
+			if (!pagep)
+				return (-1);
+		}
+
+		/*
+		 * At this point, pagep should point to the page before the
+		 * page to be deleted.
+		 */
+		NEXT_PGNO(pagep) = link_page;
+		if (item_info->pgno == to_find) {
+			item_info->pgno = ADDR(pagep);
+			item_info->pgndx = NUM_ENT(pagep);
+			item_info->seek_found_page = ADDR(pagep);
+		}
+		__delete_page(hashp, empty_page, A_OVFL);
+	}
+	__put_page(hashp, pagep, A_RAW, 1);
+
+	return (0);
+}
+
+extern int32_t
+__split_page(hashp, obucket, nbucket)
+	HTAB *hashp;
+	u_int32_t obucket, nbucket;
+{
+	DBT key, val;
+	ITEM_INFO old_ii, new_ii;
+	PAGE16 *old_pagep, *temp_pagep;
+	db_pgno_t next_pgno;
+	int32_t off;
+	u_int16_t n;
+	int8_t base_page;
+
+	off = hashp->hdr.bsize;
+	old_pagep = __get_page(hashp, obucket, A_BUCKET);
+
+	base_page = 1;
+
+	temp_pagep = hashp->split_buf;
+	memcpy(temp_pagep, old_pagep, hashp->hdr.bsize);
+
+	page_init(hashp, old_pagep, ADDR(old_pagep), HASH_PAGE);
+	__put_page(hashp, old_pagep, A_RAW, 1);
+
+	old_ii.pgno = BUCKET_TO_PAGE(obucket);
+	new_ii.pgno = BUCKET_TO_PAGE(nbucket);
+	old_ii.bucket = obucket;
+	new_ii.bucket = nbucket;
+	old_ii.seek_found_page = new_ii.seek_found_page = 0;
+
+	while (temp_pagep != 0) {
+		off = hashp->hdr.bsize;
+		for (n = 0; n < NUM_ENT(temp_pagep); n++) {
+			if (KEY_OFF(temp_pagep, n) == BIGPAIR) {
+				__get_bigkey(hashp, temp_pagep, n, &key);
+				if (__call_hash(hashp,
+				    key.data, key.size) == obucket)
+					add_bigptr(hashp, &old_ii,
+					    DATA_OFF(temp_pagep, n));
+				else
+					add_bigptr(hashp, &new_ii,
+					    DATA_OFF(temp_pagep, n));
+			} else {
+				key.size = off - KEY_OFF(temp_pagep, n);
+				key.data = KEY(temp_pagep, n);
+				off = KEY_OFF(temp_pagep, n);
+				val.size = off - DATA_OFF(temp_pagep, n);
+				val.data = DATA(temp_pagep, n);
+				if (__call_hash(hashp,
+				    key.data, key.size) == obucket)
+					__addel(hashp, &old_ii, &key, &val,
+					    NO_EXPAND, 1);
+				else
+					__addel(hashp, &new_ii, &key, &val,
+					    NO_EXPAND, 1);
+				off = DATA_OFF(temp_pagep, n);
+			}
+		}
+		next_pgno = NEXT_PGNO(temp_pagep);
+
+		/* Clear temp_page; if it's an overflow page, free it. */
+		if (!base_page)
+			__delete_page(hashp, temp_pagep, A_OVFL);
+		else
+			base_page = 0;
+		if (next_pgno != INVALID_PGNO)
+			temp_pagep = __get_page(hashp, next_pgno, A_RAW);
+		else
+			break;
+	}
+	return (0);
+}
+
+/*
+ * Add the given pair to the page.  
+ *
+ *
+ * Returns:
+ *       0 ==> OK
+ *	-1 ==> failure
+ */
+extern  int32_t
+#ifdef __STDC__
+__addel(HTAB *hashp, ITEM_INFO *item_info, const DBT *key, const DBT *val,
+    u_int32_t num_items, const u_int8_t expanding)
+#else
+__addel(hashp, item_info, key, val, num_items, expanding)
+	HTAB *hashp;
+	ITEM_INFO *item_info;
+	const DBT *key, *val;
+	u_int32_t num_items;
+	const u_int32_t expanding;
+#endif
+{
+	PAGE16 *pagep;
+	int32_t do_expand;
+	db_pgno_t next_pgno;
+
+	do_expand = 0;
+
+	pagep = __get_page(hashp,
+	    item_info->seek_found_page != 0 ?
+	    item_info->seek_found_page : item_info->pgno, A_RAW);
+	if (!pagep)
+		return (-1);
+
+	/* Advance to first page in chain with room for item. */
+	while (NUM_ENT(pagep) && NEXT_PGNO(pagep) != INVALID_PGNO) {
+		/* 
+		 * This may not be the end of the chain, but the pair may fit
+		 * anyway.
+		 */
+		if (ISBIG(PAIRSIZE(key, val), hashp) && BIGPAIRFITS(pagep))
+			break;
+		if (PAIRFITS(pagep, key, val))
+			break;
+		next_pgno = NEXT_PGNO(pagep);
+		__put_page(hashp, pagep, A_RAW, 0);
+		pagep = (PAGE16 *)__get_page(hashp, next_pgno, A_RAW);
+		if (!pagep)
+			return (-1);
+	}
+
+	if ((ISBIG(PAIRSIZE(key, val), hashp) &&
+	     !BIGPAIRFITS(pagep)) ||
+	    (!ISBIG(PAIRSIZE(key, val), hashp) &&
+	     !PAIRFITS(pagep, key, val))) {
+		do_expand = 1;
+		pagep = __add_ovflpage(hashp, pagep);
+		if (!pagep)
+			return (-1);
+
+		if ((ISBIG(PAIRSIZE(key, val), hashp) &&
+		     !BIGPAIRFITS(pagep)) ||
+		    (!ISBIG(PAIRSIZE(key, val), hashp) &&
+		     !PAIRFITS(pagep, key, val))) {
+			__put_page(hashp, pagep, A_RAW, 0);
+			return (-1);
+		}
+	}
+ 
+	/* At this point, we know the page fits, so we just add it */
+ 
+	if (ISBIG(PAIRSIZE(key, val), hashp)) {
+		if (__big_insert(hashp, pagep, key, val))
+			return (-1);
+	} else {
+		putpair((PAGE8 *)pagep, key, val);
+	}
+
+	/*
+	 * For splits, we are going to update item_info's page number
+	 * field, so that we can easily return to the same page the
+	 * next time we come in here.  For other operations, this shouldn't
+	 * matter, since adds are the last thing that happens before we
+	 * return to the user program.
+	 */
+	item_info->pgno = ADDR(pagep);
+
+	if (!expanding)
+		hashp->hdr.nkeys++;
+
+	/* Kludge: if this is a big page, then it's already been put. */
+	if (!ISBIG(PAIRSIZE(key, val), hashp))
+		__put_page(hashp, pagep, A_RAW, 1);
+
+	if (expanding)
+		item_info->caused_expand = 0;
+	else
+		switch (num_items) {
+		case NO_EXPAND:
+			item_info->caused_expand = 0;
+			break;
+		case UNKNOWN:
+			item_info->caused_expand |=
+			    (hashp->hdr.nkeys / hashp->hdr.max_bucket) >
+			    hashp->hdr.ffactor ||
+			    item_info->pgndx > hashp->hdr.ffactor;
+			break;
+		default:
+			item_info->caused_expand =
+			    num_items > hashp->hdr.ffactor ? 1 : do_expand;
+			break;
+		}
+	return (0);
+}
+
+/* 
+ * Special __addel used in big splitting; this one just puts the pointer
+ * to an already-allocated big page in the appropriate bucket.
+ */
+static int32_t
+#ifdef __STDC__
+add_bigptr(HTAB * hashp, ITEM_INFO * item_info, indx_t big_pgno)
+#else
+add_bigptr(hashp, item_info, big_pgno)
+	HTAB *hashp;
+	ITEM_INFO *item_info;
+	u_int32_t big_pgno;
+#endif
+{
+	PAGE16 *pagep;
+	db_pgno_t next_pgno;
+
+	pagep = __get_page(hashp, item_info->bucket, A_BUCKET);
+	if (!pagep)
+		return (-1);
+
+	/*
+	 * Note: in __addel(), we used item_info->pgno for the beginning of
+	 * our search for space.  Now, we use item_info->bucket, since we
+	 * know that the space required by a big pair on the base page is
+	 * quite small, and we may very well find that space early in the
+	 * chain.
+	 */
+
+	/* Find first page in chain that has space for a big pair. */
+	while (NUM_ENT(pagep) && (NEXT_PGNO(pagep) != INVALID_PGNO)) {
+		if (BIGPAIRFITS(pagep))
+			break;
+		next_pgno = NEXT_PGNO(pagep);
+		__put_page(hashp, pagep, A_RAW, 0);
+		pagep = __get_page(hashp, next_pgno, A_RAW);
+		if (!pagep)
+			return (-1);
+	}
+	if (!BIGPAIRFITS(pagep)) {
+		pagep = __add_ovflpage(hashp, pagep);
+		if (!pagep)
+			return (-1);
+#ifdef DEBUG
+		assert(BIGPAIRFITS(pagep));
+#endif
+	}
+	KEY_OFF(pagep, NUM_ENT(pagep)) = BIGPAIR;
+	DATA_OFF(pagep, NUM_ENT(pagep)) = big_pgno;
+	NUM_ENT(pagep) = NUM_ENT(pagep) + 1;
+
+	__put_page(hashp, pagep, A_RAW, 1);
+
+	return (0);
+}
+
+/*
+ *
+ * Returns:
+ *      pointer on success
+ *      NULL on error
+ */
+extern PAGE16 *
+__add_ovflpage(hashp, pagep)
+	HTAB *hashp;
+	PAGE16 *pagep;
+{
+	PAGE16 *new_pagep;
+	u_int16_t ovfl_num;
+
+	/* Check if we are dynamically determining the fill factor. */
+	if (hashp->hdr.ffactor == DEF_FFACTOR) {
+		hashp->hdr.ffactor = NUM_ENT(pagep) >> 1;
+		if (hashp->hdr.ffactor < MIN_FFACTOR)
+			hashp->hdr.ffactor = MIN_FFACTOR;
+	}
+	ovfl_num = overflow_page(hashp);
+	if (!ovfl_num)
+		return (NULL);
+
+	if (__new_page(hashp, (u_int32_t)ovfl_num, A_OVFL) != 0)
+		return (NULL);
+
+	if (!ovfl_num || !(new_pagep = __get_page(hashp, ovfl_num, A_OVFL)))
+		return (NULL);
+
+	NEXT_PGNO(pagep) = (db_pgno_t)OADDR_TO_PAGE(ovfl_num);
+	TYPE(new_pagep) = HASH_OVFLPAGE;
+
+	__put_page(hashp, pagep, A_RAW, 1);
+
+#ifdef HASH_STATISTICS
+	hash_overflows++;
+#endif
+	return (new_pagep);
+}
+
+/*
+ *
+ * Returns:
+ *      pointer on success
+ *      NULL on error
+ */
+extern PAGE16 *
+#ifdef __STDC__
+__add_bigpage(HTAB * hashp, PAGE16 * pagep, indx_t ndx, const u_int8_t
+    is_basepage)
+#else
+__add_bigpage(hashp, pagep, ndx, is_basepage)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	u_int32_t ndx;
+	const u_int32_t is_basepage;
+#endif
+{
+	PAGE16 *new_pagep;
+	u_int16_t ovfl_num;
+
+	ovfl_num = overflow_page(hashp);
+	if (!ovfl_num)
+		return (NULL);
+
+	if (__new_page(hashp, (u_int32_t)ovfl_num, A_OVFL) != 0)
+		return (NULL);
+
+	if (!ovfl_num || !(new_pagep = __get_page(hashp, ovfl_num, A_OVFL)))
+		return (NULL);
+
+	if (is_basepage) {
+		KEY_OFF(pagep, ndx) = BIGPAIR;
+		DATA_OFF(pagep, ndx) = (indx_t)ovfl_num;
+	} else
+		NEXT_PGNO(pagep) = ADDR(new_pagep);
+
+	__put_page(hashp, pagep, A_RAW, 1);
+
+	TYPE(new_pagep) = HASH_BIGPAGE;
+
+#ifdef HASH_STATISTICS
+	hash_bigpages++;
+#endif
+	return (new_pagep);
+}
+
+static void
+#ifdef __STDC__
+page_init(HTAB * hashp, PAGE16 * pagep, db_pgno_t pgno, u_int8_t type)
+#else
+page_init(hashp, pagep, pgno, type)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	db_pgno_t pgno;
+	u_int32_t type;
+#endif
+{
+	NUM_ENT(pagep) = 0;
+	PREV_PGNO(pagep) = NEXT_PGNO(pagep) = INVALID_PGNO;
+	TYPE(pagep) = type;
+	OFFSET(pagep) = hashp->hdr.bsize - 1;
+	/*
+	 * Note: since in the current version ADDR(pagep) == PREV_PGNO(pagep),
+	 * make sure that ADDR(pagep) is set after resetting PREV_PGNO(pagep).
+	 * We reset PREV_PGNO(pagep) just in case the macros are changed.
+	 */
+	ADDR(pagep) = pgno;
+
+	return;
+}
+
+int32_t
+__new_page(hashp, addr, addr_type)
+	HTAB *hashp;
+	u_int32_t addr;
+	int32_t addr_type;
+{
+	db_pgno_t paddr;
+	PAGE16 *pagep;
+
+	switch (addr_type) {		/* Convert page number. */
+	case A_BUCKET:
+		paddr = BUCKET_TO_PAGE(addr);
+		break;
+	case A_OVFL:
+	case A_BITMAP:
+		paddr = OADDR_TO_PAGE(addr);
+		break;
+	default:
+		paddr = addr;
+		break;
+	}
+	pagep = mpool_new(hashp->mp, &paddr, MPOOL_PAGE_REQUEST);
+	if (!pagep)
+		return (-1);
+#if DEBUG_SLOW
+	account_page(hashp, paddr, 1);
+#endif
+
+	if (addr_type != A_BITMAP)
+		page_init(hashp, pagep, paddr, HASH_PAGE);
+
+	__put_page(hashp, pagep, addr_type, 1);
+
+	return (0);
+}
+
+int32_t
+__delete_page(hashp, pagep, page_type)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	int32_t page_type;
+{
+	if (page_type == A_OVFL)
+		__free_ovflpage(hashp, pagep);
+	return (mpool_delete(hashp->mp, pagep));
+}
+
+static u_int8_t
+is_bitmap_pgno(hashp, pgno)
+	HTAB *hashp;
+	db_pgno_t pgno;
+{
+	int32_t i;
+
+	for (i = 0; i < hashp->nmaps; i++)
+		if (OADDR_TO_PAGE(hashp->hdr.bitmaps[i]) == pgno)
+			return (1);
+	return (0);
+}
+
+void
+__pgin_routine(pg_cookie, pgno, page)
+	void *pg_cookie;
+	db_pgno_t pgno;
+	void *page;
+{
+	HTAB *hashp;
+	PAGE16 *pagep;
+	int32_t max, i;
+
+	pagep = (PAGE16 *)page;
+	hashp = (HTAB *)pg_cookie;
+
+	/* 
+	 * There are the following cases for swapping: 
+	 * 0) New page that may be unitialized.
+	 * 1) Bucket page or overflow page.  Either swap
+	 *	the header or initialize the page.
+	 * 2) Bitmap page.  Swap the whole page!
+	 * 3) Header pages.  Not handled here; these are written directly
+	 *    to the file.
+	 */
+
+	if (NUM_ENT(pagep) == 0 && NEXT_PGNO(pagep) == 0 &&
+	    !is_bitmap_pgno(hashp, pgno)) {
+		/* XXX check for !0 LSN */
+		page_init(hashp, pagep, pgno, HASH_PAGE);
+		return;
+	}
+
+	if (hashp->hdr.lorder == DB_BYTE_ORDER)
+		return;
+	if (is_bitmap_pgno(hashp, pgno)) {
+		max = hashp->hdr.bsize >> 2;	/* divide by 4 bytes */
+		for (i = 0; i < max; i++)
+			M_32_SWAP(((int32_t *)pagep)[i]);
+	} else
+		swap_page_header_in(pagep);
+}
+
+void
+__pgout_routine(pg_cookie, pgno, page)
+	void *pg_cookie;
+	db_pgno_t pgno;
+	void *page;
+{
+	HTAB *hashp;
+	PAGE16 *pagep;
+	int32_t i, max;
+
+	pagep = (PAGE16 *)page;
+	hashp = (HTAB *)pg_cookie;
+
+	/* 
+	 * There are the following cases for swapping: 
+	 * 1) Bucket page or overflow page.  Just swap the header.
+	 * 2) Bitmap page.  Swap the whole page!
+	 * 3) Header pages.  Not handled here; these are written directly
+	 *    to the file.
+	 */
+
+	if (hashp->hdr.lorder == DB_BYTE_ORDER)
+		return;
+	if (is_bitmap_pgno(hashp, pgno)) {
+		max = hashp->hdr.bsize >> 2;	/* divide by 4 bytes */
+		for (i = 0; i < max; i++)
+			M_32_SWAP(((int32_t *)pagep)[i]);
+	} else
+		swap_page_header_out(pagep);
+}
+
+/*
+ *
+ * Returns:
+ *       0 ==> OK
+ *      -1 ==>failure
+ */
+extern int32_t
+__put_page(hashp, pagep, addr_type, is_dirty)
+	HTAB *hashp;
+	PAGE16 *pagep;
+	int32_t addr_type, is_dirty;
+{
+#if DEBUG_SLOW
+	account_page(hashp,
+	    ((BKT *)((char *)pagep - sizeof(BKT)))->pgno, -1);
+#endif
+
+	return (mpool_put(hashp->mp, pagep, (is_dirty ? MPOOL_DIRTY : 0)));
+}
+
+/*
+ * Returns:
+ *       0 indicates SUCCESS
+ *      -1 indicates FAILURE
+ */
+extern PAGE16 *
+__get_page(hashp, addr, addr_type)
+	HTAB *hashp;
+	u_int32_t addr;
+	int32_t addr_type;
+{
+	PAGE16 *pagep;
+	db_pgno_t paddr;
+
+	switch (addr_type) {			/* Convert page number. */
+	case A_BUCKET:
+		paddr = BUCKET_TO_PAGE(addr);
+		break;
+	case A_OVFL:
+	case A_BITMAP:
+		paddr = OADDR_TO_PAGE(addr);
+		break;
+	default:
+		paddr = addr;
+		break;
+	}
+	pagep = (PAGE16 *)mpool_get(hashp->mp, paddr, 0);
+
+#if DEBUG_SLOW
+	account_page(hashp, paddr, 1);
+#endif
+#ifdef DEBUG
+	assert(ADDR(pagep) == paddr || ADDR(pagep) == 0 ||
+	    addr_type == A_BITMAP || addr_type == A_HEADER);
+#endif
+
+	return (pagep);
+}
+
+static void
+swap_page_header_in(pagep)
+	PAGE16 *pagep;
+{
+	u_int32_t i;
+
+	/* can leave type and filler alone, since they're 1-byte quantities */
+
+	M_32_SWAP(PREV_PGNO(pagep));
+	M_32_SWAP(NEXT_PGNO(pagep));
+	M_16_SWAP(NUM_ENT(pagep));
+	M_16_SWAP(OFFSET(pagep));
+
+	for (i = 0; i < NUM_ENT(pagep); i++) {
+		M_16_SWAP(KEY_OFF(pagep, i));
+		M_16_SWAP(DATA_OFF(pagep, i));
+	}
+}
+
+static void
+swap_page_header_out(pagep)
+	PAGE16 *pagep;
+{
+	u_int32_t i;
+
+	for (i = 0; i < NUM_ENT(pagep); i++) {
+		M_16_SWAP(KEY_OFF(pagep, i));
+		M_16_SWAP(DATA_OFF(pagep, i))
+	}
+
+	/* can leave type and filler alone, since they're 1-byte quantities */
+
+	M_32_SWAP(PREV_PGNO(pagep));
+	M_32_SWAP(NEXT_PGNO(pagep));
+	M_16_SWAP(NUM_ENT(pagep));
+	M_16_SWAP(OFFSET(pagep));
+}
+
+#define BYTE_MASK	((1 << INT32_T_BYTE_SHIFT) -1)
+/*
+ * Initialize a new bitmap page.  Bitmap pages are left in memory
+ * once they are read in.
+ */
+extern int32_t
+__ibitmap(hashp, pnum, nbits, ndx)
+	HTAB *hashp;
+	int32_t pnum, nbits, ndx;
+{
+	u_int32_t *ip;
+	int32_t clearbytes, clearints;
+
+	/* make a new bitmap page */
+	if (__new_page(hashp, pnum, A_BITMAP) != 0)
+		return (1);
+	if (!(ip = (u_int32_t *)__get_page(hashp, pnum, A_BITMAP)))
+		return (1);
+	hashp->nmaps++;
+	clearints = ((nbits - 1) >> INT32_T_BYTE_SHIFT) + 1;
+	clearbytes = clearints << INT32_T_TO_BYTE;
+	(void)memset((int8_t *)ip, 0, clearbytes);
+	(void)memset((int8_t *)ip + clearbytes,
+	    0xFF, hashp->hdr.bsize - clearbytes);
+	ip[clearints - 1] = ALL_SET << (nbits & BYTE_MASK);
+	SETBIT(ip, 0);
+	hashp->hdr.bitmaps[ndx] = (u_int16_t)pnum;
+	hashp->mapp[ndx] = ip;
+	return (0);
+}
+
+static u_int32_t
+first_free(map)
+	u_int32_t map;
+{
+	u_int32_t i, mask;
+
+	for (mask = 0x1, i = 0; i < BITS_PER_MAP; i++) {
+		if (!(mask & map))
+			return (i);
+		mask = mask << 1;
+	}
+	return (i);
+}
+
+/*
+ * returns 0 on error
+ */
+static u_int16_t
+overflow_page(hashp)
+	HTAB *hashp;
+{
+	u_int32_t *freep;
+	int32_t bit, first_page, free_bit, free_page, i, in_use_bits, j;
+	int32_t max_free, offset, splitnum;
+	u_int16_t addr;
+#ifdef DEBUG2
+	int32_t tmp1, tmp2;
+#endif
+
+	splitnum = hashp->hdr.ovfl_point;
+	max_free = hashp->hdr.spares[splitnum];
+
+	free_page = (max_free - 1) >> (hashp->hdr.bshift + BYTE_SHIFT);
+	free_bit = (max_free - 1) & ((hashp->hdr.bsize << BYTE_SHIFT) - 1);
+
+	/*
+	 * Look through all the free maps to find the first free block.
+ 	 * The compiler under -Wall will complain that freep may be used
+	 * before being set, however, this loop will ALWAYS get executed
+	 * at least once, so freep is guaranteed to be set.
+	 */
+	first_page = hashp->hdr.last_freed >> (hashp->hdr.bshift + BYTE_SHIFT);
+	for (i = first_page; i <= free_page; i++) {
+		if (!(freep = fetch_bitmap(hashp, i)))
+			return (0);
+		if (i == free_page)
+			in_use_bits = free_bit;
+		else
+			in_use_bits = (hashp->hdr.bsize << BYTE_SHIFT) - 1;
+
+		if (i == first_page) {
+			bit = hashp->hdr.last_freed &
+			    ((hashp->hdr.bsize << BYTE_SHIFT) - 1);
+			j = bit / BITS_PER_MAP;
+			bit = bit & ~(BITS_PER_MAP - 1);
+		} else {
+			bit = 0;
+			j = 0;
+		}
+		for (; bit <= in_use_bits; j++, bit += BITS_PER_MAP)
+			if (freep[j] != ALL_SET)
+				goto found;
+	}
+
+	/* No Free Page Found */
+	hashp->hdr.last_freed = hashp->hdr.spares[splitnum];
+	hashp->hdr.spares[splitnum]++;
+	offset = hashp->hdr.spares[splitnum] -
+	    (splitnum ? hashp->hdr.spares[splitnum - 1] : 0);
+
+#define	OVMSG	"HASH: Out of overflow pages.  Increase page size\n"
+
+	if (offset > SPLITMASK) {
+		if (++splitnum >= NCACHED) {
+			(void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
+			return (0);
+		}
+		hashp->hdr.ovfl_point = splitnum;
+		hashp->hdr.spares[splitnum] = hashp->hdr.spares[splitnum - 1];
+		hashp->hdr.spares[splitnum - 1]--;
+		offset = 1;
+	}
+	/* Check if we need to allocate a new bitmap page. */
+	if (free_bit == (hashp->hdr.bsize << BYTE_SHIFT) - 1) {
+		free_page++;
+		if (free_page >= NCACHED) {
+			(void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
+			return (0);
+		}
+		/*
+		 * This is tricky.  The 1 indicates that you want the new page
+		 * allocated with 1 clear bit.  Actually, you are going to
+		 * allocate 2 pages from this map.  The first is going to be
+		 * the map page, the second is the overflow page we were
+		 * looking for.  The __ibitmap routine automatically, sets
+		 * the first bit of itself to indicate that the bitmap itself
+		 * is in use.  We would explicitly set the second bit, but
+		 * don't have to if we tell __ibitmap not to leave it clear
+		 * in the first place.
+		 */
+		if (__ibitmap(hashp,
+		    (int32_t)OADDR_OF(splitnum, offset), 1, free_page))
+			return (0);
+		hashp->hdr.spares[splitnum]++;
+#ifdef DEBUG2
+		free_bit = 2;
+#endif
+		offset++;
+		if (offset > SPLITMASK) {
+			if (++splitnum >= NCACHED) {
+				(void)write(STDERR_FILENO,
+				    OVMSG, sizeof(OVMSG) - 1);
+				return (0);
+			}
+			hashp->hdr.ovfl_point = splitnum;
+			hashp->hdr.spares[splitnum] =
+			    hashp->hdr.spares[splitnum - 1];
+			hashp->hdr.spares[splitnum - 1]--;
+			offset = 0;
+		}
+	} else {
+		/*
+		 * Free_bit addresses the last used bit.  Bump it to address
+		 * the first available bit.
+		 */
+		free_bit++;
+		SETBIT(freep, free_bit);
+	}
+
+	/* Calculate address of the new overflow page */
+	addr = OADDR_OF(splitnum, offset);
+#ifdef DEBUG2
+	(void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
+	    addr, free_bit, free_page);
+#endif
+
+	if (OADDR_TO_PAGE(addr) > MAX_PAGES(hashp)) {
+		(void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
+		return (0);
+	}
+	return (addr);
+
+found:
+	bit = bit + first_free(freep[j]);
+	SETBIT(freep, bit);
+#ifdef DEBUG2
+	tmp1 = bit;
+	tmp2 = i;
+#endif
+	/*
+	 * Bits are addressed starting with 0, but overflow pages are addressed
+	 * beginning at 1. Bit is a bit address number, so we need to increment
+	 * it to convert it to a page number.
+	 */
+	bit = 1 + bit + (i * (hashp->hdr.bsize << BYTE_SHIFT));
+	if (bit >= hashp->hdr.last_freed)
+		hashp->hdr.last_freed = bit - 1;
+
+	/* Calculate the split number for this page */
+	for (i = 0; i < splitnum && (bit > hashp->hdr.spares[i]); i++);
+	offset = (i ? bit - hashp->hdr.spares[i - 1] : bit);
+	if (offset >= SPLITMASK)
+		return (0);	/* Out of overflow pages */
+	addr = OADDR_OF(i, offset);
+#ifdef DEBUG2
+	(void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
+	    addr, tmp1, tmp2);
+#endif
+
+	if (OADDR_TO_PAGE(addr) > MAX_PAGES(hashp)) {
+		(void)write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
+		return (0);
+	}
+	/* Allocate and return the overflow page */
+	return (addr);
+}
+
+#ifdef DEBUG
+int
+bucket_to_page(hashp, n)
+	HTAB *hashp;
+	int n;
+{
+	int ret_val;
+
+	ret_val = n + hashp->hdr.hdrpages;
+	if (n != 0)
+		ret_val += hashp->hdr.spares[__log2(n + 1) - 1];
+	return (ret_val);
+}
+
+int32_t
+oaddr_to_page(hashp, n)
+	HTAB *hashp;
+	int n;
+{
+	int ret_val, temp;
+
+	temp = (1 << SPLITNUM(n)) - 1;
+	ret_val = bucket_to_page(hashp, temp);
+	ret_val += (n & SPLITMASK);
+
+	return (ret_val);
+}
+#endif /* DEBUG */
+
+static indx_t
+page_to_oaddr(hashp, pgno)
+	HTAB *hashp;
+	db_pgno_t pgno;
+{
+	int32_t sp, ret_val;
+
+	/*
+	 * To convert page number to overflow address:
+	 *
+	 * 1.  Find a starting split point -- use 0 since there are only
+	 *     32 split points.
+	 * 2.  Find the split point s.t. 2^sp + hdr.spares[sp] < pgno and
+	 *     2^(sp+1) = hdr.spares[sp+1] > pgno.  The overflow address will
+	 *     be located at sp.
+	 * 3.  return...
+	 */
+	pgno -= hashp->hdr.hdrpages;
+	for (sp = 0; sp < NCACHED; sp++)
+		if (POW2(sp) + hashp->hdr.spares[sp] < pgno &&
+		    (POW2(sp + 1) + hashp->hdr.spares[sp + 1]) > pgno)
+			break;
+
+	ret_val = OADDR_OF(sp + 1,
+	    pgno - ((POW2(sp + 1) - 1) + hashp->hdr.spares[sp]));
+#ifdef DEBUG
+	assert(OADDR_TO_PAGE(ret_val) == (pgno + hashp->hdr.hdrpages));
+#endif
+	return (ret_val);
+}
+
+/*
+ * Mark this overflow page as free.
+ */
+extern void
+__free_ovflpage(hashp, pagep)
+	HTAB *hashp;
+	PAGE16 *pagep;
+{
+	u_int32_t *freep;
+	int32_t bit_address, free_page, free_bit;
+	u_int16_t addr, ndx;
+
+	addr = page_to_oaddr(hashp, ADDR(pagep));
+
+#ifdef DEBUG2
+	(void)fprintf(stderr, "Freeing %d\n", addr);
+#endif
+	ndx = ((u_int16_t)addr) >> SPLITSHIFT;
+	bit_address =
+	    (ndx ? hashp->hdr.spares[ndx - 1] : 0) + (addr & SPLITMASK) - 1;
+	if (bit_address < hashp->hdr.last_freed)
+		hashp->hdr.last_freed = bit_address;
+	free_page = (bit_address >> (hashp->hdr.bshift + BYTE_SHIFT));
+	free_bit = bit_address & ((hashp->hdr.bsize << BYTE_SHIFT) - 1);
+
+	freep = fetch_bitmap(hashp, free_page);
+#ifdef DEBUG
+	/*
+	 * This had better never happen.  It means we tried to read a bitmap
+	 * that has already had overflow pages allocated off it, and we
+	 * failed to read it from the file.
+	 */
+	if (!freep)
+		assert(0);
+#endif
+	CLRBIT(freep, free_bit);
+#ifdef DEBUG2
+	(void)fprintf(stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
+	    obufp->addr, free_bit, free_page);
+#endif
+}
+
+static u_int32_t *
+fetch_bitmap(hashp, ndx)
+	HTAB *hashp;
+	int32_t ndx;
+{
+	if (ndx >= hashp->nmaps)
+		return (NULL);
+	if (!hashp->mapp[ndx])
+	    hashp->mapp[ndx] = (u_int32_t *)__get_page(hashp,
+	        hashp->hdr.bitmaps[ndx], A_BITMAP);
+
+	return (hashp->mapp[ndx]);
+}
+
+#ifdef DEBUG_SLOW
+static void
+account_page(hashp, pgno, inout)
+	HTAB *hashp;
+	db_pgno_t pgno;
+	int inout;
+{
+	static struct {
+		db_pgno_t pgno;
+		int times;
+	} list[100];
+	static int last;
+	int i, j;
+
+	if (inout == -1)			/* XXX: Kluge */
+		inout = 0;
+
+	/* Find page in list. */
+	for (i = 0; i < last; i++)
+		if (list[i].pgno == pgno)
+			break;
+	/* Not found. */
+	if (i == last) {
+		list[last].times = inout;
+		list[last].pgno = pgno;
+		last++;
+	}
+	list[i].times = inout;
+	if (list[i].times == 0) {
+		for (j = i; j < last; j++)
+			list[j] = list[j + 1];
+		last--;
+	}
+	for (i = 0; i < last; i++, list[i].times++)
+		if (list[i].times > 20 && !is_bitmap_pgno(hashp, list[i].pgno))
+			(void)fprintf(stderr,
+			    "Warning: pg %d has been out for %d times\n",
+			    list[i].pgno, list[i].times);
+}
+#endif /* DEBUG_SLOW */
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/hsearch.c b/mechglue/src/plugins/kdb/db2/libdb2/hash/hsearch.c
new file mode 100644
index 000000000..02ff7ef84
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/hsearch.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)hsearch.c	8.5 (Berkeley) 9/21/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "search.h"
+
+static DB *dbp = NULL;
+static ENTRY retval;
+
+extern int
+hcreate(nel)
+	u_int nel;
+{
+	HASHINFO info;
+
+	info.nelem = nel;
+	info.bsize = 256;
+	info.ffactor = 8;
+	info.cachesize = 0;
+	info.hash = NULL;
+	info.lorder = 0;
+	dbp = (DB *)__hash_open(NULL, O_CREAT | O_RDWR | O_BINARY, 0600, &info, 0);
+	return (dbp != NULL);
+}
+
+extern ENTRY *
+hsearch(item, action)
+	ENTRY item;
+	ACTION action;
+{
+	DBT key, val;
+	int status;
+
+	if (!dbp)
+		return (NULL);
+	key.data = (u_char *)item.key;
+	key.size = strlen(item.key) + 1;
+
+	if (action == ENTER) {
+		val.data = (u_char *)item.data;
+		val.size = strlen(item.data) + 1;
+		status = (dbp->put)(dbp, &key, &val, R_NOOVERWRITE);
+		if (status)
+			return (NULL);
+	} else {
+		/* FIND */
+		status = (dbp->get)(dbp, &key, &val, 0);
+		if (status)
+			return (NULL);
+		else
+			item.data = (char *)val.data;
+	}
+	retval.key = item.key;
+	retval.data = item.data;
+	return (&retval);
+}
+
+extern void
+hdestroy()
+{
+	if (dbp) {
+		(void)(dbp->close)(dbp);
+		dbp = NULL;
+	}
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/page.h b/mechglue/src/plugins/kdb/db2/libdb2/hash/page.h
new file mode 100644
index 000000000..8ef8a2e29
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/page.h
@@ -0,0 +1,178 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)page.h	8.4 (Berkeley) 11/7/95
+ */
+
+#define HI_MASK 0xFFFF0000
+#define LO_MASK (~HI_MASK)
+
+#define HI(N) ((u_int16_t)(((N) & HI_MASK) >> 16))
+#define LO(N) ((u_int16_t)((N) & LO_MASK))
+
+/* Constants for big key page overhead information. */
+#define NUMSHORTS	0
+#define KEYLEN		1
+#define DATALEN 	2
+#define NEXTPAGE 	3
+
+/*
+ * Hash pages store meta-data beginning at the top of the page (offset 0)
+ * and key/data values beginning at the bottom of the page (offset pagesize).
+ * Fields are always accessed via macros so that we can change the page
+ * format without too much pain.  The only changes that will require massive
+ * code changes are if we no longer store key/data offsets next to each
+ * other (since we use that fact to compute key lengths).  In the accessor
+ * macros below, P means a pointer to the page, I means an index of the
+ * particular entry being accessed.
+ * 
+ * Hash base page format
+ * BYTE ITEM			NBYTES 	TYPE		ACCESSOR MACRO
+ * ---- ------------------	------	--------	--------------
+ * 0	previous page number 	4	db_pgno_t		PREV_PGNO(P)
+ * 4	next page number	4	db_pgno_t		NEXT_PGNO(P)
+ * 8	# pairs on page		2	indx_t		NUM_ENT(P)
+ * 10	page type		1	u_int8_t	TYPE(P)
+ * 11	padding			1	u_int8_t	none
+ * 12	highest free byte	2	indx_t		OFFSET(P)
+ * 14	key offset 0		2	indx_t		KEY_OFF(P, I)
+ * 16	data offset 0		2	indx_t		DATA_OFF(P, I)
+ * 18	key  offset 1		2	indx_t		KEY_OFF(P, I)
+ * 20	data offset 1		2	indx_t		DATA_OFF(P, I)
+ * ...etc...
+ */
+
+/* Indices (in bytes) of the beginning of each of these entries */
+#define I_PREV_PGNO	 0
+#define I_NEXT_PGNO	 4
+#define I_ENTRIES	 8
+#define I_TYPE		10
+#define I_HF_OFFSET	12
+
+/* Overhead is everything prior to the first key/data pair. */
+#define PAGE_OVERHEAD	(I_HF_OFFSET + sizeof(indx_t))
+
+/* To allocate a pair, we need room for one key offset and one data offset. */
+#define PAIR_OVERHEAD	((sizeof(indx_t) << 1))
+
+/* Use this macro to extract a value of type T from page P at offset O. */
+#define REFERENCE(P, T, O)  (((T *)((u_int8_t *)(P) + O))[0])
+
+/*
+ * Use these macros to access fields on a page; P is a PAGE16 *.
+ */
+#define NUM_ENT(P)	(REFERENCE((P), indx_t, I_ENTRIES))
+#define PREV_PGNO(P)	(REFERENCE((P), db_pgno_t, I_PREV_PGNO))
+#define NEXT_PGNO(P)	(REFERENCE((P), db_pgno_t, I_NEXT_PGNO))
+#define TYPE(P)		(REFERENCE((P), u_int8_t, I_TYPE))
+#define OFFSET(P)	(REFERENCE((P), indx_t, I_HF_OFFSET))
+/*
+ * We need to store a page's own address on each page (unlike the Btree
+ * access method which needs the previous page).  We use the PREV_PGNO
+ * field to store our own page number.
+ */
+#define ADDR(P)		(PREV_PGNO((P)))
+
+/* Extract key/data offsets and data for a given index. */
+#define DATA_OFF(P, N) \
+	REFERENCE(P, indx_t, PAGE_OVERHEAD + N * PAIR_OVERHEAD + sizeof(indx_t))
+#define KEY_OFF(P, N) \
+	REFERENCE(P, indx_t, PAGE_OVERHEAD + N * PAIR_OVERHEAD)
+
+#define KEY(P, N)	(((PAGE8 *)(P)) + KEY_OFF((P), (N)))
+#define DATA(P, N)	(((PAGE8 *)(P)) + DATA_OFF((P), (N)))
+
+/*
+ * Macros used to compute various sizes on a page.
+ */
+#define	PAIRSIZE(K, D)	(PAIR_OVERHEAD + (K)->size + (D)->size)
+#define BIGOVERHEAD	(4 * sizeof(u_int16_t))
+#define KEYSIZE(K)	(4 * sizeof(u_int16_t) + (K)->size);
+#define OVFLSIZE	(2 * sizeof(u_int16_t))
+#define BIGPAGEOVERHEAD (4 * sizeof(u_int16_t))
+#define BIGPAGEOFFSET   4
+#define BIGPAGESIZE(P)	((P)->BSIZE - BIGPAGEOVERHEAD)
+
+#define PAGE_META(N)	(((N) + 3) * sizeof(u_int16_t))
+#define MINFILL 0.75
+#define ISBIG(N, P)	(((N) > ((P)->hdr.bsize * MINFILL)) ? 1 : 0)
+
+#define ITEMSIZE(I)    (sizeof(u_int16_t) + (I)->size)
+
+/*
+ * Big key/data pages use a different page format.  They have a single
+ * key/data "pair" containing the length of the key and data instead
+ * of offsets.
+ */
+#define BIGKEYLEN(P)	(KEY_OFF((P), 0))
+#define BIGDATALEN(P)	(DATA_OFF((P), 0))
+#define BIGKEY(P)	(((PAGE8 *)(P)) + PAGE_OVERHEAD + PAIR_OVERHEAD)
+#define BIGDATA(P) \
+	(((PAGE8 *)(P)) + PAGE_OVERHEAD + PAIR_OVERHEAD + KEY_OFF((P), 0))
+
+
+#define OVFLPAGE	0
+#define BIGPAIR		0
+#define INVALID_PGNO	0xFFFFFFFF
+
+typedef unsigned short PAGE16;
+typedef unsigned char  PAGE8;
+
+#define A_BUCKET	0
+#define A_OVFL		1
+#define A_BITMAP	2
+#define A_RAW		4
+#define A_HEADER	5
+
+#define PAIRFITS(P,K,D)	((PAIRSIZE((K),(D))) <= FREESPACE((P)))
+#define BIGPAIRFITS(P)	((FREESPACE((P)) >= PAIR_OVERHEAD))
+/*
+ * Since these are all unsigned, we need to guarantee that we never go
+ * negative.  Offset values are 0-based and overheads are one based (i.e.
+ * one byte of overhead is 1, not 0), so we need to convert OFFSETs to
+ * 1-based counting before subtraction.
+ */
+#define FREESPACE(P) \
+	((OFFSET((P)) + 1 - PAGE_OVERHEAD - (NUM_ENT((P)) * PAIR_OVERHEAD)))
+
+/* 
+ * Overhead on header pages is just one word -- the length of the
+ * header info stored on that page.
+ */
+#define HEADER_OVERHEAD 4
+
+#define HASH_PAGE	2
+#define HASH_BIGPAGE	3
+#define HASH_OVFLPAGE	4
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/page.h.patch b/mechglue/src/plugins/kdb/db2/libdb2/hash/page.h.patch
new file mode 100644
index 000000000..4a0311fea
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/page.h.patch
@@ -0,0 +1,42 @@
+*** /tmp/,RCSt1a21720	Wed Apr  3 11:49:55 1996
+--- page.h	Wed Apr  3 08:42:25 1996
+***************
+*** 158,163
+  
+  #define PAIRFITS(P,K,D)	((PAIRSIZE((K),(D))) <= FREESPACE((P)))
+  #define BIGPAIRFITS(P)	((FREESPACE((P)) >= PAIR_OVERHEAD))
+  #define FREESPACE(P) \
+  	((OFFSET((P)) - PAGE_OVERHEAD - (NUM_ENT((P)) * PAIR_OVERHEAD)))
+  
+
+--- 158,169 -----
+  
+  #define PAIRFITS(P,K,D)	((PAIRSIZE((K),(D))) <= FREESPACE((P)))
+  #define BIGPAIRFITS(P)	((FREESPACE((P)) >= PAIR_OVERHEAD))
++ /*
++  * Since these are all unsigned, we need to guarantee that we never go
++  * negative.  Offset values are 0-based and overheads are one based (i.e.
++  * one byte of overhead is 1, not 0), so we need to convert OFFSETs to
++  * 1-based counting before subtraction.
++  */
+  #define FREESPACE(P) \
+  	((OFFSET((P)) + 1 - PAGE_OVERHEAD - (NUM_ENT((P)) * PAIR_OVERHEAD)))
+  
+***************
+*** 159,165
+  #define PAIRFITS(P,K,D)	((PAIRSIZE((K),(D))) <= FREESPACE((P)))
+  #define BIGPAIRFITS(P)	((FREESPACE((P)) >= PAIR_OVERHEAD))
+  #define FREESPACE(P) \
+! 	((OFFSET((P)) - PAGE_OVERHEAD - (NUM_ENT((P)) * PAIR_OVERHEAD)))
+  
+  /* 
+   * Overhead on header pages is just one word -- the length of the
+
+--- 165,171 -----
+   * 1-based counting before subtraction.
+   */
+  #define FREESPACE(P) \
+! 	((OFFSET((P)) + 1 - PAGE_OVERHEAD - (NUM_ENT((P)) * PAIR_OVERHEAD)))
+  
+  /* 
+   * Overhead on header pages is just one word -- the length of the
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/hash/search.h b/mechglue/src/plugins/kdb/db2/libdb2/hash/search.h
new file mode 100644
index 000000000..6d6a0a82f
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/hash/search.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)search.h	8.1 (Berkeley) 6/4/93
+ */
+
+/* Backward compatibility to hsearch interface. */
+typedef struct entry {
+	char *key;
+	char *data;
+} ENTRY;
+
+typedef enum {
+	FIND, ENTER
+} ACTION;
+
+#define hcreate		kdb2_hcreate
+#define hdestroy	kdb2_hdestroy
+#define hsearch		kdb2_hsearch
+
+int	 hcreate __P((unsigned int));
+void	 hdestroy __P((void));
+ENTRY	*hsearch __P((ENTRY, ACTION));
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/include/ChangeLog b/mechglue/src/plugins/kdb/db2/libdb2/include/ChangeLog
new file mode 100644
index 000000000..676bbd44a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/include/ChangeLog
@@ -0,0 +1,74 @@
+2004-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* db-int.h: Include sys/param.h if available.
+
+2004-05-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* db-int.h: Include machine/endian.h if available.  Check for
+	__LITTLE_ENDIAN__ and __BIG_ENDIAN__, _MIPSEB and _MIPSEL.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* db-int.h: Include stdlib.h, and endian.h if available.
+	(LITTLE_ENDIAN, BIG_ENDIAN, BYTE_ORDER): If not defined, and if
+	versions with one or two leading underscores are defined, define
+	the no-underscore form in terms of the with-underscore one.
+	(DB_BYTE_ORDER): Define by checking LITTLE_ENDIAN, BIG_ENDIAN, and
+	BYTE_ORDER; report an error if that doesn't work.  Don't check
+	WORDS_BIGENDIAN.
+
+2002-09-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* db-int.h: If stdint.h or inttypes.h are found, include them.
+
+2002-08-23  Tom Yu  <tlyu@mit.edu>
+
+	* db.h: Add rename and prototype for bt_rseq(); this is a kludge
+	to avoid stuffing more things into the DB handle.
+
+2001-10-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* db-config.h.in: Remove unnecessary definitions for including
+	db.h header file. These include WORDS_BIGENDIAN, ssize_t, u_short,
+	int8_t, u_int8_t, int16_t, u_int16_t, int32_t.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* db-dbm.h: New header file which lists the dbm interfaces.
+
+	* db-ndbm.h: Change prototype from dirinfo to dirfno which matches
+	code and ndbm API.
+
+2000-07-01  Tom Yu  <tlyu@mit.edu>
+
+	* db-config.h.in: New file; contains useful tidbits from
+	config.h.in generated by autoheader.  It is needed because
+	config.h.in has some thing we don't want to leak, like renaming of
+	missing libc functions.
+
+	* .cvsignore: Twiddle to reflect current reality.
+
+	* db-int.h: #include config.h since db.h includes db-config.h
+	which is not quite the same now.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* db-int.h: Remove renaming for memmove, strerror, mkstemp since
+	this is now done by the build system.
+
+Fri Feb 13 14:39:25 1998  Tom Yu  <tlyu@mit.edu>
+
+	* db-int.h: Additional renaming.
+
+	* db.h: Rename dbopen to avoid collision with NetBSD libc.
+
+	* db-ndbm.h: Rename lots of functions to avoid collisions with
+	native dbm implementations.
+
+	* db-int.h: Rename __hash_open to avoid potential collision with
+	NetBSD libc.
+
+Thu Aug 15 15:41:12 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* db-ndbm.h: Add prototypes for missing functions dbm_error() and
+	 	dbm_clearerror().
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/include/db-config.h.in b/mechglue/src/plugins/kdb/db2/libdb2/include/db-config.h.in
new file mode 100644
index 000000000..bcd7991b3
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/include/db-config.h.in
@@ -0,0 +1,16 @@
+/* include/db-config.h.in.  Derived from autoconf-generated config.h.in. */
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+#undef u_char
+#undef u_int
+#undef u_long
+
+#undef u_int32_t
+
+/* The number of bytes in a int.  */
+#undef SIZEOF_INT
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/include/db-dbm.h b/mechglue/src/plugins/kdb/db2/libdb2/include/db-dbm.h
new file mode 100644
index 000000000..28c93786c
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/include/db-dbm.h
@@ -0,0 +1,23 @@
+#ifndef _DBM_H_
+#define	_DBM_H_
+
+#include "db.h"
+
+#define dbminit		kdb2_dbminit
+#define fetch		kdb2_fetch
+#define firstkey	kdb2_firstkey
+#define nextkey		kdb2_nextkey
+#define delete		kdb2_delete
+#define store		kdb2_store
+
+__BEGIN_DECLS
+int	 dbminit __P((char *));
+datum	 fetch __P((datum));
+datum	 firstkey __P((void));
+datum	 nextkey __P((datum));
+int	 delete __P((datum));
+int	 store __P((datum, datum));
+__END_DECLS
+
+
+#endif
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/include/db-int.h b/mechglue/src/plugins/kdb/db2/libdb2/include/db-int.h
new file mode 100644
index 000000000..bbb22925a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/include/db-int.h
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)compat.h	8.13 (Berkeley) 2/21/94
+ */
+
+#ifndef	_DB_INT_H_
+#define	_DB_INT_H_
+
+#include "config.h"
+#include "db.h"
+
+/* deal with autoconf-based stuff */
+
+#define DB_LITTLE_ENDIAN 1234
+#define DB_BIG_ENDIAN 4321
+
+#include <stdlib.h>
+#ifdef HAVE_ENDIAN_H
+# include <endian.h>
+#endif
+#ifdef HAVE_MACHINE_ENDIAN_H
+# include <machine/endian.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+/* Handle both BIG and LITTLE defined and BYTE_ORDER matches one, or
+   just one defined; both with and without leading underscores.
+
+   Ignore "PDP endian" machines, this code doesn't support them
+   anyways.  */
+#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) && !defined(BYTE_ORDER)
+# ifdef __LITTLE_ENDIAN__
+#  define LITTLE_ENDIAN __LITTLE_ENDIAN__
+# endif
+# ifdef __BIG_ENDIAN__
+#  define BIG_ENDIAN __BIG_ENDIAN__
+# endif
+#endif
+#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) && !defined(BYTE_ORDER)
+# ifdef _LITTLE_ENDIAN
+#  define LITTLE_ENDIAN _LITTLE_ENDIAN
+# endif
+# ifdef _BIG_ENDIAN
+#  define BIG_ENDIAN _BIG_ENDIAN
+# endif
+# ifdef _BYTE_ORDER
+#  define BYTE_ORDER _BYTE_ORDER
+# endif
+#endif
+#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) && !defined(BYTE_ORDER)
+# ifdef __LITTLE_ENDIAN
+#  define LITTLE_ENDIAN __LITTLE_ENDIAN
+# endif
+# ifdef __BIG_ENDIAN
+#  define BIG_ENDIAN __BIG_ENDIAN
+# endif
+# ifdef __BYTE_ORDER
+#  define BYTE_ORDER __BYTE_ORDER
+# endif
+#endif
+
+#if defined(_MIPSEL) && !defined(LITTLE_ENDIAN)
+# define LITTLE_ENDIAN
+#endif
+#if defined(_MIPSEB) && !defined(BIG_ENDIAN)
+# define BIG_ENDIAN
+#endif
+
+#if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) && defined(BYTE_ORDER)
+# if LITTLE_ENDIAN == BYTE_ORDER
+#  define DB_BYTE_ORDER DB_LITTLE_ENDIAN
+# elif BIG_ENDIAN == BYTE_ORDER
+#  define DB_BYTE_ORDER DB_BIG_ENDIAN
+# else
+#  error "LITTLE_ENDIAN and BIG_ENDIAN defined, but can't determine byte order"
+# endif
+#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
+# define DB_BYTE_ORDER DB_LITTLE_ENDIAN
+#elif defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
+# define DB_BYTE_ORDER DB_BIG_ENDIAN
+#else
+# error "can't determine byte order from included system headers"
+#endif
+
+#if 0
+#ifdef WORDS_BIGENDIAN
+#define DB_BYTE_ORDER DB_BIG_ENDIAN
+#else
+#define DB_BYTE_ORDER DB_LITTLE_ENDIAN
+#endif
+#endif
+
+/* end autoconf-based stuff */
+
+/* include necessary system header files */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+/* Tru64 5.1: int8_t is defined here, and stdint.h doesn't exist.  */
+#include <inttypes.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+/* types and constants used for database structure */
+
+#define	MAX_PAGE_NUMBER	0xffffffff	/* >= # of pages in a file */
+typedef u_int32_t	db_pgno_t;
+#define	MAX_PAGE_OFFSET	65535		/* >= # of bytes in a page */
+typedef u_int16_t	indx_t;
+#define	MAX_REC_NUMBER	0xffffffff	/* >= # of records in a tree */
+typedef u_int32_t	recno_t;
+
+/*
+ * Little endian <==> big endian 32-bit swap macros.
+ *	M_32_SWAP	swap a memory location
+ *	P_32_SWAP	swap a referenced memory location
+ *	P_32_COPY	swap from one location to another
+ */
+#define	M_32_SWAP(a) {							\
+	u_int32_t _tmp = a;						\
+	((char *)&a)[0] = ((char *)&_tmp)[3];				\
+	((char *)&a)[1] = ((char *)&_tmp)[2];				\
+	((char *)&a)[2] = ((char *)&_tmp)[1];				\
+	((char *)&a)[3] = ((char *)&_tmp)[0];				\
+}
+#define	P_32_SWAP(a) {							\
+	u_int32_t _tmp = *(u_int32_t *)a;				\
+	((char *)a)[0] = ((char *)&_tmp)[3];				\
+	((char *)a)[1] = ((char *)&_tmp)[2];				\
+	((char *)a)[2] = ((char *)&_tmp)[1];				\
+	((char *)a)[3] = ((char *)&_tmp)[0];				\
+}
+#define	P_32_COPY(a, b) {						\
+	((char *)&(b))[0] = ((char *)&(a))[3];				\
+	((char *)&(b))[1] = ((char *)&(a))[2];				\
+	((char *)&(b))[2] = ((char *)&(a))[1];				\
+	((char *)&(b))[3] = ((char *)&(a))[0];				\
+}
+
+/*
+ * Little endian <==> big endian 16-bit swap macros.
+ *	M_16_SWAP	swap a memory location
+ *	P_16_SWAP	swap a referenced memory location
+ *	P_16_COPY	swap from one location to another
+ */
+#define	M_16_SWAP(a) {							\
+	u_int16_t _tmp = a;						\
+	((char *)&a)[0] = ((char *)&_tmp)[1];				\
+	((char *)&a)[1] = ((char *)&_tmp)[0];				\
+}
+#define	P_16_SWAP(a) {							\
+	u_int16_t _tmp = *(u_int16_t *)a;				\
+	((char *)a)[0] = ((char *)&_tmp)[1];				\
+	((char *)a)[1] = ((char *)&_tmp)[0];				\
+}
+#define	P_16_COPY(a, b) {						\
+	((char *)&(b))[0] = ((char *)&(a))[1];				\
+	((char *)&(b))[1] = ((char *)&(a))[0];				\
+}
+
+/* open functions for each database type, used in dbopen() */
+
+#define __bt_open	__kdb2_bt_open
+#define __hash_open	__kdb2_hash_open
+#define __rec_open	__kdb2_rec_open
+#define __dbpanic	__kdb2_dbpanic
+
+DB	*__bt_open __P((const char *, int, int, const BTREEINFO *, int));
+DB	*__hash_open __P((const char *, int, int, const HASHINFO *, int));
+DB	*__rec_open __P((const char *, int, int, const RECNOINFO *, int));
+void	 __dbpanic __P((DB *dbp));
+
+/*
+ * There is no portable way to figure out the maximum value of a file
+ * offset, so we put it here.
+ */
+#ifdef	OFF_T_MAX
+#define	DB_OFF_T_MAX	OFF_T_MAX
+#else
+#define	DB_OFF_T_MAX	LONG_MAX
+#endif
+
+#ifndef O_ACCMODE			/* POSIX 1003.1 access mode mask. */
+#define	O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
+#endif
+
+/*
+ * If you can't provide lock values in the open(2) call.  Note, this
+ * allows races to happen.
+ */
+#ifndef O_EXLOCK			/* 4.4BSD extension. */
+#define	O_EXLOCK	0
+#endif
+
+#ifndef O_SHLOCK			/* 4.4BSD extension. */
+#define	O_SHLOCK	0
+#endif
+
+#ifndef EFTYPE
+#define	EFTYPE		EINVAL		/* POSIX 1003.1 format errno. */
+#endif
+
+#ifndef	STDERR_FILENO
+#define	STDIN_FILENO	0		/* ANSI C #defines */
+#define	STDOUT_FILENO	1
+#define	STDERR_FILENO	2
+#endif
+
+#ifndef SEEK_END
+#define	SEEK_SET	0		/* POSIX 1003.1 seek values */
+#define	SEEK_CUR	1
+#define	SEEK_END	2
+#endif
+
+#ifndef NULL				/* ANSI C #defines NULL everywhere. */
+#define	NULL		0
+#endif
+
+#ifndef	MAX				/* Usually found in <sys/param.h>. */
+#define	MAX(_a,_b)	((_a)<(_b)?(_b):(_a))
+#endif
+#ifndef	MIN				/* Usually found in <sys/param.h>. */
+#define	MIN(_a,_b)	((_a)<(_b)?(_a):(_b))
+#endif
+
+#ifndef S_ISDIR				/* POSIX 1003.1 file type tests. */
+#define	S_ISDIR(m)	((m & 0170000) == 0040000)	/* directory */
+#define	S_ISCHR(m)	((m & 0170000) == 0020000)	/* char special */
+#define	S_ISBLK(m)	((m & 0170000) == 0060000)	/* block special */
+#define	S_ISREG(m)	((m & 0170000) == 0100000)	/* regular file */
+#define	S_ISFIFO(m)	((m & 0170000) == 0010000)	/* fifo */
+#endif
+#ifndef S_ISLNK				/* BSD POSIX 1003.1 extensions */
+#define	S_ISLNK(m)	((m & 0170000) == 0120000)	/* symbolic link */
+#define	S_ISSOCK(m)	((m & 0170000) == 0140000)	/* socket */
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY	0		/* Needed for Win32 compiles */
+#endif
+#endif /* _DB_INT_H_ */
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/include/db-ndbm.h b/mechglue/src/plugins/kdb/db2/libdb2/include/db-ndbm.h
new file mode 100644
index 000000000..e99f46fdc
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/include/db-ndbm.h
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)ndbm.h	8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _NDBM_H_
+#define	_NDBM_H_
+
+#include "db.h"
+
+/* Map dbm interface onto db(3). */
+#define DBM_RDONLY	O_RDONLY
+
+/* Flags to dbm_store(). */
+#define DBM_INSERT      0
+#define DBM_REPLACE     1
+
+/*
+ * The db(3) support for ndbm(3) always appends this suffix to the
+ * file name to avoid overwriting the user's original database.
+ */
+#define	DBM_SUFFIX	".db"
+
+typedef struct {
+	char *dptr;
+	int dsize;
+} datum;
+
+typedef DB DBM;
+#define	dbm_pagfno(a)	DBM_PAGFNO_NOT_AVAILABLE
+
+#define dbm_close	kdb2_dbm_close
+#define dbm_delete	kdb2_dbm_delete
+#define dbm_fetch	kdb2_dbm_fetch
+#define dbm_firstkey	kdb2_dbm_firstkey
+#define dbm_forder	kdb2_dbm_forder
+#define dbm_nextkey	kdb2_dbm_nextkey
+#define dbm_open	kdb2_dbm_open
+#define dbm_store	kdb2_dbm_store
+#define dbm_dirfno	kdb2_dbm_dirfno
+#define dbm_error	kdb2_dbm_error
+#define dbm_clearerr	kdb2_dbm_clearerr
+
+__BEGIN_DECLS
+void	 dbm_close __P((DBM *));
+int	 dbm_delete __P((DBM *, datum));
+datum	 dbm_fetch __P((DBM *, datum));
+datum	 dbm_firstkey __P((DBM *));
+long	 dbm_forder __P((DBM *, datum));
+datum	 dbm_nextkey __P((DBM *));
+DBM	*dbm_open __P((const char *, int, int));
+int	 dbm_store __P((DBM *, datum, datum, int));
+int	 dbm_dirfno __P((DBM *));
+int	 dbm_error __P((DBM *db));
+int	 dbm_clearerr __P((DBM *db));
+__END_DECLS
+
+#endif /* !_NDBM_H_ */
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/include/db-queue.h b/mechglue/src/plugins/kdb/db2/libdb2/include/db-queue.h
new file mode 100644
index 000000000..40d32ccb6
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/include/db-queue.h
@@ -0,0 +1,245 @@
+/* 
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.3 (Berkeley) 12/13/93
+ */
+
+#ifndef	_QUEUE_H_
+#define	_QUEUE_H_
+
+/*
+ * This file defines three types of data structures: lists, tail queues,
+ * and circular queues.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list after
+ * an existing element or at the head of the list. A list may only be
+ * traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A tail queue may only be traversed in the forward direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+#define	LIST_INIT(head) {						\
+	(head)->lh_first = NULL;					\
+}
+
+#define LIST_INSERT_AFTER(listelm, elm, field) {			\
+	if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
+		(listelm)->field.le_next->field.le_prev =		\
+		    &(elm)->field.le_next;				\
+	(listelm)->field.le_next = (elm);				\
+	(elm)->field.le_prev = &(listelm)->field.le_next;		\
+}
+
+#define LIST_INSERT_HEAD(head, elm, field) {				\
+	if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
+		(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+	(head)->lh_first = (elm);					\
+	(elm)->field.le_prev = &(head)->lh_first;			\
+}
+
+#define LIST_REMOVE(elm, field) {					\
+	if ((elm)->field.le_next != NULL)				\
+		(elm)->field.le_next->field.le_prev = 			\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = (elm)->field.le_next;			\
+}
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_INIT(head) {						\
+	(head)->tqh_first = NULL;					\
+	(head)->tqh_last = &(head)->tqh_first;				\
+}
+
+#define TAILQ_INSERT_HEAD(head, elm, field) {				\
+	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
+		(elm)->field.tqe_next->field.tqe_prev =			\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(head)->tqh_first = (elm);					\
+	(elm)->field.tqe_prev = &(head)->tqh_first;			\
+}
+
+#define TAILQ_INSERT_TAIL(head, elm, field) {				\
+	(elm)->field.tqe_next = NULL;					\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &(elm)->field.tqe_next;			\
+}
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) {			\
+	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    &(elm)->field.tqe_next;				\
+	else								\
+		(head)->tqh_last = &(elm)->field.tqe_next;		\
+	(listelm)->field.tqe_next = (elm);				\
+	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
+}
+
+#define TAILQ_REMOVE(head, elm, field) {				\
+	if (((elm)->field.tqe_next) != NULL)				\
+		(elm)->field.tqe_next->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
+}
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_INIT(head) {						\
+	(head)->cqh_first = (void *)(head);				\
+	(head)->cqh_last = (void *)(head);				\
+}
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) {		\
+	(elm)->field.cqe_next = (listelm)->field.cqe_next;		\
+	(elm)->field.cqe_prev = (listelm);				\
+	if ((listelm)->field.cqe_next == (void *)(head))		\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(listelm)->field.cqe_next->field.cqe_prev = (elm);	\
+	(listelm)->field.cqe_next = (elm);				\
+}
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) {		\
+	(elm)->field.cqe_next = (listelm);				\
+	(elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
+	if ((listelm)->field.cqe_prev == (void *)(head))		\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(listelm)->field.cqe_prev->field.cqe_next = (elm);	\
+	(listelm)->field.cqe_prev = (elm);				\
+}
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) {				\
+	(elm)->field.cqe_next = (head)->cqh_first;			\
+	(elm)->field.cqe_prev = (void *)(head);				\
+	if ((head)->cqh_last == (void *)(head))				\
+		(head)->cqh_last = (elm);				\
+	else								\
+		(head)->cqh_first->field.cqe_prev = (elm);		\
+	(head)->cqh_first = (elm);					\
+}
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) {				\
+	(elm)->field.cqe_next = (void *)(head);				\
+	(elm)->field.cqe_prev = (head)->cqh_last;			\
+	if ((head)->cqh_first == (void *)(head))			\
+		(head)->cqh_first = (elm);				\
+	else								\
+		(head)->cqh_last->field.cqe_next = (elm);		\
+	(head)->cqh_last = (elm);					\
+}
+
+#define	CIRCLEQ_REMOVE(head, elm, field) {				\
+	if ((elm)->field.cqe_next == (void *)(head))			\
+		(head)->cqh_last = (elm)->field.cqe_prev;		\
+	else								\
+		(elm)->field.cqe_next->field.cqe_prev =			\
+		    (elm)->field.cqe_prev;				\
+	if ((elm)->field.cqe_prev == (void *)(head))			\
+		(head)->cqh_first = (elm)->field.cqe_next;		\
+	else								\
+		(elm)->field.cqe_prev->field.cqe_next =			\
+		    (elm)->field.cqe_next;				\
+}
+#endif	/* !_QUEUE_H_ */
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/include/db.h b/mechglue/src/plugins/kdb/db2/libdb2/include/db.h
new file mode 100644
index 000000000..980145a3d
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/include/db.h
@@ -0,0 +1,175 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)db.h	8.8 (Berkeley) 11/2/95
+ */
+
+#ifndef _DB_H_
+#define	_DB_H_
+
+#include <db-config.h>
+
+#include <sys/types.h>
+
+#define	RET_ERROR	-1		/* Return values. */
+#define	RET_SUCCESS	 0
+#define	RET_SPECIAL	 1
+
+/* Key/data structure -- a Data-Base Thang. */
+typedef struct {
+	void	*data;			/* data */
+	size_t	 size;			/* data length */
+} DBT;
+
+/* Routine flags. */
+#define	R_CURSOR	1		/* del, put, seq */
+#define	__R_UNUSED	2		/* UNUSED */
+#define	R_FIRST		3		/* seq */
+#define	R_IAFTER	4		/* put (RECNO) */
+#define	R_IBEFORE	5		/* put (RECNO) */
+#define	R_LAST		6		/* seq (BTREE, RECNO) */
+#define	R_NEXT		7		/* seq */
+#define	R_NOOVERWRITE	8		/* put */
+#define	R_PREV		9		/* seq (BTREE, RECNO) */
+#define	R_SETCURSOR	10		/* put (RECNO) */
+#define	R_RECNOSYNC	11		/* sync (RECNO) */
+
+typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE;
+
+/*
+ * !!!
+ * The following flags are included in the dbopen(3) call as part of the
+ * open(2) flags.  In order to avoid conflicts with the open flags, start
+ * at the top of the 16 or 32-bit number space and work our way down.  If
+ * the open flags were significantly expanded in the future, it could be
+ * a problem.  Wish I'd left another flags word in the dbopen call.
+ *
+ * !!!
+ * None of this stuff is implemented yet.  The only reason that it's here
+ * is so that the access methods can skip copying the key/data pair when
+ * the DB_LOCK flag isn't set.
+ */
+#if SIZEOF_INT == 4
+#define	DB_LOCK		0x20000000	/* Do locking. */
+#define	DB_SHMEM	0x40000000	/* Use shared memory. */
+#define	DB_TXN		0x80000000	/* Do transactions. */
+#else
+#define	DB_LOCK		    0x2000	/* Do locking. */
+#define	DB_SHMEM	    0x4000	/* Use shared memory. */
+#define	DB_TXN		    0x8000	/* Do transactions. */
+#endif
+
+/* deal with turning prototypes on and off */
+
+#ifndef __P
+#if defined(__STDC__) || defined(__cplusplus)
+#define	__P(protos)	protos		/* full-blown ANSI C */
+#else	/* !(__STDC__ || __cplusplus) */
+#define	__P(protos)	()		/* traditional C preprocessor */
+#endif
+#endif /* no __P from system */
+
+/* Access method description structure. */
+typedef struct __db {
+	DBTYPE type;			/* Underlying db type. */
+	int (*close)	__P((struct __db *));
+	int (*del)	__P((const struct __db *, const DBT *, u_int));
+	int (*get)	__P((const struct __db *, const DBT *, DBT *, u_int));
+	int (*put)	__P((const struct __db *, DBT *, const DBT *, u_int));
+	int (*seq)	__P((const struct __db *, DBT *, DBT *, u_int));
+	int (*sync)	__P((const struct __db *, u_int));
+	void *internal;			/* Access method private. */
+	int (*fd)	__P((const struct __db *));
+} DB;
+
+#define	BTREEMAGIC	0x053162
+#define	BTREEVERSION	3
+
+/* Structure used to pass parameters to the btree routines. */
+typedef struct {
+#define	R_DUP		0x01	/* duplicate keys */
+	u_long	flags;
+	u_int	cachesize;	/* bytes to cache */
+	int	maxkeypage;	/* maximum keys per page */
+	int	minkeypage;	/* minimum keys per page */
+	u_int	psize;		/* page size */
+	int	(*compare)	/* comparison function */
+	    __P((const DBT *, const DBT *));
+	size_t	(*prefix)	/* prefix function */
+	    __P((const DBT *, const DBT *));
+	int	lorder;		/* byte order */
+} BTREEINFO;
+
+#define	HASHMAGIC	0x061561
+#define	HASHVERSION	3
+
+/* Structure used to pass parameters to the hashing routines. */
+typedef struct {
+	u_int	bsize;		/* bucket size */
+	u_int	ffactor;	/* fill factor */
+	u_int	nelem;		/* number of elements */
+	u_int	cachesize;	/* bytes to cache */
+	u_int32_t		/* hash function */
+		(*hash) __P((const void *, size_t));
+	int	lorder;		/* byte order */
+} HASHINFO;
+
+/* Structure used to pass parameters to the record routines. */
+typedef struct {
+#define	R_FIXEDLEN	0x01	/* fixed-length records */
+#define	R_NOKEY		0x02	/* key not required */
+#define	R_SNAPSHOT	0x04	/* snapshot the input */
+	u_long	flags;
+	u_int	cachesize;	/* bytes to cache */
+	u_int	psize;		/* page size */
+	int	lorder;		/* byte order */
+	size_t	reclen;		/* record length (fixed-length records) */
+	u_char	bval;		/* delimiting byte (variable-length records */
+	char	*bfname;	/* btree file name */ 
+} RECNOINFO;
+
+#if defined(__cplusplus)
+#define	__BEGIN_DECLS	extern "C" {
+#define	__END_DECLS	};
+#else
+#define	__BEGIN_DECLS
+#define	__END_DECLS
+#endif
+
+#define dbopen	kdb2_dbopen
+#define bt_rseq		kdb2_bt_rseq /* XXX kludge */
+__BEGIN_DECLS
+DB *dbopen __P((const char *, int, int, DBTYPE, const void *));
+int	 bt_rseq(const DB*, DBT *, DBT *, void **, u_int); /* XXX kludge */
+__END_DECLS
+
+#endif /* !_DB_H_ */
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/libdb.exports b/mechglue/src/plugins/kdb/db2/libdb2/libdb.exports
new file mode 100644
index 000000000..5dbc2e438
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/libdb.exports
@@ -0,0 +1,99 @@
+__default_hash
+__kdb2_add_bigpage
+__kdb2_add_ovflpage
+__kdb2_addel
+__kdb2_big_delete
+__kdb2_big_insert
+__kdb2_big_keydata
+__kdb2_big_return
+__kdb2_bt_close
+__kdb2_bt_cmp
+__kdb2_bt_defcmp
+__kdb2_bt_defpfx
+__kdb2_bt_deleaf
+__kdb2_bt_delete
+__kdb2_bt_fd
+__kdb2_bt_free
+__kdb2_bt_get
+__kdb2_bt_new
+__kdb2_bt_open
+__kdb2_bt_pgin
+__kdb2_bt_pgout
+__kdb2_bt_put
+__kdb2_bt_ret
+__kdb2_bt_search
+__kdb2_bt_seq
+__kdb2_bt_setcur
+__kdb2_bt_split
+__kdb2_bt_sync
+__kdb2_call_hash
+__kdb2_cursor_creat
+__kdb2_dbpanic
+__kdb2_delete_page
+__kdb2_delpair
+__kdb2_expand_table
+__kdb2_find_bigpair
+__kdb2_free_ovflpage
+__kdb2_get_bigkey
+__kdb2_get_item
+__kdb2_get_item_done
+__kdb2_get_item_first
+__kdb2_get_item_next
+__kdb2_get_item_reset
+__kdb2_get_page
+__kdb2_hash_open
+__kdb2_ibitmap
+__kdb2_log2
+__kdb2_new_page
+__kdb2_ovfl_delete
+__kdb2_ovfl_get
+__kdb2_ovfl_put
+__kdb2_pgin_routine
+__kdb2_pgout_routine
+__kdb2_put_page
+__kdb2_rec_close
+__kdb2_rec_delete
+__kdb2_rec_dleaf
+__kdb2_rec_fd
+__kdb2_rec_fmap
+__kdb2_rec_fpipe
+__kdb2_rec_get
+__kdb2_rec_iput
+__kdb2_rec_open
+__kdb2_rec_put
+__kdb2_rec_ret
+__kdb2_rec_search
+__kdb2_rec_seq
+__kdb2_rec_sync
+__kdb2_rec_vmap
+__kdb2_rec_vpipe
+__kdb2_split_page
+kdb2_bt_rseq
+kdb2_dbm_clearerr
+kdb2_dbm_close
+kdb2_dbm_delete
+kdb2_dbm_dirfno
+kdb2_dbm_error
+kdb2_dbm_fetch
+kdb2_dbm_firstkey
+kdb2_dbm_nextkey
+kdb2_dbm_open
+kdb2_dbm_store
+kdb2_dbminit
+kdb2_dbopen
+kdb2_delete
+kdb2_fetch
+kdb2_firstkey
+kdb2_hcreate
+kdb2_hdestroy
+kdb2_hsearch
+kdb2_mpool_close
+kdb2_mpool_delete
+kdb2_mpool_filter
+kdb2_mpool_get
+kdb2_mpool_new
+kdb2_mpool_open
+kdb2_mpool_put
+kdb2_mpool_sync
+kdb2_nextkey
+kdb2_store
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/Makefile.inc b/mechglue/src/plugins/kdb/db2/libdb2/man/Makefile.inc
new file mode 100644
index 000000000..f85cba1f8
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/Makefile.inc
@@ -0,0 +1,7 @@
+#       @(#)Makefile.inc	8.2 (Berkeley) 11/14/94
+
+.PATH: ${.CURDIR}/db/man
+
+MAN3+=	db_btree.0 db_hash.0 db_lock.0 db_log.0 db_mpool.0 db_open.0 \
+	db_recno.0
+MLINKS+=db_open.3 db.3 db_open.3 dbopen.3
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db.man.ps b/mechglue/src/plugins/kdb/db2/libdb2/man/db.man.ps
new file mode 100644
index 000000000..23feea6e5
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db.man.ps
@@ -0,0 +1,2295 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Bold
+%%+ font Times-Italic
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 28
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll 
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Italic
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 113.45(DB_BTREE\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 113.45(anual DB_BTREE\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)
+72 84 S(ME).18 E F0(db_btree \255 btree database access method)108 96 Q F1
+(DESCRIPTION)72 112.8 Q F0 .486(The DB library is a f)108 124.8 R .485
+(amily of groups of functions that pro)-.1 F .485
+(vides a modular programming interf)-.15 F .485(ace to trans-)-.1 F .822
+(actions and record-oriented \214le access.)108 136.8 R .822
+(The library includes support for transaction, locking, logging and)5.822 F
+.258(\214le b)108 148.8 R(uf)-.2 E .258(fering functionality)-.25 F 2.758(,a)
+-.65 G 2.758(sw)223.214 148.8 S .258(ell as v)237.082 148.8 R .258(arious inde)
+-.25 F -.15(xe)-.15 G 2.758(da).15 G .258(ccess methods.)331.434 148.8 R(Man)
+5.258 E 2.758(yo)-.15 G 2.758(ft)427.878 148.8 S .258
+(he functional groups \(e.g.)436.746 148.8 R .528(the memory pool functions\) \
+are useful independently of the rest of the DB functions, although some func-)
+108 160.8 R .306(tional groups are e)108 172.8 R .306
+(xplicitly based on other functional groups \(e.g.)-.15 F .306
+(transactions and logging\).)5.306 F -.15(Fo)5.306 G 2.806(rag).15 G(eneral)
+515.57 172.8 Q .245(description of transactions, see)108 184.8 R/F2 10
+/Times-Italic@0 SF(db_txn)2.745 E F0 2.745(\(3\). F).24 F .245
+(or a general description of the access methods, see)-.15 F F2(db_open)2.745 E
+F0(\(3\)).24 E .308(and then the indi)108 196.8 R .308
+(vidual access method manual pages:)-.25 F F2(db_btr)2.807 E(ee)-.37 E F0
+(\(3\),).18 E F2(db_hash)2.807 E F0(\(3\),).28 E F2(db_lo)2.807 E(g)-.1 E F0
+.307(\(3\) and).22 F F2(db_r)2.807 E(ecno)-.37 E F0(\(3\).).18 E -.15(Fo)108
+208.8 S 3.635(rag).15 G 1.135(eneral description of the lock manager)138.45
+208.8 R 3.635(,s)-.4 G(ee)307.32 208.8 Q F2(db_loc)3.635 E(k)-.2 E F0 3.635
+(\(3\). F).67 F 1.135(or a general description of the memory)-.15 F
+(pool manager)108 220.8 Q 2.5(,s)-.4 G(ee)171.2 220.8 Q F2(db_mpool)2.5 E F0
+(\(3\).).51 E
+(This manual page describes speci\214c details of the btree access method.)108
+237.6 Q 1.518(The btree data structure is a sorted, balanced tree structure st\
+oring associated k)108 254.4 R -.15(ey)-.1 G 1.517(/data pairs.).15 F
+(Searches,)6.517 E .598(insertions, and deletions in the btree will all comple\
+te in O lg base N where base is the a)108 266.4 R -.15(ve)-.2 G .598
+(rage \214ll f).15 F(actor)-.1 E(.)-.55 E .306
+(Often, inserting ordered data into btrees results in a lo)108 278.4 R 2.806
+<778c>-.25 G .305(ll f)341.61 278.4 R(actor)-.1 E 5.305(.T)-.55 G .305
+(his implementation has been modi\214ed)386.56 278.4 R(to mak)108 290.4 Q 2.5
+(eo)-.1 G(rdered insertion the best case, resulting in a much better than norm\
+al page \214ll f)147.34 290.4 Q(actor)-.1 E(.)-.55 E F1 -.495(AC)72 307.2 S
+(CESS METHOD SPECIFIC INFORMA).495 E(TION)-.855 E F0 .175
+(The btree access method speci\214c data structure pro)108 319.2 R .176
+(vided to)-.15 F F2(db_open)2.676 E F0 .176(is typedef)2.676 F 1.176 -.5('d a)
+.55 H .176(nd named BTREEINFO.).5 F 2.638(AB)108 331.2 S .138
+(TREEINFO structure has at least the follo)124.528 331.2 R .137
+(wing \214elds, which may be initialized before calling)-.25 F F2(db_open)2.637
+E F0(:).24 E(u_int cachesize;)108 348 Q 3.743(As)133 360 S 1.243
+(uggested maximum size \(in bytes\) of the memory cache.)147.853 360 R 1.243
+(This v)6.243 F 1.243(alue is)-.25 F/F3 10/Times-Bold@0 SF(only)3.743 E F0
+(advisory)3.743 E 3.744(,a)-.65 G 1.244(nd the)514.036 360 R .017
+(access method will allocate more memory rather than f)133 372 R 2.517
+(ail. Since)-.1 F -2.15 -.25(ev e)2.517 H .016(ry search e).25 F .016
+(xamines the root page)-.15 F 1.319
+(of the tree, caching the most recently used pages substantially impro)133 384
+R -.15(ve)-.15 G 3.82(sa).15 G 1.32(ccess time.)441.05 384 R 1.32(In addition,)
+6.32 F(ph)133 396 Q .911(ysical writes are delayed as long as possible, so a m\
+oderate cache can reduce the number of I/O)-.05 F 1.497
+(operations signi\214cantly)133 408 R 6.497(.O)-.65 G -.15(bv)243.674 408 S
+(iously).15 E 3.997(,u)-.65 G 1.497(sing a cache increases \(b)288.821 408 R
+1.498(ut only increases\) the lik)-.2 F 1.498(elihood of)-.1 F .336(corruption\
+ or lost data if the system crashes while a tree is being modi\214ed.)133 420 R
+(If)5.336 E F2(cac)2.836 E(hesize)-.15 E F0 .335(is 0 \(no size)2.835 F
+(is speci\214ed\) a def)133 432 Q(ault cache is used.)-.1 E
+(int \(*compare\)\(const DBT *, const DBT *\);)108 448.8 Q .194
+(Compare is the k)133 460.8 R .494 -.15(ey c)-.1 H .194(omparison function.).15
+F .194(It must return an inte)5.194 F .194
+(ger less than, equal to, or greater than)-.15 F .656(zero if the \214rst k)133
+472.8 R .956 -.15(ey a)-.1 H -.18(rg).15 G .656
+(ument is considered to be respecti).18 F -.15(ve)-.25 G .655
+(ly less than, equal to, or greater than the).15 F .798(second k)133 484.8 R
+1.098 -.15(ey a)-.1 H -.18(rg).15 G 3.298(ument. The).18 F .798
+(same comparison function must be used on a gi)3.298 F -.15(ve)-.25 G 3.298(nt)
+.15 G .799(ree e)462.774 484.8 R -.15(ve)-.25 G .799(ry time it is).15 F 2.79
+(opened. If)133 496.8 R F2(compar)2.79 E(e)-.37 E F0 .29
+(is NULL \(no comparison function is speci\214ed\), the k)2.79 F -.15(ey)-.1 G
+2.79(sa).15 G .29(re compared le)451.08 496.8 R(xically)-.15 E(,)-.65 E
+(with shorter k)133 508.8 Q -.15(ey)-.1 G 2.5(sc).15 G
+(onsidered less than longer k)208.57 508.8 Q -.15(ey)-.1 G(s.).15 E
+(u_long \215ags;)108 525.6 Q(The \215ag v)133 537.6 Q(alue is speci\214ed by)
+-.25 E F2(or)2.5 E F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)302.2 537.6 S
+(he follo)310.81 537.6 Q(wing v)-.25 E(alues:)-.25 E(R_DUP)133 554.4 Q .354
+(Permit duplicate k)158 566.4 R -.15(ey)-.1 G 2.854(si).15 G 2.854(nt)250.752
+566.4 S .355(he tree, i.e. permit insertion if the k)261.386 566.4 R .655 -.15
+(ey t)-.1 H 2.855(ob).15 G 2.855(ei)432.64 566.4 S .355(nserted already e)
+442.715 566.4 R .355(xists in)-.15 F 1.65(the tree.)158 578.4 R 1.65(The def)
+6.65 F 1.65(ault beha)-.1 F(vior)-.2 E 4.149(,a)-.4 G 4.149(sd)295.509 578.4 S
+1.649(escribed in)308.548 578.4 R F2(db_open)4.149 E F0 1.649(\(3\), is to o)
+.24 F -.15(ve)-.15 G 1.649(rwrite a matching k).15 F -.15(ey)-.1 G .783
+(when inserting a ne)158 590.4 R 3.283(wk)-.25 G 1.083 -.15(ey o)253.542 590.4
+T 3.283(rt).15 G 3.283(of)280.508 590.4 S .783(ail if the R_NOO)292.021 590.4 R
+(VER)-.5 E .784(WRITE \215ag is speci\214ed.)-.55 F .784(The R_DUP)5.784 F .129
+(\215ag is o)158 602.4 R -.15(ve)-.15 G .129(rridden by the R_NOO).15 F(VER)-.5
+E .128(WRITE \215ag, and if the R_NOO)-.55 F(VER)-.5 E .128
+(WRITE \215ag is spec-)-.55 F(i\214ed, attempts to insert duplicate k)158 614.4
+Q -.15(ey)-.1 G 2.5(si).15 G(nto the tree will f)314.69 614.4 Q(ail.)-.1 E .835
+(If the database contains duplicate k)158 631.2 R -.15(ey)-.1 G .835
+(s, the order of retrie).15 F -.25(va)-.25 G 3.335(lo).25 G 3.336(fk)414.7
+631.2 S -.15(ey)426.266 631.2 S .836(/data pairs is unde\214ned if).15 F(the)
+158 643.2 Q F2 -.1(ge)3.003 G(t).1 E F0 .503(function is used, ho)3.003 F(we)
+-.25 E -.15(ve)-.25 G -.4(r,).15 G F2(seq)3.403 E F0 .502
+(function calls with the R_CURSOR \215ag set will al)3.003 F -.1(wa)-.1 G(ys).1
+E(return the logical `)158 655.2 Q(`\214rst')-.74 E 2.5('o)-.74 G 2.5(fa)263.72
+655.2 S .3 -.15(ny g)273.99 655.2 T(roup of duplicate k).15 E -.15(ey)-.1 G(s.)
+.15 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315
+(ution August)-.2 F(1, 1995)2.5 E(1)535 732 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 113.45(DB_BTREE\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 113.45(anual DB_BTREE\(3\))340.17 48 R(int lorder;)108 84 Q .65
+(The byte order for inte)133 96 R .65(gers in the stored database metadata.)
+-.15 F .65(The number should represent the order)5.65 F .749(as an inte)133 108
+R .749(ger; for e)-.15 F .749(xample, big endian order w)-.15 F .749
+(ould be the number 4,321.)-.1 F(If)5.749 E/F1 10/Times-Italic@0 SF(lor)3.249 E
+(der)-.37 E F0 .749(is 0 \(no order is)3.249 F
+(speci\214ed\) the current host order is used.)133 120 Q(int maxk)108 136.8 Q
+-.15(ey)-.1 G(page;).15 E .073(The maximum number of k)133 148.8 R -.15(ey)-.1
+G 2.573(sw).15 G .073(hich will be stored on an)266.155 148.8 R 2.574(ys)-.15 G
+.074(ingle page.)376.436 148.8 R .074(This functionality is not cur)5.074 F(-)
+-.2 E(rently implemented.)133 160.8 Q(int mink)108 177.6 Q -.15(ey)-.1 G(page;)
+.15 E .532(The minimum number of k)133 189.6 R -.15(ey)-.1 G 3.031(sw).15 G
+.531(hich will be stored on an)266.787 189.6 R 3.031(ys)-.15 G .531
+(ingle page.)379.813 189.6 R .531(This v)5.531 F .531(alue is used to deter)
+-.25 F(-)-.2 E .558(mine which k)133 201.6 R -.15(ey)-.1 G 3.058(sw).15 G .558
+(ill be stored on o)211.914 201.6 R -.15(ve)-.15 G(r\215o).15 E 3.058(wp)-.25 G
+.558(ages, i.e. if a k)319.424 201.6 R .859 -.15(ey o)-.1 H 3.059(rd).15 G .559
+(ata item is longer than the page-)408.336 201.6 R .063(size di)133 213.6 R
+.063(vided by the mink)-.25 F -.15(ey)-.1 G .063(page v).15 F .063
+(alue, it will be stored on o)-.25 F -.15(ve)-.15 G(r\215o).15 E 2.563(wp)-.25
+G .062(ages instead of in the page itself.)408.816 213.6 R(If)133 225.6 Q F1
+(mink)2.5 E -.3(ey)-.1 G(pa).3 E -.1(ge)-.1 G F0(is 0 \(no minimum number of k)
+2.6 E -.15(ey)-.1 G 2.5(si).15 G 2.5(ss)332.96 225.6 S(peci\214ed\) a v)343.24
+225.6 Q(alue of 2 is used.)-.25 E
+(size_t \(*pre\214x\)\(const DBT *, const DBT *\);)108 242.4 Q .691
+(Pre\214x is the pre\214x comparison function.)133 254.4 R .692
+(If speci\214ed, this function must return the number of bytes)5.691 F .195
+(of the second k)133 266.4 R .495 -.15(ey a)-.1 H -.18(rg).15 G .195
+(ument which are necessary to determine that it is greater than the \214rst k)
+.18 F .495 -.15(ey a)-.1 H -.18(rg).15 G(u-).18 E 2.994(ment. If)133 278.4 R
+.494(the k)2.994 F -.15(ey)-.1 G 2.994(sa).15 G .494(re equal, the k)211.376
+278.4 R .794 -.15(ey l)-.1 H .494(ength should be returned.).15 F .494
+(Note, the usefulness of this function)5.494 F .327(is v)133 290.4 R .327
+(ery data dependent, b)-.15 F .326(ut, in some data sets can produce signi\214\
+cantly reduced tree sizes and search)-.2 F 2.789(times. If)133 302.4 R F1(pr)
+2.789 E(e\214x)-.37 E F0 .289(is NULL \(no pre\214x function is speci\214ed\),)
+2.789 F/F2 10/Times-Bold@0 SF(and)2.789 E F0 .29
+(no comparison function is speci\214ed, a)2.79 F(def)133 314.4 Q .902(ault le)
+-.1 F .902(xical comparison function is used.)-.15 F(If)5.901 E F1(pr)3.401 E
+(e\214x)-.37 E F0 .901(is NULL and a comparison function is speci-)3.401 F
+(\214ed, no pre\214x comparison is done.)133 326.4 Q(u_int psize;)108 343.2 Q
+-.15(Pa)133 355.2 S .118
+(ge size is the size \(in bytes\) of the pages used for nodes in the tree.).15
+F .119(The minimum page size is 512)5.119 F .377
+(bytes and the maximum page size is 64K.)133 367.2 R(If)5.376 E F1(psize)2.876
+E F0 .376(is 0 \(no page size is speci\214ed\) a page size is cho-)2.876 F
+(sen based on the underlying \214le system I/O block size.)133 379.2 Q .79
+(If the \214le already e)108 396 R .79(xists \(and the O_TR)-.15 F .79
+(UNC \215ag is not speci\214ed\), the v)-.4 F .79
+(alues speci\214ed for the parameters)-.25 F
+(\215ags, lorder and psize are ignored in f)108 408 Q -.2(avo)-.1 G 2.5(ro).2 G
+2.5(ft)284.4 408 S(he v)293.01 408 Q(alues used when the tree w)-.25 E
+(as created.)-.1 E/F3 9/Times-Bold@0 SF(DB OPERA)72 424.8 Q(TIONS)-.855 E F0
+1.037(The functions returned by)108 436.8 R F1(db_open)3.537 E F0 1.036
+(for the btree access method are as described in)3.536 F F1(db_open)3.536 E F0
+1.036(\(3\), with the).24 F(follo)108 448.8 Q(wing e)-.25 E
+(xceptions and additions:)-.15 E 5.28(type The)108 465.6 R(type is DB_BTREE.)
+2.5 E 10.28(del Space)108 482.4 R 1.681(freed up by deleting k)4.181 F -.15(ey)
+-.1 G 1.681(/data pairs from the tree is ne).15 F -.15(ve)-.25 G 4.181(rr).15 G
+1.682(eclaimed, although it is reused)411.342 482.4 R .734(where possible.)133
+494.4 R .734(This means that the btree storage structure is gro)5.734 F(w-only)
+-.25 E 5.734(.T)-.65 G .734(he only solutions are to)443.734 494.4 R -.2(avo)
+133 506.4 S(id e).2 E(xcessi)-.15 E .3 -.15(ve d)-.25 H
+(eletions, or to create a fresh tree periodically from a scan of an e).15 E
+(xisting one.)-.15 E 9.72(put The)108 523.2 R F1(put)2.5 E F0(function tak)2.5
+E(es the follo)-.1 E(wing additional \215ags:)-.25 E(R_SETCURSOR)133 540 Q
+(Store the k)158 552 Q -.15(ey)-.1 G(/data pair).15 E 2.5(,s)-.4 G
+(etting or initializing the position of the cursor to reference it.)256.5 552 Q
+9.17(seq F)108 568.8 R(orw)-.15 E
+(ard sequential scans of a tree are from the least k)-.1 E .3 -.15(ey t)-.1 H
+2.5(ot).15 G(he greatest.)373.55 568.8 Q .892(The returned k)133 585.6 R 1.192
+-.15(ey f)-.1 H .892(or the).15 F F1(seq)3.393 E F0 .893
+(function is not necessarily an e)3.393 F .893
+(xact match for the speci\214ed k)-.15 F 1.193 -.15(ey i)-.1 H 3.393(nt).15 G
+(he)530.56 585.6 Q .5(btree access method.)133 597.6 R .5(The returned k)5.5 F
+.8 -.15(ey i)-.1 H 3(st).15 G .499(he smallest k)307.04 597.6 R .799 -.15(ey g)
+-.1 H .499(reater than or equal to the speci\214ed k).15 F -.15(ey)-.1 G(,)-.5
+E(permitting partial k)133 609.6 Q .3 -.15(ey m)-.1 H
+(atches and range searches.).15 E(The)133 626.4 Q F1(seq)2.5 E F0(function tak)
+2.5 E(es the follo)-.1 E(wing additional \215ags:)-.25 E(R_LAST)133 643.2 Q .04
+(The last k)158 655.2 R -.15(ey)-.1 G .04(/data pair of the database is return\
+ed, and the cursor is set or initialized to reference).15 F(it.)158 667.2 Q
+(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315
+(ution August)-.2 F(1, 1995)2.5 E(2)535 732 Q EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 113.45(DB_BTREE\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 113.45(anual DB_BTREE\(3\))340.17 48 R(R_PREV)133 84 Q(Retrie)158 96
+Q .59 -.15(ve t)-.25 H .29(he k).15 F -.15(ey)-.1 G .29
+(/data pair immediately before the cursor).15 F 5.29(.I)-.55 G 2.79(ft)395.73
+96 S .29(he cursor is not yet set, this is the)404.63 96 R
+(same as the R_LAST \215ag.)158 108 Q/F1 9/Times-Bold@0 SF(ERR)72 124.8 Q(ORS)
+-.27 E F0(The)108 136.8 Q/F2 10/Times-Italic@0 SF(btr)2.541 E(ee)-.37 E F0 .041
+(access method functions may f)2.541 F .041(ail and set)-.1 F F2(errno)2.541 E
+F0 .041(for an)2.541 F 2.541(yo)-.15 G 2.541(ft)376.152 136.8 S .041
+(he errors speci\214ed for the library func-)384.803 136.8 R(tion)108 148.8 Q
+F2(db_open)2.5 E F0(\(3\).).24 E F1(SEE ALSO)72 165.6 Q F2(db_hash)108 177.6 Q
+F0(\(3\),).28 E F2(db_loc)2.5 E(k)-.2 E F0(\(3\),).67 E F2(db_lo)2.5 E(g)-.1 E
+F0(\(3\),).22 E F2(db_mpool)2.5 E F0(\(3\),).51 E F2(db_open)2.5 E F0(\(3\),)
+.24 E F2(db_r)2.5 E(ecno)-.37 E F0(\(3\),).18 E F2(db_txn)2.5 E F0(\(3\)).24 E
+F2(The Ubiquitous B-tr)108 201.6 Q(ee)-.37 E F0 2.5(,D).18 G(ouglas Comer)
+209.47 201.6 Q 2.5(,A)-.4 G(CM Comput. Surv)276.72 201.6 Q 2.5(.1)-.65 G
+(1, 2 \(June 1979\), 121-138.)360.25 201.6 Q F2(Pr)108 225.6 Q 1.588
+(e\214x B-tr)-.37 F(ees)-.37 E F0 4.088(,B).27 G 1.587(ayer and Unterauer)
+177.636 225.6 R 4.087(,A)-.4 G 1.587(CM T)270.447 225.6 R 1.587
+(ransactions on Database Systems, V)-.35 F 1.587(ol. 2, 1 \(March 1977\),)-1.29
+F(11-26.)108 237.6 Q F2(The Art of Computer Pr)108 261.6 Q -.1(og)-.45 G -.15
+(ra).1 G(mming V).15 E(ol. 3: Sorting and Sear)-1.11 E -.15(ch)-.37 G(ing).15 E
+F0 2.5(,D).22 G(.E. Knuth, 1968, pp 471-480.)382 261.6 Q(4.4 Berk)72 732 Q(ele)
+-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E
+(3)535 732 Q EP
+%%Page: 1 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 117.9(DB_HASH\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 117.9(anual DB_HASH\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72
+84 S(ME).18 E F0(db_hash \255 hash database access method)108 96 Q F1
+(DESCRIPTION)72 112.8 Q F0 .485(The DB library is a f)108 124.8 R .485
+(amily of groups of functions that pro)-.1 F .486
+(vides a modular programming interf)-.15 F .486(ace to trans-)-.1 F .823
+(actions and record-oriented \214le access.)108 136.8 R .822
+(The library includes support for transaction, locking, logging and)5.822 F
+.258(\214le b)108 148.8 R(uf)-.2 E .258(fering functionality)-.25 F 2.758(,a)
+-.65 G 2.758(sw)223.214 148.8 S .258(ell as v)237.082 148.8 R .258(arious inde)
+-.25 F -.15(xe)-.15 G 2.758(da).15 G .258(ccess methods.)331.434 148.8 R(Man)
+5.258 E 2.758(yo)-.15 G 2.758(ft)427.878 148.8 S .258
+(he functional groups \(e.g.)436.746 148.8 R .528(the memory pool functions\) \
+are useful independently of the rest of the DB functions, although some func-)
+108 160.8 R .306(tional groups are e)108 172.8 R .306
+(xplicitly based on other functional groups \(e.g.)-.15 F .306
+(transactions and logging\).)5.306 F -.15(Fo)5.306 G 2.806(rag).15 G(eneral)
+515.57 172.8 Q .245(description of transactions, see)108 184.8 R/F2 10
+/Times-Italic@0 SF(db_txn)2.745 E F0 2.745(\(3\). F).24 F .245
+(or a general description of the access methods, see)-.15 F F2(db_open)2.745 E
+F0(\(3\)).24 E .307(and then the indi)108 196.8 R .307
+(vidual access method manual pages:)-.25 F F2(db_btr)2.808 E(ee)-.37 E F0
+(\(3\),).18 E F2(db_hash)2.808 E F0(\(3\),).28 E F2(db_lo)2.808 E(g)-.1 E F0
+.308(\(3\) and).22 F F2(db_r)2.808 E(ecno)-.37 E F0(\(3\).).18 E -.15(Fo)108
+208.8 S 3.635(rag).15 G 1.135(eneral description of the lock manager)138.45
+208.8 R 3.635(,s)-.4 G(ee)307.32 208.8 Q F2(db_loc)3.635 E(k)-.2 E F0 3.635
+(\(3\). F).67 F 1.135(or a general description of the memory)-.15 F
+(pool manager)108 220.8 Q 2.5(,s)-.4 G(ee)171.2 220.8 Q F2(db_mpool)2.5 E F0
+(\(3\).).51 E
+(This manual page describes speci\214c details of the hashing access method.)
+108 237.6 Q .59(The hash data structure is an e)108 254.4 R .591
+(xtensible, dynamic hashing scheme.)-.15 F(Backw)5.591 E .591
+(ard compatible interf)-.1 F .591(aces to the)-.1 F .209
+(functions described in)108 266.4 R F2(dbm)2.709 E F0 .209(\(3\), and).32 F F2
+(ndbm)2.709 E F0 .209(\(3\) are pro).32 F .209(vided, ho)-.15 F(we)-.25 E -.15
+(ve)-.25 G 2.708(rt).15 G .208(hese interf)382.71 266.4 R .208
+(aces are not compatible with)-.1 F(pre)108 278.4 Q(vious \214le formats.)-.25
+E F1 -.495(AC)72 295.2 S(CESS METHOD SPECIFIC INFORMA).495 E(TION)-.855 E F0
+.612(The hash access method speci\214c data structure pro)108 307.2 R .612
+(vided to)-.15 F F2(db_open)3.112 E F0 .612(is typedef)3.112 F 1.612 -.5('d a)
+.55 H .613(nd named HASHINFO.).5 F 2.5(AH)108 319.2 S
+(ASHINFO structure has at least the follo)124.94 319.2 Q
+(wing \214elds, which may be initialized before calling)-.25 E F2(db_open)2.5 E
+F0(:).24 E(u_int bsize;)108 336 Q F2(Bsize)133 348 Q F0 2.041
+(de\214nes the hash table b)4.541 F(uck)-.2 E 2.041(et size, and is, by def)-.1
+F 2.04(ault, 256 bytes.)-.1 F 2.04(It may be preferable to)7.04 F
+(increase the page size for disk-resident tables and tables with lar)133 360 Q
+(ge data items.)-.18 E(u_int cachesize;)108 376.8 Q 3.846(As)133 388.8 S 1.347
+(uggested maximum size, in bytes, of the memory cache.)147.956 388.8 R 1.347
+(This v)6.347 F 1.347(alue is)-.25 F/F3 10/Times-Bold@0 SF(only)3.847 E F0
+(advisory)3.847 E 3.847(,a)-.65 G 1.347(nd the)513.933 388.8 R
+(access method will allocate more memory rather than f)133 400.8 Q(ail.)-.1 E
+(u_int f)108 417.6 Q -.1(fa)-.25 G(ctor;).1 E F2(Ffactor)133 429.6 Q F0 1.17
+(indicates a desired density within the hash table.)3.67 F 1.169
+(It is an approximation of the number of)6.169 F -.1(ke)133 441.6 S 1.162
+(ys allo)-.05 F 1.162(wed to accumulate in an)-.25 F 3.662(yo)-.15 G 1.162
+(ne b)284.852 441.6 R(uck)-.2 E 1.162(et, determining when the hash table gro)
+-.1 F 1.162(ws or shrinks.)-.25 F(The def)133 453.6 Q(ault v)-.1 E(alue is 8.)
+-.25 E(u_int32_t \(*hash\)\(const v)108 470.4 Q(oid *, size_t\);)-.2 E F2(Hash)
+133 482.4 Q F0 .788(is a user de\214ned hash function.)3.288 F .787
+(Since no hash function performs equally well on all possible)5.788 F .017
+(data, the user may \214nd that the b)133 494.4 R .018
+(uilt-in hash function does poorly on a particular data set.)-.2 F .018
+(User speci-)5.018 F 1.154(\214ed hash functions must tak)133 506.4 R 3.654(et)
+-.1 G 1.354 -.1(wo a)260.61 506.4 T -.18(rg).1 G 1.154
+(uments \(a pointer to a byte string and a length\) and return a).18 F
+(32-bit quantity to be used as the hash v)133 518.4 Q(alue.)-.25 E .665
+(If a hash function is speci\214ed,)133 535.2 R F2(hash_open)3.165 E F0 .666
+(will attempt to determine if the hash function speci\214ed is)3.166 F
+(the same as the one with which the database w)133 547.2 Q
+(as created, and will f)-.1 E(ail if it is not.)-.1 E(int lorder;)108 564 Q .65
+(The byte order for inte)133 576 R .65(gers in the stored database metadata.)
+-.15 F .65(The number should represent the order)5.65 F .748(as an inte)133 588
+R .749(ger; for e)-.15 F .749(xample, big endian order w)-.15 F .749
+(ould be the number 4,321.)-.1 F(If)5.749 E F2(lor)3.249 E(der)-.37 E F0 .749
+(is 0 \(no order is)3.249 F .456(speci\214ed\) the current host order is used.)
+133 600 R .456(If the)5.456 F .456(\214le already e)5.456 F .456
+(xists, the speci\214ed v)-.15 F .455(alue is ignored and)-.25 F(the v)133 612
+Q(alue speci\214ed when the tree w)-.25 E(as created is used.)-.1 E
+(u_int nelem;)108 628.8 Q F2(Nelem)133 640.8 Q F0 1.225
+(is an estimate of the \214nal size of the hash table.)3.724 F 1.225
+(If not set or set too lo)6.225 F 2.525 -.65(w, h)-.25 H 1.225(ash tables will)
+.65 F -.15(ex)133 652.8 S 1.294(pand gracefully as k).15 F -.15(ey)-.1 G 3.794
+(sa).15 G 1.294(re entered, although a slight performance de)248.296 652.8 R
+1.293(gradation may be noticed.)-.15 F(The def)133 664.8 Q(ault v)-.1 E
+(alue is 1.)-.25 E .79(If the \214le already e)108 681.6 R .79
+(xists \(and the O_TR)-.15 F .79(UNC \215ag is not speci\214ed\), the v)-.4 F
+.79(alues speci\214ed for the parameters)-.25 F(bsize, f)108 693.6 Q -.1(fa)
+-.25 G(ctor).1 E 2.5(,l)-.4 G(order and nelem are ignored and the v)167.23
+693.6 Q(alues speci\214ed when the tree w)-.25 E(as created are used.)-.1 E
+(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315
+(ution August)-.2 F(1, 1995)2.5 E(1)535 732 Q EP
+%%Page: 2 5
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 117.9(DB_HASH\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 117.9(anual DB_HASH\(3\))340.17 48 R/F1 9/Times-Bold@0 SF(DB OPERA)
+72 84 Q(TIONS)-.855 E F0(The functions returned by)108 96 Q/F2 10
+/Times-Italic@0 SF(db_open)2.5 E F0
+(for the hash access method are as described in)2.5 E F2(db_open)2.5 E F0
+(\(3\).).24 E F1(ERR)72 112.8 Q(ORS)-.27 E F0(The)108 124.8 Q F2(hash)2.609 E
+F0 .109(access method functions may f)2.609 F .109(ail and set)-.1 F F2(errno)
+2.609 E F0 .109(for an)2.609 F 2.609(yo)-.15 G 2.609(ft)375.678 124.8 S .109
+(he errors speci\214ed for the library func-)384.397 124.8 R(tion)108 136.8 Q
+F2(db_open)2.5 E F0(\(3\).).24 E F1(SEE ALSO)72 153.6 Q F2(db_btr)108 165.6 Q
+(ee)-.37 E F0(\(3\),).18 E F2(db_loc)2.5 E(k)-.2 E F0(\(3\),).67 E F2(db_lo)2.5
+E(g)-.1 E F0(\(3\),).22 E F2(db_mpool)2.5 E F0(\(3\),).51 E F2(db_open)2.5 E F0
+(\(3\),).24 E F2(db_r)2.5 E(ecno)-.37 E F0(\(3\),).18 E F2(db_txn)2.5 E F0
+(\(3\)).24 E F2(Dynamic Hash T)108 189.6 Q(ables)-.92 E F0 2.5(,P).27 G(er)
+206.79 189.6 Q(-Ak)-.2 E 2.5(eL)-.1 G(arson, Communications of the A)242.86
+189.6 Q(CM, April 1988.)-.4 E F2 2.5(AN)108 213.6 S .3 -.15(ew H)123.28 213.6 T
+(ash P).15 E(ac)-.8 E(ka)-.2 E .2 -.1(ge f)-.1 H(or UNIX).1 E F0 2.5(,M).94 G
+(ar)248.41 213.6 Q(go Seltzer)-.18 E 2.5(,U)-.4 G(SENIX Proceedings, W)308.09
+213.6 Q(inter 1991.)-.4 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)
+132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(2)535 732 Q EP
+%%Page: 1 6
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 117.9(DB_LOCK\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 117.9(anual DB_LOCK\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72
+84 S(ME).18 E F0(db_lock \255 general purpose lock manager)108 96 Q F1
+(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF(#include <db_lock.h>)108 124.8 Q
+(int)108 148.8 Q(lock_cr)108 160.8 Q(eate\(const char *path, mode_t mode,)-.18
+E(int lock_modes, const int8_t con\215icts[][], u_int maxlocks\);)158 172.8 Q
+(LOCK_T)108 196.8 Q(ABLE_T *)-.9 E(lock_open\(const char *path\);)108 208.8 Q
+(int)108 232.8 Q(lock_v)108 244.8 Q(ec\(LOCK_T)-.1 E(ABLE_T *lt, DBT *lock)-.9
+E(er)-.1 E 2.5(,s)-.92 G(truct timespec *timeout,)308.21 244.8 Q
+(LOCK_REQ_T list[], int nlist, LOCK_REQ_T **elistp, DBT *con\215ict\);)158
+256.8 Q(int)108 280.8 Q(lock_get\(LOCK_T)108 292.8 Q
+(ABLE_T *lt, const DBT *lock)-.9 E(er)-.1 E(,)-.92 E
+(const DBT *obj, const lock_mode_t lock_mode, LOCK_T **lockp\);)158 304.8 Q
+(int)108 328.8 Q(lock_put\(LOCK_T *lockp\);)108 340.8 Q(int)108 364.8 Q
+(lock_close\(LOCK_T)108 376.8 Q(ABLE_T *lt\);)-.9 E(int)108 400.8 Q
+(lock_unlink\(const char *path, int f)108 412.8 Q(or)-.25 E(ce\);)-.18 E F1
+(DESCRIPTION)72 429.6 Q F0 .485(The DB library is a f)108 441.6 R .485
+(amily of groups of functions that pro)-.1 F .486
+(vides a modular programming interf)-.15 F .486(ace to trans-)-.1 F .823
+(actions and record-oriented \214le access.)108 453.6 R .822
+(The library includes support for transaction, locking, logging and)5.822 F
+.258(\214le b)108 465.6 R(uf)-.2 E .258(fering functionality)-.25 F 2.758(,a)
+-.65 G 2.758(sw)223.214 465.6 S .258(ell as v)237.082 465.6 R .258(arious inde)
+-.25 F -.15(xe)-.15 G 2.758(da).15 G .258(ccess methods.)331.434 465.6 R(Man)
+5.258 E 2.758(yo)-.15 G 2.758(ft)427.878 465.6 S .258
+(he functional groups \(e.g.)436.746 465.6 R .528(the memory pool functions\) \
+are useful independently of the rest of the DB functions, although some func-)
+108 477.6 R .306(tional groups are e)108 489.6 R .306
+(xplicitly based on other functional groups \(e.g.)-.15 F .306
+(transactions and logging\).)5.306 F -.15(Fo)5.306 G 2.806(rag).15 G(eneral)
+515.57 489.6 Q .245(description of transactions, see)108 501.6 R/F3 10
+/Times-Italic@0 SF(db_txn)2.745 E F0 2.745(\(3\). F).24 F .245
+(or a general description of the access methods, see)-.15 F F3(db_open)2.745 E
+F0(\(3\)).24 E .307(and then the indi)108 513.6 R .307
+(vidual access method manual pages:)-.25 F F3(db_btr)2.808 E(ee)-.37 E F0
+(\(3\),).18 E F3(db_hash)2.808 E F0(\(3\),).28 E F3(db_lo)2.808 E(g)-.1 E F0
+.308(\(3\) and).22 F F3(db_r)2.808 E(ecno)-.37 E F0(\(3\).).18 E -.15(Fo)108
+525.6 S 3.635(rag).15 G 1.135(eneral description of the lock manager)138.45
+525.6 R 3.635(,s)-.4 G(ee)307.32 525.6 Q F3(db_loc)3.635 E(k)-.2 E F0 3.635
+(\(3\). F).67 F 1.135(or a general description of the memory)-.15 F
+(pool manager)108 537.6 Q 2.5(,s)-.4 G(ee)171.2 537.6 Q F3(db_mpool)2.5 E F0
+(\(3\).).51 E
+(This manual page describes speci\214c details of the locking interf)108 554.4
+Q(ace.)-.1 E F3(Db_loc)108 571.2 Q(k)-.2 E F0 .346(is the library interf)2.846
+F .346(ace intended to pro)-.1 F .346(vide general-purpose locking.)-.15 F .347
+(While designed to w)5.347 F .347(ork with)-.1 F .946(the other DB functions, \
+these functions are also useful for more general locking purposes.)108 583.2 R
+.946(Locks can be)5.946 F(shared between processes.)108 595.2 Q .682
+(The function)108 612 R F3(loc)3.182 E(k_cr)-.2 E(eate)-.37 E F0 .683
+(creates and initializes the lock table identi\214ed by the)3.182 F F3(path)
+3.183 E F0(directory)3.183 E 5.683(.T)-.65 G .683(his direc-)501.827 612 R .565
+(tory must already e)108 624 R .565(xist when)-.15 F F3(loc)3.065 E(k_cr)-.2 E
+(eate)-.37 E F0 .565(is called.)3.065 F .565(If the lock table identi\214ed by)
+5.565 F F3(path)3.064 E F0 .564(already e)3.064 F .564(xists, then)-.15 F F3
+(loc)108 636 Q(k_cr)-.2 E(eate)-.37 E F0 .974
+(returns success without further action.)3.474 F .974
+(The \214les associated with the lock table are created in)5.974 F 2.017
+(the directory speci\214ed by)108 648 R F3(path)4.517 E F0 7.017(.\().28 G
+2.017(The group of the created \214les is based on the system and directory)
+250.846 648 R(def)108 660 Q .076(aults, and is not further speci\214ed by)-.1 F
+F3(loc)2.576 E(k_cr)-.2 E(eate)-.37 E F0 2.576(.\) All).18 F .076
+(\214les created by)2.576 F F3(loc)2.576 E(k_cr)-.2 E(eate)-.37 E F0 .077
+(are created with mode)2.577 F F3(mode)108 672 Q F0(\(as described in)2.5 E F3
+-.15(ch)2.5 G(mod).15 E F0(\(2\)\) and modi\214ed by the process' umask v).77 E
+(alue \(see)-.25 E F3(umask)2.5 E F0(\(2\)\).).67 E .739(The parameter)108
+688.8 R F3(loc)3.239 E(k_modes)-.2 E F0 .739(is the number of lock modes to be\
+ recognized by the lock table \(including the)3.239 F(4.4 Berk)72 732 Q(ele)-.1
+E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(1)
+535 732 Q EP
+%%Page: 2 7
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 117.9(DB_LOCK\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 117.9(anual DB_LOCK\(3\))340.17 48 R -.74(``)108 84 S(not-granted')
+.74 E 2.5('m)-.74 G 2.5(ode\). The)176.22 84 R(parameter)2.5 E/F1 10
+/Times-Italic@0 SF(con\215icts)2.5 E F0(is an)2.5 E F1(loc)2.5 E(k_modes)-.2 E
+F0(by)2.5 E F1(loc)2.5 E(k_modes)-.2 E F0(array)2.5 E 5(.A)-.65 G(non-0 v)
+467.59 84 Q(alue for:)-.25 E(con\215icts[requested_mode][held_mode])158 108 Q
+.174(indicates that)108 132 R F1 -.37(re)2.674 G(quested_mode).37 E F0(and)
+2.674 E F1(held_mode)2.674 E F0 2.675(con\215ict. The)2.674 F -.74(``)2.675 G
+(not-granted').74 E 2.675('m)-.74 G .175(ode must be represented by 0.)419.705
+132 R(The include \214le <db_lock.h> declares tw)108 148.8 Q 2.5(oc)-.1 G
+(ommonly used con\215ict arrays:)283.87 148.8 Q(int lock_sx_n;)108 165.6 Q
+(const int8_t lock_sx_c[lock_sx_n][lock_sx_n];)108 177.6 Q(These v)133 189.6 Q
+(ariables specify a con\215ict array for a simple scheme using shared and e)
+-.25 E(xclusi)-.15 E .3 -.15(ve l)-.25 H(ock modes.).15 E(int lock_g_n;)108
+206.4 Q(const int8_t lock_g_c[lock_g_n][lock_g_n];)108 218.4 Q 1.071(These v)
+133 230.4 R 1.071(ariables specify a con\215ict array that in)-.25 F -.2(vo)-.4
+G(lv).2 E 1.071(es v)-.15 F 1.07
+(arious intent lock modes \(e.g. intent shared\))-.25 F
+(that are used for multigranularity locking.)133 242.4 Q 1.53
+(In addition, <db_lock.h> de\214nes the follo)108 259.2 R 1.531
+(wing macros that name lock modes for use with the standard)-.25 F(tables abo)
+108 271.2 Q -.15(ve)-.15 G(:).15 E(LOCK_IS)144 288 Q(intent shared)169 300 Q
+(LOCK_IX)144 312 Q(intent e)169 324 Q(xclusi)-.15 E -.15(ve)-.25 G(LOCK_NG)144
+336 Q(not granted \(al)169 348 Q -.1(wa)-.1 G(ys 0\)).1 E(LOCK_S)144 360 Q
+(shared)169 372 Q(LOCK_SIX)144 384 Q(shared/intent e)169 396 Q(xclusi)-.15 E
+-.15(ve)-.25 G(LOCK_X)144 408 Q -.15(ex)169 420 S(clusi).15 E -.15(ve)-.25 G F1
+(Maxloc)108 436.8 Q(ks)-.2 E F0 .442(is the maximum number of locks to be held\
+ or requested in the table, and is used by)2.942 F F1(loc)2.941 E(k_cr)-.2 E
+(eate)-.37 E F0(to estimate ho)108 448.8 Q 2.5(wm)-.25 G
+(uch space to allocate for v)181.36 448.8 Q(arious lock-table data structures.)
+-.25 E(The function)108 465.6 Q F1(loc)2.5 E(k_cr)-.2 E(eate)-.37 E F0
+(returns -1 on f)2.5 E(ailure, setting)-.1 E F1(errno)2.5 E F0 2.5(,a).18 G
+(nd 0 on success.)356.07 465.6 Q .202(The function)108 482.4 R F1(loc)2.703 E
+(k_open)-.2 E F0 .203(returns a pointer to the lock table identi\214ed by)2.703
+F F1(path)2.703 E F0 2.703(,w).28 G .203(hich must ha)425.678 482.4 R .503 -.15
+(ve a)-.2 H .203(lready been).15 F 1.162(created by a call to)108 494.4 R F1
+(loc)3.661 E(k_cr)-.2 E(eate)-.37 E F0 6.161(.T).18 G 1.161(he process must ha)
+252.869 494.4 R 1.461 -.15(ve p)-.2 H 1.161
+(ermission to read and write \214les with o).15 F(wners,)-.25 E .06
+(groups and permissions as described for)108 506.4 R F1(loc)2.56 E(k_cr)-.2 E
+(eate)-.37 E F0 5.06(.T).18 G(he)331.04 506.4 Q F1(loc)2.56 E(k_open)-.2 E F0
+.06(function returns NULL on f)2.56 F .06(ailure, set-)-.1 F(ting)108 518.4 Q
+F1(errno)2.5 E F0(.).18 E .986(The function)108 535.2 R F1(loc)3.486 E(k_vec)
+-.2 E F0 .986
+(atomically obtains and releases one or more locks from the designated table.)
+3.486 F(The)5.986 E(function)108 547.2 Q F1(loc)4.52 E(k_vec)-.2 E F0 2.02(is \
+intended to support acquisition or trading of multiple locks under one lock ta\
+ble)4.52 F(semaphore, as is needed for lock coupling or in multigranularity lo\
+cking for lock escalation.)108 559.2 Q .746(If an)108 576 R 3.246(yo)-.15 G
+3.246(ft)140.442 576 S .746(he requested locks cannot be acquired or an)149.798
+576 R 3.246(yo)-.15 G 3.246(ft)342.786 576 S .746
+(he locks to be released cannot be released, no)352.142 576 R .117
+(locks are acquired and no locks are released, and)108 588 R F1(loc)2.617 E
+(k_vec)-.2 E F0 .117(returns an error)2.617 F 5.117(.T)-.55 G .117(he function)
+419.211 588 R F1(loc)2.617 E(k_vec)-.2 E F0 .118(returns 0)2.617 F 1.143
+(on success.)108 600 R 1.143(If an error occurs,)6.143 F F1(loc)3.642 E(k_vec)
+-.2 E F0 1.142(returns one of the follo)3.642 F 1.142(wing v)-.25 F 3.642
+(alues. In)-.25 F 1.142(addition, if)3.642 F F1(elistp)3.642 E F0 1.142(is not)
+3.642 F(NULL, it is set to point to the LOCK_REQ_T entry which w)108 612 Q
+(as being processed when the error occurred.)-.1 E(LOCK_GET_DEADLOCK)108 628.8
+Q .431(The speci\214ed)133 640.8 R F1(loc)2.931 E -.1(ke)-.2 G(r).1 E F0 -.1
+(wa)2.931 G 2.931(ss).1 G .431(elected as a victim in order to resolv)239.854
+640.8 R 2.932(ead)-.15 G 2.932(eadlock. In)407.718 640.8 R .432
+(this case, if the)2.932 F F1(con-)2.932 E(\215ict)133 652.8 Q F0(ar)2.901 E
+.401(gument is non-NULL, it is set to reference the identity of a lock)-.18 F
+.4(er holding the lock referenced)-.1 F(by)133 664.8 Q F1(elistp)2.585 E F0
+.085(at the time the request w)2.585 F .085(as denied.)-.1 F .086
+(\(This identity resides in static memory and may be o)5.086 F -.15(ve)-.15 G
+-.2(r-).15 G(written by subsequent calls to)133 676.8 Q F1(loc)2.5 E(k_vec)-.2
+E F0(\).).31 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q
+99.315(ution August)-.2 F(1, 1995)2.5 E(2)535 732 Q EP
+%%Page: 3 8
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 117.9(DB_LOCK\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 117.9(anual DB_LOCK\(3\))340.17 48 R(LOCK_GET_ERR)108 84 Q(OR)-.4 E
+(An error occurred and the e)133 96 Q(xternal v)-.15 E(ariable)-.25 E/F1 10
+/Times-Italic@0 SF(errno)2.5 E F0(has been set to indicate the error)2.5 E(.)
+-.55 E(LOCK_GET_NO)108 112.8 Q(THELD)-.4 E
+(The lock cannot be released, as it w)133 124.8 Q(as not held by the)-.1 E F1
+(loc)2.5 E -.1(ke)-.2 G(r).1 E F0(.).73 E(LOCK_GET_RESOURCE)108 141.6 Q 2.311(\
+The lock manager is unable to grant the requested locks because of limited int\
+ernal resources.)133 153.6 R(\(Releasing locks may allo)133 165.6 Q 2.5(wf)-.25
+G(uture calls to)249.4 165.6 Q F1(loc)2.5 E(k_vec)-.2 E F0(to succeed.\))2.5 E
+(LOCK_GET_TIMEOUT)108 182.4 Q 3.204(At)133 194.4 S .704(imeout ar)146.204 194.4
+R .704(gument w)-.18 F .705(as speci\214ed, and the requested locks were not a)
+-.1 F -.25(va)-.2 G .705(ilable soon enough.).25 F .705(In this)5.705 F .625
+(case, if the)133 206.4 R F1(con\215ict)3.125 E F0(ar)3.125 E .624
+(gument is non-NULL, it is set to reference the identity of a lock)-.18 F .624
+(er holding the)-.1 F .551(lock referenced by)133 218.4 R F1(elistp)3.052 E F0
+.552(at the time the request w)3.052 F .552(as denied.)-.1 F .552
+(\(This identity resides in static memory)5.552 F(and may be o)133 230.4 Q -.15
+(ve)-.15 G(rwritten by subsequent calls to).15 E F1(loc)2.5 E(k_vec)-.2 E F0
+(\).).31 E(The)108 247.2 Q F1(loc)3.005 E -.1(ke)-.2 G(r).1 E F0(ar)3.005 E
+.504(gument speci\214ed to)-.18 F F1(loc)3.004 E(k_vec)-.2 E F0 .504
+(is a pointer to an untyped byte string which identi\214es the entity)3.004 F
+(requesting or releasing the lock.)108 259.2 Q(If)5 E F1(loc)2.5 E -.1(ke)-.2 G
+(r).1 E F0(is NULL, the calling process' pid is used instead.)2.5 E(The)108 276
+Q F1(timeout)4.628 E F0(ar)4.628 E 2.128(gument pro)-.18 F 2.128(vided to)-.15
+F F1(loc)4.628 E(k_vec)-.2 E F0 2.128(speci\214es a maximum interv)4.628 F
+2.128(al to w)-.25 F 2.128(ait for the locks to be)-.1 F 2.642(granted. If)108
+288 R F1(timeout)2.642 E F0 .142(is NULL, it is ignored, and)2.642 F F1(loc)
+2.642 E(k_vec)-.2 E F0 .141
+(will not return until all of the locks are acquired or)2.642 F
+(an error has occurred.)108 300 Q(The)108 316.8 Q F1(list)4.263 E F0 1.764
+(array pro)4.263 F 1.764(vided to)-.15 F F1(loc)4.264 E(k_vec)-.2 E F0 1.764
+(is typedef)4.264 F 2.764 -.5('d i).55 H 4.264(n<).5 G 1.764
+(db_lock.h> as LOCK_REQ_T)331.114 316.8 R 6.764(.A)-.74 G(LOCK_REQ_T)476.67
+316.8 Q(structure has at least the follo)108 328.8 Q
+(wing \214elds, which must be initialized before calling)-.25 E F1(loc)2.5 E
+(k_vec)-.2 E F0(:).31 E(enum lock)108 345.6 Q(op op;)-.1 E
+(The operation to be performed, which must be set to one of the follo)133 357.6
+Q(wing v)-.25 E(alues:)-.25 E(LOCK_GET)133 374.4 Q .201
+(Get a lock, as de\214ned by the v)158 386.4 R .201(alues of)-.25 F F1(loc)
+2.701 E -.1(ke)-.2 G(r).1 E F0(,).73 E F1(obj)2.701 E F0(and)2.7 E F1(loc)2.7 E
+(k_mode)-.2 E F0 5.2(.U).18 G .2(pon return from)435.99 386.4 R F1(loc)2.7 E
+(k_vec)-.2 E F0(,).31 E .161(if the)158 398.4 R F1(loc)2.661 E(kp)-.2 E F0 .162
+(\214eld is non-NULL, a reference to the acquired lock is stored there.)2.662 F
+.162(\(This reference)5.162 F(is in)158 410.4 Q -.25(va)-.4 G(lidated by an).25
+E 2.5(yc)-.15 G(all to)247.19 410.4 Q F1(loc)2.5 E(k_vec)-.2 E F0(or)2.5 E F1
+(loc)2.5 E(k_put)-.2 E F0(which releases the lock.\))2.5 E(LOCK_PUT)133 427.2 Q
+(The lock referenced by the contents of the)158 439.2 Q F1(loc)2.5 E(kp)-.2 E
+F0(\214eld is released.)2.5 E(LOCK_PUT_ALL)133 456 Q .759
+(All locks held by the)158 468 R F1(loc)3.259 E -.1(ke)-.2 G(r).1 E F0 .759
+(are released.)3.259 F(\(An)5.759 E 3.259(yl)-.15 G .759
+(ocks acquired as a part of the current call to)358.501 468 R F1(loc)158 480 Q
+(k_vec)-.2 E F0(are not considered for this operation\).)2.5 E(LOCK_PUT_OBJ)133
+496.8 Q 1.409(All locks held by the)158 508.8 R F1(loc)3.909 E -.1(ke)-.2 G(r)
+.1 E F0 3.909(,o).73 G 3.909(nt)287.704 508.8 S 1.409(he object)299.393 508.8 R
+F1(obj)3.909 E F0 3.909(,w).48 G 1.41(ith the mode speci\214ed by)367.98 508.8
+R F1(loc)3.91 E(k_mode)-.2 E F0 3.91(,a).18 G(re)532.23 508.8 Q 2.802
+(released. A)158 520.8 R F1(loc)2.802 E(k_mode)-.2 E F0 .301
+(of LOCK_NG indicates that all locks on the object should be released.)2.802 F
+(\(An)158 532.8 Q 3.053(yl)-.15 G .553
+(ocks acquired as a part of the current call to)184.233 532.8 R F1(loc)3.054 E
+(k_vec)-.2 E F0 .554(are not considered for this opera-)3.054 F(tion\).)158
+544.8 Q(const DBT obj;)108 561.6 Q
+(An untyped byte string which speci\214es the object to be lock)133 573.6 Q
+(ed or released.)-.1 E(const lock_mode_t lock_mode;)108 590.4 Q
+(The lock mode, used as an inde)133 602.4 Q 2.5(xi)-.15 G(nto)268.94 602.4 Q F1
+(lt)2.5 E F0 1.1 -.55('s c).68 H(on\215ict array).55 E(.)-.65 E
+(LOCK_T **lockp;)108 619.2 Q 2.5(Ap)133 631.2 S
+(ointer to a pointer to a lock reference.)147.72 631.2 Q(The)108 648 Q F1
+(nlist)2.5 E F0(ar)2.5 E(gument speci\214es the number of elements in the)-.18
+E F1(list)2.5 E F0(array)2.5 E(.)-.65 E 1.229(The function)108 664.8 R F1(loc)
+3.729 E(k_g)-.2 E(et)-.1 E F0 1.228(is a simple interf)3.728 F 1.228
+(ace to the)-.1 F F1(loc)3.728 E(k_vec)-.2 E F0(functionality)3.728 E 3.728(,a)
+-.65 G 1.228(nd is equi)416.31 664.8 R -.25(va)-.25 G 1.228
+(lent to calling the).25 F F1(loc)108 676.8 Q(k_vec)-.2 E F0 .123
+(function with the)2.623 F F1(lt)2.623 E F0(and)2.623 E F1(loc)2.623 E -.1(ke)
+-.2 G(r).1 E F0(ar)2.623 E .123(guments, NULL)-.18 F F1(timeout)2.623 E F0(,)
+.68 E F1(elistp)2.623 E F0(and)2.623 E F1(con\215ict)2.623 E F0(ar)2.623 E .124
+(guments, and a sin-)-.18 F .944(gle element)108 688.8 R F1(list)3.444 E F0
+(array)3.444 E 3.444(,f)-.65 G .944(or which the)203.606 688.8 R F1(op)3.444 E
+F0 .944(\214eld is LOCK_GET)3.444 F 3.444(,a)-.74 G .944(nd the)365.014 688.8 R
+F1(obj)3.444 E F0(,).48 E F1(loc)3.444 E(k_mode)-.2 E F0(and)3.444 E F1(loc)
+3.444 E(kp)-.2 E F0 .943(\214elds are)3.443 F(4.4 Berk)72 732 Q(ele)-.1 E 2.5
+(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(3)535
+732 Q EP
+%%Page: 4 9
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 117.9(DB_LOCK\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 117.9(anual DB_LOCK\(3\))340.17 48 R .509(represented by the ar)108
+84 R .509(guments of the same name.)-.18 F .51(Note that the type of the)5.509
+F/F1 10/Times-Italic@0 SF(obj)3.01 E F0(ar)3.01 E .51(gument to)-.18 F F1(loc)
+3.01 E(k_g)-.2 E(et)-.1 E F0 .51(is dif-)3.01 F .765(ferent from the)108 96 R
+F1(obj)3.265 E F0 .765(element found in the LOCK_REQ_T structure.)3.265 F(The)
+5.765 E F1(loc)3.265 E(k_g)-.2 E(et)-.1 E F0 .765(function returns success)
+3.265 F(and f)108 108 Q(ailure as described for the)-.1 E F1(loc)2.5 E(k_vec)
+-.2 E F0(function.)2.5 E 1.186(The function)108 124.8 R F1(loc)3.686 E(k_put)
+-.2 E F0 1.187(is a simple interf)3.687 F 1.187(ace to the)-.1 F F1(loc)3.687 E
+(k_vec)-.2 E F0(functionality)3.687 E 3.687(,a)-.65 G 1.187(nd is equi)416.515
+124.8 R -.25(va)-.25 G 1.187(lent to calling the).25 F F1(loc)108 136.8 Q
+(k_vec)-.2 E F0 .374(function with a single element)2.874 F F1(list)2.874 E F0
+(array)2.873 E 2.873(,f)-.65 G .373(or which the)314.82 136.8 R F1(op)2.873 E
+F0 .373(\214eld is LOCK_PUT and the)2.873 F F1(loc)2.873 E(kp)-.2 E F0(\214eld)
+2.873 E .631(is represented by the ar)108 148.8 R .631
+(gument of the same name.)-.18 F .632(Note that the type of the)5.632 F F1(loc)
+3.132 E(kp)-.2 E F0(ar)3.132 E .632(gument to)-.18 F F1(loc)3.132 E(k_put)-.2 E
+F0(is)3.132 E(dif)108 160.8 Q .275(ferent from the)-.25 F F1(loc)2.775 E(kp)-.2
+E F0 .274(element found in the LOCK_REQ_T structure.)2.775 F(The)5.274 E F1
+(loc)2.774 E(k_put)-.2 E F0 .274(function returns suc-)2.774 F(cess and f)108
+172.8 Q(ailure as described for the)-.1 E F1(loc)2.5 E(k_vec)-.2 E F0
+(function.)2.5 E .013(The function)108 189.6 R F1(loc)2.513 E(k_close)-.2 E F0
+.013(disassociates the calling process from the lock table)2.513 F F1(lt)2.513
+E F0 2.513(,a).68 G .013(fter releasing all locks held)431.636 189.6 R .228
+(or requested by that process.)108 201.6 R .228(The function)5.228 F F1(loc)
+2.728 E(k_close)-.2 E F0 .228(returns -1 on f)2.728 F .227(ailure, setting)-.1
+F F1(errno)2.727 E F0 2.727(,a).18 G .227(nd 0 on success.)474.329 201.6 R .433
+(The function)108 218.4 R F1(loc)2.933 E(k_unlink)-.2 E F0(destro)2.933 E .433
+(ys the lock table identi\214ed by the directory)-.1 F F1(path)2.933 E F0 2.933
+(,r).28 G(emo)440.636 218.4 Q .433(ving all \214les used to)-.15 F 1.005
+(implement the lock table.)108 230.4 R 1.005(\(The directory)6.005 F F1(path)
+3.505 E F0 1.005(is not remo)3.505 F -.15(ve)-.15 G 3.505(d.\) If).15 F 1.005
+(there are processes which ha)3.505 F 1.305 -.15(ve c)-.2 H(alled).15 E F1(loc)
+108 242.4 Q(k_open)-.2 E F0 .869(without calling)3.369 F F1(loc)3.369 E
+(k_close)-.2 E F0 .869
+(\(i.e., there are processes currently using the lock table\),)3.369 F F1(loc)
+3.37 E(k_unlink)-.2 E F0 .409(will f)108 254.4 R .408
+(ail without further action, unless the force \215ag is set, in which case)-.1
+F F1(loc)2.908 E(k_unlink)-.2 E F0 .408(will attempt to delete)2.908 F .807
+(the lock table \214les re)108 266.4 R -.05(ga)-.15 G .808(rdless of an).05 F
+3.308(yp)-.15 G .808(rocesses still using the lock table.)264.662 266.4 R(An)
+5.808 E 3.308(ya)-.15 G .808(ccesses to a remo)433.208 266.4 R -.15(ve)-.15 G
+3.308(dl).15 G(ock)525.56 266.4 Q .046(table will lik)108 278.4 R .046
+(ely result in une)-.1 F .045(xpected beha)-.15 F(vior)-.2 E 5.045(.T)-.55 G
+.045(he function)304.24 278.4 R F1(loc)2.545 E(k_unlink)-.2 E F0 .045
+(returns -1 on f)2.545 F .045(ailure, setting)-.1 F F1(errno)2.545 E F0(,).18 E
+(and 0 on success.)108 290.4 Q .798(In the case of catastrophic or system f)108
+307.2 R .798(ailure, it is possible to clean up a lock table by remo)-.1 F .799
+(ving all of the)-.15 F .38(\214les in the directory speci\214ed to the)108
+319.2 R F1(loc)2.88 E(k_cr)-.2 E(eate)-.37 E F0 .379
+(function, as lock table \214les are ne)2.88 F -.15(ve)-.25 G 2.879(rc).15 G
+.379(reated in an)461.543 319.2 R 2.879(yd)-.15 G(irec-)521.68 319.2 Q
+(tory other than the one speci\214ed to)108 331.2 Q F1(loc)2.5 E(k_cr)-.2 E
+(eate)-.37 E F0(.).18 E/F2 9/Times-Bold@0 SF(ERR)72 348 Q(ORS)-.27 E F0(The)108
+360 Q F1(loc)4.158 E(k_cr)-.2 E(eate)-.37 E F0 1.658(function may f)4.158 F
+1.658(ail and set)-.1 F F1(errno)4.158 E F0 1.658(for an)4.158 F 4.158(yo)-.15
+G 4.158(ft)353.71 360 S 1.659(he errors speci\214ed for the library routines)
+363.978 360 R F1(mmap)108 372 Q F0(\(2\),).19 E F1(open)2.5 E F0(\(2\) and).24
+E F1(malloc)2.5 E F0(\(3\).).31 E(The)108 388.8 Q F1(loc)4.692 E(k_open)-.2 E
+F0 2.192(function may f)4.692 F 2.192(ail and set)-.1 F F1(errno)4.692 E F0
+2.192(for an)4.692 F 4.692(yo)-.15 G 4.692(ft)353.87 388.8 S 2.191
+(he errors speci\214ed for the library routine)364.672 388.8 R F1(mmap)108
+400.8 Q F0(\(2\) and).19 E F1(open)2.5 E F0(\(2\).).24 E(The)108 417.6 Q F1
+(loc)2.57 E(k_close)-.2 E F0 .07(function may f)2.57 F .07(ail and set)-.1 F F1
+(errno)2.57 E F0 .07(for an)2.57 F 2.57(yo)-.15 G 2.57(ft)333.76 417.6 S .07
+(he errors speci\214ed for the library routine)342.44 417.6 R F1(close)2.57 E
+F0(\(2\)).18 E(and)108 429.6 Q F1(munmap)2.5 E F0(\(2\).).19 E(The)108 446.4 Q
+F1(loc)4.071 E(k_unlink)-.2 E F0 1.571(function may f)4.071 F 1.571
+(ail and set)-.1 F F1(errno)4.071 E F0 1.571(for an)4.071 F 4.071(yo)-.15 G
+4.07(ft)353.22 446.4 S 1.57(he errors speci\214ed for the library function)
+363.4 446.4 R F1(unlink)108 458.4 Q F0(\(2\) or the follo).67 E(wing:)-.25 E
+([EB)108 475.2 Q(USY])-.1 E(The lock table w)133 487.2 Q
+(as in use and the force \215ag w)-.1 E(as not set.)-.1 E F2(SEE ALSO)72 504 Q
+F1(db_btr)108 516 Q(ee)-.37 E F0(\(3\),).18 E F1(db_hash)2.5 E F0(\(3\),).28 E
+F1(db_lo)2.5 E(g)-.1 E F0(\(3\),).22 E F1(db_mpool)2.5 E F0(\(3\),).51 E F1
+(db_open)2.5 E F0(\(3\),).24 E F1(db_r)2.5 E(ecno)-.37 E F0(\(3\),).18 E F1
+(db_txn)2.5 E F0(\(3\)).24 E F2 -.09(BU)72 532.8 S(GS).09 E F0(The)108 544.8 Q
+F1(maxloc)2.656 E(ks)-.2 E F0 .156
+(parameter is a kluge, and should be deleted in f)2.656 F -.2(avo)-.1 G 2.657
+(ro).2 G 2.657(fd)381.055 544.8 S .157(ynamically e)392.042 544.8 R .157
+(xpanding the lock table.)-.15 F(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G
+(istrib)132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(4)535 732 Q EP
+%%Page: 1 10
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.57(DB_LOG\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.57(anual DB_LOG\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72
+84 S(ME).18 E F0(db_log \255 log-manager access method)108 96 Q F1(DESCRIPTION)
+72 112.8 Q F0 .486(The DB library is a f)108 124.8 R .485
+(amily of groups of functions that pro)-.1 F .485
+(vides a modular programming interf)-.15 F .485(ace to trans-)-.1 F .822
+(actions and record-oriented \214le access.)108 136.8 R .822
+(The library includes support for transaction, locking, logging and)5.822 F
+.258(\214le b)108 148.8 R(uf)-.2 E .258(fering functionality)-.25 F 2.758(,a)
+-.65 G 2.758(sw)223.214 148.8 S .258(ell as v)237.082 148.8 R .258(arious inde)
+-.25 F -.15(xe)-.15 G 2.758(da).15 G .258(ccess methods.)331.434 148.8 R(Man)
+5.258 E 2.758(yo)-.15 G 2.758(ft)427.878 148.8 S .258
+(he functional groups \(e.g.)436.746 148.8 R .528(the memory pool functions\) \
+are useful independently of the rest of the DB functions, although some func-)
+108 160.8 R .306(tional groups are e)108 172.8 R .306
+(xplicitly based on other functional groups \(e.g.)-.15 F .306
+(transactions and logging\).)5.306 F -.15(Fo)5.306 G 2.806(rag).15 G(eneral)
+515.57 172.8 Q .245(description of transactions, see)108 184.8 R/F2 10
+/Times-Italic@0 SF(db_txn)2.745 E F0 2.745(\(3\). F).24 F .245
+(or a general description of the access methods, see)-.15 F F2(db_open)2.745 E
+F0(\(3\)).24 E .308(and then the indi)108 196.8 R .308
+(vidual access method manual pages:)-.25 F F2(db_btr)2.807 E(ee)-.37 E F0
+(\(3\),).18 E F2(db_hash)2.807 E F0(\(3\),).28 E F2(db_lo)2.807 E(g)-.1 E F0
+.307(\(3\) and).22 F F2(db_r)2.807 E(ecno)-.37 E F0(\(3\).).18 E -.15(Fo)108
+208.8 S 3.635(rag).15 G 1.135(eneral description of the lock manager)138.45
+208.8 R 3.635(,s)-.4 G(ee)307.32 208.8 Q F2(db_loc)3.635 E(k)-.2 E F0 3.635
+(\(3\). F).67 F 1.135(or a general description of the memory)-.15 F
+(pool manager)108 220.8 Q 2.5(,s)-.4 G(ee)171.2 220.8 Q F2(db_mpool)2.5 E F0
+(\(3\).).51 E
+(This manual page describes speci\214c details of the logging access method.)
+108 237.6 Q .03(These functions pro)108 254.4 R .03
+(vide a general-purpose logging f)-.15 F .03(acility suf)-.1 F .03
+(\214cient for transaction management.)-.25 F .03(Logs can)5.03 F
+(be shared by multiple processes.)108 266.4 Q 3.717(Al)108 283.2 S 1.217
+(og is represented by the directory)121.717 283.2 R(,)-.65 E F2 1.217
+(not the \214le)3.717 F F0 3.717(,n).18 G 1.217(amed by the \214rst ar)323
+283.2 R 1.218(gument to)-.18 F F2(db_open)3.718 E F0 3.718(\(3\). The).24 F
+(\214rst)3.718 E(ar)108 295.2 Q .26
+(gument must be non-NULL, and the directory must already e)-.18 F(xist)-.15 E
+F2(db_open)2.76 E F0 .26(is called.)2.76 F .26(In that directory)5.26 F 2.76
+(,t)-.65 G(he)530.56 295.2 Q 3.448
+(log is stored in one or more \214les named in the format `)108 307.2 R
+(`log.YYYY)-.74 E(.MM.DD.HH.MM.SS')-1.29 E 3.448(', where)-.74 F -.74(``)108
+319.2 S(YYYY).74 E(.MM.DD.HH.SS')-1.29 E 2.507('i)-.74 G 2.507(st)220.497 319.2
+S .007(he approximate creation time of the log \214le, and is guaranteed to be\
+ unique in)229.674 319.2 R(the directory)108 331.2 Q(.)-.65 E .465
+(The group of the created \214les is based on the system and directory def)108
+348 R .466(aults, and is not further speci\214ed by)-.1 F .073
+(the log access method.)108 360 R .072(All \214les are created with the)5.073 F
+F2(mode)2.572 E F0 .072(speci\214ed to)2.572 F F2(db_open)2.572 E F0 2.572(,\()
+.24 G .072(as described in)435.584 360 R F2 -.15(ch)2.572 G(mod).15 E F0
+(\(2\)\)).77 E(and modi\214ed by the process' umask v)108 372 Q(alue \(see)-.25
+E F2(umask)2.5 E F0(\(2\)\).).67 E(The)108 388.8 Q F2<8d61>2.5 E(gs)-.1 E F0
+(ar)2.5 E(gument to)-.18 E F2(db_open)2.5 E F0(must be 0 for the)2.5 E F2
+(db_lo)2.5 E(g)-.1 E F0(access method.)2.5 E F1 -.495(AC)72 405.6 S
+(CESS METHOD SPECIFIC INFORMA).495 E(TION)-.855 E F0 .571
+(The log access method speci\214c data structure pro)108 417.6 R .571(vided to)
+-.15 F F2(db_open)3.071 E F0 .572(is typedef)3.071 F 1.572 -.5('d a).55 H .572
+(nd named LOGINFO.).5 F(A)5.572 E(LOGINFO structure has at least the follo)108
+429.6 Q(wing \214elds, which may be initialized before calling)-.25 E F2
+(db_open)2.5 E F0(:).24 E(of)108 446.4 Q(f_t max_\214le_size;)-.25 E 1.585
+(The maximum size of a single \214le in the log.)133 458.4 R 1.584
+(If not speci\214ed, the maximum size def)6.584 F 1.584(aults to an)-.1 F
+(implementation-speci\214c v)133 470.4 Q(alue.)-.25 E(int lorder;)108 487.2 Q
+.65(The byte order for inte)133 499.2 R .65
+(gers in the stored database metadata.)-.15 F .65
+(The number should represent the order)5.65 F .749(as an inte)133 511.2 R .749
+(ger; for e)-.15 F .749(xample, big endian order w)-.15 F .749
+(ould be the number 4,321.)-.1 F(If)5.749 E F2(lor)3.249 E(der)-.37 E F0 .749
+(is 0 \(no order is)3.249 F(speci\214ed\) the current host order is used.)133
+523.2 Q 1.284(If the log already e)108 540 R 1.284(xists, the v)-.15 F 1.285(a\
+lues speci\214ed for the parameters max_\214le_size and lorder are ignored in)
+-.25 F -.1(fa)108 552 S -.2(vo)-.1 G 2.5(ro).2 G 2.5(ft)136.1 552 S(he v)144.71
+552 Q(alues used when the log w)-.25 E(as created.)-.1 E F1(DB OPERA)72 568.8 Q
+(TIONS)-.855 E F0 .687(The data part of the k)108 580.8 R -.15(ey)-.1 G .686(/\
+data pair used by the log access method is the same as for other access method\
+s.).15 F .837(The k)108 592.8 R 1.137 -.15(ey i)-.1 H 3.337(sd).15 G(if)159.421
+592.8 Q 3.337(ferent. Each)-.25 F .837(log record is identi\214ed by a log seq\
+uence number \(LSN\), which is stored in a)3.337 F(DBT)108 604.8 Q 2.702(,a)
+-.74 G .202(nd which is used as the)136.902 604.8 R F2 -.1(ke)2.702 G(y)-.2 E
+F0 .202(for all log functions that tak)2.702 F(e)-.1 E F2 -.1(ke)2.701 G(y)-.2
+E F0(ar)2.701 E 2.701(guments. Applications)-.18 F .201(cannot create)2.701 F
+(LSN')108 616.8 Q .539(s, and all LSN')-.55 F 3.039(sp)-.55 G(ro)203.216 616.8
+Q .539(vided to functions as ar)-.15 F .539(guments must \214rst be retrie)-.18
+F -.15(ve)-.25 G 3.04(du).15 G .54(sing the)440.37 616.8 R F2(put)3.04 E F0(or)
+3.04 E F2(seq)3.04 E F0(func-)3.04 E 2.783(tions. T)108 628.8 R 2.783(op)-.8 G
+(ro)153.326 628.8 Q .283(vide a distinguished v)-.15 F .282
+(alue for applications, it is guaranteed that no v)-.25 F .282(alid LSN will e)
+-.25 F -.15(ve)-.25 G 2.782(rh).15 G -2.25 -.2(av e)519.248 628.8 T(a)2.982 E
+(size of 0.)108 640.8 Q(Applications can compare LSN')108 657.6 Q 2.5(su)-.55 G
+(sing the)247.98 657.6 Q F2(lo)2.5 E(g_lsn_compar)-.1 E(e)-.37 E F0
+(function \(see belo)2.5 E(w\).)-.25 E .429(Applications can associate LSN')108
+674.4 R 2.929(sw)-.55 G .429(ith speci\214c log \214les.)253.586 674.4 R .429
+(The function)5.429 F F2(lo)2.929 E(g_lsn_\214le)-.1 E F0 .43(\(see belo)2.93 F
+.43(w\), returns the)-.25 F .214
+(name of the log \214le containing the record with a speci\214ed LSN.)108 686.4
+R .214(\(The mapping of LSN to \214le is needed for)5.214 F(4.4 Berk)72 732 Q
+(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(3, 1995)
+2.5 E(1)535 732 Q EP
+%%Page: 2 11
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.57(DB_LOG\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.57(anual DB_LOG\(3\))340.17 48 R .397(database administration.)
+108 84 R -.15(Fo)5.397 G 2.897(re).15 G .398
+(xample, a transaction manager typically records the earliest LSN needed for)
+231.931 84 R .519(restart, and the database administrator may w)108 96 R .519
+(ant to archi)-.1 F .819 -.15(ve l)-.25 H .519(og \214les to tape when the).15
+F 3.018(yc)-.15 G .518(ontain only LSN')465.624 96 R(s)-.55 E
+(before the earliest one needed for restart.\))108 108 Q
+(Applications can truncate the log \214le up to a speci\214c LSN using the)108
+124.8 Q/F1 10/Times-Italic@0 SF(lo)2.5 E(g_trunc)-.1 E F0(function \(see belo)
+2.5 E(w\).)-.25 E .221(The functions returned by)108 141.6 R F1(db_open)2.721 E
+F0 .221(for the log access method are as described in)2.721 F F1(db_open)2.721
+E F0 2.722(,w).24 G .222(ith the follo)482.586 141.6 R(w-)-.25 E(ing e)108
+153.6 Q(xceptions and additions:)-.15 E 5.28(type The)108 170.4 R
+(type is DB_LOG.)2.5 E 10.28(del The)108 187.2 R F1(del)3.505 E F0 1.005
+(function al)3.505 F -.1(wa)-.1 G 1.005
+(ys returns an error for the log-manager access method, setting).1 F F1(errno)
+3.504 E F0 1.004(to EIN-)3.504 F -1.35(VA)133 199.2 S(L.)1.35 E
+(int \(*log_\215ush\)\(const DB *db, const DBT *lsn\);)108 216 Q(The)133 228 Q
+F1(lo)2.866 E(g_\215ush)-.1 E F0 .367
+(function \215ushes the log up to and including the log record)2.866 F F1(lsn)
+2.867 E F0 5.367(.T).24 G .367(he function)454.926 228 R F1(lo)2.867 E
+(g_\215ush)-.1 E F0(returns -1 on f)133 240 Q(ailure, setting)-.1 E F1(errno)
+2.5 E F0 2.5(,a).18 G(nd 0 on success.)278.61 240 Q
+(int \(*log_lsn_compare\)\(const DB *,)108 256.8 Q .255
+(const DBT *lsn1, const DBT *lsn2\); A pointer to a function which is pro)183
+268.8 R .255(vided to permit)-.15 F .312(applications to compare LSN')133 280.8
+R 2.812(s. The)-.55 F F1(lo)2.812 E(g_lsn_compar)-.1 E(e)-.37 E F0 .312
+(function returns an inte)2.812 F .313(ger less than, equal to,)-.15 F .058
+(or greater than zero if the \214rst LSN is considered to be respecti)133 292.8
+R -.15(ve)-.25 G .058(ly less than, equal to, or greater than).15 F
+(the second LSN.)133 304.8 Q(int \(*log_lsn_\214le\)\(const DB *db,)108 321.6 Q
+(const DBT *lsn, char *name\);)183 333.6 Q(The)133 345.6 Q F1(lo)3.21 E
+(g_lsn_\214le)-.1 E F0 .71
+(function stores a pointer to the name of the \214le containing)3.21 F F1(lsn)
+3.211 E F0 .711(in the address refer)3.211 F(-)-.2 E .293(enced by)133 357.6 R
+F1(name)2.793 E(.)-.15 E F0 .293(This pointer is to an internal static object,\
+ and subsequent calls to the same function)5.293 F
+(will modify the same object.)133 369.6 Q(The function)133 386.4 Q F1(lo)2.5 E
+(g_lsn_\214le)-.1 E F0(returns -1 on f)2.5 E(ailure, setting)-.1 E F1(errno)2.5
+E F0 2.5(,a).18 G(nd 0 on success.)381.56 386.4 Q
+(int \(*log_unlink\)\(const char *path, int force\);)108 403.2 Q(The)133 415.2
+Q F1(lo)3.275 E(g_unlink)-.1 E F0 .775(function destro)3.275 F .775
+(ys the log represented by)-.1 F F1(path)3.275 E F0 5.775(.I).28 G 3.275(ft)
+394.745 415.2 S(he)404.13 415.2 Q F1(for)3.275 E(ce)-.37 E F0 .776
+(parameter is not set to 1)3.275 F .725
+(and there are other processes using the log, then)133 427.2 R F1(lo)3.224 E
+(g_unlink)-.1 E F0 .724(will return -1, setting)3.224 F F1(errno)3.224 E F0
+.724(to EB)3.224 F(USY)-.1 E(.)-1.29 E(If)133 439.2 Q F1(for)2.831 E .331
+(ce is not set or ther)-.37 F 2.831(ea)-.37 G 1.071 -.37(re n)244.287 439.2 T
+2.831(op).37 G -.45(ro)272.909 439.2 S .331(cesses using the lo).45 F .532 -.1
+(g, t)-.1 H .332(hen all \214les).1 F F0 .332(used by the log are destro)2.832
+F(yed.)-.1 E F1(lo)133 451.2 Q(g_unlink)-.1 E F0(will return -1 on f)2.5 E
+(ailure, setting)-.1 E F1(errno)2.5 E F0 2.5(,a).18 G(nd 0 on success.)337.96
+451.2 Q(int \(*log_trunc\)\(const DB *db, const DBT *lsn\);)108 468 Q(The)133
+480 Q F1(lo)2.601 E(g_trunc)-.1 E F0 .101
+(function truncates the log up to an LSN which is less than)2.601 F F1(lsn)2.6
+E F0 5.1(.T).24 G .1(he function)453.24 480 R F1(lo)2.6 E(g_trunc)-.1 E F0
+(returns -1 on f)133 492 Q(ailure, setting)-.1 E F1(errno)2.5 E F0 2.5(,a).18 G
+(nd 0 on success.)278.61 492 Q 9.72(put A)108 508.8 R .339
+(log record containing)2.839 F F1(data)2.839 E F0 .339(is appended to the log.)
+2.839 F(Unlik)5.339 E 2.84(et)-.1 G(he)382.44 508.8 Q F1(put)2.84 E F0 .34
+(functions for other access meth-)2.84 F .789(ods, the k)133 520.8 R 1.089 -.15
+(ey p)-.1 H .788(arameter is not initialized by the application, instead, the \
+LSN assigned to the data is).15 F(returned in the)133 532.8 Q F1 -.1(ke)2.5 G
+(y)-.2 E F0(parameter)2.5 E(.)-.55 E 1.157(The caller is responsible for pro)
+133 549.6 R 1.157(viding an)-.15 F 3.657(yn)-.15 G 1.157(ecessary structure to)
+318.267 549.6 R F1 1.157(data .)3.657 F F0(\(F)6.157 E 1.157(or e)-.15 F 1.157
+(xample, in a write-)-.15 F .267
+(ahead logging protocol, the application must understand what part of)133 561.6
+R F1(data)2.767 E F0 .266(is an operation code, what)2.766 F .622
+(part is redo information, and what part is undo information.)133 573.6 R .622
+(In addition, most transaction managers)5.622 F .985(will store in)133 585.6 R
+F1(data)3.485 E F0 .985(the LSN of the pre)3.485 F .984
+(vious log record for the same transaction, to support chaining)-.25 F
+(back through the transaction')133 597.6 Q 2.5(sl)-.55 G
+(og records during undo.\))258.54 597.6 Q(The parameter)133 614.4 Q F1<8d61>2.5
+E(g)-.1 E F0(must be set to 0 or e)2.5 E(xactly one of the follo)-.15 E(wing v)
+-.25 E(alues:)-.25 E(R_CHECKPOINT)133 631.2 Q .5(Specify the k)158 643.2 R -.15
+(ey)-.1 G .5(/data pair of the current call as the one to be returned when the)
+.15 F F1(seq)3 E F0 .5(function is)3 F(ne)158 655.2 Q
+(xt called with the R_CHECKPOINT \215ag.)-.15 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5
+(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(3, 1995)2.5 E(2)535
+732 Q EP
+%%Page: 3 12
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.57(DB_LOG\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.57(anual DB_LOG\(3\))340.17 48 R(R_FLUSH)133 84 Q
+(Flush immediately \(ignoring an)158 96 Q 2.5(yp)-.15 G
+(ossibility for group commit\).)296.74 96 Q 9.17(seq The)108 112.8 R/F1 10
+/Times-Italic@0 SF(seq)2.5 E F0(function tak)2.5 E(es the follo)-.1 E
+(wing additional \215ag:)-.25 E(R_CHECKPOINT)133 129.6 Q .184(The last k)158
+141.6 R -.15(ey)-.1 G .184(/data pair stored by the).15 F F1(put)2.684 E F0
+.183(function \(using the R_CHECKPOINT \215ag\) is returned,)2.684 F .216
+(and the cursor is set or initialized to reference it.)158 153.6 R .216(The e)
+5.216 F .216(xpected use of this \215ag is during restart)-.15 F .801
+(and to determine what part of the log must be a)158 165.6 R -.25(va)-.2 G .801
+(ilable for restart.).25 F .801(Therefore, the log record)5.801 F(retrie)158
+177.6 Q -.15(ve)-.25 G 3.352(dw).15 G .853
+(ith R_CHECKPOINT should contain all the information that the transaction man-)
+203.712 177.6 R(ager will need for this purpose.)158 189.6 Q 4.17(sync The)108
+206.4 R F1(sync)3.135 E F0 .635(function al)3.135 F -.1(wa)-.1 G .635
+(ys returns an error for the log-manager access method, setting).1 F F1(errno)
+3.134 E F0 .634(to EIN-)3.134 F -1.35(VA)133 218.4 S(L.)1.35 E/F2 9
+/Times-Bold@0 SF(SEE ALSO)72 235.2 Q F1(db_btr)108 247.2 Q(ee)-.37 E F0(\(3\),)
+.18 E F1(db_hash)2.5 E F0(\(3\),).28 E F1(db_loc)2.5 E(k)-.2 E F0(\(3\),).67 E
+F1(db_mpool)2.5 E F0(\(3\),).51 E F1(db_open)2.5 E F0(\(3\),).24 E F1(db_r)2.5
+E(ecno)-.37 E F0(\(3\),).18 E F1(db_txn)2.5 E F0(\(3\)).24 E(4.4 Berk)72 732 Q
+(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(3, 1995)
+2.5 E(3)535 732 Q EP
+%%Page: 1 13
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 110.12(DB_MPOOL\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 110.12(anual DB_MPOOL\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)
+72 84 S(ME).18 E F0(db_mpool \255 general purpose shared memory b)108 96 Q(uf)
+-.2 E(fer pool)-.25 E F1(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF
+(#include <db)108 124.8 Q(.h>)-.4 E(#include <mpool.h>)108 136.8 Q(int)108
+160.8 Q(mpool_cr)108 172.8 Q
+(eate\(char *path, mode_t mode, size_t cachesize, u_long \215ags\);)-.18 E
+(MPOOL *)108 196.8 Q(mpool_open\(char *path\);)108 208.8 Q(int)108 232.8 Q
+(mpool_close\(MPOOL *mp\);)108 244.8 Q(MPOOLFILE *)108 268.8 Q(mpool_f)108
+280.8 Q(open\(MPOOL *mp, char *path, size_t pagesize, v)-.25 E(oid *pgcookie,)
+-.1 E(int \(*pgin\)\(MPOOLFILE *mpf)158 292.8 Q(,)-.15 E(pgno_t pgno, v)188
+304.8 Q(oid *pgaddr)-.1 E 2.5(,v)-.92 G(oid *pgcookie\),)311.91 304.8 Q
+(int \(*pgout\)\(MPOOLFILE *mpf)158 316.8 Q(,)-.15 E(pgno_t pgno, v)188 328.8 Q
+(oid *pgaddr)-.1 E 2.5(,v)-.92 G(oid *pgcookie\);)311.91 328.8 Q(int)108 352.8
+Q(mpool_fclose\(MPOOLFILE *mpf\);)108 364.8 Q -.1(vo)108 388.8 S(id *).1 E
+(mpool_get\(MPOOLFILE *mpf)108 400.8 Q 2.5(,p)-.15 G(gno_t *pgnoaddr)252.02
+400.8 Q 2.5(,u)-.92 G(_long \215ags,)334.73 400.8 Q
+(int \(*callback\)\(MPOOLFILE *mpf)158 412.8 Q 2.5(,p)-.15 G(gno_t pgno\)\);)
+318.97 412.8 Q(int)108 436.8 Q(mpool_put\(MPOOLFILE *mpf)108 448.8 Q 2.5(,v)
+-.15 G(oid *pgaddr)253.04 448.8 Q 2.5(,u)-.92 G(_long \215ags\);)314.64 448.8 Q
+(int)108 472.8 Q(mpool_sync\(MPOOLFILE *mpf\);)108 484.8 Q(int)108 508.8 Q
+(mpool_unlink\(const char *path, int f)108 520.8 Q(or)-.25 E(ce\);)-.18 E -.1
+(vo)108 544.8 S(id).1 E(mpool_stat\(MPOOL *mp, FILE *fp\);)108 556.8 Q F1
+(DESCRIPTION)72 573.6 Q F0 .485(The DB library is a f)108 585.6 R .485
+(amily of groups of functions that pro)-.1 F .486
+(vides a modular programming interf)-.15 F .486(ace to trans-)-.1 F .823
+(actions and record-oriented \214le access.)108 597.6 R .822
+(The library includes support for transaction, locking, logging and)5.822 F
+.258(\214le b)108 609.6 R(uf)-.2 E .258(fering functionality)-.25 F 2.758(,a)
+-.65 G 2.758(sw)223.214 609.6 S .258(ell as v)237.082 609.6 R .258(arious inde)
+-.25 F -.15(xe)-.15 G 2.758(da).15 G .258(ccess methods.)331.434 609.6 R(Man)
+5.258 E 2.758(yo)-.15 G 2.758(ft)427.878 609.6 S .258
+(he functional groups \(e.g.)436.746 609.6 R .528(the memory pool functions\) \
+are useful independently of the rest of the DB functions, although some func-)
+108 621.6 R .306(tional groups are e)108 633.6 R .306
+(xplicitly based on other functional groups \(e.g.)-.15 F .306
+(transactions and logging\).)5.306 F -.15(Fo)5.306 G 2.806(rag).15 G(eneral)
+515.57 633.6 Q .245(description of transactions, see)108 645.6 R/F3 10
+/Times-Italic@0 SF(db_txn)2.745 E F0 2.745(\(3\). F).24 F .245
+(or a general description of the access methods, see)-.15 F F3(db_open)2.745 E
+F0(\(3\)).24 E .307(and then the indi)108 657.6 R .307
+(vidual access method manual pages:)-.25 F F3(db_btr)2.808 E(ee)-.37 E F0
+(\(3\),).18 E F3(db_hash)2.808 E F0(\(3\),).28 E F3(db_lo)2.808 E(g)-.1 E F0
+.308(\(3\) and).22 F F3(db_r)2.808 E(ecno)-.37 E F0(\(3\).).18 E -.15(Fo)108
+669.6 S 3.635(rag).15 G 1.135(eneral description of the lock manager)138.45
+669.6 R 3.635(,s)-.4 G(ee)307.32 669.6 Q F3(db_loc)3.635 E(k)-.2 E F0 3.635
+(\(3\). F).67 F 1.135(or a general description of the memory)-.15 F
+(pool manager)108 681.6 Q 2.5(,s)-.4 G(ee)171.2 681.6 Q F3(db_mpool)2.5 E F0
+(\(3\).).51 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q
+99.315(ution August)-.2 F(1, 1995)2.5 E(1)535 732 Q EP
+%%Page: 2 14
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 110.12(DB_MPOOL\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 110.12(anual DB_MPOOL\(3\))340.17 48 R
+(This manual page describes speci\214c details of the memory pool interf)108 84
+Q(ace.)-.1 E(The)108 100.8 Q/F1 10/Times-Italic@0 SF(db_mpool)3.682 E F0 1.182
+(function is the library interf)3.682 F 1.183(ace intended to pro)-.1 F 1.183
+(vide general-purpose, page-oriented b)-.15 F(uf)-.2 E(fer)-.25 E .16
+(management of one or more \214les.)108 112.8 R .16(While designed to w)5.16 F
+.16(ork with the other DB functions, these functions are)-.1 F .604
+(also useful for more general purposes.)108 124.8 R .604
+(The memory pools \(MPOOL)5.604 F -.55('s)-.92 G 3.104(\)a).55 G .605
+(re referred to in this document as)404.18 124.8 R .985(simply `)108 136.8 R
+(`pools')-.74 E 3.485('. Pools)-.74 F .985(may be shared between processes.)
+3.485 F .985(Pools are usually \214lled by pages from one or)5.985 F .673
+(more \214les \(MPOOLFILE')108 148.8 R 3.173(s\). P)-.55 F .674
+(ages in the pool are replaced in LR)-.15 F 3.174(U\()-.4 G .674
+(least-recently-used\) order)392.318 148.8 R 3.174(,w)-.4 G .674(ith each)
+507.946 148.8 R(ne)108 160.8 Q 4.243(wp)-.25 G 1.743
+(age replacing the page which has been unused the longest.)133.653 160.8 R -.15
+(Pa)6.742 G 1.742(ges retrie).15 F -.15(ve)-.25 G 4.242(df).15 G 1.742
+(rom the pool using)459.494 160.8 R F1(mpool_g)108 172.8 Q(et)-.1 E F0 1.255
+(are `)3.755 F(`pinned')-.74 E 3.755('i)-.74 G 3.755(nm)215.435 172.8 S(emory)
+231.97 172.8 Q 3.755(,b)-.65 G 3.755(yd)268.125 172.8 S(ef)281.88 172.8 Q 1.256
+(ault, until the)-.1 F 3.756(ya)-.15 G 1.256(re returned to the pool using the)
+358.168 172.8 R F1(mpool_put)3.756 E F0(function.)108 184.8 Q .934
+(The function)108 201.6 R F1(mpool_cr)3.434 E(eate)-.37 E F0 .934
+(creates and initializes the memory pool identi\214ed by the)3.434 F F1(path)
+3.433 E F0(directory)3.433 E 5.933(.T)-.65 G(his)528.33 201.6 Q .931
+(directory must already e)108 213.6 R .931(xist when)-.15 F F1(mpool_cr)3.431 E
+(eate)-.37 E F0 .931(is called.)3.431 F .932
+(If the memory pool identi\214ed by)5.931 F F1(path)3.432 E F0(already)3.432 E
+-.15(ex)108 225.6 S .045(ists, then).15 F F1(mpool_cr)2.545 E(eate)-.37 E F0
+.045(returns success without further action.)2.545 F .045
+(The \214les associated with the memory pool)5.045 F .87
+(are created in the directory speci\214ed by)108 237.6 R F1(path)3.37 E F0 5.87
+(.\().28 G .87(The group of the created \214les is based on the system and)
+304.08 237.6 R .258(directory def)108 249.6 R .258
+(aults, and is not further speci\214ed by)-.1 F F1(mpool_cr)2.758 E(eate)-.37 E
+F0 2.758(.\) All).18 F .258(\214les created by)2.758 F F1(mpool_cr)2.758 E
+(eate)-.37 E F0 .258(are cre-)2.758 F .048(ated with mode)108 261.6 R F1(mode)
+2.548 E F0 .049(\(as described in)2.548 F F1 -.15(ch)2.549 G(mod).15 E F0 .049
+(\(2\)\) and modi\214ed by the process' umask v).77 F .049(alue \(see)-.25 F F1
+(umask)2.549 E F0(\(2\)\).).67 E(The)108 278.4 Q F1(cac)2.544 E(hesize)-.15 E
+F0(ar)2.544 E .044(gument speci\214es the size of the pool in bytes, and shoul\
+d be the size of the normal w)-.18 F(orking)-.1 E .509(set of the application \
+with some small amount of additional memory for unusual situations.)108 290.4 R
+.509(If the number)5.509 F .362(of bytes currently `)108 302.4 R(`pinned')-.74
+E 2.862('i)-.74 G 2.862(nm)226.828 302.4 S .362(emory e)242.47 302.4 R(xceeds)
+-.15 E F1(cac)2.861 E(hesize)-.15 E F0 2.861(,t).18 G(he)351.734 302.4 Q F1
+(db_mpool)2.861 E F0 .361(functions will attempt to allocate)2.861 F
+(more memory and do not necessarily f)108 314.4 Q(ail, although the)-.1 E 2.5
+(ym)-.15 G(ay suf)341.61 314.4 Q(fer performance de)-.25 E(gradation.)-.15 E
+(The)108 331.2 Q F1<8d61>2.5 E(gs)-.1 E F0(ar)2.5 E(gument is set by)-.18 E F1
+(or)2.5 E F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)272.73 331.2 S(he follo)281.34
+331.2 Q(wing v)-.25 E(alues:)-.25 E(MPOOL_PRIV)108 348 Q -1.11(AT)-1.35 G(E)
+1.11 E(The pool is not shared by other processes or threads, so no locking of \
+pool resources is required.)144 360 Q .115(The function)108 376.8 R F1
+(mpool_open)2.615 E F0 .115
+(returns a pointer to the memory pool identi\214ed by)2.615 F F1(path)2.615 E
+F0 2.615(,w).28 G .115(hich must ha)447.525 376.8 R .415 -.15(ve a)-.2 H
+(lready).15 E .036(been created by a call to)108 388.8 R F1(mpool_cr)2.536 E
+(eate)-.37 E F0 5.036(.T).18 G .036(he process must ha)276.074 388.8 R .336
+-.15(ve p)-.2 H .036(ermission to read and write \214les with o).15 F(wn-)-.25
+E 1.157(ers, groups and permissions as described for)108 400.8 R F1(mpool_cr)
+3.657 E(eate)-.37 E F0 6.157(.T).18 G(he)365.075 400.8 Q F1(mpool_open)3.657 E
+F0 1.157(function returns NULL on)3.657 F -.1(fa)108 412.8 S(ilure, setting).1
+E F1(errno)2.5 E F0(.).18 E(The)108 429.6 Q F1(mpool_close)6.383 E F0 3.883
+(function closes the pool indicated by the MPOOL pointer)6.383 F F1(mp)6.383 E
+F0 6.383(,a).19 G 6.382(sr)480.026 429.6 S 3.882(eturned by)493.628 429.6 R F1
+(mpool_open)108 441.6 Q F0 5.047(.T).24 G .047(his function does)171.337 441.6
+R/F2 10/Times-Bold@0 SF(not)2.547 E F0 .047(imply a call to)2.547 F F1
+(mpool_sync)2.547 E F0 .047(\(or to)2.547 F F1(mpool_fclose)2.547 E F0 2.547
+(\)i).18 G .047(.e. no pages are writ-)455.951 441.6 R .404
+(ten to the source \214le as as a result of calling)108 453.6 R F1(mpool_close)
+2.904 E F0 5.404(.T).18 G .404(he function)354.658 453.6 R F1(mpool_close)2.904
+E F0 .403(returns -1 on f)2.904 F(ailure,)-.1 E(setting)108 465.6 Q F1(errno)
+2.5 E F0 2.5(,a).18 G(nd 0 on success.)169.01 465.6 Q .827(The function)108
+482.4 R F1(mpool_fopen)3.327 E F0 .827(opens a \214le for b)3.327 F(uf)-.2 E
+.828(fering in the pool speci\214ed by the MPOOL ar)-.25 F 3.328(gument. The)
+-.18 F F1(path)108 494.4 Q F0(ar)2.85 E .349
+(gument is the name of the \214le to be opened.)-.18 F(The)5.349 E F1(pa)2.849
+E -.1(ge)-.1 G(size).1 E F0(ar)2.849 E .349
+(gument is the size, in bytes, of the unit)-.18 F .738(of transfer between the\
+ application and the pool, although not necessarily the unit of transfer betwe\
+en the)108 506.4 R .12(pool and the source \214le.)108 518.4 R .12
+(Applications not kno)5.12 F .12
+(wing the page size of the source \214le should retrie)-.25 F .42 -.15(ve t)
+-.25 H .12(he meta-).15 F .234(data from the \214le using a page size that is \
+correct for the metadata, then close and reopen the \214le, or)108 530.4 R
+2.735(,o)-.4 G(ther)521.32 530.4 Q(-)-.2 E
+(wise determine the page size before calling)108 542.4 Q F1(mpool_fopen)2.5 E
+F0(.).24 E .416(If the)108 559.2 R F1(pgin)2.916 E F0 .416(function is speci\
+\214ed, it is called each time a page is read into the memory pool from the so\
+urce)2.916 F 2.835(\214le. If)108 571.2 R(the)2.835 E F1(pgout)2.835 E F0 .336
+(function is speci\214ed, it is called each time a page is written to the sour\
+ce \214le.)2.835 F .336(Both func-)5.336 F .834
+(tions are called with the MPOOLFILE pointer returned from)108 583.2 R F1
+(mpool_fopen)3.333 E F0 3.333(,t).24 G .833(he page number)421.815 583.2 R
+3.333(,ap)-.4 G .833(ointer to)505.557 583.2 R .014
+(the page being read or written, and the ar)108 595.2 R(gument)-.18 E F1
+(pgcookie)2.515 E F0 5.015(.I).18 G 2.515(fe)351.695 595.2 S .015
+(ither function f)361.98 595.2 R .015(ails, it should return non-zero)-.1 F
+(and set)108 607.2 Q F1(errno)2.5 E F0 2.5(,i).18 G 2.5(nw)168.73 607.2 S
+(hich case the)183.45 607.2 Q F1(db_mpool)2.5 E F0
+(function calling it will also f)2.5 E(ail, lea)-.1 E(ving)-.2 E F1(errno)2.5 E
+F0(intact.)2.5 E(The)108 624 Q F1(mpool_fclose)2.705 E F0 .204
+(function closes the source \214le indicated by the MPOOLFILE pointer)2.705 F
+F1(mpf)2.704 E F0 5.204(.T)1.96 G .204(his function)492.296 624 R(does)108 636
+Q F2(not)3.615 E F0 1.115(imply a call to)3.615 F F1(mpool_sync)3.615 E F0
+3.615(,i).31 G 1.115
+(.e. no pages are written to the source \214le as as a result of calling)
+268.885 636 R F1(mpool_fclose)108 648 Q F0 5(.T).18 G(he function)175.12 648 Q
+F1(mpool_fclose)2.5 E F0(returns -1 on f)2.5 E(ailure, setting)-.1 E F1(errno)
+2.5 E F0 2.5(,a).18 G(nd 0 on success.)424.33 648 Q .019(The function)108 664.8
+R F1(mpool_g)2.519 E(et)-.1 E F0 .019
+(returns a pointer to the page with the page number speci\214ed by)2.519 F F1
+(pgnoaddr)2.518 E F0 2.518(,f).73 G .018(rom the)509.152 664.8 R .986
+(source \214le speci\214ed by the MPOOLFILE pointer)108 676.8 R F1(mpf)3.486 E
+F0 5.986(.I)1.96 G 3.486(ft)342.268 676.8 S .987(he page does not e)351.864
+676.8 R .987(xist or cannot be retrie)-.15 F -.15(ve)-.25 G(d,).15 E F1
+(mpool_g)108 688.8 Q(et)-.1 E F0(returns NULL and sets errno.)2.5 E(4.4 Berk)72
+732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F
+(1, 1995)2.5 E(2)535 732 Q EP
+%%Page: 3 15
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 110.12(DB_MPOOL\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 110.12(anual DB_MPOOL\(3\))340.17 48 R(The)108 84 Q/F1 10
+/Times-Italic@0 SF<8d61>2.5 E(gs)-.1 E F0(ar)2.5 E(gument is set by)-.18 E F1
+(or)2.5 E F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)272.73 84 S(he follo)281.34 84
+Q(wing v)-.25 E(alues:)-.25 E(MPOOL_CALLB)108 100.8 Q -.4(AC)-.35 G(K).4 E 1.04
+(After the page number has been determined, b)133 112.8 R 1.04(ut before an)-.2
+F 3.54(yo)-.15 G 1.04(ther process or thread can access the)388.26 112.8 R .471
+(page, the function speci\214ed by the)133 124.8 R F1(callbac)2.971 E(k)-.2 E
+F0(ar)2.971 E .471(gument is called.)-.18 F .471(If the function f)5.471 F .472
+(ails, it should return)-.1 F 1.11(non-zero and set)133 136.8 R F1(errno)3.61 E
+F0 3.61(,i).18 G 3.61(nw)236.21 136.8 S 1.11(hich case)252.04 136.8 R F1
+(mpool_g)3.61 E(et)-.1 E F0 1.11(will also f)3.61 F 1.11(ail, lea)-.1 F(ving)
+-.2 E F1(errno)3.61 E F0 3.61(intact. The)3.61 F F1(callbac)3.61 E(k)-.2 E F0
+1.012(function is called with the MPOOLFILE pointer returned from)133 148.8 R
+F1(mpool_fopen)3.512 E F0 1.013(and the page number)3.513 F(.)-.55 E .228
+(This functionality is commonly used when page locking is required, b)133 160.8
+R .227(ut the page number of the page)-.2 F(being retrie)133 172.8 Q -.15(ve)
+-.25 G 2.5(di).15 G 2.5(sn)198.14 172.8 S(ot kno)209.53 172.8 Q(wn.)-.25 E
+(MPOOL_CREA)108 189.6 Q(TE)-1.11 E(If the speci\214ed page does not e)133 201.6
+Q(xist, create it.)-.15 E(MPOOL_LAST)108 218.4 Q 2.105
+(Return the last page of the source \214le and cop)133 230.4 R 4.605(yi)-.1 G
+2.106(ts page number to the location referenced by)347.25 230.4 R F1(pgnoaddr)
+133 242.4 Q F0(.).73 E(MPOOL_NEW)108 259.2 Q(Create a ne)133 271.2 Q 2.5(wp)
+-.25 G(age in the \214le and cop)192.45 271.2 Q 2.5(yi)-.1 G
+(ts page number to the location referenced by)290.67 271.2 Q F1(pgnoaddr)2.5 E
+F0(.).73 E(MPOOL_NOPIN)108 288 Q(Don')133 300 Q 2.918(tp)-.18 G .418
+(in the page into memory)164.068 300 R 5.418(.\()-.65 G .417
+(This \215ag is intended for deb)274.108 300 R .417(ugging purposes, when it')
+-.2 F 2.917(so)-.55 G .417(ften use-)504.873 300 R .972(ful to e)133 312 R .972
+(xamine pages which are currently held by other parts of the application.)-.15
+F -.15(Pa)5.973 G .973(ges retrie).15 F -.15(ve)-.25 G 3.473(di).15 G(n)535 312
+Q .529(this manner don')133 324 R 3.029(tn)-.18 G .528
+(eed to be returned to the memory pool, i.e. the)212.457 324 R 3.028(ys)-.15 G
+(hould)413.95 324 Q/F2 10/Times-Bold@0 SF(not)3.028 E F0 .528
+(be speci\214ed as ar)3.028 F(gu-)-.18 E(ments to the)133 336 Q F1(mpool_put)
+2.5 E F0(routine.\))2.5 E(Created pages ha)108 352.8 Q .3 -.15(ve a)-.2 H
+(ll their bytes set to 0.).15 E 2.078(All pages returned by)108 369.6 R F1
+(mpool_g)4.578 E(et)-.1 E F0 2.079
+(\(unless the MPOOL_NOPIN \215ag is speci\214ed\), will be retained \(i.e.)
+4.578 F -.74(``)108 381.6 S(pinned').74 E
+('\) in the pool until a subsequent call to)-.74 E F1(mpool_put)2.5 E F0(.).68
+E .077(The function)108 398.4 R F1(mpool_put)2.577 E F0 .076
+(indicates that the page referenced by)2.577 F F1(pgaddr)2.576 E F0 .076
+(can be e)2.576 F .076(victed from the pool.)-.25 F F1(Pgaddr)5.076 E F0
+(must be an address pre)108 410.4 Q(viously returned by)-.25 E F1(mpool_g)2.5 E
+(et)-.1 E F0(.).68 E(The \215ag v)108 427.2 Q(alue is speci\214ed by)-.25 E F1
+(or)2.5 E F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)277.2 427.2 S(he follo)285.81
+427.2 Q(wing v)-.25 E(alues:)-.25 E(MPOOL_DIR)108 444 Q(TY)-.6 E .052(The page\
+ has been modi\214ed and must be written to the source \214le before being e)
+133 456 R .052(victed from the pool.)-.25 F(MPOOL_DISCARD)108 472.8 Q .145
+(The page is unlik)133 484.8 R .144(ely to be useful in the near future, and s\
+hould be discarded before other pages in the)-.1 F(pool.)133 496.8 Q
+(The function)108 513.6 Q F1(mpool_put)2.5 E F0(returns -1 on f)2.5 E
+(ailure, setting)-.1 E F1(errno)2.5 E F0 2.5(,a).18 G(nd 0 on success.)352.77
+513.6 Q .027(The function)108 530.4 R F1(mpool_sync)2.527 E F0 .028
+(writes all pages associated with the MPOOLFILE pointer)2.528 F F1(mpf)2.528 E
+F0 2.528(,w)1.96 G .028(hich were speci-)474.414 530.4 R .431(\214ed as ar)108
+542.4 R .431(guments to the)-.18 F F1(mpool_put)2.931 E F0 .431
+(function with an associated \215ag of MPOOL_DIR)2.931 F(TY)-.6 E 2.93(,t)-1.29
+G 2.93(ot)472.61 542.4 S .43(he source \214le.)483.32 542.4 R(The function)108
+554.4 Q F1(mpool_sync)2.5 E F0(returns -1 on f)2.5 E(ailure, setting)-.1 E F1
+(errno)2.5 E F0 2.5(,a).18 G(nd 0 on success.)357.76 554.4 Q 1.075
+(The function)108 571.2 R F1(mpool_unlink)3.575 E F0(destro)3.575 E 1.075
+(ys the memory pool identi\214ed by the directory)-.1 F F1(path)3.575 E F0
+3.575(,r).28 G(emo)471.33 571.2 Q 1.075(ving all \214les)-.15 F 1.121
+(used to implement the memory pool.)108 583.2 R 1.121(\(The directory)6.121 F
+F1(path)3.621 E F0 1.121(is not remo)3.621 F -.15(ve)-.15 G 3.62(d.\) If).15 F
+1.12(there are processes which)3.62 F(ha)108 595.2 Q .871 -.15(ve c)-.2 H
+(alled).15 E F1(mpool_open)3.071 E F0 .571(without calling)3.071 F F1
+(mpool_close)3.071 E F0 .572
+(\(i.e., there are processes currently using the memory)3.071 F(pool\),)108
+607.2 Q F1(mpool_unlink)2.652 E F0 .152(will f)2.652 F .151
+(ail without further action, unless the force \215ag is set, in which case)-.1
+F F1(mpool_unlink)2.651 E F0 .524
+(will attempt to delete the memory pool \214les re)108 619.2 R -.05(ga)-.15 G
+.525(rdless of an).05 F 3.025(yp)-.15 G .525
+(rocesses still using the memory pool.)366.45 619.2 R(An)5.525 E(y)-.15 E .598
+(accesses to a remo)108 631.2 R -.15(ve)-.15 G 3.097(dm).15 G .597
+(emory pool will lik)208.95 631.2 R .597(ely result in une)-.1 F .597
+(xpected beha)-.15 F(vior)-.2 E 5.597(.T)-.55 G .597(he function)436.036 631.2
+R F1(mpool_unlink)3.097 E F0(returns -1 on f)108 643.2 Q(ailure, setting)-.1 E
+F1(errno)2.5 E F0 2.5(,a).18 G(nd 0 on success.)253.61 643.2 Q .11
+(In the case of catastrophic or system f)108 660 R .11
+(ailure, it is possible to clean up a memory pool by remo)-.1 F .11
+(ving all of the)-.15 F .569(\214les in the directory speci\214ed to the)108
+672 R F1(mpool_cr)3.068 E(eate)-.37 E F0 .568
+(function, as memory pool \214les are ne)3.068 F -.15(ve)-.25 G 3.068(rc).15 G
+.568(reated in an)487.364 672 R(y)-.15 E
+(directory other than the one speci\214ed to)108 684 Q F1(mpool_cr)2.5 E(eate)
+-.37 E F0(.).18 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q
+99.315(ution August)-.2 F(1, 1995)2.5 E(3)535 732 Q EP
+%%Page: 4 16
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 110.12(DB_MPOOL\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 110.12(anual DB_MPOOL\(3\))340.17 48 R .025(The function)108 84 R/F1
+10/Times-Italic@0 SF(mpool_stat)2.525 E F0 .026
+(writes statistics for the memory pool)2.526 F F1(mp)2.526 E F0 .026
+(to the \214le speci\214ed by)2.526 F F1(fp)2.526 E F0 5.026(.T).19 G .026
+(hese statistics)485.254 84 R .829
+(include the number of \214les participating in the pool, the acti)108 96 R
+1.129 -.15(ve p)-.25 H .829(ages in the pool, and numbers as to ho).15 F(w)-.25
+E(ef)108 108 Q(fecti)-.25 E .3 -.15(ve t)-.25 H(he cache has been.).15 E/F2 9
+/Times-Bold@0 SF(ERR)72 124.8 Q(ORS)-.27 E F0(The)108 136.8 Q F1(mpool_cr)3.852
+E(eate)-.37 E F0(,).18 E F1(mpool_open)3.852 E F0(and)3.852 E F1(mpool_fopen)
+3.852 E F0 1.353(functions may f)3.852 F 1.353(ail and set)-.1 F F1(errno)3.853
+E F0 1.353(for an)3.853 F 3.853(yo)-.15 G 3.853(ft)493.424 136.8 S 1.353
+(he errors)503.387 136.8 R(speci\214ed for the library functions)108 148.8 Q F1
+(open)2.5 E F0(\(2\),).24 E F1 -.37(re)2.5 G(ad).37 E F0(\(2\), and).77 E F1
+(malloc)2.5 E F0(\(3\).).31 E(The)108 165.6 Q F1(mpool_close)3.144 E F0(and)
+3.144 E F1(mpool_fclose)3.144 E F0 .644(functions may f)3.144 F .644
+(ail and set)-.1 F F1(errno)3.144 E F0 .643(for an)3.143 F 3.143(yo)-.15 G
+3.143(ft)425.985 165.6 S .643(he errors speci\214ed for the)435.238 165.6 R
+(library functions)108 177.6 Q F1(close)2.5 E F0(\(2\) and).18 E F1(fr)2.5 E
+(ee)-.37 E F0(\(3\).).18 E(The)108 194.4 Q F1(mpool_g)4.097 E(et)-.1 E F0 1.597
+(function may f)4.097 F 1.597(ail and set)-.1 F F1(errno)4.097 E F0 1.597
+(for an)4.097 F 4.097(yo)-.15 G 4.097(ft)349.14 194.4 S 1.597
+(he errors speci\214ed for the library functions)359.347 194.4 R F1 -.37(re)108
+206.4 S(ad).37 E F0(\(2\),).77 E F1(write)2.5 E F0(\(2\), and).18 E F1(malloc)
+2.5 E F0(\(3\) or the follo).31 E(wing:)-.25 E([EINV)108 223.2 Q(AL])-1.35 E
+(The requested page does not e)133 235.2 Q(xist and MPOOL_CREA)-.15 E(TE w)
+-1.11 E(as not set.)-.1 E(The)108 252 Q F1(mpool_put)4.288 E F0 1.787
+(function may f)4.287 F 1.787(ail and set)-.1 F F1(errno)4.287 E F0 1.787
+(for an)4.287 F 4.287(yo)-.15 G 4.287(ft)351.701 252 S 1.787
+(he errors speci\214ed for the library function)362.098 252 R F1(write)108 264
+Q F0(\(2\) or the follo).18 E(wing:)-.25 E([EA)108 280.8 Q(CCES])-.4 E
+(The source \214le w)133 292.8 Q(as not opened for writing.)-.1 E(The)108 309.6
+Q F1(mpool_sync)3.993 E F0 1.493(function may f)3.993 F 1.493(ail and set)-.1 F
+F1(errno)3.993 E F0 1.494(for an)3.993 F 3.994(yo)-.15 G 3.994(ft)353.752 309.6
+S 1.494(he errors speci\214ed for the library function)363.856 309.6 R F1
+(write)108 321.6 Q F0(\(2\).).18 E(The)108 338.4 Q F1(mpool_unlink)3.569 E F0
+1.069(function may f)3.569 F 1.068(ail and set)-.1 F F1(errno)3.568 E F0 1.068
+(for an)3.568 F 3.568(yo)-.15 G 3.568(ft)356.734 338.4 S 1.068
+(he errors speci\214ed for the library function)366.412 338.4 R F1(unlink)108
+350.4 Q F0(\(2\) or the follo).67 E(wing:)-.25 E([EB)108 367.2 Q(USY])-.1 E
+(The memory pool w)133 379.2 Q(as in use and the force \215ag w)-.1 E
+(as not set.)-.1 E F2(SEE ALSO)72 396 Q F1(db_btr)108 408 Q(ee)-.37 E F0
+(\(3\),).18 E F1(db_hash)2.5 E F0(\(3\),).28 E F1(db_loc)2.5 E(k)-.2 E F0
+(\(3\),).67 E F1(db_lo)2.5 E(g)-.1 E F0(\(3\),).22 E F1(db_open)2.5 E F0
+(\(3\),).24 E F1(db_r)2.5 E(ecno)-.37 E F0(\(3\),).18 E F1(db_txn)2.5 E F0
+(\(3\)).24 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q
+99.315(ution August)-.2 F(1, 1995)2.5 E(4)535 732 Q EP
+%%Page: 1 17
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 119.01(DB_OPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 119.01(anual DB_OPEN\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)
+72 84 S(ME).18 E F0(db_open \255 database access methods)108 96 Q F1(SYNOPSIS)
+72 112.8 Q/F2 10/Times-Bold@0 SF(#include <db)108 124.8 Q(.h>)-.4 E(DB *)108
+148.8 Q(db_open\(const char *\214le, int \215ags, int mode,)108 160.8 Q
+(DBTYPE type, DBINFO *dbinf)158 172.8 Q(o, const v)-.25 E(oid *openinf)-.1 E
+(o\);)-.25 E F1(DESCRIPTION)72 189.6 Q F0 .485(The DB library is a f)108 201.6
+R .485(amily of groups of functions that pro)-.1 F .486
+(vides a modular programming interf)-.15 F .486(ace to trans-)-.1 F .823
+(actions and record-oriented \214le access.)108 213.6 R .822
+(The library includes support for transaction, locking, logging and)5.822 F
+.258(\214le b)108 225.6 R(uf)-.2 E .258(fering functionality)-.25 F 2.758(,a)
+-.65 G 2.758(sw)223.214 225.6 S .258(ell as v)237.082 225.6 R .258(arious inde)
+-.25 F -.15(xe)-.15 G 2.758(da).15 G .258(ccess methods.)331.434 225.6 R(Man)
+5.258 E 2.758(yo)-.15 G 2.758(ft)427.878 225.6 S .258
+(he functional groups \(e.g.)436.746 225.6 R .528(the memory pool functions\) \
+are useful independently of the rest of the DB functions, although some func-)
+108 237.6 R .306(tional groups are e)108 249.6 R .306
+(xplicitly based on other functional groups \(e.g.)-.15 F .306
+(transactions and logging\).)5.306 F -.15(Fo)5.306 G 2.806(rag).15 G(eneral)
+515.57 249.6 Q .245(description of transactions, see)108 261.6 R/F3 10
+/Times-Italic@0 SF(db_txn)2.745 E F0 2.745(\(3\). F).24 F .245
+(or a general description of the access methods, see)-.15 F F3(db_open)2.745 E
+F0(\(3\)).24 E .307(and then the indi)108 273.6 R .307
+(vidual access method manual pages:)-.25 F F3(db_btr)2.808 E(ee)-.37 E F0
+(\(3\),).18 E F3(db_hash)2.808 E F0(\(3\),).28 E F3(db_lo)2.808 E(g)-.1 E F0
+.308(\(3\) and).22 F F3(db_r)2.808 E(ecno)-.37 E F0(\(3\).).18 E -.15(Fo)108
+285.6 S 3.635(rag).15 G 1.135(eneral description of the lock manager)138.45
+285.6 R 3.635(,s)-.4 G(ee)307.32 285.6 Q F3(db_loc)3.635 E(k)-.2 E F0 3.635
+(\(3\). F).67 F 1.135(or a general description of the memory)-.15 F
+(pool manager)108 297.6 Q 2.5(,s)-.4 G(ee)171.2 297.6 Q F3(db_mpool)2.5 E F0
+(\(3\).).51 E(This manual page describes the o)108 314.4 Q -.15(ve)-.15 G
+(rall structure of the a).15 E -.25(va)-.2 G(ilable access methods.).25 E .457
+(The currently supported \214le formats are btree, hashed, log and recno \(i.e\
+. \215at-\214le oriented\).)108 331.2 R .457(The btree for)5.457 F(-)-.2 E .974
+(mat is a representation of a sorted, balanced tree structure.)108 343.2 R .973
+(The hashed format is an e)5.974 F .973(xtensible, dynamic)-.15 F .801
+(hashing scheme.)108 355.2 R .802
+(The log format is a general-purpose logging f)5.801 F(acility)-.1 E 5.802(.T)
+-.65 G .802(he recno format is a byte stream)406.888 355.2 R .415
+(\214le with \214x)108 367.2 R .415(ed or v)-.15 F .415
+(ariable length records.)-.25 F .415(The formats and other)5.415 F 2.914(,f)-.4
+G .414(ormat speci\214c information are described)376.714 367.2 R
+(in detail in their respecti)108 379.2 Q .3 -.15(ve m)-.25 H(anual pages:).15 E
+F3(db_btr)2.5 E(ee)-.37 E F0(\(3\),).18 E F3(db_hash)2.5 E F0(\(3\),).28 E F3
+(db_lo)2.5 E(g)-.1 E F0(\(3\), and).22 E F3(db_r)2.5 E(ecno)-.37 E F0(\(3\).)
+.18 E .138(Db_open opens)108 396 R F3(\214le)2.638 E F0 .139
+(for reading and/or writing.)2.638 F .139(Files ne)5.139 F -.15(ve)-.25 G 2.639
+(ri).15 G .139(ntended to be preserv)349.088 396 R .139
+(ed on disk may be created)-.15 F .423
+(by setting the \214le parameter to NULL.)108 408 R .423
+(\(Note, while most of the access methods use)5.423 F F3(\214le)2.923 E F0 .423
+(as the name of an)2.923 F .429
+(underlying \214le on disk, this is not guaranteed.)108 420 R .43
+(See the manual pages for the indi)5.429 F .43(vidual access methods for)-.25 F
+(more information.\))108 432 Q(The)108 448.8 Q F3<8d61>4.328 E(gs)-.1 E F0(and)
+4.328 E F3 1.828(mode ar)4.328 F(guments)-.37 E F0 1.828
+(are as speci\214ed to the)4.328 F F3(open)4.328 E F0 1.828(\(2\) function, ho)
+.24 F(we)-.25 E -.15(ve)-.25 G 2.628 -.4(r, o).15 H 1.828(nly the O_CREA).4 F
+-.74(T,)-1.11 G .127(O_EXCL, O_EXLOCK, O_NONBLOCK, O_RDONL)108 460.8 R 2.708
+-1.29(Y, O)-1 H(_RD)1.29 E .128(WR, O_SHLOCK and O_TR)-.3 F .128
+(UNC \215ags are)-.4 F 2.5(meaningful. \(Note,)108 472.8 R
+(opening a database \214le O_WR)2.5 E(ONL)-.4 E 2.5(Yi)-1 G 2.5(sn)342.67 472.8
+S(ot possible.\))354.06 472.8 Q(The)108 489.6 Q F3(type)5.338 E F0(ar)5.338 E
+2.837(gument is of type DBTYPE \(as de\214ned in the <db)-.18 F 2.837
+(.h> include \214le\) and may be set to)-.4 F
+(DB_BTREE, DB_HASH, DB_LOG or DB_RECNO.)108 501.6 Q(The)108 518.4 Q F3(dbinfo)
+3.279 E F0(ar)3.279 E .779(gument is a pointer to a structure containing refer\
+ences to locking, logging, transaction, and)-.18 F 1.242(shared-memory b)108
+530.4 R(uf)-.2 E 1.242(fer pool information.)-.25 F(If)6.242 E F3(dbinfo)3.742
+E F0 1.241(is NULL, then the access method may still use these)3.741 F .667
+(subsystems, b)108 542.4 R .667(ut the usage will be pri)-.2 F -.25(va)-.25 G
+.668(te to the application and managed by DB.).25 F(If)5.668 E F3(dbinfo)3.168
+E F0 .668(is non-NULL,)3.168 F .481(then the module referenced by each of the \
+non-NULL \214elds is used by DB as necessary)108 554.4 R 5.48(.T)-.65 G .48
+(he \214elds of the)479.4 554.4 R(DBINFO structure are de\214ned as follo)108
+566.4 Q(ws:)-.25 E(const char *errpfx;)108 583.2 Q 2.5(Ap)133 595.2 S
+(re\214x to prepend to error messages; used only if)147.72 595.2 Q F3
+(err\214le)2.5 E F0(is non-NULL.)2.5 E(FILE *err\214le;)108 612 Q(The)133 624 Q
+F3(stdio)2.5 E F0(\(3\) \214le stream to which error messages are logged.).18 E
+.147(When an)133 648 R 2.647(ye)-.15 G .147(rror occurs in the)180.904 648 R F3
+(db_open)2.648 E F0 .148(function, or in an)2.648 F 2.648(yf)-.15 G .148
+(unction called using a \214eld of the returned)369.824 648 R .234
+(DB structure, an error v)133 660 R .234
+(alue is returned by the function, and the global v)-.25 F(ariable)-.25 E F3
+(errno)2.733 E F0 .233(is set appropri-)2.733 F(ately)133 672 Q 5.415(.I)-.65 G
+2.915(ns)163.035 672 S .416(ome cases, ho)174.84 672 R(we)-.25 E -.15(ve)-.25 G
+1.216 -.4(r, t).15 H(he).4 E F3(errno)2.916 E F0 -.25(va)2.916 G .416
+(lue may be insuf).25 F .416(\214cient to describe the cause of the error)-.25
+F(.)-.55 E .137(In these cases, if)133 684 R F3(err\214le)2.637 E F0 .137(is n\
+on-NULL, additional error information will be written to the \214le stream it)
+2.637 F(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315
+(ution August)-.2 F(1, 1995)2.5 E(1)535 732 Q EP
+%%Page: 2 18
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 119.01(DB_OPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 119.01(anual DB_OPEN\(3\))340.17 48 R .643
+(represents, preceded by the string, if an)133 84 R 1.943 -.65(y, s)-.15 H .643
+(peci\214ed by).65 F/F1 10/Times-Italic@0 SF(errpfx)3.143 E F0 5.643(.T).53 G
+.644(his error logging f)394.94 84 R .644(acility should not)-.1 F
+(be required for normal operation, b)133 96 Q(ut may be useful in deb)-.2 E
+(ugging applications.)-.2 E(char *errb)108 112.8 Q(uf;)-.2 E .03(The b)133
+124.8 R(uf)-.2 E .03(fer to which error messages are copied.)-.25 F .029
+(If non-NULL,)5.029 F F1(errb)2.529 E(uf)-.2 E F0(beha)2.529 E -.15(ve)-.2 G
+2.529(sa).15 G 2.529(sd)451.423 124.8 S .029(escribed for)462.842 124.8 R F1
+(err\214le)2.529 E F0(,).18 E -.15(ex)133 136.8 S .173(cept that the).15 F F1
+(errpfx)2.673 E F0 .174
+(\214eld is ignored and the error message is copied into the speci\214ed b)
+2.673 F(uf)-.2 E .174(fer instead)-.25 F 1.014
+(of being written to the FILE stream.)133 148.8 R 1.013
+(The DB routines assume that the associated b)6.014 F(uf)-.2 E 1.013
+(fer is at least)-.25 F(1024 bytes in length.)133 160.8 Q(LOCK_T)108 177.6 Q
+(ABLE_T *lockinfo;)-.93 E .265
+(If locking is required for the \214le being opened \(as in the case of b)133
+189.6 R(uf)-.2 E .266(fers being maintained in a shared)-.25 F 1.794(memory b)
+133 201.6 R(uf)-.2 E 1.794(fer pool\), the)-.25 F F1(loc)4.294 E(kinfo)-.2 E F0
+1.794(\214eld contains a return v)4.294 F 1.793(alue from the function)-.25 F
+F1(loc)4.293 E(k_open)-.2 E F0(that)4.293 E(should be used \(see)133 213.6 Q F1
+(db_loc)2.5 E(k)-.2 E F0 2.5(\(3\)\). If).67 F F1(loc)2.5 E(kinfo)-.2 E F0
+(is NULL, no locking is done.)2.5 E(DB *loginfo;)108 230.4 Q .93
+(If modi\214cations to the \214le being opened should be logged, the)133 242.4
+R F1(lo)3.43 E(ginfo)-.1 E F0 .93(\214eld contains a return v)3.43 F(alue)-.25
+E .063(from the function)133 254.4 R F1(dbopen)2.563 E F0 2.563(,w).24 G .062
+(hen opening a DB \214le of type DB_LOG.)247.642 254.4 R(If)5.062 E F1(lo)2.562
+E(ginfo)-.1 E F0 .062(is NULL, no logging)2.562 F(is done.)133 266.4 Q
+(MPOOL *mpoolinfo;)108 283.2 Q 1.129
+(If the cache for the \214le being opened should be maintained in a shared b)
+133 295.2 R(uf)-.2 E 1.129(fer pool, the)-.25 F F1(mpoolinfo)3.629 E F0 .102
+(\214eld contains a return v)133 307.2 R .102(alue from the function)-.25 F F1
+(mpool_open)2.602 E F0 .102(that should be used \(see)2.602 F F1(db_mpool)2.602
+E F0 2.602(\(3\)\). If).51 F F1(mpoolinfo)133 319.2 Q F0 .429
+(is NULL, a memory pool may still be created, b)2.929 F .43(ut it will be pri)
+-.2 F -.25(va)-.25 G .43(te to the application and).25 F(managed by DB.)133
+331.2 Q(TXNMGR *txninfo;)108 348 Q 1.161
+(If the accesses to the \214le being opened should tak)133 360 R 3.661(ep)-.1 G
+1.161(lace in the conte)354.474 360 R 1.161(xt of transactions \(pro)-.15 F
+(viding)-.15 E 1.239(atomicity and complete error reco)133 372 R -.15(ve)-.15 G
+1.239(ry\), the).15 F F1(txninfo)3.739 E F0 1.239(\214eld contains a return v)
+3.739 F 1.24(alue from the function)-.25 F F1(txn_open)133 384 Q F0(\(see)2.599
+E F1(db_txn)2.599 E F0 2.599(\(3\)\). If).24 F .098
+(transactions are speci\214ed, the application is responsible for making suit-)
+2.599 F 1.27(able calls to)133 396 R F1(txn_be)3.77 E(gin)-.4 E F0(,).24 E F1
+(txn_abort)3.77 E F0 3.77(,a).68 G(nd)282.91 396 Q F1(txn_commit)3.77 E F0 6.27
+(.I).68 G(f)356.12 396 Q F1(txninfo)3.77 E F0 1.27
+(is NULL, no transaction support is)3.77 F(done.)133 408 Q(The)108 424.8 Q F1
+(openinfo)2.85 E F0(ar)2.85 E .349(gument is a pointer to an access method spe\
+ci\214c structure described in the access method')-.18 F(s)-.55 E .03
+(manual page.)108 436.8 R(If)5.03 E F1(openinfo)2.53 E F0 .031
+(is NULL, each access method will use def)2.53 F .031
+(aults appropriate for the system and the)-.1 F(access method.)108 448.8 Q/F2 9
+/Times-Bold@0 SF(KEY/D)72 465.6 Q -1.35 -.855(AT A)-.315 H -.666(PA)3.105 G
+(IRS).666 E F0 .313(Access to all access methods is based on k)108 477.6 R -.15
+(ey)-.1 G .312(/data pairs.).15 F .312(Both k)5.312 F -.15(ey)-.1 G 2.812(sa)
+.15 G .312(nd data are represented by the follo)386.758 477.6 R(w-)-.25 E
+(ing data structure:)108 489.6 Q(typedef struct {)108 506.4 Q -.2(vo)144 518.4
+S(id *data;).2 E(size_t size;)144 530.4 Q 2.5(}D)108 542.4 S(BT)122.52 542.4 Q
+(;)-.55 E(The elements of the DBT structure are de\214ned as follo)108 559.2 Q
+(ws:)-.25 E 5.84(data A)108 576 R(pointer to a byte string.)2.5 E 6.95
+(size The)108 592.8 R(length of)2.5 E F1(data)2.5 E F0 2.5(,i).26 G 2.5(nb)
+215.2 592.8 S(ytes.)227.7 592.8 Q -2.15 -.25(Ke y)108 609.6 T .672(and data by\
+te strings may reference strings of essentially unlimited length, although an)
+3.422 F 3.173(yt)-.15 G .873 -.1(wo o)493.204 609.6 T 3.173(ft).1 G(hem)522.78
+609.6 Q(must \214t into a)108 621.6 Q -.25(va)-.2 G
+(ilable memory at the same time.).25 E .14(The access methods pro)108 638.4 R
+.139(vide no guarantees about byte string alignment, and applications are resp\
+onsible for)-.15 F(maintaining an)108 650.4 Q 2.5(yn)-.15 G
+(ecessary alignment.)180.07 650.4 Q F2(DB OPERA)72 667.2 Q(TIONS)-.855 E F1
+(Db_open)108 679.2 Q F0 .56
+(returns a pointer to a DB structure \(as de\214ned in the <db)3.06 F .56
+(.h> include \214le\) on success, and NULL)-.4 F 1.02(on error)108 691.2 R 6.02
+(.T)-.55 G 1.02(he DB structure describes a database type, and includes a set \
+of functions to perform v)155.03 691.2 R(arious)-.25 E(4.4 Berk)72 732 Q(ele)
+-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E
+(2)535 732 Q EP
+%%Page: 3 19
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 119.01(DB_OPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 119.01(anual DB_OPEN\(3\))340.17 48 R .241
+(actions, as described belo)108 84 R 4.041 -.65(w. E)-.25 H .241
+(ach of these functions tak).65 F .241
+(es a pointer to a DB structure, and may tak)-.1 F 2.741(eo)-.1 G .242(ne or)
+519.488 84 R .889(more DBT *')108 96 R 3.389(sa)-.55 G .889(nd a \215ag v)
+174.827 96 R .889(alue as well.)-.25 F(Indi)5.889 E .888
+(vidual access methods specify additional functions and \215ags)-.25 F
+(which are speci\214c to the method.)108 108 Q
+(The \214elds of the DB structure are as follo)5 E(ws:)-.25 E(DBTYPE type;)108
+124.8 Q(The type of the underlying access method \(and \214le format\).)133
+136.8 Q(int \(*close\)\(const DB *db\);)108 153.6 Q 3.863(Ap)133 165.6 S 1.363
+(ointer to a function to \215ush an)149.083 165.6 R 3.864(yc)-.15 G 1.364
+(ached information to disk, free an)290.968 165.6 R 3.864(ya)-.15 G 1.364
+(llocated resources, and)445.912 165.6 R .878(close an)133 177.6 R 3.378(yu)
+-.15 G .878(nderlying \214les.)179.596 177.6 R .878(Since k)5.878 F -.15(ey)-.1
+G .878(/data pairs are cached in memory).15 F 3.377(,f)-.65 G .877
+(ailing to sync the \214le with)431.445 177.6 R(the)133 189.6 Q/F1 10
+/Times-Italic@0 SF(close)2.5 E F0(or)2.5 E F1(sync)2.5 E F0
+(function may result in inconsistent or lost information.)2.5 E(The)133 206.4 Q
+F1(close)2.5 E F0(functions return -1 on f)2.5 E(ailure, setting)-.1 E F1
+(errno)2.5 E F0 2.5(,a).18 G(nd 0 on success.)355.54 206.4 Q
+(int \(*del\)\(const DB *db, TXN *txnid,)108 223.2 Q(const DBT *k)183 235.2 Q
+-.15(ey)-.1 G 2.5(,u)-.5 G(_int \215ags\);)257.65 235.2 Q 2.541(Ap)133 247.2 S
+.041(ointer to a function to remo)147.761 247.2 R .341 -.15(ve k)-.15 H -.15
+(ey).05 G .041(/data pairs from the database.).15 F .042(The k)5.041 F -.15(ey)
+-.1 G .042(/data pair associated with).15 F(the speci\214ed)133 259.2 Q F1 -.1
+(ke)2.5 G(y)-.2 E F0(are discarded from the database.)2.5 E(The)133 276 Q F1
+(txnid)3.317 E F0 .817(parameter contains a transaction ID returned from)3.317
+F F1(txn_be)3.317 E(gin)-.4 E F0 3.317(,i).24 G 3.316(ft)431.22 276 S .816
+(he \214le is being accessed)440.646 276 R
+(under transaction protection, or NULL if transactions are not in ef)133 288 Q
+(fect.)-.25 E(The parameter)133 304.8 Q F1<8d61>2.5 E(g)-.1 E F0
+(must be set to 0 or e)2.5 E(xactly one of the follo)-.15 E(wing v)-.25 E
+(alues:)-.25 E(R_CURSOR)133 321.6 Q(Delete the record referenced by the cursor)
+158 333.6 Q 5(.T)-.55 G(he cursor must ha)339.32 333.6 Q .3 -.15(ve p)-.2 H(re)
+.15 E(viously been initialized.)-.25 E(The)133 350.4 Q F1(delete)2.934 E F0
+.434(functions return -1 on error)2.934 F 2.934(,s)-.4 G(etting)297.818 350.4 Q
+F1(errno)2.934 E F0 2.934(,0o).18 G 2.934(ns)364.3 350.4 S .434
+(uccess, and 1 if the speci\214ed)376.124 350.4 R F1 -.1(ke)2.935 G(y)-.2 E F0
+.435(did not)2.935 F -.15(ex)133 362.4 S(ist in the \214le.).15 E
+(int \(*fd\)\(const DB *db\);)108 379.2 Q 3.351(Ap)133 391.2 S .851
+(ointer to a function which returns a \214le descriptor representati)148.571
+391.2 R 1.15 -.15(ve o)-.25 H 3.35(ft).15 G .85(he underlying database.)430.53
+391.2 R(A)5.85 E .338(\214le descriptor referencing the same \214le will be re\
+turned to all processes which call)133 403.2 R F1(db_open)2.838 E F0 .339
+(with the)2.839 F(same)133 415.2 Q F1(\214le)3.376 E F0 3.376(name. This)3.376
+F .876(\214le descriptor may be safely used as an ar)3.376 F .876
+(gument to the)-.18 F F1(fcntl)3.376 E F0 .875(\(2\) and).51 F F1(\215oc)3.375
+E(k)-.2 E F0(\(2\)).67 E .99(locking functions.)133 427.2 R .99
+(The \214le descriptor is not necessarily associated with an)5.99 F 3.49(yo)
+-.15 G 3.49(ft)453.98 427.2 S .99(he underlying \214les)463.58 427.2 R
+(used by the access method.)133 439.2 Q(No \214le descriptor is a)5 E -.25(va)
+-.2 G(ilable for in memory databases.).25 E(The)133 456 Q F1(fd)2.5 E F0
+(functions return -1 on error)2.5 E 2.5(,s)-.4 G(etting)278.68 456 Q F1(errno)
+2.5 E F0 2.5(,a).18 G(nd the \214le descriptor on success.)335.8 456 Q
+(int \(*get\)\(const DB *db, TXN *txnid,)108 472.8 Q(const DBT *k)183 484.8 Q
+-.15(ey)-.1 G 2.5(,D)-.5 G(BT *data, u_int \215ags\);)259.87 484.8 Q 2.854(Ap)
+133 496.8 S .354(ointer to a function which is the interf)148.074 496.8 R .354
+(ace for k)-.1 F -.15(ey)-.1 G .353(ed retrie).15 F -.25(va)-.25 G 2.853(lf).25
+G .353(rom the database.)397.995 496.8 R .353(The address and)5.353 F
+(length of the data associated with the speci\214ed)133 508.8 Q F1 -.1(ke)2.5 G
+(y)-.2 E F0(are returned in the structure referenced by)2.5 E F1(data)2.5 E F0
+(.).26 E(The)133 525.6 Q F1(txnid)3.316 E F0 .816
+(parameter contains a transaction ID returned from)3.316 F F1(txn_be)3.317 E
+(gin)-.4 E F0 3.317(,i).24 G 3.317(ft)431.215 525.6 S .817
+(he \214le is being accessed)440.642 525.6 R
+(under transaction protection, or NULL if transactions are not in ef)133 537.6
+Q(fect.)-.25 E(The)133 554.4 Q F1 -.1(ge)2.5 G(t).1 E F0
+(functions return -1 on error)2.5 E 2.5(,s)-.4 G(etting)283.02 554.4 Q F1
+(errno)2.5 E F0 2.5(,0o).18 G 2.5(ns)348.2 554.4 S(uccess, and 1 if the)359.59
+554.4 Q F1 -.1(ke)2.5 G(y)-.2 E F0 -.1(wa)2.5 G 2.5(sn).1 G(ot found.)476.83
+554.4 Q(int \(*put\)\(const DB *db, TXN *txnid,)108 571.2 Q(DBT *k)183 583.2 Q
+-.15(ey)-.1 G 2.5(,c)-.5 G(onst DBT *data, u_int \215ags\);)233.48 583.2 Q 2.5
+(Ap)133 595.2 S(ointer to a function to store k)147.72 595.2 Q -.15(ey)-.1 G
+(/data pairs in the database.).15 E(The)133 612 Q F1(txnid)3.317 E F0 .817
+(parameter contains a transaction ID returned from)3.317 F F1(txn_be)3.317 E
+(gin)-.4 E F0 3.317(,i).24 G 3.316(ft)431.22 612 S .816
+(he \214le is being accessed)440.646 612 R
+(under transaction protection, or NULL if transactions are not in ef)133 624 Q
+(fect.)-.25 E(The parameter)133 640.8 Q F1<8d61>2.5 E(g)-.1 E F0
+(must be set to 0 or e)2.5 E(xactly one of the follo)-.15 E(wing v)-.25 E
+(alues:)-.25 E(R_CURSOR)133 657.6 Q .448(Replace the k)158 669.6 R -.15(ey)-.1
+G .448(/data pair referenced by the cursor).15 F 5.449(.T)-.55 G .449
+(he cursor must ha)375.156 669.6 R .749 -.15(ve p)-.2 H(re).15 E .449
+(viously been ini-)-.25 F(tialized.)158 681.6 Q(4.4 Berk)72 732 Q(ele)-.1 E 2.5
+(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(3)535
+732 Q EP
+%%Page: 4 20
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 119.01(DB_OPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 119.01(anual DB_OPEN\(3\))340.17 48 R(R_NOO)133 84 Q(VER)-.5 E
+(WRITE)-.55 E(Enter the ne)158 96 Q 2.5(wk)-.25 G -.15(ey)220.69 96 S
+(/data pair only if the k).15 E .3 -.15(ey d)-.1 H(oes not pre).15 E(viously e)
+-.25 E(xist.)-.15 E .664(The def)133 112.8 R .664(ault beha)-.1 F .664
+(vior of the)-.2 F/F1 10/Times-Italic@0 SF(put)3.164 E F0 .664
+(functions is to enter the ne)3.164 F 3.164(wk)-.25 G -.15(ey)387.498 112.8 S
+.663(/data pair).15 F 3.163(,r)-.4 G .663(eplacing an)443.534 112.8 R 3.163(yp)
+-.15 G(re)503.03 112.8 Q(viously)-.25 E -.15(ex)133 124.8 S(isting k).15 E -.15
+(ey)-.1 G(.)-.5 E(The)133 141.6 Q F1(put)3.558 E F0 1.058
+(functions return -1 on error)3.558 F 3.559(,s)-.4 G(etting)291.089 141.6 Q F1
+(errno)3.559 E F0 3.559(,0o).18 G 3.559(ns)359.446 141.6 S 1.059
+(uccess, and 1 if the R_NOO)371.895 141.6 R(VER)-.5 E(WRITE)-.55 E F1<8d61>133
+153.6 Q(g)-.1 E F0 -.1(wa)2.5 G 2.5(ss).1 G(et and the k)172.24 153.6 Q .3 -.15
+(ey a)-.1 H(lready e).15 E(xists in the \214le.)-.15 E
+(int \(*seq\)\(const DB *db, TXN *txnid,)108 170.4 Q(DBT *k)183 182.4 Q -.15
+(ey)-.1 G 2.5(,D)-.5 G(BT *data, u_int \215ags\);)236.26 182.4 Q 2.877(Ap)133
+194.4 S .377(ointer to a function which is the interf)148.097 194.4 R .377
+(ace for sequential retrie)-.1 F -.25(va)-.25 G 2.877(lf).25 G .377
+(rom the database.)415.194 194.4 R .376(The address)5.376 F .012
+(and length of the k)133 206.4 R .312 -.15(ey a)-.1 H .012
+(re returned in the structure referenced by).15 F F1 -.1(ke)2.512 G(y)-.2 E F0
+2.512(,a).32 G .012(nd the address and length of the)412.726 206.4 R
+(data are returned in the structure referenced by)133 218.4 Q F1(data)2.5 E F0
+(.).26 E(The)133 235.2 Q F1(txnid)3.317 E F0 .817
+(parameter contains a transaction ID returned from)3.317 F F1(txn_be)3.317 E
+(gin)-.4 E F0 3.317(,i).24 G 3.316(ft)431.22 235.2 S .816
+(he \214le is being accessed)440.646 235.2 R
+(under transaction protection, or NULL if transactions are not in ef)133 247.2
+Q(fect.)-.25 E .721(Sequential k)133 264 R -.15(ey)-.1 G .721
+(/data pair retrie).15 F -.25(va)-.25 G 3.221(lm).25 G .721(ay be)277.884 264 R
+.721(gin at an)-.15 F 3.221(yt)-.15 G .721
+(ime, and the logical position of the `)346.568 264 R(`cursor')-.74 E 3.222('i)
+-.74 G(s)536.11 264 Q .947(not af)133 276 R .947(fected by calls to the)-.25 F
+F1(del)3.447 E F0(,).51 E F1 -.1(ge)3.447 G(t).1 E F0(,).68 E F1(put)3.447 E F0
+3.446(,o).68 G(r)308.572 276 Q F1(sync)3.446 E F0 3.446
+(functions. Modi\214cations)3.446 F .946(to the database during a)3.446 F 2.091
+(sequential scan will be re\215ected in the scan, i.e. records inserted behind\
+ the cursor will not be)133 288 R
+(returned while records inserted in front of the cursor will be returned.)133
+300 Q(The parameter)133 316.8 Q F1<8d61>2.5 E(g)-.1 E F0(must be set to 0 or e)
+2.5 E(xactly one of the follo)-.15 E(wing v)-.25 E(alues:)-.25 E(R_CURSOR)133
+333.6 Q .937(The data associated with the speci\214ed k)158 345.6 R 1.237 -.15
+(ey i)-.1 H 3.437(sr).15 G 3.437(eturned. This)348.546 345.6 R(dif)3.437 E .936
+(fers from the)-.25 F F1 -.1(ge)3.436 G(t).1 E F0 .936(functions in)3.436 F
+(that it sets or initializes the cursor to the location of the k)158 357.6 Q .3
+-.15(ey a)-.1 H 2.5(sw).15 G(ell.)415.5 357.6 Q(R_FIRST)133 374.4 Q .835
+(The \214rst k)158 386.4 R -.15(ey)-.1 G .835(/data pair of the database is re\
+turned, and the cursor is set or initialized to refer).15 F(-)-.2 E(ence it.)
+158 398.4 Q(R_NEXT)133 415.2 Q(Retrie)158 427.2 Q 1.015 -.15(ve t)-.25 H .715
+(he k).15 F -.15(ey)-.1 G .715(/data pair immediately after the cursor).15 F
+5.715(.I)-.55 G 3.215(ft)391.91 427.2 S .714
+(he cursor is not yet set, this is the)401.235 427.2 R
+(same as the R_FIRST \215ag.)158 439.2 Q(The)133 456 Q F1(seq)3.014 E F0 .514
+(functions return -1 on error)3.014 F 3.015(,s)-.4 G(etting)287.83 456 Q F1
+(errno)3.015 E F0 3.015(,0o).18 G 3.015(ns)354.555 456 S .515
+(uccess, and 1 if there are no k)366.46 456 R -.15(ey)-.1 G .515(/data pairs)
+.15 F(less than or greater than the speci\214ed or current k)133 468 Q -.15(ey)
+-.1 G(.)-.5 E(int \(*sync\)\(const DB *db, u_int \215ags\);)108 484.8 Q 3.291
+(Ap)133 496.8 S .791(ointer to a function to \215ush an)148.511 496.8 R 3.291
+(yc)-.15 G .791(ached information to disk.)286.388 496.8 R .79
+(If the database is in memory only)5.79 F(,)-.65 E(the)133 508.8 Q F1(sync)2.5
+E F0(function has no ef)2.5 E(fect and will al)-.25 E -.1(wa)-.1 G(ys succeed.)
+.1 E(The parameter)133 525.6 Q F1<8d61>2.5 E(g)-.1 E F0
+(must be set to 0 or a v)2.5 E
+(alue speci\214ed by an access method speci\214c manual page.)-.25 E(The)133
+542.4 Q F1(sync)2.5 E F0(functions return -1 on f)2.5 E(ailure, setting)-.1 E
+F1(errno)2.5 E F0 2.5(,a).18 G(nd 0 on success.)352.76 542.4 Q/F2 9
+/Times-Bold@0 SF(ERR)72 559.2 Q(ORS)-.27 E F0(The)108 571.2 Q F1(db_open)4.548
+E F0 2.048(function may f)4.548 F 2.049(ail and set)-.1 F F1(errno)4.549 E F0
+2.049(for an)4.549 F 4.549(yo)-.15 G 4.549(ft)345.977 571.2 S 2.049
+(he errors speci\214ed for the library functions)356.636 571.2 R F1(open)108
+583.2 Q F0(\(2\),).24 E F1(malloc)2.5 E F0(\(3\) or the follo).31 E(wing:)-.25
+E([EFTYPE])108 600 Q 2.5<418c>133 612 S(le is incorrectly formatted.)148.28 612
+Q([EINV)108 628.8 Q(AL])-1.35 E 2.557(Ap)133 640.8 S .056
+(arameter has been speci\214ed \(hash function, recno pad byte etc.\))147.777
+640.8 R .056(that is incompatible with the cur)5.056 F(-)-.2 E .725
+(rent \214le speci\214cation or)133 652.8 R 3.225(,a\215)-.4 G .725
+(ag to a function which is not meaningful for the function \(for e)248.435
+652.8 R(xample,)-.15 E .763(use of the cursor without prior initialization\) o\
+r there is a mismatch between the v)133 664.8 R .763(ersion number of)-.15 F
+(\214le and the softw)133 676.8 Q(are.)-.1 E(The)108 693.6 Q F1(close)2.913 E
+F0 .413(functions may f)2.913 F .413(ail and set)-.1 F F1(errno)2.913 E F0 .413
+(for an)2.913 F 2.913(yo)-.15 G 2.913(ft)319.62 693.6 S .414
+(he errors speci\214ed for the library functions)328.643 693.6 R F1(close)2.914
+E F0(\(2\),).18 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q
+99.315(ution August)-.2 F(1, 1995)2.5 E(4)535 732 Q EP
+%%Page: 5 21
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 119.01(DB_OPEN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 119.01(anual DB_OPEN\(3\))340.17 48 R/F1 10/Times-Italic@0 SF -.37
+(re)108 84 S(ad).37 E F0(\(2\),).77 E F1(write)2.5 E F0(\(2\),).18 E F1(fr)2.5
+E(ee)-.37 E F0(\(3\), or).18 E F1(fsync)2.5 E F0(\(2\).).31 E(The)108 100.8 Q
+F1(del)2.52 E F0(,).51 E F1 -.1(ge)2.52 G(t).1 E F0(,).68 E F1(put)2.52 E F0
+(and)2.52 E F1(seq)2.52 E F0 .02(functions may f)2.52 F .02(ail and set)-.1 F
+F1(errno)2.52 E F0 .02(for an)2.52 F 2.52(yo)-.15 G 2.52(ft)376.3 100.8 S .02
+(he errors speci\214ed for the library func-)384.93 100.8 R(tions)108 112.8 Q
+F1 -.37(re)2.5 G(ad).37 E F0(\(2\),).77 E F1(write)2.5 E F0(\(2\),).18 E F1(fr)
+2.5 E(ee)-.37 E F0(\(3\) or).18 E F1(malloc)2.5 E F0(\(3\).).31 E(The)108 129.6
+Q F1(fd)2.5 E F0(functions will f)2.5 E(ail and set)-.1 E F1(errno)2.5 E F0
+(to ENOENT for in memory databases.)2.5 E(The)108 146.4 Q F1(sync)2.5 E F0
+(functions may f)2.5 E(ail and set)-.1 E F1(errno)2.5 E F0(for an)2.5 E 2.5(yo)
+-.15 G 2.5(ft)312.71 146.4 S(he errors speci\214ed for the library function)
+321.32 146.4 Q F1(fsync)2.5 E F0(\(2\).).31 E/F2 9/Times-Bold@0 SF(SEE ALSO)72
+163.2 Q F1(db_btr)108 175.2 Q(ee)-.37 E F0(\(3\),).18 E F1(db_hash)2.5 E F0
+(\(3\),).28 E F1(db_loc)2.5 E(k)-.2 E F0(\(3\),).67 E F1(db_lo)2.5 E(g)-.1 E F0
+(\(3\),).22 E F1(db_mpool)2.5 E F0(\(3\),).51 E F1(db_r)2.5 E(ecno)-.37 E F0
+(\(3\),).18 E F1(db_txn)2.5 E F0(\(3\)).24 E F2 -.09(BU)72 192 S(GS).09 E F0
+.106(The name DBT is a mnemonic for `)108 204 R .106(`data base thang')-.74 F
+.106(', and w)-.74 F .107(as used because noone could think of a reason-)-.1 F
+(able name that w)108 216 Q(asn')-.1 E 2.5(ta)-.18 G(lready in use some)202.14
+216 Q(where else.)-.25 E(The)108 232.8 Q F1(fd)2.5 E F0(function interf)2.5 E
+(ace is a kluge, and will be deleted in a future v)-.1 E(ersion of the interf)
+-.15 E(ace.)-.1 E(Only big and little endian byte order is supported.)108 249.6
+Q(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315
+(ution August)-.2 F(1, 1995)2.5 E(5)535 732 Q EP
+%%Page: 1 22
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 111.23(DB_RECNO\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 111.23(anual DB_RECNO\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)
+72 84 S(ME).18 E F0(db_recno \255 record number database access method)108 96 Q
+F1(DESCRIPTION)72 112.8 Q F0(speci\214c details of the recno access method.)108
+124.8 Q F1 -.495(AC)72 141.6 S(CESS METHOD SPECIFIC INFORMA).495 E(TION)-.855 E
+F0 2.497(The recno access method speci\214c data structure pro)108 153.6 R
+2.497(vided to)-.15 F/F2 10/Times-Italic@0 SF(db_open)4.997 E F0 2.497
+(is typedef)4.997 F 3.497 -.5('d a).55 H 2.497(nd named REC-).5 F 2.765
+(NOINFO. A)108 165.6 R .265(RECNOINFO structure has at least the follo)2.765 F
+.266(wing \214elds, which may be initialized before call-)-.25 F(ing)108 177.6
+Q F2(db_open)2.5 E F0(:).24 E(u_int8_t b)108 194.4 Q -.25(va)-.15 G(l;).25 E
+.793(The delimiting byte to be used to mark the end of a record for v)133 206.4
+R .793(ariable-length records, and the pad)-.25 F .386(character for \214x)133
+218.4 R .387(ed-length records.)-.15 F .387(If no v)5.387 F .387
+(alue is speci\214ed, ne)-.25 F .387(wlines \(`)-.25 F(`\\n')-.74 E .387
+('\) are used to mark the end)-.74 F(of v)133 230.4 Q
+(ariable-length records and \214x)-.25 E
+(ed-length records are padded with spaces.)-.15 E(char *bfname;)108 247.2 Q
+1.152(The recno access method stores the in-memory copies of its records in a \
+btree.)133 259.2 R 1.152(If bfname is non-)6.152 F .35(NULL, it speci\214es th\
+e name of the btree \214le, as if speci\214ed as the \214le name for a)133
+271.2 R F2(db_open)2.851 E F0 .351(of a btree)2.851 F(\214le.)133 283.2 Q
+(u_int cachesize;)108 300 Q 3.847(As)133 312 S 1.347
+(uggested maximum size, in bytes, of the memory cache.)147.957 312 R 1.347
+(This v)6.347 F 1.347(alue is)-.25 F/F3 10/Times-Bold@0 SF(only)3.847 E F0
+(advisory)3.847 E 3.846(,a)-.65 G 1.346(nd the)513.934 312 R .693
+(access method will allocate more memory rather than f)133 324 R 3.193(ail. If)
+-.1 F F2(cac)3.193 E(hesize)-.15 E F0 3.193(is 0)3.193 F .693
+(\(no size is speci\214ed\) a)3.193 F(def)133 336 Q(ault size is used.)-.1 E
+(u_long \215ags;)108 352.8 Q(The \215ag v)133 364.8 Q(alue is speci\214ed by)
+-.25 E F2(or)2.5 E F0('ing an).73 E 2.5(yo)-.15 G 2.5(ft)302.2 364.8 S
+(he follo)310.81 364.8 Q(wing v)-.25 E(alues:)-.25 E(R_FIXEDLEN)133 381.6 Q
+1.49(The records are \214x)158 393.6 R 1.489(ed-length, not byte delimited.)
+-.15 F 1.489(The structure element)6.489 F F2 -.37(re)3.989 G(clen).37 E F0
+1.489(speci\214es the)3.989 F .487
+(length of the record, and the structure element)158 405.6 R F2(bval)2.987 E F0
+.488(is used as the pad character)2.988 F 5.488(.A)-.55 G .788 -.15(ny r)
+495.232 405.6 T(ecords,).15 E(inserted into the database, that are less than)
+158 417.6 Q F2 -.37(re)2.5 G(clen).37 E F0
+(bytes long are automatically padded.)2.5 E(R_NOKEY)133 434.4 Q 1.146
+(In the interf)158 446.4 R 1.146(ace speci\214ed by)-.1 F F2(db_open)3.646 E F0
+3.646(,t).24 G 1.146(he sequential record retrie)320.816 446.4 R -.25(va)-.25 G
+3.646<6c8c>.25 G 1.145(lls in both the caller')449.31 446.4 R(s)-.55 E -.1(ke)
+158 458.4 S 4.795(ya)-.05 G 2.295(nd data structures.)181.425 458.4 R 2.295
+(If the R_NOKEY \215ag is speci\214ed, the)7.295 F F2(cur)4.795 E(sor)-.1 E F0
+2.295(functions are not)4.795 F .621(required to \214ll in the k)158 470.4 R
+.921 -.15(ey s)-.1 H 3.121(tructure. This).15 F .621
+(permits applications to retrie)3.121 F .92 -.15(ve r)-.25 H .62
+(ecords at the end of).15 F(\214les without reading all of the interv)158 482.4
+Q(ening records.)-.15 E(R_SN)133 499.2 Q(APSHO)-.35 E(T)-.4 E .029
+(This \215ag requires that a snapshot of the \214le be tak)158 511.2 R .029
+(en when)-.1 F F2(db_open)2.529 E F0 .029(is called, instead of permit-)2.529 F
+(ting an)158 523.2 Q 2.5(yu)-.15 G
+(nmodi\214ed records to be read from the original \214le.)197.85 523.2 Q
+(int lorder;)108 540 Q .65(The byte order for inte)133 552 R .65
+(gers in the stored database metadata.)-.15 F .65
+(The number should represent the order)5.65 F .748(as an inte)133 564 R .749
+(ger; for e)-.15 F .749(xample, big endian order w)-.15 F .749
+(ould be the number 4,321.)-.1 F(If)5.749 E F2(lor)3.249 E(der)-.37 E F0 .749
+(is 0 \(no order is)3.249 F(speci\214ed\) the current host order is used.)133
+576 Q(u_int psize;)108 592.8 Q .284(The recno access method stores the in-memo\
+ry copies of its records in a btree.)133 604.8 R .284(This v)5.284 F .283
+(alue is the size)-.25 F .297
+(\(in bytes\) of the pages used for nodes in that tree.)133 616.8 R(If)5.297 E
+F2(psize)2.797 E F0 .297(is 0 \(no page size is speci\214ed\) a page size)2.797
+F(is chosen based on the underlying \214le system I/O block size.)133 628.8 Q
+(See)5 E F2(btr)2.5 E(ee)-.37 E F0(\(3\) for more information.).18 E
+(size_t reclen;)108 645.6 Q(The length of a \214x)133 657.6 Q
+(ed-length record.)-.15 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)
+132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(1)535 732 Q EP
+%%Page: 2 23
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 111.23(DB_RECNO\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 111.23(anual DB_RECNO\(3\))340.17 48 R/F1 9/Times-Bold@0 SF
+(DB OPERA)72 84 Q(TIONS)-.855 E F0 .972(The data part of the k)108 96 R -.15
+(ey)-.1 G .971(/data pair used by the recno access method is the same as other\
+ access methods.).15 F .198(The k)108 108 R .498 -.15(ey i)-.1 H 2.698(sd).15 G
+(if)157.504 108 Q 2.698(ferent. The)-.25 F/F2 10/Times-Italic@0 SF(data)2.698 E
+F0 .198(\214eld of the k)2.698 F .499 -.15(ey s)-.1 H .199
+(hould be a pointer to a memory location of type).15 F F2 -.37(re)2.699 G
+(cno_t).37 E F0 2.699(,a).68 G(s)536.11 108 Q .506(de\214ned in the <db)108 120
+R .506(.h> include \214le.)-.4 F .506(This type is normally the lar)5.506 F
+.506(gest unsigned inte)-.18 F .506(gral type a)-.15 F -.25(va)-.2 G .505
+(ilable to the).25 F 2.5(implementation. The)108 132 R F2(size)2.5 E F0
+(\214eld of the k)2.5 E .3 -.15(ey s)-.1 H(hould be the size of that type.).15
+E 1.944(The record number data structure is either v)108 148.8 R 1.944
+(ariable or \214x)-.25 F 1.944
+(ed-length records stored in a \215at-\214le format,)-.15 F 1.856
+(accessed by the logical record number)108 160.8 R 6.856(.T)-.55 G 1.856(he e)
+285.206 160.8 R 1.856(xistence of record number \214v)-.15 F 4.356(er)-.15 G
+1.856(equires the e)440.442 160.8 R 1.856(xistence of)-.15 F .875
+(records one through four)108 172.8 R 3.375(,a)-.4 G .875
+(nd the deletion of record number one causes record number \214v)219.68 172.8 R
+3.376(et)-.15 G 3.376(ob)489.928 172.8 S 3.376(er)503.304 172.8 S(enum-)514.45
+172.8 Q .283(bered to record number four)108 184.8 R 2.783(,a)-.4 G 2.783(sw)
+231.195 184.8 S .283(ell as the cursor)245.088 184.8 R 2.783(,i)-.4 G 2.783(fp)
+316.64 184.8 S .282(ositioned after record number one, to shift do)327.753
+184.8 R .282(wn one)-.25 F 3.18(record. The)108 196.8 R .68
+(creation of record number \214v)3.18 F 3.18(ew)-.15 G .681
+(hen records one through four do not e)295.05 196.8 R .681
+(xist causes the logical)-.15 F(creation of them with zero-length data.)108
+208.8 Q .372(Because there is no meta-data associated with the underlying recn\
+o access method \214les, an)108 225.6 R 2.872(yc)-.15 G .372(hanges made)
+487.698 225.6 R .191(to the def)108 237.6 R .191(ault v)-.1 F .191
+(alues \(e.g. \214x)-.25 F .192(ed record length or byte separator v)-.15 F
+.192(alue\) must be e)-.25 F .192(xplicitly speci\214ed each time)-.15 F
+(the \214le is opened.)108 249.6 Q 1.037(The functions returned by)108 266.4 R
+F2(db_open)3.537 E F0 1.036(for the btree access method are as described in)
+3.536 F F2(db_open)3.536 E F0 1.036(\(3\), with the).24 F(follo)108 278.4 Q
+(wing e)-.25 E(xceptions and additions:)-.15 E 5.28(type The)108 295.2 R
+(type is DB_RECNO.)2.5 E 9.72(put Using)108 312 R(the)2.558 E F2(put)2.558 E F0
+(interf)2.559 E .059(ace to create a ne)-.1 F 2.559(wr)-.25 G .059
+(ecord will cause the creation of multiple, empty records if the)293.07 312 R
+(record number is more than one greater than the lar)133 324 Q
+(gest record currently in the database.)-.18 E(The)133 340.8 Q F2(put)2.5 E F0
+(function tak)2.5 E(es the follo)-.1 E(wing additional \215ags:)-.25 E
+(R_IAFTER)133 357.6 Q 1.225
+(Append the data immediately after the data referenced by)158 369.6 R F2 -.1
+(ke)3.724 G(y)-.2 E F0 3.724(,c).32 G 1.224(reating a ne)425.354 369.6 R 3.724
+(wk)-.25 G -.15(ey)490.046 369.6 S 1.224(/data pair).15 F(.)-.55 E
+(The record number of the appended k)158 381.6 Q -.15(ey)-.1 G
+(/data pair is returned in the).15 E F2 -.1(ke)2.5 G(y)-.2 E F0(structure.)2.5
+E(R_IBEFORE)133 398.4 Q 1.343
+(Insert the data immediately before the data referenced by)158 410.4 R F2 -.1
+(ke)3.844 G(y)-.2 E F0 3.844(,c).32 G 1.344(reating a ne)424.874 410.4 R 3.844
+(wk)-.25 G -.15(ey)489.926 410.4 S 1.344(/data pair).15 F(.)-.55 E
+(The record number of the inserted k)158 422.4 Q -.15(ey)-.1 G
+(/data pair is returned in the).15 E F2 -.1(ke)2.5 G(y)-.2 E F0(structure.)2.5
+E(R_SETCURSOR)133 439.2 Q(Store the k)158 451.2 Q -.15(ey)-.1 G(/data pair).15
+E 2.5(,s)-.4 G
+(etting or initializing the position of the cursor to reference it.)256.5 451.2
+Q 9.17(seq The)108 468 R F2(seq)2.5 E F0(function tak)2.5 E(es the follo)-.1 E
+(wing additional \215ags:)-.25 E(R_LAST)133 484.8 Q .04(The last k)158 496.8 R
+-.15(ey)-.1 G .04(/data pair of the database is returned, and the cursor is se\
+t or initialized to reference).15 F(it.)158 508.8 Q(R_PREV)133 525.6 Q(Retrie)
+158 537.6 Q .59 -.15(ve t)-.25 H .29(he k).15 F -.15(ey)-.1 G .29
+(/data pair immediately before the cursor).15 F 5.29(.I)-.55 G 2.79(ft)395.73
+537.6 S .29(he cursor is not yet set, this is the)404.63 537.6 R
+(same as the R_LAST \215ag.)158 549.6 Q .749
+(If the database \214le is a character special \214le and no complete k)133
+566.4 R -.15(ey)-.1 G .748(/data pairs are currently a).15 F -.25(va)-.2 G
+(ilable,).25 E(the)133 578.4 Q F2(seq)2.5 E F0(function returns 2.)2.5 E 4.17
+(sync The)108 595.2 R F2(sync)2.5 E F0(function tak)2.5 E(es the follo)-.1 E
+(wing additional \215ag:)-.25 E(R_RECNOSYNC)133 612 Q .643
+(This \215ag causes the)158 624 R F2(sync)3.143 E F0 .644
+(function to apply to the btree \214le which underlies the recno \214le, not)
+3.143 F .09(the recno \214le itself.)158 636 R .09(\(See the)5.09 F F2(bfname)
+2.59 E F0 .09(\214eld of RECNOINFO structure, abo)2.59 F -.15(ve)-.15 G 2.59
+(,f).15 G .09(or more informa-)470.95 636 R(tion.\))158 648 Q F1(ERR)72 664.8 Q
+(ORS)-.27 E F0(The)108 676.8 Q F2 -.37(re)3.731 G(cno).37 E F0 1.231
+(access method functions may f)3.731 F 1.231(ail and set)-.1 F F2(errno)3.731 E
+F0 1.231(for an)3.731 F 3.731(yo)-.15 G 3.731(ft)392.652 676.8 S 1.231
+(he errors speci\214ed for the library)402.493 676.8 R(function)108 688.8 Q F2
+(db_open)2.5 E F0(\(3\) or the follo).24 E(wing:)-.25 E(4.4 Berk)72 732 Q(ele)
+-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E
+(2)535 732 Q EP
+%%Page: 3 24
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 111.23(DB_RECNO\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 111.23(anual DB_RECNO\(3\))340.17 48 R([EINV)108 84 Q(AL])-1.35 E
+(An attempt w)133 96 Q(as made to add a record to a \214x)-.1 E
+(ed-length database that w)-.15 E(as too lar)-.1 E(ge to \214t.)-.18 E/F1 9
+/Times-Bold@0 SF(SEE ALSO)72 112.8 Q/F2 10/Times-Italic@0 SF(db_btr)108 124.8 Q
+(ee)-.37 E F0(\(3\),).18 E F2(db_hash)2.5 E F0(\(3\),).28 E F2(db_loc)2.5 E(k)
+-.2 E F0(\(3\),).67 E F2(db_lo)2.5 E(g)-.1 E F0(\(3\),).22 E F2(db_mpool)2.5 E
+F0(\(3\),).51 E F2(db_open)2.5 E F0(\(3\),).24 E F2(db_txn)2.5 E F0(\(3\)).24 E
+F2 2.755(Document Pr)108 148.8 R 2.755
+(ocessing in a Relational Database System)-.45 F F0 5.254(,M).32 G 2.754
+(ichael Stonebrak)362.134 148.8 R(er)-.1 E 5.254(,H)-.4 G 2.754(eidi Stettner)
+454.062 148.8 R 5.254(,J)-.4 G(oseph)516.67 148.8 Q
+(Kalash, Antonin Guttman, Nadene L)108 160.8 Q
+(ynn, Memorandum No. UCB/ERL M82/32, May 1982.)-.55 E F1 -.09(BU)72 177.6 S(GS)
+.09 E F0(The)108 189.6 Q F2(sync)3.616 E F0(function')3.616 E 3.616(sR)-.55 G
+1.116(_RECNOSYNC interf)198.838 189.6 R 1.117
+(ace is a kluge, and will be deleted in a future v)-.1 F 1.117(ersion of the)
+-.15 F(interf)108 201.6 Q(ace.)-.1 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G
+(istrib)132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(3)535 732 Q EP
+%%Page: 1 25
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.57(DB_TXN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.57(anual DB_TXN\(3\))340.17 48 R/F1 9/Times-Bold@0 SF -.18(NA)72
+84 S(ME).18 E F0(db_txn \255 transaction management functions)108 96 Q F1
+(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF(#include <db)108 124.8 Q(.h>)-.4 E
+(#include <db_lock.h>)108 136.8 Q(int)108 160.8 Q(txn_cr)108 172.8 Q
+(eate\(const char *path, mode_t mode, u_int maxtxns, u_int \215ags\);)-.18 E
+(TXNMGR *)108 196.8 Q(txn_open\(const char *path, DBT *logp, LOCK_T)108 208.8 Q
+(ABLE_T *lockp,)-.9 E(int \(*r)158 220.8 Q(eco)-.18 E -.1(ve)-.1 G
+(r\)\(DBT *lsn, DBT *log_entry).1 E 2.5(,i)-.55 G(nt isundo\)\);)340.11 220.8 Q
+(TXN *)108 244.8 Q(txn_begin\(TXNMGR *txnp\);)108 256.8 Q(int)108 280.8 Q
+(txn_commit\(TXN *tid\);)108 292.8 Q(int)108 316.8 Q(txn_pr)108 328.8 Q(epar)
+-.18 E(e\(TXN *tid\);)-.18 E(int)108 352.8 Q(txn_abort\(TXN *tid\);)108 364.8 Q
+(int)108 388.8 Q(txn_close\(TXNMGR *txnp\);)108 400.8 Q(int)108 424.8 Q
+(txn_unlink\(const char *path, int f)108 436.8 Q(or)-.25 E(ce\);)-.18 E F1
+(DESCRIPTION)72 453.6 Q F0(speci\214c details of the transaction support.)108
+465.6 Q/F3 10/Times-Italic@0 SF(Db_txn)108 482.4 Q F0 .034
+(is the library interf)2.534 F .034(ace that pro)-.1 F .034
+(vides transaction semantics.)-.15 F .034(Full transaction support is pro)5.034
+F .034(vided by a)-.15 F .722(collection of modules that pro)108 494.4 R .723
+(vide well de\214ned interf)-.15 F .723
+(aces to the services required for transaction process-)-.1 F 3.488(ing. These)
+108 506.4 R .988(services are reco)3.488 F -.15(ve)-.15 G .988(ry \(see).15 F
+F3(db_lo)3.488 E(g)-.1 E F0 .988(\(3\)\), concurrenc).22 F 3.488(yc)-.15 G .988
+(ontrol \(see)371.864 506.4 R F3(db_loc)3.487 E(k)-.2 E F0 .987
+(\(3\)\), and the manage-).67 F 2.201(ment of shared data \(see)108 518.4 R F3
+(db_mpool)4.701 E F0 4.701(\(3\)\). T).51 F 2.202
+(ransaction semantics can be applied to the access methods)-.35 F(described in)
+108 530.4 Q F3(db)2.5 E F0(\(3\) through function call parameters.).23 E .629(\
+The model intended for transactional use \(and that is used by the access meth\
+ods\) is that write-ahead log-)108 547.2 R .047(ging is pro)108 559.2 R .047
+(vided by)-.15 F F3(db_lo)2.547 E(g)-.1 E F0 .047
+(\(3\) to record both before- and after).22 F .048(-image logging.)-.2 F .048
+(Locking follo)5.048 F .048(ws a tw)-.25 F(o-phase)-.1 E
+(protocol and is implemented by)108 571.2 Q F3(db_loc)2.5 E(k)-.2 E F0(\(3\).)
+.67 E .549(The function)108 588 R F3(txn_cr)3.049 E(eate)-.37 E F0 .549
+(creates and initializes the transaction re)3.049 F .548
+(gion identi\214ed by the)-.15 F F3(path)3.048 E F0(directory)3.048 E 5.548(.T)
+-.65 G(his)528.33 588 Q .572(directory must already e)108 600 R .572(xist when)
+-.15 F F3(txn_cr)3.072 E(eate)-.37 E F0 .572(is called.)3.072 F .572
+(If the transaction re)5.572 F .572(gion identi\214ed by)-.15 F F3(path)3.072 E
+F0(already)3.072 E -.15(ex)108 612 S 1.78(ists, then).15 F F3(txn_cr)4.28 E
+(eate)-.37 E F0 1.78(returns success without further action.)4.28 F 1.78
+(The \214les associated with the transaction)6.78 F(re)108 624 Q .293
+(gion are created in the directory speci\214ed by)-.15 F F3(path)2.793 E F0
+5.293(.\().28 G .293(The group of the created \214les is based on the system)
+327.657 624 R .781(and directory def)108 636 R .781
+(aults, and is not further speci\214ed by)-.1 F F3(txn_cr)3.281 E(eate)-.37 E
+F0 3.281(.\) All).18 F .78(\214les created by)3.28 F F3(txn_cr)3.28 E(eate)-.37
+E F0 .78(are cre-)3.28 F .048(ated with mode)108 648 R F3(mode)2.548 E F0 .049
+(\(as described in)2.548 F F3 -.15(ch)2.549 G(mod).15 E F0 .049
+(\(2\)\) and modi\214ed by the process' umask v).77 F .049(alue \(see)-.25 F F3
+(umask)2.549 E F0(\(2\)\).).67 E(An)108 660 Q 2.5(yn)-.15 G(ecessary)132.57 660
+Q 2.5(,a)-.65 G(ssociated log and lock re)175.23 660 Q
+(gions are created as well \(see)-.15 E F3(db_lo)2.5 E(g)-.1 E F0(\(3\) and).22
+E F3(db_loc)2.5 E(k)-.2 E F0(\(3\)\).).67 E(The)108 676.8 Q F3(maxtxns)4.191 E
+F0(ar)4.191 E 1.691(gument speci\214es the maximum number of simultaneous tran\
+sactions that are supported.)-.18 F .229
+(This bounds the size of backing \214les and is used to deri)108 688.8 R .529
+-.15(ve l)-.25 H .229(imits for the size of the lock re).15 F .229
+(gion and log\214les.)-.15 F(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)
+132.57 732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(1)535 732 Q EP
+%%Page: 2 26
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.57(DB_TXN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.57(anual DB_TXN\(3\))340.17 48 R(When there are more than)108 84
+Q/F1 10/Times-Italic@0 SF(maxtxns)2.5 E F0(concurrent transactions, calls to)
+2.5 E F1(txn_be)2.5 E(gin)-.4 E F0(may f)2.5 E(ail.)-.1 E(Def)108 100.8 Q .847
+(ault locking and logging protocols are pro)-.1 F .846
+(vided only if the backing \214les e)-.15 F 3.346(xist. If)-.15 F .846
+(the backing \214les do)3.346 F 1.433(not e)108 112.8 R 1.433(xist, the)-.15 F
+F1<8d61>3.933 E(gs)-.1 E F0 1.434
+(parameter must indicate both a logging mode and locking mode speci\214ed by)
+3.933 F F1(or)3.934 E F0('ing).73 E(together at most one \215ag from each of t\
+he TXN_LOCK and TXN_LOG classes as follo)108 124.8 Q(ws:)-.25 E(TXN_LOCK_2PL)
+108 141.6 Q(Use tw)133 153.6 Q(o-phase locking.)-.1 E(TXN_LOCK_OPTIMISTIC)108
+170.4 Q(Use optimistic locking \(not currently implemented\).)133 182.4 Q
+(TXN_LOG_REDO)108 199.2 Q(Pro)133 211.2 Q
+(vide redo-only logging \(not currently implemented\).)-.15 E(TXN_LOG_UNDO)108
+228 Q(Pro)133 240 Q(vide undo-only logging \(not currently implemented\).)-.15
+E(TXN_LOG_UNDOREDO)108 256.8 Q(Pro)133 268.8 Q
+(vide undo/redo write-ahead logging.)-.15 E(The function)108 285.6 Q F1(txn_cr)
+2.5 E(eate)-.37 E F0(returns -1 on f)2.5 E(ailure, setting)-.1 E F1(errno)2.5 E
+F0 2.5(,a).18 G(nd 0 on success.)351.83 285.6 Q 1.892(The function)108 302.4 R
+F1(txn_open)4.392 E F0 1.892(returns a pointer to the transaction re)4.392 F
+1.892(gion identi\214ed by)-.15 F F1(path)4.392 E F0 4.392(,w).28 G 1.892
+(hich must ha)476.016 302.4 R -.15(ve)-.2 G .239
+(already been created by a call to)108 314.4 R F1(txn_cr)2.739 E(eate)-.37 E F0
+5.239(.T).18 G .239(he process must ha)296.88 314.4 R .539 -.15(ve p)-.2 H .239
+(ermission to read and write \214les with).15 F -.25(ow)108 326.4 S .327
+(ners, groups and permissions as described for).25 F F1(txn_cr)2.826 E(eate)
+-.37 E F0 5.326(.T).18 G(he)362.624 326.4 Q F1(txn_open)2.826 E F0 .326
+(function returns NULL on f)2.826 F(ail-)-.1 E(ure, setting)108 338.4 Q F1
+(errno)2.5 E F0(.).18 E(The)108 355.2 Q F1 -.37(re)3.181 G(co).37 E(ver)-.1 E
+F0(ar)3.181 E .681(gument speci\214es a function that is called by)-.18 F F1
+(txn_abort)3.181 E F0 .682(during transaction abort.)3.182 F .682(This func-)
+5.682 F(tion tak)108 367.2 Q(es three ar)-.1 E(guments:)-.18 E 10.83(lsn A)108
+384 R(log sequence number \(LSN\).)2.5 E(log_entry)108 400.8 Q 2.5(Al)133 412.8
+S(og record.)145.5 412.8 Q(isundo)108 429.6 Q(An undo \215ag set to 0 if the o\
+peration is a redo and set to 1 if the operation an undo.)133 441.6 Q 1.498
+(As discussed in the)108 458.4 R F1(db_lo)3.998 E 3.998(g\()-.1 G(3\))228.44
+458.4 Q F0 1.497(manual page, the application is responsible for pro)3.997 F
+1.497(viding an)-.15 F 3.997(yn)-.15 G(ecessary)506.13 458.4 Q .486
+(structure to the log record.)108 470.4 R -.15(Fo)5.486 G 2.986(re).15 G .487
+(xample, the application must understand what part of the log record is an)
+242.256 470.4 R(operation code, what part is redo information, and what part i\
+s undo information.)108 482.4 Q(The)108 499.2 Q F1(txn_be)2.785 E(gin)-.4 E F0
+.285(function creates a ne)2.785 F 2.784(wt)-.25 G .284
+(ransaction in the designated transaction manager)264.018 499.2 R 2.784(,r)-.4
+G .284(eturning a pointer)468.332 499.2 R
+(to a TXN that uniquely identi\214es it.)108 511.2 Q(The)108 528 Q F1
+(txn_commit)2.615 E F0 .115(function ends the transaction speci\214ed by the)
+2.615 F F1(tid)2.615 E F0(ar)2.615 E 2.615(gument. An)-.18 F 2.615(yl)-.15 G
+.115(ocks held by the transac-)440.12 528 R(tion are released.)108 540 Q
+(If logging is enabled, a commit log record is written and \215ushed to disk.)5
+E(The)108 556.8 Q F1(txn_abort)2.889 E F0 .389
+(function causes an abnormal termination of the transaction.)2.889 F .388
+(If logging is enabled, the log is)5.389 F 2.312(played backw)108 568.8 R 2.312
+(ards and an)-.1 F 4.812(yr)-.15 G(eco)228.628 568.8 Q -.15(ve)-.15 G 2.312
+(ry operations are initiated through the).15 F F1 -.37(re)4.813 G(co).37 E(ver)
+-.1 E F0 2.313(function speci\214ed to)4.813 F F1(txn_open)108 580.8 Q F0 5(.A)
+.24 G(fter reco)159.62 580.8 Q -.15(ve)-.15 G
+(ry is completed, all locks held by the transaction are released.).15 E(The)108
+597.6 Q F1(txn_close)3.824 E F0 1.323
+(function detaches a process from the transaction en)3.823 F 1.323
+(vironment speci\214ed by the TXNMGR)-.4 F(pointer)108 609.6 Q 5.261(.A)-.55 G
+.261(ll mapped re)150.761 609.6 R .261(gions are unmapped and an)-.15 F 2.761
+(ya)-.15 G .262(llocated resources are freed.)323.638 609.6 R(An)5.262 E 2.762
+(yu)-.15 G .262(ncommitted trans-)466.688 609.6 R(actions are aborted.)108
+621.6 Q .69(The function)108 638.4 R F1(txn_unlink)3.19 E F0(destro)3.19 E .69
+(ys the transaction re)-.1 F .69(gion identi\214ed by the directory)-.15 F F1
+(path)3.19 E F0 3.19(,r).28 G(emo)472.1 638.4 Q .69(ving all \214les)-.15 F
+1.78(used to implement the transaction re)108 650.4 R 4.28(gion. \(The)-.15 F
+(directory)4.28 E F1(path)4.28 E F0 1.78(is not remo)4.28 F -.15(ve)-.15 G 4.28
+(d.\) If).15 F 1.78(there are processes)4.28 F .553(which ha)108 662.4 R .853
+-.15(ve c)-.2 H(alled).15 E F1(txn_open)3.052 E F0 .552(without calling)3.052 F
+F1(txn_close)3.052 E F0 .552
+(\(i.e., there are processes currently using the transac-)3.052 F .135(tion re)
+108 674.4 R(gion\),)-.15 E F1(txn_unlink)2.635 E F0 .135(will f)2.635 F .135
+(ail without further action, unless the force \215ag is set, in which case)-.1
+F F1(txn_unlink)2.636 E F0 1.67(will attempt to delete the transaction re)108
+686.4 R 1.67(gion \214les re)-.15 F -.05(ga)-.15 G 1.67(rdless of an).05 F 4.17
+(yp)-.15 G 1.67(rocesses still using the transaction)397.22 686.4 R(4.4 Berk)72
+732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315(ution August)-.2 F
+(1, 1995)2.5 E(2)535 732 Q EP
+%%Page: 3 27
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.57(DB_TXN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.57(anual DB_TXN\(3\))340.17 48 R(re)108 84 Q 2.996(gion. An)-.15
+F 2.996(ya)-.15 G .496(ccesses to a remo)165.902 84 R -.15(ve)-.15 G 2.997(dt)
+.15 G .497(ransaction re)257.007 84 R .497(gion will lik)-.15 F .497
+(ely result in une)-.1 F .497(xpected beha)-.15 F(vior)-.2 E 5.497(.T)-.55 G
+.497(he func-)506.463 84 R(tion)108 96 Q/F1 10/Times-Italic@0 SF(txn_unlink)2.5
+E F0(returns -1 on f)2.5 E(ailure, setting)-.1 E F1(errno)2.5 E F0 2.5(,a).18 G
+(nd 0 on success.)316.39 96 Q .51(In the case of catastrophic or system f)108
+112.8 R .51(ailure, it is possible to clean up a transaction re)-.1 F .51
+(gion by remo)-.15 F .51(ving all)-.15 F .34
+(of the \214les in the directory speci\214ed to the)108 124.8 R F1(txn_cr)2.841
+E(eate)-.37 E F0 .341(function, as transaction re)2.841 F .341
+(gion \214les are ne)-.15 F -.15(ve)-.25 G 2.841(rc).15 G(reated)515.57 124.8 Q
+(in an)108 136.8 Q 2.5(yd)-.15 G(irectory other than the one speci\214ed to)
+140.07 136.8 Q F1(txn_cr)2.5 E(eate)-.37 E F0(.).18 E(The)108 153.6 Q F1
+(txn_pr)3.42 E(epar)-.37 E(e)-.37 E F0 .92(function initiates the be)3.42 F
+.919(ginning of a tw)-.15 F 3.419(op)-.1 G .919(hase commit.)352.206 153.6 R
+.919(In a distrib)5.919 F .919(uted transaction, the)-.2 F .185
+(prepare directi)108 165.6 R .485 -.15(ve s)-.25 H .185
+(hould be issued to all participating transaction managers.).15 F .185
+(Each manager must tak)5.185 F 2.685(ew)-.1 G(hat-)524.45 165.6 Q -2.15 -.25
+(ev e)108 177.6 T 2.5(ra).25 G
+(ction is necessary to guarantee that a future call to)131.75 177.6 Q F1
+(txn_commit)2.5 E F0(on the speci\214ed)2.5 E F1(tid)2.5 E F0(will succeed.)2.5
+E/F2 9/Times-Bold@0 SF(SYSTEM INTEGRA)72 194.4 Q(TION)-.855 E F0 .28
+(This model can be applied to data bases other than the pro)108 206.4 R .279
+(vided access methods.)-.15 F -.15(Fo)5.279 G 2.779(re).15 G .279
+(xample, consider an)459.182 206.4 R .15(application that pro)108 218.4 R .15
+(vides transaction semantics to data stored in re)-.15 F .15
+(gular \214les accessed using the)-.15 F F1 -.37(re)2.65 G(ad).37 E F0 .15
+(\(2\) and).77 F F1(write)108 230.4 Q F0 .708(\(2\) system calls.).18 F .707
+(The operations for which transaction protection is desired are brack)5.708 F
+.707(eted by calls to)-.1 F F1(txn_be)108 242.4 Q(gin)-.4 E F0(and)2.5 E F1
+(txn_commit)2.5 E F0(.).68 E .606
+(Before data are referenced, a call is made to the lock manager)108 259.2 R(,)
+-.4 E F1(db_loc)3.106 E(k)-.2 E F0 3.106(,f).67 G .606
+(or a lock of the appropriate type)408.064 259.2 R .719
+(\(e.g. read\) on the object being lock)108 271.2 R 3.218(ed. The)-.1 F .718
+(object might be a page in the \214le, a byte, a range of bytes, or)3.218 F
+.572(some k)108 283.2 R -.15(ey)-.1 G 5.572(.B)-.5 G .573
+(efore a write is performed, the application mak)160.464 283.2 R .573
+(es a call to the log manager)-.1 F(,)-.4 E F1(db_lo)3.073 E(g)-.1 E F0 3.073
+(,t).22 G 3.073(or)506.387 283.2 S(ecord)517.79 283.2 Q .522
+(enough information to redo the operation in case of f)108 295.2 R .522
+(ailure after commit and to undo the operation in case)-.1 F .609(of abort.)108
+307.2 R .609
+(After the log message is written, the write system calls are issued.)5.609 F
+.61(After all requests are issued,)5.61 F .518(the application calls)108 319.2
+R F1(txn_commit)3.017 E F0 5.517(.W).68 G(hen)256.84 319.2 Q F1(txn_commit)
+3.017 E F0 .517(returns, the caller is guaranteed that all necessary log)3.017
+F(writes ha)108 331.2 Q .3 -.15(ve b)-.2 H(een written to disk.).15 E 1.081
+(At an)108 348 R 3.581(yt)-.15 G 1.081(ime, the application may call)142.232
+348 R F1(txn_abort)3.581 E F0 3.581(,w).68 G 1.081
+(hich will result in the appropriate calls to the)318.828 348 R F1 -.37(re)
+3.582 G(co).37 E(ver)-.1 E F0 .278(routine to restore the `)108 360 R
+(`database')-.74 E 2.778('t)-.74 G 2.778(oac)246.48 360 S .278
+(onsistent pre-transaction state.)265.916 360 R .277(\(The reco)5.277 F -.15
+(ve)-.15 G 2.777(rr).15 G .277(outine must be able to)450.562 360 R
+(either reapply or undo the update depending on the conte)108 372 Q
+(xt, for each dif)-.15 E(ferent type of log record.\))-.25 E .746
+(If the application should crash, the reco)108 388.8 R -.15(ve)-.15 G .746
+(ry process uses the).15 F F1(db_lo)3.246 E(g)-.1 E F0(interf)3.246 E .746
+(ace to read the log and call the)-.1 F F1 -.37(re)108 400.8 S(co).37 E(ver)-.1
+E F0(routine to restore the database to a consistent state.)2.5 E(The)108 417.6
+Q F1(txn_pr)3.098 E(epar)-.37 E(e)-.37 E F0 .598(function pro)3.098 F .598
+(vides the core functionality to implement distrib)-.15 F .597
+(uted transactions, b)-.2 F .597(ut it does)-.2 F .36
+(not actually manage the noti\214cation of distrib)108 429.6 R .36
+(uted transaction managers.)-.2 F .36(The caller is responsible for issu-)5.36
+F(ing)108 441.6 Q F1(txn_pr)2.82 E(epar)-.37 E(e)-.37 E F0 .32
+(calls to all sites participating in the transaction.)2.82 F .319
+(If all responses are positi)5.319 F -.15(ve)-.25 G 2.819(,t).15 G .319
+(he caller can)488.832 441.6 R .822(issue a)108 453.6 R F1(txn_commit)3.322 E
+F0 5.822(.I).68 G 3.322(fa)198.076 453.6 S 1.122 -.15(ny o)209.168 453.6 T
+3.322(ft).15 G .822(he responses are ne)236.772 453.6 R -.05(ga)-.15 G(ti).05 E
+-.15(ve)-.25 G 3.322(,t).15 G .823(he caller should issue a)349.15 453.6 R F1
+(txn_abort)3.323 E F0 5.823(.I).68 G 3.323(ng)499.747 453.6 S(eneral,)513.07
+453.6 Q(the)108 465.6 Q F1(txn_pr)2.5 E(epar)-.37 E(e)-.37 E F0
+(call requires that the transaction log be \215ushed to disk.)2.5 E .821
+(The structure of the transaction support allo)108 482.4 R .821
+(ws application designers to trade of)-.25 F 3.32(fp)-.25 G .82
+(erformance and protec-)445.07 482.4 R 3.948(tion. Since)108 494.4 R 1.448
+(DB manages man)3.948 F 3.948(ys)-.15 G 1.448(tructures in shared memory)245.36
+494.4 R 3.948(,i)-.65 G 1.448(ts information is subject to corruption by)
+367.982 494.4 R 1.306(applications when the library is link)108 506.4 R 1.306
+(ed directly with the application.)-.1 F -.15(Fo)6.306 G 3.805(rt).15 G 1.305
+(his reason, DB is designed to)416.815 506.4 R(allo)108 518.4 Q 3.367(wc)-.25 G
+.867(ompilation into a separate serv)137.777 518.4 R .868
+(er process that may be accessed via a sock)-.15 F .868(et interf)-.1 F 3.368
+(ace. In)-.1 F .868(this w)3.368 F(ay)-.1 E(DB')108 530.4 Q 2.828(sd)-.55 G
+.328(ata structures are protected from application code, b)136.388 530.4 R .328
+(ut communication o)-.2 F -.15(ve)-.15 G .327(rhead is increased.).15 F(When)
+5.327 E(applications are trusted, DB may be compiled directly into the applica\
+tion for increased performance.)108 542.4 Q F2(ERR)72 559.2 Q(ORS)-.27 E F0
+(The)108 571.2 Q F1(txn_cr)4.113 E(eate)-.37 E F0 1.613(function may f)4.113 F
+1.613(ail and set)-.1 F F1(errno)4.113 E F0 1.614(for an)4.113 F 4.114(yo)-.15
+G 4.114(ft)349.022 571.2 S 1.614
+(he errors speci\214ed for the library functions)359.246 571.2 R F1(open)108
+583.2 Q F0(\(2\),).24 E F1(write)2.5 E F0(\(2\),).18 E F1(malloc)2.5 E F0
+(\(3\),).31 E F1(loc)2.5 E(k_cr)-.2 E(eate)-.37 E F0(\(3\), and).18 E F1(lo)2.5
+E(g_cr)-.1 E(eate)-.37 E F0(\(3\).).18 E(The)108 600 Q F1(txn_open)2.509 E F0
+.009(function may f)2.509 F .009(ail and set)-.1 F F1(errno)2.508 E F0 .008
+(to an)2.508 F 2.508(yo)-.15 G 2.508(ft)323.916 600 S .008
+(he errors speci\214ed for the library functions)332.534 600 R F1(open)2.508 E
+F0(\(2\),).24 E F1(write)108 612 Q F0(\(2\),).18 E F1(malloc)2.5 E F0(\(3\),)
+.31 E F1(loc)2.5 E(k_open)-.2 E F0(\(3\), and).24 E F1(lo)2.5 E(g_open)-.1 E F0
+(\(3\).).24 E(The)108 628.8 Q F1(txn_be)2.671 E(gin)-.4 E F0 .171
+(function may f)2.671 F .171(ail and set)-.1 F F1(errno)2.671 E F0 .171
+(to ENOSPC indicating that the maximum number of concur)2.671 F(-)-.2 E
+(rent transactions has been reached.)108 640.8 Q(The)108 657.6 Q F1(txn_commit)
+2.5 E F0(function may f)2.5 E(ail and set)-.1 E F1(errno)2.5 E F0(to EINV)2.5 E
+(AL indicating that the transaction w)-1.35 E(as aborted.)-.1 E(The)108 674.4 Q
+F1(txn_close)4.582 E F0 2.082(function may f)4.582 F 2.081(ail and set)-.1 F F1
+(errno)4.581 E F0 2.081(to an)4.581 F 4.581(yo)-.15 G 4.581(ft)345.753 674.4 S
+2.081(he errors speci\214ed for the library functions)356.444 674.4 R F1(close)
+108 686.4 Q F0(\(2\),).18 E F1 -.37(re)2.5 G(ad).37 E F0(\(2\),).77 E F1(write)
+2.5 E F0(\(2\),).18 E F1(fr)2.5 E(ee)-.37 E F0(\(3\),).18 E F1(fsync)2.5 E F0
+(\(2\),).31 E F1(loc)2.5 E(k_close)-.2 E F0(\(3\) or).18 E F1(lo)2.5 E(g_close)
+-.1 E F0(\(3\).).18 E(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57
+732 Q 99.315(ution August)-.2 F(1, 1995)2.5 E(3)535 732 Q EP
+%%Page: 4 28
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF 124.57(DB_TXN\(3\) BSD)72 48 R(Programmer')2.5 E 2.5
+(sM)-.55 G 124.57(anual DB_TXN\(3\))340.17 48 R(The)108 84 Q/F1 10
+/Times-Italic@0 SF(txn_unlink)4.319 E F0 1.819(function may f)4.319 F 1.819
+(ail and set)-.1 F F1(errno)4.319 E F0 1.819(to an)4.319 F 4.319(yo)-.15 G 4.32
+(ft)347.58 84 S 1.82(he errors speci\214ed for the library functions)358.01 84
+R F1(unlink)108 96 Q F0(\(2\),).67 E F1(loc)2.5 E(k_unlink)-.2 E F0(\(3\), and)
+.67 E F1(lo)2.5 E(g_unlink)-.1 E F0(\(3\), or the follo).67 E(wing:)-.25 E([EB)
+108 112.8 Q(USY])-.1 E(The transaction re)133 124.8 Q(gion w)-.15 E
+(as in use and the force \215ag w)-.1 E(as not set.)-.1 E/F2 9/Times-Bold@0 SF
+(SEE ALSO)72 141.6 Q F1(db_btr)108 153.6 Q(ee)-.37 E F0(\(3\),).18 E F1
+(db_hash)2.5 E F0(\(3\),).28 E F1(db_loc)2.5 E(k)-.2 E F0(\(3\),).67 E F1
+(db_lo)2.5 E(g)-.1 E F0(\(3\),).22 E F1(db_mpool)2.5 E F0(\(3\),).51 E F1
+(db_open)2.5 E F0(\(3\),).24 E F1(db_r)2.5 E(ecno)-.37 E F0(\(3\)).18 E F1 .904
+(LIBTP: P)108 177.6 R(ortable)-.8 E 3.404(,M)-.1 G .904(odular T)189.738 177.6
+R -.15(ra)-.55 G .904(nsactions for UNIX).15 F F0 3.404(,M).94 G(ar)328.884
+177.6 Q .904(go Seltzer)-.18 F 3.403(,M)-.4 G .903
+(ichael Olson, USENIX proceedings,)392.041 177.6 R -.4(Wi)108 189.6 S
+(nter 1992.).4 E F2 -.09(BU)72 206.4 S(GS).09 E F0(The)108 218.4 Q F1(maxtxns)
+2.792 E F0 .292(parameter is a kluge, and should be deleted in f)2.792 F -.2
+(avo)-.1 G 2.793(ro).2 G 2.793(fd)378.448 218.4 S .293(ynamically e)389.571
+218.4 R .293(xpanding the transaction)-.15 F(re)108 230.4 Q(gion.)-.15 E
+(4.4 Berk)72 732 Q(ele)-.1 E 2.5(yD)-.15 G(istrib)132.57 732 Q 99.315
+(ution August)-.2 F(1, 1995)2.5 E(4)535 732 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db_btree.3 b/mechglue/src/plugins/kdb/db2/libdb2/man/db_btree.3
new file mode 100644
index 000000000..25e289f3c
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db_btree.3
@@ -0,0 +1,246 @@
+.\" Copyright (c) 1990, 1993, 1994, 1995
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)db_btree.3	8.11 (Berkeley) 8/1/95
+.\"
+.TH DB_BTREE 3 "August 1, 1995"
+.UC 7
+.SH NAME
+db_btree \- btree database access method
+.SH DESCRIPTION
+.so db.so
+.GN
+specific details of the btree access method.
+.PP
+The btree data structure is a sorted, balanced tree structure storing
+associated key/data pairs.
+Searches, insertions, and deletions in the btree will all complete in
+O lg base N where base is the average fill factor.
+Often, inserting ordered data into btrees results in a low fill factor.
+This implementation has been modified to make ordered insertion the best
+case, resulting in a much better than normal page fill factor.
+.SH "ACCESS METHOD SPECIFIC INFORMATION"
+The btree access method specific data structure provided to
+.I db_open
+is typedef'd and named BTREEINFO.
+A BTREEINFO structure has at least the following fields,
+which may be initialized before calling
+.IR db_open :
+.TP 5
+u_int cachesize;
+A suggested maximum size (in bytes) of the memory cache.
+This value is
+.B only
+advisory, and the access method will allocate more memory rather than fail.
+Since every search examines the root page of the tree, caching the most
+recently used pages substantially improves access time.
+In addition, physical writes are delayed as long as possible, so a moderate
+cache can reduce the number of I/O operations significantly.
+Obviously, using a cache increases (but only increases) the likelihood of
+corruption or lost data if the system crashes while a tree is being modified.
+If
+.I cachesize
+is 0 (no size is specified) a default cache is used.
+.TP 5
+int (*compare)(const DBT *, const DBT *);
+Compare is the key comparison function.
+It must return an integer less than, equal to, or greater than zero if the
+first key argument is considered to be respectively less than, equal to,
+or greater than the second key argument.
+The same comparison function must be used on a given tree every time it
+is opened.
+If
+.I compare
+is NULL (no comparison function is specified), the keys are compared
+lexically, with shorter keys considered less than longer keys.
+.TP 5
+u_long flags;
+The flag value is specified by
+.IR or 'ing
+any of the following values:
+.RS
+.TP 5
+R_DUP
+Permit duplicate keys in the tree, i.e. permit insertion if the key to be
+inserted already exists in the tree.
+The default behavior, as described in
+.IR db_open (3),
+is to overwrite a matching key when inserting a new key or to fail if
+the R_NOOVERWRITE flag is specified.
+The R_DUP flag is overridden by the R_NOOVERWRITE flag, and if the
+R_NOOVERWRITE flag is specified, attempts to insert duplicate keys into
+the tree will fail.
+.IP
+If the database contains duplicate keys, the order of retrieval of
+key/data pairs is undefined if the
+.I get
+function is used, however,
+.I seq
+function calls with the R_CURSOR flag set will always return the logical
+``first'' of any group of duplicate keys.
+.RE
+.TP 5
+int lorder;
+The byte order for integers in the stored database metadata.
+The number should represent the order as an integer; for example, 
+big endian order would be the number 4,321.
+If
+.I lorder
+is 0 (no order is specified) the current host order is used.
+.TP 5
+int maxkeypage;
+The maximum number of keys which will be stored on any single page.
+This functionality is not currently implemented.
+.\" The maximum number of keys which will be stored on any single page.
+.\" Because of the way the btree data structure works,
+.\" .I maxkeypage
+.\" must always be greater than or equal to 2.
+.\" If
+.\" .I maxkeypage
+.\" is 0 (no maximum number of keys is specified) the page fill factor is
+.\" made as large as possible (which is almost invariably what is wanted).
+.TP 5
+int minkeypage;
+The minimum number of keys which will be stored on any single page.
+This value is used to determine which keys will be stored on overflow
+pages, i.e. if a key or data item is longer than the pagesize divided
+by the minkeypage value, it will be stored on overflow pages instead
+of in the page itself.
+If
+.I minkeypage
+is 0 (no minimum number of keys is specified) a value of 2 is used.
+.TP 5
+size_t (*prefix)(const DBT *, const DBT *);
+Prefix is the prefix comparison function.
+If specified, this function must return the number of bytes of the second key
+argument which are necessary to determine that it is greater than the first
+key argument.
+If the keys are equal, the key length should be returned.
+Note, the usefulness of this function is very data dependent, but, in some
+data sets can produce significantly reduced tree sizes and search times.
+If
+.I prefix
+is NULL (no prefix function is specified),
+.B and
+no comparison function is specified, a default lexical comparison function
+is used.
+If
+.I prefix
+is NULL and a comparison function is specified, no prefix comparison is
+done.
+.TP 5
+u_int psize;
+Page size is the size (in bytes) of the pages used for nodes in the tree.
+The minimum page size is 512 bytes and the maximum page size is 64K.
+If
+.I psize
+is 0 (no page size is specified) a page size is chosen based on the
+underlying file system I/O block size.
+.PP
+If the file already exists (and the O_TRUNC flag is not specified), the
+values specified for the parameters flags, lorder and psize are ignored
+in favor of the values used when the tree was created.
+.SH "DB OPERATIONS"
+The functions returned by
+.I db_open
+for the btree access method are as described in
+.IR db_open (3),
+with the following exceptions and additions:
+.TP 5
+type
+The type is DB_BTREE.
+.TP 5
+del
+Space freed up by deleting key/data pairs from the tree is never reclaimed,
+although it is reused where possible.
+This means that the btree storage structure is grow-only.
+The only solutions are to avoid excessive deletions, or to create a fresh
+tree periodically from a scan of an existing one.
+.TP 5
+put
+The
+.I put
+function takes the following additional flags:
+.RS
+.TP 5
+R_SETCURSOR
+Store the key/data pair, setting or initializing the position of the
+cursor to reference it.
+.RE
+.TP 5
+seq
+Forward sequential scans of a tree are from the least key to the greatest.
+.IP
+The returned key for the
+.I seq
+function is not necessarily an exact match for the specified key in
+the btree access method.
+The returned key is the smallest key greater than or equal to the
+specified key, permitting partial key matches and range searches.
+.IP
+The
+.I seq
+function takes the following additional flags:
+.RS
+.TP 5
+R_LAST
+The last key/data pair of the database is returned, and the cursor
+is set or initialized to reference it.
+.TP 5
+R_PREV
+Retrieve the key/data pair immediately before the cursor.
+If the cursor is not yet set, this is the same as the R_LAST flag.
+.RE
+.SH ERRORS
+The
+.I btree
+access method functions may fail and set
+.I errno
+for any of the errors specified for the library function
+.IR db_open (3).
+.SH "SEE ALSO"
+.IR db_hash (3),
+.IR db_lock (3),
+.IR db_log (3),
+.IR db_mpool (3),
+.IR db_open (3),
+.IR db_recno (3),
+.IR db_txn (3)
+.sp
+.IR "The Ubiquitous B-tree" ,
+Douglas Comer, ACM Comput. Surv. 11, 2 (June 1979), 121-138.
+.sp
+.IR "Prefix B-trees" ,
+Bayer and Unterauer, ACM Transactions on Database Systems, Vol. 2, 1
+(March 1977), 11-26.
+.sp
+.IR "The Art of Computer Programming Vol. 3: Sorting and Searching" , 
+D.E. Knuth, 1968, pp 471-480.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db_hash.3 b/mechglue/src/plugins/kdb/db2/libdb2/man/db_hash.3
new file mode 100644
index 000000000..adb88fca7
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db_hash.3
@@ -0,0 +1,138 @@
+.\" Copyright (c) 1990, 1993, 1994, 1995
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)db_hash.3	8.13 (Berkeley) 8/1/95
+.\"
+.TH DB_HASH 3 "August 1, 1995"
+.UC 7
+.SH NAME
+db_hash \- hash database access method
+.SH DESCRIPTION
+.so db.so
+.GN
+specific details of the hashing access method.
+.PP
+The hash data structure is an extensible, dynamic hashing scheme.
+Backward compatible interfaces to the functions described in
+.IR dbm (3),
+and
+.IR ndbm (3)
+are provided, however these interfaces are not compatible with
+previous file formats.
+.SH "ACCESS METHOD SPECIFIC INFORMATION"
+The hash access method specific data structure provided to
+.I db_open
+is typedef'd and named HASHINFO.
+A HASHINFO structure has at least the following fields,
+which may be initialized before calling
+.IR db_open :
+.TP 5
+u_int bsize;
+.I Bsize
+defines the hash table bucket size, and is, by default, 256 bytes.
+It may be preferable to increase the page size for disk-resident tables
+and tables with large data items.
+.TP 5
+u_int cachesize;
+A suggested maximum size, in bytes, of the memory cache.
+This value is
+.B only
+advisory, and the access method will allocate more memory rather
+than fail.
+.TP 5
+u_int ffactor;
+.I Ffactor
+indicates a desired density within the hash table.
+It is an approximation of the number of keys allowed to accumulate in any
+one bucket, determining when the hash table grows or shrinks.
+The default value is 8.
+.TP 5
+u_int32_t (*hash)(const void *, size_t);
+.I Hash
+is a user defined hash function.
+Since no hash function performs equally well on all possible data, the
+user may find that the built-in hash function does poorly on a particular
+data set.
+User specified hash functions must take two arguments (a pointer to a byte
+string and a length) and return a 32-bit quantity to be used as the hash
+value.
+.IP
+If a hash function is specified,
+.I hash_open
+will attempt to determine if the hash function specified is the same as
+the one with which the database was created, and will fail if it is not.
+.TP 5
+int lorder;
+The byte order for integers in the stored database metadata.
+The number should represent the order as an integer; for example, 
+big endian order would be the number 4,321.
+If
+.I lorder
+is 0 (no order is specified) the current host order is used.
+If the  file already exists, the specified value is ignored and the
+value specified when the tree was created is used.
+.TP 5
+u_int nelem;
+.I Nelem
+is an estimate of the final size of the hash table.
+If not set or set too low, hash tables will expand gracefully as keys
+are entered, although a slight performance degradation may be noticed.
+The default value is 1.
+.PP
+If the file already exists (and the O_TRUNC flag is not specified), the
+values specified for the parameters bsize, ffactor, lorder and nelem are
+ignored and the values specified when the tree was created are used.
+.SH "DB OPERATIONS"
+The functions returned by
+.I db_open
+for the hash access method are as described in
+.IR db_open (3).
+.SH ERRORS
+The
+.I hash
+access method functions may fail and set
+.I errno
+for any of the errors specified for the library function
+.IR db_open (3).
+.SH "SEE ALSO"
+.IR db_btree (3),
+.IR db_lock (3),
+.IR db_log (3),
+.IR db_mpool (3),
+.IR db_open (3),
+.IR db_recno (3),
+.IR db_txn (3)
+.sp
+.IR "Dynamic Hash Tables" ,
+Per-Ake Larson, Communications of the ACM, April 1988.
+.sp
+.IR "A New Hash Package for UNIX" ,
+Margo Seltzer, USENIX Proceedings, Winter 1991.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db_lock.3 b/mechglue/src/plugins/kdb/db2/libdb2/man/db_lock.3
new file mode 100644
index 000000000..b18a38c60
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db_lock.3
@@ -0,0 +1,462 @@
+.\" Copyright (c) 1994, 1995
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)db_lock.3	8.14 (Berkeley) 8/1/95
+.\"
+.TH DB_LOCK 3 "August 1, 1995"
+.UC 7
+.SH NAME
+db_lock \- general purpose lock manager
+.SH SYNOPSIS
+.nf
+.ft B
+#include <db_lock.h>
+
+int
+lock_create(const char *path, mode_t mode,
+.ti +5
+int lock_modes, const int8_t conflicts[][], u_int maxlocks);
+
+LOCK_TABLE_T *
+lock_open(const char *path);
+
+int
+lock_vec(LOCK_TABLE_T *lt, DBT *locker, struct timespec *timeout,
+.ti +5
+LOCK_REQ_T list[], int nlist, LOCK_REQ_T **elistp, DBT *conflict);
+
+int
+lock_get(LOCK_TABLE_T *lt, const DBT *locker,
+.ti +5
+const DBT *obj, const lock_mode_t lock_mode, LOCK_T **lockp);
+
+int
+lock_put(LOCK_T *lockp);
+
+int
+lock_close(LOCK_TABLE_T *lt);
+
+int
+lock_unlink(const char *path, int force);
+.ft R
+.fi
+.SH DESCRIPTION
+.so db.so
+.GN
+specific details of the locking interface.
+.PP
+.I Db_lock
+is the library interface intended to provide general-purpose locking. 
+While designed to work with the other DB functions, these functions are
+also useful for more general locking purposes.
+Locks can be shared between processes.
+.PP
+.CR "lock table" lock
+.PP
+The parameter
+.I lock_modes
+is the number of lock modes to be recognized by the lock table
+(including the ``not-granted'' mode).
+The parameter
+.I conflicts
+is an
+.I lock_modes
+by
+.I lock_modes
+array.
+A non-0 value for:
+.sp
+.ti +5
+conflicts[requested_mode][held_mode]
+.sp
+indicates that
+.I requested_mode
+and
+.I held_mode
+conflict.
+The ``not-granted'' mode must be represented by 0.
+.PP
+The include file <db_lock.h> declares two commonly used conflict arrays:
+.TP 5
+int lock_sx_n;
+.br
+.ns
+.TP 5
+const int8_t lock_sx_c[lock_sx_n][lock_sx_n];
+These variables specify a conflict array
+for a simple scheme using shared and exclusive lock modes.
+.TP 5
+int lock_g_n;
+.br
+.ns
+.TP 5
+const int8_t lock_g_c[lock_g_n][lock_g_n];
+These variables specify a conflict array that involves various intent
+lock modes (e.g. intent shared) that are used for multigranularity locking.
+.PP
+In addition,
+<db_lock.h> defines the following macros that name lock modes for use with
+the standard tables above:
+.RS
+.TP 5
+LOCK_IS
+intent shared
+.br
+.ns
+.TP 5
+LOCK_IX
+intent exclusive
+.br
+.ns
+.TP 5
+LOCK_NG
+not granted (always 0)
+.br
+.ns
+.TP 5
+LOCK_S
+shared
+.br
+.ns
+.TP 5
+LOCK_SIX
+shared/intent exclusive
+.br
+.ns
+.TP 5
+LOCK_X
+exclusive
+.RE
+.PP
+.I Maxlocks
+is the maximum number of locks to be held or requested in the table,
+and is used by
+.I lock_create
+to estimate how much space to allocate for various lock-table data
+structures.
+.PP
+.RT lock_create
+.PP
+.OP "lock table" lock
+.PP
+The function
+.I lock_vec
+atomically obtains and releases one or more locks from the designated
+table.
+The function
+.I lock_vec
+is intended to support acquisition or trading of multiple locks
+under one lock table semaphore, as is needed for lock coupling or
+in multigranularity locking for lock escalation.
+.PP
+If any of the requested locks cannot be acquired
+or any of the locks to be released cannot be released,
+no locks are acquired and no locks are released, and
+.I lock_vec
+returns an error.
+The function
+.I lock_vec
+returns 0 on success.
+If an error occurs,
+.I lock_vec
+returns one of the following values.
+In addition, if
+.I elistp
+is not NULL, it is set to point to the LOCK_REQ_T entry which
+was being processed when the error occurred.
+.TP 5
+LOCK_GET_DEADLOCK
+The specified
+.I locker
+was selected as a victim in order to resolve a deadlock.
+In this case, if the
+.I conflict
+argument is non-NULL, it is set to reference the identity of a
+locker holding the lock referenced by
+.I elistp
+at the time the request was denied.
+(This identity resides in static memory and may be overwritten by
+subsequent calls to
+.IR lock_vec ).
+.TP 5
+LOCK_GET_ERROR
+An error occurred and the external variable
+.I errno
+has been set to indicate the error.
+.TP 5
+LOCK_GET_NOTHELD
+The lock cannot be released, as it was not held by the
+.IR locker .
+.TP 5
+LOCK_GET_RESOURCE
+The lock manager is unable to grant the requested locks because of
+limited internal resources.
+(Releasing locks may allow future calls to
+.I lock_vec
+to succeed.)
+.TP 5
+LOCK_GET_TIMEOUT
+A timeout argument was specified, and the requested locks were not
+available soon enough.
+In this case, if the
+.I conflict
+argument is non-NULL, it is set to reference the identity of a
+locker holding the lock referenced by
+.I elistp
+at the time the request was denied.
+(This identity resides in static memory and may be overwritten by
+subsequent calls to
+.IR lock_vec ).
+.PP
+The
+.I locker
+argument specified to
+.I lock_vec
+is a pointer to an untyped byte string which identifies the entity
+requesting or releasing the lock.
+If
+.I locker
+is NULL, the calling process' pid is used instead.
+.PP
+The
+.I timeout
+argument provided to
+.I lock_vec
+specifies a maximum interval to wait for the locks to be granted.
+If
+.I timeout
+is NULL, it is ignored, and
+.I lock_vec
+will not return until all of the locks are acquired or an error has
+occurred.
+.PP
+The
+.I list
+array provided to 
+.I lock_vec
+is typedef'd in <db_lock.h> as LOCK_REQ_T.
+A LOCK_REQ_T structure has at least the following fields,
+which must be initialized before calling
+.IR lock_vec :
+.TP 5
+enum lockop op;
+The operation to be performed, which must be set to one of the
+following values:
+.RS
+.TP 5
+LOCK_GET
+Get a lock, as defined by the values of
+.IR locker ,
+.I obj
+and
+.IR lock_mode .
+Upon return from
+.IR lock_vec ,
+if the
+.I lockp
+field is non-NULL, a reference to the acquired lock is stored there.
+(This reference is invalidated by any call to
+.I lock_vec
+or
+.I lock_put
+which releases the lock.)
+.TP 5
+LOCK_PUT
+The lock referenced by the contents of the
+.I lockp
+field is released.
+.TP 5
+LOCK_PUT_ALL
+All locks held by the
+.I locker
+are released.
+(Any locks acquired as a part of the current call to
+.I lock_vec
+are not considered for this operation).
+.TP 5
+LOCK_PUT_OBJ
+All locks held by the
+.IR locker ,
+on the object
+.IR obj ,
+with the mode specified by
+.IR lock_mode ,
+are released.
+A
+.I lock_mode
+of LOCK_NG indicates that all locks on the object should be released.
+(Any locks acquired as a part of the current call to
+.I lock_vec
+are not considered for this operation).
+.RE
+.TP 5
+const DBT obj;
+An untyped byte string which specifies the object to be locked or
+released.
+.TP 5
+const lock_mode_t lock_mode;
+The lock mode, used as an index into
+.IR lt 's
+conflict array.
+.TP 5
+LOCK_T **lockp;
+A pointer to a pointer to a lock reference.
+.PP
+The
+.I nlist
+argument specifies the number of elements in the
+.I list
+array.
+.PP
+The function
+.I lock_get
+is a simple interface to the
+.I lock_vec
+functionality, and is equivalent to calling the
+.I lock_vec
+function with the
+.I lt
+and
+.I locker
+arguments, NULL
+.IR timeout , 
+.I elistp
+and
+.I conflict
+arguments, and a single element
+.I list
+array, for which the
+.I op
+field is LOCK_GET, and the
+.IR obj ,
+.I lock_mode
+and
+.I lockp
+fields are represented by the arguments of the same name.
+Note that the type of the
+.I obj
+argument to
+.I lock_get
+is different from the
+.I obj
+element found in the LOCK_REQ_T structure.
+The
+.I lock_get
+function returns success and failure as described for the
+.I lock_vec
+function.
+.PP
+The function
+.I lock_put
+is a simple interface to the
+.I lock_vec
+functionality, and is equivalent to calling the
+.I lock_vec 
+function with a single element
+.I list
+array, for which the
+.I op
+field is LOCK_PUT and the
+.I lockp
+field is represented by the argument of the same name.
+Note that the type of the
+.I lockp
+argument to
+.I lock_put
+is different from the
+.I lockp
+element found in the LOCK_REQ_T structure.
+The
+.I lock_put
+function returns success and failure as described for the
+.I lock_vec
+function.
+.PP
+The function
+.I lock_close
+disassociates the calling process from the lock table
+.IR lt ,
+after releasing all locks held or requested by that process.
+.RT lock_close
+.PP
+.UN "lock table" lock
+.SH "ERRORS"
+The
+.I lock_create
+function may fail and set
+.I errno
+for any of the errors specified for the library routines
+.IR mmap (2),
+.IR open (2)
+and
+.IR malloc (3).
+.PP
+The
+.I lock_open
+function may fail and set
+.I errno
+for any of the errors specified for the library routine
+.IR mmap (2)
+and
+.IR open (2).
+.PP
+The
+.I lock_close
+function may fail and set
+.I errno
+for any of the errors specified for the library routine
+.IR close (2)
+and
+.IR munmap (2).
+.PP
+The
+.I lock_unlink
+function may fail and set
+.I errno
+for any of the errors specified for the library function
+.IR unlink (2)
+or the following:
+.TP 5
+[EBUSY]
+The lock table was in use and the force flag was not set.
+.SH "SEE ALSO"
+.IR db_btree (3),
+.IR db_hash (3),
+.IR db_log (3),
+.IR db_mpool (3),
+.IR db_open (3),
+.IR db_recno (3),
+.IR db_txn (3)
+.SH BUGS
+The
+.I maxlocks
+parameter is a kluge, and should be deleted in favor of dynamically
+expanding the lock table.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db_log.3 b/mechglue/src/plugins/kdb/db2/libdb2/man/db_log.3
new file mode 100644
index 000000000..34c4d1f5d
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db_log.3
@@ -0,0 +1,290 @@
+.\" Copyright (c) 1990, 1993, 1994, 1995
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)db_log.3	8.15 (Berkeley) 8/3/95
+.\"
+.TH DB_LOG 3 "August 3, 1995"
+.UC 7
+.SH NAME
+db_log \- log-manager access method
+.SH DESCRIPTION
+.so db.so
+.GN
+specific details of the logging access method.
+.PP
+These functions provide a general-purpose logging facility sufficient
+for transaction management.
+Logs can be shared by multiple processes.
+.PP
+A log is represented by the directory,
+.IR "not the file" ,
+named by the first argument to
+.IR db_open (3).
+The first argument must be non-NULL,
+and the directory must already exist
+.I db_open
+is called.
+In that directory, the log is stored in one or more files named
+in the format ``log.YYYY.MM.DD.HH.MM.SS'', where ``YYYY.MM.DD.HH.SS''
+is the approximate creation time of the log file, and is guaranteed
+to be unique in the directory.
+.PP
+The group of the created files is based on the system and directory
+defaults, and is not further specified by the log access method.
+All files are created with the
+.I mode
+specified to
+.IR db_open ,
+(as described in
+.IR chmod (2))
+and modified by the process' umask value (see
+.IR umask (2)).
+.PP
+The
+.I flags
+argument to
+.I db_open
+must be 0 for the
+.I db_log
+access method.
+.SH "ACCESS METHOD SPECIFIC INFORMATION"
+The log access method specific data structure provided to
+.I db_open
+is typedef'd and named LOGINFO.
+A LOGINFO structure has at least the following fields,
+which may be initialized before calling
+.IR db_open :
+.TP 5
+off_t max_file_size;
+The maximum size of a single file in the log.
+If not specified, the maximum size defaults to an implementation-specific
+value.
+.TP 5
+int lorder;
+The byte order for integers in the stored database metadata.
+The number should represent the order as an integer; for example, 
+big endian order would be the number 4,321.
+If
+.I lorder
+is 0 (no order is specified) the current host order is used.
+.PP
+If the log already exists, the values specified for the parameters
+max_file_size and lorder are ignored in favor of the values used
+when the log was created.
+.SH "DB OPERATIONS"
+The data part of the key/data pair used by the log access method
+is the same as for other access methods.
+The key is different.
+Each log record is identified by a log sequence number (LSN),
+which is stored in a DBT, and which is used as the
+.I key
+for all log functions that take
+.I key
+arguments.
+Applications cannot create LSN's, and all LSN's provided to functions
+as arguments must first be retrieved using the
+.I put
+or
+.I seq
+functions.
+To provide a distinguished value for applications, it is guaranteed that
+no valid LSN will ever have a size of 0.
+.PP
+Applications can compare LSN's using the
+.I log_lsn_compare
+function (see below).
+.PP
+Applications can associate LSN's with specific log files.
+The function
+.I log_lsn_file
+(see below), returns the name of the log file containing the
+record with a specified LSN.
+(The mapping of LSN to file is needed for database administration.
+For example, a transaction manager typically records the earliest LSN
+needed for restart, and the database administrator may want to archive
+log files to tape when they contain only LSN's before the earliest one
+needed for restart.)
+.PP
+Applications can truncate the log file up to a specific LSN using the 
+.I log_trunc
+function (see below).
+.PP
+The functions returned by
+.I db_open
+for the log access method are as described in
+.IR db_open ,
+with the following exceptions and additions:
+.TP 5
+type
+The type is DB_LOG.
+.TP 5
+del
+The
+.I del
+function always returns an error for the log-manager access method,
+setting
+.I errno
+to EINVAL.
+.TP 5
+int (*log_flush)(const DB *db, const DBT *lsn);
+The
+.I log_flush
+function flushes the log up to and including the log record
+.IR lsn .
+.RT log_flush
+.TP 5
+int (*log_lsn_compare)(const DB *,
+.ti +5
+const DBT *lsn1, const DBT *lsn2);
+A pointer to a function which is provided to permit applications to
+compare LSN's.
+The
+.I log_lsn_compare
+function returns an integer less than, equal to, or greater than zero
+if the first LSN is considered to be respectively less than, equal to,
+or greater than the second LSN.
+.TP 5
+int (*log_lsn_file)(const DB *db,
+.ti +5
+const DBT *lsn, char *name);
+.br
+The
+.I log_lsn_file
+function stores a pointer to the name of the file containing
+.I lsn
+in the address referenced by
+.IR name.
+This pointer is to an internal static object, and subsequent calls to
+the same function will modify the same object.
+.IP
+.RT log_lsn_file
+.TP 5
+int (*log_unlink)(const char *path, int force);
+The
+.I log_unlink
+function destroys the log represented by
+.IR path .
+If the
+.I force
+parameter is not set to 1 and there are other processes using the
+log, then
+.I log_unlink
+will return -1, setting
+.IR errno
+to EBUSY.
+If
+.I force is not set or there are no processes using the log, then all files
+used by the log are destroyed.
+.I log_unlink
+will return -1 on failure, setting
+.IR errno ,
+and 0 on success.
+.TP 5
+int (*log_trunc)(const DB *db, const DBT *lsn);
+The
+.I log_trunc
+function truncates the log up to an LSN which is less than
+.IR lsn .
+.RT log_trunc
+.TP 5
+put
+A log record containing
+.I data
+is appended to the log.
+Unlike the
+.I put
+functions for other access methods, the key parameter is not initialized
+by the application, instead, the LSN assigned to the data is returned in
+the
+.I key
+parameter.
+.IP
+The caller is responsible for providing any necessary structure to
+.I data .
+(For example, in a write-ahead logging protocol, the application must
+understand what part of
+.I data
+is an operation code, what part is redo information, and what part is
+undo information.
+In addition, most transaction managers will store in
+.I data
+the LSN of the previous log record for the same transaction,
+to support chaining back through the transaction's log records
+during undo.)
+.IP
+The parameter
+.I flag
+must be set to 0 or exactly one of the following values:
+.RS
+.TP 5
+R_CHECKPOINT
+Specify the key/data pair of the current call as the one to be returned
+when the
+.I seq
+function is next called with the R_CHECKPOINT flag.
+.TP 5
+R_FLUSH
+Flush immediately (ignoring any possibility for group commit).
+.RE
+.TP 5
+seq
+The
+.I seq
+function takes the following additional flag:
+.RS
+.TP 5
+R_CHECKPOINT
+The last key/data pair stored by the
+.I put
+function (using the R_CHECKPOINT flag) is returned,
+and the cursor is set or initialized to reference it.
+The expected use of this flag is during restart and to determine what
+part of the log must be available for restart.
+Therefore, the log record retrieved with R_CHECKPOINT should contain
+all the information that the transaction manager will need for this
+purpose.
+.RE
+.TP 5
+sync
+The
+.I sync
+function always returns an error for the log-manager access method,
+setting
+.I errno
+to EINVAL.
+.SH "SEE ALSO"
+.IR db_btree (3),
+.IR db_hash (3),
+.IR db_lock (3),
+.IR db_mpool (3),
+.IR db_open (3),
+.IR db_recno (3),
+.IR db_txn (3)
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db_mpool.3 b/mechglue/src/plugins/kdb/db2/libdb2/man/db_mpool.3
new file mode 100644
index 000000000..4b683b618
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db_mpool.3
@@ -0,0 +1,403 @@
+.\" Copyright (c) 1990, 1993, 1994, 1995
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)db_mpool.3	8.14 (Berkeley) 8/1/95
+.\"
+.TH DB_MPOOL 3 "August 1, 1995"
+.UC 7
+.SH NAME
+db_mpool \- general purpose shared memory buffer pool
+.SH SYNOPSIS
+.nf
+.ft B
+#include <db.h>
+#include <mpool.h>
+
+int
+mpool_create(char *path, mode_t mode, size_t cachesize, u_long flags);
+
+MPOOL *
+mpool_open(char *path);
+
+int
+mpool_close(MPOOL *mp);
+
+MPOOLFILE *
+mpool_fopen(MPOOL *mp, char *path, size_t pagesize, void *pgcookie,
+.ti +5
+int (*pgin)(MPOOLFILE *mpf,
+.ti +8
+pgno_t pgno, void *pgaddr, void *pgcookie),
+.ti +5
+int (*pgout)(MPOOLFILE *mpf,
+.ti +8
+pgno_t pgno, void *pgaddr, void *pgcookie);
+
+int
+mpool_fclose(MPOOLFILE *mpf);
+
+void *
+mpool_get(MPOOLFILE *mpf, pgno_t *pgnoaddr, u_long flags,
+.ti +5
+int (*callback)(MPOOLFILE *mpf, pgno_t pgno));
+
+int
+mpool_put(MPOOLFILE *mpf, void *pgaddr, u_long flags);
+
+int
+mpool_sync(MPOOLFILE *mpf);
+
+int
+mpool_unlink(const char *path, int force);
+
+void
+mpool_stat(MPOOL *mp, FILE *fp);
+.ft R
+.fi
+.SH DESCRIPTION
+.so db.so
+.GN
+specific details of the memory pool interface.
+.PP
+The
+.I db_mpool
+function is the library interface intended to provide general-purpose,
+page-oriented buffer management of one or more files.
+While designed to work with the other DB functions, these functions are
+also useful for more general purposes.
+The memory pools (MPOOL's) are referred to in this document as
+simply ``pools''.
+Pools may be shared between processes.
+Pools are usually filled by pages from one or more files (MPOOLFILE's).
+Pages in the pool are replaced in LRU (least-recently-used) order,
+with each new page replacing the page which has been unused the longest.
+Pages retrieved from the pool using
+.I mpool_get
+are ``pinned'' in memory, by default,
+until they are returned to the pool using the
+.I mpool_put
+function.
+.PP
+.CR "memory pool" mpool
+.PP
+The
+.I cachesize
+argument specifies the size of the pool in bytes,
+and should be the size of the normal working set of the application with
+some small amount of additional memory for unusual situations.
+If the number of bytes currently ``pinned'' in memory exceeds
+.IR cachesize ,
+the
+.I db_mpool
+functions will attempt to allocate more memory and do not necessarily fail,
+although they may suffer performance degradation.
+.PP
+The
+.I flags
+argument is set by
+.IR or 'ing
+any of the following values:
+.TP
+MPOOL_PRIVATE
+The pool is not shared by other processes or threads,
+so no locking of pool resources is required.
+.PP
+.OP "memory pool" mpool
+.PP
+The
+.I mpool_close
+function closes the pool indicated by the MPOOL pointer
+.IR mp ,
+as returned by
+.IR mpool_open .
+This function does
+.B not
+imply a call to
+.I mpool_sync
+(or to
+.IR mpool_fclose )
+i.e. no pages are written to the source file as as a result of calling
+.IR mpool_close .
+.RT mpool_close
+.PP
+The function
+.I mpool_fopen
+opens a file for buffering in the pool specified by the MPOOL
+argument.
+The
+.I path
+argument is the name of the file to be opened.
+The
+.I pagesize
+argument is the size, in bytes, of the unit of transfer between the
+application and the pool, although not necessarily the unit of transfer
+between the pool and the source file.
+Applications not knowing the page size of the source file should
+retrieve the metadata from the file using a page size that is correct
+for the metadata, then close and reopen the file, or,
+otherwise determine the page size before calling
+.IR mpool_fopen .
+.PP
+If the
+.I pgin
+function is specified, it is called each time a page is read into
+the memory pool from the source file.
+If the
+.I pgout
+function is specified, it is called each time a page is written
+to the source file.
+Both functions are called with the MPOOLFILE pointer returned from
+.IR mpool_fopen ,
+the page number, a pointer to the page being read or written, and
+the argument
+.IR pgcookie .
+If either function fails, it should return non-zero and set
+.IR errno ,
+in which case the
+.I db_mpool
+function calling it will also fail, leaving
+.I errno
+intact.
+.PP
+The
+.I mpool_fclose
+function closes the source file indicated by the MPOOLFILE pointer
+.IR mpf .
+This function does
+.B not
+imply a call to
+.IR mpool_sync ,
+i.e. no pages are written to the source file as as a result of calling
+.IR mpool_fclose .
+.RT mpool_fclose
+.\"
+.\".PP
+.\"int
+.\"mpool_fd (MPOOLFILE *mpf);
+.\"
+.\".PP
+.\"The function
+.\".I mpool_fd
+.\"takes an MPOOLFILE pointer and returns the file descriptor being
+.\"used to read/write that file
+.\"to/from the pool.
+.PP
+The function
+.I mpool_get
+returns a pointer to the page with the page number specified by
+.IR pgnoaddr ,
+from the source file specified by the MPOOLFILE pointer
+.IR mpf .
+If the page does not exist or cannot be retrieved,
+.I mpool_get
+returns NULL and sets errno.
+.PP
+The
+.I flags
+argument is set by 
+.IR or 'ing
+any of the following values:
+.TP 5
+MPOOL_CALLBACK
+After the page number has been determined, but before any other
+process or thread can access the page, the function specified by
+the
+.I callback
+argument is called.
+If the function fails, it should return non-zero and set
+.IR errno ,
+in which case
+.I mpool_get
+will also fail, leaving
+.I errno
+intact.
+The
+.I callback
+function is called with the MPOOLFILE pointer returned from
+.I mpool_fopen
+and the page number.
+This functionality is commonly used when page locking is required,
+but the page number of the page being retrieved is not known.
+.TP 5
+MPOOL_CREATE
+If the specified page does not exist, create it.
+.TP 5
+MPOOL_LAST
+Return the last page of the source file and copy its page number
+to the location referenced by
+.IR pgnoaddr .
+.TP 5
+MPOOL_NEW
+Create a new page in the file and copy its page number to the location
+referenced by
+.IR pgnoaddr .
+.TP 5
+MPOOL_NOPIN
+Don't pin the page into memory.
+(This flag is intended for debugging purposes, when it's often useful
+to examine pages which are currently held by other parts of the
+application.
+Pages retrieved in this manner don't need to be returned to the
+memory pool, i.e. they should
+.B not
+be specified as arguments to the
+.IR mpool_put
+routine.)
+.PP
+Created pages have all their bytes set to 0.
+.PP
+All pages returned by
+.I mpool_get
+(unless the MPOOL_NOPIN flag is specified),
+will be retained (i.e. ``pinned'') in the pool until a subsequent
+call to
+.IR mpool_put .
+.PP
+The function
+.I mpool_put
+indicates that the page referenced by
+.I pgaddr
+can be evicted from the pool.
+.I Pgaddr
+must be an address previously returned by
+.IR mpool_get .
+.PP
+The flag value is specified by
+.IR or 'ing
+any of the following values:
+.TP 5
+MPOOL_DIRTY
+The page has been modified and must be written to the source file
+before being evicted from the pool.
+.TP 5
+MPOOL_DISCARD
+The page is unlikely to be useful in the near future, and should be
+discarded before other pages in the pool.
+.PP
+.RT mpool_put
+.PP
+The function
+.I mpool_sync
+writes all pages associated with the MPOOLFILE pointer
+.IR mpf ,
+which were specified as arguments to the
+.I mpool_put
+function with an associated flag of
+MPOOL_DIRTY,
+to the source file.
+.RT mpool_sync
+.PP
+.UN "memory pool" mpool
+.PP
+The function
+.I mpool_stat
+writes statistics for the memory pool
+.I mp
+to the file specified by
+.IR fp .
+These statistics include the number of files participating in the pool,
+the active pages in the pool, and numbers as to how effective the cache
+has been.
+.SH ERRORS
+The
+.IR mpool_create ,
+.I mpool_open
+and
+.I mpool_fopen
+functions may fail and set
+.I errno
+for any of the errors specified for the library functions
+.IR open (2),
+.IR read (2),
+and
+.IR malloc (3).
+.PP
+The
+.I mpool_close
+and
+.I mpool_fclose
+functions may fail and set
+.I errno
+for any of the errors specified for the library functions
+.IR close (2)
+and
+.IR free (3).
+.PP
+The
+.I mpool_get
+function may fail and set
+.I errno
+for any of the errors specified for the library functions
+.IR read (2),
+.IR write (2),
+and
+.IR malloc (3)
+or the following:
+.TP 5
+[EINVAL]
+The requested page does not exist and MPOOL_CREATE was not set.
+.PP
+The
+.I mpool_put
+function may fail and set
+.I errno
+for any of the errors specified for the library function
+.IR write (2)
+or the following:
+.TP 5
+[EACCES]
+The source file was not opened for writing.
+.PP
+The
+.I mpool_sync
+function may fail and set
+.I errno
+for any of the errors specified for the library function
+.IR write (2).
+.PP
+The
+.I mpool_unlink
+function may fail and set
+.I errno
+for any of the errors specified for the library function
+.IR unlink (2)
+or the following:
+.TP 5
+[EBUSY]
+The memory pool was in use and the force flag was not set.
+.SH "SEE ALSO"
+.IR db_btree (3),
+.IR db_hash (3),
+.IR db_lock (3),
+.IR db_log (3),
+.IR db_open (3),
+.IR db_recno (3),
+.IR db_txn (3)
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db_open.3 b/mechglue/src/plugins/kdb/db2/libdb2/man/db_open.3
new file mode 100644
index 000000000..f988ef924
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db_open.3
@@ -0,0 +1,574 @@
+.\" Copyright (c) 1990, 1993, 1994, 1995
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)db_open.3	8.15 (Berkeley) 8/1/95
+.\"
+.TH DB_OPEN 3 "August 1, 1995"
+.UC 7
+.SH NAME
+db_open \- database access methods
+.SH SYNOPSIS
+.nf
+.ft B
+#include <db.h>
+
+DB *
+db_open(const char *file, int flags, int mode,
+.ti +5
+DBTYPE type, DBINFO *dbinfo, const void *openinfo);
+.ft R
+.fi
+.SH DESCRIPTION
+.so db.so
+.GN
+the overall structure of the available access methods.
+.PP
+The currently supported file formats are btree, hashed, log and recno
+(i.e. flat-file oriented).
+The btree format is a representation of a sorted, balanced tree structure.
+The hashed format is an extensible, dynamic hashing scheme.
+The log format is a general-purpose logging facility.
+The recno format is a byte stream file with fixed or variable length
+records.
+The formats and other, format specific information are described in detail
+in their respective manual pages:
+.IR db_btree (3),
+.IR db_hash (3),
+.IR db_log (3),
+and
+.IR db_recno (3).
+.PP
+Db_open opens
+.I file
+for reading and/or writing.
+Files never intended to be preserved on disk may be created by setting
+the file parameter to NULL.
+(Note, while most of the access methods use
+.I file
+as the name of an underlying file on disk, this is not guaranteed.
+See the manual pages for the individual access methods for more
+information.)
+.PP
+The
+.I flags
+and
+.I mode arguments
+are as specified to the
+.IR open (2)
+function, however, only the O_CREAT, O_EXCL, O_EXLOCK, O_NONBLOCK,
+O_RDONLY, O_RDWR, O_SHLOCK and O_TRUNC flags are meaningful.
+(Note, opening a database file O_WRONLY is not possible.)
+.\"Three additional options may be specified by
+.\".IR or 'ing
+.\"them into the
+.\".I flags
+.\"argument.
+.\".TP
+.\"DB_LOCK
+.\"Do the necessary locking in the database to support concurrent access.
+.\"If concurrent access isn't needed or the database is read-only this
+.\"flag should not be set, as it tends to have an associated performance
+.\"penalty.
+.\".TP
+.\"DB_SHMEM
+.\"Place the underlying memory pool used by the database in shared
+.\"memory.
+.\"Necessary for concurrent access.
+.\".TP
+.\"DB_TXN
+.\"Support transactions in the database.
+.\"The DB_LOCK and DB_SHMEM flags must be set as well.
+.PP
+The
+.I type
+argument is of type DBTYPE (as defined in the <db.h> include file) and
+may be set to DB_BTREE, DB_HASH, DB_LOG or DB_RECNO.
+.PP
+The
+.I dbinfo 
+argument is a pointer to a structure containing references to locking,
+logging, transaction, and shared-memory buffer pool information.
+If 
+.I dbinfo
+is NULL, then the access method may still use these subsystems,
+but the usage will be private to the application and managed by DB.
+If
+.I dbinfo
+is non-NULL,
+then the module referenced by each of the non-NULL fields is used by DB
+as necessary.
+The fields of the DBINFO structure are defined as follows:
+.TP 5
+const char *errpfx;
+A prefix to prepend to error messages; used only if
+.I errfile
+is non-NULL.
+.TP 5
+FILE *errfile;
+The
+.IR stdio (3)
+file stream to which error messages are logged.
+.sp
+When any error occurs in the
+.I db_open
+function, or in any function called using a field of the returned DB
+structure, an error value is returned by the function,
+and the global variable
+.I errno
+is set appropriately.
+In some cases, however, the
+.I errno
+value may be insufficient to describe the cause of the error.
+In these cases, if
+.I errfile
+is non-NULL, additional error information will be written to the file
+stream it represents, preceded by the string, if any, specified by
+.IR errpfx .
+This error logging facility should not be required for normal operation,
+but may be useful in debugging applications.
+.TP 5
+char *errbuf;
+The buffer to which error messages are copied.
+If non-NULL,
+.I errbuf
+behaves as described for
+.IR errfile ,
+except that the
+.I errpfx
+field is ignored and the error message is copied into the specified
+buffer instead of being written to the FILE stream.
+The DB routines assume that the associated buffer is at least 1024 bytes
+in length.
+.TP 5
+LOCK_TABLE_T *lockinfo;
+If locking is required for the file being opened (as in the case of
+buffers being maintained in a shared memory buffer pool),
+the
+.I lockinfo
+field contains a return value from the function
+.I lock_open
+that should be used
+(see
+.IR db_lock (3)).
+If
+.I lockinfo
+is NULL, no locking is done.
+.TP 5
+DB *loginfo;
+If modifications to the file being opened should be logged, the
+.I loginfo
+field contains a return value from the function
+.IR dbopen ,
+when opening a DB file of type DB_LOG.
+If
+.I loginfo
+is NULL, no logging is done.
+.TP 5
+MPOOL *mpoolinfo;
+If the cache for the file being opened should be maintained in a shared
+buffer pool, the
+.I mpoolinfo
+field contains a return value from the function 
+.I mpool_open
+that should be used
+(see
+.IR db_mpool (3)).
+If
+.I mpoolinfo
+is NULL, a memory pool may still be created,
+but it will be private to the application and managed by DB.
+.TP 5
+TXNMGR *txninfo;
+If the accesses to the file being opened should take place in the context
+of transactions (providing atomicity and complete error recovery), the
+.I txninfo
+field contains a return value from the function
+.I txn_open
+(see
+.IR db_txn (3)).
+If transactions are specified,
+the application is responsible for making suitable calls to 
+.IR txn_begin ,
+.IR txn_abort ,
+and
+.IR txn_commit .
+If
+.I txninfo
+is NULL, no transaction support is done.
+.PP
+The
+.I openinfo
+argument is a pointer to an access method specific structure described
+in the access method's manual page.
+If
+.I openinfo
+is NULL, each access method will use defaults appropriate for the system
+and the access method.
+.SH "KEY/DATA PAIRS"
+Access to all access methods is based on key/data pairs.
+Both keys and data are represented by the following data structure:
+.PP
+typedef struct {
+.RS
+void *data;
+.br
+size_t size;
+.RE
+} DBT;
+.PP
+The elements of the DBT structure are defined as follows:
+.TP 5
+data
+A pointer to a byte string.
+.ns
+.br
+.TP 5
+size
+The length of
+.IR data ,
+in bytes.
+.PP
+Key and data byte strings may reference strings of essentially unlimited
+length, although any two of them must fit into available memory at the
+same time.
+.PP
+The access methods provide no guarantees about byte string alignment,
+and applications are responsible for maintaining any necessary alignment.
+.SH "DB OPERATIONS"
+.I Db_open
+returns a pointer to a DB structure (as defined in the <db.h> include file)
+on success, and NULL on error.
+The DB structure describes a database type, and includes a set of functions
+to perform various actions, as described below.
+Each of these functions takes a pointer to a DB structure, and may take
+one or more DBT *'s and a flag value as well.
+Individual access methods specify additional functions and flags which
+are specific to the method.
+The fields of the DB structure are as follows:
+.TP 5
+DBTYPE type;
+The type of the underlying access method (and file format).
+.TP 5
+int (*close)(const DB *db);
+A pointer to a function to flush any cached information to disk,
+free any allocated resources, and close any underlying files.
+Since key/data pairs are cached in memory, failing to sync the
+file with the
+.I close
+or
+.I sync
+function may result in inconsistent or lost information.
+.IP
+The
+.I close
+functions return -1 on failure, setting
+.IR errno ,
+and 0 on success.
+.TP 5
+int (*del)(const DB *db, TXN *txnid,
+.ti +5
+const DBT *key, u_int flags);
+.br
+A pointer to a function to remove key/data pairs from the database.
+The key/data pair associated with the specified
+.I key
+are discarded from the database.
+.IP
+The
+.I txnid
+parameter contains a transaction ID returned from
+.IR txn_begin ,
+if the file is being accessed under transaction protection,
+or NULL if transactions are not in effect.
+.IP
+The parameter
+.I flag
+must be set to 0 or exactly one of the following values:
+.RS
+.TP 5
+R_CURSOR
+Delete the record referenced by the cursor.
+The cursor must have previously been initialized.
+.RE
+.IP
+The
+.I delete
+functions return -1 on error, setting
+.IR errno ,
+0 on success, and 1 if the specified
+.I key
+did not exist in the file.
+.TP 5
+int (*fd)(const DB *db);
+A pointer to a function which returns a file descriptor representative
+of the underlying database.
+A file descriptor referencing the same file will be returned to all
+processes which call
+.I db_open
+with the same
+.I file
+name.
+This file descriptor may be safely used as an argument to the
+.IR fcntl (2)
+and
+.IR flock (2)
+locking functions.
+The file descriptor is not necessarily associated with any of the
+underlying files used by the access method.
+No file descriptor is available for in memory databases.
+.IP
+The
+.I fd
+functions return -1 on error, setting
+.IR errno ,
+and the file descriptor on success.
+.TP 5
+int (*get)(const DB *db, TXN *txnid,
+.ti +5
+const DBT *key, DBT *data, u_int flags);
+.br
+A pointer to a function which is the interface for keyed retrieval from
+the database.
+The address and length of the data associated with the specified
+.I key
+are returned in the structure referenced by
+.IR data .
+.IP
+The
+.I txnid
+parameter contains a transaction ID returned from
+.IR txn_begin ,
+if the file is being accessed under transaction protection,
+or NULL if transactions are not in effect.
+.IP
+The
+.I get
+functions return -1 on error, setting
+.IR errno ,
+0 on success, and 1 if the
+.I key
+was not found.
+.TP 5
+int (*put)(const DB *db, TXN *txnid,
+.ti +5
+DBT *key, const DBT *data, u_int flags);
+.br
+A pointer to a function to store key/data pairs in the database.
+.IP
+The
+.I txnid
+parameter contains a transaction ID returned from
+.IR txn_begin ,
+if the file is being accessed under transaction protection,
+or NULL if transactions are not in effect.
+.IP
+The parameter
+.I flag
+must be set to 0 or exactly one of the following values:
+.RS
+.TP 5
+R_CURSOR
+Replace the key/data pair referenced by the cursor.
+The cursor must have previously been initialized.
+.TP 5
+R_NOOVERWRITE
+Enter the new key/data pair only if the key does not previously exist.
+.RE
+.IP
+The default behavior of the
+.I put
+functions is to enter the new key/data pair, replacing any previously
+existing key.
+.IP
+The
+.I put
+functions return -1 on error, setting
+.IR errno ,
+0 on success, and 1 if the R_NOOVERWRITE
+.I flag
+was set and the key already exists in the file.
+.TP 5
+int (*seq)(const DB *db, TXN *txnid,
+.ti +5
+DBT *key, DBT *data, u_int flags);
+.br
+A pointer to a function which is the interface for sequential
+retrieval from the database.
+The address and length of the key are returned in the structure
+referenced by
+.IR key ,
+and the address and length of the data are returned in the
+structure referenced
+by
+.IR data .
+.IP
+The
+.I txnid
+parameter contains a transaction ID returned from
+.IR txn_begin ,
+if the file is being accessed under transaction protection,
+or NULL if transactions are not in effect.
+.IP
+Sequential key/data pair retrieval may begin at any time, and the
+logical position of the ``cursor'' is not affected by calls to the
+.IR del ,
+.IR get ,
+.IR put ,
+or
+.I sync
+functions.
+Modifications to the database during a sequential scan will be reflected
+in the scan, i.e. records inserted behind the cursor will not be returned
+while records inserted in front of the cursor will be returned.
+.IP
+The parameter
+.I flag
+must be set to 0 or exactly one of the following values:
+.RS
+.TP 5
+R_CURSOR
+The data associated with the specified key is returned.
+This differs from the
+.I get
+functions in that it sets or initializes the cursor to the location of
+the key as well.
+.TP 5
+R_FIRST
+The first key/data pair of the database is returned, and the cursor
+is set or initialized to reference it.
+.TP 5
+R_NEXT
+Retrieve the key/data pair immediately after the cursor.
+If the cursor is not yet set, this is the same as the R_FIRST flag.
+.RE
+.IP
+The
+.I seq
+functions return -1 on error, setting
+.IR errno ,
+0 on success,
+and 1 if there are no key/data pairs less than or greater than the
+specified or current key.
+.TP 5
+int (*sync)(const DB *db, u_int flags);
+A pointer to a function to flush any cached information to disk.
+If the database is in memory only, the
+.I sync
+function has no effect and will always succeed.
+.IP
+The parameter
+.I flag
+must be set to 0 or a value specified by an access method specific
+manual page.
+.IP
+The
+.I sync
+functions return -1 on failure, setting
+.IR errno ,
+and 0 on success.
+.SH ERRORS
+The
+.I db_open
+function may fail and set
+.I errno
+for any of the errors specified for the library functions
+.IR open (2),
+.IR malloc (3)
+or the following:
+.TP 5
+[EFTYPE]
+A file is incorrectly formatted.
+.TP 5
+[EINVAL]
+A parameter has been specified (hash function, recno pad byte etc.)
+that is incompatible with the current file specification or, a flag
+to a function which is not meaningful for the function (for example,
+use of the cursor without prior initialization) or there is a mismatch
+between the version number of file and the software.
+.PP
+The
+.I close
+functions may fail and set
+.I errno
+for any of the errors specified for the library functions
+.IR close (2),
+.IR read (2),
+.IR write (2),
+.IR free (3),
+or
+.IR fsync (2).
+.PP
+The
+.IR del ,
+.IR get ,
+.I put
+and
+.I seq
+functions may fail and set
+.I errno
+for any of the errors specified for the library functions
+.IR read (2),
+.IR write (2),
+.IR free (3)
+or
+.IR malloc (3).
+.PP
+The
+.I fd
+functions will fail and set
+.I errno
+to ENOENT for in memory databases.
+.PP
+The
+.I sync
+functions may fail and set
+.I errno
+for any of the errors specified for the library function
+.IR fsync (2).
+.SH "SEE ALSO"
+.IR db_btree (3),
+.IR db_hash (3),
+.IR db_lock (3),
+.IR db_log (3),
+.IR db_mpool (3),
+.IR db_recno (3),
+.IR db_txn (3)
+.SH BUGS
+The name DBT is a mnemonic for ``data base thang'', and was used
+because noone could think of a reasonable name that wasn't already
+in use somewhere else.
+.PP
+The
+.I fd
+function interface is a kluge,
+and will be deleted in a future version of the interface.
+.PP
+Only big and little endian byte order is supported.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db_recno.3 b/mechglue/src/plugins/kdb/db2/libdb2/man/db_recno.3
new file mode 100644
index 000000000..6b93b3f5a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db_recno.3
@@ -0,0 +1,268 @@
+.\" Copyright (c) 1990, 1993, 1994, 1995
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)db_recno.3	8.12 (Berkeley) 8/1/95
+.\"
+.TH DB_RECNO 3 "August 1, 1995"
+.UC 7
+.SH NAME
+db_recno \- record number database access method
+.SH DESCRIPTION
+.so db.so
+specific details of the recno access method.
+.SH "ACCESS METHOD SPECIFIC INFORMATION"
+The recno access method specific data structure provided to
+.I db_open
+is typedef'd and named RECNOINFO.
+A RECNOINFO structure has at least the following fields,
+which may be initialized before calling
+.IR db_open :
+.TP 5
+u_int8_t bval;
+The delimiting byte to be used to mark the end of a record for
+variable-length records, and the pad character for fixed-length
+records.
+If no value is specified, newlines (``\en'') are used to mark the end
+of variable-length records and fixed-length records are padded with
+spaces.
+.TP 5
+char *bfname;
+The recno access method stores the in-memory copies of its records
+in a btree.
+If bfname is non-NULL, it specifies the name of the btree file,
+as if specified as the file name for a
+.I db_open
+of a btree file.
+.TP 5
+u_int cachesize;
+A suggested maximum size, in bytes, of the memory cache.
+This value is
+.B only
+advisory, and the access method will allocate more memory rather than fail.
+If
+.I cachesize
+is  0 (no size is specified) a default size is used.
+.TP 5
+u_long flags;
+The flag value is specified by
+.IR or 'ing
+any of the following values:
+.RS
+.TP 5
+R_FIXEDLEN
+The records are fixed-length, not byte delimited.
+The structure element
+.I reclen
+specifies the length of the record, and the structure element
+.I bval
+is used as the pad character.
+Any records, inserted into the database, that are less than
+.I reclen
+bytes long are automatically padded.
+.TP 5
+R_NOKEY
+In the interface specified by
+.IR db_open ,
+the sequential record retrieval fills in both the caller's key and
+data structures.
+If the R_NOKEY flag is specified, the
+.I cursor
+functions are not required to fill in the key structure.
+This permits applications to retrieve records at the end of files without
+reading all of the intervening records.
+.TP 5
+R_SNAPSHOT
+This flag requires that a snapshot of the file be taken when
+.I db_open
+is called, instead of permitting any unmodified records to be read from
+the original file.
+.RE
+.TP 5
+int lorder;
+The byte order for integers in the stored database metadata.
+The number should represent the order as an integer; for example,
+big endian order would be the number 4,321.
+If
+.I lorder
+is 0 (no order is specified) the current host order is used.
+.TP 5
+u_int psize;
+The recno access method stores the in-memory copies of its records
+in a btree.
+This value is the size (in bytes) of the pages used for nodes in that tree.
+If
+.I psize
+is 0 (no page size is specified) a page size is chosen based on the
+underlying file system I/O block size.
+See
+.IR btree (3)
+for more information.
+.TP 5
+size_t reclen;
+The length of a fixed-length record.
+.SH "DB OPERATIONS"
+The data part of the key/data pair used by the recno access method
+is the same as other access methods.
+The key is different.
+The
+.I data
+field of the key should be a pointer to a memory location of type
+.IR recno_t ,
+as defined in the <db.h> include file.
+This type is normally the largest unsigned integral type available to
+the implementation.
+The
+.I size
+field of the key should be the size of that type.
+.PP
+The record number data structure is either variable or fixed-length
+records stored in a flat-file format, accessed by the logical record
+number.
+The existence of record number five requires the existence of records
+one through four, and the deletion of record number one causes
+record number five to be renumbered to record number four, as well
+as the cursor, if positioned after record number one, to shift down
+one record.
+The creation of record number five when records one through four do
+not exist causes the logical creation of them with zero-length data.
+.PP
+Because there is no meta-data associated with the underlying recno access
+method files, any changes made to the default values (e.g. fixed record
+length or byte separator value) must be explicitly specified each time the
+file is opened.
+.PP
+The functions returned by
+.I db_open
+for the btree access method are as described in
+.IR db_open (3),
+with the following exceptions and additions:
+.TP 5
+type
+The type is DB_RECNO.
+.TP 5
+put
+Using the
+.I put
+interface to create a new record will cause the creation of multiple,
+empty records if the record number is more than one greater than the
+largest record currently in the database.
+.IP
+The
+.I put
+function takes the following additional flags:
+.RS
+.TP 5
+R_IAFTER
+Append the data immediately after the data referenced by
+.IR key ,
+creating a new key/data pair.
+The record number of the appended key/data pair is returned in the
+.I key
+structure.
+.TP 5
+R_IBEFORE
+Insert the data immediately before the data referenced by
+.IR key ,
+creating a new key/data pair.
+The record number of the inserted key/data pair is returned in the
+.I key
+structure.
+.TP 5
+R_SETCURSOR
+Store the key/data pair, setting or initializing the position of the
+cursor to reference it.
+.RE
+.TP 5
+seq
+The
+.I seq
+function takes the following additional flags:
+.RS
+.TP 5
+R_LAST
+The last key/data pair of the database is returned, and the cursor
+is set or initialized to reference it.
+.TP 5
+R_PREV
+Retrieve the key/data pair immediately before the cursor.
+If the cursor is not yet set, this is the same as the R_LAST flag.
+.RE
+.IP
+If the database file is a character special file and no complete
+key/data pairs are currently available, the
+.I seq
+function returns 2.
+.TP 5
+sync
+The
+.I sync
+function takes the following additional flag:
+.RS
+.TP 5
+R_RECNOSYNC
+This flag causes the
+.I sync
+function to apply to the btree file which underlies the recno file,
+not the recno file itself.
+(See the
+.I bfname
+field of RECNOINFO
+structure, above, for more information.)
+.RE
+.SH ERRORS
+The
+.I recno
+access method functions may fail and set
+.I errno
+for any of the errors specified for the library function
+.IR db_open (3)
+or the following:
+.TP 5
+[EINVAL]
+An attempt was made to add a record to a fixed-length database that
+was too large to fit.
+.SH "SEE ALSO"
+.IR db_btree (3),
+.IR db_hash (3),
+.IR db_lock (3),
+.IR db_log (3),
+.IR db_mpool (3),
+.IR db_open (3),
+.IR db_txn (3)
+.sp
+.IR "Document Processing in a Relational Database System" ,
+Michael Stonebraker, Heidi Stettner, Joseph Kalash, Antonin Guttman,
+Nadene Lynn, Memorandum No. UCB/ERL M82/32, May 1982.
+.SH BUGS
+The
+.I sync
+function's R_RECNOSYNC interface is a kluge,
+and will be deleted in a future version of the interface.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/db_txn.3 b/mechglue/src/plugins/kdb/db2/libdb2/man/db_txn.3
new file mode 100644
index 000000000..18ad64692
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/db_txn.3
@@ -0,0 +1,373 @@
+.\" Copyright (c) 1994, 1995
+.\"	The President and Fellows of Harvard University.  All rights reserved.
+.\" Copyright (c) 1994, 1995
+.\"	Margo I. Selzer.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)db_txn.3	8.8 (Harvard) 8/1/95
+.\"
+.TH DB_TXN 3 "August 1, 1995"
+.UC 7
+.SH NAME
+db_txn \- transaction management functions
+.SH SYNOPSIS
+.nf
+.ft B
+#include <db.h>
+#include <db_lock.h>
+
+int
+txn_create(const char *path, mode_t mode, u_int maxtxns, u_int flags);
+
+TXNMGR *
+txn_open(const char *path, DBT *logp, LOCK_TABLE_T *lockp,
+.ti +5
+int (*recover)(DBT *lsn, DBT *log_entry, int isundo));
+
+TXN *
+txn_begin(TXNMGR *txnp);
+
+int
+txn_commit(TXN *tid);
+
+int
+txn_prepare(TXN *tid);
+
+int
+txn_abort(TXN *tid);
+
+int
+txn_close(TXNMGR *txnp);
+
+int
+txn_unlink(const char *path, int force);
+.ft R
+.fi
+.SH DESCRIPTION
+.so db.so
+specific details of the transaction support.
+.PP
+.I Db_txn
+is the library interface that provides transaction semantics.
+Full transaction support is provided by a collection of modules
+that provide well defined interfaces to the services required for
+transaction processing.
+These services are recovery (see
+.IR db_log (3)),
+concurrency control (see
+.IR db_lock (3)),
+and the management of shared data (see
+.IR db_mpool (3)).
+Transaction semantics can be applied to the access methods described in
+.IR db (3)
+through function call parameters.
+.PP
+The model intended for transactional use (and that is used by the
+access methods) is that write-ahead logging is provided by
+.IR db_log (3)
+to record both before- and after-image logging.
+Locking follows a two-phase protocol and is implemented by
+.IR db_lock (3).
+.PP
+.CR "transaction region" txn
+Any necessary,
+associated log and lock regions are created as well (see
+.IR db_log (3)
+and
+.IR db_lock (3)).
+.PP
+The
+.I maxtxns
+argument specifies the maximum number of simultaneous transactions that
+are supported.
+This bounds the size of backing files and is used to derive limits for
+the size of the lock region and logfiles.
+When there are more than
+.I maxtxns
+concurrent transactions, calls to
+.I txn_begin
+may fail.
+.PP
+Default locking and logging protocols are provided only if the
+backing files exist.
+If the backing files do not exist, the
+.I flags
+parameter must indicate both a logging mode and locking mode specified by 
+.IR or 'ing
+together at most one flag from each of the TXN_LOCK and TXN_LOG classes
+as follows:
+.TP 5
+TXN_LOCK_2PL
+Use two-phase locking.
+.TP 5
+TXN_LOCK_OPTIMISTIC
+Use optimistic locking (not currently implemented).
+.TP 5
+TXN_LOG_REDO
+Provide redo-only logging (not currently implemented).
+.TP 5
+TXN_LOG_UNDO
+Provide undo-only logging (not currently implemented).
+.TP 5
+TXN_LOG_UNDOREDO
+Provide undo/redo write-ahead logging.
+.PP
+.RT txn_create
+.PP
+.OP "transaction region" txn
+.PP
+The
+.I recover
+argument specifies a function that is called by
+.I txn_abort
+during transaction abort.
+This function takes three arguments:
+.TP 5
+lsn
+A log sequence number (LSN).
+.TP 5
+log_entry
+A log record.
+.TP 5
+isundo
+An undo flag set to 0 if the operation is a redo and set to 1 if the
+operation an undo.
+.PP
+As discussed in the
+.I db_log (3)
+manual page,
+the application is responsible for providing any necessary structure
+to the log record.
+For example, the application must understand what part of the log
+record is an operation code, what part is redo information, and what
+part is undo information.
+.PP
+The
+.I txn_begin 
+function creates a new transaction in the designated transaction
+manager, returning a pointer to a TXN that uniquely identifies it.
+.PP
+The
+.I txn_commit
+function ends the transaction specified by the
+.I tid
+argument.
+Any locks held by the transaction are released.
+If logging is enabled, a commit log record is written and flushed to disk.
+.PP
+The
+.I txn_abort
+function causes an abnormal termination of the transaction.
+If logging is enabled, the log is played backwards and any recovery
+operations are initiated through the
+.I recover
+function specified to
+.IR txn_open .
+After recovery is completed, all locks held by the transaction are released.
+.PP
+The 
+.I txn_close
+function detaches a process from the transaction environment specified
+by the TXNMGR pointer.
+All mapped regions are unmapped and any allocated resources are freed.
+Any uncommitted transactions are aborted.
+.PP
+.UN "transaction region" txn
+.PP
+The
+.I txn_prepare
+function initiates the beginning of a two phase commit.
+In a distributed transaction,
+the prepare directive should be issued to all participating
+transaction managers.
+Each manager must take whatever action is necessary to guarantee
+that a future call to
+.I txn_commit
+on the specified
+.I tid
+will succeed.
+.SH "SYSTEM INTEGRATION"
+This model can be applied to data bases other than the provided access
+methods.
+For example, consider an application that provides transaction semantics
+to data stored in regular files accessed using the 
+.IR read (2)
+and
+.IR write (2)
+system calls.
+The operations for which transaction protection is desired are bracketed
+by calls to
+.I txn_begin
+and
+.IR txn_commit .
+.PP
+Before data are referenced, a call is made to the lock manager,
+.IR db_lock ,
+for a lock of the appropriate type (e.g. read)
+on the object being locked.
+The object might be a page in the file, a byte, a range of bytes,
+or some key.
+Before a write is performed, the application makes a call to the
+log manager,
+.IR db_log ,
+to record enough information to redo the operation in case of
+failure after commit and to undo the operation in case of abort.
+After the log message is written, the write system calls are issued.
+After all requests are issued, the application calls
+.IR txn_commit .
+When
+.I txn_commit
+returns, the caller is guaranteed that all necessary log writes have
+been written to disk. 
+.PP
+At any time, the application may call
+.IR txn_abort ,
+which will result in the appropriate calls to the
+.I recover
+routine to restore the ``database'' to a consistent pre-transaction
+state.
+(The recover routine must be able to either reapply or undo the update
+depending on the context, for each different type of log record.)
+.PP
+If the application should crash, the recovery process uses the
+.I db_log
+interface to read the log and call the
+.I recover
+routine to restore the database to a consistent state.
+.PP
+The
+.I txn_prepare 
+function provides the core functionality to implement distributed
+transactions,
+but it does not actually manage the notification of distributed
+transaction managers.
+The caller is responsible for issuing 
+.I txn_prepare
+calls to all sites participating in the transaction.
+If all responses are positive, the caller can issue a
+.IR txn_commit .
+If any of the responses are negative, the caller should issue a
+.IR txn_abort .
+In general, the 
+.I txn_prepare
+call requires that the transaction log be flushed to disk.
+.PP
+The structure of the transaction support allows application designers
+to trade off performance and protection.
+Since DB manages many structures in shared memory,
+its information is subject to corruption by applications when the library
+is linked directly with the application.
+For this reason, DB is designed to allow compilation into a separate
+server process that may be accessed via a socket interface.
+In this way DB's data structures are protected from application code,
+but communication overhead is increased.
+When applications are trusted, DB may be compiled directly into the
+application for increased performance.
+.SH ERRORS
+The
+.I txn_create
+function may fail and set
+.I errno
+for any of the errors specified for the library functions
+.IR open (2),
+.IR write (2),
+.IR malloc (3),
+.IR lock_create (3),
+and
+.IR log_create (3).
+.PP
+The
+.I txn_open
+function may fail and set
+.I errno
+to any of the errors specified for the library functions
+.IR open (2),
+.IR write (2),
+.IR malloc (3),
+.IR lock_open (3),
+and
+.IR log_open (3).
+.PP
+The
+.I txn_begin
+function may fail and set
+.I errno
+to ENOSPC indicating that the maximum number of concurrent
+transactions has been reached.
+.PP
+The
+.I txn_commit
+function may fail and set
+.I errno
+to EINVAL indicating that the transaction was aborted.
+.PP
+The
+.I txn_close
+function may fail and set
+.I errno
+to any of the errors specified for the library functions
+.IR close (2),
+.IR read (2),
+.IR write (2),
+.IR free (3),
+.IR fsync (2),
+.IR lock_close (3)
+or
+.IR log_close (3).
+.PP
+The
+.I txn_unlink
+function may fail and set
+.I errno
+to any of the errors specified for the library functions
+.IR unlink (2),
+.IR lock_unlink (3),
+and
+.IR log_unlink (3),
+or the following:
+.TP 5
+[EBUSY]
+The transaction region was in use and the force flag was not set.
+.SH "SEE ALSO"
+.IR db_btree (3),
+.IR db_hash (3),
+.IR db_lock (3),
+.IR db_log (3),
+.IR db_mpool (3),
+.IR db_open (3),
+.IR db_recno (3)
+.sp
+.IR "LIBTP: Portable, Modular Transactions for UNIX" ,
+Margo Seltzer, Michael Olson, USENIX proceedings, Winter 1992.
+.SH BUGS
+The
+.I maxtxns
+parameter is a kluge, and should be deleted in favor of dynamically
+expanding the transaction region.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/man/spell.ok b/mechglue/src/plugins/kdb/db2/libdb2/man/spell.ok
new file mode 100644
index 000000000..794b00bf8
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/man/spell.ok
@@ -0,0 +1,170 @@
+Ake
+Antonin
+BTREE
+BTREEINFO
+Bsize
+CALLBACK
+Comput
+D.E
+DB
+DB's
+DBINFO
+DBT
+DBTYPE
+Db
+EACCES
+EBUSY
+EFTYPE
+EINVAL
+ENOENT
+ENOSPC
+ERL
+EXCL
+EXLOCK
+FIXEDLEN
+Ffactor
+Guttman
+HASHINFO
+Heidi
+IAFTER
+IBEFORE
+Kalash
+Knuth
+LIBTP
+LOGINFO
+LRU
+LSN
+LSN's
+MPOOL
+MPOOL's
+MPOOLFILE
+MPOOLFILE's
+Maxlocks
+Mpool
+NG
+NOKEY
+NOOVERWRITE
+NOPIN
+NOTHELD
+Nadene
+Nelem
+Nelems
+OBJ
+Pgaddr
+RDONLY
+RDWR
+RECNO
+RECNOINFO
+RECNOSYNC
+REQ
+SETCURSOR
+SHLOCK
+Stettner
+Stonebraker
+Surv
+TMPDIR
+TRUNC
+TXN
+TXNMGR
+Txn
+UCB
+UNDOREDO
+USENIX
+Unterauer
+Vol
+WAL
+WRONLY
+XACT
+YYYY.MM.DD.HH.SS
+al
+bfname
+bsize
+btree
+btrees
+bval
+cachesize
+callback
+const
+db
+db.h
+dbinfo
+dbopen
+del
+elistp
+endian
+enum
+errbuf
+errfile
+errno
+errpfx
+fd
+ffactor
+getv
+ing
+int
+int32
+int8
+isundo
+kluge
+lastlsn
+lg
+lock.h
+lockinfo
+lockop
+lockp
+log.YYYY.MM.DD.HH.MM.SS
+logfiles
+loginfo
+logp
+lreq
+lsn
+lsn1
+lsn2
+lt
+maxcache
+maxkeypage
+maxlocks
+maxtxns
+meta
+minkeypage
+mmap
+mpf
+mpool
+mpool.h
+mpoolinfo
+munmap
+nacquire
+nelem
+nelems
+nmodes
+noone
+nrelease
+obj
+op
+openinfo
+pathname
+pgaddr
+pgcookie
+pgin
+pgno
+pgnoaddr
+pgout
+pid
+pp
+psize
+queue.h
+reclen
+recno
+sx
+thang
+timespec
+tmp
+trunc
+txn
+txnid
+txninfo
+txnp
+typedef
+typedef'd
+vec
+writeable
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/mpool/Makefile.in b/mechglue/src/plugins/kdb/db2/libdb2/mpool/Makefile.in
new file mode 100644
index 000000000..9745c4e30
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/mpool/Makefile.in
@@ -0,0 +1,11 @@
+thisconfigdir=./..
+myfulldir=plugins/kdb/db2/libdb2/mpool
+mydir=mpool
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..$(S)..
+STLIBOBJS=mpool.o
+
+LOCALINCLUDES=	-I. -I$(srcdir)/../include -I../include -I$(srcdir)/../db
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+# @libobj_frag@
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/mpool/Makefile.inc b/mechglue/src/plugins/kdb/db2/libdb2/mpool/Makefile.inc
new file mode 100644
index 000000000..93210c89e
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/mpool/Makefile.inc
@@ -0,0 +1,5 @@
+#	@(#)Makefile.inc	8.1 (Berkeley) 6/4/93
+
+.PATH: ${.CURDIR}/db/mpool
+
+SRCS+=	mpool.c
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/mpool/README b/mechglue/src/plugins/kdb/db2/libdb2/mpool/README
new file mode 100644
index 000000000..0f01fbcdb
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/mpool/README
@@ -0,0 +1,7 @@
+#	@(#)README	8.1 (Berkeley) 6/4/93
+
+These are the current memory pool routines.
+They aren't ready for prime time, yet, and
+the interface is expected to change.
+
+--keith
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/mpool/mpool.c b/mechglue/src/plugins/kdb/db2/libdb2/mpool/mpool.c
new file mode 100644
index 000000000..d172f71ba
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/mpool/mpool.c
@@ -0,0 +1,514 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mpool.c	8.7 (Berkeley) 11/2/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "db-int.h"
+#include "mpool.h"
+
+static BKT *mpool_bkt __P((MPOOL *));
+static BKT *mpool_look __P((MPOOL *, db_pgno_t));
+static int  mpool_write __P((MPOOL *, BKT *));
+
+/*
+ * mpool_open --
+ *	Initialize a memory pool.
+ */
+MPOOL *
+mpool_open(key, fd, pagesize, maxcache)
+	void *key;
+	int fd;
+	db_pgno_t pagesize, maxcache;
+{
+	struct stat sb;
+	MPOOL *mp;
+	int entry;
+
+	/*
+	 * Get information about the file.
+	 *
+	 * XXX
+	 * We don't currently handle pipes, although we should.
+	 */
+	if (fstat(fd, &sb))
+		return (NULL);
+	if (!S_ISREG(sb.st_mode)) {
+		errno = ESPIPE;
+		return (NULL);
+	}
+
+	/* Allocate and initialize the MPOOL cookie. */
+	if ((mp = (MPOOL *)calloc(1, sizeof(MPOOL))) == NULL)
+		return (NULL);
+	CIRCLEQ_INIT(&mp->lqh);
+	for (entry = 0; entry < HASHSIZE; ++entry)
+		CIRCLEQ_INIT(&mp->hqh[entry]);
+	mp->maxcache = maxcache;
+	mp->npages = sb.st_size / pagesize;
+	mp->pagesize = pagesize;
+	mp->fd = fd;
+	return (mp);
+}
+
+/*
+ * mpool_filter --
+ *	Initialize input/output filters.
+ */
+void
+mpool_filter(mp, pgin, pgout, pgcookie)
+	MPOOL *mp;
+	void (*pgin) __P((void *, db_pgno_t, void *));
+	void (*pgout) __P((void *, db_pgno_t, void *));
+	void *pgcookie;
+{
+	mp->pgin = pgin;
+	mp->pgout = pgout;
+	mp->pgcookie = pgcookie;
+}
+	
+/*
+ * mpool_new --
+ *	Get a new page of memory.
+ */
+void *
+mpool_new(mp, pgnoaddr, flags)
+	MPOOL *mp;
+	db_pgno_t *pgnoaddr;
+	u_int flags;
+{
+	struct _hqh *head;
+	BKT *bp;
+
+	if (mp->npages == MAX_PAGE_NUMBER) {
+		(void)fprintf(stderr, "mpool_new: page allocation overflow.\n");
+		abort();
+	}
+#ifdef STATISTICS
+	++mp->pagenew;
+#endif
+	/*
+	 * Get a BKT from the cache.  Assign a new page number, attach
+	 * it to the head of the hash chain, the tail of the lru chain,
+	 * and return.
+	 */
+	if ((bp = mpool_bkt(mp)) == NULL)
+		return (NULL);
+	if (flags == MPOOL_PAGE_REQUEST) {
+		mp->npages++;
+		bp->pgno = *pgnoaddr;
+	} else
+		bp->pgno = *pgnoaddr = mp->npages++;
+
+	bp->flags = MPOOL_PINNED | MPOOL_INUSE;
+
+	head = &mp->hqh[HASHKEY(bp->pgno)];
+	CIRCLEQ_INSERT_HEAD(head, bp, hq);
+	CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q);
+	return (bp->page);
+}
+
+int
+mpool_delete(mp, page)
+	MPOOL *mp;
+	void *page;
+{
+	struct _hqh *head;
+	BKT *bp;
+
+	bp = (BKT *)((char *)page - sizeof(BKT));
+
+#ifdef DEBUG
+	if (!(bp->flags & MPOOL_PINNED)) {
+		(void)fprintf(stderr,
+		    "mpool_delete: page %d not pinned\n", bp->pgno);
+		abort();
+	}
+#endif
+
+	/* Remove from the hash and lru queues. */
+	head = &mp->hqh[HASHKEY(bp->pgno)];
+	CIRCLEQ_REMOVE(head, bp, hq);
+	CIRCLEQ_REMOVE(&mp->lqh, bp, q);
+
+	free(bp);
+	return (RET_SUCCESS);
+}	
+	
+/*
+ * mpool_get
+ *	Get a page.
+ */
+void *
+mpool_get(mp, pgno, flags)
+	MPOOL *mp;
+	db_pgno_t pgno;
+	u_int flags;				/* XXX not used? */
+{
+	struct _hqh *head;
+	BKT *bp;
+	off_t off;
+	int nr;
+
+#ifdef STATISTICS
+	++mp->pageget;
+#endif
+
+	/* Check for a page that is cached. */
+	if ((bp = mpool_look(mp, pgno)) != NULL) {
+#ifdef DEBUG
+		if (!(flags & MPOOL_IGNOREPIN) && bp->flags & MPOOL_PINNED) {
+			(void)fprintf(stderr,
+			    "mpool_get: page %d already pinned\n", bp->pgno);
+			abort();
+		}
+#endif
+		/*
+		 * Move the page to the head of the hash chain and the tail
+		 * of the lru chain.
+		 */
+		head = &mp->hqh[HASHKEY(bp->pgno)];
+		CIRCLEQ_REMOVE(head, bp, hq);
+		CIRCLEQ_INSERT_HEAD(head, bp, hq);
+		CIRCLEQ_REMOVE(&mp->lqh, bp, q);
+		CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q);
+
+		/* Return a pinned page. */
+		bp->flags |= MPOOL_PINNED;
+		return (bp->page);
+	}
+
+	/* Get a page from the cache. */
+	if ((bp = mpool_bkt(mp)) == NULL)
+		return (NULL);
+
+	/* Read in the contents. */
+#ifdef STATISTICS
+	++mp->pageread;
+#endif
+	off = mp->pagesize * pgno;
+	if (off / mp->pagesize != pgno) {
+	    /* Run past the end of the file, or at least the part we
+	       can address without large-file support?  */
+	    errno = E2BIG;
+	    return NULL;
+	}
+	if (lseek(mp->fd, off, SEEK_SET) != off)
+		return (NULL);
+
+	if ((nr = read(mp->fd, bp->page, mp->pagesize)) != mp->pagesize) {
+		if (nr > 0) {
+			/* A partial read is definitely bad. */
+			errno = EINVAL;
+			return (NULL);
+		} else {
+			/*
+			 * A zero-length reads, means you need to create a
+			 * new page.
+			 */
+			memset(bp->page, 0, mp->pagesize);
+		}
+	}
+
+	/* Set the page number, pin the page. */
+	bp->pgno = pgno;
+	if (!(flags & MPOOL_IGNOREPIN))
+		bp->flags = MPOOL_PINNED;
+	bp->flags |= MPOOL_INUSE;
+
+	/*
+	 * Add the page to the head of the hash chain and the tail
+	 * of the lru chain.
+	 */
+	head = &mp->hqh[HASHKEY(bp->pgno)];
+	CIRCLEQ_INSERT_HEAD(head, bp, hq);
+	CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q);
+
+	/* Run through the user's filter. */
+	if (mp->pgin != NULL)
+		(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
+
+	return (bp->page);
+}
+
+/*
+ * mpool_put
+ *	Return a page.
+ */
+int
+mpool_put(mp, page, flags)
+	MPOOL *mp;
+	void *page;
+	u_int flags;
+{
+	BKT *bp;
+
+#ifdef STATISTICS
+	++mp->pageput;
+#endif
+	bp = (BKT *)((char *)page - sizeof(BKT));
+#ifdef DEBUG
+	if (!(bp->flags & MPOOL_PINNED)) {
+		(void)fprintf(stderr,
+		    "mpool_put: page %d not pinned\n", bp->pgno);
+		abort();
+	}
+#endif
+	bp->flags &= ~MPOOL_PINNED;
+	if (flags & MPOOL_DIRTY)
+		bp->flags |= flags & MPOOL_DIRTY;
+	return (RET_SUCCESS);
+}
+
+/*
+ * mpool_close
+ *	Close the buffer pool.
+ */
+int
+mpool_close(mp)
+	MPOOL *mp;
+{
+	BKT *bp;
+
+	/* Free up any space allocated to the lru pages. */
+	while ((bp = mp->lqh.cqh_first) != (void *)&mp->lqh) {
+		CIRCLEQ_REMOVE(&mp->lqh, mp->lqh.cqh_first, q);
+		free(bp);
+	}
+
+	/* Free the MPOOL cookie. */
+	free(mp);
+	return (RET_SUCCESS);
+}
+
+/*
+ * mpool_sync
+ *	Sync the pool to disk.
+ */
+int
+mpool_sync(mp)
+	MPOOL *mp;
+{
+	BKT *bp;
+
+	/* Walk the lru chain, flushing any dirty pages to disk. */
+	for (bp = mp->lqh.cqh_first;
+	    bp != (void *)&mp->lqh; bp = bp->q.cqe_next)
+		if (bp->flags & MPOOL_DIRTY &&
+		    mpool_write(mp, bp) == RET_ERROR)
+			return (RET_ERROR);
+
+	/* Sync the file descriptor. */
+	return (fsync(mp->fd) ? RET_ERROR : RET_SUCCESS);
+}
+
+/*
+ * mpool_bkt
+ *	Get a page from the cache (or create one).
+ */
+static BKT *
+mpool_bkt(mp)
+	MPOOL *mp;
+{
+	struct _hqh *head;
+	BKT *bp;
+
+	/* If under the max cached, always create a new page. */
+	if (mp->curcache < mp->maxcache)
+		goto new;
+
+	/*
+	 * If the cache is max'd out, walk the lru list for a buffer we
+	 * can flush.  If we find one, write it (if necessary) and take it
+	 * off any lists.  If we don't find anything we grow the cache anyway.
+	 * The cache never shrinks.
+	 */
+	for (bp = mp->lqh.cqh_first;
+	    bp != (void *)&mp->lqh; bp = bp->q.cqe_next)
+		if (!(bp->flags & MPOOL_PINNED)) {
+			/* Flush if dirty. */
+			if (bp->flags & MPOOL_DIRTY &&
+			    mpool_write(mp, bp) == RET_ERROR)
+				return (NULL);
+#ifdef STATISTICS
+			++mp->pageflush;
+#endif
+			/* Remove from the hash and lru queues. */
+			head = &mp->hqh[HASHKEY(bp->pgno)];
+			CIRCLEQ_REMOVE(head, bp, hq);
+			CIRCLEQ_REMOVE(&mp->lqh, bp, q);
+#ifdef DEBUG
+			{ void *spage;
+				spage = bp->page;
+				memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
+				bp->page = spage;
+			}
+#endif
+			bp->flags = 0;
+			return (bp);
+		}
+
+new:	if ((bp = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL)
+		return (NULL);
+#ifdef STATISTICS
+	++mp->pagealloc;
+#endif
+#if defined(DEBUG) || defined(PURIFY)
+	memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
+#endif
+	bp->page = (char *)bp + sizeof(BKT);
+	bp->flags = 0;
+	++mp->curcache;
+	return (bp);
+}
+
+/*
+ * mpool_write
+ *	Write a page to disk.
+ */
+static int
+mpool_write(mp, bp)
+	MPOOL *mp;
+	BKT *bp;
+{
+	off_t off;
+
+#ifdef STATISTICS
+	++mp->pagewrite;
+#endif
+
+	/* Run through the user's filter. */
+	if (mp->pgout)
+		(mp->pgout)(mp->pgcookie, bp->pgno, bp->page);
+
+	off = mp->pagesize * bp->pgno;
+	if (off / mp->pagesize != bp->pgno) {
+	    /* Run past the end of the file, or at least the part we
+	       can address without large-file support?  */
+	    errno = E2BIG;
+	    return RET_ERROR;
+	}
+	if (lseek(mp->fd, off, SEEK_SET) != off)
+		return (RET_ERROR);
+	if (write(mp->fd, bp->page, mp->pagesize) != mp->pagesize)
+		return (RET_ERROR);
+
+	bp->flags &= ~MPOOL_DIRTY;
+	return (RET_SUCCESS);
+}
+
+/*
+ * mpool_look
+ *	Lookup a page in the cache.
+ */
+static BKT *
+mpool_look(mp, pgno)
+	MPOOL *mp;
+	db_pgno_t pgno;
+{
+	struct _hqh *head;
+	BKT *bp;
+
+	head = &mp->hqh[HASHKEY(pgno)];
+	for (bp = head->cqh_first; bp != (void *)head; bp = bp->hq.cqe_next)
+		if ((bp->pgno == pgno) &&
+			(bp->flags & MPOOL_INUSE == MPOOL_INUSE)) {
+#ifdef STATISTICS
+			++mp->cachehit;
+#endif
+			return (bp);
+		}
+#ifdef STATISTICS
+	++mp->cachemiss;
+#endif
+	return (NULL);
+}
+
+#ifdef STATISTICS
+/*
+ * mpool_stat
+ *	Print out cache statistics.
+ */
+void
+mpool_stat(mp)
+	MPOOL *mp;
+{
+	BKT *bp;
+	int cnt;
+	char *sep;
+
+	(void)fprintf(stderr, "%lu pages in the file\n", mp->npages);
+	(void)fprintf(stderr,
+	    "page size %lu, cacheing %lu pages of %lu page max cache\n",
+	    mp->pagesize, mp->curcache, mp->maxcache);
+	(void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n",
+	    mp->pageput, mp->pageget, mp->pagenew);
+	(void)fprintf(stderr, "%lu page allocs, %lu page flushes\n",
+	    mp->pagealloc, mp->pageflush);
+	if (mp->cachehit + mp->cachemiss)
+		(void)fprintf(stderr,
+		    "%.0f%% cache hit rate (%lu hits, %lu misses)\n", 
+		    ((double)mp->cachehit / (mp->cachehit + mp->cachemiss))
+		    * 100, mp->cachehit, mp->cachemiss);
+	(void)fprintf(stderr, "%lu page reads, %lu page writes\n",
+	    mp->pageread, mp->pagewrite);
+
+	sep = "";
+	cnt = 0;
+	for (bp = mp->lqh.cqh_first;
+	    bp != (void *)&mp->lqh; bp = bp->q.cqe_next) {
+		(void)fprintf(stderr, "%s%d", sep, bp->pgno);
+		if (bp->flags & MPOOL_DIRTY)
+			(void)fprintf(stderr, "d");
+		if (bp->flags & MPOOL_PINNED)
+			(void)fprintf(stderr, "P");
+		if (++cnt == 10) {
+			sep = "\n";
+			cnt = 0;
+		} else
+			sep = ", ";
+			
+	}
+	(void)fprintf(stderr, "\n");
+}
+#endif
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/mpool/mpool.h b/mechglue/src/plugins/kdb/db2/libdb2/mpool/mpool.h
new file mode 100644
index 000000000..627ad5b36
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/mpool/mpool.h
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)mpool.h	8.4 (Berkeley) 11/2/95
+ */
+
+#include "db-queue.h"
+
+/*
+ * The memory pool scheme is a simple one.  Each in-memory page is referenced
+ * by a bucket which is threaded in up to two of three ways.  All active pages
+ * are threaded on a hash chain (hashed by page number) and an lru chain.
+ * Inactive pages are threaded on a free chain.  Each reference to a memory
+ * pool is handed an opaque MPOOL cookie which stores all of this information.
+ */
+#define	HASHSIZE	128
+#define	HASHKEY(pgno)	((pgno - 1) % HASHSIZE)
+
+/* The BKT structures are the elements of the queues. */
+typedef struct _bkt {
+	CIRCLEQ_ENTRY(_bkt) hq;		/* hash queue */
+	CIRCLEQ_ENTRY(_bkt) q;		/* lru queue */
+	void    *page;			/* page */
+	db_pgno_t   pgno;			/* page number */
+
+#define	MPOOL_DIRTY	0x01		/* page needs to be written */
+#define	MPOOL_PINNED	0x02		/* page is pinned into memory */
+#define	MPOOL_INUSE	0x04		/* page address is valid */
+	u_int8_t flags;			/* flags */
+} BKT;
+
+typedef struct MPOOL {
+	CIRCLEQ_HEAD(_lqh, _bkt) lqh;	/* lru queue head */
+					/* hash queue array */
+	CIRCLEQ_HEAD(_hqh, _bkt) hqh[HASHSIZE];
+	db_pgno_t	curcache;		/* current number of cached pages */
+	db_pgno_t	maxcache;		/* max number of cached pages */
+	db_pgno_t	npages;			/* number of pages in the file */
+	u_long	pagesize;		/* file page size */
+	int	fd;			/* file descriptor */
+					/* page in conversion routine */
+	void    (*pgin) __P((void *, db_pgno_t, void *));
+					/* page out conversion routine */
+	void    (*pgout) __P((void *, db_pgno_t, void *));
+	void	*pgcookie;		/* cookie for page in/out routines */
+#ifdef STATISTICS
+	u_long	cachehit;
+	u_long	cachemiss;
+	u_long	pagealloc;
+	u_long	pageflush;
+	u_long	pageget;
+	u_long	pagenew;
+	u_long	pageput;
+	u_long	pageread;
+	u_long	pagewrite;
+#endif
+} MPOOL;
+
+#define	MPOOL_IGNOREPIN	0x01		/* Ignore if the page is pinned. */
+#define	MPOOL_PAGE_REQUEST	0x01	/* Allocate a new page with a
+					   specific page number. */
+#define	MPOOL_PAGE_NEXT		0x02	/* Allocate a new page with the next
+					  page number. */
+
+#define mpool_open	kdb2_mpool_open
+#define mpool_filter	kdb2_mpool_filter
+#define mpool_new	kdb2_mpool_new
+#define mpool_get	kdb2_mpool_get
+#define mpool_delete	kdb2_mpool_delete
+#define mpool_put	kdb2_mpool_put
+#define mpool_sync	kdb2_mpool_sync
+#define mpool_close	kdb2_mpool_close
+#define mpool_stat	kdb2_mpool_stat
+
+__BEGIN_DECLS
+MPOOL	*mpool_open __P((void *, int, db_pgno_t, db_pgno_t));
+void	 mpool_filter __P((MPOOL *, void (*)(void *, db_pgno_t, void *),
+	    void (*)(void *, db_pgno_t, void *), void *));
+void	*mpool_new __P((MPOOL *, db_pgno_t *, u_int));
+void	*mpool_get __P((MPOOL *, db_pgno_t, u_int));
+int	 mpool_delete __P((MPOOL *, void *));
+int	 mpool_put __P((MPOOL *, void *, u_int));
+int	 mpool_sync __P((MPOOL *));
+int	 mpool_close __P((MPOOL *));
+#ifdef STATISTICS
+void	 mpool_stat __P((MPOOL *));
+#endif
+__END_DECLS
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/Makefile.in b/mechglue/src/plugins/kdb/db2/libdb2/recno/Makefile.in
new file mode 100644
index 000000000..4d6b9a508
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/Makefile.in
@@ -0,0 +1,13 @@
+thisconfigdir=./..
+myfulldir=plugins/kdb/db2/libdb2/recno
+mydir=recno
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..$(S)..
+STLIBOBJS=	rec_close.o rec_delete.o rec_get.o rec_open.o rec_put.o \
+		rec_search.o rec_seq.o rec_utils.o
+
+LOCALINCLUDES=	-I. -I$(srcdir)/../include -I../include -I$(srcdir)/../mpool \
+		-I$(srcdir)/../db
+
+all-unix:: all-libobjs
+clean-unix:: clean-libobjs
+# @libobj_frag@
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/Makefile.inc b/mechglue/src/plugins/kdb/db2/libdb2/recno/Makefile.inc
new file mode 100644
index 000000000..e49e22552
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/Makefile.inc
@@ -0,0 +1,6 @@
+#       @(#)Makefile.inc	8.1 (Berkeley) 6/4/93
+
+.PATH: ${.CURDIR}/db/recno
+
+SRCS+=	rec_close.c rec_delete.c rec_get.c rec_open.c rec_put.c rec_search.c \
+	rec_seq.c rec_utils.c
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/extern.h b/mechglue/src/plugins/kdb/db2/libdb2/recno/extern.h
new file mode 100644
index 000000000..98e382c37
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/extern.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.3 (Berkeley) 6/4/94
+ */
+
+#include "../btree/extern.h"
+
+#define __rec_close	__kdb2_rec_close
+#define __rec_delete	__kdb2_rec_delete
+#define __rec_dleaf	__kdb2_rec_dleaf
+#define __rec_fd	__kdb2_rec_fd
+#define __rec_fmap	__kdb2_rec_fmap
+#define __rec_fout	__kdb2_rec_fout
+#define __rec_fpipe	__kdb2_rec_fpipe
+#define __rec_get	__kdb2_rec_get
+#define __rec_iput	__kdb2_rec_iput
+#define __rec_put	__kdb2_rec_put
+#define __rec_ret	__kdb2_rec_ret
+#define __rec_search	__kdb2_rec_search
+#define __rec_seq	__kdb2_rec_seq
+#define __rec_sync	__kdb2_rec_sync
+#define __rec_vmap	__kdb2_rec_vmap
+#define __rec_vout	__kdb2_rec_vout
+#define __rec_vpipe	__kdb2_rec_vpipe
+
+int	 __rec_close __P((DB *));
+int	 __rec_delete __P((const DB *, const DBT *, u_int));
+int	 __rec_dleaf __P((BTREE *, PAGE *, u_int32_t));
+int	 __rec_fd __P((const DB *));
+int	 __rec_fmap __P((BTREE *, recno_t));
+int	 __rec_fout __P((BTREE *));
+int	 __rec_fpipe __P((BTREE *, recno_t));
+int	 __rec_get __P((const DB *, const DBT *, DBT *, u_int));
+int	 __rec_iput __P((BTREE *, recno_t, const DBT *, u_int));
+int	 __rec_put __P((const DB *dbp, DBT *, const DBT *, u_int));
+int	 __rec_ret __P((BTREE *, EPG *, recno_t, DBT *, DBT *));
+EPG	*__rec_search __P((BTREE *, recno_t, enum SRCHOP));
+int	 __rec_seq __P((const DB *, DBT *, DBT *, u_int));
+int	 __rec_sync __P((const DB *, u_int));
+int	 __rec_vmap __P((BTREE *, recno_t));
+int	 __rec_vout __P((BTREE *));
+int	 __rec_vpipe __P((BTREE *, recno_t));
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_close.c b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_close.c
new file mode 100644
index 000000000..ed3da6ea4
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_close.c
@@ -0,0 +1,187 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_close.c	8.9 (Berkeley) 11/18/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#ifdef RECNO_USE_MMAP
+#include <sys/mman.h>
+#endif
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "db-int.h"
+#include "recno.h"
+
+/*
+ * __REC_CLOSE -- Close a recno tree.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_close(dbp)
+	DB *dbp;
+{
+	BTREE *t;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	if (__rec_sync(dbp, 0) == RET_ERROR)
+		return (RET_ERROR);
+
+	/* Committed to closing. */
+	status = RET_SUCCESS;
+#ifdef	RECNO_USE_MMAP
+	if (F_ISSET(t, R_MEMMAPPED) && munmap(t->bt_smap, t->bt_msize))
+		status = RET_ERROR;
+#endif
+
+	if (!F_ISSET(t, R_INMEM)) {
+		if (F_ISSET(t, R_CLOSEFP)) {
+			if (fclose(t->bt_rfp))
+				status = RET_ERROR;
+		} else
+			if (close(t->bt_rfd))
+				status = RET_ERROR;
+	}
+
+	if (__bt_close(dbp) == RET_ERROR)
+		status = RET_ERROR;
+
+	return (status);
+}
+
+/*
+ * __REC_SYNC -- sync the recno tree to disk.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ */
+int
+__rec_sync(dbp, flags)
+	const DB *dbp;
+	u_int flags;
+{
+	struct iovec iov[2];
+	BTREE *t;
+	DBT data, key;
+	off_t off;
+	recno_t scursor, trec;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	if (flags == R_RECNOSYNC)
+		return (__bt_sync(dbp, 0));
+
+	if (F_ISSET(t, R_RDONLY | R_INMEM) || !F_ISSET(t, R_MODIFIED))
+		return (RET_SUCCESS);
+
+	/* Read any remaining records into the tree. */
+	if (!F_ISSET(t, R_EOF) && t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
+		return (RET_ERROR);
+
+	/* Rewind the file descriptor. */
+	if (lseek(t->bt_rfd, (off_t)0, SEEK_SET) != 0)
+		return (RET_ERROR);
+
+	/* Save the cursor. */
+	scursor = t->bt_cursor.rcursor;
+
+	key.size = sizeof(recno_t);
+	key.data = &trec;
+
+	if (F_ISSET(t, R_FIXLEN)) {
+		/*
+		 * We assume that fixed length records are all fixed length.
+		 * Any that aren't are either EINVAL'd or corrected by the
+		 * record put code.
+		 */
+		status = (dbp->seq)(dbp, &key, &data, R_FIRST);
+		while (status == RET_SUCCESS) {
+			if (write(t->bt_rfd, data.data, data.size) != data.size)
+				return (RET_ERROR);
+			status = (dbp->seq)(dbp, &key, &data, R_NEXT);
+		}
+	} else {
+		iov[1].iov_base = &t->bt_bval;
+		iov[1].iov_len = 1;
+
+		status = (dbp->seq)(dbp, &key, &data, R_FIRST);
+		while (status == RET_SUCCESS) {
+			iov[0].iov_base = data.data;
+			iov[0].iov_len = data.size;
+			if (writev(t->bt_rfd, iov, 2) != data.size + 1)
+				return (RET_ERROR);
+			status = (dbp->seq)(dbp, &key, &data, R_NEXT);
+		}
+	}
+
+	/* Restore the cursor. */
+	t->bt_cursor.rcursor = scursor;
+
+	if (status == RET_ERROR)
+		return (RET_ERROR);
+	if ((off = lseek(t->bt_rfd, (off_t)0, SEEK_CUR)) == -1)
+		return (RET_ERROR);
+	if (ftruncate(t->bt_rfd, off))
+		return (RET_ERROR);
+	F_CLR(t, R_MODIFIED);
+	return (RET_SUCCESS);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_delete.c b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_delete.c
new file mode 100644
index 000000000..b69c9ad74
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_delete.c
@@ -0,0 +1,197 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_delete.c	8.7 (Berkeley) 7/14/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "recno.h"
+
+static int rec_rdelete __P((BTREE *, recno_t));
+
+/*
+ * __REC_DELETE -- Delete the item(s) referenced by a key.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *	key:	key to delete
+ *	flags:	R_CURSOR if deleting what the cursor references
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+int
+__rec_delete(dbp, key, flags)
+	const DB *dbp;
+	const DBT *key;
+	u_int flags;
+{
+	BTREE *t;
+	recno_t nrec;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	switch(flags) {
+	case 0:
+		if ((nrec = *(recno_t *)key->data) == 0)
+			goto einval;
+		if (nrec > t->bt_nrecs)
+			return (RET_SPECIAL);
+		--nrec;
+		status = rec_rdelete(t, nrec);
+		break;
+	case R_CURSOR:
+		if (!F_ISSET(&t->bt_cursor, CURS_INIT))
+			goto einval;
+		if (t->bt_nrecs == 0)
+			return (RET_SPECIAL);
+		status = rec_rdelete(t, t->bt_cursor.rcursor - 1);
+		if (status == RET_SUCCESS)
+			--t->bt_cursor.rcursor;
+		break;
+	default:
+einval:		errno = EINVAL;
+		return (RET_ERROR);
+	}
+
+	if (status == RET_SUCCESS)
+		F_SET(t, B_MODIFIED | R_MODIFIED);
+	return (status);
+}
+
+/*
+ * REC_RDELETE -- Delete the data matching the specified key.
+ *
+ * Parameters:
+ *	tree:	tree
+ *	nrec:	record to delete
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+static int
+rec_rdelete(t, nrec)
+	BTREE *t;
+	recno_t nrec;
+{
+	EPG *e;
+	PAGE *h;
+	int status;
+
+	/* Find the record; __rec_search pins the page. */
+	if ((e = __rec_search(t, nrec, SDELETE)) == NULL)
+		return (RET_ERROR);
+
+	/* Delete the record. */
+	h = e->page;
+	status = __rec_dleaf(t, h, e->index);
+	if (status != RET_SUCCESS) {
+		mpool_put(t->bt_mp, h, 0);
+		return (status);
+	}
+	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+	return (RET_SUCCESS);
+}
+
+/*
+ * __REC_DLEAF -- Delete a single record from a recno leaf page.
+ *
+ * Parameters:
+ *	t:	tree
+ *	idx:	index on current page to delete
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ */
+int
+__rec_dleaf(t, h, idx)
+	BTREE *t;
+	PAGE *h;
+	u_int32_t idx;
+{
+	RLEAF *rl;
+	indx_t *ip, cnt, offset;
+	u_int32_t nbytes;
+	char *from;
+	void *to;
+
+	/*
+	 * Delete a record from a recno leaf page.  Internal records are never
+	 * deleted from internal pages, regardless of the records that caused
+	 * them to be added being deleted.  Pages made empty by deletion are
+	 * not reclaimed.  They are, however, made available for reuse.
+	 *
+	 * Pack the remaining entries at the end of the page, shift the indices
+	 * down, overwriting the deleted record and its index.  If the record
+	 * uses overflow pages, make them available for reuse.
+	 */
+	to = rl = GETRLEAF(h, idx);
+	if (rl->flags & P_BIGDATA && __ovfl_delete(t, rl->bytes) == RET_ERROR)
+		return (RET_ERROR);
+	nbytes = NRLEAF(rl);
+
+	/*
+	 * Compress the key/data pairs.  Compress and adjust the [BR]LEAF
+	 * offsets.  Reset the headers.
+	 */
+	from = (char *)h + h->upper;
+	memmove(from + nbytes, from, (char *)to - from);
+	h->upper += nbytes;
+
+	offset = h->linp[idx];
+	for (cnt = &h->linp[idx] - (ip = &h->linp[0]); cnt--; ++ip)
+		if (ip[0] < offset)
+			ip[0] += nbytes;
+	for (cnt = &h->linp[NEXTINDEX(h)] - ip; --cnt; ++ip)
+		ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
+	h->lower -= sizeof(indx_t);
+	--t->bt_nrecs;
+	return (RET_SUCCESS);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_get.c b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_get.c
new file mode 100644
index 000000000..230b2d4f5
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_get.c
@@ -0,0 +1,311 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_get.c	8.9 (Berkeley) 8/18/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "db-int.h"
+#include "recno.h"
+
+/*
+ * __REC_GET -- Get a record from the btree.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *	key:	key to find
+ *	data:	data to return
+ *	flag:	currently unused
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+int
+__rec_get(dbp, key, data, flags)
+	const DB *dbp;
+	const DBT *key;
+	DBT *data;
+	u_int flags;
+{
+	BTREE *t;
+	EPG *e;
+	recno_t nrec;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/* Get currently doesn't take any flags, and keys of 0 are illegal. */
+	if (flags || (nrec = *(recno_t *)key->data) == 0) {
+		errno = EINVAL;
+		return (RET_ERROR);
+	}
+
+	/*
+	 * If we haven't seen this record yet, try to find it in the
+	 * original file.
+	 */
+	if (nrec > t->bt_nrecs) {
+		if (F_ISSET(t, R_EOF | R_INMEM))
+			return (RET_SPECIAL);
+		if ((status = t->bt_irec(t, nrec)) != RET_SUCCESS)
+			return (status);
+	}
+
+	--nrec;
+	if ((e = __rec_search(t, nrec, SEARCH)) == NULL)
+		return (RET_ERROR);
+
+	status = __rec_ret(t, e, 0, NULL, data);
+	if (F_ISSET(t, B_DB_LOCK))
+		mpool_put(t->bt_mp, e->page, 0);
+	else
+		t->bt_pinned = e->page;
+	return (status);
+}
+
+/*
+ * __REC_FPIPE -- Get fixed length records from a pipe.
+ *
+ * Parameters:
+ *	t:	tree
+ *	cnt:	records to read
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_fpipe(t, top)
+	BTREE *t;
+	recno_t top;
+{
+	DBT data;
+	recno_t nrec;
+	size_t len;
+	int ch;
+	u_char *p;
+
+	if (t->bt_rdata.size < t->bt_reclen) {
+		t->bt_rdata.data = t->bt_rdata.data == NULL ?
+		    malloc(t->bt_reclen) :
+		    realloc(t->bt_rdata.data, t->bt_reclen);
+		if (t->bt_rdata.data == NULL)
+			return (RET_ERROR);
+		t->bt_rdata.size = t->bt_reclen;
+	}
+	data.data = t->bt_rdata.data;
+	data.size = t->bt_reclen;
+
+	for (nrec = t->bt_nrecs; nrec < top;) {
+		len = t->bt_reclen;
+		for (p = t->bt_rdata.data;; *p++ = ch)
+			if ((ch = getc(t->bt_rfp)) == EOF || !--len) {
+				if (ch != EOF)
+					*p = ch;
+				if (len != 0)
+					memset(p, t->bt_bval, len);
+				if (__rec_iput(t,
+				    nrec, &data, 0) != RET_SUCCESS)
+					return (RET_ERROR);
+				++nrec;
+				break;
+			}
+		if (ch == EOF)
+			break;
+	}
+	if (nrec < top) {
+		F_SET(t, R_EOF);
+		return (RET_SPECIAL);
+	}
+	return (RET_SUCCESS);
+}
+
+/*
+ * __REC_VPIPE -- Get variable length records from a pipe.
+ *
+ * Parameters:
+ *	t:	tree
+ *	cnt:	records to read
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_vpipe(t, top)
+	BTREE *t;
+	recno_t top;
+{
+	DBT data;
+	recno_t nrec;
+	indx_t len;
+	size_t sz;
+	int bval, ch;
+	u_char *p;
+
+	bval = t->bt_bval;
+	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
+		for (p = t->bt_rdata.data,
+		    sz = t->bt_rdata.size;; *p++ = ch, --sz) {
+			if ((ch = getc(t->bt_rfp)) == EOF || ch == bval) {
+				data.data = t->bt_rdata.data;
+				data.size = p - (u_char *)t->bt_rdata.data;
+				if (ch == EOF && data.size == 0)
+					break;
+				if (__rec_iput(t, nrec, &data, 0)
+				    != RET_SUCCESS)
+					return (RET_ERROR);
+				break;
+			}
+			if (sz == 0) {
+				len = p - (u_char *)t->bt_rdata.data;
+				t->bt_rdata.size += (sz = 256);
+				t->bt_rdata.data = t->bt_rdata.data == NULL ?
+				    malloc(t->bt_rdata.size) :
+				    realloc(t->bt_rdata.data, t->bt_rdata.size);
+				if (t->bt_rdata.data == NULL)
+					return (RET_ERROR);
+				p = (u_char *)t->bt_rdata.data + len;
+			}
+		}
+		if (ch == EOF)
+			break;
+	}
+	if (nrec < top) {
+		F_SET(t, R_EOF);
+		return (RET_SPECIAL);
+	}
+	return (RET_SUCCESS);
+}
+
+/*
+ * __REC_FMAP -- Get fixed length records from a file.
+ *
+ * Parameters:
+ *	t:	tree
+ *	cnt:	records to read
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_fmap(t, top)
+	BTREE *t;
+	recno_t top;
+{
+	DBT data;
+	recno_t nrec;
+	u_char *sp, *ep, *p;
+	size_t len;
+
+	if (t->bt_rdata.size < t->bt_reclen) {
+		t->bt_rdata.data = t->bt_rdata.data == NULL ?
+		    malloc(t->bt_reclen) :
+		    realloc(t->bt_rdata.data, t->bt_reclen);
+		if (t->bt_rdata.data == NULL)
+			return (RET_ERROR);
+		t->bt_rdata.size = t->bt_reclen;
+	}
+	data.data = t->bt_rdata.data;
+	data.size = t->bt_reclen;
+
+	sp = (u_char *)t->bt_cmap;
+	ep = (u_char *)t->bt_emap;
+	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
+		if (sp >= ep) {
+			F_SET(t, R_EOF);
+			return (RET_SPECIAL);
+		}
+		len = t->bt_reclen;
+		for (p = t->bt_rdata.data;
+		    sp < ep && len > 0; *p++ = *sp++, --len);
+		if (len != 0)
+			memset(p, t->bt_bval, len);
+		if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
+			return (RET_ERROR);
+	}
+	t->bt_cmap = (caddr_t)sp;
+	return (RET_SUCCESS);
+}
+
+/*
+ * __REC_VMAP -- Get variable length records from a file.
+ *
+ * Parameters:
+ *	t:	tree
+ *	cnt:	records to read
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_vmap(t, top)
+	BTREE *t;
+	recno_t top;
+{
+	DBT data;
+	u_char *sp, *ep;
+	recno_t nrec;
+	int bval;
+
+	sp = (u_char *)t->bt_cmap;
+	ep = (u_char *)t->bt_emap;
+	bval = t->bt_bval;
+
+	for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
+		if (sp >= ep) {
+			F_SET(t, R_EOF);
+			return (RET_SPECIAL);
+		}
+		for (data.data = sp; sp < ep && *sp != bval; ++sp);
+		data.size = sp - (u_char *)data.data;
+		if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
+			return (RET_ERROR);
+		++sp;
+	}
+	t->bt_cmap = (caddr_t)sp;
+	return (RET_SUCCESS);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_open.c b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_open.c
new file mode 100644
index 000000000..f18a1cb02
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_open.c
@@ -0,0 +1,243 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_open.c	8.12 (Berkeley) 11/18/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#ifdef RECNO_USE_MMAP
+#include <sys/mman.h>
+#endif
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "db-int.h"
+#include "recno.h"
+
+DB *
+__rec_open(fname, flags, mode, openinfo, dflags)
+	const char *fname;
+	int flags, mode, dflags;
+	const RECNOINFO *openinfo;
+{
+	BTREE *t;
+	BTREEINFO btopeninfo;
+	DB *dbp;
+	PAGE *h;
+	struct stat sb;
+	int rfd, sverrno;
+
+	/* Open the user's file -- if this fails, we're done. */
+	if (fname != NULL && (rfd = open(fname, flags | O_BINARY, mode)) < 0)
+		return (NULL);
+
+	/* Create a btree in memory (backed by disk). */
+	dbp = NULL;
+	if (openinfo) {
+		if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
+			goto einval;
+		btopeninfo.flags = 0;
+		btopeninfo.cachesize = openinfo->cachesize;
+		btopeninfo.maxkeypage = 0;
+		btopeninfo.minkeypage = 0;
+		btopeninfo.psize = openinfo->psize;
+		btopeninfo.compare = NULL;
+		btopeninfo.prefix = NULL;
+		btopeninfo.lorder = openinfo->lorder;
+		dbp = __bt_open(openinfo->bfname,
+		    O_RDWR | O_BINARY, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
+	} else
+		dbp = __bt_open(NULL, O_RDWR | O_BINARY, S_IRUSR | S_IWUSR, NULL, dflags);
+	if (dbp == NULL)
+		goto err;
+
+	/*
+	 * Some fields in the tree structure are recno specific.  Fill them
+	 * in and make the btree structure look like a recno structure.  We
+	 * don't change the bt_ovflsize value, it's close enough and slightly
+	 * bigger.
+	 */
+	t = dbp->internal;
+	if (openinfo) {
+		if (openinfo->flags & R_FIXEDLEN) {
+			F_SET(t, R_FIXLEN);
+			t->bt_reclen = openinfo->reclen;
+			if (t->bt_reclen == 0)
+				goto einval;
+		}
+		t->bt_bval = openinfo->bval;
+	} else
+		t->bt_bval = '\n';
+
+	F_SET(t, R_RECNO);
+	if (fname == NULL)
+		F_SET(t, R_EOF | R_INMEM);
+	else
+		t->bt_rfd = rfd;
+
+	if (fname != NULL) {
+		/*
+		 * In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
+		 * Unfortunately, that's not portable, so we use lseek
+		 * and check the errno values.
+		 */
+		errno = 0;
+		if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
+			switch (flags & O_ACCMODE) {
+			case O_RDONLY:
+				F_SET(t, R_RDONLY);
+				break;
+			default:
+				goto einval;
+			}
+slow:			if ((t->bt_rfp = fdopen(rfd, "rb")) == NULL)
+				goto err;
+			F_SET(t, R_CLOSEFP);
+			t->bt_irec =
+			    F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
+		} else {
+			switch (flags & O_ACCMODE) {
+			case O_RDONLY:
+				F_SET(t, R_RDONLY);
+				break;
+			case O_RDWR:
+				break;
+			default:
+				goto einval;
+			}
+
+			if (fstat(rfd, &sb))
+				goto err;
+			/*
+			 * Kluge -- we'd like to test to see if the file is too
+			 * big to mmap.  Since, we don't know what size or type
+			 * off_t's or size_t's are, what the largest unsigned
+			 * integral type is, or what random insanity the local
+			 * C compiler will perpetrate, doing the comparison in
+			 * a portable way is flatly impossible.  Hope that mmap
+			 * fails if the file is too large.
+			 */
+			if (sb.st_size == 0)
+				F_SET(t, R_EOF);
+			else {
+#ifdef RECNO_USE_MMAP
+				/*
+				 * XXX
+				 * Mmap doesn't work correctly on many current
+				 * systems.  In particular, it can fail subtly,
+				 * with cache coherency problems.  Don't use it
+				 * for now.
+				 */
+				t->bt_msize = sb.st_size;
+				if ((t->bt_smap = mmap(NULL, t->bt_msize,
+				    PROT_READ, MAP_PRIVATE, rfd,
+				    (off_t)0)) == (caddr_t)-1)
+					goto slow;
+				t->bt_cmap = t->bt_smap;
+				t->bt_emap = t->bt_smap + sb.st_size;
+				t->bt_irec = F_ISSET(t, R_FIXLEN) ?
+				    __rec_fmap : __rec_vmap;
+				F_SET(t, R_MEMMAPPED);
+#else
+				goto slow;
+#endif
+			}
+		}
+	}
+
+	/* Use the recno routines. */
+	dbp->close = __rec_close;
+	dbp->del = __rec_delete;
+	dbp->fd = __rec_fd;
+	dbp->get = __rec_get;
+	dbp->put = __rec_put;
+	dbp->seq = __rec_seq;
+	dbp->sync = __rec_sync;
+
+	/* If the root page was created, reset the flags. */
+	if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
+		goto err;
+	if ((h->flags & P_TYPE) == P_BLEAF) {
+		F_CLR(h, P_TYPE);
+		F_SET(h, P_RLEAF);
+		mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+	} else
+		mpool_put(t->bt_mp, h, 0);
+
+	if (openinfo && openinfo->flags & R_SNAPSHOT &&
+	    !F_ISSET(t, R_EOF | R_INMEM) &&
+	    t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
+                goto err;
+	return (dbp);
+
+einval:	errno = EINVAL;
+err:	sverrno = errno;
+	if (dbp != NULL)
+		(void)__bt_close(dbp);
+	if (fname != NULL)
+		(void)close(rfd);
+	errno = sverrno;
+	return (NULL);
+}
+
+int
+__rec_fd(dbp)
+	const DB *dbp;
+{
+	BTREE *t;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/* In-memory database can't have a file descriptor. */
+	if (F_ISSET(t, R_INMEM)) {
+		errno = ENOENT;
+		return (-1);
+	}
+	return (t->bt_rfd);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_put.c b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_put.c
new file mode 100644
index 000000000..e7fa75882
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_put.c
@@ -0,0 +1,280 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_put.c	8.7 (Berkeley) 8/18/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "recno.h"
+
+/*
+ * __REC_PUT -- Add a recno item to the tree.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *	key:	key
+ *	data:	data
+ *	flag:	R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
+ *	already in the tree and R_NOOVERWRITE specified.
+ */
+int
+__rec_put(dbp, key, data, flags)
+	const DB *dbp;
+	DBT *key;
+	const DBT *data;
+	u_int flags;
+{
+	BTREE *t;
+	DBT fdata, tdata;
+	recno_t nrec;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	/*
+	 * If using fixed-length records, and the record is long, return
+	 * EINVAL.  If it's short, pad it out.  Use the record data return
+	 * memory, it's only short-term.
+	 */
+	if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
+		if (data->size > t->bt_reclen)
+			goto einval;
+
+		if (t->bt_rdata.size < t->bt_reclen) {
+			t->bt_rdata.data = t->bt_rdata.data == NULL ?
+			    malloc(t->bt_reclen) :
+			    realloc(t->bt_rdata.data, t->bt_reclen);
+			if (t->bt_rdata.data == NULL)
+				return (RET_ERROR);
+			t->bt_rdata.size = t->bt_reclen;
+		}
+		memmove(t->bt_rdata.data, data->data, data->size);
+		memset((char *)t->bt_rdata.data + data->size,
+		    t->bt_bval, t->bt_reclen - data->size);
+		fdata.data = t->bt_rdata.data;
+		fdata.size = t->bt_reclen;
+	} else {
+		fdata.data = data->data;
+		fdata.size = data->size;
+	}
+
+	switch (flags) {
+	case R_CURSOR:
+		if (!F_ISSET(&t->bt_cursor, CURS_INIT))
+			goto einval;
+		nrec = t->bt_cursor.rcursor;
+		break;
+	case R_SETCURSOR:
+		if ((nrec = *(recno_t *)key->data) == 0)
+			goto einval;
+		break;
+	case R_IAFTER:
+		if ((nrec = *(recno_t *)key->data) == 0) {
+			nrec = 1;
+			flags = R_IBEFORE;
+		}
+		break;
+	case 0:
+	case R_IBEFORE:
+		if ((nrec = *(recno_t *)key->data) == 0)
+			goto einval;
+		break;
+	case R_NOOVERWRITE:
+		if ((nrec = *(recno_t *)key->data) == 0)
+			goto einval;
+		if (nrec <= t->bt_nrecs)
+			return (RET_SPECIAL);
+		break;
+	default:
+einval:		errno = EINVAL;
+		return (RET_ERROR);
+	}
+
+	/*
+	 * Make sure that records up to and including the put record are
+	 * already in the database.  If skipping records, create empty ones.
+	 */
+	if (nrec > t->bt_nrecs) {
+		if (!F_ISSET(t, R_EOF | R_INMEM) &&
+		    t->bt_irec(t, nrec) == RET_ERROR)
+			return (RET_ERROR);
+		if (nrec > t->bt_nrecs + 1) {
+			if (F_ISSET(t, R_FIXLEN)) {
+				if ((tdata.data =
+				    (void *)malloc(t->bt_reclen)) == NULL)
+					return (RET_ERROR);
+				tdata.size = t->bt_reclen;
+				memset(tdata.data, t->bt_bval, tdata.size);
+			} else {
+				tdata.data = NULL;
+				tdata.size = 0;
+			}
+			while (nrec > t->bt_nrecs + 1)
+				if (__rec_iput(t,
+				    t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
+					return (RET_ERROR);
+			if (F_ISSET(t, R_FIXLEN))
+				free(tdata.data);
+		}
+	}
+
+	if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
+		return (status);
+
+	if (flags == R_SETCURSOR)
+		t->bt_cursor.rcursor = nrec;
+	
+	F_SET(t, R_MODIFIED);
+	return (__rec_ret(t, NULL, nrec, key, NULL));
+}
+
+/*
+ * __REC_IPUT -- Add a recno item to the tree.
+ *
+ * Parameters:
+ *	t:	tree
+ *	nrec:	record number
+ *	data:	data
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS
+ */
+int
+__rec_iput(t, nrec, data, flags)
+	BTREE *t;
+	recno_t nrec;
+	const DBT *data;
+	u_int flags;
+{
+	DBT tdata;
+	EPG *e;
+	PAGE *h;
+	indx_t idx, nxtindex;
+	db_pgno_t pg;
+	u_int32_t nbytes;
+	int dflags, status;
+	char *dest, db[NOVFLSIZE];
+
+	/*
+	 * If the data won't fit on a page, store it on indirect pages.
+	 *
+	 * XXX
+	 * If the insert fails later on, these pages aren't recovered.
+	 */
+	if (data->size > t->bt_ovflsize) {
+		if (__ovfl_put(t, data, &pg) == RET_ERROR)
+			return (RET_ERROR);
+		tdata.data = db;
+		tdata.size = NOVFLSIZE;
+		*(db_pgno_t *)db = pg;
+		*(u_int32_t *)(db + sizeof(db_pgno_t)) = data->size;
+		dflags = P_BIGDATA;
+		data = &tdata;
+	} else
+		dflags = 0;
+
+	/* __rec_search pins the returned page. */
+	if ((e = __rec_search(t, nrec,
+	    nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
+	    SINSERT : SEARCH)) == NULL)
+		return (RET_ERROR);
+
+	h = e->page;
+	idx = e->index;
+
+	/*
+	 * Add the specified key/data pair to the tree.  The R_IAFTER and
+	 * R_IBEFORE flags insert the key after/before the specified key.
+	 *
+	 * Pages are split as required.
+	 */
+	switch (flags) {
+	case R_IAFTER:
+		++idx;
+		break;
+	case R_IBEFORE:
+		break;
+	default:
+		if (nrec < t->bt_nrecs &&
+		    __rec_dleaf(t, h, idx) == RET_ERROR) {
+			mpool_put(t->bt_mp, h, 0);
+			return (RET_ERROR);
+		}
+		break;
+	}
+
+	/*
+	 * If not enough room, split the page.  The split code will insert
+	 * the key and data and unpin the current page.  If inserting into
+	 * the offset array, shift the pointers up.
+	 */
+	nbytes = NRLEAFDBT(data->size);
+	if (h->upper - h->lower < nbytes + sizeof(indx_t)) {
+		status = __bt_split(t, h, NULL, data, dflags, nbytes, idx);
+		if (status == RET_SUCCESS)
+			++t->bt_nrecs;
+		return (status);
+	}
+
+	if (idx < (nxtindex = NEXTINDEX(h)))
+		memmove(h->linp + idx + 1, h->linp + idx,
+		    (nxtindex - idx) * sizeof(indx_t));
+	h->lower += sizeof(indx_t);
+
+	h->linp[idx] = h->upper -= nbytes;
+	dest = (char *)h + h->upper;
+	WR_RLEAF(dest, data, dflags);
+
+	++t->bt_nrecs;
+	F_SET(t, B_MODIFIED);
+	mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+	return (RET_SUCCESS);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_search.c b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_search.c
new file mode 100644
index 000000000..a328f1be0
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_search.c
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_search.c	8.4 (Berkeley) 7/14/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "db-int.h"
+#include "recno.h"
+
+/*
+ * __REC_SEARCH -- Search a btree for a key.
+ *
+ * Parameters:
+ *	t:	tree to search
+ *	recno:	key to find
+ *	op: 	search operation
+ *
+ * Returns:
+ *	EPG for matching record, if any, or the EPG for the location of the
+ *	key, if it were inserted into the tree.
+ *
+ * Returns:
+ *	The EPG for matching record, if any, or the EPG for the location
+ *	of the key, if it were inserted into the tree, is entered into
+ *	the bt_cur field of the tree.  A pointer to the field is returned.
+ */
+EPG *
+__rec_search(t, recno, op)
+	BTREE *t;
+	recno_t recno;
+	enum SRCHOP op;
+{
+	register indx_t idx;
+	register PAGE *h;
+	EPGNO *parent;
+	RINTERNAL *r;
+	db_pgno_t pg;
+	indx_t top;
+	recno_t total;
+	int sverrno;
+
+	BT_CLR(t);
+	for (pg = P_ROOT, total = 0;;) {
+		if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+			goto err;
+		if (h->flags & P_RLEAF) {
+			t->bt_cur.page = h;
+			t->bt_cur.index = recno - total;
+			return (&t->bt_cur);
+		}
+		for (idx = 0, top = NEXTINDEX(h);;) {
+			r = GETRINTERNAL(h, idx);
+			if (++idx == top || total + r->nrecs > recno)
+				break;
+			total += r->nrecs;
+		}
+
+		BT_PUSH(t, pg, idx - 1);
+		
+		pg = r->pgno;
+		switch (op) {
+		case SDELETE:
+			--GETRINTERNAL(h, (idx - 1))->nrecs;
+			mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+			break;
+		case SINSERT:
+			++GETRINTERNAL(h, (idx - 1))->nrecs;
+			mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+			break;
+		case SEARCH:
+			mpool_put(t->bt_mp, h, 0);
+			break;
+		}
+
+	}
+	/* Try and recover the tree. */
+err:	sverrno = errno;
+	if (op != SEARCH)
+		while  ((parent = BT_POP(t)) != NULL) {
+			if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+				break;
+			if (op == SINSERT)
+				--GETRINTERNAL(h, parent->index)->nrecs;
+			else
+				++GETRINTERNAL(h, parent->index)->nrecs;
+                        mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+                }
+	errno = sverrno;
+	return (NULL);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_seq.c b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_seq.c
new file mode 100644
index 000000000..1edaa998e
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_seq.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_seq.c	8.3 (Berkeley) 7/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "recno.h"
+
+/*
+ * __REC_SEQ -- Recno sequential scan interface.
+ *
+ * Parameters:
+ *	dbp:	pointer to access method
+ *	key:	key for positioning and return value
+ *	data:	data return value
+ *	flags:	R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
+ *
+ * Returns:
+ *	RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+int
+__rec_seq(dbp, key, data, flags)
+	const DB *dbp;
+	DBT *key, *data;
+	u_int flags;
+{
+	BTREE *t;
+	EPG *e;
+	recno_t nrec;
+	int status;
+
+	t = dbp->internal;
+
+	/* Toss any page pinned across calls. */
+	if (t->bt_pinned != NULL) {
+		mpool_put(t->bt_mp, t->bt_pinned, 0);
+		t->bt_pinned = NULL;
+	}
+
+	switch(flags) {
+	case R_CURSOR:
+		if ((nrec = *(recno_t *)key->data) == 0)
+			goto einval;
+		break;
+	case R_NEXT:
+		if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
+			nrec = t->bt_cursor.rcursor + 1;
+			break;
+		}
+		/* FALLTHROUGH */
+	case R_FIRST:
+		nrec = 1;
+		break;
+	case R_PREV:
+		if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
+			if ((nrec = t->bt_cursor.rcursor - 1) == 0)
+				return (RET_SPECIAL);
+			break;
+		}
+		/* FALLTHROUGH */
+	case R_LAST:
+		if (!F_ISSET(t, R_EOF | R_INMEM) &&
+		    t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
+			return (RET_ERROR);
+		nrec = t->bt_nrecs;
+		break;
+	default:
+einval:		errno = EINVAL;
+		return (RET_ERROR);
+	}
+	
+	if (t->bt_nrecs == 0 || nrec > t->bt_nrecs) {
+		if (!F_ISSET(t, R_EOF | R_INMEM) &&
+		    (status = t->bt_irec(t, nrec)) != RET_SUCCESS)
+			return (status);
+		if (t->bt_nrecs == 0 || nrec > t->bt_nrecs)
+			return (RET_SPECIAL);
+	}
+
+	if ((e = __rec_search(t, nrec - 1, SEARCH)) == NULL)
+		return (RET_ERROR);
+
+	F_SET(&t->bt_cursor, CURS_INIT);
+	t->bt_cursor.rcursor = nrec;
+
+	status = __rec_ret(t, e, nrec, key, data);
+	if (F_ISSET(t, B_DB_LOCK))
+		mpool_put(t->bt_mp, e->page, 0);
+	else
+		t->bt_pinned = e->page;
+	return (status);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_utils.c b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_utils.c
new file mode 100644
index 000000000..f757a724f
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/rec_utils.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rec_utils.c	8.6 (Berkeley) 7/16/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db-int.h"
+#include "recno.h"
+
+/*
+ * __rec_ret --
+ *	Build return data.
+ *
+ * Parameters:
+ *	t:	tree
+ *	e:	key/data pair to be returned
+ *   nrec:	record number
+ *    key:	user's key structure
+ *	data:	user's data structure
+ *
+ * Returns:
+ *	RET_SUCCESS, RET_ERROR.
+ */
+int
+__rec_ret(t, e, nrec, key, data)
+	BTREE *t;
+	EPG *e;
+	recno_t nrec;
+	DBT *key, *data;
+{
+	RLEAF *rl;
+	void *p;
+
+	if (key == NULL)
+		goto dataonly;
+
+	/* We have to copy the key, it's not on the page. */
+	if (sizeof(recno_t) > t->bt_rkey.size) {
+		p = (void *)(t->bt_rkey.data == NULL ?
+		    malloc(sizeof(recno_t)) :
+		    realloc(t->bt_rkey.data, sizeof(recno_t)));
+		if (p == NULL)
+			return (RET_ERROR);
+		t->bt_rkey.data = p;
+		t->bt_rkey.size = sizeof(recno_t);
+	}
+	memmove(t->bt_rkey.data, &nrec, sizeof(recno_t));
+	key->size = sizeof(recno_t);
+	key->data = t->bt_rkey.data;
+
+dataonly:
+	if (data == NULL)
+		return (RET_SUCCESS);
+
+	/*
+	 * We must copy big keys/data to make them contigous.  Otherwise,
+	 * leave the page pinned and don't copy unless the user specified
+	 * concurrent access.
+	 */
+	rl = GETRLEAF(e->page, e->index);
+	if (rl->flags & P_BIGDATA) {
+		if (__ovfl_get(t, rl->bytes,
+		    &data->size, &t->bt_rdata.data, &t->bt_rdata.size))
+			return (RET_ERROR);
+		data->data = t->bt_rdata.data;
+	} else if (F_ISSET(t, B_DB_LOCK)) {
+		/* Use +1 in case the first record retrieved is 0 length. */
+		if (rl->dsize + 1 > t->bt_rdata.size) {
+			p = (void *)(t->bt_rdata.data == NULL ?
+			    malloc(rl->dsize + 1) :
+			    realloc(t->bt_rdata.data, rl->dsize + 1));
+			if (p == NULL)
+				return (RET_ERROR);
+			t->bt_rdata.data = p;
+			t->bt_rdata.size = rl->dsize + 1;
+		}
+		memmove(t->bt_rdata.data, rl->bytes, rl->dsize);
+		data->size = rl->dsize;
+		data->data = t->bt_rdata.data;
+	} else {
+		data->size = rl->dsize;
+		data->data = rl->bytes;
+	}
+	return (RET_SUCCESS);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/recno/recno.h b/mechglue/src/plugins/kdb/db2/libdb2/recno/recno.h
new file mode 100644
index 000000000..bec772c2f
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/recno/recno.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)recno.h	8.1 (Berkeley) 6/4/93
+ */
+
+enum SRCHOP { SDELETE, SINSERT, SEARCH};	/* Rec_search operation. */
+
+#include "../btree/btree.h"
+#include "extern.h"
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/ChangeLog b/mechglue/src/plugins/kdb/db2/libdb2/test/ChangeLog
new file mode 100644
index 000000000..91d5c1f6d
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/ChangeLog
@@ -0,0 +1,85 @@
+2005-12-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (PROG_LIBPATH, DB_DEPLIB): Look for library in
+	.. instead of $TOPLIBD.
+	(myfulldir): Updated for directory rename.
+
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (BUILDTOP, myfulldir): Updated for directory move.
+	(DB_LIB, DB_DEPLIB): Define here now.
+
+2004-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* run.test (getnwords): Run data through "cat -v", because at
+	least one version of Debian Linux has an English dictionary with
+	Latin-1 characters and a "rev" that seems to default to some sort
+	of Unicode.
+
+2004-08-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* run.test (getnwords): Rewrite to drop blank lines before
+	counting lines, not after.
+
+2004-08-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* run.test (getnwords): New function.  Uses sed to get N words
+	from $DICT as other functions did before, but discards blank
+	lines.
+	(test1, test2, test12, test13, test20): Call getnwords.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* SEQ_TEST/t.c (main): Remove declaration of errno
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile: Deleted.
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-23  Tom Yu  <tlyu@mit.edu>
+
+	* dbtest.c: Include btree.h if we're compiled with -DSTATISTICS.
+
+	* Makefile.in: Add rules for bttest; also add a clean rule.
+
+2002-05-08  Ken Raeburn  <raeburn@mit.edu>
+	
+	* dbtest.c: Test for __STDC__ defined, not nonzero, to decide
+	whether to use stdarg.h or varargs.h.
+	(err): Similarly for function signature.
+
+2002-02-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* run.test: Use "/bin/." instead of "/bin" in find commands in
+	case /bin itself is a symlink.
+	(test8): Check exit status of dbtest program.
+
+	* dbtest.c (compare): Exit with error indication if comparison of
+	contents indicates a difference.
+	(get): Exit with error indication after printing message if key
+	not found.
+
+2002-01-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* run.test (test8): If test reports an error, exit with error
+	indication.
+
+	* dbtest.c (compare): Exit with error indication if size
+	comparison fails.
+
+2000-06-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* dbtest.c (err): Add format attribute to decl, for typechecking
+	under GNU C.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dbtest.c (main): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/Makefile.in b/mechglue/src/plugins/kdb/db2/libdb2/test/Makefile.in
new file mode 100644
index 000000000..af4b6bec7
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/Makefile.in
@@ -0,0 +1,36 @@
+thisconfigdir=./..
+myfulldir=plugins/kdb/db2/libdb2/test
+mydir=test
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..$(S)..
+
+FCTSH = @FCTSH@
+TMPDIR=.
+
+LOCALINCLUDES=	-I. -I$(srcdir)/../include -I../include -I$(srcdir)/../mpool \
+		-I$(srcdir)/../btree -I$(srcdir)/../hash -I$(srcdir)/../db
+
+PROG_LIBPATH=-L..
+PROG_RPATH=$(KRB5_LIBDIR)
+
+KRB5_RUN_ENV= @KRB5_RUN_ENV@
+
+DB_LIB		= -ldb
+DB_DEPLIB	= ../libdb$(DEPLIBEXT)
+
+all::
+
+dbtest: dbtest.o $(DB_DEPLIB)
+	$(CC_LINK) -o $@ dbtest.o $(STRERROR_OBJ) $(DB_LIB)
+
+check:: dbtest
+	$(KRB5_RUN_ENV) srcdir=$(srcdir) TMPDIR=$(TMPDIR) $(FCTSH) $(srcdir)/run.test
+
+bttest.o: $(srcdir)/btree.tests/main.c
+	$(CC) $(ALL_CFLAGS) -c $(srcdir)/btree.tests/main.c -o $@
+
+bttest: bttest.o $(DB_DEPLIB)
+	$(CC_LINK) -o $@ bttest.o $(STRERROR_OBJ) $(DB_LIB)
+
+clean-unix::
+	$(RM) dbtest.o dbtest __dbtest
+	$(RM) bttest.o bttest
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/README b/mechglue/src/plugins/kdb/db2/libdb2/test/README
new file mode 100644
index 000000000..0c0cd13d8
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/README
@@ -0,0 +1,74 @@
+#	@(#)README	8.8 (Berkeley) 7/31/94
+
+To build this portably, try something like:
+
+    make PORTDIR="../PORT/MACH"
+
+where MACH is the machine, i.e. "sunos.4.1.1".
+
+To run the tests, enter "sh run.test".  If your system dictionary isn't
+in /usr/share/dict/words, edit run.test to reflect the correct place.
+
+Fairly large files (the command files) are built in this directory during
+the test runs, and even larger files (the database files) are created in
+"/var/tmp".  If the latter directory doesn't exist, set the environmental
+variable TMPDIR to a directory where the files can be built.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+The script file consists of lines with an initial character which is
+the command for that line, or an initial character indicating a key
+or data entry for a previous command.
+
+Legal command characters are as follows:
+
+c: compare a record
+	+ must be followed by [kK][dD]; the data value in the database
+	  associated with the specified key is compared to the specified
+	  data value.
+e: echo a string
+	+ writes out the rest of the line into the output file; if the
+	  last character is not a carriage-return, a newline is appended.
+f: set the flags for the next command
+	+ no value zero's the flags
+g: do a get command
+	+ must be followed by [kK]
+	+ writes out the retrieved data DBT.
+o [r]: dump [reverse]
+	+ dump the database out, if 'r' is set, in reverse order.
+p: do a put command
+	+ must be followed by [kK][dD]
+r: do a del command
+	+ must be followed by [kK] unless R_CURSOR flag set.
+S: sync the database
+s: do a seq command
+	+ must be followed by [kK] if R_CURSOR flag set.
+	+ writes out the retrieved data DBT.
+
+Legal key/data characters are as follows:
+
+D [file]: data file
+	+ set the current data value to the contents of the file
+d [data]:
+	+ set the current key value to the contents of the line.
+K [file]: key file
+	+ set the current key value to the contents of the file
+k [data]:
+	+ set the current key value to the contents of the line.
+
+Blank lines, lines with leading white space, and lines with leading
+hash marks (#) are ignored.
+
+Options to dbtest are as follows:
+
+	-d: Set the DB_LOCK flag.
+	-f: Use the file argument as the database file.
+	-i: Use the rest of the argument to set elements in the info
+	    structure.  If the type is btree, then "-i cachesize=10240"
+	    will set BTREEINFO.cachesize to 10240.
+	-o: The rest of the argument is the output file instead of
+	    using stdout.
+	-s: Don't delete the database file before opening it, i.e.
+	    use the database file from a previous run.
+
+Dbtest requires two arguments, the type of access "hash", "recno"
+or "btree", and the script name or "-" to indicate stdin.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/data b/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/data
new file mode 100644
index 000000000..37a518537
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/data
@@ -0,0 +1,8 @@
+A000027875A000135891
+A000059165A000130168
+A000060256A000133490
+A040025906A000136770
+A040027881A000135829
+A040028611A000137873
+A040032413A000056974
+A040050163A000126233
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/mbox b/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/mbox
new file mode 100644
index 000000000..9d5d49d07
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/mbox
@@ -0,0 +1,399 @@
+From wiggans@aipl.arsusda.gov Mon Sep 12 11:05:58 1994
+Received: from vangogh.CS.Berkeley.EDU by python.bostic.com (8.6.9.Beta4/2.6)
+	id OAA16853; Mon, 12 Sep 1994 14:05:42 -0400
+From: wiggans@aipl.arsusda.gov
+Received: from hofmann.CS.Berkeley.EDU (hofmann.CS.Berkeley.EDU [128.32.34.35]) by vangogh.CS.Berkeley.EDU (8.7.Alpha.1/8.6.9.Beta0) with ESMTP id LAA15825 for <bostic@vangogh.CS.Berkeley.EDU>; Mon, 12 Sep 1994 11:05:20 -0700 (PDT)
+Received: from uu7.psi.com (uu7.psi.com [38.145.204.6]) by hofmann.CS.Berkeley.EDU (8.6.9/8.6.6.Beta11) with SMTP id LAA25681 for <bostic@cs.berkeley.edu>; Mon, 12 Sep 1994 11:05:44 -0700
+Received: from AIPL.ARSUSDA.GOV by uu7.psi.com (5.65b/4.0.071791-PSI/PSINet) via SMTP;
+        id AA00699 for bostic@cs.berkeley.edu; Mon, 12 Sep 94 14:06:15 -0400
+Received: by aipl.arsusda.gov (AIX 3.2/UCB 5.64/4.03)
+          id AA14802; Mon, 12 Sep 1994 14:05:48 -0400
+Message-Id: <9409121805.AA14802@aipl.arsusda.gov>
+Subject: db 1.85 problem
+To: bostic@cs.berkeley.edu (Keith Bostic)
+Date: Mon, 12 Sep 1994 14:05:47 -0400 (EDT)
+X-Mailer: ELM [version 2.4 PL22]
+Content-Type: text
+Content-Length: 2553      
+Status: RO
+
+In using the btree option to sequentially read and then write a file, we
+are having a problem with 1.85.  When compiled with 1.73 there is no
+problem.  The problem is that the seq call keeps reading the same record. 
+The code follows:
+
+/* chkseq.c  Check sequential read and write */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>    /* O_CREAT,  O_RDWR */
+#include <errno.h>    /* Error numbers */
+#include <db.h>
+ 
+extern int errno;
+extern char *sys_errlist[];
+ 
+typedef struct idst {
+  char id1[7];
+} id;
+
+void cvtid(char *, char *);
+ 
+void main() {
+  char anim10[11], datastor[212],keystor[10], *pc;
+  int i;
+  long in = 0L;
+  DB *dbp, *dbpo;
+  DBT key, data, keyo, datao;
+
+  if ((dbp = dbopen("bullxrf.db", O_RDWR, 0664
+       , DB_BTREE, NULL )) == NULL) {
+    printf("\n Error on dbopen %d %s\n",errno,strerror(errno));
+    exit(61);
+  }
+  key.size = 7;
+  keyo.size = 7;
+
+  while (dbp->seq(dbp, &key, &data,R_NEXT) == 0) {
+    in++;
+     if (in > 20) break; 
+/*      pc = (char *) key.data; 
+for (i=0;i<key.size;i++) printf("%02x",pc[i]); printf("\n"); */
+      cvtid(anim10,key.data); printf("%s\n",anim10); 
+    memcpy(keystor,key.data,key.size);
+/* for (i=0;i<key.size;i++) printf("%02x",keystor[i]); printf("\n"); */
+    memcpy(datastor,data.data,data.size);
+/* for (i=0;i<8;i++) printf("%02x",datastor[i]); printf("\n"); */
+    keyo.data = keystor;
+    datao.data = datastor;
+    datao.size = data.size;
+/*
+    if (in % 1000 == 1) {
+        cvtid(anim10,key.data); printf("%5d %s\n",in,anim10);  */
+      if (dbp->put(dbp, &keyo, &datao,0) != 0) {
+        printf("Write failed at %d\n",in);
+        exit(85);
+      }
+/*  }
+ */
+  }  
+  printf("%d Records copied\n",in);
+  dbp->close(dbp);
+}
+
+I am running on an RS/6000 AIX 3.2.5.  The section of the make file
+follows:
+
+# Make file
+all: chkseq
+
+chkseq: chkseq.c 
+	cc -gO3 -lm -o chkseq\
+  -L /data6/hash/include/sys/lib -l db  -I /data6/hash/include \
+  chkseq.c cvtid.o ascii.o
+#  -L /data12/db.1.85 -l db  -I /data12/db.1.85/include \
+
+We would appreciate your help.
+Thanks,
+
+-- 
+George Wiggans           I================================================I
+                         |Animal Improvement Programs Laboratory          |
+Phone:   301-504-8407    |Bldg 263 Beltsville Agricultural Research Center|
+FAX:     301-504-8092    |Beltsville, MD 20705-2350  USA                  |
+wiggans@aipl.arsusda.gov |                                                |
+=========================I================================================I
+
+From wiggans@aipl.arsusda.gov Fri Sep 16 20:27:22 1994
+Received: from vangogh.CS.Berkeley.EDU by python.bostic.com (8.6.9.Beta4/2.6)
+	id XAA09260; Fri, 16 Sep 1994 23:27:09 -0400
+From: wiggans@aipl.arsusda.gov
+Received: from hofmann.CS.Berkeley.EDU (hofmann.CS.Berkeley.EDU [128.32.34.35]) by vangogh.CS.Berkeley.EDU (8.7.Alpha.1/8.6.9.Beta0) with ESMTP id UAA25674 for <bostic@vangogh.CS.Berkeley.EDU>; Fri, 16 Sep 1994 20:27:03 -0700 (PDT)
+Received: from uu7.psi.com (uu7.psi.com [38.145.204.6]) by hofmann.CS.Berkeley.EDU (8.6.9/8.6.6.Beta11) with SMTP id UAA15043 for <bostic@cs.berkeley.edu>; Fri, 16 Sep 1994 20:27:16 -0700
+Received: from AIPL.ARSUSDA.GOV by uu7.psi.com (5.65b/4.0.071791-PSI/PSINet) via SMTP;
+        id AA18737 for bostic@cs.berkeley.edu; Fri, 16 Sep 94 23:27:14 -0400
+Received: by aipl.arsusda.gov (AIX 3.2/UCB 5.64/4.03)
+          id AA10907; Fri, 16 Sep 1994 23:26:18 -0400
+Message-Id: <9409170326.AA10907@aipl.arsusda.gov>
+Subject: Test case
+To: bostic@cs.berkeley.edu (Keith Bostic)
+Date: Fri, 16 Sep 1994 23:26:16 -0400 (EDT)
+X-Mailer: ELM [version 2.4 PL22]
+Content-Type: text
+Content-Length: 3713      
+Status: RO
+
+The following program loads 2 10 character animal ID which are used to
+change an animal's ID.  After loading, it closes, then opens and
+sequentially reads and rewrites the file changing the first character of
+the 2nd ID to U.  Failure is observed when the update part gets stuck on
+the first record, rereading it.  The last step displays the updated file.
+The name of the data file is a command line argument.
+
+The data:
+A000027875A000135891
+A000059165A000130168
+A000060256A000133490
+A040025906A000136770
+A040027881A000135829
+A040028611A000137873
+A040032413A000056974
+A040050163A000126233
+A040050329A000126177
+A040050411A000119017
+A040050995A000116767
+A040051022A000126669
+A040051276A000127444
+A040051514A000120563
+A040051597A000127287
+A040051627A000127284
+A040051700A000126914
+A040051810A000127286
+A040051964A000118834
+A040052164A000135104
+A040052165A000127688
+A040052186A000126926
+A040052530A000126287
+A040052560A000119160
+A040052892A000125334
+A040053004A000127684
+A040053359A000128628
+A040053378A000137680
+A040053416A000128825
+A040053589A000120369
+A040053620A000128460
+A040053751A000123525
+A040053754A000126736
+A040054191A000126286
+A040054251A000121745
+A040054253A000127848
+A040054596A000130931
+A040054981A000128731
+A040055000A000127689
+
+The program:
+/* chkseq.c  Check sequential read and write */
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>    /* O_CREAT,  O_RDWR */
+#include <errno.h>    /* Error numbers */
+#include <db.h>
+ 
+extern int errno;
+extern char *sys_errlist[];
+ 
+ 
+void main(int argc, char *argv[]) {
+  char id1[] = {"          "}, id2[] = {"          "};
+  int i;
+  long in = 0L, out = 0L;
+  DB *dbp, *dbpo;
+  DBT key, data, keyo, datao;
+  FILE *fopen(), *fin;
+
+  if ((fin = fopen(argv[1],"r")) == NULL) {
+    printf("Unable to open %s\n",argv[1]);
+    exit(25);
+  }
+  if ((dbp = dbopen("test.db",O_RDWR | O_CREAT, 0664
+       , DB_BTREE, NULL )) == NULL) {
+    printf("\n Open error on test.db %d %s\n",errno,strerror(errno));
+    exit(25);
+  }
+   
+  while (fscanf(fin," %10s%10s",id1,id2) > 0) {
+    key.size = 11;
+    data.size = 11;
+    key.data = id1;
+    data.data = id2;
+    printf("%10s %10s\n",key.data,data.data); 
+    if (dbp->put(dbp, &key, &data,R_NOOVERWRITE) != 0) {
+      printf("Error writing output\n");
+    }
+    out++;
+  }
+  printf("%d Records in\n",out);
+  dbp->close(dbp);
+  
+  if ((dbp = dbopen("test.db", O_RDWR, 0664
+       , DB_BTREE, NULL )) == NULL) {
+    printf("\n Error on dbopen %d %s\n",errno,strerror(errno));
+    exit(61);
+  }
+
+  while (dbp->seq(dbp, &key, &data,R_NEXT) == 0) {
+    strcpy(id1,key.data);
+    keyo.size = 11;
+    datao.size = 11;
+    keyo.data = id1;
+    strcpy(id2,data.data);
+    id2[0] = 'U';
+    datao.data=id2;
+    printf("%10s %10s\n",key.data,data.data); 
+    in++;
+    if (in > 50) break;
+    if (dbp->put(dbp, &keyo, &datao,0) != 0) {
+        printf("Write failed at %d\n",in);
+        exit(85);
+    }
+  }
+  printf("%d Records copied\n",in);
+  in = 0;
+    dbp->seq(dbp, &key, &data,R_FIRST);
+    printf("%10s %10s\n",key.data,data.data); 
+    in++;
+  while (dbp->seq(dbp, &key, &data,R_NEXT) == 0) {
+    in++;
+    printf("%10s %10s\n",key.data,data.data); 
+  }
+  printf("%d Records read\n",in);
+  dbp->close(dbp);
+}
+
+
+-- 
+George Wiggans           I================================================I
+                         |Animal Improvement Programs Laboratory          |
+Phone:   301-504-8407    |Bldg 263 Beltsville Agricultural Research Center|
+FAX:     301-504-8092    |Beltsville, MD 20705-2350  USA                  |
+wiggans@aipl.arsusda.gov |                                                |
+=========================I================================================I
+
+From bostic Fri Sep 23 08:44:56 1994
+To: wiggans@aipl.arsusda.gov /usr/src/local/db/test/SEQ_TEST/mbox
+Subject: Re: Test case
+
+
+OK, I've attached a tentative patch for the bug, that appears
+to fix it on my local system.  Please let me know if you have
+any further problems with this.
+
+There are a couple of issues here.  The first, is that to some
+extent, the btree code is correct.  You aren't replacing the
+cursor in your test program, you're adding a new key, which
+just happens to be where the cursor was.  So, the btree code
+is doing you a favor by returning the new key as part of the
+cursor walk, and it's not its fault.  ;-}
+
+However, because a put to the cursor record is done using a
+delete/add pair, doing it the "right" way will result in the
+exact same behavior as you saw doing it "wrong".
+
+Thinking about this further, there's another bug that's going to
+hit eventually -- if you have duplicate records, the current
+scheme of doing delete/add to replace the cursor record can result
+in a record being returned twice, which is tacky at best, if not
+actually wrong.
+
+I think I may have to revisit how duplicate records are stored.
+Which does not make me happy. ;-{
+
+--keith
+
+*** db/btree/bt_seq.c.orig	Fri Sep 23 08:35:06 1994
+--- db/btree/bt_seq.c	Fri Sep 23 08:34:58 1994
+***************
+*** 35,41 ****
+   */
+  
+  #if defined(LIBC_SCCS) && !defined(lint)
+! static char sccsid[] = "@(#)bt_seq.c	8.7 (Berkeley) 7/20/94";
+  #endif /* LIBC_SCCS and not lint */
+  
+  #include <sys/types.h>
+--- 35,41 ----
+   */
+  
+  #if defined(LIBC_SCCS) && !defined(lint)
+! static char sccsid[] = "@(#)bt_seq.c	8.8 (Berkeley) 9/23/94";
+  #endif /* LIBC_SCCS and not lint */
+  
+  #include <sys/types.h>
+***************
+*** 246,252 ****
+  	PAGE *h;
+  	indx_t index;
+  	pgno_t pg;
+! 	int exact;
+  
+  	/*
+  	 * There are a couple of states that we can be in.  The cursor has
+--- 246,252 ----
+  	PAGE *h;
+  	indx_t index;
+  	pgno_t pg;
+! 	int exact, rval;
+  
+  	/*
+  	 * There are a couple of states that we can be in.  The cursor has
+***************
+*** 255,269 ****
+  	c = &t->bt_cursor;
+  
+  	/*
+! 	 * The cursor was deleted where there weren't any duplicate records,
+! 	 * so the key was saved.  Find out where that key would go in the
+! 	 * current tree.  It doesn't matter if the returned key is an exact
+! 	 * match or not -- if it's an exact match, the record was added after
+! 	 * the delete so we can just return it.  If not, as long as there's
+! 	 * a record there, return it.
+  	 */
+! 	if (F_ISSET(c, CURS_ACQUIRE))
+! 		return (__bt_first(t, &c->key, ep, &exact));
+  
+  	/* Get the page referenced by the cursor. */
+  	if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+--- 255,299 ----
+  	c = &t->bt_cursor;
+  
+  	/*
+! 	 * The cursor was deleted and there weren't any duplicate records,
+! 	 * so the cursor's key was saved.  Find out where that key would
+! 	 * be in the current tree.  If the returned key is an exact match,
+! 	 * it means that a key/data pair was inserted into the tree after
+! 	 * the delete.  We could reasonably return the key, but the problem
+! 	 * is that this is the access pattern we'll see if the user is
+! 	 * doing seq(..., R_NEXT)/put(..., 0) pairs, i.e. the put deletes
+! 	 * the cursor record and then replaces it, so the cursor was saved,
+! 	 * and we'll simply return the same "new" record until the user
+! 	 * notices and doesn't do a put() of it.  Since the key is an exact
+! 	 * match, we could as easily put the new record before the cursor,
+! 	 * and we've made no guarantee to return it.  So, move forward or
+! 	 * back a record if it's an exact match.
+! 	 *
+! 	 * XXX
+! 	 * In the current implementation, put's to the cursor are done with
+! 	 * delete/add pairs.  This has two consequences.  First, it means
+! 	 * that seq(..., R_NEXT)/put(..., R_CURSOR) pairs are going to exhibit
+! 	 * the same behavior as above.  Second, you can return the same key
+! 	 * twice if you have duplicate records.  The scenario is that the
+! 	 * cursor record is deleted, moving the cursor forward or backward
+! 	 * to a duplicate.  The add then inserts the new record at a location
+! 	 * ahead of the cursor because duplicates aren't sorted in any way,
+! 	 * and the new record is later returned.  This has to be fixed at some
+! 	 * point.
+  	 */
+! 	if (F_ISSET(c, CURS_ACQUIRE)) {
+! 		if (rval = __bt_first(t, &c->key, ep, &exact))
+! 			return (RET_ERROR);
+! 		if (!exact)
+! 			return (rval);
+! 		/*
+! 		 * XXX
+! 		 * Kluge -- get, release, get the page.
+! 		 */
+! 		c->pg.pgno = ep->page->pgno;
+! 		c->pg.index = ep->index;
+! 		mpool_put(t->bt_mp, ep->page, 0);
+! 	}
+  
+  	/* Get the page referenced by the cursor. */
+  	if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+
+
+
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/t.c b/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/t.c
new file mode 100644
index 000000000..f77b676f1
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/SEQ_TEST/t.c
@@ -0,0 +1,85 @@
+/* chkseq.c  Check sequential read and write */
+
+#include <sys/stat.h>
+#include "db-int.h"
+#include <errno.h>    /* Error numbers */
+#include <fcntl.h>    /* O_CREAT,  O_RDWR */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+ 
+void main(int argc, char *argv[]) {
+  char id1[] = {"          "}, id2[] = {"          "};
+  int i;
+  long in = 0L, out = 0L;
+  DB *dbp, *dbpo;
+  DBT key, data, keyo, datao;
+  FILE *fopen(), *fin;
+
+  unlink("test.db");
+  if ((fin = fopen("data","r")) == NULL) {
+    printf("Unable to open %s\n","data");
+    exit(25);
+  }
+  if ((dbp = dbopen("test.db",O_RDWR | O_CREAT | O_BINARY, 0664
+       , DB_BTREE, NULL )) == NULL) {
+    printf("\n Open error on test.db %d %s\n",errno,strerror(errno));
+    exit(25);
+  }
+   
+  while (fscanf(fin," %10s%10s",id1,id2) > 0) {
+    key.size = 11;
+    data.size = 11;
+    key.data = id1;
+    data.data = id2;
+    printf("%10s %10s\n",key.data,data.data); 
+    if (dbp->put(dbp, &key, &data,R_NOOVERWRITE) != 0) {
+      printf("Error writing output\n");
+    }
+    out++;
+  }
+  printf("%d Records in\n",out);
+  dbp->close(dbp);
+  
+  if ((dbp = dbopen("test.db", O_RDWR | O_BINARY, 0664
+       , DB_BTREE, NULL )) == NULL) {
+    printf("\n Error on dbopen %d %s\n",errno,strerror(errno));
+    exit(61);
+  }
+
+  while (dbp->seq(dbp, &key, &data,R_NEXT) == 0) {
+    strcpy(id1,key.data);
+    keyo.size = 11;
+    datao.size = 11;
+    keyo.data = id1;
+    strcpy(id2,data.data);
+    id2[0] = 'U';
+    datao.data=id2;
+    printf("%10s %10s\n",key.data,data.data); 
+    in++;
+    if (in > 10) break;
+#ifdef notdef
+    if (dbp->put(dbp, &keyo, &datao,0) != 0) {
+        printf("Write failed at %d\n",in);
+        exit(85);
+    }
+#else
+    if (dbp->put(dbp, &keyo, &datao,R_CURSOR) != 0) {
+        printf("Write failed at %d\n",in);
+        exit(85);
+    }
+#endif
+  }
+  printf("%d Records copied\n",in);
+  in = 0;
+    dbp->seq(dbp, &key, &data,R_FIRST);
+    printf("%10s %10s\n",key.data,data.data); 
+    in++;
+  while (dbp->seq(dbp, &key, &data,R_NEXT) == 0) {
+    in++;
+    printf("%10s %10s\n",key.data,data.data); 
+  }
+  printf("%d Records read\n",in);
+  dbp->close(dbp);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/btree.tests/ChangeLog b/mechglue/src/plugins/kdb/db2/libdb2/test/btree.tests/ChangeLog
new file mode 100644
index 000000000..339db618a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/btree.tests/ChangeLog
@@ -0,0 +1,17 @@
+2002-08-23  Tom Yu  <tlyu@mit.edu>
+
+	* main.c: Disable append(); we don't have R_APPEND in this release
+	of DB for some reason.  Disable load() due to lack of fgetline().
+	Conditionalize lots of things on -DSTATISTICS or -DDEBUG as
+	appropriate.
+	(rlist): New function; does recursive listing of principals.
+	(main): Fix up naming of *_ENDIAN macros.  Default to read-only
+	open, with new "-w" option for opening read/write.  Actually call
+	db->sync with the correct number of arguments.
+	(show): Update call to __bt_dpage().
+	(usage): Update.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* main.c (main): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c b/mechglue/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c
new file mode 100644
index 000000000..06f02b3ad
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/btree.tests/main.c
@@ -0,0 +1,832 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <fcntl.h>
+#include "db-int.h"
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "btree.h"
+
+typedef struct cmd_table {
+	char *cmd;
+	int nargs;
+	int rconv;
+	void (*func) __P((DB *, char **));
+	char *usage, *descrip;
+} cmd_table;
+
+int stopstop;
+DB *globaldb;
+
+#if 0
+void append	__P((DB *, char **));
+#endif
+#ifdef STATISTICS
+void bstat	__P((DB *, char **));
+#endif
+void cursor	__P((DB *, char **));
+void delcur	__P((DB *, char **));
+void delete	__P((DB *, char **));
+#ifdef DEBUG
+void dump	__P((DB *, char **));
+#endif
+void first	__P((DB *, char **));
+void get	__P((DB *, char **));
+void help	__P((DB *, char **));
+void iafter	__P((DB *, char **));
+void ibefore	__P((DB *, char **));
+void icursor	__P((DB *, char **));
+void insert	__P((DB *, char **));
+void keydata	__P((DBT *, DBT *));
+void last	__P((DB *, char **));
+void list	__P((DB *, char **));
+#if 0
+void load	__P((DB *, char **));
+#endif
+#ifdef STATISTICS
+void mstat	__P((DB *, char **));
+#endif
+void next	__P((DB *, char **));
+int  parse	__P((char *, char **, int));
+void previous	__P((DB *, char **));
+#ifdef DEBUG
+void show	__P((DB *, char **));
+#endif
+void rlist	__P((DB *, char **));
+void usage	__P((void));
+void user	__P((DB *));
+
+cmd_table commands[] = {
+	"?",	0, 0, help, "help", NULL,
+#if 0
+	"a",	2, 1, append, "append key def", "append key with data def",
+#endif
+#ifdef STATISTICS
+	"b",	0, 0, bstat, "bstat", "stat btree",
+#endif
+	"c",	1, 1, cursor,  "cursor word", "move cursor to word",
+	"delc",	0, 0, delcur, "delcur", "delete key the cursor references",
+	"dele",	1, 1, delete, "delete word", "delete word",
+#ifdef DEBUG
+	"d",	0, 0, dump, "dump", "dump database",
+#endif
+	"f",	0, 0, first, "first", "move cursor to first record",
+	"g",	1, 1, get, "get key", "locate key",
+	"h",	0, 0, help, "help", "print command summary",
+	"ia",	2, 1, iafter, "iafter key data", "insert data after key",
+	"ib",	2, 1, ibefore, "ibefore key data", "insert data before key",
+	"ic",	2, 1, icursor, "icursor key data", "replace cursor",
+	"in",	2, 1, insert, "insert key def", "insert key with data def",
+	"la",	0, 0, last, "last", "move cursor to last record",
+	"li",	1, 1, list, "list file", "list to a file",
+#if 0
+	"loa",	1, 0, load, "load file", NULL,
+#endif
+	"loc",	1, 1, get, "get key", NULL,
+#ifdef STATISTICS
+	"m",	0, 0, mstat, "mstat", "stat memory pool",
+#endif
+	"n",	0, 0, next, "next", "move cursor forward one record",
+	"p",	0, 0, previous, "previous", "move cursor back one record",
+	"q",	0, 0, NULL, "quit", "quit",
+	"rli",	1, 1, rlist, "rlist file", "list to a file (recursive)",
+#ifdef DEBUG
+	"sh",	1, 0, show, "show page", "dump a page",
+#endif
+	{ NULL },
+};
+
+int recno;					/* use record numbers */
+char *dict = "words";				/* default dictionary */
+char *progname;
+
+int
+main(argc, argv)
+	int argc;
+	char **argv;
+{
+	int c;
+	int omode;
+	DB *db;
+	BTREEINFO b;
+
+	progname = *argv;
+
+	omode = O_RDONLY;
+	b.flags = 0;
+	b.cachesize = 0;
+	b.maxkeypage = 0;
+	b.minkeypage = 0;
+	b.psize = 0;
+	b.compare = NULL;
+	b.prefix = NULL;
+	b.lorder = 0;
+
+	while ((c = getopt(argc, argv, "bc:di:lp:ruw")) != -1) {
+		switch (c) {
+		case 'b':
+			b.lorder = DB_BIG_ENDIAN;
+			break;
+		case 'c':
+			b.cachesize = atoi(optarg);
+			break;
+		case 'd':
+			b.flags |= R_DUP;
+			break;
+		case 'i':
+			dict = optarg;
+			break;
+		case 'l':
+			b.lorder = DB_LITTLE_ENDIAN;
+			break;
+		case 'p':
+			b.psize = atoi(optarg);
+			break;
+		case 'r':
+			recno = 1;
+			break;
+		case 'u':
+			b.flags = 0;
+			break;
+		case 'w':
+			omode = O_RDWR;
+			break;
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (recno)
+		db = dbopen(*argv == NULL ? NULL : *argv, omode|O_BINARY,
+		    0, DB_RECNO, NULL);
+	else
+		db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|omode|O_BINARY,
+		    0600, DB_BTREE, &b);
+
+	if (db == NULL) {
+		(void)fprintf(stderr, "dbopen: %s\n", strerror(errno));
+		exit(1);
+	}
+	globaldb = db;
+	user(db);
+	exit(0);
+	/* NOTREACHED */
+}
+
+void
+user(db)
+	DB *db;
+{
+	FILE *ifp;
+	int argc, i, last;
+	char *lbuf, *argv[4], buf[512];
+
+	if ((ifp = fopen("/dev/tty", "r")) == NULL) {
+		(void)fprintf(stderr,
+		    "/dev/tty: %s\n", strerror(errno));
+		exit(1);
+	}
+	for (last = 0;;) {
+		(void)printf("> ");
+		(void)fflush(stdout);
+		if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
+			break;
+		if (lbuf[0] == '\n') {
+			i = last;
+			goto uselast;
+		}
+		lbuf[strlen(lbuf) - 1] = '\0';
+
+		if (lbuf[0] == 'q')
+			break;
+
+		argc = parse(lbuf, &argv[0], 3);
+		if (argc == 0)
+			continue;
+
+		for (i = 0; commands[i].cmd != NULL; i++)
+			if (strncmp(commands[i].cmd, argv[0],
+			    strlen(commands[i].cmd)) == 0)
+				break;
+
+		if (commands[i].cmd == NULL) {
+			(void)fprintf(stderr,
+			    "%s: command unknown ('help' for help)\n", lbuf);
+			continue;
+		}
+
+		if (commands[i].nargs != argc - 1) {
+			(void)fprintf(stderr, "usage: %s\n", commands[i].usage);
+			continue;
+		}
+
+		if (recno && commands[i].rconv) {
+			static recno_t nlong;
+			nlong = atoi(argv[1]);
+			argv[1] = (char *)&nlong;
+		}
+uselast:	last = i;
+		(*commands[i].func)(db, argv);
+	}
+	if ((db->sync)(db, 0) == RET_ERROR)
+		perror("dbsync");
+	else if ((db->close)(db) == RET_ERROR)
+		perror("dbclose");
+}
+
+int
+parse(lbuf, argv, maxargc)
+	char *lbuf, **argv;
+	int maxargc;
+{
+	int argc = 0;
+	char *c;
+
+	c = lbuf;
+	while (isspace(*c))
+		c++;
+	while (*c != '\0' && argc < maxargc) {
+		*argv++ = c;
+		argc++;
+		while (!isspace(*c) && *c != '\0') {
+			c++;
+		}
+		while (isspace(*c))
+			*c++ = '\0';
+	}
+	return (argc);
+}
+
+#if 0
+void
+append(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT key, data;
+	int status;
+
+	if (!recno) {
+		(void)fprintf(stderr,
+		    "append only available for recno db's.\n");
+		return;
+	}
+	key.data = argv[1];
+	key.size = sizeof(recno_t);
+	data.data = argv[2];
+	data.size = strlen(data.data);
+	status = (db->put)(db, &key, &data, R_APPEND);
+	switch (status) {
+	case RET_ERROR:
+		perror("append/put");
+		break;
+	case RET_SPECIAL:
+		(void)printf("%s (duplicate key)\n", argv[1]);
+		break;
+	case RET_SUCCESS:
+		break;
+	}
+}
+#endif
+
+void
+cursor(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT data, key;
+	int status;
+
+	key.data = argv[1];
+	if (recno)
+		key.size = sizeof(recno_t);
+	else
+		key.size = strlen(argv[1]) + 1;
+	status = (*db->seq)(db, &key, &data, R_CURSOR);
+	switch (status) {
+	case RET_ERROR:
+		perror("cursor/seq");
+		break;
+	case RET_SPECIAL:
+		(void)printf("key not found\n");
+		break;
+	case RET_SUCCESS:
+		keydata(&key, &data);
+		break;
+	}
+}
+
+void
+delcur(db, argv)
+	DB *db;
+	char **argv;
+{
+	int status;
+
+	status = (*db->del)(db, NULL, R_CURSOR);
+
+	if (status == RET_ERROR)
+		perror("delcur/del");
+}
+
+void
+delete(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT key;
+	int status;
+
+	key.data = argv[1];
+	if (recno)
+		key.size = sizeof(recno_t);
+	else
+		key.size = strlen(argv[1]) + 1;
+
+	status = (*db->del)(db, &key, 0);
+	switch (status) {
+	case RET_ERROR:
+		perror("delete/del");
+		break;
+	case RET_SPECIAL:
+		(void)printf("key not found\n");
+		break;
+	case RET_SUCCESS:
+		break;
+	}
+}
+
+#ifdef DEBUG
+void
+dump(db, argv)
+	DB *db;
+	char **argv;
+{
+	__bt_dump(db);
+}
+#endif
+
+void
+first(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT data, key;
+	int status;
+
+	status = (*db->seq)(db, &key, &data, R_FIRST);
+
+	switch (status) {
+	case RET_ERROR:
+		perror("first/seq");
+		break;
+	case RET_SPECIAL:
+		(void)printf("no more keys\n");
+		break;
+	case RET_SUCCESS:
+		keydata(&key, &data);
+		break;
+	}
+}
+
+void
+get(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT data, key;
+	int status;
+
+	key.data = argv[1];
+	if (recno)
+		key.size = sizeof(recno_t);
+	else
+		key.size = strlen(argv[1]) + 1;
+
+	status = (*db->get)(db, &key, &data, 0);
+
+	switch (status) {
+	case RET_ERROR:
+		perror("get/get");
+		break;
+	case RET_SPECIAL:
+		(void)printf("key not found\n");
+		break;
+	case RET_SUCCESS:
+		keydata(&key, &data);
+		break;
+	}
+}
+
+void
+help(db, argv)
+	DB *db;
+	char **argv;
+{
+	int i;
+
+	for (i = 0; commands[i].cmd; i++)
+		if (commands[i].descrip)
+			(void)printf("%s: %s\n",
+			    commands[i].usage, commands[i].descrip);
+}
+
+void
+iafter(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT key, data;
+	int status;
+
+	if (!recno) {
+		(void)fprintf(stderr,
+		    "iafter only available for recno db's.\n");
+		return;
+	}
+	key.data = argv[1];
+	key.size = sizeof(recno_t);
+	data.data = argv[2];
+	data.size = strlen(data.data);
+	status = (db->put)(db, &key, &data, R_IAFTER);
+	switch (status) {
+	case RET_ERROR:
+		perror("iafter/put");
+		break;
+	case RET_SPECIAL:
+		(void)printf("%s (duplicate key)\n", argv[1]);
+		break;
+	case RET_SUCCESS:
+		break;
+	}
+}
+
+void
+ibefore(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT key, data;
+	int status;
+
+	if (!recno) {
+		(void)fprintf(stderr,
+		    "ibefore only available for recno db's.\n");
+		return;
+	}
+	key.data = argv[1];
+	key.size = sizeof(recno_t);
+	data.data = argv[2];
+	data.size = strlen(data.data);
+	status = (db->put)(db, &key, &data, R_IBEFORE);
+	switch (status) {
+	case RET_ERROR:
+		perror("ibefore/put");
+		break;
+	case RET_SPECIAL:
+		(void)printf("%s (duplicate key)\n", argv[1]);
+		break;
+	case RET_SUCCESS:
+		break;
+	}
+}
+
+void
+icursor(db, argv)
+	DB *db;
+	char **argv;
+{
+	int status;
+	DBT data, key;
+
+	key.data = argv[1];
+	if (recno)
+		key.size = sizeof(recno_t);
+	else
+		key.size = strlen(argv[1]) + 1;
+	data.data = argv[2];
+	data.size = strlen(argv[2]) + 1;
+
+	status = (*db->put)(db, &key, &data, R_CURSOR);
+	switch (status) {
+	case RET_ERROR:
+		perror("icursor/put");
+		break;
+	case RET_SPECIAL:
+		(void)printf("%s (duplicate key)\n", argv[1]);
+		break;
+	case RET_SUCCESS:
+		break;
+	}
+}
+
+void
+insert(db, argv)
+	DB *db;
+	char **argv;
+{
+	int status;
+	DBT data, key;
+
+	key.data = argv[1];
+	if (recno)
+		key.size = sizeof(recno_t);
+	else
+		key.size = strlen(argv[1]) + 1;
+	data.data = argv[2];
+	data.size = strlen(argv[2]) + 1;
+
+	status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
+	switch (status) {
+	case RET_ERROR:
+		perror("insert/put");
+		break;
+	case RET_SPECIAL:
+		(void)printf("%s (duplicate key)\n", argv[1]);
+		break;
+	case RET_SUCCESS:
+		break;
+	}
+}
+
+void
+last(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT data, key;
+	int status;
+
+	status = (*db->seq)(db, &key, &data, R_LAST);
+
+	switch (status) {
+	case RET_ERROR:
+		perror("last/seq");
+		break;
+	case RET_SPECIAL:
+		(void)printf("no more keys\n");
+		break;
+	case RET_SUCCESS:
+		keydata(&key, &data);
+		break;
+	}
+}
+
+void
+list(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT data, key;
+	FILE *fp;
+	int status;
+
+	if ((fp = fopen(argv[1], "w")) == NULL) {
+		(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
+		return;
+	}
+	status = (*db->seq)(db, &key, &data, R_FIRST);
+	while (status == RET_SUCCESS) {
+		(void)fprintf(fp, "%s\n", key.data);
+		status = (*db->seq)(db, &key, &data, R_NEXT);
+	}
+	(void)fclose(fp);
+	if (status == RET_ERROR)
+		perror("list/seq");
+}
+
+void
+rlist(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT data, key;
+	FILE *fp;
+	int status;
+	void *cookie;
+
+	cookie = NULL;
+	if ((fp = fopen(argv[1], "w")) == NULL) {
+		(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
+		return;
+	}
+	status = bt_rseq(db, &key, &data, &cookie, R_FIRST);
+	while (status == RET_SUCCESS) {
+		(void)fprintf(fp, "%s\n", key.data);
+		status = bt_rseq(db, &key, &data, &cookie, R_NEXT);
+	}
+	(void)fclose(fp);
+	if (status == RET_ERROR)
+		perror("list/seq");
+}
+
+#if 0
+DB *BUGdb;
+void
+load(db, argv)
+	DB *db;
+	char **argv;
+{
+	register char *p, *t;
+	FILE *fp;
+	DBT data, key;
+	recno_t cnt;
+	size_t len;
+	int status;
+	char *lp, buf[16 * 1024];
+
+	BUGdb = db;
+	if ((fp = fopen(argv[1], "r")) == NULL) {
+		(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
+		return;
+	}
+	(void)printf("loading %s...\n", argv[1]);
+
+	for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
+		if (recno) {
+			key.data = &cnt;
+			key.size = sizeof(recno_t);
+			data.data = lp;
+			data.size = len + 1;
+		} else { 
+			key.data = lp;
+			key.size = len + 1;
+			for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
+			*t = '\0';
+			data.data = buf;
+			data.size = len + 1;
+		}
+
+		status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
+		switch (status) {
+		case RET_ERROR:
+			perror("load/put");
+			exit(1);
+		case RET_SPECIAL:
+			if (recno)
+				(void)fprintf(stderr,
+				    "duplicate: %ld {%s}\n", cnt, data.data);
+			else
+				(void)fprintf(stderr,
+				    "duplicate: %ld {%s}\n", cnt, key.data);
+			exit(1);
+		case RET_SUCCESS:
+			break;
+		}
+	}
+	(void)fclose(fp);
+}
+#endif
+
+void
+next(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT data, key;
+	int status;
+
+	status = (*db->seq)(db, &key, &data, R_NEXT);
+
+	switch (status) {
+	case RET_ERROR:
+		perror("next/seq");
+		break;
+	case RET_SPECIAL:
+		(void)printf("no more keys\n");
+		break;
+	case RET_SUCCESS:
+		keydata(&key, &data);
+		break;
+	}
+}
+
+void
+previous(db, argv)
+	DB *db;
+	char **argv;
+{
+	DBT data, key;
+	int status;
+
+	status = (*db->seq)(db, &key, &data, R_PREV);
+
+	switch (status) {
+	case RET_ERROR:
+		perror("previous/seq");
+		break;
+	case RET_SPECIAL:
+		(void)printf("no more keys\n");
+		break;
+	case RET_SUCCESS:
+		keydata(&key, &data);
+		break;
+	}
+}
+
+#ifdef DEBUG
+void
+show(db, argv)
+	DB *db;
+	char **argv;
+{
+	BTREE *t;
+	PAGE *h;
+	db_pgno_t pg;
+
+	pg = atoi(argv[1]);
+	t = db->internal;
+	if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
+		(void)printf("getpage of %ld failed\n", pg);
+		return;
+	}
+	if (pg == 0)
+		__bt_dmpage(h);
+	else
+		__bt_dpage(db, h);
+	mpool_put(t->bt_mp, h, 0);
+}
+#endif
+
+#ifdef STATISTICS
+void
+bstat(db, argv)
+	DB *db;
+	char **argv;
+{
+	(void)printf("BTREE\n");
+	__bt_stat(db);
+}
+
+void
+mstat(db, argv)
+	DB *db;
+	char **argv;
+{
+	(void)printf("MPOOL\n");
+	mpool_stat(((BTREE *)db->internal)->bt_mp);
+}
+#endif
+
+void
+keydata(key, data)
+	DBT *key, *data;
+{
+	if (!recno && key->size > 0)
+		(void)printf("%s/", key->data);
+	if (data->size > 0)
+		(void)printf("%s", data->data);
+	(void)printf("\n");
+}
+
+void
+usage()
+{
+	(void)fprintf(stderr,
+	    "usage: %s [-bdluw] [-c cache] [-i file] [-p page] [file]\n",
+	    progname);
+	exit (1);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/dbtest.c b/mechglue/src/plugins/kdb/db2/libdb2/test/dbtest.c
new file mode 100644
index 000000000..10a89a6fa
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/dbtest.c
@@ -0,0 +1,768 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)dbtest.c	8.17 (Berkeley) 9/1/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "db-int.h"
+#ifdef STATISTICS
+#include "btree.h"
+#endif
+
+enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+#define ATTR(x) __attribute__(x)
+#else
+#define ATTR(x)
+#endif
+
+void	 compare __P((DBT *, DBT *));
+DBTYPE	 dbtype __P((char *));
+void	 dump __P((DB *, int));
+void	 err __P((const char *, ...)) ATTR ((__format__(__printf__,1,2))) ATTR ((__noreturn__));
+void	 get __P((DB *, DBT *));
+void	 getdata __P((DB *, DBT *, DBT *));
+void	 put __P((DB *, DBT *, DBT *));
+void	 rem __P((DB *, DBT *));
+char	*sflags __P((int));
+void	 synk __P((DB *));
+void	*rfile __P((char *, size_t *));
+void	 seq __P((DB *, DBT *));
+u_int	 setflags __P((char *));
+void	*setinfo __P((DBTYPE, char *));
+void	 usage __P((void));
+void	*xmalloc __P((char *, size_t));
+
+DBTYPE type;				/* Database type. */
+void *infop;				/* Iflags. */
+u_long lineno;				/* Current line in test script. */
+u_int flags;				/* Current DB flags. */
+int ofd = STDOUT_FILENO;		/* Standard output fd. */
+
+DB *XXdbp;				/* Global for gdb. */
+int XXlineno;				/* Fast breakpoint for gdb. */
+
+int
+main(argc, argv)
+	int argc;
+	char *argv[];
+{
+	extern int optind;
+	extern char *optarg;
+	enum S command, state;
+	DB *dbp;
+	DBT data, key, keydata;
+	size_t len;
+	int ch, oflags, sflag;
+	char *fname, *infoarg, *p, *t, buf[8 * 1024];
+
+	infoarg = NULL;
+	fname = NULL;
+	oflags = O_CREAT | O_RDWR | O_BINARY;
+	sflag = 0;
+	while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)
+		switch (ch) {
+		case 'f':
+			fname = optarg;
+			break;
+		case 'i':
+			infoarg = optarg;
+			break;
+		case 'l':
+			oflags |= DB_LOCK;
+			break;
+		case 'o':
+			if ((ofd = open(optarg,
+			    O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+				err("%s: %s", optarg, strerror(errno));
+			break;
+		case 's':
+			sflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 2)
+		usage();
+
+	/* Set the type. */
+	type = dbtype(*argv++);
+
+	/* Open the descriptor file. */
+        if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
+	    err("%s: %s", *argv, strerror(errno));
+
+	/* Set up the db structure as necessary. */
+	if (infoarg == NULL)
+		infop = NULL;
+	else
+		for (p = strtok(infoarg, ",\t "); p != NULL;
+		    p = strtok(0, ",\t "))
+			if (*p != '\0')
+				infop = setinfo(type, p);
+
+	/*
+	 * Open the DB.  Delete any preexisting copy, you almost never
+	 * want it around, and it often screws up tests.
+	 */
+	if (fname == NULL) {
+		p = getenv("TMPDIR");
+		if (p == NULL)
+			p = "/var/tmp";
+		(void)sprintf(buf, "%s/__dbtest", p);
+		fname = buf;
+		(void)unlink(buf);
+	} else  if (!sflag)
+		(void)unlink(fname);
+
+	if ((dbp = dbopen(fname,
+	    oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
+		err("dbopen: %s", strerror(errno));
+	XXdbp = dbp;
+
+	state = COMMAND;
+	for (lineno = 1;
+	    (p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
+		/* Delete the newline, displaying the key/data is easier. */
+		if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
+			*t = '\0';
+		if ((len = strlen(buf)) == 0 || isspace((int) *p) || *p == '#')
+			continue;
+
+		/* Convenient gdb break point. */
+		if (XXlineno == lineno)
+			XXlineno = 1;
+		switch (*p) {
+		case 'c':			/* compare */
+			if (state != COMMAND)
+				err("line %lu: not expecting command", lineno);
+			state = KEY;
+			command = COMPARE;
+			break;
+		case 'e':			/* echo */
+			if (state != COMMAND)
+				err("line %lu: not expecting command", lineno);
+			/* Don't display the newline, if CR at EOL. */
+			if (p[len - 2] == '\r')
+				--len;
+			if (write(ofd, p + 1, len - 1) != len - 1 ||
+			    write(ofd, "\n", 1) != 1)
+				err("write: %s", strerror(errno));
+			break;
+		case 'g':			/* get */
+			if (state != COMMAND)
+				err("line %lu: not expecting command", lineno);
+			state = KEY;
+			command = GET;
+			break;
+		case 'p':			/* put */
+			if (state != COMMAND)
+				err("line %lu: not expecting command", lineno);
+			state = KEY;
+			command = PUT;
+			break;
+		case 'r':			/* remove */
+			if (state != COMMAND)
+				err("line %lu: not expecting command", lineno);
+                        if (flags == R_CURSOR) {
+				rem(dbp, &key);
+				state = COMMAND;
+                        } else {
+				state = KEY;
+				command = REMOVE;
+			}
+			break;
+		case 'S':			/* sync */
+			if (state != COMMAND)
+				err("line %lu: not expecting command", lineno);
+			synk(dbp);
+			state = COMMAND;
+			break;
+		case 's':			/* seq */
+			if (state != COMMAND)
+				err("line %lu: not expecting command", lineno);
+			if (flags == R_CURSOR) {
+				state = KEY;
+				command = SEQ;
+			} else
+				seq(dbp, &key);
+			break;
+		case 'f':
+			flags = setflags(p + 1);
+			break;
+		case 'D':			/* data file */
+			if (state != DATA)
+				err("line %lu: not expecting data", lineno);
+			data.data = rfile(p + 1, &data.size);
+			goto ldata;
+		case 'd':			/* data */
+			if (state != DATA)
+				err("line %lu: not expecting data", lineno);
+			data.data = xmalloc(p + 1, len - 1);
+			data.size = len - 1;
+ldata:			switch (command) {
+			case COMPARE:
+				compare(&keydata, &data);
+				break;
+			case PUT:
+				put(dbp, &key, &data);
+				break;
+			default:
+				err("line %lu: command doesn't take data",
+				    lineno);
+			}
+			if (type != DB_RECNO)
+				free(key.data);
+			free(data.data);
+			state = COMMAND;
+			break;
+		case 'K':			/* key file */
+			if (state != KEY)
+				err("line %lu: not expecting a key", lineno);
+			if (type == DB_RECNO)
+				err("line %lu: 'K' not available for recno",
+				    lineno);
+			key.data = rfile(p + 1, &key.size);
+			goto lkey;
+		case 'k':			/* key */
+			if (state != KEY)
+				err("line %lu: not expecting a key", lineno);
+			if (type == DB_RECNO) {
+				static recno_t recno;
+				recno = atoi(p + 1);
+				key.data = &recno;
+				key.size = sizeof(recno);
+			} else {
+				key.data = xmalloc(p + 1, len - 1);
+				key.size = len - 1;
+			}
+lkey:			switch (command) {
+			case COMPARE:
+				getdata(dbp, &key, &keydata);
+				state = DATA;
+				break;
+			case GET:
+				get(dbp, &key);
+				if (type != DB_RECNO)
+					free(key.data);
+				state = COMMAND;
+				break;
+			case PUT:
+				state = DATA;
+				break;
+			case REMOVE:
+				rem(dbp, &key);
+				if ((type != DB_RECNO) && (flags != R_CURSOR))
+					free(key.data);
+				state = COMMAND;
+				break;
+			case SEQ:
+				seq(dbp, &key);
+				if ((type != DB_RECNO) && (flags != R_CURSOR))
+					free(key.data);
+				state = COMMAND;
+				break;
+			default:
+				err("line %lu: command doesn't take a key",
+				    lineno);
+			}
+			break;
+		case 'o':
+			dump(dbp, p[1] == 'r');
+			break;
+		default:
+			err("line %lu: %s: unknown command character",
+			    lineno, p);
+		}
+	}
+#ifdef STATISTICS
+	/*
+	 * -l must be used (DB_LOCK must be set) for this to be
+	 * used, otherwise a page will be locked and it will fail.
+	 */
+	if (type == DB_BTREE && oflags & DB_LOCK)
+		__bt_stat(dbp);
+#endif
+	if (dbp->close(dbp))
+		err("db->close: %s", strerror(errno));
+	(void)close(ofd);
+	exit(0);
+}
+
+#define	NOOVERWRITE	"put failed, would overwrite key\n"
+
+void
+compare(db1, db2)
+	DBT *db1, *db2;
+{
+	register size_t len;
+	register u_char *p1, *p2;
+
+	if (db1->size != db2->size) {
+		printf("compare failed: key->data len %lu != data len %lu\n",
+		    (u_long) db1->size, (u_long) db2->size);
+		exit (1);
+	}
+
+	len = MIN(db1->size, db2->size);
+	for (p1 = db1->data, p2 = db2->data; len--;)
+		if (*p1++ != *p2++) {
+			err("compare failed at offset %d\n",
+			    p1 - (u_char *)db1->data);
+			break;
+		}
+}
+
+void
+get(dbp, kp)
+	DB *dbp;
+	DBT *kp;
+{
+	DBT data;
+
+	switch (dbp->get(dbp, kp, &data, flags)) {
+	case 0:
+		(void)write(ofd, data.data, data.size);
+		if (ofd == STDOUT_FILENO)
+			(void)write(ofd, "\n", 1);
+		break;
+	case -1:
+		err("line %lu: get: %s", lineno, strerror(errno));
+		/* NOTREACHED */
+	case 1:
+#define	NOSUCHKEY	"get failed, no such key\n"
+		if (ofd != STDOUT_FILENO) {
+			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+			exit(1);
+		} else
+			(void)fprintf(stderr, "%lu: %.*s: %s",
+			    lineno, (int) MIN(kp->size, 20), (char *) kp->data, 
+				      NOSUCHKEY);
+#undef	NOSUCHKEY
+		break;
+	}
+}
+
+void
+getdata(dbp, kp, dp)
+	DB *dbp;
+	DBT *kp, *dp;
+{
+	switch (dbp->get(dbp, kp, dp, flags)) {
+	case 0:
+		return;
+	case -1:
+		err("line %lu: getdata: %s", lineno, strerror(errno));
+		/* NOTREACHED */
+	case 1:
+		err("line %lu: getdata failed, no such key", lineno);
+		/* NOTREACHED */
+	}
+}
+
+void
+put(dbp, kp, dp)
+	DB *dbp;
+	DBT *kp, *dp;
+{
+	switch (dbp->put(dbp, kp, dp, flags)) {
+	case 0:
+		break;
+	case -1:
+		err("line %lu: put: %s", lineno, strerror(errno));
+		/* NOTREACHED */
+	case 1:
+		(void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
+		break;
+	}
+}
+
+void
+rem(dbp, kp)
+	DB *dbp;
+	DBT *kp;
+{
+	switch (dbp->del(dbp, kp, flags)) {
+	case 0:
+		break;
+	case -1:
+		err("line %lu: rem: %s", lineno, strerror(errno));
+		/* NOTREACHED */
+	case 1:
+#define	NOSUCHKEY	"rem failed, no such key\n"
+		if (ofd != STDOUT_FILENO)
+			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+		else if (flags != R_CURSOR)
+			(void)fprintf(stderr, "%lu: %.*s: %s", 
+			    lineno, (int) MIN(kp->size, 20), (char *) kp->data, 
+				      NOSUCHKEY);
+		else
+			(void)fprintf(stderr,
+			    "%lu: rem of cursor failed\n", lineno);
+#undef	NOSUCHKEY
+		break;
+	}
+}
+
+void
+synk(dbp)
+	DB *dbp;
+{
+	switch (dbp->sync(dbp, flags)) {
+	case 0:
+		break;
+	case -1:
+		err("line %lu: synk: %s", lineno, strerror(errno));
+		/* NOTREACHED */
+	}
+}
+
+void
+seq(dbp, kp)
+	DB *dbp;
+	DBT *kp;
+{
+	DBT data;
+
+	switch (dbp->seq(dbp, kp, &data, flags)) {
+	case 0:
+		(void)write(ofd, data.data, data.size);
+		if (ofd == STDOUT_FILENO)
+			(void)write(ofd, "\n", 1);
+		break;
+	case -1:
+		err("line %lu: seq: %s", lineno, strerror(errno));
+		/* NOTREACHED */
+	case 1:
+#define	NOSUCHKEY	"seq failed, no such key\n"
+		if (ofd != STDOUT_FILENO)
+			(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
+		else if (flags == R_CURSOR)
+			(void)fprintf(stderr, "%lu: %.*s: %s", 
+			    lineno, (int) MIN(kp->size, 20), (char *) kp->data, 
+				      NOSUCHKEY);
+		else
+			(void)fprintf(stderr,
+			    "%lu: seq (%s) failed\n", lineno, sflags(flags));
+#undef	NOSUCHKEY
+		break;
+	}
+}
+
+void
+dump(dbp, rev)
+	DB *dbp;
+	int rev;
+{
+	DBT key, data;
+	int lflags, nflags;
+
+	if (rev) {
+		lflags = R_LAST;
+		nflags = R_PREV;
+	} else {
+		lflags = R_FIRST;
+		nflags = R_NEXT;
+	}
+	for (;; lflags = nflags)
+		switch (dbp->seq(dbp, &key, &data, lflags)) {
+		case 0:
+			(void)write(ofd, data.data, data.size);
+			if (ofd == STDOUT_FILENO)
+				(void)write(ofd, "\n", 1);
+			break;
+		case 1:
+			goto done;
+		case -1:
+			err("line %lu: (dump) seq: %s",
+			    lineno, strerror(errno));
+			/* NOTREACHED */
+		}
+done:	return;
+}
+	
+u_int
+setflags(s)
+	char *s;
+{
+	char *p;
+
+	for (; isspace((int) *s); ++s);
+	if (*s == '\n' || *s == '\0')
+		return (0);
+	if ((p = strchr(s, '\n')) != NULL)
+		*p = '\0';
+	if (!strcmp(s, "R_CURSOR"))		return (R_CURSOR);
+	if (!strcmp(s, "R_FIRST"))		return (R_FIRST);
+	if (!strcmp(s, "R_IAFTER")) 		return (R_IAFTER);
+	if (!strcmp(s, "R_IBEFORE")) 		return (R_IBEFORE);
+	if (!strcmp(s, "R_LAST")) 		return (R_LAST);
+	if (!strcmp(s, "R_NEXT")) 		return (R_NEXT);
+	if (!strcmp(s, "R_NOOVERWRITE"))	return (R_NOOVERWRITE);
+	if (!strcmp(s, "R_PREV"))		return (R_PREV);
+	if (!strcmp(s, "R_SETCURSOR"))		return (R_SETCURSOR);
+
+	err("line %lu: %s: unknown flag", lineno, s);
+	/* NOTREACHED */
+}
+
+char *
+sflags(lflags)
+	int lflags;
+{
+	switch (lflags) {
+	case R_CURSOR:		return ("R_CURSOR");
+	case R_FIRST:		return ("R_FIRST");
+	case R_IAFTER:		return ("R_IAFTER");
+	case R_IBEFORE:		return ("R_IBEFORE");
+	case R_LAST:		return ("R_LAST");
+	case R_NEXT:		return ("R_NEXT");
+	case R_NOOVERWRITE:	return ("R_NOOVERWRITE");
+	case R_PREV:		return ("R_PREV");
+	case R_SETCURSOR:	return ("R_SETCURSOR");
+	}
+
+	return ("UNKNOWN!");
+}
+	
+DBTYPE
+dbtype(s)
+	char *s;
+{
+	if (!strcmp(s, "btree"))
+		return (DB_BTREE);
+	if (!strcmp(s, "hash"))
+		return (DB_HASH);
+	if (!strcmp(s, "recno"))
+		return (DB_RECNO);
+	err("%s: unknown type (use btree, hash or recno)", s);
+	/* NOTREACHED */
+}
+
+void *
+setinfo(db_type, s)
+	DBTYPE db_type;
+	char *s;
+{
+	static BTREEINFO ib;
+	static HASHINFO ih;
+	static RECNOINFO rh;
+	char *eq;
+
+	if ((eq = strchr(s, '=')) == NULL)
+		err("%s: illegal structure set statement", s);
+	*eq++ = '\0';
+	if (!isdigit((int) *eq))
+		err("%s: structure set statement must be a number", s);
+		
+	switch (db_type) {
+	case DB_BTREE:
+		if (!strcmp("flags", s)) {
+			ib.flags = atoi(eq);
+			return (&ib);
+		}
+		if (!strcmp("cachesize", s)) {
+			ib.cachesize = atoi(eq);
+			return (&ib);
+		}
+		if (!strcmp("maxkeypage", s)) {
+			ib.maxkeypage = atoi(eq);
+			return (&ib);
+		}
+		if (!strcmp("minkeypage", s)) {
+			ib.minkeypage = atoi(eq);
+			return (&ib);
+		}
+		if (!strcmp("lorder", s)) {
+			ib.lorder = atoi(eq);
+			return (&ib);
+		}
+		if (!strcmp("psize", s)) {
+			ib.psize = atoi(eq);
+			return (&ib);
+		}
+		break;
+	case DB_HASH:
+		if (!strcmp("bsize", s)) {
+			ih.bsize = atoi(eq);
+			return (&ih);
+		}
+		if (!strcmp("ffactor", s)) {
+			ih.ffactor = atoi(eq);
+			return (&ih);
+		}
+		if (!strcmp("nelem", s)) {
+			ih.nelem = atoi(eq);
+			return (&ih);
+		}
+		if (!strcmp("cachesize", s)) {
+			ih.cachesize = atoi(eq);
+			return (&ih);
+		}
+		if (!strcmp("lorder", s)) {
+			ih.lorder = atoi(eq);
+			return (&ih);
+		}
+		break;
+	case DB_RECNO:
+		if (!strcmp("flags", s)) {
+			rh.flags = atoi(eq);
+			return (&rh);
+		}
+		if (!strcmp("cachesize", s)) {
+			rh.cachesize = atoi(eq);
+			return (&rh);
+		}
+		if (!strcmp("lorder", s)) {
+			rh.lorder = atoi(eq);
+			return (&rh);
+		}
+		if (!strcmp("reclen", s)) {
+			rh.reclen = atoi(eq);
+			return (&rh);
+		}
+		if (!strcmp("bval", s)) {
+			rh.bval = atoi(eq);
+			return (&rh);
+		}
+		if (!strcmp("psize", s)) {
+			rh.psize = atoi(eq);
+			return (&rh);
+		}
+		break;
+	}
+	err("%s: unknown structure value", s);
+	/* NOTREACHED */
+}
+
+void *
+rfile(name, lenp)
+	char *name;
+	size_t *lenp;
+{
+	struct stat sb;
+	void *p;
+	int fd;
+	char *np;
+
+	for (; isspace((int) *name); ++name);
+	if ((np = strchr(name, '\n')) != NULL)
+		*np = '\0';
+	if ((fd = open(name, O_RDONLY, 0)) < 0 ||
+	    fstat(fd, &sb))
+		err("%s: %s\n", name, strerror(errno));
+#ifdef NOT_PORTABLE
+	if (sb.st_size > (off_t)SIZE_T_MAX)
+		err("%s: %s\n", name, strerror(E2BIG));
+#endif
+	if ((p = (void *)malloc((u_int)sb.st_size)) == NULL)
+		err("%s", strerror(errno));
+	(void)read(fd, p, (int)sb.st_size);
+	*lenp = sb.st_size;
+	(void)close(fd);
+	return (p);
+}
+
+void *
+xmalloc(text, len)
+	char *text;
+	size_t len;
+{
+	void *p;
+
+	if ((p = (void *)malloc(len)) == NULL)
+		err("%s", strerror(errno));
+	memmove(p, text, len);
+	return (p);
+}
+
+void
+usage()
+{
+	(void)fprintf(stderr,
+	    "usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
+	exit(1);
+}
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#ifdef __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+	char *fmt;
+        va_dcl
+#endif
+{
+	va_list ap;
+#ifdef __STDC__
+	va_start(ap, fmt);
+#else
+	va_start(ap);
+#endif
+	(void)fprintf(stderr, "dbtest: ");
+	(void)vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	(void)fprintf(stderr, "\n");
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/dictionary b/mechglue/src/plugins/kdb/db2/libdb2/test/dictionary
new file mode 100644
index 000000000..53640f016
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/dictionary
@@ -0,0 +1,308 @@
+abintrme
+ablatweo
+agdbevea
+aglamber
+aicehayt
+alerover
+anadanth
+ancmirtt
+ancthada
+angcther
+antasikt
+arathmsm
+arescofa
+arthatea
+asallyth
+asathedl
+ascelass
+athaneal
+atheneri
+atheryit
+athiopep
+athysidc
+atyhtiti
+auletard
+aytthepr
+bedthesa
+beiofttw
+bemofrda
+bertedud
+bessdide
+bestiemb
+blllanof
+bllssunt
+blstther
+bttelthh
+bulyousi
+bupedire
+buseatsd
+butritat
+byeditam
+cedvecur
+censaith
+centhfro
+centitar
+ceourire
+cetheaso
+chancora
+chavengl
+chederas
+chemsywh
+civadayo
+ckedacag
+ckstiptr
+colither
+congchin
+corepppl
+cronoria
+cthilath
+cthouthe
+ctofowon
+cumetbry
+dbethere
+degeerin
+detherai
+dingthin
+dryslyse
+dscesild
+ealecerm
+edftserh
+efosondi
+eherrreg
+emidesja
+ereananm
+estersns
+etedtili
+evermerh
+falsuran
+faringsi
+fawerist
+fcedethe
+fedhessh
+fedlerca
+feupbori
+ffeedift
+fllbasia
+foftabll
+fomehage
+fotsenki
+fwisudls
+ggeuptha
+gswofryt
+hedcecou
+hereacun
+huvedpth
+iabengre
+ianfovin
+iaresice
+iasmived
+idengedi
+ilftisut
+ilinefem
+imeorran
+imsstoft
+inararto
+indanrei
+ingelaly
+ingeored
+inmotiom
+inoatlfr
+inoviler
+insedihe
+intaspan
+intowade
+inyfeprt
+iobloinc
+ionepuse
+iourofig
+ireeingi
+irreland
+irsfandb
+isewhell
+isocisad
+isriacth
+istaverr
+ithmblet
+itoingri
+itongala
+itsgrint
+ivyttisa
+laltthea
+lanesmef
+lanonepi
+lerithay
+lllmeris
+lysatspa
+lysceert
+masishio
+mathmmat
+meastrei
+medengny
+medwindb
+membonam
+moronash
+mpeotlin
+msomirei
+msrmstri
+mstirtis
+nbempeef
+ncheckno
+nddtthec
+ndilymor
+nditheiv
+ndoncath
+nenkingo
+ngryasth
+nichelnd
+nndarrof
+nongeatt
+noviearc
+npecheca
+nsttmema
+nwiowhan
+oalsaldt
+obullury
+odtenens
+offorind
+ofoditin
+ogarofab
+olossofe
+olspooth
+omajorul
+omantrvi
+omawevat
+onotorit
+oorendbe
+oosarang
+othowong
+otinffte
+ouatheno
+ountshep
+ouputope
+owhesatu
+owiaindh
+padisath
+pangream
+pawicofa
+pendamam
+pepofond
+peroncti
+perysege
+petotith
+plocarov
+pomasbor
+powholyi
+ppllosof
+pptinoma
+psenesff
+puiondit
+reestand
+rendlabl
+rerathsy
+rewathat
+rirndiff
+ritricui
+samasome
+satameer
+sathecur
+sbespral
+sconbeis
+sedfinhe
+sharveon
+shhoftrd
+sianthem
+sieaveve
+simedera
+sinandff
+sinulsma
+sllobofl
+sndfermh
+soffatic
+soingris
+songiorb
+sthottsa
+suewemat
+swicales
+tagttisf
+tanalatt
+tancodbo
+tarethal
+tbisesia
+teftyall
+tengstwh
+tepeshth
+teranand
+tevinohi
+tgthehal
+thansirs
+thecequs
+thereaco
+therimut
+therorea
+thestiom
+theveame
+thhastth
+thiasatt
+thidirve
+thingbaa
+thithbed
+thovires
+thswenpe
+thublthe
+tiamarss
+tincthes
+tindtofo
+tinedave
+tisanwex
+tlarnste
+tleicorb
+tnymesie
+toftemal
+tombeasw
+torarsen
+totheheo
+toudanty
+tremywel
+treonove
+trhandfy
+trrhmont
+trysnter
+tssasofo
+ttemaith
+ttiserds
+ttorissa
+tuiabeoi
+twirfton
+tyhentha
+tyngorti
+tyoarich
+ucatbouc
+ungyconh
+untinore
+uopsaren
+upecmuit
+ureaidrb
+usinittr
+ussofedt
+usunochp
+utbapofo
+veveplel
+vimathea
+walondui
+wavairet
+waysioft
+wceempil
+wealttig
+wefondio
+werdtian
+weswevar
+whaclthe
+wheanler
+wheiforv
+whisurtr
+whrithat
+wiesulci
+wirofrec
+witthile
+wtserodr
+ybutherr
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/Makefile b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/Makefile
new file mode 100644
index 000000000..348a8f818
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/Makefile
@@ -0,0 +1,43 @@
+#	@(#)Makefile	8.16 (Berkeley) 11/20/95
+
+ALL = driver2 tcreat3 tdel thash4 tread2 tseq tverify
+OBJ = driver2.o tcreat3.o tdel.o thash4.o tread2.o tseq.o tverify.o
+CC = gcc
+
+all: ${ALL}
+
+# Uncomment the STAT line get hash and btree statistical use info.  This
+# also forces ld to load the btree debug functions for use by gdb, which
+# is useful.  The db library has to be compiled with -DSTATISTICS as well.
+INC=	-I${PORTDIR}/include -I${PORTDIR}
+OORG=	-g
+#STAT=	-DSTATISTICS
+CFLAGS=	-D__DBINTERFACE_PRIVATE -DDEBUG ${STAT} ${OORG} ${INC}
+
+tcreat3: tcreat3.o ${PORTDIR}/libdb.a
+	${CC} -o $@ tcreat3.o ${PORTDIR}/libdb.a
+
+tdel: tdel.o ${PORTDIR}/libdb.a
+	${CC} -o $@ tdel.o ${PORTDIR}/libdb.a
+
+thash4: thash4.o ${PORTDIR}/libdb.a
+	${CC} -o $@ thash4.o ${PORTDIR}/libdb.a
+
+tread2: tread2.o ${PORTDIR}/libdb.a
+	${CC} -o $@ tread2.o ${PORTDIR}/libdb.a
+
+tseq: tseq.o ${PORTDIR}/libdb.a
+	${CC} -o $@ tseq.o ${PORTDIR}/libdb.a
+
+tverify: tverify.o ${PORTDIR}/libdb.a
+	${CC} -o $@ tverify.o ${PORTDIR}/libdb.a
+
+driver2: driver2.o ${PORTDIR}/libdb.a
+	${CC} -o $@ driver2.o ${PORTDIR}/libdb.a
+
+strerror.o: ${PORTDIR}/clib/strerror.c
+	${CC} -c ${PORTDIR}/clib/strerror.c
+
+clean:
+	rm -f *.core gmon.out ${ALL} ${OBJ} t1 t2 t3
+
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/driver2.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/driver2.c
new file mode 100644
index 000000000..6a3b432cb
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/driver2.c
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)driver2.c	8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+/*
+ * Test driver, to try to tackle the large ugly-split problem.
+ */
+
+#include <sys/file.h>
+#include <stdio.h>
+#include "ndbm.h"
+
+int my_hash(key, len)
+	char	*key;
+	int	len;
+{
+	return(17);		/* So I'm cruel... */
+}
+
+main(argc, argv)
+	int	argc;
+{
+	DB	*db;
+	DBT	key, content;
+	char	keybuf[2049];
+	char	contentbuf[2049];
+	char	buf[256];
+	int	i;
+	HASHINFO	info;
+
+	info.bsize = 1024;
+	info.ffactor = 5;
+	info.nelem = 1;
+	info.cachesize = NULL;
+#ifdef HASH_ID_PROGRAM_SPECIFIED
+	info.hash_id = HASH_ID_PROGRAM_SPECIFIED;
+	info.hash_func = my_hash;
+#else
+	info.hash = my_hash;
+#endif
+	info.lorder = 0;
+	if (!(db = dbopen("bigtest", O_RDWR | O_CREAT | O_BINARY, 0644, DB_HASH, &info))) {
+		sprintf(buf, "dbopen: failed on file bigtest");
+		perror(buf);
+		exit(1);
+	}
+	srand(17);
+	key.data = keybuf;
+	content.data = contentbuf;
+	memset(keybuf, '\0', sizeof(keybuf));
+	memset(contentbuf, '\0', sizeof(contentbuf));
+	for (i=1; i <= 500; i++) {
+		key.size = 128 + (rand()&1023);
+		content.size = 128 + (rand()&1023);
+/*		printf("%d: Key size %d, data size %d\n", i, key.size,
+		       content.size); */
+		sprintf(keybuf, "Key #%d", i);
+		sprintf(contentbuf, "Contents #%d", i);
+		if ((db->put)(db, &key, &content, R_NOOVERWRITE)) {
+			sprintf(buf, "dbm_store #%d", i);
+			perror(buf);
+		}
+	}
+	if ((db->close)(db)) {
+		perror("closing hash file");
+		exit(1);
+	}
+	exit(0);
+}
+
+	
+
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/makedb.sh b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/makedb.sh
new file mode 100644
index 000000000..15901de19
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/makedb.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+#	@(#)makedb.sh	8.1 (Berkeley) 6/4/93
+
+awk '{i++; print $0; print i;}' /usr/local/lib/dict/words > WORDS
+ls /bin /usr/bin /usr/ucb /etc | egrep '^(...|....|.....|......)$' | \
+sort | uniq | \
+awk '{
+	printf "%s\n", $0
+	for (i = 0; i < 1000; i++)
+		printf "%s+", $0
+	printf "\n"
+}' > LONG.DATA
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tcreat3.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tcreat3.c
new file mode 100644
index 000000000..f11487b32
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tcreat3.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)tcreat3.c	8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include "db-int.h"
+
+#define INITIAL	25000
+#define MAXWORDS    25000	       /* # of elements in search table */
+
+char	wp1[8192];
+char	wp2[8192];
+main(argc, argv)
+char **argv;
+{
+	DBT item, key;
+	DB	*dbp;
+	HASHINFO ctl;
+	FILE *fp;
+	int	trash;
+
+	int i = 0;
+
+	argv++;
+	ctl.hash = NULL;
+	ctl.bsize = atoi(*argv++);
+	ctl.ffactor = atoi(*argv++);
+	ctl.nelem = atoi(*argv++);
+	ctl.lorder = 0;
+	if (!(dbp = dbopen( "hashtest",
+	    O_CREAT|O_TRUNC|O_RDWR|O_BINARY, 0600, DB_HASH, &ctl))){
+		/* create table */
+		fprintf(stderr, "cannot create: hash table (size %d)\n",
+			INITIAL);
+		exit(1);
+	}
+
+	key.data = wp1;
+	item.data = wp2;
+	while ( fgets(wp1, 8192, stdin) &&
+		fgets(wp2, 8192, stdin) &&
+		i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+		key.size = strlen(wp1);
+		item.size = strlen(wp2);
+
+/*
+ * enter key/data pair into the table
+ */
+		if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
+			fprintf(stderr, "cannot enter: key %s\n",
+				item.data);
+			exit(1);
+		}			
+	}
+
+	(dbp->close)(dbp);
+	exit(0);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tdel.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tdel.c
new file mode 100644
index 000000000..826611486
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tdel.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)tdel.c	8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include "db-int.h"
+#include <stdio.h>
+
+#define INITIAL	25000
+#define MAXWORDS    25000	       /* # of elements in search table */
+
+/* Usage: thash pagesize fillfactor file */
+char	wp1[8192];
+char	wp2[8192];
+main(argc, argv)
+char **argv;
+{
+	DBT item, key;
+	DB	*dbp;
+	HASHINFO ctl;
+	FILE *fp;
+	int	stat;
+
+	int i = 0;
+
+	argv++;
+	ctl.nelem = INITIAL;
+	ctl.hash = NULL;
+	ctl.bsize = atoi(*argv++);
+	ctl.ffactor = atoi(*argv++);
+	ctl.cachesize = 1024 * 1024;	/* 1 MEG */
+	ctl.lorder = 0;
+	argc -= 2;
+	if (!(dbp = dbopen( NULL, O_CREAT|O_RDWR|O_BINARY, 0400, DB_HASH, &ctl))) {
+		/* create table */
+		fprintf(stderr, "cannot create: hash table size %d)\n",
+			INITIAL);
+		exit(1);
+	}
+
+	key.data = wp1;
+	item.data = wp2;
+	while ( fgets(wp1, 8192, stdin) &&
+		fgets(wp2, 8192, stdin) &&
+		i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+		key.size = strlen(wp1);
+		item.size = strlen(wp2);
+
+/*
+ * enter key/data pair into the table
+ */
+		if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
+			fprintf(stderr, "cannot enter: key %s\n",
+				item.data);
+			exit(1);
+		}			
+	}
+
+	if ( --argc ) {
+		fp = fopen ( argv[0], "r");
+		i = 0;
+		while ( fgets(wp1, 8192, fp) &&
+			fgets(wp2, 8192, fp) &&
+			i++ < MAXWORDS) {
+		    key.size = strlen(wp1);
+		    stat = (dbp->del)(dbp, &key, 0);
+		    if (stat) {
+			fprintf ( stderr, "Error retrieving %s\n", key.data );
+			exit(1);
+		    } 
+		}
+		fclose(fp);
+	}
+	(dbp->close)(dbp);
+	exit(0);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/testit b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/testit
new file mode 100644
index 000000000..c80dc4e69
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/testit
@@ -0,0 +1,154 @@
+#!/bin/csh -f
+#
+#	@(#)testit	8.1 (Berkeley) 6/4/93
+#
+
+echo ""
+echo "PAGE FILL "
+set name=WORDS
+	set i = 256
+	foreach j ( 11 14 21 )
+	    echo "thash4 $i $j"
+	    ./thash4 $i $j 25000 65536 $name < $name
+	end
+	set i = 512
+	foreach j ( 21 28 43 )
+	    echo "thash4 $i $j"
+	    ./thash4 $i $j 25000 65536  $name < $name
+	end
+	set i = 1024
+	foreach j ( 43 57 85 )
+	    echo "thash4 $i $j"
+	    ./thash4 $i $j 25000 65536 $name < $name
+	end
+	set i = 2048
+	foreach j ( 85 114 171 )
+	    echo "thash4 $i $j"
+	    ./thash4 $i $j 25000 65536 $name < $name
+	end
+	set i = 4096
+	foreach j ( 171 228 341 )
+	    echo "thash4 $i $j"
+	    ./thash4 $i $j 25000 65536 $name < $name
+	end
+	set i = 8192
+	foreach j ( 341 455 683 )
+	    echo "thash4 $i $j"
+	    ./thash4 $i $j 25000 65536 $name < $name
+	end
+	echo "PAGE FILL "
+	set i = 256
+	foreach j ( 11 14 21 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 25000 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+	set i = 512
+	foreach j ( 21 28 43 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 25000 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+	set i = 1024
+	foreach j ( 43 57 85 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 25000 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+	set i = 2048
+	foreach j ( 85 114 171 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 25000 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+	set i = 4096
+	foreach j ( 171 228 341 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 25000 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+	set i = 8192
+	foreach j ( 341 455 683 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 25000 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+set name=LONG.DATA
+	set i = 1024
+	foreach j ( 1 2 4 )
+	    echo ./thash4 $i $j 600 65536 $name 
+	    ./thash4 $i $j 600 65536 $name < $name
+	end
+
+	set i = 2048
+	foreach j ( 1 2 4 )
+	    echo ./thash4 $i $j 600 65536 $name 
+	    ./thash4 $i $j 600 65536 $name < $name
+	end
+	set i = 4096
+	foreach j ( 1 2 4 )
+	    echo ./thash4 $i $j 600 65536 $name 
+	    ./thash4 $i $j 600 65536 $name < $name
+	end
+	set i = 8192
+	foreach j ( 2 4 8 )
+	    echo ./thash4 $i $j 600 65536 $name 
+	    ./thash4 $i $j 600 65536 $name < $name
+	end
+	echo "PAGE FILL "
+	set i = 1024
+	foreach j ( 1 2 4 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 600 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+	set i = 2048
+	foreach j ( 1 2 4 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 600 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+	set i = 4096
+	foreach j ( 1 2 4 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 600 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+	set i = 8192
+	foreach j ( 2 4 8 )
+	    echo "$i"_"$j"
+	    ./tcreat3 $i $j 600 $name < $name
+	    ./tread2 65536 < $name
+	    ./tverify $name < $name
+	    ./tseq > /dev/null
+	    ./tdel $i $j  $name < $name
+	end
+
+./driver2
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/thash4.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/thash4.c
new file mode 100644
index 000000000..b15b617bc
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/thash4.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)thash4.c	8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <errno.h>
+#include "db-int.h"
+
+#define INITIAL	25000
+#define MAXWORDS    25000	       /* # of elements in search table */
+
+/* Usage: thash pagesize fillfactor file */
+char	wp1[8192];
+char	wp2[8192];
+main(argc, argv)
+char **argv;
+{
+	DBT item, key, res;
+	DB *dbp;
+	HASHINFO ctl;
+	FILE *fp;
+	int	stat;
+	time_t	t;
+
+	int i = 0;
+
+	argv++;
+	ctl.hash = NULL;
+	ctl.bsize = atoi(*argv++);
+	ctl.ffactor = atoi(*argv++);
+	ctl.nelem = atoi(*argv++);
+	ctl.cachesize = atoi(*argv++);
+	ctl.lorder = 0;
+	if (!(dbp = dbopen( NULL, O_CREAT|O_RDWR|O_BINARY, 0400, DB_HASH, &ctl))) {
+		/* create table */
+		fprintf(stderr, "cannot create: hash table size %d)\n",
+			INITIAL);
+		fprintf(stderr, "\terrno: %d\n", errno);
+		exit(1);
+	}
+
+	key.data = wp1;
+	item.data = wp2;
+	while ( fgets(wp1, 8192, stdin) && 
+		fgets(wp2, 8192, stdin) && 
+		i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+		key.size = strlen(wp1);
+		item.size = strlen(wp2);
+
+/*
+ * enter key/data pair into the table
+ */
+		if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
+			fprintf(stderr, "cannot enter: key %s\n",
+				item.data);
+			fprintf(stderr, "\terrno: %d\n", errno);
+			exit(1);
+		}			
+	}
+
+	if ( --argc ) {
+		fp = fopen ( argv[0], "r");
+		i = 0;
+		while ( fgets(wp1, 256, fp) && 
+			fgets(wp2, 8192, fp) && 
+			i++ < MAXWORDS) {
+
+		    key.size = strlen(wp1);
+		    stat = (dbp->get)(dbp, &key, &res, 0);
+		    if (stat < 0 ) {
+			fprintf ( stderr, "Error retrieving %s\n", key.data );
+			fprintf(stderr, "\terrno: %d\n", errno);
+			exit(1);
+		    } else if ( stat > 0 ) {
+			fprintf ( stderr, "%s not found\n", key.data );
+			fprintf(stderr, "\terrno: %d\n", errno);
+			exit(1);
+		    }
+		}
+		fclose(fp);
+	}
+	dbp->close(dbp);
+	exit(0);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tread2.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tread2.c
new file mode 100644
index 000000000..1e2cc4c50
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tread2.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)tread2.c	8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include "db-int.h"
+
+#define INITIAL	25000
+#define MAXWORDS    25000	       /* # of elements in search table */
+
+typedef struct {		       /* info to be stored */
+	int num, siz;
+} info;
+
+char	wp1[8192];
+char	wp2[8192];
+main(argc, argv)
+char **argv;
+{
+	DBT item, key, res;
+	DB	*dbp;
+	HASHINFO ctl;
+	int	stat;
+
+	int i = 0;
+
+	ctl.nelem = INITIAL;
+	ctl.hash = NULL;
+	ctl.bsize = 64;
+	ctl.ffactor = 1;
+	ctl.cachesize = atoi(*argv++);
+	ctl.lorder = 0;
+	if (!(dbp = dbopen( "hashtest", O_RDONLY|O_BINARY, 0400, DB_HASH, &ctl))) {
+		/* create table */
+		fprintf(stderr, "cannot open: hash table\n" );
+		exit(1);
+	}
+
+	key.data = wp1;
+	item.data = wp2;
+	while ( fgets(wp1, 8192, stdin) &&
+		fgets(wp2, 8192, stdin) &&
+		i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+		key.size = strlen(wp1);
+		item.size = strlen(wp2);
+
+		stat = (dbp->get)(dbp, &key, &res,0);
+		if (stat < 0) {
+		    fprintf ( stderr, "Error retrieving %s\n", key.data );
+		    exit(1);
+		} else if ( stat > 0 ) {
+		    fprintf ( stderr, "%s not found\n", key.data );
+		    exit(1);
+		}
+	}
+	(dbp->close)(dbp);
+	exit(0);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tseq.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tseq.c
new file mode 100644
index 000000000..d2d36862d
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tseq.c
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)tseq.c	8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include "db-int.h"
+
+#define INITIAL	25000
+#define MAXWORDS    25000	       /* # of elements in search table */
+
+
+char	wp[8192];
+char	cp[8192];
+main(argc, argv)
+char **argv;
+{
+	DBT item, key, res;
+	DB	*dbp;
+	FILE *fp;
+	int	stat;
+
+	if (!(dbp = dbopen( "hashtest", O_RDONLY|O_BINARY, 0400, DB_HASH, NULL))) {
+		/* create table */
+		fprintf(stderr, "cannot open: hash table\n" );
+		exit(1);
+	}
+
+/*
+* put info in structure, and structure in the item
+*/
+	for ( stat = (dbp->seq) (dbp, &res, &item, 1 ); 
+	      stat == 0;
+	      stat = (dbp->seq) (dbp, &res, &item, 0 ) ) {
+
+	      memcpy ( wp, res.data, res.size );
+	      wp[res.size] = 0;
+	      memcpy ( cp, item.data, item.size );
+	      cp[item.size] = 0;
+
+	      printf ( "%s %s\n", wp, cp );
+	}
+	(dbp->close)(dbp);
+	exit(0);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tverify.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tverify.c
new file mode 100644
index 000000000..4747804f7
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash1.tests/tverify.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)tverify.c	8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include "db-int.h"
+
+#define INITIAL	25000
+#define MAXWORDS    25000	       /* # of elements in search table */
+
+typedef struct {		       /* info to be stored */
+	int num, siz;
+} info;
+
+char	wp1[8192];
+char	wp2[8192];
+main(argc, argv)
+char **argv;
+{
+	DBT key, res;
+	DB	*dbp;
+	HASHINFO ctl;
+	int	trash;
+	int	stat;
+
+	int i = 0;
+
+	ctl.nelem = INITIAL;
+	ctl.hash = NULL;
+	ctl.bsize = 64;
+	ctl.ffactor = 1;
+	ctl.cachesize = 1024 * 1024;	/* 1 MEG */
+	ctl.lorder = 0;
+	if (!(dbp = dbopen( "hashtest", O_RDONLY|O_BINARY, 0400, DB_HASH, &ctl))) {
+		/* create table */
+		fprintf(stderr, "cannot open: hash table\n" );
+		exit(1);
+	}
+
+	key.data = wp1;
+	while ( fgets(wp1, 8192, stdin) &&
+		fgets(wp2, 8192, stdin) &&
+		i++ < MAXWORDS) {
+/*
+* put info in structure, and structure in the item
+*/
+		key.size = strlen(wp1);
+
+		stat = (dbp->get)(dbp, &key, &res,0);
+		if (stat < 0) {
+		    fprintf ( stderr, "Error retrieving %s\n", key.data );
+		    exit(1);
+		} else if ( stat > 0 ) {
+		    fprintf ( stderr, "%s not found\n", key.data );
+		    exit(1);
+		}
+		if ( memcmp ( res.data, wp2, res.size ) ) {
+		    fprintf ( stderr, "data for %s is incorrect.  Data was %s.  Should have been %s\n", key.data, res.data, wp2 );
+		}
+	}
+	(dbp->close)(dbp);
+	exit(0);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/README b/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/README
new file mode 100644
index 000000000..f29ccf7e1
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/README
@@ -0,0 +1,72 @@
+#	@(#)README	8.1 (Berkeley) 6/4/93
+
+This package implements a superset of the hsearch and dbm/ndbm libraries.
+
+Test Programs:
+	All test programs which need key/data pairs expect them entered
+	with key and data on separate lines
+
+	tcreat3.c	
+		Takes 
+			bucketsize (bsize), 
+			fill factor (ffactor), and
+			initial number of elements (nelem).  
+		Creates a hash table named hashtest containing the 
+		keys/data pairs entered from standard in.
+	thash4.c
+		Takes
+			bucketsize (bsize), 
+			fill factor (ffactor), 
+			initial number of elements (nelem)
+			bytes of cache (ncached), and
+			file from which to read data  (fname)
+		Creates a table from the key/data pairs on standard in and
+		then does a read of each key/data in fname
+	tdel.c
+		Takes
+			bucketsize (bsize), and
+			fill factor (ffactor).
+			file from which to read data (fname)
+		Reads each key/data pair from fname and deletes the
+		key from the hash table hashtest
+	tseq.c
+		Reads the key/data pairs in the file hashtest and writes them
+		to standard out.
+	tread2.c
+		Takes
+			butes of cache (ncached).
+		Reads key/data pairs from standard in and looks them up
+		in the file hashtest.
+	tverify.c
+		Reads key/data pairs from standard in, looks them up
+		in the file hashtest, and verifies that the data is
+		correct.
+
+NOTES:
+
+The file search.h is provided for using the hsearch compatible interface
+on BSD systems.  On System V derived systems, search.h should appear in 
+/usr/include.
+
+The man page ../man/db.3 explains the interface to the hashing system.
+The file hash.ps is a postscript copy of a paper explaining
+the history, implementation, and performance of the hash package.
+
+"bugs" or idiosyncracies
+
+If you have a lot of overflows, it is possible to run out of overflow
+pages.  Currently, this will cause a message to be printed on stderr.
+Eventually, this will be indicated by a return error code.
+
+If you are using the ndbm interface and exit without flushing or closing the
+file, you may lose updates since the package buffers all writes.  Also,
+the db interface only creates a single database file.  To avoid overwriting
+the user's original file, the suffix ".db" is appended to the file name
+passed to dbm_open.  Additionally, if your code "knows" about the historic
+.dir and .pag files, it will break.  
+
+There is a fundamental difference between this package and the old hsearch.
+Hsearch requires the user to maintain the keys and data in the application's
+allocated memory while hash takes care of all storage management.  The down
+side is that the byte strings passed in the ENTRY structure must be null
+terminated (both the keys and the data).
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/bigtest.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/bigtest.c
new file mode 100644
index 000000000..81c559ad2
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/bigtest.c
@@ -0,0 +1,76 @@
+#include "db-int.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdlib.h>
+
+int
+main(void)
+{
+	HASHINFO info;
+	DB *db;
+	DBT key, value, returned;
+	int *data;
+	int n, i;
+
+	info.bsize = 512;
+	info.cachesize = 500;
+	info.lorder = 0;
+	info.ffactor = 4;
+	info.nelem = 0;
+	info.hash = NULL;
+
+	db = dbopen("big2.db", O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0664, DB_HASH, &info);
+	data = malloc(800 * sizeof(int));
+	for (n = 0; n < 800; n++)
+		data[n] = 0xDEADBEEF;
+	key.size = sizeof(int);
+	key.data = &n;
+	value.size = 800 * sizeof(int);
+	value.data = (void *)data;
+
+	for (n = 0; n < 200000; n++) {
+		returned.data = NULL;
+		if (n == 4627)
+			printf("");
+		if (n % 50 == 0) 
+			printf("put n = %d\n", n);
+		if (db->put(db, &key, &value, 0) != 0)	
+			printf("put error, n = %d\n", n);
+		if (db->get(db, &key, &returned, 0) != 0)
+			printf("Immediate get error, n = %d\n", n);
+		assert (returned.size == 3200);
+		for (i = 0; i < 800; i++)
+			if (((int *)returned.data)[i] != 0xDEADBEEF)
+				printf("ERRORRRRRR!!!\n");
+
+	}
+
+	for (n = 0; n < 200000; n++) {
+		if (n % 50 == 0) 
+			printf("seq n = %d\n", n);
+		if ((db->seq(db, &key, &returned, 0)) != 0)
+			printf("Seq error, n = %d\n", n);
+
+		assert(returned.size == 3200);
+
+		for (i = 0; i < 800; i++)
+			if (((int *)returned.data)[i] != 0xDEADBEEF)
+				printf("ERRORRRRRR!!! seq %d\n", n);
+	}		
+
+	for (n = 0; n < 2000; n++) {
+		if (n % 50 == 0) 
+			printf("get n = %d\n", n);
+		if (db->get(db, &key, &returned, 0) != 0)
+			printf("Late get error, n = %d\n", n);
+		assert(returned.size == 1200);
+		for (i = 0; i < 300; i++)
+			if (((int *)returned.data)[i] != 0xDEADBEEF)
+				printf("ERRORRRRRR!!!, get %d\n", n);
+	}
+   	db->close(db);
+	free(value.data);
+	return(0);
+}
+
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/passtest.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/passtest.c
new file mode 100644
index 000000000..adb72c004
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/passtest.c
@@ -0,0 +1,184 @@
+#include "db-int.h"
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+extern int hash_expansions;
+
+int
+main(void)
+{
+    FILE *keys, *vals;
+    DB *db;
+    DBT key, val;
+    char *key_line, *val_line, *get_key, *get_val, *old, *key2;
+    HASHINFO passwd;
+    int n = 0, i = 0, expected;
+   
+    key_line = (char *)malloc(100);
+    val_line = (char *)malloc(300);
+    old = (char *)malloc(300);
+
+    keys = fopen("yp.keys", "rt");
+    vals = fopen("yp.total", "rt");
+
+    passwd.bsize =  1024;
+    passwd.cachesize = 1024 * 1024;
+    passwd.ffactor = 10;
+    passwd.hash = NULL;
+    passwd.nelem = 0;
+    passwd.lorder = 4321;
+	
+
+    db = dbopen("/usr/tmp/passwd.db", O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0664, DB_HASH, 
+		&passwd);
+    if (!db) {
+	fprintf(stderr, "create_db: couldn't create database file\n");
+	exit(1);
+    }
+ 
+    while ((key_line = fgets(key_line, 100, keys)) != NULL) {
+	if (n % 1000 == 0)
+	  fprintf(stderr, "Putting #%d.\n", n);
+	n++;
+	fgets(val_line, 300, vals);
+	key.size = strlen(key_line);
+	key.data = (void *)key_line;
+	val.size = strlen(val_line);
+	val.data = (void *)val_line;
+	if (db->put(db, &key, &val, 0) != 0)
+	  fprintf(stderr, "Put error, n = %d\n", n);
+	if (db->get(db, &key, &val, 0) != 0)
+	  fprintf(stderr, "Immediate get error, n = %d\n", n);
+    }
+    fprintf(stderr, "Done with put!\n");
+    free(key_line);	
+    free(val_line);
+    fclose(keys);
+    fclose(vals);
+    db->close(db);
+
+
+
+	
+    keys = fopen("yp.keys", "rt");
+    vals = fopen("yp.total", "rt");
+    get_key = (char *)malloc(100);
+    get_val = (char *)malloc(300);
+
+    db = dbopen("/usr/tmp/passwd.db", O_RDWR|O_BINARY, 0664, DB_HASH, &passwd);
+    if (!db)
+      fprintf(stderr, "Could not open db!\n");
+    n = 0;
+    while ((get_key = fgets(get_key, 100, keys)) != NULL) {
+	n++;
+	if (n % 1000 == 0)
+	  fprintf(stderr, "Getting #%d.\n", n);
+	key.size = strlen(get_key);
+	key.data = (void *)get_key;
+	if (db->get(db, &key, &val, 0) != 0)
+	  fprintf(stderr, "Retrieval error on %s\n", get_key);
+	fgets(get_val, 300, vals);
+	if (memcmp(val.data, (void *)get_val, val.size)) {
+	    fprintf(stderr, "Unmatched get on %s.\n", get_key);
+	    fprintf(stderr, "Input = %s\nOutput = %s\n", get_val, 
+		    (char *)val.data);
+	}
+    }
+    expected = n;
+    fclose(vals);
+    fclose(keys);
+    free(get_key);
+    free(get_val);
+    db->close(db);
+
+
+
+
+    get_key = (char *)malloc(100);
+    get_val = (char *)malloc(300);
+
+    db = dbopen("/usr/tmp/passwd.db", O_RDWR, 0664, DB_HASH, &passwd);
+    if (!db)
+      fprintf(stderr, "Could not open db!\n");
+    n = 0;
+    for (;;) {
+	n++;
+	if (n % 1000 == 0)
+	  fprintf(stderr, "Sequence getting #%d.\n", n);
+	if (db->seq(db, &key, &val, 0) != 0) {
+	    fprintf(stderr, 
+		    "Exiting sequence retrieve; n = %d, expected = %d\n",
+		    n - 1 , expected);
+	    break;
+	}
+    }
+    free(get_key);
+    free(get_val);
+    db->close(db);
+
+    get_key = (char *)malloc(100);
+    key2 = (char *)malloc(100);
+
+    keys = fopen("yp.keys", "rt");
+    vals = fopen("yp.total", "rt");
+
+    db = dbopen("/usr/tmp/passwd.db", O_RDWR|O_BINARY, 0664, DB_HASH, &passwd);
+    n = 0;
+    while ((get_key = fgets(get_key, 100, keys)) != NULL) {
+	if (n % 1000 == 0)
+	  fprintf(stderr, "Deleting #%d.\n", n);
+	n+=2;
+	key2 = fgets(get_key, 100, keys);
+	if (!key2)
+	  break;	
+	key.data = (void *)key2;
+	key.size = strlen(key2);
+	if (db->del(db, &key, 0) != 0)
+	  fprintf(stderr, "Delete error on %d", n);
+    }
+
+    db->close(db);
+    free(get_key);
+    free(key2);
+    fclose(keys);
+    fclose(vals);
+
+    get_key = (char *)malloc(100);
+    key2 = (char *)malloc(100);
+    get_val = (char *)malloc(300);
+
+    keys = fopen("yp.keys", "rt");
+    vals = fopen("yp.total", "rt");
+	
+    db = dbopen("/usr/tmp/passwd.db", O_RDWR|O_BINARY, 0664, DB_HASH, &passwd);
+    n = 0;
+    while ((get_key = fgets(get_key, 100, keys)) != NULL) {
+	n += 2;
+	if (n % 1000 == 0)
+	  fprintf(stderr, "Re-retrieving #%d.\n", n);
+	key2 = fgets(key2, 100, keys);
+	if (!key2)
+	  break;
+	key.data = (void *)get_key;	
+	key.size = strlen(get_key);
+	if (db->get(db, &key, &val, 0) != 0)	
+	  fprintf(stderr, "Retrieval after delete error on %d\n", n);
+	fgets(get_val, 300, vals);
+	if (memcmp(val.data, (void *)get_val, val.size)) {
+	    fprintf(stderr, "Unmatched get after delete on %s.\n", get_key);
+	    fprintf(stderr, "Input = %s\nOutput = %s\n", get_val, 
+		    (char *)val.data);
+	}
+	fgets(get_val, 300, vals);
+    }
+
+    db->close(db);
+    free(get_key);
+    free(key2);
+    free(get_val);
+    fclose(keys);
+    fclose(vals);
+
+    exit(0);
+}
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/passwd/genpass.c b/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/passwd/genpass.c
new file mode 100644
index 000000000..da3767687
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/hash2.tests/passwd/genpass.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+main(int argc, char **argv)
+{
+	int i,j,n;
+	char *pass[8], r;
+	
+	n = atoi(argv[1]);
+
+	srandom(101173);
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < 8; j++) {
+			r = random() % 122;
+			while (r < 48)
+				r += random() % (122 - r);
+			printf("%c", r);
+		}
+		printf("\n");
+	}
+}
+
diff --git a/mechglue/src/plugins/kdb/db2/libdb2/test/run.test b/mechglue/src/plugins/kdb/db2/libdb2/test/run.test
new file mode 100644
index 000000000..48c3a63d0
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/libdb2/test/run.test
@@ -0,0 +1,746 @@
+#!/bin/sh -
+#
+#	@(#)run.test	8.13 (Berkeley) 11/2/95
+#
+
+# db regression tests
+main()
+{
+
+	PROG=./dbtest
+	TMP1=${TMPDIR-.}/t1
+	TMP2=${TMPDIR-.}/t2
+	TMP3=${TMPDIR-.}/t3
+
+	if [ \! -z "$WORDLIST" -a -f "$WORDLIST" ]; then
+		DICT=$WORDLIST
+	elif [ -f /usr/local/lib/dict/words ]; then
+		DICT=/usr/local/lib/dict/words
+	elif [ -f /usr/share/dict/words ]; then
+		DICT=/usr/share/dict/words
+	elif [ -f /usr/dict/words ]; then
+		DICT=/usr/dict/words
+	elif [ -f /usr/share/lib/dict/words ]; then
+		DICT=/usr/share/lib/dict/words
+	elif [ -f $srcdir/../test/dictionary ]; then
+		DICT=`cd $srcdir/../test && pwd`/dictionary
+	else
+		echo 'run.test: no dictionary'
+		exit 1
+	fi
+	
+	dictsize=`wc -l < $DICT`
+
+	bindir=/bin/.
+
+	if [ $# -eq 0 ]; then
+		for t in 1 2 3 4 5 6 7 8 9 10 11 12 13 20; do
+			test$t
+		done
+	else
+		while [ $# -gt 0 ]
+			do case "$1" in
+			test*)
+				$1;;
+			[0-9]*)
+				test$1;;
+			btree)
+				for t in 1 2 3 7 8 9 10 12 13; do
+					test$t
+				done;;
+			hash)
+				for t in 1 2 3 8 13 20; do
+					test$t
+				done;;
+			recno)
+				for t in 1 2 3 4 5 6 7 10 11; do
+					test$t
+				done;;
+			*)
+				echo "run.test: unknown test $1"
+				echo "usage: run.test test# | type"
+				exit 1
+			esac
+			shift
+		done
+	fi
+	rm -f $TMP1 $TMP2 $TMP3
+	exit 0
+}
+
+getnwords() {
+	# Delete blank lines because the db code appears not to
+	# like empty keys.  On Debian Linux, $DICT appears to contain
+	# some non-ASCII characters, and "rev" chokes on them.
+	sed -e '/^$/d' < $DICT | cat -v | sed -e ${1}q
+}
+
+# Take the first hundred entries in the dictionary, and make them
+# be key/data pairs.
+test1()
+{
+	echo "Test 1: btree, hash: small key, small data pairs"
+	getnwords 200 > $TMP1
+	for type in btree hash; do
+		rm -f $TMP2 $TMP3
+		for i in `cat $TMP1`; do
+			echo p
+			echo k$i
+			echo d$i
+			echo g
+			echo k$i
+		done > $TMP2
+		$PROG -o $TMP3 $type $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test1: type $type: failed"
+			exit 1
+		fi
+	done
+	echo "Test 1: recno: small key, small data pairs"
+	rm -f $TMP2 $TMP3
+	awk '{ 
+		++i;
+		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
+	}' < $TMP1 > $TMP2
+	$PROG -o $TMP3 recno $TMP2
+	if (cmp -s $TMP1 $TMP3) ; then :
+	else
+		echo "test1: type recno: failed"
+		exit 1
+	fi
+}
+
+# Take the first 200 entries in the dictionary, and give them
+# each a medium size data entry.
+test2()
+{
+	echo "Test 2: btree, hash: small key, medium data pairs"
+	mdata=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
+	echo $mdata |
+	awk '{ for (i = 1; i < 201; ++i) print $0 }' > $TMP1
+	for type in hash btree; do
+		rm -f $TMP2 $TMP3
+		for i in `getnwords 200`; do
+			echo p
+			echo k$i
+			echo d$mdata
+			echo g
+			echo k$i
+		done > $TMP2
+		$PROG -o $TMP3 $type $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test2: type $type: failed"
+			exit 1
+		fi
+	done
+	echo "Test 2: recno: small key, medium data pairs"
+	rm -f $TMP2 $TMP3
+	echo $mdata | 
+	awk '{  for (i = 1; i < 201; ++i)
+		printf("p\nk%d\nd%s\ng\nk%d\n", i, $0, i);
+	}' > $TMP2
+	$PROG -o $TMP3 recno $TMP2
+	if (cmp -s $TMP1 $TMP3) ; then :
+	else
+		echo "test2: type recno: failed"
+		exit 1
+	fi
+}
+
+# Insert the programs in $bindir with their paths as their keys.
+test3()
+{
+	echo "Test 3: hash: small key, big data pairs"
+	rm -f $TMP1
+	(find $bindir -type f -exec test -r {} \; -print | xargs cat) > $TMP1
+	for type in hash; do
+		rm -f $TMP2 $TMP3
+		for i in `find $bindir -type f -exec test -r {} \; -print`; do
+			echo p
+			echo k$i
+			echo D$i
+			echo g
+			echo k$i
+		done > $TMP2
+		$PROG -o $TMP3 $type $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test3: $type: failed"
+			exit 1
+		fi
+	done
+	echo "Test 3: btree: small key, big data pairs"
+	for psize in 512 16384 65536; do
+		echo "    page size $psize"
+		for type in btree; do
+			rm -f $TMP2 $TMP3
+			for i in `find $bindir -type f -exec test -r {} \; -print`; do
+				echo p
+				echo k$i
+				echo D$i
+				echo g
+				echo k$i
+			done > $TMP2
+			$PROG -i psize=$psize -o $TMP3 $type $TMP2
+			if (cmp -s $TMP1 $TMP3) ; then :
+			else
+				echo "test3: $type: page size $psize: failed"
+				exit 1
+			fi
+		done
+	done
+	echo "Test 3: recno: big data pairs"
+	rm -f $TMP2 $TMP3
+	find $bindir -type f -exec test -r {} \; -print | 
+	awk '{
+		++i;
+		printf("p\nk%d\nD%s\ng\nk%d\n", i, $0, i);
+	}' > $TMP2
+	for psize in 512 16384 65536; do
+		echo "    page size $psize"
+		$PROG -i psize=$psize -o $TMP3 recno $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test3: recno: page size $psize: failed"
+			exit 1
+		fi
+	done
+}
+
+# Do random recno entries.
+test4()
+{
+	echo "Test 4: recno: random entries"
+	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+	awk '{
+		for (i = 37; i <= 37 + 88 * 17; i += 17) {
+			if (i % 41)
+				s = substr($0, 1, i % 41);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		for (i = 1; i <= 15; ++i) {
+			if (i % 41)
+				s = substr($0, 1, i % 41);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		for (i = 19234; i <= 19234 + 61 * 27; i += 27) {
+			if (i % 41)
+				s = substr($0, 1, i % 41);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		exit
+	}' > $TMP1
+	rm -f $TMP2 $TMP3
+	cat $TMP1 |
+	awk 'BEGIN {
+			i = 37;
+			incr = 17;
+		}
+		{
+			printf("p\nk%d\nd%s\n", i, $0);
+			if (i == 19234 + 61 * 27)
+				exit;
+			if (i == 37 + 88 * 17) {
+				i = 1;
+				incr = 1;
+			} else if (i == 15) {
+				i = 19234;
+				incr = 27;
+			} else
+				i += incr;
+		}
+		END {
+			for (i = 37; i <= 37 + 88 * 17; i += 17)
+				printf("g\nk%d\n", i);
+			for (i = 1; i <= 15; ++i)
+				printf("g\nk%d\n", i);
+			for (i = 19234; i <= 19234 + 61 * 27; i += 27)
+				printf("g\nk%d\n", i);
+		}' > $TMP2
+	$PROG -o $TMP3 recno $TMP2
+	if (cmp -s $TMP1 $TMP3) ; then :
+	else
+		echo "test4: type recno: failed"
+		exit 1
+	fi
+}
+
+# Do reverse order recno entries.
+test5()
+{
+	echo "Test 5: recno: reverse order entries"
+	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+	awk ' {
+		for (i = 1500; i; --i) {
+			if (i % 34)
+				s = substr($0, 1, i % 34);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		exit;
+	}' > $TMP1
+	rm -f $TMP2 $TMP3
+	cat $TMP1 |
+	awk 'BEGIN {
+			i = 1500;
+		}
+		{
+			printf("p\nk%d\nd%s\n", i, $0);
+			--i;
+		}
+		END {
+			for (i = 1500; i; --i) 
+				printf("g\nk%d\n", i);
+		}' > $TMP2
+	$PROG -o $TMP3 recno $TMP2
+	if (cmp -s $TMP1 $TMP3) ; then :
+	else
+		echo "test5: type recno: failed"
+		exit 1
+	fi
+}
+		
+# Do alternating order recno entries.
+test6()
+{
+	echo "Test 6: recno: alternating order entries"
+	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+	awk ' {
+		for (i = 1; i < 1200; i += 2) {
+			if (i % 34)
+				s = substr($0, 1, i % 34);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		for (i = 2; i < 1200; i += 2) {
+			if (i % 34)
+				s = substr($0, 1, i % 34);
+			else
+				s = substr($0, 1);
+			printf("input key %d: %s\n", i, s);
+		}
+		exit;
+	}' > $TMP1
+	rm -f $TMP2 $TMP3
+	cat $TMP1 |
+	awk 'BEGIN {
+			i = 1;
+			even = 0;
+		}
+		{
+			printf("p\nk%d\nd%s\n", i, $0);
+			i += 2;
+			if (i >= 1200) {
+				if (even == 1)
+					exit;
+				even = 1;
+				i = 2;
+			}
+		}
+		END {
+			for (i = 1; i < 1200; ++i) 
+				printf("g\nk%d\n", i);
+		}' > $TMP2
+	$PROG -o $TMP3 recno $TMP2
+	sort -o $TMP1 $TMP1
+	sort -o $TMP3 $TMP3
+	if (cmp -s $TMP1 $TMP3) ; then :
+	else
+		echo "test6: type recno: failed"
+		exit 1
+	fi
+}
+
+# Delete cursor record
+test7()
+{
+	echo "Test 7: btree, recno: delete cursor record"
+	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+	awk '{
+		for (i = 1; i <= 120; ++i)
+			printf("%05d: input key %d: %s\n", i, i, $0);
+		printf("%05d: input key %d: %s\n", 120, 120, $0);
+		printf("seq failed, no such key\n");
+		printf("%05d: input key %d: %s\n", 1, 1, $0);
+		printf("%05d: input key %d: %s\n", 2, 2, $0);
+		exit;
+	}' > $TMP1
+	rm -f $TMP2 $TMP3
+
+	for type in btree recno; do
+		cat $TMP1 |
+		awk '{
+			if (i == 120)
+				exit;
+			printf("p\nk%d\nd%s\n", ++i, $0);
+		}
+		END {
+			printf("fR_NEXT\n");
+			for (i = 1; i <= 120; ++i)
+				printf("s\n");
+			printf("fR_CURSOR\ns\nk120\n");
+			printf("r\n");
+			printf("fR_NEXT\ns\n");
+			printf("fR_CURSOR\ns\nk1\n");
+			printf("r\n");
+			printf("fR_FIRST\ns\n");
+		}' > $TMP2
+		$PROG -o $TMP3 recno $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test7: type $type: failed"
+			exit 1
+		fi
+	done
+}
+
+# Make sure that overflow pages are reused.
+test8()
+{
+	echo "Test 8: btree: repeated small key, big data pairs"
+	rm -f $TMP1
+	echo "" | 
+	awk 'BEGIN {
+		for (i = 1; i <= 10; ++i) {
+			printf("p\nkkey1\nD/bin/sh\n");
+			printf("p\nkkey2\nD/bin/csh\n");
+			if (i % 8 == 0) {
+				printf("c\nkkey2\nD/bin/csh\n");
+				printf("c\nkkey1\nD/bin/sh\n");
+				printf("e\t%d of 10 (comparison)\n", i);
+			} else
+				printf("e\t%d of 10             \n", i);
+			printf("r\nkkey1\nr\nkkey2\n");
+		}
+	}' > $TMP1
+	if $PROG btree $TMP1 ; then
+	    true
+	else
+	    echo "test8: btree tests failed"
+	    exit 1
+	fi
+#	$PROG hash $TMP1
+	# No explicit test for success.
+}
+
+# Test btree duplicate keys
+test9()
+{
+	echo "Test 9: btree: duplicate keys"
+	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+	awk '{
+		for (i = 1; i <= 543; ++i)
+			printf("%05d: input key %d: %s\n", i, i, $0);
+		exit;
+	}' > $TMP1
+	rm -f $TMP2 $TMP3
+
+	for type in btree; do
+		cat $TMP1 | 
+		awk '{
+			if (i++ % 2)
+				printf("p\nkduplicatekey\nd%s\n", $0);
+			else
+				printf("p\nkunique%dkey\nd%s\n", i, $0);
+		}
+		END {
+				printf("o\n");
+		}' > $TMP2
+		$PROG -iflags=1 -o $TMP3 $type $TMP2
+		sort -o $TMP3 $TMP3
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test9: type $type: failed"
+			exit 1
+		fi
+	done
+}
+
+# Test use of cursor flags without initialization
+test10()
+{
+	echo "Test 10: btree, recno: test cursor flag use"
+	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+	awk '{
+		for (i = 1; i <= 20; ++i)
+			printf("%05d: input key %d: %s\n", i, i, $0);
+		exit;
+	}' > $TMP1
+	rm -f $TMP2 $TMP3
+
+	# Test that R_CURSOR doesn't succeed before cursor initialized
+	for type in btree recno; do
+		cat $TMP1 |
+		awk '{
+			if (i == 10)
+				exit;
+			printf("p\nk%d\nd%s\n", ++i, $0);
+		}
+		END {
+			printf("fR_CURSOR\nr\n");
+			printf("eR_CURSOR SHOULD HAVE FAILED\n");
+		}' > $TMP2
+		$PROG -o $TMP3 $type $TMP2 > /dev/null 2>&1
+		if [ -s $TMP3 ] ; then
+			echo "Test 10: delete: R_CURSOR SHOULD HAVE FAILED"
+			exit 1
+		fi
+	done
+	for type in btree recno; do
+		cat $TMP1 |
+		awk '{
+			if (i == 10)
+				exit;
+			printf("p\nk%d\nd%s\n", ++i, $0);
+		}
+		END {
+			printf("fR_CURSOR\np\nk1\ndsome data\n");
+			printf("eR_CURSOR SHOULD HAVE FAILED\n");
+		}' > $TMP2
+		$PROG -o $TMP3 $type $TMP2 > /dev/null 2>&1
+		if [ -s $TMP3 ] ; then
+			echo "Test 10: put: R_CURSOR SHOULD HAVE FAILED"
+			exit 1
+		fi
+	done
+}
+
+# Test insert in reverse order.
+test11()
+{
+	echo "Test 11: recno: reverse order insert"
+	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+	awk '{
+		for (i = 1; i <= 779; ++i)
+			printf("%05d: input key %d: %s\n", i, i, $0);
+		exit;
+	}' > $TMP1
+	rm -f $TMP2 $TMP3
+
+	for type in recno; do
+		cat $TMP1 |
+		awk '{
+			if (i == 0) {
+				i = 1;
+				printf("p\nk1\nd%s\n", $0);
+				printf("%s\n", "fR_IBEFORE");
+			} else
+				printf("p\nk1\nd%s\n", $0);
+		}
+		END {
+				printf("or\n");
+		}' > $TMP2
+		$PROG -o $TMP3 $type $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test11: type $type: failed"
+			exit 1
+		fi
+	done
+}
+
+# Take the first 20000 entries in the dictionary, reverse them, and give
+# them each a small size data entry.  Use a small page size to make sure
+# the btree split code gets hammered.
+test12()
+{
+	if ( rev < /dev/null ) > /dev/null 2>&1 ; then
+		:
+	else
+		echo "Test 12: skipped, rev not found"
+		return
+	fi
+	if test $dictsize -lt 20001 ; then
+		echo "Test 12: skipped, dictionary too small"
+		return
+	else
+		:
+	fi
+	echo "Test 12: btree: lots of keys, small page size"
+	mdata=abcdefghijklmnopqrstuvwxy
+	echo $mdata |
+	awk '{ for (i = 1; i < 20001; ++i) print $0 }' > $TMP1
+	for type in btree; do
+		rm -f $TMP2 $TMP3
+		for i in `getnwords 20000 | rev`; do
+			echo p
+			echo k$i
+			echo d$mdata
+			echo g
+			echo k$i
+		done > $TMP2
+		$PROG -i psize=512 -o $TMP3 $type $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test12: type $type: failed"
+			exit 1
+		fi
+	done
+}
+
+# Test different byte orders.
+test13()
+{
+	echo "Test 13: btree, hash: differing byte orders"
+	getnwords 50 > $TMP1
+	for order in 1234 4321; do
+		for type in btree hash; do
+			rm -f byte.file $TMP2 $TMP3
+			for i in `cat $TMP1`; do
+				echo p
+				echo k$i
+				echo d$i
+				echo g
+				echo k$i
+			done > $TMP2
+			$PROG -ilorder=$order -f byte.file -o $TMP3 $type $TMP2
+			if (cmp -s $TMP1 $TMP3) ; then :
+			else
+				echo "test13: $type/$order put failed"
+				exit 1
+			fi
+			for i in `cat $TMP1`; do
+				echo g
+				echo k$i
+			done > $TMP2
+			$PROG -s \
+			    -ilorder=$order -f byte.file -o $TMP3 $type $TMP2
+			if (cmp -s $TMP1 $TMP3) ; then :
+			else
+				echo "test13: $type/$order get failed"
+				exit 1
+			fi
+		done
+	done
+	rm -f byte.file
+}
+
+# Try a variety of bucketsizes and fill factors for hashing
+test20()
+{
+	if test $dictsize -lt 10001 ; then
+		echo "Test 20: skipped, dictionary too small"
+		return
+	else
+		:
+	fi
+	echo\
+    "Test 20: hash: bucketsize, fill factor; nelem 25000 cachesize 65536"
+	echo "abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg" |
+	awk '{
+		for (i = 1; i <= 10000; ++i) {
+			if (i % 34)
+				s = substr($0, 1, i % 34);
+			else
+				s = substr($0, 1);
+			printf("%s\n", s);
+		}
+		exit;
+	}' > $TMP1
+	getnwords 10000 |
+	awk 'BEGIN {
+		ds="abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg"
+	}
+	{
+		if (++i % 34)
+			s = substr(ds, 1, i % 34);
+		else
+			s = substr(ds, 1);
+		printf("p\nk%s\nd%s\n", $0, s);
+	}' > $TMP2
+	getnwords 10000 |
+	awk '{
+		++i;
+		printf("g\nk%s\n", $0);
+	}' >> $TMP2
+	bsize=256
+	for ffactor in 11 14 21; do
+		echo "    bucketsize $bsize, fill factor $ffactor"
+		$PROG -o$TMP3 \
+		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+		    hash $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+			exit 1
+		fi
+	done
+	bsize=512
+	for ffactor in 21 28 43; do
+		echo "    bucketsize $bsize, fill factor $ffactor"
+		$PROG -o$TMP3 \
+		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+		    hash $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+			exit 1
+		fi
+	done
+	bsize=1024
+	for ffactor in 43 57 85; do
+		echo "    bucketsize $bsize, fill factor $ffactor"
+		$PROG -o$TMP3 \
+		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+		    hash $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+			exit 1
+		fi
+	done
+	bsize=2048
+	for ffactor in 85 114 171; do
+		echo "    bucketsize $bsize, fill factor $ffactor"
+		$PROG -o$TMP3 \
+		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+		    hash $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+			exit 1
+		fi
+	done
+	bsize=4096
+	for ffactor in 171 228 341; do
+		echo "    bucketsize $bsize, fill factor $ffactor"
+		$PROG -o$TMP3 \
+		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+		    hash $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+			exit 1
+		fi
+	done
+	bsize=8192
+	for ffactor in 341 455 683; do
+		echo "    bucketsize $bsize, fill factor $ffactor"
+		$PROG -o$TMP3 \
+		    -ibsize=$bsize,ffactor=$ffactor,nelem=25000,cachesize=65536\
+		    hash $TMP2
+		if (cmp -s $TMP1 $TMP3) ; then :
+		else
+			echo "test20: type hash:\
+bsize=$bsize ffactor=$ffactor nelem=25000 cachesize=65536 failed"
+			exit 1
+		fi
+	done
+}
+
+main $*
diff --git a/mechglue/src/plugins/kdb/db2/pol_xdr.c b/mechglue/src/plugins/kdb/db2/pol_xdr.c
new file mode 100644
index 000000000..37761080a
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/pol_xdr.c
@@ -0,0 +1,88 @@
+#include <sys/types.h>
+#include <krb5.h>
+#include <gssrpc/rpc.h>
+#include <krb5/kdb.h>
+#include "policy_db.h"
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+bool_t xdr_nullstring(XDR *xdrs, char **objp)
+{
+     u_int size;
+                                                                                                                            
+     if (xdrs->x_op == XDR_ENCODE) {
+          if (*objp == NULL)
+               size = 0;
+          else
+               size = strlen(*objp) + 1;
+     }
+     if (! xdr_u_int(xdrs, &size)) {
+          return FALSE;
+        }
+     switch (xdrs->x_op) {
+     case XDR_DECODE:
+          if (size == 0) {
+               *objp = NULL;
+               return TRUE;
+          } else if (*objp == NULL) {
+               *objp = (char *) mem_alloc(size);
+               if (*objp == NULL) {
+                    errno = ENOMEM;
+                    return FALSE;
+               }
+          }
+          return (xdr_opaque(xdrs, *objp, size));
+                                                                                                                            
+     case XDR_ENCODE:
+          if (size != 0)
+               return (xdr_opaque(xdrs, *objp, size));
+          return TRUE;
+                                                                                                                            
+     case XDR_FREE:
+          if (*objp != NULL)
+               mem_free(*objp, size);
+          *objp = NULL;
+          return TRUE;
+     }
+                                                                                                                            
+     return FALSE;
+}
+                                                                                                                            
+
+
+bool_t
+xdr_osa_policy_ent_rec(XDR *xdrs, osa_policy_ent_t objp)
+{
+    switch (xdrs->x_op) {
+    case XDR_ENCODE:
+	 objp->version = OSA_ADB_POLICY_VERSION_1;
+	 /* fall through */
+    case XDR_FREE:
+	 if (!xdr_int(xdrs, &objp->version))
+	      return FALSE;
+	 break;
+    case XDR_DECODE:
+	 if (!xdr_int(xdrs, &objp->version))
+	      return FALSE;
+	 if (objp->version != OSA_ADB_POLICY_VERSION_1)
+	      return FALSE;
+	 break;
+    }
+    
+    if(!xdr_nullstring(xdrs, &objp->name))
+	return (FALSE);
+    if (!xdr_u_int32(xdrs, &objp->pw_min_life))
+	return (FALSE);
+    if (!xdr_u_int32(xdrs, &objp->pw_max_life))
+	return (FALSE);
+    if (!xdr_u_int32(xdrs, &objp->pw_min_length))
+	return (FALSE);
+    if (!xdr_u_int32(xdrs, &objp->pw_min_classes))
+	return (FALSE);
+    if (!xdr_u_int32(xdrs, &objp->pw_history_num))
+	return (FALSE);
+    if (!xdr_u_int32(xdrs, &objp->policy_refcnt))
+	return (FALSE);
+    return (TRUE);
+}
diff --git a/mechglue/src/plugins/kdb/db2/policy_db.h b/mechglue/src/plugins/kdb/db2/policy_db.h
new file mode 100644
index 000000000..8bbef800b
--- /dev/null
+++ b/mechglue/src/plugins/kdb/db2/policy_db.h
@@ -0,0 +1,101 @@
+/*
+ * Data Types for policy and principal information that
+ * exists in the respective databases.
+ *
+ * $Header$
+ *
+ * This file was originally created with rpcgen.
+ * It has been hacked up since then.
+ */
+
+#ifndef __ADB_H__
+#define __ADB_H__
+#include <sys/types.h>
+#include <errno.h>
+#include <krb5.h>
+#include <krb5/kdb.h>
+/* Okay, this is a bit obscure.  The libdb2 configure script doesn't
+   detect it, but on Tru64 5.1, netinet/in.h causes sys/bittypes.h to
+   be included, and that has a typedef for u_int32_t.  Because the
+   configure script doesn't detect it, it causes db-config.h to have a
+   #define for u_int32_t, so including db.h and then netinet/in.h
+   causes compilation to fail.
+
+   Since gssrpc/types.h includes netinet/in.h, including that first
+   will cause the typedef to be seen before the macro definition,
+   which still isn't quite right, but is close enough for now.
+
+   A better fix might be for db.h to include netinet/in.h if that's
+   where we find u_int32_t.  */
+#include <gssrpc/types.h>
+#include <gssrpc/xdr.h>
+#include <db.h>
+#include "adb_err.h"
+#include <com_err.h>
+
+typedef	long		osa_adb_ret_t;
+
+#define OSA_ADB_POLICY_DB_MAGIC	0x12345A00
+
+#define OSA_ADB_POLICY_VERSION_MASK	0x12345D00
+#define OSA_ADB_POLICY_VERSION_1	0x12345D01
+
+
+
+typedef struct _osa_adb_db_lock_ent_t {
+     FILE     *lockfile;
+     char     *filename;
+     int      refcnt, lockmode, lockcnt;
+     krb5_context context;
+} osa_adb_lock_ent, *osa_adb_lock_t;
+
+typedef struct _osa_adb_db_ent_t {
+     int        magic;
+     DB         *db;
+     HASHINFO   info;
+     BTREEINFO  btinfo;
+     char       *filename;
+     osa_adb_lock_t lock;
+     int        opencnt;
+} osa_adb_db_ent, *osa_adb_db_t, *osa_adb_princ_t, *osa_adb_policy_t;
+
+/*
+ * Return Code (the rest are in adb_err.h)
+ */
+ 
+#define OSA_ADB_OK		0
+
+/*
+ * Functions
+ */
+
+krb5_error_code	osa_adb_create_db(char *filename, char *lockfile, int magic);
+krb5_error_code	osa_adb_destroy_db(char *filename, char *lockfile, int magic);
+krb5_error_code   osa_adb_rename_db(char *filefrom, char *lockfrom,
+				  char *fileto, char *lockto, int magic);
+krb5_error_code	osa_adb_init_db(osa_adb_db_t *dbp, char *filename,
+				char *lockfile, int magic);
+krb5_error_code	osa_adb_fini_db(osa_adb_db_t db, int magic);
+krb5_error_code	osa_adb_get_lock(osa_adb_db_t db, int mode);
+krb5_error_code	osa_adb_release_lock(osa_adb_db_t db);
+krb5_error_code osa_adb_open_and_lock(osa_adb_princ_t db, int locktype);
+krb5_error_code osa_adb_close_and_unlock(osa_adb_princ_t db);
+krb5_error_code	osa_adb_close_policy(osa_adb_policy_t db);
+krb5_error_code	osa_adb_create_policy(osa_adb_policy_t db,
+				      osa_policy_ent_t entry);
+krb5_error_code	osa_adb_destroy_policy(osa_adb_policy_t db,
+				       char * name);
+krb5_error_code	osa_adb_get_policy(osa_adb_policy_t db,
+				   char * name,
+				   osa_policy_ent_t *entry,
+				   int *cnt);
+krb5_error_code	osa_adb_put_policy(osa_adb_policy_t db,
+				   osa_policy_ent_t entry);
+krb5_error_code	osa_adb_iter_policy(osa_adb_policy_t db,
+				    osa_adb_iter_policy_func func,
+				    void * data);
+void		osa_free_policy_ent(osa_policy_ent_t val);
+
+bool_t  xdr_osa_policy_ent_rec(XDR *xdrs, osa_policy_ent_t objp);
+
+#endif /* __ADB_H__ */
diff --git a/mechglue/src/prototype/.Sanitize b/mechglue/src/prototype/.Sanitize
new file mode 100644
index 000000000..318b37e78
--- /dev/null
+++ b/mechglue/src/prototype/.Sanitize
@@ -0,0 +1,34 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+getopt.c
+prototype.c
+prototype.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/prototype/ChangeLog b/mechglue/src/prototype/ChangeLog
new file mode 100644
index 000000000..d2a628191
--- /dev/null
+++ b/mechglue/src/prototype/ChangeLog
@@ -0,0 +1,20 @@
+2002-03-28  Sam Hartman  <hartmans@mit.edu>
+
+	* prototype.h prototype.c:  Update copyright to 2002
+
+2001-11-06  Sam Hartman  <hartmans@mit.edu>
+
+	* prototype.h: Same here.
+
+	* prototype.c: Update copyright form so Emacs copyright-update
+	does the right thing for new files.  Update default year from
+	1994.
+	
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* getopt.c (main): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+
+	
diff --git a/mechglue/src/prototype/getopt.c b/mechglue/src/prototype/getopt.c
new file mode 100644
index 000000000..935f0bf5f
--- /dev/null
+++ b/mechglue/src/prototype/getopt.c
@@ -0,0 +1,29 @@
+extern int optind;
+extern char *optarg;
+
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    int c;
+    int errflg = 0;
+    
+    <<<other globals here>>>;
+	
+    while ((c = getopt(argc, argv, "<<<>>>")) != -1) {
+	switch (c) {
+	    <<<add cases for arguments here>>>;
+	case '?':
+	default:
+	    errflg++;
+	    break;
+	}
+    }
+    if (errflg) {
+	fprintf(stderr, "Usage: %s <<<args>>>", argv[0]);
+	exit(2);
+    }
+    for (; optind < argc; optind++) {
+	<<<process arg optind>>>;
+    }
+}
diff --git a/mechglue/src/prototype/prototype.c b/mechglue/src/prototype/prototype.c
new file mode 100644
index 000000000..83e6d3726
--- /dev/null
+++ b/mechglue/src/prototype/prototype.c
@@ -0,0 +1,30 @@
+/*
+ * prototype/prototype.c
+ *
+ * Copyright (C) 2002 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * 
+ *
+ * <<< Description >>>
+ */
+
diff --git a/mechglue/src/prototype/prototype.h b/mechglue/src/prototype/prototype.h
new file mode 100644
index 000000000..f85d0497e
--- /dev/null
+++ b/mechglue/src/prototype/prototype.h
@@ -0,0 +1,33 @@
+/*
+ * prototype/prototype.h
+ *
+ * Copyright (C) 2002 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * <<< Description >>>
+ */
+
+#ifndef <<< include blocker>>>__
+#define <<< include blocker>>>__
+
+#endif /* __<<< include blocker>>>__ */
diff --git a/mechglue/src/slave/.Sanitize b/mechglue/src/slave/.Sanitize
new file mode 100644
index 000000000..cc66e2e2f
--- /dev/null
+++ b/mechglue/src/slave/.Sanitize
@@ -0,0 +1,42 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+kprop.M
+kprop.c
+kprop.h
+kpropd.M
+kpropd.c
+kslave_update
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/slave/ChangeLog b/mechglue/src/slave/ChangeLog
new file mode 100644
index 000000000..4b5678634
--- /dev/null
+++ b/mechglue/src/slave/ChangeLog
@@ -0,0 +1,373 @@
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Removed.  Directory configured from top level
+	now.
+	* Makefile.in (thisconfigdir, mydir): Updated.
+	(MY_SUBDIRS): Define to just ".".
+	(kprop, kpropd): Link against @LIBUTIL@.
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SERVEROBJS, kpropd): Link against apputils lib
+	instead of using LIBOBJS.
+
+2003-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Call KRB5_AC_NEED_DAEMON instead of checking
+	whether daemon() prototype is needed.
+	* Makefile.in (SERVEROBJS): Use @LIBOBJS@.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-12-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add KRB5_GETSOCKNAME_ARGS and KRB5_GETPEERNAME_ARGS
+
+	* kprop.c, kpropd.c: Use GETSOCKNAME_ARG3_TYPE and
+	GETPEERNAME_ARG3_TYPE. 
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* kprop.c, kpropd.c: Make prototypes unconditional.
+
+2001-09-24  Mitchell Berger  <mitchb@mit.edu>
+
+	* kpropd.M: Correct typo (synopsis line should say kpropd, not kprop).
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Check for daemon() prototype.
+
+	* kpropd.c: Provide prototype if needed.
+
+2001-06-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* kpropd.c (authorized_principal): Cast argument to ispace() to int.
+
+2001-01-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* kpropd.c (load_database): Initialize save_stderr variable.
+
+2001-01-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* kprop.h (KPROP_CKSUMTYPE): Delete unused macro.
+
+Tue Oct 17 08:11:56 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* kprop.c, kpropd.c: Use krb5_set_principal_realm() instead of
+	freeing library generated memory using the internal krb5_xfree(). 
+
+Sat Oct 14 14:16:20 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* kpropd.c, kprop.c:  Ensure size of database sent OTW as 4 bytes
+	instead of sizeof(int). 
+
+2000-08-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* kprop.c, kpropd.c: Compiler warning fixes including: not
+	shadowing global variabls/functions, assignments in conditionals,
+	declaring local functions static.
+
+	* configure.in: Check for mode_t being defined. 
+
+2000-06-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: kprop does not depend on the database libraries. 
+	kpropd does not depend, nor need to link in the database libraries.
+
+2000-05-08  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kprop.c (open_connection): New argument indicates output buffer
+	size.  Don't overrun it.
+	(get_tickets): Pass size of Errmsg.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+	* configure.in, kpropd.c: Removed useless test for KRB5_POSIX, and
+		removed unneeded #include of sgtty.h if POSIX_TERMIOS is
+		not defined.
+	
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* kpropd.c (authorized_principal): make the acl file contain
+	etypes, and use that in the authorization process.
+
+Wed Feb 18 16:27:28 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (thisconfigdir): Remove trailing slash.
+
+Mon Feb  2 16:59:30 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 21 15:18:24 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* kprop.c, kpropd.c (main): returns int, not void. ANSI X3.159-1989
+	2.1.2.2.1 says so, and gcc now warns about it.
+
+Sat Feb 22 19:43:35 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (kpropd): Build using KDB5_LIBS, not KDB5_LIB.
+
+Tue Feb 18 18:18:44 1997  Richard Basch  <basch@lehman.com>
+
+	* kprop.c kpropd.c: Use krb5_free_data_contents, where appropriate.
+
+Fri Jan 31 19:22:37 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Dec  5 21:15:27 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kslave_update: Update script for new filename conventions. [PR
+	280]
+
+	* kprop.M: Update outdated references to kdb5_edit and /krb5 [PR
+	279]
+
+	* kpropd.M: Update outdated references to kdb5_edit and /krb5 [PR
+	279]
+
+Fri Nov 22 15:52:07 1996  unknown  <bjaspan@mit.edu>
+
+	* kprop.c (open_connection): use sizeof instead of h_length to
+ 	determine number of bytes of addr to copy from DNS response
+ 	[krb5-misc/211]
+
+Thu Nov  7 15:18:01 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kprop.c (main): 
+	* kpropd.c (PRS): Check the error return from krb5_init_context(),
+ 		and print an error message if necessary.
+
+Tue Oct 22 16:42:37 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kpropd.c (PRS): munge realm of sname_to_princ when -r is
+ 	specified [krb5-admin/39]
+
+Tue Sep 10 14:19:08 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kprop.M, kpropd.M: remove ".so man1/header.doc"
+
+Mon Aug 12 14:33:31 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* kpropd.c: rework to use kdb5_util instead of kdb5_edit; don't
+ 	send # bytes received until kdb5_util succeeds, so kprop won't
+ 	print SUCCESS until it is true; accept an acl_file name on the
+ 	command line
+
+Fri Mar 15 14:33:06 1996  Richard Basch  <basch@lehman.com>
+
+	* kprop.c: Corrected various memory leaks and unreferenced 
+	memory access conditions.
+
+Tue Mar 12 14:01:32 1996  Richard Basch  <basch@lehman.com>
+
+	* kprop.c: Write a byte to the last-prop file to ensure the file
+		modtime is updated.  Simply opening the file isn't sufficient.
+
+Wed Mar  6 16:15:46 1996  Richard Basch  <basch@lehman.com>
+
+	* kprop.c: The credentials cache should be destroyed after any error.
+
+Tue Mar  5 12:20:00 1996  Richard Basch  <basch@lehman.com>
+
+	* kprop.c: Call krb5_sname_to_principal rather than doing the OS
+	specific calls; this also deals with site-specific hostname
+	munging that might have occurred.
+	  Removed a trailing ; that caused a spurious message to be printed
+	even upon success.
+
+	* kpropd.c: Call krb5_sname_to_principal rather than doing the OS
+	specific calls.
+	  Open the lock file read-write, as required by
+	POSIX.
+	  Downgrade the lock to a shared lock prior to the execution
+	of kdb5_edit (it also tries to place a shared lock on the dump file).
+
+Wed Sep 13 23:53:19 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* kprop.h (KPROP_SRVTAB, KPROP_DEFAULT_FILE, KPROPD_DEFAULT_FILE,
+	KPROPD_DEFAULT_KDB5_EDIT, KPROPD_DEFAULT_KRB_DB, KPROPD_ACL_FILE):
+	removed configurable pathnames, they are now in osconf.h (which
+	gets included here via k5-int.h).
+
+Wed Aug 16 02:45:19 1995  Chris Provenzano <proven@mit.edu>
+
+        * kprop.c, kpropd.c: Pass fds to krb5_lock_file() and krb5_unlock_file()
+
+Fri Jul 7 16:34:36 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove all explicit library handling and LDFLAGS.
+	* configure.in - Add USE_KDB5_LIBRARY and KRB5_LIBRARIES.
+
+Wed July  5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* kprop.c changed open to THREEPARAMOPEN
+
+Fri Jun 30 14:47:04 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add --with-dbm to select between Berkeley and DBM
+		KDC database format.
+
+
+Thu Jun 15 18:09:33 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change explicit library names to -l<lib> form, and
+		change target link line to use $(LD) and associated flags.
+	* configure.in - Add shared library usage check.
+
+Sat Jun 10 23:07:45 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* kprop.c, kpropd.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:56:39 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Sat May 20 13:46:36 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kpropd.c (load_database): If realm specified then invoke
+		kdb5_edit with -r option.
+
+	* kprop.M: Document -P (port) option.
+
+	* kpropd.M: Document -P (port) option.
+
+	* kprop.h: KPROPD_DEFAULT_KDB5_EDIT was pointing to wrong place.
+
+Mon May 15 13:11:15 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kpropd.c (recv_database): Use krb5_int32 for over the wire
+	database length. 
+	(kerberos_authenticate): Make keytab support work
+
+	* kprop.c (PRS): Add support for keytab and port specification.
+	(xmit_database): Use krb5_int32 for length of database to go over
+		the wire. 
+	(kerberos_authenticate): Add krb5_auth_setaddrs call
+
+Wed May 03 03:30:51 1995  Chris Provenzano (proven@mit.edu)
+
+        * kpropd.c: (krb5_recvauth()): No longer needs the rc_type arg.
+
+Fri Apr 14 15:23:29 1995    <tytso@rsx-11.mit.edu>
+
+	* kpropd.c (load_database): kpropd uses fork instead of vfork,
+		because it's closing file descriptors in the child.
+
+		Print out the pid of the child process if debugging is
+		enabled. 
+
+		Use _exit() instead exit() after a fork(), so that child
+		process doesn't cause the stdio buffers don't get flushed
+		twice.
+
+		When debugging is enabled and kpropd can't bind to the
+		port, it should try binding again after setting
+		SO_REUSEADDR on the socket.  This avoids problems when
+		debugging modifications to kprop/kpropd or its setup, when
+		kpropd is run twice quickly in succession. 
+
+		kpropd shouldn't signal(SIGCHLD, SIG_IGN) in the parent.
+		Instead, it should wait() until the child exits.  This was
+		causing problems because setting SIGCHLD to SIG_IGN under
+		SYSV causes child processes to get reaped automatically,
+		so the wait() for kdb5_edit was failing.
+
+Mon Mar 27 07:56:26 1995 Chris Provenzano (proven@mit.edu)
+
+        * kprop.c : Use new calling conventions for krb5_sendauth(),
+		krb5_mk_safe(), krb5_rd_safe() and krb5_mk_priv().
+
+        * kpropd.c : Use new calling conventions for krb5_recvauth(),
+		krb5_mk_safe(), krb5_rd_safe() and krb5_rd_priv().
+
+Fri Mar 24 14:49:41 1995    <tytso@rsx-11.mit.edu>
+
+	* kpropd.c (PRS): Don't bother initializing server_addrs since
+		it's not used.
+
+	* kprop.c (get_tickets): Remove the call to krb5_os_localaddr() since
+		get_in_tkt_XXXX will default appropriately.
+
+Thu Mar  2 12:26:08 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:31:13 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:21:52 1995  John Gilmore  (gnu at toad.com)
+
+	* kprop.c, kpropd.c:  Avoid <krb5/...> includes.
+
+Tue Feb 14 15:30:55 1995 Chris Provenzano  (proven@mit.edu)
+
+        * kprop.c Call krb5_sendauth() with new calling convention.
+
+	* kprop.c (kerberos_authenticate()), (xmit_database()), cleaned up
+		to not use globals. Instead use krb5_creds * args.
+
+Fri Feb 03 18:39:24 1995  Chris Provenzano (proven@mit.edu)
+
+	* kprop.c Use krb5_get_in_tkt_with_keytab() instead of
+		 krb5_get_in_tkt_with_skey().
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Thu Nov 17 18:31:18 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* kprop.c: Use NPROTOTYPE for declarations.
+	(close_database): New function. Cleans up locks properly.
+	(main): call it.
+	(open_database): Use krb5_lock_file instead of POSIX_FILE_LOCKS.
+	* kpropd.c (doit): Use krb5_lock_file.
+	(changes from jtkohl@mit.edu.)
+
+Mon Oct  3 19:13:46 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(srcdir) to find manual page for make install.
+
+Thu Sep 29 22:15:27 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executable if libraries change.
+
+	* kprop.c (open_connection): Use getsockname instead of
+		getpeername when getting the sender address.
+
+Thu Sep 15 12:48:21 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kpropd.c (PRS): Only report errors to syslog if the debug flag
+	is not set.  (Otherwise, send them to stderr).
+
+Thu Aug  4 15:15:00 1994  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in:
+	* kpropd.c: include <sgtty.h> only if POSIX_TERMIOS is not defined
+
+Sat Jul 16 00:01:41 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* kpropd.c (do_standalone): Replace detach_process() with call to
+	  daemon(), which we can now guarantee will be in libc or in the
+	  Kerberos library.
+
+
diff --git a/mechglue/src/slave/Makefile.in b/mechglue/src/slave/Makefile.in
new file mode 100644
index 000000000..566f122f2
--- /dev/null
+++ b/mechglue/src/slave/Makefile.in
@@ -0,0 +1,56 @@
+thisconfigdir=..
+myfulldir=slave
+mydir=slave
+BUILDTOP=$(REL)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+all::	kprop kpropd
+
+CLIENTSRCS= $(srcdir)/kprop.c 
+CLIENTOBJS= kprop.o 
+
+SERVERSRCS= $(srcdir)/kpropd.c 
+SERVEROBJS= kpropd.o
+
+SRCS= $(CLIENTSRCS) $(SERVERSRCS)
+
+
+kprop: $(CLIENTOBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o kprop $(CLIENTOBJS) $(KRB5_BASE_LIBS) @LIBUTIL@
+
+kpropd: $(SERVEROBJS) $(KRB5_BASE_DEPLIBS) $(APPUTILS_DEPLIB)
+	$(CC_LINK) -o kpropd $(SERVEROBJS) $(KRB5_BASE_LIBS) $(APPUTILS_LIB) @LIBUTIL@
+
+install::
+	for f in kprop kpropd; do \
+	  $(INSTALL_PROGRAM) $$f \
+		$(DESTDIR)$(SERVER_BINDIR)/`echo $$f|sed '$(transform)'`; \
+	  $(INSTALL_DATA) $(srcdir)/$$f.M \
+		${DESTDIR}$(SERVER_MANDIR)/`echo $$f|sed '$(transform)'`.8; \
+	done
+
+clean::
+	$(RM) $(CLIENTOBJS) $(SERVEROBJS)
+
+clean::
+	$(RM) kprop kpropd
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)kprop.$(OBJEXT): kprop.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h kprop.h
+$(OUTPRE)kpropd.$(OBJEXT): kpropd.c $(SRCTOP)/include/syslog.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  kprop.h
diff --git a/mechglue/src/slave/kprop.M b/mechglue/src/slave/kprop.M
new file mode 100644
index 000000000..0a442a21e
--- /dev/null
+++ b/mechglue/src/slave/kprop.M
@@ -0,0 +1,67 @@
+.\" slave/kprop.M
+.\"
+.\" Copyright 1992 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" 
+.\"
+.TH KPROP 8
+.SH NAME
+kprop \- propagate a Kerberos V5 principal database to a slave server
+.SH SYNOPSIS
+.B kprop
+[\fB\-r\fP \fIrealm\fP] [\fB\-f\fP \fIfile\fP] [\fB\-d\fP] [\fB\-P\fP
+\fIport\fP] [\fB\-s\fP \fIkeytab\fP] 
+.I slave_host
+.br
+.SH DESCRIPTION
+.I kprop
+is used to propagate a Kerberos V5 database dump file from the master
+Kerberos server to a slave Kerberos server, which is specfied by
+.IR slave_host .  
+This is done by transmitting the dumped database file to the slave
+server over an encrypted, secure channel.  The dump file must be created
+by kdb5_util, and is normally KPROP_DEFAULT_FILE
+(/usr/local/var/krb5kdc/slave_datatrans).
+.SH OPTIONS
+.TP
+\fB\-r\fP \fIrealm\fP
+specifies the realm of the master server; by default the realm returned
+by
+.IR krb5_default_local_realm (3)
+is used.
+.TP
+\fB\-f\fP \fIfile\fP
+specifies the filename where the dumped principal database file is to be
+found; by default the dumped database file is KPROP_DEFAULT_FILE
+(normally /usr/local/var/krb5kdc/slave_datatrans).
+.TP
+\fB\-P\fP \fIport\fP
+specifies the port to use to contact the
+.I kpropd
+server on the remote host.
+.TP
+.B \-d
+prints debugging information.
+.TP
+\fB\-s\fP \fIkeytab\fP
+specifies the location of the keytab file.
+.SH SEE ALSO
+kpropd(8), kdb5_util(8), krb5kdc(8)
diff --git a/mechglue/src/slave/kprop.c b/mechglue/src/slave/kprop.c
new file mode 100644
index 000000000..e730f4646
--- /dev/null
+++ b/mechglue/src/slave/kprop.c
@@ -0,0 +1,759 @@
+/*
+ * slave/kprop.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#include "k5-int.h"
+#include "com_err.h"
+#include "kprop.h"
+
+#ifndef GETSOCKNAME_ARG3_TYPE
+#define GETSOCKNAME_ARG3_TYPE unsigned int
+#endif
+
+static char *kprop_version = KPROP_PROT_VERSION;
+
+char	*progname = 0;
+int     debug = 0;
+char	*srvtab = 0;
+char	*slave_host;
+char	*realm = 0;
+char	*file = KPROP_DEFAULT_FILE;
+short	port = 0;
+
+krb5_principal	my_principal;		/* The Kerberos principal we'll be */
+				/* running under, initialized in */
+				/* get_tickets() */
+krb5_ccache	ccache;		/* Credentials cache which we'll be using */
+krb5_creds	creds;
+krb5_address	sender_addr;
+krb5_address	receiver_addr;
+
+void	PRS
+	(int, char **);
+void	get_tickets
+	(krb5_context);
+static void usage 
+	(void);
+krb5_error_code open_connection 
+	(char *, int *, char *, unsigned int);
+void	kerberos_authenticate 
+	(krb5_context, krb5_auth_context *, 
+		   int, krb5_principal, krb5_creds **);
+int	open_database 
+	(krb5_context, char *, int *);
+void	close_database 
+	(krb5_context, int);
+void	xmit_database 
+	(krb5_context, krb5_auth_context, krb5_creds *, 
+		   int, int, int);
+void	send_error 
+	(krb5_context, krb5_creds *, int, char *, krb5_error_code);
+void	update_last_prop_file 
+	(char *, char *);
+
+static void usage()
+{
+	fprintf(stderr, "\nUsage: %s [-r realm] [-f file] [-d] [-P port] [-s srvtab] slave_host\n\n",
+		progname);
+	exit(1);
+}
+
+int
+main(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	int	fd, database_fd, database_size;
+	krb5_error_code	retval;
+	krb5_context context;
+	krb5_creds *my_creds;
+	krb5_auth_context auth_context;
+	char	Errmsg[256];
+	
+	retval = krb5_init_context(&context);
+	if (retval) {
+		com_err(argv[0], retval, "while initializing krb5");
+		exit(1);
+	}
+	PRS(argc, argv);
+	get_tickets(context);
+
+	database_fd = open_database(context, file, &database_size);
+	retval = open_connection(slave_host, &fd, Errmsg, sizeof(Errmsg));
+	if (retval) {
+		com_err(progname, retval, "%s while opening connection to %s",
+			Errmsg, slave_host);
+		exit(1);
+	}
+	if (fd < 0) {
+		fprintf(stderr, "%s: %s while opening connection to %s\n",
+			progname, Errmsg, slave_host);
+		exit(1);
+	}
+	kerberos_authenticate(context, &auth_context, fd, my_principal, 
+			      &my_creds);
+	xmit_database(context, auth_context, my_creds, fd, database_fd, 
+		      database_size);
+	update_last_prop_file(slave_host, file);
+	printf("Database propagation to %s: SUCCEEDED\n", slave_host);
+	krb5_free_cred_contents(context, my_creds);
+	close_database(context, database_fd);
+	exit(0);
+}
+
+void PRS(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	register char	*word, ch;
+	
+	progname = *argv++;
+	while (--argc && (word = *argv++)) {
+		if (*word == '-') {
+			word++;
+			while (word && (ch = *word++)) {
+				switch(ch){
+				case 'r':
+					if (*word)
+						realm = word;
+					else
+						realm = *argv++;
+					if (!realm)
+						usage();
+					word = 0;
+					break;
+				case 'f':
+					if (*word)
+						file = word;
+					else
+						file = *argv++;
+					if (!file)
+						usage();
+					word = 0;
+					break;
+				case 'd':
+					debug++;
+					break;
+				case 'P':
+					if (*word)
+						port = htons(atoi(word));
+					else
+						port = htons(atoi(*argv++));
+					if (!port)
+						usage();
+					word = 0;
+					break;
+				case 's':
+					if (*word)
+						srvtab = word;
+					else
+						srvtab = *argv++;
+					if (!srvtab)
+						usage();
+					word = 0;
+					break;
+				default:
+					usage();
+				}
+				
+			}
+		} else {
+			if (slave_host)
+				usage();
+			else
+				slave_host = word;
+		}
+	}
+	if (!slave_host)
+		usage();
+}
+
+void get_tickets(context)
+    krb5_context context;
+{
+	char   buf[BUFSIZ];
+	krb5_error_code retval;
+	static char tkstring[] = "/tmp/kproptktXXXXXX";
+	krb5_keytab keytab = NULL;
+
+	/*
+	 * Figure out what tickets we'll be using to send stuff
+	 */
+	retval = krb5_sname_to_principal(context, NULL, NULL,
+					 KRB5_NT_SRV_HST, &my_principal);
+	if (retval) {
+	    com_err(progname, errno, "while setting client principal name");
+	    exit(1);
+	}
+	if (realm) {
+	    retval = krb5_set_principal_realm(context, my_principal, realm);
+	    if (retval) {
+	        com_err(progname, errno, 
+			"while setting client principal realm");
+		exit(1);
+	    }
+	}
+#if 0
+	krb5_princ_type(context, my_principal) = KRB5_NT_PRINCIPAL;
+#endif
+
+	/*
+	 * Initialize cache file which we're going to be using
+	 */
+	(void) mktemp(tkstring);
+	sprintf(buf, "FILE:%s", tkstring);
+
+	retval = krb5_cc_resolve(context, buf, &ccache);
+	if (retval) {
+		com_err(progname, retval, "while opening credential cache %s",
+			buf);
+		exit(1);
+	}
+
+	retval = krb5_cc_initialize(context, ccache, my_principal);
+	if (retval) {
+		com_err (progname, retval, "when initializing cache %s",
+			 buf);
+		exit(1);
+	}
+
+	/*
+	 * Get the tickets we'll need.
+	 *
+	 * Construct the principal name for the slave host.
+	 */
+	memset((char *)&creds, 0, sizeof(creds));
+	retval = krb5_sname_to_principal(context,
+					 slave_host, KPROP_SERVICE_NAME,
+					 KRB5_NT_SRV_HST, &creds.server);
+	if (retval) {
+	    com_err(progname, errno, "while setting server principal name");
+	    (void) krb5_cc_destroy(context, ccache);
+	    exit(1);
+	}
+	if (realm) {
+	    retval = krb5_set_principal_realm(context, creds.server, realm);
+	    if (retval) {
+	        com_err(progname, errno, 
+			"while setting server principal realm");
+		exit(1);
+	    }
+	}
+
+	/*
+	 * Now fill in the client....
+	 */
+	retval = krb5_copy_principal(context, my_principal, &creds.client);
+	if (retval) {
+		com_err(progname, retval, "While copying client principal");
+		(void) krb5_cc_destroy(context, ccache);
+		exit(1);
+	}
+	if (srvtab) {
+	        retval = krb5_kt_resolve(context, srvtab, &keytab);
+		if (retval) {
+			com_err(progname, retval, "while resolving keytab");
+			(void) krb5_cc_destroy(context, ccache);
+			exit(1);
+		}
+	}
+
+	retval = krb5_get_in_tkt_with_keytab(context, 0, 0, NULL,
+					     NULL, keytab, ccache, &creds, 0);
+	if (retval) {
+		com_err(progname, retval, "while getting initial ticket\n");
+		(void) krb5_cc_destroy(context, ccache);
+		exit(1);
+	}
+
+	if (keytab)
+	    (void) krb5_kt_close(context, keytab);
+	
+	/*
+	 * Now destroy the cache right away --- the credentials we
+	 * need will be in my_creds.
+	 */
+	retval = krb5_cc_destroy(context, ccache);
+	if (retval) {
+		com_err(progname, retval, "while destroying ticket cache");
+		exit(1);
+	}
+}
+
+krb5_error_code
+open_connection(host, fd, Errmsg, ErrmsgSz)
+	char		*host;
+	int		*fd;
+	char		*Errmsg;
+	unsigned int	 ErrmsgSz;
+{
+	int	s;
+	krb5_error_code	retval;
+	
+	struct hostent	*hp;
+	register struct servent *sp;
+	struct sockaddr_in my_sin;
+	GETSOCKNAME_ARG3_TYPE socket_length;
+
+	hp = gethostbyname(host);
+	if (hp == NULL) {
+		(void) sprintf(Errmsg, "%s: unknown host", host);
+		*fd = -1;
+		return(0);
+	}
+	my_sin.sin_family = hp->h_addrtype;
+	memcpy((char *)&my_sin.sin_addr, hp->h_addr, sizeof(my_sin.sin_addr));
+	if(!port) {
+		sp = getservbyname(KPROP_SERVICE, "tcp");
+		if (sp == 0) {
+			(void) strncpy(Errmsg, KPROP_SERVICE, ErrmsgSz - 1);
+			Errmsg[ErrmsgSz - 1] = '\0';
+			(void) strncat(Errmsg, "/tcp: unknown service", ErrmsgSz - 1 - strlen(Errmsg));
+			*fd = -1;
+			return(0);
+		}
+		my_sin.sin_port = sp->s_port;
+	} else
+		my_sin.sin_port = port;
+	s = socket(AF_INET, SOCK_STREAM, 0);
+	
+	if (s < 0) {
+		(void) sprintf(Errmsg, "in call to socket");
+		return(errno);
+	}
+	if (connect(s, (struct sockaddr *)&my_sin, sizeof my_sin) < 0) {
+		retval = errno;
+		close(s);
+		(void) sprintf(Errmsg, "in call to connect");
+		return(retval);
+	}
+	*fd = s;
+
+	/*
+	 * Set receiver_addr and sender_addr.
+	 */
+	receiver_addr.addrtype = ADDRTYPE_INET;
+	receiver_addr.length = sizeof(my_sin.sin_addr);
+	receiver_addr.contents = (krb5_octet *) malloc(sizeof(my_sin.sin_addr));
+	memcpy((char *) receiver_addr.contents, (char *) &my_sin.sin_addr,
+	       sizeof(my_sin.sin_addr));
+
+	socket_length = sizeof(my_sin);
+	if (getsockname(s, (struct sockaddr *)&my_sin, &socket_length) < 0) {
+		retval = errno;
+		close(s);
+		(void) sprintf(Errmsg, "in call to getsockname");
+		return(retval);
+	}
+	sender_addr.addrtype = ADDRTYPE_INET;
+	sender_addr.length = sizeof(my_sin.sin_addr);
+	sender_addr.contents = (krb5_octet *) malloc(sizeof(my_sin.sin_addr));
+	memcpy((char *) sender_addr.contents, (char *) &my_sin.sin_addr,
+	       sizeof(my_sin.sin_addr));
+
+	return(0);
+}
+
+
+void kerberos_authenticate(context, auth_context, fd, me, new_creds)
+    krb5_context context;
+    krb5_auth_context *auth_context;
+    int	fd;
+    krb5_principal me;
+    krb5_creds ** new_creds;
+{
+	krb5_error_code	retval;
+	krb5_error	*error = NULL;
+	krb5_ap_rep_enc_part	*rep_result;
+
+    retval = krb5_auth_con_init(context, auth_context);
+    if (retval) 
+	exit(1);
+
+    krb5_auth_con_setflags(context, *auth_context, 
+			   KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+
+    retval = krb5_auth_con_setaddrs(context, *auth_context, &sender_addr,
+				    &receiver_addr);
+    if (retval) {
+	com_err(progname, retval, "in krb5_auth_con_setaddrs");
+	exit(1);
+    }
+
+    retval = krb5_sendauth(context, auth_context, (void *)&fd, 
+			   kprop_version, me, creds.server,
+			   AP_OPTS_MUTUAL_REQUIRED, NULL, &creds, NULL,
+			   &error, &rep_result, new_creds);
+    if (retval) {
+        com_err(progname, retval, "while authenticating to server");
+	if (error) {
+	    if (error->error == KRB_ERR_GENERIC) {
+	        if (error->text.data)
+		    fprintf(stderr,
+			    "Generic remote error: %s\n",
+			    error->text.data);
+	    } else if (error->error) {
+	        com_err(progname,
+			(krb5_error_code) error->error + ERROR_TABLE_BASE_krb5,
+			"signalled from server");
+		if (error->text.data)
+		    fprintf(stderr,
+			    "Error text from server: %s\n",
+			    error->text.data);
+	    }
+	    krb5_free_error(context, error);
+	}
+	exit(1);
+    }
+    krb5_free_ap_rep_enc_part(context, rep_result);
+}
+
+char * dbpathname;
+/*
+ * Open the Kerberos database dump file.  Takes care of locking it
+ * and making sure that the .ok file is more recent that the database
+ * dump file itself.
+ *
+ * Returns the file descriptor of the database dump file.  Also fills
+ * in the size of the database file.
+ */
+int
+open_database(context, data_fn, size)
+    krb5_context context;
+    char *data_fn;
+    int	*size;
+{
+	int		fd;
+	int		err;
+	struct stat 	stbuf, stbuf_ok;
+	char		*data_ok_fn;
+	static char ok[] = ".dump_ok";
+
+	dbpathname = strdup(data_fn);
+	if (!dbpathname) {
+ 	    com_err(progname, ENOMEM, "allocating database file name '%s'",
+ 		    data_fn);
+ 	    exit(1);
+ 	}
+	if ((fd = open(dbpathname, O_RDONLY)) < 0) {
+		com_err(progname, errno, "while trying to open %s",
+			dbpathname);
+		exit(1);
+	}
+
+	err = krb5_lock_file(context, fd,
+			     KRB5_LOCKMODE_SHARED|KRB5_LOCKMODE_DONTBLOCK);
+	if (err == EAGAIN || err == EWOULDBLOCK || errno == EACCES) {
+	    com_err(progname, 0, "database locked");
+	    exit(1);
+	} else if (err) {
+	    com_err(progname, err, "while trying to lock '%s'", dbpathname);
+	    exit(1);
+	}	    
+	if (fstat(fd, &stbuf)) {
+		com_err(progname, errno, "while trying to stat %s",
+			data_fn);
+		exit(1);
+	}
+	if ((data_ok_fn = (char *) malloc(strlen(data_fn)+strlen(ok)+1))
+	    == NULL) {
+		com_err(progname, ENOMEM, "while trying to malloc data_ok_fn");
+		exit(1);
+	}
+	strcpy(data_ok_fn, data_fn);
+	strcat(data_ok_fn, ok);
+	if (stat(data_ok_fn, &stbuf_ok)) {
+		com_err(progname, errno, "while trying to stat %s",
+			data_ok_fn);
+		free(data_ok_fn);
+		exit(1);
+	}
+	free(data_ok_fn);
+	if (stbuf.st_mtime > stbuf_ok.st_mtime) {
+		com_err(progname, 0, "'%s' more recent than '%s'.",
+			data_fn, data_ok_fn);
+		exit(1);
+	}
+	*size = stbuf.st_size;
+	return(fd);
+}
+
+void
+close_database(context, fd)
+    krb5_context context;
+    int fd;
+{
+    int err;
+    err = krb5_lock_file(context, fd, KRB5_LOCKMODE_UNLOCK);
+    if (err)
+	com_err(progname, err, "while unlocking database '%s'", dbpathname);
+    free(dbpathname);
+    (void)close(fd);
+    return;
+}
+  
+/*
+ * Now we send over the database.  We use the following protocol:
+ * Send over a KRB_SAFE message with the size.  Then we send over the
+ * database in blocks of KPROP_BLKSIZE, encrypted using KRB_PRIV.
+ * Then we expect to see a KRB_SAFE message with the size sent back.
+ * 
+ * At any point in the protocol, we may send a KRB_ERROR message; this
+ * will abort the entire operation.
+ */
+void
+xmit_database(context, auth_context, my_creds, fd, database_fd, 
+	      in_database_size)
+    krb5_context context;
+    krb5_auth_context auth_context;
+    krb5_creds *my_creds;
+    int	fd;
+    int	database_fd;
+    int	in_database_size;
+{
+	krb5_int32	sent_size, n;
+	krb5_data	inbuf, outbuf;
+	char		buf[KPROP_BUFSIZ];
+	krb5_error_code	retval;
+	krb5_error	*error;
+	/* These must be 4 bytes */
+	krb5_ui_4	database_size = in_database_size; 
+	krb5_ui_4	send_size;
+
+	/*
+	 * Send over the size
+	 */
+	send_size = htonl(database_size);
+	inbuf.data = (char *) &send_size;
+	inbuf.length = sizeof(send_size); /* must be 4, really */
+	/* KPROP_CKSUMTYPE */
+	retval = krb5_mk_safe(context, auth_context, &inbuf, 
+			      &outbuf, NULL);
+	if (retval) {
+		com_err(progname, retval, "while encoding database size");
+		send_error(context, my_creds, fd, "while encoding database size", retval);
+		exit(1);
+	}
+
+	retval = krb5_write_message(context, (void *) &fd, &outbuf);
+	if (retval) {
+		krb5_free_data_contents(context, &outbuf);
+		com_err(progname, retval, "while sending database size");
+		exit(1);
+	}
+	krb5_free_data_contents(context, &outbuf);
+	/*
+	 * Initialize the initial vector.
+	 */
+	retval = krb5_auth_con_initivector(context, auth_context);
+	if (retval) {
+	    send_error(context, my_creds, fd, 
+		       "failed while initializing i_vector", retval);
+	    com_err(progname, retval, "while allocating i_vector");
+	    exit(1);
+	}
+ 
+	/*
+	 * Send over the file, block by block....
+	 */
+	inbuf.data = buf;
+	sent_size = 0;
+	while ((n = read(database_fd, buf, sizeof(buf)))) {
+		inbuf.length = n;
+		retval = krb5_mk_priv(context, auth_context, &inbuf,
+				      &outbuf, NULL);
+		if (retval) {
+			sprintf(buf,
+				"while encoding database block starting at %d",
+				sent_size);
+			com_err(progname, retval, buf);
+			send_error(context, my_creds, fd, buf, retval);
+			exit(1);
+		}
+
+		retval = krb5_write_message(context, (void *)&fd,&outbuf);
+		if (retval) {
+			krb5_free_data_contents(context, &outbuf);
+			com_err(progname, retval,
+				"while sending database block starting at %d",
+				sent_size);
+			exit(1);
+		}
+		krb5_free_data_contents(context, &outbuf);
+		sent_size += n;
+		if (debug)
+			printf("%d bytes sent.\n", sent_size);
+	}
+	if (sent_size != database_size) {
+		com_err(progname, 0, "Premature EOF found for database file!");
+		send_error(context, my_creds, fd,"Premature EOF found for database file!",
+			   KRB5KRB_ERR_GENERIC);
+		exit(1);
+	}
+
+	/*
+	 * OK, we've sent the database; now let's wait for a success
+	 * indication from the remote end.
+	 */
+	retval = krb5_read_message(context, (void *) &fd, &inbuf);
+	if (retval) {
+		com_err(progname, retval,
+			"while reading response from server");
+		exit(1);
+	}
+	/*
+	 * If we got an error response back from the server, display
+	 * the error message
+	 */
+	if (krb5_is_krb_error(&inbuf)) {
+ 	        retval = krb5_rd_error(context, &inbuf, &error);
+		if (retval) {
+			com_err(progname, retval,
+				"while decoding error response from server");
+			exit(1);
+		}
+		if (error->error == KRB_ERR_GENERIC) {
+			if (error->text.data)
+				fprintf(stderr,
+					"Generic remote error: %s\n",
+					error->text.data);
+		} else if (error->error) {
+			com_err(progname, 
+				(krb5_error_code) error->error + 
+				  ERROR_TABLE_BASE_krb5,
+				"signalled from server");
+			if (error->text.data)
+				fprintf(stderr,
+					"Error text from server: %s\n",
+					error->text.data);
+		}
+		krb5_free_error(context, error);
+		exit(1);
+	}
+
+	retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL);
+	if (retval) {
+		com_err(progname, retval,
+			"while decoding final size packet from server");
+		exit(1);
+	}
+
+	memcpy((char *)&send_size, outbuf.data, sizeof(send_size));
+	send_size = ntohl(send_size);
+	if (send_size != database_size) {
+		com_err(progname, 0,
+			"Kpropd sent database size %d, expecting %d",
+			send_size, database_size);
+		exit(1);
+	}
+	free(outbuf.data);
+	free(inbuf.data);
+}
+
+void
+send_error(context, my_creds, fd, err_text, err_code)
+    krb5_context context;
+    krb5_creds *my_creds;
+    int	fd;
+    char	*err_text;
+    krb5_error_code	err_code;
+{
+	krb5_error	error;
+	const char	*text;
+	krb5_data	outbuf;
+
+	memset((char *)&error, 0, sizeof(error));
+	krb5_us_timeofday(context, &error.ctime, &error.cusec);
+	error.server = my_creds->server;
+	error.client = my_principal;
+	error.error = err_code - ERROR_TABLE_BASE_krb5;
+	if (error.error > 127)
+		error.error = KRB_ERR_GENERIC;
+	if (err_text)
+		text = err_text;
+	else
+		text = error_message(err_code);
+	error.text.length = strlen(text) + 1;
+	error.text.data = malloc((unsigned int) error.text.length);
+	if (error.text.data) {
+		strcpy(error.text.data, text);
+		if (!krb5_mk_error(context, &error, &outbuf)) {
+			(void) krb5_write_message(context, (void *)&fd,&outbuf);
+			krb5_free_data_contents(context, &outbuf);
+		}
+		free(error.text.data);
+	}
+}
+
+void update_last_prop_file(hostname, file_name)
+	char *hostname;
+	char *file_name;
+{
+	/* handle slave locking/failure stuff */
+	char *file_last_prop;
+	int fd;
+	static char last_prop[]=".last_prop";
+
+	if ((file_last_prop = (char *)malloc(strlen(file_name) +
+					     strlen(hostname) + 1 +
+					     strlen(last_prop) + 1)) == NULL) {
+		com_err(progname, ENOMEM,
+			"while allocating filename for update_last_prop_file");
+		return;
+	}
+	strcpy(file_last_prop, file_name);
+	strcat(file_last_prop, ".");
+	strcat(file_last_prop, hostname);
+	strcat(file_last_prop, last_prop);
+	if ((fd = THREEPARAMOPEN(file_last_prop, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
+		com_err(progname, errno,
+			"while creating 'last_prop' file, '%s'",
+			file_last_prop);
+		free(file_last_prop);
+		return;
+	}
+	write(fd, "", 1);
+	free(file_last_prop);
+	close(fd);
+	return;
+}
diff --git a/mechglue/src/slave/kprop.h b/mechglue/src/slave/kprop.h
new file mode 100644
index 000000000..93e147e51
--- /dev/null
+++ b/mechglue/src/slave/kprop.h
@@ -0,0 +1,37 @@
+/*
+ * slave/kprop.h
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ */
+
+#define KPROP_SERVICE_NAME "host"
+#define TGT_SERVICE_NAME "krbtgt"
+#define KPROP_SERVICE "krb5_prop"
+
+#define KPROP_PROT_VERSION "kprop5_01"
+
+#define KPROP_BUFSIZ 32768
+
+/* pathnames are in osconf.h, included via k5-int.h */
diff --git a/mechglue/src/slave/kpropd.M b/mechglue/src/slave/kpropd.M
new file mode 100644
index 000000000..98035fcf9
--- /dev/null
+++ b/mechglue/src/slave/kpropd.M
@@ -0,0 +1,130 @@
+.\" slave/kpropd.M
+.\"
+.\" Copyright 1992 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" 
+.\"
+.TH KPROPD 8
+.SH NAME
+kpropd \- Kerberos V5 slave KDC update server
+.SH SYNOPSIS
+.B kpropd
+[
+.B \-r
+.I realm
+] [
+.B \-f
+.I slave_dumpfile
+] [
+.B \-F
+.I principal_database
+] [
+.B \-p
+.I kdb5_util_prog
+] [
+.B \-d
+] [
+.B \-S
+] [
+.B \-P
+.I port
+]
+.br
+.SH DESCRIPTION
+.I kpropd 
+is the server which accepts connections from the 
+.IR kprop (8)
+program.  
+.I kpropd 
+accepts the dumped KDC database and places it in a file, and then runs 
+.IR kdb5_util (8)
+to load the dumped database into the active database which is used by 
+.IR krb5kdc (8).
+Thus, the master Kerberos server can use 
+.IR kprop (8)
+to propagate its database to the slave slavers.  Upon a successful download 
+of the KDC database file, the slave Kerberos server will have an
+up-to-date KDC database. 
+.PP
+Normally, kpropd is invoked out of 
+.I inetd(8).  
+This is done by adding a line to the inetd.conf file which looks like
+this:
+
+kprop	stream	tcp	nowait	root	/usr/local/sbin/kpropd	kpropd
+
+However, kpropd can also run as a standalone deamon, if the
+.B \-S
+option is turned on.  This is done for debugging purposes, or if for
+some reason the system administrator just doesn't want to run it out of
+.IR inetd (8).
+.SH OPTIONS
+.TP
+\fB\-r\fP \fIrealm\fP
+specifies the realm of the master server; by default the realm returned
+by
+.IR krb5_default_local_realm (3)
+is used.
+.TP
+\fB\-f\fP \fIfile\fP
+specifies the filename where the dumped principal database file is to be
+stored; by default the dumped database file is KPROPD_DEFAULT_FILE
+(normally /usr/local/var/krb5kdc/from_master).
+.TP
+.B \-p
+allows the user to specify the pathname to the
+.IR kdb5_util (8)
+program; by default the pathname used is KPROPD_DEFAULT_KDB5_UTIL
+(normally /usr/local/sbin/kdb5_util).
+.TP
+.B \-S
+turn on standalone mode.  Normally, kpropd is invoked out of
+.IR inetd (8)
+so it expects a network connection to be passed to it from
+.I inetd (8).
+If the 
+.B \-S 
+option is specified, kpropd will put itself into the background, and
+wait for connections to the KPROP_SERVICE port (normally krb5_prop).
+.TP
+.B \-d
+turn on debug mode.  In this mode, if the
+.B \-S 
+option is selected, 
+.I kpropd
+will not detach itself from the current job and run in the background.
+Instead, it will run in the foreground and print out debugging messages
+during the database propagation.
+.TP
+.B \-P
+allow for an alternate port number for
+.I kpropd
+to listen on. This is only useful if the program is run in standalone
+mode.
+.SH FILES
+.TP "\w'kpropd.acl\ \ 'u"
+kpropd.acl
+Access file for
+.BR kpropd .
+Each entry is a line containing the principal of a host from which the
+local machine will allow Kerberos database propagation via kprop.
+.SH SEE ALSO
+kprop(8), kdb5_util(8), krb5kdc(8), inetd(8)
diff --git a/mechglue/src/slave/kpropd.c b/mechglue/src/slave/kpropd.c
new file mode 100644
index 000000000..6ded72aed
--- /dev/null
+++ b/mechglue/src/slave/kpropd.c
@@ -0,0 +1,992 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * slave/kpropd.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * XXX We need to modify the protocol so that an acknowledge is set
+ * after each block, instead after the entire series is sent over.
+ * The reason for this is so that error packets can get interpreted
+ * right away.  If you don't do this, the sender may never get the
+ * error packet, because it will die an EPIPE trying to complete the
+ * write...
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <syslog.h>
+
+#include "k5-int.h"
+#include "com_err.h"
+#include <errno.h>
+
+#include "kprop.h"
+
+#ifndef GETSOCKNAME_ARG3_TYPE
+#define GETSOCKNAME_ARG3_TYPE unsigned int
+#endif
+#ifndef GETPEERNAME_ARG3_TYPE
+#define GETPEERNAME_ARG3_TYPE unsigned int
+#endif
+
+#if defined(NEED_DAEMON_PROTO)
+extern int daemon(int, int);
+#endif
+
+#define SYSLOG_CLASS LOG_DAEMON
+
+static char *kprop_version = KPROP_PROT_VERSION;
+
+char	*progname;
+int     debug = 0;
+char	*srvtab = 0;
+int	standalone = 0;
+
+krb5_principal	server;		/* This is our server principal name */
+krb5_principal	client;		/* This is who we're talking to */
+krb5_context kpropd_context;
+krb5_auth_context auth_context;
+char	*realm = NULL;		/* Our realm */
+char	*file = KPROPD_DEFAULT_FILE;
+char	*temp_file_name;
+char	*kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
+char	*kerb_database = NULL;
+char	*acl_file_name = KPROPD_ACL_FILE;
+
+krb5_address	sender_addr;
+krb5_address	receiver_addr;
+short 		port = 0;
+
+void	PRS
+	(char**);
+void	do_standalone
+	(void);
+void	doit
+	(int);
+void	kerberos_authenticate
+	(krb5_context,
+		   int,
+		   krb5_principal *,
+		   krb5_enctype *,
+		   struct sockaddr_in);
+krb5_boolean authorized_principal
+	(krb5_context,
+    		   krb5_principal,
+		   krb5_enctype);
+void	recv_database
+	(krb5_context,
+		   int,
+		   int,
+		   krb5_data *);
+void	load_database
+	(krb5_context,
+    		   char *,
+    		   char *);
+void	send_error
+	(krb5_context,
+    		   int,
+		   krb5_error_code,
+    		   char	*);
+void	recv_error
+	(krb5_context,
+    		   krb5_data *);
+
+static void usage()
+{
+	fprintf(stderr,
+		"\nUsage: %s [-r realm] [-s srvtab] [-dS] [-f slave_file]\n",
+		progname);
+	fprintf(stderr, "\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n");
+	fprintf(stderr, "\t[-P port] [-a acl_file]\n");
+	exit(1);
+}
+
+int
+main(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	PRS(argv);
+
+	if (standalone)
+		do_standalone();
+	else
+		doit(0);
+	exit(0);
+}
+
+void do_standalone()
+{
+	struct	sockaddr_in	my_sin, frominet;
+	struct servent *sp;
+	int	finet, s;
+	GETPEERNAME_ARG3_TYPE fromlen;
+	int	ret;
+	
+	finet = socket(AF_INET, SOCK_STREAM, 0);
+	if (finet < 0) {
+		com_err(progname, errno, "while obtaining socket");
+		exit(1);
+	}
+	memset((char *) &my_sin,0, sizeof(my_sin));
+	if(!port) {
+		sp = getservbyname(KPROP_SERVICE, "tcp");
+		if (sp == NULL) {
+			com_err(progname, 0, "%s/tcp: unknown service", KPROP_SERVICE);
+			exit(1);
+		}
+		my_sin.sin_port = sp->s_port;
+	} else {
+		my_sin.sin_port = port;
+	}
+	my_sin.sin_family = AF_INET;
+	if ((ret = bind(finet, (struct sockaddr *) &my_sin, sizeof(my_sin))) < 0) {
+	    if (debug) {
+		int on = 1;
+		fprintf(stderr,
+			"%s: attempting to rebind socket with SO_REUSEADDR\n",
+			progname);
+		if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
+			       (char *)&on, sizeof(on)) < 0)
+		    com_err(progname, errno, "in setsockopt(SO_REUSEADDR)");
+		ret = bind(finet, (struct sockaddr *) &my_sin, sizeof(my_sin));
+	    }
+	    if (ret < 0) {
+		perror("bind");
+		com_err(progname, errno, "while binding listener socket");
+		exit(1);
+	    }
+	}
+	if (!debug)
+		daemon(1, 0);	    
+#ifdef PID_FILE
+	if ((pidfile = fopen(PID_FILE, "w")) != NULL) {
+		fprintf(pidfile, "%d\n", getpid());
+		fclose(pidfile);
+	} else
+		com_err(progname, errno,
+			"while opening pid file %s for writing", PID_FILE);
+#endif
+	if (listen(finet, 5) < 0) {
+		com_err(progname, errno, "in listen call");
+		exit(1);
+	}
+	while (1) {
+		int child_pid;
+	    
+		memset((char *)&frominet, 0, sizeof(frominet));
+		fromlen = sizeof(frominet);
+		s = accept(finet, (struct sockaddr *) &frominet, &fromlen);
+
+		if (s < 0) {
+			if (errno != EINTR)
+				com_err(progname, errno,
+					"from accept system call");
+			continue;
+		}
+		if (debug)
+			child_pid = 0;
+		else
+			child_pid = fork();
+		switch (child_pid) {
+		case -1:
+			com_err(progname, errno, "while forking");
+			exit(1);
+		case 0:
+			(void) close(finet);
+
+			doit(s);
+			close(s);
+			_exit(0);
+		default:
+			wait(0);
+			close(s);
+			
+		}
+	}
+}
+
+void doit(fd)
+	int	fd;
+{
+	struct sockaddr_in from;
+	int on = 1;
+	GETPEERNAME_ARG3_TYPE fromlen;
+	struct hostent	*hp;
+	krb5_error_code	retval;
+	krb5_data confmsg;
+	int lock_fd;
+	mode_t omask;
+	krb5_enctype etype;
+	int database_fd;
+
+	fromlen = sizeof (from);
+	if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
+		fprintf(stderr, "%s: ", progname);
+		perror("getpeername");
+		exit(1);
+	}
+	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on,
+		       sizeof (on)) < 0) {
+		com_err(progname, errno,
+			"while attempting setsockopt (SO_KEEPALIVE)");
+	}
+
+	if (!(hp = gethostbyaddr((char *) &(from.sin_addr.s_addr), fromlen,
+				 AF_INET))) {
+		syslog(LOG_INFO, "Connection from %s",
+		       inet_ntoa(from.sin_addr));
+		if (debug)
+			printf("Connection from %s\n",
+			       inet_ntoa(from.sin_addr));
+	} else {
+		syslog(LOG_INFO, "Connection from %s", hp->h_name);
+		if (debug)
+			printf("Connection from %s\n", hp->h_name);
+	}
+
+	/*
+	 * Now do the authentication
+	 */
+	kerberos_authenticate(kpropd_context, fd, &client, &etype, from);
+
+	if (!authorized_principal(kpropd_context, client, etype)) {
+		char	*name;
+
+		retval = krb5_unparse_name(kpropd_context, client, &name);
+		if (retval) {
+			com_err(progname, retval,
+				"While unparsing client name");
+			exit(1);
+		}
+		syslog(LOG_WARNING,
+		       "Rejected connection from unauthorized principal %s",
+		       name);
+		free(name);
+		exit(1);
+	}
+	omask = umask(077);
+	lock_fd = open(temp_file_name, O_RDWR|O_CREAT, 0600);
+	(void) umask(omask);
+	retval = krb5_lock_file(kpropd_context, lock_fd, 
+				KRB5_LOCKMODE_EXCLUSIVE|KRB5_LOCKMODE_DONTBLOCK);
+	if (retval) {
+	    com_err(progname, retval, "while trying to lock '%s'",
+		    temp_file_name);
+	    exit(1);
+	}
+	if ((database_fd = open(temp_file_name,
+				O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
+		com_err(progname, errno,
+			"while opening database file, '%s'",
+			temp_file_name);
+		exit(1);
+	}
+	recv_database(kpropd_context, fd, database_fd, &confmsg);
+	if (rename(temp_file_name, file)) {
+		com_err(progname, errno, "While renaming %s to %s",
+			temp_file_name, file);
+		exit(1);
+	}
+	retval = krb5_lock_file(kpropd_context, lock_fd, KRB5_LOCKMODE_SHARED);
+	if (retval) {
+	    com_err(progname, retval, "while downgrading lock on '%s'",
+		    temp_file_name);
+	    exit(1);
+	}
+	load_database(kpropd_context, kdb5_util, file);
+	retval = krb5_lock_file(kpropd_context, lock_fd, KRB5_LOCKMODE_UNLOCK);
+	if (retval) {
+	    com_err(progname, retval, "while unlocking '%s'", temp_file_name);
+	    exit(1);
+	}
+	(void)close(lock_fd);
+
+	/*
+	 * Send the acknowledgement message generated in
+	 * recv_database, then close the socket.
+	 */
+	retval = krb5_write_message(kpropd_context, (void *) &fd, &confmsg);
+	if (retval) { 
+		krb5_free_data_contents(kpropd_context, &confmsg);
+		com_err(progname, retval,
+			"while sending # of received bytes");
+		exit(1);
+	}
+	krb5_free_data_contents(kpropd_context, &confmsg);
+	if (close(fd) < 0) {
+		com_err(progname, errno,
+			"while trying to close database file");
+		exit(1);
+	}
+	
+	exit(0);
+}
+
+static void
+kpropd_com_err_proc(whoami, code, fmt, args)
+	const char	*whoami;
+	long		code;
+	const char	*fmt;
+	va_list		args;
+{
+	char	error_buf[8096];
+
+	error_buf[0] = '\0';
+	if (fmt)
+		vsprintf(error_buf, fmt, args);
+	syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "",
+	       code ? error_message(code) : "", code ? " " : "", error_buf);
+}
+
+void PRS(argv)
+	char	**argv;
+{
+	register char	*word, ch;
+	krb5_error_code	retval;
+	static const char	tmp[] = ".temp";
+	
+	retval = krb5_init_context(&kpropd_context);
+	if (retval) {
+		com_err(argv[0], retval, "while initializing krb5");
+		exit(1);
+	}
+
+	progname = *argv++;
+	while ((word = *argv++)) {
+		if (*word == '-') {
+			word++;
+			while (word && (ch = *word++)) {
+				switch(ch){
+				case 'f':
+					if (*word)
+						file = word;
+					else
+						file = *argv++;
+					if (!file)
+						usage();
+					word = 0;
+					break;
+				case 'F':
+					if (*word)
+						kerb_database = word;
+					else
+						kerb_database = *argv++;
+					if (!kerb_database)
+						usage();
+					word = 0;
+					break;
+				case 'p':
+					if (*word)
+						kdb5_util = word;
+					else
+						kdb5_util = *argv++;
+					if (!kdb5_util)
+						usage();
+					word = 0;
+					break;
+				case 'P':
+					if (*word)
+						port = htons(atoi(word));
+					else
+						port = htons(atoi(*argv++));
+					if (!port)
+						usage();
+					word = 0;
+					break;
+				case 'r':
+					if (*word)
+						realm = word;
+					else
+						realm = *argv++;
+					if (!realm)
+						usage();
+					word = 0;
+					break;
+				case 's':
+					if (*word)
+						srvtab = word;
+					else
+						srvtab = *argv++;
+					if (!srvtab)
+						usage();
+					word = 0;
+					break;
+				case 'd':
+					debug++;
+					break;
+				case 'S':
+					standalone++;
+					break;
+				   case 'a':
+					if (*word)
+					     acl_file_name = word;
+					else
+					     acl_file_name = *argv++;
+					if (!acl_file_name)
+					     usage();
+					word = 0;
+					break;
+				default:
+					usage();
+				}
+				
+			}
+		} else
+			/* We don't take any arguments, only options */
+			usage();
+	}
+	/*
+	 * If not in debug mode, switch com_err reporting to syslog
+	 */
+	if (! debug) {
+	    openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
+	    set_com_err_hook(kpropd_com_err_proc);
+	}
+	/*
+	 * Get my hostname, so we can construct my service name
+	 */
+	retval = krb5_sname_to_principal(kpropd_context,
+					 NULL, KPROP_SERVICE_NAME,
+					 KRB5_NT_SRV_HST, &server);
+	if (retval) {
+		com_err(progname, retval,
+			"While trying to construct my service name");
+		exit(1);
+	}
+	if (realm) {
+	    retval = krb5_set_principal_realm(kpropd_context, server, realm);
+	    if (retval) {
+	        com_err(progname, errno, 
+			"while constructing my service realm");
+		exit(1);
+	    }
+	}
+	/*
+	 * Construct the name of the temporary file.
+	 */
+	if ((temp_file_name = (char *) malloc(strlen(file) +
+					       strlen(tmp) + 1)) == NULL) {
+		com_err(progname, ENOMEM,
+			"while allocating filename for temp file");
+		exit(1);
+	}
+	strcpy(temp_file_name, file);
+	strcat(temp_file_name, tmp);
+}
+
+/*
+ * Figure out who's calling on the other end of the connection....
+ */
+void
+kerberos_authenticate(context, fd, clientp, etype, my_sin)
+    krb5_context 	  context;
+    int		 	  fd;
+    krb5_principal	* clientp;
+    krb5_enctype	* etype;
+    struct sockaddr_in	  my_sin;
+{
+    krb5_error_code	  retval;
+    krb5_ticket		* ticket;
+    struct sockaddr_in	  r_sin;
+    GETSOCKNAME_ARG3_TYPE sin_length;
+    krb5_keytab		  keytab = NULL;
+
+    /*
+     * Set recv_addr and send_addr
+     */
+    sender_addr.addrtype = ADDRTYPE_INET;
+    sender_addr.length = sizeof(my_sin.sin_addr);
+    sender_addr.contents = (krb5_octet *) malloc(sizeof(my_sin.sin_addr));
+    memcpy((char *) sender_addr.contents, (char *) &my_sin.sin_addr,
+           sizeof(my_sin.sin_addr));
+
+    sin_length = sizeof(r_sin);
+    if (getsockname(fd, (struct sockaddr *) &r_sin, &sin_length)) {
+	com_err(progname, errno, "while getting local socket address");
+	exit(1);
+    }
+
+    receiver_addr.addrtype = ADDRTYPE_INET;
+    receiver_addr.length = sizeof(r_sin.sin_addr);
+    receiver_addr.contents = (krb5_octet *) malloc(sizeof(r_sin.sin_addr));
+    memcpy((char *) receiver_addr.contents, (char *) &r_sin.sin_addr,
+           sizeof(r_sin.sin_addr));
+
+    if (debug) {
+	char *name;
+
+	retval = krb5_unparse_name(context, server, &name);
+	if (retval) {
+	    com_err(progname, retval, "While unparsing client name");
+	    exit(1);
+	}
+	printf("krb5_recvauth(%d, %s, %s, ...)\n", fd, kprop_version, name);
+	free(name);
+    }
+
+    retval = krb5_auth_con_init(context, &auth_context);
+    if (retval) {
+	syslog(LOG_ERR, "Error in krb5_auth_con_ini: %s",
+	       error_message(retval));
+    	exit(1);
+    }
+
+    retval = krb5_auth_con_setflags(context, auth_context, 
+				    KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+    if (retval) {
+	syslog(LOG_ERR, "Error in krb5_auth_con_setflags: %s",
+	       error_message(retval));
+	exit(1);
+    }
+
+    retval = krb5_auth_con_setaddrs(context, auth_context, &receiver_addr,
+				    &sender_addr);
+    if (retval) {
+	syslog(LOG_ERR, "Error in krb5_auth_con_setaddrs: %s",
+	       error_message(retval));
+	exit(1);
+    }
+
+    if (srvtab) {
+        retval = krb5_kt_resolve(context, srvtab, &keytab);
+	if (retval) {
+	  syslog(LOG_ERR, "Error in krb5_kt_resolve: %s", error_message(retval));
+	  exit(1);
+	}
+    }
+
+    retval = krb5_recvauth(context, &auth_context, (void *) &fd,
+			   kprop_version, server, 0, keytab, &ticket);
+    if (retval) {
+	syslog(LOG_ERR, "Error in krb5_recvauth: %s", error_message(retval));
+	exit(1);
+    }
+
+    retval = krb5_copy_principal(context, ticket->enc_part2->client, clientp);
+    if (retval) {
+	syslog(LOG_ERR, "Error in krb5_copy_prinicpal: %s", 
+	       error_message(retval));
+	exit(1);
+    }
+
+    *etype = ticket->enc_part.enctype;
+
+    if (debug) {
+	char * name;
+	char etypebuf[100];
+
+	retval = krb5_unparse_name(context, *clientp, &name);
+	if (retval) {
+	    com_err(progname, retval, "While unparsing client name");
+	    exit(1);
+	}
+
+	retval = krb5_enctype_to_string(*etype, etypebuf, sizeof(etypebuf));
+	if (retval) {
+	    com_err(progname, retval, "While unparsing ticket etype");
+	    exit(1);
+	}
+
+	printf("authenticated client: %s (etype == %s)\n", name, etypebuf);
+	free(name);
+    }
+
+    krb5_free_ticket(context, ticket);
+}
+
+krb5_boolean
+authorized_principal(context, p, auth_etype)
+    krb5_context context;
+    krb5_principal p;
+    krb5_enctype auth_etype;
+{
+    char		*name, *ptr;
+    char		buf[1024];
+    krb5_error_code	retval;
+    FILE		*acl_file;
+    int			end;
+    krb5_enctype	acl_etype;
+    
+    retval = krb5_unparse_name(context, p, &name);
+    if (retval)
+	return FALSE;
+
+    acl_file = fopen(acl_file_name, "r");
+    if (!acl_file)
+	return FALSE;
+
+    while (!feof(acl_file)) {
+	if (!fgets(buf, sizeof(buf), acl_file))
+	    break;
+	end = strlen(buf) - 1;
+	if (buf[end] == '\n')
+	    buf[end] = '\0';
+	if (!strncmp(name, buf, strlen(name))) {
+	    ptr = buf+strlen(name);
+
+	    /* if the next character is not whitespace or nul, then
+	       the match is only partial.  continue on to new lines. */
+	    if (*ptr && !isspace((int) *ptr))
+		continue;
+
+	    /* otherwise, skip trailing whitespace */
+	    for (; *ptr && isspace((int) *ptr); ptr++) ;
+
+	    /* now, look for an etype string. if there isn't one,
+	       return true.  if there is an invalid string, continue.
+	       If there is a valid string, return true only if it
+	       matches the etype passed in, otherwise continue */
+
+	    if ((*ptr) &&
+		((retval = krb5_string_to_enctype(ptr, &acl_etype)) ||
+		 (acl_etype != auth_etype)))
+		continue;
+
+	    free(name);
+	    fclose(acl_file);
+	    return TRUE;
+	}
+    }
+    free(name);
+    fclose(acl_file);
+    return FALSE;
+}
+
+void
+recv_database(context, fd, database_fd, confmsg)
+    krb5_context context;
+    int	fd;
+    int	database_fd;
+    krb5_data *confmsg;
+{
+	krb5_ui_4	database_size; /* This must be 4 bytes */
+	int	received_size, n;
+	char		buf[1024];
+	krb5_data	inbuf, outbuf;
+	krb5_error_code	retval;
+
+	/*
+	 * Receive and decode size from client
+	 */
+	retval = krb5_read_message(context, (void *) &fd, &inbuf);
+	if (retval) {
+		send_error(context, fd, retval, "while reading database size");
+		com_err(progname, retval,
+			"while reading size of database from client");
+		exit(1);
+	}
+	if (krb5_is_krb_error(&inbuf))
+		recv_error(context, &inbuf);
+	retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL);
+	if (retval) {
+		send_error(context, fd, retval, 
+			   "while decoding database size");
+		krb5_free_data_contents(context, &inbuf);
+		com_err(progname, retval,
+			"while decoding database size from client");
+		exit(1);
+	}
+	memcpy((char *) &database_size, outbuf.data, sizeof(database_size));
+	krb5_free_data_contents(context, &inbuf);
+	krb5_free_data_contents(context, &outbuf);
+	database_size = ntohl(database_size);
+
+	/*
+	 * Initialize the initial vector.
+	 */
+	retval = krb5_auth_con_initivector(context, auth_context);
+	if (retval) {
+	  send_error(context, fd, retval, 
+		     "failed while initializing i_vector");
+	  com_err(progname, retval, "while initializing i_vector");
+	  exit(1);
+	}
+
+	/*
+	 * Now start receiving the database from the net
+	 */
+	received_size = 0;
+	while (received_size < database_size) {
+	        retval = krb5_read_message(context, (void *) &fd, &inbuf);
+		if (retval) {
+			sprintf(buf,
+				"while reading database block starting at offset %d",
+				received_size);
+			com_err(progname, retval, buf);
+			send_error(context, fd, retval, buf);
+			exit(1);
+		}
+		if (krb5_is_krb_error(&inbuf))
+			recv_error(context, &inbuf);
+		retval = krb5_rd_priv(context, auth_context, &inbuf, 
+				      &outbuf, NULL);
+		if (retval) {
+			sprintf(buf,
+				"while decoding database block starting at offset %d",
+				received_size);
+			com_err(progname, retval, buf);
+			send_error(context, fd, retval, buf);
+			krb5_free_data_contents(context, &inbuf);
+			exit(1);
+		}
+		n = write(database_fd, outbuf.data, outbuf.length);
+		krb5_free_data_contents(context, &inbuf);
+		krb5_free_data_contents(context, &outbuf);
+		if (n < 0) {
+			sprintf(buf,
+				"while writing database block starting at offset %d",
+				received_size);
+			send_error(context, fd, errno, buf);
+		} else if (n != outbuf.length) {
+			sprintf(buf,
+				"incomplete write while writing database block starting at \noffset %d (%d written, %d expected)",
+				received_size, n, outbuf.length);
+			send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
+		}
+		received_size += outbuf.length;
+	}
+	/*
+	 * OK, we've seen the entire file.  Did we get too many bytes?
+	 */
+	if (received_size > database_size) {
+		sprintf(buf,
+			"Received %d bytes, expected %d bytes for database file",
+			received_size, database_size);
+		send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
+	}
+	/*
+	 * Create message acknowledging number of bytes received, but
+	 * don't send it until kdb5_util returns successfully.
+	 */
+	database_size = htonl(database_size);
+	inbuf.data = (char *) &database_size;
+	inbuf.length = sizeof(database_size);
+	retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL);
+	if (retval) {
+		com_err(progname, retval,
+			"while encoding # of receieved bytes");
+		send_error(context, fd, retval,
+			   "while encoding # of received bytes");
+		exit(1);
+	}
+}
+
+
+void
+send_error(context, fd, err_code, err_text)
+    krb5_context context;
+    int	fd;
+    krb5_error_code	err_code;
+    char	*err_text;
+{
+	krb5_error	error;
+	const char	*text;
+	krb5_data	outbuf;
+	char		buf[1024];
+
+	memset((char *)&error, 0, sizeof(error));
+	krb5_us_timeofday(context, &error.stime, &error.susec);
+	error.server = server;
+	error.client = client;
+	
+	if (err_text)
+		text = err_text;
+	else
+		text = error_message(err_code);
+	
+	error.error = err_code - ERROR_TABLE_BASE_krb5;
+	if (error.error > 127) {
+		error.error = KRB_ERR_GENERIC;
+		if (err_text) {
+			sprintf(buf, "%s %s", error_message(err_code),
+				err_text);
+			text = buf;
+		}
+	} 
+	error.text.length = strlen(text) + 1;
+	error.text.data = malloc(error.text.length);
+	if (error.text.data) {
+		strcpy(error.text.data, text);
+		if (!krb5_mk_error(context, &error, &outbuf)) {
+			(void) krb5_write_message(context, (void *)&fd,&outbuf);
+			krb5_free_data_contents(context, &outbuf);
+		}
+		free(error.text.data);
+	}
+}
+
+void
+recv_error(context, inbuf)
+    krb5_context context;
+    krb5_data	*inbuf;
+{
+	krb5_error	*error;
+	krb5_error_code	retval;
+
+	retval = krb5_rd_error(context, inbuf, &error);
+	if (retval) {
+		com_err(progname, retval,
+			"while decoding error packet from client");
+		exit(1);
+	}
+	if (error->error == KRB_ERR_GENERIC) {
+		if (error->text.data)
+			fprintf(stderr,
+				"Generic remote error: %s\n",
+				error->text.data);
+	} else if (error->error) {
+		com_err(progname, 
+			(krb5_error_code) error->error + ERROR_TABLE_BASE_krb5,
+			"signalled from server");
+		if (error->text.data)
+			fprintf(stderr,
+				"Error text from client: %s\n",
+				error->text.data);
+	}
+	krb5_free_error(context, error);
+	exit(1);
+}
+
+void
+load_database(context, kdb_util, database_file_name)
+    krb5_context context;
+    char *kdb_util;
+    char *database_file_name;
+{
+	static char	*edit_av[10];
+	int	error_ret, save_stderr = -1;
+	int	child_pid;
+	int 	count;
+
+	/* <sys/param.h> has been included, so BSD will be defined on
+	   BSD systems */
+#if BSD > 0 && BSD <= 43
+#ifndef WEXITSTATUS
+#define	WEXITSTATUS(w) (w).w_retcode
+#endif
+	union wait	waitb;
+#else
+	int	waitb;
+#endif
+	krb5_error_code	retval;
+
+	if (debug)
+		printf("calling kdb5_util to load database\n");
+
+	edit_av[0] = kdb_util;
+	count = 1;
+	if (realm) {
+		edit_av[count++] = "-r";	
+		edit_av[count++] = realm;	
+	}
+	edit_av[count++] = "load";
+	if (kerb_database) {
+		edit_av[count++] = "-d";
+		edit_av[count++] = kerb_database;
+	}
+	edit_av[count++] = database_file_name;
+	edit_av[count++] = NULL;
+
+	switch(child_pid = fork()) {
+	case -1:
+		com_err(progname, errno, "while trying to fork %s",
+			kdb_util);
+		exit(1);
+	case 0:
+		if (!debug) {
+			save_stderr = dup(2);
+			close(0);
+			close(1);
+			close(2);
+			open("/dev/null", O_RDWR);
+			dup(0);
+			dup(0);
+		}
+
+		execv(kdb_util, edit_av);
+		retval = errno;
+		if (!debug)
+			dup2(save_stderr, 2);
+		com_err(progname, retval, "while trying to exec %s",
+			kdb_util);
+		_exit(1);
+		/*NOTREACHED*/
+	default:
+		if (debug)
+		    printf("Child PID is %d\n", child_pid);
+		if (wait(&waitb) < 0) {
+			com_err(progname, errno, "while waiting for %s",
+				kdb_util);
+			exit(1);
+		}
+	}
+	
+	error_ret = WEXITSTATUS(waitb);
+	if (error_ret) {
+		com_err(progname, 0, "%s returned a bad exit status (%d)",
+			kdb_util, error_ret);
+		exit(1);
+	}
+	return;
+}
diff --git a/mechglue/src/slave/kslave_update b/mechglue/src/slave/kslave_update
new file mode 100644
index 000000000..a4da274ff
--- /dev/null
+++ b/mechglue/src/slave/kslave_update
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Propagate if database (principal.db) has been modified since last dump
+# (dumpfile.dump_ok) or if database has been dumped since last successful
+# propagation (dumpfile.<slave machine>.last_prop)
+
+KDB_DIR=/usr/local/var/krb5kdc
+
+KDB_FILE=$KDB_DIR/principal.db
+DUMPFILE=$KDB_DIR/slave_datatrans
+KDB5_UTIL=/usr/local/sbin/kdb5_util
+KPROP=/usr/local/sbin/kprop
+
+SLAVE=$1
+if [ -z "${SLAVE}" ]
+then 
+  echo "Usage $0 slave_server"
+fi
+
+if [ "`ls -t $DUMPFILE.dump_ok $KDB_FILE | sed -n 1p`"  = "$KDB_FILE" -o \
+     "`ls -t $DUMPFILE.${SLAVE}.last_prop $DUMPFILE.dump_ok | \
+		sed -n 1p`"  = "$DUMPFILE.dump_ok" ]
+then
+
+	date
+	$KDB5_EDIT dump $DUMPFILE > /dev/null
+
+	$KPROP -d -f $DUMPFILE ${SLAVE}
+	rm $DUMPFILE
+fi
diff --git a/mechglue/src/t_krbconf b/mechglue/src/t_krbconf
new file mode 100644
index 000000000..caca81d03
--- /dev/null
+++ b/mechglue/src/t_krbconf
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# Copyright 2003 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+
+echo "Testing if krb5-config outputs shell variables"
+echo "  Testing --libs argument"
+if `./krb5-config --libs kdb | egrep -s '\\$'`; then 
+	echo "Error './krb5-config --libs kdb' contains shell variables"; 
+	exit 1; 
+fi
+
+echo "  Testing --cflags argument"
+if `./krb5-config --cflags | egrep -s '\\$'`; then \
+	echo "Error './krb5-config --cflags' contains shell variables"; \
+	exit 1; \
+fi
+echo "krb5-config tests pass"
+exit 0
diff --git a/mechglue/src/tests/.Sanitize b/mechglue/src/tests/.Sanitize
new file mode 100644
index 000000000..0aa6de22e
--- /dev/null
+++ b/mechglue/src/tests/.Sanitize
@@ -0,0 +1,46 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+asn.1
+configure
+configure.in
+create
+dejagnu
+dump.c
+gssapi
+hammer
+misc
+resolve
+test1.c
+verify
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/ChangeLog b/mechglue/src/tests/ChangeLog
new file mode 100644
index 000000000..bc2c3c6ed
--- /dev/null
+++ b/mechglue/src/tests/ChangeLog
@@ -0,0 +1,206 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Create makefile in misc.
+	* Makefile.in (LOCAL_SUBDIRS): Add misc.
+
+2005-02-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss-threads: New subdirectory.
+	* Makefile.in (LOCAL_SUBDIRS): Add it.
+	* configure.in: Configure it.  Check for semaphore.h, sem_init,
+	sem_trywait.
+
+2005-02-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Look for dlfcn.h.  Configure new shlib
+	subdirectory.
+	* Makefile.in (LOCAL_SUBDIRS): Build in shlib subdir.
+
+2004-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Build makefile for new "threads" subdirectory.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Invoke KRB5_AC_PRIOCNTL_HACK.
+
+2003-06-04  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (kdb_check): Remove uses of "dump -old", etc., since
+	it doesn't work anymore given the new default for triple-DES
+	master keys.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+2002-09-24  Ezra Peisach  <epeisach@bu.edu>
+
+	* Makefile.in (mydir): Add missing mydir lines.
+
+2002-08-26  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Use KRB5_LIB_PARAMS instead of AC_CANONICAL_HOST
+	to set krb5_cv_host.
+	
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-07  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Fix sense of HAVE_RUNTEST.
+
+2002-07-18  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Change K5_OUTPUT_FILES to K5_AC_OUTPUT (cleanup of
+	obsolete macro).
+
+2002-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Substitute HAVE_RUNTEST with "yes" or "no".
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Invoke AC_CANONICAL_HOST.
+
+2000-11-08  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Change KRB4_DEJAGNU_TEST variable to KRBIV from
+	KRB4; dejagnu-1.3 doesn't like digits in passed-in variables.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_C_CONST and AC_TYPE_SIGNAL instead of
+	AC_RETSIGTYPE and AC_TYPE_SIGNAL.
+
+2000-08-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Define KRB4_DEJAGNU_TEST depending on if krb4
+	support is enabled.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Wed Feb 18 16:27:44 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (thisconfigdir): Remove trailing slash.
+
+Thu Feb 12 16:19:11 1998  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add commented out AC_OUTPUT to force autoreconf to
+	rebuild the configure script.
+
+Mon Feb  2 16:47:05 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* configure.in: Create the makefiles for all of the subdirectories
+		and move all of the configure.in tests from the
+		subdirectories into this configure.in.
+	
+Wed Nov 19 10:54:01 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (kdb_check): Remove temporary file generated during test.
+
+Tue Nov  4 14:36:37 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (kdb_check): Reinstated kdb checks
+
+Wed Oct  8 10:52:36 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (kdb_check): Rewritten to use current admin system tools.
+
+Wed Jul 30 18:28:06 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Add "create" directory back.
+
+Fri Jul 19 15:31:22 1996  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in (CFLAGS): the tests in Makefile.in have been
+ 	superseded by other tests in the new admin system.
+
+	* configure.in: don't build create, since it doesn't work with the
+ 	new admin system, and isn't used by anything, anyway.
+
+Mon Mar 18 21:49:39 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add KRB5_RUN_FLAGS
+
+	* Makefile.in: Use runtime flags.
+
+Wed Feb 28 00:35:58 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Build the gssapi tests directory
+
+Wed Oct 25 11:23:26 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (check-unix): Run db checks before dejagnu tests. 
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * test1.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Fri Sep 1 14:39:07 EDT 1995	Paul Park	(pjpark@mit.edu)
+
+	* Makefile.in - Add test for "old" dump format.
+
+Thu Aug 24 18:48:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Fri Jul 7 16:35:30 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS.
+
+
+Thu Jun 15 18:10:03 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Set LD_LIBRARY_PATH to be the library directory in
+		case we've built with shared libraries.
+
+Fri Jun  9 18:56:53 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Wed May 03 02:25:32 1995  Chris Provenzano  (proven@mit.edu)
+
+	* Imakefile : Removed.
+
+Wed Apr 26 17:26:19 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: Added dejagnu subdirectory for Ian's tests.
+
+Wed Mar  1 16:31:35 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Added resolve subdirectory.
+
+Tue Feb 28 01:23:18 1995  John Gilmore  (gnu at toad.com)
+
+	* dump.c, test1.c:  Avoid <krb5/...> includes.
+
+Sun Oct 23 01:47:14 1994    (tytso@rsx-11)
+
+	* Makefile.in (check): Do checks for depth = 5
+
+Fri Oct  7 01:26:42 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in (check): Add general admin/kdb confidence check.
+
+Thu Oct  6 21:41:46 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Add recursive "make check"
+
+Wed Jun 29 00:26:31 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* test1.c: added call to krb5_init_ets
+
diff --git a/mechglue/src/tests/Makefile.in b/mechglue/src/tests/Makefile.in
new file mode 100644
index 000000000..c1261adc4
--- /dev/null
+++ b/mechglue/src/tests/Makefile.in
@@ -0,0 +1,57 @@
+thisconfigdir=.
+mydir=.
+BUILDTOP=$(REL)..
+LOCAL_SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \
+	gss-threads misc
+
+RUN_SETUP = @KRB5_RUN_ENV@ KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
+KRB5_RUN_ENV= @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+TEST_DB = ./testdb
+TEST_REALM = FOO.TEST.REALM
+TEST_MKEY = footes
+TEST_NUM = 65
+TEST_DEPTH = 5
+TEST_PREFIX = "foo bar"
+
+KADMIN_OPTS= -d $(TEST_DB) -r $(TEST_REALM) -P $(TEST_MKEY)
+KTEST_OPTS= $(KADMIN_OPTS) -p $(TEST_PREFIX) -n $(TEST_NUM) -D $(TEST_DEPTH)
+
+check-unix:: kdb_check
+
+kdc.conf: Makefile
+	rm -rf kdc.conf
+	@echo "[realms]" > kdc.conf
+	@echo "$(TEST_REALM) = {" >> kdc.conf
+	@echo "  key_stash_file = `pwd`/stash_file" >> kdc.conf
+	@echo "}" >> kdc.conf
+
+
+kdb_check: kdc.conf
+	$(RM) $(TEST_DB)*
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) create
+	$(RUN_SETUP) ../tests/create/kdb5_mkdums $(KTEST_OPTS) 
+	$(RUN_SETUP) ../tests/verify/kdb5_verify $(KTEST_OPTS) 
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) dump $(TEST_DB).dump
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) dump -ov $(TEST_DB).ovdump
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) load $(TEST_DB).dump 
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) load -update -ov $(TEST_DB).ovdump 
+	$(RUN_SETUP) ../tests/verify/kdb5_verify $(KTEST_OPTS) 
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) dump $(TEST_DB).dump2
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) dump -ov $(TEST_DB).ovdump2
+	sort $(TEST_DB).dump > $(TEST_DB).sort
+	sort $(TEST_DB).dump2 > $(TEST_DB).sort2
+	sort $(TEST_DB).ovdump > $(TEST_DB).ovsort
+	sort $(TEST_DB).ovdump2 > $(TEST_DB).ovsort2
+	cmp $(TEST_DB).sort $(TEST_DB).sort2
+	cmp $(TEST_DB).ovsort $(TEST_DB).ovsort2
+	$(RUN_SETUP) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f
+	$(RM) $(TEST_DB)* stash_file
+
+clean::
+	$(RM) kdc.conf
+
+
diff --git a/mechglue/src/tests/asn.1/.Sanitize b/mechglue/src/tests/asn.1/.Sanitize
new file mode 100644
index 000000000..1710e358c
--- /dev/null
+++ b/mechglue/src/tests/asn.1/.Sanitize
@@ -0,0 +1,49 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+README
+configure
+configure.in
+debug.h
+krb5_decode_test.c
+krb5_encode_test.c
+ktest.c
+ktest.h
+ktest_equal.c
+ktest_equal.h
+reference_encode.out
+trval.c
+trval_reference.out
+utility.c
+utility.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/asn.1/ChangeLog b/mechglue/src/tests/asn.1/ChangeLog
new file mode 100644
index 000000000..dbe7c3ba6
--- /dev/null
+++ b/mechglue/src/tests/asn.1/ChangeLog
@@ -0,0 +1,498 @@
+2005-11-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* utility.h: Don't include krb5.h.
+	* utility.c: Include utility.h before krb5.h.
+
+2005-06-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* trval.c (convert_nibble): Declare the argument with a type.
+
+2004-04-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* debug.h (test): Macro renamed from "assert".
+	* krb5_decode_test.c, krb5_encode_test.c: Callers updated.
+
+2003-05-18  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_decode_test.c (main): Add new test cases for sequence
+	number compatibility.
+
+	* utility.c (krb5_data_hex_parse): Rewrite to be more lenient
+	about whitespace.
+
+2003-05-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5_decode_test.c: Modify decode_run macro to take a cleanup
+	handler to free allocated memory. Add static handlers to free
+	krb5_alt_method, passwd_phrase_element and krb5_enc_data as the
+	krb5 library does not handle at this time.
+
+	* krb5_encode_test.c: Free krb5_context at end. Utilize the many
+	ktest_empty and detroy functions to cleanup memory.
+
+	* ktest.h, ktest.c: Add many ktest free and empty functions to
+	cleanup allocated structures in tests.
+
+	* utility.c (krb5_data_hex_parse): Free temporary data.
+	
+
+2003-05-06  Sam Hartman  <hartmans@mit.edu>
+
+	* krb5_encode_test.c (main): Add etype_info2 support
+
+	* ktest.c (ktest_make_sample_etype_info): Initialize s2kparams to be null.
+	(ktest_make_sample_etype_info2): New function
+
+2002-11-07  Ezra Peisach  <epeisach@bu.edu>
+
+	* krb5_decode_test.c: Test for sam_challenege without empty
+	optional strings.
+
+	* trval_reference.out, reference_encode.out: Update to reflect
+	that optional fields in sam_challenge are not being output.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* ktest.h, ktest_equal.h, utility.c, utility.h: Make prototypes
+	unconditional.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* trval.c: Include string.h for strcmp prototype.
+
+2001-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* trval.c (decode_len, do_prim, do_cons, do_prim_bitstring,
+	do_prim_int, do_prim_string, print_tag_type, trval, trval2):
+	Always use prototype declarations.
+
+Sun Feb 18 15:33:50 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* trval.c: Add prototypes for trval() and trval2().
+
+2000-10-26  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_decode_test.c (main): Add new test cases for indefinite
+	length ticket and as_rep.  Fix up calls to decode_run() to have
+	the modifier be in the description parameter.
+
+2000-10-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* ktest.c (ktest_make_sample_etype_info): Use KRB5_ETYPE_NO_SALT
+	instead of -1.
+
+	* ktest_equal.c (ktest_equal_krb5_etype_info_entry): Test for
+	KRB5_ETYPE_NO_SALT. ktest_equal_array_of_octet() and
+	ktest_equal_array_of_char take unsigned int lengths.
+
+	* ktest_equal.h: Add len_unsigned_array macro for a prototype of a
+	function taking an unsigned int
+	count. ktest_equal_array_of_octet() is one of
+	these. ktest_equal_array_of_char() takes an unsigned int as
+	length.
+
+	* trval.c (trval): Unsigned/signed int fix. 
+
+	* utility.c (asn1_krb5_data_unparse): Better test for krb5_data
+	length being less than zero.
+
+2000-09-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5_decode_test.c (decode_run): If the ASN1 decoder returns an
+	error, add one to the error count so there will be a non-zero
+	exit. Sometimes, the decoded structure is complete enoght to pass
+	the test, even with an ASN.1 error - which can easilly get missed
+	in the output run.
+
+2000-08-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* reference_encode.out, trval_reference.out: Test encoding of
+	negative lr_type field.
+
+	* krb5_decode_test.c: Fix enc_kdc_rep_part tests to trully handle
+	a negative lr_type in a krb5_last_req_entry structure. If
+	KRB5_GENEROUS_LR_TYPE is defined, do a backwards compatibility
+	test as well.
+
+2000-07-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* utility.c: Add casts on types being sent to internal functions.
+
+	* krb5_encode_test.c: Declare internal functions as static.
+
+	* ktest.c: Remove unused functions. Clean up compiler warnings.
+
+	* trval.c: Add proper prototype for declared functions.
+
+1999-11-01  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_decode_test.c (main): Add test case for zero-length
+	SequenceOfType.
+
+1999-10-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* trval.c (print_tag_type): Use fputs when there's no formatting
+	to do.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+Sat Jul 10 10:32:31 1999  Tom Yu  <chaoself@mit.edu>
+
+	* krb5_decode_test.c (main): Add additional test cases in
+ 	encryption_key to test negative integer handling.
+
+1999-07-03  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_decode_test.c (main): Add test cases for encryption_key in
+	order to test skipping of trailing fields in sequences, as well as
+	handling of indefinite lengths in sequences.
+
+Thu Jan 28 20:04:52 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* trval.c: Now understands krb5 structure elements.
+
+	* krb5_encode_test.c: Pass trval type hints to trval2() so that
+		datastructures get properly decoded.
+
+Fri Jan 22 02:08:59 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* trval.c: Added usage message, better options parsing, and
+		support for two new options: -hex, which will accept the
+		asn.1 encoding in hex (i.e., from a packet dump), and
+		-krb5, which instructs the trval to print out the krb5
+		interpretations of the data types.  Trval will now also
+		try to interpret the field names of known krb5 structures
+		if -krb5 is specified.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Thu Dec  3 22:27:08 1998  Tom Yu  <tlyu@mit.edu>
+
+	* krb5_decode_test.c (main): Add variant test cases on
+	enc_tkt_part to test bit string values that aren't exactly 32
+	bits, including 38, 40, 29, and 24 bits to test boundary
+	conditions.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5_encode_test.c (PRS): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Mon Mar 30 13:51:58 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ktest_equal.h: Add prototypes for ktest_equal_sam_challenge and 
+	ktest_equal_sam_response
+
+	* ktest.c (ktest_make_sample_sam_response): Remove unused variable.
+
+	* krb5_decode_test.c, krb5_decode_test.c (main): Declare main as
+        int not void.
+
+Wed Feb 18 16:27:56 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 16:46:31 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sun Aug 17 14:26:19 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(srcdir).
+
+Thu Mar 20 16:50:10 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Remove AC_PROG_INSTALL.
+
+Sun Feb  9 01:31:00 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu Nov 14 14:13:41 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* krb5_encode_test.c (PRS): Add the -p option to krb5_encode_test
+		to change the sample principal value (to test encoding of
+		different krb5 principals).
+
+	* ktest.c (ktest_make_sample_principal): Use krb5_parse_principal
+ 		so that sample principal can be configured for different
+ 		purposes.
+
+	* krb5_decode_test.c (main): 
+	* krb5_encode_test.c (main): Check return value from
+		krb5_init_context to make sure it succeeded.
+
+	* Makefile.in (check): Set KRB5_CONFIG to
+	 	$(TOPSRC)/config-files/krb5.conf so that the tests work.
+
+Wed Jun  5 15:59:12 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5_decode_test.c (main): For asn1_decode_enc_kdc_rep_part,
+		starttime will equal authtime if not sent OTW.
+
+Tue Apr  2 20:57:12 1996  Chris Provenzano  <proven@mit.edu>
+
+	* utility.c (krb5_data_hex_parse()) : Do a strdup() of string before
+		sending it off to sscanf(), because some systems sscanf can't
+		handle non writeable strings.
+
+Fri Mar 29 03:00:34 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5_decode_test.c (main): add tests for krb5_sam_challenge and
+	krb5_sam_response.
+	* krb5_encode_test.c (main): likewise.
+	* ktest.c (ktest_make_sample_sam_challenge,
+	ktest_make_sample_sam_response): new functions, supporting tests
+	of new types.
+	* ktest_equal.c (ktest_equal_sam_challenge,
+	ktest_equal_sam_response): new comparators.
+	* reference_encode.out, trval_reference.out: add data for test cases.
+	
+Mon Mar 18 21:49:39 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add KRB5_RUN_FLAGS
+
+	* Makefile.in: Use runtime flags.
+
+Sun Mar  3 13:05:57 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5_decode_test.c (main): In krb5_enc_tkt_part (optionals NULL)
+		test, set starttime to authtime. Matches change to
+		lib/krb5/asn.1/krb5_decode.c.
+
+Wed Nov 15 15:28:32 1995  Chris Provenzano  (proven@mit.edu)
+
+	* ktest_equal.c (ktest_equal_krb5_etype_info_entry()) :
+		Only do emecmp() if ref->length > 0
+
+Wed Nov  8 20:03:51 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_encode_test.c (main): In case of an error in the encoding
+		routines, exit.  Otherwise, calling the print routines
+		will often lead to a coredump.
+
+	* ktest.c (ktest_make_sample_etype_info): Set etype.length to -1
+		to mean that the optional salt string is missing.  (This
+		is change in the convention used by the ASN.1 encoder and
+		decoder for this ASN.1 structure.) 
+
+Tue Oct 31 21:30:28 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_decode_test.c (main): Add tests for
+	        decode_krb5_enc_data and decode_krb5_pa_enc_ts.
+
+	* krb5_encode_test.c (main): Add tests for
+	        encode_krb5_enc_data and encode_krb5_pa_enc_ts.
+
+	* ktest.c (ktest_make_sample_pa_enc_ts): New functions to
+	        test {encode,decode}_krb5_pa_enc_ts().
+
+	* ktest_equal.c (ktest_equal_krb5_pa_enc_ts): New functions to test
+		{encode,decode}_krb5_pa_enc_ts().
+
+Sun Oct 15 10:51:22 1995    <tytso@rsts-11.mit.edu>
+
+	* ktest.c (ktest_make_sample_alt_method,
+		ktest_make_sample_etype_info): Fixed signed/unsinged -Wall
+		flame.
+
+Fri Sep 29 14:23:47 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (clean): Remove trval on a make clean
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * ktest.c, ktest_equal.c, ktest_equal.h : 
+		s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * ktest.c, ktest.h, ktest_equal.c, ktest_equal.h : Remove krb5_enctype 
+		references, and replace with krb5_keytype where appropriate
+
+Tue Aug 29 14:20:52 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krb5_decode_test.c - Fix string constant.
+	* trval.c - Remove definitions of malloc and realloc.  They should come
+		in from stdlib.h.
+
+Mon Aug 28 16:35:22 1995    <tytso@rsts-11.mit.edu>
+
+	* krb5_decode_test.c (main): Add tests for
+	        decode_krb5_{etype_info,alt_method}.
+
+	* krb5_encode_test.c (main): Add tests for
+	        encode_krb5_{etype_info,alt_method}.
+
+	* ktest_equal.c (ktest_equal_krb5_alt_method,
+	        ktest_equal_krb5_etype_info_entry,
+	        ktest_equal_krb5_etype_info) New functions to test
+		{encode,decode}_krb5_{etype_info,alt_method}.
+
+	* ktest.c (ktest_make_sample_etype_info_entry,
+		ktest_make_sample_etype_info,
+		ktest_make_sample_alt_method,
+		ktest_destroy_etype_info_entry, ktest_destroy_etype_info):
+		New functions to test
+		{encode,decode}_krb5_{etype_info,alt_method}.
+
+Sat Aug 26 12:40:57 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* krb5_encode_test.c (encoder_print_results): If trval2 returns
+		non zero, indicate with error before exiting.
+
+Fri Aug 25 21:50:37 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* krb5_encode_test.c (main): Add tests for
+		encode_krb5_padata_sequence(). 
+
+	* krb5_decode_test.c (main): Add tests for
+		decode_krb5_padata_sequence().
+
+	* ktest.c (ktest_make_sample_empty_pa_data_array): New function
+		which creates an empty pa_data array.
+
+	* trval.c:  Various -Wall cleanups.
+
+	* Makefile.in (trval): Add rule to build the standalone trval
+		program. 
+
+Thu Jul 27 15:29:10 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* krb5_{en,de}code_test.c - Use k5-int instead of krb5 and asn1.h.
+
+
+Wed Jul 12 12:30:45 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add LD_LIBRARY_PATH in case we used shared objects
+		by default.
+	* configure.in - Remove V5_USE_SHARED_LIB.
+
+
+Fri Jul 7 16:36:12 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling and LDFLAGS.
+	* configure.in - Add KRB5_LIBRARIES and V5_USE_SHARED_LIB.
+
+Tue Jun 20 14:56:53 1995    <tytso@rsx-11.mit.edu>
+
+	* ktest.h, ktest_equal.h: Change PROTOTYPE to KRB5_PROTOTYPE
+
+Fri Jun  9 18:57:22 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Mar  2 12:33:47 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:32:02 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE and ISODE_DEFS, replace check
+		for -lsocket and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:23:57 1995  John Gilmore  (gnu at toad.com)
+
+	* krb5_decode_test.c, krb5_encode_test.c, ktest.h, ktest_equal.h,
+	utility.c, utility.h:  Avoid <krb5/...> includes.
+
+Tue Feb 14 00:18:35 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Use $(LD) instead of $(CC) when linking.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Fri Nov 18 16:29:01 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* ktest.c (ktest_make_sample_keybloc): Add magic numbers for
+		keyblock structure.
+
+Tue Nov  1 20:25:02 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* trval.c: Include the tag numbers for the krb5 application tags,
+		since that's something we're going to want to check to
+		make sure they're actually correct.
+
+	* krb5_encode_test.c: 
+	* Makefile.in: 
+	* trval.c: Add the "-t option to krb5_encode_test, which causes it
+		to use the ASN.1 unparser found in trval.c.  This routine
+		will attempt to decode the ASN.1 data stream and display
+		it in a logical format for a human being to decipher.
+
+Wed Oct 19 00:11:43 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* debug.h (assert):
+	  krb5_encode_test.c (main):
+	  krb5_decode_test.c (main): Exit with a non-zero exit status when
+	  	  the test suite detects errors.
+
+	* ktest.c (ktest_destroy_enc_data): Clear the kvno field when
+		destroying the encrypted data.
+
+	* Makefile.in: "make check" depends on krb5_decode_test and
+		krb5_encode_test being up to date.
+
+Tue Oct 18 22:46:17 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* ktest_equal.c (array_compare): Don't segfault if one of the
+		arguments is NULL and the other is not.
+
+	* krb5_decode_test.c (main): Use krb5_init_ets() instead of
+		explicitly naming the error tables to initialize.
+
+	* utility.c (asn1buf_print): Remove unneeded routine.
+
+	* utility.c (krb5_data_hex_parse): Return EINVAL instead of
+		ASN1_PARSE_ERROR if KRB5_USE_ISODE is defined, since the 
+		ASN1 error codes aren't defined in that case.
+
+Fri Oct 14 15:00:41 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Clean up the test.out file.
+
+Fri Oct 14 23:45:01 1994  Theodore Y. Ts'o  (tytso@maytag)
+
+	* configure.in: Add ISODE_DEFS
+
+Thu Oct  6 21:42:27 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Add "make check" test case which runs the test programs.
+
+Tue Oct  4 14:32:39 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* krb5_decode_test.c (setup, decode_run):
+	* krb5_encode_test.c (setup, encode_run): Don't call strcat on a
+		constant string --- you can't modify a read only string!
+
+Thu Sep 29 23:01:58 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executabes when libraries change
+
+Wed Sep 28 16:12:08 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* ktest_equal.c: #include stdio.h to get NULL under sunos.
+
+Tue Sep 20 23:53:13 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Fix typo in utility.c --- we should be freeing the pointer to
+	the passed in pointer, not the passed-in pointer itself.
+
+
diff --git a/mechglue/src/tests/asn.1/Makefile.in b/mechglue/src/tests/asn.1/Makefile.in
new file mode 100644
index 000000000..6a9bbaa56
--- /dev/null
+++ b/mechglue/src/tests/asn.1/Makefile.in
@@ -0,0 +1,95 @@
+thisconfigdir=./..
+myfulldir=tests/asn.1
+mydir=asn.1
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@
+
+SRCS= $(srcdir)/krb5_encode_test.c $(srcdir)/krb5_encode_test.c \
+	$(srcdir)/ktest.c $(srcdir)/ktest_equal.c $(srcdir)/utility.c \
+	$(srcdir)/trval.c
+
+all:: krb5_encode_test krb5_decode_test trval
+
+LOCALINCLUDES = -I$(srcdir)/../../lib/krb5/asn.1
+
+ENCOBJS = krb5_encode_test.o ktest.o ktest_equal.o utility.o trval.o
+
+krb5_encode_test: $(ENCOBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o krb5_encode_test $(ENCOBJS) $(KRB5_BASE_LIBS)
+
+DECOBJS = krb5_decode_test.o ktest.o ktest_equal.o utility.o
+
+krb5_decode_test: $(DECOBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o krb5_decode_test $(DECOBJS) $(KRB5_BASE_LIBS)
+
+trval: $(srcdir)/trval.c
+	$(CC) -o trval $(ALL_CFLAGS) -DSTANDALONE $(srcdir)/trval.c
+
+check:: krb5_decode_test krb5_encode_test
+	KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; \
+		export KRB5_CONFIG ;\
+		$(RUN_SETUP) ./krb5_decode_test
+	$(RM) test.out
+	KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; \
+		export KRB5_CONFIG ;\
+		$(RUN_SETUP) ./krb5_encode_test > test.out
+	cmp test.out $(srcdir)/reference_encode.out
+	KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; \
+		export KRB5_CONFIG ;\
+		$(RUN_SETUP) ./krb5_encode_test -t > test.out
+	cmp test.out $(srcdir)/trval_reference.out
+	$(RM) test.out	
+
+install::
+
+clean::
+	rm -f *~ *.o krb5_encode_test krb5_decode_test test.out trval
+
+
+################ Dependencies ################
+krb5_decode_test.o: ktest.h utility.h ktest_equal.h debug.h
+krb5_encode_test.o: utility.h ktest.h debug.h
+trval.o: trval.c
+ktest.o: ktest.h utility.h
+ktest_equal.o: ktest_equal.h
+#utility.o: utility.h
+#utility.h: krbasn1.h asn1buf.h
+##############################################
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)krb5_encode_test.$(OBJEXT): krb5_encode_test.c \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  utility.h $(SRCTOP)/lib/krb5/asn.1/krbasn1.h $(SRCTOP)/lib/krb5/asn.1/asn1buf.h \
+  ktest.h debug.h
+$(OUTPRE)ktest.$(OBJEXT): ktest.c ktest.h $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h utility.h $(SRCTOP)/lib/krb5/asn.1/krbasn1.h \
+  $(SRCTOP)/lib/krb5/asn.1/asn1buf.h
+$(OUTPRE)ktest_equal.$(OBJEXT): ktest_equal.c ktest_equal.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h
+$(OUTPRE)utility.$(OBJEXT): utility.c utility.h $(SRCTOP)/lib/krb5/asn.1/krbasn1.h \
+  $(SRCTOP)/include/k5-int.h $(BUILDTOP)/include/krb5/osconf.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \
+  $(SRCTOP)/lib/krb5/asn.1/asn1buf.h
+$(OUTPRE)trval.$(OBJEXT): trval.c
diff --git a/mechglue/src/tests/asn.1/README b/mechglue/src/tests/asn.1/README
new file mode 100644
index 000000000..2c0c09809
--- /dev/null
+++ b/mechglue/src/tests/asn.1/README
@@ -0,0 +1,28 @@
+krb5_encode_test runs through all the functions declared in
+ src/include/krb5/asn.1/krb5_encode.h.  It passes various sample
+ inputs to each function and prints the result to standard
+ output.  This output should match the contents of the file
+ "reference_encode.out".
+
+ Each function is first run with a relatively simple, contrived
+ sample structure.  Then if the structure has any optional parts,
+ these parts are cleared and another run is made.
+
+ Some structures (namely, those containing a krb5_kdc_req_body)
+ have a third run, due to the fact that two of the kdc_req_body's
+ optional fields have mutually exclusive conditions under which
+ they may be omitted.
+
+
+krb5_decode_test runs through all the functions declared in
+ src/include/krb5/asn.1/krb5_decode.h.  It has the encodings in
+ reference_encode.out hard-coded into itself.  It sets up the
+ krb5 structures the same way krb5_encode_test does, then passes
+ its hard-coded encoding strings through the krb5 decoders.
+ 
+ The outputs of these functions are compared to the previously
+ set-up structures in memory, and the results are reported to
+ standard output.  If every line comes out prefixed by "OK: ",
+ then the decoders are working properly.  If any decoder produces
+ an anomalous output, then its output line will be prefixed by
+ "ERROR: "
diff --git a/mechglue/src/tests/asn.1/debug.h b/mechglue/src/tests/asn.1/debug.h
new file mode 100644
index 000000000..0929962e7
--- /dev/null
+++ b/mechglue/src/tests/asn.1/debug.h
@@ -0,0 +1,20 @@
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+/*
+   assert utility macro for test programs:
+   If the predicate (pred) is true, then
+   OK: <message> is printed.  Otherwise,
+   ERROR: <message> is printed.
+
+   message should be a printf format string.
+*/
+
+#include <stdio.h>
+
+#define test(pred,message)\
+  if(pred) printf("OK: ");\
+  else { printf("ERROR: "); error_count++; }\
+  printf(message);
+
+#endif
diff --git a/mechglue/src/tests/asn.1/krb5_decode_test.c b/mechglue/src/tests/asn.1/krb5_decode_test.c
new file mode 100644
index 000000000..0ff934354
--- /dev/null
+++ b/mechglue/src/tests/asn.1/krb5_decode_test.c
@@ -0,0 +1,904 @@
+#include "k5-int.h"
+#include "ktest.h"
+#include "com_err.h"
+#include "utility.h"
+#include "ktest_equal.h"
+
+#include "debug.h"
+#include <string.h>
+
+krb5_context test_context;
+int error_count = 0;
+
+void krb5_ktest_free_alt_method(krb5_context context, krb5_alt_method *val);
+void krb5_ktest_free_pwd_sequence(krb5_context context, 
+				  passwd_phrase_element *val);
+void krb5_ktest_free_enc_data(krb5_context context, krb5_enc_data *val);
+
+int main(argc, argv)
+	int argc;
+	char **argv;
+{
+  krb5_data code;
+  krb5_error_code retval;
+  
+  retval = krb5_init_context(&test_context);
+  if (retval) {
+	  com_err(argv[0], retval, "while initializing krb5");
+	  exit(1);
+  }
+  
+
+#define setup(type,typestring,constructor)\
+  type ref, *var;\
+  retval = constructor(&ref);\
+  if(retval){\
+    com_err("krb5_decode_test", retval, "while making sample %s", typestring);\
+    exit(1);\
+  }
+
+#define decode_run(typestring,description,encoding,decoder,comparator,cleanup)\
+    retval = krb5_data_hex_parse(&code,encoding);\
+    if(retval){\
+      com_err("krb5_decode_test", retval, "while parsing %s", typestring);\
+      exit(1);\
+    }\
+    retval = decoder(&code,&var);\
+    if(retval){\
+      com_err("krb5_decode_test", retval, "while decoding %s", typestring);\
+      error_count++;\
+    }\
+    test(comparator(&ref,var),typestring);\
+    printf("%s\n",description);\
+    krb5_free_data_contents(test_context, &code);\
+    cleanup(test_context, var);
+
+  /****************************************************************/
+  /* decode_krb5_authenticator */
+  {
+    setup(krb5_authenticator,"krb5_authenticator",ktest_make_sample_authenticator);
+
+    decode_run("authenticator","","62 81 A1 30 81 9E A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A4 05 02 03 01 E2 40 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A7 03 02 01 11 A8 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72",decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ref.seq_number = 0xffffff80;
+    decode_run("authenticator","(80 -> seq-number 0xffffff80)",
+	       "62 81 A1 30 81 9E"
+	       "   A0 03 02 01 05"
+	       "   A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55"
+	       "   A2 1A 30 18"
+	       "      A0 03 02 01 01"
+	       "      A1 11 30 0F"
+	       "         1B 06 68 66 74 73 61 69"
+	       "         1B 05 65 78 74 72 61"
+	       "   A3 0F 30 0D"
+	       "      A0 03 02 01 01"
+	       "      A1 06 04 04 31 32 33 34"
+	       "   A4 05 02 03 01 E2 40"
+	       "   A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A"
+	       "   A6 13 30 11"
+	       "      A0 03 02 01 01"
+	       "      A1 0A 04 08 31 32 33 34 35 36 37 38"
+	       "   A7 03 02 01 80"
+	       "   A8 24 30 22"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       ,decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ref.seq_number = 0xffffffff;
+    decode_run("authenticator","(FF -> seq-number 0xffffffff)",
+	       "62 81 A1 30 81 9E"
+	       "   A0 03 02 01 05"
+	       "   A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55"
+	       "   A2 1A 30 18"
+	       "      A0 03 02 01 01"
+	       "      A1 11 30 0F"
+	       "         1B 06 68 66 74 73 61 69"
+	       "         1B 05 65 78 74 72 61"
+	       "   A3 0F 30 0D"
+	       "      A0 03 02 01 01"
+	       "      A1 06 04 04 31 32 33 34"
+	       "   A4 05 02 03 01 E2 40"
+	       "   A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A"
+	       "   A6 13 30 11"
+	       "      A0 03 02 01 01"
+	       "      A1 0A 04 08 31 32 33 34 35 36 37 38"
+	       "   A7 03 02 01 FF"
+	       "   A8 24 30 22"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       ,decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ref.seq_number = 0xff;
+    decode_run("authenticator","(00FF -> seq-number 0xff)",
+	       "62 81 A2 30 81 9F"
+	       "   A0 03 02 01 05"
+	       "   A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55"
+	       "   A2 1A 30 18"
+	       "      A0 03 02 01 01"
+	       "      A1 11 30 0F"
+	       "         1B 06 68 66 74 73 61 69"
+	       "         1B 05 65 78 74 72 61"
+	       "   A3 0F 30 0D"
+	       "      A0 03 02 01 01"
+	       "      A1 06 04 04 31 32 33 34"
+	       "   A4 05 02 03 01 E2 40"
+	       "   A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A"
+	       "   A6 13 30 11"
+	       "      A0 03 02 01 01"
+	       "      A1 0A 04 08 31 32 33 34 35 36 37 38"
+	       "   A7 04 02 02 00 FF"
+	       "   A8 24 30 22"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       ,decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ref.seq_number = 0xffffffff;
+    decode_run("authenticator","(00FFFFFFFF -> seq-number 0xffffffff)",
+	       "62 81 A5 30 81 A2"
+	       "   A0 03 02 01 05"
+	       "   A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55"
+	       "   A2 1A 30 18"
+	       "      A0 03 02 01 01"
+	       "      A1 11 30 0F"
+	       "         1B 06 68 66 74 73 61 69"
+	       "         1B 05 65 78 74 72 61"
+	       "   A3 0F 30 0D"
+	       "      A0 03 02 01 01"
+	       "      A1 06 04 04 31 32 33 34"
+	       "   A4 05 02 03 01 E2 40"
+	       "   A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A"
+	       "   A6 13 30 11"
+	       "      A0 03 02 01 01"
+	       "      A1 0A 04 08 31 32 33 34 35 36 37 38"
+	       "   A7 07 02 05 00 FF FF FF FF"
+	       "   A8 24 30 22"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       ,decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ref.seq_number = 0x7fffffff;
+    decode_run("authenticator","(7FFFFFFF -> seq-number 0x7fffffff)",
+	       "62 81 A4 30 81 A1"
+	       "   A0 03 02 01 05"
+	       "   A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55"
+	       "   A2 1A 30 18"
+	       "      A0 03 02 01 01"
+	       "      A1 11 30 0F"
+	       "         1B 06 68 66 74 73 61 69"
+	       "         1B 05 65 78 74 72 61"
+	       "   A3 0F 30 0D"
+	       "      A0 03 02 01 01"
+	       "      A1 06 04 04 31 32 33 34"
+	       "   A4 05 02 03 01 E2 40"
+	       "   A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A"
+	       "   A6 13 30 11"
+	       "      A0 03 02 01 01"
+	       "      A1 0A 04 08 31 32 33 34 35 36 37 38"
+	       "   A7 06 02 04 7F FF FF FF"
+	       "   A8 24 30 22"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       ,decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ref.seq_number = 0xffffffff;
+    decode_run("authenticator","(FFFFFFFF -> seq-number 0xffffffff)",
+	       "62 81 A4 30 81 A1"
+	       "   A0 03 02 01 05"
+	       "   A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55"
+	       "   A2 1A 30 18"
+	       "      A0 03 02 01 01"
+	       "      A1 11 30 0F"
+	       "         1B 06 68 66 74 73 61 69"
+	       "         1B 05 65 78 74 72 61"
+	       "   A3 0F 30 0D"
+	       "      A0 03 02 01 01"
+	       "      A1 06 04 04 31 32 33 34"
+	       "   A4 05 02 03 01 E2 40"
+	       "   A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A"
+	       "   A6 13 30 11"
+	       "      A0 03 02 01 01"
+	       "      A1 0A 04 08 31 32 33 34 35 36 37 38"
+	       "   A7 06 02 04 FF FF FF FF"
+	       "   A8 24 30 22"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       "      30 0F"
+	       "         A0 03 02 01 01"
+	       "         A1 08 04 06 66 6F 6F 62 61 72"
+	       ,decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ktest_destroy_checksum(&(ref.checksum));
+    ktest_destroy_keyblock(&(ref.subkey));
+    ref.seq_number = 0;
+    ktest_empty_authorization_data(ref.authorization_data);
+    decode_run("authenticator","(optionals empty)","62 4F 30 4D A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 05 02 03 01 E2 40 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ktest_destroy_authorization_data(&(ref.authorization_data));
+    
+    decode_run("authenticator","(optionals NULL)","62 4F 30 4D A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 05 02 03 01 E2 40 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_authenticator,ktest_equal_authenticator,krb5_free_authenticator);
+
+    ktest_empty_authenticator(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_ticket */
+  {
+    setup(krb5_ticket,"krb5_ticket",ktest_make_sample_ticket);
+    decode_run("ticket","","61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_ticket,ktest_equal_ticket,krb5_free_ticket);
+    decode_run("ticket","(+ trailing [4] INTEGER","61 61 30 5F A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A4 03 02 01 01",decode_krb5_ticket,ktest_equal_ticket,krb5_free_ticket);
+
+/*
+  "61 80 30 80 "
+  "  A0 03 02 01 05 "
+  "  A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 "
+  "  A2 80 30 80 "
+  "    A0 03 02 01 01 "
+  "    A1 80 30 80 "
+  "      1B 06 68 66 74 73 61 69 "
+  "      1B 05 65 78 74 72 61 "
+  "    00 00 00 00 "
+  "  00 00 00 00 "
+  "  A3 80 30 80 "
+  "    A0 03 02 01 00 "
+  "    A1 03 02 01 05 "
+  "    A2 17 04 15 6B 72 62 41 53 4E 2E 31 "
+  "      20 74 65 73 74 20 6D 65 73 73 61 67 65 "
+  "  00 00 00 00"
+  "00 00 00 00"
+*/
+    decode_run("ticket","(indefinite lengths)", "61 80 30 80 A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 80 30 80 A0 03 02 01 01 A1 80 30 80 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 00 00 00 00 00 00 00 00 A3 80 30 80 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 00 00 00 00 00 00 00 00" ,decode_krb5_ticket,ktest_equal_ticket,krb5_free_ticket);
+/*
+  "61 80 30 80 "
+  "  A0 03 02 01 05 "
+  "  A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 "
+  "  A2 80 30 80 "
+  "    A0 03 02 01 01 "
+  "    A1 80 30 80 "
+  "      1B 06 68 66 74 73 61 69 "
+  "      1B 05 65 78 74 72 61 "
+  "    00 00 00 00 "
+  "  00 00 00 00 "
+  "  A3 80 30 80 "
+  "    A0 03 02 01 00 "
+  "    A1 03 02 01 05 "
+  "    A2 17 04 15 6B 72 62 41 53 4E 2E 31 "
+  "      20 74 65 73 74 20 6D 65 73 73 61 67 65 "
+  "  00 00 00 00"
+  "  A4 03 02 01 01 "
+  "00 00 00 00"
+*/
+    decode_run("ticket","(indefinite lengths + trailing [4] INTEGER)", "61 80 30 80 A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 80 30 80 A0 03 02 01 01 A1 80 30 80 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 00 00 00 00 00 00 00 00 A3 80 30 80 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 00 00 00 00 A4 03 02 01 01 00 00 00 00",decode_krb5_ticket,ktest_equal_ticket,krb5_free_ticket);
+
+    ktest_empty_ticket(&ref);
+
+  }
+
+  /****************************************************************/
+  /* decode_krb5_encryption_key */
+  {
+    setup(krb5_keyblock,"krb5_keyblock",ktest_make_sample_keyblock);
+
+    decode_run("encryption_key","","30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+
+    decode_run("encryption_key","(+ trailing [2] INTEGER)","30 16 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 03 02 01 01",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    decode_run("encryption_key","(+ trailing [2] SEQUENCE {[0] INTEGER})","30 1A A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 07 30 05 A0 03 02 01 01",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    decode_run("encryption_key","(indefinite lengths)","30 80 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 00 00",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    decode_run("encryption_key","(indefinite lengths + trailing [2] INTEGER)","30 80 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 03 02 01 01 00 00",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    decode_run("encryption_key","(indefinite lengths + trailing [2] SEQUENCE {[0] INTEGER})","30 80 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 80 30 80 A0 03 02 01 01 00 00 00 00 00 00",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    decode_run("encryption_key","(indefinite lengths + trailing SEQUENCE {[0] INTEGER})","30 80 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 30 80 A0 03 02 01 01 00 00 00 00",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    ref.enctype = -1;
+    decode_run("encryption_key","(enctype = -1)","30 11 A0 03 02 01 FF A1 0A 04 08 31 32 33 34 35 36 37 38",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    ref.enctype = -255;
+    decode_run("encryption_key","(enctype = -255)","30 12 A0 04 02 02 FF 01 A1 0A 04 08 31 32 33 34 35 36 37 38",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    ref.enctype = 255;
+    decode_run("encryption_key","(enctype = 255)","30 12 A0 04 02 02 00 FF A1 0A 04 08 31 32 33 34 35 36 37 38",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    ref.enctype = -2147483648;
+    decode_run("encryption_key","(enctype = -2147483648)","30 14 A0 06 02 04 80 00 00 00 A1 0A 04 08 31 32 33 34 35 36 37 38",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+    ref.enctype = 2147483647;
+    decode_run("encryption_key","(enctype = 2147483647)","30 14 A0 06 02 04 7F FF FF FF A1 0A 04 08 31 32 33 34 35 36 37 38",decode_krb5_encryption_key,ktest_equal_encryption_key,krb5_free_keyblock);
+
+    ktest_empty_keyblock(&ref);
+  }  
+  
+  /****************************************************************/
+  /* decode_krb5_enc_tkt_part */
+  {
+    setup(krb5_enc_tkt_part,"krb5_enc_tkt_part",ktest_make_sample_enc_tkt_part);
+    decode_run("enc_tkt_part","","63 82 01 14 30 82 01 10 A0 07 03 05 00 FE DC BA 98 A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 2E 30 2C A0 03 02 01 01 A1 25 04 23 45 44 55 2C 4D 49 54 2E 2C 41 54 48 45 4E 41 2E 2C 57 41 53 48 49 4E 47 54 4F 4E 2E 45 44 55 2C 43 53 2E A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72",decode_krb5_enc_tkt_part,ktest_equal_enc_tkt_part,krb5_free_enc_tkt_part);
+  
+    /* ref.times.starttime = 0; */
+    ref.times.starttime = ref.times.authtime;
+    ref.times.renew_till = 0;
+    ktest_destroy_address(&(ref.caddrs[1]));
+    ktest_destroy_address(&(ref.caddrs[0]));
+    ktest_destroy_authdata(&(ref.authorization_data[1]));
+    ktest_destroy_authdata(&(ref.authorization_data[0]));
+    /* ISODE version fails on the empty caddrs field */
+    ktest_destroy_addresses(&(ref.caddrs));
+    ktest_destroy_authorization_data(&(ref.authorization_data));
+  
+    decode_run("enc_tkt_part","(optionals NULL)","63 81 A5 30 81 A2 A0 07 03 05 00 FE DC BA 98 A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 2E 30 2C A0 03 02 01 01 A1 25 04 23 45 44 55 2C 4D 49 54 2E 2C 41 54 48 45 4E 41 2E 2C 57 41 53 48 49 4E 47 54 4F 4E 2E 45 44 55 2C 43 53 2E A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_enc_tkt_part,ktest_equal_enc_tkt_part, krb5_free_enc_tkt_part);
+
+    decode_run("enc_tkt_part","(optionals NULL + bitstring enlarged to 38 bits)","63 81 A6 30 81 A3 A0 08 03 06 02 FE DC BA 98 DC A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 2E 30 2C A0 03 02 01 01 A1 25 04 23 45 44 55 2C 4D 49 54 2E 2C 41 54 48 45 4E 41 2E 2C 57 41 53 48 49 4E 47 54 4F 4E 2E 45 44 55 2C 43 53 2E A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_enc_tkt_part,ktest_equal_enc_tkt_part,krb5_free_enc_tkt_part);
+
+    decode_run("enc_tkt_part","(optionals NULL + bitstring enlarged to 40 bits)","63 81 A6 30 81 A3 A0 08 03 06 00 FE DC BA 98 DE A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 2E 30 2C A0 03 02 01 01 A1 25 04 23 45 44 55 2C 4D 49 54 2E 2C 41 54 48 45 4E 41 2E 2C 57 41 53 48 49 4E 47 54 4F 4E 2E 45 44 55 2C 43 53 2E A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_enc_tkt_part,ktest_equal_enc_tkt_part,krb5_free_enc_tkt_part);
+
+    decode_run("enc_tkt_part","(optionals NULL + bitstring reduced to 29 bits)","63 81 A5 30 81 A2 A0 07 03 05 03 FE DC BA 98 A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 2E 30 2C A0 03 02 01 01 A1 25 04 23 45 44 55 2C 4D 49 54 2E 2C 41 54 48 45 4E 41 2E 2C 57 41 53 48 49 4E 47 54 4F 4E 2E 45 44 55 2C 43 53 2E A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_enc_tkt_part,ktest_equal_enc_tkt_part,krb5_free_enc_tkt_part);
+
+    ref.flags &= 0xFFFFFF00;
+
+    decode_run("enc_tkt_part","(optionals NULL + bitstring reduced to 24 bits)","63 81 A4 30 81 A1 A0 06 03 04 00 FE DC BA A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 2E 30 2C A0 03 02 01 01 A1 25 04 23 45 44 55 2C 4D 49 54 2E 2C 41 54 48 45 4E 41 2E 2C 57 41 53 48 49 4E 47 54 4F 4E 2E 45 44 55 2C 43 53 2E A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_enc_tkt_part,ktest_equal_enc_tkt_part,krb5_free_enc_tkt_part);
+
+    ktest_empty_enc_tkt_part(&ref);
+  }  
+  
+  /****************************************************************/
+  /* decode_krb5_enc_kdc_rep_part */
+  {
+    setup(krb5_enc_kdc_rep_part,"krb5_enc_kdc_rep_part",ktest_make_sample_enc_kdc_rep_part);
+  
+#ifdef KRB5_GENEROUS_LR_TYPE
+    decode_run("enc_kdc_rep_part","(compat_lr_type)","7A 82 01 10 30 82 01 0C A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 38 30 36 30 19 A0 04 02 02 00 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 30 19 A0 04 02 02 00 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A4 07 03 05 00 FE DC BA 98 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AB 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23",decode_krb5_enc_kdc_rep_part,ktest_equal_enc_kdc_rep_part,krb5_free_enc_kdc_rep_part);
+#endif
+  
+    decode_run("enc_kdc_rep_part","","7A 82 01 0E 30 82 01 0A A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 36 30 34 30 18 A0 03 02 01 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 30 18 A0 03 02 01 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A4 07 03 05 00 FE DC BA 98 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AB 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23",decode_krb5_enc_kdc_rep_part,ktest_equal_enc_kdc_rep_part,krb5_free_enc_kdc_rep_part);
+  
+    ref.key_exp = 0;
+    /* ref.times.starttime = 0;*/
+    ref.times.starttime = ref.times.authtime;
+    ref.times.renew_till = 0;
+    ref.flags &= ~TKT_FLG_RENEWABLE;
+    ktest_destroy_addresses(&(ref.caddrs));
+  
+#ifdef KRB5_GENEROUS_LR_TYPE
+    decode_run("enc_kdc_rep_part","(optionals NULL)(compat lr_type)","7A 81 B4 30 81 B1 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 38 30 36 30 19 A0 04 02 02 00 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 30 19 A0 04 02 02 00 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A4 07 03 05 00 FE 5C BA 98 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61",decode_krb5_enc_kdc_rep_part,ktest_equal_enc_kdc_rep_part,krb5_free_enc_kdc_rep_part);
+#endif
+
+    decode_run("enc_kdc_rep_part","(optionals NULL)","7A 81 B2 30 81 AF A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 36 30 34 30 18 A0 03 02 01 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 30 18 A0 03 02 01 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A4 07 03 05 00 FE 5C BA 98 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61",decode_krb5_enc_kdc_rep_part,ktest_equal_enc_kdc_rep_part,krb5_free_enc_kdc_rep_part);
+
+    ktest_empty_enc_kdc_rep_part(&ref);
+  }  
+
+  /****************************************************************/
+  /* decode_krb5_as_rep */
+  {
+    setup(krb5_kdc_rep,"krb5_kdc_rep",ktest_make_sample_kdc_rep);
+    ref.msg_type = KRB5_AS_REP;
+
+    decode_run("as_rep","","6B 81 EA 30 81 E7 A0 03 02 01 05 A1 03 02 01 0B A2 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A6 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_as_rep,ktest_equal_as_rep,krb5_free_kdc_rep);
+
+/*
+  6B 80 30 80
+    A0 03 02 01 05
+    A1 03 02 01 0B
+    A2 80 30 80
+      30 80
+	A1 03 02 01 0D
+	A2 09 04 07 70 61 2D 64 61 74 61
+      00 00
+      30 80
+	A1 03 02 01 0D
+	A2 09 04 07 70 61 2D 64 61 74 61
+      00 00
+    00 00 00 00
+    A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55
+    A4 80 30 80
+      A0 03 02 01 01
+      A1 80 30 80
+	1B 06 68 66 74 73 61 69
+	1B 05 65 78 74 72 61
+      00 00 00 00
+    00 00 00 00
+    A5 80 61 80 30 80
+      A0 03 02 01 05
+      A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55
+      A2 80 30 80
+	A0 03 02 01 01
+	A1 80 30 80
+	  1B 06 68 66 74 73 61 69
+	  1B 05 65 78 74 72 61
+	00 00 00 00
+      00 00 00 00
+      A3 80 30 80
+	A0 03 02 01 00
+	A1 03 02 01 05
+	A2 17 04 15 6B 72 62 41 53 4E 2E 31
+	  20 74 65 73 74 20 6D 65
+	  73 73 61 67 65
+      00 00 00 00
+    00 00 00 00 00 00
+    A6 80 30 80
+      A0 03 02 01 00
+      A1 03 02 01 05
+      A2 17 04 15 6B 72 62 41 53 4E 2E 31
+	20 74 65 73 74 20 6D 65
+	73 73 61 67 65
+    00 00 00 00
+  00 00 00 00
+*/
+    decode_run("as_rep","(indefinite lengths)","6B 80 30 80 A0 03 02 01 05 A1 03 02 01 0B A2 80 30 80 30 80 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 00 00 30 80 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 00 00 00 00 00 00 A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 80 30 80 A0 03 02 01 01 A1 80 30 80 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 00 00 00 00 00 00 00 00 A5 80 61 80 30 80 A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 80 30 80 A0 03 02 01 01 A1 80 30 80 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 00 00 00 00 00 00 00 00 A3 80 30 80 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 00 00 00 00 00 00 00 00 00 00 A6 80 30 80 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 00 00 00 00 00 00 00 00",decode_krb5_as_rep,ktest_equal_as_rep,krb5_free_kdc_rep);
+    ktest_destroy_pa_data_array(&(ref.padata));
+    decode_run("as_rep","(optionals NULL)","6B 81 C2 30 81 BF A0 03 02 01 05 A1 03 02 01 0B A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A6 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_as_rep,ktest_equal_as_rep,krb5_free_kdc_rep);
+
+  ktest_empty_kdc_rep(&ref);
+  }  
+  
+  /****************************************************************/
+  /* decode_krb5_tgs_rep */
+  {
+    setup(krb5_kdc_rep,"krb5_kdc_rep",ktest_make_sample_kdc_rep);
+    ref.msg_type = KRB5_TGS_REP;
+
+    decode_run("tgs_rep","","6D 81 EA 30 81 E7 A0 03 02 01 05 A1 03 02 01 0D A2 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A6 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_tgs_rep,ktest_equal_tgs_rep,krb5_free_kdc_rep);
+
+    ktest_destroy_pa_data_array(&(ref.padata));
+    decode_run("tgs_rep","(optionals NULL)","6D 81 C2 30 81 BF A0 03 02 01 05 A1 03 02 01 0D A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A6 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_tgs_rep,ktest_equal_tgs_rep,krb5_free_kdc_rep);
+
+  ktest_empty_kdc_rep(&ref);
+  }  
+  
+  /****************************************************************/
+  /* decode_krb5_ap_req */
+  {
+    setup(krb5_ap_req,"krb5_ap_req",ktest_make_sample_ap_req);
+    decode_run("ap_req","","6E 81 9D 30 81 9A A0 03 02 01 05 A1 03 02 01 0E A2 07 03 05 00 FE DC BA 98 A3 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A4 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_ap_req,ktest_equal_ap_req,krb5_free_ap_req);
+    ktest_empty_ap_req(&ref);
+
+  }  
+
+  /****************************************************************/
+  /* decode_krb5_ap_rep */
+  {
+    setup(krb5_ap_rep,"krb5_ap_rep",ktest_make_sample_ap_rep);
+    decode_run("ap_rep","","6F 33 30 31 A0 03 02 01 05 A1 03 02 01 0F A2 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_ap_rep,ktest_equal_ap_rep,krb5_free_ap_rep);
+    ktest_empty_ap_rep(&ref);
+  }  
+
+  /****************************************************************/
+  /* decode_krb5_ap_rep_enc_part */
+  {
+    setup(krb5_ap_rep_enc_part,"krb5_ap_rep_enc_part",ktest_make_sample_ap_rep_enc_part);
+
+    decode_run("ap_rep_enc_part","","7B 36 30 34 A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A1 05 02 03 01 E2 40 A2 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A3 03 02 01 11",decode_krb5_ap_rep_enc_part,ktest_equal_ap_rep_enc_part,krb5_free_ap_rep_enc_part);
+  
+    ktest_destroy_keyblock(&(ref.subkey));
+    ref.seq_number = 0;
+    decode_run("ap_rep_enc_part","(optionals NULL)","7B 1C 30 1A A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A1 05 02 03 01 E2 40",decode_krb5_ap_rep_enc_part,ktest_equal_ap_rep_enc_part,krb5_free_ap_rep_enc_part);
+    ktest_empty_ap_rep_enc_part(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_as_req */
+  {
+    setup(krb5_kdc_req,"krb5_kdc_req",ktest_make_sample_kdc_req);
+    ref.msg_type = KRB5_AS_REQ;
+
+    ref.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    decode_run("as_req","","6A 82 01 E4 30 82 01 E0 A1 03 02 01 05 A2 03 02 01 0A A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 82 01 AA 30 82 01 A6 A0 07 03 05 00 FE DC BA 90 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_as_req,ktest_equal_as_req,krb5_free_kdc_req);
+
+    ktest_destroy_pa_data_array(&(ref.padata));
+    ktest_destroy_principal(&(ref.client));
+#ifndef ISODE_SUCKS
+    ktest_destroy_principal(&(ref.server));
+#endif
+    ref.kdc_options |= KDC_OPT_ENC_TKT_IN_SKEY;
+    ref.from = 0;
+    ref.rtime = 0;
+    ktest_destroy_addresses(&(ref.addresses));
+    ktest_destroy_enc_data(&(ref.authorization_data));
+    decode_run("as_req","(optionals NULL except second_ticket)","6A 82 01 14 30 82 01 10 A1 03 02 01 05 A2 03 02 01 0A A4 82 01 02 30 81 FF A0 07 03 05 00 FE DC BA 98 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_as_req,ktest_equal_as_req,krb5_free_kdc_req);
+    ktest_destroy_sequence_of_ticket(&(ref.second_ticket));
+#ifndef ISODE_SUCKS
+    ktest_make_sample_principal(&(ref.server));
+#endif
+    ref.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    decode_run("as_req","(optionals NULL except server)","6A 69 30 67 A1 03 02 01 05 A2 03 02 01 0A A4 5B 30 59 A0 07 03 05 00 FE DC BA 90 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01",decode_krb5_as_req,ktest_equal_as_req,krb5_free_kdc_req);
+
+  ktest_empty_kdc_req(&ref);
+
+  }
+
+  
+  /****************************************************************/
+  /* decode_krb5_tgs_req */
+  {
+    setup(krb5_kdc_req,"krb5_kdc_req",ktest_make_sample_kdc_req);
+    ref.msg_type = KRB5_TGS_REQ;
+
+    ref.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    decode_run("tgs_req","","6C 82 01 E4 30 82 01 E0 A1 03 02 01 05 A2 03 02 01 0C A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 82 01 AA 30 82 01 A6 A0 07 03 05 00 FE DC BA 90 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_tgs_req,ktest_equal_tgs_req,krb5_free_kdc_req);
+
+    ktest_destroy_pa_data_array(&(ref.padata));
+    ktest_destroy_principal(&(ref.client));
+#ifndef ISODE_SUCKS
+    ktest_destroy_principal(&(ref.server));
+#endif
+    ref.kdc_options |= KDC_OPT_ENC_TKT_IN_SKEY;
+    ref.from = 0;
+    ref.rtime = 0;
+    ktest_destroy_addresses(&(ref.addresses));
+    ktest_destroy_enc_data(&(ref.authorization_data));
+    decode_run("tgs_req","(optionals NULL except second_ticket)","6C 82 01 14 30 82 01 10 A1 03 02 01 05 A2 03 02 01 0C A4 82 01 02 30 81 FF A0 07 03 05 00 FE DC BA 98 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_tgs_req,ktest_equal_tgs_req,krb5_free_kdc_req);
+
+    ktest_destroy_sequence_of_ticket(&(ref.second_ticket));
+#ifndef ISODE_SUCKS
+    ktest_make_sample_principal(&(ref.server));
+#endif
+    ref.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    decode_run("tgs_req","(optionals NULL except server)","6C 69 30 67 A1 03 02 01 05 A2 03 02 01 0C A4 5B 30 59 A0 07 03 05 00 FE DC BA 90 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01",decode_krb5_tgs_req,ktest_equal_tgs_req,krb5_free_kdc_req);
+
+    ktest_empty_kdc_req(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_kdc_req_body */
+  {
+    krb5_kdc_req ref, *var;
+    memset(&ref, 0, sizeof(krb5_kdc_req));
+    retval = ktest_make_sample_kdc_req_body(&ref);
+    if(retval){
+      com_err("making sample kdc_req_body",retval,"");
+      exit(1);
+    }
+    ref.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    decode_run("kdc_req_body","","30 82 01 A6 A0 07 03 05 00 FE DC BA 90 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_kdc_req_body,ktest_equal_kdc_req_body,krb5_free_kdc_req);
+
+    ktest_destroy_principal(&(ref.client));
+#ifndef ISODE_SUCKS
+    ktest_destroy_principal(&(ref.server));
+#endif
+    ref.kdc_options |= KDC_OPT_ENC_TKT_IN_SKEY;
+    ref.from = 0;
+    ref.rtime = 0;
+    ktest_destroy_addresses(&(ref.addresses));
+    ktest_destroy_enc_data(&(ref.authorization_data));
+    decode_run("kdc_req_body","(optionals NULL except second_ticket)","30 81 FF A0 07 03 05 00 FE DC BA 98 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_kdc_req_body,ktest_equal_kdc_req_body,krb5_free_kdc_req);
+
+    ktest_destroy_sequence_of_ticket(&(ref.second_ticket));
+#ifndef ISODE_SUCKS
+    ktest_make_sample_principal(&(ref.server));
+#endif
+    ref.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    decode_run("kdc_req_body","(optionals NULL except server)","30 59 A0 07 03 05 00 FE DC BA 90 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01",decode_krb5_kdc_req_body,ktest_equal_kdc_req_body,krb5_free_kdc_req);
+    ref.nktypes = 0;
+    free(ref.ktype);
+    ref.ktype = NULL;
+    decode_run("kdc_req_body","(optionals NULL except server; zero-length etypes)","30 53 A0 07 03 05 00 FE DC BA 90 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 02 30 00",decode_krb5_kdc_req_body,ktest_equal_kdc_req_body,krb5_free_kdc_req);
+
+    ktest_empty_kdc_req(&ref);
+  }
+
+  
+  /****************************************************************/
+  /* decode_krb5_safe */
+  {
+    setup(krb5_safe,"krb5_safe",ktest_make_sample_safe);
+    decode_run("safe","","74 6E 30 6C A0 03 02 01 05 A1 03 02 01 14 A2 4F 30 4D A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 05 02 03 01 E2 40 A3 03 02 01 11 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A5 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A3 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34",decode_krb5_safe,ktest_equal_safe,krb5_free_safe);
+
+    ref.timestamp = 0;
+    ref.usec = 0;
+    ref.seq_number = 0;
+    ktest_destroy_address(&(ref.r_address));
+    decode_run("safe","(optionals NULL)","74 3E 30 3C A0 03 02 01 05 A1 03 02 01 14 A2 1F 30 1D A0 0A 04 08 6B 72 62 35 64 61 74 61 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A3 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34",decode_krb5_safe,ktest_equal_safe,krb5_free_safe);
+
+    ktest_empty_safe(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_priv */
+  {
+    setup(krb5_priv,"krb5_priv",ktest_make_sample_priv);
+    decode_run("priv","","75 33 30 31 A0 03 02 01 05 A1 03 02 01 15 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_priv,ktest_equal_priv,krb5_free_priv);
+    ktest_empty_priv(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_enc_priv_part */
+  {
+    setup(krb5_priv_enc_part,"krb5_priv_enc_part",ktest_make_sample_priv_enc_part);
+    decode_run("enc_priv_part","","7C 4F 30 4D A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 05 02 03 01 E2 40 A3 03 02 01 11 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A5 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23",decode_krb5_enc_priv_part,ktest_equal_enc_priv_part,krb5_free_priv_enc_part);
+
+    ref.timestamp = 0;
+    ref.usec = 0;
+    ref.seq_number = 0;
+    ktest_destroy_address(&(ref.r_address));
+    decode_run("enc_priv_part","(optionals NULL)","7C 1F 30 1D A0 0A 04 08 6B 72 62 35 64 61 74 61 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23",decode_krb5_enc_priv_part,ktest_equal_enc_priv_part,krb5_free_priv_enc_part);
+    ktest_empty_priv_enc_part(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_cred */
+  {
+    setup(krb5_cred,"krb5_cred",ktest_make_sample_cred);
+    decode_run("cred","","76 81 F6 30 81 F3 A0 03 02 01 05 A1 03 02 01 16 A2 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_cred,ktest_equal_cred,krb5_free_cred);
+    ktest_empty_cred(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_enc_cred_part */
+  {
+    setup(krb5_cred_enc_part,"krb5_cred_enc_part",ktest_make_sample_cred_enc_part);
+    decode_run("enc_cred_part","","7D 82 02 23 30 82 02 1F A0 82 01 DA 30 82 01 D6 30 81 E8 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 07 03 05 00 FE DC BA 98 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A9 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AA 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 81 E8 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 07 03 05 00 FE DC BA 98 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A9 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AA 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A1 03 02 01 2A A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A3 05 02 03 01 E2 40 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A5 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23",decode_krb5_enc_cred_part,ktest_equal_enc_cred_part,krb5_free_cred_enc_part);
+    /* free_cred_enc_part does not free the pointer */
+    krb5_xfree(var);
+    ktest_destroy_principal(&(ref.ticket_info[0]->client));
+    ktest_destroy_principal(&(ref.ticket_info[0]->server));
+    ref.ticket_info[0]->flags = 0;
+    ref.ticket_info[0]->times.authtime = 0;
+    ref.ticket_info[0]->times.starttime = 0;
+    ref.ticket_info[0]->times.endtime = 0;
+    ref.ticket_info[0]->times.renew_till = 0;
+    ktest_destroy_addresses(&(ref.ticket_info[0]->caddrs));
+    ref.nonce = 0;
+    ref.timestamp = 0;
+    ref.usec = 0;
+    ktest_destroy_address(&(ref.s_address));
+    ktest_destroy_address(&(ref.r_address));
+    decode_run("enc_cred_part","(optionals NULL)","7D 82 01 0E 30 82 01 0A A0 82 01 06 30 82 01 02 30 15 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 30 81 E8 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 07 03 05 00 FE DC BA 98 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A9 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AA 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23",decode_krb5_enc_cred_part,ktest_equal_enc_cred_part,krb5_free_cred_enc_part);
+    /* free_cred_enc_part does not free the pointer */
+    krb5_xfree(var);
+
+    ktest_empty_cred_enc_part(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_error */
+  {
+    setup(krb5_error,"krb5_error",ktest_make_sample_error);
+    decode_run("error","","7E 81 BA 30 81 B7 A0 03 02 01 05 A1 03 02 01 1E A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A3 05 02 03 01 E2 40 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 05 02 03 01 E2 40 A6 03 02 01 3C A7 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A8 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AB 0A 1B 08 6B 72 62 35 64 61 74 61 AC 0A 04 08 6B 72 62 35 64 61 74 61",decode_krb5_error,ktest_equal_error,krb5_free_error);
+
+    ref.ctime = 0;
+    ktest_destroy_principal(&(ref.client));
+    ktest_empty_data(&(ref.text));
+    ktest_empty_data(&(ref.e_data));
+    decode_run("error","(optionals NULL)","7E 60 30 5E A0 03 02 01 05 A1 03 02 01 1E A3 05 02 03 01 E2 40 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 05 02 03 01 E2 40 A6 03 02 01 3C A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61",decode_krb5_error,ktest_equal_error,krb5_free_error);
+
+    ktest_empty_error(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_authdata */
+  {
+    krb5_authdata **ref, **var;
+    retval = ktest_make_sample_authorization_data(&ref);
+    if(retval){
+      com_err("making sample authorization_data",retval,"");
+      exit(1);
+    }
+    retval = krb5_data_hex_parse(&code,"30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72");
+    if(retval){
+      com_err("parsing authorization_data",retval,"");
+      exit(1);
+    }
+    retval = decode_krb5_authdata(&code,&var);
+    if(retval) com_err("decoding authorization_data",retval,"");
+    test(ktest_equal_authorization_data(ref,var),"authorization_data\n")
+    krb5_free_data_contents(test_context, &code);
+    krb5_free_authdata(test_context, var);
+    ktest_destroy_authorization_data(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_pwd_sequence */
+  {
+    setup(passwd_phrase_element,"passwd_phrase_element",ktest_make_sample_passwd_phrase_element);
+    decode_run("PasswdSequence","","30 18 A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61",decode_krb5_pwd_sequence,ktest_equal_passwd_phrase_element,krb5_ktest_free_pwd_sequence);
+    ktest_empty_passwd_phrase_element(&ref);
+  }
+
+  /****************************************************************/
+  /* decode_passwd_data */
+  {
+    setup(krb5_pwd_data,"krb5_pwd_data",ktest_make_sample_krb5_pwd_data);
+    decode_run("PasswdData","","30 3D A0 03 02 01 02 A1 36 30 34 30 18 A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61 30 18 A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61",decode_krb5_pwd_data,ktest_equal_krb5_pwd_data,krb5_free_pwd_data);
+    ktest_empty_pwd_data(&ref);
+  }
+
+  /****************************************************************/
+  /* decode_krb5_padata_sequence */
+  {
+    krb5_pa_data **ref, **var;
+    retval = ktest_make_sample_pa_data_array(&ref);
+    if(retval){
+      com_err("making sample pa_data array",retval,"");
+      exit(1);
+    }
+    retval = krb5_data_hex_parse(&code,"30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61");
+    if(retval){
+      com_err("parsing padata_sequence",retval,"");
+      exit(1);
+    }
+    retval = decode_krb5_padata_sequence(&code,&var);
+    if(retval) com_err("decoding padata_sequence",retval,"");
+    test(ktest_equal_sequence_of_pa_data(ref,var),"pa_data\n");
+    krb5_free_pa_data(test_context, var);
+    krb5_free_data_contents(test_context, &code);
+    ktest_destroy_pa_data_array(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_krb5_padata_sequence (empty) */
+  {
+    krb5_pa_data **ref, **var;
+    retval = ktest_make_sample_empty_pa_data_array(&ref);
+    if(retval){
+      com_err("making sample empty pa_data array",retval,"");
+      exit(1);
+    }
+    retval = krb5_data_hex_parse(&code,"30 00");
+    if(retval){
+      com_err("parsing padata_sequence (empty)",retval,"");
+      exit(1);
+    }
+    retval = decode_krb5_padata_sequence(&code,&var);
+    if(retval) com_err("decoding padata_sequence (empty)",retval,"");
+    test(ktest_equal_sequence_of_pa_data(ref,var),"pa_data (empty)\n");
+    krb5_free_pa_data(test_context, var);
+    krb5_free_data_contents(test_context, &code);
+    ktest_destroy_pa_data_array(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_pwd_sequence */
+  {
+    setup(krb5_alt_method,"krb5_alt_method",ktest_make_sample_alt_method);
+    decode_run("alt_method","","30 0F A0 03 02 01 2A A1 08 04 06 73 65 63 72 65 74",decode_krb5_alt_method,ktest_equal_krb5_alt_method,krb5_ktest_free_alt_method);
+    ref.length = 0;
+    decode_run("alt_method (no data)","","30 05 A0 03 02 01 2A",decode_krb5_alt_method,ktest_equal_krb5_alt_method,krb5_ktest_free_alt_method);
+    ktest_empty_alt_method(&ref);
+  }
+
+  /****************************************************************/
+  /* decode_etype_info */
+  {
+      krb5_etype_info ref, var;
+
+      retval = ktest_make_sample_etype_info(&ref);
+      if (retval) {
+	  com_err("krb5_decode_test", retval,
+		  "while making sample etype info");
+	  exit(1);
+      }
+      retval = krb5_data_hex_parse(&code,"30 33 30 14 A0 03 02 01 00 A1 0D 04 0B 4D 6F 72 74 6F 6E 27 73 20 23 30 30 05 A0 03 02 01 01 30 14 A0 03 02 01 02 A1 0D 04 0B 4D 6F 72 74 6F 6E 27 73 20 23 32");
+      if(retval){
+	  com_err("krb5_decode_test", retval, "while parsing etype_info");
+	  exit(1);
+      }
+      retval = decode_krb5_etype_info(&code,&var);
+      if(retval){
+	  com_err("krb5_decode_test", retval, "while decoding etype_info");
+      }
+      test(ktest_equal_etype_info(ref,var),"etype_info\n");
+
+      ktest_destroy_etype_info(var);
+      ktest_destroy_etype_info_entry(ref[2]);      ref[2] = 0;
+      ktest_destroy_etype_info_entry(ref[1]);      ref[1] = 0;
+      krb5_free_data_contents(test_context, &code);
+      
+      retval = krb5_data_hex_parse(&code,"30 16 30 14 A0 03 02 01 00 A1 0D 04 0B 4D 6F 72 74 6F 6E 27 73 20 23 30");
+      if(retval){
+	  com_err("krb5_decode_test", retval,
+		  "while parsing etype_info (only one)");
+	  exit(1);
+      }
+      retval = decode_krb5_etype_info(&code,&var);
+      if(retval){
+	  com_err("krb5_decode_test", retval,
+		  "while decoding etype_info (only one)");
+      }
+      test(ktest_equal_etype_info(ref,var),"etype_info (only one)\n");
+      
+      ktest_destroy_etype_info(var);
+      ktest_destroy_etype_info_entry(ref[0]);      ref[0] = 0;
+      krb5_free_data_contents(test_context, &code);
+      
+      retval = krb5_data_hex_parse(&code,"30 00");
+      if(retval){
+	  com_err("krb5_decode_test", retval,
+		  "while parsing etype_info (no info)");
+	  exit(1);
+      }
+      retval = decode_krb5_etype_info(&code,&var);
+      if(retval){
+	  com_err("krb5_decode_test", retval,
+		  "while decoding etype_info (no info)");
+      }
+      test(ktest_equal_etype_info(ref,var),"etype_info (no info)\n");
+
+      krb5_free_data_contents(test_context, &code);
+      ktest_destroy_etype_info(var);
+      ktest_destroy_etype_info(ref);
+  }
+
+  /****************************************************************/
+  /* decode_pa_enc_ts */
+  {
+    setup(krb5_pa_enc_ts,"krb5_pa_enc_ts",ktest_make_sample_pa_enc_ts);
+    decode_run("pa_enc_ts","","30 1A A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A1 05 02 03 01 E2 40",decode_krb5_pa_enc_ts,ktest_equal_krb5_pa_enc_ts,krb5_free_pa_enc_ts);
+    ref.pausec = 0;
+    decode_run("pa_enc_ts (no usec)","","30 13 A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_pa_enc_ts,ktest_equal_krb5_pa_enc_ts,krb5_free_pa_enc_ts);
+  }
+  
+  /****************************************************************/
+  /* decode_enc_data */
+  {
+    setup(krb5_enc_data,"krb5_enc_data",ktest_make_sample_enc_data);
+    decode_run("enc_data","","30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_enc_data,ktest_equal_enc_data,krb5_ktest_free_enc_data);
+    ktest_destroy_enc_data(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_sam_challenge */
+  {
+    setup(krb5_sam_challenge,"krb5_sam_challenge",ktest_make_sample_sam_challenge);
+    decode_run("sam_challenge","","30 78 A0 03 02 01 2A A1 07 03 05 00 80 00 00 00 A2 0B 04 09 74 79 70 65 20 6E 61 6D 65 A3 02 04 00 A4 11 04 0F 63 68 61 6C 6C 65 6E 67 65 20 6C 61 62 65 6C A5 10 04 0E 63 68 61 6C 6C 65 6E 67 65 20 69 70 73 65 A6 16 04 14 72 65 73 70 6F 6E 73 65 5F 70 72 6F 6D 70 74 20 69 70 73 65 A7 02 04 00 A8 05 02 03 54 32 10 A9 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34",decode_krb5_sam_challenge,ktest_equal_sam_challenge,krb5_free_sam_challenge);
+    ktest_empty_sam_challenge(&ref);
+
+  }
+  
+  /****************************************************************/
+  /* decode_sam_challenge */
+  {
+    setup(krb5_sam_challenge,"krb5_sam_challenge - no optionals",ktest_make_sample_sam_challenge);
+    decode_run("sam_challenge","","30 70 A0 03 02 01 2A A1 07 03 05 00 80 00 00 00 A2 0B 04 09 74 79 70 65 20 6E 61 6D 65 A4 11 04 0F 63 68 61 6C 6C 65 6E 67 65 20 6C 61 62 65 6C A5 10 04 0E 63 68 61 6C 6C 65 6E 67 65 20 69 70 73 65 A6 16 04 14 72 65 73 70 6F 6E 73 65 5F 70 72 6F 6D 70 74 20 69 70 73 65 A8 05 02 03 54 32 10 A9 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34",decode_krb5_sam_challenge,ktest_equal_sam_challenge,krb5_free_sam_challenge);
+    ktest_empty_sam_challenge(&ref);
+  }
+  
+  /****************************************************************/
+  /* decode_sam_response */
+  {
+    setup(krb5_sam_response,"krb5_sam_response",ktest_make_sample_sam_response);
+    decode_run("sam_response","","30 6A A0 03 02 01 2A A1 07 03 05 00 80 00 00 00 A2 0C 04 0A 74 72 61 63 6B 20 64 61 74 61 A3 14 30 12 A0 03 02 01 01 A1 04 02 02 07 96 A2 05 04 03 6B 65 79 A4 1C 30 1A A0 03 02 01 01 A1 04 02 02 0D 36 A2 0D 04 0B 6E 6F 6E 63 65 20 6F 72 20 74 73 A5 05 02 03 54 32 10 A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A",decode_krb5_sam_response,ktest_equal_sam_response,krb5_free_sam_response);
+
+    ktest_empty_sam_response(&ref);
+  }
+  
+  krb5_free_context(test_context);
+  exit(error_count);
+  return(error_count);
+}
+
+
+void krb5_ktest_free_alt_method(krb5_context context, krb5_alt_method *val)
+{
+  if (val->data)
+    krb5_xfree(val->data);
+  krb5_xfree(val);
+}
+
+void krb5_ktest_free_pwd_sequence(krb5_context context, 
+				  passwd_phrase_element *val)
+{
+  krb5_free_data(context, val->passwd);
+  krb5_free_data(context, val->phrase);
+  krb5_xfree(val);
+}
+
+void krb5_ktest_free_enc_data(krb5_context context, krb5_enc_data *val)
+{
+  if(val) {
+       krb5_free_data_contents(context, &(val->ciphertext));
+       free(val);
+  }
+}
diff --git a/mechglue/src/tests/asn.1/krb5_encode_test.c b/mechglue/src/tests/asn.1/krb5_encode_test.c
new file mode 100644
index 000000000..a6f869492
--- /dev/null
+++ b/mechglue/src/tests/asn.1/krb5_encode_test.c
@@ -0,0 +1,681 @@
+#include <stdio.h>
+#include "k5-int.h"
+#include "com_err.h"
+#include "utility.h"
+
+#include "ktest.h"
+#include <string.h>
+
+#include "debug.h"
+
+extern int current_appl_type;
+
+krb5_context test_context;
+int error_count = 0;
+int do_trval = 0;
+int trval2();
+
+static void encoder_print_results(code, typestring, description)
+	krb5_data *code;
+	char	*typestring;
+	char	*description;
+{
+	char	*code_string = NULL;
+	krb5_error_code	retval;
+	int r, rlen;
+
+	if (do_trval) {
+		printf("encode_krb5_%s%s:\n", typestring, description);
+		r = trval2(stdout, code->data, code->length, 0, &rlen);
+		printf("\n\n");
+		if (rlen != code->length) {
+			printf("Error: length mismatch: was %d, parsed %d\n",
+			       code->length, rlen);
+			exit(1);
+		}
+		if (r != 0) {
+			printf("Error: Return from trval2 is %d.\n", r);
+			exit(1);
+		}
+		current_appl_type = -1;	/* Reset type */
+	} else {
+		retval = asn1_krb5_data_unparse(code,&(code_string));
+		if(retval) {
+			com_err("krb5_encode_test", retval ,
+				"while unparsing %s", typestring);
+			exit(1);
+		}
+		printf("encode_krb5_%s%s: %s\n", typestring, description,
+		       code_string);
+		free(code_string);
+	}
+	ktest_destroy_data(&code);
+}	
+
+static void PRS(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	extern char *optarg;	
+	int optchar;
+	extern int print_types, print_krb5_types, print_id_and_len,
+		print_constructed_length, print_skip_context,
+		print_skip_tagnum, print_context_shortcut;
+
+	while ((optchar = getopt(argc, argv, "tp:")) != -1) {
+		switch(optchar) {
+		case 't':
+			do_trval = 1;
+			break;
+		case 'p':
+			sample_principal_name = optarg;
+			break;
+		case '?':
+		default:
+			fprintf(stderr, "Usage: %s [-t] [-p principal]\n",
+				argv[0]);
+			exit(1);
+		}
+	}
+	print_types = 1;
+	print_krb5_types = 1;
+	print_id_and_len = 0;
+	print_constructed_length = 0;
+	print_skip_context = 1;
+	print_skip_tagnum = 1;
+	print_context_shortcut = 1;
+}
+
+int
+main(argc, argv)
+	int	argc;
+	char	**argv;
+{
+  krb5_data *code;
+  krb5_error_code retval;
+
+  PRS(argc, argv);
+  
+  retval = krb5_init_context(&test_context);
+  if (retval) {
+	  com_err(argv[0], retval, "while initializing krb5");
+	  exit(1);
+  }
+  
+#define setup(value,type,typestring,constructor)\
+  retval = constructor(&(value));\
+  if(retval){\
+    com_err("krb5_encode_test", retval, "while making sample %s", typestring);\
+    exit(1);\
+  }
+    
+#define encode_run(value,type,typestring,description,encoder)\
+  retval = encoder(&(value),&(code));\
+  if(retval){\
+    com_err("krb5_encode_test", retval,"while encoding %s", typestring);\
+    exit(1);\
+  }\
+  encoder_print_results(code, typestring, description);
+      
+  /****************************************************************/
+  /* encode_krb5_authenticator */
+  {
+    krb5_authenticator authent;
+    setup(authent,authenticator,"authenticator",ktest_make_sample_authenticator);
+
+    encode_run(authent,authenticator,"authenticator","",encode_krb5_authenticator);
+
+    ktest_destroy_checksum(&(authent.checksum));
+    ktest_destroy_keyblock(&(authent.subkey));
+    authent.seq_number = 0;
+    ktest_empty_authorization_data(authent.authorization_data);
+    encode_run(authent,authenticator,"authenticator","(optionals empty)",encode_krb5_authenticator);
+
+    ktest_destroy_authorization_data(&(authent.authorization_data));
+    encode_run(authent,authenticator,"authenticator","(optionals NULL)",encode_krb5_authenticator);
+    ktest_empty_authenticator(&authent);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_ticket */
+  {
+    krb5_ticket tkt;
+    setup(tkt,ticket,"ticket",ktest_make_sample_ticket);
+    encode_run(tkt,ticket,"ticket","",encode_krb5_ticket);
+    ktest_empty_ticket(&tkt);
+  }
+
+  /****************************************************************/
+  /* encode_krb5_encryption_key */
+  {
+    krb5_keyblock keyblk;
+    setup(keyblk,keyblock,"keyblock",ktest_make_sample_keyblock);
+    current_appl_type = 1005;
+    encode_run(keyblk,keyblock,"keyblock","",encode_krb5_encryption_key);
+    ktest_empty_keyblock(&keyblk);
+  }  
+  
+  /****************************************************************/
+  /* encode_krb5_enc_tkt_part */
+  {
+    krb5_ticket tkt;
+    memset(&tkt, 0, sizeof(krb5_ticket));
+    tkt.enc_part2 = (krb5_enc_tkt_part*)calloc(1,sizeof(krb5_enc_tkt_part));
+    if(tkt.enc_part2 == NULL) com_err("allocating enc_tkt_part",errno,"");
+    setup(*(tkt.enc_part2),enc_tkt_part,"enc_tkt_part",ktest_make_sample_enc_tkt_part);
+  
+    encode_run(*(tkt.enc_part2),enc_tkt_part,"enc_tkt_part","",encode_krb5_enc_tkt_part);
+  
+    tkt.enc_part2->times.starttime = 0;
+    tkt.enc_part2->times.renew_till = 0;
+    ktest_destroy_address(&(tkt.enc_part2->caddrs[1]));
+    ktest_destroy_address(&(tkt.enc_part2->caddrs[0]));
+    ktest_destroy_authdata(&(tkt.enc_part2->authorization_data[1]));
+    ktest_destroy_authdata(&(tkt.enc_part2->authorization_data[0]));
+  
+    /* ISODE version fails on the empty caddrs field */
+    ktest_destroy_addresses(&(tkt.enc_part2->caddrs));
+    ktest_destroy_authorization_data(&(tkt.enc_part2->authorization_data));
+  
+    encode_run(*(tkt.enc_part2),enc_tkt_part,"enc_tkt_part","(optionals NULL)",encode_krb5_enc_tkt_part);
+    ktest_empty_ticket(&tkt);
+  }  
+  
+  /****************************************************************/
+  /* encode_krb5_enc_kdc_rep_part */
+  {
+    krb5_kdc_rep kdcr;
+
+    memset(&kdcr, 0, sizeof(kdcr));
+ 
+    kdcr.enc_part2 = (krb5_enc_kdc_rep_part*)
+      calloc(1,sizeof(krb5_enc_kdc_rep_part));
+    if(kdcr.enc_part2 == NULL) com_err("allocating enc_kdc_rep_part",errno,"");
+    setup(*(kdcr.enc_part2),enc_kdc_rep_part,"enc_kdc_rep_part",ktest_make_sample_enc_kdc_rep_part);
+  
+    encode_run(*(kdcr.enc_part2),enc_kdc_rep_part,"enc_kdc_rep_part","",encode_krb5_enc_kdc_rep_part);
+  
+    kdcr.enc_part2->key_exp = 0;
+    kdcr.enc_part2->times.starttime = 0;
+    kdcr.enc_part2->flags &= ~TKT_FLG_RENEWABLE;
+    ktest_destroy_addresses(&(kdcr.enc_part2->caddrs));
+  
+    encode_run(*(kdcr.enc_part2),enc_kdc_rep_part,"enc_kdc_rep_part","(optionals NULL)",encode_krb5_enc_kdc_rep_part);
+
+    ktest_empty_kdc_rep(&kdcr);
+  }  
+
+  /****************************************************************/
+  /* encode_krb5_as_rep */
+  {
+    krb5_kdc_rep kdcr;
+    setup(kdcr,kdc_rep,"kdc_rep",ktest_make_sample_kdc_rep);
+  
+/*    kdcr.msg_type = KRB5_TGS_REP;
+    test(encode_krb5_as_rep(&kdcr,&code) == KRB5_BADMSGTYPE,
+	   "encode_krb5_as_rep type check\n");
+    ktest_destroy_data(&code);*/
+  
+    kdcr.msg_type = KRB5_AS_REP;
+    encode_run(kdcr,as_rep,"as_rep","",encode_krb5_as_rep);
+  
+    ktest_destroy_pa_data_array(&(kdcr.padata));
+    encode_run(kdcr,as_rep,"as_rep","(optionals NULL)",encode_krb5_as_rep);
+
+    ktest_empty_kdc_rep(&kdcr);
+
+  }  
+  
+  /****************************************************************/
+  /* encode_krb5_tgs_rep */
+  {
+    krb5_kdc_rep kdcr;
+    setup(kdcr,kdc_rep,"kdc_rep",ktest_make_sample_kdc_rep);
+
+/*    kdcr.msg_type = KRB5_AS_REP;
+    test(encode_krb5_tgs_rep(&kdcr,&code) == KRB5_BADMSGTYPE,
+	   "encode_krb5_tgs_rep type check\n");*/
+  
+    kdcr.msg_type = KRB5_TGS_REP;
+    encode_run(kdcr,tgs_rep,"tgs_rep","",encode_krb5_tgs_rep);
+
+    ktest_destroy_pa_data_array(&(kdcr.padata));
+    encode_run(kdcr,tgs_rep,"tgs_rep","(optionals NULL)",encode_krb5_tgs_rep);
+
+    ktest_empty_kdc_rep(&kdcr);
+
+  }  
+  
+  /****************************************************************/
+  /* encode_krb5_ap_req */
+  {
+    krb5_ap_req apreq;
+    setup(apreq,ap_req,"ap_req",ktest_make_sample_ap_req);
+    encode_run(apreq,ap_req,"ap_req","",encode_krb5_ap_req);
+    ktest_empty_ap_req(&apreq);
+  }  
+
+  /****************************************************************/
+  /* encode_krb5_ap_rep */
+  {
+    krb5_ap_rep aprep;
+    setup(aprep,ap_rep,"ap_rep",ktest_make_sample_ap_rep);
+    encode_run(aprep,ap_rep,"ap_rep","",encode_krb5_ap_rep);
+    ktest_empty_ap_rep(&aprep);
+  }  
+
+  /****************************************************************/
+  /* encode_krb5_ap_rep_enc_part */
+  {
+    krb5_ap_rep_enc_part apenc;
+    setup(apenc,ap_rep_enc_part,"ap_rep_enc_part",ktest_make_sample_ap_rep_enc_part);
+    encode_run(apenc,ap_rep_enc_part,"ap_rep_enc_part","",encode_krb5_ap_rep_enc_part);
+  
+    ktest_destroy_keyblock(&(apenc.subkey));
+    apenc.seq_number = 0;
+    encode_run(apenc,ap_rep_enc_part,"ap_rep_enc_part","(optionals NULL)",encode_krb5_ap_rep_enc_part);
+    ktest_empty_ap_rep_enc_part(&apenc);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_as_req */
+  {
+    krb5_kdc_req asreq;
+    setup(asreq,kdc_req,"kdc_req",ktest_make_sample_kdc_req);
+    asreq.msg_type = KRB5_AS_REQ;
+    asreq.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    encode_run(asreq,as_req,"as_req","",encode_krb5_as_req);
+
+    ktest_destroy_pa_data_array(&(asreq.padata));
+    ktest_destroy_principal(&(asreq.client));
+#ifndef ISODE_SUCKS
+    ktest_destroy_principal(&(asreq.server));
+#endif
+    asreq.kdc_options |= KDC_OPT_ENC_TKT_IN_SKEY;
+    asreq.from = 0;
+    asreq.rtime = 0;
+    ktest_destroy_addresses(&(asreq.addresses));
+    ktest_destroy_enc_data(&(asreq.authorization_data));
+    encode_run(asreq,as_req,"as_req","(optionals NULL except second_ticket)",encode_krb5_as_req);
+    ktest_destroy_sequence_of_ticket(&(asreq.second_ticket));
+#ifndef ISODE_SUCKS
+    ktest_make_sample_principal(&(asreq.server));
+#endif
+    asreq.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    encode_run(asreq,as_req,"as_req","(optionals NULL except server)",encode_krb5_as_req);
+    ktest_empty_kdc_req(&asreq);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_tgs_req */
+  {
+    krb5_kdc_req tgsreq;
+    setup(tgsreq,kdc_req,"kdc_req",ktest_make_sample_kdc_req);
+    tgsreq.msg_type = KRB5_TGS_REQ;
+    tgsreq.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    encode_run(tgsreq,tgs_req,"tgs_req","",encode_krb5_tgs_req);
+
+    ktest_destroy_pa_data_array(&(tgsreq.padata));
+    ktest_destroy_principal(&(tgsreq.client));
+#ifndef ISODE_SUCKS
+    ktest_destroy_principal(&(tgsreq.server));
+#endif
+    tgsreq.kdc_options |= KDC_OPT_ENC_TKT_IN_SKEY;
+    tgsreq.from = 0;
+    tgsreq.rtime = 0;
+    ktest_destroy_addresses(&(tgsreq.addresses));
+    ktest_destroy_enc_data(&(tgsreq.authorization_data));
+    encode_run(tgsreq,tgs_req,"tgs_req","(optionals NULL except second_ticket)",encode_krb5_tgs_req);
+
+    ktest_destroy_sequence_of_ticket(&(tgsreq.second_ticket));
+#ifndef ISODE_SUCKS
+    ktest_make_sample_principal(&(tgsreq.server));
+#endif
+    tgsreq.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    encode_run(tgsreq,tgs_req,"tgs_req","(optionals NULL except server)",encode_krb5_tgs_req);
+
+    ktest_empty_kdc_req(&tgsreq);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_kdc_req_body */
+  {
+    krb5_kdc_req kdcrb;
+    memset(&kdcrb, 0, sizeof(kdcrb));
+    setup(kdcrb,kdc_req_body,"kdc_req_body",ktest_make_sample_kdc_req_body);
+    kdcrb.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    current_appl_type = 1007;	/* Force interpretation as kdc-req-body */
+    encode_run(kdcrb,kdc_req_body,"kdc_req_body","",encode_krb5_kdc_req_body);
+
+    ktest_destroy_principal(&(kdcrb.client));
+#ifndef ISODE_SUCKS
+    ktest_destroy_principal(&(kdcrb.server));
+#endif
+    kdcrb.kdc_options |= KDC_OPT_ENC_TKT_IN_SKEY;
+    kdcrb.from = 0;
+    kdcrb.rtime = 0;
+    ktest_destroy_addresses(&(kdcrb.addresses));
+    ktest_destroy_enc_data(&(kdcrb.authorization_data));
+    current_appl_type = 1007;	/* Force interpretation as kdc-req-body */
+    encode_run(kdcrb,kdc_req_body,"kdc_req_body","(optionals NULL except second_ticket)",encode_krb5_kdc_req_body);
+
+    ktest_destroy_sequence_of_ticket(&(kdcrb.second_ticket));
+#ifndef ISODE_SUCKS
+    ktest_make_sample_principal(&(kdcrb.server));
+#endif
+    kdcrb.kdc_options &= ~KDC_OPT_ENC_TKT_IN_SKEY;
+    current_appl_type = 1007;	/* Force interpretation as kdc-req-body */
+    encode_run(kdcrb,kdc_req_body,"kdc_req_body","(optionals NULL except server)",encode_krb5_kdc_req_body);
+
+    ktest_empty_kdc_req(&kdcrb);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_safe */
+  {
+    krb5_safe s;
+    setup(s,safe,"safe",ktest_make_sample_safe);
+    encode_run(s,safe,"safe","",encode_krb5_safe);
+
+    s.timestamp = 0;
+    /* s.usec should be opted out by the timestamp */
+    s.seq_number = 0;
+    ktest_destroy_address(&(s.r_address));
+    encode_run(s,safe,"safe","(optionals NULL)",encode_krb5_safe);
+
+    ktest_empty_safe(&s);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_priv */
+  {
+    krb5_priv p;
+    setup(p,priv,"priv",ktest_make_sample_priv);
+    encode_run(p,priv,"priv","",encode_krb5_priv);
+    ktest_empty_priv(&p);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_enc_priv_part */
+  {
+    krb5_priv_enc_part ep;
+    setup(ep,priv_enc_part,"priv_enc_part",ktest_make_sample_priv_enc_part);
+    encode_run(ep,enc_priv_part,"enc_priv_part","",encode_krb5_enc_priv_part);
+
+    ep.timestamp = 0;
+    /* ep.usec should be opted out along with timestamp */
+    ep.seq_number = 0;
+    ktest_destroy_address(&(ep.r_address));
+    encode_run(ep,enc_priv_part,"enc_priv_part","(optionals NULL)",encode_krb5_enc_priv_part);
+
+    ktest_empty_priv_enc_part(&ep);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_cred */
+  {
+    krb5_cred c;
+    setup(c,cred,"cred",ktest_make_sample_cred);
+    encode_run(c,cred,"cred","",encode_krb5_cred);
+    ktest_empty_cred(&c);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_enc_cred_part */
+  {
+    krb5_cred_enc_part cep;
+    setup(cep,cred_enc_part,"cred_enc_part",ktest_make_sample_cred_enc_part);
+    encode_run(cep,enc_cred_part,"enc_cred_part","",encode_krb5_enc_cred_part);
+
+    ktest_destroy_principal(&(cep.ticket_info[0]->client));
+    ktest_destroy_principal(&(cep.ticket_info[0]->server));
+    cep.ticket_info[0]->flags = 0;
+    cep.ticket_info[0]->times.authtime = 0;
+    cep.ticket_info[0]->times.starttime = 0;
+    cep.ticket_info[0]->times.endtime = 0;
+    cep.ticket_info[0]->times.renew_till = 0;
+    ktest_destroy_addresses(&(cep.ticket_info[0]->caddrs));
+    cep.nonce = 0;
+    cep.timestamp = 0;
+    ktest_destroy_address(&(cep.s_address));
+    ktest_destroy_address(&(cep.r_address));
+    encode_run(cep,enc_cred_part,"enc_cred_part","(optionals NULL)",encode_krb5_enc_cred_part);
+
+    ktest_empty_cred_enc_part(&cep);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_error */
+  {
+    krb5_error kerr;
+    setup(kerr,error,"error",ktest_make_sample_error);
+    encode_run(kerr,error,"error","",encode_krb5_error);
+
+    kerr.ctime = 0;
+    ktest_destroy_principal(&(kerr.client));
+    ktest_empty_data(&(kerr.text));
+    ktest_empty_data(&(kerr.e_data));
+    encode_run(kerr,error,"error","(optionals NULL)",encode_krb5_error);
+
+    ktest_empty_error(&kerr);
+  }
+  
+  /****************************************************************/
+  /* encode_krb5_authdata */
+  {
+    krb5_authdata **ad;
+    setup(ad,authorization_data,"authorization_data",ktest_make_sample_authorization_data);
+
+    retval = encode_krb5_authdata((const krb5_authdata**)ad,&(code));
+    if(retval) {
+	com_err("encoding authorization_data",retval,"");
+	exit(1);
+    }
+    current_appl_type = 1004;	/* Force type to be authdata */
+    encoder_print_results(code, "authorization_data", "");
+
+    ktest_destroy_authorization_data(&ad);
+  }
+  
+  /****************************************************************/
+  /* encode_pwd_sequence */
+  {
+    passwd_phrase_element ppe;
+    setup(ppe,passwd_phrase_element,"PasswdSequence",ktest_make_sample_passwd_phrase_element);
+    encode_run(ppe,passwd_phrase_element,"pwd_sequence","",encode_krb5_pwd_sequence);
+    ktest_empty_passwd_phrase_element(&ppe);
+  }
+
+  /****************************************************************/
+  /* encode_passwd_data */
+  {
+    krb5_pwd_data pd;
+    setup(pd,krb5_pwd_data,"PasswdData",ktest_make_sample_krb5_pwd_data);
+    encode_run(pd,krb5_pwd_data,"pwd_data","",encode_krb5_pwd_data);
+    ktest_empty_pwd_data(&pd);
+  }
+
+  /****************************************************************/
+  /* encode_padata_sequence */
+  {
+    krb5_pa_data **pa;
+    
+    setup(pa,krb5_pa_data,"PreauthData",ktest_make_sample_pa_data_array);
+    retval = encode_krb5_padata_sequence((const krb5_pa_data**)pa,&(code));
+    if(retval) {
+	com_err("encoding padata_sequence",retval,"");
+	exit(1);
+    }
+    encoder_print_results(code, "padata_sequence", "");
+    
+    ktest_destroy_pa_data_array(&pa);
+  }
+
+  /****************************************************************/
+  /* encode_padata_sequence (empty) */
+  {
+    krb5_pa_data **pa;
+    
+    setup(pa,krb5_pa_data,"EmptyPreauthData",ktest_make_sample_empty_pa_data_array);
+    retval = encode_krb5_padata_sequence((const krb5_pa_data**)pa,&(code));
+    if(retval) {
+	com_err("encoding padata_sequence(empty)",retval,"");
+	exit(1);
+    }
+    encoder_print_results(code, "padata_sequence(empty)", "");
+
+    ktest_destroy_pa_data_array(&pa);
+  }
+
+  /****************************************************************/
+  /* encode_alt_method */
+  {
+    krb5_alt_method am;
+    setup(am,krb5_alt_method,"AltMethod",ktest_make_sample_alt_method);
+    encode_run(am,krb5_alt_method,"alt_method","",encode_krb5_alt_method);
+    am.length = 0;
+    if (am.data)
+      free(am.data);
+    am.data = 0;
+    encode_run(am,krb5_alt_method,"alt_method (no data)","",
+	       encode_krb5_alt_method);
+    ktest_empty_alt_method(&am);
+  }
+
+  /****************************************************************/
+  /* encode_etype_info */
+  {
+    krb5_etype_info_entry **info;
+    
+    setup(info,krb5_etype_info_entry **,"etype_info",
+	  ktest_make_sample_etype_info);
+    retval = encode_krb5_etype_info((const krb5_etype_info_entry **)info,&(code));
+    if(retval) {
+	com_err("encoding etype_info",retval,"");
+	exit(1);
+    }
+    encoder_print_results(code, "etype_info", "");
+    ktest_destroy_etype_info_entry(info[2]);      info[2] = 0;
+    ktest_destroy_etype_info_entry(info[1]);      info[1] = 0;
+
+    retval = encode_krb5_etype_info((const krb5_etype_info_entry **)info,&(code));
+    if(retval) {
+	com_err("encoding etype_info (only 1)",retval,"");
+	exit(1);
+    }
+    encoder_print_results(code, "etype_info (only 1)", "");
+
+    ktest_destroy_etype_info_entry(info[0]);      info[0] = 0;
+    
+    retval = encode_krb5_etype_info((const krb5_etype_info_entry **)info,&(code));
+    if(retval) {
+	com_err("encoding etype_info (no info)",retval,"");
+	exit(1);
+    }
+    encoder_print_results(code, "etype_info (no info)", "");
+
+    ktest_destroy_etype_info(info);
+  }
+
+  /* encode_etype_info 2*/
+  {
+    krb5_etype_info_entry **info;
+    
+    setup(info,krb5_etype_info_entry **,"etype_info2",
+	  ktest_make_sample_etype_info2);
+    retval = encode_krb5_etype_info2((const krb5_etype_info_entry **)info,&(code));
+    if(retval) {
+	com_err("encoding etype_info",retval,"");
+	exit(1);
+    }
+    encoder_print_results(code, "etype_info2", "");
+    ktest_destroy_etype_info_entry(info[2]);      info[2] = 0;
+    ktest_destroy_etype_info_entry(info[1]);      info[1] = 0;
+
+    retval = encode_krb5_etype_info2((const krb5_etype_info_entry **)info,&(code));
+    if(retval) {
+	com_err("encoding etype_info (only 1)",retval,"");
+	exit(1);
+    }
+    encoder_print_results(code, "etype_info2 (only 1)", "");
+
+    ktest_destroy_etype_info(info);
+/*    ktest_destroy_etype_info_entry(info[0]);      info[0] = 0;*/
+    
+  }
+
+  /****************************************************************/
+  /* encode_pa_enc_ts */
+  {
+    krb5_pa_enc_ts pa_enc;
+    setup(pa_enc,krb5_pa_enc_ts,"pa_enc_ts",ktest_make_sample_pa_enc_ts);
+    encode_run(pa_enc,krb5_pa_enc_ts,"pa_enc_ts","",encode_krb5_pa_enc_ts);
+    pa_enc.pausec = 0;
+    encode_run(pa_enc,krb5_pa_enc_ts,"pa_enc_ts (no usec)","",encode_krb5_pa_enc_ts);
+  }
+
+  /****************************************************************/
+  /* encode_enc_data */
+  {
+    krb5_enc_data enc_data;
+    setup(enc_data,krb5_enc_data,"enc_data",ktest_make_sample_enc_data);
+    current_appl_type = 1001;
+    encode_run(enc_data,krb5_enc_data,"enc_data","",encode_krb5_enc_data);
+    ktest_destroy_enc_data(&enc_data);
+  }
+  /****************************************************************/
+  /* encode_krb5_sam_challenge */
+  {
+    krb5_sam_challenge sam_ch;
+    setup(sam_ch,krb5_sam_challenge,"sam_challenge",
+	  ktest_make_sample_sam_challenge);
+    encode_run(sam_ch,krb5_sam_challenge,"sam_challenge","",
+	       encode_krb5_sam_challenge);
+    ktest_empty_sam_challenge(&sam_ch);
+  }
+  /****************************************************************/
+  /* encode_krb5_sam_response */
+  {
+    krb5_sam_response sam_ch;
+    setup(sam_ch,krb5_sam_response,"sam_response",
+	  ktest_make_sample_sam_response);
+    encode_run(sam_ch,krb5_sam_response,"sam_response","",
+	       encode_krb5_sam_response);
+    ktest_empty_sam_response(&sam_ch);
+  }
+#if 0
+  /****************************************************************/
+  /* encode_krb5_sam_key */
+  {
+    krb5_sam_key sam_ch;
+    setup(sam_ch,krb5_sam_key,"sam_key",
+	  ktest_make_sample_sam_key);
+    encode_run(sam_ch,krb5_sam_key,"sam_key","",
+	       encode_krb5_sam_key);
+  }
+  /****************************************************************/
+  /* encode_krb5_enc_sam_response_enc */
+  {
+    krb5_enc_sam_response_enc sam_ch;
+    setup(sam_ch,krb5_enc_sam_response_enc,"enc_sam_response_enc",
+	  ktest_make_sample_enc_sam_response_enc);
+    encode_run(sam_ch,krb5_enc_sam_response_enc,"enc_sam_response_enc","",
+	       encode_krb5_enc_sam_response_enc);
+  }
+  /****************************************************************/
+  /* encode_krb5_predicted_sam_response */
+  {
+    krb5_predicted_sam_response sam_ch;
+    setup(sam_ch,krb5_predicted_sam_response,"predicted_sam_response",
+	  ktest_make_sample_predicted_sam_response);
+    encode_run(sam_ch,krb5_predicted_sam_response,"predicted_sam_response","",
+	       encode_krb5_predicted_sam_response);
+  }
+#endif
+
+  krb5_free_context(test_context);
+  exit(error_count);
+  return(error_count);
+}
+
+
diff --git a/mechglue/src/tests/asn.1/ktest.c b/mechglue/src/tests/asn.1/ktest.c
new file mode 100644
index 000000000..12ff8fb93
--- /dev/null
+++ b/mechglue/src/tests/asn.1/ktest.c
@@ -0,0 +1,1291 @@
+#include "ktest.h"
+#include "utility.h"
+#include <stdlib.h>
+
+char *sample_principal_name = "hftsai/extra@ATHENA.MIT.EDU";
+
+krb5_error_code ktest_make_sample_authenticator(a)
+     krb5_authenticator * a;
+{
+  krb5_error_code retval;
+
+  retval = ktest_make_sample_principal(&(a->client));
+  if(retval) return retval;
+  a->checksum = (krb5_checksum*)calloc(1,sizeof(krb5_checksum));
+  if(a->checksum == NULL) return ENOMEM;
+  retval = ktest_make_sample_checksum(a->checksum);
+  if(retval) return retval;
+  a->cusec = SAMPLE_USEC;
+  a->ctime = SAMPLE_TIME;
+  a->subkey = (krb5_keyblock*)calloc(1,sizeof(krb5_keyblock));
+  if(a->subkey == NULL) return ENOMEM;
+  retval = ktest_make_sample_keyblock(a->subkey);
+  if(retval) return retval;
+  a->seq_number = SAMPLE_SEQ_NUMBER;
+  retval = ktest_make_sample_authorization_data(&(a->authorization_data));
+  if(retval) return retval;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_principal(p)
+     krb5_principal * p;
+{
+  krb5_error_code retval;
+
+  retval = krb5_parse_name(test_context, sample_principal_name, p);
+  return retval;
+}
+
+krb5_error_code ktest_make_sample_checksum(cs)
+     krb5_checksum * cs;
+{
+  cs->checksum_type = 1;
+  cs->length = 4;
+  cs->contents = (krb5_octet*)calloc(4,sizeof(krb5_octet));
+  if(cs->contents == NULL) return ENOMEM;
+  memcpy(cs->contents,"1234",4);
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_keyblock(kb)
+     krb5_keyblock * kb;
+{
+  kb->magic = KV5M_KEYBLOCK;
+  kb->enctype = 1;
+  kb->length = 8;
+  kb->contents = (krb5_octet*)calloc(8,sizeof(krb5_octet));
+  if(kb->contents == NULL) return ENOMEM;
+  memcpy(kb->contents,"12345678",8);
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_ticket(tkt)
+     krb5_ticket * tkt;
+{
+  krb5_error_code retval;
+
+  retval = ktest_make_sample_principal(&(tkt->server));
+  if(retval) return retval;
+  retval = ktest_make_sample_enc_data(&(tkt->enc_part));
+  if(retval) return retval;
+  tkt->enc_part2 = NULL;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_enc_data(ed)
+     krb5_enc_data * ed;
+{
+  krb5_error_code retval;
+
+  ed->kvno = 5;
+  ed->enctype = 0;
+  retval = krb5_data_parse(&(ed->ciphertext),"krbASN.1 test message");
+  if(retval) return retval;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_enc_tkt_part(etp)
+     krb5_enc_tkt_part * etp;
+{
+  krb5_error_code retval;
+
+  etp->flags = SAMPLE_FLAGS;
+  etp->session = (krb5_keyblock*)calloc(1,sizeof(krb5_keyblock));
+  if(etp->session == NULL) return ENOMEM;
+  retval = ktest_make_sample_keyblock(etp->session);
+  if(retval) return retval;
+  retval = ktest_make_sample_principal(&(etp->client));
+  if(retval) return retval;
+  retval = ktest_make_sample_transited(&(etp->transited));
+  if(retval) return retval;
+  retval = ktest_make_sample_ticket_times(&(etp->times));
+  if(retval) return retval;
+  retval = ktest_make_sample_addresses(&(etp->caddrs));
+  if(retval) return retval;
+  retval = ktest_make_sample_authorization_data(&(etp->authorization_data));
+  if(retval) return retval;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_addresses(caddrs)
+     krb5_address *** caddrs;
+{
+  asn1_error_code retval;
+  int i;
+
+  *caddrs = (krb5_address**)calloc(3,sizeof(krb5_address*));
+  if(*caddrs == NULL) return ENOMEM;
+  for(i=0; i<2; i++){
+    (*caddrs)[i] = (krb5_address*)calloc(1,sizeof(krb5_address));
+    if((*caddrs)[i] == NULL) return ENOMEM;
+    retval = ktest_make_sample_address((*caddrs)[i]);
+    if(retval) return retval;
+  }
+  (*caddrs)[2] = NULL;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_authorization_data(ad)
+     krb5_authdata *** ad;
+{
+  krb5_error_code retval;
+  int i;
+
+  *ad = (krb5_authdata**)calloc(3,sizeof(krb5_authdata*));
+  if(*ad == NULL) return ENOMEM;
+
+  for(i=0; i<=1; i++){
+    (*ad)[i] = (krb5_authdata*)calloc(1,sizeof(krb5_authdata));
+    if((*ad)[i] == NULL) return ENOMEM;
+    retval = ktest_make_sample_authdata((*ad)[i]);
+    if(retval) return retval;
+  }
+  (*ad)[2] = NULL;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_transited(t)
+     krb5_transited * t;
+{
+  t->tr_type = 1;
+  return krb5_data_parse(&(t->tr_contents),
+			 "EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS.");
+}
+
+krb5_error_code ktest_make_sample_ticket_times(tt)
+     krb5_ticket_times * tt;
+{
+  tt->authtime = SAMPLE_TIME;
+  tt->starttime = SAMPLE_TIME;
+  tt->endtime = SAMPLE_TIME;
+  tt->renew_till = SAMPLE_TIME;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_address(a)
+     krb5_address * a;
+{
+  a->addrtype = ADDRTYPE_INET;
+  a->length = 4;
+  a->contents = (krb5_octet*)calloc(4,sizeof(krb5_octet));
+  if(a->contents == NULL) return ENOMEM;
+  a->contents[0] = 18;
+  a->contents[1] = 208;
+  a->contents[2] = 0;
+  a->contents[3] = 35;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_authdata(ad)
+     krb5_authdata * ad;
+{
+  ad->ad_type = 1;
+  ad->length = 6;
+  ad->contents = (krb5_octet*)calloc(6,sizeof(krb5_octet));
+  if(ad->contents == NULL) return ENOMEM;
+  memcpy(ad->contents,"foobar",6);
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_enc_kdc_rep_part(ekr)
+     krb5_enc_kdc_rep_part * ekr;
+{
+  krb5_error_code retval;
+
+  ekr->session = (krb5_keyblock*)calloc(1,sizeof(krb5_keyblock));
+  if(ekr->session == NULL) return ENOMEM;
+  retval = ktest_make_sample_keyblock(ekr->session);
+  if(retval) return retval;
+  retval = ktest_make_sample_last_req(&(ekr->last_req));
+  if(retval) return retval;
+  ekr->nonce = SAMPLE_NONCE;
+  ekr->key_exp = SAMPLE_TIME;
+  ekr->flags = SAMPLE_FLAGS;
+  ekr->times.authtime = SAMPLE_TIME;
+  ekr->times.starttime = SAMPLE_TIME;
+  ekr->times.endtime = SAMPLE_TIME;
+  ekr->times.renew_till = SAMPLE_TIME;
+  retval = ktest_make_sample_principal(&(ekr->server));
+  if(retval) return retval;
+  retval = ktest_make_sample_addresses(&(ekr->caddrs));
+  if(retval) return retval;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_last_req(lr)
+     krb5_last_req_entry *** lr;
+{
+  krb5_error_code retval;
+  int i;
+
+  *lr = (krb5_last_req_entry**)calloc(3,sizeof(krb5_last_req_entry*));
+  if(*lr == NULL) return ENOMEM;
+  for(i=0; i<=1; i++){
+    retval = ktest_make_sample_last_req_entry(&((*lr)[i]));
+    if(retval) return retval;
+  }
+  (*lr)[2] = NULL;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_last_req_entry(lre)
+     krb5_last_req_entry ** lre;
+{
+  *lre = (krb5_last_req_entry*)calloc(1,sizeof(krb5_last_req_entry));
+  if(*lre == NULL) return ENOMEM;
+  (*lre)->lr_type = -5;
+  (*lre)->value = SAMPLE_TIME;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_kdc_rep(kdcr)
+     krb5_kdc_rep * kdcr;
+{
+  krb5_error_code retval;
+
+  retval = ktest_make_sample_pa_data_array(&(kdcr->padata));
+  if(retval) return retval;
+  retval = ktest_make_sample_principal(&(kdcr->client));
+  if(retval) return retval;
+  kdcr->ticket = (krb5_ticket*)calloc(1,sizeof(krb5_ticket));
+  if(kdcr->ticket == NULL) return ENOMEM;
+  retval = ktest_make_sample_ticket(kdcr->ticket);
+  if(retval) return retval;
+  retval = ktest_make_sample_enc_data(&(kdcr->enc_part));
+  if(retval) return retval;
+  kdcr->enc_part2 = NULL;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_pa_data_array(pad)
+     krb5_pa_data *** pad;
+{
+  krb5_error_code retval;
+  int i;
+
+  *pad = (krb5_pa_data**)calloc(3,sizeof(krb5_pa_data*));
+  if(*pad == NULL) return ENOMEM;
+
+  for(i=0; i<=1; i++){
+    (*pad)[i] = (krb5_pa_data*)calloc(1,sizeof(krb5_pa_data));
+    if((*pad)[i] == NULL) return ENOMEM;
+    retval = ktest_make_sample_pa_data((*pad)[i]);
+    if(retval) return retval;
+  }
+  (*pad)[2] = NULL;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_empty_pa_data_array(pad)
+     krb5_pa_data *** pad;
+{
+  *pad = (krb5_pa_data**)calloc(1,sizeof(krb5_pa_data*));
+  if(*pad == NULL) return ENOMEM;
+
+  (*pad)[0] = NULL;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_pa_data(pad)
+     krb5_pa_data * pad;
+{
+  pad->pa_type = 13;
+  pad->length = 7;
+  pad->contents = (krb5_octet*)calloc(7,sizeof(krb5_octet));
+  if(pad->contents == NULL) return ENOMEM;
+  memcpy(pad->contents,"pa-data",7);
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_ap_req(ar)
+     krb5_ap_req * ar;
+{
+  krb5_error_code retval;
+  ar->ap_options = SAMPLE_FLAGS;
+  ar->ticket = (krb5_ticket*)calloc(1,sizeof(krb5_ticket));
+  if(ar->ticket == NULL) return ENOMEM;
+  retval = ktest_make_sample_ticket(ar->ticket);
+  if(retval) return retval;
+  retval = ktest_make_sample_enc_data(&(ar->authenticator));
+  if(retval) return retval;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_ap_rep(ar)
+     krb5_ap_rep * ar;
+{
+  return ktest_make_sample_enc_data(&(ar->enc_part));
+}
+
+krb5_error_code ktest_make_sample_ap_rep_enc_part(arep)
+     krb5_ap_rep_enc_part * arep;
+{
+  krb5_error_code retval;
+
+  arep->ctime = SAMPLE_TIME;
+  arep->cusec = SAMPLE_USEC;
+  arep->subkey = (krb5_keyblock*)calloc(1,sizeof(krb5_keyblock));
+  if(arep->subkey == NULL) return ENOMEM;
+  retval = ktest_make_sample_keyblock(arep->subkey);
+  if(retval) return retval;
+  arep->seq_number = SAMPLE_SEQ_NUMBER;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_kdc_req(kr)
+     krb5_kdc_req * kr;
+{
+  krb5_error_code retval;
+
+  /* msg_type is left up to the calling procedure */
+  retval = ktest_make_sample_pa_data_array(&(kr->padata));
+  if(retval) return retval;
+  kr->kdc_options = SAMPLE_FLAGS;
+  retval = ktest_make_sample_principal(&(kr->client));
+  if(retval) return retval;
+  retval = ktest_make_sample_principal(&(kr->server));
+  if(retval) return retval;
+  kr->from = SAMPLE_TIME;
+  kr->till = SAMPLE_TIME;
+  kr->rtime = SAMPLE_TIME;
+  kr->nonce = SAMPLE_NONCE;
+  kr->nktypes = 2;
+  kr->ktype = (krb5_enctype*)calloc(2,sizeof(krb5_enctype));
+  kr->ktype[0] = 0;
+  kr->ktype[1] = 1;
+  retval = ktest_make_sample_addresses(&(kr->addresses));
+  if(retval) return retval;
+  retval = ktest_make_sample_enc_data(&(kr->authorization_data));
+  if(retval) return retval;
+  retval = ktest_make_sample_authorization_data(&(kr->unenc_authdata));
+  if(retval) return retval;
+  retval = ktest_make_sample_sequence_of_ticket(&(kr->second_ticket));
+  if(retval) return retval;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_kdc_req_body(krb)
+     krb5_kdc_req * krb;
+{
+  krb5_error_code retval;
+
+  krb->kdc_options = SAMPLE_FLAGS;
+  retval = ktest_make_sample_principal(&(krb->client));
+  if(retval) return retval;
+  retval = ktest_make_sample_principal(&(krb->server));
+  if(retval) return retval;
+  krb->from = SAMPLE_TIME;
+  krb->till = SAMPLE_TIME;
+  krb->rtime = SAMPLE_TIME;
+  krb->nonce = SAMPLE_NONCE;
+  krb->nktypes = 2;
+  krb->ktype = (krb5_enctype*)calloc(2,sizeof(krb5_enctype));
+  krb->ktype[0] = 0;
+  krb->ktype[1] = 1;
+  retval = ktest_make_sample_addresses(&(krb->addresses));
+  if(retval) return retval;
+  retval = ktest_make_sample_enc_data(&(krb->authorization_data));
+  if(retval) return retval;
+  retval = ktest_make_sample_authorization_data(&(krb->unenc_authdata));
+  if(retval) return retval;
+  retval = ktest_make_sample_sequence_of_ticket(&(krb->second_ticket));
+  if(retval) return retval;
+  return 0;
+}
+  
+krb5_error_code ktest_make_sample_safe(s)
+     krb5_safe * s;
+{
+  krb5_error_code retval;
+
+  retval = ktest_make_sample_data(&(s->user_data));
+  if(retval) return retval;
+  s->timestamp = SAMPLE_TIME;
+  s->usec = SAMPLE_USEC;
+  s->seq_number = SAMPLE_SEQ_NUMBER;
+  s->s_address = (krb5_address*)calloc(1,sizeof(krb5_address));
+  if(s->s_address == NULL) return ENOMEM;
+  retval = ktest_make_sample_address(s->s_address);
+  if(retval) return retval;
+  s->r_address = (krb5_address*)calloc(1,sizeof(krb5_address));
+  if(s->r_address == NULL) return ENOMEM;
+  retval = ktest_make_sample_address(s->r_address);
+  if(retval) return retval;
+  s->checksum = (krb5_checksum*)calloc(1,sizeof(krb5_checksum));
+  if(s->checksum == NULL) return ENOMEM;
+  retval = ktest_make_sample_checksum(s->checksum);
+  if(retval) return retval;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_priv(p)
+     krb5_priv * p;
+{
+  return ktest_make_sample_enc_data(&(p->enc_part));
+}
+
+krb5_error_code ktest_make_sample_priv_enc_part(pep)
+     krb5_priv_enc_part * pep;
+{
+  krb5_error_code retval;
+  retval = ktest_make_sample_data(&(pep->user_data));
+  if(retval) return retval;
+  pep->timestamp = SAMPLE_TIME;
+  pep->usec = SAMPLE_USEC;
+  pep->seq_number = SAMPLE_SEQ_NUMBER;
+  pep->s_address = (krb5_address*)calloc(1,sizeof(krb5_address));
+  if(pep->s_address == NULL) return ENOMEM;
+  retval = ktest_make_sample_address(pep->s_address);
+  if(retval) return retval;
+  pep->r_address = (krb5_address*)calloc(1,sizeof(krb5_address));
+  if(pep->r_address == NULL) return ENOMEM;
+  retval = ktest_make_sample_address(pep->r_address);
+  if(retval) return retval;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_cred(c)
+     krb5_cred * c;
+{
+  krb5_error_code retval;
+  retval = ktest_make_sample_sequence_of_ticket(&(c->tickets));
+  if(retval) return retval;
+  retval = ktest_make_sample_enc_data(&(c->enc_part));
+  if(retval) return retval;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_sequence_of_ticket(sot)
+     krb5_ticket *** sot;
+{
+  krb5_error_code retval;
+  int i;
+
+  *sot = (krb5_ticket**)calloc(3,sizeof(krb5_ticket*));
+  if(*sot == NULL) return ENOMEM;
+  for(i=0; i<2; i++){
+    (*sot)[i] = (krb5_ticket*)calloc(1,sizeof(krb5_ticket));
+    if((*sot)[i] == NULL) return ENOMEM;
+    retval = ktest_make_sample_ticket((*sot)[i]);
+    if(retval) return retval;
+  }
+  (*sot)[2] = NULL;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_cred_enc_part(cep)
+     krb5_cred_enc_part * cep;
+{
+  krb5_error_code retval;
+
+  cep->nonce = SAMPLE_NONCE;
+  cep->timestamp = SAMPLE_TIME;
+  cep->usec = SAMPLE_USEC;
+  cep->s_address = (krb5_address*)calloc(1,sizeof(krb5_address));
+  if(cep->s_address == NULL) return ENOMEM;
+  retval = ktest_make_sample_address(cep->s_address);
+  if(retval) return retval;
+  cep->r_address = (krb5_address*)calloc(1,sizeof(krb5_address));
+  if(cep->r_address == NULL) return ENOMEM;
+  retval = ktest_make_sample_address(cep->r_address);
+  if(retval) return retval;
+  retval = ktest_make_sequence_of_cred_info(&(cep->ticket_info));
+  if(retval) return retval;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sequence_of_cred_info(soci)
+     krb5_cred_info *** soci;
+{
+  krb5_error_code retval;
+  int i;
+
+  *soci = (krb5_cred_info**)calloc(3,sizeof(krb5_cred_info*));
+  if(*soci == NULL) return ENOMEM;
+  for(i=0; i<2; i++){
+    (*soci)[i] = (krb5_cred_info*)calloc(1,sizeof(krb5_cred_info));
+    if((*soci)[i] == NULL) return ENOMEM;
+    retval = ktest_make_sample_cred_info((*soci)[i]);
+    if(retval) return retval;
+  }
+  (*soci)[2] = NULL;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_cred_info(ci)
+     krb5_cred_info * ci;
+{
+  krb5_error_code retval;
+
+  ci->session = (krb5_keyblock*)calloc(1,sizeof(krb5_keyblock));
+  if(ci->session == NULL) return ENOMEM;
+  retval = ktest_make_sample_keyblock(ci->session);
+  if(retval) return retval;
+  retval = ktest_make_sample_principal(&(ci->client));
+  if(retval) return retval;
+  retval = ktest_make_sample_principal(&(ci->server));
+  if(retval) return retval;
+  ci->flags = SAMPLE_FLAGS;
+  ci->times.authtime = SAMPLE_TIME;
+  ci->times.starttime = SAMPLE_TIME;
+  ci->times.endtime = SAMPLE_TIME;
+  ci->times.renew_till = SAMPLE_TIME;
+  retval = ktest_make_sample_addresses(&(ci->caddrs));
+  if(retval) return retval;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_error(kerr)
+     krb5_error * kerr;
+{
+  krb5_error_code retval;
+
+  kerr->ctime = SAMPLE_TIME;
+  kerr->cusec = SAMPLE_USEC;
+  kerr->susec = SAMPLE_USEC;
+  kerr->stime = SAMPLE_TIME;
+  kerr->error = SAMPLE_ERROR;
+  retval = ktest_make_sample_principal(&(kerr->client));
+  if(retval) return retval;
+  retval = ktest_make_sample_principal(&(kerr->server));
+  if(retval) return retval;
+  retval = ktest_make_sample_data(&(kerr->text));
+  if(retval) return retval;
+  retval = ktest_make_sample_data(&(kerr->e_data));
+  if(retval) return retval;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_data(d)
+     krb5_data * d;
+{
+  d->data = (char*)calloc(8,sizeof(char));
+  if(d->data == NULL) return ENOMEM;
+  d->length = 8;
+  memcpy(d->data,"krb5data",8);
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_passwd_phrase_element(ppe)
+     passwd_phrase_element * ppe;
+{
+  krb5_error_code retval;
+
+  ppe->passwd = (krb5_data*)calloc(1,sizeof(krb5_data));
+  if(ppe->passwd == NULL) return ENOMEM;
+  retval = ktest_make_sample_data(ppe->passwd);
+  if(retval) return retval;
+  ppe->phrase = (krb5_data*)calloc(1,sizeof(krb5_data));
+  if(ppe->phrase == NULL) return ENOMEM;
+  retval = ktest_make_sample_data(ppe->phrase);
+  if(retval) return retval;
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_krb5_pwd_data(pd)
+     krb5_pwd_data * pd;
+{
+  krb5_error_code retval;
+  int i;
+
+  pd->sequence_count = 2;
+
+  pd->element = (passwd_phrase_element**)calloc(3,sizeof(passwd_phrase_element*));
+  if(pd->element == NULL) return ENOMEM;
+
+  for(i=0; i<=1; i++){
+    pd->element[i] = (passwd_phrase_element*)calloc(1,sizeof(passwd_phrase_element));
+    if(pd->element[i] == NULL) return ENOMEM;
+    retval = ktest_make_sample_passwd_phrase_element(pd->element[i]);
+    if(retval) return retval;
+  }
+  pd->element[2] = NULL;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_alt_method(p)
+     krb5_alt_method * p;
+{
+    p->method = 42;
+    p->data = (krb5_octet *) strdup("secret");
+    if(p->data == NULL) return ENOMEM;
+    p->length = strlen((char *) p->data);
+    return 0;
+}
+
+krb5_error_code ktest_make_sample_etype_info(p)
+     krb5_etype_info_entry *** p;
+{
+    krb5_etype_info_entry **info;
+    int	i;
+    char buf[80];
+
+    info = malloc(sizeof(krb5_etype_info_entry *) * 4);
+    if (!info)
+	return ENOMEM;
+    memset(info, 0, sizeof(krb5_etype_info_entry *) * 4);
+
+    for (i=0; i < 3; i++) {
+	info[i] = malloc(sizeof(krb5_etype_info_entry));
+	if (info[i] == 0)
+	    goto memfail;
+	info[i]->etype = i;
+	sprintf(buf, "Morton's #%d", i);
+	info[i]->length = strlen(buf);
+	info[i]->salt = malloc((size_t) (info[i]->length+1));
+	if (info[i]->salt == 0)
+	    goto memfail;
+	strcpy((char *) info[i]->salt, buf);
+	info[i]->s2kparams.data = NULL;
+	info[i]->s2kparams.length = 0;
+	info[i]->magic = KV5M_ETYPE_INFO_ENTRY;
+    }
+    free(info[1]->salt);
+    info[1]->length = KRB5_ETYPE_NO_SALT;
+    info[1]->salt = 0;
+    *p = info;
+    return 0;
+memfail:
+    ktest_destroy_etype_info(info);
+    return ENOMEM;
+}
+
+
+krb5_error_code ktest_make_sample_etype_info2(p)
+     krb5_etype_info_entry *** p;
+{
+    krb5_etype_info_entry **info;
+    int	i;
+    char buf[80];
+
+    info = malloc(sizeof(krb5_etype_info_entry *) * 4);
+    if (!info)
+	return ENOMEM;
+    memset(info, 0, sizeof(krb5_etype_info_entry *) * 4);
+
+    for (i=0; i < 3; i++) {
+	info[i] = malloc(sizeof(krb5_etype_info_entry));
+	if (info[i] == 0)
+	    goto memfail;
+	info[i]->etype = i;
+	sprintf(buf, "Morton's #%d", i);
+	info[i]->length = strlen(buf);
+	info[i]->salt = malloc((size_t) (info[i]->length+1));
+	if (info[i]->salt == 0)
+	    goto memfail;
+	strcpy((char *) info[i]->salt, buf);
+	sprintf(buf, "s2k: %d", i);
+	info[i]->s2kparams.data = malloc(strlen(buf)+1);
+	if (info[i]->s2kparams.data == NULL)
+	    goto memfail;
+	strcpy( info[i]->s2kparams.data, buf);
+	info[i]->s2kparams.length = strlen(buf);
+	info[i]->magic = KV5M_ETYPE_INFO_ENTRY;
+    }
+    free(info[1]->salt);
+    info[1]->length = KRB5_ETYPE_NO_SALT;
+    info[1]->salt = 0;
+    *p = info;
+    return 0;
+memfail:
+    ktest_destroy_etype_info(info);
+    return ENOMEM;
+}
+
+
+krb5_error_code ktest_make_sample_pa_enc_ts(pa_enc)
+     krb5_pa_enc_ts * pa_enc;
+{
+  pa_enc->patimestamp = SAMPLE_TIME;
+  pa_enc->pausec = SAMPLE_USEC;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_sam_challenge(p)
+     krb5_sam_challenge * p;
+{
+  krb5_error_code retval;
+
+  p->magic = KV5M_SAM_CHALLENGE;
+  p->sam_type = 42; /* information */
+  p->sam_flags = KRB5_SAM_USE_SAD_AS_KEY; /* KRB5_SAM_* values */
+  p->sam_type_name.data = strdup("type name");
+  if (p->sam_type_name.data == NULL) return ENOMEM;
+  p->sam_type_name.length = strlen(p->sam_type_name.data);
+  p->sam_track_id.data = 0;
+  p->sam_track_id.length = 0;
+  p->sam_challenge_label.data = strdup("challenge label");
+  if (p->sam_challenge_label.data == NULL) return ENOMEM;
+  p->sam_challenge_label.length = strlen(p->sam_challenge_label.data);
+  p->sam_challenge.data = strdup("challenge ipse");
+  if (p->sam_challenge.data == NULL) return ENOMEM;
+  p->sam_challenge.length = strlen(p->sam_challenge.data);
+  p->sam_response_prompt.data = strdup("response_prompt ipse");
+  if (p->sam_response_prompt.data == NULL) return ENOMEM;
+  p->sam_response_prompt.length = strlen(p->sam_response_prompt.data);
+  p->sam_pk_for_sad.data = 0;
+  p->sam_pk_for_sad.length = 0;
+  p->sam_nonce = 0x543210;
+  retval = ktest_make_sample_checksum(&p->sam_cksum);
+  if(retval) return retval;
+
+  return 0;
+}
+
+krb5_error_code ktest_make_sample_sam_response(p)
+     krb5_sam_response * p;
+{
+  p->magic = KV5M_SAM_RESPONSE;
+  p->sam_type = 42; /* information */
+  p->sam_flags = KRB5_SAM_USE_SAD_AS_KEY; /* KRB5_SAM_* values */
+  p->sam_track_id.data = strdup("track data");
+  if (p->sam_track_id.data == NULL) return ENOMEM;
+  p->sam_track_id.length = strlen(p->sam_track_id.data);
+  p->sam_enc_key.ciphertext.data = strdup("key");
+  if (p->sam_enc_key.ciphertext.data == NULL) return ENOMEM;
+  p->sam_enc_key.ciphertext.length = strlen(p->sam_enc_key.ciphertext.data);
+  p->sam_enc_key.enctype = ENCTYPE_DES_CBC_CRC;
+  p->sam_enc_key.kvno = 1942;
+  p->sam_enc_nonce_or_ts.ciphertext.data = strdup("nonce or ts");
+  if (p->sam_enc_nonce_or_ts.ciphertext.data == NULL) return ENOMEM;
+  p->sam_enc_nonce_or_ts.ciphertext.length = 
+    strlen(p->sam_enc_nonce_or_ts.ciphertext.data);
+  p->sam_enc_nonce_or_ts.enctype = ENCTYPE_DES_CBC_CRC;
+  p->sam_enc_nonce_or_ts.kvno = 3382;
+  p->sam_nonce = 0x543210;
+  p->sam_patimestamp = SAMPLE_TIME;
+
+  return 0;
+}
+
+
+
+
+
+/****************************************************************/
+/* destructors */
+
+void ktest_destroy_data(d)
+     krb5_data ** d;
+{
+  if(*d != NULL){
+    if((*d)->data != NULL) free((*d)->data);
+    free(*d);
+    *d = NULL;
+  }
+}
+
+void ktest_empty_data(d)
+     krb5_data * d;
+{
+  if(d->data != NULL){
+    free(d->data);
+    d->data = NULL;
+    d->length = 0;
+  }
+}  
+
+void ktest_destroy_checksum(cs)
+     krb5_checksum ** cs;
+{
+  if(*cs != NULL){
+    if((*cs)->contents != NULL) free((*cs)->contents);
+    free(*cs);
+    *cs = NULL;
+  }
+}
+
+void ktest_empty_keyblock(kb)
+     krb5_keyblock * kb;
+{
+  if (kb != NULL) {
+    if (kb->contents) {
+      free (kb->contents);
+      kb->contents = NULL;
+    }
+  }
+}
+
+void ktest_destroy_keyblock(kb)
+     krb5_keyblock ** kb;
+{
+  if(*kb != NULL){
+    if((*kb)->contents != NULL) free((*kb)->contents);
+    free(*kb);
+    *kb = NULL;
+  }
+}
+
+void ktest_empty_authorization_data(ad)
+     krb5_authdata ** ad;
+{
+  int i;
+
+  if(*ad != NULL) {
+    for(i=0; ad[i] != NULL; i++)
+      ktest_destroy_authdata(&(ad[i]));
+  }
+}
+
+void ktest_destroy_authorization_data(ad)
+     krb5_authdata *** ad;
+{
+  ktest_empty_authorization_data(*ad);
+  free(*ad);
+  *ad = NULL;
+}
+
+void ktest_destroy_authdata(ad)
+     krb5_authdata ** ad;
+{
+  if(*ad != NULL){
+    if((*ad)->contents != NULL) free((*ad)->contents);
+    free(*ad);
+    *ad = NULL;
+  }
+}
+
+void ktest_empty_pa_data_array(pad)
+     krb5_pa_data ** pad;
+{
+  int i;
+
+  for(i=0; pad[i] != NULL; i++)
+    ktest_destroy_pa_data(&(pad[i]));
+}
+
+void ktest_destroy_pa_data_array(pad)
+     krb5_pa_data *** pad;
+{
+  ktest_empty_pa_data_array(*pad);
+  free(*pad);
+  *pad = NULL;
+}
+
+void ktest_destroy_pa_data(pad)
+     krb5_pa_data ** pad;
+{
+  if(*pad != NULL){
+    if((*pad)->contents != NULL) free((*pad)->contents);
+    free(*pad);
+    *pad = NULL;
+  }
+}
+
+
+void ktest_destroy_address(a)
+     krb5_address ** a;
+{
+  if(*a != NULL){
+    if((*a)->contents != NULL) free((*a)->contents);
+    free(*a);
+    *a = NULL;
+  }
+}
+
+void ktest_empty_addresses(a)
+     krb5_address ** a;
+{
+  int i;
+
+  for(i=0; a[i] != NULL; i++)
+    ktest_destroy_address(&(a[i]));
+}  
+
+void ktest_destroy_addresses(a)
+     krb5_address *** a;
+{
+  ktest_empty_addresses(*a);
+  free(*a);
+  *a = NULL;
+}
+
+void ktest_destroy_principal(p)
+     krb5_principal * p;
+{
+  int i;
+
+  for(i=0; i<(*p)->length; i++)
+    ktest_empty_data(&(((*p)->data)[i]));
+  ktest_empty_data(&((*p)->realm));
+  free((*p)->data);
+  free(*p);
+  *p = NULL;
+}
+
+void ktest_destroy_sequence_of_integer(soi)
+     long ** soi;
+{
+  free(*soi);
+  *soi = NULL;
+}
+
+#if 0
+void ktest_destroy_sequence_of_enctype(soi)
+     krb5_enctype ** soi;
+{
+  free(*soi);
+  *soi = NULL;
+}
+#endif
+
+void ktest_destroy_sequence_of_ticket(sot)
+     krb5_ticket *** sot;
+{
+  int i;
+
+  for(i=0; (*sot)[i] != NULL; i++)
+    ktest_destroy_ticket(&((*sot)[i]));
+  free(*sot);
+  *sot = NULL;
+}
+
+void ktest_destroy_ticket(tkt)
+     krb5_ticket ** tkt;
+{
+  ktest_destroy_principal(&((*tkt)->server));
+  ktest_destroy_enc_data(&((*tkt)->enc_part));
+  /*  ktest_empty_enc_tkt_part(((*tkt)->enc_part2));*/
+  free(*tkt);
+  *tkt = NULL;
+}  
+
+void ktest_empty_ticket(tkt)
+     krb5_ticket * tkt;
+{
+  if(tkt->server)
+    ktest_destroy_principal(&((tkt)->server));
+  ktest_destroy_enc_data(&((tkt)->enc_part));
+  if (tkt->enc_part2) {
+    ktest_destroy_enc_tkt_part(&(tkt->enc_part2));
+  }
+}  
+
+void ktest_destroy_enc_data(ed)
+     krb5_enc_data * ed;
+{
+  ktest_empty_data(&(ed->ciphertext));
+  ed->kvno = 0;
+}
+
+void ktest_destroy_etype_info_entry(i)
+    krb5_etype_info_entry *i;
+{
+    if (i->salt)
+	free(i->salt);
+    ktest_empty_data(&(i->s2kparams));
+    free(i);
+}
+
+void ktest_destroy_etype_info(info)
+    krb5_etype_info_entry **info;
+{
+  int i;
+
+  for(i=0; info[i] != NULL; i++)
+      ktest_destroy_etype_info_entry(info[i]);
+  free(info);
+}
+    
+
+void ktest_empty_kdc_req(kr)
+     krb5_kdc_req *kr;
+{
+  if (kr->padata)
+      ktest_destroy_pa_data_array(&(kr->padata));
+
+  if (kr->client)
+      ktest_destroy_principal(&(kr->client));
+
+  if (kr->server)
+      ktest_destroy_principal(&(kr->server));
+  if (kr->ktype)
+      free(kr->ktype);
+  if (kr->addresses)
+      ktest_destroy_addresses(&(kr->addresses));
+      ktest_destroy_enc_data(&(kr->authorization_data));
+  if (kr->unenc_authdata)
+      ktest_destroy_authorization_data(&(kr->unenc_authdata));
+  if (kr->second_ticket)
+      ktest_destroy_sequence_of_ticket(&(kr->second_ticket));
+
+}
+
+void ktest_empty_kdc_rep(kr)
+     krb5_kdc_rep *kr;
+{
+  if (kr->padata)
+      ktest_destroy_pa_data_array(&(kr->padata));
+
+  if (kr->client)
+      ktest_destroy_principal(&(kr->client));
+
+  if (kr->ticket)
+      ktest_destroy_ticket(&(kr->ticket));
+
+  ktest_destroy_enc_data(&kr->enc_part);
+
+  if (kr->enc_part2) {
+    ktest_empty_enc_kdc_rep_part(kr->enc_part2);
+    free(kr->enc_part2);
+    kr->enc_part2 = NULL;
+  }
+}
+
+
+void ktest_empty_authenticator(a)
+     krb5_authenticator * a;
+{
+
+  if(a->client) 
+    ktest_destroy_principal(&(a->client));
+  if(a->checksum)
+    ktest_destroy_checksum(&(a->checksum));
+  if(a->subkey)
+    ktest_destroy_keyblock(&(a->subkey));
+  if(a->authorization_data)
+    ktest_destroy_authorization_data(&(a->authorization_data));
+}
+
+void ktest_empty_enc_tkt_part(etp)
+     krb5_enc_tkt_part * etp;
+{
+
+  if(etp->session)
+    ktest_destroy_keyblock(&(etp->session));
+  if(etp->client) 
+    ktest_destroy_principal(&(etp->client));
+  if (etp->caddrs)
+      ktest_destroy_addresses(&(etp->caddrs));
+  if(etp->authorization_data)
+    ktest_destroy_authorization_data(&(etp->authorization_data));
+  ktest_destroy_transited(&(etp->transited));
+}
+
+void ktest_destroy_enc_tkt_part(etp)
+     krb5_enc_tkt_part ** etp;
+{
+  if(*etp) {
+    ktest_empty_enc_tkt_part(*etp);
+    free(*etp);
+    *etp = NULL;
+  }
+}
+
+void ktest_empty_enc_kdc_rep_part(ekr)
+     krb5_enc_kdc_rep_part * ekr;
+{
+
+  if(ekr->session)
+    ktest_destroy_keyblock(&(ekr->session));
+
+  if(ekr->server) 
+    ktest_destroy_principal(&(ekr->server));
+
+  if (ekr->caddrs)
+    ktest_destroy_addresses(&(ekr->caddrs));
+  ktest_destroy_last_req(&(ekr->last_req));
+}
+
+
+void ktest_destroy_transited(t)
+     krb5_transited * t;
+{
+  if(t->tr_contents.data)
+    ktest_empty_data(&(t->tr_contents));
+}
+
+
+void ktest_empty_ap_rep(ar)
+     krb5_ap_rep * ar;
+{
+  ktest_destroy_enc_data(&ar->enc_part);
+}
+
+void ktest_empty_ap_req(ar)
+     krb5_ap_req * ar;
+{
+
+  if(ar->ticket)
+      ktest_destroy_ticket(&(ar->ticket));
+  ktest_destroy_enc_data(&(ar->authenticator));
+}
+
+void ktest_empty_cred_enc_part(cep)
+     krb5_cred_enc_part * cep;
+{
+  if (cep->s_address)
+      ktest_destroy_address(&(cep->s_address));
+  if (cep->r_address)
+      ktest_destroy_address(&(cep->r_address));
+  if (cep->ticket_info)
+    ktest_destroy_sequence_of_cred_info(&(cep->ticket_info));
+}
+
+void ktest_destroy_cred_info(ci)
+     krb5_cred_info ** ci;
+{
+  if((*ci)->session)
+    ktest_destroy_keyblock(&((*ci)->session));
+  if((*ci)->client) 
+    ktest_destroy_principal(&((*ci)->client));
+  if((*ci)->server) 
+    ktest_destroy_principal(&((*ci)->server));
+  if ((*ci)->caddrs)
+    ktest_destroy_addresses(&((*ci)->caddrs));
+  free(*ci);
+  *ci = NULL;
+}
+
+void ktest_destroy_sequence_of_cred_info(soci)
+     krb5_cred_info *** soci;
+{
+  int i;
+
+  for(i=0; (*soci)[i] != NULL; i++)
+    ktest_destroy_cred_info(&((*soci)[i]));
+  free(*soci);
+  *soci = NULL;
+}
+
+
+void ktest_empty_safe(s)
+     krb5_safe * s;
+{
+  ktest_empty_data(&(s->user_data));
+  ktest_destroy_address(&(s->s_address));
+  ktest_destroy_address(&(s->r_address));
+  ktest_destroy_checksum(&(s->checksum));
+}
+
+void ktest_empty_priv_enc_part(pep)
+     krb5_priv_enc_part * pep;
+{
+  ktest_empty_data(&(pep->user_data));
+  ktest_destroy_address(&(pep->s_address));
+  ktest_destroy_address(&(pep->r_address));
+}
+
+void ktest_empty_priv(p)
+     krb5_priv * p;
+{
+  ktest_destroy_enc_data(&(p->enc_part));
+}
+
+void ktest_empty_cred(c)
+     krb5_cred * c;
+{
+
+  ktest_destroy_sequence_of_ticket(&(c->tickets));
+  ktest_destroy_enc_data(&(c->enc_part));
+  /* enc_part2 */
+
+}
+
+void ktest_destroy_last_req(lr)
+     krb5_last_req_entry *** lr;
+{
+  int i;
+
+  if(*lr) {
+    for(i=0; (*lr)[i] != NULL; i++) {
+      free((*lr)[i]);
+    }
+    free(*lr);
+  }
+}
+
+void ktest_empty_error(kerr)
+     krb5_error * kerr;
+{
+  if(kerr->client)
+    ktest_destroy_principal(&(kerr->client));
+  if(kerr->server)
+    ktest_destroy_principal(&(kerr->server));
+  ktest_empty_data(&(kerr->text));
+  ktest_empty_data(&(kerr->e_data));
+}
+
+void ktest_empty_ap_rep_enc_part(arep)
+     krb5_ap_rep_enc_part * arep;
+{
+  ktest_destroy_keyblock(&((arep)->subkey));
+}
+
+void ktest_empty_passwd_phrase_element(ppe)
+     passwd_phrase_element * ppe;
+{
+  ktest_destroy_data(&(ppe->passwd));
+  ktest_destroy_data(&(ppe->phrase));
+}
+
+void ktest_empty_pwd_data(pd)
+     krb5_pwd_data * pd;
+{
+  int i;
+
+  for(i=0; i <= pd->sequence_count; i++){
+    if(pd->element[i]) {
+      ktest_empty_passwd_phrase_element(pd->element[i]);
+      free(pd->element[i]);
+      pd->element[i] = NULL;
+    }
+  }
+  free(pd->element);
+  
+}
+
+void ktest_empty_alt_method(am)
+     krb5_alt_method *am;
+{
+  if (am->data) {
+    free(am->data);
+    am->data = NULL;
+  }
+}
+
+void ktest_empty_sam_challenge(p)
+     krb5_sam_challenge * p;
+{
+  ktest_empty_data(&(p->sam_type_name));
+  ktest_empty_data(&(p->sam_track_id));
+  ktest_empty_data(&(p->sam_challenge_label));
+  ktest_empty_data(&(p->sam_challenge));
+  ktest_empty_data(&(p->sam_response_prompt));
+  ktest_empty_data(&(p->sam_pk_for_sad));
+
+  if(p->sam_cksum.contents != NULL) {
+    free(p->sam_cksum.contents);
+    p->sam_cksum.contents = NULL;
+  }
+
+}
+
+void ktest_empty_sam_response(p)
+     krb5_sam_response * p;
+{
+  ktest_empty_data(&(p->sam_track_id));
+  ktest_empty_data(&(p->sam_enc_key.ciphertext));
+  ktest_empty_data(&(p->sam_enc_nonce_or_ts.ciphertext));
+}
diff --git a/mechglue/src/tests/asn.1/ktest.h b/mechglue/src/tests/asn.1/ktest.h
new file mode 100644
index 000000000..915f36a00
--- /dev/null
+++ b/mechglue/src/tests/asn.1/ktest.h
@@ -0,0 +1,204 @@
+#ifndef __KTEST_H__
+#define __KTEST_H__
+
+#include "k5-int.h"
+
+#define SAMPLE_USEC 123456
+#define SAMPLE_TIME 771228197  /* Fri Jun 10  6:03:17 GMT 1994 */
+#define SAMPLE_SEQ_NUMBER 17
+#define SAMPLE_NONCE 42
+#define SAMPLE_FLAGS 0xFEDCBA98
+#define SAMPLE_ERROR 0x3C;
+krb5_error_code ktest_make_sample_data
+	(krb5_data *d);
+krb5_error_code ktest_make_sample_authenticator
+	(krb5_authenticator *a);
+  krb5_error_code ktest_make_sample_principal
+	(krb5_principal *p);
+  krb5_error_code ktest_make_sample_checksum
+	(krb5_checksum *cs);
+  krb5_error_code ktest_make_sample_keyblock
+	(krb5_keyblock *kb);
+krb5_error_code ktest_make_sample_ticket
+	(krb5_ticket *tkt);
+  krb5_error_code ktest_make_sample_enc_data
+	(krb5_enc_data *ed);
+krb5_error_code ktest_make_sample_enc_tkt_part
+	(krb5_enc_tkt_part *etp);
+  krb5_error_code ktest_make_sample_transited
+	(krb5_transited *t);
+  krb5_error_code ktest_make_sample_ticket_times
+	(krb5_ticket_times *tt);
+  krb5_error_code ktest_make_sample_addresses
+	(krb5_address ***caddrs);
+  krb5_error_code ktest_make_sample_address
+	(krb5_address *a);
+  krb5_error_code ktest_make_sample_authorization_data
+	(krb5_authdata ***ad);
+  krb5_error_code ktest_make_sample_authdata
+	(krb5_authdata *ad);
+krb5_error_code ktest_make_sample_enc_kdc_rep_part
+	(krb5_enc_kdc_rep_part *ekr);
+krb5_error_code ktest_make_sample_kdc_req
+	(krb5_kdc_req *kr);
+
+  krb5_error_code ktest_make_sample_last_req
+	(krb5_last_req_entry ***lr);
+  krb5_error_code ktest_make_sample_last_req_entry
+	(krb5_last_req_entry **lre);
+krb5_error_code ktest_make_sample_kdc_rep
+	(krb5_kdc_rep *kdcr);
+  krb5_error_code ktest_make_sample_pa_data_array
+	(krb5_pa_data ***pad);
+  krb5_error_code ktest_make_sample_empty_pa_data_array
+	(krb5_pa_data ***pad);
+  krb5_error_code ktest_make_sample_pa_data
+	(krb5_pa_data *pad);
+krb5_error_code ktest_make_sample_ap_req
+	(krb5_ap_req *ar);
+krb5_error_code ktest_make_sample_ap_rep
+	(krb5_ap_rep *ar);
+krb5_error_code ktest_make_sample_ap_rep_enc_part
+	(krb5_ap_rep_enc_part *arep);
+krb5_error_code ktest_make_sample_kdc_req_body
+	(krb5_kdc_req *krb);
+krb5_error_code ktest_make_sample_safe
+	(krb5_safe *s);
+krb5_error_code ktest_make_sample_priv
+	(krb5_priv *p);
+krb5_error_code ktest_make_sample_priv_enc_part
+	(krb5_priv_enc_part *pep);
+krb5_error_code ktest_make_sample_cred
+	(krb5_cred *c);
+krb5_error_code ktest_make_sample_cred_enc_part
+	(krb5_cred_enc_part *cep);
+  krb5_error_code ktest_make_sample_sequence_of_ticket
+	(krb5_ticket ***sot);
+krb5_error_code ktest_make_sample_error
+	(krb5_error *kerr);
+krb5_error_code ktest_make_sequence_of_cred_info
+	(krb5_cred_info ***soci);
+  krb5_error_code ktest_make_sample_cred_info
+	(krb5_cred_info *ci);
+krb5_error_code ktest_make_sample_passwd_phrase_element
+	(passwd_phrase_element *ppe);
+krb5_error_code ktest_make_sample_krb5_pwd_data
+	(krb5_pwd_data *pd);
+krb5_error_code ktest_make_sample_alt_method
+	(krb5_alt_method *am);
+
+krb5_error_code ktest_make_sample_etype_info
+    (krb5_etype_info_entry *** p);
+krb5_error_code ktest_make_sample_etype_info2
+    (krb5_etype_info_entry *** p);
+krb5_error_code ktest_make_sample_pa_enc_ts
+	(krb5_pa_enc_ts *am);
+krb5_error_code ktest_make_sample_sam_challenge
+	(krb5_sam_challenge * p);
+krb5_error_code ktest_make_sample_sam_response
+	(krb5_sam_response * p);
+
+/*----------------------------------------------------------------------*/
+
+void ktest_empty_authorization_data
+	(krb5_authdata **ad);
+void ktest_destroy_authorization_data
+	(krb5_authdata ***ad);
+  void ktest_destroy_authorization_data
+	(krb5_authdata ***ad);
+void ktest_empty_addresses
+	(krb5_address **a);
+void ktest_destroy_addresses
+	(krb5_address ***a);
+  void ktest_destroy_address
+	(krb5_address **a);
+void ktest_empty_pa_data_array
+	(krb5_pa_data **pad);
+void ktest_destroy_pa_data_array
+	(krb5_pa_data ***pad);
+  void ktest_destroy_pa_data
+	(krb5_pa_data **pad);
+
+void ktest_destroy_data
+	(krb5_data **d);
+void ktest_empty_data
+	(krb5_data *d);
+void ktest_destroy_principal
+	(krb5_principal *p);
+void ktest_destroy_checksum
+	(krb5_checksum **cs);
+void ktest_empty_keyblock
+	(krb5_keyblock *kb);
+void ktest_destroy_keyblock
+	(krb5_keyblock **kb);
+void ktest_destroy_authdata
+	(krb5_authdata **ad);
+void ktest_destroy_sequence_of_integer
+	(long **soi);
+void ktest_destroy_sequence_of_ticket
+	(krb5_ticket ***sot);
+  void ktest_destroy_ticket
+	(krb5_ticket **tkt);
+void ktest_empty_ticket
+	(krb5_ticket *tkt);
+void ktest_destroy_enc_data
+	(krb5_enc_data *ed);
+void ktest_empty_error
+        (krb5_error * kerr);
+void ktest_destroy_etype_info_entry
+	(krb5_etype_info_entry *i);
+void ktest_destroy_etype_info
+	(krb5_etype_info_entry **info);
+
+void ktest_empty_kdc_req
+        (krb5_kdc_req *kr);
+void ktest_empty_kdc_rep
+        (krb5_kdc_rep *kr);
+
+void ktest_empty_authenticator
+        (krb5_authenticator *a);
+void ktest_empty_enc_tkt_part
+        (krb5_enc_tkt_part * etp);
+void ktest_destroy_enc_tkt_part
+        (krb5_enc_tkt_part ** etp);
+void ktest_empty_enc_kdc_rep_part
+        (krb5_enc_kdc_rep_part * ekr);
+void ktest_destroy_transited
+        (krb5_transited * t);
+void ktest_empty_ap_rep
+        (krb5_ap_rep * ar);
+void ktest_empty_ap_req
+        (krb5_ap_req * ar);
+void ktest_empty_cred_enc_part
+        (krb5_cred_enc_part * cep);
+void ktest_destroy_cred_info
+        (krb5_cred_info ** ci);
+void ktest_destroy_sequence_of_cred_info
+        (krb5_cred_info *** soci);
+void ktest_empty_safe
+        (krb5_safe * s);
+void ktest_empty_priv
+        (krb5_priv * p);
+void ktest_empty_priv_enc_part
+        (krb5_priv_enc_part * pep);
+void ktest_empty_cred
+        (krb5_cred * c);
+void ktest_destroy_last_req
+        (krb5_last_req_entry *** lr);
+void ktest_empty_ap_rep_enc_part
+        (krb5_ap_rep_enc_part * arep);
+void ktest_empty_passwd_phrase_element
+        (passwd_phrase_element * ppe);
+void ktest_empty_pwd_data
+        (krb5_pwd_data * pd);
+void ktest_empty_alt_method
+	(krb5_alt_method *am);
+void ktest_empty_sam_challenge
+	(krb5_sam_challenge * p);
+void ktest_empty_sam_response
+	(krb5_sam_response * p);
+
+extern krb5_context test_context;
+extern char *sample_principal_name;
+
+#endif
diff --git a/mechglue/src/tests/asn.1/ktest_equal.c b/mechglue/src/tests/asn.1/ktest_equal.c
new file mode 100644
index 000000000..7f2fa44b1
--- /dev/null
+++ b/mechglue/src/tests/asn.1/ktest_equal.c
@@ -0,0 +1,669 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "ktest_equal.h"
+
+#define FALSE 0
+#define TRUE 1
+
+#define struct_equal(field,comparator)\
+comparator(&(ref->field),&(var->field))
+
+#define ptr_equal(field,comparator)\
+comparator(ref->field,var->field)
+
+#define scalar_equal(field)\
+((ref->field) == (var->field))
+
+#define len_equal(length,field,comparator)\
+((ref->length == var->length) && \
+ comparator(ref->length,ref->field,var->field))
+
+int ktest_equal_authenticator(ref, var)
+     krb5_authenticator * ref;
+     krb5_authenticator * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p = p && ptr_equal(client,ktest_equal_principal_data);
+  p = p && ptr_equal(checksum,ktest_equal_checksum);
+  p = p && scalar_equal(cusec);
+  p = p && scalar_equal(ctime);
+  p = p && ptr_equal(subkey,ktest_equal_keyblock);
+  p = p && scalar_equal(seq_number);
+  p = p && ptr_equal(authorization_data,ktest_equal_authorization_data);
+  return p;
+}
+
+int ktest_equal_principal_data(ref, var)
+     krb5_principal_data * ref;
+     krb5_principal_data * var;
+{
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  return(struct_equal(realm,ktest_equal_data) &&
+	 len_equal(length,data,ktest_equal_array_of_data) &&
+	 scalar_equal(type));
+}
+
+int ktest_equal_authdata(ref, var)
+     krb5_authdata * ref;
+     krb5_authdata * var;
+{
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  return(scalar_equal(ad_type) &&
+	 len_equal(length,contents,ktest_equal_array_of_octet));
+}
+
+int ktest_equal_checksum(ref, var)
+     krb5_checksum * ref;
+     krb5_checksum * var;
+{
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  return(scalar_equal(checksum_type) && len_equal(length,contents,ktest_equal_array_of_octet));
+}
+
+int ktest_equal_keyblock(ref, var)
+     krb5_keyblock * ref;
+     krb5_keyblock * var;
+{
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  return(scalar_equal(enctype) && len_equal(length,contents,ktest_equal_array_of_octet));
+}
+
+int ktest_equal_data(ref, var)
+     krb5_data * ref;
+     krb5_data * var;
+{
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  return(len_equal(length,data,ktest_equal_array_of_char));
+}
+
+int ktest_equal_ticket(ref, var)
+     krb5_ticket * ref;
+     krb5_ticket * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p = p && ptr_equal(server,ktest_equal_principal_data);
+  p = p && struct_equal(enc_part,ktest_equal_enc_data);
+  /* enc_part2 is irrelevant, as far as the ASN.1 code is concerned */
+  return p;
+}
+
+int ktest_equal_enc_data(ref, var)
+     krb5_enc_data * ref;
+     krb5_enc_data * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(enctype);
+  p=p&&scalar_equal(kvno);
+  p=p&&struct_equal(ciphertext,ktest_equal_data);
+  return p;
+}
+
+int ktest_equal_encryption_key(ref, var)
+     krb5_keyblock * ref;
+     krb5_keyblock * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p = p && scalar_equal(enctype);
+  p = p && len_equal(length,contents,ktest_equal_array_of_octet);
+  return p;
+}
+
+int ktest_equal_enc_tkt_part(ref, var)
+     krb5_enc_tkt_part * ref;
+     krb5_enc_tkt_part * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p = p && scalar_equal(flags);
+  p = p && ptr_equal(session,ktest_equal_encryption_key);
+  p = p && ptr_equal(client,ktest_equal_principal_data);
+  p = p && struct_equal(transited,ktest_equal_transited);
+  p = p && struct_equal(times,ktest_equal_ticket_times);
+  p = p && ptr_equal(caddrs,ktest_equal_addresses);
+  p = p && ptr_equal(authorization_data,ktest_equal_authorization_data);
+  return p;
+}
+
+int ktest_equal_transited(ref, var)
+     krb5_transited * ref;
+     krb5_transited * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p = p && scalar_equal(tr_type);
+  p = p && struct_equal(tr_contents,ktest_equal_data);
+  return p;
+}
+
+int ktest_equal_ticket_times(ref, var)
+     krb5_ticket_times * ref;
+     krb5_ticket_times * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p = p && scalar_equal(authtime);
+  p = p && scalar_equal(starttime);
+  p = p && scalar_equal(endtime);
+  p = p && scalar_equal(renew_till);
+  return p;
+}
+
+int ktest_equal_address(ref, var)
+     krb5_address * ref;
+     krb5_address * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(addrtype);
+  p=p&&len_equal(length,contents,ktest_equal_array_of_octet);
+  return p;
+}
+
+int ktest_equal_enc_kdc_rep_part(ref, var)
+     krb5_enc_kdc_rep_part * ref;
+     krb5_enc_kdc_rep_part * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&ptr_equal(session,ktest_equal_keyblock);
+  p=p&&ptr_equal(last_req,ktest_equal_last_req);
+  p=p&&scalar_equal(nonce);
+  p=p&&scalar_equal(key_exp);
+  p=p&&scalar_equal(flags);
+  p=p&&struct_equal(times,ktest_equal_ticket_times);
+  p=p&&ptr_equal(server,ktest_equal_principal_data);
+  p=p&&ptr_equal(caddrs,ktest_equal_addresses);
+  return p;
+}
+
+int ktest_equal_priv(ref, var)
+     krb5_priv * ref;
+     krb5_priv * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&struct_equal(enc_part,ktest_equal_enc_data);
+  return p;
+}
+
+int ktest_equal_cred(ref, var)
+     krb5_cred * ref;
+     krb5_cred * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&ptr_equal(tickets,ktest_equal_sequence_of_ticket);
+  p=p&&struct_equal(enc_part,ktest_equal_enc_data);
+  return p;
+}
+
+int ktest_equal_error(ref, var)
+     krb5_error * ref;
+     krb5_error * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(ctime);
+  p=p&&scalar_equal(cusec);
+  p=p&&scalar_equal(susec);
+  p=p&&scalar_equal(stime);
+  p=p&&scalar_equal(error);
+  p=p&&ptr_equal(client,ktest_equal_principal_data);
+  p=p&&ptr_equal(server,ktest_equal_principal_data);
+  p=p&&struct_equal(text,ktest_equal_data);
+  p=p&&struct_equal(e_data,ktest_equal_data);
+  return p;
+}
+
+int ktest_equal_ap_req(ref, var)
+     krb5_ap_req * ref;
+     krb5_ap_req * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(ap_options);
+  p=p&&ptr_equal(ticket,ktest_equal_ticket);
+  p=p&&struct_equal(authenticator,ktest_equal_enc_data);
+  return p;
+}
+
+int ktest_equal_ap_rep(ref, var)
+     krb5_ap_rep * ref;
+     krb5_ap_rep * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&struct_equal(enc_part,ktest_equal_enc_data);
+  return p;
+}
+
+int ktest_equal_ap_rep_enc_part(ref, var)
+     krb5_ap_rep_enc_part * ref;
+     krb5_ap_rep_enc_part * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(ctime);
+  p=p&&scalar_equal(cusec);
+  p=p&&ptr_equal(subkey,ktest_equal_encryption_key);
+  p=p&&scalar_equal(seq_number);
+  return p;
+}
+
+int ktest_equal_safe(ref, var)
+     krb5_safe * ref;
+     krb5_safe * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&struct_equal(user_data,ktest_equal_data);
+  p=p&&scalar_equal(timestamp);
+  p=p&&scalar_equal(usec);
+  p=p&&scalar_equal(seq_number);
+  p=p&&ptr_equal(s_address,ktest_equal_address);
+  p=p&&ptr_equal(r_address,ktest_equal_address);
+  p=p&&ptr_equal(checksum,ktest_equal_checksum);
+  return p;
+}
+
+
+int ktest_equal_enc_cred_part(ref, var)
+     krb5_cred_enc_part * ref;
+     krb5_cred_enc_part * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(nonce);
+  p=p&&scalar_equal(timestamp);
+  p=p&&scalar_equal(usec);
+  p=p&&ptr_equal(s_address,ktest_equal_address);
+  p=p&&ptr_equal(r_address,ktest_equal_address);
+  p=p&&ptr_equal(ticket_info,ktest_equal_sequence_of_cred_info);
+  return p;
+}
+
+int ktest_equal_enc_priv_part(ref, var)
+     krb5_priv_enc_part * ref;
+     krb5_priv_enc_part * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&struct_equal(user_data,ktest_equal_data);
+  p=p&&scalar_equal(timestamp);
+  p=p&&scalar_equal(usec);
+  p=p&&scalar_equal(seq_number);
+  p=p&&ptr_equal(s_address,ktest_equal_address);
+  p=p&&ptr_equal(r_address,ktest_equal_address);
+  return p;
+}
+
+int ktest_equal_as_rep(ref, var)
+     krb5_kdc_rep * ref;
+     krb5_kdc_rep * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(msg_type);
+  p=p&&ptr_equal(padata,ktest_equal_sequence_of_pa_data);
+  p=p&&ptr_equal(client,ktest_equal_principal_data);
+  p=p&&ptr_equal(ticket,ktest_equal_ticket);
+  p=p&&struct_equal(enc_part,ktest_equal_enc_data);
+  p=p&&ptr_equal(enc_part2,ktest_equal_enc_kdc_rep_part);
+  return p;
+}
+
+int ktest_equal_tgs_rep(ref, var)
+     krb5_kdc_rep * ref;
+     krb5_kdc_rep * var;
+{
+  return ktest_equal_as_rep(ref,var);
+}
+
+int ktest_equal_as_req(ref, var)
+     krb5_kdc_req * ref;
+     krb5_kdc_req * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(msg_type);
+  p=p&&ptr_equal(padata,ktest_equal_sequence_of_pa_data);
+  p=p&&scalar_equal(kdc_options);
+  p=p&&ptr_equal(client,ktest_equal_principal_data);
+  p=p&&ptr_equal(server,ktest_equal_principal_data);
+  p=p&&scalar_equal(from);
+  p=p&&scalar_equal(till);
+  p=p&&scalar_equal(rtime);
+  p=p&&scalar_equal(nonce);
+  p=p&&len_equal(nktypes,ktype,ktest_equal_array_of_enctype);
+  p=p&&ptr_equal(addresses,ktest_equal_addresses);
+  p=p&&struct_equal(authorization_data,ktest_equal_enc_data);
+/* This field isn't actually in the ASN.1 encoding. */
+/* p=p&&ptr_equal(unenc_authdata,ktest_equal_authorization_data); */
+  return p;
+}
+
+int ktest_equal_tgs_req(ref, var)
+     krb5_kdc_req * ref;
+     krb5_kdc_req * var;
+{
+  return ktest_equal_as_req(ref,var);
+}
+
+int ktest_equal_kdc_req_body(ref, var)
+     krb5_kdc_req * ref;
+     krb5_kdc_req * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(kdc_options);
+  p=p&&ptr_equal(client,ktest_equal_principal_data);
+  p=p&&ptr_equal(server,ktest_equal_principal_data);
+  p=p&&scalar_equal(from);
+  p=p&&scalar_equal(till);
+  p=p&&scalar_equal(rtime);
+  p=p&&scalar_equal(nonce);
+  p=p&&len_equal(nktypes,ktype,ktest_equal_array_of_enctype);
+  p=p&&ptr_equal(addresses,ktest_equal_addresses);
+  p=p&&struct_equal(authorization_data,ktest_equal_enc_data);
+  /* This isn't part of the ASN.1 encoding. */
+  /* p=p&&ptr_equal(unenc_authdata,ktest_equal_authorization_data); */
+  return p;
+}
+
+int ktest_equal_last_req_entry(ref, var)
+     krb5_last_req_entry * ref;
+     krb5_last_req_entry * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(lr_type);
+  p=p&&scalar_equal(value);
+  return p;
+}
+
+int ktest_equal_pa_data(ref, var)
+     krb5_pa_data * ref;
+     krb5_pa_data * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(pa_type);
+  p=p&&len_equal(length,contents,ktest_equal_array_of_octet);
+  return p;
+}
+
+int ktest_equal_cred_info(ref, var)
+     krb5_cred_info * ref;
+     krb5_cred_info * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&ptr_equal(session,ktest_equal_keyblock);
+  p=p&&ptr_equal(client,ktest_equal_principal_data);
+  p=p&&ptr_equal(server,ktest_equal_principal_data);
+  p=p&&scalar_equal(flags);
+  p=p&&struct_equal(times,ktest_equal_ticket_times);
+  p=p&&ptr_equal(caddrs,ktest_equal_addresses);
+
+  return p;
+}
+
+int ktest_equal_passwd_phrase_element(ref, var)
+     passwd_phrase_element * ref;
+     passwd_phrase_element * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&ptr_equal(passwd,ktest_equal_data);
+  p=p&&ptr_equal(phrase,ktest_equal_data);
+  return p;
+}
+
+int ktest_equal_krb5_pwd_data(ref, var)
+     krb5_pwd_data * ref;
+     krb5_pwd_data * var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(sequence_count);
+  p=p&&ptr_equal(element,ktest_equal_array_of_passwd_phrase_element);
+  return p;
+}
+
+int ktest_equal_krb5_alt_method(ref, var)
+    krb5_alt_method *ref;
+    krb5_alt_method *var;
+{
+    if (ref->method != var->method)
+	return FALSE;
+    if (ref->length != var->length)
+	return FALSE;
+    if (memcmp(ref->data, var->data, ref->length) != 0)
+	return FALSE;
+    return TRUE;
+}
+
+int ktest_equal_krb5_etype_info_entry(ref, var)
+    krb5_etype_info_entry *ref;
+    krb5_etype_info_entry *var;
+{
+    if (ref->etype != var->etype)
+	return FALSE;
+    if (ref->length != var->length)
+	return FALSE;
+    if (ref->length > 0 && ref->length != KRB5_ETYPE_NO_SALT)
+    	if (memcmp(ref->salt, var->salt, ref->length) != 0)
+	    return FALSE;
+    return TRUE;
+}
+
+int ktest_equal_krb5_pa_enc_ts(ref, var)
+    krb5_pa_enc_ts *ref;
+    krb5_pa_enc_ts *var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(patimestamp);
+  p=p&&scalar_equal(pausec);
+  return p;
+}
+
+#define equal_str(f) struct_equal(f,ktest_equal_data)
+
+int ktest_equal_sam_challenge(ref, var)
+     krb5_sam_challenge *ref;
+     krb5_sam_challenge *var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(sam_type);
+  p=p&&scalar_equal(sam_flags);
+  p=p&&scalar_equal(sam_nonce);
+  p=p&&ktest_equal_checksum(&ref->sam_cksum,&var->sam_cksum);
+  p=p&&equal_str(sam_track_id);
+  p=p&&equal_str(sam_challenge_label);
+  p=p&&equal_str(sam_challenge);
+  p=p&&equal_str(sam_response_prompt);
+  p=p&&equal_str(sam_pk_for_sad);
+  return p;
+}
+
+int ktest_equal_sam_response(ref, var)
+     krb5_sam_response *ref;
+     krb5_sam_response *var;
+{
+  int p=TRUE;
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  p=p&&scalar_equal(sam_type);
+  p=p&&scalar_equal(sam_flags);
+  p=p&&equal_str(sam_track_id);
+  p=p&&struct_equal(sam_enc_key,ktest_equal_enc_data);
+  p=p&&struct_equal(sam_enc_nonce_or_ts,ktest_equal_enc_data);
+  p=p&&scalar_equal(sam_nonce);
+  p=p&&scalar_equal(sam_patimestamp);
+  return p;
+}
+
+/**** arrays ****************************************************************/
+
+int ktest_equal_array_of_data(length, ref, var)
+     const int length;
+     krb5_data * ref;
+     krb5_data * var;
+{
+  int i,p=TRUE;
+
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  for(i=0; i<(length); i++){
+    p = p && ktest_equal_data(&(ref[i]),&(var[i]));
+  }
+  return p;
+}
+
+int ktest_equal_array_of_octet(length, ref, var)
+     const unsigned int length;
+     krb5_octet * ref;
+     krb5_octet * var;
+{
+  int i, p=TRUE;
+
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  for(i=0; i<length; i++)
+    p = p && (ref[i] == var[i]);
+  return p;
+}
+
+int ktest_equal_array_of_char(length, ref, var)
+     const unsigned int length;
+     char * ref;
+     char * var;
+{
+  int i, p=TRUE;
+
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  for(i=0; i<length; i++)
+    p = p && (ref[i] == var[i]);
+  return p;
+}
+
+int ktest_equal_array_of_enctype(length, ref, var)
+     const int length;
+     krb5_enctype * ref;
+     krb5_enctype * var;
+{
+  int i, p=TRUE;
+
+  if(ref==var) return TRUE;
+  else if(ref == NULL || var == NULL) return FALSE;
+  for(i=0; i<length; i++)
+    p = p && (ref[i] == var[i]);
+  return p;
+}
+
+#define array_compare(comparator)\
+int i,p=TRUE;\
+if(ref==var) return TRUE;\
+if(!ref || !ref[0])\
+  return (!var || !var[0]);\
+if(!var || !var[0]) return FALSE;\
+for(i=0; ref[i] != NULL && var[i] != NULL; i++)\
+  p = p && comparator(ref[i],var[i]);\
+if(ref[i] == NULL && var[i] == NULL) return p;\
+else return FALSE
+
+int ktest_equal_authorization_data(ref, var)
+     krb5_authdata ** ref;
+     krb5_authdata ** var;
+{
+  array_compare(ktest_equal_authdata);
+}
+
+int ktest_equal_addresses(ref, var)
+     krb5_address ** ref;
+     krb5_address ** var;
+{
+  array_compare(ktest_equal_address);
+}
+
+int ktest_equal_last_req(ref, var)
+     krb5_last_req_entry ** ref;
+     krb5_last_req_entry ** var;
+{
+  array_compare(ktest_equal_last_req_entry);
+}
+
+int ktest_equal_sequence_of_ticket(ref, var)
+     krb5_ticket ** ref;
+     krb5_ticket ** var;
+{
+  array_compare(ktest_equal_ticket);
+}
+
+int ktest_equal_sequence_of_pa_data(ref, var)
+     krb5_pa_data ** ref;
+     krb5_pa_data ** var;
+{
+  array_compare(ktest_equal_pa_data);
+}
+
+int ktest_equal_sequence_of_cred_info(ref, var)
+     krb5_cred_info ** ref;
+     krb5_cred_info ** var;
+{
+  array_compare(ktest_equal_cred_info);
+}
+
+int ktest_equal_array_of_passwd_phrase_element(ref, var)
+     passwd_phrase_element ** ref;
+     passwd_phrase_element ** var;
+{
+  array_compare(ktest_equal_passwd_phrase_element);
+}
+
+int ktest_equal_etype_info(ref, var)
+     krb5_etype_info_entry ** ref;
+     krb5_etype_info_entry ** var;
+{
+  array_compare(ktest_equal_krb5_etype_info_entry);
+}
diff --git a/mechglue/src/tests/asn.1/ktest_equal.h b/mechglue/src/tests/asn.1/ktest_equal.h
new file mode 100644
index 000000000..d45cf51a3
--- /dev/null
+++ b/mechglue/src/tests/asn.1/ktest_equal.h
@@ -0,0 +1,93 @@
+#ifndef __KTEST_EQUAL_H__
+#define __KTEST_EQUAL_H__
+
+#include "k5-int.h"
+
+/* int ktest_equal_structure(krb5_structure *ref, *var) */
+/* effects  Returns true (non-zero) if ref and var are
+             semantically equivalent (i.e. have the same values,
+	     but aren't necessarily the same object).
+	    Returns false (zero) if ref and var differ. */
+
+#define generic(funcname,type)\
+int funcname (type *ref, type *var)
+
+#define len_array(funcname,type)\
+int funcname (const int length, type *ref, type *var)
+#define len_unsigned_array(funcname,type)\
+int funcname (const unsigned int length, type *ref, type *var)
+
+generic(ktest_equal_authenticator,krb5_authenticator);
+generic(ktest_equal_principal_data,krb5_principal_data);
+generic(ktest_equal_checksum,krb5_checksum);
+generic(ktest_equal_keyblock,krb5_keyblock);
+generic(ktest_equal_data,krb5_data);
+generic(ktest_equal_authdata,krb5_authdata);
+generic(ktest_equal_ticket,krb5_ticket);
+generic(ktest_equal_enc_tkt_part,krb5_enc_tkt_part);
+generic(ktest_equal_transited,krb5_transited);
+generic(ktest_equal_ticket_times,krb5_ticket_times);
+generic(ktest_equal_address,krb5_address);
+generic(ktest_equal_enc_data,krb5_enc_data);
+
+generic(ktest_equal_enc_kdc_rep_part,krb5_enc_kdc_rep_part);
+generic(ktest_equal_priv,krb5_priv);
+generic(ktest_equal_cred,krb5_cred);
+generic(ktest_equal_error,krb5_error);
+generic(ktest_equal_ap_req,krb5_ap_req);
+generic(ktest_equal_ap_rep,krb5_ap_rep);
+generic(ktest_equal_ap_rep_enc_part,krb5_ap_rep_enc_part);
+generic(ktest_equal_safe,krb5_safe);
+
+generic(ktest_equal_last_req_entry,krb5_last_req_entry);
+generic(ktest_equal_pa_data,krb5_pa_data);
+generic(ktest_equal_cred_info,krb5_cred_info);
+
+generic(ktest_equal_enc_cred_part,krb5_cred_enc_part);
+generic(ktest_equal_enc_priv_part,krb5_priv_enc_part);
+generic(ktest_equal_as_rep,krb5_kdc_rep);
+generic(ktest_equal_tgs_rep,krb5_kdc_rep);
+generic(ktest_equal_as_req,krb5_kdc_req);
+generic(ktest_equal_tgs_req,krb5_kdc_req);
+generic(ktest_equal_kdc_req_body,krb5_kdc_req);
+generic(ktest_equal_encryption_key,krb5_keyblock);
+
+generic(ktest_equal_passwd_phrase_element,passwd_phrase_element);
+generic(ktest_equal_krb5_pwd_data,krb5_pwd_data);
+generic(ktest_equal_krb5_alt_method,krb5_alt_method);
+generic(ktest_equal_krb5_pa_enc_ts,krb5_pa_enc_ts);
+
+generic(ktest_equal_sam_challenge,krb5_sam_challenge);
+generic(ktest_equal_sam_response,krb5_sam_response);
+
+int ktest_equal_last_req
+	(krb5_last_req_entry **ref, krb5_last_req_entry **var);
+int ktest_equal_sequence_of_ticket
+	(krb5_ticket **ref, krb5_ticket **var);
+int ktest_equal_sequence_of_pa_data
+	(krb5_pa_data **ref, krb5_pa_data **var);
+int ktest_equal_sequence_of_cred_info
+	(krb5_cred_info **ref, krb5_cred_info **var);
+
+len_array(ktest_equal_array_of_enctype,krb5_enctype);
+len_array(ktest_equal_array_of_data,krb5_data);
+len_unsigned_array(ktest_equal_array_of_octet,krb5_octet);
+
+int ktest_equal_array_of_passwd_phrase_element
+	(passwd_phrase_element **ref, passwd_phrase_element **var);
+int ktest_equal_authorization_data
+	(krb5_authdata **ref, krb5_authdata **var);
+int ktest_equal_addresses
+	(krb5_address **ref, krb5_address **var);
+int ktest_equal_array_of_char
+	(const unsigned int length, char *ref, char *var);
+
+int ktest_equal_etype_info
+    (krb5_etype_info_entry ** ref,
+		    krb5_etype_info_entry ** var);
+
+int ktest_equal_krb5_etype_info_entry
+    (krb5_etype_info_entry * ref,
+		    krb5_etype_info_entry * var);
+
+#endif
diff --git a/mechglue/src/tests/asn.1/reference_encode.out b/mechglue/src/tests/asn.1/reference_encode.out
new file mode 100644
index 000000000..a118c050d
--- /dev/null
+++ b/mechglue/src/tests/asn.1/reference_encode.out
@@ -0,0 +1,53 @@
+encode_krb5_authenticator: 62 81 A1 30 81 9E A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A4 05 02 03 01 E2 40 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A7 03 02 01 11 A8 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
+encode_krb5_authenticator(optionals empty): 62 4F 30 4D A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 05 02 03 01 E2 40 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
+encode_krb5_authenticator(optionals NULL): 62 4F 30 4D A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 05 02 03 01 E2 40 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
+encode_krb5_ticket: 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_keyblock: 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38
+encode_krb5_enc_tkt_part: 63 82 01 14 30 82 01 10 A0 07 03 05 00 FE DC BA 98 A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 2E 30 2C A0 03 02 01 01 A1 25 04 23 45 44 55 2C 4D 49 54 2E 2C 41 54 48 45 4E 41 2E 2C 57 41 53 48 49 4E 47 54 4F 4E 2E 45 44 55 2C 43 53 2E A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
+encode_krb5_enc_tkt_part(optionals NULL): 63 81 A5 30 81 A2 A0 07 03 05 00 FE DC BA 98 A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 2E 30 2C A0 03 02 01 01 A1 25 04 23 45 44 55 2C 4D 49 54 2E 2C 41 54 48 45 4E 41 2E 2C 57 41 53 48 49 4E 47 54 4F 4E 2E 45 44 55 2C 43 53 2E A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
+encode_krb5_enc_kdc_rep_part: 7A 82 01 0E 30 82 01 0A A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 36 30 34 30 18 A0 03 02 01 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 30 18 A0 03 02 01 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A4 07 03 05 00 FE DC BA 98 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AB 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23
+encode_krb5_enc_kdc_rep_part(optionals NULL): 7A 81 B2 30 81 AF A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 36 30 34 30 18 A0 03 02 01 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A 30 18 A0 03 02 01 FB A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A4 07 03 05 00 FE 5C BA 98 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61
+encode_krb5_as_rep: 6B 81 EA 30 81 E7 A0 03 02 01 05 A1 03 02 01 0B A2 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A6 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_as_rep(optionals NULL): 6B 81 C2 30 81 BF A0 03 02 01 05 A1 03 02 01 0B A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A6 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_tgs_rep: 6D 81 EA 30 81 E7 A0 03 02 01 05 A1 03 02 01 0D A2 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A6 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_tgs_rep(optionals NULL): 6D 81 C2 30 81 BF A0 03 02 01 05 A1 03 02 01 0D A3 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A4 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A6 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_ap_req: 6E 81 9D 30 81 9A A0 03 02 01 05 A1 03 02 01 0E A2 07 03 05 00 FE DC BA 98 A3 5E 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A4 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_ap_rep: 6F 33 30 31 A0 03 02 01 05 A1 03 02 01 0F A2 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_ap_rep_enc_part: 7B 36 30 34 A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A1 05 02 03 01 E2 40 A2 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A3 03 02 01 11
+encode_krb5_ap_rep_enc_part(optionals NULL): 7B 1C 30 1A A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A1 05 02 03 01 E2 40
+encode_krb5_as_req: 6A 82 01 E4 30 82 01 E0 A1 03 02 01 05 A2 03 02 01 0A A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 82 01 AA 30 82 01 A6 A0 07 03 05 00 FE DC BA 90 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_as_req(optionals NULL except second_ticket): 6A 82 01 14 30 82 01 10 A1 03 02 01 05 A2 03 02 01 0A A4 82 01 02 30 81 FF A0 07 03 05 00 FE DC BA 98 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_as_req(optionals NULL except server): 6A 69 30 67 A1 03 02 01 05 A2 03 02 01 0A A4 5B 30 59 A0 07 03 05 00 FE DC BA 90 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01
+encode_krb5_tgs_req: 6C 82 01 E4 30 82 01 E0 A1 03 02 01 05 A2 03 02 01 0C A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 82 01 AA 30 82 01 A6 A0 07 03 05 00 FE DC BA 90 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_tgs_req(optionals NULL except second_ticket): 6C 82 01 14 30 82 01 10 A1 03 02 01 05 A2 03 02 01 0C A4 82 01 02 30 81 FF A0 07 03 05 00 FE DC BA 98 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_tgs_req(optionals NULL except server): 6C 69 30 67 A1 03 02 01 05 A2 03 02 01 0C A4 5B 30 59 A0 07 03 05 00 FE DC BA 90 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01
+encode_krb5_kdc_req_body: 30 82 01 A6 A0 07 03 05 00 FE DC BA 90 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 A9 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 AA 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_kdc_req_body(optionals NULL except second_ticket): 30 81 FF A0 07 03 05 00 FE DC BA 98 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01 AB 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_kdc_req_body(optionals NULL except server): 30 59 A0 07 03 05 00 FE DC BA 90 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 03 02 01 2A A8 08 30 06 02 01 00 02 01 01
+encode_krb5_safe: 74 6E 30 6C A0 03 02 01 05 A1 03 02 01 14 A2 4F 30 4D A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 05 02 03 01 E2 40 A3 03 02 01 11 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A5 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A3 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
+encode_krb5_safe(optionals NULL): 74 3E 30 3C A0 03 02 01 05 A1 03 02 01 14 A2 1F 30 1D A0 0A 04 08 6B 72 62 35 64 61 74 61 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A3 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
+encode_krb5_priv: 75 33 30 31 A0 03 02 01 05 A1 03 02 01 15 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_enc_priv_part: 7C 4F 30 4D A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 05 02 03 01 E2 40 A3 03 02 01 11 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A5 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23
+encode_krb5_enc_priv_part(optionals NULL): 7C 1F 30 1D A0 0A 04 08 6B 72 62 35 64 61 74 61 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23
+encode_krb5_cred: 76 81 F6 30 81 F3 A0 03 02 01 05 A1 03 02 01 16 A2 81 BF 30 81 BC 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 61 5C 30 5A A0 03 02 01 05 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65 A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_enc_cred_part: 7D 82 02 23 30 82 02 1F A0 82 01 DA 30 82 01 D6 30 81 E8 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 07 03 05 00 FE DC BA 98 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A9 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AA 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 81 E8 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 07 03 05 00 FE DC BA 98 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A9 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AA 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A1 03 02 01 2A A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A3 05 02 03 01 E2 40 A4 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 A5 0F 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23
+encode_krb5_enc_cred_part(optionals NULL): 7D 82 01 0E 30 82 01 0A A0 82 01 06 30 82 01 02 30 15 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 30 81 E8 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 07 03 05 00 FE DC BA 98 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A7 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A8 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A9 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AA 20 30 1E 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23 30 0D A0 03 02 01 02 A1 06 04 04 12 D0 00 23
+encode_krb5_error: 7E 81 BA 30 81 B7 A0 03 02 01 05 A1 03 02 01 1E A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A3 05 02 03 01 E2 40 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 05 02 03 01 E2 40 A6 03 02 01 3C A7 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A8 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 AB 0A 1B 08 6B 72 62 35 64 61 74 61 AC 0A 04 08 6B 72 62 35 64 61 74 61
+encode_krb5_error(optionals NULL): 7E 60 30 5E A0 03 02 01 05 A1 03 02 01 1E A3 05 02 03 01 E2 40 A4 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A5 05 02 03 01 E2 40 A6 03 02 01 3C A9 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 AA 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61
+encode_krb5_authorization_data: 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
+encode_krb5_pwd_sequence: 30 18 A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61
+encode_krb5_pwd_data: 30 3D A0 03 02 01 02 A1 36 30 34 30 18 A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61 30 18 A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61
+encode_krb5_padata_sequence: 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61
+encode_krb5_padata_sequence(empty): 30 00
+encode_krb5_alt_method: 30 0F A0 03 02 01 2A A1 08 04 06 73 65 63 72 65 74
+encode_krb5_alt_method (no data): 30 05 A0 03 02 01 2A
+encode_krb5_etype_info: 30 33 30 14 A0 03 02 01 00 A1 0D 04 0B 4D 6F 72 74 6F 6E 27 73 20 23 30 30 05 A0 03 02 01 01 30 14 A0 03 02 01 02 A1 0D 04 0B 4D 6F 72 74 6F 6E 27 73 20 23 32
+encode_krb5_etype_info (only 1): 30 16 30 14 A0 03 02 01 00 A1 0D 04 0B 4D 6F 72 74 6F 6E 27 73 20 23 30
+encode_krb5_etype_info (no info): 30 00
+encode_krb5_etype_info2: 30 51 30 1E A0 03 02 01 00 A1 0D 1B 0B 4D 6F 72 74 6F 6E 27 73 20 23 30 A2 08 04 06 73 32 6B 3A 20 30 30 0F A0 03 02 01 01 A2 08 04 06 73 32 6B 3A 20 31 30 1E A0 03 02 01 02 A1 0D 1B 0B 4D 6F 72 74 6F 6E 27 73 20 23 32 A2 08 04 06 73 32 6B 3A 20 32
+encode_krb5_etype_info2 (only 1): 30 20 30 1E A0 03 02 01 00 A1 0D 1B 0B 4D 6F 72 74 6F 6E 27 73 20 23 30 A2 08 04 06 73 32 6B 3A 20 30
+encode_krb5_pa_enc_ts: 30 1A A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A1 05 02 03 01 E2 40
+encode_krb5_pa_enc_ts (no usec): 30 13 A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
+encode_krb5_enc_data: 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+encode_krb5_sam_challenge: 30 70 A0 03 02 01 2A A1 07 03 05 00 80 00 00 00 A2 0B 04 09 74 79 70 65 20 6E 61 6D 65 A4 11 04 0F 63 68 61 6C 6C 65 6E 67 65 20 6C 61 62 65 6C A5 10 04 0E 63 68 61 6C 6C 65 6E 67 65 20 69 70 73 65 A6 16 04 14 72 65 73 70 6F 6E 73 65 5F 70 72 6F 6D 70 74 20 69 70 73 65 A8 05 02 03 54 32 10 A9 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
+encode_krb5_sam_response: 30 6A A0 03 02 01 2A A1 07 03 05 00 80 00 00 00 A2 0C 04 0A 74 72 61 63 6B 20 64 61 74 61 A3 14 30 12 A0 03 02 01 01 A1 04 02 02 07 96 A2 05 04 03 6B 65 79 A4 1C 30 1A A0 03 02 01 01 A1 04 02 02 0D 36 A2 0D 04 0B 6E 6F 6E 63 65 20 6F 72 20 74 73 A5 05 02 03 54 32 10 A6 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
diff --git a/mechglue/src/tests/asn.1/trval.c b/mechglue/src/tests/asn.1/trval.c
new file mode 100644
index 000000000..fc18bc0e7
--- /dev/null
+++ b/mechglue/src/tests/asn.1/trval.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright (C) 1992,1993 Trusted Information Systems, Inc.
+ *
+ * Permission to include this software in the Kerberos V5 distribution
+ * was graciously provided by Trusted Information Systems.
+ * 
+ * Trusted Information Systems makes no representation about the
+ * suitability of this software for any purpose.  It is provided
+ * "as is" without express or implied warranty.
+ * 
+ * Copyright (C) 1994 Massachusetts Institute of Technology
+ * 
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ */
+
+/*****************************************************************************
+ * trval.c.c
+ *****************************************************************************/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#define OK 0
+#define NOTOK (-1)
+	
+	/* IDENTIFIER OCTET = TAG CLASS | FORM OF ENCODING | TAG NUMBER */
+	
+	/* TAG CLASSES */
+#define ID_CLASS   0xc0		/* bits 8 and 7 */
+#define CLASS_UNIV 0x00		/* 0 = universal */
+#define CLASS_APPL 0x40		/* 1 = application */
+#define CLASS_CONT 0x80		/* 2 = context-specific */
+#define CLASS_PRIV 0xc0		/* 3 = private */
+	
+	/* FORM OF ENCODING */
+#define ID_FORM   0x20		/* bit 6 */
+#define FORM_PRIM 0x00		/* 0 = primitive */
+#define FORM_CONS 0x20		/* 1 = constructed */
+	
+	/* TAG NUMBERS */
+#define ID_TAG    0x1f		/* bits 5-1 */
+#define PRIM_BOOL 0x01		/* Boolean */
+#define PRIM_INT  0x02		/* Integer */
+#define PRIM_BITS 0x03		/* Bit String */
+#define PRIM_OCTS 0x04		/* Octet String */
+#define PRIM_NULL 0x05		/* Null */
+#define PRIM_OID  0x06		/* Object Identifier */
+#define PRIM_ODE  0x07		/* Object Descriptor */
+#define CONS_EXTN 0x08		/* External */
+#define PRIM_REAL 0x09		/* Real */
+#define PRIM_ENUM 0x0a		/* Enumerated type */
+#define PRIM_ENCR 0x0b		/* Encrypted */
+#define CONS_SEQ  0x10		/* SEQUENCE/SEQUENCE OF */
+#define CONS_SET  0x11		/* SET/SET OF */
+#define DEFN_NUMS 0x12		/* Numeric String */
+#define DEFN_PRTS 0x13		/* Printable String */
+#define DEFN_T61S 0x14		/* T.61 String */
+#define DEFN_VTXS 0x15		/* Videotex String */
+#define DEFN_IA5S 0x16		/* IA5 String */
+#define DEFN_UTCT 0x17		/* UTCTime */
+#define DEFN_GENT 0x18		/* Generalized Time */
+#define DEFN_GFXS 0x19		/* Graphics string (ISO2375) */
+#define DEFN_VISS 0x1a		/* Visible string */
+#define DEFN_GENS 0x1b		/* General string */
+#define DEFN_CHRS 0x1c		/* Character string */
+	
+#define	LEN_XTND	0x80	/* long or indefinite form */
+#define	LEN_SMAX	127	/* largest short form */
+#define	LEN_MASK	0x7f	/* mask to get number of bytes in length */
+#define	LEN_INDF	(-1)	/* indefinite length */
+
+#define KRB5	/* Do krb5 application types */
+	
+int print_types = 0;
+int print_id_and_len = 1;
+int print_constructed_length = 1;	
+int print_primitive_length = 1;
+int print_skip_context = 0;
+int print_skip_tagnum = 1;
+int print_context_shortcut = 0;
+int do_hex = 0;
+#ifdef KRB5
+int print_krb5_types = 0;
+#endif
+
+int current_appl_type = -1;
+
+int decode_len (FILE *, unsigned char *, int);
+int do_prim (FILE *, int, unsigned char *, int, int);
+int do_cons (FILE *, unsigned char *, int, int, int *);
+int do_prim_bitstring (FILE *, int, unsigned char *, int, int);
+int do_prim_int (FILE *, int, unsigned char *, int, int);
+int do_prim_string (FILE *, int, unsigned char *, int, int);
+void print_tag_type (FILE *, int, int);
+int trval (FILE *, FILE *);
+int trval2 (FILE *, unsigned char *, int, int, int *);
+
+
+/****************************************************************************/
+
+#ifdef STANDALONE
+
+static void usage()
+{
+	fprintf(stderr, "Usage: trval [--types] [--krb5] [--krb5decode] [--hex] [-notypebytes] [file]\n");
+	exit(1);
+}
+
+/*
+ * Returns true if the option was selected.  Allow "-option" and
+ * "--option" syntax, since we used to accept only "-option"
+ */
+static
+int check_option(word, option)
+	char *word;
+	char *option;
+{
+	if (word[0] != '-')
+		return 0;
+	if (word[1] == '-')
+		word++;
+	if (strcmp(word+1, option))
+		return 0;
+	return 1;
+}
+
+int main(argc, argv)
+	int argc;
+	char **argv;
+{
+	int optflg = 1;
+	FILE *fp;
+	int r = 0;
+	
+	while (--argc > 0) {
+		argv++;
+		if (optflg && *(argv)[0] == '-') {
+			if (check_option(*argv, "help"))
+				usage();
+			else if (check_option(*argv, "types"))
+				print_types = 1;
+			else if (check_option(*argv, "notypes"))
+				print_types = 0;
+			else if (check_option(*argv, "krb5"))
+				print_krb5_types = 1;
+			else if (check_option(*argv, "hex"))
+				do_hex = 1;
+			else if (check_option(*argv, "notypebytes"))
+				print_id_and_len = 0;
+			else if (check_option(*argv, "krb5decode")) {
+				print_id_and_len = 0;
+				print_krb5_types = 1;
+				print_types = 1;
+			} else {
+				fprintf(stderr,"trval: unknown option: %s\n", *argv);
+				usage();
+			}
+		} else {
+			optflg = 0;
+			if ((fp = fopen(*argv,"r")) == NULL) {
+				fprintf(stderr,"trval: unable to open %s\n", *argv);
+				continue;
+			}
+			r = trval(fp, stdout);
+			fclose(fp);
+		}
+	}
+	if (optflg) r = trval(stdin, stdout);
+	
+	exit(r);
+}
+#endif
+
+static int convert_nibble(int ch)
+{
+    if (isdigit(ch))
+	return (ch - '0');
+    if (ch >= 'a' && ch <= 'f')
+	return (ch - 'a' + 10);
+    if (ch >= 'A' && ch <= 'F')
+	return (ch - 'A' + 10);
+    return -1;
+}
+
+int trval(fin, fout)
+	FILE	*fin;
+	FILE	*fout;
+{
+	unsigned char *p;
+	unsigned int maxlen;
+	int len;
+	int cc, cc2, n1, n2;
+	int r;
+	int rlen;
+	
+	maxlen = BUFSIZ;
+	p = (unsigned char *)malloc(maxlen);
+	len = 0;
+	while ((cc = fgetc(fin)) != EOF) {
+		if (len == maxlen) {
+			maxlen += BUFSIZ;
+			p = (unsigned char *)realloc(p, maxlen);
+		}
+		if (do_hex) {
+			if (cc == ' ' || cc == '\n' || cc == '\t')
+				continue;
+			cc2 = fgetc(fin);
+			if (cc2 == EOF)
+				break;
+			n1 = convert_nibble(cc);
+			n2 = convert_nibble(cc2);
+			cc = (n1 << 4) + n2;
+		}
+		p[len++] = cc;
+	}
+	fprintf(fout, "<%d>", len);
+	r = trval2(fout, p, len, 0, &rlen);
+	fprintf(fout, "\n");
+	(void) free(p);
+	return(r);
+}
+
+int trval2(fp, enc, len, lev, rlen)
+	FILE *fp;
+	unsigned char *enc;
+	int len;
+	int lev;
+	int *rlen;
+{
+	int l, eid, elen, xlen, r, rlen2;
+	int rlen_ext = 0;
+
+	r = OK;
+
+	if (len < 2) {
+		fprintf(fp, "missing id and length octets (%d)\n", len);
+		return(NOTOK);
+	}
+	
+	fprintf(fp, "\n");
+	for (l=0; l<lev; l++) fprintf(fp, ".  ");
+	
+context_restart:
+	eid = enc[0];
+	elen = enc[1];
+
+	if (print_id_and_len) {
+		fprintf(fp, "%02x ", eid);
+		fprintf(fp, "%02x ", elen);
+	}
+	
+	if (elen == LEN_XTND) {
+		fprintf(fp,
+			"indefinite length encoding not implemented (0x%02x)\n", elen);
+		return(NOTOK);
+	}
+	
+	xlen = 0;
+	if (elen & LEN_XTND) {
+		xlen = elen & LEN_MASK;
+		if (xlen > len - 2) {
+			fprintf(fp, "extended length too long (%d > %d - 2)\n", xlen, len);
+			return(NOTOK);
+		}
+		elen = decode_len(fp, enc+2, xlen);
+	}
+	
+	if (elen > len - 2 - xlen) {
+		fprintf(fp, "length too long (%d > %d - 2 - %d)\n", elen, len, xlen);
+		return(NOTOK);
+	}
+	
+	print_tag_type(fp, eid, lev);
+
+	if (print_context_shortcut &&
+	    ((eid & ID_CLASS) == CLASS_CONT) && (lev > 0)) {
+		rlen_ext += 2 + xlen;
+		enc += 2 + xlen;
+		goto context_restart;
+	}
+
+	switch(eid & ID_FORM) {
+	case FORM_PRIM:
+		r = do_prim(fp, eid & ID_TAG, enc+2+xlen, elen, lev+1);
+		*rlen = 2 + xlen + elen + rlen_ext;
+		break;
+	case FORM_CONS:
+		if (print_constructed_length) {
+			fprintf(fp, "constr ");
+			fprintf(fp, "<%d>", elen);
+		}
+		r = do_cons(fp, enc+2+xlen, elen, lev+1, &rlen2);
+		*rlen = 2 + xlen + rlen2 + rlen_ext;
+		break;
+	}
+	
+	return(r);
+}
+
+int decode_len(fp, enc, len)
+	FILE *fp;
+	unsigned char *enc;
+	int len;
+{
+	int rlen;
+	int i;
+	
+	if (print_id_and_len)
+		fprintf(fp, "%02x ", enc[0]);
+	rlen = enc[0];
+	for (i=1; i<len; i++) {
+		if (print_id_and_len)
+			fprintf(fp, "%02x ", enc[i]);
+		rlen = (rlen * 0x100) + enc[i];
+	}
+	return(rlen);
+}
+
+/*
+ * This is the printing function for bit strings
+ */
+int do_prim_bitstring(fp, tag, enc, len, lev)
+	FILE *fp;
+	int tag;
+	unsigned char *enc;
+	int len;
+	int lev;
+{
+	int	i;
+	long	num = 0;
+
+	if (tag != PRIM_BITS || len > 5)
+		return 0;
+
+	for (i=1; i < len; i++) {
+		num = num << 8;
+		num += enc[i];
+	}
+
+	fprintf(fp, "0x%lx", num);
+	if (enc[0])
+		fprintf(fp, " (%d unused bits)", enc[0]);
+	return 1;
+}
+
+/*
+ * This is the printing function for integers
+ */
+int do_prim_int(fp, tag, enc, len, lev)
+	FILE *fp;
+	int tag;
+	unsigned char *enc;
+	int len;
+	int lev;
+{
+	int	i;
+	long	num = 0;
+
+	if (tag != PRIM_INT || len > 4)
+		return 0;
+
+	if (enc[0] & 0x80)
+		num = -1;
+
+	for (i=0; i < len; i++) {
+		num = num << 8;
+		num += enc[i];
+	}
+
+	fprintf(fp, "%ld", num);
+	return 1;
+}
+
+
+/*
+ * This is the printing function which we use if it's a string or
+ * other other type which is best printed as a string
+ */
+int do_prim_string(fp, tag, enc, len, lev)
+	FILE *fp;
+	int tag;
+	unsigned char *enc;
+	int len;
+	int lev;
+{
+	int	i;
+
+	/*
+	 * Only try this printing function with "reasonable" types
+	 */
+	if ((tag < DEFN_NUMS) && (tag != PRIM_OCTS))
+		return 0;
+
+	for (i=0; i < len; i++)
+		if (!isprint(enc[i]))
+			return 0;
+	fprintf(fp, "\"%.*s\"", len, enc);
+	return 1;
+}
+
+int do_prim(fp, tag, enc, len, lev)
+	FILE *fp;
+	int tag;
+	unsigned char *enc;
+	int len;
+	int lev;
+{
+	int n;
+	int i;
+	int j;
+	int width;
+
+	if (do_prim_string(fp, tag, enc, len, lev))
+		return OK;
+	if (do_prim_int(fp, tag, enc, len, lev))
+		return OK;
+	if (do_prim_bitstring(fp, tag, enc, len, lev))
+		return OK;
+
+	if (print_primitive_length)
+		fprintf(fp, "<%d>", len);
+	
+	width = (80 - (lev * 3) - 8) / 4;
+	
+	for (n = 0; n < len; n++) {
+		if ((n % width) == 0) {
+			fprintf(fp, "\n");
+			for (i=0; i<lev; i++) fprintf(fp, "   ");
+		}
+		fprintf(fp, "%02x ", enc[n]);
+		if ((n % width) == (width-1)) {
+			fprintf(fp, "    ");
+			for (i=n-(width-1); i<=n; i++)
+				if (isprint(enc[i])) fprintf(fp, "%c", enc[i]);
+				else fprintf(fp, ".");
+		}
+	}
+	if ((j = (n % width)) != 0) {
+		fprintf(fp, "    ");
+		for (i=0; i<width-j; i++) fprintf(fp, "   ");
+		for (i=n-j; i<n; i++)
+			if (isprint(enc[i])) fprintf(fp, "%c", enc[i]);
+			else fprintf(fp, ".");
+	}
+	return(OK);
+}
+
+int do_cons(fp, enc, len, lev, rlen)
+FILE *fp;
+unsigned char *enc;
+int len;
+int lev;
+int *rlen;
+{
+    int n;
+    int r = 0;
+    int rlen2;
+    int rlent;
+    int save_appl;
+
+    save_appl = current_appl_type;
+    for (n = 0, rlent = 0; n < len; n+=rlen2, rlent+=rlen2) {
+	r = trval2(fp, enc+n, len-n, lev, &rlen2);
+	current_appl_type = save_appl;
+	if (r != OK) return(r);
+    }
+    if (rlent != len) {
+	fprintf(fp, "inconsistent constructed lengths (%d != %d)\n",
+	rlent, len);
+	return(NOTOK);
+    }
+    *rlen = rlent;
+    return(r);
+}
+
+struct typestring_table {
+	int	k1, k2;
+	char	*str;
+	int	new_appl;
+};
+
+static char *lookup_typestring(table, key1, key2)
+	struct typestring_table *table;
+	int	key1, key2;
+{
+	struct typestring_table *ent;
+
+	for (ent = table; ent->k1 > 0; ent++) {
+		if ((ent->k1 == key1) &&
+		    (ent->k2 == key2)) {
+			if (ent->new_appl)
+				current_appl_type = ent->new_appl;
+			return ent->str;
+		}
+	}
+	return 0;
+}
+
+
+struct typestring_table univ_types[] = {
+	{ PRIM_BOOL, -1, "Boolean"},
+	{ PRIM_INT, -1, "Integer"},
+	{ PRIM_BITS, -1, "Bit String"},
+	{ PRIM_OCTS, -1, "Octet String"},
+	{ PRIM_NULL, -1, "Null"},
+	{ PRIM_OID, -1, "Object Identifier"},
+	{ PRIM_ODE, -1, "Object Descriptor"},
+	{ CONS_EXTN, -1, "External"},
+	{ PRIM_REAL, -1, "Real"},
+	{ PRIM_ENUM, -1, "Enumerated type"},
+	{ PRIM_ENCR, -1, "Encrypted"},
+	{ CONS_SEQ, -1, "Sequence/Sequence Of"},
+	{ CONS_SET, -1, "Set/Set Of"},
+	{ DEFN_NUMS, -1, "Numeric String"},
+	{ DEFN_PRTS, -1, "Printable String"},
+	{ DEFN_T61S, -1, "T.61 String"},
+	{ DEFN_VTXS, -1, "Videotex String"},
+	{ DEFN_IA5S, -1, "IA5 String"},
+	{ DEFN_UTCT, -1, "UTCTime"},
+	{ DEFN_GENT, -1, "Generalized Time"},
+	{ DEFN_GFXS, -1, "Graphics string (ISO2375)"},
+	{ DEFN_VISS, -1, "Visible string"},
+	{ DEFN_GENS, -1, "General string"},
+	{ DEFN_CHRS, -1, "Character string"},
+	{ -1, -1, 0}
+	};
+
+#ifdef KRB5
+struct typestring_table krb5_types[] = {
+	{ 1, -1, "Krb5 Ticket"},
+	{ 2, -1, "Krb5 Autenticator"},
+	{ 3, -1, "Krb5 Encrypted ticket part"},
+	{ 10, -1, "Krb5 AS-REQ packet"},
+	{ 11, -1, "Krb5 AS-REP packet"},
+	{ 12, -1, "Krb5 TGS-REQ packet"},
+	{ 13, -1, "Krb5 TGS-REP packet"},
+	{ 14, -1, "Krb5 AP-REQ packet"},
+	{ 15, -1, "Krb5 AP-REP packet"},
+	{ 20, -1, "Krb5 SAFE packet"},
+	{ 21, -1, "Krb5 PRIV packet"},
+	{ 22, -1, "Krb5 CRED packet"},
+	{ 30, -1, "Krb5 ERROR packet"},
+	{ 25, -1, "Krb5 Encrypted AS-REP part"},
+	{ 26, -1, "Krb5 Encrypted TGS-REP part"},
+	{ 27, -1, "Krb5 Encrypted AP-REP part"},
+	{ 28, -1, "Krb5 Encrypted PRIV part"},
+	{ 29, -1, "Krb5 Encrypted CRED part"},
+	{ -1, -1, 0}
+};
+
+struct typestring_table krb5_fields[] = {
+	{ 1000, 0, "name-type"}, /* PrincipalName */
+	{ 1000, 1, "name-string"},
+
+	{ 1001, 0, "etype"},	/* Encrypted data */
+	{ 1001, 1, "kvno"},	
+	{ 1001, 2, "cipher"},
+
+	{ 1002, 0, "addr-type"},	/* HostAddress */
+	{ 1002, 1, "address"},	
+
+	{ 1003, 0, "addr-type"},	/* HostAddresses */
+	{ 1003, 1, "address"},	
+
+	{ 1004, 0, "ad-type"},	/* AuthorizationData */
+	{ 1004, 1, "ad-data"},	
+
+	{ 1005, 0, "keytype"},	/* EncryptionKey */
+	{ 1005, 1, "keyvalue"},	
+
+	{ 1006, 0, "cksumtype"},	/* Checksum */
+	{ 1006, 1, "checksum"},
+
+	{ 1007, 0, "kdc-options"},	/* KDC-REQ-BODY */
+	{ 1007, 1, "cname", 1000},	
+	{ 1007, 2, "realm"},
+	{ 1007, 3, "sname", 1000},	
+	{ 1007, 4, "from"},
+	{ 1007, 5, "till"},	
+	{ 1007, 6, "rtime"},
+	{ 1007, 7, "nonce"},
+	{ 1007, 8, "etype"},
+	{ 1007, 9, "addresses", 1003},
+	{ 1007, 10, "enc-authorization-data", 1001},
+	{ 1007, 11, "additional-tickets"},
+
+	{ 1008, 1, "padata-type"},	/* PA-DATA */
+	{ 1008, 2, "pa-data"},
+
+	{ 1009, 0, "user-data"},	/* KRB-SAFE-BODY */
+	{ 1009, 1, "timestamp"},	
+	{ 1009, 2, "usec"},
+	{ 1009, 3, "seq-number"},	
+	{ 1009, 4, "s-address", 1002},
+	{ 1009, 5, "r-address", 1002},
+
+	{ 1010, 0, "lr-type"},	/* LastReq */
+	{ 1010, 1, "lr-value"},
+
+	{ 1011, 0, "key", 1005},	/* KRB-CRED-INFO */
+	{ 1011, 1, "prealm"},	
+	{ 1011, 2, "pname", 1000},
+	{ 1011, 3, "flags"},	
+	{ 1011, 4, "authtime"},
+	{ 1011, 5, "startime"},	
+	{ 1011, 6, "endtime"},
+	{ 1011, 7, "renew-till"},
+	{ 1011, 8, "srealm"},
+	{ 1011, 9, "sname", 1000},
+	{ 1011, 10, "caddr", 1002},
+
+	{ 1, 0, "tkt-vno"},	/* Ticket */
+	{ 1, 1, "realm"},
+	{ 1, 2, "sname", 1000},
+	{ 1, 3, "tkt-enc-part", 1001},
+
+	{ 2, 0, "authenticator-vno"}, /* Authenticator */
+	{ 2, 1, "crealm"},
+	{ 2, 2, "cname", 1000},
+	{ 2, 3, "cksum", 1006},
+	{ 2, 4, "cusec"},
+	{ 2, 5, "ctime"},
+	{ 2, 6, "subkey", 1005},
+	{ 2, 7, "seq-number"},
+	{ 2, 8, "authorization-data", 1004},
+
+	{ 3, 0, "flags"}, /* EncTicketPart */
+	{ 3, 1, "key", 1005},
+	{ 3, 2, "crealm"},
+	{ 3, 3, "cname", 1000},
+	{ 3, 4, "transited"},
+	{ 3, 5, "authtime"},
+	{ 3, 6, "starttime"},
+	{ 3, 7, "endtime"},
+	{ 3, 8, "renew-till"},
+	{ 3, 9, "caddr", 1003},
+	{ 3, 10, "authorization-data", 1004},
+
+	{ 10, 1, "pvno"},	/* AS-REQ */
+	{ 10, 2, "msg-type"},
+	{ 10, 3, "padata", 1008},
+	{ 10, 4, "req-body", 1007},
+
+	{ 11, 0, "pvno"},	/* AS-REP */
+	{ 11, 1, "msg-type"},
+	{ 11, 2, "padata", 1008},
+	{ 11, 3, "crealm"},
+	{ 11, 4, "cname", 1000},
+	{ 11, 5, "ticket"},
+	{ 11, 6, "enc-part", 1001},
+
+	{ 12, 1, "pvno"},	/* TGS-REQ */
+	{ 12, 2, "msg-type"},
+	{ 12, 3, "padata", 1008},
+	{ 12, 4, "req-body", 1007},
+
+	{ 13, 0, "pvno"},	/* TGS-REP */
+	{ 13, 1, "msg-type"},
+	{ 13, 2, "padata", 1008},
+	{ 13, 3, "crealm"},
+	{ 13, 4, "cname", 1000},
+	{ 13, 5, "ticket"},
+	{ 13, 6, "enc-part", 1001},
+
+	{ 14, 0, "pvno"},	/* AP-REQ */
+	{ 14, 1, "msg-type"},
+	{ 14, 2, "ap-options"},
+	{ 14, 3, "ticket"},
+	{ 14, 4, "authenticator", 1001},
+
+	{ 15, 0, "pvno"},	/* AP-REP */
+	{ 15, 1, "msg-type"},
+	{ 15, 2, "enc-part", 1001},
+	
+	{ 20, 0, "pvno"},	/* KRB-SAFE */
+	{ 20, 1, "msg-type"},
+	{ 20, 2, "safe-body", 1009},
+	{ 20, 3, "cksum", 1006},
+
+	{ 21, 0, "pvno"},	/* KRB-PRIV */
+	{ 21, 1, "msg-type"},
+	{ 21, 2, "enc-part", 1001},
+
+	{ 22, 0, "pvno"},	/* KRB-CRED */
+	{ 22, 1, "msg-type"},
+	{ 22, 2, "tickets"},
+	{ 22, 3, "enc-part", 1001},
+
+	{ 25, 0, "key", 1005},	/* EncASRepPart */
+	{ 25, 1, "last-req", 1010},
+	{ 25, 2, "nonce"},
+	{ 25, 3, "key-expiration"},
+	{ 25, 4, "flags"},
+	{ 25, 5, "authtime"},
+	{ 25, 6, "starttime"},
+	{ 25, 7, "enddtime"},
+	{ 25, 8, "renew-till"},
+	{ 25, 9, "srealm"},
+	{ 25, 10, "sname", 1000},
+	{ 25, 11, "caddr", 1003},
+	
+	{ 26, 0, "key", 1005},	/* EncTGSRepPart */
+	{ 26, 1, "last-req", 1010},
+	{ 26, 2, "nonce"},
+	{ 26, 3, "key-expiration"},
+	{ 26, 4, "flags"},
+	{ 26, 5, "authtime"},
+	{ 26, 6, "starttime"},
+	{ 26, 7, "enddtime"},
+	{ 26, 8, "renew-till"},
+	{ 26, 9, "srealm"},
+	{ 26, 10, "sname", 1000},
+	{ 26, 11, "caddr", 1003},
+	
+	{ 27, 0, "ctime"},	/* EncApRepPart */
+	{ 27, 1, "cusec"},
+	{ 27, 2, "subkey", 1005},
+	{ 27, 3, "seq-number"},
+
+	{ 28, 0, "user-data"},	/* EncKrbPrivPart */
+	{ 28, 1, "timestamp"},
+	{ 28, 2, "usec"},
+	{ 28, 3, "seq-number"},
+	{ 28, 4, "s-address", 1002},
+	{ 28, 5, "r-address", 1002},
+
+	{ 29, 0, "ticket-info", 1011},	/* EncKrbCredPart */
+	{ 29, 1, "nonce"},
+	{ 29, 2, "timestamp"},
+	{ 29, 3, "usec"},
+	{ 29, 4, "s-address", 1002},
+	{ 29, 5, "r-address", 1002},
+
+	{ 30, 0, "pvno"},	/* KRB-ERROR */
+	{ 30, 1, "msg-type"},
+	{ 30, 2, "ctime"},
+	{ 30, 3, "cusec"},
+	{ 30, 4, "stime"},
+	{ 30, 5, "susec"},
+	{ 30, 6, "error-code"},
+	{ 30, 7, "crealm"},
+	{ 30, 8, "cname", 1000},
+	{ 30, 9, "realm"},
+	{ 30, 10, "sname", 1000},
+	{ 30, 11, "e-text"},
+	{ 30, 12, "e-data"},
+	
+	{ -1, -1, 0}
+};
+#endif
+
+void print_tag_type(fp, eid, lev)
+        FILE *fp;
+        int     eid;
+        int     lev;
+{
+	int	tag = eid & ID_TAG;
+	int	do_space = 1;
+	char	*str;
+
+	fprintf(fp, "[");
+	
+	switch(eid & ID_CLASS) {
+	case CLASS_UNIV:
+		if (print_types && print_skip_tagnum)
+			do_space = 0;
+		else
+			fprintf(fp, "UNIV %d", tag);
+		break;
+	case CLASS_APPL:
+		current_appl_type = tag;
+#ifdef KRB5
+		if (print_krb5_types) {
+			str = lookup_typestring(krb5_types, tag, -1);
+			if (str) {
+				fputs(str, fp);
+				break;
+			}
+		}
+#endif
+		fprintf(fp, "APPL %d", tag);
+		break;
+	case CLASS_CONT:
+#ifdef KRB5
+		if (print_krb5_types && current_appl_type) {
+			str = lookup_typestring(krb5_fields,
+						current_appl_type, tag);
+			if (str) {
+				fputs(str, fp);
+				break;
+			}
+		}
+#endif
+		if (print_skip_context && lev)
+			fprintf(fp, "%d", tag);
+		else
+			fprintf(fp, "CONT %d", tag);
+		break;
+	case CLASS_PRIV:
+		fprintf(fp, "PRIV %d", tag);
+		break;
+	}
+	
+	if (print_types && ((eid & ID_CLASS) == CLASS_UNIV)) {
+		if (do_space)
+			fputs(" ", fp);
+		str = lookup_typestring(univ_types, eid & ID_TAG, -1);
+		if (str)
+			fputs(str, fp);
+		else
+			fprintf(fp, "UNIV %d???", eid & ID_TAG);
+	}
+	
+	fprintf(fp, "] ");
+	
+}	
+
+/*****************************************************************************/
+
diff --git a/mechglue/src/tests/asn.1/trval_reference.out b/mechglue/src/tests/asn.1/trval_reference.out
new file mode 100644
index 000000000..95311d3fe
--- /dev/null
+++ b/mechglue/src/tests/asn.1/trval_reference.out
@@ -0,0 +1,1198 @@
+encode_krb5_authenticator:
+
+[Krb5 Autenticator] 
+.  [Sequence/Sequence Of] 
+.  .  [authenticator-vno] [Integer] 5
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [cksum] [Sequence/Sequence Of] 
+.  .  .  [cksumtype] [Integer] 1
+.  .  .  [checksum] [Octet String] "1234"
+.  .  [cusec] [Integer] 123456
+.  .  [ctime] [Generalized Time] "19940610060317Z"
+.  .  [subkey] [Sequence/Sequence Of] 
+.  .  .  [keytype] [Integer] 1
+.  .  .  [keyvalue] [Octet String] "12345678"
+.  .  [seq-number] [Integer] 17
+.  .  [authorization-data] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [ad-type] [Integer] 1
+.  .  .  .  [ad-data] [Octet String] "foobar"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [ad-type] [Integer] 1
+.  .  .  .  [ad-data] [Octet String] "foobar"
+
+encode_krb5_authenticator(optionals empty):
+
+[Krb5 Autenticator] 
+.  [Sequence/Sequence Of] 
+.  .  [authenticator-vno] [Integer] 5
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [cusec] [Integer] 123456
+.  .  [ctime] [Generalized Time] "19940610060317Z"
+
+encode_krb5_authenticator(optionals NULL):
+
+[Krb5 Autenticator] 
+.  [Sequence/Sequence Of] 
+.  .  [authenticator-vno] [Integer] 5
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [cusec] [Integer] 123456
+.  .  [ctime] [Generalized Time] "19940610060317Z"
+
+encode_krb5_ticket:
+
+[Krb5 Ticket] 
+.  [Sequence/Sequence Of] 
+.  .  [tkt-vno] [Integer] 5
+.  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  [sname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  [etype] [Integer] 0
+.  .  .  [kvno] [Integer] 5
+.  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_keyblock:
+
+[Sequence/Sequence Of] 
+.  [keytype] [Integer] 1
+.  [keyvalue] [Octet String] "12345678"
+
+encode_krb5_enc_tkt_part:
+
+[Krb5 Encrypted ticket part] 
+.  [Sequence/Sequence Of] 
+.  .  [flags] [Bit String] 0xfedcba98
+.  .  [key] [Sequence/Sequence Of] 
+.  .  .  [keytype] [Integer] 1
+.  .  .  [keyvalue] [Octet String] "12345678"
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [transited] [Sequence/Sequence Of] 
+.  .  .  [flags] [Integer] 1
+.  .  .  [key] [Octet String] "EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS."
+.  .  [authtime] [Generalized Time] "19940610060317Z"
+.  .  [starttime] [Generalized Time] "19940610060317Z"
+.  .  [endtime] [Generalized Time] "19940610060317Z"
+.  .  [renew-till] [Generalized Time] "19940610060317Z"
+.  .  [caddr] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  [address] [Octet String] <4>
+               12 d0 00 23                                   ...#
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  [address] [Octet String] <4>
+               12 d0 00 23                                   ...#
+.  .  [authorization-data] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [ad-type] [Integer] 1
+.  .  .  .  [ad-data] [Octet String] "foobar"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [ad-type] [Integer] 1
+.  .  .  .  [ad-data] [Octet String] "foobar"
+
+encode_krb5_enc_tkt_part(optionals NULL):
+
+[Krb5 Encrypted ticket part] 
+.  [Sequence/Sequence Of] 
+.  .  [flags] [Bit String] 0xfedcba98
+.  .  [key] [Sequence/Sequence Of] 
+.  .  .  [keytype] [Integer] 1
+.  .  .  [keyvalue] [Octet String] "12345678"
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [transited] [Sequence/Sequence Of] 
+.  .  .  [flags] [Integer] 1
+.  .  .  [key] [Octet String] "EDU,MIT.,ATHENA.,WASHINGTON.EDU,CS."
+.  .  [authtime] [Generalized Time] "19940610060317Z"
+.  .  [endtime] [Generalized Time] "19940610060317Z"
+
+encode_krb5_enc_kdc_rep_part:
+
+[Krb5 Encrypted TGS-REP part] 
+.  [Sequence/Sequence Of] 
+.  .  [key] [Sequence/Sequence Of] 
+.  .  .  [keytype] [Integer] 1
+.  .  .  [keyvalue] [Octet String] "12345678"
+.  .  [last-req] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [lr-type] [Integer] -5
+.  .  .  .  [lr-value] [Generalized Time] "19940610060317Z"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [lr-type] [Integer] -5
+.  .  .  .  [lr-value] [Generalized Time] "19940610060317Z"
+.  .  [nonce] [Integer] 42
+.  .  [key-expiration] [Generalized Time] "19940610060317Z"
+.  .  [flags] [Bit String] 0xfedcba98
+.  .  [authtime] [Generalized Time] "19940610060317Z"
+.  .  [starttime] [Generalized Time] "19940610060317Z"
+.  .  [enddtime] [Generalized Time] "19940610060317Z"
+.  .  [renew-till] [Generalized Time] "19940610060317Z"
+.  .  [srealm] [General string] "ATHENA.MIT.EDU"
+.  .  [sname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [caddr] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  [address] [Octet String] <4>
+               12 d0 00 23                                   ...#
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  [address] [Octet String] <4>
+               12 d0 00 23                                   ...#
+
+encode_krb5_enc_kdc_rep_part(optionals NULL):
+
+[Krb5 Encrypted TGS-REP part] 
+.  [Sequence/Sequence Of] 
+.  .  [key] [Sequence/Sequence Of] 
+.  .  .  [keytype] [Integer] 1
+.  .  .  [keyvalue] [Octet String] "12345678"
+.  .  [last-req] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [lr-type] [Integer] -5
+.  .  .  .  [lr-value] [Generalized Time] "19940610060317Z"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [lr-type] [Integer] -5
+.  .  .  .  [lr-value] [Generalized Time] "19940610060317Z"
+.  .  [nonce] [Integer] 42
+.  .  [flags] [Bit String] 0xfe5cba98
+.  .  [authtime] [Generalized Time] "19940610060317Z"
+.  .  [enddtime] [Generalized Time] "19940610060317Z"
+.  .  [srealm] [General string] "ATHENA.MIT.EDU"
+.  .  [sname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+
+encode_krb5_as_rep:
+
+[Krb5 AS-REP packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 11
+.  .  [padata] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [padata-type] [Integer] 13
+.  .  .  .  [pa-data] [Octet String] "pa-data"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [padata-type] [Integer] 13
+.  .  .  .  [pa-data] [Octet String] "pa-data"
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [ticket] [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  [enc-part] [Sequence/Sequence Of] 
+.  .  .  [etype] [Integer] 0
+.  .  .  [kvno] [Integer] 5
+.  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_as_rep(optionals NULL):
+
+[Krb5 AS-REP packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 11
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [ticket] [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  [enc-part] [Sequence/Sequence Of] 
+.  .  .  [etype] [Integer] 0
+.  .  .  [kvno] [Integer] 5
+.  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_tgs_rep:
+
+[Krb5 TGS-REP packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 13
+.  .  [padata] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [padata-type] [Integer] 13
+.  .  .  .  [pa-data] [Octet String] "pa-data"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [padata-type] [Integer] 13
+.  .  .  .  [pa-data] [Octet String] "pa-data"
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [ticket] [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  [enc-part] [Sequence/Sequence Of] 
+.  .  .  [etype] [Integer] 0
+.  .  .  [kvno] [Integer] 5
+.  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_tgs_rep(optionals NULL):
+
+[Krb5 TGS-REP packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 13
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [ticket] [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  [enc-part] [Sequence/Sequence Of] 
+.  .  .  [etype] [Integer] 0
+.  .  .  [kvno] [Integer] 5
+.  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_ap_req:
+
+[Krb5 AP-REQ packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 14
+.  .  [ap-options] [Bit String] 0xfedcba98
+.  .  [ticket] [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  [authenticator] [Sequence/Sequence Of] 
+.  .  .  [etype] [Integer] 0
+.  .  .  [kvno] [Integer] 5
+.  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_ap_rep:
+
+[Krb5 AP-REP packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 15
+.  .  [enc-part] [Sequence/Sequence Of] 
+.  .  .  [etype] [Integer] 0
+.  .  .  [kvno] [Integer] 5
+.  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_ap_rep_enc_part:
+
+[Krb5 Encrypted AP-REP part] 
+.  [Sequence/Sequence Of] 
+.  .  [ctime] [Generalized Time] "19940610060317Z"
+.  .  [cusec] [Integer] 123456
+.  .  [subkey] [Sequence/Sequence Of] 
+.  .  .  [keytype] [Integer] 1
+.  .  .  [keyvalue] [Octet String] "12345678"
+.  .  [seq-number] [Integer] 17
+
+encode_krb5_ap_rep_enc_part(optionals NULL):
+
+[Krb5 Encrypted AP-REP part] 
+.  [Sequence/Sequence Of] 
+.  .  [ctime] [Generalized Time] "19940610060317Z"
+.  .  [cusec] [Integer] 123456
+
+encode_krb5_as_req:
+
+[Krb5 AS-REQ packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 10
+.  .  [padata] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [padata-type] [Integer] 13
+.  .  .  .  [pa-data] [Octet String] "pa-data"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [padata-type] [Integer] 13
+.  .  .  .  [pa-data] [Octet String] "pa-data"
+.  .  [req-body] [Sequence/Sequence Of] 
+.  .  .  [kdc-options] [Bit String] 0xfedcba90
+.  .  .  [cname] [Sequence/Sequence Of] 
+.  .  .  .  [name-type] [Integer] 1
+.  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  [General string] "extra"
+.  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  [name-type] [Integer] 1
+.  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  [General string] "extra"
+.  .  .  [from] [Generalized Time] "19940610060317Z"
+.  .  .  [till] [Generalized Time] "19940610060317Z"
+.  .  .  [rtime] [Generalized Time] "19940610060317Z"
+.  .  .  [nonce] [Integer] 42
+.  .  .  [etype] [Sequence/Sequence Of] 
+.  .  .  .  [Integer] 0
+.  .  .  .  [Integer] 1
+.  .  .  [addresses] [Sequence/Sequence Of] 
+.  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  [address] [Octet String] <4>
+                  12 d0 00 23                                ...#
+.  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  [address] [Octet String] <4>
+                  12 d0 00 23                                ...#
+.  .  .  [enc-authorization-data] [Sequence/Sequence Of] 
+.  .  .  .  [etype] [Integer] 0
+.  .  .  .  [kvno] [Integer] 5
+.  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  .  [additional-tickets] [Sequence/Sequence Of] 
+.  .  .  .  [Krb5 Ticket] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  .  .  [Krb5 Ticket] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_as_req(optionals NULL except second_ticket):
+
+[Krb5 AS-REQ packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 10
+.  .  [req-body] [Sequence/Sequence Of] 
+.  .  .  [kdc-options] [Bit String] 0xfedcba98
+.  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  [till] [Generalized Time] "19940610060317Z"
+.  .  .  [nonce] [Integer] 42
+.  .  .  [etype] [Sequence/Sequence Of] 
+.  .  .  .  [Integer] 0
+.  .  .  .  [Integer] 1
+.  .  .  [additional-tickets] [Sequence/Sequence Of] 
+.  .  .  .  [Krb5 Ticket] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  .  .  [Krb5 Ticket] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_as_req(optionals NULL except server):
+
+[Krb5 AS-REQ packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 10
+.  .  [req-body] [Sequence/Sequence Of] 
+.  .  .  [kdc-options] [Bit String] 0xfedcba90
+.  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  [name-type] [Integer] 1
+.  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  [General string] "extra"
+.  .  .  [till] [Generalized Time] "19940610060317Z"
+.  .  .  [nonce] [Integer] 42
+.  .  .  [etype] [Sequence/Sequence Of] 
+.  .  .  .  [Integer] 0
+.  .  .  .  [Integer] 1
+
+encode_krb5_tgs_req:
+
+[Krb5 TGS-REQ packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 12
+.  .  [padata] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [padata-type] [Integer] 13
+.  .  .  .  [pa-data] [Octet String] "pa-data"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [padata-type] [Integer] 13
+.  .  .  .  [pa-data] [Octet String] "pa-data"
+.  .  [req-body] [Sequence/Sequence Of] 
+.  .  .  [kdc-options] [Bit String] 0xfedcba90
+.  .  .  [cname] [Sequence/Sequence Of] 
+.  .  .  .  [name-type] [Integer] 1
+.  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  [General string] "extra"
+.  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  [name-type] [Integer] 1
+.  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  [General string] "extra"
+.  .  .  [from] [Generalized Time] "19940610060317Z"
+.  .  .  [till] [Generalized Time] "19940610060317Z"
+.  .  .  [rtime] [Generalized Time] "19940610060317Z"
+.  .  .  [nonce] [Integer] 42
+.  .  .  [etype] [Sequence/Sequence Of] 
+.  .  .  .  [Integer] 0
+.  .  .  .  [Integer] 1
+.  .  .  [addresses] [Sequence/Sequence Of] 
+.  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  [address] [Octet String] <4>
+                  12 d0 00 23                                ...#
+.  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  [address] [Octet String] <4>
+                  12 d0 00 23                                ...#
+.  .  .  [enc-authorization-data] [Sequence/Sequence Of] 
+.  .  .  .  [etype] [Integer] 0
+.  .  .  .  [kvno] [Integer] 5
+.  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  .  [additional-tickets] [Sequence/Sequence Of] 
+.  .  .  .  [Krb5 Ticket] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  .  .  [Krb5 Ticket] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_tgs_req(optionals NULL except second_ticket):
+
+[Krb5 TGS-REQ packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 12
+.  .  [req-body] [Sequence/Sequence Of] 
+.  .  .  [kdc-options] [Bit String] 0xfedcba98
+.  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  [till] [Generalized Time] "19940610060317Z"
+.  .  .  [nonce] [Integer] 42
+.  .  .  [etype] [Sequence/Sequence Of] 
+.  .  .  .  [Integer] 0
+.  .  .  .  [Integer] 1
+.  .  .  [additional-tickets] [Sequence/Sequence Of] 
+.  .  .  .  [Krb5 Ticket] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  .  .  [Krb5 Ticket] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_tgs_req(optionals NULL except server):
+
+[Krb5 TGS-REQ packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 12
+.  .  [req-body] [Sequence/Sequence Of] 
+.  .  .  [kdc-options] [Bit String] 0xfedcba90
+.  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  [name-type] [Integer] 1
+.  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  [General string] "extra"
+.  .  .  [till] [Generalized Time] "19940610060317Z"
+.  .  .  [nonce] [Integer] 42
+.  .  .  [etype] [Sequence/Sequence Of] 
+.  .  .  .  [Integer] 0
+.  .  .  .  [Integer] 1
+
+encode_krb5_kdc_req_body:
+
+[Sequence/Sequence Of] 
+.  [kdc-options] [Bit String] 0xfedcba90
+.  [cname] [Sequence/Sequence Of] 
+.  .  [name-type] [Integer] 1
+.  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  [General string] "hftsai"
+.  .  .  [General string] "extra"
+.  [realm] [General string] "ATHENA.MIT.EDU"
+.  [sname] [Sequence/Sequence Of] 
+.  .  [name-type] [Integer] 1
+.  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  [General string] "hftsai"
+.  .  .  [General string] "extra"
+.  [from] [Generalized Time] "19940610060317Z"
+.  [till] [Generalized Time] "19940610060317Z"
+.  [rtime] [Generalized Time] "19940610060317Z"
+.  [nonce] [Integer] 42
+.  [etype] [Sequence/Sequence Of] 
+.  .  [Integer] 0
+.  .  [Integer] 1
+.  [addresses] [Sequence/Sequence Of] 
+.  .  [Sequence/Sequence Of] 
+.  .  .  [addr-type] [Integer] 2
+.  .  .  [address] [Octet String] <4>
+            12 d0 00 23                                      ...#
+.  .  [Sequence/Sequence Of] 
+.  .  .  [addr-type] [Integer] 2
+.  .  .  [address] [Octet String] <4>
+            12 d0 00 23                                      ...#
+.  [enc-authorization-data] [Sequence/Sequence Of] 
+.  .  [etype] [Integer] 0
+.  .  [kvno] [Integer] 5
+.  .  [cipher] [Octet String] "krbASN.1 test message"
+.  [additional-tickets] [Sequence/Sequence Of] 
+.  .  [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_kdc_req_body(optionals NULL except second_ticket):
+
+[Sequence/Sequence Of] 
+.  [kdc-options] [Bit String] 0xfedcba98
+.  [realm] [General string] "ATHENA.MIT.EDU"
+.  [till] [Generalized Time] "19940610060317Z"
+.  [nonce] [Integer] 42
+.  [etype] [Sequence/Sequence Of] 
+.  .  [Integer] 0
+.  .  [Integer] 1
+.  [additional-tickets] [Sequence/Sequence Of] 
+.  .  [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  [Krb5 Ticket] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_kdc_req_body(optionals NULL except server):
+
+[Sequence/Sequence Of] 
+.  [kdc-options] [Bit String] 0xfedcba90
+.  [realm] [General string] "ATHENA.MIT.EDU"
+.  [sname] [Sequence/Sequence Of] 
+.  .  [name-type] [Integer] 1
+.  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  [General string] "hftsai"
+.  .  .  [General string] "extra"
+.  [till] [Generalized Time] "19940610060317Z"
+.  [nonce] [Integer] 42
+.  [etype] [Sequence/Sequence Of] 
+.  .  [Integer] 0
+.  .  [Integer] 1
+
+encode_krb5_safe:
+
+[Krb5 SAFE packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 20
+.  .  [safe-body] [Sequence/Sequence Of] 
+.  .  .  [user-data] [Octet String] "krb5data"
+.  .  .  [timestamp] [Generalized Time] "19940610060317Z"
+.  .  .  [usec] [Integer] 123456
+.  .  .  [seq-number] [Integer] 17
+.  .  .  [s-address] [Sequence/Sequence Of] 
+.  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  [address] [Octet String] <4>
+               12 d0 00 23                                   ...#
+.  .  .  [r-address] [Sequence/Sequence Of] 
+.  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  [address] [Octet String] <4>
+               12 d0 00 23                                   ...#
+.  .  [cksum] [Sequence/Sequence Of] 
+.  .  .  [cksumtype] [Integer] 1
+.  .  .  [checksum] [Octet String] "1234"
+
+encode_krb5_safe(optionals NULL):
+
+[Krb5 SAFE packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 20
+.  .  [safe-body] [Sequence/Sequence Of] 
+.  .  .  [user-data] [Octet String] "krb5data"
+.  .  .  [s-address] [Sequence/Sequence Of] 
+.  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  [address] [Octet String] <4>
+               12 d0 00 23                                   ...#
+.  .  [cksum] [Sequence/Sequence Of] 
+.  .  .  [cksumtype] [Integer] 1
+.  .  .  [checksum] [Octet String] "1234"
+
+encode_krb5_priv:
+
+[Krb5 PRIV packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 21
+.  .  [3] [Sequence/Sequence Of] 
+.  .  .  [pvno] [Integer] 0
+.  .  .  [msg-type] [Integer] 5
+.  .  .  [enc-part] [Octet String] "krbASN.1 test message"
+
+encode_krb5_enc_priv_part:
+
+[Krb5 Encrypted PRIV part] 
+.  [Sequence/Sequence Of] 
+.  .  [user-data] [Octet String] "krb5data"
+.  .  [timestamp] [Generalized Time] "19940610060317Z"
+.  .  [usec] [Integer] 123456
+.  .  [seq-number] [Integer] 17
+.  .  [s-address] [Sequence/Sequence Of] 
+.  .  .  [addr-type] [Integer] 2
+.  .  .  [address] [Octet String] <4>
+            12 d0 00 23                                      ...#
+.  .  [r-address] [Sequence/Sequence Of] 
+.  .  .  [addr-type] [Integer] 2
+.  .  .  [address] [Octet String] <4>
+            12 d0 00 23                                      ...#
+
+encode_krb5_enc_priv_part(optionals NULL):
+
+[Krb5 Encrypted PRIV part] 
+.  [Sequence/Sequence Of] 
+.  .  [user-data] [Octet String] "krb5data"
+.  .  [s-address] [Sequence/Sequence Of] 
+.  .  .  [addr-type] [Integer] 2
+.  .  .  [address] [Octet String] <4>
+            12 d0 00 23                                      ...#
+
+encode_krb5_cred:
+
+[Krb5 CRED packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 22
+.  .  [tickets] [Sequence/Sequence Of] 
+.  .  .  [Krb5 Ticket] 
+.  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  .  [Krb5 Ticket] 
+.  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  [tkt-vno] [Integer] 5
+.  .  .  .  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  .  [General string] "extra"
+.  .  .  .  .  [tkt-enc-part] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [etype] [Integer] 0
+.  .  .  .  .  .  [kvno] [Integer] 5
+.  .  .  .  .  .  [cipher] [Octet String] "krbASN.1 test message"
+.  .  [enc-part] [Sequence/Sequence Of] 
+.  .  .  [etype] [Integer] 0
+.  .  .  [kvno] [Integer] 5
+.  .  .  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_enc_cred_part:
+
+[Krb5 Encrypted CRED part] 
+.  [Sequence/Sequence Of] 
+.  .  [ticket-info] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [key] [Sequence/Sequence Of] 
+.  .  .  .  .  [keytype] [Integer] 1
+.  .  .  .  .  [keyvalue] [Octet String] "12345678"
+.  .  .  .  [prealm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [pname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [flags] [Bit String] 0xfedcba98
+.  .  .  .  [authtime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [startime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [endtime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [renew-till] [Generalized Time] "19940610060317Z"
+.  .  .  .  [srealm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [caddr] [Sequence/Sequence Of] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  .  [address] [Octet String] <4>
+                     12 d0 00 23                             ...#
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  .  [address] [Octet String] <4>
+                     12 d0 00 23                             ...#
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [key] [Sequence/Sequence Of] 
+.  .  .  .  .  [keytype] [Integer] 1
+.  .  .  .  .  [keyvalue] [Octet String] "12345678"
+.  .  .  .  [prealm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [pname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [flags] [Bit String] 0xfedcba98
+.  .  .  .  [authtime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [startime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [endtime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [renew-till] [Generalized Time] "19940610060317Z"
+.  .  .  .  [srealm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [caddr] [Sequence/Sequence Of] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  .  [address] [Octet String] <4>
+                     12 d0 00 23                             ...#
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  .  [address] [Octet String] <4>
+                     12 d0 00 23                             ...#
+.  .  [nonce] [Integer] 42
+.  .  [timestamp] [Generalized Time] "19940610060317Z"
+.  .  [usec] [Integer] 123456
+.  .  [s-address] [Sequence/Sequence Of] 
+.  .  .  [addr-type] [Integer] 2
+.  .  .  [address] [Octet String] <4>
+            12 d0 00 23                                      ...#
+.  .  [r-address] [Sequence/Sequence Of] 
+.  .  .  [addr-type] [Integer] 2
+.  .  .  [address] [Octet String] <4>
+            12 d0 00 23                                      ...#
+
+encode_krb5_enc_cred_part(optionals NULL):
+
+[Krb5 Encrypted CRED part] 
+.  [Sequence/Sequence Of] 
+.  .  [ticket-info] [Sequence/Sequence Of] 
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [key] [Sequence/Sequence Of] 
+.  .  .  .  .  [keytype] [Integer] 1
+.  .  .  .  .  [keyvalue] [Octet String] "12345678"
+.  .  .  [Sequence/Sequence Of] 
+.  .  .  .  [key] [Sequence/Sequence Of] 
+.  .  .  .  .  [keytype] [Integer] 1
+.  .  .  .  .  [keyvalue] [Octet String] "12345678"
+.  .  .  .  [prealm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [pname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [flags] [Bit String] 0xfedcba98
+.  .  .  .  [authtime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [startime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [endtime] [Generalized Time] "19940610060317Z"
+.  .  .  .  [renew-till] [Generalized Time] "19940610060317Z"
+.  .  .  .  [srealm] [General string] "ATHENA.MIT.EDU"
+.  .  .  .  [sname] [Sequence/Sequence Of] 
+.  .  .  .  .  [name-type] [Integer] 1
+.  .  .  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  .  .  [General string] "hftsai"
+.  .  .  .  .  .  [General string] "extra"
+.  .  .  .  [caddr] [Sequence/Sequence Of] 
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  .  [address] [Octet String] <4>
+                     12 d0 00 23                             ...#
+.  .  .  .  .  [Sequence/Sequence Of] 
+.  .  .  .  .  .  [addr-type] [Integer] 2
+.  .  .  .  .  .  [address] [Octet String] <4>
+                     12 d0 00 23                             ...#
+
+encode_krb5_error:
+
+[Krb5 ERROR packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 30
+.  .  [ctime] [Generalized Time] "19940610060317Z"
+.  .  [cusec] [Integer] 123456
+.  .  [stime] [Generalized Time] "19940610060317Z"
+.  .  [susec] [Integer] 123456
+.  .  [error-code] [Integer] 60
+.  .  [crealm] [General string] "ATHENA.MIT.EDU"
+.  .  [cname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  [sname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+.  .  [e-text] [General string] "krb5data"
+.  .  [e-data] [Octet String] "krb5data"
+
+encode_krb5_error(optionals NULL):
+
+[Krb5 ERROR packet] 
+.  [Sequence/Sequence Of] 
+.  .  [pvno] [Integer] 5
+.  .  [msg-type] [Integer] 30
+.  .  [cusec] [Integer] 123456
+.  .  [stime] [Generalized Time] "19940610060317Z"
+.  .  [susec] [Integer] 123456
+.  .  [error-code] [Integer] 60
+.  .  [realm] [General string] "ATHENA.MIT.EDU"
+.  .  [sname] [Sequence/Sequence Of] 
+.  .  .  [name-type] [Integer] 1
+.  .  .  [name-string] [Sequence/Sequence Of] 
+.  .  .  .  [General string] "hftsai"
+.  .  .  .  [General string] "extra"
+
+encode_krb5_authorization_data:
+
+[Sequence/Sequence Of] 
+.  [Sequence/Sequence Of] 
+.  .  [ad-type] [Integer] 1
+.  .  [ad-data] [Octet String] "foobar"
+.  [Sequence/Sequence Of] 
+.  .  [ad-type] [Integer] 1
+.  .  [ad-data] [Octet String] "foobar"
+
+encode_krb5_pwd_sequence:
+
+[Sequence/Sequence Of] 
+.  [0] [Octet String] "krb5data"
+.  [1] [Octet String] "krb5data"
+
+encode_krb5_pwd_data:
+
+[Sequence/Sequence Of] 
+.  [0] [Integer] 2
+.  [1] [Sequence/Sequence Of] 
+.  .  [Sequence/Sequence Of] 
+.  .  .  [0] [Octet String] "krb5data"
+.  .  .  [1] [Octet String] "krb5data"
+.  .  [Sequence/Sequence Of] 
+.  .  .  [0] [Octet String] "krb5data"
+.  .  .  [1] [Octet String] "krb5data"
+
+encode_krb5_padata_sequence:
+
+[Sequence/Sequence Of] 
+.  [Sequence/Sequence Of] 
+.  .  [1] [Integer] 13
+.  .  [2] [Octet String] "pa-data"
+.  [Sequence/Sequence Of] 
+.  .  [1] [Integer] 13
+.  .  [2] [Octet String] "pa-data"
+
+encode_krb5_padata_sequence(empty):
+
+[Sequence/Sequence Of] 
+
+encode_krb5_alt_method:
+
+[Sequence/Sequence Of] 
+.  [0] [Integer] 42
+.  [1] [Octet String] "secret"
+
+encode_krb5_alt_method (no data):
+
+[Sequence/Sequence Of] 
+.  [0] [Integer] 42
+
+encode_krb5_etype_info:
+
+[Sequence/Sequence Of] 
+.  [Sequence/Sequence Of] 
+.  .  [0] [Integer] 0
+.  .  [1] [Octet String] "Morton's #0"
+.  [Sequence/Sequence Of] 
+.  .  [0] [Integer] 1
+.  [Sequence/Sequence Of] 
+.  .  [0] [Integer] 2
+.  .  [1] [Octet String] "Morton's #2"
+
+encode_krb5_etype_info (only 1):
+
+[Sequence/Sequence Of] 
+.  [Sequence/Sequence Of] 
+.  .  [0] [Integer] 0
+.  .  [1] [Octet String] "Morton's #0"
+
+encode_krb5_etype_info (no info):
+
+[Sequence/Sequence Of] 
+
+encode_krb5_etype_info2:
+
+[Sequence/Sequence Of] 
+.  [Sequence/Sequence Of] 
+.  .  [0] [Integer] 0
+.  .  [1] [General string] "Morton's #0"
+.  .  [2] [Octet String] "s2k: 0"
+.  [Sequence/Sequence Of] 
+.  .  [0] [Integer] 1
+.  .  [2] [Octet String] "s2k: 1"
+.  [Sequence/Sequence Of] 
+.  .  [0] [Integer] 2
+.  .  [1] [General string] "Morton's #2"
+.  .  [2] [Octet String] "s2k: 2"
+
+encode_krb5_etype_info2 (only 1):
+
+[Sequence/Sequence Of] 
+.  [Sequence/Sequence Of] 
+.  .  [0] [Integer] 0
+.  .  [1] [General string] "Morton's #0"
+.  .  [2] [Octet String] "s2k: 0"
+
+encode_krb5_pa_enc_ts:
+
+[Sequence/Sequence Of] 
+.  [0] [Generalized Time] "19940610060317Z"
+.  [1] [Integer] 123456
+
+encode_krb5_pa_enc_ts (no usec):
+
+[Sequence/Sequence Of] 
+.  [0] [Generalized Time] "19940610060317Z"
+
+encode_krb5_enc_data:
+
+[Sequence/Sequence Of] 
+.  [etype] [Integer] 0
+.  [kvno] [Integer] 5
+.  [cipher] [Octet String] "krbASN.1 test message"
+
+encode_krb5_sam_challenge:
+
+[Sequence/Sequence Of] 
+.  [0] [Integer] 42
+.  [1] [Bit String] 0x80000000
+.  [2] [Octet String] "type name"
+.  [4] [Octet String] "challenge label"
+.  [5] [Octet String] "challenge ipse"
+.  [6] [Octet String] "response_prompt ipse"
+.  [8] [Integer] 5517840
+.  [9] [Sequence/Sequence Of] 
+.  .  [0] [Integer] 1
+.  .  [1] [Octet String] "1234"
+
+encode_krb5_sam_response:
+
+[Sequence/Sequence Of] 
+.  [0] [Integer] 42
+.  [1] [Bit String] 0x80000000
+.  [2] [Octet String] "track data"
+.  [3] [Sequence/Sequence Of] 
+.  .  [0] [Integer] 1
+.  .  [1] [Integer] 1942
+.  .  [2] [Octet String] "key"
+.  [4] [Sequence/Sequence Of] 
+.  .  [0] [Integer] 1
+.  .  [1] [Integer] 3382
+.  .  [2] [Octet String] "nonce or ts"
+.  [5] [Integer] 5517840
+.  [6] [Generalized Time] "19940610060317Z"
+
diff --git a/mechglue/src/tests/asn.1/utility.c b/mechglue/src/tests/asn.1/utility.c
new file mode 100644
index 000000000..660161fa1
--- /dev/null
+++ b/mechglue/src/tests/asn.1/utility.c
@@ -0,0 +1,125 @@
+#include "utility.h"
+#include "krb5.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+char hexchar (const unsigned int digit);
+
+asn1_error_code asn1_krb5_data_unparse(code, s)
+     const krb5_data * code;
+     char ** s;
+{
+  if(*s != NULL) free(*s);
+  
+  if(code==NULL){
+    *s = (char*)calloc(strlen("<NULL>")+1, sizeof(char));
+    if(*s == NULL) return ENOMEM;
+    strcpy(*s,"<NULL>");
+  }else if(code->data == NULL || ((int) code->length) <= 0){
+    *s = (char*)calloc(strlen("<EMPTY>")+1, sizeof(char));
+    if(*s==NULL) return ENOMEM;
+    strcpy(*s,"<EMPTY>");
+  }else{
+    int i;
+
+    *s = (char*)calloc((size_t) 3*(code->length), sizeof(char));
+    if(*s == NULL) return ENOMEM;
+    for(i = 0; i < code->length; i++){
+      (*s)[3*i] = hexchar((unsigned char) (((code->data)[i]&0xF0)>>4));
+      (*s)[3*i+1] = hexchar((unsigned char) ((code->data)[i]&0x0F));
+      (*s)[3*i+2] = ' ';
+    }
+    (*s)[3*(code->length)-1] = '\0';
+  }
+  return 0;
+}
+
+char hexchar(digit)
+     const unsigned int digit;
+{
+  if(digit<=9)
+    return '0'+digit;
+  else if(digit<=15)
+    return 'A'+digit-10;
+  else
+    return 'X';
+}
+
+krb5_error_code krb5_data_parse(d, s)
+     krb5_data * d;
+     const char * s;
+{
+  /*if(d->data != NULL){
+    free(d->data);
+    d->length = 0;
+  }*/
+  d->data = (char*)calloc(strlen(s),sizeof(char));
+  if(d->data == NULL) return ENOMEM;
+  d->length = strlen(s);
+  memcpy(d->data,s,strlen(s));
+  return 0;
+}
+
+krb5_error_code krb5_data_hex_parse(krb5_data *d, const char *s)
+{
+    int lo;
+    long v;
+    const char *cp;
+    char *dp;
+    char buf[2];
+
+    d->data = calloc((strlen(s) / 2 + 1), 1);
+    if (d->data == NULL)
+	return ENOMEM;
+    d->length = 0;
+    buf[1] = '\0';
+    for (lo = 0, dp = d->data, cp = s; *cp; cp++) {
+	if (*cp < 0)
+	    return ASN1_PARSE_ERROR;
+	else if (isspace(*cp))
+	    continue;
+	else if (isxdigit(*cp)) {
+	    buf[0] = *cp;
+	    v = strtol(buf, NULL, 16);
+	} else
+	    return ASN1_PARSE_ERROR;
+	if (lo) {
+	    *dp++ |= v;
+	    lo = 0;
+	} else {
+	    *dp = v << 4;
+	    lo = 1;
+	}
+    }
+
+    d->length = dp - d->data;
+    return 0;
+}
+
+#if 0
+void asn1buf_print(buf)
+     const asn1buf * buf;
+{
+  asn1buf bufcopy;
+  char *s=NULL;
+  int length;
+  int i;
+  
+  bufcopy.base = bufcopy.next = buf->next;
+  bufcopy.bound = buf->bound;
+  length = asn1buf_len(&bufcopy);
+
+  s = calloc(3*length, sizeof(char));
+  if(s == NULL) return;
+  for(i=0; i<length; i++){
+    s[3*i] = hexchar(((bufcopy.base)[i]&0xF0)>>4);
+    s[3*i+1] = hexchar((bufcopy.base)[i]&0x0F);
+    s[3*i+2] = ' ';
+  }
+  s[3*length-1] = '\0';
+
+  printf("%s\n",s);
+  free(s);
+}
+#endif
diff --git a/mechglue/src/tests/asn.1/utility.h b/mechglue/src/tests/asn.1/utility.h
new file mode 100644
index 000000000..4c761244f
--- /dev/null
+++ b/mechglue/src/tests/asn.1/utility.h
@@ -0,0 +1,31 @@
+#ifndef __UTILITY_H__
+#define __UTILITY_H__
+
+#include "krbasn1.h"
+#include "asn1buf.h"
+
+asn1_error_code asn1_krb5_data_unparse
+	(const krb5_data *code, char **s);
+/* modifies  *s;
+   effects   Instantiates *s with a string representation of the series
+	      of hex octets in *code.  (e.g. "02 02 00 7F")  If code==NULL,
+	      the string rep is "<NULL>".  If code is empty (it contains no
+	      data or has length <= 0), the string rep is "<EMPTY>".
+	     If *s is non-NULL, then its currently-allocated storage
+	      will be freed prior to the instantiation.
+	     Returns ENOMEM or the string rep cannot be created. */
+
+krb5_error_code krb5_data_parse
+	(krb5_data *d, const char *s);
+/* effects  Parses character string *s into krb5_data *d. */
+
+krb5_error_code krb5_data_hex_parse
+	(krb5_data *d, const char *s);
+/* requires  *s is the string representation of a sequence of
+              hexadecimal octets.  (e.g. "02 01 00")
+   effects  Parses *s into krb5_data *d. */
+
+void asn1buf_print
+	(const asn1buf *buf);
+
+#endif
diff --git a/mechglue/src/tests/configure.in b/mechglue/src/tests/configure.in
new file mode 100644
index 000000000..9b8619b14
--- /dev/null
+++ b/mechglue/src/tests/configure.in
@@ -0,0 +1,30 @@
+K5_AC_INIT(configure.in)
+CONFIG_RULES
+KRB5_RUN_FLAGS
+KRB5_BUILD_PROGRAM
+dnl Set krb5_cv_host
+KRB5_LIB_PARAMS
+dnl
+AC_HEADER_STDC
+AC_CHECK_FUNCS(strchr sem_init sem_trywait)
+AC_CHECK_HEADERS(unistd.h stdlib.h sys/param.h sys/socket.h dlfcn.h semaphore.h)
+AC_C_CONST
+AC_PROG_INSTALL
+AC_CHECK_PROG(RUNTEST,runtest,runtest)
+if test x"$RUNTEST" != x; then
+	HAVE_RUNTEST=yes
+else
+	HAVE_RUNTEST=no
+fi
+AC_SUBST(HAVE_RUNTEST)
+AC_TYPE_SIGNAL
+CHECK_SIGNALS
+if test "$KRB4_LIB" = ''; then
+	KRB4_DEJAGNU_TEST="KRBIV=0"
+else
+	AC_MSG_RESULT(Kerberos 4 testing enabled)
+	KRB4_DEJAGNU_TEST="KRBIV=1"
+fi
+AC_SUBST(KRB4_DEJAGNU_TEST)
+KRB5_AC_PRIOCNTL_HACK
+V5_AC_OUTPUT_MAKEFILE(. resolve asn.1 create hammer verify gssapi dejagnu threads shlib gss-threads misc)
diff --git a/mechglue/src/tests/create/.Sanitize b/mechglue/src/tests/create/.Sanitize
new file mode 100644
index 000000000..ce26940a4
--- /dev/null
+++ b/mechglue/src/tests/create/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+kdb5_mkdums.M
+kdb5_mkdums.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/create/ChangeLog b/mechglue/src/tests/create/ChangeLog
new file mode 100644
index 000000000..0d0395d00
--- /dev/null
+++ b/mechglue/src/tests/create/ChangeLog
@@ -0,0 +1,226 @@
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_mkdums.c (set_dbname_help): Set default realm and construct
+	an argument vector describing the database pathname, before
+	calling krb5_db_open.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+ 	* Makefile.in (KDB5_DEP_LIB): Use DL_LIB and THREAD_LINKOPTS
+	instead of explicitly using -ldl and -lpthread.
+
+	Novell merge.
+	* Makefile.in:
+	* kdb5_mkdums.c:
+
+2004-05-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_mkdums.c (main): Fix memory leak of master principal at exit. 
+
+2003-05-22  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_mkdums.c (main): When attempting to register writable
+	keytab, do not fail if error is KRB5_KT_TYPE_EXISTS.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_mkdums.c (main): Call krb5_c_valid_enctype instead of
+	valid_enctype.
+
+2001-11-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_mkdums.c (main): Invoke krb5_free_context when finished. 
+	(add_princ): Use krb5_free_principal to prevent memory leak.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_mkdums.c: Make prototypes unconditional.
+
+2000-07-28  Ezra Peisach  <epeisach@engrailed.mit.edu>
+
+	* kdb5_mkdums.c: Remove unused quit().
+
+2000-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_mkdums.c: Remove unused variable.
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kdb5_mkdums.c (main): Make sure buffer 'principal' is terminated.
+
+2000-05-08  Ken Raeburn  <raeburn@mit.edu>
+	    Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kdb5_mkdums.c (main): Make sure buffer "tmp" is
+	null-terminated.  Don't overflow buffer "tmp" or "tmp2".
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* kdb5_mkdums.c: update to new crypto api
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdb5_mkdums.c (argv): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Mon Mar 30 16:57:43 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_mkdums.c: Add parenthesis about assignements in conditionals.
+
+
+Wed Feb 18 16:28:15 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 16:46:04 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sun Aug 17 14:26:57 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(SRCS) line.
+
+Wed Jul 30 18:27:36 1997  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_mkdums.c: Update to match reality of libkdb, so that it
+	actually works.
+
+Tue Feb 18 18:20:14 1997  Richard Basch  <basch@lehman.com>
+
+	* kdb5_mkdums.c (add_princ): 
+		Replace krb5_xfree with krb5_free_data_contents
+
+Sun Feb  9 01:35:19 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Tue Sep 10 14:20:09 1996  Tom Yu  <tlyu@mit.edu>
+
+	* kdb5_mkdums.M: remove ".so man1/header.doc"
+
+Thu May  2 21:17:27 1996  Richard Basch  <basch@lehman.com>
+
+	* kdb5_mkdums.c: fixed various abstraction violations where the
+		code "knew" the cryptosystem_entry structure
+
+Sat Dec 23 01:04:40 1995    <tytso@rsts-11.mit.edu>
+
+	* configure.in: Add check for DBM/db libraries
+
+Wed Dec 13 03:51:53 1995  Chris Provenzano (proven@mit.edu)
+ 
+        * kdb5_mkdums.c : Remove mkvno from krb5_db_entry
+ 
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * kdb5_mkdums.c : Remove krb5_enctype from krb5_string_to_key() args.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * kdb5_mkdums.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * kdb5_mkdums.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate
+
+Thu Jul 27 15:30:09 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb5_mkdums.c - Restore old logic to find the etype now that crypto-
+		conf.c is correctly generated.
+
+Thu Jul 27 02:59:05 1995        Chris Provenzano (proven@mit.edu)
+        * kdb5_mkdums.c : Use new kdb format.
+
+Mon Jul 17 15:23:24 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb5_mkdums.c - Change setting of defaulted keytype to be DEFAULT_
+		KDC_ETYPE instead of using the keytype array to find the
+		etype.
+
+
+Wed Jul 12 12:31:27 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Remove V5_USE_SHARED_LIB.
+
+
+Fri Jul 7 16:37:07 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling and LDFLAGS.
+	* configure.in - Add USE_KDB5_LIBRARY and KRB5_LIBRARIES
+
+
+Thu Jun 15 18:10:55 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove DBMLIB.
+	* configure.in - Remove check for dbm libraries.  Use shared library
+		linking rules.
+
+Fri Jun  9 18:58:15 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Fri Mar 31 17:05:49 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb5_mkdums.c (add_princ): Zero out the entry before inserting it.
+
+Thu Mar  2 12:34:37 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:32:20 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:24:52 1995  John Gilmore  (gnu at toad.com)
+
+	* kdb5_mkdums.c:  Avoid <krb5/...> includes.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Sun Oct 23 00:50:07 1994    (tytso@rsx-11)
+
+	* kdb5_mkdums.c (add_princ): Create principals with correct realm
+		name. 
+
+	* configure.in: Look for ndbm or dbm libraries
+
+Thu Oct  6 12:41:28 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb5_mkdums.c (main, set_dbname_help): Allow master key password
+		to be passed in on the command line; to make testing
+		scripts simpler.
+
+	* kdb5_mkdums.c (add_princ): Initialize all the fields of the
+		principal. 
+
+Thu Sep 29 22:58:05 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Relink executable when libraries change
+
+Thu Sep 15 17:16:46 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb5_mkdums.c (add_princ): Initialize key version number to be 1.
+
+
diff --git a/mechglue/src/tests/create/Makefile.in b/mechglue/src/tests/create/Makefile.in
new file mode 100644
index 000000000..cbdf40908
--- /dev/null
+++ b/mechglue/src/tests/create/Makefile.in
@@ -0,0 +1,32 @@
+thisconfigdir=./..
+myfulldir=tests/create
+mydir=create
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+SRCS=$(srcdir)/kdb5_mkdums.c
+KDB5_DEP_LIBS=$(THREAD_LINKOPTS) $(DL_LIB)
+
+all:: kdb5_mkdums
+
+kdb5_mkdums: kdb5_mkdums.o $(KDB5_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o kdb5_mkdums kdb5_mkdums.o $(KDB5_DEP_LIBS) $(KDB5_LIBS) $(KRB5_BASE_LIBS)
+
+all:: kdb5_mkdums
+
+install::
+
+clean::
+	$(RM) kdb5_mkdums.o kdb5_mkdums
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)kdb5_mkdums.$(OBJEXT): kdb5_mkdums.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SS_DEPS)
diff --git a/mechglue/src/tests/create/kdb5_mkdums.M b/mechglue/src/tests/create/kdb5_mkdums.M
new file mode 100644
index 000000000..23e258532
--- /dev/null
+++ b/mechglue/src/tests/create/kdb5_mkdums.M
@@ -0,0 +1,141 @@
+.\" tests/create/kdb5_mkdums.M
+.\"
+.\" Copyright 1990 by the Massachusetts Institute of Technology.
+.\"
+.\" Export of this software from the United States of America may
+.\"   require a specific license from the United States Government.
+.\"   It is the responsibility of any person or organization contemplating
+.\"   export to obtain such a license before exporting.
+.\" 
+.\" WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+.\" distribute this software and its documentation for any purpose and
+.\" without fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright notice and
+.\" this permission notice appear in supporting documentation, and that
+.\" the name of M.I.T. not be used in advertising or publicity pertaining
+.\" to distribution of the software without specific, written prior
+.\" permission.  Furthermore if you modify this software you must label
+.\" your software as modified software and not distribute it in such a
+.\" fashion that it might be confused with the original M.I.T. software.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose.  It is provided "as is" without express
+.\" or implied warranty.
+.\" 
+.\"
+.TH KDB5_MKDUMS 8
+.SH NAME
+kdb5_mkdums \- create a new Kerberos V5 principal database
+.SH SYNOPSIS
+.B kdb5_mkdums
+.B \-n
+.I number
+.B \-p
+.I prefix
+[
+.B \-D
+.I depth
+] [
+.B \-r
+.I realm
+] [
+.B \-d
+.I dbname
+] [
+.B \-k
+.I keytype
+] [
+.B \-M
+.I mkeyname
+] [
+.B \-e
+.I enctype
+] [
+.B \-m
+]
+.br
+.SH DESCRIPTION
+.I kdb5_mkdums
+is used to create many test entries in a Kerberos version 5 principal
+database. 
+Each entry is created with a known password, for later verification.
+.I kdb5_verify
+can be used to verify that the entries were stored correctly in the
+database and can be retrieved.
+.I kdc5_hammer
+can be used to make repeated ticket requests of the KDC for principals
+created via
+.I kdb5_mkdums
+in order to ``stress test'' the KDC.
+.PP
+The
+.B \-p
+.I prefix
+argument specifies the prefix name for each principal to be created.
+The current number and depth will be appended to the prefix.
+.PP
+The
+.B \-n
+.I num_to_create
+argument specifies the number of principals to create (at each depth).
+.PP
+The
+.B \-D
+.I depth
+option specifies the maximum number of components a principal should
+have; the default depth is 1.
+.PP
+The
+.B \-r
+.I realm
+option specifies the realm in which the entreis should be created;
+by default the realm returned by
+.IR krb5_default_local_realm (3)
+is used.
+.PP
+The
+.B \-d
+.I dbname
+option specifies the name under which the principal database is to be
+created; by default the database is in DEFAULT_DBM_FILE (normally
+/krb5/principal).
+.PP
+The
+.B \-k
+.I keytype
+option specifies the key type (as an ascii representation of a decimal
+number) of the master key in the database; the default is KEYTYPE_DES.
+.PP
+The
+.B \-M
+.I mkeyname
+option specifies the principal name for the master key in the database;
+the default is KRB5_KDB_M_NAME (usually "K/M" in the KDC's realm).
+.PP
+The
+.B \-e
+.I enctype
+option specifies the encryption type (as an ascii representation of a decimal
+number) to be used when placing entries in
+the database; the default is the default encryption type for the master
+keytype.
+.SH EXAMPLE
+.I
+kdb5_mkdums -p test -n 2 -D 3
+.R
+will create the following principals, each with their printed names as
+passwords:
+.nf
+.in +1i
+test1-DEPTH-1@FOO.MIT.EDU
+test2-DEPTH-1@FOO.MIT.EDU
+test1-DEPTH-1/test1-DEPTH-2@FOO.MIT.EDU
+test2-DEPTH-1/test2-DEPTH-2@FOO.MIT.EDU
+test1-DEPTH-1/test1-DEPTH-2/test1-DEPTH-3@FOO.MIT.EDU
+test2-DEPTH-1/test2-DEPTH-2/test2-DEPTH-3@FOO.MIT.EDU
+.in -1i
+.fi
+.SH BUGS
+Should be do something intelligent about testing fields other than the
+password.
+.SH AUTHOR
+Jon Rochlis, MIT Network Services
diff --git a/mechglue/src/tests/create/kdb5_mkdums.c b/mechglue/src/tests/create/kdb5_mkdums.c
new file mode 100644
index 000000000..aa5f487ac
--- /dev/null
+++ b/mechglue/src/tests/create/kdb5_mkdums.c
@@ -0,0 +1,430 @@
+/*
+ * tests/create/kdb5_mkdums.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Edit a KDC database.
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+#include <ss/ss.h>
+#include <stdio.h>
+
+
+#define REALM_SEP	'@'
+#define REALM_SEP_STR	"@"
+
+struct mblock {
+    krb5_deltat max_life;
+    krb5_deltat max_rlife;
+    krb5_timestamp expiration;
+    krb5_flags flags;
+    krb5_kvno mkvno;
+} mblock = {				/* XXX */
+    KRB5_KDB_MAX_LIFE,
+    KRB5_KDB_MAX_RLIFE,
+    KRB5_KDB_EXPIRATION,
+    KRB5_KDB_DEF_FLAGS,
+    1
+};
+
+int set_dbname_help (char *, char *);
+
+static void
+usage(who, status)
+char *who;
+int status;
+{
+    fprintf(stderr,
+	    "usage: %s -p prefix -n num_to_create [-d dbpathname] [-r realmname]\n",
+	    who);
+    fprintf(stderr, "\t [-D depth] [-k enctype] [-M mkeyname]\n");
+
+    exit(status);
+}
+
+int master_princ_set = 0;
+krb5_keyblock master_keyblock;
+krb5_principal master_princ;
+krb5_db_entry master_entry;
+krb5_pointer master_random;
+krb5_context test_context;
+
+static char *progname;
+static char *cur_realm = 0;
+static char *mkey_name = 0;
+static char *mkey_password = 0;
+static krb5_boolean manual_mkey = FALSE;
+
+void add_princ (krb5_context, char *);
+
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    extern char *optarg;	
+    int optchar, i, n;
+    char tmp[4096], tmp2[BUFSIZ], *str_newprinc;
+
+    krb5_error_code retval;
+    char *dbname = 0;
+    int enctypedone = 0;
+    extern krb5_kt_ops krb5_ktf_writable_ops;
+    int num_to_create;
+    char principal_string[BUFSIZ];
+    char *suffix = 0;
+    int depth;
+
+    krb5_init_context(&test_context);
+
+    if (strrchr(argv[0], '/'))
+	argv[0] = strrchr(argv[0], '/')+1;
+
+    progname = argv[0];
+
+    memset(principal_string, 0, sizeof(principal_string));
+    num_to_create = 0;
+    depth = 1;
+
+    while ((optchar = getopt(argc, argv, "D:P:p:n:d:r:k:M:e:m")) != -1) {
+	switch(optchar) {
+	case 'D':
+	    depth = atoi(optarg);       /* how deep to go */
+	    break;
+        case 'P':		/* Only used for testing!!! */
+	    mkey_password = optarg;
+	    break;
+	case 'p':                       /* prefix name to create */
+	    strncpy(principal_string, optarg, sizeof(principal_string) - 1);
+	    principal_string[sizeof(principal_string) - 1] = '\0';
+	    suffix = principal_string + strlen(principal_string);
+	    break;
+	case 'n':                        /* how many to create */
+	    num_to_create = atoi(optarg);
+	    break;
+	case 'd':			/* set db name */
+	    dbname = optarg;
+	    break;
+	case 'r':
+	    cur_realm = optarg;
+	    break;
+	case 'k':
+	    master_keyblock.enctype = atoi(optarg);
+	    enctypedone++;
+	    break;
+	case 'M':			/* master key name in DB */
+	    mkey_name = optarg;
+	    break;
+	case 'm':
+	    manual_mkey = TRUE;
+	    break;
+	case '?':
+	default:
+	    usage(progname, 1);
+	    /*NOTREACHED*/
+	}
+    }
+
+    if (!(num_to_create && suffix)) usage(progname, 1);
+
+
+    if ((retval = krb5_kt_register(test_context, &krb5_ktf_writable_ops))) {
+        if (retval != KRB5_KT_TYPE_EXISTS) {
+	  com_err(progname, retval,
+		"while registering writable key table functions");
+	  exit(1);
+	}
+    }
+
+    if (!enctypedone)
+	master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+
+    if (!krb5_c_valid_enctype(master_keyblock.enctype)) {
+	com_err(progname, KRB5_PROG_ETYPE_NOSUPP,
+		"while setting up enctype %d", master_keyblock.enctype);
+	exit(1);
+    }
+
+    if (!dbname)
+	dbname = DEFAULT_KDB_FILE;	/* XXX? */
+
+    if (!cur_realm) {
+	if ((retval = krb5_get_default_realm(test_context, &cur_realm))) {
+	    com_err(progname, retval, "while retrieving default realm name");
+	    exit(1);
+	}	    
+    }
+    if ((retval = set_dbname_help(progname, dbname)))
+	exit(retval);
+
+    for (n = 1; n <= num_to_create; n++) {
+      /* build the new principal name */
+      /* we can't pick random names because we need to generate all the names 
+	 again given a prefix and count to test the db lib and kdb */
+      (void) sprintf(suffix, "%d", n);
+      (void) sprintf(tmp, "%s-DEPTH-1", principal_string);
+      tmp[sizeof(tmp) - 1] = '\0';
+      str_newprinc = tmp;
+      add_princ(test_context, str_newprinc);
+
+      for (i = 2; i <= depth; i++) {
+	(void) sprintf(tmp2, "/%s-DEPTH-%d", principal_string, i);
+	tmp2[sizeof(tmp2) - 1] = '\0';
+	strncat(tmp, tmp2, sizeof(tmp) - 1 - strlen(tmp));
+	str_newprinc = tmp;
+	add_princ(test_context, str_newprinc);
+      }
+    }
+
+    retval = krb5_db_fini(test_context);
+    memset((char *)master_keyblock.contents, 0, 
+	   (size_t) master_keyblock.length);
+    if (retval && retval != KRB5_KDB_DBNOTINITED) {
+	com_err(progname, retval, "while closing database");
+	exit(1);
+    }
+    if (master_princ_set) {
+	krb5_free_principal(test_context, master_princ);
+    }
+    krb5_free_context(test_context);
+    exit(0);
+}
+
+void
+add_princ(context, str_newprinc)
+    krb5_context 	  context;
+    char 		* str_newprinc;
+{
+    krb5_error_code 	  retval;
+    krb5_principal 	  newprinc;
+    krb5_db_entry 	  newentry;
+    char 		  princ_name[4096];
+
+    memset((char *)&newentry, 0, sizeof(newentry));
+    sprintf(princ_name, "%s@%s", str_newprinc, cur_realm);
+    if ((retval = krb5_parse_name(context, princ_name, &newprinc))) {
+      com_err(progname, retval, "while parsing '%s'", princ_name);
+      return;
+    }
+
+    /* Add basic data */
+    newentry.len = KRB5_KDB_V1_BASE_LENGTH;
+    newentry.attributes = mblock.flags;
+    newentry.max_life = mblock.max_life;
+    newentry.max_renewable_life = mblock.max_rlife;
+    newentry.expiration = mblock.expiration;
+    newentry.pw_expiration = mblock.expiration;
+    
+    /* Add princ to db entry */
+    if ((retval = krb5_copy_principal(context, newprinc, &newentry.princ))) {
+      	com_err(progname, retval, "while encoding princ to db entry for '%s'", 
+	        princ_name);
+	krb5_free_principal(context, newprinc);
+	goto error;
+    }
+
+    {
+	/* Add mod princ to db entry */
+	krb5_int32 now;
+
+	retval = krb5_timeofday(context, &now);
+	if (retval) {
+	    com_err(progname, retval, "while fetching date");
+	    krb5_free_principal(context, newprinc);
+	    goto error;
+	}
+	retval = krb5_dbe_update_mod_princ_data(context, &newentry, now,
+					       master_princ);
+	if (retval) {
+	    com_err(progname, retval, "while encoding mod_princ data");
+	    krb5_free_principal(context, newprinc);
+	    goto error;
+	}
+    }
+
+    {   /* Add key and salt data to db entry */
+        krb5_data pwd, salt;
+        krb5_keyblock key;
+
+        if ((retval = krb5_principal2salt(context, newprinc, &salt))) {
+	    com_err(progname, retval, "while converting princ to salt for '%s'",
+		    princ_name);
+	    krb5_free_principal(context, newprinc);
+	    goto error;
+        }
+
+	krb5_free_principal(context, newprinc);
+
+    	pwd.length = strlen(princ_name);
+    	pwd.data = princ_name;  /* must be able to regenerate */
+    	if ((retval = krb5_c_string_to_key(context, master_keyblock.enctype, 
+					   &pwd, &salt, &key))) {
+	    com_err(progname,retval,"while converting password to key for '%s'",
+		    princ_name);
+	    krb5_free_data_contents(context, &salt);
+	    goto error;
+	}
+	krb5_free_data_contents(context, &salt);
+
+	if ((retval = krb5_dbe_create_key_data(context, &newentry))) {
+	    com_err(progname, retval, "while creating key_data for '%s'",
+		    princ_name);
+            free(key.contents);
+	    goto error;
+        }
+
+        if ((retval = krb5_dbekd_encrypt_key_data(context,&master_keyblock, 
+						  &key, NULL, 1, 
+						  newentry.key_data))) {
+    	    com_err(progname, retval, "while encrypting key for '%s'", 
+		    princ_name);
+            free(key.contents);
+	    goto error;
+        }
+        free(key.contents);
+    }
+
+    {
+	int one = 1;
+
+    	if ((retval = krb5_db_put_principal(context, &newentry, &one))) {
+	    com_err(progname, retval, "while storing principal date");
+	    goto error;
+    	}
+    	if (one != 1) {
+	   com_err(progname,0,"entry not stored in database (unknown failure)");
+	    goto error;
+    	}
+    }
+
+    fprintf(stdout, "Added %s to database\n", princ_name);
+
+error: /* Do cleanup of newentry regardless of error */
+#if 0
+    krb5_dbe_free_contents(context, &newentry);
+#endif
+    krb5_db_free_principal(context, &newentry, 1);
+    return;
+}
+
+int
+set_dbname_help(pname, dbname)
+char *pname;
+char *dbname;
+{
+    krb5_error_code retval;
+    int nentries;
+    krb5_boolean more;
+    krb5_data pwd, scratch;
+    char *args[2];
+
+    /* assemble & parse the master key name */
+
+    if ((retval = krb5_db_setup_mkey_name(test_context, mkey_name, cur_realm, 
+					  0, &master_princ))) {
+	com_err(pname, retval, "while setting up master key name");
+	return(1);
+    }
+    master_princ_set = 1;
+    if (mkey_password) {
+	pwd.data = mkey_password;
+	pwd.length = strlen(mkey_password);
+	retval = krb5_principal2salt(test_context, master_princ, &scratch);
+	if (retval) {
+	    com_err(pname, retval, "while calculated master key salt");
+	    return(1);
+	}
+	if ((retval = krb5_c_string_to_key(test_context,
+					   master_keyblock.enctype,
+					   &pwd, &scratch,
+					   &master_keyblock))) {
+	    com_err(pname, retval,
+		    "while transforming master key from password");
+	    return(1);
+	}
+	free(scratch.data);
+    } else {
+	if ((retval = krb5_db_fetch_mkey(test_context, master_princ, 
+					master_keyblock.enctype, manual_mkey, 
+					FALSE, 0, NULL, &master_keyblock))) {
+	    com_err(pname, retval, "while reading master key");
+	    return(1);
+	}
+    }
+
+    /* Ick!  Current DAL interface requires that the default_realm
+       field be set in the krb5_context.  */
+    if ((retval = krb5_set_default_realm(test_context, cur_realm))) {
+	com_err(pname, retval, "setting default realm");
+	return 1;
+    }
+    /* Pathname is passed to db2 via 'args' parameter.  */
+    args[1] = NULL;
+    args[0] = malloc(sizeof("dbname=") + strlen(dbname));
+    if (args[0] == NULL) {
+	com_err(pname, errno, "while setting up db parameters");
+	return 1;
+    }
+    sprintf(args[0], "dbname=%s", dbname);
+
+    if ((retval = krb5_db_open(test_context, args, KRB5_KDB_OPEN_RO))) {
+	com_err(pname, retval, "while initializing database");
+	return(1);
+    }
+    if ((retval = krb5_db_verify_master_key(test_context, master_princ, 
+					   &master_keyblock))){
+	com_err(pname, retval, "while verifying master key");
+	(void) krb5_db_fini(test_context);
+	return(1);
+    }
+    nentries = 1;
+    if ((retval = krb5_db_get_principal(test_context, master_princ, 
+				       &master_entry, &nentries, &more))) {
+	com_err(pname, retval, "while retrieving master entry");
+	(void) krb5_db_fini(test_context);
+	return(1);
+    } else if (more) {
+	com_err(pname, KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE,
+		"while retrieving master entry");
+	(void) krb5_db_fini(test_context);
+	return(1);
+    } else if (!nentries) {
+	com_err(pname, KRB5_KDB_NOENTRY, "while retrieving master entry");
+	(void) krb5_db_fini(test_context);
+	return(1);
+    }
+
+    mblock.max_life = master_entry.max_life;
+    mblock.max_rlife = master_entry.max_renewable_life;
+    mblock.expiration = master_entry.expiration;
+
+    /* don't set flags, master has some extra restrictions */
+    mblock.mkvno = master_entry.key_data[0].key_data_kvno;
+
+    krb5_db_free_principal(test_context, &master_entry, nentries);
+    return 0;
+}
+
diff --git a/mechglue/src/tests/dejagnu/.Sanitize b/mechglue/src/tests/dejagnu/.Sanitize
new file mode 100644
index 000000000..6a8238787
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/.Sanitize
@@ -0,0 +1,43 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+config
+configure
+configure.in
+krb-root
+krb-standalone
+t_inetd.c
+Makefile.in
+
+
+Things-to-lose:
+
+tmpdir
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/dejagnu/ChangeLog b/mechglue/src/tests/dejagnu/ChangeLog
new file mode 100644
index 000000000..8ab80f332
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/ChangeLog
@@ -0,0 +1,149 @@
+2005-08-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (site.exp): Write KRB5_DB_MODULE_DIR setting into
+	site.exp.  Depend on Makefile.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (check-runtest-yes): Add PRIOCNTL_HACK.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* t_inetd.c: Remove declaration of errno
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (RUNTEST): Variable renamed from HAVE_RUNTEST.
+	(check): Depend on check-runtest-@HAVE_RUNTEST@.
+	(check-runtest-yes, check-runtest-no): Renamed from check-runtest,
+	check-.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (HAVE_RUNTEST): Include $(DEJAFLAGS).
+
+2000-08-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (KRB4_RUNTESTFLAGS): Set from configure.in and pass
+	to runtest if krb4 compatibility is enabled.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Mon Mar 30 13:57:07 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* t_inetd.c: Include stdlib.h (if present) for atoi() prototype, 
+	Include unistd.h (if present) for dup() prototype.
+
+
+Wed Feb 18 16:28:37 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 16:45:49 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Oct  7 08:02:13 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (runenv.vars): Use tr to remove newlines in multiple
+	        lines of variables.
+
+Fri Oct  3 02:26:45 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fix up site.exp generation to reduce the quoting
+	lossage somewhat.
+
+Sun Aug 17 14:26:57 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(SRCS) line.
+
+Sun Feb  9 01:38:26 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Wed Nov 20 16:01:34 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* Makefile.in (check-): warn more loudly about unrun tests
+
+Mon Oct  7 15:46:47 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (HAVE_RUNTEST): Renamed from RUNTEST as
+		config/pre.in now defines.
+
+Sun Apr  7 23:03:01 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add KRB5_RUN_FLAGS
+
+	* Makefile.in (site.exp): Create site.exp with runtime environment
+		line from configure.
+
+Mon Feb 26 03:38:24 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* *.exp: use $REALMNAME for the testing realm.
+	* default.exp: if REALMNAME isn't set, set it to KRBTEST.COM.
+
+Fri Sep 29 14:23:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (clean-unix): Remove the dejagnu temporary files.
+
+Tue Aug 29 14:22:28 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Replace explicit library list with $(LIBS).  This
+		gets set with the needed libraries (e.g. -lsocket on Solaris).
+
+Sat Aug 26 18:10:44 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* .Sanitize: Add t_inetd.c
+
+        * t_inetd.c: Small program to simulate the use of inetd in running
+		tests. 
+
+	* configure.in: Add programming rules, shared libraries and
+		signal handling
+
+	* Makefile.in: Build/clean t_inetd if dejagnu tests are run.
+
+Thu Aug 24 18:48:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Wed Jun 21 18:13:11 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove AC_CONFIG_FRAGMENTS call, since it's no
+		longer needed.  (The aclocal.m4 V5_SET_TOPTREE handles it
+		all automatically now.)
+
+Fri Jun  9 18:58:29 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Wed Apr 26 18:41:04 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Check for runtest program present on system for
+		make check. 
+
+	* Makefile.in (check): Run runtest only if present on system
+	              (install): do nothing
+
+	
+
diff --git a/mechglue/src/tests/dejagnu/Makefile.in b/mechglue/src/tests/dejagnu/Makefile.in
new file mode 100644
index 000000000..28a820134
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/Makefile.in
@@ -0,0 +1,54 @@
+thisconfigdir=./..
+myfulldir=tests/dejagnu
+mydir=dejagnu
+BUILDTOP=$(REL)..$(S)..
+RUNTEST = @RUNTEST@ $(DEJAFLAGS)
+RUNTESTFLAGS =
+KRB5_RUN_ENV= @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+KRB4_RUNTESTFLAGS=@KRB4_DEJAGNU_TEST@
+
+SRCS=$(srcdir)/t_inetd.c
+
+all install::
+
+check:: check-runtest-@HAVE_RUNTEST@
+
+check-runtest-no::
+	@echo "+++"
+	@echo "+++ WARNING: tests/dejagnu tests not run."
+	@echo "+++ runtest is unavailable."
+	@echo "+++"
+
+check-runtest-yes:: t_inetd site.exp
+	$(RUNTEST) --tool krb --srcdir $(srcdir) $(KRB4_RUNTESTFLAGS) PRIOCNTL_HACK=@PRIOCNTL_HACK@ $(RUNTESTFLAGS)
+
+t_inetd:: t_inetd.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_inetd t_inetd.o $(KRB5_BASE_LIBS)
+
+clean::
+	$(RM) t_inetd t_inetd.o site.exp runenv.vars runenv.vals
+
+clean-unix::
+	$(RM) -rf tmpdir dbg.log krb.log krb.sum
+
+runenv.vars: Makefile
+	echo '$(KRB5_RUN_ENV)' | tr ';' '\012' | \
+		sed -ne 's% *\([^=]*\)=.*%\1%p' > runenv.vars
+
+runenv.vals: runenv.vars
+	$(KRB5_RUN_ENV) for i in `cat runenv.vars`; do \
+		eval echo "{$$i=\$$$$i}"; done > runenv.vals
+
+site.exp: runenv.vals Makefile
+	echo "set runvarlist [list `cat runenv.vals | tr '\n' ' '`]" | \
+		sed -e 's%=\.%='`pwd`'/.%g' > site.exp
+	echo "set KRB5_DB_MODULE_DIR {$(KRB5_DB_MODULE_DIR)}" >> site.exp
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)t_inetd.$(OBJEXT): t_inetd.c $(COM_ERR_DEPS)
diff --git a/mechglue/src/tests/dejagnu/config/.Sanitize b/mechglue/src/tests/dejagnu/config/.Sanitize
new file mode 100644
index 000000000..d3482ee52
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/config/.Sanitize
@@ -0,0 +1,33 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+ChangeLog
+default.exp
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/dejagnu/config/ChangeLog b/mechglue/src/tests/dejagnu/config/ChangeLog
new file mode 100644
index 000000000..cc348ee32
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/config/ChangeLog
@@ -0,0 +1,666 @@
+2005-10-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (setup_krb5_conf): Don't include a non-listening KDC
+	port in the client's config file.
+
+2005-09-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp: Initialize can_get_root to yes.
+	(setup_root_shell): If can_get_root is "no", log a message and
+	return, without making another attempt.  On failing attempts, set
+	can_get_root to "no".
+
+2005-08-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (setup_kerberos_files): Don't write database_name
+	entry into KDC config file.
+	(setup_krb5_conf): Write new config lines for the realm into the
+	krb5.conf files.
+
+2005-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (start_tail): Make 'standalone' an additional
+	argument.
+	(start_kerberos_daemons): Pass it.
+
+2005-01-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (start_tail): New proc.  Handles GNU tail race
+	condition with less delay than the old code that was in
+	start_kerberos_daemons.
+	(start_kerberos_daemons): Call start_tail for both log files.
+
+2005-01-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (start_kerberos_daemons): Format date internally
+	rather than running "date".
+
+2004-06-17  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (setup_krb5_conf): Default to not using SRV records
+	to look up KDCs, to avoid timeouts on KRBTEST.COM's DNS servers.
+
+2004-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp: Set new variable portbase from $PORTBASE or
+	default.
+	(setup_kerberos_files, setup_krb5_conf, setup_kerberos_env): Use
+	portbase to select all port numbers.
+
+2004-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (passes): Add "mode=udp" to existing pass
+	specifications.  Add a new pass which does AES and "mode=tcp".
+	(setup_kerberos_files, setup_krb5_conf): Check global var "mode"
+	and use it to force UDP or TCP communication between client and
+	KDC.  Also, have clients try another random port where we don't
+	expect anything to be listening.
+
+2004-02-13  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (PRIOCNTL_HACK): Use "==" instead of "eq", which is
+	not present in tcl-8.3.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (PRIOCNTL_HACK): Wrap "spawn" to do priocntl things
+	to work around Solaris 9 pty-close bug.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (passes): Add an AES-only pass.
+	(start_kerberos_daemons): Check for error "No principal in keytab
+	matches desired name".
+	(dump_db): New proc, for debugging.
+	(spawn_xterm): Add GSSCLIENT to list of exported variables.
+
+2003-06-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (setup_root_shell): Check for "not authorized".  Map
+	eof to unsupported.
+
+2003-06-04  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (setup_root_shell): Don't try to use the procedure
+	"-" when handling error messages from rlogin.
+
+2003-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (setup_root_shell): Handle error messages indicating
+	"-x" isn't supported.
+	(start_kerberos_daemons): "cannont" => "cannot".
+
+2003-06-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp: Default RLOGIN_FLAGS to "-x".
+	(start_kerberos_daemons): Watch for "Cannot bind server socket"
+	and log it.  Watch for "no sockets set up" and report an error.
+	(setup_root_shell): Watch for "Cannot assign requested address",
+	log it and give up.
+
+2003-05-21  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Be slightly more lenient about matching password
+	prompts.
+
+2003-05-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (spawn_xterm): Add KPASSWD and REALMNAME to the list
+	of exported variables.
+
+2003-04-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp: Add passes for testing AES.
+	(start_kerberos_daemons): Add a small delay between starting the
+	"tail -f" processes and appending the markers to their files.
+	(spawn_xterm): Add RLOGIN, RLOGIND, FTP, and FTPD to the list of
+	variables to export to the environment.  Check that variables are
+	defined before exporting them.
+
+2003-03-28  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (start_kerberos_daemons): If we get a timeout
+	looking for the mark, log out the last 10 lines of the kdc
+	logfile.
+
+2003-03-26  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (v4kinit): Expect failure when kiniting to a des3
+	TGT, due to fix for MITKRB5-SA-2003-004.
+	(setup_kadmind_srvtab): Remove.  It's not needed anymore.
+
+2003-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (setup_root_shell): If we get connection refused
+	messages, followed by no unrecognized errors and then eof, report
+	it as an unsupported test.
+
+2003-02-04  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (start_kerberos_daemons): Use correct argument to
+	"-4" flag.
+
+2003-02-04  Sam Hartman  <hartmans@mit.edu>
+
+	* default.exp (start_kerberos_daemons): Enable  krb4 
+
+2003-01-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (start_kerberos_daemons): Record more information
+	when "tail -f" doesn't show the mark written to the log file.
+	Look for and discard non-matching lines.
+	(setup_root_shell): Ignore the message displayed by rlogin when
+	a connection is refused to one address but other addresses are
+	available.
+
+2002-11-08  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Add (disabled) debugging code for catching leaking
+	ptys.  expect eof from the correct spawn_ids when killing kdc and
+	kadmind to avoid leaking ptys.
+	(do_klist, v4klist, v4klist_none): Check for eof to avoid leaking
+	ptys.
+
+2002-10-07  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (stop_kerberos_daemons): Kill, expect eof, wait, in
+	that order.  Avoids delivery of multiple signals (HUP+TERM) to KDC
+	daemons when shutting down.
+
+2002-09-29  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (start_kerberos_daemons): Fix to use "tail -f" to
+	check for setup messages from daemons; this avoids a few race
+	conditions.
+
+2002-03-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (modify_principal, kinit_kt, v4kinit_kt, do_klist,
+	do_klist_kt, do_klist_err, do_kdestroy, xst, v4klist, v4kdestroy,
+	v4klist_none): New procs.
+	(add_random_key): No need to call expect_after in 'body' since
+	both branches at invocation site will do it.
+	(setup_root_shell, setup_root_shell_remote): Set correct value for
+	KRB5_CONFIG.
+	(passes): Add des-crc and des-md5 krb4 passes.
+	(top level): Set KLIST and KDESTROY.
+	(spawn_xterm): New proc useful for debugging only.
+	(start_kerberos_daemons): Wait longer for "starting"
+	line in log file.
+
+2002-02-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* default.exp (start_kerberos_daemons): In starting the kadmin
+	daemon, the last line in the log file might read "Seeding random
+	number" for a second. If that is the case, wait three seconds and
+	refetch the last line of the log file to look for the "starting
+	kadmind message"
+
+2002-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (start_kerberos_daemons): When standalone, delete
+	KDC replay cache before starting it up.
+
+2001-10-31  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (check_k5login, check_klogin): Error out if there is
+	a nonexistent .k5login or .klogin for root.
+	(setup_{kadmind_,}srvtab, add_{random,kerberos}_key): Notice
+	unmatched output to avoid timing out on certain errors.  Look for
+	command echoes.  Clear the expect_after list in places to avoid
+	problems with lingering expect_after clauses against invalid
+	spawn_ids.  expect eof in places to avoid pty deadlock.
+
+2001-10-27  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Mark as unused the test passes that won't
+	accomplish anything due to disabling of SUPPORT_DESMD5 in the
+	code.
+
+2001-10-24  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Add support for setting SUPPORT_DESMD5 flag on the
+	TGT principal.  Add test pass des.md5-tgt for exercising enctype
+	similarity inconsistency.  Add test pass des.no-kdc-md5 for
+	exercising failure to constrain session key issuance to
+	permitted_enctypes.  Pepper the code with null calls to
+	expect_after to prevent misfiring of expect_after clauses.
+	(setup_srvtab): Look for some possible error cases to avoid timing
+	out.
+	(setup_root_shell): Restore timeout so we don't wait 5 minutes in
+	other places.
+
+2001-08-06    <epeisach@mit.edu>
+
+	* default.exp (setup_root_shell): Also recognize "nection reset by
+	peer" as a failure to get a root shell. This happens if
+	tcp_wrappers are in use in inetd.conf, but rlogind is not prsent
+	on the machine.
+
+2001-06-22  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Use the interface variable $TMPDIR to allow the
+	specification of an alternative temporary directory.  Wrap a loop
+	around various testings and settings of interface variables that
+	specify the locations of programs to be tested, e.g. $KADMIND.
+	Add some support for having different sets of enctypes on client,
+	server, and kdc.  The envstack changes and multiple config file
+	support should get cleaned up somewhat later to possibly allow for
+	programs to execute on different hosts.
+	(check_k5login): Fix up to reflect actual (perhaps bogus) behavior
+	of krb5_kuserok(), which doesn't do quite what we expect, so there
+	really does need to be something like "luser@KRBTEST.COM" in the
+	.k5login file.
+	(check_klogin): New procedure; .klogin also needs to be checked
+	for the v4gssftp test.
+	(envstack_push, envstack_pop): New procedure; keep a stack of
+	environment variable state, which is useful for running different
+	programs with different config files.
+	(setup_runtime_flags, setup_kerberos_env): Rewrite somewhat so
+	they play nice with the envstack.
+	(setup_krb5_conf): New procedure; write a config file with the
+	contents parameterized based on the type of program that will use
+	it.
+	(setup_kerberos_files): Create different krb5.conf files for
+	client, server, and kdc.
+	(setup_kadmind_srvtab, setup_kerberos_db, start_kerberos_daemons):
+	Rewrite to play nice with envstack.
+	(setup_root_shell_noremote): New procedure from raeburn; handle
+	the case where we're already running as root.
+	(setup_root_shell): Call setup_root_shell_noremote as appropriate.
+	
+2001-06-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* default.exp: Add an entry for krb524_server for the localhost
+	with a non-standard port number.
+
+2001-04-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* default.exp: For Kerberos 4 tests, use a different ticket file
+	name from the V5 tests.
+
+2000-11-08  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Use $KRBIV rather than $KRB4 since dejagnu-1.3
+	doesn't deal with digits in passed-in variables.
+
+Thu Oct 12 12:06:03 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* default.exp: Add dict_file entry (and create one) for kdc.conf
+
+Tue Aug 22 09:47:50 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* default.exp: Create a properly formatted krb.conf file.  Also
+ 	provide a krb4_srvtab stanza (even though we are falling back on
+ 	the keytab file) so the tests do not try to access an installed
+ 	systems /etc/srvtab file.
+
+2000-08-09  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Add an eof clause to avoid breakage if rlogin exits
+	too quickly.
+
+2000-08-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* default.exp: Create krb.conf and krb.realms files for v4
+	compatibility. Set KRBTKFILE environment variable. Add
+	v4_compatible_enctype() proc to test if krb4 tests are being run
+	and if the current encryption type being tested is compatible with
+	V4.  Added v4kinit() proc. Quoting of lists in mutipass variable
+	assignments is unnecessary.
+
+2000-08-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* default.exp: Protect Quote quotation marks in multipass variable
+	assignments. Dejagnu (June 1999 release) fails overwise. 
+
+2000-07-22  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Add code to handle setting of PASS to constrain
+	multipass testing to particular passes.  dejagnu-1.3 doesn't have
+	support for PASS, so we kludge it here, though some later versions
+	handle it by themselves.
+	(krb_exit): Add new proc to clean up on exit.
+	(kinit): Remove "expect \r" since "expect eof" will drain the pty
+	buffer properly anyway.
+
+2000-07-02  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Add rudimentary support for multiple passes.  For
+	now, iterate over a few combinations of des_krbtgt and assorted
+	enctype lists.  Will eventually allow for separate krb5.conf files
+	for clients and servers.  Add varibles RLOGIN and RLOGIN_FLAGS to
+	permit run-time configuration of rlogin program if necessary.  Set
+	up an onexit handler that calls stop_kerberos_daemons.  Replace
+	many uses of doubled-up send_log and verbose with single calls to
+	verbose -log.  Replace instances of send_error with perror where
+	appropriate, since this will cause successor test to fail, which
+	is usually what we want.
+	(setup_root_shell): Replace calls to untested with calls to
+	unsupported; also use note for explanatory text previously printed
+	using untested.  Add match string for "connection refused" and
+	collapse common code into a single expect clause by using the -re
+	flag.
+	(start_kerberos_daemons): Conditionalize calls to fail based on
+	$standalone; in the !$standalone case, call perror instead.  Calls
+	to fail and pass for a given test should have consistent strings,
+	and extraneous calls to fail should not be made in order to keep
+	the total number of passed and failed tests constant regardless of
+	success of setup steps.  Much remains to be done in this area
+	though.
+
+2000-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (setup_kerberos_files): Include des3 in supported
+	enctypes.
+
+2000-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Remove default_tgs_enctypes for now as it was
+	causing tests to fail when the tgt is DES3.  Need to investigate
+	further.
+
+2000-02-06  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Use $KINIT -5 to deal with modified kinit
+	behavior.
+
+1999-08-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* default.exp (setup_kerberos_files): Set kdc_supported_enctypes
+	in kdc.conf, and include des3-cbc-sha1:normal.
+	(setup_kerberos_db): If setting up krbtgt to use des3, now use
+	only des3, not des3 and des-crc both.
+
+1999-08-30  Ken Raeburn  <raeburn@raeburn.org>
+
+	* default.exp (des3_krbtgt): New variable.
+	(setup_kerberos_files): Remove des3 from supported_enctypes in
+	kdc.conf.
+	(setup_kerberos_db): If des3_krbtgt is set, change krbtgt key, and
+	get a des3 key in addition to des.
+
+1999-08-27  Ken Raeburn  <raeburn@raeburn.org>
+
+	* default.exp: Set default principal expiration a bit further into
+	the future.
+
+1999-08-26  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (setup_kerberos_files): Tweak enctypes entered into
+	config files to exercise 3DES a little.
+
+Fri Jan 30 23:48:57 1998  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp: Add kpasswd_server to krb5.conf.
+
+Wed Jan 21 11:39:11 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Added kpasswd_port variable to kdc.conf creation.
+	(proven@cygnus.com)
+
+Mon Nov 25 14:23:06 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* defualt.exp: Ezra's fix so that the dejagnu tests don't bomb out
+ 		if KRB5_KTNAME is set for some reason.
+
+Tue Nov 19 15:13:30 1996  Tom Yu  <tlyu@mit.edu>
+
+	* default.exp (check_k5login): Check for principal
+ 	$env(USER)@$REALMNAME rather than simply $env(USER), so that
+ 	kuser_ok dtrt, hopefully.
+
+Mon Nov 11 20:52:27 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* dejagnu: set env(TERM) dumb, find ktutil
+
+	Tue Sep 17 20:58:43 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* default.exp: Set terminal type to "dumb" to avoid interference
+	from "resize".
+
+	Tue Sep  3 02:27:40 1996  Mark W. Eichin  <eichin@kitten.gen.ma.us>
+
+	* default.exp: find a path to ktutil, for the v4 tests.
+
+	Wed Jun 12 12:56:10 1996  Mark W. Eichin  <eichin@kitten.gen.ma.us>
+
+	* default.exp (setup_kerberos_files): set default_domain, so v4
+	tests work.
+
+Sun Nov 10 09:48:58 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* default.exp (setup_wrapper): Set KRB5_CONFIG in script.
+
+Mon Aug 12 22:58:58 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Rewrite to use kadmin.local instead of kdb5_edit.
+
+Thu Aug  8 23:08:13 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* default.exp: In add_kerberos_key and add_random_key only execute
+ 	the final expect_after if the spawn ID is still open; also soak up
+ 	all the kadmin responses.
+
+Thu Aug  8 22:13:27 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* default.exp: Sleep for two seconds while waiting for KDC to
+        start; sleep(1) doesn't always take up any time.
+
+Mon Aug  5 21:16:48 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Update to new kdb5_util convention.
+
+Mon Jul 29 11:19:20 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: (kinit): Wait for eof from kinit before waiting for
+		exit. 
+
+Sat Jul 27 02:20:54 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Rewrite to use kdb5_util instead of kdb5_create and
+		kdb5_stash. No longer add the kadmin/admin and changepw
+		keys to the database as this is handled automatically.
+
+Fri Jul 19 19:50:23 1996  Marc Horowitz  <marc@mit.edu>
+
+	* default.exp: changes to work with the new admin system.  This is
+ 	primarily creating the correct keytab for the new admin server,
+ 	and using the new admin client for principal creation.
+
+Mon May  6 11:54:20 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Add procedure setup_wrapper to first setup shared
+		library environment variables and the exec program
+
+Sat May  4 11:56:17 1996  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* default.exp: For stty_init set to \^h as on some /bin/sh, ^ is
+		treated as a pipe.
+
+Fri May  3 20:48:16 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	Tue Apr  2 22:22:47 1996  Chris Provenzano  <proven@cygnus.com>
+
+	* default.exp : Do an stty to set kill and erase correctly. 
+		Things don't work if kill is set to '@'.
+
+	Fri Mar 29 15:02:32 1996  Chris Provenzano  <proven@cygnus.com>
+
+	* default.exp : Always use variable BINSH instead of sh.
+		Use -f flag with kinit to get forwardable tickets.
+		Setup kdc.conf to allow forwardable tickets.
+
+	Thu Mar 28 17:30:55 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* default.exp (touch, tail1): New proc.
+	(start_kerberos_daemons, stop_root_shell): Use them, and sleep
+	built-in command.
+
+	Wed Mar 27 22:43:08 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* default.exp (start_kerberos_daemons): Use ">>" to avoid updating
+	mod time on kadmind log file.
+
+	Wed Mar 27 21:35:57 1996  Marc Horowitz <marc@mit.edu>
+
+	* default.exp: (start_kerberos_daemons): exec the kadmind
+		inside an sh to redirect stderr (this is a pending
+		bug), and keep the same pid, so that
+		stop_kerberos_daemons doesn't leave a kadmind running.
+
+	Wed Mar 27 21:24:35 1996  Marc Horowitz <marc@mit.edu>
+
+	* default.exp: (start_kerberos_daemons): add a check for
+		"cannot initialize network" as a failure message to
+		the kadmind5 startup expect checks
+
+	Wed Mar 27 21:10:47 1996  Marc Horowitz <marc@mit.edu>
+
+	* default.exp (start_kerberos_daemons): use ezra's KDC tail
+		changes for kadmind5, too.
+	* rlogin.exp (start_rlogin_daemon): start klogind with sh -c
+		so that setsid() won't fail due to the process already
+		being the leader of a process group
+	
+Sun Apr  7 23:06:13 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Major changes to use run time environment variables as
+		passed in by configure. 
+
+Tue Mar 26 00:38:14 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp (start_kerberos_daemons): New methodology for
+		starting KDC so that the KDC will not hang on a full
+		output buffer which is being ignored.
+		(setup_kerberos_files): Enable des3 encryption types.
+
+Thu Mar 14 15:20:33 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* default.exp (add_kerberos_key): clarify "lost KDC" text.
+
+Mon Mar  4 20:45:30 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Log krb5kdc to stderr so that test can detect
+		properly when server has started. Change
+		start_kerberos_daemons to take advantage of this.
+
+Sat Oct  7 08:03:43 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Change kdc.conf ports definitions to current
+		methodology. 
+
+Thu Sep 28 18:54:43 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* default.exp: set timeout to 100 since the default of 10 is
+	ludicrous with NFS.
+
+Wed Sep 13 14:02:03 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* default.exp: Save the key used to generate the database files.
+		Also generate a set of environment setup scripts.
+		These are the convenience of someone who wishes to run some
+		of the tests by hand, when tests are bombing.
+
+Sun Sep 10 10:09:41 1995  Ezra Peisach  (epeisach@dcl)
+
+	* default.exp: Add des-cbc-crc to supported_enctypes as krb5_edit
+		requires it for random keys.
+
+Sat Sep  9 16:28:48 1995  Ezra Peisach  (epeisach@dcl)
+
+	* default.exp: supported_keytypes -> supported_enctypes
+
+Sat Aug 26 17:57:47 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* default.exp - Determine location of t_inetd.
+
+
+Thu Aug 3 11:56:43 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Generate kdc.conf with new symbolic values.
+
+
+Mon Jul 17 15:25:56 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Add handling of kdc.conf which has the KDC profile.
+		Remove parameters from command lines of admin utilities because
+		they're not needed anymore since we have the KDC profile.  Also
+		remove prompting for the master key since we have usage of the
+		stash file.
+
+
+Wed Jul 12 14:10:09 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Correctly set LD_LIBRARY_PATH.  Also set it before
+		using RESOLVE.
+
+Thu Jun 22 12:02:15 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Change argument ordering for KDC.  Realm must come last.
+
+
+Mon Jun 19 13:38:27 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Fix setup_root_shell() with LD_LIBRARY_PATH.
+
+Thu Jun 15 18:13:55 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Setup and use LD_LIBRARY_PATH, in case we were built
+		with shared libraries.
+
+Fri Jun  9 23:45:08 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* default.exp: Use the principal "krbtest/admin@KRBTEST.COM" for
+		kadmin 
+
+Thu Jun 8 14:58:15 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Add logging section to the profile.  Also, export
+		profile location to root shell.
+
+
+Mon Jun 5 16:09:25 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Reverse prompting order for kadmin5.
+
+
+Thu Jun 1 14:48:57 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - Change admin instance name to kadmin.
+
+
+Fri May 26 17:55:56 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp - fix typo for restoring setting of KRB5_CONFIG on exit.
+
+
+Fri May 12 16:15:07 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* default.exp: Change to use new kadmin/kadmind.  Add entries for
+		krbtest/kadmin5, changepw and extraction for changepw service
+		entry.
+
+Wed May 10 16:53:28 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: Added domain_realm stanza to krb5.conf.
+	               setup_srvtab: Takes optional service name to
+		       		       extract. 
+
+
+Fri May 05 09:21:21 1995  Chris Provenzano (proven@mit.edu)
+
+	* default.exp : Removed FILE: part of env(KRB5CCNAME).
+
+Wed May  3 22:00:48 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: (get_hostname): The FQDN returned by resolve needs
+		to be made lower case as the host name is entered directly
+		into the database.
+
+Mon May  1 21:32:57 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* default.exp: (get_hostname): Use tests/resolve/resolve to get
+		the fully qualified domain name of the local host.
+		Needed for systems where gethostname() doesn't return the
+		FQDN. 
+
+Thu Apr 27 00:22:30 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* default.exp: KRB5KDC: add -n to don't fork. Set up krb5.conf 
+		and set KRB5_CONFIG to point to it.
+
+Wed Apr 26 17:46:57 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* default.exp (KADMIND, KADMIN): use kadmind.old, since these test
+	the old server not the new (unfinished) one.
+
diff --git a/mechglue/src/tests/dejagnu/config/default.exp b/mechglue/src/tests/dejagnu/config/default.exp
new file mode 100644
index 000000000..abb7b794a
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/config/default.exp
@@ -0,0 +1,2681 @@
+# Basic expect script for Kerberos tests.
+# This is a DejaGnu test script.
+# Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
+# This script is automatically run by DejaGnu before running any of
+# the Kerberos test scripts.
+
+# This file provides several functions which deal with a local
+# Kerberos database.  We have to do this such that we don't interfere
+# with any existing Kerberos database.  We will create all the files
+# in the directory $tmppwd, which will have been created by the
+# testsuite default script.  We will use $REALMNAME as our Kerberos
+# realm name, defaulting to KRBTEST.COM.
+
+set timeout 100
+set stty_init {erase \^h kill \^u}
+set env(TERM) dumb
+
+set des3_krbtgt 0
+set tgt_support_desmd5 0
+set supported_enctypes "des-cbc-crc:normal"
+set kdc_supported_enctypes "des-cbc-crc:normal"
+
+# The names of the individual passes must be unique; lots of things
+# depend on it.  The PASSES variable may not contain comments; only
+# small pieces get evaluated, so comments will do strange things.
+
+# Most of the purpose of using multiple passes is to exercise the
+# dependency of various bugs on configuration file settings,
+# particularly with regards to encryption types.
+
+# The des.no-kdc-md5 pass will fail if the KDC does not constrain
+# session key enctypes to those in its permitted_enctypes list.  It
+# works by assuming enctype similarity, thus allowing the client to
+# request a des-cbc-md4 session key.  Since only des-cbc-crc is in the
+# KDC's permitted_enctypes list, the TGT will be unusable.
+
+# KLUDGE for tracking down leaking ptys
+if 0 {
+    rename spawn oldspawn
+    rename wait oldwait
+    proc spawn { args } {
+	upvar 1 spawn_id spawn_id
+	verbose "spawn: args=$args"
+	set pid [eval oldspawn $args]
+	verbose "spawn: pid=$pid spawn_id=$spawn_id"
+	return $pid
+    }
+    proc wait { args } {
+	upvar 1 spawn_id spawn_id
+	verbose "wait: args=$args"
+	set ret [eval oldwait $args]
+	verbose "wait: $ret"
+	return $ret
+    }
+}
+
+# Hack around Solaris 9 kernel race condition that causes last output
+# from a pty to get dropped.
+if { $PRIOCNTL_HACK } {
+    catch {exec priocntl -s -c FX -m 30 -p 30 -i pid [getpid]}
+    rename spawn oldspawn
+    proc spawn { args } {
+	upvar 1 spawn_id spawn_id
+	set newargs {}
+	set inflags 1
+	set eatnext 0
+	foreach arg $args {
+	    if { $arg == "-ignore" \
+		     || $arg == "-open" \
+		     || $arg == "-leaveopen" } {
+		lappend newargs $arg
+		set eatnext 1
+		continue
+	    }
+	    if [string match "-*" $arg] {
+		lappend newargs $arg
+		continue
+	    }
+	    if { $eatnext } {
+		set eatnext 0
+		lappend newargs $arg
+		continue
+	    }
+	    if { $inflags } {
+		set inflags 0
+		set newargs [concat $newargs {priocntl -e -c FX -p 0}]
+	    }
+	    lappend newargs $arg
+	}
+	set pid [eval oldspawn $newargs]
+	return $pid
+    }
+}
+
+# The des.des3-tgt.no-kdc-des3 pass will fail if the KDC doesn't
+# constrain ticket key enctypes to those in permitted_enctypes.  It
+# does this by not putting des3 in the permitted_enctypes, while
+# creating a TGT princpal that has a des3 key as well as a des key.
+
+# XXX -- master_key_type is fragile w.r.t. permitted_enctypes; it is
+# possible to configure things such that you have a master_key_type
+# that is not permitted, and the error message used to be cryptic.
+
+set passes {
+    {
+	des
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des-cbc-crc:normal}
+	{dummy=[verbose -log "DES TGT, DES enctype"]}
+    }
+    {
+	des.des3tgt
+	mode=udp
+	des3_krbtgt=1
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{dummy=[verbose -log "DES3 TGT, DES enctype"]}
+    }
+    {
+	des3
+	mode=udp
+	des3_krbtgt=1
+	{supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{dummy=[verbose -log "DES3 TGT, DES3 + DES enctypes"]}
+    }
+    {
+	aes
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des-cbc-crc:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des-cbc-crc}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des-cbc-crc}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des-cbc-crc}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES + DES enctypes"]}
+    }
+    {
+	aesonly
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES enctypes"]}
+    }
+    {
+	aes-tcp
+	mode=tcp
+	des3_krbtgt=0
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES via TCP"]}
+    }
+    {
+	aes-des3
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES + DES enctypes"]}
+    }
+    {
+	des3-aes
+	mode=udp
+	des3_krbtgt=1
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES + DES enctypes, DES3 TGT"]}
+    }
+    {
+	des-v4
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=des-cbc-crc:v4}
+	{kdc_supported_enctypes=des-cbc-crc:v4}
+	{default_tkt_enctypes(client)=des-cbc-crc}
+	{dummy=[verbose -log "DES TGT, DES-CRC enctype, V4 salt"]}
+    }
+    {
+	des-md5-v4
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=des-cbc-md5:v4 des-cbc-crc:v4}
+	{kdc_supported_enctypes=des-cbc-md5:v4 des-cbc-crc:v4}
+	{default_tkt_enctypes(client)=des-cbc-md5 des-cbc-crc}
+	{dummy=[verbose -log "DES TGT, DES-MD5 and -CRC enctypes, V4 salt"]}
+    }
+    {
+	all-des-des3-enctypes
+	mode=udp
+	des3_krbtgt=1
+	{supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal \
+		des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm \
+		des-cbc-md4:normal}
+	{kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal \
+		des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm \
+		des-cbc-md4:normal}
+	{dummy=[verbose -log "DES3 TGT, many DES3 + DES enctypes"]}
+    }
+    {
+	des.no-kdc-md5
+	mode=udp
+	des3_krbtgt=0
+	tgt_support_desmd5=0
+	{permitted_enctypes(kdc)=des-cbc-crc}
+	{default_tgs_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc}
+	{default_tkt_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc}
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des-cbc-crc:normal}
+	{master_key_type=des-cbc-crc}
+	{dummy=[verbose -log \
+		"DES TGT, KDC permitting only des-cbc-crc"]}
+    }
+    {
+	des.des3-tgt.no-kdc-des3
+	mode=udp
+	tgt_support_desmd5=0
+	{permitted_enctypes(kdc)=des-cbc-crc}
+	{default_tgs_enctypes(client)=des-cbc-crc}
+	{default_tkt_enctypes(client)=des-cbc-crc}
+	{supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{master_key_type=des-cbc-crc}
+	{dummy=[verbose -log \
+		"DES3 TGT, KDC permitting only des-cbc-crc"]}
+    }
+}
+
+# des.md5-tgt is set as unused, since it won't trigger the error case
+# if SUPPORT_DESMD5 isn't honored.
+
+# The des.md5-tgt pass will fail if enctype similarity is inconsisent;
+# between 1.0.x and 1.1, the decrypt functions became more strict
+# about matching enctypes, while the KDB retrieval functions didn't
+# coerce the enctype to match what was requested.  It works by setting
+# SUPPORT_DESMD5 on the TGT principal, forcing an enctype of
+# des-cbc-md5 on the TGT key.  Since the database only contains a
+# des-cbc-crc key, the decrypt will fail if enctypes are not coerced.
+
+# des.no-kdc-md5.client-md4-skey is retained in unsed_passes, even
+# though des.no-kdc-md5 is roughly equivalent, since the associated
+# comment needs additional investigation at some point re the kadmin
+# client.
+
+# The des.no-kdc-md5.client-md4-skey will fail on TGS requests due to
+# the KDC issuing session keys that it won't accept.  It will also
+# fail for a kadmin client, but for different reasons, since the kadm5
+# library does some curious filtering of enctypes, and also uses
+# get_in_tkt() rather than get_init_creds(); the former does an
+# intersection of the enctypes provided by the caller and those listed
+# in the config file!
+
+set unused_passes {
+    {
+	des.md5-tgt
+	des3_krbtgt=0
+	tgt_support_desmd5=1
+	supported_enctypes=des-cbc-crc:normal
+	kdc_supported_enctypes=des-cbc-crc:normal
+	{permitted_enctypes(kdc)=des-cbc-md5 des-cbc-md4 des-cbc-crc}
+	{permitted_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc}
+	{dummy=[verbose -log "DES TGT, SUPPORTS_DESMD5"]}
+    }
+    {
+	des.md5-tgt.no-kdc-md5
+	des3_krbtgt=0
+	tgt_support_desmd5=1
+	{permitted_enctypes(kdc)=des-cbc-crc}
+	{default_tgs_enctypes(client)=des-cbc-crc}
+	{default_tkt_enctypes(client)=des-cbc-crc}
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des-cbc-crc:normal}
+	{master_key_type=des-cbc-crc}
+	{dummy=[verbose -log \
+		"DES TGT, SUPPORTS_DESMD5, KDC permitting only des-cbc-crc"]}
+    }
+    {
+	des.no-kdc-md5.client-md4-skey
+	des3_krbtgt=0
+	{permitted_enctypes(kdc)=des-cbc-crc}
+	{permitted_enctypes(client)=des-cbc-crc des-cbc-md4}
+	{default_tgs_enctypes(client)=des-cbc-crc des-cbc-md4}
+	{default_tkt_enctypes(client)=des-cbc-md4}
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des-cbc-crc:normal}
+	{dummy=[verbose -log \
+		"DES TGT, DES enctype, KDC permitting only des-cbc-crc, client requests des-cbc-md4 session key"]}
+    }
+    {
+	all-enctypes
+	des3_krbtgt=1
+	{supported_enctypes=\
+	aes256-cts-hmac-sha1-96:normal aes256-cts-hmac-sha1-96:norealm \
+	aes128-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:norealm \
+	des3-cbc-sha1:normal des3-cbc-sha1:none \
+	des-cbc-md5:normal des-cbc-md4:normal des-cbc-crc:normal \
+	des-cbc-md5:v4 des-cbc-md4:v4 des-cbc-crc:v4 \
+	}
+	{kdc_supported_enctypes=\
+	des3-cbc-sha1:normal des3-cbc-sha1:none \
+	des-cbc-md5:normal des-cbc-md4:normal des-cbc-crc:normal \
+	des-cbc-md5:v4 des-cbc-md4:v4 des-cbc-crc:v4 \
+	}
+	{dummy=[verbose -log "DES3 TGT, default enctypes"]}
+    }
+    # This won't work for anything using GSSAPI until it gets AES support.
+    {
+	aes-only
+	des3_krbtgt=0
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES only, no DES or DES3 support"]}
+    }
+}
+#	{supported_enctypes=des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal }
+#	{kdc_supported_enctypes= des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal}
+
+# This shouldn't be necessary on dejagnu-1.4 and later, but 1.3 seems
+# to need it because its runtest.exp doesn't deal with PASS at all.
+if [info exists PASS] {
+    foreach pass $passes {
+	if { [lsearch -exact $PASS [lindex $pass 0]] >= 0 } {
+	    lappend MULTIPASS $pass
+	}
+    }
+} else {
+    set MULTIPASS $passes
+}
+
+set last_passname_conf ""
+set last_passname_db ""
+
+# We do everything in a temporary directory.
+if ![info exists TMPDIR] {
+    set tmppwd "[pwd]/tmpdir"
+    if ![file isdirectory $tmppwd] {
+	catch "exec mkdir $tmppwd" status
+    }
+} else {
+    set tmppwd $TMPDIR
+}
+verbose "tmppwd=$tmppwd"
+
+# On Ultrix, use /bin/sh5 in preference to /bin/sh.
+if ![info exists BINSH] {
+    if [file exists /bin/sh5] {
+	set BINSH /bin/sh5
+    } else {
+	set BINSH /bin/sh
+    }
+}
+
+# For security, we must not use generally known passwords.  This is
+# because some of the tests may be run as root.  If the passwords were
+# generally know, then somebody could work out the appropriate
+# Kerberos ticket to use, and come in when, say, the telnetd daemon
+# was being tested by root.  The window for doing this is very very
+# small, so the password does not have to be perfect, it just can't be
+# constant.
+if ![info exists KEY] {
+    catch {exec $BINSH -c "echo $$"} KEY
+    verbose "KEY is $KEY"
+    set keyfile [open $tmppwd/KEY w]
+    puts $keyfile "$KEY"
+    close $keyfile
+}
+
+# Clear away any files left over from a previous run.
+# We can't use them now because we don't know the right KEY.
+# krb5.conf might change if running tests on another host
+catch "exec rm -f $tmppwd/db.ok $tmppwd/srvtab $tmppwd/krb5.conf $tmppwd/kdc.conf $tmppwd/cpw_srvtab $tmppwd/krb.realms $tmppwd/krb.conf"
+
+# Put the installed kerberos directories on PATH.
+# This needs to be fixed for V5.
+# set env(PATH) $env(PATH):/usr/kerberos/bin:/usr/kerberos/etc
+# verbose "PATH=$env(PATH)"
+
+# Some of the tests expect $env(USER) to be set.
+if ![info exists env(USER)] {
+    if [info exists env(LOGNAME)] {
+	set env(USER) $env(LOGNAME)
+    } else {
+	if [info exists logname] {
+	    set env(USER) $logname
+	} else {
+	    catch "exec whoami" env(USER)
+	}
+    }
+}
+
+# set the realm. The user can override this on the runtest line.
+if ![info exists REALMNAME] {
+    set REALMNAME "KRBTEST.COM"
+}
+verbose "Test realm is $REALMNAME"
+
+# Find some programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be ...tests/dejagnu.
+
+foreach i {
+    {KDB5_UTIL $objdir/../../kadmin/dbutil/kdb5_util}
+    {KRB5KDC $objdir/../../kdc/krb5kdc}
+    {KADMIND $objdir/../../kadmin/server/kadmind}
+    {KADMIN $objdir/../../kadmin/cli/kadmin}
+    {KADMIN_LOCAL $objdir/../../kadmin/cli/kadmin.local}
+    {KINIT $objdir/../../clients/kinit/kinit}
+    {KTUTIL $objdir/../../kadmin/ktutil/ktutil}
+    {KLIST $objdir/../../clients/klist/klist}
+    {KDESTROY $objdir/../../clients/kdestroy/kdestroy}
+    {RESOLVE $objdir/../resolve/resolve}
+    {T_INETD $objdir/t_inetd}
+} {
+    set varname [lindex $i 0]
+    if ![info exists $varname] {
+	eval set varval [lindex $i 1]
+	set varval [findfile $varval]
+	set $varname $varval
+	verbose "$varname=$varval"
+    } {
+	eval set varval \$$varname
+	verbose "$varname already set to $varval"
+    }
+}
+
+if ![info exists RLOGIN] {
+    set RLOGIN rlogin
+}
+
+if ![info exists RLOGIN_FLAGS] {
+    set RLOGIN_FLAGS "-x"
+}
+
+# We use a couple of variables to hold shell prompts which may be
+# overridden by the user.
+
+if ![info exists ROOT_PROMPT] {
+    set ROOT_PROMPT "(%|#|>|\\$) $"
+}
+
+if ![info exists SHELL_PROMPT] {
+    set SHELL_PROMPT "(%|#|>|\\$) $"
+}
+
+verbose "setting up onexit handler (old handler=[exit -onexit])"
+exit -onexit [concat {
+    verbose "calling stop_kerberos_daemons (onexit handler)"
+    stop_kerberos_daemons;
+} [exit -onexit]]
+
+# check_k5login
+
+# Most of the tests won't work if the user has a .k5login file, unless
+# the user's name appears with $REALMNAME in .k5login
+
+# This procedure returns 1 if the .k5login file appears to be OK, 0
+# otherwise.  This check is not foolproof.
+
+# Note that this previously checked for a username with no realm; this
+# works for krb4's kuserok() but not for krb5_kuserok(), due to some
+# implementation details.  *sigh*
+
+proc check_k5login { testname } {
+    global env
+    global REALMNAME
+
+    if {![file exists ~/.k5login]} {
+	if {$env(USER) == "root"} {
+	    return 0
+	} else {
+	    return 1
+	}
+    }
+
+    verbose "looking for $env(USER)@$REALMNAME in ~/.k5login" 2
+    set file [open ~/.k5login r]
+    while { [gets $file principal] != -1 } {
+	verbose " found $principal" 2
+	if { $principal == "$env(USER)@$REALMNAME" } {
+	    close $file
+	    return 1
+	}
+    }
+    close $file
+
+    note "$testname test requires that your name appear in your ~/.k5login"
+    note "file in the form $env(USER)@$REALMNAME"
+    unsupported "$testname"
+
+    return 0
+}
+
+proc check_klogin { testname } {
+    global env
+    global REALMNAME
+
+    if {![file exists ~/.klogin]} {
+	if {$env(USER) == "root"} {
+	    return 0
+	} else {
+	    return 1
+	}
+    }
+
+    verbose "looking for $env(USER) in ~/.klogin" 2
+    set file [open ~/.klogin r]
+    while { [gets $file principal] != -1 } {
+	verbose " found $principal" 2
+	if { $principal == "$env(USER)" \
+		|| $principal == "$env(USER)@$REALMNAME" } {
+	    close $file
+	    return 1
+	}
+    }
+    close $file
+
+    note "$testname test requires that your name appear in your ~/.klogin"
+    note "file without a realm."
+    unsupported "$testname"
+
+    return 0
+}
+
+# check_exit_status
+# Check the exit status of a spawned program.  Returns 1 if the
+# program succeeded, 0 if it failed.
+
+proc check_exit_status { testname } {
+    global spawn_id
+
+    verbose "about to wait ($testname)"
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list ($testname)"
+    catch "close -i $spawn_id"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } {
+	verbose -log "exit status: $status_list"
+	fail "$testname"
+	return 0
+    } else {
+	return 1
+    }
+}
+
+#
+# ENVSTACK
+#
+
+# These procedures implement an environment variable stack.  They use
+# the global variable $envvars_tosave for the purpose of identifying
+# which environment variables to save.  They also track which ones are
+# unset at any particular point.  The stack pointer is $envstackp,
+# which is an integer.  The arrays $envstack$envstackp and
+# $unenvstack$envstackp store respectively the set of old environment
+# variables/values pushed onto the stack and the set of old unset
+# environment variables for a given value of $envstackp.
+
+# Changing the value of $envvars_tosave after performing the first
+# push operation may result in strangeness.
+
+#
+# envstack_push
+#
+# Push set of current environment variables.
+#
+proc envstack_push { } {
+    global env
+    global envvars_tosave
+    global envstackp
+    global envstack$envstackp
+    global unenvstack$envstackp
+
+    verbose "envstack_push: starting, sp=$envstackp"
+    foreach i $envvars_tosave {
+	if [info exists env($i)] {
+	    verbose "envstack_push: saving $i=$env($i)"
+	    set envstack${envstackp}($i) $env($i)
+	} {
+	    verbose "envstack_push: marking $i as unset"
+	    set unenvstack${envstackp}($i) unset
+	}
+    }
+    incr envstackp
+    verbose "envstack_push: exiting, sp=$envstackp"
+}
+
+#
+# envstack_pop
+#
+# Pop set of current environment variables.
+#
+proc envstack_pop { } {
+    global env
+    global envstackp
+
+    verbose "envstack_pop: starting, sp=$envstackp"
+    incr envstackp -1
+    global envstack$envstackp	# YUCK!!! no obvious better way though...
+    global unenvstack$envstackp
+    if {$envstackp < 0} {
+	perror "envstack_pop: stack underflow!"
+	return
+    }
+    if [info exists envstack$envstackp] {
+	foreach i [array names envstack$envstackp] {
+	    if [info exists env($i)] {
+		verbose "envstack_pop: $i was $env($i)"
+	    }
+	    eval set env($i) \$envstack${envstackp}($i)
+	    verbose "envstack_pop: restored $i to $env($i)"
+	}
+	unset envstack$envstackp
+    }
+    if [info exists unenvstack$envstackp] {
+	foreach i [array names unenvstack$envstackp] {
+	    if [info exists env($i)] {
+		verbose "envstack_pop: $i was $env($i)"
+		unset env($i)
+		verbose "envstack_pop: $i unset"
+	    } {
+		verbose "envstack_pop: ignoring already unset $i"
+	    }
+	}
+	unset unenvstack$envstackp
+    }
+    verbose "envstack_pop: exiting, sp=$envstackp"
+}
+
+#
+# Initialize the envstack
+#
+set envvars_tosave {
+    KRB5_CONFIG KRB5CCNAME KRBTKFILE KRB5RCACHEDIR
+    KERBEROS_SERVER KRB5_KDC_PROFILE
+}
+set krb5_init_vars [list ]
+# XXX -- fix me later!
+foreach i $runvarlist {
+    verbose "processing $i"
+    if {[regexp "^(\[^=\]*)=(.*)" $i foo evar evalue]} {
+	verbose "adding $evar to savelist"
+	lappend envvars_tosave $evar
+	verbose "savelist $envvars_tosave"
+	lappend krb5_init_vars $i
+    }
+}
+set envstackp 0
+envstack_push
+
+# setup_runtime_flags
+# Sets the proper flags for shared libraries. 
+# Configuration is through a site.exp and the runvarlist variable
+# Returns 1 if variables were already set, otherwise 0
+proc setup_runtime_env { } {
+    global env
+    global krb5_init_vars
+
+    # Set the variables
+    foreach i $krb5_init_vars {
+	regexp "^(\[^=\]*)=(.*)" $i foo evar evalue
+	set env($evar) "$evalue"
+	verbose "$evar=$evalue"
+    }
+    return 0
+}
+
+# get_hostname
+# This procedure will get the local hostname.  It sets the global
+# variables hostname (the full name) and localhostname (the first part
+# of the name).  Returns 1 on success, 0 on failure.
+
+proc get_hostname { } {
+    global RESOLVE
+    global hostname
+    global localhostname
+    global domain
+    global tmppwd
+
+    if {[info exists hostname] && [info exists localhostname]} {
+	return 1
+    }
+
+    envstack_push
+    setup_runtime_env
+    catch "exec $RESOLVE -q >$tmppwd/hostname" exec_output
+    envstack_pop
+    if ![string match "" $exec_output] {
+	verbose -log $exec_output
+	perror "can't get hostname"
+	return 0
+    }
+    set file [open $tmppwd/hostname r]
+    if { [ gets $file hostname ] == -1 } {
+	perror "no output from hostname"
+	return 0
+    }
+    close $file
+    catch "exec rm -f $tmppwd/hostname" exec_output
+    regexp "^(\[^.\]*)\\.(.*)$" $hostname foo localhostname domain
+
+    set hostname [string tolower $hostname]
+    set localhostname [string tolower $localhostname]
+    set domain [string tolower $domain]
+    verbose "hostname: $hostname; localhostname: $localhostname; domain $domain"
+
+    return 1
+}
+
+# modify_principal name options...
+
+proc modify_principal { name args } {
+    global KADMIN_LOCAL
+    global REALMNAME
+
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    expect_after {
+	eof {
+	    fail "modprinc (kadmin.local)"
+	    return 0
+	}
+	timeout {
+	    fail "modprinc (kadmin.local)"
+	    return 0
+	}
+    }
+    expect "kadmin.local: "
+    send "modprinc $args $name\r"
+    expect -re "modprinc \[^\n\r\]* $name"
+    expect -re "Principal .* modified."
+    send "quit\r"
+    expect eof
+    catch expect_after
+    if ![check_exit_status "kadmin.local modprinc"] {
+	perror "kadmin.local modprinc exited abnormally"
+    }
+    return 1
+}
+
+# kdc listens on +0..+3, depending whether we're testing reachable or not
+# client tries +1 and +6
+# kadmind +4
+# kpasswd +5
+# krb524 +7
+# application servers (krlogind, telnetd, krshd, ftpd, etc) +8
+if [info exists PORTBASE] {
+    set portbase $PORTBASE
+} else {
+    set portbase 3085
+}
+
+# setup_kerberos_files
+# This procedure will create some Kerberos files which must be created
+# manually before trying to run any Kerberos programs.  Returns 1 on
+# success, 0 on failure.
+
+proc setup_kerberos_files { } {
+    global REALMNAME
+    global hostname
+    global domain
+    global tmppwd
+    global supported_enctypes
+    global kdc_supported_enctypes
+    global last_passname_conf
+    global multipass_name
+    global master_key_type
+    global mode
+    global portbase
+
+    if ![get_hostname] { 
+	return 0
+    }
+
+    setup_krb5_conf client
+    setup_krb5_conf server
+    setup_krb5_conf kdc
+
+    # Create a kdc.conf file.
+    if { ![file exists $tmppwd/kdc.conf] \
+	    || $last_passname_conf != $multipass_name } {
+	if ![info exists master_key_type] {
+	    set master_key_type des-cbc-md5
+	}
+	set conffile [open $tmppwd/kdc.conf w]
+	puts $conffile "\[kdcdefaults\]"
+	puts $conffile "	kdc_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]"
+	puts $conffile "	kdc_tcp_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]"
+	puts $conffile ""
+	puts $conffile "\[realms\]"
+	puts $conffile "	$REALMNAME = \{"
+#	puts $conffile "		database_name = $tmppwd/db"
+	puts $conffile "		admin_database_name = $tmppwd/adb"
+	puts $conffile "		admin_database_lockfile = $tmppwd/adb.lock"
+	puts $conffile "		key_stash_file = $tmppwd/stash"
+	puts $conffile "		acl_file = $tmppwd/acl"
+	puts $conffile "		kadmind_port = [expr 4 + $portbase]"
+	puts $conffile "		kpasswd_port = [expr 5 + $portbase]"
+	puts $conffile "		max_life = 1:00:00"
+	puts $conffile "		max_renewable_life = 3:00:00"
+	puts $conffile "		master_key_type = $master_key_type"
+	puts $conffile "		master_key_name = master/key"
+	puts $conffile "		supported_enctypes = $supported_enctypes"
+	puts $conffile "		kdc_supported_enctypes = $kdc_supported_enctypes"
+	if { $mode == "tcp" } {
+	    puts $conffile "		kdc_ports = [expr 3 + $portbase]"
+	    puts $conffile "		kdc_tcp_ports = [expr 1 + $portbase],[expr 3 + $portbase]"
+	} else {
+	    puts $conffile "		kdc_ports = [expr 1 + $portbase]"
+	    puts $conffile "		kdc_tcp_ports = [expr 3 + $portbase]"
+	}
+	puts $conffile "		default_principal_expiration = 2037.12.31.23.59.59"
+	puts $conffile "		default_principal_flags = -postdateable forwardable"
+	puts $conffile "		dict_file = $tmppwd/dictfile"
+	puts $conffile "	\}"
+	puts $conffile ""
+	close $conffile
+    }
+
+    # Create ACL file.
+    if ![file exists $tmppwd/acl] {
+	set aclfile [open $tmppwd/acl w]
+	puts $aclfile "krbtest/admin@$REALMNAME *"
+	close $aclfile
+    }
+
+    # Create krb.conf file
+    if ![file exists $tmppwd/krb.conf] {
+	set conffile [open $tmppwd/krb.conf w]
+	puts $conffile "$REALMNAME"
+	puts $conffile "$REALMNAME $hostname:[expr 1 + $portbase] admin server"
+	close $conffile
+    }
+
+    # Create krb.realms file
+    if ![file exists $tmppwd/krb.realms] {
+	set conffile [open $tmppwd/krb.realms w]
+	puts $conffile ".[string toupper $domain] $REALMNAME"
+	puts $conffile "[string toupper $domain]. $REALMNAME"
+	close $conffile
+    }
+
+    # Create dictfile file.
+    if ![file exists $tmppwd/dictfile] {
+	set dictfile [open $tmppwd/dictfile w]
+	puts $dictfile "weak_password"
+	close $dictfile
+    }
+
+    set last_passname_conf $multipass_name
+    return 1
+}
+
+proc setup_krb5_conf { {type client} } {
+    global tmppwd
+    global hostname
+    global domain
+    global REALMNAME
+    global last_passname_conf
+    global multipass_name
+    global default_tgs_enctypes
+    global default_tkt_enctypes
+    global permitted_enctypes
+    global mode
+    global portbase
+    global KRB5_DB_MODULE_DIR
+
+    # Create a krb5.conf file.
+    if { ![file exists $tmppwd/krb5.$type.conf] \
+	    || $last_passname_conf != $multipass_name } {
+	set conffile [open $tmppwd/krb5.$type.conf w]
+	puts $conffile "\[libdefaults\]"
+	puts $conffile "	default_realm = $REALMNAME"
+	puts $conffile "	dns_lookup_kdc = false"
+	if [info exists default_tgs_enctypes($type)] {
+	    puts $conffile \
+		    "	default_tgs_enctypes = $default_tgs_enctypes($type)"
+	}
+	if [info exists default_tkt_enctypes($type)] {
+	    puts $conffile \
+		    "	default_tkt_enctypes = $default_tkt_enctypes($type)"
+	}
+	if [info exists permitted_enctypes($type)] {
+	    puts $conffile \
+		    "	permitted_enctypes = $permitted_enctypes($type)"
+	}
+	puts $conffile "	krb4_config = $tmppwd/krb.conf"
+	puts $conffile "	krb4_realms = $tmppwd/krb.realms"
+	puts $conffile "	krb4_srvtab = $tmppwd/v4srvtab"
+	if { $mode == "tcp" } {
+	    puts $conffile "	udp_preference_limit = 1"
+	}
+	puts $conffile ""
+	puts $conffile "\[realms\]"
+	puts $conffile "	$REALMNAME = \{"
+	# There's probably nothing listening here.  It would be a good
+	# test for the handling of a non-responsive KDC address.  However,
+	# on some systems, like Tru64, we often wind up with the client's
+	# socket bound to this address, causing our request to appear in
+	# our incoming queue as if it were a response, which causes test
+	# failures.  If we were running the client and KDC on different
+	# hosts, this would be okay....
+	#puts $conffile "		kdc = $hostname:[expr 6 + $portbase]"
+	puts $conffile "		kdc = $hostname:[expr 1 + $portbase]"
+	puts $conffile "		admin_server = $hostname:[expr 4 + $portbase]"
+	puts $conffile "		kpasswd_server = $hostname:[expr 5 + $portbase]"
+	puts $conffile "		default_domain = $domain"
+	puts $conffile "                krb524_server = $hostname:[expr 7 + $portbase]"
+	puts $conffile "		database_module = foo_db2"
+	puts $conffile "	\}"
+	puts $conffile ""
+	puts $conffile "\[domain_realm\]"
+	puts $conffile "	.$domain = $REALMNAME"
+	puts $conffile "	$domain = $REALMNAME"
+	puts $conffile ""
+	puts $conffile "\[logging\]"
+	puts $conffile "	admin_server = FILE:$tmppwd/kadmind5.log"
+	puts $conffile "	kdc = FILE:$tmppwd/kdc.log"
+	puts $conffile "	default = FILE:$tmppwd/others.log"
+	puts $conffile ""
+	puts $conffile "\[db_modules\]"
+	puts $conffile "	db_module_dir = $tmppwd/../../../util/fakedest$KRB5_DB_MODULE_DIR"
+	puts $conffile "	foo_db2 = {"
+	puts $conffile "		db_library = db2"
+	puts $conffile "		database_name = $tmppwd/db"
+	puts $conffile "	}"
+	close $conffile
+    }
+}
+
+# Save the original values of the environment variables we are going
+# to muck with.
+
+# XXX deal with envstack later.
+
+if [info exists env(KRB5_CONFIG)] {
+    set orig_krb5_conf $env(KRB5_CONFIG)
+} else {
+    catch "unset orig_krb5_config"
+}
+
+if [info exists env(KRB5CCNAME)] {
+    set orig_krb5ccname $env(KRB5CCNAME)
+} else {
+    catch "unset orig_krb5ccname"
+}
+
+if [ info exists env(KRB5RCACHEDIR)] {
+    set orig_krb5rcachedir $env(KRB5RCACHEDIR)
+} else {
+    catch "unset orig_krb5rcachedir"
+}
+
+if [ info exists env(KERBEROS_SERVER)] {
+    set orig_kerberos_server $env(KERBEROS_SERVER)
+} else {
+    catch "unset orig_kerberos_server"
+}
+
+# setup_kerberos_env
+# Set the environment variables needed to run Kerberos programs.
+
+proc setup_kerberos_env { {type client} } {
+    global REALMNAME
+    global env
+    global tmppwd
+    global hostname
+    global krb5_init_vars
+    global portbase
+
+    # Set the environment variable KRB5_CONFIG to point to our krb5.conf file.
+    # All the Kerberos tools check KRB5_CONFIG.
+    # Actually, V5 doesn't currently use this.
+    set env(KRB5_CONFIG) $tmppwd/krb5.$type.conf
+    verbose "KRB5_CONFIG=$env(KRB5_CONFIG)"
+
+    # Direct the Kerberos programs at a local ticket file.
+    set env(KRB5CCNAME) $tmppwd/tkt
+    verbose "KRB5CCNAME=$env(KRB5CCNAME)"
+
+    # Direct the Kerberos programs at a local ticket file.
+    set env(KRBTKFILE) $tmppwd/tktv4
+    verbose "KRBTKFILE=$env(KRBTKFILE)"
+
+    # Direct the Kerberos server at a cache file stored in the
+    # temporary directory.
+    set env(KRB5RCACHEDIR) $tmppwd
+    verbose "KRB5RCACHEDIR=$env(KRB5RCACHEDIR)"
+
+    # Tell the Kerberos tools how to contact the $REALMNAME server.
+    set env(KERBEROS_SERVER) "$REALMNAME:$hostname:[expr 1 + $portbase]"
+    verbose "KERBEROS_SERVER=$env(KERBEROS_SERVER)"
+
+    # Get the run time environment variables... (including LD_LIBRARY_PATH)
+    setup_runtime_env
+
+    # Set our kdc config file.
+    set env(KRB5_KDC_PROFILE) $tmppwd/kdc.conf
+    verbose "KRB5_KDC_PROFILE=$env(KRB5_KDC_PROFILE)"
+
+    # Create an environment setup script.  (For convenience)
+    if ![file exists $tmppwd/env.sh] {
+	set envfile [open $tmppwd/env.sh w]
+	puts $envfile "KRB5_CONFIG=$env(KRB5_CONFIG)"
+	puts $envfile "KRB5CCNAME=$env(KRB5CCNAME)"
+	puts $envfile "KRB5RCACHEDIR=$env(KRB5RCACHEDIR)"
+	puts $envfile "KERBEROS_SERVER=$env(KERBEROS_SERVER)"
+	puts $envfile "KRB5_KDC_PROFILE=$env(KRB5_KDC_PROFILE)"
+	puts $envfile "export KRB5_CONFIG KRB5CCNAME KRB5RCACHEDIR"
+	puts $envfile "export KERBEROS_SERVER KRB5_KDC_PROFILE"
+	foreach i $krb5_init_vars {
+		regexp "^(\[^=\]*)=(.*)" $i foo evar evalue
+		puts $envfile "$evar=$env($evar)"
+		puts $envfile "export $evar"
+	}
+	close $envfile
+    }
+    if ![file exists $tmppwd/env.csh] {
+	set envfile [open $tmppwd/env.csh w]
+	puts $envfile "setenv KRB5_CONFIG $env(KRB5_CONFIG)"
+	puts $envfile "setenv KRB5CCNAME $env(KRB5CCNAME)"
+	puts $envfile "setenv KRB5RCACHEDIR $env(KRB5RCACHEDIR)"
+	puts $envfile "setenv KERBEROS_SERVER $env(KERBEROS_SERVER)"
+	puts $envfile "setenv KRB5_KDC_PROFILE $env(KRB5_KDC_PROFILE)"
+	foreach i $krb5_init_vars {
+		regexp "^(\[^=\]*)=(.*)" $i foo evar evalue
+		puts $envfile "setenv $evar $env($evar)"
+	}
+	close $envfile
+    }
+    return 1
+}
+
+# Restore the Kerberos environment, in case setup_kerberos_env was
+# already called by an earlier test.
+
+proc restore_kerberos_env { } {
+    global env
+    global orig_krb5_config
+    global orig_krb5ccname
+    global orig_krb5rcachedir
+    global orig_kerberos_server
+
+    if [info exists orig_krb5_config] {
+    set env(KRB5_CONFIG) $orig_krb5_config
+    } else {
+    catch "unset env(KRB5_CONFIG)"
+    }
+
+    if [info exists orig_krb5ccname] {
+	set env(KRB5CCNAME) $orig_krb5ccname
+    } else {
+	catch "unset env(KRB5CCNAME)"
+    }
+
+    if [info exists orig_krb5rcachedir] {
+	set env(KRB5RCACHEDIR) $orig_krb5rcachedir
+    } else {
+	catch "unset env(KRB5RCACHEDIR)"
+    }
+
+    if [info exists orig_kerberos_server] {
+	set env(KERBEROS_SERVER) $orig_kerberos_server
+    } else {
+	catch "unset env(KERBEROS_SERVER)"
+    }
+
+}
+
+# setup_kerberos_db
+# Initialize the Kerberos database.  If the argument is non-zero, call
+# pass at relevant points.  Returns 1 on success, 0 on failure.
+
+proc setup_kerberos_db { standalone } {
+    global REALMNAME
+    global KDB5_UTIL
+    global KADMIN_LOCAL
+    global KEY
+    global tmppwd
+    global spawn_id
+    global des3_krbtgt
+    global tgt_support_desmd5
+    global multipass_name
+    global last_passname_db
+
+    set failall 0
+
+    if {!$standalone && [file exists $tmppwd/db.ok] \
+	&& $last_passname_db == $multipass_name} {
+	return 1
+    }
+
+    catch "exec rm -f [glob -nocomplain $tmppwd/db* $tmppwd/adb*]"
+
+    # Creating a new database means we need a new srvtab.
+    catch "exec rm -f $tmppwd/srvtab"
+
+    envstack_push
+    if { ![setup_kerberos_files] || ![setup_kerberos_env kdc] } {
+	set failall 1
+    }
+
+    # Set up a common expect_after for use in multiple places.
+    set def_exp_after {
+	timeout {
+	    set test "$test (timeout)"
+	    break
+	}
+	eof {
+	    set test "$test (eof)"
+	    break
+	}
+    }
+
+    set test "kdb5_util create"
+    set body {
+	if $failall {
+	    break
+	}
+	#exec xterm
+	verbose "starting $test"
+	spawn $KDB5_UTIL -r $REALMNAME create
+	expect_after $def_exp_after
+
+	expect "Enter KDC database master key:"
+
+	set test "kdb5_util create (verify)"
+	send "masterkey$KEY\r"
+	expect "Re-enter KDC database master key to verify:"
+
+	set test "kdb5_util create"
+	send "masterkey$KEY\r"
+	expect {
+	    -re "\[Cc\]ouldn't" {
+		expect eof
+		break
+	    }
+	    "Cannot find/read stored" exp_continue
+	    "Warning: proceeding without master key" exp_continue
+	    eof { }
+	}
+	catch expect_after
+	if ![check_exit_status kdb5_util] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch expect_after
+    if $ret {
+	set failall 1
+	if $standalone {
+	    fail $test
+	}
+    } else {
+	if $standalone {
+	    pass $test
+	}
+    }
+
+    # Stash the master key in a file.
+    set test "kdb5_util stash"
+    set body {
+	if $failall {
+	    break
+	}
+	spawn $KDB5_UTIL  -r $REALMNAME stash
+	verbose "starting $test"
+	expect_after $def_exp_after
+	expect "Enter KDC database master key:"
+	send "masterkey$KEY\r"
+	expect eof
+	catch expect_after
+	if ![check_exit_status kdb5_util] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch "expect eof"
+    catch expect_after
+    if $ret {
+	set failall 1
+	if $standalone {
+	    fail $test
+	} else {
+	    catch "exec rm -f $tmppwd/db.ok $tmppwd/adb.db"
+	}
+    } else {
+	if $standalone {
+	    pass $test
+	}
+    }
+
+    # Add an admin user.
+#send_user "will run: $KADMIN_LOCAL -r $REALMNAME\n"
+#exec xterm
+    set test "kadmin.local ank krbtest/admin"
+    set body {
+	if $failall {
+	    break
+	}
+	spawn $KADMIN_LOCAL -r $REALMNAME
+	verbose "starting $test"
+	expect_after $def_exp_after
+
+	expect "kadmin.local: "
+	send "ank krbtest/admin@$REALMNAME\r"
+	# It echos...
+	expect "ank krbtest/admin@$REALMNAME\r"
+	expect "Enter password for principal \"krbtest/admin@$REALMNAME\":"
+	send "adminpass$KEY\r"
+	expect "Re-enter password for principal \"krbtest/admin@$REALMNAME\":"
+	send "adminpass$KEY\r"
+	expect {
+	    "Principal \"krbtest/admin@$REALMNAME\" created" { }
+	    "Principal or policy already exists while creating*" { }
+	}
+	expect "kadmin.local: "
+	send "quit\r"
+	expect eof
+	catch expect_after
+	if ![check_exit_status kadmin_local] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch "expect eof"
+    catch expect_after
+    if $ret {
+	set failall 1
+	if $standalone {
+	    fail $test
+	} else {
+	    catch "exec rm -f $tmppwd/db.ok $tmppwd/adb.db"
+	}
+    } else {
+	if $standalone {
+	    pass $test
+	}
+    }
+
+    if $des3_krbtgt {
+	# Set the TGT key to DES3.
+	set test "kadmin.local TGT to DES3"
+	set body {
+	    if $failall {
+		break
+	    }
+	    spawn $KADMIN_LOCAL -r $REALMNAME -e des3-cbc-sha1:normal
+	    verbose "starting $test"
+	    expect_after $def_exp_after
+
+	    expect "kadmin.local: "
+	    send "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r"
+	    # It echos...
+	    expect "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r"
+	    expect {
+		"Key for \"krbtgt/$REALMNAME@$REALMNAME\" randomized." { }
+	    }
+	    expect "kadmin.local: "
+	    send "quit\r"
+	    expect eof
+	    catch expect_after
+	    if ![check_exit_status kadmin_local] {
+		break
+	    }
+	}
+	set ret [catch $body]
+	catch "expect eof"
+	catch expect_after
+	if $ret {
+	    set failall 1
+	    if $standalone {
+		fail $test
+	    } else {
+		catch "exec rm -f $tmppwd/db.ok $tmppwd/adb.db"
+	    }
+	} else {
+	    if $standalone {
+		pass $test
+	    }
+	}
+    }
+    if $tgt_support_desmd5 {
+	# Make TGT support des-cbc-md5
+	set test "kadmin.local TGT to SUPPORT_DESMD5"
+	set body {
+	    if $failall {
+		break
+	    }
+	    spawn $KADMIN_LOCAL -r $REALMNAME
+	    verbose "starting $test"
+	    expect_after $def_exp_after
+
+	    expect "kadmin.local: "
+	    send "modprinc +support_desmd5 krbtgt/$REALMNAME@$REALMNAME\r"
+	    # It echos...
+	    expect "modprinc +support_desmd5 krbtgt/$REALMNAME@$REALMNAME\r"
+	    expect {
+		"Principal \"krbtgt/$REALMNAME@$REALMNAME\" modified.\r\n" { }
+	    }
+	    expect "kadmin.local: "
+	    send "quit\r"
+	    expect eof
+	    catch expect_after
+	    if ![check_exit_status kadmin_local] {
+		break
+	    }
+	}
+	set ret [catch $body]
+	catch "expect eof"
+	catch expect_after
+	if $ret {
+	    set failall 1
+	    if $standalone {
+		fail $test
+	    } else {
+		catch "exec rm -f $tmppwd/db.ok $tmppwd/adb.db"
+	    }
+	} else {
+	    if $standalone {
+		pass $test
+	    }
+	}
+    }
+    envstack_pop
+
+    # create the admin database lock file
+    catch "exec touch $tmppwd/adb.lock"
+
+    set last_passname_db $multipass_name
+    return 1
+}
+
+proc start_tail { fname spawnid_var pid_var which standalone } {
+    upvar $spawnid_var spawnid
+    upvar $pid_var pid
+    global timeout
+
+    set f [open $fname a]
+
+    spawn tail -f $fname
+    set spawnid $spawn_id
+    set pid [exp_pid]
+
+    set markstr "===MARK $pid [clock format [clock seconds]] ==="
+    puts $f $markstr
+    flush $f
+
+    set p 0
+    set otimeout $timeout
+    set timeout 1
+    set ok 0
+    while { $ok == 0 && $p < 3 } {
+	expect {
+	    -i $spawn_id
+	    -ex "$markstr\r\n" { set ok 1 }
+	    -re "\[^\r\n\]*\r\n" { exp_continue }
+	    timeout {
+		# Some versions of GNU tail had a race condition where
+		# the first batch of data would be read from the end
+		# of the file, and then there was a brief window
+		# before calling stat and recording the size of the
+		# file.  If the marker is written during that window,
+		# then yet another file modification is needed to get
+		# the first one noticed.
+		if { $p < 3 } {
+		    verbose -log "no tail output yet, prodding with a blank line"
+		    incr p
+		    puts $f ""
+		    flush $f
+		    exp_continue
+		} else {
+		    close $f
+		    verbose -log "tail $fname output:"
+		    verbose -log [exec tail $fname]
+		    if {$standalone} {
+			verbose -log "tail -f timed out ($timeout sec) looking for mark in $which log"
+			fail "$which"
+		    } else {
+			perror "$which tail -f timed out ($timeout sec) looking for mark in $which log"
+		    }
+		    stop_kerberos_daemons
+		    exec kill $pid
+		    expect -i $spawn_id eof
+		    wait -i $spawn_id
+		    set timeout $otimeout
+		    return 0
+		}
+	    }
+	}
+    }
+    close $f
+    set timeout $otimeout
+    return 1
+}
+
+# start_kerberos_daemons
+# A procedure to build a Kerberos database and start up the kerberos
+# and kadmind daemons.  This sets the global variables kdc_pid,
+# kdc_spawn_id, kadmind_pid, and kadmind_spawn_id.  The procedure
+# stop_kerberos_daemons should be used to stop the daemons.  If the
+# argument is non-zero, call pass at relevant points.  Returns 1 on
+# success, 0 on failure.
+
+proc start_kerberos_daemons { standalone } {
+    global BINSH
+    global REALMNAME
+    global KRB5KDC
+    global KADMIND
+    global KEY
+    global kdc_pid
+    global kdc_spawn_id
+    global kadmind_pid
+    global kadmind_spawn_id
+    global tmppwd
+    global env
+    global timeout
+
+    if ![setup_kerberos_db 0] {
+	return 0
+    }
+
+    if {$standalone} {
+        catch "exec rm -f $tmppwd/krb.log"
+	catch "exec rm -f $tmppwd/kadmind.log"
+	catch "exec rm -f $tmppwd/krb5kdc_rcache"
+    }
+
+    # Start up the kerberos daemon
+    # Why are we doing all this with the log file you may ask.
+    #   We need a handle on when the server starts. If we log the output
+    #   of the server to say stderr, then if we stop looking for output,
+    #   buffers will fill and the server will stop working....
+    #   So, we look to see when a line is added to the log file and then
+    #   check it..
+    # The same thing is done a little later for the kadmind
+    set kdc_lfile $tmppwd/kdc.log
+    set kadmind_lfile $tmppwd/kadmind5.log
+
+    if ![start_tail $kdc_lfile tailf_spawn_id tailf_pid krb5kdc $standalone] {
+	return 0
+    }
+
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $KRB5KDC -r $REALMNAME -n -4 full
+    envstack_pop
+    set kdc_pid [exp_pid]
+    set kdc_spawn_id $spawn_id
+
+    expect {
+	-i $tailf_spawn_id
+	-re "commencing operation\r\n" { }
+	-re "krb5kdc: \[a-zA-Z\]* - Cannot bind server socket to \[ 0-9a-fA-F:.\]*\r\n" {
+	    verbose -log "warning: $expect_out(0,string)"
+	    exp_continue
+	}
+	"no sockets set up?" {
+	    if {$standalone} {
+		verbose -log "krb5kdc startup failed to bind listening sockets"
+		fail "krb5kdc"
+	    } else {
+		perror "krb5kdc startup failed to bind listening sockets"
+	    }
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+	timeout {
+	    if {$standalone} {
+		verbose -log "krb5kdc startup timed out"
+		fail "krb5kdc"
+	    } else {
+		perror "krb5kdc startup timed out"
+	    }
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+    }
+    exec kill $tailf_pid
+    expect -i $tailf_spawn_id eof
+    wait -i $tailf_spawn_id
+
+    if {$standalone} {
+	pass "krb5kdc"
+    }
+
+    # Give the kerberos daemon a few seconds to get set up.
+#    sleep 2
+
+    #
+    # Save setting of KRB5_KTNAME. We do not want to override kdc.conf
+    # file during kadmind startup. (this is in case user has KRB5_KTNAME
+    # set before starting make check)
+    #
+    if [info exists env(KRB5_KTNAME)] {
+	set start_save_ktname $env(KRB5_KTNAME)
+    }
+    catch "unset env(KRB5_KTNAME)"
+
+    if ![start_tail $kadmind_lfile tailf_spawn_id tailf_pid kadmind $standalone] {
+	return 0
+    }
+
+    # Start up the kadmind daemon
+    # XXXX kadmind uses stderr a lot.  the sh -c and redirect can be
+    # removed when this is fixed
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $BINSH -c "exec $KADMIND -r $REALMNAME -nofork 2>>$kadmind_lfile"
+    envstack_pop
+    set kadmind_pid [exp_pid]
+    set kadmind_spawn_id $spawn_id
+
+    # Restore KRB5_KTNAME
+    if [info exists start_save_ktname] {
+        set env(KRB5_KTNAME) $start_save_ktname
+        unset start_save_ktname
+    }
+
+    expect {
+	-i $tailf_spawn_id
+	"Seeding random number" exp_continue
+	"cannot initialize network" {
+	    if {$standalone} {
+		verbose -log "kadmind failed network init"
+		fail "kadmind"
+	    } else {
+		perror "kadmind failed network init"
+	    }
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+	"cannot bind to network address" {
+	    if {$standalone} {
+		verbose -log "kadmind failed to bind socket"
+		fail "kadmind"
+	    } else {
+		perror "kadmind failed to bind socket"
+	    }
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+	"No principal in keytab matches desired name" {
+	    dump_db
+	    exp_continue
+	}
+	"starting" { }
+	timeout {
+	    if {$standalone} {
+		verbose -log "kadmind failed to start"
+		fail "kadmind"
+	    } else {
+		verbose -log "kadmind failed to start"
+		perror "kadmind failed to start"
+	    }
+#sleep 10
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+    }
+    exec kill $tailf_pid
+    expect -i $tailf_spawn_id eof
+    wait -i $tailf_spawn_id
+
+    if {$standalone} {
+	pass "kadmind"
+    }
+
+    # Give the kadmind daemon a few seconds to get set up.
+#    sleep 2
+
+    return 1
+}
+
+# stop_kerberos_daemons
+# Stop the kerberos daemons.  Returns 1 on success, 0 on failure.
+
+proc stop_kerberos_daemons { } {
+    global kdc_pid
+    global kdc_spawn_id
+    global kadmind_pid
+    global kadmind_spawn_id
+
+    verbose "entered stop_kerberos_daemons"
+
+    if [info exists kdc_pid] {
+	if [catch "exec kill $kdc_pid" msg] {
+	    verbose "kill kdc: $msg"
+	}
+	if [catch "expect -i $kdc_spawn_id eof" msg] {
+	    verbose "expect kdc eof: $msg"
+	}
+	set kdc_list [wait -i $kdc_spawn_id]
+	verbose "wait -i $kdc_spawn_id returned $kdc_list (kdc)"
+	unset kdc_pid
+	unset kdc_list
+    }
+
+    if [info exists kadmind_pid] {
+	if [catch "exec kill $kadmind_pid" msg] {
+	    verbose "kill kadmind: $msg"
+	}
+	if [catch "expect -i $kadmind_spawn_id eof" msg] {
+	    verbose "expect kadmind eof: $msg"
+	}
+	set kadmind_list [wait -i $kadmind_spawn_id]
+	verbose "wait -i $kadmind_spawn_id returned $kadmind_list (kadmind5)"
+	unset kadmind_pid
+	unset kadmind_list
+    }
+
+    verbose "exiting stop_kerberos_daemons"
+
+    return 1
+}
+
+# add_kerberos_key
+# Add an key to the Kerberos database.  start_kerberos_daemons must be
+# called before this procedure.  If the standalone argument is
+# non-zero, call pass at relevant points.  Returns 1 on success, 0 on
+# failure.
+
+proc add_kerberos_key { kkey standalone } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    # Use kadmin to add an key.
+    set test "kadmin ank $kkey"
+    set body {
+	envstack_push
+	setup_kerberos_env client
+	spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank $kkey@$REALMNAME"
+	envstack_pop
+	verbose "starting $test"
+	expect_after {
+	    "Cannot contact any KDC" {
+		set test "$test (lost KDC)"
+		break
+	    }
+	    timeout {
+		set test "$test (timeout)"
+		break
+	    }
+	    eof {
+		set test "$test (eof)"
+		break
+	    }
+	}
+	expect -re "assword\[^\r\n\]*: *"
+	send "adminpass$KEY\r"
+	expect "Enter password for principal \"$kkey@$REALMNAME\":"
+	send "$kkey"
+	send "$KEY\r"
+	expect "Re-enter password for principal \"$kkey@$REALMNAME\":"
+	send "$kkey"
+	send "$KEY\r"
+	expect {
+	    "Principal \"$kkey@$REALMNAME\" created" { }
+	    "Principal or policy already exists while creating*" { }
+	}
+	expect eof
+	if ![check_exit_status kadmin] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch "expect eof"
+    catch expect_after
+    if $ret {
+	if $standalone {
+	    fail $test
+	}
+	return 0
+    } else {
+	if $standalone {
+	    pass $test
+	}
+	return 1
+    }
+}
+
+# dump_db
+proc dump_db { } {
+    global KADMIN_LOCAL
+    global REALMNAME
+
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    expect_after {
+	eof {
+	    perror "failed to get debugging dump of database (eof)"
+	}
+	timeout {
+	    perror "failed to get debugging dump of database (timeout)"
+	}
+    }
+    expect "kadmin.local: "
+    send "getprincs\r"
+    expect "kadmin.local: "
+    send "quit\r"
+    expect eof
+    catch expect_after
+}
+
+# add_random_key
+# Add a key with a random password to the Kerberos database.
+# start_kerberos_daemons must be called before this procedure.  If the
+# standalone argument is non-zero, call pass at relevant points.
+# Returns 1 on success, 0 on failure.
+
+proc add_random_key { kkey standalone } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    # Use kadmin to add an key.
+    set test "kadmin ark $kkey"
+    set body {
+	envstack_push
+	setup_kerberos_env client
+	spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $kkey@$REALMNAME"
+	envstack_pop
+	expect_after {
+	    timeout {
+		set test "$test (timeout)"
+		break
+	    }
+	    eof {
+		set test "$test (eof)"
+		break
+	    }
+	}
+	expect -re "assword\[^\r\n\]*: *"
+	send "adminpass$KEY\r"
+	expect {
+	    "Principal \"$kkey@$REALMNAME\" created" { }
+	    "Principal or policy already exists while creating*" { }
+	}
+	expect eof
+	if ![check_exit_status kadmin] {
+	    break
+	}
+    }
+    if [catch $body] {
+	catch expect_after
+	if $standalone {
+	    fail $test
+	}
+	return 0
+    } else {
+	catch expect_after
+	if $standalone {
+	    pass $test
+	}
+	return 1
+    }
+}
+
+# setup_srvtab
+# Set up a srvtab file.  start_kerberos_daemons and add_random_key
+# $id/$hostname must be called before this procedure.  If the
+# argument is non-zero, call pass at relevant points.  Returns 1 on
+# success, 0 on failure. If the id field is not provided, host is used.
+
+proc setup_srvtab { standalone {id host} } {
+    global REALMNAME
+    global KADMIN_LOCAL
+    global KEY
+    global tmppwd
+    global hostname
+    global spawn_id
+    global last_service
+
+    if {!$standalone && [file exists $tmppwd/srvtab] && $last_service == $id} {
+	return 1
+    }
+
+    catch "exec rm -f $tmppwd/srvtab $tmppwd/srvtab.old"
+
+    if ![get_hostname] {
+	return 0
+    }
+
+    catch "exec rm -f $hostname-new-srvtab"
+
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    envstack_pop
+    expect_after {
+	-re "(.*)\r\nkadmin.local:  " {
+	    fail "kadmin.local srvtab (unmatched output: $expect_out(1,string))"
+	    if {!$standalone} {
+		catch "exec rm -f $tmppwd/srvtab"
+	    }
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin.local srvtab"
+	    if {!$standalone} {
+		catch "exec rm -f $tmppwd/srvtab"
+	    }
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin.local srvtab"
+	    if {!$standalone} {
+		catch "exec rm -f $tmppwd/srvtab"
+	    }
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect "kadmin.local:  "
+    send "xst -k $hostname-new-srvtab $id/$hostname\r"
+    expect "xst -k $hostname-new-srvtab $id/$hostname\r\n"
+    expect {
+	-re ".*Entry for principal $id/$hostname.* added to keytab WRFILE:$hostname-new-srvtab." { }
+	-re "\r\nkadmin.local:  " {
+	    if {$standalone} {
+		fail "kadmin.local srvtab"
+	    } else {
+		catch "exec rm -f $tmppwd/srvtab"
+	    }
+	    catch expect_after
+	    return 0
+	}
+    }
+    expect "kadmin.local:  "
+    send "quit\r"
+    expect eof
+    catch expect_after
+    if ![check_exit_status "kadmin.local srvtab"] {
+	if {!$standalone} {
+	    catch "exec rm -f $tmppwd/srvtab"
+	}
+	return 0
+    }
+
+    catch "exec mv -f $hostname-new-srvtab $tmppwd/srvtab" exec_output
+    if ![string match "" $exec_output] {
+	verbose -log "$exec_output"
+	perror "can't mv new srvtab"
+	return 0
+    }
+
+    if {$standalone} {
+	pass "kadmin.local srvtab"
+    }
+
+    # Make the srvtab file globally readable in case we are using a
+    # root shell and the srvtab is NFS mounted.
+    catch "exec chmod a+r $tmppwd/srvtab"
+
+    # Remember what we just extracted
+    set last_service $id
+
+    return 1
+}
+
+# kinit
+# Use kinit to get a ticket.  If the argument is non-zero, call pass
+# at relevant points.  Returns 1 on success, 0 on failure.
+
+proc kinit { name pass standalone } {
+    global REALMNAME
+    global KINIT
+    global spawn_id
+
+    # Use kinit to get a ticket.
+	#
+	# For now always get forwardable tickets. Later when we need to make
+	# tests that distiguish between forwardable tickets and otherwise
+	# we should but another option to this proc. --proven
+	#
+    spawn $KINIT -5 -f $name@$REALMNAME
+    expect {
+	"Password for $name@$REALMNAME:" {
+	    verbose "kinit started"
+	}
+	timeout {
+	    fail "kinit"
+	    return 0
+	}
+	eof {
+	    fail "kinit"
+	    return 0
+	}
+    }
+    send "$pass\r"
+    expect eof
+    if ![check_exit_status kinit] {
+	return 0
+    }
+
+    if {$standalone} {
+	pass "kinit"
+    }
+
+    return 1
+}
+
+proc kinit_kt { name keytab standalone testname } {
+    global REALMNAME
+    global KINIT
+    global spawn_id
+
+    # Use kinit to get a ticket.
+	#
+	# For now always get forwardable tickets. Later when we need to make
+	# tests that distiguish between forwardable tickets and otherwise
+	# we should but another option to this proc. --proven
+	#
+    spawn $KINIT -5 -f -k -t $keytab $name@$REALMNAME
+    expect {
+	timeout {
+	    fail "kinit $testname"
+	    return 0
+	}
+	eof { }
+    }
+    if ![check_exit_status "kinit $testname"] {
+	return 0
+    }
+
+    if {$standalone} {
+	pass "kinit $testname"
+    }
+
+    return 1
+}
+
+# List tickets.  Requires client and server names, and test name.
+# Checks that klist exist status is zero.
+# Records pass or fail, and returns 1 or 0.
+proc do_klist { myname servname testname } {
+    global KLIST
+    global tmppwd
+
+    spawn $KLIST -5 -e
+    expect {
+	-re "Ticket cache:\[ 	\]*(.+:)?$tmppwd/tkt.*Default principal:\[ 	\]*$myname.*$servname\r\n" {
+	    verbose "klist started"
+	}
+	timeout {
+	    fail $testname
+	    return 0
+	}
+	eof {
+	    fail $testname
+	    return 0
+	}
+    }
+
+    expect eof
+
+    if ![check_exit_status $testname] {
+	return 0
+    }
+    pass $testname
+    return 1
+}
+
+proc do_klist_kt { keytab testname } {
+    global KLIST
+    global tmppwd
+
+    spawn $KLIST -5 -e -k $keytab
+    expect {
+	-re "Keytab name:\[ 	\]*(.+:)?.*KVNO Principal\r\n---- -*\r\n" {
+	    verbose "klist started"
+	}
+	timeout {
+	    fail $testname
+	    return 0
+	}
+	eof {
+	    fail $testname
+	    return 0
+	}
+    }
+    set more 1
+    while {$more} {
+	expect {
+	    -re { *[0-9][0-9]* *[a-zA-Z/@.-]* \([/a-zA-Z 0-9-]*\) *\r\n} {
+		verbose -log "key: $expect_out(buffer)"
+	    }
+	    eof { set more 0 }
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return 0
+    }
+    pass $testname
+    return 1
+}
+
+proc do_klist_err { testname } {
+    global KLIST
+    global spawn_id
+
+    spawn $KLIST -5
+    # Might say "credentials cache" or "credentials cache file".
+    expect {
+	-re "klist: No credentials cache.*found.*\r\n" {
+	    verbose "klist started"
+	}
+	timeout {
+	    fail $testname
+	    return 0
+	}
+	eof {
+	    fail $testname
+	    return 0
+	}
+    }
+    # We can't use check_exit_status, because we expect an exit status
+    # of 1.
+    catch "expect eof"
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list ($testname)"
+    if { [lindex $status_list 2] != 0 } {
+	fail "$testname (bad exit status) $status_list"
+	return 0
+    } else { if { [lindex $status_list 3] != 1 } {
+	fail "$testname (bad exit status) $status_list"
+	return 0
+    } else {
+	pass $testname
+    } }
+    return 1
+}
+
+proc do_kdestroy { testname } {
+    global KDESTROY
+    spawn $KDESTROY -5
+    if ![check_exit_status $testname] {
+	fail $testname
+	return 0
+    }
+    pass $testname
+    return 1
+}
+
+proc xst { keytab name } {
+    global KADMIN_LOCAL
+    global REALMNAME
+
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    envstack_pop
+    catch expect_after
+    expect_after {
+	-re "(.*)\r\nkadmin.local:  " {
+	    fail "kadmin.local xst $keytab (unmatched output: $expect_out(1,string)"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin.local xst $keytab (timeout)"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin.local xst $keytab (eof)"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect "kadmin.local:  "
+    send "xst -k $keytab $name\r"
+    expect -re "xst -k \[^\r\n\]*\r\n.*Entry for principal .* added to keytab WRFILE:.*\r\nkadmin.local:  "
+    send "quit\r"
+    expect eof
+    catch expect_after
+    if ![check_exit_status "kadmin.local $keytab"] {
+	perror "kadmin.local xst $keytab exited abnormally"
+	return 0
+    }
+    return 1
+}
+
+# v4_compatible_enctype
+# Returns 1 if v4 testing is enabled this passes encryption types are compatable with kerberos 4 work
+proc v4_compatible_enctype {} {
+    global supported_enctypes
+    global KRBIV
+
+    if ![info exists KRBIV] {
+	return 0;
+    }
+
+    if { $KRBIV && [string first des-cbc-crc:v4 "$supported_enctypes"] >= 0} {
+	return 1
+    } else {
+	return 0
+    }
+}
+
+# kinit
+# Use kinit to get a ticket.  If the argument is non-zero, call pass
+# at relevant points.  Returns 1 on success, 0 on failure.
+
+proc v4kinit { name pass standalone } {
+    global REALMNAME
+    global KINIT
+    global spawn_id
+    global des3_krbtgt
+
+    # Use kinit to get a ticket.
+	#
+	# For now always get forwardable tickets. Later when we need to make
+	# tests that distiguish between forwardable tickets and otherwise
+	# we should but another option to this proc. --proven
+	#
+    spawn $KINIT -4 $name@$REALMNAME
+    expect {
+	"Password for $name@$REALMNAME:" {
+	    verbose "v4kinit started"
+	}
+	timeout {
+	    fail "v4kinit"
+	    return 0
+	}
+	eof {
+	    fail "v4kinit"
+	    return 0
+	}
+    }
+    send "$pass\r"
+    expect eof
+    if {$des3_krbtgt == 0} {
+	if ![check_exit_status v4kinit] {
+	    return 0
+	}
+    } else {
+	# Fail if kinit is successful with a des3 TGT.
+	set status_list [wait -i $spawn_id]
+	set testname v4kinit
+	verbose "wait -i $spawn_id returned $status_list ($testname)"
+	if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 1 } {
+	    verbose -log "exit status: $status_list"
+	    fail "$testname (exit status)"
+	}
+    }
+    if {$standalone} {
+	pass "v4kinit"
+    }
+
+    return 1
+}
+
+proc v4kinit_kt { name keytab standalone } {
+    global REALMNAME
+    global KINIT
+    global spawn_id
+
+    # Use kinit to get a ticket.
+	#
+	# For now always get forwardable tickets. Later when we need to make
+	# tests that distiguish between forwardable tickets and otherwise
+	# we should but another option to this proc. --proven
+	#
+    spawn $KINIT -4 -k -t $keytab $name@$REALMNAME
+    expect {
+	timeout {
+	    fail "v4kinit"
+	    return 0
+	}
+	eof { }
+    }
+    if ![check_exit_status kinit] {
+	return 0
+    }
+
+    if {$standalone} {
+	pass "v4kinit"
+    }
+
+    return 1
+}
+
+# List v4 tickets.
+# Client and server are regular expressions.
+proc v4klist { client server testname } {
+    global KLIST
+    global tmppwd
+
+    spawn $KLIST -4
+    expect {
+	-re "Kerberos 4 ticket cache:\[ 	\]*(.+:)?$tmppwd/tkt.*Principal:\[ 	\]*$client.*$server\r\n" {
+	    verbose "klist started"
+	}
+	timeout {
+	    fail $testname
+	    return 0
+	}
+	eof {
+	    fail $testname
+	    return 0
+	}
+    }
+
+    expect eof
+
+    if ![check_exit_status $testname] {
+	return 0
+    }
+    pass $testname
+    return 1
+}
+
+# Destroy tickets.
+proc v4kdestroy { testname } {
+    global KDESTROY
+    spawn $KDESTROY -4
+    if ![check_exit_status $testname] {
+	return 0
+    }
+    pass $testname
+    return 1
+}
+
+# Try to list the krb4 tickets -- there shouldn't be any ticket file.
+proc v4klist_none { testname } {
+    global KLIST
+    global tmppwd
+
+    # Double check that the ticket was destroyed.
+    spawn $KLIST -4
+    expect {
+	-re "Kerberos 4 ticket cache:\[ 	\]*(.+:)?$tmppwd/tkt.*klist: You have no tickets cached.*\r\n" {
+	    verbose "v4klist started"
+	    pass "$testname (output)"
+	}
+	timeout {
+	    fail "$testname (output)"
+	    # Skip the 'wait' below, if it's taking too long.
+	    untested "$testname (exit status)"
+	    return 0
+	}
+	eof {
+	    fail "$testname (output)"
+	}
+    }
+    # We can't use check_exit_status, because we expect an exit status
+    # of 1.
+    expect eof
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list (v4klist)"
+    if { [lindex $status_list 2] != 0 } {
+	fail "$testname (exit status)"
+	return 0
+    } else {
+	if { [lindex $status_list 3] != 1 } {
+	    fail "$testname (exit status)"
+	    return 0
+	} else {
+	    pass "$testname (exit status)"
+	}
+    }
+    return 1
+}
+
+# Set up a root shell using rlogin $hostname -l root.  This is used
+# when testing the daemons that must be run as root, such as telnetd
+# or rlogind.  This sets the global variables rlogin_spawn_id and
+# rlogin_pid.  Returns 1 on success, 0 on failure.
+#
+# This procedure will only succeed if the person running the test has
+# a valid ticket for a name listed in the /.klogin file.  Naturally,
+# Kerberos must already be installed on this machine.  It's a pain,
+# but I can't think of a better approach.
+
+if ![info exists can_get_root] { set can_get_root yes }
+
+proc setup_root_shell { testname } {
+    global BINSH
+    global ROOT_PROMPT
+    global KEY
+    global RLOGIN
+    global RLOGIN_FLAGS
+    global hostname
+    global rlogin_spawn_id
+    global rlogin_pid
+    global tmppwd
+    global env
+    global krb5_init_vars
+    global can_get_root
+
+    global timeout
+
+    if [string match $can_get_root no] {
+	note "$testname test requires ability to log in as root"
+	unsupported $testname
+	return 0
+    }
+
+    # Make sure we are using the original values of the environment
+    # variables.  This means that the caller must call
+    # setup_kerberos_env after calling this procedure.
+
+    # XXX fixme to deal with envstack
+    restore_kerberos_env
+
+    setup_runtime_env
+
+    set me [exec whoami]
+    if [string match root $me] {
+	return [setup_root_shell_noremote $testname]
+    }
+
+    if ![get_hostname] {
+	set can_get_root no
+	return 0
+    }
+
+    # If you have not installed Kerberos on your system, and you want
+    # to run these tests, you can do it if you are willing to put your
+    # root password in this file (this is not a very good idea, but
+    # it's safe enough if you disconnect from the network and remember
+    # to remove the password later).  Change the rlogin in the next
+    # line to be /usr/ucb/rlogin (or whatever is appropriate for your
+    # system).  Then change the lines after "word:" a few lines
+    # farther down to be
+    #    send "rootpassword\r"
+    #    exp_continue
+
+    eval spawn $RLOGIN $hostname -l root $RLOGIN_FLAGS
+    set rlogin_spawn_id $spawn_id
+    set rlogin_pid [exp_pid]
+    set old_timeout $timeout
+    set timeout 300
+    set got_refused 0
+
+    expect {
+	-re {connect to address [0-9a-fA-F.:]*: Connection refused} {
+	    note $expect_out(buffer)
+	    set got_refused 1
+	    exp_continue
+	}
+	-re "word:|erberos rlogin failed|ection refused|ection reset by peer|not authorized" {
+	    note "$testname test requires ability to rlogin as root"
+	    unsupported "$testname"
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+	"Cannot assign requested address" {
+	    note "$testname: rlogin as root 'cannot assign requested address'"
+	    unsupported "$testname"
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+	-re "usage: rlogin|illegal option -- x|invalid option -- x" {
+	    note "$testname: rlogin doesn't like command-line flags"
+	    unsupported "$testname"
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    perror "timeout from rlogin $hostname -l root"
+	    perror "If you have an unusual root prompt,"
+	    perror "try running with ROOT_PROMPT=\"regexp\""
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+	eof {
+	    if {$got_refused} {
+		# reported some errors, continued, and failed
+		note "$testname test requires ability to log in as root"
+		unsupported $testname
+	    } else {
+		# unknown problem?
+#		perror "eof from rlogin $hostname -l root"
+		note "eof (and unrecognized messages?) from rlogin $hostname -l root"
+		note "$testname test requires ability to log in as root"
+		unsupported $testname
+	    }
+	    stop_root_shell
+	    set timeout $old_timeout
+	    catch "expect_after"
+	    set can_get_root no
+	    return 0
+	}
+    }
+
+    expect_after {
+	timeout {
+	    perror "timeout from rlogin $hostname -l root"
+	    stop_root_shell
+	    set timeout $old_timeout
+	    catch "expect_after"
+	    set can_get_root no
+	    return 0
+	}
+	eof {
+	    perror "eof from rlogin $hostname -l root"
+	    stop_root_shell
+	    set timeout $old_timeout
+	    catch "expect_after"
+	    set can_get_root no
+	    return 0
+	}
+    }
+
+    # Make sure the root shell is using /bin/sh.
+    send "$BINSH\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Set up a shell variable tmppwd.  The callers use this to keep
+    # command line lengths down.  The command line length is important
+    # because we are feeding input to a shell via a pty.  On some
+    # systems a pty will only accept 255 characters.
+    send "tmppwd=$tmppwd\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Set up our krb5.conf
+    send "KRB5_CONFIG=$tmppwd/krb5.server.conf\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+    send "export KRB5_CONFIG\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # For all of our runtime environment variables - send them over...
+    foreach i $krb5_init_vars {
+	regexp "^(\[^=\]*)=(.*)" $i foo evar evalue
+	send "$evar=$env($evar)\r"
+	expect {
+		-re "$ROOT_PROMPT" { }
+        }
+
+        send "export $evar\r"
+        expect {
+		-re "$ROOT_PROMPT" { }
+        }
+    }
+
+    # Move over to the right directory.
+    set dir [pwd]
+    send "cd $dir\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+	"$dir:" {
+	    perror "root shell can not cd to $dir"
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+    }
+
+    expect_after
+    set timeout $old_timeout
+
+    return 1
+}
+
+proc setup_root_shell_noremote { testname } {
+    global BINSH
+    global ROOT_PROMPT
+    global KEY
+    global hostname
+    global rlogin_spawn_id
+    global rlogin_pid
+    global tmppwd
+    global env
+    global krb5_init_vars
+
+    eval spawn $BINSH
+    set rlogin_spawn_id $spawn_id
+    set rlogin_pid [exp_pid]
+
+    expect_after {
+	timeout {
+	    perror "timeout from root shell"
+	    stop_root_shell
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    perror "eof from root shell"
+	    stop_root_shell
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Set up a shell variable tmppwd.  The callers use this to keep
+    # command line lengths down.  The command line length is important
+    # because we are feeding input to a shell via a pty.  On some
+    # systems a pty will only accept 255 characters.
+    send "tmppwd=$tmppwd\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Set up our krb5.conf
+    send "KRB5_CONFIG=$tmppwd/krb5.server.conf\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+    send "export KRB5_CONFIG\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # For all of our runtime environment variables - send them over...
+    foreach i $krb5_init_vars {
+	regexp "^(\[^=\]*)=(.*)" $i foo evar evalue
+	send "$evar=$env($evar)\r"
+	expect {
+		-re "$ROOT_PROMPT" { }
+        }
+
+        send "export $evar\r"
+        expect {
+		-re "$ROOT_PROMPT" { }
+        }
+    }
+
+    # Move over to the right directory.
+    set dir [pwd]
+    send "cd $dir\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+	"$dir:" {
+	    perror "root shell can not cd to $dir"
+	    stop_root_shell
+	    return 0
+	}
+    }
+
+    expect_after
+
+    return 1
+}
+
+# Kill off a root shell started by setup_root_shell.
+
+proc stop_root_shell { } {
+    global rlogin_spawn_id
+    global rlogin_pid
+
+    catch "close -i $rlogin_spawn_id"
+    catch "exec kill $rlogin_pid"
+    sleep 1
+    catch "exec kill -9 $rlogin_pid"
+    catch "wait -i $rlogin_spawn_id"
+}
+
+# Check the date.  The string will be the output of date on this
+# system, and we must make sure that it is in the same timezone as the
+# output of date run a second time.  The first date will be run on an
+# rlogin or some such connection to the local system.  This is to test
+# to make sure that the TZ environment variable is handled correctly.
+# Returns 1 on sucess, 0 on failure.
+
+proc check_date { date } {
+    catch "exec date" ndate
+    set atz ""
+    set ntz ""
+    scan $date "%s %s %d %d:%d:%d %s %d" adow amon adom ahr amn asc atz ayr
+    scan $ndate "%s %s %d %d:%d:%d %s %d" ndow nmon ndom nhr nmn nsc ntz nyr
+    if { $atz != $ntz } {
+	verbose -log "date check failed: $atz != $ntz"
+	return 0
+    }
+    return 1
+}
+
+proc touch { file } {
+    set f [open $file "a"]
+    puts $f ""
+    close $f
+}
+
+# Implement this in tcl someday?
+proc tail1 { file } {
+    exec tail -1 $file
+}
+
+# setup_wrapper
+# Sets up a wraper script to set the runtime shared library environment 
+# variables and then executes a specific command. This is used to allow
+# a "rsh klist" or telnetd to execute login.krb5. 
+proc setup_wrapper { file command } {
+    global BINSH
+    global env
+    global krb5_init_vars
+
+    # We will start with a BINSH script
+    catch "exec rm -f $file"
+
+    set f [open $file "w" 0777]
+    puts $f "#!$BINSH"
+    puts $f "KRB5_CONFIG=$env(KRB5_CONFIG)"
+    puts $f "export KRB5_CONFIG"
+    foreach i $krb5_init_vars {
+	regexp "^(\[^=\]*)=(.*)" $i foo evar evalue
+	puts $f "$evar=$env($evar)"
+	puts $f "export $evar"
+    }
+    puts $f "exec $command"
+    close $f
+    
+    return 1
+}
+
+proc krb_exit { } {
+    stop_kerberos_daemons
+}
+
+# helpful sometimes for debugging the test suite
+proc spawn_xterm { } {
+    global env
+    foreach i {KDB5_UTIL KRB5KDC KADMIND KADMIN KADMIN_LOCAL KINIT KTUTIL KLIST RLOGIN RLOGIND FTP FTPD KPASSWD REALMNAME GSSCLIENT} {
+	global $i
+	if [info exists $i] { set env($i) [set $i] }
+    }
+    exec "xterm"
+}
diff --git a/mechglue/src/tests/dejagnu/krb-root/.Sanitize b/mechglue/src/tests/dejagnu/krb-root/.Sanitize
new file mode 100644
index 000000000..e03079694
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-root/.Sanitize
@@ -0,0 +1,34 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+ChangeLog
+rlogin.exp
+telnet.exp
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/dejagnu/krb-root/ChangeLog b/mechglue/src/tests/dejagnu/krb-root/ChangeLog
new file mode 100644
index 000000000..317764bcb
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-root/ChangeLog
@@ -0,0 +1,91 @@
+2005-01-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* rlogin.exp (start_rlogin_daemon): Use built-in sleep command.
+	* telnet.exp (start_telnet_daemon): Likewise.
+
+2004-11-15  Tom Yu  <tlyu@mit.edu>
+
+	* telnet.exp (telnet_test): Work around possible race condition
+	with client's resetting of terminal mode when returning from
+	interactive command mode.  Test whether requiring encryption
+	works.
+
+2004-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* rlogin.exp (start_rlogin_daemon, rlogin_test): Use portbase to
+	compute all port numbers.
+	* telnet.exp (start_telnet_daemon, telnet_test): Likewise.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* telnet.exp: Skip tests if no DES key types are enabled.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* rlogin.exp: Fix previous change.
+
+2002-07-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* rlogin.exp: Update expected "encrypting" message for encrypted
+	rlogin.
+
+Thu Aug 10 09:54:52 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* rlogin.exp: Change RLOGIN to KRLOGIN so we do not use the
+ 	incorrect binary as used for the root login in default.exp.
+
+Thu Nov 14 15:20:19 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* telnet.exp: telnet may output fqdn in upper-case
+
+Mon Nov 11 20:53:38 1996  Mark Eichin  <eichin@cygnus.com>
+	Tue Sep 17 18:30:57 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* rlogin.exp: In first rlogin test, drain last \r from rlogin
+	session to prevent rlogin from hanging in tcsetattr(TCSADRAIN)
+	call.
+
+Mon May  6 11:44:18 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* telnet.exp: Use a wrapper script for login.krb5 to setup shared
+		libraries properly. 
+
+Fri Mar 29 01:34:47 1996  Marc Horowitz  <marc@mit.edu>
+
+	* telnet.exp (start_telnet_daemon) use sh -c around telnetd
+	invocation to avoid having the rlogin die when the first telnetd
+	exits.
+	(telnet_test) If telnet finishes (prints connection closed), but
+	doesnt exit by an expect timeout, then kill the telnet so the
+	tests can go on.
+
+Fri Mar 29 01:09:14 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* rlogin.exp (rlogin_test): Make connection-closed patterns the
+ 	same, so the correct matching will happen when that message is
+ 	really expected.
+
+Thu Mar 28 18:17:31 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* rlogin.exp (rlogin_test), telnet.exp (telnet_test): Handle
+	failures from closed connections.
+
+	* telnet.exp (telnet_test): Move -- before hostname.
+
+Thu Mar 28 16:37:36 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* telnet.exp (telnet_test): use -- to end the getopt arguments.
+
+Tue Mar 19 10:03:01 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* telnet.exp: Put back in the encrypted telnet tests.
+
+Sun Mar  3 15:42:29 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rlogin.exp: Change to execute new program name and proper
+		arguments. 
+
+Fri Nov 10 21:15:28 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* telnet.exp: Comment out encrypted telnet tests.
+
diff --git a/mechglue/src/tests/dejagnu/krb-root/rlogin.exp b/mechglue/src/tests/dejagnu/krb-root/rlogin.exp
new file mode 100644
index 000000000..bc4056467
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-root/rlogin.exp
@@ -0,0 +1,320 @@
+# Kerberos rlogin test.
+# This is a DejaGnu test script.
+# This script tests Kerberos rlogin.
+# Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/src.
+
+if ![info exists KRLOGIN] {
+    set KRLOGIN [findfile $objdir/../../appl/bsd/rlogin]
+}
+
+if ![info exists KRLOGIND] {
+    set KRLOGIND [findfile $objdir/../../appl/bsd/klogind]
+}
+
+if ![info exists LOGINKRB5] {
+    set LOGINKRB5 [findfile $objdir/../../appl/bsd/login.krb5]
+}
+
+# Start up a root shell.
+if ![setup_root_shell rlogin] {
+    return
+}
+
+# Make sure .k5login is reasonable.
+if ![check_k5login rlogin] {
+    stop_root_shell
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    stop_root_shell
+    return
+}
+
+# A procedure to start up the rlogin daemon.
+
+proc start_rlogin_daemon { option } {
+    global REALMNAME
+    global KRLOGIND
+    global LOGINKRB5
+    global ROOT_PROMPT
+    global tmppwd
+    global hostname
+    global rlogin_spawn_id
+    global krlogind_pid
+    global portbase
+
+    # The -p argument tells it to accept a single connection, so we
+    # don't need to use inetd.  The 3543 is the port to listen at.
+    # Note that tmppwd here is a shell variable, which is set in
+    # setup_root_shell, not a TCL variable.  The sh -c is to workaround
+    # the broken controlling tty handling in hpux, and shouldn't hurt
+    # anything else.
+    send -i $rlogin_spawn_id "sh -c \"$KRLOGIND -k -c -D [expr 8 + $portbase] -S \$tmppwd/srvtab -M $REALMNAME -L $LOGINKRB5 $option\" &\r"
+    expect {
+	-i $rlogin_spawn_id 
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+    send -i $rlogin_spawn_id "echo \$!\r"
+    expect {
+	-i $rlogin_spawn_id
+	-re "\[0-9\]+" {
+	    set krlogind_pid $expect_out(0,string)
+	    verbose "krlogind process ID is $krlogind_pid"
+	}
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+    expect {
+	-i $rlogin_spawn_id
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+
+    # Give the rlogin daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the rlogin daemon.
+
+proc stop_rlogin_daemon { } {
+    global krlogind_pid
+
+    if [info exists krlogind_pid] {
+	catch "exec kill $krlogind_pid"
+	unset krlogind_pid
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc rlogin_test { } {
+    global REALMNAME
+    global KRLOGIN
+    global BINSH
+    global SHELL_PROMPT
+    global KEY
+    global hostname
+    global hostname
+    global env
+    global portbase
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_kerberos_key host/$hostname 0] \
+        || ![setup_srvtab 0] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    # Start up the rlogin daemon.
+    start_rlogin_daemon -k
+
+    # Make an rlogin connection.
+    spawn $KRLOGIN $hostname -k $REALMNAME -D [expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	"onnection closed." {
+	    fail "$testname (connection closed)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "rlogin"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Switch to /bin/sh to try to avoid confusion from the shell
+    # prompt.
+    set testname "shell"
+    send "$BINSH\r"
+    expect -re "$SHELL_PROMPT"
+
+    set testname "date"
+    send "date\r"
+    expect "date"
+    expect {
+	-re "\[A-Za-z0-9 :\]+\[\r\n\]+" {
+	    if [check_date $expect_out(0,string)] {
+		pass "date"
+	    } else {
+		fail "date"
+	    }
+	}
+    }
+    expect -re "$SHELL_PROMPT"
+
+    set testname "exit"
+    send "exit\r"
+    expect -re "$SHELL_PROMPT"
+    send "exit\r"
+    expect {
+	"onnection closed." {
+	    pass $testname
+	}
+    }
+    # This last expect seems useless, but without it the rlogin process
+    # sometimes hangs on HP-UX, in a tcsetattr call with TCSADRAIN.
+    expect {
+        "\r" { }
+    }
+
+    expect_after
+
+    if [check_exit_status "exit status"] {
+	pass "exit status"
+    }
+
+    # The rlogin daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_rlogin_daemon
+
+    # Try an encrypted connection.
+    start_rlogin_daemon -e
+    spawn $KRLOGIN $hostname -x -k $REALMNAME -D [expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	"onnection closed" {
+	    fail "$testname (connection closed)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "encrypted rlogin"
+    expect -re "encrypting .* transmissions"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Switch to /bin/sh to try to avoid confusion from the shell
+    # prompt.
+    set testname "shell"
+    send "$BINSH\r"
+    expect -re "$SHELL_PROMPT"
+
+    # Make sure the encryption is not destroying the text.
+    set testname "echo"
+    send "echo hello\r"
+    expect "echo hello"
+    expect "hello"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Send some characters which might cause an interrupt, and then
+    # make sure we can still talk to the shell.
+    set testname "interrupt characters"
+    send "\003\177\034\r"
+    expect -re "$SHELL_PROMPT"
+    send "echo hello\r"
+    expect "echo hello"
+    expect "hello"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    set testname "~."
+    send "~."
+    expect {
+	"Closed connection.\r" {
+	    pass $testname
+	}
+	"onnection closed" {
+	    pass $testname
+	}
+    }
+
+    expect_after
+
+    if [check_exit_status "exit status"] {
+	pass "exit status"
+    }
+
+    # The rlogin daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_rlogin_daemon
+}
+
+# Run the test.  Logging in sometimes takes a while, so increase the
+# timeout.
+set oldtimeout $timeout
+set timeout 60
+set status [catch rlogin_test msg]
+set timeout $oldtimeout
+
+# Shut down the kerberos daemons, the rlogin daemon, and the root
+# process.
+stop_kerberos_daemons
+
+stop_rlogin_daemon
+
+stop_root_shell
+
+if { $status != 0 } {
+    send_error "ERROR: error in rlogin.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
diff --git a/mechglue/src/tests/dejagnu/krb-root/telnet.exp b/mechglue/src/tests/dejagnu/krb-root/telnet.exp
new file mode 100644
index 000000000..c283d6150
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-root/telnet.exp
@@ -0,0 +1,449 @@
+# Kerberos telnet test.
+# This is a DejaGnu test script.
+# This script tests Kerberos telnet.
+# Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/src.
+
+if ![info exists TELNET] {
+    set TELNET [findfile $objdir/../../appl/telnet/telnet/telnet]
+}
+
+if ![info exists TELNETD] {
+    set TELNETD [findfile $objdir/../../appl/telnet/telnetd/telnetd]
+}
+
+if ![info exists LOGINKRB5] {
+    set LOGINKRB5 [findfile $objdir/../../appl/bsd/login.krb5]
+}
+
+if ![regexp des- $supported_enctypes] {
+    # Telnet needs a DES enctype.
+    verbose "Skipping telnet tests for lack of DES support."
+    return
+}
+
+# Remove old wrapper script
+    catch "exec rm -f $tmppwd/login.wrap"
+
+# Start up a root shell.
+if ![setup_root_shell telnet] {
+    return
+}
+
+# Make sure .k5login is reasonable.
+if ![check_k5login rlogin] {
+    stop_root_shell
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    stop_root_shell
+    return
+}
+
+# A procedure to start up the telnet daemon.
+
+proc start_telnet_daemon { args } {
+    global REALMNAME
+    global TELNETD
+    global LOGINKRB5
+    global ROOT_PROMPT
+    global tmppwd
+    global hostname
+    global rlogin_spawn_id
+    global telnetd_pid
+    global portbase
+
+    # Setup the shared library wrapper for login.krb5
+    if ![file exists $tmppwd/login.wrap] {
+	    setup_wrapper $tmppwd/login.wrap "$LOGINKRB5 $*"
+    }
+
+    # The -debug argument tells it to accept a single connection, so
+    # we don't need to use inetd.  The portbase+8 is the port to listen at.
+    # Note that tmppwd here is a shell variable, which is set in
+    # setup_root_shell, not a TCL variable.
+    send -i $rlogin_spawn_id "sh -c \"$TELNETD $args -debug -t \$tmppwd/srvtab -R $REALMNAME -L $tmppwd/login.wrap -X KERBEROS_V4 [expr 8 + $portbase]\" &\r"
+    expect {
+	-i $rlogin_spawn_id 
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+    send -i $rlogin_spawn_id "echo \$!\r"
+    expect {
+	-i $rlogin_spawn_id
+	-re "\[0-9\]+" {
+	    set telnetd_pid $expect_out(0,string)
+	    verbose "telnetd process ID is $telnetd_pid"
+	}
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+    expect {
+	-i $rlogin_spawn_id
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+
+    # Give the telnet daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the telnet daemon.
+
+proc stop_telnet_daemon { } {
+    global telnetd_pid
+
+    if [info exists telnetd_pid] {
+	catch "exec kill $telnetd_pid"
+	unset telnetd_pid
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc telnet_test { } {
+    global REALMNAME
+    global TELNET
+    global BINSH
+    global SHELL_PROMPT
+    global KEY
+    global hostname
+    global localhostname
+    global env
+    global portbase
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_kerberos_key host/$hostname 0] \
+        || ![setup_srvtab 0] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    # Start up the telnet daemon.
+    start_telnet_daemon
+
+    # Start up our telnet connection.  We first try it without
+    # authentication, so the daemon should prompt for a login.
+    spawn $TELNET -- $hostname -[expr 8 + $portbase]
+    set telnet_pid [exp_pid]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "simple telnet"
+    expect {
+	"ogin: " {
+	    pass $testname
+	}
+    }
+
+    # Move back to telnet command mode and make sure it seems
+    # reasonable.
+    set testname "telnet command mode"
+    send "\035"
+    expect {
+	"telnet> " {
+	    pass $testname
+	}
+    }
+
+    set testname "telnet status"
+    send "status\r"
+    # use -nocase because telnet may output the fqdn in upper-case;
+    # however, -nocase requires the whole pattern to be in lower case
+    expect {
+	-nocase -re "connected to $localhostname.*operating in single character mode.*catching signals locally.*remote character echo.*flow control.*escape character is '.\]'" {
+	    pass $testname
+	}
+    }
+
+    set testname "back to command mode"
+
+    # For some reason, the telnet client doesn't necessarily reset the
+    # terminal mode back to raw after exiting command mode.
+    # Kick it somewhat by sending a CR.
+    send "\r"
+    expect "ogin: "
+
+    send "\035"
+    expect {
+	"telnet> " {
+	    pass $testname
+	}
+    }
+
+    set testname "quit"
+    send "quit\r"
+    expect {
+	"Connection closed.\r" {
+	    pass $testname
+	}
+    }
+
+    expect_after
+
+# on hpux 10.x, the child telnet will hang in an ioctl().  This will
+# wait a while for an EOF, and kill the process if it doesn't exit by
+# itself.  The hang doesn't happen when telnet is run at the shell.
+
+    expect {
+	eof { }
+	timeout {
+	    stop_telnet_daemon
+	}
+    }
+
+    if ![check_exit_status "exit status"] {
+	return
+    }
+
+    pass "exit status"
+
+    # The telnet daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_telnet_daemon
+
+    # Try an authenticated connection.
+    start_telnet_daemon
+    spawn $TELNET -a -k $REALMNAME -- $hostname -[expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	"Connection closed by foreign host.\r" {
+	    fail "$testname (connection closed)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "authenticated telnet"
+    expect "Kerberos V5 accepts you"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Switch to /bin/sh to try to avoid confusion from the shell
+    # prompt.
+    set testname "shell"
+    send "$BINSH\r"
+    expect -re "$SHELL_PROMPT"
+
+    set testname "date"
+    send "date\r"
+    expect "date"
+    expect {
+	-re "\[A-Za-z0-9 :\]+\[\r\n\]+" {
+	    if [check_date $expect_out(0,string)] {
+		pass "date"
+	    } else {
+		fail "date"
+	    }
+	}
+    }
+    expect -re "$SHELL_PROMPT"
+
+    set testname "exit"
+    send "exit\r"
+    expect -re "$SHELL_PROMPT"
+    send "exit\r"
+    expect {
+	"Connection closed by foreign host.\r" {
+	    pass $testname
+	}
+    }
+
+    expect_after
+    catch "expect eof"
+
+    # We can't use check_exit_status, because we expect an exit status
+    # of 1.
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list (klist)"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 1 } {
+	send_log "exit status: $status_list\n"
+	verbose "exit status: $status_list"
+	fail "exit status"
+    } else {
+	pass "exit status"
+    }
+
+    # The telnet daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_telnet_daemon
+
+    # Try an authenticated encrypted connection.
+    start_telnet_daemon
+    spawn $TELNET -a -x -k $REALMNAME -- $hostname -[expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail $testname
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail $testname
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "encrypted telnet"
+    expect "Kerberos V5 accepts you"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Make sure the encryption is not destroying the text.
+    set testname "echo"
+    send "echo hello\r"
+    expect "echo hello"
+    expect "hello"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Move back to telnet command mode and check the encryption status.
+    set testname "encryption status"
+    send "\035"
+    expect "telnet> "
+    send "status\r"
+    expect {
+	-re "Currently encrypting output with DES_CFB64.*Currently decrypting input with DES_CFB64" {
+	    pass $testname
+	}
+    }
+
+    set testname "exit status"
+    send "exit\r"
+    expect "Connection closed by foreign host.\r"
+
+    expect_after
+    catch "expect eof"
+
+    # We can't use check_exit_status, because we expect an exit status
+    # of 1.
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list (klist)"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 1 } {
+	send_log "exit status: $status_list\n"
+	verbose "exit status: $status_list"
+	fail "exit status"
+    } else {
+	pass "exit status"
+    }
+
+    # The telnet daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_telnet_daemon
+
+    set testname "reject unencrypted telnet"
+    # Check rejection of unencrypted client when encryption is required
+    start_telnet_daemon -e
+
+    # unencrypted, unauthenticated
+    spawn $TELNET -- $hostname -[expr 8 + $portbase]
+    expect_after {
+	timeout {
+	    fail $testname
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail $testname
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    expect {
+	-re "Unencrypted connection refused.*\n" {
+	    pass $testname
+	}
+    }
+    catch "expect_after"
+    catch "expect eof"
+    catch wait
+
+    # The telnet daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_telnet_daemon
+}
+
+# Run the test.  Logging in sometimes takes a while, so increase the
+# timeout.
+set oldtimeout $timeout
+set timeout 60
+set status [catch telnet_test msg]
+set timeout $oldtimeout
+
+# Shut down the kerberos daemons, the telnet daemon, and the rlogin
+# process.
+stop_kerberos_daemons
+
+stop_telnet_daemon
+
+stop_root_shell
+
+if { $status != 0 } {
+    send_error "ERROR: error in telnet.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/.Sanitize b/mechglue/src/tests/dejagnu/krb-standalone/.Sanitize
new file mode 100644
index 000000000..a9df2c392
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/.Sanitize
@@ -0,0 +1,39 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+ChangeLog
+gssapi.exp
+gssftp.exp
+kadmin.exp
+rcp.exp
+rsh.exp
+sample.exp
+standalone.exp
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/ChangeLog b/mechglue/src/tests/dejagnu/krb-standalone/ChangeLog
new file mode 100644
index 000000000..9168ac4c9
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/ChangeLog
@@ -0,0 +1,467 @@
+2005-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* v4gssftp.exp: Identify file correctly for top-level error
+	messages.
+
+2005-02-10  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.exp (kadmin_add_rnd): Add "flags" arg, defaulting to
+	empty string.
+	(kadmin_test): Add test for fallback to kadmin/admin if
+	kadmin/fqdn is missing.
+
+2005-01-14  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.exp (kadmin_list): Check for communication failure.
+	(kadmin_test): Create a large number of principals, then attempt
+	to list, in order to check for fixed-size buffer problems in
+	RPCSEC_GSS.
+
+2005-01-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssftp.exp (start_ftp_daemon): Use built-in sleep command.
+	* rcp.exp (start_rsh_daemon): Likewise.
+	* rsh.exp (start_rsh_daemon): Likewise.
+	* sample.exp (start_sserver_daemon): Likewise.
+	* v4gssftp.exp (start_ftp_daemon): Likewise.
+	* v4krb524d.exp (start_k524_daemon): Likewise.
+
+2004-12-20  Tom Yu  <tlyu@mit.edu>
+
+	* pwhist.exp: New file.  Perform some sanity checking on password
+	history mechanism, including erroneous loss of history when
+	growing the history array.  Also tries to trigger some known
+	buffer overflows and memory leaks.
+
+2004-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi.exp (run_client, doit): Use portbase to compute all port
+	numbers.
+	* gssftp.exp (start_ftp_daemon, ftp_test): Likewise.
+	* rcp.exp (start_rsh_daemon, rcp_one_test): Likewise.
+	* rsh.exp (start_rsh_daemon, rsh_test): Likewise.
+	* sample.exp (start_sserver_daemon, test_sclient): Likewise.
+	* v4gssftp.exp (start_ftp_daemon, v4ftp_test): Likewise.
+	* v4krb524d.exp (start_k524_daemon): Likewise.
+
+2004-02-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* rcp.exp (stop_rsh_daemon): Check for any output before eof,
+	causing any such info to be dumped into the debug log.
+	* rsh.exp (stop_rsh_daemon): Likewise.
+
+	* gssapi.exp (doit): Fix typo in log message.
+
+2004-02-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssapi.exp (doit): Run server with additional options to export
+	and re-import the GSSAPI context, and log info to a file in
+	tmpdir.
+
+2003-12-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* gssftp.exp (ftp_test): Look for "GSSAPI authentication failed"
+	error.
+
+2003-05-21  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.exp: Be slightly more lenient about matching password
+	prompts.
+
+2003-03-26  Tom Yu  <tlyu@mit.edu>
+
+	* v4gssftp.exp (v4ftp_test): Return early if $des3_krbtgt set.
+
+	* v4krb524d.exp (doit): Return early if $des3_krbtgt set.
+
+	* v4standalone.exp (check_and_destroy_v4_tix): Return early if
+	$des3_krbtgt set.
+
+2003-01-01  Ezra Peisach  <epeisach@bu.edu>
+
+	* standalone.exp: Only run the keytab to srvtab tests if kerberos 4
+	support is compiled into the source tree.
+
+2002-09-30  Tom Yu  <tlyu@mit.edu>
+
+	* rsh.exp (rsh_test): Explicitly call stop_rsh_daemon upon pass
+	for "encrypted rsh" test, to avoid zombies.
+
+2002-04-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* v4gssftp.exp (v4ftp_test): Update checked messages for change of
+	"credentials cache file" to "credentials cache" in error message
+	table.
+
+2002-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* standalone.exp: Move setting of KLIST and KDESTROY into
+	default.exp.
+	(doit): Call do_klist instead of implementing it here.  Add a new
+	principal to the database, and test getting tickets using a
+	keytab, with multiple kvnos starting at 253 and going up past
+	256; if first supported enctype supports v4, convert the keytab to
+	a srvtab and try getting tickets using it too.  Verify that
+	kadmin.local can read the high kvno correctly.
+
+	* v4standalone.exp: Move setting of KLIST and KDESTROY into
+	default.exp.  Print correct filename in top-level error message.
+	(check_and_destroy_v4_tix): New proc.
+	(doit): Call v4kinit and check_and_destroy_v4_tix.
+
+	* gssftp.exp (ftp_test): Bump kvno past 256, with multiple entries
+	in the keytab, before running test.
+
+2001-11-06  Tom Yu  <tlyu@mit.edu>
+
+        * rsh.exp: Fix date-grabbing regexp to deal with older versions of
+	expect/tcl that have limited regexp capabilities.
+
+12001-11-02  Tom Yu  <tlyu@mit.edu>
+
+	* rsh.exp: Fix date grabbing code so we don't try to parse the
+	timezone-less date out of of a syslog message.  expect eof in
+	places to drain pty buffers and avoid deadlock.
+
+2001-11-02  Tom Yu  <tlyu@mit.edu>
+
+	* v4gssftp.exp: Calling send_error from within a dejagnu test is
+	wrong.  So is calling exit.  Fix to not do these things.  Expect
+	eof rather than "\r" so as to drain pty buffers and avoid
+	deadlock.
+
+2001-11-02  Tom Yu  <tlyu@mit.edu>
+
+	* gssftp.exp: Calling send_error from within a dejagnu test is
+	wrong.  So is calling exit.  Fix to not do these things.  Expect
+	eof rather than "\r" so as to drain pty buffers and avoid
+	deadlock.
+
+2001-10-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* rcp.exp, rsh_exp (stop_rsh_daemon): Do not close a process and
+	then look for eof. Some versions of expect go through a full
+	timeout in this scenario and others return immediately. New order:
+	kill process, expect eof, close, and then wait.
+
+2001-10-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* rsh.exp (rsh_test): Add stop_rsh_daemon before invoking
+	start_rsh_daemon again to prevent running out of ptys.
+
+2001-10-24  Mitchell Berger  <mitchb@mit.edu>
+
+	* kadmin.exp: Corrected a couple of unimportant typos.  Added procedures
+	kadmin_addpol, kadmin_delpol, kadmin_listpols, kadmin_modpol, and
+	kadmin_showpol, which provide the tools with which to perform policy
+	tests.  Added some basic policy operations to the tests of basic
+	kadmin functions.  Added a test case to exercise the kadmind crash
+	that used to occur when the history number of a policy was decreased.
+
+2001-10-24  Tom Yu  <tlyu@mit.edu>
+
+	* rcp.exp (stop_rsh_daemon): Call "expect eof" to drain pty buffer
+	and avoid deadlock.
+
+	* rsh.exp (stop_rsh_daemon, rsh_test): Call "expect eof" to drain
+	pty buffer and avoid deadlock.
+
+2001-07-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* v4gssftp.exp, gssftp.exp: Test transfering a file > 1MB to
+ 	exercise PBSZ failure.
+
+2001-06-22  Tom Yu  <tlyu@mit.edu>
+
+	* gssftp.exp: Use $tmppwd rather than hardcoding tmpdir.
+
+	* kadmin.exp: Use $tmppwd rather than hardcoding tmpdir.
+
+	* rcp.exp: Use $tmppwd rather than hardcoding tmpdir.
+
+	* rsh.exp: Rearrange ordering of environment setup slightly.
+
+	* standalone.exp: Use $KLIST -5 -e so as to better debug enctype
+	problems.
+
+	* v4gssftp.exp: Do check_klogin as well as check_k5login.  Use
+	$tmppwd rather than hardcoding tmpdir.
+
+2001-06-17  Ezra Peisach  <epeisach@mit.edu>
+
+	* v4krb524d.exp: New tests for the krb524d and k524init programs. 
+
+2001-06-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* v4gssftp.exp: During test, set KRB5CCNAME to a non-existant
+	cache. Restore at end to previous setting. This prevents failures
+	caused when the krb5 cache contains valid information - as in the
+	case of this test being run immediately after the gssftp.exp test.
+
+2001-06-08  Mitchell Berger  <mitchb@mit.edu>
+
+	* gssftp.exp: Invocation of ftpd changed to use -U /dev/null and
+	-a so that the test may successfully be run by root without failing
+	(i.e. root is granted ftp access) and without opening the running
+	ftpd to a password attack (i.e. authorization is required).
+	Check for successful login messages added.
+
+	* v4gssftp.exp: Same changes.
+
+2001-06-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* v4gssftp.exp: Allow for "decrypt integrity check failed" error
+	minor code from GSSAPI as well.
+
+2001-04-26  Tom Yu  <tlyu@mit.edu>
+
+	* v4gssftp.exp: Allow for "no credentials cache found" error minor
+	code from GSSAPI.
+
+2000-11-08  Tom Yu  <tlyu@mit.edu>
+
+	* v4gssftp.exp: Fix to handle some cases of krb4 failure prior to
+	timing out.
+
+Tue Aug 22 11:43:14 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* v4gssftp.exp: New tests for the krb4 compatible interface to gssftp. 
+
+2000-08-08  Ezra Peisach  <epeisach@engrailed.mit.edu>
+
+	* v4standalone.exp: New set of tests for basic V4 functionality.
+
+2000-07-04  Tom Yu  <tlyu@mit.edu>
+
+	* rsh.exp: Drain buffers on klist test to avoid wedging rsh on
+	exit under HP/UX.
+
+	* gssapi.exp: Rework significantly to deal with HP/UX lossage that
+	probably resulted from when either the client or the server wound
+	up blocking on tty output.  Abstract things a little more.  Remove
+	dead duplicate code that used to deal with "-v2".  Should figure
+	out why the "-v2" stuff disappeared mysteriously.
+
+2000-02-07  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.exp: Use $KDESTROY -5 to deal with changed behavior.
+
+2000-02-06  Tom Yu  <tlyu@mit.edu>
+
+	* standalone.exp: Use $KLIST -5 and $KDESTROY -5 to deal with
+	changed behavior in these programs.  Wait for eof in some cases to
+	avoid hanging.
+
+	* rsh.exp: Wait for eof to prevent hanging.
+
+	* gssapi.exp: Use $KINIT -5 to deal with new kinit behavior.
+
+Fri Nov  6 10:05:31 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* gssftp.exp: Changes to deal with new text messages in ftp/ftpd.
+
+Fri Jan 30 23:49:54 1998  Tom Yu  <tlyu@mit.edu>
+
+	* kadmin.exp: Fix to deal with new kpasswd program.
+
+Sun Nov  9 10:07:07 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* gssftp.exp: Replace "else if" with "elseif" as expect 5.25
+ 	requires it. [krb5-misc/487]
+
+Mon Nov 11 20:54:37 1996  Mark Eichin  <eichin@cygnus.com>
+	Tue Sep 17 19:19:56 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* gssapi.exp (doit): Add more info to first set of "gssclient3"
+	failure messages.  Drain client-side output in gssclient3 tests
+	also, to prevent hanging on HP-UX.
+
+Wed Nov  6 20:31:52 1996  Tom Yu  <tlyu@mit.edu>
+
+	* gssftp.exp: Check for "foo: No such file or directory" in
+	addition to "foo not found".
+
+Mon Oct 14 08:05:11 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gssftp.exp: Test ls and nlist commands. [krb5-appl/108]
+
+Wed Aug 14 20:27:36 1996  Tom Yu  <tlyu@mit.edu>
+
+	* gssftp.exp: Do case insensitive match in case hostname doesn't
+		get downcased.
+
+Mon Aug 12 22:58:09 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kadmin.exp: Rewrite using kadmin.local instead of kdb5_edit.
+
+Tue Aug  6 11:50:14 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* kadmin.exp: Fix to specify "2500 seconds" explictly to avoid
+		getting negative maxlife.
+
+Mon Jul 29 11:30:24 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kadmin.exp: Added back in. Rewritten to use new admin system.
+
+Tue Jul 23 23:40:05 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* kadmin.exp: removed, since it was for the old admin server.
+
+Mon Jul 22 04:19:46 1996  Marc Horowitz  <marc@mit.edu>
+
+	* gssftp.exp (ftp_test): check for the banner with -nocase, since
+ 	hostnames are case insensitive.
+
+Fri Jul 19 19:56:26 1996  Marc Horowitz  <marc@mit.edu>
+
+	* gssapi.exp: port to changes in gss-sample, most importantly,
+ 	output format changes and the removal of the -v2 flag.
+
+Mon May  6 08:05:33 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rcp.exp: Use a wrapper script to set up the remote rcp as
+		started from kshd. 
+
+	* rsh.exp: Setup a wrapper script in executing klist in the remote
+		shell so that environment variables are properly set.
+
+	* kadmin.exp: (kpasswd_cpw): After giving new password, wait for
+		the newline or we hang waiting for the process to finish. 
+
+Fri May  3 21:44:24 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	Fri Mar 29 15:05:30 1996  Chris Provenzano  <proven@cygnus.com>
+
+	* rsh.exp: Add tests for ticket forwarding.
+
+	Thu Mar 28 19:30:53 1996  Marc Horowitz  <marc@mit.edu>
+
+	* kadmin.exp and gssapi.exp: Fix syntax of expect_after blocks.
+  	The -i $foo must be inside the {, and the { must be by itself at
+ 	the end of the line.
+	* gssftp.exp (start_ftp_daemon): use krb5.conf, not krb.conf
+
+	Thu Mar 28 17:32:47 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* gssftp.exp (ftp_test): Explicitly select binary mode.
+
+	Wed Mar 27 22:45:53 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* kadmin.exp: Don't look at output from kadmind to drain it; that
+	problem is handled elsewhere now.
+
+	Thu Mar 14 14:57:19 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kadmin.exp (kadmin_delete, kamind_add, kadmin_add_rnd,
+	kadmin_examine, kadmin_cpw, kadmin_cpw_rnd, kadmin_modify,
+	kadmin_rename, kadmin_list, kadmin_extract, kadmin_extractv4):
+	check for "lost KDC" as well.
+
+	Sun Feb 18 00:56:52 1996  Mark W. Eichin  <eichin@cygnus.com>
+
+	* kadmin.exp (kadmin_show): extend regexp to match current kadmin
+	interface.
+	(kadmin_add): match more of extended output (tentative change,
+	should be expanded later to actually check the values.)
+
+Wed Apr 17 17:53:51 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gssftp.exp: Fix the expect string so that it doesn't assume that
+		the client is using its fully qualified domain name as its
+		local hostname.  We now check to make sure that FTP banner
+		contains $localhostname, plus optional characters (which
+		can be the domainname depending on the system.)
+
+Mon Apr  8 14:13:06 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rcp.exp: Invoke kshd with -L for every environment variable we
+		want passed to invoke rcp with...
+
+Fri Mar 15 15:09:17 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* gssftp.exp: Add dejagnu for GSS-API ftp.
+
+Sun Mar  3 14:35:27 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rcp.exp, rsh.exp: Change name of kshd to match current executable
+		name. Change calling arguments to match current usage.
+	
+
+Sat Jan 27 01:10:39 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* kadmin.exp: use a longer password for kadmin_modify test to meet
+	password quality constraints.
+
+Wed Dec 13 15:28:17 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* kadmin.exp: test that kadmin_modify doesn't corrupt key entries.
+
+Sat Oct  7 08:02:08 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* sample.exp: Make changes to deal with NetBSD expect. Similar to
+		the AIX fix in gssapi.exp
+
+Thu Aug 31 12:02:36 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gssapi.exp - Repeat tests with -v2 switch.
+
+Sat Aug 26 17:56:50 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* sample.exp: Add inetd test
+
+Thu Aug 24 18:48:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Thu Aug 3 11:57:28 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kadmin.exp - Gut expected string handling for kadmin5 until we
+		firm up a concrete output format that we can test for.  Remove
+		addv4 function test since it isn't supported in the same way.
+
+
+Mon Jul 17 15:27:34 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kadmin.exp - Remove parameters from command lines of admin utilities
+		because they're not needed anymore since we have the KDC
+		profile.  Also remove prompting for the master key since we
+		have full usage of the stash file.
+
+Fri Jun  9 23:45:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* kadmin.exp: Use the principal "krbtest/admin@KRBTEST.COM" for
+		kadmin.
+
+Mon Jun 5 16:10:15 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kadmin.exp - Change prompting order for kadmin ank and kadmin cpw.
+
+
+Thu Jun 1 14:50:02 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kadmin.exp: Change admin instance name to kadmin.
+
+
+Mon May 22 15:44:09 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* gssapi.exp	- Add dejagnu test for GSS-API client and server.
+
+
+Thu May 11 12:25:38 EDT 1995	Paul Park	(pjpark@mit.edu)
+	Add kadmin.exp for kadmin tests.
+
+Wed May 10 17:00:01 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* .Sanitize (Things-to-keep): Add sample.exp
+
+	* sample.exp: Added sample client/server tests.
+
+Sat May  6 17:12:37 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* standalone.exp: klist test - added new line to prevent an OSF/1
+	        expect bug which would hang the klist process in waiting.
+
+Fri May  5 12:49:19 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* rcp.exp: (rcp_test()): Encrypted rcp are no longer expected to
+		fail. 
+
+Fri May 05 09:21:21 1995  Chris Provenzano (proven@mit.edu)
+
+	* rcp.exp (rcp_test()): Pass -c and -C args to encrypted rcp.
+		These are necessary for the test realm because krshd
+		nukes all environement variables before execing rcp.
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/gssapi.exp b/mechglue/src/tests/dejagnu/krb-standalone/gssapi.exp
new file mode 100644
index 000000000..793c0db19
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/gssapi.exp
@@ -0,0 +1,328 @@
+# Test for the GSS-API.
+# This is a DejaGnu test script.
+# This script tests that the GSS-API tester functions correctly.
+
+# This mostly just calls procedures in test/dejagnu/config/default.exp.
+
+if ![info exists KDESTROY] {
+    set KDESTROY [findfile $objdir/../../clients/kdestroy/kdestroy]
+}
+
+if ![info exists GSSCLIENT] {
+    set GSSCLIENT [findfile $objdir/../../appl/gss-sample/gss-client]
+}
+
+if ![info exists GSSSERVER] {
+    set GSSSERVER [findfile $objdir/../../appl/gss-sample/gss-server]
+}
+
+# Set up the Kerberos files and environment.
+if {![get_hostname] || ![setup_kerberos_files] || ![setup_kerberos_env]} {
+    return
+}
+
+# Initialize the Kerberos database.  The argument tells
+# setup_kerberos_db that it is being called from here.
+if ![setup_kerberos_db 0] {
+    return
+}
+
+#
+# Like kinit in default.exp, but allows us to specify a different ccache.
+#
+proc our_kinit { name pass ccache } {
+    global REALMNAME
+    global KINIT
+    global spawn_id
+
+    # Use kinit to get a ticket.
+    spawn $KINIT -5 -c $ccache $name@$REALMNAME
+    expect {
+	"Password for $name@$REALMNAME:" {
+	    verbose "kinit started"
+	}
+	timeout {
+	    fail "kinit"
+	    return 0
+	}
+	eof {
+	    fail "kinit"
+	    return 0
+	}
+    }
+    send "$pass\r"
+    # This last expect seems useless, but without it the test hangs on
+    # AIX.
+    expect {
+        "\r" { }
+    }
+    expect eof
+    if ![check_exit_status kinit] {
+	return 0
+    }
+
+    return 1
+}
+
+#
+# Destroys a particular ccache.
+#
+proc our_kdestroy { ccache } {
+    global KDESTROY
+    global spawn_id
+
+    spawn $KDESTROY -c $ccache
+    if ![check_exit_status "kdestroy"] {
+	return 0
+    }
+    return 1
+}
+
+#
+# Stops the gss-server.
+#
+proc stop_gss_server { } {
+    global gss_server_pid
+    global gss_server_spawn_id
+
+    if [info exists gss_server_pid] {
+	catch "close -i $gss_server_spawn_id"
+	catch "exec kill $gss_server_pid"
+	wait -i $gss_server_spawn_id
+	unset gss_server_pid
+    }
+}
+
+#
+# Restore environment variables possibly set.
+#
+proc gss_restore_env { } {
+    global env
+    global gss_save_ccname
+    global gss_save_ktname
+
+    catch "unset env(KRB5CCNAME)"
+    if [info exists gss_save_ccname] {
+	set env(KRB5CCNAME) $gss_save_ccname
+	unset gss_save_ccname
+    }
+    catch "unset env(KRB5_KTNAME)"
+    if [info exists gss_save_ktname] {
+	set env(KRB5_KTNAME) $gss_save_ktname
+	unset gss_save_ktname
+    }
+}
+
+proc run_client {test tkfile client} {
+    global env
+    global hostname
+    global GSSCLIENT
+    global spawn_id
+    global gss_server_spawn_id
+    global REALMNAME
+    global portbase
+
+    set env(KRB5CCNAME) $tkfile
+    verbose "KRB5CCNAME=$env(KRB5CCNAME)"
+    verbose "spawning gssclient, identity=$client"
+    spawn $GSSCLIENT -port [expr 8 + $portbase] $hostname gssservice@$hostname "message from $client"
+    set got_client 0
+    set got_server 0
+    expect_after {
+	-i $spawn_id
+	timeout {
+	    if {!$got_client} {
+		verbose -log "client timeout"
+		fail $test
+		catch "expect_after"
+		return
+	    }
+	}
+	eof {
+	    if {!$got_client} {
+		verbose -log "client eof"
+		fail $test
+		catch "expect_after"
+		return
+	    }
+	}
+	-i $gss_server_spawn_id
+	timeout {
+	    if {!$got_server} {
+		verbose -log "server timeout"
+		fail $test
+		catch "expect_after"
+		return
+	    }
+	}
+	eof {
+	    if {!$got_server} {
+		verbose -log "server eof"
+		fail $test
+		catch "expect_after"
+		return
+	    }
+	}
+    }
+    expect {
+	-i $gss_server_spawn_id
+	"Accepted connection: \"$client@$REALMNAME\"" exp_continue
+	"Received message: \"message from $client\"" {
+	    set got_server 1
+	    if {!$got_client} {
+		exp_continue
+	    }
+	}
+	-i $spawn_id
+	"Signature verified" {
+	    set got_client 1
+	    if {!$got_server} {
+		exp_continue
+	    }
+	}
+    }
+    catch "expect_after"
+    if ![check_exit_status $test] {
+	# check_exit_staus already calls fail for us
+	return
+    }
+    pass $test
+}
+
+proc doit { } {
+    global REALMNAME
+    global env
+    global KLIST
+    global KDESTROY
+    global KEY
+    global GSSTEST
+    global GSSSERVER
+    global GSSCLIENT
+    global hostname
+    global tmppwd
+    global spawn_id
+    global timeout
+    global gss_server_pid
+    global gss_server_spawn_id
+    global gss_save_ccname
+    global gss_save_ktname
+    global portbase
+
+    # Start up the kerberos and kadmind daemons.
+    if ![start_kerberos_daemons 0] {
+	perror "failed to start kerberos daemons"
+    }
+
+    # Use kadmin to add a key for us.
+    if ![add_kerberos_key gsstest0 0] {
+	perror "failed to set up gsstest0 key"
+    }
+
+    # Use kadmin to add a key for us.
+    if ![add_kerberos_key gsstest1 0] {
+	perror "failed to set up gsstest1 key"
+    }
+
+    # Use kadmin to add a key for us.
+    if ![add_kerberos_key gsstest2 0] {
+	perror "failed to set up gsstest2 key"
+    }
+
+    # Use kadmin to add a key for us.
+    if ![add_kerberos_key gsstest3 0] {
+	perror "failed to set up gsstest3 key"
+    }
+
+    # Use kadmin to add a service key for us.
+    if ![add_random_key gssservice/$hostname 0] {
+	perror "failed to set up gssservice/$hostname key"
+    }
+
+    # Use kdb5_edit to create a srvtab entry for gssservice
+    if ![setup_srvtab 0 gssservice] {
+	perror "failed to set up gssservice srvtab"
+    }
+
+    catch "exec rm -f $tmppwd/gss_tk_0 $tmppwd/gss_tk_1 $tmppwd/gss_tk_2 $tmppwd/gss_tk_3"
+
+    # Use kinit to get a ticket.
+    if ![our_kinit gsstest0 gsstest0$KEY $tmppwd/gss_tk_0] {
+	perror "failed to kinit gsstest0"
+    }
+
+    # Use kinit to get a ticket.
+    if ![our_kinit gsstest1 gsstest1$KEY $tmppwd/gss_tk_1] {
+	perror "failed to kinit gsstest1"
+    }
+
+    # Use kinit to get a ticket.
+    if ![our_kinit gsstest2 gsstest2$KEY $tmppwd/gss_tk_2] {
+	perror "failed to kinit gsstest2"
+    }
+
+    # Use kinit to get a ticket.
+    if ![our_kinit gsstest3 gsstest3$KEY $tmppwd/gss_tk_3] {
+	perror "failed to kinit gsstest3"
+    }
+
+    #
+    # Save settings of KRB5CCNAME and KRB5_KTNAME
+    #
+    if [info exists env(KRB5CCNAME)] {
+	set gss_save_ccname $env(KRB5CCNAME)
+    }
+    if [info exists env(KRB5_KTNAME)] {
+	set gss_save_ktname $env(KRB5_KTNAME)
+    }
+
+    #
+    # set KRB5CCNAME and KRB5_KTNAME
+    #
+    set env(KRB5_KTNAME) FILE:$tmppwd/srvtab
+    verbose "KRB5_KTNAME=$env(KRB5_KTNAME)"
+
+    # Now start the gss-server.
+    spawn $GSSSERVER -export -logfile $tmppwd/gss-server.log -verbose -port [expr 8 + $portbase] gssservice@$hostname
+    set gss_server_pid [exp_pid]
+    set gss_server_spawn_id $spawn_id
+    sleep 2
+
+    run_client gssclient0 $tmppwd/gss_tk_0 gssclient0
+    run_client gssclient1 $tmppwd/gss_tk_1 gssclient1
+    run_client gssclient2 $tmppwd/gss_tk_2 gssclient2
+    run_client gssclient3 $tmppwd/gss_tk_3 gssclient3
+
+    stop_gss_server
+    gss_restore_env
+
+    if ![our_kdestroy $tmppwd/gss_tk_0] {
+	perror "failed kdestroy gss_tk_0" 0
+    }
+
+    if ![our_kdestroy $tmppwd/gss_tk_1] {
+	perror "failed kdestroy gss_tk_1" 0
+    }
+
+    if ![our_kdestroy $tmppwd/gss_tk_2] {
+	perror "failed kdestroy gss_tk_2" 0
+    }
+
+    if ![our_kdestroy $tmppwd/gss_tk_3] {
+	perror "failed kdestroy gss_tk_3" 0
+    }
+
+    catch "exec rm -f $tmppwd/gss_tk_0 $tmppwd/gss_tk_1 $tmppwd/gss_tk_2 $tmppwd/gss_tk_3"
+
+    return
+}
+
+set status [catch doit msg]
+
+stop_gss_server
+gss_restore_env
+stop_kerberos_daemons
+
+if { $status != 0 } {
+    perror "error in gssapi.exp" 0
+    perror $msg 0
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/gssftp.exp b/mechglue/src/tests/dejagnu/krb-standalone/gssftp.exp
new file mode 100644
index 000000000..8d78c58c8
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/gssftp.exp
@@ -0,0 +1,453 @@
+# Kerberos ftp test.
+# This is a DejaGnu test script.
+# This script tests Kerberos ftp.
+# Originally written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
+# Modified bye Ezra Peisach for GSSAPI support.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/build/tests/dejagnu
+
+if ![info exists FTP] {
+    set FTP [findfile $objdir/../../appl/gssftp/ftp/ftp]
+}
+
+if ![info exists FTPD] {
+    set FTPD [findfile $objdir/../../appl/gssftp/ftpd/ftpd]
+}
+
+# Make sure .klogin is reasonable.
+if ![check_k5login ftp] {
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    return
+}
+
+# A procedure to start up the ftp daemon.
+
+proc start_ftp_daemon { } {
+    global FTPD
+    global tmppwd
+    global ftpd_spawn_id
+    global ftpd_pid
+    global portbase
+
+    # The -p argument tells it to accept a single connection, so we
+    # don't need to use inetd.  Portbase+8 is the port to listen at.
+    # We rely on KRB5_KTNAME being set to the proper keyfile as there is
+    # no way to cleanly set it with the gssapi API.
+    # The -U argument tells it to use an alternate ftpusers file (using
+    # /dev/null will allow root to login regardless of /etc/ftpusers).
+    # The -a argument requires authorization, to mitigate any
+    # vulnerability introduced by circumventing ftpusers.
+    spawn $FTPD -p [expr 8 + $portbase] -a -U /dev/null -r $tmppwd/krb5.conf
+    set ftpd_spawn_id $spawn_id
+    set ftpd_pid [exp_pid]
+
+    # Give the ftp daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the ftp daemon.
+
+proc stop_ftp_daemon { } {
+    global ftpd_spawn_id
+    global ftpd_pid
+
+    if [info exists ftpd_pid] {
+	catch "close -i $ftpd_spawn_id"
+	catch "exec kill $ftpd_pid"
+	catch "wait -i $ftpd_spawn_id"
+	unset ftpd_pid
+    }
+}
+
+# Create a file to use for ftp testing.
+set file [open $tmppwd/ftp-test w]
+puts $file "This file is used for ftp testing."
+close $file
+
+# Create a large file to use for ftp testing. File needs to be 
+# larger that 2^20 or 1MB for PBSZ testing.
+set file [open $tmppwd/bigftp-test w]
+puts $file "This file is used for ftp testing.\n"
+seek $file 1048576 current
+puts $file "This file is used for ftp testing."
+close $file
+
+
+# Test that a file was copied correctly.
+proc check_file { filename {bigfile 0}} {
+    if ![file exists $filename] {
+	verbose "$filename does not exist"
+	send_log "$filename does not exist\n"
+	return 0
+    }
+
+    set file [open $filename r]
+    if { [gets $file line] == -1 } {
+	verbose "$filename is empty"
+	send_log "$filename is empty\n"
+	close $file
+	return 0
+    }
+
+    if ![string match "This file is used for ftp testing." $line] {
+	verbose "$filename contains $line"
+	send_log "$filename contains $line\n"
+	close $file
+	return 0
+    }
+
+    if {$bigfile} {
+	# + 1 for the newline
+	seek $file 1048577 current
+	if { [gets $file line] == -1 } {
+	    verbose "$filename is truncated"
+	    send_log "$filename is truncated\n"
+	    close $file
+	    return 0
+	}
+
+	if ![string match "This file is used for ftp testing." $line] {
+	    verbose "$filename contains $line"
+	    send_log "$filename contains $line\n"
+	    close $file
+	    return 0
+	}
+    }
+
+    if { [gets $file line] != -1} {
+	verbose "$filename is too long ($line)"
+	send_log "$filename is too long ($line)\n"
+	close $file
+	return 0
+    }
+
+    close $file
+
+    return 1
+}
+
+#
+# Restore environment variables possibly set.
+#
+proc ftp_restore_env { } {
+    global env
+    global ftp_save_ktname
+
+    catch "unset env(KRB5_KTNAME)"
+    if [info exists ftp_save_ktname] {
+	set env(KRB5_KTNAME) $ftp_save_ktname
+	unset ftp_save_ktname
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc ftp_test { } {
+    global FTP
+    global KEY
+    global REALMNAME
+    global hostname
+    global localhostname
+    global env
+    global ftpd_spawn_id
+    global ftpd_pid
+    global spawn_id
+    global tmppwd
+    global ftp_save_ktname
+    global portbase
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_random_key ftp/$hostname 0] \
+	|| ![modify_principal ftp/$hostname -kvno 254] \
+        || ![setup_srvtab 0 ftp] \
+	|| ![xst $tmppwd/srvtab ftp/$hostname]
+	|| ![xst $tmppwd/srvtab ftp/$hostname]
+	|| ![xst $tmppwd/srvtab ftp/$hostname]
+	|| ![do_klist_kt $tmppwd/srvtab "gssftp keytab list"]
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    #
+    # Save settings of KRB5_KTNAME
+    #
+    if [info exists env(KRB5_KTNAME)] {
+	set ftp_save_ktname $env(KRB5_KTNAME)
+    }
+
+    #
+    # set KRB5_KTNAME
+    #
+    set env(KRB5_KTNAME) FILE:$tmppwd/srvtab
+    verbose "KRB5_KTNAME=$env(KRB5_KTNAME)"
+
+    # Start the ftp daemon.
+    start_ftp_daemon
+
+    # Make an ftp client connection to it.
+    spawn $FTP $hostname [expr 8 + $portbase]
+
+    expect_after {
+	"GSSAPI authentication failed" {
+	    fail "$testname (auth failed)"
+	    catch "expect_after"
+	    return
+	}
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "ftp connection"
+    expect -nocase "connected to $hostname"
+    expect -nocase -re "$localhostname.*ftp server .version \[0-9.\]*. ready."
+    expect -re "Using authentication type GSSAPI; ADAT must follow"
+    expect "GSSAPI accepted as authentication type"
+    expect {
+	"GSSAPI authentication succeeded" { pass "ftp authentication" }
+	eof	{ fail "ftp authentication" ; catch "expect_after" ; return }
+    }
+    expect -nocase "name ($hostname:$env(USER)): "
+    send "$env(USER)\r"
+    expect "GSSAPI user $env(USER)@$REALMNAME is authorized as $env(USER)"
+    expect "Remote system type is UNIX."
+    expect "Using binary mode to transfer files."
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "binary"
+    send "binary\r"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "status"
+    send "status\r"
+    expect -nocase "connected to $hostname."
+    expect "Authentication type: GSSAPI"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "ls"
+    send "ls $tmppwd/ftp-test\r"
+    expect -re "Opening ASCII mode data connection for .*ls."
+    expect -re ".* $tmppwd/ftp-test"
+    expect "ftp> " {
+	pass $testname
+    } 
+
+    set testname "nlist"
+    send "nlist $tmppwd/ftp-test\r"
+    expect -re "Opening ASCII mode data connection for file list."
+    expect -re "$tmppwd/ftp-test"
+    expect -re ".* Transfer complete."
+    expect "ftp> " {
+	pass $testname
+    } 
+
+    set testname "ls missing"
+    send "ls $tmppwd/ftp-testmiss\r"
+    expect -re "Opening ASCII mode data connection for .*ls."
+    expect {
+	-re "$tmppwd/ftp-testmiss not found" {}
+	-re "$tmppwd/ftp-testmiss: No such file or directory"
+    }
+    expect "ftp> " {
+	pass $testname
+    } 
+
+
+    set testname "get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get $tmppwd/ftp-test $tmppwd/copy\r"
+    expect "Opening BINARY mode data connection for $tmppwd/ftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "put"
+    catch "exec rm -f $tmppwd/copy"
+    send "put $tmppwd/ftp-test $tmppwd/copy\r"
+    expect "Opening BINARY mode data connection for $tmppwd/copy"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes sent in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "cd"
+    send "cd $tmppwd\r"
+    expect "CWD command successful."
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "lcd"
+    send "lcd $tmppwd\r"
+    expect "Local directory now $tmppwd"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "local get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get ftp-test copy\r"
+    expect "Opening BINARY mode data connection for ftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "big local get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get bigftp-test copy\r"
+    expect "Opening BINARY mode data connection for bigftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy 1] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "start encryption"
+    send "private\r"
+    expect "Data channel protection level set to private"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "status"
+    send "status\r"
+    expect "Protection Level: private"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "encrypted get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get ftp-test copy\r"
+    expect "Opening BINARY mode data connection for ftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "big encrypted get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get bigftp-test copy\r"
+    expect "Opening BINARY mode data connection for bigftp-test"
+    expect {
+	-timeout 300
+	"Transfer complete" {}
+	-re "Length .* of PROT buffer > PBSZ" {
+	    fail "$testname (PBSZ)"
+	    return 0
+	}
+    }
+    expect -re "\[0-9\]+ bytes received in \[0-9.e+-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy 1] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+    
+    set testname "close"
+    send "close\r"
+    expect "Goodbye."
+    expect "ftp> "
+    set status_list [wait -i $ftpd_spawn_id]
+    verbose "wait -i $ftpd_spawn_id returned $status_list ($testname)"
+    catch "close -i $ftpd_spawn_id"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } {
+	send_log "exit status: $status_list\n"
+	verbose "exit status: $status_list"
+	fail $testname
+    } else {
+	pass $testname
+	unset ftpd_pid
+    }
+
+    set testname "quit"
+    send "quit\r"
+    expect_after
+    expect eof
+    if [check_exit_status $testname] {
+	pass $testname
+    }
+}
+
+# The ftp client will look in $HOME/.netrc for the user name to use.
+# To avoid confusing the testsuite, point $HOME at a directory where
+# we know there is no .netrc file.
+if [info exists env(HOME)] {
+    set home $env(HOME)
+} elseif [info exists home] {
+    unset home
+}
+set env(HOME) $tmppwd
+
+# Run the test.  Logging in sometimes takes a while, so increase the
+# timeout.
+set oldtimeout $timeout
+set timeout 60
+set status [catch ftp_test msg]
+set timeout $oldtimeout
+
+# Shut down the kerberos daemons and the ftp daemon.
+stop_kerberos_daemons
+
+stop_ftp_daemon
+
+ftp_restore_env
+
+# Reset $HOME, for safety in case we are going to run more tests.
+if [info exists home] {
+    set env(HOME) $home
+} else {
+    unset env(HOME)
+}
+
+if { $status != 0 } {
+    perror "error in gssftp.exp: $msg"
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/kadmin.exp b/mechglue/src/tests/dejagnu/krb-standalone/kadmin.exp
new file mode 100644
index 000000000..e3e39168d
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/kadmin.exp
@@ -0,0 +1,1075 @@
+# Kerberos kadmin test.
+# This is a DejaGnu test script.
+# This script tests Kerberos kadmin5 using kadmin.local as verification.
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    return
+}
+
+# find kpasswd
+if ![info exists KPASSWD] {
+    set KPASSWD [findfile $objdir/../../clients/kpasswd/kpasswd]
+}
+
+# find kdestroy
+if ![info exists KDESTROY] {
+    set KDESTROY [findfile $objdir/../../clients/kdestroy/kdestroy]
+}
+
+#++
+# kadmin_add	- Test add new v5 principal function of kadmin.
+#
+# Adds principal $pname with password $password.  Returns 1 on success.
+#--
+proc kadmin_add { pname password } {
+    global REALMNAME
+    global KADMIN
+    global KADMIN_LOCAL
+    global KEY
+    global spawn_id
+    global tmppwd
+
+    set good 0
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin add $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin add $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin add $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*:" {
+	send "adminpass$KEY\r"
+    }
+    expect "Enter password for principal \"$pname@$REALMNAME\":" { send "$password\r" }
+    expect "Re-enter password for principal \"$pname@$REALMNAME\":" { send "$password\r" }
+    expect "Principal \"$pname@$REALMNAME\" created." { set good 1 }
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin add)"
+    catch "close -i $spawn_id"
+    if { $good == 1 } {
+	#
+	# use kadmin.local to verify that a principal was created and that its
+	# salt types are 0 (normal).
+	#
+	spawn $KADMIN_LOCAL -r $REALMNAME
+	expect_after {
+	    -i $spawn_id
+	    timeout {
+		fail "kadmin add $pname"
+		catch "expect_after"
+		return 0
+	    }
+	    eof {
+		fail "kadmin add $pname"
+		catch "expect_after"
+		return 0
+	    }
+	}
+	set good 0
+	expect "kadmin.local: " { send "getprinc $pname\r" }
+	expect "Principal: $pname@$REALMNAME" { set good 1 }
+	expect "Expiration date:" { verbose "got expiration date" }
+	expect "Last password change:" { verbose "got last pwchange" }
+	expect "Password expiration date:" { verbose "got pwexpire date" }
+	expect "Maximum ticket life:" { verbose "got max life" }
+	expect "Maximum renewable life:" { verbose "got max rlife" }
+	expect "Last modified:" { verbose "got last modified" }
+	expect "Last successful authentication:" { verbose "last succ auth" }
+	expect "Last failed authentication:" { verbose "last pw failed" }
+	expect "Failed password attempts:" { verbose "num failed attempts" }
+	expect "Number of keys:" { verbose "num keys"} 
+	expect {
+		"Key: " { verbose "Key listed" 
+			exp_continue
+		}
+		"Attributes:" { verbose "attributes" }
+	}
+	expect "kadmin.local: " { send "q\r" }
+
+	expect_after
+	expect eof
+	set k_stat [wait -i $spawn_id]
+	verbose "wait -i $spawn_id returned $k_stat (kadmin.local show)"
+	catch "close -i $spawn_id"
+	if { $good == 1 } {
+	    pass "kadmin add $pname"
+	    return 1
+	}
+	else {
+	    fail "kadmin add $pname"
+	    return 0
+	}
+    }
+    else {
+	fail "kadmin add $pname"
+	return 0
+    }
+}
+
+#++
+# kadmin_add_rnd	- Test add new v5 principal with random key function.
+#
+# Adds principal $pname with random key.  Returns 1 on success.
+#--
+proc kadmin_add_rnd { pname { flags "" } } {
+    global REALMNAME
+    global KADMIN
+    global KADMIN_LOCAL
+    global KEY
+    global spawn_id
+    global tmppwd
+
+    set good 0
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $flags $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin add rnd $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin add_rnd $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin add_rnd $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+    expect "Principal \"$pname@$REALMNAME\" created." { set good 1 }
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin add_rnd)"
+    catch "close -i $spawn_id"
+    if { $good == 1 } {
+	#
+	# use kadmin.local to verify that a principal was created and that its
+	# salt types are 0 (normal).
+	#
+	spawn $KADMIN_LOCAL -r $REALMNAME
+	expect_after {
+	     -i $spawn_id
+	    timeout {
+		fail "kadmin add_rnd $pname"
+		catch "expect_after"
+		return 0
+	    }
+	    eof {
+		fail "kadmin add_rnd $pname"
+		catch "expect_after"
+		return 0
+	    }
+	}
+	set good 0
+	expect "kadmin.local:" { send "getprinc $pname\r" }
+	expect "Principal: $pname@$REALMNAME" { set good 1 }
+	expect "kadmin.local:" { send "q\r" }
+	expect_after
+	expect eof
+	set k_stat [wait -i $spawn_id]
+	verbose "wait -i $spawn_id returned $k_stat (kadmin.local show)"
+	catch "close -i $spawn_id"
+	if { $good == 1 } {
+	    pass "kadmin add_rnd $pname"
+	    return 1
+	}
+	else {
+	    fail "kadmin add_rnd $pname"
+	    return 0
+	}
+    }
+    else {
+	fail "kadmin add_rnd $pname"
+	return 0
+    }
+}
+
+#++
+# kadmin_show	- Test show principal function of kadmin.
+# 
+# Retrieves entry for $pname.  Returns 1 on success.
+#--
+proc kadmin_show { pname } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "get_principal $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin show $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin show $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin show $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *"
+    send "adminpass$KEY\r"
+    expect -re "\r.*Principal: $pname@$REALMNAME.*Key: .*Attributes:.*Policy: .*\r"
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin show)"
+    catch "close -i $spawn_id"
+    pass "kadmin show $pname"
+    return 1
+}
+
+#++
+# kadmin_cpw	- Test change password function of kadmin
+#
+# Change password of $pname to $password.  Returns 1 on success.
+#--
+proc kadmin_cpw { pname password } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "cpw $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin cpw $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin cpw $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin cpw $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+
+    expect "Enter password for principal \"$pname\":" { send "$password\r" }
+    expect "Re-enter password for principal \"$pname\":" { send "$password\r" }
+    # When in doubt, jam one of these in there.
+    expect "\r"
+    expect "Password for \"$pname@$REALMNAME\" changed."
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin cpw)"
+    catch "close -i $spawn_id"
+    pass "kadmin cpw $pname"
+    return 1
+}
+
+#++
+# kadmin_cpw_rnd	- Test change random key function of kadmin.
+#
+# Changes principal $pname's key to a new random key.  Returns 1 on success.
+#--
+proc kadmin_cpw_rnd { pname } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "cpw -randkey $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin cpw_rnd $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin cpw_rnd $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin cpw_rnd $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+    # When in doubt, jam one of these in there.
+    expect "\r"
+    expect "Key for \"$pname@$REALMNAME\" randomized."
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin cpw_rnd)"
+    catch "close -i $spawn_id"
+    pass "kadmin cpw_rnd $pname"
+    return 1
+}
+
+#++
+# kadmin_modify	- Test modify principal function of kadmin.
+#
+# Modifies principal $pname with flags $flags.  Returns 1 on success.
+#--
+proc kadmin_modify { pname flags } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "modprinc $flags $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin modify $pname ($flags) lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin modify $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin modify $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *"
+    send "adminpass$KEY\r"
+    # When in doubt, jam one of these in there.
+    expect "\r"
+    expect "Principal \"$pname@$REALMNAME\" modified."
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin modify)"
+    catch "close -i $spawn_id"
+    pass "kadmin modify $pname"
+    return 1
+}
+
+
+#++
+# kadmin_list	- Test list database function of kadmin.
+#
+# Lists the database and verifies that output matches regular expression
+# "(.*@$REALMNAME)*".  Returns 1 on success.
+#--
+proc kadmin_list {  } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "get_principals *"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin ldb lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	"Communication failure" {
+	    fail "kadmin ldb got RPC error"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin ldb"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin ldb"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+    expect -re "\(.*@$REALMNAME\r\n\)+"
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin list)"
+    catch "close -i $spawn_id"
+    pass "kadmin ldb"
+    return 1
+}
+
+#++
+# kadmin_extract	- Test extract service key function of kadmin.
+#
+# Extracts service key for service name $name instance $instance.  Returns
+# 1 on success.
+#--
+proc kadmin_extract { instance name } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+    global tmppwd
+
+    catch "exec rm -f $tmppwd/keytab"
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "xst -k $tmppwd/keytab $name/$instance"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin xst $instance $name lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin xst $instance $name"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin xst $instance $name"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+#    expect -re "kadmin: Entry for principal $name/$instance with kvno [0-9], encryption type .* added to keytab WRFILE:$tmppwd/keytab."
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin xst)"
+    catch "close -i $spawn_id"
+    catch "exec rm -f $instance-new-srvtab"
+    pass "kadmin xst $instance $name"
+    return 1
+}
+
+#++
+# kadmin_extractv4	- Test extract service key in v4 format function of
+#			  kadmin.
+#
+# Extracts service key for service name $name instance $instance in version
+# 4 format.  Returns 1 on success.
+#--
+#proc kadmin_extractv4 { instance name } {
+#    global REALMNAME
+#    global KADMIN
+#    global KEY
+#    global spawn_id
+#
+#    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "xst4 $instance $name"
+#    expect_after {
+#	"Cannot contact any KDC" {
+#	    fail "kadmin xst4 $instance $name lost KDC"
+#	    catch "expect_after"
+#	    return 0
+#	}
+#	timeout {
+#	    fail "kadmin xst4 $instance $name"
+#	    catch "expect_after"
+#	    return 0
+#	}
+#	eof {
+#	    fail "kadmin xst4 $instance $name"
+#	    catch "expect_after"
+#	    return 0
+#	}
+#    }
+#    expect -re "assword\[^\r\n\]*: *" {
+#	send "adminpass$KEY\r"
+#    }
+#    expect "extracted entry $name to key table $instance-new-v4-srvtab"
+#    expect_after
+#    expect eof
+#    set k_stat [wait -i $spawn_id]
+#    verbose "wait -i $spawn_id returned $k_stat (kadmin xst4)"
+#    catch "close -i $spawn_id"
+#    catch "exec rm -f $instance-new-v4-srvtab"
+#    pass "kadmin xst4 $instance $name"
+#    return 1
+#}
+
+#++
+# kadmin_delete	- Test delete principal function of kadmin.
+#
+# Deletes principal $pname.  Returns 1 on success.
+#--
+proc kadmin_delete { pname } {
+    global REALMNAME
+    global KADMIN
+    global KADMIN_LOCAL
+    global KEY
+    global spawn_id
+    global tmppwd
+
+    set good 0
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "delprinc -force $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin_delete $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin delprinc $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin delprinc $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+    expect "Principal \"$pname@$REALMNAME\" deleted." { set good 1 }
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin delprinc)"
+    catch "close -i $spawn_id"
+    if { $good == 1 } {
+	#
+	# use kadmin.local to verify that the old principal is not present.
+	#
+	spawn $KADMIN_LOCAL -r $REALMNAME
+	expect_after {
+	    -i $spawn_id
+	    timeout {
+		fail "kadmin delprinc $pname"
+		catch "expect_after"
+		return 0
+	    }
+	    eof {
+		fail "kadmin delprinc $pname"
+		catch "expect_after"
+		return 0
+	    }
+	}
+	set good 0
+	expect "kadmin.local: " { send "getprinc $pname\r" }
+	expect "Principal does not exist while retrieving \"$pname@$REALMNAME\"." { set good 1 }
+	expect "kadmin.local: " { send "quit\r" }
+	expect_after
+	expect eof
+	set k_stat [wait -i $spawn_id]
+	verbose "wait -i $spawn_id returned $k_stat (kadmin.local show)"
+	catch "close -i $spawn_id"
+	if { $good == 1 } {
+	    pass "kadmin delprinc $pname"
+	    return 1
+	}
+	else {
+	    fail "kadmin delprinc $pname"
+	    return 0
+	}
+    }
+    else {
+	fail "kadmin delprinc $pname"
+	return 0
+    }
+}
+
+#++
+# kpasswd_cpw	- Test password changing using kpasswd.
+#
+# Change $princ's password from $opw to $npw.  Returns 1 on success.
+#--
+proc kpasswd_cpw { princ opw npw } {
+    global KPASSWD
+    global REALMNAME
+
+    spawn $KPASSWD $princ
+    expect_after {
+	timeout {
+	    fail "kpasswd $princ $npw"
+#	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kpasswd $princ $npw"
+#	    catch "expect_after"
+	    return 0
+	}
+    }
+
+#    expect "Changing password for $princ."
+#    expect "Old password:" { send "$opw\r" }
+#    expect "New password:" { send "$npw\r" }
+#    expect "New password (again):" { send "$npw\r" }
+    expect "Password for $princ@$REALMNAME:" { send "$opw\r" }
+    expect "Enter new password:"  { send "$npw\r" }
+    expect "Enter it again:"      { send "$npw\r" }
+#    expect "Kerberos password changed."
+    expect "Password changed."
+    expect_after
+    expect eof
+
+    if ![check_exit_status "kpasswd"] {
+	fail "kpasswd $princ $npw"
+	return 0
+    }
+    pass "kpasswd $princ $npw"
+    return 1
+}
+
+#++
+# kadmin_addpol	- Test add new policy function of kadmin.
+#
+# Adds policy $pname.  Returns 1 on success.
+#--
+proc kadmin_addpol { pname } {
+    global REALMNAME
+    global KADMIN
+    global KADMIN_LOCAL
+    global KEY
+    global spawn_id
+    global tmppwd
+
+    set good 0
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "addpol $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin addpol $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin addpol $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin addpol $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin addpol)"
+    catch "close -i $spawn_id"
+    #
+    # use kadmin.local to verify that a policy was created
+    #
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    expect_after {
+        -i $spawn_id
+        timeout {
+	    fail "kadmin addpol $pname"
+	    catch "expect_after"
+	    return 0
+        }
+        eof {
+	    fail "kadmin addpol $pname"
+	    catch "expect_after"
+	    return 0
+        }
+    }
+    set good 0
+    expect "kadmin.local: " { send "getpol $pname\r" }
+    expect "Policy: $pname" { set good 1 }
+    expect "Maximum password life:" { verbose "got max pw life" }
+    expect "Minimum password life:" { verbose "got min pw life" }
+    expect "Minimum password length:" { verbose "got min pw length" }
+    expect "Minimum number of password character classes:" {
+        verbose "got min pw character classes" }
+    expect "Number of old keys kept:" { verbose "got num old keys kept" }
+    expect "Reference count:" { verbose "got refcount" }
+    expect "kadmin.local: " { send "q\r" }
+
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin.local showpol)"
+    catch "close -i $spawn_id"
+    if { $good == 1 } {
+        pass "kadmin addpol $pname"
+        return 1
+    }
+    else {
+        fail "kadmin addpol $pname"
+        return 0
+    }
+}
+
+#++
+# kadmin_delpol	- Test delete policy function of kadmin.
+#
+# Deletes policy $pname.  Returns 1 on success.
+#--
+proc kadmin_delpol { pname } {
+    global REALMNAME
+    global KADMIN
+    global KADMIN_LOCAL
+    global KEY
+    global spawn_id
+    global tmppwd
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "delpol -force $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin_delpol $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin delpol $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin delpol $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin delpol)"
+    catch "close -i $spawn_id"
+    #
+    # use kadmin.local to verify that the old policy is not present.
+    #
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    expect_after {
+        -i $spawn_id
+        timeout {
+	    fail "kadmin delpol $pname"
+	    catch "expect_after"
+	    return 0
+        }
+        eof {
+	    fail "kadmin delpol $pname"
+	    catch "expect_after"
+	    return 0
+        }
+    }
+    set good 0
+    expect "kadmin.local: " { send "getpol $pname\r" }
+    expect "Policy does not exist while retrieving policy \"$pname\"." {
+	set good 1
+    }
+    expect "kadmin.local: " { send "quit\r" }
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin.local showpol)"
+    catch "close -i $spawn_id"
+    if { $good == 1 } {
+        pass "kadmin delpol $pname"
+        return 1
+    }
+    else {
+        fail "kadmin delpol $pname"
+        return 0
+    }
+}
+
+#++
+# kadmin_listpols	- Test list policy database function of kadmin.
+#
+# Lists the policies.  Returns 1 on success.
+#--
+proc kadmin_listpols {  } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "get_policies *"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin lpols lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin lpols"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin lpols"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+	send "adminpass$KEY\r"
+    }
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin listpols)"
+    catch "close -i $spawn_id"
+    pass "kadmin lpols"
+    return 1
+}
+
+#++
+# kadmin_modpol	- Test modify policy function of kadmin.
+#
+# Modifies policy $pname with flags $flags.  Returns 1 on success.
+#--
+proc kadmin_modpol { pname flags } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "modpol $flags $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin modpol $pname ($flags) lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin modpol $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin modpol $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *"
+    send "adminpass$KEY\r"
+    # When in doubt, jam one of these in there.
+    expect "\r"
+    # Sadly, kadmin doesn't print a confirmation message for policy operations.
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin modpol)"
+    catch "close -i $spawn_id"
+    pass "kadmin modpol $pname"
+    return 1
+}
+
+#++
+# kadmin_showpol	- Test show policy function of kadmin.
+# 
+# Retrieves entry for $pname.  Returns 1 on success.
+#--
+proc kadmin_showpol { pname } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "get_policy $pname"
+    expect_after {
+	"Cannot contact any KDC" {
+	    fail "kadmin showpol $pname lost KDC"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin showpol $pname"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin showpol $pname"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect -re "assword\[^\r\n\]*: *"
+    send "adminpass$KEY\r"
+    expect -re "\r.*Policy: $pname.*Number of old keys kept: .*Reference count: .*\r"
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin showpol)"
+    catch "close -i $spawn_id"
+    pass "kadmin showpol $pname"
+    return 1
+}
+
+#++
+# kdestroy
+#--
+proc kdestroy { } {
+    global KDESTROY
+
+    spawn $KDESTROY -5
+    if ![check_exit_status "kdestroy"] {
+	return 0
+    }
+    return 1
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc kadmin_test { } {
+    global hostname
+
+    # Start up the kerberos and kadmind daemons
+    if {![start_kerberos_daemons 0] } {
+	return
+    }
+
+    # Test basic kadmin functions.
+    if {![kadmin_add v5principal/instance1 v5principal] \
+	|| ![kadmin_addpol standardpol] \
+	|| ![kadmin_showpol standardpol] \
+	|| ![kadmin_listpols] \
+	|| ![kadmin_modpol standardpol "-minlength 5"] \
+	|| ![kadmin_add v4principal/instance2 v4principal] \
+	|| ![kadmin_add_rnd v5random] \
+	|| ![kadmin_show v5principal/instance1] \
+	|| ![kadmin_show v4principal/instance2] \
+	|| ![kadmin_show v5random] \
+	|| ![kadmin_cpw v5principal/instance1 faroutman] \
+	|| ![kadmin_cpw v4principal/instance2 honkydory] \
+	|| ![kadmin_cpw_rnd v5random] \
+	|| ![kadmin_modify v5random -allow_tix] \
+	|| ![kadmin_modify v5random +allow_tix] \
+	|| ![kadmin_modify v5random "-policy standardpol"] \
+	|| ![kadmin_list] \
+	|| ![kadmin_extract instance1 v5principal] \
+	|| ![kadmin_delete v5random] \
+	|| ![kadmin_delete v4principal/instance2] \
+	|| ![kadmin_delete v5principal/instance1] \
+	|| ![kadmin_delpol standardpol]} {
+	return
+    }
+
+# You cannot extract a v4 key...
+#	|| ![kadmin_extractv4 instance2 v4principal] \
+
+    # now test kpasswd
+    if {![kadmin_add testprinc/instance thisisatest] \
+	    || ![kpasswd_cpw testprinc/instance thisisatest anothertest] \
+	    || ![kpasswd_cpw testprinc/instance anothertest goredsox] \
+	    || ![kadmin_delete testprinc/instance]} {
+	return
+    }
+
+    # now test that we can kinit with principals/passwords.
+    if {![kadmin_add testprinc1/instance thisisatest] \
+	    || ![kinit testprinc1/instance thisisatest 0] \
+	    || ![kdestroy] \
+	    || ![kpasswd_cpw testprinc1/instance thisisatest anothertest] \
+	    || ![kinit testprinc1/instance anothertest 0] \
+	    || ![kdestroy] \
+	    || ![kpasswd_cpw testprinc1/instance anothertest goredsox] \
+	    || ![kinit testprinc1/instance goredsox 0] \
+	    || ![kdestroy] \
+	    || ![kadmin_cpw testprinc1/instance betterwork] \
+	    || ![kinit testprinc1/instance betterwork 0] \
+	    || ![kdestroy] \
+	    || ![kadmin_delete testprinc1/instance]} {
+	return
+    }
+
+    # now test modify changes.
+    if {![kadmin_add testuser longtestpw] \
+	    || ![kinit testuser longtestpw 0] \
+	    || ![kdestroy] \
+	    || ![kadmin_modify testuser "-maxlife \"2500 seconds\""] \
+	    || ![kinit testuser longtestpw 0] \
+	    || ![kdestroy] \
+	    || ![kadmin_delete testuser]} {
+	return
+    }
+
+    # now test that reducing the history number doesn't make kadmind vulnerable.
+    if {![kadmin_addpol crashpol] \
+	    || ![kadmin_modpol crashpol "-history 5"] \
+	    || ![kadmin_add crash first] \
+	    || ![kadmin_modify crash "-policy crashpol"] \
+	    || ![kadmin_cpw crash second] \
+	    || ![kadmin_cpw crash third] \
+	    || ![kadmin_cpw crash fourth] \
+	    || ![kadmin_modpol crashpol "-history 3"] \
+	    || ![kadmin_cpw crash fifth] \
+	    || ![kadmin_delete crash] \
+	    || ![kadmin_delpol crashpol]} {
+	return
+    }
+
+    # test retrieval of large number of principals
+    # bug [2877]
+    for { set i 0 } { $i < 200 } { incr i } {
+	if { ![kadmin_add "foo$i" foopass] } {
+	    return
+	}
+    }
+
+    if { ![kadmin_list] } {
+	return
+    }
+
+    # test fallback to kadmin/admin
+    if {![kadmin_delete kadmin/$hostname] \
+	    || ![kadmin_list] \
+	    || ![kadmin_add_rnd kadmin/$hostname -allow_tgs_req] \
+	    || ![kadmin_list]} {
+	return
+    }
+
+    verbose "kadmin_test succeeded"
+}
+
+# Run the test.
+set status [catch kadmin_test msg]
+
+# Shut down the kerberos daemons and the rsh daemon.
+stop_kerberos_daemons
+
+if { $status != 0 } {
+    send_error "ERROR: error in kadmin.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/pwhist.exp b/mechglue/src/tests/dejagnu/krb-standalone/pwhist.exp
new file mode 100644
index 000000000..f9938e091
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/pwhist.exp
@@ -0,0 +1,215 @@
+# password history tests
+
+# one *non-interactive* kadmin.local request
+proc onerq { rq pname str {flags ""} } {
+    global REALMNAME
+    global KADMIN_LOCAL
+
+    spawn $KADMIN_LOCAL -r $REALMNAME -q "$rq $flags $pname"
+    expect_after {
+	timeout {
+	    verbose "kadmin.local $rq $flags $pname timed out"
+	    catch expect_after
+	    kill [exp_pid]
+	    close
+	    expect eof
+	    wait
+	    return 0
+	} eof {
+	    verbose "kadmin.local $rq $flags $pname got EOF"
+	    catch expect_after
+	    wait
+	    return 0
+	}
+    }
+    expect $str
+    expect_after
+    expect eof
+    wait
+    return 1
+}
+
+proc addprinc { pname pw } {
+    global REALMNAME
+
+    return [onerq addprinc $pname \
+		"Principal \"$pname@$REALMNAME\" created." "-pw $pw"]
+}
+
+proc delprinc { pname } {
+    global REALMNAME
+    return [onerq delprinc $pname \
+		"Principal \"$pname@$REALMNAME\" deleted." "-force"]
+}
+
+proc cpw { pname pw } {
+    global REALMNAME
+
+    return [onerq cpw $pname \
+		"Password for \"$pname@$REALMNAME\" changed." "-pw $pw"]
+}
+
+proc modprinc { pname flags } {
+    global REALMNAME
+
+    return [onerq modprinc $pname \
+		"Principal \"$pname@$REALMNAME\" modified." $flags]
+}
+
+proc addpol { pname } {
+    if ![onerq addpol $pname ""] {
+	return 0
+    }
+    return [onerq getpol $pname "Policy: $pname"]
+}
+
+proc delpol { pname } {
+    onerq delpol $pname "" -force
+    return [onerq getpol $pname \
+		"Policy does not exist while retrieving policy \"$pname\"."]
+}
+
+proc modpol { pname flags } {
+    return [onerq modpol $pname "" $flags]
+}
+
+# Mandatory command must return true.
+# Issues a break in its parent on failure.
+proc mustrun { cmd } {
+    if ![eval $cmd] {
+	perror "mandatory command failed: $cmd"
+	uplevel break
+    }
+}
+
+# Fail test if command fails.
+# Issues a break in its parent on failure.
+proc chkpass { cmd } {
+    upvar test test
+    if ![eval $cmd] {
+	verbose "unexpected failure: $cmd"
+	fail $test
+	uplevel break
+    }
+}
+
+# Fail test if command succeeds.
+# Issues a break in its parent on failure.
+proc chkfail { cmd } {
+    upvar test test
+    if [eval $cmd] {
+	verbose "unexpected success: $cmd"
+	fail $test
+	uplevel break
+    }
+}
+
+# wrapper to run command (actually usually sequence of commands)
+#
+# If any part of CMD throws an exception, set failall, otherwise pass.
+# If failall is already true, report unresolved.
+proc wraptest { test cmd } {
+    upvar failall failall
+    if $failall {
+	unresolved $test
+	return
+    }
+    if [catch $cmd] {
+	set failall 1
+    } else {
+	pass $test
+    }
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    return
+}
+
+set failall 0
+wraptest "nkeys=1, nhist=3" {
+    mustrun { addpol crashpol }
+    mustrun { modpol crashpol "-history 3"}
+    mustrun { addprinc crash 1111 }
+    mustrun { modprinc crash "-policy crashpol" }
+    chkpass { cpw crash 2222 }
+    chkfail { cpw crash 2222 }
+    chkfail { cpw crash 1111 }
+}
+verbose {old_keys [ 1111 ->[] ]}
+
+# The following will result in reading/writing past array bounds if
+# add_to_history() is not patched.
+#
+# NOTE: A pass from this test does not mean the bug isn't present;
+# check with Purify, valgrind, etc.
+wraptest "array bounds ok on nkeys=1, nhist 3->2" {
+    mustrun { modpol crashpol "-history 2" }
+    chkpass { cpw crash 3333 }
+}
+verbose {old_keys [ ->2222 ]}
+
+wraptest "verify nhist=2" {
+    mustrun { delprinc crash }
+    mustrun { addprinc crash 1111 }
+    mustrun { modprinc crash "-policy crashpol" }
+    chkpass { cpw crash 2222 }
+    chkfail { cpw crash 2222 }
+    chkfail { cpw crash 1111 }
+}
+verbose {old_keys [ ->1111 ]}
+
+# The following will fail if growing the history array causes an extra
+# key to be lost due to failure to shift entries.
+wraptest "grow nhist 2->3" {
+    mustrun { modpol crashpol "-history 3" }
+    chkpass { cpw crash 3333 }
+    chkfail { cpw crash 3333 }
+    chkfail { cpw crash 2222 }
+    chkfail { cpw crash 1111 }
+}
+verbose {old_keys [ 2222 ->1111 ]}
+
+wraptest "grow nhist 3->4" {
+    mustrun { modpol crashpol "-history 4" }
+    chkfail { cpw crash 3333 }
+    chkfail { cpw crash 2222 }
+    chkfail { cpw crash 1111 }
+    chkpass { cpw crash 4444 }
+    chkfail { cpw crash 3333 }
+    chkfail { cpw crash 2222 }
+    chkfail { cpw crash 1111 }
+}
+verbose {old_keys [ 2222 3333 ->1111 ]}
+wraptest "shrink nhist 4->3" {
+    mustrun { modpol crashpol "-history 3" }
+    chkfail { cpw crash 4444 }
+    chkfail { cpw crash 3333 }
+    chkfail { cpw crash 2222 }
+    chkfail { cpw crash 1111 }
+    chkpass { cpw crash 5555 }
+}
+verbose {old_keys [ 4444 ->3333 ]}
+wraptest "verify nhist=3" {
+    chkfail { cpw crash 5555 }
+    chkfail { cpw crash 4444 }
+    chkfail { cpw crash 3333 }
+    chkpass { cpw crash 2222 }
+}
+verbose {old_keys [ ->4444 5555 ]}
+wraptest "shrink nhist 3->2" {
+    mustrun { modpol crashpol "-history 2" }
+    chkfail { cpw crash 2222 }
+    chkfail { cpw crash 5555 }
+    chkfail { cpw crash 4444 }
+    chkpass { cpw crash 3333 }
+}
+verbose {old_keys [ ->2222 ]}
+
+delprinc crash
+delpol crashpol
+
+stop_kerberos_daemons
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/rcp.exp b/mechglue/src/tests/dejagnu/krb-standalone/rcp.exp
new file mode 100644
index 000000000..94ec240e6
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/rcp.exp
@@ -0,0 +1,232 @@
+# Kerberos rcp test.
+# This is a DejaGnu test script.
+# This script tests Kerberos rcp.
+# Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/src.
+
+if ![info exists RCP] {
+    set RCP [findfile $objdir/../../appl/bsd/rcp]
+}
+
+if ![info exists KRSHD] {
+    set KRSHD [findfile $objdir/../../appl/bsd/kshd]
+}
+
+# Remove old wrapper script
+    catch "exec rm -f $tmppwd/rcp"
+
+# Make sure .k5login is reasonable.
+if ![check_k5login rcp] {
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    return
+}
+
+# A procedure to start up the rsh daemon (rcp talks to the rsh
+# daemon).
+
+proc start_rsh_daemon { } {
+    global REALMNAME
+    global KRSHD
+    global RCP
+    global tmppwd
+    global krshd_spawn_id
+    global krshd_pid
+    global portbase
+
+    # Setup the shared library wrapper for login.krb5
+    if ![file exists $tmppwd/rcp] {
+	    setup_wrapper $tmppwd/rcp "$RCP $*"
+    }
+
+
+    # The -D argument tells it to accept a single connection, so we
+    # don't need to use inetd.  The portbase+8 is the port to listen at.
+    #
+    # The -L ENV_SET is for the I/S Athena brokeness in dot files where
+    #	LD_LIBRARY_PATH will be overridden causing the "exec csh -c rcp ..." 
+    #	to fail as the .cshrc is read in. We do not use the -f option as
+    #	a users shell might be sh...
+    #	Later a proper fix would be to have kshd exec rcp directly
+    #   shell indirection...
+    spawn $KRSHD -k -c -D [expr 8 + $portbase] -P $tmppwd -S $tmppwd/srvtab -M $REALMNAME -L ENV_SET
+    set krshd_spawn_id $spawn_id
+    set krshd_pid [exp_pid]
+
+    # Give the rsh daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the rsh daemon.
+
+proc stop_rsh_daemon { } {
+    global krshd_spawn_id
+    global krshd_pid
+
+    if [info exists krshd_pid] {
+	catch "exec kill $krshd_pid"
+	catch {
+	    expect {
+		-i $krshd_spawn_id
+		-re ..*	{ exp_continue }
+		eof	{}
+	    }
+	}
+	catch "close -i $krshd_spawn_id"
+	catch "wait -i $krshd_spawn_id"
+	unset krshd_pid
+    }
+}
+
+# Create a file to use for rcp testing.
+set file [open $tmppwd/rcp-test w]
+puts $file "This file is used for rcp testing."
+close $file
+
+# Test that a file was copied correctly.
+proc check_file { filename } {
+    if ![file exists $filename] {
+	verbose "$filename does not exist"
+	send_log "$filename does not exist\n"
+	return 0
+    }
+
+    set file [open $filename r]
+    if { [gets $file line] == -1 } {
+	verbose "$filename is empty"
+	send_log "$filename is empty\n"
+	close $file
+	return 0
+    }
+
+    if ![string match "This file is used for rcp testing." $line] {
+	verbose "$filename contains $line"
+	send_log "$filename contains $line\n"
+	close $file
+	return 0
+    }
+
+    if { [gets $file line] != -1} {
+	verbose "$filename is too long ($line)"
+	send_log "$filename is too long ($line)\n"
+	close $file
+	return 0
+    }
+
+    close $file
+
+    return 1
+}
+
+# Test copying one file to another.
+proc rcp_one_test { testname options frompref topref } {
+    global REALMNAME
+    global RCP
+    global tmppwd
+    global portbase
+
+    send_log "rm -f $tmppwd/copy\n"
+    verbose "exec rm -f $tmppwd/copy"
+    catch "exec rm -f $tmppwd/copy"
+
+    set from [format "%s%s" $frompref $tmppwd/rcp-test]
+    set to [format "%s%s" $topref $tmppwd/copy]
+
+    send_log "$RCP $options -D [expr 8 + $portbase] -N -k $REALMNAME $from $to\n"
+    verbose "$RCP $options -D [expr 8 + $portbase] -N -k $REALMNAME $from $to"
+    catch "exec $RCP $options -D [expr 8 + $portbase] -N -k $REALMNAME $from $to" exec_output
+
+    if ![string match "" $exec_output] {
+	send_log "$exec_output\n"
+	verbose "$exec_output"
+	fail $testname
+	return 0
+    }
+
+    if ![check_file $tmppwd/copy] {
+	fail $testname
+	return 0
+    }
+
+    pass $testname
+
+    return 1
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc rcp_test { } {
+    global RCP
+    global KEY
+    global hostname
+    global hostname
+    global env
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_kerberos_key host/$hostname 0] \
+        || ![setup_srvtab 0] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    rcp_one_test "local rcp" "" "" ""
+
+    start_rsh_daemon
+    rcp_one_test "rcp from" "" "$hostname:" ""
+    stop_rsh_daemon
+
+    start_rsh_daemon
+    rcp_one_test "rcp to" "" "" "$hostname:"
+    stop_rsh_daemon
+
+    # Doing rcp between two hosts actually just executes rsh rcp on
+    # the source.  We could test this, but we're not set up for it
+    # right now.  Also, it's pretty much covered by the other rcp
+    # tests and by the rsh tests.
+    # start_rsh_daemon
+    # rcp_one_test "rcp between" "" "$hostname:" "$hostname:"
+    # stop_rsh_daemon
+
+    start_rsh_daemon
+    rcp_one_test "encrypted rcp from" "-x -c $env(KRB5CCNAME) -C $env(KRB5_CONFIG)" "$hostname:" ""
+    stop_rsh_daemon
+
+    start_rsh_daemon
+    rcp_one_test "encrypted rcp to" "-x -c $env(KRB5CCNAME) -C $env(KRB5_CONFIG)" "" "$hostname:"
+    stop_rsh_daemon
+
+    # Doing rcp between two hosts actually just executes rsh rcp on
+    # the source.  We could test this, but we're not set up for it
+    # right now.  Also, it's pretty much covered by the other rcp
+    # tests and by the rsh tests.
+    # start_rsh_daemon
+    # rcp_one_test "encrypted rcp between" "-x" "$hostname:" "$hostname:"
+    # stop_rsh_daemon
+}
+
+# Run the test.
+set status [catch rcp_test msg]
+
+# Shut down the kerberos daemons and the rsh daemon.
+stop_kerberos_daemons
+
+stop_rsh_daemon
+
+if { $status != 0 } {
+    send_error "ERROR: error in rcp.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/rsh.exp b/mechglue/src/tests/dejagnu/krb-standalone/rsh.exp
new file mode 100644
index 000000000..b7c02a2a7
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/rsh.exp
@@ -0,0 +1,294 @@
+# Kerberos rsh test.
+# This is a DejaGnu test script.
+# This script tests Kerberos rsh.
+# Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/src.
+
+if ![info exists RSH] {
+    set RSH [findfile $objdir/../../appl/bsd/rsh]
+}
+
+if ![info exists KRSHD] {
+    set KRSHD [findfile $objdir/../../appl/bsd/kshd]
+}
+
+if ![info exists KLIST] {
+    set KLIST [findfile $objdir/../../clients/klist/klist]
+}
+
+# Make sure .k5login is reasonable.
+if ![check_k5login rsh] {
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_db 0]} {
+    return
+}
+
+# A procedure to start up the rsh daemon.
+
+proc start_rsh_daemon { option } {
+    global REALMNAME
+    global KRSHD
+    global tmppwd
+    global krshd_spawn_id
+    global krshd_pid
+    global portbase
+
+    # The -D argument tells it to accept a single connection, so we
+    # don't need to use inetd.  The portbase+8 is the port to listen at.
+    spawn $KRSHD -k -c -D [expr 8 + $portbase] -S $tmppwd/srvtab -M $REALMNAME -A $option
+    set krshd_spawn_id $spawn_id
+    set krshd_pid [exp_pid]
+
+    # Give the rsh daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the rsh daemon.
+
+proc stop_rsh_daemon { } {
+    global krshd_spawn_id
+    global krshd_pid
+
+    if [info exists krshd_pid] {
+	catch "exec kill $krshd_pid"
+	catch {
+	    expect {
+		-i $krshd_spawn_id
+		-re ..*	{ exp_continue }
+		eof	{}
+	    }
+	}
+	catch "close -i $krshd_spawn_id"
+	catch "wait -i $krshd_spawn_id"
+	unset krshd_pid
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc rsh_test { } {
+    global REALMNAME
+    global KLIST
+    global RSH
+    global KEY
+    global BINSH
+    global hostname
+    global env
+    global spawn_id
+    global tmppwd
+    global portbase
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_kerberos_key host/$hostname 0] \
+        || ![setup_srvtab 0] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![setup_kerberos_env client] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    # Start up the rsh daemon.
+    start_rsh_daemon -k
+
+    # Run rsh date.
+    set testname "date"
+    spawn $RSH $hostname -k $REALMNAME -D [expr 8 + $portbase] -A date
+    expect {
+	-re "\[A-Za-z0-9\]+ \[A-Za-z0-9\]+ +\[0-9\]+ \[0-9\]+:\[0-9\]+:\[0-9\]+ \[A-Za-z0-9\]+ \[0-9\]+\r\n" {
+	    set result $expect_out(0,string)
+	}
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+    expect eof
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    if [check_date $result] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    # The rsh daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_rsh_daemon
+
+    # Check encrypted rsh.
+    set failed no
+    start_rsh_daemon -ek
+    set testname "encrypted rsh"
+    spawn $RSH $hostname -x -k $REALMNAME -D [expr 8 + $portbase] -A echo hello
+    expect {
+	"hello" { expect eof }
+	timeout {
+	    fail "$testname (timeout)"
+	    set failed yes
+	}
+	eof {
+	    fail "$testname (eof)"
+	    set failed yes
+	}
+    }
+
+    catch "expect eof"
+    if { $failed == "no" } {
+	if ![check_exit_status $testname] {
+	    return
+	}
+	pass $testname
+	stop_rsh_daemon
+    } else {
+	catch "wait -i $spawn_id"
+	catch "close -i $spawn_id"
+	stop_rsh_daemon
+    }
+
+    # Check ticket forwarding
+    set failed no
+    start_rsh_daemon -k
+    set testname "rsh forwarding tickets"
+
+    # We need a wrapper for klist in order to setup for shared library 
+    # runtime environment
+    setup_wrapper $tmppwd/klist.wrap $KLIST
+
+    spawn $RSH $hostname -f -k $REALMNAME -D [expr 8 + $portbase] -A $BINSH -c $tmppwd/klist.wrap 
+    expect {
+	"Ticket cache:*\r" {
+	    expect eof
+	}
+ 	"klist: No credentials cache file found" {
+	    fail "$testname (not forwarded)"
+	    return
+	}
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    pass $testname
+
+    stop_rsh_daemon
+
+    # Check encrypted ticket forwarding
+    set failed no
+    start_rsh_daemon -e
+    set testname "encrypted rsh forwarding tickets"
+    spawn $RSH $hostname -x -f -k $REALMNAME -D [expr 8 + $portbase] -A $BINSH -c $tmppwd/klist.wrap 
+    expect {
+	"Ticket cache:*\r" {
+	    expect eof
+	}
+ 	"klist: No credentials cache file found" {
+	    fail "$testname (not forwarded)"
+	    return
+	}
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    pass $testname
+
+    stop_rsh_daemon
+
+    # Check stderr
+    start_rsh_daemon -k
+    set testname "rsh to stderr"
+    spawn $RSH $hostname -k $REALMNAME -D [expr 8 + $portbase] -A $BINSH -c "'echo hello 1>&2'"
+    expect {
+	"hello" { expect eof }
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    pass $testname
+
+    stop_rsh_daemon
+
+    start_rsh_daemon -e
+    set testname "encrypted rsh to stderr"
+    spawn $RSH $hostname -x -k $REALMNAME -D [expr 8 + $portbase] -A $BINSH -c "'echo hello 1>&2'"
+    expect {
+	"hello" { expect eof }
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    pass $testname
+
+    # The rsh daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_rsh_daemon
+}
+
+# Run the test.
+set status [catch rsh_test msg]
+
+# Shut down the kerberos daemons and the rsh daemon.
+stop_kerberos_daemons
+
+stop_rsh_daemon
+
+if { $status != 0 } {
+    send_error "ERROR: error in rsh.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/sample.exp b/mechglue/src/tests/dejagnu/krb-standalone/sample.exp
new file mode 100644
index 000000000..c19c49e91
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/sample.exp
@@ -0,0 +1,210 @@
+# Test for the sample clients
+# This is a DejaGnu test script.
+# This script tests that sample user-user communication works.
+
+# This mostly just calls procedures in test/dejagnu/config/default.exp.
+
+if ![info exists KLIST] {
+    set KLIST [findfile $objdir/../../clients/klist/klist]
+}
+
+if ![info exists KDESTROY] {
+    set KDESTROY [findfile $objdir/../../clients/kdestroy/kdestroy]
+}
+
+if ![info exists SSERVER] {
+    set SSERVER [findfile $objdir/../../appl/sample/sserver/sserver]
+}
+if ![info exists SCLIENT] {
+    set SCLIENT [findfile $objdir/../../appl/sample/sclient/sclient]
+}
+
+# Set up the Kerberos files and environment.
+if {![get_hostname] || ![setup_kerberos_files] || ![setup_kerberos_env]} {
+    return
+}
+
+# Initialize the Kerberos database.  The argument tells
+# setup_kerberos_db that it is being called from here.
+if ![setup_kerberos_db 0] {
+    return
+}
+
+proc start_sserver_daemon { inetd } {
+    global spawn_id
+    global sserver_pid
+    global sserver_spawn_id
+    global SSERVER
+    global T_INETD
+    global tmppwd
+    global portbase
+
+    # if inetd = 0, then we are running stand-alone
+    if !{$inetd} {
+	    # Start the sserver
+	    spawn $SSERVER -p [expr 8 + $portbase] -S $tmppwd/srvtab
+	    set sserver_pid [exp_pid]
+	    set sserver_spawn_id $spawn_id
+
+	    verbose "sserver_spawn is $sserver_spawn_id" 1
+    } else {
+	    # Start the sserver
+	    spawn $T_INETD [expr 8 + $portbase] $SSERVER sserver -S $tmppwd/srvtab
+	    set sserver_pid [exp_pid]
+	    set sserver_spawn_id $spawn_id
+
+	    verbose "sserver_spawn (t_inetd) is $sserver_spawn_id" 1
+    }
+
+    # Give sserver some time to start
+    sleep 2
+
+    return 1
+}
+
+
+proc stop_sserver_daemon { } {
+    global sserver_pid
+    global sserver_spawn_id
+
+    if [info exists sserver_pid] {
+	catch "close -i $sserver_spawn_id"
+	catch "exec kill $sserver_pid"
+	wait -i $sserver_spawn_id
+	unset sserver_pid
+    }
+
+    return 1
+}
+
+proc stop_check_sserver_daemon { } {
+    global sserver_spawn_id
+    global sserver_pid
+
+    # Check the exit status of sserver - should exit here
+    set status_list [wait -i $sserver_spawn_id]
+    verbose "wait -i $sserver_spawn_id returned $status_list (sserver)"
+    catch "close -i $sserver_spawn_id"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } {
+	send_log "exit status: $status_list\n"
+	verbose "exit status: $status_list"
+	fail "sserver"
+    } else {
+	pass "sserver"
+    }
+    # In either case the server shutdown
+    unset sserver_pid
+}
+
+proc test_sclient { msg } {
+    global REALMNAME
+    global SCLIENT
+    global hostname
+    global spawn_id
+    global portbase
+
+    # Test the client
+    spawn $SCLIENT $hostname [expr 8 + $portbase]
+    verbose "sclient_spawn is  $spawn_id" 1
+
+    expect {
+	"sendauth succeeded, reply is:" {
+		verbose "Start proper message"
+	}
+	timeout {
+		fail $msg 
+		return 0
+	}
+	eof {
+		fail $msg 
+		return 0
+	}	
+     }
+
+    expect {
+	"You are krbtest/admin@$REALMNAME\r" {
+		verbose "received valid sample message"}
+	eof {
+		fail $msg 
+		return 0
+	    }
+    }
+    # This last expect seems useless, but without it the test hangs on
+    # NETBSD.
+    expect {
+        "\r" { }
+    }
+
+    if ![check_exit_status "ssample"] {
+	return 0
+    }
+
+    return 1
+}
+# We are about to start up a couple of daemon processes.  We do all
+# the rest of the tests inside a proc, so that we can easily kill the
+# processes when the procedure ends.
+
+proc doit { } {
+    global hostname
+    global KEY
+    global sserver_pid
+    global sserver_spawn_id
+
+    # Start up the kerberos and kadmind daemons.
+    if ![start_kerberos_daemons 0] {
+	return
+    }
+
+    # Use kadmin to add an host key.
+    if ![add_random_key sample/$hostname 1] {
+	return
+    }
+
+    # Use ksrvutil to create a srvtab entry for sample
+    if ![setup_srvtab 1 sample] {
+	return
+    }
+
+    # Use kinit to get a ticket.
+    if ![kinit krbtest/admin adminpass$KEY 1] {
+	return
+    }
+
+    if ![start_sserver_daemon 0 ] {
+	return 
+    }
+
+    if ![test_sclient sclient] {
+	return
+    }
+    
+    pass "sample - standalone"
+
+    stop_check_sserver_daemon
+    
+    if ![start_sserver_daemon 1 ] {
+	return 
+    }
+
+    if ![test_sclient sclient-inetd] {
+	return
+    }
+    
+    pass "sample - inetd"
+
+    stop_check_sserver_daemon
+    return
+}
+
+set status [catch doit msg]
+
+stop_sserver_daemon
+
+stop_kerberos_daemons
+
+if { $status != 0 } {
+    send_error "ERROR: error in sample.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/standalone.exp b/mechglue/src/tests/dejagnu/krb-standalone/standalone.exp
new file mode 100644
index 000000000..dbe9b950c
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/standalone.exp
@@ -0,0 +1,156 @@
+# Standalone Kerberos test.
+# This is a DejaGnu test script.
+# This script tests that the Kerberos tools can talk to each other.
+
+# This mostly just calls procedures in testsuite/config/default.exp.
+
+# Set up the Kerberos files and environment.
+if {![get_hostname] || ![setup_kerberos_files] || ![setup_kerberos_env]} {
+    return
+}
+
+# Initialize the Kerberos database.  The argument tells
+# setup_kerberos_db that it is being called from here.
+if ![setup_kerberos_db 1] {
+    return
+}
+
+# We are about to start up a couple of daemon processes.  We do all
+# the rest of the tests inside a proc, so that we can easily kill the
+# processes when the procedure ends.
+
+proc doit { } {
+    global REALMNAME
+    global KLIST
+    global KDESTROY
+    global KEY
+    global KADMIN_LOCAL
+    global KTUTIL
+    global hostname
+    global tmppwd
+    global spawn_id
+    global supported_enctypes
+    global KRBIV
+
+    # Start up the kerberos and kadmind daemons.
+    if ![start_kerberos_daemons 1] {
+	return
+    }
+
+    # Use kadmin to add an host key.
+    if ![add_random_key host/$hostname 1] {
+	return
+    }
+
+    # Use ksrvutil to create a srvtab entry.
+    if ![setup_srvtab 1] {
+	return
+    }
+
+    # Use kinit to get a ticket.
+    if ![kinit krbtest/admin adminpass$KEY 1] {
+	return
+    }
+
+    # Make sure that klist can see the ticket.
+    if ![do_klist "krbtest/admin@$REALMNAME" "krbtgt/$REALMNAME@$REALMNAME" "klist"] {
+	return
+    }
+
+    # Destroy the ticket.
+    spawn $KDESTROY -5
+    if ![check_exit_status "kdestroy"] {
+	return
+    }
+    pass "kdestroy"
+
+    # Double check that the ticket was destroyed.
+    if ![do_klist_err "klist after destroy"] { return }
+
+    if ![add_random_key foo/bar 1] {
+	return
+    }
+
+    set keytab $tmppwd/fookeytab
+    catch "exec rm -f $keytab"
+
+    modify_principal foo/bar -kvno 252
+    foreach vno {253 254 255 256 257 258} {
+	xst $tmppwd/fookeytab foo/bar
+	do_klist_kt $tmppwd/fookeytab "klist keytab foo/bar vno $vno"
+	kinit_kt "foo/bar" $tmppwd/fookeytab 1 "kt kvno $vno"
+	do_klist "foo/bar" "krbtgt/$REALMNAME@$REALMNAME" "klist kt foo/bar vno $vno"
+	do_kdestroy "kdestroy foo/bar vno $vno"
+	
+	if {[info exists KRBIV] && $KRBIV &&
+	    [regexp {des-cbc-[a-z0-9-]*:v4} [lindex $supported_enctypes 0]]} {
+	    catch "exec rm -f $tmppwd/foosrvtab"
+	    spawn $KTUTIL
+	    expect_after {
+		timeout	{ fail "ktutil converting keytab to srvtab" ; set ok 0 }
+		eof	{ fail "ktutil converting keytab to srvtab" ; set ok 0 }
+	    }
+	    expect "ktutil: "
+	    send "rkt $tmppwd/fookeytab\r"
+	    expect -ex "rkt $tmppwd/fookeytab\r"
+	    expect "ktutil: "
+# for debugging, just log this
+#	    send "list\r"
+#	    expect "ktutil: "
+	    #
+	    send "wst $tmppwd/foosrvtab\r"
+	    expect -ex "wst $tmppwd/foosrvtab\r"
+	    expect "ktutil: "
+# for debugging, just log this
+#	    send "clear\r"
+#	    expect "ktutil: "
+#	    send "rst $tmppwd/foosrvtab\r"
+#	    expect "ktutil: "
+#	    send "list\r"
+#	    expect "ktutil: "
+	    # okay, now quit and finish testing
+	    send "quit\r"
+	    expect eof
+	    catch expect_after
+	    if [check_exit_status "ktutil converting keytab to srvtab (vno $vno)"] {
+		pass "ktutil converting keytab to srvtab (vno $vno)"
+		do_klist_kt $tmppwd/fookeytab "klist srvtab foo/bar vno $vno"
+		kinit_kt "foo/bar" "SRVTAB:$tmppwd/foosrvtab" 1 "st kvno $vno"
+		do_klist "foo/bar" "krbtgt/$REALMNAME@$REALMNAME" "klist st foo/bar vno $vno"
+		do_kdestroy "kdestroy st foo/bar vno $vno"
+	    }
+	} else {
+	    verbose "skipping v5kinit/srvtab tests because of non-v4 enctype"
+	}
+    }
+    catch "exec rm -f $keytab"
+    # Check that kadmin.local can actually read the correct kvno, even
+    # if we don't expect kadmin to be able to.
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    set ok 1
+    expect_after {
+	timeout		{ fail "kadmin.local correct high kvno" ; set ok 0 }
+	eof		{ fail "kadmin.local correct high kvno" ; set ok 0 }
+    }
+    expect "kadmin.local: "
+    send "getprinc foo/bar\r"
+#    exec sleep 10
+    expect "Key: vno $vno,"
+    send "quit\r"
+    expect eof
+    if [check_exit_status "kadmin.local examine foo/bar for high kvno"] {
+	if $ok {
+	    pass "kadmin.local correct high kvno"
+	}
+    }
+}
+
+set status [catch doit msg]
+
+stop_kerberos_daemons
+
+if { $status != 0 } {
+    send_error "ERROR: error in standalone.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/v4gssftp.exp b/mechglue/src/tests/dejagnu/krb-standalone/v4gssftp.exp
new file mode 100644
index 000000000..e739e9bd9
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/v4gssftp.exp
@@ -0,0 +1,505 @@
+# Kerberos ftp test.
+# This is a DejaGnu test script.
+# This script tests Kerberos ftp.
+# Originally written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.
+# Modified bye Ezra Peisach for GSSAPI support.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/build/tests/dejagnu
+
+if ![info exists FTP] {
+    set FTP [findfile $objdir/../../appl/gssftp/ftp/ftp]
+}
+
+if ![info exists FTPD] {
+    set FTPD [findfile $objdir/../../appl/gssftp/ftpd/ftpd]
+}
+
+# If we do not have what is for a V4 test - return
+if ![v4_compatible_enctype] {
+    return
+}
+
+# Make sure .klogin is reasonable.
+if ![check_k5login ftp] {
+    return
+}
+
+if ![check_klogin ftp] {
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    return
+}
+
+# A procedure to start up the ftp daemon.
+
+proc start_ftp_daemon { } {
+    global FTPD
+    global tmppwd
+    global ftpd_spawn_id
+    global ftpd_pid
+    global portbase
+
+    # The -p argument tells it to accept a single connection, so we
+    # don't need to use inetd.  Portbase+8 is the port to listen at.
+    # We rely on KRB5_KTNAME being set to the proper keyfile as there is
+    # no way to cleanly set it with the gssapi API.
+    # The -U argument tells it to use an alternate ftpusers file (using
+    # /dev/null will allow root to login regardless of /etc/ftpusers).
+    # The -a argument requires authorization, to mitigate any
+    # vulnerability introduced by circumventing ftpusers.
+    spawn $FTPD -p [expr 8 + $portbase] -a -U /dev/null -r $tmppwd/krb.conf
+    set ftpd_spawn_id $spawn_id
+    set ftpd_pid [exp_pid]
+
+    # Give the ftp daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the ftp daemon.
+
+proc stop_ftp_daemon { } {
+    global ftpd_spawn_id
+    global ftpd_pid
+
+    if [info exists ftpd_pid] {
+	catch "close -i $ftpd_spawn_id"
+	catch "exec kill $ftpd_pid"
+	catch "wait -i $ftpd_spawn_id"
+	unset ftpd_pid
+    }
+}
+
+# Create a file to use for ftp testing.
+set file [open $tmppwd/ftp-test w]
+puts $file "This file is used for ftp testing."
+close $file
+
+# Create a large file to use for ftp testing. File needs to be 
+# larger that 2^20 or 1MB for PBSZ testing.
+set file [open $tmppwd/bigftp-test w]
+puts $file "This file is used for ftp testing.\n"
+seek $file 1048576 current
+puts $file "This file is used for ftp testing."
+close $file
+
+# Test that a file was copied correctly.
+proc check_file { filename {bigfile 0}} {
+    if ![file exists $filename] {
+	verbose "$filename does not exist"
+	send_log "$filename does not exist\n"
+	return 0
+    }
+
+    set file [open $filename r]
+    if { [gets $file line] == -1 } {
+	verbose "$filename is empty"
+	send_log "$filename is empty\n"
+	close $file
+	return 0
+    }
+
+    if ![string match "This file is used for ftp testing." $line] {
+	verbose "$filename contains $line"
+	send_log "$filename contains $line\n"
+	close $file
+	return 0
+    }
+
+    if {$bigfile} {
+	# + 1 for the newline
+	seek $file 1048577 current
+	if { [gets $file line] == -1 } {
+	    verbose "$filename is truncated"
+	    send_log "$filename is truncated\n"
+	    close $file
+	    return 0
+	}
+
+	if ![string match "This file is used for ftp testing." $line] {
+	    verbose "$filename contains $line"
+	    send_log "$filename contains $line\n"
+	    close $file
+	    return 0
+	}
+    }
+
+    if { [gets $file line] != -1} {
+	verbose "$filename is too long ($line)"
+	send_log "$filename is too long ($line)\n"
+	close $file
+	return 0
+    }
+
+    close $file
+
+    return 1
+}
+
+#
+# Restore environment variables possibly set.
+#
+proc ftp_restore_env { } {
+    global env
+    global ftp_save_ktname
+    global ftp_save_ccname
+
+    catch "unset env(KRB5_KTNAME)"
+    if [info exists ftp_save_ktname] {
+	set env(KRB5_KTNAME) $ftp_save_ktname
+	unset ftp_save_ktname
+    }
+
+    catch "unset env(KRB5CCNAME)"
+    if [info exists ftp_save_ccname] {
+	set env(KRB5CCNAME) $ftp_save_ccname
+	unset ftp_save_ccname
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc v4ftp_test { } {
+    global FTP
+    global KEY
+    global REALMNAME
+    global hostname
+    global localhostname
+    global env
+    global ftpd_spawn_id
+    global ftpd_pid
+    global spawn_id
+    global tmppwd
+    global ftp_save_ktname
+    global ftp_save_ccname
+    global des3_krbtgt
+    global portbase
+
+    if {$des3_krbtgt} {
+	return
+    }
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_random_key ftp/$hostname 0] \
+        || ![setup_srvtab 0 ftp] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![v4kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    #
+    # Save settings of KRB5_KTNAME
+    #
+    if [info exists env(KRB5_KTNAME)] {
+	set ftp_save_ktname $env(KRB5_KTNAME)
+    }
+
+    #
+    # set KRB5_KTNAME
+    #
+    set env(KRB5_KTNAME) FILE:$tmppwd/srvtab
+    verbose "KRB5_KTNAME=$env(KRB5_KTNAME)"
+
+    #
+    # Save settings of KRB5CCNAME
+    # These tests fail if the krb5 cache happens to have a valid credential
+    # which can result from running the gssftp.exp test immediately
+    # preceeding these tests.
+    #
+    if [info exists env(KRB5CCNAME)] {
+	set ftp_save_ccname $env(KRB5CCNAME)
+    }
+
+    #
+    # set KRB5_KTNAME
+    #
+    set env(KRB5CCNAME) FILE:$tmppwd/non-existant-cache
+    verbose "KRB5CCNAME=$env(KRB5CCNAME)"
+
+    # Start the ftp daemon.
+    start_ftp_daemon
+
+    # Make an ftp client connection to it.
+    spawn $FTP $hostname [expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "ftp connection(v4)"
+    expect -nocase "connected to $hostname"
+    expect -nocase -re "$localhostname.*ftp server .version \[0-9.\]*. ready."
+    expect -re "Using authentication type GSSAPI; ADAT must follow"
+    expect "GSSAPI accepted as authentication type"
+    expect "GSSAPI error major: Miscellaneous failure"
+    expect {
+	"GSSAPI error minor: Unsupported credentials cache format version number" {}
+	"GSSAPI error minor: No credentials cache found" {}
+	"GSSAPI error minor: Decrypt integrity check failed" {}
+    }
+    expect "GSSAPI error: initializing context"
+    expect "GSSAPI authentication failed"
+    expect -re "Using authentication type KERBEROS_V4; ADAT must follow"
+    expect {
+	"Kerberos V4 authentication succeeded" { pass "ftp authentication" }
+	eof	{ fail "ftp authentication" ; catch "expect_after" ; return }
+	-re "Kerberos V4 .* failed.*\r" {
+	    fail "ftp authentication";
+	    send "quit\r"; catch "expect_after";
+	    return
+	}
+    }
+    expect -nocase "name ($hostname:$env(USER)): "
+    send "$env(USER)\r"
+    expect "Kerberos user $env(USER)@$REALMNAME is authorized as $env(USER)"
+    expect "Remote system type is UNIX."
+    expect "Using binary mode to transfer files."
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "binary(v4)"
+    send "binary\r"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "status(v4)"
+    send "status\r"
+    expect -nocase "connected to $hostname."
+    expect "Authentication type: KERBEROS_V4"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "ls(v4)"
+    send "ls $tmppwd/ftp-test\r"
+    expect -re "Opening ASCII mode data connection for .*ls."
+    expect -re ".* $tmppwd/ftp-test"
+    expect "ftp> " {
+	pass $testname
+    } 
+
+    set testname "nlist(v4)"
+    send "nlist $tmppwd/ftp-test\r"
+    expect -re "Opening ASCII mode data connection for file list."
+    expect -re "$tmppwd/ftp-test"
+    expect -re ".* Transfer complete."
+    expect "ftp> " {
+	pass $testname
+    } 
+
+    set testname "ls missing(v4)"
+    send "ls $tmppwd/ftp-testmiss\r"
+    expect -re "Opening ASCII mode data connection for .*ls."
+    expect {
+	-re "$tmppwd/ftp-testmiss not found" {}
+	-re "$tmppwd/ftp-testmiss: No such file or directory"
+    }
+    expect "ftp> " {
+	pass $testname
+    } 
+
+
+    set testname "get(v4)"
+    catch "exec rm -f $tmppwd/copy"
+    send "get $tmppwd/ftp-test $tmppwd/copy\r"
+    expect "Opening BINARY mode data connection for $tmppwd/ftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "put(v4)"
+    catch "exec rm -f $tmppwd/copy"
+    send "put $tmppwd/ftp-test $tmppwd/copy\r"
+    expect "Opening BINARY mode data connection for $tmppwd/copy"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes sent in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "cd(v4)"
+    send "cd $tmppwd\r"
+    expect "CWD command successful."
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "lcd(v4)"
+    send "lcd $tmppwd\r"
+    expect "Local directory now $tmppwd"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "local get(v4)"
+    catch "exec rm -f $tmppwd/copy"
+    send "get ftp-test copy\r"
+    expect "Opening BINARY mode data connection for ftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "big local get(v4)"
+    catch "exec rm -f $tmppwd/copy"
+    send "get bigftp-test copy\r"
+    expect "Opening BINARY mode data connection for bigftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy 1] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "start encryption(v4)"
+    send "private\r"
+    expect "Data channel protection level set to private"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "status(v4)"
+    send "status\r"
+    expect "Protection Level: private"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "encrypted get(v4)"
+    catch "exec rm -f $tmppwd/copy"
+    send "get ftp-test copy\r"
+    expect "Opening BINARY mode data connection for ftp-test"
+    expect "Transfer complete"
+    expect {
+	-re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds" {}
+	-re "krb_rd_priv failed for KERBEROS_V4" {
+	    fail $testname
+	    send "quit\r"
+	    catch "expect_after"
+	    return
+	}
+    }
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+
+    # Test a large file that will overflow PBSZ size
+    set testname "big encrypted get(v4)"
+    catch "exec rm -f $tmppwd/copy"
+    send "get bigftp-test copy\r"
+    expect "Opening BINARY mode data connection for bigftp-test"
+    expect "Transfer complete"
+    expect {
+	-re "\[0-9\]+ bytes received in \[0-9.e+-\]+ seconds" {}
+	-re "krb_rd_priv failed for KERBEROS_V4" {
+	    fail $testname
+	    send "quit\r"
+	    catch "expect_after"
+	    return
+	}
+    }
+    expect "ftp> "
+    if [check_file $tmppwd/copy 1] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "close(v4)"
+    send "close\r"
+    expect "Goodbye."
+    expect "ftp> "
+    set status_list [wait -i $ftpd_spawn_id]
+    verbose "wait -i $ftpd_spawn_id returned $status_list ($testname)"
+    catch "close -i $ftpd_spawn_id"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } {
+	send_log "exit status: $status_list\n"
+	verbose "exit status: $status_list"
+	fail $testname
+    } else {
+	pass $testname
+	unset ftpd_pid
+    }
+
+    set testname "quit(v4)"
+    send "quit\r"
+    expect_after
+    expect eof
+    if [check_exit_status $testname] {
+	pass $testname
+    }
+
+}
+
+# The ftp client will look in $HOME/.netrc for the user name to use.
+# To avoid confusing the testsuite, point $HOME at a directory where
+# we know there is no .netrc file.
+if [info exists env(HOME)] {
+    set home $env(HOME)
+} elseif [info exists home] {
+    unset home
+}
+set env(HOME) $tmppwd
+
+# Run the test.  Logging in sometimes takes a while, so increase the
+# timeout.
+set oldtimeout $timeout
+set timeout 60
+set status [catch v4ftp_test msg]
+set timeout $oldtimeout
+
+# Shut down the kerberos daemons and the ftp daemon.
+stop_kerberos_daemons
+
+stop_ftp_daemon
+
+ftp_restore_env
+
+# Reset $HOME, for safety in case we are going to run more tests.
+if [info exists home] {
+    set env(HOME) $home
+} else {
+    unset env(HOME)
+}
+
+if { $status != 0 } {
+    perror "error in v4gssftp.exp: $msg"
+}
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/v4krb524d.exp b/mechglue/src/tests/dejagnu/krb-standalone/v4krb524d.exp
new file mode 100644
index 000000000..d78f14ba3
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/v4krb524d.exp
@@ -0,0 +1,168 @@
+# Standalone Kerberos test.
+# This is a DejaGnu test script.
+# This script tests that the Kerberos tools can talk to each other.
+
+# This mostly just calls procedures in testsuite/config/default.exp.
+
+if ![info exists K524INIT] {
+    set K524INIT [findfile $objdir/../../krb524/k524init]
+}
+
+if ![info exists KRB524D] {
+    set KRB524D [findfile $objdir/../../krb524/krb524d]
+}
+
+if ![info exists KLIST] {
+    set KLIST [findfile $objdir/../../clients/klist/klist]
+}
+
+if ![info exists KDESTROY] {
+    set KDESTROY [findfile $objdir/../../clients/kdestroy/kdestroy]
+}
+
+# Set up the Kerberos files and environment.
+if {![get_hostname] || ![setup_kerberos_files] || ![setup_kerberos_env]} {
+    return
+}
+
+# If we do not have what is for a V4 test - return
+if ![v4_compatible_enctype] {
+    return
+}
+
+# Initialize the Kerberos database.  The argument tells
+# setup_kerberos_db that it is being called from here.
+if ![setup_kerberos_db 1] {
+    return
+}
+
+# A procedure to stop the krb524 daemon.
+proc start_k524_daemon { } {
+    global KRB524D
+    global k524d_spawn_id
+    global k524d_pid
+    global REALMNAME
+    global portbase
+
+    spawn $KRB524D -m -p [expr 7 + $portbase] -r $REALMNAME -nofork
+    set k524d_spawn_id $spawn_id
+    set k524d_pid [exp_pid]
+
+    # Give the krb524d daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the krb524 daemon.
+proc stop_k524_daemon { } {
+    global k524d_spawn_id
+    global k524d_pid
+
+    if [info exists k524d_pid] {
+	catch "close -i $k524d_spawn_id"
+	catch "exec kill $k524d_pid"
+	catch "wait -i $k524d_spawn_id"
+	unset k524d_pid
+    }
+}
+
+# We are about to start up a couple of daemon processes.  We do all
+# the rest of the tests inside a proc, so that we can easily kill the
+# processes when the procedure ends.
+
+proc doit { } {
+    global env
+    global KEY
+    global K524INIT
+    # To pass spawn_id to the wait process
+    global spawn_id
+    global KLIST
+    global KDESTROY
+    global tmppwd
+    global REALMNAME
+    global des3_krbtgt
+
+    if {$des3_krbtgt} {
+	return
+    }
+    # Start up the kerberos and kadmind daemons.
+    if ![start_kerberos_daemons 1] {
+	return
+    }
+
+    # Add a user key and get a V5 ticket
+    if {![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    # Start the krb524d daemon.
+    start_k524_daemon
+
+    # The k524init program does not advertise anything on success -
+    #only failure.
+    spawn $K524INIT
+    expect {
+	-timeout 10 
+	-re "k524init: .*\r" {
+	    fail "k524init"
+	    return
+	}
+	eof {}
+	timeout {}
+    }
+
+
+    if ![check_exit_status "k524init"] {
+	return
+    }
+    pass "k524init"
+
+    # Make sure that klist can see the ticket.
+    spawn $KLIST -4
+    expect {
+	-re "Kerberos 4 ticket cache:\[ 	\]*(.+:)?$tmppwd/tkt.*Principal:\[ 	\]*$env(USER)@$REALMNAME.*krbtgt\.$REALMNAME@$REALMNAME\r\n" {
+	    verbose "klist started"
+	}
+	timeout {
+	    fail "v4klist"
+	    return
+	}
+	eof {
+	    fail "v4klist"
+	    return
+	}
+    }
+
+    expect {
+        "\r" { }
+	eof { }
+    }
+
+    if ![check_exit_status "klist"] {
+	return
+    }
+    pass "krb524d: v4klist"
+
+    # Destroy the ticket.
+    spawn $KDESTROY -4
+    if ![check_exit_status "kdestroy"] {
+	return
+    }
+    pass "krb524d: v4kdestroy"
+
+    pass "krb524d: krb524d"
+}
+
+set status [catch doit msg]
+
+stop_kerberos_daemons
+
+stop_k524_daemon
+
+if { $status != 0 } {
+    send_error "ERROR: error in v4krb524d.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
+
+
diff --git a/mechglue/src/tests/dejagnu/krb-standalone/v4standalone.exp b/mechglue/src/tests/dejagnu/krb-standalone/v4standalone.exp
new file mode 100644
index 000000000..cc42e8dab
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/krb-standalone/v4standalone.exp
@@ -0,0 +1,95 @@
+# Standalone Kerberos test.
+# This is a DejaGnu test script.
+# This script tests that the Kerberos tools can talk to each other.
+
+# This mostly just calls procedures in testsuite/config/default.exp.
+
+# Set up the Kerberos files and environment.
+if {![get_hostname] || ![setup_kerberos_files] || ![setup_kerberos_env]} {
+    return
+}
+
+# If we do not have what is for a V4 test - return
+if ![v4_compatible_enctype] {
+    return
+}
+
+# Initialize the Kerberos database.  The argument tells
+# setup_kerberos_db that it is being called from here.
+if ![setup_kerberos_db 1] {
+    return
+}
+
+# We are about to start up a couple of daemon processes.  We do all
+# the rest of the tests inside a proc, so that we can easily kill the
+# processes when the procedure ends.
+
+proc check_and_destroy_v4_tix { client server } {
+    global REALMNAME
+    global des3_krbtgt
+
+    # Skip this if we're using a des3 TGT, since that's supposed to fail.
+    if {$des3_krbtgt} {
+	return
+    }
+    # Make sure that klist can see the ticket.
+    if ![v4klist "$client" "$server" "v4klist"] {
+	return
+    }
+
+    # Destroy the ticket.
+    if ![v4kdestroy "v4kdestroy"] {
+	return
+    }
+
+    if ![v4klist_none "v4klist no tix 1"] {
+	return
+    }
+}
+
+proc doit { } {
+    global REALMNAME
+    global KLIST
+    global KDESTROY
+    global KEY
+    global hostname
+    global spawn_id
+    global tmppwd
+
+    # Start up the kerberos and kadmind daemons.
+    if ![start_kerberos_daemons 1] {
+	return
+    }
+
+    # Use kadmin to add an host key.
+    if ![add_random_key host/$hostname 1] {
+	return
+    }
+
+    # Use ksrvutil to create a srvtab entry.
+    if ![setup_srvtab 1] {
+	return
+    }
+
+    # Use kinit to get a ticket.
+    if [v4kinit krbtest.admin adminpass$KEY 1] {
+	check_and_destroy_v4_tix krbtest.admin@$REALMNAME krbtgt.$REALMNAME@$REALMNAME
+    }
+
+    # Use kinit with srvtab to get a ticket.
+    # XXX - Currently kinit doesn't support "-4 -k"!
+#    set shorthost [string range $hostname 0 [expr [string first . $hostname] - 1]]
+#    if [v4kinit_kt host.$shorthost SRVTAB:$tmppwd/srvtab 1] {
+#	check_and_destroy_v4_tix host.$shorthost@$REALMNAME krbtgt.$REALMNAME@$REALMNAME
+#    }
+}
+
+set status [catch doit msg]
+
+stop_kerberos_daemons
+
+if { $status != 0 } {
+    send_error "ERROR: error in v4standalone.exp\n"
+    send_error "$msg\n"
+    exit 1
+}
diff --git a/mechglue/src/tests/dejagnu/t_inetd.c b/mechglue/src/tests/dejagnu/t_inetd.c
new file mode 100644
index 000000000..80835b58b
--- /dev/null
+++ b/mechglue/src/tests/dejagnu/t_inetd.c
@@ -0,0 +1,139 @@
+/*
+ * tests/dejagnu/t_inetd.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * A simple program to simulate starting a process from inetd.
+ *
+ * Unlike a proper inetd situation, environment variables are passed 
+ * to the client.
+ *
+ * usage: t_inetd port program argv0 ...
+ *		
+ */
+
+
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "com_err.h"
+
+
+char *progname;
+
+static void usage()
+{
+	fprintf(stderr, "%s: port program argv0 argv1 ...\n", progname);
+	exit(1);
+}
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+	unsigned short port;
+	char *path;
+	int sock, acc;
+	int one = 1;
+	struct sockaddr_in l_inaddr, f_inaddr;	/* local, foreign address */
+	int namelen = sizeof(f_inaddr);
+#ifdef POSIX_SIGNALS
+	struct sigaction csig;
+#endif
+
+	progname = argv[0];
+
+	if(argc <= 3) usage();
+
+	if(atoi(argv[1]) == 0) usage();
+
+	port = htons(atoi(argv[1]));
+	path = argv[2];
+
+	if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+	    com_err(progname, errno, "creating socket");
+	    exit(3);
+	}
+
+	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
+			  sizeof (one));
+
+	l_inaddr.sin_family = AF_INET;
+	l_inaddr.sin_addr.s_addr = 0;
+	l_inaddr.sin_port = port;
+
+	if (bind(sock, (struct sockaddr *)&l_inaddr, sizeof(l_inaddr))) {
+	    com_err(progname, errno, "binding socket");
+	    exit(3);
+	}
+
+	if (listen(sock, 1) == -1) {
+	    com_err(progname, errno, "listening");
+	    exit(3);
+	}
+
+	if ((acc = accept(sock, (struct sockaddr *)&f_inaddr,
+			  &namelen)) == -1) {
+	    com_err(progname, errno, "accepting");
+	    exit(3);
+	}
+
+	dup2(acc, 0);
+	dup2(acc, 1);
+	dup2(acc, 2);
+	close(sock);
+	sock = 0;
+
+	/* Don't wait for a child signal... Otherwise dejagnu gets confused */
+#ifdef POSIX_SIGNALS
+	csig.sa_handler = (RETSIGTYPE (*)())0;
+	sigemptyset(&csig.sa_mask);
+	csig.sa_flags = 0;
+	sigaction(SIGCHLD, &csig, (struct sigaction *)0);
+#else
+	signal(SIGCHLD, SIG_IGN);
+#endif
+
+	if(execv(path, &argv[3]))
+		fprintf(stderr, "t_inetd: Could not exec %s\n", path);
+	exit(1);
+}
+
diff --git a/mechglue/src/tests/dump.c b/mechglue/src/tests/dump.c
new file mode 100644
index 000000000..1e40ffeda
--- /dev/null
+++ b/mechglue/src/tests/dump.c
@@ -0,0 +1,43 @@
+/*
+ * tests/dump.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Dump out a krb5_data to stderr (for debugging purposes).
+ */
+
+#include <stdio.h>
+#include "krb5.h"
+
+void dump_data (data)
+    krb5_data *data;
+{
+    unsigned char *ptr = (unsigned char *)data->data;
+    int i;
+    for (i=0; i<data->length; i++) {
+	fprintf(stderr, "%02x ", ptr[i]);
+	if ((i % 16) == 15) fprintf(stderr, "\n");
+    }
+    fprintf(stderr, "\n");    
+}
diff --git a/mechglue/src/tests/gss-threads/ChangeLog b/mechglue/src/tests/gss-threads/ChangeLog
new file mode 100644
index 000000000..ae92cd926
--- /dev/null
+++ b/mechglue/src/tests/gss-threads/ChangeLog
@@ -0,0 +1,22 @@
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (gss-client, gss-server): Use THREAD_LINKOPTS
+	instead of PTHREAD_LIBS.
+
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-unix): Use @THREAD_SUPPORT@ and helper targets
+	to build programs only if thread support is enabled.
+	(all-unix-0, all-unix-1): New helper targets.
+
+2005-02-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss-misc.c: Include autoconf.h.  If both time.h and sys/time.h
+	are available, and they're compatible, include both.
+
+2005-02-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* New directory.
+	* All files copies from appl/gss-sample, with Jeff Altman's
+	changes for multithreading on Windows, and mine for pthreads.
+
diff --git a/mechglue/src/tests/gss-threads/Makefile.in b/mechglue/src/tests/gss-threads/Makefile.in
new file mode 100644
index 000000000..827399ee9
--- /dev/null
+++ b/mechglue/src/tests/gss-threads/Makefile.in
@@ -0,0 +1,54 @@
+# Derived from appl/gss-sample, January 2005.
+
+thisconfigdir=./..
+myfulldir=tests/gss-threads
+mydir=gss-threads
+BUILDTOP=$(REL)..$(S)..
+DEFINES = -DUSE_AUTOCONF_H -DGSSAPI_V2
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+PTHREAD_LIBS=@PTHREAD_LIBS@
+
+SRCS= $(srcdir)/gss-client.c $(srcdir)/gss-misc.c $(srcdir)/gss-server.c
+
+OBJS= gss-client.o gss-misc.o gss-server.o
+
+all-unix:: all-unix-@THREAD_SUPPORT@
+all-unix-1:: gss-server gss-client
+all-unix-0::
+all-windows:: $(OUTPRE)gss-server.exe $(OUTPRE)gss-client.exe
+
+gss-server: gss-server.o gss-misc.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) $(PTHREAD_CFLAGS) -o gss-server gss-server.o gss-misc.o $(GSS_LIBS) $(KRB5_BASE_LIBS) $(THREAD_LINKOPTS)
+
+gss-client: gss-client.o gss-misc.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) $(PTHREAD_CFLAGS) -o gss-client gss-client.o gss-misc.o $(GSS_LIBS) $(KRB5_BASE_LIBS) $(THREAD_LINKOPTS)
+
+$(OUTPRE)gss-server.exe: $(OUTPRE)gss-server.obj $(OUTPRE)gss-misc.obj $(GLIB) $(KLIB)
+	link $(EXE_LINKOPTS) -out:$@ $** ws2_32.lib
+
+$(OUTPRE)gss-client.exe: $(OUTPRE)gss-client.obj $(OUTPRE)gss-misc.obj $(GLIB) $(KLIB)
+	link $(EXE_LINKOPTS) -out:$@ $** ws2_32.lib
+
+clean-unix::
+	$(RM) gss-server gss-client
+
+install-unix::
+#	$(INSTALL_PROGRAM) gss-client $(DESTDIR)$(CLIENT_BINDIR)/gss-tclient
+#	$(INSTALL_PROGRAM) gss-server $(DESTDIR)$(SERVER_BINDIR)/gss-tserver
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)gss-client.$(OBJEXT): gss-client.c $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gss-misc.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/fake-addrinfo.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h
+$(OUTPRE)gss-misc.$(OBJEXT): gss-misc.c $(BUILDTOP)/include/krb5/autoconf.h \
+  $(BUILDTOP)/include/gssapi/gssapi_generic.h $(BUILDTOP)/include/gssapi/gssapi.h \
+  gss-misc.h
+$(OUTPRE)gss-server.$(OBJEXT): gss-server.c $(BUILDTOP)/include/gssapi/gssapi_generic.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h gss-misc.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
diff --git a/mechglue/src/tests/gss-threads/README b/mechglue/src/tests/gss-threads/README
new file mode 100644
index 000000000..f555b3e3a
--- /dev/null
+++ b/mechglue/src/tests/gss-threads/README
@@ -0,0 +1,165 @@
+[Out of date; needs updating for thread safety test support.  -- KR 2005-02-09]
+
+# Copyright 1993 by OpenVision Technologies, Inc.
+# 
+# Permission to use, copy, modify, distribute, and sell this software
+# and its documentation for any purpose is hereby granted without fee,
+# provided that the above copyright notice appears in all copies and
+# that both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of OpenVision not be used
+# in advertising or publicity pertaining to distribution of the software
+# without specific, written prior permission. OpenVision makes no
+# representations about the suitability of this software for any
+# purpose.  It is provided "as is" without express or implied warranty.
+# 
+# OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+# EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+This directory contains a sample GSS-API client and server
+application.  In addition to serving as an example of GSS-API
+programming, this application is also intended to be a tool for
+testing the performance of GSS-API implementations.
+
+Each time the client is invoked, it performs one or more exchanges
+with the server.  Each exchange with the server consists primarily of
+the following steps:
+
+	1. A TCP/IP connection is established.
+
+	2. (optional, on by default) The client and server establish a
+	   GSS-API context, and the server prints the identify of the
+	   client.
+
+      /	3. The client sends a message to the server.  The message may
+     /     be plaintext, cryptographically "signed" but not encrypted,
+     |     or encrypted (default).
+     |
+0 or |  4. The server decrypts the message (if necessary), verifies
+more |     its signature (if there is one) and prints it.
+times|
+     |  5. The server sends either a signature block (the default) or an
+     |     empty token back to the client to acknowledge the message.
+     \
+      \ 6. If the server sent a signature block, the client verifies
+           it and prints a message indicating that it was verified.
+  
+	7. The client sends an empty block to the server to tell it
+	   that the exchange is finished.
+  
+	8. The client and server close the TCP/IP connection and
+	   destroy the GSS-API context.
+
+The client also supports the -v1 flag which uses an older exchange
+format compatible with previous releases of Kerberos and with samples
+shipped in the Microsoft SDK.
+  
+The server's command line usage is
+  
+	gss-server [-port port] [-verbose] [-once] [-inetd] [-export]
+		[-logfile file] service_name
+  
+where service_name is a GSS-API service name of the form
+"service@host" (or just "service", in which case the local host name
+is used).  The command-line options have the following meanings:
+  
+-port	The TCP port on which to accept connections.  Default is 4444.
+  
+-once	Tells the server to exit after a single exchange, rather than
+	persisting.
+  
+-inetd	Tells the server that it is running out of inetd, so it should
+	interact with the client on stdin rather than binding to a
+	network port.  Implies "-once".
+  
+-export	Tells the server to test the gss_export_sec_context function
+	after establishing a context with a client.
+
+-logfile
+	The file to which the server should append its output, rather
+	than sending it to stdout.
+  
+The client's command line usage is
+
+	gss-client [-port port] [-mech mechanism] [-d] [-f] [-q]
+        [-seq] [-noreplay] [-nomutual]		
+        [-ccount count] [-mcount count] [-na] [-nw] [-nx] [-nm]
+		host service_name msg
+
+where host is the host running the server, service_name is the service
+name that the server will establish connections as (if you don't
+specify the host name in the service name when running gss-server, and
+it's running on a different machine from gss-client, make sure to
+specify the server's host name in the service name you specify to
+gss-client!) and msg is the message.  The command-line options have
+the following meanings:
+
+-port	The TCP port to which to connect.  Default is 4444.
+
+-mech	The OID of the GSS-API mechanism to use.
+
+-d	Tells the client to delegate credentials to the server.  For
+	the Kerberos GSS-API mechanism, this means that a forwardable
+	TGT will be sent to the server, which will put it in its
+	credential cache (you must have acquired your tickets with
+	"kinit -f" for this to work).
+
+-seq Tells the client to enforce ordered message delivery via
+    sequencing.  
+
+-noreplay Tells the client to disable the use of replay
+    detection.
+
+-nomutual Tells the client to disable the use of mutual authentication.
+
+-f	Tells the client that the "msg" argument is actually the name
+	of a file whose contents should be used as the message.
+
+-q	Tells the client to be quiet, i.e., to only print error
+	messages.
+
+-ccount	Specifies how many sessions the client should initiate with
+	the server (the "connection count").
+
+-mcount	Specifies how many times the message should be sent to the
+	server in each session (the "message count").
+
+-na	Tells the client not to do any authentication with the
+	server.  Implies "-nw", "-nx" and "-nm".
+
+-nw	Tells the client not to "wrap" messages.  Implies "-nx".
+
+-nx	Tells the client not to encrypt messages.
+
+-nm	Tells the client not to ask the server to send back a
+	cryptographic checksum ("MIC").
+
+To run the server on a host, you need to make sure that the principal
+corresponding to service_name is in the default keytab on the server
+host, and that the gss-server process can read the keytab.  For
+example, the service name "host@server" corresponds to the Kerberos
+principal "host/server.domain.com@REALM".
+
+This sample application uses the following GSS-API functions:
+
+	gss_accept_sec_context		gss_inquire_names_for_mech
+	gss_acquire_cred		gss_oid_to_str
+	gss_delete_sec_context		gss_release_buffer
+	gss_display_name		gss_release_cred
+	gss_display_status		gss_release_name
+	gss_export_sec_context		gss_release_oid
+	gss_get_mic			gss_release_oid_set
+	gss_import_name			gss_str_to_oid
+	gss_import_sec_context		gss_unwrap
+	gss_init_sec_context		gss_verify_mic
+	gss_inquire_context		gss_wrap
+  
+This application was originally written by Barry Jaspan of OpenVision
+Technologies, Inc.  It was updated significantly by Jonathan Kamens of
+OpenVision Technologies, Inc.
+
+$Id$
diff --git a/mechglue/src/tests/gss-threads/gss-client.c b/mechglue/src/tests/gss-threads/gss-client.c
new file mode 100644
index 000000000..f199dc252
--- /dev/null
+++ b/mechglue/src/tests/gss-threads/gss-client.c
@@ -0,0 +1,883 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 2003, 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock.h>
+#else
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#endif
+
+#include <gssapi/gssapi_generic.h>
+#include "gss-misc.h"
+#include "port-sockets.h"
+#include "fake-addrinfo.h"
+
+static int verbose = 1;
+
+static void usage()
+{
+     fprintf(stderr, "Usage: gss-client [-port port] [-mech mechanism] [-d]\n");
+     fprintf(stderr, "       [-seq] [-noreplay] [-nomutual]");
+     fprintf(stderr, " [-threads num]");
+     fprintf(stderr, "\n");
+     fprintf(stderr, "       [-f] [-q] [-ccount count] [-mcount count]\n");
+     fprintf(stderr, "       [-v1] [-na] [-nw] [-nx] [-nm] host service msg\n");
+     exit(1);
+}
+
+/*
+ * Function: get_server_info
+ *
+ * Purpose: Sets up a socket address for the named host and port.
+ *
+ * Arguments:
+ *
+ * 	host		(r) the target host name
+ * 	port		(r) the target port, in host byte order
+ *
+ * Returns: 0 on success, or -1 on failure
+ *
+ * Effects:
+ *
+ * The host name is resolved with gethostbyname(), and "saddr" is set
+ * to the desired socket address.  If an error occurs, an error
+ * message is displayed and -1 is returned.
+ */
+struct sockaddr_in saddr;
+static int get_server_info(host, port)
+    char *host;
+    u_short port;
+{
+     struct hostent *hp;
+
+     if ((hp = gethostbyname(host)) == NULL) {
+	  fprintf(stderr, "Unknown host: %s\n", host);
+	  return -1;
+     }
+     
+     saddr.sin_family = hp->h_addrtype;
+     memcpy((char *)&saddr.sin_addr, hp->h_addr, sizeof(saddr.sin_addr));
+     saddr.sin_port = htons(port);
+     return 0;
+}
+
+/*
+ * Function: connect_to_server
+ *
+ * Purpose: Opens a TCP connection to the name host and port.
+ *
+ * Arguments:
+ *
+ * 	host		(r) the target host name
+ * 	port		(r) the target port, in host byte order
+ *
+ * Returns: the established socket file desciptor, or -1 on failure
+ *
+ * Effects:
+ *
+ * The host name is resolved with gethostbyname(), and the socket is
+ * opened and connected.  If an error occurs, an error message is
+ * displayed and -1 is returned.
+ */
+static int connect_to_server()
+{
+    int s;
+
+     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	  perror("creating socket");
+	  return -1;
+     }
+     if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+	  perror("connecting to server");
+	  (void) closesocket(s);
+	  return -1;
+     }
+     return s;
+}
+
+/*
+ * Function: client_establish_context
+ *
+ * Purpose: establishes a GSS-API context with a specified service and
+ * returns the context handle
+ *
+ * Arguments:
+ *
+ * 	s		    (r) an established TCP connection to the service
+ * 	service_name(r) the ASCII service name of the service
+ *	gss_flags	(r) GSS-API delegation flag (if any)
+ *	auth_flag	(r) whether to actually do authentication
+ *  v1_format   (r) whether the v1 sample protocol should be used
+ *	oid		    (r) OID of the mechanism to use
+ * 	context		(w) the established GSS-API context
+ *	ret_flags	(w) the returned flags from init_sec_context
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * service_name is imported as a GSS-API name and a GSS-API context is
+ * established with the corresponding service; the service should be
+ * listening on the TCP connection s.  The default GSS-API mechanism
+ * is used, and mutual authentication and replay detection are
+ * requested.
+ * 
+ * If successful, the context handle is returned in context.  If
+ * unsuccessful, the GSS-API error messages are displayed on stderr
+ * and -1 is returned.
+ */
+static int client_establish_context(s, service_name, gss_flags, auth_flag,
+				    v1_format, oid, gss_context, ret_flags)
+     int s;
+     char *service_name;
+     gss_OID oid;
+     OM_uint32 gss_flags;
+     int auth_flag;
+     int v1_format;
+     gss_ctx_id_t *gss_context;
+     OM_uint32 *ret_flags;
+{
+     if (auth_flag) {
+       gss_buffer_desc send_tok, recv_tok, *token_ptr;
+       gss_name_t target_name;
+       OM_uint32 maj_stat, min_stat, init_sec_min_stat;
+       int token_flags;
+
+       /*
+	* Import the name into target_name.  Use send_tok to save
+	* local variable space.
+	*/
+       send_tok.value = service_name;
+       send_tok.length = strlen(service_name) ;
+       maj_stat = gss_import_name(&min_stat, &send_tok,
+				  (gss_OID) gss_nt_service_name, &target_name);
+       if (maj_stat != GSS_S_COMPLETE) {
+	 display_status("parsing name", maj_stat, min_stat);
+	 return -1;
+       }
+     
+       if (!v1_format) {
+	 if (send_token(s, TOKEN_NOOP|TOKEN_CONTEXT_NEXT, empty_token) < 0) {
+	   (void) gss_release_name(&min_stat, &target_name);
+	   return -1;
+	 }
+       }
+
+       /*
+	* Perform the context-establishement loop.
+	*
+	* On each pass through the loop, token_ptr points to the token
+	* to send to the server (or GSS_C_NO_BUFFER on the first pass).
+	* Every generated token is stored in send_tok which is then
+	* transmitted to the server; every received token is stored in
+	* recv_tok, which token_ptr is then set to, to be processed by
+	* the next call to gss_init_sec_context.
+	* 
+	* GSS-API guarantees that send_tok's length will be non-zero
+	* if and only if the server is expecting another token from us,
+	* and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
+	* and only if the server has another token to send us.
+	*/
+     
+       token_ptr = GSS_C_NO_BUFFER;
+       *gss_context = GSS_C_NO_CONTEXT;
+
+       do {
+	 maj_stat =
+	   gss_init_sec_context(&init_sec_min_stat,
+				GSS_C_NO_CREDENTIAL,
+				gss_context,
+				target_name,
+				oid,
+				gss_flags,
+				0,
+				NULL,	/* no channel bindings */
+				token_ptr,
+				NULL,	/* ignore mech type */
+				&send_tok,
+				ret_flags,
+				NULL);	/* ignore time_rec */
+
+	 if (token_ptr != GSS_C_NO_BUFFER)
+	   free (recv_tok.value);
+
+	 if (send_tok.length != 0) {
+	   if (verbose)
+	     printf("Sending init_sec_context token (size=%d)...",
+		    (int) send_tok.length);
+	   if (send_token(s, v1_format?0:TOKEN_CONTEXT, &send_tok) < 0) {
+	     (void) gss_release_buffer(&min_stat, &send_tok);
+	     (void) gss_release_name(&min_stat, &target_name);
+	     if (*gss_context != GSS_C_NO_CONTEXT) {
+		 gss_delete_sec_context(&min_stat, gss_context,
+					GSS_C_NO_BUFFER);
+		 *gss_context = GSS_C_NO_CONTEXT;
+	     }
+	     return -1;
+	   }
+	 }
+	 (void) gss_release_buffer(&min_stat, &send_tok);
+ 
+	 if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
+	      display_status("initializing context", maj_stat,
+			     init_sec_min_stat);
+	      (void) gss_release_name(&min_stat, &target_name);
+	      if (*gss_context != GSS_C_NO_CONTEXT)
+		      gss_delete_sec_context(&min_stat, gss_context,
+					     GSS_C_NO_BUFFER);
+	      return -1;
+	 }
+	  
+	 if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+	   if (verbose)
+	     printf("continue needed...");
+	   if (recv_token(s, &token_flags, &recv_tok) < 0) {
+	     (void) gss_release_name(&min_stat, &target_name);
+	     return -1;
+	   }
+	   token_ptr = &recv_tok;
+	 }
+	 if (verbose)
+	   printf("\n");
+       } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+       (void) gss_release_name(&min_stat, &target_name);
+     }
+     else {
+       if (send_token(s, TOKEN_NOOP, empty_token) < 0)
+	 return -1;
+     }
+
+     return 0;
+}
+
+static void read_file(file_name, in_buf)
+    char		*file_name;
+    gss_buffer_t	in_buf;
+{
+    int fd, count;
+    struct stat stat_buf;
+    
+    if ((fd = open(file_name, O_RDONLY, 0)) < 0) {
+	perror("open");
+	fprintf(stderr, "Couldn't open file %s\n", file_name);
+	exit(2);
+    }
+    if (fstat(fd, &stat_buf) < 0) {
+	perror("fstat");
+	exit(3);
+    }
+    in_buf->length = stat_buf.st_size;
+
+    if (in_buf->length == 0) {
+	in_buf->value = NULL;
+	return;
+    }
+
+    if ((in_buf->value = malloc(in_buf->length)) == 0) {
+	fprintf(stderr, "Couldn't allocate %d byte buffer for reading file\n",
+		(int) in_buf->length);
+	exit(4);
+    }
+
+    /* this code used to check for incomplete reads, but you can't get
+       an incomplete read on any file for which fstat() is meaningful */
+
+    count = read(fd, in_buf->value, in_buf->length);
+    if (count < 0) {
+	perror("read");
+	exit(5);
+    }
+    if (count < in_buf->length)
+	fprintf(stderr, "Warning, only read in %d bytes, expected %d\n",
+		count, (int) in_buf->length);
+}
+
+/*
+ * Function: call_server
+ *
+ * Purpose: Call the "sign" service.
+ *
+ * Arguments:
+ *
+ * 	host		(r) the host providing the service
+ * 	port		(r) the port to connect to on host
+ * 	service_name	(r) the GSS-API service name to authenticate to
+ *	gss_flags	(r) GSS-API delegation flag (if any)
+ *	auth_flag	(r) whether to do authentication
+ *	wrap_flag	(r) whether to do message wrapping at all
+ *	encrypt_flag	(r) whether to do encryption while wrapping
+ *	mic_flag	(r) whether to request a MIC from the server
+ * 	msg		(r) the message to have "signed"
+ *	use_file	(r) whether to treat msg as an input file name
+ *	mcount		(r) the number of times to send the message
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * call_server opens a TCP connection to <host:port> and establishes a
+ * GSS-API context with service_name over the connection.  It then
+ * seals msg in a GSS-API token with gss_wrap, sends it to the server,
+ * reads back a GSS-API signature block for msg from the server, and
+ * verifies it with gss_verify.  -1 is returned if any step fails,
+ * otherwise 0 is returned.  */
+static int call_server(host, port, oid, service_name, gss_flags, auth_flag,
+		       wrap_flag, encrypt_flag, mic_flag, v1_format, msg, use_file,
+		       mcount)
+     char *host;
+     u_short port;
+     gss_OID oid;
+     char *service_name;
+     OM_uint32 gss_flags;
+     int auth_flag, wrap_flag, encrypt_flag, mic_flag;
+     int v1_format;
+     char *msg;
+     int use_file;
+     int mcount;
+{
+     gss_ctx_id_t context;
+     gss_buffer_desc in_buf, out_buf;
+     int s, state;
+     OM_uint32 ret_flags;
+     OM_uint32 maj_stat, min_stat;
+     gss_name_t		src_name, targ_name;
+     gss_buffer_desc	sname, tname;
+     OM_uint32		lifetime;
+     gss_OID		mechanism, name_type;
+     int		is_local;
+     OM_uint32		context_flags;
+     int		is_open;
+     gss_qop_t		qop_state;
+     gss_OID_set	mech_names;
+     gss_buffer_desc	oid_name;
+     size_t	i;
+     int token_flags;
+
+     /* Open connection */
+     if ((s = connect_to_server()) < 0)
+	  return -1;
+
+     /* Establish context */
+     if (client_establish_context(s, service_name, gss_flags, auth_flag,
+				  v1_format, oid, &context,
+				  &ret_flags) < 0) {
+         (void) closesocket(s);
+         return -1;
+     }
+
+     if (auth_flag && verbose) {
+         /* display the flags */
+         display_ctx_flags(ret_flags);
+
+         /* Get context information */
+         maj_stat = gss_inquire_context( &min_stat, context,
+                                         &src_name, &targ_name, &lifetime,
+                                         &mechanism, &context_flags,
+                                         &is_local,
+                                         &is_open);
+         if (maj_stat != GSS_S_COMPLETE) {
+             display_status("inquiring context", maj_stat, min_stat);
+             return -1;
+         }
+
+         maj_stat = gss_display_name(&min_stat, src_name, &sname,
+                                      &name_type);
+         if (maj_stat != GSS_S_COMPLETE) {
+             display_status("displaying source name", maj_stat, min_stat);
+             return -1;
+         }
+         maj_stat = gss_display_name(&min_stat, targ_name, &tname,
+                                      (gss_OID *) NULL);
+         if (maj_stat != GSS_S_COMPLETE) {
+             display_status("displaying target name", maj_stat, min_stat);
+             return -1;
+         }
+         printf("\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
+                 (int) sname.length, (char *) sname.value,
+                 (int) tname.length, (char *) tname.value, lifetime,
+                 context_flags,
+                 (is_local) ? "locally initiated" : "remotely initiated",
+                 (is_open) ? "open" : "closed");
+
+         (void) gss_release_name(&min_stat, &src_name);
+         (void) gss_release_name(&min_stat, &targ_name);
+         (void) gss_release_buffer(&min_stat, &sname);
+         (void) gss_release_buffer(&min_stat, &tname);
+
+         maj_stat = gss_oid_to_str(&min_stat,
+                                    name_type,
+                                    &oid_name);
+         if (maj_stat != GSS_S_COMPLETE) {
+             display_status("converting oid->string", maj_stat, min_stat);
+             return -1;
+         }
+         printf("Name type of source name is %.*s.\n",
+                 (int) oid_name.length, (char *) oid_name.value);
+         (void) gss_release_buffer(&min_stat, &oid_name);
+
+         /* Now get the names supported by the mechanism */
+         maj_stat = gss_inquire_names_for_mech(&min_stat,
+                                                mechanism,
+                                                &mech_names);
+         if (maj_stat != GSS_S_COMPLETE) {
+             display_status("inquiring mech names", maj_stat, min_stat);
+             return -1;
+         }
+
+         maj_stat = gss_oid_to_str(&min_stat,
+                                    mechanism,
+                                    &oid_name);
+         if (maj_stat != GSS_S_COMPLETE) {
+             display_status("converting oid->string", maj_stat, min_stat);
+             return -1;
+         }
+         printf("Mechanism %.*s supports %d names\n",
+                 (int) oid_name.length, (char *) oid_name.value,
+                 (int) mech_names->count);
+         (void) gss_release_buffer(&min_stat, &oid_name);
+
+         for (i=0; i<mech_names->count; i++) {
+             maj_stat = gss_oid_to_str(&min_stat,
+                                        &mech_names->elements[i],
+                                        &oid_name);
+             if (maj_stat != GSS_S_COMPLETE) {
+                 display_status("converting oid->string", maj_stat, min_stat);
+                 return -1;
+             }
+             printf("  %d: %.*s\n", (int) i,
+                     (int) oid_name.length, (char *) oid_name.value);
+
+             (void) gss_release_buffer(&min_stat, &oid_name);
+         }
+         (void) gss_release_oid_set(&min_stat, &mech_names);
+     }
+
+    if (use_file) {
+        read_file(msg, &in_buf);
+    } else {
+        /* Seal the message */
+        in_buf.value = msg;
+        in_buf.length = strlen(msg);
+    }
+
+    for (i = 0; i < mcount; i++) {
+        if (wrap_flag) {
+            maj_stat = gss_wrap(&min_stat, context, encrypt_flag, GSS_C_QOP_DEFAULT,
+                                 &in_buf, &state, &out_buf);
+            if (maj_stat != GSS_S_COMPLETE) {
+                display_status("wrapping message", maj_stat, min_stat);
+                (void) closesocket(s);
+                (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+                return -1;
+            } else if (encrypt_flag && ! state) {
+                fprintf(stderr, "Warning!  Message not encrypted.\n");
+            }
+        }
+        else {
+            out_buf = in_buf;
+        }
+
+        /* Send to server */
+        if (send_token(s, (v1_format?0
+                            :(TOKEN_DATA |
+                               (wrap_flag ? TOKEN_WRAPPED : 0) |
+                               (encrypt_flag ? TOKEN_ENCRYPTED : 0) |
+                               (mic_flag ? TOKEN_SEND_MIC : 0))), &out_buf) < 0) {
+            (void) closesocket(s);
+            (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+            return -1;
+        }
+        if (out_buf.value != in_buf.value)
+            (void) gss_release_buffer(&min_stat, &out_buf);
+
+        /* Read signature block into out_buf */
+        if (recv_token(s, &token_flags, &out_buf) < 0) {
+            (void) closesocket(s);
+            (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+            return -1;
+        }
+
+        if (mic_flag) {
+            /* Verify signature block */
+            maj_stat = gss_verify_mic(&min_stat, context, &in_buf,
+                                       &out_buf, &qop_state);
+            if (maj_stat != GSS_S_COMPLETE) {
+                display_status("verifying signature", maj_stat, min_stat);
+                (void) closesocket(s);
+                (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+                return -1;
+            }
+
+            if (verbose)
+                printf("Signature verified.\n");
+        }
+        else {
+            if (verbose)
+                printf("Response received.\n");
+        }
+
+        free (out_buf.value);
+    }
+
+    if (use_file)
+        free(in_buf.value);
+
+    /* Send NOOP */
+    if (!v1_format)
+        (void) send_token(s, TOKEN_NOOP, empty_token);
+
+    if (auth_flag) {
+        /* Delete context */
+        maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf);
+        if (maj_stat != GSS_S_COMPLETE) {
+            display_status("deleting context", maj_stat, min_stat);
+            (void) closesocket(s);
+            (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+            return -1;
+        }
+
+        (void) gss_release_buffer(&min_stat, &out_buf);
+    }
+
+    (void) closesocket(s);
+    return 0;
+}
+
+static void parse_oid(char *mechanism, gss_OID *oid)
+{
+    char	*mechstr = 0, *cp;
+    gss_buffer_desc tok;
+    OM_uint32 maj_stat, min_stat;
+    
+    if (isdigit((int) mechanism[0])) {
+	mechstr = malloc(strlen(mechanism)+5);
+	if (!mechstr) {
+	    fprintf(stderr, "Couldn't allocate mechanism scratch!\n");
+	    return;
+	}
+	sprintf(mechstr, "{ %s }", mechanism);
+	for (cp = mechstr; *cp; cp++)
+	    if (*cp == '.')
+		*cp = ' ';
+	tok.value = mechstr;
+    } else
+	tok.value = mechanism;
+    tok.length = strlen(tok.value);
+    maj_stat = gss_str_to_oid(&min_stat, &tok, oid);
+    if (maj_stat != GSS_S_COMPLETE) {
+	display_status("str_to_oid", maj_stat, min_stat);
+	return;
+    }
+    if (mechstr)
+	free(mechstr);
+}
+
+static int max_threads = 1;
+
+#ifdef _WIN32
+static thread_count = 0;
+static HANDLE hMutex = NULL;
+static HANDLE hEvent = NULL;
+
+void
+InitHandles(void)
+{
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+void
+CleanupHandles(void)
+{
+    CloseHandle(hMutex);
+    CloseHandle(hEvent);
+}
+
+BOOL
+WaitAndIncrementThreadCounter(void)
+{
+    for (;;) {
+        if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
+            if ( thread_count < max_threads ) {
+                thread_count++;
+                ReleaseMutex(hMutex);
+                return TRUE;
+            } else {
+                ReleaseMutex(hMutex);
+
+                if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) {
+                    continue;
+                } else {
+                    return FALSE;
+                }
+            }
+        } else {
+            return FALSE;
+        }
+    }
+}
+
+BOOL
+DecrementAndSignalThreadCounter(void)
+{
+    if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
+        if (thread_count == max_threads)
+            SetEvent(hEvent);
+        thread_count--;
+        ReleaseMutex(hMutex);
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+#else /* assume pthread */
+static pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t counter_cond = PTHREAD_COND_INITIALIZER;
+int counter = 0;
+
+static int
+WaitAndIncrementThreadCounter(void)
+{
+    int err;
+    err = pthread_mutex_lock(&counter_mutex);
+    if (err) {
+	perror("pthread_mutex_lock");
+	return 0;
+    }
+    if (counter == max_threads) {
+	err = pthread_cond_wait(&counter_cond, &counter_mutex);
+	if (err) {
+	    perror("pthread_cond_wait");
+	    return 0;
+	}
+    }
+    counter++;
+    pthread_mutex_unlock(&counter_mutex);
+    return 1;
+}
+static void
+DecrementAndSignalThreadCounter(void)
+{
+    int err;
+    sleep(1);
+    err = pthread_mutex_lock(&counter_mutex);
+    if (err) {
+	perror("pthread_mutex_lock");
+	return;
+    }
+    if (counter == max_threads)
+	pthread_cond_broadcast(&counter_cond);
+    counter--;
+    pthread_mutex_unlock(&counter_mutex);
+}
+#endif
+
+static char *service_name, *server_host, *msg;
+static char *mechanism = 0;
+static u_short port = 4444;
+static int use_file = 0;
+static OM_uint32 gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
+static OM_uint32 min_stat;
+static gss_OID oid = GSS_C_NULL_OID;
+static int mcount = 1, ccount = 1;
+static int auth_flag, wrap_flag, encrypt_flag, mic_flag, v1_format;
+
+static void worker_bee(void * unused)
+{
+    printf("worker bee!\n");
+    if (call_server(server_host, port, oid, service_name,
+                    gss_flags, auth_flag, wrap_flag, encrypt_flag, mic_flag,
+                    v1_format, msg, use_file, mcount) < 0)
+        if ( max_threads == 1 )
+            exit(6);
+
+    if ( max_threads > 1 )
+        DecrementAndSignalThreadCounter();
+    free(unused);
+}
+
+int main(argc, argv)
+     int argc;
+     char **argv;
+{
+     int i;
+
+     display_file = stdout;
+     auth_flag = wrap_flag = encrypt_flag = mic_flag = 1;
+     v1_format = 0;
+
+     /* Parse arguments. */
+     argc--; argv++;
+     while (argc) {
+	  if (strcmp(*argv, "-port") == 0) {
+	       argc--; argv++;
+	       if (!argc) usage();
+	       port = atoi(*argv);
+	   } else if (strcmp(*argv, "-mech") == 0) {
+	       argc--; argv++;
+	       if (!argc) usage();
+	       mechanism = *argv;
+	   } 
+#if defined(_WIN32) || 1
+           else if (strcmp(*argv, "-threads") == 0) {
+               argc--; argv++;
+               if (!argc) usage();
+               max_threads = atoi(*argv);
+           } 
+#endif
+           else if (strcmp(*argv, "-d") == 0) {
+	       gss_flags |= GSS_C_DELEG_FLAG;
+	   } else if (strcmp(*argv, "-seq") == 0) {
+	       gss_flags |= GSS_C_SEQUENCE_FLAG;
+	   } else if (strcmp(*argv, "-noreplay") == 0) {
+	       gss_flags &= ~GSS_C_REPLAY_FLAG;
+	   } else if (strcmp(*argv, "-nomutual") == 0) {
+	       gss_flags &= ~GSS_C_MUTUAL_FLAG;
+	  } else if (strcmp(*argv, "-f") == 0) {
+	       use_file = 1;
+	  } else if (strcmp(*argv, "-q") == 0) {
+	       verbose = 0;
+	  } else if (strcmp(*argv, "-ccount") == 0) {
+	    argc--; argv++;
+	    if (!argc) usage();
+	    ccount = atoi(*argv);
+	    if (ccount <= 0) usage();
+	  } else if (strcmp(*argv, "-mcount") == 0) {
+	    argc--; argv++;
+	    if (!argc) usage();
+	    mcount = atoi(*argv);
+	    if (mcount < 0) usage();
+	  } else if (strcmp(*argv, "-na") == 0) {
+	    auth_flag = wrap_flag = encrypt_flag = mic_flag = 0;
+	  } else if (strcmp(*argv, "-nw") == 0) {
+	    wrap_flag = 0;
+	  } else if (strcmp(*argv, "-nx") == 0) {
+	    encrypt_flag = 0;
+	  } else if (strcmp(*argv, "-nm") == 0) {
+	    mic_flag = 0;
+	  } else  if (strcmp(*argv, "-v1") == 0) {
+	    v1_format = 1;
+	  } else
+	    break;
+	  argc--; argv++;
+     }
+     if (argc != 3)
+	  usage();
+
+#ifdef _WIN32
+    if (max_threads < 1) {
+        fprintf(stderr, "warning: there must be at least one thread\n");
+        max_threads = 1;
+    }
+
+    InitHandles();
+    SetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT","1");
+#endif
+
+     server_host = *argv++;
+     service_name = *argv++;
+     msg = *argv++;
+
+     if (mechanism)
+	 parse_oid(mechanism, &oid);
+
+     if (get_server_info(server_host, port) < 0) {
+	 exit(1);
+     }
+
+    if ( max_threads == 1 ) {
+        for (i = 0; i < ccount; i++) {
+            worker_bee(0);
+        }
+    } else {
+        for (i = 0; i < ccount; i++) {
+            if ( WaitAndIncrementThreadCounter() ) {
+#ifdef _WIN32
+                uintptr_t handle = _beginthread(worker_bee, 0, (void *)0);
+                if (handle == (uintptr_t)-1) {
+                    exit(7);
+                }
+#else
+		int err;
+		pthread_t thr;
+		err = pthread_create(&thr, 0, (void *(*)(void *))worker_bee, malloc(12));
+		if (err) {
+		    perror("pthread_create");
+		    exit(7);
+		}
+		(void) pthread_detach(thr);
+#endif
+            } else {
+                exit(8);
+            }
+        }
+    }
+
+    if (oid != GSS_C_NULL_OID)
+        (void) gss_release_oid(&min_stat, &oid);
+	 
+#ifdef _WIN32
+    CleanupHandles();
+#else
+    if (max_threads > 1)
+	sleep(10);
+#endif
+
+    return 0;
+}
diff --git a/mechglue/src/tests/gss-threads/gss-misc.c b/mechglue/src/tests/gss-threads/gss-misc.c
new file mode 100644
index 000000000..3405275fa
--- /dev/null
+++ b/mechglue/src/tests/gss-threads/gss-misc.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 2003, 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock.h>
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+#include <errno.h>
+#include "krb5/autoconf.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+
+/* need struct timeval */
+#if HAVE_TIME_H && (!HAVE_SYS_TIME_H || TIME_WITH_SYS_TIME)
+# include <time.h>
+#endif
+#if HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <gssapi/gssapi_generic.h>
+#include "gss-misc.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern char *malloc();
+#endif
+
+FILE *display_file;
+
+gss_buffer_desc empty_token_buf = { 0, (void *) "" };
+gss_buffer_t empty_token = &empty_token_buf;
+
+static void display_status_1
+	(char *m, OM_uint32 code, int type);
+
+static int write_all(int fildes, char *buf, unsigned int nbyte)
+{
+     int ret;
+     char *ptr;
+
+     for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
+	  ret = send(fildes, ptr, nbyte, 0);
+	  if (ret < 0) {
+	       if (errno == EINTR)
+		    continue;
+	       return(ret);
+	  } else if (ret == 0) {
+	       return(ptr-buf);
+	  }
+     }
+
+     return(ptr-buf);
+}
+
+static int read_all(int fildes, char *buf, unsigned int nbyte)
+{
+    int ret;
+    char *ptr;
+    fd_set rfds;
+    struct timeval tv;
+
+    FD_ZERO(&rfds);
+    FD_SET(fildes, &rfds);
+    tv.tv_sec = 10;
+    tv.tv_usec = 0;
+
+    for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
+	if (select(FD_SETSIZE, &rfds, NULL, NULL, &tv) <= 0
+	    || !FD_ISSET(fildes, &rfds))
+	    return(ptr-buf);
+	ret = recv(fildes, ptr, nbyte, 0);
+	if (ret < 0) {
+	    if (errno == EINTR)
+		continue;
+	    return(ret);
+	} else if (ret == 0) {
+	    return(ptr-buf);
+	}
+    }
+
+    return(ptr-buf);
+}
+
+/*
+ * Function: send_token
+ *
+ * Purpose: Writes a token to a file descriptor.
+ *
+ * Arguments:
+ *
+ * 	s		(r) an open file descriptor
+ *	flags		(r) the flags to write
+ * 	tok		(r) the token to write
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * If the flags are non-null, send_token writes the token flags (a
+ * single byte, even though they're passed in in an integer). Next,
+ * the token length (as a network long) and then the token data are
+ * written to the file descriptor s.  It returns 0 on success, and -1
+ * if an error occurs or if it could not write all the data.
+ */
+int send_token(s, flags, tok)
+     int s;
+     int flags;
+     gss_buffer_t tok;
+{
+     int ret;
+     unsigned char char_flags = (unsigned char) flags;
+     unsigned char lenbuf[4];
+
+     if (char_flags) {
+	 ret = write_all(s, (char *)&char_flags, 1);
+	 if (ret != 1) {
+	     perror("sending token flags");
+	     return -1;
+	 }
+     }
+     if (tok->length > 0xffffffffUL)
+	 abort();
+     lenbuf[0] = (tok->length >> 24) & 0xff;
+     lenbuf[1] = (tok->length >> 16) & 0xff;
+     lenbuf[2] = (tok->length >> 8) & 0xff;
+     lenbuf[3] = tok->length & 0xff;
+
+     ret = write_all(s, lenbuf, 4);
+     if (ret < 0) {
+	  perror("sending token length");
+	  return -1;
+     } else if (ret != 4) {
+	 if (display_file)
+	     fprintf(display_file, 
+		     "sending token length: %d of %d bytes written\n", 
+		     ret, 4);
+	  return -1;
+     }
+
+     ret = write_all(s, tok->value, tok->length);
+     if (ret < 0) {
+	  perror("sending token data");
+	  return -1;
+     } else if (ret != tok->length) {
+	 if (display_file)
+	     fprintf(display_file, 
+		     "sending token data: %d of %d bytes written\n", 
+		     ret, (int) tok->length);
+	 return -1;
+     }
+     
+     return 0;
+}
+
+/*
+ * Function: recv_token
+ *
+ * Purpose: Reads a token from a file descriptor.
+ *
+ * Arguments:
+ *
+ * 	s		(r) an open file descriptor
+ *	flags		(w) the read flags
+ * 	tok		(w) the read token
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * recv_token reads the token flags (a single byte, even though
+ * they're stored into an integer, then reads the token length (as a
+ * network long), allocates memory to hold the data, and then reads
+ * the token data from the file descriptor s.  It blocks to read the
+ * length and data, if necessary.  On a successful return, the token
+ * should be freed with gss_release_buffer.  It returns 0 on success,
+ * and -1 if an error occurs or if it could not read all the data.
+ */
+int recv_token(s, flags, tok)
+     int s;
+     int *flags;
+     gss_buffer_t tok;
+{
+     int ret;
+     unsigned char char_flags;
+     unsigned char lenbuf[4];
+
+     ret = read_all(s, (char *) &char_flags, 1);
+     if (ret < 0) {
+       perror("reading token flags");
+       return -1;
+     } else if (! ret) {
+       if (display_file)
+	 fputs("reading token flags: 0 bytes read\n", display_file);
+       return -1;
+     } else {
+       *flags = (int) char_flags;
+     }
+
+     if (char_flags == 0 ) {
+     lenbuf[0] = 0;
+     ret = read_all(s, &lenbuf[1], 3);
+     if (ret < 0) {
+	 perror("reading token length");
+	 return -1;
+     } else if (ret != 3) {
+	 if (display_file)
+	     fprintf(display_file, 
+		     "reading token length: %d of %d bytes read\n", 
+		     ret, 3);
+	 return -1;
+     }
+     }
+     else {
+       ret = read_all(s, lenbuf, 4);
+       if (ret < 0) {
+	 perror("reading token length");
+	 return -1;
+       } else if (ret != 4) {
+	 if (display_file)
+	   fprintf(display_file, 
+		   "reading token length: %d of %d bytes read\n", 
+		   ret, 4);
+	 return -1;
+       }
+     }
+
+     tok->length = ((lenbuf[0] << 24)
+		    | (lenbuf[1] << 16)
+		    | (lenbuf[2] << 8)
+		    | lenbuf[3]);
+     tok->value = (char *) malloc(tok->length ? tok->length : 1);
+     if (tok->length && tok->value == NULL) {
+	 if (display_file)
+	     fprintf(display_file, 
+		     "Out of memory allocating token data\n");
+	  return -1;
+     }
+
+     ret = read_all(s, (char *) tok->value, tok->length);
+     if (ret < 0) {
+	  perror("reading token data");
+	  free(tok->value);
+	  return -1;
+     } else if (ret != tok->length) {
+	  fprintf(stderr, "sending token data: %d of %d bytes written\n", 
+		  ret, (int) tok->length);
+	  free(tok->value);
+	  return -1;
+     }
+
+     return 0;
+}
+
+static void display_status_1(m, code, type)
+     char *m;
+     OM_uint32 code;
+     int type;
+{
+     OM_uint32 maj_stat, min_stat;
+     gss_buffer_desc msg;
+     OM_uint32 msg_ctx;
+     
+     msg_ctx = 0;
+     while (1) {
+	  maj_stat = gss_display_status(&min_stat, code,
+				       type, GSS_C_NULL_OID,
+				       &msg_ctx, &msg);
+	  if (display_file)
+	      fprintf(display_file, "GSS-API error %s: %s\n", m,
+		      (char *)msg.value); 
+	  (void) gss_release_buffer(&min_stat, &msg);
+	  
+	  if (!msg_ctx)
+	       break;
+     }
+}
+
+/*
+ * Function: display_status
+ *
+ * Purpose: displays GSS-API messages
+ *
+ * Arguments:
+ *
+ * 	msg		a string to be displayed with the message
+ * 	maj_stat	the GSS-API major status code
+ * 	min_stat	the GSS-API minor status code
+ *
+ * Effects:
+ *
+ * The GSS-API messages associated with maj_stat and min_stat are
+ * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
+ * followed by a newline.
+ */
+void display_status(msg, maj_stat, min_stat)
+     char *msg;
+     OM_uint32 maj_stat;
+     OM_uint32 min_stat;
+{
+     display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
+     display_status_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+/*
+ * Function: display_ctx_flags
+ *
+ * Purpose: displays the flags returned by context initation in
+ *	    a human-readable form
+ *
+ * Arguments:
+ *
+ * 	int		ret_flags
+ *
+ * Effects:
+ *
+ * Strings corresponding to the context flags are printed on
+ * stdout, preceded by "context flag: " and followed by a newline
+ */
+
+void display_ctx_flags(flags)
+     OM_uint32 flags;
+{
+     if (flags & GSS_C_DELEG_FLAG)
+	  fprintf(display_file, "context flag: GSS_C_DELEG_FLAG\n");
+     if (flags & GSS_C_MUTUAL_FLAG)
+	  fprintf(display_file, "context flag: GSS_C_MUTUAL_FLAG\n");
+     if (flags & GSS_C_REPLAY_FLAG)
+	  fprintf(display_file, "context flag: GSS_C_REPLAY_FLAG\n");
+     if (flags & GSS_C_SEQUENCE_FLAG)
+	  fprintf(display_file, "context flag: GSS_C_SEQUENCE_FLAG\n");
+     if (flags & GSS_C_CONF_FLAG )
+	  fprintf(display_file, "context flag: GSS_C_CONF_FLAG \n");
+     if (flags & GSS_C_INTEG_FLAG )
+	  fprintf(display_file, "context flag: GSS_C_INTEG_FLAG \n");
+}
+
+void print_token(tok)
+     gss_buffer_t tok;
+{
+    int i;
+    unsigned char *p = tok->value;
+
+    if (!display_file)
+	return;
+    for (i=0; i < tok->length; i++, p++) {
+	fprintf(display_file, "%02x ", *p);
+	if ((i % 16) == 15) {
+	    fprintf(display_file, "\n");
+	}
+    }
+    fprintf(display_file, "\n");
+    fflush(display_file);
+}
+
+#ifdef _WIN32
+#include <sys\timeb.h>
+#include <time.h>
+
+int gettimeofday (struct timeval *tv, void *ignore_tz)
+{
+    struct _timeb tb;
+    _tzset();
+    _ftime(&tb);
+    if (tv) {
+	tv->tv_sec = tb.time;
+	tv->tv_usec = tb.millitm * 1000;
+    }
+    return 0;
+}
+#endif /* _WIN32 */
diff --git a/mechglue/src/tests/gss-threads/gss-misc.h b/mechglue/src/tests/gss-threads/gss-misc.h
new file mode 100644
index 000000000..35b3b7390
--- /dev/null
+++ b/mechglue/src/tests/gss-threads/gss-misc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef _GSSMISC_H_
+#define _GSSMISC_H_
+
+#include <gssapi/gssapi_generic.h>
+#include <stdio.h>
+
+extern FILE *display_file;
+
+int send_token
+	(int s, int flags, gss_buffer_t tok);
+int recv_token
+	(int s, int *flags, gss_buffer_t tok);
+void display_status
+	(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat);
+void display_ctx_flags
+	(OM_uint32 flags);
+void print_token
+	(gss_buffer_t tok);
+
+/* Token types */
+#define TOKEN_NOOP		(1<<0)
+#define TOKEN_CONTEXT		(1<<1)
+#define TOKEN_DATA		(1<<2)
+#define TOKEN_MIC		(1<<3)
+
+/* Token flags */
+#define TOKEN_CONTEXT_NEXT	(1<<4)
+#define TOKEN_WRAPPED		(1<<5)
+#define TOKEN_ENCRYPTED		(1<<6)
+#define TOKEN_SEND_MIC		(1<<7)
+
+extern gss_buffer_t empty_token;
+
+#endif
diff --git a/mechglue/src/tests/gss-threads/gss-server.c b/mechglue/src/tests/gss-threads/gss-server.c
new file mode 100644
index 000000000..6cbac84af
--- /dev/null
+++ b/mechglue/src/tests/gss-threads/gss-server.c
@@ -0,0 +1,850 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <gssapi/gssapi_generic.h>
+#include "gss-misc.h"
+#include "port-sockets.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+static void usage()
+{
+     fprintf(stderr, "Usage: gss-server [-port port] [-verbose] [-once]");
+#ifdef _WIN32
+     fprintf(stderr, " [-threads num]");
+#endif
+     fprintf(stderr, "\n");
+     fprintf(stderr, "       [-inetd] [-export] [-logfile file] service_name\n");
+     exit(1);
+}
+
+FILE *log;
+
+int verbose = 0;
+
+/*
+ * Function: server_acquire_creds
+ *
+ * Purpose: imports a service name and acquires credentials for it
+ *
+ * Arguments:
+ *
+ * 	service_name	(r) the ASCII service name
+ * 	server_creds	(w) the GSS-API service credentials
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * The service name is imported with gss_import_name, and service
+ * credentials are acquired with gss_acquire_cred.  If either opertion
+ * fails, an error message is displayed and -1 is returned; otherwise,
+ * 0 is returned.
+ */
+static int server_acquire_creds(service_name, server_creds)
+     char *service_name;
+     gss_cred_id_t *server_creds;
+{
+     gss_buffer_desc name_buf;
+     gss_name_t server_name;
+     OM_uint32 maj_stat, min_stat;
+
+     name_buf.value = service_name;
+     name_buf.length = strlen(name_buf.value) + 1;
+     maj_stat = gss_import_name(&min_stat, &name_buf, 
+				(gss_OID) gss_nt_service_name, &server_name);
+     if (maj_stat != GSS_S_COMPLETE) {
+	  display_status("importing name", maj_stat, min_stat);
+	  return -1;
+     }
+
+     maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
+				 GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+				 server_creds, NULL, NULL);
+     if (maj_stat != GSS_S_COMPLETE) {
+	  display_status("acquiring credentials", maj_stat, min_stat);
+	  return -1;
+     }
+
+     (void) gss_release_name(&min_stat, &server_name);
+
+     return 0;
+}
+
+/*
+ * Function: server_establish_context
+ *
+ * Purpose: establishses a GSS-API context as a specified service with
+ * an incoming client, and returns the context handle and associated
+ * client name
+ *
+ * Arguments:
+ *
+ * 	s		(r) an established TCP connection to the client
+ * 	service_creds	(r) server credentials, from gss_acquire_cred
+ * 	context		(w) the established GSS-API context
+ * 	client_name	(w) the client's ASCII name
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * Any valid client request is accepted.  If a context is established,
+ * its handle is returned in context and the client name is returned
+ * in client_name and 0 is returned.  If unsuccessful, an error
+ * message is displayed and -1 is returned.
+ */
+static int server_establish_context(s, server_creds, context, client_name, 
+				    ret_flags)
+     int s;
+     gss_cred_id_t server_creds;
+     gss_ctx_id_t *context;
+     gss_buffer_t client_name;
+     OM_uint32 *ret_flags;
+{
+     gss_buffer_desc send_tok, recv_tok;
+     gss_name_t client;
+     gss_OID doid;
+     OM_uint32 maj_stat, min_stat, acc_sec_min_stat;
+     gss_buffer_desc	oid_name;
+     int token_flags;
+
+     if (recv_token(s, &token_flags, &recv_tok) < 0)
+       return -1;
+
+     if (recv_tok.value) {
+       free (recv_tok.value);
+       recv_tok.value = NULL;
+     }
+
+     if (! (token_flags & TOKEN_NOOP)) {
+       if (log)
+	 fprintf(log, "Expected NOOP token, got %d token instead\n",
+		 token_flags);
+       return -1;
+     }
+
+     *context = GSS_C_NO_CONTEXT;
+
+     if (token_flags & TOKEN_CONTEXT_NEXT) {
+       do {
+	 if (recv_token(s, &token_flags, &recv_tok) < 0)
+	   return -1;
+
+	 if (verbose && log) {
+	   fprintf(log, "Received token (size=%d): \n", (int) recv_tok.length);
+	   print_token(&recv_tok);
+	 }
+
+	 maj_stat =
+	   gss_accept_sec_context(&acc_sec_min_stat,
+				  context,
+				  server_creds,
+				  &recv_tok,
+				  GSS_C_NO_CHANNEL_BINDINGS,
+				  &client,
+				  &doid,
+				  &send_tok,
+				  ret_flags,
+				  NULL, 	/* ignore time_rec */
+				  NULL); 	/* ignore del_cred_handle */
+
+	 if(recv_tok.value) {
+	     free(recv_tok.value);
+	     recv_tok.value = NULL;
+	 }
+
+	 if (send_tok.length != 0) {
+	   if (verbose && log) {
+	     fprintf(log,
+		     "Sending accept_sec_context token (size=%d):\n",
+		     (int) send_tok.length);
+	     print_token(&send_tok);
+	   }
+	   if (send_token(s, TOKEN_CONTEXT, &send_tok) < 0) {
+	     if (log)
+	       fprintf(log, "failure sending token\n");
+	     return -1;
+	   }
+
+	   (void) gss_release_buffer(&min_stat, &send_tok);
+	 }
+	 if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
+	      display_status("accepting context", maj_stat,
+			     acc_sec_min_stat);
+	      if (*context != GSS_C_NO_CONTEXT)
+		      gss_delete_sec_context(&min_stat, context,
+					     GSS_C_NO_BUFFER);
+	      return -1;
+	 }
+ 
+	 if (verbose && log) {
+	   if (maj_stat == GSS_S_CONTINUE_NEEDED)
+	     fprintf(log, "continue needed...\n");
+	   else
+	     fprintf(log, "\n");
+	   fflush(log);
+	 }
+       } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+       /* display the flags */
+       display_ctx_flags(*ret_flags);
+
+       if (verbose && log) {
+	 maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name);
+	 if (maj_stat != GSS_S_COMPLETE) {
+	   display_status("converting oid->string", maj_stat, min_stat);
+	   return -1;
+	 }
+	 fprintf(log, "Accepted connection using mechanism OID %.*s.\n",
+		 (int) oid_name.length, (char *) oid_name.value);
+	 (void) gss_release_buffer(&min_stat, &oid_name);
+       }
+
+       maj_stat = gss_display_name(&min_stat, client, client_name, &doid);
+       if (maj_stat != GSS_S_COMPLETE) {
+	 display_status("displaying name", maj_stat, min_stat);
+	 return -1;
+       }
+       maj_stat = gss_release_name(&min_stat, &client);
+       if (maj_stat != GSS_S_COMPLETE) {
+	 display_status("releasing name", maj_stat, min_stat);
+	 return -1;
+       }
+     }
+     else {
+       client_name->length = *ret_flags = 0;
+
+       if (log)
+	 fprintf(log, "Accepted unauthenticated connection.\n");
+     }
+
+     return 0;
+}
+
+/*
+ * Function: create_socket
+ *
+ * Purpose: Opens a listening TCP socket.
+ *
+ * Arguments:
+ *
+ * 	port		(r) the port number on which to listen
+ *
+ * Returns: the listening socket file descriptor, or -1 on failure
+ *
+ * Effects:
+ *
+ * A listening socket on the specified port and created and returned.
+ * On error, an error message is displayed and -1 is returned.
+ */
+static int create_socket(port)
+     u_short port;
+{
+     struct sockaddr_in saddr;
+     int s;
+     int on = 1;
+     
+     saddr.sin_family = AF_INET;
+     saddr.sin_port = htons(port);
+     saddr.sin_addr.s_addr = INADDR_ANY;
+
+     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	  perror("creating socket");
+	  return -1;
+     }
+     /* Let the socket be reused right away */
+     (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
+     if (bind(s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
+	  perror("binding socket");
+	  (void) close(s);
+	  return -1;
+     }
+     if (listen(s, 5) < 0) {
+	  perror("listening on socket");
+	  (void) close(s);
+	  return -1;
+     }
+     return s;
+}
+
+static float timeval_subtract(tv1, tv2)
+	struct timeval *tv1, *tv2;
+{
+	return ((tv1->tv_sec - tv2->tv_sec) +
+		((float) (tv1->tv_usec - tv2->tv_usec)) / 1000000);
+}
+
+/*
+ * Yes, yes, this isn't the best place for doing this test.
+ * DO NOT REMOVE THIS UNTIL A BETTER TEST HAS BEEN WRITTEN, THOUGH.
+ * 					-TYT
+ */
+static int test_import_export_context(context)
+	gss_ctx_id_t *context;
+{
+	OM_uint32	min_stat, maj_stat;
+	gss_buffer_desc context_token, copied_token;
+	struct timeval tm1, tm2;
+	
+	/*
+	 * Attempt to save and then restore the context.
+	 */
+	gettimeofday(&tm1, (struct timezone *)0);
+	maj_stat = gss_export_sec_context(&min_stat, context, &context_token);
+	if (maj_stat != GSS_S_COMPLETE) {
+		display_status("exporting context", maj_stat, min_stat);
+		return 1;
+	}
+	gettimeofday(&tm2, (struct timezone *)0);
+	if (verbose && log)
+		fprintf(log, "Exported context: %d bytes, %7.4f seconds\n",
+			(int) context_token.length, 
+			timeval_subtract(&tm2, &tm1));
+	copied_token.length = context_token.length;
+	copied_token.value = malloc(context_token.length);
+	if (copied_token.value == 0) {
+	  if (log)
+	    fprintf(log, "Couldn't allocate memory to copy context token.\n");
+	  return 1;
+	}
+	memcpy(copied_token.value, context_token.value, copied_token.length);
+	maj_stat = gss_import_sec_context(&min_stat, &copied_token, context);
+	if (maj_stat != GSS_S_COMPLETE) {
+		display_status("importing context", maj_stat, min_stat);
+		return 1;
+	}
+	free(copied_token.value);
+	gettimeofday(&tm1, (struct timezone *)0);
+	if (verbose && log)
+		fprintf(log, "Importing context: %7.4f seconds\n",
+			timeval_subtract(&tm1, &tm2));
+	(void) gss_release_buffer(&min_stat, &context_token);
+	return 0;
+}
+
+/*
+ * Function: sign_server
+ *
+ * Purpose: Performs the "sign" service.
+ *
+ * Arguments:
+ *
+ * 	s		(r) a TCP socket on which a connection has been
+ *			accept()ed
+ * 	service_name	(r) the ASCII name of the GSS-API service to
+ * 			establish a context as
+ *	export		(r) whether to test context exporting
+ * 
+ * Returns: -1 on error
+ *
+ * Effects:
+ *
+ * sign_server establishes a context, and performs a single sign request.
+ *
+ * A sign request is a single GSS-API sealed token.  The token is
+ * unsealed and a signature block, produced with gss_sign, is returned
+ * to the sender.  The context is the destroyed and the connection
+ * closed.
+ *
+ * If any error occurs, -1 is returned.
+ */
+static int sign_server(s, server_creds, export)
+     int s;
+     gss_cred_id_t server_creds;
+     int export;
+{
+    gss_buffer_desc client_name, xmit_buf, msg_buf;
+    gss_ctx_id_t context;
+    OM_uint32 maj_stat, min_stat;
+    int i, conf_state, ret_flags;
+    char	*cp;
+    int token_flags;
+
+    /* Establish a context with the client */
+    if (server_establish_context(s, server_creds, &context,
+                                  &client_name, &ret_flags) < 0)
+        return(-1);
+
+    if (context == GSS_C_NO_CONTEXT) {
+        printf("Accepted unauthenticated connection.\n");
+    }
+    else {
+        printf("Accepted connection: \"%.*s\"\n",
+                (int) client_name.length, (char *) client_name.value);
+        (void) gss_release_buffer(&min_stat, &client_name);
+
+        if (export) {
+            for (i=0; i < 3; i++)
+                if (test_import_export_context(&context))
+                    return -1;
+        }
+    }
+
+    do {
+        /* Receive the message token */
+        if (recv_token(s, &token_flags, &xmit_buf) < 0)
+            return(-1);
+
+        if (token_flags & TOKEN_NOOP) {
+            if (log)
+                fprintf(log, "NOOP token\n");
+            if(xmit_buf.value) {
+                free(xmit_buf.value);
+                xmit_buf.value = 0;
+            }
+            break;
+        }
+
+        if (verbose && log) {
+            fprintf(log, "Message token (flags=%d):\n", token_flags);
+            print_token(&xmit_buf);
+        }
+
+        if ((context == GSS_C_NO_CONTEXT) &&
+             (    token_flags & (TOKEN_WRAPPED|TOKEN_ENCRYPTED|TOKEN_SEND_MIC))) {
+            if (log)
+                fprintf(log,
+                         "Unauthenticated client requested authenticated services!\n");
+            if(xmit_buf.value) {
+                free (xmit_buf.value);
+                xmit_buf.value = 0;
+            }
+            return(-1);
+        }
+
+        if (token_flags & TOKEN_WRAPPED) {
+            maj_stat = gss_unwrap(&min_stat, context, &xmit_buf, &msg_buf,
+                                   &conf_state, (gss_qop_t *) NULL);
+            if (maj_stat != GSS_S_COMPLETE) {
+                display_status("unsealing message", maj_stat, min_stat);
+                if(xmit_buf.value) {
+                    free (xmit_buf.value);
+                    xmit_buf.value = 0;
+                }
+                return(-1);
+            } else if (! conf_state && (token_flags & TOKEN_ENCRYPTED)) {
+                fprintf(stderr, "Warning!  Message not encrypted.\n");
+            }
+
+            if(xmit_buf.value) {
+                free (xmit_buf.value);
+                xmit_buf.value = 0;
+            }
+        }
+        else {
+            msg_buf = xmit_buf;
+        }
+
+        if (log) {
+            fprintf(log, "Received message: ");
+            cp = msg_buf.value;
+            if ((isprint((int) cp[0]) || isspace((int) cp[0])) &&
+                 (isprint((int) cp[1]) || isspace((int) cp[1]))) {
+                fprintf(log, "\"%.*s\"\n", (int) msg_buf.length, 
+                         (char *) msg_buf.value);
+                 } else {
+                     fprintf(log, "\n");
+                     print_token(&msg_buf);
+                 }
+        }
+
+        if (token_flags & TOKEN_SEND_MIC) {
+            /* Produce a signature block for the message */
+            maj_stat = gss_get_mic(&min_stat, context, GSS_C_QOP_DEFAULT,
+                                    &msg_buf, &xmit_buf);
+            if (maj_stat != GSS_S_COMPLETE) {
+                display_status("signing message", maj_stat, min_stat);
+                return(-1);
+            }
+
+            if(msg_buf.value) {
+                free (msg_buf.value);
+                msg_buf.value = 0;
+            }
+
+            /* Send the signature block to the client */
+            if (send_token(s, TOKEN_MIC, &xmit_buf) < 0)
+                return(-1);
+
+            if(xmit_buf.value) {
+                free (xmit_buf.value);
+                xmit_buf.value = 0;
+            }
+        }
+        else {
+            if(msg_buf.value) {
+                free (msg_buf.value);
+                msg_buf.value = 0;
+            }
+            if (send_token(s, TOKEN_NOOP, empty_token) < 0)
+                return(-1);
+        }
+    } while (1 /* loop will break if NOOP received */);
+
+    if (context != GSS_C_NO_CONTEXT) {
+        /* Delete context */
+        maj_stat = gss_delete_sec_context(&min_stat, &context, NULL);
+        if (maj_stat != GSS_S_COMPLETE) {
+            display_status("deleting context", maj_stat, min_stat);
+            return(-1);
+        }
+    }
+
+    if (log)
+        fflush(log);
+
+    return(0);
+}
+
+static int max_threads = 1;
+
+#ifdef _WIN32
+static thread_count = 0;
+static HANDLE hMutex = NULL;
+static HANDLE hEvent = NULL;
+
+void
+InitHandles(void)
+{
+    hMutex = CreateMutex(NULL, FALSE, NULL);
+    hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+void
+CleanupHandles(void)
+{
+    CloseHandle(hMutex);
+    CloseHandle(hEvent);
+}
+
+BOOL
+WaitAndIncrementThreadCounter(void)
+{
+    for (;;) {
+        if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
+            if ( thread_count < max_threads ) {
+                thread_count++;
+                ReleaseMutex(hMutex);
+                return TRUE;
+            } else {
+                ReleaseMutex(hMutex);
+
+                if (WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0) {
+                    continue;
+                } else {
+                    return FALSE;
+                }
+            }
+        } else {
+            return FALSE;
+        }
+    }
+}
+
+BOOL
+DecrementAndSignalThreadCounter(void)
+{
+    if (WaitForSingleObject(hMutex, INFINITE) == WAIT_OBJECT_0) {
+        if ( thread_count == max_threads )
+            SetEvent(hEvent);
+        thread_count--;
+        ReleaseMutex(hMutex);
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+#else /* assume pthread */
+static pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t counter_cond = PTHREAD_COND_INITIALIZER;
+int counter = 0;
+
+static int
+WaitAndIncrementThreadCounter(void)
+{
+    int err;
+    err = pthread_mutex_lock(&counter_mutex);
+    if (err) {
+	perror("pthread_mutex_lock");
+	return 0;
+    }
+    if (counter == max_threads) {
+	err = pthread_cond_wait(&counter_cond, &counter_mutex);
+	if (err) {
+	    perror("pthread_cond_wait");
+	    return 0;
+	}
+    }
+    counter++;
+    pthread_mutex_unlock(&counter_mutex);
+    return 1;
+}
+static void
+DecrementAndSignalThreadCounter(void)
+{
+    int err;
+    err = pthread_mutex_lock(&counter_mutex);
+    if (err) {
+	perror("pthread_mutex_lock");
+	return;
+    }
+    if (counter == max_threads)
+	pthread_cond_broadcast(&counter_cond);
+    counter--;
+    pthread_mutex_unlock(&counter_mutex);
+}
+#endif
+
+struct _work_plan {
+    int             s;
+    gss_cred_id_t   server_creds;
+    int             export;
+};
+
+static void *
+worker_bee(void * param)
+{
+    struct _work_plan *work = (struct _work_plan *) param;
+
+    /* this return value is not checked, because there's
+     * not really anything to do if it fails 
+     */
+    sign_server(work->s, work->server_creds, work->export);
+    closesocket(work->s);
+    free(work);
+
+#if defined _WIN32 || 1
+    if ( max_threads > 1 )
+        DecrementAndSignalThreadCounter();
+#endif
+    return 0;
+}
+
+int
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+     char *service_name;
+     gss_cred_id_t server_creds;
+     OM_uint32 min_stat;
+     u_short port = 4444;
+     int once = 0;
+     int do_inetd = 0;
+     int export = 0;
+
+     signal(SIGPIPE, SIG_IGN);
+     log = stdout;
+     display_file = stdout;
+     argc--; argv++;
+     while (argc) {
+	  if (strcmp(*argv, "-port") == 0) {
+	       argc--; argv++;
+	       if (!argc) usage();
+	       port = atoi(*argv);
+	  } 
+#if defined _WIN32 || 1
+          else if (strcmp(*argv, "-threads") == 0) {
+              argc--; argv++;
+              if (!argc) usage();
+              max_threads = atoi(*argv);
+          } 
+#endif
+          else if (strcmp(*argv, "-verbose") == 0) {
+	      verbose = 1;
+	  } else if (strcmp(*argv, "-once") == 0) {
+	      once = 1;
+	  } else if (strcmp(*argv, "-inetd") == 0) {
+	      do_inetd = 1;
+	  } else if (strcmp(*argv, "-export") == 0) {
+	      export = 1;
+	  } else if (strcmp(*argv, "-logfile") == 0) {
+	      argc--; argv++;
+	      if (!argc) usage();
+	      /* Gross hack, but it makes it unnecessary to add an
+                 extra argument to disable logging, and makes the code
+                 more efficient because it doesn't actually write data
+                 to /dev/null. */
+	      if (! strcmp(*argv, "/dev/null")) {
+		log = display_file = NULL;
+	      }
+	      else {
+		log = fopen(*argv, "a");
+		display_file = log;
+		if (!log) {
+		  perror(*argv);
+		  exit(1);
+		}
+	      }
+	  } else
+	       break;
+	  argc--; argv++;
+     }
+     if (argc != 1)
+	  usage();
+
+     if ((*argv)[0] == '-')
+	  usage();
+
+#ifdef _WIN32
+    if (max_threads < 1) {
+        fprintf(stderr, "warning: there must be at least one thread\n");
+        max_threads = 1;
+    }
+
+    if (max_threads > 1 && do_inetd)
+        fprintf(stderr, "warning: one thread may be used in conjunction with inetd\n");
+
+    InitHandles();
+#endif
+
+     service_name = *argv;
+
+     if (server_acquire_creds(service_name, &server_creds) < 0)
+	 return -1;
+     
+     if (do_inetd) {
+	 close(1);
+	 close(2);
+
+	 sign_server(0, server_creds, export);
+	 close(0);
+     } else {
+	 int stmp;
+
+ 	 if ((stmp = create_socket(port)) >= 0) {
+             if (listen(stmp, max_threads == 1 ? 0 : max_threads) < 0)
+                 perror("listening on socket");
+
+             do {
+                 struct _work_plan * work = malloc(sizeof(struct _work_plan));
+
+                 if ( work == NULL ) {
+                     fprintf(stderr, "fatal error: out of memory");
+                     break;
+                 }
+
+                 /* Accept a TCP connection */
+                 if ((work->s = accept(stmp, NULL, 0)) < 0) {
+                     perror("accepting connection");
+                     continue;
+                 }
+                  
+                 work->server_creds = server_creds;
+                 work->export = export;
+
+                 if (max_threads == 1) {
+                     worker_bee((void *)work);
+                 } 
+#if defined _WIN32 || 1
+                 else {
+                     if ( WaitAndIncrementThreadCounter() ) {
+#ifdef _WIN32
+                         uintptr_t handle = _beginthread(worker_bee, 0, (void *)work);
+                         if (handle == (uintptr_t)-1) {
+                             closesocket(work->s);
+                             free(work);
+                         }
+#else
+			 int err;
+			 pthread_t thr;
+			 err = pthread_create(&thr, 0, (void *(*)(void *))worker_bee,
+					      (void *) work);
+			 if (err) {
+			     perror("pthread_create");
+			     closesocket(work->s);
+			     free(work);
+			 }
+			 (void) pthread_detach(thr);
+#endif
+                     } else {
+                         fprintf(stderr, "fatal error incrementing thread counter");
+                         closesocket(work->s);
+                         free(work);
+                         break;
+                     }
+                 }
+#endif
+             } while (!once);
+
+ 	     closesocket(stmp);
+ 	 }
+     }
+
+     (void) gss_release_cred(&min_stat, &server_creds);
+
+#ifdef _WIN32
+    CleanupHandles();
+#else
+    if (max_threads > 1)
+	while (1)
+	    sleep (999999);
+#endif
+
+     return 0;
+}
diff --git a/mechglue/src/tests/gssapi/.Sanitize b/mechglue/src/tests/gssapi/.Sanitize
new file mode 100644
index 000000000..c7ae1c708
--- /dev/null
+++ b/mechglue/src/tests/gssapi/.Sanitize
@@ -0,0 +1,37 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+t_imp_name.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/gssapi/ChangeLog b/mechglue/src/tests/gssapi/ChangeLog
new file mode 100644
index 000000000..2be821e58
--- /dev/null
+++ b/mechglue/src/tests/gssapi/ChangeLog
@@ -0,0 +1,66 @@
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_imp_name.c: Make prototypes unconditional.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Use srcdir.
+
+2001-07-23  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_imp_name.c (display_status_1): Remove variable that was set
+	but never used.
+
+2000-07-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_imp_name.c: Profide full prototypes for internal functions.
+
+2000-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* t_imp_name.c: Define GSSAPI_V2 for proper variable types.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-04-14    <tytso@rsts-11.mit.edu>
+
+	* t_imp_name.c: Initialize display_file variable in main(),
+		instead of using a static initializer.  (Needed for
+		Linux/glibc 2.1)
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Wed Feb 18 16:29:15 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 16:45:28 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sun Feb  9 01:40:15 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Sat Mar 16 07:24:03 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Add USE_ANAME
+
+
diff --git a/mechglue/src/tests/gssapi/Makefile.in b/mechglue/src/tests/gssapi/Makefile.in
new file mode 100644
index 000000000..8f31b904d
--- /dev/null
+++ b/mechglue/src/tests/gssapi/Makefile.in
@@ -0,0 +1,27 @@
+thisconfigdir=./..
+myfulldir=tests/gssapi
+mydir=gssapi
+BUILDTOP=$(REL)..$(S)..
+DEFINES = -DUSE_AUTOCONF_H
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+SRCS= $(srcdir)/t_imp_name.c
+
+OBJS= t_imp_name.o
+
+all:: t_imp_name
+
+t_imp_name: t_imp_name.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_imp_name t_imp_name.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+
+clean::
+	$(RM) t_imp_name
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)t_imp_name.$(OBJEXT): t_imp_name.c $(BUILDTOP)/include/gssapi/gssapi.h \
+  $(BUILDTOP)/include/gssapi/gssapi_generic.h
diff --git a/mechglue/src/tests/gssapi/t_imp_name.c b/mechglue/src/tests/gssapi/t_imp_name.c
new file mode 100644
index 000000000..f4ca41370
--- /dev/null
+++ b/mechglue/src/tests/gssapi/t_imp_name.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 1996, Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Simple test program for testing how GSSAPI import name works.  (May
+ * be made into a more full-fledged test program later.)
+ * 
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+
+#define GSSAPI_V2
+void display_status (char *, OM_uint32, OM_uint32);
+static void display_status_1 (char *, OM_uint32, int);
+static void display_buffer (gss_buffer_desc);
+static int test_import_name (char *);
+
+FILE *display_file;
+
+int main(argc, argv)
+	int argc;
+	char **argv;
+{
+	int retval;
+
+	display_file = stdout;
+
+	retval = test_import_name("host@dcl.mit.edu");
+
+	return retval;
+}
+
+static int test_import_name(name)
+	char *name;
+{
+	OM_uint32 maj_stat, min_stat;
+	gss_name_t gss_name;
+	gss_buffer_desc buffer_name;
+	gss_OID	name_oid;
+
+	buffer_name.value = name;
+	buffer_name.length = strlen(name) + 1;
+	maj_stat = gss_import_name(&min_stat, &buffer_name,
+				   (gss_OID) gss_nt_service_name,
+				   &gss_name);
+	if (maj_stat != GSS_S_COMPLETE) {
+		display_status("parsing name", maj_stat, min_stat);
+		return -1;
+	}
+	
+	maj_stat = gss_display_name(&min_stat, gss_name, &buffer_name,
+				    &name_oid);
+	if (maj_stat != GSS_S_COMPLETE) {
+		display_status("displaying context", maj_stat, min_stat);
+		return -1;
+	}
+	printf("name is: ");
+	display_buffer(buffer_name);
+	printf("\n");
+	(void) gss_release_buffer(&min_stat, &buffer_name);
+
+	gss_oid_to_str(&min_stat, name_oid, &buffer_name);
+	printf("name type is: ");
+	display_buffer(buffer_name);
+	printf("\n");
+	(void) gss_release_buffer(&min_stat, &buffer_name);
+
+	(void) gss_release_name(&min_stat, &gss_name);
+	return 0;
+}
+
+static void display_buffer(buffer)
+	gss_buffer_desc buffer;
+{
+    char *namebuf;
+    
+    namebuf = malloc(buffer.length+1);    
+    if (!namebuf) {
+	fprintf(stderr, "display_buffer: couldn't allocate buffer!\n");
+	exit(1);
+    }
+    strncpy(namebuf, buffer.value, buffer.length);
+    namebuf[buffer.length] = '\0';
+    printf("%s", namebuf);
+    free(namebuf);
+}
+
+void display_status(msg, maj_stat, min_stat)
+     char *msg;
+     OM_uint32 maj_stat;
+     OM_uint32 min_stat;
+{
+     display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
+     display_status_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static void display_status_1(m, code, type)
+     char *m;
+     OM_uint32 code;
+     int type;
+{
+     OM_uint32 min_stat;
+     gss_buffer_desc msg;
+#ifdef	GSSAPI_V2
+     OM_uint32 msg_ctx;
+#else	/* GSSAPI_V2 */
+     int msg_ctx;
+#endif	/* GSSAPI_V2 */
+     
+     msg_ctx = 0;
+     while (1) {
+	  (void) gss_display_status(&min_stat, code,
+				       type, GSS_C_NULL_OID,
+				       &msg_ctx, &msg);
+	  if (display_file)
+	      fprintf(display_file, "GSS-API error %s: %s\n", m,
+		      (char *)msg.value); 
+	  (void) gss_release_buffer(&min_stat, &msg);
+	  
+	  if (!msg_ctx)
+	       break;
+     }
+}
+
diff --git a/mechglue/src/tests/hammer/.Sanitize b/mechglue/src/tests/hammer/.Sanitize
new file mode 100644
index 000000000..260590333
--- /dev/null
+++ b/mechglue/src/tests/hammer/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+kdc5_hammer.c
+pp.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/hammer/ChangeLog b/mechglue/src/tests/hammer/ChangeLog
new file mode 100644
index 000000000..ee30e9ffa
--- /dev/null
+++ b/mechglue/src/tests/hammer/ChangeLog
@@ -0,0 +1,205 @@
+2003-01-12  Ezra Peisach  <epeisach@bu.edu>
+
+	* kdc5_hammer.c (verify_cs_pair): Use krb5_free_creds() instead of
+	krb5_free_cred_contents() to cleanup memory leak.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc5_hammer.c (main): Delete '-k' option which didn't do
+	anything.
+	(usage): Don't display '-k' option.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_hammer.c: Make prototypes unconditional.
+
+2001-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdc5_hammer.c (main): Initialize enctype at entry; eliminate
+	enctypedone variable.
+
+2000-07-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdc5_hammer.c: Move global (to file) enctype into main to prevent
+	being shadowed in other routines. Remove unused krb5_parse_lifetime().
+
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kdc5_hammer.c (main): Make sure buffer 'prefix' is null-terminated.
+
+2000-05-08  Ken Raeburn  <raeburn@mit.edu>
+	    Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kdc5_hammer.c (main): Don't overflow buffers "ctmp" or "stmp".
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdc5_hammer.c (main): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Mon Mar 30 16:48:17 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdc5_hammer.c (usage): Change usage to refelect reality
+	Add parenthesis around assignements in conditionals.
+
+Wed Feb 18 16:29:34 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 16:45:05 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sun Aug 17 14:26:57 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(SRCS) line.
+
+Tue Feb 18 18:21:16 1997  Richard Basch  <basch@lehman.com>
+
+	* kdc5_hammer.c (verify_cs_pair):
+		Use krb5_free_data_contents instead of krb5_xfree
+
+Sun Feb  9 01:45:03 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Fri Jan 19 23:00:37 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdc5_hammer.c: Remove krb5_kdc_default_options.
+
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * kdc5_hammer.c : Remove krb5_enctype from krb5_string_to_key() args.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * kdc5_hammer.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * kdc5_hammer.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate
+
+Wed Jul 12 12:31:51 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Remove V5_USE_SHARED_LIB
+
+
+Fri Jul 7 16:37:54 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling and LDFLAGS.
+	* configure.in - Add KRB5_LIBRARIES and V5_USE_SHARED_LIB.
+
+
+Thu Jun 22 12:02:48 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdc5_hammer.c - Change generation of server principals so that
+		we can use kdc5_hammer with kdb5_mkdums.  Also add logic
+		to time these operations.
+
+
+Sat Jun 10 23:08:04 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* kdc5_hammer.c: krb5_auth_context redefinitions
+
+Fri Jun  9 18:58:36 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Apr 20 13:06:53 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdc_hammer.c (usage()): Removed -M as not used.
+	               (main()): Add missing option to getopt call. 
+		       On exit, close the ccache, free context, and exit
+		       with status set to number of errors encountered.
+
+Mon Mar 27 07:56:26 1995 Chris Provenzano (proven@mit.edu)
+
+        * kdc5_hammer.c (verify_cs_pair()): Use new calling conventions 
+		for krb5_rd_req() and krb5_mk_req_extended(),
+
+Fri Mar 24 14:52:03 1995    <tytso@rsx-11.mit.edu>
+
+	* kdc5_hammer.c (get_tgt): Remove the call to krb5_os_localaddr()
+		since get_in_tkt_XXXX will default appropriately.
+
+Thu Mar  2 12:34:23 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:32:38 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:25:13 1995  John Gilmore  (gnu at toad.com)
+
+	* kdc5_hammer.c, pp.c:  Avoid <krb5/...> includes.
+
+Mon Feb 06 17:19:04 1995 Chris Provenzano  (proven@mit.edu)
+
+        * kdc5_hammer.c Removed krb5_keytype, changed krb5_enctype to
+                krb5_enctype *, changed krb5_preauthtype to krb5_preauthtype *
+                for krb5_get_in_tkt_with_password() rotuine.
+
+Fri Feb  3 11:45:23 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdc_hammer.c (get_server_key): Add keytype parameter
+
+Wed Jan 25 16:54:40 1995  Chris Provenzano (proven@mit.edu)
+
+        * Removed all narrow types and references to wide.h and narrow.h
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Tue Nov  8 17:53:40 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdc5_hammer.c (get_server_key): Use the published interface to
+		call krb5_string_to_key().
+
+Sun Oct 23 01:44:37 1994    (tytso@rsx-11)
+
+	* kdc5_hammer.c (main): Allow kdc_hammer to be called on an
+		arbitrary realm.
+
+Tue Oct  4 17:24:36 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdc_hammer.c (get_server_key): Add widen.h and narrow.h around
+		declaration to make argument types be widened.
+
+Fri Sep 30 22:08:45 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdc_hammer.c: Add placeholder for magic number
+
+Thu Sep 29 22:59:09 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+ 	* Makefile.in: Relink executable when libraries change
+
+
+Thu Sep 15 17:38:51 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdc_hammer.c (get_server_key): index() -> strchr()
+
diff --git a/mechglue/src/tests/hammer/Makefile.in b/mechglue/src/tests/hammer/Makefile.in
new file mode 100644
index 000000000..b9a17e048
--- /dev/null
+++ b/mechglue/src/tests/hammer/Makefile.in
@@ -0,0 +1,30 @@
+thisconfigdir=./..
+myfulldir=tests/hammer
+mydir=hammer
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+SRCS=$(srcdir)/kdc5_hammer.c
+
+all:: kdc5_hammer
+
+kdc5_hammer: kdc5_hammer.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o kdc5_hammer kdc5_hammer.o $(KRB5_BASE_LIBS)
+
+install::
+
+clean::
+	$(RM) kdc5_hammer.o kdc5_hammer
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)kdc5_hammer.$(OBJEXT): kdc5_hammer.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h
diff --git a/mechglue/src/tests/hammer/kdc5_hammer.c b/mechglue/src/tests/hammer/kdc5_hammer.c
new file mode 100644
index 000000000..5fd8d1c51
--- /dev/null
+++ b/mechglue/src/tests/hammer/kdc5_hammer.c
@@ -0,0 +1,530 @@
+/*
+ * tests/hammer/kdc5_hammer.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Initialize a credentials cache.
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+
+#include "k5-int.h"
+#include "com_err.h"
+
+#define KRB5_DEFAULT_OPTIONS 0
+#define KRB5_DEFAULT_LIFE 60*60*8 /* 8 hours */
+#define KRB5_RENEWABLE_LIFE 60*60*2 /* 2 hours */
+
+struct h_timer {
+    float	ht_cumulative;
+    float	ht_min;
+    float	ht_max;
+    krb5_int32	ht_observations;
+};
+
+extern int optind;
+extern char *optarg;
+char *prog;
+
+static int brief;
+static char *cur_realm = 0;
+static int do_timer = 0;
+
+krb5_data tgtname = {
+    0, 
+    KRB5_TGS_NAME_SIZE,
+    KRB5_TGS_NAME
+};
+
+int verify_cs_pair 
+	(krb5_context,
+		   char *,
+		   krb5_principal,
+		   char *,
+		   char *,
+		   int, int, int,
+		   krb5_ccache);
+
+int get_tgt 
+	(krb5_context,
+		   char *,
+		   krb5_principal *,
+		   krb5_ccache);
+
+static void
+usage(who, status)
+char *who;
+int status;
+{
+    fprintf(stderr,
+	    "usage: %s -p prefix -n num_to_check [-c cachename] [-r realmname]\n",
+	    who);
+    fprintf(stderr, "\t [-D depth]\n");
+    fprintf(stderr, "\t [-P preauth type] [-R repeat_count] [-t] [-b] [-v] \n");
+
+    exit(status);
+}
+
+static krb5_preauthtype * patype = NULL, patypedata[2] = { 0, -1 };
+static krb5_context test_context;
+
+struct timeval	tstart_time, tend_time;
+struct timezone	dontcare;
+
+struct h_timer in_tkt_times = { 0.0, 1000000.0, -1.0, 0 };
+struct h_timer tgs_req_times = { 0.0, 1000000.0, -1.0, 0 };
+/*
+ * Timer macros.
+ */
+#define	swatch_on()	((void) gettimeofday(&tstart_time, &dontcare))
+#define	swatch_eltime()	((gettimeofday(&tend_time, &dontcare)) ? -1.0 :	\
+			 (((float) (tend_time.tv_sec -			\
+				    tstart_time.tv_sec)) +		\
+			  (((float) (tend_time.tv_usec -		\
+				     tstart_time.tv_usec))/1000000.0)))
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    krb5_ccache ccache = NULL;
+    char *cache_name = NULL;		/* -f option */
+    int option;
+    int errflg = 0;
+    krb5_error_code code;
+    int num_to_check, n, i, j, repeat_count, counter;
+    int n_tried, errors;
+    char prefix[BUFSIZ], client[4096], server[4096];
+    int depth;
+    char ctmp[4096], ctmp2[BUFSIZ], stmp[4096], stmp2[BUFSIZ];
+    krb5_principal client_princ;
+    krb5_error_code retval;
+
+    krb5_init_context(&test_context);
+
+    if (strrchr(argv[0], '/'))
+	prog = strrchr(argv[0], '/')+1;
+    else
+	prog = argv[0];
+
+    num_to_check = 0;
+    depth = 1;
+    repeat_count = 1;
+    brief = 0;
+    n_tried = 0;
+    errors = 0;
+
+    while ((option = getopt(argc, argv, "D:p:n:c:R:P:e:bvr:t")) != -1) {
+	switch (option) {
+	case 't':
+	    do_timer = 1;
+	    break;
+	case 'b':
+	    brief = 1;
+	    break;
+	case 'v':
+	    brief = 0;
+	    break;
+	case 'R':
+	    repeat_count = atoi(optarg); /* how many times? */
+	    break;
+	case 'r':
+	    cur_realm = optarg;
+	    break;
+	case 'D':
+	    depth = atoi(optarg);       /* how deep to go */
+	    break;
+	case 'p':                       /* prefix name to check */
+	    strncpy(prefix, optarg, sizeof(prefix) - 1);
+	    prefix[sizeof(prefix) - 1] = '\0';
+	    break;
+       case 'n':                        /* how many to check */
+	    num_to_check = atoi(optarg);
+	    break;
+	case 'P':
+	    patypedata[0] = atoi(optarg);
+	    patype = patypedata;
+	    break;
+	case 'c':
+	    if (ccache == NULL) {
+		cache_name = optarg;
+		
+		code = krb5_cc_resolve (test_context, cache_name, &ccache);
+		if (code != 0) {
+		    com_err (prog, code, "resolving %s", cache_name);
+		    errflg++;
+		}
+	    } else {
+		fprintf(stderr, "Only one -c option allowed\n");
+		errflg++;
+	    }
+	    break;
+	case '?':
+	default:
+	    errflg++;
+	    break;
+	}
+    }
+
+    if (!(num_to_check && prefix[0])) usage(prog, 1);
+
+    if (!cur_realm) {
+	if ((retval = krb5_get_default_realm(test_context, &cur_realm))) {
+	    com_err(prog, retval, "while retrieving default realm name");
+	    exit(1);
+	}	    
+    }
+
+    if (ccache == NULL) {
+	if ((code = krb5_cc_default(test_context, &ccache))) {
+	    com_err(prog, code, "while getting default ccache");
+	    exit(1);
+	}
+    }
+
+    memset(ctmp, 0, sizeof(ctmp));
+    memset(stmp, 0, sizeof(stmp));
+
+    for (counter = 0; counter < repeat_count; counter++) {
+      fprintf(stderr, "\nRound %d\n", counter);
+
+      for (n = 1; n <= num_to_check; n++) {
+	/* build the new principal name */
+	/* we can't pick random names because we need to generate all the names 
+	   again given a prefix and count to test the db lib and kdb */
+	ctmp[0] = '\0';
+	for (i = 1; i <= depth; i++) {
+	  (void) sprintf(ctmp2, "%s%s%d-DEPTH-%d", (i != 1) ? "/" : "",
+			 prefix, n, i);
+	  ctmp2[sizeof(ctmp2) - 1] = '\0';
+	  strncat(ctmp, ctmp2, sizeof(ctmp) - 1 - strlen(ctmp));
+	  ctmp[sizeof(ctmp) - 1] = '\0';
+	  sprintf(client, "%s@%s", ctmp, cur_realm);
+
+	  if (get_tgt (test_context, client, &client_princ, ccache)) {
+	    errors++;
+	    n_tried++;
+	    continue;
+	  }
+	  n_tried++;
+
+	  stmp[0] = '\0';
+	  for (j = 1; j <= depth; j++) {
+	    (void) sprintf(stmp2, "%s%s%d-DEPTH-%d", (j != 1) ? "/" : "",
+			   prefix, n, j);
+	    stmp2[sizeof (stmp2) - 1] = '\0';
+	    strncat(stmp, stmp2, sizeof(stmp) - 1 - strlen(stmp));
+	    stmp[sizeof(stmp) - 1] = '\0';
+	    sprintf(server, "%s@%s", stmp, cur_realm);
+	    if (verify_cs_pair(test_context, client, client_princ, 
+			       stmp, cur_realm, n, i, j, ccache))
+	      errors++;
+	    n_tried++;
+	  }
+	  krb5_free_principal(test_context, client_princ);
+	}
+      }
+    }
+    fprintf (stderr, "\nTried %d.  Got %d errors.\n", n_tried, errors);
+    if (do_timer) {
+	if (in_tkt_times.ht_observations)
+	    fprintf(stderr, 
+		    "%8d  AS_REQ requests: %9.6f average (min: %9.6f, max:%9.6f)\n",
+		    in_tkt_times.ht_observations,
+		    in_tkt_times.ht_cumulative /
+		    (float) in_tkt_times.ht_observations,
+		    in_tkt_times.ht_min,
+		    in_tkt_times.ht_max);
+	if (tgs_req_times.ht_observations)
+	    fprintf(stderr, 
+		    "%8d TGS_REQ requests: %9.6f average (min: %9.6f, max:%9.6f)\n",
+		    tgs_req_times.ht_observations,
+		    tgs_req_times.ht_cumulative /
+		    (float) tgs_req_times.ht_observations,
+		    tgs_req_times.ht_min,
+		    tgs_req_times.ht_max);
+    }
+
+    (void) krb5_cc_close(test_context, ccache);
+
+    krb5_free_context(test_context);
+
+    exit(errors);
+  }
+
+
+static krb5_error_code 
+get_server_key(context, server, enctype, key)
+    krb5_context context;
+    krb5_principal server;
+    krb5_enctype enctype;
+    krb5_keyblock ** key;
+{
+    krb5_error_code retval;
+    krb5_encrypt_block eblock;
+    char * string;
+    krb5_data salt;
+    krb5_data pwd;
+
+    if ((retval = krb5_principal2salt(context, server, &salt)))
+	return retval;
+
+    if ((retval = krb5_unparse_name(context, server, &string)))
+	goto cleanup_salt;
+
+    pwd.data = string;
+    pwd.length = strlen(string);
+
+    if ((*key = (krb5_keyblock *)malloc(sizeof(krb5_keyblock)))) {
+    	krb5_use_enctype(context, &eblock, enctype);
+    	if ((retval = krb5_string_to_key(context, &eblock, *key, &pwd, &salt)))
+	    free(*key);
+    } else 
+        retval = ENOMEM;
+
+    free(string);
+
+cleanup_salt:
+    free(salt.data);
+    return retval;
+}
+
+int verify_cs_pair(context, p_client_str, p_client, service, hostname, 
+		   p_num, c_depth, s_depth, ccache)
+    krb5_context context;
+    char *p_client_str;
+    krb5_principal p_client;
+    char * service;
+    char * hostname;
+    int p_num, c_depth, s_depth;
+    krb5_ccache ccache;
+{
+    krb5_error_code 	  retval;
+    krb5_creds 	 	  creds;
+    krb5_creds 		* credsp = NULL;
+    krb5_ticket 	* ticket = NULL;
+    krb5_keyblock 	* keyblock = NULL;
+    krb5_auth_context 	  auth_context = NULL;
+    krb5_data		  request_data;
+    char		* sname;
+    float		  dt;
+
+    if (brief)
+      fprintf(stderr, "\tprinc (%d) client (%d) for server (%d)\n", 
+	      p_num, c_depth, s_depth);
+    else
+      fprintf(stderr, "\tclient %s for server %s\n", p_client_str, 
+	      service);
+
+    /* Initialize variables */
+    memset((char *)&creds, 0, sizeof(creds));
+
+    /* Do client side */
+    sname = (char *) malloc(strlen(service)+strlen(hostname)+2);
+    if (sname) {
+	sprintf(sname, "%s@%s", service, hostname);
+	retval = krb5_parse_name(context, sname, &creds.server);
+	free(sname);
+    }
+    else
+	retval = ENOMEM;
+    if (retval)
+	return(retval);
+
+    /* obtain ticket & session key */
+    if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
+	com_err(prog, retval, "while getting client princ for %s", hostname);
+    	krb5_free_cred_contents(context, &creds);
+	return retval;
+    }
+
+    if ((retval = krb5_get_credentials(context, 0,
+                                      ccache, &creds, &credsp))) {
+	com_err(prog, retval, "while getting creds for %s", hostname);
+    	krb5_free_cred_contents(context, &creds);
+	return retval;
+    }
+
+    krb5_free_cred_contents(context, &creds);
+
+    if (do_timer)
+	swatch_on();
+
+    if ((retval = krb5_mk_req_extended(context, &auth_context, 0, NULL,
+			            credsp, &request_data))) {
+	com_err(prog, retval, "while preparing AP_REQ for %s", hostname);
+        krb5_auth_con_free(context, auth_context);
+	return retval;
+    }
+
+    krb5_auth_con_free(context, auth_context);
+    auth_context = NULL;
+
+    /* Do server side now */
+    if ((retval = get_server_key(context, credsp->server,
+				credsp->keyblock.enctype, &keyblock))) {
+	com_err(prog, retval, "while getting server key for %s", hostname);
+	goto cleanup_rdata;
+    }
+
+    if (krb5_auth_con_init(context, &auth_context)) {
+	com_err(prog, retval, "while creating auth_context for %s", hostname);
+	goto cleanup_keyblock;
+    }
+
+    if (krb5_auth_con_setuseruserkey(context, auth_context, keyblock)) {
+	com_err(prog, retval, "while setting auth_context key %s", hostname);
+	goto cleanup_keyblock;
+    }
+
+    if ((retval = krb5_rd_req(context, &auth_context, &request_data, 
+			     NULL /* server */, 0, NULL, &ticket))) { 
+	com_err(prog, retval, "while decoding AP_REQ for %s", hostname); 
+        krb5_auth_con_free(context, auth_context);
+	goto cleanup_keyblock;
+    }
+
+    if (do_timer) {
+	dt = swatch_eltime();
+	tgs_req_times.ht_cumulative += dt;
+	tgs_req_times.ht_observations++;
+	if (dt > tgs_req_times.ht_max)
+	    tgs_req_times.ht_max = dt;
+	if (dt < tgs_req_times.ht_min)
+	    tgs_req_times.ht_min = dt;
+    }
+
+    krb5_auth_con_free(context, auth_context);
+
+    if (!(krb5_principal_compare(context,ticket->enc_part2->client,p_client))){
+    	char *returned_client;
+        if ((retval = krb5_unparse_name(context, ticket->enc_part2->client, 
+			       	       &returned_client))) 
+	    com_err (prog, retval, 
+		     "Client not as expected, but cannot unparse client name");
+      	else
+	    com_err (prog, 0, "Client not as expected (%s).", returned_client);
+	retval = KRB5_PRINC_NOMATCH;
+      	free(returned_client);
+    } else {
+	retval = 0;
+    }
+
+    krb5_free_ticket(context, ticket);
+
+cleanup_keyblock:
+    krb5_free_keyblock(context, keyblock);
+
+cleanup_rdata:
+    krb5_free_data_contents(context, &request_data);
+    if(credsp ) krb5_free_creds(context, credsp);
+
+    return retval;
+}
+
+int get_tgt (context, p_client_str, p_client, ccache)
+    krb5_context context;
+    char *p_client_str;
+    krb5_principal *p_client;
+    krb5_ccache ccache;
+{
+    char *cache_name = NULL;		/* -f option */
+    long lifetime = KRB5_DEFAULT_LIFE;	/* -l option */
+    int options = KRB5_DEFAULT_OPTIONS;
+    krb5_error_code code;
+    krb5_creds my_creds;
+    krb5_timestamp start;
+    krb5_principal tgt_server;
+    float dt;
+
+    if (!brief)
+      fprintf(stderr, "\tgetting TGT for %s\n", p_client_str);
+
+    if ((code = krb5_timeofday(context, &start))) {
+	com_err(prog, code, "while getting time of day");
+	return(-1);
+    }
+
+    memset((char *)&my_creds, 0, sizeof(my_creds));
+    
+    if ((code = krb5_parse_name (context, p_client_str, p_client))) {
+	com_err (prog, code, "when parsing name %s", p_client_str);
+	return(-1);
+    }
+
+
+    if ((code = krb5_build_principal_ext(context, &tgt_server,
+				krb5_princ_realm(context, *p_client)->length,
+				krb5_princ_realm(context, *p_client)->data,
+				tgtname.length,
+				tgtname.data,
+				krb5_princ_realm(context, *p_client)->length,
+				krb5_princ_realm(context, *p_client)->data,
+				0))) {
+	com_err(prog, code, "when setting up tgt principal");
+	return(-1);
+    }
+
+    my_creds.client = *p_client;
+    my_creds.server = tgt_server;
+
+    code = krb5_cc_initialize (context, ccache, *p_client);
+    if (code != 0) {
+	com_err (prog, code, "when initializing cache %s",
+		 cache_name?cache_name:"");
+	return(-1);
+    }
+
+    my_creds.times.starttime = 0;	/* start timer when request
+					   gets to KDC */
+    my_creds.times.endtime = start + lifetime;
+    my_creds.times.renew_till = 0;
+
+    if (do_timer)
+	swatch_on();
+
+    code = krb5_get_in_tkt_with_password(context, options, 0,
+					 NULL, patype, p_client_str, ccache,
+					 &my_creds, 0);
+    if (do_timer) {
+	dt = swatch_eltime();
+	in_tkt_times.ht_cumulative += dt;
+	in_tkt_times.ht_observations++;
+	if (dt > in_tkt_times.ht_max)
+	    in_tkt_times.ht_max = dt;
+	if (dt < in_tkt_times.ht_min)
+	    in_tkt_times.ht_min = dt;
+    }
+    my_creds.server = my_creds.client = 0;
+    krb5_free_principal(context, tgt_server);
+    krb5_free_cred_contents(context, &my_creds);
+    if (code != 0) {
+	com_err (prog, code, "while getting initial credentials");
+	return(-1);
+      }
+
+    return(0);
+}
diff --git a/mechglue/src/tests/hammer/pp.c b/mechglue/src/tests/hammer/pp.c
new file mode 100644
index 000000000..403d60de8
--- /dev/null
+++ b/mechglue/src/tests/hammer/pp.c
@@ -0,0 +1,28 @@
+/*
+ * tests/hammer/pp.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * For copying and distribution information, please see the file
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include "krb5.h"
+
+void
+print_principal(p)
+	krb5_principal	p;
+{
+	char	*buf;
+	krb5_error_code	retval;
+
+	if (retval = krb5_unparse_name(p, &buf)) {
+		com_err("DEBUG: Print_principal", retval,
+			"while unparsing name");
+		exit(1);
+	}
+	printf("%s\n", buf);
+	free(buf);
+}
diff --git a/mechglue/src/tests/misc/.Sanitize b/mechglue/src/tests/misc/.Sanitize
new file mode 100644
index 000000000..781d1f54b
--- /dev/null
+++ b/mechglue/src/tests/misc/.Sanitize
@@ -0,0 +1,32 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+test_getsockname.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/misc/ChangeLog b/mechglue/src/tests/misc/ChangeLog
new file mode 100644
index 000000000..559980a1f
--- /dev/null
+++ b/mechglue/src/tests/misc/ChangeLog
@@ -0,0 +1,21 @@
+2005-11-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (test_getpw.$(OBJEXT)): New intermediate target.
+	(test_getpw): Don't build directly from source.
+	(test_getsockname): New target.
+
+	* test_getsockname.c: Include autoconf.h.
+	(main): Fix type of variable 'i' used for size of socket address.
+
+2005-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (test_getpw): Depend on, and link against, the
+	support library.
+
+2005-03-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* test_getpw.c: New file.
+	* Makefile.in: New file, based on ../resolve/Makefile.in.
+	(test_getpw): New target.
+	(check): Build and run it.
+
diff --git a/mechglue/src/tests/misc/Makefile.in b/mechglue/src/tests/misc/Makefile.in
new file mode 100644
index 000000000..3f5cf03a2
--- /dev/null
+++ b/mechglue/src/tests/misc/Makefile.in
@@ -0,0 +1,35 @@
+thisconfigdir=./..
+myfulldir=tests/misc
+mydir=misc
+BUILDTOP=$(REL)..$(S)..
+RUN_SETUP = @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+OBJS=test_getpw.o
+SRCS=$(srcdir)/test_getpw.c
+
+all:: test_getpw
+
+check:: test_getpw
+	$(RUN_SETUP) ./test_getpw
+
+test_getpw: $(OUTPRE)test_getpw.$(OBJEXT) $(SUPPORT_DEPLIB)
+	$(CC_LINK) $(ALL_CFLAGS) -o test_getpw $(OUTPRE)test_getpw.$(OBJEXT) $(SUPPORT_LIB)
+test_getpw.$(OBJEXT): $(srcdir)/../misc/test_getpw.c ../../include/krb5/autoconf.h
+
+test_getsockname: $(OUTPRE)test_getsockname.$(OBJEXT)
+	$(CC_LINK) $(ALL_CFLAGS) -o test_getsockname $(OUTPRE)test_getsockname.$(OBJEXT) $(LIBS)
+
+install::
+
+clean::
+	$(RM) test_getpw
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)test_getpw.$(OBJEXT): test_getpw.c $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h
diff --git a/mechglue/src/tests/misc/test_getpw.c b/mechglue/src/tests/misc/test_getpw.c
new file mode 100644
index 000000000..cd5def6a9
--- /dev/null
+++ b/mechglue/src/tests/misc/test_getpw.c
@@ -0,0 +1,25 @@
+#include "krb5/autoconf.h"
+#include "k5-platform.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+int main()
+{
+    uid_t my_uid;
+    struct passwd *pwd, pwx;
+    char pwbuf[BUFSIZ];
+    int x;
+
+    my_uid = getuid();
+    printf("my uid: %ld\n", (long) my_uid);
+
+    x = k5_getpwuid_r(my_uid, &pwx, pwbuf, sizeof(pwbuf), &pwd);
+    printf("k5_getpwuid_r returns %d\n", x);
+    if (x != 0)
+	exit(1);
+    printf("    username is '%s'\n", pwd->pw_name);
+    exit(0);
+}
diff --git a/mechglue/src/tests/misc/test_getsockname.c b/mechglue/src/tests/misc/test_getsockname.c
new file mode 100644
index 000000000..90bf68dfd
--- /dev/null
+++ b/mechglue/src/tests/misc/test_getsockname.c
@@ -0,0 +1,91 @@
+/*
+ * test_getsockname.c
+ * 
+ * This routine demonstrates a bug in the socket emulation library of
+ * Solaris and other monstrosities that uses STREAMS.  On other
+ * machines with a real networking layer, it prints the local
+ * interface address that is used to send a message to a specific
+ * host.  On Solaris, it prints out 0.0.0.0.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include "krb5/autoconf.h"
+
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    int sock;
+    GETSOCKNAME_ARG3_TYPE i;
+    struct hostent *host;
+    struct sockaddr_in s_sock;		/* server address */
+    struct sockaddr_in c_sock;		/* client address */
+    
+    char *hostname;
+
+    if (argc == 2) {
+	hostname = argv[1];
+    } else {
+	fprintf(stderr, "Usage: %s hostname\n", argv[0]);
+	exit(1);
+    }
+
+    /* Look up server host */
+    if ((host = gethostbyname(hostname)) == (struct hostent *) 0) {
+	fprintf(stderr, "%s: unknown host\n", hostname);
+	exit(1);
+    }
+
+    /* Set server's address */
+    (void) memset((char *)&s_sock, 0, sizeof(s_sock));
+
+    memcpy((char *)&s_sock.sin_addr, host->h_addr, sizeof(s_sock.sin_addr));
+#ifdef DEBUG
+    printf("s_sock.sin_addr is %s\n", inet_ntoa(s_sock.sin_addr));
+#endif
+    s_sock.sin_family = AF_INET;
+    s_sock.sin_port = htons(5555);
+    
+    /* Open a socket */
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	perror("socket");
+	exit(1);
+    }
+
+    memset((char *)&c_sock, 0, sizeof(c_sock));
+    c_sock.sin_family = AF_INET;
+
+    /* Bind it to set the address; kernel will fill in port # */
+    if (bind(sock, (struct sockaddr *)&c_sock, sizeof(c_sock)) < 0) {
+	perror("bind");
+	exit(1);
+    }
+	
+    /* "connect" the datagram socket; this is necessary to get a local address
+       properly bound for getsockname() below. */
+    if (connect(sock, (struct sockaddr *)&s_sock, sizeof(s_sock)) == -1) {
+	perror("connect");
+	exit(1);
+    }
+    
+    /* Get my address */
+    memset((char *) &c_sock, 0, sizeof(c_sock));
+    i = sizeof(c_sock);
+    if (getsockname(sock, (struct sockaddr *)&c_sock, &i) < 0) {
+	perror("getsockname");
+	exit(1);
+    }
+
+    printf("My interface address is: %s\n", inet_ntoa(c_sock.sin_addr));
+    
+    exit(0);
+}
diff --git a/mechglue/src/tests/misc/test_nfold.c b/mechglue/src/tests/misc/test_nfold.c
new file mode 100644
index 000000000..78b586618
--- /dev/null
+++ b/mechglue/src/tests/misc/test_nfold.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * All rights reserved.
+ * 
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government.  It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+    int inlen, outlen, i;
+    unsigned char *instr, *outstr;
+
+    if (argc != 3) {
+	fprintf(stderr, "%s: instr outlen\n", argv[0]);
+	exit(1);
+    }
+
+    instr = (unsigned char *) argv[1];
+    inlen = strlen(instr)*8;
+    outlen = atoi(argv[2]);
+    if (outlen%8) {
+	fprintf(stderr, "outlen must be a multiple of 8\n");
+	exit(1);
+    }
+
+    if ((outstr = (unsigned char *) malloc(outlen/8)) == NULL) {
+	fprintf(stderr, "ENOMEM\n");
+	exit(1);
+    }
+
+    krb5_nfold(inlen,instr,outlen,outstr);
+
+    printf("%d-fold(",outlen);
+    for (i=0; i<(inlen/8); i++)
+	printf("%02x",instr[i]);
+    printf(") = ");
+    for (i=0; i<(outlen/8); i++)
+	printf("%02x",outstr[i]);
+    printf("\n");
+
+    exit(0);
+}
diff --git a/mechglue/src/tests/resolve/.Sanitize b/mechglue/src/tests/resolve/.Sanitize
new file mode 100644
index 000000000..8fe14489d
--- /dev/null
+++ b/mechglue/src/tests/resolve/.Sanitize
@@ -0,0 +1,37 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+resolve.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/resolve/ChangeLog b/mechglue/src/tests/resolve/ChangeLog
new file mode 100644
index 000000000..9c87c632f
--- /dev/null
+++ b/mechglue/src/tests/resolve/ChangeLog
@@ -0,0 +1,132 @@
+2005-10-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (resolve, addrinfo-test, fake-addrinfo-test): Don't
+	use "$<" outside of implicit rules.
+
+2005-09-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo-test.c: New file.
+	* Makefile.in (check): Do pass arguments to addrinfo-test
+	invocation added by Marc's patch.
+	(fake-addrinfo-test): New target.
+	(all): Depend on it.
+	(SRCS): Fix typo in last change.  Add fake-addrinfo-test.c.
+	(OBJS): Add fake-addrinfo-test.o.
+
+2005-09-01  Marc Aurele La France  <tsi@ualberta.ca>
+
+	* Makefile.in:  Build addrinfo-test.
+	* addrinfo-test.c (main):  'numeric' -> 'numerichost';  Add -n option
+	to set AI_NUMERICSERV (if available);  print usage message when no
+	arguments are given.
+
+2004-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* addrinfo-test.c: New file.
+
+2003-07-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* resolve.c (main): If gethostbyname fails, report the failing
+	hostname.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2001-07-06  Ezra Peisach  <epeisach@mit.edu>
+
+	* resolve.c: Include stdlib.h (if present) for exit() prototype.
+
+2001-06-12  Tom Yu  <tlyu@mit.edu>
+
+	* resolve.c (main): Make error message note that misconfiguration
+	of /etc/hosts, as well as problems with resolver library, are all
+	likely to cause failure.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+Mon Mar 30 13:50:15 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* resolve.c: Include unistd.h if present on system (for
+	        gethostname prototype). 
+
+Wed Feb 18 16:30:37 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 16:44:41 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Feb 26 23:12:24 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Add $(LIBS) so that compile doesn't blow out under
+	Solaris due to lack of -lnsl -lsocket.
+
+Sat Feb 22 20:28:32 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* resolve.c (main): Make the test for a FQDN be a bit more
+		stringent.
+
+	* Makefile.in (resolve): The resolve program doesn't need to be
+		linked against the Kerberos library.
+
+Sun Feb  9 01:48:01 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Mon Mar 18 21:49:39 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add KRB5_RUN_FLAGS
+
+	* Makefile.in: Use runtime flags.
+
+Wed Sep 13 13:57:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* resolve.c (main): Fix fencepost error; use argv[1] to test for a
+		specfied host if argc is >= 1, not just > 1.
+
+Wed Jul 12 12:32:14 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add LD_LIBRARY_PATH in case we were linked with shared
+		libraries by default.
+	* configure.in - Remove V5_USE_SHARED_LIB.
+
+
+Fri Jul 7 16:38:47 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove LDFLAGS and use DEPLIBS.
+	* configure.in - Add KRB5_LIBRARIES and V5_USE_SHARED_LIB
+
+Fri Jun  9 18:58:43 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Mon May  1 20:00:18 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* resolve.c (main): Add --quiet option which only prints the fully
+		qualified domain name.  This will allow this routine to be
+		used in the deja gnu tests to determine the FQDN of the
+		local host.
+
+Tue Apr 25 22:16:38 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* resolve.c (main): copy the address sent back by gethostbyname
+	before calling gethostbyaddr, since the return is *static*.
+	(main): reindent declaration to make add-change-log-entry happy.
+
diff --git a/mechglue/src/tests/resolve/Makefile.in b/mechglue/src/tests/resolve/Makefile.in
new file mode 100644
index 000000000..a08706989
--- /dev/null
+++ b/mechglue/src/tests/resolve/Makefile.in
@@ -0,0 +1,44 @@
+thisconfigdir=./..
+myfulldir=tests/resolve
+mydir=resolve
+BUILDTOP=$(REL)..$(S)..
+RUN_SETUP = @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+OBJS=resolve.o addrinfo-test.o fake-addrinfo-test.o
+SRCS=$(srcdir)/resolve.c $(srcdir)/addrinfo-test.c \
+	$(srcdir)/fake-addrinfo-test.c
+
+all:: resolve addrinfo-test fake-addrinfo-test
+
+resolve: resolve.o
+	$(CC_LINK) -o $@ resolve.o $(LIBS)
+
+addrinfo-test: addrinfo-test.o
+	$(CC_LINK) -o $@ addrinfo-test.o $(LIBS)
+
+fake-addrinfo-test: fake-addrinfo-test.o
+	$(CC_LINK) -o $@ fake-addrinfo-test.o $(SUPPORT_LIB) $(LIBS)
+
+check:: resolve addrinfo-test
+	$(RUN_SETUP) ./resolve
+	$(RUN_SETUP) ./addrinfo-test -p telnet
+	$(RUN_SETUP) ./fake-addrinfo-test -p telnet
+
+install::
+
+clean::
+	$(RM) resolve addrinfo-test
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)resolve.$(OBJEXT): resolve.c
+$(OUTPRE)addrinfo-test.$(OBJEXT): addrinfo-test.c
+$(OUTPRE)fake-addrinfo-test.$(OBJEXT): fake-addrinfo-test.c \
+  addrinfo-test.c $(SRCTOP)/include/fake-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h
diff --git a/mechglue/src/tests/resolve/addrinfo-test.c b/mechglue/src/tests/resolve/addrinfo-test.c
new file mode 100644
index 000000000..1aa30602c
--- /dev/null
+++ b/mechglue/src/tests/resolve/addrinfo-test.c
@@ -0,0 +1,302 @@
+/*
+ * test/resolve/addrinfo-test.c
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * A simple program to test the functionality of the getaddrinfo function.
+ *
+ * Usage:
+ *   addrinfo-test [-t|-u|-R|-I] [-d|-s|-r] [-p port] [-P] [hostname]
+ *
+ *   When invoked with no arguments, NULL is used for the node name,
+ *   which (at least with a non-null "port") means a socket address
+ *   is desired that can be used with connect() or bind() (depending
+ *   on whether "-P" is given).
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h> /* needed for IPPROTO_* on NetBSD */
+#ifdef USE_FAKE_ADDRINFO
+#include "fake-addrinfo.h"
+#endif
+
+static const char *protoname (int p) {
+    static char buf[30];
+
+#define X(N) if (p == IPPROTO_ ## N) return #N
+
+    X(TCP);
+    X(UDP);
+    X(ICMP);
+    X(IPV6);
+#ifdef IPPROTO_GRE
+    X(GRE);
+#endif
+    X(NONE);
+    X(RAW);
+#ifdef IPPROTO_COMP
+    X(COMP);
+#endif
+
+    sprintf(buf, " %-2d", p);
+    return buf;
+}	
+
+static const char *socktypename (int t) {
+    static char buf[30];
+    switch (t) {
+    case SOCK_DGRAM: return "DGRAM";
+    case SOCK_STREAM: return "STREAM";
+    case SOCK_RAW: return "RAW";
+    case SOCK_RDM: return "RDM";
+    case SOCK_SEQPACKET: return "SEQPACKET";
+    }
+    sprintf(buf, " %-2d", t);
+    return buf;
+}
+
+static char *whoami;
+
+static void usage () {
+    fprintf(stderr,
+	    "usage:\n"
+	    "\t%s [ options ] [host]\n"
+	    "options:\n"
+	    "\t-t\tspecify protocol IPPROTO_TCP\n"
+	    "\t-u\tspecify protocol IPPROTO_UDP\n"
+	    "\t-R\tspecify protocol IPPROTO_RAW\n"
+	    "\t-I\tspecify protocol IPPROTO_ICMP\n"
+	    "\n"
+	    "\t-d\tspecify socket type SOCK_DGRAM\n"
+	    "\t-s\tspecify socket type SOCK_STREAM\n"
+	    "\t-r\tspecify socket type SOCK_RAW\n"
+	    "\n"
+	    "\t-4\tspecify address family AF_INET\n"
+	    "\t-6\tspecify address family AF_INET6\n"
+	    "\n"
+	    "\t-p P\tspecify port P (service name or port number)\n"
+	    "\t-N\thostname is numeric, skip DNS query\n"
+	    "\t-n\tservice/port is numeric (sets AI_NUMERICSERV)\n"
+	    "\t-P\tset AI_PASSIVE\n"
+	    "\n"
+	    "default: protocol 0, socket type 0, address family 0, null port\n"
+	    ,
+	    whoami);
+    /* [ -t | -u | -R | -I ] [ -d | -s | -r ] [ -p port ] */
+    exit (1);
+}
+
+static const char *familyname (int f) {
+    static char buf[30];
+    switch (f) {
+    default:
+	sprintf(buf, "AF %d", f);
+	return buf;
+    case AF_INET: return "AF_INET";
+    case AF_INET6: return "AF_INET6";
+    }
+}
+
+#define eaistr(X) (X == EAI_SYSTEM ? strerror(errno) : gai_strerror(X))
+
+int main (int argc, char *argv[])
+{
+    struct addrinfo *ap, *ap2;
+    int err, numerichost = 0, numericserv = 0;
+    char *hname, *port = 0, *sep;
+    struct addrinfo hints;
+
+    whoami = strrchr(argv[0], '/');
+    if (whoami == 0)
+	whoami = argv[0];
+    else
+	whoami = whoami+1;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = 0;
+    hints.ai_socktype = 0;
+
+    hname = 0;
+    hints.ai_family = 0;
+
+    if (argc == 1)
+	usage ();
+
+    while (++argv, --argc > 0) {
+	char *arg;
+	arg = *argv;
+
+	if (*arg != '-')
+	    hname = arg;
+	else if (arg[1] == 0 || arg[2] != 0)
+	    usage ();
+	else
+	    switch (arg[1]) {
+	    case 'u':
+		hints.ai_protocol = IPPROTO_UDP;
+		break;
+	    case 't':
+		hints.ai_protocol = IPPROTO_TCP;
+		break;
+	    case 'R':
+		hints.ai_protocol = IPPROTO_RAW;
+		break;
+	    case 'I':
+		hints.ai_protocol = IPPROTO_ICMP;
+		break;
+	    case 'd':
+		hints.ai_socktype = SOCK_DGRAM;
+		break;
+	    case 's':
+		hints.ai_socktype = SOCK_STREAM;
+		break;
+	    case 'r':
+		hints.ai_socktype = SOCK_RAW;
+		break;
+	    case 'p':
+		if (argv[1] == 0 || argv[1][0] == 0 || argv[1][0] == '-')
+		    usage ();
+		port = argv[1];
+		argc--, argv++;
+		break;
+	    case '4':
+		hints.ai_family = AF_INET;
+		break;
+	    case '6':
+		hints.ai_family = AF_INET6;
+		break;
+	    case 'N':
+		numerichost = 1;
+		break;
+	    case 'n':
+		numericserv = 1;
+		break;
+	    case 'P':
+		hints.ai_flags |= AI_PASSIVE;
+		break;
+	    default:
+		usage ();
+	    }
+    }
+
+    if (hname && !numerichost)
+	hints.ai_flags |= AI_CANONNAME;
+    if (numerichost) {
+#ifdef AI_NUMERICHOST
+	hints.ai_flags |= AI_NUMERICHOST;
+#else
+	fprintf(stderr, "AI_NUMERICHOST not defined on this platform\n");
+	exit(1);
+#endif
+    }
+    if (numericserv) {
+#ifdef AI_NUMERICSERV
+	hints.ai_flags |= AI_NUMERICSERV;
+#else
+	fprintf(stderr, "AI_NUMERICSERV not defined on this platform\n");
+	exit(1);
+#endif
+    }
+
+    printf("getaddrinfo(hostname %s, service %s,\n"
+	   "            hints { ",
+	   hname ? hname : "(null)", port ? port : "(null)");
+    sep = "";
+#define Z(FLAG) if (hints.ai_flags & AI_##FLAG) printf("%s%s", sep, #FLAG), sep = "|"
+    Z(CANONNAME);
+    Z(PASSIVE);
+#ifdef AI_NUMERICHOST
+    Z(NUMERICHOST);
+#endif
+#ifdef AI_NUMERICSERV
+    Z(NUMERICSERV);
+#endif
+    if (sep[0] == 0)
+	printf ("no-flags");
+    if (hints.ai_family)
+	printf(" %s", familyname(hints.ai_family));
+    if (hints.ai_socktype)
+	printf(" SOCK_%s", socktypename(hints.ai_socktype));
+    if (hints.ai_protocol)
+	printf(" IPPROTO_%s", protoname(hints.ai_protocol));
+    printf(" }):\n");
+
+    err = getaddrinfo(hname, port, &hints, &ap);
+    if (err) {
+	printf("\terror => %s\n", eaistr(err));
+	return 1;
+    }
+
+#if defined(SIN6_LEN)
+    if (ap->ai_addr->sa_len == 0)
+	printf ("BAD: sa_len not set!\n");
+#endif
+
+
+    for (ap2 = ap; ap2; ap2 = ap2->ai_next) {
+	char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+	/* If we don't do this, even AIX's own getnameinfo will reject
+	   the sockaddr structures.  The sa_len field doesn't get set
+	   either, on AIX, but getnameinfo won't complain.  */
+	if (ap2->ai_addr->sa_family == 0) {
+	    printf("BAD: sa_family zero! fixing...\n");
+	    ap2->ai_addr->sa_family = ap2->ai_family;
+	} else if (ap2->ai_addr->sa_family != ap2->ai_family) {
+	    printf("BAD: sa_family != ai_family! fixing...\n");
+	    ap2->ai_addr->sa_family = ap2->ai_family;
+	}
+	if (getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof(hbuf),
+			pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV))
+	    strcpy(hbuf, "..."), strcpy(pbuf, "...");
+	printf("%p:\n"
+	       "\tfamily = %s\tproto = %-4s\tsocktype = %s\n",
+	       ap2, familyname(ap2->ai_family),
+	       protoname (ap2->ai_protocol),
+	       socktypename (ap2->ai_socktype));
+	if (ap2->ai_canonname) {
+	    if (ap2->ai_canonname[0])
+		printf("\tcanonname = %s\n", ap2->ai_canonname);
+	    else
+		printf("BAD: ai_canonname is set but empty!\n");
+	} else if (ap2 == ap && (hints.ai_flags & AI_CANONNAME)) {
+	    printf("BAD: first ai_canonname is null!\n");
+	}
+	printf("\taddr = %-28s\tport = %s\n", hbuf, pbuf);
+
+	err = getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof (hbuf),
+			  pbuf, sizeof(pbuf), NI_NAMEREQD);
+	if (err)
+	    printf("\tgetnameinfo(NI_NAMEREQD): %s\n", eaistr(err));
+	else
+	    printf("\tgetnameinfo => %s, %s\n", hbuf, pbuf);
+    }
+    return 0;
+}
diff --git a/mechglue/src/tests/resolve/fake-addrinfo-test.c b/mechglue/src/tests/resolve/fake-addrinfo-test.c
new file mode 100644
index 000000000..f04024d73
--- /dev/null
+++ b/mechglue/src/tests/resolve/fake-addrinfo-test.c
@@ -0,0 +1,2 @@
+#define USE_FAKE_ADDRINFO
+#include "addrinfo-test.c"
diff --git a/mechglue/src/tests/resolve/resolve.c b/mechglue/src/tests/resolve/resolve.c
new file mode 100644
index 000000000..b1fe969d3
--- /dev/null
+++ b/mechglue/src/tests/resolve/resolve.c
@@ -0,0 +1,170 @@
+/*
+ * test/resolve/resolve.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * A simple program to test the functionality of the resolver library.
+ * It simply will try to get the IP address of the host, and then look 
+ * up the name from the address. If the resulting name does not contain the
+ * domain name, then the resolve library is broken.
+ *
+ * Warning: It is possible to fool this program into thinking everything is 
+ * alright byt a clever use of /etc/hosts - but this is better than nothing.
+ *
+ * Usage:
+ *   resolve [hostname]
+ *
+ *   When invoked with no arguments, gethostname is used for the local host.
+ *
+ */
+
+/* This program tests the resolve library and sees if it is broken... */
+
+#include <stdio.h>
+
+#if STDC_HEADERS
+#include <string.h>
+#else
+#ifndef HAVE_STRCHR
+#define strchr index
+#endif
+char *strchr();
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <netdb.h>
+
+int
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+	char myname[MAXHOSTNAMELEN+1];
+	char *ptr;
+	char addrcopy[4];
+	struct hostent *host;
+	int quiet = 0;
+
+	argc--; argv++;
+	while (argc) {
+	    if ((strcmp(*argv, "--quiet") == 0) ||
+		(strcmp(*argv, "-q") == 0)) {
+		quiet++;
+	    } else 
+		break;
+	    argc--; argv++;
+	}
+
+	if (argc >= 1) {
+		strncpy(myname, *argv, MAXHOSTNAMELEN);
+	} else {
+		if(gethostname(myname, MAXHOSTNAMELEN)) {
+			perror("gethostname failure");
+			exit(1);
+		}
+	}
+	
+	myname[MAXHOSTNAMELEN] = '\0';	/* for safety */
+	
+	/* Look up the address... */
+	if (!quiet)
+	    printf("Hostname:  %s\n", myname);
+	
+
+	/* Set the hosts db to close each time - effectively rewinding file */
+	sethostent(0);
+
+	if((host = gethostbyname (myname)) == NULL) {
+		fprintf(stderr,
+			"Could not look up address for hostname '%s' - fatal\n",
+			myname);
+		exit(2);
+	}
+	
+	ptr = host->h_addr_list[0];
+#define UC(a) (((int)a)&0xff)
+	if (!quiet)
+	    printf("Host address: %d.%d.%d.%d\n", 
+		   UC(ptr[0]), UC(ptr[1]), UC(ptr[2]), UC(ptr[3]));
+
+	memcpy(addrcopy, ptr, 4);
+
+	/* Convert back to full name */
+	if((host = gethostbyaddr(addrcopy, 4, AF_INET)) == NULL) {
+		fprintf(stderr, "Error looking up IP address - fatal\n");
+		exit(2);
+	}
+	
+	if (quiet)
+	    printf("%s\n", host->h_name);
+	else
+	    printf("FQDN: %s\n", host->h_name);
+	
+	/*
+	 * The host name must have at least one '.' in the name, and
+	 * if there is only one '.', it must not be at the end of the
+	 * string.  (i.e., "foo." is not a FQDN)
+	 */
+	ptr = strchr(host->h_name, '.');
+	if (ptr == NULL || ptr[1] == '\0') {
+		fprintf(stderr,
+			"\nResolve library did not return a "
+			"fully qualified domain name.\n\n"
+			"If you are using /etc/hosts before DNS, "
+			"e.g. \"files\" is listed first\n"
+			"for \"hosts:\" in nsswitch.conf, ensure that "
+			"you have listed the FQDN\n"
+			"as the first name for the local host.\n\n"
+			"If this does not correct the problem, "
+			"you may have to reconfigure the kerberos\n"
+			"distribution to select a "
+			"different set of libraries using \n"
+			"--with-netlib[=libs]\n");
+		exit(3);
+	}
+
+	if (!quiet)
+	    printf("Resolve library appears to have passed the test\n");
+
+	/* All ok */
+	exit(0);
+
+}
+
+
diff --git a/mechglue/src/tests/shlib/ChangeLog b/mechglue/src/tests/shlib/ChangeLog
new file mode 100644
index 000000000..bfea7ca78
--- /dev/null
+++ b/mechglue/src/tests/shlib/ChangeLog
@@ -0,0 +1,31 @@
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_loader): Use DL_LIB instead of -ldl.
+
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* t_loader.c (verbose): New variable.
+	(do_close_1): Drop filename argument.  Change messages
+	accordingly, and only display them if verbose.  Line up "done"
+	messages vertically.
+	(do_open_1): Likewise.  Add library version argument, used when on
+	AIX, in combination with RTLD_MEMBER.
+	(do_open): Don't pass filename.  Do pass library version; callers
+	changed.
+	(do_close): Don't pass filename.
+	(get_sym_1): Renamed from get_sym, added line number argument.
+	Print messages if verbose.
+	(get_sym): New macro.
+	(xbasename): Function deleted.
+	(HORIZ): New macro.
+	(main): Turn off output buffering.  Print messages before and
+	after calling functions in loaded libraries.  Disable first set of
+	tests, that don't call any functions.  Test gssapi library without
+	loading any other libraries, then test it after loading com_err,
+	and unload com_err first.
+
+2005-02-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: New file.
+	* t_loader.c: New file.
+
diff --git a/mechglue/src/tests/shlib/Makefile.in b/mechglue/src/tests/shlib/Makefile.in
new file mode 100644
index 000000000..49cf20fa2
--- /dev/null
+++ b/mechglue/src/tests/shlib/Makefile.in
@@ -0,0 +1,39 @@
+thisconfigdir=./..
+myfulldir=tests/shlib
+mydir=shlib
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@
+
+VALGRIND=valgrind
+VALGRINDFLAGS=--tool=memcheck --leak-check=yes --show-reachable=yes
+
+SRCS=$(srcdir)/t_loader.c
+
+all::
+
+run-t_loader: t_loader
+	$(RUN_SETUP) ./t_loader
+
+valgrind-t_loader: t_loader
+	$(RUN_SETUP) $(VALGRIND) $(VALGRINDFLAGS) ./t_loader
+
+t_loader: t_loader.o
+	$(CC_LINK) -o t_loader t_loader.o $(DL_LIB)
+
+check-unix::
+
+install::
+
+clean::
+	$(RM) t_loader.o t_loader
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)t_loader.$(OBJEXT): t_loader.c $(BUILDTOP)/include/krb5/autoconf.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/gssapi/gssapi.h
diff --git a/mechglue/src/tests/shlib/t_loader.c b/mechglue/src/tests/shlib/t_loader.c
new file mode 100644
index 000000000..ecd6a4e83
--- /dev/null
+++ b/mechglue/src/tests/shlib/t_loader.c
@@ -0,0 +1,372 @@
+/* foo */
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "krb5/autoconf.h"
+#include "krb5.h"
+#include "gssapi/gssapi.h"
+#define HAVE_DLOPEN 1
+
+static int verbose = 1;
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+/* Solaris man page recommends link.h too */
+
+/* lazy = 1 means resolve symbols later, 0 means now; any
+   other flags we should be testing?  On Windows, maybe?
+
+   Return value is the library handle.  On error, print a message and
+   exit.  */
+#define do_open(LIB,REV,FLAGS) do_open_1(LIB,REV,FLAGS,__LINE__)
+static void *do_open_1(const char *libname, const char *rev, int lazy, int line);
+
+/* Look up a function symbol in the library and return a pointer.
+
+   The return value may need casting to the correct type.  On error,
+   print a message and exit.  */
+static void *get_sym_1(void *libhandle, const char *sym, int line);
+#define get_sym(LIB, NAME) get_sym_1(LIB, NAME, __LINE__)
+#define GET_FSYM(TYPE, LIB, NAME) ((TYPE) get_sym(LIB, NAME))
+#define get_gfun(LIB, NAME) ((OM_uint32 KRB5_CALLCONV(*)()) get_sym(LIB, NAME))
+
+/* Close dynamically-opened library.
+
+   If the OS reports an error in doing so, print a message and
+   exit.  */
+#define do_close(X) do_close_1(X, __LINE__)
+static void do_close_1(void *libhandle, int line);
+
+#ifdef HAVE_DLOPEN
+
+#ifdef _AIX
+# define SHLIB_SUFFIX ".a"
+#else
+# define SHLIB_SUFFIX ".so"
+#endif
+
+#define HORIZ 25
+
+static void *do_open_1(const char *libname, const char *rev,
+		       int lazy, int line)
+{
+    void *p;
+    char *namebuf;
+    size_t sz;
+
+    if (verbose)
+	printf("from line %d: do_open(%s)...%*s", line, libname,
+	       HORIZ-strlen(libname), "");
+    sz = strlen(SHLIB_SUFFIX) + strlen(libname) + 4;
+#ifdef _AIX
+    sz += strlen(rev) + 8;
+#endif
+    namebuf = malloc(sz);
+    if (namebuf == 0) {
+	perror("malloc");
+	exit(1);
+    }
+    strcpy(namebuf, "lib");
+    strcat(namebuf, libname);
+    strcat(namebuf, SHLIB_SUFFIX);
+#ifdef _AIX
+    strcat(namebuf, "(shr.o.");
+    strcat(namebuf, rev);
+    strcat(namebuf, ")");
+#endif
+
+#ifndef RTLD_MEMBER
+#define RTLD_MEMBER 0
+#endif
+    p = dlopen(namebuf, (lazy ? RTLD_LAZY : RTLD_NOW) | RTLD_MEMBER);
+    if (p == 0) {
+	fprintf(stderr, "dlopen of %s failed: %s\n", namebuf, dlerror());
+	exit(1);
+    }
+    free(namebuf);
+    if (verbose)
+	printf("done: %p\n", p);
+    return p;
+}
+
+#define SYM_PREFIX ""
+static void *get_sym_1(void *libhandle, const char *symname, int line)
+{
+    void *s;
+
+    /* Bah.  Fix this later, if we care.  */
+    assert(strlen(SYM_PREFIX) == 0);
+
+    if (verbose)
+	printf("from line %d: get_sym(%s)...%*s", line, symname,
+	       HORIZ-strlen(symname), "");
+
+    s = dlsym(libhandle, symname);
+    if (s == 0) {
+	fprintf(stderr, "symbol %s not found\n", symname);
+	exit(1);
+    }
+    if (verbose)
+	printf("done: %p\n", s);
+    return s;
+}
+
+static void do_close_1(void *libhandle, int line)
+{
+    if (verbose) {
+	char pbuf[3*sizeof(libhandle)+4];
+	sprintf(pbuf, "%p", libhandle);
+	printf("from line %d: do_close(%s)...%*s", line, pbuf,
+	       HORIZ-1-strlen(pbuf), "");
+    }
+    if (dlclose(libhandle) != 0) {
+	fprintf(stderr, "dlclose failed: %s\n", dlerror());
+	exit(1);
+    }
+    if (verbose)
+	printf("done\n");
+}
+
+#elif defined _WIN32
+
+static void *do_open(const char *libname, int lazy)
+{
+    /* To be written?  */
+    abort();
+}
+
+static void *get_sym(void *libhandle, const char *symname)
+{
+    abort();
+}
+
+static void do_close(void *libhandle)
+{
+    abort();
+}
+
+#else
+
+static void *do_open(const char *libname, int lazy)
+{
+    printf("don't know how to do dynamic loading here, punting\n");
+    exit(0);
+}
+
+static void *get_sym(void *libhandle, const char *symname)
+{
+    abort();
+}
+
+static void do_close(void *libhandle)
+{
+    abort();
+}
+
+#endif
+
+int main()
+{
+    void *celib, *k5lib, *gsslib, *celib2;
+
+    (void) setvbuf(stdout, 0, _IONBF, 0);
+
+#if 0
+    /* Simplest test: Load, then unload out of order.  */
+    celib = do_open("com_err", "3.0", 0);
+    k5lib = do_open("krb5", "3.2", 0);
+    gsslib = do_open("gssapi_krb5", "2.2", 0);
+    celib2 = do_open("com_err", "3.0", 0);
+    do_close(celib);
+    do_close(k5lib);
+    do_close(celib2);
+    do_close(gsslib);
+#endif
+
+    celib = do_open("com_err", "3.0", 0);
+    k5lib = do_open("krb5", "3.2", 0);
+    gsslib = do_open("gssapi_krb5", "2.2", 0);
+    celib2 = do_open("com_err", "3.0", 0);
+    do_close(celib2);
+    {
+	typedef krb5_error_code KRB5_CALLCONV (*ict)(krb5_context *);
+	typedef void KRB5_CALLCONV (*fct)(krb5_context);
+
+	ict init_context = (ict) get_sym(k5lib, "krb5_init_context");
+	fct free_context = (fct) get_sym(k5lib, "krb5_free_context");
+	krb5_context ctx;
+	krb5_error_code err;
+
+#define CALLING(S) (verbose ? printf("at   line %d: calling %s...%*s", __LINE__, #S, (int)(HORIZ+1-strlen(#S)), "") : 0)
+#define DONE() (verbose ? printf("done\n") : 0)
+
+	CALLING(krb5_init_context);
+	err = init_context(&ctx);
+	DONE();
+	if (err) {
+	    fprintf(stderr, "error 0x%lx initializing context\n",
+		    (unsigned long) err);
+	    exit(1);
+	}
+	CALLING(krb5_free_context);
+	free_context(ctx);
+	DONE();
+    }
+    celib2 = do_open("com_err", "3.0", 0);
+    do_close(celib);
+    do_close(k5lib);
+    do_close(celib2);
+    do_close(gsslib);
+
+    /* Test gssapi_krb5 without having loaded anything else.  */
+    gsslib = do_open("gssapi_krb5", "2.2", 1);
+    {
+	OM_uint32 KRB5_CALLCONV (*init_sec_context)(OM_uint32 *, gss_cred_id_t,
+						    gss_ctx_id_t *, gss_name_t,
+						    gss_OID,
+						    OM_uint32, OM_uint32,
+						    gss_channel_bindings_t,
+						    gss_buffer_t, gss_OID *,
+						    gss_buffer_t,
+						    OM_uint32 *, OM_uint32 *)
+	    = get_gfun(gsslib, "gss_init_sec_context");
+	OM_uint32 KRB5_CALLCONV (*import_name)(OM_uint32 *, gss_buffer_t,
+					       gss_OID, gss_name_t *)
+	    = get_gfun(gsslib, "gss_import_name");
+	OM_uint32 KRB5_CALLCONV (*release_buffer)(OM_uint32 *, gss_buffer_t)
+	    = get_gfun(gsslib, "gss_release_buffer");
+	OM_uint32 KRB5_CALLCONV (*release_name)(OM_uint32 *, gss_name_t *)
+	    = get_gfun(gsslib, "gss_release_name");
+	OM_uint32 KRB5_CALLCONV (*delete_sec_context)(OM_uint32 *,
+						      gss_ctx_id_t *,
+						      gss_buffer_t)
+	    = get_gfun(gsslib, "gss_delete_sec_context");
+
+	OM_uint32 gmaj, gmin;
+	OM_uint32 retflags;
+	gss_ctx_id_t gctx = GSS_C_NO_CONTEXT;
+	gss_buffer_desc token;
+	gss_name_t target;
+	static gss_buffer_desc target_name_buf = {
+	    9, "x@mit.edu"
+	};
+	static gss_OID_desc service_name = {
+	    10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"
+	};
+
+	CALLING(gss_import_name);
+	gmaj = import_name(&gmin, &target_name_buf, &service_name, &target);
+	DONE();
+	if (gmaj != GSS_S_COMPLETE) {
+	    fprintf(stderr,
+		    "import_name reports error major 0x%lx minor 0x%lx(%ld)\n",
+		    (unsigned long) gmaj, (unsigned long) gmin,
+		    (signed long) gmin);
+	    exit(1);
+	}
+	/* This will probably get different errors, depending on
+	   whether we have tickets at the time.  Doesn't matter much,
+	   we're ignoring the error and testing whether we're doing
+	   cleanup properly.  (Though the internal cleanup needed in
+	   the two cases might be different.)  */
+	CALLING(gss_init_sec_context);
+	gmaj = init_sec_context(&gmin, GSS_C_NO_CREDENTIAL, &gctx, target,
+				GSS_C_NULL_OID, 0, 0, NULL, GSS_C_NO_BUFFER,
+				NULL, &token, &retflags, NULL);
+	DONE();
+	/* Ignore success/failure indication.  */
+	if (token.length) {
+	    CALLING(gss_release_buffer);
+	    release_buffer(&gmin, &token);
+	    DONE();
+	}
+	CALLING(gss_release_name);
+	release_name(&gmin, &target);
+	DONE();
+	if (gctx != GSS_C_NO_CONTEXT) {
+	    CALLING(gss_delete_sec_context);
+	    delete_sec_context(&gmin, gctx, GSS_C_NO_BUFFER);
+	    DONE();
+	}
+    }
+    do_close(gsslib);
+
+    /* Test gssapi_krb5 with com_err already loaded, then unload
+       com_err first.  */
+    celib = do_open("com_err", "3.0", 1);
+    gsslib = do_open("gssapi_krb5", "2.2", 1);
+    {
+	OM_uint32 KRB5_CALLCONV (*init_sec_context)(OM_uint32 *, gss_cred_id_t,
+						    gss_ctx_id_t *, gss_name_t,
+						    gss_OID,
+						    OM_uint32, OM_uint32,
+						    gss_channel_bindings_t,
+						    gss_buffer_t, gss_OID *,
+						    gss_buffer_t,
+						    OM_uint32 *, OM_uint32 *)
+	    = get_gfun(gsslib, "gss_init_sec_context");
+	OM_uint32 KRB5_CALLCONV (*import_name)(OM_uint32 *, gss_buffer_t,
+					       gss_OID, gss_name_t *)
+	    = get_gfun(gsslib, "gss_import_name");
+	OM_uint32 KRB5_CALLCONV (*release_buffer)(OM_uint32 *, gss_buffer_t)
+	    = get_gfun(gsslib, "gss_release_buffer");
+	OM_uint32 KRB5_CALLCONV (*release_name)(OM_uint32 *, gss_name_t *)
+	    = get_gfun(gsslib, "gss_release_name");
+	OM_uint32 KRB5_CALLCONV (*delete_sec_context)(OM_uint32 *,
+						      gss_ctx_id_t *,
+						      gss_buffer_t)
+	    = get_gfun(gsslib, "gss_delete_sec_context");
+
+	OM_uint32 gmaj, gmin;
+	OM_uint32 retflags;
+	gss_ctx_id_t gctx = GSS_C_NO_CONTEXT;
+	gss_buffer_desc token;
+	gss_name_t target;
+	static gss_buffer_desc target_name_buf = {
+	    9, "x@mit.edu"
+	};
+	static gss_OID_desc service_name = {
+	    10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"
+	};
+
+	CALLING(gss_import_name);
+	gmaj = import_name(&gmin, &target_name_buf, &service_name, &target);
+	DONE();
+	if (gmaj != GSS_S_COMPLETE) {
+	    fprintf(stderr,
+		    "import_name reports error major 0x%lx minor 0x%lx(%ld)\n",
+		    (unsigned long) gmaj, (unsigned long) gmin,
+		    (signed long) gmin);
+	    exit(1);
+	}
+	/* This will probably get different errors, depending on
+	   whether we have tickets at the time.  Doesn't matter much,
+	   we're ignoring the error and testing whether we're doing
+	   cleanup properly.  (Though the internal cleanup needed in
+	   the two cases might be different.)  */
+	CALLING(gss_init_sec_context);
+	gmaj = init_sec_context(&gmin, GSS_C_NO_CREDENTIAL, &gctx, target,
+				GSS_C_NULL_OID, 0, 0, NULL, GSS_C_NO_BUFFER,
+				NULL, &token, &retflags, NULL);
+	DONE();
+	/* Ignore success/failure indication.  */
+	if (token.length) {
+	    CALLING(gss_release_buffer);
+	    release_buffer(&gmin, &token);
+	    DONE();
+	}
+	CALLING(gss_release_name);
+	release_name(&gmin, &target);
+	DONE();
+	if (gctx != GSS_C_NO_CONTEXT) {
+	    CALLING(gss_delete_sec_context);
+	    delete_sec_context(&gmin, gctx, GSS_C_NO_BUFFER);
+	    DONE();
+	}
+    }
+    do_close(celib);
+    do_close(gsslib);
+
+    return 0;
+}
diff --git a/mechglue/src/tests/test1.c b/mechglue/src/tests/test1.c
new file mode 100644
index 000000000..bb142ead4
--- /dev/null
+++ b/mechglue/src/tests/test1.c
@@ -0,0 +1,195 @@
+/*
+ * tests/test1.c
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Regression tests for the kerberos library.
+ */
+
+#include "krb5.h"
+
+unsigned char key_one[8] = { 0x10, 0x23, 0x32, 0x45, 0x54, 0x67, 0x76, 0x89 };
+unsigned char key_two[8] = { 0xea, 0x89, 0x57, 0x76, 0x5b, 0xcd, 0x0d, 0x34 };
+
+extern void dump_data();
+
+tkt_test_1()
+{
+    krb5_data *data;
+    krb5_ticket tk_in, *tk_out;
+    krb5_keyblock sess_k, serv_k, *nsess;
+    krb5_enc_tkt_part tk_in_enc;
+    int code;
+    krb5_address *addr_list[2];
+    krb5_address addr_1;
+    static krb5_octet ip_addr_1[4] = { 18, 72, 0, 122 };
+    char *out;
+    
+    /*
+     * fill in some values on the "in" side of the ticket
+     */
+    code = krb5_parse_name ("server/test/1@BOGUS.ORG", &tk_in.server);
+    if (code != 0) {
+	com_err("tkt_test_1", code, " parsing server principal");
+	return;
+    }
+
+    serv_k.enctype = 1;		/* XXX symbolic constant */
+    serv_k.length = 8;		/* XXX symbolic constant */
+    serv_k.contents = key_one;
+    
+    sess_k.enctype = 1;		/* XXX symbolic constant */
+    sess_k.length = 8;		/* XXX symbolic constant */
+    sess_k.contents = key_two;
+
+    tk_in.etype = 1;		/* XXX symbolic constant here */
+    tk_in.skvno = 4;		
+
+    tk_in.enc_part2 = &tk_in_enc;
+
+    tk_in_enc.flags = 0x11;
+    tk_in_enc.session = &sess_k;
+
+    tk_in_enc.times.authtime = 42;
+    tk_in_enc.times.starttime = 43;
+    tk_in_enc.times.endtime = 44;
+    
+    code = krb5_parse_name ("client/test/1@BOGUS.ORG", &tk_in_enc.client);
+    if (code != 0) {
+	com_err("tkt_test_1", code, " parsing client principal");
+	return;
+    }
+    tk_in_enc.transited.length = 0;
+
+    addr_1.addrtype = ADDRTYPE_INET; /* XXX should be KRB5_ADDR... */
+    addr_1.length = 4;
+    addr_1.contents = ip_addr_1;
+
+    addr_list[0] = &addr_1;
+    addr_list[1] = 0;
+
+    
+    tk_in_enc.caddrs = addr_list;
+    tk_in_enc.authorization_data = 0;
+
+    code = krb5_encrypt_tkt_part(&serv_k, &tk_in);
+    if (code != 0) {
+	com_err ("tkt_test_1", code, " encrypting ticket");
+	return;
+    }
+
+    data = 0;    
+    
+    code = krb5_encode_ticket (&tk_in,  &data);
+    if (code != 0) {
+	com_err ("tkt_test_1", code, " encoding ticket");
+	return;
+    }
+
+    dump_data(data);
+
+    tk_out = 0;
+    code = krb5_decode_ticket (data, &tk_out);
+    if (code != 0) {
+	com_err ("tkt_test_1", code, "decoding ticket");
+	return;
+    }
+    /* check the plaintext values */
+    if (tk_out->etype != 1) {
+	com_err ("tkt_test_1", 0, "wrong etype");
+	return;
+    }
+    if (tk_out->skvno != 4) {
+	com_err ("tkt_test_1", 0, "wrong kvno");
+	return;
+    }
+
+    code = krb5_unparse_name(tk_out->server, &out);
+    if (code != 0) {
+	com_err ("tkt_test_1", code, "couldn't unparse server principal");
+	return;
+    }
+    if (strcmp (out, "server/test/1@BOGUS.ORG") != 0) {
+	com_err("tkt_test_1", 0, "wrong server principal");
+	return;
+    }
+    free(out);
+    out = 0;
+    
+    /* decode the ciphertext */
+    code = krb5_decrypt_tkt_part (&serv_k, tk_out);
+    if (code != 0) {
+	com_err ("tkt_test_1", code, "while decrypting ticket");
+	return;
+    }
+
+    /* check the contents */
+    if (tk_out->enc_part2->flags != 0x11) {
+	com_err("tkt_test_1", 0, "wrong flags");
+	return;
+    }
+
+    nsess = tk_out->enc_part2->session;
+
+    if (nsess->enctype != 1) {
+	com_err("tkt_test_1", 0, "wrong session key type");
+	return;
+    }
+    if (nsess->length != 8) {
+	com_err("tkt_test_1", 0, "wrong session key length");
+	return;
+    }
+    if (memcmp(nsess->contents, key_two, 8) != 0) {
+	com_err("tkt_test_1", 0, "wrong session key contents");
+	return;
+    }
+
+    code = krb5_unparse_name(tk_out->enc_part2->client, &out);
+    if (code != 0) {
+	com_err ("tkt_test_1", code, "couldn't unparse client principal");
+	return;
+    }
+    if (strcmp (out, "client/test/1@BOGUS.ORG") != 0) {
+	com_err("tkt_test_1", 0, "wrong client principal");
+	return;
+    }
+    free(out);
+    out = 0;
+    if (tk_out->enc_part2->transited.length != 0) {
+	com_err("tkt_test_1", 0, "wrong transited length");
+	return;
+    }
+    /* XXX should check address here, too */
+    /* XXX should check times here */
+    /* XXX should check auth. data here */
+    printf("test 1 passed\n");
+}
+
+
+
+main()
+{
+    krb5_init_ets();
+    tkt_test_1();
+}
diff --git a/mechglue/src/tests/threads/ChangeLog b/mechglue/src/tests/threads/ChangeLog
new file mode 100644
index 000000000..9d212cc91
--- /dev/null
+++ b/mechglue/src/tests/threads/ChangeLog
@@ -0,0 +1,18 @@
+2005-12-20  Sam Hartman  <hartmans@mit.edu>
+
+	* t_rcache.c: Include krb5.h after k5-int.h
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (t_rcache, prof1): Use THREAD_LINKOPTS instead of
+	-lpthread.
+
+2004-12-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof1.c: New file.
+	* Makefile.in (prof1, prof1.o): New targets.
+
+2004-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in, t_rcache.c: New files.
+
diff --git a/mechglue/src/tests/threads/Makefile.in b/mechglue/src/tests/threads/Makefile.in
new file mode 100644
index 000000000..5386d00e1
--- /dev/null
+++ b/mechglue/src/tests/threads/Makefile.in
@@ -0,0 +1,44 @@
+thisconfigdir=./..
+myfulldir=tests/threads
+mydir=threads
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+RUN_SETUP = @KRB5_RUN_ENV@
+
+SRCS=$(srcdir)/t_rcache.c
+
+all::
+
+N = 4
+run-t_rcache: t_rcache
+	$(RUN_SETUP) ./t_rcache -n $(N)
+
+t_rcache: t_rcache.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_rcache t_rcache.o $(KRB5_BASE_LIBS) $(THREAD_LINKOPTS)
+
+syms: syms.o
+	$(CC_LINK) -o syms syms.o
+
+run-syms: syms
+	$(RUN_SETUP) ./syms
+
+prof1: prof1.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o prof1 prof1.o $(KRB5_BASE_LIBS) $(THREAD_LINKOPTS)
+
+prof1.o: prof1.c
+
+check-unix:: run-t_rcache
+
+install::
+
+clean::
+	$(RM) t_rcache.o t_rcache
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+
diff --git a/mechglue/src/tests/threads/prof1.c b/mechglue/src/tests/threads/prof1.c
new file mode 100644
index 000000000..766bfa3d0
--- /dev/null
+++ b/mechglue/src/tests/threads/prof1.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <time.h>
+#include <sys/time.h>
+#include <utime.h>
+#include <com_err.h>
+#include <profile.h>
+
+int nthreads = 10;
+unsigned int delay = 3600;
+
+volatile int done = 0; /* XXX hack */
+
+const char *path = "/tmp/foo1.conf:/tmp/foo.conf";
+const char *filename = "/tmp/foo.conf";
+
+const char *prog;
+
+static void *worker(void *arg)
+{
+    profile_t p;
+    long err;
+    int i;
+    const char *const names[] = {
+	"one", "two", "three", 0
+    };
+    char **values;
+    const char *mypath = (random() & 1) ? path : filename;
+
+    while (!done) {
+	err = profile_init_path(mypath, &p);
+	if (err) {
+	    com_err(prog, err, "calling profile_init(\"%s\")", mypath);
+	    exit(1);
+	}
+	for (i = 0; i < 10; i++) {
+	    values = 0;
+	    err = profile_get_values(p, names, &values);
+	    if (err == 0 && values != 0)
+		profile_free_list(values);
+	}
+	profile_release(p);
+    }
+    return 0;
+}
+
+static void *modifier(void *arg)
+{
+    struct timespec req;
+    while (!done) {
+	req.tv_sec = 0;
+	req.tv_nsec = random() & 499999999;
+	nanosleep(&req, 0);
+	utime(filename, 0);
+/*	printf("."), fflush(stdout); */
+    }
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    int i;
+    pthread_t thr;
+
+    prog = argv[0];
+    for (i = 0; i < nthreads; i++) {
+	assert(0 == pthread_create(&thr, 0, worker, 0));
+    }
+    sleep(1);
+    pthread_create(&thr, 0, modifier, 0);
+    sleep(delay);
+    done = 1;
+    sleep(2);
+    return 0;
+}
diff --git a/mechglue/src/tests/threads/t_rcache.c b/mechglue/src/tests/threads/t_rcache.c
new file mode 100644
index 000000000..49b6927b4
--- /dev/null
+++ b/mechglue/src/tests/threads/t_rcache.c
@@ -0,0 +1,174 @@
+/*
+ * test/threads/t_rcache.c
+ *
+ * Copyright (C) 2006 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * 
+ *
+ */
+
+
+#include <stdio.h>
+#include <com_err.h>
+
+#include "k5-int.h"
+#include <krb5.h>
+#include <pthread.h>
+
+krb5_context ctx;
+krb5_rcache rcache;
+krb5_data piece = { .data = "hello", .length = 5 };
+time_t end_time;
+const char *prog;
+
+struct tinfo {
+    time_t now;
+    unsigned long my_ctime;
+    unsigned int my_cusec;
+    unsigned int total;
+    int idx;
+};
+
+#undef INIT_ONCE
+
+static void try_one (struct tinfo *t)
+{
+    krb5_donot_replay r;
+    krb5_error_code err;
+    char buf[100], buf2[100];
+    krb5_rcache my_rcache;
+
+    sprintf(buf, "host/all-in-one.mit.edu/%p@ATHENA.MIT.EDU", buf);
+    r.server = buf;
+    r.client = (t->my_cusec & 7) + "abcdefgh@ATHENA.MIT.EDU";
+    if (t->now != t->my_ctime) {
+	if (t->my_ctime != 0) {
+	    sprintf(buf2, "%3d: %ld %5d\n", t->idx, t->my_ctime, t->my_cusec);
+	    printf("%s", buf2);
+	}
+	t->my_ctime = t->now;
+	t->my_cusec = 1;
+    } else
+	t->my_cusec++;
+    r.ctime = t->my_ctime;
+    r.cusec = t->my_cusec;
+#ifndef INIT_ONCE
+    err = krb5_get_server_rcache(ctx, &piece, &my_rcache);
+    if (err) {
+	com_err(prog, err, "getting replay cache");
+	exit(1);
+    }
+#else
+    my_rcache = rcache;
+#endif
+    err = krb5_rc_store(ctx, my_rcache, &r);
+    if (err) {
+	com_err(prog, err, "storing in replay cache");
+	exit(1);
+    }
+#ifndef INIT_ONCE
+    krb5_rc_close(ctx, my_rcache);
+#endif
+}
+
+static void *run_a_loop (void *x)
+{
+    struct tinfo t = { 0 };
+/*    int chr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"[(*(int*)x) % 27]; */
+
+    t.now = time(0);
+    t.idx = *(int *)x;
+    while (t.now != time(0))
+	;
+    t.now = time(0);
+    while (t.now < end_time) {
+	t.now = time(0);
+	try_one(&t);
+	t.total++;
+/*	printf("%c", chr); */
+	fflush(stdout);
+    }
+    printf("thread %p total %u\n", &t, t.total);
+    *(int*)x = t.total;
+    return 0;
+}
+
+int main (int argc, char *argv[])
+{
+    int n;
+    krb5_error_code err;
+    int interval = 20 /* 5 * 60 */;
+
+    prog = argv[0];
+    unlink("/var/tmp/rc_hello_7882");
+    unlink("/var/tmp/hello_7882");
+    n = 2;
+    err = krb5_init_context(&ctx);
+    if (err) {
+	com_err(prog, err, "initializing context");
+	return 1;
+    }
+#ifdef INIT_ONCE
+    err = krb5_get_server_rcache(ctx, &piece, &rcache);
+    if (err) {
+	com_err(prog, err, "getting replay cache");
+	return 1;
+    }
+#endif
+    end_time = time(0) + interval;
+#undef DIRECT
+#ifdef DIRECT
+    {
+	int zero = 0;
+	run_a_loop(&zero);
+    }
+#else
+    {
+	int i, *ip;
+
+	ip = malloc(sizeof(int) * n);
+	if (ip == 0 && n > 0) {
+	    perror("malloc");
+	    exit(1);
+	}
+	for (i = 0; i < n; i++)
+	    ip[i] = i;
+
+	for (i = 0; i < n; i++) {
+	    pthread_t new_thread;
+	    int perr;
+	    perr = pthread_create(&new_thread, 0, run_a_loop, &ip[i]);
+	    if (perr) {
+		errno = perr;
+		perror("pthread_create");
+		exit(1);
+	    }
+	}
+	while (time(0) < end_time + 1)
+	    sleep(1);
+	for (i = 0; i < n; i++)
+	    printf("thread %d total %5d\n", i, ip[i]);
+    }
+#endif
+    return 0;
+}
diff --git a/mechglue/src/tests/verify/.Sanitize b/mechglue/src/tests/verify/.Sanitize
new file mode 100644
index 000000000..c138cd1e4
--- /dev/null
+++ b/mechglue/src/tests/verify/.Sanitize
@@ -0,0 +1,38 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+kdb5_verify.c
+pkey.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/tests/verify/ChangeLog b/mechglue/src/tests/verify/ChangeLog
new file mode 100644
index 000000000..039cd2fe2
--- /dev/null
+++ b/mechglue/src/tests/verify/ChangeLog
@@ -0,0 +1,196 @@
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_verify.c (set_dbname_help): Set default realm and construct
+	argument vector describing database location, before calling
+	krb5_db_open.
+
+2005-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (KDB5_DEP_LIB): Use DL_LIB and THREAD_LINKOPTS
+	instead of explicitly using -ldl and -lpthread.
+
+	Novell merge.
+	* Makefile.in:
+	* kdb5_verify.c:
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-04-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_verify.c (main): Call krb5_c_valid_enctype instead of
+	valid_enctype.
+
+2001-11-19  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_verify.c (main): Use krb5_free_unparsed_name() to free up
+	memory.
+	(check_princ): Use krb5_free_data_contents() and
+	krb5_free_principal() to cleanup memory leak.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* kdb5_verify.c: Make prototypes unconditional.
+
+2000-07-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_verify.c (check_princ): Compiler warning cleanup. Get rid
+	of unused function.
+
+2000-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* kdb5_verify.c: Remove unused variable.
+
+2000-05-11  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kdb5_verify.c (main): Make sure buffer "principal_string" is
+	properly terminated.
+
+2000-05-08  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* kdb5_verify.c (main): Don't overflow buffer "tmp".
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+1998-10-27  Marc Horowitz  <marc@mit.edu>
+
+	* kdb5_verify.c: update to new crypto api
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* kdb5_verify.c (argv): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
+
+Mon Mar 30 16:46:20 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kdb5_verify.c: Declare main() as int instead of void.
+	Add parentheses around assignements in conditionals.
+
+Wed Feb 18 16:30:59 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 16:44:21 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Sun Aug 17 14:26:57 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(SRCS) line.
+
+Sun Feb  9 01:57:53 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new program build procedure.
+
+Thu May  2 21:16:40 1996  Richard Basch  <basch@lehman.com>
+
+	* kdb5_verify.c: fixed various abstraction violations where the
+		code "knew" the cryptosystem_entry structure
+
+Sat Dec 23 01:05:33 1995    <tytso@rsts-11.mit.edu>
+
+	* configure.in (withval): Add check for DBM/db libraries.
+
+Wed Dec 13 03:51:53 1995  Chris Provenzano (proven@mit.edu)
+
+        * kdb5_verify.c : Remove mkvno for krb5_db_entry
+
+Thu Nov 09 17:05:57 1995  Chris Provenzano (proven@mit.edu)
+
+        * kdb5_verify.c : Remove krb5_enctype from krb5_string_to_key() args.
+
+Wed Sep 06 14:20:57 1995   Chris Provenzano (proven@mit.edu)
+
+        * kdb5_verify.c : s/keytype/enctype/g, s/KEYTYPE/ENCTYPE/g
+
+Tue Sep 05 22:10:34 1995   Chris Provenzano (proven@mit.edu)
+
+        * kdb5_verify.c : Remove krb5_enctype references, and replace with
+                krb5_keytype where appropriate
+
+Thu Jul 27 15:31:18 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb5_verify.c - Restore old logic to find the etype now that crypto-
+		conf.c is correctly generated.
+
+Thu Jul 27 02:59:05 1995        Chris Provenzano (proven@mit.edu)
+        * kdb5_verify.c : Use new kdb format.
+
+Mon Jul 17 15:25:03 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kdb5_verify.c - Change setting of defaulted keytype to be DEFAULT_
+		KDC_ETYPE instead of using the keytype array to find the
+		etype.
+
+
+Wed Jul 12 12:33:00 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Remove V5_USE_SHARED_LIB.
+
+
+Fri Jul 7 16:40:26 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove explicit library handling and LDFLAGS.
+	* configure.in - Add USE_KDB5_LIBRARY and KRB5_LIBRARIES
+
+
+Thu Jun 15 18:12:00 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Remove DBMLIB.
+	* configure.in - Remove check for dbm libraries, use shared library
+		linking rules.
+
+Fri Jun  9 18:58:51 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Mar  2 12:34:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (ISODELIB): Remove reference to $(ISODELIB).
+
+Wed Mar  1 16:33:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Remove ISODE_INCLUDE, replace check for -lsocket
+		and -lnsl with WITH_NETLIB check.
+
+Tue Feb 28 01:25:37 1995  John Gilmore  (gnu at toad.com)
+
+	* kdb5_verify.c:  Avoid <krb5/...> includes.
+
+Fri Jan 13 15:23:47 1995  Chris Provenzano (proven@mit.edu)
+
+    * Added krb5_context to all krb5_routines
+
+Sun Oct 23 00:50:42 1994    (tytso@rsx-11)
+
+	* kdb5_verify.c (check_princ): Check principals with the correct
+		realm name.
+
+	* configure.in: Look for ndbm or dbm libraries
+
+Thu Oct  6 12:42:47 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* kdb5_verify.c (main, set_dbname_help): Allow master key password
+		to be passed in on the command line; to make testing
+		scripts simpler.
+
+	* kdb5_verify.c (check_princ): Check to make sure key version
+		number is 1, not 0.
+
+Thu Sep 29 23:00:05 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+ 	* Makefile.in: Relink executable when libraries change
+
diff --git a/mechglue/src/tests/verify/Makefile.in b/mechglue/src/tests/verify/Makefile.in
new file mode 100644
index 000000000..e0123c410
--- /dev/null
+++ b/mechglue/src/tests/verify/Makefile.in
@@ -0,0 +1,31 @@
+thisconfigdir=./..
+myfulldir=tests/verify
+mydir=verify
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+KDB5_DEP_LIB=$(THREAD_LINKOPTS) $(DL_LIB)
+
+SRCS=$(srcdir)/kdb5_verify.c
+
+all:: kdb5_verify
+
+kdb5_verify: kdb5_verify.o $(KDB5_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o kdb5_verify kdb5_verify.o $(KDB5_LIBS) $(KDB5_DEP_LIB) $(KRB5_BASE_LIBS)
+
+install::
+
+clean::
+	$(RM) kdb5_verify.o kdb5_verify
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+$(OUTPRE)kdb5_verify.$(OBJEXT): kdb5_verify.c $(SRCTOP)/include/k5-int.h \
+  $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  $(SRCTOP)/include/krb5/kdb.h $(SS_DEPS)
diff --git a/mechglue/src/tests/verify/kdb5_verify.c b/mechglue/src/tests/verify/kdb5_verify.c
new file mode 100644
index 000000000..10661edd5
--- /dev/null
+++ b/mechglue/src/tests/verify/kdb5_verify.c
@@ -0,0 +1,469 @@
+/*
+ * tests/verify/kdb5_verify.c
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Edit a KDC database.
+ */
+
+#include "k5-int.h"
+#include "com_err.h"
+#include <ss/ss.h>
+#include <stdio.h>
+
+#define REALM_SEP	'@'
+#define REALM_SEP_STR	"@"
+
+struct mblock {
+    krb5_deltat max_life;
+    krb5_deltat max_rlife;
+    krb5_timestamp expiration;
+    krb5_flags flags;
+    krb5_kvno mkvno;
+} mblock = {				/* XXX */
+    KRB5_KDB_MAX_LIFE,
+    KRB5_KDB_MAX_RLIFE,
+    KRB5_KDB_EXPIRATION,
+    KRB5_KDB_DEF_FLAGS,
+    0
+};
+
+int set_dbname_help (krb5_context, char *, char *);
+
+static void
+usage(who, status)
+char *who;
+int status;
+{
+    fprintf(stderr,
+	    "usage: %s -p prefix -n num_to_check [-d dbpathname] [-r realmname]\n",
+	    who);
+    fprintf(stderr, "\t [-D depth] [-k enctype] [-M mkeyname]\n");
+
+    exit(status);
+}
+
+krb5_keyblock master_keyblock;
+krb5_principal master_princ;
+krb5_db_entry master_entry;
+krb5_encrypt_block master_encblock;
+krb5_pointer master_random;
+char *str_master_princ;
+
+static char *progname;
+static char *cur_realm = 0;
+static char *mkey_name = 0;
+static char *mkey_password = 0;
+static krb5_boolean manual_mkey = FALSE;
+
+
+int check_princ (krb5_context, char *);
+
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    extern char *optarg;	
+    int optchar, i, n;
+    char tmp[4096], tmp2[BUFSIZ], *str_princ;
+
+    krb5_context context;
+    krb5_error_code retval;
+    char *dbname = 0;
+    int enctypedone = 0;
+    int num_to_check;
+    char principal_string[BUFSIZ];
+    char *suffix = 0;
+    int depth, errors;
+
+    krb5_init_context(&context);
+
+    if (strrchr(argv[0], '/'))
+	argv[0] = strrchr(argv[0], '/')+1;
+
+    progname = argv[0];
+
+    memset(principal_string, 0, sizeof(principal_string));
+    num_to_check = 0;
+    depth = 1;
+
+    while ((optchar = getopt(argc, argv, "D:P:p:n:d:r:R:k:M:e:m")) != -1) {
+	switch(optchar) {
+	case 'D':
+	    depth = atoi(optarg);       /* how deep to go */
+	    break;
+        case 'P':		/* Only used for testing!!! */
+	    mkey_password = optarg;
+	    break;
+	case 'p':                       /* prefix name to check */
+	    strncpy(principal_string, optarg, sizeof(principal_string) - 1);
+	    principal_string[sizeof(principal_string) - 1] = '\0';
+	    suffix = principal_string + strlen(principal_string);
+	    break;
+       case 'n':                        /* how many to check */
+	    num_to_check = atoi(optarg);
+	    break;
+	case 'd':			/* set db name */
+	    dbname = optarg;
+	    break;
+	case 'r':
+	    cur_realm = optarg;
+	    break;
+	case 'k':
+	    master_keyblock.enctype = atoi(optarg);
+	    enctypedone++;
+	    break;
+	case 'M':			/* master key name in DB */
+	    mkey_name = optarg;
+	    break;
+	case 'm':
+	    manual_mkey = TRUE;
+	    break;
+	case '?':
+	default:
+	    usage(progname, 1);
+	    /*NOTREACHED*/
+	}
+    }
+
+    if (!(num_to_check && suffix)) usage(progname, 1);
+
+    if (!enctypedone)
+	master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
+
+    if (!krb5_c_valid_enctype(master_keyblock.enctype)) {
+	com_err(progname, KRB5_PROG_ETYPE_NOSUPP,
+		"while setting up enctype %d", master_keyblock.enctype);
+	exit(1);
+    }
+
+    krb5_use_enctype(context, &master_encblock, master_keyblock.enctype);
+
+    if (!dbname)
+	dbname = DEFAULT_KDB_FILE;	/* XXX? */
+
+    if (!cur_realm) {
+	if ((retval = krb5_get_default_realm(context, &cur_realm))) {
+	    com_err(progname, retval, "while retrieving default realm name");
+	    exit(1);
+	}	    
+    }
+    if ((retval = set_dbname_help(context, progname, dbname)))
+	exit(retval);
+
+    errors = 0;
+
+    fprintf(stdout, "\nChecking ");
+
+    for (n = 1; n <= num_to_check; n++) {
+      /* build the new principal name */
+      /* we can't pick random names because we need to generate all the names 
+	 again given a prefix and count to test the db lib and kdb */
+      (void) sprintf(suffix, "%d", n);
+      (void) sprintf(tmp, "%s-DEPTH-1", principal_string);
+      str_princ = tmp;
+      if (check_princ(context, str_princ)) errors++;
+
+      for (i = 2; i <= depth; i++) {
+	(void) sprintf(tmp2, "/%s-DEPTH-%d", principal_string, i);
+	tmp2[sizeof(tmp2) - 1] = '\0';
+	strncat(tmp, tmp2, sizeof(tmp) - 1 - strlen(tmp));
+	str_princ = tmp;
+	if (check_princ(context, str_princ)) errors++;
+      }
+    }
+
+    if (errors)
+      fprintf(stdout, "\n%d errors/principals failed.\n", errors);
+    else
+      fprintf(stdout, "\nNo errors.\n");
+
+    krb5_finish_random_key(context, &master_encblock, &master_random);
+    krb5_finish_key(context, &master_encblock);
+
+    retval = krb5_db_fini(context);
+    memset((char *)master_keyblock.contents, 0, (size_t) master_keyblock.length);
+    if (retval && retval != KRB5_KDB_DBNOTINITED) {
+	com_err(progname, retval, "while closing database");
+	exit(1);
+    }
+
+    if (str_master_princ) {
+	krb5_free_unparsed_name(context, str_master_princ);
+    }
+    krb5_free_context(context);
+    exit(0);
+}
+
+int
+check_princ(context, str_princ)
+    krb5_context context;
+    char * str_princ;
+{
+    krb5_error_code retval;
+    krb5_db_entry kdbe;
+    krb5_keyblock pwd_key, db_key;
+    krb5_data pwd, salt;
+    krb5_principal princ;
+    krb5_boolean more;
+    int nprincs = 1;
+    /* char *str_mod_name; */
+    char princ_name[4096];
+
+    sprintf(princ_name, "%s@%s", str_princ, cur_realm);
+
+    fprintf(stderr, "\t%s ...\n", princ_name);
+
+    if ((retval = krb5_parse_name(context, princ_name, &princ))) {
+      com_err(progname, retval, "while parsing '%s'", princ_name);
+      goto out;
+    }
+
+    pwd.data = princ_name;  /* must be able to regenerate */
+    pwd.length = strlen(princ_name);
+
+    if ((retval = krb5_principal2salt(context, princ, &salt))) {
+	com_err(progname, retval, "while converting principal to salt for '%s'", princ_name);
+	krb5_free_principal(context, princ);
+	goto out;
+    }
+
+    if ((retval = krb5_string_to_key(context, &master_encblock, 
+				    &pwd_key, &pwd, &salt))) {
+	com_err(progname, retval, "while converting password to key for '%s'", 
+		princ_name);
+	krb5_free_data_contents(context, &salt);
+	krb5_free_principal(context, princ);
+	goto out;
+    }
+    krb5_free_data_contents(context, &salt);
+
+    if ((retval = krb5_db_get_principal(context, princ, &kdbe, 
+					&nprincs, &more))) {
+      com_err(progname, retval, "while attempting to verify principal's existence");
+      krb5_free_principal(context, princ);
+      goto out;
+    }
+    krb5_free_principal(context, princ);
+
+    if (nprincs != 1) {
+      com_err(progname, 0, "Found %d entries db entry for %s.\n", nprincs,
+	      princ_name);
+      goto errout;
+    }
+
+    if ((retval = krb5_dbekd_decrypt_key_data(context, &master_keyblock, 
+				       	     kdbe.key_data, &db_key, NULL))) {
+	com_err(progname, retval, "while decrypting key for '%s'", princ_name);
+	goto errout;
+    }
+
+    if ((pwd_key.enctype != db_key.enctype) ||
+	(pwd_key.length != db_key.length)) {
+      fprintf (stderr, "\tKey types do not agree (%d expected, %d from db)\n",
+	       pwd_key.enctype, db_key.enctype);
+errout:
+      krb5_db_free_principal(context, &kdbe, nprincs);
+      return(-1);
+    }
+    else {
+      if (memcmp((char *)pwd_key.contents, (char *) db_key.contents, 
+		 (size_t) pwd_key.length)) {
+	fprintf(stderr, "\t key did not match stored value for %s\n", 
+		princ_name);
+	goto errout;
+      }
+    }
+
+    free((char *)pwd_key.contents);
+    free((char *)db_key.contents);
+
+    if (kdbe.key_data[0].key_data_kvno != 1) {
+      fprintf(stderr,"\tkvno did not match stored value for %s.\n", princ_name);
+      goto errout;
+    }
+
+    if (kdbe.max_life != mblock.max_life) {
+      fprintf(stderr, "\tmax life did not match stored value for %s.\n", 
+	      princ_name);
+      goto errout;
+    }
+
+    if (kdbe.max_renewable_life != mblock.max_rlife) {
+      fprintf(stderr, 
+	      "\tmax renewable life did not match stored value for %s.\n",
+	      princ_name);
+      goto errout;
+    }
+
+    if (kdbe.expiration != mblock.expiration) {
+      fprintf(stderr, "\texpiration time did not match stored value for %s.\n",
+	      princ_name);
+      goto errout;
+    }
+
+/*
+    if ((retval = krb5_unparse_name(context, kdbe.mod_name, &str_mod_name)))
+      com_err(progname, retval, "while unparsing mode name");
+    else {
+      if (strcmp(str_mod_name, str_master_princ) != 0) {
+	fprintf(stderr, "\tmod name isn't the master princ (%s not %s).\n",
+		str_mod_name, str_master_princ);
+	free(str_mod_name);
+	goto errout;
+      }
+      else free(str_mod_name);
+    }
+*/
+
+    if (kdbe.attributes != mblock.flags) {
+      fprintf(stderr, "\tAttributes did not match stored value for %s.\n",
+	      princ_name);
+      goto errout;
+    }
+
+    out:
+    krb5_db_free_principal(context, &kdbe, nprincs);
+
+    return(0);
+}
+
+int
+set_dbname_help(context, pname, dbname)
+    krb5_context context;
+    char *pname;
+    char *dbname;
+{
+    krb5_error_code retval;
+    int nentries;
+    krb5_boolean more;
+    krb5_data pwd, scratch;
+    char *args[2];
+
+    /* assemble & parse the master key name */
+
+    if ((retval = krb5_db_setup_mkey_name(context, mkey_name, cur_realm, 0,
+					 &master_princ))) {
+	com_err(pname, retval, "while setting up master key name");
+	return(1);
+    }
+    if (mkey_password) {
+	pwd.data = mkey_password;
+	pwd.length = strlen(mkey_password);
+	retval = krb5_principal2salt(context, master_princ, &scratch);
+	if (retval) {
+	    com_err(pname, retval, "while calculated master key salt");
+	    return(1);
+	}
+	if ((retval = krb5_string_to_key(context, &master_encblock, 
+				    &master_keyblock, &pwd, &scratch))) {
+	    com_err(pname, retval,
+		    "while transforming master key from password");
+	    return(1);
+	}
+	free(scratch.data);
+    } else {
+	if ((retval = krb5_db_fetch_mkey(context, master_princ,
+					 master_keyblock.enctype,
+					manual_mkey, FALSE, (char *) NULL, 0,
+					&master_keyblock))) {
+	    com_err(pname, retval, "while reading master key");
+	    return(1);
+	}
+    }
+
+    /* Ick!  Current DAL interface requires that the default_realm
+       field be set in the krb5_context.  */
+    if ((retval = krb5_set_default_realm(context, cur_realm))) {
+	com_err(pname, retval, "setting default realm");
+	return 1;
+    }
+    /* Pathname is passed to db2 via 'args' parameter.  */
+    args[1] = NULL;
+    args[0] = malloc(sizeof("dbname=") + strlen(dbname));
+    if (args[0] == NULL) {
+	com_err(pname, errno, "while setting up db parameters");
+	return 1;
+    }
+    sprintf(args[0], "dbname=%s", dbname);
+
+    if ((retval = krb5_db_open(context, args, KRB5_KDB_OPEN_RO))) {
+	com_err(pname, retval, "while initializing database");
+	return(1);
+    }
+    if ((retval = krb5_db_verify_master_key(context, master_princ, 
+					    &master_keyblock))) {
+	com_err(pname, retval, "while verifying master key");
+	(void) krb5_db_fini(context);
+	return(1);
+    }
+    nentries = 1;
+    if ((retval = krb5_db_get_principal(context, master_princ, &master_entry, 
+				       &nentries, &more))) {
+	com_err(pname, retval, "while retrieving master entry");
+	(void) krb5_db_fini(context);
+	return(1);
+    } else if (more) {
+	com_err(pname, KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE,
+		"while retrieving master entry");
+	(void) krb5_db_fini(context);
+	return(1);
+    } else if (!nentries) {
+	com_err(pname, KRB5_KDB_NOENTRY, "while retrieving master entry");
+	(void) krb5_db_fini(context);
+	return(1);
+    }
+
+    if ((retval = krb5_unparse_name(context, master_princ, 
+				    &str_master_princ))) {
+      com_err(pname, retval, "while unparsing master principal");
+      krb5_db_fini(context);
+      return(1);
+    }
+
+    if ((retval = krb5_process_key(context,
+				  &master_encblock, &master_keyblock))) {
+	com_err(pname, retval, "while processing master key");
+	(void) krb5_db_fini(context);
+	return(1);
+    }
+    if ((retval = krb5_init_random_key(context,
+				      &master_encblock, &master_keyblock,
+				      &master_random))) {
+	com_err(pname, retval, "while initializing random key generator");
+	krb5_finish_key(context, &master_encblock);
+	(void) krb5_db_fini(context);
+	return(1);
+    }
+    mblock.max_life = master_entry.max_life;
+    mblock.max_rlife = master_entry.max_renewable_life;
+    mblock.expiration = master_entry.expiration;
+    /* don't set flags, master has some extra restrictions */
+    mblock.mkvno = master_entry.key_data[0].key_data_kvno;
+
+    krb5_db_free_principal(context, &master_entry, nentries);
+    return 0;
+}
+
diff --git a/mechglue/src/tests/verify/pkey.c b/mechglue/src/tests/verify/pkey.c
new file mode 100644
index 000000000..a577f064f
--- /dev/null
+++ b/mechglue/src/tests/verify/pkey.c
@@ -0,0 +1,24 @@
+/*
+ * tests/verify/pkey.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * For copying and distribution information, please see the file
+ * <krb5/copyright.h>.
+ *
+ */
+
+#include <stdio.h>
+
+void pkey(k)
+     unsigned char *k;
+{
+  int i;
+  unsigned int foo;
+
+  for (i = 0 ; i < 8 ; i++) {
+    foo = *k++;
+    fprintf(stderr, "%x ", foo);
+  }
+}
diff --git a/mechglue/src/util/.Sanitize b/mechglue/src/util/.Sanitize
new file mode 100644
index 000000000..aa8bcf580
--- /dev/null
+++ b/mechglue/src/util/.Sanitize
@@ -0,0 +1,55 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+Sanitize
+autoconf
+berk_db
+configure
+configure.in
+depfix.sed
+et
+getsyms
+getsyms.sed
+kbuild
+kfrags
+libupdate.sh
+makeshlib.sh
+lndir
+makedepend
+profile
+pty
+reconf
+ss
+
+Things-to-lose:
+
+unifdef
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/util/ChangeLog b/mechglue/src/util/ChangeLog
new file mode 100644
index 000000000..a306f5d92
--- /dev/null
+++ b/mechglue/src/util/ChangeLog
@@ -0,0 +1,758 @@
+2005-12-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* depfix.pl (uniquify): New subroutine.
+	(do_subs_2): Use it.
+	(do_subs): Fix substitution pattern for " ./".
+
+2005-11-03  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Delete .svn directories to avoid pathname length bloat.
+
+2005-10-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* depfix.pl: Rename from depfix2.pl, and incorporate all
+	substitutions from depfix.sed.
+	* depfix.sed: Deleted.
+
+2005-10-25  Tom Yu  <tlyu@mit.edu>
+
+	* ac_check_krb5.m4: Set LIBS rather than LDFLAGS.
+
+2005-10-18  Tom Yu  <tlyu@mit.edu>
+
+	* ac_check_krb5.m4: Example autoconf macro to use krb5-config for
+	setting build flags for applications.
+
+2005-10-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* db2: Directory moved to modules/kdb/db2/libdb2.
+	* Makefile.in (LOCAL_SUBDIRS): Don't reference it.
+	(MAYBE_DB_k5, MAYBE_DB_sys): Variables deleted.
+
+2005-09-08  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Update for svn.
+
+2005-08-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(FAKEPREFIX)/lib): Target deleted.
+	(all-unix): Don't build it.
+
+2005-04-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* depgen.sed: Deleted.
+	* depfix2.pl: New file.
+
+2005-04-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* depgen.sed: Delete faulty check for $(srcdir), and redundant
+	check for $(SRCTOP).
+
+2004-12-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* depfix.sed: Don't change foo.o to $(OUTPRE)foo.$(OBJEXT) here.
+	* depgen.sed: Add new argument for STLIBOBJS.  
+	Do the OUTPRE/OBJEXT substitution here, and if STLIBOBJS is
+	non-empty, add foo.so and foo.po while we're at it.
+
+2004-12-21  Tom Yu  <tlyu@mit.edu>
+
+	* def-check.pl: Check for PRIVATE or INTERNAL annotations in defs
+	file.
+
+2004-10-31  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Rework quoting for RELTAIL check.  Don't check RELTAIL if
+	doing a "-current" snapshot.
+
+2004-09-24  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Rework somewhat to handle patchlevel.h being the new
+	master version stamp file.
+
+2004-09-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* reconf: Export ACLOCAL=true to environment.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-windows): Build support directory.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MAC_SUBDIRS): Don't set.
+	(all-mac): Target deleted.
+
+2004-06-16  Tom Yu  <tlyu@mit.edu>
+
+	* depfix.sed: Delete /os/usr/include as well, to cope with an
+	athena hack.  (#include "/os/usr/include/sys/rwstlock.h" in
+	sys/vnode.h)
+
+2004-05-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCAL_SUBDIRS): Build support library.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libupdate.sh, makeshlib.sh: Deleted.
+	* Makefile.in (libupdate, makeshlib): Targets deleted.
+	(all-recurse): Don't depend on them.
+	(clean): Don't try to delete them.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCAL_SUBDIRS): Renamed from MY_SUBDIRS.
+
+2004-03-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* reconf: Delete autom4te.cache directories after running
+	autoreconf.
+
+2004-02-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Drop apputils.
+
+2004-02-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Build in apputils dir.
+
+2004-02-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-recurse): Remove exitsleep.
+	
+	* Makefile.in (all-unix, clean-unix): Add new rule to build fake
+	root directory for _RLD_ROOT hacks.
+
+2003-12-05  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (DL_COMPILE, DL_COMPILE_TAIL): New variables to
+	support compilation of the exitsleep LD_PRELOAD object.
+
+	* exitsleep.c: New file.  LD_PRELOAD object for Solaris, to work
+	around a kernel bug where final output prior to a pty close gets
+	lost.
+
+2003-05-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* depfix.sed: Don't check for krb524 headers.
+
+2003-05-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* depgen.sed: Put print command on separate lines from
+	substitution commands, instead of using s///p form.
+
+2003-05-15  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Remote autom4te.cache files.
+
+2003-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* reconf: Restore support for 2.52; reject older versions.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* reconf: Drop support for 2.52 and earlier.
+
+2003-04-10  Tom Yu  <tlyu@mit.edu>
+
+	* reconf: Warn if autoconf-2.52 is used, as it generates buggy
+	configure scripts that don't work with BSD /bin/sh, and don't
+	comply with POSIX.2 (no conditions inside "case" statement).
+
+2003-02-05  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Exclude .rconf files.
+
+2002-12-23  Tom Yu  <tlyu@mit.edu>
+
+	* depfix.sed: Convert dependencies on generated krb524 and krb4
+	headers to variable references.
+
+2002-11-27  Tom Yu  <tlyu@mit.edu>
+
+	* depfix.sed: Remove tcl-specific headers from dependencies.
+	Delete now obsolete comment about gcc-specific directories.
+
+2002-11-13  Ezra Peisach  <epeisach@bu.edu>
+
+	* reconf: For pre autoconf 2.54 - invoke autoreconf with -l for
+	localdir. Posr 2.54 use the -I option.
+
+2002-09-27  Tom Yu  <tlyu@mit.edu>
+
+	* depgen.sed: Solaris sed doesn't like '\(^.*$\)'; replace it with
+	'^\(.*\)$'.
+
+2002-09-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* depgen.sed: Now expects a fifth argument, the pathname for
+	libgcc.  Replaces "libgcc" part with "include" and emits sed
+	patterns to discard any names starting with that prefix.
+	* depfix.sed: Drop handling of /mit/gnu and /mit/cygnus.
+
+	* Makefile.in (MY_SUBDIRS): Use MAYBE_DB_@DB_VERSION@.
+	(MAYBE_DB_k5, MAYBE_DB_sys): New variables.
+
+	* depfix.sed: Replace db2 headers with $(DB_DEPS).
+
+2002-09-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* depgen.sed: Now expects four values passed in; generates
+	complete sed script, with quoting for ".." in pathnames.
+
+2002-09-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* reconf: Give up if autoreconf fails.
+
+2002-09-03  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: set -e to catch errors.  Only build and clean autoconf if
+	it exists.
+
+2002-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS) [##WIN32##]: Hide variable definition
+	inside "!if 0" block.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MAYBE_ET_k5, MAYBE_ET_sys, MAYBE_SS_k5,
+	MAYBE_SS_sys): New variables.
+	(MY_SUBDIRS): Refer to them, choosing via new configure
+	substitutions.
+
+	* depfix.sed: Replace in-tree ss header files with $(SS_DEPS).
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Delete dyn.
+	* dyn: Directory and contents deleted.
+
+	* reconf: Create include/krb5/autoconf.stmp on success if it
+	didn't already exist.
+
+2002-07-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SLIBSH): Use vertical-bar instead of comma for
+	substituting CC in case the CC specified uses commas.
+
+2002-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* depfix.sed: Ignore header files under /mit/gnu/.  Replace
+	$(BUILDTOP)/include/com_err.h with $(COM_ERR_DEPS), now defined
+	via pre.in.
+
+2002-04-25  Ezra Peisach  <epeisach@bu.edu>
+
+	* reconf: Only for autoreconf 2.53, create a private copy of
+	autoreconf with a patch to a bug that prevented use of three
+	levels configure.in files. The bug is fixed in the development
+	version 2.53a.
+
+2002-04-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* def-check.pl: Handle KRB5_CALLCONV_WRONG in .def file.
+
+2002-04-05  Danilo Almeida  <dalmeida@mit.edu>
+
+	* def-check.pl: Better error checking.  Handles variable argument
+	functions more nicely.  Support for KRB5_CALLCONV_WRONG,
+	KRB5INT_BEGIN_DECLS, KRB5INT_END_DECLS.  Works with krb5.hin,
+	krb5.h, and k5-int.h (giving different information for the last
+	one, of course).
+
+2001-10-25  Ezra Peisach  <epeisach@mit.edu>
+
+	* reconf: Require autoconf 2.13. Remove support for local autoconf
+	tree.
+
+2001-10-17  Danilo Almeida  <dalmeida@mit.edu>
+
+	* def-check.pl: Provide a little bit of usage info.  More
+	error-checking.
+
+2001-10-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* def-check.pl: New file.  Not currently used by any automatic
+	processes.  Checks krb5.hin against krb5_32.def for consistency;
+	might work with other .h/.def files but hasn't been tested.
+
+2001-10-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* depfix.sed: Change "foo.o" to "$(OUTPRE)foo.$(OBJEXT)" so that
+	generated dependencies will take effect on Windows too.
+
+2001-09-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* depgen.sed: New file.
+	* depfix.sed: Remove /foo/../ sequences, looping 'til no more.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* depfix.sed: Temporarily add trailing whitespace to make
+	substitutions more regular.  Split lines before writing out.
+	Drop "$(srcdir)/" prefix for files in current directory, in favor
+	of using VPATH.
+
+2001-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* getsyms: Fix quoting around find command looking for
+	configure.in files; sort list.
+
+2001-04-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unixmac): Target deleted.
+
+2001-04-05  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: When generating multiple tarballs, also generate a
+	consolidated tarball.  Default to making a single
+	tarball. [pullups from krb5-1-2-2-branch]
+
+2001-01-28  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove rule for aix.bincmds; we don't need it
+	anymore.
+
+	* makeshlib.sh: Use the linker flag -berok so that unresolved
+	symbols don't turn into link-time errors for building shared libs
+	on AIX.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* reconf: Rework syntax to detect version numbers of newer
+	autoconf versions. For autoconf > 2.19, we need to pass an
+	absolute path for the localdir to autoreconf.
+
+2000-10-27  Ezra Peisach  <epeisach@mit.edu>
+
+	* reconf: Pass "-m util/autoconf" to autoreconf only if we are
+	using the source trees version of autoconf.
+
+2000-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* reconf: Look for autoconf 2.12 or later.  Don't use "grep -q",
+	it's not portable enough.
+
+2000-06-30  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-unix, clean_unix): Removed util/db2 include
+	symlinking rules.
+
+	* Makefile.in (all-unix, clean_unix): Update for current geography
+	of util/db2; needs to be moved to util/db2/Makefile.in at some
+	point.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-16  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel (reldate): Fix to deal with release branch snapshots.
+
+Wed May 19 11:43:36 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add all and cleanup rules for windows for windows,
+		et, and profile subdirectories.
+
+Sat May 15 19:48:31 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* makeshlib.sh (library): Add -bnoentry to the AIX shared library
+ 		link line so that the shared libraries can be dynamically
+ 		loaded.  Also make the library file executable, which is
+ 		apparently also necessary.  (Patch from Duke, needed for
+ 		SAP.  Note: I didn't take their addition of -lbsd, since I
+ 		don't think that's needed or a good idea).
+
+1999-01-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, configure.in: Move the responsibility for
+		generating the Makefile in this directory to the top-level
+		configure script.  The local configure.in script has been
+		deleted.
+
+Thu Sep 24 20:05:33 1998  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Add fixes to deal with "tails" on release directories,
+	e.g. for beta releases.
+
+Wed Feb 18 16:31:21 1998  Tom Yu  <tlyu@mit.edu>
+
+	* send-pr/Makefile.in: Remove trialing slash from thisconfigdir.
+	Fix up BUILDTOP for new conventions.
+
+	* Makefile.in (thisconfigdir): Remove trailing slash.
+
+Mon Feb  2 16:16:45 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Wed Jan 28 17:26:46 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in, Makefile.in: Remove conditional AppendRule only
+		for AIX, and make it happen all the time in Makefile.in
+
+Wed Nov 19 10:52:38 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (clean-unix): Remove db lib symlinks.
+
+Thu Nov 13 20:28:31 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* libupdate.sh: Add semicolons to prevent Bash 2.0 from
+	 	complaining.  [krb5-build/486]
+
+Wed Oct  8 16:19:49 1997  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Allow for edits of relevant files that should be changed
+	each time a release is cut.  Some snapshot support.  Add "-9" flag
+	to gzip.
+
+Fri Feb 21 15:58:19 1997  Sam Hartman  <hartmans@mit.edu>
+
+	* makeshlib.sh : Remove non AIX stuff; rewrite AIX stuff to work
+ 	with new build system.
+
+Fri Dec  6 10:59:32 1996  Tom Yu  <tlyu@mit.edu>
+
+	* getsyms: Don't echo filename if there are no bad symbols.
+
+	* getsyms.sed: Fixup to handle long comments somewhat more
+	gracefully.
+
+Mon Nov 25 21:00:24 1996  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Add support for --srconly, --doconly, --nocheckout,
+	--repository, etc.  They do the obvious things.
+
+Fri Nov 22 11:08:16 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* makeshlib.sh (VERSION): Fix SunOS shared libs [226]
+
+Tue Nov 12 17:32:08 1996  Barry Jaspan  <bjaspan@mit.edu>
+
+	* send-pr/send-pr.sh (MAIL_AGENT): change "[-x" to "[ -x"
+
+Sat Nov  2 02:24:20 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in (SHLIB_TAIL_COMP): Add send-pr
+
+Fri Nov  8 13:17:23 1996  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Fix to work with new modules definitions because cvs
+ 	export -d foo doesn't dtrt.
+
+Sun Nov  3 21:07:35 1996  Tom Yu  <tlyu@mit.edu>
+
+	* mkrel: Run make in doc so that .info and .ps files get created.
+	[krb5-misc/143]
+
+Thu Oct 31 12:51:13 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* kbuild: Add an option SHARED for configuring --enable-shared. 
+
+Tue Oct 29 15:39:12 1996  Tom Yu  <tlyu@mit.edu>
+
+	* makeshlib.sh: Allow stuffing of SONAME field in shared lib if
+	gcc is being used; this requires newer (2.7.0?) gcc and possibly
+	binutils (2.6?)
+
+Mon Oct 21 21:23:15 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fixes for new subdir recursion method.
+
+Thu Sep  5 18:48:46 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (all-unix): Fix symlinking so building in a link
+ 		farm or in source directory won't result in dangling
+ 		db-ndbm.h symlink.
+
+Sat Aug 31 01:34:41 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* makeshlib.sh (*-*-aix*): Echo more stuff before running it.
+	Always use /bin/ld -- the GNU linker isn't supported yet.  Don't
+	pass -x or -bfilelist.  Whitespace changes.
+
+Thu Aug 15 20:48:16 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* makeshlib.sh (alpha-*-osf*): add -expect_unresolved (due to
+		dbm_error and dbm_clearerr not being in libc when making
+		libkdb5)
+
+Thu Aug 15 16:30:00 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (all unix): "install" the db-ndbm header file with
+	 	symlinks.
+
+Sun Jul 28 00:43:16 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* makeshlib.sh (aix Allow symbols for the shared library to
+        overide symbols from libc.
+
+Wed Jul 10 00:52:28 1996  Marc Horowitz  <marc@mit.edu>
+
+	* Makefile.in (all-unix): "install" the db2 headers and libs with
+ 	symlinks.  db2 has its own self-contained autoconf setup, so this
+ 	is necessary here.
+	(all-unix): before installing db2, remove the links, so ln won't
+	fail the second time.
+
+Tue Jul  9 19:29:12 1996  Marc Horowitz  <marc@mit.edu>
+
+	* configure.in (CONFIG_DIRS): always build db2
+
+Mon May 20 11:05:49 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* libupdate.sh: allow to deal with multiple directories at once
+
+Sun May 19 23:53:21 1996  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* libupdate.sh: do the shift before the assignments
+
+Sat May 18 02:05:39 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* libupdate.sh: Define $library from the positional arguments
+		before --force uses $library.
+
+Tue Apr 16 22:26:36 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	Wed Mar  6 05:02:36 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* libupdate.sh: $ARCHIVE does not delete when creating. Explicitly
+	remove $library when using --force.
+
+Fri Mar 29 16:42:24 1996  Richard Basch  <basch@lehman.com>
+
+	* makeshlib.sh: Added support for SunOS shared libraries.
+
+Sat Feb 24 19:03:53 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* makeshlib.sh: Add support for HPUX and Sinix (sys5r4 on mips).
+
+Wed Feb  7 00:26:47 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Folded in danw's changes to allow
+		building Makefiles for the Macintosh.  We now can build
+		MPW makefiles which are interpreted by CodeWarrior.
+
+Thu Nov  2 17:05:05 1995    <tytso@rsx-11.mit.edu>
+
+	* makeshlib.sh: Added support for Linux shared libraries.
+
+Wed Oct 11 17:21:16 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* makeshlib.sh:  bring in library version and do something with it for AIX.
+
+Mon Oct  9 19:00:13 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* makeshlib.sh: For NetBSD convert flags designed for cc to ones
+		for ld.
+
+Mon Oct  2 12:12:20 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* makeshlib.sh: For solaris, if you are not using gcc, add the -h
+		argument to specify the name of the shared library to
+		load. (i.e. libfoo.so.0.1).
+
+Mon Sep 25 16:41:11 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Thu Aug 24 18:40:48 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Mon Aug  7 19:36:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* reconf: If using the autoconf in the local tree, invoke it using
+		/bin/sh, so that it works even if autoconf has been
+		checked out from SCCS without the execute bit set.
+
+Wed Jul 26 15:39:53 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in (SHLIB_TAIL_COMP): Add pty to CONFIG_DIRS
+
+Thu Jul 13 16:09:10 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* makeshlib.sh (ldflags): Protect test for HAVE_GCC so it works if not using gcc.
+
+
+Thu Jul  6 09:52:08 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (clean): Remove makeshlib
+
+Tue Jul  4 02:11:56 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* makeshlib.sh: Add support for NetBSD shared libraries.
+
+Sun Jul  2 20:42:45 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* makeshlib.sh (ldflags): Adapt AIX case to work with Gcc.
+
+	* configure.in: Move Gcc test to top level configure.in.
+
+Fri Jun 23 19:11:20 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* configure.in: Add aix.bincmds as target on AIX.
+	(SHLIB_TAIL_COMP): set and substitute so SHLIBDIR works
+
+	* Makefile.in (makeshlib): Create aix.bincmds with the binder
+        script exerpt to get the libpath right.
+
+	* configure.in: Modified to test and see if we're using Gcc
+
+	* Makefile.in (makeshlib): Make makeshlib from makeshlib.sh
+
+
+	* makeshlib.sh (LIBPATH): Modified to allow for substitution of CC
+        and HAVE_GCC from Makefile.  Modified to imbed the proper search
+        path into the shared libraries for AIX.
+
+
+Thu Jun 22 21:02:13 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* makeshlib: Added AIX support.
+
+Mon Jun 19 00:58:33 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* getsyms, getsyms.sed: fix a few random bugs
+
+	* getsyms, getsyms.sed: simple scripts to find #ifdef's that
+		aren't declared with configure.in
+
+Fri Jun 16 14:05:03 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* libupdate.sh: oops they were right to begin with; hack
+		aclocal.m4 instead.
+
+	* libupdate.sh: ARADD and ARCHIVE were backwards
+
+Thu Jun 15 18:14:46 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* makeshlib - Add arguments for library search directories, library
+		lists and flags to link with.
+
+Fri Jun  9 18:59:02 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.  Use DO_SUBDIRS to
+		recurse down subdirectories.
+
+Tue Jun  6 19:46:00 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: fix make install
+
+
+Fri May 26 18:43:35 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in	- Add berk_db
+
+Fri May 26 13:29:07 1995  Ezra Peisach  (epeisach@kangaroo.mit.edu)
+
+	* makeshlib: For alpha-osf1 update the local shared library registry 
+
+Fri May 26 12:41:28 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* makeshlib: Added alpha-osf1 support. Will only work
+		for libcrypto at the moment.
+
+Thu May 25 21:39:02 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* makeshlib: Added shell script for creating shared libraries
+
+Tue May  2 21:32:23 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: remove spurious whitespace from blank line
+
+Fri Apr 28 15:30:03 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* lndir (ls): use ls -a to get dotfiles too.
+
+Fri Apr 28 10:59:25 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* reconf (usage): fix the whole message.
+
+Wed Apr 26 11:31:04 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* reconf (usage): fix pathname in message.
+	(verbose): add -v --verbose to echo actual autoreconf line.
+
+Thu Apr 20 21:19:36 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* depfix.sed: Also remove pathnames of the form /mit/cygnus....
+		from the generated list of dependencies.
+
+Sat Apr 15 06:40:28 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* configure.in: Add profile directory
+
+Tue Mar 28 18:50:04 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (all):  Split into all-$(WHAT).
+	(unixmac):  Add.
+	(libupdate):  Use $(RM).
+
+Mon Feb 27 00:01:41 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* lndir: if $0 contains slashes, but does not have a leading
+	slash, prepend `pwd` so that relative invocation works.
+
+Fri Feb  3 16:50:07 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* reconf: If util/autoconf isn't built, try to use autoconf
+		utilities found in the user's path.
+
+Tue Nov  8 01:44:26 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Don't use $< in a non suffix rule context.
+
+Tue Nov  1 14:49:00 1994    (tytso@rsx-11)
+
+	* libupdate.sh: Use library.stamp to determine whether or not
+		$arcmd needs to be rerun. 
+
+	* libupdate.sh: touch the library first, before running $aradd, in
+		case changing the mod time of the library after running
+		$aradd causes problems on some systems.
+
+	* libupdate.sh: Change use of "head -1" to "sed 1q"
+
+	* configure.in: 
+	* Makefile.in:
+	* libupdate.sh: Add support for the new libupdate shell script.
+		It automatically updates a library from a file listing of
+		constituent .o files.  It only calls "ar" if it absolutely
+		has to, in order to speed things up for partial
+		recompilations.  (ar is dreadfully slow if you're using
+		one based on the BFD library.) 
+
+Tue Oct 11 19:07:09 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* kbuild (MAKETARGETS): default to "all check" for make, but allow
+	override from config fragments.
+
+Mon Oct  3 23:36:12 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in: Don't build unifdef directory --- we don't need it
+			anymore.
+
+Fri Sep 30 20:22:53 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* kbuild: log arguments to THISCONF, RECONF files.
+
+Fri Sep 30 19:28:24 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* kbuild: set SRCDIR by default from program name.
+
+Thu Sep 29 19:54:38 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* kbuild: complete rewrite.
+	* kfrags: fragments of input to kbuild.
+
diff --git a/mechglue/src/util/Makefile.in b/mechglue/src/util/Makefile.in
new file mode 100644
index 000000000..c9fd1d8ce
--- /dev/null
+++ b/mechglue/src/util/Makefile.in
@@ -0,0 +1,61 @@
+thisconfigdir=./..
+myfulldir=util
+mydir=util
+##WIN32###Windows NMAKE doesn't like @ in make variable names, and on
+##WIN32### Windows we don't do the @FOO@ substitutions we do with UNIX
+##WIN32### configure scripts.  The set of subdirs to use is hard-coded
+##WIN32### below in the 'all-windows' target anyways, so just hide this.
+##WIN32##!if 0
+LOCAL_SUBDIRS=support $(MAYBE_ET_@COM_ERR_VERSION@) $(MAYBE_SS_@SS_VERSION@) \
+	profile pty send-pr
+##WIN32##!endif
+BUILDTOP=$(REL)..
+
+MAYBE_ET_k5 = et
+MAYBE_SS_k5 = ss
+MAYBE_ET_sys =
+MAYBE_SS_sys =
+
+editsh = sed -e 's,@''ARADD''@,$(ARADD),g' -e 's,@''ARCHIVE''@,$(ARCHIVE),g'
+HOST_TYPE=@HOST_TYPE@
+HAVE_GCC=@HAVE_GCC@
+SLIBSH=sed -e 's|@''CC''@|$(CC)|g' -e 's,@''HOST_TYPE''@,$(HOST_TYPE),g' -e 's,@''HAVE_GCC''@,$(HAVE_GCC),g'
+
+DL_COMPILE=@DL_COMPILE@
+DL_COMPILE_TAIL=@DL_COMPILE_TAIL@
+
+all-recurse:
+
+clean-unix::
+	$(RM) -r $(FAKEPREFIX)
+
+NO_OUTDIR=1
+all-windows::
+	@echo Making in util\windows
+	cd windows
+	$(MAKE) -$(MFLAGS)
+	@echo Making in util\support
+	cd ..\support
+	$(MAKE) -$(MFLAGS)
+	@echo Making in util\et
+	cd ..\et
+	$(MAKE) -$(MFLAGS) 
+	@echo Making in util\profile
+	cd ..\profile
+	$(MAKE) -$(MFLAGS) 
+	cd ..
+
+clean-windows::
+	@echo Making clean in util\windows
+	cd windows
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in util\et
+	cd ..\et
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in util\profile
+	cd ..\profile
+	$(MAKE) -$(MFLAGS) clean
+	cd ..
+
+install::
+	@echo nothing to install in util
diff --git a/mechglue/src/util/Sanitize b/mechglue/src/util/Sanitize
new file mode 100755
index 000000000..ffe6e487f
--- /dev/null
+++ b/mechglue/src/util/Sanitize
@@ -0,0 +1,418 @@
+#! /bin/sh
+### Sanitize -- remove the unclean bits from a distribution or a file
+###		(perhaps this should be called an Exorcist?)
+###
+### See the file Sanitize.texi for whatever sort of documentation this
+### program has.
+###
+### Usage: Sanitize [keep-cvs] [keep-sanitize] [test] [recover] [verbose] [-n] ...
+###        Note that the highest level Sanitize command-line may have arbitrary
+###        other options, which have meaning only within some `Do-first' or
+###        `Do-last' script fragment.
+###
+### The -n option, like make's -n option, simply shows you what the
+### script *would have* done, given the other parameters you've passed
+### to it.  No actions are taken except traversal of the directory tree.
+###
+### written by K. Richard Pixley, hacked by david d `zoo' zuhn
+### -n option, lots of comments added by Bill Cox
+###
+
+SHELL=/bin/sh ; export SHELL
+
+## We have three cases:
+## 	The path given was absolute
+##      action: just keep it
+##      The name had a relative path
+##      action: make it absolute.
+##      The name had no directory components and was path searched
+##      action: just keep it, since the path search will *still* work
+
+case $0 in
+/*) sanprog=$0 ;;
+*/*)
+	sanprog=$0
+	sandir=`dirname $sanprog`
+	sandir=`(cd $sandir; pwd)`
+	sanprog=$sandir/`basename $sanprog`
+	;;
+*) sanprog=$0 ;;
+esac
+
+### "debugger"
+#set -x
+
+### Some variables and temp files; remove on any exit.
+
+workdir=/tmp
+cleaned=${workdir}/$$San.clean
+keepers=${workdir}/$$San.keep
+losers=${workdir}/$$San.lose
+sandd=${workdir}/$$San.temp
+
+sanStatus=1
+trap 'rm -f ${cleaned} ${keepers} ${sandd} ${losers} ; exit $sanStatus' 0
+
+### Make sure there is a .Sanitize
+
+if [ ! -f .Sanitize ] ; then
+    echo '***' No .Sanitize file in `pwd`! 1>&2
+    exit 1
+else
+    true
+fi
+
+### check for optional things-to-lose section first
+if ( egrep '^Things-to-lose:$' < .Sanitize > /dev/null ) ; then
+    losingthings=true
+else
+    losingthings=
+fi
+
+### Check that all trigger lines exist and are in order.
+if [ -n "${losingthings}" ] ; then
+    egrep '^Do-first:$|^Things-to-keep:$|^Things-to-lose:|^Do-last:$' < .Sanitize > ${sandd}
+
+    diff ${sandd} - <<EOF
+Do-first:
+Things-to-keep:
+Things-to-lose:
+Do-last:
+EOF
+
+else
+    egrep '^Do-first:$|^Things-to-keep:$|^Do-last:$' < .Sanitize > ${sandd}
+
+    diff ${sandd} - <<EOF
+Do-first:
+Things-to-keep:
+Do-last:
+EOF
+
+fi
+
+if [ "$?" != "0" ] ; then
+    echo '***' ${sanprog}: Some required trigger lines are missing 1>&2
+    echo '***' or out-of-order in `pwd`/.Sanitize 1>&2
+    exit 1
+else
+    true
+fi
+
+### die on errors
+set -e
+
+### set verbose
+if ( echo $* | egrep verbose > /dev/null ) ; then
+    verbose=true
+else
+    verbose=
+fi
+
+### set no_action flag if '-n' set
+### The echo ... egrep sequence didn't work
+### with the leading hyphen.
+no_action=
+for opt in $*
+do
+    case $opt in
+    -n)
+        no_action=true
+        ;;
+     *)
+        ;;
+    esac
+done
+
+### cache current directory name.
+THISDIR=`pwd`
+
+### Remove comments & blank lines.
+egrep -v "^#" < .Sanitize | sed -e '/^$/d' > ${cleaned}
+
+### Do-first stuff.
+### Note that the parameters to Sanitize are also passed 
+### to the fragment.  The fragment may optionally set the 
+### variables `keep_these_too' and `lose_these_too'.
+
+sed -e '/^Things\-to\-keep:$/,$d' -e '1d' ${cleaned} > ${sandd}
+
+if [ -s ${sandd} ] ; then
+    if [ -n "${no_action}" ] ; then
+        echo ". ${sandd} $*"
+    else
+        . ${sandd} $*
+    fi
+else
+    if [ -n "${verbose}" ] ; then
+        echo "No \`Do-first' fragment to execute."
+    else
+        true
+    fi
+fi
+
+### Things-to-keep:
+### Just build the list of keepers for now.
+sed -e '1,/^Things\-to\-keep:$/d' ${cleaned} > ${sandd}
+
+if [ -n "${losingthings}" ] ; then
+    sed -e '/^Things\-to\-lose:$/,$d' ${sandd} > ${keepers}
+else
+    sed -e '/^Do-last:$/,$d' ${sandd} > ${keepers}
+fi
+
+if [ -n "${keep_these_too}" ] ; then
+    for i in ${keep_these_too} ; do
+    	if [ -n "${verbose}" ] ; then
+            echo Keeping $i 
+        else
+            true
+        fi
+        echo $i >> ${keepers}
+    done
+else
+    true
+fi
+
+### Things-to-lose:
+### Just build the list of losers for now.
+if [ -n "${losingthings}" ] ; then
+    sed -e '1,/^Things\-to\-lose:$/d' \
+        -e '/^Do\-last:$/,$d' ${cleaned} \
+        > ${losers}
+else
+    cat /dev/null > ${losers}
+fi
+
+if [ -n "${lose_these_too}" ] ; then
+    for i in ${lose_these_too} ; do
+        if [ -n "${verbose}" ] ; then
+            echo Losing $i
+        else
+            true
+        fi
+        echo $i >> ${losers}
+    done
+else
+    true
+fi
+
+### catch and handle "recover"
+if ( echo $* | egrep recover > /dev/null ) ; then
+    if [ -d .Recover ] ; then
+        cd .Recover
+        replace=`ls -a | egrep -v '^\.$|^\.\.$'`
+        if [ -n "${no_action}" ] ; then
+            echo "cd .Recover"
+            echo "mv ${replace} .."
+            echo "cd .."
+            cd ..             # Must also do this for real..
+            echo "rmdir .Recover"
+        else
+            if [ -n "${verbose}" ] ; then
+                echo Replacing ${replace}
+            fi
+            mv ${replace} ..
+            cd ..
+            rmdir .Recover
+        fi
+    else
+        true
+    fi
+
+    for i in `egrep -v CVS ${keepers} | egrep -v \\.Recover` ; do
+        if [ -d "$i" ] ; then
+            if [ -n "${no_action}" ] ; then
+                echo "cd $i"
+            else
+                if [ -n "${verbose}" ] ; then
+                    echo Running ${sanprog} on ${THISDIR}/$i
+                else
+                    true
+                fi
+            fi
+            (cd $i ; ${sanprog} $*) | sed 's/^/    /'
+        else
+            true
+        fi    
+    done
+
+    sanStatus=0
+    exit 0
+else
+### catch and handle "test"
+    if ( echo $* | egrep test > /dev/null ) ; then
+        echo CVS >> ${keepers}
+        echo .Sanitize >> ${keepers}
+        echo .Recover >> ${keepers}
+#       echo .cvsignore >> ${keepers}
+        if [ -n "${no_action}" ] ; then
+            echo "mkdir .Recover"
+        else
+            if [ -n "${verbose}" ] ; then
+                echo Keeping CVS, .Sanitize, .cvsignore, and .Recover
+                echo Creating ${THISDIR}/.Recover to hold unclean files...
+            else
+                true
+            fi
+            mkdir .Recover
+        fi
+        safe=safe
+    else
+### if not testing, then lose .Sanitize.
+        if [ -n "${verbose}" ] ; then
+            echo Losing .Sanitize
+        else
+            true
+        fi
+        echo .Sanitize >> ${losers}
+
+### catch and handle "keep-cvs"
+        if ( echo $* | egrep keep-cvs > /dev/null ) ; then
+            if [ -n "${verbose}" ] ; then
+                echo Keeping CVS #, .cvsignore
+            else
+                true
+            fi
+            echo CVS >> ${keepers}
+#           echo .cvsignore >> ${keepers}
+        else
+            if [ -n "${verbose}" ] ; then
+                echo Losing CVS #, .cvsignore
+            else
+                true
+            fi
+            echo CVS >> ${losers}
+#           echo .cvsignore >> ${losers}
+        fi
+    fi
+fi
+
+### otherwise move files away
+
+### Issue errors for explicit losers which don't exist.
+tolose=`sed -e 's/[ ]*$//' ${losers}`
+if [ -n "${tolose}" ] ; then
+    for i in ${tolose} ; do
+        if [ -f $i -o -d $i ]; then
+            if [ -n "${safe}" ] ; then
+                if [ -n "${no_action}" ] ; then
+                    echo "mv $i .Recover"
+                else
+                    if [ -n "${verbose}" ] ; then
+                        echo Caching $i in .Recover...
+                    else
+                        true
+                    fi
+                    mv $i .Recover
+                fi
+            else
+                if [ -n "${no_action}" ] ; then
+                    echo "rm -rf $i"
+                else
+                    if [ -n "${verbose}" ] ; then
+                        echo Removing ${THISDIR}/$i
+                    else
+                        true
+                    fi
+                    rm -rf $i
+                fi
+            fi
+        else
+            echo '***' "Can't" remove expected file/directory ${THISDIR}/$i - not found. 1>&2
+        fi
+    done
+else
+    true
+fi
+
+### lose everything else in the directory, 
+### except the explicit keepers.
+
+tolose=`(ls -a | egrep -v '^\.$|^\.\.$' ; \
+         sed -e 's/[ ]*$//' ${keepers}) | sort | uniq -u`
+# $tolose is a list of files from ${keepers} or in directory but not both
+if [ -n "${tolose}" ] ; then
+    for i in ${tolose} ; do
+        if [ -f $i -o -d $i ]; then
+            # is in directory and not in ${keepers}
+            if [ -n "${safe}" ] ; then
+                if [ -n "${no_action}" ] ; then
+                    echo "mv $i .Recover"
+		else
+                    echo '***' Caching unexpected file ${THISDIR}/$i in .Recover... 1>&2
+                    mv $i .Recover
+                fi
+            else
+                if [ -n "${no_action}" ] ; then
+                    echo "rm -rf $i"
+                else
+                    echo '***' Removing unexpected file ${THISDIR}/$i 1>&2
+                    rm -rf $i
+                fi
+            fi
+        else
+            # is in ${keepers} but not in directory
+            echo '***' "Can't" keep expected file ${THISDIR}/$i - not found. 1>&2
+        fi
+    done
+else
+    true
+fi
+
+### Recurse into any subdirectories flagged as keepers.
+### Do the same good deeds down there.
+for i in `egrep -v CVS ${keepers} | egrep -v \\.Recover` ; do
+    if [ -d $i ] ; then
+        if [ -n "${no_action}" ] ; then
+            echo "cd $i"
+        else
+            if [ -n "${verbose}" ] ; then
+                echo Running ${sanprog} on ${THISDIR}/$i
+            else
+                true
+            fi
+        fi
+        (cd $i ; ${sanprog} $*) | sed 's/^/    /'
+    else
+        true
+    fi
+done
+
+### Do-last:
+
+sed -e '1,/^Do\-last:$/d' ${cleaned} > ${sandd}
+if [ -s ${sandd} ] ; then 
+    if [ -n "${no_action}" ] ; then
+        echo ". ${sandd} $*"
+    else
+        . ${sandd} $*
+    fi
+else
+    if [ -n "${verbose}" ] ; then
+        echo "No \`Do-last' fragment to execute."
+    else
+        true
+    fi
+fi
+
+### cleanup
+
+if ( echo $* | egrep test > /dev/null ) ; then
+    if [ -n "${safe}" -a "`cd .Recover ; (echo empty ; ls -a) | \
+            egrep -v '^\.$|^\.\.$'`" = "empty" ] ; then
+        if [ -n "${no_action}" ] ; then
+            echo "rmdir .Recover"
+        else
+            if [ -n "${verbose}" ] ; then
+                echo Removing .Recover.  It was not needed.
+            else
+                true
+            fi
+            rmdir .Recover
+        fi
+    fi
+fi
+
+sanStatus=0
+### eof.
diff --git a/mechglue/src/util/ac_check_krb5.m4 b/mechglue/src/util/ac_check_krb5.m4
new file mode 100644
index 000000000..e18183b65
--- /dev/null
+++ b/mechglue/src/util/ac_check_krb5.m4
@@ -0,0 +1,58 @@
+dnl Copyright (C) 2005 by the Massachusetts Institute of Technology.
+dnl All rights reserved.
+dnl
+dnl Export of this software from the United States of America may
+dnl   require a specific license from the United States Government.
+dnl   It is the responsibility of any person or organization contemplating
+dnl   export to obtain such a license before exporting.
+dnl 
+dnl WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+dnl distribute this software and its documentation for any purpose and
+dnl without fee is hereby granted, provided that the above copyright
+dnl notice appear in all copies and that both that copyright notice and
+dnl this permission notice appear in supporting documentation, and that
+dnl the name of M.I.T. not be used in advertising or publicity pertaining
+dnl to distribution of the software without specific, written prior
+dnl permission.  Furthermore if you modify this software you must label
+dnl your software as modified software and not distribute it in such a
+dnl fashion that it might be confused with the original M.I.T. software.
+dnl M.I.T. makes no representations about the suitability of
+dnl this software for any purpose.  It is provided "as is" without express
+dnl or implied warranty.
+
+dnl AC_CHECK_KRB5
+dnl
+dnl Check for krb5-config; update CPPFLAGS and LDFLAGS accordingly.
+dnl
+AC_DEFUN([AC_CHECK_KRB5],
+[AC_ARG_WITH([kerberos5],
+	[  --with-kerberos5=PATH   Enable Kerberos 5 support],
+	[if test "x$withval" != "xno"; then
+		if test "x$withval" = "xyes"; then
+			KRB5ROOT=/usr/local
+		else
+			KRB5ROOT=${withval}
+		fi
+		AC_MSG_CHECKING([for krb5-config])
+		if test -x "$KRB5ROOT/bin/krb5-config"; then
+			KRB5CONF=$KRB5ROOT/bin/krb5-config
+			AC_MSG_RESULT([$KRB5CONF])
+			AC_MSG_CHECKING([for gssapi support in krb5-config])
+			if "$KRB5CONF" | grep gssapi > /dev/null; then
+				AC_MSG_RESULT([yes])
+				k5confopts=gssapi
+			else
+				AC_MSG_RESULT([no])
+				k5confopts=
+			fi
+			K5CFLAGS=`"$KRB5CONF" --cflags $k5confopts`
+			CPPFLAGS="$CPPFLAGS $K5CFLAGS"
+
+			K5LIBS=`"$KRB5CONF" --libs $k5confopts`
+			LIBS="$LIBS $K5LIBS"
+		else
+			AC_MSG_RESULT([no])
+			AC_MSG_WARN([--with-kerberos5 specified but krb5-config not found])
+		fi
+	fi])
+])
diff --git a/mechglue/src/util/def-check.pl b/mechglue/src/util/def-check.pl
new file mode 100644
index 000000000..447421e8e
--- /dev/null
+++ b/mechglue/src/util/def-check.pl
@@ -0,0 +1,246 @@
+#!/usr/athena/bin/perl -w
+
+# Code initially generated by s2p
+# Code modified to use strict and IO::File
+
+eval 'exec /usr/athena/bin/perl -S $0 ${1+"$@"}'
+    if 0; # line above evaluated when running under some shell (i.e., not perl)
+
+use strict;
+use IO::File;
+
+my $h_filename = shift @ARGV || die "usage: $0 header-file [def-file]\n";
+my $d_filename = shift @ARGV;
+
+my $h = open_always($h_filename);
+my $d = open_always($d_filename) if $d_filename;
+
+sub open_always
+{
+    my $file = shift || die;
+    my $handle = new IO::File "<$file";
+    die "Could not open $file\n" if !$handle;
+    return $handle;
+}
+
+my @convW = ();
+my @convC = ();
+my @convK = ();
+my @convD = ();
+my @vararg = ();
+
+my $len1;
+my %conv;
+my $printit;
+my $vararg;
+
+LINE:
+while (! $h->eof()) {
+    $_ = $h->getline();
+    chop;
+    # get calling convention info for function decls
+    # what about function pointer typedefs?
+    # need to verify unhandled syntax actually triggers a report, not ignored
+    # blank lines
+    if (/^[ \t]*$/) {
+        next LINE;
+    }
+  Top:
+    # drop KRB5INT_BEGIN_DECLS and KRB5INT_END_DECLS
+    if (/^ *KRB5INT_BEGIN_DECLS/) {
+        next LINE;
+    }
+    if (/^ *KRB5INT_END_DECLS/) {
+        next LINE;
+    }
+    # drop preprocessor directives
+    if (/^ *#/) {
+        next LINE;
+    }
+    if (/^ *\?==/) {
+        next LINE;
+    }
+    s/#.*$//;
+    if (/^} *$/) {
+        next LINE;
+    }
+    # strip comments
+  Cloop1:
+    if (/\/\*./) {
+	s;/\*[^*]*;/*;;
+	s;/\*\*([^/]);/*$1;;
+	s;/\*\*$;/*;;
+	s;/\*\*/; ;g;
+	goto Cloop1;
+    }
+    # multi-line comments?
+    if (/\/\*$/) {
+	$_ .= "\n";
+	$len1 = length;
+	$_ .= $h->getline();
+	chop if $len1 < length;
+	goto Cloop1 if /\/\*./;
+    }
+    # blank lines
+    if (/^[ \t]*$/) {
+        next LINE;
+    }
+    if (/ *extern "C" {/) {
+        next LINE;
+    }
+    # elide struct definitions
+  Struct1:
+    if (/{[^}]*}/) {
+	s/{[^}]*}/ /g;
+	goto Struct1;
+    }
+    # multi-line defs
+    if (/{/) {
+	$_ .= "\n";
+	$len1 = length;
+	$_ .= $h->getline();
+	chop if $len1 < length;
+	goto Struct1;
+    }
+  Semi:
+    unless (/;/) {
+	$_ .= "\n";
+	$len1 = length;
+	$_ .= $h->getline();
+	chop if $len1 < length;
+	s/\n/ /g;
+	s/[ \t]+/ /g;
+	s/^[ \t]*//;
+	goto Top;
+    }
+    if (/^typedef[^;]*;/) {
+	s/^typedef[^;]*;//g;
+	goto Semi;
+    }
+    if (/^struct[^\(\)]*;/) {
+	s/^struct[^\(\)]*;//g;
+	goto Semi;
+    }
+    # should just have simple decls now; split lines at semicolons
+    s/ *;[ \t]*$//;
+    s/ *;/\n/g;
+    if (/^[ \t]*$/) {
+        next LINE;
+    }
+    s/[ \t]*$//;
+    goto Notfunct unless /\(.*\)/;
+    # Get rid of KRB5_PROTOTYPE
+    s/KRB5_PROTOTYPE//;
+    s/KRB5_STDARG_P//;
+    # here, is probably function decl
+    # strip simple arg list - parens, no parens inside; discard, iterate.
+    # the iteration should deal with function pointer args.
+    $vararg = /\.\.\./;
+  Striparg:
+    if (/ *\([^\(\)]*\)/) {
+	s/ *\([^\(\)]*\)//g;
+	goto Striparg;
+    }
+    # replace return type etc with one token indicating calling convention
+    if (/CALLCONV/) {
+	if (/\bKRB5_CALLCONV_WRONG\b/) {
+	    s/^.*KRB5_CALLCONV_WRONG *//;
+	    die "Invalid function name: '$_'" if (!/^[A-Za-z0-9_]+$/);
+	    push @convW, $_;
+	    push @vararg, $_ if $vararg;
+	} elsif (/\bKRB5_CALLCONV_C\b/) {
+	    s/^.*KRB5_CALLCONV_C *//;
+	    die "Invalid function name: '$_'" if (!/^[A-Za-z0-9_]+$/);
+	    push @convC, $_;
+	    push @vararg, $_ if $vararg;
+	} elsif (/\bKRB5_CALLCONV\b/) {
+	    s/^.*KRB5_CALLCONV *//;
+	    die "Invalid function name: '$_'" if (!/^[A-Za-z0-9_]+$/);
+	    push @convK, $_;
+	    push @vararg, $_ if $vararg;
+	} else {
+	    die "Unrecognized calling convention while parsing: '$_'\n";
+	}
+	goto Hadcallc;
+    }
+    # deal with no CALLCONV indicator
+    s/^.* (\w+) *$/$1/;
+    die "Invalid function name: '$_'" if (!/^[A-Za-z0-9_]+$/);
+    push @convD, $_;
+    push @vararg, $_ if $vararg;
+  Hadcallc:
+    goto Skipnotf;
+  Notfunct:
+    # probably a variable
+    s/^/VARIABLE_DECL /;
+  Skipnotf:
+    # toss blank lines
+    if (/^[ \t]*$/) {
+        next LINE;
+    }
+}
+
+print join("\n\t", "Using default calling convention:", sort(@convD));
+print join("\n\t", "\nUsing KRB5_CALLCONV:", sort(@convK));
+print join("\n\t", "\nUsing KRB5_CALLCONV_C:", sort(@convC));
+print join("\n\t", "\nUsing KRB5_CALLCONV_WRONG:", sort(@convW));
+print "\n","-"x70,"\n";
+
+%conv = ();
+map { $conv{$_} = "default"; } @convD;
+map { $conv{$_} = "KRB5_CALLCONV"; } @convK;
+map { $conv{$_} = "KRB5_CALLCONV_C"; } @convC;
+map { $conv{$_} = "KRB5_CALLCONV_WRONG"; } @convW;
+
+my %vararg = ();
+map { $vararg{$_} = 1; } @vararg;
+
+if (!$d) {
+    print "No .DEF file specified\n";
+    exit;
+}
+
+LINE2:
+while (! $d->eof()) {
+    $_ = $d->getline();
+    chop;
+    #
+    if (/^;/) {
+        $printit = 0;
+        next LINE2;
+    }
+    if (/^[ \t]*$/) {
+        $printit = 0;
+        next LINE2;
+    }
+    if (/^EXPORTS/) {
+        $printit = 0;
+        next LINE2;
+    }
+    s/[ \t]*//g;
+    my($xconv);
+    if (/PRIVATE/ || /INTERNAL/) {
+	$xconv = "PRIVATE";
+    } elsif (/!CALLCONV/ || /KRB5_CALLCONV_WRONG/) {
+	$xconv = "KRB5_CALLCONV_WRONG";
+    } elsif ($vararg{$_}) {
+	$xconv = "KRB5_CALLCONV_C";
+    } else {
+	$xconv = "KRB5_CALLCONV";
+    }
+    s/;.*$//;
+
+    if ($xconv eq "PRIVATE") {
+	print "\t private $_\n";
+	next LINE2;
+    }
+    if (!defined($conv{$_})) {
+	print "No calling convention specified for $_!\n";
+    } elsif (! ($conv{$_} eq $xconv)) {
+	print "Function $_ should have calling convention '$xconv', but has '$conv{$_}' instead.\n";
+    } else {
+#	print "Function $_ is okay.\n";
+    }
+}
+
+#print "Calling conventions defined for: ", keys(%conv);
diff --git a/mechglue/src/util/depfix.pl b/mechglue/src/util/depfix.pl
new file mode 100644
index 000000000..09a15dd57
--- /dev/null
+++ b/mechglue/src/util/depfix.pl
@@ -0,0 +1,189 @@
+#!env perl -w
+eval 'exec perl -S $0 ${1+"$@"}'
+  if 0;
+$0 =~ s/^.*?(\w+)[\.\w+]*$/$1/;
+
+# Input: srctop thisdir srcdir buildtop libgccfilename stlibobjs
+
+# Notes: myrelativedir is something like "lib/krb5/asn.1" or ".".
+# stlibobjs will usually be empty, or include spaces.
+
+# A typical set of inputs, produced with srcdir=.. at top level:
+#
+# SRCTOP = ../../../util/et/../..
+# thisdir = util/et
+# srcdir = ../../../util/et
+# BUILDTOP = ../..
+# libgcc file name = /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/libgcc.a
+# STLIBOBJS = error_message.o et_name.o com_err.o
+
+my($SRCTOP,$thisdir,$srcdir,$BUILDTOP,$libgccpath,$STLIBOBJS) = @ARGV;
+
+if (0) {
+    print STDERR "SRCTOP = $SRCTOP\n";
+    print STDERR "BUILDTOP = $BUILDTOP\n";
+    print STDERR "STLIBOBJS = $STLIBOBJS\n";
+}
+
+$libgccincdir = $libgccpath;
+$libgccincdir =~ s,libgcc\.[^ ]*$,include,;
+$libgccincdir = quotemeta($libgccincdir);
+#$srcdirpat = quotemeta($srcdir);
+
+sub my_qm {
+    my($x) = @_;
+    $x = quotemeta($x);
+    $x =~ s,\\/,/,g;
+    return $x;
+}
+
+sub strrep {
+    my($old,$new,$s) = @_;
+    my($l) = "strrep('$old','$new','$s')";
+    my($out) = "";
+    while ($s ne "") {
+	my($i) = index($s, $old);
+	if ($i == -1) {
+	    $out .= $s;
+	    $s = "";
+	} else {
+	    $out .= substr($s, 0, $i) . $new;
+	    if (length($s) > $i + length($old)) {
+		$s = substr($s, $i + length($old));
+	    } else {
+		$s = "";
+	    }
+	}
+    }
+#    print STDERR "$l = '$out'\n";
+    return $out;
+}
+
+sub do_subs {
+    local($_) = @_;
+    s,\\$, \\,g; s, + \\$, \\,g;
+    s,//+,/,g; s, \./, ,g;
+    if ($STLIBOBJS ne "") {
+	# Only care about the additional prefixes if we're building
+	# shared libraries.
+	s,^([a-zA-Z0-9_\-]*)\.o:,$1.so $1.po \$(OUTPRE)$1.\$(OBJEXT):,;
+    } else {
+	s,^([a-zA-Z0-9_\-]*)\.o:,\$(OUTPRE)$1.\$(OBJEXT):,;
+    }
+    # Drop GCC include files, they're basically system headers.
+    s,$libgccincdir/[^ ]* ,,go;
+    s,$libgccincdir/[^ ]*$,,go;
+    # Recognize $(SRCTOP) and variants.
+    my($srct) = $SRCTOP . "/";
+    $_ = strrep(" $srct", " \$(SRCTOP)/", $_);
+#    s, $pat, \$(SRCTOP)/,go;
+    while ($srct =~ m,/[a-z][a-zA-Z0-9_.\-]*/\.\./,) {
+	$srct =~ s,/[a-z][a-zA-Z0-9_.\-]*/\.\./,/,;
+	$_ = strrep(" $srct", " \$(SRCTOP)/", $_);
+    }
+    # Now try to produce pathnames relative to $(srcdir).
+    if ($thisdir eq ".") {
+	# blah
+    } else {
+	my($pat) = " \$(SRCTOP)/$thisdir/";
+	my($out) = " \$(srcdir)/";
+	$_ = strrep($pat, $out, $_);
+	while ($pat =~ m,/[a-z][a-zA-Z0-9_.\-]*/$,) {
+	    $pat =~ s,/[a-z][a-zA-Z0-9_.\-]*/$,/,;
+	    $out .= "../";
+	    if ($pat ne " \$(SRCTOP)/") {
+		$_ = strrep($pat, $out, $_);
+	    }
+	}
+    }
+    # Now substitute for BUILDTOP:
+    $_ = strrep(" $BUILDTOP/", " \$(BUILDTOP)/", $_);
+    return $_;
+}
+
+sub do_subs_2 {
+    local($_) = @_;
+    # Add a trailing space.
+    s/$/ /;
+    # Remove excess spaces.
+    s/  */ /g;
+    # Delete Tcl-specific headers.
+    s;/[^ ]*/tcl\.h ;;g;
+    s;/[^ ]*/tclDecls\.h ;;g;
+    s;/[^ ]*/tclPlatDecls\.h ;;g;
+    # Delete system-specific or compiler-specific files.
+    s;/os/usr/include/[^ ]* ;;g;
+    s;/usr/include/[^ ]* ;;g;
+    s;/usr/lib/[^ ]* ;;g;
+    # Remove foo/../ sequences.
+    while (m/\/[a-z][a-z0-9_.\-]*\/\.\.\//) {
+	s//\//g;
+    }
+    # Use VPATH.
+    s;\$\(srcdir\)/([^ /]* );$1;g;
+
+    # Allow override of some util dependencies in case local tools are used.
+    s;\$\(BUILDTOP\)/include/com_err.h ;\$(COM_ERR_DEPS) ;g;
+    s;\$\(BUILDTOP\)/include/ss/ss.h \$\(BUILDTOP\)/include/ss/ss_err.h ;\$(SS_DEPS) ;g;
+    s;\$\(BUILDTOP\)/include/db.h \$\(BUILDTOP\)/include/db-config.h ;\$(DB_DEPS) ;g;
+
+    $_ = &uniquify($_);
+
+    # Some krb4 dependencies should only be present if building with krb4
+    # enabled.
+    s;\$\(BUILDTOP\)/include/kerberosIV/krb_err.h ;\$(KRB_ERR_H_DEP) ;g;
+
+    # Delete trailing whitespace.
+    s; *$;;g;
+
+    return $_;
+}
+
+sub uniquify {
+    # Apparently some versions of gcc -- like
+    # "gcc version 3.4.4 20050721 (Red Hat 3.4.4-2)"
+    # -- will sometimes emit duplicate header file names.
+    local($_) = @_;
+    my(@words) = split " ", $_;
+    my($w);
+    my($result) = "";
+    my(%seen);
+    undef %seen;
+    foreach $w (@words) {
+	next if defined($seen{$w});
+	$seen{$w} = 1;
+	if ($result ne "") { $result .= " "; }
+	$result .= $w;
+    }
+    return $result . " ";
+}
+
+sub split_lines {
+    local($_) = @_;
+    s/(.{50}[^ ]*) /$1 \\\n  /g;
+    return $_ . "\n";
+}
+
+print <<EOH ;
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+EOH
+my $buf = '';
+while (<STDIN>) {
+    # Strip newline.
+    chop;
+    # Do directory-specific path substitutions on each filename read.
+    $_ = &do_subs($_);
+    if (m/\\$/) {
+	chop;
+	$buf .= $_;
+    } else {
+	$buf = &do_subs_2($buf . $_);
+	print &split_lines($buf);
+	$buf = '';
+    }
+}
+exit 0;
diff --git a/mechglue/src/util/et/.Sanitize b/mechglue/src/util/et/.Sanitize
new file mode 100644
index 000000000..f2f266bfb
--- /dev/null
+++ b/mechglue/src/util/et/.Sanitize
@@ -0,0 +1,60 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+com_err.3
+com_err.c
+com_err.h
+com_err.texinfo
+compile_et.1
+compile_et.c
+compile_et.sh
+compiler.h
+config_script
+configure
+configure.in
+error_message.c
+error_table.h
+error_table.y
+et_c.awk
+et_h.awk
+et_lex.lex.l
+et_name.c
+init_et.c
+internal.h
+mit-sipb-copyright.h
+test1.et
+test2.et
+test_et.c
+texinfo.tex
+vfprintf.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/util/et/ChangeLog b/mechglue/src/util/et/ChangeLog
new file mode 100644
index 000000000..b7e3710f0
--- /dev/null
+++ b/mechglue/src/util/et/ChangeLog
@@ -0,0 +1,964 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c (com_err_initialize, com_err_terminate): If
+	SHOW_INITFINI_FUNCS is defined, print tracing messages.
+
+2005-01-17  Jeffrey Altman <jaltman@mit.edu>
+
+        * error_message.c: implement library unload cleanup of mutexes
+
+2005-01-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c (com_err_terminate): Lock the list mutex before
+	walking through it; unlock and destroy it afterwards.
+
+2004-11-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* et_h.awk: Declare initialize_*_error_table as taking no
+	arguments.
+	* et_h.pl: Regenerated.
+
+2004-10-07  Tom Yu  <tlyu@mit.edu>
+
+	* et_c.awk, et_h.awk: Fix off-by-one error.
+	* et_c.pl, et_h.pl: Regenerated.
+
+2004-10-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* et_c.awk, et_h.awk: Complain if the error table is too large.
+	* et_c.pl, et_h.pl: Regenerated.
+
+2004-07-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c (remove_error_table) [!ENABLE_THREADS &&
+	DEBUG_THREADS]: Update test for 'initialized' field in mutex.
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* vfprintf.c: Don't test macintosh.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(OUTPRE)test_et.exe): New target.
+	(check-windows): Build and run test_et.exe.
+	(SHLIB_EXPLIBS): Add $(LIBS).
+
+	* error_message.c: Include autoconf.h.
+	(HAVE_STRERROR) [_WIN32]: Don't define.
+	(error_message) [_WIN32]: Check for range WSABASEERR+[0,1100)
+	instead of all values under 12000.  Use k5_getspecific and
+	k5_setspecific for local buffer.
+
+	* test_et.c (EXPORT_LIST): Define on Windows.
+	(main): Use add/remove_error_table, not the initialize_ routines.
+	(main) [EXPORT_LIST]: Don't test error_table_name, it's not in the
+	export list.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* com_err.c (com_err_va): In success case, don't then fall
+	through into error case.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* com_err.c: Include stdlib.h.
+	(com_err_hook_lock): New mutex.
+	(com_err_lock_hook_handle): New function.
+	(com_err_va, set_com_err_hook, reset_com_err_hook): Call
+	com_err_finish_init, and grab the lock.
+	* error_message.c: Don't include k5-thread.h.
+	(com_err_finish_init): New function.
+	(com_err_initialize): Initialize the new mutex.
+	* error_table.h: Include k5-thread.h.
+	(com_err_hook_lock, com_err_finish_init): Declare.
+
+2004-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c (terminated): New variable.
+	(com_err_terminate): Set it.
+	(remove_error_table): Check it, warn and abort if set.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c (buffer): Static variable deleted.
+	(com_err_initialize): Register cleanup support for com_err
+	thread-specific data key.
+	(error_message): Use a per-thread dynamically-allocated buffer
+	instead of static storage, for the case where an unknown error
+	code is given.  If any errors occur allocating or tracking the
+	buffer, return a fixed message.
+
+	* t_com_err.c: Include stdlib.h.  If TEST_THREADS is defined,
+	include pthread.h.
+	(run): Renamed from main, changed signature.
+	(main): New function.  Just call run, or if TEST_THREADS is
+	defined, create a thread to call it.
+
+2004-05-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Invoke KRB5_BUILD_PROGRAM and KRB5_RUN_FLAGS.
+	* Makefile.in (PROG_RPATH, PROG_LIBPATH, RUN_SETUP): New
+	variables.
+	(test_et, t_com_err): Use the built library, even if shared.
+	(check-unix): Set up the environment properly to load shared
+	libraries when running the test programs.
+
+	* configure.in: Enable dependency support for shared lib.
+	* Makefile.in (test_et, t_com_err): Depend on, and link against,
+	the new support library.
+	(SHLIB_EXPDEPS, SHLIB_EXPLIBS, SHLIB_RDIRS, SHLIB_DIRS): New
+	variables.
+
+2004-04-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBINITFUNC, LIBFINIFUNC): New variables.
+
+	* error_message.c (com_err_terminate): Free heap storage in
+	et_list_dynamic.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	Delete support for old globally-visible linked list, necessary
+	for thread support.
+	* Makefile.in (STLIBOBJS, LINTFILES, LIBOBJS, SRCS): Drop
+	init_et.c.
+	* error_message.c: Include k5-platform.h.
+	(et_list_lock): Use new partial initializer.
+	(com_err_initialize, com_err_terminate): New init/fini functions.
+	(error_message, add_error_table, remove_error_table): Ensure the
+	initializer ran successfully.
+	* error_table.h (_et_list) [!_WIN32]: Delete declaration.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libcom_err.exports: New file.
+
+2004-03-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c: Include k5-thread.h.
+	(_et_list): Now always static.
+	(et_list_lock): New mutex.
+	(error_message): Lock it while manipulating the table lists.
+	(add_error_table, remove_error_table): Likewise.
+
+2003-07-04  Kenneth Raeburn  <raeburn@mit.edu>
+
+	* test_et.c: Conditionalize sys_nerr declaration on
+	NEED_SYS_ERRLIST, not HAVE_SYS_ERRLIST.
+
+2003-06-12  Alexandra Ellwood  <lxs@mit.edu>
+    * error_table.h, et_c.awk, et_c.pl, et_h.awk, et_c.awk: Removed Mac 
+    OS support because it prevents darwin builds from getting com error 
+    strings via the initialize_*_error_table function
+
+2003-04-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* test_et.c [HAVE_SYS_ERRLIST]: Do declare sys_nerr.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* compile_et.c: Don't declare malloc or errno.  Include stdlib.h
+	and errno.h.
+	* test_et.c: Don't declare errno or sys_nerr.
+
+2003-03-06  Alexandra Ellwood  <lxs@mit.edu>
+    * com_err.c, com_err.h, error_message.c, et_c.awk, et_h.awk: 
+      Removed Mac OS 9-specific code.
+    * et_h.awk: define compat macro for init_foo_err_table
+      so that it gets defined to nothing on the Mac.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_INSTALL,
+	AC_PROG_ARCHIVE, AC_PROG_RANLIB.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* et_h.awk: It's "const struct error_table et_" in the c file, so
+	it's now const here too.
+
+2002-10-07  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in (install-headers): build compile_et so it can be used later
+
+2002-09-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* com_err.c (default_com_err_proc, com_err_va, set_com_err_hook):
+	Define with prototype syntax.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(COM_ERR_HDR)): Quote target of copy, since it
+	will now contain forward slashes even on Windows.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (install): Don't install mit-sipb-copyright.h, it's
+	never referenced.
+
+2002-07-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c: Put # for cpp directives in first column.
+
+2002-07-08  Tom Yu  <tlyu@mit.edu>
+
+	* et_c.awk: Fix up <com_err.h> inclusion for windows and mac.
+
+	* et_c.pl: Regenerate.
+
+2002-07-03  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fix rebuild rules et_?.perl -> et_?.pl.  Also,
+	strip the "#!" line.
+
+	* error_table.h: Fix mac conditional, due to _et_list declaration
+	moving from et_c.awk
+
+	* et_c.perl, et_h.perl: Remove.
+
+	* et_c.pl, et_h.pl: Generate.
+
+2002-07-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* com_err.h: Windows should include <win-mac.h> as opposed
+	to <Kerberos5/win-mac.h>
+	[pullup from 1-2-2-branch]
+
+2002-07-03  Miro Jurisic  <meeroh@mit.edu>
+
+	* et_c.perl, et_h.perl: 
+        Renamed to et_c.pl and et_h.pl because the extension is used
+        as a newline separator heuristic in MacPerl parser
+
+	* et_c.perl, et_h.perl: 
+        Removed #! from the first line to avoid confusing MacPerl
+
+	[pullups from 1-2-2-branch]
+
+2002-07-03  Alexandra Ellwood  <lxs@mit.edu>
+
+	* com_err.h, error_message.c, et.pbexp, et_c.awk, et_h.awk: 
+        conditionalized com_err so it doesn't need to export et_list 
+        on Mac OS X 
+	[pullup from 1-2-2-branch]
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* com_err.h (KRB5_EXPORTVAR): Don't define.
+
+	* com_err.c, com_err.h, compile_et.c, error_message.c,
+	error_table.h, et_c.awk, et_c.perl, et_h.awk, et_h.awk, et_h.perl,
+	etN-ame.c, init_et.c, internal.h, vfprintf.c: Drop NEAR/FAR
+	support and _MSDOS support.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* com_err.c, com_err.h, error_message.c, init_et.c: Don't use
+	KRB5_DLLIMP.
+
+2001-06-20  Ezra Peisach  <epeisach@mit.edu>
+
+	* error_message.c (error_message): Conditional label on _sgi so
+	gcc does not warn about being defined and not used.
+
+2001-06-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c (error_message): Handle some Irix error codes
+	ranging up above sys_nerr, and above 256.
+
+	* test_et.c (main): Test one of the high-numbered Irix system
+	error codes.
+
+2001-03-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* com_err.h: For struct error_table, change the base from an
+	unsigned to signed long (error messages and tables are signed)
+
+2001-03-07  Ken Raeburn  <raeburn@mit.edu>
+
+	* test_et.c (main): Only use sys_nerr tests if HAVE_SYS_ERRLIST.
+
+2001-01-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* com_err.h (add_error_table, remove_error_table): Annotate as
+	modifying internal state.
+	(struct et_list, _et_list): Remove.
+
+	* error_table.h (struct et_list, _et_list): Put back here.
+
+	* error_message.c (add_error_table, remove_error_table): Annotate
+	specific modifications.  Disable inconsistent-defifition checks
+	since _et_list isn't describe in the header file but is global and
+	modified.
+
+	* et_c.awk: Make the generated initialization function simply call
+	add_error_table, and drop the static linked-list node.
+
+2001-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* error_message.c (add_error_table, remove_error_table): Allow
+	tables to be entered and removed multiple times, keeping the count
+	correct.
+	* t_com_err.c (main): Update to reflect new semantics.
+
+2001-01-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (test1.c, test2.c, et1.c, et2.c, test1.h, test2.h,
+	et1.h, et2.h): All depend on compile_et and awk scripts.
+	(prefix, bindir, datadir, mydatadir): New variables.
+	(install-unix): Install compile_et and awk scripts, and compile_et
+	man page.
+	(compile_et): Pass awk script install dir as extra argument.
+	(et_c.awk, et_h.awk): Delete targets for putting copies in build
+	tree.
+	* config_script: Take install dir as extra argument.
+	* compile_et.sh: Accept "-d DIR" to override awk script
+	directory.  Set "-ex" shell flags before running awk commands.
+
+2000-12-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* et_c.awk: Don't generate macros we won't use.  Assume ANSI C
+	prototypes.  Include com_err.h in output file, rather than
+	duplicating declarations.
+
+	* com_err.c: Assume ANSI C; drop conditional-prototype macros and
+	varargs.h support.
+
+	* com_err.h: Get rid of old 68k-Mac pragmas.
+	(HAVE_STDARG_H, ET_P, ET_STDARG_P, ET_VARARGS): Don't define.
+	(struct et_list, _et_list): Declare, with annotations.
+	* error_table.h (struct et_list, _et_list): Don't declare here.
+
+	* error_message.c (_et_list): Annotate.
+	(error_message, add_error_table, remove_error_table): Check
+	'table' field of et_list for null pointer.
+
+	* t_com_err.c: Include string.h.
+	(try_one): Check strcmp value against zero explicitly.
+	(main): Annotate arguments as unused.  Cast add_error_table and
+	remove_error_table return values to void.
+
+	* Makefile.in (clean-unix): Clean up lclint files too.
+	(clean-lclint): New target.
+	(et1.c, et2.c, et1.h, et2.h, test1.c, test1.h, test2.h, test2.c):
+	Show dependencies on awk scripts.
+	(LCLINTOPTS): Remove +boolint, add +mod-uncon, +modinternalstrict,
+	+mod-filesys, remove expected error.
+	(com_err.lcd): New target; processes library through lclint and
+	generates a dump file.
+	(do-lclint): Now runs lclint on one of the test programs, and
+	depends on (but doesn't currently use) com_err.lcd.
+	(rebuild, rebuild-c, rebuild-h): New targets: Rebuild perl
+	versions of awk scripts.
+	(clean-files): Get more generated files from test cases.
+	* et_c.perl, et_h.perl: Rebuilt.
+
+2000-11-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (check-unix): Depend on, and run, t_com_err and
+	test_et.
+	* test_et.c (main): Return type is int; return 0 at end.  Use %ld
+	format for error code values.
+	(error_table_name): Declare.
+
+2000-11-08  Ken Raeburn  <raeburn@mit.edu>
+
+	Test out lclint and its4 on com_err library, fixing reported
+	problems (including a rewrite of the memory management model).
+	One lclint error left on Solaris, due to deficiencies in lclint.
+	Its4 chokes in parser.
+	* com_err.h (struct error_table): Annotate MSGS as pointing to
+	'shared' data.
+	(error_message): Returned data is 'observer' and 'dependent';
+	modifies internal state.
+	* com_err.c (default_com_err_proc): Cast various return values to
+	void.
+	(reset_com_err_hook): Use NULL, not 0.
+	(com_err_hook): Annotate as 'null'.
+	* error_table.h (_et_list): Annotate as 'null' and 'dependent'.
+	(struct et_list): Annotate NEXT as 'dependent' and 'null', and
+	TABLE as 'dependent'.
+	(struct dynamic_et_list): Duplicate et_list definition, except
+	NEXT is annotated as 'only' instead of 'dependent'.
+	(error_table_name, error_table_name_r): Annotate for lclint.
+	* et_h.awk: Add lclint annotations for initialize_* functions.
+	* error_message.c (_et_list): Can be 'null'.
+	(error_message): Explicitly compare against zero.  Cast strerror
+	argument to int.
+	(et_list_dynamic): New variable, for dynamically allocated list
+	elements; _et_list is now for statically allocated elements only.
+	(add_error_table, remove_error_table): Check both lists.
+	* et_name.c (error_table_name, error_table_name_r): Annotate for
+	lclint.
+	* init_et.c (et_add_error_table): Change "link" to "e" to avoid
+	confusion with C library function in analysis tools.
+	* et1.et, et2.et, t_com_err.c: New files.  Exercise addition and
+	removal of error tables from list, using both interfaces.
+	* Makefile.in (LCLINT, LCLINTOPTS, ITS4, ITS4OPTS): New
+	variables.
+	(do-lclint, do-its4, et1.o, et2.o, t_com_err.o, t_com_err): New
+	targets.  Not automatically invoked at present.
+	(FILES): Updated.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Change AC_CONST to AC_C_CONST, AC_HEADER_EGREP to
+	AC_EGREP_HEADER, AC_HAVE_HEADERS to AC_CHECK_HEADERS. Updates to
+	autoconf 2 namespace.
+
+2000-07-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* et_c.awk: Actually define NOARGS as needed. Add prototype for
+	error table initiialization function.
+
+2000-07-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* com_err.h (com_err): Undo previous change; com_err accepts a
+	null pointer in place of the format string, but gcc warns about
+	it.
+
+2000-06-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* com_err.h (com_err): Declare with format attribute if using
+	gcc.
+
+2000-05-07  Miro Jurisic  <meeroh@mit.edu>
+
+	* com_err.c (default_com_err_proc): use strncpy
+	where strncpy was meant (typo in Nalin's patch)
+
+2000-05-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* com_err.c (default_com_err_proc) [_MSDOS || _WIN32 ||
+	macintosh]: Don't overflow buffer "errbuf".
+
+2000-02-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (com_err.o): Depends on com_err.c.
+
+1999-10-28  Alexandra Ellwood  <lxs@mit.edu>
+
+	* error_message.c, error_table.h: Added support to use ErrorLib 
+	to get MIT Support Library and Mac OS Toolbox error codes 
+	(similar to the way windows does it).
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-18  Miro Jurisic  <meeroh@mit.edu>
+
+	* et.exp: Added et.exp, MacOS export file for com_err library
+
+1999-06-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* texinfo.tex: Get rid of control characters in text file.
+
+Wed May 19 11:44:31 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add windows build rules for putting header files in
+		include dir.  Do cleanup of header for windows clean.
+
+Mon May 10 15:27:07 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Mon Mar 15 16:01:56 1999  Tom Yu  <tlyu@mit.edu>
+
+	* com_err.h: Fix GSS_DLLIMP.
+
+Mon Feb  1 19:42:45 1999  Tom Yu  <tlyu@mit.edu>
+
+	* et_c.awk: Fix to not depend on CPP symbol "unix".
+
+	* et_h.awk: Fix to not depend on CPP symbol "unix".
+
+1998-12-01  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* com_err.h, error_table.h, error_message.c: Use "#if
+	        defined(MSDOS) || ..." instead of "#if
+	        !defined(unix)", since not all Unix compilers define
+		"unix".
+
+1998-07-02  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* com_err.c (MacMessageBox): Change TextBox to TETextBox to match
+		up with CodeWarrior changes.
+
+Wed Feb 18 16:33:07 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Wed Jan 28 17:54:57 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in, Makefile.in: Remove CopySrcHeader from
+		configure.in, and move functionality to Makefile.in
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Tue Oct  7 07:43:05 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(srcdir) as prefix to srcs.
+
+Mon Jul 21 12:00:24 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* error_message.c (error_message): Mask error code with
+		ERRCODE_MASK to handle case where 32bit ints are zero
+		filed in the gssapi layer.
+
+	* error_table.h: Define ERRCODE_MAX, the maximum allowed error
+		code (32bits).  
+
+Tue Mar 18 15:07:40 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* com_err.h: Add 'extern "C"' for C++ compatibility; also check for
+		__cplusplus since some C++ compilers don't set __STDC__
+
+Mon Mar  3 14:57:35 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* error_message.c: Don't declare sys_nerr on Macintosh.
+
+	* com_err.c: Fix MacMessageBox prototype.
+
+Sat Mar  1 11:54:02 1997  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+	* com_err.h: Do not declare com_err_hook extern if you want it
+ 	static in the source file. [383]
+	
+
+Sat Feb 22 12:18:47 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Move list file construction to win-post.in
+
+	* et_c.awk et_h.awk error_message.c com_err.c:
+		Put back #ifdef unix, and also based it on AIX.
+		We do NOT want the compatibility interface on any new
+		architectures.  Since we have distributed Kerberos on
+		AIX before, we need it there.  If newer Unix systems
+		lack the #define, so be it... it doesn't matter.
+
+Sat Feb 22 02:18:47 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* et_h.awk (char_shift): Avoid #ifdef unix
+	* error_message.c: Remove #ifdef unix
+	* com_err.c: Remove #ifdef unix
+
+Sat Feb 22 00:34:05 1997  Sam Hartman  <hartmans@luminous.MIT.EDU>
+
+	* Makefile.in (LIBMAJOR):  Bump to 3 so that the krb5 lib is preferred to the NetBSD system library.
+
+Fri Feb 14 13:55:45 1997  Richard Basch  <basch@lehman.com>
+
+	* com_err.c com_err.h error_message.c error_table.h et_c.awk et_h.awk:
+		Removed experimental V2 API
+		Added table register/deregister functions
+		Only make the com_err_hook vars/funcs available on Unix
+		Only expose _et_list on Unix
+
+Tue Feb 11 13:31:49 1997  Richard Basch  <basch@lehman.com>
+
+	* com_err.c: If the application is a console application, simply
+		display the message to stderr. (win32)
+
+Mon Feb 10 21:30:41 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* com_err.c, com_err.h (com_err_va): Fix broken Windows 16
+		declaration.  (Should be KRB5_CALLCONV, and using ET_P)
+
+Fri Feb  7 22:10:23 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* compile_et.c: Change the emitted name of the struct error_table
+ 		to be et_XXX_error_table, instead of it being a static
+ 		variable named "et".  (This change has already been made
+		in the awk versions of compile_et.)
+
+	* com_err.h, com_err.c: Remove the void *priv argument from
+ 		com_err_va() and et_com_err() experimental API's.  (That
+ 		was a braino; the private data pointer should come from
+ 		the hook_func_data field.)
+
+Fri Feb  7 19:03:07 1997  Richard Basch  <basch@lehman.com>
+
+	* com_err.c com_err.h: Added old interface function com_err_va
+
+Tue Feb  4 15:59:01 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in com_err.h error_table.h et_c.awk error_message.c
+		Corrected various declarations for Windows build
+
+Wed Jan 29 17:32:23 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Add rules to build test_et (for testing!)
+
+	* com_err.h, error_table.h: Fixed up varargs/stdargs declarations
+		Move definition of struct error_table into com_err.h, and 
+		define first draft of the V2 API.  Removed the Windows
+		specific declarations from error_table.h, since it's now
+		safe to 
+
+	* com_err.c, error_message.c, init_et.c, et_name.c: Added new
+		V2 API's.  Cleaned up C code.  
+
+	* test_et.c: Added new test case for error code 0
+
+	* et_c.awk: Added __far for Windows 16 pointer.
+
+	* internal.h: File removed, no longer used.
+
+	* error_table.y: Add #include the header file "com_err.h"
+
+Thu Nov 21 11:55:16 EST 1996    Richard Basch   <basch@lehman.com>
+
+        * Makefile.in: win32 build
+	* com_err.h error_table.h init_et.c internal.h
+		Win32 support
+
+Tue Dec 31 12:54:54 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (RELDIR): Add for new procedure.
+
+Mon Dec 30 17:30:43 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to use new library build procedure.
+
+Mon Nov 18 20:37:19 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Set shared library version to 1.0. [krb5-libs/201]
+
+Wed Nov 13 19:19:08 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (clean-unix): Remove shared/*.
+
+Thu Oct 17 18:24:50 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* error_message.c (error_message): Work around a compiler bug on
+		the Alpha.
+
+Thu Sep  5 21:31:07 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* et_c.awk: Change continuation processing so that it doesn't
+ 		depend on ANSI C string concatenation.  (No need for it,
+ 		since the .c file isn't designed for human consumption
+ 		anyway.)
+
+Fri Aug 30 22:55:14 1996  Tom Yu  <tlyu@mit.edu>
+
+	* internal.h: #ifdef NEED_SYS_ERRLIST -> #ifdef
+		SYS_ERRLIST_DECLARED for sanity's sake.
+
+	* error_message.c: cpp symbol police: HAS_FOO -> HAVE_FOO
+
+	* configure.in: Fix up check for strerror; use autoconf
+		conventions
+
+Wed Jun 12 12:10:59 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* error_table.h: For Win32, define away FAR and NEAR.
+
+Mon Jun 10 21:54:09 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* com_err.h:
+	* error_table.h: Add Windows-32 ifdefs.  Change use of
+		INTERFACE to KRB5_CALLCONV and KRB5_DLLIMP.  See
+		ChangeLog entries for src/include/krb5.hin for more
+		information.
+
+
+	* vfprintf.c, internal.h, compile_et.c, et_c.awk, com_err.c:
+	 	Change _WINDOWS to _MSDOS, and add check for _WIN32.
+
+Sun May 12 01:13:02 1996  Marc Horowitz  <marc@mit.edu>
+
+	* et_c.awk: deal with continuations in the input .et file.
+
+Wed Mar 20 00:19:08 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (SRCS): Fix SRCS definition so that it doesn't fool
+		the Macintosh macfiles.sh Makefile generation script.
+
+Tue Mar 12 22:34:10 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Use AC_HEADER_STDARG.
+
+Sat Feb 24 18:50:03 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* error_message.c (HAS_STRERROR): Windows has strerror()
+
+Wed Feb  7 00:19:17 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (CCFILES): Checked in danw's changes to support
+		building Makefiles for the Macintosh; use standard SRCS
+		macro for the source files.
+
+Fri Oct  6 22:06:48 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Oct  2 15:22:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* error_message.c (error_message): Fix logic if #ifdefs for
+		HAVE_STRERROR and HAVE_SYS_ERRLIST.  strerror() is used in
+		preference to sys_errlist().
+
+Mon Oct  2 11:16:32 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in (V5_MAKE_SHARED_LIB): Add version number 0.1 for
+		library creation. 
+
+	* Makefile.in (clean-unix): Remove DONE
+
+Mon Sep 25 16:41:50 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Wed Sep 20 12:00:00 1995	James Mattly <mattly@fusion.com>
+
+	* com_err.c:  Mac UI improvements, added a hilite arround the default button,
+		also made the window respond to enter, return, and escape keys.
+
+Fri Sep 22 19:58:22 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* error_message.c (sys_nerr): Only define sys_nerr if we're on a
+		Macintosh.  On those systems which use sys_nerr, it's an
+		external variable, defined by libc.  Under Windows, it's
+		apparently an cpp macro.
+
+Mon Aug  7 19:22:52 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (compile_et): Add $(SHELL) to invocation of
+		config_script, so that the tree can build even after
+		checked into a broken SCCS system.
+
+Thu Jul 13 15:40:56 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* com_err.h: error_message should be const char * (as it is in
+        error_message.c), not char const * (as currently presented).
+
+Alspo, since error_message
+ets declared const even on non-ansi compilers, set the return type that way so AIX cc doesn't barf.	
+
+Wed Jul 12 12:37:24 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* error_message.c: Do not include stdlib.h unless it exists
+
+Fri Jul 7 16:42:20 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Add DEPLIBS, needed by shared library rule.
+
+Wed July  5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* com_err.[ch] added _MACINTOSH conditional
+	* vsprintf.h added inclusion of stdarg.h for _MACINTSOH
+
+Fri Jun 23 20:08:16 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in: fix typo; appended "all" rule needs two colons to
+		keep gmake from breaking.
+
+Thu Jun 22 16:14:25 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* error_table.h: reverse sense of KRB5_PROVIDE_PROTOTYPES
+
+Fri Jun 23 10:50:14 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* Makefile.in - Change "./done" and "done" to DONE.  Shared library
+		script requires "DONE".
+
+Thu Jun 22 13:06:47 1995  Sam Hartman  <hartmans@tardis.MIT.EDU>
+
+	* Makefile.in Changed libcom_err.a to libcom_err.$(STEXT), removed rule to clean it up on Unix as aclocal.m4 already inserts the rule.  If this breaks on Macs, please let me know how I should do this in the future.
+
+	* configure.in: Changed to make libcom_err as a shared library.
+
+Fri Jun  9 19:00:05 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Jun  8 11:26:09 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* Makefile.in (install): Don't install compile_et.1; we're not
+		installing the program, anyway.
+
+Tue Jun  6 19:45:34 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* configure.in:
+	* Makefile.in: fix make install
+
+Fri Jun 2 18:05:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* error_message.c: better handling of Winsock errors.
+
+Tue May  2 21:35:09 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: remove spurious whitespace from blank line
+
+Fri Apr 14 08:48:00 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* com_err.h: If FAR is not defined, define it away.
+
+Thu Apr 13 16:02:24 1995 Keith Vetter (keithv@fusion.com)
+
+        * com_err.c, compile_et.c, error_ta.h, et_c.awk, internal.h:
+           __STDC__ conditionals also checks for the _WINDOWS define.
+
+Wed Apr 5 16:25:35 1995 Keith Vetter (keithv@fusion.com)
+
+	* com_err.h: added FAR to pointers in prototypes.
+
+Wed Mar 29 08:56:47 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in:  Fix up Mac makefile.
+	* error_message.c:  For errno, use strerror if HAS_STRERROR.
+	* configure.in:  Define HAS_STRERROR.
+
+Thu Mar 23 19:00:03 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* com_err.c (default_com_err_proc): Fixed breakage introduced by
+		windows port.  com_err() is supposed to print a newline at
+		after printing the error message!
+
+Wed Mar 22 11:34:09 1995 Keith Vetter (keithv@fusion.com)
+
+	* com_err.c: added _WINDOWS equivalent condition to HAVE_STDARG_H
+ 	   since windows fakes autoconf by defining such constants in
+	   k5-config.h which isn't included for this file.
+
+Thu Mar 16 19:57:20 1995 Keith Vetter (keithv@fusion.com)
+
+	* com_err.c: added missing INTERFACE on a prototype.
+        * com_err.h: added _WINDOWS as an equivalent to __STDC__ since this
+           file gets included by windows programs in which __STDC__ isn't defined.
+        * makefile.in: added xxx-mac targets to mimic xxx-unix, and added
+            copying com_err.h to src\include for the PC.
+
+Wed Mar 16 17:30:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* com_err.h: problem with this file needing k5-config for windows
+	   stuff but many application programs don't include it. So for
+	   now I've put the windows stuff that is needed directly into it.
+
+Wed Mar 15 23:02:14 1995 Keith Vetter (keithv@fusion.com)
+
+	* com_err.c: made to work on the PC. Biggest changes was that
+           the error message now gets built in a buffer and either gets
+           printed to stderr or for Windows gets displays in a message box.
+        * err_message.c: fixed up includes and some 32/16 bit ints.
+        * et_name.c: changed two ints into longs.
+        * com_err.h: added windows keyword INTERFACE to prototypes.
+        * error_table.h: Added some windows specific defines since this
+           source doesn't really know about k5-config.h. Also, added 
+           prototype for error_table_name().
+	* Makefile.in: PC rules to make com_err, err_message and et_name.
+
+Tue Feb 28 13:23:58 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* error_table.h: Remove #ifdef STDC check to see if we should use
+		const --- configure takes care of this.
+
+Tue Feb 28 01:35:14 1995  John Gilmore  (gnu at toad.com)
+
+	* com_err.3:  Document "com_err.h" rather than <com_err.h>.
+
+Fri Feb  3 08:11:26 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* com_err.h: All routines defined in the com_err library should
+		have extern before the prototypes.   (Required for SGI
+		platform).
+
+Wed Jan 25 20:48:50 1995  Mark Eichin  (eichin@tweedledumber.cygnus.com)
+
+	* Makefile.in (SRCS): add com_err.c explicit dependency to work
+	around VPATH bug in Solaris make. Also fix typo in comment.
+
+Fri Nov 18 00:34:29 1994  Mark Eichin  <eichin@cygnus.com>
+
+	* configure.in: add caching to perror check (from epeisach).
+
+Fri Oct 21 21:06:48 1994    (tytso@rsx-11)
+
+	* Makefile.in (SED): Don't specify an explicit pathname for sed.
+
+Tue Oct 11 12:43:00 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Don't rm the awk and sed scripts during a make clean!
+
+Thu Oct  6 19:39:11 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* compile_et.sh: Replace basename with sed -- more portable.
+
+Mon Oct  3 17:27:28 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in:
+	  configure.in: Don't try to compile compile_et.  Use awk/sed
+	  	  version instead.  It's more apt to be portable, since it
+		  doesn't use awk or sed.  :-(
+	
+
+Fri Sep 30 17:12:15 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* compile_et.c: Add declaration of error_message() manually.
+
+	* internal.h: Use autoconf to determine whether or not to declare
+		perror().
+
+	* configure.in:
+	  compiler.h:
+	  internal.h:
+	  compilet_et.c:
+	  init_et.c: Let configure take care of removing const with AC_CONST.
+
+Thu Sep  8 22:33:07 1994  Theodore Y. Ts'o  (tytso@pinata)
+
+	* com_err.c (default_com_err_proc): Reversed order of \n\r to make
+		jik happy.
+
+Wed Jul 13 23:19:34 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: nuke the libcom_err.a.bak stuff
+
+Sun Jul  3 07:48:04 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: cleaning up to not spew ignored errors
+
+Wed Jun 22 18:47:36 1994  Mark Eichin  (eichin@tweedledumber.cygnus.com)
+
+	* com_err.h: Only set STDARG_PROTOTYPES based on STDC if it isn't
+	set already (clean up warnings.)
+
+Wed Jun 22 17:55:48 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* Makefile.in (CP): set CP so CopySrcHeader actually works.
+
+Tue Jun 21 00:20:44 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: add "includes" to "all" dependencies
+
+	* configure.in: should be CopySrcHeader
+
+Mon Jun 20 21:59:37 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in: install com_err.h during build
+
diff --git a/mechglue/src/util/et/ISSUES b/mechglue/src/util/et/ISSUES
new file mode 100644
index 000000000..2197fb7af
--- /dev/null
+++ b/mechglue/src/util/et/ISSUES
@@ -0,0 +1,60 @@
+Issues to be addressed for src/util/et: -*- text -*-
+
+Non-thread-safe aspects:
+
+error_message uses a static buffer for "unknown error code" messages;
+a per-thread buffer may be better, but that depends on dynamic
+allocation working.  A caller-provided buffer would be best, but
+that's a API change.
+
+initialize_foo_error_table uses a global linked list hung off an
+unprotected variable in the library.  {add,remove}_error_table do
+likewise, but can be changed without externally visible effect.
+
+Workaround: Use a global lock for all calls to error_message and
+com_err, and when adding or removing error tables.
+
+API divergence:
+
+Transarc and Heimdal both have APIs that are different from this
+version.  (Specifics?)
+
+Karl Ramm has offered to try to combine them.
+
+Workaround:
+
+Reference counting:
+
+If libraries are dynamically loaded and unloaded, and the init/fini
+functions add and remove error tables for *other* libraries they
+depend on (e.g., if a dynamically loadable Zephyr library's fini
+function removes the krb4 library error table and then dlcloses the
+krb4 library, while another dlopen reference keeps the krb4 library
+around), the error table is kept; a table must be removed the same
+number of times it was added before the library itself can be
+discarded.
+
+It's not implemented as a reference count, but the effect is the same.
+
+Fix needed: Update documentation.
+
+64-bit support:
+
+Values are currently computed as 32-bit values, sign-extended to
+"long", and output with "L" suffixes.  Type errcode_t is "long".
+Kerberos uses a seperately chosen signed type of at least 32 bits for
+error codes.  The com_err library only look at the low 32 bits, so
+this is mostly just an issue for application code -- if anything
+truncates to 32 bits, and then widens without sign-extending, the
+value may not compare equal to the macro defined in the .h file.  This
+isn't anything unusual for signed constants, of course, just something
+to keep in mind....
+
+Workaround: Always use signed types of at least 32 bits for error
+codes.
+
+man page:
+
+No documentation on add_error_table/remove_error_table interfaces,
+even though they're the new, preferred interface.
+
diff --git a/mechglue/src/util/et/Makefile.in b/mechglue/src/util/et/Makefile.in
new file mode 100644
index 000000000..b5baa191f
--- /dev/null
+++ b/mechglue/src/util/et/Makefile.in
@@ -0,0 +1,262 @@
+prefix=@prefix@
+bindir=@bindir@
+datadir=@datadir@
+mydatadir=$(datadir)/et
+thisconfigdir=.
+myfulldir=util/et
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+RELDIR=../util/et
+SED = sed
+
+##DOS##BUILDTOP = ..\..
+##DOS##LIBNAME=$(OUTPRE)comerr.lib
+##DOS##XTRA=
+##DOS##OBJFILE=$(OUTPRE)comerr.lst
+
+STLIBOBJS=error_message.o et_name.o com_err.o
+STOBJLISTS=OBJS.ST
+LIBBASE=com_err
+LIBMAJOR=3
+LIBMINOR=0
+LIBINITFUNC=com_err_initialize
+LIBFINIFUNC=com_err_terminate
+
+all-unix:: all-liblinks
+clean-unix:: clean-liblinks clean-libs clean-libobjs clean-lclint
+install-unix:: install-libs
+
+LINTFLAGS=-uhvb 
+LINTFILES= error_message.c et_name.c com_err.c
+LIBOBJS=$(OUTPRE)com_err.$(OBJEXT) \
+	$(OUTPRE)error_message.$(OBJEXT) \
+	$(OUTPRE)et_name.$(OBJEXT)
+# for et_lex.lex.c include in error_table.y
+LOCALINCLUDES=-I. -I$(srcdir)
+
+FILES=	Makefile et_name.c error_message.c compile_et.c \
+		et_lex.lex.l error_table.y init_et.c \
+		com_err.c com_err.h \
+		error_table.h mit-sipb-copyright.h \
+		test_et.c test1.et test2.et \
+		t_com_err.c et1.et et2.et \
+		compiler.h internal.h \
+		com_err.texinfo texinfo.tex
+#SRCS=	compile_et.c error_table.c error_message.c et_name.c \
+#	init_et.c com_err.c
+SRCS= $(srcdir)/error_message.c \
+	$(srcdir)/et_name.c \
+	$(srcdir)/com_err.c
+
+#
+# Warning flags
+#
+# Uncomment WFLAGS if you want really anal GCC warning messages
+#
+#
+WFLAGS=		-ansi -D_POSIX_SOURCE -pedantic \
+			-Wall -Wwrite-strings -Wpointer-arith \
+			-Wcast-qual -Wcast-align -Wtraditional \
+			-Wstrict-prototypes -Wmissing-prototypes \
+			-Wnested-externs -Winline -DNO_INLINE_FUNCS -Wshadow 
+
+DEPLIBS=
+SHLIB_LIBS=
+SHLIB_EXPDEPS = $(SUPPORT_DEPLIB)
+SHLIB_EXPLIBS=-l$(SUPPORT_LIBNAME) $(LIBS)
+SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@	
+SHLIB_LIBDIRS= @SHLIB_LIBDIRS@
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+SHLIB_DIRS=-L$(TOPLIBD)
+
+COM_ERR_HDR=$(BUILDTOP)$(S)include$(S)com_err.h
+
+all-windows:: $(COM_ERR_HDR)
+
+$(COM_ERR_HDR): com_err.h
+	$(CP) com_err.h "$@"
+
+error_table.c: et_lex.lex.c 
+error_table.c: $(srcdir)/error_table.y
+
+error_table.o: error_table.c et_lex.lex.c
+	$(CC) $(ALL_CFLAGS) -c error_table.c
+
+com_err.o : com_err.c
+
+et_lex.lex.o: et_lex.lex.c
+test1.o: test1.c
+test2.o: test2.c
+test_et.o: test1.h test2.h
+et1.o: et1.c
+et2.o: et2.c
+test1.c test2.c et1.c et2.c test1.h test2.h et1.h et2.h: \
+	compile_et et_c.awk et_h.awk
+t_com_err.o: et1.h et2.h t_com_err.c
+
+# /u1/kr/lclint-2.5q/bin/lclint -warnposix -D__sparc
+LCLINT=lclint
+# +posixlib	gets more complete errno list than ansilib
+# -usedef	turns off bogus warnings from poor dataflow analysis (should be
+#		redundant with gcc warnings anyways)
+# -warnposix
+# +charintliteral
+# +ignoresigns
+# -predboolint
+# -exportlocal
+# -retvalint	allow ignoring of int return values (e.g., fputs)
+LCLINTOPTS=+posixlib \
+	-usedef -warnposix +charintliteral +ignoresigns -predboolint +boolint \
+	-exportlocal -retvalint \
+	+mod-uncon +modinternalstrict +modfilesys
+com_err.lcd: error_table.c error_table.h et_lex.lex.c com_err.h
+	$(LCLINT) $(LCLINTOPTS) $(LOCALINCLUDES) $(DEFS) $(SRCS) \
+		-dump com_err.new -expect 1
+	mv -f com_err.new com_err.lcd
+do-lclint: com_err.lcd t_com_err.c et1.c et2.c et1.h et2.h
+	$(LCLINT) $(LCLINTOPTS) $(LOCALINCLUDES) \
+		$(srcdir)/t_com_err.c et1.c et2.c
+# "-load com_err.lcd" -> lclint brokenness
+clean-lclint:
+	$(RM) com_err.new com_err.lcd
+ITS4=its4
+ITS4OPTS=
+do-its4: error_table.y et_lex.lex.c
+	$(ITS4) $(ITS4OPTS) $(SRCS)
+
+#test_et: test_et.o test1.o test2.o $(LIBOBJS)
+#	$(CC) -o test_et test_et.o test1.o test2.o $(LIBOBJS)
+#t_com_err: t_com_err.o et1.o et2.o $(LIBOBJS)
+#	$(CC) -o t_com_err t_com_err.o et1.o et2.o $(LIBOBJS)
+
+PROG_RPATH=$(KRB5_LIBDIR)
+PROG_LIBPATH=-L$(TOPLIBD)
+test_et: test_et.o test1.o test2.o $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o test_et test_et.o test1.o test2.o -lcom_err $(SUPPORT_LIB)
+t_com_err: t_com_err.o et1.o et2.o $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
+	$(CC_LINK) -o t_com_err t_com_err.o et1.o et2.o -lcom_err $(SUPPORT_LIB)
+
+$(OUTPRE)test_et.exe: $(OUTPRE)test_et.$(OBJEXT) $(OUTPRE)test1.$(OBJEXT) \
+	$(OUTPRE)test2.$(OBJEXT) $(CLIB)
+	link $(EXE_LINKOPTS) -out:$(OUTPRE)test_et$(EXEEXT) $**
+
+all-unix:: compile_et includes
+
+includes:: com_err.h
+	if cmp $(srcdir)/com_err.h \
+	$(BUILDTOP)/include/com_err.h >/dev/null 2>&1; then :; \
+	else \
+		(set -x; $(RM) $(BUILDTOP)/include/com_err.h; \
+		 $(CP) $(srcdir)/com_err.h \
+			$(BUILDTOP)/include/com_err.h) ; \
+	fi
+
+clean-unix::
+	$(RM) $(BUILDTOP)/include/com_err.h
+
+RUN_SETUP = @KRB5_RUN_ENV@
+# test_et doesn't have an interesting exit status, but it'll exercise
+# some cases that t_com_err doesn't, so let's see if it crashes.
+check-unix:: t_com_err test_et
+	$(RUN_SETUP) ./test_et
+	$(RUN_SETUP) ./t_com_err
+
+check-windows:: $(OUTPRE)test_et$(EXEEXT)
+	set path=$(BUILDTOP)\lib\$(OUTPRE);%path%;
+	path
+	$(OUTPRE)test_et$(EXEEXT)
+
+# The real compile_et just isn't portable.  (But then again, anything using 
+# lex and yacc isn't portable by definition.  :-(  )
+#
+#compile_et: compile_et.o error_table.o
+#	$(CC) $(CFLAGS) -o $@ compile_et.o error_table.o $(LEXLIB) $(BSDLIB)
+#
+install-unix:: compile_et
+	$(INSTALL) compile_et $(DESTDIR)$(bindir)/compile_et
+	test -d $(DESTDIR)$(mydatadir) || mkdir $(DESTDIR)$(mydatadir)
+	$(INSTALL_DATA) $(srcdir)/et_c.awk $(DESTDIR)$(mydatadir)
+	$(INSTALL_DATA) $(srcdir)/et_h.awk $(DESTDIR)$(mydatadir)
+
+
+install-headers:: compile_et
+
+compile_et: $(srcdir)/compile_et.sh $(srcdir)/config_script
+	$(SHELL) $(srcdir)/config_script $(srcdir)/compile_et.sh \
+		"$(mydatadir)" $(AWK) $(SED) > compile_et
+	chmod 755 compile_et	
+
+rebuild: rebuild-c rebuild-h
+rebuild-c:
+	a2p < $(srcdir)/et_c.awk | awk 'NR != 1 || $$0 !~ /^\043!/{print;}' > $(srcdir)/et_c.tmp
+	mv -f $(srcdir)/et_c.tmp $(srcdir)/et_c.pl
+rebuild-h:
+	a2p < $(srcdir)/et_h.awk | awk 'NR != 1 || $$0 !~ /^\043!/{print;}' > $(srcdir)/et_h.tmp
+	mv -f $(srcdir)/et_h.tmp $(srcdir)/et_h.pl
+
+clean-unix::
+	$(RM) compile_et
+
+depend:: 
+
+install:: com_err.h 
+	$(INSTALL_DATA) $(srcdir)/com_err.h  $(DESTDIR)$(KRB5_INCDIR)/com_err.h
+
+install-unix:: compile_et.1
+	$(INSTALL_DATA) $(srcdir)/compile_et.1 $(DESTDIR)$(CLIENT_MANDIR)/compile_et.1
+
+
+## install_library_target(com_err,$(LIBOBJS),$(LINTFILES),)
+
+clean-unix:: clean-files
+
+clean-files::
+	rm -f *~ \#* *.bak \
+		*.otl *.aux *.toc *.PS *.dvi *.x9700 *.ps \
+		*.cp *.fn *.ky *.log *.pg *.tp *.vr \
+		*.o profiled/?*.o libcom_err.a libcom_err_p.a \
+		com_err.o compile_et \
+		et.ar TAGS y.tab.c lex.yy.c error_table.c \
+		et_lex.lex.c \
+		test1.h test1.c test2.h test2.c test_et \
+		et1.c et1.h et2.c et2.h t_com_err \
+		eddep makedep *.ln
+
+clean-windows::
+	$(RM) $(COM_ERR_HDR)
+
+com_err.ps : com_err.dvi
+com_err.dvi: com_err.texinfo
+
+libcom_err.o:	$(LIBOBJS)
+	ld -r -s -o libcom_err.o $(LIBOBJS)
+	chmod -x libcom_err.o
+
+archive:	et.tar
+
+TAGS:	et_name.c error_message.c compile_et.c error_table.c \
+		lex.yy.c init_et.c
+	etags et_name.c error_message.c compile_et.c \
+		error_table.c init_et.c
+
+depend::  et_lex.lex.c
+
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+error_message.so error_message.po $(OUTPRE)error_message.$(OBJEXT): \
+  error_message.c $(BUILDTOP)/include/krb5/autoconf.h \
+  com_err.h error_table.h $(SRCTOP)/include/k5-thread.h \
+  $(SRCTOP)/include/k5-platform.h
+et_name.so et_name.po $(OUTPRE)et_name.$(OBJEXT): et_name.c \
+  com_err.h error_table.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+com_err.so com_err.po $(OUTPRE)com_err.$(OBJEXT): com_err.c \
+  com_err.h error_table.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
diff --git a/mechglue/src/util/et/com_err.3 b/mechglue/src/util/et/com_err.3
new file mode 100644
index 000000000..d4704342c
--- /dev/null
+++ b/mechglue/src/util/et/com_err.3
@@ -0,0 +1,96 @@
+.\" Copyright (c) 1988 Massachusetts Institute of Technology,
+.\" Student Information Processing Board.  All rights reserved.
+.\"
+.\" util/et/com_err.3
+.\"
+.TH COM_ERR 3 "22 Nov 1988" SIPB
+.SH NAME
+com_err \- common error display routine
+.SH SYNOPSIS
+.nf
+ #include "com_err.h"
+.PP
+void com_err (whoami, code, format, ...);
+	const char *whoami;
+	long code;
+	const char *format;
+.PP
+proc = set_com_err_hook (proc);
+.fi
+void (*
+.I proc
+) (const char *, long, const char *, va_list);
+.nf
+.PP
+proc = reset_com_err_hook ();
+.PP
+void initialize_XXXX_error_table ();
+.fi
+.SH DESCRIPTION
+.I Com_err
+displays an error message on the standard error stream
+.I stderr
+(see
+.IR stdio (3S))
+composed of the
+.I whoami
+string, which should specify the program name or some subportion of
+a program, followed by an error message generated from the
+.I code
+value (derived from
+.IR compile_et (1)),
+and a string produced using the
+.I format
+string and any following arguments, in the same style as
+.IR fprintf (3).
+
+The behavior of
+.I com_err
+can be modified using
+.I set_com_err_hook;
+this defines a procedure which is called with the arguments passed to
+.I com_err,
+instead of the default internal procedure which sends the formatted
+text to error output.  Thus the error messages from a program can all
+easily be diverted to another form of diagnostic logging, such as
+.IR syslog (3).
+.I Reset_com_err_hook
+may be used to restore the behavior of
+.I com_err
+to its default form.  Both procedures return the previous ``hook''
+value.  These ``hook'' procedures must have the declaration given for
+.I proc
+above in the synopsis.
+
+The
+.I initialize_XXXX_error_table
+routine is generated mechanically by
+.IR compile_et (1)
+from a source file containing names and associated strings.  Each
+table has a name of up to four characters, which is used in place of
+the
+.B XXXX
+in the name of the routine.  These routines should be called before
+any of the corresponding error codes are used, so that the
+.I com_err
+library will recognize error codes from these tables when they are
+used.
+
+The
+.B com_err.h
+header file should be included in any source file that uses routines
+from the
+.I com_err
+library; executable files must be linked using
+.I ``-lcom_err''
+in order to cause the
+.I com_err
+library to be included.
+
+.\" .IR for manual entries
+.\" .PP for paragraph breaks
+
+.SH "SEE ALSO"
+compile_et (1), syslog (3).
+
+Ken Raeburn, "A Common Error Description Library for UNIX".
diff --git a/mechglue/src/util/et/com_err.c b/mechglue/src/util/et/com_err.c
new file mode 100644
index 000000000..94b379816
--- /dev/null
+++ b/mechglue/src/util/et/com_err.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright 1997 by Massachusetts Institute of Technology
+ * 
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+ * used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. and the M.I.T. S.I.P.B. make no representations about
+ * the suitability of this software for any purpose.  It is
+ * provided "as is" without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "com_err.h"
+#include "error_table.h"
+
+#if defined(_WIN32)
+#include <io.h>
+#endif
+
+static /*@null@*/ et_old_error_hook_func com_err_hook = 0;
+k5_mutex_t com_err_hook_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
+static void default_com_err_proc (const char *whoami, errcode_t code,
+				  const char *fmt, va_list ap)
+{
+#if defined(_WIN32)
+
+	char errbuf[1024] = "";
+
+	if (whoami) {
+		errbuf[sizeof(errbuf) - 1] = '\0';
+		strncat (errbuf, whoami, sizeof(errbuf) - 1 - strlen(errbuf));
+		strncat (errbuf, ": ", sizeof(errbuf) - 1 - strlen(errbuf));
+	}
+	if (code) {
+		errbuf[sizeof(errbuf) - 1] = '\0';
+		strncat (errbuf, error_message(code), sizeof(errbuf) - 1 - strlen(errbuf));
+		strncat (errbuf, " ", sizeof(errbuf) - 1 - strlen(errbuf));
+	}
+	if (fmt)
+	    /* ITS4: ignore vsprintf */
+	    vsprintf (errbuf + strlen (errbuf), fmt, ap);
+	errbuf[sizeof(errbuf) - 1] = '\0';
+
+#ifdef _WIN32
+	if (_isatty(_fileno(stderr))) {
+	    fputs(errbuf, stderr);
+	    fputc('\r', stderr);
+	    fputc('\n', stderr);
+	    fflush(stderr);
+	} else
+#endif /* _WIN32 */
+	    MessageBox ((HWND)NULL, errbuf, "Kerberos", MB_ICONEXCLAMATION);
+
+#else /* !_WIN32 */
+    
+	if (whoami) {
+		fputs(whoami, stderr);
+		fputs(": ", stderr);
+	}
+	if (code) {
+		fputs(error_message(code), stderr);
+		fputs(" ", stderr);
+	}
+	if (fmt) {
+		vfprintf(stderr, fmt, ap);
+	}
+	/* should do this only on a tty in raw mode */
+	putc('\r', stderr);
+	putc('\n', stderr);
+	fflush(stderr);
+
+#endif
+}
+
+void KRB5_CALLCONV com_err_va(const char *whoami,
+			      errcode_t code,
+			      const char *fmt,
+			      va_list ap)
+{
+    int err;
+    et_old_error_hook_func p;
+
+    err = com_err_finish_init();
+    if (err)
+	goto best_try;
+    err = k5_mutex_lock(&com_err_hook_lock);
+    if (err)
+	goto best_try;
+    p = com_err_hook ? com_err_hook : default_com_err_proc;
+    (*p)(whoami, code, fmt, ap);
+    k5_mutex_unlock(&com_err_hook_lock);
+    return;
+
+best_try:
+    /* Yikes.  Our library initialization failed or we couldn't lock
+       the lock we want.  We could be in trouble.  Gosh, we should
+       probably print an error message.  Oh, wait.  That's what we're
+       trying to do.  In fact, if we're losing on initialization here,
+       there's a good chance it has to do with failed initialization
+       of the caller.  */
+    if (!com_err_hook)
+	default_com_err_proc(whoami, code, fmt, ap);
+    else
+	(com_err_hook)(whoami, code, fmt, ap);
+    assert(err == 0);
+    abort();
+}
+
+
+void KRB5_CALLCONV_C com_err(const char *whoami,
+			     errcode_t code,
+			     const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	com_err_va(whoami, code, fmt, ap);
+	va_end(ap);
+}
+
+#if !(defined(_WIN32))
+/* Make a separate function because the assert invocations below
+   use the macro expansion on some platforms, which may be insanely
+   long and incomprehensible.  */
+static int com_err_lock_hook_handle(void)
+{
+    return k5_mutex_lock(&com_err_hook_lock);
+}
+
+et_old_error_hook_func set_com_err_hook (et_old_error_hook_func new_proc)
+{
+	et_old_error_hook_func x;
+
+	/* Broken initialization?  What can we do?  */
+	assert(com_err_finish_init() == 0);
+	assert(com_err_lock_hook_handle() == 0);
+	x = com_err_hook;
+	com_err_hook = new_proc;
+	k5_mutex_unlock(&com_err_hook_lock);
+	return x;
+}
+
+et_old_error_hook_func reset_com_err_hook ()
+{
+	et_old_error_hook_func x;
+
+	/* Broken initialization?  What can we do?  */
+	assert(com_err_finish_init() == 0);
+	assert(com_err_lock_hook_handle() == 0);
+	x = com_err_hook;
+	com_err_hook = NULL;
+	k5_mutex_unlock(&com_err_hook_lock);
+	return x;
+}
+#endif
diff --git a/mechglue/src/util/et/com_err.h b/mechglue/src/util/et/com_err.h
new file mode 100644
index 000000000..042a9bd45
--- /dev/null
+++ b/mechglue/src/util/et/com_err.h
@@ -0,0 +1,72 @@
+/*
+ * Header file for common error description library.
+ *
+ * Copyright 1988, Student Information Processing Board of the
+ * Massachusetts Institute of Technology.
+ *
+ * Copyright 1995 by Cygnus Support.
+ *
+ * For copyright and distribution info, see the documentation supplied
+ * with this package.
+ */
+
+#ifndef __COM_ERR_H
+
+#if defined(_WIN32)
+#include <win-mac.h>
+#endif
+
+#ifndef KRB5_CALLCONV
+#define KRB5_CALLCONV
+#define KRB5_CALLCONV_C
+#endif
+
+#include <stdarg.h>
+
+typedef long errcode_t;
+typedef void (*et_old_error_hook_func) (const char *, errcode_t,
+					const char *, va_list ap);
+	
+struct error_table {
+	/*@shared@*/ char const * const * msgs;
+        long base;
+	unsigned int n_msgs;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Public interfaces */
+extern void KRB5_CALLCONV_C com_err
+	(const char *, errcode_t, const char *, ...);
+extern void KRB5_CALLCONV com_err_va
+	(const char *whoami, errcode_t code, const char *fmt,
+	 va_list ap);
+extern /*@observer@*//*@dependent@*/ const char * KRB5_CALLCONV error_message
+	(errcode_t)
+       /*@modifies internalState@*/;
+extern errcode_t KRB5_CALLCONV add_error_table
+	(/*@dependent@*/ const struct error_table *)
+       /*@modifies internalState@*/;
+extern errcode_t KRB5_CALLCONV remove_error_table
+	(const struct error_table *)
+       /*@modifies internalState@*/;
+
+#if !defined(_WIN32)
+/*
+ * The display routine should be application specific.  A global hook,
+ * may cause inappropriate display procedures to be called between
+ * applications under non-Unix environments.
+ */
+
+extern et_old_error_hook_func set_com_err_hook (et_old_error_hook_func);
+extern et_old_error_hook_func reset_com_err_hook (void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#define __COM_ERR_H
+#endif /* ! defined(__COM_ERR_H) */
diff --git a/mechglue/src/util/et/com_err.texinfo b/mechglue/src/util/et/com_err.texinfo
new file mode 100644
index 000000000..918f15276
--- /dev/null
+++ b/mechglue/src/util/et/com_err.texinfo
@@ -0,0 +1,555 @@
+\input texinfo @c -*-texinfo-*-
+
+@c util/et/com_err.texinfo
+
+@c Note that although this source file is in texinfo format (more
+@c or less), it is not yet suitable for turning into an ``info''
+@c file.  Sorry, maybe next time.
+@c
+@c In order to produce hardcopy documentation from a texinfo file,
+@c run ``tex com_err.texinfo'' which will load in texinfo.tex,
+@c provided in this distribution.  (texinfo.tex is from the Free
+@c Software Foundation, and is under different copyright restrictions
+@c from the rest of this package.)
+
+@ifinfo
+@barfo
+@end ifinfo
+
+@iftex
+@tolerance 10000
+
+@c Mutate section headers...
+@begingroup
+  @catcode#=6
+  @gdef@secheading#1#2#3{@secheadingi {#3@enspace #1}}
+@endgroup
+@end iftex
+
+@setfilename com_err
+@settitle A Common Error Description Library for UNIX
+
+@ifinfo
+This file documents the use of the Common Error Description library.
+
+Copyright (C) 1987, 1988 Student Information Processing Board of the
+Massachusetts Institute of Technology.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.  Furthermore if you modify this
+software you must label your software as modified software and not
+distribute it in such a fashion that it might be confused with the
+original M.I.T. software.  M.I.T. and the M.I.T. S.I.P.B.
+make no representations about the suitability of this software for any
+purpose.  It is provided "as is" without express or implied warranty.
+
+Note that the file texinfo.tex, provided with this distribution, is from
+the Free Software Foundation, and is under different copyright restrictions
+from the remainder of this package.
+
+@end ifinfo
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+
+@setchapternewpage odd
+
+@titlepage
+@center @titlefont{A Common Error Description}
+@center @titlefont{Library for UNIX}
+@sp 2
+@center Ken Raeburn
+@center Bill Sommerfeld
+@sp 1
+@center MIT Student Information Processing Board
+@sp 3
+@center last updated 1 January 1989
+@center for version 1.2
+@center ***DRAFT COPY ONLY***
+
+@vskip 2in
+
+@center @b{Abstract}
+
+UNIX has always had a clean and simple system call interface, with a
+standard set of error codes passed between the kernel and user
+programs.  Unfortunately, the same cannot be said of many of the
+libraries layered on top of the primitives provided by the kernel.
+Typically, each one has used a different style of indicating errors to
+their callers, leading to a total hodgepodge of error handling, and
+considerable amounts of work for the programmer.  This paper describes
+a library and associated utilities which allows a more uniform way for
+libraries to return errors to their callers, and for programs to
+describe errors and exceptional conditions to their users.
+
+@page
+@vskip 0pt plus 1filll
+
+Copyright @copyright{} 1987, 1988 by the Student Information Processing
+Board of the Massachusetts Institute of Technology.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.  M.I.T. and the M.I.T. S.I.P.B.
+make no representations about the suitability of this software for any
+purpose.  It is provided "as is" without express or implied warranty.
+
+Note that the file texinfo.tex, provided with this distribution, is from
+the Free Software Foundation, and is under different copyright restrictions
+from the remainder of this package.
+
+@end titlepage
+
+@ifinfo
+@c should put a menu here someday....
+@end ifinfo
+
+@page
+
+@section Why com_err?
+
+In building application software packages, a programmer often has to
+deal with a number of libraries, each of which can use a different
+error-reporting mechanism.  Sometimes one of two values is returned,
+indicating simply SUCCESS or FAILURE, with no description of errors
+encountered.  Sometimes it is an index into a table of text strings,
+where the name of the table used is dependent on the library being
+used when the error is generated; since each table starts numbering at
+0 or 1, additional information as to the source of the error code is
+needed to determine which table to look at.  Sometimes no text messages are
+supplied at all, and the programmer must supply them at any point at which
+he may wish to report error conditions.
+Often, a global variable is assigned some value describing the error, but
+the programmer has to know in each case whether to look at @code{errno},
+@code{h_errno}, the return value from @code{hes_err()}, or whatever other
+variables or routines are specified.
+And what happens if something
+in the procedure of
+examining or reporting the error changes the same variable?
+
+The package we have developed is an attempt to present a common
+error-handling mechanism to manipulate the most common form of error code
+in a fashion that does not have the problems listed above.
+
+A list of up to 256 text messages is supplied to a translator we have
+written, along with the three- to four-character ``name'' of the error
+table.  The library using this error table need only call a routine
+generated from this error-table source to make the table ``known'' to the
+com_err library, and any error code the library generates can be converted
+to the corresponding error message.  There is also a default format for
+error codes accidentally returned before making the table known, which is
+of the form @samp{unknown code foo 32}, where @samp{foo} would be the name
+of the table.
+
+@section Error codes
+
+Error codes themselves are 32 bit (signed) integers, of which the high
+order 24 bits are an identifier of which error table the error code is
+from, and the low order 8 bits are a sequential error number within
+the table.  An error code may thus be easily decomposed into its component
+parts.  Only the lowest 32 bits of an error code are considered significant
+on systems which support wider values.
+
+Error table 0 is defined to match the UNIX system call error table
+(@code{sys_errlist}); this allows @code{errno} values to be used directly
+in the library (assuming that @code{errno} is of a type with the same width
+as @t{long}).  Other error table numbers are formed by compacting together
+the first four characters of the error table name.  The mapping between
+characters in the name and numeric values in the error code are defined in
+a system-independent fashion, so that two systems that can pass integral
+values between them can reliably pass error codes without loss of meaning;
+this should work even if the character sets used are not the same.
+(However, if this is to be done, error table 0 should be avoided, since the
+local system call error tables may differ.)
+
+Any variable which is to contain an error code should be declared @t{long}.
+The draft proposed American National Standard for C (as of May, 1988)
+requires that @t{long} variables be at least 32 bits; any system which does
+not support 32-bit @t{long} values cannot make use of this package (nor
+much other software that assumes an ANSI-C environment base) without
+significant effort.
+
+@section Error table source file
+
+The error table source file begins with the declaration of the table name,
+as
+
+@example
+error_table @var{tablename}
+@end example
+
+Individual error codes are
+specified with
+
+@example
+error_code @var{ERROR_NAME}, @var{"text message"}
+@end example
+
+where @samp{ec} can also be used as a short form of @samp{error_code}.  To
+indicate the end of the table, use @samp{end}.  Thus, a (short) sample
+error table might be:
+
+@example
+
+        error_table     dsc
+
+        error_code      DSC_DUP_MTG_NAME,
+                        "Meeting already exists"
+
+        ec              DSC_BAD_PATH,
+                        "A bad meeting pathname was given"
+
+        ec              DSC_BAD_MODES,
+                        "Invalid mode for this access control list"
+
+        end
+
+@end example
+
+@section The error-table compiler
+
+The error table compiler is named @code{compile_et}.  It takes one
+argument, the pathname of a file (ending in @samp{.et}, e.g.,
+@samp{dsc_err.et}) containing an error table source file.  It parses the
+error table, and generates two output files -- a C header file
+(@samp{discuss_err.h}) which contains definitions of the numerical values
+of the error codes defined in the error table, and a C source file which
+should be compiled and linked with the executable.  The header file must be
+included in the source of a module which wishes to reference the error
+codes defined; the object module generated from the C code may be linked in
+to a program which wishes to use the printed forms of the error codes.
+
+This translator accepts a @kbd{-language @var{lang}} argument, which
+determines for which language (or language variant) the output should be
+written.  At the moment, @var{lang} is currently limited to @kbd{ANSI-C}
+and @kbd{K&R-C}, and some abbreviated forms of each.  Eventually, this will
+be extended to include some support for C++.  The default is currently
+@kbd{K&R-C}, though the generated sources will have ANSI-C code
+conditionalized on the symbol @t{__STDC__}.
+
+@section Run-time support routines
+
+Any source file which uses the routines supplied with or produced by the
+com_err package should include the header file @file{<com_err.h>}.  It
+contains declarations and definitions which may be needed on some systems.
+(Some functions cannot be referenced properly without the return type
+declarations in this file.  Some functions may work properly on most
+architectures even without the header file, but relying on this is not
+recommended.)
+
+The run-time support routines and variables provided via this package
+include the following:
+
+@example
+void initialize_@var{xxxx}_error_table (void);
+@end example
+
+One of these routines is built by the error compiler for each error table.
+It makes the @var{xxxx} error table ``known'' to the error reporting
+system.  By convention, this routine should be called in the initialization
+routine of the @var{xxxx} library.  If the library has no initialization
+routine, some combination of routines which form the core of the library
+should ensure that this routine is called.  It is not advised to leave it
+the caller to make this call.
+
+There is no harm in calling this routine more than once.
+
+@example
+#define ERROR_TABLE_BASE_@var{xxxx} @var{nnnnn}L
+@end example
+
+This symbol contains the value of the first error code entry in the
+specified table.
+This rarely needs be used by the
+programmer.
+
+@example
+const char *error_message (long code);
+@end example
+
+This routine returns the character string error message associated
+with @code{code}; if this is associated with an unknown error table, or
+if the code is associated with a known error table but the code is not
+in the table, a string of the form @samp{Unknown code @var{xxxx nn}} is
+returned, where @var{xxxx} is the error table name produced by
+reversing the compaction performed on the error table number implied
+by that error code, and @var{nn} is the offset from that base value.
+
+Although this routine is available for use when needed, its use should be
+left to circumstances which render @code{com_err} (below) unusable.
+
+@example
+void com_err (const char *whoami,  /* module reporting error */
+              long code,           /* error code */
+              const char *format,  /* format for additional detail */
+              ...);                /*  (extra parameters) */
+@end example
+
+This routine provides an alternate way to print error messages to
+standard error; it allows the error message to be passed in as a
+parameter, rather than in an external variable.  @emph{Provide grammatical
+context for ``message.''}
+
+If @var{format} is @code{(char *)NULL}, the formatted message will not be
+printed.  @var{format} may not be omitted.
+
+@example
+#include <stdarg.h>
+
+void com_err_va (const char *whoami,
+                 long code,
+                 const char *format,
+                 va_list args);
+@end example
+
+This routine provides an interface, equivalent to @code{com_err} above,
+which may be used by higher-level variadic functions (functions which
+accept variable numbers of arguments).
+
+@example
+#include <stdarg.h>
+
+void (*set_com_err_hook (void (*proc) ())) ();
+
+void (*@var{proc}) (const char *whoami, long code, va_list args);
+
+void reset_com_err_hook ();
+@end example
+
+These two routines allow a routine to be dynamically substituted for
+@samp{com_err}.  After @samp{set_com_err_hook} has been called,
+calls to @samp{com_err} will turn into calls to the new hook routine.
+@samp{reset_com_err_hook} turns off this hook.  This may intended to
+be used in daemons (to use a routine which calls @var{syslog(3)}), or
+in a window system application (which could pop up a dialogue box).
+
+If a program is to be used in an environment in which simply printing
+messages to the @code{stderr} stream would be inappropriate (such as in a
+daemon program which runs without a terminal attached),
+@code{set_com_err_hook} may be used to redirect output from @code{com_err}.
+The following is an example of an error handler which uses @var{syslog(3)}
+as supplied in BSD 4.3:
+
+@example
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+/* extern openlog (const char * name, int logopt, int facility); */
+/* extern syslog (int priority, char * message, ...); */
+
+void hook (const char * whoami, long code,
+           const char * format, va_list args)
+@{
+    char buffer[BUFSIZ];
+    static int initialized = 0;
+    if (!initialized) @{
+        openlog (whoami,
+                 LOG_NOWAIT|LOG_CONS|LOG_PID|LOG_NDELAY,
+                 LOG_DAEMON);
+        initialized = 1;
+    @}
+    vsprintf (buffer, format, args);
+    syslog (LOG_ERR, "%s %s", error_message (code), buffer);
+@}
+@end example
+
+After making the call
+@code{set_com_err_hook (hook);},
+any calls to @code{com_err} will result in messages being sent to the
+@var{syslogd} daemon for logging.
+The name of the program, @samp{whoami}, is supplied to the
+@samp{openlog()} call, and the message is formatted into a buffer and
+passed to @code{syslog}.
+
+Note that since the extra arguments to @code{com_err} are passed by
+reference via the @code{va_list} value @code{args}, the hook routine may
+place any form of interpretation on them, including ignoring them.  For
+consistency, @code{printf}-style interpretation is suggested, via
+@code{vsprintf} (or @code{_doprnt} on BSD systems without full support for
+the ANSI C library).
+
+@section Coding Conventions
+
+The following conventions are just some general stylistic conventions
+to follow when writing robust libraries and programs.  Conventions
+similar to this are generally followed inside the UNIX kernel and most
+routines in the Multics operating system.  In general, a routine
+either succeeds (returning a zero error code, and doing some side
+effects in the process), or it fails, doing minimal side effects; in
+any event, any invariant which the library assumes must be maintained.
+
+In general, it is not in the domain of non user-interface library
+routines to write error messages to the user's terminal, or halt the
+process.  Such forms of ``error handling'' should be reserved for
+failures of internal invariants and consistancy checks only, as it
+provides the user of the library no way to clean up for himself in the
+event of total failure.
+
+Library routines which can fail should be set up to return an error
+code.  This should usually be done as the return value of the
+function; if this is not acceptable, the routine should return a
+``null'' value, and put the error code into a parameter passed by
+reference.
+
+Routines which use the first style of interface can be used from
+user-interface levels of a program as follows:
+
+@example
+@{
+    if ((code = initialize_world(getuid(), random())) != 0) @{
+        com_err("demo", code,
+                "when trying to initialize world");
+        exit(1);
+    @}
+    if ((database = open_database("my_secrets", &code))==NULL) @{
+        com_err("demo", code,
+                "while opening my_secrets");
+        exit(1);
+    @}
+@}
+@end example
+
+A caller which fails to check the return status is in error.  It is
+possible to look for code which ignores error returns by using lint;
+look for error messages of the form ``foobar returns value which is
+sometimes ignored'' or ``foobar returns value which is always
+ignored.''
+
+Since libraries may be built out of other libraries, it is often necessary
+for the success of one routine to depend on another.  When a lower level
+routine returns an error code, the middle level routine has a few possible
+options.  It can simply return the error code to its caller after doing
+some form of cleanup, it can substitute one of its own, or it can take
+corrective action of its own and continue normally.  For instance, a
+library routine which makes a ``connect'' system call to make a network
+connection may reflect the system error code @code{ECONNREFUSED}
+(Connection refused) to its caller, or it may return a ``server not
+available, try again later,'' or it may try a different server.
+
+Cleanup which is typically necessary may include, but not be limited
+to, freeing allocated memory which will not be needed any more,
+unlocking concurrancy locks, dropping reference counts, closing file
+descriptors, or otherwise undoing anything which the procedure did up
+to this point.  When there are a lot of things which can go wrong, it
+is generally good to write one block of error-handling code which is
+branched to, using a goto, in the event of failure.  A common source
+of errors in UNIX programs is failing to close file descriptors on
+error returns; this leaves a number of ``zombied'' file descriptors
+open, which eventually causes the process to run out of file
+descriptors and fall over.
+
+@example
+@{
+    FILE *f1=NULL, *f2=NULL, *f3=NULL;
+    int status = 0;
+
+    if ( (f1 = fopen(FILE1, "r")) == NULL) @{
+        status = errno;
+        goto error;
+    @}
+
+    /*
+     * Crunch for a while
+     */
+
+    if ( (f2 = fopen(FILE2, "w")) == NULL) @{
+        status = errno;
+        goto error;
+    @}
+
+    if ( (f3 = fopen(FILE3, "a+")) == NULL) @{
+        status = errno;
+            goto error;
+    @}
+
+    /*
+     * Do more processing.
+     */
+    fclose(f1);
+    fclose(f2);
+    fclose(f3);
+    return 0;
+
+error:
+    if (f1) fclose(f1);
+    if (f2) fclose(f2);
+    if (f3) fclose(f3);
+    return status;
+@}
+@end example
+
+@section Building and Installation
+
+The distribution of this package will probably be done as a compressed
+``tar''-format file available via anonymous FTP from SIPB.MIT.EDU.
+Retrieve @samp{pub/com_err.tar.Z} and extract the contents.  A subdirectory
+@t{profiled} should be created to hold objects compiled for profiling.
+Running ``make all'' should then be sufficient to build the library and
+error-table compiler.  The files @samp{libcom_err.a},
+@samp{libcom_err_p.a}, @samp{com_err.h}, and @samp{compile_et} should be
+installed for use; @samp{com_err.3} and @samp{compile_et.1} can also be
+installed as manual pages.
+
+Potential problems:
+
+@itemize @bullet
+
+@item Use of @code{strcasecmp}, a routine provided in BSD for
+case-insensitive string comparisons.  If an equivalent routine is
+available, you can modify @code{CFLAGS} in the makefile to define
+@code{strcasecmp} to the name of that routine.
+
+@item Compilers that defined @code{__STDC__} without providing the header
+file @code{<stdarg.h>}.  One such example is Metaware's High ``C''
+compiler, as provided at Project Athena on the IBM RT/PC workstation; if
+@code{__HIGHC__} is defined, it is assumed that @code{<stdarg.h>} is not
+available, and therefore @code{<varargs.h>} must be used.  If the symbol
+@code{VARARGS} is defined (e.g., in the makefile), @code{<varargs.h>} will
+be used.
+
+@item If your linker rejects symbols that are simultaneously defined in two
+library files, edit @samp{Makefile} to remove @samp{perror.c} from the
+library.  This file contains a version of @var{perror(3)} which calls
+@code{com_err} instead of calling @code{write} directly.
+
+@end itemize
+
+As I do not have access to non-BSD systems, there are probably
+bugs present that may interfere with building or using this package on
+other systems.  If they are reported to me, they can probably be fixed for
+the next version.
+
+@section Bug Reports
+
+Please send any comments or bug reports to the principal author: Ken
+Raeburn, @t{Raeburn@@Athena.MIT.EDU}.
+
+@section Acknowledgements
+
+I would like to thank: Bill Sommerfeld, for his help with some of this
+documentation, and catching some of the bugs the first time around;
+Honeywell Information Systems, for not killing off the @emph{Multics}
+operating system before I had an opportunity to use it; Honeywell's
+customers, who persuaded them not to do so, for a while; Ted Anderson of
+CMU, for catching some problems before version 1.2 left the nest; Stan
+Zanarotti and several others of MIT's Student Information Processing Board,
+for getting us started with ``discuss,'' for which this package was
+originally written; and everyone I've talked into --- I mean, asked to read
+this document and the ``man'' pages.
+
+@bye
diff --git a/mechglue/src/util/et/compile_et.1 b/mechglue/src/util/et/compile_et.1
new file mode 100644
index 000000000..a082bca46
--- /dev/null
+++ b/mechglue/src/util/et/compile_et.1
@@ -0,0 +1,79 @@
+.\" Copyright (c) 1988 Massachusetts Institute of Technology,
+.\" Student Information Processing Board.  All rights reserved.
+.\"
+.\" util/et/compile_et.1
+.\"
+.TH COMPILE_ET 1 "22 Nov 1988" SIPB
+.SH NAME
+compile_et \- error table compiler
+.SH SYNOPSIS
+.B compile_et
+file
+.SH DESCRIPTION
+.B Compile_et
+converts a table listing error-code names and associated messages into
+a C source file suitable for use with the
+.IR com_err (3)
+library.
+
+The source file name must end with a suffix of ``.et''; the file
+consists of a declaration supplying the name (up to four characters
+long) of the error-code table:
+
+.B error_table
+.I name
+
+followed by up to 256 entries of the form:
+
+.B error_code
+.I name,
+"
+.I string
+"
+
+and a final
+
+.B end
+
+to indicate the end of the table.
+
+The name of the table is used to construct the name of a subroutine
+.I initialize_XXXX_error_table
+which must be called in order for the
+.I com_err
+library to recognize the error table.
+
+The various error codes defined are assigned sequentially increasing
+numbers (starting with a large number computed as a hash function of
+the name of the table); thus for compatibility it is suggested that
+new codes be added only to the end of an existing table, and that no
+codes be removed from tables.
+
+The names defined in the table are placed into a C header file with
+preprocessor directives defining them as integer constants of up to
+32 bits in magnitude.
+
+A C source file is also generated which should be compiled and linked
+with the object files which reference these error codes; it contains
+the text of the messages and the initialization subroutine.  Both C
+files have names derived from that of the original source file, with
+the ``.et'' suffix replaced by ``.c'' and ``.h''.
+
+A ``#'' in the source file is treated as a comment character, and all
+remaining text to the end of the source line will be ignored.
+
+.SH BUGS
+
+Since
+.B compile_et
+uses a very simple parser based on
+.IR yacc (1),
+its error recovery leaves much to be desired.
+
+.\" .IR for manual entries
+.\" .PP for paragraph breaks
+
+.SH "SEE ALSO"
+com_err (3).
+
+Ken Raeburn, "A Common Error Description Library for UNIX".
diff --git a/mechglue/src/util/et/compile_et.c b/mechglue/src/util/et/compile_et.c
new file mode 100644
index 000000000..dfaad5f57
--- /dev/null
+++ b/mechglue/src/util/et/compile_et.c
@@ -0,0 +1,348 @@
+/*
+ *
+ * Copyright 1986, 1987, 1988
+ * by MIT Student Information Processing Board.
+ *
+ * For copyright info, see "mit-sipb-copyright.h".
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <string.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "mit-sipb-copyright.h"
+#include "compiler.h"
+
+#ifndef lint
+static const char copyright[] =
+    "Copyright 1987,1988 by MIT Student Information Processing Board";
+#endif
+
+extern char *gensym();
+extern char *current_token;
+extern int table_number, current;
+char buffer[BUFSIZ];
+char *table_name = (char *)NULL;
+FILE *hfile, *cfile;
+
+/* lex stuff */
+extern FILE *yyin;
+extern int yylineno;
+
+char * xmalloc (size) unsigned int size; {
+    char * p = malloc (size);
+    if (!p) {
+	perror (whoami);
+	exit (1);
+    }
+    return p;
+}
+
+static int check_arg (str_list, arg) char const *const *str_list, *arg; {
+    while (*str_list)
+	if (!strcmp(arg, *str_list++))
+	    return 1;
+    return 0;
+}
+
+static const char *const debug_args[] = {
+    "d",
+    "debug",
+    0,
+};
+
+static const char *const lang_args[] = {
+    "lang",
+    "language",
+    0,
+};
+
+static const char *const language_names[] = {
+    "C",
+    "K&R C",
+    "C++",
+    0,
+};
+
+static const char * const c_src_prolog[] = {
+    "static const char * const text[] = {\n",
+    0,
+};
+
+static const char * const krc_src_prolog[] = {
+    "#if defined(__STDC__) || defined(_WIN32)\n",
+    "#define NOARGS void\n",
+    "#else\n",
+    "#define NOARGS\n",
+    "#define const\n",
+    "#endif\n\n",
+    "static const char * const text[] = {\n",
+    0,
+};
+
+static const char *const struct_def[] = {
+    "struct error_table {\n",
+    "    char const * const * msgs;\n",
+    "    long base;\n",
+    "    int n_msgs;\n",
+    "};\n",
+    "struct et_list {\n",
+    "    struct et_list *next;\n",
+    "    const struct error_table * table;\n",
+    "};\n",
+    "extern struct et_list *_et_list;\n",
+    "\n", 0,
+};
+
+static const char warning[] =
+    "/*\n * %s:\n * This file is automatically generated; please do not edit it.\n */\n";
+
+/* pathnames */
+char c_file[MAXPATHLEN];	/* output file */
+char h_file[MAXPATHLEN];	/* output */
+
+static void usage () {
+    fprintf (stderr, "%s: usage: %s ERROR_TABLE\n",
+	     whoami, whoami);
+    exit (1);
+}
+
+static void dup_err (type, one, two) char const *type, *one, *two; {
+    fprintf (stderr, "%s: multiple %s specified: `%s' and `%s'\n",
+	     whoami, type, one, two);
+    usage ();
+}
+
+int main (argc, argv) int argc; char **argv; {
+    char *p, *ename;
+    int len;
+    char const * const *cpp;
+    int got_language = 0;
+
+    /* argument parsing */
+    debug = 0;
+    filename = 0;
+    whoami = argv[0];
+    p = strrchr (whoami, '/');
+    if (p)
+	whoami = p+1;
+    while (argv++, --argc) {
+	char *arg = *argv;
+	if (arg[0] != '-') {
+	    if (filename)
+		dup_err ("filenames", filename, arg);
+	    filename = arg;
+	}
+	else {
+	    arg++;
+	    if (check_arg (debug_args, arg))
+		debug++;
+	    else if (check_arg (lang_args, arg)) {
+		got_language++;
+		arg = *++argv, argc--;
+		if (!arg)
+		    usage ();
+		if (language)
+		    dup_err ("languanges", language_names[(int)language], arg);
+#define check_lang(x,v) else if (!strcasecmp(arg,x)) language = v
+		check_lang ("c", lang_C);
+		check_lang ("ansi_c", lang_C);
+		check_lang ("ansi-c", lang_C);
+		check_lang ("krc", lang_KRC);
+		check_lang ("kr_c", lang_KRC);
+		check_lang ("kr-c", lang_KRC);
+		check_lang ("k&r-c", lang_KRC);
+		check_lang ("k&r_c", lang_KRC);
+		check_lang ("c++", lang_CPP);
+		check_lang ("cplusplus", lang_CPP);
+		check_lang ("c-plus-plus", lang_CPP);
+#undef check_lang
+		else {
+		    fprintf (stderr, "%s: unknown language name `%s'\n",
+			     whoami, arg);
+		    fprintf (stderr, "\tpick one of: C K&R-C\n");
+		    exit (1);
+		}
+	    }
+	    else {
+		fprintf (stderr, "%s: unknown control argument -`%s'\n",
+			 whoami, arg);
+		usage ();
+	    }
+	}
+    }
+    if (!filename)
+	usage ();
+    if (!got_language)
+	language = lang_KRC;
+    else if (language == lang_CPP) {
+	fprintf (stderr, "%s: Sorry, C++ support is not yet finished.\n",
+		 whoami);
+	exit (1);
+    }
+
+    p = xmalloc (strlen (filename) + 5);
+    strcpy (p, filename);
+    filename = p;
+    p = strrchr(filename, '/');
+    if (p == (char *)NULL)
+	p = filename;
+    else
+	p++;
+    ename = p;
+    len = strlen (ename);
+    p += len - 3;
+    if (strcmp (p, ".et"))
+	p += 3;
+    *p++ = '.';
+    /* now p points to where "et" suffix should start */
+    /* generate new filenames */
+    strcpy (p, "c");
+    strcpy (c_file, ename);
+    *p = 'h';
+    strcpy (h_file, ename);
+    strcpy (p, "et");
+
+    yyin = fopen(filename, "r");
+    if (!yyin) {
+	perror(filename);
+	exit(1);
+    }
+
+    hfile = fopen(h_file, "w");
+    if (hfile == (FILE *)NULL) {
+	perror(h_file);
+	exit(1);
+    }
+    fprintf (hfile, warning, h_file);
+
+    cfile = fopen(c_file, "w");
+    if (cfile == (FILE *)NULL) {
+	perror(c_file);
+	exit(1);
+    }
+    fprintf (cfile, warning, c_file);
+
+    /* prologue */
+    if (language == lang_C)
+	cpp = c_src_prolog;
+    else if (language == lang_KRC)
+	cpp = krc_src_prolog;
+    else
+	abort ();
+    while (*cpp)
+	fputs (*cpp++, cfile);
+
+    /* parse it */
+    yyparse();
+    fclose(yyin);		/* bye bye input file */
+
+    fputs ("    0\n};\n\n", cfile);
+    for (cpp = struct_def; *cpp; cpp++)
+	fputs (*cpp, cfile);
+    fprintf(cfile,
+	    "const struct error_table et_%s_error_table = { text, %ldL, %d };\n\n",
+	    table_name, table_number, current);
+    fputs("static struct et_list link = { 0, 0 };\n\n",
+	  cfile);
+    fprintf(cfile, "void initialize_%s_error_table (%s) {\n",
+	    table_name, (language == lang_C) ? "void" : "NOARGS");
+    fputs("    if (!link.table) {\n", cfile);
+    fputs("        link.next = _et_list;\n", cfile);
+    fprintf(cfile, "        link.table = &et_%s_error_table;\n", table_name);
+    fputs("        _et_list = &link;\n", cfile);
+    fputs("    }\n", cfile);
+    fputs("}\n", cfile);
+    fclose(cfile);
+
+    fprintf (hfile, "extern void initialize_%s_error_table ();\n",
+	     table_name);
+    fprintf (hfile, "#define ERROR_TABLE_BASE_%s (%ldL)\n",
+	     table_name, table_number);
+    /* compatibility... */
+    fprintf (hfile, "\n/* for compatibility with older versions... */\n");
+    fprintf (hfile, "#define init_%s_err_tbl initialize_%s_error_table\n",
+	     table_name, table_name);
+    fprintf (hfile, "#define %s_err_base ERROR_TABLE_BASE_%s\n", table_name,
+	     table_name);
+    fclose(hfile);		/* bye bye include file */
+
+    return 0;
+}
+
+int yyerror(s) char *s; {
+    fputs(s, stderr);
+#ifdef NO_YYLINENO
+    fprintf(stderr, "\nLast token was '%s'\n", current_token);
+#else
+    fprintf(stderr, "\nLine number %d; last token was '%s'\n",
+	    yylineno, current_token);
+#endif
+}
+
+#ifdef NEED_STRCASECMP
+/* Need strcasecmp for this machine */
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+/* based on @(#)strcasecmp.c	1.3 (Berkeley) 8/3/87 */
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+strcasecmp(s1, s2)
+	register char *s1, *s2;
+{
+	register char *cm = charmap;
+
+	while (cm[*s1] == cm[*s2++])
+		if (*s1++ == '\0')
+			return(0);
+	return(cm[*s1] - cm[*--s2]);
+}
+
+#endif
diff --git a/mechglue/src/util/et/compile_et.sh b/mechglue/src/util/et/compile_et.sh
new file mode 100755
index 000000000..adb0be666
--- /dev/null
+++ b/mechglue/src/util/et/compile_et.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+#
+AWK=@AWK@
+DIR=@DIR@
+
+usage="usage: $0 [ -d scriptDir ] inputfile.et"
+
+if [ "$1" = "-d" ]; then
+    if [ $# -lt 3 ]; then
+	echo $usage 1>&2 ; exit 1
+    fi
+    DIR=$2 ; shift ; shift
+fi
+if [ $# -ne 1 ]; then
+    echo $usage 1>&2 ; exit 1
+fi
+
+ROOT=`echo $1 | sed -e s/.et$//`
+BASE=`echo $ROOT | sed -e 's;.*/;;'`
+
+set -ex
+$AWK -f ${DIR}/et_h.awk outfile=${BASE}.h $ROOT.et
+$AWK -f ${DIR}/et_c.awk outfile=${BASE}.c $ROOT.et
diff --git a/mechglue/src/util/et/compiler.h b/mechglue/src/util/et/compiler.h
new file mode 100644
index 000000000..3e23f1296
--- /dev/null
+++ b/mechglue/src/util/et/compiler.h
@@ -0,0 +1,14 @@
+/*
+ * definitions common to the source files of the error table compiler
+ */
+
+enum lang {
+    lang_C,			/* ANSI C (default) */
+    lang_KRC,			/* C: ANSI + K&R */
+    lang_CPP			/* C++ */
+};
+
+int debug;			/* dump debugging info? */
+char *filename;			/* error table source */
+enum lang language;
+const char *whoami;
diff --git a/mechglue/src/util/et/config_script b/mechglue/src/util/et/config_script
new file mode 100755
index 000000000..ee3bb2702
--- /dev/null
+++ b/mechglue/src/util/et/config_script
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# This program takes a shell script and configures for the following
+# variables:	@DIR@
+#		@AWK@
+#		@SED@
+#
+# Usage: config_script <filename> [<dir>] [<awk>] [<sed>]
+#
+
+FILE=$1
+DIR=$2
+AWK=$3
+SED=$4
+
+if test "${AWK}x" = "x" ; then
+	AWK=awk
+fi
+if test "${SED}x" = "x" ; then
+	SED=sed
+fi
+sed -e "s;@DIR@;${DIR};" -e "s;@AWK@;${AWK};" -e "s;@SED@;${SED};" $FILE
diff --git a/mechglue/src/util/et/configure.in b/mechglue/src/util/et/configure.in
new file mode 100644
index 000000000..e6a51f99a
--- /dev/null
+++ b/mechglue/src/util/et/configure.in
@@ -0,0 +1,27 @@
+K5_AC_INIT(error_table.y)
+CONFIG_RULES
+AC_C_CONST
+AC_PROG_LEX
+AC_PROG_YACC
+AC_PROG_AWK
+HAVE_YYLINENO
+DECLARE_SYS_ERRLIST
+dnl
+dnl Fancy caching of perror result...
+AC_MSG_CHECKING(for perror declaration)
+AC_CACHE_VAL(krb5_cv_decl_perror,
+[AC_EGREP_HEADER(perror, errno.h, 
+  krb5_cv_decl_perror=yes, krb5_cv_decl_perror=no)])dnl
+AC_MSG_RESULT($krb5_cv_decl_perror)
+if test $krb5_cv_decl_perror = yes; then
+	AC_DEFINE(HDR_HAS_PERROR)
+fi
+dnl
+AC_CHECK_FUNCS(strerror)
+AC_HEADER_STDARG
+AC_CHECK_HEADERS(stdlib.h)
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_LIBRARY_WITH_DEPS
+KRB5_BUILD_PROGRAM dnl for test programs
+KRB5_RUN_FLAGS dnl for test programs
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/util/et/error_message.c b/mechglue/src/util/et/error_message.c
new file mode 100644
index 000000000..b7f8947d2
--- /dev/null
+++ b/mechglue/src/util/et/error_message.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright 1997,2000,2001,2004 by Massachusetts Institute of Technology
+ * 
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+ * used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. and the M.I.T. S.I.P.B. make no representations about
+ * the suitability of this software for any purpose.  It is
+ * provided "as is" without express or implied warranty.
+ */
+
+#include "autoconf.h"
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include "com_err.h"
+#include "error_table.h"
+#include "k5-platform.h"
+
+#if !defined(HAVE_STRERROR) && !defined(SYS_ERRLIST_DECLARED)
+extern char const * const sys_errlist[];
+extern const int sys_nerr;
+#endif
+
+/*@null@*/ static struct et_list * _et_list = (struct et_list *) NULL;
+/*@null@*//*@only@*/static struct dynamic_et_list * et_list_dynamic;
+static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+static int terminated = 0;	/* for debugging shlib fini sequence errors */
+
+MAKE_INIT_FUNCTION(com_err_initialize);
+MAKE_FINI_FUNCTION(com_err_terminate);
+
+int com_err_initialize(void)
+{
+    int err;
+#ifdef SHOW_INITFINI_FUNCS
+    printf("com_err_initialize\n");
+#endif
+    terminated = 0;
+    err = k5_mutex_finish_init(&et_list_lock);
+    if (err)
+	return err;
+    err = k5_mutex_finish_init(&com_err_hook_lock);
+    if (err)
+	return err;
+    err = k5_key_register(K5_KEY_COM_ERR, free);
+    if (err)
+	return err;
+    return 0;
+}
+
+void com_err_terminate(void)
+{
+    struct dynamic_et_list *e, *enext;
+    if (! INITIALIZER_RAN(com_err_initialize) || PROGRAM_EXITING()) {
+#ifdef SHOW_INITFINI_FUNCS
+	printf("com_err_terminate: skipping\n");
+#endif
+	return;
+    }
+#ifdef SHOW_INITFINI_FUNCS
+    printf("com_err_terminate\n");
+#endif
+    k5_key_delete(K5_KEY_COM_ERR);
+    k5_mutex_destroy(&com_err_hook_lock);
+    k5_mutex_lock(&et_list_lock);
+    for (e = et_list_dynamic; e; e = enext) {
+	enext = e->next;
+	free(e);
+    }
+    k5_mutex_unlock(&et_list_lock);
+    k5_mutex_destroy(&et_list_lock);
+    terminated = 1;
+}
+
+#ifndef DEBUG_TABLE_LIST
+#define dprintf(X)
+#else
+#define dprintf(X) printf X
+#endif
+
+const char * KRB5_CALLCONV
+error_message(long code)
+    /*@modifies internalState@*/
+{
+	unsigned long offset;
+	unsigned long l_offset;
+	struct et_list *et;
+	struct dynamic_et_list *det;
+	unsigned long table_num;
+	int started = 0;
+	unsigned int divisor = 100;
+	char *cp, *cp1;
+	const struct error_table *table;
+	int merr;
+
+	l_offset = (unsigned long)code & ((1<<ERRCODE_RANGE)-1);
+	offset = l_offset;
+	table_num = ((unsigned long)code - l_offset) & ERRCODE_MAX;
+	if (table_num == 0) {
+#ifdef __sgi
+	system_error_code:
+#endif
+		if (code == 0)
+			goto oops;
+
+		/* This could trip if int is 16 bits.  */
+		if ((unsigned long)(int)code != code)
+		    abort ();
+#ifdef HAVE_STRERROR
+		cp = strerror((int) code);
+		if (cp)
+			return cp;
+		goto oops;
+#else
+#ifdef HAVE_SYS_ERRLIST
+		if (offset < sys_nerr)
+			return(sys_errlist[offset]);
+		else
+			goto oops;
+#else
+		goto oops;
+#endif /* HAVE_SYS_ERRLIST */
+#endif /* HAVE_STRERROR */
+	}
+#ifdef __sgi
+	/* Irix 6.5 uses a much bigger table than other UNIX systems
+	   I've looked at, but the table is sparse.  The sparse
+	   entries start around 500, but sys_nerr is only 152.  */
+	if (code > 0 && code <= 1600)
+	    goto system_error_code;
+#endif
+
+	if (CALL_INIT_FUNCTION(com_err_initialize))
+	    return 0;
+	merr = k5_mutex_lock(&et_list_lock);
+	if (merr)
+	    goto oops;
+	dprintf (("scanning static list for %x\n", table_num));
+	for (et = _et_list; et != NULL; et = et->next) {
+	    if (et->table == NULL)
+		continue;
+	    dprintf (("\t%x = %s\n", et->table->base & ERRCODE_MAX,
+		      et->table->msgs[0]));
+	    if ((et->table->base & ERRCODE_MAX) == table_num) {
+		table = et->table;
+		goto found;
+	    }
+	}
+	dprintf (("scanning dynamic list for %x\n", table_num));
+	for (det = et_list_dynamic; det != NULL; det = det->next) {
+	    dprintf (("\t%x = %s\n", det->table->base & ERRCODE_MAX,
+		      det->table->msgs[0]));
+	    if ((det->table->base & ERRCODE_MAX) == table_num) {
+		table = det->table;
+		goto found;
+	    }
+	}
+	goto no_table_found;
+
+ found:
+	k5_mutex_unlock(&et_list_lock);
+	dprintf (("found it!\n"));
+	/* This is the right table */
+
+	/* This could trip if int is 16 bits.  */
+	if ((unsigned long)(unsigned int)offset != offset)
+	    goto no_table_found;
+
+	if (table->n_msgs <= (unsigned int) offset)
+	    goto no_table_found;
+
+	return table->msgs[offset];
+
+ no_table_found:
+	k5_mutex_unlock(&et_list_lock);
+#if defined(_WIN32)
+	/*
+	 * WinSock errors exist in the 10000 and 11000 ranges
+	 * but might not appear if WinSock is not initialized
+	 */
+	if (code >= WSABASEERR && code < WSABASEERR + 1100) {
+		table_num = 0;
+		offset = code;
+		divisor = WSABASEERR;
+	}
+#endif
+#ifdef _WIN32	
+	{
+		LPVOID msgbuf;
+
+		if (! FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+				     NULL /* lpSource */,
+				     (DWORD) code,
+				     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+				     (LPTSTR) &msgbuf,
+				     (DWORD) 0 /*sizeof(buffer)*/,
+				     NULL /* va_list */ )) {
+			/*
+			 * WinSock errors exist in the 10000 and 11000 ranges
+			 * but might not appear if WinSock is not initialized
+			 */
+			if (code >= WSABASEERR && code < WSABASEERR + 1100) {
+			    table_num = 0;
+			    offset = code;
+			    divisor = 10000;
+			}
+
+			goto oops;
+		} else {
+			char *buffer;
+			cp = k5_getspecific(K5_KEY_COM_ERR);
+			if (cp == NULL) {
+			    cp = malloc(ET_EBUFSIZ);
+			    if (cp == NULL) {
+			    win32_no_specific:
+				return "Unknown error code";
+			    }
+			    if (k5_setspecific(K5_KEY_COM_ERR, cp) != 0) {
+				free(cp);
+				goto win32_no_specific;
+			    }
+			}
+			buffer = cp;
+			strncpy(buffer, msgbuf, ET_EBUFSIZ);
+			buffer[ET_EBUFSIZ-1] = '\0';
+			cp = buffer + strlen(buffer) - 1;
+			if (*cp == '\n') *cp-- = '\0';
+			if (*cp == '\r') *cp-- = '\0';
+			if (*cp == '.') *cp-- = '\0';
+
+			LocalFree(msgbuf);
+			return buffer;
+		}
+	}
+#endif
+
+oops:
+
+#if TARGET_OS_MAC
+	{
+		/* ComErr doesn't know about this error, ask the system */
+		/* Of course there's no way to tell if it knew what error it got */
+		return (strerror (code));
+	}
+#endif
+
+	cp = k5_getspecific(K5_KEY_COM_ERR);
+	if (cp == NULL) {
+	    cp = malloc(ET_EBUFSIZ);
+	    if (cp == NULL) {
+	    no_specific:
+		return "Unknown error code";
+	    }
+	    if (k5_setspecific(K5_KEY_COM_ERR, cp) != 0) {
+		free(cp);
+		goto no_specific;
+	    }
+	}
+	cp1 = cp;
+	strcpy(cp, "Unknown code ");
+	cp += sizeof("Unknown code ") - 1;
+	if (table_num != 0L) {
+		(void) error_table_name_r(table_num, cp);
+		while (*cp != '\0')
+			cp++;
+		*cp++ = ' ';
+	}
+	while (divisor > 1) {
+	    if (started != 0 || offset >= divisor) {
+		*cp++ = '0' + offset / divisor;
+		offset %= divisor;
+		started++;
+	    }
+	    divisor /= 10;
+	}
+	*cp++ = '0' + offset;
+	*cp = '\0';
+	return(cp1);
+}
+
+/*@-incondefs@*/ /* _et_list is global on unix but not in header annotations */
+errcode_t KRB5_CALLCONV
+add_error_table(/*@dependent@*/ const struct error_table * et)
+     /*@modifies _et_list,et_list_dynamic@*/
+/*@=incondefs@*/
+{
+    struct dynamic_et_list *del;
+    int merr;
+
+    if (CALL_INIT_FUNCTION(com_err_initialize))
+	return 0;
+
+    del = (struct dynamic_et_list *)malloc(sizeof(struct dynamic_et_list));
+    if (del == NULL)
+	return errno;
+
+    del->table = et;
+
+    merr = k5_mutex_lock(&et_list_lock);
+    if (merr) {
+	free(del);
+	return merr;
+    }
+    del->next = et_list_dynamic;
+    et_list_dynamic = del;
+    return k5_mutex_unlock(&et_list_lock);
+}
+
+/*@-incondefs@*/ /* _et_list is global on unix but not in header annotations */
+errcode_t KRB5_CALLCONV
+remove_error_table(const struct error_table * et)
+     /*@modifies _et_list,et_list_dynamic@*/
+/*@=incondefs@*/
+{
+    struct dynamic_et_list **del;
+    struct et_list **el;
+    int merr;
+
+    if (CALL_INIT_FUNCTION(com_err_initialize))
+	return 0;
+#if !defined(ENABLE_THREADS) && defined(DEBUG_THREADS)
+    if (et_list_lock.os.initialized == 0 && terminated != 0) {
+	fprintf(stderr, "\n\n *** Function remove_error_table called after com_err library termination. ***\n *** Shared library termination code executed in incorrect order?          ***\n\n");
+	abort();
+    }
+#endif
+    merr = k5_mutex_lock(&et_list_lock);
+    if (merr)
+	return merr;
+
+    /* Remove the first occurrance we can find.  Prefer dynamic
+       entries, but if there are none, check for a static one too.  */
+    for (del = &et_list_dynamic; *del; del = &(*del)->next)
+	if ((*del)->table->base == et->base) {
+	    /*@only@*/ struct dynamic_et_list *old = *del;
+	    *del = old->next;
+	    free (old);
+	    return k5_mutex_unlock(&et_list_lock);
+	}
+    for (el = &_et_list; *el; el = &(*el)->next)
+	if ((*el)->table != NULL && (*el)->table->base == et->base) {
+	    struct et_list *old = *el;
+	    *el = old->next;
+	    old->next = NULL;
+	    old->table = NULL;
+	    return k5_mutex_unlock(&et_list_lock);
+	}
+    k5_mutex_unlock(&et_list_lock);
+    return ENOENT;
+}
+
+int com_err_finish_init()
+{
+    return CALL_INIT_FUNCTION(com_err_initialize);
+}
diff --git a/mechglue/src/util/et/error_table.h b/mechglue/src/util/et/error_table.h
new file mode 100644
index 000000000..ea804cf00
--- /dev/null
+++ b/mechglue/src/util/et/error_table.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1988 by the Student Information Processing Board of the
+ * Massachusetts Institute of Technology.
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+
+#ifndef _ET_H
+
+#include <errno.h>
+
+#define ET_EBUFSIZ 64
+
+struct et_list {
+    /*@dependent@*//*@null@*/ struct et_list *next;
+    /*@dependent@*//*@null@*/ const struct error_table *table;
+};
+
+struct dynamic_et_list {
+    /*@only@*//*@null@*/ struct dynamic_et_list *next;
+    /*@dependent@*/ const struct error_table *table;
+};
+
+#define	ERRCODE_RANGE	8	/* # of bits to shift table number */
+#define	BITS_PER_CHAR	6	/* # bits to shift per character in name */
+#define ERRCODE_MAX   0xFFFFFFFFUL      /* Mask for maximum error table */
+
+extern /*@observer@*/ const char *error_table_name (unsigned long)
+     /*@modifies internalState@*/;
+extern const char *error_table_name_r (unsigned long,
+					   /*@out@*/ /*@returned@*/ char *outbuf)
+     /*@modifies outbuf@*/;
+
+#include "k5-thread.h"
+extern k5_mutex_t com_err_hook_lock;
+extern int com_err_finish_init(void);
+
+#define _ET_H
+#endif
diff --git a/mechglue/src/util/et/error_table.y b/mechglue/src/util/et/error_table.y
new file mode 100644
index 000000000..f6b082fd4
--- /dev/null
+++ b/mechglue/src/util/et/error_table.y
@@ -0,0 +1,231 @@
+%{
+#include <stdio.h>
+char *str_concat(), *ds(), *quote();
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+char *current_token = (char *)NULL;
+extern char *table_name;
+%}
+%union {
+	char *dynstr;
+}
+
+%token ERROR_TABLE ERROR_CODE_ENTRY END
+%token <dynstr> STRING QUOTED_STRING
+%type <dynstr> ec_name description table_id
+%{
+%}
+%start error_table
+%%
+
+error_table	:	ERROR_TABLE table_id error_codes END
+			{ table_name = ds($2);
+			  current_token = table_name;
+			  put_ecs(); }
+		;
+
+table_id	:	STRING
+			{ current_token = $1;
+			  set_table_num($1);
+			  $$ = $1; }
+		;
+
+error_codes	:	error_codes ec_entry
+		|	ec_entry
+		;
+
+ec_entry	:	ERROR_CODE_ENTRY ec_name ',' description
+			{ add_ec($2, $4);
+			  free($2);
+			  free($4); }
+		|	ERROR_CODE_ENTRY ec_name '=' STRING ',' description
+			{ add_ec_val($2, $4, $6);
+			  free($2);
+			  free($4);
+			  free($6);
+			}
+		;
+
+ec_name		:	STRING
+			{ $$ = ds($1);
+			  current_token = $$; }
+		;
+
+description	:	QUOTED_STRING
+			{ $$ = ds($1);
+			  current_token = $$; }
+		;
+
+%%
+/*
+ *
+ * Copyright 1986, 1987 by the MIT Student Information Processing Board
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "com_err.h"
+#include "internal.h"
+#include "error_table.h"
+#include "mit-sipb-copyright.h"
+
+
+extern FILE *hfile, *cfile;
+
+static long gensym_n = 0;
+char *
+gensym(x)
+	char const *x;
+{
+	char *symbol;
+	if (!gensym_n) {
+		struct timeval tv;
+		struct timezone tzp;
+		gettimeofday(&tv, &tzp);
+		gensym_n = (tv.tv_sec%10000)*100 + tv.tv_usec/10000;
+	}
+	symbol = malloc(32 * sizeof(char));
+	gensym_n++;
+	sprintf(symbol, "et%ld", gensym_n);
+	return(symbol);
+}
+
+char *
+ds(string)
+	char const *string;
+{
+	char *rv;
+	rv = malloc(strlen(string)+1);
+	strcpy(rv, string);
+	return(rv);
+}
+
+char *
+quote(string)
+	char const *string;
+{
+	char *rv;
+	rv = malloc(strlen(string)+3);
+	strcpy(rv, "\"");
+	strcat(rv, string);
+	strcat(rv, "\"");
+	return(rv);
+}
+
+long table_number;
+int current = 0;
+char **error_codes = (char **)NULL;
+
+add_ec(name, description)
+	char const *name, *description;
+{
+	fprintf(cfile, "\t\"%s\",\n", description);
+	if (error_codes == (char **)NULL) {
+		error_codes = (char **)malloc(sizeof(char *));
+		*error_codes = (char *)NULL;
+	}
+	error_codes = (char **)realloc((char *)error_codes,
+				       (current + 2)*sizeof(char *));
+	error_codes[current++] = ds(name);
+	error_codes[current] = (char *)NULL;
+}
+
+add_ec_val(name, val, description)
+	char const *name, *val, *description;
+{
+	const int ncurrent = atoi(val);
+	if (ncurrent < current) {
+		printf("Error code %s (%d) out of order", name,
+		       current);
+		return;
+	}
+      
+	while (ncurrent > current)
+	     fputs("\t(char *)NULL,\n", cfile), current++;
+	
+	fprintf(cfile, "\t\"%s\",\n", description);
+	if (error_codes == (char **)NULL) {
+		error_codes = (char **)malloc(sizeof(char *));
+		*error_codes = (char *)NULL;
+	}
+	error_codes = (char **)realloc((char *)error_codes,
+				       (current + 2)*sizeof(char *));
+	error_codes[current++] = ds(name);
+	error_codes[current] = (char *)NULL;
+} 
+
+put_ecs()
+{
+	int i;
+	for (i = 0; i < current; i++) {
+	     if (error_codes[i] != (char *)NULL)
+		  fprintf(hfile, "#define %-40s (%ldL)\n",
+			  error_codes[i], table_number + i);
+	}
+}
+
+/*
+ * char_to_num -- maps letters and numbers into a small numbering space
+ * 	uppercase ->  1-26
+ *	lowercase -> 27-52
+ *	digits    -> 53-62
+ *	underscore-> 63
+ */
+
+static const char char_set[] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
+int char_to_num(c)
+	char c;
+{
+	const char *where;
+	int diff;
+
+	where = strchr (char_set, c);
+	if (where) {
+		diff = where - char_set + 1;
+		assert (diff < (1 << ERRCODE_RANGE));
+		return diff;
+	}
+	else if (isprint (c))
+		fprintf (stderr,
+			 "Illegal character `%c' in error table name\n",
+			 c);
+	else
+		fprintf (stderr,
+			 "Illegal character %03o in error table name\n",
+			 c);
+	exit (1);
+}
+
+set_table_num(string)
+	char *string;
+{
+	if (char_to_num (string[0]) > char_to_num ('z')) {
+		fprintf (stderr, "%s%s%s%s",
+			 "First character of error table name must be ",
+			 "a letter; name ``",
+			 string, "'' rejected\n");
+		exit (1);
+	}
+	if (strlen(string) > 4) {
+		fprintf(stderr, "Table name %s too long, truncated ",
+			string);
+		string[4] = '\0';
+		fprintf(stderr, "to %s\n", string);
+	}
+	while (*string != '\0') {
+		table_number = (table_number << BITS_PER_CHAR)
+			+ char_to_num(*string);
+		string++;
+	}
+	table_number = table_number << ERRCODE_RANGE;
+}
+
+#include "et_lex.lex.c"
diff --git a/mechglue/src/util/et/et.exp b/mechglue/src/util/et/et.exp
new file mode 100644
index 000000000..00e15a2df
--- /dev/null
+++ b/mechglue/src/util/et/et.exp
@@ -0,0 +1,8 @@
+#
+# comerr library Macintosh export file
+#
+# $Header$
+
+error_message
+add_error_table
+remove_error_table
diff --git a/mechglue/src/util/et/et.pbexp b/mechglue/src/util/et/et.pbexp
new file mode 100644
index 000000000..31097615a
--- /dev/null
+++ b/mechglue/src/util/et/et.pbexp
@@ -0,0 +1,10 @@
+#
+# comerr library Macintosh export file
+#
+# $Header$
+
+_com_err
+_com_err_va
+_error_message
+_add_error_table
+_remove_error_table
diff --git a/mechglue/src/util/et/et1.et b/mechglue/src/util/et/et1.et
new file mode 100644
index 000000000..71c4e6c59
--- /dev/null
+++ b/mechglue/src/util/et/et1.et
@@ -0,0 +1,11 @@
+	error_table et1
+
+ec	ET1_M0, "error table 1 message 0"
+
+ec	ET1_M1,
+	"error table 1 message 1"
+
+error_code ET1_M2,
+	"error table 1 message 2"
+
+end
diff --git a/mechglue/src/util/et/et2.et b/mechglue/src/util/et/et2.et
new file mode 100644
index 000000000..4425f047a
--- /dev/null
+++ b/mechglue/src/util/et/et2.et
@@ -0,0 +1,11 @@
+	error_table et2
+
+ec	ET2_M0, "error table 2 message 0"
+
+ec	ET2_M1,
+	"error table 2 message 1"
+
+error_code ET2_M2,
+	"error table 2 message 2"
+
+end
diff --git a/mechglue/src/util/et/et_c.awk b/mechglue/src/util/et/et_c.awk
new file mode 100644
index 000000000..cc277f5dc
--- /dev/null
+++ b/mechglue/src/util/et/et_c.awk
@@ -0,0 +1,213 @@
+BEGIN { 
+char_shift=64
+## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+c2n["A"]=1
+c2n["B"]=2
+c2n["C"]=3
+c2n["D"]=4
+c2n["E"]=5
+c2n["F"]=6
+c2n["G"]=7
+c2n["H"]=8
+c2n["I"]=9
+c2n["J"]=10
+c2n["K"]=11
+c2n["L"]=12
+c2n["M"]=13
+c2n["N"]=14
+c2n["O"]=15
+c2n["P"]=16
+c2n["Q"]=17
+c2n["R"]=18
+c2n["S"]=19
+c2n["T"]=20
+c2n["U"]=21
+c2n["V"]=22
+c2n["W"]=23
+c2n["X"]=24
+c2n["Y"]=25
+c2n["Z"]=26
+c2n["a"]=27
+c2n["b"]=28
+c2n["c"]=29
+c2n["d"]=30
+c2n["e"]=31
+c2n["f"]=32
+c2n["g"]=33
+c2n["h"]=34
+c2n["i"]=35
+c2n["j"]=36
+c2n["k"]=37
+c2n["l"]=38
+c2n["m"]=39
+c2n["n"]=40
+c2n["o"]=41
+c2n["p"]=42
+c2n["q"]=43
+c2n["r"]=44
+c2n["s"]=45
+c2n["t"]=46
+c2n["u"]=47
+c2n["v"]=48
+c2n["w"]=49
+c2n["x"]=50
+c2n["y"]=51
+c2n["z"]=52
+c2n["0"]=53
+c2n["1"]=54
+c2n["2"]=55
+c2n["3"]=56
+c2n["4"]=57
+c2n["5"]=58
+c2n["6"]=59
+c2n["7"]=60
+c2n["8"]=61
+c2n["9"]=62
+c2n["_"]=63
+}
+/^#/ { next }
+/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ {
+	table_number = 0
+	table_name = $2
+	mod_base = 1000000
+	for(i=1; i<=length(table_name); i++) {
+	    table_number=(table_number*char_shift)+c2n[substr(table_name,i,1)]
+	}
+
+	# We start playing *_high, *low games here because the some
+	# awk programs do not have the necessary precision (sigh)
+	tab_base_low = table_number % mod_base
+	tab_base_high = int(table_number / mod_base)
+	tab_base_sign = 1;
+
+	# figure out: table_number_base=table_number*256
+	tab_base_low = tab_base_low * 256
+	tab_base_high = (tab_base_high * 256) + \
+			int(tab_base_low / mod_base)
+	tab_base_low = tab_base_low % mod_base
+
+	if (table_number > 128*256*256) {
+		# figure out:  table_number_base -= 256*256*256*256
+		# sub_high, sub_low is 256*256*256*256
+		sub_low = 256*256*256 % mod_base
+		sub_high = int(256*256*256 / mod_base)
+
+		sub_low = sub_low * 256
+		sub_high = (sub_high * 256) + int(sub_low / mod_base)
+		sub_low = sub_low % mod_base
+
+		tab_base_low = sub_low - tab_base_low;
+		tab_base_high = sub_high - tab_base_high;
+		tab_base_sign = -1;
+		if (tab_base_low < 0) {
+			tab_base_low = tab_base_low + mod_base
+			tab_base_high--
+		}
+	}
+	print "/*" > outfile
+	print " * " outfile ":" > outfile
+	print " * This file is automatically generated; please do not edit it." > outfile
+	print " */" > outfile
+
+	print "#if defined(_WIN32)" > outfile
+	print "# include \"win-mac.h\"" > outfile
+	print "#endif" > outfile
+	print "" > outfile
+	print "#if !defined(_WIN32)" > outfile
+	print "extern void initialize_" table_name "_error_table (void);" > outfile
+	print "#endif" > outfile
+	print "" > outfile
+	print "/* Lclint doesn't handle null annotations on arrays" > outfile
+	print "   properly, so we need this typedef in each" > outfile
+	print "   generated .c file.  */" > outfile
+	print "/*@-redef@*/" > outfile
+	print "typedef /*@null@*/ const char *ncptr;" > outfile
+	print "/*@=redef@*/" > outfile
+	print "" > outfile
+	print "static ncptr const text[] = {" > outfile
+	table_item_count = 0
+}
+
+(continuation == 1) && ($0 ~ /\\[ \t]*$/) {
+	text=substr($0,1,length($0)-1);
+#	printf "\t\t\"%s\"\n", text > outfile
+	cont_buf=cont_buf text;
+}
+
+(continuation == 1) && ($0 ~ /"[ \t]*$/) {
+#	printf "\t\t\"%s,\n", $0 > outfile
+	printf "\t%s,\n", cont_buf $0 > outfile
+	continuation = 0;
+}
+
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*$/ {
+	table_item_count++
+	skipone=1
+	next
+}
+
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*"[ \t]*$/ {
+	text=""
+	for (i=3; i<=NF; i++) { 
+	    text = text FS $i
+	}
+	text=substr(text,2,length(text)-1);
+	printf "\t%s,\n", text > outfile
+	table_item_count++
+}
+
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*\\[ \t]*$/ {
+	text=""
+	for (i=3; i<=NF; i++) { 
+	    text = text FS $i
+	}
+	text=substr(text,2,length(text)-2);
+#	printf "\t%s\"\n", text > outfile
+	cont_buf=text
+	continuation++;
+}
+
+/^[ \t]*".*\\[ \t]*$/ {
+	if (skipone) {
+	    text=substr($0,1,length($0)-1);
+#	    printf "\t%s\"\n", text > outfile
+	    cont_buf=text
+	    continuation++;
+	}
+	skipone=0
+}
+
+{ 
+	if (skipone) {
+	    printf "\t%s,\n", $0 > outfile
+	}
+	skipone=0
+}
+END {
+	if (table_item_count > 256) {
+	    print "Error table too large!" | "cat 1>&2"
+	    exit 1
+	}
+	print "    0" > outfile
+	print "};" > outfile
+	print "" > outfile
+	print "#include <com_err.h>" > outfile
+	print "" > outfile
+	if (tab_base_high == 0) {
+	    print "const struct error_table et_" table_name "_error_table = { text, " \
+		sprintf("%dL, %d };", tab_base_sign*tab_base_low, \
+		table_item_count) > outfile
+	} else {
+	    print "const struct error_table et_" table_name "_error_table = { text, " \
+		sprintf("%d%06dL, %d };", tab_base_sign*tab_base_high, \
+		tab_base_low, table_item_count) > outfile
+	}
+	print "" > outfile
+	print "#if !defined(_WIN32)" > outfile
+	print "void initialize_" table_name "_error_table (void)" > outfile
+	print "    /*@modifies internalState@*/" > outfile
+	print "{" > outfile
+	print "    (void) add_error_table (&et_" table_name "_error_table);" > outfile
+	print "}" > outfile
+	print "#endif" > outfile
+}
diff --git a/mechglue/src/util/et/et_c.pl b/mechglue/src/util/et/et_c.pl
new file mode 100644
index 000000000..a845eb0f8
--- /dev/null
+++ b/mechglue/src/util/et/et_c.pl
@@ -0,0 +1,289 @@
+eval 'exec /usr/athena/bin/perl -S $0 ${1+"$@"}'
+    if $running_under_some_shell;
+			# this emulates #! processing on NIH machines.
+			# (remove #! line above if indigestible)
+
+eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;
+			# process any FOO=bar switches
+
+$[ = 1;			# set array base to 1
+$FS = ' ';		# set field separator
+$, = ' ';		# set output field separator
+$\ = "\n";		# set output record separator
+
+$char_shift = 64;
+## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+$c2n{'A'} = 1;
+$c2n{'B'} = 2;
+$c2n{'C'} = 3;
+$c2n{'D'} = 4;
+$c2n{'E'} = 5;
+$c2n{'F'} = 6;
+$c2n{'G'} = 7;
+$c2n{'H'} = 8;
+$c2n{'I'} = 9;
+$c2n{'J'} = 10;
+$c2n{'K'} = 11;
+$c2n{'L'} = 12;
+$c2n{'M'} = 13;
+$c2n{'N'} = 14;
+$c2n{'O'} = 15;
+$c2n{'P'} = 16;
+$c2n{'Q'} = 17;
+$c2n{'R'} = 18;
+$c2n{'S'} = 19;
+$c2n{'T'} = 20;
+$c2n{'U'} = 21;
+$c2n{'V'} = 22;
+$c2n{'W'} = 23;
+$c2n{'X'} = 24;
+$c2n{'Y'} = 25;
+$c2n{'Z'} = 26;
+$c2n{'a'} = 27;
+$c2n{'b'} = 28;
+$c2n{'c'} = 29;
+$c2n{'d'} = 30;
+$c2n{'e'} = 31;
+$c2n{'f'} = 32;
+$c2n{'g'} = 33;
+$c2n{'h'} = 34;
+$c2n{'i'} = 35;
+$c2n{'j'} = 36;
+$c2n{'k'} = 37;
+$c2n{'l'} = 38;
+$c2n{'m'} = 39;
+$c2n{'n'} = 40;
+$c2n{'o'} = 41;
+$c2n{'p'} = 42;
+$c2n{'q'} = 43;
+$c2n{'r'} = 44;
+$c2n{'s'} = 45;
+$c2n{'t'} = 46;
+$c2n{'u'} = 47;
+$c2n{'v'} = 48;
+$c2n{'w'} = 49;
+$c2n{'x'} = 50;
+$c2n{'y'} = 51;
+$c2n{'z'} = 52;
+$c2n{'0'} = 53;
+$c2n{'1'} = 54;
+$c2n{'2'} = 55;
+$c2n{'3'} = 56;
+$c2n{'4'} = 57;
+$c2n{'5'} = 58;
+$c2n{'6'} = 59;
+$c2n{'7'} = 60;
+$c2n{'8'} = 61;
+$c2n{'9'} = 62;
+$c2n{'_'} = 63;
+
+line: while (<>) {
+    chomp;	# strip record separator
+    @Fld = split($FS, $_, 9999);
+    if (/^#/) {
+	next line;
+    }
+    if (/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/) {
+	$table_number = 0;
+	$table_name = $Fld[2];
+	$mod_base = 1000000;
+	for ($i = 1; $i <= length($table_name); $i++) {
+	    $table_number = ($table_number * $char_shift) +
+
+	      $c2n{substr($table_name, $i, 1)};
+	}
+
+	# We start playing *_high, *low games here because the some
+	# awk programs do not have the necessary precision (sigh)
+	$tab_base_low = $table_number % $mod_base;
+	$tab_base_high = int($table_number / $mod_base);
+	$tab_base_sign = 1;
+
+	# figure out: table_number_base=table_number*256
+	$tab_base_low = $tab_base_low * 256;
+	$tab_base_high = ($tab_base_high * 256) + int($tab_base_low /
+
+	  $mod_base);
+	$tab_base_low = $tab_base_low % $mod_base;
+
+	if ($table_number > 128 * 256 * 256) {
+	    # figure out:  table_number_base -= 256*256*256*256
+	    # sub_high, sub_low is 256*256*256*256
+	    $sub_low = 256 * 256 * 256 % $mod_base;
+	    $sub_high = int(256 * 256 * 256 / $mod_base);
+
+	    $sub_low = $sub_low * 256;
+	    $sub_high = ($sub_high * 256) + int($sub_low / $mod_base);
+	    $sub_low = $sub_low % $mod_base;
+
+	    $tab_base_low = $sub_low - $tab_base_low;
+	    $tab_base_high = $sub_high - $tab_base_high;
+	    $tab_base_sign = -1;
+	    if ($tab_base_low < 0) {
+		$tab_base_low = $tab_base_low + $mod_base;
+		$tab_base_high--;
+	    }
+	}
+	&Pick('>', $outfile) &&
+	    (print $fh '/*');
+	&Pick('>', $outfile) &&
+	    (print $fh ' * ' . $outfile . ':');
+	&Pick('>', $outfile) &&
+	    (print $fh
+
+	      ' * This file is automatically generated; please do not edit it.');
+	&Pick('>', $outfile) &&
+	    (print $fh ' */');
+
+	&Pick('>', $outfile) &&
+	    (print $fh '#if defined(_WIN32)');
+	&Pick('>', $outfile) &&
+	    (print $fh "# include \"win-mac.h\"");
+	&Pick('>', $outfile) &&
+	    (print $fh '#endif');
+	&Pick('>', $outfile) &&
+	    (print $fh '');
+	&Pick('>', $outfile) &&
+	    (print $fh '#if !defined(_WIN32)');
+	&Pick('>', $outfile) &&
+	    (print $fh 'extern void initialize_' . $table_name .
+
+	      '_error_table (void);');
+	&Pick('>', $outfile) &&
+	    (print $fh '#endif');
+	&Pick('>', $outfile) &&
+	    (print $fh '');
+	&Pick('>', $outfile) &&
+	    (print $fh "/* Lclint doesn't handle null annotations on arrays");
+	&Pick('>', $outfile) &&
+	    (print $fh '   properly, so we need this typedef in each');
+	&Pick('>', $outfile) &&
+	    (print $fh '   generated .c file.  */');
+	&Pick('>', $outfile) &&
+	    (print $fh '/*@-redef@*/');
+	&Pick('>', $outfile) &&
+	    (print $fh 'typedef /*@null@*/ const char *ncptr;');
+	&Pick('>', $outfile) &&
+	    (print $fh '/*@=redef@*/');
+	&Pick('>', $outfile) &&
+	    (print $fh '');
+	&Pick('>', $outfile) &&
+	    (print $fh 'static ncptr const text[] = {');
+	$table_item_count = 0;
+    }
+
+    if (($continuation == 1) && ($_ =~ /\\[ \t]*$/)) {
+	$text = substr($_, 1, length($_) - 1);
+	#	printf "\t\t\"%s\"\n", text > outfile
+	$cont_buf = $cont_buf . $text;
+    }
+
+    if (($continuation == 1) && ($_ =~ /"[ \t]*$/)) {
+	#	printf "\t\t\"%s,\n", $0 > outfile
+	&Pick('>', $outfile) &&
+	    (printf $fh "\t%s,\n", $cont_buf . $_);
+	$continuation = 0;
+    }
+
+    if (/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*$/) {
+	$table_item_count++;
+	$skipone = 1;
+	next line;
+    }
+
+    if (/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*"[ \t]*$/) {
+	$text = '';
+	for ($i = 3; $i <= $#Fld; $i++) {
+	    $text = $text . $FS . $Fld[$i];
+	}
+	$text = substr($text, 2, length($text) - 1);
+	&Pick('>', $outfile) &&
+	    (printf $fh "\t%s,\n", $text);
+	$table_item_count++;
+    }
+
+    if (/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,[ \t]*".*\\[ \t]*$/) {
+	$text = '';
+	for ($i = 3; $i <= $#Fld; $i++) {
+	    $text = $text . $FS . $Fld[$i];
+	}
+	$text = substr($text, 2, length($text) - 2);
+	#	printf "\t%s\"\n", text > outfile
+	$cont_buf = $text;
+	$continuation++;
+    }
+
+    if (/^[ \t]*".*\\[ \t]*$/) {
+	if ($skipone) {
+	    $text = substr($_, 1, length($_) - 1);
+	    #	    printf "\t%s\"\n", text > outfile
+	    $cont_buf = $text;
+	    $continuation++;
+	}
+	$skipone = 0;
+    }
+
+    if ($skipone) {
+	&Pick('>', $outfile) &&
+	    (printf $fh "\t%s,\n", $_);
+    }
+    $skipone = 0;
+}
+
+if ($table_item_count > 256) {
+    &Pick('|', 'cat 1>&2') &&
+	(print $fh 'Error table too large!');
+    exit 1;
+}
+&Pick('>', $outfile) &&
+    (print $fh '    0');
+&Pick('>', $outfile) &&
+    (print $fh '};');
+&Pick('>', $outfile) &&
+    (print $fh '');
+&Pick('>', $outfile) &&
+    (print $fh '#include <com_err.h>');
+&Pick('>', $outfile) &&
+    (print $fh '');
+if ($tab_base_high == 0) {
+    &Pick('>', $outfile) &&
+	(print $fh 'const struct error_table et_' . $table_name .
+
+	  '_error_table = { text, ' . sprintf('%dL, %d };',
+
+	  $tab_base_sign * $tab_base_low, $table_item_count));
+}
+else {
+    &Pick('>', $outfile) &&
+	(print $fh 'const struct error_table et_' . $table_name .
+
+	  '_error_table = { text, ' . sprintf('%d%06dL, %d };',
+
+	  $tab_base_sign * $tab_base_high, $tab_base_low, $table_item_count));
+}
+&Pick('>', $outfile) &&
+    (print $fh '');
+&Pick('>', $outfile) &&
+    (print $fh '#if !defined(_WIN32)');
+&Pick('>', $outfile) &&
+    (print $fh 'void initialize_' . $table_name . '_error_table (void)');
+&Pick('>', $outfile) &&
+    (print $fh '    /*@modifies internalState@*/');
+&Pick('>', $outfile) &&
+    (print $fh '{');
+&Pick('>', $outfile) &&
+    (print $fh '    (void) add_error_table (&et_' . $table_name .
+
+      '_error_table);');
+&Pick('>', $outfile) &&
+    (print $fh '}');
+&Pick('>', $outfile) &&
+    (print $fh '#endif');
+
+exit $ExitValue;
+
+sub Pick {
+    local($mode,$name,$pipe) = @_;
+    $fh = $name;
+    open($name,$mode.$name.$pipe) unless $opened{$name}++;
+}
diff --git a/mechglue/src/util/et/et_h.awk b/mechglue/src/util/et/et_h.awk
new file mode 100644
index 000000000..65c6c453f
--- /dev/null
+++ b/mechglue/src/util/et/et_h.awk
@@ -0,0 +1,168 @@
+BEGIN { 
+char_shift=64
+## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+c2n["A"]=1
+c2n["B"]=2
+c2n["C"]=3
+c2n["D"]=4
+c2n["E"]=5
+c2n["F"]=6
+c2n["G"]=7
+c2n["H"]=8
+c2n["I"]=9
+c2n["J"]=10
+c2n["K"]=11
+c2n["L"]=12
+c2n["M"]=13
+c2n["N"]=14
+c2n["O"]=15
+c2n["P"]=16
+c2n["Q"]=17
+c2n["R"]=18
+c2n["S"]=19
+c2n["T"]=20
+c2n["U"]=21
+c2n["V"]=22
+c2n["W"]=23
+c2n["X"]=24
+c2n["Y"]=25
+c2n["Z"]=26
+c2n["a"]=27
+c2n["b"]=28
+c2n["c"]=29
+c2n["d"]=30
+c2n["e"]=31
+c2n["f"]=32
+c2n["g"]=33
+c2n["h"]=34
+c2n["i"]=35
+c2n["j"]=36
+c2n["k"]=37
+c2n["l"]=38
+c2n["m"]=39
+c2n["n"]=40
+c2n["o"]=41
+c2n["p"]=42
+c2n["q"]=43
+c2n["r"]=44
+c2n["s"]=45
+c2n["t"]=46
+c2n["u"]=47
+c2n["v"]=48
+c2n["w"]=49
+c2n["x"]=50
+c2n["y"]=51
+c2n["z"]=52
+c2n["0"]=53
+c2n["1"]=54
+c2n["2"]=55
+c2n["3"]=56
+c2n["4"]=57
+c2n["5"]=58
+c2n["6"]=59
+c2n["7"]=60
+c2n["8"]=61
+c2n["9"]=62
+c2n["_"]=63
+}
+/^#/ { next }
+/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/ {
+	table_number = 0
+	table_name = $2
+	mod_base = 1000000
+	for(i=1; i<=length(table_name); i++) {
+	    table_number=(table_number*char_shift)+c2n[substr(table_name,i,1)]
+	}
+	# We start playing *_high, *low games here because the some
+	# awk programs do not have the necessary precision (sigh)
+	tab_base_low = table_number % mod_base
+	tab_base_high = int(table_number / mod_base)
+	tab_base_sign = 1;
+
+	# figure out: table_number_base=table_number*256
+	tab_base_low = tab_base_low * 256
+	tab_base_high = (tab_base_high * 256) + \
+			int(tab_base_low / mod_base)
+	tab_base_low = tab_base_low % mod_base
+
+	if (table_number > 128*256*256) {
+		# figure out:  table_number_base -= 256*256*256*256
+		# sub_high, sub_low is 256*256*256*256
+		sub_low = 256*256*256 % mod_base
+		sub_high = int(256*256*256 / mod_base)
+
+		sub_low = sub_low * 256
+		sub_high = (sub_high * 256) + int(sub_low / mod_base)
+		sub_low = sub_low % mod_base
+
+		tab_base_low = sub_low - tab_base_low;
+		tab_base_high = sub_high - tab_base_high;
+		tab_base_sign = -1;
+		if (tab_base_low < 0) {
+			tab_base_low = tab_base_low + mod_base
+			tab_base_high--
+		}
+	}
+	curr_low = tab_base_low
+	curr_high = tab_base_high
+	curr_sign = tab_base_sign
+	print "/*" > outfile
+	print " * " outfile ":" > outfile
+	print " * This file is automatically generated; please do not edit it." > outfile
+	print " */" > outfile
+	print "" > outfile
+	print "#include <com_err.h>" > outfile
+	print "" > outfile
+	table_item_count = 0
+}
+
+/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,/ {
+	tag=substr($2,1,length($2)-1)
+	if (curr_high == 0) {
+		printf "#define %-40s (%dL)\n", tag, \
+			curr_sign*curr_low > outfile
+	} else {
+		printf "#define %-40s (%d%06dL)\n", tag, curr_high*curr_sign, \
+			curr_low > outfile
+	}
+	curr_low += curr_sign;
+	if (curr_low >= mod_base) {
+		curr_low -= mod_base;
+		curr_high++
+	}
+	if (curr_low < 0) {
+		cur_low += mod_base
+		cur_high--
+	}
+}
+
+END {
+	if (table_item_count > 256) {
+	    print "Error table too large!" | "cat 1>&2"
+	    exit 1
+	}
+	if (tab_base_high == 0) {
+		print "#define ERROR_TABLE_BASE_" table_name " (" \
+			sprintf("%d", tab_base_sign*tab_base_low) \
+			"L)" > outfile
+	} else {
+		print "#define ERROR_TABLE_BASE_" table_name " (" \
+			sprintf("%d%06d", tab_base_sign*tab_base_high, \
+			tab_base_low) "L)" > outfile
+	}
+	print "" > outfile
+	print "extern const struct error_table et_" table_name "_error_table;" > outfile
+	print "" > outfile
+	print "#if !defined(_WIN32)" > outfile
+	print "/* for compatibility with older versions... */" > outfile
+	print "extern void initialize_" table_name "_error_table (void) /*@modifies internalState@*/;" > outfile
+	print "#else" > outfile
+	print "#define initialize_" table_name "_error_table()" > outfile
+	print "#endif" > outfile
+	print "" > outfile
+	print "#if !defined(_WIN32)" > outfile
+	print "#define init_" table_name "_err_tbl initialize_" table_name "_error_table" > outfile
+	print "#define " table_name "_err_base ERROR_TABLE_BASE_" table_name > outfile
+	print "#endif" > outfile
+}
+
diff --git a/mechglue/src/util/et/et_h.pl b/mechglue/src/util/et/et_h.pl
new file mode 100644
index 000000000..5ab8e8b46
--- /dev/null
+++ b/mechglue/src/util/et/et_h.pl
@@ -0,0 +1,234 @@
+eval 'exec /usr/athena/bin/perl -S $0 ${1+"$@"}'
+    if $running_under_some_shell;
+			# this emulates #! processing on NIH machines.
+			# (remove #! line above if indigestible)
+
+eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;
+			# process any FOO=bar switches
+
+$[ = 1;			# set array base to 1
+$, = ' ';		# set output field separator
+$\ = "\n";		# set output record separator
+
+$char_shift = 64;
+## "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+$c2n{'A'} = 1;
+$c2n{'B'} = 2;
+$c2n{'C'} = 3;
+$c2n{'D'} = 4;
+$c2n{'E'} = 5;
+$c2n{'F'} = 6;
+$c2n{'G'} = 7;
+$c2n{'H'} = 8;
+$c2n{'I'} = 9;
+$c2n{'J'} = 10;
+$c2n{'K'} = 11;
+$c2n{'L'} = 12;
+$c2n{'M'} = 13;
+$c2n{'N'} = 14;
+$c2n{'O'} = 15;
+$c2n{'P'} = 16;
+$c2n{'Q'} = 17;
+$c2n{'R'} = 18;
+$c2n{'S'} = 19;
+$c2n{'T'} = 20;
+$c2n{'U'} = 21;
+$c2n{'V'} = 22;
+$c2n{'W'} = 23;
+$c2n{'X'} = 24;
+$c2n{'Y'} = 25;
+$c2n{'Z'} = 26;
+$c2n{'a'} = 27;
+$c2n{'b'} = 28;
+$c2n{'c'} = 29;
+$c2n{'d'} = 30;
+$c2n{'e'} = 31;
+$c2n{'f'} = 32;
+$c2n{'g'} = 33;
+$c2n{'h'} = 34;
+$c2n{'i'} = 35;
+$c2n{'j'} = 36;
+$c2n{'k'} = 37;
+$c2n{'l'} = 38;
+$c2n{'m'} = 39;
+$c2n{'n'} = 40;
+$c2n{'o'} = 41;
+$c2n{'p'} = 42;
+$c2n{'q'} = 43;
+$c2n{'r'} = 44;
+$c2n{'s'} = 45;
+$c2n{'t'} = 46;
+$c2n{'u'} = 47;
+$c2n{'v'} = 48;
+$c2n{'w'} = 49;
+$c2n{'x'} = 50;
+$c2n{'y'} = 51;
+$c2n{'z'} = 52;
+$c2n{'0'} = 53;
+$c2n{'1'} = 54;
+$c2n{'2'} = 55;
+$c2n{'3'} = 56;
+$c2n{'4'} = 57;
+$c2n{'5'} = 58;
+$c2n{'6'} = 59;
+$c2n{'7'} = 60;
+$c2n{'8'} = 61;
+$c2n{'9'} = 62;
+$c2n{'_'} = 63;
+
+line: while (<>) {
+    ($Fld1,$Fld2) = split(' ', $_, 9999);
+    if (/^#/) {
+	next line;
+    }
+    if (/^[ \t]*(error_table|et)[ \t]+[a-zA-Z][a-zA-Z0-9_]+/) {
+	$table_number = 0;
+	$table_name = $Fld2;
+	$mod_base = 1000000;
+	for ($i = 1; $i <= length($table_name); $i++) {
+	    $table_number = ($table_number * $char_shift) +
+
+	      $c2n{substr($table_name, $i, 1)};
+	}
+	# We start playing *_high, *low games here because the some
+	# awk programs do not have the necessary precision (sigh)
+	$tab_base_low = $table_number % $mod_base;
+	$tab_base_high = int($table_number / $mod_base);
+	$tab_base_sign = 1;
+
+	# figure out: table_number_base=table_number*256
+	$tab_base_low = $tab_base_low * 256;
+	$tab_base_high = ($tab_base_high * 256) + int($tab_base_low /
+
+	  $mod_base);
+	$tab_base_low = $tab_base_low % $mod_base;
+
+	if ($table_number > 128 * 256 * 256) {
+	    # figure out:  table_number_base -= 256*256*256*256
+	    # sub_high, sub_low is 256*256*256*256
+	    $sub_low = 256 * 256 * 256 % $mod_base;
+	    $sub_high = int(256 * 256 * 256 / $mod_base);
+
+	    $sub_low = $sub_low * 256;
+	    $sub_high = ($sub_high * 256) + int($sub_low / $mod_base);
+	    $sub_low = $sub_low % $mod_base;
+
+	    $tab_base_low = $sub_low - $tab_base_low;
+	    $tab_base_high = $sub_high - $tab_base_high;
+	    $tab_base_sign = -1;
+	    if ($tab_base_low < 0) {
+		$tab_base_low = $tab_base_low + $mod_base;
+		$tab_base_high--;
+	    }
+	}
+	$curr_low = $tab_base_low;
+	$curr_high = $tab_base_high;
+	$curr_sign = $tab_base_sign;
+	&Pick('>', $outfile) &&
+	    (print $fh '/*');
+	&Pick('>', $outfile) &&
+	    (print $fh ' * ' . $outfile . ':');
+	&Pick('>', $outfile) &&
+	    (print $fh
+
+	      ' * This file is automatically generated; please do not edit it.');
+	&Pick('>', $outfile) &&
+	    (print $fh ' */');
+	&Pick('>', $outfile) &&
+	    (print $fh '');
+	&Pick('>', $outfile) &&
+	    (print $fh '#include <com_err.h>');
+	&Pick('>', $outfile) &&
+	    (print $fh '');
+	$table_item_count = 0;
+    }
+
+    if (/^[ \t]*(error_code|ec)[ \t]+[A-Z_0-9]+,/) {
+	$tag = substr($Fld2, 1, length($Fld2) - 1);
+	if ($curr_high == 0) {
+	    &Pick('>', $outfile) &&
+		(printf $fh "#define %-40s (%dL)\n", $tag,
+
+		  $curr_sign * $curr_low);
+	}
+	else {
+	    &Pick('>', $outfile) &&
+		(printf $fh "#define %-40s (%d%06dL)\n", $tag,
+
+		  $curr_high * $curr_sign, $curr_low);
+	}
+	$curr_low += $curr_sign;
+	if ($curr_low >= $mod_base) {	#???
+	    $curr_low -= $mod_base;
+	    $curr_high++;
+	}
+	if ($curr_low < 0) {
+	    $cur_low += $mod_base;
+	    $cur_high--;
+	}
+    }
+}
+
+if ($table_item_count > 256) {
+    &Pick('|', 'cat 1>&2') &&
+	(print $fh 'Error table too large!');
+    exit 1;
+}
+if ($tab_base_high == 0) {
+    &Pick('>', $outfile) &&
+	(print $fh '#define ERROR_TABLE_BASE_' . $table_name . ' (' .
+
+	  sprintf('%d', $tab_base_sign * $tab_base_low) . 'L)');
+}
+else {
+    &Pick('>', $outfile) &&
+	(print $fh '#define ERROR_TABLE_BASE_' . $table_name . ' (' .
+
+	  sprintf('%d%06d', $tab_base_sign * $tab_base_high,
+
+	  $tab_base_low) . 'L)');
+}
+&Pick('>', $outfile) &&
+    (print $fh '');
+&Pick('>', $outfile) &&
+    (print $fh 'extern const struct error_table et_' . $table_name .
+
+      '_error_table;');
+&Pick('>', $outfile) &&
+    (print $fh '');
+&Pick('>', $outfile) &&
+    (print $fh '#if !defined(_WIN32)');
+&Pick('>', $outfile) &&
+    (print $fh '/* for compatibility with older versions... */');
+&Pick('>', $outfile) &&
+    (print $fh 'extern void initialize_' . $table_name .
+
+      '_error_table (void) /*@modifies internalState@*/;');
+&Pick('>', $outfile) &&
+    (print $fh '#else');
+&Pick('>', $outfile) &&
+    (print $fh '#define initialize_' . $table_name . '_error_table()');
+&Pick('>', $outfile) &&
+    (print $fh '#endif');
+&Pick('>', $outfile) &&
+    (print $fh '');
+&Pick('>', $outfile) &&
+    (print $fh '#if !defined(_WIN32)');
+&Pick('>', $outfile) &&
+    (print $fh '#define init_' . $table_name . '_err_tbl initialize_' .
+
+      $table_name . '_error_table');
+&Pick('>', $outfile) &&
+    (print $fh '#define ' . $table_name . '_err_base ERROR_TABLE_BASE_' .
+
+      $table_name);
+&Pick('>', $outfile) &&
+    (print $fh '#endif');
+
+exit $ExitValue;
+
+sub Pick {
+    local($mode,$name,$pipe) = @_;
+    $fh = $name;
+    open($name,$mode.$name.$pipe) unless $opened{$name}++;
+}
diff --git a/mechglue/src/util/et/et_lex.lex.l b/mechglue/src/util/et/et_lex.lex.l
new file mode 100644
index 000000000..b363e8ca4
--- /dev/null
+++ b/mechglue/src/util/et/et_lex.lex.l
@@ -0,0 +1,23 @@
+PC	[^\"]
+AN	[A-Z_a-z0-9]
+%%
+
+error_table	return ERROR_TABLE;
+et		return ERROR_TABLE;
+error_code	return ERROR_CODE_ENTRY;
+ec		return ERROR_CODE_ENTRY;
+end		return END;
+
+[\t\n ]		;
+
+\"{PC}*\"	{ register char *p; yylval.dynstr = ds(yytext+1);
+		  if (p=strrchr(yylval.dynstr, '"')) *p='\0';
+		  return QUOTED_STRING;
+		}
+
+{AN}*	{ yylval.dynstr = ds(yytext); return STRING; }
+
+#.*\n		;
+
+.		{ return (*yytext); }
+%%
diff --git a/mechglue/src/util/et/et_name.c b/mechglue/src/util/et/et_name.c
new file mode 100644
index 000000000..64923c998
--- /dev/null
+++ b/mechglue/src/util/et/et_name.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1997 by Massachusetts Institute of Technology
+ * 
+ * Copyright 1987 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+ * used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. and the M.I.T. S.I.P.B. make no representations about
+ * the suitability of this software for any purpose.  It is
+ * provided "as is" without express or implied warranty.
+ */
+
+#include "com_err.h"
+#include "error_table.h"
+
+static const char char_set[] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
+const char *
+error_table_name_r (unsigned long num,
+		    /*@out@*/ /*@returned@*/ char *outbuf)
+     /*@modifies outbuf@*/
+{
+	long ch;
+	int i;
+	/*@out@*/ char *p;
+
+	p = outbuf;
+	num >>= ERRCODE_RANGE;
+
+	for (i = 3; i >= 0; i--) {
+		ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1);
+		if (ch != 0)
+			*p++ = char_set[ch-1];
+	}
+	*p = '\0';
+	return(outbuf);
+}
+
+/*@observer@*/
+const char * error_table_name(unsigned long num)
+     /*@modifies internalState@*/
+{
+	static char buf[6];
+
+	return error_table_name_r(num, buf);
+}
diff --git a/mechglue/src/util/et/init_et.c b/mechglue/src/util/et/init_et.c
new file mode 100644
index 000000000..b0a406403
--- /dev/null
+++ b/mechglue/src/util/et/init_et.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1997 by Massachusetts Institute of Technology
+ * 
+ * Copyright 1986, 1987, 1988 by MIT Student Information Processing Board
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice
+ * appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation,
+ * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+ * used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. and the M.I.T. S.I.P.B. make no representations about
+ * the suitability of this software for any purpose.  It is
+ * provided "as is" without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "com_err.h"
+#include "error_table.h"
+
+#if 0
+/*
+ * XXX This function is provided without any prototypes in the public
+ * interface, and isn't used internally.  It's probably safe to make
+ * it go away.
+ */
+struct foobar {
+    struct et_list etl;
+    struct error_table et;
+};
+
+int init_error_table(msgs, base, count)
+    const char * const * msgs;
+    int base;
+    int count;
+{
+    struct foobar * new_et;
+
+    if (!base || !count || !msgs)
+	return 0;
+
+    new_et = (struct foobar *) malloc(sizeof(struct foobar));
+    if (!new_et)
+	return errno;	/* oops */
+    new_et->etl.table = &new_et->et;
+    new_et->et.msgs = msgs;
+    new_et->et.base = base;
+    new_et->et.n_msgs= count;
+
+    new_et->etl.next = _et_list;
+    _et_list = &new_et->etl;
+    return 0;
+}
+
+extern errcode_t KRB5_CALLCONV et_init(ectx)
+	et_ctx *ectx;
+{
+	struct et_context *ctx;
+
+	ctx = malloc(sizeof(struct et_context));
+	if (!ctx)
+		return ENOMEM;
+	ctx->tables = 0;
+	ctx->hook_func = 0;
+	ctx->hook_func_data = 0;
+	
+	*ectx = ctx;
+	return 0;
+}
+
+extern void KRB5_CALLCONV et_shutdown(ectx)
+	et_ctx ectx;	
+{
+	struct et_list *p, *n;
+
+	p = ectx->tables;
+	while (p) {
+		n = p->next;
+		free(p);
+		p = n;
+	}
+	free(ectx);
+}
+
+extern errcode_t KRB5_CALLCONV et_add_error_table(ectx, tbl)
+	et_ctx ectx;
+	struct error_table *tbl;
+{
+	struct et_list *e;
+
+	e = malloc(sizeof(struct et_list));
+	if (!e)
+		return ENOMEM;
+	
+	e->table = tbl;
+	e->next = ectx->tables;
+	ectx->tables = e;
+	
+	return 0;
+}
+
+#endif
diff --git a/mechglue/src/util/et/internal.h b/mechglue/src/util/et/internal.h
new file mode 100644
index 000000000..57b5cd58e
--- /dev/null
+++ b/mechglue/src/util/et/internal.h
@@ -0,0 +1,15 @@
+/*
+ * internal include file for com_err package
+ */
+#include "mit-sipb-copyright.h"
+
+#include <errno.h>
+
+#ifndef SYS_ERRLIST_DECLARED
+extern char const * const sys_errlist[];
+extern const int sys_nerr;
+#endif
+
+#if defined(__STDC__) && !defined(HDR_HAS_PERROR) && !defined(WIN32)
+void perror (const char *);
+#endif
diff --git a/mechglue/src/util/et/libcom_err.exports b/mechglue/src/util/et/libcom_err.exports
new file mode 100644
index 000000000..ea8f32d5f
--- /dev/null
+++ b/mechglue/src/util/et/libcom_err.exports
@@ -0,0 +1,9 @@
+add_error_table
+com_err
+com_err_va
+error_message
+error_table_name
+error_table_name_r
+remove_error_table
+reset_com_err_hook
+set_com_err_hook
diff --git a/mechglue/src/util/et/mit-sipb-copyright.h b/mechglue/src/util/et/mit-sipb-copyright.h
new file mode 100644
index 000000000..d7c4ee096
--- /dev/null
+++ b/mechglue/src/util/et/mit-sipb-copyright.h
@@ -0,0 +1,22 @@
+/*
+
+Copyright 1987, 1988 by the Student Information Processing Board
+	of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+Furthermore if you modify this software you must label
+your software as modified software and not distribute it in such a
+fashion that it might be confused with the original M.I.T. software.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/mechglue/src/util/et/t_com_err.c b/mechglue/src/util/et/t_com_err.c
new file mode 100644
index 000000000..2cba3cfdc
--- /dev/null
+++ b/mechglue/src/util/et/t_com_err.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "com_err.h"
+#include "et1.h"
+#include "et2.h"
+
+int misc_err, known_err;	/* known_err is err in whether or not
+                                   table is 'known' to library */
+int fail;
+
+static void
+try_one (errcode_t code, int known, int table, int msgno)
+{
+    const char *msg = error_message (code);
+    char buffy[1024];
+
+    sprintf (buffy, "error table %d message %d", table, msgno);
+    if (0 == strcmp (buffy, msg)) {
+	if (!known) {
+	    known_err++;
+	}
+	return;
+    }
+    sprintf (buffy, "Unknown code et%d %d", table, msgno);
+    if (!strcmp (buffy, msg)) {
+	if (known)
+	    known_err++;
+	return;
+    }
+    printf ("error code %ld got unrecognized message '%s',\n"
+	    "should have been table %d message %d\n",
+	    (long) code, msg, table, msgno);
+    misc_err++;
+}
+
+static void
+try_table (int table, int known, int lineno,
+	   errcode_t c0, errcode_t c1, errcode_t c2)
+{
+    try_one (c0, known, table, 0);
+    try_one (c1, known, table, 1);
+    try_one (c2, known, table, 2);
+    if (misc_err != 0 || known_err != 0) {
+	fail++;
+	if (known_err)
+	    printf ("table list error from line %d, table %d\n", lineno,
+		    table);
+	if (misc_err)
+	    printf ("misc errors from line %d table %d\n", lineno, table);
+	misc_err = known_err = 0;
+    }
+}
+
+static void
+try_em_1 (int t1_known, int t2_known, int lineno)
+{
+    try_table (1, t1_known, lineno, ET1_M0, ET1_M1, ET1_M2);
+    try_table (2, t2_known, lineno, ET2_M0, ET2_M1, ET2_M2);
+}
+#define try_em(A,B) try_em_1(A,B,__LINE__)
+
+static void *run(/*@unused@*/ void *x)
+{
+    try_em (0, 0);
+    (void) add_error_table (&et_et1_error_table);
+    try_em (1, 0);
+    (void) add_error_table (&et_et2_error_table);
+    try_em (1, 1);
+    (void) remove_error_table (&et_et1_error_table);
+    try_em (0, 1);
+    (void) remove_error_table (&et_et1_error_table);
+    try_em (0, 1);
+    (void) remove_error_table (&et_et2_error_table);
+    try_em (0, 0);
+
+    initialize_et1_error_table ();
+    try_em (1, 0);
+    (void) add_error_table (&et_et1_error_table);
+    try_em (1, 0);
+    (void) remove_error_table (&et_et1_error_table);
+    try_em (1, 0);
+    (void) remove_error_table (&et_et1_error_table);
+    try_em (0, 0);
+
+    initialize_et1_error_table ();
+    try_em (1, 0);
+    (void) add_error_table (&et_et1_error_table);
+    try_em (1, 0);
+    (void) add_error_table (&et_et2_error_table);
+    try_em (1, 1);
+    (void) remove_error_table (&et_et1_error_table);
+    try_em (1, 1);
+    (void) remove_error_table (&et_et1_error_table);
+    try_em (0, 1);
+    (void) remove_error_table (&et_et2_error_table);
+    try_em (0, 0);
+    (void) remove_error_table (&et_et2_error_table);
+    try_em (0, 0);
+
+    (void) add_error_table (&et_et2_error_table);
+    try_em (0, 1);
+    initialize_et2_error_table ();
+    try_em (0, 1);
+    (void) add_error_table (&et_et1_error_table);
+    try_em (1, 1);
+    (void) remove_error_table (&et_et1_error_table);
+    try_em (0, 1);
+    (void) remove_error_table (&et_et2_error_table);
+    try_em (0, 1);
+    (void) remove_error_table (&et_et2_error_table);
+    try_em (0, 0);
+
+    return 0;
+}
+
+#ifdef TEST_THREADS
+#include <pthread.h>
+#endif
+
+int main (/*@unused@*/ int argc, /*@unused@*/ char *argv[])
+{
+#ifdef TEST_THREADS
+    pthread_t t;
+    int err;
+    void *t_retval;
+
+    err = pthread_create(&t, 0, run, 0);
+    if (err) {
+	fprintf(stderr, "pthread_create error: %s\n", strerror(err));
+	exit(1);
+    }
+    err = pthread_join(t, &t_retval);
+    if (err) {
+	fprintf(stderr, "pthread_join error: %s\n", strerror(err));
+	exit(1);
+    }
+    return fail;
+#else
+    run(0);
+    return fail;
+#endif
+}
diff --git a/mechglue/src/util/et/test1.et b/mechglue/src/util/et/test1.et
new file mode 100644
index 000000000..4c7b77f0e
--- /dev/null
+++ b/mechglue/src/util/et/test1.et
@@ -0,0 +1,69 @@
+	error_table	krb
+
+	error_code	KRB_MK_AP_TKFIL,
+			"Can't read ticket file"
+
+	ec		KRB_MK_AP_NOTKT,
+			"Can't find ticket or TGT"
+
+	ec		KRB_MK_AP_TGTEXP,
+			"TGT expired"
+
+	ec		KRB_RD_AP_UNDEC,
+			"Can't decode authenticator"
+
+	ec		KRB_RD_AP_EXP,
+			"Ticket expired"
+
+	ec		KRB_RD_AP_REPEAT,
+			"Repeated request"
+
+	ec		KRB_RD_AP_NOT_US,
+			"The ticket isn't for us"
+
+	ec		KRB_RD_AP_INCON,
+			"Request is inconsistent"
+
+	ec		KRB_RD_AP_TIME,
+			"Delta-T too big"
+
+	ec		KRB_RD_AP_BADD,
+			"Incorrect net address"
+
+	ec		KRB_RD_AP_VERSION,
+			"Protocol version mismatch"
+
+	ec		KRB_RD_AP_MSG_TYPE,
+			"Invalid message type"
+
+	ec		KRB_RD_AP_MODIFIED,
+			"Message stream modified"
+
+	ec		KRB_RD_AP_ORDER,
+			"Message out of order"
+
+	ec		KRB_RD_AP_UNAUTHOR,
+			"Unauthorized request"
+
+	ec		KRB_GT_PW_NULL,
+			"Current password is null"
+
+	ec		KRB_GT_PW_BADPW,
+			"Incorrect current password"
+
+	ec		KRB_GT_PW_PROT,
+			"Protocol error"
+
+	ec		KRB_GT_PW_KDCERR,
+			"Error returned by KDC"
+
+	ec		KRB_GT_PW_NULLTKT,
+			"Null ticket returned by KDC"
+
+	ec		KRB_SKDC_RETRY,
+			"Retry count exceeded"
+
+	ec		KRB_SKDC_CANT,
+			"Can't send request"
+
+	end
diff --git a/mechglue/src/util/et/test2.et b/mechglue/src/util/et/test2.et
new file mode 100644
index 000000000..55ad74ead
--- /dev/null
+++ b/mechglue/src/util/et/test2.et
@@ -0,0 +1,9 @@
+	error_table	quux
+
+	ec	FOO_ERR, "foo"
+
+	ec	BAR_ERR, "bar"
+
+	ec	BAZ_ERR, "meow"
+
+	end
diff --git a/mechglue/src/util/et/test_et.c b/mechglue/src/util/et/test_et.c
new file mode 100644
index 000000000..8ef3d725f
--- /dev/null
+++ b/mechglue/src/util/et/test_et.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <errno.h>
+#include "com_err.h"
+#include "test1.h"
+#include "test2.h"
+
+#ifdef _WIN32
+# define EXPORT_LIST
+#endif
+
+/* XXX Not part of official public API.  */
+extern const char *error_table_name (errcode_t);
+
+#ifdef NEED_SYS_ERRLIST
+extern int sys_nerr;
+#endif
+
+int main()
+{
+	printf("Before initiating error table:\n\n");
+#ifndef EXPORT_LIST
+	printf("Table name '%s'\n", error_table_name(KRB_MK_AP_TGTEXP));
+	printf("UNIX  name '%s'\n", error_table_name(EPERM));
+#endif
+	printf("Msg TGT-expired is '%s'\n", error_message(KRB_MK_AP_TGTEXP));
+	printf("Msg EPERM is '%s'\n", error_message(EPERM));
+	printf("Msg FOO_ERR is '%s'\n", error_message(FOO_ERR));
+	printf("Msg 1002 is '%s'\n", error_message (1002));
+#ifdef HAVE_SYS_ERRLIST
+	printf("Msg {sys_nerr-1} is '%s'\n", error_message(sys_nerr-1));
+	printf("Msg {sys_nerr} is '%s'\n", error_message(sys_nerr));
+#endif
+	printf("Msg 0 is '%s'\n", error_message(0));
+
+	printf("With 0: tgt-expired -> %s\n", error_message(KRB_MK_AP_TGTEXP));
+
+	initialize_krb_error_table();
+#ifndef EXPORT_LIST
+	printf("KRB error table initialized:  base %ld (%s), name %s\n",
+	       ERROR_TABLE_BASE_krb, error_message(ERROR_TABLE_BASE_krb),
+	       error_table_name(ERROR_TABLE_BASE_krb));
+#else
+	printf("KRB error table initialized:  base %ld (%s)\n",
+	       ERROR_TABLE_BASE_krb, error_message(ERROR_TABLE_BASE_krb));
+#endif
+	add_error_table(&et_krb_error_table);
+	printf("With krb: tgt-expired -> %s\n",
+	       error_message(KRB_MK_AP_TGTEXP));
+
+	add_error_table(&et_quux_error_table);
+#ifndef EXPORT_LIST
+	printf("QUUX error table initialized: base %ld (%s), name %s\n",
+	       ERROR_TABLE_BASE_quux, error_message(ERROR_TABLE_BASE_quux),
+	       error_table_name(ERROR_TABLE_BASE_quux));
+#else
+	printf("QUUX error table initialized: base %ld (%s)\n",
+	       ERROR_TABLE_BASE_quux, error_message(ERROR_TABLE_BASE_quux));
+#endif
+
+	printf("Msg for TGT-expired is '%s'\n",
+	       error_message(KRB_MK_AP_TGTEXP));
+#ifdef HAVE_SYS_ERRLIST
+	printf("Msg {sys_nerr-1} is '%s'\n", error_message(sys_nerr-1));
+#endif
+	printf("Msg FOO_ERR is '%s'\n", error_message(FOO_ERR));
+	printf("Msg KRB_SKDC_CANT is '%s'\n",
+		    error_message(KRB_SKDC_CANT));
+	printf("Msg 1e6 (8B 64) is '%s'\n", error_message(1000000));
+	printf("\n\nCOM_ERR tests:\n");
+	com_err("whoami", FOO_ERR, (char *)NULL);
+	com_err("whoami", FOO_ERR, " -- message goes %s", "here");
+	com_err("whoami", 0, (char *)0);
+	com_err("whoami", 0, "error number %d\n", 0);
+	return 0;
+}
diff --git a/mechglue/src/util/et/texinfo.tex b/mechglue/src/util/et/texinfo.tex
new file mode 100644
index 000000000..eb29dfd7f
--- /dev/null
+++ b/mechglue/src/util/et/texinfo.tex
@@ -0,0 +1,2077 @@
+%% TeX macros to handle texinfo files
+
+%   Copyright (C) 1985, 1986, 1988 Richard M. Stallman
+
+%		       NO WARRANTY
+
+%  BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
+%NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
+%WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
+%RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
+%WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+%BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+%FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
+%AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
+%DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+%CORRECTION.
+
+% IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
+%STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
+%WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
+%LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
+%OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+%USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
+%DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
+%A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
+%PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
+%DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
+
+%		GENERAL PUBLIC LICENSE TO COPY
+
+%  1. You may copy and distribute verbatim copies of this source file
+%as you receive it, in any medium, provided that you conspicuously
+%and appropriately publish on each copy a valid copyright notice
+%"Copyright (C) 1986 Richard M. Stallman"; and include
+%following the copyright notice a verbatim copy of the above disclaimer
+%of warranty and of this License.
+
+%  2. You may modify your copy or copies of this source file or
+%any portion of it, and copy and distribute such modifications under
+%the terms of Paragraph 1 above, provided that you also do the following:
+
+%    a) cause the modified files to carry prominent notices stating
+%    that you changed the files and the date of any change; and
+
+%    b) cause the whole of any work that you distribute or publish,
+%    that in whole or in part contains or is a derivative of this
+%    program or any part thereof, to be licensed at no charge to all
+%    third parties on terms identical to those contained in this
+%    License Agreement (except that you may choose to grant more extensive
+%    warranty protection to some or all third parties, at your option).
+
+%    c) You may charge a distribution fee for the physical act of
+%    transferring a copy, and you may at your option offer warranty
+%    protection in exchange for a fee.
+
+%Mere aggregation of another unrelated program with this program (or its
+%derivative) on a volume of a storage or distribution medium does not bring
+%the other program under the scope of these terms.
+
+%  3. You may copy and distribute this program (or a portion or derivative
+%of it, under Paragraph 2) in object code or executable form under the terms
+%of Paragraphs 1 and 2 above provided that you also do one of the following:
+
+%    a) accompany it with the complete corresponding machine-readable
+%    source code, which must be distributed under the terms of
+%    Paragraphs 1 and 2 above; or,
+
+%    b) accompany it with a written offer, valid for at least three
+%    years, to give any third party free (except for a nominal
+%    shipping charge) a complete machine-readable copy of the
+%    corresponding source code, to be distributed under the terms of
+%    Paragraphs 1 and 2 above; or,
+
+%    c) accompany it with the information you received as to where the
+%    corresponding source code may be obtained.  (This alternative is
+%    allowed only for noncommercial distribution and only if you
+%    received the program in object code or executable form alone.)
+
+%For an executable file, complete source code means all the source code for
+%all modules it contains; but, as a special exception, it need not include
+%source code for modules which are standard libraries that accompany the
+%operating system on which the executable file runs.
+
+%  4. You may not copy, sublicense, distribute or transfer this program
+%except as expressly provided under this License Agreement.  Any attempt
+%otherwise to copy, sublicense, distribute or transfer this program is void and
+%your rights to use the program under this License agreement shall be
+%automatically terminated.  However, parties who have received computer
+%software programs from you with this License Agreement will not have
+%their licenses terminated so long as such parties remain in full compliance.
+
+%  5. If you wish to incorporate parts of this program into other free
+%programs whose distribution conditions are different, write to the Free
+%Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
+%worked out a simple rule that can be stated here, but we will often permit
+%this.  We will be guided by the two goals of preserving the free status of
+%all derivatives of our free software and of promoting the sharing and reuse of
+%software.
+
+%In other words, you are welcome to use, share and improve this program.
+%You are forbidden to forbid anyone else to use, share and improve
+%what you give them.   Help stamp out software-hoarding!
+
+\def\texinfoversion{1.18}
+\message{Loading texinfo package [Version \texinfoversion]:}
+\message{}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexdot=\.
+\let\ptexstar=\*
+\let\ptexend=\end
+\let\ptexbullet=\bullet
+\let\ptexb=\b
+\let\ptexc=\c
+\let\ptexi=\i
+\let\ptext=\t
+\let\ptexl=\l
+\let\ptexL=\L
+
+\def\tie{\penalty 10000\ }     % Save plain tex definition of ~.
+
+\message{Basics,}
+\chardef\other=12
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset  \bindingoffset=0pt
+\newdimen \normaloffset   \normaloffset=\hoffset
+\newdimen\pagewidth \newdimen\pageheight
+\pagewidth=\hsize \pageheight=\vsize
+
+%---------------------Begin change-----------------------
+%
+% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\cornerlong \newdimen\cornerthick
+\newdimen \topandbottommargin
+\newdimen \outerhsize \newdimen \outervsize
+\cornerlong=1pc\cornerthick=.3pt	% These set size of cropmarks
+\outerhsize=7in
+\outervsize=9.5in
+\topandbottommargin=.75in
+%
+%---------------------End change-----------------------
+
+% \onepageout takes a vbox as an argument.  Note that \pagecontents
+% does insertions itself, but you have to call it yourself.
+\chardef\PAGE=255  \output={\onepageout{\pagecontents\PAGE}}
+\def\onepageout#1{\hoffset=\normaloffset
+\ifodd\pageno  \advance\hoffset by \bindingoffset
+\else \advance\hoffset by -\bindingoffset\fi
+\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
+ {\let\hsize=\pagewidth \makefootline}}
+\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+
+
+% Here is a modification of the main output routine for Near East Publications
+% This provides right-angle cropmarks at all four corners.
+% The contents of the page are centerlined into the cropmarks,
+% and any desired binding offset is added as an \hskip on either
+% site of the centerlined box.  (P. A. MacKay, 12 November, 1986)
+%
+\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
+		 \shipout
+		 \vbox to \outervsize{\hsize=\outerhsize
+                 \vbox{\line{\ewtop\hfill\ewtop}}
+                 \nointerlineskip
+                 \line{\vbox{\moveleft\cornerthick\nstop}
+                       \hfill
+                       \vbox{\moveright\cornerthick\nstop}}
+                 \vskip \topandbottommargin
+                 \centerline{\ifodd\pageno\hskip\bindingoffset\fi
+			\vbox{
+			{\let\hsize=\pagewidth \makeheadline}
+			\pagebody{#1}
+			{\let\hsize=\pagewidth \makefootline}}
+			\ifodd\pageno\else\hskip\bindingoffset\fi}
+		 \vskip \topandbottommargin plus1fill minus1fill
+                 \boxmaxdepth\cornerthick
+                 \line{\vbox{\moveleft\cornerthick\nsbot}
+                       \hfill
+                       \vbox{\moveright\cornerthick\nsbot}}
+                 \nointerlineskip
+                 \vbox{\line{\ewbot\hfill\ewbot}}
+	}
+  \advancepageno 
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+%
+% Do @cropmarks to get crop marks
+\def\cropmarks{\let\onepageout=\croppageout }
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+%
+% Here are the rules for the cropmarks.  Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+  {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+  {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.
+% The argument can be delimited with [...] or with "..." or braces
+% or it can be a whole line.
+% #1 should be a macro which expects
+% an ordinary undelimited TeX argument.
+
+\def\parsearg #1{\let\next=#1\begingroup\obeylines\futurelet\temp\parseargx}
+
+\def\parseargx{%
+\ifx \obeyedspace\temp \aftergroup\parseargdiscardspace \else%
+\aftergroup \parseargline %
+\fi \endgroup}
+
+{\obeyspaces %
+\gdef\parseargdiscardspace {\begingroup\obeylines\futurelet\temp\parseargx}}
+
+\gdef\obeyedspace{\ }
+
+\def\parseargline{\begingroup \obeylines \parsearglinex}
+{\obeylines %
+\gdef\parsearglinex #1^^M{\endgroup \next {#1}}}
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment.  Type Return to continue.}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo  is the same as @foo, for now.
+\newhelp\EMsimple{Type <Return> to continue}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+%% @end foo executes the definition of \Efoo.
+%% foo can be delimited by doublequotes or brackets.
+
+\def\end{\parsearg\endxxx}
+
+\def\endxxx #1{%
+\expandafter\ifx\csname E#1\endcsname\relax
+\expandafter\ifx\csname #1\endcsname\relax
+\errmessage{Undefined command @end #1}\else
+\errorE{#1}\fi\fi
+\csname E#1\endcsname}
+\def\errorE#1{
+{\errhelp=\EMsimple \errmessage{@end #1 not within #1 environment}}}
+
+% Single-spacing is done by various environments.
+
+\newskip\singlespaceskip \singlespaceskip = \baselineskip
+\def\singlespace{%
+{\advance \baselineskip by -\singlespaceskip
+\kern \baselineskip}%
+\baselineskip=\singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\sf \char '100}}
+
+% Define @` and @' to be the same as ` and '
+% but suppressing ligatures.
+\def\`{{`}}
+\def\'{{'}}
+
+% Used to generate quoted braces.
+
+\def\mylbrace {{\tt \char '173}}
+\def\myrbrace {{\tt \char '175}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @w prevents a word break
+\def\w #1{\hbox{#1}}
+
+% @group ... @end group  forces ... to be all on one page.
+
+\def\group{\begingroup% \inENV ???
+\def \Egroup{\egroup\endgroup}
+\vbox\bgroup}
+
+% @br   forces paragraph break
+
+\let\br = \par
+
+% @dots{}  output some dots
+
+\def\dots{$\ldots$}
+
+% @page    forces the start of a new page
+
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+\def\exdent{\errmessage{@exdent in filled text}}
+  % @lisp, etc, define \exdent locally from \internalexdent
+
+{\obeyspaces
+\gdef\internalexdent{\parsearg\exdentzzz}}
+
+\def\exdentzzz #1{{\advance \leftskip by -\lispnarrowing
+\advance \hsize by -\leftskip
+\advance \hsize by -\rightskip
+\leftline{{\rm#1}}}}
+
+% @include file    insert text of that file as input.
+
+\def\include{\parsearg\includezzz}
+\def\includezzz #1{{\def\thisfile{#1}\input #1
+}}
+
+\def\thisfile{}
+
+% @center line   outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n   outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\par \vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+\def\comment{\parsearg \commentxxx}
+
+\def\commentxxx #1{}
+
+\let\c=\comment
+
+\long\def\ignore #1\end ignore{}
+
+\outer\def\ifset{\parsearg\ifsetxxx}
+
+\def\ifsetxxx #1#2\end ifset{%
+\expandafter\ifx\csname IF#1\endcsname\relax \else #2\fi}
+
+\outer\def\ifclear{\parsearg\ifclearxxx}
+
+\def\ifclearxxx #1#2\end ifclear{%
+\expandafter\ifx\csname IF#1\endcsname\relax #2\fi}
+
+% Some texinfo constructs that are trivial in tex
+
+\def\iftex{}
+\def\Eiftex{}
+\long\def\ifinfo #1\end ifinfo{}
+\long\def\menu #1\end menu{}
+\def\asis#1{#1}
+
+\def\node{\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\lastnode=\relax
+
+\def\donoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\setref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\unnumbnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\let\refill=\relax
+
+\let\setfilename=\comment
+
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\losespace#3{}}, node `\losespace#1{}'}
+\def\losespace #1{#1}
+
+\message{fonts,}
+
+% Font-change commands.
+
+%% Try out Computer Modern fonts at \magstephalf
+\font\tenrm=cmr10 scaled \magstephalf
+\font\tentt=cmtt10 scaled \magstephalf
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\font\tenbf=cmb10 scaled \magstephalf 
+\font\tenit=cmti10 scaled \magstephalf
+\font\tensl=cmsl10 scaled \magstephalf
+\font\tensf=cmss10 scaled \magstephalf
+\def\li{\sf}
+\font\tensc=cmcsc10 scaled \magstephalf
+
+% Fonts for @defun, etc.
+\font\defbf=cmbx10 scaled \magstep1 %was 1314
+\let\deftt=\tentt
+\def\df{\let\tt=\deftt \defbf}
+
+% Font for title
+\font\titlerm = cmbx10 scaled \magstep5
+
+% Fonts for indices
+\font\indit=cmti9 \font\indrm=cmr9
+\def\indbf{\indrm} \def\indsl{\indit}
+\def\indexfonts{\let\it=\indit \let\sl=\indsl \let\bf=\indbf \let\rm=\indrm}
+
+% Fonts for headings
+\font\chaprm=cmbx10 scaled \magstep3
+\font\chapit=cmti10 scaled \magstep3
+\font\chapsl=cmsl10 scaled \magstep3
+\font\chaptt=cmtt10 scaled \magstep3
+\font\chapsf=cmss10 scaled \magstep3
+\let\chapbf=\chaprm
+
+\font\secrm=cmbx10 scaled \magstep2
+\font\secit=cmti10 scaled \magstep2
+\font\secsl=cmsl10 scaled \magstep2
+\font\sectt=cmtt10 scaled \magstep2
+\font\secsf=cmss10 scaled \magstep2
+\let\secbf=\secrm
+
+\font\ssecrm=cmbx10 scaled \magstep1
+\font\ssecit=cmti10 scaled \magstep1
+\font\ssecsl=cmsl10 scaled \magstep1
+\font\ssectt=cmtt10 scaled \magstep1
+\font\ssecsf=cmss10 scaled \magstep1
+\let\ssecbf=\ssecrm
+
+\def\textfonts{\let\rm=\tenrm\let\it=\tenit\let\sl=\tensl\let\bf=\tenbf%
+\let\sc=\tensc\let\sf=\tensf}
+\def\chapfonts{\let\rm=\chaprm\let\it=\chapit\let\sl=\chapsl\let\bf=\chapbf\let\tt=\chaptt\let\sf=\chapsf}
+\def\secfonts{\let\rm=\secrm\let\it=\secit\let\sl=\secsl\let\bf=\secbf\let\tt=\sectt\let\sf=\secsf}
+\def\subsecfonts{\let\rm=\ssecrm\let\it=\ssecit\let\sl=\ssecsl\let\bf=\ssecbf\let\tt=\ssectt\let\sf=\ssecsf}
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+\def\i#1{{\sl #1}}
+\let\var=\i
+\let\dfn=\i
+\let\emph=\i
+\let\cite=\i
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+\def\t#1{{\tt \rawbackslash \frenchspacing #1}\null}
+\let\ttfont = \t
+\let\kbd=\t
+\let\code=\t
+\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null}
+\def\key #1{{\tt \uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+\let\file=\samp
+
+\def\l#1{{\li #1}\null}
+
+\def\r#1{{\rm #1}}
+\def\s#1{{\sc #1}}
+\def\ii#1{{\it #1}}
+
+\def\titlefont#1{{\titlerm #1}}
+
+\def\titlepage{\begingroup \parindent=0pt \hbox{}%
+\let\oldpage=\page
+\def\page{\oldpage \hbox{}}}
+
+\def\Etitlepage{\endgroup\page\HEADINGSon}
+
+% Make altmode in file print out right
+
+\catcode `\^^[=\active \def^^[{$\diamondsuit$}
+
+\message{page headings,}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks \evenheadline    % Token sequence for heading line of even pages
+\newtoks \oddheadline     % Token sequence for heading line of odd pages
+\newtoks \evenfootline    % Token sequence for footing line of even pages
+\newtoks \oddfootline     % Token sequence for footing line of odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}}
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
+\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
+\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+%
+}% unbind the catcode of @.
+
+% @headings on   turns them on.
+% @headings off  turns them off.
+% By default, they are off.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1,
+% Put current file name in lower left corner,
+% Put chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSon{
+\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line...  specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+\message{tables,}
+
+% Tables -- @table, @ftable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table and @ftable define @item, @itemx, etc., with these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\par \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\par \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}\itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}\itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+\advance \hsize by -\rightskip %
+\advance \hsize by -\leftskip %
+\setbox0=\hbox{\itemfont{#1}}%
+\itemindex{#1}%
+\parskip=0in %
+\noindent %
+\ifdim \wd0>\itemmax %
+\vadjust{\penalty 10000}%
+\hbox to \hsize{\hskip -\tableindent\box0\hss}\ %
+\else %
+\hbox to 0pt{\hskip -\tableindent\box0\hss}%
+\fi %
+\endgroup %
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+%% Contains a kludge to get @end[description] to work
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1        \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1        \endtabley}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Neccessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\endgroup\afterenvbreak}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{\itemizey {#1}{\Eitemize}}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\begingroup %
+\itemno = 0 %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\endgroup\afterenvbreak}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+\def\bullet{$\ptexbullet$}
+\def\minus{$-$}
+
+\def\enumerate{\itemizey{\the\itemno.}\Eenumerate\flushcr}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{\in hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 300}}%
+\flushcr}
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that	accumulates this index.  The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+
+\def\newindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1	% Open the file
+\expandafter\xdef\csname#1index\endcsname{%	% Define \xxxindex
+\noexpand\doindex {#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1	% Open the file
+\expandafter\xdef\csname#1index\endcsname{%	% Define \xxxindex
+\noexpand\docodeindex {#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+\def\synindex #1 #2 {%
+\expandafter\xdef\csname#1index\endcsname{%	% Define \xxxindex
+\noexpand\doindex {#2}}%
+}
+
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex #1 #2 {%
+\expandafter\xdef\csname#1index\endcsname{%	% Define \xxxindex
+\noexpand\docodeindex {#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+%  and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\bf{\realbackslash bf }%
+\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\dots{\realbackslash dots }%
+\def\copyright{\realbackslash copyright }%
+}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexnofonts{%
+\let\code=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+@gdef@realbackslash{\}}
+
+\let\indexbackslash=0  %overridden during \printindex.
+
+\def\doind #1#2{%
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\count10=\lastpenalty %
+\escapechar=`\\%
+{\let\folio=0% Expand all macros now EXCEPT \folio
+\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+% so it will be output as is; and it will print as backslash in the indx.
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2}%
+}%
+% Now produce the complete index entry.  We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}}}%
+\temp }%
+\penalty\count10}}
+
+\def\dosubind #1#2#3{%
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\count10=\lastpenalty %
+\escapechar=`\\%
+{\let\folio=0%
+\def\rawbackslashxx{\indexbackslash}%
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2 #3}%
+}%
+% Now produce the complete index entry.  We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
+\temp }%
+\penalty\count10}}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+
+% Define the user-accessible indexing commands 
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% This is what you call to cause a particular index to get printed.
+% Write
+% @unnumbered Function Index
+% @printindex fn
+
+\def\printindex{\parsearg\doprintindex}
+
+\def\doprintindex#1{\tex %
+\catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
+\catcode`\$=\other\catcode`\_=\other
+\catcode`\~=\other
+\def\indexbackslash{\rawbackslashxx}
+\indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
+\begindoublecolumns
+\openin 1 \jobname.#1s
+\ifeof 1 \else \closein 1 \input \jobname.#1s
+\fi
+\enddoublecolumns
+\Etex}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+% Same as \bigskipamount except no shrink.
+% \balancecolumns gets confused if there is any shrink.
+\newskip\initialskipamount \initialskipamount 12pt plus4pt
+
+\outer\def\initial #1{%
+{\let\tentt=\sectt \let\sf=\sectt
+\ifdim\lastskip<\initialskipamount
+\removelastskip \penalty-200 \vskip \initialskipamount\fi
+\line{\secbf#1\hfill}\kern 2pt\penalty3000}}
+
+\outer\def\entry #1#2{
+{\parfillskip=0in \parskip=0in \parindent=0in
+\hangindent=1in \hangafter=1%
+\noindent\hbox{#1}\leaders\Dotsbox\hskip 0pt plus 1filll #2\par
+}}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\leaders\Dotsbox\hskip 0pt plus 1filll#2\par
+}}
+
+%% Define two-column mode, which is used in indexes.
+%% Adapted from the TeXBook, page 416
+\catcode `\@=11
+
+\newbox\partialpage
+
+\newdimen\doublecolumnhsize  \doublecolumnhsize = 3.11in
+\newdimen\doublecolumnvsize  \doublecolumnvsize = 19.1in
+
+\def\begindoublecolumns{\begingroup
+  \output={\global\setbox\partialpage=\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}\eject
+  \output={\doublecolumnout} \hsize=\doublecolumnhsize \vsize=\doublecolumnvsize}
+\def\enddoublecolumns{\output={\balancecolumns}\eject
+  \endgroup \pagegoal=\vsize}
+
+\def\doublecolumnout{\splittopskip=\topskip \splitmaxdepth=\maxdepth
+  \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage
+  \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+  \onepageout\pagesofar \unvbox255 \penalty\outputpenalty}
+\def\pagesofar{\unvbox\partialpage %
+  \hsize=\doublecolumnhsize % have to restore this since output routine
+%	      changes it to set cropmarks (P. A. MacKay, 12 Nov. 1986)
+  \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\balancecolumns{\setbox0=\vbox{\unvbox255} \dimen@=\ht0
+  \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+  \divide\dimen@ by2 \splittopskip=\topskip
+  {\vbadness=10000 \loop \global\setbox3=\copy0
+    \global\setbox1=\vsplit3 to\dimen@
+    \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt \repeat}
+  \setbox0=\vbox to\dimen@{\unvbox1}  \setbox2=\vbox to\dimen@{\unvbox3}
+  \pagesofar}
+
+\catcode `\@=\other
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount \chapno
+\newcount \secno
+\newcount \subsecno
+\newcount \subsubsecno
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount \appendixno  \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+\newwrite \contentsfile
+\openout \contentsfile = \jobname.toc
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it.  @section does likewise
+
+\def\thischapter{} \def\thissection{}
+\def\seccheck#1{\if \pageno<0 %
+\errmessage{@#1 not allowed after generating table of contents}\fi
+%
+}
+
+\outer\def\chapter{\parsearg\chapterzzz}
+\def\chapterzzz #1{\seccheck{chapter}%
+\secno=0 \subsecno=0 \subsubsecno=0 \global\advance \chapno by 1 \message{Chapter \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}\gdef\thischapter{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\donoderef %
+}
+
+\outer\def\appendix{\parsearg\appendixzzz}
+\def\appendixzzz #1{\seccheck{appendix}%
+\secno=0 \subsecno=0 \subsubsecno=0 \global\advance \appendixno by 1 \message{Appendix \appendixletter}%
+\chapmacro {#1}{Appendix \appendixletter}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash chapentry {#1}{Appendix \appendixletter}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\unnumbnoderef %
+}
+
+\outer\def\unnumbered{\parsearg\unnumberedzzz}
+\def\unnumberedzzz #1{\seccheck{unnumbered}%
+\secno=0 \subsecno=0 \subsubsecno=0 \message{(#1)}
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\unnumbnoderef %
+}
+
+\outer\def\section{\parsearg\sectionzzz}
+\def\sectionzzz #1{\seccheck{section}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash secentry %
+{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsection{\parsearg\appendixsectionzzz}
+\outer\def\appendixsec{\parsearg\appendixsectionzzz}
+\def\appendixsectionzzz #1{\seccheck{appendixsection}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash secentry %
+{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedseczzz}
+\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\subsection{\parsearg\subsectionzzz}
+\def\subsectionzzz #1{\seccheck{subsection}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubseczzz}
+\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\subsubsection{\parsearg\subsubsectionzzz}
+\def\subsubsectionzzz #1{\seccheck{subsubsection}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsubsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%\
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubseczzz}
+\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash subsubsecentry{#1}%
+{\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%\
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}
+
+% Define @majorheading, @heading and @subheading
+
+\outer\def\majorheading #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \line{\chaprm #1\hfill}}\bigskip \par\penalty 200}
+
+\outer\def\chapheading #1{\chapbreak %
+{\chapfonts \line{\chaprm #1\hfill}}\bigskip \par\penalty 200}
+
+\let\heading=\secheadingi
+\let\subheading=\subsecheadingi
+\let\subsubheading=\subsubsecheadingi
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGodd{
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain}
+
+\def\chfplain #1#2{%
+\pchapsepmacro %
+{\chapfonts \line{\chaprm #2.\enspace #1\hfill}}\bigskip \par\penalty 5000 %
+}
+
+\def\unnchfplain #1{%
+\pchapsepmacro %
+{\chapfonts \line{\chaprm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \line{\chaprm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen}
+
+% Parameter controlling skip before section headings.
+
+\newskip \subsecheadingskip  \subsecheadingskip = 17pt plus 8pt minus 4pt
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+
+\newskip \secheadingskip  \secheadingskip = 21pt plus 8pt minus 4pt
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+
+\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
+\def\plainsecheading #1{\secheadingi {#1}}
+\def\secheadingi #1{{\advance \secheadingskip by \parskip %
+\secheadingbreak}%
+{\secfonts \line{\secrm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsecheading #1#2#3#4{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\secfonts \line{\secrm#2.#3.#4\enspace #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsubsecfonts{\subsecfonts} % Maybe this should change
+
+\def\subsubsecheading #1#2#3#4#5{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\secfonts \line{\secrm#2.#3.#4.#5\enspace #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
+
+\message{toc printing,}
+
+\def\Dotsbox{\hbox to 1em{\hss.\hss}} % Used by index macros
+
+\def\finishcontents{%
+\ifnum\pageno>0 %
+\pagealignmacro %
+\immediate\closeout \contentsfile%
+\pageno=-1		% Request roman numbered pages
+\fi}
+
+\outer\def\contents{%
+\finishcontents %
+\unnumbchapmacro{Table of Contents}
+\def\thischapter{Table of Contents}
+{\catcode`\\=0
+\catcode`\{=1		% Set up to handle contents files properly
+\catcode`\}=2
+\catcode`\@=11
+\input \jobname.toc
+}
+\vfill \eject}
+
+\outer\def\summarycontents{%
+\finishcontents %
+\unnumbchapmacro{Summary Table of Contents}
+\def\thischapter{Summary Table of Contents}
+{\catcode`\\=0
+\catcode`\{=1		% Set up to handle contents files properly
+\catcode`\}=2
+\catcode`\@=11
+\def\smallbreak{}
+\def\secentry ##1##2##3##4{}
+\def\subsecentry ##1##2##3##4##5{}
+\def\subsubsecentry ##1##2##3##4##5##6{}
+\def\unnumbsecentry ##1##2{}
+\def\unnumbsubsecentry ##1##2{}
+\def\unnumbsubsubsecentry ##1##2{}
+\let\medbreak=\smallbreak
+\input \jobname.toc
+}
+\vfill \eject}
+
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+% These macros generate individual entries in the table of contents
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+\def\chapentry #1#2#3{%
+\medbreak
+\line{#2.\space#1\leaders\hbox to 1em{\hss.\hss}\hfill #3}
+}
+
+\def\unnumbchapentry #1#2{%
+\medbreak
+\line{#1\leaders\Dotsbox\hfill #2}
+}
+
+\def\secentry #1#2#3#4{%
+\line{\enspace\enspace#2.#3\space#1\leaders\Dotsbox\hfill#4}
+}
+
+\def\unnumbsecentry #1#2{%
+\line{\enspace\enspace#1\leaders\Dotsbox\hfill #2}
+}
+
+\def\subsecentry #1#2#3#4#5{%
+\line{\enspace\enspace\enspace\enspace
+#2.#3.#4\space#1\leaders\Dotsbox\hfill #5}
+}
+
+\def\unnumbsubsecentry #1#2{%
+\line{\enspace\enspace\enspace\enspace#1\leaders\Dotsbox\hfill #2}
+}
+
+\def\subsubsecentry #1#2#3#4#5#6{%
+\line{\enspace\enspace\enspace\enspace\enspace\enspace
+#2.#3.#4.#5\space#1\leaders\Dotsbox\hfill #6}
+}
+
+\def\unnumbsubsubsecentry #1#2{%
+\line{\enspace\enspace\enspace\enspace\enspace\enspace#1\leaders\Dotsbox\hfill #2}
+}
+
+\message{environments,}
+
+% @tex ... @end tex    escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+\catcode `\%=14
+\catcode`\"=12
+\catcode`\|=12
+\catcode`\<=12
+\catcode`\>=12
+\escapechar=`\\
+%
+\let\{=\ptexlbrace
+\let\}=\ptexrbrace
+\let\.=\ptexdot
+\let\*=\ptexstar
+\def\@={@}%
+\let\bullet=\ptexbullet
+\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
+\let\L=\ptexL
+%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^M gets inside @lisp
+% phr: changed space to \null, to avoid overfull hbox problems.
+{\obeyspaces%
+\gdef\lisppar{\null\endgraf}}
+
+% Cause \obeyspaces to make each Space cause a word-separation
+% rather than the default which is that it acts punctuation.
+% This is because space in tt font looks funny.
+{\obeyspaces %
+\gdef\sepspaces{\def {\ }}}
+
+\newskip\aboveenvskipamount \aboveenvskipamount= 0pt
+\def\aboveenvbreak{{\advance\aboveenvskipamount by \parskip
+\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}}
+
+\def\afterenvbreak{\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}
+
+\def\lisp{\aboveenvbreak\begingroup\inENV %This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Elisp{\endgroup\afterenvbreak}%
+\parskip=0pt \advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \tt \rawbackslash
+\def\next##1{}\next}
+
+
+\let\example=\lisp
+\def\Eexample{\Elisp}
+
+\let\smallexample=\lisp
+\def\Esmallexample{\Elisp}
+
+% Macro for 9 pt. examples, necessary to print with 5" lines.
+% From Pavel@xerox.  This is not really used unless the
+% @smallbook command is given.
+
+\def\smalllispx{\aboveenvbreak\begingroup\inENV
+%			This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Esmalllisp{\endgroup\afterenvbreak}%
+\parskip=0pt \advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \ninett \rawbackslash
+\def\next##1{}\next}
+
+% This is @display; same as @lisp except use roman font.
+
+\def\display{\begingroup\inENV %This group ends at the end of the @display body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Edisplay{\endgroup\afterenvbreak}%
+\parskip=0pt \advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% This is @format; same as @lisp except use roman font and don't narrow margins
+
+\def\format{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Eformat{\endgroup\afterenvbreak}
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @flushleft and @flushright
+
+\def\flushleft{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushleft{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+\def\flushright{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushright{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\advance \leftskip by 0pt plus 1fill
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @quotation - narrow the margins.
+
+\def\quotation{\begingroup\inENV %This group ends at the end of the @quotation body
+{\parskip=0pt  % because we will skip by \parskip too, later
+\aboveenvbreak}%
+\singlespace
+\parindent=0pt
+\def\Equotation{\par\endgroup\afterenvbreak}%
+\advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing}
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=36pt
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
+\global\advance\parencount by 1 }
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+% also in that case restore the outer-level definition of (.
+\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+\global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text.  This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
+\def\lbrb{{\tt\char`\[}} \def\rbrb{{\tt\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+\leftskip = 0in  %
+\noindent        %
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1     %
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}%
+\tolerance=10000 \hbadness=10000    % Make all lines underfull and no complaints
+{\df #1}\enskip        % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+%    such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in \leftskip=\defbodyindent %
+\begingroup\obeylines\activeparens\spacesplit#3}
+
+\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in \leftskip=\defbodyindent %
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+%  the first is all of #2 before the space token,
+%  the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl #1%
+\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
+\interlinepenalty=10000
+\endgraf\vskip -\parskip \penalty 10000}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special form}%
+\defunargs {#2}\endgroup %
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop {Funny Method} foo-class frobnicate argument
+
+\def\defop #1 {\def\defoptype{#1}%
+\defmethparsebody\Edefop\defopx\defopheader}
+
+\def\defopheader #1#2#3{\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defmethod == @defop Method
+
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+
+\def\defmethodheader #1#2#3{\dosubind {fn}{\code{#2}}{on #1}% entry in function index
+\begingroup\defname {#2}{Operation on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defmethparsebody\Edefcv\defcvx\defcvheader}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defmethparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\vskip -\parskip \penalty 10000}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defmethparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\defmethparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+\message{cross reference,}
+% Define cross-reference macros
+\newwrite \auxfile
+
+% \setref{foo} defines a cross-reference point named foo.
+
+\def\setref#1{%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ysectionnumberandtype}}
+
+\def\unnumbsetref#1{%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ynothing}}
+
+% \xref and \pxref generate cross references to specified points.
+
+\def\pxref #1{see \xrefX [#1,,,,,,,]}
+\def\xref #1{See \xrefX [#1,,,,,,,]}
+\def\xrefX [#1,#2,#3,#4,#5,#6]{%
+\setbox1=\hbox{\i{\losespace#5{}}}%
+\setbox0=\hbox{\losespace#3{}}%
+\ifdim \wd0 =0pt \setbox0=\hbox{\losespace#1{}}\fi%
+\ifdim \wd1 >0pt%
+section \unhbox0{} in \unhbox1%
+\else%
+\refx{#1-snt} [\unhbox0], page\tie \refx{#1-pg}%
+\fi }
+
+% \dosetq is the interface for calls from other macros
+
+\def\dosetq #1#2{{\let\folio=0%
+\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
+\next}}
+
+% \internalsetq {foo}{page} expands into CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 chapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 section\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+section\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Define @refx to reference a specific cross-reference string.
+
+\def\refx#1{%
+{%
+\expandafter\ifx\csname X#1\endcsname\relax
+% If not defined, say something at least.
+\expandafter\gdef\csname X#1\endcsname {$<$undefined$>$}%
+\message {WARNING: Cross-reference "#1" used but not yet defined}%
+\message {}%
+\fi %
+\csname X#1\endcsname %It's defined, so just use it.
+}}
+
+% Read the last existing aux file, if any.  No error if none exists.
+
+% This is the macro invoked by entries in the aux file.
+\def\xrdef #1#2{
+{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
+
+{
+\catcode `\^^@=\other
+\catcode `\^^A=\other
+\catcode `\^^B=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\^^K=\other
+\catcode `\^^L=\other
+\catcode `\^^N=\other
+\catcode `\^^O=\other
+\catcode `\^^P=\other
+\catcode `\^^Q=\other
+\catcode `\^^R=\other
+\catcode `\^^S=\other
+\catcode `\^^T=\other
+\catcode `\^^U=\other
+\catcode `\^^V=\other
+\catcode `\^^W=\other
+\catcode `\^^X=\other
+\catcode `\^^Y=\other
+\catcode `\^^Z=\other
+\catcode `\^^[=\other
+\catcode `\^^\=\other
+\catcode `\^^]=\other
+\catcode `\^^^=\other
+\catcode `\^^_=\other
+\catcode `\@=\other
+\catcode `\^=\other
+\catcode `\~=\other
+\catcode `\[=\other
+\catcode `\]=\other
+\catcode`\"=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode `\$=\other
+\catcode `\#=\other
+\catcode `\&=\other
+
+% the aux file uses ' as the escape.
+% Turn off \ as an escape so we do not lose on
+% entries which were dumped with control sequences in their names.
+% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+% Reference to such entries still does not work the way one would wish,
+% but at least they do not bomb out when the aux file is read in.
+
+\catcode `\{=1 \catcode `\}=2
+\catcode `\%=\other
+\catcode `\'=0
+\catcode `\\=\other
+
+'openin 1 'jobname.aux
+'ifeof 1 'else 'closein 1 'input 'jobname.aux
+'fi
+}
+
+% Open the new aux file.  Tex will close it automatically at exit.
+
+\openout \auxfile=\jobname.aux
+
+% Footnotes.
+
+\newcount \footnoteno
+
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+\gdef\footnote{\global\advance \footnoteno by \@ne
+\edef\thisfootno{$^{\the\footnoteno}$}%
+\let\@sf\empty
+\ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+\thisfootno\@sf\parsearg\footnotezzz}
+
+\gdef\footnotezzz #1{\insert\footins{
+\interlinepenalty\interfootnotelinepenalty
+\splittopskip\ht\strutbox % top baseline for broken footnotes
+\splitmaxdepth\dp\strutbox \floatingpenalty\@MM
+\leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+\footstrut\hang\textindent{\thisfootno}#1\strut}}
+
+}%end \catcode `\@=11
+
+% End of control word definitions.
+
+\message{and turning on texinfo input format.}
+
+\newindex{cp}
+\newcodeindex{fn}
+\newcodeindex{vr}
+\newcodeindex{tp}
+\newcodeindex{ky}
+\newcodeindex{pg}
+
+% Set some numeric style parameters, for 8.5 x 11 format.
+
+\hsize = 6.5in
+\parindent 15pt
+\parskip 18pt plus 1pt
+\baselineskip 15pt
+\advance\topskip by 1.2cm
+
+% Prevent underfull vbox error messages.
+\vbadness=10000
+
+% Use @smallbook to reset parameters for 7x9.5 format
+\def\smallbook{
+\global\lispnarrowing = 0.3in
+\global\baselineskip 12pt
+\global\parskip 3pt plus 1pt
+\global\hsize = 5in
+\global\doublecolumnhsize=2.4in \global\doublecolumnvsize=15.0in
+\global\vsize=7.5in
+\global\tolerance=700
+\global\hfuzz=1pt
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+\global\font\ninett=cmtt9
+
+\global\let\smalllisp=\smalllispx
+\global\let\smallexample=\smalllispx
+\global\def\Esmallexample{\Esmalllisp}
+}
+
+%% For a final copy, take out the rectangles
+%% that mark overfull boxes (in case you have decided
+%% that the text looks ok even though it passes the margin).
+\def\finalout{\overfullrule=0pt}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary)
+% Define certain chars to be always in tt font.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt \char '042}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt \char '176}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+\catcode`\_=\active
+\def_{{\tt \char '137}}
+\catcode`\|=\active
+\def|{{\tt \char '174}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+{\catcode`\\=\other
+@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+%% These look ok in all fonts, so just make them not special.  The @rm below
+%% makes sure that the current font starts out as the newly loaded cmr10
+\catcode`\$=\other \catcode`\%=\other \catcode`\&=\other \catcode`\#=\other
+
+\catcode 17=0   @c Define control-q
+\catcode`\\=\active
+@let\=@normalbackslash
+
+@textfonts
+@rm
diff --git a/mechglue/src/util/et/vfprintf.c b/mechglue/src/util/et/vfprintf.c
new file mode 100644
index 000000000..cad291602
--- /dev/null
+++ b/mechglue/src/util/et/vfprintf.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)vfprintf.c	5.2 (Berkeley) 6/27/88 */
+
+#include <stdio.h>
+#if defined(HAVE_STDARG_H) || defined(_WIN32)
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#define VARARGS
+#endif
+
+int
+vfprintf(iop, fmt, ap)
+	FILE *iop;
+	char *fmt;
+	va_list ap;
+{
+	int len;
+	char localbuf[BUFSIZ];
+
+	if (iop->_flag & _IONBF) {
+		iop->_flag &= ~_IONBF;
+		iop->_ptr = iop->_base = localbuf;
+		len = _doprnt(fmt, ap, iop);
+		(void) fflush(iop);
+		iop->_flag |= _IONBF;
+		iop->_base = NULL;
+		iop->_bufsiz = 0;
+		iop->_cnt = 0;
+	} else
+		len = _doprnt(fmt, ap, iop);
+
+	return (ferror(iop) ? EOF : len);
+}
diff --git a/mechglue/src/util/exitsleep.c b/mechglue/src/util/exitsleep.c
new file mode 100644
index 000000000..95232e5b3
--- /dev/null
+++ b/mechglue/src/util/exitsleep.c
@@ -0,0 +1,47 @@
+/*
+ * util/exitsleep.c
+ *
+ * Copyright (C) 2003 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Kludge to sleep 100ms prior to exit on Solaris 9 to work around a
+ * pty bug.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <link.h>
+
+void
+exit(int status)
+{
+    void (*realexit)(int);
+    struct timeval tv;
+
+    tv.tv_sec = 0;
+    tv.tv_usec = 100000;
+    realexit = (void (*)(int))dlsym(RTLD_NEXT, "exit");
+    select(0, 0, 0, 0, &tv);
+    realexit(status);
+}
diff --git a/mechglue/src/util/getsyms b/mechglue/src/util/getsyms
new file mode 100755
index 000000000..6db164c60
--- /dev/null
+++ b/mechglue/src/util/getsyms
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Run this from the TOP of the source tree!
+M4=gm4
+configs=`find $1 -name configure.in -print|sort|sed -e 's@/configure.in@@'`
+for dir in $configs; do
+	syms=""
+	libs=""
+	headers=""
+	types=""
+	funcs=""
+	AC_MACRODIR=./util/autoconf
+	# The following bits shamelessly stolen from autoheader.sh
+	eval "`$M4 -I$AC_MACRODIR autoheader.m4 $dir/configure.in|
+		sed -n -e '
+		: again
+		/^@@@.*@@@$/s/^@@@\(.*\)@@@$/\1/p
+		/^@@@/{
+			s/^@@@//p
+			n
+			s/^/@@@/
+			b again
+		}'`"
+	allsyms="`for sym in $syms; do echo $sym; done | sort | uniq`"
+	if test -n "$funcs"; then
+		funcs="`for func in $funcs; do echo $func; done | sort | uniq`"
+		funcs="`for func in $funcs; do echo $func
+			done | sed 's/[^a-zA-Z0-9_]/_/g' | tr '[a-z]' '[A-Z]' | sed 's/^/HAVE_/'`"
+	allsyms="$allsyms $funcs"
+	fi
+	if test -n "$headers"; then
+		headers="`for header in $headers; do echo $header
+			done | sort | uniq`"
+		headers="`for header in $headers; do echo $header
+			done | sed 's/[^a-zA-Z0-9_]/_/g' | tr '[a-z]' '[A-Z]' | sed 's/^/HAVE_/'`"
+	allsyms="$allsyms $headers"
+	fi
+	if test -n "$libs"; then
+		libs="`for lib in $libs; do echo $lib
+			done | sort | uniq`"
+		libs="`for lib in $libs; do echo $lib
+			done | sed 's/[^a-zA-Z0-9_]/_/g' | tr '[a-z]' '[A-Z]' | sed 's/^/HAVE_LIB/'`"
+	allsyms="$allsyms $libs"
+	fi
+	echo $dir/configure.in: $allsyms
+	allsyms="`echo $allsyms|tr ' ' '|'`"
+	files="$dir/*.[ch]"
+	if test ! "`echo $files`" = "$dir/"'*.[ch]'; then
+	for file in $files; do
+		badsyms=""
+		fsyms=`sed -f ./util/getsyms.sed $file`
+		fsyms="`for sym in $fsyms; do echo $sym; done | sort | uniq`"
+		for sym in $fsyms; do
+			if echo $sym|egrep -s "$allsyms">/dev/null; then :
+			else
+				badsyms="$badsyms $sym"
+			fi
+		done
+		if test -n "$badsyms"; then
+			echo $file:$badsyms
+		fi
+	done
+	fi
+done
diff --git a/mechglue/src/util/getsyms.sed b/mechglue/src/util/getsyms.sed
new file mode 100644
index 000000000..a24b5157f
--- /dev/null
+++ b/mechglue/src/util/getsyms.sed
@@ -0,0 +1,42 @@
+# emulate a C preprocessor (well, sort of)
+:TOP
+y/	/ /
+s/  */ /g
+s%/\*.*\*/%%
+/\/\*/{
+	:COMMENT
+	/\*\//!{
+		s/.*//
+		N
+		bCOMMENT
+	}
+	s%^.*\*/%%
+	bTOP
+}
+/^ *# *ifdef/{
+	s/^ *# *ifdef //
+	b
+}
+/^ *# *ifndef/{
+	s/^ *# *ifndef //
+	b
+}
+/^ *# *if.*defined/{
+	s/^ *# *if //
+	:IF
+	/^defined/!{
+		:NUKE
+		s/^.//
+		/^defined/!bNUKE
+	}
+	h
+	/^defined/s/^defined *( *\([A-Za-z0-9_]*\) *).*/\1/p
+	g
+	/^defined/s/^defined *( *\([[A-Za-z0-9_]*\) *)//
+	/defined/!{
+		d
+		b
+	}
+	bIF
+}
+d
diff --git a/mechglue/src/util/kbuild b/mechglue/src/util/kbuild
new file mode 100755
index 000000000..7596f6170
--- /dev/null
+++ b/mechglue/src/util/kbuild
@@ -0,0 +1,168 @@
+#!/bin/sh
+#
+# Kerberos V5 build tool.  Builds Kerberos V5 using a specified 
+# configuration file to control which support programs are used to
+# compile it, which options are given to configure, etc.
+#
+# usage: kbuild { [ frag ] [ var=value ] [ config-lib-path ] }
+#    where frag is something like base, or gcc, or cns, where it finds
+#    base.conf in the config lib path
+#    var=value sets var to value in the script processing (useful to override
+#    SRCDIR or KRB4)
+#    config-lib-path adds itself to the search path for frags.
+#
+#
+# frags themselves are files named frag.conf which have variable settings
+# and filenames. # is a comment marker. If the line is an assignment, it's
+# read; if it begins with /, it's an explicit member of the path; if it 
+# doesn't, it's searched for in the path set in the last fragment.
+#
+# for example, at mit, one might say
+#
+# /mit/krb5/sandbox/util/kbuild base suncc athena
+#
+# or at cygnus, one might say
+#
+# /6h/eichin/mit-v5/build/base/util/kbuild base gcc cns
+#
+# You get the idea.
+#
+# -- Mark Eichin <eichin@cygnus.com> This file is in the Public Domain.
+#
+
+progname=$0
+pts="`echo ${progname} | sed 's=[^/]*$=='`"
+
+#
+# sneak in default knowledge that this program is one level down from the
+# top of the source tree
+#
+
+case $pts in
+/*)   SRCDIR="`echo ${pts} | sed 's=[^/]*/*$=='`"
+      echo "default srcdir $SRCDIR";;
+../*) SRCDIR="`cd ${pts}/.. ; pwd`"
+      echo "default srcdir $SRCDIR";;
+esac
+
+conflib=". $pts/kfrags"
+
+THISCONF=./kbuild.temp
+RECONF=./kbuild.reconf
+rm -f $THISCONF
+BUILD_PATH=./build-path
+rm -rf $BUILD_PATH
+
+echo '#' $0 $* > $THISCONF
+
+echo  $0 $* > $RECONF
+chmod +x $RECONF
+
+for arg
+do
+  case "$arg" in
+  /*)	conflib="$arg $conflib" ;;
+  ..*)	conflib="$arg $conflib" ;;
+  *=*)  echo $arg >> $THISCONF ;;
+  *)
+	  for p in $conflib
+	  do
+		frag=$p/$arg.conf
+		if test -r $frag ; then
+			break
+		fi
+	  done
+	  echo "# $frag" >> $THISCONF
+	  awk '/^#/ { next; } /^[ \t]*$/ {next; }/^[a-zA-Z0-9_]+=.*$/ { print; next; } /^\// { print "ABS_PROGS=\"${ABS_PROGS} "$0"\""; next; } { print "CMD_PROGS=\"${CMD_PROGS} "$0"\""; next; }' < $frag | sed -e 's/^PATH=/XPATH=/' >> $THISCONF
+	;;
+  esac
+done
+
+CONFIG_OPTS="-v"
+MAKETARGETS="all check"
+# echo ==== THISCONF: =====
+# cat $THISCONF
+# echo --------------------
+. $THISCONF
+
+
+if test "x${CC}" != "x"
+then
+	CONFIG_OPTS="$CONFIG_OPTS --with-cc=${CC}"
+fi
+
+if test "x${CC_OPTS}" != "x"
+then
+	CONFIG_OPTS="$CONFIG_OPTS --with-ccopts=${CC_OPTS}"
+fi
+
+if test "x${KRB4}" != "x"
+then
+	CONFIG_OPTS="$CONFIG_OPTS --with-krb4=${KRB4}"
+fi
+
+if test "x${SHARED}" != "x"
+then
+	CONFIG_OPTS="$CONFIG_OPTS --enable-shared"
+fi
+
+/bin/rm -rf $BUILD_PATH
+mkdir $BUILD_PATH
+cd $BUILD_PATH
+
+for i in $CMD_PROGS
+do
+missed=true
+# echo "trying cmdprog $i"
+	for p in `echo $XPATH | sed 's/:/ /g'`
+	do
+# echo "trying cmdprog $i in path element $p"
+		if test -x $p/$i ; then
+			if test -x $i ; then
+# echo "nuking $i"
+				rm $i
+			fi
+# echo "linking $p/$i"
+			ln -s $p/$i
+			missed=false
+			break
+		fi
+	done
+if $missed ; then
+	echo "COULDN'T FIND $i in $XPATH"
+fi
+done
+
+for i in $ABS_PROGS
+do
+	if test -x $i ; then
+# echo "trying absprog $i"
+	base=`echo $i | sed 's-^.*/\([^/]*\)$-\1-p'`
+	if test -x $base ; then
+		rm $base
+# echo "nuking $base"
+	fi
+# echo "linking $i"
+	ln -s $i 
+	else
+		echo "COULDN'T FIND $i"
+	fi
+done
+
+cd ..
+
+echo "Build path is `pwd`/$BUILD_PATH"
+echo "contents of build path: "
+ls -l $BUILD_PATH
+PATH=`pwd`/$BUILD_PATH
+export PATH
+echo "======"
+
+echo "configuring with: $SRCDIR/configure $CONFIG_OPTS"
+$SRCDIR/configure $CONFIG_OPTS
+
+echo "Configuration done.  Building using the command:"
+echo "	(setenv PATH $PATH; make $MAKETARGETS)"
+echo " "
+
+make $MAKETARGETS
diff --git a/mechglue/src/util/kfrags/.Sanitize b/mechglue/src/util/kfrags/.Sanitize
new file mode 100644
index 000000000..82814fe28
--- /dev/null
+++ b/mechglue/src/util/kfrags/.Sanitize
@@ -0,0 +1,40 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+ChangeLog
+athena.conf
+base.conf
+cns.conf
+gcc.conf
+ranlib.conf
+sunpro.conf
+svr4.conf
+ucb.conf
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/util/kfrags/ChangeLog b/mechglue/src/util/kfrags/ChangeLog
new file mode 100644
index 000000000..7959ad940
--- /dev/null
+++ b/mechglue/src/util/kfrags/ChangeLog
@@ -0,0 +1,37 @@
+Thu Oct 31 12:39:42 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* shared.conf: Add for compiling with shared libraries
+
+	* base.conf: Add "uname" for config.guess
+
+Tue Nov  1 20:19:17 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* base.conf: add "ls" and "touch" since libupdate uses them
+
+Fri Oct 28 19:18:40 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* ranlib.conf: new file. some svr4 need ranlib too.
+
+Fri Oct 28 19:06:12 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* gcc.conf (CC_OPTS): don't set CC_OPTS until we figure out
+	quoting again.
+
+Tue Oct 18 14:38:58 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* base.conf: add "sort" since "make check" needs it.
+
+Tue Oct 11 19:10:13 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* ucb.conf: add "ranlib" for ucb, it's a common element.
+	* sunpro.conf: New file. Points to Sun (not MIT) installation path
+	for their unbundled compiler ("SUNWspro").
+
+Thu Sep 29 19:55:43 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* base.conf: simplest path, lists all executables.
+	* ucb.conf: add /usr/ucb to the base path.
+	* svr4.conf: add /usr/ccs/bin instead.
+	* athena.conf: sets KRB4 to /usr/athena.
+	* cns.conf: sets KRB4 to /usr/kerberos.
+	* gcc.conf: overrids CC and CC_OPTS for gcc -g -O -Wall.
diff --git a/mechglue/src/util/kfrags/athena.conf b/mechglue/src/util/kfrags/athena.conf
new file mode 100644
index 000000000..86e9f34c8
--- /dev/null
+++ b/mechglue/src/util/kfrags/athena.conf
@@ -0,0 +1 @@
+KRB4=/usr/athena
diff --git a/mechglue/src/util/kfrags/base.conf b/mechglue/src/util/kfrags/base.conf
new file mode 100644
index 000000000..f6b3b348f
--- /dev/null
+++ b/mechglue/src/util/kfrags/base.conf
@@ -0,0 +1,16 @@
+PATH=/bin:/usr/bin
+cp rm mv test cat cmp echo true ls touch
+
+awk sed grep egrep chmod mkdir tr ln
+
+ar lex yacc
+
+install
+cc
+make
+
+# for "make check"
+sort
+
+# For config.guess
+uname
diff --git a/mechglue/src/util/kfrags/cns.conf b/mechglue/src/util/kfrags/cns.conf
new file mode 100644
index 000000000..63327bc05
--- /dev/null
+++ b/mechglue/src/util/kfrags/cns.conf
@@ -0,0 +1 @@
+KRB4=/usr/kerberos
diff --git a/mechglue/src/util/kfrags/gcc.conf b/mechglue/src/util/kfrags/gcc.conf
new file mode 100644
index 000000000..4019d8284
--- /dev/null
+++ b/mechglue/src/util/kfrags/gcc.conf
@@ -0,0 +1,2 @@
+CC=gcc
+# CC_OPTS=" -g -O -Wall " doesn't work
diff --git a/mechglue/src/util/kfrags/ranlib.conf b/mechglue/src/util/kfrags/ranlib.conf
new file mode 100644
index 000000000..6906e90ca
--- /dev/null
+++ b/mechglue/src/util/kfrags/ranlib.conf
@@ -0,0 +1 @@
+ranlib
diff --git a/mechglue/src/util/kfrags/shared.conf b/mechglue/src/util/kfrags/shared.conf
new file mode 100644
index 000000000..ba5bb74c2
--- /dev/null
+++ b/mechglue/src/util/kfrags/shared.conf
@@ -0,0 +1,4 @@
+# For shared libraries
+SHARED=true
+# ld is needed on the Alpha.
+ld
diff --git a/mechglue/src/util/kfrags/sunpro.conf b/mechglue/src/util/kfrags/sunpro.conf
new file mode 100644
index 000000000..c79a57bc4
--- /dev/null
+++ b/mechglue/src/util/kfrags/sunpro.conf
@@ -0,0 +1 @@
+/opt/SUNWspro/bin/cc
diff --git a/mechglue/src/util/kfrags/svr4.conf b/mechglue/src/util/kfrags/svr4.conf
new file mode 100644
index 000000000..9a455cf31
--- /dev/null
+++ b/mechglue/src/util/kfrags/svr4.conf
@@ -0,0 +1 @@
+PATH=/bin:/usr/bin:/usr/ccs/bin
diff --git a/mechglue/src/util/kfrags/ucb.conf b/mechglue/src/util/kfrags/ucb.conf
new file mode 100644
index 000000000..19ca6b176
--- /dev/null
+++ b/mechglue/src/util/kfrags/ucb.conf
@@ -0,0 +1,2 @@
+PATH=/bin:/usr/bin:/usr/ucb
+ranlib
diff --git a/mechglue/src/util/lndir b/mechglue/src/util/lndir
new file mode 100755
index 000000000..31566c6bf
--- /dev/null
+++ b/mechglue/src/util/lndir
@@ -0,0 +1,103 @@
+#! /bin/sh
+
+# lndir - create shadow link tree
+#
+# Time stamp <89/11/28 18:56:54 gildea>
+# By Stephen Gildea <gildea@bbn.com> based on
+#  XConsortium: lndir.sh,v 1.1 88/10/20 17:37:16 jim Exp
+#
+# Used to create a copy of the a directory tree that has links for all non-
+# directories (except those named RCS).  If you are building the distribution
+# on more than one machine, you should use this script.
+#
+# If your master sources are located in /usr/local/src/X and you would like
+# your link tree to be in /usr/local/src/new-X, do the following:
+#
+# 	%  mkdir /usr/local/src/new-X
+#	%  cd /usr/local/src/new-X
+# 	%  lndir ../X
+#
+# Note: does not link files beginning with "."  Is this a bug or a feature?
+#
+# Improvements over R3 version:
+#   Allows the fromdir to be relative: usually you want to say "../dist"
+#   The name is relative to the todir, not the current directory.
+#
+# Bugs in R3 version fixed:
+#   Do "pwd" command *after* "cd $DIRTO".
+#   Don't try to link directories, avoiding error message "<dir> exists".
+#   Barf with Usage message if either DIRFROM *or* DIRTO is not a directory.
+
+USAGE="Usage: $0 fromdir [todir]"
+
+case $0 in 
+/*) lndir=$0 ;;
+*/*) lndir=`pwd`/$0 ;;
+*) lndir=$0 ;;
+esac
+
+if [ $# -lt 1 -o $# -gt 2 ]
+then
+	echo "$USAGE"
+	exit 1
+fi
+
+DIRFROM=$1
+
+if [ $# -eq 2 ];
+then
+	DIRTO=$2
+else
+	DIRTO=.
+fi
+
+if [ ! -d $DIRTO ]
+then
+	echo "$0: $DIRTO is not a directory"
+	echo "$USAGE"
+	exit 2
+fi
+
+cd $DIRTO
+
+if [ ! -d $DIRFROM ]
+then
+	echo "$0: $DIRFROM is not a directory"
+	echo "$USAGE"
+	exit 2
+fi
+
+pwd=`pwd`
+
+if [ `(cd $DIRFROM; pwd)` = $pwd ]
+then
+	echo "$pwd: FROM and TO are identical!"
+	exit 1
+fi
+
+for file in `ls -a $DIRFROM`
+do
+	if [ ! -d $DIRFROM/$file ]
+	then
+		ln -s $DIRFROM/$file .
+	else
+	       if [ $file != RCS -a $file != CVS -a $file != . -a $file != .. ]
+		then
+			echo $file:
+			mkdir $file
+			(cd $file
+			 pwd=`pwd`
+			 case "$DIRFROM" in
+				 /*) ;;
+				 *)  DIRFROM=../$DIRFROM ;;
+			 esac
+			 if [ `(cd $DIRFROM/$file; pwd)` = $pwd ]
+			 then
+				echo "$pwd: FROM and TO are identical!"
+				exit 1
+			 fi
+			 $lndir $DIRFROM/$file
+			)
+		fi
+	fi
+done
diff --git a/mechglue/src/util/makedepend/.Sanitize b/mechglue/src/util/makedepend/.Sanitize
new file mode 100644
index 000000000..45eae8dc2
--- /dev/null
+++ b/mechglue/src/util/makedepend/.Sanitize
@@ -0,0 +1,42 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+ChangeLog
+cpp.ed
+cppsetup.c
+def.h
+ifparser.c
+ifparser.h
+include.c
+main.c
+mkdepend.man
+parse.c
+pr.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/util/makedepend/ChangeLog b/mechglue/src/util/makedepend/ChangeLog
new file mode 100644
index 000000000..3cea4feb4
--- /dev/null
+++ b/mechglue/src/util/makedepend/ChangeLog
@@ -0,0 +1,5 @@
+Wed Mar 29 08:58:37 1995  John Gilmore  (gnu at toad.com)
+
+	* def.h:  Replace STDARG_PROTOTYPES with HAVE_STDARG_H.
+
+
diff --git a/mechglue/src/util/makedepend/cpp.ed b/mechglue/src/util/makedepend/cpp.ed
new file mode 100644
index 000000000..ffa586f54
--- /dev/null
+++ b/mechglue/src/util/makedepend/cpp.ed
@@ -0,0 +1,75 @@
+#
+# $XConsortium: cpp.ed,v 1.3 89/12/12 12:44:18 jim Exp $
+#
+# $Locker $
+#
+/struct symtab stab/d
+/struct symtab \*defloc;/d
+/struct symtab \*udfloc;/d
+/struct symtab \*incloc;/d
+/struct symtab \*ifloc;/d
+/struct symtab \*elsloc;/d
+/struct symtab \*eifloc;/d
+/struct symtab \*ifdloc;/d
+/struct symtab \*ifnloc;/d
+/struct symtab \*ysysloc;/d
+/struct symtab \*varloc;/d
+/struct symtab \*lneloc;/d
+/struct symtab \*ulnloc;/d
+/struct symtab \*uflloc;/d
+/^sayline(/s/$/	DELETED/p
+.,/^}/d
+/^unfill(/s/$/	DELETED/p
+.-1,/^}/d
+/^doincl(/s/$/	DELETED/p
+.-1,/^}/d
+/^equfrm(/s/$/	DELETED/p
+.,/^}/d
+/^dodef(/s/$/	DELETED/p
+.-1,/^}/d
+/^control(/s/$/	DELETED/p
+.-1,/^}/d
+/^savestring(/s/$/	DELETED/p
+.-1,/^}/d
+/^stsym(/s/$/	DELETED/p
+.-1,/^}/d
+/^ppsym(/s/$/	DELETED/p
+.-1,/^}/d
+/^yyerror(/s/$/	DELETED/p
+.,/^}/d
+/^ppwarn(/s/$/	DELETED/p
+.,/^}/d
+/^lookup(/s/$/	DELETED/p
+.-1,/^}/d
+/^subst(/s/$/	DELETED/p
+.-1,/^}/d
+/^trmdir(/s/$/	DELETED/p
+.-1,/^}/d
+/^copy(/s/$/	DELETED/p
+.-1,/^}/d
+/^pperror(/s/$/	DELETED/p
+.,/^}/d
+/^main(/s/$/	CHANGED to cpp_varsetup(argc,argv)/p
+.c
+cpp_varsetup(argc,argv)
+.
+/^strdex(/s/$/	DELETED/p
+.-1,/^}/d
+/^ for(i=1; i<argc; i++)/s/$/	To the end DELETED/p
+.,$c
+}
+.
+/^dump(/s/$/	DELETED/p
+.,/^}/c
+dump() { fatal("dump\n"); }
+.
+/^refill(/s/$/	DELETED/p
+.,/^}/c
+refill() { fatal("refill\n"); }
+.
+/^slookup(/s/$/	DELETED/p
+.-1,/^}/c
+static struct symtab *slookup() { fatal("slookup\n"); }
+.
+w
+q
diff --git a/mechglue/src/util/makedepend/cppsetup.c b/mechglue/src/util/makedepend/cppsetup.c
new file mode 100644
index 000000000..bf1c4fc5e
--- /dev/null
+++ b/mechglue/src/util/makedepend/cppsetup.c
@@ -0,0 +1,242 @@
+/* $XConsortium: cppsetup.c,v 1.13 94/04/17 20:10:32 gildea Exp $ */
+/*
+
+Copyright (c) 1993, 1994  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+
+#include "def.h"
+
+#ifdef	CPP
+/*
+ * This file is strictly for the sake of cpy.y and yylex.c (if
+ * you indeed have the source for cpp).
+ */
+#define IB 1
+#define SB 2
+#define NB 4
+#define CB 8
+#define QB 16
+#define WB 32
+#define SALT '#'
+#if pdp11 | vax | ns16000 | mc68000 | ibm032
+#define COFF 128
+#else
+#define COFF 0
+#endif
+/*
+ * These variables used by cpy.y and yylex.c
+ */
+extern char	*outp, *inp, *newp, *pend;
+extern char	*ptrtab;
+extern char	fastab[];
+extern char	slotab[];
+
+/*
+ * cppsetup
+ */
+struct filepointer	*currentfile;
+struct inclist		*currentinc;
+
+cppsetup(line, filep, inc)
+	register char	*line;
+	register struct filepointer	*filep;
+	register struct inclist		*inc;
+{
+	register char *p, savec;
+	static boolean setupdone = FALSE;
+	boolean	value;
+
+	if (!setupdone) {
+		cpp_varsetup();
+		setupdone = TRUE;
+	}
+
+	currentfile = filep;
+	currentinc = inc;
+	inp = newp = line;
+	for (p=newp; *p; p++)
+		;
+
+	/*
+	 * put a newline back on the end, and set up pend, etc.
+	 */
+	*p++ = '\n';
+	savec = *p;
+	*p = '\0';
+	pend = p;
+
+	ptrtab = slotab+COFF;
+	*--inp = SALT; 
+	outp=inp; 
+	value = yyparse();
+	*p = savec;
+	return(value);
+}
+
+struct symtab *lookup(symbol)
+	char	*symbol;
+{
+	static struct symtab    undefined;
+	struct symtab   *sp;
+
+	sp = isdefined(symbol, currentinc, NULL);
+	if (sp == NULL) {
+		sp = &undefined;
+		sp->s_value = NULL;
+	}
+	return (sp);
+}
+
+pperror(tag, x0,x1,x2,x3,x4)
+	int	tag,x0,x1,x2,x3,x4;
+{
+	warning("\"%s\", line %d: ", currentinc->i_file, currentfile->f_line);
+	warning(x0,x1,x2,x3,x4);
+}
+
+
+yyerror(s)
+	register char	*s;
+{
+	fatalerr("Fatal error: %s\n", s);
+}
+#else /* not CPP */
+
+#include "ifparser.h"
+struct _parse_data {
+    struct filepointer *filep;
+    struct inclist *inc;
+    const char *line;
+};
+
+static const char *
+_my_if_errors (ip, cp, expecting)
+    IfParser *ip;
+    const char *cp;
+    const char *expecting;
+{
+    struct _parse_data *pd = (struct _parse_data *) ip->data;
+    int lineno = pd->filep->f_line;
+    char *filename = pd->inc->i_file;
+    char prefix[300];
+    int prefixlen;
+    int i;
+
+    sprintf (prefix, "\"%s\":%d", filename, lineno);
+    prefixlen = strlen(prefix);
+    fprintf (stderr, "%s:  %s", prefix, pd->line);
+    i = cp - pd->line;
+    if (i > 0 && pd->line[i-1] != '\n') {
+	putc ('\n', stderr);
+    }
+    for (i += prefixlen + 3; i > 0; i--) {
+	putc (' ', stderr);
+    }
+    fprintf (stderr, "^--- expecting %s\n", expecting);
+    return NULL;
+}
+
+
+#define MAXNAMELEN 256
+
+static struct symtab *
+_lookup_variable (ip, var, len)
+    IfParser *ip;
+    const char *var;
+    int len;
+{
+    char tmpbuf[MAXNAMELEN + 1];
+    struct _parse_data *pd = (struct _parse_data *) ip->data;
+
+    if (len > MAXNAMELEN)
+	return 0;
+
+    strncpy (tmpbuf, var, len);
+    tmpbuf[len] = '\0';
+    return isdefined (tmpbuf, pd->inc, NULL);
+}
+
+
+static int
+_my_eval_defined (ip, var, len)
+    IfParser *ip;
+    const char *var;
+    int len;
+{
+    if (_lookup_variable (ip, var, len))
+	return 1;
+    else
+	return 0;
+}
+
+#define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
+
+static int
+_my_eval_variable (ip, var, len)
+    IfParser *ip;
+    const char *var;
+    int len;
+{
+    struct symtab *s;
+
+    s = _lookup_variable (ip, var, len);
+    if (!s)
+	return 0;
+    do {
+	var = s->s_value;
+	if (!isvarfirstletter(*var))
+	    break;
+	s = _lookup_variable (ip, var, strlen(var));
+    } while (s);
+
+    return atoi(var);
+}
+
+
+cppsetup(line, filep, inc)
+	register char	*line;
+	register struct filepointer	*filep;
+	register struct inclist		*inc;
+{
+    IfParser ip;
+    struct _parse_data pd;
+    int val = 0;
+
+    pd.filep = filep;
+    pd.inc = inc;
+    pd.line = line;
+    ip.funcs.handle_error = _my_if_errors;
+    ip.funcs.eval_defined = _my_eval_defined;
+    ip.funcs.eval_variable = _my_eval_variable;
+    ip.data = (char *) &pd;
+
+    (void) ParseIfExpression (&ip, line, &val);
+    if (val)
+	return IF;
+    else
+	return IFFALSE;
+}
+#endif /* CPP */
+
diff --git a/mechglue/src/util/makedepend/def.h b/mechglue/src/util/makedepend/def.h
new file mode 100644
index 000000000..8a49b3215
--- /dev/null
+++ b/mechglue/src/util/makedepend/def.h
@@ -0,0 +1,135 @@
+/* $XConsortium: def.h,v 1.25 94/04/17 20:10:33 gildea Exp $ */
+/*
+
+Copyright (c) 1993, 1994  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define MAXDEFINES	512
+#define MAXFILES	512
+#define MAXDIRS		64
+#define SYMTABINC	10	/* must be > 1 for define() to work right */
+#define	TRUE		1
+#define	FALSE		0
+
+/* the following must match the directives table in main.c */
+#define	IF		0
+#define	IFDEF		1
+#define	IFNDEF		2
+#define	ELSE		3
+#define	ENDIF		4
+#define	DEFINE		5
+#define	UNDEF		6
+#define	INCLUDE		7
+#define	LINE		8
+#define	PRAGMA		9
+#define ERROR           10
+#define IDENT           11
+#define SCCS            12
+#define ELIF            13
+#define EJECT           14
+#define IFFALSE         15     /* pseudo value --- never matched */
+#define ELIFFALSE       16     /* pseudo value --- never matched */
+#define INCLUDEDOT      17     /* pseudo value --- never matched */
+#define IFGUESSFALSE    18     /* pseudo value --- never matched */
+#define ELIFGUESSFALSE  19     /* pseudo value --- never matched */
+
+#ifdef DEBUG
+extern int	_debugmask;
+/*
+ * debug levels are:
+ * 
+ *     0	show ifn*(def)*,endif
+ *     1	trace defined/!defined
+ *     2	show #include
+ *     3	show #include SYMBOL
+ *     4-6	unused
+ */
+#define debug(level,arg) { if (_debugmask & (1 << level)) warning arg; }
+#else
+#define	debug(level,arg) /**/
+#endif /* DEBUG */
+
+typedef	unsigned char boolean;
+
+struct symtab {
+	char	*s_name;
+	char	*s_value;
+};
+
+struct	inclist {
+	char		*i_incstring;	/* string from #include line */
+	char		*i_file;	/* path name of the include file */
+	struct inclist	**i_list;	/* list of files it itself includes */
+	int		i_listlen;	/* length of i_list */
+	struct symtab	*i_defs;	/* symbol table for this file */
+	int		i_ndefs;	/* current # defines */
+	int		i_deflen;	/* amount of space in table */
+	boolean		i_defchecked;	/* whether defines have been checked */
+	boolean		i_notified;	/* whether we have revealed includes */
+	boolean		i_marked;	/* whether it's in the makefile */
+	boolean		i_searched;	/* whether we have read this */
+	boolean         i_included_sym; /* whether #include SYMBOL was found */
+					/* Can't use i_list if TRUE */
+};
+
+struct filepointer {
+	char	*f_p;
+	char	*f_base;
+	char	*f_end;
+	long	f_len;
+	long	f_line;
+};
+
+#ifndef NO_STDLIB_H		/* X_NOT_STDC_ENV */
+#include <stdlib.h>
+#if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
+char *malloc(), *realloc();
+#endif /* macII */
+#else
+char			*malloc();
+char			*realloc();
+#endif
+
+char			*copy();
+char			*base_name();
+char			*getline();
+struct symtab		*slookup();
+struct symtab		*isdefined();
+struct symtab		*fdefined();
+struct filepointer	*getfile();
+struct inclist		*newinclude();
+struct inclist		*inc_path();
+
+#ifdef HAVE_STDARG_H	/* NeedVarargsPrototypes */
+extern fatalerr(char *, ...);
+extern warning(char *, ...);
+extern warning1(char *, ...);
+#endif
diff --git a/mechglue/src/util/makedepend/ifparser.c b/mechglue/src/util/makedepend/ifparser.c
new file mode 100644
index 000000000..e0f171d72
--- /dev/null
+++ b/mechglue/src/util/makedepend/ifparser.c
@@ -0,0 +1,451 @@
+/*
+ * $XConsortium: ifparser.c,v 1.7 94/01/18 21:30:50 rws Exp $
+ *
+ * Copyright 1992 Network Computing Devices, Inc.
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Network Computing Devices may not be
+ * used in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  Network Computing Devices makes
+ * no representations about the suitability of this software for any purpose.
+ * It is provided ``as is'' without express or implied warranty.
+ * 
+ * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * Author:  Jim Fulton
+ *          Network Computing Devices, Inc.
+ * 
+ * Simple if statement processor
+ *
+ * This module can be used to evaluate string representations of C language
+ * if constructs.  It accepts the following grammar:
+ * 
+ *     EXPRESSION	:=	VALUE
+ * 			 |	VALUE  BINOP	EXPRESSION
+ * 
+ *     VALUE		:=	'('  EXPRESSION  ')'
+ * 			 |	'!'  VALUE
+ * 			 |	'-'  VALUE
+ * 			 |	'defined'  '('  variable  ')'
+ * 			 |	'defined'  variable
+ *			 |	# variable '(' variable-list ')'
+ * 			 |	variable
+ * 			 |	number
+ * 
+ *     BINOP		:=	'*'	|  '/'	|  '%'
+ * 			 |	'+'	|  '-'
+ * 			 |	'<<'	|  '>>'
+ * 			 |	'<'	|  '>'	|  '<='  |  '>='
+ * 			 |	'=='	|  '!='
+ * 			 |	'&'	|  '|'
+ * 			 |	'&&'	|  '||'
+ * 
+ * The normal C order of precidence is supported.
+ * 
+ * 
+ * External Entry Points:
+ * 
+ *     ParseIfExpression		parse a string for #if
+ */
+
+#include "ifparser.h"
+#include <ctype.h>
+
+/****************************************************************************
+		   Internal Macros and Utilities for Parser
+ ****************************************************************************/
+
+#define DO(val) if (!(val)) return NULL
+#define CALLFUNC(ggg,fff) (*((ggg)->funcs.fff))
+#define SKIPSPACE(ccc) while (isspace(*ccc)) ccc++
+#define isvarfirstletter(ccc) (isalpha(ccc) || (ccc) == '_')
+
+
+static const char *
+parse_variable (g, cp, varp)
+    IfParser *g;
+    const char *cp;
+    const char **varp;
+{
+    SKIPSPACE (cp);
+
+    if (!isvarfirstletter (*cp))
+	return CALLFUNC(g, handle_error) (g, cp, "variable name");
+
+    *varp = cp;
+    /* EMPTY */
+    for (cp++; isalnum(*cp) || *cp == '_'; cp++) ;
+    return cp;
+}
+
+
+static const char *
+parse_number (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    SKIPSPACE (cp);
+
+    if (!isdigit(*cp))
+	return CALLFUNC(g, handle_error) (g, cp, "number");
+
+#ifdef WIN32
+    *valp = strtol(cp, &cp, 0);
+#else
+    *valp = atoi (cp);
+    /* EMPTY */
+    for (cp++; isdigit(*cp); cp++) ;
+#endif
+    return cp;
+}
+
+
+static const char *
+parse_value (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    const char *var;
+
+    *valp = 0;
+
+    SKIPSPACE (cp);
+    if (!*cp)
+	return cp;
+
+    switch (*cp) {
+      case '(':
+	DO (cp = ParseIfExpression (g, cp + 1, valp));
+	SKIPSPACE (cp);
+	if (*cp != ')') 
+	    return CALLFUNC(g, handle_error) (g, cp, ")");
+
+	return cp + 1;			/* skip the right paren */
+
+      case '!':
+	DO (cp = parse_value (g, cp + 1, valp));
+	*valp = !(*valp);
+	return cp;
+
+      case '-':
+	DO (cp = parse_value (g, cp + 1, valp));
+	*valp = -(*valp);
+	return cp;
+
+      case '#':
+	DO (cp = parse_variable (g, cp + 1, &var));
+	SKIPSPACE (cp);
+	if (*cp != '(')
+	    return CALLFUNC(g, handle_error) (g, cp, "(");
+	do {
+	    DO (cp = parse_variable (g, cp + 1, &var));
+	    SKIPSPACE (cp);
+	} while (*cp && *cp != ')');
+	if (*cp != ')')
+	    return CALLFUNC(g, handle_error) (g, cp, ")");
+	*valp = 1; /* XXX */
+	return cp + 1;
+
+      case 'd':
+	if (strncmp (cp, "defined", 7) == 0 && !isalnum(cp[7])) {
+	    int paren = 0;
+	    cp += 7;
+	    SKIPSPACE (cp);
+	    if (*cp == '(') {
+		paren = 1;
+		cp++;
+	    }
+	    DO (cp = parse_variable (g, cp, &var));
+	    SKIPSPACE (cp);
+	    if (paren && *cp != ')')
+		return CALLFUNC(g, handle_error) (g, cp, ")");
+	    *valp = (*(g->funcs.eval_defined)) (g, var, cp - var);
+	    return cp + paren;		/* skip the right paren */
+	}
+	/* fall out */
+    }
+
+    if (isdigit(*cp)) {
+	DO (cp = parse_number (g, cp, valp));
+    } else if (!isvarfirstletter(*cp))
+	return CALLFUNC(g, handle_error) (g, cp, "variable or number");
+    else {
+	DO (cp = parse_variable (g, cp, &var));
+	*valp = (*(g->funcs.eval_variable)) (g, var, cp - var);
+    }
+    
+    return cp;
+}
+
+
+
+static const char *
+parse_product (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_value (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '*':
+	DO (cp = parse_product (g, cp + 1, &rightval));
+	*valp = (*valp * rightval);
+	break;
+
+      case '/':
+	DO (cp = parse_product (g, cp + 1, &rightval));
+	*valp = (*valp / rightval);
+	break;
+
+      case '%':
+	DO (cp = parse_product (g, cp + 1, &rightval));
+	*valp = (*valp % rightval);
+	break;
+    }
+    return cp;
+}
+
+
+static const char *
+parse_sum (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_product (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '+':
+	DO (cp = parse_sum (g, cp + 1, &rightval));
+	*valp = (*valp + rightval);
+	break;
+
+      case '-':
+	DO (cp = parse_sum (g, cp + 1, &rightval));
+	*valp = (*valp - rightval);
+	break;
+    }
+    return cp;
+}
+
+
+static const char *
+parse_shift (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_sum (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '<':
+	if (cp[1] == '<') {
+	    DO (cp = parse_shift (g, cp + 2, &rightval));
+	    *valp = (*valp << rightval);
+	}
+	break;
+
+      case '>':
+	if (cp[1] == '>') {
+	    DO (cp = parse_shift (g, cp + 2, &rightval));
+	    *valp = (*valp >> rightval);
+	}
+	break;
+    }
+    return cp;
+}
+
+
+static const char *
+parse_inequality (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_shift (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '<':
+	if (cp[1] == '=') {
+	    DO (cp = parse_inequality (g, cp + 2, &rightval));
+	    *valp = (*valp <= rightval);
+	} else {
+	    DO (cp = parse_inequality (g, cp + 1, &rightval));
+	    *valp = (*valp < rightval);
+	}
+	break;
+
+      case '>':
+	if (cp[1] == '=') {
+	    DO (cp = parse_inequality (g, cp + 2, &rightval));
+	    *valp = (*valp >= rightval);
+	} else {
+	    DO (cp = parse_inequality (g, cp + 1, &rightval));
+	    *valp = (*valp > rightval);
+	}
+	break;
+    }
+    return cp;
+}
+
+
+static const char *
+parse_equality (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_inequality (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '=':
+	if (cp[1] == '=')
+	    cp++;
+	DO (cp = parse_equality (g, cp + 1, &rightval));
+	*valp = (*valp == rightval);
+	break;
+
+      case '!':
+	if (cp[1] != '=')
+	    break;
+	DO (cp = parse_equality (g, cp + 2, &rightval));
+	*valp = (*valp != rightval);
+	break;
+    }
+    return cp;
+}
+
+
+static const char *
+parse_band (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_equality (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '&':
+	if (cp[1] != '&') {
+	    DO (cp = parse_band (g, cp + 1, &rightval));
+	    *valp = (*valp & rightval);
+	}
+	break;
+    }
+    return cp;
+}
+
+
+static const char *
+parse_bor (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_band (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '|':
+	if (cp[1] != '|') {
+	    DO (cp = parse_bor (g, cp + 1, &rightval));
+	    *valp = (*valp | rightval);
+	}
+	break;
+    }
+    return cp;
+}
+
+
+static const char *
+parse_land (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_bor (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '&':
+	if (cp[1] != '&')
+	    return CALLFUNC(g, handle_error) (g, cp, "&&");
+	DO (cp = parse_land (g, cp + 2, &rightval));
+	*valp = (*valp && rightval);
+	break;
+    }
+    return cp;
+}
+
+
+static const char *
+parse_lor (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    int rightval;
+
+    DO (cp = parse_land (g, cp, valp));
+    SKIPSPACE (cp);
+
+    switch (*cp) {
+      case '|':
+	if (cp[1] != '|')
+	    return CALLFUNC(g, handle_error) (g, cp, "||");
+	DO (cp = parse_lor (g, cp + 2, &rightval));
+	*valp = (*valp || rightval);
+	break;
+    }
+    return cp;
+}
+
+
+/****************************************************************************
+			     External Entry Points
+ ****************************************************************************/
+
+const char *
+ParseIfExpression (g, cp, valp)
+    IfParser *g;
+    const char *cp;
+    int *valp;
+{
+    return parse_lor (g, cp, valp);
+}
+
+
diff --git a/mechglue/src/util/makedepend/ifparser.h b/mechglue/src/util/makedepend/ifparser.h
new file mode 100644
index 000000000..c33379822
--- /dev/null
+++ b/mechglue/src/util/makedepend/ifparser.h
@@ -0,0 +1,76 @@
+/*
+ * $XConsortium: ifparser.h,v 1.1 92/08/22 13:05:39 rws Exp $
+ *
+ * Copyright 1992 Network Computing Devices, Inc.
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Network Computing Devices may not be
+ * used in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  Network Computing Devices makes
+ * no representations about the suitability of this software for any purpose.
+ * It is provided ``as is'' without express or implied warranty.
+ * 
+ * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ * 
+ * Author:  Jim Fulton
+ *          Network Computing Devices, Inc.
+ * 
+ * Simple if statement processor
+ *
+ * This module can be used to evaluate string representations of C language
+ * if constructs.  It accepts the following grammar:
+ * 
+ *     EXPRESSION	:=	VALUE
+ * 			 |	VALUE  BINOP	EXPRESSION
+ * 
+ *     VALUE		:=	'('  EXPRESSION  ')'
+ * 			 |	'!'  VALUE
+ * 			 |	'-'  VALUE
+ * 			 |	'defined'  '('  variable  ')'
+ * 			 |	variable
+ * 			 |	number
+ * 
+ *     BINOP		:=	'*'	|  '/'	|  '%'
+ * 			 |	'+'	|  '-'
+ * 			 |	'<<'	|  '>>'
+ * 			 |	'<'	|  '>'	|  '<='  |  '>='
+ * 			 |	'=='	|  '!='
+ * 			 |	'&'	|  '|'
+ * 			 |	'&&'	|  '||'
+ * 
+ * The normal C order of precidence is supported.
+ * 
+ * 
+ * External Entry Points:
+ * 
+ *     ParseIfExpression		parse a string for #if
+ */
+
+#include <stdio.h>
+
+#define const /**/
+typedef int Bool;
+#define False 0
+#define True 1
+
+typedef struct _if_parser {
+    struct {				/* functions */
+	char *(*handle_error) (/* struct _if_parser *, const char *,
+				 const char * */);
+	int (*eval_variable) (/* struct _if_parser *, const char *, int */);
+	int (*eval_defined) (/* struct _if_parser *, const char *, int */);
+    } funcs;
+    char *data;
+} IfParser;
+
+char *ParseIfExpression (/* IfParser *, const char *, int * */);
+
diff --git a/mechglue/src/util/makedepend/include.c b/mechglue/src/util/makedepend/include.c
new file mode 100644
index 000000000..349020aff
--- /dev/null
+++ b/mechglue/src/util/makedepend/include.c
@@ -0,0 +1,295 @@
+/* $XConsortium: include.c,v 1.16 94/04/17 20:10:34 gildea Exp $ */
+/*
+
+Copyright (c) 1993, 1994  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+
+
+#include "def.h"
+
+extern struct	inclist	inclist[ MAXFILES ],
+			*inclistp;
+extern char	*includedirs[ ];
+extern char	*notdotdot[ ];
+extern boolean show_where_not;
+extern boolean warn_multiple;
+
+struct inclist *inc_path(file, include, dot)
+	register char	*file,
+			*include;
+	boolean	dot;
+{
+	static char	path[ BUFSIZ ];
+	register char		**pp, *p;
+	register struct inclist	*ip;
+	struct stat	st;
+	boolean	found = FALSE;
+
+	/*
+	 * Check all previously found include files for a path that
+	 * has already been expanded.
+	 */
+	for (ip = inclist; ip->i_file; ip++)
+	    if ((strcmp(ip->i_incstring, include) == 0) && !ip->i_included_sym)
+	    {
+		found = TRUE;
+		break;
+	    }
+
+	/*
+	 * If the path was surrounded by "" or is an absolute path,
+	 * then check the exact path provided.
+	 */
+	if (!found && (dot || *include == '/')) {
+		if (stat(include, &st) == 0) {
+			ip = newinclude(include, include);
+			found = TRUE;
+		}
+		else if (show_where_not)
+			warning1("\tnot in %s\n", include);
+	}
+
+	/*
+	 * See if this include file is in the directory of the
+	 * file being compiled.
+	 */
+	if (!found) {
+		for (p=file+strlen(file); p>file; p--)
+			if (*p == '/')
+				break;
+		if (p == file)
+			strcpy(path, include);
+		else {
+			strncpy(path, file, (p-file) + 1);
+			path[ (p-file) + 1 ] = '\0';
+			strcpy(path + (p-file) + 1, include);
+		}
+		remove_dotdot(path);
+		if (stat(path, &st) == 0) {
+			ip = newinclude(path, include);
+			found = TRUE;
+		}
+		else if (show_where_not)
+			warning1("\tnot in %s\n", path);
+	}
+
+	/*
+	 * Check the include directories specified. (standard include dir
+	 * should be at the end.)
+	 */
+	if (!found)
+		for (pp = includedirs; *pp; pp++) {
+			sprintf(path, "%s/%s", *pp, include);
+			remove_dotdot(path);
+			if (stat(path, &st) == 0) {
+				ip = newinclude(path, include);
+				found = TRUE;
+				break;
+			}
+			else if (show_where_not)
+				warning1("\tnot in %s\n", path);
+		}
+
+	if (!found)
+		ip = NULL;
+	return(ip);
+}
+
+/*
+ * Ocaisionally, pathnames are created that look like ../x/../y
+ * Any of the 'x/..' sequences within the name can be eliminated.
+ * (but only if 'x' is not a symbolic link!!)
+ */
+remove_dotdot(path)
+	char	*path;
+{
+	register char	*end, *from, *to, **cp;
+	char		*components[ MAXFILES ],
+			newpath[ BUFSIZ ];
+	boolean		component_copied;
+
+	/*
+	 * slice path up into components.
+	 */
+	to = newpath;
+	if (*path == '/')
+		*to++ = '/';
+	*to = '\0';
+	cp = components;
+	for (from=end=path; *end; end++)
+		if (*end == '/') {
+			while (*end == '/')
+				*end++ = '\0';
+			if (*from)
+				*cp++ = from;
+			from = end;
+		}
+	*cp++ = from;
+	*cp = NULL;
+
+	/*
+	 * Now copy the path, removing all 'x/..' components.
+	 */
+	cp = components;
+	component_copied = FALSE;
+	while(*cp) {
+		if (!isdot(*cp) && !isdotdot(*cp) && isdotdot(*(cp+1))) {
+			if (issymbolic(newpath, *cp))
+				goto dont_remove;
+			cp++;
+		} else {
+		dont_remove:
+			if (component_copied)
+				*to++ = '/';
+			component_copied = TRUE;
+			for (from = *cp; *from; )
+				*to++ = *from++;
+			*to = '\0';
+		}
+		cp++;
+	}
+	*to++ = '\0';
+
+	/*
+	 * copy the reconstituted path back to our pointer.
+	 */
+	strcpy(path, newpath);
+}
+
+isdot(p)
+	register char	*p;
+{
+	if(p && *p++ == '.' && *p++ == '\0')
+		return(TRUE);
+	return(FALSE);
+}
+
+isdotdot(p)
+	register char	*p;
+{
+	if(p && *p++ == '.' && *p++ == '.' && *p++ == '\0')
+		return(TRUE);
+	return(FALSE);
+}
+
+issymbolic(dir, component)
+	register char	*dir, *component;
+{
+#ifdef S_IFLNK
+	struct stat	st;
+	char	buf[ BUFSIZ ], **pp;
+
+	sprintf(buf, "%s%s%s", dir, *dir ? "/" : "", component);
+	for (pp=notdotdot; *pp; pp++)
+		if (strcmp(*pp, buf) == 0)
+			return (TRUE);
+	if (lstat(buf, &st) == 0
+	&& (st.st_mode & S_IFMT) == S_IFLNK) {
+		*pp++ = copy(buf);
+		if (pp >= ¬dotdot[ MAXDIRS ])
+			fatalerr("out of .. dirs, increase MAXDIRS\n");
+		return(TRUE);
+	}
+#endif
+	return(FALSE);
+}
+
+/*
+ * Add an include file to the list of those included by 'file'.
+ */
+struct inclist *newinclude(newfile, incstring)
+	register char	*newfile, *incstring;
+{
+	register struct inclist	*ip;
+
+	/*
+	 * First, put this file on the global list of include files.
+	 */
+	ip = inclistp++;
+	if (inclistp == inclist + MAXFILES - 1)
+		fatalerr("out of space: increase MAXFILES\n");
+	ip->i_file = copy(newfile);
+	ip->i_included_sym = FALSE;
+	if (incstring == NULL)
+		ip->i_incstring = ip->i_file;
+	else
+		ip->i_incstring = copy(incstring);
+
+	return(ip);
+}
+
+included_by(ip, newfile)
+	register struct inclist	*ip, *newfile;
+{
+	register i;
+
+	if (ip == NULL)
+		return;
+	/*
+	 * Put this include file (newfile) on the list of files included
+	 * by 'file'.  If 'file' is NULL, then it is not an include
+	 * file itself (i.e. was probably mentioned on the command line).
+	 * If it is already on the list, don't stick it on again.
+	 */
+	if (ip->i_list == NULL)
+		ip->i_list = (struct inclist **)
+			malloc(sizeof(struct inclist *) * ++ip->i_listlen);
+	else {
+		for (i=0; i<ip->i_listlen; i++)
+			if (ip->i_list[ i ] == newfile) {
+			    i = strlen(newfile->i_file);
+			    if (!ip->i_included_sym &&
+				!(i > 2 &&
+				  newfile->i_file[i-1] == 'c' &&
+				  newfile->i_file[i-2] == '.'))
+			    {
+				/* only bitch if ip has */
+				/* no #include SYMBOL lines  */
+				/* and is not a .c file */
+				if (warn_multiple)
+				{
+					warning("%s includes %s more than once!\n",
+						ip->i_file, newfile->i_file);
+					warning1("Already have\n");
+					for (i=0; i<ip->i_listlen; i++)
+						warning1("\t%s\n", ip->i_list[i]->i_file);
+				}
+			    }
+			    return;
+			}
+		ip->i_list = (struct inclist **) realloc(ip->i_list,
+			sizeof(struct inclist *) * ++ip->i_listlen);
+	}
+	ip->i_list[ ip->i_listlen-1 ] = newfile;
+}
+
+inc_clean ()
+{
+	register struct inclist *ip;
+
+	for (ip = inclist; ip < inclistp; ip++) {
+		ip->i_marked = FALSE;
+	}
+}
diff --git a/mechglue/src/util/makedepend/main.c b/mechglue/src/util/makedepend/main.c
new file mode 100644
index 000000000..ccf35147c
--- /dev/null
+++ b/mechglue/src/util/makedepend/main.c
@@ -0,0 +1,688 @@
+/* $XConsortium: main.c,v 1.83 94/04/17 20:10:36 gildea Exp $ */
+/*
+
+Copyright (c) 1993, 1994  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+
+#include "def.h"
+#ifdef hpux
+#define sigvec sigvector
+#endif /* hpux */
+
+#include <signal.h>
+
+#if NeedVarargsPrototypes
+#include <stdarg.h>
+#endif
+
+#ifdef DEBUG
+int	_debugmask;
+#endif
+
+char *ProgramName;
+
+char	*directives[] = {
+	"if",
+	"ifdef",
+	"ifndef",
+	"else",
+	"endif",
+	"define",
+	"undef",
+	"include",
+	"line",
+	"pragma",
+	"error",
+	"ident",
+	"sccs",
+	"elif",
+	"eject",
+	NULL
+};
+
+#define MAKEDEPEND
+#include "imakemdep.h"	/* from config sources */
+#undef MAKEDEPEND
+
+struct	inclist inclist[ MAXFILES ],
+		*inclistp = inclist,
+		maininclist;
+
+char	*filelist[ MAXFILES ];
+char	*includedirs[ MAXDIRS + 1 ];
+char	*notdotdot[ MAXDIRS ];
+char	*objprefix = "";
+char	*objsuffix = OBJSUFFIX;
+char	*startat = "# DO NOT DELETE";
+int	width = 78;
+boolean	append = FALSE;
+boolean	printed = FALSE;
+boolean	verbose = FALSE;
+boolean	show_where_not = FALSE;
+boolean warn_multiple = FALSE;	/* Warn on multiple includes of same file */
+
+static
+#ifdef SIGNALRETURNSINT
+int
+#else
+void
+#endif
+catch (sig)
+    int sig;
+{
+	fflush (stdout);
+	fatalerr ("got signal %d\n", sig);
+}
+
+#if defined(USG) || (defined(SYSV386) && defined(SYSV)) || defined(WIN32)
+#define USGISH
+#endif
+
+#ifndef USGISH
+#ifndef _POSIX_SOURCE
+#define sigaction sigvec
+#define sa_handler sv_handler
+#define sa_mask sv_mask
+#define sa_flags sv_flags
+#endif
+struct sigaction sig_act;
+#endif /* USGISH */
+
+main(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	register char	**fp = filelist;
+	register char	**incp = includedirs;
+	register char	*p;
+	register struct inclist	*ip;
+	char	*makefile = NULL;
+	struct filepointer	*filecontent;
+	struct symtab *psymp = predefs;
+	char *endmarker = NULL;
+	char *defincdir = NULL;
+
+	ProgramName = argv[0];
+
+	while (psymp->s_name)
+	{
+	    define2(psymp->s_name, psymp->s_value, &maininclist);
+	    psymp++;
+	}
+	if (argc == 2 && argv[1][0] == '@') {
+	    struct stat ast;
+	    int afd;
+	    char *args;
+	    char **nargv;
+	    int nargc;
+	    char quotechar = '\0';
+
+	    nargc = 1;
+	    if ((afd = open(argv[1]+1, O_RDONLY)) < 0)
+		fatalerr("cannot open \"%s\"\n", argv[1]+1);
+	    fstat(afd, &ast);
+	    args = (char *)malloc(ast.st_size + 1);
+	    if ((ast.st_size = read(afd, args, ast.st_size)) < 0)
+		fatalerr("failed to read %s\n", argv[1]+1);
+	    args[ast.st_size] = '\0';
+	    close(afd);
+	    for (p = args; *p; p++) {
+		if (quotechar) {
+		    if (quotechar == '\\' ||
+			(*p == quotechar && p[-1] != '\\'))
+			quotechar = '\0';
+		    continue;
+		}
+		switch (*p) {
+		case '\\':
+		case '"':
+		case '\'':
+		    quotechar = *p;
+		    break;
+		case ' ':
+		case '\n':
+		    *p = '\0';
+		    if (p > args && p[-1])
+			nargc++;
+		    break;
+		}
+	    }
+	    if (p[-1])
+		nargc++;
+	    nargv = (char **)malloc(nargc * sizeof(char *));
+	    nargv[0] = argv[0];
+	    argc = 1;
+	    for (p = args; argc < nargc; p += strlen(p) + 1)
+		if (*p) nargv[argc++] = p;
+	    argv = nargv;
+	}
+	for(argc--, argv++; argc; argc--, argv++) {
+	    	/* if looking for endmarker then check before parsing */
+		if (endmarker && strcmp (endmarker, *argv) == 0) {
+		    endmarker = NULL;
+		    continue;
+		}
+		if (**argv != '-') {
+			/* treat +thing as an option for C++ */
+			if (endmarker && **argv == '+')
+				continue;
+			*fp++ = argv[0];
+			continue;
+		}
+		switch(argv[0][1]) {
+		case '-':
+			endmarker = &argv[0][2];
+			if (endmarker[0] == '\0') endmarker = "--";
+			break;
+		case 'D':
+			if (argv[0][2] == '\0') {
+				argv++;
+				argc--;
+			}
+			for (p=argv[0] + 2; *p ; p++)
+				if (*p == '=') {
+					*p = ' ';
+					break;
+				}
+			define(argv[0] + 2, &maininclist);
+			break;
+		case 'I':
+			if (incp >= includedirs + MAXDIRS)
+			    fatalerr("Too many -I flags.\n");
+			*incp++ = argv[0]+2;
+			if (**(incp-1) == '\0') {
+				*(incp-1) = *(++argv);
+				argc--;
+			}
+			break;
+		case 'Y':
+			defincdir = argv[0]+2;
+			break;
+		/* do not use if endmarker processing */
+		case 'a':
+			if (endmarker) break;
+			append = TRUE;
+			break;
+		case 'w':
+			if (endmarker) break;
+			if (argv[0][2] == '\0') {
+				argv++;
+				argc--;
+				width = atoi(argv[0]);
+			} else
+				width = atoi(argv[0]+2);
+			break;
+		case 'o':
+			if (endmarker) break;
+			if (argv[0][2] == '\0') {
+				argv++;
+				argc--;
+				objsuffix = argv[0];
+			} else
+				objsuffix = argv[0]+2;
+			break;
+		case 'p':
+			if (endmarker) break;
+			if (argv[0][2] == '\0') {
+				argv++;
+				argc--;
+				objprefix = argv[0];
+			} else
+				objprefix = argv[0]+2;
+			break;
+		case 'v':
+			if (endmarker) break;
+			verbose = TRUE;
+#ifdef DEBUG
+			if (argv[0][2])
+				_debugmask = atoi(argv[0]+2);
+#endif
+			break;
+		case 's':
+			if (endmarker) break;
+			startat = argv[0]+2;
+			if (*startat == '\0') {
+				startat = *(++argv);
+				argc--;
+			}
+			if (*startat != '#')
+				fatalerr("-s flag's value should start %s\n",
+					"with '#'.");
+			break;
+		case 'f':
+			if (endmarker) break;
+			makefile = argv[0]+2;
+			if (*makefile == '\0') {
+				makefile = *(++argv);
+				argc--;
+			}
+			break;
+
+		case 'm':
+			warn_multiple = TRUE;
+			break;
+			
+		/* Ignore -O, -g so we can just pass ${CFLAGS} to
+		   makedepend
+		 */
+		case 'O':
+		case 'g':
+			break;
+		default:
+			if (endmarker) break;
+	/*		fatalerr("unknown opt = %s\n", argv[0]); */
+			warning("ignoring option %s\n", argv[0]);
+		}
+	}
+	if (!defincdir) {
+#ifdef PREINCDIR
+	    if (incp >= includedirs + MAXDIRS)
+		fatalerr("Too many -I flags.\n");
+	    *incp++ = PREINCDIR;
+#endif
+	    if (incp >= includedirs + MAXDIRS)
+		fatalerr("Too many -I flags.\n");
+	    *incp++ = INCLUDEDIR;
+#ifdef POSTINCDIR
+	    if (incp >= includedirs + MAXDIRS)
+		fatalerr("Too many -I flags.\n");
+	    *incp++ = POSTINCDIR;
+#endif
+	} else if (*defincdir) {
+	    if (incp >= includedirs + MAXDIRS)
+		fatalerr("Too many -I flags.\n");
+	    *incp++ = defincdir;
+	}
+
+	redirect(startat, makefile);
+
+	/*
+	 * catch signals.
+	 */
+#ifdef USGISH
+/*  should really reset SIGINT to SIG_IGN if it was.  */
+#ifdef SIGHUP
+	signal (SIGHUP, catch);
+#endif
+	signal (SIGINT, catch);
+#ifdef SIGQUIT
+	signal (SIGQUIT, catch);
+#endif
+	signal (SIGILL, catch);
+#ifdef SIGBUS
+	signal (SIGBUS, catch);
+#endif
+	signal (SIGSEGV, catch);
+#ifdef SIGSYS
+	signal (SIGSYS, catch);
+#endif
+#else
+	sig_act.sa_handler = catch;
+#ifdef _POSIX_SOURCE
+	sigemptyset(&sig_act.sa_mask);
+	sigaddset(&sig_act.sa_mask, SIGINT);
+	sigaddset(&sig_act.sa_mask, SIGQUIT);
+#ifdef SIGBUS
+	sigaddset(&sig_act.sa_mask, SIGBUS);
+#endif
+	sigaddset(&sig_act.sa_mask, SIGILL);
+	sigaddset(&sig_act.sa_mask, SIGSEGV);
+	sigaddset(&sig_act.sa_mask, SIGHUP);
+	sigaddset(&sig_act.sa_mask, SIGPIPE);
+#ifdef SIGSYS
+	sigaddset(&sig_act.sa_mask, SIGSYS);
+#endif
+#else
+	sig_act.sa_mask = ((1<<(SIGINT -1))
+			   |(1<<(SIGQUIT-1))
+#ifdef SIGBUS
+			   |(1<<(SIGBUS-1))
+#endif
+			   |(1<<(SIGILL-1))
+			   |(1<<(SIGSEGV-1))
+			   |(1<<(SIGHUP-1))
+			   |(1<<(SIGPIPE-1))
+#ifdef SIGSYS
+			   |(1<<(SIGSYS-1))
+#endif
+			   );
+#endif /* _POSIX_SOURCE */
+	sig_act.sa_flags = 0;
+	sigaction(SIGHUP, &sig_act, (struct sigaction *)0);
+	sigaction(SIGINT, &sig_act, (struct sigaction *)0);
+	sigaction(SIGQUIT, &sig_act, (struct sigaction *)0);
+	sigaction(SIGILL, &sig_act, (struct sigaction *)0);
+#ifdef SIGBUS
+	sigaction(SIGBUS, &sig_act, (struct sigaction *)0);
+#endif
+	sigaction(SIGSEGV, &sig_act, (struct sigaction *)0);
+#ifdef SIGSYS
+	sigaction(SIGSYS, &sig_act, (struct sigaction *)0);
+#endif
+#endif /* USGISH */
+
+	/*
+	 * now peruse through the list of files.
+	 */
+	for(fp=filelist; *fp; fp++) {
+		filecontent = getfile(*fp);
+		ip = newinclude(*fp, (char *)NULL);
+
+		find_includes(filecontent, ip, ip, 0, FALSE);
+		freefile(filecontent);
+		recursive_pr_include(ip, ip->i_file, base_name(*fp));
+		inc_clean();
+	}
+	if (printed)
+		printf("\n");
+	exit(0);
+}
+
+struct filepointer *getfile(file)
+	char	*file;
+{
+	register int	fd;
+	struct filepointer	*content;
+	struct stat	st;
+
+	content = (struct filepointer *)malloc(sizeof(struct filepointer));
+	if ((fd = open(file, O_RDONLY)) < 0) {
+		warning("cannot open \"%s\"\n", file);
+		content->f_p = content->f_base = content->f_end = (char *)malloc(1);
+		*content->f_p = '\0';
+		return(content);
+	}
+	fstat(fd, &st);
+	content->f_base = (char *)malloc(st.st_size+1);
+	if (content->f_base == NULL)
+		fatalerr("cannot allocate mem\n");
+	if ((st.st_size = read(fd, content->f_base, st.st_size)) < 0)
+		fatalerr("failed to read %s\n", file);
+	close(fd);
+	content->f_len = st.st_size+1;
+	content->f_p = content->f_base;
+	content->f_end = content->f_base + st.st_size;
+	*content->f_end = '\0';
+	content->f_line = 0;
+	return(content);
+}
+
+freefile(fp)
+	struct filepointer	*fp;
+{
+	free(fp->f_base);
+	free(fp);
+}
+
+char *copy(str)
+	register char	*str;
+{
+	register char	*p = (char *)malloc(strlen(str) + 1);
+
+	strcpy(p, str);
+	return(p);
+}
+
+match(str, list)
+	register char	*str, **list;
+{
+	register int	i;
+
+	for (i=0; *list; i++, list++)
+		if (strcmp(str, *list) == 0)
+			return(i);
+	return(-1);
+}
+
+/*
+ * Get the next line.  We only return lines beginning with '#' since that
+ * is all this program is ever interested in.
+ */
+char *getline(filep)
+	register struct filepointer	*filep;
+{
+	register char	*p,	/* walking pointer */
+			*eof,	/* end of file pointer */
+			*bol;	/* beginning of line pointer */
+	register	lineno;	/* line number */
+
+	p = filep->f_p;
+	eof = filep->f_end;
+	if (p >= eof)
+		return((char *)NULL);
+	lineno = filep->f_line;
+
+	for(bol = p--; ++p < eof; ) {
+		if (*p == '/' && *(p+1) == '*') { /* consume comments */
+			*p++ = ' ', *p++ = ' ';
+			while (*p) {
+				if (*p == '*' && *(p+1) == '/') {
+					*p++ = ' ', *p = ' ';
+					break;
+				}
+				else if (*p == '\n')
+					lineno++;
+				*p++ = ' ';
+			}
+			continue;
+		}
+#ifdef WIN32
+		else if (*p == '/' && *(p+1) == '/') { /* consume comments */
+			*p++ = ' ', *p++ = ' ';
+			while (*p && *p != '\n')
+				*p++ = ' ';
+			lineno++;
+			continue;
+		}
+#endif
+		else if (*p == '\\') {
+			if (*(p+1) == '\n') {
+				*p = ' ';
+				*(p+1) = ' ';
+				lineno++;
+			}
+		}
+		else if (*p == '\n') {
+			lineno++;
+			if (*bol == '#') {
+				register char *cp;
+
+				*p++ = '\0';
+				/* punt lines with just # (yacc generated) */
+				for (cp = bol+1; 
+				     *cp && (*cp == ' ' || *cp == '\t'); cp++);
+				if (*cp) goto done;
+			}
+			bol = p+1;
+		}
+	}
+	if (*bol != '#')
+		bol = NULL;
+done:
+	filep->f_p = p;
+	filep->f_line = lineno;
+	return(bol);
+}
+
+/*
+ * Strip the file name down to what we want to see in the Makefile.
+ * It will have objprefix and objsuffix around it.
+ */
+char *base_name(file)
+	register char	*file;
+{
+	register char	*p;
+
+	file = copy(file);
+	for(p=file+strlen(file); p>file && *p != '.'; p--) ;
+
+	if (*p == '.')
+		*p = '\0';
+	return(file);
+}
+
+#if defined(USG) && !defined(CRAY) && !defined(SVR4)
+int rename (from, to)
+    char *from, *to;
+{
+    (void) unlink (to);
+    if (link (from, to) == 0) {
+	unlink (from);
+	return 0;
+    } else {
+	return -1;
+    }
+}
+#endif /* USGISH */
+
+redirect(line, makefile)
+	char	*line,
+		*makefile;
+{
+	struct stat	st;
+	FILE	*fdin, *fdout;
+	char	backup[ BUFSIZ ],
+		buf[ BUFSIZ ];
+	boolean	found = FALSE;
+	int	len;
+
+	/*
+	 * if makefile is "-" then let it pour onto stdout.
+	 */
+	if (makefile && *makefile == '-' && *(makefile+1) == '\0')
+		return;
+
+	/*
+	 * use a default makefile is not specified.
+	 */
+	if (!makefile) {
+		if (stat("Makefile", &st) == 0)
+			makefile = "Makefile";
+		else if (stat("makefile", &st) == 0)
+			makefile = "makefile";
+		else
+			fatalerr("[mM]akefile is not present\n");
+	}
+	else
+	    stat(makefile, &st);
+	if ((fdin = fopen(makefile, "r")) == NULL)
+		fatalerr("cannot open \"%s\"\n", makefile);
+	sprintf(backup, "%s.bak", makefile);
+	unlink(backup);
+#ifdef WIN32
+	fclose(fdin);
+#endif
+	if (rename(makefile, backup) < 0)
+		fatalerr("cannot rename %s to %s\n", makefile, backup);
+#ifdef WIN32
+	if ((fdin = fopen(backup, "r")) == NULL)
+		fatalerr("cannot open \"%s\"\n", backup);
+#endif
+	if ((fdout = freopen(makefile, "w", stdout)) == NULL)
+		fatalerr("cannot open \"%s\"\n", backup);
+	len = strlen(line);
+	while (!found && fgets(buf, BUFSIZ, fdin)) {
+		if (*buf == '#' && strncmp(line, buf, len) == 0)
+			found = TRUE;
+		fputs(buf, fdout);
+	}
+	if (!found) {
+		if (verbose)
+		warning("Adding new delimiting line \"%s\" and dependencies...\n",
+			line);
+		puts(line); /* same as fputs(fdout); but with newline */
+	} else if (append) {
+	    while (fgets(buf, BUFSIZ, fdin)) {
+		fputs(buf, fdout);
+	    }
+	}
+	fflush(fdout);
+#if defined(USGISH) || defined(_SEQUENT_)
+	chmod(makefile, st.st_mode);
+#else
+        fchmod(fileno(fdout), st.st_mode);
+#endif /* USGISH */
+}
+
+#if NeedVarargsPrototypes
+fatalerr(char *msg, ...)
+#else
+/*VARARGS*/
+fatalerr(msg,x1,x2,x3,x4,x5,x6,x7,x8,x9)
+    char *msg;
+#endif
+{
+#if NeedVarargsPrototypes
+	va_list args;
+#endif
+	fprintf(stderr, "%s: error:  ", ProgramName);
+#if NeedVarargsPrototypes
+	va_start(args, msg);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+#else
+	fprintf(stderr, msg,x1,x2,x3,x4,x5,x6,x7,x8,x9);
+#endif
+	exit (1);
+}
+
+#if NeedVarargsPrototypes
+warning(char *msg, ...)
+#else
+/*VARARGS0*/
+warning(msg,x1,x2,x3,x4,x5,x6,x7,x8,x9)
+    char *msg;
+#endif
+{
+#if NeedVarargsPrototypes
+	va_list args;
+#endif
+	fprintf(stderr, "%s: warning:  ", ProgramName);
+#if NeedVarargsPrototypes
+	va_start(args, msg);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+#else
+	fprintf(stderr, msg,x1,x2,x3,x4,x5,x6,x7,x8,x9);
+#endif
+}
+
+#if NeedVarargsPrototypes
+warning1(char *msg, ...)
+#else
+/*VARARGS0*/
+warning1(msg,x1,x2,x3,x4,x5,x6,x7,x8,x9)
+    char *msg;
+#endif
+{
+#if NeedVarargsPrototypes
+	va_list args;
+	va_start(args, msg);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+#else
+	fprintf(stderr, msg,x1,x2,x3,x4,x5,x6,x7,x8,x9);
+#endif
+}
diff --git a/mechglue/src/util/makedepend/mkdepend.man b/mechglue/src/util/makedepend/mkdepend.man
new file mode 100644
index 000000000..72d1c87bf
--- /dev/null
+++ b/mechglue/src/util/makedepend/mkdepend.man
@@ -0,0 +1,370 @@
+.\" $XConsortium: mkdepend.man,v 1.15 94/04/17 20:10:37 gildea Exp $
+.\" Copyright (c) 1993, 1994  X Consortium
+.\" 
+.\" Permission is hereby granted, free of charge, to any person obtaining a
+.\" copy of this software and associated documentation files (the "Software"), 
+.\" to deal in the Software without restriction, including without limitation 
+.\" the rights to use, copy, modify, merge, publish, distribute, sublicense, 
+.\" and/or sell copies of the Software, and to permit persons to whom the 
+.\" Software furnished to do so, subject to the following conditions:
+.\" 
+.\" The above copyright notice and this permission notice shall be included in
+.\" all copies or substantial portions of the Software.
+.\" 
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 
+.\" THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
+.\" WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 
+.\" OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
+.\" SOFTWARE.
+.\" 
+.\" Except as contained in this notice, the name of the X Consortium shall not 
+.\" be used in advertising or otherwise to promote the sale, use or other 
+.\" dealing in this Software without prior written authorization from the 
+.\" X Consortium.
+.\" "
+.so man1/header.doc
+.TH MAKEDEPEND 1 \*h
+.UC 4
+.SH NAME
+makedepend \- create dependencies in makefiles
+.SH SYNOPSIS
+.B makedepend
+[
+.B \-Dname=def
+] [
+.B \-Dname
+] [
+.B \-Iincludedir
+] [
+.B \-Yincludedir
+] [
+.B \-a
+] [
+.B \-fmakefile
+] [
+.B \-oobjsuffix
+] [
+.B \-pobjprefix
+] [
+.B \-sstring
+] [
+.B \-wwidth
+] [
+.B \-v
+] [
+.B \-m
+] [
+\-\^\-
+.B otheroptions
+\-\^\-
+]
+sourcefile .\|.\|.
+.br
+.SH DESCRIPTION
+.B Makedepend
+reads each
+.I sourcefile
+in sequence and parses it like a C-preprocessor,
+processing all
+.I #include,
+.I #define,
+.I #undef,
+.I #ifdef,
+.I #ifndef,
+.I #endif,
+.I #if
+and
+.I #else
+directives so that it can correctly tell which
+.I #include,
+directives would be used in a compilation.
+Any
+.I #include,
+directives can reference files having other
+.I #include
+directives, and parsing will occur in these files as well.
+.PP
+Every file that a
+.I sourcefile
+includes,
+directly or indirectly,
+is what
+.B makedepend
+calls a "dependency".
+These dependencies are then written to a
+.I makefile
+in such a way that
+.B make(1)
+will know which object files must be recompiled when a dependency has changed.
+.PP
+By default,
+.B makedepend
+places its output in the file named
+.I makefile
+if it exists, otherwise
+.I Makefile.
+An alternate makefile may be specified with the
+.B \-f
+option.
+It first searches the makefile for
+the line
+.sp
+    # DO NOT DELETE THIS LINE \-\^\- make depend depends on it.
+.sp
+or one provided with the
+.B \-s
+option,
+as a delimiter for the dependency output.
+If it finds it, it will delete everything
+following this to the end of the makefile
+and put the output after this line.
+If it doesn't find it, the program
+will append the string to the end of the makefile
+and place the output following that.
+For each
+.I sourcefile
+appearing on the command line,
+.B makedepend
+puts lines in the makefile of the form
+.sp
+     sourcefile.o:\0dfile .\|.\|.
+.sp
+Where "sourcefile.o" is the name from the command
+line with its suffix replaced with ".o",
+and "dfile" is a dependency discovered in a
+.I #include
+directive while parsing
+.I sourcefile
+or one of the files it included.
+.SH EXAMPLE
+Normally,
+.B makedepend
+will be used in a makefile target so that typing "make depend" will
+bring the dependencies up to date for the makefile.
+For example,
+.nf
+    SRCS\0=\0file1.c\0file2.c\0.\|.\|.
+    CFLAGS\0=\0\-O\0\-DHACK\0\-I\^.\^.\^/foobar\0\-xyz
+    depend:
+            makedepend\0\-\^\-\0$(CFLAGS)\0\-\^\-\0$(SRCS)
+.fi
+.SH OPTIONS
+.B Makedepend
+will ignore any option that it does not understand so that you may use
+the same arguments that you would for
+.B cc(1).
+.TP 5
+.B \-Dname=def or \-Dname
+Define.
+This places a definition for
+.I name
+in
+.B makedepend's
+symbol table.
+Without 
+.I =def
+the symbol becomes defined as "1".
+.TP 5
+.B \-Iincludedir
+Include directory.
+This option tells
+.B makedepend
+to prepend
+.I includedir
+to its list of directories to search when it encounters
+a
+.I #include
+directive.
+By default,
+.B makedepend
+only searches the standard include directories (usually /usr/include
+and possibly a compiler-dependent directory).
+.TP 5
+.B \-Yincludedir
+Replace all of the standard include directories with the single specified
+include directory; you can omit the
+.I includedir
+to simply prevent searching the standard include directories.
+.TP 5
+.B \-a
+Append the dependencies to the end of the file instead of replacing them. 
+.TP 5
+.B \-fmakefile
+Filename.
+This allows you to specify an alternate makefile in which
+.B makedepend
+can place its output.
+.TP 5
+.B \-oobjsuffix
+Object file suffix.
+Some systems may have object files whose suffix is something other
+than ".o".
+This option allows you to specify another suffix, such as
+".b" with
+.I -o.b
+or ":obj"
+with
+.I -o:obj
+and so forth.
+.TP 5
+.B \-pobjprefix
+Object file prefix.
+The prefix is prepended to the name of the object file. This is
+usually used to designate a different directory for the object file.
+The default is the empty string.
+.TP 5
+.B \-sstring
+Starting string delimiter.
+This option permits you to specify
+a different string for
+.B makedepend
+to look for in the makefile.
+.TP 5
+.B \-wwidth
+Line width.
+Normally,
+.B makedepend
+will ensure that every output line that it writes will be no wider than
+78 characters for the sake of readability.
+This option enables you to change this width.
+.TP 5
+.B \-v
+Verbose operation.
+This option causes 
+.B makedepend
+to emit the list of files included by each input file on standard output.
+.TP 5
+.B \-m
+Warn about multiple inclusion.
+This option causes 
+.B makedepend
+to produce a warning if any input file includes another file more than
+once.  In previous versions of 
+.B makedepend
+this was the default behavior; the default has been changed to better
+match the behavior of the C compiler, which does not consider multiple
+inclusion to be an error.  This option is provided for backward 
+compatibility, and to aid in debugging problems related to multiple
+inclusion.
+.TP 5
+.B "\-\^\- options \-\^\-"
+If
+.B makedepend
+encounters a double hyphen (\-\^\-) in the argument list,
+then any unrecognized argument following it
+will be silently ignored; a second double hyphen terminates this
+special treatment.
+In this way,
+.B makedepend
+can be made to safely ignore esoteric compiler arguments that might
+normally be found in a CFLAGS
+.B make
+macro (see the
+.B EXAMPLE
+section above).
+All options that
+.B makedepend
+recognizes and appear between the pair of double hyphens
+are processed normally.
+.SH ALGORITHM
+The approach used in this program enables it to run an order of magnitude
+faster than any other "dependency generator" I have ever seen.
+Central to this performance are two assumptions:
+that all files compiled by a single
+makefile will be compiled with roughly the same
+.I -I
+and
+.I -D
+options;
+and that most files in a single directory will include largely the
+same files.
+.PP
+Given these assumptions,
+.B makedepend
+expects to be called once for each makefile, with
+all source files that are maintained by the
+makefile appearing on the command line.
+It parses each source and include
+file exactly once, maintaining an internal symbol table
+for each.
+Thus, the first file on the command line will take an amount of time
+proportional to the amount of time that a normal C preprocessor takes.
+But on subsequent files, if it encounter's an include file
+that it has already parsed, it does not parse it again.
+.PP
+For example,
+imagine you are compiling two files,
+.I file1.c
+and
+.I file2.c,
+they each include the header file
+.I header.h,
+and the file
+.I header.h
+in turn includes the files
+.I def1.h
+and
+.I def2.h.
+When you run the command
+.sp
+    makedepend\0file1.c\0file2.c
+.sp
+.B makedepend
+will parse
+.I file1.c
+and consequently,
+.I header.h
+and then
+.I def1.h
+and
+.I def2.h.
+It then decides that the dependencies for this file are
+.sp
+    file1.o:\0header.h\0def1.h\0def2.h
+.sp
+But when the program parses
+.I file2.c
+and discovers that it, too, includes
+.I header.h,
+it does not parse the file,
+but simply adds
+.I header.h,
+.I def1.h
+and
+.I def2.h
+to the list of dependencies for
+.I file2.o.
+.SH "SEE ALSO"
+cc(1), make(1)
+.SH BUGS
+.B makedepend
+parses, but does not currently evaluate, the SVR4
+#predicate(token-list) preprocessor expression;
+such expressions are simply assumed to be true.
+This may cause the wrong
+.I #include
+directives to be evaluated.
+.PP
+Imagine you are parsing two files,
+say
+.I file1.c
+and
+.I file2.c,
+each includes the file
+.I def.h.
+The list of files that
+.I def.h
+includes might truly be different when
+.I def.h
+is included by
+.I file1.c
+than when it is included by
+.I file2.c.
+But once
+.B makedepend
+arrives at a list of dependencies for a file,
+it is cast in concrete.
+.SH AUTHOR
+Todd Brunhoff, Tektronix, Inc. and MIT Project Athena
diff --git a/mechglue/src/util/makedepend/parse.c b/mechglue/src/util/makedepend/parse.c
new file mode 100644
index 000000000..cf557c0ba
--- /dev/null
+++ b/mechglue/src/util/makedepend/parse.c
@@ -0,0 +1,567 @@
+/* $XConsortium: parse.c,v 1.30 94/04/17 20:10:38 gildea Exp $ */
+/*
+
+Copyright (c) 1993, 1994  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+
+#include "def.h"
+
+extern char	*directives[];
+extern struct inclist	maininclist;
+
+find_includes(filep, file, file_red, recursion, failOK)
+	struct filepointer	*filep;
+	struct inclist		*file, *file_red;
+	int			recursion;
+	boolean			failOK;
+{
+	register char	*line;
+	register int	type;
+	boolean recfailOK;
+
+	while (line = getline(filep)) {
+		switch(type = deftype(line, filep, file_red, file, TRUE)) {
+		case IF:
+		doif:
+			type = find_includes(filep, file,
+				file_red, recursion+1, failOK);
+			while ((type == ELIF) || (type == ELIFFALSE) ||
+			       (type == ELIFGUESSFALSE))
+				type = gobble(filep, file, file_red);
+			if (type == ELSE)
+				gobble(filep, file, file_red);
+			break;
+		case IFFALSE:
+		case IFGUESSFALSE:
+		    doiffalse:
+			if (type == IFGUESSFALSE || type == ELIFGUESSFALSE)
+			    recfailOK = TRUE;
+			else
+			    recfailOK = failOK;
+			type = gobble(filep, file, file_red);
+			if (type == ELSE)
+			    find_includes(filep, file,
+					  file_red, recursion+1, recfailOK);
+			else
+			if (type == ELIF)
+			    goto doif;
+			else
+			if ((type == ELIFFALSE) || (type == ELIFGUESSFALSE))
+			    goto doiffalse;
+			break;
+		case IFDEF:
+		case IFNDEF:
+			if ((type == IFDEF && isdefined(line, file_red, NULL))
+			 || (type == IFNDEF && !isdefined(line, file_red, NULL))) {
+				debug(1,(type == IFNDEF ?
+				    "line %d: %s !def'd in %s via %s%s\n" : "",
+				    filep->f_line, line,
+				    file->i_file, file_red->i_file, ": doit"));
+				type = find_includes(filep, file,
+					file_red, recursion+1, failOK);
+				while (type == ELIF || type == ELIFFALSE || type == ELIFGUESSFALSE)
+					type = gobble(filep, file, file_red);
+				if (type == ELSE)
+					gobble(filep, file, file_red);
+			}
+			else {
+				debug(1,(type == IFDEF ?
+				    "line %d: %s !def'd in %s via %s%s\n" : "",
+				    filep->f_line, line,
+				    file->i_file, file_red->i_file, ": gobble"));
+				type = gobble(filep, file, file_red);
+				if (type == ELSE)
+					find_includes(filep, file,
+						file_red, recursion+1, failOK);
+				else if (type == ELIF)
+				    	goto doif;
+				else if (type == ELIFFALSE || type == ELIFGUESSFALSE)
+				    	goto doiffalse;
+			}
+			break;
+		case ELSE:
+		case ELIFFALSE:
+		case ELIFGUESSFALSE:
+		case ELIF:
+			if (!recursion)
+				gobble(filep, file, file_red);
+		case ENDIF:
+			if (recursion)
+				return(type);
+		case DEFINE:
+			define(line, file);
+			break;
+		case UNDEF:
+			if (!*line) {
+			    warning("%s, line %d: incomplete undef == \"%s\"\n",
+				file_red->i_file, filep->f_line, line);
+			    break;
+			}
+			undefine(line, file_red);
+			break;
+		case INCLUDE:
+			add_include(filep, file, file_red, line, FALSE, failOK);
+			break;
+		case INCLUDEDOT:
+			add_include(filep, file, file_red, line, TRUE, failOK);
+			break;
+		case ERROR:
+		    	warning("%s: %d: %s\n", file_red->i_file,
+				 filep->f_line, line);
+		    	break;
+		    
+		case PRAGMA:
+		case IDENT:
+		case SCCS:
+		case EJECT:
+			break;
+		case -1:
+			warning("%s", file_red->i_file);
+			if (file_red != file)
+			    warning1(" (reading %s)", file->i_file);
+			warning1(", line %d: unknown directive == \"%s\"\n",
+				 filep->f_line, line);
+			break;
+		case -2:
+			warning("%s", file_red->i_file);
+			if (file_red != file)
+			    warning1(" (reading %s)", file->i_file);
+			warning1(", line %d: incomplete include == \"%s\"\n",
+				 filep->f_line, line);
+			break;
+		}
+	}
+	return(-1);
+}
+
+gobble(filep, file, file_red)
+	register struct filepointer *filep;
+	struct inclist		*file, *file_red;
+{
+	register char	*line;
+	register int	type;
+
+	while (line = getline(filep)) {
+		switch(type = deftype(line, filep, file_red, file, FALSE)) {
+		case IF:
+		case IFFALSE:
+		case IFGUESSFALSE:
+		case IFDEF:
+		case IFNDEF:
+			type = gobble(filep, file, file_red);
+			while ((type == ELIF) || (type == ELIFFALSE) ||
+			       (type == ELIFGUESSFALSE))
+			    type = gobble(filep, file, file_red);
+			if (type == ELSE)
+			        (void)gobble(filep, file, file_red);
+			break;
+		case ELSE:
+		case ENDIF:
+			debug(0,("%s, line %d: #%s\n",
+				file->i_file, filep->f_line,
+				directives[type]));
+			return(type);
+		case DEFINE:
+		case UNDEF:
+		case INCLUDE:
+		case INCLUDEDOT:
+		case PRAGMA:
+		case ERROR:
+		case IDENT:
+		case SCCS:
+		case EJECT:
+			break;
+		case ELIF:
+		case ELIFFALSE:
+		case ELIFGUESSFALSE:
+			return(type);
+		case -1:
+			warning("%s, line %d: unknown directive == \"%s\"\n",
+				file_red->i_file, filep->f_line, line);
+			break;
+		}
+	}
+	return(-1);
+}
+
+/*
+ * Decide what type of # directive this line is.
+ */
+int deftype (line, filep, file_red, file, parse_it)
+	register char	*line;
+	register struct filepointer *filep;
+	register struct inclist *file_red, *file;
+	int	parse_it;
+{
+	register char	*p;
+	char	*directive, savechar;
+	register int	ret;
+
+	/*
+	 * Parse the directive...
+	 */
+	directive=line+1;
+	while (*directive == ' ' || *directive == '\t')
+		directive++;
+
+	p = directive;
+	while (*p >= 'a' && *p <= 'z')
+		p++;
+	savechar = *p;
+	*p = '\0';
+	ret = match(directive, directives);
+	*p = savechar;
+
+	/* If we don't recognize this compiler directive or we happen to just
+	 * be gobbling up text while waiting for an #endif or #elif or #else
+	 * in the case of an #elif we must check the zero_value and return an
+	 * ELIF or an ELIFFALSE.
+	 */
+
+	if (ret == ELIF && !parse_it)
+	{
+	    while (*p == ' ' || *p == '\t')
+		p++;
+	    /*
+	     * parse an expression.
+	     */
+	    debug(0,("%s, line %d: #elif %s ",
+		   file->i_file, filep->f_line, p));
+	    ret = zero_value(p, filep, file_red);
+	    if (ret != IF)
+	    {
+		debug(0,("false...\n"));
+		if (ret == IFFALSE)
+		    return(ELIFFALSE);
+		else
+		    return(ELIFGUESSFALSE);
+	    }
+	    else
+	    {
+		debug(0,("true...\n"));
+		return(ELIF);
+	    }
+	}
+
+	if (ret < 0 || ! parse_it)
+		return(ret);
+
+	/*
+	 * now decide how to parse the directive, and do it.
+	 */
+	while (*p == ' ' || *p == '\t')
+		p++;
+	switch (ret) {
+	case IF:
+		/*
+		 * parse an expression.
+		 */
+		ret = zero_value(p, filep, file_red);
+		debug(0,("%s, line %d: %s #if %s\n",
+			 file->i_file, filep->f_line, ret?"false":"true", p));
+		break;
+	case IFDEF:
+	case IFNDEF:
+		debug(0,("%s, line %d: #%s %s\n",
+			file->i_file, filep->f_line, directives[ret], p));
+	case UNDEF:
+		/*
+		 * separate the name of a single symbol.
+		 */
+		while (isalnum(*p) || *p == '_')
+			*line++ = *p++;
+		*line = '\0';
+		break;
+	case INCLUDE:
+		debug(2,("%s, line %d: #include %s\n",
+			file->i_file, filep->f_line, p));
+
+		/* Support ANSI macro substitution */
+		{
+		    struct symtab *sym = isdefined(p, file_red, NULL);
+		    while (sym) {
+			p = sym->s_value;
+			debug(3,("%s : #includes SYMBOL %s = %s\n",
+			       file->i_incstring,
+			       sym -> s_name,
+			       sym -> s_value));
+			/* mark file as having included a 'soft include' */
+			file->i_included_sym = TRUE; 
+			sym = isdefined(p, file_red, NULL);
+		    }
+		}
+
+		/*
+		 * Separate the name of the include file.
+		 */
+		while (*p && *p != '"' && *p != '<')
+			p++;
+		if (! *p)
+			return(-2);
+		if (*p++ == '"') {
+			ret = INCLUDEDOT;
+			while (*p && *p != '"')
+				*line++ = *p++;
+		} else
+			while (*p && *p != '>')
+				*line++ = *p++;
+		*line = '\0';
+		break;
+	case DEFINE:
+		/*
+		 * copy the definition back to the beginning of the line.
+		 */
+		strcpy (line, p);
+		break;
+	case ELSE:
+	case ENDIF:
+	case ELIF:
+	case PRAGMA:
+	case ERROR:
+	case IDENT:
+	case SCCS:
+	case EJECT:
+		debug(0,("%s, line %d: #%s\n",
+			file->i_file, filep->f_line, directives[ret]));
+		/*
+		 * nothing to do.
+		 */
+		break;
+	}
+	return(ret);
+}
+
+struct symtab *isdefined(symbol, file, srcfile)
+	register char	*symbol;
+	struct inclist	*file;
+	struct inclist	**srcfile;
+{
+	register struct symtab	*val;
+
+	if (val = slookup(symbol, &maininclist)) {
+		debug(1,("%s defined on command line\n", symbol));
+		if (srcfile != NULL) *srcfile = &maininclist;
+		return(val);
+	}
+	if (val = fdefined(symbol, file, srcfile))
+		return(val);
+	debug(1,("%s not defined in %s\n", symbol, file->i_file));
+	return(NULL);
+}
+
+struct symtab *fdefined(symbol, file, srcfile)
+	register char	*symbol;
+	struct inclist	*file;
+	struct inclist	**srcfile;
+{
+	register struct inclist	**ip;
+	register struct symtab	*val;
+	register int	i;
+	static int	recurse_lvl = 0;
+
+	if (file->i_defchecked)
+		return(NULL);
+	file->i_defchecked = TRUE;
+	if (val = slookup(symbol, file))
+		debug(1,("%s defined in %s as %s\n", symbol, file->i_file, val->s_value));
+	if (val == NULL && file->i_list)
+		{
+		for (ip = file->i_list, i=0; i < file->i_listlen; i++, ip++)
+			if (val = fdefined(symbol, *ip, srcfile)) {
+				break;
+			}
+		}
+	else if (val != NULL && srcfile != NULL) *srcfile = file;
+	recurse_lvl--;
+	file->i_defchecked = FALSE;
+
+	return(val);
+}
+
+/*
+ * Return type based on if the #if expression evaluates to 0
+ */
+zero_value(exp, filep, file_red)
+	register char	*exp;
+	register struct filepointer *filep;
+	register struct inclist *file_red;
+{
+	if (cppsetup(exp, filep, file_red))
+	    return(IFFALSE);
+	else
+	    return(IF);
+}
+
+define(def, file)
+	char	*def;
+	struct inclist	*file;
+{
+    char *val;
+
+    /* Separate symbol name and its value */
+    val = def;
+    while (isalnum(*val) || *val == '_')
+	val++;
+    if (*val)
+	*val++ = '\0';
+    while (*val == ' ' || *val == '\t')
+	val++;
+
+    if (!*val)
+	val = "1";
+    define2(def, val, file);
+}
+
+define2(name, val, file)
+	char	*name, *val;
+	struct inclist	*file;
+{
+    int first, last, below;
+    register struct symtab *sp = NULL, *dest;
+
+    /* Make space if it's needed */
+    if (file->i_defs == NULL)
+    {
+	file->i_defs = (struct symtab *)
+			malloc(sizeof (struct symtab) * SYMTABINC);
+	file->i_deflen = SYMTABINC;
+	file->i_ndefs = 0;
+    }
+    else if (file->i_ndefs == file->i_deflen)
+	file->i_defs = (struct symtab *)
+			realloc(file->i_defs,
+			    sizeof(struct symtab)*(file->i_deflen+=SYMTABINC));
+
+    if (file->i_defs == NULL)
+	fatalerr("malloc()/realloc() failure in insert_defn()\n");
+
+    below = first = 0;
+    last = file->i_ndefs - 1;
+    while (last >= first)
+    {
+	/* Fast inline binary search */
+	register char *s1;
+	register char *s2;
+	register int middle = (first + last) / 2;
+
+	/* Fast inline strchr() */
+	s1 = name;
+	s2 = file->i_defs[middle].s_name;
+	while (*s1++ == *s2++)
+	    if (s2[-1] == '\0') break;
+
+	/* If exact match, set sp and break */
+	if (*--s1 == *--s2) 
+	{
+	    sp = file->i_defs + middle;
+	    break;
+	}
+
+	/* If name > i_defs[middle] ... */
+	if (*s1 > *s2) 
+	{
+	    below = first;
+	    first = middle + 1;
+	}
+	/* else ... */
+	else
+	{
+	    below = last = middle - 1;
+	}
+    }
+
+    /* Search is done.  If we found an exact match to the symbol name,
+       just replace its s_value */
+    if (sp != NULL)
+    {
+	free(sp->s_value);
+	sp->s_value = copy(val);
+	return;
+    }
+
+    sp = file->i_defs + file->i_ndefs++;
+    dest = file->i_defs + below + 1;
+    while (sp > dest)
+    {
+	*sp = sp[-1];
+	sp--;
+    }
+    sp->s_name = copy(name);
+    sp->s_value = copy(val);
+}
+
+struct symtab *slookup(symbol, file)
+	register char	*symbol;
+	register struct inclist	*file;
+{
+	register int first = 0;
+	register int last = file->i_ndefs - 1;
+
+	if (file) while (last >= first)
+	{
+	    /* Fast inline binary search */
+	    register char *s1;
+	    register char *s2;
+	    register int middle = (first + last) / 2;
+
+	    /* Fast inline strchr() */
+	    s1 = symbol;
+	    s2 = file->i_defs[middle].s_name;
+	    while (*s1++ == *s2++)
+	        if (s2[-1] == '\0') break;
+
+	    /* If exact match, we're done */
+	    if (*--s1 == *--s2) 
+	    {
+	        return file->i_defs + middle;
+	    }
+
+	    /* If symbol > i_defs[middle] ... */
+	    if (*s1 > *s2) 
+	    {
+	        first = middle + 1;
+	    }
+	    /* else ... */
+	    else
+	    {
+	        last = middle - 1;
+	    }
+	}
+	return(NULL);
+}
+
+undefine(symbol, file)
+	char	*symbol;
+	register struct inclist	*file;
+{
+	register struct symtab *ptr;
+	struct inclist *srcfile;
+	while ((ptr = isdefined(symbol, file, &srcfile)) != NULL)
+	{
+	    srcfile->i_ndefs--;
+	    for (; ptr < srcfile->i_defs + srcfile->i_ndefs; ptr++)
+		*ptr = ptr[1];
+	}
+}
diff --git a/mechglue/src/util/makedepend/pr.c b/mechglue/src/util/makedepend/pr.c
new file mode 100644
index 000000000..407b1ec0b
--- /dev/null
+++ b/mechglue/src/util/makedepend/pr.c
@@ -0,0 +1,127 @@
+/* $XConsortium: pr.c,v 1.17 94/04/17 20:10:38 gildea Exp $ */
+/*
+
+Copyright (c) 1993, 1994  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+
+#include "def.h"
+
+extern struct	inclist	inclist[ MAXFILES ],
+			*inclistp;
+extern char	*objprefix;
+extern char	*objsuffix;
+extern int	width;
+extern boolean	printed;
+extern boolean	verbose;
+extern boolean	show_where_not;
+
+add_include(filep, file, file_red, include, dot, failOK)
+	struct filepointer	*filep;
+	struct inclist	*file, *file_red;
+	char	*include;
+	boolean	dot;
+{
+	register struct inclist	*newfile;
+	register struct filepointer	*content;
+
+	/*
+	 * First decide what the pathname of this include file really is.
+	 */
+	newfile = inc_path(file->i_file, include, dot);
+	if (newfile == NULL) {
+		if (failOK)
+		    return;
+		if (file != file_red)
+			warning("%s (reading %s, line %d): ",
+				file_red->i_file, file->i_file, filep->f_line);
+		else
+			warning("%s, line %d: ", file->i_file, filep->f_line);
+		warning1("cannot find include file \"%s\"\n", include);
+		show_where_not = TRUE;
+		newfile = inc_path(file->i_file, include, dot);
+		show_where_not = FALSE;
+	}
+
+	if (newfile) {
+		included_by(file, newfile);
+		if (!newfile->i_searched) {
+			newfile->i_searched = TRUE;
+			content = getfile(newfile->i_file);
+			find_includes(content, newfile, file_red, 0, failOK);
+			freefile(content);
+		}
+	}
+}
+
+recursive_pr_include(head, file, base)
+	register struct inclist	*head;
+	register char	*file, *base;
+{
+	register int	i;
+
+	if (head->i_marked)
+		return;
+	head->i_marked = TRUE;
+	if (head->i_file != file)
+		pr(head, file, base);
+	for (i=0; i<head->i_listlen; i++)
+		recursive_pr_include(head->i_list[ i ], file, base);
+}
+
+pr(ip, file, base)
+	register struct inclist  *ip;
+	char	*file, *base;
+{
+	static char	*lastfile;
+	static int	current_len;
+	register int	len, i;
+	char	buf[ BUFSIZ ];
+
+	printed = TRUE;
+	len = strlen(ip->i_file)+1;
+	if (current_len + len > width || file != lastfile) {
+		lastfile = file;
+		sprintf(buf, "\n%s%s%s: %s", objprefix, base, objsuffix,
+			ip->i_file);
+		len = current_len = strlen(buf);
+	}
+	else {
+		buf[0] = ' ';
+		strcpy(buf+1, ip->i_file);
+		current_len += len;
+	}
+	fwrite(buf, len, 1, stdout);
+
+	/*
+	 * If verbose is set, then print out what this file includes.
+	 */
+	if (! verbose || ip->i_list == NULL || ip->i_notified)
+		return;
+	ip->i_notified = TRUE;
+	lastfile = NULL;
+	printf("\n# %s includes:", ip->i_file);
+	for (i=0; i<ip->i_listlen; i++)
+		printf("\n#\t%s", ip->i_list[ i ]->i_incstring);
+}
diff --git a/mechglue/src/util/mkrel b/mechglue/src/util/mkrel
new file mode 100755
index 000000000..51d47afc9
--- /dev/null
+++ b/mechglue/src/util/mkrel
@@ -0,0 +1,220 @@
+#!/bin/sh
+set -e
+repository=svn+ssh://svn.mit.edu/krb5
+dodoc=t
+dosrc=t
+checkout=t
+multitar=nil
+while test $# -gt 2; do
+	case $1 in
+	--srconly)
+		dodoc=nil;;
+	--doconly)
+		dosrc=nil;;
+	--multi*)
+		multitar=t;;
+	--repository)
+		shift; repository=$1;;
+	--nocheckout)
+		checkout=nil;;
+	esac
+	shift
+done
+if test $# -lt 2; then
+	echo "usage: $0 [opts] release-tag release-dir"
+	echo "	release-tag is relative to $repository/"
+	exit 1
+fi
+
+reltag=$1
+reldir=$2
+
+relmajor=0
+relminor=0
+relpatch=0
+relhead=
+# reltail=
+reldate=`date +%Y%m%d`
+
+case "$reldir" in
+*/*)
+	echo "release-dir may not contain slashes."
+	exit 1
+	;;
+*" "*|*"	"*)
+	echo "release-dir may  not contain whitespace."
+	exit 1
+	;;
+krb5-*.*.*-*)
+	release=`echo $reldir|sed -e 's/krb5-//'`
+	relhead=`echo $release|sed -e 's/-.*//'`
+	reltail=`echo $release|sed -e 's/.*-//'`
+	relmajor=`echo $relhead|awk -F. '{print $1}'`
+	relminor=`echo $relhead|awk -F. '{print $2}'`
+	relpatch=`echo $relhead|awk -F. '{print $3}'`
+	;;
+krb5-*.*.*)
+	release=`echo $reldir|sed -e 's/krb5-//'`
+	relmajor=`echo $release|awk -F. '{print $1}'`
+	relminor=`echo $release|awk -F. '{print $2}'`
+	relpatch=`echo $release|awk -F. '{print $3}'`
+	;;
+krb5-*.*-current)
+	release=`echo $reldir|sed -e 's/krb5-//'`
+	relhead=`echo $release|sed -e 's/-.*//'`
+	relmajor=`echo $relhead|awk -F. '{print $1}'`
+	relminor=`echo $relhead|awk -F. '{print $2}'`
+	release=${relhead}-$reldate
+	;;
+krb5-*.*-*)
+	release=`echo $reldir|sed -e 's/krb5-//'`
+	relhead=`echo $release|sed -e 's/-.*//'`
+	reltail=`echo $release|sed -e 's/.*-//'`
+	relmajor=`echo $relhead|awk -F. '{print $1}'`
+	relminor=`echo $relhead|awk -F. '{print $2}'`
+	;;
+krb5-*.*)
+	release=`echo $reldir|sed -e 's/krb5-//'`
+	relmajor=`echo $release|awk -F. '{print $1}'`
+	relminor=`echo $release|awk -F. '{print $2}'`
+	;;
+krb5-current)
+	release=current-$reldate
+	;;
+*)
+	release="$reldir"
+	;;
+esac
+
+echo "release=$release"
+echo "major=$relmajor minor=$relminor patch=$relpatch"
+
+# $release is used for send-pr
+# $reltag, $release, $reldate are used for brand.c currently
+# $relmajor, $relminor, $relpatch are used for patchlevel.h currently
+
+#
+# $newstyle = t if patchlevel.h is the master version stamp file.  If
+# so, we don't edit it here.
+#
+if test $checkout = t; then
+	if svn cat $repository/$reltag/src/patchlevel.h | grep KRB5_RELDATE > /dev/null 2>&1; then
+		newstyle=t
+	else
+		newstyle=nil;
+	fi
+else
+	if grep KRB5_RELDATE $reldir/src/patchlevel.h > /dev/null 2>&1; then
+		newstyle=t;
+	else
+		newstyle=nil;
+	fi
+fi
+
+if test $newstyle = t; then
+	echo "parsing new style patchlevel.h..."
+	if test $checkout = t; then
+		eval `svn cat $repository/$reltag/src/patchlevel.h | sed -n 's/#define \([A-Z0-9_]*\)[ \t]*\(.*\)/\1=\2/p'`
+	else
+		eval `sed -n 's/#define \([A-Z0-9_]*\)[ \t]*\(.*\)/\1=\2/p' < $reldir/src/patchlevel.h`
+	fi
+	if test "$KRB5_RELTAG" != $reltag && \
+		test "$KRB5_RELTAG" != `echo $reltag|sed 's%[^/]*/%%'` ; then
+		echo "WARNING: patchlevel.h '$KRB5_RELTAG' != $reltag"
+	fi
+	if test "$KRB5_MAJOR_RELEASE" != "$relmajor" || \
+		test "$KRB5_MINOR_RELEASE" != "$relminor" || \
+		test "$KRB5_PATCHLEVEL" != "$relpatch" || \
+		( test -n "$reltail" && \
+			test "$KRB5_RELTAIL" != "$reltail" ); then
+
+		echo "WARNING: patchlevel.h $KRB5_MAJOR_RELEASE.$KRB5_MINOR_RELEASE.$KRB5_PATCHLEVEL${KRB5_RELTAIL+-$KRB5_RELTAIL} != $relmajor.$relminor.$relpatch${reltail+-$reltail}"
+	fi
+else
+	echo "old style patchlevel.h"
+fi
+
+if test $checkout = t; then
+	echo "Checking out krb5 with tag $reltag into directory $reldir..."
+	svn export $repository/$reltag $reldir
+fi
+
+if test $dosrc = t; then
+	if test -d $reldir/src/util/autoconf; then
+		echo "Building autoconf..."
+		(cd $reldir/src/util/autoconf
+			M4=gm4 ./configure
+			make)
+	fi
+	echo "Creating configure scripts..."
+	(cd $reldir/src; util/reconf)
+
+	if test -d $reldir/src/util/autoconf; then
+		echo "Cleaning src/util/autoconf..."
+		(cd $reldir/src/util/autoconf; make distclean)
+	fi
+fi
+
+echo "Editing release-specific files..."
+
+if test $newstyle = t; then 
+	(cd $reldir/src && \
+		sed -e '/RELDATE/c\
+#define KRB5_RELDATE "'"$reldate"'"' patchlevel.h > patchlevel.h.new && \
+		mv patchlevel.h.new patchlevel.h)
+else
+
+	(cd $reldir/src/lib/krb5/krb && \
+		sed -e '/static/s%KRB5_BRAND:[^"]*"%'"KRB5_BRAND: $reltag $release $reldate"'"%' \
+			brand.c > brand.c.new && mv brand.c.new brand.c; \
+		rm -f brand.c.new)
+
+	(cd $reldir/src/util/send-pr && \
+		sed -e 's%RELEASE=.*%RELEASE='"krb5-$release"'%' Makefile.in \
+			> Makefile.in.new && mv Makefile.in.new Makefile.in)
+
+	(cd $reldir/src && \
+		cat > patchlevel.h <<EOF
+#define KRB5_MAJOR_RELEASE $relmajor
+#define KRB5_MINOR_RELEASE $relminor
+#define KRB5_PATCHLEVEL    $relpatch
+EOF
+	)
+fi
+
+echo "Nuking unneeded files..."
+find $reldir \( -name TODO -o -name todo -o -name .cvsignore \
+	-o -name BADSYMS -o -name .Sanitize -o -name .rconf \) -print \
+	| xargs rm -f || true
+find $reldir -type d \( -name autom4te.cache -o -name .svn \) -exec rm -rf {} \; || true
+
+if test $dodoc = t; then
+	echo "Building doc..."
+	(cd $reldir/doc; make)
+fi
+
+echo "Generating tarfiles..."
+GZIP=-9; export GZIP
+if test $multitar = t; then
+	if test $dosrc = t; then
+		gtar --exclude $reldir/src/lib/crypto \
+			--exclude $reldir/src/lib/des425 \
+			--exclude $reldir/doc \
+			-zcf ${reldir}.src.tar.gz $reldir
+
+		gtar zcf ${reldir}.crypto.tar.gz \
+			$reldir/src/lib/crypto \
+			$reldir/src/lib/des425
+	fi
+	if test $dodoc = t; then
+		gtar zcf ${reldir}.doc.tar.gz $reldir/doc $reldir/README
+	fi
+	ls -l ${reldir}.*.tar.gz
+fi
+
+gtar zcf ${reldir}.tar.gz $reldir
+ls -l ${reldir}.tar.gz
+
+echo "Done."
+
+exit 0
diff --git a/mechglue/src/util/profile/.Sanitize b/mechglue/src/util/profile/.Sanitize
new file mode 100644
index 000000000..de71c22d3
--- /dev/null
+++ b/mechglue/src/util/profile/.Sanitize
@@ -0,0 +1,49 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+dosshell.ini
+krb5.conf
+prof_err.et
+prof_file.c
+prof_init.c
+prof_int.h
+prof_parse.c
+prof_section.c
+prof_tree.c
+profile.hin
+test.ini
+test_parse.c
+test_profile.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/util/profile/ChangeLog b/mechglue/src/util/profile/ChangeLog
new file mode 100644
index 000000000..cbb95706e
--- /dev/null
+++ b/mechglue/src/util/profile/ChangeLog
@@ -0,0 +1,1306 @@
+2005-10-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (profile_update_file_data): Drop test of
+	STAT_ONCE_PER_SECOND, just do it always.
+	* prof_int.h (stuct _prf_data_t): Likewise.
+	(STAT_ONCE_PER_SECOND): Don't define.
+
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-06-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* profile.swg (errcode_t* tcl8 argout typemap): Cast return value
+	from error_message to char* to silence Sun compiler warning.
+	(errcode_t tcl8 out typemap): Likewise.
+	* profile_tcl.c: Regenerated.
+
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't check for getpwuid_r here.
+	* prof_file.c (profile_open_file): Use k5_getpwuid_r.
+
+2005-03-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check struct stat for fields st_mtimensec,
+	st_mtimespec.tv_nsec, and st_mtim.tv_nsec.
+	* prof_file.c (profile_update_file_data): If one of them is
+	found, use it as the fractional part of the timestamp.  Do
+	re-read the file if the fractional parts don't match.
+	* prof_int.h (struct _prf_data_t): Add new field frac_ts.
+
+2005-03-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_tree.c (profile_node_iterator): After checking skip_num
+	counter, also skip over deleted nodes.
+	* prof_test1 (test3): New proc.
+	(top level): Run it.
+
+2005-02-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_tree.c (profile_node_iterator): Check that the root node
+	pointer is not null; raise assertion failure if it is.
+
+	* prof_int.h: Include k5-platform.h.
+	(struct _prf_data_t): Reorder fields, and insert some padding.
+
+	* prof_file.c (scan_shared_trees_locked): Check that the "root"
+	field isn't null.
+	(profile_open_file): Update the in-memory file contents after
+	updating the refcount instead of before.
+	(profile_update_file_data): If the root node in the file data is
+	null, always do the update.  Check that it's not null before
+	returning a success indication.
+	(profile_dereference_data_locked): Scan linked list of file data
+	objects for sanity check, before and after.
+	(profile_dereference_data_locked): Don't do it here.
+
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (profile_library_initializer,
+	profile_library_finalizer): If SHOW_INITFINI_FUNCS is defined,
+	print tracing messages.
+
+2005-01-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (profile_free_file_data): Destroy mutex before
+	freeing containing structure.
+	(profile_open_file): If mutex creation fails, free storage
+	directly instead of calling profile_close_file.
+
+2004-12-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_tree.c (profile_node_iterator): When the iterator has a
+	current file, lock it, and unlock it before changing it or
+	returning.
+
+2004-11-04  Alexandra Ellwood  <lxs@mit.edu>
+
+	* prof_init.c, profile.hin: added profile_is_modified
+	and profile_is_writable so that callers can check to see
+	if profile_release() will fail before calling it.
+
+2004-11-04  Alexandra Ellwood  <lxs@mit.edu>
+
+	* prof_set.c: profile calls which set values should not fail 
+        if file is not writable.  You can now write to a different 
+        file with profile_flush_to_file() or buffer with 
+        profile_flush_to_buffer().
+
+2004-10-30  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_int.h (STAT_ONCE_PER_SECOND): Define.
+	(struct _prf_data_t) [STAT_ONCE_PER_SECOND]: New field LAST_STAT.
+	* prof_file.c (scan_shared_trees_locked,
+	scan_shared_trees_unlocked): Redefine to do nothing for now.
+	(profile_update_file_data) [STAT_ONCE_PER_SECOND]: If the current
+	time is the same time as the last stat of the file, just return;
+	otherwise, save away the current time.
+
+2004-10-26  Ken Raeburn  <raeburn@mit.edu>
+
+	Permit exporting profile file data into a buffer.
+	* prof_file.c (profile_flush_file_data_to_buffer): New function.
+	* profi_init.c (profile_flush_to_buffer, profile_free_buffer): New
+	functions.
+	* prof_parse.c (output_quoted_string): Use a callback instead of
+	stdio calls.
+	(dump_profile): Renamed from dump_profile_to_file.  Use a callback
+	instead of stdio calls.
+	(dump_profile_to_file_cb): New function.
+	(profile_write_tree_file): Updated to new internal interface.
+	(struct prof_buf): New type.
+	(add_data_to_buffer, dump_profile_to_buffer_cb,
+	profile_write_tree_to_buffer): New functions.
+	* prof_int.h (profile_write_tree_to_buffer,
+	profile_flush_file_data_to_buffer): Declare.
+	* profile.hin (profile_flush_to_buffer, profile_free_buffer):
+	Declare.
+	* libprofile.exports: Export profile_flush_to_buffer and
+	profile_free_buffer.
+	* profile.swg (profile_flush_to_buffer): Declare.
+	* profile_tcl.c: Regenerated.
+
+2004-10-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (profile_update_file_data): When resetting flags,
+	preserve SHARED flag.
+	(scan_shared_trees_locked, scan_shared_trees_unlocked): Convert to
+	macros, so line numbers reported by assert will be useful.
+	* prof_test1 (test2): Run new test of modifications with other
+	existing open profile handles.
+
+2004-10-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* libprofile.exports: Add profile_flush_to_file.
+
+2004-10-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (write_data_to_file): New function, split out from
+	profile_flush_file_data.  Add argument can_create indicating
+	whether the old file should already exist or not.
+	(profile_flush_file_data): Call it.
+	(profile_flush_file_data_to_file): New function.
+	* prof_int.h (profile_flush_file_data_to_file): Declare it.
+	(profile_flush_file_to_file): New macro.
+	* prof_init.c (profile_flush_to_file): New function.
+	* profile.hin (profile_flush_to_file): Declare.
+	* profile.swg (profile_flush_to_file): Declare.
+	* profile_tcl.c: Regenerated.
+	* prof_test1: Use profile_flush_to_file instead of profile_flush,
+	and reload from the new filename.
+
+2004-10-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c, prof_int.h, prof_set.c: Remove support for
+	non-SHARE_TREE_DATA case.
+	* prof_int.h (struct _prf_data_t): Change filespec to a trailing
+	char array.  Add a length field for the filespec.
+	(profile_make_prf_data): Declare.
+	(profile_lock_global, profile_unlock_global): Prototypes need
+	argument lists.
+	* prof_file.c: Include stddef.h.
+	(scan_shared_trees_locked, scan_shared_trees_unlocked): New
+	functions.
+	(r_access, rw_access): Now take const_profile_filespec_t arg.
+	(profile_make_prf_data): New function.
+	(profile_open_file): Scan trees at beginning and end.  Use
+	profile_make_prf_data to allocate and initialize storage.
+	(profile_dereference_data, profile_free_file_data): Scan trees.
+	(profile_ser_size, profile_ser_externalize): Filespec is never
+	null.
+	* prof_set.c (rw_setup): Use profile_make_prf_data to allocate
+	and initialize storage.
+
+2004-10-13  Alexandra Ellwood  <lxs@mit.edu>
+
+        * prof_file.c (profile_library_initializer, 
+        profile_library_finalizer): Added macros to avoid adding 
+        error tables on platforms that don't use them (ie: OSX).
+
+2004-10-13  Alexandra Ellwood  <lxs@mit.edu>
+
+	* prof_int.h Added prototypes for profile_lock_global()
+        and profile_unlock_global().
+
+2004-10-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_init.c (profile_init): Don't add error table here.
+	* prof_file.c (profile_library_initializer): Add it here.
+	(profile_library_finalizer): Remove it here.
+
+2004-09-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (profile_dereference_data_locked): New function.
+	(profile_dereference_data): Call it.
+	* prof_set.c (rw_setup): Likewise.
+	* prof_int.h (profile_dereference_data_locked): Declare it.
+
+2004-09-26  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (check-unix-tcl-ok): Use KRB5_RUN_ENV.
+
+	* configure.in: Use KRB5_RUN_FLAGS.
+
+2004-09-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_tree.c (struct profile_node): Add new bitfield DELETED.
+	(profile_add_node): Move variable CMP into inner block where it's
+	used.  Clear deleted flag.
+	(profile_find_node): Skip deleted nodes.
+	(profile_remove_node): Just set the deleted flag, don't modify the
+	tree.
+	* Makefile.in (profile_tcl.c): Target should be in srcdir.
+	(profile_tcl.o): Depend on profile.h.
+	(DO_TCL): New variable.
+	(check-unix-tcl-, check-unix-tcl-ok): New targets.
+	(check-unix): Depend on one of them, based on DO_TCL.
+	* configure.in: Set and substitute DO_TCL.
+	* prof_test1: New file.
+
+	* profile.swg: Only include tclsh.i if building for Tcl.
+	(Tcl_SetResult, my_tcl_setresult): Compile hack only if building
+	for Tcl.
+	(%typemap SWIGTYPE *OUTPUT): Initialization is not specific to the
+	scripting language.  Add Python code.
+	(%typemap errcode_t, errcode_t*): Add placeholders for Python
+	support.
+	* profile_tcl.c: Regenerated.
+
+2004-08-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (profile_open_file): If an error occurs while
+	updating from the input file, destroy the mutex only if we're not
+	sharing file data.
+
+2004-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_parse.c (parse_std_line): Rewrite handling of whitespace in
+	and after tag, to strip trailing whitespace (per current locale,
+	not just ASCII space characters), and prohibit any internal space
+	characters in tag names.
+
+	* profile.swg: New file.
+	* configure.in: Look for Tcl.
+	* Makefile.in (profile_tcl, profile_tcl.c, profile_tcl.o): New
+	targets, not built by default.
+	(PROG_LIBPATH, PROG_RPATH, LOCALINCLUDES): Add Tcl options.
+	(DEFINES): Define.
+	(clean-unix): Delete profile_tcl.
+	* profile_tcl.c: New file, generated from profile.swg, but checked
+	in to avoid requiring swig in order to generate the test program.
+
+	* prof_int.h (struct _prf_data_t): Add a mutex.
+	* prof_file.c (profile_open_file): Initialize data mutex.
+	(profile_update_file_data, profile_flush_file_data): Lock it while
+	manipulating file data.
+	(profile_lock_global, profile_unlock_global): New functions.
+	* prof_set.c (rw_setup): Acquire global lock while checking flags
+	and adjusting ref count.
+	(profile_update_relation, profile_rename_section,
+	profile_add_relation): Lock data mutex while manipulating profile
+	data.
+	* prof_tree.c (profile_node_iterator): Do more magic number
+	tests.
+
+2004-07-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* libprofile.exports: Don't try to export
+	krb5int_profile_shared_data.
+
+	* Makefile.in (MLIBS): Add $(LIBS).
+
+2004-06-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_int.h, prof_parse.c, profile.hin: Don't test macintosh or
+	__MWERKS__.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SHLIB_EXPLIBS): Add $(LIBS).
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-06-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (profile_open_file): Handle earlier (draft POSIX)
+	specifications of getpwuid_r.
+
+2004-06-02  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for getpwuid_r.
+	* prof_file.c (profile_open_file) [HAVE_PWD_H && HAVE_GETPWUID_R]:
+	Use getpwuid_r if available.
+
+2004-05-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: When generating prtest, use AC_CONFIG_FILES
+	instead of K5_GEN_FILE so that a chmod may be added to make the
+	script executable.
+
+2004-05-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (DEPLIBS, MLIBS, SHLIB_EXPDEPS, SHLIB_EXPLIBS): Add
+	the new support library.
+
+2004-04-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c: Include k5-platform.h.
+	(krb5int_profile_shared_data): Now static.  Use new partial mutex
+	initializer.
+	(struct global_shared_profile_data, g_shared_trees,
+	g_shared_trees_mutex): Moved here from prof_int.h.
+	(profile_library_initializer, profile_library_finalizer): New
+	init/fini functions.  Deal with mutex.
+	(profile_open_file): Verify initializer ran successfully.
+
+2004-04-22  Ken Raeburn  <raeburn@mit.edu>
+
+	* libprofile.exports: New file.
+
+2004-03-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_int.h: Include k5-thread.h.  Don't include sys/types.h and
+	pthread.h.
+	(SHARE_TREE_DATA): Always define.
+	(USE_PTHREADS): Don't define.
+	(prof_mutex_lock, prof_mutex_unlock): Deleted.
+	(struct global_shared_profile_data): Change mutex to use
+	k5_mutex_t instead of pthread_mutex_t.
+	(g_shared_trees_mutex): Don't conditionalize on USE_PTHREADS.
+	* prof_file.c (krb5int_profile_shared_data): Initialize mutex.
+	(profile_open_file, profile_dereference_data): Use new mutex
+	macros.  Check return status when locking.  Fix a potential memory
+	leak in an error case.
+
+2004-03-08  Ezra Peisach  <epeisach@mit.edu>
+
+	* prof_get.c (profile_parse_boolean): Declare first argument as
+	const char *.
+
+2004-02-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_init.c (prof_int32): If long is 4 bytes and int is not,
+	then use long, not int, for prof_int32.
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c, prof_get.c, prof_init.c, prof_parse.c, prof_set.c,
+	prof_tree.c: Use ANSI style function definitions.
+
+2004-01-30  Alexandra Ellwood  <lxs@mit.edu>
+
+    * prof-int.h: prof-int.h should include pthread.h when USE_PTHREADS 
+    is defined.
+
+2003-12-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_get.c (profile_iterator_create): NAMES argument points to
+	const pointers.
+	* profile.hin (profile_iterator_create): Declaration updated.
+
+2003-12-14 Jeffrey Altman <jaltman@mit.edu>
+
+   * all files: move prof-int.h to be the first include file
+     in order to obtain platform specific config preprocessor
+     variables which are used to selectively include stdlib.h
+
+2003-07-03 Alexandra Ellwood <lxs@mit.edu>
+
+    * profile.hin: Remove leading spaces in #define and #include 
+    in public headers to support K&R C compilers
+    
+2003-04-28  Ezra Peisach  <epeisach@bu.edu>
+
+	* prof_file.c (r_access): Static function. Only include if
+	SHARE_TREE_DATA defined.
+
+2003-03-06 Alexandra Ellwood <lxs@mit.edu>
+    * profile.hin, prof_file.c (profile_flush_file_data): Stop copying
+    the resource fork.  We stopped writing resources to the krb5
+    configuration in KfM 4.5.x.  In KfM 5.0 will no longer read
+    preferences from the resource fork so we can destroy it on copy.
+    
+    * prof-int.h: No longer include MoreFiles.  Removed framework style
+    includes for Kerberos headers.
+    
+    * prof_FSp_glue.c, prof_init.c, profile.hin: Moved Mac FSSpec-based 
+      functions into a separate file so they will only be built with KfM.
+      These functions will be exported but not in the headers because
+      they are deprecated.
+
+2003-01-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (profile_flush_file_data) [_WIN32]: Don't call
+	sync.
+
+2003-01-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_int.h (SHARE_TREE_DATA): Define only on Mac.
+
+	* profile.pbexp: New file.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Check for pwd.h.
+	* prof_file.c: Include pwd.h if available.
+	(profile_open_file) [HAVE_PWD_H]: If $HOME isn't set, look up the
+	home directory in the passwd file.  Expand the filename before
+	checking against the cache.
+	(profile_open_file) [SHARE_TREE_DATA]: Fix the sense of the test
+	for read access.
+
+	* configure.in: Use V5_AC_OUTPUT_MAKEFILE instead of
+	K5_GEN_MAKEFILE and K5_AC_OUTPUT.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2003-01-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (make_hard_link): New function.
+	(profile_flush_file_data): Use it to attempt a safe profile file
+	replacement.
+
+	* prof_parse.c (profile_parse_file)
+	[PROFILE_SUPPORTS_FOREIGN_NEWLINES]: Look for \r and treat it as a
+	line break.
+	* prof_int.h: Don't include prof_err.h.
+	(PROFILE_SUPPORTS_FOREIGN_NEWLINES) [macintosh]: Define new
+	macro.
+
+2002-12-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_file.c (r_access): New function.
+	(profile_open_file): Use it.
+
+	* profile.hin: Don't test MACINTOSH any more.  On Mac OS X,
+	include TargetConditionals.h, set some pragmas, define
+	COPY_RESOURCE_FORK, and error out if TARGET_RT_MAC_CFM is
+	defined; don't set the old m68k CFM pragmas.  Always use
+	PROFILE_USES_PATHS code, don't test or define it.
+	(FSp_profile_init, FSp_profile_init_path): Declare, on Mac OS X.
+	* prof_int.h (NO_SYS_TYPES_H, NO_SYS_STAT_H) [macintosh]: Don't
+	define these.
+	* prof_file.c: Always inclued sys/types.h and sys/stat.h.
+	(GetMacOSTempFilespec): Deleted.
+	(profile_flush_file_data) [COPY_RESOURCE_FORK]: Copy Mac resource
+	fork from old file to new before renaming.
+	(rw_access, profile_update_file_data, profile_flush_file_data,
+	profile_free_file_data): Assume PROFILE_USES_PATHS, don't test.
+	* prof_init.c (profile_ser_size, profile_ser_externalize,
+	profile_ser_internalize): Likewise.
+	(FSp_profile_init, FSp_profile_init_path): Define, on MacOS X.
+	* profile.exp: Add FSp_* functions.
+
+2002-12-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* prof_file.c: Cast return from prof_mutex_lock and
+	prof_mutex_unlock to void to avoid warnings of code with no side
+	effects.
+
+2002-12-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_int.h: Define USE_PTHREADS and include pthread.h if on
+	MacOS X.
+	(struct global_shared_profile_data) [USE_PTHREADS]: Add a mutex.
+	(g_shared_trees_mutex) [USE_PTHREADS]: New macro, references the
+	global mutex.
+	(prof_mutex_lock, prof_mutex_unlock) [SHARE_TREE_DATA]: Define to
+	use pthread functions or do nothing.
+	(profile_free_file_data): Delete declaration.
+	(profile_dereference_data): Declare.
+	* prof_file.c (profile_free_file_data): Now static.
+	(profile_open_file, profile_dereference_data) [SHARE_TREE_DATA]:
+	Grab lock while manipulating global data list or its contents.
+
+	* prof_int.h (SHARE_TREE_DATA): Define.
+	(struct _prf_file_t) [SHARE_TREE_DATA]: Make data field a pointer
+	rather than an array.
+	(struct global_shared_profile_data): New type, for profile library
+	global data.
+	(krb5int_profile_shared_data): Declare new variable.
+	(g_shared_trees): New macro, refers to a field in the global data.
+	(PROFILE_FILE_SHARED): New flag macro.
+	* prof_file.c (krb5int_profile_shared_data): Initialize here.
+	(profile_open_file) [SHARE_TREE_DATA]: Scan g_shared_trees for an
+	entry with the same filename.  If found, increment its reference
+	count, update it, and return it; otherwise, allocate a new one,
+	and add it to the list after filling it in.
+	(profile_dereference_data): New function.  Decrement reference
+	count if SHARE_TREE_DATA, and free the data if appropriate.
+	(profile_free_file): Call profile_dereference_data.
+	(profile_free_file_data) [SHARE_TREE_DATA]: If the SHARED flag is
+	set, remove it from the g_shared_trees list before freeing.  Free
+	up the allocated space.
+	* prof_set.c (rw_setup) [SHARE_TREE_DATA]: If the object's data is
+	shared, copy it into a new data structure not in the global shared
+	list, and dereference the old one.
+
+2002-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_int.h: Include Mac OS X versions of header files if
+	appropriate.  Only include prof_err.h if profile.h doesn't define
+	ERROR_TABLE_BASE_prof.
+	(struct _prf_data_t): Move most of contents of _prf_file_t here.
+	Add reference count.
+	(prf_data_t): New typedef.
+	(struct _prf_file_t): Include an array of one _prf_data_t
+	structure.
+	* prof_file.c (profile_open_file): Fill in "data" field.  Drop
+	some old Mac specific code.
+	(profile_flush_file_data): Renamed from profile_flush_file, now
+	takes prf_data_t argument.
+	(profile_flush_file_data): Likewise.
+	(profile_free_file): Now calls profile_free_file_data.
+	(profile_free_file_data): New function, with most of old
+	profile_free_file code.
+	* prof_init.c (profile_init_path): Removed old Mac version.
+	(profile_ser_size, profile_ser_externalize): Get file data from
+	new "data" field.
+	* prof_set.c (rw_setup, profile_update_relation,
+	profile_clear_relation, profile_rename_section,
+	profile_add_relation): Likewise.
+	* prof_tree.c (profile_node_iterator): Likewise.
+	* test_profile.c (do_batchmode): Likewise.
+	* prof_int.h (profile_flush_file): Now a macro.
+	* prof_err.et (PROF_MAGIC_FILE_DATA): New error code value.
+
+	* prof_get.c (conf_yes, conf_no): Entries now point to const.
+	(profile_parse_boolean): Updated type of 'p' correspondingly.
+
+2002-10-07  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in: Support install-headers
+
+2002-10-03  Sam Hartman  <hartmans@mit.edu>
+
+	* Makefile.in :  Move test_* from all to check targets. so that
+	com_err is not needed on mac.
+
+2002-09-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): Don't reference et directory.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(PROFILE_HDR)): Quote target of copy.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (EXTRADEPSRCS): New variable.
+	(.d): Depend on includes.
+
+2002-06-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_parse.c (strip_line): Simplify loop by preserving "p"
+	rather than recomputing it.
+
+	* configure.in: Look for strdup.
+	* prof_tree.c (profile_create_node): Use strdup.
+	(strdup, MYstrdup): Define it if the OS doesn't provide it.
+
+2002-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_get.c (profile_get_integer): Set errno to 0 before strtol
+	call, so we can distinguish error from LONG_MIN/MAX.  Break out
+	different error conditions and comment them.
+
+2002-05-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_get.c (conf_yes, conf_no): Now const.
+	(profile_parse_boolean): Local variable P points to const.
+
+2002-02-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBMINOR): Bump, due to error table changes.
+	(Tom's change from 1.2.x branch.)
+
+2002-01-23	Alexandra Ellwood <lxs@mit.edu>
+
+	* prof_init.c, prof_tree.c: Fixed calls to
+	profile_update_file_data to handle the possibility that we have
+	lost permission to read one of the configuration files in the file
+	list.  We should only fail catastrophically (EACCES) if we can't
+	read all of the files in the profile.
+
+2001-12-05  Ezra Peisach  <epeisach@mit.edu>
+
+	* test_profile.c (main): Call profile_release() before exiting
+	in case of error return. (memory leak testing)
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_int.h, profile.hin, test_parse.c: Make prototypes
+	unconditional.  Don't define PROTOTYPE.
+
+2001-10-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* profile.hin (KRB5_EXPORTVAR): Don't define.
+
+	* prof_file.c, prof_int.h, prof_parse.c, profile.hin,
+	test_profile.c: Drop _MSDOS support.
+
+	* profile.hin (NEAR, FAR): Don't define.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_get.c, prof_init.c, prof_set.c, profile.hin: Don't use
+	KRB5_DLLIMP.
+
+2001-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_tree.c (struct profile_iterator): Member "names" now points
+	to const.
+	(profile_node_iterator_create): Argument "names" now points to
+	const.
+	(profile_node_iterator): Local variable "cpp" now points to
+	const.
+	* prof_int.h (profile_node_iterator_create): Decl updated.
+	* prof_get.c (profile_get_values): Argument "names" now points to
+	const.
+	* profile.hin (profile_get_values): Decl updated.
+
+2001-07-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* prof_int.h: Provide prototypes for profile_ser_size,
+	profile_ser_externalize, profile_ser_internalize.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* test_profile.c: Include <string.h> for strcmp() prototype.
+
+	* argv_parse.c (argv_parse): Cast argument to isspace() as int.
+	* prof_parse.c (skip_over_blanks, parse_std_line, need_double_quotes): 
+	Likewise.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (MLIBS): Do not link against libgen.a for test
+	programs. (only needed for krb5 an_to_ln code).
+
+2001-02-02  Tom Yu  <tlyu@mit.edu>
+
+	* krb5.conf: Test with trailing whitespace on "default_realm"
+	line.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Use AC_C_CONST instead of AC_CONST and
+	AC_CHECK_FUNCS instead of AC_HAVE_FUNCS.
+
+2000-08-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* krb5.conf: Test with a space after ']' and '{'
+
+	* prof_parse.c (parse_std_line): Spaces after '{' or ']' should
+	not be a fatal error. This is a common lossage in krb5.conf files.
+
+2000-07-24  Ezra Peisach  <epeisach@mit.edu>
+
+	* prof_init.c: Cleanup internal type warnings in calls to profile_init.
+
+	* test_parse.c (main): Cast arguments to error_message. 
+
+	* prof_file.c (profile_open_file): Variable with argument to
+	malloc should be unsigned.
+
+	* profile.hin: Revert changes to const_profile_filespect_t and
+	profile_filespec_t to preserve interface.
+
+2000-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* prof_init.c (profile_init_path): Use profile_filespec_t instead
+	     of char *. (change  provided by Nathan Neulinger <nneul@umr.edu>)
+
+	* profile.hin: Make definition of const_profile_filespec_t to be
+		based on profile_filespec_t.
+
+2000-05-15	Alexandra Ellwood <lxs@mit.edu>
+
+	* prof_get.c:
+		prof_parse_boolean () was missing some curly brackets
+		and was failing to check all the values in the list of
+		possible strings.
+
+2000-04-03  Jeffrey Altman <jaltman@columbia.edu>
+
+        * prof_get.c: 
+            profile_get_boolean() was calling prof_parse_boolean()
+            instead of profile_get_boolean()
+
+2000-04-03  Jeffrey Altman <jaltman@columbia.edu>
+
+        * prof_get.c: 
+          . Added #include <limits.h> for definitions of INT_MAX, etc.
+          . Changed 'ret_int' to 'ret_boolean' in prof_get_boolean
+
+2000-03-24  Miro Jurisic  <meeroh@mit.edu>
+
+	* prof_get.c: Added prof_get_boolean and changed prof_get_integer
+	to return errors for malformed input
+	* prof.hin: Added prof_get_boolean
+	* profile.exp: Added prof_get_boolean
+	* prof_err.et: Added PROF_BAD_BOOLEAN, PROF_BAD_INTEGER
+
+Fri Jan 28 16:27:01 2000  Ezra Peisach  <epeisach@mit.edu>
+
+	* argv_parse.c: Include string.h (for strlen prototype)
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-09-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* profile.hin (profile_init, profile_init_path): Define and use
+	const_profile_filespec_t.
+
+	* prof_init.c (profile_init, profile_init_path):
+	* prof_file.c (profile_open_file):
+	* prof_int.h (profile_open_file): Use const_profile_filespec_t.
+
+	* prof_int.h (PROFILE_LAST_FILESPEC): Compare a char against a char,
+	not a void*.
+
+	* Makefile.in: Remove DOSDEFS to avoid warnings.  The thing it
+	defined is already set in win-mac.h.
+
+1999-08-18  Miro Jurisic  <meeroh@mit.edu>
+
+	* profile.exp: removed com_err functions (they are in a library
+	of their own now) from MacOS export file
+
+1999-08-05  Danilo Almeida  <dalmeida@mit.edu>
+
+	* prof_get.c (profile_free_string): 
+	* profile.hin: Add profile_free_string to free strings allocated
+	by profile_get_string. -- And then remove them because
+	profile_release_string already exists for that purpose.	
+
+1999-08-03 Alexandra Ellwood <lxs@mit.edu>
+
+	* prof_file.c (profile_open_file)
+		Mac OS side now sets profile->magic to PROF_MAGIC_FILE 
+		so the rest of the functions think it's a real profile.
+		  
+1999-07-22 Jeffrey Altman <jaltman@columbia.edu>
+
+        * prof_init.c (prof_init)
+          Change behavior so that a NULL filespec means allocate
+          a profile without a backing store.
+
+1999-07-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_int.h (profile_t): Delete typedef, since Miro changed
+	prof_int.h to include profile.h, which also has the typedef.
+	* prof_file.c, prof_init.c: Fix typos and missed variable and type
+	name changes from Miro's patch.
+
+1999-07-21 Miro Jurisic   <meeroh@mit.edu>
+
+	* profile.hin, prof_file.c, prof_init.c, prof_int.h:
+		MacOS now uses file specifiers rather than file paths
+
+1999-07-14 Miro Jurisic   <meeroh@mit.edu>
+
+	* profile.hin: added #ifdef __cplusplus extern "C" 
+
+1999-06-23  Danilo Almeida  <dalmeida@mit.edu>
+
+	* prof_init.c (profile_abandon, profile_release): Check whether
+		profile is valid before partying on it.
+
+1999-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* prof_tree.c (profile_node_iterator): Remove semicolon after
+	function body.
+
+1999-06-16  Danilo Almeida  <dalmeida@mit.edu>
+
+	* prof_init.c (profile_init_path): Fix memory leak.
+
+1999-06-09 Miro Jurisic   <meeroh@mit.edu>
+
+	* prof_file.c (profile_update_file): if fopen fails and errno is 0, set
+	errno to ENOENT so that we can try multiple names for settings file
+	(From Chas Williams)
+
+Wed May 19 11:46:02 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add windows build rules for putting header files in
+		include dir.  Do cleanup of header for windows clean.
+
+Mon May 10 15:27:19 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1999-04-14    <tytso@rsts-11.mit.edu>
+
+	* prof_init.c (profile_abandon): New function which frees the
+		profile handle and throwing away any changes that might
+		have been made before they are flushed to disk.
+
+	* prof_file.c (profile_close_file): Move functionality of freeing
+		the profile file to the new function profile_free_file().
+
+Mon Mar 15 16:03:34 1999  Tom Yu  <tlyu@mit.edu>
+
+	* profile.hin: Fix GSS_DLLIMP.
+
+Mon Mar  8 19:10:06 1999  Tom Yu  <tlyu@mit.edu>
+
+	* profile.hin: Fix prototype of profile_flush() to use long rather
+	than errcode_t to avoid breaking other stuff that includes
+	profile.h.
+
+Mon Mar  8 14:38:24 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* prof_tree.c (profile_node_iterator): Fix bug where it will loop
+		endlessly when searching an empty section.
+
+	* test_profile.c: Add code so that the "add" code will interpret
+		"NULL" as calling profile_add_relation with a null pointer
+		for the value.
+
+Wed Mar  3 18:23:47 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* prof_file.c (profile_flush_file): On the Macintosh, fopen()
+		doesn't set errno when fopen fails to open a file.  Work
+		around this by setting errno to PROF_FAIL_OPEN in this case.
+
+	* prof_err.et: Add new error code PROF_FAIL_OPEN.
+
+Tue Mar  2 18:55:50 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* test_profile.c: Added ability to test profile set functions, and
+		in a batch mode.
+	
+	* prof_init.c (profile_flush): Add new public function for
+		flushing changes made to the profile.
+
+	* prof_parse.c (profile_write_tree_file): Add official internal
+		function for flushing out a profile tree to a FILE *.
+	
+	* configure.in, prof_file.c (rw_access): Add new function which
+		checks to see whether we have read/write access, and
+		emulate this for losing non-POSIX OS's.
+
+	* prof_file.c (profile_flush_file): Add support for writing
+ 	 	modified profile file's.  Call profile_flush_file from
+ 	 	profile_close_file().
+
+	* prof_tree.c: Add new functions profile_get_node_name,
+ 		profile_get_node_value, profile_find_node,
+ 		profile_remove_node, profile_set_relation_value,
+ 		profile_rename_node.  Rewrite profile_find_node_relation
+ 		and profile_find_node_subsection in terms of
+ 		profile_find_node.
+	
+	* prof_set.c, Makefile.in: Add a new file which exports the public
+		interfaces for setting profile entries.
+
+	* prof_get.c, prof_init.c, prof_int.h: Add the KRB5_DLLIMP and
+ 		KRB5_CALLCONV to all of the various profile routines so
+ 		they can be properly exported via a Windows DLL.
+
+	* prof_int.h: Add definition for the flags in the profile
+		structure.
+	
+	* prof_err.et: Add new error codes PROF_SET_SECTION_VALUE,
+		PROF_EINVAL, PROF_READ_ONLY, and PROF_EXISTS.
+
+Fri Feb 19 00:49:10 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* test_parse.c (main): Add a call to profile_verify_node so we can
+		test the internal rep invariants.
+
+	* prof_tree.c (profile_verify_node): Fix bug in
+		profile_verify_node in the group_level test.  Also make
+		profile_verify_node check the return code when it is
+		recursively testing the child nodes.
+
+Mon Jan 25 18:44:26 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* prof_tree.c (profile_node_iterator): Added comments indicating
+		that profile_node_iterator, not being an exported
+		interface, returns pointers into the parse tree, and that
+		values should be strdup()'ed before returning them to a
+		calling application.
+
+	* prof_get.c (profile_iterator): Strdup the name and value strings
+		before returning them to the calling application.
+
+Thu Jan 21 15:21:18 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* profile.hin: Fix definition of PROTOYPE so that it works under
+	 	C++.
+
+1998-12-31  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* prof_tree.c (profile_node_iterator): Make sure the pointer to
+		the iterator function is non-NULL before checking the
+		magic value.
+
+1998-12-15  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* prof_file.c (profile_open_file): Add ability to parse filenames
+		that begin with "~/" and substitute it with "$HOME/".
+
+1998-12-04  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* prof_get.c: Add new public profile_iterator functions for
+		iterating over values found in the profile file.
+
+1998-11-17  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* prof_get.c (profile_get_values): If there are no relations
+		found, return PROF_NO_RELATION, instead of an empty list.
+
+1998-11-13  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Set the myfulldir and mydir variables (which are
+		relative to buildtop and thisconfigdir, respectively.)
+
+	* configure.in: Build the test script prtest for doing regression
+		test suites of the profile library.
+
+	* prof_err.et (PROF_MAGIC_ITERATOR): Add a new error code for the
+		magic number for the iterator structure.
+
+	* prof_file.c (profile_update_file): Increment the update serial
+		number when the profile file is re-read.
+
+	* prof_tree.c (profile_make_node_final, profile_is_node_final):
+		Add a new attribute for a node, which is whether or not
+		the node is "final".  This controls whether or not the
+		next profile file should be searched when looking up a key
+		which matches the section named by the node.
+		(profile_node_iterator_create, profile_node_iterator_free,
+		profile_node_iterator): New functions which take a
+		profile_t and returns all of the names or values for a
+		particular search key.  This iterator follows the rules of
+		doing multiple profile file lookups using the "final node"
+		marker to stop searching subsequent profile files.
+	
+	* prof_parse.c (parse_std_line): Add support for marking top level
+		sections, subsections, and individual nodes as final,
+		using the '*' character.
+		(dump_profile_to_file): Print finalized sections with the '*'
+		character.
+
+	* prof_get.c: Update routines to use the iterators provided by
+		prof_tree.c.
+
+	* prof_int.c: Add upd_serial member to the prf_file_t structure.
+		Define the symbolic flags used by the profile node
+		iterator.  Add function declarations for
+		profile_make_node_final, profile_is_node_final,
+		profile_node_iterator_create, profile_node_iterator_free,
+		profile_node_iterator, and profile_get_value.
+
+	* test_profile.c: Add the query1 command which tests
+		profile_get_value. 
+
+1998-11-05  Geoffrey King  <gjking@mit.edu>
+
+	* prof_init.c (profile_init): Fix a problem whereby if the last
+		pathname in a list of pathnames was nonexistent, an
+		error would be returned that they were all nonexistent.
+
+1998-11-03  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Added prof_get.c to the list of files to be compiled.
+	
+	* profile.hin: Added declarations for profile_free_list(),
+		profile_get_relation_names(), and
+		profile_get_subsection_names().  (These are new public
+		interfaces to the profile library.)
+
+	* prof_int.h: Removed the profile_section_t structure, which was
+		used only by the now-defunct prof_section.c file.  Added
+		the internal interfaces for the new public interfaces.
+		Removed unused declarations which were never
+		implemented(profile_get, profile_update).
+
+	* prof_init.c: Moved all of the profile querying functions
+		(profile_get_values(), profile_get_value(), etc.) to
+		prof_get.c.  In the process, removed the really
+		bletcherous (and badly implemented)
+		profile_get_first_values(), which did nothing like what
+		the named implied.  Also added to prof_get.c new functions
+		profile_get_subsection_names() and
+		profile_get_relation_names(). 
+	  	(profile_ser_internalize): Rewrote error handling to be
+		clearer, and removed a bug where memory was not freed
+		correctly in an error case.  
+		(profile_init): If a list of pathnames is passed in,
+		profile_init will now try to open all of them, now that
+		we've defined query fallback semantics in prof_get.c
+
+	* prof_parse.c: Fix lint warning.
+
+	* prof_tree.c (profile_find_node_relation,
+		profile_find_node_subsection): Allow the returned value or
+		subsection field to be NULL (in case the caller isn't
+		interested in getting the returned value or subsection,
+		and only cares about getting the name).
+		(profile_delete_node_relation,
+		profile_delete_interior_node_relation): Removed these
+		functions and replaced it with profile_remove_node(),
+		which takes a boolean argument section_flag. 
+		(profile_find_node_name): Removed this function.  (This
+		was a Cygnus/Fusion special used by the now removed
+		profile_find_first_values() function.)
+
+	* test_profile.c: Added commands to test the new
+		profile_get_subsection_names() and
+		profile_get_relation_names() interfaces.
+
+1998-08-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* prof_tree.c (profile_delete_node_relation): Fix bug where
+		deleting a node would corrupt the linked list.
+		(profile_add_node): Fix another linked list corruption
+		problem where an insertion into the middle of the linked
+		list didn't update a previous link.  [krb5-libs/615]
+
+1998-07-12  Sam Hartman  <hartmans@fundsxpress.com>
+
+	* Makefile.in: Add dependency on -lcom_err
+
+Mon Mar  2 16:19:58 1998  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in: Integrate in the krb5 build tree rules.
+	(use CC_LINK, etc).
+
+	* configure.in: Add AC_BUILD_PROGRAM for test programs.
+
+Wed Feb 18 16:33:38 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Wed Jan 28 17:58:10 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in, Makefile.in: Remove CopyHeader from
+		configure.in, and move functionality to Makefile.in
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+Fri Jan 23 20:55:06 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* prof_parse.c (parse_std_line, parse_quoted_string,
+ 	 	need_double_quotes, output_quoted_string, dump_profile,
+ 	 	dump_profile_to_file): Vastly improved the profile
+	 	parsing; whitespace at the end of lines are now ignored.
+		Added quoted string parsing, complete with backquote
+	 	processing.  Strings which need to be quoted are properly
+	 	quoted on output.
+
+Sat Feb 22 18:33:17 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Move list file construction to win-post.in
+
+Tue Feb 18 00:14:13 1997  Richard Basch  <basch@lehman.com>
+
+	* profile.hin prof_int.h prof_init.c:
+		Export profile_get_values() [krb4 dll requires it]
+
+Sat Feb 15 01:58:19 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in (all-windows): Fixed win16/win32 build
+		after libhack merge broke it...
+
+Fri Feb  7 18:56:57 1997  Richard Basch  <basch@lehman.com>
+
+	* prof_int.h:
+		Include com_err.h rather than redefining errcode_t
+		Structure element "magic" should not be errcode_t
+
+Wed Feb  5 20:18:33 1997  Richard Basch  <basch@lehman.com>
+
+	* profile.hin: Do not process the contents of profile.h
+		(or the profile.hin subset) more than once.
+
+	* test_parse.c:
+		Do not include "com_err.h" (conflicting errcode_t definition)
+
+	* Makefile.in:
+		Fixed typo (all-max -> all-mac)
+		Inconsistent colon usage; all-windows needed :: not :
+
+Thu Jan  2 17:36:44 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in:
+	* configure.in: Update to new library build procedure.
+
+Mon Nov  4 17:04:51 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* prof_parse.c (parse_std_line): Accept either ';' or '#' on the
+		first line of a string as a comment character.
+
+Fri Jul 12 20:28:49 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (CFLAGS): On Windows builds, add -DHAVE_STDLIB_H
+
+Mon Jun 24 09:37:26 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* prof_file.c, prof_init.c, prof_parse.c, prof_section.c,
+		prof_tree.c, test_parse.c, test_profile.c, configure.in:
+		Only include stdlib.h if it's available.
+
+Thu Jun 13 22:13:51 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to ET_RULES
+
+Mon Jun 10 17:35:02 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* test_profile.c: Add usage message if not enough arguments.
+
+	* prof_parse.c (dump_profile_to_file, dump_profile): Dump the
+ 		profile using the correct line terminator for Windows,
+ 		Macintosh, etc.
+
+	* prof_parse.c:
+	* prof_file.c: Change _WINDOWS to _MSDOS, and add check for _WIN32.
+
+	* prof_int.h: Add size #defines for _WIN32.  Handle prototypes
+		correctly for _WIN32.
+
+Fri Feb 16 15:18:17 1996    <tytso@rsts-11.mit.edu>
+
+	* prof_int.h: Added comment to profile state structure
+
+Wed Feb 14 16:43:48 1996    <tytso@rsts-11.mit.edu>
+
+	* prof_parse.c (parse_std_line): Make parsing more flexible, so we
+		don't barf over lack of spaces around the equals sign.
+
+Tue Dec 12 19:18:14 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* krb5.conf: use host:portnum in example files, not host,portnum.
+
+Fri Jan  5 09:04:20 1996  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* profile.hin: Add profile_init_path prototype
+
+Thu Dec 21 18:20:46 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* configure.in: Check for the stat call, since profile_update_file
+		needs to know whether it exists.  (It doesn't on the Mac.)
+
+	* prof_file.c (profile_update_file): Change use of HAS_STAT to
+		HAVE_STAT, to confirm with autoconf test.  If the stat()
+		call does not exist, assume that our in-core memory image
+		is correct, and never re-read the profile file unless we
+		explicitly close it.
+
+Fri Oct  6 22:07:01 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Remove ##DOS!include of config/windows.in.
+		config/windows.in is now included by wconfig.
+
+Mon Oct  2 16:39:49 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* prof_init.c (profile_init_path): Add const declarations.
+
+Tue Sep 26 20:00:28 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* prof_init.c (profile_init_path): takes a single string entry
+	that has pathnames seperated by colons, and splits it into
+	file names for profile_init. No provision for quoting colons in
+	pathnames, but shells don't solve that either.
+
+Tue Sep 26 19:23:59 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* prof_init.c (profile_init): handle multiple input files by
+	grabbing the first one that doesn't return ENOENT.
+
+Mon Sep 25 16:42:13 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Fri Sep 22 19:51:44 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* prof_int.h: added SIZEOF defines for the PC, and added missing
+		prototype for profile_find_node_name()
+
+	* prof_init.c (profile_get_first_values): Remove unused variables.
+
+Mon Sep 11 15:30:52 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* prof_parse.c (dump_profile_to_file): Convert C+ comment to
+		standard C one.
+
+Tue Aug 29 14:23:16 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add checks for size of short, int and long.
+	* prof_init.c - Add routines to serialize profile context.
+
+Tue Aug 15 17:17:40 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* prof_parse.c (strip_line,parse_line): Declare as static.
+
+	* prof_int.h: Add missing prototypes
+
+Thu Jul  6 10:05:47 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* prof_file.c: prof_int.h must be included after stdio.h
+
+Wed July 5 15:52:31 1995  James Mattly  <mattly@fusion.com>
+	* prof_file.c added conditionals for sys/*.h include files
+	* prof_int.h added _MACINTOSH conditional
+	* test_parse.c added _MACINTOSH conditional
+
+Fri Jun  9 19:00:19 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Thu Jun  8 17:56:34 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in (install): Add install target.
+
+Fri May 26 20:07:13 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* configure.in, Makefile.in: Add support for building shared libraries.
+
+Sat May  6 17:21:59 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* test_parse.c: Include prof_int.h - this program relies on
+		internal functions.
+
+Fri May  5 00:02:41 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* prof_init.c (profile_get_values): Return PROF_NO_PROFILE if the
+		passed-in profile variable is NULL (instead of core dumping).
+	
+	* prof_err.et (PROF_NO_PROFILE): Defined new error code.
+
+Thu May  4 23:57:56 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* prof_tree.c (profile_free_node): Copy child->next to a scratch
+		pointer before freeing the node; otherwise we have to
+		dereference a freed object.
+
+Fri Apr 28 15:54:40 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* prof_parse.c (strip_line): Don't try to strip an empty line.
+		This causes memory reference error.
+
+Thu Apr 27 20:26:48 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in (clean-unix): Remove profile.h and test_profile
+
+Thu Apr 27 15:36:27 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* test_parse.c (main): can't make function declarations local to
+	functions under SunOS cc. (dump_profile) Also needs to be protected.
+
+Thu Apr 27 10:43:24 1995 Keith Vetter (keithv@fusion.com)
+
+	* Makefile.in: made to work on the PC.
+	* profile.hin, prof_int.h: use _MSDOS instead of _WINDOWS 
+	   so we can compile DOS test programs.
+	* *.c: Don't need to include file unistd.h.
+	* test_*.c: Made to work under DOS--used stubs for the com_err stuff.
+	* prof_parse.c: Turned a 2k automatic array into a malloc'ed block
+	   because windows dll's shouldn't use up a lot of stack space.
+
+Wed Apr 26 09:54:18 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* profile.hin: Only define PROTOTYPE if it is undefined.
+
+Tue Apr 25 17:28:48 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* configure.in: Add AC_CONST for platforms that do not support const.
+
+Mon Apr 24 17:05:27 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* Makefile.in (all): Use ARADD to facilitate incremental
+	rebuilding of library.
+
+	* configure.in: Add AC_PROG_ARCHIVE_ADD
+
+	* prof_init.c (profile_get_values): If profile is null return
+	NULL.
+
+Sat Apr 22 01:25:58 1995  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Rename profile.h.in to profile.hin to, make things
+		easier for systems with an 8.3 filesystem.
+
diff --git a/mechglue/src/util/profile/Makefile.in b/mechglue/src/util/profile/Makefile.in
new file mode 100644
index 000000000..067007d84
--- /dev/null
+++ b/mechglue/src/util/profile/Makefile.in
@@ -0,0 +1,191 @@
+thisconfigdir=.
+myfulldir=util/profile
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD) $(TCL_LIBPATH)
+PROG_RPATH=$(KRB5_LIBDIR)$(TCL_RPATH)
+KRB5_RUN_ENV=@KRB5_RUN_ENV@
+##DOS##BUILDTOP = ..\..
+##DOS##OBJFILE=$(OUTPRE)profile.lst
+##DOS##LIBNAME=$(OUTPRE)profile.lib
+
+LOCALINCLUDES=-I. $(TCL_INCLUDES)
+# for tcl.h
+DEFINES=-DHAS_STDARG
+
+STLIBOBJS = \
+	prof_tree.o \
+	prof_file.o \
+	prof_parse.o \
+	prof_get.o \
+	prof_set.o \
+	prof_err.o \
+	prof_init.o
+
+OBJS = $(OUTPRE)prof_tree.$(OBJEXT) \
+	$(OUTPRE)prof_file.$(OBJEXT) \
+	$(OUTPRE)prof_parse.$(OBJEXT) \
+	$(OUTPRE)prof_get.$(OBJEXT) \
+	$(OUTPRE)prof_set.$(OBJEXT) \
+	$(OUTPRE)prof_err.$(OBJEXT) \
+	$(OUTPRE)prof_init.$(OBJEXT)
+
+SRCS = $(srcdir)/prof_tree.c \
+	$(srcdir)/prof_file.c \
+	$(srcdir)/prof_parse.c \
+	$(srcdir)/prof_get.c \
+	$(srcdir)/prof_set.c \
+	prof_err.c \
+	$(srcdir)/prof_init.c
+
+EXTRADEPSRCS=$(srcdir)/test_parse.c $(srcdir)/test_profile.c
+
+DEPLIBS = $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
+MLIBS = -lcom_err $(SUPPORT_LIB) $(LIBS)
+
+LIBBASE=profile
+LIBMAJOR=1
+LIBMINOR=1
+SHLIB_EXPDEPS = $(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
+SHLIB_EXPLIBS = -lcom_err $(SUPPORT_LIB) $(LIBS)
+SHLIB_DIRS = -L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+STOBJLISTS=OBJS.ST
+
+PROFILE_HDR=$(BUILDTOP)$(S)include$(S)profile.h
+
+all-unix:: includes 
+all-unix:: all-libs
+all-windows:: $(PROFILE_HDR)
+
+install-headers-unix:: includes
+
+$(PROFILE_HDR):: profile.h
+	$(CP) profile.h "$@"
+
+includes:: profile.h
+	if cmp profile.h \
+	$(BUILDTOP)/include/profile.h >/dev/null 2>&1; then :; \
+	else \
+		(set -x; $(RM) $(BUILDTOP)/include/profile.h; \
+		 $(CP) profile.h $(BUILDTOP)/include/profile.h) ; \
+	fi
+
+clean-unix::
+	$(RM) $(BUILDTOP)/include/profile.h
+
+##DOS##LIBOBJS = $(OBJS)
+
+
+awk-windows:
+	$(AWK) -f $(BUILDTOP)/util/et/et_h.awk outfile=prof_err.h prof_err.et
+	$(AWK) -f $(BUILDTOP)/util/et/et_c.awk outfile=prof_err.c prof_err.et
+	if exist prof_err.h copy profile.hin+prof_err.h profile.h
+	if exist profile.h copy profile.h $(BUILDTOP)\include\profile.h
+
+test_parse: test_parse.$(OBJEXT) $(OBJS) $(DEPLIBS)
+	$(CC_LINK) -o test_parse test_parse.$(OBJEXT) $(OBJS) $(MLIBS)
+
+test_profile: test_profile.$(OBJEXT) argv_parse.$(OBJEXT) $(OBJS) $(DEPLIBS)
+	$(CC_LINK) -o test_profile test_profile.$(OBJEXT) \
+		argv_parse.$(OBJEXT) $(OBJS) $(MLIBS)
+
+.d: includes
+
+# NEED TO FIX!!
+$(OUTPRE)test_parse.exe: 
+	$(CC) $(CFLAGS2) -o test_parse.exe test_parse.c \
+		prof_parse.c prof_tree.c /link /stack:16384
+
+# NEED TO FIX!!
+$(OUTPRE)test_profile.exe: 
+	$(CC) $(CFLAGS2) -o test_profile.exe test_profile.c prof_init.c \
+		prof_file.c prof_parse.c prof_tree.c /link /stack:16384
+
+profile.h: prof_err.h profile.hin
+	cat $(srcdir)/profile.hin prof_err.h > $@
+
+prof_err.h: $(srcdir)/prof_err.et
+
+prof_err.c: $(srcdir)/prof_err.et
+
+prof_err.o: prof_err.c
+
+# not built by default, but may be useful for testing
+$(srcdir)/profile_tcl.c: profile.swg
+	(cd $(srcdir) && swig -tcl8 -o profile_tcl.c profile.swg)
+profile_tcl.o: $(srcdir)/profile_tcl.c profile.h
+profile_tcl: profile_tcl.o libprofile.a
+	$(CC_LINK) -o profile_tcl profile_tcl.o \
+		$(TCL_MAYBE_RPATH) \
+		-L../et -L../.. libprofile.a $(DEPLIBS) $(TCL_LIBS)
+
+clean-unix:: clean-libs clean-libobjs
+	$(RM) $(PROGS) *.o *~ test_parse core prof_err.h \
+		prof_err.c test_profile profile.h profile_tcl
+
+clean-windows::
+	$(RM) $(PROFILE_HDR)
+
+check-unix:: test_parse test_profile
+
+DO_TCL=@DO_TCL@
+check-unix:: check-unix-tcl-$(DO_TCL)
+
+check-unix-tcl-:
+	@echo "+++"
+	@echo "+++ Tcl not available, some profile tests not run."
+	@echo "+++"
+
+check-unix-tcl-ok: profile_tcl
+	cp $(srcdir)/test.ini test2.ini
+	$(KRB5_RUN_ENV) ./profile_tcl $(srcdir)/prof_test1
+
+check-windows:: $(OUTPRE)test_profile.exe $(OUTPRE)test_parse.exe
+	$(RM) $(OUTPRE)*.obj
+	$(OUTPRE)test_parse test.ini
+
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+prof_tree.so prof_tree.po $(OUTPRE)prof_tree.$(OBJEXT): \
+  prof_tree.c prof_int.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+prof_file.so prof_file.po $(OUTPRE)prof_file.$(OBJEXT): \
+  prof_file.c prof_int.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+prof_parse.so prof_parse.po $(OUTPRE)prof_parse.$(OBJEXT): \
+  prof_parse.c prof_int.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+prof_get.so prof_get.po $(OUTPRE)prof_get.$(OBJEXT): \
+  prof_get.c prof_int.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+prof_set.so prof_set.po $(OUTPRE)prof_set.$(OBJEXT): \
+  prof_set.c prof_int.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+prof_err.so prof_err.po $(OUTPRE)prof_err.$(OBJEXT): \
+  prof_err.c $(COM_ERR_DEPS)
+prof_init.so prof_init.po $(OUTPRE)prof_init.$(OBJEXT): \
+  prof_init.c prof_int.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+test_parse.so test_parse.po $(OUTPRE)test_parse.$(OBJEXT): \
+  test_parse.c prof_int.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h
+test_profile.so test_profile.po $(OUTPRE)test_profile.$(OBJEXT): \
+  test_profile.c prof_int.h $(SRCTOP)/include/k5-thread.h \
+  $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-platform.h \
+  $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h argv_parse.h
diff --git a/mechglue/src/util/profile/argv_parse.c b/mechglue/src/util/profile/argv_parse.c
new file mode 100644
index 000000000..7740d5345
--- /dev/null
+++ b/mechglue/src/util/profile/argv_parse.c
@@ -0,0 +1,168 @@
+/*
+ * argv_parse.c --- utility function for parsing a string into a
+ * 	argc, argv array.
+ * 
+ * This file defines a function argv_parse() which parsing a
+ * passed-in string, handling double quotes and backslashes, and
+ * creates an allocated argv vector which can be freed using the
+ * argv_free() function.
+ *
+ * See argv_parse.h for the formal definition of the functions.
+ *
+ * Copyright 1999 by Theodore Ts'o.
+ * 
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose with or without fee is hereby granted, provided that
+ * the above copyright notice and this permission notice appear in all
+ * copies.  THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE
+ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  (Isn't
+ * it sick that the U.S. culture of lawsuit-happy lawyers requires
+ * this kind of disclaimer?)
+ *
+ * Version 1.1, modified 2/27/1999
+ */
+
+#include "prof_int.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <ctype.h>
+#include <string.h>
+#include "argv_parse.h"
+
+#define STATE_WHITESPACE	1
+#define STATE_TOKEN		2
+#define STATE_QUOTED		3
+
+/*
+ * Returns 0 on success, -1 on failure.
+ */
+int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv)
+{
+	int	argc = 0, max_argc = 0;
+	char 	**argv, **new_argv, *buf, ch;
+	char	*cp = 0, *outcp = 0;
+	int	state = STATE_WHITESPACE;
+
+	buf = malloc(strlen(in_buf)+1);
+	if (!buf)
+		return -1;
+
+	max_argc = 0; argc = 0; argv = 0;
+	outcp = buf;
+	for (cp = in_buf; (ch = *cp); cp++) {
+		if (state == STATE_WHITESPACE) {
+			if (isspace((int) ch))
+				continue;
+			/* Not whitespace, so start a new token */
+			state = STATE_TOKEN;
+			if (argc >= max_argc) {
+				max_argc += 3;
+				new_argv = realloc(argv,
+						  (max_argc+1)*sizeof(char *));
+				if (!new_argv) {
+					if (argv) free(argv);
+					free(buf);
+					return -1;
+				}
+				argv = new_argv;
+			}
+			argv[argc++] = outcp;
+		}
+		if (state == STATE_QUOTED) {
+			if (ch == '"')
+				state = STATE_TOKEN;
+			else
+				*outcp++ = ch;
+			continue;
+		}
+		/* Must be processing characters in a word */
+		if (isspace((int) ch)) {
+			/*
+			 * Terminate the current word and start
+			 * looking for the beginning of the next word.
+			 */
+			*outcp++ = 0;
+			state = STATE_WHITESPACE;
+			continue;
+		}
+		if (ch == '"') {
+			state = STATE_QUOTED;
+			continue;
+		}
+		if (ch == '\\') {
+			ch = *++cp;
+			switch (ch) {
+			case '\0':
+				ch = '\\'; cp--; break;
+			case 'n':
+				ch = '\n'; break;
+			case 't':
+				ch = '\t'; break;
+			case 'b':
+				ch = '\b'; break;
+			}
+		}
+		*outcp++ = ch;
+	}
+	if (state != STATE_WHITESPACE)
+		*outcp++ = '\0';
+	if (argv == 0) {
+		argv = malloc(sizeof(char *));
+		free(buf);
+	}
+	argv[argc] = 0;
+	if (ret_argc)
+		*ret_argc = argc;
+	if (ret_argv)
+		*ret_argv = argv;
+	return 0;
+}
+
+void argv_free(char **argv)
+{
+	if (*argv)
+		free(*argv);
+	free(argv);
+}
+
+#ifdef DEBUG
+/*
+ * For debugging
+ */
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	int	ac, ret;
+	char	**av, **cpp;
+	char	buf[256];
+
+	while (!feof(stdin)) {
+		if (fgets(buf, sizeof(buf), stdin) == NULL)
+			break;
+		ret = argv_parse(buf, &ac, &av);
+		if (ret != 0) {
+			printf("Argv_parse returned %d!\n", ret);
+			continue;
+		}
+		printf("Argv_parse returned %d arguments...\n", ac);
+		for (cpp = av; *cpp; cpp++) {
+			if (cpp != av)
+				printf(", ");
+			printf("'%s'", *cpp);
+		}
+		printf("\n");
+		argv_free(av);
+	}
+	exit(0);
+}
+#endif /* DEBUG */
diff --git a/mechglue/src/util/profile/argv_parse.h b/mechglue/src/util/profile/argv_parse.h
new file mode 100644
index 000000000..84568e7bd
--- /dev/null
+++ b/mechglue/src/util/profile/argv_parse.h
@@ -0,0 +1,43 @@
+/*
+ * argv_parse.h --- header file for the argv parser.
+ *
+ * This file defines the interface for the functions argv_parse() and
+ * argv_free().
+ * 
+ ***********************************************************************
+ * int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv)
+ *
+ * This function takes as its first argument a string which it will
+ * parse into an argv argument vector, with each white-space separated
+ * word placed into its own slot in the argv.  This function handles
+ * double quotes and backslashes so that the parsed words can contain
+ * special characters.   The count of the number words found in the
+ * parsed string, as well as the argument vector, are returned into
+ * ret_argc and ret_argv, respectively.
+ ***********************************************************************
+ * extern void argv_free(char **argv);
+ * 
+ * This function frees the argument vector created by argv_parse().
+ ***********************************************************************
+ *
+ * Copyright 1999 by Theodore Ts'o.
+ * 
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose with or without fee is hereby granted, provided that
+ * the above copyright notice and this permission notice appear in all
+ * copies.  THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE
+ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  (Isn't
+ * it sick that the U.S. culture of lawsuit-happy lawyers requires
+ * this kind of disclaimer?)
+ *
+ * Version 1.1, modified 2/27/1999
+ */
+
+extern int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv);
+extern void argv_free(char **argv);
diff --git a/mechglue/src/util/profile/configure.in b/mechglue/src/util/profile/configure.in
new file mode 100644
index 000000000..44f59088f
--- /dev/null
+++ b/mechglue/src/util/profile/configure.in
@@ -0,0 +1,21 @@
+K5_AC_INIT(prof_parse.c)
+CONFIG_RULES
+AC_C_CONST
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_HEADERS(unistd.h stdlib.h pwd.h)
+AC_CHECK_FUNCS(stat access strdup)
+AC_CHECK_MEMBERS([struct stat.st_mtimensec,struct stat.st_mtimespec.tv_nsec,struct stat.st_mtim.tv_nsec],,,[#include <sys/types.h>
+#include <sys/stat.h>])
+AC_PROG_AWK
+AC_KRB5_TCL
+DO_TCL=
+test "$TCL_LIBS" != "" && DO_TCL=ok
+AC_SUBST(DO_TCL)
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_PROGRAM
+KRB5_BUILD_LIBRARY_WITH_DEPS
+KRB5_RUN_FLAGS
+AC_CONFIG_FILES(prtest, [chmod +x prtest])
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/util/profile/dosshell.ini b/mechglue/src/util/profile/dosshell.ini
new file mode 100644
index 000000000..cec96ec59
--- /dev/null
+++ b/mechglue/src/util/profile/dosshell.ini
@@ -0,0 +1,537 @@
+EGA.INI/VGA.INI
+****************  WARNING  ********************
+This file may contain lines with more than 256
+characters. Some editors will truncate or split
+these lines. If you are not sure whether your
+editor can handle long lines, exit now without
+saving the file.
+
+Note: The editor which is invoked by the
+	  MS-DOS 5.0 EDIT command can be used
+	  to edit this file.
+****************  NOTE  ***********************
+Everything up to the first left square bracket
+character is considered a comment.
+***********************************************
+[savestate]
+screenmode = text
+resolution = low
+startup = filemanager
+filemanagermode = shared
+sortkey = name
+pause = disabled
+explicitselection = disabled
+swapmouse = disabled
+tasklist = disabled
+switching = disabled
+[programstarter]
+currentcolor = Ocean
+filemanager = enabled
+command = enabled
+group = 
+{
+	program = 
+	{
+	command = COMMAND
+	title = Command Prompt
+	help = Starts the MS-DOS command prompt where you can type any MS-DOS command.^m^mTo return to MS-DOS Shell from the command line:^m^m1. Type exit^m2. Press ENTER.^m^mRelated Topic^m   " More on Command Prompt "~$129~
+	pause = disabled
+	}
+	program = 
+	{
+	command = EDIT %1
+	title = Editor
+	help = Starts MS-DOS Editor, a text editor you can use to create and modify text files. After you choose Editor, you can specify the file you want to work with in a dialog box.^m^mRelated Topic^m   " More on Editor "~$130~
+	pause = disabled
+	dialog = 
+	{
+		title = File to Edit
+		info = Enter the name of the file to edit. To start MS-DOS Editor without opening a file, press ENTER.
+		prompt = File to edit?
+		parameter = %1
+	}
+	}
+	program = 
+	{
+	command = QBASIC %1
+	title = MS-DOS QBasic
+	help = Starts MS-DOS QBasic, a programming environment you can use to create, modify, run, and debug programs. After you choose MS-DOS QBasic, you can specify the file you want to work with in a dialog box.^m^mRelated Topic^m   " More on MS-DOS QBasic "~$131~
+	pause = disabled
+	dialog = 
+	{
+		title = MS-DOS QBasic File
+		info = Enter the name of a QBasic program. To start without opening a program, press ENTER.
+		prompt = QBasic File?
+		parameter = %1
+	}
+	}
+	group = 
+	{
+	title = Disk Utilities
+	help = Displays program items you can choose to manage your disks. You can also choose to open the Main group or any group you may have added.
+	program = 
+	{
+		command = diskcopy %1
+		title = Disk Copy
+		pause = enabled
+		dialog = 
+		{
+		title = Disk Copy
+		info = Enter the source and destination drives.
+		prompt = Parameters . . .
+		default = a: b:
+		parameter = %1
+		}
+		help = Temporarily leaves MS-DOS Shell to copy the contents of a floppy disk to another floppy disk. After you choose Disk Copy, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m   " More on Disk Copy "~$132~
+	}
+	program = 
+	{
+		command = backup %1
+		title = Backup Fixed Disk
+		pause = enabled
+		dialog = 
+		{
+		title = Backup Fixed Disk
+		info = Enter the source and destination drives.
+		prompt = Parameters . . .
+		default = c:\*.* a: /s
+		parameter = %1 
+		}
+		help = Temporarily leaves MS-DOS Shell to copy files from one disk to another. After you choose Backup Fixed Disk, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m   " More on Backup Fixed Disk "~$133~
+	}
+	program = 
+	{
+		command = restore %1
+		title = Restore Fixed Disk
+		pause = enabled
+		dialog = 
+		{
+		title = Restore Fixed Disk
+		info = Enter the source and destination drives.
+		prompt = Parameters . . .
+		parameter = %1
+		}
+		help = Temporarily leaves MS-DOS Shell to restore files that were backed up. After you choose Restore Fixed Disk, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m   " More on Restore Fixed Disk "~$134~
+	}
+	program = 
+	{
+		command = format %1 /q
+		title = Quick Format
+		pause = enabled
+		dialog = 
+		{
+		title = Quick Format
+		info = Enter the drive to quick format.
+		prompt = Parameters . . .
+		default = a:
+		parameter = %1
+		}
+		help = Temporarily leaves MS-DOS Shell to prepare a disk to accept MS-DOS files. After you choose Quick Format, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m   " More on Quick Format "~$136~
+		screenmode = text
+		alttab = enabled
+		altesc = enabled
+		ctrlesc = enabled
+		prevent = enabled
+	}
+	program = 
+	{
+		command = format %1
+		title = Format
+		pause = enabled
+		dialog = 
+		{
+		title = Format
+		info = Enter the drive to format.
+		prompt = Parameters . . .
+		default = a:
+		parameter = %1
+		}
+		help = Temporarily leaves MS-DOS Shell to prepare a disk to accept MS-DOS files. After you choose Format, a dialog box suggests parameters and switches you can either accept or replace.^m^mRelated Topic^m   " More on Format "~$135~
+	}
+	program = 
+	{
+		command = undelete %1
+		title = Undelete
+		help = Recovers deleted files.^m^mWARNING: If your disk is full or if you are using task swapping, using this program item may render some deleted files unrecoverable.^m^mRelated Procedure^m   " Restoring Deleted Files "~I155~
+		pause = enabled
+		dialog = 
+		{
+		title = Undelete
+		info = WARNING! This action may cause the permanent loss of some deleted files.  Press F1 for more information.
+		prompt = Parameters . . .
+		default = /LIST
+		parameter = %1
+		}
+		screenmode = text
+		alttab = enabled
+		altesc = enabled
+		ctrlesc = enabled
+		prevent = enabled
+	}
+	}
+}
+color = 
+{
+	selection = 
+	{
+	title = Basic Blue
+	foreground = 
+	{
+		base = black
+		highlight = brightwhite
+		selection = brightwhite
+		alert = brightred
+		menubar = black
+		menu = black
+		disabled = white
+		accelerator = cyan
+		dialog = black
+		button = black
+		elevator = white
+		titlebar = black
+		scrollbar = brightwhite
+		borders = black
+		drivebox = black
+		driveicon = black
+		cursor = black
+	}
+	background = 
+	{
+		base = brightwhite
+		highlight = blue
+		selection = black
+		alert = brightwhite
+		menubar = white
+		menu = brightwhite
+		disabled = brightwhite
+		accelerator = brightwhite
+		dialog = brightwhite
+		button = white
+		elevator = white
+		titlebar = white
+		scrollbar = black
+		borders = brightwhite
+		drivebox = brightwhite
+		driveicon = brightwhite
+		cursor = brightblack
+	}
+	}
+	selection = 
+	{
+	title = Ocean
+	foreground = 
+	{
+		base = black
+		highlight = brightwhite
+		selection = brightwhite
+		alert = brightwhite
+		menubar = black
+		menu = black
+		disabled = white
+		accelerator = brightwhite
+		dialog = black
+		button = black
+		elevator = white
+		titlebar = black
+		scrollbar = brightwhite
+		borders = black
+		drivebox = black
+		driveicon = black
+		cursor = black
+	}
+	background = 
+	{
+		base = brightwhite
+		highlight = blue
+		selection = black
+		alert = white
+		menubar = cyan
+		menu = cyan
+		disabled = cyan
+		accelerator = cyan
+		dialog = cyan
+		button = brightwhite
+		elevator = white
+		titlebar = white
+		scrollbar = black
+		borders = black
+		drivebox = brightwhite
+		driveicon = brightwhite
+		cursor = brightcyan
+	}
+	}
+	selection = 
+	{
+	title = Monochrome-2 Colors
+	foreground = 
+	{
+		base = black
+		highlight = white
+		selection = white
+		alert = black
+		menubar = black
+		menu = black
+		disabled = white
+		accelerator = white
+		dialog = black
+		button = white
+		elevator = black
+		titlebar = white
+		scrollbar = white
+		borders = black
+		drivebox = black
+		driveicon = black
+	}
+	background = 
+	{
+		base = white
+		highlight = black
+		selection = black
+		alert = white
+		menubar = white
+		menu = white
+		disabled = white
+		accelerator = black
+		dialog = white
+		button = black
+		elevator = white
+		titlebar = black
+		scrollbar = black
+		borders = black
+		drivebox = white
+		driveicon = white
+	}
+	}
+	selection = 
+	{
+	title = Monochrome-4 Colors
+	foreground = 
+	{
+		base = black
+		highlight = brightwhite
+		selection = brightwhite
+		alert = black
+		menubar = black
+		menu = black
+		disabled = white
+		accelerator = brightwhite
+		dialog = black
+		button = black
+		elevator = white
+		titlebar = black
+		scrollbar = brightwhite
+		borders = black
+		drivebox = black
+		driveicon = black
+		cursor = black
+	}
+	background = 
+	{
+		base = brightwhite
+		highlight = brightblack
+		selection = brightblack
+		alert = brightwhite
+		menubar = brightwhite
+		menu = white
+		disabled = white
+		accelerator = brightblack
+		dialog = brightwhite
+		button = white
+		elevator = white
+		titlebar = white
+		scrollbar = black
+		borders = black
+		drivebox = brightwhite
+		driveicon = brightwhite
+		cursor = black
+	}
+	}
+	selection = 
+	{
+	title = Reverse
+	foreground = 
+	{
+		base = white
+		highlight = black
+		selection = black
+		alert = white
+		menubar = white
+		menu = white
+		disabled = black
+		accelerator = black
+		dialog = white
+		button = black
+		elevator = white
+		titlebar = black
+		scrollbar = black
+		borders = white
+		drivebox = white
+		driveicon = white
+	}
+	background = 
+	{
+		base = black
+		highlight = white
+		selection = white
+		alert = black
+		menubar = black
+		menu = black
+		disabled = black
+		accelerator = white
+		dialog = black
+		button = white
+		elevator = black
+		titlebar = white
+		scrollbar = white
+		borders = black
+		drivebox = black
+		driveicon = black
+	}
+	}
+	selection = 
+	{
+	title = Hot Pink
+	foreground = 
+	{
+		base = black
+		highlight = brightwhite
+		selection = brightwhite
+		alert = brightmagenta
+		menubar = black
+		menu = black
+		disabled = white
+		accelerator = magenta
+		dialog = black
+		button = brightwhite
+		elevator = white
+		titlebar = brightwhite
+		scrollbar = brightwhite
+		borders = black
+		drivebox = black
+		driveicon = black
+		cursor = black
+	}
+	background = 
+	{
+		base = brightwhite
+		highlight = brightmagenta
+		selection = magenta
+		alert = brightwhite
+		menubar = brightwhite
+		menu = brightwhite
+		disabled = brightwhite
+		accelerator = brightwhite
+		dialog = brightwhite
+		button = magenta
+		elevator = white
+		titlebar = magenta
+		scrollbar = black
+		borders = black
+		drivebox = brightwhite
+		driveicon = brightwhite
+		cursor = brightred
+	}
+	}
+	selection = 
+	{
+	title = Emerald City
+	foreground = 
+	{
+		base = black
+		highlight = black
+		selection = brightwhite
+		alert = green
+		menubar = black
+		menu = black
+		disabled = white
+		accelerator = green
+		dialog = black
+		button = brightwhite
+		elevator = white
+		titlebar = brightwhite
+		scrollbar = brightwhite
+		borders = black
+		drivebox = black
+		driveicon = black
+		cursor = black
+	}
+	background = 
+	{
+		base = brightwhite
+		highlight = brightgreen
+		selection = green
+		alert = brightwhite
+		menubar = brightwhite
+		menu = brightwhite
+		disabled = brightwhite
+		accelerator = brightwhite
+		dialog = brightwhite
+		button = green
+		elevator = white
+		titlebar = green
+		scrollbar = black
+		borders = black
+		drivebox = brightwhite
+		driveicon = brightwhite
+		cursor = brightcyan
+	}
+	}
+	selection = 
+	{
+	title = Turquoise
+	foreground = 
+	{
+		base = black
+		highlight = brightwhite
+		selection = brightwhite
+		alert = brightred
+		menubar = brightwhite
+		menu = black
+		disabled = white
+		accelerator = white
+		dialog = black
+		button = black
+		elevator = white
+		titlebar = black
+		scrollbar = brightwhite
+		borders = black
+		drivebox = black
+		driveicon = black
+		cursor = black
+	}
+	background = 
+	{
+		base = brightwhite
+		highlight = brightblue
+		selection = black
+		alert = brightwhite
+		menubar = brightcyan
+		menu = brightcyan
+		disabled = brightcyan
+		accelerator = brightcyan
+		dialog = brightcyan
+		button = brightwhite
+		elevator = white
+		titlebar = white
+		scrollbar = black
+		borders = black
+		drivebox = brightwhite
+		driveicon = brightwhite
+		cursor = cyan
+	}
+	}
+}
+
+associations = 
+{
+	association = 
+	{
+	program = EDIT
+	extension = TXT
+	}
+	association = 
+	{
+	program = QBASIC /run 
+	extension = BAS
+	}
+}
diff --git a/mechglue/src/util/profile/krb5.conf b/mechglue/src/util/profile/krb5.conf
new file mode 100644
index 000000000..19c59c60d
--- /dev/null
+++ b/mechglue/src/util/profile/krb5.conf
@@ -0,0 +1,57 @@
+[libdefaults]
+	default_realm = ATHENA.MIT.EDU 
+	default_tgs_enctypes = des-cbc-crc
+	default_tkt_enctypes = des-cbc-crc
+	krb4_config = /etc/athena/krb.conf
+	krb4_realms = /etc/athena/krb.realms
+	default_keytab_name = FILE:/etc/krb5.keytab
+	kdc_timesync = 1
+	ccache_type = 4
+
+[realms] 
+	ATHENA.MIT.EDU = { 
+#		kdc = kerberos-2000.mit.edu
+		kdc = kerberos.mit.edu:88
+		kdc = kerberos-1.mit.edu:88
+		kdc = kerberos-2.mit.edu:88
+		kdc = kerberos-3.mit.edu:88
+		admin_server = kerberos.mit.edu
+		default_domain = mit.edu
+	} 
+	MEDIA-LAB.MIT.EDU = {
+		kdc = kerberos.media.mit.edu
+		admin_server = kerberos.media.mit.edu
+	}
+	ZONE.MIT.EDU = {
+		kdc = casio.mit.edu
+		kdc = seiko.mit.edu
+		admin_server = casio.mit.edu
+	}
+	MOOF.MIT.EDU = {
+		kdc = three-headed-dogcow.mit.edu:88
+		kdc = three-headed-dogcow-1.mit.edu:88
+		admin_server = three-headed-dogcow.mit.edu
+	}
+	CYGNUS.COM = {
+		kdc = KERBEROS-1.CYGNUS.COM
+		kdc = KERBEROS.CYGNUS.COM
+		admin_server = KERBEROS.CYGNUS.COM
+	}
+	GREY17.ORG = {
+		kdc = kerberos.grey17.org
+		admin_server = kerberos.grey17.org
+	}
+	IHTFP.ORG = {
+		kdc = kerberos.ihtfp.org
+		admin_server = kerberos.ihtfp.org
+	}
+
+[domain_realm]
+	.mit.edu = ATHENA.MIT.EDU
+	mit.edu = ATHENA.MIT.EDU
+	.media.mit.edu = MEDIA-LAB.MIT.EDU
+	media.mit.edu = MEDIA-LAB.MIT.EDU
+
+[login]
+	krb4_convert = true
+	krb4_get_tickets = true
diff --git a/mechglue/src/util/profile/libprofile.exports b/mechglue/src/util/profile/libprofile.exports
new file mode 100644
index 000000000..26db5e898
--- /dev/null
+++ b/mechglue/src/util/profile/libprofile.exports
@@ -0,0 +1,55 @@
+et_prof_error_table
+initialize_prof_error_table
+profile_abandon
+profile_add_node
+profile_add_relation
+profile_clear_relation
+profile_close_file
+profile_create_node
+profile_dereference_data
+profile_find_node
+profile_find_node_relation
+profile_find_node_subsection
+profile_flush
+profile_flush_file_data
+profile_free_file
+profile_free_list
+profile_free_node
+profile_get_boolean
+profile_get_integer
+profile_get_node_name
+profile_get_node_parent
+profile_get_node_value
+profile_get_relation_names
+profile_get_string
+profile_get_subsection_names
+profile_get_value
+profile_get_values
+profile_init
+profile_init_path
+profile_is_node_final
+profile_iterator
+profile_iterator_create
+profile_iterator_free
+profile_make_node_final
+profile_node_iterator
+profile_node_iterator_create
+profile_node_iterator_free
+profile_open_file
+profile_parse_file
+profile_release
+profile_release_string
+profile_remove_node
+profile_rename_node
+profile_rename_section
+profile_ser_externalize
+profile_ser_internalize
+profile_ser_size
+profile_set_relation_value
+profile_update_file_data
+profile_update_relation
+profile_verify_node
+profile_write_tree_file
+profile_flush_to_file
+profile_flush_to_buffer
+profile_free_buffer
diff --git a/mechglue/src/util/profile/prof_FSp_glue.c b/mechglue/src/util/profile/prof_FSp_glue.c
new file mode 100644
index 000000000..511c85f15
--- /dev/null
+++ b/mechglue/src/util/profile/prof_FSp_glue.c
@@ -0,0 +1,91 @@
+/*
+ * prof_FSp_glue.c --- Deprecated FSSpec functions.  Mac-only.
+ */
+
+#include "prof_int.h"
+
+#include <Kerberos/FSpUtils.h>
+#include <limits.h>
+
+long KRB5_CALLCONV FSp_profile_init (const FSSpec* files, profile_t *ret_profile);
+
+long KRB5_CALLCONV FSp_profile_init_path (const FSSpec* files, profile_t *ret_profile);
+
+errcode_t KRB5_CALLCONV
+FSp_profile_init(files, ret_profile)
+	const FSSpec* files;
+	profile_t *ret_profile;
+{
+    unsigned int        fileCount = 0;
+    const FSSpec       *nextSpec;
+    profile_filespec_t *pathArray = NULL;
+    unsigned int        i;
+    errcode_t           retval = 0;
+
+    for (nextSpec = files; ; nextSpec++) {
+        if ((nextSpec -> vRefNum == 0) &&
+            (nextSpec -> parID == 0) &&
+            (StrLength (nextSpec -> name) == 0))
+            break;
+        fileCount++;
+    }
+    
+    pathArray = (profile_filespec_t *) malloc ((fileCount + 1) * sizeof(const_profile_filespec_t));
+    if (pathArray == NULL) {
+        retval = ENOMEM;
+    }
+    
+    if (retval == 0) {
+        for (i = 0; i < fileCount + 1; i++) {
+            pathArray [i] = NULL;
+        }
+    }
+        
+    if (retval == 0) {
+        for (i = 0; i < fileCount; i++) {
+            OSStatus err = noErr;
+            
+            if (err == noErr) {
+                pathArray[i] = (char *) malloc (sizeof(char) * PATH_MAX);
+                if (pathArray[i] == NULL) {
+                    err = memFullErr;
+                }
+            }
+            /* convert the FSSpec to an path */
+            if (err == noErr) {
+                err = FSSpecToPOSIXPath (&files[i], pathArray[i], PATH_MAX);
+            }
+
+            if (err == memFullErr) {
+                retval = ENOMEM;
+                break;
+            } else if (err != noErr) {
+                retval = ENOENT;
+                break;
+            }
+        }
+    }
+    
+    if (retval == 0) {
+        retval = profile_init ((const_profile_filespec_t *) pathArray, 
+                               ret_profile);
+    }
+    
+    if (pathArray != NULL) {
+        for (i = 0; i < fileCount; i++) {
+            if (pathArray [i] != 0)
+                free (pathArray [i]);
+        }
+        free (pathArray);
+    }
+    
+    return retval;
+}
+
+errcode_t KRB5_CALLCONV
+FSp_profile_init_path(files, ret_profile)
+	const FSSpec* files;
+	profile_t *ret_profile;
+{
+    return FSp_profile_init (files, ret_profile);
+}
diff --git a/mechglue/src/util/profile/prof_err.et b/mechglue/src/util/profile/prof_err.et
new file mode 100644
index 000000000..af7801ee0
--- /dev/null
+++ b/mechglue/src/util/profile/prof_err.et
@@ -0,0 +1,66 @@
+error_table prof
+
+error_code	PROF_VERSION,	"Profile version 0.0"
+
+#
+# generated by prof_tree.c
+#
+error_code	PROF_MAGIC_NODE,	"Bad magic value in profile_node"
+error_code	PROF_NO_SECTION,	"Profile section not found"
+error_code	PROF_NO_RELATION,	"Profile relation not found"
+error_code	PROF_ADD_NOT_SECTION, 
+	"Attempt to add a relation to node which is not a section"
+error_code	PROF_SECTION_WITH_VALUE, 
+	"A profile section header has a non-zero value"
+error_code	PROF_BAD_LINK_LIST, 	"Bad linked list in profile structures"
+error_code	PROF_BAD_GROUP_LVL, 	"Bad group level in profile strctures"
+error_code	PROF_BAD_PARENT_PTR, 	
+	"Bad parent pointer in profile strctures"
+error_code	PROF_MAGIC_ITERATOR,	"Bad magic value in profile iterator"
+error_code	PROF_SET_SECTION_VALUE,	"Can't set value on section node"
+error_code	PROF_EINVAL,		"Invalid argument passed to profile library"
+error_code	PROF_READ_ONLY,		"Attempt to modify read-only profile"
+
+#
+# generated by prof_parse.c
+#
+
+error_code	PROF_SECTION_NOTOP, "Profile section header not at top level"
+error_code	PROF_SECTION_SYNTAX, "Syntax error in profile section header"
+error_code	PROF_RELATION_SYNTAX, "Syntax error in profile relation"
+error_code	PROF_EXTRA_CBRACE, "Extra closing brace in profile"
+error_code	PROF_MISSING_OBRACE, "Missing open brace in profile"
+
+#
+# generated by prof_init.c
+# 
+error_code	PROF_MAGIC_PROFILE,	"Bad magic value in profile_t"
+error_code	PROF_MAGIC_SECTION,	"Bad magic value in profile_section_t"
+error_code	PROF_TOPSECTION_ITER_NOSUPP,
+	"Iteration through all top level section not supported"
+error_code	PROF_INVALID_SECTION,	"Invalid profile_section object"
+error_code	PROF_END_OF_SECTIONS,	"No more sections"
+error_code	PROF_BAD_NAMESET,	"Bad nameset passed to query routine"
+error_code	PROF_NO_PROFILE,	"No profile file open"
+
+#
+# generated by prof_file.c
+#
+error_code      PROF_MAGIC_FILE,	"Bad magic value in profile_file_t"
+error_code	PROF_FAIL_OPEN,		"Couldn't open profile file"
+
+#
+# generated by prof_set.c
+#
+error_code	PROF_EXISTS,		"Section already exists"
+
+#
+# generated by prof_get.c
+#
+error_code	PROF_BAD_BOOLEAN,		"Invalid boolean value"
+error_code	PROF_BAD_INTEGER,		"Invalid integer value"
+
+error_code	PROF_MAGIC_FILE_DATA, "Bad magic value in profile_file_data_t"
+
+
+end
diff --git a/mechglue/src/util/profile/prof_file.c b/mechglue/src/util/profile/prof_file.c
new file mode 100644
index 000000000..265ccd6cf
--- /dev/null
+++ b/mechglue/src/util/profile/prof_file.c
@@ -0,0 +1,607 @@
+/*
+ * prof_file.c ---- routines that manipulate an individual profile file.
+ */
+
+#include "prof_int.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stddef.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#if defined(_WIN32)
+#include <io.h>
+#define HAVE_STAT	
+#define stat _stat
+#endif
+
+#include "k5-platform.h"
+
+struct global_shared_profile_data {
+	/* This is the head of the global list of shared trees */
+	prf_data_t trees;
+	/* Lock for above list.  */
+	k5_mutex_t mutex;
+};
+#define g_shared_trees		(krb5int_profile_shared_data.trees)
+#define g_shared_trees_mutex	(krb5int_profile_shared_data.mutex)
+
+static struct global_shared_profile_data krb5int_profile_shared_data = {
+    0,
+    K5_MUTEX_PARTIAL_INITIALIZER
+};
+
+MAKE_INIT_FUNCTION(profile_library_initializer);
+MAKE_FINI_FUNCTION(profile_library_finalizer);
+
+int profile_library_initializer(void)
+{
+#ifdef SHOW_INITFINI_FUNCS
+    printf("profile_library_initializer\n");
+#endif
+#if !USE_BUNDLE_ERROR_STRINGS
+    add_error_table(&et_prof_error_table);
+#endif
+    return k5_mutex_finish_init(&g_shared_trees_mutex);
+}
+void profile_library_finalizer(void)
+{
+    if (! INITIALIZER_RAN(profile_library_initializer) || PROGRAM_EXITING()) {
+#ifdef SHOW_INITFINI_FUNCS
+	printf("profile_library_finalizer: skipping\n");
+#endif
+	return;
+    }
+#ifdef SHOW_INITFINI_FUNCS
+    printf("profile_library_finalizer\n");
+#endif
+    k5_mutex_destroy(&g_shared_trees_mutex);
+#if !USE_BUNDLE_ERROR_STRINGS
+    remove_error_table(&et_prof_error_table);
+#endif
+}
+
+static void profile_free_file_data(prf_data_t);
+
+#if 0
+
+#define scan_shared_trees_locked()				\
+	{							\
+	    prf_data_t d;					\
+	    k5_mutex_assert_locked(&g_shared_trees_mutex);	\
+	    for (d = g_shared_trees; d; d = d->next) {		\
+		assert(d->magic == PROF_MAGIC_FILE_DATA);	\
+		assert((d->flags & PROFILE_FILE_SHARED) != 0);	\
+		assert(d->filespec[0] != 0);			\
+		assert(d->fslen <= 1000); /* XXX */		\
+		assert(d->filespec[d->fslen] == 0);		\
+		assert(d->fslen = strlen(d->filespec));		\
+		assert(d->root != NULL);			\
+	    }							\
+	}
+
+#define scan_shared_trees_unlocked()			\
+	{						\
+	    int r;					\
+	    r = k5_mutex_lock(&g_shared_trees_mutex);	\
+	    assert (r == 0);				\
+	    scan_shared_trees_locked();			\
+	    k5_mutex_unlock(&g_shared_trees_mutex);	\
+	}
+
+#else
+
+#define scan_shared_trees_locked()	{ ; }
+#define scan_shared_trees_unlocked()	{ ; }
+
+#endif
+
+static int rw_access(const_profile_filespec_t filespec)
+{
+#ifdef HAVE_ACCESS
+	if (access(filespec, W_OK) == 0)
+		return 1;
+	else
+		return 0;
+#else
+	/*
+	 * We're on a substandard OS that doesn't support access.  So
+	 * we kludge a test using stdio routines, and hope fopen
+	 * checks the r/w permissions.
+	 */
+	FILE	*f;
+
+	f = fopen(filespec, "r+");
+	if (f) {
+		fclose(f);
+		return 1;
+	}
+	return 0;
+#endif
+}
+
+static int r_access(const_profile_filespec_t filespec)
+{
+#ifdef HAVE_ACCESS
+	if (access(filespec, R_OK) == 0)
+		return 1;
+	else
+		return 0;
+#else
+	/*
+	 * We're on a substandard OS that doesn't support access.  So
+	 * we kludge a test using stdio routines, and hope fopen
+	 * checks the r/w permissions.
+	 */
+	FILE	*f;
+
+	f = fopen(filespec, "r");
+	if (f) {
+		fclose(f);
+		return 1;
+	}
+	return 0;
+#endif
+}
+
+prf_data_t
+profile_make_prf_data(const char *filename)
+{
+    prf_data_t d;
+    size_t len, flen, slen;
+    char *fcopy;
+
+    flen = strlen(filename);
+    slen = offsetof(struct _prf_data_t, filespec);
+    len = slen + flen + 1;
+    if (len < sizeof(struct _prf_data_t))
+	len = sizeof(struct _prf_data_t);
+    d = malloc(len);
+    if (d == NULL)
+	return NULL;
+    memset(d, 0, len);
+    fcopy = (char *) d + slen;
+    assert(fcopy == d->filespec);
+    strcpy(fcopy, filename);
+    d->refcount = 1;
+    d->comment = NULL;
+    d->magic = PROF_MAGIC_FILE_DATA;
+    d->root = NULL;
+    d->next = NULL;
+    d->fslen = flen;
+    return d;
+}
+
+errcode_t profile_open_file(const_profile_filespec_t filespec,
+			    prf_file_t *ret_prof)
+{
+	prf_file_t	prf;
+	errcode_t	retval;
+	char		*home_env = 0;
+	unsigned int	len;
+	prf_data_t	data;
+	char		*expanded_filename;
+
+	retval = CALL_INIT_FUNCTION(profile_library_initializer);
+	if (retval)
+		return retval;
+
+	scan_shared_trees_unlocked();
+
+	prf = malloc(sizeof(struct _prf_file_t));
+	if (!prf)
+		return ENOMEM;
+	memset(prf, 0, sizeof(struct _prf_file_t));
+	prf->magic = PROF_MAGIC_FILE;
+
+	len = strlen(filespec)+1;
+	if (filespec[0] == '~' && filespec[1] == '/') {
+		home_env = getenv("HOME");
+#ifdef HAVE_PWD_H
+		if (home_env == NULL) {
+		    uid_t uid;
+		    struct passwd *pw, pwx;
+		    char pwbuf[BUFSIZ];
+
+		    uid = getuid();
+		    if (!k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw)
+			&& pw != NULL && pw->pw_dir[0] != 0)
+			home_env = pw->pw_dir;
+		}
+#endif
+		if (home_env)
+			len += strlen(home_env);
+	}
+	expanded_filename = malloc(len);
+	if (expanded_filename == 0)
+	    return errno;
+	if (home_env) {
+	    strcpy(expanded_filename, home_env);
+	    strcat(expanded_filename, filespec+1);
+	} else
+	    memcpy(expanded_filename, filespec, len);
+
+	retval = k5_mutex_lock(&g_shared_trees_mutex);
+	if (retval) {
+	    free(expanded_filename);
+	    free(prf);
+	    scan_shared_trees_unlocked();
+	    return retval;
+	}
+	scan_shared_trees_locked();
+	for (data = g_shared_trees; data; data = data->next) {
+	    if (!strcmp(data->filespec, expanded_filename)
+		/* Check that current uid has read access.  */
+		&& r_access(data->filespec))
+		break;
+	}
+	if (data) {
+	    data->refcount++;
+	    (void) k5_mutex_unlock(&g_shared_trees_mutex);
+	    retval = profile_update_file_data(data);
+	    free(expanded_filename);
+	    prf->data = data;
+	    *ret_prof = prf;
+	    scan_shared_trees_unlocked();
+	    return retval;
+	}
+	(void) k5_mutex_unlock(&g_shared_trees_mutex);
+	data = profile_make_prf_data(expanded_filename);
+	if (data == NULL) {
+	    free(prf);
+	    free(expanded_filename);
+	    return ENOMEM;
+	}
+	free(expanded_filename);
+	prf->data = data;
+
+	retval = k5_mutex_init(&data->lock);
+	if (retval) {
+	    free(data);
+	    free(prf);
+	    return retval;
+	}
+
+	retval = profile_update_file(prf);
+	if (retval) {
+		profile_close_file(prf);
+		return retval;
+	}
+
+	retval = k5_mutex_lock(&g_shared_trees_mutex);
+	if (retval) {
+	    profile_close_file(prf);
+	    scan_shared_trees_unlocked();
+	    return retval;
+	}
+	scan_shared_trees_locked();
+	data->flags |= PROFILE_FILE_SHARED;
+	data->next = g_shared_trees;
+	g_shared_trees = data;
+	scan_shared_trees_locked();
+	(void) k5_mutex_unlock(&g_shared_trees_mutex);
+
+	*ret_prof = prf;
+	return 0;
+}
+
+errcode_t profile_update_file_data(prf_data_t data)
+{
+	errcode_t retval;
+#ifdef HAVE_STAT
+	struct stat st;
+	unsigned long frac;
+	time_t now;
+#endif
+	FILE *f;
+
+	retval = k5_mutex_lock(&data->lock);
+	if (retval)
+	    return retval;
+
+#ifdef HAVE_STAT
+	now = time(0);
+	if (now == data->last_stat && data->root != NULL) {
+	    k5_mutex_unlock(&data->lock);
+	    return 0;
+	}
+	if (stat(data->filespec, &st)) {
+	    retval = errno;
+	    k5_mutex_unlock(&data->lock);
+	    return retval;
+	}
+	data->last_stat = now;
+#if defined HAVE_STRUCT_STAT_ST_MTIMENSEC
+	frac = st.st_mtimensec;
+#elif defined HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
+	frac = st.st_mtimespec.tv_nsec;
+#elif defined HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+	frac = st.st_mtim.tv_nsec;
+#else
+	frac = 0;
+#endif
+	if (st.st_mtime == data->timestamp
+	    && frac == data->frac_ts
+	    && data->root != NULL) {
+	    k5_mutex_unlock(&data->lock);
+	    return 0;
+	}
+	if (data->root) {
+		profile_free_node(data->root);
+		data->root = 0;
+	}
+	if (data->comment) {
+		free(data->comment);
+		data->comment = 0;
+	}
+#else
+	/*
+	 * If we don't have the stat() call, assume that our in-core
+	 * memory image is correct.  That is, we won't reread the
+	 * profile file if it changes.
+	 */
+	if (data->root) {
+	    k5_mutex_unlock(&data->lock);
+	    return 0;
+	}
+#endif
+	errno = 0;
+	f = fopen(data->filespec, "r");
+	if (f == NULL) {
+		retval = errno;
+		k5_mutex_unlock(&data->lock);
+		if (retval == 0)
+			retval = ENOENT;
+		return retval;
+	}
+	data->upd_serial++;
+	data->flags &= PROFILE_FILE_SHARED;
+	if (rw_access(data->filespec))
+		data->flags |= PROFILE_FILE_RW;
+	retval = profile_parse_file(f, &data->root);
+	fclose(f);
+	if (retval) {
+	    k5_mutex_unlock(&data->lock);
+	    return retval;
+	}
+	assert(data->root != NULL);
+#ifdef HAVE_STAT
+	data->timestamp = st.st_mtime;
+	data->frac_ts = frac;
+#endif
+	k5_mutex_unlock(&data->lock);
+	return 0;
+}
+
+static int
+make_hard_link(const char *oldpath, const char *newpath)
+{
+#ifdef _WIN32
+    return -1;
+#else
+    return link(oldpath, newpath);
+#endif
+}
+
+static errcode_t write_data_to_file(prf_data_t data, const char *outfile,
+				    int can_create)
+{
+	FILE		*f;
+	profile_filespec_t new_file;
+	profile_filespec_t old_file;
+	errcode_t	retval = 0;
+
+	retval = ENOMEM;
+	
+	new_file = old_file = 0;
+	new_file = malloc(strlen(outfile) + 5);
+	if (!new_file)
+		goto errout;
+	old_file = malloc(strlen(outfile) + 5);
+	if (!old_file)
+		goto errout;
+
+	sprintf(new_file, "%s.$$$", outfile);
+	sprintf(old_file, "%s.bak", outfile);
+
+	errno = 0;
+
+	f = fopen(new_file, "w");
+	if (!f) {
+		retval = errno;
+		if (retval == 0)
+			retval = PROF_FAIL_OPEN;
+		goto errout;
+	}
+
+	profile_write_tree_file(data->root, f);
+	if (fclose(f) != 0) {
+		retval = errno;
+		goto errout;
+	}
+
+	unlink(old_file);
+	if (make_hard_link(outfile, old_file) == 0) {
+	    /* Okay, got the hard link.  Yay.  Now we've got our
+	       backup version, so just put the new version in
+	       place.  */
+	    if (rename(new_file, outfile)) {
+		/* Weird, the rename didn't work.  But the old version
+		   should still be in place, so no special cleanup is
+		   needed.  */
+		retval = errno;
+		goto errout;
+	    }
+	} else if (errno == ENOENT && can_create) {
+	    if (rename(new_file, outfile)) {
+		retval = errno;
+		goto errout;
+	    }
+	} else {
+	    /* Couldn't make the hard link, so there's going to be a
+	       small window where data->filespec does not refer to
+	       either version.  */
+#ifndef _WIN32
+	    sync();
+#endif
+	    if (rename(outfile, old_file)) {
+		retval = errno;
+		goto errout;
+	    }
+	    if (rename(new_file, outfile)) {
+		retval = errno;
+		rename(old_file, outfile); /* back out... */
+		goto errout;
+	    }
+	}
+
+	data->flags = 0;
+	if (rw_access(outfile))
+		data->flags |= PROFILE_FILE_RW;
+	retval = 0;
+
+errout:
+	if (new_file)
+		free(new_file);
+	if (old_file)
+		free(old_file);
+	return retval;
+}
+
+errcode_t profile_flush_file_data_to_buffer (prf_data_t data, char **bufp)
+{
+	errcode_t	retval;
+	retval = k5_mutex_lock(&data->lock);
+	if (retval)
+		return retval;
+	retval = profile_write_tree_to_buffer(data->root, bufp);
+	k5_mutex_unlock(&data->lock);
+	return retval;
+}
+
+errcode_t profile_flush_file_data(prf_data_t data)
+{
+	errcode_t	retval = 0;
+
+	if (!data || data->magic != PROF_MAGIC_FILE_DATA)
+		return PROF_MAGIC_FILE_DATA;
+
+	retval = k5_mutex_lock(&data->lock);
+	if (retval)
+	    return retval;
+	
+	if ((data->flags & PROFILE_FILE_DIRTY) == 0) {
+	    k5_mutex_unlock(&data->lock);
+	    return 0;
+	}
+
+	retval = write_data_to_file(data, data->filespec, 0);
+	k5_mutex_unlock(&data->lock);
+	return retval;
+}
+
+errcode_t profile_flush_file_data_to_file(prf_data_t data, const char *outfile)
+{
+    errcode_t retval = 0;
+
+    if (!data || data->magic != PROF_MAGIC_FILE_DATA)
+	return PROF_MAGIC_FILE_DATA;
+
+    retval = k5_mutex_lock(&data->lock);
+    if (retval)
+	return retval;
+    retval = write_data_to_file(data, outfile, 1);
+    k5_mutex_unlock(&data->lock);
+    return retval;
+}
+
+
+
+void profile_dereference_data(prf_data_t data)
+{
+    int err;
+    err = k5_mutex_lock(&g_shared_trees_mutex);
+    if (err)
+	return;
+    profile_dereference_data_locked(data);
+    (void) k5_mutex_unlock(&g_shared_trees_mutex);
+}
+void profile_dereference_data_locked(prf_data_t data)
+{
+    scan_shared_trees_locked();
+    data->refcount--;
+    if (data->refcount == 0)
+	profile_free_file_data(data);
+    scan_shared_trees_locked();
+}
+
+int profile_lock_global()
+{
+    return k5_mutex_lock(&g_shared_trees_mutex);
+}
+int profile_unlock_global()
+{
+    return k5_mutex_unlock(&g_shared_trees_mutex);
+}
+
+void profile_free_file(prf_file_t prf)
+{
+    profile_dereference_data(prf->data);
+    free(prf);
+}
+
+/* Call with mutex locked!  */
+static void profile_free_file_data(prf_data_t data)
+{
+    scan_shared_trees_locked();
+    if (data->flags & PROFILE_FILE_SHARED) {
+	/* Remove from linked list.  */
+	if (g_shared_trees == data)
+	    g_shared_trees = data->next;
+	else {
+	    prf_data_t prev, next;
+	    prev = g_shared_trees;
+	    next = prev->next;
+	    while (next) {
+		if (next == data) {
+		    prev->next = next->next;
+		    break;
+		}
+		prev = next;
+		next = next->next;
+	    }
+	}
+    }
+    if (data->root)
+	profile_free_node(data->root);
+    if (data->comment)
+	free(data->comment);
+    data->magic = 0;
+    k5_mutex_destroy(&data->lock);
+    free(data);
+    scan_shared_trees_locked();
+}
+
+errcode_t profile_close_file(prf_file_t prf)
+{
+	errcode_t	retval;
+	
+	retval = profile_flush_file(prf);
+	if (retval)
+		return retval;
+	profile_free_file(prf);
+	return 0;
+}
diff --git a/mechglue/src/util/profile/prof_get.c b/mechglue/src/util/profile/prof_get.c
new file mode 100644
index 000000000..08fac7f06
--- /dev/null
+++ b/mechglue/src/util/profile/prof_get.c
@@ -0,0 +1,462 @@
+/*
+ * prof_get.c --- routines that expose the public interfaces for
+ * 	querying items from the profile.
+ *
+ */
+
+#include "prof_int.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#include <limits.h>
+
+/*
+ * These functions --- init_list(), end_list(), and add_to_list() are
+ * internal functions used to build up a null-terminated char ** list
+ * of strings to be returned by functions like profile_get_values.
+ *
+ * The profile_string_list structure is used for internal booking
+ * purposes to build up the list, which is returned in *ret_list by
+ * the end_list() function.
+ *
+ * The publicly exported interface for freeing char** list is
+ * profile_free_list().
+ */
+
+struct profile_string_list {
+	char	**list;
+	int	num;
+	int	max;
+};
+
+/*
+ * Initialize the string list abstraction.
+ */
+static errcode_t init_list(struct profile_string_list *list)
+{
+	list->num = 0;
+	list->max = 10;
+	list->list = malloc(list->max * sizeof(char *));
+	if (list->list == 0)
+		return ENOMEM;
+	list->list[0] = 0;
+	return 0;
+}
+
+/*
+ * Free any memory left over in the string abstraction, returning the
+ * built up list in *ret_list if it is non-null.
+ */
+static void end_list(struct profile_string_list *list, char ***ret_list)
+{
+	char	**cp;
+
+	if (list == 0)
+		return;
+
+	if (ret_list) {
+		*ret_list = list->list;
+		return;
+	} else {
+		for (cp = list->list; *cp; cp++)
+			free(*cp);
+		free(list->list);
+	}
+	list->num = list->max = 0;
+	list->list = 0;
+}
+
+/*
+ * Add a string to the list.
+ */
+static errcode_t add_to_list(struct profile_string_list *list, const char *str)
+{
+	char 	*newstr, **newlist;
+	int	newmax;
+	
+	if (list->num+1 >= list->max) {
+		newmax = list->max + 10;
+		newlist = realloc(list->list, newmax * sizeof(char *));
+		if (newlist == 0)
+			return ENOMEM;
+		list->max = newmax;
+		list->list = newlist;
+	}
+	newstr = malloc(strlen(str)+1);
+	if (newstr == 0)
+		return ENOMEM;
+	strcpy(newstr, str);
+
+	list->list[list->num++] = newstr;
+	list->list[list->num] = 0;
+	return 0;
+}
+
+/*
+ * Return TRUE if the string is already a member of the list.
+ */
+static int is_list_member(struct profile_string_list *list, const char *str)
+{
+	char **cpp;
+
+	if (!list->list)
+		return 0;
+
+	for (cpp = list->list; *cpp; cpp++) {
+		if (!strcmp(*cpp, str))
+			return 1;
+	}
+	return 0;
+}	
+	
+/*
+ * This function frees a null-terminated list as returned by
+ * profile_get_values.
+ */
+void KRB5_CALLCONV profile_free_list(char **list)
+{
+    char	**cp;
+
+    if (list == 0)
+	    return;
+    
+    for (cp = list; *cp; cp++)
+	free(*cp);
+    free(list);
+}
+
+errcode_t KRB5_CALLCONV
+profile_get_values(profile_t profile, const char *const *names,
+		   char ***ret_values)
+{
+	errcode_t		retval;
+	void			*state;
+	char			*value;
+	struct profile_string_list values;
+
+	if ((retval = profile_node_iterator_create(profile, names,
+						   PROFILE_ITER_RELATIONS_ONLY,
+						   &state)))
+		return retval;
+
+	if ((retval = init_list(&values)))
+		return retval;
+
+	do {
+		if ((retval = profile_node_iterator(&state, 0, 0, &value)))
+			goto cleanup;
+		if (value)
+			add_to_list(&values, value);
+	} while (state);
+
+	if (values.num == 0) {
+		retval = PROF_NO_RELATION;
+		goto cleanup;
+	}
+
+	end_list(&values, ret_values);
+	return 0;
+	
+cleanup:
+	end_list(&values, 0);
+	return retval;
+}
+
+/*
+ * This function only gets the first value from the file; it is a
+ * helper function for profile_get_string, profile_get_integer, etc.
+ */
+errcode_t profile_get_value(profile_t profile, const char **names,
+			    const char **ret_value)
+{
+	errcode_t		retval;
+	void			*state;
+	char			*value;
+
+	if ((retval = profile_node_iterator_create(profile, names,
+						   PROFILE_ITER_RELATIONS_ONLY,
+						   &state)))
+		return retval;
+
+	if ((retval = profile_node_iterator(&state, 0, 0, &value)))
+		goto cleanup;
+
+	if (value)
+		*ret_value = value;
+	else
+		retval = PROF_NO_RELATION;
+	
+cleanup:
+	profile_node_iterator_free(&state);
+	return retval;
+}
+
+errcode_t KRB5_CALLCONV
+profile_get_string(profile_t profile, const char *name, const char *subname,
+		   const char *subsubname, const char *def_val,
+		   char **ret_string)
+{
+	const char	*value;
+	errcode_t	retval;
+	const char	*names[4];
+
+	if (profile) {
+		names[0] = name;
+		names[1] = subname;
+		names[2] = subsubname;
+		names[3] = 0;
+		retval = profile_get_value(profile, names, &value);
+		if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION)
+			value = def_val;
+		else if (retval)
+			return retval;
+	} else
+		value = def_val;
+    
+	if (value) {
+		*ret_string = malloc(strlen(value)+1);
+		if (*ret_string == 0)
+			return ENOMEM;
+		strcpy(*ret_string, value);
+	} else
+		*ret_string = 0;
+	return 0;
+}
+
+errcode_t KRB5_CALLCONV
+profile_get_integer(profile_t profile, const char *name, const char *subname,
+		    const char *subsubname, int def_val, int *ret_int)
+{
+	const char	*value;
+	errcode_t	retval;
+	const char	*names[4];
+	char            *end_value;
+	long		ret_long;
+
+	*ret_int = def_val;
+	if (profile == 0)
+		return 0;
+
+	names[0] = name;
+	names[1] = subname;
+	names[2] = subsubname;
+	names[3] = 0;
+	retval = profile_get_value(profile, names, &value);
+	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
+		*ret_int = def_val;
+		return 0;
+	} else if (retval)
+		return retval;
+
+	if (value[0] == 0)
+	    /* Empty string is no good.  */
+	    return PROF_BAD_INTEGER;
+	errno = 0;
+	ret_long = strtol (value, &end_value, 10);
+
+	/* Overflow or underflow.  */
+	if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0)
+	    return PROF_BAD_INTEGER;
+	/* Value outside "int" range.  */
+	if ((long) (int) ret_long != ret_long)
+	    return PROF_BAD_INTEGER;
+	/* Garbage in string.  */
+	if (end_value != value + strlen (value))
+	    return PROF_BAD_INTEGER;
+	
+   
+	*ret_int = ret_long;
+	return 0;
+}
+
+static const char *const conf_yes[] = {
+    "y", "yes", "true", "t", "1", "on",
+    0,
+};
+
+static const char *const conf_no[] = {
+    "n", "no", "false", "nil", "0", "off",
+    0,
+};
+
+static errcode_t
+profile_parse_boolean(const char *s, int *ret_boolean)
+{
+    const char *const *p;
+    
+    if (ret_boolean == NULL)
+    	return PROF_EINVAL;
+
+    for(p=conf_yes; *p; p++) {
+		if (!strcasecmp(*p,s)) {
+			*ret_boolean = 1;
+	    	return 0;
+		}
+    }
+
+    for(p=conf_no; *p; p++) {
+		if (!strcasecmp(*p,s)) {
+			*ret_boolean = 0;
+			return 0;
+		}
+    }
+	
+	return PROF_BAD_BOOLEAN;
+}
+
+errcode_t KRB5_CALLCONV
+profile_get_boolean(profile_t profile, const char *name, const char *subname,
+		    const char *subsubname, int def_val, int *ret_boolean)
+{
+	const char	*value;
+	errcode_t	retval;
+	const char	*names[4];
+
+	if (profile == 0) {
+		*ret_boolean = def_val;
+		return 0;
+	}
+
+	names[0] = name;
+	names[1] = subname;
+	names[2] = subsubname;
+	names[3] = 0;
+	retval = profile_get_value(profile, names, &value);
+	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
+		*ret_boolean = def_val;
+		return 0;
+	} else if (retval)
+		return retval;
+   
+	return profile_parse_boolean (value, ret_boolean);
+}
+
+/*
+ * This function will return the list of the names of subections in the
+ * under the specified section name.
+ */
+errcode_t KRB5_CALLCONV
+profile_get_subsection_names(profile_t profile, const char **names,
+			     char ***ret_names)
+{
+	errcode_t		retval;
+	void			*state;
+	char			*name;
+	struct profile_string_list values;
+
+	if ((retval = profile_node_iterator_create(profile, names,
+		   PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY,
+		   &state)))
+		return retval;
+
+	if ((retval = init_list(&values)))
+		return retval;
+
+	do {
+		if ((retval = profile_node_iterator(&state, 0, &name, 0)))
+			goto cleanup;
+		if (name)
+			add_to_list(&values, name);
+	} while (state);
+
+	end_list(&values, ret_names);
+	return 0;
+	
+cleanup:
+	end_list(&values, 0);
+	return retval;
+}
+
+/*
+ * This function will return the list of the names of relations in the
+ * under the specified section name.
+ */
+errcode_t KRB5_CALLCONV
+profile_get_relation_names(profile_t profile, const char **names,
+			   char ***ret_names)
+{
+	errcode_t		retval;
+	void			*state;
+	char			*name;
+	struct profile_string_list values;
+
+	if ((retval = profile_node_iterator_create(profile, names,
+		   PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY,
+		   &state)))
+		return retval;
+
+	if ((retval = init_list(&values)))
+		return retval;
+
+	do {
+		if ((retval = profile_node_iterator(&state, 0, &name, 0)))
+			goto cleanup;
+		if (name && !is_list_member(&values, name))
+			add_to_list(&values, name);
+	} while (state);
+
+	end_list(&values, ret_names);
+	return 0;
+	
+cleanup:
+	end_list(&values, 0);
+	return retval;
+}
+
+errcode_t KRB5_CALLCONV
+profile_iterator_create(profile_t profile, const char *const *names, int flags,
+			void **ret_iter)
+{
+	return profile_node_iterator_create(profile, names, flags, ret_iter);
+}
+
+void KRB5_CALLCONV
+profile_iterator_free(void **iter_p)
+{
+	profile_node_iterator_free(iter_p);
+}
+
+errcode_t KRB5_CALLCONV
+profile_iterator(void **iter_p, char **ret_name, char **ret_value)
+{
+	char *name, *value;
+	errcode_t	retval;
+	
+	retval = profile_node_iterator(iter_p, 0, &name, &value);
+	if (retval)
+		return retval;
+
+	if (ret_name) {
+		if (name) {
+			*ret_name = malloc(strlen(name)+1);
+			if (!*ret_name)
+				return ENOMEM;
+			strcpy(*ret_name, name);
+		} else
+			*ret_name = 0;
+	}
+	if (ret_value) {
+		if (value) {
+			*ret_value = malloc(strlen(value)+1);
+			if (!*ret_value) {
+				if (ret_name) {
+					free(*ret_name);
+					*ret_name = 0;
+				}
+				return ENOMEM;
+			}
+			strcpy(*ret_value, value);
+		} else
+			*ret_value = 0;
+	}
+	return 0;
+}
+
+void KRB5_CALLCONV
+profile_release_string(char *str)
+{
+	free(str);
+}
diff --git a/mechglue/src/util/profile/prof_init.c b/mechglue/src/util/profile/prof_init.c
new file mode 100644
index 000000000..9aafb3c63
--- /dev/null
+++ b/mechglue/src/util/profile/prof_init.c
@@ -0,0 +1,372 @@
+/*
+ * prof_init.c --- routines that manipulate the user-visible profile_t
+ * 	object.
+ */
+
+#include "prof_int.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+
+/* Find a 4-byte integer type */
+#if	(SIZEOF_SHORT == 4)
+typedef short	prof_int32;
+#elif	(SIZEOF_INT == 4)
+typedef int	prof_int32;
+#elif	(SIZEOF_LONG == 4)
+typedef long	prof_int32;
+#else	/* SIZEOF_LONG == 4 */
+error(do not have a 4-byte integer type)
+#endif	/* SIZEOF_LONG == 4 */
+
+errcode_t KRB5_CALLCONV
+profile_init(const_profile_filespec_t *files, profile_t *ret_profile)
+{
+	const_profile_filespec_t *fs;
+	profile_t profile;
+	prf_file_t  new_file, last = 0;
+	errcode_t retval = 0;
+
+	profile = malloc(sizeof(struct _profile_t));
+	if (!profile)
+		return ENOMEM;
+	memset(profile, 0, sizeof(struct _profile_t));
+	profile->magic = PROF_MAGIC_PROFILE;
+
+        /* if the filenames list is not specified return an empty profile */
+        if ( files ) {
+	    for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) {
+		retval = profile_open_file(*fs, &new_file);
+		/* if this file is missing, skip to the next */
+		if (retval == ENOENT || retval == EACCES) {
+			continue;
+		}
+		if (retval) {
+			profile_release(profile);
+			return retval;
+		}
+		if (last)
+			last->next = new_file;
+		else
+			profile->first_file = new_file;
+		last = new_file;
+	    }
+	    /*
+	     * If last is still null after the loop, then all the files were
+	     * missing, so return the appropriate error.
+	     */
+	    if (!last) {
+		profile_release(profile);
+		return ENOENT;
+	    }
+	}
+
+        *ret_profile = profile;
+        return 0;
+}
+
+errcode_t KRB5_CALLCONV
+profile_init_path(const_profile_filespec_list_t filepath,
+		  profile_t *ret_profile)
+{
+	int n_entries, i;
+	unsigned int ent_len;
+	const char *s, *t;
+	profile_filespec_t *filenames;
+	errcode_t retval;
+
+	/* count the distinct filename components */
+	for(s = filepath, n_entries = 1; *s; s++) {
+		if (*s == ':')
+			n_entries++;
+	}
+	
+	/* the array is NULL terminated */
+	filenames = (profile_filespec_t*) malloc((n_entries+1) * sizeof(char*));
+	if (filenames == 0)
+		return ENOMEM;
+
+	/* measure, copy, and skip each one */
+	for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) {
+		ent_len = t-s;
+		filenames[i] = (char*) malloc(ent_len + 1);
+		if (filenames[i] == 0) {
+			/* if malloc fails, free the ones that worked */
+			while(--i >= 0) free(filenames[i]);
+                        free(filenames);
+			return ENOMEM;
+		}
+		strncpy(filenames[i], s, ent_len);
+		filenames[i][ent_len] = 0;
+		if (*t == 0) {
+			i++;
+			break;
+		}
+	}
+	/* cap the array */
+	filenames[i] = 0;
+
+	retval = profile_init((const_profile_filespec_t *) filenames, 
+			      ret_profile);
+
+	/* count back down and free the entries */
+	while(--i >= 0) free(filenames[i]);
+	free(filenames);
+
+	return retval;
+}
+
+errcode_t KRB5_CALLCONV
+profile_is_writable(profile_t profile, int *writable)
+{
+    if (!profile || profile->magic != PROF_MAGIC_PROFILE)
+        return PROF_MAGIC_PROFILE;
+    
+    if (!writable) 
+        return EINVAL;
+    
+    if (profile->first_file)
+        *writable = (profile->first_file->data->flags & PROFILE_FILE_RW);
+    
+    return 0;
+}
+
+errcode_t KRB5_CALLCONV
+profile_is_modified(profile_t profile, int *modified)
+{
+    if (!profile || profile->magic != PROF_MAGIC_PROFILE)
+        return PROF_MAGIC_PROFILE;
+    
+    if (!modified) 
+        return EINVAL;
+    
+    if (profile->first_file)
+        *modified = (profile->first_file->data->flags & PROFILE_FILE_DIRTY);
+    
+    return 0;
+}
+
+errcode_t KRB5_CALLCONV
+profile_flush(profile_t profile)
+{
+	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
+		return PROF_MAGIC_PROFILE;
+
+	if (profile->first_file)
+		return profile_flush_file(profile->first_file);
+
+	return 0;
+}
+
+errcode_t KRB5_CALLCONV
+profile_flush_to_file(profile_t profile, const_profile_filespec_t outfile)
+{
+	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
+		return PROF_MAGIC_PROFILE;
+
+	if (profile->first_file)
+		return profile_flush_file_to_file(profile->first_file,
+						  outfile);
+
+	return 0;
+}
+
+errcode_t KRB5_CALLCONV
+profile_flush_to_buffer(profile_t profile, char **buf)
+{
+    return profile_flush_file_data_to_buffer(profile->first_file->data, buf);
+}
+
+void KRB5_CALLCONV
+profile_free_buffer(profile_t profile, char *buf)
+{
+    free(buf);
+}
+
+void KRB5_CALLCONV
+profile_abandon(profile_t profile)
+{
+	prf_file_t	p, next;
+
+	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
+		return;
+
+	for (p = profile->first_file; p; p = next) {
+		next = p->next;
+		profile_free_file(p);
+	}
+	profile->magic = 0;
+	free(profile);
+}
+
+void KRB5_CALLCONV
+profile_release(profile_t profile)
+{
+	prf_file_t	p, next;
+
+	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
+		return;
+
+	for (p = profile->first_file; p; p = next) {
+		next = p->next;
+		profile_close_file(p);
+	}
+	profile->magic = 0;
+	free(profile);
+}
+
+/*
+ * Here begins the profile serialization functions.
+ */
+errcode_t profile_ser_size(const char *unused, profile_t profile,
+			   size_t *sizep)
+{
+    size_t	required;
+    prf_file_t	pfp;
+
+    required = 3*sizeof(prof_int32);
+    for (pfp = profile->first_file; pfp; pfp = pfp->next) {
+	required += sizeof(prof_int32);
+	required += strlen(pfp->data->filespec);
+    }
+    *sizep += required;
+    return 0;
+}
+
+static void pack_int32(prof_int32 oval, unsigned char **bufpp, size_t *remainp)
+{
+    (*bufpp)[0] = (unsigned char) ((oval >> 24) & 0xff);
+    (*bufpp)[1] = (unsigned char) ((oval >> 16) & 0xff);
+    (*bufpp)[2] = (unsigned char) ((oval >> 8) & 0xff);
+    (*bufpp)[3] = (unsigned char) (oval & 0xff);
+    *bufpp += sizeof(prof_int32);
+    *remainp -= sizeof(prof_int32);
+}
+
+errcode_t profile_ser_externalize(const char *unused, profile_t profile,
+				  unsigned char **bufpp, size_t *remainp)
+{
+    errcode_t		retval;
+    size_t		required;
+    unsigned char	*bp;
+    size_t		remain;
+    prf_file_t		pfp;
+    prof_int32		fcount, slen;
+
+    required = 0;
+    bp = *bufpp;
+    remain = *remainp;
+    retval = EINVAL;
+    if (profile) {
+	retval = ENOMEM;
+	(void) profile_ser_size(unused, profile, &required);
+	if (required <= remain) {
+	    fcount = 0;
+	    for (pfp = profile->first_file; pfp; pfp = pfp->next)
+		fcount++;
+	    pack_int32(PROF_MAGIC_PROFILE, &bp, &remain);
+	    pack_int32(fcount, &bp, &remain);
+	    for (pfp = profile->first_file; pfp; pfp = pfp->next) {
+		slen = (prof_int32) strlen(pfp->data->filespec);
+		pack_int32(slen, &bp, &remain);
+		if (slen) {
+		    memcpy(bp, pfp->data->filespec, (size_t) slen);
+		    bp += slen;
+		    remain -= (size_t) slen;
+		}
+	    }
+	    pack_int32(PROF_MAGIC_PROFILE, &bp, &remain);
+	    retval = 0;
+	    *bufpp = bp;
+	    *remainp = remain;
+	}
+    }
+    return(retval);
+}
+
+static int unpack_int32(prof_int32 *intp, unsigned char **bufpp,
+			size_t *remainp)
+{
+    if (*remainp >= sizeof(prof_int32)) {
+	*intp = (((prof_int32) (*bufpp)[0] << 24) |
+		 ((prof_int32) (*bufpp)[1] << 16) |
+		 ((prof_int32) (*bufpp)[2] << 8) |
+		 ((prof_int32) (*bufpp)[3]));
+	*bufpp += sizeof(prof_int32);
+	*remainp -= sizeof(prof_int32);
+	return 0;
+    }
+    else
+	return 1;
+}
+
+errcode_t profile_ser_internalize(const char *unused, profile_t *profilep,
+				  unsigned char **bufpp, size_t *remainp)
+{
+	errcode_t		retval;
+	unsigned char	*bp;
+	size_t		remain;
+	int			i;
+	prof_int32		fcount, tmp;
+	profile_filespec_t		*flist = 0;
+
+	bp = *bufpp;
+	remain = *remainp;
+
+	if (remain >= 12)
+		(void) unpack_int32(&tmp, &bp, &remain);
+	else
+		tmp = 0;
+	
+	if (tmp != PROF_MAGIC_PROFILE) {
+		retval = EINVAL;
+		goto cleanup;
+	}
+	
+	(void) unpack_int32(&fcount, &bp, &remain);
+	retval = ENOMEM;
+
+	flist = (profile_filespec_t *) malloc(sizeof(profile_filespec_t) * (fcount + 1));
+	if (!flist)
+		goto cleanup;
+	
+	memset(flist, 0, sizeof(char *) * (fcount+1));
+	for (i=0; i<fcount; i++) {
+		if (!unpack_int32(&tmp, &bp, &remain)) {
+			flist[i] = (char *) malloc((size_t) (tmp+1));
+			if (!flist[i])
+				goto cleanup;
+			memcpy(flist[i], bp, (size_t) tmp);
+			flist[i][tmp] = '\0';
+			bp += tmp;
+			remain -= (size_t) tmp;
+		}
+	}
+
+	if (unpack_int32(&tmp, &bp, &remain) ||
+	    (tmp != PROF_MAGIC_PROFILE)) {
+		retval = EINVAL;
+		goto cleanup;
+	}
+
+	if ((retval = profile_init((const_profile_filespec_t *) flist, 
+				   profilep)))
+		goto cleanup;
+	
+	*bufpp = bp;
+	*remainp = remain;
+    
+cleanup:
+	if (flist) {
+		for (i=0; i<fcount; i++) {
+			if (flist[i])
+				free(flist[i]);
+		}
+		free(flist);
+	}
+	return(retval);
+}
diff --git a/mechglue/src/util/profile/prof_int.h b/mechglue/src/util/profile/prof_int.h
new file mode 100644
index 000000000..3ff2b0f51
--- /dev/null
+++ b/mechglue/src/util/profile/prof_int.h
@@ -0,0 +1,248 @@
+/*
+ * prof-int.h
+ */
+
+#include <time.h>
+#include <stdio.h>
+
+#if defined(__MACH__) && defined(__APPLE__)
+#include <TargetConditionals.h>
+#define PROFILE_SUPPORTS_FOREIGN_NEWLINES
+#endif
+
+#include "k5-thread.h"
+#include "k5-platform.h"
+#include "com_err.h"
+#include "profile.h"
+
+#if defined(_WIN32)
+#define SIZEOF_INT      4
+#define SIZEOF_SHORT    2
+#define SIZEOF_LONG     4
+#endif
+
+typedef long prf_magic_t;
+
+/*
+ * This is the structure which stores the profile information for a
+ * particular configuration file.
+ *
+ * Locking strategy:
+ * - filespec, fslen are fixed after creation
+ * - refcount and next should only be tweaked with the global lock held
+ * - other fields can be tweaked after grabbing the in-struct lock
+ */
+struct _prf_data_t {
+	prf_magic_t	magic;
+	k5_mutex_t	lock;
+	struct profile_node *root;
+	time_t		last_stat;
+	time_t		timestamp; /* time tree was last updated from file */
+	unsigned long	frac_ts;   /* fractional part of timestamp, if any */
+	int		flags;	/* r/w, dirty */
+	int		upd_serial; /* incremented when data changes */
+	char		*comment;
+
+	size_t		fslen;
+
+	/* Some separation between fields controlled by different
+	   mutexes.  Theoretically, both could be accessed at the same
+	   time from different threads on different CPUs with separate
+	   caches.  Don't let the threads clobber each other's
+	   changes.  One mutex controlling the whole thing would be
+	   better, but sufficient separation might suffice.
+
+	   This is icky.  I just hope it's adequate.
+
+	   For next major release, fix this.  */
+	union { double d; void *p; UINT64_TYPE ll; k5_mutex_t m; } pad;
+
+	int		refcount; /* prf_file_t references */
+	struct _prf_data_t *next;
+	/* Was: "profile_filespec_t filespec".  Now: flexible char
+	   array ... except, we need to work in C89, so an array
+	   length must be specified.  */
+	const char	filespec[sizeof("/etc/krb5.conf")];
+};
+
+typedef struct _prf_data_t *prf_data_t;
+prf_data_t profile_make_prf_data(const char *);
+
+struct _prf_file_t {
+	prf_magic_t	magic;
+	struct _prf_data_t	*data;
+	struct _prf_file_t *next;
+};
+
+typedef struct _prf_file_t *prf_file_t;
+
+/*
+ * The profile flags
+ */
+#define PROFILE_FILE_RW		0x0001
+#define PROFILE_FILE_DIRTY	0x0002
+#define PROFILE_FILE_SHARED	0x0004
+
+/*
+ * This structure defines the high-level, user visible profile_t
+ * object, which is used as a handle by users who need to query some
+ * configuration file(s)
+ */
+struct _profile_t {
+	prf_magic_t	magic;
+	prf_file_t	first_file;
+};
+
+/*
+ * Used by the profile iterator in prof_get.c
+ */
+#define PROFILE_ITER_LIST_SECTION	0x0001
+#define PROFILE_ITER_SECTIONS_ONLY	0x0002
+#define PROFILE_ITER_RELATIONS_ONLY	0x0004
+
+#define PROFILE_ITER_FINAL_SEEN		0x0100
+
+/*
+ * Check if a filespec is last in a list (NULL on UNIX, invalid FSSpec on MacOS
+ */
+
+#define	PROFILE_LAST_FILESPEC(x) (((x) == NULL) || ((x)[0] == '\0'))
+
+/* profile_parse.c */
+
+errcode_t profile_parse_file
+	(FILE *f, struct profile_node **root);
+
+errcode_t profile_write_tree_file
+	(struct profile_node *root, FILE *dstfile);
+
+errcode_t profile_write_tree_to_buffer
+	(struct profile_node *root, char **buf);
+
+
+/* prof_tree.c */
+
+void profile_free_node
+	(struct profile_node *relation);
+
+errcode_t profile_create_node
+	(const char *name, const char *value,
+		   struct profile_node **ret_node);
+
+errcode_t profile_verify_node
+	(struct profile_node *node);
+
+errcode_t profile_add_node
+	(struct profile_node *section,
+		    const char *name, const char *value,
+		    struct profile_node **ret_node);
+
+errcode_t profile_make_node_final
+	(struct profile_node *node);
+	
+int profile_is_node_final
+	(struct profile_node *node);
+
+const char *profile_get_node_name
+	(struct profile_node *node);
+
+const char *profile_get_node_value
+	(struct profile_node *node);
+
+errcode_t profile_find_node
+	(struct profile_node *section,
+		    const char *name, const char *value,
+		    int section_flag, void **state,
+		    struct profile_node **node);
+
+errcode_t profile_find_node_relation
+	(struct profile_node *section,
+		    const char *name, void **state,
+		    char **ret_name, char **value);
+
+errcode_t profile_find_node_subsection
+	(struct profile_node *section,
+		    const char *name, void **state,
+		    char **ret_name, struct profile_node **subsection);
+		   
+errcode_t profile_get_node_parent
+	(struct profile_node *section,
+		   struct profile_node **parent);
+		   
+errcode_t profile_delete_node_relation
+	(struct profile_node *section, const char *name);
+
+errcode_t profile_find_node_name
+	(struct profile_node *section, void **state,
+		    char **ret_name);
+
+errcode_t profile_node_iterator_create
+	(profile_t profile, const char *const *names,
+		   int flags, void **ret_iter);
+
+void profile_node_iterator_free
+	(void	**iter_p);
+
+errcode_t profile_node_iterator
+	(void	**iter_p, struct profile_node **ret_node,
+		   char **ret_name, char **ret_value);
+
+errcode_t profile_remove_node
+	(struct profile_node *node);
+
+errcode_t profile_set_relation_value
+	(struct profile_node *node, const char *new_value);
+
+errcode_t profile_rename_node
+	(struct profile_node *node, const char *new_name);
+
+/* prof_file.c */
+
+errcode_t profile_open_file
+	(const_profile_filespec_t file, prf_file_t *ret_prof);
+
+#define profile_update_file(P) profile_update_file_data((P)->data)
+errcode_t profile_update_file_data
+	(prf_data_t profile);
+
+#define profile_flush_file(P) (((P) && (P)->magic == PROF_MAGIC_FILE) ? profile_flush_file_data((P)->data) : PROF_MAGIC_FILE)
+errcode_t profile_flush_file_data
+	(prf_data_t data);
+
+#define profile_flush_file_to_file(P,F) (((P) && (P)->magic == PROF_MAGIC_FILE) ? profile_flush_file_data_to_file((P)->data, (F)) : PROF_MAGIC_FILE)
+errcode_t profile_flush_file_data_to_file
+	(prf_data_t data, const char *outfile);
+
+errcode_t profile_flush_file_data_to_buffer
+	(prf_data_t data, char **bufp);
+
+void profile_free_file
+	(prf_file_t profile);
+
+errcode_t profile_close_file
+	(prf_file_t profile);
+
+void profile_dereference_data (prf_data_t);
+void profile_dereference_data_locked (prf_data_t);
+
+int profile_lock_global (void);
+int profile_unlock_global (void);
+
+/* prof_init.c -- included from profile.h */
+errcode_t profile_ser_size
+        (const char *, profile_t, size_t *);
+
+errcode_t profile_ser_externalize
+        (const char *, profile_t, unsigned char **, size_t *);
+
+errcode_t profile_ser_internalize
+        (const char *, profile_t *, unsigned char **, size_t *);
+
+/* prof_get.c */
+
+errcode_t profile_get_value
+	(profile_t profile, const char **names,
+		    const char	**ret_value);
+/* Others included from profile.h */
+	
+/* prof_set.c -- included from profile.h */
diff --git a/mechglue/src/util/profile/prof_parse.c b/mechglue/src/util/profile/prof_parse.c
new file mode 100644
index 000000000..d229bbb3a
--- /dev/null
+++ b/mechglue/src/util/profile/prof_parse.c
@@ -0,0 +1,492 @@
+#include "prof_int.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#include <ctype.h>
+
+#define SECTION_SEP_CHAR '/'
+
+#define STATE_INIT_COMMENT	1
+#define STATE_STD_LINE		2
+#define STATE_GET_OBRACE	3
+
+struct parse_state {
+	int	state;
+	int	group_level;
+	struct profile_node *root_section;
+	struct profile_node *current_section;
+};
+
+static char *skip_over_blanks(char *cp)
+{
+	while (*cp && isspace((int) (*cp)))
+		cp++;
+	return cp;
+}
+
+static void strip_line(char *line)
+{
+	char *p = line + strlen(line);
+	while (p > line && (p[-1] == '\n' || p[-1] == '\r'))
+	    *p-- = 0;
+}
+
+static void parse_quoted_string(char *str)
+{
+	char *to, *from;
+
+	to = from = str;
+
+	for (to = from = str; *from && *from != '"'; to++, from++) {
+		if (*from == '\\') {
+			from++;
+			switch (*from) {
+			case 'n':
+				*to = '\n';
+				break;
+			case 't':
+				*to = '\t';
+				break;
+			case 'b':
+				*to = '\b';
+				break;
+			default:
+				*to = *from;
+			}
+			continue;
+		}
+		*to = *from;
+	}
+	*to = '\0';
+}
+
+
+static errcode_t parse_init_state(struct parse_state *state)
+{
+	state->state = STATE_INIT_COMMENT;
+	state->group_level = 0;
+
+	return profile_create_node("(root)", 0, &state->root_section);
+}
+
+static errcode_t parse_std_line(char *line, struct parse_state *state)
+{
+	char	*cp, ch, *tag, *value;
+	char	*p;
+	errcode_t retval;
+	struct profile_node	*node;
+	int do_subsection = 0;
+	void *iter = 0;
+	
+	if (*line == 0)
+		return 0;
+	if (line[0] == ';' || line[0] == '#')
+		return 0;
+	strip_line(line);
+	cp = skip_over_blanks(line);
+	ch = *cp;
+	if (ch == 0)
+		return 0;
+	if (ch == '[') {
+		if (state->group_level > 0)
+			return PROF_SECTION_NOTOP;
+		cp++;
+		p = strchr(cp, ']');
+		if (p == NULL)
+			return PROF_SECTION_SYNTAX;
+		*p = '\0';
+		retval = profile_find_node_subsection(state->root_section,
+						 cp, &iter, 0,
+						 &state->current_section);
+		if (retval == PROF_NO_SECTION) {
+			retval = profile_add_node(state->root_section,
+						  cp, 0,
+						  &state->current_section);
+			if (retval)
+				return retval;
+		} else if (retval)
+			return retval;
+
+		/*
+		 * Finish off the rest of the line.
+		 */
+		cp = p+1;
+		if (*cp == '*') {
+			profile_make_node_final(state->current_section);
+			cp++;
+		}
+		/*
+		 * A space after ']' should not be fatal 
+		 */
+		cp = skip_over_blanks(cp);
+		if (*cp)
+			return PROF_SECTION_SYNTAX;
+		return 0;
+	}
+	if (ch == '}') {
+		if (state->group_level == 0)
+			return PROF_EXTRA_CBRACE;
+		if (*(cp+1) == '*')
+			profile_make_node_final(state->current_section);
+		retval = profile_get_node_parent(state->current_section,
+						 &state->current_section);
+		if (retval)
+			return retval;
+		state->group_level--;
+		return 0;
+	}
+	/*
+	 * Parse the relations
+	 */
+	tag = cp;
+	cp = strchr(cp, '=');
+	if (!cp)
+		return PROF_RELATION_SYNTAX;
+	if (cp == tag)
+	    return PROF_RELATION_SYNTAX;
+	*cp = '\0';
+	p = tag;
+	/* Look for whitespace on left-hand side.  */
+	while (p < cp && !isspace((int)*p))
+	    p++;
+	if (p < cp) {
+	    /* Found some sort of whitespace.  */
+	    *p++ = 0;
+	    /* If we have more non-whitespace, it's an error.  */
+	    while (p < cp) {
+		if (!isspace((int)*p))
+		    return PROF_RELATION_SYNTAX;
+		p++;
+	    }
+	}
+	cp = skip_over_blanks(cp+1);
+	value = cp;
+	if (value[0] == '"') {
+		value++;
+		parse_quoted_string(value);
+	} else if (value[0] == 0) {
+		do_subsection++;
+		state->state = STATE_GET_OBRACE;
+	} else if (value[0] == '{' && *(skip_over_blanks(value+1)) == 0)
+		do_subsection++;
+	else {
+		cp = value + strlen(value) - 1;
+		while ((cp > value) && isspace((int) (*cp)))
+			*cp-- = 0;
+	}
+	if (do_subsection) {
+		p = strchr(tag, '*');
+		if (p)
+			*p = '\0';
+		retval = profile_add_node(state->current_section,
+					  tag, 0, &state->current_section);
+		if (retval)
+			return retval;
+		if (p)
+			profile_make_node_final(state->current_section);
+		state->group_level++;
+		return 0;
+	}
+	p = strchr(tag, '*');
+	if (p)
+		*p = '\0';
+	profile_add_node(state->current_section, tag, value, &node);
+	if (p)
+		profile_make_node_final(node);
+	return 0;
+}
+
+static errcode_t parse_line(char *line, struct parse_state *state)
+{
+	char	*cp;
+	
+	switch (state->state) {
+	case STATE_INIT_COMMENT:
+		if (line[0] != '[')
+			return 0;
+		state->state = STATE_STD_LINE;
+	case STATE_STD_LINE:
+		return parse_std_line(line, state);
+	case STATE_GET_OBRACE:
+		cp = skip_over_blanks(line);
+		if (*cp != '{')
+			return PROF_MISSING_OBRACE;
+		state->state = STATE_STD_LINE;
+	}
+	return 0;
+}
+
+errcode_t profile_parse_file(FILE *f, struct profile_node **root)
+{
+#define BUF_SIZE	2048
+	char *bptr;
+	errcode_t retval;
+	struct parse_state state;
+
+	bptr = malloc (BUF_SIZE);
+	if (!bptr)
+		return ENOMEM;
+
+	retval = parse_init_state(&state);
+	if (retval) {
+		free (bptr);
+		return retval;
+	}
+	while (!feof(f)) {
+		if (fgets(bptr, BUF_SIZE, f) == NULL)
+			break;
+#ifndef PROFILE_SUPPORTS_FOREIGN_NEWLINES
+		retval = parse_line(bptr, &state);
+		if (retval) {
+			free (bptr);
+			return retval;
+		}
+#else
+		{
+		    char *p, *end;
+
+		    if (strlen(bptr) >= BUF_SIZE - 1) {
+			/* The string may have foreign newlines and
+			   gotten chopped off on a non-newline
+			   boundary.  Seek backwards to the last known
+			   newline.  */
+			long offset;
+			char *c = bptr + strlen (bptr);
+			for (offset = 0; offset > -BUF_SIZE; offset--) {
+			    if (*c == '\r' || *c == '\n') {
+				*c = '\0';
+				fseek (f, offset, SEEK_CUR);
+				break;
+			    }
+			    c--;
+			}
+		    }
+
+		    /* First change all newlines to \n */
+		    for (p = bptr; *p != '\0'; p++) {
+			if (*p == '\r')
+                            *p = '\n';
+		    }
+		    /* Then parse all lines */
+		    p = bptr;
+		    end = bptr + strlen (bptr);
+		    while (p < end) {
+			char* newline;
+			char* newp;
+
+			newline = strchr (p, '\n');
+			if (newline != NULL)
+			    *newline = '\0';
+
+			/* parse_line modifies contents of p */
+			newp = p + strlen (p) + 1;
+			retval = parse_line (p, &state);
+			if (retval) {
+			    free (bptr);
+			    return retval;
+			}
+
+			p = newp;
+		    }
+		}
+#endif
+	}
+	*root = state.root_section;
+
+	free (bptr);
+	return 0;
+}
+
+/*
+ * Return TRUE if the string begins or ends with whitespace
+ */
+static int need_double_quotes(char *str)
+{
+	if (!str || !*str)
+		return 0;
+	if (isspace((int) (*str)) ||isspace((int) (*(str + strlen(str) - 1))))
+		return 1;
+	if (strchr(str, '\n') || strchr(str, '\t') || strchr(str, '\b'))
+		return 1;
+	return 0;
+}
+
+/*
+ * Output a string with double quotes, doing appropriate backquoting
+ * of characters as necessary.
+ */
+static void output_quoted_string(char *str, void (*cb)(const char *,void *),
+				 void *data)
+{
+	char	ch;
+	char buf[2];
+
+	cb("\"", data);
+	if (!str) {
+		cb("\"", data);
+		return;
+	}
+	buf[1] = 0;
+	while ((ch = *str++)) {
+		switch (ch) {
+		case '\\':
+			cb("\\\\", data);
+			break;
+		case '\n':
+			cb("\\n", data);
+			break;
+		case '\t':
+			cb("\\t", data);
+			break;
+		case '\b':
+			cb("\\b", data);
+			break;
+		default:
+			/* This would be a lot faster if we scanned
+			   forward for the next "interesting"
+			   character.  */
+			buf[0] = ch;
+			cb(buf, data);
+			break;
+		}
+	}
+	cb("\"", data);
+}
+
+
+
+#if defined(_WIN32)
+#define EOL "\r\n"
+#endif
+
+#ifndef EOL
+#define EOL "\n"
+#endif
+
+/* Errors should be returned, not ignored!  */
+static void dump_profile(struct profile_node *root, int level,
+			 void (*cb)(const char *, void *), void *data)
+{
+	int i;
+	struct profile_node *p;
+	void *iter;
+	long retval;
+	char *name, *value;
+	
+	iter = 0;
+	do {
+		retval = profile_find_node_relation(root, 0, &iter,
+						    &name, &value);
+		if (retval)
+			break;
+		for (i=0; i < level; i++)
+			cb("\t", data);
+		if (need_double_quotes(value)) {
+			cb(name, data);
+			cb(" = ", data);
+			output_quoted_string(value, cb, data);
+			cb(EOL, data);
+		} else {
+			cb(name, data);
+			cb(" = ", data);
+			cb(value, data);
+			cb(EOL, data);
+		}
+	} while (iter != 0);
+
+	iter = 0;
+	do {
+		retval = profile_find_node_subsection(root, 0, &iter,
+						      &name, &p);
+		if (retval)
+			break;
+		if (level == 0)	{ /* [xxx] */
+			cb("[", data);
+			cb(name, data);
+			cb("]", data);
+			cb(profile_is_node_final(p) ? "*" : "", data);
+			cb(EOL, data);
+			dump_profile(p, level+1, cb, data);
+			cb(EOL, data);
+		} else { 	/* xxx = { ... } */
+			for (i=0; i < level; i++)
+				cb("\t", data);
+			cb(name, data);
+			cb(" = {", data);
+			cb(EOL, data);
+			dump_profile(p, level+1, cb, data);
+			for (i=0; i < level; i++)
+				cb("\t", data);
+			cb("}", data);
+			cb(profile_is_node_final(p) ? "*" : "", data);
+			cb(EOL, data);
+		}
+	} while (iter != 0);
+}
+
+static void dump_profile_to_file_cb(const char *str, void *data)
+{
+	fputs(str, data);
+}
+
+errcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile)
+{
+	dump_profile(root, 0, dump_profile_to_file_cb, dstfile);
+	return 0;
+}
+
+struct prof_buf {
+	char *base;
+	size_t cur, max;
+	int err;
+};
+
+static void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len)
+{
+	if (b->err)
+		return;
+	if (b->max - b->cur < len) {
+		size_t newsize;
+		char *newptr;
+
+		newsize = b->max + (b->max >> 1) + len + 1024;
+		newptr = realloc(b->base, newsize);
+		if (newptr == NULL) {
+			b->err = 1;
+			return;
+		}
+		b->base = newptr;
+		b->max = newsize;
+	}
+	memcpy(b->base + b->cur, d, len);
+	b->cur += len; 		/* ignore overflow */
+}
+
+static void dump_profile_to_buffer_cb(const char *str, void *data)
+{
+	add_data_to_buffer((struct prof_buf *)data, str, strlen(str));
+}
+
+errcode_t profile_write_tree_to_buffer(struct profile_node *root,
+				       char **buf)
+{
+	struct prof_buf prof_buf = { 0, 0, 0, 0 };
+
+	dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf);
+	if (prof_buf.err) {
+		*buf = NULL;
+		return ENOMEM;
+	}
+	add_data_to_buffer(&prof_buf, "", 1); /* append nul */
+	if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) {
+		char *newptr = realloc(prof_buf.base, prof_buf.cur);
+		if (newptr)
+			prof_buf.base = newptr;
+	}
+	*buf = prof_buf.base;
+	return 0;
+}
diff --git a/mechglue/src/util/profile/prof_set.c b/mechglue/src/util/profile/prof_set.c
new file mode 100644
index 000000000..85f228630
--- /dev/null
+++ b/mechglue/src/util/profile/prof_set.c
@@ -0,0 +1,286 @@
+/*
+ * prof_set.c --- routines that expose the public interfaces for
+ * 	inserting, updating and deleting items from the profile.
+ *
+ * WARNING: These routines only look at the first file opened in the
+ * profile.  It's not clear how to handle multiple files, actually.
+ * In the future it may be necessary to modify this public interface,
+ * or possibly add higher level functions to support this correctly.
+ *
+ * WARNING: We're not yet doing locking yet, either.  
+ *
+ */
+
+#include "prof_int.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+
+static errcode_t rw_setup(profile_t profile)
+{
+   	prf_file_t	file;
+	errcode_t	retval = 0;
+
+	if (!profile)
+		return PROF_NO_PROFILE;
+
+	if (profile->magic != PROF_MAGIC_PROFILE)
+		return PROF_MAGIC_PROFILE;
+
+	file = profile->first_file;
+
+	retval = profile_lock_global();
+	if (retval)
+	    return retval;
+
+	/* Don't update the file if we've already made modifications */
+	if (file->data->flags & PROFILE_FILE_DIRTY) {
+	    profile_unlock_global();
+	    return 0;
+	}
+
+	if ((file->data->flags & PROFILE_FILE_SHARED) != 0) {
+	    prf_data_t new_data;
+	    new_data = profile_make_prf_data(file->data->filespec);
+	    if (new_data == NULL) {
+		retval = ENOMEM;
+	    } else {
+		retval = k5_mutex_init(&new_data->lock);
+		if (retval == 0) {
+		    new_data->root = NULL;
+		    new_data->flags = file->data->flags & ~PROFILE_FILE_SHARED;
+		    new_data->timestamp = 0;
+		    new_data->upd_serial = file->data->upd_serial;
+		}
+	    }
+
+	    if (retval != 0) {
+		profile_unlock_global();
+		free(new_data);
+		return retval;
+	    }
+	    profile_dereference_data_locked(file->data);
+	    file->data = new_data;
+	}
+
+	profile_unlock_global();
+	retval = profile_update_file(file);
+
+	return retval;
+}
+
+
+/* 
+ * Delete or update a particular child node 
+ * 
+ * ADL - 2/23/99, rewritten TYT 2/25/99
+ */
+errcode_t KRB5_CALLCONV
+profile_update_relation(profile_t profile, const char **names,
+			const char *old_value, const char *new_value)
+{	
+	errcode_t	retval;
+	struct profile_node *section, *node;
+	void		*state;
+	const char	**cpp;
+
+	retval = rw_setup(profile);
+	if (retval)
+		return retval;
+	
+	if (names == 0 || names[0] == 0 || names[1] == 0)
+		return PROF_BAD_NAMESET;
+
+	if (!old_value || !*old_value)
+		return PROF_EINVAL;
+
+	retval = k5_mutex_lock(&profile->first_file->data->lock);
+	if (retval)
+	    return retval;
+	section = profile->first_file->data->root;
+	for (cpp = names; cpp[1]; cpp++) {
+		state = 0;
+		retval = profile_find_node(section, *cpp, 0, 1,
+					   &state, §ion);
+		if (retval) {
+		    k5_mutex_unlock(&profile->first_file->data->lock);
+		    return retval;
+		}
+	}
+
+	state = 0;
+	retval = profile_find_node(section, *cpp, old_value, 0, &state, &node);
+	if (retval == 0) {
+	    if (new_value)
+		retval = profile_set_relation_value(node, new_value);
+	    else
+		retval = profile_remove_node(node);
+	}
+	if (retval == 0)
+	    profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
+	k5_mutex_unlock(&profile->first_file->data->lock);
+	
+	return retval;
+}
+
+/* 
+ * Clear a particular all of the relations with a specific name.
+ * 
+ * TYT - 2/25/99
+ */
+errcode_t KRB5_CALLCONV
+profile_clear_relation(profile_t profile, const char **names)
+{	
+	errcode_t	retval;
+	struct profile_node *section, *node;
+	void		*state;
+	const char	**cpp;
+
+	retval = rw_setup(profile);
+	if (retval)
+		return retval;
+	
+	if (names == 0 || names[0] == 0 || names[1] == 0)
+		return PROF_BAD_NAMESET;
+
+	section = profile->first_file->data->root;
+	for (cpp = names; cpp[1]; cpp++) {
+		state = 0;
+		retval = profile_find_node(section, *cpp, 0, 1,
+					   &state, §ion);
+		if (retval)
+			return retval;
+	}
+
+	state = 0;
+	do {
+		retval = profile_find_node(section, *cpp, 0, 0, &state, &node);
+		if (retval)
+			return retval;
+		retval = profile_remove_node(node);
+		if (retval)
+			return retval;
+	} while (state);
+
+	profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
+	
+	return 0;
+}
+
+/* 
+ * Rename a particular section; if the new_section name is NULL,
+ * delete it.
+ * 
+ * ADL - 2/23/99, rewritten TYT 2/25/99
+ */
+errcode_t KRB5_CALLCONV
+profile_rename_section(profile_t profile, const char **names,
+		       const char *new_name)
+{	
+	errcode_t	retval;
+	struct profile_node *section, *node;
+	void		*state;
+	const char	**cpp;
+	
+	retval = rw_setup(profile);
+	if (retval)
+		return retval;
+	
+	if (names == 0 || names[0] == 0 || names[1] == 0)
+		return PROF_BAD_NAMESET;
+
+	retval = k5_mutex_lock(&profile->first_file->data->lock);
+	if (retval)
+	    return retval;
+	section = profile->first_file->data->root;
+	for (cpp = names; cpp[1]; cpp++) {
+		state = 0;
+		retval = profile_find_node(section, *cpp, 0, 1,
+					   &state, §ion);
+		if (retval) {
+		    k5_mutex_unlock(&profile->first_file->data->lock);
+		    return retval;
+		}
+	}
+
+	state = 0;
+	retval = profile_find_node(section, *cpp, 0, 1, &state, &node);
+	if (retval == 0) {
+	    if (new_name)
+		retval = profile_rename_node(node, new_name);
+	    else
+		retval = profile_remove_node(node);
+	}
+	if (retval == 0)
+	    profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
+	k5_mutex_unlock(&profile->first_file->data->lock);
+	return retval;
+}
+
+/*
+ * Insert a new relation.  If the new_value argument is NULL, then
+ * create a new section instead.
+ *
+ * Note: if the intermediate sections do not exist, this function will
+ * automatically create them.
+ *
+ * ADL - 2/23/99, rewritten TYT 2/25/99
+ */
+errcode_t KRB5_CALLCONV
+profile_add_relation(profile_t profile, const char **names,
+		     const char *new_value)
+{
+	errcode_t	retval;
+    	struct profile_node *section;
+	const char 	**cpp;
+	void		*state;
+
+	retval = rw_setup(profile);
+	if (retval)
+		return retval;
+	
+	if (names == 0 || names[0] == 0 || names[1] == 0)
+		return PROF_BAD_NAMESET;
+
+	retval = k5_mutex_lock(&profile->first_file->data->lock);
+	if (retval)
+	    return retval;
+	section = profile->first_file->data->root;
+	for (cpp = names; cpp[1]; cpp++) {
+		state = 0;
+		retval = profile_find_node(section, *cpp, 0, 1,
+					   &state, §ion);
+		if (retval == PROF_NO_SECTION)
+			retval = profile_add_node(section, *cpp, 0, §ion);
+		if (retval) {
+		    k5_mutex_unlock(&profile->first_file->data->lock);
+		    return retval;
+		}
+	}
+
+	if (new_value == 0) {
+		retval = profile_find_node(section, *cpp, 0, 1, &state, 0);
+		if (retval == 0) {
+		    k5_mutex_unlock(&profile->first_file->data->lock);
+		    return PROF_EXISTS;
+		} else if (retval != PROF_NO_SECTION) {
+		    k5_mutex_unlock(&profile->first_file->data->lock);
+		    return retval;
+		}
+	}
+
+	retval = profile_add_node(section, *cpp, new_value, 0);
+	if (retval) {
+	    k5_mutex_unlock(&profile->first_file->data->lock);
+	    return retval;
+	}
+
+	profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
+	k5_mutex_unlock(&profile->first_file->data->lock);
+	return 0;
+}
+
diff --git a/mechglue/src/util/profile/prof_test1 b/mechglue/src/util/profile/prof_test1
new file mode 100644
index 000000000..bd4901272
--- /dev/null
+++ b/mechglue/src/util/profile/prof_test1
@@ -0,0 +1,154 @@
+# To do: Should run all tests and return a useful exit status, not
+# punt on the first failure.
+
+set wd [pwd]
+set verbose 0
+
+proc test1 {} {
+    global wd verbose
+    set p [profile_init_path $wd/test2.ini]
+    set sect {{test section 1} child_section child}
+    set iter [profile_iterator_create $p $sect 0]
+    set done 0
+    if $verbose { puts "Iterating over {$sect} entries:" }
+    while {!$done} {
+	set pair [profile_iterator $iter]
+	if [string match $pair {{} {}}] {
+	    set done 1
+	} else {
+	    set val [lindex $pair 1]
+	    if $verbose { puts -nonewline "\t$val" }
+	}
+    }
+    if $verbose { puts "" }
+    #profile_iterator_free $iter
+
+    set iter [profile_iterator_create $p $sect 0]
+    set done 0
+    if $verbose { puts "Iterating again, deleting:" }
+    while {!$done} {
+	set pair [profile_iterator $iter]
+	if [string match $pair {{} {}}] {
+	    set done 1
+	} else {
+	    set val [lindex $pair 1]
+	    if $verbose { puts -nonewline "\t$val" }
+	    profile_update_relation $p $sect $val
+	}
+    }
+    if $verbose { puts "" }
+    #profile_iterator_free $iter
+    catch {file delete $wd/test3.ini}
+    profile_flush_to_file $p $wd/test3.ini
+    profile_release $p
+
+    if $verbose { puts "Reloading new profile" }
+    set p [profile_init_path $wd/test3.ini]
+    set iter [profile_iterator_create $p $sect 0]
+    set done 0
+    if $verbose { puts "Iterating again:" }
+    set found_some 0
+    while {!$done} {
+	set pair [profile_iterator $iter]
+	if [string match $pair {{} {}}] {
+	    set done 1
+	} else {
+	    set found_some 1
+	    set val [lindex $pair 1]
+	    if $verbose { puts -nonewline "\t$val" }
+	}
+    }
+    #profile_iterator_free $iter
+    profile_abandon $p
+
+    if {$found_some} {
+	if $verbose { puts "" }
+	puts stderr "Error: Deleting in iterator didn't get them all."
+	exit 1
+    } else {
+	puts "OK: test1: Deleting in iteration got rid of all entries."
+    }
+}
+
+proc test2 {} {
+    global wd verbose
+
+    # lxs said: create A, read A, flush A, read A, create B, read B, crash
+    # (where "create" refers to the object, not the file)
+
+    if $verbose { puts "Running test2" }
+    set c [profile_init_path $wd/test2.ini]
+    # create A
+    set a [profile_init_path $wd/test2.ini]
+    if $verbose { puts "Opened profile $wd/test2.ini" }
+    # read A
+    set x [profile_get_values $a {{test section 1} foo}]
+    if $verbose { puts "Read $x from profile" }
+    if $verbose { puts "updating" }
+    exec sleep 2
+    profile_update_relation $a {{test section 1} foo} [lindex $x 0] [lindex $x 0]
+    set x [profile_get_values $a {{test section 1} foo}]
+    if $verbose { puts "Read $x from profile" }
+    # flush A
+    profile_flush $a
+    # read A again
+    set x [profile_get_values $a {{test section 1} foo}]
+    if $verbose { puts "Read $x from profile" }
+    profile_release $a
+    # create B
+    set b [profile_init_path $wd/test2.ini]
+    if $verbose { puts "Opened profile again" }
+    # read B
+    set x [profile_get_values $b {{test section 1} foo}]
+    if $verbose { puts "Read $x from profile" }
+    # read B
+    set x [profile_get_values $b {{test section 1} foo}]
+    if $verbose { puts "Read $x from profile" }
+    # If we got this far, now what?
+    profile_release $b
+    profile_release $c
+    puts "OK: test2: Modifications don't corrupt existing open handles"
+}
+
+proc test3 {} {
+    # lxs said: Start with a relation in the file.  Open, delete
+    # relation, add relation back, list relations.  In 1.4 release
+    # code, got two back.
+
+    global wd verbose
+
+    exec cp $wd/test2.ini $wd/test1c.ini
+    set p [profile_init_path $wd/test1c.ini]
+    set sect {{test section 1} quux}
+
+    set v [profile_get_values $p $sect]
+    set v1 [lindex $v 0]
+    if $verbose { puts "Old values: $v" }
+    profile_clear_relation $p $sect
+    if $verbose { puts "Cleared." }
+    # profile_get_values raises an exception if no data is there; so if
+    # it succeeds, the test fails.
+    catch {
+	set v [profile_get_values $p $sect]
+	if $verbose { puts "New values: $v" }
+	puts stderr "Error: test3: Clearing relation didn't get rid of all values."
+	exit 1
+    }
+    if $verbose { puts "Adding back $v1 ..." }
+    profile_add_relation $p $sect $v1
+    set v [profile_get_values $p $sect]
+    if $verbose { puts "New values: $v" }
+    if [llength $v]!=1 {
+	puts stderr "Error: test3: Adding one entry after clearing relation leaves [llength $v] entries."
+	exit 1
+    }
+    profile_abandon $p
+    file delete $wd/test1c.ini
+    puts "OK: test3: Clearing relation and adding one entry yields correct count."
+}
+
+test1
+test2
+test3
+
+exit 0
diff --git a/mechglue/src/util/profile/prof_tree.c b/mechglue/src/util/profile/prof_tree.c
new file mode 100644
index 000000000..b014e245d
--- /dev/null
+++ b/mechglue/src/util/profile/prof_tree.c
@@ -0,0 +1,714 @@
+/*
+ * prof_tree.c --- these routines maintain the parse tree of the
+ * 	config file.
+ * 
+ * All of the details of how the tree is stored is abstracted away in
+ * this file; all of the other profile routines build, access, and
+ * modify the tree via the accessor functions found in this file.
+ *
+ * Each node may represent either a relation or a section header.
+ * 
+ * A section header must have its value field set to 0, and may a one
+ * or more child nodes, pointed to by first_child.
+ * 
+ * A relation has as its value a pointer to allocated memory
+ * containing a string.  Its first_child pointer must be null.
+ *
+ */
+
+
+#include "prof_int.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#include <ctype.h>
+
+struct profile_node {
+	errcode_t	magic;
+	char *name;
+	char *value;
+	int group_level;
+	int final:1;		/* Indicate don't search next file */
+	int deleted:1;
+	struct profile_node *first_child;
+	struct profile_node *parent;
+	struct profile_node *next, *prev;
+};
+
+#define CHECK_MAGIC(node) \
+	  if ((node)->magic != PROF_MAGIC_NODE) \
+		  return PROF_MAGIC_NODE;
+
+/*
+ * Free a node, and any children
+ */
+void profile_free_node(struct profile_node *node)
+{
+	struct profile_node *child, *next;
+
+	if (node->magic != PROF_MAGIC_NODE)
+		return;
+	
+	if (node->name)
+		free(node->name);
+	if (node->value)
+		free(node->value);
+
+	for (child=node->first_child; child; child = next) {
+		next = child->next;
+		profile_free_node(child);
+	}
+	node->magic = 0;
+	
+	free(node);
+}
+
+#ifndef HAVE_STRDUP
+#undef strdup
+#define strdup MYstrdup
+static char *MYstrdup (const char *s)
+{
+    size_t sz = strlen(s) + 1;
+    char *p = malloc(sz);
+    if (p != 0)
+	memcpy(p, s, sz);
+    return p;
+}
+#endif
+
+/*
+ * Create a node
+ */
+errcode_t profile_create_node(const char *name, const char *value,
+			      struct profile_node **ret_node)
+{
+	struct profile_node *new;
+
+	new = malloc(sizeof(struct profile_node));
+	if (!new)
+		return ENOMEM;
+	memset(new, 0, sizeof(struct profile_node));
+	new->name = strdup(name);
+	if (new->name == 0) {
+	    profile_free_node(new);
+	    return ENOMEM;
+	}
+	if (value) {
+		new->value = strdup(value);
+		if (new->value == 0) {
+		    profile_free_node(new);
+		    return ENOMEM;
+		}
+	}
+	new->magic = PROF_MAGIC_NODE;
+
+	*ret_node = new;
+	return 0;
+}
+
+/*
+ * This function verifies that all of the representation invarients of
+ * the profile are true.  If not, we have a programming bug somewhere,
+ * probably in this file.
+ */
+errcode_t profile_verify_node(struct profile_node *node)
+{
+	struct profile_node *p, *last;
+	errcode_t	retval;
+
+	CHECK_MAGIC(node);
+
+	if (node->value && node->first_child)
+		return PROF_SECTION_WITH_VALUE;
+
+	last = 0;
+	for (p = node->first_child; p; last = p, p = p->next) {
+		if (p->prev != last)
+			return PROF_BAD_LINK_LIST;
+		if (last && (last->next != p))
+			return PROF_BAD_LINK_LIST;
+		if (node->group_level+1 != p->group_level)
+			return PROF_BAD_GROUP_LVL;
+		if (p->parent != node)
+			return PROF_BAD_PARENT_PTR;
+		retval = profile_verify_node(p);
+		if (retval)
+			return retval;
+	}
+	return 0;
+}
+
+/*
+ * Add a node to a particular section
+ */
+errcode_t profile_add_node(struct profile_node *section, const char *name,
+			   const char *value, struct profile_node **ret_node)
+{
+	errcode_t retval;
+	struct profile_node *p, *last, *new;
+
+	CHECK_MAGIC(section);
+
+	if (section->value)
+		return PROF_ADD_NOT_SECTION;
+
+	/*
+	 * Find the place to insert the new node.  We look for the
+	 * place *after* the last match of the node name, since 
+	 * order matters.
+	 */
+	for (p=section->first_child, last = 0; p; last = p, p = p->next) {
+		int cmp;
+		cmp = strcmp(p->name, name);
+		if (cmp > 0)
+			break;
+	}
+	retval = profile_create_node(name, value, &new);
+	if (retval)
+		return retval;
+	new->group_level = section->group_level+1;
+	new->deleted = 0;
+	new->parent = section;
+	new->prev = last;
+	new->next = p;
+	if (p)
+		p->prev = new;
+	if (last)
+		last->next = new;
+	else
+		section->first_child = new;
+	if (ret_node)
+		*ret_node = new;
+	return 0;
+}
+
+/*
+ * Set the final flag on a particular node.
+ */
+errcode_t profile_make_node_final(struct profile_node *node)
+{
+	CHECK_MAGIC(node);
+
+	node->final = 1;
+	return 0;
+}
+
+/*
+ * Check the final flag on a node
+ */
+int profile_is_node_final(struct profile_node *node)
+{
+	return (node->final != 0);
+}
+
+/*
+ * Return the name of a node.  (Note: this is for internal functions
+ * only; if the name needs to be returned from an exported function,
+ * strdup it first!)
+ */
+const char *profile_get_node_name(struct profile_node *node)
+{
+	return node->name;
+}
+
+/*
+ * Return the value of a node.  (Note: this is for internal functions
+ * only; if the name needs to be returned from an exported function,
+ * strdup it first!)
+ */
+const char *profile_get_node_value(struct profile_node *node)
+{
+	return node->value;
+}
+
+/*
+ * Iterate through the section, returning the nodes which match
+ * the given name.  If name is NULL, then interate through all the
+ * nodes in the section.  If section_flag is non-zero, only return the
+ * section which matches the name; don't return relations.  If value
+ * is non-NULL, then only return relations which match the requested
+ * value.  (The value argument is ignored if section_flag is non-zero.)
+ * 
+ * The first time this routine is called, the state pointer must be
+ * null.  When this profile_find_node_relation() returns, if the state
+ * pointer is non-NULL, then this routine should be called again.
+ * (This won't happen if section_flag is non-zero, obviously.)
+ *
+ */
+errcode_t profile_find_node(struct profile_node *section, const char *name,
+			    const char *value, int section_flag, void **state,
+			    struct profile_node **node)
+{
+	struct profile_node *p;
+
+	CHECK_MAGIC(section);
+	p = *state;
+	if (p) {
+		CHECK_MAGIC(p);
+	} else
+		p = section->first_child;
+	
+	for (; p; p = p->next) {
+		if (name && (strcmp(p->name, name)))
+			continue;
+		if (section_flag) {
+			if (p->value)
+				continue;
+		} else {
+			if (!p->value)
+				continue;
+			if (value && (strcmp(p->value, value)))
+				continue;
+		}
+		if (p->deleted)
+		    continue;
+		/* A match! */
+		if (node)
+			*node = p;
+		break;
+	}
+	if (p == 0) {
+		*state = 0;
+		return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION;
+	}
+	/*
+	 * OK, we've found one match; now let's try to find another
+	 * one.  This way, if we return a non-zero state pointer,
+	 * there's guaranteed to be another match that's returned.
+	 */
+	for (p = p->next; p; p = p->next) {
+		if (name && (strcmp(p->name, name)))
+			continue;
+		if (section_flag) {
+			if (p->value)
+				continue;
+		} else {
+			if (!p->value)
+				continue;
+			if (value && (strcmp(p->value, value)))
+				continue;
+		}
+		/* A match! */
+		break;
+	}
+	*state = p;
+	return 0;
+}
+
+
+/*
+ * Iterate through the section, returning the relations which match
+ * the given name.  If name is NULL, then interate through all the
+ * relations in the section.  The first time this routine is called,
+ * the state pointer must be null.  When this profile_find_node_relation()
+ * returns, if the state pointer is non-NULL, then this routine should
+ * be called again.
+ *
+ * The returned character string in value points to the stored
+ * character string in the parse string.  Before this string value is
+ * returned to a calling application (profile_find_node_relation is not an
+ * exported interface), it should be strdup()'ed.
+ */
+errcode_t profile_find_node_relation(struct profile_node *section,
+				     const char *name, void **state,
+				     char **ret_name, char **value)
+{
+	struct profile_node *p;
+	errcode_t	retval;
+
+	retval = profile_find_node(section, name, 0, 0, state, &p);
+	if (retval)
+		return retval;
+
+	if (p) {
+		if (value)
+			*value = p->value;
+		if (ret_name)
+			*ret_name = p->name;
+	}
+	return 0;
+}
+
+/*
+ * Iterate through the section, returning the subsections which match
+ * the given name.  If name is NULL, then interate through all the
+ * subsections in the section.  The first time this routine is called,
+ * the state pointer must be null.  When this profile_find_node_subsection()
+ * returns, if the state pointer is non-NULL, then this routine should
+ * be called again.
+ *
+ * This is (plus accessor functions for the name and value given a
+ * profile node) makes this function mostly syntactic sugar for
+ * profile_find_node. 
+ */
+errcode_t profile_find_node_subsection(struct profile_node *section,
+				       const char *name, void **state,
+				       char **ret_name,
+				       struct profile_node **subsection)
+{
+	struct profile_node *p;
+	errcode_t	retval;
+
+	retval = profile_find_node(section, name, 0, 1, state, &p);
+	if (retval)
+		return retval;
+
+	if (p) {
+		if (subsection)
+			*subsection = p;
+		if (ret_name)
+			*ret_name = p->name;
+	}
+	return 0;
+}
+
+/*
+ * This function returns the parent of a particular node.
+ */
+errcode_t profile_get_node_parent(struct profile_node *section,
+				  struct profile_node **parent)
+{
+	*parent = section->parent;
+	return 0;
+}
+
+/*
+ * This is a general-purpose iterator for returning all nodes that
+ * match the specified name array.  
+ */
+struct profile_iterator {
+	prf_magic_t		magic;
+	profile_t		profile;
+	int			flags;
+	const char 		*const *names;
+	const char		*name;
+	prf_file_t		file;
+	int			file_serial;
+	int			done_idx;
+	struct profile_node 	*node;
+	int			num;
+};
+
+errcode_t profile_node_iterator_create(profile_t profile,
+				       const char *const *names, int flags,
+				       void **ret_iter)
+{
+	struct profile_iterator *iter;
+	int	done_idx = 0;
+
+	if (profile == 0)
+		return PROF_NO_PROFILE;
+	if (profile->magic != PROF_MAGIC_PROFILE)
+		return PROF_MAGIC_PROFILE;
+	if (!names)
+		return PROF_BAD_NAMESET;
+	if (!(flags & PROFILE_ITER_LIST_SECTION)) {
+		if (!names[0])
+			return PROF_BAD_NAMESET;
+		done_idx = 1;
+	}
+
+	if ((iter = malloc(sizeof(struct profile_iterator))) == NULL)
+		return ENOMEM;
+
+	iter->magic = PROF_MAGIC_ITERATOR;
+	iter->profile = profile;
+	iter->names = names;
+	iter->flags = flags;
+	iter->file = profile->first_file;
+	iter->done_idx = done_idx;
+	iter->node = 0;
+	iter->num = 0;
+	*ret_iter = iter;
+	return 0;
+}
+
+void profile_node_iterator_free(void **iter_p)
+{
+	struct profile_iterator *iter;
+
+	if (!iter_p)
+		return;
+	iter = *iter_p;
+	if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
+		return;
+	free(iter);
+	*iter_p = 0;
+}
+
+/*
+ * Note: the returned character strings in ret_name and ret_value
+ * points to the stored character string in the parse string.  Before
+ * this string value is returned to a calling application
+ * (profile_node_iterator is not an exported interface), it should be
+ * strdup()'ed.
+ */
+errcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node,
+				char **ret_name, char **ret_value)
+{
+	struct profile_iterator 	*iter = *iter_p;
+	struct profile_node 		*section, *p;
+	const char			*const *cpp;
+	errcode_t			retval;
+	int				skip_num = 0;
+
+	if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
+		return PROF_MAGIC_ITERATOR;
+	if (iter->file && iter->file->magic != PROF_MAGIC_FILE)
+	    return PROF_MAGIC_FILE;
+	if (iter->file && iter->file->data->magic != PROF_MAGIC_FILE_DATA)
+	    return PROF_MAGIC_FILE_DATA;
+	/*
+	 * If the file has changed, then the node pointer is invalid,
+	 * so we'll have search the file again looking for it.
+	 */
+	if (iter->file) {
+	    retval = k5_mutex_lock(&iter->file->data->lock);
+	    if (retval)
+		return retval;
+	}
+	if (iter->node && (iter->file->data->upd_serial != iter->file_serial)) {
+		iter->flags &= ~PROFILE_ITER_FINAL_SEEN;
+		skip_num = iter->num;
+		iter->node = 0;
+	}
+	if (iter->node && iter->node->magic != PROF_MAGIC_NODE) {
+	    if (iter->file)
+		k5_mutex_unlock(&iter->file->data->lock);
+	    return PROF_MAGIC_NODE;
+	}
+get_new_file:
+	if (iter->node == 0) {
+		if (iter->file == 0 ||
+		    (iter->flags & PROFILE_ITER_FINAL_SEEN)) {
+			if (iter->file)
+			    k5_mutex_unlock(&iter->file->data->lock);
+			profile_node_iterator_free(iter_p);
+			if (ret_node)
+				*ret_node = 0;
+			if (ret_name)
+				*ret_name = 0;
+			if (ret_value)
+				*ret_value =0;
+			return 0;
+		}
+		k5_mutex_unlock(&iter->file->data->lock);
+		if ((retval = profile_update_file(iter->file))) {
+		    if (retval == ENOENT || retval == EACCES) {
+			/* XXX memory leak? */
+			iter->file = iter->file->next;
+			if (iter->file) {
+			    retval = k5_mutex_lock(&iter->file->data->lock);
+			    if (retval) {
+				profile_node_iterator_free(iter_p);
+				return retval;
+			    }
+			}
+			skip_num = 0;
+			retval = 0;
+			goto get_new_file;
+		    } else {
+			profile_node_iterator_free(iter_p);
+			return retval;
+		    }
+		}
+		retval = k5_mutex_lock(&iter->file->data->lock);
+		if (retval) {
+		    profile_node_iterator_free(iter_p);
+		    return retval;
+		}
+		iter->file_serial = iter->file->data->upd_serial;
+		/*
+		 * Find the section to list if we are a LIST_SECTION,
+		 * or find the containing section if not.
+		 */
+		section = iter->file->data->root;
+		assert(section != NULL);
+		for (cpp = iter->names; cpp[iter->done_idx]; cpp++) {
+			for (p=section->first_child; p; p = p->next) {
+				if (!strcmp(p->name, *cpp) && !p->value)
+					break;
+			}
+			if (!p) {
+				section = 0;
+				break;
+			}
+			section = p;
+			if (p->final)
+				iter->flags |= PROFILE_ITER_FINAL_SEEN;
+		}
+		if (!section) {
+			k5_mutex_unlock(&iter->file->data->lock);
+			iter->file = iter->file->next;
+			if (iter->file) {
+			    retval = k5_mutex_lock(&iter->file->data->lock);
+			    if (retval) {
+				profile_node_iterator_free(iter_p);
+				return retval;
+			    }
+			}
+			skip_num = 0;
+			goto get_new_file;
+		}
+		iter->name = *cpp;
+		iter->node = section->first_child;
+	}
+	/*
+	 * OK, now we know iter->node is set up correctly.  Let's do
+	 * the search.
+	 */
+	for (p = iter->node; p; p = p->next) {
+		if (iter->name && strcmp(p->name, iter->name))
+			continue;
+		if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) &&
+		    p->value)
+			continue;
+		if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) &&
+		    !p->value)
+			continue;
+		if (skip_num > 0) {
+			skip_num--;
+			continue;
+		}
+		if (p->deleted)
+			continue;
+		break;
+	}
+	iter->num++;
+	if (!p) {
+		k5_mutex_unlock(&iter->file->data->lock);
+		iter->file = iter->file->next;
+		if (iter->file) {
+		    retval = k5_mutex_lock(&iter->file->data->lock);
+		    if (retval) {
+			profile_node_iterator_free(iter_p);
+			return retval;
+		    }
+		}
+		iter->node = 0;
+		skip_num = 0;
+		goto get_new_file;
+	}
+	k5_mutex_unlock(&iter->file->data->lock);
+	if ((iter->node = p->next) == NULL)
+		iter->file = iter->file->next;
+	if (ret_node)
+		*ret_node = p;
+	if (ret_name)
+		*ret_name = p->name;
+	if (ret_value)
+		*ret_value = p->value;
+	return 0;
+}
+
+/* 
+ * Remove a particular node.
+ * 
+ * TYT, 2/25/99
+ */
+errcode_t profile_remove_node(struct profile_node *node)
+{
+	CHECK_MAGIC(node);
+
+	if (node->parent == 0)
+		return PROF_EINVAL; /* Can't remove the root! */
+	
+	node->deleted = 1;
+
+	return 0;
+}
+
+/*
+ * Set the value of a specific node containing a relation.
+ *
+ * TYT, 2/25/99
+ */
+errcode_t profile_set_relation_value(struct profile_node *node,
+				     const char *new_value)
+{
+	char	*cp;
+	
+	CHECK_MAGIC(node);
+
+	if (!node->value)
+		return PROF_SET_SECTION_VALUE;
+
+	cp = malloc(strlen(new_value)+1);
+	if (!cp)
+		return ENOMEM;
+
+	strcpy(cp, new_value);
+	free(node->value);
+	node->value = cp;
+
+	return 0;
+}
+
+/*
+ * Rename a specific node
+ *
+ * TYT 2/25/99
+ */
+errcode_t profile_rename_node(struct profile_node *node, const char *new_name)
+{
+	char			*new_string;
+	struct profile_node 	*p, *last;
+
+	CHECK_MAGIC(node);
+
+	if (strcmp(new_name, node->name) == 0)
+		return 0;	/* It's the same name, return */
+
+	/*
+	 * Make sure we can allocate memory for the new name, first!
+	 */
+	new_string = malloc(strlen(new_name)+1);
+	if (!new_string)
+		return ENOMEM;
+	strcpy(new_string, new_name);
+
+	/*
+	 * Find the place to where the new node should go.  We look
+	 * for the place *after* the last match of the node name,
+	 * since order matters.
+	 */
+	for (p=node->parent->first_child, last = 0; p; last = p, p = p->next) {
+		if (strcmp(p->name, new_name) > 0)
+			break;
+	}
+
+	/*
+	 * If we need to move the node, do it now.
+	 */
+	if ((p != node) && (last != node)) {
+		/*
+		 * OK, let's detach the node
+		 */
+		if (node->prev)
+			node->prev->next = node->next;
+		else
+			node->parent->first_child = node->next;
+		if (node->next)
+			node->next->prev = node->prev;
+
+		/*
+		 * Now let's reattach it in the right place.
+		 */
+		if (p)
+			p->prev = node;
+		if (last)
+			last->next = node;
+		else
+			node->parent->first_child = node;
+		node->next = p;
+		node->prev = last;
+	}
+
+	free(node->name);
+	node->name = new_string;
+	return 0;
+}
diff --git a/mechglue/src/util/profile/profile.5 b/mechglue/src/util/profile/profile.5
new file mode 100644
index 000000000..7f3b36ab5
--- /dev/null
+++ b/mechglue/src/util/profile/profile.5
@@ -0,0 +1,71 @@
+
+A profile file is a generic way of storing program configuration
+information for applications.  An application may choose to consult
+multiple configuration files; for example, a Kerberos application
+might look first in ~/.krb5rc, and then in /etc/krb5.conf.  So
+/etc/krb5.conf would contain the side-wide default configuration for
+Kerberos, and ~/.krb5rc would contain the user's specific
+configuration overrides.
+
+Configuration information is stored in relations, which have a name
+and a value.  There may be multiple relations with the same name.
+Relations are always contained inside named sections.  Sections can
+contain relations and other named child sections.
+
+Top-level sections are defined by enclosing the section name in square
+braces.  Child sections are defined by enclosing the contents of the
+child section in curly braces.  Relations are defined by using the
+format "name = value".  
+
+An example profile file might look like this:
+
+[libdefaults]
+	default_realm = ATHENA.MIT.EDU
+
+[realms]
+	ATHENA.MIT.EDU = {
+		kdc = kerberos.mit.edu:88
+		kdc = kerberos-1.mit.edu:88
+		kdc = kerberos-2.mit.edu:88
+		admin_server = kerberos.mit.edu:88
+		default_domain = mit.edu
+	}
+	CYGNUS.COM = {
+		kdc = KERBEROS-1.CYGNUS.COM
+		kdc = KERBEROS.CYGNUS.COM
+		admin_server = KERBEROS.MIT.EDU
+	}
+
+In this example, the profile file has two top-level sections,
+"libdefaults" and "realms".  The libdefaults section has a single
+relation which is named "default_realm" and has the value
+"ATHENA.MIT.EDU".  The realms section has two child sections,
+"ATHENA.MIT.EDU" and "CYGNUS.MIT.EDU".  Each of these child has a
+number of relations, "kdc", "admin_server", and (in the case of
+"ATHENA.MIT.EDU"), "default_domain".  Note that there are multiple
+relations with the name "kdc" in both sections; if a
+profile_get_values() is called querying the "kdc" relation, both
+values will be returned.
+
+Sections may be marked as "final".  If they are marked as final, then
+the contents of that section override all subsequent profile files (if
+the application is searching multiple profile files for its
+configuration information).  Normally, all of the profiles are
+searched for a matching relation, and all of the values found in all
+of the various profile files will be returned.  
+
+Top-level sections are marked as final by adding an '*' character
+following the closing square brace.  Child sections are marked as
+final by adding a '*' character after the closing curly brace.  So for
+example, in this example both the "libdefaults" and "ATHENA.MIT.EDU"
+sections have been marked as final:
+
+[libdefaults]*
+	default_realm = ATHENA.MIT.EDU
+
+[realms]
+	ATHENA.MIT.EDU = {
+		kdc = kerberos.mit.edu:88
+		admin_server = kerberos.mit.edu:88
+	}*
+
diff --git a/mechglue/src/util/profile/profile.exp b/mechglue/src/util/profile/profile.exp
new file mode 100644
index 000000000..eaf720cd2
--- /dev/null
+++ b/mechglue/src/util/profile/profile.exp
@@ -0,0 +1,35 @@
+#
+# Profile library Macintosh export file
+#
+# $Header$
+
+profile_init
+profile_init_path
+profile_flush
+profile_abandon
+profile_release
+profile_get_values
+profile_free_list
+profile_get_string
+profile_get_boolean
+profile_get_integer
+profile_get_relation_names
+profile_get_subsection_names
+profile_iterator_create
+profile_iterator_free
+profile_iterator
+profile_release_string
+profile_update_relation
+profile_clear_relation
+profile_rename_section
+profile_add_relation
+
+### Temporary -- DO NOT USE
+
+profile_ser_internalize
+profile_ser_externalize
+profile_ser_size
+
+# Mac only
+FSp_profile_init
+FSp_profile_init_path
diff --git a/mechglue/src/util/profile/profile.hin b/mechglue/src/util/profile/profile.hin
new file mode 100644
index 000000000..10abe725a
--- /dev/null
+++ b/mechglue/src/util/profile/profile.hin
@@ -0,0 +1,125 @@
+/*
+ * profile.h
+ */
+
+#ifndef _KRB5_PROFILE_H
+#define _KRB5_PROFILE_H
+
+#if defined(_WIN32)
+#include <win-mac.h>
+#endif
+
+#if defined(__MACH__) && defined(__APPLE__)
+#    include <TargetConditionals.h>
+#    if TARGET_RT_MAC_CFM
+#        error "Use KfM 4.0 SDK headers for CFM compilation."
+#    endif
+#endif
+
+#ifndef KRB5_CALLCONV
+#define KRB5_CALLCONV
+#define KRB5_CALLCONV_C
+#endif
+
+typedef struct _profile_t *profile_t;
+
+/*
+ * Used by the profile iterator in prof_get.c
+ */
+#define PROFILE_ITER_LIST_SECTION	0x0001
+#define PROFILE_ITER_SECTIONS_ONLY	0x0002
+#define PROFILE_ITER_RELATIONS_ONLY	0x0004
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef char* profile_filespec_t;	/* path as C string */
+typedef char* profile_filespec_list_t;	/* list of : separated paths, C string */
+typedef const char * const_profile_filespec_t;	/* path as C string */
+typedef const char * const_profile_filespec_list_t;	/* list of : separated paths, C string */
+
+long KRB5_CALLCONV profile_init
+	(const_profile_filespec_t *files, profile_t *ret_profile);
+
+long KRB5_CALLCONV profile_init_path
+	(const_profile_filespec_list_t filelist, profile_t *ret_profile);
+
+long KRB5_CALLCONV profile_flush
+	(profile_t profile);
+long KRB5_CALLCONV profile_flush_to_file
+	(profile_t profile, const_profile_filespec_t outfile);
+long KRB5_CALLCONV profile_flush_to_buffer
+	(profile_t profile, char **bufp);
+void KRB5_CALLCONV profile_free_buffer
+	(profile_t profile, char *buf);
+
+long KRB5_CALLCONV profile_is_writable
+	(profile_t profile, int *writable);
+long KRB5_CALLCONV profile_is_modified
+	(profile_t profile, int *modified);
+
+void KRB5_CALLCONV profile_abandon
+	(profile_t profile);
+
+void KRB5_CALLCONV profile_release
+	(profile_t profile);
+
+long KRB5_CALLCONV profile_get_values
+	(profile_t profile, const char *const *names, char ***ret_values);
+
+void KRB5_CALLCONV profile_free_list
+	(char **list);
+
+long KRB5_CALLCONV profile_get_string
+	(profile_t profile, const char *name, const char *subname, 
+			const char *subsubname, const char *def_val,
+			char **ret_string);
+long KRB5_CALLCONV profile_get_integer
+	(profile_t profile, const char *name, const char *subname,
+			const char *subsubname, int def_val,
+			int *ret_default);
+
+long KRB5_CALLCONV profile_get_boolean
+	(profile_t profile, const char *name, const char *subname,
+			const char *subsubname, int def_val,
+			int *ret_default);
+
+long KRB5_CALLCONV profile_get_relation_names
+	(profile_t profile, const char **names, char ***ret_names);
+
+long KRB5_CALLCONV profile_get_subsection_names
+	(profile_t profile, const char **names, char ***ret_names);
+
+long KRB5_CALLCONV profile_iterator_create
+	(profile_t profile, const char *const *names,
+		   int flags, void **ret_iter);
+
+void KRB5_CALLCONV profile_iterator_free
+	(void **iter_p);
+	
+long KRB5_CALLCONV profile_iterator
+	(void	**iter_p, char **ret_name, char **ret_value);
+
+void KRB5_CALLCONV profile_release_string (char *str);
+
+long KRB5_CALLCONV profile_update_relation
+	(profile_t profile, const char **names, 
+		   const char *old_value, const char *new_value);
+
+long KRB5_CALLCONV profile_clear_relation
+	(profile_t profile, const char **names);
+
+long KRB5_CALLCONV profile_rename_section
+	(profile_t profile, const char **names, 
+		   const char *new_name);
+
+long KRB5_CALLCONV profile_add_relation
+	(profile_t profile, const char **names, 
+		   const char *new_value);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _KRB5_PROFILE_H */
diff --git a/mechglue/src/util/profile/profile.pbexp b/mechglue/src/util/profile/profile.pbexp
new file mode 100644
index 000000000..9033b54ea
--- /dev/null
+++ b/mechglue/src/util/profile/profile.pbexp
@@ -0,0 +1,33 @@
+#
+# Profile library Macintosh export file
+#
+# $Header$
+
+_profile_init
+_profile_init_path
+_FSp_profile_init
+_FSp_profile_init_path
+_profile_flush
+_profile_abandon
+_profile_release
+_profile_get_values
+_profile_free_list
+_profile_get_string
+_profile_get_boolean
+_profile_get_integer
+_profile_get_relation_names
+_profile_get_subsection_names
+_profile_iterator_create
+_profile_iterator_free
+_profile_iterator
+_profile_release_string
+_profile_update_relation
+_profile_clear_relation
+_profile_rename_section
+_profile_add_relation
+
+### Temporary -- DO NOT USE
+
+_profile_ser_internalize
+_profile_ser_externalize
+_profile_ser_size
diff --git a/mechglue/src/util/profile/profile.swg b/mechglue/src/util/profile/profile.swg
new file mode 100644
index 000000000..2e75bb4c6
--- /dev/null
+++ b/mechglue/src/util/profile/profile.swg
@@ -0,0 +1,258 @@
+%{
+/*
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Input for wrapper generator program SWIG for profile routines.
+ */
+#include <errno.h>
+#include "com_err.h"
+#include "profile.h"
+
+#ifdef SWIGTCL
+/* Reduce warnings about cast discarding const to just this one, from
+   every SWIG-generated call to Tcl_SetResult.  */
+static void my_tcl_setresult(Tcl_Interp *i, const char *str, Tcl_FreeProc *f)
+{
+    Tcl_SetResult(i, (char *) str, f);
+}
+#undef Tcl_SetResult
+#define Tcl_SetResult my_tcl_setresult
+#endif
+%}
+
+%include "typemaps.i"
+
+/* These should perhaps be part of the general SWIG package, maybe?  */
+%typemap(in,numinputs=0) SWIGTYPE *OUTPUT ($1_basetype tmp) {
+    /*generic swigtype hack*/ $1 = &tmp;
+}
+%typemap(tcl8,argout) SWIGTYPE *OUTPUT
+  "/*generic swigtype hack*/ Tcl_SetObjResult(interp,SWIG_NewInstanceObj((void *) *$1, $*1_descriptor,0));";
+%typemap(python,argout) SWIGTYPE *OUTPUT
+  "/*generic swigtype hack*/ resultobj = SWIG_NewPointerObj((void *) *$1, $*1_descriptor,0);";
+
+%module profile
+
+typedef long errcode_t;
+%inline %{
+typedef void **iter_t; /* ick */
+%}
+
+/* As a hack, if we have too much trouble trying to manage output
+   arguments for functions returning error codes, this output argument
+   type will let us twist it around into a function returning the
+   interesting type, and incidentally possibly raising an error.  */
+%typemap(in,numinputs=0) errcode_t * (errcode_t tmp) {
+    /* in errcode_t * */
+    tmp = 0;
+    $1 = &tmp;
+}
+%typemap(tcl8,argout) errcode_t* {
+    /* argout errcode_t * */
+    if (*$1) {
+	/* There could be a memory leak here in the SWIG-Tcl layer,
+	   I'm not sure.  Not going to worry about it though.  */
+	Tcl_SetResult(interp, (char *) error_message(*$1), TCL_STATIC);
+	SWIG_fail;
+    }
+}
+/* returning errcode_t */
+%typemap(tcl8,out) errcode_t {
+    /* out errcode_t $1 */
+    if ($1) {
+	/* There could be a memory leak here in the SWIG-Tcl layer,
+	   I'm not sure.  Not going to worry about it though.  */
+	Tcl_SetResult(interp, (char *) error_message($1), TCL_STATIC);
+	SWIG_fail;
+    }
+}
+%typemap(python,argout) errcode_t* {
+    /* do something with *($1) */ abort();
+}
+%typemap(python,out) errcode_t {
+    /* do something with $1 */ abort();
+}
+
+/* "char **OUTPUT" : Supply a place for the function to stuff one
+   string pointer.  */
+%typemap(in,numinputs=0) char **OUTPUT (char * tmp) {
+    /* in char **OUTPUT */
+    tmp = NULL;
+    $1 = &tmp;
+}
+%typemap(tcl8,argout) char **OUTPUT {
+    /* argout char **OUTPUT */
+/*    Tcl_SetResult(interp, *$1, TCL_DYNAMIC); */
+    char *s = ($1 && *$1) ? *$1 : "";
+    Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
+			     Tcl_NewStringObj(s, strlen(s)));
+}
+%typemap(freearg) char **OUTPUT {
+    /* There may be a memory leak here.  Investigate later, if anyone
+       cares.  */
+/*    profile_release_string(*$1); */
+}
+
+/* "char **nullterm" : Null-terminated list of strings, from a single
+   input value which is a list.  */
+%typemap(tcl8,in) char **nullterm {
+    /* in char **nullterm */
+    int n;
+    if (Tcl_SplitList(interp, Tcl_GetStringFromObj($input,NULL), &n, &$1) == TCL_ERROR) SWIG_fail;
+}
+%typemap(tcl8,freearg) char **nullterm {
+    /* freearg char **nullterm */
+    if ($1) { Tcl_Free((char *)$1); $1 = (char **) NULL; }
+}
+
+/* "char ***OUTPUT" : Supply a place for the function to stuff a
+   pointer to a list of strings, which will be combined into a list to
+   return, and the data from the function itself freed before
+   returning.  */
+%typemap(in,numinputs=0) char ***OUTPUT (char ** tmp) {
+    /* in char ***OUTPUT */
+    tmp = NULL;
+    $1 = &tmp;
+}
+%typemap(tcl8,argout) char ***OUTPUT {
+    /* argout char ***OUTPUT */
+    int i;
+    for (i = 0; (*$1)[i]; i++)
+	Tcl_AppendElement(interp, (*$1)[i]);
+}
+%typemap(tcl8,freearg) char ***OUTPUT {
+    /* freearg char ***OUTPUT */
+    profile_free_list(*$1);
+}
+
+typedef struct _profile_t *profile_t;
+
+errcode_t profile_init_path(const char *path = NULL, profile_t *OUTPUT);
+errcode_t profile_init(const char **nullterm = NULL, profile_t *OUTPUT);
+errcode_t profile_flush(profile_t);
+errcode_t profile_flush_to_file(profile_t, const char *path);
+/* Nota bene: There is nothing at all in this code to prevent a script
+   from accessing a profile object after calling one of these routines
+   to destroy it!  */
+void profile_abandon(profile_t);
+void profile_release(profile_t);
+
+errcode_t profile_get_values(profile_t p, const char **nullterm,
+			     char ***OUTPUT);
+
+/* XXX Because of the way this is specified, the default can only be
+   given if you're actually using all three names (e.g., for realm
+   data).  SWIG currently doesn't support a non-optional argument (at
+   the scripting-language level -- the output-only argument doesn't
+   count) after an optional one.  */
+extern errcode_t profile_get_string(profile_t p,
+				    const char *name,
+				    const char *subname,
+				    const char *subsubname = NULL,
+				    const char *defval = NULL,
+				    char **OUTPUT);
+
+errcode_t profile_get_integer(profile_t p,
+			      const char *name,
+			      const char *subname,
+			      const char *subsubname = NULL,
+			      int defval = 0,
+			      int *OUTPUT);
+errcode_t profile_get_boolean(profile_t p,
+			      const char *name,
+			      const char *subname,
+			      const char *subsubname = NULL,
+			      int defval = 0,
+			      int *OUTPUT);
+errcode_t profile_get_relation_names(profile_t p,
+				     const char **nullterm,
+				     char ***OUTPUT);
+errcode_t profile_get_subsection_names(profile_t p,
+				       const char **nullterm,
+				       char ***OUTPUT);
+
+%rename("profile_iterator_create") iter_create;
+%rename("profile_iterator_free") iter_free;
+%inline %{
+static errcode_t iter_create(profile_t p, const char **nullterm,
+			     int flags, iter_t *OUTPUT)
+{
+    iter_t it;
+    errcode_t err;
+    char **args;
+
+    it = malloc(sizeof(*it));
+    if (it == NULL)
+	return errno;
+    {
+	/* Memory leak!
+
+	   The profile code seems to assume that I'll keep the string
+	   array around for as long as the iterator is valid; I can't
+	   create the iterator and then throw them away.
+
+	   But right now, I can't be bothered to track the necessary
+	   information to do the cleanup later.  */
+	int count, j;
+	for (count = 0; nullterm[count]; count++) ;
+	args = calloc(count+1, sizeof(char *));
+	if (args == NULL)
+	    return errno;
+	for (j = 0; j < count; j++) {
+	    args[j] = strdup(nullterm[j]);
+	    if (args[j] == NULL)
+		return errno;
+	}
+	args[j] = NULL;
+    }
+    err = profile_iterator_create(p, args, flags, it);
+    if (err)
+	free(it);
+    else
+	*OUTPUT = it;
+    return err;
+}
+static errcode_t iter_free(iter_t i)
+{
+    profile_iterator_free(i);
+    free(i);
+}
+%}
+errcode_t profile_iterator(iter_t, char **OUTPUT, char **OUTPUT);
+
+
+errcode_t profile_update_relation(profile_t p, const char **nullterm,
+				  const char *oldval,
+				  const char *newval = NULL);
+errcode_t profile_clear_relation(profile_t p, const char **nullterm);
+errcode_t profile_rename_section(profile_t p, const char **nullterm,
+				 const char *new_name = NULL);
+errcode_t profile_add_relation(profile_t p, const char **nullterm,
+			       const char *new_val = NULL);
+/* XXX Should be using profile_free_buffer blah.  */
+errcode_t profile_flush_to_buffer(profile_t p, char **OUTPUT);
+
+#ifdef SWIGTCL
+%include "tclsh.i"
+#endif
diff --git a/mechglue/src/util/profile/profile_tcl.c b/mechglue/src/util/profile/profile_tcl.c
new file mode 100644
index 000000000..31a82f1b4
--- /dev/null
+++ b/mechglue/src/util/profile/profile_tcl.c
@@ -0,0 +1,2159 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.21
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+/*************************************************************** -*- c -*-
+ * Tcl/precommon.swg
+ *
+ * Rename all exported symbols from common.swg, to avoid symbol
+ * clashes if multiple interpreters are included
+ *
+ ************************************************************************/
+
+#define SWIG_TypeRegister    SWIG_Tcl_TypeRegister
+#define SWIG_TypeCheck       SWIG_Tcl_TypeCheck
+#define SWIG_TypeCast        SWIG_Tcl_TypeCast
+#define SWIG_TypeDynamicCast SWIG_Tcl_TypeDynamicCast
+#define SWIG_TypeName        SWIG_Tcl_TypeName
+#define SWIG_TypeQuery       SWIG_Tcl_TypeQuery
+#define SWIG_TypeClientData  SWIG_Tcl_TypeClientData
+#define SWIG_PackData        SWIG_Tcl_PackData 
+#define SWIG_UnpackData      SWIG_Tcl_UnpackData 
+
+
+/***********************************************************************
+ * common.swg
+ *
+ *     This file contains generic SWIG runtime support for pointer
+ *     type checking as well as a few commonly used macros to control
+ *     external linkage.
+ *
+ * Author : David Beazley (beazley@cs.uchicago.edu)
+ *
+ * Copyright (c) 1999-2000, The University of Chicago
+ * 
+ * This file may be freely redistributed without license or fee provided
+ * this copyright message remains intact.
+ ************************************************************************/
+
+#include <string.h>
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#  if defined(_MSC_VER) || defined(__GNUC__)
+#    if defined(STATIC_LINKED)
+#      define SWIGEXPORT(a) a
+#      define SWIGIMPORT(a) extern a
+#    else
+#      define SWIGEXPORT(a) __declspec(dllexport) a
+#      define SWIGIMPORT(a) extern a
+#    endif
+#  else
+#    if defined(__BORLANDC__)
+#      define SWIGEXPORT(a) a _export
+#      define SWIGIMPORT(a) a _export
+#    else
+#      define SWIGEXPORT(a) a
+#      define SWIGIMPORT(a) a
+#    endif
+#  endif
+#else
+#  define SWIGEXPORT(a) a
+#  define SWIGIMPORT(a) a
+#endif
+
+#ifdef SWIG_GLOBAL
+#  define SWIGRUNTIME(a) SWIGEXPORT(a)
+#else
+#  define SWIGRUNTIME(a) static a
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+typedef struct swig_type_info {
+  const char             *name;
+  swig_converter_func     converter;
+  const char             *str;
+  void                   *clientdata;
+  swig_dycast_func        dcast;
+  struct swig_type_info  *next;
+  struct swig_type_info  *prev;
+} swig_type_info;
+
+#ifdef SWIG_NOINCLUDE
+
+SWIGIMPORT(swig_type_info *) SWIG_TypeRegister(swig_type_info *);
+SWIGIMPORT(swig_type_info *) SWIG_TypeCheck(char *c, swig_type_info *);
+SWIGIMPORT(void *)           SWIG_TypeCast(swig_type_info *, void *);
+SWIGIMPORT(swig_type_info *) SWIG_TypeDynamicCast(swig_type_info *, void **);
+SWIGIMPORT(const char *)     SWIG_TypeName(const swig_type_info *);
+SWIGIMPORT(swig_type_info *) SWIG_TypeQuery(const char *);
+SWIGIMPORT(void)             SWIG_TypeClientData(swig_type_info *, void *);
+SWIGIMPORT(char *)           SWIG_PackData(char *, void *, int);
+SWIGIMPORT(char *)           SWIG_UnpackData(char *, void *, int);
+
+#else
+
+static swig_type_info *swig_type_list = 0;
+
+/* Register a type mapping with the type-checking */
+SWIGRUNTIME(swig_type_info *)
+SWIG_TypeRegister(swig_type_info *ti) {
+  swig_type_info *tc, *head, *ret, *next;
+  /* Check to see if this type has already been registered */
+  tc = swig_type_list;
+  while (tc) {
+    if (strcmp(tc->name, ti->name) == 0) {
+      /* Already exists in the table.  Just add additional types to the list */
+      if (tc->clientdata) ti->clientdata = tc->clientdata;
+      head = tc;
+      next = tc->next;
+      goto l1;
+    }
+    tc = tc->prev;
+  }
+  head = ti;
+  next = 0;
+
+  /* Place in list */
+  ti->prev = swig_type_list;
+  swig_type_list = ti;
+
+  /* Build linked lists */
+  l1:
+  ret = head;
+  tc = ti + 1;
+  /* Patch up the rest of the links */
+  while (tc->name) {
+    head->next = tc;
+    tc->prev = head;
+    head = tc;
+    tc++;
+  }
+  if (next) next->prev = head;
+  head->next = next;
+  return ret;
+}
+
+/* Check the typename */
+SWIGRUNTIME(swig_type_info *) 
+SWIG_TypeCheck(char *c, swig_type_info *ty) {
+  swig_type_info *s;
+  if (!ty) return 0;        /* Void pointer */
+  s = ty->next;             /* First element always just a name */
+  do {
+    if (strcmp(s->name,c) == 0) {
+      if (s == ty->next) return s;
+      /* Move s to the top of the linked list */
+      s->prev->next = s->next;
+      if (s->next) {
+        s->next->prev = s->prev;
+      }
+      /* Insert s as second element in the list */
+      s->next = ty->next;
+      if (ty->next) ty->next->prev = s;
+      ty->next = s;
+      s->prev = ty;
+      return s;
+    }
+    s = s->next;
+  } while (s && (s != ty->next));
+  return 0;
+}
+
+/* Cast a pointer up an inheritance hierarchy */
+SWIGRUNTIME(void *) 
+SWIG_TypeCast(swig_type_info *ty, void *ptr) {
+  if ((!ty) || (!ty->converter)) return ptr;
+  return (*ty->converter)(ptr);
+}
+
+/* Dynamic pointer casting. Down an inheritance hierarchy */
+SWIGRUNTIME(swig_type_info *) 
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/* Return the name associated with this type */
+SWIGRUNTIME(const char *)
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/* Search for a swig_type_info structure */
+SWIGRUNTIME(swig_type_info *)
+SWIG_TypeQuery(const char *name) {
+  swig_type_info *ty = swig_type_list;
+  while (ty) {
+    if (ty->str && (strcmp(name,ty->str) == 0)) return ty;
+    if (ty->name && (strcmp(name,ty->name) == 0)) return ty;
+    ty = ty->prev;
+  }
+  return 0;
+}
+
+/* Set the clientdata field for a type */
+SWIGRUNTIME(void)
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  swig_type_info *tc, *equiv;
+  if (ti->clientdata == clientdata) return;
+  ti->clientdata = clientdata;
+  equiv = ti->next;
+  while (equiv) {
+    if (!equiv->converter) {
+      tc = swig_type_list;
+      while (tc) {
+        if ((strcmp(tc->name, equiv->name) == 0))
+          SWIG_TypeClientData(tc,clientdata);
+        tc = tc->prev;
+      }
+    }
+    equiv = equiv->next;
+  }
+}
+
+/* Pack binary data into a string */
+SWIGRUNTIME(char *)
+SWIG_PackData(char *c, void *ptr, int sz) {
+  static char hex[17] = "0123456789abcdef";
+  int i;
+  unsigned char *u = (unsigned char *) ptr;
+  register unsigned char uu;
+  for (i = 0; i < sz; i++,u++) {
+    uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* Unpack binary data from a string */
+SWIGRUNTIME(char *)
+SWIG_UnpackData(char *c, void *ptr, int sz) {
+  register unsigned char uu = 0;
+  register int d;
+  unsigned char *u = (unsigned char *) ptr;
+  int i;
+  for (i = 0; i < sz; i++, u++) {
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    *u = uu;
+  }
+  return c;
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+ * $Header: /cvsroot/SWIG/Lib/tcl/swigtcl8.swg,v 1.19 2003/12/09 12:44:49 beazley Exp $
+ * 
+ * swigtcl8.swg
+ */
+
+#include <tcl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Constant table */
+
+#define SWIG_TCL_INT     1
+#define SWIG_TCL_FLOAT   2
+#define SWIG_TCL_STRING  3
+#define SWIG_TCL_POINTER 4
+#define SWIG_TCL_BINARY  5
+
+/* Flags for pointer conversion */
+#define SWIG_POINTER_EXCEPTION     0x1
+#define SWIG_POINTER_DISOWN        0x2
+
+/* Swig fail macro */
+
+#define SWIG_fail   goto fail
+
+/* Constant information structure */
+typedef struct swig_const_info {
+    int type;
+    char *name;
+    long lvalue;
+    double dvalue;
+    void   *pvalue;
+    swig_type_info **ptype;
+} swig_const_info;
+
+typedef int   (*swig_wrapper)(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
+typedef int   (*swig_wrapper_func)(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
+typedef char *(*swig_variable_func)(ClientData, Tcl_Interp *, char *, char *, int);
+typedef void  (*swig_delete_func)(ClientData);
+
+typedef struct swig_method {
+  const char     *name;
+  swig_wrapper   method;
+} swig_method;
+
+typedef struct swig_attribute {
+  const char     *name;
+  swig_wrapper   getmethod;
+  swig_wrapper   setmethod;
+} swig_attribute;
+
+typedef struct swig_class {
+  const char         *name;
+  swig_type_info   **type;
+  swig_wrapper       constructor;
+  void              (*destructor)(void *);
+  swig_method        *methods;
+  swig_attribute     *attributes;
+  struct swig_class **bases;
+} swig_class;
+
+typedef struct swig_instance {
+  Tcl_Obj       *thisptr;
+  void          *thisvalue;
+  swig_class   *classptr;
+  int            destroy;
+  Tcl_Command    cmdtok;
+} swig_instance;
+
+#define SWIG_NewPointerObj(ptr, type, flags) \
+  SWIG_Tcl_NewPointerObj(ptr, type, flags)
+#define SWIG_ConvertPtr(oc, ptr, ty, flags) \
+  SWIG_Tcl_ConvertPtr(interp, oc, ptr, ty, flags)
+#define SWIG_ConvertPtrFromString(c, ptr, ty, flags) \
+  SWIG_Tcl_ConvertPtrFromString(interp, c, ptr, ty, flags)
+#define SWIG_ConvertPacked(obj, ptr, sz, ty, flags) \
+  SWIG_Tcl_ConvertPacked(interp, obj, ptr, sz, ty, flags)
+#define SWIG_MakePtr(c, ptr, ty, flags) \
+  SWIG_Tcl_MakePtr(c, ptr, ty, flags)
+#define SWIG_NewPackedObj(ptr, sz, type, flags) \
+  SWIG_Tcl_NewPackedObj(ptr, sz, type, flags)
+#define SWIG_GetArgs SWIG_Tcl_GetArgs
+#define SWIG_PointerTypeFromString(c) \
+  SWIG_Tcl_PointerTypeFromString(c)
+#define SWIG_Acquire(ptr) \
+  SWIG_Tcl_Acquire(ptr)
+#define SWIG_Disown(ptr) \
+  SWIG_Tcl_Disown(ptr)
+#define SWIG_Thisown(ptr) \
+  SWIG_Tcl_Thisown(ptr)
+#define SWIG_InstallConstants(interp, constants) \
+  SWIG_Tcl_InstallConstants(interp, constants)
+#define SWIG_GetConstant(key) \
+  SWIG_Tcl_GetConstant(key)
+#define SWIG_NewInstanceObj(thisvalue, type, flags) \
+  SWIG_Tcl_NewInstanceObj(interp, thisvalue, type, flags)
+#define SWIG_ObjectConstructor SWIG_Tcl_ObjectConstructor
+#define SWIG_MethodCommand SWIG_Tcl_MethodCommand
+#define SWIG_ObjectDelete SWIG_Tcl_ObjectDelete
+
+#ifdef SWIG_NOINCLUDE
+
+SWIGIMPORT(int)       SWIG_Tcl_ConvertPtrFromString(Tcl_Interp *, char *, void **, swig_type_info *,int flags);
+SWIGIMPORT(int)       SWIG_Tcl_ConvertPtr(Tcl_Interp *, Tcl_Obj *, void **, swig_type_info *, int flags);
+SWIGIMPORT(int)       SWIG_Tcl_ConvertPacked(Tcl_Interp *, Tcl_Obj *, void *, int sz, swig_type_info *, int flags);
+SWIGIMPORT(void)      SWIG_Tcl_MakePtr(char *, void *, swig_type_info *, int flags);
+SWIGIMPORT(Tcl_Obj *) SWIG_Tcl_NewPointerObj(void *, swig_type_info *, int flags);
+SWIGIMPORT(Tcl_Obj *) SWIG_Tcl_NewPackedObj(void *, int sz, swig_type_info *, int flags);
+SWIGIMPORT(int)       SWIG_Tcl_GetArgs(Tcl_Interp *, int, Tcl_Obj *CONST [], const char *, ...);
+SWIGIMPORT(char *)    SWIG_Tcl_PointerTypeFromString(char *c);
+SWIGIMPORT(void)      SWIG_Tcl_Acquire(void *ptr);
+SWIGIMPORT(int)       SWIG_Tcl_Disown(void *ptr);
+SWIGIMPORT(int)       SWIG_Tcl_Thisown(void *ptr);
+SWIGIMPORT(void)      SWIG_Tcl_InstallConstants(Tcl_Interp *interp, struct swig_const_info constants[]);
+SWIGIMPORT(Tcl_Obj *) SWIG_Tcl_GetConstant(const char *key);
+SWIGIMPORT(Tcl_Obj *) SWIG_Tcl_NewInstanceObj(Tcl_Interp *interp, void *, swig_type_info *, int flags);
+SWIGIMPORT(int)       SWIG_Tcl_ObjectConstructor(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
+SWIGIMPORT(int)       SWIG_Tcl_MethodCommand(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
+SWIGIMPORT(void)      SWIG_Tcl_ObjectDelete(ClientData);
+
+#else
+
+/* Object support */
+static Tcl_HashTable  swigobjectTable;
+static int            swigobjectTableinit = 0;
+
+/* Acquire ownership of a pointer */
+SWIGRUNTIME(void)
+SWIG_Tcl_Acquire(void *ptr) {
+  Tcl_HashEntry *entryPtr;
+  int newobj;
+  if (!swigobjectTableinit) {
+    Tcl_InitHashTable(&swigobjectTable, TCL_ONE_WORD_KEYS);
+    swigobjectTableinit = 1;
+  }
+  entryPtr = Tcl_CreateHashEntry(&swigobjectTable, (char *) ptr, &newobj);
+}
+
+/* Disown a pointer.  Returns 1 if we owned it to begin with */
+SWIGRUNTIME(int)
+SWIG_Tcl_Disown(void *ptr) {
+  Tcl_HashEntry *entryPtr;
+  if (!swigobjectTableinit) return 0;
+  entryPtr = Tcl_FindHashEntry(&swigobjectTable, (char *) ptr);
+  if (entryPtr) {
+    Tcl_DeleteHashEntry(entryPtr);
+    return 1;
+  }
+  return 0;
+}
+
+SWIGRUNTIME(int)
+SWIG_Tcl_Thisown(void *ptr) {
+  if (!swigobjectTableinit) return 0;
+  if (Tcl_FindHashEntry(&swigobjectTable, (char *) ptr)) {
+    return 1;
+  }
+  return 0;
+}
+
+/* Convert a pointer value */
+SWIGRUNTIME(int)
+SWIG_Tcl_ConvertPtrFromString(Tcl_Interp *interp, char *c, void **ptr, swig_type_info *ty, int flags) {
+  swig_type_info *tc;
+  /* Pointer values must start with leading underscore */
+  while (*c != '_') {
+    *ptr = (void *) 0;
+    if (strcmp(c,"NULL") == 0) return TCL_OK;
+    /* Hmmm. It could be an object name. */
+    if (Tcl_VarEval(interp,c," cget -this", (char *) NULL) == TCL_OK) {
+      Tcl_Obj *result = Tcl_GetObjResult(interp);
+      c = Tcl_GetStringFromObj(result, NULL);
+      continue;
+    }
+    Tcl_ResetResult(interp);
+    if (flags & SWIG_POINTER_EXCEPTION) 
+      Tcl_SetResult(interp, (char *) "Type error. Expected a pointer", TCL_STATIC);
+    return TCL_ERROR;
+  }
+  c++;
+  c = SWIG_UnpackData(c,ptr,sizeof(void *));
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if ((!tc) && (flags & SWIG_POINTER_EXCEPTION)) {
+      Tcl_SetResult(interp, (char *) "Type error. Expected ", TCL_STATIC);
+      Tcl_AppendElement(interp, (char *) ty->name);
+      return TCL_ERROR;
+    } else if (!tc) {
+      Tcl_ResetResult(interp);
+      return TCL_ERROR;
+    }
+    if (flags & SWIG_POINTER_DISOWN) {
+      SWIG_Disown((void *) *ptr);
+    }
+    *ptr = SWIG_TypeCast(tc,(void *) *ptr);
+  }
+  return TCL_OK;
+}
+
+/* Convert a pointer value */
+SWIGRUNTIME(int)
+SWIG_Tcl_ConvertPtr(Tcl_Interp *interp, Tcl_Obj *oc, void **ptr, swig_type_info *ty, int flags) {
+  return SWIG_Tcl_ConvertPtrFromString(interp, Tcl_GetStringFromObj(oc,NULL), ptr, ty, flags);
+}
+
+/* Convert a pointer value */
+SWIGRUNTIME(char *)
+SWIG_Tcl_PointerTypeFromString(char *c) {
+  char d;
+  /* Pointer values must start with leading underscore. NULL has no type */
+  if (*c != '_') {
+    return 0;
+  }
+  c++;
+  /* Extract hex value from pointer */
+  while ((d = *c)) {
+    if (!(((d >= '0') && (d <= '9')) || ((d >= 'a') && (d <= 'f')))) break;
+    c++;
+  }
+  return c;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME(int)
+SWIG_Tcl_ConvertPacked(Tcl_Interp *interp, Tcl_Obj *obj, void *ptr, int sz, swig_type_info *ty, int flags) {
+  swig_type_info *tc;
+  char  *c;
+
+  if (!obj) goto type_error;
+  c = Tcl_GetStringFromObj(obj,NULL);
+  /* Pointer values must start with leading underscore */
+  if (*c != '_') goto type_error;
+  c++;
+  c = SWIG_UnpackData(c,ptr,sz);
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) goto type_error;
+  }
+  return TCL_OK;
+
+type_error:
+
+  if (flags) {
+    if (ty) {
+      Tcl_SetResult(interp, (char *) "Type error. Expected ", TCL_STATIC);
+      Tcl_AppendElement(interp, (char *) ty->name);
+      return TCL_ERROR;
+    } else {
+      Tcl_SetResult(interp, (char *) "Expected packed data.", TCL_STATIC);
+      return TCL_ERROR;
+    }
+  }
+  return TCL_ERROR;
+}
+
+
+/* Take a pointer and convert it to a string */
+SWIGRUNTIME(void)
+SWIG_Tcl_MakePtr(char *c, void *ptr, swig_type_info *ty, int flags) {
+  if (ptr) {
+    *(c++) = '_';
+    c = SWIG_PackData(c,&ptr,sizeof(void *));
+    strcpy(c,ty->name);
+  } else {
+    strcpy(c,(char *)"NULL");
+  }
+  flags = 0;
+}
+
+/* Create a new pointer object */
+SWIGRUNTIME(Tcl_Obj *)
+SWIG_Tcl_NewPointerObj(void *ptr, swig_type_info *type, int flags) {
+  Tcl_Obj *robj;
+  char result[512];
+  SWIG_MakePtr(result,ptr,type,flags);
+  robj = Tcl_NewStringObj(result,-1);
+  return robj;
+}
+
+SWIGRUNTIME(Tcl_Obj *)
+SWIG_Tcl_NewPackedObj(void *ptr, int sz, swig_type_info *type, int flags) {
+  char result[1024];
+  char *r = result;
+  if ((2*sz + 1 + strlen(type->name)) > 1000) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  strcpy(r,type->name);
+  flags = 0;
+  return Tcl_NewStringObj(result,-1);
+}
+
+static Tcl_HashTable   swigconstTable;
+static int             swigconstTableinit = 0;
+
+/* Install Constants */
+SWIGRUNTIME(void)
+SWIG_Tcl_InstallConstants(Tcl_Interp *interp, swig_const_info constants[]) {
+  int i;
+  Tcl_Obj *obj;
+  Tcl_HashEntry *entryPtr;
+  int            newobj;
+
+  if (!swigconstTableinit) {
+    Tcl_InitHashTable(&swigconstTable, TCL_STRING_KEYS);
+    swigconstTableinit = 1;
+  }
+  for (i = 0; constants[i].type; i++) {
+    switch(constants[i].type) {
+    case SWIG_TCL_INT:
+      obj = Tcl_NewIntObj(constants[i].lvalue);
+      break;
+    case SWIG_TCL_FLOAT:
+      obj = Tcl_NewDoubleObj(constants[i].dvalue);
+      break;
+    case SWIG_TCL_STRING:
+      obj = Tcl_NewStringObj((char *) constants[i].pvalue,-1);
+      break;
+    case SWIG_TCL_POINTER:
+      obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0);
+      break;
+    case SWIG_TCL_BINARY:
+      obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype),0);
+      break;
+    default:
+      obj = 0;
+      break;
+    }
+    if (obj) {
+      Tcl_ObjSetVar2(interp,Tcl_NewStringObj(constants[i].name,-1), NULL, obj, TCL_GLOBAL_ONLY);
+      entryPtr = Tcl_CreateHashEntry(&swigconstTable, constants[i].name, &newobj);
+      Tcl_SetHashValue(entryPtr, (ClientData) obj);
+    }
+  }
+}
+
+SWIGRUNTIME(Tcl_Obj *)
+SWIG_Tcl_GetConstant(const char *key) {
+  Tcl_HashEntry *entryPtr;
+  if (!swigconstTableinit) return 0;
+  entryPtr = Tcl_FindHashEntry(&swigconstTable, key);
+  if (entryPtr) {
+    return (Tcl_Obj *) Tcl_GetHashValue(entryPtr);
+  }
+  printf("Searching %s\n", key);
+  return 0;
+}
+
+/* Get arguments */
+SWIGRUNTIME(int)
+SWIG_Tcl_GetArgs(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], const char *fmt, ...) {
+  int        argno = 0, opt = 0;
+  long       tempi;
+  double     tempd;
+  const char *c;
+  va_list    ap;
+  void      *vptr;
+  Tcl_Obj   *obj = 0;
+  swig_type_info *ty;
+
+  va_start(ap,fmt);
+  for (c = fmt; (*c && (*c != ':') && (*c != ';')); c++,argno++) {
+    if (*c == '|') {
+      opt = 1;
+      c++;
+    }
+    if (argno >= (objc-1)) {
+      if (!opt) {
+        Tcl_SetResult(interp, (char *) "Wrong # args. ", TCL_STATIC);
+        goto argerror;
+      } else {
+        va_end(ap);
+        return TCL_OK;
+      }
+    }
+
+    vptr = va_arg(ap,void *);
+    if (vptr) {
+      if (isupper(*c)) {
+        obj = SWIG_GetConstant(Tcl_GetStringFromObj(objv[argno+1],0));
+        if (!obj) obj = objv[argno+1];
+      } else {
+        obj = objv[argno+1];
+      }
+      switch(*c) {
+      case 'i': case 'I':
+      case 'l': case 'L':
+      case 'h': case 'H':
+      case 'b': case 'B':
+        if (Tcl_GetLongFromObj(interp,obj,&tempi) != TCL_OK) goto argerror;
+        if ((*c == 'i') || (*c == 'I')) *((int *)vptr) = (int)tempi;
+        else if ((*c == 'l') || (*c == 'L')) *((long *)vptr) = (long)tempi;
+        else if ((*c == 'h') || (*c == 'H')) *((short*)vptr) = (short)tempi;
+        else if ((*c == 'b') || (*c == 'B')) *((unsigned char *)vptr) = (unsigned char)tempi;
+        break;
+      case 'f': case 'F':
+      case 'd': case 'D':
+        if (Tcl_GetDoubleFromObj(interp,obj,&tempd) != TCL_OK) goto argerror;
+        if ((*c == 'f') || (*c == 'F')) *((float *) vptr) = (float)tempd;
+        else if ((*c == 'd') || (*c == 'D')) *((double*) vptr) = tempd;
+        break;
+      case 's': case 'S':
+        if (*(c+1) == '#') {
+          int *vlptr = (int *) va_arg(ap, void *);
+          *((char **) vptr) = Tcl_GetStringFromObj(obj, vlptr);
+          c++;
+        } else {
+          *((char **)vptr) = Tcl_GetStringFromObj(obj,NULL);
+        }
+        break;
+      case 'c': case 'C':
+        *((char *)vptr) = *(Tcl_GetStringFromObj(obj,NULL));
+        break;
+      case 'p': case 'P':
+        ty = (swig_type_info *) va_arg(ap, void *);
+        if (SWIG_Tcl_ConvertPtr(interp, obj, (void **) vptr, ty, SWIG_POINTER_EXCEPTION) == TCL_ERROR) goto argerror;
+        break;
+      case 'o': case 'O':
+        *((Tcl_Obj **)vptr) = objv[argno+1];
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+  if ((*c != ';') && ((objc-1) > argno)) {
+    Tcl_SetResult(interp, (char *) "Wrong # args.", TCL_STATIC);
+    goto argerror;
+  }
+  va_end(ap);
+  return TCL_OK;
+
+ argerror:
+  {
+    char temp[32];
+    sprintf(temp,"%d", argno+1);
+    c = strchr(fmt,':');
+    if (!c) c = strchr(fmt,';');
+    if (!c) c = (char *)"";
+    Tcl_AppendResult(interp,c," argument ", temp, NULL);
+    va_end(ap);
+    return TCL_ERROR;
+  }
+}
+
+SWIGRUNTIME(void)
+SWIG_Tcl_ObjectDelete(ClientData clientData) {
+  swig_instance *si = (swig_instance *) clientData;
+  if ((si) && (si->destroy) && (SWIG_Disown(si->thisvalue))) {
+    if (si->classptr->destructor) {
+      (si->classptr->destructor)(si->thisvalue);
+    }
+  }
+  Tcl_DecrRefCount(si->thisptr);
+  free(si);
+}
+
+/* Function to invoke object methods given an instance */
+SWIGRUNTIME(int)
+SWIG_Tcl_MethodCommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST _objv[]) {
+  char *method,   *attrname;
+  swig_instance   *inst = (swig_instance *) clientData;
+  swig_method     *meth;
+  swig_attribute  *attr;
+  Tcl_Obj         *oldarg;
+  Tcl_Obj         **objv;
+  int              rcode;
+  swig_class      *cls;
+  swig_class      *cls_stack[64];
+  int              cls_stack_bi[64];
+  int              cls_stack_top = 0;
+  int              numconf = 2;
+  int              bi;
+
+  objv = (Tcl_Obj **) _objv;
+  if (objc < 2) {
+    Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC);
+    return TCL_ERROR;
+  }
+  method = Tcl_GetStringFromObj(objv[1],NULL);
+  if (strcmp(method,"-acquire") == 0) {
+    inst->destroy = 1;
+    SWIG_Acquire(inst->thisvalue);
+    return TCL_OK;
+  }
+  if (strcmp(method,"-disown") == 0) {
+    if (inst->destroy) {
+      SWIG_Disown(inst->thisvalue);
+    }
+    inst->destroy = 0;
+    return TCL_OK;
+  }
+  if (strcmp(method,"-delete") == 0) {
+    Tcl_DeleteCommandFromToken(interp,inst->cmdtok);
+    return TCL_OK;
+  }
+  cls_stack[cls_stack_top] = inst->classptr;
+  cls_stack_bi[cls_stack_top] = -1;
+  cls = inst->classptr;
+  while (1) {
+    bi = cls_stack_bi[cls_stack_top];
+    cls = cls_stack[cls_stack_top];
+    if (bi != -1) {
+      cls = cls->bases[bi];
+      if (cls) {
+        cls_stack_bi[cls_stack_top]++;
+        cls_stack_top++;
+        cls_stack[cls_stack_top] = cls;
+        cls_stack_bi[cls_stack_top] = -1;
+        continue;
+      }
+    }
+    if (!cls) {
+      cls_stack_top--;
+      if (cls_stack_top < 0) break;
+      else continue;
+    }
+    cls_stack_bi[cls_stack_top]++;
+
+    meth = cls->methods;
+    /* Check for methods */
+    while (meth && meth->name) {
+      if (strcmp(meth->name,method) == 0) {
+        oldarg = objv[1];
+        objv[1] = inst->thisptr;
+        Tcl_IncrRefCount(inst->thisptr);
+        rcode = (*meth->method)(clientData,interp,objc,objv);
+        objv[1] = oldarg;
+        Tcl_DecrRefCount(inst->thisptr);
+        return rcode;
+      }
+      meth++;
+    }
+    /* Check class methods for a match */
+    if (strcmp(method,"cget") == 0) {
+      if (objc < 3) {
+        Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC);
+        return TCL_ERROR;
+      }
+      attrname = Tcl_GetStringFromObj(objv[2],NULL);
+      attr = cls->attributes;
+      while (attr && attr->name) {
+        if ((strcmp(attr->name, attrname) == 0) && (attr->getmethod)) {
+          oldarg = objv[1];
+          objv[1] = inst->thisptr;
+          Tcl_IncrRefCount(inst->thisptr);
+          rcode = (*attr->getmethod)(clientData,interp,2, objv);
+          objv[1] = oldarg;
+          Tcl_DecrRefCount(inst->thisptr);
+          return rcode;
+        }
+        attr++;
+      }
+      if (strcmp(attrname, "-this") == 0) {
+        Tcl_SetObjResult(interp, Tcl_DuplicateObj(inst->thisptr));
+        return TCL_OK;
+      }
+      if (strcmp(attrname, "-thisown") == 0) {
+        if (SWIG_Thisown(inst->thisvalue)) {
+          Tcl_SetResult(interp,(char*)"1",TCL_STATIC);
+        } else {
+          Tcl_SetResult(interp,(char*)"0",TCL_STATIC);
+        }
+        return TCL_OK;
+      }
+    } else if (strcmp(method, "configure") == 0) {
+      int i;
+      if (objc < 4) {
+        Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC);
+        return TCL_ERROR;
+      }
+      i = 2;
+      while (i < objc) {
+        attrname = Tcl_GetStringFromObj(objv[i],NULL);
+        attr = cls->attributes;
+        while (attr && attr->name) {
+          if ((strcmp(attr->name, attrname) == 0) && (attr->setmethod)) {
+            oldarg = objv[i];
+            objv[i] = inst->thisptr;
+            Tcl_IncrRefCount(inst->thisptr);
+            rcode = (*attr->setmethod)(clientData,interp,3, &objv[i-1]);
+            objv[i] = oldarg;
+            Tcl_DecrRefCount(inst->thisptr);
+            if (rcode != TCL_OK) return rcode;
+            numconf += 2;
+          }
+          attr++;
+        }
+        i+=2;
+      }
+    }
+  }
+  if (strcmp(method,"configure") == 0) {
+    if (numconf >= objc) {
+      return TCL_OK;
+    } else {
+      Tcl_SetResult(interp,(char *) "Invalid attribute name.", TCL_STATIC);
+      return TCL_ERROR;
+    }
+  }
+  if (strcmp(method,"cget") == 0) {
+      Tcl_SetResult(interp,(char *) "Invalid attribute name.", TCL_STATIC);
+      return TCL_ERROR;
+  }
+
+  Tcl_SetResult(interp, (char *) "Invalid method. Must be one of: configure cget -acquire -disown -delete", TCL_STATIC);
+  cls = inst->classptr;
+  bi = 0;
+  while (cls) {
+    meth = cls->methods;
+    while (meth && meth->name) {
+      char *cr = (char *) Tcl_GetStringResult(interp);
+      if (!strstr(strchr(cr,':'), meth->name))
+        Tcl_AppendElement(interp, (char *) meth->name);
+      meth++;
+    }
+    cls = inst->classptr->bases[bi++];
+  }
+  return TCL_ERROR;
+}
+
+/* Function to create objects */
+SWIGRUNTIME(int)
+SWIG_Tcl_ObjectConstructor(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    Tcl_Obj          *newObj = 0;
+    void             *thisvalue = 0;
+    swig_instance   *newinst = 0;
+    swig_class      *classptr = (swig_class *) clientData;
+    swig_wrapper     cons = 0;
+    char             *name = 0;
+    int               firstarg = 0;
+    int               thisarg = 0;
+    int               destroy = 1;
+
+    if (!classptr) {
+      Tcl_SetResult(interp, (char *) "swig: internal runtime error. No class object defined.", TCL_STATIC);
+      return TCL_ERROR;
+    }
+    cons = classptr->constructor;
+    if (objc > 1) {
+      char *s = Tcl_GetStringFromObj(objv[1],NULL);
+      if (strcmp(s,"-this") == 0) {
+        thisarg = 2;
+        cons = 0;
+      } else if (strcmp(s,"-args") == 0) {
+        firstarg = 1;
+      } else if (objc == 2) {
+        firstarg = 1;
+        name = s;
+      } else if (objc >= 3) {
+        char *s1;
+        name = s;
+        s1 = Tcl_GetStringFromObj(objv[2],NULL);
+        if (strcmp(s1,"-this") == 0) {
+          thisarg = 3;
+          cons = 0;
+        } else {
+          firstarg = 1;
+        }
+      }
+    }
+    if (cons) {
+      int result;
+      result = (*cons)(0, interp, objc-firstarg, &objv[firstarg]);
+      if (result != TCL_OK) {
+        return result;
+      }
+      newObj = Tcl_DuplicateObj(Tcl_GetObjResult(interp));
+      if (!name) name = Tcl_GetStringFromObj(newObj,NULL);
+    } else if (thisarg > 0) {
+      if (thisarg < objc) {
+        destroy = 0;
+        newObj = Tcl_DuplicateObj(objv[thisarg]);
+        if (!name) name = Tcl_GetStringFromObj(newObj,NULL);
+      } else {
+        Tcl_SetResult(interp, (char *) "wrong # args.", TCL_STATIC);
+        return TCL_ERROR;
+      }
+    } else {
+      Tcl_SetResult(interp, (char *) "No constructor available.", TCL_STATIC);
+      return TCL_ERROR;
+    }
+    if (SWIG_Tcl_ConvertPtr(interp,newObj, (void **) &thisvalue, *(classptr->type), SWIG_POINTER_EXCEPTION) == TCL_ERROR) {
+      Tcl_DecrRefCount(newObj);
+      return TCL_ERROR;
+    }
+    newinst = (swig_instance *) malloc(sizeof(swig_instance));
+    newinst->thisptr = newObj;
+    Tcl_IncrRefCount(newObj);
+    newinst->thisvalue = thisvalue;
+    newinst->classptr = classptr;
+    newinst->destroy = destroy;
+    if (destroy) {
+      SWIG_Acquire(thisvalue);
+    }
+    newinst->cmdtok = Tcl_CreateObjCommand(interp,name, (swig_wrapper) SWIG_MethodCommand, (ClientData) newinst, (swig_delete_func) SWIG_ObjectDelete);
+    return TCL_OK;
+}
+
+
+/* This function takes the current result and turns it into an object command */
+SWIGRUNTIME(Tcl_Obj *)
+SWIG_Tcl_NewInstanceObj(Tcl_Interp *interp, void *thisvalue, swig_type_info *type, int flags) {
+  Tcl_Obj *robj = SWIG_NewPointerObj(thisvalue, type,0);
+  /* Check to see if this pointer belongs to a class or not */
+  if ((type->clientdata) && (interp)) {
+    Tcl_CmdInfo    ci;
+    char          *name;
+    name = Tcl_GetStringFromObj(robj,NULL);
+    if (!Tcl_GetCommandInfo(interp,name, &ci) || (flags)) {
+      swig_instance *newinst = (swig_instance *) malloc(sizeof(swig_instance));
+      newinst->thisptr = Tcl_DuplicateObj(robj);
+      Tcl_IncrRefCount(newinst->thisptr);
+      newinst->thisvalue = thisvalue;
+      newinst->classptr = (swig_class *) type->clientdata;
+      newinst->destroy = flags;
+      newinst->cmdtok = Tcl_CreateObjCommand(interp, Tcl_GetStringFromObj(robj,NULL), (swig_wrapper_func) SWIG_MethodCommand, (ClientData) newinst, (swig_delete_func) SWIG_ObjectDelete);
+      if (flags) {
+        SWIG_Acquire(thisvalue);
+      }
+    }
+  }
+  return robj;
+}
+
+#endif
+
+/* Structure for command table */
+typedef struct {
+  const char *name;
+  int       (*wrapper)(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
+  ClientData  clientdata;
+} swig_command_info;
+
+/* Structure for variable linking table */
+typedef struct {
+  const char *name;
+  void *addr;
+  char * (*get)(ClientData, Tcl_Interp *, char *, char *, int);
+  char * (*set)(ClientData, Tcl_Interp *, char *, char *, int);
+} swig_var_info;
+
+
+/* Contract support */
+
+#define SWIG_contract_assert(expr, msg)  if (!(expr)) { Tcl_SetResult(interp, (char *) msg, TCL_STATIC ); goto fail; } else
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define  SWIGTYPE_p_p_char swig_types[0] 
+#define  SWIGTYPE_p_p_p_char swig_types[1] 
+#define  SWIGTYPE_p_iter_t swig_types[2] 
+#define  SWIGTYPE_iter_t swig_types[3] 
+#define  SWIGTYPE_p_profile_t swig_types[4] 
+#define  SWIGTYPE_profile_t swig_types[5] 
+#define  SWIGTYPE_p_int swig_types[6] 
+static swig_type_info *swig_types[8];
+
+/* -------- TYPES TABLE (END) -------- */
+
+#define SWIG_init    Profile_Init
+#define SWIG_name    "profile"
+#define SWIG_prefix  ""
+#define SWIG_version "0.0"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef MAC_TCL
+#pragma export on
+#endif
+SWIGEXPORT(int) SWIG_init(Tcl_Interp *);
+#ifdef MAC_TCL
+#pragma export off
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/*
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Input for wrapper generator program SWIG for profile routines.
+ */
+#include <errno.h>
+#include "com_err.h"
+#include "profile.h"
+
+#ifdef SWIGTCL
+/* Reduce warnings about cast discarding const to just this one, from
+   every SWIG-generated call to Tcl_SetResult.  */
+static void my_tcl_setresult(Tcl_Interp *i, const char *str, Tcl_FreeProc *f)
+{
+    Tcl_SetResult(i, (char *) str, f);
+}
+#undef Tcl_SetResult
+#define Tcl_SetResult my_tcl_setresult
+#endif
+
+
+typedef void **iter_t; /* ick */
+
+extern errcode_t profile_get_string(profile_t,char const *,char const *,char const *,char const *,char **);
+
+static errcode_t iter_create(profile_t p, const char **nullterm,
+			     int flags, iter_t *OUTPUT)
+{
+    iter_t it;
+    errcode_t err;
+    char **args;
+
+    it = malloc(sizeof(*it));
+    if (it == NULL)
+	return errno;
+    {
+	/* Memory leak!
+
+	   The profile code seems to assume that I'll keep the string
+	   array around for as long as the iterator is valid; I can't
+	   create the iterator and then throw them away.
+
+	   But right now, I can't be bothered to track the necessary
+	   information to do the cleanup later.  */
+	int count, j;
+	for (count = 0; nullterm[count]; count++) ;
+	args = calloc(count+1, sizeof(char *));
+	if (args == NULL)
+	    return errno;
+	for (j = 0; j < count; j++) {
+	    args[j] = strdup(nullterm[j]);
+	    if (args[j] == NULL)
+		return errno;
+	}
+	args[j] = NULL;
+    }
+    err = profile_iterator_create(p, args, flags, it);
+    if (err)
+	free(it);
+    else
+	*OUTPUT = it;
+    return err;
+}
+static errcode_t iter_free(iter_t i)
+{
+    profile_iterator_free(i);
+    free(i);
+}
+
+
+
+/* A TCL_AppInit() function that lets you build a new copy
+ * of tclsh.
+ *
+ * The macro SWIG_init contains the name of the initialization
+ * function in the wrapper file.
+ */
+
+#ifndef SWIG_RcFileName
+char *SWIG_RcFileName = "~/.myapprc";
+#endif
+
+
+#ifdef MAC_TCL
+extern int		MacintoshInit _ANSI_ARGS_((void));
+#endif
+
+int Tcl_AppInit(Tcl_Interp *interp){
+
+  if (Tcl_Init(interp) == TCL_ERROR) 
+    return TCL_ERROR;
+
+  /* Now initialize our functions */
+
+  if (SWIG_init(interp) == TCL_ERROR)
+    return TCL_ERROR;
+#if TCL_MAJOR_VERSION > 7 || TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION >= 5
+   Tcl_SetVar(interp, (char *) "tcl_rcFileName",SWIG_RcFileName,TCL_GLOBAL_ONLY);
+#else
+   tcl_RcFileName = SWIG_RcFileName;
+#endif
+#ifdef SWIG_RcRsrcName
+  Tcl_SetVar(interp, (char *) "tcl_rcRsrcName",SWIG_RcRsrcName,TCL_GLOBAL);
+#endif
+  
+  return TCL_OK;
+}
+
+#if TCL_MAJOR_VERSION > 7 || TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION >= 4
+int main(int argc, char **argv) {
+#ifdef MAC_TCL
+    char *newArgv[2];
+    
+    if (MacintoshInit()  != TCL_OK) {
+	Tcl_Exit(1);
+    }
+
+    argc = 1;
+    newArgv[0] = "tclsh";
+    newArgv[1] = NULL;
+    argv = newArgv;
+#endif
+
+  Tcl_Main(argc, argv, Tcl_AppInit);
+  return(0);
+
+}
+#else
+extern int main();
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+static int
+_wrap_profile_init_path(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    char *arg1 = (char *) NULL ;
+    profile_t *arg2 = (profile_t *) 0 ;
+    errcode_t result;
+    profile_t tmp2 ;
+    
+    {
+        /*generic swigtype hack*/ arg2 = &tmp2;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"|s:profile_init_path ?path? ",&arg1) == TCL_ERROR) SWIG_fail;
+    result = (errcode_t)profile_init_path((char const *)arg1,arg2);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    /*generic swigtype hack*/ Tcl_SetObjResult(interp,SWIG_NewInstanceObj((void *) *arg2, SWIGTYPE_profile_t,0));
+    return TCL_OK;
+    fail:
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_init(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    char **arg1 = (char **) NULL ;
+    profile_t *arg2 = (profile_t *) 0 ;
+    errcode_t result;
+    profile_t tmp2 ;
+    
+    {
+        /*generic swigtype hack*/ arg2 = &tmp2;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"|o:profile_init ?nullterm? ",0) == TCL_ERROR) SWIG_fail;
+    if (objc > 1) {
+        {
+            /* in char **nullterm */
+            int n;
+            if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[1],NULL), &n, &arg1) == TCL_ERROR) SWIG_fail;
+        }
+    }
+    result = (errcode_t)profile_init((char const **)arg1,arg2);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    /*generic swigtype hack*/ Tcl_SetObjResult(interp,SWIG_NewInstanceObj((void *) *arg2, SWIGTYPE_profile_t,0));
+    {
+        /* freearg char **nullterm */
+        if (arg1) {
+            Tcl_Free((char *)arg1); arg1 = (char **) NULL; 
+        }
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg1) {
+            Tcl_Free((char *)arg1); arg1 = (char **) NULL; 
+        }
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_flush(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    errcode_t result;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"o:profile_flush profile_t ",0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    result = (errcode_t)profile_flush(arg1);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    return TCL_OK;
+    fail:
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_flush_to_file(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char *arg2 ;
+    errcode_t result;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"os:profile_flush_to_file profile_t path ",0,&arg2) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    result = (errcode_t)profile_flush_to_file(arg1,(char const *)arg2);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    return TCL_OK;
+    fail:
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_abandon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"o:profile_abandon profile_t ",0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    profile_abandon(arg1);
+    
+    
+    return TCL_OK;
+    fail:
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_release(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"o:profile_release profile_t ",0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    profile_release(arg1);
+    
+    
+    return TCL_OK;
+    fail:
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_get_values(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    char ***arg3 = (char ***) 0 ;
+    errcode_t result;
+    char **tmp3 ;
+    
+    {
+        /* in char ***OUTPUT */
+        tmp3 = NULL;
+        arg3 = &tmp3;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"oo:profile_get_values p nullterm ",0,0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    {
+        /* in char **nullterm */
+        int n;
+        if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[2],NULL), &n, &arg2) == TCL_ERROR) SWIG_fail;
+    }
+    result = (errcode_t)profile_get_values(arg1,(char const **)arg2,arg3);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* argout char ***OUTPUT */
+        int i;
+        for (i = 0; (*arg3)[i]; i++)
+        Tcl_AppendElement(interp, (*arg3)[i]);
+    }
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    {
+        /* freearg char ***OUTPUT */
+        profile_free_list(*arg3);
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    {
+        /* freearg char ***OUTPUT */
+        profile_free_list(*arg3);
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_get_string(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char *arg2 ;
+    char *arg3 ;
+    char *arg4 = (char *) NULL ;
+    char *arg5 = (char *) NULL ;
+    char **arg6 = (char **) 0 ;
+    errcode_t result;
+    char *tmp6 ;
+    
+    {
+        /* in char **OUTPUT */
+        tmp6 = NULL;
+        arg6 = &tmp6;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"oss|ss:profile_get_string p name subname ?subsubname? ?defval? ",0,&arg2,&arg3,&arg4,&arg5) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    result = (errcode_t)profile_get_string(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4,(char const *)arg5,arg6);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* argout char **OUTPUT */
+        /*    Tcl_SetResult(interp, *arg6, TCL_DYNAMIC); */
+        char *s = (arg6 && *arg6) ? *arg6 : "";
+        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
+        Tcl_NewStringObj(s, strlen(s)));
+    }
+    {
+        /* There may be a memory leak here.  Investigate later, if anyone
+               cares.  */
+        /*    profile_release_string(*arg6); */
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* There may be a memory leak here.  Investigate later, if anyone
+               cares.  */
+        /*    profile_release_string(*arg6); */
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_get_integer(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char *arg2 ;
+    char *arg3 ;
+    char *arg4 = (char *) NULL ;
+    int arg5 = (int) 0 ;
+    int *arg6 = (int *) 0 ;
+    errcode_t result;
+    int temp6 ;
+    
+    arg6 = &temp6;
+    if (SWIG_GetArgs(interp, objc, objv,"oss|si:profile_get_integer p name subname ?subsubname? ?defval? ",0,&arg2,&arg3,&arg4,&arg5) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    result = (errcode_t)profile_get_integer(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4,arg5,arg6);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        Tcl_Obj *o;
+        o = Tcl_NewIntObj((int) *(arg6));
+        Tcl_ListObjAppendElement(interp,Tcl_GetObjResult(interp),o);
+    }
+    return TCL_OK;
+    fail:
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_get_boolean(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char *arg2 ;
+    char *arg3 ;
+    char *arg4 = (char *) NULL ;
+    int arg5 = (int) 0 ;
+    int *arg6 = (int *) 0 ;
+    errcode_t result;
+    int temp6 ;
+    
+    arg6 = &temp6;
+    if (SWIG_GetArgs(interp, objc, objv,"oss|si:profile_get_boolean p name subname ?subsubname? ?defval? ",0,&arg2,&arg3,&arg4,&arg5) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    result = (errcode_t)profile_get_boolean(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4,arg5,arg6);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        Tcl_Obj *o;
+        o = Tcl_NewIntObj((int) *(arg6));
+        Tcl_ListObjAppendElement(interp,Tcl_GetObjResult(interp),o);
+    }
+    return TCL_OK;
+    fail:
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_get_relation_names(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    char ***arg3 = (char ***) 0 ;
+    errcode_t result;
+    char **tmp3 ;
+    
+    {
+        /* in char ***OUTPUT */
+        tmp3 = NULL;
+        arg3 = &tmp3;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"oo:profile_get_relation_names p nullterm ",0,0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    {
+        /* in char **nullterm */
+        int n;
+        if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[2],NULL), &n, &arg2) == TCL_ERROR) SWIG_fail;
+    }
+    result = (errcode_t)profile_get_relation_names(arg1,(char const **)arg2,arg3);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* argout char ***OUTPUT */
+        int i;
+        for (i = 0; (*arg3)[i]; i++)
+        Tcl_AppendElement(interp, (*arg3)[i]);
+    }
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    {
+        /* freearg char ***OUTPUT */
+        profile_free_list(*arg3);
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    {
+        /* freearg char ***OUTPUT */
+        profile_free_list(*arg3);
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_get_subsection_names(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    char ***arg3 = (char ***) 0 ;
+    errcode_t result;
+    char **tmp3 ;
+    
+    {
+        /* in char ***OUTPUT */
+        tmp3 = NULL;
+        arg3 = &tmp3;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"oo:profile_get_subsection_names p nullterm ",0,0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    {
+        /* in char **nullterm */
+        int n;
+        if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[2],NULL), &n, &arg2) == TCL_ERROR) SWIG_fail;
+    }
+    result = (errcode_t)profile_get_subsection_names(arg1,(char const **)arg2,arg3);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* argout char ***OUTPUT */
+        int i;
+        for (i = 0; (*arg3)[i]; i++)
+        Tcl_AppendElement(interp, (*arg3)[i]);
+    }
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    {
+        /* freearg char ***OUTPUT */
+        profile_free_list(*arg3);
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    {
+        /* freearg char ***OUTPUT */
+        profile_free_list(*arg3);
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_iterator_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    int arg3 ;
+    iter_t *arg4 = (iter_t *) 0 ;
+    errcode_t result;
+    iter_t tmp4 ;
+    
+    {
+        /*generic swigtype hack*/ arg4 = &tmp4;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"ooi:profile_iterator_create p nullterm flags ",0,0,&arg3) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    {
+        /* in char **nullterm */
+        int n;
+        if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[2],NULL), &n, &arg2) == TCL_ERROR) SWIG_fail;
+    }
+    result = (errcode_t)iter_create(arg1,(char const **)arg2,arg3,arg4);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    /*generic swigtype hack*/ Tcl_SetObjResult(interp,SWIG_NewInstanceObj((void *) *arg4, SWIGTYPE_iter_t,0));
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_iterator_free(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    iter_t arg1 = (iter_t) 0 ;
+    errcode_t result;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"o:profile_iterator_free i ",0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_iter_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    result = (errcode_t)iter_free(arg1);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    return TCL_OK;
+    fail:
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_iterator(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    iter_t arg1 = (iter_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    char **arg3 = (char **) 0 ;
+    errcode_t result;
+    char *tmp2 ;
+    char *tmp3 ;
+    
+    {
+        /* in char **OUTPUT */
+        tmp2 = NULL;
+        arg2 = &tmp2;
+    }
+    {
+        /* in char **OUTPUT */
+        tmp3 = NULL;
+        arg3 = &tmp3;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"o:profile_iterator iter_t ",0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_iter_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    result = (errcode_t)profile_iterator(arg1,arg2,arg3);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* argout char **OUTPUT */
+        /*    Tcl_SetResult(interp, *arg2, TCL_DYNAMIC); */
+        char *s = (arg2 && *arg2) ? *arg2 : "";
+        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
+        Tcl_NewStringObj(s, strlen(s)));
+    }
+    {
+        /* argout char **OUTPUT */
+        /*    Tcl_SetResult(interp, *arg3, TCL_DYNAMIC); */
+        char *s = (arg3 && *arg3) ? *arg3 : "";
+        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
+        Tcl_NewStringObj(s, strlen(s)));
+    }
+    {
+        /* There may be a memory leak here.  Investigate later, if anyone
+               cares.  */
+        /*    profile_release_string(*arg2); */
+    }
+    {
+        /* There may be a memory leak here.  Investigate later, if anyone
+               cares.  */
+        /*    profile_release_string(*arg3); */
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* There may be a memory leak here.  Investigate later, if anyone
+               cares.  */
+        /*    profile_release_string(*arg2); */
+    }
+    {
+        /* There may be a memory leak here.  Investigate later, if anyone
+               cares.  */
+        /*    profile_release_string(*arg3); */
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_update_relation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    char *arg3 ;
+    char *arg4 = (char *) NULL ;
+    errcode_t result;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"oos|s:profile_update_relation p nullterm oldval ?newval? ",0,0,&arg3,&arg4) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    {
+        /* in char **nullterm */
+        int n;
+        if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[2],NULL), &n, &arg2) == TCL_ERROR) SWIG_fail;
+    }
+    result = (errcode_t)profile_update_relation(arg1,(char const **)arg2,(char const *)arg3,(char const *)arg4);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_clear_relation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    errcode_t result;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"oo:profile_clear_relation p nullterm ",0,0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    {
+        /* in char **nullterm */
+        int n;
+        if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[2],NULL), &n, &arg2) == TCL_ERROR) SWIG_fail;
+    }
+    result = (errcode_t)profile_clear_relation(arg1,(char const **)arg2);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_rename_section(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    char *arg3 = (char *) NULL ;
+    errcode_t result;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"oo|s:profile_rename_section p nullterm ?new_name? ",0,0,&arg3) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    {
+        /* in char **nullterm */
+        int n;
+        if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[2],NULL), &n, &arg2) == TCL_ERROR) SWIG_fail;
+    }
+    result = (errcode_t)profile_rename_section(arg1,(char const **)arg2,(char const *)arg3);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_add_relation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    char *arg3 = (char *) NULL ;
+    errcode_t result;
+    
+    if (SWIG_GetArgs(interp, objc, objv,"oo|s:profile_add_relation p nullterm ?new_val? ",0,0,&arg3) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    {
+        /* in char **nullterm */
+        int n;
+        if (Tcl_SplitList(interp, Tcl_GetStringFromObj(objv[2],NULL), &n, &arg2) == TCL_ERROR) SWIG_fail;
+    }
+    result = (errcode_t)profile_add_relation(arg1,(char const **)arg2,(char const *)arg3);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* freearg char **nullterm */
+        if (arg2) {
+            Tcl_Free((char *)arg2); arg2 = (char **) NULL; 
+        }
+    }
+    return TCL_ERROR;
+}
+
+
+static int
+_wrap_profile_flush_to_buffer(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    profile_t arg1 = (profile_t) 0 ;
+    char **arg2 = (char **) 0 ;
+    errcode_t result;
+    char *tmp2 ;
+    
+    {
+        /* in char **OUTPUT */
+        tmp2 = NULL;
+        arg2 = &tmp2;
+    }
+    if (SWIG_GetArgs(interp, objc, objv,"o:profile_flush_to_buffer p ",0) == TCL_ERROR) SWIG_fail;
+    if ((SWIG_ConvertPtr(objv[1], (void **) &arg1, SWIGTYPE_profile_t,SWIG_POINTER_EXCEPTION | 0) != TCL_OK)) SWIG_fail;
+    result = (errcode_t)profile_flush_to_buffer(arg1,arg2);
+    
+    {
+        /* out errcode_t result */
+        if (result) {
+            /* There could be a memory leak here in the SWIG-Tcl layer,
+            	   I'm not sure.  Not going to worry about it though.  */
+            Tcl_SetResult(interp, (char *) error_message(result), TCL_STATIC);
+            SWIG_fail;
+        }
+    }
+    {
+        /* argout char **OUTPUT */
+        /*    Tcl_SetResult(interp, *arg2, TCL_DYNAMIC); */
+        char *s = (arg2 && *arg2) ? *arg2 : "";
+        Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
+        Tcl_NewStringObj(s, strlen(s)));
+    }
+    {
+        /* There may be a memory leak here.  Investigate later, if anyone
+               cares.  */
+        /*    profile_release_string(*arg2); */
+    }
+    return TCL_OK;
+    fail:
+    {
+        /* There may be a memory leak here.  Investigate later, if anyone
+               cares.  */
+        /*    profile_release_string(*arg2); */
+    }
+    return TCL_ERROR;
+}
+
+
+
+static swig_command_info swig_commands[] = {
+    { SWIG_prefix "profile_init_path", (swig_wrapper_func) _wrap_profile_init_path, NULL},
+    { SWIG_prefix "profile_init", (swig_wrapper_func) _wrap_profile_init, NULL},
+    { SWIG_prefix "profile_flush", (swig_wrapper_func) _wrap_profile_flush, NULL},
+    { SWIG_prefix "profile_flush_to_file", (swig_wrapper_func) _wrap_profile_flush_to_file, NULL},
+    { SWIG_prefix "profile_abandon", (swig_wrapper_func) _wrap_profile_abandon, NULL},
+    { SWIG_prefix "profile_release", (swig_wrapper_func) _wrap_profile_release, NULL},
+    { SWIG_prefix "profile_get_values", (swig_wrapper_func) _wrap_profile_get_values, NULL},
+    { SWIG_prefix "profile_get_string", (swig_wrapper_func) _wrap_profile_get_string, NULL},
+    { SWIG_prefix "profile_get_integer", (swig_wrapper_func) _wrap_profile_get_integer, NULL},
+    { SWIG_prefix "profile_get_boolean", (swig_wrapper_func) _wrap_profile_get_boolean, NULL},
+    { SWIG_prefix "profile_get_relation_names", (swig_wrapper_func) _wrap_profile_get_relation_names, NULL},
+    { SWIG_prefix "profile_get_subsection_names", (swig_wrapper_func) _wrap_profile_get_subsection_names, NULL},
+    { SWIG_prefix "profile_iterator_create", (swig_wrapper_func) _wrap_profile_iterator_create, NULL},
+    { SWIG_prefix "profile_iterator_free", (swig_wrapper_func) _wrap_profile_iterator_free, NULL},
+    { SWIG_prefix "profile_iterator", (swig_wrapper_func) _wrap_profile_iterator, NULL},
+    { SWIG_prefix "profile_update_relation", (swig_wrapper_func) _wrap_profile_update_relation, NULL},
+    { SWIG_prefix "profile_clear_relation", (swig_wrapper_func) _wrap_profile_clear_relation, NULL},
+    { SWIG_prefix "profile_rename_section", (swig_wrapper_func) _wrap_profile_rename_section, NULL},
+    { SWIG_prefix "profile_add_relation", (swig_wrapper_func) _wrap_profile_add_relation, NULL},
+    { SWIG_prefix "profile_flush_to_buffer", (swig_wrapper_func) _wrap_profile_flush_to_buffer, NULL},
+    {0, 0, 0}
+};
+
+static swig_var_info swig_variables[] = {
+    {0,0,0,0}
+};
+
+static swig_const_info swig_constants[] = {
+    {0,0,0,0,0,0}
+};
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_p_char[] = {{"_p_p_char", 0, "char **", 0},{"_p_p_char"},{0}};
+static swig_type_info _swigt__p_p_p_char[] = {{"_p_p_p_char", 0, "char ***", 0},{"_p_p_p_char"},{0}};
+static swig_type_info _swigt__p_iter_t[] = {{"_p_iter_t", 0, "iter_t *", 0},{"_p_iter_t"},{0}};
+static swig_type_info _swigt__iter_t[] = {{"_iter_t", 0, "iter_t", 0},{"_iter_t"},{0}};
+static swig_type_info _swigt__p_profile_t[] = {{"_p_profile_t", 0, "profile_t *", 0},{"_p_profile_t"},{0}};
+static swig_type_info _swigt__profile_t[] = {{"_profile_t", 0, "profile_t", 0},{"_profile_t"},{0}};
+static swig_type_info _swigt__p_int[] = {{"_p_int", 0, "int *", 0},{"_p_int"},{0}};
+
+static swig_type_info *swig_types_initial[] = {
+_swigt__p_p_char, 
+_swigt__p_p_p_char, 
+_swigt__p_iter_t, 
+_swigt__iter_t, 
+_swigt__p_profile_t, 
+_swigt__profile_t, 
+_swigt__p_int, 
+0
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+#ifdef __cplusplus
+}
+#endif
+
+SWIGEXPORT(int) SWIG_init(Tcl_Interp *interp) {
+    int i;
+    static int _init = 0;
+    if (interp == 0) return TCL_ERROR;
+#ifdef USE_TCL_STUBS
+    if (Tcl_InitStubs(interp, (char*)"8.1", 0) == NULL) {
+        return TCL_ERROR;
+    }
+#endif
+    
+    Tcl_PkgProvide(interp, (char*)SWIG_name, (char*)SWIG_version);
+    
+#ifdef SWIG_namespace
+    Tcl_Eval(interp, "namespace eval " SWIG_namespace " { }");
+#endif
+    if (!_init) {
+        for (i = 0; swig_types_initial[i]; i++) {
+            swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]);
+        }
+        _init = 1;
+    }
+    for (i = 0; swig_commands[i].name; i++) {
+        Tcl_CreateObjCommand(interp, (char *) swig_commands[i].name, (swig_wrapper_func) swig_commands[i].wrapper, swig_commands[i].clientdata, NULL);
+    }
+    for (i = 0; swig_variables[i].name; i++) {
+        Tcl_SetVar(interp, (char *) swig_variables[i].name, (char *) "", TCL_GLOBAL_ONLY);
+        Tcl_TraceVar(interp, (char *) swig_variables[i].name, TCL_TRACE_READS | TCL_GLOBAL_ONLY, (Tcl_VarTraceProc *) swig_variables[i].get, (ClientData) swig_variables[i].addr);
+        Tcl_TraceVar(interp, (char *) swig_variables[i].name, TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, (Tcl_VarTraceProc *) swig_variables[i].set, (ClientData) swig_variables[i].addr);
+    }
+    SWIG_InstallConstants(interp, swig_constants);
+    
+    return TCL_OK;
+}
+SWIGEXPORT(int) Profile_SafeInit(Tcl_Interp *interp) {
+    return SWIG_init(interp);
+}
+
diff --git a/mechglue/src/util/profile/prtest.in b/mechglue/src/util/profile/prtest.in
new file mode 100644
index 000000000..ef3efb308
--- /dev/null
+++ b/mechglue/src/util/profile/prtest.in
@@ -0,0 +1,36 @@
+#!/bin/sh
+SRCDIR=@srcdir@
+SCRIPT=$SRCDIR/prtest.script
+REPORT=prtest.report
+TESTPROG=./test_profile
+
+rm -f $REPORT
+
+if test -f $SCRIPT ; then 
+	: 
+else
+	echo "$SCRIPT not found!"
+	exit 1
+fi
+
+grep -v ^\# < $SCRIPT | while read filespec cmd args
+do
+	case $filespec in
+	krb5)
+		file=$SRCDIR/krb5.conf
+		;;
+	test)
+		file=$SRCDIR/test.ini
+		;;
+	*)
+		echo "Unknown file specifer $file!"
+		exit 1
+		;;
+	esac
+	if test $cmd = parse ; then
+	    echo \# test_parse $filespec   >> $REPORT 2>&1
+	    $TESTPARSE $file >> $REPORT    >> $REPORT 2>&1
+	fi
+	echo \# $filespec $cmd $args  >> $REPORT 2>&1
+	$TESTPROG $file $cmd $args    >> $REPORT 2>&1 
+done 
diff --git a/mechglue/src/util/profile/prtest.script b/mechglue/src/util/profile/prtest.script
new file mode 100644
index 000000000..5d5a14422
--- /dev/null
+++ b/mechglue/src/util/profile/prtest.script
@@ -0,0 +1,11 @@
+krb5 query realms ATHENA.MIT.EDU kdc
+krb5 query1 realms ATHENA.MIT.EDU kdc
+krb5 query libdefaults ticket_lifetime
+krb5 query1 libdefaults ticket_lifetime
+krb5 query libdefaults not_present
+krb5 query1 libdefaults not_present
+krb5 list_sections libdefaults
+krb5 list_sections realms
+krb5 list_relations libdefaults
+krb5 list_relations realms
+krb5 list_relations realms ATHENA.MIT.EDU
diff --git a/mechglue/src/util/profile/test.ini b/mechglue/src/util/profile/test.ini
new file mode 100644
index 000000000..c1c8830aa
--- /dev/null
+++ b/mechglue/src/util/profile/test.ini
@@ -0,0 +1,47 @@
+this is a comment.  Everything up to the first square brace is ignored.
+
+[test section 2]
+	test_child = "foo\nbar"
+	child_section2 = "one"
+	child_section2 = {
+		child = slick
+		child = harry
+		child = "john\tb "
+	}
+	child_section2 = foo
+
+[realms]
+ATHENA.MIT.EDU = {
+	server = KERBEROS.MIT.EDU:88
+	server = KERBEROS1.MIT.EDU:750
+	server = KERBEROS2.MIT.EDU:750
+	admin = KERBEROS.MIT.EDU
+	etype = DES-MD5
+}
+	
+
+
+[test section 1]
+    foo = "bar "
+
+[test section 2]
+	quux = "bar"
+	frep = bar
+	kappa = alpha
+	beta = epsilon
+
+[test section 1]
+    bar = foo
+	foo = bar2
+    quux = zap
+	foo = bar3
+	child_section = {
+		child = slick
+		child = harry
+		child = john
+	}
+	child_section = foo
+
+
+
+
diff --git a/mechglue/src/util/profile/test_parse.c b/mechglue/src/util/profile/test_parse.c
new file mode 100644
index 000000000..961149c80
--- /dev/null
+++ b/mechglue/src/util/profile/test_parse.c
@@ -0,0 +1,54 @@
+#include "prof_int.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#include <ctype.h>
+
+void dump_profile (struct profile_node *root, int level);
+
+int main(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	struct profile_node *root;
+	unsigned long retval;
+	FILE *f;
+
+	initialize_prof_error_table();
+	if (argc != 2) {
+		fprintf(stderr, "%s: Usage <filename>\n", argv[0]);
+		exit(1);
+	}
+
+	f = fopen(argv[1], "r");
+	if (!f) {
+		perror(argv[1]);
+		exit(1);
+	}
+
+	retval = profile_parse_file(f, &root);
+	if (retval) {
+		printf("profile_parse_file error %s\n", 
+		       error_message((errcode_t) retval));
+		exit(1);
+	}
+	fclose(f);
+	
+	printf("\n\nDebugging dump.\n");
+	profile_write_tree_file(root, stdout);
+	
+	retval = profile_verify_node(root);
+	if (retval) {
+		printf("profile_verify_node reported an error: %s\n",
+		       error_message((errcode_t) retval));
+		exit(1);
+	}
+
+	profile_free_node(root);
+
+	return 0;
+}
diff --git a/mechglue/src/util/profile/test_profile.c b/mechglue/src/util/profile/test_profile.c
new file mode 100644
index 000000000..5cdbf7689
--- /dev/null
+++ b/mechglue/src/util/profile/test_profile.c
@@ -0,0 +1,169 @@
+/*
+ * test_profile.c --- testing program for the profile routine
+ */
+
+#include "prof_int.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "argv_parse.h"
+#include "com_err.h"
+
+const char *program_name = "test_profile";
+
+#define PRINT_VALUE	1
+#define PRINT_VALUES	2
+
+static void do_batchmode(profile)
+	profile_t	profile;
+{
+	errcode_t	retval;
+	int		argc, ret;
+	char		**argv, **values, **cpp;
+	char		buf[256];
+	const char	**names, *value;
+	char		*cmd;
+	int		print_status;
+
+	while (!feof(stdin)) {
+		if (fgets(buf, sizeof(buf), stdin) == NULL)
+			break;
+		printf(">%s", buf);
+		ret = argv_parse(buf, &argc, &argv);
+		if (ret != 0) {
+			printf("Argv_parse returned %d!\n", ret);
+			continue;
+		}
+		cmd = *(argv);
+		names = (const char **) argv + 1;
+		print_status = 0;
+		retval = 0;
+		if (cmd == 0) {
+			argv_free(argv);
+			continue;
+		}
+		if (!strcmp(cmd, "query")) {
+			retval = profile_get_values(profile, names, &values);
+			print_status = PRINT_VALUES;
+		} else if (!strcmp(cmd, "query1")) {
+			retval = profile_get_value(profile, names, &value);
+			print_status = PRINT_VALUE;
+		} else if (!strcmp(cmd, "list_sections")) {
+			retval = profile_get_subsection_names(profile, names, 
+							      &values);
+			print_status = PRINT_VALUES;
+		} else if (!strcmp(cmd, "list_relations")) {
+			retval = profile_get_relation_names(profile, names, 
+							    &values);
+			print_status = PRINT_VALUES;
+		} else if (!strcmp(cmd, "dump")) {
+			retval = profile_write_tree_file
+				(profile->first_file->data->root, stdout);
+		} else if (!strcmp(cmd, "clear")) {
+			retval = profile_clear_relation(profile, names);
+		} else if (!strcmp(cmd, "update")) {
+			retval = profile_update_relation(profile, names+2,
+							 *names, *(names+1));
+		} else if (!strcmp(cmd, "verify")) {
+			retval = profile_verify_node
+				(profile->first_file->data->root);
+		} else if (!strcmp(cmd, "rename_section")) {
+			retval = profile_rename_section(profile, names+1,
+							*names);
+		} else if (!strcmp(cmd, "add")) {
+			value = *names;
+			if (strcmp(value, "NULL") == 0)
+				value = NULL;
+			retval = profile_add_relation(profile, names+1,
+						      value);
+		} else if (!strcmp(cmd, "flush")) {
+			retval = profile_flush(profile);
+		} else {
+			printf("Invalid command.\n");
+		}
+		if (retval) {
+			com_err(cmd, retval, "");
+			print_status = 0;
+		}
+		switch (print_status) {
+		case PRINT_VALUE:
+			printf("%s\n", value);
+			break;
+		case PRINT_VALUES:
+			for (cpp = values; *cpp; cpp++)
+				printf("%s\n", *cpp);
+			profile_free_list(values);
+			break;
+		}
+		printf("\n");
+		argv_free(argv);
+	}
+	profile_release(profile);
+	exit(0);
+	
+}
+
+
+int main(argc, argv)
+    int		argc;
+    char	**argv;
+{
+    profile_t	profile;
+    long	retval;
+    char	**values, **cpp;
+    const char	*value;
+    const char	**names;
+    char	*cmd;
+    int		print_value = 0;
+    
+    if (argc < 2) {
+	    fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name);
+	    exit(1);
+    }
+
+    initialize_prof_error_table();
+    
+    retval = profile_init_path(argv[1], &profile);
+    if (retval) {
+	com_err(program_name, retval, "while initializing profile");
+	exit(1);
+    }
+    cmd = *(argv+2);
+    names = (const char **) argv+3;
+    if (!cmd || !strcmp(cmd, "batch"))
+	    do_batchmode(profile);
+    if (!strcmp(cmd, "query")) {
+	    retval = profile_get_values(profile, names, &values);
+    } else if (!strcmp(cmd, "query1")) {
+	    retval = profile_get_value(profile, names, &value);
+	    print_value++;
+    } else if (!strcmp(cmd, "list_sections")) {
+	    retval = profile_get_subsection_names(profile, names, &values);
+    } else if (!strcmp(cmd, "list_relations")) {
+	    retval = profile_get_relation_names(profile, names, &values);
+    } else {
+	    fprintf(stderr, "Invalid command.\n");
+	    exit(1);
+    }
+    if (retval) {
+	    com_err(argv[0], retval, "while getting values");
+	    profile_release(profile);
+	    exit(1);
+    }
+    if (print_value) {
+	    printf("%s\n", value);
+    } else {
+	    for (cpp = values; *cpp; cpp++)
+		    printf("%s\n", *cpp);
+	    profile_free_list(values);
+    }
+    profile_release(profile);
+
+    return 0;
+}
+    
+    
diff --git a/mechglue/src/util/pty/.Sanitize b/mechglue/src/util/pty/.Sanitize
new file mode 100644
index 000000000..d1b4efbe3
--- /dev/null
+++ b/mechglue/src/util/pty/.Sanitize
@@ -0,0 +1,52 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+README
+Makefile.in
+configure.in
+configure
+cleanup.c
+dump-utmp.c
+getpty.c
+init_slave.c
+libpty.h
+init.c
+logwtmp.c
+open_ctty.c
+open_slave.c
+pty-int.h
+pty_err.et
+update_utmp.c
+update_wtmp.c
+vhangup.c
+void_assoc.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/util/pty/ChangeLog b/mechglue/src/util/pty/ChangeLog
new file mode 100644
index 000000000..77868b199
--- /dev/null
+++ b/mechglue/src/util/pty/ChangeLog
@@ -0,0 +1,934 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2004-09-22  Tom Yu  <tlyu@mit.edu>
+
+	* pty-int.h: Include util.h if present.
+
+2004-07-30  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Only sanity-check setutent() API if there is no
+	utmpx.h, since some setutent() implementations aren't sysV-derived,
+	e.g., NetBSD.
+
+2004-07-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* pty-int.h: Include port-sockets.h instead of netdb.h and
+	netinet/in.h.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (clean-mac): Target deleted.
+
+2004-06-11  Ken Raeburn  <raeburn@mit.edu>
+
+	* pty-int.h (_AIX && _THREAD_SAFE): Undefine _THREAD_SAFE.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-04-12  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Remove tests for strsave, sys_errlist,
+	krb5_sigtype, setjmp, dirent, F_SETOWN. These are left over from
+	the split from appl/bsd.
+
+2004-02-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* cleanup.c, init.c, init_slave.c, vhangup.c: Use ANSI style
+	function definitions.
+
+2003-03-03  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Delete unused ADD_DEF, probably left over from
+	appl/bsd.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_INSTALL,
+	AC_PROG_ARCHIVE, AC_PROG_RANLIB.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2002-12-06  Ezra Peisach  <epeisach@bu.edu>
+
+	* configure.in: Quote the argument to AC_CHECK_HEADER. Autoconf
+	2.57 was having problems.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+	* pty_err.et: Add final "end" statement.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (install): Don't install libpty.h.
+	* configure.in: Always build static library only.
+
+2002-06-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* cleanup.c, getpty.c, init.c, init_slave.c, logwtmp.c,
+	open_ctty.c, open_slave.c, pty_paranoia.c, sane_hostname.c,
+	update_utmp.c, update_wtmp.c, vhangup.c, void_assoc.c: Include
+	"com_err.h" instead of <com_err.h>.
+
+	* pty-int.h: Don't include syslog.h.
+
+2002-05-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* sane_hostname.c (pty_make_sane_hostname): Always initialize
+	"ai".
+
+2002-03-26  Ken Raeburn  <raeburn@mit.edu>
+
+	* sane_hostname.c: Include fake-addrinfo.h, not fake-addrinfo.c.
+	(FAI_PREFIX): Delete.
+
+2002-02-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBMINOR): Bump due to change in internals.  (Tom's
+	change from 1.2.x branch.)
+
+2001-12-03  Sam Hartman  <hartmans@mit.edu>
+
+	* README: s-pty_init_ets/pty_init/
+
+2001-11-28  Tom Yu  <tlyu@mit.edu>
+
+	* update_utmp.c (PTY_GETUTXENT): Fix typo.  Thanks to Shawn
+	Stepper. [fixes krb5-build/1020]
+
+2001-11-19  Tom Yu  <tlyu@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Patch from Garry Zacheiss to
+	kludge around cases where we need to use more than 2 characters of
+	LINE in order to avoid conflicts in UT_ID.
+
+2001-10-18  Ezra Peisach  <epeisach@mit.edu>
+
+	* sane_hostname.c (pty_make_sane_hostname): Do not declare addrbuf
+	twice, shadowing the first declaration.
+
+
+2001-10-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (includes): Depend on
+	$(BUILDTOP)/include/krb5/autoconf.h. Automatic dependencies do not
+	work on systems in which shared libraries are build without static
+	ones.
+
+2001-09-11  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Cosmetic fix in utmpx.ut_exit check.
+
+Wed Sep  5 20:08:21 2001  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in ($(BUILDTOP)/include/krb5/autoconf.h): Add rules to
+ 	build include/krb5/autoconf.h - this file is wiped out during a
+ 	make clean and sane_hostname.c depends on it.
+
+2001-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* sane_hostname.c: Include socket-utils.h and fake-addrinfo.c.
+	(FAI_PREFIX): Define to krb5int_pty.
+	(sockaddrlen, do_ntoa): Deleted.
+	(pty_make_sane_hostname): Use socklen instead of sockaddrlen.
+	Delete support for not having getnameinfo.  Move code for do_ntoa
+	inline.
+
+2001-07-02  Tom Yu  <tlyu@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Remember to chop off leading
+	"/dev/" for the non-sysV case.  Handle lseek() returning non-zero
+	yet non-negative values (it usually does... :-), so that we can
+	actually write somewhere not at the beginning of the utmp file if
+	necessary.
+
+2001-06-28  Ken Raeburn  <raeburn@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Don't copy host if it's a null
+	pointer.
+
+	* dump-utmp.c (print_ut): Use size of ut_name field, not ut_user,
+	which may not exist, for width when printing ut_name field value.
+	Specify width when printing hostname, it may be unterminated.
+	(main): Move utp and utxp declarations closer to their usages, and
+	make both conditionalized so they're not declared if they're not
+	used.
+
+2001-06-21  Ezra Peisach  <epeisach@mit.edu>
+
+	* libpty.h: Change variable line in prototype to tty_line to
+	prevent shadowing.
+
+2001-06-11  Ezra Peisach  <epeisach@mit.edu>
+
+	* pty-int.h: Provide revoke() prototype if system headers lacking. 
+
+	* logwtmp.c: Provide logwtmp() prototype if needed. 
+
+	* configure.in: Check for system provided getutmp(), logwtmp() and
+	revoke() prototypes.  Check for util.h, libutil.h.
+
+	* update_wtmp.c: Provide prototype for getutmp() if needed.
+
+2001-05-15  Tom Yu  <tlyu@mit.edu>
+
+	* getpty.c: Make pty_getpty() into ptyint_getpty_ext(), which has
+	an extra argument that determines whether to call grantpt() and
+	unlockpt() on systems that support it.  The new pty_getpty() will
+	simply call the extended version.  This is to support some
+	wackiness needed by pty_paranoia.c tests.
+
+	* pty-int.h: Add prototype for ptyint_getpty_ext().
+
+	* pty_paranoia.c: Add rant about ptys and quirks therein.  Needs
+	to be updated somewhat.  Add some more paranoia for the case where
+	we actually succeed in opening the slave of a closed master and
+	then succeed in opening the same master.  This program will get
+	rewritten at some point to actually see what things result in EOFs
+	and under what conditions data will actually get passed between
+	master and slave.
+
+2001-05-10  Tom Yu  <tlyu@mit.edu>
+
+	* pty_paranoia.c: New file; do many paranoid checks about ctty
+	handling by the pty drivers.
+
+	* Makefile.in: Add rules for pty_paranoia and check-paranoia,
+	which runs pty_paranoia.
+
+	* configure.in: Define REVOKE_NEEDS_OPEN for Tru64.  Add support
+	for program building and run flags for the sake of pty_paranoia.
+
+	* open_slave.c: Fix somewhat; AIX doesn't like opening the ctty
+	twice, so only do initial open if we special-case it in
+	configure.in, e.g. for Tru64.
+
+2001-05-08  Tom Yu  <tlyu@mit.edu>
+
+	* logwtmp.c: Delete code under "#if 0".  Fix reversed test for
+	loggingin.  Don't forget to set the ut_tv or ut_time for the
+	entry.
+
+	* update_utmp.c: Update rant about Tru64; remove fetching of
+	ut_user from old entry.  The existence of the old ut_user in the
+	logout entry in wtmp was confusing last.
+
+	* cleanup.c: Call update_utmp() with the correct pid to assist in
+	finding the old utmp entry.
+
+	* open_ctty.c: Reformat somewhat and revise comment.
+
+	* open_slave.c: Rework significantly.  Primarily, keep a fd open
+	to the slave if we need to reopen the slave device following
+	vhangup() or revoke(), to accommodate various OS quirks.
+
+	* update_utmp.c: Revise history section somewhat to document more
+	HP-UX brokenness.  Search via ut_pid before searching via
+	ut_line.  Copy stuff around because entuxent() will clobber some
+	things.
+
+	* void_assoc.c: Revise comment and reformat somewhat.
+
+2001-05-04  Ezra Peisach  <epeisach@mit.edu>
+
+	* open_slave.c (pty_open_slave): If revoke() present on system but
+	VHANG_FIRST is not defined, declare local variable.
+
+2001-05-04  Tom Yu  <tlyu@mit.edu>
+
+	* dump-utmp.c: Fix some off-by-one errors.  Handle cases where we
+	have utmpname() but not utmpname().
+
+	* pty-int.h: Fix typo; VHANG_first -> VHANG_FIRST.
+
+	* open_slave.c (pty_open_slave): Add workaround for Tru64 v5.0,
+	since its revoke() will fail if the slave isn't open already.
+
+2001-05-03  Ezra Peisach  <epeisach@rna.mit.edu>
+
+	* sane_hostname.c (pty_make_sane_hostname): Preserve const
+	property of incomming parameter in casts.
+
+2001-05-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* cleanup.c (pty_cleanup): Delcare local variable only if
+	VHANG_LAST defined.
+
+	* logwtmp.c (pty_logwtmp): Only declare local variables if
+	logwtmp() not available on system.
+
+	* sane_hostname.c (sockaddrlen): Only define static function if
+	HAVE_GETNAMEINFO defined. (pty_make_sane_hostname) Declare goto
+	target only if code compiled in.
+
+2001-05-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Fix typo (OWRONLY ->
+	O_WRONLY).
+
+2001-05-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* update_wtmp.c (ptyint_update_wtmpx): Add missing semi-colon in
+ 	code path if PTY_UTMP_E_EXIT and PTY_UTMPX_E_EXIT exist.
+
+2001-04-30  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Fix some quoting of shell variables when passing
+	to "test".  Reorder some logic in consistency checks to validate
+	cache variables against "yes" to account for possible empty or
+	nonexistent values.
+
+	* pty-int.h: Fix conditional prototype of update_wtmp().
+
+	* update_wtmp.c: Fix conditional compilation of update_wtmp() to
+	cover the case where we have setutxent() but don't have updwtmpx()
+	and WTMPX_FILE, as is the case on some Linux installations.
+
+2001-04-27  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in(K5_CHECK_UT_MEMBER): Fix typo in previous; make
+	sure to include the correct header when checking structure
+	members.
+
+	* configure.in: Many changes to support the rewriting of the utmp
+	pieces of libpty.  Do a large amount of checking for consistency
+	of various utmp and utmpx APIs as currently understood.  See rant
+	in update_utmp.c.
+
+	* dump-utmp.c: Rewrite; now has capability to use utmp{,x}name()
+	to extract entries from utmp and utmpx files.  Adjusts field
+	widths when printing as appropriate.
+
+	* libpty.h: Update call signature for update_utmp() and logwtmp();
+	make prototypes unconditional.
+
+	* logwtmp.c: Rewrite.  Use pututline() or pututxline() API
+	whenever possible.
+
+	* pty-int.h: Update call signatures for update_wtmp{,x}(); make
+	prototypes unconditional.
+
+	* sane_hostname.c: Use the autoconf-correct macro names.
+
+	* update_utmp.c: Rewrite.  Basically, use functions from the
+	pututline() or pututxline() API whenever possible, to avoid
+	lossage.  Inserted large rant about the conjectured history of BSD
+	utmp, sysV utmp, and utmpx, as well as documentation about some
+	known quirks.
+
+	* update_wtmp.c: Rewrite.  Add new function ptyint_logwtmpx() that
+	takes a utmpx rather than a utmp, so it can fail to lose data
+	converting to and from utmp.
+
+2001-01-12  Tom Yu  <tlyu@mit.edu>
+
+	* sane_hostname.c: Switch off of KRB5_USE_INET6 instead of
+	AF_INET6, which may be defined without a corresponding struct
+	sockaddr_in6.
+
+2000-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* sane_hostname.c (pty_make_sane_hostname, do_ntoa): Pass address
+	as const sockaddr pointer.
+	* libpty.h (pty_make_sane_hostname): Update prototype.
+
+	* sane_hostname.c (sockaddrlen, downcase): New function.
+	(do_ntoa, pty_make_sane_hostname): Reimplement using getnameinfo
+	and getaddrinfo if available.
+	* configure.in: Check for IPv6 support.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Quote macro use inside AC_CHECK_LIB. Change
+	AC_FUNC_CHECK to AC_CHECK_FUNC, AC_HAVE_FUNCS to AC_CHECK_FUNCS
+	and AC_HEADER_CHECK to AC_CHECK_HEADER..
+
+2000-06-30  Ezra Peisach  <epeisach@mit.edu>
+
+	* pty-int.h: Add getutmpx() prototype if needed.
+
+	* configure.in: If getutmpx() exists on the system, test if a
+	prototype is provided by the system headers.
+
+2000-06-28  Ezra Peisach  <epeisach@mit.edu>
+
+	* getpty.c (pty_getpty): More conditionalizing variable defintion
+	based on OS features.
+
+	* cleanup.c (pty_cleanup): Add parenthesis about assignment in
+	conditional (gcc suggestion).
+
+	* pty-int.h: Include pty.h if it exists (for openpty prototype
+	under Linux).
+
+	* configure.in: Check for pty.h
+
+2000-06-26  Ezra Peisach  <epeisach@mit.edu>
+
+	* libpty.h: If SOCK_DGRAM is not defined, provide a definition for
+	struct sockaddr_in to satisfy prototype. (based on similar 
+	code in k5-int.h).
+
+	* update_wtmp.c (ptyint_update_wtmp), update_utmp.c
+	(pty_update_utmp), open_slave.c (pty_open_slave), getpty.c
+	(pty_getpty): conditionalize definition of variables based on code
+	paths that are included.
+
+	
+
+1999-10-26  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Check for alpha*-dec-osf* instead of
+	alpha-dec-osf*.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Use "co" instead of "cons" for
+	console line on Solaris.  Patch from Larry Schwimmer
+	(schwim@whatmore.Stanford.EDU).
+
+	* Makefile.in (dump-utmp): Add a rule for building, never
+	automatically done.
+	(dump-utmp.o): Depends on dump-utmp.c.
+
+	Updates from Cygnus KerbNet:
+
+	* dump-utmp.c (ut_typename): Only define if
+	HAVE_STRUCT_UTMP_UT_TYPE is defined.
+	(main): Dump more info, and conditionalize it better.
+
+	* dump-utmp.c (ctime): Declare, to prevent crashes on Alpha.
+
+	* dump-utmp.c (UTMPX): Define if not defined but HAVE_UTMPX_H is
+	defined.
+	(ut_typename): Return shorter forms for some symbols.
+	(main): Require `-x' flag for [uw]tmpx file instead of guessing
+	from the name.  Reject unknown `-' arguments.  Print a message if
+	an error occurs while reading from utmpx file.  Break up output
+	statements into smaller pieces.  Conditionalize output of some
+	utmp fields on whether those fields are present.  Print out exit
+	status fields and timestamp.
+
+Fri Apr 23 23:13:57 1999  Tom Yu  <tlyu@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): utx.ut_pid is a pid_t, and
+	ent.ut_pid is sometimes a short; accordingly, use pid rather than
+	ent.ut_pid, which might have gotten truncated.  This fixes an Irix
+	problem found by <rbasch@mit.edu>.
+
+1999-04-14    <tytso@rsts-11.mit.edu>
+
+	* update_wtmp.c: Don't use updwtmpx() even if it exists for glibc
+		2.1, since it's the same as updwtmp(), and glibc doesn't
+		define PATH_WTMPX.  updwtmpx() is not part of the XPG
+		standard anyway.  (Needed for RedHat 6.0.)
+
+Sun Mar 28 17:50:57 1999  Tom Yu  <tlyu@mit.edu>
+
+	* update_wtmp.c: Define WTMPX_FILE to be _PATH_WTMPX in case we're
+	on a system that cleans up the namespace that way.
+
+Wed Feb 17 19:47:36 1999  Tom Yu  <tlyu@mit.edu>
+
+	* sane_hostname.c (pty_make_sane_hostname): Remove unused
+	"char *scratch".
+
+Tue Feb 16 20:18:40 1999  Tom Yu  <tlyu@mit.edu>
+
+	* sane_hostname.c: Re-order so that pty-int.h precedes libpty.h to
+	prevent conflicting definitions of struct sockaddr_in
+
+Thu Feb 11 22:24:03 1999  Tom Yu  <tlyu@mit.edu>
+
+	* sane_hostname.c: Force maxlen to be 16 if it's less than 16,
+	since otherwise a numeric IP address won't fit.
+
+	* Makefile.in: Add sane_hostname.{o,c}; bump minor version.
+
+	* libpty.h: Add prototype for make_sane_hostname.
+
+	* sane_hostname.c: New file; add function to "sanitize" hostname
+	for logging purposes.
+
+1999-01-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Remove test CHECK_WAIT_TYPE since nothing is using
+		the results of that test (WAIT_USES_INT).
+
+1998-08-16    <hartmans@fundsxpress.com>
+
+	* Makefile.in (SHLIB_EXPDEPS): Depend on lib_comerr
+
+1998-07-05    <hartmans@fundsxpress.com>
+
+	* update_utmp.c (pty_update_utmp): If the ut_exit differs test
+	indicates the structures differ, and we don't have a special case,
+	do nothing rather than trying to copy the field.  It's not worth
+	breaking the build over.
+
+Mon Apr  6 19:35:33 1998  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Don't record LOGIN_PROCESS
+	entries, as they confuse last on some systems. [pty/569]
+
+Thu Mar 12 18:09:25 1998  Tom Yu  <tlyu@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Fix bogus entry of
+	PTY_LOGIN_PROCESS types on BSD-ish systems. [pty/531]
+
+Wed Feb 18 16:33:58 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Mon Feb  2 16:18:08 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* configure.in, Makefile.in: Remove CopySrcHeader and CopyHeader 
+		from configure.in and move equivalent functionality to
+		Makefile.in 
+
+Sun Dec  7 00:05:28 1997  Tom Yu  <tlyu@mit.edu>
+
+	* getpty.c (pty_getpty): Fix goof in previous, which introduced
+	another fencepost error.
+
+Thu Dec  4 21:48:12 1997  Tom Yu  <tlyu@mit.edu>
+
+	* getpty.c (pty_getpty): Fix checks on string lengths to account
+	for terminating nul character.  Some whitespace fixups.
+
+Wed Dec  3 17:16:44 1997  Tom Yu  <tlyu@mit.edu>
+
+	* pty_err.et: Add PTY_OPEN_SLAVE_TOOSHORT error code.
+
+	* open_slave.c (pty_open_slave): Check to ensure that the slave
+	name is not NULL or zero-length.
+
+Tue Oct 28 13:28:54 1997  Ezra Peisach  <epeisach@.mit.edu>
+
+	* pty-int.h: Do not prototype initialize_pty_error_table as
+	        pty-err.h does as well.
+
+Fri Oct 24 09:12:43 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (CFILES): Add $(srcdir).
+
+Wed Oct  1 04:53:30 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Default to a long rather than an int for a time_t
+	for paranoia reasons.
+
+Tue Jun  3 23:05:07 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* getpty.c (pty_getpty): Remove erroneous space from the HPUX open().
+
+Fri Apr 25 19:14:48 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* configure.in: Check for openpty() in -lutil.  It's there on
+		FreeBSD and BSDI systems.
+
+Fri Feb 21 18:25:47 1997  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* pty-int.h: No longer prototype error table init function.
+
+Thu Jan 16 18:47:12 1997  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Cause "clean" to dtrt.
+	
+	* configure.in: Punt spurious call to KRB5_LIB_PARAMS.
+
+Sun Dec 29 21:32:41 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Update to set STLIBOBJS instead of LIBSRCS; also
+	clean up a little bit.
+
+Fri Dec 27 17:09:46 1996  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Fix to use OBJS.ST rather than ./OBJS.ST.
+
+	* Makefile.in:
+	* configure.in: Changes to use new library build system.
+
+Thu Dec  5 22:43:35 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Apply platform specific patch
+		so that HPUX works.  (Kludge for 1.0 release) [PR#40]
+
+Fri Nov 22 11:52:52 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in : Make sure time_t is define [203]
+	* update_wtmp.c (ptyint_update_wtmp): Use time_t for call to time(2). [203]
+
+Fri Nov 15 08:33:54 1996  Ezra Peisach  <epeisach@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Handle case where utmp uses
+		ut_exit.e_exit and utmpx uses ut_exit.ut_exit.
+
+	* configure.in (UT_EXIT_STRUCTURE_DIFFER): If utmpx.h exists, and
+		getutmpx does not exist then test if the ut_exit part of
+		the utmp/utmpx structure is a structure and if their types
+		differ. (e_exit vs. ut_exit).
+
+Fri Nov  8 17:45:42 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Add code which attempts to
+		compensate for systems that don't have getutmpx()
+
+	* configure.in: Check for getutmpx().  Replace calls to
+		AC_FUNC_CHECK with AC_HAVE_FUNCS().
+
+Thu Jun 13 22:14:24 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to ET_RULES
+
+
+Thu Jun 13 14:12:16 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* update_wtmp.c (ptyint_update_wtmp): Only update wtmpx if we have
+ 	updwtmpx.  This probably should be more general, but I'm not
+ 	really sure of HP caviats.
+
+	* configure.in :  check for updwtmpx
+
+	* getpty.c (pty_getpty): Actually check for 256 ptys on SunOS and
+ 	other old-style systems.
+Tue Apr 16 22:06:36 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* dump-utmp.c: New file.  Not automatically used by anything, but
+	may be useful for examining utmp/wtmp files when comparing
+	behavior against system software.
+
+	Sun Mar 31 02:04:28 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* update_utmp.c (pty_update_utmp): Always use id "cons" for
+	console.  For HP-UX, omit "kl" prefix.  Reindent for readability.
+	* update_wtmp.c (ptyint_update_wtmp): For HP-UX, copy ut_id and
+	ut_type from input utmp structure.  Reindent for readability.
+
+	Wed Mar 27 21:14:33 1996  Marc Horowitz <marc@mit.edu>
+
+	* init_slave.c (pty_initialize_slave): Spurious signal stuff
+		which did nothing deleted.
+
+Tue Apr 16 13:43:43 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* configure.in :  Don't use streams on HPUX.
+
+	* getpty.c (pty_getpty): Check /dev/ptym/clone for HPUX10, only
+ 	try /dev/ptmx if HAVE_STREAMS defined so we can bipass for HPUX9.
+
+Sun Apr 14 00:36:33 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* pty-int.h: Don't include sys/wait.h here.
+
+	* configure.in : Check for waitpid.
+
+Sat Apr 13 18:58:43 1996  Sam Hartman  <hartmans@mit.edu>
+
+	* cleanup.c (pty_cleanup): If we are doing a vhangup, then fork
+ 	and dissociate on hangup.  This makes the HP happy, because there
+ 	is no way to get rid of a controlling terminal besides setsid() on
+ 	the HP.
+
+Sun Mar 24 19:59:14 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in : Do streams handling by deciding what modules to
+ 	push for each system.
+
+	* init_slave.c (pty_initialize_slave): Better abstraction for
+ 	dealing with what modules get pushed on what streams system.
+  	There is a list of modules controlled on a module-by-module basis
+ 	by configure.in, and the modules included in that list are pushed.
+
+	* void_assoc.c: Duplicate comment from open_ctty.c explaining that
+ 	it's OK to call void_association twice, and giving the caviats
+ 	about setsid.
+
+	* open_ctty.c (pty_open_ctty): Remove test to make sure /dev/tty
+ 	worked, so we can push the streams for the HP.
+
+	* open_slave.c (pty_open_slave): Test to see if /dev/tty works
+ 	only after calling pty_initialize_slave.
+
+Sat Mar 23 15:24:38 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in : Remove shadow passwords check because nothing in
+ 	libpty cares about the result; remove use of libkrb5, libkrb4,
+ 	libkadm; Check for _getpty
+
+	* getpty.c (pty_getpty): Support _getpty for Irix; Irix has
+ 	/dev/ptmx, but it doesn't work correctly at all.  Also, Irix,
+ 	tends to create device nodes on the fly.
+
+	* pty-int.h: No need to include sys/socket.h
+
+Sat Feb 24 21:34:58 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* vhangup.c (ptyint_vhangup): Don't do call vhangup() if system
+		doesn't have it.
+
+Sat Jan 27 01:13:34 1996  Mark Eichin  <eichin@cygnus.com>
+
+	* void_assoc.c (ptyint_void_association): if we don't have
+	TIOCNOTTY (HP/UX 9 for example) don't try to use it.
+
+Fri Jan 26 00:26:37 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* cleanup.c (pty_cleanup): Update utmp only if update_utmp is true.
+
+Tue Jan 16 13:52:22 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* void_assoc.c (ptyint_void_association): Move setsid call from
+        open_ctty to void_association.
+
+	* logwtmp.c (pty_logwtmp): Pass user argument to update_wtmp.
+
+	* update_utmp.c (update_utmp): Implement PTY_UTMP_USERNAME_VALID flag
+
+Mon Jan 15 15:48:37 1996  Sam Hartman  (hartmans@justforfun)
+
+	* cleanup.c: Change to indiciate utmp user name is valid.
+
+	* 
+
+Mon Jan 15 15:21:16 1996  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* update_utmp.c (pty_update_utmp): Add flags field; use ttyslot
+        only if reasonable.
+
+Fri Jan 12 16:33:37 1996  Sam Hartman  <hartmans@infocalypse>
+
+	* open_slave.c (pty_open_slave): Don't use fchmod or fchown; they
+ 	don't buy much security unless /dev is world-writable and may
+ 	prevent Solaris lossage.
+
+Thu Dec 21 00:12:58 1995  Sam Hartman  <hartmans@portnoy>
+
+	* open_slave.c (pty_open_slave): Open with no delay.
+
+
+Wed Jan 10 22:20:04 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* open_slave.c (pty_open_slave): Added hack by Doug Engert to get
+		util/pty to work under Solaris.  We should double check to
+		make sure this is a correct fix.
+
+
+Sun Nov 12 12:44:33 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* open_ctty.c (pty_open_ctty): Remove redundant Ultrix calls to setpgrp()
+
+Sun Oct 22 03:48:37 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* update_wtmp.c (ptyint_update_wtmp): Add comments explaining why ifdefs are right.
+
+Sun Oct 22 01:20:52 1995  Sam Hartman  <hartmans@infocalypse>
+
+	* update_wtmp.c (ptyint_update_wtmp): Try utx not uts.
+
+Mon Oct 16 17:41:45 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+
+
+	* update_wtmp.c (ptyint_update_wtmp): Update to take host name, so
+        we can get the full host name if it is chopped in utmp.
+	* update_wtmp.c (ptyint_update_wtmp):  Insert fallback path for Sunos and others, return defined value.
+
+
+
+
+	* update_utmp.c (pty_update_utmp): Incorperate utmpx handling patch from ramus@nersc.gov to deal with support for longer hostanmes in utmpx.
+
+
+*update_utmp.c: Add return statement and fallback path for Sunos.
+
+Sat Oct 14 20:49:40 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+Fri Aug 11 17:49:36 1995  Samuel D Hartman  (hartmans@vorlon)
+
+
+Fri Sep 29 14:18:03 1995  Theodore Y. Ts'o  <tytso@dcl>
+	* update_wtmp.c (ptyint_update_wtmp): If EMPTY not defined as a
+        utmp type, use DEAD_PROCESS.
+
+
+
+	* configure.in:
+	* Makefile.in: Use the SubdirLibraryRule defined in aclocal.m4 to
+		create the DONE file (and to properly clean it up).
+
+Mon Sep 25 16:42:36 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Thu Sep  7 19:13:05 1995  Mark Eichin  <eichin@cygnus.com>
+
+	* update_utmp.c: ultimately fall back to /etc/utmp for UTMP_FILE,
+	if it is still missing after all previous efforts.
+	* update_wtmp.c: /usr/adm/wtmp for WTMP_FILE likewise.
+
+Thu Aug 24 18:40:48 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Update file list
+
+Tue Aug 15 21:42:16 1995    <tytso@rsts-11.mit.edu>
+
+	* update_wtmp.c (ptyint_update_wtmp): If EMPTY is not defined,
+		then set ut.ut_type to 0 instead.
+
+
+
+Fri Aug 11 15:49:30 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* Makefile.in (CFILES): Rename initialize_slave.c to init_slave.c
+        so it isn't truncated in libpty.a.
+
+Fri Aug 11 01:12:03 1995  Sam Hartman  <hartmans@infocalypse>
+
+	* initialize_slave.c (pty_initialize_slave): You really do need to
+        push and pop the streams on a Sun. 
+
+Fri Aug 11 00:49:23 1995  Sam Hartman  <hartmans@dragons-lair.MIT.EDU>
+
+	* configure.in (ac_cv_func_setsid): Pretend that Ultrix doesn't
+        have setsid, because if it does make the call then the pty never
+        becomes controlling tty.
+
+Thu Aug 10 09:47:07 1995  Sam Hartman  <hartmans@dragons-lair.MIT.EDU>
+
+	* open_ctty.c (pty_open_ctty): Move setpgrp() after void_assoc call
+
+Wed Aug  9 00:16:40 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* pty-int.h (VHANG_first): Change defines so VHANG_FIRST doesn't
+        get defined under Ultrix because Ultrix can only establish
+        controlling terminal once per process and we need to get
+        controlling terminal again after vhangup().
+
+	* getpty.c (pty_getpty): Use the right test for slave buffer length.
+
+Tue Aug  8 22:20:33 1995  Tom Yu  <tlyu@lothlorien.MIT.EDU>
+
+	* update_utmp.c (UTMP_FILE): _PATH_UTMP under NetBSD, not
+		_UTMP_PATH; also fix typo (missing '&' on reference to
+		ent)
+
+Tue Aug  8 20:47:01 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* update_utmp.c (pty_update_utmp): change #ifdef NO_UT_PID to
+		#ifndef
+
+Tue Aug  8 09:13:50 1995  Sam Hartman  <hartmans@pao.mit.edu>
+
+	* open_slave.c (pty_open_slave): Dissociate from controlling
+        terminal before calling revoke.
+	(pty_open_slave): Don't ask for a controlling terminal unless we need it.
+
+Tue Aug  8 20:32:08 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* update_utmp.c: flush preprocessor directive to left margin.
+	* pty_err.et: Fix typo in error description.
+
+	* cleanup.c (pty_cleanup): Don't change slave before revoking it.  Also return a value all the time, not just on systems without revoke.
+
+
+	* update_utmp.c (pty_update_utmp): Move #ifdef back to column 1.
+
+Mon Aug  7 17:41:39 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* cleanup.c (pty_cleanup): Call pty_update_utmp using new interface.
+
+	* update_utmp.c logwtmp.c : Call ptyint_update_wtmp not pty_update_wtmp.
+
+	* cleanup.c (pty_cleanup): We can't use pid_t because we need to
+        use something in libpty.h and we can't wait for pid_t to be
+        defined there because we may not have configure.
+
+	* update_wtmp.c (pty_update_wtmp): Rename to ptyint_update_wtmp.
+
+	* update_utmp.c (pty_update_utmp): Change interface so it doesn't take a struct utmp.
+
+	* libpty.h: Remove pty_update_wtmp as it's becoming  an internal interface.
+
+Sat Aug  5 01:00:35 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* open_slave.c (pty_open_slave): pty_open_ctty returns != 0 on
+		error, not less than.
+
+Fri Aug  4 13:59:11 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* libpty.h (pty_cleanup): Fix argument type of pid to patch that
+		used in the C file.  Include <utmpx.h> if present.  Only
+		include <utmp.h> if it is present.
+	
+	* configure.in: Check for utmp.h and utmpx.h
+
+Fri Aug  4 00:59:20 1995  Tom Yu  <tlyu@dragons-lair.MIT.EDU>
+
+	* Makefile.in: use libupdate so to not get multiple copies of
+		object files upon rebuild.
+
+	* vhangup.c (ptyint_vhangup): Make sure preprocessor directives
+		are at left margin.
+
+	* open_slave.c (pty_open_slave): Make sure preprocessor directives
+		are at left margin.
+
+	* open_ctty.c (pty_open_ctty): Make sure preprocessor directives
+		are at left margin.
+
+	* cleanup.c (pty_cleanup): Add missing declarations for retval and
+		fd.  Also, align preprocessor directives with left margin.
+
+Thu Aug  3 15:04:34 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* configure.in: Check for vhangup and killpg.
+
+	* cleanup.c (pty_cleanup): Kill the process group associated with
+        the pty if using revoke.  This won't always work, but will at
+        least attempt to remove processes associated with the pty.
+
+Wed Aug  2 11:59:19 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* init.c (pty_init): New file to handle initialization--currently only error tables.
+
+	* getpty.c (pty_getpty): Reverse sense of logic tests so they work.  
+
+Tue Aug  1 08:20:06 1995  Sam Hartman  <hartmans@tertius.mit.edu>
+
+	* cleanup.c (pty_cleanup): Allow pid to be zero (unknown).
+
+	* pty-int.h: Define VHANG_FIRST and VHANG_LAST based on presence
+        of vhangup.
+
+	* pty_err.et: Define PTY_GETPTY_SLAVE_TOOLONG
+
+	* getpty.c (pty_getpty): Close slave side if we call openpty.
+
+	(pty_getpty): Take length parameter; return error if it isn't big enough.
+
+
+
+Tue Aug  1 12:06:14 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* open_ctty.c (pty_open_ctty): Fixed typo TIOCSTTY to TIOCSCTTY.
+
+
diff --git a/mechglue/src/util/pty/Makefile.in b/mechglue/src/util/pty/Makefile.in
new file mode 100644
index 000000000..0e8f394c8
--- /dev/null
+++ b/mechglue/src/util/pty/Makefile.in
@@ -0,0 +1,157 @@
+thisconfigdir=.
+myfulldir=util/pty
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+RELDIR=../util/pty
+
+SED = sed
+
+KRB5_RUN_ENV= @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+LIBBASE=pty
+LIBMAJOR=1
+LIBMINOR=2
+
+STLIBOBJS= cleanup.o getpty.o init_slave.o open_ctty.o open_slave.o \
+	update_utmp.o update_wtmp.o vhangup.o void_assoc.o pty_err.o \
+	logwtmp.o init.o sane_hostname.o
+
+STOBJLISTS=OBJS.ST
+
+INSTALLFILE = cp
+
+# for pty-int.h
+LOCALINCLUDES=-I. -I$(srcdir)
+
+FILES= Makefile cleanup.c getpty.c init_slave.c open_ctty.c open_slave.c update_utmp.c update_wtmp.c vhangup.c void_assoc.c pty_err.h pty_err.c\
+logwtmp.c init.c
+
+CFILES=$(srcdir)/cleanup.c $(srcdir)/getpty.c $(srcdir)/init_slave.c \
+	$(srcdir)/open_ctty.c $(srcdir)/open_slave.c \
+	$(srcdir)/update_utmp.c $(srcdir)/update_wtmp.c $(srcdir)/vhangup.c \
+	$(srcdir)/void_assoc.c $(srcdir)/logwtmp.c \
+	$(srcdir)/init.c $(srcdir)/sane_hostname.c
+
+
+SRCS=pty_err.c $(CFILES)
+SHLIB_EXPDEPS = \
+	$(COM_ERR_DEPLIB)
+SHLIB_EXPLIBS= -lcom_err 
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+DEPLIBS=
+
+#
+all-unix:: includes pty_err.h
+
+all-unix:: all-liblinks
+
+dump-utmp: dump-utmp.o
+	$(CC) $(LDFLAGS) -o dump-utmp dump-utmp.o
+dump-utmp.o: dump-utmp.c
+
+pty_paranoia: pty_paranoia.o $(COM_ERR_DEPLIB) $(PTY_DEPLIB)
+	$(CC_LINK) -o pty_paranoia pty_paranoia.o $(PTY_LIB) $(COM_ERR_LIB) $(LIBS)
+
+check-paranoia: pty_paranoia
+	$(KRB5_RUN_ENV) ./pty_paranoia
+
+install-unix:: install-libs
+
+clean-unix::
+	$(RM) libpty.a $(BUILDTOP)/include/libpty.h pty_err.c pty_err.h
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+depend::  pty_err.h
+
+#install:: libpty.h
+#	$(INSTALL_DATA) $(srcdir)/libpty.h  $(DESTDIR)$(KRB5_INCDIR)/libpty.h
+
+includes:: libpty.h
+	if cmp $(srcdir)/libpty.h \
+	$(BUILDTOP)/include/libpty.h >/dev/null 2>&1; then :; \
+	else \
+		(set -x; $(RM) $(BUILDTOP)/include/libpty.h; \
+		 $(CP) $(srcdir)/libpty.h \
+			$(BUILDTOP)/include/libpty.h) ; \
+	fi
+
+includes:: $(BUILDTOP)/include/krb5/autoconf.h
+
+clean-unix::
+	$(RM) $(BUILDTOP)/include/libpty.h
+
+
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs clean-files
+
+clean-files::
+	rm -f *~ \#* *.bak \
+		*.otl *.aux *.toc *.PS *.dvi *.x9700 *.ps \
+		*.cp *.fn *.ky *.log *.pg *.tp *.vr \
+		*.o profiled/?*.o libcom_err.a libcom_err_p.a \
+		com_err.o compile_et \
+		et.ar TAGS y.tab.c lex.yy.c error_table.c \
+		et_lex.lex.c \
+		test1.h test1.c test2.h test2.c test_et \
+		eddep makedep *.ln
+
+pty_err.o: pty_err.c
+pty_err.h: pty_err.et
+pty_err.c: pty_err.et
+
+$(BUILDTOP)/include/krb5/autoconf.h: $(SRCTOP)/include/krb5/autoconf.h.in
+	(cd $(BUILDTOP)/include; $(MAKE) krb5/autoconf.h)
+
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+pty_err.so pty_err.po $(OUTPRE)pty_err.$(OBJEXT): pty_err.c \
+  $(COM_ERR_DEPS)
+cleanup.so cleanup.po $(OUTPRE)cleanup.$(OBJEXT): cleanup.c \
+  $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+getpty.so getpty.po $(OUTPRE)getpty.$(OBJEXT): getpty.c \
+  $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+init_slave.so init_slave.po $(OUTPRE)init_slave.$(OBJEXT): \
+  init_slave.c $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+open_ctty.so open_ctty.po $(OUTPRE)open_ctty.$(OBJEXT): \
+  open_ctty.c $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+open_slave.so open_slave.po $(OUTPRE)open_slave.$(OBJEXT): \
+  open_slave.c $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+update_utmp.so update_utmp.po $(OUTPRE)update_utmp.$(OBJEXT): \
+  update_utmp.c $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+update_wtmp.so update_wtmp.po $(OUTPRE)update_wtmp.$(OBJEXT): \
+  update_wtmp.c $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+vhangup.so vhangup.po $(OUTPRE)vhangup.$(OBJEXT): vhangup.c \
+  $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+void_assoc.so void_assoc.po $(OUTPRE)void_assoc.$(OBJEXT): \
+  void_assoc.c $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h
+logwtmp.so logwtmp.po $(OUTPRE)logwtmp.$(OBJEXT): logwtmp.c \
+  $(COM_ERR_DEPS) libpty.h pty-int.h pty_err.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+init.so init.po $(OUTPRE)init.$(OBJEXT): init.c $(COM_ERR_DEPS) \
+  libpty.h pty-int.h pty_err.h $(SRCTOP)/include/port-sockets.h \
+  $(BUILDTOP)/include/krb5/autoconf.h
+sane_hostname.so sane_hostname.po $(OUTPRE)sane_hostname.$(OBJEXT): \
+  sane_hostname.c $(COM_ERR_DEPS) pty-int.h pty_err.h \
+  $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  libpty.h $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/fake-addrinfo.h
diff --git a/mechglue/src/util/pty/README b/mechglue/src/util/pty/README
new file mode 100644
index 000000000..f10dd2b37
--- /dev/null
+++ b/mechglue/src/util/pty/README
@@ -0,0 +1,108 @@
+	This file is to serve as documentation and usage notes on
+libpty until
+more formal docs are written.  By that point, it will probably
+describe how pty can be broken out of the Kerberos distribution.
+
+void pty_init(void);
+
+	 Initialize error tables.
+
+
+long pty_getpty ( int *fd, char *slave, int slavelength);
+	Find and initialize a clean master pty.  This should open the
+pty as fd, and return the name of the slave.  It should return 0 or an
+error code.  The slavelength parameter should include the maximum
+length allocated for a slave name.  The slave may not be initialized, although any
+
+operating-system specific initialization (for example, unlockpt and
+grantpt) may be performed.
+
+long pty_open_slave (/*in */ char * slave, /* out*/ int *fd)
+
+	Initialize the slave side by dissociating the current terminal
+and by setting process groups, etc.  In addition, it will initialize
+the terminal flags (termios or old BSD) appropriately; the application
+may have to do additional customization, but this should sanitize
+things.  In addition, the pty will be opened securely, and will become
+the controlling terminal.  This procedure will fail unless the process
+is running as root.  Ideally, pty_open_slave will be called in a child
+process of the process that called pty_getpty.  If an operating system
+implements setsid() per the POSIX spec, but does not implement
+TIOCNOTTY, this procedure will not be able to insure that the
+controlling terminal is established if it is called in the parent
+process.  Unfortunately, the parent process must not write to the pty
+until the slave side is opened.  Also, the parent process should not
+open the slave side through other means unless it is prepared to have
+that file descriptor subjected to a vhangup() or revoke() when
+pty_open_slave is called in the child.  So, ideally, the parent calls
+pty_getpty, forks, waits for the slave to call pty_open_slave, then
+continues.  Since this synchronization may be difficult to build in to
+existing programs, pty_open_slave makes an effort to function if
+called in the parent under operating systems where this is possible.
+Currently, I haven't found any operating systems where this isn't
+possible.  Also note that pty_open_slave will succeed only once per process.
+
+long pty_open_ctty(int *fd, char *line)
+
+	Attempt to disassociate the current process from its controlling terminal and open line as a new controlling terminal.  No assumption about line being the slave side of a pty is made.
+
+long pty_initialize_slave (int fd)
+
+	Perform the non-security related initializations on the slave
+side of a pty.  For example, push the appropriate streams, set termios
+structures, etc.  This is included in pty_open_slave.  I am interested
+in any suggestions on how to pass information on the state to which
+the application wants the terminal initialized.  For example, rlogind
+wants a transparent channel, while other programs likely want cooked
+mode.  I can't take a termios structure because I may be on a
+non-termios system.  Currently, I push the streams, do a bit of
+cleanup, but don't really modify the terminal that much. Another
+possible goal for this function would be to do enough initialization
+that the slave side of the pty can be treated simply as a tty instead
+of a pty after this call.
+
+
+long pty_update_utmp ( int process_type, int pid, char *user, char
+*line, char *host, int flags)
+
+	Update the utmp information or return an error.The
+process_type is one of the magic types defined in libpty.h.  The flags
+are logical combinations of one of the following:
+
+    		PTY_TTYSLOT_USABLE: The tty pointed to by the line
+		  parameter is the first tty that would be found by
+		  searching stdin then stdout.  In other words,
+		  ttyslot() would return the right slot in utmp on
+		  systems where ttyslot() is cannonically used.  Note
+		  that for inserting utmp entries for new logins, it
+		  is not always possible to find the right place if
+		  this flag is not given. Thus, for programs like
+		  telnetd that set up utmp entries, it is important to
+		  be able to set this flag on the initial utmp update.
+		  It is expected that this flag may be cleared on
+		  update_utmp calls to remove utmp entries.
+
+		PTY_UTMP_USERNAME_VALID: the username field in the
+		  utmp entry associated with this line contains the
+		  user who (is/was) associated with the line.
+		  Regardless of this flag, the utmp file will contain
+		  the username specified after this call.  However, if
+		  a username is needed by the system for wtmp logout
+		  (Solaris 2.1 for example), then the system can fetch
+		  the user from the utmp record before doing the wtmp
+		  update.  This will only be attempted if the username
+		  is a null pointer.  
+
+long pty_cleanup(char *slave, pid_t pid, int update_wtmp)
+
+	Clean up after the slave application has exited.  Close down
+the pty, HUPing processes associated with it.  (pid is the pid of the
+slave process that may have died, slave is the name of the slave
+terminal.)  PID is allowed to be zero if unknown; this may disable
+some cleanup operations.  This routine may fork on some systems.  As
+such, SIGCHLD may be generated and blocked for some time during the
+routine.  In addition, on systems without waitpid() or wait4(), wait()
+may be called.
+
+
+    
diff --git a/mechglue/src/util/pty/cleanup.c b/mechglue/src/util/pty/cleanup.c
new file mode 100644
index 000000000..57cc796ac
--- /dev/null
+++ b/mechglue/src/util/pty/cleanup.c
@@ -0,0 +1,112 @@
+/*
+ * pty_cleanup: Kill processes associated with pty.
+ *
+ * (C)Copyright 1995, 1996 by the Massachusetts Institute of Technology.
+ *
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+long pty_cleanup (char *slave,
+		  /* May be zero for unknown.  */
+		  int pid,
+		  int update_utmp)
+{
+#ifdef VHANG_LAST
+    int retval, fd;
+#endif
+    
+    if (update_utmp)
+	pty_update_utmp(PTY_DEAD_PROCESS, pid,  "", slave, (char *)0, PTY_UTMP_USERNAME_VALID);
+    
+    (void)chmod(slave, 0666);
+    (void)chown(slave, 0, 0);
+#ifdef HAVE_REVOKE
+    revoke(slave);
+    /*
+     * Revoke isn't guaranteed to send a SIGHUP to the processes it
+     * dissociates from the terminal.  The best solution without a Posix
+     * mechanism for forcing a hangup is to killpg() the process
+     * group of the pty.  This will at least kill the shell and
+     * hopefully, the child processes.  This is not always the case, however.
+     * If the shell puts each job in a process group and doesn't pass
+     * along SIGHUP, all processes may not die.
+     */
+    if ( pid > 0 ) {
+#ifdef HAVE_KILLPG
+	killpg(pid, SIGHUP);
+#else
+	kill( -(pid), SIGHUP );
+#endif /*HAVE_KILLPG*/
+    }
+#else /* HAVE_REVOKE*/
+#ifdef VHANG_LAST
+    {
+      int status;
+#ifdef POSIX_SIGNALS
+      sigset_t old, new;
+      sigemptyset(&new);
+      sigaddset(&new, SIGCHLD);
+      sigprocmask ( SIG_BLOCK, &new, &old);
+#else /*POSIX_SIGNALS*/
+      int mask = sigblock(sigmask(SIGCHLD));
+#endif /*POSIX_SIGNALS*/
+      switch (retval = fork()) {
+      case -1:
+#ifdef POSIX_SIGNALS
+	sigprocmask(SIG_SETMASK, &old, 0);
+#else /*POSIX_SIGNALS*/
+	sigsetmask(mask);
+#endif /*POSIX_SIGNALS*/
+	return errno;
+      case 0:
+	ptyint_void_association();
+	if ((retval = pty_open_ctty(slave, &fd)))
+	  exit(retval);
+	ptyint_vhangup();
+	exit(0);
+	break;
+      default:
+#ifdef HAVE_WAITPID
+	waitpid(retval, &status, 0);
+#else /*HAVE_WAITPID*/
+	wait(&status);
+#endif
+#ifdef POSIX_SIGNALS
+	sigprocmask(SIG_SETMASK, &old, 0);
+#else /*POSIX_SIGNALS*/
+	sigsetmask(mask);
+#endif /*POSIX_SIGNALS*/
+
+	break;
+      }
+    }
+#endif /*VHANG_LAST*/
+#endif /* HAVE_REVOKE*/
+#ifndef HAVE_STREAMS
+    slave[strlen("/dev/")] = 'p';
+    (void)chmod(slave, 0666);
+    (void)chown(slave, 0, 0);
+#endif
+    return 0;
+}
diff --git a/mechglue/src/util/pty/configure.in b/mechglue/src/util/pty/configure.in
new file mode 100644
index 000000000..a20f559a7
--- /dev/null
+++ b/mechglue/src/util/pty/configure.in
@@ -0,0 +1,261 @@
+K5_AC_INIT(getpty.c)
+CONFIG_RULES
+AC_PROG_AWK
+AC_CHECK_FUNCS(fchmod fchown revoke vhangup killpg _getpty)
+dnl
+LOGINLIBS=
+dnl
+dnl Make our operating system-specific security checks and definitions for
+dnl login.
+dnl  In addition, the following code decides what streams modules will
+dnl be pushed onto a pty.In particular, if HAVE_STREAMS is defined and
+dnl HAVE_LINE_PUSH is not defined, modules may be pushed by inserting
+dnl An appropriate generic ifdef for each module in init_slave.c and
+dnl  AC_DEFINES for the operating systems that need the modules.
+dnl  Each OS that supports streams has a different idea of what you want to
+dnl push.
+dnl
+case $krb5_cv_host in
+*-*-ultrix*)
+echo "Disabling initial vhangup and setsid because they break under Ultrix..."
+AC_DEFINE([OPEN_CTTY_ONLY_ONCE],[1])
+ac_cv_func_setsid=no # setsid doesn't do the right thing under Ultrix even though present
+;;
+
+*-*-aix3*) # AIX has streams include files but not streams TTY
+# Moreover, strops.h trashes sys/ioctl.h
+krb5_cv_has_streams=no
+;;
+alpha*-dec-osf*)
+	AC_CHECK_LIB(security,main,
+		AC_DEFINE(HAVE_SETLUID)
+		LOGINLIBS="$LOGINLIBS -lsecurity"
+	)
+	AC_MSG_RESULT(will open ctty prior to revoke due to OSF/1 lossage)
+	AC_DEFINE(REVOKE_NEEDS_OPEN)
+	;;
+*-*-solaris*)
+     AC_DEFINE(PUSH_PTEM)
+     AC_DEFINE(PUSH_LDTERM)
+     AC_DEFINE(PUSH_TTCOMPAT)
+     ;;
+*-*-hpux*)
+     krb5_cv_has_streams=no
+     ;;
+esac
+dnl
+AC_SUBST(LOGINLIBS)
+dnl
+AC_CHECK_LIB(util,openpty, [AC_DEFINE(HAVE_OPENPTY) LIBS="$LIBS -lutil"])
+AC_TYPE_MODE_T
+AC_CHECK_TYPE(time_t, long)
+AC_CHECK_FUNCS(setreuid gettosbyname setsid ttyname line_push ptsname grantpt openpty)
+AC_CHECK_HEADERS(unistd.h stdlib.h string.h libutil.h pty.h sys/filio.h sys/sockio.h sys/label.h sys/tty.h sys/wait.h ttyent.h lastlog.h sys/select.h sys/ptyvar.h util.h)
+AC_CHECK_FUNCS(waitpid)
+CHECK_SIGNALS
+AC_CHECK_HEADER(termios.h,[AC_CHECK_FUNC(cfsetispeed,AC_DEFINE(POSIX_TERMIOS))])
+
+######################################################################
+#
+# utmp related hair here.  There's lots of it.
+#
+
+AC_CHECK_HEADERS(utmp.h utmpx.h)
+AC_CHECK_FUNCS(setutent setutxent updwtmp updwtmpx logwtmp getutmp getutmpx)
+AC_CHECK_FUNCS(utmpname utmpxname)
+
+AC_DEFUN(K5_CHECK_UT_MEMBER,
+[AC_MSG_CHECKING([for $2 in struct $1])
+AC_CACHE_VAL([krb5_cv_struct_$1_$2],
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <$1.h>], [struct $1 u; u.$2;],
+eval "krb5_cv_struct_$1_$2=yes", eval "krb5_cv_struct_$1_$2=no")])
+if eval "test \"`echo '$krb5_cv_struct_'$1'_'$2`\" = yes"; then
+  AC_MSG_RESULT(yes)
+  krb5_tr_ut=HAVE_STRUCT_`echo $1'_'$2 | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  AC_DEFINE_UNQUOTED($krb5_tr_ut)
+else
+  AC_MSG_RESULT(no)
+fi])
+
+if test "$ac_cv_header_utmp_h" = yes; then
+  AC_MSG_RESULT(checking struct utmp members)
+  for krb5_mem in ut_host ut_syslen ut_addr ut_id ut_pid ut_type ut_exit; do
+    K5_CHECK_UT_MEMBER(utmp, $krb5_mem)
+  done
+fi
+
+if test "$ac_cv_header_utmpx_h" = yes; then
+  AC_MSG_RESULT(checking struct utmpx members)
+  for krb5_mem in ut_host ut_syslen ut_addr ut_id ut_pid ut_type ut_exit; do
+    K5_CHECK_UT_MEMBER(utmpx, $krb5_mem)
+  done
+fi
+
+AC_DEFUN(K5_CHECK_UT_EXIT_MEMBER,
+[AC_MSG_CHECKING([for ut_exit.$2 in struct $1])
+AC_CACHE_VAL([krb5_cv_struct_$1_ut_exit_$2],
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <$1.h>], [struct $1 u; u.ut_exit.$2;],
+eval "krb5_cv_struct_$1_ut_exit_$2=yes",
+eval "krb5_cv_struct_$1_ut_exit_$2=no")])
+if eval "test \"`echo '$krb5_cv_struct_'$1'_ut_exit_'$2`\" = yes"; then
+  AC_MSG_RESULT(yes)
+  ifelse([$3], , :, [$3])
+else
+  AC_MSG_RESULT(no)
+  ifelse([$4], , :, [$4])
+fi])
+
+if test "$krb5_cv_struct_utmp_ut_exit" = yes; then
+  AC_MSG_RESULT(checking for working ut_exit.e_exit in struct utmp)
+  for krb5_mem in __e_exit ut_e_exit ut_exit e_exit; do
+    K5_CHECK_UT_EXIT_MEMBER(utmp, $krb5_mem,
+[krb5_utmp_e_exit=$krb5_mem
+krb5_utmp_e_termination=`echo $krb5_mem|sed -e 's%_exit$%_termination%'`], )
+  done
+  if test "${krb5_utmp_e_exit+set}" = set; then
+    AC_MSG_RESULT([working ut_exit.e_exit in utmp is $krb5_utmp_e_exit])
+    AC_DEFINE_UNQUOTED(PTY_UTMP_E_EXIT, $krb5_utmp_e_exit)
+    AC_DEFINE_UNQUOTED(PTY_UTMP_E_TERMINATION, $krb5_utmp_e_termination)
+  else
+    AC_MSG_RESULT([cannot find working ut_exit.e_exit in utmp])
+  fi
+fi
+
+if test "$krb5_cv_struct_utmpx_ut_exit" = yes; then
+  AC_MSG_RESULT(checking for working ut_exit.e_exit in struct utmpx)
+  for krb5_mem in __e_exit ut_e_exit ut_exit e_exit; do
+    K5_CHECK_UT_EXIT_MEMBER(utmpx, $krb5_mem,
+[krb5_utmpx_e_exit=$krb5_mem
+krb5_utmpx_e_termination=`echo $krb5_mem|sed -e 's%_exit$%_termination%'`], )
+  done
+  if test "${krb5_utmpx_e_exit+set}" = set; then
+    AC_MSG_RESULT([working ut_exit.e_exit in utmpx is $krb5_utmpx_e_exit])
+    AC_DEFINE_UNQUOTED(PTY_UTMPX_E_EXIT, $krb5_utmpx_e_exit)
+    AC_DEFINE_UNQUOTED(PTY_UTMPX_E_TERMINATION, $krb5_utmpx_e_termination)
+  else
+    AC_MSG_RESULT([cannot find working ut_exit.e_exit in utmpx])
+  fi
+fi
+
+if test "$ac_cv_header_utmpx_h" = yes; then
+  AC_MSG_CHECKING(consistency of utmpx API)
+  if test "$ac_cv_func_setutxent" = yes; then
+    if test "$krb5_cv_struct_utmpx_ut_id" = yes \
+      && test "$krb5_cv_struct_utmpx_ut_type" = yes \
+      && test "$krb5_cv_struct_utmpx_ut_pid" = yes; then
+      AC_MSG_RESULT(ok)
+    else
+      AC_MSG_RESULT(not ok)
+      AC_MSG_ERROR([have setutxent but no ut_id, ut_type, or ut_pid in utmpx])
+    fi
+  else
+    AC_MSG_RESULT(not ok)
+    AC_MSG_ERROR([have utmpx.h but no setutxent])
+  fi
+fi
+
+if test "$ac_cv_func_setutent" = yes && \
+  test "$ac_cv_header_utmpx_h" = no; then
+  AC_MSG_CHECKING(consistency of sysV-ish utmp API)
+  if test "$ac_cv_header_utmp_h" = yes; then
+    if test "$krb5_cv_struct_utmp_ut_id" = yes \
+      && test "$krb5_cv_struct_utmp_ut_type" = yes \
+      && test "$krb5_cv_struct_utmp_ut_pid" = yes; then
+      AC_MSG_RESULT(ok)
+    else
+      AC_MSG_RESULT(not ok)
+      AC_MSG_ERROR([have setutent but no ut_id, ut_type, or ut_pid in utmp])
+    fi
+  else
+    AC_MSG_RESULT(not ok)
+    AC_MSG_ERROR([have setutent but no utmp.h])
+  fi
+fi
+
+#
+# end of utmp-related hair
+#
+######################################################################
+dnl
+KRB5_NEED_PROTO([#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+],getutmp)
+dnl
+#########################################
+KRB5_NEED_PROTO([#include <sys/types.h>
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+],logwtmp)
+########################################
+KRB5_NEED_PROTO([#include <unistd.h>
+],revoke)
+########################################
+dnl
+AC_MSG_CHECKING([streams interface])
+AC_CACHE_VAL(krb5_cv_has_streams,
+[AC_TRY_COMPILE(
+[#include <sys/stream.h>
+#include <sys/stropts.h>], [],
+krb5_cv_has_streams=yes, krb5_cv_has_streams=no)])
+AC_MSG_RESULT($krb5_cv_has_streams)
+if test $krb5_cv_has_streams = yes; then
+AC_DEFINE(HAVE_STREAMS)
+fi
+dnl
+dnl
+dnl
+AC_MSG_CHECKING([arguments to getpgrp])
+AC_CACHE_VAL(krb5_cv_getpgrp_args,
+[AC_TRY_COMPILE(
+[#ifndef __STDC__
+#define __STDC__ 1
+#endif
+#include <unistd.h>
+#include <sys/types.h>], [pid_t pid = getpgrp(getpid())],
+krb5_cv_getpgrp_args=pid, krb5_cv_getpgrp_args=void)])
+AC_MSG_RESULT($krb5_cv_getpgrp_args)
+if test $krb5_cv_getpgrp_args = pid; then
+AC_DEFINE(GETPGRP_ONEARG)
+fi
+dnl
+dnl
+AC_MSG_CHECKING([number of arguments to setpgrp])
+AC_CACHE_VAL(krb5_cv_setpgrp_args,
+[AC_TRY_COMPILE(
+[#ifndef __STDC__
+#define __STDC__ 1
+#endif
+#include <unistd.h>],[setpgrp(0,0)],
+krb5_cv_setpgrp_args=two, krb5_cv_setpgrp_args=void)])
+AC_MSG_RESULT($krb5_cv_setpgrp_args)
+if test $krb5_cv_setpgrp_args = two; then
+AC_DEFINE(SETPGRP_TWOARG)
+fi
+dnl
+KRB5_AC_INET6
+AC_C_CONST
+dnl KRB5_BUILD_LIBRARY_WITH_DEPS
+KRB5_BUILD_LIBRARY_STATIC
+KRB5_BUILD_LIBOBJS
+KRB5_BUILD_PROGRAM
+KRB5_RUN_FLAGS
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/util/pty/dump-utmp.c b/mechglue/src/util/pty/dump-utmp.c
new file mode 100644
index 000000000..d4c303fb3
--- /dev/null
+++ b/mechglue/src/util/pty/dump-utmp.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ *
+ * dump-utmp.c: dump utmp and utmpx format files for debugging purposes.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifndef UTMPX
+#ifdef HAVE_UTMPX_H
+#define UTMPX
+#endif
+#endif
+
+#if defined(HAVE_UTMPNAME) || defined(HAVE_UTMPXNAME)
+#define UTN			/* we can set utmp or utmpx for getut*() */
+#endif
+
+#ifdef UTMPX
+#include <utmpx.h>
+void print_utx(int, const struct utmpx *);
+#endif
+#include <utmp.h>
+
+void print_ut(int, const struct utmp *);
+
+void usage(const char *);
+
+#if defined (HAVE_STRUCT_UTMP_UT_TYPE) || defined (UTMPX)
+char *ut_typename(int);
+
+char *
+ut_typename(int t) {
+    switch (t) {
+#define S(N) case N : return #N
+#define S2(N,N2) case N : return #N2
+	S(EMPTY);
+	S(RUN_LVL);
+	S(BOOT_TIME);
+	S(OLD_TIME);
+	S(NEW_TIME);
+	S2(INIT_PROCESS,INIT);
+	S2(LOGIN_PROCESS,LOGIN);
+	S2(USER_PROCESS,USER);
+	S2(DEAD_PROCESS,DEAD);
+	S(ACCOUNTING);
+    default: return "??";
+    }
+}
+#endif
+
+#define S2D(x) (sizeof(x) * 2.4 + 1.5)
+
+void
+print_ut(int all, const struct utmp *u)
+{
+    int lu, ll;
+#ifdef HAVE_STRUCT_UTMP_UT_ID
+    int lid;
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_PID
+    int lpid;
+#endif
+#ifdef PTY_UTMP_E_EXIT
+    int let, lee;
+#endif
+
+#ifdef HAVE_STRUCT_UTMP_UT_TYPE
+    if (!all && ((u->ut_type == EMPTY) || (u->ut_type == DEAD_PROCESS)))
+	return;
+#endif
+
+    lu = sizeof(u->ut_name);
+    ll = sizeof(u->ut_line);
+    printf("%-*.*s:", lu, lu, u->ut_name);
+    printf("%-*.*s:", ll, ll, u->ut_line);
+#ifdef HAVE_STRUCT_UTMP_UT_ID
+    lid = sizeof(u->ut_id);
+    printf("%-*.*s:", lid, lid, u->ut_id);
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_PID
+    lpid = S2D(u->ut_pid);
+    printf("%*ld", lpid, (long)u->ut_pid);
+#endif
+#ifdef PTY_UTMP_E_EXIT
+    let = S2D(u->ut_exit.PTY_UTMP_E_TERMINATION);
+    lee = S2D(u->ut_exit.PTY_UTMP_E_EXIT);
+    printf("(%*ld,", let, (long)u->ut_exit.PTY_UTMP_E_TERMINATION);
+    printf("%*ld)", lee, (long)u->ut_exit.PTY_UTMP_E_EXIT);
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_TYPE
+    printf(" %-9s", ut_typename(u->ut_type));
+#endif
+    printf(" %s", ctime(&u->ut_time) + 4);
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    if (u->ut_host[0])
+	printf(" %.*s\n", (int) sizeof(u->ut_host), u->ut_host);
+#endif
+
+    return;
+}
+
+#ifdef UTMPX
+void
+print_utx(int all, const struct utmpx *u)
+{
+    int lu, ll, lid, lpid;
+#ifdef PTY_UTMPX_E_EXIT
+    int let, lee;
+#endif
+
+    if (!all && ((u->ut_type == EMPTY) || (u->ut_type == DEAD_PROCESS)))
+	return;
+
+    lu = sizeof(u->ut_user);
+    ll = sizeof(u->ut_line);
+    lid = sizeof(u->ut_id);
+    printf("%-*.*s:", lu, lu, u->ut_user);
+    printf("%-*.*s:", ll, ll, u->ut_line);
+    printf("%-*.*s", lid, lid, u->ut_id);
+    if (lu + ll + lid >= 60)
+	printf("\n");
+    else
+	printf(":");
+    lpid = S2D(u->ut_pid);
+    printf("%*ld", lpid, (long)u->ut_pid);
+#ifdef PTY_UTMPX_E_EXIT
+    let = S2D(u->ut_exit.PTY_UTMPX_E_TERMINATION);
+    lee = S2D(u->ut_exit.PTY_UTMPX_E_EXIT);
+    printf("(%*ld,", let, (long)u->ut_exit.PTY_UTMPX_E_TERMINATION);
+    printf("%*ld)", lee, (long)u->ut_exit.PTY_UTMPX_E_EXIT);
+#endif
+    printf(" %-9s", ut_typename(u->ut_type));
+    printf(" %s", ctime(&u->ut_tv.tv_sec) + 4);
+#ifdef HAVE_STRUCT_UTMPX_UT_HOST
+    if (u->ut_host[0])
+	printf(" %s\n", u->ut_host);
+#endif
+
+    return;
+}
+#endif
+
+#ifdef UTMPX
+#define OPTX "x"
+#else
+#define OPTX
+#endif
+#ifdef UTN
+#define OPTG "g"
+#else
+#define OPTG
+#endif
+#define OPTS "a" OPTX OPTG
+
+void
+usage(const char *prog)
+{
+    fprintf(stderr, "usage: %s [-" OPTS "] file\n", prog);
+    exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+    int c;
+    int all, is_utmpx, do_getut;
+    int f;
+    char *fn;
+    size_t recsize;
+    size_t nread;
+    union {
+	struct utmp ut;
+#ifdef UTMPX
+	struct utmpx utx;
+#endif
+    } u;
+
+    all = is_utmpx = do_getut = 0;
+    recsize = sizeof(struct utmp);
+
+    while ((c = getopt(argc, argv, OPTS)) != EOF) {
+	switch (c) {
+	case 'a':
+	    all = 1;
+	    break;
+#ifdef UTMPX
+	case 'x':
+	    is_utmpx = 1;
+	    recsize = sizeof(struct utmpx);
+	    break;
+#endif
+#ifdef UTN
+	case 'g':
+	    do_getut = 1;
+	    break;
+#endif
+	default:
+	    usage(argv[0]);
+	}
+    }
+    if (argc <= optind)
+	usage(argv[0]);
+    fn = argv[optind];
+    if (!do_getut) {
+	f = open(fn, O_RDONLY);
+	if (f == -1) {
+	    perror(fn);
+	    exit(1);
+	}
+	while ((nread = read(f, &u, recsize)) > 0) {
+	    if (nread < recsize) {
+		fprintf(stderr, "short read");
+		close(f);
+		exit(1);
+	    }
+	    if (is_utmpx) {
+#ifdef UTMPX
+		print_utx(all, &u.utx);
+#else
+		abort();
+#endif
+	    } else {
+		print_ut(all, &u.ut);
+	    }
+	}
+	if (nread == -1) {
+	    perror("read");
+	    exit(1);
+	}
+	close(f);
+    } else {
+	if (is_utmpx) {
+#ifdef UTMPX
+#ifdef HAVE_UTMPXNAME
+	    struct utmpx *utxp;
+	    utmpxname(fn);
+	    setutxent();
+	    while ((utxp = getutxent()) != NULL)
+		print_utx(all, utxp);
+#else
+	    fprintf(stderr, "no utmpxname(); can't use getutxent()\n");
+	    exit(1);
+#endif
+#else
+	    abort();
+#endif
+	} else {
+#ifdef HAVE_UTMPNAME
+	    struct utmp *utp;
+	    utmpname(fn);
+	    setutxent();
+	    while ((utp = getutent()) != NULL)
+		print_ut(all, utp);
+#else
+	    fprintf(stderr, "no utmpname(); can't use getutent()\n");
+	    exit(1);
+#endif
+	}
+    }
+    exit(0);    
+}
diff --git a/mechglue/src/util/pty/getpty.c b/mechglue/src/util/pty/getpty.c
new file mode 100644
index 000000000..610a471e6
--- /dev/null
+++ b/mechglue/src/util/pty/getpty.c
@@ -0,0 +1,150 @@
+/*
+ * pty_getpty: open a PTY master.
+ *
+ * Copyright 1995, 1996 by the Massachusetts Institute of Technology.
+ *
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+long
+ptyint_getpty_ext(int *fd, char *slave, int slavelength, int do_grantpt)
+{
+#if !defined(HAVE__GETPTY) && !defined(HAVE_OPENPTY)
+    char *cp;
+    char *p;
+    int i,ptynum;
+    struct stat stb;
+    char slavebuf[1024];
+#endif
+
+#ifdef HAVE__GETPTY
+    char *slaveret; /*Temporary to hold pointer to slave*/
+#endif /*HAVE__GETPTY*/
+
+#ifdef HAVE_OPENPTY
+    int slavefd;
+
+    if(openpty(fd, &slavefd, slave, (struct termios *) 0,
+         (struct winsize *) 0)) return 1;
+    close(slavefd);
+    return 0;
+#else /*HAVE_OPENPTY*/
+#ifdef HAVE__GETPTY
+    /* This code is included for Irix; as of version 5.3, Irix has /dev/ptmx,
+     * but it fails to work properly; even after calling unlockpt,
+     * root gets permission denied opening the pty.
+     * The code to support _getpty should be removed if Irix gets working
+     * streams ptys in favor of maintaining the least needed code
+     * paths.
+     */
+    if ((slaveret = _getpty(fd, O_RDWR|O_NDELAY, 0600, 0)) == 0) {
+	*fd = -1;
+	return PTY_GETPTY_NOPTY;
+    }
+    if (strlen(slaveret) > slavelength - 1) {
+	close(*fd);
+	*fd = -1;
+	return PTY_GETPTY_SLAVE_TOOLONG;
+    }
+    else strcpy(slave, slaveret);
+    return 0;
+#else /*HAVE__GETPTY*/
+    
+    *fd = open("/dev/ptym/clone", O_RDWR|O_NDELAY);	/* HPUX*/
+#ifdef HAVE_STREAMS
+    if (*fd < 0) *fd = open("/dev/ptmx",O_RDWR|O_NDELAY); /*Solaris*/
+#endif
+    if (*fd < 0) *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */
+    if (*fd < 0) *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */
+
+    if (*fd >= 0) {
+
+#if defined(HAVE_GRANTPT)&&defined(HAVE_STREAMS)
+	if (do_grantpt)
+	    if (grantpt(*fd) || unlockpt(*fd)) return PTY_GETPTY_STREAMS;
+#endif
+    
+#ifdef HAVE_PTSNAME
+	p = ptsname(*fd);
+#else
+#ifdef	HAVE_TTYNAME
+	p = ttyname(*fd);
+#else
+	/* XXX If we don't have either what do we do */
+#endif
+#endif
+	if (p) {
+	    if (strlen(p) > slavelength - 1) {
+		    close (*fd);
+		    *fd = -1;
+		    return PTY_GETPTY_SLAVE_TOOLONG;
+	    }
+	    strcpy(slave, p);
+	    return 0;
+	}
+
+	if (fstat(*fd, &stb) < 0) {
+	    close(*fd);
+	    return PTY_GETPTY_FSTAT;
+	}
+	ptynum = (int)(stb.st_rdev&0xFF);
+	sprintf(slavebuf, "/dev/ttyp%x", ptynum);
+	if (strlen(slavebuf) > slavelength - 1) {
+	    close(*fd);
+	    *fd = -1;
+	    return PTY_GETPTY_SLAVE_TOOLONG;
+	}
+	strncpy(slave, slavebuf, slavelength);
+	return 0;
+    } else {
+    	for (cp = "pqrstuvwxyzPQRST";*cp; cp++) {
+	    sprintf(slavebuf,"/dev/ptyXX");
+	    slavebuf[sizeof("/dev/pty") - 1] = *cp;
+	    slavebuf[sizeof("/dev/ptyp") - 1] = '0';
+	    if (stat(slavebuf, &stb) < 0)
+		break;
+	    for (i = 0; i < 16; i++) {
+		slavebuf[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
+		*fd = open(slavebuf, O_RDWR);
+		if (*fd < 0) continue;
+
+		/* got pty */
+		slavebuf[sizeof("/dev/") - 1] = 't';
+		if (strlen(slavebuf) > slavelength -1) {
+		    close(*fd);
+		    *fd = -1;
+		    return PTY_GETPTY_SLAVE_TOOLONG;
+		}
+		strncpy(slave, slavebuf, slavelength);
+		return 0;
+	    }
+	}
+	return PTY_GETPTY_NOPTY;
+    }
+#endif /*HAVE__GETPTY*/
+#endif /* HAVE_OPENPTY */
+}
+
+long
+pty_getpty(int *fd, char *slave, int slavelength)
+{
+    return ptyint_getpty_ext(fd, slave, slavelength, 1);
+}
diff --git a/mechglue/src/util/pty/init.c b/mechglue/src/util/pty/init.c
new file mode 100644
index 000000000..b48a1f8a7
--- /dev/null
+++ b/mechglue/src/util/pty/init.c
@@ -0,0 +1,33 @@
+/*
+ * pty_init: Initialize internal state of pty.
+ * 
+ * Currently initializes error tables.
+ * 
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ *
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+long pty_init(void)
+{
+    initialize_pty_error_table();
+    return 0;
+}
diff --git a/mechglue/src/util/pty/init_slave.c b/mechglue/src/util/pty/init_slave.c
new file mode 100644
index 000000000..ce7507645
--- /dev/null
+++ b/mechglue/src/util/pty/init_slave.c
@@ -0,0 +1,100 @@
+/*
+ * pty_init_slave: open slave side of terminal, clearing for use.
+ *
+ * Copyright 1995, 1996 by the Massachusetts Institute of Technology.
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+/* * The following is an array of modules that should be pushed on the
+ *  stream.  See configure.in for caviats and notes about when this
+ *  array is used and not used.
+ */
+#if defined(HAVE_STREAMS)&&(!defined(HAVE_LINE_PUSH))
+static char *push_list[] = {
+#ifdef PUSH_PTEM
+  "ptem",
+#endif
+#ifdef PUSH_LDTERM
+  "ldterm",
+#endif
+#ifdef PUSH_TTCOMPAT
+"ttcompat",
+#endif
+  0};
+#endif /*HAVE_STREAMS but not HAVE_LINE_PUSH*/
+
+ 
+
+long pty_initialize_slave (int fd)
+{
+#if defined(POSIX_TERMIOS) && !defined(ultrix)
+    struct termios new_termio;
+#else
+    struct sgttyb b;
+#endif /* POSIX_TERMIOS */
+    int pid;
+	    
+#ifdef HAVE_STREAMS
+#ifdef HAVE_LINE_PUSH
+        while (ioctl (fd, I_POP, 0) == 0); /*Clear out any old lined's*/
+
+    if (line_push(fd) < 0)
+	{
+	    (void) close(fd); fd = -1;
+	    return PTY_OPEN_SLAVE_LINE_PUSHFAIL;
+	}
+#else /*No line_push */
+    {
+       char **module = &push_list[0];
+      while (*module)
+		if (ioctl(fd, I_PUSH, *(module++)) < 0)
+		  	return PTY_OPEN_SLAVE_PUSH_FAIL;
+    }
+
+#endif /*LINE_PUSH*/
+#endif /*HAVE_STREAMS*/
+
+    /*
+	 * Under Ultrix 3.0, the pgrp of the slave pty terminal
+	 * needs to be set explicitly.  Why rlogind works at all
+	 * without this on 4.3BSD is a mystery.
+	 */
+#ifdef GETPGRP_ONEARG
+    pid = getpgrp(getpid());
+#else
+    pid = getpgrp();
+#endif
+
+#ifdef TIOCSPGRP
+    ioctl(fd, TIOCSPGRP, &pid);
+#endif
+
+    
+#if defined(POSIX_TERMIOS) && !defined(ultrix)
+	tcsetpgrp(fd, pid);
+	tcgetattr(fd,&new_termio);
+	new_termio.c_cc[VMIN] = 1;
+	new_termio.c_cc[VTIME] = 0;
+    tcsetattr(fd,TCSANOW,&new_termio);
+#endif /* POSIX_TERMIOS */
+
+    return 0;
+}
diff --git a/mechglue/src/util/pty/libpty.h b/mechglue/src/util/pty/libpty.h
new file mode 100644
index 000000000..d95c8fe08
--- /dev/null
+++ b/mechglue/src/util/pty/libpty.h
@@ -0,0 +1,54 @@
+/*
+ * Header file for manipulation of ptys and utmp entries.
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ *
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#ifndef __LIBPTY_H__
+
+/* Constants for pty_update_utmp */
+#define PTY_LOGIN_PROCESS 0
+#define PTY_USER_PROCESS 1
+#define PTY_DEAD_PROCESS 2
+
+/* flags to update_utmp*/
+#define PTY_TTYSLOT_USABLE (0x1)
+#define PTY_UTMP_USERNAME_VALID (0x2)
+
+long pty_init(void);
+long pty_getpty ( int *fd, char *slave, int slavelength);
+
+long pty_open_slave (const char *slave, int *fd);
+long pty_open_ctty (const char *slave, int *fd);
+
+long pty_initialize_slave ( int fd);
+long pty_update_utmp(int process_type, int pid, const char *user,
+		     const char *tty_line, const char *host, int flags);
+
+long pty_logwtmp(const char *tty, const char *user, const char *host);
+
+long pty_cleanup(char *slave, int pid, int update_utmp);
+
+#ifndef SOCK_DGRAM
+struct sockaddr;
+#endif
+
+long pty_make_sane_hostname(const struct sockaddr *, int, int, int, char **);
+#define __LIBPTY_H__
+#endif
diff --git a/mechglue/src/util/pty/logwtmp.c b/mechglue/src/util/pty/logwtmp.c
new file mode 100644
index 000000000..21a35d3a9
--- /dev/null
+++ b/mechglue/src/util/pty/logwtmp.c
@@ -0,0 +1,112 @@
+/*
+ * pty_logwtmp: Implement the logwtmp function if not present.
+ *
+ * Copyright 1995, 2001 by the Massachusetts Institute of Technology.
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+#if defined(HAVE_SETUTXENT) || defined(HAVE_SETUTENT)
+#ifdef HAVE_SETUTXENT
+#define PTY_STRUCT_UTMPX struct utmpx
+#else
+#define PTY_STRUCT_UTMPX struct utmp
+#endif
+
+#ifdef NEED_LOGWTMP_PROTO
+void logwtmp(const char *, const char *, const char *);
+#endif
+
+long
+pty_logwtmp(const char *tty, const char *user, const char *host)
+{
+#ifndef HAVE_LOGWTMP
+    PTY_STRUCT_UTMPX utx;
+    int loggingin;
+    size_t len;
+    const char *cp;
+    char utmp_id[5];
+#endif
+
+#ifdef HAVE_LOGWTMP
+    logwtmp(tty,user,host);
+    return 0;
+#else
+
+    loggingin = (user[0] != '\0');
+
+    memset(&utx, 0, sizeof(utx));
+    strncpy(utx.ut_line, tty, sizeof(utx.ut_line));
+    strncpy(utx.ut_user, user, sizeof(utx.ut_user));
+#if (defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMPX_UT_HOST))	   \
+	|| (!defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMP_UT_HOST))
+    strncpy(utx.ut_host, host, sizeof(utx.ut_host));
+    utx.ut_host[sizeof(utx.ut_host) - 1] = '\0';
+#endif
+#ifdef HAVE_SETUTXENT
+    gettimeofday(&utx.ut_tv, NULL);
+#else
+    (void)time(&utx.ut_time);
+#endif
+    utx.ut_pid = (loggingin ? getpid() : 0);
+    utx.ut_type = (loggingin ? USER_PROCESS : DEAD_PROCESS);
+
+    len = strlen(tty);
+    if (len >= 2)
+	cp = tty + len - 2;
+    else
+	cp = tty;
+    sprintf(utmp_id, "kr%s", cp);
+    strncpy(utx.ut_id, utmp_id, sizeof(utx.ut_id));
+
+#ifdef HAVE_SETUTXENT
+    return ptyint_update_wtmpx(&utx);
+#else
+    return ptyint_update_wtmp(&utx);
+#endif
+
+#endif /* !HAVE_LOGWTMP */
+}
+
+#else  /* !(defined(HAVE_SETUTXENT) || defined(HAVE_SETUTENT)) */
+
+long
+pty_logwtmp(const char *tty, const char *user, const char *host)
+{
+    struct utmp ut;
+
+#ifdef HAVE_LOGWTMP
+    logwtmp(tty,user,host);
+    return 0;
+#else
+
+    memset(&ut, 0, sizeof(ut));
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+    ut.ut_host[sizeof(ut.ut_host) - 1] = '\0';
+#endif
+    strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
+    strncpy(ut.ut_name, user, sizeof(ut.ut_name));
+    return ptyint_update_wtmp(&ut);
+
+#endif /* !HAVE_LOGWTMP */
+}
+
+#endif /* !(defined(HAVE_SETUTXENT) || defined(HAVE_SETUTENT)) */
diff --git a/mechglue/src/util/pty/open_ctty.c b/mechglue/src/util/pty/open_ctty.c
new file mode 100644
index 000000000..5a1730b31
--- /dev/null
+++ b/mechglue/src/util/pty/open_ctty.c
@@ -0,0 +1,67 @@
+/*
+ * pty_open_ctty: Open and establish controlling terminal.
+ *
+ * Copyright 1995, 1996 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+/* 
+ * This function will be called twice.  The first time it will acquire
+ * a controlling terminal from which to vhangup() or revoke() (see
+ * comments in open_slave.c); the second time, it will be to open the
+ * actual slave device for use by the application.  We no longer call
+ * ptyint_void_association(), as that will be called in
+ * pty_open_slave() to avoid spurious calls to setsid(), etc.
+ *
+ * It is assumed that systems where vhangup() exists and does break
+ * the ctty association will allow the slave to be re-acquired as the
+ * ctty.  Also, if revoke() or vhangup() doesn't break the ctty
+ * association, we assume that we can successfully reopen the slave.
+ *
+ * This function doesn't check whether we actually acquired the ctty;
+ * we assume that the caller will check that, or that it doesn't
+ * matter in the particular case.
+ */
+long
+pty_open_ctty(const char *slave, int *fd)
+{
+
+#ifdef ultrix
+    /*
+     * The Ultrix (and other BSD tty drivers) require the process
+     * group to be zero, in order to acquire the new tty as a
+     * controlling tty.  This may actually belong in
+     * ptyint_void_association().
+     */
+    (void) setpgrp(0, 0);
+#endif
+    *fd = open(slave, O_RDWR);
+    if (*fd < 0)
+	return PTY_OPEN_SLAVE_OPENFAIL;
+#ifdef ultrix
+    setpgrp(0, getpid());
+#endif
+
+#ifdef TIOCSCTTY
+    ioctl(*fd, TIOCSCTTY, 0); /* Don't check return.*/
+#endif /* TIOCSTTY */
+    return 0;
+}
diff --git a/mechglue/src/util/pty/open_slave.c b/mechglue/src/util/pty/open_slave.c
new file mode 100644
index 000000000..5bab6bc36
--- /dev/null
+++ b/mechglue/src/util/pty/open_slave.c
@@ -0,0 +1,101 @@
+/*
+ * pty_open_slave: open slave side of terminal, clearing for use.
+ *
+ * Copyright 1995, 1996, 2001 by the Massachusetts Institute of
+ * Technology.
+ *
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+long
+pty_open_slave(const char *slave, int *fd)
+{
+    int tmpfd;
+    long retval;
+
+    /* Sanity check. */
+    if (slave == NULL || *slave == '\0')
+	return PTY_OPEN_SLAVE_TOOSHORT;
+
+    /* First, set up a new session and void old associations. */
+    ptyint_void_association();
+
+    /*
+     * Make a first attempt at acquiring the ctty under certain
+     * condisions.  This is necessary for several reasons:
+     *
+     * Under Irix, if you open a pty slave and then close it, a
+     * subsequent open of the slave will cause the master to read EOF.
+     * To prevent this, don't close the first fd until we do the real
+     * open following vhangup().
+     *
+     * Under Tru64 v5.0, if there isn't a fd open on the slave,
+     * revoke() fails with ENOTTY, curiously enough.
+     *
+     * Anyway, sshd seems to make a practice of doing this.
+     */
+#if defined(VHANG_FIRST) || defined(REVOKE_NEEDS_OPEN)
+    retval = pty_open_ctty(slave, fd);
+    if (retval)
+	return retval;
+    if (*fd < 0)
+	return PTY_OPEN_SLAVE_OPENFAIL;
+#endif
+
+    /* chmod and chown the slave. */
+    if (chmod(slave, 0))
+	return PTY_OPEN_SLAVE_CHMODFAIL;
+    if (chown(slave, 0, 0) == -1)
+	return PTY_OPEN_SLAVE_CHOWNFAIL;
+
+#ifdef HAVE_REVOKE
+    if (revoke(slave) < 0) {
+	return PTY_OPEN_SLAVE_REVOKEFAIL;
+    }
+#else /* !HAVE_REVOKE */
+#ifdef VHANG_FIRST
+    ptyint_vhangup();
+#endif
+#endif /* !HAVE_REVOKE */
+
+    /* Open the pty for real. */
+    retval = pty_open_ctty(slave, &tmpfd);
+#if defined(VHANG_FIRST) || defined(REVOKE_NEEDS_OPEN)
+    close(*fd);
+#endif
+    if (retval) {
+	*fd = -1;
+	return PTY_OPEN_SLAVE_OPENFAIL;
+    }
+    *fd = tmpfd;
+    retval = pty_initialize_slave(*fd);
+    if (retval)
+	return retval;
+    /* Make sure it's really our ctty. */
+    tmpfd = open("/dev/tty", O_RDWR|O_NDELAY);
+    if (tmpfd < 0) {
+	close(*fd);
+	*fd = -1;
+	return PTY_OPEN_SLAVE_NOCTTY;
+    }
+    close(tmpfd);
+    return 0;
+}
diff --git a/mechglue/src/util/pty/pty-int.h b/mechglue/src/util/pty/pty-int.h
new file mode 100644
index 000000000..30f01d6ab
--- /dev/null
+++ b/mechglue/src/util/pty/pty-int.h
@@ -0,0 +1,136 @@
+/* Includes needed by libpty*/
+#ifndef __PTY_INT_H__
+#include <pty_err.h>
+#include <sys/types.h>
+
+#if defined(_AIX) && defined(_THREAD_SAFE)
+/* On AIX 4.3.3, both utmp.h and utmpx.h will define struct utmp_data,
+   and they'll define them differently, if _THREAD_SAFE is defined.
+
+   We don't actually care about this library being thread-safe, but
+   for various reasons we do use both versions of the interface at the
+   moment.
+
+   So trick the system headers into not "helping" us in that area.
+
+   This is an ugly hack, and shouldn't be needed.  Bleah.  */
+# undef _THREAD_SAFE
+#endif
+
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef __SCO__
+#include <sys/unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pwd.h>
+     
+#ifdef HAVE_SYS_LABEL_H
+/* only SunOS 4? */
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+     
+#include <signal.h>
+
+#ifdef hpux
+#include <sys/ptyio.h>
+#endif
+#ifdef sysvimp
+#include <compat.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_STREAMS
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#endif
+
+#if defined(POSIX_TERMIOS) && !defined(ultrix)
+#include <termios.h>
+#else
+#include <sgtty.h>
+#endif
+     
+#include "port-sockets.h"
+#include <string.h>
+#include <sys/param.h>
+
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+
+#ifdef HAVE_STREAMS
+/* krlogin doesn't test sys/tty... */
+#ifdef HAVE_SYS_TTY_H
+#include <sys/tty.h>
+#endif
+
+
+
+#ifdef HAVE_SYS_PTYVAR_H
+/* Solaris actually uses packet mode, so the real macros are needed too */
+#include <sys/ptyvar.h>
+#endif
+#endif
+
+#if defined(HAVE_VHANGUP) && !defined(OPEN_CTTY_ONLY_ONCE) \
+	&& !defined(HAVE_REVOKE)
+/*
+ * Breaks under Ultrix and others where you cannot get controlling
+ * terminal twice.
+ */
+#define VHANG_FIRST
+#define VHANG_LAST
+#endif
+
+#if defined(NEED_GETUTMPX_PROTOTYPE)
+extern void getutmpx (const struct utmp *, struct utmpx *);
+#endif
+
+#if defined(NEED_REVOKE_PROTO)
+extern int revoke(const char *);
+#endif
+
+/* Internal functions */
+long ptyint_void_association(void);
+long ptyint_open_ctty (char *slave, int *fd);
+long ptyint_getpty_ext(int *, char *, int, int);
+#ifdef HAVE_SETUTXENT
+long ptyint_update_wtmpx(struct utmpx *utx);
+#endif
+#if !(defined(WTMPX_FILE) && defined(HAVE_UPDWTMPX)) \
+	|| !defined(HAVE_SETUXENT)
+long ptyint_update_wtmp(struct utmp *ut);
+#endif
+void ptyint_vhangup(void);
+
+#define __PTY_INT_H__
+#endif
diff --git a/mechglue/src/util/pty/pty_err.et b/mechglue/src/util/pty/pty_err.et
new file mode 100644
index 000000000..770cce7a9
--- /dev/null
+++ b/mechglue/src/util/pty/pty_err.et
@@ -0,0 +1,50 @@
+#
+# util/pty/pty_err.et
+#
+# Copyright 1995 by the Massachusetts Institute of Technology.
+# All Rights Reserved.
+#
+# 
+# Permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+
+# libpty--pty handling error table
+
+error_table pty
+
+error_code PTY_GETPTY_STREAMS, "Failed to unlock or grant streams pty."
+
+error_code PTY_GETPTY_FSTAT, "fstat of master pty failed"
+
+error_code PTY_GETPTY_NOPTY, "All terminal ports in use"
+
+error_code PTY_GETPTY_SLAVE_TOOLONG, "buffer to hold slave pty name is too short"
+
+error_code PTY_OPEN_SLAVE_OPENFAIL, "Failed to open slave side of pty"
+error_code PTY_OPEN_SLAVE_CHMODFAIL, "Failed to chmod slave side of pty"
+
+error_code PTY_OPEN_SLAVE_NOCTTY, "Unable to set controlling terminal"
+error_code PTY_OPEN_SLAVE_CHOWNFAIL, "Failed to chown slave side of pty"
+error_code PTY_OPEN_SLAVE_LINE_PUSHFAIL, "Call to line_push failed to push streams on slave pty"
+
+error_code PTY_OPEN_SLAVE_PUSH_FAIL, "Failed to push stream on slave side of pty"
+
+
+error_code PTY_OPEN_SLAVE_REVOKEFAIL, "Failed to revoke slave side of pty"
+
+error_code PTY_UPDATE_UTMP_PROCTYPE_INVALID, "bad process type passed to pty_update_utmp"
+error_code PTY_OPEN_SLAVE_TOOSHORT, "Slave pty name is zero-length"
+
+end
diff --git a/mechglue/src/util/pty/pty_paranoia.c b/mechglue/src/util/pty/pty_paranoia.c
new file mode 100644
index 000000000..466a65888
--- /dev/null
+++ b/mechglue/src/util/pty/pty_paranoia.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright 2001 by the Massachusetts Institute of Technology.
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+/*
+ * A rant on the nature of pseudo-terminals:
+ * -----------------------------------------
+ *
+ * Controlling terminals and job control:
+ *
+ * First, some explanation of job control and controlling terminals is
+ * necessary for background.  This discussion applies to hardwired
+ * terminals as well as ptys.  On most modern systems, all processes
+ * belong to a process group.  A process whose process group id (pgid)
+ * is the sames as its pid is the process group leader of its process
+ * group.  Process groups belong to sessions.  On a modern system, a
+ * process that is not currently a process group leader may create a
+ * new session by calling setsid(), which makes it a session leader as
+ * well as a process group leader, and also removes any existing
+ * controlling terminal (ctty) association.  Only a session leader may
+ * acquire a ctty.  It's not clear how systems that don't have
+ * setsid() handle ctty acquisition, though probably any process group
+ * leader that doesn't have a ctty may acquire one that way.
+ *
+ * A terminal that is a ctty has an associated foreground process
+ * group, which is a member of the terminal's associated session.
+ * This process group gets read/write access to the terminal and will
+ * receive terminal-generated signals (e.g. SIGINT, SIGTSTP).  Process
+ * groups belonging to the session but not in the foreground may get
+ * signals that suspend them if they try to read/write from the ctty,
+ * depending on various terminal settings.
+ *
+ * On many systems, the controlling process (the session leader
+ * associated with a ctty) exiting will cause the session to lose its
+ * ctty, even though some processes may continue to have open file
+ * descriptors on the former ctty.  It is possible for a process to
+ * have no file descriptors open on its controlling tty, but to
+ * reacquire such by opening /dev/tty, as long as its session still
+ * has a ctty.
+ *
+ * On ptys in general:
+ *
+ * Ptys have a slave side and a master side.  The slave side looks
+ * like a hardwired serial line to the application that opens it;
+ * usually, telnetd or rlogind, etc. opens the slave and hands it to
+ * the login program as stdin/stdout/stderr.  The master side usually
+ * gets the actual network traffic written to/from it.  Roughly, the
+ * master and slave are two ends of a bidirectional pair of FIFOs,
+ * though this can get complicated by other things.
+ *
+ * The master side of a pty is theoretically a single-open device.
+ * This MUST be true on systems that have BSD-style ptys, since there
+ * is usually no way to allocate an unused pty except by attempting to
+ * open all the master pty nodes in the system.
+ *
+ * Often, but not always, the last close of a slave device will cause
+ * the master to get an EOF.  Closing the master device will sometimes
+ * cause the foreground process group of the slave to get a SIGHUP,
+ * but that may depend on terminal settings.
+ *
+ * BSD ptys:
+ *
+ * On a BSD-derived system, the master nodes are named like
+ * /dev/ptyp0, and the slave nodes are named like /dev/ttyp0.  The
+ * last two characters are the variable ones, and a shell-glob type
+ * pattern for a slave device is usually of the form
+ * /dev/tty[p-z][0-9a-f], though variants are known to exist.
+ *
+ * System V cloning ptys:
+ *
+ * There is a cloning master device (usually /dev/ptmx, but the name
+ * can vary) that gets opened.  Each open of the cloning master
+ * results in an open file descriptor of a unique master device.  The
+ * application calls ptsname() to find the pathname to the slave node.
+ *
+ * In theory, the slave side of the pty is locked out until the
+ * process opening the master calls grantpt() to adjust permissions
+ * and unlockpt() to unlock the slave.  It turns out that Unix98
+ * doesn't require that the slave actually get locked out, or that
+ * unlockpt() actually do anything on such systems.  At least AIX
+ * allows the slave to be opened prior to calling unlockpt(), but most
+ * other SysV-ish systems seem to actually lock out the slave.
+ *
+ * Pty security:
+ *
+ * It's not guaranteed on a BSD-ish system that a slave can't be
+ * opened when the master isn't open.  It's even possible to acquire
+ * the slave as a ctty (!) if the open is done as non-blocking.  It's
+ * possible to open the master corresponding to an open slave, which
+ * creates some security issues: once this master is open, data
+ * written to the slave will actually pass to the master.
+ *
+ * On a SysV-ish system, the close of the master will invalidate any
+ * open file descriptors on the slave.
+ *
+ * In general, there are two functions that can be used to "clean" a
+ * pty slave, revoke() and vhangup().  revoke() will invalidate all
+ * file descriptors open on a particular pathname (often this only
+ * works on terminal devices), usually by invalidating the underlying
+ * vnode.  vhangup() will send a SIGHUP to the foreground process
+ * group of the control terminal.  On many systems, it also has
+ * revoke() semantics.
+ *
+ * If a process acquires a controlling terminal in order to perform a
+ * vhangup(), the reopen of the controlling terminal after the
+ * vhangup() call should be done prior to the close of the file
+ * descriptor used to initially acquire the controlling terminal,
+ * since that will likely prevent the process on the master side from
+ * reading a spurious EOF due to all file descriptors to the slave
+ * being closed.
+ *
+ * Known quirks of various OSes:
+ *
+ * AIX 4.3.3:
+ *
+ * If the environment variable XPG_SUS_ENV is not equal to "ON", then
+ * it's possible to open the slave prior to calling unlockpt().
+ */
+
+/*
+ * NOTE: this program will get reworked at some point to actually test
+ * passing of data between master and slave, and to do general cleanup.
+ *
+ * This is rather complex, so it bears some explanation.
+ *
+ * There are multiple child processes and a parent process.  These
+ * communicate via pipes (which we assume here to be unidirectional).
+ * The pipes are:
+ *
+ * pp1 - parent -> any children
+ *
+ * p1p - any children -> parent
+ *
+ * p21 - only child2 -> child1
+ *
+ * A parent process will acquire a pty master and slave via
+ * pty_getpty().  It will then fork a process, child1.  It then does a
+ * waitpid() for child1, and then writes to child2 via syncpipe pp1.
+ * It then reads from child3 via syncpipe p1p, then closes the
+ * master.  It writes to child3 via syncpipe pp1 to indicate that it
+ * has closed the master.  It then reads from child3 via syncpipe p1p
+ * and exits with a value appropriate to what it read from child3.
+ *
+ * child1 will acquire the slave as its ctty and fork child2; child1
+ * will exit once it reads from the syncpipe p21 from child2.
+ *
+ * child2 will set a signal handler for SIGHUP and then write to
+ * child1 via syncpipe p21 to indicate that child2 has set up the
+ * handler.  It will then read from the syncpipe pp1 from the parent
+ * to confirm that the parent has seen child1 exit, and then checks to
+ * see if it still has a ctty.  Under Unix98, and likely earlier
+ * System V derivatives, the exiting of the session leader associated
+ * with a ctty (in this case, child1) will cause the entire session to
+ * lose its ctty.
+ *
+ * child2 will then check to see if it can reopen the slave, and
+ * whether it has a ctty after reopening it.  This should fail on most
+ * systems.
+ *
+ * child2 will then fork child3 and immediately exit.
+ *
+ * child3 will write to the syncpipe p1p and read from the syncpipe
+ * pp1.  It will then check if it has a ctty and then attempt to
+ * reopen the slave.  This should fail.  It will then write to the
+ * parent via syncpipe p1p and exit.
+ *
+ * If this doesn't fail, child3 will attempt to write to the open
+ * slave fd.  This should fail unless a prior call to revoke(),
+ * etc. failed due to lack of permissions, e.g. NetBSD when running as
+ * non-root.
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+#include <sys/wait.h>
+#include <stdlib.h>
+
+char *prog;
+int masterfd, slavefd;
+char slave[64], slave2[64];
+pid_t pid1, pid2, pid3;
+int status1, status2;
+int pp1[2], p1p[2], p21[2];
+
+void handler(int);
+void rdsync(int, int *, const char *);
+void wrsync(int, int, const char *);
+void testctty(const char *);
+void testex(int, const char *);
+void testwr(int, const char *);
+void child1(void);
+void child2(void);
+void child3(void);
+
+void
+handler(int sig)
+{
+    printf("pid %ld got signal %d\n", (long)getpid(), sig);
+    fflush(stdout);
+    return;
+}
+
+void
+rdsync(int fd, int *status, const char *caller)
+{
+    int n;
+    char c;
+
+#if 0
+    printf("rdsync: %s: starting\n", caller);
+    fflush(stdout);
+#endif
+    while ((n = read(fd, &c, 1)) < 0) {
+	if (errno != EINTR) {
+	    fprintf(stderr, "rdsync: %s", caller);
+	    perror("");
+	    exit(1);
+	} else {
+	    printf("rdsync: %s: got EINTR; looping\n", caller);
+	    fflush(stdout);
+	}
+    }
+    if (!n) {
+	fprintf(stderr, "rdsync: %s: unexpected EOF\n", caller);
+	exit(1);
+    }
+    printf("rdsync: %s: got sync byte\n", caller);
+    fflush(stdout);
+    if (status != NULL)
+	*status = c;
+}
+
+void
+wrsync(int fd, int status, const char *caller)
+{
+    int n;
+    char c;
+
+    c = status;
+    while ((n = write(fd, &c, 1)) < 0) {
+	if (errno != EINTR) {
+	    fprintf(stderr, "wrsync: %s", caller);
+	    perror("");
+	    exit(1);
+	} else {
+	    printf("wrsync: %s: got EINTR; looping\n", caller);
+	    fflush(stdout);
+	}
+    }
+#if 0
+    printf("wrsync: %s: sent sync byte\n", caller);
+#endif
+    fflush(stdout);
+}
+
+void
+testctty(const char *caller)
+{
+    int fd;
+
+    fd = open("/dev/tty", O_RDWR|O_NONBLOCK);
+    if (fd < 0) {
+	printf("%s: no ctty\n", caller);
+    } else {
+	printf("%s: have ctty\n", caller);
+    }
+}
+
+void
+testex(int fd, const char *caller)
+{
+    fd_set rfds, xfds;
+    struct timeval timeout;
+    int n;
+    char c;
+
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+    FD_ZERO(&rfds);
+    FD_ZERO(&xfds);
+    FD_SET(fd, &rfds);
+    FD_SET(fd, &xfds);
+
+    n = select(fd + 1, &rfds, NULL, &xfds, &timeout);
+    if (n < 0) {
+	fprintf(stderr, "testex: %s: ", caller);
+	perror("select");
+    }
+    if (n) {
+	if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &xfds)) {
+	    n = read(fd, &c, 1);
+	    if (!n) {
+		printf("testex: %s: got EOF\n", caller);
+		fflush(stdout);
+		return;
+	    } else if (n == -1) {
+		printf("testex: %s: got errno=%ld (%s)\n",
+		       caller, (long)errno, strerror(errno));
+	    } else {
+		printf("testex: %s: read 1 byte!?\n", caller);
+	    }
+	}
+    } else {
+	printf("testex: %s: no exceptions or readable fds\n", caller);
+    }
+}
+
+void
+testwr(int fd, const char *caller)
+{
+    fd_set wfds;
+    struct timeval timeout;
+    int n;
+
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+    FD_ZERO(&wfds);
+    FD_SET(fd, &wfds);
+
+    n = select(fd + 1, NULL, &wfds, NULL, &timeout);
+    if (n < 0) {
+	fprintf(stderr, "testwr: %s: ", caller);
+	perror("select");
+    }
+    if (n) {
+	if (FD_ISSET(fd, &wfds)) {
+	    printf("testwr: %s: is writable\n", caller);
+	    fflush(stdout);
+	}
+    }
+}
+
+
+void
+child3(void)
+{
+    int n;
+
+    ptyint_void_association();
+    slavefd = open(slave, O_RDWR|O_NONBLOCK);
+    if (slavefd < 0) {
+	wrsync(p1p[1], 1, "[02] child3->parent");
+	printf("child3: failed reopen of slave\n");
+	fflush(stdout);
+	exit(1);
+    }
+#ifdef TIOCSCTTY
+    ioctl(slavefd, TIOCSCTTY, 0);
+#endif
+
+    printf("child3: reopened slave\n");
+    testctty("child3: after reopen of slave");
+    testwr(slavefd, "child3: after reopen of slave");
+    testex(slavefd, "child3: after reopen of slave");
+    close(slavefd);
+    testctty("child3: after close of slave");
+
+    /*
+     * Sync for parent to close master.
+     */
+    wrsync(p1p[1], 0, "[02] child3->parent");
+    rdsync(pp1[0], NULL, "[03] parent->child3");
+
+    testctty("child3: after close of master");
+    printf("child3: attempting reopen of slave\n");
+    fflush(stdout);
+    slavefd = open(slave, O_RDWR|O_NONBLOCK);
+    if (slavefd < 0) {
+	printf("child3: failed reopen of slave after master close: "
+	       "errno=%ld (%s)\n", (long)errno, strerror(errno));
+	wrsync(p1p[1], 0, "[04] child3->parent");
+	fflush(stdout);
+	exit(0);
+    }
+    if (fcntl(slavefd, F_SETFL, 0) == -1) {
+	perror("child3: fcntl");
+	wrsync(p1p[1], 2, "[04] child3->parent");
+	exit(1);
+    }
+#ifdef TIOCSCTTY
+    ioctl(slavefd, TIOCSCTTY, 0);
+#endif
+    printf("child3: reopened slave after master close\n");
+    testctty("child3: after reopen of slave after master close");
+    testwr(slavefd, "child3: after reopen of slave after master close");
+    testex(slavefd, "child3: after reopen of slave after master close");
+    n = write(slavefd, "foo", 4);
+    if (n < 0) {
+	printf("child3: writing to slave of closed master: errno=%ld (%s)\n",
+	       (long)errno, strerror(errno));
+	wrsync(p1p[1], 1, "[04] child3->parent");
+    } else {
+	printf("child3: wrote %d byes to slave of closed master\n", n);
+	fflush(stdout);
+	wrsync(p1p[1], 2, "[04] child3->parent");
+    }
+    rdsync(pp1[0], NULL, "[05] parent->child3");
+    testex(slavefd, "child3: after parent reopen of master");
+    testwr(slavefd, "child3: after parent reopen of master");
+    fflush(stdout);
+    n = write(slavefd, "bar", 4);
+    if (n < 0) {
+	perror("child3: writing to slave");
+    } else {
+	printf("child3: wrote %d bytes to slave\n", n);
+	fflush(stdout);
+    }
+    wrsync(p1p[1], 0, "[06] child3->parent");
+    rdsync(pp1[0], NULL, "[07] parent->child3");
+    wrsync(p1p[1], 0, "[08] child3->parent");
+    exit(0);
+}
+
+void
+child2(void)
+{
+    struct sigaction sa;
+
+    close(p21[0]);
+    setpgid(0, 0);
+    sa.sa_flags = 0;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_handler = handler;
+    if (sigaction(SIGHUP, &sa, NULL) < 0) {
+	wrsync(p21[1], 1, "[00] child2->child1");
+	perror("child2: sigaction");
+	fflush(stdout);
+	exit(1);
+    }
+    printf("child2: set up signal handler\n");
+    testctty("child2: after start");
+    testwr(slavefd, "child2: after start");
+    wrsync(p21[1], 0, "[00] child2->child1");
+    rdsync(pp1[0], NULL, "[01] parent->child2");
+
+    testctty("child2: after child1 exit");
+    testex(slavefd, "child2: after child1 exit");
+    testwr(slavefd, "child2: after child1 exit");
+    close(slavefd);
+    testctty("child2: after close of slavefd");
+    slavefd = open(slave, O_RDWR|O_NONBLOCK);
+    if (slavefd < 0) {
+	wrsync(p1p[1], 1, "[02] child2->parent");
+	printf("child2: failed reopen of slave\n");
+	fflush(stdout);
+	exit(1);
+    }
+#ifdef TIOCSCTTY
+    ioctl(slavefd, TIOCSCTTY, 0);
+#endif
+    printf("child2: reopened slave\n");
+    testctty("child2: after reopen of slave");
+    fflush(stdout);
+    close(slavefd);
+    pid3 = fork();
+    if (!pid3) {
+	child3();
+    } else if (pid3 == -1) {
+	wrsync(p1p[1], 1, "[02] child2->parent");
+	perror("child2: fork of child3");
+	exit(1);
+    }
+    printf("child2: forked child3=%ld\n", (long)pid3);
+    fflush(stdout);
+    exit(0);
+}
+
+void
+child1(void)
+{
+    int status;
+
+#if 0
+    setuid(1);
+#endif
+    close(pp1[1]);
+    close(p1p[0]);
+    close(masterfd);
+    ptyint_void_association();
+    slavefd = open(slave, O_RDWR|O_NONBLOCK);
+    if (slavefd < 0) {
+	perror("child1: open slave");
+	exit(1);
+    }
+#ifdef TIOCSCTTY
+    ioctl(slavefd, TIOCSCTTY, 0);
+#endif
+
+    printf("child1: opened slave\n");
+    testctty("child1: after slave open");
+
+    if (pipe(p21) < 0) {
+	perror("pipe child2->child1");
+	exit(1);
+    }
+    pid2 = fork();
+    if (!pid2) {
+	child2();
+    } else if (pid2 == -1) {
+	perror("child1: fork child2");
+	exit(1);
+    }
+    close(p21[1]);
+    printf("child1: forked child2=%ld\n", (long)pid2);
+    fflush(stdout);
+    rdsync(p21[0], &status, "[00] child2->child1");
+    exit(status);
+}
+
+int
+main(int argc, char *argv[])
+{
+    long retval;
+    int status;
+    char buf[4];
+    int n;
+
+    prog = argv[0];
+
+    printf("parent: pid=%ld\n", (long)getpid());
+
+    retval = ptyint_getpty_ext(&masterfd, slave, sizeof(slave), 0);
+
+    if (retval) {
+	com_err(prog, retval, "open master");
+	exit(1);
+    }
+#if 0
+    chown(slave, 1, -1);
+#endif
+    printf("parent: master opened; slave=%s\n", slave);
+    fflush(stdout);
+
+#if defined(HAVE_GRANTPT) && defined(HAVE_STREAMS)
+#ifdef O_NOCTTY
+    printf("parent: attempting to open slave before unlockpt\n");
+    fflush(stdout);
+    slavefd = open(slave, O_RDWR|O_NONBLOCK|O_NOCTTY);
+    if (slavefd < 0) {
+	printf("parent: failed slave open before unlockpt errno=%ld (%s)\n",
+	       (long)errno, strerror(errno));
+    } else {
+	printf("parent: WARNING: "
+	       "succeeded in opening slave before unlockpt\n");
+    }
+    close(slavefd);
+#endif
+    if (grantpt(masterfd) < 0) {
+	perror("parent: grantpt");
+	exit(1);
+    }
+    if (unlockpt(masterfd) < 0) {
+	perror("parent: unlockpt");
+	exit(1);
+    }
+#endif /* HAVE_GRANTPT && HAVE_STREAMS */
+
+    if (pipe(pp1) < 0) {
+	perror("pipe parent->child1");
+	exit(1);
+    }
+    if (pipe(p1p) < 0) {
+	perror("pipe child1->parent");
+	exit(1);
+    }
+
+    pid1 = fork();
+    if (!pid1) {
+	child1();
+    } else if (pid1 == -1) {
+	perror("fork of child1");
+	exit(1);
+    }
+    printf("parent: forked child1=%ld\n", (long)pid1);
+    fflush(stdout);
+    if (waitpid(pid1, &status1, 0) < 0) {
+	perror("waitpid for child1");
+	exit(1);
+    }
+    printf("parent: child1 exited, status=%d\n", status1);
+    if (status1)
+	exit(status1);
+
+    wrsync(pp1[1], 0, "[01] parent->child2");
+    rdsync(p1p[0], &status, "[02] child3->parent");
+    if (status) {
+	fprintf(stderr, "child2 or child3 got an error\n");
+	exit(1);
+    }
+
+    printf("parent: closing master\n");
+    fflush(stdout);
+    close(masterfd);
+    chmod(slave, 0666);
+    printf("parent: closed master\n");
+    wrsync(pp1[1], 0, "[03] parent->child3");
+
+    rdsync(p1p[0], &status, "[04] child3->parent");
+    switch (status) {
+    case 1:
+	break;
+    case 0:
+	exit(0);
+    default:
+	fprintf(stderr, "child3 got an error\n");
+	fflush(stdout);
+	exit(1);
+    }
+
+    retval = pty_getpty(&masterfd, slave2, sizeof(slave2));
+    printf("parent: new master opened; slave=%s\n", slave2);
+#if 0
+#ifdef HAVE_REVOKE
+    printf("parent: revoking\n");
+    revoke(slave2);
+#endif
+#endif
+    fflush(stdout);
+    wrsync(pp1[1], 0, "[05] parent->child3");
+    rdsync(p1p[0], NULL, "[06] child3->parent");
+
+    n = read(masterfd, buf, 4);
+    if (n < 0) {
+	perror("parent: reading from master");
+    } else {
+	printf("parent: read %d bytes (%.*s) from master\n", n, n, buf);
+	fflush(stdout);
+    }
+    chmod(slave2, 0666);
+    close(masterfd);
+    wrsync(pp1[1], 0, "[07] parent->child3");
+    rdsync(p1p[0], NULL, "[08] child3->parent");
+    fflush(stdout);
+    exit(0);
+}
diff --git a/mechglue/src/util/pty/sane_hostname.c b/mechglue/src/util/pty/sane_hostname.c
new file mode 100644
index 000000000..8ef6de875
--- /dev/null
+++ b/mechglue/src/util/pty/sane_hostname.c
@@ -0,0 +1,116 @@
+/*
+ * pty_make_sane_hostname: Make a sane hostname from an IP address.
+ * This returns allocated memory!
+ * 
+ * Copyright 1999, 2000, 2001 by the Massachusetts Institute of
+ * Technology.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+#include "com_err.h"
+#include "pty-int.h"
+#include <sys/socket.h>
+#include "libpty.h"
+#include <arpa/inet.h>
+
+#include "socket-utils.h"
+#include "fake-addrinfo.h"
+
+static void
+downcase (char *s)
+{
+    for (; *s != '\0'; s++)
+	*s = tolower ((int) *s);
+}
+
+long
+pty_make_sane_hostname(const struct sockaddr *addr, int maxlen,
+		       int strip_ldomain, int always_ipaddr, char **out)
+{
+    struct addrinfo *ai = 0;
+    char addrbuf[NI_MAXHOST];
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    struct utmp ut;
+#else
+    struct utmpx utx;
+#endif
+    char *cp, *domain;
+    char lhost[MAXHOSTNAMELEN];
+    size_t ut_host_len;
+
+    /* Note that on some systems (e.g., AIX 4.3.3), we may get an IPv6
+       address such as ::FFFF:18.18.1.71 when an IPv4 connection comes
+       in.  That's okay; at least on AIX, getnameinfo will deal with
+       that properly.  */
+
+    *out = NULL;
+    if (maxlen && maxlen < 16)
+	/* assume they meant 16, otherwise IPv4 addr won't fit */
+	maxlen = 16;
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    ut_host_len = sizeof (ut.ut_host);
+#else
+    ut_host_len = sizeof (utx.ut_host);
+#endif
+    if (maxlen == 0)
+	maxlen = ut_host_len;
+    *out = malloc(ut_host_len);
+    if (*out == NULL)
+	return ENOMEM;
+
+    if (always_ipaddr) {
+    use_ipaddr:
+	if (getnameinfo (addr, socklen (addr), addrbuf, sizeof (addrbuf),
+			 (char *)0, 0, NI_NUMERICHOST) == 0)
+	    strncpy(*out, addrbuf, ut_host_len);
+	else
+	    strncpy(*out, "??", ut_host_len);
+	(*out)[ut_host_len - 1] = '\0';
+	return 0;
+    }
+
+    /* If we didn't want to chop off the local domain, this would be
+       much simpler -- just a single getnameinfo call and a strncpy.  */
+    if (getnameinfo(addr, socklen (addr), addrbuf, sizeof (addrbuf),
+		    (char *) NULL, 0, NI_NAMEREQD) != 0)
+	goto use_ipaddr;
+    downcase (addrbuf);
+    if (strip_ldomain) {
+	struct addrinfo hints;
+	(void) gethostname(lhost, sizeof (lhost));
+	memset (&hints, 0, sizeof (hints));
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_flags = AI_CANONNAME;
+	if (getaddrinfo(lhost, (char *)NULL, &hints, &ai) == 0
+	    && ai != NULL) {
+		if (ai->ai_canonname != NULL) {
+			downcase (ai->ai_canonname);
+			domain = strchr (ai->ai_canonname, '.');
+			if (domain != NULL) {
+				cp = strstr (addrbuf, domain);
+				if (cp != NULL)
+					*cp = '\0';
+			}
+		}
+		freeaddrinfo (ai);
+	}
+    }
+    strncpy(*out, addrbuf, ut_host_len);
+    (*out)[ut_host_len - 1] = '\0';
+    if (strlen(*out) >= maxlen)
+	goto use_ipaddr;
+    return 0;
+}
diff --git a/mechglue/src/util/pty/update_utmp.c b/mechglue/src/util/pty/update_utmp.c
new file mode 100644
index 000000000..004582650
--- /dev/null
+++ b/mechglue/src/util/pty/update_utmp.c
@@ -0,0 +1,706 @@
+/*
+ * pty_update_utmp: Update or create a utmp entry
+ * 
+ * Copyright 1995, 2001 by the Massachusetts Institute of Technology.
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+/*
+ * Rant about the historical vagaries of utmp:
+ * -------------------------------------------
+ *
+ * There exist many subtly incompatible incarnations of utmp, ranging
+ * from BSD to System V to Unix98 and everywhere in between.  This
+ * rant attempts to collect in one place as much knowledge as possible
+ * about this portability nightmare.
+ *
+ * BSD:
+ * ----
+ *
+ * The simplest (and earliest? possibly dating back to Version 7...)
+ * case is 4.x BSD utmp/wtmp.  There are no auxiliary files.  There is
+ * only a struct utmp, declared in utmp.h.  Its contents usually
+ * include:
+ *
+ *	char ut_line[]
+ *	char ut_name[]
+ *	char ut_host[]
+ *	long ut_time
+ *
+ * The meanings of these fields follow their names reasonbly well.
+ * The ut_line field usually is the pathname of the tty device
+ * associated with the login, with the leading "/dev/" stripped off.
+ *
+ * It is believed that ut_host is nul-terminated, while the other
+ * strings are merely nul-padded.
+ *
+ * Generally, ut_name is an empty string for a logout record in both
+ * utmp and wtmp.  For entries made by the window system or other
+ * terminal emulation stuff, ut_host is an empty string (at least
+ * under SunOS 4.x, it seems).  The macro nonuser() is used to
+ * determine this if a utmp entry is made by the window system on at
+ * least SunOS 4.x.
+ *
+ * The native login never clears its own utmp entry or writes its own
+ * logout record; its parent (one of init, rlogind, telnetd, etc.)
+ * should handle that.  In theory, getty could do that, but getty
+ * usually doesn't fork to exec login.
+ *
+ * Old (c. 1984) System V:
+ * -----------------------
+ *
+ * This is partially conjecture, based on some reading of
+ * /usr/xpg2include/utmp.h on a SunOS 4.x system.  There appears to
+ * only be a struct utmp, declared in utmp.h.  It is likely used for
+ * both utmp and wtmp files.  It is quite likely that the utmp is only
+ * supposed to be accessed via the getutline()/pututline() API.  The
+ * contents of struct utmp seem to include:
+ *
+ *	char	ut_user[]
+ *	char	ut_id[]
+ *	char	ut_line[]
+ *	short	ut_pid
+ *	short	ut_type
+ *	struct exit_status ut_exit
+ *	time_t	ut_time
+ *
+ * On these systems, ut_name is often #define'ed to be ut_user to be
+ * somewhat compatible with the BSD-style utmp.  Note that there is
+ * not necessarily a ut_host field in this utmp structure.
+ *
+ * The ut_id field bears some explanation.  The systems that use this
+ * style of utmp also use a sysV-ish init, which starts processes out
+ * of /etc/inittab rather than /etc/ttys, and has the concept of
+ * runlevels.  The first field in each line of /etc/inittab contains a
+ * unique ID field.  init probably gets really confused if there are
+ * conflicts here.  Every process that init starts gets its own entry
+ * written to utmp.
+ *
+ * It is possible for multiple entries to have the same ut_line but
+ * different ut_id values, since the sysadmin will be responsible for
+ * assigning values to ut_id.  Usually, ut_id is four characters,
+ * while the permissible unique ID values for entries in /etc/inittab
+ * are constrained to two characters, but this is not always the
+ * case.  In the case where we are emulating the vendor's login
+ * program and being run out of getty, we need to account for which
+ * value of ut_id was used by the getty, since pututline() will search
+ * based on ut_id and not ut_line for some reason.
+ *
+ * The ut_pid and ut_type fields are used for bookkeeping by init.
+ * The ut_type field gets the value INIT_PROCESS for processes started
+ * by init.  It gets the value LOGIN_PROCESS if it is a process that
+ * is prompting for a login name, and it gets the value USER_PROCESS
+ * for an actual valid login.  When the process dies, either init
+ * cleans up after it and records a DEAD_PROCESS entry in utmp, or the
+ * process itself does so.  It's not completely clear which actually
+ * happens, though it is quite possible that init only cleans up after
+ * processes that it starts itself.
+ *
+ * Other values of ut_type exist; they're largely internal bookkeeping
+ * for init's runlevels and such, and don't really interest this
+ * library at all.
+ *
+ * The ut_exit field contains the following members:
+ *
+ *	short	e_termination
+ *	short	e_exit
+ *
+ * It is not clear how these values are used; presumably they record
+ * the process termination status of dead processes.
+ *
+ * There is no uniform API for manipulating wtmp on systems that use
+ * this sort of utmp structure; it can be assumed that the structure
+ * can be directly written to the wtmp file.
+ *
+ * Unix98:
+ * -------
+ *
+ * This description also likely applies to later System V derivatives
+ * as well as systems conforming to earlier X/Open standards such as
+ * XPG4.  There is a new header, utmpx.h, which defines a struct utmpx
+ * and a new getutxline()/pututxline() API for accessing it.  Some
+ * systems actually have a utmpx file on disk; others use the utmpx
+ * API to access a file named utmp, just to further confuse matters.
+ *
+ * The utmpx structure is guaranteed (by Unix98) to contain at least
+ * the following:
+ *
+ *	char	ut_user[]
+ *	char	ut_line[]
+ *	char	ut_id[]
+ *	pid_t	ut_pid
+ *	short	ut_type
+ *	struct timeval ut_tv
+ *
+ * It is not guaranteed to contain, but often does contain, the
+ * following:
+ *
+ *	char	ut_host[]
+ *	int	ut_syslen
+ *	int	ut_session
+ *	struct exit_status ut_exit
+ *
+ * The ut_syslen field, on systems that contain it, contains the
+ * number of significant characters in ut_host, including the
+ * terminating nul character.
+ *
+ * The main difference between this struct utmpx and the struct utmp
+ * used by early sysV derivatives is the change from a time_t or long
+ * for ut_time to a struct timeval for ut_tv.
+ *
+ * Comments in various header files imply that ut_session is used for
+ * window systems, but it's not clear how.  Perhaps it contains the
+ * session ID of the session running the window system, e.g. the xdm
+ * or X server on an X11 system.
+ *
+ * Most of the description of the earlier sysV format probably applies
+ * here, with suitable changes of names.  On systems that maintain
+ * utmpx and utmp files in parallel, it is assumed that using the
+ * pututxline() API is sufficient to keep them in sync.  There are no
+ * known counterexamples to this.
+ *
+ * Nevertheless, there are, on some systems, API functions getutmp()
+ * and getutmpx() that appear to convert from struct utmpx to struct
+ * utmp and vice versa.  This could be useful when there is a wtmp
+ * file but not a corresponding wtmpx file.
+ *
+ * Incidentally, ut_exit is sometimes present in the struct utmp but
+ * not the struct utmpx for a given system.  Sometimes, it exists in
+ * both, but contains differently named members.  It's probably one of
+ * the least portable pieces in this whole mess.
+ *
+ * Known Quirks of Specific OSes:
+ * ------------------------------
+ *
+ * Solaris 2.x:
+ *
+ * Has utmpd, which will automatically clean up utmpx, utmp, wtmpx,
+ * wtmp after process termination, provided that pututxline() was
+ * used.
+ *
+ * Solaris 8 seems to have a bug in utmpname() that causes
+ * garbage filenames to be generated.  Solaris 7 (and possibly Solaris
+ * 8) have a bug in utmpxname() that prevents them from looking at
+ * anything other than /var/adm/utmpx, it seems.  For some reason,
+ * though, utmpname() goes and looks at the corresponding utmpx file.
+ *
+ * Solaris 7 (and may be 8 as well) has a bug in pututline() that
+ * interacts badly with prior invocation of getutline(): if
+ * getutline() finds an entry, calling pututline() without first
+ * calling setutent() will overwrite the record following the one that
+ * was intended.
+ *
+ * Also, ut_exit in utmpx contains ut_e_termination and
+ * ut_e_exit (otherwise it contains the expected e_termination and
+ * e_exit) only if _XPG4_2 is defined and __EXTENSIONS__ is not, which
+ * is not a compilation environment we're likely to encourage.  The
+ * ut_exit field of utmp contains the expected fields.
+ *
+ * If _XPG4_2 is not defined or __EXTENSIONS__ is defined, the
+ * functions getutmp(), getutmpx(), updwtmp(), and updwtmpx() are
+ * available, as well as the undocumented functions makeutx() and
+ * modutx().
+ *
+ * All the files utmp, utmpx, wtmp, and wtmpx exist.
+ *
+ * HP-UX 10.x:
+ *
+ * There is a curious interaction between how we allocate pty masters
+ * and how ttyname() works.  It seems that if /dev/ptmx/clone is
+ * opened, a call to ptsname() on the master fd gets a filename of the
+ * form /dev/pty/tty[pqrs][0-9a-f], while ttyname() called on a fd
+ * opened with that filename returns a filename of the form
+ * /dev/tty[pqrs][0-9a-f] instead.  These two filenames are actually
+ * hardlinks to the same special device node, so it shouldn't be a
+ * security problem.
+ *
+ * We can't call ttyname() in the parent because it would involve
+ * possibly acquiring a controlling terminal (which would be
+ * potentially problematic), so we have to resort to some trickery in
+ * order to ensure that the ut_line in the wtmp logout and login
+ * records match.  If they don't match, various utilities such as last
+ * will get confused.  Of course it's likely an OS bug that ttyname()
+ * and ptsname() are inconsistent in this way, but it's one that isn't
+ * too painful to work around.
+ *
+ * It seems that the HP-UX native telnetd has problems similar to ours
+ * in this area, though it manages to write the correct logout record
+ * to wtmp somehow.  It probably does basically what we do here:
+ * search for a record with a matching ut_pid and grab its ut_line for
+ * writing into the logout record.  Interestingly enough, its
+ * LOGIN_PROCESS record is of the form pty/tty[pqrs][0-9][a-f].
+ *
+ * Uses four-character unique IDs for /etc/inittab, which means that
+ * programs not running out of init should use two-character ut_id
+ * fields to avoid conflict.
+ *
+ * In utmpx, ut_exit contains __e_termination and __e_exit, while
+ * ut_exit in utmp contains the expected fields.
+ *
+ * There is no wtmpx file, despite there being utmp and utmpx files.
+ *
+ * Irix 6.x:
+ *
+ * In utmpx, ut_exit contains __e_termination and __e_exit, which get
+ * #define aliases e_termination and e_exit if _NO_XOPEN4 is true.
+ * Curiously enough, utmp.h declares ut_exit to have __e_termination
+ * and __e_exit as well, but does #define e_termination
+ * __e_termination, etc. if another header (utmpx.h) hasn't already
+ * declared struct __exit_status.  It seems that the default
+ * compilation environment has the effect of making _NO_XOPEN4 true
+ * though.
+ *
+ * If _NO_XOPEN4 is true, getutmp(), getutmpx(), updwtmp(), and
+ * updwtmpx() are available, as well as the undocumented functions
+ * makeutx() and modutx().
+ *
+ * All the files utmp, utmpx, wtmp, and wtmpx exist.
+ *
+ * Tru64 Unix 4.x:
+ *
+ * In utmpx, ut_exit contains ut_termination and ut_exit, while utmp
+ * contains the expected fields.  The files utmp and wtmp seem to
+ * exist, but not utmpx or wtmpx.
+ *
+ * When writing a logout entry, the presence of a non-empty username
+ * confuses last.
+ *
+ * AIX 4.3.x:
+ *
+ * The ut_exit field seems to exist in utmp, but not utmpx. The files
+ * utmp and wtmp seem to exist, but not utmpx, or wtmpx.
+ *
+ * libpty Implementation Decisions:
+ * --------------------------------
+ *
+ * We choose to use the pututxline() whenever possible, falling back
+ * to pututline() and calling write() to write out struct utmp if
+ * necessary.  The code to handle pututxline() and pututline() is
+ * rather similar, since the structure members are quite similar, and
+ * we make the assumption that it will never be necessary to call
+ * both.  This allows us to avoid duplicating lots of code, by means
+ * of some slightly demented macros.
+ *
+ * If neither pututxline() nor pututline() are available, we assume
+ * BSD-style utmp files and behave accordingly, writing the structure
+ * out to disk ourselves.
+ *
+ * On systems where updwtmpx() or updwtmp() are available, we use
+ * those to update the wtmpx or wtmp file.  When they're not
+ * available, we write the utmpx or utmp structure out to disk
+ * ourselves, though sometimes conversion from utmpx to utmp format is
+ * needed.
+ *
+ * We assume that at logout the system is ok with with having an empty
+ * username both in utmp and wtmp.
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+#if !defined(UTMP_FILE) && defined(_PATH_UTMP)
+#define UTMP_FILE _PATH_UTMP
+#endif
+
+/* if it is *still* missing, assume SunOS */
+#ifndef UTMP_FILE
+#define	UTMP_FILE	"/etc/utmp"
+#endif
+
+/*
+ * The following grossness exists to avoid duplicating lots of code
+ * between the cases where we have an old-style sysV utmp and where we
+ * have a modern (Unix98 or XPG4) utmpx.  See the above history rant
+ * for further explanation.
+ */
+#if defined(HAVE_SETUTXENT) || defined(HAVE_SETUTENT)
+#ifdef HAVE_SETUTXENT
+#define PTY_STRUCT_UTMPX struct utmpx
+#define PTY_SETUTXENT setutxent
+#define PTY_GETUTXENT getutxent
+#define PTY_GETUTXLINE getutxline
+#define PTY_PUTUTXLINE pututxline
+#define PTY_ENDUTXENT endutxent
+#else
+#define PTY_STRUCT_UTMPX struct utmp
+#define PTY_SETUTXENT setutent
+#define PTY_GETUTXENT getutent
+#define PTY_GETUTXLINE getutline
+#define PTY_PUTUTXLINE pututline
+#define PTY_ENDUTXENT endutent
+#endif
+
+static int better(const PTY_STRUCT_UTMPX *, const PTY_STRUCT_UTMPX *,
+		  const PTY_STRUCT_UTMPX *);
+static int match_pid(const PTY_STRUCT_UTMPX *,
+		     const PTY_STRUCT_UTMPX *);
+static PTY_STRUCT_UTMPX *best_utxent(const PTY_STRUCT_UTMPX *);
+
+/*
+ * Utility function to determine whether A is a better match for
+ * SEARCH than B.  Should only be called by best_utxent().
+ */
+static int
+better(const PTY_STRUCT_UTMPX *search,
+       const PTY_STRUCT_UTMPX *a, const PTY_STRUCT_UTMPX *b)
+{
+    if (strncmp(search->ut_id, b->ut_id, sizeof(b->ut_id))) {
+	if (!strncmp(search->ut_id, a->ut_id, sizeof(a->ut_id))) {
+	    return 1;
+	}
+    }
+
+    if (strncmp(a->ut_id, b->ut_id, sizeof(b->ut_id))) {
+	/* Got different UT_IDs; find the right one. */
+	if (!strncmp(search->ut_id, b->ut_id, sizeof(b->ut_id))) {
+	    /* Old entry already matches; use it. */
+	    return 0;
+	}
+	if (a->ut_type == LOGIN_PROCESS
+	    && b->ut_type != LOGIN_PROCESS) {
+	    /* Prefer LOGIN_PROCESS */
+	    return 1;
+	}
+	if (search->ut_type == DEAD_PROCESS
+	    && a->ut_type == USER_PROCESS
+	    && b->ut_type != USER_PROCESS) {
+	    /*
+	     * Try USER_PROCESS if we're entering a DEAD_PROCESS.
+	     */
+	    return 1;
+	}
+	return 0;
+    } else {
+	/*
+	 * Bad juju.  We shouldn't get two entries with identical
+	 * ut_id fields for the same value of ut_line.  pututxline()
+	 * will probably pick the first entry, in spite of the strange
+	 * state of utmpx, if we rewind with setutxent() first.
+	 *
+	 * For now, return 0, to force the earlier entry to be used.
+	 */
+	return 0;
+    }
+}
+
+static int
+match_pid(const PTY_STRUCT_UTMPX *search, const PTY_STRUCT_UTMPX *u)
+{
+    if (u->ut_type != LOGIN_PROCESS && u->ut_type != USER_PROCESS)
+	return 0;
+    if (u->ut_pid == search->ut_pid) {
+	/*
+	 * One of ut_line or ut_id should match, else some nastiness
+	 * may result.  We can fall back to searching by ut_line if
+	 * need be.  This should only really break if we're login.krb5
+	 * running out of getty, or we're cleaning up after the vendor
+	 * login, and either the vendor login or the getty has
+	 * different ideas than we do of what both ut_id and ut_line
+	 * should be.  It should be rare, though.  We may want to
+	 * remove this restriction later.
+	 */
+	if (!strncmp(u->ut_line, search->ut_line, sizeof(u->ut_line)))
+	    return 1;
+	if (!strncmp(u->ut_id, search->ut_id, sizeof(u->ut_id)))
+	    return 1;
+    }
+    return 0;
+}
+
+/*
+ * This expects to be called with SEARCH pointing to a struct utmpx
+ * with its ut_type equal to USER_PROCESS or DEAD_PROCESS, since if
+ * we're making a LOGIN_PROCESS entry, we presumably don't care about
+ * preserving existing state.  At the very least, the ut_pid, ut_line,
+ * ut_id, and ut_type fields must be filled in by the caller.
+ */
+static PTY_STRUCT_UTMPX *
+best_utxent(const PTY_STRUCT_UTMPX *search)
+{
+    PTY_STRUCT_UTMPX utxtmp, *utxp;
+    int i, best;
+
+    memset(&utxtmp, 0, sizeof(utxtmp));
+
+    /*
+     * First, search based on pid, but only if non-zero.
+     */
+    if (search->ut_pid) {
+	i = 0;
+	PTY_SETUTXENT();
+	while ((utxp = PTY_GETUTXENT()) != NULL) {
+	    if (match_pid(search, utxp)) {
+		return utxp;
+	    }
+	    i++;
+	}
+    }
+    /*
+     * Uh-oh, someone didn't enter our pid.  Try valiantly to search
+     * by terminal line.
+     */
+    i = 0;
+    best = -1;
+    PTY_SETUTXENT();
+    while ((utxp = PTY_GETUTXLINE(search)) != NULL) {
+	if (better(search, utxp, &utxtmp)) {
+	    utxtmp = *utxp;
+	    best = i;
+	}
+	memset(utxp, 0, sizeof(*utxp));
+	i++;
+    }
+    if (best == -1)
+	return NULL;
+    PTY_SETUTXENT();
+    for (i = 0; i <= best; i++) {
+	if (utxp != NULL)
+	    memset(utxp, 0, sizeof(*utxp));
+	utxp = PTY_GETUTXLINE(search);
+    }
+    return utxp;
+}
+
+/*
+ * All calls to this function for a given login session must have the
+ * pids be equal; various things will break if this is not the case,
+ * since we do some searching based on the pid.  Note that if a parent
+ * process calls this via pty_cleanup(), it should still pass the
+ * child's pid rather than its own.
+ */
+long
+pty_update_utmp(int process_type, int pid, const char *username,
+		    const char *line, const char *host, int flags)
+{
+    PTY_STRUCT_UTMPX utx, *utxtmp, utx2;
+    const char *cp;
+    size_t len;
+    char utmp_id[5];
+
+    /*
+     * Zero things out in case there are fields we don't handle here.
+     * They tend to be non-portable anyway.
+     */
+    memset(&utx, 0, sizeof(utx));
+    utxtmp = NULL;
+    cp = line;
+    if (strncmp(cp, "/dev/", sizeof("/dev/") - 1) == 0)
+	cp += sizeof("/dev/") - 1;
+    strncpy(utx.ut_line, cp, sizeof(utx.ut_line));
+    utx.ut_pid = pid;
+    switch (process_type) {
+    case PTY_LOGIN_PROCESS:
+	utx.ut_type = LOGIN_PROCESS;
+	break;
+    case PTY_USER_PROCESS:
+	utx.ut_type = USER_PROCESS;
+	break;
+    case PTY_DEAD_PROCESS:
+	utx.ut_type = DEAD_PROCESS;
+	break;
+    default:
+	return PTY_UPDATE_UTMP_PROCTYPE_INVALID;
+    }
+    len = strlen(line);
+    if (len >= 2) {
+	cp = line + len - 1;
+	if (*(cp - 1) != '/')
+	    cp--;		/* last two characters, unless it's a / */
+    } else
+	cp = line;
+    /*
+     * HP-UX has mostly 4-character inittab ids, while most other sysV
+     * variants use only 2-charcter inittab ids, so to avoid
+     * conflicts, we pick 2-character ut_ids for our own use.  We may
+     * want to feature-test for this, but it would be somewhat of a
+     * pain, and would eit cross-compiling.
+     */
+#ifdef __hpux
+    strcpy(utmp_id, cp);
+#else
+    if (len > 2 && *(cp - 1) != '/')
+      sprintf(utmp_id, "k%s", cp - 1);
+    else
+      sprintf(utmp_id, "k0%s", cp);
+#endif
+    strncpy(utx.ut_id, utmp_id, sizeof(utx.ut_id));
+    /*
+     * Get existing utmpx entry for PID or LINE, if any, so we can
+     * copy some stuff from it.  This is particularly important if we
+     * are login.krb5 and are running out of getty, since getty will
+     * have written the entry for the line with ut_type ==
+     * LOGIN_PROCESS, and what it has recorded in ut_id may not be
+     * what we come up with, since that's up to the whim of the
+     * sysadmin who writes the inittab entry.
+     *
+     * Note that we may be screwed if we try to write a logout record
+     * for a vendor's login program, since it may construct ut_line
+     * and ut_id differently from us; even though we search on ut_pid,
+     * we validate against ut_id or ut_line to sanity-check.  We may
+     * want to rethink whether to actually include this check, since
+     * it should be highly unlikely that there will be a bogus entry
+     * in utmpx matching our pid.
+     */
+    if (process_type != PTY_LOGIN_PROCESS)
+	utxtmp = best_utxent(&utx);
+
+#ifdef HAVE_SETUTXENT
+    if (gettimeofday(&utx.ut_tv, NULL))
+	return errno;
+#else
+    (void)time(&utx.ut_time);
+#endif
+    /*
+     * On what system is there not ut_host?  Unix98 doesn't mandate
+     * this field, but we have yet to see a system that supports utmpx
+     * that doesn't have it.  For what it's worth, some ancient utmp
+     * headers on svr4 systems imply that there's no ut_host in struct
+     * utmp...
+     */
+#if (defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMPX_UT_HOST))	\
+	|| (!defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMP_UT_HOST))
+    if (host != NULL) {
+	strncpy(utx.ut_host, host, sizeof(utx.ut_host));
+	/* Unlike other things in utmpx, ut_host is nul-terminated? */
+	utx.ut_host[sizeof(utx.ut_host) - 1] = '\0';
+    } else
+	utx.ut_host[0] = '\0';
+#if (defined(HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMPX_UT_SYSLEN))	\
+	|| (!defined (HAVE_SETUTXENT) && defined(HAVE_STRUCT_UTMP_UT_SYSLEN))
+    if (host != NULL)
+	utx.ut_syslen = strlen(utx.ut_host) + 1;
+    else
+	utx.ut_syslen = 0;
+#endif
+#endif
+
+    /* XXX deal with ut_addr? */
+
+    if (utxtmp != NULL) {
+	/*
+	 * For entries not of type LOGIN_PROCESS, override some stuff
+	 * with what was in the previous entry we found, if any.
+	 */
+	strncpy(utx.ut_id, utxtmp->ut_id, sizeof(utx.ut_id));
+	utx.ut_pid = utxtmp->ut_pid;
+    }
+
+    strncpy(utx.ut_user, username, sizeof(utx.ut_user));
+
+    /*
+     * Make a copy now and deal with copying relevant things out of
+     * utxtmp in case setutxline() or pututxline() clobbers utxtmp.
+     * (After all, the returned pointer from the getutx*() functions
+     * is allowed to point to static storage that may get overwritten
+     * by subsequent calls to related functions.)
+     */
+    utx2 = utx;
+    if (process_type == PTY_DEAD_PROCESS && utxtmp != NULL) {
+	/*
+	 * Use ut_line from old entry to avoid confusing last on
+	 * HP-UX.
+	 */
+	strncpy(utx2.ut_line, utxtmp->ut_line, sizeof(utx2.ut_line));
+    }
+
+    PTY_SETUTXENT();
+    PTY_PUTUTXLINE(&utx);
+    PTY_ENDUTXENT();
+
+    /* Don't record LOGIN_PROCESS entries. */
+    if (process_type == PTY_LOGIN_PROCESS)
+	return 0;
+
+#ifdef HAVE_SETUTXENT
+    return ptyint_update_wtmpx(&utx2);
+#else
+    return ptyint_update_wtmp(&utx2);
+#endif
+}
+
+#else /* !(HAVE_SETUTXENT || HAVE_SETUTENT) */
+
+long
+pty_update_utmp(int process_type, int pid, const char *username,
+		const char *line, const char *host, int flags)
+{
+    struct utmp ent, ut;
+    const char *cp;
+    int tty, lc, fd;
+    off_t seekpos;
+    ssize_t ret;
+    struct stat statb;
+
+    memset(&ent, 0, sizeof(ent));
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    if (host)
+	strncpy(ent.ut_host, host, sizeof(ent.ut_host));
+#endif
+    strncpy(ent.ut_name, username, sizeof(ent.ut_name));
+    cp = line;
+    if (strncmp(cp, "/dev/", sizeof("/dev/") - 1) == 0)
+	cp += sizeof("/dev/") - 1;
+    strncpy(ent.ut_line, cp, sizeof(ent.ut_line));
+    (void)time(&ent.ut_time);
+
+    if (flags & PTY_TTYSLOT_USABLE)
+	tty = ttyslot();
+    else {
+	tty = -1;
+	fd = open(UTMP_FILE, O_RDONLY);
+	if (fd == -1)
+	    return errno;
+	for (lc = 0; ; lc++) {
+	    seekpos = lseek(fd, (off_t)(lc * sizeof(struct utmp)), SEEK_SET);
+	    if (seekpos != (off_t)(lc * sizeof(struct utmp)))
+		break;
+	    if (read(fd, (char *) &ut, sizeof(struct utmp))
+		!= sizeof(struct utmp))
+		break;
+	    if (strncmp(ut.ut_line, ent.ut_line, sizeof(ut.ut_line)) == 0) {
+		tty = lc;
+		break;
+	    }
+	}
+	close(fd);
+    }
+    if (tty > 0) {
+	fd = open(UTMP_FILE, O_WRONLY);
+	if (fd == -1)
+	    return 0;
+	if (fstat(fd, &statb)) {
+	    close(fd);
+	    return 0;
+	}
+	seekpos = lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
+	if (seekpos != (off_t)(tty * sizeof(struct utmp))) {
+	    close(fd);
+	    return 0;
+	}
+	ret = write(fd, (char *)&ent, sizeof(struct utmp));
+	if (ret != sizeof(struct utmp)) {
+	    ftruncate(fd, statb.st_size);
+	}
+	close(fd);
+    }
+    /* Don't record LOGIN_PROCESS entries. */
+    if (process_type == PTY_LOGIN_PROCESS)
+	return 0;
+    else
+	return ptyint_update_wtmp(&ent);
+}
+#endif
diff --git a/mechglue/src/util/pty/update_wtmp.c b/mechglue/src/util/pty/update_wtmp.c
new file mode 100644
index 000000000..988bae61a
--- /dev/null
+++ b/mechglue/src/util/pty/update_wtmp.c
@@ -0,0 +1,127 @@
+/*
+ * ptyint_update_wtmp: Update wtmp.
+ *
+ * Copyright 1995, 2001 by the Massachusetts Institute of Technology.
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+#if !defined(WTMP_FILE) && defined(_PATH_WTMP)
+#define WTMP_FILE _PATH_WTMP
+#endif
+
+#if !defined(WTMPX_FILE) && defined(_PATH_WTMPX)
+#define WTMPX_FILE _PATH_WTMPX
+#endif
+
+/* if it is *still* missing, assume SunOS */
+#ifndef WTMP_FILE
+#define	WTMP_FILE	"/usr/adm/wtmp"
+#endif
+
+#ifdef HAVE_SETUTXENT
+
+#if defined(HAVE_GETUTMP) && defined(NEED_GETUTMP_PROTO)
+extern void getutmp(const struct utmpx *, struct utmp *);
+#endif
+
+/*
+ * Welcome to conditional salad.
+ *
+ * This really wants to take a (const struct utmpx *) but updutmpx()
+ * on Solaris at least doesn't take a const argument.  *sigh*
+ */
+long
+ptyint_update_wtmpx(struct utmpx *ent)
+{
+#if !(defined(HAVE_UPDWTMPX) && defined(WTMPX_FILE))
+    struct utmp ut;
+#endif
+
+#if defined(HAVE_UPDWTMPX) && defined(WTMPX_FILE)
+    updwtmpx(WTMPX_FILE, ent);
+    return 0;
+#else
+
+#ifdef HAVE_GETUTMP
+    getutmp(ent, &ut);
+#else  /* Emulate getutmp().  Yuck. */
+    memset(&ut, 0, sizeof(ut));
+    strncpy(ut.ut_name, ent->ut_user, sizeof(ut.ut_name));
+    strncpy(ut.ut_line, ent->ut_line, sizeof(ut.ut_line));
+    ut.ut_time = ent->ut_tv.tv_sec;
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+    strncpy(ut.ut_host, ent->ut_host, sizeof(ut.ut_host));
+    ut.ut_host[sizeof(ut.ut_host) - 1] = '\0';
+#ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
+    ut.ut_syslen = strlen(ut.ut_host) + 1;
+#endif
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_ID
+    strncpy(ut.ut_id, ent->ut_id, sizeof(ut.ut_id));
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_PID
+    ut.ut_pid = ent->ut_pid;
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_TYPE
+    ut.ut_type = ent->ut_type;
+#endif
+#if defined(PTY_UTMP_E_EXIT) && defined(PTY_UTMPX_E_EXIT)
+    ut.ut_exit.PTY_UTMP_E_EXIT = ent->ut_exit.PTY_UTMPX_E_EXIT;
+    ut.ut_exit.PTY_UTMP_E_TERMINATION =
+	ent->ut_exit.PTY_UTMPX_E_TERMINATION;
+#endif
+#endif /* !HAVE_GETUTMP */
+
+    return ptyint_update_wtmp(&ut);
+#endif /* !(defined(WTMPX_FILE) && defined(HAVE_UPDWTMPX)) */
+}
+
+#endif  /* HAVE_SETUTXENT */
+
+#if !(defined(WTMPX_FILE) && defined(HAVE_UPDWTMPX)) \
+	|| !defined(HAVE_SETUTXENT)
+
+long
+ptyint_update_wtmp(struct utmp *ent)
+{
+#ifndef HAVE_UPDWTMP
+    int fd;
+    struct stat statb;
+#endif
+
+#ifdef HAVE_UPDWTMP
+    updwtmp(WTMP_FILE, ent);
+#else
+    fd = open(WTMP_FILE, O_WRONLY | O_APPEND, 0);
+    if (fd != -1 && !fstat(fd, &statb)) {
+	if (write(fd, (char *)ent, sizeof(struct utmp))
+	    != sizeof(struct utmp))
+	    (void)ftruncate(fd, statb.st_size);
+	(void)close(fd);
+    }
+#endif
+    /*
+     * no current failure cases; file not found is not failure!
+     */
+    return 0;
+}
+
+#endif
diff --git a/mechglue/src/util/pty/vhangup.c b/mechglue/src/util/pty/vhangup.c
new file mode 100644
index 000000000..292437142
--- /dev/null
+++ b/mechglue/src/util/pty/vhangup.c
@@ -0,0 +1,50 @@
+/*
+ * pty_open_slave: open slave side of terminal, clearing for use.
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ *
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+void ptyint_vhangup(void)
+{
+#ifdef HAVE_VHANGUP
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+    /* Initialize "sa" structure. */
+    (void) sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    
+#endif
+
+#ifdef POSIX_SIGNALS
+	sa.sa_handler = SIG_IGN;
+	(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
+	vhangup();
+	sa.sa_handler = SIG_DFL;
+	(void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
+#else
+	signal(SIGHUP, SIG_IGN);
+	vhangup();
+	signal(SIGHUP, SIG_DFL);
+#endif
+#endif
+}
diff --git a/mechglue/src/util/pty/void_assoc.c b/mechglue/src/util/pty/void_assoc.c
new file mode 100644
index 000000000..a39c9c723
--- /dev/null
+++ b/mechglue/src/util/pty/void_assoc.c
@@ -0,0 +1,49 @@
+/*
+ * ptyint_void_association(): Void association with controlling terminal
+ *
+ * Copyright 1995, 1996 by the Massachusetts Institute of Technology.
+ *
+ * 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * M.I.T. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ * 
+ */
+
+#include "com_err.h"
+#include "libpty.h"
+#include "pty-int.h"
+
+/*
+ * This function gets called to set up the current process as a
+ * session leader (hence, can't be called except from a process that
+ * isn't already a session leader) and dissociates the controlling
+ * terminal (if any) from the session.
+ */
+long
+ptyint_void_association(void)
+{
+    int fd;
+#ifdef HAVE_SETSID
+    (void) setsid();
+#endif
+    /* Void tty association first */
+#ifdef TIOCNOTTY
+    fd = open("/dev/tty", O_RDWR);
+    if (fd >= 0) {
+	ioctl(fd, TIOCNOTTY, 0);
+	close(fd);
+    }
+#endif
+    return 0;
+}
diff --git a/mechglue/src/util/reconf b/mechglue/src/util/reconf
new file mode 100755
index 000000000..604b7164b
--- /dev/null
+++ b/mechglue/src/util/reconf
@@ -0,0 +1,106 @@
+#!/bin/sh
+
+force=
+autoreconfprog=autoreconf
+localdir=.
+autoreconfoptions=""
+verbose=false
+localdirarg=
+
+autoreconf="/bin/sh $autoreconfprog"
+
+# This should prevent autoreconf -- at least, the Debian version -- from
+# running aclocal in directories with configure.in but not aclocal.m4, so
+# that we can find the top-level one via the --include option.
+ACLOCAL=true ; export ACLOCAL
+
+usage="Usage: $0 [--force] [--verbose] [--help]"
+for option
+do
+  case "$option" in
+  --force | -f)
+    echo "Remaking all configuration files"
+    force=--force ;;
+  -help | --help | --hel | --he | --h)
+    echo "$usage"; exit 0 ;;
+  -v | --verbose)
+    verbose=true ;;
+  *) echo "$usage"; exit 1 ;;
+  esac
+done
+
+# Currently (2003-04-24) we need 2.52 or later.
+patb="2.(1[0-9][0-9])|(5[2-9])|([6-9][0-9])"
+
+# sedcmd1 recognizes the older 2.12 version, and sedcmd2 the newer 2.49
+sedcmd1="s,.*version \(.*\)$,\1,"
+sedcmd2="s,.*) \(.*\)$,\1,;1q"
+
+if autoreconf --version | sed -e "$sedcmd1" -e "$sedcmd2" | egrep "$patb" >/dev/null && \
+    autoconf --version  | sed -e "$sedcmd1" -e "$sedcmd2"  | egrep "$patb" >/dev/null && \
+    autoheader --version | sed -e "$sedcmd1" -e "$sedcmd2" | egrep "$patb" >/dev/null; then
+    autoreconf=autoreconf
+    autoreconfoptions=
+    autoconfversion=`autoconf --version | sed -e "$sedcmd1" -e "$sedcmd2"`
+	echo "Using autoconf version $autoconfversion found in your path..."
+	localdir=`pwd`
+
+	# Determine if we need to patch autoreconf for 2.53
+	case "$autoconfversion" in
+	  2.52)
+	       echo "WARNING: autoconf 2.52 is known to generate buggy configure scripts!"
+	       ;;
+	  2.53)
+	       echo "Patching autoreconf"
+	       # Walk the path to find autoreconf
+	       autoreconfpath=
+	       for i in `echo $PATH | sed -e 's/:/ /g'` ; do
+		   if test -r $i/autoreconf; then
+		       autoreconfpath=$i/autoreconf
+		       break
+		   fi
+	       done
+	       if test "x$autoreconfpath" = "x" ; then 
+		   echo "Could not find autoreconf executable!!!"
+		   exit
+	       fi
+	       
+	       echo "About to patch $autoreconfpath to ..."
+	       TMPCMD=/tmp/autoreconf$$
+	       sed -e 's/push @ARGV, $_;/push @ARGV, catfile ($directory, $_);/' $autoreconfpath > $TMPCMD
+	       autoreconf="/bin/sh $TMPCMD"
+	       trap "rm $TMPCMD" 0
+	       ;;
+	  *)
+	       ;;
+	esac
+
+	# Determine the proper argument to autoreconf 
+	case "$autoconfversion" in
+	  2.1*)
+	       localdirarg="-l"
+	       ;;
+	  2.5[23])
+	       localdirarg="-l"
+	       ;;
+	    *)
+	       localdirarg="-I"
+	       ;;
+	esac
+else
+	echo "Couldn't find autoconf 2.52 or higher in your path."
+	echo " "
+	echo "Please install or add to your path and re-run ./util/reconf"
+	exit 1
+fi
+
+if $verbose ; then 
+	echo $autoreconf $autoreconfoptions $localdirarg $localdir --verbose $force
+fi
+$autoreconf $autoreconfoptions  $localdirarg $localdir --verbose $force || exit 1
+if test $? = 0 ; then
+    if test ! -d include/krb5/autoconf.stmp ; then
+	cp /dev/null include/krb5/autoconf.stmp
+    fi
+fi
+find . -name autom4te.cache -print | xargs rm -rf
diff --git a/mechglue/src/util/send-pr/COPYING b/mechglue/src/util/send-pr/COPYING
new file mode 100644
index 000000000..515b6d333
--- /dev/null
+++ b/mechglue/src/util/send-pr/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+he GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/mechglue/src/util/send-pr/ChangeLog b/mechglue/src/util/send-pr/ChangeLog
new file mode 100644
index 000000000..d443d9172
--- /dev/null
+++ b/mechglue/src/util/send-pr/ChangeLog
@@ -0,0 +1,31 @@
+2004-09-24  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (RELEASE): Set from KRB5_VERSION, which comes from
+	patchlevel.h.
+
+2004-03-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (MY_SUBDIRS): Deleted.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-01-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, configure.in: Move the responsibility for
+		generating the Makefile in this directory to the top-level
+		configure script.  The local configure.in script has been
+		deleted.
+
diff --git a/mechglue/src/util/send-pr/INSTALL b/mechglue/src/util/send-pr/INSTALL
new file mode 100644
index 000000000..711c63d8a
--- /dev/null
+++ b/mechglue/src/util/send-pr/INSTALL
@@ -0,0 +1,83 @@
+	Installation procedures for `send-pr'
+
+If you receive `send-pr' as part of a larger software distribution, it
+will be automatically installed when the full distribution is
+installed.  The `send-pr' directory, however, is easily installed by
+itself by following these steps:
+
+1.  Unpack the distribution into a directory which we will refer to as
+    SRCDIR.  
+
+2.  Edit the `Makefile' to reflect local conventions.
+
+    Specifically, you should edit the variable "prefix" to alter
+    the installation location.  The default is '/usr/local'.  All
+    files are installed under "prefix" (see below).
+
+3.  Run 
+	make all install [ info ] install-info [ clean ]
+
+    from the "build directory".  The targets mean the following:
+
+	 all	Builds `send-pr' and `install-sid'
+
+     install	Installs the following:
+
+			    send-pr	into PREFIX/bin 
+			install-sid	into PREFIX/bin
+			  send-pr.1	into PREFIX/man/man1
+			 categories	as PREFIX/lib/gnats/SITE
+		      send-pr-el.in	as PREFIX/lib/emacs/lisp/send-pr.el
+
+        info	(optional) Builds "send-pr.info" from "send-pr.texi"
+		(send-pr.info is included with this distribution)
+
+install-info	Installs "send-pr.info" into PREFIX/info
+
+       clean 	(optional) Removes all intermediary build files that can
+		           be rebuilt from source code
+
+4.  Run 
+
+	install-sid SID
+
+    where SID is the submitter identification code you received with
+    `send-pr'.  If you've downloaded `send-pr' from the Net, use "net"
+    for this value.
+
+
+5.  Any users who wish to use the Emacs version of `send-pr' must place
+    the following line in their ".emacs" files:
+
+	(autoload 'send-pr "send-pr" "Submit a Problem Report." t)
+
+
+6.  Create a mail alias for the support site you received `send-pr'
+    from, and for every site with which you wish to use `send-pr' to
+    communicate with, each with a suffix of `-gnats'.  The support
+    site(s) will provide the correct addresses toward which these
+    aliases should point.  For instance, edit your mail aliases file
+    to contain something like:
+
+	# support sites; for use with send-pr
+	cygnus-gnats:     bugs@cygnus.com            # Cygnus Support
+	bumblebee-gnats:  bumblebugs@bumblebee.com   # Bumblebee BASIC, Inc.
+	mycompany-gnats:  bugs@my.company.com      (if you use GNATS locally)
+
+    `send-pr' automatically searches for these aliases when you type
+
+	send-pr cygnus
+	send-pr bumblebee
+	send-pr SITE...
+
+    `send-pr' also uses SITE to determine the categories of bugs the site
+    in question accepts by looking in PREFIX/lib/gnats/SITE
+
+
+7.  That's it!  See "send-pr.info", "send-pr.texi", and/or "send-pr.1" for
+    information on using `send-pr'.
+
+
+Copyright (c) 1993, Free Software Foundation, Inc.  
+See the file COPYING for copyright information concerning this
+distribution and all its components.
diff --git a/mechglue/src/util/send-pr/MANIFEST b/mechglue/src/util/send-pr/MANIFEST
new file mode 100644
index 000000000..35375a6fd
--- /dev/null
+++ b/mechglue/src/util/send-pr/MANIFEST
@@ -0,0 +1,20 @@
+	MANIFEST for send-pr
+
+The following files should have accompanied this distribution.
+
+	COPYING		copyright information
+      ChangeLog		sourcecode change log
+        INSTALL		installation procedure
+    Makefile.in		Makefile template used by `configure'
+       MANIFEST		list of accompanying files
+         README		introductory information
+        config/		any specialized configuration files
+   configure.in		input file for `configure'
+     categories		list of valid categories
+ install-sid.sh		script which installs Submitter-Id
+  send-pr-el.in		elisp version of `send-pr' for Emacs
+    send-pr.man		`send-pr' man file, installed as send-pr.1
+   send-pr.info		`send-pr' Info file
+     send-pr.sh		`send-pr' shell script - command line version
+   send-pr.texi		`send-pr' Texinfo documentation
+  send-pr.input 	`send-pr' Texinfo documentation input file
diff --git a/mechglue/src/util/send-pr/Makefile.in b/mechglue/src/util/send-pr/Makefile.in
new file mode 100644
index 000000000..6d586c69e
--- /dev/null
+++ b/mechglue/src/util/send-pr/Makefile.in
@@ -0,0 +1,48 @@
+thisconfigdir=./../..
+myfulldir=util/send-pr
+mydir=util/send-pr
+BUILDTOP=$(REL)..$(S)..
+#
+# Makefile for building a standalone send-pr.
+#
+RELEASE=@KRB5_VERSION@
+SUBMITTER=net
+sendprname = krb5-send-pr
+EMACS=emacs
+
+infodir = $(prefix)/info
+lispdir = $(prefix)/lib/emacs/site-lisp
+mandir  = $(KRB5MANROOT)
+man1dir = $(mandir)/man1
+datadir = @datadir@
+
+all:: send-pr  install-sid
+
+send-pr: send-pr.sh
+	sed -e 's,@DATADIR@,$(datadir),g' \
+	    -e 's,@SUBMITTER@,$(SUBMITTER),g' \
+	    -e 's/@DEFAULT_RELEASE@/$(RELEASE)/g' $(srcdir)/send-pr.sh > send-pr
+
+
+
+install-sid: install-sid.sh
+	sed -e 's,@ADMIN_BINDIR@,$(ADMIN_BINDIR),g' $(srcdir)/install-sid.sh > install-sid
+
+install:: all
+	if [ -d $(DESTDIR)$(prefix) ]; then true ; else mkdir $(DESTDIR)$(prefix) ; fi
+	if [ -d $(DESTDIR)$(ADMIN_BINDIR) ]; then true ; else mkdir $(DESTDIR)$(ADMIN_BINDIR) ; fi
+	cp send-pr $(DESTDIR)$(ADMIN_BINDIR)/$(sendprname)
+	chmod 755 $(DESTDIR)$(ADMIN_BINDIR)/$(sendprname)
+	if [ -d $(DESTDIR)$(datadir) ] ; then true ; else mkdir $(DESTDIR)$(datadir) ; fi
+	if [ -d $(DESTDIR)$(datadir)/gnats ] ; then true ; else mkdir $(DESTDIR)$(datadir)/gnats ; fi
+	cp $(srcdir)/categories $(DESTDIR)$(datadir)/gnats/mit
+	chmod 644 $(DESTDIR)$(datadir)/gnats/mit
+	-parent=`echo $(DESTDIR)$(man1dir)|sed -e 's@/[^/]*$$@@'`; \
+	if [ -d $$parent ] ; then true ; else mkdir $$parent ; fi
+	if [ -d $(DESTDIR)$(man1dir) ] ; then true ; else mkdir $(DESTDIR)$(man1dir) ; fi
+	sed -e 's/send-pr/$(sendprname)/g' $(srcdir)/send-pr.1 > $(DESTDIR)$(man1dir)/$(sendprname).1
+	chmod 644 $(DESTDIR)$(man1dir)/$(sendprname).1
+
+clean::
+	rm -f install-sid send-pr send-pr.el*
+
diff --git a/mechglue/src/util/send-pr/README b/mechglue/src/util/send-pr/README
new file mode 100644
index 000000000..b47917955
--- /dev/null
+++ b/mechglue/src/util/send-pr/README
@@ -0,0 +1,43 @@
+	send-pr - sends bug reports to a central support site
+
+`send-pr' uses electronic mail to submit support questions and
+software bugs to a central site.  No piece of software is perfect, and
+software organizations understand this `send-pr' is designed to allow
+users who have problems to submit reports of these problems to sites
+responsible for supporting the software in question, in a defined form
+which can be read by an electronically managed database.
+
+`send-pr' is part of a suite of programs known collectively as GNATS,
+an acronym for Problem Report Management System.  GNATS consists of
+several programs which, used in concert, formulate and partially
+administer a database of Problem Reports, or PRs, at a central support
+site.  A PR goes through several states in its lifetime; GNATS tracks
+the PR and all information associated with it through each state and
+finally acts as an archive for PRs which have been resolved.
+
+The same engine can be used to submit bugs to any number of support
+sites by setting up aliases for each of them; `send-pr' error-checks
+each PR as it is sent to be sure that the category specified matches a
+category supported by the site in question.
+
+`send-pr' invokes an editor on a problem report template (after trying
+to fill in some fields with reasonable default values).  When you exit
+the editor, `send-pr' sends the completed form to the support site.
+At the support site, the PR is assigned a unique number and is stored
+in the GNATS database according to its category and customer-id.  GNATS
+automatically replies with an acknowledgement, citing the category and
+the PR number.
+
+See the Texinfo file `send-pr.texi' or the Info file `send-pr.info'
+for detailed installation and usage information.
+
+See the file MANIFEST for a list of the files which should have
+accompanied this distribution.
+
+See `send-pr.texi', `send-pr.info', or the file INSTALL for the
+installation procedure for `send-pr'.
+
+
+Copyright (c) 1993, Free Software Foundation, Inc.  
+See the file COPYING for copyright information concerning this
+distribution and all its components.
diff --git a/mechglue/src/util/send-pr/categories b/mechglue/src/util/send-pr/categories
new file mode 100644
index 000000000..7700dd2bb
--- /dev/null
+++ b/mechglue/src/util/send-pr/categories
@@ -0,0 +1,11 @@
+krb5-libs
+krb5-admin
+krb5-kdc
+krb5-clients
+krb5-appl
+krb5-doc
+krb5-misc
+krb5-build
+pty
+telnet
+test
diff --git a/mechglue/src/util/send-pr/install-sid.sh b/mechglue/src/util/send-pr/install-sid.sh
new file mode 100644
index 000000000..15681cf74
--- /dev/null
+++ b/mechglue/src/util/send-pr/install-sid.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+# Drop in the SUBMITTER id into a site's installed send-pr script.
+# Copyright (C) 1993 Free Software Foundation, Inc.
+# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a
+# version written by Heinz G. Seidl (hgs@ide.com).
+#
+# This file is part of GNU GNATS.
+#
+# GNU GNATS is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU GNATS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU GNATS; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+COMMAND=`echo $0 | sed -e 's,.*/,,g'`
+USAGE="Usage: $COMMAND [--install-dir=prefix] [--help] [--version] submitter-id"
+
+VERSION=3.99
+
+BINDIR=@BINDIR@
+
+SUBMITTER=
+TEMP=/tmp/sp$$
+
+if [ $# -eq 0 ]; then
+  echo "$USAGE"
+  exit 1
+fi
+
+while [ $# -gt 0 ]; do
+  case "$1" in
+    -install-dir=*|--install-dir=*|--install-di=*|--install-d=*|--install-=*|--install=*|--instal=*|--insta=*|--inst=*|--ins=*|--in=*|--i=*)
+    I=`echo "$1" | sed 's/-*i[a-z\-]*=//'`
+    BINDIR=$I/bin ;;
+    --version) echo $COMMAND version $VERSION ; exit 1 ;;
+    -*) echo "$USAGE" ; exit 1 ;;
+    *) SUBMITTER=$1 ;;
+  esac
+  shift
+done
+
+path=`echo $0 | sed -e "s;${COMMAND};;"`
+
+[ -z "$path" ] && path=.
+
+if [ -f $BINDIR/send-pr ]; then
+  SPPATHLIST=$BINDIR/send-pr
+else
+      if [ -f $path/send-pr ]; then
+	 SPPATHLIST=$path/send-pr
+      else
+	 echo "$COMMAND: cannot find \`$BINDIR/send-pr' or \`$path/send-pr'" >&2
+	 exit 1
+      fi
+fi
+
+trap 'rm -f $TEMP ; exit 0' 0
+trap 'echo "$COM: Aborting ..."; rm -f $TEMP ; exit 1' 1 2 3 13 15
+
+for SPPATH in $SPPATHLIST; do
+   sed -e "s/^SUBMITTER=.*/SUBMITTER=${SUBMITTER}/" $SPPATH > $TEMP
+
+   if grep $SUBMITTER $TEMP > /dev/null; then
+      cp $SPPATH $SPPATH.orig &&
+      rm -f $SPPATH &&
+      cp $TEMP $SPPATH &&
+      chmod a+rx $SPPATH &&
+      rm -f $TEMP $SPPATH.orig ||
+      { echo "$COMMAND: unable to replace send-pr" >&2 ; exit 1; }  
+   else
+      echo "$COMMAND: something went wrong when sed-ing the submitter into send-pr" >&2
+      exit 1
+   fi
+done
+
+echo "$COMMAND: \`$SUBMITTER' is now the default submitter ID for send-pr"
+
+exit 0
diff --git a/mechglue/src/util/send-pr/send-pr.1 b/mechglue/src/util/send-pr/send-pr.1
new file mode 100644
index 000000000..bc241d7f2
--- /dev/null
+++ b/mechglue/src/util/send-pr/send-pr.1
@@ -0,0 +1,289 @@
+.\" -*- nroff -*-
+.\" ---------------------------------------------------------------------------
+.\"    man page for send-pr (by Heinz G. Seidl, hgs@cygnus.com)
+.\"    updated Feb 1993 for GNATS 3.00 by Jeffrey Osier, jeffrey@cygnus.com
+.\"
+.\"    This file is part of the Problem Report Management System (GNATS)
+.\"    Copyright 1992 Cygnus Support
+.\"
+.\"    This program is free software; you can redistribute it and/or
+.\"    modify it under the terms of the GNU General Public
+.\"    License as published by the Free Software Foundation; either
+.\"    version 2 of the License, or (at your option) any later version.
+.\"
+.\"    This program is distributed in the hope that it will be useful,
+.\"    but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\"    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\"    General Public License for more details.
+.\"
+.\"    You should have received a copy of the GNU Library General Public
+.\"    License along with this program; if not, write to the Free
+.\"    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
+.\"
+.\" ---------------------------------------------------------------------------
+.nh
+.TH SEND-PR 1 3.99 "February 1993"
+.SH NAME
+send-pr \- send problem report (PR) to a central support site
+.SH SYNOPSIS
+.B send-pr
+[
+.I site
+]
+[
+.B \-f
+.I problem-report
+]
+[
+.B \-t
+.I mail-address
+]
+.br
+.in +0.8i
+[
+.B \-P
+]
+[
+.B \-L
+]
+[
+.B \-s
+.I severity
+]
+[
+.B \-c
+.I address
+]
+.br
+[
+.B \-\-request-id
+]
+[
+.B \-V
+]
+.SH DESCRIPTION
+.B send-pr
+is a tool used to submit 
+.I problem reports 
+.\" SITE ADMINISTRATORS - change this if you use a local default
+(PRs) to a central support site.  In most cases the correct 
+.I site
+will be the default.  This argument indicates the support site which
+is responsible for the category of problem involved.  Some sites may
+use a local address as a default.  
+.I site
+values are defined by using the 
+.BR aliases (5).
+.LP
+.B send-pr
+invokes an editor on a problem report template (after trying to fill
+in some fields with reasonable default values).  When you exit the
+editor,
+.B send-pr 
+sends the completed form to the
+.I Problem Report Management System
+(\fBGNATS\fR) at a central support site.  At the support site, the PR
+is assigned a unique number and is stored in the \fBGNATS\fR database
+according to its category and submitter-id.  \fBGNATS\fR automatically
+replies with an acknowledgement, citing the category and the PR
+number.
+.LP
+To ensure that a PR is handled promptly, it should contain your (unique)
+\fIsubmitter-id\fR and one of the available \fIcategories\fR to identify the
+problem area.  (Use
+.B `send-pr -L'
+to see a list of categories.)
+.LP
+The
+.B send-pr
+template at your site should already be customized with your
+submitter-id (running `\|\fBinstall-sid\fP \fIsubmitter-id\fP\|' to
+accomplish this is part of the installation procedures for
+.BR send-pr ).
+If this hasn't been done, see your system administrator for your
+submitter-id, or request one from your support site by invoking
+.B `send-pr \-\-request\-id'.
+If your site does not distinguish between different user sites, or if
+you are not affiliated with the support site, use
+.B `net'
+for this field.
+.LP
+The more precise your problem description and the more complete your
+information, the faster your support team can solve your problems.
+.SH OPTIONS
+.TP
+.BI \-f " problem-report"
+specify a file (\fIproblem-report\fR) which already contains a
+complete problem report.
+.B send-pr
+sends the contents of the file without invoking the editor.  If 
+the value for 
+.I problem-report
+is
+.BR `\|\-\|' ,
+then
+.B send-pr
+reads from standard input.
+.TP
+.BI \-s " severity"
+Give the problem report the severity
+.IR severity .
+.TP
+.BI \-t " mail-address"
+Change mail address at the support site for problem reports.  The
+default 
+.I mail-address
+is the address used for the default 
+.IR site .  
+Use the
+.I site
+argument rather than this option in nearly all cases.
+.TP
+.BI \-c " address"
+Put
+.I address
+in the 
+.B Cc:
+header of the message.
+.TP
+.B \-P
+print the form specified by the environment variable 
+.B PR_FORM 
+on standard output.  If 
+.B PR_FORM
+is not set, print the standard blank PR template.  No mail is sent.
+.TP
+.B -L
+print the list of available categories.  No mail is sent.
+.TP
+.B \-\-request\-id
+sends mail to the default support site, or
+.I site
+if specified, with a request for your 
+.IR submitter-id . 
+If you are
+not affiliated with 
+.IR site ,
+use a
+.I submitter-id
+of
+.BR net \|'.
+.TP
+.B \-V
+Display the 
+.B send-pr
+version number.
+.LP
+Note: use
+.B send-pr
+to submit problem reports rather than mailing them directly.  Using
+both the template and
+.B send-pr
+itself will help ensure all necessary information will reach the
+support site.
+.SH ENVIRONMENT
+The environment variable 
+.B EDITOR
+specifies the editor to invoke on the template.
+.br
+default:
+.B vi
+.sp
+If the environment variable 
+.B PR_FORM
+is set, then its value is used as the file name of the template for
+your problem-report editing session.  You can use this to start with a
+partially completed form (for example, a form with the identification
+fields already completed).
+.SH "HOW TO FILL OUT A PROBLEM REPORT"
+Problem reports have to be in a particular form so that a program can
+easily manage them.  Please remember the following guidelines:
+.IP \(bu 3m 
+describe only 
+.B one problem
+with each problem report.
+.IP \(bu 3m
+For follow-up mail, use the same subject line as the one in the automatic
+acknowledgent. It consists of category, PR number and the original synopsis
+line.  This allows the support site to relate several mail messages to a
+particular PR and to record them automatically.
+.IP \(bu 3m 
+Please try to be as accurate as possible in the subject and/or synopsis line.
+.IP \(bu 3m 
+The subject and the synopsis line are not confidential.  This is
+because open-bugs lists are compiled from them.  Avoid confidential
+information there.
+.LP
+See the GNU 
+.B Info 
+file
+.B send-pr.info
+or the document \fIReporting Problems With send-pr\fR\ for detailed
+information on reporting problems
+.SH "HOW TO SUBMIT TEST CASES, CODE, ETC."
+Submit small code samples with the PR.  Contact the support site for
+instructions on submitting larger test cases and problematic source
+code.
+.SH FILES
+.ta \w'/tmp/pbad$$  'u
+/tmp/p$$	copy of PR used in editing session
+.br
+/tmp/pf$$	copy of empty PR form, for testing purposes
+.br
+/tmp/pbad$$	file for rejected PRs
+.SH EMACS USER INTERFACE
+An Emacs user interface for 
+.B send-pr
+with completion of field values is part of the 
+.B send-pr
+distribution (invoked with
+.BR "M-x send-pr" ).
+See the file
+.B send-pr.info
+or the ASCII file
+.B INSTALL
+in the top level directory of the distribution for configuration and
+installation information.  The Emacs LISP template file is 
+.B send-pr-el.in
+and is installed as
+.BR send-pr.el .
+.SH INSTALLATION AND CONFIGURATION
+See 
+.B send-pr.info
+or
+.B INSTALL
+for installation instructions.
+.SH SEE ALSO
+.I Reporting Problems Using send-pr
+(also installed as the GNU Info file
+.BR send-pr.info ).
+.LP
+.BR gnats (l),
+.BR query-pr (1),
+.BR edit-pr (1),
+.BR gnats (8),
+.BR queue-pr (8),
+.BR at-pr (8),
+.BR mkcat (8),
+.BR mkdist (8).
+.SH AUTHORS
+Jeffrey Osier, Brendan Kehoe, Jason Merrill, Heinz G. Seidl (Cygnus
+Support)
+.SH COPYING
+Copyright (c) 1992, 1993 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+
diff --git a/mechglue/src/util/send-pr/send-pr.sh b/mechglue/src/util/send-pr/send-pr.sh
new file mode 100644
index 000000000..e15ea5dfe
--- /dev/null
+++ b/mechglue/src/util/send-pr/send-pr.sh
@@ -0,0 +1,542 @@
+#!/bin/sh
+# Submit a problem report to a GNATS site.
+# Copyright (C) 1993 Free Software Foundation, Inc.
+# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a
+# version written by Heinz G. Seidl (hgs@cygnus.com).
+#
+# This file is part of GNU GNATS.
+#
+# GNU GNATS is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU GNATS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU GNATS; see the file COPYING.  If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# The version of this send-pr.
+VERSION=3.99
+
+# The submitter-id for your site.
+SUBMITTER=@SUBMITTER@
+
+# Where the GNATS directory lives, if at all.
+[ -z "$GNATS_ROOT" ] && 
+GNATS_ROOT=
+
+# The default mail address for PR submissions. 
+GNATS_ADDR=krb5-bugs@mit.edu
+
+# Where the gnats category tree lives.
+DATADIR=@DATADIR@
+
+# If we've been moved around, try using GCC_EXEC_PREFIX.
+[ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && 
+  DATADIR=@DATADIR@
+
+
+# The default release for this host.
+DEFAULT_RELEASE="@DEFAULT_RELEASE@"
+
+# The default organization.
+DEFAULT_ORGANIZATION=
+
+# The default site to look for.
+GNATS_SITE=mit
+
+# Newer config information?
+[ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config
+
+# What mailer to use.  This must come after the config file, since it is
+# host-dependent.
+for dir in /usr/lib /usr/sbin /usr/ucblib; do
+  if test -f $dir/sendmail; then
+    MAIL_AGENT="$dir/sendmail -oi -t"
+    break
+  fi
+done
+
+# How to read the passwd database.
+PASSWD="cat /etc/passwd"
+if test -f /bin/domainname && test -n "`/bin/domainname`"; then
+  if test -f /usr/bin/niscat && 
+     /usr/bin/niscat passwd.org_dir > /dev/null 2>&1; then
+    PASSWD="/usr/bin/niscat passwd.org_dir"
+  elif test -f /usr/bin/ypcat && /usr/bin/ypcat passwd > /dev/null 2>&1; then
+    PASSWD="/usr/bin/ypcat passwd"
+  fi
+fi
+
+# Figure out how to do "echo -n"
+
+if test "`echo -n foo`" = foo; then
+  ECHON1="echo -n"
+  ECHON2=
+elif test "`echo 'foo\c'`" = foo; then
+  ECHON1=echo
+  ECHON2='\c'
+else
+  ECHON1=echo
+  ECHON2=
+fi
+
+#
+
+if [ -z "$TMPDIR" ]; then
+  TMPDIR=/tmp
+else
+  if [ "`echo $TMPDIR | grep '/$'`" != "" ]; then
+    TMPDIR="`echo $TMPDIR | sed -e 's,/$,,'`"
+  fi
+fi
+
+TEMP=$TMPDIR/p$$
+BAD=$TMPDIR/pbad$$
+REF=$TMPDIR/pf$$
+
+# find a user name
+if [ "$LOGNAME" = "" ]; then
+	if [ "$USER" != "" ]; then
+		LOGNAME="$USER"
+	else
+		LOGNAME="UNKNOWN"
+	fi
+fi
+
+FROM="$LOGNAME"
+if [ -z "$REPLYTO" ]; then
+  REPLYTO="$LOGNAME"
+fi
+
+# Find out the name of the originator of this PR.
+if [ -n "$NAME" ]; then
+  ORIGINATOR="$NAME"
+elif [ -f $HOME/.fullname ]; then
+  ORIGINATOR="`sed -e '1q' $HOME/.fullname`"
+else
+  # Must use temp file due to incompatibilities in quoting behavior
+  # and to protect shell metacharacters in the expansion of $LOGNAME
+  $PASSWD | grep "^$LOGNAME:" | awk -F: '{print $5}' | sed -e 's/,.*//' > $TEMP
+  ORIGINATOR="`cat $TEMP`"
+  rm -f $TEMP
+fi
+
+if [ -n "$ORGANIZATION" ]; then
+  if [ -f "$ORGANIZATION" ]; then
+    ORGANIZATION="`cat $ORGANIZATION`"
+  fi
+else
+  if [ -n "$DEFAULT_ORGANIZATION" ]; then
+    ORGANIZATION="$DEFAULT_ORGANIZATION"
+  elif [ -f $HOME/.organization ]; then
+    ORGANIZATION="`cat $HOME/.organization`"
+  elif [ -f $HOME/.signature ]; then
+    ORGANIZATION="`cat $HOME/.signature`"
+  fi
+fi
+
+# If they don't have a preferred editor set, then use
+if [ -z "$VISUAL" ]; then
+  if [ -z "$EDITOR" ]; then
+    EDIT=vi
+  else
+    EDIT="$EDITOR"
+  fi
+else
+  EDIT="$VISUAL"
+fi
+
+# Find out some information.
+SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \
+        ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""`
+ARCH=`[ -f /bin/arch ] && /bin/arch`
+MACHINE=`[ -f /bin/machine ] && /bin/machine`
+
+COMMAND=`echo $0 | sed -e 's,.*/,,'`
+USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [-s severity]
+       [-c address] [--request-id] [--version]"
+REMOVE=
+BATCH=
+CC=
+SEVERITY_C=
+
+while [ $# -gt 0 ]; do
+  case "$1" in
+    -r) ;; 		# Ignore for backward compat.
+    -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+	shift ; GNATS_ADDR="$1"
+	EXPLICIT_GNATS_ADDR=true
+        ;;
+    -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+	shift ; IN_FILE="$1"
+	if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then
+	  echo "$COMMAND: cannot read $IN_FILE"
+	  exit 1
+	fi
+	;;
+    -b | --batch) BATCH=true ;;
+    -c | --cc) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+	shift ; CC="$1"
+	;;
+    -s | --severity) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi
+	shift ; SEVERITY_C="$1"
+	;;
+    -p | -P | --print) PRINT=true ;;
+    -L | --list) FORMAT=norm ;;
+    -l | -CL | --lisp) FORMAT=lisp ;;
+    --request-id) REQUEST_ID=true ;;
+    -h | --help) echo "$USAGE"; exit 0 ;;
+    -V | --version) echo "$VERSION"; exit 0 ;;
+    -*) echo "$USAGE" ; exit 1 ;;
+    *) if [ -z "$USER_GNATS_SITE" ]; then
+	 if [ ! -r "$DATADIR/gnats/$1" ]; then
+	   echo "$COMMAND: the GNATS site $1 does not have a categories list."
+	   exit 1
+	 else
+	   # The site name is the alias they'll have to have created.
+	   USER_GNATS_SITE=$1
+	 fi
+       else
+	 echo "$USAGE" ; exit 1
+       fi
+       ;;
+ esac
+ shift
+done
+
+if [ -n "$USER_GNATS_SITE" ] && [ "$USER_GNATS_SITE" != "$GNATS_SITE" ]; then
+  GNATS_SITE=$USER_GNATS_SITE
+  GNATS_ADDR=$USER_GNATS_SITE-gnats
+fi
+
+if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then
+  cat << '__EOF__'
+It seems that send-pr is not installed with your unique submitter-id.
+You need to run
+
+          install-sid YOUR-SID
+
+where YOUR-SID is the identification code you received with `send-pr'.
+`send-pr' will automatically insert this value into the template field
+`>Submitter-Id'.  If you've downloaded `send-pr' from the Net, use `net'
+for this value.  If you do not know your id, run `send-pr --request-id' to 
+get one from your support site.
+__EOF__
+  exit 1
+fi
+
+if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then
+  CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort`
+else
+  echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list."
+  exit 1
+fi
+
+if [ -z "$CATEGORIES" ]; then
+  echo "$COMMAND: the categories list for $GNATS_SITE was empty!"
+  exit 1
+fi
+
+case "$FORMAT" in
+  lisp) echo "$CATEGORIES" | \
+        awk 'BEGIN {printf "( "} {printf "(\"%s\") ",$0} END {printf ")\n"}'
+        exit 0
+        ;;
+  norm) l=`echo "$CATEGORIES" | \
+	awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
+	     END {print max + 1;}'`
+	c=`expr 70 / $l`
+	if [ $c -eq 0 ]; then c=1; fi
+	echo "$CATEGORIES" | \
+        awk 'BEGIN {print "Known categories:"; i = 0 }
+          { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } }
+            END { print ""; }'
+        exit 0
+        ;;
+esac
+
+ORIGINATOR_C='<name of the PR author (one line)>'
+ORGANIZATION_C='<organization of PR author (multiple lines)>'
+CONFIDENTIAL_C='<[ yes | no ] (one line)>'
+SYNOPSIS_C='<synopsis of the problem (one line)>'
+if [ -z "$SEVERITY_C" ]; then
+  SEVERITY_C='<[ non-critical | serious | critical ] (one line)>'
+fi
+PRIORITY_C='<[ low | medium | high ] (one line)>'
+CATEGORY_C='<name of the product (one line)>'
+CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>'
+RELEASE_C='<release number or tag (one line)>'
+ENVIRONMENT_C='<machine, os, target, libraries (multiple lines)>'
+DESCRIPTION_C='<precise description of the problem (multiple lines)>'
+HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>'
+FIX_C='<how to correct or work around the problem, if known (multiple lines)>'
+
+# Catch some signals. ($xs kludge needed by Sun /bin/sh)
+xs=0
+trap 'rm -f $REF $TEMP; exit $xs' 0
+trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15
+
+# If they told us to use a specific file, then do so.
+if [ -n "$IN_FILE" ]; then
+  if [ "$IN_FILE" = "-" ]; then
+    # The PR is coming from the standard input.
+    if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
+      sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP
+    else
+      cat > $TEMP
+    fi
+  else
+    # Use the file they named.
+    if [ -n "$EXPLICIT_GNATS_ADDR" ]; then
+      sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP
+    else
+      cat $IN_FILE > $TEMP
+    fi
+  fi
+else
+
+  if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
+    # If their PR_FORM points to a bogus entry, then bail.
+    if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then
+      echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM"
+      sleep 1
+      PRINT_INTERN=bad_prform
+    fi
+  fi
+
+  if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then
+    cp $PR_FORM $TEMP || 
+      ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit )
+  else
+    for file in $TEMP $REF ; do
+      cat  > $file << '__EOF__'
+SEND-PR: -*- send-pr -*-
+SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as
+SEND-PR: will all comments (text enclosed in `<' and `>').
+SEND-PR: 
+SEND-PR: Please consult the send-pr man page `send-pr(1)' or the Texinfo
+SEND-PR: manual if you are not sure how to fill out a problem report.
+SEND-PR:
+SEND-PR: Choose from the following categories:
+SEND-PR:
+__EOF__
+
+      # Format the categories so they fit onto lines.
+	l=`echo "$CATEGORIES" | \
+	awk 'BEGIN {max = 0; } { if (length($0) > max) { max = length($0); } }
+	     END {print max + 1;}'`
+	c=`expr 61 / $l`
+	if [ $c -eq 0 ]; then c=1; fi
+	echo "$CATEGORIES" | \
+        awk 'BEGIN {printf "SEND-PR: "; i = 0 }
+          { printf ("%-'$l'.'$l's", $0);
+	    if ((++i % '$c') == 0) { printf "\nSEND-PR: " } }
+            END { printf "\nSEND-PR:\n"; }' >> $file
+
+      cat >> $file << __EOF__
+To: $GNATS_ADDR
+Subject: 
+From: $FROM
+Reply-To: $REPLYTO
+Cc: $CC
+X-send-pr-version: $VERSION
+
+
+>Submitter-Id:	$SUBMITTER
+>Originator:	$ORIGINATOR
+>Organization:
+${ORGANIZATION-	$ORGANIZATION_C}
+>Confidential:	$CONFIDENTIAL_C
+>Synopsis:	$SYNOPSIS_C
+>Severity:	$SEVERITY_C
+>Priority:	$PRIORITY_C
+>Category:	$CATEGORY_C
+>Class:		$CLASS_C
+>Release:	${DEFAULT_RELEASE-$RELEASE_C}
+>Environment:
+	$ENVIRONMENT_C
+`[ -n "$SYSTEM" ] && echo System: $SYSTEM`
+`[ -n "$ARCH" ] && echo Architecture: $ARCH`
+`[ -n "$MACHINE" ] && echo Machine: $MACHINE`
+>Description:
+	$DESCRIPTION_C
+>How-To-Repeat:
+	$HOW_TO_REPEAT_C
+>Fix:
+	$FIX_C
+__EOF__
+    done
+  fi
+
+  if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then
+    cat $TEMP
+    xs=0; exit
+  fi
+
+  chmod u+w $TEMP
+  if [ -z "$REQUEST_ID" ]; then
+    eval $EDIT $TEMP
+  else
+    ed -s $TEMP << '__EOF__'
+/^Subject/s/^Subject:.*/Subject: request for a customer id/
+/^>Category/s/^>Category:.*/>Category: send-pr/
+w
+q
+__EOF__
+  fi
+
+  if cmp -s $REF $TEMP ; then
+    echo "$COMMAND: problem report not filled out, therefore not sent"
+    xs=1; exit
+  fi
+fi
+
+#
+#	Check the enumeration fields
+
+# This is a "sed-subroutine" with one keyword parameter 
+# (with workaround for Sun sed bug)
+#
+SED_CMD='
+/$PATTERN/{
+s|||
+s|<.*>||
+s|^[ 	]*||
+s|[ 	]*$||
+p
+q
+}'
+
+
+while [ -z "$REQUEST_ID" ]; do
+  CNT=0
+
+  # 1) Confidential
+  #
+  PATTERN=">Confidential:"
+  CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+  case "$CONFIDENTIAL" in
+    ""|yes|no) CNT=`expr $CNT + 1` ;;
+    *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;;
+  esac
+  #
+  # 2) Severity
+  #
+  PATTERN=">Severity:"
+  SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+  case "$SEVERITY" in
+    ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;;
+    *)  echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'."
+  esac
+  #
+  # 3) Priority
+  #
+  PATTERN=">Priority:"
+  PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+  case "$PRIORITY" in
+    ""|low|medium|high) CNT=`expr $CNT + 1` ;;
+    *)  echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'."
+  esac
+  #
+  # 4) Category
+  #
+  PATTERN=">Category:"
+  CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+  FOUND=
+  for C in $CATEGORIES
+  do
+    if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi
+  done
+  if [ -n "$FOUND" ]; then
+    CNT=`expr $CNT + 1`	
+  else
+    if [ -z "$CATEGORY" ]; then
+      echo "$COMMAND: you must include a Category: field in your report."
+    else
+      echo "$COMMAND: \`$CATEGORY' is not a known category."
+    fi
+  fi
+  #
+  # 5) Class
+  #
+  PATTERN=">Class:"
+  CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP`
+  case "$CLASS" in
+    ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;;
+    *)  echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'."
+  esac
+
+  [ $CNT -lt 5 -a -z "$BATCH" ] && 
+    echo "Errors were found with the problem report."
+
+  while true; do
+    if [ -z "$BATCH" ]; then
+      $ECHON1 "a)bort, e)dit or s)end? $ECHON2"
+      read input
+    else
+      if [ $CNT -eq 5 ]; then
+        input=s
+      else
+        input=a
+      fi
+    fi
+    case "$input" in
+      a*)
+	if [ -z "$BATCH" ]; then
+	  echo "$COMMAND: the problem report remains in $BAD and is not sent."
+	  mv $TEMP $BAD
+        else
+	  echo "$COMMAND: the problem report is not sent."
+	fi
+	xs=1; exit
+	;;
+      e*)
+        eval $EDIT $TEMP
+	continue 2
+	;;
+      s*)
+	break 2
+	;;
+    esac
+  done
+done
+#
+#	Remove comments and send the problem report
+#	(we have to use patterns, where the comment contains regex chars)
+#
+# /^>Originator:/s;$ORIGINATOR;;
+sed  -e "
+/^SEND-PR:/d
+/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;;
+/^>Confidential:/s;<.*>;;
+/^>Synopsis:/s;$SYNOPSIS_C;;
+/^>Severity:/s;<.*>;;
+/^>Priority:/s;<.*>;;
+/^>Category:/s;$CATEGORY_C;;
+/^>Class:/s;<.*>;;
+/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;;
+/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;;
+/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;;
+/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;;
+/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;;
+" $TEMP > $REF
+
+if $MAIL_AGENT < $REF; then
+  echo "$COMMAND: problem report sent"
+  xs=0; exit
+else
+  echo "$COMMAND: mysterious mail failure."
+  if [ -z "$BATCH" ]; then
+    echo "$COMMAND: the problem report remains in $BAD and is not sent."
+    mv $REF $BAD
+  else
+    echo "$COMMAND: the problem report is not sent."
+  fi
+  xs=1; exit
+fi
diff --git a/mechglue/src/util/ss/.Sanitize b/mechglue/src/util/ss/.Sanitize
new file mode 100644
index 000000000..ae8afe63c
--- /dev/null
+++ b/mechglue/src/util/ss/.Sanitize
@@ -0,0 +1,64 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+cmd_tbl.lex.l
+config_script
+configure
+configure.in
+copyright.h
+ct.y
+ct_c_awk.in
+ct_c_sed.in
+data.c
+error.c
+execute_cmd.c
+help.c
+invocation.c
+list_rqs.c
+listen.c
+mit-sipb-copyright.h
+mk_cmds.c
+mk_cmds.sh
+options.c
+pager.c
+parse.c
+prompt.c
+request_tbl.c
+requests.c
+ss.h
+ss_err.et
+ss_internal.h
+std_rqs.ct
+test_ss.c
+utils.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/util/ss/ChangeLog b/mechglue/src/util/ss/ChangeLog
new file mode 100644
index 000000000..5fbe42838
--- /dev/null
+++ b/mechglue/src/util/ss/ChangeLog
@@ -0,0 +1,430 @@
+2005-08-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Use K5_AC_INIT instead of AC_INIT.
+
+2005-03-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (EXTRADEPSRCS): Define.
+
+2004-06-16  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (all-mac): Target deleted.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-03-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* error.c (ss_error): Always use ANSI C form.  Don't try to hide
+	the declaration in the header file.
+
+	* ss.h: Always use the prototype forms of declarations.
+
+2003-06-27  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (HDRS): Remove mit-sipb-copyright.h.
+	(includes): Depend on copied version of the headers, not local
+	versions.  Don't do any copying; instead, move the copying
+	commands to new targets for each header.
+	($(HDRDIR)/timestamp): New target; create the directory here if
+	needed.
+	(clean-unix): Remove the timestamp file.
+
+2003-04-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* ss.h: Don't declare errno.  Include errno.h.
+
+2003-02-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (std_rqs.c): Depend on ct_c.sed and ct_c.awk.
+
+2003-01-23  Ezra Peisach  <epeisach@bu.edu>
+
+	* parse.c: Include errno.h for declaration of errno.
+
+2003-01-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* configure.in: Don't explicitly invoke AC_PROG_INSTALL, and
+	certainly not twice.
+
+	* Makefile.in: Add AC_SUBST_FILE marker for lib_frag and libobj_frag.
+
+2003-01-05  Sam Hartman  <hartmans@mit.edu>
+
+	* pager.c: Remove declaration of errno
+
+	* help.c: Remove declaration of errno
+
+2002-12-12  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in (depend-dependencies): Was previously
+	depend-prerecurse.
+
+2002-09-10  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LOCALINCLUDES): Drop references to .. and et
+	directories in source and build trees.
+	(depend-prerecurse): Depend on 'includes'.
+
+2002-08-29  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Revert $(S)=>/ change, for Windows support.
+
+2002-08-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in: Change $(S)=>/ and $(U)=>.. globally.
+
+2002-08-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in ($(HDRS)): Depend on 'includes'.
+	(std_rqs.c): Depend on mk_cmds.
+
+2001-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* mk_cmds.c, ss_internal.h: Make prototypes unconditional.
+	* ss_internal.h (PROTOTYPE, const, volatile): Delete.
+	(pointer): Always use void*.
+
+2001-09-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SRCS): Don't include ss_err.h.
+	(depend-prerecurse): Depend on ss_err.h.
+
+2001-06-20  Ken Raeburn  <raeburn@mit.edu>
+
+	* request_tbl.c (ss_add_request_table): Delete unnecessary cast in
+	size arg to realloc.
+
+	* invocation.c (ss_delete_invocation): Delete unnecessary cast in
+	arg to free.
+
+2001-06-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* request_tbl.c (ss_add_request_table): Do not cast argument to
+	realloc() to char *.
+
+2001-04-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (unixmac): Target deleted.
+
+2000-11-01  Ezra Peisach  <epeisach@mit.edu>
+
+	* configure.in: Change AC_RETSIGTYPE to AC_TYPE_SIGNAL.
+
+2000-08-07  Ezra Peisach  <epeisach@mit.edu>
+
+	* ss_internal.h: Only use fake sigmask, sigblock and sigsetmask if
+	USE_SIGPROCMASK is defined and not POSIX_SIGNALS.
+
+2000-08-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* listen.c (ss_quit): Now returns void.  Fix type of argument ARGV
+	to fit prototype.
+
+	* ss.h (ss_execute_line) [__STDC__]: Make prototype
+	unconditional.
+	(ss_quit): Use __SS_PROTO and return void, as with other
+	command functions.
+
+2000-08-02  Ezra Peisach  <epeisach@mit.edu>
+
+	* requests.c (DECLARE): Fix prototype for dispatch functions to
+	properly match what is expected by ss library.
+
+	* pager.c (ss_pager_create): Cast return from fork to int for use
+	in switch statement.
+
+	* ss.h: Provide full prototype for ss_name(). Add prototypes for
+	ss_execute_line(), ss_delete_invocation(), ss_add_info_dir(),
+	ss_delete_info_dir(), ss_abort_subsystem(), ss_get_prompt(),
+	ss_set_prompt(), ss_add_request_table(),
+	ss_delete_request_table(), ss_quit().
+
+	* ss_internal.h: Made full prototypes for ss_parse(),
+	ss_page_stdin(), ss_pagre_create(). Add prototypes for
+	ss_self_identify(), ss_subsystem_name(), ss_subsystem_version(),
+	ss_unimplemented(). Moved ss_execute_line() to ss.h
+
+2000-07-03  Ezra Peisach  <epeisach@mit.edu>
+
+	* test_ss.c (main): Change usage of ss_listen to agree with 
+	prototype.
+
+	* ss.h: Add prototype for ss_listen() and ss_create_invocation()
+
+2000-05-01  Nalin Dahyabhai  <nalin@redhat.com>
+
+	* help.c (ss_help): Don't overflow buffers "buffer" or "buf".
+	* list_rqs.c (ss_list_requests): Don't overflow buffer "buffer".
+	* mk_cmds.c (main): Don't overflow buffer "c_file".
+	* utils.c (generate_rqte): Update lengths of constant strings in
+	computing buffer size.
+
+2000-02-01  Ken Raeburn  <raeburn@mit.edu>
+
+	* listen.c (ss_listen): Local var END should be volatile.
+
+1999-10-26  Wilfredo Sanchez  <tritan@mit.edu>
+
+	* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
+	LOCAL_INCLUDES such that one can override CFLAGS from the command
+	line without losing CPP search patchs and defines. Some associated
+	Makefile cleanup.
+
+1999-01-20  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* listen.c (print_prompt): Replace BSD-style ioctl with termios
+		interface.
+
+Mon Apr  6 19:45:25 1998  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* Makefile.in (includes): Don't mkdir unless the directory doesn't
+ 	exist yet.
+
+Mon Mar 30 11:30:00 1998  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* ss_internal.h: Add ss_pager_create prototype.
+
+	* ss.h: Add ss_list_requests prototype.
+
+	* request_tbl.c (ss_add_request_table, ss_delete_request_table):
+        Declare function types as void.
+
+	* prompt.c (ss_set_prompt): Declare function as void.
+
+	* listen.c (ss_quit): Int function should return a value.
+
+	* list_rqs.c (ss_list_requests): Fix arguments to match proper
+        prototype for a ss type handler.
+
+	* execute_cmd.c (ss_execute_command): Declare as returning int
+
+Wed Feb 18 16:35:55 1998  Tom Yu  <tlyu@mit.edu>
+
+	* Makefile.in: Remove trailing slash from thisconfigdir.  Fix up
+	BUILDTOP for new conventions.
+
+Fri Feb 13 13:35:51 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in: Add AC_PROG_INSTALL since it's needed to install
+		the libraries and header files.
+
+Wed Jan 28 17:38:29 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* configure.in, Makefile.in: Remove CopySrcHeader and CopyHeader 
+		from configure.in and move equivalent functionality to
+		Makefile.in 
+
+	* Makefile.in: Define BUILDTOP and thisconfigdir in the Makefile
+
+	* cmd_tbl.lex.l, ct.y, requests.c, ss.h: Remove #include of
+		<mit-sipb-copyright.h>, since it's not needed.
+
+Tue Nov 18 19:22:34 1997  Tom Yu  <tlyu@mit.edu>
+
+	* configure.in: Update to new library build system.
+
+	* Makefile.in: Update to new library build system.
+
+Thu Sep 18 20:44:03 1997  Tom Yu  <tlyu@mit.edu>
+
+	* utils.c: Replace HAS_STRDUP with something more sane.
+
+	* configure.in: Replace HAS_STRDUP with something more sane.
+
+Sun Aug 17 14:39:56 1997  Ezra Peisach  <epeisach@mit.edu>
+
+	* Makefile.in (SRCS): Add $(srcdir) as needed.
+
+Wed Feb  5 22:52:41 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Remove the target ct_c.awk before copying over it.
+		If ct_c.awk.in were read-only, ct_c.awk will become
+		read-only and cannot be updated again.
+
+Thu Jun 13 21:43:44 1996  Tom Yu  <tlyu@voltage-multiplier.mit.edu>
+
+	* configure.in: remove ref to SS_RULES, ET_RULES	
+
+Tue Mar 12 22:32:56 1996  Ken Raeburn  <raeburn@cygnus.com>
+
+	* configure.in: Use AC_HEADER_STDARG instead of calling
+	AC_CHECK_HEADER on stdarg.h.
+
+Mon Sep 25 16:42:57 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in: Removed "foo:: foo-$(WHAT)" lines from the
+		Makefile. 
+
+Thu Aug 24 18:19:54 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* .Sanitize: Updated to reflect ct_c.* to ct_c.*.in filename changes.
+
+Mon Aug  7 19:14:28 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in (mk_cmds): Add $(SHELL) to invocation of
+		config_script, so that the tree can build even after
+		checked into a broken SCCS system.
+
+Fri Jul 7 16:42:42 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* configure.in - Add symlink to $(TOPLIBD) for libss.
+
+Wed Jun 28 16:35:43 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* Makefile.in, ct_c_sed.in, ct_c_awk.in: Rename ct_c.*.in to
+		ct_c_*.in, so that the sources will unpack cleanly under
+		DOS.  Argh.
+
+Wed Jun 28 11:24:20 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in, ct_c.sed.in, ct_c.awk.in, config_script: Rename
+		ct_c.* to ct_c.*.in.  ct_c.sed.in is now processed by sed
+		to remove comment lines beginning with '#', since some sed
+		programs can't handle that.  Change config_script so that
+		the directory where the ct_c.* files can be specified,
+		since those are in the build directory, instead of the
+		source directory.  (This is all for the sake of System V
+		sed's.  Sigh.)
+
+Tue Jun 27 15:46:06 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* listen.c(listen_int_handler) - Add argument to conform to signal
+		handler prototype.
+
+Tue Jun 13 01:48:33 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* Makefile.in: don't install libss.a
+
+Fri Jun  9 19:00:11 1995    <tytso@rsx-11.mit.edu>
+
+	* configure.in: Remove standardized set of autoconf macros, which
+		are now handled by CONFIG_RULES.
+
+Fri Jun  9 06:20:37 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* error.c (ss_error): remove const declaration from local
+		variable. (it is used with free is called on the contents).
+
+	* ss_internal.h: Include stdlib.h if present on system. If is
+	present, don't redeclare malloc.
+
+	* configure.in: Check for stdlib.h before including blindly.
+
+Thu Jun  8 23:22:07 1995    <tytso@rsx-11.mit.edu>
+
+	* list_req.c, ss_internal.h: Clean up -Wall flames.
+
+	* configure.in: Don't install the internal ss include files.
+
+Thu Jun  8 22:54:16 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* mk_cmds.c (main): Change mk_cmds so that the output file is
+		always created in the current directory, instead of in the
+		directory where the source file is located.
+
+Thu Jun  8 11:27:47 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* Makefile.in (install): Don't install in this directory.
+
+Thu Apr 27 12:26:26 1995  Ezra Peisach  <epeisach@kangaroo.mit.edu>
+
+	* pager.c: Use posix signals.
+
+	* listen.c: Use posix signals.
+
+	* list_rqs.c: Use posix signals.
+
+	* help.c: Call wait with proper casting (int * vs. union wait *)
+
+	* configure.in: Add AC_PROG_ARCHIVE_ADD and CHECK_SIGNALS.
+
+	* Makefile.in (all): Use ARADD for incremental changes to library
+
+Tue Mar 28 18:51:08 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in (all):  Run all-$(WHAT).
+	(unixmac):  Build includes at this time.
+	(LDFLAGS):  Punt duplicated setting.
+
+Sat Mar 18 18:49:03 1995  John Gilmore  (gnu at toad.com)
+
+	* configure.in:  Use AC_CHECK_HEADERS(stdarg.h), not CHECK_STDARG.
+	* error.c:  Use HAVE_STDARG_H, not STDARG_PROTOTYPES.
+
+Mon Feb 27 22:40:18 1995  John Gilmore  (gnu at toad.com)
+
+	* Makefile.in:  Avoid recompilation of std_rqs.c every single time
+	`make' is run.
+	* error.c:  Use "com_err.h", not <com_err.h>.
+
+Thu Feb 23 14:24:31 1995  Mark Eichin  (eichin@cygnus.com)
+
+	* mk_cmds.sh: use ${SED} not sed in backtick expressions.
+	Explicitly check for ${FILE} since sed doesn't give an error if it
+	is absent. Also set -e to catch other conditions.
+
+Sat Oct 22 09:54:50 1994    (tytso@rsx-11)
+
+	* list_rqs.c (ss_list_requests): 
+	* listen.c (ss_listen): 
+	* configure.in: Add AC_RETSIGTYPE to get proper return type for
+		signal hanlders.
+
+Fri Oct 21 21:07:16 1994    (tytso@rsx-11)
+
+	* Makefile.in (SED): Don't specify an explicit pathname for sed.
+
+Tue Oct 11 12:41:40 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in: Don't rm the awk and sed scripts during a make clean!
+
+Fri Oct  7 15:37:19 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* ct_c.sed: Add extra check to make sure blank lines get squeezed
+		out.  Needed for AIX's sed, for some reason.
+
+Thu Oct  6 19:40:09 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* mk_cmds.sh -- replace basename with sed -- more portable
+
+Mon Oct  3 17:26:27 1994  Theodore Y. Ts'o  (tytso@dcl)
+
+	* Makefile.in:
+	  configure.in:  Don't try to compile mk_cmds.  Use awk/sed shell
+	  	  script replacement instead.  It's more apt to be
+		  portable, since it doesn't use lex or yacc.  :-(
+
+Tue Aug 30 21:30:18 1994  Theodore Y. Ts'o  (tytso at tsx-11)
+
+	* cmd_tbl.lex.l: Add declaration for strdup() if HAS_STRDUP is not
+	defined. 
+
+	* ct.y: Added #include of string.h; added declaration for
+	strdup() if HAS_STRDUP is not defined.
+
+Tue Jul 19 20:27:59 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: remove spurious includes rules
+
+Wed Jul 13 23:20:44 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: nuke libss.a.bak crud
+
+Sun Jul  3 07:48:43 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* Makefile.in: changing things to now spew ignored errors.
+
+Wed Jun 22 18:51:50 1994  Mark Eichin  (eichin@cygnus.com)
+
+	* configure.in: ss_err.h is *not* a SrcHeader. Note that there is
+	duplication between the Copy*Header lines and the includes: rule
+	in the Makefile.in, which should later be fixed.
+
+Tue Jun 21 00:21:05 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in: should be CopySrcHeader
+
+Mon Jun 20 21:58:40 1994  Tom Yu  (tlyu at dragons-lair)
+
+	* configure.in: install headers during build
+
diff --git a/mechglue/src/util/ss/Makefile.in b/mechglue/src/util/ss/Makefile.in
new file mode 100644
index 000000000..97693a9e6
--- /dev/null
+++ b/mechglue/src/util/ss/Makefile.in
@@ -0,0 +1,223 @@
+thisconfigdir=.
+myfulldir=util/ss
+mydir=.
+BUILDTOP=$(REL)..$(S)..
+SED = sed
+
+INSTALLLIB=cp
+INSTALLFILE=cp
+
+all::
+
+TOP=$(BUILDTOP)
+
+LIBBASE=ss
+LIBMAJOR=1
+LIBMINOR=0
+RELDIR=../util/ss
+
+STOBJLISTS=OBJS.ST
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+install-unix:: install-libs
+
+# hard coded srcdir/.. is so that ss/ss.h works
+
+# hard coded .. is so that ss/ss_err.h works
+# hard coded ../et is so com_err.h works
+# CFLAGS= -g
+# CPPFLAGS= -I${INCDIR} -I. -I.. -I../et
+LOCALINCLUDES= -I. -I$(srcdir)/
+
+# with ss_err.o first, ss_err.h should get rebuilt first too.  should not
+# be relying on this, though.
+STLIBOBJS=\
+	ss_err.o \
+	std_rqs.o \
+	invocation.o help.o \
+	execute_cmd.o listen.o parse.o error.o prompt.o \
+	request_tbl.o list_rqs.o pager.o requests.o \
+	data.o
+
+SRCS=	$(srcdir)/invocation.c $(srcdir)/help.c \
+	$(srcdir)/execute_cmd.c $(srcdir)/listen.c $(srcdir)/parse.c \
+	$(srcdir)/error.c $(srcdir)/prompt.c \
+	$(srcdir)/request_tbl.c $(srcdir)/list_rqs.c $(srcdir)/pager.c \
+	$(srcdir)/requests.c $(srcdir)/data.c
+EXTRADEPSRCS= \
+	$(srcdir)/mk_cmds.c $(srcdir)/utils.c $(srcdir)/options.c \
+	cmd_tbl.lex.c ct.tab.c \
+	ss_err.c \
+	std_rqs.c
+depend-dependencies: ss_err.h includes
+
+std_rqs.o: std_rqs.c ss_err.h
+
+CODE= $(SRCS) $(MKCMDSFILES)
+
+MKCMDSOBJS=	mk_cmds.o utils.o options.o ct.tab.o cmd_tbl.lex.o
+
+MKCMDSFILES=	mk_cmds.c utils.c options.c ct.y cmd_tbl.lex.l
+
+MKCMDSCSRCS=	mk_cmds.c utils.c options.c ct.tab.c cmd_tbl.lex.c
+
+
+HFILES=	ss.h mit-sipb-copyright.h
+BUILT_HFILES = ss_err.h
+
+# for 'tags' and dependencies
+
+CFILES=	$(SRCS) $(MKCMDSCSRCS) test_ss.c
+
+# for building archives
+
+FILES=	$(SRCS) $(MKCMDSFILES) $(HFILES) \
+	ss_err.et std_rqs.ct Makefile \
+	test_ss.c ss mit-sipb-copyright.h copyright.h
+
+#
+# stuff to build
+#
+
+all-unix::	mk_cmds ct_c.awk ct_c.sed includes # libss_p.a lint
+all-unix:: all-liblinks
+all-windows::  all-unix
+
+dist:	archives
+
+install::
+
+includes:: mk_cmds ct_c.sed ct_c.awk ss_err.h
+
+HDRDIR=$(BUILDTOP)/include/ss
+HDRS =	$(HDRDIR)/ss.h \
+	$(HDRDIR)/ss_err.h
+
+BUILD_HDRS = ss_err.h
+SRC_HDRS = ss.h 
+SRC_HDRS_DEP = $(srcdir)/ss.h 
+
+includes:: $(HDRS)
+$(HDRDIR)/timestamp:
+	if [ -d $(HDRDIR) ] ; then :; else mkdir -p $(HDRDIR); fi
+	echo timestamp > $(HDRDIR)/timestamp
+$(HDRDIR)/ss.h: ss.h $(HDRDIR)/timestamp
+	$(RM) $(HDRDIR)/ss.h
+	$(CP) $(srcdir)/ss.h $(HDRDIR)/ss.h
+$(HDRDIR)/ss_err.h: ss_err.h $(HDRDIR)/timestamp
+	$(RM) $(HDRDIR)/ss_err.h
+	$(CP) ss_err.h $(HDRDIR)/ss_err.h
+
+clean-unix::
+	$(RM) $(HDRS) $(HDRDIR)/timestamp
+
+std_rqs.c: std_rqs.ct mk_cmds ct_c.sed ct_c.awk
+
+ss_err.h: ss_err.et
+
+ss_err.c: ss_err.et
+
+clean::
+	$(RM) ss_err.o ss_err.c ss_err.h std_rqs.c
+
+depend:: ss_err.h
+
+ct.tab.c ct.tab.h: ct.y
+	$(RM) ct.tab.* y.*
+	$(YACC) -d $(srcdir)/ct.y
+	$(MV) y.tab.c ct.tab.c
+	$(MV) y.tab.h ct.tab.h
+
+# install_library_target(ss,$(OBJS),$(SRCS),)
+
+#mk_cmds: $(MKCMDSOBJS)
+#	$(CC) $(ALL_CFLAGS) -o $@ $(MKCMDSOBJS) $(LEXLIB) $(BSDLIB)
+#
+#mk_cmds.o:	ss_err.h
+#
+#install::
+#	$(INSTALLPROG) mk_cmds ${DESTDIR}$(PROGDIR)/mk_cmds
+
+mk_cmds: $(srcdir)/mk_cmds.sh $(srcdir)/config_script 
+	$(SHELL) $(srcdir)/config_script $(srcdir)/mk_cmds.sh . $(AWK) $(SED) > mk_cmds
+	chmod 755 mk_cmds	
+
+ct_c.awk: $(srcdir)/ct_c_awk.in
+	$(RM) $@
+	$(CP) $(srcdir)/ct_c_awk.in $@
+
+ct_c.sed: $(srcdir)/ct_c_sed.in
+	$(SED) -e '/^#/d' $(srcdir)/ct_c_sed.in > ct_c.sed
+
+clean::
+	$(RM) mk_cmds ct_c.awk ct_c.sed $(MKCMDSOBJS)
+
+# 
+
+clean::
+	rm -f *.o *~ \#* *.bak core \
+		ss_err.h ct.tab.c ct.tab.h cmd_tbl.lex.c \
+		lex.yy.c y.tab.c \
+		libss.a libss_p.a llib-lss.ln mk_cmds \
+		ss.ar ss.tar \
+		TAGS test_ss
+
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+invocation.so invocation.po $(OUTPRE)invocation.$(OBJEXT): \
+  invocation.c ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS) copyright.h
+help.so help.po $(OUTPRE)help.$(OBJEXT): help.c ss_internal.h \
+  ss.h $(BUILDTOP)/include/ss/ss_err.h $(COM_ERR_DEPS) \
+  copyright.h
+execute_cmd.so execute_cmd.po $(OUTPRE)execute_cmd.$(OBJEXT): \
+  execute_cmd.c ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS) copyright.h
+listen.so listen.po $(OUTPRE)listen.$(OBJEXT): listen.c \
+  copyright.h ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS)
+parse.so parse.po $(OUTPRE)parse.$(OBJEXT): parse.c \
+  ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS) copyright.h
+error.so error.po $(OUTPRE)error.$(OBJEXT): error.c \
+  copyright.h $(COM_ERR_DEPS) ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h
+prompt.so prompt.po $(OUTPRE)prompt.$(OBJEXT): prompt.c \
+  copyright.h ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS)
+request_tbl.so request_tbl.po $(OUTPRE)request_tbl.$(OBJEXT): \
+  request_tbl.c copyright.h ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS)
+list_rqs.so list_rqs.po $(OUTPRE)list_rqs.$(OBJEXT): \
+  list_rqs.c copyright.h ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS)
+pager.so pager.po $(OUTPRE)pager.$(OBJEXT): pager.c \
+  ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS) copyright.h
+requests.so requests.po $(OUTPRE)requests.$(OBJEXT): \
+  requests.c ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS)
+data.so data.po $(OUTPRE)data.$(OBJEXT): data.c ss_internal.h \
+  ss.h $(BUILDTOP)/include/ss/ss_err.h $(COM_ERR_DEPS) \
+  copyright.h
+mk_cmds.so mk_cmds.po $(OUTPRE)mk_cmds.$(OBJEXT): mk_cmds.c \
+  copyright.h ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS)
+utils.so utils.po $(OUTPRE)utils.$(OBJEXT): utils.c \
+  copyright.h ss_internal.h ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS)
+options.so options.po $(OUTPRE)options.$(OBJEXT): options.c \
+  copyright.h ss.h $(BUILDTOP)/include/ss/ss_err.h $(COM_ERR_DEPS)
+cmd_tbl.lex.o: cmd_tbl.lex.c ct.tab.h
+ct.tab.o: ct.tab.c ss.h $(BUILDTOP)/include/ss/ss_err.h \
+  $(COM_ERR_DEPS)
+ss_err.so ss_err.po $(OUTPRE)ss_err.$(OBJEXT): ss_err.c \
+  $(COM_ERR_DEPS)
+std_rqs.so std_rqs.po $(OUTPRE)std_rqs.$(OBJEXT): std_rqs.c \
+  $(SS_DEPS) $(COM_ERR_DEPS)
diff --git a/mechglue/src/util/ss/cmd_tbl.lex.l b/mechglue/src/util/ss/cmd_tbl.lex.l
new file mode 100644
index 000000000..b47085e98
--- /dev/null
+++ b/mechglue/src/util/ss/cmd_tbl.lex.l
@@ -0,0 +1,81 @@
+N	[0-9]
+PC	[^\"]
+AN      [A-Z_a-z0-9]
+%%
+
+command_table	return l_command_table();
+request		return l_request();
+unimplemented	return l_unimplemented();
+end		return l_end();
+
+[\t\n ]		;
+
+\"{PC}*\"	return l_quoted_string();
+
+{AN}*		return l_string();
+
+#.*\n		;
+
+.		return (*yytext);
+%%
+/*
+ * User-subroutines section.
+ *
+ * Have to put all this stuff here so that the include file
+ * from YACC output can be included, since LEX doesn't allow
+ * an include file before the code it generates for the above
+ * rules.
+ *
+ * Copyright 1987 by MIT Student Information Processing Board.
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+#include <string.h>
+#include "ct.tab.h"
+
+#ifndef HAS_STRDUP
+extern char *strdup();
+#endif
+
+extern char *last_token;
+
+static l_command_table()
+{
+     last_token = "command_table";
+     return COMMAND_TABLE;
+}
+
+static l_request()
+{
+     last_token = "request";
+     return REQUEST;
+}
+
+static l_unimplemented()
+{
+     last_token = "unimplemented";
+     return UNIMPLEMENTED;
+}
+
+static l_end()
+{
+     last_token = "end";
+     return END;
+}
+
+static l_quoted_string()
+{
+     register char *p;
+     yylval.dynstr = strdup(yytext+1);
+     if (p=strrchr(yylval.dynstr, '"'))
+	  *p='\0';
+     last_token = strdup(yylval.dynstr);
+     return STRING;
+}
+
+static l_string()
+{
+     yylval.dynstr = strdup(yytext);
+     last_token = strdup(yylval.dynstr);
+     return STRING;
+}
diff --git a/mechglue/src/util/ss/config_script b/mechglue/src/util/ss/config_script
new file mode 100755
index 000000000..5add600ed
--- /dev/null
+++ b/mechglue/src/util/ss/config_script
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# This program takes a shell script and configures for the following
+# variables:	@DIR@
+#		@AWK@
+#		@SED@
+#
+# Usage: config_script <filename> [<dir>] [<awk>] [<sed>]
+#
+
+FILE=$1
+DIR=$2
+AWK=$3
+SED=$4
+
+if test "${DIR}x" = "x" ; then
+	DIR=.
+fi
+DIR=`cd ${DIR}; pwd`
+if test "${AWK}x" = "x" ; then
+	AWK=awk
+fi
+if test "${SED}x" = "x" ; then
+	SED=sed
+fi
+
+
+sed -e "s;@DIR@;${DIR};" -e "s;@AWK@;${AWK};" -e "s;@SED@;${SED};" $FILE
diff --git a/mechglue/src/util/ss/configure.in b/mechglue/src/util/ss/configure.in
new file mode 100644
index 000000000..f68c53380
--- /dev/null
+++ b/mechglue/src/util/ss/configure.in
@@ -0,0 +1,17 @@
+K5_AC_INIT(ct.y)
+CONFIG_RULES
+AC_PROG_LEX
+AC_PROG_YACC
+AC_PROG_AWK
+HAVE_YYLINENO
+AC_CHECK_FUNCS(strdup)
+CHECK_DIRENT
+CHECK_WAIT_TYPE
+CHECK_SIGNALS
+CHECK_SIGPROCMASK
+AC_TYPE_SIGNAL
+AC_HEADER_STDARG
+AC_CHECK_HEADERS(stdlib.h)
+KRB5_BUILD_LIBRARY_STATIC
+KRB5_BUILD_LIBOBJS
+V5_AC_OUTPUT_MAKEFILE
diff --git a/mechglue/src/util/ss/copyright.h b/mechglue/src/util/ss/copyright.h
new file mode 100644
index 000000000..d118f10bf
--- /dev/null
+++ b/mechglue/src/util/ss/copyright.h
@@ -0,0 +1,22 @@
+/*
+
+Copyright 1987, 1989 by the Student Information Processing Board
+	of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+Furthermore if you modify this software you must label
+your software as modified software and not distribute it in such a
+fashion that it might be confused with the original M.I.T. software.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/mechglue/src/util/ss/ct.y b/mechglue/src/util/ss/ct.y
new file mode 100644
index 000000000..0727492cf
--- /dev/null
+++ b/mechglue/src/util/ss/ct.y
@@ -0,0 +1,81 @@
+%{
+/*
+ * Copyright 1987 by MIT Student Information Processing Board
+ *
+ * For copyright info, see mit-sipb-copyright.h.
+ */
+#include <stdio.h>
+#include <string.h>
+
+#ifndef HAS_STRDUP
+extern char *strdup();
+#endif
+
+char *str_concat3(), *generate_rqte(), *quote();
+long flag_value();
+char *last_token = (char *)NULL;
+FILE *output_file;
+long gensym_n = 0;
+
+%}
+%union {
+	char *dynstr;
+	long flags;
+}
+
+%token COMMAND_TABLE REQUEST UNKNOWN UNIMPLEMENTED END
+%token <dynstr> STRING
+%token <dynstr> FLAGNAME
+%type <dynstr> namelist header request_list
+%type <dynstr> request_entry
+%type <flags> flag_list options
+%left OPTIONS
+%{
+#include "ss.h"
+%}
+%start command_table
+%%
+command_table :	header request_list END ';'
+		{ write_ct($1, $2); }
+	;
+
+header	:	COMMAND_TABLE STRING ';'
+		{ $$ = $2; }
+	;
+
+request_list :	request_list request_entry
+		{ $$ = str_concat3($1, $2, ""); }
+	|
+		{ $$ = ""; }
+	;
+
+request_entry :	REQUEST STRING ',' STRING ',' namelist ',' options ';'
+		{ $$ = generate_rqte($2, quote($4), $6, $8); }
+	|	REQUEST STRING ',' STRING ',' namelist ';'
+		{ $$ = generate_rqte($2, quote($4), $6, 0); }
+	|	UNKNOWN namelist ';'
+		{ $$ = generate_rqte("ss_unknown_request",
+					(char *)NULL, $2, 0); }
+	|	UNIMPLEMENTED STRING ',' STRING ',' namelist ';'
+		{ $$ = generate_rqte("ss_unimplemented", quote($4), $6, 3); }
+	;
+
+options	:	'(' flag_list ')'
+		{ $$ = $2; }
+	|	'(' ')'
+		{ $$ = 0; }
+	;
+
+flag_list :	flag_list ',' STRING
+		{ $$ = $1 | flag_val($3); }
+	|	STRING
+		{ $$ = flag_val($1); }
+	;
+
+namelist: 	STRING
+		{ $$ = quote(strdup($1)); }
+	|	namelist ',' STRING
+		{ $$ = str_concat3($1, quote($3), ",\n    "); }
+	;
+
+%%
diff --git a/mechglue/src/util/ss/ct_c_awk.in b/mechglue/src/util/ss/ct_c_awk.in
new file mode 100644
index 000000000..872f6e007
--- /dev/null
+++ b/mechglue/src/util/ss/ct_c_awk.in
@@ -0,0 +1,77 @@
+/^command_table / {
+	cmdtbl = $2;
+	printf "/* %s.c - automatically generated from %s.ct */\n", \
+		rootname, rootname > outfile
+	print "#include <ss/ss.h>" > outfile
+	print "" >outfile
+	print "#ifndef __STDC__" > outfile
+	print "#define const" > outfile
+	print "#endif" > outfile
+	print "" > outfile
+}
+	
+/^BOR$/ {
+	cmdnum++
+	options = 0
+	cmdtab = ""
+	printf "static char const * const ssu%05d[] = {\n", cmdnum > outfile
+}
+
+/^sub/ {
+	subr = substr($0, 6, length($0)-5)
+}
+
+/^hlp/ {
+	help = substr($0, 6, length($0)-5)
+}
+
+/^cmd/ {
+	cmd = substr($0, 6, length($0)-5)
+	printf "%s\"%s\",\n", cmdtab, cmd > outfile
+	cmdtab = "    "
+}
+
+/^opt/ {
+	opt = substr($0, 6, length($0)-5)
+	if (opt == "dont_list") {
+		options += 1
+	}
+	if (opt == "dont_summarize") {
+		options += 2
+	}
+}
+
+/^EOR/ {
+	print "    (char const *)0" > outfile
+	print "};" > outfile 
+	printf "extern void %s __SS_PROTO;\n", subr > outfile
+	subr_tab[cmdnum] = subr
+	options_tab[cmdnum] = options
+	help_tab[cmdnum] = help
+}
+
+/^[0-9]/ {
+	linenum = $1;
+}
+
+/^ERROR/ {
+	error = substr($0, 8, length($0)-7)
+	printf "Error in line %d: %s\n", linenum, error
+	print "#__ERROR_IN_FILE__" > outfile
+}
+
+END {
+	printf "static ss_request_entry ssu%05d[] = {\n", cmdnum+1 > outfile
+	for (i=1; i <= cmdnum; i++) {
+		printf "    { ssu%05d,\n", i > outfile
+		printf "      %s,\n", subr_tab[i] > outfile
+		printf "      \"%s\",\n", help_tab[i] > outfile
+		printf "      %d },\n", options_tab[i] > outfile
+	}
+	print "    { 0, 0, 0, 0 }" > outfile
+	print "};" > outfile
+	print "" > outfile
+	printf "ss_request_table %s = { 2, ssu%05d };\n", \
+		cmdtbl, cmdnum+1 > outfile
+}
+
diff --git a/mechglue/src/util/ss/ct_c_sed.in b/mechglue/src/util/ss/ct_c_sed.in
new file mode 100644
index 000000000..f99cd7fd2
--- /dev/null
+++ b/mechglue/src/util/ss/ct_c_sed.in
@@ -0,0 +1,161 @@
+#
+# This script parses a command_table file into something which is a bit 
+# easier for an awk script to understand.
+#
+# Input syntax: a .ct file
+#
+# Output syntax:
+# (for the command_table line)
+#	command_table  <command_table>
+#
+#(for each request definition)
+#	BOR
+#	sub: <subroutine name>
+#	hlp: <help text>
+#	cmd: <command>
+#	opt: <option>
+#	EOR
+# (there may be more than one 'cmd' or 'opt' line
+#
+# A number sent to the output represents a parse error --- it will be 
+# followed by the next line which will have the form:
+#	ERROR: <error text>
+#
+# The design of this output syntax is such that it should be easy for
+# an awk script to parse.
+
+#
+# The first section of this script is just to cannoicalize the file.  
+# It removes comments, and puts each command_table request onto a single
+# line
+#
+:FIRST
+y/	/ /
+s/^ *//
+s/#.*$//
+/; *$/!{
+N
+y/	/ /
+s/\n */ /
+bFIRST
+}
+s/, */, /g
+/^$/d
+#
+# Now we take care of some syntatic sugar.....
+#
+/^unimplemented/ {
+	s/^unimplemented [A-Za-z_0-9]*/request ss_unimplemented/
+	s/;/, (dont_list, dont_summarize);/
+}
+/^unknown/ {
+	s/^unknown /request ss_unknown, "", /
+}
+#
+# Dispatch based on the keyword....  illegal keywords are prefixed by ERROR:
+# and are handled by the awk script.
+#
+/^command_table /bCMD
+/^request /bREQUEST
+/^end;/bEND
+s/ .*//
+s/^/ERROR: unknown keyword: /
+=
+b
+#
+# Handle the command_table keyword
+#
+:CMD
+s/;$//
+p
+d
+b
+#
+# Handle the request keyword --- this is the heart of the sed script.
+# 
+:REQUEST
+s/^request *//
+h
+i\
+BOR
+# First, parse out the subroutine name
+s/^/sub: /
+s/,.*//
+p
+# Next, parse out the help message, being careful to handle a quoted string
+g
+s/^[^,]*, *//
+h
+/^"/ {
+	s/^"//
+	s/".*//
+	x
+	s/^"[^"]*", *//
+	x
+	b EMITHLP
+}
+s/[^a-zA-Z0-9].*//
+x
+s/[a-zA-Z0-9]*, *//
+x
+:EMITHLP
+s/^/hlp: /
+p
+# Next take care of the command names
+:CMDLIST
+g
+/^(/b OPTIONS
+/^;/b EOR
+/^"/ {
+	s/^"//
+	s/".*//
+	x
+	s/^"[^"]*"//
+	s/, *//
+	x
+	b EMITREQ
+}
+s/[^A-Za-z_0-9].*//
+x
+s/[A-Za-z_0-9]*//
+s/, *//
+x
+:EMITREQ
+s/^/cmd: /
+p
+b CMDLIST
+#
+# Here we parse the list of options.
+#
+: OPTIONS
+g
+s/^(//
+h
+: OPTLIST
+/^)/ b EOR
+/^[^A-Za-z_0-9]/ {
+	=
+	c\
+ERROR: parse error in options list
+}
+s/[^A-Za-z_0-9].*//
+x
+s/[A-Za-z_0-9]*//
+s/, *//
+x
+s/^/opt: /
+p
+g
+b OPTLIST
+: EOR
+c\
+EOR\
+
+d
+b
+#
+# Handle the end keyword --- it's basically ignored.
+#
+:END
+d
+b
diff --git a/mechglue/src/util/ss/data.c b/mechglue/src/util/ss/data.c
new file mode 100644
index 000000000..dd6341c0c
--- /dev/null
+++ b/mechglue/src/util/ss/data.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright 1987, 1988, 1989 Massachusetts Institute of Technology
+ * (Student Information Processing Board)
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include <stdio.h>
+#include "ss_internal.h"
+#include "copyright.h"
+
+const static char copyright[] =
+    "Copyright 1987, 1988, 1989 by the Massachusetts Institute of Technology";
+
+ss_data **_ss_table = (ss_data **)NULL;
+char *_ss_pager_name = (char *)NULL;
diff --git a/mechglue/src/util/ss/error.c b/mechglue/src/util/ss/error.c
new file mode 100644
index 000000000..064805506
--- /dev/null
+++ b/mechglue/src/util/ss/error.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1987, 1988, 1989 by MIT Student Information Processing
+ * Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include <stdio.h>
+
+#include "copyright.h"
+#include "com_err.h"
+#include "ss_internal.h"
+
+char * ss_name(sci_idx)
+    int sci_idx;
+{
+    register char *ret_val;
+    register ss_data *infop;
+    
+    infop = ss_info(sci_idx);
+    if (infop->current_request == (char const *)NULL) {
+	ret_val = malloc((unsigned)
+			 (strlen(infop->subsystem_name)+1)
+			 * sizeof(char));
+	if (ret_val == (char *)NULL)
+	    return((char *)NULL);
+	strcpy(ret_val, infop->subsystem_name);
+	return(ret_val);
+    }
+    else {
+	register char *cp;
+	register char const *cp1;
+	ret_val = malloc((unsigned)sizeof(char) * 
+			 (strlen(infop->subsystem_name)+
+			  strlen(infop->current_request)+
+			  4));
+	cp = ret_val;
+	cp1 = infop->subsystem_name;
+	while (*cp1)
+	    *cp++ = *cp1++;
+	*cp++ = ' ';
+	*cp++ = '(';
+	cp1 = infop->current_request;
+	while (*cp1)
+	    *cp++ = *cp1++;
+	*cp++ = ')';
+	*cp = '\0';
+	return(ret_val);
+    }
+}
+
+void ss_error (int sci_idx, long code, const char * fmt, ...)
+{
+    register char *whoami;
+    va_list pvar;
+    va_start (pvar, fmt);
+    whoami = ss_name (sci_idx);
+    com_err_va (whoami, code, fmt, pvar);
+    free (whoami);
+    va_end(pvar);
+}
+
+void ss_perror (sci_idx, code, msg) /* for compatibility */
+    int sci_idx;
+    long code;
+    char const *msg;
+{
+    ss_error (sci_idx, code, "%s", msg);
+}
diff --git a/mechglue/src/util/ss/execute_cmd.c b/mechglue/src/util/ss/execute_cmd.c
new file mode 100644
index 000000000..3f684052c
--- /dev/null
+++ b/mechglue/src/util/ss/execute_cmd.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright 1987, 1988, 1989 by Massachusetts Institute of Technology
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include "ss_internal.h"
+#include "copyright.h"
+#include <stdio.h>
+
+
+/*
+ * get_request(tbl, idx)
+ *
+ * Function:
+ *      Gets the idx'th request from the request table pointed to
+ *      by tbl.
+ * Arguments:
+ *      tbl (ss_request_table *)
+ *              pointer to request table
+ *      idx (int)
+ *              index into table
+ * Returns:
+ *      (ss_request_entry *)
+ *              pointer to request table entry
+ * Notes:
+ *      Has been replaced by a macro.
+ */
+
+#ifdef __SABER__
+/* sigh.  saber won't deal with pointer-to-const-struct */
+static struct _ss_request_entry * get_request (tbl, idx)
+    ss_request_table * tbl;
+    int idx;
+{
+    struct _ss_request_table *tbl1 = (struct _ss_request_table *) tbl;
+    struct _ss_request_entry *e = (struct _ss_request_entry *) tbl1->requests;
+    return e + idx;
+}
+#else
+#define get_request(tbl,idx)    ((tbl) -> requests + (idx))
+#endif
+
+/*
+ * check_request_table(rqtbl, argc, argv, sci_idx)
+ *
+ * Function:
+ *      If the command string in argv[0] is in the request table, execute
+ *      the commands and return error code 0.  Otherwise, return error
+ *      code ss_et_command_not_found.
+ * Arguments:
+ *      rqtbl (ss_request_table *)
+ *              pointer to request table
+ *      argc (int)
+ *              number of elements in argv[]
+ *      argv (char *[])
+ *              argument string array
+ *      sci_idx (int)
+ *              ss-internal index for subsystem control info structure
+ * Returns:
+ *      (int)
+ *              zero if command found, ss_et_command_not_found otherwise
+ * Notes:
+ */
+
+static int check_request_table (rqtbl, argc, argv, sci_idx)
+    register ss_request_table *rqtbl;
+    int argc;
+    char *argv[];
+    int sci_idx;
+{
+#ifdef __SABER__
+    struct _ss_request_entry *request;
+#else
+    register ss_request_entry *request;
+#endif
+    register ss_data *info;
+    register char const * const * name;
+    char *string = argv[0];
+    int i;
+
+    info = ss_info(sci_idx);
+    info->argc = argc;
+    info->argv = argv;
+    for (i = 0; (request = get_request(rqtbl, i))->command_names; i++) {
+	for (name = request->command_names; *name; name++)
+	    if (!strcmp(*name, string)) {
+		info->current_request = request->command_names[0];
+		(request->function)(argc, (const char *const *) argv,
+				    sci_idx,info->info_ptr);
+		info->current_request = (char *)NULL;
+		return(0);
+	    }
+    }
+    return(SS_ET_COMMAND_NOT_FOUND);
+}
+
+/*
+ * really_execute_command(sci_idx, argc, argv)
+ *
+ * Function:
+ *      Fills in the argc, argv values in the subsystem entry and
+ *      call the appropriate routine.
+ * Arguments:
+ *      sci_idx (int)
+ *              ss-internal index for subsystem control info structure
+ *      argc (int)
+ *              number of arguments in argument list
+ *      argv (char **[])
+ *              pointer to parsed argument list (may be reallocated
+ *              on abbrev expansion)
+ *
+ * Returns:
+ *      (int)
+ *              Zero if successful, ss_et_command_not_found otherwise.
+ * Notes:
+ */
+
+static int really_execute_command (sci_idx, argc, argv)
+    int sci_idx;
+    int argc;
+    char **argv[];
+{
+    register ss_request_table **rqtbl;
+    register ss_data *info;
+
+    info = ss_info(sci_idx);
+
+    for (rqtbl = info->rqt_tables; *rqtbl; rqtbl++) {
+        if (check_request_table (*rqtbl, argc, *argv, sci_idx) == 0)
+            return(0);
+    }
+    return(SS_ET_COMMAND_NOT_FOUND);
+}
+
+/*
+ * ss_execute_command(sci_idx, argv)
+ *
+ * Function:
+ *	Executes a parsed command list within the subsystem.
+ * Arguments:
+ *	sci_idx (int)
+ *		ss-internal index for subsystem control info structure
+ *	argv (char *[])
+ *		parsed argument list
+ * Returns:
+ *	(int)
+ *		Zero if successful, ss_et_command_not_found otherwise.
+ * Notes:
+ */
+
+int
+ss_execute_command(sci_idx, argv)
+	int sci_idx;
+	register char *argv[];
+{
+	register int i, argc;
+	char **argp;
+
+	argc = 0;
+	for (argp = argv; *argp; argp++)
+		argc++;
+	argp = (char **)malloc((argc+1)*sizeof(char *));
+	for (i = 0; i <= argc; i++)
+		argp[i] = argv[i];
+	i = really_execute_command(sci_idx, argc, &argp);
+	free(argp);
+	return(i);
+}
+
+/*
+ * ss_execute_line(sci_idx, line_ptr)
+ *
+ * Function:
+ *      Parses and executes a command line within a subsystem.
+ * Arguments:
+ *      sci_idx (int)
+ *              ss-internal index for subsystem control info structure
+ *      line_ptr (char *)
+ *              Pointer to command line to be parsed.
+ * Returns:
+ *      (int)
+ *      	Error code.
+ * Notes:
+ */
+
+int ss_execute_line (sci_idx, line_ptr)
+    int sci_idx;
+    char *line_ptr;
+{
+    char **argv;
+    int argc, ret;
+
+    /* flush leading whitespace */
+    while (line_ptr[0] == ' ' || line_ptr[0] == '\t')
+        line_ptr++;
+
+    /* check if it should be sent to operating system for execution */
+    if (*line_ptr == '!') {
+        if (ss_info(sci_idx)->flags.escape_disabled)
+            return SS_ET_ESCAPE_DISABLED;
+        else {
+            line_ptr++;
+            system(line_ptr);
+	    return 0;
+        }
+    }
+
+    /* parse it */
+    argv = ss_parse(sci_idx, line_ptr, &argc);
+    if (argc == 0)
+        return 0;
+
+    /* look it up in the request tables, execute if found */
+    ret = really_execute_command (sci_idx, argc, &argv);
+
+    free(argv);
+
+    return(ret);
+}
diff --git a/mechglue/src/util/ss/help.c b/mechglue/src/util/ss/help.c
new file mode 100644
index 000000000..2752f40ed
--- /dev/null
+++ b/mechglue/src/util/ss/help.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <fcntl.h>	/* just for O_* */
+#include <sys/wait.h>
+#include "ss_internal.h"
+#include "copyright.h"
+
+
+void ss_help (argc, argv, sci_idx, info_ptr)
+    int argc;
+    char const * const *argv;
+    int sci_idx;
+    pointer info_ptr;
+{
+    char buffer[MAXPATHLEN];
+    char const *request_name;
+    int code;
+    int fd, child;
+    register int idx;
+    register ss_data *info;
+
+    request_name = ss_current_request(sci_idx, &code);
+    if (code != 0) {
+	ss_perror(sci_idx, code, "");
+	return;		/* no ss_abort_line, if invalid invocation */
+    }
+    if (argc == 1) {
+	ss_list_requests(argc, argv, sci_idx, info_ptr);
+	return;
+    }
+    else if (argc != 2) {
+	/* should do something better than this */
+	sprintf(buffer, "usage:\n\t%s [topic|command]\nor\t%s\n",
+		request_name, request_name);
+	ss_perror(sci_idx, 0, buffer);
+	return;
+    }
+    info = ss_info(sci_idx);
+    if (info->info_dirs == (char **)NULL) {
+	ss_perror(sci_idx, SS_ET_NO_INFO_DIR, (char *)NULL);
+	return;
+    }
+    if (info->info_dirs[0] == (char *)NULL) {
+	ss_perror(sci_idx, SS_ET_NO_INFO_DIR, (char *)NULL);
+	return;
+    }
+    for (idx = 0; info->info_dirs[idx] != (char *)NULL; idx++) {
+	(void) strncpy(buffer, info->info_dirs[idx], sizeof(buffer) - 1);
+	buffer[sizeof(buffer) - 1] = '\0';
+	(void) strncat(buffer, "/", sizeof(buffer) - 1 - strlen(buffer));
+	(void) strncat(buffer, argv[1], sizeof(buffer) - 1 - strlen(buffer));
+	(void) strncat(buffer, ".info", sizeof(buffer) - 1 - strlen(buffer));
+	if ((fd = open(&buffer[0], O_RDONLY)) >= 0) goto got_it;
+    }
+    if ((fd = open(&buffer[0], O_RDONLY)) < 0) {
+	char buf[MAXPATHLEN];
+	strncpy(buf, "No info found for ", sizeof(buf) - 1);
+	buf[sizeof(buf) - 1] = '\0';
+	strncat(buf, argv[1], sizeof(buf) - 1 - strlen(buf));
+	ss_perror(sci_idx, 0, buf);
+	return;
+    }
+got_it:
+    switch (child = fork()) {
+    case -1:
+	ss_perror(sci_idx, errno, "Can't fork for pager");
+	return;
+    case 0:
+	(void) dup2(fd, 0); /* put file on stdin */
+	ss_page_stdin();
+    default:
+	(void) close(fd); /* what can we do if it fails? */
+#ifdef WAIT_USES_INT
+	while (wait((int *)NULL) != child) {
+#else
+	while (wait((union wait *)NULL) != child) {
+#endif
+	    /* do nothing if wrong pid */
+	};
+    }
+}
+
+#ifndef USE_DIRENT_H
+#include <sys/dir.h>
+#else
+#include <dirent.h>
+#endif
+
+void ss_add_info_dir(sci_idx, info_dir, code_ptr)
+    int sci_idx;
+    char *info_dir;
+    int *code_ptr;
+{
+    register ss_data *info;
+    DIR *d;
+    int n_dirs;
+    register char **dirs;
+
+    info = ss_info(sci_idx);
+    if (info_dir == NULL && *info_dir) {
+	*code_ptr = SS_ET_NO_INFO_DIR;
+	return;
+    }
+    if ((d = opendir(info_dir)) == (DIR *)NULL) {
+	*code_ptr = errno;
+	return;
+    }
+    closedir(d);
+    dirs = info->info_dirs;
+    for (n_dirs = 0; dirs[n_dirs] != (char *)NULL; n_dirs++)
+	;		/* get number of non-NULL dir entries */
+    dirs = (char **)realloc((char *)dirs,
+			    (unsigned)(n_dirs + 2)*sizeof(char *));
+    if (dirs == (char **)NULL) {
+	info->info_dirs = (char **)NULL;
+	*code_ptr = errno;
+	return;
+    }
+    info->info_dirs = dirs;
+    dirs[n_dirs + 1] = (char *)NULL;
+    dirs[n_dirs] = malloc((unsigned)strlen(info_dir)+1);
+    strcpy(dirs[n_dirs], info_dir);
+    *code_ptr = 0;
+}
+
+void ss_delete_info_dir(sci_idx, info_dir, code_ptr)
+    int sci_idx;
+    char *info_dir;
+    int *code_ptr;
+{
+    register char **i_d;
+    register char **info_dirs;
+
+    info_dirs = ss_info(sci_idx)->info_dirs;
+    for (i_d = info_dirs; *i_d; i_d++) {
+	if (!strcmp(*i_d, info_dir)) {
+	    while (*i_d) {
+		*i_d = *(i_d+1);
+		i_d++;
+	    }
+	    *code_ptr = 0;
+	    return;
+	}
+    }
+    *code_ptr = SS_ET_NO_INFO_DIR;
+}
diff --git a/mechglue/src/util/ss/invocation.c b/mechglue/src/util/ss/invocation.c
new file mode 100644
index 000000000..5e1a2565b
--- /dev/null
+++ b/mechglue/src/util/ss/invocation.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+#include "ss_internal.h"
+#include "copyright.h"
+#define	size	sizeof(ss_data *)
+
+
+int ss_create_invocation(subsystem_name, version_string, info_ptr,
+			 request_table_ptr, code_ptr)
+	char *subsystem_name, *version_string;
+	char *info_ptr;
+	ss_request_table *request_table_ptr;
+	int *code_ptr;
+{
+	register int sci_idx;
+	register ss_data *new_table;
+	register ss_data **table;
+
+	*code_ptr = 0;
+	table = _ss_table;
+	new_table = (ss_data *) malloc(sizeof(ss_data));
+
+	if (table == (ss_data **) NULL) {
+		table = (ss_data **) malloc(2 * size);
+		table[0] = table[1] = (ss_data *)NULL;
+	}
+	initialize_ss_error_table ();
+
+	for (sci_idx = 1; table[sci_idx] != (ss_data *)NULL; sci_idx++)
+		;
+	table = (ss_data **) realloc((char *)table,
+				     ((unsigned)sci_idx+2)*size);
+	table[sci_idx+1] = (ss_data *) NULL;
+	table[sci_idx] = new_table;
+
+	new_table->subsystem_name = subsystem_name;
+	new_table->subsystem_version = version_string;
+	new_table->argv = (char **)NULL;
+	new_table->current_request = (char *)NULL;
+	new_table->info_dirs = (char **)malloc(sizeof(char *));
+	*new_table->info_dirs = (char *)NULL;
+	new_table->info_ptr = info_ptr;
+	new_table->prompt = malloc((unsigned)strlen(subsystem_name)+4);
+	strcpy(new_table->prompt, subsystem_name);
+	strcat(new_table->prompt, ":  ");
+#ifdef silly
+	new_table->abbrev_info = ss_abbrev_initialize("/etc/passwd", code_ptr);
+#else
+	new_table->abbrev_info = NULL;
+#endif
+	new_table->flags.escape_disabled = 0;
+	new_table->flags.abbrevs_disabled = 0;
+	new_table->rqt_tables =
+		(ss_request_table **) calloc(2, sizeof(ss_request_table *));
+	*(new_table->rqt_tables) = request_table_ptr;
+	*(new_table->rqt_tables+1) = (ss_request_table *) NULL;
+	_ss_table = table;
+	return(sci_idx);
+}
+
+void
+ss_delete_invocation(sci_idx)
+	int sci_idx;
+{
+	register ss_data *t;
+	int ignored_code;
+
+	t = ss_info(sci_idx);
+	free(t->prompt);
+	free(t->rqt_tables);
+	while(t->info_dirs[0] != (char *)NULL)
+		ss_delete_info_dir(sci_idx, t->info_dirs[0], &ignored_code);
+	free((char *)t->info_dirs);
+	free((char *)t);
+}
diff --git a/mechglue/src/util/ss/list_rqs.c b/mechglue/src/util/ss/list_rqs.c
new file mode 100644
index 000000000..045a0c82b
--- /dev/null
+++ b/mechglue/src/util/ss/list_rqs.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+#include "copyright.h"
+#include "ss_internal.h"
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+
+#ifdef lint     /* "lint returns a value which is sometimes ignored" */
+#define DONT_USE(x)     x=x;
+#else /* !lint */
+#define DONT_USE(x)     ;
+#endif /* lint */
+
+static char const twentyfive_spaces[26] =
+    "                         ";
+static char const NL[2] = "\n";
+
+void
+ss_list_requests(argc, argv, sci_idx, info_ptr)
+    int argc;
+    const char * const *argv;
+    int sci_idx;
+#ifdef __STDC__
+    void *info_ptr;
+#else
+    char *info_ptr;
+#endif
+{
+    register ss_request_entry *entry;
+    register char const * const *name;
+    register int spacing;
+    register ss_request_table **table;
+
+    char buffer[BUFSIZ];
+    FILE *output;
+    int fd;
+#ifdef POSIX_SIGNALS
+    struct sigaction nsig, osig;
+    sigset_t nmask, omask;
+#else
+    int mask;
+    RETSIGTYPE (*func)();
+#endif
+#ifndef WAIT_USES_INT
+    union wait waitb;
+#else
+    int waitb;
+#endif
+
+    DONT_USE(argc);
+    DONT_USE(argv);
+
+#ifdef POSIX_SIGNALS
+    sigemptyset(&nmask);
+    sigaddset(&nmask, SIGINT);
+    sigprocmask(SIG_BLOCK, &nmask, &omask);
+    
+    nsig.sa_handler = SIG_IGN;
+    sigemptyset(&nsig.sa_mask);
+    nsig.sa_flags = 0;
+    sigaction(SIGINT, &nsig, &osig);
+#else
+    mask = sigblock(sigmask(SIGINT));
+    func = signal(SIGINT, SIG_IGN);
+#endif
+
+    fd = ss_pager_create();
+    output = fdopen(fd, "w");
+
+#ifdef POSIX_SIGNALS
+    sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
+#else
+    sigsetmask(mask);
+#endif
+
+    fprintf (output, "Available %s requests:\n\n",
+	     ss_info (sci_idx) -> subsystem_name);
+
+    for (table = ss_info(sci_idx)->rqt_tables; *table; table++) {
+        entry = (*table)->requests;
+        for (; entry->command_names; entry++) {
+            spacing = -2;
+            buffer[0] = '\0';
+            if (entry->flags & SS_OPT_DONT_LIST)
+                continue;
+            buffer[sizeof(buffer) - 1] = '\0';
+            for (name = entry->command_names; *name; name++) {
+                register int len = strlen(*name);
+                strncat(buffer, *name, sizeof(buffer) - 1 - strlen(buffer));
+                spacing += len + 2;
+                if (name[1]) {
+                    strncat(buffer, ", ", sizeof(buffer) - 1 - strlen(buffer));
+                }
+            }
+            if (spacing > 23) {
+                strncat(buffer, NL, sizeof(buffer) - 1 - strlen(buffer));
+                fputs(buffer, output);
+                spacing = 0;
+                buffer[0] = '\0';
+            }
+            strncat(buffer, twentyfive_spaces, sizeof(buffer) - 1 - (25-spacing));
+            strncpy(buffer + 25, entry->info_string, sizeof(buffer) - 1 - 25);
+            strncat(buffer, NL, sizeof(buffer) - 1 - strlen(buffer));
+            fputs(buffer, output);
+        }
+    }
+    fclose(output);
+#ifndef NO_FORK
+    wait(&waitb);
+#endif
+#ifdef POSIX_SIGNALS
+    sigaction(SIGINT, &osig, (struct sigaction *)0);
+#else
+    (void) signal(SIGINT, func);
+#endif
+}
diff --git a/mechglue/src/util/ss/listen.c b/mechglue/src/util/ss/listen.c
new file mode 100644
index 000000000..ae9700757
--- /dev/null
+++ b/mechglue/src/util/ss/listen.c
@@ -0,0 +1,169 @@
+/*
+ * Listener loop for subsystem library libss.a.
+ *
+ *	util/ss/listen.c
+ * 
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "copyright.h"
+#include "ss_internal.h"
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <termios.h>
+#include <sys/param.h>
+
+static ss_data *current_info;
+static jmp_buf listen_jmpb;
+
+static RETSIGTYPE print_prompt()
+{
+    struct termios termbuf;
+
+    if (tcgetattr(STDIN_FILENO, &termbuf) == 0) {
+	termbuf.c_lflag |= ICANON|ISIG|ECHO;
+	tcsetattr(STDIN_FILENO, TCSANOW, &termbuf);
+    }
+    (void) fputs(current_info->prompt, stdout);
+    (void) fflush(stdout);
+}
+
+static RETSIGTYPE listen_int_handler(signo)
+    int signo;
+{
+    putc('\n', stdout);
+    longjmp(listen_jmpb, 1);
+}
+
+int ss_listen (sci_idx)
+    int sci_idx;
+{
+    register char *cp;
+    register ss_data *info;
+    char input[BUFSIZ];
+    char buffer[BUFSIZ];
+    char *volatile end = buffer;
+    int code;
+    jmp_buf old_jmpb;
+    ss_data *old_info = current_info;
+#ifdef POSIX_SIGNALS
+    struct sigaction isig, csig, nsig, osig;
+    sigset_t nmask, omask;
+#else
+    register RETSIGTYPE (*sig_cont)();
+    RETSIGTYPE (*sig_int)(), (*old_sig_cont)();
+    int mask;
+#endif
+    
+    current_info = info = ss_info(sci_idx);
+    info->abort = 0;
+
+#ifdef POSIX_SIGNALS
+    csig.sa_handler = (RETSIGTYPE (*)())0;
+    sigemptyset(&nmask);
+    sigaddset(&nmask, SIGINT);
+    sigprocmask(SIG_BLOCK, &nmask, &omask);
+#else
+    sig_cont = (RETSIGTYPE (*)())0;
+    mask = sigblock(sigmask(SIGINT));
+#endif
+
+    memcpy(old_jmpb, listen_jmpb, sizeof(jmp_buf));
+
+#ifdef POSIX_SIGNALS
+    nsig.sa_handler = listen_int_handler;
+    sigemptyset(&nsig.sa_mask);
+    nsig.sa_flags = 0;
+    sigaction(SIGINT, &nsig, &isig);
+#else
+    sig_int = signal(SIGINT, listen_int_handler);
+#endif
+
+    setjmp(listen_jmpb);
+
+#ifdef POSIX_SIGNALS
+    sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
+#else
+    (void) sigsetmask(mask);
+#endif
+    while(!info->abort) {
+	print_prompt();
+	*end = '\0';
+#ifdef POSIX_SIGNALS
+	nsig.sa_handler = listen_int_handler;	/* fgets is not signal-safe */
+	osig = csig;
+	sigaction(SIGCONT, &nsig, &csig);
+	if ((RETSIGTYPE (*)())csig.sa_handler==(RETSIGTYPE (*)())listen_int_handler)
+	    csig = osig;
+#else
+	old_sig_cont = sig_cont;
+	sig_cont = signal(SIGCONT, print_prompt);
+	if (sig_cont == print_prompt)
+	    sig_cont = old_sig_cont;
+#endif
+	if (fgets(input, BUFSIZ, stdin) != input) {
+	    code = SS_ET_EOF;
+	    goto egress;
+	}
+	cp = strchr(input, '\n');
+	if (cp) {
+	    *cp = '\0';
+	    if (cp == input)
+		continue;
+	}
+#ifdef POSIX_SIGNALS
+	sigaction(SIGCONT, &csig, (struct sigaction *)0);
+#else
+	(void) signal(SIGCONT, sig_cont);
+#endif
+	for (end = input; *end; end++)
+	    ;
+
+	code = ss_execute_line (sci_idx, input);
+	if (code == SS_ET_COMMAND_NOT_FOUND) {
+	    register char *c = input;
+	    while (*c == ' ' || *c == '\t')
+		c++;
+	    cp = strchr (c, ' ');
+	    if (cp)
+		*cp = '\0';
+	    cp = strchr (c, '\t');
+	    if (cp)
+		*cp = '\0';
+	    ss_error (sci_idx, 0,
+		    "Unknown request \"%s\".  Type \"?\" for a request list.",
+		       c);
+	}
+    }
+    code = 0;
+egress:
+#ifdef POSIX_SIGNALS
+    sigaction(SIGINT, &isig, (struct sigaction *)0);
+#else
+    (void) signal(SIGINT, sig_int);
+#endif
+    memcpy(listen_jmpb, old_jmpb, sizeof(jmp_buf));
+    current_info = old_info;
+    return code;
+}
+
+void ss_abort_subsystem(sci_idx, code)
+    int sci_idx;
+    int code;
+{
+    ss_info(sci_idx)->abort = 1;
+    ss_info(sci_idx)->exit_status = code;
+    
+}
+
+void ss_quit(argc, argv, sci_idx, infop)
+    int argc;
+    char const * const *argv;
+    int sci_idx;
+    pointer infop;
+{
+    ss_abort_subsystem(sci_idx, 0);
+}
diff --git a/mechglue/src/util/ss/mit-sipb-copyright.h b/mechglue/src/util/ss/mit-sipb-copyright.h
new file mode 100644
index 000000000..d6d5f1edc
--- /dev/null
+++ b/mechglue/src/util/ss/mit-sipb-copyright.h
@@ -0,0 +1,22 @@
+/*
+
+Copyright 1987 by the Student Information Processing Board
+	of the Massachusetts Institute of Technology
+
+Permission to use, copy, modify, and distribute this software
+and its documentation for any purpose and without fee is
+hereby granted, provided that the above copyright notice
+appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation,
+and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+Furthermore if you modify this software you must label
+your software as modified software and not distribute it in such a
+fashion that it might be confused with the original M.I.T. software.
+M.I.T. and the M.I.T. S.I.P.B. make no representations about
+the suitability of this software for any purpose.  It is
+provided "as is" without express or implied warranty.
+
+*/
+
diff --git a/mechglue/src/util/ss/mk_cmds.c b/mechglue/src/util/ss/mk_cmds.c
new file mode 100644
index 000000000..8e29ccfb3
--- /dev/null
+++ b/mechglue/src/util/ss/mk_cmds.c
@@ -0,0 +1,102 @@
+/*
+ * make_commands.c
+ *
+ * util/ss/mk_cmds.c
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "copyright.h"
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <string.h>
+#include "ss_internal.h"
+
+static const char copyright[] =
+    "Copyright 1987 by MIT Student Information Processing Board";
+
+extern pointer malloc (unsigned);
+extern char *last_token;
+extern FILE *output_file;
+
+extern FILE *yyin, *yyout;
+#ifndef NO_YYLINENO
+extern int yylineno;
+#endif
+
+int main(argc, argv)
+    int argc;
+    char **argv;
+{
+    char c_file[MAXPATHLEN];
+    int result;
+    char *path, *p, *q;
+
+    if (argc != 2) {
+	fputs("Usage: ", stderr);
+	fputs(argv[0], stderr);
+	fputs("cmdtbl.ct\n", stderr);
+	exit(1);
+    }
+
+    path = malloc(strlen(argv[1])+4); /* extra space to add ".ct" */
+    strcpy(path, argv[1]);
+    p = strrchr(path, '/');
+    if (p == (char *)NULL)
+	p = path;
+    else
+	p++;
+    p = strrchr(p, '.');
+    if (p == (char *)NULL || strcmp(p, ".ct"))
+	strcat(path, ".ct");
+    yyin = fopen(path, "r");
+    if (!yyin) {
+	perror(path);
+	exit(1);
+    }
+
+    p = strrchr(path, '.');
+    *p = '\0';
+    q = rindex(path, '/');
+    strncpy(c_file, (q) ? q + 1 : path, sizeof(c_file) - 1);
+    c_file[sizeof(c_file) - 1] = '\0';
+    strncat(c_file, ".c", sizeof(c_file) - 1 - strlen(c_file));
+    *p = '.';
+
+    output_file = fopen(c_file, "w+");
+    if (!output_file) {
+	perror(c_file);
+	exit(1);
+    }
+
+    fputs("/* ", output_file);
+    fputs(c_file, output_file);
+    fputs(" - automatically generated from ", output_file);
+    fputs(path, output_file);
+    fputs(" */\n", output_file);
+    fputs("#include <ss/ss.h>\n\n", output_file);
+    fputs("#ifndef __STDC__\n#define const\n#endif\n\n", output_file);
+    /* parse it */
+    result = yyparse();
+    /* put file descriptors back where they belong */
+    fclose(yyin);		/* bye bye input file */
+    fclose(output_file);	/* bye bye output file */
+
+    return result;
+}
+
+yyerror(s)
+    char *s;
+{
+    fputs(s, stderr);
+#ifdef NO_YYLINENO
+    fprintf(stderr, "\nLast token was '%s'\n", last_token);
+#else
+    fprintf(stderr, "\nLine %d; last token was '%s'\n",
+	    yylineno, last_token);
+#endif
+}
diff --git a/mechglue/src/util/ss/mk_cmds.sh b/mechglue/src/util/ss/mk_cmds.sh
new file mode 100755
index 000000000..aaf3256b5
--- /dev/null
+++ b/mechglue/src/util/ss/mk_cmds.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+#
+
+DIR=@DIR@
+AWK=@AWK@
+SED=@SED@
+
+set -e
+FILE=$1
+ROOT=`echo $1 | ${SED} -e s/.ct$//`
+BASE=`echo $ROOT | ${SED} -e 's;.*/;;'`
+TMP=ct$$.c
+
+if [ ! -r ${FILE} ] ; then
+	echo mk_cmds: ${FILE} not found
+	exit 1
+fi
+
+${SED} -f ${DIR}/ct_c.sed  ${FILE} \
+	| ${AWK} -f ${DIR}/ct_c.awk rootname=${ROOT} outfile=${TMP} -
+
+if grep "^#__ERROR_IN_FILE" ${TMP} > /dev/null; then
+	rm ${TMP}
+	exit 1
+else
+	mv ${TMP} ${BASE}.c
+	exit 0
+fi
diff --git a/mechglue/src/util/ss/options.c b/mechglue/src/util/ss/options.c
new file mode 100644
index 000000000..dd648b01a
--- /dev/null
+++ b/mechglue/src/util/ss/options.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+#include "copyright.h"
+#include <stdio.h>
+#include "ss.h"
+
+struct option {
+     char *text;
+     long value;
+};
+
+static struct option options[] = {
+     { "dont_list", SS_OPT_DONT_LIST },
+     { "^list", SS_OPT_DONT_LIST },
+     { "dont_summarize", SS_OPT_DONT_SUMMARIZE },
+     { "^summarize", SS_OPT_DONT_SUMMARIZE },
+     { (char *)NULL, 0 }
+};
+
+long
+flag_val(string)
+     register char *string;
+{
+     register struct option *opt;
+     for (opt = options; opt->text; opt++)
+	  if (!strcmp(opt->text, string))
+	       return(opt->value);
+     return(0);
+}
diff --git a/mechglue/src/util/ss/pager.c b/mechglue/src/util/ss/pager.c
new file mode 100644
index 000000000..c8a52f079
--- /dev/null
+++ b/mechglue/src/util/ss/pager.c
@@ -0,0 +1,108 @@
+/*
+ * Pager: Routines to create a "more" running out of a particular file
+ * descriptor.
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "ss_internal.h"
+#include "copyright.h"
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <signal.h>
+
+static char MORE[] = "more";
+extern char *_ss_pager_name;
+extern char *getenv();
+
+/*
+ * this needs a *lot* of work....
+ *
+ * run in same process
+ * handle SIGINT sensibly
+ * allow finer control -- put-page-break-here
+ */
+void ss_page_stdin();
+
+#ifndef NO_FORK
+int ss_pager_create() 
+{
+	int filedes[2];
+     
+	if (pipe(filedes) != 0)
+		return(-1);
+
+	switch((int) fork()) {
+	case -1:
+		return(-1);
+	case 0:
+		/*
+		 * Child; dup read half to 0, close all but 0, 1, and 2
+		 */
+		if (dup2(filedes[0], 0) == -1)
+			exit(1);
+		ss_page_stdin();
+	default:
+		/*
+		 * Parent:  close "read" side of pipe, return
+		 * "write" side.
+		 */
+		(void) close(filedes[0]);
+		return(filedes[1]);
+	}
+}
+#else /* don't fork */
+int ss_pager_create()
+{
+    int fd;
+    fd = open("/dev/tty", O_WRONLY, 0);
+    return fd;
+}
+#endif
+
+void ss_page_stdin()
+{
+	int i;
+#ifdef POSIX_SIGNALS
+	struct sigaction sa;
+	sigset_t mask;
+#endif
+	for (i = 3; i < 32; i++)
+		(void) close(i);
+#ifdef POSIX_SIGNALS
+	sa.sa_handler = SIG_DFL;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	sigaction(SIGINT, &sa, (struct sigaction *)0);
+#else
+	(void) signal(SIGINT, SIG_DFL);
+#endif
+	{
+#ifdef POSIX_SIGNALS
+		sigemptyset(&mask);
+		sigaddset(&mask, SIGINT);
+		sigprocmask(SIG_UNBLOCK, &mask, (sigset_t *)0);
+#else
+		int mask = sigblock(0);
+		mask &= ~sigmask(SIGINT);
+		sigsetmask(mask);
+#endif
+	}
+	if (_ss_pager_name == (char *)NULL) {
+		if ((_ss_pager_name = getenv("PAGER")) == (char *)NULL)
+			_ss_pager_name = MORE;
+	}
+	(void) execlp(_ss_pager_name, _ss_pager_name, (char *) NULL);
+	{
+		/* minimal recovery if pager program isn't found */
+		char buf[80];
+		register int n;
+		while ((n = read(0, buf, 80)) > 0)
+			write(1, buf, (unsigned) n);
+	}
+	exit(errno);
+}
diff --git a/mechglue/src/util/ss/parse.c b/mechglue/src/util/ss/parse.c
new file mode 100644
index 000000000..382a61a40
--- /dev/null
+++ b/mechglue/src/util/ss/parse.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright info, see copyright.h.
+ */
+
+#include "ss_internal.h"
+#include "copyright.h"
+#include <errno.h>
+
+enum parse_mode { WHITESPACE, TOKEN, QUOTED_STRING };
+
+/*
+ * parse(line_ptr, argc_ptr)
+ *
+ * Function:
+ *      Parses line, dividing at whitespace, into tokens, returns
+ *      the "argc" and "argv" values.
+ * Arguments:
+ *      line_ptr (char *)
+ *              Pointer to text string to be parsed.
+ *      argc_ptr (int *)
+ *              Where to put the "argc" (number of tokens) value.
+ * Returns:
+ *      argv (char **)
+ *              Series of pointers to parsed tokens.
+ */
+
+#define NEW_ARGV(old,n) (char **)realloc((char *)old,\
+					 (unsigned)(n+2)*sizeof(char*))
+
+char **ss_parse (sci_idx, line_ptr, argc_ptr)
+    int sci_idx;
+    register char *line_ptr;
+    int *argc_ptr;
+{
+    register char **argv, *cp;
+    register int argc;
+    register enum parse_mode parse_mode;
+
+    argv = (char **) malloc (sizeof(char *));
+    if (argv == (char **)NULL) {
+	ss_error(sci_idx, errno, "Can't allocate storage");
+	*argc_ptr = 0;
+	return(argv);
+    }
+    *argv = (char *)NULL;
+
+    argc = 0;
+
+    parse_mode = WHITESPACE;	/* flushing whitespace */
+    cp = line_ptr;		/* cp is for output */
+    while (1) {
+#ifdef DEBUG
+	{
+	    printf ("character `%c', mode %d\n", *line_ptr, parse_mode);
+	}
+#endif
+	while (parse_mode == WHITESPACE) {
+	    if (*line_ptr == '\0')
+		goto end_of_line;
+	    if (*line_ptr == ' ' || *line_ptr == '\t') {
+		line_ptr++;
+		continue;
+	    }
+	    if (*line_ptr == '"') {
+		/* go to quoted-string mode */
+		parse_mode = QUOTED_STRING;
+		cp = line_ptr++;
+		argv = NEW_ARGV (argv, argc);
+		argv[argc++] = cp;
+		argv[argc] = NULL;
+	    }
+	    else {
+		/* random-token mode */
+		parse_mode = TOKEN;
+		cp = line_ptr;
+		argv = NEW_ARGV (argv, argc);
+		argv[argc++] = line_ptr;
+		argv[argc] = NULL;
+	    }
+	}
+	while (parse_mode == TOKEN) {
+	    if (*line_ptr == '\0') {
+		*cp++ = '\0';
+		goto end_of_line;
+	    }
+	    else if (*line_ptr == ' ' || *line_ptr == '\t') {
+		*cp++ = '\0';
+		line_ptr++;
+		parse_mode = WHITESPACE;
+	    }
+	    else if (*line_ptr == '"') {
+		line_ptr++;
+		parse_mode = QUOTED_STRING;
+	    }
+	    else {
+		*cp++ = *line_ptr++;
+	    }
+	}
+	while (parse_mode == QUOTED_STRING) {
+	    if (*line_ptr == '\0') {
+		ss_error (sci_idx, 0,
+			  "Unbalanced quotes in command line");
+		free (argv);
+		*argc_ptr = 0;
+		return NULL;
+	    }
+	    else if (*line_ptr == '"') {
+		if (*++line_ptr == '"') {
+		    *cp++ = '"';
+		    line_ptr++;
+		}
+		else {
+		    parse_mode = TOKEN;
+		}
+	    }
+	    else {
+		*cp++ = *line_ptr++;
+	    }
+	}
+    }
+end_of_line:
+    *argc_ptr = argc;
+#ifdef DEBUG
+    {
+	int i;
+	printf ("argc = %d\n", argc);
+	for (i = 0; i <= argc; i++)
+	    printf ("\targv[%2d] = `%s'\n", i,
+		    argv[i] ? argv[i] : "<NULL>");
+    }
+#endif
+    return(argv);
+}
diff --git a/mechglue/src/util/ss/prompt.c b/mechglue/src/util/ss/prompt.c
new file mode 100644
index 000000000..0751baeba
--- /dev/null
+++ b/mechglue/src/util/ss/prompt.c
@@ -0,0 +1,28 @@
+/*
+ * prompt.c: Routines for retrieving and setting a prompt.
+ *
+ * util/ss/prompt.c
+ *
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "copyright.h"
+#include <stdio.h>
+#include "ss_internal.h"
+
+void
+ss_set_prompt(sci_idx, new_prompt)
+     int sci_idx;
+     char *new_prompt;
+{
+     ss_info(sci_idx)->prompt = new_prompt;
+}
+
+char *
+ss_get_prompt(sci_idx)
+     int sci_idx;
+{
+     return(ss_info(sci_idx)->prompt);
+}
diff --git a/mechglue/src/util/ss/request_tbl.c b/mechglue/src/util/ss/request_tbl.c
new file mode 100644
index 000000000..46eb3a0ad
--- /dev/null
+++ b/mechglue/src/util/ss/request_tbl.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include "copyright.h"
+#include "ss_internal.h"
+
+#define ssrt ss_request_table	/* for some readable code... */
+
+void
+ss_add_request_table(sci_idx, rqtbl_ptr, position, code_ptr)
+	int sci_idx;
+	ssrt *rqtbl_ptr;
+	int position;		/* 1 -> becomes second... */
+	int *code_ptr;
+{
+	register ss_data *info;
+	register int i, size;
+
+	info = ss_info(sci_idx);
+	for (size=0; info->rqt_tables[size] != (ssrt *)NULL; size++)
+		;
+	/* size == C subscript of NULL == #elements */
+	size += 2;		/* new element, and NULL */
+	info->rqt_tables = (ssrt **)realloc(info->rqt_tables,
+					    size*sizeof(ssrt));
+	if (info->rqt_tables == (ssrt **)NULL) {
+		*code_ptr = errno;
+		return;
+	}
+	if (position > size - 2)
+		position = size - 2;
+
+	if (size > 1)
+		for (i = size - 2; i >= position; i--)
+			info->rqt_tables[i+1] = info->rqt_tables[i];
+
+	info->rqt_tables[position] = rqtbl_ptr;
+	info->rqt_tables[size-1] = (ssrt *)NULL;
+	*code_ptr = 0;
+}
+
+void
+ss_delete_request_table(sci_idx, rqtbl_ptr, code_ptr)
+     int sci_idx;
+     ssrt *rqtbl_ptr;
+     int *code_ptr;
+{
+     register ss_data *info;
+     register ssrt **rt1, **rt2;
+
+     *code_ptr = SS_ET_TABLE_NOT_FOUND;
+     info = ss_info(sci_idx);
+     rt1 = info->rqt_tables;
+     for (rt2 = rt1; *rt1; rt1++) {
+	  if (*rt1 != rqtbl_ptr) {
+	       *rt2++ = *rt1;
+	       *code_ptr = 0;
+	  }
+     }
+     *rt2 = (ssrt *)NULL;
+     return;
+}
diff --git a/mechglue/src/util/ss/requests.c b/mechglue/src/util/ss/requests.c
new file mode 100644
index 000000000..ccd0f792c
--- /dev/null
+++ b/mechglue/src/util/ss/requests.c
@@ -0,0 +1,47 @@
+/*
+ * Various minor routines...
+ *
+ * Copyright 1987, 1988, 1989 by MIT
+ *
+ * For copyright information, see mit-sipb-copyright.h.
+ */
+
+#include <stdio.h>
+#include "ss_internal.h"
+
+#define	DECLARE(name)	void name(argc,argv,sci_idx,info_ptr)int argc,sci_idx;const char * const *argv; pointer info_ptr;
+
+/*
+ * ss_self_identify -- assigned by default to the "." request
+ */
+DECLARE(ss_self_identify)
+{
+     register ss_data *info = ss_info(sci_idx);
+     printf("%s version %s\n", info->subsystem_name,
+	    info->subsystem_version);
+}
+
+/*
+ * ss_subsystem_name -- print name of subsystem
+ */
+DECLARE(ss_subsystem_name)
+{
+     printf("%s\n", ss_info(sci_idx)->subsystem_name);
+}
+
+/*
+ * ss_subsystem_version -- print version of subsystem
+ */
+DECLARE(ss_subsystem_version)
+{
+     printf("%s\n", ss_info(sci_idx)->subsystem_version);
+}
+
+/*
+ * ss_unimplemented -- routine not implemented (should be
+ * set up as (dont_list,dont_summarize))
+ */
+DECLARE(ss_unimplemented)
+{
+     ss_perror(sci_idx, SS_ET_UNIMPLEMENTED, "");
+}
diff --git a/mechglue/src/util/ss/ss.h b/mechglue/src/util/ss/ss.h
new file mode 100644
index 000000000..45ba4061b
--- /dev/null
+++ b/mechglue/src/util/ss/ss.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see mit-sipb-copyright.h.
+ */
+
+#ifndef _ss_h
+#define _ss_h __FILE__
+
+#include <errno.h>
+#include <ss/ss_err.h>
+
+#ifdef __STDC__
+#define __SS_CONST const
+#define __SS_PROTO (int, const char * const *, int, void *)
+#else
+#define __SS_CONST
+#define __SS_PROTO ()
+#endif
+
+typedef __SS_CONST struct _ss_request_entry {
+    __SS_CONST char * __SS_CONST *command_names; /* whatever */
+    void (* __SS_CONST function) __SS_PROTO; /* foo */
+    __SS_CONST char * __SS_CONST info_string;	/* NULL */
+    int flags;			/* 0 */
+} ss_request_entry;
+
+typedef __SS_CONST struct _ss_request_table {
+    int version;
+    ss_request_entry *requests;
+} ss_request_table;
+
+#define SS_RQT_TBL_V2	2
+
+typedef struct _ss_rp_options {	/* DEFAULT VALUES */
+    int version;		/* SS_RP_V1 */
+    void (*unknown) __SS_PROTO;	/* call for unknown command */
+    int allow_suspend;
+    int catch_int;
+} ss_rp_options;
+
+#define SS_RP_V1 1
+
+#define SS_OPT_DONT_LIST	0x0001
+#define SS_OPT_DONT_SUMMARIZE	0x0002
+
+void ss_help __SS_PROTO;
+void ss_list_requests __SS_PROTO;
+void ss_quit __SS_PROTO;
+char *ss_current_request();
+char *ss_name(int);
+void ss_error (int, long, char const *, ...);
+void ss_perror (int, long, char const *);
+int ss_listen (int);
+int ss_create_invocation(char *, char *, char *, ss_request_table *, int *);
+void ss_delete_invocation(int);
+void ss_add_info_dir(int , char *, int *);
+void ss_delete_info_dir(int , char *, int *);
+int ss_execute_command(int sci_idx, char **);
+void ss_abort_subsystem(int, int);
+void ss_set_prompt(int, char *);
+char *ss_get_prompt(int);
+void ss_add_request_table(int, ss_request_table *, int, int *);
+void ss_delete_request_table(int, ss_request_table *, int *);
+int ss_execute_line (int, char*);
+extern ss_request_table ss_std_requests;
+#endif /* _ss_h */
diff --git a/mechglue/src/util/ss/ss_err.et b/mechglue/src/util/ss/ss_err.et
new file mode 100644
index 000000000..80e9dfa44
--- /dev/null
+++ b/mechglue/src/util/ss/ss_err.et
@@ -0,0 +1,39 @@
+	error_table ss
+
+ec	SS_ET_SUBSYSTEM_ABORTED,
+	"Subsystem aborted"
+
+ec	SS_ET_VERSION_MISMATCH,
+	"Version mismatch"
+
+ec	SS_ET_NULL_INV,
+	"No current invocation"
+
+ec	SS_ET_NO_INFO_DIR,
+	"No info directory"
+
+ec	SS_ET_COMMAND_NOT_FOUND,
+	"Command not found"
+
+ec	SS_ET_LINE_ABORTED,
+	"Command line aborted"
+
+ec	SS_ET_EOF,
+	"End-of-file reached"
+
+ec	SS_ET_PERMISSION_DENIED,
+	"Permission denied"
+
+ec	SS_ET_TABLE_NOT_FOUND,
+	"Request table not found"
+
+ec	SS_ET_NO_HELP_FILE,
+	"No info available"
+
+ec	SS_ET_ESCAPE_DISABLED,
+	"Shell escapes are disabled"
+
+ec	SS_ET_UNIMPLEMENTED,
+	"Sorry, this request is not yet implemented"
+
+	end
diff --git a/mechglue/src/util/ss/ss_internal.h b/mechglue/src/util/ss/ss_internal.h
new file mode 100644
index 000000000..f8d059d21
--- /dev/null
+++ b/mechglue/src/util/ss/ss_internal.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#ifndef _ss_ss_internal_h
+#define _ss_ss_internal_h __FILE__
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+typedef void * pointer;
+
+#include "ss.h"
+
+#if defined(__GNUC__)
+#define LOCAL_ALLOC(x) __builtin_alloca(x)
+#define LOCAL_FREE(x)
+#else
+#if defined(vax)
+#define LOCAL_ALLOC(x) alloca(x)
+#define LOCAL_FREE(x)
+extern pointer alloca (unsigned);
+#else
+#if defined(__HIGHC__)	/* Barf! */
+pragma on(alloca);
+#define LOCAL_ALLOC(x) alloca(x)
+#define LOCAL_FREE(x)
+extern pointer alloca (unsigned);
+#else
+/* no alloca? */
+#define LOCAL_ALLOC(x) malloc(x)
+#define LOCAL_FREE(x) free(x)
+#endif
+#endif
+#endif				/* LOCAL_ALLOC stuff */
+
+typedef char BOOL;
+
+typedef struct _ss_abbrev_entry {
+    char *name;			/* abbrev name */
+    char **abbrev;		/* new tokens to insert */
+    unsigned int beginning_of_line : 1;
+} ss_abbrev_entry;
+
+typedef struct _ss_abbrev_list {
+    int n_abbrevs;
+    ss_abbrev_entry *first_abbrev;
+} ss_abbrev_list;
+
+typedef struct {
+/*    char *path; */
+    ss_abbrev_list abbrevs[127];
+} ss_abbrev_info;
+
+typedef struct _ss_data {	/* init values */
+    /* this subsystem */
+    char *subsystem_name;
+    char *subsystem_version;
+    /* current request info */
+    int argc;
+    char **argv;		/* arg list */
+    char const *current_request; /* primary name */
+    /* info directory for 'help' */
+    char **info_dirs;
+    /* to be extracted by subroutines */
+    pointer info_ptr;		/* (void *) NULL */
+    /* for ss_listen processing */
+    char *prompt;
+    ss_request_table **rqt_tables;
+    ss_abbrev_info *abbrev_info;
+    struct {
+	unsigned int  escape_disabled : 1,
+		      abbrevs_disabled : 1;
+    } flags;
+    /* to get out */
+    int abort;			/* exit subsystem */
+    int exit_status;
+} ss_data;
+
+#define CURRENT_SS_VERSION 1
+
+#define	ss_info(sci_idx)	(_ss_table[sci_idx])
+#define	ss_current_request(sci_idx,code_ptr)	\
+     (*code_ptr=0,ss_info(sci_idx)->current_request)
+void ss_unknown_function();
+void ss_delete_info_dir();
+char **ss_parse (int, char *, int *);
+ss_abbrev_info *ss_abbrev_initialize (char *, int *);
+void ss_page_stdin (void);
+int ss_pager_create (void);
+void ss_self_identify __SS_PROTO;
+void ss_subsystem_name __SS_PROTO;
+void ss_subsystem_version __SS_PROTO;
+void ss_unimplemented __SS_PROTO;
+
+extern ss_data **_ss_table;
+extern char *ss_et_msgs[];
+
+#ifndef HAVE_STDLIB_H
+extern pointer malloc (unsigned);
+extern pointer realloc (pointer, unsigned);
+extern pointer calloc (unsigned, unsigned);
+#endif
+
+#if defined(USE_SIGPROCMASK) && !defined(POSIX_SIGNALS)
+/* fake sigmask, sigblock, sigsetmask */
+#include <signal.h>
+#ifdef sigmask
+#undef sigmask
+#endif
+#define sigmask(x) (1L<<(x)-1)
+#define sigsetmask(x) sigprocmask(SIG_SETMASK,&x,NULL)
+static int _fake_sigstore;
+#define sigblock(x) (_fake_sigstore=x,sigprocmask(SIG_BLOCK,&_fake_sigstore,0))
+#endif
+#endif /* _ss_internal_h */
diff --git a/mechglue/src/util/ss/std_rqs.ct b/mechglue/src/util/ss/std_rqs.ct
new file mode 100644
index 000000000..500288a02
--- /dev/null
+++ b/mechglue/src/util/ss/std_rqs.ct
@@ -0,0 +1,46 @@
+	command_table	ss_std_requests;
+
+	request	ss_self_identify, "Identify the subsystem.",
+		".",
+		(dont_list, dont_summarize);
+
+	request	ss_help, "Display info on command or topic.",
+		help;
+
+	unimplemented
+		ss_list_help,
+		"List topics for which help is available.",
+		list_help, lh;
+
+	request	ss_list_requests, "List available commands.",
+		list_requests, lr, "?";
+
+	request	ss_quit, "Leave the subsystem.",
+		quit, q;
+
+	unimplemented
+		ss_abbrev,
+		"Enable/disable abbreviation processing of request lines.",
+		abbrev, ab;
+
+	unimplemented
+		ss_execute,
+		"Execute a UNIX command line.",
+		execute, e;
+
+	unimplemented
+		ss_summarize_requests,
+		"Produce a list of the most commonly used requests.",
+		"?";
+		
+	request	ss_subsystem_name,
+		"Return the name of this subsystem.",
+		subsystem_name,
+		(dont_list);
+
+	request	ss_subsystem_version,
+		"Return the version of this subsystem.",
+		subsystem_version,
+		(dont_list);
+
+	end;
diff --git a/mechglue/src/util/ss/test_ss.c b/mechglue/src/util/ss/test_ss.c
new file mode 100644
index 000000000..9bab95c3c
--- /dev/null
+++ b/mechglue/src/util/ss/test_ss.c
@@ -0,0 +1,99 @@
+/*
+ * util/ss/test_ss.c
+ */
+
+
+#include <stdio.h>
+#include "ss.h"
+
+extern ss_request_table test_cmds;
+
+#define TRUE 1
+#define FALSE 0
+
+static char def_subsystem_name[5] = "test";
+static char version [4] = "1.0";
+
+int main(argc, argv)
+    int argc;
+    char **argv;
+{
+    int code;
+    char *argv0 = argv[0];
+    char *initial_request = (char *)NULL;
+    int quit = FALSE;	/* quit after processing request */
+    int sci_idx;
+    char *subsystem_name;
+
+    subsystem_name = def_subsystem_name;
+
+    for (; *argv; ++argv, --argc) {
+	printf("checking arg: %s\n", *argv);
+	if (!strcmp(*argv, "-prompt")) {
+	    if (argc == 1) {
+		fprintf(stderr,
+			"No argument supplied with -prompt\n");
+		exit(1);
+	    }
+	    argc--; argv++;
+	    subsystem_name = *argv;
+	}
+	else if (!strcmp(*argv, "-request") || !strcmp(*argv, "-rq")) {
+	    if (argc == 1) {
+		fprintf(stderr,
+			"No string supplied with -request.\n");
+		exit(1);
+	    }
+	    argc--; argv++;
+	    initial_request = *argv;
+	}
+	else if (!strcmp(*argv, "-quit"))
+	    quit = TRUE;
+	else if (!strcmp(*argv, "-no_quit"))
+	    quit = FALSE;
+	else if (**argv == '-') {
+	    fprintf(stderr, "Unknown control argument %s\n",
+		    *argv);
+	    fprintf(stderr,
+	"Usage: %s [gateway] [ -prompt name ] [ -request name ] [ -quit ]\n",
+		    argv0);
+	    exit(1);
+	}
+    }
+
+    sci_idx = ss_create_invocation(subsystem_name, version,
+				   (char *)NULL, &test_cmds, &code);
+    if (code) {
+	ss_perror(sci_idx, code, "creating invocation");
+	exit(1);
+    }
+
+    (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &code);
+    if (code) {
+	ss_perror (sci_idx, code, "adding standard requests");
+	exit (1);
+    }
+
+    if (!quit)
+	printf("test version %s.  Type '?' for a list of commands.\n\n",
+	       version);
+
+    if (initial_request != (char *)NULL) {
+	code = ss_execute_line(sci_idx, initial_request);
+	if (code != 0)
+	    ss_perror(sci_idx, code, initial_request);
+    }
+    if (!quit || code)
+	code =  ss_listen (sci_idx);
+    exit(0);
+}
+
+
+void test_cmd (argc, argv)
+    int argc;
+    char **argv;
+{
+    while (++argv, --argc)
+	fputs(*argv, stdout);
+    putchar ('\n');
+}
diff --git a/mechglue/src/util/ss/utils.c b/mechglue/src/util/ss/utils.c
new file mode 100644
index 000000000..c57800157
--- /dev/null
+++ b/mechglue/src/util/ss/utils.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 1987, 1988 by MIT Student Information Processing Board
+ *
+ * For copyright information, see copyright.h.
+ */
+
+#include <string.h>
+#include "copyright.h"
+#include "ss_internal.h"	/* includes stdio and string */
+
+extern FILE *output_file;
+
+char *gensym(), *str_concat3(), *quote();
+extern long gensym_n;
+
+void write_ct(hdr, rql)
+    char const *hdr, *rql;
+{
+    char *sym;
+    sym = gensym("ssu");
+    fputs("static ss_request_entry ", output_file);
+    fputs(sym, output_file);
+    fputs("[] = {\n", output_file);
+    fputs(rql, output_file);
+    fputs("    { 0, 0, 0, 0 }\n", output_file);
+    fputs("};\n\nss_request_table ", output_file);
+    fputs(hdr, output_file);
+    fprintf(output_file, " = { %d, ", SS_RQT_TBL_V2);
+    fputs(sym, output_file);
+    fputs(" };\n", output_file);
+}
+
+char * generate_cmds_string(cmds)
+    char const *cmds;
+{
+    char * var_name = gensym("ssu");
+    fputs("static char const * const ", output_file);
+    fputs(var_name, output_file);
+    fputs("[] = {\n", output_file);
+    fputs(cmds, output_file);
+    fputs(",\n    (char const *)0\n};\n", output_file);
+    return(var_name);
+}
+
+void generate_function_definition(func)
+    char const *func;
+{
+    fputs("extern void ", output_file);
+    fputs(func, output_file);
+    fputs(" __SS_PROTO;\n", output_file);
+}
+
+char * generate_rqte(func_name, info_string, cmds, options)
+    char const *func_name;
+    char const *info_string;
+    char const *cmds;
+    int options;
+{
+    int size;
+    char *string, *var_name, numbuf[16];
+    var_name = generate_cmds_string(cmds);
+    generate_function_definition(func_name);
+    size = 6;		/* "    { " */
+    size += strlen(var_name)+8; /* "quux, " */
+    size += strlen(func_name)+8; /* "foo, " */
+    size += strlen(info_string)+8; /* "\"Info!\", " */
+    sprintf(numbuf, "%d", options);
+    size += strlen(numbuf)+5;		/* " }," + NL + NUL */
+    string = malloc(size);
+    strcpy(string, "    { ");
+    strcat(string, var_name);
+    strcat(string, ",\n      ");
+    strcat(string, func_name);
+    strcat(string, ",\n      ");
+    strcat(string, info_string);
+    strcat(string, ",\n      ");
+    strcat(string, numbuf);
+    strcat(string, " },\n");
+    return(string);
+}
+
+char *
+gensym(name)
+	char *name;
+{
+	char *symbol;
+
+	symbol = malloc((strlen(name)+6) * sizeof(char));
+	gensym_n++;
+	sprintf(symbol, "%s%05ld", name, gensym_n);
+	return(symbol);
+}
+
+/* concatenate three strings and return the result */
+char *str_concat3(a, b, c)
+	register char *a, *b, *c;
+{
+	char *result;
+	int size_a = strlen(a);
+	int size_b = strlen(b);
+	int size_c = strlen(c);
+
+	result = malloc((size_a + size_b + size_c + 2)*sizeof(char));
+	strcpy(result, a);
+	strcpy(&result[size_a], c);
+	strcpy(&result[size_a+size_c], b);
+	return(result);
+}
+
+/* return copy of string enclosed in double-quotes */
+char *quote(string)
+	register char *string;
+{
+	register char *result;
+	int len;
+	len = strlen(string)+1;
+	result = malloc(len+2);
+	result[0] = '"';
+	strncpy(&result[1], string, len-1);
+	result[len] = '"';
+	result[len+1] = '\0';
+	return(result);
+}
+
+#ifndef HAVE_STRDUP
+/* make duplicate of string and return pointer */
+char *strdup(s)
+	register char *s;
+{
+	register int len = strlen(s) + 1;
+	register char *new;
+	new = malloc(len);
+	strncpy(new, s, len);
+	return(new);
+}
+#endif
diff --git a/mechglue/src/util/support/ChangeLog b/mechglue/src/util/support/ChangeLog
new file mode 100644
index 000000000..8aa8414c3
--- /dev/null
+++ b/mechglue/src/util/support/ChangeLog
@@ -0,0 +1,226 @@
+2005-09-09  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake_addrinfo.c (getaddrinfo): Conditionalize last change on
+	AI_NUMERICSERV being defined.
+
+2005-09-01  Marc Aurele La France  <tsi@ualberta.ca>
+
+	* fake_addrinfo.c (getaddrinfo):  AI_NUMERICSERV fix for AIX.
+
+2005-07-28  Jeffrey Altman <jaltman@mit.edu>
+
+        * threads.c: Stub krb5int_pthread_loaded added for Windows
+        to prevent export errors.
+
+2005-05-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c [HAVE_PRAGMA_WEAK_REF]: Declare
+	pthread_{g,s}etspecific, pthread_key_{create,delete},
+	pthread_{create,join} as weak references.
+	(krb5int_pthread_loaded, loaded_test_aux) [HAVE_PRAGMA_WEAK_REF]:
+	New functions.
+	(flag_pthread_loaded, loaded_test_once) [HAVE_PRAGMA_WEAK_REF]:
+	New variables.
+	* libkrb5support.exports: Add krb5int_pthread_loaded.
+
+2005-05-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.c (fai_add_hosts_by_name): Pass null pointer
+	instead of telnet as service name.
+
+2005-03-20  Alexandra Ellwood  <lxs@mit.edu>
+
+	* threads.c (thread_termination): Free array of pointers
+	to thread-specific data (t) on thread termination.  Use
+	existing mutex to prevent the deletion of the array from
+	interfering with the global list of thread specific data
+	(used for library termination).
+
+2005-02-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (k5_key_delete) [pthread case]: Reset flags and
+	destructor function pointer to unset state.
+	(krb5int_thread_support_init, krb5int_thread_support_fini): If
+	SHOW_INITFINI_FUNCS is defined, print some tracing messages.
+
+2005-01-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (k5_key_delete) [ENABLE_THREADS && !_WIN32]: Don't
+	abort, just leak resources for now.
+
+2005-01-17  Jeffrey Altman <jaltman@mit.edu>
+
+        * threads.c: implement cleanup of static vars on library
+                unload (for Windows)
+
+2005-01-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (k5_mutex_lock_update_stats,
+	krb5int_mutex_unlock_update_stats, krb5int_mutex_report_stats):
+	Define as KRB5_CALLCONV.
+	(krb5int_mutex_lock_update_stats,
+	krb5int_mutex_unlock_update_stats, krb5int_mutex_report_stats)
+	[_WIN32]: Undef macros before defining functions.
+
+2005-01-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (krb5int_mutex_lock_update_stats,
+	krb5int_mutex_unlock_update_stats, krb5int_mutex_report_stats)
+	[_WIN32 && !DEBUG_THREADS_STATS]: Define empty versions for
+	Windows.
+
+2004-12-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * Makefile.in: rename krb5support_32.dll to k5sprt32.dll
+
+2004-12-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c [DEBUG_THREADS_STATS]: Include stdio.h.
+	(stats_logfile) [DEBUG_THREADS_STATS]: New variable.
+	(krb5int_thread_support_init) [DEBUG_THREADS_STATS]: Set it to
+	point to a file on /dev/tty or stderr.
+	(krb5int_thread_support_fini) [DEBUG_THREADS_STATS]: Flush it.
+	(k5_mutex_lock_update_stats, krb5int_mutex_unlock_update_stats,
+	get_stddev, krb5int_mutex_report_stats) [DEBUG_THREADS_STATS]: New
+	functions.
+	* libkrb5support.exports: Add krb5int_mutex_*_stats.
+
+	* libkrb5support.exports: Add krb5int_in6addr_any.
+
+2004-11-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.c (HAVE_GETADDRINFO, HAVE_GETNAMEINFO)[_WIN32]:
+	Don't define here.
+	(protoname): Handle IPPROTO_IGMP.
+	(debug_dump_addrinfo_args): Update for current interfaces to
+	socktypename and familyname.
+
+2004-11-15  Ken Raeburn  <raeburn@mit.edu>
+
+	* cache-addrinfo.h, init-addrinfo.c: New files, split out from
+	fake-addrinfo.c.
+	* fake-addrinfo.c: Include cache-addrinfo.h.
+	(FAI_CACHE, struct face, struct fac): Moved to cache-addrinfo.h.
+	(krb5int_fac, krb5int_init_fac, krb5int_fini_fac): Moved to
+	init-addrinfo.c.
+	(addrinfo, struct addrinfo): Don't define.
+	(AI_* and NI_* and EAI_* macros): Don't define.
+	* threads.c: Include cache-addrinfo.h.
+	(krb5int_init_fac, krb5int_fini_fac): Don't declare.
+	* Makefile.in (SRCS, STLIBOBJS, LIBOBJS): Updated.
+
+2004-11-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.c: Import most of the contents of
+	include/fake-addrinfo.h, so we only compile it once.
+	(krb5int_getaddrinfo, krb5int_freeaddrinfo, krb5int_getnameinfo,
+	krb5int_gai_strerror): New functions, always defined and
+	exported.
+	* libkrb5support.exports: Export the new functions, not the old
+	_fac symbols.
+
+2004-10-25  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkrb5support.exports: Export krb5int_fac, _lock_fac,
+	_unlock_fac.
+
+2004-08-08  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (GET_NO_PTHREAD_TSD) [!HAVE_PRAGMA_WEAK_REF]: Macro
+	result type should be pointer to tsd_block.
+
+2004-07-31  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (krb5int_thread_support_init): Do finish
+	initialization after key creation in POSIX case.
+
+2004-07-23  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.c (krb5int_fac): Initialize the mutex.
+	(krb5int_init_fac, krb5int_fini_fac): New functions; finish
+	initializing or destroy the mutex.
+	(krb5int_lock_fac, krb5int_unlock_fac): New functions; lock the
+	mutex after calling krb5int_call_thread_support_init, or unlock
+	it.
+	* threads.c (krb5int_call_thread_support_init): New function.
+	(krb5int_init_fac, krb5int_fini_fac): Declare.
+	(krb5int_thread_support_init, krb5int_thread_support_fini): Call
+	them.
+
+2004-07-19  Ken Raeburn  <raeburn@mit.edu>
+
+	* fake-addrinfo.c: New file.
+	* Makefile.in (STLIBOBJS, LIBOBJS, SRCS): Add it.
+
+2004-07-06  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (struct tsd_block) [_WIN32]: Define.
+	(k5_setspecific) [_WIN32]: Don't fill in a 'next' field.  Fix
+	variable reference for TSD key.
+
+2004-06-24  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c: Reorganize code: One definition of each function,
+	with per-platform conditional tests inside, instead of
+	per-platform definitions for each function.  Combine common
+	aspects of each function across platforms.
+
+2004-06-21  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (key_lock): Change to a k5_mutex_t.
+	(k5_key_register): Use k5_ lock routines.
+	(pthread_getspecific, pthread_setspecific, pthread_key_create,
+	pthread_key_delete) [HAVE_PRAGMA_WEAK_REF]: Declare weak.
+	(tsd_if_single) [HAVE_PRAGMA_WEAK_REF]: New variable.
+	(krb5int_thread_support_init): Do pthread key creation only if
+	pthread code is loaded.
+	(krb5int_thread_support_fini): Do pthread key deletion only if
+	pthread code is loaded.
+	(k5_key_register, k5_getspecific, k5_setspecific): Use
+	tsd_if_single when pthread code is not loaded.
+
+2004-06-17  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (BUILDTOP, LIBNAME, XTRA, OBJFILE): Define for
+	Windows.
+	(LIBOBJS): Define.
+	($(BUILDTOP)/include/krb5/autoconf.h): Disable rule on Windows.
+
+	* threads.c (tls_idx, key_lock, destructors, destructors_set): New
+	variables for Windows.
+	(krb5int_thread_support_init, krb5int_thread_support_fini,
+	k5_key_register, k5_getspecific, k5_setspecific, k5_key_delete,
+	krb5int_thread_detach_hook): New functions for Windows.  Some are
+	just placeholders.
+
+2004-06-14  Ken Raeburn  <raeburn@mit.edu>
+
+	* libkrb5support.exports: Drop krb5int_foreach_localaddr.
+
+2004-06-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (LIBBASE): Renamed from LIB.
+
+2004-05-05  Ken Raeburn  <raeburn@mit.edu>
+
+	* threads.c (krb5int_thread_support_fini) [!ENABLE_THREADS]:
+	Provide a dummy function for now.
+
+	* foreachaddr.c: Deleted.  Code moved to lib/krb5/os/localaddr.c.
+	* fake-addrinfo.c: Deleted.
+	* Makefile.in (SRCS, STLIBOBJS): Updated.
+
+2004-05-04  Ken Raeburn  <raeburn@mit.edu>
+
+	* New directory.
+	* Makefile.in: New file.
+	* threads.c: New file.  Thread-specific data support.
+	* fake-addrinfo.c: New file.  Placeholder.
+	* foreachaddr.c: New file, based on include/foreachaddr.c.
+	* libkrb5support.exports: New file.
+
+	* threads.c (k5_key_register, destructors, k5_setspecific)
+	[!ENABLE_THREADS]: Update to fit declarations.
+
+	* Makefile.in (SHLIB_EXPLIBS): Include $(LIBS).
+	(SHLIB_RDIRS): Use $(KRB5_LIBDIR), for lack of anything better.
diff --git a/mechglue/src/util/support/Makefile.in b/mechglue/src/util/support/Makefile.in
new file mode 100644
index 000000000..5a8fcff16
--- /dev/null
+++ b/mechglue/src/util/support/Makefile.in
@@ -0,0 +1,86 @@
+thisconfigdir=../..
+myfulldir=util/support
+mydir=util/support
+BUILDTOP=$(REL)..$(S)..
+RELDIR=../util/support
+
+##DOS##BUILDTOP = ..\..
+##DOS##LIBNAME=$(OUTPRE)k5sprt32.lib
+##DOS##XTRA=
+##DOS##OBJFILE=$(OUTPRE)k5sprt32.lst
+
+SED = sed
+
+KRB5_RUN_ENV= @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+LIBBASE=krb5support
+LIBMAJOR=0
+LIBMINOR=0
+
+LIBINITFUNC=krb5int_thread_support_init
+LIBFINIFUNC=krb5int_thread_support_fini
+
+STLIBOBJS= \
+	threads.o \
+	init-addrinfo.o \
+	fake-addrinfo.o
+
+LIBOBJS= \
+	$(OUTPRE)threads.$(OBJEXT) \
+	$(OUTPRE)init-addrinfo.$(OBJEXT) \
+	$(OUTPRE)fake-addrinfo.$(OBJEXT)
+
+STOBJLISTS=OBJS.ST
+
+INSTALLFILE = cp
+
+LOCALINCLUDES=-I. -I$(srcdir)
+
+SRCS=\
+	$(srcdir)/threads.c \
+	$(srcdir)/init-addrinfo.c \
+	$(srcdir)/fake-addrinfo.c
+SHLIB_EXPDEPS =
+# Add -lm if dumping thread stats, for sqrt.
+SHLIB_EXPLIBS= $(LIBS)
+SHLIB_DIRS=
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+
+DEPLIBS=
+
+#
+all-unix:: all-liblinks
+
+install-unix:: install-libs
+
+clean-unix:: clean-liblinks clean-libs clean-libobjs
+
+##DOS##!if 0
+$(BUILDTOP)/include/krb5/autoconf.h: $(SRCTOP)/include/krb5/autoconf.h.in
+	(cd $(BUILDTOP)/include; $(MAKE) krb5/autoconf.h)
+##DOS##!endif
+
+# @lib_frag@
+# @libobj_frag@
+
+# +++ Dependency line eater +++
+# 
+# Makefile dependencies follow.  This must be the last section in
+# the Makefile.in file
+#
+threads.so threads.po $(OUTPRE)threads.$(OBJEXT): threads.c \
+  $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/k5-platform.h cache-addrinfo.h $(SRCTOP)/include/port-sockets.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/fake-addrinfo.h
+init-addrinfo.so init-addrinfo.po $(OUTPRE)init-addrinfo.$(OBJEXT): \
+  init-addrinfo.c $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/fake-addrinfo.h \
+  cache-addrinfo.h
+fake-addrinfo.so fake-addrinfo.po $(OUTPRE)fake-addrinfo.$(OBJEXT): \
+  fake-addrinfo.c $(SRCTOP)/include/port-sockets.h $(BUILDTOP)/include/krb5/autoconf.h \
+  $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-platform.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/fake-addrinfo.h \
+  cache-addrinfo.h
diff --git a/mechglue/src/util/support/cache-addrinfo.h b/mechglue/src/util/support/cache-addrinfo.h
new file mode 100644
index 000000000..807c652f8
--- /dev/null
+++ b/mechglue/src/util/support/cache-addrinfo.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
+
+/* Approach overview:
+
+   If a system version is available but buggy, save handles to it,
+   redefine the names to refer to static functions defined here, and
+   in those functions, call the system versions and fix up the
+   returned data.  Use the native data structures and flag values.
+
+   If no system version exists, use gethostby* and fake it.  Define
+   the data structures and flag values locally.
+
+
+   On Mac OS X, getaddrinfo results aren't cached (though
+   gethostbyname results are), so we need to build a cache here.  Now
+   things are getting really messy.  Because the cache is in use, we
+   use getservbyname, and throw away thread safety.  (Not that the
+   cache is thread safe, but when we get locking support, that'll be
+   dealt with.)  This code needs tearing down and rebuilding, soon.
+
+
+   Note that recent Windows developers' code has an interesting hack:
+   When you include the right header files, with the right set of
+   macros indicating system versions, you'll get an inline function
+   that looks for getaddrinfo (or whatever) in the system library, and
+   calls it if it's there.  If it's not there, it fakes it with
+   gethostby* calls.
+
+   We're taking a simpler approach: A system provides these routines or
+   it does not.
+
+   Someday, we may want to take into account different versions (say,
+   different revs of GNU libc) where some are broken in one way, and
+   some work or are broken in another way.  Cross that bridge when we
+   come to it.  */
+
+/* To do, maybe:
+
+   + For AIX 4.3.3, using the RFC 2133 definition: Implement
+     AI_NUMERICHOST.  It's not defined in the header file.
+
+     For certain (old?) versions of GNU libc, AI_NUMERICHOST is
+     defined but not implemented.
+
+   + Use gethostbyname2, inet_aton and other IPv6 or thread-safe
+     functions if available.  But, see
+     http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=135182 for one
+     gethostbyname2 problem on Linux.  And besides, if a platform is
+     supporting IPv6 at all, they really should be doing getaddrinfo
+     by now.
+
+   + inet_ntop, inet_pton
+
+   + Conditionally export/import the function definitions, so a
+     library can have a single copy instead of multiple.
+
+   + Upgrade host requirements to include working implementations of
+     these functions, and throw all this away.  Pleeease?  :-)  */
+
+#include "port-sockets.h"
+#include "socket-utils.h"
+#include "k5-platform.h"
+#include "k5-thread.h"
+
+#include "fake-addrinfo.h"
+
+#if defined (__APPLE__) && defined (__MACH__)
+#define FAI_CACHE
+#endif
+
+struct face {
+    struct in_addr *addrs4;
+    struct in6_addr *addrs6;
+    unsigned int naddrs4, naddrs6;
+    time_t expiration;
+    char *canonname, *name;
+    struct face *next;
+};
+
+/* fake addrinfo cache */
+struct fac {
+    k5_mutex_t lock;
+    struct face *data;
+};
+
+extern struct fac krb5int_fac;
+
+extern int krb5int_init_fac (void);
+extern void krb5int_fini_fac (void);
diff --git a/mechglue/src/util/support/fake-addrinfo.c b/mechglue/src/util/support/fake-addrinfo.c
new file mode 100644
index 000000000..6d534703d
--- /dev/null
+++ b/mechglue/src/util/support/fake-addrinfo.c
@@ -0,0 +1,1342 @@
+/*
+ * Copyright (C) 2001,2002,2003,2004,2005 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
+
+/* Approach overview:
+
+   If a system version is available but buggy, save handles to it,
+   redefine the names to refer to static functions defined here, and
+   in those functions, call the system versions and fix up the
+   returned data.  Use the native data structures and flag values.
+
+   If no system version exists, use gethostby* and fake it.  Define
+   the data structures and flag values locally.
+
+
+   On Mac OS X, getaddrinfo results aren't cached (though
+   gethostbyname results are), so we need to build a cache here.  Now
+   things are getting really messy.  Because the cache is in use, we
+   use getservbyname, and throw away thread safety.  (Not that the
+   cache is thread safe, but when we get locking support, that'll be
+   dealt with.)  This code needs tearing down and rebuilding, soon.
+
+
+   Note that recent Windows developers' code has an interesting hack:
+   When you include the right header files, with the right set of
+   macros indicating system versions, you'll get an inline function
+   that looks for getaddrinfo (or whatever) in the system library, and
+   calls it if it's there.  If it's not there, it fakes it with
+   gethostby* calls.
+
+   We're taking a simpler approach: A system provides these routines or
+   it does not.
+
+   Someday, we may want to take into account different versions (say,
+   different revs of GNU libc) where some are broken in one way, and
+   some work or are broken in another way.  Cross that bridge when we
+   come to it.  */
+
+/* To do, maybe:
+
+   + For AIX 4.3.3, using the RFC 2133 definition: Implement
+     AI_NUMERICHOST.  It's not defined in the header file.
+
+     For certain (old?) versions of GNU libc, AI_NUMERICHOST is
+     defined but not implemented.
+
+   + Use gethostbyname2, inet_aton and other IPv6 or thread-safe
+     functions if available.  But, see
+     http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=135182 for one
+     gethostbyname2 problem on Linux.  And besides, if a platform is
+     supporting IPv6 at all, they really should be doing getaddrinfo
+     by now.
+
+   + inet_ntop, inet_pton
+
+   + Conditionally export/import the function definitions, so a
+     library can have a single copy instead of multiple.
+
+   + Upgrade host requirements to include working implementations of
+     these functions, and throw all this away.  Pleeease?  :-)  */
+
+#include "port-sockets.h"
+#include "socket-utils.h"
+#include "k5-platform.h"
+#include "k5-thread.h"
+
+#include <stdio.h>		/* for sprintf */
+#include <errno.h>
+
+#define IMPLEMENT_FAKE_GETADDRINFO
+#include "fake-addrinfo.h"
+
+#ifdef S_SPLINT_S
+/*@-incondefs@*/
+extern int
+getaddrinfo (/*@in@*/ /*@null@*/ const char *,
+	     /*@in@*/ /*@null@*/ const char *,
+	     /*@in@*/ /*@null@*/ const struct addrinfo *,
+	     /*@out@*/ struct addrinfo **)
+    ;
+extern void
+freeaddrinfo (/*@only@*/ /*@out@*/ struct addrinfo *)
+    ;
+extern int
+getnameinfo (const struct sockaddr *addr, socklen_t addrsz,
+	     /*@out@*/ /*@null@*/ char *h, socklen_t hsz,
+	     /*@out@*/ /*@null@*/ char *s, socklen_t ssz,
+	     int flags)
+    /*@requires (maxSet(h)+1) >= hsz /\ (maxSet(s)+1) >= ssz @*/
+    /* too hard: maxRead(addr) >= (addrsz-1) */
+    /*@modifies *h, *s@*/;
+extern /*@dependent@*/ char *gai_strerror (int code) /*@*/;
+/*@=incondefs@*/
+#endif
+
+
+#include "cache-addrinfo.h"
+
+#if (defined (__linux__) && defined(HAVE_GETADDRINFO)) || defined (_AIX)
+/* See comments below.  */
+#  define WRAP_GETADDRINFO
+#endif
+
+#if defined (__linux__) && defined(HAVE_GETADDRINFO)
+# define COPY_FIRST_CANONNAME
+#endif
+
+#ifdef _AIX
+# define NUMERIC_SERVICE_BROKEN
+# define COPY_FIRST_CANONNAME
+#endif
+
+
+#ifdef COPY_FIRST_CANONNAME
+# include <string.h>
+#endif
+
+#ifdef NUMERIC_SERVICE_BROKEN
+# include <ctype.h>		/* isdigit */
+# include <stdlib.h>		/* strtoul */
+#endif
+
+
+/* Do we actually have *any* systems we care about that don't provide
+   either getaddrinfo or one of these two flavors of
+   gethostbyname_r?  */
+#if !defined(HAVE_GETHOSTBYNAME_R) || defined(THREADSAFE_GETHOSTBYNAME)
+#define GET_HOST_BY_NAME(NAME, HP, ERR) \
+    { (HP) = gethostbyname (NAME); (ERR) = h_errno; }
+#define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \
+    { (HP) = gethostbyaddr ((ADDR), (ADDRLEN), (FAMILY)); (ERR) = h_errno; }
+#else
+#ifdef _AIX /* XXX should have a feature test! */
+#define GET_HOST_BY_NAME(NAME, HP, ERR) \
+    {									\
+	struct hostent my_h_ent;					\
+	struct hostent_data my_h_ent_data;				\
+	(HP) = (gethostbyname_r((NAME), &my_h_ent, &my_h_ent_data)	\
+		? 0							\
+		: &my_h_ent);						\
+	(ERR) = h_errno;						\
+    }
+/*
+#define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \
+    {									\
+	struct hostent my_h_ent;					\
+	struct hostent_data my_h_ent_data;				\
+	(HP) = (gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &my_h_ent,	\
+				&my_h_ent_data)				\
+		? 0							\
+		: &my_h_ent);						\
+	(ERR) = my_h_err;						\
+    }
+*/
+#else
+#ifdef GETHOSTBYNAME_R_RETURNS_INT
+#define GET_HOST_BY_NAME(NAME, HP, ERR) \
+    {									\
+	struct hostent my_h_ent, *my_hp;				\
+	int my_h_err;							\
+	char my_h_buf[8192];						\
+	(HP) = (gethostbyname_r((NAME), &my_h_ent,			\
+				my_h_buf, sizeof (my_h_buf), &my_hp,	\
+				&my_h_err)				\
+		? 0							\
+		: &my_h_ent);						\
+	(ERR) = my_h_err;						\
+    }
+#define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \
+    {									\
+	struct hostent my_h_ent, *my_hp;				\
+	int my_h_err;							\
+	char my_h_buf[8192];						\
+	(HP) = (gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &my_h_ent,	\
+				my_h_buf, sizeof (my_h_buf), &my_hp,	\
+				&my_h_err)				\
+		? 0							\
+		: &my_h_ent);						\
+	(ERR) = my_h_err;						\
+    }
+#else
+#define GET_HOST_BY_NAME(NAME, HP, ERR) \
+    {									\
+	struct hostent my_h_ent;					\
+	int my_h_err;							\
+	char my_h_buf[8192];						\
+	(HP) = gethostbyname_r((NAME), &my_h_ent,			\
+			       my_h_buf, sizeof (my_h_buf), &my_h_err);	\
+	(ERR) = my_h_err;						\
+    }
+#define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \
+    {									\
+	struct hostent my_h_ent;					\
+	int my_h_err;							\
+	char my_h_buf[8192];						\
+	(HP) = gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &my_h_ent,	\
+			       my_h_buf, sizeof (my_h_buf), &my_h_err);	\
+	(ERR) = my_h_err;						\
+    }
+#endif /* returns int? */
+#endif /* _AIX */
+#endif
+
+/* Now do the same for getservby* functions.  */
+#ifndef HAVE_GETSERVBYNAME_R
+#define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR) \
+    ((SP) = getservbyname (NAME, PROTO), (ERR) = (SP) ? 0 : -1)
+#define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR) \
+    ((SP) = getservbyport (PORT, PROTO), (ERR) = (SP) ? 0 : -1)
+#else
+#ifdef GETSERVBYNAME_R_RETURNS_INT
+#define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR) \
+    {									\
+	struct servent my_s_ent, *my_sp;				\
+	int my_s_err;							\
+	char my_s_buf[8192];						\
+	(SP) = (getservbyname_r((NAME), (PROTO), &my_s_ent,		\
+				my_s_buf, sizeof (my_s_buf), &my_sp,	\
+				&my_s_err)				\
+		? 0							\
+		: &my_s_ent);						\
+	(ERR) = my_s_err;						\
+    }
+#define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR) \
+    {									\
+	struct servent my_s_ent, *my_sp;				\
+	int my_s_err;							\
+	char my_s_buf[8192];						\
+	(SP) = (getservbyport_r((PORT), (PROTO), &my_s_ent,		\
+				my_s_buf, sizeof (my_s_buf), &my_sp,	\
+				&my_s_err)				\
+		? 0							\
+		: &my_s_ent);						\
+	(ERR) = my_s_err;						\
+    }
+#else
+/* returns ptr -- IRIX? */
+#define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR) \
+    {									\
+	struct servent my_s_ent;					\
+	char my_s_buf[8192];						\
+	(SP) = getservbyname_r((NAME), (PROTO), &my_s_ent,		\
+			       my_s_buf, sizeof (my_s_buf));		\
+	(ERR) = (SP) == NULL;						\
+    }
+
+#define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR) \
+    {									\
+	struct servent my_s_ent, *my_sp;				\
+	char my_s_buf[8192];						\
+	my_sp = getservbyport_r((PORT), (PROTO), &my_s_ent,		\
+				my_s_buf, sizeof (my_s_buf));		\
+	(SP) = my_sp;							\
+	(ERR) = my_sp == 0;						\
+	(ERR) = (ERR);	/* avoid "unused" warning */			\
+    }
+#endif
+#endif
+
+#if defined(WRAP_GETADDRINFO) || defined(FAI_CACHE)
+static inline int
+system_getaddrinfo (const char *name, const char *serv,
+		    const struct addrinfo *hint,
+		    struct addrinfo **res)
+{
+    return getaddrinfo(name, serv, hint, res);
+}
+
+static inline void
+system_freeaddrinfo (struct addrinfo *ai)
+{
+    freeaddrinfo(ai);
+}
+
+/* Note: Implementations written to RFC 2133 use size_t, while RFC
+   2553 implementations use socklen_t, for the second parameter.
+
+   Mac OS X (10.2) and AIX 4.3.3 appear to be in the RFC 2133 camp,
+   but we don't have an autoconf test for that right now.  */
+static inline int
+system_getnameinfo (const struct sockaddr *sa, socklen_t salen,
+		    char *host, size_t hostlen, char *serv, size_t servlen,
+		    int flags)
+{
+    return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+}
+#endif
+
+#if !defined (HAVE_GETADDRINFO) || defined(WRAP_GETADDRINFO) || defined(FAI_CACHE)
+
+#undef  getaddrinfo
+#define getaddrinfo	my_fake_getaddrinfo
+#undef  freeaddrinfo
+#define freeaddrinfo	my_fake_freeaddrinfo
+
+#endif
+
+#if !defined (HAVE_GETADDRINFO)
+
+#undef  gai_strerror
+#define gai_strerror	my_fake_gai_strerror
+
+#endif /* ! HAVE_GETADDRINFO */
+
+#if (!defined (HAVE_GETADDRINFO) || defined (WRAP_GETADDRINFO)) && defined(DEBUG_ADDRINFO)
+/* Some debug routines.  */
+
+static const char *protoname (int p, char *buf) {
+#define X(N) if (p == IPPROTO_ ## N) return #N
+
+    X(TCP);
+    X(UDP);
+    X(ICMP);
+    X(IPV6);
+#ifdef IPPROTO_GRE
+    X(GRE);
+#endif
+    X(NONE);
+    X(RAW);
+#ifdef IPPROTO_COMP
+    X(COMP);
+#endif
+#ifdef IPPROTO_IGMP
+    X(IGMP);
+#endif
+
+    sprintf(buf, " %-2d", p);
+    return buf;
+}	
+
+static const char *socktypename (int t, char *buf) {
+    switch (t) {
+    case SOCK_DGRAM: return "DGRAM";
+    case SOCK_STREAM: return "STREAM";
+    case SOCK_RAW: return "RAW";
+    case SOCK_RDM: return "RDM";
+    case SOCK_SEQPACKET: return "SEQPACKET";
+    }
+    sprintf(buf, " %-2d", t);
+    return buf;
+}
+
+static const char *familyname (int f, char *buf) {
+    switch (f) {
+    default:
+	sprintf(buf, "AF %d", f);
+	return buf;
+    case AF_INET: return "AF_INET";
+    case AF_INET6: return "AF_INET6";
+#ifdef AF_UNIX
+    case AF_UNIX: return "AF_UNIX";
+#endif
+    }
+}
+
+static void debug_dump_getaddrinfo_args (const char *name, const char *serv,
+					 const struct addrinfo *hint)
+{
+    const char *sep;
+    fprintf(stderr,
+	    "getaddrinfo(hostname %s, service %s,\n"
+	    "            hints { ",
+	    name ? name : "(null)", serv ? serv : "(null)");
+    if (hint) {
+	char buf[30];
+	sep = "";
+#define Z(FLAG) if (hint->ai_flags & AI_##FLAG) fprintf(stderr, "%s%s", sep, #FLAG), sep = "|"
+	Z(CANONNAME);
+	Z(PASSIVE);
+#ifdef AI_NUMERICHOST
+	Z(NUMERICHOST);
+#endif
+	if (sep[0] == 0)
+	    fprintf(stderr, "no-flags");
+	if (hint->ai_family)
+	    fprintf(stderr, " %s", familyname(hint->ai_family, buf));
+	if (hint->ai_socktype)
+	    fprintf(stderr, " SOCK_%s", socktypename(hint->ai_socktype, buf));
+	if (hint->ai_protocol)
+	    fprintf(stderr, " IPPROTO_%s", protoname(hint->ai_protocol, buf));
+    } else
+	fprintf(stderr, "(null)");
+    fprintf(stderr, " }):\n");
+}
+
+static void debug_dump_error (int err)
+{
+    fprintf(stderr, "error %d: %s\n", err, gai_strerror(err));
+}
+
+static void debug_dump_addrinfos (const struct addrinfo *ai)
+{
+    int count = 0;
+    char buf[10];
+    fprintf(stderr, "addrinfos returned:\n");
+    while (ai) {
+	fprintf(stderr, "%p...", ai);
+	fprintf(stderr, " socktype=%s", socktypename(ai->ai_socktype, buf));
+	fprintf(stderr, " ai_family=%s", familyname(ai->ai_family, buf));
+	if (ai->ai_family != ai->ai_addr->sa_family)
+	    fprintf(stderr, " sa_family=%s",
+		    familyname(ai->ai_addr->sa_family, buf));
+	fprintf(stderr, "\n");
+	ai = ai->ai_next;
+	count++;
+    }
+    fprintf(stderr, "end addrinfos returned (%d)\n");
+}
+
+#endif
+
+#if !defined (HAVE_GETADDRINFO) || defined (WRAP_GETADDRINFO)
+
+static
+int getaddrinfo (const char *name, const char *serv,
+		 const struct addrinfo *hint, struct addrinfo **result);
+
+static
+void freeaddrinfo (struct addrinfo *ai);
+
+#endif
+
+#if !defined (HAVE_GETADDRINFO)
+
+#define HAVE_FAKE_GETADDRINFO /* was not originally HAVE_GETADDRINFO */
+#define HAVE_GETADDRINFO
+#define NEED_FAKE_GETNAMEINFO
+#undef  HAVE_GETNAMEINFO
+#define HAVE_GETNAMEINFO 1
+
+#undef  getnameinfo
+#define getnameinfo	my_fake_getnameinfo
+
+static
+char *gai_strerror (int code);
+
+#endif
+
+#if !defined (HAVE_GETADDRINFO)
+static
+int getnameinfo (const struct sockaddr *addr, socklen_t len,
+		 char *host, socklen_t hostlen,
+		 char *service, socklen_t servicelen,
+		 int flags);
+#endif
+
+/* Fudge things on older gai implementations.  */
+/* AIX 4.3.3 is based on RFC 2133; no AI_NUMERICHOST.  */
+#ifndef AI_NUMERICHOST
+# define AI_NUMERICHOST 0
+#endif
+/* Partial RFC 2553 implementations may not have AI_ADDRCONFIG and
+   friends, which RFC 3493 says are now part of the getaddrinfo
+   interface, and we'll want to use.  */
+#ifndef AI_ADDRCONFIG
+# define AI_ADDRCONFIG 0
+#endif
+#ifndef AI_V4MAPPED
+# define AI_V4MAPPED 0
+#endif
+#ifndef AI_ALL
+# define AI_ALL 0
+#endif
+#ifndef AI_DEFAULT
+# define AI_DEFAULT (AI_ADDRCONFIG|AI_V4MAPPED)
+#endif
+
+#if defined(HAVE_FAKE_GETADDRINFO) || defined(FAI_CACHE)
+#define NEED_FAKE_GETADDRINFO
+#endif
+
+#if defined(NEED_FAKE_GETADDRINFO) || defined(WRAP_GETADDRINFO)
+#include <stdlib.h>
+#endif
+
+#ifdef NEED_FAKE_GETADDRINFO
+#include <string.h> /* for strspn */
+
+static inline int translate_h_errno (int h);
+
+static inline int fai_add_entry (struct addrinfo **result, void *addr,
+				 int port, const struct addrinfo *template)
+{
+    struct addrinfo *n = malloc (sizeof (struct addrinfo));
+    if (n == 0)
+	return EAI_MEMORY;
+    if (template->ai_family != AF_INET
+#ifdef KRB5_USE_INET6
+	&& template->ai_family != AF_INET6
+#endif
+	)
+	return EAI_FAMILY;
+    *n = *template;
+    if (template->ai_family == AF_INET) {
+	struct sockaddr_in *sin4;
+	sin4 = malloc (sizeof (struct sockaddr_in));
+	if (sin4 == 0)
+	    return EAI_MEMORY;
+	n->ai_addr = (struct sockaddr *) sin4;
+	sin4->sin_family = AF_INET;
+	sin4->sin_addr = *(struct in_addr *)addr;
+	sin4->sin_port = port;
+#ifdef HAVE_SA_LEN
+	sin4->sin_len = sizeof (struct sockaddr_in);
+#endif
+    }
+#ifdef KRB5_USE_INET6
+    if (template->ai_family == AF_INET6) {
+	struct sockaddr_in6 *sin6;
+	sin6 = malloc (sizeof (struct sockaddr_in6));
+	if (sin6 == 0)
+	    return EAI_MEMORY;
+	n->ai_addr = (struct sockaddr *) sin6;
+	sin6->sin6_family = AF_INET6;
+	sin6->sin6_addr = *(struct in6_addr *)addr;
+	sin6->sin6_port = port;
+#ifdef HAVE_SA_LEN
+	sin6->sin6_len = sizeof (struct sockaddr_in6);
+#endif
+    }
+#endif
+    n->ai_next = *result;
+    *result = n;
+    return 0;
+}
+
+#ifdef FAI_CACHE
+/* fake addrinfo cache entries */
+#define CACHE_ENTRY_LIFETIME	15 /* seconds */
+
+static void plant_face (const char *name, struct face *entry)
+{
+    entry->name = strdup(name);
+    if (entry->name == NULL)
+	/* @@ Wastes memory.  */
+	return;
+    k5_mutex_assert_locked(&krb5int_fac.lock);
+    entry->next = krb5int_fac.data;
+    entry->expiration = time(0) + CACHE_ENTRY_LIFETIME;
+    krb5int_fac.data = entry;
+#ifdef DEBUG_ADDRINFO
+    printf("added cache entry '%s' at %p: %d ipv4, %d ipv6; expire %d\n",
+	   name, entry, entry->naddrs4, entry->naddrs6, entry->expiration);
+#endif
+}
+
+static int find_face (const char *name, struct face **entry)
+{
+    struct face *fp, **fpp;
+    time_t now = time(0);
+
+    /* First, scan for expired entries and free them.
+       (Future improvement: Integrate these two loops.)  */
+#ifdef DEBUG_ADDRINFO
+    printf("scanning cache at %d for '%s'...\n", now, name);
+#endif
+    k5_mutex_assert_locked(&krb5int_fac.lock);
+    for (fpp = &krb5int_fac.data; *fpp; ) {
+	fp = *fpp;
+#ifdef DEBUG_ADDRINFO
+	printf("  checking expiration time of @%p: %d\n",
+	       fp, fp->expiration);
+#endif
+	if (fp->expiration < now) {
+#ifdef DEBUG_ADDRINFO
+	    printf("\texpiring cache entry\n");
+#endif
+	    free(fp->name);
+	    free(fp->canonname);
+	    free(fp->addrs4);
+	    free(fp->addrs6);
+	    *fpp = fp->next;
+	    free(fp);
+	    /* Stay at this point in the list, and check again.  */
+	} else
+	    /* Move forward.  */
+	    fpp = &(*fpp)->next;
+    }
+
+    for (fp = krb5int_fac.data; fp; fp = fp->next) {
+#ifdef DEBUG_ADDRINFO
+	printf("  comparing entry @%p\n", fp);
+#endif
+	if (!strcasecmp(fp->name, name)) {
+#ifdef DEBUG_ADDRINFO
+	    printf("\tMATCH!\n");
+#endif
+	    *entry = fp;
+	    return 1;
+	}
+    }
+    return 0;
+}
+
+#endif
+
+static int krb5int_lock_fac(void), krb5int_unlock_fac(void);
+
+static inline int fai_add_hosts_by_name (const char *name,
+					 struct addrinfo *template,
+					 int portnum, int flags,
+					 struct addrinfo **result)
+{
+#ifdef FAI_CACHE
+
+    struct face *ce;
+    int i, r, err;
+
+    err = krb5int_lock_fac();
+    if (err) {
+	errno = err;
+	return EAI_SYSTEM;
+    }
+    if (!find_face(name, &ce)) {
+	struct addrinfo myhints = { 0 }, *ai, *ai2;
+	int i4, i6, aierr;
+
+#ifdef DEBUG_ADDRINFO
+	printf("looking up new data for '%s'...\n", name);
+#endif
+	myhints.ai_socktype = SOCK_STREAM;
+	myhints.ai_flags = AI_CANONNAME;
+	/* Don't set ai_family -- we want to cache all address types,
+	   because the next lookup may not use the same constraints as
+	   the current one.  We *could* cache them separately, so that
+	   we never have to look up an IPv6 address if we are always
+	   asked for IPv4 only, but let's deal with that later, if we
+	   have to.  */
+	/* Try NULL for the service for now.
+
+	   It would be nice to use the requested service name, and not
+	   have to patch things up, but then we'd be doing multiple
+	   queries for the same host when we get different services.
+	   We were using "telnet" for a little more confidence that
+	   getaddrinfo would heed the hints to only give us stream
+	   socket types (with no socket type and null service name, we
+	   might get stream *and* dgram *and* raw, for each address,
+	   or only raw).  The RFC 3493 description of ai_socktype
+	   sometimes associates it with the specified service,
+	   sometimes not.
+
+	   But on Mac OS X (10.3, 10.4) they've "extended" getaddrinfo
+	   to make SRV RR queries.  (Please, somebody, show me
+	   something in the specs that actually supports this?  RFC
+	   3493 says nothing about it, but it does say getaddrinfo is
+	   the new way to look up hostnames.  RFC 2782 says SRV
+	   records should *not* be used unless the application
+	   protocol spec says to do so.  The Telnet spec does not say
+	   to do it.)  And then they complain when our code
+	   "unexpectedly" seems to use this "extension" in cases where
+	   they don't want it to be used.
+
+	   Fortunately, it appears that if we specify ai_socktype as
+	   SOCK_STREAM and use a null service name, we only get one
+	   copy of each address on all the platforms I've tried,
+	   although it may not have ai_socktype filled in properly.
+	   So, we'll fudge it with that for now.  */
+	aierr = system_getaddrinfo(name, NULL, &myhints, &ai);
+	if (aierr) {
+	    krb5int_unlock_fac();
+	    return aierr;
+	}
+	ce = malloc(sizeof(struct face));
+	memset(ce, 0, sizeof(*ce));
+	ce->expiration = time(0) + 30;
+	for (ai2 = ai; ai2; ai2 = ai2->ai_next) {
+#ifdef DEBUG_ADDRINFO
+	    printf("  found an address in family %d...\n", ai2->ai_family);
+#endif
+	    switch (ai2->ai_family) {
+	    case AF_INET:
+		ce->naddrs4++;
+		break;
+	    case AF_INET6:
+		ce->naddrs6++;
+		break;
+	    default:
+		break;
+	    }
+	}
+	ce->addrs4 = calloc(ce->naddrs4, sizeof(*ce->addrs4));
+	if (ce->addrs4 == NULL && ce->naddrs4 != 0) {
+	    krb5int_unlock_fac();
+	    system_freeaddrinfo(ai);
+	    return EAI_MEMORY;
+	}
+	ce->addrs6 = calloc(ce->naddrs6, sizeof(*ce->addrs6));
+	if (ce->addrs6 == NULL && ce->naddrs6 != 0) {
+	    krb5int_unlock_fac();
+	    free(ce->addrs4);
+	    system_freeaddrinfo(ai);
+	    return EAI_MEMORY;
+	}
+	for (ai2 = ai, i4 = i6 = 0; ai2; ai2 = ai2->ai_next) {
+	    switch (ai2->ai_family) {
+	    case AF_INET:
+		ce->addrs4[i4++] = ((struct sockaddr_in *)ai2->ai_addr)->sin_addr;
+		break;
+	    case AF_INET6:
+		ce->addrs6[i6++] = ((struct sockaddr_in6 *)ai2->ai_addr)->sin6_addr;
+		break;
+	    default:
+		break;
+	    }
+	}
+	ce->canonname = ai->ai_canonname ? strdup(ai->ai_canonname) : 0;
+	system_freeaddrinfo(ai);
+	plant_face(name, ce);
+    }
+    template->ai_family = AF_INET6;
+    template->ai_addrlen = sizeof(struct sockaddr_in6);
+    for (i = 0; i < ce->naddrs6; i++) {
+	r = fai_add_entry (result, &ce->addrs6[i], portnum, template);
+	if (r) {
+	    krb5int_unlock_fac();
+	    return r;
+	}
+    }
+    template->ai_family = AF_INET;
+    template->ai_addrlen = sizeof(struct sockaddr_in);
+    for (i = 0; i < ce->naddrs4; i++) {
+	r = fai_add_entry (result, &ce->addrs4[i], portnum, template);
+	if (r) {
+	    krb5int_unlock_fac();
+	    return r;
+	}
+    }
+    if (*result && (flags & AI_CANONNAME))
+	(*result)->ai_canonname = (ce->canonname
+				   ? strdup(ce->canonname)
+				   : NULL);
+    krb5int_unlock_fac();
+    return 0;
+
+#else
+
+    struct hostent *hp;
+    int i, r;
+    int herr;
+
+    GET_HOST_BY_NAME (name, hp, herr);
+    if (hp == 0)
+	return translate_h_errno (herr);
+    for (i = 0; hp->h_addr_list[i]; i++) {
+	r = fai_add_entry (result, hp->h_addr_list[i], portnum, template);
+	if (r)
+	    return r;
+    }
+    if (*result && (flags & AI_CANONNAME))
+	(*result)->ai_canonname = strdup (hp->h_name);
+    return 0;
+
+#endif
+}
+
+static inline void
+fake_freeaddrinfo (struct addrinfo *ai)
+{
+    struct addrinfo *next;
+    while (ai) {
+	next = ai->ai_next;
+	if (ai->ai_canonname)
+	  free (ai->ai_canonname);
+	if (ai->ai_addr)
+	  free (ai->ai_addr);
+	free (ai);
+	ai = next;
+    }
+}
+
+static inline int
+fake_getaddrinfo (const char *name, const char *serv,
+		  const struct addrinfo *hint, struct addrinfo **result)
+{
+    struct addrinfo *res = 0;
+    int ret;
+    int port = 0, socktype;
+    int flags;
+    struct addrinfo template;
+
+#ifdef DEBUG_ADDRINFO
+    debug_dump_getaddrinfo_args(name, serv, hint);
+#endif
+
+    if (hint != 0) {
+	if (hint->ai_family != 0 && hint->ai_family != AF_INET)
+	    return EAI_NODATA;
+	socktype = hint->ai_socktype;
+	flags = hint->ai_flags;
+    } else {
+	socktype = 0;
+	flags = 0;
+    }
+
+    if (serv) {
+	size_t numlen = strspn (serv, "0123456789");
+	if (serv[numlen] == '\0') {
+	    /* pure numeric */
+	    unsigned long p = strtoul (serv, 0, 10);
+	    if (p == 0 || p > 65535)
+		return EAI_NONAME;
+	    port = htons (p);
+	} else {
+	    struct servent *sp;
+	    int try_dgram_too = 0, s_err;
+
+	    if (socktype == 0) {
+		try_dgram_too = 1;
+		socktype = SOCK_STREAM;
+	    }
+	try_service_lookup:
+	    GET_SERV_BY_NAME(serv, socktype == SOCK_STREAM ? "tcp" : "udp",
+			     sp, s_err);
+	    if (sp == 0) {
+		if (try_dgram_too) {
+		    socktype = SOCK_DGRAM;
+		    goto try_service_lookup;
+		}
+		return EAI_SERVICE;
+	    }
+	    port = sp->s_port;
+	}
+    }
+
+    if (name == 0) {
+	name = (flags & AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1";
+	flags |= AI_NUMERICHOST;
+    }
+
+    template.ai_family = AF_INET;
+    template.ai_addrlen = sizeof (struct sockaddr_in);
+    template.ai_socktype = socktype;
+    template.ai_protocol = 0;
+    template.ai_flags = 0;
+    template.ai_canonname = 0;
+    template.ai_next = 0;
+    template.ai_addr = 0;
+
+    /* If NUMERICHOST is set, parse a numeric address.
+       If it's not set, don't accept such names.  */
+    if (flags & AI_NUMERICHOST) {
+	struct in_addr addr4;
+#if 0
+	ret = inet_aton (name, &addr4);
+	if (ret)
+	    return EAI_NONAME;
+#else
+	addr4.s_addr = inet_addr (name);
+	if (addr4.s_addr == 0xffffffff || addr4.s_addr == -1)
+	    /* 255.255.255.255 or parse error, both bad */
+	    return EAI_NONAME;
+#endif
+	ret = fai_add_entry (&res, &addr4, port, &template);
+    } else {
+	ret = fai_add_hosts_by_name (name, &template, port, flags,
+				     &res);
+    }
+
+    if (ret && ret != NO_ADDRESS) {
+	fake_freeaddrinfo (res);
+	return ret;
+    }
+    if (res == 0)
+	return NO_ADDRESS;
+    *result = res;
+    return 0;
+}
+
+#ifdef NEED_FAKE_GETNAMEINFO
+static inline int
+fake_getnameinfo (const struct sockaddr *sa, socklen_t len,
+		  char *host, socklen_t hostlen,
+		  char *service, socklen_t servicelen,
+		  int flags)
+{
+    struct hostent *hp;
+    const struct sockaddr_in *sinp;
+    struct servent *sp;
+    size_t hlen, slen;
+
+    if (sa->sa_family != AF_INET) {
+	return EAI_FAMILY;
+    }
+    sinp = (const struct sockaddr_in *) sa;
+
+    hlen = hostlen;
+    if (hostlen < 0 || hlen != hostlen) {
+	errno = EINVAL;
+	return EAI_SYSTEM;
+    }
+    slen = servicelen;
+    if (servicelen < 0 || slen != servicelen) {
+	errno = EINVAL;
+	return EAI_SYSTEM;
+    }
+
+    if (host) {
+	if (flags & NI_NUMERICHOST) {
+#if (defined(__GNUC__) && defined(__mips__)) || 1 /* thread safety always */
+	    /* The inet_ntoa call, passing a struct, fails on IRIX 6.5
+	       using gcc 2.95; we get back "0.0.0.0".  Since this in a
+	       configuration still important at Athena, here's the
+	       workaround, which also happens to be thread-safe....  */
+	    const unsigned char *uc;
+	    char tmpbuf[20];
+	numeric_host:
+	    uc = (const unsigned char *) &sinp->sin_addr;
+	    sprintf(tmpbuf, "%d.%d.%d.%d", uc[0], uc[1], uc[2], uc[3]);
+	    strncpy(host, tmpbuf, hlen);
+#else
+	    char *p;
+	numeric_host:
+	    p = inet_ntoa (sinp->sin_addr);
+	    strncpy (host, p, hlen);
+#endif
+	} else {
+	    int herr;
+	    GET_HOST_BY_ADDR((const char *) &sinp->sin_addr,
+			     sizeof (struct in_addr),
+			     sa->sa_family, hp, herr);
+	    if (hp == 0) {
+		if (herr == NO_ADDRESS && !(flags & NI_NAMEREQD)) /* ??? */
+		    goto numeric_host;
+		return translate_h_errno (herr);
+	    }
+	    /* According to the Open Group spec, getnameinfo can
+	       silently truncate, but must still return a
+	       null-terminated string.  */
+	    strncpy (host, hp->h_name, hlen);
+	}
+	host[hostlen-1] = 0;
+    }
+
+    if (service) {
+	if (flags & NI_NUMERICSERV) {
+	    char numbuf[10];
+	    int port;
+	numeric_service:
+	    port = ntohs (sinp->sin_port);
+	    if (port < 0 || port > 65535)
+		return EAI_FAIL;
+	    sprintf (numbuf, "%d", port);
+	    strncpy (service, numbuf, slen);
+	} else {
+	    int serr;
+	    GET_SERV_BY_PORT(sinp->sin_port,
+			     (flags & NI_DGRAM) ? "udp" : "tcp",
+			     sp, serr);
+	    if (sp == 0)
+		goto numeric_service;
+	    strncpy (service, sp->s_name, slen);
+	}
+	service[servicelen-1] = 0;
+    }
+
+    return 0;
+}
+#endif
+
+#if defined(HAVE_FAKE_GETADDRINFO) || defined(NEED_FAKE_GETNAMEINFO)
+
+static inline
+char *gai_strerror (int code)
+{
+    switch (code) {
+    case EAI_ADDRFAMILY: return "address family for nodename not supported";
+    case EAI_AGAIN:	return "temporary failure in name resolution";
+    case EAI_BADFLAGS:	return "bad flags to getaddrinfo/getnameinfo";
+    case EAI_FAIL:	return "non-recoverable failure in name resolution";
+    case EAI_FAMILY:	return "ai_family not supported";
+    case EAI_MEMORY:	return "out of memory";
+    case EAI_NODATA:	return "no address associated with hostname";
+    case EAI_NONAME:	return "name does not exist";
+    case EAI_SERVICE:	return "service name not supported for specified socket type";
+    case EAI_SOCKTYPE:	return "ai_socktype not supported";
+    case EAI_SYSTEM:	return strerror (errno);
+    default:		return "bogus getaddrinfo error?";
+    }
+}
+#endif
+
+static inline int translate_h_errno (int h)
+{
+    switch (h) {
+    case 0:
+	return 0;
+#ifdef NETDB_INTERNAL
+    case NETDB_INTERNAL:
+	if (errno == ENOMEM)
+	    return EAI_MEMORY;
+	return EAI_SYSTEM;
+#endif
+    case HOST_NOT_FOUND:
+	return EAI_NONAME;
+    case TRY_AGAIN:
+	return EAI_AGAIN;
+    case NO_RECOVERY:
+	return EAI_FAIL;
+    case NO_DATA:
+#if NO_DATA != NO_ADDRESS
+    case NO_ADDRESS:
+#endif
+	return EAI_NODATA;
+    default:
+	return EAI_SYSTEM;
+    }
+}
+
+#if defined(HAVE_FAKE_GETADDRINFO) || defined(FAI_CACHE)
+static inline
+int getaddrinfo (const char *name, const char *serv,
+		 const struct addrinfo *hint, struct addrinfo **result)
+{
+    return fake_getaddrinfo(name, serv, hint, result);
+}
+
+static inline
+void freeaddrinfo (struct addrinfo *ai)
+{
+    fake_freeaddrinfo(ai);
+}
+
+#ifdef NEED_FAKE_GETNAMEINFO
+static inline
+int getnameinfo (const struct sockaddr *sa, socklen_t len,
+		 char *host, socklen_t hostlen,
+		 char *service, socklen_t servicelen,
+		 int flags)
+{
+    return fake_getnameinfo(sa, len, host, hostlen, service, servicelen,
+			    flags);
+}
+#endif /* NEED_FAKE_GETNAMEINFO */
+#endif /* HAVE_FAKE_GETADDRINFO */
+#endif /* NEED_FAKE_GETADDRINFO */
+
+
+#ifdef WRAP_GETADDRINFO
+
+static inline
+int
+getaddrinfo (const char *name, const char *serv, const struct addrinfo *hint,
+	     struct addrinfo **result)
+{
+    int aierr;
+#if defined(_AIX) || defined(COPY_FIRST_CANONNAME)
+    struct addrinfo *ai;
+#endif
+#ifdef NUMERIC_SERVICE_BROKEN
+    int service_is_numeric = 0;
+    int service_port = 0;
+    int socket_type = 0;
+#endif
+
+#ifdef DEBUG_ADDRINFO
+    debug_dump_getaddrinfo_args(name, serv, hint);
+#endif
+
+#ifdef NUMERIC_SERVICE_BROKEN
+    /* AIX 4.3.3 is broken.  (Or perhaps out of date?)
+
+       If a numeric service is provided, and it doesn't correspond to
+       a known service name for tcp or udp (as appropriate), an error
+       code (for "host not found") is returned.  If the port maps to a
+       known service for both udp and tcp, all is well.  */
+    if (serv && serv[0] && isdigit(serv[0])) {
+	unsigned long lport;
+	char *end;
+	lport = strtoul(serv, &end, 10);
+	if (!*end) {
+	    if (lport > 65535)
+		return EAI_SOCKTYPE;
+	    service_is_numeric = 1;
+	    service_port = htons(lport);
+#ifdef AI_NUMERICSERV
+	    if (hint && hint->ai_flags & AI_NUMERICSERV)
+		serv = "9";
+	    else
+#endif
+		serv = "discard";	/* defined for both udp and tcp */
+	    if (hint)
+		socket_type = hint->ai_socktype;
+	}
+    }
+#endif
+
+    aierr = system_getaddrinfo (name, serv, hint, result);
+    if (aierr || *result == 0) {
+#ifdef DEBUG_ADDRINFO
+	debug_dump_error(aierr);
+#endif
+	return aierr;
+    }
+
+    /* Linux libc version 6 (libc-2.2.4.so on Debian) is broken.
+
+       RFC 2553 says that when AI_CANONNAME is set, the ai_canonname
+       flag of the first returned structure has the canonical name of
+       the host.  Instead, GNU libc sets ai_canonname in each returned
+       structure to the name that the corresponding address maps to,
+       if any, or a printable numeric form.
+
+       RFC 2553 bis and the new Open Group spec say that field will be
+       the canonical name if it can be determined, otherwise, the
+       provided hostname or a copy of it.
+
+       IMNSHO, "canonical name" means CNAME processing and not PTR
+       processing, but I can see arguing it.  Using the numeric form
+       when that's not the form provided is just wrong.  So, let's fix
+       it.
+
+       The glibc 2.2.5 sources indicate that the canonical name is
+       *not* allocated separately, it's just some extra storage tacked
+       on the end of the addrinfo structure.  So, let's try this
+       approach: If getaddrinfo sets ai_canonname, we'll replace the
+       *first* one with allocated storage, and free up that pointer in
+       freeaddrinfo if it's set; the other ai_canonname fields will be
+       left untouched.  And we'll just pray that the application code
+       won't mess around with the list structure; if we start doing
+       that, we'll have to start replacing and freeing all of the
+       ai_canonname fields.
+
+       Ref: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=133668 .
+
+       Since it's dependent on the target hostname, it's hard to check
+       for at configure time.  Always do it on Linux for now.  When
+       they get around to fixing it, add a compile-time or run-time
+       check for the glibc version in use.
+
+       Some Windows documentation says that even when AI_CANONNAME is
+       set, the returned ai_canonname field can be null.  The NetBSD
+       1.5 implementation also does this, if the input hostname is a
+       numeric host address string.  That case isn't handled well at
+       the moment.
+
+       Libc version 5 didn't have getaddrinfo at all.  */
+
+#ifdef COPY_FIRST_CANONNAME
+    /*
+     * This code must *always* return an error, return a null
+     * ai_canonname, or return an ai_canonname allocated here using
+     * malloc, so that freeaddrinfo can always free a non-null
+     * ai_canonname.  Note that it really doesn't matter if the
+     * AI_CANONNAME flag was set.
+     */
+    ai = *result;
+    if (ai->ai_canonname) {
+	struct hostent *hp;
+	const char *name2 = 0;
+	int i, herr;
+
+	/*
+	 * Current versions of GET_HOST_BY_NAME will fail if the
+	 * target hostname has IPv6 addresses only.  Make sure it
+	 * fails fairly cleanly.
+	 */
+	GET_HOST_BY_NAME (name, hp, herr);
+	if (hp == 0) {
+	    /*
+	     * This case probably means it's an IPv6-only name.  If
+	     * ai_canonname is a numeric address, get rid of it.
+	     */
+	    if (ai->ai_canonname && strchr(ai->ai_canonname, ':'))
+		ai->ai_canonname = 0;
+	    name2 = ai->ai_canonname ? ai->ai_canonname : name;
+	} else {
+	    /* Sometimes gethostbyname will be directed to /etc/hosts
+	       first, and sometimes that file will have entries with
+	       the unqualified name first.  So take the first entry
+	       that looks like it could be a FQDN.  */
+	    for (i = 0; hp->h_aliases[i]; i++) {
+		if (strchr(hp->h_aliases[i], '.') != 0) {
+		    name2 = hp->h_aliases[i];
+		    break;
+		}
+	    }
+	    /* Give up, just use the first name (h_name ==
+	       h_aliases[0] on all systems I've seen).  */
+	    if (hp->h_aliases[i] == 0)
+		name2 = hp->h_name;
+	}
+
+	ai->ai_canonname = strdup(name2);
+	if (name2 != 0 && ai->ai_canonname == 0) {
+	    system_freeaddrinfo(ai);
+	    *result = 0;
+#ifdef DEBUG_ADDRINFO
+	    debug_dump_error(EAI_MEMORY);
+#endif
+	    return EAI_MEMORY;
+	}
+	/* Zap the remaining ai_canonname fields glibc fills in, in
+	   case the application messes around with the list
+	   structure.  */
+	while ((ai = ai->ai_next) != NULL)
+	    ai->ai_canonname = 0;
+    }
+#endif
+
+#ifdef NUMERIC_SERVICE_BROKEN
+    if (service_port != 0) {
+	for (ai = *result; ai; ai = ai->ai_next) {
+	    if (socket_type != 0 && ai->ai_socktype == 0)
+		/* Is this check actually needed?  */
+		ai->ai_socktype = socket_type;
+	    switch (ai->ai_family) {
+	    case AF_INET:
+		((struct sockaddr_in *)ai->ai_addr)->sin_port = service_port;
+		break;
+	    case AF_INET6:
+		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = service_port;
+		break;
+	    }
+	}
+    }
+#endif
+
+#ifdef _AIX
+    for (ai = *result; ai; ai = ai->ai_next) {
+	/* AIX 4.3.3 libc is broken.  It doesn't set the family or len
+	   fields of the sockaddr structures.  Usually, sa_family is
+	   zero, but I've seen it set to 1 in some cases also (maybe
+	   just leftover from previous contents of the memory
+	   block?).  So, always override what libc returned.  */
+	ai->ai_addr->sa_family = ai->ai_family;
+#ifdef HAVE_SA_LEN /* always true on AIX, actually */
+	ai->ai_addr->sa_len = ai->ai_addrlen;
+#endif
+    }
+#endif
+
+    /* Not dealt with currently:
+
+       - Some versions of GNU libc can lose some IPv4 addresses in
+	 certain cases when multiple IPv4 and IPv6 addresses are
+	 available.  */
+
+#ifdef DEBUG_ADDRINFO
+    debug_dump_addrinfos(*result);
+#endif
+
+    return 0;
+}
+
+static inline
+void freeaddrinfo (struct addrinfo *ai)
+{
+#ifdef COPY_FIRST_CANONNAME
+    if (ai) {
+      free(ai->ai_canonname);
+	ai->ai_canonname = 0;
+	system_freeaddrinfo(ai);
+    }
+#else
+    system_freeaddrinfo(ai);
+#endif
+}
+#endif /* WRAP_GETADDRINFO */
+
+extern int krb5int_call_thread_support_init(void);
+static int krb5int_lock_fac (void)
+{
+    int err;
+    err = krb5int_call_thread_support_init();
+    if (err)
+	return err;
+    return k5_mutex_lock(&krb5int_fac.lock);
+}
+
+static int krb5int_unlock_fac (void)
+{
+    return k5_mutex_unlock(&krb5int_fac.lock);
+}
+
+#if defined(KRB5_USE_INET6) && defined(NEED_INSIXADDR_ANY) 
+/* If compiling with IPv6 support and C library does not define in6addr_any */
+const struct in6_addr krb5int_in6addr_any = IN6ADDR_ANY_INIT;
+#endif
+
+
+
+int krb5int_getaddrinfo (const char *node, const char *service,
+			 const struct addrinfo *hints,
+			 struct addrinfo **aip)
+{
+    return getaddrinfo(node, service, hints, aip);
+}
+
+void krb5int_freeaddrinfo (struct addrinfo *ai)
+{
+    freeaddrinfo(ai);
+}
+
+const char *krb5int_gai_strerror(int err)
+{
+    return gai_strerror(err);
+}
+
+int krb5int_getnameinfo (const struct sockaddr *sa, socklen_t salen,
+			 char *hbuf, size_t hbuflen,
+			 char *sbuf, size_t sbuflen,
+			 int flags)
+{
+    return getnameinfo(sa, salen, hbuf, hbuflen, sbuf, sbuflen, flags);
+}
diff --git a/mechglue/src/util/support/init-addrinfo.c b/mechglue/src/util/support/init-addrinfo.c
new file mode 100644
index 000000000..4c94dc743
--- /dev/null
+++ b/mechglue/src/util/support/init-addrinfo.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology,
+ * Cambridge, MA, USA.  All Rights Reserved.
+ * 
+ * This software is being provided to you, the LICENSEE, by the 
+ * Massachusetts Institute of Technology (M.I.T.) under the following 
+ * license.  By obtaining, using and/or copying this software, you agree 
+ * that you have read, understood, and will comply with these terms and 
+ * conditions:  
+ * 
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute 
+ * this software and its documentation for any purpose and without fee or 
+ * royalty is hereby granted, provided that you agree to comply with the 
+ * following copyright notice and statements, including the disclaimer, and 
+ * that the same appear on ALL copies of the software and documentation, 
+ * including modifications that you make for internal use or for 
+ * distribution:
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS 
+ * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not 
+ * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF 
+ * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF 
+ * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 
+ * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.   
+ * 
+ * The name of the Massachusetts Institute of Technology or M.I.T. may NOT 
+ * be used in advertising or publicity pertaining to distribution of the 
+ * software.  Title to copyright in this software and any associated 
+ * documentation shall at all times remain with M.I.T., and USER agrees to 
+ * preserve same.
+ *
+ * Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.  
+ */
+
+/* Stuff that needs initialization for fake-addrinfo.c.
+
+   Separated out, so that static linking against this library doesn't
+   require pulling in socket/nsl/whatever libraries for code not using
+   getaddrinfo.  */
+
+#include "port-sockets.h"
+#include "socket-utils.h"
+#include "k5-platform.h"
+#include "k5-thread.h"
+
+#include <stdio.h>		/* for sprintf */
+#include <errno.h>
+
+#define IMPLEMENT_FAKE_GETADDRINFO
+#include "fake-addrinfo.h"
+#include "cache-addrinfo.h"
+
+struct fac krb5int_fac = { K5_MUTEX_PARTIAL_INITIALIZER, 0 };
+
+int krb5int_init_fac (void)
+{
+    return k5_mutex_finish_init(&krb5int_fac.lock);
+}
+
+void krb5int_fini_fac (void)
+{
+    k5_mutex_destroy(&krb5int_fac.lock);
+}
diff --git a/mechglue/src/util/support/libkrb5support.exports b/mechglue/src/util/support/libkrb5support.exports
new file mode 100644
index 000000000..9607ef822
--- /dev/null
+++ b/mechglue/src/util/support/libkrb5support.exports
@@ -0,0 +1,13 @@
+krb5int_key_register
+krb5int_key_delete
+krb5int_getspecific
+krb5int_setspecific
+krb5int_mutex_lock_update_stats
+krb5int_mutex_unlock_update_stats
+krb5int_mutex_report_stats
+krb5int_getaddrinfo
+krb5int_freeaddrinfo
+krb5int_gai_strerror
+krb5int_getnameinfo
+krb5int_in6addr_any
+krb5int_pthread_loaded
diff --git a/mechglue/src/util/support/threads.c b/mechglue/src/util/support/threads.c
new file mode 100644
index 000000000..8a00e4c2b
--- /dev/null
+++ b/mechglue/src/util/support/threads.c
@@ -0,0 +1,608 @@
+/*
+ * util/support/threads.c
+ *
+ * Copyright 2004,2005 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Preliminary thread support.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "k5-thread.h"
+#include "k5-platform.h"
+
+MAKE_INIT_FUNCTION(krb5int_thread_support_init);
+MAKE_FINI_FUNCTION(krb5int_thread_support_fini);
+
+#ifndef ENABLE_THREADS /* no thread support */
+
+static void (*destructors[K5_KEY_MAX])(void *);
+struct tsd_block { void *values[K5_KEY_MAX]; };
+static struct tsd_block tsd_no_threads;
+static unsigned char destructors_set[K5_KEY_MAX];
+
+#elif defined(_WIN32)
+
+static DWORD tls_idx;
+static CRITICAL_SECTION key_lock;
+struct tsd_block {
+  void *values[K5_KEY_MAX];
+};
+static void (*destructors[K5_KEY_MAX])(void *);
+static unsigned char destructors_set[K5_KEY_MAX];
+
+void krb5int_thread_detach_hook (void)
+{
+    /* XXX Memory leak here!
+       Need to destroy all TLS objects we know about for this thread.  */
+    struct tsd_block *t;
+    int i, err;
+
+    err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
+    if (err)
+	return;
+
+    t = TlsGetValue(tls_idx);
+    if (t == NULL)
+	return;
+    for (i = 0; i < K5_KEY_MAX; i++) {
+	if (destructors_set[i] && destructors[i] && t->values[i]) {
+	    void *v = t->values[i];
+	    t->values[i] = 0;
+	    (*destructors[i])(v);
+	}
+    }
+}
+
+/* Stub function not used on Windows. */ 
+int krb5int_pthread_loaded (void)
+{
+    return 0;
+}
+#else /* POSIX threads */
+
+/* Must support register/delete/register sequence, e.g., if krb5 is
+   loaded so this support code stays in the process, and gssapi is
+   loaded, unloaded, and loaded again.  */
+
+static k5_mutex_t key_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+static void (*destructors[K5_KEY_MAX])(void *);
+static unsigned char destructors_set[K5_KEY_MAX];
+
+/* This is not safe yet!
+
+   Thread termination concurrent with key deletion can cause two
+   threads to interfere.  It's a bit tricky, since one of the threads
+   will want to remove this structure from the list being walked by
+   the other.
+
+   Other cases, like looking up data while the library owning the key
+   is in the process of being unloaded, we don't worry about.  */
+
+struct tsd_block {
+    struct tsd_block *next;
+    void *values[K5_KEY_MAX];
+};
+
+#ifdef HAVE_PRAGMA_WEAK_REF
+# pragma weak pthread_getspecific
+# pragma weak pthread_setspecific
+# pragma weak pthread_key_create
+# pragma weak pthread_key_delete
+# pragma weak pthread_create
+# pragma weak pthread_join
+static volatile int flag_pthread_loaded = -1;
+static void loaded_test_aux(void)
+{
+    if (flag_pthread_loaded == -1)
+	flag_pthread_loaded = 1;
+    else
+	/* Could we have been called twice?  */
+	flag_pthread_loaded = 0;
+}
+static pthread_once_t loaded_test_once = PTHREAD_ONCE_INIT;
+int krb5int_pthread_loaded (void)
+{
+    int x = flag_pthread_loaded;
+    if (x != -1)
+	return x;
+    if (&pthread_getspecific == 0
+	|| &pthread_setspecific == 0
+	|| &pthread_key_create == 0
+	|| &pthread_key_delete == 0
+	|| &pthread_once == 0
+	|| &pthread_mutex_lock == 0
+	|| &pthread_mutex_unlock == 0
+	|| &pthread_mutex_destroy == 0
+	|| &pthread_mutex_init == 0
+	|| &pthread_self == 0
+	|| &pthread_equal == 0
+	/* This catches Solaris 9.  May be redundant with the above
+	   tests now.  */
+# ifdef HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP_IN_THREAD_LIB
+	|| &pthread_mutexattr_setrobust_np == 0
+# endif
+	/* Any program that's really multithreaded will have to be
+	   able to create threads.  */
+	|| &pthread_create == 0
+	|| &pthread_join == 0
+	/* Okay, all the interesting functions -- or stubs for them --
+	   seem to be present.  If we call pthread_once, does it
+	   actually seem to cause the indicated function to get called
+	   exactly one time?  */
+	|| pthread_once(&loaded_test_once, loaded_test_aux) != 0
+	|| pthread_once(&loaded_test_once, loaded_test_aux) != 0
+	/* This catches cases where pthread_once does nothing, and
+	   never causes the function to get called.  That's a pretty
+	   clear violation of the POSIX spec, but hey, it happens.  */
+	|| flag_pthread_loaded < 0) {
+	flag_pthread_loaded = 0;
+	return 0;
+    }
+    /* If we wanted to be super-paranoid, we could try testing whether
+       pthread_get/setspecific work, too.  I don't know -- so far --
+       of any system with non-functional stubs for those.  */
+    return flag_pthread_loaded;
+}
+static struct tsd_block tsd_if_single;
+# define GET_NO_PTHREAD_TSD()	(&tsd_if_single)
+#else
+# define GET_NO_PTHREAD_TSD()	(abort(),(struct tsd_block *)0)
+#endif
+
+static pthread_key_t key;
+static void thread_termination(void *);
+
+static void thread_termination (void *tptr)
+{
+    int err = k5_mutex_lock(&key_lock);
+    if (err == 0) {
+        int i, pass, none_found;
+        struct tsd_block *t = tptr;
+        
+        /* Make multiple passes in case, for example, a libkrb5 cleanup
+            function wants to print out an error message, which causes
+            com_err to allocate a thread-specific buffer, after we just
+            freed up the old one.
+            
+            Shouldn't actually happen, if we're careful, but check just in
+            case.  */
+        
+        pass = 0;
+        none_found = 0;
+        while (pass < 4 && !none_found) {
+            none_found = 1;
+            for (i = 0; i < K5_KEY_MAX; i++) {
+                if (destructors_set[i] && destructors[i] && t->values[i]) {
+                    void *v = t->values[i];
+                    t->values[i] = 0;
+                    (*destructors[i])(v);
+                    none_found = 0;
+                }
+            }
+        }
+        free (t);
+        err = k5_mutex_unlock(&key_lock);
+   }
+    
+    /* remove thread from global linked list */
+}
+
+#endif /* no threads vs Win32 vs POSIX */
+
+void *k5_getspecific (k5_key_t keynum)
+{
+    struct tsd_block *t;
+    int err;
+
+    err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
+    if (err)
+	return NULL;
+
+    assert(keynum >= 0 && keynum < K5_KEY_MAX);
+    assert(destructors_set[keynum] == 1);
+
+#ifndef ENABLE_THREADS
+
+    t = &tsd_no_threads;
+
+#elif defined(_WIN32)
+
+    t = TlsGetValue(tls_idx);
+
+#else /* POSIX */
+
+    if (K5_PTHREADS_LOADED)
+	t = pthread_getspecific(key);
+    else
+	t = GET_NO_PTHREAD_TSD();
+
+#endif
+
+    if (t == NULL)
+	return NULL;
+    return t->values[keynum];
+}
+
+int k5_setspecific (k5_key_t keynum, void *value)
+{
+    struct tsd_block *t;
+    int err;
+
+    err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
+    if (err)
+	return err;
+
+    assert(keynum >= 0 && keynum < K5_KEY_MAX);
+    assert(destructors_set[keynum] == 1);
+
+#ifndef ENABLE_THREADS
+
+    t = &tsd_no_threads;
+
+#elif defined(_WIN32)
+
+    t = TlsGetValue(tls_idx);
+    if (t == NULL) {
+	int i;
+	t = malloc(sizeof(*t));
+	if (t == NULL)
+	    return errno;
+	for (i = 0; i < K5_KEY_MAX; i++)
+	    t->values[i] = 0;
+	/* add to global linked list */
+	/*	t->next = 0; */
+	err = TlsSetValue(tls_idx, t);
+	if (err) {
+	    free(t);
+	    return err;
+	}
+    }
+
+#else /* POSIX */
+
+    if (K5_PTHREADS_LOADED) {
+	t = pthread_getspecific(key);
+	if (t == NULL) {
+	    int i;
+	    t = malloc(sizeof(*t));
+	    if (t == NULL)
+		return errno;
+	    for (i = 0; i < K5_KEY_MAX; i++)
+		t->values[i] = 0;
+	    /* add to global linked list */
+	    t->next = 0;
+	    err = pthread_setspecific(key, t);
+	    if (err) {
+		free(t);
+		return err;
+	    }
+	}
+    } else {
+	t = GET_NO_PTHREAD_TSD();
+    }
+
+#endif
+
+    t->values[keynum] = value;
+    return 0;
+}
+
+int k5_key_register (k5_key_t keynum, void (*destructor)(void *))
+{
+    int err;
+
+    err = CALL_INIT_FUNCTION(krb5int_thread_support_init);
+    if (err)
+	return err;
+
+    assert(keynum >= 0 && keynum < K5_KEY_MAX);
+
+#ifndef ENABLE_THREADS
+
+    assert(destructors_set[keynum] == 0);
+    destructors[keynum] = destructor;
+    destructors_set[keynum] = 1;
+    err = 0;
+
+#elif defined(_WIN32)
+
+    /* XXX: This can raise EXCEPTION_POSSIBLE_DEADLOCK.  */
+    EnterCriticalSection(&key_lock);
+    assert(destructors_set[keynum] == 0);
+    destructors_set[keynum] = 1;
+    destructors[keynum] = destructor;
+    LeaveCriticalSection(&key_lock);
+    err = 0;
+
+#else /* POSIX */
+
+    err = k5_mutex_lock(&key_lock);
+    if (err == 0) {
+	assert(destructors_set[keynum] == 0);
+	destructors_set[keynum] = 1;
+	destructors[keynum] = destructor;
+	err = k5_mutex_unlock(&key_lock);
+    }
+
+#endif
+    return 0;
+}
+
+int k5_key_delete (k5_key_t keynum)
+{
+    assert(keynum >= 0 && keynum < K5_KEY_MAX);
+
+#ifndef ENABLE_THREADS
+
+    assert(destructors_set[keynum] == 1);
+    if (destructors[keynum] && tsd_no_threads.values[keynum])
+	(*destructors[keynum])(tsd_no_threads.values[keynum]);
+    destructors[keynum] = 0;
+    tsd_no_threads.values[keynum] = 0;
+    destructors_set[keynum] = 0;
+
+#elif defined(_WIN32)
+
+    /* XXX: This can raise EXCEPTION_POSSIBLE_DEADLOCK.  */
+    EnterCriticalSection(&key_lock);
+    /* XXX Memory leak here!
+       Need to destroy the associated data for all threads.
+       But watch for race conditions in case threads are going away too.  */
+    assert(destructors_set[keynum] == 1);
+    destructors_set[keynum] = 0;
+    destructors[keynum] = 0;
+    LeaveCriticalSection(&key_lock);
+
+#else /* POSIX */
+
+    {
+	int err;
+
+	/* XXX RESOURCE LEAK:
+
+	   Need to destroy the allocated objects first!  */
+
+	err = k5_mutex_lock(&key_lock);
+	if (err == 0) {
+	    assert(destructors_set[keynum] == 1);
+	    destructors_set[keynum] = 0;
+	    destructors[keynum] = NULL;
+	    k5_mutex_unlock(&key_lock);
+	}
+    }
+
+#endif
+
+    return 0;
+}
+
+int krb5int_call_thread_support_init (void)
+{
+    return CALL_INIT_FUNCTION(krb5int_thread_support_init);
+}
+
+#include "cache-addrinfo.h"
+
+#ifdef DEBUG_THREADS_STATS
+#include <stdio.h>
+static FILE *stats_logfile;
+#endif
+
+int krb5int_thread_support_init (void)
+{
+    int err;
+
+#ifdef SHOW_INITFINI_FUNCS
+    printf("krb5int_thread_support_init\n");
+#endif
+
+#ifdef DEBUG_THREADS_STATS
+    /*    stats_logfile = stderr; */
+    stats_logfile = fopen("/dev/tty", "w+");
+    if (stats_logfile == NULL)
+      stats_logfile = stderr;
+#endif
+
+#ifndef ENABLE_THREADS
+
+    /* Nothing to do for TLS initialization.  */
+
+#elif defined(_WIN32)
+
+    tls_idx = TlsAlloc();
+    /* XXX This can raise an exception if memory is low!  */
+    InitializeCriticalSection(&key_lock);
+
+#else /* POSIX */
+
+    err = k5_mutex_finish_init(&key_lock);
+    if (err)
+	return err;
+    if (K5_PTHREADS_LOADED) {
+	err = pthread_key_create(&key, thread_termination);
+	if (err)
+	    return err;
+    }
+
+#endif
+
+    err = krb5int_init_fac();
+    if (err)
+	return err;
+
+    return 0;
+}
+
+void krb5int_thread_support_fini (void)
+{
+    if (! INITIALIZER_RAN (krb5int_thread_support_init))
+	return;
+
+#ifdef SHOW_INITFINI_FUNCS
+    printf("krb5int_thread_support_fini\n");
+#endif
+
+#ifndef ENABLE_THREADS
+
+    /* Do nothing.  */
+
+#elif defined(_WIN32)
+
+    /* ... free stuff ... */
+    TlsFree(tls_idx);
+    DeleteCriticalSection(&key_lock);
+
+#else /* POSIX */
+
+    if (! INITIALIZER_RAN(krb5int_thread_support_init))
+	return;
+    if (K5_PTHREADS_LOADED)
+	pthread_key_delete(key);
+    /* ... delete stuff ... */
+    k5_mutex_destroy(&key_lock);
+
+#endif
+
+#ifdef DEBUG_THREADS_STATS
+    fflush(stats_logfile);
+    /* XXX Should close if not stderr, in case unloading library but
+       not exiting.  */
+#endif
+
+    krb5int_fini_fac();
+}
+
+#ifdef DEBUG_THREADS_STATS
+void KRB5_CALLCONV
+k5_mutex_lock_update_stats(k5_debug_mutex_stats *m,
+			   k5_mutex_stats_tmp startwait)
+{
+  k5_debug_time_t now;
+  k5_debug_timediff_t tdiff, tdiff2;
+
+  now = get_current_time();
+  (void) krb5int_call_thread_support_init();
+  m->count++;
+  m->time_acquired = now;
+  tdiff = timediff(now, startwait);
+  tdiff2 = tdiff * tdiff;
+  if (m->count == 1 || m->lockwait.valmin > tdiff)
+    m->lockwait.valmin = tdiff;
+  if (m->count == 1 || m->lockwait.valmax < tdiff)
+    m->lockwait.valmax = tdiff;
+  m->lockwait.valsum += tdiff;
+  m->lockwait.valsqsum += tdiff2;
+}
+
+void KRB5_CALLCONV
+krb5int_mutex_unlock_update_stats(k5_debug_mutex_stats *m)
+{
+  k5_debug_time_t now = get_current_time();
+  k5_debug_timediff_t tdiff, tdiff2;
+  tdiff = timediff(now, m->time_acquired);
+  tdiff2 = tdiff * tdiff;
+  if (m->count == 1 || m->lockheld.valmin > tdiff)
+    m->lockheld.valmin = tdiff;
+  if (m->count == 1 || m->lockheld.valmax < tdiff)
+    m->lockheld.valmax = tdiff;
+  m->lockheld.valsum += tdiff;
+  m->lockheld.valsqsum += tdiff2;
+}
+
+#include <math.h>
+static inline double
+get_stddev(struct k5_timediff_stats sp, int count)
+{
+  long double mu, mu_squared, rho_squared;
+  mu = (long double) sp.valsum / count;
+  mu_squared = mu * mu;
+  /* SUM((x_i - mu)^2)
+     = SUM(x_i^2 - 2*mu*x_i + mu^2)
+     = SUM(x_i^2) - 2*mu*SUM(x_i) + N*mu^2
+
+     Standard deviation rho^2 = SUM(...) / N.  */
+  rho_squared = (sp.valsqsum - 2 * mu * sp.valsum + count * mu_squared) / count;
+  return sqrt(rho_squared);
+}
+
+void KRB5_CALLCONV
+krb5int_mutex_report_stats(k5_mutex_t *m)
+{
+  char *p;
+
+  /* Tweak this to only record data on "interesting" locks.  */
+  if (m->stats.count < 10)
+    return;
+  if (m->stats.lockwait.valsum < 10 * m->stats.count)
+    return;
+
+  p = strrchr(m->loc_created.filename, '/');
+  if (p == NULL)
+    p = m->loc_created.filename;
+  else
+    p++;
+  fprintf(stats_logfile, "mutex @%p: created at line %d of %s\n",
+	  (void *) m, m->loc_created.lineno, p);
+  if (m->stats.count == 0)
+    fprintf(stats_logfile, "\tnever locked\n");
+  else {
+    double sd_wait, sd_hold;
+    sd_wait = get_stddev(m->stats.lockwait, m->stats.count);
+    sd_hold = get_stddev(m->stats.lockheld, m->stats.count);
+    fprintf(stats_logfile,
+	    "\tlocked %d time%s; wait %lu/%f/%lu/%fus, hold %lu/%f/%lu/%fus\n",
+	    m->stats.count, m->stats.count == 1 ? "" : "s",
+	    (unsigned long) m->stats.lockwait.valmin,
+	    (double) m->stats.lockwait.valsum / m->stats.count,
+	    (unsigned long) m->stats.lockwait.valmax,
+	    sd_wait,
+	    (unsigned long) m->stats.lockheld.valmin,
+	    (double) m->stats.lockheld.valsum / m->stats.count,
+	    (unsigned long) m->stats.lockheld.valmax,
+	    sd_hold);
+  }
+}
+#elif defined _WIN32
+/* On Windows, everything defined in the export list must be defined.
+   The UNIX systems where we're using the export list don't seem to
+   care.  */
+#undef krb5int_mutex_lock_update_stats
+void KRB5_CALLCONV
+krb5int_mutex_lock_update_stats(k5_debug_mutex_stats *m,
+				k5_mutex_stats_tmp startwait)
+{
+}
+#undef krb5int_mutex_unlock_update_stats
+void KRB5_CALLCONV
+krb5int_mutex_unlock_update_stats(k5_debug_mutex_stats *m)
+{
+}
+#undef krb5int_mutex_report_stats
+void KRB5_CALLCONV
+krb5int_mutex_report_stats(k5_mutex_t *m)
+{
+}
+#endif
diff --git a/mechglue/src/util/windows/ChangeLog b/mechglue/src/util/windows/ChangeLog
new file mode 100644
index 000000000..96fd0aee4
--- /dev/null
+++ b/mechglue/src/util/windows/ChangeLog
@@ -0,0 +1,16 @@
+2000-02-04  Danilo Almeida  <dalmeida@mit.edu>
+
+	* getopt.c, getopt_long.c, getopt.h: Update to latest BSD code
+	found (from NetBSD).
+
+	* Makefile.in: Build getopt.lib which includes getopt.obj and
+	getopt_long.obj.
+
+Mon May 10 15:27:34 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+1998-05-06  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* getopt.c (getopt): POSIX states that getopt returns -1
+		when it is done parsing options, not EOF.
diff --git a/mechglue/src/util/windows/Makefile.in b/mechglue/src/util/windows/Makefile.in
new file mode 100644
index 000000000..be5d4f5d6
--- /dev/null
+++ b/mechglue/src/util/windows/Makefile.in
@@ -0,0 +1,14 @@
+BUILDTOP = ..\..
+
+all-windows:: $(OUTPRE)libecho.exe $(OUTPRE)getopt.lib
+
+$(OUTPRE)libecho.exe: $(OUTPRE)libecho.obj
+	link -out:$@ $**
+
+$(OUTPRE)getopt.lib: $(OUTPRE)getopt.obj $(OUTPRE)getopt_long.obj
+	lib -out:$@ $**
+
+install-windows::
+
+clean-windows::
+	$(RM) $(OUTPRE)*.res $(OUTPRE)*.map $(OUTPRE)*.obj $(OUTPRE)*.exe
diff --git a/mechglue/src/util/windows/getopt.c b/mechglue/src/util/windows/getopt.c
new file mode 100644
index 000000000..2b21c7be5
--- /dev/null
+++ b/mechglue/src/util/windows/getopt.c
@@ -0,0 +1,152 @@
+/*	$NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $	*/
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)getopt.c	8.3 (Berkeley) 4/27/95";
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+#ifdef __weak_alias
+__weak_alias(getopt,_getopt);
+#endif
+
+
+int	opterr = 1,		/* if error message should be printed */
+	optind = 1,		/* index into parent argv vector */
+	optopt,			/* character checked for validity */
+	optreset;		/* reset getopt */
+char	*optarg;		/* argument associated with option */
+
+static char * _progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+_progname(nargv0)
+	char * nargv0;
+{
+	char * tmp;
+
+	_DIAGASSERT(nargv0 != NULL);
+
+	tmp = strrchr(nargv0, '/');
+	if (tmp)
+		tmp++;
+	else
+		tmp = nargv0;
+	return(tmp);
+}
+
+#define	BADCH	(int)'?'
+#define	BADARG	(int)':'
+#define	EMSG	""
+
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+	int nargc;
+	char * const nargv[];
+	const char *ostr;
+{
+	static char *__progname = 0;
+	static char *place = EMSG;		/* option letter processing */
+	char *oli;				/* option letter list index */
+        __progname = __progname?__progname:_progname(*nargv);
+
+	_DIAGASSERT(nargv != NULL);
+	_DIAGASSERT(ostr != NULL);
+
+	if (optreset || !*place) {		/* update scanning pointer */
+		optreset = 0;
+		if (optind >= nargc || *(place = nargv[optind]) != '-') {
+			place = EMSG;
+			return (-1);
+		}
+		if (place[1] && *++place == '-'	/* found "--" */
+		    && place[1] == '\0') {
+			++optind;
+			place = EMSG;
+			return (-1);
+		}
+	}					/* option letter okay? */
+	if ((optopt = (int)*place++) == (int)':' ||
+	    !(oli = strchr(ostr, optopt))) {
+		/*
+		 * if the user didn't specify '-' as an option,
+		 * assume it means -1.
+		 */
+		if (optopt == (int)'-')
+			return (-1);
+		if (!*place)
+			++optind;
+		if (opterr && *ostr != ':')
+			(void)fprintf(stderr,
+			    "%s: illegal option -- %c\n", __progname, optopt);
+		return (BADCH);
+	}
+	if (*++oli != ':') {			/* don't need argument */
+		optarg = NULL;
+		if (!*place)
+			++optind;
+	}
+	else {					/* need an argument */
+		if (*place)			/* no white space */
+			optarg = place;
+		else if (nargc <= ++optind) {	/* no arg */
+			place = EMSG;
+			if (*ostr == ':')
+				return (BADARG);
+			if (opterr)
+				(void)fprintf(stderr,
+				    "%s: option requires an argument -- %c\n",
+				    __progname, optopt);
+			return (BADCH);
+		}
+	 	else				/* white space */
+			optarg = nargv[optind];
+		place = EMSG;
+		++optind;
+	}
+	return (optopt);			/* dump back option letter */
+}
diff --git a/mechglue/src/util/windows/getopt.h b/mechglue/src/util/windows/getopt.h
new file mode 100644
index 000000000..7137f0379
--- /dev/null
+++ b/mechglue/src/util/windows/getopt.h
@@ -0,0 +1,33 @@
+#ifndef __GETOPT_H__
+#define __GETOPT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int opterr;		/* if error message should be printed */
+extern int optind;		/* index into parent argv vector */
+extern int optopt;		/* character checked for validity */
+extern int optreset;		/* reset getopt */
+extern char *optarg;		/* argument associated with option */
+
+struct option
+{
+  const char *name;
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+#define no_argument       0
+#define required_argument 1
+#define optional_argument 2
+
+int getopt(int, char**, char*);
+int getopt_long(int, char**, char*, struct option*, int*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GETOPT_H__ */
diff --git a/mechglue/src/util/windows/getopt_long.c b/mechglue/src/util/windows/getopt_long.c
new file mode 100644
index 000000000..bb819628e
--- /dev/null
+++ b/mechglue/src/util/windows/getopt_long.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1987, 1993, 1994, 1996
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+
+extern int	  opterr;	/* if error message should be printed */
+extern int	  optind;	/* index into parent argv vector */
+extern int	  optopt;	/* character checked for validity */
+extern int	  optreset;	/* reset getopt */
+extern char *optarg;	/* argument associated with option */
+
+#define __P(x) x
+#define _DIAGASSERT(x) assert(x)
+
+static char * __progname __P((char *));
+int getopt_internal __P((int, char * const *, const char *));
+
+static char *
+__progname(nargv0)
+	char * nargv0;
+{
+	char * tmp;
+
+	_DIAGASSERT(nargv0 != NULL);
+
+	tmp = strrchr(nargv0, '/');
+	if (tmp)
+		tmp++;
+	else
+		tmp = nargv0;
+	return(tmp);
+}
+
+#define	BADCH	(int)'?'
+#define	BADARG	(int)':'
+#define	EMSG	""
+
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_internal(nargc, nargv, ostr)
+	int nargc;
+	char * const *nargv;
+	const char *ostr;
+{
+	static char *place = EMSG;		/* option letter processing */
+	char *oli;				/* option letter list index */
+
+	_DIAGASSERT(nargv != NULL);
+	_DIAGASSERT(ostr != NULL);
+
+	if (optreset || !*place) {		/* update scanning pointer */
+		optreset = 0;
+		if (optind >= nargc || *(place = nargv[optind]) != '-') {
+			place = EMSG;
+			return (-1);
+		}
+		if (place[1] && *++place == '-') {	/* found "--" */
+			/* ++optind; */
+			place = EMSG;
+			return (-2);
+		}
+	}					/* option letter okay? */
+	if ((optopt = (int)*place++) == (int)':' ||
+	    !(oli = strchr(ostr, optopt))) {
+		/*
+		 * if the user didn't specify '-' as an option,
+		 * assume it means -1.
+		 */
+		if (optopt == (int)'-')
+			return (-1);
+		if (!*place)
+			++optind;
+		if (opterr && *ostr != ':')
+			(void)fprintf(stderr,
+			    "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
+		return (BADCH);
+	}
+	if (*++oli != ':') {			/* don't need argument */
+		optarg = NULL;
+		if (!*place)
+			++optind;
+	} else {				/* need an argument */
+		if (*place)			/* no white space */
+			optarg = place;
+		else if (nargc <= ++optind) {	/* no arg */
+			place = EMSG;
+			if ((opterr) && (*ostr != ':'))
+				(void)fprintf(stderr,
+				    "%s: option requires an argument -- %c\n",
+				    __progname(nargv[0]), optopt);
+			return (BADARG);
+		} else				/* white space */
+			optarg = nargv[optind];
+		place = EMSG;
+		++optind;
+	}
+	return (optopt);			/* dump back option letter */
+}
+
+#if 0
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt2(nargc, nargv, ostr)
+	int nargc;
+	char * const *nargv;
+	const char *ostr;
+{
+	int retval;
+
+	if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
+		retval = -1;
+		++optind; 
+	}
+	return(retval);
+}
+#endif
+
+/*
+ * getopt_long --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, index)
+	int nargc;
+	char ** nargv;
+	char * options;
+	struct option * long_options;
+	int * index;
+{
+	int retval;
+
+	_DIAGASSERT(nargv != NULL);
+	_DIAGASSERT(options != NULL);
+	_DIAGASSERT(long_options != NULL);
+	/* index may be NULL */
+
+	if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
+		char *current_argv = nargv[optind++] + 2, *has_equal;
+		int i, current_argv_len, match = -1;
+
+		if (*current_argv == '\0') {
+			return(-1);
+		}
+		if ((has_equal = strchr(current_argv, '=')) != NULL) {
+			current_argv_len = has_equal - current_argv;
+			has_equal++;
+		} else
+			current_argv_len = strlen(current_argv);
+
+		for (i = 0; long_options[i].name; i++) { 
+			if (strncmp(current_argv, long_options[i].name, current_argv_len))
+				continue;
+
+			if (strlen(long_options[i].name) == (unsigned)current_argv_len) { 
+				match = i;
+				break;
+			}
+			if (match == -1)
+				match = i;
+		}
+		if (match != -1) {
+			if (long_options[match].has_arg == required_argument ||
+			    long_options[match].has_arg == optional_argument) {
+				if (has_equal)
+					optarg = has_equal;
+				else
+					optarg = nargv[optind++];
+			}
+			if ((long_options[match].has_arg == required_argument)
+			    && (optarg == NULL)) {
+				/*
+				 * Missing argument, leading :
+				 * indicates no error should be generated
+				 */
+				if ((opterr) && (*options != ':'))
+					(void)fprintf(stderr,
+				      "%s: option requires an argument -- %s\n",
+				      __progname(nargv[0]), current_argv);
+				return (BADARG);
+			}
+		} else { /* No matching argument */
+			if ((opterr) && (*options != ':'))
+				(void)fprintf(stderr,
+				    "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
+			return (BADCH);
+		}
+		if (long_options[match].flag) {
+			*long_options[match].flag = long_options[match].val;
+			retval = 0;
+		} else 
+			retval = long_options[match].val;
+		if (index)
+			*index = match;
+	}
+	return(retval);
+}
diff --git a/mechglue/src/util/windows/libecho.c b/mechglue/src/util/windows/libecho.c
new file mode 100644
index 000000000..9fcbe2e98
--- /dev/null
+++ b/mechglue/src/util/windows/libecho.c
@@ -0,0 +1,76 @@
+/*
+ * libecho.c
+ *
+ * For each argument on the command line, echo it.  Should expand
+ * DOS wildcards correctly.
+ *
+ * Syntax: libecho [-p prefix] list...
+ */
+#include <stdio.h>
+#include <io.h>
+#include <string.h>
+
+void echo_files(char *, char *);
+
+int
+main(int argc, char *argv[])
+{
+  int i;
+  char *prefix;
+
+  prefix = "";
+
+  if (argc < 2) {
+    fprintf(stderr, "Usage:  libecho [-p prefix] list...\n");
+    return 1;
+  }
+
+  for (i = 1 ; i < argc ; i++)
+    if (!stricmp(argv[i], "-p"))
+      prefix = argv[++i];
+    else
+      echo_files(prefix, argv[i]);
+
+  return 0;
+}
+
+void
+echo_files(char *prefix, char *f)
+{
+  long ff;
+  struct _finddata_t fdt;
+  char *slash;
+  char filepath[256];
+
+  /*
+   * We're unix based quite a bit here.  Look for normal slashes and
+   * make them reverse slashes.
+   */
+  while((slash = strrchr(f, '/')) != NULL)
+    *slash = '\\';
+
+  strcpy(filepath, f);
+
+  slash = strrchr(filepath, '\\');
+
+  if (slash) {
+    slash++;
+    *slash = 0;
+  } else {
+    filepath[0] = '\0';
+  }
+
+  ff = _findfirst(f, &fdt);
+
+  if (ff < 0)
+    return;
+
+  printf("%s%s%s\n", prefix, filepath, fdt.name);
+
+  for (;;) {
+    if (_findnext(ff, &fdt) < 0)
+      break;
+    printf("%s%s%s\n", prefix, filepath, fdt.name);
+  }
+  _findclose(ff);
+}
diff --git a/mechglue/src/wconfig.c b/mechglue/src/wconfig.c
new file mode 100644
index 000000000..087a54b5c
--- /dev/null
+++ b/mechglue/src/wconfig.c
@@ -0,0 +1,219 @@
+/*
+ * wconfig.c
+ *
+ * Copyright 1995,1996,1997,1998 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Program to take the place of the configure shell script under DOS.
+ * The makefile.in files are constructed in such a way that all this
+ * program needs to do is uncomment lines beginning ##DOS by removing the
+ * first 5 characters of the line.  This will allow lines like:
+ * ##DOS!include win-pre.in to become: !include win-pre.in
+ *
+ * We also turn any line beginning with '@' into a blank line.
+ *
+ * If a config directory is specified, then the output will be start with
+ * config\pre.in, then the filtered stdin text, and will end with
+ * config\post.in.
+ *
+ * Syntax: wconfig [options] [config_directory] <input_file >output_file
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+static int copy_file (char *path, char *fname);
+void add_ignore_list(char *str);
+
+int mit_specific = 0;
+
+char *win16_flag = "WIN16##";
+char *win32_flag = "WIN32##";
+
+
+int main(int argc, char *argv[])
+{
+	char *ignore_str = "--ignore=";
+	int ignore_len;
+	char *cp, tmp[80];
+	char *win_flag;
+	char wflags[1024];
+
+#ifdef _WIN32
+	win_flag = win32_flag;
+#else
+	win_flag = "UNIX##";
+#endif
+
+	wflags[0] = 0;
+
+	ignore_len = strlen(ignore_str);
+	argc--; argv++;
+	while (*argv && *argv[0] == '-') {
+		wflags[sizeof(wflags) - 1] = '\0';
+		if (strlen (wflags) + 1 + strlen (*argv) > sizeof (wflags) - 1) {
+			fprintf (stderr,
+				 "wconfig: argument list too long (internal limit %d)",
+				 sizeof (wflags));
+			exit (1);
+		}
+		if (wflags[0])
+			strcat(wflags, " ");
+		strcat(wflags, *argv);
+
+		if (!strcmp(*argv, "--mit")) {
+			mit_specific = 1;
+			argc--; argv++;
+			continue;
+		}
+		if (!strcmp(*argv, "--win16")) {
+			win_flag = win16_flag;
+			argc--; argv++;
+			continue;
+		}
+		if (!strcmp(*argv, "--win32")) {
+			win_flag = win32_flag;
+			argc--; argv++;
+			continue;
+		}
+		if (!strncmp(*argv, "--enable-", 9)) {
+			sprintf(tmp, "%s##", (*argv)+ignore_len);
+			for (cp = tmp; *cp; cp++) {
+				if (islower(*cp))
+					*cp = toupper(*cp);
+			}
+			cp = malloc(strlen(tmp)+1);
+			if (!cp) {
+				fprintf(stderr,
+					"wconfig: malloc failed!\n");
+				exit(1);
+			}
+			strcpy(cp, tmp);
+			add_ignore_list(cp);
+			argc--; argv++;
+			continue;
+		}
+		if (!strncmp(*argv, ignore_str, ignore_len)) {
+			add_ignore_list((*argv)+ignore_len);
+			argc--; argv++;
+			continue;
+		}
+		fprintf(stderr, "Invalid option: %s\n", *argv);
+		exit(1);
+	}
+
+	if (win_flag)
+		add_ignore_list(win_flag);
+
+	if (mit_specific)
+		add_ignore_list("MIT##");
+		
+	if (wflags[0] && (argc > 0))
+		printf("WCONFIG_FLAGS=%s\n", wflags);
+
+	if (argc > 0)
+		copy_file (*argv, "win-pre.in");
+
+	copy_file("", "-");
+    
+	if (argc > 0)
+		copy_file (*argv, "win-post.in");
+
+	return 0;
+}
+
+char *ignore_list[64] = {
+	"DOS##",
+	"DOS",
+	};
+
+/*
+ * Add a new item to the ignore list
+ */
+void add_ignore_list(char *str)
+{
+	char **cpp;
+
+	for (cpp = ignore_list; *cpp; cpp++)
+		;
+	*cpp = str;
+}
+
+		
+/*
+ * 
+ * Copy_file
+ * 
+ * Copies file 'path\fname' to stdout.
+ * 
+ */
+static int
+copy_file (char *path, char *fname)
+{
+    FILE *fin;
+    char buf[1024];
+    char **cpp, *ptr;
+    int len;
+
+    if (strcmp(fname, "-") == 0) {
+	    fin = stdin;
+    } else {
+#ifdef _WIN32
+	    sprintf(buf, "%s\\%s", path, fname);
+#else
+	    sprintf(buf, "%s/%s", path, fname);
+#endif
+	    fin = fopen (buf, "r");                     /* File to read */
+	    if (fin == NULL) {
+		    fprintf(stderr, "wconfig: Can't open file %s\n", buf);
+		    return 1;
+	    }
+    }
+    
+
+    while (fgets (buf, sizeof(buf), fin) != NULL) { /* Copy file over */
+	    if (buf[0] == '@') {
+		    fputs("\n", stdout);
+		    continue;
+	    }
+	    if (buf[0] != '#' || buf[1] != '#') {
+		    fputs(buf, stdout);
+		    continue;
+	    }
+	    ptr = buf;
+	    for (cpp = ignore_list; *cpp; cpp++) {
+		    len = strlen(*cpp);
+		    if (memcmp (*cpp, buf+2, len) == 0) {
+			    ptr += 2+len;
+			    break;
+		    }
+	    }
+	    fputs(ptr, stdout);
+    }
+
+    fclose (fin);
+
+    return 0;
+}
diff --git a/mechglue/src/windows/.Sanitize b/mechglue/src/windows/.Sanitize
new file mode 100644
index 000000000..163ea0f1e
--- /dev/null
+++ b/mechglue/src/windows/.Sanitize
@@ -0,0 +1,37 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+changelo
+cns
+gss
+makefile
+readme
+wintel
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/windows/ChangeLog b/mechglue/src/windows/ChangeLog
new file mode 100644
index 000000000..d2fcb8fa2
--- /dev/null
+++ b/mechglue/src/windows/ChangeLog
@@ -0,0 +1,174 @@
+2005-11-29  Jeffrey Altman <jaltman@mit.edu>
+
+	* Makefile.in: build src/windows/kfwlogon
+
+2004-12-15  Jeffrey Altman <jaltman@mit.edu>
+   
+         * version.rc: rename krb5support.dll to k5sprt32.dll
+
+2004-09-30  Jeffrey Altman <jaltman@mit.edu>
+
+        * version.rc: Add pismere condition resource strings
+
+2004-09-24  Tom Yu  <tlyu@mit.edu>
+
+	* version.rc: Use patchlevel.h to generate version stamp info.
+
+2004-06-18  Ken Raeburn  <raeburn@mit.edu>
+
+	* version.rc: Add info for support library.
+
+2004-02-02  Jeffrey Altman <jaltman@mit.edu>
+
+    * README: Document PreserveInitialTicketIdentity registry key
+
+2004-01-30  Jeffrey Altman <jaltman@mit.edu>
+
+    * README: Update the text to include the details of the new 
+      Windows registry keys necessary to access the TGT session key.
+      Also, provide details on the incompatibility of the gss.exe
+      sample client and the versions distributed by Microsoft.
+
+2003-12-22  Jeffrey Altman <jaltman@mit.edu>
+
+    * README: Update to more clearly specify the build environment 
+      requirements.  Supported compilers include MSVC++ 6.0, MSVS.NET,
+      and MSVS.NET 2003.  Clarify requirements for building with DNS
+      support.  Also, add text describing MSLSA: credential cache 
+      and how to configure Windows so it can be used.
+
+2003-07-22  Tom Yu  <tlyu@mit.edu>
+
+	* README: Revert previous change, as it was in error; socklen_t
+	was introduced in Aug 2001 Platform SDK, and the actual problem
+	reported was very probably a compilation environment
+	misconfiguration.
+
+2003-07-18  Tom Yu  <tlyu@mit.edu>
+
+	* README: Note requirement for Feb 2003 Platform SDK.  Thanks to
+	Doug Engert and Rodney Dyer.
+
+2002-04-10  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Build ms2mit.
+	* version.rc: 1.3 (TEST) beta.
+	* README: Note on building ms2mit.
+
+2000-06-21  Danilo Almeida  <dalmeida@mit.edu>
+
+	* README: Update documentation with DNS information.  Fix up the
+	language a bit.
+
+2000-04-25  Danilo Almeida  <dalmeida@mit.edu>
+
+	* version.rc: Bump version to 1.2 beta.
+
+2000-02-06  Danilo Almeida  <dalmeida@mit.edu>
+
+	* README: Add documentation about debug vs. release builds.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* version.rc: Bump version up to 1.1.1.
+
+1999-09-15  Danilo Almeida  <dalmeida@mit.edu>
+
+	* README: Add documentation about configuration under windows and
+	krbcc32.dll.
+
+1999-09-09  Danilo Almeida  <dalmeida@mit.edu>
+
+	* README: Explicitly say that we support only Win32 and not Win16.
+
+1999-09-08  Danilo Almeida  <dalmeida@mit.edu>
+
+	* README: Update with install target information and more.
+	* mkbin.bat: Remove mkbin.bat as it is no longer used.
+
+1999-09-01  Danilo Almeida  <dalmeida@mit.edu>
+
+	* readme, README: readme renamed to README.
+
+	* version.rc: Boost version to 1.1.  Include 1998 & 1999 in copyright
+	years.
+
+1999-06-21  Danilo Almeida  <dalmeida@mit.edu>
+
+	* version.rc: Boost version to 1.0.8.
+
+Wed May 19 13:14:38 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove unncessary LIBCMD definition from recursive
+		make invocations.
+
+Tue May 18 19:52:56 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove - from recursive Win32 make invocation.
+
+	* readme: Update with Unix-less build method.  Add notice saying
+		we build with MSVC++ 6.0 and do not know whether it works
+		with other compiler/make utilties.
+
+Mon May 17 19:53:28 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* version.rc: Boost version to 1.0.6.
+
+Mon May 17 14:19:08 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add NO_OUTPRE flag to prevent creation of output
+		directory under win32.  Add clean-windows target.  Reflect
+		that we only build this under win32 by removing wconfig
+		tags.
+
+Mon Feb  8 21:45:05 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* readme: Update readme file so that it doesn't have obviously
+		incorrect information in it.  (It's still not perfect!)
+
+1998-05-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* mkbin.bat: Added convenience batch file which copies all of the
+		appropriate files out of the build tree into a single kbin
+		directory
+
+	* Makefile.in: Add the windows/lib directory to the list of
+		directories to be built (and cleaned).
+
+Tue Aug  5 18:40:55 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* version.rc: New file containing the version resource information
+		for MIT releases of the Krb5 software.
+
+Fri Apr 28 11:21:01 1995 Keith Vetter (keithv@fusion.com)
+
+	* makefile: added gss, new subdirectory for gss demo.
+
+Wed Apr 19 18:37:07 1995 Keith Vetter (keithv@fusion.com)
+
+	* readme: updated about how to make it, and about gssapi.
+
+Wed Apr 5 16:14:49 1995 Keith Vetter (keithv@fusion.com)
+
+	* readme: updated about realms, conf files and telnet port.
+
+Tue Mar 28 12:00:00  1995 Keith Vetter (keithv@fusion.com)
+
+	* ChangeLog renamed to changelo to avoid having to always rename it.
+
+Mon Mar 27 23:34:58 1995 Keith Vetter (keithv@fusion.com)
+
+	* makefile: fixed typo on the cd command
+
+Mon Mar 27 20:34:58 1995 Keith Vetter (keithv@fusion.com)
+
+	* makefile: makes recursively in wintel directory
+        * readme: updated for wintel program.
+
+Thu Mar 23 14:00:00 1995 Keith Vetter (keithv@fusion.com)
+
+	* readme: updated to reflect name change of zipping target.
+
+Wed Mar 22 15:01:33 1995 Keith Vetter (keithv@fusion.com)
+
+	* readme: how-to create Windows version of kerberos 5
diff --git a/mechglue/src/windows/Makefile.in b/mechglue/src/windows/Makefile.in
new file mode 100644
index 000000000..f1045951a
--- /dev/null
+++ b/mechglue/src/windows/Makefile.in
@@ -0,0 +1,63 @@
+BUILDTOP=..
+NO_OUTPRE=1
+
+#
+# Makefile that recurses into cns subdirectory.
+#
+all-windows::
+	@echo Making in windows\lib
+	cd lib
+	$(MAKE) -$(MFLAGS)
+	@echo Making in windows\cns
+	cd ..\cns
+	$(MAKE) -$(MFLAGS)
+	@echo Making in windows\wintel
+	cd ..\wintel
+	$(MAKE) -$(MFLAGS)
+	@echo Making in windows\gss
+	cd ..\gss
+	$(MAKE) -$(MFLAGS)
+	@echo Making in windows\gina
+	cd ..\gina
+	$(MAKE) -$(MFLAGS)
+	@echo Making in windows\ms2mit
+	cd ..\ms2mit
+	$(MAKE) -$(MFLAGS)
+!if "$(KRB5_KFW_COMPILE)"=="1" 
+        @echo Making in windows\kfwlogon
+        cd ..\kfwlogon
+        $(MAKE) -$(MFLAGS) 
+        @echo Making in windows\identity 
+        cd ..\identity 
+        $(MAKE) -$(MFLAGS) 
+!endif 
+	cd ..
+
+clean-windows::
+	@echo Making clean in windows\lib
+	cd lib
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in windows\cns
+	cd ..\cns
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in windows\wintel
+	cd ..\wintel
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in windows\gss
+	cd ..\gss
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in windows\gina
+	cd ..\gina
+	$(MAKE) -$(MFLAGS) clean
+	@echo Making clean in windows\ms2mit
+	cd ..\ms2mit
+	$(MAKE) -$(MFLAGS) clean
+!if "$(KRB5_KFW_COMPILE)"=="1" 
+        @echo Making clean in windows\kfwlogon
+        cd ..\kfwlogon
+        $(MAKE) -$(MFLAGS) clean 
+        @echo Making clean in windows\identity 
+        cd ..\identity 
+        $(MAKE) -$(MFLAGS) clean 
+!endif 
+	cd ..
diff --git a/mechglue/src/windows/README b/mechglue/src/windows/README
new file mode 100644
index 000000000..96757e925
--- /dev/null
+++ b/mechglue/src/windows/README
@@ -0,0 +1,308 @@
+	       Building & Running Kerberos 5 on Windows
+	       ----------------------------------------
+
+Kerberos 5 builds on Windows with MSVC++ 6.0, MSVS.NET, and 
+MSVS.NET 2003.  You will need the November 2001 platform SDK or 
+later; this SDK is required to define getaddrinfo.  It may or 
+may not build with other compilers or make utilities.
+
+These build instructions assume that you have the standalone source
+distribution of Kerberos 5 rather than the MIT Kerberos for Windows
+distribution (which includes a working Kerberos 4).
+
+There are two methods for building a Windows version of Kerberos 5.
+The traditional method involves starting on a Unix machine and
+creating a distribution that can be built on Windows.  The second
+method works from the sources that come from the Unix distribution if
+you have certain Unix-type utilities (see below).
+
+IMPORTANT NOTE: By default, the sources are built with debug
+information and linked against the debug version of the Microsoft C
+Runtime library, which is not found on most Windows systems unless
+they have development tools.  To build a release version, you need to
+define NODEBUG either in the environment or the nmake command-line.
+
+To configuring the build environment execute first the compiler
+batch file, vcvars32.bat or vsvars32.bat, followed by the SDK
+batch file, setenv.bat.  For example, 
+
+  "c:\program files\microsoft visual studio .net 2003\common7\tools\vsvars32.bat"
+  "c:\program files\microsoft sdk\setenv.bat" /2000 /RETAIL
+
+or 
+
+  "c:\program files\microsoft visual studio\vc98\bin\vcvars32.bat"
+  "c:\program files\microsoft sdk\setenv.bat" /2000 /DEBUG
+  
+DNS Support: To support DNS lookups, you will need to define
+KRB5_DNS_LOOKUP, KRB5_DNS_LOOKUP_KDC, or KRB5_DNS_LOOKUP_REALMS.  When 
+any of the KRB5_DNS_LOOKUP definitions are used, the default build will use
+the WSHelper library which is part of the Kerberos for Windows (Kfw) 
+distribution.  If you are building outside of KfW and wish to build Krb5 
+with DNS support, you must provide a resolver library whose include files 
+match the Unix resolver library.  You will need to define KRB5_NO_WSHELPER,
+define DNS_INC to point to the include directory for the library and DNS_LIB 
+to library itself.  The default is not to support DNS because the build 
+cannot know whether there is a DNS resolver library around for it to use.
+
+
+Traditional Build Method:
+------------------------
+
+On the Unix side
+1) cd xxx/src                          # Go to where the source lives
+2) make -f Makefile.in kerbsrc.zip     # Do some Unix-side configuring
+                                       # ...and create kerbsrc.zip
+3) <transfer kerbsrc.zip to the PC>
+
+
+On the PC side
+1) md \krb5                            # Create dir where we'll put the tree
+2) cd \krb5
+3) unzip kerbsrc.zip
+        - or -
+   pkunzip -d kerbsrc.zip
+4) nmake [NODEBUG=1] [DNS-options]     # Build the sources
+5) nmake install [NODEBUG=1] [options] # Copy headers, libs, executables
+
+
+All-Windows Build Method:
+------------------------
+
+First, make sure you have sed, gawk, cat, and cp.
+
+1) cd xxx/src                          # Go to where the source lives
+2) nmake -f Makefile.in prep-windows   # Create Makefile for Windows
+3) nmake [NODEBUG=1] [DNS-options]     # Build the sources
+4) nmake install [NODEBUG=1] [options] # Copy headers, libs, executables
+
+
+Notes on the install Target:
+---------------------------
+
+For the install target, you will need to define KRB_INSTALL_DIR to
+point to the directory where the header, library, and executable files
+will be installed.  You can either define this in the environment or
+at the nmake command-line.  For example:
+
+nmake install [NODEBUG=1] KRB_INSTALL_DIR=c:\sdk\krb5
+
+Make sure you create the directory first.  Otherwise, nmake will
+complain.  The files will get installed into include, lib, and bin
+subdirectories.  You can then copy the binaries to where ever you want
+have them (probably somewhere in your path).
+
+
+Running Kerberos 5 Apps:
+-----------------------
+
+Make sure you have a valid krb5.ini file.  That will look just like a
+Unix krb5.conf file.  You can place this file in the same directory as
+your krb5_32.dll or in your Windows directory.  You should then be
+able to run the applications that are built.  Note that Kerberos 5
+will not look for the krb5.ini file in your path.
+
+
+krb5.ini File:
+-------------
+
+WARNING: Despite its name, this is not a Windows .ini file.
+Therefore, do not try to use any .ini tools, including the Windows API
+or any installer tools to manipulate this file.  Its format is subtly
+different from Windows .ini files!
+
+
+Controlling the Kerberos 5 Run-Time Environment:
+-----------------------------------------------
+
+The Kerberos 5 configuration file and credentials cache can be
+controlled with environment variables and registry settings.  The
+environment variable for a particular setting always takes precedence.
+Next in precedence comes the setting in the registry under
+HKEY_CURRENT_USER\Software\MIT\Kerberos5.  Then comes the registry
+setting under HKEY_LOCAL_MACHINE\Software\MIT\Kerberos5.  If none of
+those are found, a default value is used.
+
+Configuration File:
+- Environment: KRB5_CONFIG
+- Registry Value: config
+- Default: looks in krb5_32.dll's dir and Windows directory
+
+Default Credentials Cache:
+- Environment: KRB5CCNAME
+- Registry Value: ccname
+- Default: API:krb5cc or FILE:%TEMP%\krb5cc or FILE:<windows dir>\krb5cc
+
+
+Credentials Cache:
+-----------------
+
+In addition to standard FILE: (disk file) and MEMORY: (in-process
+non-shared memory) Windows supports the API: cache type, which is a
+shared memory cache.  This is implemented by krbcc32.dll, which is not
+included the the krb5-only distribution.  Rather, it is part of MIT's
+Kerberos for Win32 suite.  
+
+As of the 1.3.2 release, a new cache type, MSLSA:, has been added for
+use in accessing the Microsoft Kerberos Logon Session credentials 
+cache.  The MSLSA: cache is available when the user logon is performed
+using Kerberos either to an Active Directory Domain or a non-Microsoft
+KDC.
+
+A user is able to logon to Windows using the Kerberos LSA if the machine
+is part of a Windows 2000 or Windows 2003 Active Directory domain or
+if the machine has been configured to authenticate to a non-Microsoft KDC
+such as MIT.  The instructions for configuring a Windows 2000 XP
+workstation to authenticate to a non-Microsoft KDC are documented
+in TechNet somewhere.  In brief:
+
+  1. Install the Windows 2000 or XP support tools in order to obtain
+     the tools: KSETUP.EXE and KTPASS.EXE.
+  2. Install the Windows 2000 or XP Resource Kit to obtain the tools
+     KERBTRAY.EXE and KLIST.EXE
+  3. Add Realms and associated KDCs with: *KSETUP /AddKdc <realm>
+     [<kdcname>]*.  If you leave off the <kdcname> DNS SRV records will
+     be used.
+  4. Specify the password change service host for the realm with:
+     *KSETUP /AddKpasswd <realm> <Kpwdhost>*
+  5. Assign the realm of the local machine with: *KSETUP /SetRealm
+     <realm>* where realm must be all upper case.   
+  6. Assign the local machine's password with: *KSETUP
+     /SetComputerPassword <Password>
+     *
+  7. Specify the capabilities of the Realm KDC with: *KSETUP
+     /SetRealmFlags <realm> <flag> [<flag> ...]* where flags may be
+     *None, SendAddress, TcpSupported, Delegate, *and *NcSupported*,
+  8. Map principal names to local accounts with: *KSETUP /MapUser
+     <principal> <account>*
+
+On the MIT KDC, you must then create service principals using the "Password" 
+assigned to the machine.  So far the minimum list of principals required appear 
+to be for a machine named "mymachine" in the realm "EXAMPLE.COM" with a 
+domain name of "example.com":
+
+   * host/mymachine@EXAMPLE.COM
+   * host/mymachine.example.com@EXAMPLE.COM
+   * cifs/mymachine@EXAMPLE.COM
+   * cifs/mymachine.example.com@EXAMPLE.COM
+
+There may very well be other serivces for which principals must be created depending 
+on what services are being executed on the machine.
+
+It is very important to note that while you can successfully log into a Windows 
+workstation by authenticating to the KDC without creating a host key; the logon 
+session you receive will not be a Kerberos Logon Session.  There will be no Kerberos 
+principal and no LSA cache to access.
+
+The result of a real KSETUP configuration looks like this:
+
+   [C:\4\4NT]ksetup
+   default realm = KRB5.COLUMBIA.EDU (external)
+   ATHENA.MIT.EDU:
+           kdc = kerberos.mit.edu
+           kdc = kerberos-1.mit.edu
+           kdc = kerberos-2.mit.edu
+           kdc = kerberos-3.mit.edu
+           Realm Flags = 0x0 none
+   CC.COLUMBIA.EDU:
+           kdc = kerberos.cc.columbia.edu
+           Realm Flags = 0x0 none
+   GRAND.CENTRAL.ORG:
+           kdc = penn.central.org
+           kdc = grand-opening.mit.edu
+           Realm Flags = 0x0 none
+   KRB5.COLUMBIA.EDU:
+           kdc = yclept.kermit.columbia.edu
+           Realm Flags = 0x0 none
+   OPENAFS.ORG:
+           kdc = virtue.openafs.org
+           Realm Flags = 0x0 none
+   Mapping jaltman@KRB5.COLUMBIA.EDU to jaltman.
+   Mapping jaltman@CC.COLUMBIA.EDU to jaltman.
+   Mapping jaltman@ATHENA.MIT.EDU to jaltman.
+   Mapping all users (*) to a local account by the same name (*).
+
+The MSLSA: credential cache relies on the ability to extract the entire
+Kerberos ticket including the session key from the Kerberos LSA.  In an
+attempt to increase security Microsoft has begun to implement a feature
+by which they no longer export the session keys for Ticket Getting Tickets.
+This has the side effect of making them useless to the MIT krb5 library
+when attempting to request additional service tickets.
+
+This new feature has been seen in Windows 2003 Server, Windows 2000 Server SP4,
+and Windows XP SP2 Beta.  We assume that it will be implemented in all future
+Microsoft operating systems supporting the Kerberos SSPI.  Microsoft does work
+closely with MIT and has provided a registry key to disable this new feature.
+
+  HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters
+    AllowTGTSessionKey = 0x01 (DWORD)
+
+On Windows XP SP2 Beta 1 the key was specified as 
+
+  HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos
+    AllowTGTSessionKey = 0x01 (DWORD)
+
+However, we anticipate that this will be changed to match the Server platforms 
+in time for SP2 RC1.
+
+It has been noted that the Microsoft Kerberos LSA does not provide enough 
+information within its KERB_EXTERNAL_TICKET structure to properly construct
+the Client Principal simply by examining a single ticket. From the MSDN
+Library:
+
+  ClientName 
+    KERB_EXTERNAL_NAME structure that contains the client name in the ticket. 
+    This name is relative to the current domain. 
+
+  DomainName 
+    UNICODE_STRING that contains the name of the domain that corresponds to 
+    the ServiceName member. This is the domain that issued the ticket. 
+
+  TargetDomainName 
+    UNICODE_STRING that contains the name of the domain in which the ticket is
+    valid. For an interdomain ticket, this is the destination domain. 
+
+  AltTargetDomainName 
+    UNICODE_STRING that contains a synonym for the destination domain. Every 
+    domain has two names: a DNS name and a NetBIOS name. If the name returned 
+    in the ticket is different from the name used to request the ticket (the 
+    Kerberos Key Distribution Center (KDC) may do name mapping), this string 
+    contains the original name. 
+
+Unfortunately, there is no field here which contains the domain of the client.
+In order for the krb5_ccache to properly report the client principal name, the 
+client principal name is constructed by utilizing the ClientName and DomainName
+fields of the Initial TGT associated with the Kerberos LSA credential cache.
+To disable the use of the TGT info and instead simply use the "DomainName" field
+of the current ticket define one of the following registry keys depending on
+whether the change should be system global or just for the current user.
+
+   HKLM\Software\MIT\Kerberos5\
+      PreserveInitialTicketIdentity = 0x0 (DWORD)
+
+   HKCU\Software\MIT\Kerberos5\
+      PreserveInitialTicketIdentity = 0x0 (DWORD)
+
+GSSAPI Sample Client:
+---------------------
+
+The GSS API Sample Client provided in this distribution is compatible with the
+gss-server application built on Unix/Linux systems.  This client is not compatible
+with the Platform SDK/Samples/Security/SSPI/GSS/ samples which Microsoft has been
+shipping as of January 2004.  Revised versions of these samples are available upon 
+request to krbdev@mit.edu.  Microsoft is committed to distribute revised samples
+which are compatible with the MIT distributed tools in a future SDK and via MSDN.
+
+Kerberos 4 Library Support:
+---------------------------
+
+The krb4_32.dll that is built (but not installed) is not supported.
+If you need Kerberos 4, you can use the krbv4w32.dll that MIT
+distributes as part of the MIT Kerberos for Windows distribution.
+
+
+More Information:
+----------------
+
+For more information, please read the Kerberos 5 documentation in
+the doc directory of the distribution.
diff --git a/mechglue/src/windows/ccapi/ChangeLog b/mechglue/src/windows/ccapi/ChangeLog
new file mode 100644
index 000000000..10aa5bb96
--- /dev/null
+++ b/mechglue/src/windows/ccapi/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27      Jeffrey Altman <jaltman@mit.edu>
+
+ * src/windows/ccapi directory created to store the CCAPI Windows 
+   executables
diff --git a/mechglue/src/windows/ccapi/server/ChangeLog b/mechglue/src/windows/ccapi/server/ChangeLog
new file mode 100644
index 000000000..20db85e91
--- /dev/null
+++ b/mechglue/src/windows/ccapi/server/ChangeLog
@@ -0,0 +1,5 @@
+2004-10-27      Jeffrey Altman <jaltman@mit.edu>
+
+ * src/windows/ccapi/server directory created to store the CCAPI Windows 
+   Server executable
+
diff --git a/mechglue/src/windows/cns/.Sanitize b/mechglue/src/windows/cns/.Sanitize
new file mode 100644
index 000000000..a9f9a8ad5
--- /dev/null
+++ b/mechglue/src/windows/cns/.Sanitize
@@ -0,0 +1,57 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+changelo
+clock00.ico
+clock05.ico
+clock10.ico
+clock15.ico
+clock20.ico
+clock25.ico
+clock30.ico
+clock35.ico
+clock40.ico
+clock45.ico
+clock50.ico
+clock55.ico
+clock60.ico
+clockexp.ico
+clocktkt.ico
+cns.c
+cns.def
+cns.h
+cns.ico
+cns.rc
+kpasswd.c
+krbini.h
+makefile
+tktlist.c
+tktlist.h
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/windows/cns/ChangeLog b/mechglue/src/windows/cns/ChangeLog
new file mode 100644
index 000000000..d32fd8ac3
--- /dev/null
+++ b/mechglue/src/windows/cns/ChangeLog
@@ -0,0 +1,313 @@
+2005-03-15  Jeffrey Altman <jaltman@mit.edu>
+
+        * tktlist.c: do not mix pointers to long and time_t 
+
+2004-09-30  Jeffrey Altman <jaltman@mit.edu>
+
+        * Makefile.in: add $(BUILDTOP) to include path for patchlevel.h
+
+2004-01-30  Jeffrey Altman <jaltman@mit.edu>
+
+    * options.c, cnsres5.rc, cns.h, cns_reg.c cns_reg.h, cns.c:
+      Add checkbox for requesting "no addresses" if it is not
+      specified in the krb5.ini file.
+
+2003-02-25  Tom Yu  <tlyu@mit.edu>
+
+	* kpasswd.c (k5_change_password): Don't pass a NULL pointer to
+	sprintf().
+
+2002-07-12  Ken Raeburn  <raeburn@mit.edu>
+
+	* cns.h: Don't define DEFINE_SOCKADDR.
+
+2002-06-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SYSLIBS): Use ws2_32.lib instead of wsock32.lib.
+
+2002-06-11  Danilo Almeida  <dalmeida@mit.edu>
+
+	* cns.c: Do not use krb_get_notification_message() or
+	krb5_get_notification_message().
+	[pullup from 1-2-2-branch]
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* cns.c: Don't declare pointers or functions FAR any more.
+
+2000-05-08  Ken Raeburn  <raeburn@mit.edu>
+	    Nalin Dahyabhai  <nalin@redhat.com>
+	
+	* cns.c (kwin_push_login): Don't overflow buffer "fullname".
+	(kwin_command): Don't overflow buffer "copyright".
+	* cns_reg.c (cns_load_registry): Don't overflow buffer
+	"cns_res.def_confname".
+	* tktlist.c (ticket_init_list): Don't overflow buffer "buf".
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Windows fix for updated win-pre.in.
+
+1999-08-26  Danilo Almeida  <dalmeida@mit.edu>
+
+	* cns_reg.c (cns_load_registry, cns_save_registry): Honor setting
+	in cns_res.cc_override.
+
+Mon May 17 19:55:08 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add included version resouce script to 
+		resource file dependency.
+
+Mon May 17 14:19:30 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove win16 stuff.  Fix resource dependencies.
+		Link resource file directly instead of explicitly
+		converting it to an object file.
+
+Mon May 10 15:27:57 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Tue Jan  5 01:38:18 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* cns.c (position_dialog): If the registry position for the window
+		is all zeros, then default to centering the window in the
+		correct place.
+
+1998-05-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Folded in enhancements from Cygnus's Kerbnet-1.2 (plus our
+		changes made since Cygnus's last snapshot).  See
+		ChangeLog from Cygnus (included below) for more details.
+
+---------------------- Begin of ChangeLog from Cygnus
+
+Fri Mar 28 15:12:28 1997  Michael Graff  <explorer@cygnus.com>
+
+	* Makefile.in, cns.c, options.c: use the registry now, not an ini file.
+
+	* cns_reg.c, cns_reg.h: registry functions.
+
+Wed Mar 12 17:32:59 1997  Michael Graff  <explorer@cygnus.com>
+
+	* cns.h, passwd.c, kpasswd.c: use krb5_change_password() rather
+	than rolling our own.
+
+	* cnsres5.rc: remove forced uppercase realm name
+
+Wed Mar  5 19:13:31 1997  Michael Graff  <explorer@cygnus.com>
+
+	* cns.c: Start to use init creds stuff.
+
+Mon Nov  4 21:46:52 1996  Michael Graff  <explorer@cygnus.com>
+
+	* cns.c: update name from Kerb*Net to KerbNet
+
+	* cns.h: add length to extern character array to give the compiler
+	more of a hint.
+
+	* kpasswd.c: remove two unused variables.
+
+	* tktlist.c: Pull definition of MAX_K_NAME_SZ from cns.h rather
+	than having a local definition.
+
+Fri Aug  9 03:41:52 1996  Michael Graff  <explorer@cygnus.com>
+
+	* Makefile.in: rename executable to kerbnet.exe
+
+	* cns.def: rename to kerbnet.def
+
+Wed Aug  7 14:25:34 1996  Michael Graff  <explorer@cygnus.com>
+
+	* Makefile.in: Build kerbnet, not cns.exe
+	
+	* cns.c:
+	* cns.h:
+	* cnsres5.rc:
+	* krbini.h:  Help file is kerbnet.hlp, program name is kerb*net.
+
+	* cns.def: rename to kerbnet.def.
+
+Sat Aug 3 13:58:20 1996  Jeff Bigler  <jcb@cygnus.com>
+
+	* cns-help.hpj, cns-help.doc, cns-help.hlp:  added help files.
+	The cns-help.hpj is a RoboHelp help project.  RoboHelp requires
+	cns-help.doc, which is a Microsoft Word document, and it creates
+	cns-help.hlp, which is the actual help file.
+
+	* Makefile.in:  added line to install section to install help
+	file.
+
+Thu Jul 25 13:52:04 1996    <explorer@cygnus.com>
+
+	* options.c (opts_command): Display a warning message when changing
+	the location of the krb.conf file, since the KRB5 libraries
+	will have opened it and tucked it away in krb5_context->profile,
+	which we as a client don't have access to.
+
+Wed Aug  7 18:03:16 1996  Jeff Bigler  <jcb@viola.cygnus.com>
+
+	* kerbnet.hpj:  new help project (RoboHelp)
+	* kerbnet.doc:  help file (Microsoft Word document)
+	* kerbnet.hlp:  new help file (Windows help file)
+
+Wed Jul 24 06:12:24 1996  Michael Graff  <explorer@cygnus.com>
+
+	* Makefile.in: Build cnsres[45].rc into executable, depending on
+	if we're compiling for V4 or V5.
+
+	* cns.rc: remove, no longer needed. cnsres[45].rc replace this,
+	and allow GUI editors for editing the .rc files.
+
+	* kpasswd.c: make this work for V5
+	
+	* options.c:
+	* cns.c:
+	* cnsres5.rc:
+	* krbini.h:  Add forwardable option to options menu
+
+Tue Jul 16 12:42:48 1996  Michael Graff  <explorer@cygnus.com>
+
+	* options.c:
+	* password.c:  Split parts of cns.c into these files.  Each deals
+	with the respective dialogs.
+
+	* debug.c:
+	* heap.c:  Added to aid in debugging.
+
+Wed Jul 10 18:01:03 1996  Michael Graff  <explorer@cygnus.com>
+
+	* cns.c: Remove the quick hacks mentioned below.
+
+Thu Jul 25 13:52:04 1996    <explorer@lenin.cygnus.com>
+
+	* options.c (opts_command): Display a warning message when changing
+	the location of the krb.conf file, since the KRB5 libraries
+	will have opened it and tucked it away in krb5_context->profile,
+	which we as a client don't have access to.
+
+Fri Jun 28 19:29:14 1996  Michael Graff  <explorer@cygnus.com>
+
+	* cns.c: Really quick hacks to disable some features that just
+	plain don't work correctly.  The "cns" client has some flavor of
+	memory problems (malloc/free) that needs to be tracked down.
+
+	* cnsres5.rc: reload this using a dialog editor.  Add clickbox
+	for "ticket options" of "forwardable"
+
+Wed Jun 26 14:58:23 1996  Michael Graff  <explorer@cygnus.com>
+
+	* cns.h kpasswd.c:  formatting change, including changing
+ 	// to /* */
+
+	* Makefile.in: update some of the WIN32 entries for debugging.
+	Also make resouce.obj only a dependancy for WIN32 builds.
+
+	* cns.c tktlist.h tktlist.c:  Rewrite to use the message functions
+	from <windowsx.h>, included in VC 2.0 and above.  This makes most
+ 	of the details of 16- vs 32-bit hidden to the code.  (Disgusting
+	magic happens in <windowsx.h>)
+
+Tue Jun 25 13:57:59 1996  Michael Graff  <explorer@cygnus.com>
+
+	* Makefile.in: Fix to work for WIN32 native compiles.  Many
+	changes; some should be put into common files (win-post.in or
+	windows.in?)
+
+---------------------- End of ChangeLog from Cygnus
+
+Wed Jan 10 23:16:41 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* cns.rc: Add an #ifdef for enabling lower case realm (for use
+		with DCE).
+
+	* cns.c (kwin_command): When obtaining tickets, we make them
+		forwardable by default.  XXX This should really a
+		configurable option in the UI.
+
+Sat Jun 10 23:08:57 1995  Tom Yu  (tlyu@dragons-lair)
+
+	* kpasswd.c: krb5_auth_context redefinitions
+
+
+Mon Jun 5 14:19:51 EDT 1995	Paul Park	(pjpark@mit.edu)
+	* kpasswd.c : Use new krb5_adm_connect() calling sequence.
+
+Fri Jun 2 11:45:23 1995 Keith Vetter (keithv@fusion.com)
+
+	* makefile: cleaned up and made consistent with telnet's makefile.
+
+Tue May 30 17:28:04 1995 Keith Vetter (keithv@fusion.com)
+
+	* kpasswd.c: new file for k5 password changing.
+	* makefile: added new file to obj list.
+	* cns.c: added call to kpasswd stuff.
+	* cns.h: added prototype for kpasswd stuff.
+
+Thu Apr 27 11:46:42 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.c, cns.rc, krbini.h: K5 no longer has conf and realms files
+	   but one generic config file. Changed options menu to so we can
+	   specify where it lives.
+
+Thu Apr 20 12:17:34 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.c, tktlist.c, krbini.h: Fixed up #include so it
+	   it only relies on krb5.h. We now include winsock 
+	   ourselves and we needed to pull one constant out of
+	   k5-config.h (INI_KRB_CCACHE).
+
+Tue Apr 18 16:19:07 1995 Keith Vetter (keithv@fusion.com)
+
+	* makefile: better compile flags.
+
+Mon Apr 17 18:01:14 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.rc, tktlist.c: better spacing for ticket info.
+
+Thu Apr 13 16:19:01 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.c: Added better error message for incorrect password.
+        * tktlist.c: flag string gets displayed within parentheses.
+
+Fri Apr 7 15:03:10 1995 Keith Vetter (keithv@fusion.com)
+
+        * cns.c, cns.h, cns.rc: added option dialog widget allowing user
+           to specify where the ccache lives. Also, default name and realm
+           is now pulled from the ccache everytime you select one.
+	* cns.c: fixed memory leak in k5_dest_tkt.
+
+Wed Apr 5 16:01:16 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.h, cns.rc, cns.c: GUI changes: re-order and resize
+           edit boxes, add hidden button for better CR handling.
+        * cns.c: used krb5_us_timeofday instead of krb5_timeofday
+           for timezone/clock skew fix (not tested by tytso yet).
+        * cns.c: added password changing stub with correct interface.
+        * cns.def: changed kwin to cns as the name of the program.
+
+Fri Mar 31 16:47:18 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.c: realms file was not getting saved properly.
+
+Thu Mar 30 16:11:27 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.h, cns.c, tktlist.c: improved error handling for a bad cache.
+        * cns.rc: conditionally removed more instance stuff.
+
+Tue Mar 28 21:52:01 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.rc, cns.h, cns.c: removed instance edit box for K5.
+        * makefile: RFLAGS need version k4 or k5 set.
+        * tktlist.c: also displays ticket flags.
+
+Mon Mar 27 20:31:04 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.c. cns.rc: removed debugging menu item
+        * cns.c: fixed up parsing and unparsing of user name
+        * makefile: removed some configuration crud
+        
+
+Wed Mar 22 16:27:48 1995 Keith Vetter (keithv@fusion.com)
+
+	* cns.c: added some error checking code to catch missing realms files
diff --git a/mechglue/src/windows/cns/Makefile.in b/mechglue/src/windows/cns/Makefile.in
new file mode 100644
index 000000000..7ea2def12
--- /dev/null
+++ b/mechglue/src/windows/cns/Makefile.in
@@ -0,0 +1,75 @@
+# Makefile for the Kerberos for Windows ticket manager
+# Works for both k4 and k5 releases.
+#
+NAME 	 = krb5
+OBJS 	 = $(OUTPRE)cns.obj $(OUTPRE)tktlist.obj $(OUTPRE)password.obj $(OUTPRE)options.obj
+
+##### Options
+# Set NODEBUG if building release instead of debug
+!IF ! defined(KVERSION)
+KVERSION = 5
+!endif
+KRB 	 = KRB$(KVERSION)
+
+!if $(KVERSION) == 4
+BUILDTOP = ..
+LIBDIR 	 = $(BUILDTOP)\lib\krb
+KLIB 	 = $(LIBDIR)\kerberos.lib 
+RESFILE  = $(OUTPRE)cnsres4.res
+XOBJS    = $(RESFILE)
+LOCALINCLUDES = /I$(BUILDTOP) /I$(BUILDTOP)\include
+!endif
+
+!if $(KVERSION) == 5
+BUILDTOP =..\..
+LIBDIR	 = $(BUILDTOP)\lib
+RESFILE  = $(OUTPRE)cnsres5.res
+XOBJS    = $(RESFILE) $(OUTPRE)kpasswd.obj $(OUTPRE)cns_reg.obj
+LOCALINCLUDES = /I$(BUILDTOP) /I$(BUILDTOP)\include /I$(BUILDTOP)\include\krb5
+!endif
+
+##### C Compiler
+#CC 	 = cl
+!ifdef NODEBUG
+DEFINES  = /D$(KRB)=1
+!else
+DEFINES  = /D$(KRB)=1 /DDEBUG
+!endif
+
+##### RC Compiler
+#RC 	 = rc
+RFLAGS 	 = /D$(KRB)=1 $(LOCALINCLUDES)
+RCFLAGS  = $(RFLAGS) -DKRB5_APP
+
+##### CVSRES -- .res -> .obj converter
+CVTRES = cvtres
+
+##### Linker
+LINK 	 = link
+LIBS 	 = $(KLIB) $(CLIB) $(WLIB) ../lib/$(OUTPRE)libwin.lib
+SYSLIBS = kernel32.lib ws2_32.lib user32.lib gdi32.lib advapi32.lib
+LFLAGS = /nologo $(LOPTS)
+
+all:: Makefile $(OUTPRE)$(NAME).exe
+
+$(OUTPRE)$(NAME).exe: $(NAME).def $(OBJS) $(XOBJS) $(LIBS)
+	$(LINK) $(LFLAGS) /map:$*.map /out:$@ $(OBJS) $(XOBJS) \
+	  $(LIBS) $(SYSLIBS)
+
+install::
+	$(CP) $(OUTPRE)$(NAME).exe $(DESTDIR)
+	$(CP) krb5.hlp $(DESTDIR)
+
+clean:: 
+	$(RM) $(OUTPRE)*.exe
+	$(RM) $(OUTPRE)*.res
+	$(RM) $(OUTPRE)*.map
+
+$(OBJS): cns.h tktlist.h
+
+$(RESFILE): cns.h ..\version.rc
+
+$(RESFILE): clock00.ico clock05.ico clock10.ico clock15.ico clock20.ico \
+	 clock25.ico clock30.ico clock35.ico clock40.ico clock45.ico \
+	 clock50.ico clock55.ico clock60.ico clockexp.ico clocktkt.ico \
+	 cns.ico
diff --git a/mechglue/src/windows/cns/clock00.ico b/mechglue/src/windows/cns/clock00.ico
new file mode 100644
index 0000000000000000000000000000000000000000..1c2e424c83feaba846167809f124ed859e27099b
GIT binary patch
literal 1086
zcmd5)%MHRX41Fm`+z=z=ggCMRY{jXn*XT6OCS2Ko6PV|wrA=u;NEPBG{yZmf;>dtQ
z2Jbg8Tryxw>pdM}?|}6J*jbEnq&O_80f}2`KUEdLiK>c*nl3^J5D_kDJ)vqIg~LLo
z{s3iz_9-uXbuyIC^%*!*B>BGO!}ko&U;Fvv!@K)F)Z5ni3(FoD2T<IB!yLjcE5<KT
zP5Ye9Z)i*;oo0@XOnIup#ufx8INt`6llR5ejnmrx_Uu${#;5A2<1_u)yZ?Fs8mJQl

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock05.ico b/mechglue/src/windows/cns/clock05.ico
new file mode 100644
index 0000000000000000000000000000000000000000..1e092832be47233d4cec5ccf11e9c98f5eae45a2
GIT binary patch
literal 1086
zcmd5)I}XAy41Fm`-4I8}gc!L1f{SpDPN>-!nad5}675Y`S(rPO@Z9u6N?@uGZlCRE
zCr%t0P>7)Q93r;}SkP)shq6+@YyvDLMr;X%DK%i+lG^uG4)8~wJ3~zuMNz;Q!-TDW
zSSudEPeP*pK(a>KtGw|z5y`sz2%IIndKmCH_VYuY4D+SGzI?6cF5aKV22Yo4z|S3T
z`}~FF41@(pAHZe|aLUr~A=dhH&fynnj3d2fjh=)&YYm6mpil<aDu6v>Yhu^nPAjp>
Z?XgGhKbTPIHuk9x>2Zv=k{aLM>j_+x5QYE%

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock10.ico b/mechglue/src/windows/cns/clock10.ico
new file mode 100644
index 0000000000000000000000000000000000000000..15e00b24af94ea279af062fb5c16dc81b395919d
GIT binary patch
literal 1086
zcmd5)%MpSw5PhICxjB}=$?<3djy7O9PHvJmumfp=R3cY9;H2>_A0ZlU==jLn-M0xF
zmRTS|j3ik?aEpNzeUdOBHW9Fx0c**TdoseD7BJ0`I`&NgaG@v~N6Qe_S{P%v;pzqF
zBqI4pO3WW1YtenmhgMpUz4j;2c&n%2*H>D3_bFXny!(~Thgwy>uJk}R2mAAE@SNwP
zx~uyO&lv~<NFTs%3UbQQ@FmXqbI#!xw5}1oWsP2hBIgW;+Q3Ez<vqYHa|iNBo`CX7
Yif5OWp0Cyn)oycReMpb2^7a4q1gNVHY5)KL

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock15.ico b/mechglue/src/windows/cns/clock15.ico
new file mode 100644
index 0000000000000000000000000000000000000000..93a52866c84a8c5b25d936448bf5fac40e4bd7db
GIT binary patch
literal 1086
zcmd5)!4ZNm5M0!mj337mcsV}pKuhvvev&q@1ezd~$kz^dY21S#M8gjqm+al`B^){C
zfCMw7=^BFD4A{`8DFb4c0INB$l^l5>6D()}(;jK!(3Aid%CdE|3}LN>F@_tiS#VAw
zl8>as`~h;0?kXQzX+i$lpFji0pq|oMF|4n&dee2FwbFrBb*O7S&~4%VJR7_e#i;J?
z@e9uxhy%zTz<vsH%Ch)JoD1ii!!Piz6}@GRUc@5j42RmlCI;0#!X<NOpgNJ_uimpu
VOU+js#%lZASRc|Ot9<=`Jpn<04U7N)

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock20.ico b/mechglue/src/windows/cns/clock20.ico
new file mode 100644
index 0000000000000000000000000000000000000000..5fd55dad65bec7c44ece1baf2569569ec591a9f6
GIT binary patch
literal 1086
zcmd5)F>b>!3_K?Vv;}^Gr=nwi&_2mi1aye?4SUD~{0ZwN?N;Om-l85Yxh`GX$P|>;
zkvxf{MS(zu9f~4{$aM!i(-s9C$}s~Dd*DU(h&Lj`6E)ys$lz<$0bJ<1XsGGJdk^Ov
z55lkzf_MZ!*%I{+q)swk<qtPjr2aXNyqWP<@zN+>qF3D5a>lC}*ZIckd~2+Z?=|o3
zFCH&8#k0YtZCCl&$0ICfU|E3b2E48#-#F8GoU&^9Cn4xL=kSXp6Un4mV<Jml2#!PT
t;4_EMn*b4Cv=`!?I1{I2KaypfXF;Y8SgM`&*7}ehS>^6G*^1qIuW#563hDp=

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock25.ico b/mechglue/src/windows/cns/clock25.ico
new file mode 100644
index 0000000000000000000000000000000000000000..fc163fa23d4967135acb93dc84874f5076de5890
GIT binary patch
literal 1086
zcmd5)I}(C05PhIC=^T$h<yd+HJrb3fv5;ItkH7&eg_B5YX-7wVOJE=w=+trH?c0~n
zCYxCxLX0F?L+lv?8*-8`pzR`HwE(s<MjVI;OM1Y#C2j1x0^pCLa751#Wm&=)!wK8|
zuvQ|1pA3on1G}`A=lxY$c^zq`#fEv&D$upBQ?0!9sjfY(bQ<U^(EffE><`aZ!TI(0
zzOJw#KMQ1ev$}tWUod-M+JLM9_MZT|ESo;WTEEZP{9+wBF?i+}#8hNoY-*xh0Tpjv
kJvzRT@5G5X6UUBaUUb7fWNRFza(82Mbx4iO^7Z$61JPd!1ONa4

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock30.ico b/mechglue/src/windows/cns/clock30.ico
new file mode 100644
index 0000000000000000000000000000000000000000..3dfd8458d2804c5ffd5d0308e5555abab1339773
GIT binary patch
literal 1086
zcmd5)I}XAy41Fy~*$_v_gc!L29EpiY3^dn(BlHsON$AQAx-~pEtx7@*3m}~M^I|)(
zBLfLiXuX8cEd^H8TGJqH5@0a{)^bMPkrT`*0qa9rI}`=LjiT_1k|xTsgte9q*KRl`
z7MV+qMEn7rNtZm&`%<2;GKPEb6VxiirVg<(Du`F6j_^LhS%hEbv!F0OdcS_G*EcrA
zzv;LChhJ#Uz&HU}18hIRoU&~E5$D1==kN=4%7a1jjsc8W&T^>9C7l&3uTJDE`Ow+N
ZPWM=R64UscKA-7RG}VXn$XmYtUw0}w2KfL0

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock35.ico b/mechglue/src/windows/cns/clock35.ico
new file mode 100644
index 0000000000000000000000000000000000000000..b508e881d648eaf8094e965adf35afc1e6dc4697
GIT binary patch
literal 1086
zcmd5)OAdlC5Phf#JL3^p8JFHbkK{@c7t(9gBX|k8h~Ux_*q!wa1z`y8)HrlLZ$9k|
z86d(0NwR>@Z2~N*lY|Co9Rc$xuo546OO7z31WZV&Z7p(u2YDV8B~27X0b>jUzCQ3?
zEHXcFiTDGu_FPljinS+=<22<tzv6KkyI5hDI)!(v=;sr=KIVP90nP?k)iYn$)1mYA
z`)sEd4~=*EHca@MXMkJ(FEn>xoPg{BY(Bx<vTXbj@AaN@`Gp!4Kqq-e2ga-`odvmK
o*VPfYl)*0VKq<aM@K^grOPqO<FLmAorumNE%^@@LmaqS>Cn}f->Hq)$

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock40.ico b/mechglue/src/windows/cns/clock40.ico
new file mode 100644
index 0000000000000000000000000000000000000000..d7e64a398494b2f9fd6bfda0ce5f8b19ea02e8eb
GIT binary patch
literal 1086
zcmd5)I}XAy41EQpY=|4s2{Cd5I1&?)7-+7MN?d?Tw0B@dbmateBRn@PZTNIT2si#b
z+i~p5K!gF}cmkoz0GLt7F%8lp0>(pNE<W;#9AQKW7@tzvp~wIpWSLi#G?C{yj4=$j
z>cBa%$o#}5;t%LhQ`5=|R$B8Mns}<TDpiZE(j~t~+$w0^=-`r$vV*1G`UxjbxO-pn
z!~1lE`N8{qt<$gdjko#M+LS{!^AHBO@&7_|2i_Bq+<@gbm|K>-f5f?P&$;|Uwep~q
ztkHr#Ys#*tJ79kX3fjjjaH1}@WcrIuttBp)v77~+@!V7U(;PA*t1Q34egEqYV}k{Q

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock45.ico b/mechglue/src/windows/cns/clock45.ico
new file mode 100644
index 0000000000000000000000000000000000000000..e35b2008dfb46e3ec83fc7051b684677430a7f89
GIT binary patch
literal 1086
zcmc(eO-{ow5QSe#rLZeU$O?7Ijuk4W;2f;5#De4+<_Nt+auT}j3GlAwvz^q5NGc>G
znAm=P<N5Q*kqWI;RVxL#E2LYns%|1bqJBcR4Lar{v*3%;Ln3+g-e+=Yw>wF@H|gO6
zWPkseaQiA9&>voU<UDe0Is*D8%?q)qVP2$~C^7SIkz3aDNxYx-YaJ_XQj2G*ZY74=
zHUTSJbzP^XX*eJgL-aKQYiKdKQU1T|dl@SE#!F)u`}28eN>@&}Gj7af@EF-U6fScD
zmFD@(?Iy&pGmrVQzl}Wm2adzkew06)yHUM16`t*_weMVVxDRx~2mN2*();6OEWh(L
Q@BfN<{j>id#9GSp1(5Foj{pDw

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock50.ico b/mechglue/src/windows/cns/clock50.ico
new file mode 100644
index 0000000000000000000000000000000000000000..b1eaa1c82952b060a1823219067081c461c56392
GIT binary patch
literal 1086
zcmd5)OK!qI41J-MyrY#^bcM*O>asVWH|Z5vVTlEqYos?Qmq<=hww!?3b^4qkOu{EC
zgzAhx&-Qri$Uue>^86V_yAkk8o#!-2?-?+D0N%_;{vc;~qy$_{Y3#nJ03K9TRFpJP
z*EO7T420$&1hdHe%w^&q(B?pGD`!|#c{azmsCemNufB_!t<uT&yzdi+E<_gzKdFco
z2@9Bi{r-1TKD}33f1URY`%b@QZ2VZiBz<wncAit*`tPB+1D6RXeu4Qdm|Ip{ek6qc
zo^$z)4l05qStEfVYsRi;Yhe0AP5WgZ@pwfa{gY+HpNwybx6G+oFu2GAwXe-#GqTG3
J7CiL7{s6@@{?q^f

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock55.ico b/mechglue/src/windows/cns/clock55.ico
new file mode 100644
index 0000000000000000000000000000000000000000..845a7b3d78f685d2b431841e2bb5e5b8b7afc2f3
GIT binary patch
literal 1086
zcmd5)OLD?641J-@XjgiKteEcTs;oNnNLkf0T@YUbZa^-PoP;$esCT$eaf0oEvI3^E
z^?8zFNf`kJCMe4nC><uioVqM&klqU5`3ZPcANiA9U`h$tkkZ?^XaQcdZBUdn(RCfH
zwG8<F!h5yIJnB;M52zVvY~>7#F}%$wE=HVW*cq2%W*bTJ9kGiT`d$_BOmQ8tNW~Hf
zb|UHb4Duv#<0PxkYH7cr@tEK2Hd_vPny1-hc=SI)a|bRHP#=NSEtp$YUoPT(zUN$i
zr9lM{CEtkPn$>r`20r#-g5^)pi*IWB-@h0e<J6k3Bo>&Fuh3s}=!|^j?*Ho-GMoLK

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clock60.ico b/mechglue/src/windows/cns/clock60.ico
new file mode 100644
index 0000000000000000000000000000000000000000..0e9d6ebd14d4696ef4fcc7220127e16f899af2c2
GIT binary patch
literal 1086
zcmd5)I}XAy41EQpY`_sZAvV~U5FCk#NDQ>+;0RozJqa@>ARFO1fhH}bLINS&`15Sn
zjw1sJdPvhTgw8!+LY<~GNb>|3_JOJR$ZK+f0VR<86ld2(0q~$GyrQIuvMiD3IRn-m
zSSuEppSVQ)0Uhu3xXKe&TJs#MxYEj~8aCR*nAuuI`G(j845_yXcqBLrSg}Fle-;1l
z!f`)sRINX|#rO3W5A`|Vfn3egzz_c~G<Tq#fb0sazQNqGti6e~^*!hE3*D6mL9#{w
qU6#A`9$23I1dEH;vmG`4i>=o#PAvIv(yKXSMppUwy}I5?dfxzVT>t|B

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clockexp.ico b/mechglue/src/windows/cns/clockexp.ico
new file mode 100644
index 0000000000000000000000000000000000000000..6a22b90b94bc5b1569fb5d467a99ab7bcb29d4ea
GIT binary patch
literal 1086
zcmc&yy-LJD5dLxsAsnc0kW^yn3&`5tgWL<GTY^H;S!x%y%A+LUYY1Xz<tY|Pv26V2
zHb2~PTqQb}nVoNTcIKO7fB*|5$pu8-7r-UYB%wpO4uG>0;7VfDTWWw)TA=VLTYuNo
z06)~VKWOQqX&Mwo!Ha(Tq3^|`@+ToNe<FtRG<DJfjVaS1l9^I#21hI~WMFs^@kY0)
z&Wz8GN>gc_Gr?n1W`^%EJ}^3Gg*4ZhFThJCu;7G4rn1F^TS?IEgoO<`OgPm#B8L%|
z>>ZMW@%1A%V=*)GiAX?)IVT+ElUmYZm<L<B#OZL)(b;VNKfsCS*ODZGA^DdN?!aLI
zatEk=wLpAK_wxmF%ksWEKiFq?&$;{}!{NbfSwMF7un6BKsNKV7?c#gomLJNkdS%z&
wvHjXqwtKDY%S~mSs%#%ucC)N(zKY%5S~-;}7kA1%cC~wctB>)W+5C_91E-}X{{R30

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/clocktkt.ico b/mechglue/src/windows/cns/clocktkt.ico
new file mode 100644
index 0000000000000000000000000000000000000000..dc4d246f4af8b968c21d4a4e646ee8b278971f02
GIT binary patch
literal 1086
zcmd5)Jqp4w7=5i`AxQNInZ(gWT)l=4;t{$DF7_yya{{;a7RAlc(Xm^6U+PZ_S`h?&
z$@}uXd@pGe0t5)5^$>zn2#h#t&4ic)K->YwGDptI09{5Ptt>uoh74dwmQ@2IQ{;J$
zG)-A>zQZ}mNH&?0@NbB04F>pJ8>@^`q_JF&Ew!?+icJn1-83yX?fnK`(@!W*v0HGt
z5p89^&;Q4-tb%-CQ$s@iTks9ML<w}x<nakPAF(cM^}O8tT4=s=K7PS<sKg_3$wRbc
q1Lw**<HKU#D`rVpOxNLIse5jh^jEuvNBk{Y-b-!gd3P7zxUUOhem?5}

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/cns-help.doc b/mechglue/src/windows/cns/cns-help.doc
new file mode 100644
index 0000000000000000000000000000000000000000..6aae7b7528d68b8c83f79200e4b3166404da42dd
GIT binary patch
literal 22528
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

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/cns-help.hlp b/mechglue/src/windows/cns/cns-help.hlp
new file mode 100644
index 0000000000000000000000000000000000000000..a9a00244d5d852052e8944c7d8eb88571904bca4
GIT binary patch
literal 11944
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

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/cns-help.hpj b/mechglue/src/windows/cns/cns-help.hpj
new file mode 100644
index 000000000..bd668b31c
--- /dev/null
+++ b/mechglue/src/windows/cns/cns-help.hpj
@@ -0,0 +1,133 @@
+;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+; Help Project File for KERBNET 
+;
+;  You may edit this file.
+;
+;  It's probably best not to change the CONTENTS= value 
+;  unless you rename the IDH_CONTENTS context string in 
+;  the KERBNET.DOC file.
+;
+
+[OPTIONS]
+; The optional ROOT= entry sets the working directory for the Help Compiler 
+; ROOT=C:\PROJECT
+
+; The optional BMROOT= entry sets forth the directories which the
+; help compiler will search for bitmaps used in the Help system.
+;
+;BMROOT=C:\ROBOHELP
+
+; The CONTENTS= tells the help Engine which topic contains the contents 
+CONTENTS=IDH_CONTENTS
+
+; Title is Displayed in the Title Bar of WINHELP.EXE
+TITLE=Kerb*Net
+
+; The BUILD= setting allows complex Help systems which require
+; different versions to use the same source.  This is similar to #ifdef's 
+; in the 'C' language.  Everything to the right of the = sign in the 
+; BUILD= statement is an EXPRESSION.  See the Help compiler 
+; documentation for more information about build expressions.
+BUILD=WINDOWS
+
+; The Warning Level is used by the Help Compiler (HC.EXE)
+; WARNING=1  - Only the most severe warnings are reported
+; WARNING=2  - Intermediate Level of warnings
+; WARNING=3  - Most stringent error reporting
+
+; The Compress option is used by the Help Compiler to make 
+; smaller, faster loading .HLP files.  However, using compression
+; increases Compile times.
+; COMPRESS=YES, ON, OFF, NO, TRUE or FALSE
+
+
+OLDKEYPHRASE=NO
+OPTCDROM=0
+NOTES=1
+REPORT=YES
+COMPRESS=12
+ERRORLOG=C:\krbhelp\KERBNET.ERR
+[BUILDTAGS]
+; The Build Tags section specifies to the Help Compiler the names
+; of all the valid build tags used in this Help project.  The [BUILDTAGS]
+; section is optional.
+WINDOWS
+
+
+[CONFIG]
+; The config section allows you to define some macros which will be
+; executed when the help system is first executed.
+;
+; The next line gives you browse buttons:
+;
+BrowseButtons()
+
+;
+; To create a glossary button which displays a list of defined terms
+; in a secondary window, remove the semi colon at the start of the next
+; line and do the same with the Glossary window in the [WINDOWS] section
+;CreateButton("Glossary_Btn","&Glossary","JI(`bubble.hlp>Gloss',`IDH_Glossary')")
+;
+ 
+
+[FILES]
+; The files section is where you specify to the Help Compiler which
+; Rich Text Format (.RTF) (your help source) files will be used in the
+; Help system.  RoboHELP generates and maintains the main .RTF 
+; file for your Help System.  If you desire to have multiple .RTF files,
+; simply add the additonal names to the [FILES] section.
+
+KERBNET.RTF
+[ALIAS]
+; The Alias  section allows you to set up aliases for context strings 
+; in your help system.  
+; 
+; Brief example:
+; 
+;    IDH_UserID = IDH_RoboGenerated_Id
+;    IDH_WMP_MenuID = IDH_RoboGenerated_Id
+;    IDH_Any = IDH_AnyOther
+
+[MAP]
+; 
+; The Map Section is where the C language #defines are translated 
+; or mapped into the Help System Context Strings.  Standard C syntax
+; can be employed.  The .HH file is meant to be #include(d) into your 
+; Windows application source code.
+; 
+
+[BITMAPS]
+; 
+; The [BITMAPS] section is where you list any Bitmaps which have
+; been placed by reference in the Help System.  See the Help compiler
+; documentation for more information about placing bitmaps.
+; 
+; The [BITMAPS] section is not really required under Windows 3.1,
+; with the advent of the BMROOT item in the [OPTIONS] section.
+; 
+;FOO1.BMP
+;FOO2.BMP
+;C:\FOO\FOO3.BMP
+;And So On
+
+[WINDOWS]
+; Windows Help can display help in one of 5 secondary windows.
+; Before using a secondary window, the window must be defined
+; in this section:
+; 
+;Gloss = "Glossary",(100,100,350,350),0,(255,255,255),(255,255,255)
+main=,,0,,
+
+[BAGGAGE]
+; 
+; The Baggage section allows the user to include files which
+; will be placed in the internal file system for WinHelp.  
+; Using files from Baggage is a little faster for CDROM, since
+; the CDROM drive table does not need to be read from disk.
+;
+; Baggage files are referred to as regular bitmaps, except
+; that you prefix the filename with '!'.
+;
+;    For Instance:
+;       {bmc !bitmap.bmp} instead of {bmc bitmap.bmp}
+;
diff --git a/mechglue/src/windows/cns/cns.c b/mechglue/src/windows/cns/cns.c
new file mode 100644
index 000000000..7a02abba7
--- /dev/null
+++ b/mechglue/src/windows/cns/cns.c
@@ -0,0 +1,2208 @@
+/*
+ * cns.c
+ *
+ * Main routine of the Kerberos user interface.  Also handles
+ * all dialog level management functions.
+ *
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#include <windows.h>
+#include <windowsx.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "cns.h"
+#include "tktlist.h"
+#include "cns_reg.h"
+
+#include "../lib/gic.h"
+
+enum {				       /* Actions after login */
+  LOGIN_AND_EXIT,
+  LOGIN_AND_MINIMIZE,
+  LOGIN_AND_RUN,
+};
+
+/*
+ * Globals
+ */
+static HICON kwin_icons[MAX_ICONS];    /* Icons depicting time */
+HFONT hfontdialog = NULL;	       /* Font in which the dialog is drawn. */
+static HFONT hfonticon = NULL;	       /* Font for icon label */
+HINSTANCE hinstance;
+static int dlgncmdshow;		       /* ncmdshow from WinMain */
+#if 0
+static UINT wm_kerberos_changed;       /* message for cache changing */
+#endif
+static int action;		       /* After login actions */
+static UINT kwin_timer_id;	       /* Timer being used for update */
+BOOL alert;		       	       /* Actions on ticket expiration */
+BOOL beep;
+static BOOL alerted;		       /* TRUE when user already alerted */
+BOOL isblocking = FALSE;	       /* TRUE when blocked in WinSock */
+static DWORD blocking_end_time;	       /* Ending count for blocking timeout */
+static FARPROC hook_instance;	       /* handle for blocking hook function */
+
+char confname[FILENAME_MAX];           /* krb5.conf (or krb.conf for krb4) */
+
+#ifdef KRB5
+char ccname[FILENAME_MAX];             /* ccache file location */
+BOOL forwardable;                      /* TRUE to get forwardable tickets */
+BOOL noaddresses;
+krb5_context k5_context;
+krb5_ccache k5_ccache;
+#endif
+
+/*
+ * Function: Called during blocking operations.  Implement a timeout
+ *	if nothing occurs within the specified time, cancel the blocking
+ *	operation.  Also permit the user to press escape in order to
+ *	cancel the blocking operation.
+ *
+ * Returns: TRUE if we got and dispatched a message, FALSE otherwise.
+ */
+BOOL CALLBACK
+blocking_hook_proc(void)
+{
+  MSG msg;
+  BOOL rc;
+
+  if (GetTickCount() > blocking_end_time) {
+    WSACancelBlockingCall();
+    return FALSE;
+  }
+
+  rc = (BOOL)PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
+  if (!rc)
+    return FALSE;
+
+  if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) {
+    WSACancelBlockingCall();
+    blocking_end_time = msg.time - 1;
+    return FALSE;
+  }
+
+  TranslateMessage(&msg);
+  DispatchMessage(&msg);
+
+  return TRUE;
+}
+
+
+/*
+ * Function: Set up a blocking hook function.
+ *
+ * Parameters:
+ *	timeout - # of seconds to block for before cancelling.
+ */
+void
+start_blocking_hook(int timeout)
+{
+  FARPROC proc;
+
+  if (isblocking)
+    return;
+
+  isblocking = TRUE;
+  blocking_end_time = GetTickCount() + (1000 * timeout);
+#ifdef _WIN32
+  proc = WSASetBlockingHook(blocking_hook_proc);
+#else
+  hook_instance = MakeProcInstance(blocking_hook_proc, hinstance);
+  proc = WSASetBlockingHook(hook_instance);
+#endif
+  assert(proc != NULL);
+}
+
+
+/*
+ * Function: End the blocking hook fuction set up above.
+ */
+void
+end_blocking_hook(void)
+{
+#ifndef _WIN32
+  FreeProcInstance(hook_instance);
+#endif
+  WSAUnhookBlockingHook();
+  isblocking = FALSE;
+}
+
+
+/*
+ * Function: Centers the specified window on the screen.
+ *
+ * Parameters:
+ *		hwnd - the window to center on the screen.
+ */
+void
+center_dialog(HWND hwnd)
+{
+  int scrwidth, scrheight;
+  int dlgwidth, dlgheight;
+  RECT r;
+  HDC hdc;
+
+  if (hwnd == NULL)
+    return;
+
+  GetWindowRect(hwnd, &r);
+  dlgwidth = r.right  - r.left;
+  dlgheight = r.bottom - r.top ;
+  hdc = GetDC(NULL);
+  scrwidth = GetDeviceCaps(hdc, HORZRES);
+  scrheight = GetDeviceCaps(hdc, VERTRES);
+  ReleaseDC(NULL, hdc);
+  r.left = (scrwidth - dlgwidth) / 2;
+  r.top  = (scrheight - dlgheight) / 2;
+  MoveWindow(hwnd, r.left, r.top, dlgwidth, dlgheight, TRUE);
+}
+
+
+/*
+ * Function: Positions the kwin dialog either to the saved location
+ * 	or the center of the screen if no saved location.
+ *
+ * Parameters:
+ *		hwnd - the window to center on the screen.
+ */
+static void
+position_dialog(HWND hwnd)
+{
+  int scrwidth, scrheight;
+  HDC hdc;
+  int x, y, cx, cy;
+
+  if (hwnd == NULL)
+    return;
+
+  hdc = GetDC(NULL);
+  scrwidth = GetDeviceCaps(hdc, HORZRES);
+  scrheight = GetDeviceCaps(hdc, VERTRES);
+  ReleaseDC(NULL, hdc);
+  x = cns_res.x;
+  y = cns_res.y;
+  cx = cns_res.cx;
+  cy = cns_res.cy;
+
+  if (x > scrwidth ||
+      y > scrheight ||
+      x + cx <= 0 ||
+      y + cy <= 0)
+    center_dialog(hwnd);
+  else
+    MoveWindow(hwnd, x, y, cx, cy, TRUE);
+}
+
+
+/*
+ * Function: Set font of all dialog items.
+ *
+ * Parameters:
+ *		hwnd - the dialog to set the font of
+ */
+void
+set_dialog_font(HWND hwnd, HFONT hfont)
+{
+  hwnd = GetWindow(hwnd, GW_CHILD);
+
+  while (hwnd != NULL) {
+    SetWindowFont(hwnd, hfont, 0);
+    hwnd = GetWindow(hwnd, GW_HWNDNEXT);
+  }
+}
+
+
+/*
+ * Function: Trim leading and trailing white space from a string.
+ *
+ * Parameters:
+ *	s - the string to trim.
+ */
+void
+trim(char *s)
+{
+  int l;
+  int i;
+
+  for (i = 0 ; s[i] ; i++)
+    if (s[i] != ' ' && s[i] != '\t')
+      break;
+
+  l = strlen(&s[i]);
+  memmove(s, &s[i], l + 1);
+
+  for (l--; l >= 0; l--) {
+    if (s[l] != ' ' && s[l] != '\t')
+      break;
+  }
+  s[l + 1] = 0;
+}
+
+
+/*
+ * Function: This routine figures out the current time epoch and
+ * returns the conversion factor.  It exists because Microloss
+ * screwed the pooch on the time() and _ftime() calls in its release
+ * 7.0 libraries.  They changed the epoch to Dec 31, 1899!
+ */
+time_t
+kwin_get_epoch(void)
+{
+  static struct tm jan_1_70 = {0, 0, 0, 1, 0, 70};
+  time_t epoch = 0;
+
+  epoch = -mktime(&jan_1_70);		/* Seconds til 1970 localtime */
+  epoch += _timezone;				/* Seconds til 1970 GMT */
+
+  return epoch;
+}
+
+
+/*
+ * Function: Save the credentials for later restoration.
+ *
+ * Parameters:
+ *	c - Returned pointer to saved credential cache.
+ *
+ *	pname - Returned as principal name of session.
+ *
+ *	pinstance - Returned as principal instance of session.
+ *
+ *	ncred - Returned number of credentials saved.
+ */
+static void
+push_credentials(CREDENTIALS **cp, char *pname, char *pinstance, int *ncred)
+{
+#ifdef KRB4
+  int i;
+  char service[ANAME_SZ];
+  char instance[INST_SZ];
+  char realm[REALM_SZ];
+  CREDENTIALS *c;
+
+  if (krb_get_tf_fullname(NULL, pname, pinstance, NULL) != KSUCCESS) {
+    pname[0] = 0;
+
+    pinstance[0] = 0;
+  }
+
+  *ncred = krb_get_num_cred();
+  if (*ncred <= 0)
+    return;
+
+  c= malloc(*ncred * sizeof(CREDENTIALS));
+  assert(c != NULL);
+  if (c == NULL) {
+    *ncred = 0;
+
+    return;
+  }
+
+  for (i = 0; i < *ncred; i++) {
+    krb_get_nth_cred(service, instance, realm, i + 1);
+    krb_get_cred(service, instance, realm, &c[i]);
+  }
+
+  *cp = c;
+#endif
+
+#ifdef KRB5     /* FIXME */
+  return;
+#endif
+}
+
+
+/*
+ * Function: Restore the saved credentials.
+ *
+ *	c - Pointer to saved credential cache.
+ *
+ *	pname - Principal name of session.
+ *
+ *	pinstance - Principal instance of session.
+ *
+ *	ncred - Number of credentials saved.
+ */
+static void
+pop_credentials(CREDENTIALS *c, char *pname, char *pinstance, int ncred)
+{
+#ifdef KRB4
+  int i;
+
+  if (pname[0])
+    in_tkt(pname, pinstance);
+  else
+    dest_tkt();
+
+  if (ncred <= 0)
+    return;
+
+  for (i = 0; i < ncred; i++) {
+    krb_save_credentials(c[i].service, c[i].instance, c[i].realm,
+			 c[i].session, c[i].lifetime, c[i].kvno,
+			 &(c[i].ticket_st),
+			 c[i].issue_date);
+  }
+
+  free(c);
+#endif
+#ifdef KRB5     /* FIXME */
+  return;
+#endif
+}
+
+
+/*
+ * Function: Save most recent login triplets for placement on the
+ *	bottom of the file menu.
+ *
+ * Parameters:
+ *	hwnd - the handle of the window containing the menu to edit.
+ *
+ *	name - A login name to save in the recent login list
+ *
+ *	instance - An instance to save in the recent login list
+ *
+ *	realm - A realm to save in the recent login list
+ */
+static void
+kwin_push_login(HWND hwnd, char *name, char *instance, char *realm)
+{
+  HMENU hmenu;
+  int i;
+  int id;
+  int ctitems;
+  char fullname[MAX_K_NAME_SZ + 3];
+  char menuitem[MAX_K_NAME_SZ + 3];
+  BOOL rc;
+
+  fullname[sizeof(fullname) - 1] = '\0';
+  strncpy(fullname, "&x ", sizeof(fullname) - 1);
+  strncat(fullname, name, sizeof(fullname) - 1 - strlen(fullname));
+  strncat(fullname, ".", sizeof(fullname) - 1 - strlen(fullname));
+  strncat(fullname, instance, sizeof(fullname) - 1 - strlen(fullname));
+  strncat(fullname, "@", sizeof(fullname) - 1 - strlen(fullname));
+  strncat(fullname, realm, sizeof(fullname) - 1 - strlen(fullname));
+
+  hmenu = GetMenu(hwnd);
+  assert(hmenu != NULL);
+
+  hmenu = GetSubMenu(hmenu, 0);
+  assert(hmenu != NULL);
+
+  ctitems = GetMenuItemCount(hmenu);
+  assert(ctitems >= FILE_MENU_ITEMS);
+
+  if (ctitems == FILE_MENU_ITEMS) {
+    rc = AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+    assert(rc);
+
+    ctitems++;
+  }
+
+  for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
+    GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
+
+    if (strcmp(&fullname[3], &menuitem[3]) == 0) {
+      rc = RemoveMenu(hmenu, i, MF_BYPOSITION);
+      assert(rc);
+
+      ctitems--;
+
+      break;
+    }
+  }
+
+  rc = InsertMenu(hmenu, FILE_MENU_ITEMS + 1, MF_BYPOSITION, 1, fullname);
+  assert(rc);
+
+  ctitems++;
+  if (ctitems - FILE_MENU_ITEMS - 1 > FILE_MENU_MAX_LOGINS) {
+    RemoveMenu(hmenu, ctitems - 1, MF_BYPOSITION);
+
+    ctitems--;
+  }
+
+  id = 0;
+  for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
+    GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
+
+    rc = RemoveMenu(hmenu, i, MF_BYPOSITION);
+    assert(rc);
+
+    menuitem[1] = '1' + id;
+    rc = InsertMenu(hmenu, i, MF_BYPOSITION, IDM_FIRST_LOGIN + id, menuitem);
+    assert(rc);
+
+    id++;
+  }
+}
+
+
+/*
+ * Function: Initialize the logins on the file menu form the KERBEROS.INI
+ *	file.
+ *
+ * Parameters:
+ *	hwnd - handle of the dialog containing the file menu.
+ */
+static void
+kwin_init_file_menu(HWND hwnd)
+{
+  HMENU hmenu;
+  int i;
+  char menuitem[MAX_K_NAME_SZ + 3];
+  int id;
+  BOOL rc;
+
+  hmenu = GetMenu(hwnd);
+  assert(hmenu != NULL);
+
+  hmenu = GetSubMenu(hmenu, 0);
+  assert(hmenu != NULL);
+
+  id = 0;
+  for (i = 0; i < FILE_MENU_MAX_LOGINS; i++) {
+    strcpy(menuitem + 3, cns_res.logins[i]);
+
+    if (!menuitem[3])
+      continue;
+
+    menuitem[0] = '&';
+    menuitem[1] = '1' + id;
+    menuitem[2] = ' ';
+
+    if (id == 0) {
+      rc = AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
+      assert(rc);
+    }
+    AppendMenu(hmenu, MF_STRING, IDM_FIRST_LOGIN + id, menuitem);
+
+    id++;
+  }
+}
+
+
+/*
+ * Function: Save the items on the file menu in the KERBEROS.INI file.
+ *
+ * Parameters:
+ *	hwnd - handle of the dialog containing the file menu.
+ */
+static void
+kwin_save_file_menu(HWND hwnd)
+{
+  HMENU hmenu;
+  int i;
+  int id;
+  int ctitems;
+  char menuitem[MAX_K_NAME_SZ + 3];
+
+  hmenu = GetMenu(hwnd);
+  assert(hmenu != NULL);
+
+  hmenu = GetSubMenu(hmenu, 0);
+  assert(hmenu != NULL);
+
+  ctitems = GetMenuItemCount(hmenu);
+  assert(ctitems >= FILE_MENU_ITEMS);
+
+  id = 0;
+  for (i = FILE_MENU_ITEMS + 1; i < ctitems; i++) {
+    GetMenuString(hmenu, i, menuitem, sizeof(menuitem), MF_BYPOSITION);
+
+    strcpy(cns_res.logins[id], menuitem + 3);
+
+    id++;
+  }
+}
+
+
+
+/*
+ * Function: Given an expiration time, choose an appropriate
+ *	icon to display.
+ *
+ * Parameters:
+ *	expiration time of expiration in time() compatible units
+ *
+ * Returns: Handle of icon to display
+ */
+HICON
+kwin_get_icon(time_t expiration)
+{
+  int ixicon;
+  time_t dt;
+
+  dt = expiration - time(NULL);
+  dt = dt / 60;			/* convert to minutes */
+  if (dt <= 0)
+    ixicon = IDI_EXPIRED - IDI_FIRST_CLOCK;
+  else if (dt > 60)
+    ixicon = IDI_TICKET - IDI_FIRST_CLOCK;
+  else
+    ixicon = (int)(dt / 5);
+
+  return kwin_icons[ixicon];
+}
+
+
+/*
+ * Function: Intialize name fields in the Kerberos dialog.
+ *
+ * Parameters:
+ *	hwnd - the window recieving the message.
+ *
+ *	fullname - the full kerberos name to initialize with
+ */
+void
+kwin_init_name(HWND hwnd, char *fullname)
+{
+  char name[ANAME_SZ];
+  char instance[INST_SZ];
+  char realm[REALM_SZ];
+  int krc;
+#ifdef KRB5
+  krb5_error_code code;
+  char *ptr;
+#endif    
+
+  if (fullname == NULL || fullname[0] == 0) {
+#ifdef KRB4
+    strcpy(name, krb_get_default_user());
+    strcpy(instance, cns_res.instance);
+    krc = krb_get_lrealm(realm, 1);
+    if (krc != KSUCCESS)
+      realm[0] = 0;
+    strcpy(realm, cns_res.realm);
+#endif /* KRB4 */
+
+#ifdef KRB5
+    strcpy(name, cns_res.name);
+    
+    *realm = '\0';
+    code = krb5_get_default_realm(k5_context, &ptr);
+    if (!code) {
+      strcpy(realm, ptr);
+      /*      free(ptr); XXX */
+    }
+    strcpy(realm, cns_res.realm);
+#endif /* KRB5 */
+
+  } else {
+#ifdef KRB4
+    kname_parse(name, instance, realm, fullname);
+    SetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance);
+#endif
+
+#ifdef KRB5
+    krc = k5_kname_parse(name, realm, fullname);
+    *instance = '\0';
+#endif
+  }
+
+  SetDlgItemText(hwnd, IDD_LOGIN_NAME, name);
+  SetDlgItemText(hwnd, IDD_LOGIN_REALM, realm);
+}
+
+
+/*
+ * Function: Set the focus to the name control if no name
+ * 	exists, the realm control if no realm exists or the
+ * 	password control.  Uses PostMessage not SetFocus.
+ *
+ * Parameters:
+ *	hwnd - the Window handle of the parent.
+ */
+void
+kwin_set_default_focus(HWND hwnd)
+{
+  char name[ANAME_SZ];
+  char realm[REALM_SZ];
+  HWND hwnditem;
+
+  GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+
+  trim(name);
+  if (strlen(name) <= 0)
+    hwnditem = GetDlgItem(hwnd, IDD_LOGIN_NAME);
+  else {
+    GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
+    trim(realm);
+
+    if (strlen(realm) <= 0)
+      hwnditem = GetDlgItem(hwnd, IDD_LOGIN_REALM);
+    else
+      hwnditem = GetDlgItem(hwnd, IDD_LOGIN_PASSWORD);
+  }
+
+  PostMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)hwnditem, MAKELONG(1, 0));
+}
+
+
+/*
+ * Function: Save the values which live in the KERBEROS.INI file.
+ *
+ * Parameters:
+ *	hwnd - the window handle of the dialog containing fields to
+ *		be saved
+ */
+static void
+kwin_save_name(HWND hwnd)
+{
+  char name[ANAME_SZ];
+  char instance[INST_SZ];
+  char realm[REALM_SZ];
+
+  GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+  trim(name);
+
+#ifdef KRB4
+  krb_set_default_user(name);
+  GetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
+  trim(instance);
+  strcpy(cns_res.instance, instance);
+#endif
+
+#ifdef KRB5
+  strcpy(cns_res.name, name);
+  *instance = '\0';
+#endif
+
+  GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
+  trim(realm);
+  strcpy(cns_res.realm, realm);
+
+  kwin_push_login(hwnd, name, instance, realm);
+}
+
+
+/*
+ * Function: Process WM_INITDIALOG messages.  Set the fonts
+ *	for all items on the dialog and populate the ticket list.
+ *	Also set the default values for user, instance and realm.
+ *
+ * Returns: TRUE if we didn't set the focus here,
+ * 	FALSE if we did.
+ */
+static BOOL
+kwin_initdialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
+{
+  LOGFONT lf;
+  HDC hdc;
+  char name[ANAME_SZ];
+
+  position_dialog(hwnd);
+  ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+  kwin_init_file_menu(hwnd);
+  kwin_init_name(hwnd, (char *)lParam);
+  hdc = GetDC(NULL);
+  assert(hdc != NULL);
+
+  memset(&lf, 0, sizeof(lf));
+  lf.lfHeight = -MulDiv(9, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+  strcpy(lf.lfFaceName, "Arial");
+  hfontdialog = CreateFontIndirect(&lf);
+  assert(hfontdialog != NULL);
+
+  if (hfontdialog == NULL) {
+    ReleaseDC(NULL, hdc);
+
+    return TRUE;
+  }
+
+  lf.lfHeight = -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+  hfonticon = CreateFontIndirect(&lf);
+  assert(hfonticon != NULL);
+
+  if (hfonticon == NULL) {
+    ReleaseDC(NULL, hdc);
+
+    return TRUE;
+  }
+
+  ReleaseDC(NULL, hdc);
+
+  set_dialog_font(hwnd, hfontdialog);
+  GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+  trim(name);
+
+  if (strlen(name) > 0)
+    SetFocus(GetDlgItem(hwnd, IDD_LOGIN_PASSWORD));
+  else
+    SetFocus(GetDlgItem(hwnd, IDD_LOGIN_NAME));
+
+  ShowWindow(hwnd, dlgncmdshow);
+
+  kwin_timer_id = SetTimer(hwnd, 1, KWIN_UPDATE_PERIOD, NULL);
+  assert(kwin_timer_id != 0);
+
+  return FALSE;
+}
+
+
+/*
+ * Function: Process WM_DESTROY messages.  Delete the font
+ *	created for use by the controls.
+ */
+static void
+kwin_destroy(HWND hwnd)
+{
+  RECT r;
+
+  ticket_destroy(GetDlgItem(hwnd, IDD_TICKET_LIST));
+
+  if (hfontdialog != NULL)
+    DeleteObject(hfontdialog);
+
+  if (hfonticon != NULL)
+    DeleteObject(hfonticon);
+
+  kwin_save_file_menu(hwnd);
+  GetWindowRect(hwnd, &r);
+  cns_res.x = r.left;
+  cns_res.y = r.top;
+  cns_res.cx = r.right - r.left;
+  cns_res.cy = r.bottom - r.top;
+
+  KillTimer(hwnd, kwin_timer_id);
+}
+
+
+/*
+ * Function: Retrievs item WindowRect in hwnd client
+ *	coordiate system.
+ *
+ * Parameters:
+ *	hwnditem - the item to retrieve
+ *
+ *	item - dialog in which into which to translate
+ *
+ *	r - rectangle returned
+ */
+static void
+windowrect(HWND hwnditem, HWND hwnd, RECT *r)
+{
+  GetWindowRect(hwnditem, r);
+  ScreenToClient(hwnd, (LPPOINT)&(r->left));
+  ScreenToClient(hwnd, (LPPOINT)&(r->right));
+}
+
+
+/*
+ * Function: Process WM_SIZE messages.  Resize the
+ *	list and position the buttons attractively.
+ */
+static void
+kwin_size(HWND hwnd, UINT state, int cxdlg, int cydlg)
+{
+#define listgap 8
+  RECT r;
+  RECT rdlg;
+  int hmargin, vmargin;
+  HWND hwnditem;
+  int cx, cy;
+  int i;
+  int titlebottom;
+  int editbottom;
+  int listbottom;
+  int gap;
+  int left;
+  int titleleft[IDD_MAX_TITLE - IDD_MIN_TITLE + 1];
+
+  if (state == SIZE_MINIMIZED)
+    return;
+
+  GetClientRect(hwnd, &rdlg);
+
+  /*
+   * The ticket list title
+   */
+  hwnditem = GetDlgItem(hwnd, IDD_TICKET_LIST_TITLE);
+
+  if (hwnditem == NULL)
+    return;
+
+  windowrect(hwnditem, hwnd, &r);
+  hmargin = r.left;
+  vmargin = r.top;
+  cx = cxdlg - 2 * hmargin;
+  cy = r.bottom - r.top;
+  MoveWindow(hwnditem, r.left, r.top, cx, cy, TRUE);
+
+  /*
+   * The buttons
+   */
+  cx = 0;
+
+  for (i = IDD_MIN_BUTTON; i <= IDD_MAX_BUTTON; i++) {
+    hwnditem = GetDlgItem(hwnd, i);
+    windowrect(hwnditem, hwnd, &r);
+    if (i == IDD_MIN_BUTTON)
+      hmargin = r.left;
+
+    cx += r.right - r.left;
+  }
+
+  gap = (cxdlg - 2 * hmargin - cx) / (IDD_MAX_BUTTON - IDD_MIN_BUTTON);
+  left = hmargin;
+  for (i = IDD_MIN_BUTTON; i <= IDD_MAX_BUTTON; i++) {
+    hwnditem = GetDlgItem(hwnd, i);
+    windowrect(hwnditem, hwnd, &r);
+    editbottom = -r.top;
+    cx = r.right - r.left;
+    cy = r.bottom - r.top;
+    r.top = rdlg.bottom - vmargin - cy;
+    MoveWindow(hwnditem, left, r.top, cx, cy, TRUE);
+
+    left += cx + gap;
+  }
+
+  /*
+   * Edit fields: stretch boxes, keeping the gap between boxes equal to
+   * what it was on entry.
+   */
+  editbottom += r.top;
+
+  hwnditem = GetDlgItem(hwnd, IDD_MIN_EDIT);
+  windowrect(hwnditem, hwnd, &r);
+  gap = r.right;
+  hmargin = r.left;
+  editbottom += r.bottom;
+  titlebottom = -r.top;
+
+  hwnditem = GetDlgItem(hwnd, IDD_MIN_EDIT + 1);
+  windowrect(hwnditem, hwnd, &r);
+  gap = r.left - gap;
+
+  cx = cxdlg - 2 * hmargin - (IDD_MAX_EDIT - IDD_MIN_EDIT) * gap;
+  cx = cx / (IDD_MAX_EDIT - IDD_MIN_EDIT + 1);
+  left = hmargin;
+
+  for (i = IDD_MIN_EDIT; i <= IDD_MAX_EDIT; i++) {
+    hwnditem = GetDlgItem(hwnd, i);
+    windowrect(hwnditem, hwnd, &r);
+    cy = r.bottom - r.top;
+    r.top = editbottom - cy;
+    MoveWindow(hwnditem, left, r.top, cx, cy, TRUE);
+    titleleft[i-IDD_MIN_EDIT] = left;
+
+    left += cx + gap;
+  }
+
+  /*
+   * Edit field titles
+   */
+  titlebottom += r.top;
+  windowrect(GetDlgItem(hwnd, IDD_MIN_TITLE), hwnd, &r);
+  titlebottom += r.bottom;
+  listbottom = -r.top;
+
+  for (i = IDD_MIN_TITLE; i <= IDD_MAX_TITLE; i++) {
+    hwnditem = GetDlgItem(hwnd, i);
+    windowrect(hwnditem, hwnd, &r);
+    cx = r.right - r.left;
+    cy = r.bottom - r.top;
+    r.top = titlebottom - cy;
+    MoveWindow(hwnditem, titleleft[i-IDD_MIN_TITLE], r.top, cx, cy, TRUE);
+  }
+
+  /*
+   * The list
+   */
+  listbottom = r.top - listgap;
+  hwnditem = GetDlgItem(hwnd, IDD_TICKET_LIST);
+  windowrect(hwnditem, hwnd, &r);
+  hmargin = r.left;
+  cx = cxdlg - 2 * hmargin;
+  cy = listbottom - r.top;
+  MoveWindow(hwnditem, r.left, r.top, cx, cy, TRUE);
+}
+
+
+/*
+ * Function: Process WM_GETMINMAXINFO messages
+ */
+static void
+kwin_getminmaxinfo(HWND hwnd, LPMINMAXINFO lpmmi)
+{
+  lpmmi->ptMinTrackSize.x =
+    (KWIN_MIN_WIDTH * LOWORD(GetDialogBaseUnits())) / 4;
+
+  lpmmi->ptMinTrackSize.y =
+    (KWIN_MIN_HEIGHT * HIWORD(GetDialogBaseUnits())) / 8;
+}
+
+
+/*
+ * Function: Process WM_TIMER messages
+ */
+static void
+kwin_timer(HWND hwnd, UINT timer_id)
+{
+  HWND hwndfocus;
+  time_t t;
+  time_t expiration;
+  BOOL expired;
+#ifdef KRB4
+  CREDENTIALS c;
+  int ncred;
+  int i;
+  char service[ANAME_SZ];
+  char instance[INST_SZ];
+  char realm[REALM_SZ];
+#endif
+#ifdef KRB5
+  krb5_error_code code;
+  krb5_cc_cursor cursor;
+  krb5_creds cred;
+  int n;
+  char *s;
+#endif
+
+  if (timer_id != 1) {
+    FORWARD_WM_TIMER(hwnd, timer_id, DefDlgProc);
+    return;
+  }
+
+  expired = FALSE;
+  ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+
+  if (alerted) {
+    if (IsIconic(hwnd))
+      InvalidateRect(hwnd, NULL, TRUE);
+
+    return;
+  }
+
+#ifdef KRB4
+  ncred = krb_get_num_cred();
+  for (i = 1; i <= ncred; i++) {
+    krb_get_nth_cred(service, instance, realm, i);
+
+    if (_stricmp(service, "krbtgt") == 0) {
+      /* Warn if ticket will expire w/i TIME_BUFFER seconds */
+      krb_get_cred(service, instance, realm, &c);
+      expiration = c.issue_date + (long)c.lifetime * 5L * 60L;
+      t = TIME_BUFFER + time(NULL);
+
+      if (t >= expiration) {
+	expired = TRUE;
+	/* Don't alert because of stale tickets */
+	if (t >= expiration + KWIN_UPDATE_PERIOD / 1000) {
+	  alerted = TRUE;
+
+	  if (IsIconic(hwnd))
+	    InvalidateRect(hwnd, NULL, TRUE);
+	  return;
+	}
+	break;
+      }
+    }
+  }
+#endif
+
+#ifdef KRB5
+  code = krb5_cc_start_seq_get(k5_context, k5_ccache, &cursor);
+
+  while (code == 0) {
+    code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &cred);
+    if (code)
+      break;
+    n = krb5_princ_component(k5_context, cred.server, 0)->length;
+    s = krb5_princ_component(k5_context, cred.server, 0)->data;
+    if (n != KRB5_TGS_NAME_SIZE)
+      continue;
+    if (memcmp(KRB5_TGS_NAME, s, KRB5_TGS_NAME_SIZE))
+      continue;
+
+    /* Warn if ticket will expire w/i TIME_BUFFER seconds */
+    expiration = cred.times.endtime;
+    t = TIME_BUFFER + time(NULL);
+
+    if (t >= expiration) {
+      expired = TRUE;
+      /* Don't alert because of stale tickets */
+      if (t >= expiration + KWIN_UPDATE_PERIOD / 1000) {
+	alerted = TRUE;
+
+	if (IsIconic(hwnd))
+	  InvalidateRect(hwnd, NULL, TRUE);
+	return;
+      }
+      break;
+    }
+  }
+  if (code == 0 || code == KRB5_CC_END)
+    krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
+    
+#endif
+
+  if (!expired) {
+    if (IsIconic(hwnd))
+      InvalidateRect(hwnd, NULL, TRUE);
+
+    return;
+  }
+
+  alerted = TRUE;
+
+  if (beep)
+    MessageBeep(MB_ICONEXCLAMATION);
+
+  if (alert) {
+    if (IsIconic(hwnd)) {
+      hwndfocus = GetFocus();
+      ShowWindow(hwnd, SW_RESTORE);
+      SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+		   SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
+      SetFocus(hwndfocus);
+    }
+
+    SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+		 SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
+
+    return;
+  }
+
+  if (IsIconic(hwnd))
+    InvalidateRect(hwnd, NULL, TRUE);
+}
+
+/*
+ * Function: Process WM_COMMAND messages
+ */
+static void
+kwin_command(HWND hwnd, int cid, HWND hwndCtl, UINT codeNotify)
+{
+  char                      name[ANAME_SZ];
+  char                      realm[REALM_SZ];
+  char                      password[MAX_KPW_LEN];
+  HCURSOR                   hcursor;
+  BOOL                      blogin;
+  HMENU                     hmenu;
+  char                      menuitem[MAX_K_NAME_SZ + 3];
+  char                      copyright[128];
+  int                       id;
+#ifdef KRB4
+  char                      instance[INST_SZ];
+  int                       lifetime;
+  int                       krc;
+#endif
+#ifdef KRB5
+  long                      lifetime;
+  krb5_error_code           code;
+  krb5_principal            principal;
+  krb5_creds                creds;
+  krb5_get_init_creds_opt   opts;
+  gic_data                  gd;
+#endif
+
+#ifdef KRB4
+  EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), krb_get_num_cred() > 0);
+#endif
+
+#ifdef KRB5
+  EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), k5_get_num_cred(1) > 0);
+#endif
+
+  GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+  trim(name);
+  blogin = strlen(name) > 0;
+
+  if (blogin) {
+    GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
+    trim(realm);
+    blogin = strlen(realm) > 0;
+  }
+
+  if (blogin) {
+    GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password));
+    blogin = strlen(password) > 0;
+  }
+
+  EnableWindow(GetDlgItem(hwnd, IDD_LOGIN), blogin);
+  id = (blogin) ? IDD_LOGIN : IDD_PASSWORD_CR2;
+  SendMessage(hwnd, DM_SETDEFID, id, 0);
+
+  if (codeNotify != BN_CLICKED && codeNotify != 0 && codeNotify != 1)
+    return; /* FALSE */
+
+  /*
+   * Check to see if this item is in a list of the ``recent hosts'' sort
+   * of list, under the FILE menu.
+   */
+  if (cid >= IDM_FIRST_LOGIN && cid < IDM_FIRST_LOGIN + FILE_MENU_MAX_LOGINS) {
+    hmenu = GetMenu(hwnd);
+    assert(hmenu != NULL);
+
+    hmenu = GetSubMenu(hmenu, 0);
+    assert(hmenu != NULL);
+
+    if (!GetMenuString(hmenu, cid, menuitem, sizeof(menuitem), MF_BYCOMMAND))
+      return; /* TRUE */
+
+    if (menuitem[0])
+      kwin_init_name(hwnd, &menuitem[3]);
+
+    return; /* TRUE */
+  }
+
+  switch (cid) {
+  case IDM_EXIT:
+    if (isblocking)
+      WSACancelBlockingCall();
+    WinHelp(hwnd, KERBEROS_HLP, HELP_QUIT, 0);
+    PostQuitMessage(0);
+
+    return; /* TRUE */
+
+  case IDD_PASSWORD_CR2:                      /* Make CR == TAB */
+    id = GetDlgCtrlID(GetFocus());
+    assert(id != 0);
+
+    if (id == IDD_MAX_EDIT)
+      PostMessage(hwnd, WM_NEXTDLGCTL,
+		  (WPARAM)GetDlgItem(hwnd, IDD_MIN_EDIT), MAKELONG(1, 0));
+    else
+      PostMessage(hwnd, WM_NEXTDLGCTL, 0, 0);
+
+    return; /* TRUE */
+
+  case IDD_LOGIN:
+    if (isblocking)
+      return; /* TRUE */
+
+    GetDlgItemText(hwnd, IDD_LOGIN_NAME, name, sizeof(name));
+    trim(name);
+    GetDlgItemText(hwnd, IDD_LOGIN_REALM, realm, sizeof(realm));
+    trim(realm);
+    GetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, password, sizeof(password));
+    SetDlgItemText(hwnd, IDD_LOGIN_PASSWORD, "");  /* nuke the password */
+    trim(password);
+
+#ifdef KRB4
+    GetDlgItemText(hwnd, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
+    trim(instance);
+#endif
+
+    hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+    lifetime = cns_res.lifetime;
+    start_blocking_hook(BLOCK_MAX_SEC);
+
+#ifdef KRB4
+    lifetime = (lifetime + 4) / 5;
+    krc = krb_get_pw_in_tkt(name, instance, realm, "krbtgt", realm,
+			    lifetime, password);
+#endif
+
+#ifdef KRB5
+    principal = NULL;
+    
+    /*
+     * convert the name + realm into a krb5 principal string and parse it into a principal
+     */
+    sprintf(menuitem, "%s@%s", name, realm);
+    code = krb5_parse_name(k5_context, menuitem, &principal);
+    if (code)
+      goto errorpoint;
+    
+    /*
+     * set the various ticket options.  First, initialize the structure, then set the ticket
+     * to be forwardable if desired, and set the lifetime.
+     */
+    krb5_get_init_creds_opt_init(&opts);
+    krb5_get_init_creds_opt_set_forwardable(&opts, forwardable);
+    krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime * 60);
+    if (noaddresses) {
+		krb5_get_init_creds_opt_set_address_list(&opts, NULL);
+ 	}    
+
+    /*
+     * get the initial creds using the password and the options we set above
+     */
+    gd.hinstance = hinstance;
+    gd.hwnd = hwnd;
+    gd.id = ID_VARDLG;
+    code = krb5_get_init_creds_password(k5_context, &creds, principal, password, 
+					gic_prompter, &gd, 0, NULL, &opts);
+    if (code)
+      goto errorpoint;
+    
+    /*
+     * initialize the credential cache
+     */
+    code = krb5_cc_initialize(k5_context, k5_ccache, principal);
+    if (code)
+      goto errorpoint;
+    
+    /*
+     * insert the principal into the cache
+     */
+    code = krb5_cc_store_cred(k5_context, k5_ccache, &creds);
+    
+  errorpoint:
+    
+    if (principal)
+      krb5_free_principal(k5_context, principal);
+
+    end_blocking_hook();
+    SetCursor(hcursor);
+    kwin_set_default_focus(hwnd);
+    
+    if (code) {
+      if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+	MessageBox(hwnd, "Password incorrect", NULL, 
+		   MB_OK | MB_ICONEXCLAMATION);
+      else 
+	com_err(NULL, code, "while logging in");
+    }
+#endif /* KRB5 */
+    
+#ifdef KRB4
+    if (krc != KSUCCESS) {
+      MessageBox(hwnd, krb_get_err_text(krc),	"",
+		 MB_OK | MB_ICONEXCLAMATION);
+
+      return; /* TRUE */
+    }
+#endif
+
+    kwin_save_name(hwnd);
+    alerted = FALSE;
+
+    switch (action) {
+    case LOGIN_AND_EXIT:
+      SendMessage(hwnd, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_EXIT, 0, 0));
+      break;
+
+    case LOGIN_AND_MINIMIZE:
+      ShowWindow(hwnd, SW_MINIMIZE);
+      break;
+    }
+
+    return; /* TRUE */
+
+  case IDD_TICKET_DELETE:
+    if (isblocking)
+      return; /* TRUE */
+
+#ifdef KRB4
+    krc = dest_tkt();
+    if (krc != KSUCCESS)
+      MessageBox(hwnd, krb_get_err_text(krc),	"",
+		 MB_OK | MB_ICONEXCLAMATION);
+#endif
+
+#ifdef KRB5
+    code = k5_dest_tkt();
+#endif
+
+    kwin_set_default_focus(hwnd);
+    alerted = FALSE;
+
+    return; /* TRUE */
+
+  case IDD_CHANGE_PASSWORD:
+    if (isblocking)
+      return; /* TRUE */
+    password_dialog(hwnd);
+    kwin_set_default_focus(hwnd);
+
+    return; /* TRUE */
+
+  case IDM_OPTIONS:
+    if (isblocking)
+      return; /* TRUE */
+    opts_dialog(hwnd);
+
+    return; /* TRUE */
+
+  case IDM_HELP_INDEX:
+    WinHelp(hwnd, KERBEROS_HLP, HELP_INDEX, 0);
+
+    return; /* TRUE */
+
+  case IDM_ABOUT:
+    ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+    if (isblocking)
+      return; /* TRUE */
+
+#ifdef KRB4
+    strcpy(copyright, "        Kerberos 4 for Windows ");
+#endif
+#ifdef KRB5
+    strcpy(copyright, "        Kerberos V5 for Windows ");
+#endif
+#ifdef _WIN32
+    strncat(copyright, "32-bit\n", sizeof(copyright) - 1 - strlen(copyright));
+#else
+    strncat(copyright, "16-bit\n", sizeof(copyright) - 1 - strlen(copyright));
+#endif
+    strncat(copyright, "\n                Version 1.12\n\n",
+            sizeof(copyright) - 1 - strlen(copyright));
+#ifdef ORGANIZATION
+    strncat(copyright, "          For information, contact:\n",
+	    sizeof(copyright) - 1 - strlen(copyright));
+    strncat(copyright, ORGANIZATION, sizeof(copyright) - 1 - strlen(copyright));
+#endif
+    MessageBox(hwnd, copyright, KWIN_DIALOG_NAME, MB_OK);
+
+    return; /* TRUE */
+  }
+
+  return; /* FALSE */
+}
+
+
+/*
+ * Function: Process WM_SYSCOMMAND messages by setting
+ *	the focus to the password or name on restore.
+ */
+static void
+kwin_syscommand(HWND hwnd, UINT cmd, int x, int y)
+{
+  if (cmd == SC_RESTORE)
+    kwin_set_default_focus(hwnd);
+
+  if (cmd == SC_CLOSE) {
+    SendMessage(hwnd, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_EXIT, 0, 0));
+    return;
+  }
+
+  FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, DefDlgProc);
+}
+
+
+/*
+ * Function: Process WM_PAINT messages by displaying an
+ *	informative icon when we are iconic.
+ */
+static void
+kwin_paint(HWND hwnd)
+{
+  HDC hdc;
+  PAINTSTRUCT ps;
+  HICON hicon;
+  time_t expiration = 0;
+  time_t dt;
+  char buf[20];
+  RECT r;
+#ifdef KRB4
+  int i;
+  int ncred;
+  char service[ANAME_SZ];
+  char instance[INST_SZ];
+  char realm[REALM_SZ];
+  CREDENTIALS c;
+#endif
+#ifdef KRB5
+  krb5_error_code code;
+  krb5_cc_cursor cursor;
+  krb5_creds c;
+  int n;
+  char *service;
+#endif
+
+  if (!IsIconic(hwnd)) {
+    FORWARD_WM_PAINT(hwnd, DefDlgProc);
+    return;
+  }
+
+#ifdef KRB4
+  ncred = krb_get_num_cred();
+
+  for (i = 1; i <= ncred; i++) {
+    krb_get_nth_cred(service, instance, realm, i);
+    krb_get_cred(service, instance, realm, &c);
+    if (_stricmp(c.service, "krbtgt") == 0) {
+      expiration = c.issue_date - kwin_get_epoch()
+	+ (long)c.lifetime * 5L * 60L;
+      break;
+    }
+  }
+#endif
+
+#ifdef KRB5
+  code = krb5_cc_start_seq_get(k5_context, k5_ccache, &cursor);
+
+  while (code == 0) {
+    code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
+    if (code)
+      break;
+    n = krb5_princ_component(k5_context, c.server, 0)->length;
+    service = krb5_princ_component(k5_context, c.server, 0)->data;
+    if (n != KRB5_TGS_NAME_SIZE)
+      continue;
+    if (memcmp(KRB5_TGS_NAME, service, KRB5_TGS_NAME_SIZE))
+      continue;
+    expiration = c.times.endtime;
+    break;
+                
+  }
+  if (code == 0 || code == KRB5_CC_END)
+    krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
+#endif
+
+  hdc = BeginPaint(hwnd, &ps);
+  GetClientRect(hwnd, &r);
+  DefWindowProc(hwnd, WM_ICONERASEBKGND, (WPARAM)hdc, 0);
+
+  if (expiration == 0) {
+    strcpy(buf, KWIN_DIALOG_NAME);
+    hicon = LoadIcon(hinstance, MAKEINTRESOURCE(IDI_KWIN));
+  }
+  else {
+    hicon = kwin_get_icon(expiration);
+    dt = (expiration - time(NULL)) / 60;
+
+    if (dt <= 0)
+      sprintf(buf, "%s - %s", KWIN_DIALOG_NAME, "Expired");
+    else if (dt < 60) {
+      dt %= 60;
+      sprintf(buf, "%s - %ld min", KWIN_DIALOG_NAME, dt);
+    }
+    else {
+      dt /= 60;
+      sprintf(buf, "%s - %ld hr", KWIN_DIALOG_NAME, dt);
+    }
+
+    buf[sizeof(buf) - 1] = '\0';
+    if (dt > 1)
+      strncat(buf, "s", sizeof(buf) - 1 - strlen(buf));
+  }
+
+  DrawIcon(hdc, r.left, r.top, hicon);
+  EndPaint(hwnd, &ps);
+  SetWindowText(hwnd, buf);
+}
+
+
+/*
+ * Function: Window procedure for the Kerberos control panel dialog.
+ */
+LRESULT CALLBACK
+kwin_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+
+#if 0
+  if (message == wm_kerberos_changed) {       /* Message from the ccache */
+    n = ticket_init_list(GetDlgItem(hwnd, IDD_TICKET_LIST));
+    EnableWindow(GetDlgItem(hwnd, IDD_TICKET_DELETE), n > 0);
+
+    return 0;
+  }
+#endif
+
+  switch (message) {
+    HANDLE_MSG(hwnd, WM_GETMINMAXINFO, kwin_getminmaxinfo);
+
+    HANDLE_MSG(hwnd, WM_DESTROY, kwin_destroy);
+
+    HANDLE_MSG(hwnd, WM_MEASUREITEM, ticket_measureitem);
+
+    HANDLE_MSG(hwnd, WM_DRAWITEM, ticket_drawitem);
+
+  case WM_SETCURSOR:
+    if (isblocking) {
+      SetCursor(LoadCursor(NULL, IDC_WAIT));
+      return TRUE;
+    }
+    break;
+
+    HANDLE_MSG(hwnd, WM_SIZE, kwin_size);
+
+    HANDLE_MSG(hwnd, WM_SYSCOMMAND, kwin_syscommand);
+
+    HANDLE_MSG(hwnd, WM_TIMER, kwin_timer);
+
+    HANDLE_MSG(hwnd, WM_PAINT, kwin_paint);
+    
+  case WM_ERASEBKGND:
+    if (!IsIconic(hwnd))
+      break;
+    return 0;
+
+  case WM_KWIN_SETNAME:
+    kwin_init_name(hwnd, (char *)lParam);
+  }
+
+  return DefDlgProc(hwnd, message, wParam, lParam);
+}
+
+
+/*
+ * Function: Dialog procedure called by the dialog manager
+ *	to process dialog specific messages.
+ */
+static BOOL CALLBACK
+kwin_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+  switch (message) {
+    HANDLE_MSG(hwnd, WM_INITDIALOG, kwin_initdialog);
+
+    HANDLE_MSG(hwnd, WM_COMMAND, kwin_command);
+  }
+
+  return FALSE;
+}
+
+
+/*
+ * Function: Initialize the kwin dialog class.
+ *
+ * Parameters:
+ *	hinstance - the instance to initialize
+ *
+ * Returns: TRUE if dialog class registration is sucessfully, false otherwise.
+ */
+static BOOL
+kwin_init(HINSTANCE hinstance)
+{
+  WNDCLASS class;
+  ATOM rc;
+
+  class.style = CS_HREDRAW | CS_VREDRAW;
+  class.lpfnWndProc = (WNDPROC)kwin_wnd_proc;
+  class.cbClsExtra = 0;
+  class.cbWndExtra = DLGWINDOWEXTRA;
+  class.hInstance = hinstance;
+  class.hIcon = NULL;
+  /*		LoadIcon(hinstance, MAKEINTRESOURCE(IDI_KWIN)); */
+  class.hCursor = NULL;
+  class.hbrBackground = NULL;
+  class.lpszMenuName = NULL;
+  class.lpszClassName = KWIN_DIALOG_CLASS;
+
+  rc = RegisterClass(&class);
+  assert(rc);
+
+  return rc;
+}
+
+
+/*
+ * Function: Initialize the KWIN application.  This routine should
+ *	only be called if no previous instance of the application
+ *	exists.  Currently it only registers a class for the kwin
+ *	dialog type.
+ *
+ * Parameters:
+ *	hinstance - the instance to initialize
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static BOOL
+init_application(HINSTANCE hinstance)
+{
+  BOOL rc;
+
+#if 0
+#ifdef KRB4
+  wm_kerberos_changed = krb_get_notification_message();
+#endif
+
+#ifdef KRB5
+  wm_kerberos_changed = krb5_get_notification_message();
+#endif
+#endif
+
+  rc = kwin_init(hinstance);
+
+  return rc;
+}
+
+
+/*
+ * Function: Quits the KWIN application.  This routine should
+ *	be called when the last application instance exits.
+ *
+ * Parameters:
+ *	hinstance - the instance which is quitting.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static BOOL
+quit_application(HINSTANCE hinstance)
+{
+  return TRUE;
+}
+
+
+/*
+ * Function: Initialize the current instance of the KWIN application.
+ *
+ * Parameters:
+ *	hinstance - the instance to initialize
+ *
+ *	ncmdshow - show flag to indicate wheather to come up minimized
+ *		or not.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+static BOOL
+init_instance(HINSTANCE hinstance, int ncmdshow)
+{
+  WORD versionrequested;
+  WSADATA wsadata;
+  int rc;
+  int i;
+
+  versionrequested = 0x0101;			/* We need version 1.1 */
+  rc = WSAStartup(versionrequested, &wsadata);
+  if (rc != 0) {
+    MessageBox(NULL, "Couldn't initialize Winsock library", "",
+	       MB_OK | MB_ICONSTOP);
+
+    return FALSE;
+  }
+
+  if (versionrequested != wsadata.wVersion) {
+    WSACleanup();
+    MessageBox(NULL, "Winsock version 1.1 not available", "",
+	       MB_OK | MB_ICONSTOP);
+
+    return FALSE;
+  }
+
+#ifdef KRB5
+  {
+    krb5_error_code code;
+
+    code = krb5_init_context(&k5_context);
+    if (!code) {
+#if 0				/* Not needed under windows */
+      krb5_init_ets(k5_context);
+#endif
+      code = k5_init_ccache(&k5_ccache);
+    }
+    if (code) {
+      com_err(NULL, code, "while initializing program");
+      return FALSE;
+    }
+    k5_name_from_ccache(k5_ccache);
+  }
+#endif
+
+  cns_load_registry();
+
+  /*
+   * Set up expiration action
+   */
+  alert = cns_res.alert;
+  beep = cns_res.beep;
+
+  /*
+   * ticket options
+   */
+  forwardable = cns_res.forwardable;
+  noaddresses = cns_res.noaddresses;
+
+  /*
+   * Load clock icons
+   */
+  for (i = IDI_FIRST_CLOCK; i <= IDI_LAST_CLOCK; i++)
+    kwin_icons[i - IDI_FIRST_CLOCK] = LoadIcon(hinstance, MAKEINTRESOURCE(i));
+
+#ifdef KRB4
+  krb_start_session(NULL);
+#endif
+
+  return TRUE;
+}
+
+
+/*
+ * Function: Quits the current instance of the KWIN application.
+ *
+ * Parameters:
+ *	hinstance - the instance to quit.
+ *
+ * Returns: TRUE if termination was sucessfully, false otherwise.
+ */
+static BOOL
+quit_instance(HINSTANCE hinstance)
+{
+  int i;
+
+#ifdef KRB4
+  krb_end_session(NULL);
+#endif
+
+#ifdef KRB5     /* FIXME */
+  krb5_cc_close(k5_context, k5_ccache);
+#endif
+
+  WSACleanup();
+
+  /*
+   * Unload clock icons
+   */
+  for (i = IDI_FIRST_CLOCK; i <= IDI_LAST_CLOCK; i++)
+    DestroyIcon(kwin_icons[i - IDI_FIRST_CLOCK]);
+
+  return TRUE;
+}
+
+
+/*
+ * Function: Main routine called on program invocation.
+ *
+ * Parameters:
+ *	hinstance - the current instance
+ *
+ *	hprevinstance - previous instance if one exists or NULL.
+ *
+ *	cmdline - the command line string passed by Windows.
+ *
+ *	ncmdshow - show flag to indicate wheather to come up minimized
+ *		or not.
+ *
+ * Returns: TRUE if initialized sucessfully, false otherwise.
+ */
+int PASCAL
+WinMain(HINSTANCE hinst, HINSTANCE hprevinstance, LPSTR cmdline, int ncmdshow)
+{
+  DLGPROC dlgproc;
+  HWND hwnd;
+  HACCEL haccel;
+  MSG msg;
+  char *p;
+  char buf[MAX_K_NAME_SZ + 9];
+  char name[MAX_K_NAME_SZ];
+
+  strcpy(buf, cmdline);
+  action = LOGIN_AND_RUN;
+  name[0] = 0;
+  p = strtok(buf, " ,");
+
+  while (p != NULL) {
+    if (_stricmp(p, "/exit") == 0)
+      action = LOGIN_AND_EXIT;
+    else if (_stricmp(p, "/minimize") == 0)
+      action = LOGIN_AND_MINIMIZE;
+    else
+      strcpy(name, p);
+
+    p = strtok(NULL, " ,");
+  }
+
+  dlgncmdshow = ncmdshow;
+  hinstance = hinst;
+
+#ifndef _WIN32
+  /*
+   * If a previous instance of this application exits, bring it
+   * to the front and exit.
+   *
+   * This code is not compiled for WIN32, since hprevinstance will always
+   * be NULL.
+   */
+  if (hprevinstance != NULL) {
+    hwnd = FindWindow(KWIN_DIALOG_CLASS, NULL);
+
+    if (IsWindow(hwnd) && IsWindowVisible(hwnd)) {
+      if (GetWindowWord(hwnd, GWW_HINSTANCE) == hprevinstance) {
+	if (name[0])
+	  SendMessage(hwnd, WM_KWIN_SETNAME, 0, (LONG)name);
+
+	ShowWindow(hwnd, ncmdshow);
+	SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
+		     SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
+
+	return FALSE;
+      }
+    }
+  }
+
+  if (hprevinstance == NULL)
+#endif /* _WIN32 */
+
+  if (!init_application(hinstance))
+      return FALSE;
+
+  if (!init_instance(hinstance, ncmdshow))
+    return FALSE;
+
+#ifdef _WIN32
+  dlgproc = kwin_dlg_proc;
+#else
+  dlgproc = (FARPROC)MakeProcInstance(kwin_dlg_proc, hinstance);
+  assert(dlgproc != NULL);
+
+  if (dlgproc == NULL)
+    return 1;
+#endif
+
+  hwnd = CreateDialogParam(hinstance, MAKEINTRESOURCE(ID_KWIN),
+			   HWND_DESKTOP, dlgproc, (LONG)name);
+  assert(hwnd != NULL);
+
+  if (hwnd == NULL)
+    return 1;
+  haccel = LoadAccelerators(hinstance, MAKEINTRESOURCE(IDA_KWIN));
+  assert(hwnd != NULL);
+
+  while (GetMessage(&msg, NULL, 0, 0)) {
+    if (!TranslateAccelerator(hwnd, haccel, &msg) &&
+	!IsDialogMessage(hwnd, &msg)) {
+      TranslateMessage(&msg);
+      DispatchMessage(&msg);
+    }
+  }
+
+  DestroyWindow(hwnd);
+
+#ifndef _WIN32
+  FreeProcInstance((FARPROC)dlgproc);
+#endif
+
+  cns_save_registry();
+
+  return 0;
+}
+
+
+#if 0
+
+#define WM_ASYNC_COMPLETED (WM_USER + 1)
+#define GETHOSTBYNAME_CLASS "krb_gethostbyname"
+static HTASK htaskasync;	/* Asynchronos call in progress */
+static BOOL iscompleted;	/* True when async call is completed */
+
+/*
+ * This routine is called to cancel a blocking hook call within
+ * the Kerberos library.  The need for this routine arises due
+ * to bugs which exist in existing WINSOCK implementations.  We
+ * blocking gethostbyname with WSAASyncGetHostByName.  In order
+ * to cancel such an operation, this routine must be called.
+ * Applications may call this routine in addition to calls to
+ * WSACancelBlockingCall to get any sucy Async calls canceled.
+ * Return values are as they would be for WSACancelAsyncRequest.
+ */
+int
+krb_cancel_blocking_call(void)
+{
+  if (htaskasync == NULL)
+    return 0;
+  iscompleted = TRUE;
+
+  return WSACancelAsyncRequest(htask);
+}
+
+
+/*
+ * Window proceedure for temporary Windows created in
+ * krb_gethostbyname.  Fields completion messages.
+ */
+LRESULT CALLBACK
+krb_gethostbyname_wnd_proc(HWND hwnd, UINT message,
+			   WPARAM wParam, LPARAM lParam)
+{
+  if (message == WM_ASYNC_COMPLETED) {
+    iscompleted = TRUE;
+    return 0;
+  }
+  
+  return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+
+/*
+ * The WINSOCK routine gethostbyname has a bug in both FTP and NetManage
+ * implementations which causes the blocking hook, if any, not to be
+ * called.  This routine attempts to work around the problem by using
+ * the async routines to emulate the functionality of the synchronous
+ * routines
+ */
+struct hostent *PASCAL
+krb_gethostbyname(
+		  const char *name)
+{
+  HWND hwnd;
+  char buf[MAXGETHOSTSTRUCT];
+  BOOL FARPROC blockinghook;
+  WNDCLASS wc;
+  static BOOL isregistered;
+  
+  blockinghook = WSASetBlockingHook(NULL);
+  WSASetBlockingHook(blockinghook);
+
+  if (blockinghook == NULL)
+    return gethostbyname(name);
+
+  if (RegisterWndClass() == NULL)
+    return gethostbyname(name);
+
+  if (!isregistered) {
+    wc.style = 0;
+    wc.lpfnWndProc = gethostbyname_wnd_proc;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = hlibinstance;
+    wc.hIcon = NULL;
+    wc.hCursor = NULL;
+    wc.hbrBackground = NULL;
+    wc.lpszMenuName  = NULL;
+    wc.lpszClassName = GETHOSTBYNAME_CLASS;
+
+    if (!RegisterClass(&wc))
+      return gethostbyname(name);
+
+    isregistered = TRUE;
+  }
+
+  hwnd = CreateWindow(GETHOSTBYNAME_CLASS, "", WS_OVERLAPPED,
+		      -100, -100, 0, 0, HWND_DESKTOP, NULL, hlibinstance, NULL);
+  if (hwnd == NULL)
+    return gethostbyname(name);
+
+  htaskasync =
+    WSAAsyncGetHostByName(hwnd, WM_ASYNC_COMPLETED, name, buf, sizeof(buf));
+  b = blockinghook(NULL);
+}
+
+#endif  /* if 0 */
+
+#ifdef KRB5
+
+/*
+ * Function: destroys all tickets in a k5 ccache
+ *
+ * Returns: K5 error code (0 == success)
+ */
+krb5_error_code
+k5_dest_tkt(void)
+{
+  krb5_error_code code;
+  krb5_principal princ;
+
+  if (code = krb5_cc_get_principal(k5_context, k5_ccache, &princ)) {
+    com_err(NULL, code, "while retrieving principal name");
+    return code;
+  }
+
+  code = krb5_cc_initialize(k5_context, k5_ccache, princ);
+  if (code != 0) {
+    com_err(NULL, code, "when re-initializing cache");
+    krb5_free_principal(k5_context, princ);
+    return code;
+  }
+
+  krb5_free_principal(k5_context, princ);
+
+  return code;
+}
+
+/*
+ * 
+ * k5_get_num_cred
+ * 
+ * Returns: number of creds in the credential cache, -1 on error
+ * 
+ */
+int
+k5_get_num_cred(int verbose)
+{
+  krb5_error_code code;
+  krb5_cc_cursor cursor;
+  krb5_creds c;
+  int ncreds = 0;
+
+  /* Turn off OPENCLOSE and leave open while we use ccache */
+  if (code = krb5_cc_set_flags(k5_context, k5_ccache, 0)) {
+    if (code == KRB5_FCC_NOFILE)
+      return 0;
+    if (verbose)
+      com_err(NULL, code,
+	      "while setting cache flags (ticket cache %s)",
+	      krb5_cc_get_name(k5_context, k5_ccache));
+    return -1;
+  }
+
+  if (code = krb5_cc_start_seq_get(k5_context, k5_ccache, &cursor)) {
+    if (verbose)
+      com_err(NULL, code, "while starting to retrieve tickets.");
+    return -1;
+  }
+
+  while (1) {                                 /* Loop and get creds */
+    code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
+    if (code)
+      break;
+    ++ncreds;
+  }
+
+  if (code != KRB5_CC_END) {                  /* Error while looping??? */
+    if (verbose)
+      com_err(NULL, code, "while retrieving a ticket.");
+    return -1;
+  }
+
+  if (code = krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor)) {
+    if (verbose)
+      com_err(NULL, code, "while closing ccache.");
+  } else if (code = krb5_cc_set_flags(k5_context, k5_ccache,
+				      KRB5_TC_OPENCLOSE)) {
+    if (verbose)
+      com_err(NULL, code, "while closing ccache.");
+  }
+
+  return ncreds;
+}
+
+static int
+k5_get_num_cred2()
+{
+  krb5_error_code code;
+  krb5_cc_cursor cursor;
+  krb5_creds c;
+  int ncreds = 0;
+
+  code = krb5_cc_start_seq_get(k5_context, k5_ccache, &cursor);
+  if (code == KRB5_FCC_NOFILE)
+    return 0;
+
+  while (1) {
+    code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
+    if (code)
+      break;
+    ++ncreds;
+  }
+
+  if (code == KRB5_CC_END)
+    krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor);
+
+  return ncreds;
+}
+
+
+/*
+ * Function: Parses fullname into name and realm
+ *
+ * Parameters:
+ *  name - buffer filled with name of user
+ *  realm - buffer filled with realm of user
+ *  fullname - string in form name.instance@realm
+ *
+ * Returns: 0
+ */
+int
+k5_kname_parse(char *name, char *realm, char *fullname)
+{
+  char *ptr;                                  /* For parsing */
+
+  ptr = strchr(fullname, '@');               /* Name, realm separator */
+
+  if (ptr != NULL)                            /* Get realm */
+    strcpy(realm, ptr + 1);
+  else
+    *realm = '\0';
+
+  if (ptr != NULL) {                          /* Get the name */
+    strncpy(name, fullname, ptr - fullname);
+    name[ptr - fullname] = '\0';
+  } else
+    strcpy(name, fullname);
+
+  ptr = strchr(name, '.');                   /* K4 compatability */
+  if (ptr != NULL)
+    *ptr = '\0';
+
+  return 0;
+}
+
+
+/*
+ * Function: Initializes ccache and catches illegal caches such as
+ *  bad format or no permissions.
+ *
+ * Parameters:
+ *  ccache - credential cache structure to use
+ *
+ * Returns: krb5_error_code
+ */
+krb5_error_code
+k5_init_ccache(krb5_ccache *ccache)
+{
+  krb5_error_code code;
+  krb5_principal princ;
+  FILE *fp;
+
+  code = krb5_cc_default(k5_context, ccache); /* Initialize the ccache */
+  if (code)
+    return code;
+
+  code = krb5_cc_get_principal(k5_context, *ccache, &princ);
+  if (code == KRB5_FCC_NOFILE) {              /* Doesn't exist yet */
+    fp = fopen(krb5_cc_get_name(k5_context, *ccache), "w");
+    if (fp == NULL)                         /* Can't open it */
+      return KRB5_FCC_PERM;
+    fclose (fp);
+  }
+
+  if (code) {                                 /* Bad, delete and try again */
+    remove(krb5_cc_get_name(k5_context, *ccache));
+    code = krb5_cc_get_principal(k5_context, *ccache, &princ);
+    if (code == KRB5_FCC_NOFILE)            /* Doesn't exist yet */
+      return 0;
+    if (code)
+      return code;
+  }
+
+  /*  krb5_free_principal(k5_context, princ); */
+
+  return 0;
+}
+
+
+/*
+ * 
+ * Function: Reads the name and realm out of the ccache.
+ * 
+ * Parameters:
+ *  ccache - credentials cache to get info from
+ * 
+ *  name - buffer to hold user name
+ * 
+ *  realm - buffer to hold the realm
+ * 
+ * 
+ * Returns: TRUE if read names, FALSE if not
+ * 
+ */
+int
+k5_name_from_ccache(krb5_ccache k5_ccache)
+{
+  krb5_error_code code;
+  krb5_principal princ;
+  char name[ANAME_SZ];
+  char realm[REALM_SZ];
+  char *defname;
+
+  if (code = krb5_cc_get_principal(k5_context, k5_ccache, &princ))
+    return FALSE;
+
+  code = krb5_unparse_name(k5_context, princ, &defname);
+  if (code) {
+    return FALSE;
+  }
+
+  k5_kname_parse(name, realm, defname);       /* Extract the components */
+  strcpy(cns_res.name, name);
+  strcpy(cns_res.realm, realm);
+
+  return TRUE;
+}
+#endif /* KRB5 */
diff --git a/mechglue/src/windows/cns/cns.h b/mechglue/src/windows/cns/cns.h
new file mode 100644
index 000000000..cdd6da3b3
--- /dev/null
+++ b/mechglue/src/windows/cns/cns.h
@@ -0,0 +1,249 @@
+/*
+ * cns.h
+ *
+ * Public Domain -- written by Cygnus Support.
+ */
+
+/* Only one time, please */
+#ifndef	KWIN_DEFS
+#define KWIN_DEFS
+
+#if !defined(KRB4) && !defined(KRB5)
+#define KRB5
+#endif
+
+#ifndef RC_INVOKED
+
+#ifdef KRB4
+#include "mit-copyright.h"
+#include "krb.h"
+#include "kadm.h"
+#include "org.h"
+#endif
+
+#ifdef KRB5
+#include "winsock.h"
+#include "krb5.h"
+#include "krbini.h"
+#include "com_err.h"
+
+#define DEFAULT_TKT_LIFE    120             /* In 5 minute units */
+#define ANAME_SZ	        40
+#define	REALM_SZ	        40
+#define	SNAME_SZ	        40
+#define	INST_SZ		        40
+#define MAX_KPW_LEN	        128
+/* include space for '.' and '@' */
+#define	MAX_K_NAME_SZ	    (ANAME_SZ + INST_SZ + REALM_SZ + 2)
+#ifdef CYGNUS
+#define ORGANIZATION        "Cygnus Solutions\n(800)CYGNUS-1\nhttp://www.cygnus.com\ninfo@cygnus.com"
+#endif
+#define CREDENTIALS         char
+#endif
+
+/*
+ * Constants
+ */
+#define BLOCK_MAX_SEC 30	       /* Blocking timeout duration */
+#define KWIN_UPDATE_PERIOD 30000       /* Every 30 seconds update the screen */
+#define TIME_BUFFER	300	       /* Pop-up time buffer in seconds */
+#define WM_KWIN_SETNAME (WM_USER+100)  /* Sets the name fields in the dialog */
+
+#endif /* RC_INVOKED */
+
+/*
+ * Menu items
+ */
+#define FILE_MENU_ITEMS 3
+#define FILE_MENU_MAX_LOGINS 5
+#define IDM_KWIN 1000
+#define   IDM_OPTIONS 1001
+#define   IDM_EXIT 1002
+#define   IDM_FIRST_LOGIN 1003
+
+#define   IDM_HELP_INDEX 1020
+#define   IDM_ABOUT 1021
+
+/*
+ * Accelerator
+ */
+#define IDA_KWIN 2000
+
+/*
+ * Dialog and dialog item ids
+ */
+#define KWIN_DIALOG_CLASS "KERBEROS"	/* class for kerberos dialog */
+#define KWIN_DIALOG_NAME "Krb5"		/* name for kerberos dialog */
+
+#define ID_KWIN 100			/* the main kerberos dialog */
+#define IDD_KWIN_FIRST 101
+#define   IDD_TICKET_LIST_TITLE 101
+#define   IDD_TICKET_LIST 102
+
+#ifdef KRB4
+
+#define IDD_MIN_TITLE 103
+#define   IDD_LOGIN_NAME_TITLE 103
+#define   IDD_LOGIN_INSTANCE_TITLE 104
+#define   IDD_LOGIN_REALM_TITLE 105
+#define   IDD_LOGIN_PASSWORD_TITLE 106
+#define IDD_MAX_TITLE 106
+
+#define IDD_MIN_EDIT 107
+#define   IDD_LOGIN_NAME 107
+#define   IDD_LOGIN_INSTANCE 108
+#define   IDD_LOGIN_REALM 109
+#define   IDD_LOGIN_PASSWORD 110
+#define IDD_MAX_EDIT 110
+
+#endif
+
+#ifdef KRB5
+
+#define IDD_MIN_TITLE 103
+#define   IDD_LOGIN_NAME_TITLE 103
+#define   IDD_LOGIN_PASSWORD_TITLE 104
+#define   IDD_LOGIN_REALM_TITLE 105
+#define IDD_MAX_TITLE 105
+
+#define IDD_MIN_EDIT 107
+#define   IDD_LOGIN_NAME 107
+#define   IDD_LOGIN_PASSWORD 108
+#define   IDD_LOGIN_REALM 109
+#define IDD_MAX_EDIT 109
+
+#endif
+
+#define IDD_MIN_BUTTON 111
+#define   IDD_CHANGE_PASSWORD 111
+#define   IDD_TICKET_DELETE 112
+#define   IDD_LOGIN 113
+#define   IDD_MAX_BUTTON 113
+#define IDD_PASSWORD_CR2 114            /* For better cr handling */
+
+#define IDD_KWIN_LAST 114
+
+
+#define ID_PASSWORD 200
+#define   IDD_PASSWORD_NAME 204
+#define   IDD_PASSWORD_INSTANCE 205
+#define   IDD_PASSWORD_REALM 206
+#define   IDD_OLD_PASSWORD 207
+#define   IDD_NEW_PASSWORD1 208
+#define   IDD_NEW_PASSWORD2 209
+#define   IDD_PASSWORD_CR 210
+
+
+#define ID_OPTS 300
+#define   IDD_CONF 301
+#define   IDD_REALMS 302
+#define   IDD_LIFETIME 303
+#define   IDD_CCACHE 304
+#define   IDD_ACTIONS 310
+#define     IDD_BEEP 311
+#define     IDD_ALERT 312
+#define   IDD_TKOPT 320
+#define   IDD_FORWARDABLE 321
+#define   IDD_NOADDRESSES 322
+
+/*
+ * the entire range (400 through 499) is reserved for the blasted variable
+ * dialog box thingie.
+ */
+#define ID_VARDLG    400
+
+/*
+ * Dialog dimensions
+ */
+#define KWIN_MIN_WIDTH 180
+#define KWIN_MIN_HEIGHT 110
+
+/*
+ * Icons
+ */
+#define IDI_KWIN 1		/* The program icon */
+
+#define ICON_WIDTH 30	/* Width used with icons */
+#define ICON_HEIGHT 20	/* Height used with icons */
+
+#define IDI_FIRST_CLOCK 2
+#define IDI_0_MIN 2		/* < 5 minutes left */
+#define IDI_5_MIN 3
+#define IDI_10_MIN 4
+#define IDI_15_MIN 5
+#define IDI_20_MIN 6
+#define IDI_25_MIN 7
+#define IDI_30_MIN 8
+#define IDI_35_MIN 9
+#define IDI_40_MIN 10
+#define IDI_45_MIN 11
+#define IDI_50_MIN 12
+#define IDI_55_MIN 13
+#define IDI_60_MIN 14
+#define IDI_EXPIRED 15
+#define IDI_TICKET 16
+#define IDI_LAST_CLOCK 16
+#define MAX_ICONS (IDI_LAST_CLOCK - IDI_FIRST_CLOCK + 1)
+
+#ifndef RC_INVOKED
+
+extern BOOL isblocking;
+extern HFONT hfontdialog;
+extern HINSTANCE hinstance;
+extern BOOL alert;
+extern BOOL beep;
+
+extern char confname[FILENAME_MAX];
+
+#ifdef KRB5
+extern krb5_context k5_context;
+extern krb5_ccache k5_ccache;
+extern char ccname[FILENAME_MAX];
+extern BOOL forwardable;
+extern BOOL noaddresses;
+#endif
+
+/*
+ * Prototypes
+ */
+
+/* in cns.c */
+
+void kwin_init_name(HWND, char *);
+void kwin_set_default_focus(HWND);
+time_t kwin_get_epoch(void);
+
+/* in options.c */
+BOOL opts_initdialog(HWND, HWND, LPARAM);
+void opts_command(HWND, int, HWND, UINT);
+BOOL CALLBACK opts_dlg_proc(HWND, UINT, WPARAM, LPARAM);
+BOOL opts_dialog(HWND);
+
+/* in password.c */
+BOOL change_password(HWND, char *, char *, char *, char *, char *);
+void password_command(HWND, int, HWND, UINT);
+BOOL password_initdialog(HWND, HWND, LPARAM);
+BOOL CALLBACK password_dlg_proc(HWND, UINT, WPARAM, LPARAM);
+BOOL password_dialog(HWND);
+
+#ifdef KRB5
+krb5_error_code k5_dest_tkt(void);
+int k5_get_num_cred(int);
+int k5_kname_parse(char *, char *, char *);
+krb5_error_code k5_init_ccache(krb5_ccache *);
+int k5_name_from_ccache(krb5_ccache);
+krb5_error_code k5_change_password(HWND, krb5_context, char *, char *, char *,
+				   char *, char **);
+
+#endif /* KRB5 */
+
+HICON kwin_get_icon(time_t);
+void trim(char *);
+void start_blocking_hook(int);
+void end_blocking_hook(void);
+void center_dialog(HWND);
+void set_dialog_font(HWND, HFONT);
+
+#endif /* RC_INVOKED */
+
+#endif
diff --git a/mechglue/src/windows/cns/cns.ico b/mechglue/src/windows/cns/cns.ico
new file mode 100644
index 0000000000000000000000000000000000000000..645efa5ba049b95732ee60341a4603a7bd1df9cb
GIT binary patch
literal 1086
zcmc&yv5wO~6da#XY$@VQj}Wd-lvmM)ub@P(Tp^Us?z|F(x7&gb;1{l-J0#puLQfGY
zL`AmCN-=rN?%Kl930=uc=DnTq+qdgUfCLvP%M19pPJk=cvV0WyPs%T;J@Xpzf=KxB
zp+df!MC7hGD`^EhRKW9(z&Ea6v-h1vB73B6r`Ctf*T+Zs@Z`6=c{QwddnBI@D(#Md
zj7U!-l7JQ%J+?r5O_aPk!EX%SA;j37Hb;@&VKeSe<I_%TAu^=AVIn8aBs!0gut4!0
zNC&>6ierF{i|AOzC5emyZ{?JF^di}3;){qO-cQHMxnB?Bv}o}>c~Mm~Q>oyo&s-7;
z!!WRq9(hZ7>rj}z#XO7Rz0uGkA6XMi$RULXTST2DJ8ziwdC_DGLYmvqIwex2rzw;q
zw`UE7H8AqG!RDm2a|-?-45jtN4GDBEE*@Et7mhom_xD>>TEvDeR#UjFbKl^F^-Z%~
zUDj0`l-b*?Z|dqtJ<VO;v~5$@Y>2{b-uHc7SHB|7;B?#8_1uom=w2;&?wsB(cwvlI
tt9crSIOnkB#u)NA-RIoVwFNJX0xJJx3hzlZ6IQiY|6>`9VESMG^FQ(KGx`7k

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/cns_reg.c b/mechglue/src/windows/cns/cns_reg.c
new file mode 100644
index 000000000..92255fe4f
--- /dev/null
+++ b/mechglue/src/windows/cns/cns_reg.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1997 Cygnus Solutions
+ *
+ * Author:  Michael Graff
+ */
+
+#include <windows.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "cns.h"
+#include "cns_reg.h"
+
+#include "../lib/registry.h"
+
+cns_reg_t cns_res;  /* yes, a global.  Sue me. */
+
+/*
+ * function to load all the data we will want from the registry.  If the
+ * registry data cannot be found this function will initialize a default
+ * environment.
+ */
+void
+cns_load_registry(void)
+{
+  char    tmp[1024];
+  DWORD   tdw;
+  char   *ts;
+  HKEY    key;
+  int     i;
+
+  /*
+   * Set up reasonable default values.  These will all be overwritten if
+   * the registry is successfully opened.
+   */
+  cns_res.name[0] = '\0';
+  cns_res.realm[0] = '\0';
+  cns_res.x = 0;
+  cns_res.y = 0;
+  cns_res.cx = 0;
+  cns_res.cy = 0;
+
+  cns_res.alert = 0;
+  cns_res.beep = 0;
+  cns_res.lifetime = DEFAULT_TKT_LIFE * 5;
+  cns_res.forwardable = 1;
+  cns_res.noaddresses = 0;
+    
+  for (i = 1 ; i < FILE_MENU_MAX_LOGINS ; i++)
+    cns_res.logins[i][0] = '\0';
+
+  /*
+   * by default, allow the user to override the config file location and NOT the
+   * cred cache name.
+   */
+  cns_res.conf_override = 1;
+  cns_res.cc_override = 0;
+
+  {
+	char *s;
+	s = krb5_cc_default_name(k5_context);
+	
+	strcpy(cns_res.def_ccname, s);
+  }
+
+  cns_res.def_confname[0] = '\0';
+
+  /*
+   * If the system has these keys in the registry, do not allow the user to
+   * override the config file and ccache locations.
+   */
+  key = registry_open(HKEY_LOCAL_MACHINE, KERBNET_BASE, KEY_READ);
+  if (key != INVALID_HANDLE_VALUE) {
+	if (registry_string_get(key, KERBNET_HOME, &ts) == 0) {
+		cns_res.conf_override = 0;
+		cns_res.def_confname[sizeof(cns_res.def_confname) - 1];
+		strncpy(cns_res.def_confname, ts,
+		        sizeof(cns_res.def_confname) - 1);
+		strncat(cns_res.def_confname, "\\etc\\krb5.conf",
+			sizeof(cns_res.def_confname) - 1 -
+			strlen(cns_res.def_confname));
+		free(ts);
+	  }
+
+	  if (registry_string_get(key, "ccname", &ts) == 0) {
+		cns_res.cc_override = 0;
+		strcpy(cns_res.def_ccname, ts);
+		free(ts);
+	  }
+  }
+
+  /*
+   * Try to open the registry.  If we succeed, read the last used values from there.  If we
+   * do not get the registry open simply return.
+   */
+  key = registry_open(HKEY_CURRENT_USER, KERBNET_CNS_BASE, KEY_ALL_ACCESS);
+
+  if (key == INVALID_HANDLE_VALUE)
+	return;
+
+  if (registry_dword_get(key, "x", &tdw) == 0)
+	  cns_res.x = tdw;
+
+  if (registry_dword_get(key, "y", &tdw) == 0)
+	  cns_res.y = tdw;
+
+  if (registry_dword_get(key, "cx", &tdw) == 0)
+	  cns_res.cx = tdw;
+
+  if (registry_dword_get(key, "cy", &tdw) == 0)
+	  cns_res.cy = tdw;
+
+  if (registry_dword_get(key, "lifetime", &tdw) == 0)
+	  cns_res.lifetime = tdw;
+
+  if (registry_dword_get(key, "forwardable", &tdw) == 0)
+	  cns_res.forwardable = tdw;
+
+  if (registry_dword_get(key, "noaddresses", &tdw) == 0)
+   	  cns_res.noaddresses = tdw;
+ 
+  if (registry_dword_get(key, "alert", &tdw) == 0)
+	  cns_res.alert = tdw;
+
+  if (registry_dword_get(key, "beep", &tdw) == 0)
+	  cns_res.beep = tdw;
+
+  if (registry_string_get(key, "name", &ts) == 0) {
+	strcpy(cns_res.name, ts);
+	free(ts);
+  }
+
+  if (registry_string_get(key, "realm", &ts) == 0) {
+	strcpy(cns_res.realm, ts);
+	free(ts);
+  }
+
+  if (cns_res.conf_override && (registry_string_get(key, "confname", &ts) == 0)) {
+	strcpy(cns_res.confname, ts);
+	free(ts);
+  } else
+	  strcpy(cns_res.confname, cns_res.def_confname);
+
+  if (cns_res.cc_override && (registry_string_get(key, "ccname", &ts) == 0)) {
+	strcpy(cns_res.ccname, ts);
+	free(ts);
+  } else
+	  strcpy(cns_res.ccname, cns_res.def_ccname);
+
+  for (i = 0 ; i < FILE_MENU_MAX_LOGINS ; i++) {
+    sprintf(tmp, "login_%02d", i);
+    if (registry_string_get(key, tmp, &ts) == 0) {
+      strcpy(cns_res.logins[i], ts);
+      free(ts);
+    }
+  }
+
+  registry_close(key);
+}
+
+/*
+ * save all the registry data, creating the keys if needed.
+ */
+void
+cns_save_registry(void)
+{
+  char    tmp[1024];
+  HKEY    key;
+  int     i;
+
+  /*
+   * First, create the heirachy...  This is gross, but functional
+   */
+  key = registry_key_create(HKEY_CURRENT_USER, CYGNUS_SOLUTIONS, KEY_WRITE);
+  if (key == INVALID_HANDLE_VALUE)
+	  return;
+
+  key = registry_key_create(HKEY_CURRENT_USER, KERBNET_SANS_VERSION, KEY_WRITE);
+  if (key == INVALID_HANDLE_VALUE)
+	  return;
+  registry_close(key);
+
+  key = registry_key_create(HKEY_CURRENT_USER, KERBNET_BASE, KEY_WRITE);
+  if (key == INVALID_HANDLE_VALUE)
+	  return;
+  registry_close(key);
+
+  key = registry_key_create(HKEY_CURRENT_USER, KERBNET_CNS_BASE, KEY_WRITE);
+  if (key == INVALID_HANDLE_VALUE)
+	return;
+
+  registry_dword_set(key, "x", cns_res.x);
+  registry_dword_set(key, "y", cns_res.y);
+  registry_dword_set(key, "cx", cns_res.cx);
+  registry_dword_set(key, "cy", cns_res.cy);
+
+  registry_dword_set(key, "alert", cns_res.alert);
+  registry_dword_set(key, "beep", cns_res.beep);
+  registry_dword_set(key, "lifetime", cns_res.lifetime);
+  registry_dword_set(key, "forwardable", cns_res.forwardable);
+  registry_dword_set(key, "noaddresses", cns_res.noaddresses);
+
+  registry_string_set(key, "name", cns_res.name);
+  registry_string_set(key, "realm", cns_res.realm);
+
+  if (cns_res.conf_override)
+  {
+      if (strcmp(cns_res.confname, cns_res.def_confname))
+	  registry_string_set(key, "confname", cns_res.confname);
+      else
+	  registry_value_delete(key, "confname");
+  }
+
+  if (cns_res.cc_override)
+  {
+      if (strcmp(cns_res.ccname, cns_res.def_ccname))
+	  registry_string_set(key, "ccname", cns_res.ccname);
+      else
+	  registry_value_delete(key, "ccname");
+  }
+
+  for (i = 0 ; i < FILE_MENU_MAX_LOGINS ; i++)
+    if (cns_res.logins[i][0] != '\0') {
+      sprintf(tmp, "login_%02d", i);
+      registry_string_set(key, tmp, cns_res.logins[i]);
+    }
+
+  registry_close(key);
+}
diff --git a/mechglue/src/windows/cns/cns_reg.h b/mechglue/src/windows/cns/cns_reg.h
new file mode 100644
index 000000000..9ebed4fe8
--- /dev/null
+++ b/mechglue/src/windows/cns/cns_reg.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1997 Cygnus Solutions
+ *
+ * Author:  Michael Graff
+ */
+
+#include <krb5.h>
+
+typedef struct cns_reg {
+  DWORD         x;                               /* default dialog size */
+  DWORD         y;
+  DWORD         cx;
+  DWORD         cy;
+  DWORD         lifetime;                        /* ticket lifetime */
+  DWORD         beep;                            /* beep on expire/warning? */
+  DWORD         alert;                           /* alert (deiconify) when tix expired? */
+  DWORD         forwardable;                     /* get forwardable tickets? */
+  DWORD         conf_override;                   /* allow changing of confname */
+  DWORD         cc_override;                     /* allow changing of ccname */
+  DWORD         noaddresses;                     /* Don't require address in tickets */
+  char          name[MAX_K_NAME_SZ];             /* last user used */
+  char          realm[MAX_K_NAME_SZ];            /* last realm used */
+  char          confname[FILENAME_MAX];
+  char          ccname[FILENAME_MAX];
+  char          def_confname[FILENAME_MAX];
+  char          def_ccname[FILENAME_MAX];
+  char          logins[FILE_MENU_MAX_LOGINS][MAX_K_NAME_SZ];
+} cns_reg_t;
+
+extern cns_reg_t cns_res;
+
+void cns_load_registry(void);
+void cns_save_registry(void);
diff --git a/mechglue/src/windows/cns/cnsres4.rc b/mechglue/src/windows/cns/cnsres4.rc
new file mode 100644
index 000000000..77e21e028
--- /dev/null
+++ b/mechglue/src/windows/cns/cnsres4.rc
@@ -0,0 +1,108 @@
+#include <windows.h>
+
+#define KRB4
+#include "cns.h"
+
+IDI_KWIN ICON PRELOAD cns.ico
+IDI_0_MIN ICON PRELOAD clock00.ico
+IDI_5_MIN ICON PRELOAD clock05.ico
+IDI_10_MIN ICON PRELOAD clock10.ico
+IDI_15_MIN ICON PRELOAD clock15.ico
+IDI_20_MIN ICON PRELOAD clock20.ico
+IDI_25_MIN ICON PRELOAD clock25.ico
+IDI_30_MIN ICON PRELOAD clock30.ico
+IDI_35_MIN ICON PRELOAD clock35.ico
+IDI_40_MIN ICON PRELOAD clock40.ico
+IDI_45_MIN ICON PRELOAD clock45.ico
+IDI_50_MIN ICON PRELOAD clock50.ico
+IDI_55_MIN ICON PRELOAD clock55.ico
+IDI_60_MIN ICON PRELOAD clock60.ico
+IDI_EXPIRED ICON PRELOAD clockexp.ico
+IDI_TICKET ICON PRELOAD clocktkt.ico
+
+IDM_KWIN MENU PRELOAD
+BEGIN
+	POPUP "&File"
+	BEGIN
+ 		MENUITEM "&Options...", IDM_OPTIONS
+ 		MENUITEM SEPARATOR
+ 		MENUITEM "E&xit", IDM_EXIT
+	END
+
+	POPUP "&Help"
+	BEGIN
+		MENUITEM "&Index\tF1", IDM_HELP_INDEX
+		MENUITEM SEPARATOR
+		MENUITEM "&About Kerberos...", IDM_ABOUT
+	END
+END
+
+IDA_KWIN ACCELERATORS PRELOAD
+BEGIN
+	VK_F1, IDM_HELP_INDEX, VIRTKEY
+END
+
+ID_KWIN DIALOG PRELOAD MOVEABLE DISCARDABLE 0, 0, 276, 114
+STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX
+CLASS KWIN_DIALOG_CLASS
+CAPTION KWIN_DIALOG_NAME
+MENU IDM_KWIN
+FONT 8, "Arial"
+BEGIN
+	CONTROL "       Start Time           End Time           Ticket", IDD_TICKET_LIST_TITLE, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 16, 7, 240, 8
+	CONTROL "", IDD_TICKET_LIST, "LISTBOX", LBS_NOTIFY | LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL, 8, 18, 261, 52
+	CONTROL "&Name", IDD_LOGIN_NAME_TITLE, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 6, 69, 27, 8
+   	CONTROL "&Instance", IDD_LOGIN_INSTANCE_TITLE, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 73, 69, 36, 8
+   	CONTROL "&Realm", IDD_LOGIN_REALM_TITLE, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 140, 69, 26, 8
+	CONTROL "&Password", IDD_LOGIN_PASSWORD_TITLE, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 207, 69, 36, 8
+   	CONTROL "", IDD_LOGIN_NAME, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 6, 79, 62, 12
+   	CONTROL "", IDD_LOGIN_INSTANCE, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 73, 79, 62, 12
+	CONTROL "", IDD_LOGIN_REALM, "EDIT", ES_LEFT | ES_AUTOHSCROLL | ES_UPPERCASE | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 140, 79, 62, 12
+   	CONTROL "", IDD_LOGIN_PASSWORD, "EDIT", ES_LEFT | ES_AUTOHSCROLL | ES_PASSWORD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 207, 79, 62, 12
+
+	CONTROL "&Change Password...", IDD_CHANGE_PASSWORD, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 6, 96, 74, 14
+	CONTROL "&Delete", IDD_TICKET_DELETE, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 122, 96, 52, 14
+	CONTROL "&Login", IDD_LOGIN, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 216, 96, 52, 14
+	CONTROL "", IDD_PASSWORD_CR2, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 5000, 5000, 0, 0
+END
+
+ID_PASSWORD DIALOG 96, 50, 143, 129
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Change Password"
+FONT 8, "Arial"
+BEGIN
+	CONTROL "&Name:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 9, 53, 8
+	CONTROL "", IDD_PASSWORD_NAME, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_GROUP | WS_TABSTOP, 61, 6, 76, 12
+	CONTROL "&Instance:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 26, 53, 8
+	CONTROL "", IDD_PASSWORD_INSTANCE, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 61, 23, 76, 12
+	CONTROL "&Realm:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 43, 53, 8
+	CONTROL "", IDD_PASSWORD_REALM, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 61, 40, 76, 12
+	CONTROL "&Old Password:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 60, 53, 8
+	CONTROL "", IDD_OLD_PASSWORD, "EDIT", ES_LEFT | ES_AUTOHSCROLL | ES_PASSWORD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 61, 57, 76, 12
+	CONTROL "&New Password:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 77, 53, 8
+	CONTROL "", IDD_NEW_PASSWORD1, "EDIT", ES_LEFT | ES_AUTOHSCROLL | ES_PASSWORD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 61, 74, 76, 12
+	CONTROL "&New Password:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 94, 53, 8
+	CONTROL "", IDD_NEW_PASSWORD2, "EDIT", ES_LEFT | ES_AUTOHSCROLL | ES_PASSWORD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 61, 91, 76, 12
+	CONTROL "", IDD_PASSWORD_CR, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 5000, 5000, 0, 0
+	CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 13, 110, 52, 14
+	CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 77, 110, 52, 14
+END
+
+ID_OPTS DIALOG 97, 52, 148, 107
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Kerberos Options"
+FONT 8, "Arial"
+BEGIN
+	CONTROL "&Conf file:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 9, 40, 8
+	CONTROL "", IDD_CONF, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 60, 6, 82, 12
+	CONTROL "&Realms file:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 26, 40, 8
+	CONTROL "", IDD_REALMS, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 60, 23, 82, 12
+	CONTROL "&Ticket lifetime:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 5, 43, 53, 8
+	CONTROL "", IDD_LIFETIME, "EDIT", ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 60, 40, 20, 12
+	CONTROL "minutes", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 85, 43, 46, 8
+	CONTROL "Action when login expires", 209, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 56, 138, 23
+	CONTROL "&Alert ", IDD_ALERT, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 31, 65, 28, 12
+	CONTROL "&Beep", IDD_BEEP, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 80, 65, 39, 12
+	CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 17, 87, 52, 14
+	CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 81, 87, 52, 14
+END
diff --git a/mechglue/src/windows/cns/cnsres5.rc b/mechglue/src/windows/cns/cnsres5.rc
new file mode 100644
index 000000000..d398078e3
--- /dev/null
+++ b/mechglue/src/windows/cns/cnsres5.rc
@@ -0,0 +1,215 @@
+//Microsoft Developer Studio generated resource script.
+//
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "cns.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_KWIN                ICON    PRELOAD DISCARDABLE "cns.ico"
+IDI_0_MIN               ICON    PRELOAD DISCARDABLE "clock00.ico"
+IDI_5_MIN               ICON    PRELOAD DISCARDABLE "clock05.ico"
+IDI_10_MIN              ICON    PRELOAD DISCARDABLE "clock10.ico"
+IDI_15_MIN              ICON    PRELOAD DISCARDABLE "clock15.ico"
+IDI_20_MIN              ICON    PRELOAD DISCARDABLE "clock20.ico"
+IDI_25_MIN              ICON    PRELOAD DISCARDABLE "clock25.ico"
+IDI_30_MIN              ICON    PRELOAD DISCARDABLE "clock30.ico"
+IDI_35_MIN              ICON    PRELOAD DISCARDABLE "clock35.ico"
+IDI_40_MIN              ICON    PRELOAD DISCARDABLE "clock40.ico"
+IDI_45_MIN              ICON    PRELOAD DISCARDABLE "clock45.ico"
+IDI_50_MIN              ICON    PRELOAD DISCARDABLE "clock50.ico"
+IDI_55_MIN              ICON    PRELOAD DISCARDABLE "clock55.ico"
+IDI_60_MIN              ICON    PRELOAD DISCARDABLE "clock60.ico"
+IDI_EXPIRED             ICON    PRELOAD DISCARDABLE "clockexp.ico"
+IDI_TICKET              ICON    PRELOAD DISCARDABLE "clocktkt.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDM_KWIN MENU PRELOAD DISCARDABLE 
+BEGIN
+    POPUP "&File"
+    BEGIN
+        MENUITEM "&Options...",                 IDM_OPTIONS
+        MENUITEM SEPARATOR
+        MENUITEM "E&xit",                       IDM_EXIT
+    END
+    POPUP "&Help"
+    BEGIN
+        MENUITEM "&Index\tF1",                  IDM_HELP_INDEX
+        MENUITEM SEPARATOR
+        MENUITEM "&About Kerberos...",          IDM_ABOUT
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDA_KWIN ACCELERATORS PRELOAD MOVEABLE PURE 
+BEGIN
+    VK_F1,          IDM_HELP_INDEX,         VIRTKEY 
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+ID_KWIN DIALOG PRELOAD DISCARDABLE  0, 0, 336, 115
+STYLE WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+#ifdef CYGNUS
+CAPTION "KerbNet"
+#else
+CAPTION "Kerberos"
+#endif
+MENU IDM_KWIN
+CLASS "KERBEROS"
+FONT 8, "Arial"
+BEGIN
+    CONTROL         "        Start Time            End Time            Ticket",
+                    IDD_TICKET_LIST_TITLE,"Static",SS_LEFTNOWORDWRAP | 
+                    WS_GROUP,16,7,311,8
+    LISTBOX         IDD_TICKET_LIST,8,18,319,52,LBS_OWNERDRAWFIXED | 
+                    LBS_DISABLENOSCROLL | WS_VSCROLL
+    LTEXT           "&Name",IDD_LOGIN_NAME_TITLE,6,69,27,8
+    LTEXT           "&Password",IDD_LOGIN_PASSWORD_TITLE,125,69,42,8
+    LTEXT           "&Realm",IDD_LOGIN_REALM_TITLE,239,69,26,8
+    EDITTEXT        IDD_LOGIN_NAME,6,79,84,12,ES_AUTOHSCROLL
+    EDITTEXT        IDD_LOGIN_PASSWORD,126,78,84,12,ES_PASSWORD | 
+                    ES_AUTOHSCROLL
+    EDITTEXT        IDD_LOGIN_REALM,239,79,84,12,ES_AUTOHSCROLL
+    PUSHBUTTON      "&Change Password...",IDD_CHANGE_PASSWORD,6,96,84,14
+    PUSHBUTTON      "&Delete",IDD_TICKET_DELETE,141,96,52,14
+    DEFPUSHBUTTON   "&Login",IDD_LOGIN,271,96,52,14
+    PUSHBUTTON      "",IDD_PASSWORD_CR2,5000,5000,6,6,NOT WS_TABSTOP
+END
+
+ID_PASSWORD DIALOG DISCARDABLE  96, 50, 143, 112
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Change Password"
+FONT 8, "Arial"
+BEGIN
+    LTEXT           "&Name:",-1,5,9,53,8,NOT WS_GROUP
+    EDITTEXT        IDD_PASSWORD_NAME,61,6,76,12,ES_AUTOHSCROLL | WS_GROUP
+    LTEXT           "&Realm:",-1,5,26,53,8,NOT WS_GROUP
+    EDITTEXT        IDD_PASSWORD_REALM,61,23,76,12,ES_AUTOHSCROLL
+    LTEXT           "&Old Password:",-1,5,43,53,8,NOT WS_GROUP
+    EDITTEXT        IDD_OLD_PASSWORD,61,40,76,12,ES_PASSWORD | 
+                    ES_AUTOHSCROLL
+    LTEXT           "&New Password:",-1,5,60,53,8,NOT WS_GROUP
+    EDITTEXT        IDD_NEW_PASSWORD1,61,57,76,12,ES_PASSWORD | 
+                    ES_AUTOHSCROLL
+    LTEXT           "&New Password:",-1,5,77,53,8,NOT WS_GROUP
+    EDITTEXT        IDD_NEW_PASSWORD2,61,74,76,12,ES_PASSWORD | 
+                    ES_AUTOHSCROLL
+    PUSHBUTTON      "",IDD_PASSWORD_CR,5000,5000,0,0,NOT WS_TABSTOP
+    DEFPUSHBUTTON   "OK",IDOK,13,93,52,14,WS_GROUP
+    PUSHBUTTON      "Cancel",IDCANCEL,77,93,52,14
+END
+
+ID_OPTS DIALOG DISCARDABLE  97, 52, 169, 138
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+#ifdef CYGNUS
+CAPTION "KerbNet Options"
+#else
+CAPTION "Kerberos Options"
+#endif
+FONT 8, "Arial"
+BEGIN
+    LTEXT           "&Config file:",-1,5,9,40,8,NOT WS_GROUP
+    EDITTEXT        IDD_CONF,70,6,92,12,ES_AUTOHSCROLL
+    LTEXT           "Cre&dential cache:",-1,5,26,58,8,NOT WS_GROUP
+    EDITTEXT        IDD_CCACHE,70,23,92,12,ES_AUTOHSCROLL
+    LTEXT           "&Ticket lifetime:",-1,5,43,53,8,NOT WS_GROUP
+    EDITTEXT        IDD_LIFETIME,70,40,32,12,ES_AUTOHSCROLL
+    LTEXT           "minutes",-1,109,42,46,8,NOT WS_GROUP
+    GROUPBOX        "Action when login expires",IDD_ACTIONS,5,56,158,23,
+                    WS_GROUP
+    CONTROL         "&Alert ",IDD_ALERT,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,41,65,28,12
+    CONTROL         "&Beep",IDD_BEEP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+                    95,65,39,12
+    GROUPBOX        "Ticket options",IDD_TKOPT,5,86,158,23,WS_GROUP
+    CONTROL         "&Forwardable",IDD_FORWARDABLE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,25,95,65,12
+    CONTROL         "&NoAddresses",IDD_NOADDRESSES,"Button",BS_AUTOCHECKBOX |
+                    WS_TABSTOP,90,95,65,12
+    DEFPUSHBUTTON   "OK",IDOK,19,117,52,14
+    PUSHBUTTON      "Cancel",IDCANCEL,95,117,52,14
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""cns.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
+#include "..\version.rc"
diff --git a/mechglue/src/windows/cns/debug.c b/mechglue/src/windows/cns/debug.c
new file mode 100644
index 000000000..d35e64ed5
--- /dev/null
+++ b/mechglue/src/windows/cns/debug.c
@@ -0,0 +1,91 @@
+#ifdef DEBUG
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <crtdbg.h>
+
+void
+OutputHeading(const char *explanation)
+{
+  _RPT1(_CRT_WARN,
+	"\n\n%s:\n*********************************\n", explanation );
+}
+
+/*
+ * The following macros set and clear, respectively, given bits
+ * of the C runtime library debug flag, as specified by a bitmask.
+ */
+#define  SET_CRT_DEBUG_FIELD(a) \
+            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+#define  CLEAR_CRT_DEBUG_FIELD(a) \
+            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
+
+_CrtMemState s1;
+_CrtMemState s2;
+_CrtMemState s3;
+static _CrtMemState *ss1 = NULL;
+static _CrtMemState *ss2 = NULL;
+
+void debug_init();
+
+void
+debug_check()
+{
+  _CrtMemState *temp;
+
+  OutputHeading("Checking memory...");
+
+  if (ss1 == NULL) {
+    debug_init();
+    ss1 = &s1;
+    ss2 = &s2;
+  }
+
+  _CrtCheckMemory();
+
+  /*   _CrtMemDumpAllObjectsSince( NULL ); */
+
+  _CrtMemCheckpoint( &s2 );
+  
+  if ( _CrtMemDifference( &s3, &s1, &s2 ) )
+    _CrtMemDumpStatistics( &s3 );
+
+  /*   _CrtDumpMemoryLeaks(); */
+
+  /*
+   * swap the snapshots around
+   */
+  temp = ss1;
+  ss1 = ss2;
+  ss2 = temp;
+}
+
+void
+debug_init()
+{
+  /* Send all reports to STDOUT */
+   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
+   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
+   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
+   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
+   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
+   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
+
+   _CrtMemCheckpoint( &s1 );
+
+   /*
+    * Set the debug-heap flag so that freed blocks are kept on the
+    * linked list, to catch any inadvertent use of freed memory
+    */
+   SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );
+
+
+   /*
+    * Set the debug-heap flag so that memory leaks are reported when
+    * the process terminates. Then, exit.
+    */
+   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
+}
+#endif /* DEBUG */
+
diff --git a/mechglue/src/windows/cns/heap.c b/mechglue/src/windows/cns/heap.c
new file mode 100644
index 000000000..46d39df0b
--- /dev/null
+++ b/mechglue/src/windows/cns/heap.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <malloc.h>
+
+void heapdump( void )
+{
+   _HEAPINFO hinfo;
+   int heapstatus;
+   hinfo._pentry = NULL;
+   while( ( heapstatus = _heapwalk( &hinfo ) ) == _HEAPOK )
+   { printf( "%6s block at %Fp of size %4.4X\n",
+        ( hinfo._useflag == _USEDENTRY ? "USED" : "FREE" ),
+          hinfo._pentry, hinfo._size );
+   }
+
+   switch( heapstatus )
+   {
+   case _HEAPEMPTY:
+      printf( "OK - empty heap\n" );
+      break;
+   case _HEAPEND:
+      printf( "OK - end of heap\n" );
+      break;
+   case _HEAPBADPTR:
+      printf( "ERROR - bad pointer to heap\n" );
+      break;
+   case _HEAPBADBEGIN:
+      printf( "ERROR - bad start of heap\n" );
+      break;
+   case _HEAPBADNODE:
+      printf( "ERROR - bad node in heap\n" );
+      break;
+   }
+}
diff --git a/mechglue/src/windows/cns/kerbnet.doc b/mechglue/src/windows/cns/kerbnet.doc
new file mode 100644
index 0000000000000000000000000000000000000000..161b3c31eabb25652b3a0009cadf4f8f354c03cb
GIT binary patch
literal 22528
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
S#UH}{bH4S*pB?-@&i@YzaoD5)

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/kerbnet.hlp b/mechglue/src/windows/cns/kerbnet.hlp
new file mode 100644
index 0000000000000000000000000000000000000000..c25fafcd5b5d4e139a611ab196bd7202605625b7
GIT binary patch
literal 16334
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

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/cns/kerbnet.hpj b/mechglue/src/windows/cns/kerbnet.hpj
new file mode 100644
index 000000000..7d0356993
--- /dev/null
+++ b/mechglue/src/windows/cns/kerbnet.hpj
@@ -0,0 +1,133 @@
+;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+; Help Project File for KERBNET 
+;
+;  You may edit this file.
+;
+;  It's probably best not to change the CONTENTS= value 
+;  unless you rename the IDH_CONTENTS context string in 
+;  the KERBNET.DOC file.
+;
+
+[OPTIONS]
+; The optional ROOT= entry sets the working directory for the Help Compiler 
+; ROOT=C:\PROJECT
+
+; The optional BMROOT= entry sets forth the directories which the
+; help compiler will search for bitmaps used in the Help system.
+;
+;BMROOT=C:\ROBOHELP
+
+; The CONTENTS= tells the help Engine which topic contains the contents 
+CONTENTS=IDH_CONTENTS
+
+; Title is Displayed in the Title Bar of WINHELP.EXE
+TITLE=Kerb*Net
+
+; The BUILD= setting allows complex Help systems which require
+; different versions to use the same source.  This is similar to #ifdef's 
+; in the 'C' language.  Everything to the right of the = sign in the 
+; BUILD= statement is an EXPRESSION.  See the Help compiler 
+; documentation for more information about build expressions.
+BUILD=WINDOWS
+
+; The Warning Level is used by the Help Compiler (HC.EXE)
+; WARNING=1  - Only the most severe warnings are reported
+; WARNING=2  - Intermediate Level of warnings
+; WARNING=3  - Most stringent error reporting
+
+; The Compress option is used by the Help Compiler to make 
+; smaller, faster loading .HLP files.  However, using compression
+; increases Compile times.
+; COMPRESS=YES, ON, OFF, NO, TRUE or FALSE
+
+
+OLDKEYPHRASE=NO
+OPTCDROM=0
+NOTES=1
+REPORT=YES
+COMPRESS=12
+ERRORLOG=C:\windows\desktop\kerberos 5\win95 gui\cns help\KERBNET.ERR
+[BUILDTAGS]
+; The Build Tags section specifies to the Help Compiler the names
+; of all the valid build tags used in this Help project.  The [BUILDTAGS]
+; section is optional.
+WINDOWS
+
+
+[CONFIG]
+; The config section allows you to define some macros which will be
+; executed when the help system is first executed.
+;
+; The next line gives you browse buttons:
+;
+BrowseButtons()
+
+;
+; To create a glossary button which displays a list of defined terms
+; in a secondary window, remove the semi colon at the start of the next
+; line and do the same with the Glossary window in the [WINDOWS] section
+;CreateButton("Glossary_Btn","&Glossary","JI(`bubble.hlp>Gloss',`IDH_Glossary')")
+;
+ 
+
+[FILES]
+; The files section is where you specify to the Help Compiler which
+; Rich Text Format (.RTF) (your help source) files will be used in the
+; Help system.  RoboHELP generates and maintains the main .RTF 
+; file for your Help System.  If you desire to have multiple .RTF files,
+; simply add the additonal names to the [FILES] section.
+
+KERBNET.RTF
+[ALIAS]
+; The Alias  section allows you to set up aliases for context strings 
+; in your help system.  
+; 
+; Brief example:
+; 
+;    IDH_UserID = IDH_RoboGenerated_Id
+;    IDH_WMP_MenuID = IDH_RoboGenerated_Id
+;    IDH_Any = IDH_AnyOther
+
+[MAP]
+; 
+; The Map Section is where the C language #defines are translated 
+; or mapped into the Help System Context Strings.  Standard C syntax
+; can be employed.  The .HH file is meant to be #include(d) into your 
+; Windows application source code.
+; 
+
+[BITMAPS]
+; 
+; The [BITMAPS] section is where you list any Bitmaps which have
+; been placed by reference in the Help System.  See the Help compiler
+; documentation for more information about placing bitmaps.
+; 
+; The [BITMAPS] section is not really required under Windows 3.1,
+; with the advent of the BMROOT item in the [OPTIONS] section.
+; 
+;FOO1.BMP
+;FOO2.BMP
+;C:\FOO\FOO3.BMP
+;And So On
+
+[WINDOWS]
+; Windows Help can display help in one of 5 secondary windows.
+; Before using a secondary window, the window must be defined
+; in this section:
+; 
+;Gloss = "Glossary",(100,100,350,350),0,(255,255,255),(255,255,255)
+main=,,0,,
+
+[BAGGAGE]
+; 
+; The Baggage section allows the user to include files which
+; will be placed in the internal file system for WinHelp.  
+; Using files from Baggage is a little faster for CDROM, since
+; the CDROM drive table does not need to be read from disk.
+;
+; Baggage files are referred to as regular bitmaps, except
+; that you prefix the filename with '!'.
+;
+;    For Instance:
+;       {bmc !bitmap.bmp} instead of {bmc bitmap.bmp}
+;
diff --git a/mechglue/src/windows/cns/kpasswd.c b/mechglue/src/windows/cns/kpasswd.c
new file mode 100644
index 000000000..3219ea2aa
--- /dev/null
+++ b/mechglue/src/windows/cns/kpasswd.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997 Cygnus Solutions.
+ *
+ * Author:  Michael Graff
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "krb5.h"
+#include "com_err.h"
+
+#include "cns.h"
+
+#include "../lib/gic.h"
+
+/*
+ * k5_change_password
+ * 
+ * Use the new functions to change the password.
+ */
+krb5_error_code
+k5_change_password(HWND hwnd, krb5_context context, char *user, char *realm,
+		   char *opasswd, char *npasswd, char **text)
+{
+	krb5_error_code	           ret;
+	krb5_data                  result_string;
+	krb5_data                  result_code_string;
+	int                        result_code;
+	krb5_get_init_creds_opt    opts;
+	krb5_creds                 creds;
+	krb5_principal             princ;
+	char                      *name;
+	gic_data                   gd;
+
+	*text = NULL;
+
+	name = malloc(strlen(user) + strlen(realm) + 2);
+	if (name == NULL) {
+		*text = "Failed to allocate memory while changing password";
+		return 1;
+	}
+	sprintf(name, "%s@%s", user, realm);
+
+	ret = krb5_parse_name(context, name, &princ);
+	free(name);
+	if (ret) {
+		*text = "while parsing name";
+		return ret;
+	}
+
+	krb5_get_init_creds_opt_init(&opts);
+	krb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
+	krb5_get_init_creds_opt_set_renew_life(&opts, 0);
+	krb5_get_init_creds_opt_set_forwardable(&opts, 0);
+	krb5_get_init_creds_opt_set_proxiable(&opts, 0);
+
+	gd.hinstance = hinstance;
+	gd.hwnd = hwnd;
+	gd.id = ID_VARDLG;
+
+	ret = krb5_get_init_creds_password(context, &creds, princ, opasswd, gic_prompter,
+		&gd, 0, "kadmin/changepw", &opts);
+	if (ret) {
+		*text = "while getting creds";
+		return ret;
+	}
+
+	ret = krb5_change_password(context, &creds, npasswd, &result_code, &result_code_string,
+		&result_string);
+	if (ret) {
+		*text = "while changing password";
+		return ret;
+	}
+
+	if (result_code) {
+		*text = malloc(result_code_string.length + result_string.length + 3);
+		if (*text == NULL)
+			return -1;
+
+		sprintf(*text, "%.*s%s%.*s",
+			result_code_string.length, result_code_string.data,
+			(result_string.length ? ": " : ""),
+			result_string.length,
+			result_string.data ? result_string.data : "");
+	}
+
+	return 0;
+}
diff --git a/mechglue/src/windows/cns/krb5.def b/mechglue/src/windows/cns/krb5.def
new file mode 100644
index 000000000..6a88ffbb9
--- /dev/null
+++ b/mechglue/src/windows/cns/krb5.def
@@ -0,0 +1,9 @@
+NAME            KRB5
+DESCRIPTION     'KRB5 - Credentials Manager'
+EXETYPE         WINDOWS
+STUB            'WINSTUB.EXE'
+SEGMENTS _TEXT CLASS 'CODE' PRELOAD
+CODE            DISCARDABLE
+DATA PRELOAD MULTIPLE MOVEABLE
+HEAPSIZE 20480
+STACKSIZE 20480
diff --git a/mechglue/src/windows/cns/krbini.h b/mechglue/src/windows/cns/krbini.h
new file mode 100644
index 000000000..8daf93b73
--- /dev/null
+++ b/mechglue/src/windows/cns/krbini.h
@@ -0,0 +1,37 @@
+/* Kerberos changed window message */
+#define WM_KERBEROS_CHANGED "Kerberos Changed"
+
+/* Kerberos Windows initialization file */
+#define KERBEROS_INI    "kerberos.ini"
+#ifdef CYGNUS
+#define KERBEROS_HLP    "kerbnet.hlp"
+#else
+#define KERBEROS_HLP    "krb5.hlp"
+#endif
+#define INI_DEFAULTS    "Defaults"
+#define   INI_USER        "User"          /* Default user */
+#define   INI_INSTANCE    "Instance"      /* Default instance */
+#define   INI_REALM       "Realm"         /* Default realm */
+#define   INI_POSITION    "Position"
+#define   INI_OPTIONS     "Options"
+#define   INI_DURATION    "Duration"   /* Ticket duration in minutes */
+#define INI_EXPIRATION  "Expiration" /* Action on expiration (alert or beep) */
+#define   INI_ALERT       "Alert"
+#define   INI_BEEP        "Beep"
+#define   INI_FILES       "Files"
+#ifdef KRB4
+#define   INI_KRB_CONF    "krb.conf"     /* Location of krb.conf file */
+#define   DEF_KRB_CONF    "krb.conf"      /* Default name for krb.conf file */
+#endif /* KRB4 */
+#ifdef KRB5
+#define INI_KRB5_CONF   "krb5.ini"	/* From k5-config.h */
+#define INI_KRB_CONF    INI_KRB5_CONF	/* Location of krb.conf file */
+#define DEF_KRB_CONF    INI_KRB5_CONF	/* Default name for krb.conf file */
+#define INI_TICKETOPTS  "TicketOptions" /* Ticket options */
+#define   INI_FORWARDABLE  "Forwardable" /* get forwardable tickets */
+#define INI_KRB_CCACHE  "krb5cc"       	/* From k5-config.h */
+#endif /* KRB5 */
+#define INI_KRB_REALMS  "krb.realms"    /* Location of krb.realms file */
+#define DEF_KRB_REALMS  "krb.realms"    /* Default name for krb.realms file */
+#define INI_RECENT_LOGINS "Recent Logins"    
+#define INI_LOGIN       "Login"
diff --git a/mechglue/src/windows/cns/options.c b/mechglue/src/windows/cns/options.c
new file mode 100644
index 000000000..9e7c30e94
--- /dev/null
+++ b/mechglue/src/windows/cns/options.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+/*
+ * functions to tweak the options dialog
+ */
+
+#include <windows.h>
+#include <windowsx.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "cns.h"
+#include "tktlist.h"
+#include "cns_reg.h"
+
+/*
+ * Function: Process WM_INITDIALOG messages for the options dialog.
+ * 	Set up all initial dialog values from the KERBEROS_INI file.
+ *
+ * Returns: TRUE if we didn't set the focus here,
+ * 	    FALSE if we did.
+ */
+BOOL
+opts_initdialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
+{
+  center_dialog(hwnd);
+  set_dialog_font(hwnd, hfontdialog);
+
+  /* krb.conf file */
+  strcpy(confname, cns_res.confname);
+#ifndef _WIN32
+  _strupr(confname);
+#endif
+  SetDlgItemText(hwnd, IDD_CONF, confname);
+
+  if (cns_res.conf_override == 0)
+      EnableWindow(GetDlgItem(hwnd, IDD_CONF), 0);
+  else
+      EnableWindow(GetDlgItem(hwnd, IDD_CONF), 1);
+
+  /* Credential cache file */
+  strcpy(ccname, cns_res.ccname);
+#ifndef _WIN32
+  _strupr(ccname);
+#endif
+  SetDlgItemText(hwnd, IDD_CCACHE, ccname);
+
+  if (cns_res.cc_override == 0)
+      EnableWindow(GetDlgItem(hwnd, IDD_CCACHE), 0);
+  else
+      EnableWindow(GetDlgItem(hwnd, IDD_CCACHE), 1);
+
+  /* Ticket duration */
+  SetDlgItemInt(hwnd, IDD_LIFETIME, cns_res.lifetime, FALSE);
+
+  /* Expiration action */
+  alert = cns_res.alert;
+  SendDlgItemMessage(hwnd, IDD_ALERT, BM_SETCHECK, alert, 0);
+
+  beep = cns_res.beep;
+  SendDlgItemMessage(hwnd, IDD_BEEP, BM_SETCHECK, beep, 0);
+
+  forwardable = cns_res.forwardable;
+  SendDlgItemMessage(hwnd, IDD_FORWARDABLE, BM_SETCHECK, forwardable, 0);
+
+  noaddresses = cns_res.noaddresses;
+  SendDlgItemMessage(hwnd, IDD_NOADDRESSES, BM_SETCHECK, noaddresses, 0);
+ 
+  return TRUE;
+}
+
+
+/*
+ * Function: Process WM_COMMAND messages for the options dialog.
+ */
+void
+opts_command(HWND hwnd, int cid, HWND hwndCtl, UINT codeNotify)
+{
+  char newname[FILENAME_MAX];
+  BOOL b;
+  int lifetime;
+
+  switch (cid) {
+  case IDOK:
+
+    /* Ticket duration */
+    lifetime = GetDlgItemInt(hwnd, IDD_LIFETIME, &b, FALSE);
+
+    if (!b) {
+      MessageBox(hwnd, "Lifetime must be a number!", "",
+		 MB_OK | MB_ICONEXCLAMATION);
+      return; /* TRUE */
+    }
+
+    cns_res.lifetime = lifetime;
+
+    if (cns_res.conf_override) {
+	    /* krb.conf file */
+	    GetDlgItemText(hwnd, IDD_CONF, newname, sizeof(newname));
+	    trim(newname);
+	    if (newname[0] == '\0')
+		    strcpy(newname, cns_res.def_confname);
+	    if (_stricmp(newname, confname)) {  /* file name changed */
+	      MessageBox(NULL,
+			 "Change to configuration file location requires a restart"
+			 "of KerbNet.\n"
+			 "Please exit this application and restart it for the change to take"
+			 "effect",
+			 "", MB_OK | MB_ICONEXCLAMATION);
+	    }
+	    strcpy(confname, newname);
+    }
+
+    /* Credential cache file */
+    GetDlgItemText(hwnd, IDD_CCACHE, newname, sizeof(newname));
+    trim(newname);
+
+    if (newname[0] == '\0')
+	    strcpy(newname, cns_res.def_ccname);
+
+    if (_stricmp(ccname, newname)) {     /* Did we change ccache file? */
+      krb5_error_code code;
+      krb5_ccache cctemp;
+
+      code = k5_init_ccache(&cctemp);
+      if (code) {                     /* Problem opening new one? */
+	com_err(NULL, code, 
+		"while changing ccache.\r\nRestoring old ccache.");
+      } else {
+        strcpy(ccname, newname);
+        strcpy(cns_res.ccname, newname);
+
+	code = krb5_cc_close(k5_context, k5_ccache);
+	k5_ccache = cctemp;         /* Copy new into old */
+	if (k5_name_from_ccache(k5_ccache)) {
+	  kwin_init_name(GetParent(hwnd), "");
+	  kwin_set_default_focus(GetParent(hwnd));
+	}
+	ticket_init_list(GetDlgItem (GetParent(hwnd),
+				     IDD_TICKET_LIST));
+      }
+    }
+
+    /*
+     * get values for the clickboxes
+     */
+    alert = SendDlgItemMessage(hwnd, IDD_ALERT, BM_GETCHECK, 0, 0);
+    cns_res.alert = alert;
+
+    beep = SendDlgItemMessage(hwnd, IDD_BEEP, BM_GETCHECK, 0, 0);
+    cns_res.beep = beep;
+
+    forwardable = SendDlgItemMessage(hwnd, IDD_FORWARDABLE, BM_GETCHECK, 0, 0);
+    cns_res.forwardable = forwardable;
+
+    noaddresses = SendDlgItemMessage(hwnd, IDD_NOADDRESSES, BM_GETCHECK, 0, 0);
+    cns_res.noaddresses = noaddresses;
+
+    EndDialog(hwnd, IDOK);
+
+    return; /* TRUE */
+
+  case IDCANCEL:
+    EndDialog(hwnd, IDCANCEL);
+
+    return; /* TRUE */
+  }
+
+  return; /* FALSE */
+}
+
+
+/*
+ * Function: Process dialog specific messages for the opts dialog.
+ */
+BOOL CALLBACK
+opts_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+  switch (message) {
+    HANDLE_MSG(hwnd, WM_INITDIALOG, opts_initdialog);
+
+    HANDLE_MSG(hwnd, WM_COMMAND, opts_command);
+  }
+
+  return FALSE;
+}
+
+
+/*
+ * Function: Display and process the options dialog.
+ *
+ * Parameters:
+ *	hwnd - the parent window for the dialog
+ *
+ * Returns: TRUE if the dialog completed successfully, FALSE otherwise.
+ */
+BOOL
+opts_dialog(HWND hwnd)
+{
+  DLGPROC dlgproc;
+  int rc;
+
+#ifdef _WIN32
+  dlgproc = opts_dlg_proc;
+#else
+  dlgproc = (FARPROC)MakeProcInstance(opts_dlg_proc, hinstance);
+  assert(dlgproc != NULL);
+
+  if (dlgproc == NULL)
+    return FALSE;
+#endif
+
+  rc = DialogBox(hinstance, MAKEINTRESOURCE(ID_OPTS), hwnd, dlgproc);
+  assert(rc != -1);
+
+#ifndef _WIN32
+  FreeProcInstance((FARPROC)dlgproc);
+#endif
+
+  return rc == IDOK;
+}
diff --git a/mechglue/src/windows/cns/password.c b/mechglue/src/windows/cns/password.c
new file mode 100644
index 000000000..ad02201f1
--- /dev/null
+++ b/mechglue/src/windows/cns/password.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+/*
+ * functions to tweak the options dialog
+ */
+
+#include <windows.h>
+#include <windowsx.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "cns.h"
+
+/*
+ * Function: Changes the password.
+ *
+ * Parameters:
+ *	hwnd - the current window from which command was invoked.
+ *
+ *	name - name of user to change password for
+ *
+ *	instance - instance of user to change password for
+ *
+ *	realm - realm in which to change password
+ *
+ *	oldpw - the old password
+ *
+ *	newpw - the new password to change to
+ *
+ * Returns: TRUE if change took place, FALSE otherwise.
+ */
+BOOL
+change_password(HWND hwnd, char *name, char *instance, char *realm,
+		char *oldpw, char *newpw)
+{
+#ifdef KRB4
+  des_cblock new_key;
+  char *ret_st;
+  int krc;
+  char *p;
+  CREDENTIALS *c;
+  int ncred;
+  char pname[ANAME_SZ];
+  char pinstance[INST_SZ];
+
+  push_credentials(&c, pname, pinstance, &ncred);
+  krc = krb_get_pw_in_tkt(name, instance, realm, PWSERV_NAME, KADM_SINST,
+			  1, oldpw);
+
+  if (krc != KSUCCESS) {
+    if (krc == INTK_BADPW)
+      p = "Old password is incorrect";
+    else
+      p = krb_get_err_text(krc);
+    pop_credentials(c, pname, pinstance, ncred);
+    MessageBox(hwnd, p, "", MB_OK | MB_ICONEXCLAMATION);
+
+    return FALSE;
+  }
+
+  krc = kadm_init_link(PWSERV_NAME, KRB_MASTER, realm);
+
+  if (krc != KSUCCESS) {
+    pop_credentials(c, pname, pinstance, ncred);
+    MessageBox(hwnd, kadm_get_err_text(krc), "", MB_OK | MB_ICONEXCLAMATION);
+
+    return FALSE;
+  }
+
+  des_string_to_key(newpw, new_key);
+  krc = kadm_change_pw2(new_key, newpw, &ret_st);
+  pop_credentials(c, pname, pinstance, ncred);
+
+  if (ret_st != NULL)
+    free(ret_st);
+
+  if (krc != KSUCCESS) {
+    MessageBox(hwnd, kadm_get_err_text(krc), "", MB_OK | MB_ICONEXCLAMATION);
+
+    return FALSE;
+  }
+
+  return TRUE;
+#endif /* KRB4 */
+
+#ifdef KRB5
+  char *msg;                                  /* Message string */
+  krb5_error_code code;                       /* Return value */
+  code = k5_change_password(hwnd, k5_context, name, realm, oldpw, newpw, &msg);
+
+  if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+      MessageBox(NULL, "Password incorrect", NULL, MB_ICONEXCLAMATION);
+  else if (code == -1)
+	  MessageBox(NULL, (msg ? msg : "Cannot change password"), NULL,
+		 MB_ICONEXCLAMATION);
+  else if (code != 0)
+	  com_err(NULL, code, (msg ? msg : "while changing password."));
+  else
+	  MessageBox(NULL, (msg ? msg : "Password changed"), "Kerberos", MB_OK | MB_APPLMODAL);
+
+  return (code == 0);
+
+#endif /* KRB5 */
+}
+/*
+ * Function: Process WM_COMMAND messages for the password dialog.
+ */
+void
+password_command(HWND hwnd, int cid, HWND hwndCtl, UINT codeNotify)
+{
+  char name[ANAME_SZ];
+  char instance[INST_SZ];
+  char realm[REALM_SZ];
+  char oldpw[MAX_KPW_LEN];
+  char newpw1[MAX_KPW_LEN];
+  char newpw2[MAX_KPW_LEN];
+  HCURSOR hcursor;
+  BOOL b;
+  int id;
+
+  if (codeNotify != BN_CLICKED) {
+    GetDlgItemText(hwnd, IDD_PASSWORD_NAME, name, sizeof(name));
+    trim(name);
+    GetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm, sizeof(realm));
+    trim(realm);
+    GetDlgItemText(hwnd, IDD_OLD_PASSWORD, oldpw, sizeof(oldpw));
+    GetDlgItemText(hwnd, IDD_NEW_PASSWORD1, newpw1, sizeof(newpw1));
+    GetDlgItemText(hwnd, IDD_NEW_PASSWORD2, newpw2, sizeof(newpw2));
+    b = strlen(name) && strlen(realm) && strlen(oldpw) &&
+      strlen(newpw1) && strlen(newpw2);
+    EnableWindow(GetDlgItem(hwnd, IDOK), b);
+    id = (b) ? IDOK : IDD_PASSWORD_CR;
+    SendMessage(hwnd, DM_SETDEFID, id, 0);
+
+    return; /* FALSE */
+  }
+
+  switch (cid) {
+  case IDOK:
+    if (isblocking)
+      return; /* TRUE */
+
+    GetDlgItemText(hwnd, IDD_PASSWORD_NAME, name, sizeof(name));
+    trim(name);
+    GetDlgItemText(hwnd, IDD_PASSWORD_INSTANCE, instance, sizeof(instance));
+    trim(instance);
+    GetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm, sizeof(realm));
+    trim(realm);
+    GetDlgItemText(hwnd, IDD_OLD_PASSWORD, oldpw, sizeof(oldpw));
+    GetDlgItemText(hwnd, IDD_NEW_PASSWORD1, newpw1, sizeof(newpw1));
+    GetDlgItemText(hwnd, IDD_NEW_PASSWORD2, newpw2, sizeof(newpw2));
+
+    if (strcmp(newpw1, newpw2) != 0) {
+      MessageBox(hwnd, "The two passwords you entered don't match!", "",
+		 MB_OK | MB_ICONEXCLAMATION);
+      SetDlgItemText(hwnd, IDD_NEW_PASSWORD1, "");
+      SetDlgItemText(hwnd, IDD_NEW_PASSWORD2, "");
+      PostMessage(hwnd, WM_NEXTDLGCTL,
+		  (WPARAM)GetDlgItem(hwnd, IDD_NEW_PASSWORD1), MAKELONG(1, 0));
+
+      return; /* TRUE */
+    }
+
+    hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+    start_blocking_hook(BLOCK_MAX_SEC);
+
+    if (change_password(hwnd, name, instance, realm, oldpw, newpw1))
+      EndDialog(hwnd, IDOK);
+    else
+      PostMessage(hwnd, WM_NEXTDLGCTL,
+		  (WPARAM)GetDlgItem(hwnd, IDD_OLD_PASSWORD), MAKELONG(1, 0));
+
+    end_blocking_hook();
+    SetCursor(hcursor);
+
+    return; /* TRUE */
+
+  case IDCANCEL:
+    if (isblocking)
+      WSACancelBlockingCall();
+    EndDialog(hwnd, IDCANCEL);
+
+    return; /* TRUE */
+
+  case IDD_PASSWORD_CR:
+    id = GetDlgCtrlID(GetFocus());
+    assert(id != 0);
+
+    if (id == IDD_NEW_PASSWORD2)
+      PostMessage(hwnd, WM_NEXTDLGCTL,
+		  (WPARAM)GetDlgItem(hwnd, IDD_PASSWORD_NAME), MAKELONG(1, 0));
+    else
+      PostMessage(hwnd, WM_NEXTDLGCTL, 0, 0);
+
+    return; /* TRUE */
+
+  }
+
+  return; /* FALSE */
+}
+
+
+/*
+ * Function: Process WM_INITDIALOG messages for the password dialog.
+ * 	Set up all initial dialog values from the parent dialog.
+ *
+ * Returns: TRUE if we didn't set the focus here,
+ * 	FALSE if we did.
+ */
+BOOL
+password_initdialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
+{
+  char name[ANAME_SZ];
+  char realm[REALM_SZ];
+  HWND hwndparent;
+  int id;
+#ifdef KRB4
+  char instance[INST_SZ];
+#endif
+
+  center_dialog(hwnd);
+  set_dialog_font(hwnd, hfontdialog);
+
+  hwndparent = GetParent(hwnd);
+  assert(hwndparent != NULL);
+
+  GetDlgItemText(hwndparent, IDD_LOGIN_NAME, name, sizeof(name));
+  trim(name);
+  SetDlgItemText(hwnd, IDD_PASSWORD_NAME, name);
+
+#ifdef KRB4
+  GetDlgItemText(hwndparent, IDD_LOGIN_INSTANCE, instance, sizeof(instance));
+  trim(instance);
+  SetDlgItemText(hwnd, IDD_PASSWORD_INSTANCE, instance);
+#endif
+
+  GetDlgItemText(hwndparent, IDD_LOGIN_REALM, realm, sizeof(realm));
+  trim(realm);
+  SetDlgItemText(hwnd, IDD_PASSWORD_REALM, realm);
+
+  if (strlen(name) == 0)
+    id = IDD_PASSWORD_NAME;
+  else if (strlen(realm) == 0)
+    id = IDD_PASSWORD_REALM;
+  else
+    id = IDD_OLD_PASSWORD;
+
+  SetFocus(GetDlgItem(hwnd, id));
+
+  return FALSE;
+}
+
+
+/*
+ * Function: Process dialog specific messages for the password dialog.
+ */
+BOOL CALLBACK
+password_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+  switch (message) {
+
+    HANDLE_MSG(hwnd, WM_INITDIALOG, password_initdialog);
+
+    HANDLE_MSG(hwnd, WM_COMMAND, password_command);
+
+  case WM_SETCURSOR:
+    if (isblocking) {
+      SetCursor(LoadCursor(NULL, IDC_WAIT));
+      SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
+
+      return TRUE;
+    }
+    break;
+  }
+
+  return FALSE;
+}
+
+
+/*
+ * Function: Display and process the password dialog.
+ *
+ * Parameters:
+ *	hwnd - the parent window for the dialog
+ *
+ * Returns: TRUE if the dialog completed successfully, FALSE otherwise.
+ */
+BOOL
+password_dialog(HWND hwnd)
+{
+  DLGPROC dlgproc;
+  int rc;
+
+#ifdef _WIN32
+  dlgproc = password_dlg_proc;
+#else
+  dlgproc = (FARPROC)MakeProcInstance(password_dlg_proc, hinstance);
+  assert(dlgproc != NULL);
+
+  if (dlgproc == NULL)
+    return FALSE;
+#endif
+
+  rc = DialogBox(hinstance, MAKEINTRESOURCE(ID_PASSWORD), hwnd, dlgproc);
+  assert(rc != -1);
+
+#ifndef _WIN32
+  FreeProcInstance((FARPROC)dlgproc);
+#endif
+
+  return rc == IDOK;
+}
diff --git a/mechglue/src/windows/cns/tktlist.c b/mechglue/src/windows/cns/tktlist.c
new file mode 100644
index 000000000..68a6f1c62
--- /dev/null
+++ b/mechglue/src/windows/cns/tktlist.c
@@ -0,0 +1,442 @@
+/*
+ * tktlist.c
+ *
+ * Handle all actions of the Kerberos ticket list.
+ *
+ * Copyright 1994 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ */
+
+#if !defined(KRB5) && !defined(KRB4)
+#define KRB5 1
+#endif
+
+#include <windows.h>
+#include <windowsx.h>
+
+#include <stdio.h>
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef KRB4
+#include "mit-copyright.h"
+#include "kerberos.h"
+#endif
+
+#ifdef KRB5
+#include "winsock.h"
+#include "krb5.h"
+#include "com_err.h"
+#endif
+
+#include "cns.h"
+#include "tktlist.h"
+
+/*
+ * Ticket information for a list line
+ */
+typedef struct {
+  BOOL ticket;		/* TRUE if this is a real ticket */
+  time_t issue_time;	/* time_t of issue */
+  long lifetime;		/* Lifetime for ticket in 5 minute intervals */
+  char buf[0];		/* String to display */
+} TICKETINFO, *LPTICKETINFO;
+
+/*
+ * Function: Returns a standard ctime date with day of week and year
+ *	removed.
+ *
+ * Parameters:
+ *	t - time_t date to convert
+ *
+ * Returns: A pointer to the adjusted time value.
+ */
+static char *
+short_date (time_t t)
+{
+  static char buf[26 - 4];
+  char *p;
+
+  p = ctime(&t);
+  assert(p != NULL);
+
+  strcpy (buf, p + 4);
+  buf[12] = '\0';
+
+  return buf;
+}
+
+
+/*+
+ * Function: Initializes and populates the ticket list with all existing
+ * 	Kerberos tickets.
+ *
+ * Parameters:
+ * 	hwnd - the window handle of the ticket window.
+ *
+ * Returns: Number of elements in the list or -1 on error
+ */
+int
+ticket_init_list (HWND hwnd)
+{
+  int ncred;
+  LRESULT rc;
+  int l;
+  LPTICKETINFO lpinfo;
+  char buf[26+2 + 26+2 + ANAME_SZ+1 + INST_SZ+1 + REALM_SZ + 22];
+#ifdef KRB4
+  int i;
+  time_t expiration;
+  char service[ANAME_SZ];
+  char instance[INST_SZ];
+  char realm[REALM_SZ];
+  CREDENTIALS c;
+#endif
+#ifdef KRB5
+  krb5_cc_cursor cursor;
+  krb5_error_code code;
+  krb5_creds c;
+  krb5_flags flags;
+  char *sname;                            /* Name of the service */
+  char *flags_string(krb5_creds *cred);
+#endif
+
+  SetWindowRedraw(hwnd, FALSE);
+
+  rc = ListBox_GetCount(hwnd);
+  assert(rc != LB_ERR);
+
+  if (rc > 0)
+    ticket_destroy(hwnd);
+
+  while (--rc >= 0)
+    ListBox_DeleteString(hwnd, rc);
+
+#ifdef KRB4
+  ncred = krb_get_num_cred();
+  for (i = 1; i <= ncred; i++) {
+    krb_get_nth_cred(service, instance, realm, i);
+    krb_get_cred(service, instance, realm, &c);
+    strcpy(buf, " ");
+    strncat(buf, short_date(c.issue_date - kwin_get_epoch()),
+            sizeof(buf) - 1 - strlen(buf));
+    expiration = c.issue_date - kwin_get_epoch() + (long) c.lifetime * 5L * 60L;
+    strncat(buf, "      ", sizeof(buf) - 1 - strlen(buf));
+    strncat(buf, short_date(expiration), sizeof(buf) - 1 - strlen(buf));
+    strncat(buf, "      ", sizeof(buf) - 1 - strlen(buf));
+    l = strlen(buf);
+    sprintf(&buf[l], "%s%s%s%s%s (%d)",
+	    c.service, (c.instance[0] ? "." : ""), c.instance,
+	    (c.realm[0] ? "@" : ""), c.realm, c.kvno);
+    l = strlen(buf);
+
+    lpinfo = (LPTICKETINFO) malloc(sizeof(TICKETINFO) + l + 1);
+    assert(lpinfo != NULL);
+
+    if (lpinfo == NULL)
+      return -1;
+
+    lpinfo->ticket = TRUE;
+    lpinfo->issue_time = c.issue_date - kwin_get_epoch(); /* back to system time */
+    lpinfo->lifetime = (long) c.lifetime * 5L * 60L;
+    strcpy(lpinfo->buf, buf);
+
+    rc = ListBox_AddItemData(hwnd, lpinfo);
+    assert(rc >= 0);
+
+    if (rc < 0)
+      return -1;
+  }
+
+#endif
+  
+#ifdef KRB5
+  
+  ncred = 0;
+  flags = 0;
+  if (code = krb5_cc_set_flags(k5_context, k5_ccache, flags)) {
+    if (code != KRB5_FCC_NOFILE) {
+      return -1;
+    }
+  } else {
+    if (code = krb5_cc_start_seq_get(k5_context, k5_ccache, &cursor)) {
+      return -1;
+    }
+    while (1) {
+      code = krb5_cc_next_cred(k5_context, k5_ccache, &cursor, &c);
+      if (code != 0)
+	break;
+      
+      ncred++;
+      strcpy (buf, "  ");
+      strncat(buf, short_date (c.times.starttime - kwin_get_epoch()),
+	      sizeof(buf) - 1 - strlen(buf));
+      strncat(buf, "      ", sizeof(buf) - 1 - strlen(buf));
+      strncat(buf, short_date (c.times.endtime - kwin_get_epoch()),
+	      sizeof(buf) - 1 - strlen(buf));
+      strncat(buf, "      ", sizeof(buf) - 1 - strlen(buf));
+      
+      /* Add ticket service name and realm */
+      code = krb5_unparse_name (k5_context, c.server, &sname);
+      if (code) {
+	com_err (NULL, code, "while unparsing server name");
+	break;
+      }
+      strncat (buf, sname, sizeof(buf) - 1 - strlen(buf));
+
+      strncat (buf, flags_string (&c), sizeof(buf) - 1 - strlen(buf)); /* Add flag info */
+      
+      l = strlen(buf);
+      lpinfo = (LPTICKETINFO) malloc(sizeof(TICKETINFO) + l + 1);
+      assert(lpinfo != NULL);
+      
+      if (lpinfo == NULL)
+	return -1;
+      
+      lpinfo->ticket = TRUE;
+      lpinfo->issue_time = c.times.starttime - kwin_get_epoch();
+      lpinfo->lifetime = c.times.endtime - c.times.starttime;
+      strcpy(lpinfo->buf, buf);
+      
+      rc = ListBox_AddItemData(hwnd, lpinfo);
+      assert(rc >= 0);
+      
+      if (rc < 0)
+	return -1;
+    }
+    if (code == KRB5_CC_END) {               /* End of ccache */
+      if (code = krb5_cc_end_seq_get(k5_context, k5_ccache, &cursor)) {
+	return -1;
+      }
+      flags = KRB5_TC_OPENCLOSE;          /* turns on OPENCLOSE mode */
+      if (code = krb5_cc_set_flags(k5_context, k5_ccache, flags)) {
+	return -1;
+      }
+    } else {
+      return -1;
+    }
+  }
+#endif
+  
+  if (ncred <= 0) {
+    strcpy(buf, " No Tickets");
+    lpinfo = (LPTICKETINFO) malloc(sizeof(TICKETINFO) + strlen(buf) + 1);
+    assert(lpinfo != NULL);
+    
+    if (lpinfo == NULL)
+      return -1;
+    
+    lpinfo->ticket = FALSE;
+    strcpy (lpinfo->buf, buf);
+    rc = ListBox_AddItemData(hwnd, lpinfo);
+    assert(rc >= 0);
+  }
+  
+  SetWindowRedraw(hwnd, TRUE);
+  
+  return ncred;
+}
+
+
+/*
+ * Function: Destroy the ticket list.  Make sure to delete all
+ *	ticket entries created during ticket initialization.
+ *
+ * Parameters:
+ *	hwnd - the window handle of the ticket window.
+ */
+void
+ticket_destroy (
+		HWND hwnd)
+{
+  int i;
+  int n;
+  LRESULT rc;
+
+  n = ListBox_GetCount(hwnd);
+
+  for (i = 0; i < n; i++) {
+    rc = ListBox_GetItemData(hwnd, i);
+    assert(rc != LB_ERR);
+
+    if (rc != LB_ERR)
+      free ((void *) rc);
+  }
+}
+
+
+/*
+ * Function: Respond to the WM_MEASUREITEM message for the ticket list
+ * 	by setting each list item up at 1/4 inch hight.
+ */
+void
+ticket_measureitem(HWND hwnd, MEASUREITEMSTRUCT *lpmi)
+{
+  int logpixelsy;
+  HDC hdc;
+
+  if (lpmi->CtlID != IDD_TICKET_LIST)
+    return;
+
+  hdc = GetDC(HWND_DESKTOP);
+  logpixelsy = GetDeviceCaps(hdc, LOGPIXELSY);
+  ReleaseDC(HWND_DESKTOP, hdc);
+  lpmi->itemHeight = logpixelsy / 4;	/* 1/4 inch */
+}
+
+
+/*
+ * Function: Respond to the WM_DRAWITEM message for the ticket list
+ * 	by displaying a single list item.
+ */
+void
+ticket_drawitem(HWND hwnd, const DRAWITEMSTRUCT *lpdi)
+{
+  BOOL rc;
+  COLORREF bkcolor;
+  HBRUSH hbrush;
+  UINT textheight;
+  UINT alignment;
+  int left, top;
+  BOOL b;
+  LPTICKETINFO lpinfo;
+  HICON hicon;
+#if 0
+  COLORREF textcolor;
+  COLORREF orgbkcolor;
+  COLORREF orgtextcolor;
+#endif
+  SIZE Size;
+
+  if (lpdi->CtlID != IDD_TICKET_LIST)
+    return;
+
+  lpinfo = (LPTICKETINFO) lpdi->itemData;
+
+  if (lpdi->itemAction == ODA_FOCUS)
+    return;
+
+#if 0
+  if (lpdi->itemState & ODS_SELECTED) {
+    textcolor = GetSysColor(COLOR_HIGHLIGHTTEXT);
+    bkcolor = GetSysColor(COLOR_HIGHLIGHT);
+
+    orgtextcolor = SetTextColor(lpdi->hDC, textcolor);
+    assert(textcolor != 0x80000000);
+
+    orgbkcolor = SetBkColor(lpdi->hDC, bkcolor);
+    assert(bkcolor != 0x80000000);
+  }
+  else
+#endif
+
+    bkcolor = GetBkColor(lpdi->hDC);
+  hbrush = CreateSolidBrush(bkcolor);
+  assert(hbrush != NULL);
+
+  FillRect(lpdi->hDC, &(lpdi->rcItem), hbrush);
+  DeleteObject(hbrush);
+
+  /*
+   * Display the appropriate icon
+   */
+  if (lpinfo->ticket) {
+    hicon = kwin_get_icon(lpinfo->issue_time + lpinfo->lifetime);
+    left = lpdi->rcItem.left - (32 - ICON_WIDTH) / 2;
+    top = lpdi->rcItem.top;
+    top += (lpdi->rcItem.bottom - lpdi->rcItem.top - 32) / 2;
+
+    b = DrawIcon(lpdi->hDC, left, top, hicon);
+    assert(b);
+  }
+
+  /*
+   * Display centered string
+   */
+#ifdef _WIN32
+  GetTextExtentPoint32(lpdi->hDC, "X", 1, &Size);
+#else
+  GetTextExtentPoint(lpdi->hDC, "X", 1, &Size);
+#endif
+
+  textheight = Size.cy;
+
+  alignment = SetTextAlign(lpdi->hDC, TA_TOP | TA_LEFT);
+
+  if (lpinfo->ticket)
+    left = lpdi->rcItem.left + ICON_WIDTH;
+  else
+    left = lpdi->rcItem.left;
+
+  top = lpdi->rcItem.top;
+  top += (lpdi->rcItem.bottom - lpdi->rcItem.top - textheight) / 2;
+  rc = TextOut(lpdi->hDC, left, top, (LPSTR) lpinfo->buf,
+	       strlen((LPSTR) lpinfo->buf));
+  assert(rc);
+
+  alignment = SetTextAlign(lpdi->hDC, alignment);
+
+#if 0
+  if (lpdi->itemState & ODS_SELECTED) {
+    textcolor = SetTextColor(lpdi->hDC, orgtextcolor);
+    assert(textcolor != 0x80000000);
+
+    bkcolor = SetBkColor(lpdi->hDC, orgbkcolor);
+    assert(bkcolor != 0x80000000);
+  }
+
+#endif
+}
+
+
+#ifdef KRB5
+
+/*
+ * 
+ * Flags_string
+ * 
+ * Return buffer with the current flags for the credential
+ * 
+ */
+char *
+flags_string(krb5_creds *cred) {
+  static char buf[32];
+  int i = 0;
+
+  buf[i++] = ' ';    
+  buf[i++] = '(';    
+  if (cred->ticket_flags & TKT_FLG_FORWARDABLE)
+    buf[i++] = 'F';
+  if (cred->ticket_flags & TKT_FLG_FORWARDED)
+    buf[i++] = 'f';
+  if (cred->ticket_flags & TKT_FLG_PROXIABLE)
+    buf[i++] = 'P';
+  if (cred->ticket_flags & TKT_FLG_PROXY)
+    buf[i++] = 'p';
+  if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)
+    buf[i++] = 'D';
+  if (cred->ticket_flags & TKT_FLG_POSTDATED)
+    buf[i++] = 'd';
+  if (cred->ticket_flags & TKT_FLG_INVALID)
+    buf[i++] = 'i';
+  if (cred->ticket_flags & TKT_FLG_RENEWABLE)
+    buf[i++] = 'R';
+  if (cred->ticket_flags & TKT_FLG_INITIAL)
+    buf[i++] = 'I';
+  if (cred->ticket_flags & TKT_FLG_HW_AUTH)
+    buf[i++] = 'H';
+  if (cred->ticket_flags & TKT_FLG_PRE_AUTH)
+    buf[i++] = 'A';
+
+  buf[i++] = ')';    
+  buf[i] = '\0';
+  if (i <= 3)
+    buf[0] = '\0';
+  return(buf);
+}
+
+#endif /* KRB5 */
diff --git a/mechglue/src/windows/cns/tktlist.h b/mechglue/src/windows/cns/tktlist.h
new file mode 100644
index 000000000..a522f76c7
--- /dev/null
+++ b/mechglue/src/windows/cns/tktlist.h
@@ -0,0 +1,27 @@
+/*
+ * tktlist.h
+ *
+ * Handle all actions of the Kerberos ticket list.
+ *
+ * Copyright 1994 by the Massachusetts Institute of Technology. 
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>. 
+ */
+
+/* Only one time, please */
+#ifndef	TKTLIST_DEFS
+#define TKTLIST_DEFS
+
+/*
+ * Prototypes
+ */
+BOOL ticket_init_list(HWND);
+
+void ticket_destroy(HWND);
+
+void ticket_measureitem(HWND, MEASUREITEMSTRUCT *);
+
+void ticket_drawitem(HWND, const DRAWITEMSTRUCT *);
+
+#endif
diff --git a/mechglue/src/windows/gina/ChangeLog b/mechglue/src/windows/gina/ChangeLog
new file mode 100644
index 000000000..a8d2d05a4
--- /dev/null
+++ b/mechglue/src/windows/gina/ChangeLog
@@ -0,0 +1,20 @@
+2005-10-20  Jeffrey Altman <jaltman@mit.edu>
+
+	* Makefile.in (WINLIBS): Link to the multi-threaded library.
+
+2002-06-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (WINLIBS): Use ws2_32.lib instead of wsock32.lib.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Windows fix for updated win-pre.in.
+
+Mon May 17 14:24:25 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Reflect that we only build this under win32.
+
+Mon May 10 15:28:12 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
diff --git a/mechglue/src/windows/gina/Makefile.in b/mechglue/src/windows/gina/Makefile.in
new file mode 100644
index 000000000..4a3103267
--- /dev/null
+++ b/mechglue/src/windows/gina/Makefile.in
@@ -0,0 +1,35 @@
+BUILDTOP=..\..
+
+OBJS=	$(OUTPRE)ginastub.$(OBJEXT)
+
+# Set NODEBUG if building release instead of debug
+
+LOCALINCLUDES = -I$(BUILDTOP)\include
+
+WINLIBS = advapi32.lib comctl32.lib \
+	libcmt.lib kernel32.lib ws2_32.lib user32.lib shell32.lib oldnames.lib
+
+WINDLLFLAGS = /nodefaultlib /incremental:no /release \
+	/nologo /base:0x1c000000 /dll $(LOPTS)
+
+DEFINES = -DUNICODE -D_UNICODE
+!ifdef NODEBUG
+DEFINES = $(DEFINES)
+!else
+DEFINES = $(DEFINES) -DDBG
+!endif
+
+all-windows::
+all-windows:: $(OUTPRE)kgina.dll
+
+clean-windows::
+	$(RM) $(OUTPRE)kgina.dll
+
+$(OUTPRE)kgina.dll: $(OBJS) $(KLIB) $(CLIB)
+	link $(WINDLLFLAGS) -def:gina.def -out:$*.dll \
+	   $** $(WINLIBS)
+
+$(OUTPRE)ginastub.obj: ginastub.h
+
+#$(OUTPRE)gina.res: res.rc
+#	$(RC) $(RFLAGS) -r -fo $@ res.rc
diff --git a/mechglue/src/windows/gina/gina.def b/mechglue/src/windows/gina/gina.def
new file mode 100644
index 000000000..99e066bec
--- /dev/null
+++ b/mechglue/src/windows/gina/gina.def
@@ -0,0 +1,21 @@
+LIBRARY         KGINA
+
+DESCRIPTION     'Alternate Windows NT Logon GUI'
+
+EXPORTS
+; Version 1.0
+        WlxNegotiate
+        WlxInitialize
+        WlxDisplaySASNotice
+        WlxLoggedOutSAS
+        WlxActivateUserShell
+        WlxLoggedOnSAS
+        WlxDisplayLockedNotice
+        WlxWkstaLockedSAS
+        WlxIsLockOk
+        WlxIsLogoffOk
+        WlxLogoff
+        WlxShutdown
+; Version 1.1
+	WlxScreenSaverNotify
+	WlxStartApplication
diff --git a/mechglue/src/windows/gina/ginastub.c b/mechglue/src/windows/gina/ginastub.c
new file mode 100644
index 000000000..ec4291b2b
--- /dev/null
+++ b/mechglue/src/windows/gina/ginastub.c
@@ -0,0 +1,365 @@
+
+/*
+  Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+  ginastub.c
+
+Abstract:
+  This sample illustrates a pass-thru "stub" gina which can be used
+  in some cases to simplify gina development.
+
+  A common use for a gina is to implement code which requires the
+  credentials of the user logging onto the workstation. The credentials
+  may be required for syncronization with foreign account databases
+  or custom authentication activities.
+
+  In this example case, it is possible to implement a simple gina
+  stub layer which simply passes control for the required functions
+  to the previously installed gina, and captures the interesting
+  parameters from that gina. In this scenario, the existing functionality
+  in the existent gina is retained. In addition, the development time
+  is reduced drastically, as existing functionality does not need to
+  be duplicated.
+
+  When dealing with credentials, take steps to maintain the security
+  of the credentials. For instance, if transporting credentials over
+  a network, be sure to encrypt the credentials.
+
+Author:
+  Scott Field (sfield) 18-Jul-96
+*/
+
+
+#include <windows.h>
+#include <stdio.h>
+#include <winwlx.h>
+#include "ginastub.h"
+
+
+/* Location of the real msgina. */
+
+#define REALGINA_PATH TEXT("MSGINA.DLL")
+
+
+/* winlogon function dispatch table */
+PGWLX_DISPATCH_VERSION pWlxFuncs;
+
+
+/* winlogon version */
+DWORD WlxVersion;
+
+
+/* Functions pointers to the real msgina which we will call. */
+
+PGWLX_Negotiate GWlxNegotiate;
+PGWLX_Initialize GWlxInitialize;
+PGWLX_DisplaySASNotice GWlxDisplaySASNotice;
+PGWLX_LoggedOutSAS GWlxLoggedOutSAS;
+PGWLX_ActivateUserShell GWlxActivateUserShell;
+PGWLX_LoggedOnSAS GWlxLoggedOnSAS;
+PGWLX_DisplayLockedNotice GWlxDisplayLockedNotice;
+PGWLX_WkstaLockedSAS GWlxWkstaLockedSAS;
+PGWLX_IsLockOk GWlxIsLockOk;
+PGWLX_IsLogoffOk GWlxIsLogoffOk;
+PGWLX_Logoff GWlxLogoff;
+PGWLX_Shutdown GWlxShutdown;
+
+
+/* NEW for version 1.1 */
+
+PGWLX_StartApplication GWlxStartApplication;
+PGWLX_ScreenSaverNotify GWlxScreenSaverNotify;
+
+
+/* hook into the real GINA. */
+
+static BOOL
+MyInitialize(void)
+{
+    HINSTANCE hDll;
+
+    /* Load MSGINA.DLL. */
+
+    if (! (hDll = LoadLibrary(REALGINA_PATH)))
+	return FALSE;
+
+
+    /* Get pointers to all of the WLX functions in the real MSGINA. */
+
+    GWlxNegotiate = (PGWLX_Negotiate)
+	GetProcAddress(hDll, "WlxNegotiate");
+    if (! GWlxNegotiate)
+	return FALSE;
+
+    GWlxInitialize = (PGWLX_Initialize)
+	GetProcAddress(hDll, "WlxInitialize");
+    if (! GWlxInitialize)
+	return FALSE;
+
+    GWlxDisplaySASNotice = (PGWLX_DisplaySASNotice)
+	GetProcAddress(hDll, "WlxDisplaySASNotice");
+    if (! GWlxDisplaySASNotice)
+	return FALSE;
+
+    GWlxLoggedOutSAS = (PGWLX_LoggedOutSAS)
+	GetProcAddress(hDll, "WlxLoggedOutSAS");
+    if (! GWlxLoggedOutSAS)
+	return FALSE;
+
+    GWlxActivateUserShell = (PGWLX_ActivateUserShell)
+	GetProcAddress(hDll, "WlxActivateUserShell");
+    if (! GWlxActivateUserShell)
+	return FALSE;
+
+    GWlxLoggedOnSAS = (PGWLX_LoggedOnSAS)
+	GetProcAddress(hDll, "WlxLoggedOnSAS");
+    if (! GWlxLoggedOnSAS)
+	return FALSE;
+
+    GWlxDisplayLockedNotice = (PGWLX_DisplayLockedNotice)
+	GetProcAddress(hDll, "WlxDisplayLockedNotice");
+    if (! GWlxDisplayLockedNotice)
+	return FALSE;
+
+    GWlxIsLockOk = (PGWLX_IsLockOk)
+	GetProcAddress(hDll, "WlxIsLockOk");
+    if (! GWlxIsLockOk)
+	return FALSE;
+
+    GWlxWkstaLockedSAS = (PGWLX_WkstaLockedSAS)
+	GetProcAddress(hDll, "WlxWkstaLockedSAS");
+    if (! GWlxWkstaLockedSAS)
+	return FALSE;
+
+    GWlxIsLogoffOk = (PGWLX_IsLogoffOk)
+	GetProcAddress(hDll, "WlxIsLogoffOk");
+    if (! GWlxIsLogoffOk)
+	return FALSE;
+
+    GWlxLogoff = (PGWLX_Logoff)
+	GetProcAddress(hDll, "WlxLogoff");
+    if (! GWlxLogoff)
+	return FALSE;
+
+    GWlxShutdown = (PGWLX_Shutdown)
+	GetProcAddress(hDll, "WlxShutdown");
+    if (! GWlxShutdown)
+	return FALSE;
+
+
+    /* Don't check for failure because these don't exist prior to NT 4.0 */
+
+    GWlxStartApplication = (PGWLX_StartApplication)
+	GetProcAddress(hDll, "WlxStartApplication");
+    GWlxScreenSaverNotify = (PGWLX_ScreenSaverNotify)
+	GetProcAddress(hDll, "WlxScreenSaverNotify");
+
+
+    /* Everything loaded ok. Return success. */
+    return TRUE;
+}
+
+BOOL
+WINAPI
+WlxNegotiate(
+	DWORD dwWinlogonVersion,
+	DWORD *pdwDllVersion)
+{
+    if (! MyInitialize())
+	return FALSE;
+
+    WlxVersion = dwWinlogonVersion;
+    return (* GWlxNegotiate)(dwWinlogonVersion, pdwDllVersion);
+}
+
+BOOL
+WINAPI
+WlxInitialize(
+	LPWSTR lpWinsta,
+	HANDLE hWlx,
+	PVOID pvReserved,
+	PVOID pWinlogonFunctions,
+	PVOID *pWlxContext)
+{
+    pWlxFuncs = (PGWLX_DISPATCH_VERSION) pWinlogonFunctions;
+    
+    return (* GWlxInitialize)(
+	lpWinsta,
+	hWlx,
+	pvReserved,
+	pWinlogonFunctions,
+	pWlxContext
+	);
+}
+
+VOID
+WINAPI
+WlxDisplaySASNotice(
+	PVOID pWlxContext)
+{
+    (* GWlxDisplaySASNotice)(pWlxContext);
+}
+
+int
+WINAPI
+WlxLoggedOutSAS(
+	PVOID pWlxContext,
+	DWORD dwSasType,
+	PLUID pAuthenticationId,
+	PSID pLogonSid,
+	PDWORD pdwOptions,
+	PHANDLE phToken,
+	PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
+	PVOID *pProfile)
+{
+    int iRet;
+  
+    iRet = (* GWlxLoggedOutSAS)(
+	pWlxContext,
+	dwSasType,
+	pAuthenticationId,
+	pLogonSid,
+	pdwOptions,
+	phToken,
+	pMprNotifyInfo,
+	pProfile
+	);
+  
+    if (iRet == WLX_SAS_ACTION_LOGON) {
+	/* copy pMprNotifyInfo and pLogonSid for later use */
+	
+	/* pMprNotifyInfo->pszUserName */
+	/* pMprNotifyInfo->pszDomain */
+	/* pMprNotifyInfo->pszPassword */
+	/* pMprNotifyInfo->pszOldPassword */
+    }
+  
+    return iRet;
+}
+
+BOOL
+WINAPI
+WlxActivateUserShell(
+	PVOID pWlxContext,
+	PWSTR pszDesktopName,
+	PWSTR pszMprLogonScript,
+	PVOID pEnvironment)
+{
+    return (* GWlxActivateUserShell)(
+	pWlxContext,
+	pszDesktopName,
+	pszMprLogonScript,
+	pEnvironment
+	);
+}
+
+int
+WINAPI
+WlxLoggedOnSAS(
+	PVOID pWlxContext,
+	DWORD dwSasType,
+	PVOID pReserved)
+{
+    return (* GWlxLoggedOnSAS)(pWlxContext, dwSasType, pReserved);
+}
+
+VOID
+WINAPI
+WlxDisplayLockedNotice(
+	PVOID pWlxContext)
+{
+    (* GWlxDisplayLockedNotice)(pWlxContext);
+}
+
+BOOL
+WINAPI
+WlxIsLockOk(
+	PVOID pWlxContext)
+{
+    return (* GWlxIsLockOk)(pWlxContext);
+}
+
+int
+WINAPI
+WlxWkstaLockedSAS(
+	PVOID pWlxContext,
+	DWORD dwSasType)
+{
+    return (* GWlxWkstaLockedSAS)(pWlxContext, dwSasType);
+}
+
+BOOL
+WINAPI
+WlxIsLogoffOk(
+	PVOID pWlxContext
+	)
+{
+    BOOL bSuccess;
+  
+    bSuccess = (* GWlxIsLogoffOk)(pWlxContext);
+    if (bSuccess) {
+	/* if it's ok to logoff, finish with the stored credentials */
+	/* and scrub the buffers */
+    }
+  
+    return bSuccess;
+}
+
+VOID
+WINAPI
+WlxLogoff(
+	PVOID pWlxContext
+	)
+{
+    (* GWlxLogoff)(pWlxContext);
+}
+
+VOID
+WINAPI
+WlxShutdown(
+PVOID pWlxContext,
+DWORD ShutdownType
+)
+{
+    (* GWlxShutdown)(pWlxContext, ShutdownType);
+}
+
+
+/* NEW for version 1.1 */
+
+BOOL
+WINAPI
+WlxScreenSaverNotify(
+PVOID pWlxContext,
+BOOL * pSecure
+)
+{
+    if (GWlxScreenSaverNotify)
+	return (* GWlxScreenSaverNotify)(pWlxContext, pSecure);
+  
+    /* if not exported, return something intelligent */
+    *pSecure = TRUE;
+    return TRUE;
+}
+
+BOOL
+WINAPI
+WlxStartApplication(
+	PVOID pWlxContext,
+	PWSTR pszDesktopName,
+	PVOID pEnvironment,
+	PWSTR pszCmdLine
+	)
+{
+    if (GWlxStartApplication)
+	return (* GWlxStartApplication)(
+		pWlxContext,
+		pszDesktopName,
+		pEnvironment,
+		pszCmdLine
+		);
+
+    /* if not exported, return something intelligent */
+    return TRUE;	/* ??? */
+}
diff --git a/mechglue/src/windows/gina/ginastub.h b/mechglue/src/windows/gina/ginastub.h
new file mode 100644
index 000000000..e9c833492
--- /dev/null
+++ b/mechglue/src/windows/gina/ginastub.h
@@ -0,0 +1,39 @@
+/* WinLogin 1.0 */
+typedef BOOL	(CALLBACK * PGWLX_Negotiate)
+	(DWORD, DWORD *);
+typedef BOOL	(CALLBACK * PGWLX_Initialize)
+	(LPWSTR, HANDLE, PVOID, PVOID, PVOID);
+typedef VOID	(CALLBACK * PGWLX_DisplaySASNotice)
+	(PVOID);
+typedef int	(CALLBACK * PGWLX_LoggedOutSAS)
+	(PVOID, DWORD, PLUID, PSID, PDWORD, PHANDLE,
+	 PWLX_MPR_NOTIFY_INFO, PVOID *);
+typedef BOOL	(CALLBACK * PGWLX_ActivateUserShell)
+	(PVOID, PWSTR, PWSTR, PVOID);
+typedef int	(CALLBACK * PGWLX_LoggedOnSAS)
+	(PVOID, DWORD, PVOID);
+typedef VOID	(CALLBACK * PGWLX_DisplayLockedNotice)
+	(PVOID);
+typedef int	(CALLBACK * PGWLX_WkstaLockedSAS)
+	(PVOID, DWORD);
+typedef BOOL	(CALLBACK * PGWLX_IsLockOk)
+	(PVOID);
+typedef BOOL	(CALLBACK * PGWLX_IsLogoffOk)
+	(PVOID);
+typedef VOID	(CALLBACK * PGWLX_Logoff)
+	(PVOID);
+typedef VOID	(CALLBACK * PGWLX_Shutdown)
+	(PVOID, DWORD);
+
+/* WinLogin 1.1 */
+typedef BOOL	(CALLBACK * PGWLX_StartApplication)
+	(PVOID, PWSTR, PVOID, PWSTR);
+typedef BOOL	(CALLBACK * PGWLX_ScreenSaverNotify)
+	(PVOID, BOOL *);
+
+
+#if defined(WLX_VERSION_1_1)
+typedef PWLX_DISPATCH_VERSION_1_1 PGWLX_DISPATCH_VERSION;
+#else
+typedef PWLX_DISPATCH_VERSION_1_0 PGWLX_DISPATCH_VERSION;
+#endif
diff --git a/mechglue/src/windows/gss/.Sanitize b/mechglue/src/windows/gss/.Sanitize
new file mode 100644
index 000000000..f76438c92
--- /dev/null
+++ b/mechglue/src/windows/gss/.Sanitize
@@ -0,0 +1,40 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+changelo
+gss-clie.c
+gss-misc.c
+gss.c
+gss.def
+gss.h
+gss.ico
+gss.rc
+makefile
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/mechglue/src/windows/gss/ChangeLog b/mechglue/src/windows/gss/ChangeLog
new file mode 100644
index 000000000..c513de941
--- /dev/null
+++ b/mechglue/src/windows/gss/ChangeLog
@@ -0,0 +1,177 @@
+2004-09-30  Jeffrey Altman <jaltman@mit.edu>
+
+        * Makefile.in: Add $(BUILDTOP) to include path for patchlevel.h
+
+2004-02-12  Jeffrey Altman <jaltman@mit.edu>
+
+    * Fix libpath for krbcc32.lib (only affects KRB5_KFW_COMPILE builds)
+
+2004-02-11  Jeffrey Altman <jaltman@mit.edu>
+
+    * gss-misc.h: Add file.  Copy from src/appl/gss-sample/
+
+2004-02-06  Jeffrey Altman <jaltman@mit.edu>
+
+    * resource.h: add new component id values for replay, mutual, sequence
+
+    * gss.rc: add new components for replay, mutual, sequence
+
+    * gss.h, gss.c, gss-client.c: add support for replay, mutual, and sequence
+
+2004-02-04  Jeffrey Altman <jaltman@mit.edu>
+
+    * resource.h: add new component id values for ccache
+
+    * Makefile.in: add conditional linkage to krbcc32.lib (if KRB5_KFW_BUILD)
+
+    * gss.rc: add new component for ccache selection
+ 
+    * gss.h, gss.c, gss-client.c: add support for ccache selection and 
+      if built with USE_LEASH add support for dynamic querying of the 
+      available ccache list
+
+2004-01-30  Jeffrey Altman <jaltman@mit.edu>
+
+    * resource.h: new file containing new ui component id values
+    
+    * gss.rc: new user interface definition
+
+    * gss.h, gss-misc.c, gss-client.c: Updates to support new UI and 
+      corrections to add compatibility with the Unix gss-server
+
+    * Makefile.in: add linkage to comctl32.lib
+
+2002-06-13  Ken Raeburn  <raeburn@mit.edu>
+
+	* Makefile.in (SYSLIBS): Use ws2_32.lib instead of wsock32.lib.
+
+2001-10-03  Ken Raeburn  <raeburn@mit.edu>
+
+	* gss.c, gss.h: Don't declare functions FAR any more.
+
+1999-12-03  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: 	* Makefile.in: Windows fix for updated win-pre.in.
+
+Mon May 17 19:53:58 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Add included version resouce script to 
+		resource file dependency.
+
+Mon May 17 14:21:42 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Remove win16 stuff.  Fix resource dependencies.
+		Link resource file directly instead of explicitly
+		converting it to an object file.
+
+Mon May 10 15:28:27 1999  Danilo Almeida  <dalmeida@mit.edu>
+
+	* Makefile.in: Do win32 build in subdir.
+
+Tue Aug  5 18:45:35 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in, gss.rc: Use the version resource from
+		windows/version.rc, which affects the version resources
+		for the entire krb5 distribution.
+
+Mon Jul 28 23:30:03 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Take out the /nod option, and remove libc.lib from
+ 		the list of libraries to be linked.
+
+	* gss-misc.c: Add additional debugging messages so we can see the
+		winsock error numbers.
+
+Tue Apr 29 06:45:32 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* gss.rc: Add version resource information to test version server
+	 	code.
+
+Sat Feb 15 12:21:15 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Link in ComErr library $(CLIB)
+
+Tue Feb 11 14:07:28 1997  Richard Basch  <basch@lehman.com>
+
+	* gss.c: Initialize/shutdown Winsock library
+	* gss.rc: More descriptive dialog box with an example
+
+Mon Feb 10 23:18:46 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Use WLIB definition in config/windows.in
+
+Tue Feb  4 16:18:25 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: win16 - fixed the winsock.lib path reference
+
+Thu Jan 30 22:07:35 1997  Richard Basch  <basch@lehman.com>
+
+	* Makefile.in: Win32 - link in the resource file
+
+Fri Nov 22 15:52:55 1996  unknown  <bjaspan@mit.edu>
+
+	* gss-client.c (connect_to_server): use sizeof instead of h_length
+ 	to determine number of bytes of addr to copy from DNS response
+ 	[krb5-misc/211]
+
+Tue Oct 29 10:17:25 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gss-client.c (client_establish_context): Fix typo; service_name
+ 		really should be nt_service_name.
+
+Thu Jul 25 02:16:56 1996  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* gss-client.c (client_establish_context): Remove OID's that
+		weren't being used, and rename gss_nt_service_name to
+		nt_service_name to prevent name colision.
+
+	* gss.c (parse_name): Add code to parse an optional fourth
+	 	parameter which is the mechanism OID to actually use.  If
+	 	it is ommited, the default mechanism is used.
+
+	* gss-client.c (client_establish_context): Added parameter
+		oid_name, which allows the user to specify the OID that
+		he/she actually wants to use to as the mechanism.
+
+Wed Jun 12 00:16:46 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* gss-clie.c: Renamed to gss-client.c, for VFAT/NTFS filesystems
+
+	* makefile: Renamed to Makefile.in, so that we can do WIN16/WIN32
+ 		specializations.  Remove /nologo option for Win32 RFLAGS,
+ 		since RC apparently doesn't support it.
+
+	* changelo: Renamed to ChangeLog, to make life easier.
+
+Thu Feb 29 13:25:07 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss.c: Add closeoscket() call so that program properly
+		cleans up the socket.
+
+Thu Feb 29 01:23:01 1996  Theodore Y. Ts'o  <tytso@dcl>
+
+	* gss.rc:
+	* gss.c: Added support for users to enter the GSSAPI target
+		name into the combobox.  The syntax is: 
+		"host port gssapi_target_name"
+
+Wed Sep 13 11:07:45 1995 Keith Vetter (keithv@fusion.com)
+
+	* gss-clie.c: turned const_gss_OID into const gss_OID.
+	* gss-misc.c: needed more includes.
+	* gss.c: needed more includes.
+
+Fri Apr 28 17:07:01 1995 Keith Vetter (keithv@fusion.com)
+
+	* gss-misc.c: bug with reading 4 bytes into a 2 byte entity.
+	* *.c, *.h, *.rc: changed UI -- not great but better.
+
+Fri Apr 28 11:45:23 1995 Keith Vetter (keithv@fusion.com)
+
+	* gss.rc: added an icon for the program.
+
+Fri Apr 28 11:20:38 1995 Keith Vetter (keithv@fusion.com)
+
+	* Initial release
+
+
diff --git a/mechglue/src/windows/gss/Makefile.in b/mechglue/src/windows/gss/Makefile.in
new file mode 100644
index 000000000..60c54e823
--- /dev/null
+++ b/mechglue/src/windows/gss/Makefile.in
@@ -0,0 +1,48 @@
+# makefile: Constructs the Kerberos for Windows ticket manager
+# Works for both k4 and k5 releases.
+#
+OBJS	= $(OUTPRE)gss.obj $(OUTPRE)gss-client.obj $(OUTPRE)gss-misc.obj
+RESFILE = $(OUTPRE)gss.res
+XOBJS	= $(RESFILE)
+
+##### Options
+# Set NODEBUG if building release instead of debug
+BUILDTOP=..\..
+
+!if defined(KRB5_KFW_COMPILE)
+KFWINC= /I$(BUILDTOP)\..\..\krbcc\include
+KFWLIB= $(BUILDTOP)\..\..\..\..\target\lib\$(CPU)\$(OUTPRE_DBG)\krbcc32.lib
+!endif
+LOCALINCLUDES= /I$(BUILDTOP) /I$(BUILDTOP)\include /I$(BUILDTOP)\include\krb5 $(KFWINC)
+
+##### RC Compiler
+RFLAGS	= $(LOCALINCLUDES)
+RCFLAGS	= $(RFLAGS) -D_WIN32 -DGSS_APP
+
+##### Linker
+LINK	= link
+LIBS	= $(GLIB) $(CLIB) $(WLIB)
+SYSLIBS	= kernel32.lib ws2_32.lib user32.lib gdi32.lib comdlg32.lib comctl32.lib
+LFLAGS	= /nologo $(LOPTS)
+
+all:: Makefile $(OUTPRE)gss.exe
+
+$(OUTPRE)gss.exe: gss.def $(OBJS) $(XOBJS) $(LIBS)
+	$(LINK) $(LFLAGS) /map:$*.map /out:$@ $(OBJS) $(XOBJS) \
+	  $(LIBS) $(SYSLIBS) $(KFWLIB)
+
+$(OBJS) $(XOBJS): gss.h
+
+$(RESFILE): ..\version.rc
+
+install::
+	copy $(OUTPRE)gss.exe ..\floppy
+
+clean:: 
+	if exist $(OUTPRE)*.exe del $(OUTPRE)*.exe
+	if exist ..\floppy\gss.exe del ..\floppy\gss.exe
+	if exist $(OUTPRE)*.obj del $(OUTPRE)*.obj
+	if exist $(OUTPRE)*.res del $(OUTPRE)*.res
+	if exist $(OUTPRE)*.map del $(OUTPRE)*.map
+	if exist $(OUTPRE)*.pdb del $(OUTPRE)*.pdb
+	if exist *.err del *.err
diff --git a/mechglue/src/windows/gss/gss-client.c b/mechglue/src/windows/gss/gss-client.c
new file mode 100644
index 000000000..d9c1491c2
--- /dev/null
+++ b/mechglue/src/windows/gss/gss-client.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+#include <winsock.h>
+
+#include <gssapi/gssapi_generic.h>
+#include <gssapi\gssapi_krb5.h>
+#include "gss.h"
+#include "gss-misc.h"
+
+static int verbose = 1;
+
+/*
+ * Function: connect_to_server
+ *
+ * Purpose: Opens a TCP connection to the name host and port.
+ *
+ * Arguments:
+ *
+ * 	host		(r) the target host name
+ * 	port		(r) the target port, in host byte order
+ *
+ * Returns: the established socket file desciptor, or -1 on failure
+ *
+ * Effects:
+ *
+ * The host name is resolved with gethostbyname(), and the socket is
+ * opened and connected.  If an error occurs, an error message is
+ * displayed and -1 is returned.
+ */
+static int connect_to_server(host, port)
+     char *host;
+     u_short port;
+{
+     struct sockaddr_in saddr;
+     struct hostent *hp;
+     int s;
+     
+     if ((hp = gethostbyname(host)) == NULL) {
+	  printf("Unknown host: %s\r\n", host);
+	  return -1;
+     }
+     
+     saddr.sin_family = hp->h_addrtype;
+     memcpy((char *)&saddr.sin_addr, hp->h_addr, sizeof(saddr.sin_addr));
+     saddr.sin_port = htons(port);
+
+     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+	  perror("creating socket");
+	  return -1;
+     }
+     if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+	  perror("connecting to server");
+	  (void) closesocket(s);
+	  return -1;
+     }
+     return s;
+}
+
+/*
+ * Function: client_establish_context
+ *
+ * Purpose: establishes a GSS-API context with a specified service and
+ * returns the context handle
+ *
+ * Arguments:
+ *
+ * 	s		(r) an established TCP connection to the service
+ * 	service_name	(r) the ASCII service name of the service
+ *	gss_flags	(r) GSS-API delegation flag (if any)
+ *	auth_flag	(r) whether to actually do authentication
+ *	oid		(r) OID of the mechanism to use
+ * 	context		(w) the established GSS-API context
+ *	ret_flags	(w) the returned flags from init_sec_context
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * service_name is imported as a GSS-API name and a GSS-API context is
+ * established with the corresponding service; the service should be
+ * listening on the TCP connection s.  The default GSS-API mechanism
+ * is used, and mutual authentication and replay detection are
+ * requested.
+ * 
+ * If successful, the context handle is returned in context.  If
+ * unsuccessful, the GSS-API error messages are displayed on stderr
+ * and -1 is returned.
+ */
+int client_establish_context( int s, 
+                              char *service_name,
+                              OM_uint32 gss_flags, 
+                              int auth_flag,
+                              int v1_format, 
+                              gss_OID oid, 
+                              gss_ctx_id_t *gss_context, 
+                              OM_uint32 *ret_flags)
+{
+    if (auth_flag) {
+        gss_buffer_desc send_tok, recv_tok, *token_ptr;
+        gss_name_t target_name;
+        OM_uint32 maj_stat, min_stat, init_sec_min_stat;
+        int token_flags;
+
+       /*
+        * Import the name into target_name.  Use send_tok to save
+        * local variable space.
+        */
+        send_tok.value = service_name;
+        send_tok.length = strlen(service_name) ;
+        maj_stat = gss_import_name(&min_stat, &send_tok,
+                                    (gss_OID) gss_nt_service_name, &target_name);
+        if (maj_stat != GSS_S_COMPLETE) {
+            display_status("parsing name", maj_stat, min_stat);
+            return -1;
+        }
+     
+        if (!v1_format) {
+            if (send_token(s, TOKEN_NOOP|TOKEN_CONTEXT_NEXT, empty_token) < 0) {
+                (void) gss_release_name(&min_stat, &target_name);
+                return -1;
+            }
+        }
+
+       /*
+        * Perform the context-establishement loop.
+        *
+        * On each pass through the loop, token_ptr points to the token
+        * to send to the server (or GSS_C_NO_BUFFER on the first pass).
+        * Every generated token is stored in send_tok which is then
+        * transmitted to the server; every received token is stored in
+        * recv_tok, which token_ptr is then set to, to be processed by
+        * the next call to gss_init_sec_context.
+        * 
+        * GSS-API guarantees that send_tok's length will be non-zero
+        * if and only if the server is expecting another token from us,
+        * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
+        * and only if the server has another token to send us.
+        */
+
+        token_ptr = GSS_C_NO_BUFFER;
+        *gss_context = GSS_C_NO_CONTEXT;
+
+        do {
+            maj_stat =
+                gss_init_sec_context(&init_sec_min_stat,
+                                      GSS_C_NO_CREDENTIAL,
+                                      gss_context,
+                                      target_name,
+                                      oid,
+                                      gss_flags,
+                                      0,
+                                      NULL,	/* no channel bindings */
+                                      token_ptr,
+                                      NULL,	/* ignore mech type */
+                                      &send_tok,
+                                      ret_flags,
+                                      NULL);	/* ignore time_rec */
+
+            if (token_ptr != GSS_C_NO_BUFFER)
+                free (recv_tok.value);
+
+            if (send_tok.length != 0) {
+                if (verbose)
+                    printf("Sending init_sec_context token (size=%d)...",
+                            (int) send_tok.length);
+                if (send_token(s, v1_format?0:TOKEN_CONTEXT, &send_tok) < 0) {
+                    (void) gss_release_buffer(&min_stat, &send_tok);
+                    (void) gss_release_name(&min_stat, &target_name);
+                    return -1;
+                }
+            }
+            (void) gss_release_buffer(&min_stat, &send_tok);
+
+            if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
+                display_status("initializing context", maj_stat,
+                                init_sec_min_stat);
+                (void) gss_release_name(&min_stat, &target_name);
+                if (*gss_context != GSS_C_NO_CONTEXT)
+                    gss_delete_sec_context(&min_stat, gss_context,
+                                            GSS_C_NO_BUFFER);
+                return -1;
+            }
+
+            if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+                if (verbose)
+                    printf("continue needed...");
+                if (recv_token(s, &token_flags, &recv_tok) < 0) {
+                    (void) gss_release_name(&min_stat, &target_name);
+                    return -1;
+                }
+                token_ptr = &recv_tok;
+            }
+            if (verbose)
+                printf("\r\n");
+        } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+        (void) gss_release_name(&min_stat, &target_name);
+    }
+    else {
+        if (send_token(s, TOKEN_NOOP, empty_token) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+static void read_file(file_name, in_buf)
+    char		*file_name;
+    gss_buffer_t	in_buf;
+{
+    int fd, count;
+    struct stat stat_buf;
+    
+    if ((fd = open(file_name, O_RDONLY, 0)) < 0) {
+	perror("open");
+	printf("Couldn't open file %s\r\n", file_name);
+	exit(1);
+    }
+    if (fstat(fd, &stat_buf) < 0) {
+	perror("fstat");
+	exit(1);
+    }
+    in_buf->length = stat_buf.st_size;
+
+    if (in_buf->length == 0) {
+	in_buf->value = NULL;
+	return;
+    }
+
+    if ((in_buf->value = malloc(in_buf->length)) == 0) {
+	printf("Couldn't allocate %d byte buffer for reading file\r\n",
+		(int) in_buf->length);
+	exit(1);
+    }
+
+    /* this code used to check for incomplete reads, but you can't get
+       an incomplete read on any file for which fstat() is meaningful */
+
+    count = read(fd, in_buf->value, in_buf->length);
+    if (count < 0) {
+	perror("read");
+	exit(1);
+    }
+    if (count < in_buf->length)
+	printf("Warning, only read in %d bytes, expected %d\r\n",
+		count, (int) in_buf->length);
+}
+
+/*
+ * Function: call_server
+ *
+ * Purpose: Call the "sign" service.
+ *
+ * Arguments:
+ *
+ * 	host		(r) the host providing the service
+ * 	port		(r) the port to connect to on host
+ * 	service_name	(r) the GSS-API service name to authenticate to
+ *	gss_flags	(r) GSS-API delegation flag (if any)
+ *	auth_flag	(r) whether to do authentication
+ *	wrap_flag	(r) whether to do message wrapping at all
+ *	encrypt_flag	(r) whether to do encryption while wrapping
+ *	mic_flag	(r) whether to request a MIC from the server
+ * 	msg		(r) the message to have "signed"
+ *	use_file	(r) whether to treat msg as an input file name
+ *	mcount		(r) the number of times to send the message
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * call_server opens a TCP connection to <host:port> and establishes a
+ * GSS-API context with service_name over the connection.  It then
+ * seals msg in a GSS-API token with gss_wrap, sends it to the server,
+ * reads back a GSS-API signature block for msg from the server, and
+ * verifies it with gss_verify.  -1 is returned if any step fails,
+ * otherwise 0 is returned.  */
+int call_server(char *host, u_short port, gss_OID oid, char *service_name, 
+                OM_uint32 gss_flags, int auth_flag,
+		        int wrap_flag, int encrypt_flag, int mic_flag, int v1_format, 
+                char *msg, int use_file, int mcount)
+{
+     gss_ctx_id_t context;
+     gss_buffer_desc in_buf, out_buf;
+     int s, state;
+     OM_uint32 ret_flags;
+     OM_uint32 maj_stat, min_stat;
+     gss_name_t		src_name, targ_name;
+     gss_buffer_desc	sname, tname;
+     OM_uint32		lifetime;
+     gss_OID		mechanism, name_type;
+     int		is_local;
+     OM_uint32		context_flags;
+     int		is_open;
+     gss_qop_t		qop_state;
+     gss_OID_set	mech_names;
+     gss_buffer_desc	oid_name;
+     size_t	i;
+     int token_flags;
+
+     /* Open connection */
+     if ((s = connect_to_server(host, port)) < 0)
+	  return -1;
+
+     /* Establish context */
+     if (client_establish_context(s, service_name, gss_flags, auth_flag,
+				  v1_format, oid, &context,
+				  &ret_flags) < 0) {
+	  (void) closesocket(s);
+	  return -1;
+     }
+
+     if (auth_flag) {
+         if (verbose) {
+             /* display the flags */
+             /* display_ctx_flags(ret_flags); */
+
+             /* Get context information */
+             maj_stat = gss_inquire_context(&min_stat, context,
+					&src_name, &targ_name, &lifetime,
+					&mechanism, &context_flags,
+					&is_local,
+					&is_open);
+             if (maj_stat != GSS_S_COMPLETE) {
+                 display_status("inquiring context", maj_stat, min_stat);
+                 return -1;
+             }
+
+             maj_stat = gss_display_name(&min_stat, src_name, &sname,
+                                          &name_type);
+             if (maj_stat != GSS_S_COMPLETE) {
+                 display_status("displaying source name", maj_stat, min_stat);
+                 return -1;
+             }
+             maj_stat = gss_display_name(&min_stat, targ_name, &tname,
+                                          (gss_OID *) NULL);
+             if (maj_stat != GSS_S_COMPLETE) {
+                 display_status("displaying target name", maj_stat, min_stat);
+                 return -1;
+             }
+             printf("\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\r\n",
+                     (int) sname.length, (char *) sname.value,
+                     (int) tname.length, (char *) tname.value, lifetime,
+                     context_flags,
+                     (is_local) ? "locally initiated" : "remotely initiated",
+                     (is_open) ? "open" : "closed");
+
+             (void) gss_release_name(&min_stat, &src_name);
+             (void) gss_release_name(&min_stat, &targ_name);
+             (void) gss_release_buffer(&min_stat, &sname);
+             (void) gss_release_buffer(&min_stat, &tname);
+
+             maj_stat = gss_oid_to_str(&min_stat,
+                                        name_type,
+                                        &oid_name);
+             if (maj_stat != GSS_S_COMPLETE) {
+                 display_status("converting oid->string", maj_stat, min_stat);
+                 return -1;
+             }
+             printf("Name type of source name is %.*s.\r\n",
+                     (int) oid_name.length, (char *) oid_name.value);
+             (void) gss_release_buffer(&min_stat, &oid_name);
+
+             /* Now get the names supported by the mechanism */
+             maj_stat = gss_inquire_names_for_mech(&min_stat,
+                                                    mechanism,
+                                                    &mech_names);
+             if (maj_stat != GSS_S_COMPLETE) {
+                 display_status("inquiring mech names", maj_stat, min_stat);
+                 return -1;
+             }
+
+             maj_stat = gss_oid_to_str(&min_stat,
+                                        mechanism,
+                                        &oid_name);
+             if (maj_stat != GSS_S_COMPLETE) {
+                 display_status("converting oid->string", maj_stat, min_stat);
+                 return -1;
+             }
+             printf("Mechanism %.*s supports %d names\r\n",
+                     (int) oid_name.length, (char *) oid_name.value,
+                     (int) mech_names->count);
+             (void) gss_release_buffer(&min_stat, &oid_name);
+
+             for (i=0; i<mech_names->count; i++) {
+                 maj_stat = gss_oid_to_str(&min_stat,
+                                            &mech_names->elements[i],
+                                            &oid_name);
+                 if (maj_stat != GSS_S_COMPLETE) {
+                     display_status("converting oid->string", maj_stat, min_stat);
+                     return -1;
+                 }
+                 printf("  %d: %.*s\r\n", (int) i,
+                         (int) oid_name.length, (char *) oid_name.value);
+
+                 (void) gss_release_buffer(&min_stat, &oid_name);
+             }
+             (void) gss_release_oid_set(&min_stat, &mech_names);
+         }
+     }
+     
+     if (use_file) {
+         read_file(msg, &in_buf);
+     } else {
+	 /* Seal the message */
+	 in_buf.value = msg;
+	 in_buf.length = strlen(msg);
+     }
+
+     for (i = 0; i < mcount; i++) {
+       if (wrap_flag) {
+	 maj_stat = gss_wrap(&min_stat, context, encrypt_flag, GSS_C_QOP_DEFAULT,
+			     &in_buf, &state, &out_buf);
+	 if (maj_stat != GSS_S_COMPLETE) {
+	   display_status("wrapping message", maj_stat, min_stat);
+	   (void) closesocket(s);
+	   (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+	   return -1;
+	 } else if (encrypt_flag && ! state) {
+	   fprintf(stderr, "Warning!  Message not encrypted.\r\n");
+	 }
+       }
+       else {
+	 out_buf = in_buf;
+       }
+
+       /* Send to server */
+       if (send_token(s, (v1_format?0
+			  :(TOKEN_DATA |
+			  (wrap_flag ? TOKEN_WRAPPED : 0) |
+			  (encrypt_flag ? TOKEN_ENCRYPTED : 0) |
+			  (mic_flag ? TOKEN_SEND_MIC : 0))), &out_buf) < 0) {
+	 (void) closesocket(s);
+	 (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+	 return -1;
+       }
+       if (out_buf.value != in_buf.value)
+	 (void) gss_release_buffer(&min_stat, &out_buf);
+
+       /* Read signature block into out_buf */
+       if (recv_token(s, &token_flags, &out_buf) < 0) {
+	 (void) closesocket(s);
+	 (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+	 return -1;
+       }
+
+       if (mic_flag) {
+	 /* Verify signature block */
+	 maj_stat = gss_verify_mic(&min_stat, context, &in_buf,
+				   &out_buf, &qop_state);
+	 if (maj_stat != GSS_S_COMPLETE) {
+	   display_status("verifying signature", maj_stat, min_stat);
+	   (void) closesocket(s);
+	   (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+	   return -1;
+	 }
+
+	 if (verbose)
+	   printf("Signature verified.\r\n");
+       }
+       else {
+	 if (verbose)
+	   printf("Response received.\r\n");
+       }
+
+       free (out_buf.value);
+     }
+
+     if (use_file)
+       free(in_buf.value);
+
+     /* Send NOOP */
+     if (!v1_format)
+     (void) send_token(s, TOKEN_NOOP, empty_token);
+
+     if (auth_flag) {
+       /* Delete context */
+       maj_stat = gss_delete_sec_context(&min_stat, &context, &out_buf);
+       if (maj_stat != GSS_S_COMPLETE) {
+	 display_status("deleting context", maj_stat, min_stat);
+	 (void) closesocket(s);
+	 (void) gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
+	 return -1;
+       }
+
+       (void) gss_release_buffer(&min_stat, &out_buf);
+     }
+
+     (void) closesocket(s);
+     return 0;
+}
+
+static void parse_oid(char *mechanism, gss_OID *oid)
+{
+    char	*mechstr = 0, *cp;
+    gss_buffer_desc tok;
+    OM_uint32 maj_stat, min_stat;
+    
+    if (isdigit((int) mechanism[0])) {
+	mechstr = malloc(strlen(mechanism)+5);
+	if (!mechstr) {
+	    printf("Couldn't allocate mechanism scratch!\r\n");
+	    return;
+	}
+	sprintf(mechstr, "{ %s }", mechanism);
+	for (cp = mechstr; *cp; cp++)
+	    if (*cp == '.')
+		*cp = ' ';
+	tok.value = mechstr;
+    } else
+	tok.value = mechanism;
+    tok.length = strlen(tok.value);
+    maj_stat = gss_str_to_oid(&min_stat, &tok, oid);
+    if (maj_stat != GSS_S_COMPLETE) {
+	display_status("str_to_oid", maj_stat, min_stat);
+	return;
+    }
+    if (mechstr)
+	free(mechstr);
+}
+
+int
+gss (char *server_host, char *service_name, char *mechanism, char *msg, int port,
+     int verbose, int delegate, int mutual, int replay, int sequence, 
+     int v1_format, int auth_flag, int wrap_flag,
+     int encrypt_flag, int mic_flag, int ccount, int mcount, char *ccache)
+{
+    int use_file = 0;
+    OM_uint32 gss_flags = 0, min_stat;
+    gss_OID oid = GSS_C_NULL_OID;
+    OM_uint32     minor_status;
+    int i;
+    int rc = 0;
+
+    if (ccount <= 0)  ccount = 1;
+    if (mcount <= 0)  mcount = 1;
+
+    if (mechanism && mechanism[0])
+        parse_oid(mechanism, &oid);
+
+    if ( delegate )
+        gss_flags |= GSS_C_DELEG_FLAG;
+    if ( mutual )
+        gss_flags |= GSS_C_MUTUAL_FLAG;
+    if ( replay )
+        gss_flags |= GSS_C_REPLAY_FLAG;
+    if ( sequence )
+        gss_flags |= GSS_C_SEQUENCE_FLAG;
+
+    /* By using this function the independence between the application and
+     * the underlying authentication system is broken
+     */
+    if ( ccache && ccache[0] )
+        gss_krb5_ccache_name(&minor_status, ccache, NULL);
+
+    for (i = 0; i < ccount; i++) {
+        if (call_server(server_host, port, oid, service_name,
+                         gss_flags, auth_flag, wrap_flag, encrypt_flag, mic_flag,
+                         v1_format, msg, use_file, mcount) < 0)
+            rc = -1;
+        break;
+    }
+
+    if (oid != GSS_C_NULL_OID)
+        (void) gss_release_oid(&min_stat, &oid);
+	 
+    return rc;
+}
diff --git a/mechglue/src/windows/gss/gss-misc.c b/mechglue/src/windows/gss/gss-misc.c
new file mode 100644
index 000000000..28227e248
--- /dev/null
+++ b/mechglue/src/windows/gss/gss-misc.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (C) 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+#include "gss.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys\timeb.h>
+#include <time.h>
+
+FILE *display_file;
+DWORD ws_err;
+
+gss_buffer_desc empty_token_buf = { 0, (void *) "" };
+gss_buffer_t empty_token = &empty_token_buf;
+
+static void display_status_1
+	(char *m, OM_uint32 code, int type);
+
+static int write_all(int fildes, char *buf, unsigned int nbyte)
+{
+    int ret;
+    char *ptr;
+
+    for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
+        ret = send(fildes, ptr, nbyte, 0);
+        if (ret < 0) {
+            ws_err = WSAGetLastError();
+            errno = ws_err;
+            return(ret);
+        } else if (ret == 0) {
+            return(ptr-buf);
+        }
+    }
+
+    return(ptr-buf);
+}
+
+static int read_all(int s, char *buf, unsigned int nbyte)
+{
+    int ret;
+    char *ptr;
+    fd_set rfds;
+    struct timeval tv;
+
+    FD_ZERO(&rfds);
+    FD_SET(s, &rfds);
+    tv.tv_sec = 10;
+    tv.tv_usec = 0;
+
+    for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
+        if ( select(FD_SETSIZE, &rfds, NULL, NULL, &tv) <= 0 || !FD_ISSET(s, &rfds) )
+            return(ptr-buf);
+        ret = recv(s, ptr, nbyte, 0);
+        if (ret < 0) {
+            ws_err = WSAGetLastError();
+            errno = ws_err;
+            return(ret);
+        } else if (ret == 0) {
+            return(ptr-buf);
+        }
+    }
+
+    return(ptr-buf);
+}
+
+/*
+ * Function: send_token
+ *
+ * Purpose: Writes a token to a file descriptor.
+ *
+ * Arguments:
+ *
+ * 	s		(r) an open file descriptor
+ *	flags		(r) the flags to write
+ * 	tok		(r) the token to write
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ *
+ * If the flags are non-null, send_token writes the token flags (a
+ * single byte, even though they're passed in in an integer). Next,
+ * the token length (as a network long) and then the token data are
+ * written to the file descriptor s.  It returns 0 on success, and -1
+ * if an error occurs or if it could not write all the data.
+ */
+int send_token(int s, int flags, gss_buffer_t tok)
+{
+     int len, ret;
+     unsigned char char_flags = (unsigned char) flags;
+     unsigned char lenbuf[4];
+
+     if (char_flags) {
+         ret = write_all(s, (char *)&char_flags, 1);
+         if (ret != 1) {
+             my_perror("sending token flags");
+             OkMsgBox ("Winsock error  %d \n", ws_err);
+             return -1;
+         }
+     }
+    if (tok->length > 0xffffffffUL)
+        abort();
+    lenbuf[0] = (tok->length >> 24) & 0xff;
+    lenbuf[1] = (tok->length >> 16) & 0xff;
+    lenbuf[2] = (tok->length >> 8) & 0xff;
+    lenbuf[3] = tok->length & 0xff;
+
+    ret = write_all(s, lenbuf, 4);
+    if (ret < 0) {
+        my_perror("sending token length");
+		OkMsgBox ("Winsock error  %d \n", ws_err);
+        return -1;
+    } else if (ret != 4) {
+        if (verbose)
+            printf("sending token length: %d of %d bytes written\r\n", 
+                     ret, 4);
+        return -1;
+    }
+
+    ret = write_all(s, tok->value, tok->length);
+    if (ret < 0) {
+        my_perror("sending token data");
+		OkMsgBox ("Winsock error  %d \n", ws_err);
+        return -1;
+    } else if (ret != tok->length) {
+        if (verbose)
+            printf("sending token data: %d of %d bytes written\r\n", 
+                     ret, (int) tok->length);
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+ * Function: recv_token
+ *
+ * Purpose: Reads a token from a file descriptor.
+ *
+ * Arguments:
+ *
+ * 	s		(r) an open file descriptor
+ *	flags		(w) the read flags
+ * 	tok		(w) the read token
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Effects:
+ * 
+ * recv_token reads the token flags (a single byte, even though
+ * they're stored into an integer, then reads the token length (as a
+ * network long), allocates memory to hold the data, and then reads
+ * the token data from the file descriptor s.  It blocks to read the
+ * length and data, if necessary.  On a successful return, the token
+ * should be freed with gss_release_buffer.  It returns 0 on success,
+ * and -1 if an error occurs or if it could not read all the data.
+ */
+int recv_token(int s, int * flags, gss_buffer_t tok)
+{
+    int ret;
+    unsigned char char_flags;
+    unsigned char lenbuf[4];
+
+    ret = read_all(s, (char *) &char_flags, 1);
+    if (ret < 0) {
+        my_perror("reading token flags");
+		OkMsgBox ("Winsock error  %d \n", ws_err);
+        return -1;
+    } else if (! ret) {
+        if (display_file)
+            printf("reading token flags: 0 bytes read\r\n", display_file);
+        return -1;
+    } else {
+        *flags = (int) char_flags;
+    }
+
+    if (char_flags == 0 ) {
+        lenbuf[0] = 0;
+        ret = read_all(s, &lenbuf[1], 3);
+        if (ret < 0) {
+            my_perror("reading token length");
+            OkMsgBox ("Winsock error  %d \n", ws_err);
+            return -1;
+        } else if (ret != 3) {
+            if (verbose)
+                printf("reading token length: %d of %d bytes read\r\n", 
+                         ret, 3);
+            return -1;
+        }
+    }
+    else {
+        ret = read_all(s, lenbuf, 4);
+        if (ret < 0) {
+            my_perror("reading token length");
+            OkMsgBox ("Winsock error  %d \n", ws_err);
+            return -1;
+        } else if (ret != 4) {
+            if (verbose)
+                printf("reading token length: %d of %d bytes read\r\n", 
+                         ret, 4);
+            return -1;
+        }
+    }
+
+    tok->length = ((lenbuf[0] << 24)
+                    | (lenbuf[1] << 16)
+                    | (lenbuf[2] << 8)
+                    | lenbuf[3]);
+    tok->value = (char *) malloc(tok->length ? tok->length : 1);
+    if (tok->length && tok->value == NULL) {
+        if (verbose)
+            printf("Out of memory allocating token data\r\n");
+        return -1;
+    }
+
+    ret = read_all(s, (char *) tok->value, tok->length);
+    if (ret < 0) {
+        my_perror("reading token data");
+		OkMsgBox ("Winsock error  %d \n", ws_err);
+        free(tok->value);
+        return -1;
+    } else if (ret != tok->length) {
+        printf("sending token data: %d of %d bytes written\r\n", 
+                 ret, (int) tok->length);
+        free(tok->value);
+        return -1;
+    }
+
+    return 0;
+}
+
+void 
+free_token(gss_buffer_t tok)
+{
+    if (tok->length <= 0 || tok->value == NULL)
+        return;
+
+    free(tok->value);
+    tok->value = NULL;
+    tok->length = 0;
+}
+
+/*+
+ * Function: display_status
+ *
+ * Purpose: displays GSS-API messages
+ *
+ * Arguments:
+ *
+ *	msg		a string to be displayed with the message
+ *	maj_stat	the GSS-API major status code
+ *	min_stat	the GSS-API minor status code
+ *
+ * Effects:
+ *
+ * The GSS-API messages associated with maj_stat and min_stat are
+ * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
+ * followed by a newline.
+ */
+void
+display_status (char *msg, OM_uint32 maj_stat, OM_uint32 min_stat) {
+    display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
+    display_status_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static void
+display_status_1(char *m, OM_uint32 code, int type) {
+    OM_uint32 maj_stat, min_stat;
+    gss_buffer_desc msg;
+    OM_uint32 msg_ctx;
+     
+    msg_ctx = 0;
+    while (1) {
+        maj_stat = gss_display_status(&min_stat, code,
+                                      type, GSS_C_NULL_OID,
+                                      &msg_ctx, &msg);
+        if (verbose)
+            printf("GSS-API error %s: %s\r\n", m,
+                     (char *)msg.value); 
+        OkMsgBox ("GSS-API error %s: %s\n", m,
+            (char *)msg.value);
+        (void) gss_release_buffer(&min_stat, &msg);
+	  
+        if (!msg_ctx)
+            break;
+    }
+}
+
+/*
+ * Function: display_ctx_flags
+ *
+ * Purpose: displays the flags returned by context initation in
+ *	    a human-readable form
+ *
+ * Arguments:
+ *
+ * 	int		ret_flags
+ *
+ * Effects:
+ *
+ * Strings corresponding to the context flags are printed on
+ * stdout, preceded by "context flag: " and followed by a newline
+ */
+
+void display_ctx_flags(flags)
+     OM_uint32 flags;
+{
+     if (flags & GSS_C_DELEG_FLAG)
+	  printf("context flag: GSS_C_DELEG_FLAG\r\n");
+     if (flags & GSS_C_MUTUAL_FLAG)
+	  printf("context flag: GSS_C_MUTUAL_FLAG\r\n");
+     if (flags & GSS_C_REPLAY_FLAG)
+	  printf("context flag: GSS_C_REPLAY_FLAG\r\n");
+     if (flags & GSS_C_SEQUENCE_FLAG)
+	  printf("context flag: GSS_C_SEQUENCE_FLAG\r\n");
+     if (flags & GSS_C_CONF_FLAG )
+	  printf("context flag: GSS_C_CONF_FLAG \r\n");
+     if (flags & GSS_C_INTEG_FLAG )
+	  printf("context flag: GSS_C_INTEG_FLAG \r\n");
+}
+
+void print_token(tok)
+     gss_buffer_t tok;
+{
+    int i;
+    unsigned char *p = tok->value;
+
+    if (!verbose)
+	return;
+    for (i=0; i < tok->length; i++, p++) {
+	printf("%02x ", *p);
+	if ((i % 16) == 15) {
+	    printf("\r\n");
+	}
+    }
+    printf("\r\n");
+}
+
+
+int gettimeofday (struct timeval *tv, void *ignore_tz)
+{
+    struct _timeb tb;
+    _tzset();
+    _ftime(&tb);
+    if (tv) {
+	tv->tv_sec = tb.time;
+	tv->tv_usec = tb.millitm * 1000;
+    }
+    return 0;
+}
+
+/*+*************************************************************************
+** 
+** OkMsgBox
+** 
+** A MessageBox version of printf
+** 
+***************************************************************************/
+void
+OkMsgBox (char *format, ...) {
+    char buf[256];								// Message goes into here
+    char *args;                                 // Args for printf
+
+    args = (char *) &format + sizeof(format);
+    vsprintf (buf, format, args);
+    MessageBox(NULL, buf, "", MB_OK);
+}
+/*+*************************************************************************
+** 
+** My_perror
+** 
+** A windows conversion of perror displaying the output into a MessageBox.
+** 
+***************************************************************************/
+void
+my_perror (char *msg) {
+    char *err;
+
+    err = strerror (errno);
+
+    if (msg && *msg != '\0') 
+        OkMsgBox ("%s: %s", msg, err);
+    else
+        MessageBox (NULL, err, "", MB_OK);
+}
+
diff --git a/mechglue/src/windows/gss/gss-misc.h b/mechglue/src/windows/gss/gss-misc.h
new file mode 100644
index 000000000..35b3b7390
--- /dev/null
+++ b/mechglue/src/windows/gss/gss-misc.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1994 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef _GSSMISC_H_
+#define _GSSMISC_H_
+
+#include <gssapi/gssapi_generic.h>
+#include <stdio.h>
+
+extern FILE *display_file;
+
+int send_token
+	(int s, int flags, gss_buffer_t tok);
+int recv_token
+	(int s, int *flags, gss_buffer_t tok);
+void display_status
+	(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat);
+void display_ctx_flags
+	(OM_uint32 flags);
+void print_token
+	(gss_buffer_t tok);
+
+/* Token types */
+#define TOKEN_NOOP		(1<<0)
+#define TOKEN_CONTEXT		(1<<1)
+#define TOKEN_DATA		(1<<2)
+#define TOKEN_MIC		(1<<3)
+
+/* Token flags */
+#define TOKEN_CONTEXT_NEXT	(1<<4)
+#define TOKEN_WRAPPED		(1<<5)
+#define TOKEN_ENCRYPTED		(1<<6)
+#define TOKEN_SEND_MIC		(1<<7)
+
+extern gss_buffer_t empty_token;
+
+#endif
diff --git a/mechglue/src/windows/gss/gss.c b/mechglue/src/windows/gss/gss.c
new file mode 100644
index 000000000..f42d293ea
--- /dev/null
+++ b/mechglue/src/windows/gss/gss.c
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2003, 2004 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+/*+*************************************************************************
+**
+** GSS test	- Windows scaffolding to test the gssapi dll
+**
+** Given a hostname it does the equivalent of the Unix command
+** ./gss-client [-port <port>] <hostname> host@<hostname> "msg"
+**
+***************************************************************************/
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <commctrl.h>
+#include "gss.h"
+#include <krb5.h>
+#ifdef USE_LEASH
+#include <cacheapi.h>
+#endif
+
+#include "resource.h"
+
+#define GSSAPI_INI	"gsstest.ini"				// Which INI file
+#define INI_HOSTS	"GSSAPI Hosts"				// INI file section
+#define INI_HOST	"Host"						// INI file line label
+#define INI_SVCS	"GSSAPI Services"			// INI file section
+#define INI_SVC	    "Service"					// INI file line label
+#define INI_MSGS	"GSSAPI Messages"			// INI file section
+#define INI_MSG	    "Message"					// INI file line label
+#define INI_MECHS	"GSSAPI Mechanisms"			// INI file section
+#define INI_MECH	"Mech"  					// INI file line label
+#define INI_LAST    "GSSAPI Most Recent" 
+#define INI_LAST_HOST "Host"
+#define INI_LAST_PORT "Port"
+#define INI_LAST_SVC  "Service"
+#define INI_LAST_MECH "Mechanism"
+#define INI_LAST_MSG  "Message"
+#define INI_LAST_DELEGATE  "Delegation"
+#define INI_LAST_SEQUENCE  "Sequence"
+#define INI_LAST_MUTUAL    "Mutual"
+#define INI_LAST_REPLAY    "Replay"
+#define INI_LAST_VERBOSE   "Verbose"
+#define INI_LAST_CCOUNT    "Call Count"
+#define INI_LAST_MCOUNT    "Message Count"
+#define INI_LAST_VER1      "Version One"
+#define INI_LAST_NOAUTH    "No Auth"
+#define INI_LAST_NOWRAP    "No Wrap"
+#define INI_LAST_NOCRYPT   "No Encrypt"
+#define INI_LAST_NOMIC     "No Mic"
+#define INI_LAST_CCACHE    "CCache"
+
+#define MAX_SAVED 9
+char hosts[MAX_SAVED][256];
+char svcs[MAX_SAVED][256];
+char msgs[MAX_SAVED][256];
+char mechs[MAX_SAVED][256];
+char szHost[256];			// GSSAPI Host to connect to
+char szService[256];		// Service to do
+char szMessage[256];        // Message to send
+char szMech[256];			// OID to use
+char szCCache[256];         // CCache to use
+int port = 0;				// Which port to use
+int delegate = 0;           // Delegate?
+int replay = 1;             // Replay?
+int mutual = 1;             // Mutual?
+int sequence = 0;           // Sequence?
+int verbose = 1;            // Verbose?
+int ccount = 1;             // Call Count
+int mcount = 1;             // Message Count
+int gssv1 = 0;              // Version 1?
+int noauth = 0;             // No Auth?
+int nowrap = 0;             // No Wrap?
+int nocrypt = 0;            // No Crypt?
+int nomic = 0;              // No Mic?
+
+HWND hDialog = 0;
+
+static void do_gssapi_test (void);
+static void parse_name (char *name);
+static void read_saved(void);
+static void write_saved (void);
+static void	update_saved (void);
+static void fill_combo (HWND hDlg);
+
+/*+*************************************************************************
+**
+** WinMain
+**
+** Sets up the Dialog that drives our program
+**
+***************************************************************************/
+int __stdcall
+WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
+{
+	WSADATA wsadata;
+	WORD versionrequested;
+	int rc;
+
+	InitCommonControls();
+
+	versionrequested = 0x0101;		/* Version 1.1 */
+	rc = WSAStartup(versionrequested, &wsadata);
+	if (rc) {
+	    MessageBox(NULL, "Couldn't initialize Winsock library", "",
+		       MB_OK | MB_ICONSTOP);
+	    return FALSE;
+	}
+	if (versionrequested != wsadata.wVersion) {
+	    WSACleanup();
+	    MessageBox(NULL, "Winsock version 1.1 not available", "",
+		       MB_OK | MB_ICONSTOP);
+	    return FALSE;
+	}
+	
+	rc = DialogBoxParam (hInstance, "GSSAPIDLG", HWND_DESKTOP, OpenGssapiDlg, 0L);
+	rc = GetLastError();
+
+	WSACleanup();
+	return 0;
+}
+/*+*************************************************************************
+**
+** Do_gssapi_test
+**
+** Does the actual call to GSS-client
+**
+***************************************************************************/
+void
+do_gssapi_test (void) {
+	int n;										// Return value
+	HCURSOR hcursor;							// For the hourglass cursor
+
+	hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+	n = gss (szHost, szService, szMech, szMessage[0] ? szMessage : "Test Gssapi Message", port,
+             verbose, delegate, mutual, replay, sequence, 
+             gssv1, !noauth, !nowrap, !nocrypt, !nomic, ccount, mcount,
+             szCCache);
+	SetCursor(hcursor);
+
+	if (n)
+		MessageBox (NULL, "gss failed", "", IDOK | MB_ICONINFORMATION);
+}
+
+/*+*************************************************************************
+**
+** OpenGssapiDlg(HWND, unsigned, WORD, LONG)
+**
+** Processes messages for "Open Gssapi Connection" dialog box
+**
+** Messages:
+** 	WM_INITDIALOG - initialize dialog box
+** 	WM_COMMAND    - Input received
+**
+***************************************************************************/
+INT_PTR CALLBACK
+OpenGssapiDlg(
+	HWND hDlg,
+	UINT message,
+	WPARAM wParam,
+	LPARAM lParam)
+{
+	HDC hDC;									// For getting graphic info
+	DWORD Ext;									// Size of dialog
+	int xExt, yExt;								// Size broken apart
+    char buff[64];
+
+	switch (message) {
+	case WM_INITDIALOG:
+        hDialog = hDlg;
+		/*
+		** First center the dialog
+		*/
+		hDC = GetDC(hDlg);
+		Ext = GetDialogBaseUnits();
+		xExt = (190 *LOWORD(Ext)) /4 ;
+		yExt = (72 * HIWORD(Ext)) /8 ;
+		SetWindowPos(hDlg, NULL,
+			(GetSystemMetrics(SM_CXSCREEN)/2)-(xExt/2),
+			(GetSystemMetrics(SM_CYSCREEN)/2)-(yExt/2),
+			0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
+		ReleaseDC(hDlg, hDC);
+
+        SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_LIMITTEXT, sizeof(szHost), 0);
+		read_saved ();							// Get the host list
+		fill_combo (hDlg);						// Put into combo box
+
+		SendMessage(hDlg, WM_SETFOCUS, 0, 0);
+		return (TRUE);
+
+    case WM_HSCROLL:
+		switch (LOWORD(wParam)) {
+		case TB_THUMBTRACK:
+		case TB_THUMBPOSITION: 
+			{
+				long pos = HIWORD(wParam); // the position of the slider
+				int  ctrlID = GetDlgCtrlID((HWND)lParam);
+
+				if (ctrlID == GSS_CALL_COUNT) {
+                    sprintf(buff,"Call Count: %d",pos);
+					SetWindowText(GetDlgItem(hDialog, IDC_STATIC_CCOUNT),buff);
+				}
+				if (ctrlID == GSS_MESSAGE_COUNT) {
+                    sprintf(buff,"Message Count: %d",pos);
+					SetWindowText(GetDlgItem(hDialog, IDC_STATIC_MSG_COUNT),buff);
+				}
+			}
+			break;
+        case TB_BOTTOM:
+        case TB_TOP:
+        case TB_ENDTRACK:
+        case TB_LINEDOWN:
+        case TB_LINEUP:
+        case TB_PAGEDOWN:
+        case TB_PAGEUP:
+		default:
+			{
+				int  ctrlID = GetDlgCtrlID((HWND)lParam);
+				long pos = SendMessage(GetDlgItem(hDialog,ctrlID), TBM_GETPOS, 0, 0); // the position of the slider
+
+				if (ctrlID == GSS_CALL_COUNT) {
+                    sprintf(buff,"Call Count: %d",pos);
+					SetWindowText(GetDlgItem(hDialog, IDC_STATIC_CCOUNT),buff);
+				}
+				if (ctrlID == GSS_MESSAGE_COUNT) {
+                    sprintf(buff,"Message Count: %d",pos);
+					SetWindowText(GetDlgItem(hDialog, IDC_STATIC_MSG_COUNT),buff);
+				}
+			}
+		}
+        break;
+
+
+	case WM_COMMAND:
+		switch (wParam) {
+		case GSS_CANCEL:						// Only way out of the dialog
+		case IDCANCEL:							// From the menu
+			EndDialog(hDlg, FALSE);
+			break;
+
+		case GSS_OK:
+			GetDlgItemText(hDlg, GSS_HOST_NAME, szHost, 256);
+			SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_SHOWDROPDOWN, FALSE, 0);
+
+			if (!*szHost) {
+				MessageBox(hDlg, "You must enter a host name", NULL, MB_OK);
+				break;
+			}
+
+			GetDlgItemText(hDlg, GSS_SERVICE_NAME, szService, 256);
+			SendDlgItemMessage(hDlg, GSS_SERVICE_NAME, CB_SHOWDROPDOWN, FALSE, 0);
+
+			if (!*szService) {
+				MessageBox(hDlg, "You must enter a service name", NULL, MB_OK);
+				break;
+			}
+
+            GetDlgItemText(hDlg, GSS_MECHANISM, szMech, 256);
+            GetDlgItemText(hDlg, GSS_CCACHE_NAME, szCCache, 256);
+            GetDlgItemText(hDlg, GSS_MESSAGE, szMessage, 256);
+            GetDlgItemText(hDlg, GSS_PORT, buff, 32);
+            if (!*buff) {
+				MessageBox(hDlg, "You must enter a valid port number", NULL, MB_OK);
+				break;
+            }
+            port = atoi(buff);
+            if (port == 0 || port == -1)
+                port = 4444;
+
+            ccount = SendDlgItemMessage( hDlg, GSS_CALL_COUNT, TBM_GETPOS, 0, 0);
+            mcount = SendDlgItemMessage( hDlg, GSS_MESSAGE_COUNT, TBM_GETPOS, 0, 0);
+
+            verbose = IsDlgButtonChecked(hDlg, GSS_VERBOSE);
+            delegate = IsDlgButtonChecked(hDlg, GSS_DELEGATION);
+            mutual = IsDlgButtonChecked(hDlg, GSS_MUTUAL);
+            replay = IsDlgButtonChecked(hDlg, GSS_REPLAY);
+            sequence = IsDlgButtonChecked(hDlg, GSS_SEQUENCE);
+            gssv1 = IsDlgButtonChecked(hDlg, GSS_VERSION_ONE);
+
+            noauth = IsDlgButtonChecked(hDlg, GSS_NO_AUTH);
+            if ( noauth ) {
+                nowrap = nocrypt = nomic = 0;
+            } else {
+                nowrap = IsDlgButtonChecked(hDlg, GSS_NO_WRAP);
+                nocrypt = IsDlgButtonChecked(hDlg, GSS_NO_ENCRYPT);
+                nomic = IsDlgButtonChecked(hDlg, GSS_NO_MIC);
+            }
+
+			update_saved ();        			// Add it to the host list
+			fill_combo (hDlg);					// Update the combo box
+            SetDlgItemText(hDlg, GSS_OUTPUT, "");
+            do_gssapi_test ();      			// Test GSSAPI
+
+			//EndDialog(hDlg, TRUE);
+			break;
+		
+        case GSS_NO_AUTH:
+            if ( IsDlgButtonChecked(hDlg, GSS_NO_AUTH) ) {
+                // disable the other no_xxx options
+                EnableWindow(GetDlgItem(hDlg, GSS_NO_WRAP), FALSE);
+                EnableWindow(GetDlgItem(hDlg, GSS_NO_ENCRYPT), FALSE);
+                EnableWindow(GetDlgItem(hDlg, GSS_NO_MIC), FALSE);
+            } else {
+                // enable the other no_xxx options
+                EnableWindow(GetDlgItem(hDlg, GSS_NO_WRAP), TRUE);
+                EnableWindow(GetDlgItem(hDlg, GSS_NO_ENCRYPT), TRUE);
+                EnableWindow(GetDlgItem(hDlg, GSS_NO_MIC), TRUE);
+            }
+            break;
+        }
+		return FALSE;
+	}
+	return FALSE;
+
+}
+/*+*************************************************************************
+**
+** Parse_name
+**
+** Turns NAME which the user entered into host, service and port.
+** The host is up to first space, port is after that and service is made
+** from host.
+**
+***************************************************************************/
+static void
+parse_name (char *name) {
+	char *ptr;
+	char seps[] = " ,\t";
+	char tempname[256];
+	
+	memset( &tempname[0], '\0', 256 );
+	strcpy( tempname, name);
+	ptr = strtok( tempname, seps);
+	if (ptr != NULL ){
+	    strcpy( szHost, ptr );
+	} else {
+	    wsprintf( szHost, "k5test" );
+	}
+	if(ptr){
+	    ptr = strtok( NULL, seps);
+	}
+	if( ptr ){
+		port = atoi (ptr);
+	}
+	if( ptr ){
+	    ptr = strtok( NULL, seps);
+	}
+	if( ptr ){
+	    strcpy( szService, ptr );
+	}else{
+	    wsprintf (szService, "sample@%s", szHost); // Make the service name
+	}
+	if( ptr ){
+	    ptr = strtok( NULL, seps);
+	}
+	if( ptr ){
+	    wsprintf (szMech, "{ %s }", ptr); // Put in the OID
+	    for (ptr = szMech; *ptr; ptr++)
+		    if (*ptr == '.')
+			    *ptr = ' ';
+    } else {
+	   szMech[0] = 0;
+	}
+
+}
+/*+*************************************************************************
+**
+** read_saved
+**
+** Reads all the hosts listed in the INI file.
+**
+***************************************************************************/
+static void
+read_saved (void) {
+	int i;					/* Index */
+	char buff[32];
+	
+	for (i = 0; MAX_SAVED; ++i) {		/* Read this many entries */
+		wsprintf (buff, INI_HOST "%d", i);
+		GetPrivateProfileString(INI_HOSTS, buff, "", hosts[i], 256, GSSAPI_INI);
+		if (*hosts[i] == '\0')		/* No more entries??? */
+			break;
+	}
+	for (i = 0; MAX_SAVED; ++i) {		/* Read this many entries */
+		wsprintf (buff, INI_SVC "%d", i);
+		GetPrivateProfileString(INI_SVCS, buff, "", svcs[i], 256, GSSAPI_INI);
+		if (*svcs[i] == '\0')		/* No more entries??? */
+			break;
+	}
+	for (i = 0; MAX_SAVED; ++i) {		/* Read this many entries */
+		wsprintf (buff, INI_MSG "%d", i);
+		GetPrivateProfileString(INI_MSGS, buff, "", msgs[i], 256, GSSAPI_INI);
+		if (*msgs[i] == '\0')		/* No more entries??? */
+			break;
+	}
+	for (i = 0; MAX_SAVED; ++i) {		/* Read this many entries */
+		wsprintf (buff, INI_MECH "%d", i);
+		GetPrivateProfileString(INI_MECHS, buff, "", mechs[i], 256, GSSAPI_INI);
+		if (*mechs[i] == '\0')		/* No more entries??? */
+			break;
+	}
+    GetPrivateProfileString(INI_LAST, INI_LAST_HOST, "", szHost, 256, GSSAPI_INI);
+    GetPrivateProfileString(INI_LAST, INI_LAST_PORT, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        port = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_SVC, "", szService, 256, GSSAPI_INI);
+    GetPrivateProfileString(INI_LAST, INI_LAST_MSG, "", szMessage, 256, GSSAPI_INI);
+    GetPrivateProfileString(INI_LAST, INI_LAST_MECH, "", szMech, 256, GSSAPI_INI);
+    GetPrivateProfileString(INI_LAST, INI_LAST_CCACHE, "", szCCache, 256, GSSAPI_INI);
+    GetPrivateProfileString(INI_LAST, INI_LAST_DELEGATE, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        delegate = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_MUTUAL, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        mutual = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_REPLAY, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        replay = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_SEQUENCE, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        sequence = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_VERBOSE, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        verbose = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_CCOUNT, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        ccount = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_MCOUNT, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        mcount = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_VER1, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        gssv1 = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_NOAUTH, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        noauth = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_NOWRAP, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        nowrap = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_NOCRYPT, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        nocrypt = atoi(buff);
+    GetPrivateProfileString(INI_LAST, INI_LAST_NOMIC, "", buff, 32, GSSAPI_INI);
+    if ( buff[0] )  
+        nomic = atoi(buff);
+}
+
+/*+*************************************************************************
+**
+** write_saved
+**
+** Writes the hosts list back to the ini file.
+**
+***************************************************************************/
+static void
+write_saved () {
+	int i;										// Index
+	char buff[32];
+
+	for (i = 0; i < MAX_SAVED; ++i) {
+		if (*hosts[i] == '\0')					// End of the list?
+			break;
+		wsprintf (buff, INI_HOST "%d", i);
+		WritePrivateProfileString(INI_HOSTS, buff, hosts[i], GSSAPI_INI);
+	}
+	for (i = 0; i < MAX_SAVED; ++i) {
+		if (*svcs[i] == '\0')					// End of the list?
+			break;
+		wsprintf (buff, INI_SVC "%d", i);
+		WritePrivateProfileString(INI_SVCS, buff, svcs[i], GSSAPI_INI);
+	}
+	for (i = 0; i < MAX_SAVED; ++i) {
+		if (*msgs[i] == '\0')					// End of the list?
+			break;
+		wsprintf (buff, INI_MSG "%d", i);
+		WritePrivateProfileString(INI_MSGS, buff, msgs[i], GSSAPI_INI);
+	}
+	for (i = 0; i < MAX_SAVED; ++i) {
+		if (*mechs[i] == '\0')					// End of the list?
+			break;
+		wsprintf (buff, INI_MECH "%d", i);
+		WritePrivateProfileString(INI_MECHS, buff, mechs[i], GSSAPI_INI);
+	}
+    WritePrivateProfileString(INI_LAST, INI_LAST_HOST, szHost, GSSAPI_INI);
+    wsprintf(buff, "%d", port);
+    WritePrivateProfileString(INI_LAST, INI_LAST_PORT, buff, GSSAPI_INI);
+    WritePrivateProfileString(INI_LAST, INI_LAST_SVC, szService, GSSAPI_INI);
+    WritePrivateProfileString(INI_LAST, INI_LAST_MECH, szMech, GSSAPI_INI);
+    WritePrivateProfileString(INI_LAST, INI_LAST_CCACHE, szCCache, GSSAPI_INI);
+    WritePrivateProfileString(INI_LAST, INI_LAST_MSG, szMessage, GSSAPI_INI);
+    wsprintf(buff, "%d", delegate);
+    WritePrivateProfileString(INI_LAST, INI_LAST_DELEGATE, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", mutual);
+    WritePrivateProfileString(INI_LAST, INI_LAST_MUTUAL, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", replay);
+    WritePrivateProfileString(INI_LAST, INI_LAST_REPLAY, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", sequence);
+    WritePrivateProfileString(INI_LAST, INI_LAST_SEQUENCE, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", verbose);
+    WritePrivateProfileString(INI_LAST, INI_LAST_VERBOSE, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", ccount);
+    WritePrivateProfileString(INI_LAST, INI_LAST_CCOUNT, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", mcount);
+    WritePrivateProfileString(INI_LAST, INI_LAST_MCOUNT, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", gssv1);
+    WritePrivateProfileString(INI_LAST, INI_LAST_VER1, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", noauth);
+    WritePrivateProfileString(INI_LAST, INI_LAST_NOAUTH, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", nowrap);
+    WritePrivateProfileString(INI_LAST, INI_LAST_NOWRAP, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", nocrypt);
+    WritePrivateProfileString(INI_LAST, INI_LAST_NOCRYPT, buff, GSSAPI_INI);
+    wsprintf(buff, "%d", nomic);
+    WritePrivateProfileString(INI_LAST, INI_LAST_NOMIC, buff, GSSAPI_INI);
+}
+/*+*************************************************************************
+**
+** Update_saved
+**
+** Updates the host list with the new NAME the user typed.
+**
+***************************************************************************/
+static void
+update_saved (void) {
+	int i;										// Index
+
+	for (i = 0; i < MAX_SAVED-1; ++i) {			// Find it in the list
+		if (! _stricmp (szHost, hosts[i])) 		// A match
+			break;
+		if (*hosts[i] == '\0')					// End of the list
+			break;
+	}
+	memmove (hosts[1], hosts[0], i * sizeof(hosts[0])); // Move the data down
+	strcpy (hosts[0], szHost);					// Insert this item
+
+    for (i = 0; i < MAX_SAVED-1; ++i) {			// Find it in the list
+		if (! _stricmp (szService, svcs[i])) 		// A match
+			break;
+		if (*svcs[i] == '\0')					// End of the list
+			break;
+	}
+	memmove (svcs[1], svcs[0], i * sizeof(svcs[0])); // Move the data down
+	strcpy (svcs[0], szService);					// Insert this item
+
+	for (i = 0; i < MAX_SAVED-1; ++i) {			// Find it in the list
+		if (! _stricmp (szMessage, msgs[i])) 		// A match
+			break;
+		if (*msgs[i] == '\0')					// End of the list
+			break;
+	}
+	memmove (msgs[1], msgs[0], i * sizeof(msgs[0])); // Move the data down
+	strcpy (msgs[0], szMessage);					// Insert this item
+
+	for (i = 0; i < MAX_SAVED-1; ++i) {			// Find it in the list
+		if (! _stricmp (szMech, mechs[i])) 		// A match
+			break;
+		if (*mechs[i] == '\0')					// End of the list
+			break;
+	}
+	memmove (mechs[1], mechs[0], i * sizeof(hosts[0])); // Move the data down
+	strcpy (mechs[0], szMech);					// Insert this item
+
+	write_saved ();
+}
+/*+*************************************************************************
+**
+** Fill_combo
+**
+** Fills the combo box with the contents of the host list. Item 0 goes
+** into the edit portion and the rest go into the libt box.
+**
+***************************************************************************/
+static void
+fill_combo (HWND hDlg) {
+	int i;										// Index
+    char buff[256];
+#ifdef USE_LEASH
+    krb5_error_code retval;
+    apiCB * cc_ctx = 0;
+    struct _infoNC ** pNCi = 0;
+#endif
+
+	SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_RESETCONTENT, 0, 0);
+	SetDlgItemText(hDlg, GSS_HOST_NAME, szHost);
+	SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_SETEDITSEL, 0, 0);
+	for (i = 1; i < MAX_SAVED; ++i) {			// Fill in the list box
+		if (*hosts[i] == '\0')
+			break;
+		SendDlgItemMessage(hDlg, GSS_HOST_NAME, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) hosts[i]));
+	}
+
+	SendDlgItemMessage(hDlg, GSS_SERVICE_NAME, CB_RESETCONTENT, 0, 0);
+	SetDlgItemText(hDlg, GSS_SERVICE_NAME, szService);
+	SendDlgItemMessage(hDlg, GSS_SERVICE_NAME, CB_SETEDITSEL, 0, 0);
+	for (i = 1; i < MAX_SAVED; ++i) {			// Fill in the list box
+		if (*svcs[i] == '\0')
+			break;
+		SendDlgItemMessage(hDlg, GSS_SERVICE_NAME, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) svcs[i]));
+	}
+
+	SendDlgItemMessage(hDlg, GSS_MECHANISM, CB_RESETCONTENT, 0, 0);
+	SetDlgItemText(hDlg, GSS_MECHANISM, szMech);
+	SendDlgItemMessage(hDlg, GSS_MECHANISM, CB_SETEDITSEL, 0, 0);
+	for (i = 1; i < MAX_SAVED; ++i) {			// Fill in the list box
+		if (*mechs[i] == '\0')
+			break;
+		SendDlgItemMessage(hDlg, GSS_MECHANISM, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) mechs[i]));
+	}
+
+    SendDlgItemMessage(hDlg, GSS_CCACHE_NAME, CB_RESETCONTENT, 0, 0);
+	SetDlgItemText(hDlg, GSS_CCACHE_NAME, szCCache);
+	SendDlgItemMessage(hDlg, GSS_CCACHE_NAME, CB_SETEDITSEL, 0, 0);
+
+#ifdef USE_LEASH
+    retval = cc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL);
+    if (retval)
+        goto skip_ccache;
+
+    retval = cc_get_NC_info(cc_ctx, &pNCi);
+    if (retval) 
+        goto clean_ccache;
+
+    for ( i=0; pNCi[i]; i++ ) {
+        if (pNCi[i]->vers == CC_CRED_V5) {
+            sprintf(buff,"API:%s",pNCi[i]->name);
+            SendDlgItemMessage(hDlg, GSS_CCACHE_NAME, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) buff));
+        }
+    }
+
+  clean_ccache:
+    if (pNCi)
+        cc_free_NC_info(cc_ctx, &pNCi);
+    if (cc_ctx)
+        cc_shutdown(&cc_ctx);
+  skip_ccache:
+#endif /* USE_LEASH */
+    if ( szCCache[0] )
+        SendDlgItemMessage(hDlg, GSS_CCACHE_NAME, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) szCCache));
+    SendDlgItemMessage(hDlg, GSS_CCACHE_NAME, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) "MSLSA:"));
+
+	SendDlgItemMessage(hDlg, GSS_MESSAGE, CB_RESETCONTENT, 0, 0);
+	SetDlgItemText(hDlg, GSS_MESSAGE, szMessage);
+	SendDlgItemMessage(hDlg, GSS_MESSAGE, CB_SETEDITSEL, 0, 0);
+	for (i = 1; i < MAX_SAVED; ++i) {			// Fill in the list box
+		if (*msgs[i] == '\0')
+			break;
+		SendDlgItemMessage(hDlg, GSS_MESSAGE, CB_ADDSTRING, 0, (LPARAM) ((LPSTR) msgs[i]));
+	}
+
+    wsprintf(buff, "%d", port);
+    SetDlgItemText(hDlg, GSS_PORT, buff);
+
+    CheckDlgButton(hDlg, GSS_VERBOSE, verbose);
+    CheckDlgButton(hDlg, GSS_DELEGATION, delegate);
+    CheckDlgButton(hDlg, GSS_MUTUAL, mutual);
+    CheckDlgButton(hDlg, GSS_REPLAY, replay);
+    CheckDlgButton(hDlg, GSS_SEQUENCE, sequence);
+    CheckDlgButton(hDlg, GSS_VERSION_ONE, gssv1);
+    CheckDlgButton(hDlg, GSS_NO_AUTH, noauth);
+    CheckDlgButton(hDlg, GSS_NO_WRAP, nowrap);
+    CheckDlgButton(hDlg, GSS_NO_ENCRYPT, nocrypt);
+    CheckDlgButton(hDlg, GSS_NO_MIC, nomic);
+
+    if ( noauth ) {
+        // disable the other no_xxx options
+        EnableWindow(GetDlgItem(hDlg, GSS_NO_WRAP), FALSE);
+        EnableWindow(GetDlgItem(hDlg, GSS_NO_ENCRYPT), FALSE);
+        EnableWindow(GetDlgItem(hDlg, GSS_NO_MIC), FALSE);
+    } else {
+        // enable the other no_xxx options
+        EnableWindow(GetDlgItem(hDlg, GSS_NO_WRAP), TRUE);
+        EnableWindow(GetDlgItem(hDlg, GSS_NO_ENCRYPT), TRUE);
+        EnableWindow(GetDlgItem(hDlg, GSS_NO_MIC), TRUE);
+    }
+
+    SendDlgItemMessage(hDlg, GSS_CALL_COUNT, TBM_SETRANGEMIN, (WPARAM) FALSE, (LPARAM) 1);
+    SendDlgItemMessage(hDlg, GSS_CALL_COUNT, TBM_SETRANGEMAX, (WPARAM) FALSE, (LPARAM) 20);
+    SendDlgItemMessage(hDlg, GSS_CALL_COUNT, TBM_SETPOS, (WPARAM) FALSE, (LPARAM) ccount);
+    sprintf(buff,"Call Count: %d",ccount);
+    SetWindowText(GetDlgItem(hDialog, IDC_STATIC_CCOUNT),buff);
+
+    SendDlgItemMessage(hDlg, GSS_MESSAGE_COUNT, TBM_SETRANGEMIN, (WPARAM) FALSE, (LPARAM) 1);
+    SendDlgItemMessage(hDlg, GSS_MESSAGE_COUNT, TBM_SETRANGEMAX, (WPARAM) FALSE, (LPARAM) 20);
+    SendDlgItemMessage(hDlg, GSS_MESSAGE_COUNT, TBM_SETPOS, (WPARAM) FALSE, (LPARAM) mcount);
+    sprintf(buff,"Message Count: %d",mcount);
+    SetWindowText(GetDlgItem(hDialog, IDC_STATIC_MSG_COUNT),buff);
+}
+
+int
+gss_printf (const char *format, ...) {
+    static char myprtfstr[4096];
+    int i, len, rc=0;
+    char *cp;
+    va_list ap;
+
+    va_start(ap, format);
+    rc = _vsnprintf(myprtfstr, sizeof(myprtfstr)-1, format, ap);
+    va_end(ap);
+
+    SendDlgItemMessage(hDialog, GSS_OUTPUT, EM_REPLACESEL, FALSE, (LPARAM) myprtfstr);
+    return rc;
+}
diff --git a/mechglue/src/windows/gss/gss.def b/mechglue/src/windows/gss/gss.def
new file mode 100644
index 000000000..f49806698
--- /dev/null
+++ b/mechglue/src/windows/gss/gss.def
@@ -0,0 +1,15 @@
+;
+; Gss - tests the GSSAPI dll
+;
+
+NAME		GSS
+DESCRIPTION	'Tests the gssapi dll'
+
+EXETYPE		windows
+STUB		'winstub.exe'
+CODE		preload moveable
+DATA		preload moveable multiple
+HEAPSIZE	1024
+STACKSIZE	4096
+
+EXPORTS		OpenGssapiDlg
diff --git a/mechglue/src/windows/gss/gss.h b/mechglue/src/windows/gss/gss.h
new file mode 100644
index 000000000..60d91bf6b
--- /dev/null
+++ b/mechglue/src/windows/gss/gss.h
@@ -0,0 +1,43 @@
+/*+*************************************************************************
+** 
+** gss.h
+** 
+** 
+***************************************************************************/
+#include <windows.h>
+#include "winsock.h"
+#include <string.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+
+// gss.c
+INT_PTR CALLBACK OpenGssapiDlg(	HWND hDlg,	UINT message,	WPARAM wParam,	LPARAM lParam);
+
+// gss-misc.c
+int send_token(int s, int flags, gss_buffer_t tok);
+int recv_token(int s, int *flags, gss_buffer_t tok);
+void free_token(gss_buffer_t tok);
+void display_status(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat);
+static void display_status_1(char *m, OM_uint32 code, int type);
+void OkMsgBox (char *format, ...);
+void my_perror (char *msg);
+
+// gss-client.c
+int
+gss (char *server_host, char *service_name, char *mechanism, char *msg, int port,
+     int verbose, int delegate, int mutual, int replay, int sequence, 
+     int v1_format, int auth_flag, int wrap_flag,
+     int encrypt_flag, int mic_flag, int ccount, int mcount, char * ccache);
+int call_server(char *host, u_short port, gss_OID oid, char *service_name, 
+                OM_uint32 deleg_flag, int auth_flag,
+		        int wrap_flag, int encrypt_flag, int mic_flag, int v1_format, 
+                char *msg, int use_file, int mcount);
+int connect_to_server(char *host, u_short port);
+int client_establish_context(int s, char *service_name, OM_uint32 deleg_flag,
+                             int auth_flag, int v1_format, gss_OID oid, 
+                             gss_ctx_id_t *gss_context, OM_uint32 *ret_flags);
+
+
+extern int verbose;
+#define printf  gss_printf
diff --git a/mechglue/src/windows/gss/gss.ico b/mechglue/src/windows/gss/gss.ico
new file mode 100644
index 0000000000000000000000000000000000000000..8cd96a18a5ac029bc2e3e07d6b601e39a0703b20
GIT binary patch
literal 766
zcmc(bF>b>!3`OapyHW(`YL8uWg7j#<h9_Oc$LT1+T{N+e6m26whHm*bMSlJ-T9(Mb
zGffvU{Je>LlD~+F_$CH<XBC;zo?}KtndhEZDT!IubwyBrMb#>T$6Ch!fh8{>=iI%m
zJ?5O7>5GP;g`Z9sy=XgC%|#@&9I|RjJ)!~ST;-6V0}V`$0{ytiVMs*=F3&e%K<<bg
z$Q`NgV9fE?HZs~&^=9)=Zp_cYY(rm*{;Iu9yN;fMQyb26?|Sbu|3TkI9lde)Rcj5y
o*7+8)>J3M|@3JCXHI=YoMq#uc-nWjrouYrXGT}MmZeEuD040CM6951J

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/gss/gss.rc b/mechglue/src/windows/gss/gss.rc
new file mode 100644
index 000000000..46cf6424e
--- /dev/null
+++ b/mechglue/src/windows/gss/gss.rc
@@ -0,0 +1,148 @@
+// Microsoft Visual C++ generated resource script.
+//
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+GSS                     ICON                    "gss.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+GSSAPIDLG DIALOGEX 63, 65, 330, 311
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "Test GSSAPI Connection"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
+BEGIN
+    RTEXT           "Hostname:",IDC_STATIC_HOST,5,12,60,10,NOT WS_GROUP
+    COMBOBOX        GSS_HOST_NAME,70,9,245,60,CBS_DROPDOWN | CBS_AUTOHSCROLL | 
+                    WS_VSCROLL | WS_GROUP | WS_TABSTOP
+    DEFPUSHBUTTON   "Test",GSS_OK,80,290,51,14,WS_GROUP
+    PUSHBUTTON      "Exit",GSS_CANCEL,185,290,51,14
+    RTEXT           "Port:",IDC_STATIC_PORT,16,27,50,8
+    EDITTEXT        GSS_PORT,70,25,40,14,ES_RIGHT | ES_AUTOHSCROLL | 
+                    ES_NUMBER
+    COMBOBOX        GSS_SERVICE_NAME,70,41,245,60,CBS_DROPDOWN | CBS_SORT | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "GSS Service Name:",IDC_STATIC_SERVICE,1,44,64,8
+    COMBOBOX        GSS_CCACHE_NAME,70,69,245,60,CBS_DROPDOWN | CBS_SORT | 
+                    WS_VSCROLL | WS_TABSTOP
+    RTEXT           "CCache Name:",IDC_STATIC_CCACHE,16,71,49,8
+    COMBOBOX        GSS_MECHANISM,70,110,245,60,CBS_DROPDOWN | 
+                    CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+    RTEXT           "Mechanism (OID):",IDC_STATIC_MECH,0,115,65,8
+    RTEXT           "Test Message:",IDC_STATIC_MSG,0,55,65,8
+    COMBOBOX        GSS_MESSAGE,70,55,245,60,CBS_DROPDOWN | CBS_AUTOHSCROLL | 
+                    CBS_SORT | WS_VSCROLL | WS_TABSTOP
+    LTEXT           "The following items are optional and should only be altered by those who understand their implications.",
+                    IDC_STATIC_OPTIONS,10,85,305,20
+    CONTROL         "Verbose Output",GSS_VERBOSE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,72,138,65,10
+    CONTROL         "Delegation",GSS_DELEGATION,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,72,150,50,10
+    CONTROL         "Version 1",GSS_VERSION_ONE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,150,138,45,10
+    CONTROL         "No Auth",GSS_NO_AUTH,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,72,162,42,10
+    CONTROL         "No Wrap",GSS_NO_WRAP,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,132,162,45,10
+    CONTROL         "No Encrypt",GSS_NO_ENCRYPT,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,198,162,51,10
+    CONTROL         "No Mic",GSS_NO_MIC,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,270,162,39,10
+    CONTROL         "Slider1",GSS_CALL_COUNT,"msctls_trackbar32",TBS_BOTH | 
+                    WS_TABSTOP,66,174,100,15
+    CONTROL         "Slider2",GSS_MESSAGE_COUNT,"msctls_trackbar32",TBS_BOTH | 
+                    WS_TABSTOP,204,174,100,15
+    CTEXT           "Call Count",IDC_STATIC_CCOUNT,72,192,90,8
+    CTEXT           "Message Count",IDC_STATIC_MSG_COUNT,210,192,90,8
+    GROUPBOX        "Output",IDC_GROUP_OUTPUT,0,210,325,75
+    GROUPBOX        "Configuration Options",IDC_GROUP_OPTIONS,0,0,325,205
+    EDITTEXT        GSS_OUTPUT,0,220,320,60,ES_MULTILINE | ES_AUTOVSCROLL | 
+                    ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL
+    CONTROL         "Mutual",GSS_MUTUAL,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,132,150,37,10
+    CONTROL         "Replay",GSS_REPLAY,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,198,150,38,10
+    CONTROL         "Sequence",GSS_SEQUENCE,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,270,150,49,10
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resrc1.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""resource.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
+
+#include <winver.h>
+#include "..\version.rc"
+
+TestTrackerMOTD TEXT ver_serv.txt
diff --git a/mechglue/src/windows/gss/resource.h b/mechglue/src/windows/gss/resource.h
new file mode 100644
index 000000000..de7b2c127
--- /dev/null
+++ b/mechglue/src/windows/gss/resource.h
@@ -0,0 +1,50 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by gss.rc
+//
+#define GSS_HOST_NAME                   1000
+#define GSS_PORT                        1001
+#define GSS_SERVICE_NAME                1003
+#define IDC_STATIC_SERVICE              1004
+#define GSS_MECHANISM                   1005
+#define IDC_STATIC_MECH                 1006
+#define IDC_STATIC_MSG                  1007
+#define GSS_MESSAGE                     1008
+#define IDC_STATIC_OPTIONS              1009
+#define GSS_VERBOSE                     1010
+#define GSS_DELEGATION                  1011
+#define GSS_VERSION_ONE                 1012
+#define GSS_NO_AUTH                     1013
+#define GSS_NO_WRAP                     1014
+#define GSS_NO_ENCRYPT                  1015
+#define GSS_NO_MIC                      1016
+#define GSS_CALL_COUNT                  1017
+#define GSS_MESSAGE_COUNT               1018
+#define IDC_STATIC_CCOUNT               1019
+#define IDC_STATIC_MSG_COUNT            1020
+#define IDC_GROUP_OUTPUT                1021
+#define IDC_GROUP_OPTIONS               1022
+#define GSS_OUTPUT                      1023
+#define GSS_OK                          1024
+#define GSS_CANCEL                      1025
+#define IDC_STATIC_PORT                 1026
+#define IDC_STATIC_HOST                 1027
+#define GSS_CCACHE_NAME                 1028
+#define IDC_STATIC_CCACHE               1029
+#define GSS_MUTUAL                      1030
+#define GSS_REPLAY                      1031
+#define GSS_SEQUENCE                    1032
+
+#define IDD_GSSAPIDLG                   101
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC                     1
+#define _APS_NEXT_RESOURCE_VALUE        102
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1033
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/mechglue/src/windows/gss/ver_serv.txt b/mechglue/src/windows/gss/ver_serv.txt
new file mode 100644
index 000000000..c7dcf80d7
--- /dev/null
+++ b/mechglue/src/windows/gss/ver_serv.txt
@@ -0,0 +1,11 @@
+
+The user provided information, along with version information about this application and the machine configuration, will be logged each time the application is launched. Recording this information will provide usage information to IS staff. This information will help us to focus our resources and serve you better in the future. This information will be treated as confidential and will only be accessible by IS staff members.
+
+If you would rather remain anonymous during this testing phase then use the "Register Anonymously" check box.
+
+To see more information about configuring the version checking part of this application please consult the local help file.
+
+We welcome comments on suggestions about this test-tracking system; please send them to testtrack@mit.edu.
+
+		Paul B. Hill
+		MIT Information Systems
diff --git a/mechglue/src/windows/identity/ChangeLog b/mechglue/src/windows/identity/ChangeLog
new file mode 100644
index 000000000..ada18d283
--- /dev/null
+++ b/mechglue/src/windows/identity/ChangeLog
@@ -0,0 +1,19 @@
+2005-11-29  Jeffrey Altman <jaltman@mit.edu>
+
+Second Beta of KFW 3.0.0:
+
+All features completed except for:
+
+ * Debug Window
+
+ * KRB5.INI (aka Realm) Editor
+
+ * Column Selection
+
+ * Graphics are incomplete
+
+ * Documentation is incomplete
+
+
+  
+
diff --git a/mechglue/src/windows/identity/Makefile b/mechglue/src/windows/identity/Makefile
new file mode 100644
index 000000000..253d71935
--- /dev/null
+++ b/mechglue/src/windows/identity/Makefile
@@ -0,0 +1,190 @@
+#
+# Copyright (c) 2004 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+!ifdef ETAGRUN
+all: finale doc
+!else
+all: finale
+!endif
+
+MODULE=all
+!include <config/Makefile.w32>
+
+!ifndef CLEANRUN
+!ifndef TESTRUN
+!ifndef ETAGRUN
+RMAKE=$(MAKECMD) /nologo all
+!else
+RMAKE=$(MAKECMD) /nologo etag
+!endif
+!else
+RMAKE=$(MAKECMD) /nologo test
+!endif
+!else
+RMAKE=$(MAKECMD) /nologo clean
+!endif
+
+start:
+
+config: start
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+include: config
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+util: include
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+kherr: util
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+kconfig: kherr
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+kmq: kconfig
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+kcreddb: kmq
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+kmm: kcreddb
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+help: kmm
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+uilib: help
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+nidmgrdll: uilib
+	$(ECHO) -- Entering $@
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+ui: nidmgrdll
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+# Now build the plugins
+plugincommon: ui
+	$(ECHO) -- Entering $@
+	$(CD) plugins\common
+	$(RMAKE)
+	$(CD) ..\..
+	$(ECHO) -- Done with $@
+
+krb5plugin: plugincommon
+	$(ECHO) -- Entering $@
+	$(CD) plugins\krb5
+	$(RMAKE)
+	$(CD) ..\..
+	$(ECHO) -- Done with $@
+
+!ifndef NO_KRB4
+finale: krb4plugin
+
+krb4plugin: plugincommon
+	$(ECHO) -- Entering $@
+	$(CD) plugins\krb4
+	$(RMAKE)
+	$(CD) ..\..
+	$(ECHO) -- Done with $@
+!endif
+
+!ifdef BUILD_AFS
+finale: afsplugin
+
+afsplugin: plugincommon
+	$(ECHO) -- Entering $@
+	$(CD) plugins\afs
+	$(RMAKE)
+	$(CD) ..\..
+	$(ECHO) -- Done with $@
+!endif
+
+finale: krb5plugin
+	$(ECHO) -- Done.
+
+pdoc:
+
+doc: pdoc
+	$(ECHO) -- Entering $@:
+	$(CD) $@
+	$(RMAKE)
+	$(CD) ..
+	$(ECHO) -- Done with $@
+
+clean::
+	$(MAKECMD) /nologo CLEANRUN=1
+
+test::
+	$(MAKECMD) /nologo TESTRUN=1
+
+etags::
+	$(RM) $(TAGFILE)
+	$(MAKECMD) /nologo ETAGRUN=1
diff --git a/mechglue/src/windows/identity/apiversion.txt b/mechglue/src/windows/identity/apiversion.txt
new file mode 100644
index 000000000..e2367db2a
--- /dev/null
+++ b/mechglue/src/windows/identity/apiversion.txt
@@ -0,0 +1,57 @@
+# Copyright (c) 2004 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+# This file documents the versions of the API for NetIDMgr.  The
+# syntax of the file is:
+#
+# Version=<api-version number>
+# AppVersion=<netidmgr-version>
+# Date=<release date> | NOTRELEASED
+# # <comments>
+# <symbol-name>
+# # comment
+# Schema:<path-to-schema>
+# # comment
+
+
+#----------------------------------------------------------------
+Version=1
+AppVersion=0.1.0.0
+Date=NOTRELEASED
+# Original Khimaira API.
+
+#----------------------------------------------------------------
+Version=2
+AppVersion=0.1.1.0
+Date=Nov 01, 2005
+# Alpha 1 release of NetIDMgr, along with KFW 3.0.0 beta
+
+#----------------------------------------------------------------
+Version=3
+AppVersion=0.1.2.0
+Date=Nov 30, 2005
+# Alpha 2 release of NetIDMgr, along with KFW 3.0.0 beta 2
+
+Version=4
+AppVersion=1.0.0.0
+Date=Dec 05, 2005
diff --git a/mechglue/src/windows/identity/config/Makefile b/mechglue/src/windows/identity/config/Makefile
new file mode 100644
index 000000000..f10928fc5
--- /dev/null
+++ b/mechglue/src/windows/identity/config/Makefile
@@ -0,0 +1,125 @@
+#
+# Copyright (c) 2004 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+MODULE=config
+!include <Makefile.w32>
+
+all: showvars mkalldirs mkversion
+
+showvars:
+	$(ECHO) SRC= $(SRC)
+	$(ECHO) DESTDIR = $(DESTDIR)
+	$(ECHO) OBJDIR = $(OBJDIR)
+	$(ECHO).
+	$(ECHO) CC = $(CC)
+	$(ECHO) DOXYGEN = $(DOXYGEN)
+	$(ECHO) HHC = $(HHC)
+
+mkalldirs:
+!	if !exist($(DESTROOT))
+	-$(MKDIR) $(DESTROOT)
+!	endif
+!	if !exist($(OBJROOT))
+	-$(MKDIR) $(OBJROOT)
+!	endif
+!	if !exist($(DESTDIR))
+	-$(MKDIR) $(DESTDIR)
+!	endif
+!	if !exist($(OBJDIR))
+	-$(MKDIR) $(OBJDIR)
+!	endif
+!	if !exist($(INCDIR))
+	-$(MKDIR) $(INCDIR)
+!	endif
+!	if !exist($(BINDIR))
+	-$(MKDIR) $(BINDIR)
+!	endif
+!	if !exist($(LIBDIR))
+	-$(MKDIR) $(LIBDIR)
+!	endif
+!	if !exist($(DOCDIR))
+	-$(MKDIR) $(DOCDIR)
+!	endif
+	$(ECHO) Done creating directories.
+
+VERSIONINT=$(INCDIR)\netidmgr_intver.h
+
+VERSIONEXT=$(INCDIR)\netidmgr_version.h
+
+# Version related defines
+
+! if "$(KH_BUILD)"=="RETAIL"
+kh_fileflags=0
+! else
+kh_fileflags=VS_FF_DEBUG
+! endif
+! if "$(KH_RELEASE)"=="PRERELEASE"
+kh_fileflags=$(kh_fileflags) | VS_FF_PRERELEASE
+! elseif "$(KH_RELEASE)"=="PRIVATE"
+kh_fileflags=$(kh_fileflags) | VS_FF_PRIVATEBUILD
+! elseif "$(KH_RELEASE)"=="SPECIAL"
+kh_fileflags=$(kh_fileflags) | VS_FF_SPECIALBUILD
+! endif
+
+kh_fileos=VOS_NT_WINDOWS32
+kh_filetype_app=VFT_APP
+kh_filetype_dll=VFT_DLL
+
+mkversion: $(VERSIONINT) $(VERSIONEXT)
+
+# Version and build strings
+
+!if "$(KH_RELEASE)" == "OFFICIAL"
+NETIDMGR_VERSION_STR_1033=$(NETIDMGR_VERSION)
+NETIDMGR_COMMENT_STR_1033=Official build.  Please send bug reports to kfw-bugs@MIT.EDU
+!elseif "$(KH_RELEASE)" == "PRERELEASE"
+NETIDMGR_VERSION_STR_1033=$(NETIDMGR_VERSION) Prelease $(NETIDMGR_RELEASEDESC)
+NETIDMGR_COMMENT_STR_1033=Prerelease build.  Please send bug reports to kfw-bugs@MIT.EDU
+!elseif "$(KH_RELEASE)" == "PRIVATE"
+NETIDMGR_VERSION_STR_1033=$(NETIDMGR_VERSION).PRIVATE
+NETIDMGR_PRIVATE_STR_1033=Private build.  Please send bug reports to kfw-bugs@MIT.EDU
+!elseif "$(KH_RELEASE)" == "SPECIAL"
+NETIDMGR_VERSION_STR_1033=$(NETIDMGR_VERSION).SPECIAL
+NETIDMGR_SPECIAL_STR_1033=Special build.  Please send bug reports to kfw-bugs@MIT.EDU
+!endif
+
+!if "$(KH_BUILD)" == "DEBUG"
+NETIDMGR_VERSION_STR_1033=$(NETIDMGR_VERSION_STR_1033).DEBUG
+!else
+!endif
+
+NETIDMGR_PRODUCT_1033=NetIDMgr $(NETIDMGR_VERSION_STR_1033)
+
+!include netidmgr_version.h.in
+
+!include netidmgr_intver.h.in
+
+clean::
+!	if exist($(VERSIONINT))
+	$(RM) $(VERSIONINT)
+!	endif
+!	if exist($(VERSIONEXT))
+	$(RM) $(VERSIONEXT)
+!	endif
+
diff --git a/mechglue/src/windows/identity/config/Makefile.w32 b/mechglue/src/windows/identity/config/Makefile.w32
new file mode 100644
index 000000000..264d19ed2
--- /dev/null
+++ b/mechglue/src/windows/identity/config/Makefile.w32
@@ -0,0 +1,277 @@
+#
+#  Khimaira : Win32 configuration makefile
+#             This file will be included by all the makefiles
+#             in the build tree.
+#
+# Copyright (c) 2004,2005 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+!ifndef KHIMAIRA_WIN32_CONFIG
+KHIMAIRA_WIN32_CONFIG=1
+
+# Environment Variables
+#  The following environment variables MUST be set:
+#   KH_ROOT : Root of the source tree.
+#   KH_BUILD: One of DEBUG or RETAIL
+#
+#  The following environment variables are optional:
+#   KH_RUNTIME: One of STATIC or DLL, specifies whether the CRT libs
+#               are linked statically or through MSVCRT.DLL.
+#   KH_AUXCFLAGS: Optional flags for CL
+#   KH_RELEASE: Release type.  One of OFFICIAL, PRERELEASE, PRIVATE or SPECIAL.
+#      OFFICIAL   : An official release of Khimaira
+#      PREPRELEASE: A beta/release candidate release
+#      PRIVATE    : Private build
+#      SPECIAL    : Special build.  Typically one with non-mainline patches.
+
+# Version info
+NETIDMGR_VERSION_MAJOR=1
+NETIDMGR_VERSION_MINOR=0
+NETIDMGR_VERSION_PATCH=0
+NETIDMGR_VERSION_AUX=0
+NETIDMGR_RELEASEDESC=
+
+# The API version.  This number must be incremented each time the API
+# changes.  Plugins specify the version of the API that they were
+# compiled against and the Module Manager uses the API numbers to
+# decide whether the plugin is safe to load or not.
+#
+# Changes to the API version numbers should be documented in
+# apiversion.txt at the root of the source tree.
+NETIDMGR_VERSION_API=4
+
+NETIDMGR_VERSION=$(NETIDMGR_VERSION_MAJOR).$(NETIDMGR_VERSION_MINOR).$(NETIDMGR_VERSION_PATCH).$(NETIDMGR_VERSION_AUX)
+NETIDMGR_VERSIONC=$(NETIDMGR_VERSION_MAJOR),$(NETIDMGR_VERSION_MINOR),$(NETIDMGR_VERSION_PATCH),$(NETIDMGR_VERSION_AUX)
+
+# Source information
+NETIDMGR_SRC_COMPANY_1033=Massachusetts Institute of Technology
+NETIDMGR_SRC_COPYRIGHT_1033=(C) 2005 Massachusetts Institute of Technology
+
+# Choose the default build type if one is not set
+!if ("$(KH_BUILD)" != "DEBUG") && ("$(KH_BUILD)" != "RETAIL")
+!  if defined(NODEBUG) && "$(NODEBUG)"=="1"
+KH_BUILD=RETAIL
+!  else
+KH_BUILD=DEBUG
+!  endif
+!endif
+
+!if "$(KH_BUILD)"=="DEBUG" && defined(NODEBUG) && "$(NODEBUG)"=="1"
+! error The Khimaira build configuration is set for DEBUG while the Platform SDK build environment is set to RETAIL.
+!endif
+
+# The default release type is PRIVATE is no other type is specified
+!if ("$(KH_RELEASE)" != "OFFICIAL") && ("$(KH_RELEASE)" != "PRERELEASE") && ("$(KH_RELEASE)" != "PRIVATE") && ("$(KH_RELEASE)" != "SPECIAL")
+KH_RELEASE=PRIVATE
+!endif
+
+# Actual build environment settings
+
+# See what compiler we are using
+# TODO: Update this to support other compilers
+!if defined(MSVCVer) && "$(MSVCVer)"=="8.0"
+KH_CLVER=vc8
+!else
+KH_CLVER=vc7
+!endif
+
+# Check for required env vars
+!ifndef MODULE
+!	error MODULE must be specified
+!endif
+!ifndef KH_ROOT
+! ifndef PISMERE
+!   error Either KH_ROOT or PISMERE must be defined
+! else
+KH_ROOT=$(PISMERE)\athena\auth\krb5\src\windows\identity
+! endif
+!endif
+
+!ifdef NODEBUG
+OUTPRE_DBG=rel
+!else
+OUTPRE_DBG=dbg
+!endif
+OUTPRE1=obj
+OUTPRE2=$(OUTPRE1)\$(CPU)
+OUTPRE3=$(OUTPRE2)\$(OUTPRE_DBG)
+OUTPRE=$(OUTPRE3)^\
+
+
+
+# Output directory structure
+DESTROOT=$(KH_ROOT)\obj
+OBJROOT=$(KH_ROOT)\obj
+SRC=$(KH_ROOT)
+
+DESTDIR=$(DESTROOT)\$(CPU)\$(OUTPRE_DBG)
+OBJDIR=$(OBJROOT)\$(CPU)\$(OUTPRE_DBG)
+
+OBJ=$(OBJDIR)\$(MODULE)
+INCDIR=$(DESTDIR)\inc
+#BINDIR=$(DESTDIR)\bin
+BINDIR=$(KH_ROOT)\$(OUTPRE)
+#LIBDIR=$(DESTDIR)\lib
+LIBDIR=$(KH_ROOT)\$(OUTPRE)
+DOCDIR=$(DESTDIR)\doc
+
+# Source directories
+CONFDIR=$(SRC)\config
+
+# Setup environment for win32.mak
+
+!if "$(KH_BUILD)" == "RETAIL"
+NODEBUG=1
+!endif
+
+# Win32.mak
+!include <Win32.Mak>
+
+# Program macros
+
+CD=cd
+RM=del /q
+MKDIR=mkdir
+RMDIR=rmdir
+ECHO=echo
+MAKECMD=nmake
+CP=copy /y
+LINK=link
+CCSV=perl $(SRC)\config\ccsv.pl
+MC=mc
+
+!ifdef KH_DOXYFULLPATH
+DOXYGEN=$(KH_DOXYFULLPATH)
+!else
+DOXYGEN=doxygen
+!endif
+
+!ifdef KH_HHCFULLPATH
+HHC=$(KH_HHCFULLPATH)
+!else
+HHC=hhc
+!endif
+
+!ifdef KH_KFWPATH
+KFWINCDIR=$(KH_KFWPATH)\inc
+kfwincflags = -I$(KFWINCDIR)\krb5 -I$(KFWINCDIR)\krb5\KerberosIV -I$(KFWINCDIR)\krb4 -I$(KFWINCDIR)\loadfuncs -I$(KFWINCDIR)
+KFWLIBDIR=$(KH_KFWPATH)\lib\$(CPU)
+!else if defined(PISMERE)
+KFWINCDIR=$(PISMERE)\athena\auth\krb5\src\include
+kfwincflags = -I$(KFWINCDIR) -I$(PISMERE)\athena\util\loadfuncs -I$(PISMERE)\athena\auth\krb5\src\include\kerberosIV -I$(PISMERE)\athena\auth\krb4\include
+KFWLIBDIR=$(PISMERE)\target\lib\$(CPU)\$(OUTPRE_DBG)
+!endif
+
+!ifdef KH_AFSPATH
+AFSINCDIR=$(KH_AFSPATH)\include
+AFSLIBDIR=$(KH_AFSPATH)\lib
+afsincflags=-I$(AFSINCDIR)
+!endif
+
+#EXTLIBDIR=$(SRC)\ext-lib\$(CPU)
+#EXTINCDIR=-I$(SRC)\ext-inc
+
+incflags= -I$(INCDIR) -I$(SRC)\include -I. -I$(OBJ) $(kfwincflags) $(afsincflags)
+rincflags= /i $(INCDIR) /i $(SRC)\include /i .
+khdefines=-DUNICODE -D_UNICODE
+khcwarn=/Wp64
+!ifndef KH_NO_WX
+khcwarn=$(khcwarn) /WX
+!endif
+
+#DEBUG_SYMBOLS
+ldebug=$(ldebug) /DEBUG
+cdebug=$(cdebug) -Os -Zi
+
+khcflags=$(cdebug) $(cflags) $(incflags) $(khdefines) $(khcwarn)
+khlguiflags=$(ldebug) $(guilflags)
+khlconflags=$(ldebug) $(conlflags)
+khldllguiflags=$(ldebug) $(dlllflags)
+khldllconflags=$(ldebug) $(dlllflags)
+
+!if "$(KH_RUNTIME)" == "STATIC"
+khcflags=$(khcflags) $(cvarsmt)
+khlguiflags=$(khlguiflags) $(guilibsmt)
+khlconflags=$(khlconflags) $(conlibsmt)
+khldllguiflags=$(khldllguiflags) $(guilibsmt)
+khldllconflags=$(khldllconflags) $(conlibsmt)
+!else
+khcflags=$(khcflags) $(cvarsdll)
+khlguiflags=$(khlguiflags) $(guilibsdll)
+khlconflags=$(khlconflags) $(conlibsdll)
+khldllguiflags=$(khldllguiflags) $(guilibsdll)
+khldllconflags=$(khldllconflags) $(conlibsdll)
+!endif
+
+C2OBJ=$(CC) $(khcflags) $(KH_AUXCFLAGS) /Fo"$@" /c $**
+
+EXECONLINK=$(LINK) /NOLOGO $(khlconflags) /OUT:$@ $**
+
+EXEGUILINK=$(LINK) /NOLOGO $(khlguiflags) /OUT:$@ $**
+
+DLLCONLINK=$(LINK) /NOLOGO $(khldllconflags) /OUT:$@ /IMPLIB:$(LIBDIR)\$(@B).lib $**
+
+DLLGUILINK=$(LINK) /NOLOGO $(khldllguiflags) /OUT:$@ /IMPLIB:$(LIBDIR)\$(@B).lib $**
+
+DLLRESLINK=$(LINK) /NOLOGO /DLL /NOENTRY /MACHINE:$(PROCESSOR_ARCHITECTURE) /OUT:$@ $**
+
+RC2RES=$(RC) $(RFLAGS) $(rincflags) /fo $@ $**
+
+MC2RC=$(MC) $(MCFLAGS) -h $(OBJ)\ -m 1024 -r $(OBJ)\ -x $(OBJ)\ $**
+
+{}.c{$(OBJ)}.obj:
+	$(C2OBJ)
+
+{$(OBJ)}.c{$(OBJ)}.obj:
+	$(C2OBJ)
+
+{}.h{$(INCDIR)}.h:
+	$(CP) $** $@
+
+{}.rc{$(OBJ)}.res:
+	$(RC2RES)
+
+{$(OBJ)}.rc{$(OBJ)}.res:
+	$(RC2RES)
+
+clean::
+!if exist($(OBJ))
+	$(RM) $(OBJ)\
+!endif
+
+test::
+
+mkdirs::
+!if !exist($(OBJ))
+	$(MKDIR) $(OBJ)
+!endif
+
+TAGFILE = $(SRC)\TAGS
+
+etag::
+	etags -o $(TAGFILE) -a *.c *.h
+
+.SUFFIXES: .h
+
+.SILENT:
+
+!endif
diff --git a/mechglue/src/windows/identity/config/ccsv.pl b/mechglue/src/windows/identity/config/ccsv.pl
new file mode 100644
index 000000000..c6c82814f
--- /dev/null
+++ b/mechglue/src/windows/identity/config/ccsv.pl
@@ -0,0 +1,124 @@
+#!/usr/bin/perl
+
+#
+# Copyright (c) 2004 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+
+# This is a simple script that is used for generating C code from CSV
+#files.  We expect three arguments, the <input> which is the .csv file
+#to be parsed, a <config> which is a configuration file and the
+#<output>.  
+
+#   The configuration file is a perl file which defines the following
+#variables :
+
+# $skip_lines : the number of lines to skip in the csv.  The default is 0
+
+# @pquote : an array of boolean integers that specify whether or not
+# to quote the specific field using double quotes.  The default is to
+# not quote anything.
+
+# $file_prefix : the prefix for the file
+
+# $record_prefix : the prefix for each record
+
+# $field_sep : the field separator.  The default is ','
+
+# $record_postfix : the postfix for each record
+
+# $record_sep : A record separator.  Only shows up between records.
+
+# $file_postfix : the postfix for the entire file
+
+use Text::ParseWords;
+
+sub do_nothingus {
+}
+
+if($#ARGV != 2) {
+    print "Usage: ccsv.pl <input-filename> <config-filename> <output-filename>\n";
+    die;
+}
+
+$infn=$ARGV[0];
+$cfgfn=$ARGV[1];
+$outfn=$ARGV[2];
+
+$skip_lines = 0;
+@pquote = {};
+$file_prefix = "";
+$record_prefix = "";
+$field_sep = ",";
+$record_postfix = "";
+$record_sep = "\n";
+$file_postfix = "";
+$record_parser = \&do_nothingus;
+
+($inbase) = ($infn =~ m/^(\w*)/);
+
+do $cfgfn;
+
+open(IN, "<".$infn) or die "Can't open input file:".$infn;
+open(OUT, ">".$outfn) or die "Can't open output file:".$outfn;
+
+print OUT $file_prefix;
+
+$first_line = 1;
+
+while(<IN>) {
+    chomp $_;
+    if($skip_lines > 0) {
+	$skip_lines--;
+    } elsif (m/^\#/) {
+        # ignore
+    } else {
+	if($first_line == 0){
+	    print OUT $record_sep;
+	} else {
+	    $first_line = 0;
+	}
+
+	@fields = &parse_line(',',0,$_);
+	for(@fields) {
+	    chomp;
+	    s/^\s*//;
+	}
+
+	&$record_parser(\@fields);
+
+	print OUT $record_prefix;
+	for(my $i=0; $i <= $#fields; $i++) {
+	    print OUT $field_sep if $i != 0;
+	    print OUT 'L"' if $pquote[$i] == 1;
+	    print OUT $fields[$i];
+	    print OUT '"' if $pquote[$i] == 1;
+	}
+	print OUT $record_postfix;
+    }
+}
+
+print OUT $file_postfix;
+
+close INF;
+close OUT;
diff --git a/mechglue/src/windows/identity/config/csvschema.cfg b/mechglue/src/windows/identity/config/csvschema.cfg
new file mode 100644
index 000000000..ba3bf9bfc
--- /dev/null
+++ b/mechglue/src/windows/identity/config/csvschema.cfg
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 2004 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+$file_prefix = <<EOS;
+/*
+This file was autogenerated from:
+    $cfgfn
+    $infn
+
+Do not modify directly.
+*/
+#include<kconfig.h>
+
+kconf_schema schema_$inbase\[] = {
+EOS
+
+$record_prefix = "{";
+
+$record_sep = ",\n";
+
+$record_postfix = "}";
+
+$file_postfix = <<EOS;
+
+};
+
+
+EOS
+
+$skip_lines = 1;
+
+@pquote = (1,0,0,1);
+
+sub rec_handler {
+    $arr = shift;
+    if($$arr[1] =~ "KC_STRING") {
+	$$arr[2] = "(khm_int64) L\"".$$arr[2]."\"";
+	$$arr[2] =~ s/\[\~\]/\\0/g;
+    }
+
+    if($#$arr == 2){
+	$$arr[3] = "";
+    }
+}
+
+$record_parser = \&rec_handler;
diff --git a/mechglue/src/windows/identity/config/netidmgr_intver.h.in b/mechglue/src/windows/identity/config/netidmgr_intver.h.in
new file mode 100644
index 000000000..d1863c433
--- /dev/null
+++ b/mechglue/src/windows/identity/config/netidmgr_intver.h.in
@@ -0,0 +1,34 @@
+$(VERSIONINT): Makefile
+	$(CP) << $(VERSIONINT)
+/*
+ * This is an autogenerated file.  Do not modify directly.
+ * 
+ * File generated by running $(MAKE) in $(MAKEDIR)
+ * To regenerate, run "$(MAKE) clean" and "$(MAKE) all" on $(MAKEDIR)
+ */
+#ifndef __NETIDMGR_VERSION_INTERNAL_H
+#define __NETIDMGR_VERSION_INTERNAL_H
+
+#include<netidmgr_version.h>
+
+/* Language specific version strings */
+#define KH_VERSTR_COMPANY_1033	"$(NETIDMGR_SRC_COMPANY_1033)"
+#define KH_VERSTR_COPYRIGHT_1033 "$(NETIDMGR_SRC_COPYRIGHT_1033)"
+#define KH_VERSTR_PRODUCT_1033	"$(NETIDMGR_PRODUCT_1033)"
+#define KH_VERSTR_VERSION_1033	"$(NETIDMGR_VERSION_STR_1033)"
+
+!ifdef NETIDMGR_COMMENT_STR_1033
+#define KH_VERSTR_COMMENT_1033	"$(NETIDMGR_COMMENT_STR_1033)"
+#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_COMMENT_1033
+!endif
+!ifdef NETIDMGR_PRIVATE_STR_1033
+#define KH_VERSTR_PRIVATE_1033	"$(NETIDMGR_PRIVATE_STR_1033)"
+#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_PRIVATE_1033
+!endif
+!ifdef NETIDMGR_SPECIAL_STR_1033
+#define KH_VERSTR_SPECIAL_1033	"$(NETIDMGR_SPECIAL_STR_1033)"
+#define KH_VERSTR_BUILDINFO_1033 KH_VERSTR_SPECIAL_1033
+!endif
+#endif
+<<
+
diff --git a/mechglue/src/windows/identity/config/netidmgr_version.h.in b/mechglue/src/windows/identity/config/netidmgr_version.h.in
new file mode 100644
index 000000000..2be3943a5
--- /dev/null
+++ b/mechglue/src/windows/identity/config/netidmgr_version.h.in
@@ -0,0 +1,62 @@
+$(VERSIONEXT): Makefile
+	$(CP) << $(VERSIONEXT)
+/* Copyright (c) 2004 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef __NETIDMGR_VERSION_H
+#define __NETIDMGR_VERSION_H
+
+#include<windows.h>
+
+/* Version number macros */
+#define KH_VERSION_MAJOR 	$(NETIDMGR_VERSION_MAJOR)
+#define KH_VERSION_MINOR 	$(NETIDMGR_VERSION_MINOR)
+#define KH_VERSION_PATCH 	$(NETIDMGR_VERSION_PATCH)
+#define KH_VERSION_AUX 		$(NETIDMGR_VERSION_AUX)
+
+#define KH_VERSION_API          $(NETIDMGR_VERSION_API)
+
+#define KH_VERSION_LIST 	$(NETIDMGR_VERSIONC)
+#define KH_VERSION_STRING 	"$(NETIDMGR_VERSION)"
+#define KH_VERSION_STRINGW 	L"$(NETIDMGR_VERSION)"
+#define KH_VERSION_STRINGC 	"$(NETIDMGR_VERSIONC)"
+#define KH_VERSION_STRINGCW 	L"$(NETIDMGR_VERSIONC)"
+#define KH_VERSION_STRINGAPI    "$(NETIDMGR_VERSION_API)"
+
+/* Version definition macros */
+#define KH_VER_FILEFLAGMASK     0x17L
+#define KH_VER_FILEFLAGS 	$(kh_fileflags)
+#define KH_VER_FILEOS 		$(kh_fileos)
+#define KH_VER_FILETYPEDLL 	$(kh_filetype_dll)
+#define KH_VER_FILETYPEAPP 	$(kh_filetype_app)
+
+/* Special macros for NetIDMgr special string resources */
+#define NIMV_MODULE             "NIDM_Module"
+#define NIMV_PLUGINS            "NIDM_Plugins"
+#define NIMV_APIVER             "NIDM_APIVers"
+#define NIMV_SUPPORT            "NIDM_Support"
+
+#endif
+<<
+
diff --git a/mechglue/src/windows/identity/doc/Makefile b/mechglue/src/windows/identity/doc/Makefile
new file mode 100644
index 000000000..b9cc463b3
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/Makefile
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2004 Massachusetts Institute of Technology
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+MODULE=doc
+!include <../config/Makefile.w32>
+
+all: mkdirs docs
+
+docs:
+	$(DOXYGEN) <<
+@INCLUDE = doxyfile.cfg
+
+PROJECT_NUMBER = "$(KHIMAIRA_VERSION)"
+
+OUTPUT_DIRECTORY = "$(DOCDIR)"
+
+STRIP_FROM_PATH = "$(SRC)"
+
+INTERNAL_DOCS = NO
+
+WARN_LOGFILE = "$(OBJ)\doxywarnings.txt"
+
+INPUT =  "$(SRC)\include"
+INPUT += "$(SRC)\kconfig"
+INPUT += "$(SRC)\kcreddb"
+INPUT += "$(SRC)\kmq"
+INPUT += "$(SRC)\ui"
+INPUT += "$(SRC)\uilib"
+INPUT += "$(SRC)\util"
+INPUT += "$(SRC)\doc"
+INPUT += "$(SRC)\kmm"
+INPUT += "$(SRC)\kherr"
+!ifndef NO_AFS
+INPUT += "$(SRC)\plugins\afs"
+!endif
+
+IMAGE_PATH = "$(SRC)\doc\images"
+
+INCLUDE_PATH = "$(INCDIR)" "$(SRC)\include"
+
+CHM_FILE = "$(DOCDIR)\devdocs.chm"
+<<
+	-$(HHC) $(DOCDIR)\html\index.hhp
+
+clean::
+	$(RMDIR) /s $(DOCDIR)\html
+	$(RM) $(DOCDIR)\*.*
diff --git a/mechglue/src/windows/identity/doc/cred_aquisition.h b/mechglue/src/windows/identity/doc/cred_aquisition.h
new file mode 100644
index 000000000..251b5b2c7
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/cred_aquisition.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2005 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \page cred_acq Managed credential acquisition
+
+    Credential providers and the identity provider must participate in
+    managed credential acquisition in order to respond to the user's
+    requests to obtain new credentials for an identity or to obtain
+    new credentials for an existing identity.
+
+    There are two major processes that result in managed credential
+    acuqisition.  One is the acquisition of initial credentials, while
+    the other is the acquisition of new crednetials.  Both processes
+    acquire new credentials (or replace existing credentials with new
+    ones). The difference between the two processes lie in the way the
+    new credentials are obtained.  Initial credentials are obtained
+    using user supplied username and password while new credentials
+    are obtained using other existing credentials.
+
+    \section cred_acq_init Initial Credentials
+
+    When a user initiates the process of initial credential
+    acquisition, NetIDMgr broadcasts a
+    <::KMSG_CRED,::KMSG_CRED_INITIAL_CREDS> message.  Credential
+    providers which need to participate in the initial credential
+    acquisition should respond to this message as detailed in 
+    \ref cred_acq_handle.
+
+    \section cred_acq_new New Credentials
+
+    When a user initiates the process of obtaining new credentials
+    based on existing credentials, NetIDMgr broadcasts a
+    <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> message.  Credential providers
+    which need to participate in the initial credential acquisition
+    should respond to this message as detailed in \ref cred_acq_handle.
+
+    The following pages provide detailed information:
+
+    - \subpage cred_acq_new_resp
+    - \subpage cred_acq_dlgproc
+ */
+
+/*! \page cred_acq_new_resp Handling new credentials acquisition
+
+    The process of acquiring new credentials whether they are initial
+    credentials or not, happen as follows :
+
+    - NetIDMgr creates a ::khui_new_creds object and a credentials
+      acquisition window.
+
+    - <::KMSG_CRED,::KMSG_CRED_INITIAL_CREDS> or
+      <::KMSG_CRED,::KMSG_CRED_NEW_CREDS> is sent to all the
+      credentials providers.
+
+    - The credential providers create the panels (where appropriate)
+      for customizing their respective credential types.  The type,
+      panel and any dependency information is populated into a
+      ::khui_new_creds_by_type structure and added to the
+      ::khui_new_creds structure.
+
+    - <::KMSG_CRED, ::KMSG_CRED_DIALOG_PRESTART> is sent to all the
+      credentials providers.  Credentials providers should use this
+      message to finialize initialization in preparation of showing
+      the credentials acquisition window, such as by initializing the
+      controls of the individual panels.
+
+    - <::KMSG_CRED, ::KMSG_CRED_DIALOG_START> is sent to all the
+      credentials providers.
+
+    - The dialog for obtaining credentials is displayed.
+      Notifications between the main dialog and the individual panels
+      are done through ::KHUI_WM_NC_NOTIFY messages to the dialog
+      procedures.
+
+    - Once the dialog completes, NetIDMgr sends
+      <::KMSG_CRED,::KMSG_CRED_DIALOG_END> message to all the
+      credentials providers.  The UI portion ends here.  The
+      individual dialog controls are destroyed as a result of the main
+      credentials acquisition window being destroyed.
+
+    - NetIDMgr posts <::KMSG_CRED,::KMSG_CRED_DIALOG_PROCESS> message
+      to all the credentials providers.  Each provider should check if
+      the user cancelled the dialog or indicated that the new
+      credentials should be obtained and act accordingly.  The
+      credentials provider is responsible for removing the
+      ::khui_new_creds_by_type structre from the ::khui_new_creds
+      structure and freeing up any resources it allocated earlier in
+      preparation for obtaining new credentials.
+
+    \section cred_acq_handle Responding to credential acquisition messages
+
+    The credential acquisition messages are
+    <::KMSG_CRED,::KMSG_CRED_INITIAL_CREDS> and <::KMSG_CRED,
+    ::KMSG_CRED_NEW_CREDS>.  They are structured as follows :
+
+    - \b type : ::KMSG_CRED
+    - \b subtype: ::KMSG_CRED_INITIAL_CREDS or ::KMSG_CRED_NEW_CREDS
+    - \b uparam : 0 (unused)
+    - \b vparam : a pointer to a ::khui_new_creds structure.
+
+    The \a vparam parameter of the message, as shown above, is a
+    pointer to a ::khui_new_creds structure.  You can use the \a
+    subtype field of this structure to determine whether this is an
+    initial credentials acquisition or a new credentials acquisition
+    at any point.
+
+    In response to this message, a credentials provider is expected to
+    provide a configuration panel which the user can use to customize
+    how the credentials of this type are to be obtained.  The panel is
+    described by the ::khui_new_cred_panel structure.
+
+    \subsection cred_acq_panel_spec Specifying the credentials type panel
+
+    The credentials type panel is used by the user to customize how
+    credentials of the specified type are to be obtained.  The
+    ::khui_new_cred_panel structure that describes the panel can be
+    used to specify a number of parameters that guide how the panel is
+    to be displayed in the new credentials acquisition dialog.
+
+    The \a name field defines a localized string that will be
+    displayed in the tab control that houses the panel.  Optionally,
+    an icon can be specified in the \a icon field which will appear
+    alongside the name.  A tooltip may be provided in the \a tooltip
+    field which will be displayed when the user hovers the mouse over
+    the tab.
+
+    In order to assert that the tab appears at a specific position in
+    the list of tabs, you can specify a positive number in the \a
+    ordinal field.  Zero does not count as a valid ordinal.  The
+    panels with positive ordinals are arranged first in increasing
+    order of ordinal (conflicts are resolved by sorting along the \a
+    name).  Then the panels without a positive ordianl are arranged
+    behind these in increasing order of \a name.
+
+    The \a hwnd_panel field is used to specify the handle to the
+    dialog or window of the panel.  The parent of this window should
+    be set to the \a hwnd parameter of the ::khui_new_creds structure
+    which is passed in to the message handler.
+
+    Following is a code snippet which suggests how this could be done:
+
+    \code
+       // Message handling code for KMSG_CRED_NEW_CREDS or
+       // KMSG_CRED_INIT_CREDS
+       ...
+       khui_new_creds * c;
+       khui_new_creds_by_type * t;
+
+       c = (khui_new_creds *) vparam;
+       t = PMALLOC(sizeof(*t));
+       ZeroMemory(t, sizeof(*t));
+
+       t->type = my_cred_type;
+
+       // set look and feel params
+       t->ordinal = 3; // third in line
+       t->name = L"My panel name";
+       t->icon = LoadIcon(my_hInstance, MAKEINTRESOURCE(IDI_PANEL_ICON));
+       t->tooltip = L"Configure credentials of my type";
+
+       t->hwnd_panel = CreateDialog(
+           my_hInstance, 
+	   MAKEINTRESOURCE(IDD_MY_PANEL),
+	   c->hwnd,
+	   my_dialog_proc);
+
+       if(KHM_FAILED(khui_cw_add_type(c,t))) {
+           // handle error
+       }
+    \endcode
+
+    It is important to note that the ::khui_new_creds_by_type pointer
+    that is passed into khui_cw_add_type() points to an allocated
+    block of memory which should remain in memory until
+    <::KMSG_CRED,::KMSG_CRED_DIALOG_PROCESS> message is received.
+
+    For information on how the dialog procedure should be written, see
+    \ref cred_acq_dlgproc .
+ 
+*/
+
+/*! \page cred_acq_dlgproc Writing the dialog procedure for a cred type panel
+
+    
+*/
diff --git a/mechglue/src/windows/identity/doc/cred_data_types.h b/mechglue/src/windows/identity/doc/cred_data_types.h
new file mode 100644
index 000000000..8fa7b1f36
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/cred_data_types.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2005 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \page cred_data_types Data types in NetIDMgr
+
+    NetIDMgr's Credentials Database supports several useful data types.  In
+    addition, plug-ins can define custom data types.  Only a few operations
+    are expected of these data types since the core KCDB delegates fine grained
+    operations to other entities that understand the underlying format.
+
+    A field in a credential can have any one of these data types, but it must
+    have some data type.  Each value can be at most \a KCDB_TYPE_MAXCB bytes
+    in length regardless of the data type.
+
+    Some data types have a fixed size (such as \a Int32), while others are
+    variable size.  The required memory for each field in a credential is
+    allocated as needed.
+
+    \section kcdb_pg_dt Data types
+
+    Descriptions of individual data types are below.
+
+    \subsection kcdb_pg_idt Individual data types
+
+    \subsubsection kcdb_pg_idt_v Void
+
+    Pretty useless.  This data type is used to indicate that the associated
+    object doesn't actually contain any data.
+
+    \subsubsection kcdb_pg_idt_s String
+
+    A unicode string that is terminated with a unicode NULL (L'\\0').  By
+    default, the type has the following flags :
+
+    \a KCDB_TYPE_FLAG_CB_AUTO
+
+    This is because, as long as the string is terminated with a unicode NULL,
+    the length of the string, and therefore it's size in bytes, can be inferred
+    from the data itself.
+
+    \subsubsection kcdb_pg_idt_d Date
+
+    Dates and times in NetIDMgr are stored as \a FILETIME structures.  Utility
+    functions are provided for converting from other formats such as \a time_t.
+
+    \subsubsection kcdb_pg_idt_i Interval
+
+    Stores an interval of time. Stored as a 64 bit signed integer. The
+    string representation of this data type is different from the \a
+    Date data type and designate an interval of time.
+
+    The special value _I64_MAX (which is defined in limits.h as
+    0x7fffffffffffffff, or in otherwords, the largest positive value
+    that can be stored in a 64 bit signed integer) is used to
+    represent an interval of unknown length.
+
+    The string representations of a data value of Interval type are
+    defined as follows for English (US):
+
+    - "(Unknown)" if the value is _I64_MAX
+
+    - "(Expired)" if the value is less than zero
+
+    - "%d days %d hours" if the value is greater than 24 hours
+
+    - "%d hours %d mins" if the value is greater than 1 hour
+
+    - "%d mins %d secs" if the value is greater than 1 minute
+
+    - "%d seconds" otherwise
+
+    \subsubsection kcdb_pg_idt_i32 Int32
+
+    A signed 32 bit integer.
+
+    \subsubsection kcdb_pg_idt_i64 Int64
+
+    A signed 64 bit integer.
+
+    \subsubsection kcdb_pg_idt_da Data
+
+    Raw data.  Can contain a byte stream.  This data type can be used by
+    plug-ins to associate raw data with a credential.  However, there is no
+    built in string representation for this data type.  As such, this is not
+    meant to be used for storing anything that has to be displayed to the user
+    verbatim.
+
+    \section kcdb_pg_cust Custom data types
+
+    \subsection kcdb_pg_cb Custom data type call backs
+
+    Custom data types in the NetIDMgr Credentials Database are defined using
+    \a kcdb_type structures which must include several callback functions.
+    The expected behavior of these callback functions is documented below.
+
+    \subsubsection kcdb_pg_cb_ts toString
+
+    \code
+      khm_int32   toString(
+        const void * data,
+        khm_int32 cb_data,
+        wchar_t *buffer,
+        khm_int32 *pcb_buffer,
+        khm_int32 flags);
+    \endcode
+
+    Produce the localized string representation of the object pointed to by
+    \a data.  The size of the data block is specified by the \a cb_data
+    parameter.  If the data type specified the \a KCDB_TYPE_FLAG_CB_AUTO flag
+    then \a cb_data can be \a KCDB_CBSIZE_AUTO, in which case the size of the
+    data block is to be inferred.
+
+    \a toString should assume that the block of data pointed to by \a data is
+    valid for this data type.
+
+    The \a pcb_buffer parameter is always a valid pointer to an \a khm_int32
+    variable.
+
+    The \a buffer parameter is a pointer to a \a wchar_t buffer which is to
+    receive the unicode string representing the object.  \a buffer may be
+    \a NULL, in which case the required size of the buffer should be returned
+    in \a pcb_buffer.  In this case, the function should return
+    \a KHM_ERROR_TOO_LONG.
+
+    If the \a buffer parameter is not \a NULL and the \a pcb_buffer specifies
+    that the buffer is large enough to hold the string representation, the
+    function should copy the string representation to the buffer, set the
+    \a pcb_buffer to the number of bytes that were copied including the
+    terminating \a NULL, and return \a KHM_ERROR_SUCCESS.
+
+    If the \a buffer parameter is not \a NULL and the \a pcb_buffer specifies
+    a buffer that is not large enough, the function should set \a pcb_buffer
+    to the required size (including the terminating \a NULL) and then return
+    \a KHM_ERROR_TOO_LONG.
+
+    \subsubsection kcdb_pg_cb_cmp comp
+
+    \code
+      khm_int32 comp(
+        const void * data1,
+        khm_int32 cb_data1,
+        const void * data2,
+        khm_int32 cb_d2);
+    \endcode
+
+    Compares two objects and returns a value indicating the relative ordering.
+
+    Since the KCDB does not interpret any data type, it relies on a loose
+    definition of what a relative ordering is.  It is left up to each data
+    type callback to interpret what 'ascending' and 'descending' mean.
+
+    The return value \a r should be as follows :
+
+    \a r < 0 : if \a data1 < \a data2
+
+    \a r > 0 : if \a data1 > \a data2
+
+    \a r = 0 : if \a data1 = \a data2 or no relative ordering can be determined
+    for the two objects \a data1 and \a data2.
+
+    The function should assume that both objects are valid for this data type.
+
+    The size specifiers \a cb_data1 and \a cb_data2 can (either or both) be
+    \a KCDB_CBSIZE_AUTO if the data type specified \a KCDB_TYPE_FLAG_CB_AUTO
+    flag.
+
+    \subsubsection kcdb_pg_cb_dup dup
+
+    \code
+      khm_int32 dup(
+        const void * d_src,
+        khm_int32 cb_src,
+        void * d_dst,
+        khm_int32 * pcb_dst);
+    \endcode
+
+    Duplicate an object.  The object pointed to by \a d_src is to be copied to
+    the buffer pointed to by \a d_dst.  The function is to assume that \a d_src
+    object is valid.  The size specifier \a cb_src may be \a KCDB_CBSIZE_AUTO
+    if \a KCDB_TYPE_FLAG_CB_AUTO was specified for the data type.
+
+    If \a d_dst pointer is \a NULL, then the required buffer size should be
+    returned in \a pcb_dst.  In this case, the function itself should return
+    \a KHM_ERROR_TOO_LONG.  The same behavior should occur if \a d_dst is non
+    \a NULL and \a pcb_dst indicates that the buffer is not sufficient.
+
+    If \a d_dst is not \a NULL and \a pcb_dst indicates that the buffer is
+    sufficient, then a copy of the object in \a d_src should be placed in
+    \a d_dst.  The function shold return \a KHM_ERROR_SUCCESS and set
+    \a pcb_dst to the number of bytes that were copied.
+
+    This callback will only be called when the credentials database is
+    retrieving objects from the outside.  Once it receives an object it may be
+    copied or moved as required.  Hence the object should not assume to reside
+    in a specific location of memory.  Also, \a dup is not intended to perform
+    such functions as reference counting which require knowledge of a precise
+    number of instances of an object, as the credentials database may copy
+    the object simply by copying the block of memory.
+
+    Note that whenever \a pcb_dst is to be set, it MUST be set to a valid byte
+    count.  It can not be assigned \a KCDB_CBSIZE_AUTO even if the data type
+    supports it.  The \a pcb_dst parameter is used internally to allocate
+    memory for the object.
+    
+    \subsubsection kcdb_pg_cb_iv isValid
+
+    \code
+      khm_boolean isValid(
+        const void * data,
+        khm_int32 cb_data);
+    \endcode
+
+    Checks if the object pointed to by the \a data pointer is a valid object
+    for this data type.  If the data type specified the \a KCDB_TYPE_CB_AUTO
+    flag, then the \a cb_data parameter may be \a KCDB_CBSIZE_AUTO, in which
+    the size of the object should be inferred from the data.
+
+    The function should be able to determine the validity of the object and
+    return \a TRUE if it is valid.  Return \a FALSE if it isn't, or if the
+    size of the object can not be inferred from the given data, or if the
+    inferred size exceeds \a KCDB_TYPE_MAXCB.
+
+*/
diff --git a/mechglue/src/windows/identity/doc/cred_main.h b/mechglue/src/windows/identity/doc/cred_main.h
new file mode 100644
index 000000000..b5be8ad5a
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/cred_main.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \page cred Credentials Providers 
+
+    \section cred_contents Contents
+
+    - \subpage cred_data_types
+    - \subpage cred_acq
+    - \subpage cred_prop_pages
+    - \subpage cred_msgs
+*/
diff --git a/mechglue/src/windows/identity/doc/cred_msgs.h b/mechglue/src/windows/identity/doc/cred_msgs.h
new file mode 100644
index 000000000..49f644c91
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/cred_msgs.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \page cred_msgs Handling credentials provider messages
+
+A credentials provider plugin receives a number of messages during the
+course of execution.  This section describes the appropriate ways of
+handling these messages.
+
+\section pi_credmsg_system System mesages
+
+There are only two system messages that a credentials provider needs
+to handle.  Both of these are explained elsewhere as they deal with
+initialization and uninitialization of the plugin.  See the following
+two sections for details on handling these messages.
+
+- <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> \ref pi_pt_cred_init
+- <::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> \ref pi_pt_cred_exit
+
+\section pi_credmsg_cred Credential messages
+
+
+
+*/
diff --git a/mechglue/src/windows/identity/doc/cred_prop_pages.h b/mechglue/src/windows/identity/doc/cred_prop_pages.h
new file mode 100644
index 000000000..e4d41b106
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/cred_prop_pages.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2005 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \page cred_prop_pages Property Pages for Credentials
+
+   This section describes the logistics of property pages.  When a
+   user selects the 'Properties' option from a menu (either the File
+   menu or a context menu), then a KHUI_ACTION_PROPERTIES action is
+   triggered.  This is handled by the credentials window and triggers
+   the launch of a property sheet if there is a valid context to
+   extract properties from.
+
+   Sequence of actions:
+
+   - KHUI_ACTION_PROPERTIES action is triggered.
+
+   - The main window dispatches the action to the credentials window.
+
+   - If there is a valid context, then the credentials window calls
+     khui_ps_create_sheet() to create an empty property sheet
+     structure of type ::khui_property_sheet.  The \a ctx member of
+     the structure is populated with the property context obtained
+     through khui_context_get().
+
+   - A global message is broadcast of type
+     <::KMSG_CRED,::KMSG_CRED_PP_BEGIN> with the parameter blob that
+     is a pointer to the ::khui_property_sheet structure.
+
+   - Subscribers to <::KMSG_CRED> messages handle the message, check
+     the \a ctx member of the structure and determine whether or not
+     and what type property pages to add to the property sheet.  New
+     property sheets are added by calling khui_ps_add_page().
+
+   - Once all the pages are added, a
+     <::KMSG_CRED,::KMSG_CRED_PP_PRECREATE> message is broadcast.
+     This is a chance for the property page providers to do any
+     processing before the property page is created.
+
+   - The property sheet is created and made visible with a call to
+     khui_ps_show_sheet().
+
+   - The NetIDMgr message loop takes over.  Further interaction
+     including notifications of 'Ok','Cancel','Apply' and other
+     property sheet related actions are handled through WIN32
+     messages.
+
+   - Once the user closes the property sheet, a
+     <::KMSG_CRED,::KMSG_CRED_PP_END> message is sent to all
+     subscribers.  Individual subscribers who added pages to the
+     property sheet must free up any associated resources at this
+     point.
+
+   - All the ::khui_property_page structures that were allocated as
+     well as the ::khui_property_sheet structure are freed up with a
+     call to khui_ps_destroy_sheet().
+
+The maximum number of property sheets that can be open at one time is
+currently set to 256.  Each property sheet can have a maximum of 16
+property pages.
+ */
diff --git a/mechglue/src/windows/identity/doc/doxyfile.cfg b/mechglue/src/windows/identity/doc/doxyfile.cfg
new file mode 100644
index 000000000..7aac8021b
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/doxyfile.cfg
@@ -0,0 +1,1000 @@
+# Doxyfile 1.2.18
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = NetIDMgr
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = 
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, 
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en 
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, 
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these class will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will
+# prepend the brief description of a member or function before the
+# detailed description.  Note: if both HIDE_UNDOC_MEMBERS and
+# BRIEF_MEMBER_DESC are set to NO, the brief descriptions will be
+# completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show
+# all inherited members of a class in the documentation of that class
+# as if those members were ordinary class members. Constructors,
+# destructors and assignment operators of the base classes will not be
+# shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = 
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower case letters. If set to YES upper case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments  will behave just like the Qt-style comments (thus requiring an 
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# reimplements.
+
+INHERIT_DOCS           = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consist of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+SHOW_DIRECTORIES       = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = 
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.
+
+INPUT_FILTER           = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = header.html
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet
+
+HTML_STYLESHEET        = stylesheet.css
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output dir.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run 
+# the html help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND             = YES
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one
+# that is generated for HTML Help). For this to work a browser that
+# supports JavaScript and frames is required (for instance Mozilla,
+# Netscape 4.0+, or Internet explorer 4.0+). Note that for large
+# projects the tree generation can take a very long time. In such
+# cases it is better to disable this feature.  Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimised for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assigments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_XML           = NO
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = _WIN32 \
+                         UNICODE \
+                         _UNICODE
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are
+# alone on a line, have an all uppercase name, and do not end with a
+# semicolon. Such function macros are typically used for boiler-plate
+# code, and will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermedate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
+
+# The CGI_NAME tag should be the name of the CGI script that 
+# starts the search engine (doxysearch) with the correct parameters. 
+# A script with this name will be generated by doxygen.
+
+CGI_NAME               = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the 
+# cgi binaries are located. See the documentation of your http daemon for 
+# details.
+
+CGI_URL                = 
+
+# The DOC_URL tag should be the absolute URL to the directory where the 
+# documentation is located. If left blank the absolute path to the 
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL                = 
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the 
+# documentation is located. If left blank the directory on the local machine 
+# will be used.
+
+DOC_ABSPATH            = 
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary 
+# is installed.
+
+BIN_ABSPATH            = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to 
+# documentation generated for other projects. This allows doxysearch to search 
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS          = 
diff --git a/mechglue/src/windows/identity/doc/footer.html b/mechglue/src/windows/identity/doc/footer.html
new file mode 100644
index 000000000..13314c2b0
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/footer.html
@@ -0,0 +1,19 @@
+<hr size="1">
+
+<table width="100%" border="0">
+  <tr>
+    <td>
+      <address style="align:right;">
+        <small>Generated on $datetime for $projectname $projectnumber by <a href="http://www.doxygen.org/index.html">Doxygen</a> $doxygenversion<br>
+	© 2004 Massachusetts Institute of Technology. Contact <a href="mailto:khimaira@mit.edu">khimaira@mit.edu</a><br>
+	</small>
+      </address>
+    </td>
+    <td width="100" align="right">
+      <img src="khimaira_logo_small.png" border="0">
+    </td>
+  </tr>
+</table>
+
+</body>
+</html>
diff --git a/mechglue/src/windows/identity/doc/header.html b/mechglue/src/windows/identity/doc/header.html
new file mode 100644
index 000000000..4235468f3
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/header.html
@@ -0,0 +1,5 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+<title>$title
+
+
diff --git a/mechglue/src/windows/identity/doc/images/credview-select-outline.jpg b/mechglue/src/windows/identity/doc/images/credview-select-outline.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d06ca9f88cc2b5f816b837f4a3d2247186df5c0b
GIT binary patch
literal 16084
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
Xg7(?pxrzMKb^#C2hN!Pd`>6i`gPRKu

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/identity/doc/images/khimaira_logo_small.png b/mechglue/src/windows/identity/doc/images/khimaira_logo_small.png
new file mode 100644
index 0000000000000000000000000000000000000000..26c338007d5dc8534986c5dc5461d786c157a3d5
GIT binary patch
literal 3970
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
Xg7(?pxrzMKb^#C2hN!Pd`>6i`gPRKu

literal 0
HcmV?d00001

diff --git a/mechglue/src/windows/identity/doc/main_page.h b/mechglue/src/windows/identity/doc/main_page.h
new file mode 100644
index 000000000..238ce3e6c
--- /dev/null
+++ b/mechglue/src/windows/identity/doc/main_page.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2005 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \mainpage NetIDMgr
+
+    \image html khimaira_logo.png
+
+    \section main_dev Documentation for Developers
+
+    NetIDMgr is a credentials manager, which currently manages
+    Kerberos IV, Kerberos V and AFS credentials.  This document
+    describes the API that is implemented by the NetIDMgr system.
+
+    See the following sections for more information :
+    - \subpage license
+    - \subpage bugs
+    - \subpage releases
+
+    © 2004 Massachusetts Institute of Technology
+*/
+
+/*!
+    \page license License agreement and credits
+
+    NetIDMgr is distributed under the MIT License.
+
+    \section license_l MIT License
+
+    Copyright © 2004 Massachusetts Institute of Technology
+ 
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+
+    \section license_credits Credits
+
+    NetIDMgr was developed at the Massachusetts Institute of
+    Technology.
+
+    (Contributor list goes here)
+
+    At the moment, no contributers have come forward to accept
+    responsibility.
+
+    Information Services and
+    Technology at Massachusetts
+    Institute of Technology
+*/
+
+/*! \page bugs Reporting bugs
+
+    NetIDMgr bugs can be reported to 
+    kfw-bugs@mit.edu for now.
+
+    In the future, there will actually be a place to track NetIDMgr bugs.
+
+    When reporting bugs, please include as much information as
+    possible to help diagnose the problem.  More guidelines about
+    reporting bugs will appear here at some point in time.
+
+    \image html khimaira_logo_small.png
+*/
+
+/*! \page releases Prior releases
+
+    - 0.1.1 First Alpha release Nov 01, 2005\n
+      Released along with Kerberos for Windows 3.0.0 beta.
+
+    - 0.1.2 Second Alpha release Nov 30, 2005\n
+      Released along with Kerberos for Windows 3.0.0 beta 2.
+*/
diff --git a/mechglue/src/windows/identity/doc/netidmgr.doc b/mechglue/src/windows/identity/doc/netidmgr.doc
new file mode 100755
index 0000000000000000000000000000000000000000..f6eda5d5a3df0a10dcb06c877cd14a60b1204a96
GIT binary patch
literal 1199616
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%0DP1`v9qQshV6RE` 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

}RDod2;K2)8WfpHLecO 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 z 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

~U@M~$RgkIDmq7YBI)kb)nY zutKF5VIE%(!ssclueWV`I|TjwHu)-oW5bV4tO-#gWO3!%}}bF0vLFS6ft>GJ8t%leEQ zna|^nRGum`3;Ea-Svrt)kY~+D&Bn=S>hN=wRLeUXAI^2BJ&DrM6)|iVi;Lt(+;cC` zYvH|xzuCW#ICHx1$&t?rxAT@VuXJF>8-$AmeuYZzRYN^ z8E*QWzwRatUUjL6jqH8sO@Eq)iue&vJe~OWvk!BH-%5zrSGOs@D>Qt2MI^E1P=Vg6 z0rvq#vx8o7%BvS`9LVvv2t|>nCJIy9)h+pDa%a1v)DQHu<>)e9cMY*AWSe4 zDR)V95XUoIG1RD>AxKfQ!nTn7sC!kT7$2dh6`Lc87a+4Ffb?XRY3tKiw_bQLQz4PNY8b)83Cu&&qDT^j=Kb z{UI--H{zk_B~IFRcsWgYSl(wPL5=il-Los}(Rj^n%exlW?eN|yN^edf`hrXPg0<;) zEbo<;o5y;f!}DnJQp6;`H8eD=dxm%>N%qIdHQmmB(P9%!nXHUWn(R5m)jg%MAQD&y ze}g%CzpFpAVi>9SITBJ(wZ*;Vh_or*9p^sLfg@|yCEy1-4V4*{LH+#_zHb+U^YRkYSXSdjvE zaYHNa2(zaoCMOsrOh1#H+aGarCj$~TF4ukeuCyNgP|LlKUHZ)tMd?#4G1r?5BtN~mDH%Fl zWUG4Eszp11w$%3BGx<5cggpK*O}BjOhZm-%z8}5_%JZz&{fFzfA8VoCmm2?Y)hs11 zCGqE;@S3W@?_2VJwGb=KP*zIv=ax|F(#3zWC;U$Qz64@Y0Sp6nAloM(5Qygc z2h=B_$=T_~(y?k%57ciSZ~C)6o-5%uFXv96fgI=n1Y9CstX{d7m9fS1SU_MKso*spTi z=J?qMPbCkWh)Bg=<>P17tG_FC$@N)}D!o9Y{+G!W2tt}It;FZtwU-9AYVXqBWKQ-P zPT8%NK5ytlPJg{F_$tGc;jS{xR9Oroqpf z$3V2S0Jr;oI3vNb58&Xz+2i{qpGKVc!9l%V&lf5FyOXZZB31QSA&5&W z0tbFDKz~m9T`#~y`bk?gLm4-_sXtlx=Nt(B#lrVt&=I=d$~*=FgXUG{hggFPhC|gc z%jrD8-Dq^2DD?H4P|eWsfbXEFasV$LxQ29o5?cppLaf=RTST-w9Uj!|nA-|#PYYiz zb6X{hw+R#Fe9PaE+4z%MwC4DC zkTBr#&IGQ88DJF(1!|PyhIEUVa6@*G0qkon?pc%|?6XsLX@MKQv~hn7p)JI!SPY?h zCuv`d>vinMC;$y8ur7uShs~vInOjrEcOuO_1$T`GfxE=O?Xm>a{%Y!Vn8-RE?%>e& zSFn1A>Y@n{>!2JPo{bemit1B@*$Qt&y8vX1=hM*5 ze^O0DQXBNEltglmxr;9xnK^t6qLndsmhS`o$^1z>J3B+|C@>F8h1pIPaZqZaR)tRm z=N!lej?nk|hs^PxN$3leYdK}W>8hnRp6<>RO>7OAA}qBS-KiTlT;H{BGn(D2r~-fHe8cdb z+qQ33LA(?Dl(Q(dkhqU3r#!Bhoh?qs*MGvc&pCZ(qp5sEp5mpG=%LxPIHn=q*i$Y3G8kNe;S$LWnc;y=zJ zU@m1}&GC=X$>94Di~mrI|F3_6;r=J`PY(E^)uVjqM{RokEwBH{WzR^orw#wF$tCyS zH{*XkY1uQp{H5OiLvlIFb>fXtXY?TPnx90G*J}^I$lJ;teRZn<7UM?8#Arw#aIdgA zm7=CS=5b>!j@P-Q+GOamR}#%RT)NUMo^q>vk!6<9#(hOu z@f=%>elvpNuCFnh048bXhD7d&aAzYp*-86jXg^wuf=I-OM))+EK)}x=+NPPe3V~yI~9fve$T-N>Wlnk4hKx^sCVnO#VTc6f>z3Q?FF=G|8sC^)e=PER(VIyc#``NeXKxaCYRuM&;{%7ASd82!r)>d#2F=P zc~9v&5OB_sQQTpjD~C;b@pFnZ!wm@120?1UzPfABW0$1ygkwyRg}g>o-eG_7(1n2!@3@#iVk&`>3+RPQ)bC@cyuCs8XH)rD^Fi~(*d zZa8}oH>laT?rAu2<*Qk85vE^)IH=GV#8pnXzPjHXWLbQmE7+lc46cv?$^lb35~XfT zNs^dDL{cssYggs2%~^RE!j$6kfQYLjeG*H}Bq+pRVcg%y^mdWs(DYj|8OmtWnN)1+}K#N$j{w7evso~mq(vx`M_Ps-P?iAm!=_AolFk9uEmpUqZ724 zT>^0a#cKKM0*h%g&PTp+PmrorB3w0laKgOzhR zKkihLdsB^XY=w`fdUB(HqQSmUel zJ}@p8md|5yF}EJufp3$j9Wb0eN&fU1*qFgE@Eg+6m55OkX_t9mv^J){xB#wHC6{t{ zTi`jH{D5Nry3%%tZ3WjBX7SxT8j57zDe~A_2Npxu>h>m(Wbj1Yl+R$(w+ZsY<*gXP zsW3Yjx(7!NKHjB`2*$;Z(q(^9@1j%>DBTl>r$(?T=e#bG-1Uo z>95x)rQMXUo2b|-Y5Xu8Dh@ZVSYBsPb;@cU9O3Re#^G*0QI7ZDHLl*FdiM}{&Uz;eFzk$02EVMV#Db~BMwDu;h0_*v5 zE9T?I1Iq<$N(AeGN6n>lf~U{66+#<|is>&Al+>lmD_3Z+qx-#geFjf$Xt`WiTNRp* zhBynP!@h&kMI7U(eFx3}k*D^y_%C8JfNnkf4w?|&^0wYA+8@`0PnLdUs?&&%a3{7e@ z?q!E+t*<4nj;K>y;)JaFiq>&b;vgN-$M%HC$=%L^0iT{mY1_`$4sDjlzAv62w>?(q zH~6T_?-E78`KR1IyS?$zF3PR28;f+7jv;I}xHlI_;};aK(M{mz8;=~M1!?cqt6!8% zps>}NtX?mU<=Hp!Pb+K&oMFz~egBwc``DL%kyX*E(EnIoc`-m)S^#IVi||xn&$;v+ zq+CZmAM;BpI`6+xUM?D_TkZSD$G!KArUAbs?*BI`_aBD-UGx7(LjS)?$bm?>J)rH* z6O?pqet)fuiH@1!`f?(jM^O&9U*k|dTMrEUS%NA8_zZeziWi6#c;iZQu1rT?5 zUh7lQIG?J{B}4EK8#=Z9I|%on?}JgEeN0p}%f`3<6##A{yA!iyZ}hHENsENXH@t8V z_ZBwmsd`Vtzj@2~#+kQur-d4Q1VSr9vYQv5g{1`CgKL#o`bTJofxx{L;YSYc^Oqls zy!6}}-US3DkwK4qLvQ!{Ym^laK$T=I;}_KI+8;4iiwt*L>L(8kuUynb|H(+t13VB& zK={qn%Dwe$7p44CR;rS<6&()%SXwsT!FepFE2do_YYEaDwb({ z*8N4ef~R~K=R!~vtphHJ49RBlYy_ge7;wk*CiF@AS(=!hwCGl4B=mk9I(lPxcH7Ys7w0vM4%QV%9aU*q|$O)N#yYE~T^jJLu3I08IlYdKe4M9jwZD z34nRr{>s4>Qlx#EBU6zIW(#_zjJrFf2kY?OwD|I12p_MM9Kt5osWwnLZ`!!J==E++ zqU1trQ~o)B=d4+o*0HHU#<$cq`4nS^%mTS8Q+AwjI=p~jiL*npv5n{xRo3FYgS!~? zDxxJYh!Ee`w42u|Lq9t>3^wy+&lGler$_HxR<|_Y9~~o!kJSLxHpx`LU6^>afZKD4 zo#{`pRojSyW^{JwsDif6D91J@r&!J63;W(t)=?m8{DYK`hv%vR=hYxB(`;2CJhkJj z3fI7W1^qafhwZ(Yd&)7(1!MCdrLe-Y@%fyWw^Da%1A+T=T}&Yx3&o?~kjk$SoBdOk zHxLC5nb8VVndjZMc9+nJf?YCIs7wN-j?jCl1Sf207FW4SfhMvNVjdjZ=7wvh<%obgI`62 zX*BVpo&WNHSc(cYw|94fyxVU`z5foMQU>YqRujckjM-VeOfY9iZaS$r;183=qm;(= z0*p6LW53Guwtz2GuDOiWKPg^&6IYJ;*%&$ES; z9w7&HJYtRMaVqPBjx0Bo%u>&Jug&4u+-0v7CPv$tM|o?LMg2$SLpVlEdMfhro!OFU zd(@cR(R$S^3qmxRUFrQF_VFN}PNfa1Oe2FQ^;#&CeHSfSOSzTwtVvu0hUFpHb@&i+ zvWr5$RnydbgTY*wHaPzQ2It}~nw(E}lNLBhGj)!On^&l=c(@JaWYHe1UhR*;t`B$C z3S2HIidGIbM;*Vex`aqDMan?l7|qsXZRqszF2?m9;Tv0j$@UUbkhY@copVoz;8eaw zuh6;x{|?f3A9T zQq(5ipHf)F9_@*&{Wv>hXWus==vDjj#qrl#+i0vATC5#TX;b5F!%7M@Bcld%6gxzb zeq*yGgQsgGsv%{Fr;EoK^b#1$C3~BUth$%Ar#Od>m%r6X)$g1mw;@AMu}$M=WvZ1V z^nGG`?ht2zKnZ8YQ{xU3#H3AP2k!Qs&0`;4;ARA{V5@maRY2eZTfZ0@*iDxs$k5?! zjwYC$>(rfjntK!LIC`#4qcOTglWAo;oIB`( z0b2`^M!Pt-8A)uIw(`p)k~fw_`yF)4c=v#y_XKTuu@tnk@f2(Mz;hhXKjIUa4;z2B*S=^3&42{oK(BOae|HO^;nYu;6-JZHlJ7hjE=$EBzUk8jKuRJf5 z`@rvz*ol=D6)#@~1afW~iG;jT+EKWC+2}LTb8y!LFfQhJOf;?h}>EfD@}GhJ?0$}iNJ8{B};DOwtU@Dm2FIwq)n zO1Ur3Z%yO-PL4W$`Btc9Lt^b~W*?WJrk0M>w^UM$;L1US)GNMISDrS?)oBXm*tP^c zH@SRuZXT=sYgQrIDHottMUtFG2y*`0) zvk&#{Pjb#RA8zHBeh+s!ZDDmt)Q9(3T1)J^wR8S#34>2aEk_<3=CDC6Yl|}eX+h6i z7kM^HbAaZftJ{pz%38O#?1#@2OzjHu@Jo=w%x@cPL?2RWMRy--Yn#!i&T&a=sRCD)(UswSl;wqGA~s+2eq$=mjv#-r{D7k4$;a*yD8 zw@(5yZ5sz*J!MVVl78B=djCVGoTXHbon@a$<0)y1Au4s?O`T0adHEY$lW%6yz;b;< z^(DJ|b>wzrp&d~Mh}O;6$>ik#{~=~Kf%oFuw-b19Vmu6N=NCrZ;MAbM)al+7(*F?G z^%DNDIm`?@IJxMq=eZ{&pwX8QlTSbvnND@NJ}3$IW#b)5!Ppp2G84sC9dU_Yw%I55*gRF^=57}#Qa@os`4`EA{Uw>+n~{mjSfIBQ|J7SiKN|fHeh7gY7dp3jel+|a zJYA~YQn%#%`pXlL_)OhPZTDZOe~j!u6)SVYYH!&pK-tuoJ!S8uF3O0E=h^!pW@v9#`SbkQ zVDi{cQQSk%^lr=k6vHW?zoPhGb^r3@Qfh0OPs!y#?z{ zz-aVu-`$M5kiG#2YJpe)H2Ak-!9cN9>p(Y@0=0#;`omsp69){< z#=X~H^=$7Ya73kG(4!Qf>-=E)5q~ZtbLo1~Hejo405)0YVtyr$)ckkk+C2Yf$=4M2 zR7b1(uZmg$lF6Jy?qNOkFY)3d4YFePq^37G$X061=yi+mT1jppi1P4sR7M zX^+qjA5_Sem?>{C=_y9);}&EG5-h8>Is_@v=oy2{IANa{Nx9c&nrg&e1?N%Dwutgr zJ{a#iOO`1+HUTLC=6G-O{D}0NyX!oKa`5@LBOxK$&)Pmd(ExhDr4Wuow7RbNPZ!L- zCh2DO^ebd(B_G5_9gbgVW`<)&@Yr4oJ@pSDecFD)KYi}G>f1&BSX zUN$CGxC?}eRo=B~sD3H^hB;7nU_?nLC=h@sN~!N;kj5b?y7$YSRH+K{Mz zN75-IamTN=gsWy)<@EKw*T)NktQV9zo91;|7{@P^;HpYlWNEtM&I495IhemjZ#u30K$nTrVjW27ltBS%J^e_YB-`5%)-&T}04aRMt`y=-{!O zN8C6|J}0BT$`!f1y{c4ax?3>3*wqQlf49Gbwpb&AlEV6TE2oG0)N_LZRH<5FI5&T0 zsO15=WcuwB&*#b)Vubq@q#seu`Oa25HP(bT*zsSge5j}@oM+Leu&Fy=i)0}^{QaEHx5yb0bPhxz#UHvMny0|DBnT)FKs-=-1Th|;v~=0<)Rf*y88!R?UJ zg-%rs@Iu5L<`Z*I_}=Z`r>XZUIKwHa1?gR6N?Lnt|IOc<$;J3Qg`TnuppCe;Qj!6u zY<{etYF*+!pR?xBVfAL;eD!YdAew3(t{T^yTO^pXt}aJcLclHUceOUjUl1k53M!sH zMOa(VQM(?)RS11C%%c#NK2yfE9wzu23D4AMvddbi(M4>8_vL%P@DO!552q~Xk0Fx! z9L1VxDqcd%>9#q}e{B*;Q_4M<{3&MNO5?SeFm_CG7!QN=7{|6k!g;ucT__!AASTi54eJ?Sdj#%bcN`HC)X!NEp^ogGbYiKo^>RS4A2vC z?*doe$m;}R({7mY`suBchX#C&ka(U!w|VBqvEH`tpfp8Era0T}djNO170Yq(nrB_k zM04eC$a>h}c=Egw{Pm9BRPTuCn~Pml(MBKLQuuFeEni!ZbxTfLmg-1K%1wo$;8^wKE2E5HYaBT5+p&0Qiz2{PZajG>*I2rSA}Kf?1LYbJD2Z9YMc`@ z<&RYRfl;dO)Au01nPhCWXys5~gpRcLpz;qI5!NX=YeM{G-m$nfpJAQQsE|I&XQHI` zDX}$plUFP^s^chXz0Rr49vJi7R~EQLH)ZA9b7n4HdDvWJe{6gFzMrWM>tVk2+RrBs zg}*vfqQpz_>nOO(vhIL3u5Y+=Oz1U|PYqwlg}i5D!K>ug0&YGMgKC34Kp8JExMHNI zQ>@R<6?oo>E(gY4S!)mZrpRhFd*)-)aR)BDR=!`pLQ|A)DYar)DDJCS1*&(y?8C_ZNU2* zPKIaRIjosVo+Eq{D6c&v?XVrb>ST z*DV*BOZ4(jwx75y@;|EABTnqAGzj6>4*8-5d3-FBPvbb`F$?f8_eSqE;>7;r#U{cb z7QK^`jG{c7Gr2eQ&yt;=nVh`QaO1pJmQV)eA`X8Y!K7DDd-N zp&gdB{4YDXX9^>+^Tv}~dO%7;+pV=L)7t-&R&PhrJr zG&QgMB!B|s7YgG{*M9utDgDh`KtMXu2*t4jW{F9+_Mg(zHx;n&DQZ{|R$juby9WE; zo#=lc)B>%*$IKWF`tx*%h{tJY^a)#qc=H5k{rK>FZeFD6m}t!hic5NK3lT;yLRX5oRBmFJ8G2Sq}70&3>Ts z3jcsz#r)`}CvK{8d0PXp7CBRgEc0dP zD>!IIL1(?5d8G(^Ko9Fu)6q+a=7+zjR}`da#~Xv+E-=7CPYM+6+`0L)R5s@pnhyoPhIBOsbe zc97#3?G=u2Iy_07x;a@ZR9#qQdX^zEK)JxSF~|KU}mb&J51 zD6}?dv9qu~$dalvB0;ia430SpD`IO+SYmX>4}tA|sHF0m znDCva;w5Cyw)hRgkTmx7YTtf0FdPUBq53UsS!;2KXAXUgI=9kbZQ#L^!MgOLw3Urf z!fk!7{)&>|>amyM-d*^}QHoOGqdfLA+s(?Bsctn=;yGjen0NTzjkVS9Aggz8CyWVa zzICfYMlAecOBiZ3AC-9uTtmk?VYiOrbYJKXMpMq%O84nv~ZDJnhfg%r0^a4AqpwivEa_c{sCV`zQ-+;R} zL02T@F6yHBE2jZ@U9FtlZdi2A_}94!{H*x=&qBrIcGtYS3+24OY@264t8#McO!e=^ zOJS|FT)!;5$0X4CxH@67f-J5irEzkN_*VUFBnHa`+rF3ga%}6_;VlQt#fm zZWexxP)&;m)X7{fFY6WEs>6IQ9^RLIAiQ9yU06zvn<$scmk-8evGp^;vI%PxIi?+dutqQ(QL{lVN1+~z9aRA?nm4F@tEk2u^2rueEU>BtO z!peO+AH!1+qgK=T)m0yk{~??C2MwF)IG6NDo;R{fV;XutHPQOdmJbEj@Rad|0eDDal!h0@zW)6ApftODlh7yXSM9oVl2J zjhUM%;;tnPd=))HG8`%85zB|AH5qjD-=$Ozc-GFsdwdB=!w+9Dc>TQ)ZaK>p_15kD zQ9uG^mj`bzn3nfwxhQlP+sJRgNrOYz6+NWOqkA^OO03nMFFn{Wk_!m8H_t8pOtt<1 z_u}~a@*WQW692K+8fO05gm4+{_&Ohe6#rWv2AaGe4H+=%W?aQ6bj9KNvUFVkYVmSM z?iSOB*38P-&JM4Iw4&|X5Ln5=d^5ys<1K}L+&$B00N?4Z{@Eq}Y?MjD6%upD2)bOIUqO>kXIV61P+?s>D{FS(MuCYi z?p&h*xmvh(xCX2p>yco=(b#sMxa^+zV)1$Sq0jh#paRg@(9b!yTNt+dhyVA~_222A zZvd4g>{|u8-}ldPM5Mhc7<&4e^y>owoQ#+C_GoME|Bkl8|IHv|H|sd~rHk6v4s5eN zsQ;H9su~Ec;d(JqnGqa*;G6&O*BY>J{)}PpspK6`GD6}5((uX=XJXvTs)Rf@MKn(W z2W*llv}RC@^bqE)eWId11b1xXK;4;WY-j}mf@2x6+~0XR0cti@yGWD#UwVP!sP9-) zR-$EHU`?}ey9{PHNjpi6>U{K$wT_a{X+A_z=3rUKngd5$uFq%TBwYUbV_nTaNrwiJ zb*mL*TE&cAVi3wRuVCtvDMa#cqDy}v?(f}zMlNvuy8nwo>qS6CQL2lNwhuo&do={vK z3&4I38COU1F_?9Qm;*JL8Q5*Eed^`yE(qP&^QW$sy+SwMY60de2S=(UiLte{Ew3dDiQ%V$4nvRO3R~-Cpz}0EFgl z>>@-o(F&@0$A3wE>$Moq&*!)4dc6bTZYf*ntnZ-Tta;_`K|%9iU=5@F)AVZHu&Rk3OSa?=~so}Fy=-2&Wcbd;&#^%cuq%U4Rd810Xs^3Kd|KUSi z74cMpaQ>NZm7z675S5bGmiNx7D%IxKK1USMo|4>ueC)tlP8^hSwnvJA{^*)WuyT^I zZuQv}%T0YlY0q|dZo|y%?*39Bf@~q(txG-5Vt13Vy$LYpmM)Tf@OwpU9*%}==S(Dd z$dZYdlGrz84uw374FYgjOVhr6LX+97cf$==lP{Ri!#f@mS2c|!x}3*E@KKdT9r)Tb zZZhX(mGDs+7Ops0wCB~VGWq1fj#R&N(MRQ}4Rg&2M%J1nxiDuPXYKh%g-GVC{LKOV zMA=&lLc_x=;}%LvWlPX;s`Z%!(z*_|TfvuaEXv4GdFN(?Z>+ZarHa;3Ga&~ra|k;% zbR)8d?@BtF5Yca`rgSA9E3s%-5qR-yGC9V;qu=Hmd0P&KfhDLG#E#$v5owUc*a-EO z#}C>@B;;n9HyQd0%<=b_Jj_YX&Gn64_|TLW4-#JLi_&zKDuygd2&CC)?Yg^Ja~4sb z0hXFx2BGD`heR%ODdE#}VCgEk*mVOE)(NWis_sH3^SUo!%RM|!qk7=wzWG@k6K9&c z&6!jxO9DwpTx9{JJZQfLj~{InL%I{%&CKb_aQBiKj7d$q=kU6_EC2#z*G((!uzuz8 zyGUV$WHB+AysR9)NycAg)Z?i6(W`4#zUyIGciohe0>UNZyp=_z&APCk*u8|I76N7A zcS2jOpw9;n)p&|`1zmWNb7P_Vq-qYzCOunnL6Y6t(u2anqsGgl9ohENRwg7zbu0>Zz} z)kGPYEtlEImn>g9&e-=v4_0RsUvDm{5M(;95cAak(RkCKq4NBDL0yf)Ug^~ym1D;$ z!Q#_5t=_LuEp|`>W7$QLBUE~u83Sr(L4p#m()Cipk?3J0Lh0=aG2G1%>y5iJd$2KW zq;P$|c2@TEuvQSyoy|Tk5{HrZ%cl73m;K%apBT&$rCQEjWNiBJ^K>Nr4P)lHucyJR zN32r2=Ud^HLrLmlv(eFbvhWj{kdorDvPr^O(F?aQp$&_qu)D~e{^jk=o{j|>(=g*9 z-`J&Um&ej!RfVu;VVV^&3Prbw5JbS8nK|EH&+_`EZSBF@aIsOT1G0I2VPz(>)dwl} zigo(Vs#fR8$E6q-y*6sHb#^RkRM%~(%?>J9Pi%9%bV zEh6h8_4B4Cne8?dHn`nL_U$hU0#`%h7y8J$ScP4<*X|_#tD6G&7TV-pZ5}0Dwtu5$ zh~3XWx}q^?zh?=->t^X~1>VVZ&UT%IUIapNRZ4jRJ6LvWgj4p`whREaPdDvC@3W!? zHo>19ZZz>WL1*1ZT<10#JT%(7JTPls03A)eP4F(deVy@$w~ez7NKc2`AgLUmf+hio z>r36y@f453WR&*@FZuJkdFUzbaZBRNdP3pp{N}dC)ScI(?=g6%FIw7{h~8aO z>HdOSRp=LJAF>w?^)qkWcsvrn#{muNte=^qK)s;Sf5m@Bdun81mG^N@8PYt_x$ zD|QmFq9ZTb>4)@X$|AhfjGXy>8ep`nZ{j_lE<9Y5%AFZdTen2yLM2`t$i77=&-}LJ z-bXt1Qu)3Q#ecv3{0L_cBJ5qSwY@lHQ8iZUaTs9TjWEA7Wq-SPhDQ9!-kls-dFppAj zF2wQ{Hg)|D5ioZ{H;%y>pPeqF$@tcKni8Xldbd1mdAktllt-;JVm2%glbqf-<*3-z zEqb*^+H9fk!w-gBM>d(!g65e>#jhn=NsGDPOPD&f=avDsG=g*WM)Q=8ZimcQ zh8tOf`l{>`*iW(0Yc!ZcTIM+e5!PDQif85nJqPEK&KplHW?+Hip7v@ht$joP zvqPS%mABsBAM+iQaok};7!^D*`+4_*I~&-rwF9}KAL4~IHEqlpGQo6;HCIYEib9&o zeRLOiK)+D3xjP%ppE6~W$Iafh?8vEFpPX5?t6W|eMx4IKH|%j!;W4cQM-Uf!!jkip z^Hvq=u6Z06EQyiO(_g~%id_gPLv+Y%N(f1ZBx;`ssg2-G!aL?(eNSmdNR~)lfECVH zR$?kR$ky6jVqQ*Tkit*Zyj=D1axEKqpL5&_<7cP~_`#7+Bzk+!s zoaWP?Fi1*Sf3!AazN+9uE;Gb$PT5vXt`Qf8?u-SRD~?IvoMG5B@y+Lm*Ruu&!z(DjOp%J$d=gFBhirZ@8*T0+IaIbfD7;^^bR2|Ia^ zF+O!3QWY=XcxM2AIa5|>POdCT|x@B9{g^UB=E%i#cgDJFeCZd$;(wrITJCsgQ z8TPl=9VRcE#g8@`-#e$CZ98bF4GZ1oOQfGOv%`12=;7rn^#8PTn`}EDYITxjtp+SG zWMVM>Wq+9SJZSpi2424RYH_hkEq2YqLKD0B=`x`k2pfyF3+deXte*BrAsyY>88jUQ z92PM}Q&cYbc!_LCeg`F_e9I(iK!5`rdtQof4fQ;Bt=nJ_{|>rwMjdO6P1pf~oPH2{ zr^T~(YCrT#mO@H_HGe1zi^(r5o?q4jhi;P%$@c(H19(NNI1-q{lafw02?MaWC4kND znf0E9l4jW5B8co(6>xpu@_96PuV%9Rjm*G{)$3GUN7s%Xng3sDG)p=$pV+YrM^DAr z2!wqHDJqDE8t>NI0XNw8)$Q#EQQRM_8lArarp^=9heXhO1p-8e+)I|TA+#Zd{`Ybe z_>Ua_pO<4F1T8s{@=485!N^j+lGV1Sy0_GQ3^?!E^C8O=YBrg(#9HpkBl6e>4tnwa z*fkJfDVKNs!xQ#fjHnyS6wzRG7Kg%UoW;U zoMa|Y78KM8Hy0#4{n%vG26~LtOp{mlYa=*+SFV@=Q=v6nCBS1uzFrI+MW zg=VhPv1>gsFQYcvCPMn~_b#?|q0CHXE9;;tP^-o23#H!8=$_$6w>mJDrz$(rc@%<= z^it+d6$3|iOi9>*I>gc)gxTus%+W1TMhBY7sw$Lz#+y>U)46v`#W~B@mhg4jjnzUe zcJ3sd1{iA$%-=EflLHc6#04&x>hr1NVM&F#&zjyd6nm+afH)m8U-RMZaJ^XZ#l@W= z<-zyYrg;OEElpe#)8m5E#m=+HL`U_XXem~37xVVech?txV>1OAQj@l|ydvgRvWb>} z(1@)K^XH*)3WB>PcL7BD0bmOrIiF&wj9Cj!?}xW^Kx!U4*<8s{=-xEgNt<2DEn-yO zpo*UuJx0BQ%?=V*lprUcfvm6jwmL>&2Fwg?B#PgqHLS{u}X4>S@+vtver&9txIY@85h?RSHh_6pCl zOAjT5HkEQ`)r6KmdB)zYvVZt!*6hdqE(9tE5T~g5VRn;PN{0Cc^01?f=hLMl-d#P$ zuq^lT-AT)P^529y7TkjKg-W-g%Ly{G<)2c6?cB9qIPxSL!M3=>r8kw^$wKv2AEN9O z@)r>9M)mg^Eqau@90h&exidvrdM9``@^d68?~oGPyH$k>MFui5asQ9e>ZMb zH@7R2^DLgM+@Dy2Ezrs8AS-Z<-AvBv(c%fdHhhQ~Tj+Nnyg_v>Z;BQxiMXV z_Tq3!E!7QJ)~LN_u!BbywE9s$PX=>~K}&TyFte|Vm~#)BOf}ga_VJDOeCrwYrYaQr z#Gkp^;F~;(J9>CJE+EKjMzZl9DoghMXJ(5_GCGA%i`*WnaWPwyRpO?&bJi9%zM(Ka z1LAPTDjsMA-6>F{zJT$_D}I}R}fO(r!wQBKHbY|E zpjVea++;LpJ2ffY)$E)b-fM2JN$E%L@xU+j~APaZjh=V&W+Z5La{5zUn?6N4~X-o6?ypBow>U z+Ab8lh*HirBI{s%O^XH?+1Q9OW?#PaR8V$Ui> z!xNpa`^6&%b)uj0k=7Y=Jl|aI^&Y5sH2{0WKBf{{ZCBK^KeYhLxp~dpx$;`Nc|!Cy ziqqcU-2(L-5eUOt+OwVwb+V27dc|J<>$ zqx_1aBegz@aBWUGW;}&Q5iEfzI<;25=!lA`3Pm|Pdc~PyLa=zSjob3Y%XWv~j0X=I z!;3*NeP7tE?G8;yJx6f2tq{w&j6L|z3El` zCF&sxn)eWQ*;+>w+SzM5;JmGv+$d2YljtvB7`eYp&iMFZbbGpSLWEa-UQLu4r9ga? zp+N-G?s$~5g?lPTVd=T!TEc+D^8pzAK}CsH;hCjJ{xr>#?DlTg*O@DDxzix1G``5F zQcR$BYph*{C3R#I|ERaJYni!+dS=oouZLpxtIaK zTfy;d)IGsUgP*yR9OA)6;YpKQ>t2{XQ)dnX@EyQ>hrWc}*|`76;Ovf=N}V*#y=&j7ks+Y#$+ z&$^w+zY$F;1^(tV28`(5qW}n!4PaJv2F@r){z_#bi2c(?Ig)f7I3zBCUIc75s~Uf! zdcGm_)780G2I9XGxg>x1&As{`!Tl-j|9=EGwkEzM6t?&sG*D%2nqst^&X+bl76yUm zj%*N{=r4T;J;31h$uYlp3o^rb8Q3Gw?C#V_183FR?*k`e{)|k_S2u^7-Z|`h--F7w zgMNAo!yRb*>k{8`WXpd2*(CUn8&=1#lnYgV3lJr2a{iR^W-7TZnqZDQZC38D?T$(eg57tjc5usTd5sf_W&Pv?ChS8BKpw_P}z$ z)5~uSR}&xe`4v(WE+;;EDz&uY@?|%o#;CQ9{EaYy^T=odJH1~#&hl(LQv+EcSMo*y zRn&@|#H^oVFju(pG4As<3lftK>$k-KJno_{_aw)=j^?>&S=d9B;15vWjwV=GQxHhx zOi_lG*+&n@QIDvjg_ztppZTGxmjlHPg*eK(B0+>T>~=cBYHobu=)PC#NU_9G_nB&; zh|sU)F{e4$b)UF3*(EB-XuE+S_hl4&Tp$yW1nJR*#6i~J7!?t6YfVkJq}mk1{#mKO1*V!0Z)BlBA4eG72uY|7-BQqXG!UO3s`y{*y$4iN zTemO@qM}k%6i~VXqEsmXq(wv#L_p~+AcoLF0!ULZL`6WQ2}qGD(jg(#(4;CLy@Z6` zkzNET5=eYozjMx~=YHS0_xP3w5&{CIohn&sJNZZ)@nSn=Ij-WXAtPm=j$nlqS(#rJFtn13i)I@8Yo(f=h-r=bOl#bn_J z2elv`AA&gH*sxpe$%z{?c95#*Fx|Jq4~_a<9SSXG5l;@zva64ikhAlM$dL<&HiVyM z=w`{XXbO<70So$fKh^&|#eo%$jZ2^I%WGTo(^aTOgvbq2O(4sZRp!!J=l4_42_|N)0E$!G~IBNh;P9TJpL~ zBW7WlOQ?W5$!||_d0l!OvZEkR)iWdMTD)!5ef#KiKV>3D@j$m$V%XpXI!;g|JRt|l_C78GW)Y;p5 znmWdN1Tyv;&8vRiT?SpMs>Dv_ra6#ZEFZkZmb~|bs3~~K>WeNQ{p;UBFNuM7_SeiL z6P@=mY61PW8G4<;P~g=kbUQd_Y)AVspb9Mpj_ZIfF%E55vmQ?eg!?!Ek#k}O5&D3h zREC<1{v=CJttS8`Y%Qt-#R$kpO$zuXncLNsJ} znQf6q&17O6qwR=eIVSgGVCLN}+U}Ahc{#QS4f{xzF6`#85@wjK`^C1QGfs_Sg2z%u~nRoCf4MfS~^;pb_bN_1E*gq;q?e* zwC|~&##DHpKK*r|#2sA-?F%;#II}B>a^6^hy>@BkYS+q5#EC1~vZ>3;-CQtb!ZBoY zCq@P|f>joH1HA^Fkk^#m+oRbs)i`#xs;A+hMB1{JYO_i;Em&J4Tb zw+eG53k!3rw`Iq)hZa!fUa}l;mOhiw=?8=5BN`*miHU?Ik0>cJ#NRMVp$l+0jhkHL zh3F|uxEz&KU>D4^!Yy5P;|<)rRTVW!G0Bu_sytIE+*t46Jb>L0b(I^q^<;%FLq6Hi z;{2&G!-bZLH3tvYDQkKo`};Yhendg=%P%~Atd7aKTUMUZ>kY(k9hXh;|<|Akv?U&p}{W&6<>g!|$N8 zOWq~;ZD*urR0_uSR?c zzEukaep_BC4)8QB@rst=EyQO-gaPHsGWA^v{Xv`FaO`(PeYIdLEyhIQkz z;H-rE#fu}W>eSLVmp9LI!n?u>u?OYU$hk;R`DtF`wS3gRRik&oH(ks)XVw{)Vwu27bIqU1HqYc}7`7M6AgQo9ty;Y%0;mV);Fshg9}?e;cHsuA?XoW(|RC z8pke*G}>xos~1E(T;&E4#T8EbpZPpv<`rsIhGs)ii6iop1FCszu&rKr;h-oC1M>|p zAL25Bb;30WSMGyw1C$(Ym74yZQ(%MF>e{cZjIuwJvSr$E!ChUM!m#fuN(~l86y`an zy`CQdY{mMx`CjJ0pqd;>l0G^8Vr`@MQ!~$9T_pMK%;Y8yW;i&;+B9IsdMqgHT4&k- zbhUq$w`%~((LMi2kkau46sf=iL#f6fk7ikZvEYWM6D?6gsa8hoGKpvSOTM14iWzzv zmpA{7#;~=yfs8YGo&Bc`Qmtm8lW2AU)%4c7{}cn>___Wl zw8-pqw%KM?r-L{&_e=*T1h29G(W--I=(N|`Q?A{6^Yzuk!Yag9jVE+eW{P|OYiniF z5^GUL_Z0kXLH567s~XOOxpX zwn_IOzEHQ>2zOLkD8+-r>BGlduw)pU;+ft+bLi`Qr(NZ(k`NA1s!LddUK=@Yi!t)C zKg1bTdL&3zZbSC2)8NQeP~XD!RiCgIAe{CqS#l*WAVlE)5F!-6Z<9GKxkYJr=tn18 z0tXzW#`}~)L@1=F#PCg9!ZWL|Aaiejl5G%9u(I8l(NCY-Hm~1e#>eNreLBEOy-XVy zyf)%b4O(fL4TVZC*~kgz6(h=*11cK1xhre!pVX89LdLIB2ryGJ)SPcL-$ju3`hW;x zF)BwyrWmQ1i#0Xlha4GOU3?E{x7;rXlfXy?a@v5JHdDtO$U6LJx(wT}T)Rv;XPv6$ zf|B<(22E8Tn4*T&bO;Tem-qUQvCKPQeM=~L=mFpK8ZJmsmt^7aUf?9b&?L5wq>^tj zD>GCO?^*oPVnVr6B$L5$J%uFc_@Tl8w}vXhEJ8K_)P*!zM+&5pFV(;B(NT({%}x^kRK zt?Eb%zw0b-e&X#e3c6tMUrzi_qNf2hdjpe{u!l1~Ia$~q*YD^NZPG(om1uH-`3;|0 z#o~E86WOmksfZEzlZ+bkD>5C^A`)=Fip#%<$_H{HZruA-Tt56KQJF1A^8(;0@-GPW zCwR@W1v3A0P{Qv{-krEL?4$s1Y|8W02mDk91RFWJXd+;&KdDxL6T&~D1r@15zTny{ zqfB(SbJJJWBi(Zux}TCs3{U?^RTDK*^NX4FHYe}fc$8#aqFd&>&%-wk@7x_MP23C! ztg)5mg}%OncvMh->cM@2e;Wx%%%#ZFA?r>a0W&JTn7f#~3yMaG@1s)TiVZCDu zee)2ws9qWGZ3W7M zI_(?X5T1<@%a}7A&lqCn?<=crn@7yf_V0O1Eq-`cDxSK6I1q2&S=G?wmRw5oOuJ8e z$Wix^(2_P{(qZ{I4a-g1Y(aG(1=Y=pB2a(V49lUHS3?+CJKT+CAdj~g)U|S|rz(~n zzdRREl9X9`ku!I6s#tQ>wKux#ak^;q=2-Ejl1j*)T_P#ms;;<%B4f7fTd;pHU1 zB{`BXLQdbk_LSCRR@XLSYRxpd?M8erazSpRQ*Q*>=l)#w->x)ZV|L@2Cg6{#ZNC`Ul}(Orlx z<3(4hukk;5&bk%8b*_YL-g_qDh55_jyQ>7{&;qPqu8CRS>8Y3l?NfI>oOPF9v(12I z-zC@<TyRB8+WjS6-1N0|2ks#e)Szok+0NS zPZSKxAVtEYn39PEglc7N`NT8q>MQ9ImlPYgP3E3Zm$XJOv%N<%@un-g$X2Eup1<} znXb!6)P9qedBdi-ab~&O>63ZHN|e8)mKz5NpXqV@dd^ZvC^Qg1Y%96qmDOECpzZ!h z^Y$7_9?fbzt@SQqx={T#`~bKF9S7J3R^(l$KI@z6F8qqQH&Kz!99#HPlZ)IfxbCVz{t3xIsWn|H`Ie|{nwF@0Ymp0 z%h^jYHlK!`^hH9n)0Zk9F(ti*zt0&R8&!Ier>}3`lidnztxTcNtk!w|ot0deZ=};E zlQZhmq?dfJdcJ!6OHQkpDMCBMw+{%lGO5rPd0V@J6SVyV&J&(oO<9+`#atPL8z+BHJLUuR=twCsS%yU zckgO{(y}klzOM z*&)u5m*iLrI?8rosyQlef5fsPX7sHn3}v^!+b3_4CIRwl04n&EIMonM>NEQ223D?9 zlS}siG6sm__yr7{Ms}4kS;UCOZVey7-gvYItxd_4K{45=+S^Rq!F-dFT+)Yz)Y?Mx zQ_pNmE@Njf7V#qR1defT4-bWc)W<5zir52f#_+5~(`!4*y4=yzMq5zA(?!?Ou^Z95 zdAr9d&TyM+c#Y|RB&xSx zEMVA`XCLkJH0di}rmZD;0@1VG0`xvwkA^|h4=-KmY?U`L{`A7BStkG8Z7r>(2V9^K zu88oi^J0Fzu5SI?Q!&(#AyHV#fOg15?v=cmf=N}vRUgs3oDoCp6W^PsR4U&Yup3!^sAX=C$Y&fV_p$mtwgYY!#sh$SuQq?sWPcR$3I z@ALkoH++{G(YhOuk1Ac4yE#bj#MIzx-b8j&bFRj!y1e}5I|BPAY2D?TR7GMw)-SYw zxFiDx?Ub6vo5vwa?enC#FC(ti;}=K>cU_M3aJPy;^ABwZ(fYx>(J=?i&o zIfL&@UGKOhj1)9K&9)l)s;s9K(3rbO)6}}FZe)j92prl&qk&5&ZT0bp)0m-@lbnD^QB>0A3v_yq1(ki9z3ZGfy_x7fV>EAjQ8B^h=GV# z5@kW9ikt}00K6TOxCHZ%>~wWHJ*dd)%tO9sk2@O}bfF|=v+5mNnZ}uWQP54so066~ z(w~JhK@BnPYqqeG(w_c4NnB$LJ+FgGeEIUnl3tM(XCj89e>fPDo|G#&;4_vF>KZx- z3TZ}8v6xt>k}p5Mu~D-^z2;76}W*lB}O@oRPXP1IG4+G{fnA0AjX9c{D&?7-~JFjwqd?T zJ#eMuckw9fniN`;nr|WWd(ND^<-H2JknKqS7hJR3bo`!ltg#Ul!depF8W6Mefb3HNsG}^#$wygf}lhEAKt(so=*<& zvx{r+^!M3efOHlE-)QC*b`!rRMx?sg0a^QVSG=g&HUjZ0o!db|BQEH8=9-_zW%VT< zOyRb2t67Ji5vUrVt{MM-_ev180M<|Elo9wy?U9>>`b=WGLgmY={;wh|m%h>5&s`}4 zw+CANG$@HbPzieZ_d9>%=l?|7D4s7jf=w8Q-=SR{Ia9pT~)j|IFx8Hta=4X|Z(<*J8&!xf|dc@05;=xw*v~ zERgGFb$Qu4jI+wUWXn@)!t_xF?e1@7BGhpJxydt#6QurvOa z+X%30em}+McvvWYaS>~1Dk(O%9l=)xke<1?MuRpZ-%vgw1fEqLQRRCg!+&cX{Y4Gf z20vv;Q0q*;(Ntxl+nE8Iadd3W?g2aMR$hTXrz3C0Y2VG{y@?0lofJTau})wIf+zsi zIoew@6A0KuTW?xXo&ejLkFiOFWiQxWWEE(sgB=hA;<%l^(TGW+w~lmDmbIw%9yNQ# zfKyq&2za~1ySYV>L{;)*yc1uV!*O(}RF zvJjdO-3=JMthk8K_kr{#C%wIL{XDOIjXgP85kSV^6BxX;*$f6pXHn_f{U++`99^q! zH!J8ov<3rL{F&`84ZM8CfmA8&fvp}B z@EY>r#B3@xQu0dgLZOCpvP(Xp+sb`XrL9tq#U%Q98oPp_XVW@Cg8_T|lugvEN>Wko zpQu3MPb5V|Qfrd8eB+i}uVZ`9=k&1$vXuboHg5BQ#+Ua^jlDMzPwoTE1y_y3U-VhW zBO2L2C3+A9?fL@c=4{nayY1=uLkGQ%2_)O{R)Dpr$c0@J`b!{%0#x|)(oZIPIzN?d?v7jj?BN~h^qnw3He*UuBAWs8GX*q0tc2m@-9K5SfMqq z^i1!-e6l)5Jpi8)F4oiODk1q*1Vp*BaES>g8Ipm~?%y zPy1ypRb}0h0nvP;2`QZn`_ZpAFxU}bQU4W1B}ter8jY6dG5`3RocMr zNdBz_V8oO!CDcanU$PS{GBvT6GX^H_IXP9t@;K6`aBz~Rk3A%1xghDKbB32v;8hAY zC?#ssFQ*$)9=t0(=h~dh%L}Kd4+Qs>skEXr+#vIbbo(`kv@hs4u3OcCA9PY(wtx%- ze>K*c=e^{nWwt3;<>^gSN`Kx)t`C=P%2viZcC*j?bKwUcgx8N~4F)8IXBDFs!8`T; zIZv$0@|`mt1z28!gwS92y~y%o!TtBQdrZ26um0UknemHLQ$DRhGB)Z2Em;NgYL3!7XOIGnQ!&`^{Qj#i72Q^%tmH78 z81HrSmrL-|`gy4vH}RS5jLs#J6ZPxnyjLG*&s;yWd#hq%-kyu(UE`Aa*ZiKBKW{Vm zp`9IgsWDJdJZGM@=DvLWtZdUD;>jVvznjOF}s+&s!E*) z9vPxsFRHo-oW=dAfa0yLD9hA%P->nHM7(YIrUEFJRl5;n1@+(=m%Dyxp#=e2!FFVmDxJ=h{_;Rs zvT=pWd>*22pz!7HBcEq*F3TB%d&08Eivs#@I?Ac%4*8ot8x&eT!bNiPcsbwj6$Jiu zqt*Kps`WA#ubb2eXA)lYjbEJV3%|n%)mlGozAe=j94G4J{Rout1aiE&=i{QXX<5{# z>fy7)TcG||%RW|`KtT1u&K^Y)Tv_#9sSR&v5U@Rjw(NGGzxaPQy#B?Wgzw1g%WLt{ z$!k-ezP;!@pdQa{9%AViUl@L$U+YbK;BA!~`0EA>-0BHF@7Lx&*y_;W10_33I`Rpg zGv*5*taCMus5HGnz7YGaqR+zdUZ zFCO&_eBW@S)yg(Ou1-+SZ0nuY&9GyMhVx@>id0D;`}{RC&HvT-M5hfhyaqF_Z$APl zb1ztq5X}2fe4O8~yC%guxPNacLNF~h)m5xJt+Fff3!n%8ll~|^LNe+(?V0|dxtAKf zEJywHIWx)ZoJ-ZiK|tavr+zxMXW{`pEgvfOM~-9DA~b#o%Kt%f{>vY%Q73JB$WkJR z-hKwBoW?*Oe_?s1sKt$Y@`${qr@&G?cu!U$3839d~V5L(n)yI_^H2Y0-aXr4uI$1^zjG_+C zX>-hZXJunKT!I0M?#QOyoATa{gW%N5E;!z9TsO0;^;nS&l9T3u1zNY(*WAr2M89wm z*=Q3jGe|nU71%fqQn-;HapOvxlB_fV#)>b8;}6O(wGE!SdkNXiyPwS+8D^g4abLd8 z^W0Rhxjt>yyA`iYrmYpF`m%@{j*uR2BUNnQ1a#2e2b)%%Az#>3>66s#T+-nQWN@@9 zQgEnVihO>3P|AFM%qydPOIo#L<+%&t2_`K9C_>8x?%jA@M!)QUVaQQvpkLhlf#U+NdK>1sg_wgR*De;U%~kFU=41y$H^SV^ zx|oyB}n|?Fm6S*49Vq^5E!VK;j|(TjdPDvtnj+#g)9ZICa*)VsO#3)ysJJ~TY7J` zbgY@Iu>tK4(K_FVeMK-Cf*2NqLU@?qclKY6(6husZUN^rzA(7u88H&&N9cW=qF%@3Gp3W5>|3h+Y5R!>185$?+K???nF zXVzfThhj(fBck)%f}tPXE*16S)yp9AUh^dki{0K3Nbo1tqEp zJHVW;`)JQr`U`t)cO2gCu>2Z2u+r%@T~~fIWALxuzgrLv7uA zSuQ2-f{+zi$h;(G^h;}U@nIDh_rJ2w1FQ2@cSqphsb#bMj|cQTWGE>iOx#iL2&Z`m z7$maI!_7sDxU_?v!X#Lpu{m6wn-306RP*;VX&IeL)p`@o{`p_P7P&*88@SU2T%D_nA=iC5Qm?ekgi6YOSmG)MM3)I}}b z*iUz%(~uB2GQ9!kj9%5*OFO>Ht12}m^r}|%fbB+7d00Yi>!Dn}d+*<@a>aMFL3L+)@N^Oi8ksi^LJIbPfOW@=&_vq>K?Zb=xW`5IBa{-NT`(#1m{r4Uv8 zNARFiII1ah9Uga!5~3Gt(Cp;Vj!1 ztdGy9`JaojziOiTve?_sqNT2w!D7)KtogK=2N8ASin;11kin+%U6N@~Fu8f)0o&nY zcLe}(E{-ALRISCA_t%9NC6NoP6NX_M7g8RtE*+-RtwY{%Z+m!dSAFql&x214JrQ}~ zA-1v%!o_NzI{4qaic^IrHP2=LFGf0a{Ar!JqJ*ec^EF?MdB4#h5RkVlBY=78~xqw$zr@zi}Ql;TJ^?A)bDa{K<`wPI`aw}R(CdqU0+x!9% zFDXGMC?|ZUtN(Z4aY!yh3dB86G+;!2;n`q&&@sB*3O!%nCYxuNfterk~- z1C#;#QBcFvrzv^Zn3cfj(UJ5}^863epq596EIzK5Ss_N=fyeUv$Ayd?pUaVa505yT z)$rEl6wx$Bn5k?R^E;hqGKeJMnm%9fCVr(JIBKnBt^Oq9$F;=wH&d1_I9<4q%vQF@NDBnm?|q9QV-s0`t@J(^WN!SLHQdi|8-gkI(0vC z{laz_xa>`MNev75j3KgwXf{&IG4_VW@#vbipmybwy=@UD^w83Ek6XipR!e9ICt%3b zb?EjhuB4I!qRb-oW~!FxT+WQ|KKjgGpdu3TPdCQ?+k0PBzDo|jm*5+h;cwOs<`l`r z+)?Q}c=7HnhUbrj*lJ6c7r2E#jzw7%f8=|;J8|buu_9*U^90}I6p(PZ3(kJS)fLFv zE_fyqg*Bnrn4(HT#9`+^8qql`|U+OcrfJcXa zG;;&_$FD#&bt_6s?%wBY%J&YeY?>&wQ5VYp`g?FO^VvR^$cq#N*@+6?ez zi9#rK{Bna)<|cE}c+YT7Ff#c**D_^J`IYaOAHc?iztJeyjHdtKj-ltkEBh~}3w~&6 zEIJdMH>3Pvj#PHyD{IT|5yJ~W5t7%8V)h3gSY-b0BlcE-a&iC&kd3bJ`iILGoLx`D zqDi;0xiaUjsT#wO&N&f`%Q!u>Ds@fd?S>oJ^#U?2;snbv3RmZ_R(BiagN**!D-O3e zq`|HdMKivWW)~i4U#RYUO%0J7_=4_Ex4xNv;r6bIGg+p(GoBhEas+naM%a%hTMx%J z98B~t+%WL{{sj0M@btM+|N4er>W@dLWH}0l(a9FQDBd5Bw3c>i=6doo^j>9AzCW_E zYyU>09_26fD*gJ8M?ZSOTzHi(4F2&b=KnVUIBZu^MS)Bel0ODYzz5e=Zn%jJb;d*X zScEPAM$mu2K%{Qf*qR+R`^7&fA+gw&X)N_Ma`fTg>Ug-``kyH%ic=JZka!RfdgC8N z^|GP;39S8r%i!hxpw!5Y^s@$?C&NnQ*;!`FQ*Ha1Uixec-b4R>T&g^Bp&7B8{4Re$ z%;DKS<_zXEpwi86SzrjsGdw5L!%j0?v0lf&JhK%2BnxZ!{`idnxxLG*CI{Zv#h|j=+#M zZtnMB)(9rx%K5G%lk`Qti+sR^l9Gfz5MlPf1ty`1u(pFq+=LfSu?kXz3L389=|F;zyW>o+t7>&&%8X6kf zZ$mUsX&4V3I&}CD*q@|@nihumkGBGePF*6-wW}$M=fgYH5xiqBYnzOhz_zuwi_ya)w z{zpecyKn!2gY<_EA7P;V^FvyieRRJ+JVryipO$Xl{(T4N4<0%|$0!XvJWjX&42$Fe z)!Wu5&bmI9I(RZXrQiy`0IOczU1^znPrB9U1tau7Ppm=RKx}Ud{mxyDG_bi=pXx5l z-eWikTQ7S0p5QU{MP2AsntyTBhu-Op^pXbRr%fYU&w%I*d?RUQOYXX{omXH?W@%I3 z?Dlb*eft1t_y2&2{@?-74-n2svg`*Sa6NnCfYjsgliwkz)9d~$EpT_@-jfJ5eO9QO z%$nfA?*P!B1J(BcK%}zUTr-q)hfV$g!oP<==${~b8>C^R`_bod8ZgZ~x;ds|Z!c%; zrMJJIU|B;4Yw0bxaNA*vBT$XY<8S86~bC5*eXJ1OMeb;*1Yh=^S3 z3|Q)gT6H&})!auM8L<`7p7ywmrSE9W(-UHkN0?AmC%(~$z`xM|2mS~xXCMV!3lJ4M zkDd-+J=e2EMqqnwj_A}L9Cu*Xe7si@M@_v3u}&0jTrM2+F98=l7eA1s&dJ}vr@D%J zQ3G}U>HCNwAUPerhHSMXsC6P|(ws1m_=@~_5fyEuY|gR2V8yP-bJVlNN1;h8SLu!^ z%BhUFxNlZQ_HdV`mjImSu*vGz+#TP>nbGIpXrh2{TK9E%aRbCXNwoO8r#A%ZQR#(4IN}Rboa10Y7A9V z?C0?sN_%H8gH9iXl|WFe{eUPC#Q84nvAC0?dx(3tNmE7qRsqfq14o3V$+LrSEQh)3 zjlkhl$g9qOJx)suzD8R5^fGJdA){F{ND7-wh0c?+O1E6StJ#c<3=IbK*VaT}xE4f+ zoAT~7iwvjd*A(aus~rAcLwDtLmHbq2c$8|BKrv)N&YF)!eLjRnxZ2os-lVwu<=%@C z9qlJM7-+w_@<^pS!r5(rllSAczSqA7EN_dl#>A zbI}Z+8C-wTksW4>GTQz0Xq0s_H-;LvW{)52PqLvv|JA9pgLF z8~HCsDj-~>fa(RG!^Al?LD7JSflYc)8{BT!E@pd8y3^!FVEPb`fn0;$jdLsb zF`?~Q4?LHeLrmYwy#EFro#QHsOEVbha}U#uIJhfP5)#=|-o*mYy#v-$(mARG8I{;{n z^uW}C%H3By9bvcaE7Qp4Z88Ip;Qe3sebwHo!J+3q*BqrRUOhc9P<4`PtDs!Fc>{~M z%fW4AoSIe+lyjbpSs&3*BXcIrNT)McjBwBQAznUsVk&&Q2fZHkjb^LidntFdBQvtw z1P>Cl7g>VCzwFrxyFK_AYB~B~>vM5{oDsVUCjPX#pf;OnZ!9gAs5n>g$V)qnLQwQs z;q>ael%e_NJjZZpddt+au#@Qv&t9%62gK)NDfA>pw2r5;-*D5xA?+vNOa4PTNjLhI zIfb@#2YDqIP@(&3$l6cqS<9&+`L-yZ z+CTJ-#vQ0(;poz$BdsjT@!4G5fbnyKZ6=QdcWAPoYkz6Y!YA>Rbdo~cWu^m-%(crL zho@@AWy#d?DUZF-RD!q1km!qHZgafFU}Iy|vH(xd=pl~#on8d*65?Ix-Pb6=lM^lYl~kHuTdX4uF)hb#nUIqF{T$>s4d3fFzgB z^7GBHzNNL#X&d}iz6VFe!*Y2|E@syiv{$rBRuc`U*q1)dl8Sl}SfmChy3B1DwLm>e z9IlS(&Bq{>%jJ{r?g~C-yF^s%-BjKUvB7iiV3+IX(QuEWdpNJ1O+eDSTJ!Ub#}as~ zX40>(>Fe0i{necq(&;c50^MD@6nvsn+by^>c9<^n^Yu=0B~kh2uy6qcDqUz_oiG#a zlwCr;*T+=18$ZA6i3d$PR^SFl)BwqHgo;9wZ%h1qLwmO-EN1!0%9j!pq?4OJ4_e71 zb#JA`S3Y{T;jM^b2I$LGa#0sK>?SI<98@uggi9dJ@vEB*YEBs+`-XT3$2mOB$4V*! zsm7IiWMIa4!a|VB zx5_OUXthO@&fd}sm%R7GZEA*|6)zXL!=MbF3d;ERSYcddFaeEevu`9?`9L!oNdp2=n{)vmPJ76n;&I~5=NZ^PJ$Ns`dLE1kAp7DMN|zFcw5l|plUVw6>Cmn1a#MT7R3+uW z>bmkKsQuX40w`0U9$1E(4ZKHOh{YG3i))C!`>7auuy*K~IrOp=`r@Enb%J>ARw)o$ z(z1l>H z_<%3fukZAhmdk~Wb>aDFsIy=y0?+Xsq&;wJQ#)@#~{;H!TqeEPa3l$8OPUUrk3N^1s4_}C(Bow8F@|qCs3-=#jJ}#VU zgRu^<=@*2i<4sX!GHsWrO7@jnUkdLzpiXm3kTUAtn%}G&qY6phs*WC!R z>1b)!W_jrU?2*T=*Bbp6KV`K(K@^;O+I`mjou4)?8xI?aa0bPYcHet`#DFRm6|d5b zRm?Xs9@m&+z_mBPC0h@iJIh#)X@Q`Kq_~*Z93b!u&-_}-6 z4A7Sr0GZq}G6guEtpG}t8p?UV?)TGObk2XFzic!xw(1WLPx$`CO`rdA|~+}{BG zXVd>ThW`JGA^U#PZKAd(cW_~aTH=R&yQ&J9fRRls4vIx`<{Wj-IW1-5TFYn-XA;S_H46AZf-(0z#uiJeA&h)U7tnpyd{IBE+j>@Z?7m)ueL zjppzjpqyZ-*pUKwc3*i~WW+a`+g~`iLvY$k9O;S_Fk8?QmD0PDdWd%4ZHv#Y0~K+~ zNg-_V9oL9O^QMjK%RcpUl7$yqnsUztI%mwtwv0^nG1XF9FC`n>r(@*HO;42?ry?;V zNGZ&NjcrK3Uv(qSH@K5Q4<9Xwbqn!-vv2!qS?H|2ecwm^%;~&#-_+{SjgpSn51?9VLn2+ep&|w8_onek$E-vw^q$?H{4v4 zL++oeJnI?Jw~u+IJP(=DepZ#6=%}Fo8sTMQJ8i2Hvx*s+r%?{eI~$kFrL>c>SN*~P zC`rp4vbC5${MAF{joWtbBt*jvW1k+aK#{GCtCdXY)xeUwh83Mlvu+~=Rg2|#dA6Yi z9jK(D1TQi*9){W54pn+kvwJ+!M}>&)Uq|WcAAxUV%#Q*)tS*V8EK!s&9thOV8`Lb> z8PIJ#;Q!jDSJW;;)II6AVwb}KVOEH0lSfl$7@D%G}%QN3ae{h&$1KSua zIOpvySM3Sl92;m6<5E!j1J;;sr(yzpXtk+uhH}n#W3H6VQ|@YBLNv@g%2#_y zEO2N(gk#908=sTw%$BsT`x>(+TCb92QJ6NpGqty2Kd;B*$+vx~Qy#$+dd=hs!bOXg zA|7Qus|9YNVM$2ACUU@IqLWO&Q`PiQgTY*6UvRD~w$#N_EGd`n=Ds_4-pO;^Jbc16 z`Gc(}CyTb=>y=(P@Qnl>Zs-badqpmN2}yzBPLm)lq0?YKXJxT0WTZTr30vN1b}6O9 z!MW$tE|>Y_zHS5FZdYCezN`jCDxAvdBJsmfHP?EU$4J6t2rDtW_ujn=2${(MN~&<@ zjne+ZQ02UWPB&Et_k-NDEIy%z$4Sx`*SQ}j8V^Y|Tc=GF5so54O6pBf`Sr@|Oiuh^ zPrBRdaZ(ut9Ui*a`W9p!-QxZI^rbE?ZR@{KpeX`JZMl)3zTRH^3<<~uo{3Dx@ zY>`mR+qG*za!(zSQ^^LsLdzoZ8;!n8|6KGV=#`|-+%jB7h5xp3NpxXfagj$V-)iwd zMd5&3~RL>pnR-KV7r!n9Q)6Bm377Jy`Xw~VO=g?z{MmE=pq zI~q^3mJoLnn)>e00@VaTRiT3#(dB9O8lO#flo`&p7Odb@w#Llk7pB8?v&4m!PKR_LN%6LX6PbAvft){HHHJZj`UN zA(Um)9Q4#g>B`)Ef%dOWp#rh!Pa){tBb|G3?Ai;RrCAUHwy;%81lH!U0p@AP$;vWV zHqv3ekFix$=AMZE_g}Xxcu;%Djnw3DkJ#9xu#9=JAVCJOxb8=j6>XT*_urUW(V%=G;shO5~X~Nq5bChxvHSl{9)K zE|DuY$FS~pq5i#z&e`UJEdrnqNEc2E%fn)Rd{5ps$JTG03uKG$d$iEZ_|Pzm4GyWs zrTyEEp4?mJ-73lgrjM>>`?XfarX8dgIZrZ$<>geYK=abS0(H8aoY<-`u^{ft`Y4lu zf7?=VUoy(NQaa0HIK_7{pA3&3E0mjOllMug} zNL;OZUnv8#tyyaG$bAnmF8D!W_jWvQsW>kK+xf*|cO)g~pX6ja z=@EFCTfI;qYz{kp3Y>(y>wWIg0x;<-ZWE7aEVkLJ2EE*#3$-ir0#YFah~GtC3rXD) z|4!(Di1>rhQQw>M{|9wGOvaepe|@wOo#kYMWW;vvyHCWPM}NUFY&!!{Xn?=L$F~{i zyTI&P|2DfZ{T09hH2!S?rX*uy`B<)vGih#oe;2EOL6j7d9EUi#2-8=ezM3sPfw`2@ zz5seT!AFUD$Ge>Q4@@2T4O2e6WMwNLzRr}Qk1@X{)a~N{zgoThlB14-RoQse`VSXw!PvNB!Az{6oY5t2)q21DL-Q2Po75&! z&3b(e#ovyq4elrZ1UvR*gns;%$}gA+`zL04Zbl@m767Xy|DUS`^?lNRgNO7&^Fqfi z@ArxS4JMiDpZYRf95Y$ZkGB-k#*sRzQLFQGEx5IXufzlVqFXH;VrLG37 zyxu#Zqv3aT6PG<#b~z~te7)@7w|a|Qvl*EMfs(z9@8F~g%9K#-rQ1*DjgQWClZBq4a$-siZF?(=@f(-eC(gNpeFfvjwQVvDjPI{N5A zrJu-~^=s>^V)tfPKex8~r`Eqq_8*LuwQl)y-&cXYS#dx0{d4OgAh}xP=NoZ@Kfeky zCzhi&Kk|bV_UNe|ros<0@B#Z3CHAW8mphkg+W$tF0Dx(%bi^;I0@sTuG?N36=T`PK zs|~eOqJ}Jwdnj2)m+$^Is;y@@cwa~0cQP1nX6r0 z(*Mr(q2fCm6Lx==*c_gOj^_l*KfXuvbgYeSdgq`g{z!I1uXf>ds{pJBX4Pu;shknoR_RZKhCR4w%?G@o&*SyBYz zHrjh?UcT(`7!(Jb@qS=TR7UQ7x=5iSV($G=SeV|k*6}Agzz(<+#=n23fjjZbIrFc{ z23g&GO4+(8`$}RDB(8koMwAQ@OL`cbm#n`WxQZ~_nI2W&YTkHA%&q7dXR-@>4$8W% ziK?8NKTWnXiTvEl0lUx7?TR#RA{Ak-7Q#FdceSP3r5t9~+}Nl6^5%;TaGk*CbkqQ4 z$%Kmc5)YTExNlis6$5(59jwqlq@o`Z{GE+AwXWl!LLSSOQ8COBQ98wuGy+b7NWzjT zI}YveNMd^!>rIWh;LtxT1Ji|+H|`5NIBbrb*GgB?O;WKNa)pd}Bo3@Z7jyU3gvItb zQTdPqTLCpVp=!!i0j=J&qlF<>G?k8~IsInN(Q`OLW$6)x9i0hh0V})tHg-_YOIf1( zF{lGO{}`b3#Q|oFc<@ouwKY-qOUi|zUxaq7Ag0;7`yVt*d%vAt@Yr!tRaaTOT?7J@ z<~cQgT3&lqD0+#xs#0sVT|imr>;TTcJHNXeqe7A+`nD@32Ya>iLV`3{x)B7=KyDah z@2(Vf=5Nnu%V}{EeM+E5EU@UQD(A-P$a*`mOBD~5H6-#adX+W|=BmAwkLDfKwV1As zyXv|D%Dfb?Q!BB>=B3gh;?Y-}AG@8`Ed4Ey-Rj5?>NqxLn>38RVH0}d7~7?2Kl+6j zD(fEg_-jStL||kSqAvkE{`e02AL|1J)~8&x^@`|*G1{2XMECTZe;S6SxS$YrNKm13 zWj&(M! z574N6v)lg^7)H_l^a7*ZrA9`xz>yjWJ$XfEa_QQNyKp4J;vRP^Qw&X#8h=I^s0F=7 z)7R9B6Dowgq=+a*WK5L_(Id{JArV51d?AN9XZ&mX4rF@Coz0!DnD&jacB|_vNXoR1slynxMV;89GC8B4fM8)J-VFk_SnGf$)-UPqfB{AqLvy%n9^_Pc4-{lkJJLUxE9H zXf4t}({_XjU10Or{{9!nNTLYYbB?=lq^A`~@>iDSO0Z?x1EV9XKt|Qpd}?#YK2>ao z(IXBd&d;eJ(zfn??in(Bcd@hbweh%Ts@Uz#rRy{W&y=^cu?WZl#e4$h7m}PY?8|ub za#M<&1y`{T@j2_5YZJ(V+PPjFjG23;B2?3j*c=wfd`#-x8UZ$llp0W%J7-QCvuk^3 z?AtX=e@%&Jw}y|JdKNY3+1%X(=>B#_x?w(1O)M8I9Se-n(GK1$F|sj<&d6OmFIMIkPgwJ(=!eIK^)hA#WcB!@)(}m; z@xrL~LnwN!bE^X&^SoAQLXsN_m)mluE~-ELROE1&Ir<>LOrPg~D7|Lp*#5{@`*A8K z7y<1C_m9vW(I$2E)`!ohAw@Nbg+fSs8;cVv0nKWkIO0&Pa5t0*?VvjrG?{93YPP_~ z`gJ*gU#Vc_eYq*RO4EV+@MOZ?EAAB^m(+I@C10FMuRrv#Li31xRW+}UlARp?-!rgz z&dL5<+{1S64^Yj>-*dAsM0+;>sF)D^DnZHi*NpAv-+|%)n*5XrpTHyaPme|4N*0&P z*d%S40K(KsZ9NPKH;^d#%Z+p1jC19^=r5zm-`QRONt5fO26CbF@hOFT8|B|XWCE8z z*h=h(3|uB%5R36ER(Tb;BUn%?9J#n#_$wH*`!Exi@kw1QM)%1X2Pg5ME=JtlcBM_jz9M&8vM$LbqMzFR@>K!hGVn zAoi&4?!egYihE&VdST1D(8q_fM0JirA0Gj3=H2MIJ}|cDXtAk8m_^UT1gE6P##G)d z!&CDv&%grXvFDD2IS=%lwgnjDjc#qQYU4NYlA8T@qr@`eVxRi!d}^;LFu%$+cku zU9Gjj@wn_xU_f`T7xm)s1Kk-E!87rv3>nVLH($LFbJ0uL@AI!dLcwg&myDK6eH?B> z3*I;9NQQcmYeEF9xu*BqT)dkldn;nDv`!j$%iTz^-#=a>L+_4kTrMwuU3PhqqM#U1 zrgJ6QTJ)w?^w~Ae@Z3Yrj$9r)HrVDUH@-g0nv<&&2lW`MoPH?&R z%Fl@_B?4iyu8})rmals}5DIwb@q3K#%X2~^9fZ#nOH814N|_655Q33s$Mf$PW;^Bk z%r{lM;YYsOwQE7EK-8tlR&_6W8OW)j3=nC4ow^r36@##xQuq&QpbWFkJxyz0t!XGl z(#R51>Wch*v{7jT65$6;G@rMguDH4fsQS$UY7c32UmOg3ZYlBG;Oh5M6!t#)dd9Y7D*YsPe+S?r0s=Y!b5yhjQ(yCh(JY*UZAZm%Hm8xD>im(axni6; zMe+dL_7G03Yg?4r!}QW-h}KAT)d0}6SB>cw!KtxmJ?cV7VOr9UJ? zwc`wpI|MJ{ZAn_>bRiP7W>rnjQdJOJ7eaH8Y^n{xZ2_p{^6I$AEg(;D-lsKjoiqq4 zNn7pRrkrdaHZhBAGmkzxTGXK1{k}DAb3?g;tHkMEZ3S zqlXzPg^%)&pJaYgg`|5{%Sq>s^kF{`d)C)hzq46>ct2)BI{B?j13F|82w%jqszh1b zpVg{&@r>EgQG)KA>jH3(0%?zw*&`Mk6|-z?u6zBjKc7%{MExPD$R7!Ds&9CckpyWBvDxIA>(gVAQawV3!?#r}~*rZ+l?#|fk5DWF> zw}L`LFDid5(m@E#wl~K9GO}VQOf6ISsw)Lj>en;dbwo@j{HBE)Ya&m`*J{O}@_^{e zhYu9oBxn%5!qWMKv2r=gu=@<}FmV?djlfJ^7JMXsFq}QpM%s9oVw_GVZvD zrZK(cAh18&U@yFe*QZH>O?zo&5j`m0w!)+z^!c&wTxV(22>rZ`lg#=BS66q&Hj>x8 zZP_X)0@6&g9JB{`@@L!}~882H}Tzx}(+-D4}n)c&R;aldGX6t0KOm-Iw;Zh%s_!*Z0<*d|eWb zCqW5Eh9G-71d?FpBQ*f9>ObuQ<>412P1$cCwZYY&OxonJlw`eRO_s|cYb$*fe*saC zqAYS**qS4MYo7m%L^1(Ge{66wSk|%r0^M>2`4&HA_a+48lV9-piy2ho38iJ2yx`hb zNch2+Kla)V#bCNt;7hXA0>GjujfF={55|Dqph%f;mqh!!dz3kfYV*TF{7z~JzA{@x z=^Nb0CyvC?N#T1q--e|t+V=UNNVl10b4F0Y8{^M`<p1LsH*JEJ10F9+&uyl0;LOQzteP8IDXJ|7Dw_bYPhI^!JtZWTC5!&^$ZOeP@{Nk0^ZzydAX~M<6 zvprXv2Hb;@dM8i50B5ItmEv}eVwn^w{K%^|aXmj^svA=MLF|(DW}1}9kNbCa_4oxN zJX1H(+27gzu;!I}g@pVC^Jd}jYwF$U)#ByS8k~bk>XVK<$nkhYc9NOVvr^dCJrUNQ zPGU#q%9KDCuN=EksbAT5v4q&rQ6#6#E^UXj+`6SbI&}QKbM7&-pvX>_{H1h3+WUYT z{UX9I6|%0kT6Ocjh&NRXOt-aJqY_br$AXuLiFp_jw0IROsTz=#G(d*C@;}WEdE{}A zj))&}^wamg+h%`qB+RIS8!F+~WLQ~iUza)CR9Sor_VJ_TceZ4R==K77p4VzS(rA^D zWi3<%`U-76XWFDv>si!?ZSaHl(+_P}PkiPGm?(~%Z*?y1;Q^($(Y@dtAU;?-mPFi9MNH`rX5G|;F9t)W5<6R-kH6hXPUqz_}0tjWIF3e993WXDh;Jdc349s4!1}ly-025;9X?| z`;>zw)TZszM1$=kO+c{DElY!lWIEw!o>||D>({*I$_CQqGF7h0if1Fm*VZgw&;xVs zd#WY}MYd%F7_WN9rSp%pgj*=&{qWt#MR9S785T;kZokK7w=}P5TRtH$0!jQz9#W+z zU(m_u^pk6McdQLMBU(NcD9?G3TZwrlB-mcaBGRBL2ak~j!*+=m*qN^HZCtPD%=Hzz zanEn0cd2F`UIZoI(atQZcC!nN_do(_nPk{FUI;%KjLKO!i!o zPhIqoexXB!u<{YEV7xSGUa;Q%07$44>xs@>4UdC|GVI^|nIT#I@3cAf`kd5Wi8oXQ%t^;>FkLJH__TAeOk zx?DB>^2E!T1k*>=yam2<75pR7W>ho(9`_R6`1-XA!>t7UjB(GKWl93%oPpH)$gSZG zRy}fhY?gJE1wFvPP}Ro_DI2!;`Gw7g_%HBKTg?_^+po|12ljc$D7omgx3zw1WBN5& zc567hj%dtNT2{_-hrJi(ZaB`eo~?!PSx>Vw>~k*J*uhV(G1OYcky47RM?T_v*r%-6 zBcv~p94T>pv~cX&u&>A(J-XvcRIQ^ubnMx>EhH)cMrI=axGVKZNs3u zzxEVniY^@D5f*Dp7X<48a9_OrFCLv7jZ0HMW-~A_G!>$4Iy>)sp=N8V%Cz1`y zhqI&`7tej;5&4JWU>`4`cWS}mf~nJAwoh&!pbEKttCp{FZo}};Oxf_jf2xsmq z@QEDrB9%6oeX*i$KH{3={4|GWcv(_a1k_>A&DXgE1wmY9)e5;RtGT+c^vxwZXCxBe zb}I+Y?ThuQwcj0mgFl7sYn%h{t2(`6yU;feJC7rF@Ls<}wy8`z9L(W5;=5y1$EdJr zx|%342ta1G8c>s6zDbB;r@?-D1Fsi8+V7grOESMv{T8DTeRTr=^uVZ|iaPzB4`1Kv zgSU*r%D(dWkGl+WVdgzs-pWpNj^beA!Rf7 zyJT@I4{#XEr4ndpTxC1*YE|Ii>b^sh17eMIj)GE%itefGJ7Jok-1(8t$bdnGk~Pq0 zul+Eu$H6(V{XX`Z<)dwjIbq0aje-6CHsY@@7Y%4u$nQgR?Twi{&rKDQ**IA1NH?zR z$6?mT2ULuUD_SE4>@t_s)XNWC0h!Z!8!S5vzPb->aHG!{W+9co;&hW2^1dlnN)}w@ zM0M1nt7^LrbZUO8lE@gJ8eQ0cL>RqRVvD={^yB-dEseGLo+gPMpv`aMp}(bS?EOl_ zvv?1CiAU~E&DaCZp`E$@_Vpb@_aulO2h^`2-UfSUZ<**x?>m@NWebk41(RhA%vndX z4s1a(Uu$ns=R`JO0PGA7u$Vlv`dM!8e6+$DvtisRUvzd3GeF(-a#2Ug8#5Up^JPZFjnB4~6KeysLF>QZgcr9>|`*W8HP`)CW|*DSM__h0EL4p3&4yXbx`YBCIw{k< ztiawO#_8p*$GzQ2-4`udm$4o6JZzht*L_=tmmcySX<(_O^1a`SY;eK1u)~M>XZ@@i zgd6qazf8DE>-4TdVqfSjv6-%KM{+4dz%r7>Bn}=tNaNOS_=pj9Pk}jdp$FU>XZ$=e zx~?SOshu&o0hrFMn0w;Bvt=IT&|CO+VO{n+TT<$`EV7O*x}z`(@GjJ@AC&&ic0>F- zn-Wo*MFD)}7iw820y(O9eE-e}nK-py-gM*_)kZe}5?mcRHa)X_4%uTS@(VltrHgv0 z2Fpg5uYfV}H{#rdh|T^UwMFuFogI)&w)@w?9+`-{Uj$Xy1TqbSA)f!5XI)!MOiGfr zhQG5lND*~Kw~?L^Ou#8!Y=&lBmHwrV3cCT!K>IcV{W%UI4$S@M3CI1)%oeiqM)URn zm#VGk7DfX$xu29d-Cw$p;`2JcE{Fcl5H;@q67~N)qE<^Oe3jhXzGq~T^~Es3-&jw8 zrLZ_em7yzZ^Cs9~VSz#)$_h2UL`1^hA3pxkDs3S@jfT1KP(RG7q5JX`NJw&z*k>wu}gY-0tGPb=E&__12B;gqc4d#;N zLgNFgXR`L_pu1LFvhk z_-X3cPqFMXa@7RsQYF1smXZOCqzE46KG2{+CCLsVIRq&5xYIC@X1q^CMj zHoI^o-8Q1w0cxVJid5ulpm)jHY_FG+U>Lud;rG)eU)nz@PnChv*aK!}kg8!`ZJ~ZS zFWcU^i)hhkYs1rK#<~)OyIum01y#<J2oxu;r6nj6=^pp<|ennxyLJxZ;oi>Rh=UYUtC@( zcpL04m3B;J)3-LhqOioP>v_cGNe4F8) z_o;Pmrg`dKAY@pZK||*KKvKTLb`1?-V$qMpT~(B6jV`*>xS8<*%FwG-rdxIg~kle~&Afy*#KoUl{20NC?W0V+vV&APO#5Lk@;DsbP*0IK?~drM=9Qj$XPtT)n~h}py8Cv((M z%nWA5!Fe(eX|B>atf6s9Y}P-d-~COi&aQLq+=KX#5(rf$eKaATwb&<;$=z(&T>G{r zeU5%bSD0-2xyd%z|HW&c_Xp2E@)acS;1co5Tb5IjyinPszl@tt}C?V8(1U=kZ&R3JpF&%OyV66qKIF+59ps<~R zjIh0>krp~)oz=JKS4`lQBQ80i`2dXf0>{8CP;PvxB4x*+@i4BjmfB#&@WeIN#F%Au z^7&OczE~}JgKUVMSM^eX;;uPjanG&@yat_r%SbT1)I$ht6&v!5Tq|Cat*hg-24AC) zwiB^8`lxTWvwB+}lvl&{O`BBs6d~=a@rNwB!3diO#|U)ey^>M}53i98wIbX@z!5zM z+tE?EP~IW@b*GlURWKVoXSLrg{?t=!`DX#I5tvW=g8ex^%hSgz@i9@pI)$Bj3oxPE zblQ_;Z*I44i?)tZku1Ww%HNJDlDO_Tt(|HDWw+Plbo;9rOqbRS_5!AndYUOuVzqIZ zIoNs-*6=g~p^4Ty@#x%?{hDt67*jV#E?4AM)mi>=h6^tnn1&e25$M5|(TZZzZZN7f z9tan4U#cxHvI9XZwWRMr3on#^YnSB2mJ^#kf<50|&wwN+*wutfK~upL%XQ-iP-jF0hg9-3duR*iqmjc!g+oes(M8^* zMOPd?P?6*mK-r5$>is=-dK&GefqQ z+iVUAHVaR#m@U?(@uN=Do$p*4F?<8hjZ@kHEf&{PR3j&jJFM~2r3ni8pPxJc5sS<# zq{M4B$J*qNqz`S>!X-ktmsuh`!n_>?9r?q`tA!|D9~YD!PtW?opi?eosn=9jT_EK8 zW1~>#8NW_~>`-p2olOUPptNMcF-5^_uPsV+i$@Eo8e=R+%_z7pOEzbMZEysIF=zp0 zn(<7lB%OUcT_3IW+i)ub&r{g?$V&${&=_ed5j;e#LWJ>0qbrRWj~r7@?8`eqeuRd> zH-*6b8D84yj(#Mvk;d zzZ`Wscjo`*sGU16LSP)*HvJ4B4ge9iQ_;U@0I|X?|My+Ls|NpH5@z!^+qGb+rjodOET%KIuKnW1E-vTrYu&~fs}UzAX12Z0Y<$_w17ZNf zfPk7mgWmqDaLEcv23xg%kENkhX*R6=;wO2ji##V5ef9UyoqvW+d2K*yOOjE=(glg{ z<)K|PQz49Q!s5}x*&$|jEXM|>L;u#i%4jO(0mvn2sCG!^)cxD9o0|P3Hco<9v}(vF zS?t*|i_q;7ThM~o<*aWfo?YIJioIQr3b!jLX_yWT4R!sxqXT|yP{U#&jkALzhHd}& z9-tzilF!n%5wQ8^;i=4zr6mt=cvI)6c4SE8dReRae2CQ}Yqwplh;Q*n+qiza%puVW zUh{mU_;shl$mfX(mZ%R#3aF`fe<+H8&TLY1{o@|eCR?`2pi~i`I@{r zc~_M|htO309wfZ2O+Y(%wWf7R0>?-l5YiP z4ho9iRgD&ze_RLWcF6>BRn~O~pl{OF4-AuK>lOo|`KMP8@CdVv8q`MSm|%!OzM#Zx z`rEL<9Uqke=iyacPj`7vZ>dN4;$fW9Ybnq|Q~7%f#u&`3@~x&DQK7QtyvnuEDzyv~ z%@^}1edJK$bYLS^5=P(zA!0uJC-vf-?T}rj)1ff86q=y9)^d9x8>klpnmB206}GK5 zkia*L`B1i6OG%Z;zkgfG8c&$&HY=NCFEe99^b@02o`dCz^MT{)e8C+8X?Q&>sV00= zb#OsKSv1?hO!J!_d~XP6k-bJpSUM@t&;FB>z@*n?jxE{KIaM9nGfs6PkkbUP`Ax^z z*>SC~JzG_-p3x6QiT5OsZUzvwF$4j#Mh4qKPgUe+kIpP1#`Jm@lZTx;F*JBt zHNJ1*X-5==vr`Qb2U<>0VY5BS#{C*zeAipdjENv)$gR1p(+~C3!!OCH%jJl-8+_&LI_x zFylR|7C)9{MbI$?^un~^#{%c)%1!q-$d}cUD7psk-Y>krR)iiZVadnUuA_YUyTwvV zM%Z?Y+^#yqF2Ff*5tJ|x=0?c*V(6Gp2?<{hWTzg~`J#~;+yFsh7|xV0yHzYKu9)vz zS?=N=%yWckm&~d-NGph*$(iY)c(__ymGqDi{Y8#SPbQ}EaiVmYLNB{Pg(;4A^N9qz znrid*l%#Xel)WP#5lT{(%0kQG6175Gk|ByOTTkxX*ZXA?QEfEg3oMQP{a^t`0n=I+|*)P9$(?Dv2n)f~Ng&`9jn7j(N?{@AA8 zQ@|)$2IxY7{WKA6RJ)qA3rIEsiVu8}ycca43uK3EW6)pZ*|$IR0uFTDZ6}s7Pz}kM zoAm-fyE{?--!hcXb|?rVD+KIZ`gS~$DUl0r$o4j0Cykn4ihJZVqhvWS(8^4_A|=}dz`9c*%lDwcISk8Zpj^@Kd7h)Z8L z53K-oir!pXFUvyr*XAFe=dQ}M1{M0k*yqbdkl`GTJvCDWL?1rBZ-eEYXdILr1r9jL zltHublLvBc9mBLQ{X){4X5DihJ|ca?yn$og%lHLU_)w5xh#AjD-B@ zHt{5gcfXb)RLGDoe9JSh7&uzgD?tJbdy+nbW6-t<9x^U?{~YgSY7t`@O-g zsOpS9I!kQk7;h(}(9ouYA1dpef)<%#z~@3%#Q zw)b~?^wwZ;ct+|yn!R4QWDfWIfK}e@KxX z-pAXftEcm7f60R9PA>dD$=4|js*;x<78NN7WIG(bjl;;`aG076`7ymADyq_3o*#CE zY&tsih*CLnV`0>WJrKhs1YcU7caxn-1&iRV}q&8vHe1k!I; z$9`s+=Eycxovb?F_`%6#5W9B4O=0l%v&9qHim65xXOE8=QCo;BPDq|f8+K#Ihxw!d zcu8pFS79>GgH+7Am6zOVL;ppNR;yWCGmZGIq#<9JM@fN=r@X`6L6JS?i!li%14#&8 zgwaE6OO6-s?WXcNQb|7;y4@dY=?t~&F{paw*-QIowJz45NLgET{^Dts|E+?v4X9=y zQ!X=58{3Qq}(TRq_hrZ#;K#0{q zs)(dfO-?UvRmo5f-tLPAk{(Yd<-@T&=1o^ZqpZ<+Rk6#4dRf_2 zCv1v}e~Eb8l2ybs*2T9z2^)0{M5`PgYTj$2&&bkfzsIs@YOSzE#T)6%pAg@UqwL>1 zV?0vzxX-zckxhAkL>uQ;of^_(=Zqf+D}N0NAcLlxaMk>$H9o0i=@;mizg&qzh<>#) z_AS^M*e7DAX3tcXWPxHY9f7*0JdSdn9podCqhcTx3!mC9D;Pl zzPh;nyjmU)6qW0F3k+j|DqY)@yy0nODoK{4$W2eU%BD%U_=w2GDbFnlIk&~ESE~61 zMI=~0@-=AD%P4eIgj(e$J)#mCecr5F$=`L%)Eb5VJmbRYN|9-XGD7qc$+;+Wb4eYHEr9x_7!0EK^sC*fP8hUshJw z_1Pdg?BS!|)*c5-)icdX&z!Cg6(&{o4@TKxJp?TTs$l*}Qi$q0jV$^C{j312D*}hz ztDwQaAV8ITA|@-vsGUp3??P|6n)53lxG;Ut=fdWb6KyYy;;ruaiy#d86Iaf1$Q!}q zO&59P)puYs`h6`H>S4m9isjvHkcPUB(o8!W2!w7DPm^f0*TdFO0WCy<0xu&v?|$j~ zl1t=FvkEj1ib@_){5*KIaK&!D4~C;$uq&|hi>e$FG_~u5-RQmc5L7hC$`?|t9q2i( zb}vCoFTu(u2~2qh9f0nl8Wzp1-t<4RLB4c|w9j?}#V@G?t z>hX9ouIcILMkQYz^Ghf*Mh5CaO<~j%>b#=|_uzvgT<>^qSd1hCennUl6THW)Vkxu7 zs;8&}#(4{VwV*X?XpeY(A57~*?^@N1L1@XqJvm)$lLmUJnckNIhp>`|}CE=an1l*4CTpwZ-&QEu+v{;bDtLIsTS*qaDORhr47Q zr{sR>m1}Reqx>W*%IRDQOihASWh|&)>Fk>Hp#QM}QpKH)9H*J&BMVth-_{MgBJu(1 za)uYJ%X3XX(NT;Is7n!=tDD5d{i=A_LQ&?QP~Y0x8eq#wWr@xgd?gAvMqa(XrFc&Y zTeAD%t($pI>CoKC(i5s7^CkTO(@Tm*P%) zYlX;LC{if(wP3jjdYEM1@ zg8i!|wf`?#6mP!Hxt70bQUJI8qD7hKiRJtsHI%6PpYKoH9(GoOH8vG`85(LF9~5uo z?_!I#9V8*Oh>GcWTK+wnP(z1-f&v3~nAW0GW zn#b|SduK-r>-8kbkXE;H#otIeL#{=DxVon!|hd1QO&LZf4P5-DFHf!!m;lLJj&9^TZr1>Qq@ z$jK^+x)BZbV43qScdBy7dR272YK04^(jzb01nkwtL9M{g2KZ6_8mkUmnxLb8uvvkE6C11U`lz5Hq1@ z4#+@Y#T2=v*@FF7kBo@zaJjpTniOrEe2 zQf;cb1CM=IS>Wncu<&sA5wg0c$gbTy&6Na(6=W`1SDQrUA98y`1&opnk&IsSr>xkhx)gsv0Nf(7>yi)#laJv)awc_J72yRVm zV(0H5Ke;OD$$oYD;?=tr8crP!2A|~px-h3{D~l~2X7Q|cFF7&ptMerpeY=&rqk9FC z2%4p_2wkEv&m+k;m^mf6Pg59!lfN7;JmePNR5_ZV^_}e&yY`8lK|E^{TSit_-(6R|cW}4tgK2`4eYu zAx^Z?EvP`u%ng~?0b2Eq7^^grfcMip#Ne*jcKXbSzP+Beol$Rs@0)2zOdR5%r5;i~ z4o78^_pvMD!uX;et{$k=({s6*BYk?v8JJUsboQ|sA~u$xSK0@v-iQktp1i|f$B$5l z`&mU8fRIdxHtYV}t-_F9MP;^uM0{^p6c7faHQuT~Hq!S!Xki_=qcCWZQQwn0NUb3) zS_1(*m{HVe!&kS$V7?mQ=0>kBV^!Y*Td&X_-T(sQk>!wQjpj(+a0?w-;^#vP6rqP)P6+W zyR3q<-cq|h)}RQ~Ia`V4l-?VMfL@Q2S6N{5kbLzjEY*}~7k5B{&-lvgoo0crrgs5Z zN`a;nUGReIY5inU;ukB|jQkm;w!%C;-qBV8tT4q^{Mv3%Wp1O@}a6$2jM;a*P%1d)3aq>7F2G*p3csQCF_y z%m~Hvx-pFnG`?e#&?z;Uio&5nCdNC9uO=SfSaC(!CF@M7}+p}uzt=T^R#t0p4yxJl`o&*vqnM8?fUv~` zHvtD&UC_$%`IavXq@I1ZhP!DiG0C~{atfhfn!}3`uJ(X+LBm3&HCH2z;itacZ&}+~ zDN^$P@-PA{az9e!qoc;wz$@E(u9g2d$0Ial(HFLhEzbNXfKs@yRm!MyP5psc_i}*s z+wfn~A^`2&X3c7=s1Ya`1;llJDue=A{jDs8?`#Jqzq2i1F=f}ld3)u#cuz0kCi^35 z6d1Q)rxlaaZrxPUIq}b@4{4sZUMBWXB8!WL=(GO zBPA@dtfpzwlqB=k!s0p`+te$r1~0V~CCd!0+J#iC)uyKR=C@iVB}1F!TorF|9x6yy ztvWvLE#EQ>D+z>sdR_f{Aw4lsH5zw6S*1h7tYl!n*d<$=_bK%r`#KrLQFL< z1UXqs3J8WNJx!DFHSnq|BB*1#S16#gl zB|QqAByq%fkEd{Ufa6pRMb8OWt0N5d?gNSe2^`&0B^Rhc9FI?)otg;sR<^EsH~?X$ zk7nM)sTO~!*eP&_{kFRIwvPMYIx4A)AgwGSA`@1EB~n@)eJ#M1RS=h+E;rlFYp_uj zsR&rafVs2FtX5;$<$g7|<@#I^ez$nT`QfD->#onPHVN#cZ63?>CSA$i|1c{pa>t1< zohPbs?to84Q4Z~1R5`XOUSF#$HN68eDceI$^-{*mlvzmU9tgqMPp|r=Oul_>W!MSl z+3~tX*m5NfUQ`&+57W5+1fuzYBYNb+4YIp}(k3xu=nI`?+NDC+8gFN{)Xbo#qJN^{ z)Y%rQfdd8mNpfxRZK=lbJ+|f)@6J3^LR_?JMB~|8+d^YG(rN?n$Dr(~lz#$cC?STf{uJ+qstULgqF7%&#V=opbSoOE>uhZZ8L*bWt z;MS6`R{e4ERabV;I?9>xpLa)mwB^*_AOCl+`~Um*nD?Lj^u@gg*gU2+9(I59PTga3 zcXn(Qu0{d!+}()<+FykA<*oPXJWV?iDe?gDRvDiIPKQ68TmMCe(wOeaYTq2iWf{ja zz{v#%o27yo@}L=^a6hAhZC7aV03XXi!JyJ(O|6%zi1(Y`gJ2dfo{zhcJ|dqH8|HDI zc3jHWV|nSJV|7wUt*Wx?_}fmoBNBx(t)&jH8}(7L+2+T%vL}m|H~jF^A&%iGjD@W@rgJa%JO0N8i`EiBP;H3bl@WeyP^l9-%4| zaq`I=c<};6L>!oN+nI2i=^KOexM$9T~V=>pV8dqw+c7{ zcR$jyen3%c7d)MP}?X+?ia5UZefzpUtfIr&NfYe0H^#dE7r5p z?`*zz|I!q4O~+LmS3^(Tns|iX#FEjgy~lu*kAm-PqkXl%HZ{2&ZE<+MsM-OLy_QzL zb}9X9)BZlOxZS=I|Lvm%Cxa!wp;U)xC(Pw>2@V)}(+LQCkZPp-W*p?J9dt0RNDcD^ z$@>L)U?sstCr5HLjE=AEDKEQRMBfXc_uYT5fbirTMs#zyov!dXx{gSFH`7ZGG}LGZ z@&|q)cia|eVv~8;O=ec|p5|&Z3fJI&>Y^YraW`KPZ`~ z_b)i0qTF9sb!zL@0XK*S${4J_r}}irc>pu7riVFyLG%%)qjzOCWCt;8p{e-xv`2C_ zMC4bR{gvFeBS>lm`tXOIlk%f)AvOd!+g@4xJyv1{wGf5jNSyUe0uxJ^((460EDw4S)r3oP#r6jd)NrOd4&8Vi7V!;1$;re_T+vq_C ztfWDhaQiLB!cx$jY=%&|{)Fsbb}$0Xd7Fr~q~Ym@Ewv;d0dT@`Q&PVUvW&eILzhe0 zZ~?_TWS-y~R*y#IuCtalt1y2sfXD_N`mf3BtBOOG_E}IEzPTUXw&Z?-e`j;x<|@0` ziCLdGOx*{A`7Q2<$xI+C^~$U)d{WF}X$V(2auhb=u5k*SmGapVx@-(%)b+Uw zSV9H#Op{8egu@GN@2bROYdzrbr)diP{LXUhcLsgk(i|V`_|7Ka(jel~x$O$Xuq6@y zvK#)ovWEBRDdmWR?xyoTD+61Pfe;zI=_Kl&&~`@A;S$mYmy}Rlzx)|9+9ji&{F1d1 z0Mju!;Su!Bs*88_NF717Wo=>+nmBXowdjI2;f@Hw2$=6ua?$S@JO4^5I3WcW(}t_g z)f0{h#lHed_`N0{TCaEq=Z1%_`J?12rDqoCOlu}JuZ-<=;P}QO`WuDPk z7iiF$Y9IL-&2l&D$cau_MR1<4Td!V2#(%rC_@5=)&O;v19Oo_@19R1{1N%D*7AGsv zn5E}jwTn$gOVMwn&ipDptiFN^zyA;R-U2AEWm^};2~HrmCRlKHcX#*T?jGEOySux) zySx0j6CgOj33h+7_S$!!b5`xM-+8ZI-MY1_sGpwQqkD`VbBwQh_Ut(tWUr9+r3VP# z9mTHCC{0e5eWId=O{!5bniONhyoJRKp)4om20Vi7;PWdswtYf0gu9#@S8?XV7GM)t5g=Aa$3%+ z@3CdVRwDqAzuhb8pS#z+0cm?1?MQ7|9p#aJlBOV@rq-Cg6lQf4l)D z-v42!t;`{ACR)~g^WOHZe|qQ2ip6Q(-2(41@EM5q|5jmD3-vdH{Z)8`%R3jW*R3p> zna08b=%=b9kj^Q^)Awr%CJCABCB{dO+@p&4eY`na?#bv;#EFl@YkzQlN^Gug7W-}= zJ)HmIvZbQKlo;!woEQ+jc2mav3IdijZxUKLopPI)Y-6pUXyLA~2GDMS2Vc**_$g4k zxLkw)jKj9jQH3%`)K8}T)#VED6(rpISzaYp;m>uC|A+4{xOq~~kJ&zGu&P?)QMnt2 zSkzEMhyg6VKTCCwIcO)u#kntmYdmsea6nrPrl@<8z33ix-Kzr6ShTXz&P4^u5H4hh zm+nu_+?vapYh`9b{~FPHJf?oAMD5_bFapsKQBiK1jMqjD5z7y;QSd)l-wC{ykCXf{ zT+yWXg}Sy38+VcE5_eJTBREEZV>`=NS64>^23!_pMa+*syF`4i8$(oL#id2ABjd-3 zd{s!8^-;RjkOYxe4v{$tEIqdCehFgFphmA}fMfobdnU^-W6+2=@;UKFv<|QkW zxvPqTxHQLCRSEnDNd|b>cFNK>L(-IaD492$n^Ahy2S5qIC9kU z>1ql(R>tzrpA9Dd@`W+~;VZKCw_O^SAbP2H!1ba=yG+Tn8**)`uJ^+uI zVU`)IXv2zCo3l_eSs}pjnLniH6(@(IyI7i%j#pXPt6ajIW@R+h`?l96j~ z1K8T7UrLLlw~~U&y=vJ=XI*W+g541(FL4n+REKKP4U96&IctplmAo^Ce|qLl(z(dK z63bcQHGWw5SSv$9U^-$`0xe=_KY#f|zs0~DNYN3a=F%i3DVe;U$nM z$^wI2%`9t9(8oMS*ZxXqL8~33?_U}mzWn*w*En7#GI{uLo=w##yyA?5sTD>Q(y8C4 zeRPbfVegi$WhhqF=0=lYJTn=x$f3lp%I>=lC_w@>hoeY`wr94pvi5b6r&%qK! zdse8p1LNg-WbcLX5C;}-=uAQHXv&xEQ^d#K;p6$l)T|XPq@je0x&CeWXOS171V9aN zuUxXrlTp@sl`6)>sJFLwTm`W^^PIU2zDpnrUQDVm$Y`yXC~sye@@KYwYK z{WF}QkmbJ+f(98Fg698}^E-g|@Gswh0>5VBVDPR*<4C7!x$1fU^uDztje)Flh9I;c z{J9Z{`@Q1WzCjlb$qknkVe-ARHUR*)u@3*l?)vVW0F3CKVpH8ruQY9F4x;`cQiYU9 zcxj>WNK51P?&bP?l%JsH8kL5@O$q{8#YX%%`C%NsIHTPF;eVoGoaCPB8{1qhWm(2?rFjCB_rmAUkXWT0Y?e*s04k@Xefw2az zd5ish4gN1R_}8oA|AUd>e^|xsrS*JKWAi)sgR+DR4o;W| z8YUb4ual)>_Lr6NN$T+xm1PwdsEv}Fr^+*uV!p&ceG+;;X3uWv35T5GVzRHSLqE&W zK~n>M1eA)2|I!`J^n|_-Ej83@Q*T}UOqMCvK~8aqxnS_6woHgeYln*!<$R}-IM)3C zn|B(g7#OqOdoRF%o__@Q1+09eev48HNe*0$`LAm+KsEn!H2eRjiWF6Dn!)@RN4t-L zCu&(g((Z_eW22wLP@hq~zIP6Uyo7Yw1BXDQr5fHD)-%b!lO)$Rs;rlrnqI&H`|)Ov z`7SUB_}<;cObzW>z>UQAB%7k=Pl0kx|u zQG|_@xdvl2^1YNT;`}{$@@M};USU=a`N*z0*=N9SzrZkQcY7YN)218JIy~q@iF$5m zaBR}rwJ<9O*)4GhirL!D3`}qW0Mh9<3l6USdz|!jj5a%|3@&-$) z(2d%XyZzAk!IYfrEv@jI62CXGHvy9PcUq^xi`Q3hNnuGLJ3sR+ExAxNbn)38Rufj~ zL)=@M{43!81rkY5QcuD!_IH|Aql=(B=Y-snTuwpuEnRS|x_keDJCHh%0#^KYy5o&~ zaCJd-0sns%rTE{X{97ykvaNis2@c`?l;wK$7z%@<`IG1pP32fyxnd2p;ui>1HZV}h ztkP=dV2}mJ@K$8Mi!#ClSHnKrOxFX`G7_}~AqEo$2Iw%jbyujl{^E~!m3$U$8BUVI zBn1=hOHf;aJ$Im6qWT`H|JxHOO9onoN}6zes|{2=?$#c0dwGyCfWdJ77Ui708xi%I z!t%?qwzdK2Z8N<;ijS5QC|e_BmyO(^ipW#xULilk)FvD_WX`%tQ7{ZN2EOQvzgnwe zSk$90If7C|hh!1kVS*|(uLKh!;?s`{l`ad%uEzw`hi&kaWMGVBR9q?VwRa$eL#Nij z#b$fp&O9x|XDcF+!q37=89fOxGVd<`wb=sFbU|(q8 zI7!5>{k`RYzjs9OcjKLJR22Uf;tb;7nt0g$mu&(wd9U9Ro2l)LnqYwB-`4jxU;eir z{)uY;FEkNE%5H}P6+!bDCi+ucI;^!yiu!$mN|0AHZ=AB)4PwI4*DUkmRzh(O4<^}L zAPU2H#u40sK~XeJDID%v1W8+i+tTg(S8hx>csr3g$)w{hwPdppt*c>s;Cp|vdBZ~~ zJ9=O+7LwjFyg>A z<`+}vRN6}fC9Dy-MAYw+TaV3aGc`qW2_>($5@79DkUWXr6bXgA-$kBTtk2jgA4U}t z2!0nyo;-B@n5`~Uh%bJAE7CQY0PYt|2xN#a5dB^Bn@c%)d;taT@1mstYXmU6YkQ%3 z1p(0i?&w@&cu(841NG`un)VY4h0ebf^j|a(C)=_4)8wTj^bbqOs5eH~%uBJ}@K`zD zicz@y&lZ$`LuF(|>lPF#@rO}G4@~$OO}N>v@If%=#Z4A`Qkwb@)xd^O{r5*KSn?68$E^11Wool;V2Fi?`M?7%X1z~=b3A7S;NJQaf_=M}#YbB29GNNI zQ~aW$nl@Ie+sREx0s!xoH1Ml-%7It~&tlJ_8`-Bh?~_s8Qty4>Q?9XU7;)4}(TcYc zaKixW%Xq=Bq8GESTO-$6anI7fB2M}@@js~U-`e;`L;ANi{!h^c*>RR7aQwv&UgF(; zMiN|n1>tdd%5jYq^DOm#U4}(~HL^BzaI`nlvqAu-Z1l|$80iV=2!RPME?Pl*8(RSz zS4}!#4hua4AuBtBHm#hVy^*yeAp;#7Fjs+A(8k&kcbTqQ36|n?X7BVuhF$7BZH%-Bcg`}%U+pMu5 zcO0u;h=Gw3DP)b;NWX8EULjom6wC%~G@#A6k$@fxKlFT)u`Op&aRO$g*G(DPH{epl$1+50^eEITQ%c#mOnM*R zGbnf&_(q(

~zika2V5Jvs3zB;mR|-`@r{^y%iLxGsJb( z{TCN3C-j8eC*g16!vaQYL-)-iJgxo~BEfPgep(0doz`B`_3|my@NpW4YXZzR*=$rW zWxmN1cMy%W?W4(56%?VfL73&-L*0CWdL{Qr6B{+5(Z15$b671*k1ILDyb%Q)v^6ZYrK#m^H7rx0LEr0rWMtvnH|Eqe^wVfiqOeVc~UIgtJFEK-c)g8kuiec%Cx zSgp4ua^u$sEA%x_BT?X;H*;JRCVjxVt*wlQGw&1A#$vo z@l}g8_Ba^BJhG6!ncjasR+KgPq9NmZy0sEUUh4>rwOt+lsyYYic%?p!!Wj-OHkJ3W z6$?o25VYiNn6E%$g~uqkXXvo;s}l`vxQ_) zqUB6by#O$aS_Z@0Jjty^&#v_qCSP$6?l76*l3-_uk3m9h=v;0XJAfC;YOXc#i5gva zEXfEFf7qcd@geuTAZ1{KL*Et~%#0g>akyQ(q*zV_V=vdx0Uz9r3Tzmfjn5CFT6=5J zk5^y$8p@(iRSm~WW*P#nBW}r!3iT*o?5P5TK${DBl)4w!wPY=M>m zITl=khwkg3@|B8=Lp;tzEh{%`4i|)X6GwgQ5NZ)!Emtk|#-hTVd-oFiSasx-+jou3#>1~?7~{_#)zU&HP<_526yW@TmiZ=gFsN!nqK?hU$6W{j&TMiQy){JrRm zpbCAk5b+R6ofH+x$Qx5)3A$g6Rb$r!ATSAt-Be{Coj1=$j-yZ#!QGW>;z|_=b6SlQ zY;*XwFq~&4taGT~n_x@PP^%5GGyx5 zo}@Xc4LPs%u5x4^F~yBAe4XwLmKB_v8>su%bpL)q`G~X#h5`+OzA$CqZC2#fGyq9@ zab8eRj(te2D7sV0CRvHgMT4KTg$lQpUC>@AWGP$rCL)KNb`+Okw|QaEjbKM7I#1T$ z+4o7g!?GL7aJ(>m7R#Ze8-|YNU>5f9>YIxhhC=ao8Q4en?f|nhI$ejtA8JLIvbFv5 z>DDS`Up*Pe&zE-rd7_f}xD-vY*1Syq(?{e?B_o_IrfvIycRW=~E~Gh-A{#5YpYw$b z;nX8nK4;r39hg*;(*DxrILP+~nRxl$%^_2!_$B`PAK23d)Q+tceNh0NSsc z{*!m5GGE%^hM>fx=0nQpptLTDsHWzq4gv{2L|HBNNZ+sPn;aXuzALKSIOEfnjuNtn zLtpzPh48p|Ov6Frc_zoYLS9bszFB6AMdK0gL>Rv8yohbc8V+10c3?@!)>IT%fJ7B_ zY^cpxr28-+2;cMD>|#fkoap#;%kqcmN#xeZ-C2^WM<$3uF|&`jY^Q19U9G#IuDYt; zj-BU5M(;&ARD)=g2k#AP<_bpjk8^+7T@KMO=SW5ke;%UG+o$x3>~B;`JP;wc-OF** zsoeg2)1~b0E_b|VZU36&zX=8pQXm=i{x1>g&AtDFE3q^FH=cA7UV{cg|4smF)>n;q zfH|`F)0v*1`cCRo5E&uJ?S_S?6$NE{}g5__IamU(+N zVSCc}bnd1d8T5UckxyLsymk;H>3))!O+E~BMT-p8s+x`SHT2(W{w}~G!BdwT`nTe?*Art!_Ao@3~{KvW9 zNm7WtA02WKBh8(jW+=9Nm_`Er`K#ADZnn~w@X(-?r#u-Hvaz8vq&U0?N3MS24S8GNtJ)W)y`vLEQFc5kp;qGK0Prt}>-Rj_C#0B$K*#r<%#hjM}mc@~O zWR${A11HHp#y>+8>1)a0izng3SYQb3Rv(~w=~EFV=k4cm(OXx(ZSz~Ef`gCpzM>!7 zG7c;2*E0ZRIk-|@I2`2kw}Z>@RW3u3!lpiguE3E>jOB$VV58}=$B-o7&#GQ6>Rv3h zdHq5-POC%E-up=w+RV$ZIpD(uVYTrzw8iun*%(m81mNGsmnrM{Nr+YxDN!ssAU%KmjZK*S)$b8(6@ZKL(`&mPEB4KOZ+|`XDytG_wA|l+;7Q& zNT=R4`U|UrF4!M?${MxhP|fi4)S&jC%=e5IUMSG1NSwG{jqr37#4GnH`9bFBLW5J_ zIebiBlcHB-_015tFrKO^?eSFQvqe+0B~q&|Ns4XCxKSA7&5+N!24}u;$%7`!o(8KoyBECyzLYY2G4Cx> zSEYMS)usWvAnOL9EHVB3mp1q|JpL0K1U{HBu>23K@NZ-5A6Cf7%KoPnG6Ek&evjpU zWrnJ&HcCTyFVIx=3I#mZIW}&`4h1}rHHnM%_iz*m0bdtYJwRdon0^L=3=YzN6fX(u zL9X*d)}(6u=~**j-+uSFa?ISQhd{F!J&25&Af(cjve`1eteqrBSbvS{$&vanao0AU zo?>HS;Cr|_))Y4O`s99m1^@tJV>!T~;4xj*o84`Mg_xq7YmzJ1>;goPm@}Tn4%T%u z)9Ai*`}ksj#zTA+=)H`%bS)4fMD~Nst691sc&Ibx8Z_Va9`*|y^APs4n`K^^#_-W+NFxL>Jel%v2E>Wu94`G{3%ueI>4eFgv ztk}|z&x`4k-#~!^wZF?Io<=Q(HA8gVABiK2#(P?A^?cOh%7iMq%e`KC{e?yMWy?s< z+d_4(l4uIf)d+(9vF+&qvOSwj4$Tzq1C(7hOZWE#H7+lMt=K6q<24^pa2t3rD?i@> z0~`kT+_aH$PVbo)3Gc=b!~;&k-js#g=zCuk$k~^5bJt!FKj+d-Vq_Ja1-My3c!B7F6wS z7erP;%NVlK!6GJa^}%(1fcVY3sAEazdz z)EyS9+p8Ju0V#Th=qa>Qs!le$H%&(U^CnX<*9QX}!aU$rM!V0f;JGnUG(`&DvIW*x ztp24e$k56TA0nmvF+7$-@PG0%C6<*XzA8DGxFc*>jDiR9CuNr+;3vS)-p79B)5~Tg zX5;aOHD}y`4`+Z#a5->aa^2tOQC%9LCJZ;t^PQnjK(>p7jIw6lv*NH-$$37(^zcS) zG!-5)6srl)s!SdN7{!GNrA;@Wp<5)0>eY@)C*V~M-zP!a8Bg38;78!bk;+(Yzi*|5 zW_&mT?%^CVa7&*)z@Gz0Q$=F%pTAAVDvO(;h z+QUSYcG^4zSb}IR_>!`;yc9?sPcQDv_*~{hw#i%#)@>){HQld6Cx3>O_jX1@4v|dV zUFol^&QNl_n>>l9jD4>M?vgUR#Y@!SW3czZ_mj7>$#OTUxGEjTQ;vFBbX7&={@60| zk=B%J=VYu&?MWMQ3)Og1au)fG>{0KL*${=PNE|zy>%%bpo_OP3W|fa>?a!Aae%5rM zPZa{nP)DUrcroD92*G}IJ>)gi%1Uc1jnaX|?B<%pK0q&x%_Ky041yrT?A(vtQO#dM zyWK|+y&~l>+E2_Z!4!#Fjvs3*sh;GQa<6F@A3U1qwOTViI7@5|lBl&b$2>NxF1E`2 zObStd;lqakhQ3NscS3JZYaIpro&t6q^eb_MkDy^)EfJA+LWH?gD|NFFoJ^vCAjuQR zVCALy?s#h*ks77d3CPjIlvsuDk%>+?or*~!+IWRyAnZV3M9X*D+~7Rn5(m$`*@Vxj zT)Hg8^Rz*LxfMzy@%GWvM)VeA4=oZl&%&Ks*C63#;?~~ys`Gh!Gy1)tR&P_A>|ujr z5!+H4Z0XQ8_#dD%V#L-Wxnb-dUz$cS{V+VlQ3gO`cq#%{MP z-aIX~>uJU6n+l3x_TpB zW&xn8JM6W92gBYe8W!?NcnpgB9yDC>)6MV&l>|h3|E0O*rU2^;c3M2;|}!h1($D5#WnBJbLxsz2lr1aS~Fky`l~_2Y)s z^du%^7DO=5M7#;qn*t-IpasaiO=*w^Iror?)L2hAzHGbmrS?R>I!4%X*{RCj3m!;H zQ}A0BfeBhY)IU#iYfEY_?n*;`cV5Ft&U23Rv7D+42bUH$G>P!*TME^AP2Zegtpl9F zRbO5n4}Hm(BN3Zf9lhdEe?sP`lB%wLMWo+${9;4)WWIcfT&1|z7MEc}%)Bj=Dz^%dR(fb}6<%_L?Qa75-(;iat>Gq?&# z?J)t^+fnx$@%0yOw}0VBqdn)FJehn+|6ZQ_@?|joA@$OQ99osTs0MB3(kUHQia1wO?rrTc#lFtxIM zNMLVX$kTxtLMw!Y{^0&Gwp)`!$#itg<}6Jj=ydg`CtT_vH_bz$UmVIeN7ZT46bX?X z4bJd)ld`Z<`B00wYZ!jJNYtjMbL?PH7d_Es{$w2zm$>Ni4tbWuI6?881qz+IxE~{onZNYPORtXbMq!ikY)IY4Bu=;` zCU$PHgpDZ8j6jCk|<58$p_vOmH$OC>x@W=Cxz z6~;s&o0615Gx{SnN-C5}YW7fWd`U{<3srXJ`DvWBIH}uwR_h~CC=}bAacjzZ!2H#( z`lwu!);oLvkbtcfsCKF&m;E(P&POnR&gCiy;n1V(Z~?2INq)=tE7jBA0- z?Z=tz$M@d`FVaMNe#|s|Bx+sRqRp{De90wodhaP3h-ybr199+Tde85wVIVQ<^0jO2 z-TH245V*qUAh4d!Ie@Zr%PF1)@j8-7U#?E#kmzRj7vD+Go(4+F%Qm@k=Py04 zV6|YE=&AUwZJ!V6IX+c(w6In$ijT7{cRy*t*L`0WRz^#YkmmiKcE01=C3j)HoBga5 zD<)M|ljqY#P}IQ9QC?)lJZZh@aun?RIOYbNlreZ5)Ls*cJ~O5tgVDc-8@Vs{?X!~2 z7X6?zIZ8);;26w)HJ*Ca(bdPgh)hCsYw51WT=v8sVC2ZgJcv6N+tdjc)rVc^Az}}; zf>R&=eY!N#Gsu7QhS6R4PUR;Xa%<~M7H49o*Gbo{;K=E=Yg(ezAdvwTA@-(YxK_tP z)-A`{vG2=T z`<0n-rZ>EyQs%uT@|A;$ZECCc3tWYr;3A%sw)c2_Mva^So!Ph~rv1^(GBLX=~H za8-F}2XUs7t(1k9y3>V}>U|`p5=~ag&6OE#1vmYO8<(knMY*-9Dp7|1tdHqhGyD9) zg27K&aZMyc&`m|;^muZ-YXRLHa78;5TsqtPAJaIZV#;#EA}Q0ct=Uzx=)mdUr2kJb z4`UfR&bzD>Q9IC=$aGFM<%iLc#>^l2#VIhiYO5Z$Oe+U)*Aas=47kzE+w8!po^_UM zUYz2*u}E|5O>KnEr1Q7IIsal9DMg;RJfii^n5}rKN1l~D>O2u11fMbrx`EHs=|?8>lKs?askQtExbK$V+`4*;IVQJg31N<|#l(#WQ+CCZGx z-YM-aw@{tvp(|8nGDBjw-wTI5@}}WsyB7F1UY;$DZOwCyhV&QDs^O z(?8*5C3q9Xy;9CM{xzly(ogXu_%dL|*R)<6tNB`W^D95?bwb-CxlrF-UY`$BKJuI1 z&vDJhcFCrJ;4en}%TmuwPwy~gKtF>^7!%{y*)K4cz9>Bn*T&)%D&$;a`i{IGZQ0m# z#|P>um)!gmBRn3~t}^fjNRW&mrdl+idcUOCaf%fG?9tM>fVUi4o)xJ`*up+kN%zFxt+> zb!M~FeD+Y?h0H=uv`gPNFE-w_o5dX{AW(Cm_zn(qd=l`Ck3BtR(34m}dMrpk!co$3 zbnocl`z-NWx6(OX4%c09Fo7lDpMfR)_9%D50V8zqby%M>^m_C#jq85@j(vGc|HbcT zAzLYjPb)V+$CuBgyzftA^)FA(qR&6fQvPCMfLDAM_zrP?zsvjOY_=gu#rm9v9EG(j zsy|w1rYJ@)SpZmDKzeW%kfhS;l0+y5e~9LZjTJ;5AOLX?$E&TTqeHI#C+Qyo*y`Bk zQU}eT7y-p04U2deDbKIk@frvTJRgsydW&wn(Lj(aJ$>gw->=RW90d-sFCH!u25}Va zwqTOt*4t*@{KQF9*_!ujiVmPxn^xP5c|#KzTWl*aEge`}ihVbFix1h-u9`yLz}s9t zVxFKZqO0@MW>P$jzUh8vf(lTGWcxv^o)NaArORCHo0k(73)sjC4X-ASqqhdI>O%bD zW+SvVbs=F8#Uq^6^nX`qk)`OvK}(RYlGpQ8C?Jr$gh31ucaAVu2VFGgX#grXnL(e( z&!BjUVM}KO8bxZ!`lT!?qFRhuUBf)?4qW zNod&EPV+sJYTm?G-0@RF+TcP)Nu z#r+va7#LaLZu&`+3Z@iwz>M{6l_AJr2m}}9Y>8jr41m>I<0>X$BfW-u zGI;isO#fikij}4G;lq2tNN9fqu#scLCJwLOoXUuz> z(Hfi*W-^s?UcCoY3_N;zh73nIpJkvnc8mBb!%qOe&om<8`*L`NB{kfibUD+G*STu( znhKdiwyYEsTA9U039DTB>Z<2$@5^q)(QdItB-u251@V){D39`}KMUb;>OLG%D5z=& zTSqXr^lJqOZ+=@W9&Xlha-tcdaF^fT4i5?{>Z2@T(szqwHD9;Mjf|K_oa2IExv zE0SY|0maODIa9lGJRaVLig}}4sy$=kD^knuDZ%SfHlZt*463rpIksfB2KRpOH%7B?b>%H_}}K|{1OJkmV! zc!%~Ix^4a?I}55Q_FdyB)qb=o8mo4isFHGlFLR>#Qx1n2zRRurzcuGLAm1ZCEXy^^ zG|N$)>-j5$7UR_&&B;p-Axt<7P~5R)k!oO$8uEJ6B*oCmS#Y3M_7&2-*DO;tO45%g z3ULPk$6Ue207FTJH3-Vs>2?PQ5K9HY0o!~HL=Mv60UA+i%Q?l zj}RZ2t|EvW&aSZ?SNeYzR*u}JGg{xShVC4lGo-8rd`*h^bVwvo>b6ntK&2UGO46fl zgfxrjq-CpAF8sKQXcQXAP@z!M%h|s&xXM_rp7mI5$1(6J$(?;h9Z8S>BTNKCDp}^^ zaet%q^yKJCo4FPW?sA!vfa;f+(5#L2C5+2}3-8-8Yt{(Mklts)17m!c?M2^xtV^h; zeU7!|gVKkZ$Q`w~thSly>1_5qMmkdYcyU`xM-{+IhdVe+bg`9KyF6Tj`%Pu(Msuf* zGQq4TG+1WjZ=tr>;9j*K=*b-#8p<`5 zNQspjNM(%wS~XvzuwE#vin`WzjwC4C<&jTxxpSW`<4u>?vOMH>Htp=@=MySC)E6)B z5kQiTUQ1?Om+ShuDF$tw_H8lv*XzjbLD#eCyxM7x#CM^MOcy*hN-Ug}#t3@6c;ouB zFhNkA(YD2n)Z2bk>RkI8_K}4R8EjZw4v8|QA z`YTeG3G9yjsJ|Q(2k0boG))|6yXQ7ECHPyTy6Ni|o-@FuUx%oauKdKmK0+!&VblB? zjhD)4o9sseM{bEOVR@jLK|XpDbU|i@?vFYyYVZHD8s$XO{o4L=#X1AoKIx3JiR$LA z14d?{$?+LkjWd3_IvuMSQG(MVe)8SwLh3IgKfb+!6)`Km0!m9+bI6~@{^l?iqGkJm z4hW(Y`x?z|>%(cCG^eIq%*LNB$(!CCP?DGSC9p<5w$nwp@SLxpR&-RPx05os7#N|K zA+3?wU!8qL`U;Gz1d~q9J&ZVk!DblAtjz+6_3ikcOp0NQTE!!mB}j#<674jZ@1PG= zyEYjPN&@-7 z>I?Rurx@4tfb&2{N_1--*4m2EPG+?Px1wUb_xb)dvAyL3*(P{-Do&>h;|*z3Z7)J* z${c{oePv}BMyB&x9rcK~GyitR`>-#$@Dl5%I`d_`#pZaEo^JxLZ%eZnm$@R9`7JOG*_aw)!HoW#k=hu!U=^#He+v1n zn!7~@me+e2V!_SUM{H&(L%|msQGEFUB&K0sswx~e&tj^DT;;_@go3Wcg;7WF&SC@j z-cG0RG-VjL2XfIg+5S=`1&ewG@s35R)>CnWryegN4LHW!n78<}RjM7omMDDdWP|sQZ878e@KEUS z#yGPjwjg?7HriKVPL!*@-f${`nV1Cc!{PQus3#9Eh~VQ(kl04fdAb40czw-9OHc7q zX>F|)@&<&8CsYE@!AsHEIRC79Y}@GaLlER(CFNcX6Y+yBUqZJV8}y!X6^|W&BRvBz zmB`l8_A-JlADXiqcI%7a(>9Vf*BU>f<@xlQ?-dE&H3(DTmY!&rf3f82Pl8vs`>9Dp z?R{8W<86qc56-r`!c|`ZWwPpTSvV^Ta^Dnz4BY74q#7^)0v1oFtZ?WRXiWEyw4qQl_z+8 ze^m(>W$hN5-yZpwj%oSUO)p1ax!Jp0SRzdTa+JCaTaE>{aAkpnu*u;=;Q05@kGoOd zr+CS{pKmsoPrR=lPWpl$hN1{;r{n=A0BGea$Vmn#IpWm@KSXGgCh$^sumkr?M42*x z2^+^qWkX$<^CJL|8MCR|>H5>&*@N>zx)gHKv;N`wkmzg~oxKtxtYV}m%XC%%OHdU+ z>A!9fXH5UD_sV9B(+mx^VLNeHp8Q?t#EAUsue%apHy7B*Lu6||lDD|0Q~xA5ApmGF4qd3BW*f=ojCI5^zElAUWi{X$VKJX^U-I=$U{M$WcUM`IDGen2JZ~T(lNu=CdCA6%WDc3OSZV+|CIo}rW)UpV`?GR5 zZXd?fA-J?Xl?p*~=W(8z`Hs>T<=nN^QkGeC3)z$fBSnNY@Cv;24itJ(duyq|bQNnc zH?V9f_dattH*?TkB|!mF1^R5y+XeD3 zR3mUYL`cVMcz92*5~b$wT269(39dsc*5scTcG~9U{cYRaPn`iu%%y04_IKY}EeV)) zx9CVm`e^pqx17}g1*6zjEF@GtCyY%oMaCac7WFKru9_T*{fDu0Zp*%}UzL^>_D4&6 zf4b~QM(=-kv|24U@5)R`1x#uEoTS%hA=jpav%1ZL@LI~(}DFI+QFJ}^4HYfjwAYwVd1ALhqQX@9myz6Gcf zYxuViXww#(MMgKN!A$Jw8?@)&fT3DD8qZFNbE~gMyn9F^T1TkiFhdxbfGDT)PUy=m zfn`pXElK3DVHH~1hd`pVoEi2M7(WC2bX?{!KkEjahz28bluO^WmFdTma4PA&VqUoj z)t21KkMTZMn%WsSzn8&O2emH{0n;(+OmuP7IPD+It)}2lgpBkZoUc$P%Py<(kCd_1 ztsAye;+Do#2kT6oqCIRjw6cf#{PEGAvDP(njJ&MZD#Q0AD3fcy3M6@YHJUE1zNICm zW=uUyCf<3$Er*_=+c(BX`7GO~ioWfKr;F5XOz7bRYeWAxx<;vS6lxxcgd_mGMkkB2!7T}U~Nr_@nw zcMo`2SA$%ECrhoTGEXLa8u)JXeR;rqb}pvP*;%i+7Apm7!aDnfk*T-%iVBD%!NX3q$$|9ln&Oz^f!T^t5ubObLee80t{_XV zqh=D;HV5!=x^(Op3yC;M2(aIJ>8Fce)=)Tl=J4#ZE>gsRd~)En<&9lD8*H{yC?;ve zDesYIUPN|J7^E%57@faK9q_-gPE@duKdaLOynnNW&hDCTyZ0gv!sT}Hobjzju^Qlr zi=iKDVjA2E?&x>Rg=HcFuDu!pV?>o2D4RD^vn(o=b>p#P=bx&LGgjuo3f!>NE621F zxntTEO4DN09a?e3F$T%cdW*QvfE`_96^~(YgGj3 zHtj20{1$GcsVYa`e1Pq#c3Vz27Q4Gs<%?wjQelH%?1%@KIi= zz2RL8c)oK~(b%oL12kgi`z&(XNUHIHIKh%MW8;>eJ;H5?<lm*?+gM9N|y z;i{$=7ekXMwK<;~l!YIsXmz`zO_l3dD=3r({BnG;^UIAR^1zjjPuHOM4ae>DC2PqP zQl(o|*hvq*m4h-WSEdg-v*st8oHkvFzMz4i&hGCHA!YG+uH_^68Z7pf$8(q&hO@8C zm~tKelI9RG7cH_q~2ddDt0g~ z1Qk}Bf2cKh000eD#Nm=^lu(Y_In~NCeQBls?EW2ylQs1ZPY+qrD^FR^_N!JzqP^8R zGh#YJAz6AG-S|}wR-kP@bxZz6QS=udL+X~ou)@*EHo%eHj5bS_iE$oPl?gtVXfE{E z1LRfnqU-Nj)tSl$yaP!C2{NI%%nDZEw>z_3A1J`N7x;&6T!9e>x_Nkc&=rE}=|* zk{#3GPGp`ab7645a9-tP;qn*|h3RpZYRv3I4i@b?nLH{9Qm1x6E7ZA*o>6Nw-`pL8 zL%ud@K8b!xsgwjEQ?`$*2stEI%k8eyZAfn=u_crV_=xz6z*^%1UGC*Z=lO$);e7#y zdzR$QJKhn<2A4%ZiMrC37$kImNF7CmlGTQ*wKUuc@w6!5-_{1 zd=N77j@`kBZSCEUY=zm}R7GGeXW1YmB2;`#LA)TR#**CL-5ZxAAeWwd`#5YeWgLy@ zF?;?ZV6L-P1RQQlv!BCG36*Afyf-kb6i>CTxH|^9IY;A4sb;Sr@huO?{M{TfX^m+; z`JP`_t=2@zZ^B(L=tLO*vEhYSPl4Qcn+)X!hoi$OZyiz%W)tNsr3komLwyBdhugc}jkLK!m0jhrgOAh|l0k=;rAp~<5czc01Tv@O|Tk8;#LbEOGdILu+Nxb*Dly~)JF?~@+%!AhNF zwNcoNHuFxKR2hj>GfmD3?wBrrJa0H}T<$*)-_u);KkR|<7Mxdk({jyjKPq+yki57F z6M0v(o_pe&L|)k2&QED>cuUuDV%x@F4D;u*R9(5`i$Eh9M3l!n;JfKn4nHK%7wY`c zyAyY6TTCr9B3(Rd0( z6QU7GA_A>BLX5k+x{_dOor7~RPp~b_1I7mow}=`Lyr+b^x2}wV6&0S_T(D%F(}2X; z6~~&nIk=6v2~YSc7E2{~sOZYVZDEoj^>tXDdtyRTfF3wfxruXQMoxmHSLtn{mw#U= zw(|vAaN9d@_tKSNE%vmJRjLi{N3q@HkGD}lZo0`4FAqyP2+gFWBBXQn9|O^p`JTf# zo3me*Ju~ml3|@nKs*?eDyi}eod0bq^H)ljnT}JI|SLx?;TU)G+;s-8XVkN;=>LU&E zKp*HC4iVQ&=ORMnEr}-z8D&*&E2M!*uRRa;QtxelpxcQlqR5`(%tC;En0ncw<`1FF zmQP{*+zgczj+mmX=f$JCjwFVsd!o9VwXNrdB9}_uX|35lxfz3v$Cjy$ilSjCHKN!f zu`NT-zP^D*^Wn4umsY7yX{)6Ian$QdW(X8Ew$ijqEvKP zDBByF>;fGc#F9>)PHFgCyAMu2%$6}*)muAO%(Z>=GEmUda+Mz;`zGABCd+`?+Nya; zN-Pto><2L^eaf#Nu}?!#*rZK#hmkSZzGuT*hR31z*%}D$Dcq{Uk+#oJRxJk0){uS`DZCrZ zb&;o@Ps)hE;LLKQXU6~bR& zn8;M>zTL8dL@~I{F=ji$OWz(`v+2g%uK=U8|QobG9?6$})CfA6$sby$q#S@Lu*(PiI`m~zs zI6hU|!aziK1Dj)?{Kp>aR$*CtJKJzFw~@#6=GsF+jcv~Y2!+{YbJlOrpvM%FzkhPz zMgF+$7E3@$-RRl7yHMQ0l-Y`7Ox8u?dYR_#T9>=^5svN?9bOe5@;uxuiJ40e>6U!z zcVS@Cs8b6b<9k{T2=f!B%7@r_j~o!j9yjSAj73YqSK;ixak<2MPwv4U2ED<_?Kh}- zQkwAR-|ajT45aX?V_T|{K&4=B*fRe*)mqA}MD#H{FtG;3#z-jk44MOce|Ak*>zbtE zobTV!!J`p7e4m>TAsl7CPa(b*^k&izsS6x{Ad&VsT>3^}P(P9?AozNV3hNQ)VHlO8 zv0GVlb{I~!{GnkIM93^k;gpbC5hmn_Ge~J+o*kJ4duRn)X{-gw*7V#ahRg0Z=e?WX zqqA8U{8cMf2vGPWLapj@dSo=9?N7`vsK!_KH-jX&j7PTSvVF-!O@VTV1L46=%rz?? z?RScYjHxz{9cHFxE|GKVPY`VV-%{(z*90LRhJLSDuhW7D93(v_78lO1`VjHpeV1Dj zc*WLu9<<_9OzO7ec@zoz(cRN^rbaE!oSK$Yg{kh)qK%lfi4)s=(#oRqoT)Rvp>@yB zzCb4fWdAj}9uSBy8^S1dsoJ5PqAHn|4xT5W?jN zqguu$ISP&t6oWURU?n$yVlbj7ZNvKv>9$riQ96heDjk#Q_5L(FENq}{K+ylb_;;l8 z5`I9gl~7ktfSXlnQKk!Tn=nfy3I84NC8rx4zf7_TPb~21`!N(KcBX70hADFPi-iX1#vyyqN;nDMyvKWln3w|`Yv6s~doT3ePe(HTbu+L-TX z)f`gL%$e>9%hyZaxvE)Id2n38vp~lfOtaXO|4J@H1rXt*Tt$~2X^G^?lH{bwo*fV+ z@{5H5&JDL0y9Oq&{pAKn-bSjw4a3F)bmOBtYK>wM*imD^5Jdv^R_8*qml0}qo61i1 zaW&Z-6q-hMkqnetcKQhb%k+lp3&WKAI+kSa88C*hn3yLg0wU$AueTqL- zh^2Ib-r*>g@#1i*&o1Mzn$`sdd%s80rcQ)9AWU{bHWiiScevuH`cV$8;MX*g>Qt|u zMNe3EsJ<&zK39grU9#tUp8G`!yED`N&B`GQzO{9Q<*Hm6(kwzwwu0DPsVvb=ieRWt zko44KYFi@Ph8n_zz)+kxG_u*2zjD2{jQOypr<8zwZmSii$XQjM{+-jQn1S6{V7$T8 z>Bhp9Bn^Pc8A*61y+&O?p)b`zzD6Qk^%X0P+m-DIvuUhihRb3SHq*ZBrvO*Ph0!t@ z7t-O=)#sdCc}(1|&QP`dWkih|iL)1R#Xk5u5~pnb}GCr>T`mwv4!Bhjt% zyx}sFuB==?BwML{&mnP$s}xG1KfJYy_j(xdR{a{U;^Hc(#@f7T{1j4w!v3&4N@rtE zs0>?Gy_oGazqFIexw}kxzk~}R>#eeuk^C!kPryCcmLaCk3s1c>w%(Fjw0Z6@XvHys zp-$QfMQ3V3fVW7uX<&ZebC>Tq+NqbRTpz0y3eNI> zbKh$h;lv5d8kNk2soeZw%LJ-q=0+f~hXZ;dz;6&wNcWin zR*esANu-J}w@J>Aj094_w-wC9vl!=VE+l!h6+NV0-Vs2?k0Ib|f zQhkbmYAYM&tSz6r)AwB|Q^sfcW>4Asu!Z)~pgOCZd{|NUf)Gh-!tdn0NN1T$mS00K$33V zTFIYMK*p4{{%iaZPDG5hUCJ2y0KgLTrjob!x6S?80~_8g9MkT195{cuh_hFlXy4kW z&+VT0^CD{@gh8i@D-Ps@y);Bg8}_-QVY1eezQH@2SzZK%;-9|M!PfAEF!&V6TppkH zyxQWo8P1Kn@0rvCoNKYarDwlwlAsnx%sTwzn%0{>7%rKb57d)l;Pam{E4Wgn-7j`r zm?jsh7_rk{1*-=GwwbfR2VG>L2+dB}@bpxH4hx)$2zFrXX}Z2SyO%A|_UR|mWt@tG zUF+Me@=kjOJP4;G3;J~GS_pFf_&;$S-kG=fLWD!z>!Y>ezAaN*vx_U!P}+UrW<~~?ojZ15Tm?-! zrrkWoLhWS{u~b>Y`}&O;(~BV0Uv2?rK!jg%EM@FtQ5yvzMML%=H9Gmgc1wF)Huke| z2X#*B-#j(2-QQk;Iq0QKulQuL|7F{_YPr$Q%em|xoB*ckweKtFA=5yF{tNx)#y8@+ zAtbru&$*y?H&i52rdMAjH7 z_mSaHsP&+l@|?v8L~h(Ya$7cAG;I5YqXhz?m^|c6qY=dNdx$2b@1ZsbC`Z=k)-u<* z;(*T!m>W0PE#;-=WY1nE08_WRET_~*v*||kooj)`GP+kPq-_-n)l0gXPwl z)tjIhf%~|sNZAC9i0N4DzqpPK=mU@%LC*Rtz)Zzg1p=GK80_dppU7Bo9qh{Bvuy1{ z%f7liR`;evVziObEqs{OpR+stPLdjj<*%7SX%>pa;%3jnOe-NL7q3W`-<86_DP##^m z&#)QG=Yj?z2g*o?q+h(RQl)>7v=`S%<`X3BfP|7`-IK@B!#`ZbR z)}?;-mq`q9z{sCi2A|!tOpk9?CTxsDi)}edwkd34{dR02tIy@n7?=pdwpNc1t!^l2 z_k{On;}MNp$}2@ucZVpkQ)5d-& zV81j(BVC(2Hm|+9xQtnMnM|+t`X|T!8B$??E>cpP*?K7PVOH}|T`o-tVd*By@;$zpQ33}im7??9vVP*V+Cvxd=)5kX2G@O@Xoho5j}n_~si z7Qjg^Kavev;%$v3$?4bdD>aQt?P`cAGsq>Dp3GkwMXFF_i4yIyHe1R28~l|sRDoc| zvr@uyZ9LzU;VK>&L@J=E(aiF1el`EETM+nKH~W>KGnDJkLC1n2_!eF4xs;k!vs8Wm zgI~vid?tsKg8wSCI21AU@-<>uT>E8judnCzlU8Uq?NpVs zHNrZ}Lt!62Ar*kZlH`t6_>b%{r(mjX6 zuwI<+W2oaQ!iqtTKL}=zkQMXOQN)ul>|G)~VgI$$Arj`<5OuUqLu>Vc(dOaP%#EBE zS8Flnz-RGrJkj@;%SztP_Y!yohdx5j2a0ay97{No^9@Glg2lL`J!$)d;!1EQfDyiH z4_+?KP}<~~HwRJ|H1;$ocF{Q;{*^|v`=$WG4JZ{uCt?SyU#gP^htK;HsdQ)AV0l-2 zBQS&@6RpTMX~p=XxGIy#(%0ZjKzRuh6hb ztvc#zca1sbRGf}9=FK={gk)6JUSJ(GC*Oj?sk88HOBVl(*u{dGy{vsM){X!yp>6jm zIN|TzMitnN`mmpqYL?Eo=|jr_!~tz@h_5cwGao6zm7NHNmBjKJNnZgGD?W7gsWC>* zWg$-XwUzQ}kP|Pqjqju&3DEixiuJZZ7 zoqrd3D)V5_2^oqwzzlL+>;;=7dO1!<9B_*G_jyCFhCftgG$=FT(>OmE?AHxi_}#l3 zx)D(A;y{YMX0IjM7gFS1?|{q0Vw-Aoz;5fq+W{^B!>sq^o`+?^fJ{gO4(LC&@Ml_w zr2%fo#qtQ_ESmTbKOvdFj!Id}CHC*}5N)+YX`wT>KRSUJWEQTrwMCv|zW-g7ks&g> zxK0vqVroPsKlE7sDG<4$3w42#J|IyMqVR#*0U51MeWL-~zB6-qU4;;t3|v7n& zmTrCCp0i{sIccDe4I>%7H)A)+F73&O#R6!dSJeE@>YP9C$9ujm z!!=^$Jz#B$C&Li-u$vJ8Cba(N1l72zv9D9laI=)UX0XbzD zLRIH~8f=S}!Ex<4j<$E7@S&|Mfetih4+6Og`={FpC{u#q`_p)jLwGMjjxy@&zwT}T zy?CGb&4RhVDc^;XX%WKiI0O@tJe@K8Xy&`%28M8UwY&R`Wg%zD;xJMpB*l=EsLc@H z>Rz5CT(vaTTxm23($Zy#;pIGVkDO&yB0banWb3+C*Gu?Pz$F-4_fI+xc>nS9`y>D3 zRM`Z~VYIME%(g(ge1;)hydf88BB4w?Bqan}7l`qocZqL4B^NiOs&^XyUmg;`Een?C@p7>iIETV`=O^f$*NdtLDMM z7Qy#;8wN)&F@<}JYq{;5#p$p|mKkl{%Nt6oaKg!>pxm`iRgT=7dBq|HP#pj}I}9sc8{fVOF`J(vn1GdsPUI zV*`y1N`V=4fL8|HC@%(ZBq^Rj=b-@;&gStC_u3w}8Yd3r*bKSiL{<48zU*D?rRV|)m zhxp)TL~A${#_ON;EW>Otc|!DYQP={1{;0j_!&i3)JM184#! zsfM>l!DDGKG{kPDogI9p@7x_jJ*=E(-95Y@Sp+ebYa3@nn3oiRra|}vO_E)ik|ekp_-lK(;9Df( z2&V-r*+x|rVClEeypdgjM6yT-SO(Ru6bp$Z@NE%kzi6{l)!gv%6bMNwW~(yRR?u(a zGfc^s$$DGeJb?bBCN*B#Unatp>z%OS6)-x80B?}6FukERTk^==$>jcvamv8%X{$zf zGNorV%sZJ4(Ev%0{>8FMQFYnCLUf$JpoS;x%huT%ndRjuxe(GzACid9tUE*Mb%ZTh zLHjjG0X$9OFEkMdt)sVA%7j*7+@XPC*b~aW(ANL%)cS7l`ECw1RUiRC6O$9l2YY8y zN2{d2ro5~~XREa6AGm1pQZ9&n*t*l}9KdUPX!Ht``v(8^?O&jS65(v6ln4j32;YFY*;Bf*bfZma;)ae%k3P6vk z!CP%5L_#nFOG4m;i~g%A@PuGUyBHyj(}T*kps8e42fF`pB013Xj}wET5$JP$NISVN zOp%5(D8JY7{^ybpQt0o%(j2>BhI)8^1UJR_ftV`$Z=ivg$_F`oMsgCs?P5QmL?-@` zZNT!sHPO$MH;_YryeJAl(0c5u77dRXW&gE^IB13Pe5ncEIVFot^kv4isF?fle$(I!Gd8j6`xml27Hy?zh?P| zVzAHnK0OF=FtA#JtrUxSgq8m_BpuSKmV`nhwK_IHm}dIUm7^IfmbAtgS~6|5<+!**uZH5 z=1Q5$^5E^Hb3gK1Z2;kNe-B>-5yQ0cdUt*|VV>3D&2{R!C;0W!<5B!>?&9|WprZE%r@y>3FAviYWu{p1ahe8-o^tM2 zHimNi*pj0!5aPsCJ1bde)mB7C!3DgUbRFjwNKJr*d_rFXU0=ogCR89~M%qRV6smczc<< zxut7k|L}F(J9wB|nVqx|eAfTk#rNzdy@9bUkA)>~QhCZlCQZ|J9gJJnQR0u3yTZHP zi2ho@*|&h~|FejpD$(?FzDPDb|D%>DmN#38p6)`WVu$Ov*O%+G$#h#P=nw*APNAC) zvIU2?-00mSru_?X@n%NBEzAA1R?R;~W+1q-a-Xfed)Gbk+8wnvryuU-G%;1=_ZQsj z-EmQ3x1(MfC+v&2-9KH}`I>q!LePEy?U2{+xHr*uXMS`WmLZ{WC?5inI#51Qq?F39C*?)+d^C|I+D4xoy_Rg0HZv-{~mF<8}F>e6WMm zP}Vf@Db;z{^|C0*Y&?u&rUyY(dwKgh zM6NKlwc`TA*!bDHXdVuUVjct*PMu_SU43n8YpV5(gK^`th{9No9)3v8{|uv8$xPTO zC6HI-*V&&^%o*vg=lv?@TLNA{riq`TM6_&0S$eun!AWGIj6w^r-7G?+nvgUb?lrrzPY~4Tm%MwUu zAhwG)LT?|BfKO`4DTF2JI6H-|QC-o`Fa@!Uc{IY5k87$p^aU1!pbJ8RZNg4*jE!CvU{Hse2t%wV z6tVJijH1KBnv_!371vBnz?xudPOasX?vwu3aEeqH)`x`T&ZVJ3Ms(tYmcF@Xy2~jE zYM7b|@kp7 z;Q?0Lfd4X9_tD=M`YKV80@8s3*;b2mYH6J3DPddg_ zt+$)duTERK2K;@AhknGNRJl-sDOF>0?diMcrU7C&DI7TtkaK*oMo|&z=ZeGU5*j5^ zG$>&k1S^6)&dxf00_099RH!;tH*)}#FscY?9~oT1`?xJsDCM_94sb!VxTc`*F%ek_ zgGk|F@DwaB_8RTIX4tNcjhzZmKgA;Mqc9=tco=ksFqcvc--IBRu=ikJcV;|1C&xS+ zW+(fdS8*(9dOkG!+njf#=lF8SCU6W$NWwhiUJ3qeM4Vjf`(QlmAcOIw{cZZO;9_m) ziG~4OoI|sk;H7mxp^NW&dwY5@w{ph73ny<#u3piR08=-x`|I^JmUV3lZUFfY);ZZQ z)ePX(7Rs}~VMrCMONTEnNHoXYv}uW&tmQhUoi!0rX;o|37N7*BALa#`E3pg*gLa5S zVQ8r?Q^RuV!hsx7-|saj-IU>A7b$X#5>ihn@&x4`tPSxxVJnIH&N)`!%b(G-7!r;N zWx(_YJk&;}bW?)CM#~ni%uW1O+*T6I)782!_Lmv(kQ8qU;U5{zx&LvAc%$1b+HdU( z%#_n=M_ttxrf;@oyY1urR@0)ls(wM(w*SiV{hVT$Xlcpm-s?iGeqX$N-54iH%ACgh zQw-8X6X=1)@e3TU$@lF|nhq*pOk80LO&nS4B}y7OHYE@JjJmI*#~QA}h=WHb?Q``M zkYs&iYIg@mxOV|R@e{b9S!Z3e%B?b`1#bLNCM~^iGK>ZzkqRh?UKT$MeZrrD5MRZg zIB}IW*E=k%;GEyYSYc^^oezCWxJRsCJ)zN@ix|H2?&(V3yFTb=Thog&;WNj~)&Sl5 zklIncXjS5hxr7?+lv9i`aR^{f+HaTgNImYNnp~Up06RR16XoTq-Dz zOVTV$l_b9yioWXNJsIzdY{A0OW3TpJgygtSm=1ZYr|=OTNU&r${Ird=e&GYe0}o*|ybnZ_$C_ z_VXu}!%a<@9EFB-_X3{Nu*5dPGAfxBS82Q}Q@kFNRC8Zw=med^xUD4wzXyEcw|$=5 z`q+cdg}-*sw)p%CGc!%t`x1B0v+u$OOTPJdszS1T!MCgUF}V7A8Jua%vmRmuV`-Eo zru*fWwtyDJ^CVilfHkXxCXm^pcL!gc+`(5}y*?O_`nv8W6n3)QFYP8#O0NHK zG3=n=2I%Z7NrX`E3XP(;%m=S*q7}Yl*lGR=#iOoz z-FZ(=!nG2YZwpPSL#&sX;H$Q&)rBB z!xHmlo!sb}5`CNi6+{DJg)UcJVJGiq3uR^ zofp7#CidS0#0^Uv=8NqC#HlAL5@9BScL$FR#(>E+18XoQP?RHFMtw-AD$-Q7rCv@I z?4#o}1?1x7q$Yy4#BC29lpi`edhZg~c&}!G-ATzmP7dBB9;+gnJHAtL@kd3#jNkGx z81wk-?_9kbHR7CHl0$gkS8f(iK;dusd}g#Rck$OI*(Uq(`#Df3{SuTp&c^up-U*3Ajp6Jwo8m+`YHcIyeOG=N?(57ajq`uuN)gr z`Y}j2OcYhD=YLJt5@B0k-1)xy29d&TbsJrQIzYwSN1k{?2`@#yBD@8&9*39xpQLcv ze+j(*k;47|suRNgr|!r9v!XrwU!^|&d!3NqSN>S=ABy%|r0jock$@EK0i^7|tAl`~ zqPa-l0e+A5zpLAGgPQ#|@&77r4{Gq=Dvtb-r2hZXu>TFnpJn`|WDVf@pEQL3U4q(2 zUEX<(6A`3g50o;a&)7tdwaqe}QQ)<#$l>81LT}Khw{A^vOL)G8eq&YDlH*}67YPQ= z2Lx~Tye$doQ+b-h=CZ925_znP3qpW~@c)t+y@ND2a4sS2O%FvF2~Q=mFm)roW{K%T z_wu1D^me1wv z9GNaU+s`s+@|9+0tshJlCPnTj2t}JiEM%NNxgs3o-t3FeS9ho@Ni#=FvNyvqi$q!| zl{~BENoDGY?(#J++!tZgWtOJRyyp*mog#wpsDJv*^unZ82$1QhR^?1?(AzTqnSZ`E zCl8`$z^=4{gB#c_R(-dGSx|@hJ@!mC z?X;JVDS*c0mAg_&BgQwaWbkc`Ss&8Zq>SP|qvM#_z_X9$+$($rju|W7nMOR-96`>! zY3Oy<;ejnkA1?LNJ`Zb>j}ZaHt_4AbaoEKQp`5j4Mu|k}EsDeh-K=r*ScrNvM`iM9 zi(&&Yd;21_w%&aROj>xyxJkOmQcv+F`sz>yp|zhJv43WR=7fKucne9ww8b=b$lyeK ztYt4H`oN#IZhQ$n8J6cD#xfoG0R3u-$ue;ghZV-%$laXoXq?Z|b@-U7EFp@le6tvm zM*?W1En&krI@BM?2-feO+s9egm zB0)Ra@n)?4tTn zp|ZQ2opF#{Wy5aVCxNV1r|zpR?Ox{d8bU?FaCX8g0+@ z&>*)O#T>;e%OBI1UnM6Sn5Lc!_h$An$FcaBAN*#LaEji1xTd% zDf$fiQ&;B4yDYr`nW`!72N#!{l}#P*pN)(6K7=Up8-{I$YBx1q%Qsb(m6$k-X>W~s zzp;D_k4+Jm3rTRtX2trdICDH5*6{jLe?78GhCwZt<{>I1M@m=3v^ku*nTZ%mUi+St zxa*m%OJjVreQdOS(lIU`z8!D$lLRk zfKR{1LB&RtcJuS-ym;JvF3azEHx6xnu+bM0A@>$=0>U5;6AobqnmibQ zO4!Xts7QI@vX0oojGO@)(-z{50^rNptfF9z-3bJSPXZCVQ~54ElLou* z?p3?b+_NBZFzndGZNM9Wc3>1-9L`6?B8h3jT>JW}dF$Sgh-SpN7_p~~hFuavtlyg7 zE>BZ;({Kn0HcbbYWQOptaYI!OL2{zNgxtO%t zo!*8E>Tx^X4K~P6>SU(!5-QsBbpGTi^zUZ;qus57`g`syf^0vK8`^yX?24#Q%})3h zwzJ(|&SYu*==221jU{4zqkdvGyQ1SlL-*-T#5@93RoR0pu7fLIKXWB0*oVBK zn6Y>ZkoUaH9wDZpi_1rf{ZD*qt!YjwE}-Lk;_~2-nL~dmg$D?kl5!Mr2foJ-n%zfU zH->9?OjdLtUs&-wMI~|Kh4W>Xy?vRg8kNMvZ@nG#{$rz+@tKI z;A>#Jp@7;Y$@jkKyc2~c8@;9D&;{CKSU!2(S|pN*ET0j+_7r6Gjq(frx<-XlFVigTvs? z__JIuC`}Di>7b-dh5|6Jj`)?nCmhGe{+dlYU`WVH$~kE3DvyQ}7=h$fKv>taP^fz! z@hQ5SnSg&99IK8I-_i6U^rs5Jw=l{mVu`FhRu>Zl9pf|nF=y9 z^ym7II%dXcuxJTt_qr{kO4yqXFEbDsqqGp>ojR(up_pk@n~(AHw0*8tCt<5B(zUL$kUh9n}0jHZNQue;lMao+#wjkWVP@cK|V_F;t)C-TDkfNbgK_ zaxb!nm*5wCvzFH0YO{8F9JdaM8TUL9Yv#>7bwBX`wJ^fefmX3FtPrYB%*xB5<&?pPnBLZw)p}!B>D$91|K)z>s_=&qK z>OuB-ec;o^G{6zyLH$%>EB2*Z^K+e2rTX{6LjxBy8!Wd4dYu;-*@`^*cPtWdZcr~R zeC$I?CetFNtv;x4%4@BX!VPLFI+>xT^>3}U%db^&$1@#b(lQo9A)DlgmI$T#5S7)XiJ>8DT}G-- zNZ>lntHRJlA>+_`iJ^_%IorG9CU0yyC~IDutqJ8qk={;_sr5GGj)uV+-r$T%JHT#i z*(S>DW-Nvktzw128v9pLvb%#S3S+0i&Lp~2w3>2U8?p8X&K1ZAZ>(PI?;=AuTun6j zsW8~sQqwVA?$>y;sJncSbyM8lDVs65o+1NPcTS2-5cR&wH73@QdxNswM$BZA4qqgO z#|ptx*-oxZ^^8b9GKER!Ohek^-XN*3>IjuQ&s>LIYr>=~#W=mIXNEp4svjaV!#Vr0DJDczrWRZhcR+~?{^=pHRyxgQE8S^Dz{>a!Dl^#+&X@$9T- z1MK9!vE@&-6Bht~m~TNFis4?CNI9P@*`{Bppnb?yYhr|E~^$7U6=_a|!JZL99foCCj0JAr7)fXl7&ewfaU=a{kORnJx74wVzw+l+;DR8 zNoUYh6AJokYda*~NG>wlxI7nQRq8I4Drxyn#JfnL1jC?yda*5g+kA4S}uz69bJndJ_q zl~suA^QJ!uL;_vi_UX*e1au)xLUA_>c*3{8^4zlYId%A4+#V%0j&a2On=oj<+}KvZ zQB6O5hm0O=JA0-QuZI~R8;-(uHeZEDenJnNd9R}l{1@G5e^4Diysb&Kc}C>5Y^;>5 zdf84iiNr9yGPTc1VObGChCR;wwnBAkiWN$lD<97WbpPOD4zvs8>qkOf=ZhF$J*#1R z+$(*-_(^px!b@VNZ?TQcqVf|urJfW0=m_X*CF~N5c3$SsJqxUKuXx5IkMgdCy+2;- z4r=IkFc?3uOVkzy?gJVkPphlsRpL0MR4+@l&1woh!DqJReK04TM#V(H?qFap_^tr zUXAJv^-PMOnTWB`N^>nPa^((yV8ru2YMGBaAEbK|H{ zf#W1>WQl#L*D_Wg_6OFTENb8sCLK$VyxF%XddPk^_?69|>RUtekti7jozon;p6ifD zzR$~KBzhaV0~LuMOcP9*Brx7^7KY3}ZN#Scdd*^LoX<0+(;dg@X$8_%3QyFAyVgEy zFBe;Ws**GEr`i>iPOG}`l2kJ?%kX)2zPewl)OR}#%!N$x%xoDg%r;l28y;Tc6&?yg z$0iN;;s~&NdW=79m<+v!XzzBn;e(STa4|W~4hB2zxfPPu>Iq~9XW*TJrgjwWG{A)F z;7{252YAA}w9Ms2+99MBl4HpU%op$cy+6rjAg?DU>E$iFWC z-CCF}Fzrm_OAP+fdn%HtQ6|)0^xQ2>ERt4wqAU$va!IvLQ0H7StizpbslB284kj?e98WG_yXCOy9quf6OfLg4CZc%IPck=1!JTU*WEQ{4@OL&aEiw zk@B*Kr;;c`HQ#A3#=ES~8Q%-a-G;fI?w+c@7i9a_ukhvIjX@z`mog8*y1r`5H);Em z3OP|@({Y)$>WVhCZPw%vDQ%o-P2%XM%Ajq!Q9sY2URwVMV}W~FdM|3Ge6DaO8`Na+ ztiK$-j-2(0{q&4fr}sCCCN@IKx%<%Ik(2lp_7A`>JnLv`PfA~&%@JEWC*Qz&T3{as zU!S>adzG_%KhS(NK}O1}9GTFvHOT>cfffz=!bA5VHNlj&Tq{orzzRIEmp1bCbG1|H z<>~y)bvcJf@UHRf1;AhV7YLwn*#1bpxW{AVp?(IZF-WrF zwsz$JTfeI`pR*#0b3p0i0UH4$(a7T-iNgnZ#2Aj#D#-%*z3FSubTbO7QD7Lc3tZYa zXrHq7fH~Ch^sKaqfjzXnz1(j(l4yH{TY00@E$#2-`fUe=-eN|zo_9Fx@y8eL9>0@IG$9{>+o>fq6rY6NJ`3gC{KL-qWoyw}tX z6%5SYJ7nApR38V(Y06M{M9QeM;l_%kwFXn+Gaappk)7p?_IG;A_vQ!lLwyz8KNC(_ zq!#cMw)N6?&gqj4<{Y6eTxdM7V*O8G!G1I=#`K;{D!q6CVuuEgFe6GICG?co|s+MjHIU zc2t08cdxMzc;hyL>?MNiH{4XAHrdONh&I^}xwNSq8vSp|KugxbuZE8pbJqq{l>SgB zH2C1%j{swnRoP<%jkaw5?dx-bBwpV(21Pc@KO8Z;HE6dNgT;69!Mn;Z7g0A3BWo{(m*O~lv zO&BabKO<4&#awqxcvd~(1Pv&V{!jGi;Vspsf3cPM|WwjkZPG~x-TL)-M%si0sIDynL3!q)ef z>@*&IHl1iY8Hwu+?JZ!2><(>P*)miJ*~nfNzxxX_XB1j|TsLM-KRkw>%aU}Zen`s< z)-`Yj=4Yt>5K9WTMwUDo3f>DyD-ztxEak?2{IKEtZGqogr$72rlfd|}y?`b0uem5R z$EV?t4_Q-@D%r+=z#G>UHWg1)c1D^4Dtq44cUb8@TpSRVIiR2dcC3w7G~428S*hUSWO-=>Q8^7l!c z<&Q!fuq&h15~J^OkJnoF9Cl)|*kLE!8^l|kXcy7%oqGKgEmurk^nIkYSU1fB5^qFN zu+d{nXz>}wqPOW5&`IpeN-Zoa#T#4_t1C^>RqN8^u$Z>JV$i|)8`psxtF&zNR!mq+ z*6s1k`setu6$$wn7$E5tZsJK3fltNL$hLBjOV;w`=#Iaa<)=F>`%!`l(N(mD`{;W` zHTyx5qz$L}OqPX9Xu+CGd*T5(+~TPG=M04zUoFu$?^(K-Nu&76wdM#pMfM#rzALfL z=7A}Ui$Z$4gjy-6oNoj5Fi2}Km&o`5ZoF`aHnyX1b1y* zLkJMuy>WMU3+|1(LvVM8X_EZkyze|S*K_mTp4wGs)!u8bT@TIKMM_qc3i5*mjILV~ ze8@=gnWcA9#sED`pZfjc=4>A5+F}GHV7}G0CA0CF_JEU^td_gfm%3-ItR2tH$60qB zVI4karmaR;b6)$UOZW^!Sj5)ZiC`@vH0ZfZc?+J)t;Dy5p&h3J!#}>8*8UXpMZrZ` z8}_9~d_oA5xZd|UD+c9PL_G2zbT|i4MBY&4Nk!pk1Qd|%n#|Oe_vBh;;}7_xTmDP{ zCDMWP!c0IM;p9E8Yw79*l`{(Fd%0|lmaO7`zzcz^0AGklN3Bu2YEdI{s|5D#0Y!UO zEYZM_QZ%YOVah@Gn|vhXS4i*Qstvi#^{lEta-&3+{lMhh1eJ%hg`& zwF8?~1-`HE;GWgZ6wZ-)d|@XL8fQDqQ_h&-{R}$Ns+@Ahxh@GMK^Z|1OUIN@y!UL> z!UZxLasd2^R?54oD(c$5zCE(qZ(NxJUd$1>pWF}?f!)nTTY*eTOu<3m`@7@^g5DCy z3F^Ybb@tMv$GyhOaI4_J>_FXBNb`fP9c7yhw6FgDuxkm^Blo!&he)S{N!VjkeM4c+J5E4I>ul>!xt#pe%S(oQ&gbAvu$(=@GTs4ByUh<(~Zvr)5e^>BTLk3P z26adC>Mi64j^DVrS14SEi(!wbb3Q}0Un4tAur`8!+iWL-MNMmFQHaV?Un|J)g#ga_ zfJI|1iROuCzsIiujo2UBa-&o-IAGuuWDYoegBd7u7#K=5C}8g(1j0~!NoHF{du@Z4 z7=DB>?}y=jPbtvp8B9LCp9r4nYI(_uojeqiA|+!sM<`5|lfosNVG&X34)pEs^a<7w z`D{yJ^m@!HAH=EVD z?Zcx{99$+Xhui(?<~(IC(J!zi%`Wxo5n?W{=Lq)ZH9wHNIQ`@bLwkl{sCW{ z_e@O}aM0Yzjc%>1eW=+*5qN4^6{Pzl_Jkm`|9V*)3;AdhpM&DL3p4V(aa$G+=g;0P3diMK;BO$H+;U;oZW(bCFc_#$x^^I zyQvLwh{b2BtxvXV%_xpV=zoo9XcQ^AqgRttKhlN%iII3ig^s#X|u(t1x{BNB=-_NO<&et zi_&4apiWc>XTj;@sVztknWj?F`~hbMSXZ@sw?TP6 z)ML3boUNg$M4`_Gub5EsA-0;S*Pw}0V+Jc}tmo^8J*`awNQUCZip`EpOl>!C1W*%o zJ20pqM7qTle3VuRy6r4s5hG83cZVKwck>mzeFl`T)~>o)12~u31O#sqcmZ^VtX~6n})dM|50 zJN$21jGG4(V3*t463{ovtdTTt^NZEoYM&~0?Ep89=P276c3V!knE_iD+LnsxgXXn! zagRAup*xP#Xw~WfOL(2t0xQLF?dj|sI`Ja{$ZB-o@vS79X;G>bS8;YCmH+nj1M zz!D$sWSgvQmwfR=aIiG#qHm*O&_}~sv)Da%I}9Nlp76DT`ZYJ6 zVEQ=SW>L&^51inG<|-eE&cj491}tiAEBKj>yDSZ+jW)sR1cZqcpadE2k6BTUXL`}r zFW@2a#e>$eX$So>(J&8xiAKI zJ=Ub(-xmY%(ydn_S*jbIFoA%bf-+4>d^q>V9U*oOZDJnT1cz!XJxm`4E`!ePT^ z0ltveS>KHt5*B_JogF4?Y|1yK)SCBp33{+}G(?u!Y#Icu50m8?eqvin2+90Z zY!Dy6uHnMWz~WuG9#q0L869(X>Zev|e+PA;8mj}{VZ1t_BwSC=3%Sylt+x)570;(} z&+kfcDY!%6c^0{5WB8cyBk^`32D+iKGz#o|U@08!7a=U1{_1VG&nR)Xz1wP7k@D;U z)arkR?;pFrLjKTXWhuk$iDItGBWobvoUZa3?H0N=}Vj9 zu$We|n=;F?o>DKf*9%0wZ!C?{pAJY{=q>6XLI)@s4~18bPI1eqr^L)q?D^%YMnq>` zEEO>K(NtK6D}|i3Rk?%TkjvvFl2SM5%c5{C11oLfQ{L7_<4hCrK_>0ZnJVq<=a@dH zycpLqofi;PrTZO}RH<;xwpB=8e|LyciNdBrwlNdiW+mu&;=Adjc=ViAVK}8%Ejjvz ziL?ch?AYhwvaB-v9pw+oT9NwQq@jxI>>+G^FmIUwK4qyB1U{>nu?+ueCWa$s<>Lj4 z$Lo}}G^XyednG6~o7emNLjfYIXVB48QIxz;(+II`cET+gYu5;|Tz>qOFV&rj*XC2= zifeWF)F2X69BqK1$wX0NMTBXQ(DILWMxG0ynrZn_rmB|L;ie)Vyz>-{DZz4H5p?9{kyuHBX#`W@tBjS2+hA^vi0-o_sYf04gaR#5Xo{b zQ*Y#6ND@JuAMWm9&t;MsFHbbvq=X}G7~G3B!yv4J$cjIeW7g>99gEL%AS_-tfRTReQJT6c*)}JSi9S{qHyqGz$bviRmeGLz}U!?kb*I$LdDZ@1ai0m`?Lco7-TLVR%BrbzF^bMI0)5r-`FxO_j6AC$jzgvJMh_R)9=-GtjbA)sdSl|MS(j3rfq~m-`q8MigrcpYT(+HSG3mh2rJZaM zVjhcMrb8pCVuso~#T+iIr$3VQDf)eti-29bH%!gqSX(Ss;|02U`#GB^YfSgW3p;D~ zxiIQ<2>d?1LV;%2n}}eJG%gUVsLG{88xbqEOU+MGsv)07D^V@mQsv4NQCG`4>|s4; z)>f3Guw@w4ociuAj|Li0OL-5z4USL<;~&hiFw)B1_c5~fVSVVn|7_LyFik&6DpdLo zwZ5I)ic9o^KI+)#6H~UKWiU1wJr1!|OKe2k*OX{EY}@B+8GKV%$rlDAq!iL1{bUJ^ zq>S)$XtjIgS{hBV#{BT+-0qGn)%?ftj|JqB{7-o3k#}HByYd<(>e{gXle?VlIh>P=^vJ%gNUBF)*DU z%0oddKOX;81(G`HkeyMNb9_SUgMzgx`=-V^;GVaVb3a%(6;aR&v|U-c823C?Oc}_v z!)ej*H3_gke~>wNToD!c8v;+jI(Ol@Hmk@OCW@%Il#jW&!gXw~*_mSYcXoXG)r-xy zbBQC#ppLYQ-1Agc3LL74f|BNEVS4!$nC1rgD`0wC0f)CCRf`$vRu1AGoI*SjTOS|S z%eK~d^^ynzE|3cy$;QG26@?6WQ7K;Ib~vqq36*b#;&t`tcy;Uq>$I}-PJta>_=U*w zd8f?&&ca*gxsQ05!dMQ?QvzZyFU31?qCRG309X6Ob4RijXs<^r+f0HfiPMBMg>BMoKGL;BD?gi4=nl6Fg@w5mCF==*sxU@;Clw_Dd#8W&|u`gpi<0J zpxP{ne@~ROj>@R)Gp_*kpoTr$a*`Pc6ClMX*AP3=Utggt1|SJjdG)Z4rsE z6{9fnfrp@}&ur{Il2|%xu4->#&!`7{$04VYYjLT$L0Pp=J(57c=h#J9Lb(-~nzwf$ zgwD4^>C%-CD9K){kp=}eLLijT+Fq-o3S`*kwUxwSTU4mynZPIn>LoLYsu_rnlrt+4 z&&7ReG+I)PPM#YXs-~rPEID5q#(cV171L$ePJrIwrOPRdnWeC`F;=q9T@2egg+$PI z-jBxdQLZFy1VWNhWX}Y>YI)AmF*2jNGR+4ukujSCXG}5OO+Op}2Fz!>u$Ay1MA2eo zS$vO4*{z8TS*iVzyQB@r2&8gHOylv4W2E!lR0dw=x5<{#4iJCcD1&*R0jVrx#V3;i4!24a|fJZvC{_SS8*<8*WI>Z4?Q*!F&uvHp1bqg?x-CQ8|}_UZ0kns5vQ+oG0sMXXBvzgI@wMGA(K01 zU6p%6f>nlu;m7@62{j?*c-S3Y@H`%aRICdJ__pl}(p#6tigi4BFt~ge#;A+l+L#IW z-+u~i&9I<+D>8U(h+bz;UM>|=1o12Hd0HG6Tr*W0;a9KQ3$HM=0MzQPP%Pmk!1&mt z8(px;1_R$Ic(n9=!7;URltZ9DDd-h_u#_PXnjLy-@Zmm!;?Q0B6smSj>@lZUX|Md* zT1jzmW)SZvc}mOC+K9+QbLOd=L4A>jdOc2sh|)4yQ~TWFjt|YoigGn{ZL(6j6H2rf zv{1ET2VBboJ5R;_6R7p;S;^2l9NHMxY_&TeAxNG&*qF6&D3Yt(< z;?StPszAR<&H;b8pPhY=Q1ucxt@0?uW%EAyy{4lB*uzKK$%t~s#^RDYo+v5 zN2?TvhET`m`~~8D5N98ryFR?Xwg`DaJ&ZaK!#!Xh&%#{c%Ym>O^m&%|uX3k(e9sdk zK?Dv=Zl74Nq<B(malV>_)a)#_NY?Y-wWk& zv9aGcEBppt1T3S_!9y6J!i~QPeM|8Zi|m($NnPGfPg0}bVCk+C7JUX}1W&o5zMQwu zx_g;)*Q(|M@nRL`ZQ4je*j=2a^rQ>Lqg;m*Ae^qe@`7dMsuU6T7ImWA4UNq`HJg_^ zc{F=dvP*CS_KI_CQI#odZ?qgLjI>8*koPgvr5aPR^!$tLEeabCl({bY*tTp!h$s9f zd6Ji{4pVQ0lw5Cg!R7R#s^II#V%L@y6W~U|!>!MKr~QhhTgsToADLqCXa-Gjp?Hhn z^l1}vko>n9P@_O~`Hzcwfmu`7g$g54It{5OKQ?E@R~C+fP^wHi3OVt#z_F07eG7q6 zO`(oot~2NdH{+{Z`xH42n|j1POIwv#ut+Qr_g%cg<;zCanOho`z2A0u!vxY z-^g%tq*ZI>9Jy~2yakX?aNmDtGwrzHQAeXnk*($?TKLfandIFIWY^94#JwCt^F;{u zfh2fz_PjThOrk)eaDrUb=$jZ#&R$i$}aOS=FYa2Hz5E@=f-#nx0nw^Toftl>s@ zdABD?hqe~XFX;iO-uD^)#zIlB&u+Z9t7O#JmWO=-?@;|?f8Ns2un)8AF=x|~^sAh; z_5=o%D2&uhUIedyBz!XZx>a#sVoP2eNpb9k285CaXL!uRiR6%dnk^q!_&bVTdoKv$ z-chpow!2zq-m(cC8ETkU!Z*a8T`#()&qST6B-;m3Nm2%{y!go3^nB&hR`BMA9Ny7l&6pl#P zVZe52+FyUqws(|eP!66(Xd_$FhvTux6DWZLsYYLifXRR~g8fYLWxd1|e@_Is00sZV zK`SM4`sFOq{S-^vQkgu3+!5G$B$;JkDTSeiZ|9xG5476!h~%cjZ5&x{p)sT zg8?V4y*3k!Dj^I2R#NuYp`)``6hF{Sq~b&F2sK8#Oq<0*B)Wx$vOFo`PmIjDedWkf z;KY>PUaPzcJ9dOEhKpGQ;2V_7JC(pX>wk0S^eCVe6j;H6!3r1>zZ&$=5d7KMU&hn! z`ql4^JT8Yxs2a(pUmwn`fUu{4S*Xz1BlXn!4f2?HjyHdvo`OpTA;#%pT@*>3}p^H_NI6mT4q+ zF?V@VplH=JI$3`+WUKep)ZYv+FO*TqRJ}=72nm}CUFuxEwiF-!B0G?x7Lc9jj=O(r z4oY6QI;l;jRzHYZA#Yl<=)E2S>RKw6#Sap6)fwh@?16)oKk#OC$BlukzCz<}>X-cp zlP_LV-gBfRD~OBeblf?r4_m&@6Zg7T!Wx(0G!(3q?gKgn^E$QE5>vQ4Q0~VW@}`_z zF}-22F+8<@;&x&XfSx{WA@&-brPFNPVw&yP;Jhz&iixk(Q0^UHYb5sg#^`pBwFZUY z+|aUdP6(R%K_h}@f58U9bkSmst%RskMh}6J#<|1ts_<>Y)IDgxR+nj9D`V2xwXS48f zcK6~^qbtMy*3mJoYvT?K9a-LUnB`2+qK z$ZKZ}=r9IW9qg`hr(v4+(#Dz+5#BPVJf2a{A+RD$`vbhoDxQ|&Z!N&5tMip0y*C=cqhwO{xf1w+ zWScoU<9@tapBK*Eb^QLxJTIkiH78!q zV2JM>Mx8a%AkH?1NiW*;8|U%kh>wON6z%Q;gGVPCCk3Z@=cdn3sW^T-!FRBif*zON0=-w3R6 zJO~Asr9p_(*6%%MjhOyylnmMvfUmZh)yuE*hLPItOej}RDEpcI@jl1tTzanGfAShs9TD|pl;JpW-7Va zMNF5q4nM)-g)7#TOxD+|vx%ZInnE6#T6gA@+qjurSu@#dkh-+?@27d;k#CzOSWxAv zcx9g$2bA4c!&hXUW)gvS&j>U1WhqEzZ9g!B5(`di1Bcmh>gCTH&I}3-S&Y|uPW0$@ z&^O$_6)g2?5hdi;v_Tdx2TC<<_+JrJA)i6FDV$vwq*IvG=ZE;&72f2;`n=zw6$BRJ zQKL#7a0zzbr=C3zT!N_0-74kC(&)yy|_3aWw}EvfS2ewM?NP31rM@u>w8KJ%VKkfNn} zWm46TCY;Z!;0MI|%drRJEzHa#er}sB!n!pV}JVuWlW*Nmb@boSWXJ zzNR_bwiNg)SCvpIKDTFI8Az%{eXy}J`7{iNLS%=5IP=8kH&jDT1EW6)`$^o(K95X| z*+n<96>$)sCAKYz`Q4=;ZgHt#HWD0jpN_G!EAY_Ra+>x~YuXuz8cz*__IM@A0s58d z-vpu=)59h^Y}nc?L`h5%Noao5P1s*>i(;fEMKad z&L{s!OY#E?E8O60LSD(5>{{Siz2g^^2{wX38v&B4K7gn^Ukb(rDyYgZfi8o_68Sth zsW}ZLA1jXN*9|Ub{XBn;AeAselI+eDT^Wlv1D~lg3z@-b%`&R^yNj+Ac7{XA!AZ5Y zT?#i9khU@3ALwjg4QH1Z5_r{oT`8BVU)`nA4P?9)1Tr;)bI*-|$ipuK4)SzxeT1SJ z=RFD0IiJF^wC^Cd<+;g_3+0>Nx)0p=qFM61uMF_gG_3{imRuG0Q~=9kj=jG(1?ldE zzTbW6UIj$J^YXPGWm*8j8$Ffzx3;AIpP+N=_o)}LCdtv@$kSf5?hkk?j%5)W4GcMa z=-0Eu#=z{a(RqVTTKpO)!=BS6!Wfq(GG2INDWf(Zj7cFxHPg#{N}3+H<>!x&ZPlQj z9_=J*G~ylnPQ=OYcpfd05~IO+c~n1!^UCrz%L`s$*mjjt|IYv^f-w6fa-nR>w=`XJ zH~rsBM}RT-mpTEy35Ipdh}69hvB4B1)=hem>@~n;%nwDylX+2E{{$Q)Rv1LiTBv8r zH$%Y|H6+ftX9)U#R)B$%*R@YK#*qC!!J%aQd)03s*zfs^#|@FWh4_oSw$IR`nPKxy zhWzY6;OJ?oH?Pztepn1K=3FE{#Lv!sIwh3f8?^}@ihn`y=5j`)AJr?E@2D$rK);B{ zG4(NUPIAzzh&BHe6V?fB&G53k5{AvUV^+bn?wj5t1oC?uVn7k{n!JM2Cxyg1ZSXjQ zwwbWd`hfe-1n498V@*Cu_X4ewRxPq?ccp{Xb$VFXQKcrU8W-H4u!D%rKupi#j63G( zLk}=JCObQ3G`6D4rh9QS}tXcXbFh1 zdw#=Y!Q&fDhdR~fZfv)>>{~W-Q&nXcqc5YlH_4X210hN_k~@WmZgpVx5iXpREfvqZ z&%952Mx$or@8__ow2_)(a+H4;&@r0nJNk3NYRIx#uj;yFW)K#8RX&lH4?FpgG%F1& zf+WgQ-pDeXNFW6i)A1lt%2c9!+@?9(P`zxPgPEeCglt7leBEcml;wD-fN}}7i6j3z zTUR@WMZ2{?7s|of?WJHu8m3|XMMr@l>?-&q`^~3$Zw)+m5|cF;Jk4q=OeQC3Cl8dr zs^uk8ub8WY@5=r<#Rk-Qt0W-IDiysZBY&wT_luk!)tj8AUx|wkwx{s-=<@YYHqC)8 z?2{@TG~2^%r{WT+$#?l}Jc9&zvorZvNgI6%Wt<384fKKpwZp5B2cgq2=y3A0t>+id zIvVINYpsL^W#VmW55bM@4b1^AUf2U?F8`qxdXREKivO#ohZpnKr{SBRR9b#Hz6*(2 zEs6r^5omP#;5GJYP~MCv35i9Vh4nk`ishQa>xi@;6<0$zr5X9`ug%6FyhO0ivj z`+uD9@Eshh``vM@EU{olia?or34(dC1JSJrs-2M-P$E)%%m`1{UdFn+kh^2);JK=A zCBd5twvYlI5!G40qUBG!n^>w{rkX7XaG_qk7hkW)j9FaQzC;OS&K}eHN-YnsEfimO zJYS4$<=9s!wO{ix)w?{pSa+{7IKH{hwczMltVB8vSvd0lOFOQ#?Zg9}h0h%YNNfXT4bbVKIMza_M`fGt^S1iFox(O{#5YdM|bCwM9T*pJ3C9J4V#@@kIBy; z!ARW!eQik9#IcqSA;3-sYm}Nh%;r^K;`XxX*Va2py z4Yk)=y{HQtoWUn#%VSL6=s>g7Dagj*jK!Ra|CxF%Tq9&Q87Pf;ae*nFh#8d;^B1tE znS>UOJqL|K{y=UDT1#i&S&iZPPyhO?`PH2V*txx-$#F+a>^l6nIh3bs1`GLwK@!b1 zIl|mNFi5PZ%WVS8T{Gn>+#j|e)Cmxokx*WL!YHoD(22XUsT^=ut`}NeWW%#>w>}o& zJ1=wqRM}v%ZJw?49jx9DUhDvD_5DvkNAX9O)C2wao>vajG0#*XQGbB&ScPblw@*sVG}4F!*0p2k+#X59zp6RraEZ- z=w=MczMh#e_s^6Hr}@C4Ql%`p>R--t579s*$Z9%$Qe*}_Roaf2%T_Po9n$pM(h6#9 zmBlhe+LYgzleIy!by_dizY;NuIOB}Zn{e%A9#~XX^G7j9N(8DD$Q06AyH;XL7q#&) zZ#0nX5n3{2M|Nq>r`gxrXS?w%z657Dgq{8I39S>HIm19F;}3L;;JvIy9}VA|f(_9T zj=z4*7JRS%>vj9yWGi{sY3!@de*-Nz8F4-m1tjigp*HHI?y9jXMGt1H)H7AJ;VFuJ zkDfOHW*gPwWJXTelUGcv|Hhi7QZBCg4;E;~wO#d#<9?|8JiTd_ud#4&0Sm=L>|Y*K zABc{y;(`Ij^e{VG40GS&op_oxlWc$2-bWT3#@y{^TwI&duZwyp{Y6q>IUGN3;_=HY zIc!>~C`TQ(9P>Klz6{^PKI9-2pHbwxoN1loF+nN5Pjimf*@T%dFnIxmCu@ImAhK)T z54dqJzjr;=wr{m_I8dOQo!hr> z)xgg6^z5MNOK@F~t-M|J3o&8Nvc7;tw5Agz2Z> zQcSM;14mN+@|0qI^}16K6+5|K$H*U+{r}M$%{ch39L2y@J*Z)nmt~>MQMN`1&AO=9 zZ!gv{W$#<;n8};T%&zi6q{^*rsx=>VY~m01bid@2<)L$y(H#%F|FWq22a>7zulPLv z)?Wq~lshIF2L7_X7qa)LwZP*6q|zEj5<<3m4&QfwV3y7IhMkYpZ@lg07iDBjvjEfR z+N8-B{+URv8~lDR(_s)!-y9W3qKdClX1Elli;pmS?P-2X*HBi0e8=~9_}Bra?z;rh zLjTyITbyp0-;a(U#9-hZOImvzXG#qbAzH|}4X z$oUA!_?rihg$fpT*BKZGgj*Pf^=0vgiDo%AcactUXTcBm;F zM*qPY=E_3zV2SzlpR)inPMx%W`ydfzx$HCRvt)Vkk9?VdUfMdI)RB;c}5X*8i#Ji%Gh(v+X~gZC_UKd79eSDpmYtyIHkO zMkCCP5Y_cdz0f^Npl{CvmsOX<-{|}vw$%r*w31a6?36KZs1Eyst8kwEO@|q9)hJAG zvz78H^mwb=oz}ncjZtUGSN!^OSoo{l4CYmKMJ7oRdzQw0Y&5Vk|Bp2LiN}L#&CQh< zRiLk3F&|IT>V}w`3%X@Ud1Lv zaysBYv04slD+#F+iNt^L(04w_`uS6{{-s;a;jA{!e=K~u z2lN9)aWoH~M0Z(KZp@5H49u zt**CHUT+3EBepnhR9V>b&?l89MwIW~f;^v$J|li13VHEE+wXO2HEGkLX3=@WfhiZr z;G&7Km|$^d<20<+J^2?Q(Z!rJblAEFAS?-Am_NFgD!cy0jRsS>+xz*YvVKhYn|Y&{ ze(iRaF$?VJ$HA{UGQ^ak?X{x*SR8Ez*>6SIN65f$8PO|>K-Ip&aqlNsOWXY#2P(%& z^%32ddU%41f+f}&bntYb!<*+rl;HLk`l>4Hs5X8AbdvI(SScdPUH^N&fddV`ghor% z?vprf%;KaCKbl?Jq<>im$LaR*#`9)jwPD}e@z6TxjHTr-hXVs+ed56+^*k)SfH@*7 zc`8(r>f$U~jb)-bPP(|ZAI2$mc6B@~_3F!6(Q6z!rfn?VrQ&NHsp3+9(f2?$Eii+a zkSPV|YKN$Lfi;o1LMH#3+Y3-`MR&O14uh7_l8UfpJiXrBuF=DIpXE6*zI8sdYoSk* zRhtq=4_-wO>rm03wYAe=@_jif)9<%?K12)F$d-9FMkDuQEXmjOyT1D0QQnOj~Qtu{>CImI_+9oPn=Crw!*t_O{YolJ03%Iob!b7iQx7T z1HT^XL)s&MES)d`x`vVQ-?0=J0EW#I;^_w;+&qa_TYI`F!r6r#p}2%LHvGrnPq4Mu ze^8-reMh|pYKiRK&y&3I%wC{DXhKf+Y@8We?_Ga@N=NlZAhv|z`pv$ zr8oZv;cyB zZ(bYS1rl2r`qCxQG=BgZoj@=z`oEozr;lL~Vk?S;p!KfIpA4fNtch&-*L#0BK?$a1 zlyRzhg5SMP(|+X{UrhTK+p~2eSlAPyqrYonLAAdn+CQp$-Mkd5dUZ zQ%ET)3WLhDj@xT7#7zcyl+EExiRwMg^8S{6pJ^1Tccr7XFz5bKZ}_z}k|{As3kGzx z48ZfTD2IMHBvwZF_*FWFPO~lxmM?TI{F>P=m%TN4{mhn#}d zKW0e43|GMz7W-oHPQhMS94+2}A~TrT2x}i;_LXiFy=9PwC#e?kA%i|KjwWmXZ=nz% zGLIwHp|;`DQ3)ywhP}vk;6N!jy$T4FA*P^=5usx>eZ)JU+16j$f#BVN{z^pvuV1d} zZ4rR#5kakKG>|tzW$M@|ZkXRh@6-)v%M57rXG(eh%hlI5s!s3dLQOTTd&`b(64E7N zEb8lh9B3G&R6P%Ho(_gvwNd+i@3``Zz1sYMO$XXS=R1xr=Jn(x$`M;6Sn6@_266Dg zPD$^-l7qF|%YG3e_o`lTKf;gK!SHJNV$|7^lvH0$-;4pK^iN|!Tsnnt0~y^LE!HI^ z19c?RDE&uXk^|r%yQ1^`E%b6&LgT5|u>!JK`r>*RLb3x`aRRam%tGrjSmTmmKrA6v z`M-}x%bYLYaWO{YHgj>Z%{-sSZ5rl?Do=s*H@f7YjhFs9$BG**Vg%50&5_ZuEa#jo@y1FI=ruKvhADEv_G zyU|LDg1yIKRkls!rg%(me|O@mj@g>g-niwYppgHo00Bd|NMrwKWaLE8NSoN#Uq*S{ zxd#%BO~`v&`!K0V;l!^QLO3u+?exXbBps;Df#h>ANsZh3J%V(JGL>XZu~LgETc6e4 z0W0F_N)})0hMLM#4I09kV`^{Tq|_spr;JFQr^xhOO0VtZ@UzsSyt8oN2b$Yqk@O^j z((u#gY0=>KY}>tSNn_MNv9mmx{#-Si=ze0bn(#Ipw;OYEhT)4!*G~`;P4He9B#+Fn z2LO9r2H{V6_UPf#g^=QK;xQW&BVafX{~oBkH9VYb$#uPSmS-Wm-mkT_Q_m!^E+e-M zce@VzbCODzo4%4f&#YYL=B^VhMs~2hJz=8UCx$~5r~}4Z5Nc|4aWTCxQ}#X9aRiR; zWJ+9!=GDNMx}AJ1GtXFcvxDYyVsH*>F7jdfc+93spS!+Hgl}~wX9(!cB8EG{F2LPP z%AZ04utHL~M-)NM9POR7SLf5nx{@$z%)%x7Ge#=L}|km=O-ZUUomr|u0(?~FVwi)A?FcM$qt z!iPK3?1Q=H>j_Q5fGFY4Ph3U@hf1ZBW;$&*4%Y{KMU)7#K1uG~YC#+D!-iiMfl}Yay8*x#c-ue(v~{I*=K0TrGR0sd&{np=q}o2X7&& zq<0;#gY77ng^b~H!>lMhhPi5feJ;0#7&q!Jhxz5g8_{;x!w@IPIOk^1q0X{^llx(I zEchcNyUP7&EqF|AGDAk}J!ej^5-LFX_*PuuqV-eV7gP zC8*J<^UukhVz2yOH|!14@^r;2;5l|fsv?}9U?#rqcjCC~hd}Si&-OPaX+T9DmBypW zlVdxl<)$|aQf^igMxEHH(E=Muf=peKnt2t+%iB!($&r|ob9w_k*ZCGK;1ZSGAThB5 z0zOadW&Hs(-4?ey zlQ_m&w6iro$bkZ!WUtH>8Z-lPC-k6sVOcsps&THrPMOsA^wx0T=xQUwfP2(uPwvlV z0i5<`u5`HkA6%LfgY=+29-vi4cIWDmC$g0h;<-ItbI9+&IuvJ5_OA?(2wXPKC7Hgf zof|P2wtdPz%2Q7U#@Tk*3$IsXj=^6V_COK@MtfeE@CoIZx?7|^W_z`UU14~6kS zpx-Z%>7o-RR*XqQzfkOWG#$0_e|hda)Y{u|i*bUFbYOsU%Dk_VN9a zw>Az3>gx8E({@{T(w|9%b2jgq0Zvyoxk^2j9)}$cIK^fhl#*M%rpoMgZd&6^8#{9&JE~}Bs|aW;2ciA28;Aa% zQvQD`ylE`>wjI$$Cw)R60sq&gq>pWm|8x=l zzc(diV&UMR7dAGt)wiJ+Hq*A%7u46a)YJcOQ_}x7CH-$x(*HIk{cls!|28H4Z&T9$ zHYNRUQ_}x7CH-$x(*IvgNk5ru8eZPR8Ldc9#keMr@AZvIT}>Fh(?Mj)jtH-i$}^ui zVATsWvxUo@iDr{3`}s6gH3j8`$_SY;q&0r{+Y0b49FoNoF9L?Qx>awZpCGrBE&k|f3Mzc#Fc`JfjE~{zTOk5x?U+l4uvG~MNd4BfL;Y(a~Y(3|U z>q2OFeE+>D2^G18Dx4>(p$nQ7+TU^I! zJ{-w)epeCE7soq_EQXGx40y5YF9`Q?deeohE&_E!(lDAW69MQP!KMCZfv;y`K|A4$ z+dxbB6RCy{XI~@y*`Iet2*Va{biLLZ3NEf%|6k zhzRuKjGE%Tf4xbWKlJUIR>H+)BE=;P8n}QA$X*>~3ro`envx$x&XMc1&ujUf}(P#PI&j* z_tPIP*!)|YjI_^KJ1HeJxURS&_3Nn5sj!W5O8}5oHH`-~`XL9m_g7pDm4&_fnowcQ z*D3gW7mdktJC!<#P5yuPmBBJm7m4LjfL~v)0ZyJjN)_OOp90#NA#``|hKJ2KkDTnFh1Rw^MrueW$Ex z)rnC%E(n+EOvA4z@fz(XSX5qbJ(uzsTf&-A6>W9Dsd-aaV%;5tYTIPV{jx*qSMu={ zkO@eh=t)=y>rTeD9S`eCT46r4yeVfD(>jc(|I-(nMTCgysn#L7lykRK z0EP%wJZHute2Y__AR4z^kY50SFSG;>zUIL0QU8Pfz~TU*gaF;txVO(} z**~;uJb_CLdAhB3IVv)#zb=n=>6ewoxaRq!R659U9#mZQ0xu$Y60a-1ocPNwcaU%^ zWV~h0uFNFaCdnyocKj-)VLLQFim+WzHew9LB=vd3N7VjKv8h&N)C4P&M%Z`e+J@t; zcBh3vvDRrRq7*u;g(`4U5wA!9rw$lwXT9G{w>^~0eBoSBQNRr@!h$Wd3?vC?u06nARrFT88rpicu%pFgjTm~v~PKx z&#d?pt?BeDJs&${k>@!Bt{Bo|oS4u(Ie1NCVZR$7#3UDTyHu4GEL|~=xHU=g;$_s| zYOHeWs!TkKPhU6nsV0$b7K`S%wnFtW&}Bl5M%2RMx?dy<80O>}hcx}K)x(da>Pd=@`6WCkguE<-{30h-03`uWUpVpj-h&I!ZE0+8@}vj#P{Z(0~SgY z91`!|84$nz=g(WR|IeQT(_x5$1>a9cJNWWs{=$`(nc?R0E-ONFwRMH_`LmyN-Y+>& z-yf|8+Lz3FSvG^+%nWOGw0i*;d+wMhk808Ttg+^6Z{~k(olOs<3BaD~G|x=adUcmg zs|$Eo&NaWq3xLMnMkS@I;(GZT_MDZzgOhs<1}s+B^C?H0PqHH}hOQC44cE*`lM@r{ z1igMe12DQUex%?AaguuA{UXerW0?F+STMr! z%tm_VA+j%N4E`XRUe!!FN*(3&Z3ui=n#+gbA2L#4SI^1T#W+c@j_IeI-GhWlK=SJd>0uQ_U9L_{_!+$nhMwHusw__z_oh zJO`qcev9vPuayfneb#5Yw0h%$*XIA7Grjf1-9f3f{O8t#;1Ty!W&65GRAb1^rIOSL zx$}53x^mt3JUw0aD3SoZbe(oVh+|C6@l_&ji`RZ)#3XyMJb3?kmtwA=ql@UQec9 zIf+p${zFx7p)=IZS40lYgSPIItEQ9ycWSadVeZ_;x zDMUF32Wpa~ifS?@&jHc3k0r$*Ye}e@5NZm?s5|a5!avCh(1=0)eq-! zsHyG_r4yu5RG=VdM;`lvglon(t-4ifg5fMYH*Twzk#peS)T!O`SQyAUusdy!IGP8(;;xTubrPdth@GmbqCy#3qG{8Sa@joao+mrxj zKUVi^3?!IH;c>(heIn;35GjdBc#fQ&Wlj!oX+w;}>ulmwmibf#UsBArbGgtIKfOa+ z)^>wYqR9KhgqkQQZi2H-zoG8)4`Y_@QGlxJSpIRqg`M%`gZEvkdB@TNT)(83r^}QA z3AQ#9BRQx6Rnikql$t*tVWLaKs;s_C9~8q!a`QlPTUj~ca{^n>=CJBy(61$8M@QG; zODiqOMXi)60)uOt`1I*)=KO~u>Ac(UeT% zej-ZZ!SpuaGt}@E(3xz$d)0hVL2vnH`SwQ2=98`oxQUvniMcr6%cZ(rH#@gSl`@vm z-+)Ug!EY_0to#~oMzG0+>(3{V+zWp5wSH%(CWqZat>>3jXA3bhq}k`n^I^f2=|gE} zw+9`QV+gj(-H`MbAM0`nvf&&+SK=96UbLfYw8rkw9_c>V^62rP>|k)C|i zBiQU2!TSI{dlYqZm>-vUO;;D!4Hyk{p@uUE+`|9)-66k?+mB>p&x+knNWT2-?#YUH zrU22a`(TpZT4E%fN!#RynSR@zPIiD^fbytBe(si~47|RFfjXpn$;#-k{?YLHQFt`A zN!0o6&Q9uRWwYLykYP5LRW{dV5t~F>2e_s&@QYB5A~Et^IslNZ*D=yV1+RC;-Eec$ z7er1Y-xj*?82jq>H|UtocOMHP`z_|C(b@4VDui1OEdQa^Sf;CO2oe|xq-H>#W_{7U zqgFH02sOk(1skPKOx6CT4+9us%3D^%p`_oD$+$pLURObtPjoSw6So}`w>>7Td0`%` zDD^dz=Qo8-4=hZf6a}G?XA@IM*6S(J6Q)>j1f=4_;}r4iH}g(4T%4S*zWzG8@>?@* zr4Vs}S40Jp!Bw`i7>%O}H`ZT3`?_0VvY5bo=uWUyk%m<)mvb?-J3DrLEm!AY| zW2RVJoLs9?*$RT5o0zP*zuhc<6o$;F(cn_k>!O z!h3i=8KEO9n&Isf!T*&|YSwt2=d#(;#pPgPyskDgk60x+F4BigL>GR~G&#kDVl{)Krb?x5>~OEzq#t$dt)Rdb-DPfD82>XnfUF?-}KK6;_wf)Y(%;oN{!ySsGrf z-g2{zM!cT#X68yMPGWjQ2y)qzIv>3`O&95d`Q;tv7eUen>8#5Uc``YtPCg`<8ToMl}-2J{k#)O}|)G+Q}lJW1|L!D&K01 zUMU)axK24=ZnA}_z2mCDQnLu1;AY8h5~X%h&m*9j(Z$a>{8Cqz;WIq+-I>Pe{2Y&z zAjO{-dkzY54UZwE^IvDDV@1rYz6RYG%k4?HWWv<0g+T0SXYpI>cB zsa9m+r!log1uNxC7E7s=Y_w6G9s>1pkT0?&STtt&#h02HrJ9sqPdLDhy0%xNfh_#k zFW@G3R!9Q&=EbN9jdUD-ys`KW5J$!T29z0T@QnG6O?7JpTIGt%U@stQ48OW|riYij z=Zk4VaPJ?6!OZ!roc%nX<^TGccb44_vDtq5vIqf$;L96D;-@HMB7jXBOK9F{uhM_z zfYwQ<^@BH(RoJP2dkIT(7TNTtppPy(HKgt=Uj=(mSHx<1?)e*<&T}o+b_4|k6Ka-7mFuX&>#3RzIeW;XUI5~= zzlt_6N0+!n?Y|J6a6OfJNl@qybghAoYwT@<_W zu>rfggf7hpPR|rGJ4Ap0_EN4apB_wG$+4lR&=@mMU0u_-DwLT^#! zE_myUpkx!BfWGc(bX(d3S3G0bhzT>C&`CD<5hwu(4S~h|0GQOd!+o2FjsQ79Ze;YP zm>KKGAv5834h^Be!sph!)h?#yhwoOKnyu*Z;_e41--SJrIqE2R8t!(CjeBM1+a0@P zQ6ng8A(KPVU1%fy>`A{yKWp@t7l|%u>fZdBAOt?z8AUfBZc`YZa~HxjDS^~^xi6{> zL*YL|CsEsFtD*Sa5U==T;MB_c?KW249)uC})g~^4;V(&+wD&*o5lNz3yG)w;(uBq^ ze(7M~!=5F@QK9arzMR*82UfI^N7bYaRW|;Lh)>tit=Kr3K0SE_zxC>~gF1$%u=be5 z{Q(lylnzf!8e?2aV1f$x;Ig)`R7<|cFTLmJmCFv3S>oy*h4#3b6M*M_`Vk>m)`=V% zW`vwO9lN<$JZp6O^&^}k`iSl=;(Cqj5-RCKpBZII9+S!tn*>BqgXw`BUYz(}D;Ro; zq_TzyH+`*vD|~Cg1%E3p{)9fbOliG3rSDo$s-l+SH`g9}Do)mQR-TEv za6HMWzLb{p2wyJih1fE#p}kwKvjur%G;3SRA)eCKGc6|CmvWUOFWSuFg&;9&p)F?}HROobNNk{)WSq#Ab?{$ta2z8=auqpBit%%&vK ztz>cdA(&xz81&bn?y_EdUTTxEQ)iDw}!qTU$3oEqMurvgH76kMCI5Sd|6O@#oJR7Cgyz1IH5k4{A!n;>6tE@ zA2Q32;-svL-JZv8*x;80Jq_1~zzD2T-EStBG;DO3dzm?s{dnb)a?I&U-u(JH;w#`g z`QdjA6tN-TCr&lrPE^y%;k)~Ytx5VfD(ekR+ABj)+^V#1q~O!5>j=|KzWn9+%Yuky z#`hvY3B#UTT1T+Y@Gx^p+2^gPa5n>rT$ylcSMh!b$LR-*-6tMc$0vi8S+jHf9X-_Q zGS#DeJ*HUX_3UFc%eQuV8AHc%S@RY?qJAsoiMy5UawomfRkfW^!yh9%$8V-Cw%qFu zqESaq!NpYz!TH^F)5*%*elr`qfd?r&eGoHpO`XupZ`vHj;k&xGC*R)9-6Sh(?Mo)d zh23ER6p$&v7*M^oGkpYIq8GvxXP4RLp7QcecKDe6C8Et+JE>igLTZ*DVcv;LG2_0zV?~*>yF?vUR3Z8WF98 zxqcW=VV|G=U4*0oF=xF&E^c+fmL{44x0+?YhI~_A1F_l_I6|NS-l+geL~@aUXawt+ zcfcUIiMeH^bDgh;C&1>};|;Q@K3zkQ<7|nYwu<)knzf$d>C@el4!1+vX=4yhKHt#P z$F^c0{+V6M+tm}CnN~K;3lcEC^;@dxa_gR{{7y!S5_V18rqn{g8=D~Iu&k*+84B3^&lDgeQ_i_$?mmS0fOU-S`j=L^|R| z^zlL_(9Bif*9S{u28R$)>snke@*dbXil%5#j}xr~OBlA`qN-3lLh`p<=4>(-j}n1J ziv{her6HE;d_G?j-{_4On1RxXi&U`DKs9(*OxHWT01Satw3qQuKX=H}ZLQ-ZIMrJ= zZRIBEwQl1Y3&v)>1urL8SQ9 z@+xh*7(}Hf1=}&!OB=*V!sF5@*_%u}34~W+7%lW*76CRI6J@GZMVfh>e3M>5uBiJwWt;<{0w!+Sz@+SMbDIzP;W?y&KQ%ke2`=71v#}8p=c!Uzc zd|GvUem%BjNATs04|qA#sK+zzdlZl`%YSG&HfmmZ%Lp|)QJ9|pV!WeZ7kNz^mh({OEGd}KJOJVusWAUP(s<;s(HGMxQ`5RwTd#=^76eV+9nYraK)Mo z<(|<(pwVqS*AXD)C&PXs=K!tTi!~dum6b0(9<8=GP5F*#mLs*&98;+o*SV=a8@K3|3gYNICmly!~jalwy=;hBu!{&=buTDY*$*-g@I#I7M0 zeF?5p5kC*Zix(oGO)m=MzEv6NY+ikqMSejWw%@*8UD*Em))F^&T<(d3$13sh&czde zZSS+aww^e{P`8{(Gtrgfad89q$ic3-2Bt8~#uOj}UGB*zc9My+?rEz51+-jxukMSQ zi^ljBy~5JXMA6pPO)=R&o~aJ^Hx962H?(!lnj4&0!5;+CmG(CiJDqy+rC$tD4CRGO zTPdDqQUxYj(VM~;p_bvXH~rRi_QFCR$7)gJxL;Ph`6aA_W-oc=&5|-Z98Baka%+@* zC2DKZp5MF-gVGXkR;H*@A6k``0)WCxs@o3=EomD$*OX5m1Q1V|rbgj{b2bi!5OXv4 z-H?ooY{$EO$piQL0q-za*yAMzgI*!1MO*+8%O69PeWJLIAi4*YYZ>`P`po^m?c-xz z>|ZlrO4QRAfnWH1PG6Q`8RB(hRgg?#6h$skL;W`(OI%h=E8WKx%}~O-H3(=>N8P7g zCuNwMeWxgqEJgI;geD3U;-|eO+p95hIJ@7utss#TYNUC7*yCz+<59m9Z7Dl{i)I19 zWTSa*XYgwAantu#bA%|c9^~2gW?3?#`ZpAXDA5`Za`fQiJtJT%_COCy+|15_D!LH- zfi>h~y+qHr18fSG90XHY4I+uC$w@L7CO6#q7=8UnutGWU5n;a(zz zdU-L3Cx4*6gFGMoyAX{1p>x*U(&Jh=nk_mp0;BJJ=9=)4O_AI>nWbl1poedF4{?%x zINWTy1y?p$0BKCEOzhLfQOvFq1~8C<%sX?moyP;a#MJU4(J|Ocz2KlffM@*P;Sul) zps~}7KaEu)KsP|JZo>W~PG$sJGBO=$)!edV(**b4f7N(N4y9-As z<+M*ge<6-NiiIN;iE`oZ8L$0yhcV$uq_#gv^j5Mxm*4+ImAlss@$`-bwvH5&mX=D_ zxJ-Ch49I6uebQ_4fzZ`8APwg7h3|LlBUfQe0J%y>-&7n#fzm}ZlSEy7=8lOfLkwLJ z`|vEs676KLjBQsp0q%LE=8eM+oB552W9bhqNm06|vn&ef45dNO^pIvd*%;4KVa9_< zN8Kb~v~Yv>2{z(V4D3h-pF7bN!5yjw0Hi(^A4KB>?ccg(@sbt7IvZ(lAJeB68LICk zn4eTpvLJ@NO`3Z3Cnw)CXVvEr)BBi0+F!q=ISo;27XJ$_ud^ygw*hUaXfKct>e{k= z>_nF*z5QgKKeTqPUKF-K0Rtp#&bF^CiI&>bL;PWH*Kb_48K_a)Oj}U;GVG$pVG) zshCv_8QE;!D5Ct7!y+?ZXxx$fGxM3QQEQ?n3!_|M*hB4~Ei#cKSmAa=Crn$LFYN#4 z_dzu{)sF7KpC33;weP*MX()!$&bZ+MT#7)rDOLN6g-{^&*6uC|Q?%6FN~u;#2eS5P zb2G(Se5}1xnOMYa)u8iWS7G>rQrRa6qQq47_}ZH)Z`JIEAEW2|!CaTHjYnfW$6j$! zbqb=|kXQ?})y*+LOw_M;AaFL#D`X|3t=%V4JX0LI$!HIF$G<%F5o&qI;mizc_dYja zqmH-+q_8Bdjk|gl3Q#jC-JKSYDU{H;UE=vCN#~aDJ6lOwmEp}nn_a*nyz*4OCbV?Z;HL1)G4=sQn zF~dK^(h$`^S-Y^XKG@s$sqI$g^kVJX>=F+C$->3de2Qd4I7Yu`-+dM@o#M!$(mBXv zrg`MFa(-=R2->QyW0wG@={6?-F&(b)k}0&+5BU@w=zyo{cPWXrH`h!s3hz_#6W$oi zv*d@q%h;IQz*_ z$FaA3zj~)ENze19QU+Np2k$}y&~yq`96qGN;>g$|?|bf1R(#yZgaeD_|HdThio~?W z+mHbK&#?wEgh-_&-GHLi03h5a>z34$*aTk0(|sTm?P>jqa+K7LTZ-uddynHaK?lN9BYyvYe%`C>5=6pFvtq-cHt}JcoL`BAi5WHG@zgmwjGNNaK zzdCM0tJ$M+LZo+%c~W+7!2i+3h+|_Q)wr>71dC({eRkKk8LC1sxl$L&T9eaNOLV$9 zp?wW@QfOFTvM^mvjoc5yH#OLGwm}i$y|F&D0UbNgKIj{*^g5HM)GOJ?$_YS(?|x`D zueB=^m694e6HHA_OihE807OZ4oY39+rWLS?$+hMqYY3|qux9E*;qH=^$~A*9bL*`- zMV8B_Ps$PBXRrb3$_6Jt!QKK)ks-)^2c%jpq-&gE#OxA-K2(8)$fw)e21nmNHNYfc zu3fC;oEsAy0-Q+NLOsUbfLAw)$~Az>t6Xz1NPCkbA_AtF7FQlK+L8o>^=Ofs>V|rd ze6l)zXhqL?mV%LoTzWnCU(gynLEINa45)%Pu6IjIop=SO)kh_)G#nCtlqx7!1N}b_PFlJuHiCirE6#;tT4wLS?Ef!Pw-B!CaF zdX%%itue}UnK#O{_4b=}5qxmVerabeW3#F59WDWczj-1fppS6S2*D4_3U-SEI#Cr> zpnJ6l*-#XW&6=|%7eO6sh=bD+PrtQ?A8}#@@$k)g@u!MWSr?l#^1A37WI?B{{O!#K zC)A|x1U#9xB20gJO&PuVp;L9?OxkwbMjg3)Rjz+3Xpy#Kl>@H6BiaZ}Fu(mD^ z_@>cn@Jh>pR^Pt$)VfvhR2iJvhg=V9UYmLF(xu_}<{syVnJ_;6V8_l;AGBG9uYSnQ zjLb;wpV0kLHjuM8;Q77artEXWl*37R#yN4Ng$ z1LvEDki7Tx@0I!F5FzU~Mqa7_K`5k@I5f^LpsCr%P8u#s{7GbU#!tQK6{b)wTp+GZ z#S}{+_@J%QRFB11{t`VGu+AmFYA1^z5NG~yC8N@D#GB7Iz7Y4xG(8SwYwzN_SvmKk zgg;Kt??Kd77i+UQ6eug=m{Ox`^yIv=Hd_0#pO>%mm<$-!p3TiXlWN9NpT z+l?Z-x^m89yylF>I_1X+izJ|H?Rj0dL-`YV_lAUIiUuO9&n{Cfopt4V?nXN|VS{?M ze^kf>4t69gG)c2TL7k0l3V2orCD6$^dYV%8s+iS#;@hcQOWJx>?K2Al>KV>3@Z<;a zBkXHaK4D(gI2LN}qUKLJ6>p8kJr!Ng=YOelc8gG>ppjQ$x5dI`KZtA^>;iQ}8 z1_g}c&^w0gU!T7}1-DF5?1=rW)f%)6q;1>Cho!I<^TKC4d-uDg916bf zLvFYXKigwW9LOpHTQJ$dp)G|fin$%NZ09vPBF073K!U2`tX(>9+t5NZqgv2{t zXd+@#+rO`4dXBCKH}2T>3muG7)%54_kpV zX{OO$$dp@%d&5o8Y*U;y>DW@F z{XwYpsX$_JX$D&^i}k6{zXBux3FlZby@`Wyq88(InijqxLt>Ep3Jrb_c!eJ^c*^+$ zsC5_4y6Nn3uDqFE_iR&`&xJs`i|G*=eUmfgH`9C3H+T4eyo#y76`7OAMDP%~*WP$$ z)>nM@53}umVpUL4oAb&>M4|9cIE4n-IIzB@brHYditT)GoY+NHHg%<84654vW6I45 zH3D3f(MSD}4ygRT@+<5@41B{u5@~nt?v8yq$UmSnQvdgm%KhBGN z%Oi|3iCq?($2z!i{VYV^ru<`XPjZKk9^|dy2GbBkxd#-;k4}v{M8BSCd2o|30!p`E z2VL9MiiO9WWYvP&!ubdVW0*|@)Gof$IPVOXQSN_fI^X&u8Qm6u{n^yxYm{ZCa3M<6 zy$+sb*H|`c44vsp9tPju3=-$)S5BHS(&HVV{9D_lt5?dTa`== zGr}tx9<+^-C3keh>6-c8T*HeeQDfi5+RTA`$EdspaU4(CZg{&XIdr1kM=73s2sBBd zKuOe>l8Q6%`?fsIrK`%vDlS86fm+9yUz3s=<+l%MwEBY>Y~Xv<0~Ujqy8fK*WTu=T z_f(iX3H~p-DBd*1nXr6`JbSWX=X61qxL0nv?+K5RaxDmy=kivucbQx2*+Nfy@tm5m zR~FJ2oluTXmev|X=;wPNd`@NT)FF`dfTl!7Du!64lj;{dWJhsyES~i{J^{eK>u}Nn zQAGzOZ#wXg-)X7se4i6kF||qW#IH!pt;?h`ntSy0O>gavA;nhc{zht`R6Vd0xv50J zifPn7`P0Vhc(^q~OT3sfpn-zos1LqWuEG1w_cQ zb`O^MI*}EN@0U|)$@_68QEDSRHx5P(Zvf$nx0<4(V=)N$pG@V-1zzagMq|Sqvu9u4@K*Rw6zJ!^SC-zRg`jvnlmBR7x(^#7g*pdr!WzP z0PiBr%K)paRG%a7D4e^if1L9KeS8?7E=(9}nXcuyxsi#{?+y21(M)6&<`?#S9?46Z z&mm0_)vdwx*F3peWTYgOtbmyVo8*kw<>w0U} zI&EW{yZSrt9@tXFFER6dvZg7Sx6UYJMHJmUfOD*J(7${y{ZGlKtG$HkM)+CviYr+@&HMJXpme?2%q<84dn^bdshc(mykXXAS{Y4k_NsA4%5l3}%e@;f-@dEca5eixT~=6}nllDz3>A*psL1oauzMu3cuXhu^PRr0#ub_I>9x7&g_ z;X$VzP@v0FCAB5qnR=CKBmH*XCi&Gw+k$SEXbZpN4xtiZ$lgvt;5dneXU@6Qb@;)DaLj6XUPd_ zF%W}OWN%?L#;#wm_ywj!@QCYz%Lq0b9#Xy(wS!=AaR!;(&LSBjCd_&;0d@7avs^!(gVLwlg8})iJhO%-nR|{TG#X6N+js= zw%RipigXbdqar)sC{1>eA83!My+p%}G{bImuj2D{g3?A@Kb0#lB_vCE9qrVmk1`zl z@>Mg*UOYPektE2rDFsZ1hP-0Wj!49rNO51nWj9VwB=7-QboJdn-U6?**at?zLMGPy^d9Hu ze3UoiJF{kl<@SqHSimh3lZVASwmQnixct%!@Z4wIVUBwGn@lpT?XJ{c9P8s5lje1! z9R${jk?T0f^OkBKtSso&b3EZOyWJobV4HIKqfFyzRcm;Gg=feDfSr-`#w!X{igH3A zF3aKy@VP{+EreD1vsJ<3*H5cpSug2WVEE-!Vl){-5ciXGi4T>CqAAwwbC06r*D;v* zPct1yNW>4dW_ori2g>wa!)k_16wI)~EFNY#iabQ6Pmtnx-{6C0qqVW~){}npwv_u2 zD7?e|@}rZzi}367f)pSLMJVWC*`!!Dn!-3rN|zlxfh0lG2z@CpM{!XgDWofz;OcT* z1@-Xr@$jfQR7gVJSH|=vLE}m`_)9;)05d$$X;6+#=LYz|ld#RE_3h`?A!+82K>sAK z-#=4*Z#o71CW#X2*P-@TA*7M@pqMhXI7RQ z%kN6{28Gg6?(rEdv9}wl&9BMjc&7q0MY{criyy)FN%e};tkiih<6gCLC4TzMO@to&C3?Z(?|OCu!=ZLHuAL0CKPlPwWvd&z0l!quU&2kw8#jD! zGk1J5gwEIyxMIYf@Rdye2iWd6lI4(V{;lKnPqntw%93t6UuXErpx_) zZiS4&0u8Ti`0>z-3cEH>5%R~pcBfTyMs+1)yZl4+>ISgP!OXAx-Dfj?JC`w?B25m7 z+!LCQbehr2m`yKVk`;DNo3lMvg}t&j5hbQuT^weDvgf&D3s0R$WZ- zpMf}RifrnNq55FGyPw-?86x5CP&P$3y0Sj#9VMl0zX}ezlSvouzNf>kc%KnK{`fW4 zj?SCxwanVO%ThLY^4NzQ+&c(SNqJZsU{|5~82|x25iq~Tc>co+y6Z!d2hul%U2P2v zY;_oJvAUfsJoybH1#HwED!GsPf$s)AMDNc(!yg%$SdwUc`=%!|fkD$($r{d3eB%Cn z(vb(*^xdntY4;uUX%xNPVutR^q!ziqE)r>(g`>GkDX!bZkLD99(-@ z;UhP8g*o(p?6L(e@B%-m8M(3Np+3*UfWtc+hF_R9B*O%H;BBx*rGW0M=qauV< zgUDkn=wH83W>h6&mxU3Ed`ErszEs$mu+*6wJl(XhJ?-J@xsuMghOUU0!*CUpBiiSX*BC5@W+!r=-fKwYoP4{ZYjtkuy}!pUPYXBNch>AS{~_0+65r4Hb%whw^+k% z7eu|PH4b6%2Zkj}f70RKU_drCH2TP*Y_UeSz(*bhxZVD^irCgdu0o1Q_ z{YH^b!cl4*em*oi6TnuczRRb72~abnkMzZ+wI>`M(<_8v8o2HqvAFzSLB3M-j8bKo z>|?Q<4u$}<6tdxHg1kla>ED=c1EMTE3wf6BD5_BHKq#slGSxiPG1ixCtVHm)F!1CK z5_#>9$y(tXDLK-{`x_;Yw~;pfnP%CL)V>PZR-MLi1D7-50nGTn#lSP`BCMzfi&(D} zl!kw;amwq7{ZGULl=$^iB%+MY`a7)VX*pvU{Wk^V2K8tqfmsjMhbLlp3c+5PA%$^B z5@m33?VYZQpl$Cph_KM(!^xJ__c7~5>Kh}g&peWO|3jbs(6E-iHqETCqp`LR8XX=` zJJPxVrY7X=56CJ(C<$n>Q2$k!LG*hoqvwfMN6RCw(ql7$o*c%1V+^2xF`0~f(9Qqz zlK@s{*GR{|LU3=E{)4-!aD^suIlzf+8z(jAYP|8z%D(Y`nM8!jif|YjSraD0P+zFS z{0_V7Uph=iQ7U&O(2O>a!!es!M?8n{fW2EXb9l5X^uO&ARV^#D7^Uk`(tmfLkE2$Ff`kH4Hj?|n-Lju`G|G;-C`{w%^L2xL6| zm&9KOK{o4UFw(J!KRVZ-P_mHyCqev&>FL12ABfeWW7{!1{1-!m72c7;Pyd&f*3~&h zTHfc7Nq9>rq)@2}yO{1zA(8kG8cg8#q&>5~r)2q!{Q%acfBlObF8SLB$v$?iH)GFdWrD}$0_+{sp1h0%VpIKJA*(^kdXGbW zDfsjA(8v6jZ@qv1J6Yu2R(Gk}79IhlP~%jeYG@U$BPztP|1bY}Sf6E|{lui02H&V% zbx8z-6ZqGE{(7qD{i(-4>6{(LMsIRo+x5OQ{15aP)0X;Ojo+XBCi7XliM$uD8`8~+ z-J$%srgFieg`_ z_5^W-$D*SQYor)?+RDYSVj7)uDs)Dl3Y-=`WWS20kSUIt&O>3GYYMP~t&m$I> zUv8Ma91un;S$xN(PK6veP@*@)s{Ez2zh5Rhk@3~uhjgK&4_e6M3{|P-^aDzhVv4L2 zrtBAAL7uPv8UAakzjBO&nwV}ZXn;~t=HzayO`JKWR}?KT4TjyjpG5tili0+-rc%kK ziBnWVnsq%>JS{3u8s%u|HLN8;a!xQY~!Vw!qPn$pm*7O-`wt42qg4>U_L zt)05#JtCL8ZFBk|T}levK@;-+;@3yy9BeOb7%u@(C&D>}vDy*+F!`@0DgOxT$&V_K z*r(AxY{FQrK@03@TT|+L^N+wxLxwDb5wE%ncXz$qLQa=~LC-2h40z@Um_*GbiccXH z&P2AjWI@}HoO#+EjN(+iuzV$-kf|!9Bc2I|GOYuHVmyV1$b!c3Jh8}fGKRrV$WDSX zM4l8iJ+>?+ zKhb&=-??k0c~g9ra5C+=DrCtNYF#o4E)MhV#*$a8FaV7diY-7}cre)}`N& zB*g*VG}FZ++@+&N!0SNFz-j-a-8X^Ns99@G2XCB9IWqtAD}tWd{cbZ~&zBgV*NohY zzaY+iGsPHAZ;G1tmgZHs3lN?5Cua*EN5P?@w%_f2e|{&n&eh*EZE2dL5!F8XqygEp zw%$rp*C)It+zNTjNq{nZc(N`oHdNRW^zFzSKr#WI*`-!4-E4G+3D@6>4wdmCZKYFy z>F&DJ6ZS z1Y_Bf?x7+2wuM~y`6LK?-xaiS1M(3uRtm)X+k^S;#@t+fKYASUN9H-Vv{H8Xkz2WU zUoiApp=iOd_>0$ps=D4^xBPq3hpq=U)=kvM*RnAsO?Edmc5 z?ET!yaCrmdlTgyvH*kW;*VGn)UxaY;mwDYp_?sLVJwg5o#1(I=qqt8G@RW&_%}@6P z*)^*PFTe8~r)${H*jJ}#{7~OAeB^}7Zhw=aE_i4v;}d$M^vLWR0*cm(_oD&5aOG;L55XZBqs~aHTo&y^B%W?v z)*pJUqz{Sf(r4@M&YZ2;o-|bWUY)<~zEZDNn|-VW()ZCB0Uxg`{eW~CrOeaAjQYf+ z)m+OPCo%%tq~&DMS@m{c;P{!O|Sk8pv17E|| zhYJ(0mpi}WH+-onc%ao%U#<0zy#ajcJp7Z6`?IwL@2w`Kg(`<<9OoON++UZCCKOyz zj~A7FMHo~#olskSbMk_L)H+uw2R~+vmLPduFMo6$qO}?FUOiJEfzc5vV)7x*yF?@T z@JD|;1v+dZu)AL8v&B@sjGpg9=)9kB75)gIHESg{`fTS%f=IGoIVBSOe*SvoJw3XR=AHL z>QTKnDM&nO$HF8TJ~7#`1oj1H3(k|IVB#j(&(cr>srb!p8JC*G)=@s*@dU@N+eaOL z8}ZCJ*&jUnb;-c;Zp7<$-RGBg6=bz;{`Ojs+wQ{ddE@!7)83Y-p?;~yZtcdS$}3@= zpZ3JFMjSprY2-Wk0VYZeIeI!E^A-E{;$&;j_dSe{aB=UKo5av^&Fr+SQf0?#=XvkG z9LM8;EXYzP5>uc?Hb5MGUB5#cV`FP;`UKgDL|IC*_3nQG0i-lG_D;$U zhX04Ow~VUuS@s5Tg1bv_cMb0Dx^Z`Rm*DR14#C~sgA?2d?he6WcK+wwyY5z%C-r97N2V|6)tTnVFr4nd`sWi37O?wop}NA!1?v7g1GJ z4k8vH-M>UtRlfnB|7i?-W@ZESWcl|S6rJpiRZLy985Kpv8C6X^T!0(^xfl7@A1Pf% zF%K6BmA^6o(w9(S2GaQ}P#|;vV}O5o`quzuP3_EGEQpvnn3?`VAZLDlXBQ_^Lt6w` z$%tftX56|syx(JO`Y1|Au7$kiTB}{4fi{_>3ba_ly^!@prKmD zm0bM{vW8BFmtku>?c(hlx=a}j7p8bmSqW8O*XnG?#R-r5oluvB$1=JM{Z%^Ha*+pX zGbszdsplE=%Vku0M8l6lQ55I;`|N#pN`a&cW z36dqjJMV&17%oHlJYR}@?-H|mT%vK*DVN3AVa7>)6WZG8mN}aW z-rF~KbDWzhhx&?S%d{hut#Nn2WZG^-=rq1q(a@h~js$Q}~kf;RfDg_6%OFoN|cBt?5MNWwO0T>Lp^UH;$m`F7i=!xTA*g>*q* z2$6B-sI{CF%4}hM3-Q7RBV2P#VoWe0IBdOlxd3(4Y*62-%fKSI1XmX(K!j`$Refof z!ND}+U-_0mYB=tduyDSrz(^Dnynyw|`c~=EtlN`v2L`pmvikayOot35i<%WxplK>M zEl9mRgj>eIyc-)qbv=K9JjO^?sv^D9R#RgZr?>hp{AL~uP3H_nG#~Ncce8JXWcui$ z@%HB($|P_UiCG`JJ-EZYU=Hj)iW~d>L*Pn@Uudf{edp z%+p_YG_Hf-`k}SP$e1wTVhk*Qf8C!ef!cI|@tveHruih;&}JTRNz!2DxTv4)w!wDf zfaevgpE_Q&mwy^oTq;}GHhGiAnArsRvzrM@IX;7|JgXh;{%-#J3C)o9I}$HKlZd$B zm$)>Ev2})vQA^C$Nv;{$^(g%4IJhEe5o*JNZwME3Yy-HM{jdNbWF2WVX$=)Zv_CBP zi2EU#n)2jm4M8y!(7j38Hnic0vl}wO#P_h5+V$40cb&p6@2fZgVIe(nihf+I_$ux9 zWM3)4D8mfXdRpa__P&)SDmYY0dkd*P&MJ2{WujUL{d@$mmM^Uz6#B_28xfvS$g?pg zB;phQ5Z)+tT%<8?tO2e*w*!Tu`s zTHo59jX-Wb`1SFaLe3W=^8{2SaHF~|c~-*6sy=HWQF7UN?aRvsnrRxxv7C%jZ~;P* zg@f5SC&2SXxB^d*=Eo!!(Z+y7h(d9^(z6}+4?*OIfUO~elLcK}%xxyk4vLC^ArN(P z3;}*c=xWVc{>`nNszLf_r615o#nasPqxip8zjN5u4As)tZzN82;ZaCxDxR_PLaLBh z4^;uE*xU_bB{1Zlj^dt1i^K!*898^=Smo}mq3TRTw)19h?IxI@m>};&SO@OeqK!Lq zYoFX9U7*j{$n9U$Tn675l^r+h73*Ndqu8bpTU|If322E9?cQ_sh42hU1iJ|C$WBX8 z!4{ucuh3kavMLNsOg9DU_U#PDWb4)mhKABEI@SqqvB%c*JI3+(h6RIyV5Mgo`1Yay z3@>0fsM_P<1Ni!(7+T^5F!~9)##qbJ*kr<=yVU#qrG`DaeVrJ)L{KxG7+q(ZxD|em- zXM;Y9Gpf)O6BzWR5WN7sga&p-71Sz3onEb6SXEk?T`iUhX$&+ie?&YVwuFLAx&;v? z-Uuv&JGLLnxT~dqoB$ym%%#o(z!&e4%V0JMlP~2AYql7aw6weGa6Jf2YT}*bWL4 zt<69iv`R*IcX#gE!xk;`d9y&>W@Wdoy{B$i{5Tu4neeyo<&$>H7@Uofwpo*2c}A=4 zRcSm__g-GmZ0Xpn#Q1%xhnp2smmQuxTjg|}xu(l6K1r|MA6^H_Bkj&dr!zS`;08vM zq@!Z%7flnH-6#tNG z8AW-k`ME!^&pi2r$4#iRz{Kt>6^+ZNerNL11cAfLX)&jG9-eCgcCsEB#Q(U_pI>VE z)LMUVx;mDC4O{J}w^M&{`c1*YVwyR(zC!#Z%xGUFG%>FKslfObe;eSAudJBt-e~2--i^I$*NB)B9DufU?9nw9v&Q|B&TrU$3{)w zz{S3VhC+o220<~ISt8GsvyeT(GD=A6?7)}cR_Qm~W;jKj%k>mLiq=72Qm76!tI)gs zepJ&bI4}lXP=VYQrcvPmAMshV9EMcMI5|1-goK=$nv#=~8?W^MDZq_QRMEr$dHXF& zd>etuDPu7aJc0-yakXFLVlygo2f6J2erxNs`qeqQQsyo*;ucb0!}QMA8^v-M5nm-E zB0@@2bCjEhhliVcNS{wbon2Yay6I97f;{pz8Br|)sY><-XE94y^Dn~dc9mY~evH}7 z7gaYw1h1mds8~aNrs@?(V;bk9>EQc&(#_3H_sb0w|A+5kq@}18EwBuk-mOVxk&Gv} z<3T;Aj5{Uz$^t*B^k*5_XCk>WLa?nhq|0X21KA3(O*pcH@N=$ zLDrO`mF?B1C;BkDJWrngocDZwbSNEW2c(qcjQi~HD#N$V^0UfzzEO+C+=rk1bKNIy zc~5Q6ty3;K0~yhPhP9EI&uM$3JNCj-PQPcyM&tJ24Z`f`{o^&B1sV!U_Ft`>#cpq> zO3rj2xkE!k?f$sdeCsm#^QVj!k5(H}>${oJWWn&iAs2#{KK?e*FVLIaRF!{YA(O^h zM(#WHp>}oYe}wEyrTu++div)$DxUpR$ylkuVlZS0`LM>!1PKsxpF=8a=}^=-=pm9Z z{l7($)PX9!bimhXzO>fFxwPN?VrREdnB&Y*TE&P-h3a<)2RBTCAOw^B6>&J71GPQ}SJ6*V;# z72HZ{}#2Fos;AJDOwFSm0lX^ELARA{oagz4jSR5V7X89*U{V~mYj$1ZcSNmlpdDuE*f z;03r;rBb=0=06?r{Wa3Gr4_n`{%qoAnuSuy;BM2S{qh?SxH zg%X0zFFy7Cs%Bq_1f&cc3*cMYRg=y0Z47pvuM@Sa`Cg6lCX@ETL9k z=-?I<@)IM8#H;I3>>RJ$Zj-Ocb&JSc*#Weon^^+B4QkBe0(2prGsEoHp z7yK|07?vq_o5N6J=WN}83^?5sMTzwzNKhUm+KhfSibGY&aCCHhe}5N&>O)9IHUmyM zg&FuG%D!7Cc-G?5QtT5-@HK==hSINJBUurKXd`^-<7CLf5K0vNnaHN7RWLm)eBG^; ze|Y_QjO)ujTb9pmB0cuOYn=i{tLk9(2xU#(+_Se^sc*|zORK$^3-5jp6hLp+_Y@G% zJmy~M=Hryfo=d{)K$fyF`ZLoyT_y><^#@0wQTBAx?OKfp&um7u%INoQww(pw{u}=` z)N!@ZdCzY%l(If=_2J>+D;Ov-pC67&8^wji$G5k)4Gj&-IB3R*TnuY=Wx9jwF=F-5do6bgOGk%@l0TiQ|rYOCBZZ82B)-ux4uyAnBra*%x!GRLVYzy&HZcddY ztcV0JEfZOvn}(5Go(ZcZ6%?3L_}$v64T==$AFK9qf0D$`ZVuamWtZ_*>8T(a8J^B@ z64B0TzEAcZ)TyST;=DT);RHHHjBY9XKs}l2Ux-bUE`|3G+#rtSA+fPt=+>aa@jEaA znT=?Yl61tx#C(5YRe!#Zy`+^*WplVrtFWdr>aAQq_;Yiw5g7TxxTr8EWbw~Yo!QNvXSS$T!A_lk*fD%MO{0CdPks=d0bxghaQJSY5f=OU|$M< zsZjI|^52g0x}9q%DJePM98$bAZ+@-bdYL)a)z%ZZeop22bmsRt?(uu~a&~T z5kmYABISHDVBno-lC>pGt->%@IO`51fw0ul($dq@%W7{wi02Cmz$FE4GzmysSaPS^ydFKK+= z?QZ7Ut%sm+1nwb0<1CUNA~InyzaVi#J+4T2&TP~hOL%#Cxw}8|1-yds@$qHTwd>!g zc9C;Il*n2tD=p$@V#?K^)V||}{P2ClNggf%hI*5hd;4oCY1$a|=D)naN#Z;fRZSuZ zynSP5cQr8hz2k7b^gB#8pAVWUf7e)1U+_0?I1kFMDcU(qfw}8@B5leoeUVC?q7q6;us6|Qwl**6vDeei+Dq^M-q>hDW%TLATlAlAYdo<1g$6Xv zn;q#ZD={}Wc`1;=-dOBwq)HS*ASxO7_Tpjz^fcU=_DXNHr;!d;$_v3aNIfht!HR;( zQgsxf84%WiwX)kWc$}yoiyzZ8HO~!=zAxz*|N7n7y_DLJhKWA?s+uL`$#n=OCZ>yUZhtef5uxwlB8La=9 zku1T%t7L@vJwJ^-Zqv$3jrp)QJjKnps9~hlX6JoA{&;(PJI}`N8M|KExVH798o4$e zao7sB$soOOaxZ=X|BRrMk8YKlf8 zfiiq!SW76zyN}x+jK+=*qKX(PB_pw5Kvf|4j49FVGV?G3nz}CSR6(pWy z|KYwrD2#%V@>7z?s(LC)fY#u|M2q3uoD10XB;kI^n!=YgChN-fu{cWUzF2_fwkwiy zD1;+eR-b}KjoU1?*@Cl-H1DCV_+bF}6)KB81#)vLCJGbssiO$KS{n-OE+t$w3I1WY z5>#~^TKt&8iV1e0#jh@gN(36m+gu3pIjfpzusAYnmZWIU<%D+kt1UE2`6_b7P-e~q zNsk{0RmmooEA`F>1_p+P#9LM6LZNdl=|2$4lTGZbm2kvkPwh&`&_b+|;$@R_gjtl_ zV8=vPsmahx%g|X?Y4tp+modaBU`-?bZ`J>^pxln4ky(I`c{}{&G&Pdc(@Aa9#ZU1< zsSN0hJ--vIIa!k~mZKmWde*Fpjb1`)>3=6GBv3UU3+AO$r;ReJM2wg6k5`^IDSr`S z;rX#|l1P`VbZk;Rq8<}08H%C$gS7T8m37Qjj zX)^pz_#yePpa#!{Z9c)#AU`tV5BOA|mf9ojg>Rxw)(Ws$a3WWYaegY8Dk0-y9yVADyR|inn0#1 z$ywAn&UCpdkub^o*a?@YO!7A(tSaM^0FQ-HL#I0Mz#`%HL#3drOV1mzbLL2_s0(R` zXGiR}uNjFdOAIBo3e}zO7=(s;W#!HnKGL^K^Qz}q&Qs0N0gVc zUumZb^G1MKNxEBk8c*)oYto?{8PTW*D%aOXM)RGM1uXKbaqj|VP~O^tBPO^rB)1xC zuz5STJVgeUKlY|FN=+OnnG4f!lRD=6PRX9EUS&$+r)53v!z)@|F>Fph6LAu%@}>p} zZpn{y$|$b;`$e6o`B4gofes2k@|o(N3uFGl8~O&MYDgnOH8t+p?xL5;gt?9&w#sE= z$rNI5CkVcBNM$3{imco`#lbNG*+NJZNj^%O*iY4MDCA0bFvA693FV{Z$-(!h8ME`< zWA6y$fH2~IQG!Ls5*6k=8?~@82smU7pvSRzbEGioBt8d8aPWu~aP?CQwe4qk`Ti zQUu8Wtud2UMPa}U&$1^VfH|nzV8Mz3fR!4-O}I%-Hc#X#+jM_mNeO2+;vTW~qhn`; z|68skTwcqmP#=8E+^Q-;p!%+YVCf>S4z4WoXzur>(>21uSx5F~8A>8D=Nwa=CyoJ~ z{QSS@JO#p8m-sJ~|0h=e-(p)@;c!zuS#9M<4M3XZ?BV6YWSq%Nm63`(V;PlpFkPuT zKiNdD+v@?CHXF+%hsWK{&MtPt(6Bh_K-k~k@Hv-sh3YiH&a5oi1eI=dbW|YiVWeg` zZ}k?veNb4b?0mm1+o@JoGtPyTr-UqtY{aVhC8=t&)^^)R|0}SCnZn`dD6`_K<2WCS zDc{`Gd2-_9e3^oNm&eWc9BR8fqQ7L#>B5*ur@o(`%GdTJb7dB_r%0cNDY^N*Gz|O% z(QXg}itQ~E@R)QAss!zVMS?Pc7MSXm`*HBHl8t~*qVs`eBGrRRTyz>e>M=4I&uVpT zOSTV}v@k;N?>gIE_d}F3{4CcF|B$}@l^PZf+Kf353o%cnd7N@WN^Ua@uszNdB*IM& zo=y??u8y=V#8(Zo6__`+V||>xd;IMqtbsHPWg%W2l1~zN7mn<%^OsU0D*ynn*XwmV zoPXc*ZXxuxn@<>hU2*O5zZ>eoI_d!)=3ZF)##5&#EypD?zRNL^h>zZaN)Go5uoGto^Noq625P&t0KLUQ{H#3zO%X(3=2_e6ahnrh! z@79Ou{q6eW=Zo34@(zZRz5}67H!tW#R`z$c5im&v75G_n@)tc&TnM>Cl1zvE&W5+s zBaN~=bC-_d*SOL}otc^2P_Sso6+i4eZw=}(d|X_TFrtsOZy)>HSC5-7hReO2e)`XT zJf1zQEo$W?)g3Q^#{y}CgNS@>>0=P$p=j|w8;V)?yxlOr$z z;UN-nfQIXGz182$EVQ?#T1WHsxx3T7X8wrBKjEl(MEMju3kKhJav;S8oQ6Du$NkdJ z+<^({VRdxm2;SHXjJi=XREUK$UpY~#sT#u+gQMasC07=`g5bX`pOc>;ixOsJLIjpx zi*E4bCnPqAkr;ICf7~eM`tOb6e>*POIhp^%&hY=-(QQ&r$T}0mKX=F0phAZYfkuLb zhK3Fa3KA|*q=Eno5#ITouSkUtfe3sgszd$)fe9NRXh4jt@zZyE0QeC$*nx)Y^?s(@ z>g${IA!SV(+kbp~JUSZnj+5Wv>$5>1eStTD3WBH?;f@TrLc`X=)&vYPfka(nervI4 zz_R(`G{-tu8X*0t$B=gSJV}UTU2S)z0reAnlVBDVKU@t0vY)1ISLBP5ni{s4W~${P zmgPb{fDP^*ZisXj)iE?SpTc4${73SdU8}Nmb#nnLCx=X6+ijhMP1m-ULLE$<7Xdow z2odU)J};FhG%~5YT1q%4)XYt;4i z9dnPO>$6J>OQ^s|2WvPr)l1#AlAB#Wyt*;Pgzmb|xK;ADO3Ul}G?I=?$E<7( zvwd5)RisOP^c5W=7`u+qY>iWK`}p~7*|mnct1UL=@cQ~>%a^UcGraViksak6r*K?4 zwG+mTw%De$2um`rDUaT`kEIjz?g~<~#!{qoY+k-HIZfjj$KW(X=gy=RQnjvc?l^oI zv}o7q>FvE5RYVUlY+H|calGBWRsfz&(EB-}_@DIeAD{pK=BW6OUiAMbKgGXJ1uz0E zO@N+w7OwwtQ?UG>y%a`9Bp~S-8JZfa>AyfkV{?L%qO!u$;`9aM319@tLW0Fahlj|? zN<4~9O-xMs1?43rztBx!z1 znz8EYN_z_kDGv75@8r$eDQjz$72MpN9o}BAFO>Tj7#N!J*=#s;T&5Ln<7_1-tkQH* zUS`voeC7<2EFQTG8crX9`yp^x^m+{o4L>YaZ!u^A)lkwk37W8}Iy_vE*i>gt6yW5` z_A70ctg|{3^xCZfe92d%dqr65{+zid2V~9!Naz_{yv-vi$^alDsslc*jWD6Ersxlu7t7PQK9y}+CjoKPScDRJ$CqrHYAzmrH3k=Zzr5_1*` z2?gbU|87J?L?zqnU41^a)&AY0nGYDkH)C?k`n{+3LEF0a!L+El<_ZU9Mpl4L6|l@B z-fFADj13QEEH^0|R$_6cYuwm2VsRx9Ig`h&>HQEH&~LzmT?sZAY^(g4jZp)&{B*W_ zXCYKOdUs6Up1Ly3;8q`{d*z@s6YM!4Y*<{UQdf5!ntA%(hjt&TC#MkIi|xY_D*+YM zZ%_qNg&GR89_+cBphYYDFqPFhJe>JDq#70`zImCy`5{>A{tqK+2I+Nj>6FdtE7Yt2}DTzF=0tVaw2=I>hJYx4+<^pF1x&2E4!!GESc78jdFDuCkKQvvh7_X-uRJzRoSot-1A8_k%j9UP4k{P8@{DHv1`m`V|l0HoKl zW#6+`(P@ZM{)+<>9Ua&+Y!KxO1Qay1goK2Cj}H!Fn0~L{`=5(-p!)_*&Aft!QAQ0O zD(L1UfKxtJAugszi&jxcCaDik|KK8zh8LZIF`GvprGoFhLWtEp6@%Q4@$aavM~xp4Bj== zd2gkvULu{y|Gc+aBYFW~&#p-|MgQ{h;+0j<1Kj_&vVx6;Cw7Dsa!t$ zm6ZmF*LToCXTgRa@rT#~yo& zhK7z#wr_h~Q(e=&nWc+IQ)5xm-nX;~HARQw{2!=^rI_mkFY89uR{Wo)PPZ=zA?#B= z#=PnXPsI!P8%=(9o|d*!%<)!Is}l(=##u?rl=cFl-nu(Sw@))j9Eqw~h{raLyL(7E z7S+X4#c?sv9CTQz`DWTl$sVra?6>p@Pd|OcJR!?_NobCwMJwLF!+#~9*9++S`Dol+ z{_cM9{K@w_=J65%8cYE^zBr7E3ES}nZqa7%7sa!~b21UjW_Q^#crlaIai~!r(JwHYimmB|$@D#)N=Npsdc7c) zihtTR(?NTG6EVqbwv9c03Kkg^WU-&@UKdKrUI9H@uW(C}Ac>)1PY*@wnWr-)oHF1+E{8LzJeyKL(v@Yk?4 z|5Rp6_qyLtXZq;w!!u0e-_8#|E@?~Pmo^3g>gqCtJ-pdD_T(CS7pFCLXgj60S+#eA zX=w*#mbpD9P-RlRh@#QmqzA9WUHrbUm-ySnVMpdo0hFbNWa;V_TqCbKz;D1p3(=_;+i}<1_`9E?II*z z)gx3KwslK4ucy~ZO2PSzh?=iCJJIq<+mT9vS)ZbI3_X#NFpCb?vNQ$HM6`!tD&#SKb(ea}l!df@&KI*Fawcoz?ZGCc5*2Bq; z;r?*=4hz)(_pc&}nOwfgZ|a(Es&c_7vaaNKCrZFfka<(iTGVganb{Q;ck#qc+N9o9 z>;U5DUbS-e+gnvNJqp{^^kpwTMzt=^nskRs7S_^Dkpt~T!p7^V^5g|^aEG~+6JXvp zZqk@r583Jy#x;&Jh1$e*|tcIT#v<8~`u zpx)CM-hJsd`DSWql9J4AoUK&Y>@v8&eeG})J1BN;4!}IN-WOx+R5mgBx7k3qcr01i)9tk@+3BnowT?0=ob4y!+1r#$a zJ~!ie@=L|UL;l2?OnDWzQnG(>L)9s8Kf-@famV{1OyHf*$JNb^DToAH*#d3Cc;(2xNh$(YYiEvn^&mY0;jYO9!Qs`hKPbs33~t z*lKm-Q7(%q=%w8lI>A#qHQv*Mt|YuPK$Sa1S!hHNifRlZo&y$v%9a zkMdKUskc>eJZUMS`Z3Kpd0Ns^e9|Ndb*3_9jNH!BCsXnrXg|T`#2eCeUA3lSe!4{x zhEOO>bBi>&SoZ@uad%TpVp^N&s01n3TeJBUi1qPLFq`iqJ+G}!Z*NBC5tkFb>zMTU z9h>?PU5mF;u5508japDO_6CA{Pi|7d_o1GJugy6O{UnX%vd9ZX!8fJH%Y*3eysW?0 zt>e`3ymoklm6RMnJAWWr^J%&|Sy)g#j|zk}f1Gpr2i7t$F!W%<@tu0JFf)Ue@wuL6 zRU{pq^ZCxY@x1=nxMag9Nu(coeomF~-v0{4-+8xwF=q7rzNhw8UJRCN0h1S%*gwB2 z;PPkp@>0$>;wuoJ#PwnQS+@@}6&$yo#VvErB)Qz0M%TN8lKqy#gwnN8;?s$-HZT6( zBoanhn|`VUh3%i^ztVl&>dz&y%2lE{w>#^CzP<>DB46ovTA(x}t~cS5=WTcyA_)*| z70vyuIyl4cHS0nFUaN8CCX3N9w~Tge_oLCT>6OUkAcg^a?;@QH?9w5gw8FAun%`$s zM)%nBL(QlrW_09oZm#o6r?#yBjCyy9iD2Q``*vA6#zAc6QtetPXJ3C3R_b@kVfj)} z4h4g1-PsY*(P_o$(OXz)-6_|ped8wvDQZH^ti^bKO7-JQ8&3l~&m??TA3Q5lbP#wO zj|jL1GK|HGz)=^#OkAw)(k(AZpW=w`>W=q_>&SOHPXuzQ(2uBxp|jJ$yGavv70mpN zAgd3v&_vmrx}shVpe0}3WFx<+-U#v3s>peiheBS_I-^bbL6Z05woU{P5qD5dA`aD5 zKYl5ZAX*rCIt$2a)c5FL9$7?MTdA`^5oM{PBd=o{?zO?0jjEuj-o>ynfbj-qH>D*8 zccO7=2Hw5tSON@MY_-taZk{4&w|1rd`S=6;2-I7ljpj`i)I@5~9^yjN@KQ1QY%QC_I zvaZ_cnN`agEPJ>!f)>5e=KERT@km#|E5>6!OnEN8|E4CLz-Y?hF(ihfQWtB9FkLlO zP#oZS(2R|yB9W{K;y$WW;eI^7lU*8-+LL1#pErYsta8rHE+o4bph0uyy86J}&Zne16QNMcac zy&V5Ro%3r{HKwxSS;wXlFWaUD_7DBg;WdKL#|vsm_s2Z?m1J_6B(DbVeG!@hcvJoD zU1`?ArDSl8xG&^yNPS1W;2N*Ax3RQDlG!L4!iTwvwLZP$3a4G4c$I=m2KUAZGzV|3 z>(`^+uE#%#$@Ez*m{?dxIlahOk8`w1dhc8N`rY3~AY9+475vUz+6Q;)W{$KQ-9+?0 zaN63^jiV|-QNG*SqY7MMt9?A5vF zZGB6%F7Kwu{}bglj2OP#%HEC##<@~#^R{-m|CG@=h4nbYmZ5%lOJdG(Ac+*GzTVy} zGK~`3CzcB}n4ZpEI0@zf_D$MODzC+ccj05?vbdgNIJY;FuQ?F&4=?*!>JY(cVo$lPh41M#1SF|B{s}m^U?Ktwz2%#->wGj^yRNdWNAr0^<{Z}` zD*B#PnqB3p&YQM{%pUpaLduV`J@$s~*4VG9+~x$ZiKe#!V$sN?plcp?toBmnY&yUh z0e~klS`?j44fi#Az$_>;R(PNvmte%zp)*XTSrfgwPIRpOzIlDS2#m?vTCL-FI4^H3 zDJgMuMAP%xF;6OcyX;IV?Pl>@OQxRR-R*f8fZLwt_w(60yPKbLOG{39%?vTdgC-d5 zH}Tu5mP@@~?fN()XT(!|IeaJ_sgff!q`<<_;e`aI2D0abc) zt17JK_2pnZ^cqV{2#;;|(N9zwQf8D?AM>w#4Cw{Is~OE7NM>LzcayfB?-IW&^+L5fT(YJ@Oz3V0P?jiG7koKPEPk$H zGg;-Lc;~jgccjRXVSc*{BI&il?B(5#d~0Us&s^bA3{VIHl&#p2Iys3y$CHOcEWvr} zfhQ!CU3H9)tcG4gBEAdu95*_!&R6L4z>HW$7~*Sc=^1ZEvK-3LdizXeEth33-j^cL zR{z2ybf;cWQn&n21l83bh3@Z){0uOi+`)os{J-y80l;dBr?V{bp)rSOYp`(;#Sca`<>#M88;vh}+#Z_B2En_;n>9&f! z&DMy5fM$R=5J|-P!T_PEf#C;xI@H|=d9qVl4OpzF3RGAwjE+-l*x&)(=vW5-{D%=r zPG^Bh0iSPo*E{eBfD4nu?4O-Z2OSd^w!LVGAv_`kISuw2E*qN8vNtfDlP#(0f3W|o znXnIj@*qa-U-wl`Fy5dDxZiV9f4Vg{wODc(>DUjxDuK5w8;V+CWi)wR=asLokG!UK z&%1^lKd#!5YZFSyvz&g3vt(kLEUYRVi{n?&X538B3^8F{5wNm)pFYM4B#3Vn%i?5_ z7o8^P_)frl%Z50f3Ok_7dU=eCIF9&(6llNn-!F|~I&hlt4T{|3;O!*oj5^XAEqX!$ zO3?_+&5Uz~RqKdKsYaGcGEFMa$T^`1=3gsWMWf*@jDNA0|1N@c$o+&}=rrA@z4^lU z6gf!Z(rk6bBDD^=K)_AK;C%NQ2`9cyRUj&(c50q*$M69`uNt_*!e!4HZ>J6 zLebkgw!N})Zfj$gY#8^U-Ot$b#og__tg^EeZ{r}=-CHxblTSCdOCViV%5u57<#*a< zx2`^8IInrRy_A-c|xS3yjw00V?DO&-MG8FPby z>0Sp1P8#l)rj4_+tFyCSO6T4Z&)X1Y;7dILC0FFN9rv^oARu{Eymvm=eY8PEw;>7DsTTX+gX8<2HjSU#Q< zvNV5zZQr^eerjg61(!}RUi00bVa3Hsbz@U22%AiDb?)ymjR&yTVS=AH$7*YmFH zh*Fghc_ubHX*swF5zC_=Yc4D_HhyUbjPVJ!T$JUnC2i~HFBXr%ZLT%9Mt}-ws;JuX zQGAP(rvq|>QcQ}DI#=QJvV2>6JOrk9t(Fv!4XZo6iO~-eNED6&#---kT)ZHJ3?USa z++Aa4nzPkFojN>n)k07IMPL8Mz(B)9noxPJ%*b?!Oo{j7 zfliOIc!zX{G;nAVO{5Zco0p}OY@y`mQUEDHxl+-eaHt&o8om>n6B-~5!e7Bab`kku zkn&<`D98z0D&m#~Lq}^V2WJ<5m$y4BK;~^imx{-%eRjd^c3aXn@=s^xD*it4}$eXS_PI<|qoB7_O?l=TR71OzuTLehIRP|IU2-`l8~lCe!z1p^e@_y*3s9G-INE^j_!WGyDYM$ zJSpgKYO`ML_qHSA+x#%EhjUIFk=@{48V$C`S?2g*JM^mx3RZkR%n*n_rtk9#x(BcFqAeT#Z za12q0FTFB5;x{2gPMESzOb0jsX{TbmAfE;zC!%lhq#agh))Pht5yu6*& z>i7DLy~kW&T@FWKZSy|g3F!5BA=Cs`B10e?+xvemBMEfjX-?95^0mR%2qUu*O^>ZF zZDZB6U>%$nc3TJkZRkl-^KtdKJ=z8ou&JRcgBDP9`C;_Cr@$=Z1bcQQHMqP^s+bQi zCcrBY>S9Xt?uTn?KrQR2oOqsPtV-3cjG>OQL0RpxXfZQd|2f{{uNETFz(X!?RP4ob z1QUwv0@b0f)4jzssMfDRIn?5eW^(}VsP?Aan2~N;IT6y)mZpOdd^3AuL@8YyFQfOh zSENqNNv%YjR0>-lqM5w_DCB9qp~bAMIO7eusYNy2AJ$lPdJG4qHuKIYOcRt-!@5T+ zQ~($zUh)^>Yvh`7adhPBz$eV5is~AS%Cw1W9XSGQAPpeGHZQSmvEm3b&Kyd!!YdCM zr3MH2s}jkKFQigbA9^|bL=d;(YOH!Z7T`$oNC#BE74ft`Gu4MQCg|*gI`9I}D1S9% zUR^*5mC^2=u2&*$;1`(ShO%xJd#V|*<|xTAu)BZ71bBC~E%1D+4TUVH-%xuaOatH7 z@%*bO)LE5;k|L9CNlq!=YLymV-G*ZQ>I?u^O&-RtI(i6=dj5L`HRBUz<)LHrU228$ z2J8ZWB4{W;!5y08L+8~t9$t3hh4$ux4!M~!0|uy?3}#gZZc3G(h38_O?09Ta-l!Ue zz%Wz2nB=dz877!fms!dLS9vYBI7lIL;@#6M`|VW@#fL*661}|sw4b7lk<4J%VA>&W zc9<^EH4p32{CQ{pfNI0dCBu!skPcQmeiPN{_HjPQ5Mj?g?^_%M0%ewqdU){%5L>|E zSmgDo{neB%FhIZBmq1`Xkbi+g@d9@1Mrz&1ZUX_ZYtl z_&%Sqw{eI5)%I4FzX0%I`(IT5KVZU#g@Nd}P5PZCu=08={WI4c*@Z5k@|tU9kA?|O zj>Z9lA3CUVmKm~U;K;xMgS)g(?Fk>gMtF3g+_AZv${eejv%Lb2x+OE8>kavDxvE}G zYKT&IPZB3pU=ITAxY%ok+{W|d_XEoFgMm*cW?IeTWFKJg&92F@IYvj0a9)#>mIYHTs?$o+hB82OLr@N z8U&hMbe%Uw`tZHtXr9B{I#6RfP5+GIe?HzhH|nn{7!#bPwG48ef94eS;Nb4! z*2}{))!E-KI4(J)4iZ~txVLnnQp=mBITU$MIN&v>Q;6{U!W&$PMgM7m&i^m8G}C!7 z4$@>%_GlvRS)KO%rn&E9M*%=mbpe9(tZ4aaG`s(VV#eT9lKXJT-lKS&dzQRlb3eF4 z>+kPS1hFxNJ^nD7E6uO(k@R!uPAj)$#FkLMCMV(lhzzaI720>+_wjww*9eS}=a;qF zu_5!PA_N(AW_LtAi&Ef(1{A0$nbm|A{8C6nCz9j84}BZPs%;l$*!c;y)*RbVKFQIy zxItC3!QXQ+t}&wx%M_AE|aR7bifT^5@ZKYo`krv$(|pP@OTo0`1`Xtv0Z7 zmfEVYYps{)(AHHil}y)EwJ4f~cn|F`Tn7P3Ah#0SdUID)uliXFrGg#?%%2}{0yDG7 z)GqdPd>p*mj?2f?2FvFlH?4N&TDmf_FhTnXrrSQKUTCI12RD5)ph15^)<+8>Pvm1+VF*!Shn^9jnuM% zn0h&T=Z~(`>_FhB8U)%wBC3LuwvP0aD2{SzMwbMI=?Z$jyRS1H`0lQu0(A;FaRWTyQsCYAiQQSQlGQ>+IcAJ55U;&h?eS1IR@d%D_jC$)3H7MRZ*ymtRK-a-B7aohyIbijC2y zW>K{c2s~QR2dymGrRbOiT)d@x9*uATHu)Vsv~!0$5=~a?ipNp z!Wy=z9JbLRQApgz-CVjy16<^IeySmLDb-w7!!SaqJ}f2hhs`hUoMIybZEQ5pAzVk2 zlNvFV`1exO;=(wC6}(+4MnL)G-f7?EmQ#mJa#m_(2aGLfjePY<+uF1Yp1$>AsoWT6 zOGBCseB`iJ4pUAhI>55%dtpUfuKAtJ>X8#OT)O{R7maX590{{TqWih5#SGj{Tjhey z!-cA&fC{=2b|_?h65T`UbnLGB{BgmLUyOC~`){AqJhofXXiWnG0$CI+IPcD``BG1u zRRLxCvs8Ao^Gc@7Iwt#82mH{3ivgP#2d6cN>nhHRp_KoOvqHQQbNvZN?OHMF5WpTI zt*$-UWQ7{xK9#M;c5beEAg+K_0(O4n(A@ajRKqMmk=VK&?&v@`Oix>dMWafpEcyRp z?=8dP+M0FIP6!Z!y9G(G;GuB~kl-4$ae_4N1h)i2aHnwzE{(f15Zv9}-QD4K)>?a? z{oMQQefBwj?)h=}(f!OhYu2nWYE+Fu&wAg%6p+$>Jj$zOnfJ;wndHVMd$*t)YXBM= zX2OufDeoc8S;k9MT(j$wIK0x&A|u7lR&y{ls&kh|U+h*L=MFgHrlICy0U^;Kf>6y#Y7JI$VwEhWpR6Op|d%?3&yT1qTx= zwdDR0>`dY0973|_a(?n?ZnP!6m_NFqB2DNd%M(_*=;Pos)g4iHo*o8z%za+2)U%%K z-ZsVE30c2USy3or35Ie(L5A9v4t=wO)e2Gxi}R>|!w30F93?SPx$#CfTeDm<`>*GD zb}AW?=#KTP}6t)Y(P4vJg1=KYMaTN$9`kp z^wEs=aXOSJrM@T7uJc~?-gwh$+X*U5LS-fzCf8U$FO`;8p6@gE(#*`cL0R4<-g?uh zM0`c>U6a%~Uw7CeDVw!CwC4}z@~}@ z%;O$2=%N#yO}Z&6nVlj4a9}~8XTpU4eAW*@b(A~Ce>%n4Vje7#JC(aW-}vd2o_Ls? zi7?N8yvtQmf5AR$J1ALI$`qu$XJRqyn~4q@6kUQEc&a)1=&anfKuykf^DU1HdWW~p zcBRNxRcrB&3yMK=ClyogWBA14pQ_(u{jAj32$0df`(@(nTK;*gb}T(CDJ)?|V186K zW3g3Bl8%ZOcqV_ju8`4@kW09TYVNm(SYqy`T5l@fsGXAT1Kr>29+mQI#%YNs7$dw4R7Q5GtVX|um)^e_z- z@SM?S3fix^;9Eb3xjB_!R7+LiuSZm)f)uxV$Wzx)_$37u@BkuiaDVas>$>3H!7cyGby+G`U-@mt9rbfUedK@3Sx4p zDrVoH`6z|P?|yK}zgkmawT|1!*Pm$?MX+*C080!5t8VtS@%gP-R@KKA6-+~K>L9cU z^so6GnNM~Hd_Y%jRg@D=`x8p8-<6}AC*+*J!Yt-xttwn}4C*~~i{>V4!Utl>25amI zW$`ohz$LxPFt>{3i4@(UkNLf=?{>NL=w_sYKO~?Iq*4emZVkzT6uex*z)h6>v+e#n z^X)0OkD!q4yF`*{-XS^J#^Rz(lmPdHxk6okd|g4KJv@I0@L+A*Q!z&`M#&)jM_sr{ zsxVE?F*mM{6+0)}we-zoVGa2=I2}jxMr{iIt1@HzNn^l94V}_5)Mxm;21M*ASjkl%CGTe!cIi%0?CYxmA9nfZp^a{`xB=|QI1_uZdBcc9o1+* zuD4`XqOTajF|8uX-DcgOpffdWdNqo8u4u;CQC>K9m5RLefA^0r`h6kIGlL!Z(XK?wF;cH%*JqYB0F8f^bgs=!RB5#SnB2 zOu0a1&i&!qI9ni;0Y1nR?O`=qhK3K%qw`XXIGCXnDKdq|i zGQvsjLyyO`xLHAA+4@9(fW2F;iz;>f8OQ0Q#;G~}=Wv^nZA4&f>`w;-W|JKmU3@_! zIx6X?5>yR*>lc6W833U1&%pnC`2VLtkoEf3t>$Gh?+iAt)kRh(3Y*$H(WPNu>xGjNw98@!A>#e+ zOtJx<<;f7GMQ|X)n4{!eanHZS#FBxW3G&i19N`g%0;?Z`wqZ6Ul~2Ay9B`YUg(?;r zW`lAo%Xf^V)aiPj3JUY(FU>0-#AaV_KqVS?$GZAMRAGGNTm#y5JoDP`?@RV5M^w+v zDP8T}%n=-NyQsE6+nh+yHLe_2RU2s5%S>#VNNO!()Z;W+>@2^uCX=-?v224|pu`Em zC|VuGm*$GRBYaFMg2m-0o~wQuuUW1Rhp)_!HD9^C(P{j6To43$FoU>ENYwMb(q*>F z8izhm`$xh9qRH|gu!Kq>cQ*lZ>75*eGZvPJ!BLaiJL&cx0^)sRKr3Olx+cjWdS!Ap ztE=jHL`ujzsSgZBs8YMU{L|(&} zWTQ~ybofgMH6&d@5<$T4z~w(LGx$;eNT!pzz+Y*6h zV+{rE_x)7YE70co*uWY8>lBKIRRwSF=4Kso@9Vlc3AG&-jfzbd&O1Z)k|UuHZt~g! z{l3@NYu?sg0X838oOX0voEANfV^r%6!-{!z<<@#K{b}dC*H)&CpXvSfdmsGN*|xPQ z;&Ixul|-@Hcl=^Nuw2@?e}uCOY8D??t5Lbs{9xl{L)gyrNU``hD-fU{^f0yQe+?86 zY3S0(Zdl)jH*YljpvLPcSuX+kgt$|^{m>3>9dG@nOVzod`$G}y!0yA9 zH)}xf4~_e&r`ruLL+yL}}{$=qG&HNA&k-3$FKqxWzV{Loo@9Xj9gu}u2P zYT(3tr|WX|X@+$vwz`-nYzb86{Qgpj#8Uf5%VG<8OiSK7q=tTEuxDwHc*jh3#3(+a zZtD1?)hhBI4qqoMrkk{;Y1~T~L*JLa|8<^q76!RLaJj!Mcuc}DQ3~37vGeA} znZW6Rux$y9H)i*G?_aJ#iPTBM4MHs&XD05h~Gbx6afzxWB`a^O0$DrcWg0K&zQK)VN zA<3gb^@Qev{l63ER^|%>94~&LRJuXEYUgIOt0?j=D%N_=ccue&vbw^y?Q(K!Y8R!p zw$0lc%sr7`l9qpkXb9ciK{9IJ_VnkRd3Z_;Du50g&-ja=PcN`kD3}#hmf83z}bl@{d_2>sg?cHDZ2yyQ^zusnzIEn zpTJgP|CaXLiW~M+5T;@VbD1ccK>U_^u&jIUm+G0^hgaw9@nBuwTWvqKUERHuuW(mq zKqp>zoLyf#hT<0{^j})|XRw|YW-^L^ILpGg?W>=r8y1HLw}ti3Ge)_=jbZgvVQt%v z7cnR*gtC(P1FGO4(x4KnhHCcDqk-Mi$+2KBF1kf$TI$k*;K;vagM3z1h| z>x9aJs5-UG>KS-#vUeB|yeKG?>s*jjMx(_G)Y z(@fNALk&$#6>gkw@6@9PcFTbyk z5e$pR)HvVc{fCGv|57keNGvJg#`P~9v$7{saTGcY zXS!EaheN44_4SydB3iaPeJ8%YnsZ6h6a0LfPnpLx`dcpbFuc2UKBk_{*E&|4S4)#J z-c7gXb3M*N_sLBM2yce3zK8qMnO8No&0=$5$F8U2!$&APX^FH}(#ArsSCyNKi@Ffs zD@L0~S6sgSV4Ly1Q1P{+TSdbP6^s$uR;6ttr&iwjR{(&A2`up!pzi@&7jNJFX#p?T4EC06b-&lQl*m?ga=-6aXPt+V2 zR^uL{EwwUL;)|7RxV+PrNSL9GMDHUVHX?lhf z^9k~q^w-RNolg<0n4yYg_uWu%qN(s2&!>;TPihsX%^dETQ9m@A7YdsS%WH!QNW6#> zlub17;v98o3ks;TOR9Q%1qwKc*i{eKb|)GniYAimE*NjuXK^)j#Hy0NC}^W3btvM4 z5}w!XW(~h%I%=08n{mC_7a(|QEYsqUCnw@R{q3g_gUA3{izLh`4cPsK;5+qw7>zJ1 zMRxA764y8gldScJaj5p_1<|u;TSbidad~sT{@nV@ijYrOwXbL=oH31ehX+vnL_+tI z`I4HtN;um(zE_wdVLxwtdOz!62u`O;_~E6HA@(Yts{*jzIpAziWL`Z9sbjDy4zi5+ zRR`P0@1QS~Gq>TL6bY9{x+@vca9GC=PNRN5cU%VUCo~&TXm4rtc=x;?o~_Y*#c5v3^^# z{3v{*nEn&d{MlTJ;aPFxI9`g`PK8YWfRfNpaMrW89O82rrvkn^L{X8cJGg8$*R+wm z*DZlYm_E?EObG-ACc4lhbZXSh#-F@2FQ( zUw->49=Q%#51gKFkJA~Z5zX|z8vrOthTSdu9Ad1#v;ipO941_Hw8*GK$)vBcwNE~{ncezrtL zxVEc-{sE$@!+AaDUJmujgD6S-qxyV{^m7hT?TV3j6QhDX`>8$~WLMkYIEc2-O(A>T zk62HprNC`cXyRJg(X8=qXA7I{7ZrUc49OSo-eX5&WDrCJG0my3h0+;l`|k;ozP|qQ z(B9x=jC}ZZlI9K*DCHO<+LnjZ#vd_Bub1#$L!ZZ*&B`q_$Q-UsTir^@M?zrobX}xrfeUZE$fW8&nZ1u zSrIy=CPKUj3(~B zaGVwY-eCprJ0Y7FMX9FCt!z~yQFVDcSu}_Jr9mVqA9pY!@rTqb-qvbE*r<_p#&-PC zwp${LW0F?;x@Ltw%<7$1CePOZNm))i96AEy`YVA-o#A8;w-(dq>p2;I6#`bf z`KPL9gmkd13>i4joA4`|R9LeQcVUQF>LY0L^Bce1m4*f6la!9PC^eO#JYsf~T*=~( z_$@_r61ZZXiK4`0-HmV4a~1KYmntq9qtKpM%Oite5WKcBtT?QSS@z2lnLZUW}8o`Pf4MT5qt0Qlxg%)15a-y>|L$LSPSA5 zj zgc|n~e9J%?lEd8Mi!XuMaZc=!X06oo(n+ykN(&^|Das(YY4?o1iV@q-JzN}az|tZ+ z-MyE75ch2(U(K#bnrMEG2Czu{wDK>PB>!W#f`3U}%*M{k#_=!a;QtvXz(3mt{LKl# z$?-p+*FdiS3VN-e0*7A9-Hjp}x>(L;DG1tF=_PWQ>4hP_UC(+znB9ygA%anE=R^G3D(r3sAhxy6wY$zIfD20ZuS+i@=8bRSx5+cb7qk1vEM z(83YdcMp>`2aT6U{QOuERq&0e{(zz1e~AB05<2)uwRyd%Q{Ic3X3N4e1xSb-zlZ1v=4}WDO}^i3LX*Cez>DEIUK)w15Jzu_I7DY|R%>K^ z1f@krj==xM#@5bme){{<(bDR|T*~0s^v!`JIQy8KygUJ+4if{6<-!2oH=UQyv*S~| zIC)R(q44rwj+Zg3*|*o)oB4kC{n?C&XA^|FlV&DI<|ZU8C5K-KxJrKr!j@%xh1Doo zGJ3}+wM0+Pf|Zn%egSEtdk&m1(a}T0!Up^M`-g^DnVFecSol)@FfxvhpZ6CkT1Gwel_0hPe$gPX`Yw-L90xEDWuPlCr=V^TqgyhjVeAW z!8O=+HypzsV&xAaKI&f1w0ke=MUNG?p5=gdj!dJB2S*zqeOC&h;0Jo$Qz+AS<;Z8f zkn~NI%}I^$!RA9GRc|HNJ;sm5R_(O({MOfLEMr)4F_>~&|FmdjWm=P9)z{a@$jErK z)U4-GhNF)1ViAc}oUWd)fhWv?=QT0$46%lvt(j#R*T@oqh2a^5mFlh2;b5WZCNgAt zcsWza&VFdH5tLPTpo!QMn?+V$nL0;W#%}P$d(Ox%6gTJXRi64|)*)lG;7bYYT=Pnr zMAS{g+rar<8K-@$gmS;~2T5R@0By$u4hc7Hd=Zb5@LN2~-Ycr~HmV4^8-2^ls^x?! zt1GXX_Uh)O5KIJVyQjyzp{xEaQmSTwjCNsc(R6G}ALC;mR=rNG!p}h?>sce-@XW~yd!>~|( z*wOUK+8q_ub%ZNtL+SnQ0sB+!jOoGN-r0=@FK^upuNdq$-My?s`@X zNbga}kDhgXghibu0PwF)@lRN^7&&LI3*}%(&02zt+2P7Gp zTH6TmUy(LBo%?T5?U4Gpym7N*R`|G;*%WRlV<}aq$`-wPz;m75hXC;)zn3XV_D@6} zg!3h1rqfZG`)Xq?@{j!`Rh)=-6d#uQ?z*oZ)0cqc;d-Jm2yXOVQ<7GIhuCxx7l_nn zbP7HW`|HvG71Q>nalj>fa4EiM`YNoQ*L!|0$YF1dum!ZW4&7AJ7g0>8e*Lk+aLUH3 zat&S`e5wa8)YXmG(MejARgkO_wW~YOMiCI)`)*{`vE;$m z$Vc|(p}|b)!Kh7kMP`cWx6R7g?8k>}`MaWgIQiC%*&;_eY@QCls@kTi}_G?Y=w-WYCpZza(WM^VuA7 zKS3(WS8U0!!ePM&#)Nh&_On}lu3ev;u^FCf#D<*mFUN}7lA7C7`AJaZPm=No&d47! zue!^S$sjH0ui>2Mx2|9t_t+QAFY73&lHjSKTxBEEK2!%Qa}~!>6itsOsvZ_dyU~_a zp;9-k2PnC}saej9G-9c}f6oT|AomN8d`Q{fK@wZhfD%hz8QzfW%ZfM19CFT{FD>nqx+xjE_UD!RJf=warpYHj8=-?OV2!%3T0 zZcgX>lf8$Z_Gc<)W@a*0M=Q2iost4G6IKtncE-#u_D*e$SuwjnE>;3h@;V&)>uw%D zOl@^&V4kp7A4F zUoO%x&;}{Q7vn&KwyLE1TADtQ6-A_bh=v)Y8byGJi}k$d*N0p`_WU@#vX6ZXjaYi7 z+-%&8m7ZD{RlGH!*EVH4L4)bcYewkF5$oh-F=ArgAUKZm7TlTB`c`6VaVLZB`@Arp zq_wegsJuJBOL8kHy@e`@1xL@V@)vNyQJP*OCM=d1MWuI;ITs{>qLoQ39iCUG7vd|S z9Q~b++`axMQPvwDcU))tr1$I}q<-Pa$1Pb?Xosp8s13EEHoevxZBzlL=B+;XV@O7N zb^M~>LUk_yp1%~qri6PZ`B36gH?7F|_u^LHz<^M~sm)6{DaD@dZpro`Z}jw=35rJ~ zi0jki!&%Qw7lML`vGFhd?Cd21h<5b_`tPYle&GeH#?C^b(~ow#URn2f_X?R^lXnY` zFGqxDDN4EVMWb;{I%(|I`+_@6FfSL>?q;9exOF3&b>H}eouvr6<{=QweH#$fy}6c# zrYNxT72*4Gs63C&8=%|Uy}540b2V6fsfOZ3fM^jgxm^}$hMX&zn$fuPIDv3K3c`GK z*|^8b{PEDpM;^NBt5rNX35!r*~w!h?J>xoLN1iA-;%VP!FKd)P~F0{$_1PrWKUj|^le0b(Q^zhR%Tb1M* zT^wqMD{zbtw3}iinWL6~vVN_!d@^j-Hq5Lo=CQ_6m8L;u{-LClcZ*{sq_Ux`oZstT zKxs(qKZ+Fbjar!M%!}xgOQl(MRy_BMkg|ckH!nrlc>Idss~t&#uD!yml@qtFhP{h& zW2U(3%=SBnWV#78X4c!v9_BMO=P&VzMV^X$%p-ktd}oT%S~P$OS+3bYYS z%$+s7|6slq31X0OA=f|RWIO++q%z~{0yY?-&N(V#ogvmeuCinPrZhf~hS~FydGIB3 z?@Jb4v~!$Hl+fCLRumiczrWSKgyiR2*-pGDAVyE(HYw39GambSRlc+|Iy!n99J9Y3 zC;rJ)JmkKqV{Cq50X=YMe;?-kq}ImS8O5eHY*f; zI+5e3(*Hq!q*qO@8|v}siK2I1r$c}5yL33Z!K>ddzS=pH8=Xsn2pd(4v2EO+V zt<+~WX*Ytqv9APvkp{I~iZMkJ@ar>td{vha|JD#&%`Nl+4p&$T*==0^F|k^1xg>TV8;E>6meFAZE@25Q>OEBrE*+YDy9VB?DLrG`L$U(K#q$SRH3q|DqmU*_T z>8nKnP;9qpv`NZ6ETF3#e2iHdbv0j9X_W^ZKY9}k`VU`_ciZ_ z)t9)HoBTpIMPpPFZzF{%OYJ8T4Z9TDI@(^73OW)!n|8`R*#)gI&!vQgD=DJO7jXr0 zk8eC~F`RU&x-2-}I!Qh<(Lq20(|x&BLz*Ng6-TAt1dfI{&I&Q{=f$B*bP*NQR7r;z5A1UY|C(d3y)xv2h$+qphtXW3=gg0kw}>JMc@S@ZysZ>Oo;d za&+qyqnXa`9oG%dSjy+!c$XfS?O_70cVd%6IIV=!SI-bvhgt_@`%qnRLKWfcY2tCD4Mqh5;TmNVLhHT=py$e!t}+SEP70ioj|))DCHqD0KUu@(foxM#%m+v zuvF}6u|kULore-6@I)r4DfBm41PINCy z`=zwbSg$~7ZfXNRz*+iKVz6Y(W(k`}v~?3*`XtROuh;IKjz`|q;;STX6!7=PVlwC7 zsC%OHwtm>&s*7lkZ1jEUlByVYrSqz;GQ}KTne_$g5n~@XwBm_jtpl8OFzc8v=1x6b z$xLe4ftPs|fI=Tag61^;BEs@>Sfct}DZ;b1#d5lnacSf0f}4*yD^PVKN~<|ABc^x) zh)G{s_Q%h7s@rF6c556?#f+y^LQXU&kr`mVwd7a)GAZ@RIg?$A8AiWdm3PXv&d{#! zO$kl%pX}J}8GW4E`>h6>Ei~0AH9E3g4NsM}NotPz>cE;`kYBqrMX?&!|ELi4ykUOn zFM-j?$rYmE_(gnt8m7BYgA8p?1;x^e)og$F00-Yr*T)Fj2<6cT@CxR>m~pBR5CJ0l z8XHJH&wkgSX~8vz_t?QU_X`oK=JgU1xCn&9UV{u+RFG7Lv_9W$dc2`AZO>Tn$+rE@ z8vFzG72JKYzdnqUn3+^oA%Bva`p}?zJ#zAJcXo9&q&%ca_0&CLNXViM-zYRzD{`{? zV6u8H$VQZ7-G?}5J?6kz%MiCADqL?F9l1DxpnM`d^&ouWX z)<8=PT@-Y(WiG89qe-UOwW!7KntpG59#~0yWtB7yM_->*nw~7Sp5JyQ4WW=9(sJ)0a1UzD>8kmX?;!xUcc2!N=m)(2}<`b5CQ7BQwtq zZM*nWEPwDj&oy>EegS5K^{QuE^_;&}3t?9NOsS7rJzpZfk9cYD(l(ALNSMAqO)c%# zKl@KMgk?E@q-XL@M*d+dfC6WpIJP46vEO3(W5m1h=?Tx~hC8pg)<$b5*OK5ClKt|% zRO2z`?NKzmuIAGxKkhIdZGs+r*jSMUPFom@K`r~Xd&sr1FnxJV8o!cD)n89IUGi7L zYve+WQe<+lV~mrOM$v z7IgZZhxRfDUyMIIHh(7DH9~4X2A6Kpr9Q(9Nbios&HiY5iwavtee?VKPprhpKN##4 z;rCdC>A>p-S4m{Dufrl;!$OIz`foT$7$=YLO-3YNz?K=2%q*<%KW5tPa`$R*;5=i! zHgEZ3#&R=~FD|^Us9pKRYDT{73_kK79JYYiIfL?NTl2P`ui=$PJ}wNxY8;TA9nWtL z+v4%?6O^g15^E!R;gVPiWJ<(v8G~g?$Q$?tB#i%^!)qi4_%6p?aCJ{L0v^}LBVxd5 ztka&wdd-@BubgonC=!VkOX1+&$(IE6ec`S^uFl(MlA?9B zxS5FWZkGtGZg}v{5qA;72a)p8M6g7gT?%`bsVH#HDyAw@YREAROMlDNi4Ao$hd6p` z?t1Ngu?a~hBo)CLqEW~IUI)`d4@fS*B!q@Oftw$_XL*hQVM}@=Prqh`B832TMk1P1 zPhX-79?GLLjSfcd-&aLfn?`?Aambd{h|N*TjgMl;!j9b5w7PgZ8Y1%iJ3#*T(r+Zo z-*1FoR1V#EIEN2ic6{ge=51DBeRJn>=n;-9XpFaaF}*vPiIun5;ymd8bITqPwu z*n&0>Wi@gVdMsVMNxMoy7}+|tz@HQ~G$lf;#J~2tkWC<)*N~F0S$JtN2UOVEmP|8) zI$aMez0dXcvdZWyQnQRr)-8i$!n(=K&&(HL#yOh=3U%{~vUSE={R>UKhD`vz!j9hg zM?2PeNP@8YJ%hei@3(_!NsKJ`w8aoD#YX0dimcfrgzsM{3>1HJHN${+q?F{-NG3H}>9yE^O!8TpBhtSN|aPP*gC7PJ=Z; zr`WsdR=Q5A*2!xl7!C!ZH=|$8YbCIL8#FBgo;=}!*MoiAK1by*$m03V_Ypx2E)-7I z_a^m^9IGHF6Z(r5C6-EIstMmm*un!jK4^d{k+_AVz?%Ok(0g>35I>B={3Mk_i;Gqd zg!t(MqbVfqrIUkxa%%7vy>|@*d1;ZQ5lw_DXxKzVxm3EPC6c=e{5{3R8`Cotd7UV!Jf-p|BB~_qCm^ zt?l`h2sq5A5DoAf0ivi#3^QT~WYJ5eLFdKSQlaB_dr1<+H;s53rTxqi$ zz7hRmcif!GNUv3auLQBU$44{`u~ z$Ma1IZk0~S5Zsu22V>J)7%*_8`?qPv*u*a&K&4!h{PljE^v%J6WqQQm)>OylrY1`q z-pqaheYA#DHo?_pbwegF3X(ouXy3UXtdqb`$T9UTwLrFgG0QA6QnXnmXHDVxZ#^e4 zH5)Rr`-Z*L+wz768tLqhVomDvc>MgN5TxuZP94PrBzJL~fhH z-|M)Cv)eVDRy#8qS}7*;@sJXq<>5&PYAkf93q?zZ>_W%o^3brw8yD-OBJuki(305sJ9lEhLQWH~c(@kl6L?lFq3I*|TWL8X z)j>pW{CI6GPDNc^Y)|25Vum$V2816F9b&Vt!NH%s^0Mg>1k&Kxd^E@jA>>)BbbkNo zrIT7w2&{;jmIhpAWhsyeROxj7ySI1F$BK$VV#H`nvVfN?;yBTLG+=6YfIMaZh1C^_ z8OG56^o}{0`dt*hYI+10t|5pvNk=Z5;NR5u7WdE2`g|2Ne_O}TA9apOZ;fukw9eWlwCCfyo^b*g-N=N3hHcJllD?@k@XKzaIK~;gk_S z8-Q@AJY3!EP+@;sb8okjKyw5-JhaoAq?L&Qra~3KxK(9HU$X3R3+Inqd1!#^y`Ht38hO1KF`jdy#G3);BOBjdz_;euRHnz(XbU0U zhn}7ACif@jIei*jkEie{XD8{!B_zl*fOioSowCJ{*IitaP4iWm)2`*a9+pi|oOO(} zRztSnKYCJyWWb|!AH5pX;hndzG-nYVhs^40?5XDJ-K@>hJiWx2tIYeCEWihz$N(+y zoc3)Qp5BCQ;nuhwvxcJp;V(?*;rf#lAJGfl`?Vg*03^xP_+FDll_>jlE<0 z4|~?SfN}|iS2ZGFz;C_sOWHJ+`_0q1e``UbmrsSJ`vAg8QeY#(vxBw``CQ8BwK;zUaN$C1L4Vv+-w2dR!$kLN5`~}So`KNE>ZXi01}A!YT(eSG zzauD4<8|6_hr2j_l$hlkdXWaqfOBv<6l6*-Ohm$Y-_S7p`X8Ql!>X(326n8 z=Ief?qybTtLW7gpPT#neI~Wpl)rZdzGK?)5;q$G&JQ4xlez$>`O+Pm=%rGl9;s^=g zTjXJpJ-3GEJ_igp*x6HWV{q?}yI;VE-^KlI^)An&6%YEieP^RFi$(XNPj6Eg$2Nz) zMzdc^P04ASgl)Vl?G;55$Gx0u&%1Eao_b3aNDG>2OFl6zoMWK!=K6Yz{n7Drg4eP# zIA|;_b)*urv#4gxM2HCVT>rjWA3S=Nd1N|LGNGAo<6Z>h>hUKavv9(Y$+Mk_zOh#vEeDQ>y#H*<77xqqcm5MA&4x0`e-IKUn>b=3(U_;kw?L9}JU>q9=o7E(Cta;l}#>IKj%&B*u_E5iNMOBCJzA5eP1SiWW^Xapf&*?GV zpQ0ACttlLb>svTPP|1q1Q!$Q9#KoT8A{q}*US1+sTwAd=)2Ex0IkI1{7&3s5! ztDM(AiODdAq|#Y++l!Zk%^zic4N1_VIGT+`Q4^nP^PtcW`D$pX({EP;f6=ms3^DVC z0rk8bo7#*?3qzWbHDJJ^`R3ZqLvWDKdgMuY)cy6Z@*yc)2$?NwSxGRo|A&DaFtoSO z>2m_tFJSQmXwxMxL-L{zlpq&Wk)JS^GhD@7p$(QU8T*(ew8w7T^w@mbNvEEm6m?1( zPpD#C<=a~+qMI=EL1;;zy{=dECIGpGImAqwtK1g>?6q4^TMb;X(Aw~1#GTE>lQ>_$ z<&}cG-AeuU8@-?Qb}*6xRgp4cp|bQ?jQJsCVitM*=6^Tj>Avd(BZ&s$>gA>QWc4}0 zszMkX)IV+gV#}yRj#WB3#iC!PM6~f7>=yHP6RuZ<(jJz(njiaCmM}j&c=$iutbBT4 zYp%Plew_OSoTF7Ij`p>r_A7M{-KTTbtpXl)$ZJR0)l8jT0&h~N+(Z6Rvm4CneLHuj z<9HP9?>*;&`s4m$d2EpN@wj5?!Hk1s3Z6KO=lU1=EKNTrOklwM6aMIaf8Ntm@_2oM z>3y2CEzvwL+^BgQiXg&vOxf61P1(T?_w7(%tZ!1K@?{7|K7{dL5qMzWqty{~w{b&CGD2 zmchAeA@(m;a7#yIhC|B6e0zVX{$)15P#&6Qwg~vcb!kmNsCT7SQ1AZzFQ6&J7~*=m z9_i@j=HYaCeSd$xx;nG5F_k&8;UbVI+o_Vn#!zwgN6TU^@C=7NMV?DLq0N0^u(9oy zO5}k@`sc3A{tBtu=6TCP1ExHvksL^k1QCI96wAJ6b3R-e39PGk+fd6P-NANR{TD%8^53@KrNYBW?&T(>TFByF9pB={;Y2=czL&S6z^6Czb2!P)=1(FWu3zo?fv3 z`Mk7ssmg3_1*i;)AOG*YbenCkebL5DcVf@cR4B~0++moJ zJGd+sJ`xxP7&37)o!MNq83OC->gZKF7pSIvJLKQYvDR8NjirnxuZ?{N9uVajHR;@6 zJgHf$bI^E~>_4Wv6Hp8+9KB%G>$5Sk2K$gEz?g0?@Z7kspjC*7miZPpL5|;|3oT!wp7J z?WCsVUr(01jj}O2y&Fj!_@_&f;(Lq)QsnR3`+XoIw|3Q@L-|To}y>TUL+&IM{&5>-G?-UXVbD6Ad_mSw* zX3zNB)z|(WkUh8#ju*WO{g%4m{S2!sGUMfT{OzP0|oWO?mMZ%mLPiIYSI>ge8#fe~^L)ePAw#VNhRVGkBO)`~_8ffs=Z z@G`6HA6LL5-XJ+l!@mYMe2`(2KAG0Uh=RWwxgj$)GiI**u>}e8{as`unqktPF%8dN zpTJID@Ui*|G6N6bE#$vXX2wzO!$P0f5hmgPO#T-U`riuUe}r=XJyJOUzdJdh{n2#c zh49L(ii)nStz1IFAr{tV@=%tpwGks=4t$9heFg1@waey4tEz1t>()3N+2+gK+Qpzv z#NA&KxRxSevYzewt!Cj=S(^#NJt92Qj?Oi+niKVd}U3GjxDCX%h zQ8nizC`GRp9g@xuAQ&rz2R=N`wDp>u7#(V-LNi<<9(X=??D;V@{Mxx0iLx1yO=3g< z1jC~xiD)54+JGY^p4+B)p?BZ;Ie##=0N@n}2i)TL`fL5FWcJ8$*3 zv#RUQUUv7TtleDh$~cga{Y{dJ`=U*kmwU@n;*}L1H=U~R9S1aIp<}x6I?(m*(!B-+9Aih?FlnJF*zF=OsZI3oA6jqL|wW;IF(IAU9G5d@qcYhQ(2+O0@z>AH!ak!yk z_iKZ@M9&ZP{OQ8Viy`B~1eWfdncwiP>J5+cB3)dA94@DvIw->~Q}t(hRX&vW6g#wa zFygx5Ks?&$Hd7auNC8ed6}{_!O$~H8N(s>%95a%W{okd%cMGl;+!O9+NA<23MV?L# z5^Fw?iebp#+Igkbn^dqbRJ8b?Z1L5^#9i<+5eRg{;#L&|Nk{D z!zpmQ6>w+BJBOghWY;XRP7a(gsI^}WC!e^v-KMYo8cuz9n!5C&xkj z{b3otf&uI!upqzzSpVt4BoHXTwS0sL+djL>#?!N@S;!m8XxQ_WJ#MFRlT zQHvTgeZSkVPFO8?23ayn%T(_(&E0ukOn3htUXCauv4wlKl;HONVec)&>gu*cO+o@B zNC*V?;O?%05ZqmYvvGGPKuBTmAvha%cL?sTy~y{Sx>e_%>aKgM@6&%ef5_fU z8FQ{7bMee~43adB0aXgCT7LY;_}qidZNx?0z8tsvH~=9-`=s^#G5F;2?MW@Pds3Zq zgq6LA$JpP)ORjt-oK+FtJJ!(PXcTN5lr!o6$HWf|(OmQ_Y!`F?Xe!b$!1@Ii3Q8e( zm$`^=Y7FaHKpR0vpdeWdE9~=HzsPABQB{Jwe*&8J6~P7@{V}L zY*(w!^O~)Q~kL z*<-U~bR_PweIERHC#!LwXrvi*uC%$K;@I=08*w+BgOL0N)4f97-DaZd8vTgrKYCK^Ikh&IZ5MnJq|q}_ooO^AaDqwPQI;&y8f z`9B{;_*l%U*IwQ2Rz&(_w13Ed!ImzmX#QY{5&(m}h8ElJ(9IH#0mCa6WK)dE|Iv+Q#Q{ zeC3C!#ukAq_sOgnX8{4YdC~=vLNO4(JZ5?mm(e!Z-16zoZ*3e_>mwp`Jr55Bh4t=~ z3!fJRUmsEdd8K_Wep?K(iJn04H&S9dbmwNqD8Xr7 zMjnP`oB6xlBnZ}b+*Ilpeb#OVkGCtkcuPUSbRo`@=P{?jXkq)^!?A^&pJm}6fxbe1 zg4it!-3oEMt9kp>s?CnQ1bA^LbTyM5$;ajFI|$=t45FM9CXvmZn6&RUOXu|N4%1lY zB-SiF^+}v%yf0^Wcxw5H-&C8~cngO0Be|z-?{`4QF*#u`pY^elyT++&t4o42G&myX z#H|PFo17>glf>HR!YoPmn2XJo?xO)V8$OKQ{=q!6_JHCL(5_3WVMbd&qww3zY5TxF zN}~}^17fnGu|A~nA3}>USEO351ssPi^T(;W*)n2ChyIK5`3)!8#;l={OOFHRN#CBe z+vtVhYRIc~?2xCoxvi=1<|M|JR$1Cx2>GAxe>5rl*ynU*ICRm>zk!=oP3Xk0Hk--w zIM?KNU1-@8Xb;tPyR*$481pi9r&h^{!`-?fv-;*VHBBhmY{^Sab~qLt$Ol7TmmWU}sq?LYGWlikH)1udVR`8Rh`;F(Vcx9`(A?&7qu%G^b zv-=K6Fm{AtrYa?YEi60{ouTRBN)|-*q}qQZTJn2}fQ+1}+Dt7P_xp9(L4O^1!K~u>D_WcV5K_NeC4C%w@(T7%NSwan273Bi;@%5n0mv zMEF#eh8^2^IO9qZfa7o;amp@V6P3rO8BvMK8-|k}@v!Q7JNd!OL#cp<70*z0(tJRG3R027QoJrG zwP_491@@bz&=xC3u-4v^yMBY-qj3FMKs}G^$T87tPp)hAoFof3n|MF+PDR^q>RhcA zYBy`ec)&%=5dOS3e{3jdHDk0duwq?+!vb*CyV2kgZzh<{wr?Fr7{7vLY_Zux6S7d0 zIjWhu@wdK>`DP_EYf=ZA#$}Y+ZhhUx+s|~hR zcMo}<5R0|(G5{CQ($dn==LSs1DmTfeqN{5J2@^vkgCj>a05d+LX0?97r_9x$yl5eM zP({Mj-l#LtqHOZ0jl#8W$}c5xs9vdyVo7!aM=mwu_JL;4mxFPYZurC9Q6k zG+ot+-OM6%hFX3c6EFR6Kb19G6$(lTj>=9m$|CxW#R;U~xNXcx5)FgmYr%rpzVK^z zTC*@|cRxR(iyijC?lMW?d01*o;-jr+2l=xCtA3z&TN7csF)GC~M{!$#Q>>M9nGDhC z@f-#PcIP$MbrDdGCJ$d>A)O~v1U2d*dN>g#*n~#hhSAXX5C_Nb3oJ3hea@-T+x~`;BeZ zmC5p9uM}YMf_)%}ukxaE4k{%d+1xhRTZ(yzwd&!+>%YX!XF_jpZ?d~lg-R+)JUQu| z*G)uL$#%ig^eVCb|>%%@DFl`gM!+@1-~k zlGrx1u=MN5Qr@TwbF%PO>K?L|WP!!SAX*K!`ZkBKk4Rc<^>NHAYKULDuRNFyMpdGK zW56Ubc906vAw#cxL%XNAjND(d`~;<*hZxb0%_byxWfexQ(uw?Ylh4DTdrc>>YZHO9 z(<^3hE*OLQ*M5?76ppup!wKD~ho*a3_@8(M!~zD;&k7SQ@)?2h-wuvL8NsPwfrj6V zm>N7hl?cN}cNIof^t1&PXJR?Oy%(E<`O+@y8RB(3V*g`zBNr0~JN^CZVI)oGG~)Rn z=6ARA#p(BPHrIiXUvld+R%S-jkp z)o6jj;5ZDDj6Upt3-W+?o%I6;jmtUwz#%Y#cS1$&`FsOK`=eU)++Jm5813xj#VGf3mi)wo|mxGXU}O zGJLXUCt~`Gu=|%({(qaqe_rK(B=Ol;*#89u`0wjfC#%letqZ^Nyiz^S67C9etm)Lu zFQ2G{f$6*xJ|UW47Z#4JjA{;UGdOE^xZ1JZH^iij3fdauZ0W7M)H1fsSo73|Z+$@!#njKjOb*wLqj zw5Hlh@~N1yr{&$jQdpCS>M)z$1=jdoZ-l+u5`p5#I?Px&jAPVcb@m=D==Lm(7%*2>Wl9tz zFv$#VE!BU+f*Thbq{MUDLg|<|clwOf%8p8|u{gW)Qv4&DkT&zpN2gXEe=j0rs)1Kx z)(~UM1+bHoU3y|SIjy#-u@TWotyB5g$GlI%$1UpIS_FPMr{A^F7+Ey~GtgeV6vwJ9 zxsCi>C6=qa{MFSL=i6m|BiDr3{o8#RT)_x5Hiu zQn^!ZcT)}c26($=3-j$*zP9lRYmEF_D9F?aOwHc9rmo zq8pGFeHFtK@pTvq?0%%UW#VHNpZJo`k6yd77ILP;ccZk3Ka^x07Z1B8Q&bFJk((v! z*42`&JFVopB_>a#jp^h_Q=T|Pqx+vJ32jPFu719G9Jch6bVsAWL-M!Aoo%Z_;z5&K zza~6bi~SUKkm+KD=|9zX+N^~(M_){hNtw_1G?|2(czefEo^$Mx|>1qz{;3!ECCFXm=7mC)QnIj@6WbsX2L;>t52NS#m zqxns$%S7H)2GB_-YW8pSWU@n}7pPu(^vKzTDQns$ig$yedK}QV+MV1BoLjsn22043 zSZg}r`qnWPzRe!8@m-@ zfNugbWk&RHWfvoi*Mr}rN`*TE~H?0Ku zI$yAa7pg7G$muAtNu4n?Img%KycpyO1heXod=q8RckysmD^uQ1De{-bn`M@pC{>O2 zI(s?8WlIa%Eyx-_WM78jB3$#p)Ih(-I>aXW75wI6%a8sN2{l8$UbjbO znaaREiqc6D?)TZe@l}b!&e`PBnx^}QJ-*e2tsS8p53q6AL}X1UpP?H2Ysts#H+uKn z-g!?cD|pxTFcI4v9aHZwbSr{|-i)(VnnSHbR_2wpVXpsHUF(x3$otUQRb5)~9ii62 zN~a~72HizY+KrS`qH}7@=mEL!DGhl7PEK6&tm-acl-Lm@alArs|!$x_SO`yYG*s7=PGDEv~VptP7 zQjkU9o-YGvc^ajs;lGTr&vERpDDtn-ayDjm=6?}X{y#&@vC&b^CnPQ=UXrB81XBj2 zj>@;|WfD{n6LDb2BP2CI+Z#B@jR?LI{D}Zh*`K}KGPTd=K5SvdE*jQ1cVk$2snND< z{V+9W{?uC4)BVc;)oH(1@0s;p_j>~=!}7e5UG*Q2tx+w*0_tY_wX404Kn@TKnF>Jl zlP|k!cenGO{i}ZWzQ+1z^j8Ydf++qXG4W09qF5=eH)dw1v&UKD3qWyZfE|}0!UH-3 zFnC?&$VU)7LXC4^XGmCxJMV|Qv()w#qvu%-q(AZ#5l5g>v%bU3N37o3MPHwpsUF7k zm41+ZTlWVU7p9_|1mSU3sH~vB-#9&ro`!FJ?(rJl5XP2>>8Ii4tp{?F71udi%Ae-X zg!wv-+ts0`iz6njo~-|OSgPqSeum$Q!hVF_`nQAq`@sHzTXnDeVMX9H|A{bX*L=Fr zp#MHKRXShS#KW_%1=dcQ+;cd;x?Io#@?|KhUa%dUX#d$51|kgpquv3?O$~5acZ}#= z@O0PmKq@c1kp@F4tQq3-cM<6FpyJD>61u}iT=qyDEdwvF)=`uFot-zZejObh>+9>o zX#!~}DV}FrgLhX)0C6s(oLoZLM*A0GehU!hsUB=hk9H;hMwtH$_U)+3fjPtMH!>S; zwiuCF9+P293Affo`zOMjWA3wrBu!;iRR*(4(d6$lq(6kYjI{LNAIN-oaL|=EH7qPF zIl0+4D=#PP&zf}7(R>~wM>_IOJT7OCD1)*9a1seR$HmR$sdLqDINXCz(ZLYH-~~(0 zMkZU6Gro)=iRb2iYaelQLRc35cNs6M)pDsi|HkYcS_9YrbVz9-}KS zdvqCfl}d(&Ap%s~&st)zxT;Lf$n5g;28*~2EkIIb>ka&zU(^Tqzu5NF{pGujp8}~y zN8WCXJW}-eeZoV6RNEP!fGS_l_$Cv!Jjf!fsov76hNF(#YRSUl`l#eGS0-=p2B?Sb z@9*E$)z$DDVb$N}TFb@5p&2sKWt%*IFf=Rx_O8aGAG8d^xSiiJv1&O63H|CGgkdZ3 z$U~*U@lY~*YdKqg;mcYlZ5v@BJ|{2P6Ik*F_q|iv1AT}Cgh*zD2Y@>1bK%30Y4I zcN;}5*GLGMhA?$#^7=M`VBqn1f1AStvLhfUWB*`z9cao@Z-x6swM@H7!M>!Rw9kERiK3iq) z_V3G}bEk%!&$Yg(H;y_Ng|{*`&JoVg0?V!P z7UhP44p_?M64Xa(q=PZ6n(&+vp@8@~7Xtv7^0muEH+5_rvR)|bi~-k~Ca0#12>9B3 zzO+f-K=$|d2PXD7SP*0hq|fITeLfPQ!N1!LC|y^f!`H^trP#t4+O+7S}~?D>GWNF<}STT~1pcfw6vr=zz^$?Cln z%waMt9)xCDWK$H8Q7j6Ov`i_#=;{XCNLpKCMFoJ3-r zip~_ZCkdn0`ea3|W48P4n=8~;gZri9 zrq;q?iu<&zE<#)CYm(s@O1VvfRAfzKqm>_CwCpd~!8%5jvnFPo2h81eak{WN-ngt4 zi0%dm(i2~+R7CH63q28s&N+7ZL_e*|s}LAS=#S~a)tU{L-_NU*g%s9 z^tal7W)&1rZ4d2?FRLh}I$r{S`6K|Cr?h~xs5bo9pgm+S_;1og+N!RaQr=|xRP(Kv zQAv`M4Sm;K>y5*7A3-<0!z;~sd3q6nJf?IFbMPBiQ$h}If9OSCZ1bt9+mB#b2Ch2% z6xNBiQt~u~^Ju2gAu!%y>@R+LG$Vw@mmb|&ja(OLcRzDhfi%=s%XNwF{Qm-c}} zG#oY4UzmO3E^9CJ6LQFqnQ(5R%H7qdc5F2~!w61ZWbm!*HjFz+nS#l^eEQ5Rd&~ctK}z&yq_>%{ z`yGL$1{Kv7(hCENGrQM9a)>f|ML_(I>N?@x^K@xmIyrP}DQ>A1Z!RsTsug6 z*bi~WvjZJZ(I$y)q@K~_FE~gS%{tUBnuM?+Pj!Ls^mmg=*X*vP47V0M$ z+KQh~KcA$Jin>y^)hdUbMDos(P?DEO!e=rVi~b;(SblypUBtTw+Z{+-lWc^K$tOQVuPk!h z(0?f%X!KLDo_DJ(A}NrH8AC5;dPYaP`*JXUNm53Qj-bhELtztz#Qja~I$zKFkR7L@ zmTrp`rSocK{fCsP@B(brhU+i1la4a%sxa;t9;QyI?>fttGavRP>vE|Tvkz$w(yEOE zI5h*X-hQN_ZYyrnrtcwEBL4%@2JL=O>aIJM^$9`r(bl&qz{DAZy%YiolVZWI5i50* zaJV#on4J$eOM5z9;z3|xFP?YU8Ot#+9wsAeIq$DmZR2>HW(Z>xG;ckNUgqYrBSn4l z3Ytc>gv;rk706;;F{=0jsOznYQ|5)fRJpiwO^H6aGGP|&@=5E^yA;*>i~qD%p7oE7 zVLJuaF25EJvjeeG+RNRDDf-z|mya>fnk`>28@tIt4>>$z(RqiAY0E5=h8ilpI<7{F zVaGP6H7V+oWrgWP$-ng&|4sn__w^UCieE#lb_#(Q#|BpJ1%!S_t3+%(ZyA~!wmb1_O5nCj=z^4gcz-ir8;PP zksb6zyr>#CZ;;ktS8=mlR!U9I`9aDg6f>?bP_LExZM*_|eMq6#5KX|`NxW*c31qww zF@yz9$7$jPOs3(wDu6!JT0YMz__7YUA;ro<45JSYqwa(0@VkC@X+(~6wCT3vSglA{ z;0V4~V9-Mmrg;Kf>8XrQnRZic;JdDp{IZ0Kb@4 zI5z@kG#PyGbQVDTht)Xmrxwm(QY7OT5dRv`=ZDt0(7$gNm$smPWgw3cre_%?4XOGd z^l6~`#dv1fQnS8+ZUL1`ODQ=?F(NIk&1SMYI~&EI`_XIy(uT)&E1D(x zu(HV{K)`dDMXDYB#Z&y261E71RmsK*X0_o<;q&H*{xCgq20B34!>ef1uCq-lROqSW8WJnfImeR z;$7-B6rJXNF})XYRIVV(^E9btWO4D=G_!MEq->wqj|%5fFD6Dk0LXte7zSD|foG<9 z$Ca((QV$OLdkaW*tsr*bSozFfszbG+_v2hGM1>%PxlHX>O#EvkCeibk-`BfM_rIua zh>qqN zDE%+KT<{-!`P*l{{NSCh-QC;2`SL~kvb^8gb-xw~oLuXYp84{-QloK_?Wup_%NMiM zQHSvtJI{t9j+oYxUgY#Hc^!(aPWk|UMmp{HMwXC2pQ9BM=^AK2uUhh;H5&2<5(h#^ z^nSgtMWG&_n3yHj06IPYtWtySP$k#6I zs)%DtQ{>-7)+elEs!T|MD&Ld7K0pSZc5ftD3V;g_pm^Q+SuvrK=ItM#+;>|!H+^N| zI}#Vbe7`yo{#tB8JwESD_0A+{{si#mhy?#TA5V~! zwzfyZfs)~m)~?4Z?H$2}^1H;D4B0OI=r-ee!7b|DI!XKhEis!VY;dB`ySh7 zuRsF|+cnOiE&uNPtD%%Q78YkCWAN;v%UKA4dKHWDR;v9p_i(C@Xlz5h3zatqca_vc zLeCGp9@`#!!X0r6>-wqz5&b?70kqgZFL_;RdW2~8(jtl zQIPCjV9^E*Fc&^}IqY8QYHoEFfT_<;H)(E~MjJq=L8F8Z%NM|%Dh*MkGso{Zw;sKV zB!^o)J%?_Dn=88J*Nq*TNe#_dDdtr19VKv>7jhVe#P8o5L>>pYefmYAp)*h$nXPFRKR;!dyv{)%c$KRD-y0=HPTPN5NLn6xvz0vKC z5s+BoKH%<0xNPGGm*n+z`94@fr0zlYLqnshB{kDt5}mm#vc#F0PrKr~O@}fdOR&At6t9xk1hL&hA9=IV~Kn zRY_GLhe40BCq_;D$;+z2op*W-Ep;oj(X|7qqardNE`xmpQJG@Zb3e8~jZnaAY^4ly zC~X`}U4G1zP=s-sXEut-pUjgIaOnB0Ch{AxGX|I8@b)A+t5mzI7|Z(Tl4Bz~!#)iB z78=J&Lw7VL;O7&W@sZ-B4!G5+r53nEp6g-X{b4|xS#@>D_qM?Ozz*3OJd`w~iy?(fcBYFon; z)5?Re>xd_WvSgo-hprT>?Hl;!7={9+e4Mtb+F`W3dEtw?`WG#& zR=11O+uPXC(2K#r(2^2qV2W^Bt-279k^GXY9C&{Sq7HB!T`teLLAukJ>N2`_=9ur;`%U$_RoplRFfr? z^>AknH#3LM3+v9@SjLa^c>?4*Ykd3@<)jg~giU*%F)SK|2Su9f2|+j{FYpoI?H1hL zmGx8*!6hh6(XZlv{qdbZts7I?hW9Qb-Xz=EsTeeXW>6iaGT;aI6b%-CI98FKG(Q!z z4*!n7SLQHjy=Wjr?DJ*95xe-M*$Gv*CS@b8_d?W1tLER(_ND965`rEbNCXzQFEp5@ zf;I+nWUJYTwM6z3F>@6pk_}0rpgcR(wnAk~3sst%?d+e;^`x)nP+f#dM4Bn%3u@5p z(h|L4!m-;7T{LFO_K(JRQ0CWfpcuAYA-+>28P2vD0**H^p;yKc4({RINRaf%2>%@T zlOYF*3aLs|sIOjto~8h!85tNXa(7X7y9{*je!-yFm=QQyteKsQOK;bNqnqa;b@oC4f%RqiccO5m_&v z7mz@F{tyfcwT%G$%IDvk|34XWaK*sP8vrBSx&?e6E{`n?VBO~g|4T;ypLh(w&usg# zO$H4Qm%b$}tQPPp{|?CE7G5FsaJ{Rmnd^1W{KxNfGkd!{Rho4f50^Z*TW)JREmt!# zD|NE5stnh0`^#8=I(MsW)tpEcqNhC`<@gB4UTUP#vbef*&+=L3<7-b~mK?C=_0(Fn zG3)B9&~3JcS>Xx8`;y?-%o@ zm^GN>Ws{skO}Gy$)O!zG+>Hzi|1wgfVRF?zojMNii?69HES{GYo(u)#yvO;>Wm+w% zZMc&f-O}eCR0L5Hc~&=dfWfaCanx-kb|XZ^uB(P@s?`sboZ#$6DQ)}cbdMV zG_F>fSFN*PMrRX&9^1O0;l}ISv!(6TbN11SD(e00ccx}IWF!Jn4}$(0mXN~r6un9! zu)xuL)HR&?I2bDU8U6bFXlZU{W?(rqjP7hFP?l^e7S)q0`vYR{WzM6MVkrxjy z11akHCr7?n4dXS%kUBXBj>md3p9Pm;n5{28Nin|H-8RR%=ORLJJjPBz!p(74{*JL0ol0U1xTybMg#_qv=L z9UR=NW3Ow}ODJ9(st(!zwp#wKiPQ4oCgnPophg80+VO0>O&vE~m-XW5Kw$UlykA2J z#dY-)Y0RWF)&mOz*2|1qo{b+qFgK8V0P__QKFG*+bqu)Icwx?AwbbmmH+4`_LSTDz z*kbj*c(T#6Y0_-5p=DB|p&HzVi?2p*oVGaQ5ji@7`k;u2Q*rG9aUpyVB*7o4uGNYB zIO`%n3t_7zO@g7dw<(QO^xf2__8HKEC$3_*Cq6WxeJK~R_8tifIN43nEncpNmO8n} zvsc7pDtroka?yjt%L_5AmTbxd7%~$eqxObkIzL<&aH*E*tAr#?JbnjhhH}rFj1sjn zCCdxlBVE4w_Nrqs__K_mk`6LpG@UTuEa;%6ROT?yMTI9>1@hw%VKY3e7FO&OBUYCsc{CN|M@OyYD`R;aLmW6NgTvc(A{EMVA z2Mb?Gzf#xMQFn)KLV@CM9q+3nS^lSPJB~pr(vMxG24Ox~8lx!%{|8;8+032P_{&Rj9rY)Mv!f@TK-j zB+8Ad`w@)#Ml8xZajultC{%In>%4ga-C^cJU-FfWlZ75sOq#U)O3KrNs@o>k=4xnR ztBGIr;OwmH)A&1+1n|)H>i9uwkouQ_%`?dh<0i`POK@VAkR1`0I2xhrJY5I6&Id3R zaO|Avh*5y-<3oT%W4%wTuQYONGY)>mw(AF}tE(U4Hb^t=(*)WuVyWm?3b&adBvppE zm&}aPvwg=2&6A_G6qoP>XNhFvv59~Ou2}t<)_XtLgRN!}GwYJeW@xioOT&v>K-2nq z%0^l$CbolC^PlxH1BxvRXTsvUga5P{+SwtP&u$ASwRIJkZOnS@Z=rJ+<4%yo3$#5X3$kc*gb%bNHcGQy~na-oUE_&xRV*Eb%vn$ znsZ9sVncua1UqBKOftDBCPPA_Ut7lu;0>P$jEyaKhcaGf(L*Ksvevfvg z2H|RA0eq4S@dl*6kH)(T!a~&|s2SC%edk=}amcS|xe^&GiLaA!lw-iPc!Fg| zjZ%1aQcslek=!#QCQje7_m|N%M`jmnx;o>a#+)nWx7o3_mx9atz`O{zs^S^GWB%_E8uS>A%xZgxbm1uo~6pA8js;Z-!W zSy`ltbSWou-)j>a$!~Mq%}^f0s~xw^(I11CLQcMcboDl+0yP_ydx^JMdBj zRTw))ceX9=g%DDAC@|v&nN79eGnr!7I4Y67I(n+Us2@E)1o7?fHldCSF_o%DX=)@r zJ7B0y-5<1Bg{#74vOhQ9kDU}X3L-Yh1s5WZMd#oya&B=p>HzOpQ2Dw}L(Hl4lxXBp z8*<nBm5exEG+pwAWg z7_w3BFRJUUrC;qdIraT~^V1O|&odM)$(#~KgR!5`%_Zfiv z+|0tA{TVVliUWuLaJvP_7X#c4+W;=S+}~S}pXL9LAYe!`iigNb@r~gn6j6-jfRFo& zf9dFhkR_(jgWhn_KPw=_hIoV-P}`2Yc|P>2`gq9ixZPnV`4DuS-s8~-QquVjApWa; zfA0e>urz710hPz=tEhnQM647;(1#7Lt<-6ZQT2*i--w`^sb+jesO8fLOUKQ^Q6PSC zAY!RkNJ_^{%o47G4!j$b|MmgZ1F<5pF&Eekz~O6ZYN_=D!&s|}IQ}4+S9BzCX1T2= zjQ+&bL$Xe;{9bBcr8{J_-KwRw+GVXJ$eDJa15aUa6byo)?~6y*-h7GpV1QStfuxaO~)H^YZ`Sde_?4`D*+V1nk}16axn+75p;NQA@^@93rS^2O}zPD8_8 zIHACRApxi=p-t=Q${JT7ZwZr-_m6=H6PAhDKtsjA{n3bj9ECP3gM%9&pX&1C^oy^B zhC;rRibrL&uE%loI6O$4a;?>wZ}P9JX)&Te-T!%%Qj*5^2Uo*8K?wrB9*x})23j#Gfc2IVyo%nZdi|wbzEHY=zfPa&9z1oam@uHvu^b78f zewpFU(O)9(C?isBh0eD0cyp14GqRGJg9@Pp(D6MTgvQ&DOL zUUyC0Mc|dk;qsr-fVr2hs^aE!+-?}yvg3`1 zr!dYSK%9qrDd>*gk?qEpWmYgI78nvf!CJJXu%E}4KC@F&ed&# zpRz&f{e~SR?jDP-5^U*;I2zHwTNS4fa=?h-6kgo69si3H`)cXHFZfXuCf)8U;2Ja` zouy$B`jxW-#&!HRJ8=S!tH1AB32(Ib#1N>AJRfepMpaHS8-_AQpTMUrZ;5gysp4O` zF{n0YpbjT?`Rc2kG`#2JNk>=7C+9UI8%Dvq14*E7q2Ku))K*Gw#Q!=g=9PW+ctEPH z+lRp2{&h~TCwM~Z%8ND=g>h6zI#~8<{yDgLR!7MJl|UqnoCv3i8a5`!92!d-^o%AN zGfTD=Fgg>J32ne@Zj!ckX#Em+Vu|LJML!6K_}-zs4-|I7<0Y9=+q=-leA0?o zQ~i3TW`AeZCe^g1!fhdB%VlJ&t0g>#ZIF;|=pbq9iH6$P&L2I;1KeT3P-*J=>I_a&`?m_iN^+BTK zxd=%Jwt`3 zkhIXAZ~W}oi}MZ4Ott#0bWA!?9)cWJd<*qLeKL0i)`Lw#+@PYn8q*5kfBIFfU;jDF*gpS zK6ZqbSnroUJb>E*MQv$~pn-H6^~9iTL!o}Cp9tRwDE(tzKvA84q{>Ew63c*-_yB_X z2+t=6PxTT?VcSPR3>zv!2ss95{1weD9ZdliDtqK*P6RU)k^ldJu0eG%8NE<;?~&xd zKVmY5fd7>YzqF<@P{xI_lUR|y^Izuz{IMDaAe`I}K<@lcK+2v8KxC+0KqM$fK-#a| zz(PLa1A?Z%{r{W&&l~cHgH5o9y!du`AK@ZL+1feJY|1@wak14=(n8UK-H{FGaU8b| z0)P`2f$~0x!jLkto~N#whEOA zMgl8yoNB^CjY(yPT%(Uq@u4}O<>Ol}`spXFufPAh-!G24>bPZ0PtK^xPZn|(_I7sM zf6sbN7tKS(!sf{E*Jo9koB=K1IgUXj68yWwFi3#RzVB4}c|9@u^nqvm>X$?U#aSe+ zNI%p^A~9?ppyfTfVLu`(8U{NepbZf%#W4v9TIbUBt?B9f)f3~O-{^pAAbOV_f)6Oh zW2M5@(u3>rIlnsz8<^MBEpv4e3B!AX927VflS8DQ!wCX|bv^h_7 zD!FvyaNYg{{9DHxXA1IRDj+e(6k#KN>n!Fjf`YZPaiY34-6cIgY3A!pG$lVXxzJc8 zlH=}F`LQ_W(O08RsnQ9|#*pf4Qh07qr?HU(oKj9t*e!VTLh{3}dtA>t z*5gW%1%~@<%^fr>+KLRX9(4Pl`j8g(xlt!<5;GR8{-sg`#Z4N+heJxu;1sxiPM*N??h+o0 zBD6aOYt0k4rdxr*+j)*QTU& zLQ1omsusthl1fYh2~=ayXNGdM(`?u;9h{gPvMDoaZ8Mp>6Lkw$17~E~BTvAKYh}Et z_kyRUI$p}_X2xPdy}5&Mm$Mwp1)>i z#)n243NO09x$Je`q2y_on6Vs6n2|7LhZOnDKOF6s%q!V#TkM7V82b>%(K}ms90jip z?-BAPUL-SL9S+~6UzvD4j;3y(bSX&FSk}r0C7hDqF`t-}n9@(5V``|{5Nt!7w4^wX z{i>pSj~W?uXo`1g$Q7;F-7IJi3#cZ*bYUg&qZj(?qgCCvxmsHY>(-Vb_lZ7Gg{xg3 zrM-%YF2j9{2uJzY4}$P-ubi(`Liade$*S>sA@dP=mevq?cw3wuEq0`lEfPBWK`SYH z&nPsuqDo;elv2Duj#NLC?|Mu*bkf73*j?s2ivm?Vrn~s$14!6xf4)>*iw}%aThTJK zbQT?U0rW9w$TEF%gF60by5`S%ll}qpB{W=GN?PX0?P+yjV7(_iZD25`?^l)oQWGbLMH?YM|`!nc!L@59zyE^$W@GFJLfk<(`tM;OMi8Nkc&`hX=w#{{I(y zZy6R>ux*Rt1cC-_BoH82kkCjV1P$&M+@Y}`L4p(9ErdoIcemg{g9d1VyIXK~=Pk0& zzW3bw&Ux?J_r3RH|AQ`BwW{VERjaDT9M@x9-(H%egb%wiVR`(VTvY3nq)g2o&YOK5 zwJGmB-E2?f%bj?OL|Tcjn1fXT9+}{&Op#*6ol?Fi@st2%gC#B)BD-acs`Rqp+ojiq z5r4i(i6kI80f8A8U83Zu!M0VA!Cgn5xZ9**A+gKLICKgtpfS#DG8XbxLRQ(q%f_8fYj@im{kJ*xb`BnV!h1^wigNqcEFH{!V6#Qi(SNX(Mt z$6$R|T`v8d%-bx++>{-0OWGg5LDXvyQadFINdYWlwCvtJgmAnY8SXqY3JRwT55!d0 z=^{d^35ZkLl6W#u7-XIr(cy{7ZuDN5UhQ$^~i}^L$J4Vu`IO48su&zZaV(-XuEP7 zX)Um@8es&Z|1v}ds&=g-%hX%9)X$9OF!pz6Le?gRBuIamZaBI8(d@!iaq4@`o`m^o z`2#t>(?xH%H4iS&&!E~!=gF#{H=k#^fcT;3eA8R!_~c`q5q0=)*o*%M>M-~<58vy5QHTFU9sU<}_+QlFe^H13MIHVZb@*S@;eSzw|3w}C z7j^i5f;ybuy*!*3_sw_#?{zm1doVRh*AiiESeqfW7Daj0Lh!F0%7d~=_{_)T&K=BT zV{%jf>(+~b{sC8)wj5FucL|}${W-pk1;@cTz6a3!go8v~{O|u$NNmD=k zZ%I=-|C==R%*^$FD@{EzI*J^+wY}Zoa-jd8NK<$H|4y2^{J)o`R)brv|8GcBPZm5a znZ*9Xrc3-LXY`tbdzG0aJv_Hzpm)8g?din2gJ-zD)q)7O|6k1W+Q(d_A;`UMdoDDOo8Jxtd% zwCFc<9_04-Ck6{1=0@E?CI4g6)H5dki_+AQ|I^accmJ6*wcY=5Y3iu|ZE0%n|5lnB z>rtBe(?6xDx9ojMJOw_NB)(^QXUB@Lfci9((mk{-SD2lvJ|Op#QHws$6MlGD-nGbzDHh-lnJ^ICQq6s{eMUuc96esqfOT-xfhOI znW9i8SJ`*czhm}qi%;?@l(8A?`yZzcSN_M+)T;lzG&Sr0S!rrBqN^CH#%}>q!{AhV zg}~HY1w94F*=$B-@RGHP`|i~{WI>^sF4(sBT*O>h1|^4M^2tF`Jdu>Tz2!n;6JbO5 z-i@OzjCcwWJ*|8#9LBcHqHOTxY5Q`FzkMXOi8^H>J~vOf#>HM6^Y@LoTSf@f$bBhI4?3$A9&C!Y$vZSnTLzrSkep2<-GMrYqJFWbos(PTf6KI8os8( z?I$u#3_XA7!)neYxi2+wBkM>uy8Phw10#`NaA3Hl^bIKN)IR#r=pj(r5SiA1_oqy1uS zxD8W0v0ZrW&hr4l<$f2RUeE1{H%X*lgqdVya#s|Ye`W3Yfn(87fxsmF3Ec!|U+j@BD-!V{~7AJto8w4ahpfW!*`j?Z>~|grEEp_5n1-?Sk>3vo4Q~ z5Y6n~PxBBExM(2SKd*o{&SOm&Cd|8VCqEadGt1z;k9%NmvhQ53lqy@=d;a^I>;5Kv znoE#pH2xwMqxku`qa3qjCF7Od`RR`o0{V`di|5;lgRF{Gmox+ z2vLWL%*@UN3|XXHM>-HkiUFmx{~>2x-nR6Y9gN~zZ^5kU-1SHd##6*=?js~jnW=aY z{8xzj$yXwIi2Kd{Dn$c6{gX$cu^&C#KRCh!!D>N39@2MGkjI2J|NoVLTYUQ{1g<#% z2J!CD^%MQswvPm537-)Yhl^OG`juB}Mnp>U|ZQ-LUX z*o{rv^a}{spReakR;I~zx7^o>>j>hYdih@e?5O%nXg<;eavsLuhF(qYOb;aEru{>j zy5rKIyFrNcbL;1VIs!nzS_tjmbgA#zZ~n}XcYW?Yx*~KNf8#c6H(YRFSi>6^V<{xs zRm_}Snn6T&DPE|SYrD!FN)hTHO-aY>Y=VN8#F!_}q+|JmmuJ0_l)d%{^%G_%OHk+Y zGd@SNffT-tT_CbfxXZcsX)L$nfTQis*~v+)>t+%sXLOcOB&%j#qP$i-9-?&HHywJa zeYp#gJEFPJW%|f#>uGS{z0=tBwZtJA0yP@B_WD36#*TUGokNyr%npW)Qw=+V{xJ8( zMgmaJ3~PsjL$^Y1RUqHP2kGIC+CR}FRRSe!M5*I-@h322zb&V4+gZN42nfk96j=AOi*l(zOr?+maz}5^@Mg zX26z=0kr_e*E8sr20LR8BB;cA^~MiHK{bHn-3RFb%plJnAtt2i#5?B4)?s#3^yL); zP3WW2&`3YkVM9(27RE<&*5x(KDjH19vF@sa~@%w&?{4kN~3M133-H;!+a(p2f za(0^azA91olbicDjjvW;n{;Ax9(y}c@flcI=~vA)KQ4j=eT5tW%jofP}rHrFV=v-63rbV!IMi?S0zWFw)_N7A=S%MyS=o`b&H@n*nTTG z0d3y2VvtNAHwUR;ec%vf3p1XWoHWsrI1RThan=@jK|Kx@@u_s^!B;^wZF=%bnrkw| z_0Dy{jjoFE9-Lw`6`v1uoBz6|nRSH@T}D}(N;}K@Ft>B-Y0a*$#uhHq;97$!S5mJ` zO^G5W(W97nBk|y|k-IKN`0E^ZF|Ek%avaH(yD1Mcxna-P%|e0raobxysj=nj zl!Lefv-?-M2pv}UmNvw_gT(5r2-H8g7Qi`i`)&4x!8hWX>+K@47#45fPr6FVT1JSn zHP?;m`wqdJ@Qp9ADqaiceR%gj)Ar;_v?V@tzb?*naA)l>rR$>X32vuqE zTej|~o$4LMMxegpnga(V1vWW;5~~kNn{A2@RgbU*{A80t+Y)qcVADYacxY$lAAop{ zV1a>Mhvg`9u~ffKd9l%BSXbj+T?$;;N@~f5+MQ`UK|r7Z%#+L(w2rDjQ}2wIP5UxjLb#?#GwpLtus!! zzv?TW0Y|-`U*=iVL(tec;BpBG1Q>cYha;@8RKDksk*d|w!~s{rs`1AR6QgAF>TWp=-TPoV^>>i*DU*Ht{MhN+p}8)h@}f}xpyr|o+!pD=+4L;C6toas3iodo=7Dnt zRyG`E+=ogBTTZ zLuKb^-@XQ{_6AC5Kn-X@@R-2jCx+ZnLnvTwoUxd;e;C(ArN7QqZuqA+yC_CcWQ5l5H986 z1_dcMyR6R5fxs^rLQaqVXv1KPl`D%>d#jp$gBHzN8)%v}@=Sxn)Sb2-+XGA-Wl*%n z2J~OAqS+~`8=|7Wrwx0>*Btoqzx~n_{&`zqpHqHXh-@1l@pRN7;g8WoTZ~nBk8EHN zW188A&~kKz()g>_zrLuhE(*#3i!j{ekFe@o684VTP3YZ-b3A@rpsK(F|42bv^Kbf* ziLuo;A7Q*VfFo7f!#(-$m8jR+V}esi<6&&_^8AxxiSLg0AQ1Z8E2QSmeB0ybxDptu`!((L>lz2ZXogX@l4QdblT1N+ z6e2G=bm$jb;$s5v#=vSUym@l_x_dR3iAJabvy!DCBhdHvhb4P(_a>Vry`0d>%^~fD zdPtdGD?2S=_9;IHi(`4UrexXa-nWNDm-G21mp`$o{6at4kuR$jI@0XU_vXf3ARIs( zJe9W>n2g&z!bs7L5pxqh!pK#O2w7xx>X8_2_`SS`RO*0`ifyiv3`51voV>+6dw zd+_ym-=CB^mhkyQ{M_a}wXHge%S+`DKi7F8Q53qJ=BByESMtPSsI1jZ)xu9d2yZ5T zWs%#5@o}0D^jAY<@;OtNuht1t+}5|YoESG&v$=6jTKY>zT{2mV_=Be?jbY0%U(rfP zy<+NSz*B^qr?gk6!&-FKyIF+y4E&59fi*r3AFO!ia~;IWAh74-m7BY*IS`n~D_nR0 zy+1?w!i`SXco_Vl^m+rm&QHj2ye7V;CV)HsXwogvQe1Fv>Cm1b7;kbP4K7TbtH1^~ z4SZt=``P);66@Y+b4U?cCU=MMtuB8(p{r~BZS zj4E8|WZRfvgBN?`z2Zjpca?eVB(^Zv)+Z-Hhog;OH;TG#<)2@=hVgy4p^nj%r&pQK zlpv0zC{rE5ELCdtfl%Y=$<_5w?O5;)sRS17Z`is{98Q~KKYYKTKj{E!`XS}SL2RIP zU(u2#M?YE!6}Psvjwicn25&jh$6h5WK#Ye0RI|r61cjV&%mcy$?GWJ`A-u_y{LK9Q zQN(?7_vra|?h~CGa=vAlTQ7XdL-oC^$_KA@8ud99L-M&qc9^IW8AT zMa1(8tj=r0kNy1vsPC0&mj-m>G33z{^_w^TY^R^z+1}jmBB2GRc_=IvG)z?1#!vBk zWB|miQ{Z(b%pu%*9?eI#qvaCy>a$bxv+3ht&e7#f&$X4o=!^7vKb#cAFcd|Od@Cxt zXT`l@RtLMj>qzm#{tvE*Kk+wPn;l~|jagbMZ;iYJU~+k?g_UNGCROiZ4qnG9n1f-_ zTWa*gkq4;)L%NRv0T56TJq$%2Ib#TzNasKO9@(4-gebedsEChjF~%oT$WM^~_8fu| zUIjWau<##raq&h*kTkrZf-iKQ{iE4SLi*2P+T@br&A00^*E!m!7A00jwxN{-whzQ?AgbSD8)=FgF8G;%= z-Tl{&ei485@gw}nJI!u&-B$D@Ae4zB4xFW$QnJ9TXQtUaA8VZ2smZ2of7XW(FnA~T zj{hdBI{ZnLG9fJ)!^3`*j@9)svI=380!M`84tZO4$7j_CSX75smzy1bqm+DR(ezZE)>2!jx?Jzcio~l@c zK-ATrNi4O2Yb#fuhg>Wij&;7ljz0f8Q1&lxn2TC(@AXZ2cm=pqA1o6gAoi@Ig;Vl- zFTO6Ydv7%>Bey!r$amh|5askxp09M`1Gyi?2xMrpkRv?HEU;TS8&fPr{ijHcVS#~= zb_R6Z5fiUKpxgSQ;@cj2e}!GG9N)Dia5{Te$;8zy^WOWAkbU`X9j|Qa+vV#?iRNv9 z^F6|yJYlfFtWq#DjmI(1bn)RAF@f95doP>iLF+M zTZYAW2Z2CarKT_3;X{Su=K&1^V}#0#;&XJA(%i^sy_Hc;AH0wqI3vIcxZnGG!kLJR zNaa(3uEx|13Ls&vGKE13D3ANuoy;;dQjI}HpuHfr@hu<6ro14YC(a_pf0!vs)rU$4ub+2bPC239iL^qjtZ<(D-ag9VGGc4u6O< zKp{2uQdb|XnIu2pxw8uRSQ9zl{OG9_{b1k5UwB1d=+gyn)cMfhykxh(o+3p3JQs>@ z4z-6j=?oBxY@WyT&6>+#M~clUi+YYL67hk za!`r2B$PUG)81h#vS*&$by9!R{UknwK0z>!%@NgvbM%+bni27R0Ia2#fkpqs5*qV? z#=7;ZEC9^F6;g0_J%reJNBpoqIBFugAe`2vsX8PYcM(J{WWvW>U7#hVI!*L9r;1@5 zWFpv(QhZZ1-*d)oU6g_L$+DF?yc6jxIOYK3*c~&2QN-1eU6gEsZzi2)sylbuP~I&#>eann1V_ z{661@myZJ$UVQnc3A&6~LH`&I=>t{Bal|jbz=NNxM&_lZ-S6AVQOPD;XA~D7T;sYl zc-&NJqa6e<7lzuAJ>L_uM?F9gj@d0PxIez}h?!nG9peH97&+dT_sze<)IlpyQ>#&z zr~TFa5*+qz;qZCy>?aDL{-@ZjySBhrUA!(9ZajdtDFoJ$qBo9OXo?)j*`qHT1_cs* zhna4rHrBHYK^0hZVnp1Gof{zfPb!lD#v@nNFFI=ud;BstUfR?#x^VE3} ztutr$1-!rRIse34y9+&1-11r3NS*aAsj0573MKT#tdsEBZXMZ$BNlyplBtO2gx z_Sts(?Xq=(pFV{LDB?WN`E`wH_Y+L@26#wAO=achr029wmWKH}s|maQ>~rAE-lg8+ zizeN>*p@{b7m-j>3io|Juk3AY_>6Wt4cyf;<(J2(;^(E`mMG?066~;A)ZFec;kU%W zlpNcf!)V`fdVV-XT8LVTIr+p45|u8ym?dz^Tj0&UXCc56=g?$CaVRQ3L}Q5^u-1{6 z`XnahP4+B;c3o4I(M5oBkuF_>XK<%%2F;)zVwTr2eAUyHPIUknOY21364Sccp1+te zH%v+k0=tfSTV7|&OM?T}rObY|RV+%upJ|gm<%6MF`FH8gYLOeV@eNi5VAY7Jz^DqBnOw zIOj{@O8E&*8E3niH4LKmpHDG>QLLY728jLuD2RR3=pfjHw zq$-y8<|*%XOo=f2!M42*)9kJDjNe{GT&S*LAEUJVW`0J}h(D~W`P$8&T3q?-5WU85 zr(?_|Qfz=cF-?vzq4_Gy3|=V`OJCp>$%NQ6A~F*H)bpRVJ6v+O7z;+EgmDfRYc0#VIBs4;ZKhw^~s9ct3VPm!m=sw-6_0q!M!S zBuKo^{O1>Z6{%2Y8@(O5pKl33c+J-Qo=2XbncFoFAR{%nZo!%KEpVnZPA`^eMc)uD z;*`pzGlqk;>tvP8%+8g|y^b~;pHI5{V%zRs6ma)d*ixm$^?x|dKD4&h_V_G0hX$$L zU{ej^c&SctQit3&y^nnG@fr}ppu@i!yV-q5v?!m?WMa>xc+Jw|2FmX*O@>$C*NMRP zrU@a}z0V+7#O*voC|)?Eqe5VSrxtkwq`vPf5p;jY%RN*g0vgAJP#5fgC1Ef-wJ*-g z+pYP6>4A}#RlU+lBMi~$I11QYAC)Ay8IjNQ#Uj_6yBZzg5V;sFDC}l%{@`IHx)JyG z{2=yW?&x|By@mJe%H^EuzO7A2z+-|eh0J0iBf?4vZM%6Q-8PEyt@CXs1H|*w?i9>% zqXufpHfNykemJ^#cb2?(^W&nFssmuBa|lt~I2NCsy6to=jR{wwLDWX!PdgMee=l^Q z!*Mm#C)2Gxul}5D48AdFs+ciozV1`_)q416eI1^_{?K@}@~7{3`yT}jNrU*oR)&&j zkbnNQKn8i;`x*;3PZ@##jF{2iEy&3Ab>v7Ls$C=)h(Sjhgx<%mU!8gq&xG9Z8mlAl zZ^`9-5Y!h)YusQ}GF!V80xCnF=GSkaJf2`21i>_HQ4R|fX{jH@?_^%xxeE7Tz9_h9fv z_l4_1PcGf)Hxs@ON;VjXgmDUfbi2%E7#KZWE z6R&vxmR{{>khfNH3}9trT+QRp=udvdtpKt-%PtM!p(>C=&8~sVt`4^iJbX<2(Z6j# zw#fOe<@Bw!snsfyj0y%GE1P9Kk0{4#%_f&Npm!vnxqDyW=-4;cbmr5)Ohd`(4?b6t zsPmU6p%@@h>gIM4hQVp=xs}unZZQML%jmS)itwmwE*V`9sX(?QK5(hg{s*23)*Y<^jGfHU6bX}miC9t?2=9evZvamA$A%_O8)dV*t@Wu) z;8L2W%BH``uiIcn5m=h?`f|28;57=#j3?)N$sJU;%X2@TW(}smpb|ZV5=R+wgN%+R z69S|`M)~q%mxn!<{r#Se0gMrTkA=;SZ$Ce#{APTQx;I`txwFH1JTrqfeL*!iC`7l| zaH;ViRLe_3Upq_RERaHJ9nBr2!#HZqbEgz-QX?vD zB+yIw#4p3R5UQm!ORWk@Hqd;Lo$x&tOu<#E`L0Bz@RZpLIQPdy>EjiHS=BJBNFZV3 zat^^S34j2(m$S{XifcoP+_cvnX&UL^Px*xn8`u+bKiD0M?Uckrb29t4(WVVnpjs#p zmP{;era&l%PhzcV?rdhdm8eLZbeNo`Y~oDE5+L`E1R~0bMB0 zz$u4*M(q}_T(E87>3Qd-a~nw~#l(8m>1ITFl1uRYS8X%;TT?ksjIB`F0TuFRH;5|Gpw;wW=`1A^DAG74J zN9fzIU(HJk7#k2c@{(Z;i6&v1ti6*x_~cjhn#NVlQ>p*SUUppiTLh@|L)B#j3E3VU zoqummuDW=lUXK|_|E?rK*^_P%`zokm;3a7fd(9$7KR}5ro49 zWtzJsiE_>I^E6h16$R_Oh_6#gl14R&7yWL0pm8Y)%0)yoq-R90=HUg1z&^Hq>+s{~%jK#Rsu$BhW-LpjI+Y2yWN73S zx|3;a1}EO2yI0Xoz~Z zG)(XA8Orb+LqpO%qWvdzn!@J(@~8+|G{|nI96t)SojECF=7sL1ZxEQJcd9mDe{k;h zmq=2gv-<;KB!e6K^S%!(_bOgAj^SO|S(4_9oul_^dz9BoM=bDiC$6$o6rK--aOuDy z=+ho`klx+y7s)cB6)%xA=etq^dnM*7`6F^5jxY>bWV7AKRdT}md8 z2e_U& zge=vl(7wn}ep?bU#ySycFc8y^NW!nwOOZd z3OT9fG$AI`*!VJ?ujAkrAb^%+n1zD6AR_B`=YVIIV8P4}^@V2ZtO zJOUZu?DYeVEthwmx;-PJ-gmfd-kiBYTT??rAD_ZK9r_5lpl5p&N#85+-lLQCNm2R= z5~<4J6WTgg^RdjUdcDl?_w0kZu`$x7caFbk9gxz1B)zYNA8v1S5>AAbB)p-Gae}%@ zoQHx>aC`shiMyHoySvseAeZ*v5GarXK?T2Q1VW)6MMtSBdHs$eAk>~=G{>h<5%$#( ztnx1dABlQe`Z8|YE)F*#&Ic`ci5r$Q6TA)Tn1VgBTrc>Xnrm$&R)e#qZLJ@a&hMrH^jf{ z8B;9yKK3e*2+U|g^w^WG{2h#=ILqz0Tu>ksD`a%G+dlZ{j_?lc4yCF4NyZHlpT!OS zDTaduE~_h}YslUV`oZQ+8iz&>y|sfpkNzauS%gR7@!E+Vk+D&6)eNeo$7Hgr!Iw?)vPFkQD~Dc0P)IssIZ{%C)MsS{t!AC~4tZtj+i>Q43xW(BSfm)AB6Hda@wVhIvp*NqwdnoO#NYEvR{b^in! zBFT&hd#Eq<6R=c9#4r?=lvIfnClhZo8@0NYObXzO2udHR7)bUJTvSWdXZLDnY*2cE z{CzY^-7I}vWRZFKZ+vIca%{6Pa8X2*iiAP$nL0#9aXK5PYXvHA0d#r!6v`0-j#>?Y z#t3&b=B7ZBszyhv5rJmDmtlse;H|Dp zfWGJ`u_&Gu$+h;lax=J9$L9NQBh$kvEYt3MpQki65cmTvlmroR1ti+p8vGd`BW*^~ zmB>6a-j8(qk@9Yz>Ev0Nj#6f>*E#2_J3(m?BnVa(pu!vBn)0HhqE(EzSlc+ywmEt` zw0rjQa%J|}Q5Dt9!p3paLn>8rNLp1Dq_ua4_VkG#`@7f78F%IW)6oV8z=59T{K9NNI~0#jshj%IPgHupMg0W`U0g01 zVN}!85n)!5LL=5@MmLVFGi)|v4>b9Af8Lo|%>hptaY>mB&H@~n|dr0T9bzWrZ(AoE?pdrty}jG=@Dqqd}mu8E5d_Ph%x zvERVo!m+<_5`ldc^~YzXzT-5zZmKuxHw?gzS)Zn|_*29!@>|aHt1xJlQMGtng{h;Q z76~sQ7Nw7llO|qXB!7%w3W|TBR^aQmW<;=N_c}NOYXBT1b+U_F?NFtJW)73ijCiz{ z5U72JW=sez-Op%oJQ^#EU>Y9SkwET1Ny4{|FV;6*rQV9ItWX_9&WwnHL#}g%z?!Ev zubOZOFX(@_6RxTbvMgavR9rd$X+7&q!LSIVqhJFLMBS(97s3>fXjL;~TQ_b? zD}@8N5V0@VOgV4Zf=i$oW9*#nGr7DgunJH??IV=|;UqazFZ{0Ei}?er=^3>iJ;k0v zGA9CsY=QL;%Ve_@d&nD){5Oygkk*QqW}qwG%x&d zdl2#vxV@CV2=lZ(j69_`_GwEsErgiWPTPf(_8x9t2nF(Vk~(naxSX%5J6ZTL$7Mxx zyE`z-VTjQ5>E7H<96JcW%X4hUrcoi?VlbIp6=tmwdkHbD?1&v-2@DG*ty``q6d1?D zb}H1XsH~fv>|zpP!E#<<$MhL;W`V(yi9DY%Y1VUvj(f>53lc}(-Ppg<2A14Go*f0T zvYuZ_A(am*N@fwz7sCUY_>4FlPA^m?Qj;_)Viq^KQLUU`d{owt!;g@vR|}jvq+c0%o9GEOdE(yaTh@^MVy*5j^N$EZ~izef+LI zF#D;M$Hy-qFiUZvlgLEI|6jcr`=4G+3L)Dee^p$rB0nz-<4_60VJd`PiHCp+E>8yD zQzJt`>dnlf>|p)h($9O>GV`u|LSIWJnR{oTGq9g`QsYCMFW!={>$TdSC=>}bx;Fo4 z-tYrwXJP#w$oO(|ZcZAsyt^=C3%S4(w+uPn z;r^!@C%n768%APp7B@%u52`hXdEf1txvUBDl(G4O^OW+YJ>mWN-|9lpAl(&eBCyGf z2-q+Yps zJE$GKLnJwPJO9M~)VP?crxuwn)bI}<}+$s7GL zmIpPDd+V!dsXM1-<%RXZEQ5>Dk!N>u*Wbmn`&R?G0c$iRmj@L!vv1cd>Nno)EZz=Z zZ;pnZmhTGntF?IkXsJ{;fJZ+rwgGg|k`n+y)OU7-Ze2i+hNAYWrRi)h0}85U{38aM zStBq`SzNpxH10@MVr`zvq`GYU_|S8}Qq?&5!*%OAGTEi_vMPKsdDf$}x%A-Sj(WBA z=WEY2fj1XlnY$;PUo{3Z%3LW2DRAI66HKG*EQ_XoS?}&HPGJPR*hw%>1~zkIJ|UT| zGFTN#d?$Pj)6wB~Q$hJMERo^Yv;}&@IL<*QnVUQje zCajJ_&3>kn77w1bzq|0ij1^!5ja3*tjKJ3XJ7RxumIw&gFKm9!08wwfUW+YPfBb*B zmpi{-u`MG+lqLL$ zL|TM4a)|{~_&ZZK=yt72S`F%&2xIlnr&i~+oRqfw?``rqo8NED-Hy!hIl6Bw2$>JG zN(I%36x&o#IA6`zWBEK@4^l$Z4MNd@MD|C9 z<{HhHLZoO2+6HQDd>BOFb5!J8xwRU74%GnWKd>~HzK8=TOs{6VHRN_M+pqQnWIA=I+pg6)*+vF>fm$dZZmJnUb~nW$<81fud6 z97X1LcTAA*PEA;;y|`TZy(dwCZTqR_Z<9X3hS*H*4%3EzWv{dqY&I|=KCV>-IGNLH=^W0#GNQZ>RhU;S18_RJD^ z3A{*|;+_#CDHZvqTX`I*MkMO>O~lNSRfn-&m`Roktl2ACmxb#-Wtf+C@mjg#fbLjO zdD`!A{PkHx5pe-_+f2s76cMTh`8tLN1wk`>ch@}&(!fE0SKb$R<%b?RzlH2?ivk1H>$FB!+yMrt4f-dp9FKHb{*G~u<&Gh4$$F(U@n z1irqSHe+TnsWH``5Yfi|%^qEfj@z?@1a+~-2>4zMLh=RW_do(H@4%22Hq0*!_-8V4v!&CgNn{Q#pQy=vBk5-(I}@Ig>HYqgl^)p$f%# zE(ShT=h5V6B|s zqOX?mazAJQw|=M5XM2hNDx|$CRcz61k#kf@& znRGDCKw3%~UjEcgNYcI-;6E66&sgq{wGvX6D%X*&s}PLCVX&sYq?lNJyYCZ9c*rlk zmam{FzBO*fMtWSaz?Xbm_LkC1gF;l!PEfG^f-QM54LJU6%bt$Wwuu#sJPKukZ8fH4 z{8-@TzTc#gsXxP%Y_NSv?Vwwdo>(+^D$l92wm67*q(;u`%ZhQF`s@Sw7A}p=S zJE_&Vb?*}PtVB`Q?;*UG*<;tK%#N=vZUt-#A}B}WaN4^~86sH0wi(=50Aqa3h+P^` z+Iu6z^Q_xwT5fSZwaLVga2`EbkUu)4ffKihI=|& z%lr%xfJwcPlbn8cKqU$fGO^q~2=3;tJ)2pD% z672gV{0X$PZXCvVJT^|?LO-HEw={4AZNY8hB~+bb6B}nv;r#-2REDe~YHTQ9TE;C; z+mnP)r4gGdF7orX13F_xn=&cmbK(UfkUg8r7l!nD_&V-{t})S1Mbpn_Zb^e>1UWi{ zR#SNt4q%lsk!jX@c)V^-;r3qf$dV!$Tat|oXI;bvLR)6_-W8PtfR#AJu$KXFxtaK^ z+>5lJJ8t(}3gu>E?x_X3pil9f$GaNlFd^#^@!)0^%2 zXMp{5qHo|Bd%%8MbDtXZ>iD(!aJ$W1r?szFRvvOHJ6Ca8@e;o=H9ZxP>GO~A?=p$sN*CBk zD_a4`bbkH;^WWEzP3u?`=;jiipe~Fp!mTEl!E^bKqT)RemR|}aFtlK_>(Zj!4vS8j zlClziGEeS>Q``~T6E4ZcM39xg0r{8?C`0p-&E$sHt*lz`$|1MyGTt3qHPbvph^dk0 z#H^z`hya)i?5|~NmeY-9ey0tPy4#Je3;E0}O`@HtqcIYwG}D4arw*L4Zt(n<*$5b;zyt8plXLN3$1~fLzyB}x-ZCn#=4hw9kJyKrIID5lM4Ao|nh}Q|bykB@-=xeV1HFg4YX%^7;veiKS!L!bBe z{{80LmJ$~)^hnlmZ}{!)n|PA`um3G>k(G>v>|flXsFS^eh`om{3p9n36+p)I1)$HY zWb6dAb0Gt;e1WE_FpJvTxj^I2WSngO#8vEFj9q|aEX?viv#-Ygm(nUgXM0yCQy?@y z;Gg_zo(@20ofbd=0TiH}8MI-Pf6n~d11&`pE1;&YWbdTwMPY5p`yTM!shVODl%?tjJv&8_5Q zZ>kD((PdT=lVDZ@dbmLQ4;`cEzXxf3W^oS}N!7oSg4QXi$_lOLpDqYMfB!=ae+Bxl z803I<7A}@#0FM6_bSWUN+4lbWYsdK*XvO6O#&w%+KC z*3b7j+Y(ZaNg@eLrz%#b_V0P=+Q+4p$@QgF|6@5oZSUC$d{l@nRkMpIE?b1{FY>)esT;n@7T6O0bGOi0Way9T^Hbm!RB!JGcSp^IwvF5OtAE?Ob;A;h6J@);xso#nY04+ z&*dMP4CWt=tK+(wh~K=4wwuCCa4GZ%QYO{ATR-0#{TTu`aY9&4VKpMH@+0TlUd(%O zah2TBA=xj{%%$?%vli-Dih&jb-(N8j7_-1&V+NvvIoI_>j69z82qCZKy0|z>;x0;( zuHL-10Ya9H?;iu00#Twos&waOCvD^jOBT&LnLSK=bL}48;0hr@m8&rnO7Wg~8<1cE zPFNx*4RK>+Y!J*32xl9jWs1Ij@Xxj~(fAmx^!z2b(bM0>ez*(4Ux}z(M%mp9hl>UX zTzp2idE4xHig;+)NKVih8~X@786i9@`$S$)rE@m80H~2@`tOZ2i`{r$*py>>OHwI^5gU{@g)4J zR#Zl?j%xCP=loVUZi+6=aYKl_Flzr0(p+NoTXk48T{bsr zs<~t*{T|LY6kGUt@}m%gkIEmAdy7Owsm4c(>AN(jq`BH^3K4fY$FGdC4ZofV;qdX=lXP~Pv2BQ*@}Y?^+_ERJV(4@$K`nZV}X_gNY&{u|9e_N{#xeGCMOTc z0XdBsDbiw@Vuhe5=O>cdDNKKtsk=^3q{4wR2c@CkxfY^x_qJy&o$Ff+og3cRk#lzM z7t?h3xk5CKQ!!*nAt&J%`s&`UWnNXn+_F2U{0Wp3QMYi^;+*WTXcPo&wh~~BT1UP{ z3cmoZWPx#hm}7#;_21lnp22+Nee{##y+1hAgac@J_#!_>wZYrI_y5L-j4VS0!da0W z{L-UV_&L(>lVhj9)k3E5Ti({fPL2&Lg7i&GzCLAKA78;f<)CC)-rvYULi;hlBU!94 z(gn)>U?rp(IAh@GrM$4k3L}EX*b6=>6yAMRxciDH7`awx{KSs=#17+^is?ttJ$6L& zH|V|&T^exEIi&jIFT|oZG|vH2CMsi2{uY>?K)^znAIm+X|P96hhYm!f#0zBL}HlG-BHZZcsB>dl~ElC{h9hbv-i{8m)-SSIfQk;=#xUzif!V%c0N7tSGang z0aGxw1%}}4g-7tdM1k8_$=&asoCR!pP`*W^<}_^Uo3Z+Ynfp(L{o8wCeHv*Lh1h}( zLB92xYLsfkR=!qJc;;IOqz4FMY?K)>x2r`)n+K7Z@VS_Eh8Iew_Swkd<)$FO0?4-9ldfiuHoLjj z30yQBM;Z0jri`v5J-{#|O6g64!xG0mlN=$%dpGJSQHd)rJxD{d<}&dht-$8hZYfZa zn{Kiy!uYM*f&s|OKw_yZ>`OS#dzPoAyjp{LF z9m~i6Gscyai~#@lCY{c*e*y;S4%u*(>;%`HU(2jKTz4@ zr)8}GCN)00tl#Jh2UIp1JP-C%1QjOyt|X7+=d)oqh)^w@#39L$89)y_($1ZnA%FC( zb}664k9#W^kni6y*(Wp*Ph`Z$&iZFDT6txgDw67fd%H$7DE@|%lZ%GRcV*Q0cC2McD=EHTx2*_zOnq`v}CK2`95|El}yht`YI_W>4MUz?cTv*kMW~% z;_LDuh4h=AqQQ+=g$x-60s~SP>#FB9=DMtiOk%XpRV7K^--VWc6T0FgGx|{xWCBmQ zrh|C-gnLfgm)UceH-Li<`KI#uy~JC6#2jD<-N<%yNcNO0GC5UBB_LKW|U&g=AJ^Bo1617 z(1}>wtO+^!s&zKCecs#Lx%P{b+zj}0eEsahv)^Ikjltt>MtQT&EC*WZ-I<*KwN-{G z3kOF~mk|qIMD$L-yF4Z-89liR$)n-dgLKh&OHr4b&imxiq}dt0SvEXm*q~}^GEy}3 z66$g6BDvdKp>}68FE3b%6xUWmNNmGz0_(EsegbQ28#Q4vDm1JI<<0XBUyeXo*uO1mAbf|pc#9s8uoj0HIXn%0`z|@l@H|CI&VTjSFm}~^=7EdC zKN)A8c>kd$kUIu%+}y#NkNI@9RztHM03F8WWw1;{&x?Wv!h-gqk zk-Z22ry^ZvTr}+lAU3-P}tlvI*dwavd!L7D?<01wZ z6c+C8?ELug11vL^oTL};#R?sVsc(SFdr1Lglnz6BD5DGIUA{+_t0lv&RuPT+fy%kZ zar5mpc9%DH?k#h_8w(PlRyT>kS-vnCJsPeu@Zdy8?B`DzR8j%tL{^X-N%Zdhwmm#kS-3DR6#U0tCU z2r@V*#ezpfNEp;1q<4lL#7y9`w&%hFF$Zp&?WUs>U7B(dYWTI+ ztW1Oij3|*ayzVD6{_d6cex)NeX&?|nNY5n{S#{ctv>qHhAKdlQb<^M$wVAG9p)eYj z-iFb{&aO>5zDjK^x|v_OvB7CKT5h!km#8(d7O&#!a@cR1oY!poGr&ytk3n5s<_b@jYms!78!i!-F z8DuPBEP^g-6IkZE3t-z2V*cK0+RAICFAUtxy1TGt47Q$%SeP&-BUEu;;5oF(p_jY_ zppiz3F_~8@I5lr=WoJ;?;%VsJSzdlTRw7Es`E;jjNGf0^@LrUS)Z7pb79wG-shPZb zIyT149c#Fd=lm^XxUjwA^O<1 z8QoHa6MLM593@h5d#db^& ztTBVp3(d^wPN<(cQxu1{uiax-Kr=Tt8 zQYyeFiSbJCv#P^0o*FglW5e)x4X31+U8O8@@}ka`#yDH&Nvi>eTmLS6!n?Tj>zkjU z;J~OW6)PAh^6=p*8!MnLqkZ4|0X6SdRN&?`5n<$|9S}C(nY=5+^Vj4{pq#i+Bz63> zp4EjNo3G9d4X)}2(|T%##pUJlW35dAb*t1b99W2v(F$_WA#esLt~%)gS~l-R4~{QjI}T!-&9NsHUDc}B^~?6Q=!jF& z2gc27STV6LzmhlHBd1`;?ePh|Yl76&Pb>6&y>CLLf+db*QH)TT?=ZyIWZ`;)OCoX) zi(@bGxElj5i>7g9e#%y=sfk!}+B}Rzb3ScF8$NrRn0&%YPbJ9m<$antz3lWj-xx{b z>MN8*R4fiNeV=<{#>dET2RAI~oTVxb=3UuFE>B~~mX2z3904JOU;F3En652jvemdv z#@?0f=xT?VtXA3lHk&?4apZDU)M%COz73U$BjgZTR?R<4jIoYJ2FJS)=2H~41mXk8 zIVP7C+#*G6e@4dC==L3kF8KxL<7VGq8ng*JONiuIrhS(UMg~$iVO>TLU@U4D!bI%o7I6DeCUZ{c{d$3Z?MlTu6c?;<30ANp>) z@N0@C;K7ScVL|7sRXdu#+JuA^c6B4g)PxV7;i^H-8R}mdPu|z{{E?@nWgH$B zP*%~>(bm3itV8x0e!5Eb4*<(4DEwF%jfjl;;PtN3u=68qP(IK?G2_dsF?E#r&&r;> z;ezSP^YK^p?atjdO1kTu=<@us?vZj2DqsYB+2+(jpUDfY=;E*8N%2XSb?{@8hv7Y=-l95R6683A5v`_H_B0^ejoF36UWyq8q zs=gEhgBdpYyOKIDE(nv$-BfYlGombWcPk|&^%=sXdYl?<8>hNM)vSfB@}QEyCrMUC zz+frzEMq6u#co^p5W~*tCc`p4c_&PP-StQEZv7gWhA2&c4#OUG+_t5@EBUJlEuH&v z+b`O)>-kA&v}~N%*q*Xo8E#$}gD81HTjp+-9N3K%1GHY)1bj@-eCPR+NOY6Rl?id; z`<9?sq57jGr7Cs9 z>(}1i`m2y7Sa$gF;bFt?#TtI3^5x9E2w4WBtNJ-1a$%H0Io89^g>dD$w}V*2RXngau;d4rgkl2tNW zwKOWCbP)z=DQ;#zw`dpANc2~Rn0>#sm9 znA^sC=o_m>2y-gG-mZY=@lTmja9|27t|s?JGn`NOcOe;%S;9C^>m}yXob>^6@?Yas z&U*Qm0GDX~p%byM6&k3Z3ld%RW!Ki5Z{s)9bK6LSn&X8r*?8i>K@2WB+4a)P*K6S5Ho9w;KFRF$+2lwVk%f0H( z&f^=L)jKkNQ(=c>APvDYLf{z(;hFT{uP|~EBAY(^yMWqm`TY$F#VszicbfiSg)dLY zX;!J#VD;RBS}V9PH#2iHIW#|185KB=On9yzURYmP2!}Dby!^b@74-BJ)O?>cMHhuE zAho@tc0+FUBH~7@AB<~tQGmECnY(zx(=68J$Wk=f2vZMi{hapw{hf6)vs(WSyx5{7 z25M;e?*nn<La@^F&s7DVjrlcqucv zqwkt{Ig`9Xpet1lmzyP_=i6d;nvSpn&Ip$MT>2SNdZn>W#*MJ7c>$3B*`j_6&*zAF zsU_}5*9#R>n92t1&k#+|8Tp7@?E|+|bxN{4|wBT9w;`8|DQhv2-di!QEgIcs+G~iA#1A26)}|?>NOKtPY``ZBDPq1`bHq)&jTOXn3wky}(BKdu7x?0C(mw`Zs*LzJIZ(Awr zWE*KdvW9oMxl3p*U~1rVzV2jvp$$jY@|Qj{9hE^tPjl6Co?W}){UQL^$UWvQTK&DQj_w=0E*sAi)$y@RI(&#E8QG4%EOTFlaBc^ytb zdz}R$^XNuU93D9sp_*igNwIr>F2d1*)(r47i=#Df{%pF2(N5|!3T;t8Q*_0Y4buxl zPVqU_!4%`f%ME$sWaNjTPxo^hoLI*nL_90QvSAZ87H~Uioc5*vve;2<*g{l1RzPrV zmph`oR~SLE0S1;12(s(lKJ7MWZb{gQU(aA+x;VQII8H0U5IO-3Jp+Tx1onr-bwPZt z7p_$j-t%imOsKEIl!U9u^`1`8v+-<@{Rnt;MMpy!-x4FLoQR#Mb@Kki!nSTpZnIUm zeake%YOzhF&2dJel0{>oJfLKWy?Rrc3#M=u5$NcpQ-70h8wS^_VI+xDp7>?*u2i2{ z+evkTMe{_8&2C@Yg0ggruYq$up+kC6U0^w`n==b>=rhIyT=Ai@#oN!dz5N^4d(aDF zdQ8k)P;^s>sSwGEz7C%Bd7pVL^3)~GHLnNXpF3h95l*^jS!ITfi{ zX7ed_Eg@PqFje~^=M()#^v<0nhUPECXxPT6YAe&Nt0k}>ZRi^fMDGq*6G?@6r?BhV zz_a&{g1>~Gw3|R*zmhWtI@VLNMCt1YY_?zzrxa?O-*MO*fPgdIviqGj@EiUgWE`)Z z?^TM~k`ORg-ZEHL|G?%uK)f_lpY5J`FIUsgeC3t4nosv99*kjR=X#)agO*MX zB|`gj5U$VMILLZ8aX97NU3H{CwY9a~gGecVb}0-W=LeMq@i;ELDq0? zSWO@`+w_+ov3%^RA7Hq!2a-Y;Vs7N22I9&xr_=aZeSUFvYbV@Y=0b9`V%y&EE%GPh zOCI25mRnW7Ba6OI(d;T>+AI<In7Z*-vR!BK+&DBzi)?*dS z+n$vgw(}_&pvMefZ1Ei(4z|>yPail)c?X+T?q}FInzNXo5w~4>|0qYF-_$?_7P(5B zm_@oO&>~-T^6OWBA}W~=>0F5<-XxXZ#-eZb8LkEG9y&_?VX@bqrX_93LRsuDWS*=p zk&Cyx5Ddnu=Z}1bL%3}Jz{8(#zV}eTZ4wanm(2_ETiF2r6pl z2qY!f>>R_@1%58vP58BN((o4R(sNt}SsKb>$G$eNm0u?sunEF3V_N-?7`6g<$9(s5 zM6U?BD1)u?<+xcyW;|59^@HsCJ3|}D`?x+4IK8;2UTiU%>pCN~M%>weS59s?c^Tq* zkSa%i^?C;`vCb9Qyf}P~TnP1RN3kCut{RCXDV7)evyoViGd~MnOgg4*Vcc$n19IpH zL}8dMkq8uY{bmVI6*on*C224iG|9Engc!XR6<;S#d=5mU0fvnd@+#Os`c(!ZC+CW_ z2$o%?iyL`h19je(OR5Rg)$cMnsoAnngbUYBv<`f%_<-Zy^1W8f7o~9nkFY;NAok;C z%Q4!pN*<1VnA;x7_l`9vioMTg=P!!g>mL;RWR^yN>J!8G3$KZNm@IUc-?k!t8hAsf1@Nu_lzdwH@fTpv$>Hw0{2@c%{nfR#^ms;7UY^|FbbJ=?>M_md zg}U=yEAk4w|2=TaZMT!RwWakp@rg%aTBO6SUE%HEsa!$b5xs`)U1`P1C~m+_m1<)? z_j6;Gztnry_f4|M;=izVkm?6sjXhPM+scl7cTrk~&McVk4#@Ad5OMF^5QUqaaW_7x zQDa$k%wGN~-0k8Ie&j#8c;Sb&t{V2fg|gVY_(y~spV(dvJ!*gd!(z|)%VOVel59JI z{--MOqp6pv}<)Jw0t6&TKkV-W&W6b=~722K+Zq5L_`bv>sNE|A*1L;dPb2koOIA zU70G{t@w77YrFYpxnk!TWX=V>!O_EWGI>f_IySV#`_zv-dv}5YZpTb*4%r(|o=O$F z>D7)WdiOWPA9i1R{N}G4Y?mEVvT{~`t$q@=MTNCT0v|$Nm z2lwk=Wk`rgNWeF*>#tyu7NFR%zG3TgysE#?Wd>@w=zz=+p}qfEkfCpjqy6^i0x?4n z5T2a&%k}yF_I7%6bMHq?&HLdi+<|&XuCaCjzkapaRH4ZdZzZIz{VQ7ocln5WH1Oz$UZJc1{Vl|KBi*eZr9qGUOB|rM4klHT+Hq)$9n1#vD>~* zrJ#*}cV8;f&eo8Mn3H#pqDOZuLEVB3g2lB8)RQrssXm!)9F7Slzn*^7JiIP>QY4wx zUGZqAN)Bsxt2jX^{_;I0R#LlQ(lf{7@XXkkh}hAq8q&yYn2cvp)Gjw^DsT7SST9+Kl9G@EwIy7uIl@qz2Oz zphb~Y5}-r9tphiV29QurYOb%#o^Vo5A^oCN;4wTHSZO%H&s)SKQIO+;nHp~gx*l!w z_wB35zXqJUGyehnpy_UpP`Ce5oFv^c(*^h*p_~A$Sk+>i_=yn7t7Q(KL`xi&cNBU^7zD$DH5g(1BFE!bf+ks6D` z{n4;^i_y$S2BZPS^kxqrc`h*1_B0U>ZurUs|IN3|-_V?IjG)jrOeni7hFPosJ@l2Y zEuGd977=X^%`n*E2zsp_G15_05|x*dw)okJxrNCQ=-arqpy5;9Y=n3t z(2Whys)64s8>;Y9G+@B$@iDLqA8xq!ilLkL)bLLQ`T$&Wac4DAQ4XW<9#e(|jKR#>h>huG=bRdi-c6QUc zUcc1cE!<`+HF9+Unlf`?QH^d!g0ZS1)MRjDfIqa7ip=6|n=jt`SIUR&!EsvV?O&~j zr8eIaq~Fxpc`cy>@$cmSY-_JB9a_maIVW zU%jWjP4yTkN#vNM|FL3IW6*M%2-UKigwz0!lb8A}ck+s}qO1`}V&oz!s0HDg!6bG0 zNJm0i68RuV`IfsnNqJkt1#KNRn{>Ddsd%R=1yNP8Fy&EiboE_FDZ0uE&2U+n9pZN-tOItQjVlw-XpjX}KW$5L zEQa)nq03l~Aiq}9KF;DVn1>T!4rZJkdYg<7HO9EAK|55pdn3PsVl;C8I95T%87M5L z+8TiEUv-m~;dT16W-=>?nhdBH;9Lav76B*5zN5VIZQ^@$Ule7i{fB$)@P=cC!fPPq z`6!V|;oVPzU4Wjt2teq8w%O&zKn9Dww*_{q+qf6L{`_)EdB0K8xelghszZ2@YR+Mv zH~BE)i^7s;fC60;qX_jUFksfc3}o5&y`PvtwG9ZCoCB;s*i5Z6Bvl9U%g}SnGbXu& z`w~y+uO;SWi9EMsCUykoeaxUY4?biWnn$)z?Nnw4^*k3#KLV%jG z)(Yr#?@Gl(L} z993%I3^T0yshJQlz+l2Ak$=dyA7)ryU|{{26o3FT925Ab5oo7p$jlmL4H}5 z1t<|zA=A>d>zdz3HVQV)ym%jmFH-GXOqXu3X8Am`Kcij>=@jtmf>LcmULCaI8Xd30iu5-}h7~WiTTC>eW4eZN&v&_`B(Kk0t2TwN#y7^GpZTh3 zq|*Fh=)#i?bZp0OaS@_+%LuD`>;mcZ(m^#0rv@jEEZD6$b72c9cU;`o1>}-+li`l2 zmMfnw+MGn?`2qH=Y^{fybQ6sGt$Wy?co76`_8u92@37|oV$)PlD{90ut2*sUF)UXb zUTUxHxL=LTdcGO6@3_o%-P58)*M~$aJQ;gG?q43`?)#@aYf0e3O$bD6)eGwUGRq#8 z_7vBWup3MGRdz2-Jatt3i)y45YW8!?U3#C}M7D6kG}Sjc1AN=l>pZDa(V>NrKnHpu z!my8obzXIl=g5%|R1$ms`_)>Du`Iz=&vO&0Hm~~<%O~&SlcS@P6Tj9=liRMH%_~7j z00YJ97|_;U@laE%e|2RIO!ea4hk^33vyrLkLJdYZAxm zj-F^Q9`Rm0yuq@gCqJm-Yam={@)C@0ck5q`T&?m@w2;Foe4%LF?B>o1g6D#N)-rEk zB$4N!?*D$Li>Eo#ipjYo(VwYsX5*hEy>Q0DFj=B2(RQl>i+|)felP(r0)zt1=8>@x z)i)wWO;##KLKINA=G{gZ`{Z>iD1Z~?D=R!L8t#JfjMn?%y#^TbK1KZp3Suoof>J&X zuLfQU-ZMBK_;S?l?@(L`8qM>F;VH>fO?%tLQa_FJQZ9XRptude_|N2%Wy;WTY6XKv z`@!^92D0{+xULHF=E@ZR877o5sDn9Th1`V>{ENXW^P8F@=kR08>JDZ5SfLiRZ)~0{ zWMlxk6d=3NaaPFHP)^#P@wqLvoC;(@TaBAVIJs=wZIvEj1rq|syr|8ca*hjTKPBum>98Wl!Jb*GKA1B zC$C3O$VBl+@=@TlBT0Gntj;~vBYaP@&@H7EXu`!uG>jG}Sp^~6GR4nrD%SK`qzC5Y zXqXdpO*ZIy6w;L}g_&3{ax`klqDU_nxr!`Do|Bv`Q~9Cphl??VEk3=dyRTaJ=*Aru znP(F!)~wi3MW$jqdkQ9<8riG6D%hXG)3Z zvN?|1$pT^z=Z_g~?>>B1(}6--w`C#7OMP>qO~KLzluptfm;FB1%C~N@7imtmYaLFz zErqgkZhO{4CZKP1c_TfBnh_CCx<`kh(9L2iO1p^5=bf*MZM_LLqn!|~A6QrnZ1BEX z1(Ydngs}3tiD7IXk)bnw4|3AbpqP#Xw$COpq0HO=kpK%u_%{sob@1mKaF8Vk2nYoJ zVmHDEK#V{UM)))+IOIJegZ{gyP?+tTH$VUJmf`pp-%9iGFPydSuZxEw z!wOyvB1xiuKZW!7HcbGRC-?MTI*&#rE?1n|4gLUCL4eY*dxJ&`Py;_I6^5*%4Tue8 zNx~SD2|$B`Fma`Ig?z9%`u)!OvMb^bzi(+rCdk?R22k87Gd`)RuFpnvz~u_O-jtaArwLX@aF~RW%7h8j6 zpBG&c_9=BQEOKd8vz2Jn#B6CVueruxZPe`(wA0fJ^**{h_MyjK87Di9DrcI9pz&u4 zk;Z3}L@QJkIfpxgP3y=kRbWOVYiIE_lZav^-@KavUXIS5i1 zBkO|l-YhD+k3=2Au%&CUP&(l(q>Nc2^nz`UVN3CV{hkFz65->DkzdR_lZ8@KsxC1X z!{dI&(A^2}Og4cJRDXT>{1X5#9~??kxaK&@TuVe5_I=Oa1rI}jUrSdb@_0e)M_|d; zc`D5OCvk$w0d@7vbK*-;T9xUX0yGu#c$&>Iq?mUOHsseXn@j3)pfyb0-ynFUh`Xb- zIKT(0l5FRt@7$AZyIfZ;OHW0#3RvNs9!}l~j8^W=qmC4*Rf*cJrkD0gV%|0T>jqr_ zkR<*qdQrwwzTA@wUM5h(;~U^S_1UKS6H+UsV_3qzE=)G0zVY_N_i=%<01^seX8KIK zX+$Fh3KMtvyc9%SRUhSFHR4*RMW^kB9U272X3*bHX-NwKXo_EA`3+>bQtg5kMB z0AZ6E4vv~vPkywyaiJ730N+wZAW4NkZ|U>#uX_^zYf@rLvj#7pvCK_+w%uZ=%rCM% z=OBtvN78vGH@TQBX3{}n110-C7h%d0L|d%lJIar_qPqutyEwai?;0|JcW*X1%{xA; ztp;4aTiP|rjlp7^I!>vbC#MXBT_snOu868r*lMIvPhOI&XX7ZZ?kxXU=$-HaACh&F z)2vJ|cU4}bA{{~NW0}zOQO!;H+$~SH$kR;<1o1;ng?8S!sjU>Yx`P%*IS?w9G&xXW z?kd&R+E-W42lZMKP9TpT#303rVHGM49j=VtB4W~?bgP&qI3oYx(6jDk93{9?w zY3n;=wuUH3f-GaHkyOktr;-3!tE(wp6~y!Hw}ayDuelW7>OG~W20qreCyh}@$-2y0 z7i7IWIEXC>gLcqS-gv=e{CddDBUe-_}ILe8CdH)_f|{#Fdg3KWUM z1G4Mq#8i7FF(JCQpdV}Add`XXnict%j+%o+aD{TlHsaMn zc303sY9U5-#R=<{+-C;e>r-!QUVVkp5O5oM&b!X?94SI`FW@`KfDNcXG07h=KV$aq zv!B-#7Mec*sj0$LCHUlp*X&q1cQWC$J5@#Jle6@=ZrQMPOh4;N}-+mC#5A zmf`QjCW(9XJQK}oeF0FvB zbk-^iE-NSU3t(tN`uc%67NDyLS_k+2r07hxtGT*cyHdxpN-JUn3bfyEM`#c|M7tlR2gDs5#NZ}WG6%55OF21rzWGgA9 zDT0n|uvK7bgG91<{y8QHXDdAyGXg6NT6vA21yq#_e)X#NCyag1aul%sfzRRk_FU*Z z$8utKpJs{^6Izsw7dTZJ#-Thd{7en9OS63r$~0kRtum%sR)uZL`XL>|QIt{H0A(Vy z|5M?!azS~)FS*Z>w~`PKB0ony=!x16n$ zA`kl77DjJC{z2Shk&_m1r%8=Uf%6gl$>bNcn!#_mhi=a=1$>X%XzWE9r40%9v-fE* z4J8GT_EtkOAkQ!4Bgjsz-n|3dcA4*5#e0~&P98;W=RFmkz;1~4zKlrp8m?+r6>Q>T z+nIeAaXL_m*D#W{_F^dEUvzN&?REgcze&06yhEg&dSBhVS>Wny*Vhw0JT|p6-B??3hh*+kH`vBT+}DP+jVT~T~H|r z7m))6njJ51EVh|n&PFep+a=tN3G=FHcLqA2Cm$X(qi0AdfDbvyr|o{2jXOxOB3}Z{ z8I#IsDDXDe4Tt(DoE3VH-D&TCgk*jQUI??2!e_UX0s-Vewlr@9un_C9>0$xLD7304 z@Zc%uZ(L5ll#1ll!xFyQOM#pum7q6$TbM*C(9Mqo+E@S$RtX4-+w&F$Cy)SXis6e9 z&r9jX*+YiE*~2+oK+IvQ(J6>%ZW?>wCYf4Zu6n%WT3XHx>gEDk-OYAC)$ zDi30$4h38isuV;hQwOHdDS+nu#BAY$`m@<6GxwLiad~?N&)!<($|ddctQ=o)4om3|SDCiDpLW4Zq* z7-qt{d?Bp729N|OwmEJcK)5s1h}5hQe(O5v&rNS>=bJv6^G>#w0!H4atbCsQjIcxI zODUCQ^E>WHTB!dxfF@i*tjqLWC<*STueS-+WVXOAWpknb=r=WOE_0Y9zHLje)cD+} zP=H&HcYNG+B;#}N@7>m=!K;DhVQW!*miHh)H$S&Hz6ouq_Q_h^ zN+faNM;S#2TJSgIE|cF;T%IDDQ$lM0YS$GFbjDT^{_jjh3Lgt`TJB#(lF36x47Mu3 zpq*Ta0pv^K%g~9Gh&+`bcI-%uFpoH$aa7dQ1*r&!(GwsL>}n^CMF}~Y9L4NUH}DyR zAi#IReJ<>HB89RS2{l~@*6*==U^+fvwEk@P)pYP%@>i)$q7ZHDyNh>PZWCV0lyrz% z8lpAi>Qd?)uACegZzmVRhzFvcYl(Knj{{}4f#|yYZ0I&cxTpfa5jIb%1degGGwe(DfKp56Lhnr$Jfa{rn$nDIqgqDgki$I1PyN z4#2NC0#>7dWBKtoRUt=pWppQ@+0EYjw@KkoCm_$Hm%pY5*Qnp}amG?MT-x?2WFP2c zLDV*}cUHYGf+KmY0(Jskbmuht1@fzrj?0yR?lUSS%iT}#b_*tO~sX0`wjN+i< zV0O9MOJj^VX+xyM>1RdeyzDwnwCKIwunu*r)X64tlm5che(=$bWD&A8NLu7Sa^&%U zL2AdAhyH7<4YDCu9sf}cXr~&u5^4GDFZb1Uyd=GGIgwWG$532JRnnI_fa6!?^Ip+n zId^BThqbkZMdG8qC!0p+@L%K_)X8mIkznU_mw&FZr4W!OUbYeU_}Q%(F#kT*PBN-B zX=vnVnbtR(Z#Vg8{GrIS9_aN)Rx9`$SS^pybB%#}2RxhRhsmgj&5>A~rU6czKb23^cUrBk{aT6}>mm10d$ z?{~hDPXVi5;FB9v>-|`kD2*cw7p=?>hgu>>FUdT7pYC=$vs~ey+eP05C1Y18-Lnj3 z{t0B`#~Q`^rx}^Vw{MEX{z?fQ8Y28BtqA$e99rVJEKm&i=J$`k20}px^M+Fl_@sib zjQ^&J{I7n8g5P{YQO567lTd?wV-pI#%Ln8D-WZAg@2dW{tp2w${C{OQW~GoF-}3S$ z{r2{@8lM~{#ubA4bA$EC<#y-KK9DoxV&ufP-?EL$H^`6ga{VJd{>!47}1n|){{beW^Zwc;=gGn(2Rq?ie&KH__?t3+0 z)wh$YUj<*RS0WPlC(*z<-Gw2!s+WsuPmF44>3TmOs6TYGE+95;>A*F)=a=gvnb55+&XgNgHPmGz0O zP!VY+rMY}PpFtqBCl>I&qe2Km`w=){1l>X9o);r4mVed+DG2LS>Jw{$N^y09F*x)= zXSj9s9S{AGd<#QQUOnS?|I4*wA&8JzwqzGbTrcL(Fn2x_6urE>HSkz(555?#nmE9` zF?*cMC^t03-!P>lX$BbkbhBUN8ounH`nS{w#`<_YKScXqFCwvJeLpRow`_abk>u*^ zSiN%Q=*cJ_Sl?tLz~BG3c2~+oM{TJ;mP>*Xz;3Q-L4y}|y>;+5A*SWsT5`oQd{9;U zGZ|szeP1NSsEldX(*{p2dRXqno!XB=4Z3)p3dq6nwvEq=&owEgHK$i=YxJh&kvvO; zgbYz+e<6Ucz8_q+?9JW}?W3d5i_>#>7zbf{2x?aEgr%3AHHHKQRg}c0Dt@L;vE0Eo z@Y8X>CZ;tJ|IT##OB>kI4DYqZAuiINmcBH)e{NIL{AEWo_u_(gOz?GddqV$pE@^j~ zH1i~K{CGa=+2`g(%H9zfKN37)=|k6}YW*au{V*HEdZVUBJ(ZVu9uA_=q$bf@;qC(a z+&*XaM9vo%&qw}!J%Yf??|fWzoLya$G|@(S5f z@^yfnqR`uwrDliq(Zfy3=vCpFO;7UlQv3}eSYs!JANz0A1rSJEU&I`^a%aNc@$AW> z#39g^R5k20A~hj9P&&W9AJhNpcwf+-854!?%yVvGSN4C9_ts%?ZEOA~1cw9&7Tkin zJHZJ~kfPAS-Q6`^~nZIT~P{5X@-}Uab z7yJFZ_Oj3E`uD@*8dR;V=0(-&_CF{p(qeE@+vX@Z&T-QKF5pErtQtG!K}{MG)vKnn zNRA2#hKS&88o8z#hccSDI}YSm$pdg=_t=2T5D(c)GE@%PiSvgbd!4SHx=y3bQn@Mf zQq|g?hvhXnn!wsYFS6Q@(jE-oA~BW}GFEnbKmcKJG{5!7pDZ_w_RLeh3k6qo%c^+}mE+9aFxh73b}qeyMZc0}4DYb`h@c z?J)5jgP#a2BC|Cj6Pi!0@7*`_BoqHm%k2RB_QgU047WO&X@IjC~lx!F*xF$Q6m@Xnwt9Z44GWj zA_W0ox&4E~46c2UB#i`ShZ2oqN4E8-l}w!iTU7~6JcgVcY27vKn=?-S&TNc`8dPSC z$8ak|{i$zRh`64Hs4Kb;yooV^t&s6?UTpdP>Hb2;^sLvD;T^wErR{{(cpf?V1?uOB zgBEC{pBJC9UXl(tF37EQcb28|?*BjN=5 zXS_2b;%{9PBQJrUV!n?-`q9*&&0hOE|D}(xv~hIO7dSm>lP0ojJWpWshX=-y)RJlM zR$}fZ!R*Z1-tjxH-5$MdlD(R5@edEjF9K*{98#v` znm(9$D~7i)q5JIp80O8F{@gRZH^k630}^S;J3GfB5+tn5TIHxAuT~j0W2ha#yRQ)n zc6NQ&#PG2w4Dr`5`prvb9<^W1(I#nZ5#C_?hip0e)G?-M;pQbfyg0subxCtV6IwP4Og8*MxtMKCQw<`!RisUOC9fyH5 z$#o$mEFs>gTUKmU+EoFB*;a*q9}X@89KI{s3;JJ~G>;3goAH8tNq&I0~k?F0oQGOOo;>Y^M|DohpP)6mF+CR#=%_0AJBw>1Xv&)S# zRxXcYr%K>iiyZrtf6?MM#KIF{Zgr6+m~SXfx|;%DfXKMsICx z6%i5f=wfla=}pi^Y;lknZ8?G?+n=QQVlyYrpKx|(?i47o>N=!GH(lNNhDDkdP3O!S zG?mZ~PZfl75BQmu{PBI^(svhBcueF5uy^KGgB<_>nfmOU8Kc=B^#*=h$PH3M@jy}@MFJZ$GASVq)=3n@uBL8~Mo!N^NzGzi*}?PG`6TP*Bt**I6^u!LI|$YdUdHpE%k%Ui^2j3a zX4c`Ys7brFo}2Vta#O*{;VawKRx&}F`4PBg4 zEjG4u94#7vv@KJul@!Qajdg0KXr0|1TSbMH%zHA7vm2jH&&9YF%h|GmnziYgg{!YI ze)t6`%$Zv{i5qu*T8Vm7ikxJK0x#EOw%ES(@@|`E&`9sxcg0hE;3fTXaz(8b%BAP7 z2Pv}#Oel~TL*i)XM`Q!U$AgccH5r}IH0A;Gii;VRmRlP+yctE<7NE=QTGoL-Cq?B zb@hcw*3z7r=I5)g^W=LS@P@Lxo0Xi7iiwh;i?67QZKg6tyWXfbN4D z5QrpiWnpExx4pYVgilD2mK+qAQXi5>tvT8|+l6QGsVt-UV-EJXwD}t#?+>cR#xQtR zT1Y`sZ8RiH1P4ADA&A;HC`f`!{MXO7lsVbPMn=ZQYXRgSW>}__nB=eNafES+nXxGd zSF&zK=$ah7%Iw0e-+mM(H|JKBG-X#57dJ#y=GUMzrKk-p4o{EIkIqhlCPro^7S#0g z2B0s?Vq??7EWODW4cb zwWiM07Wbf*NF5M>VD5TxipvNr1;KsQ1vj8G@q5d$@M)UCQBT=V*EwPj>kba+ShdID z>0rOmgM)*c;Nu5RsoTx9_`aVZ9L#9EZHwEx)muow(% z+^&%8%4!Ijs2YoIgAWXo=SDFi-|j@L*i-eMK@T%;jZ-$9X zUQ+g1vf%Ra_ZJ~Xe>F~mUiEJ5%692$L39b*W}pj4acq~L{M|%ch3#C~TZle{Ae5l8 z#0SypGso2~XiQgcU)8N~!Hy?w!7eG^a*Qi%Px*~An}NeOw{4*zA`*3)0L(7OCM@`+ zD{#Z(T^}tvUlwelDSgB!fAI)R9Ly-a3Qk|e{YPcw?_Ka}h@uI_#n1o;xKfS+q`qp| z^j1GB>J>f(wVerdJN9jiawr7jd2Z9sMAILfXC1A?VWO33C}8+Rr~>_ohf*_MtIImPsC1!SD(p6&t3OwBhP`j;4$DDv|a!4Ex+Jh ziDjzo+|bZa=22r=7<<$j6LL12La*0!t4M3zhlvc!RApslM;r>>_bRDo;ajX^WMmKI zGGm5|RDH4J5fK$PH=NuGoP8C<+0k?kTHLt@xnM>u5V-jEI7T#_oC#IE43|2}-{Q_U zE*Bq&pM<t@&JgxO8CR(6Z zNN7KudK`sBZdq@jW)UmP%HeMX_)MkzugoGR+uz9Xzcq`0(lGxwW^smpdWJt1Mm_3t zT3AxFzG#5N2N;5Yjo`WvDG$lc4r;2r+`K%~Hc<^F5Qvnj=o=kVe@<>mc5!|gEL^Jg ztbhQyte&thDJh)9TVrfBH@;yuPF^HgZB1=@R3d!*Q|-C!w!qSiW@?$y_R$f!5!vMK zo|(@6iNRMd=Y{dPxJBbOFEeLBi%OxP?^uwHX9#>AMB^TvGG}1}MSH$2#|-~C4*xwo z9P{C_a2r3y#74IX5aep4>LkbDEu-xvZH6bqA=v$fDkUvR|AVHwuCA(f*B}U_q6Hwq z!uknP(?Na!+rw*5Ky4{%qK)+tjI5iR>s?W?mBsWG3^myM?v_>oUQQ`h z2!V>fdJu?CXKK$MnIUYldQRZW8K^yDE;|)OW&VChrMjwWe`mx517)QoQ_#Nae)rQp z8eYvusyED0<-ACN)S?;b6Y@#SIyF$gJ^*+sfNE;eN_#dafZ_KvZr@a?POINTXe8J~ zG%k(Dp4}cER^Gq{GT-33S937u?d7&Vj}SM{+}PoUft(CSeRVk3YEL%&)iB z4$Kpj10p3L7Vv?m@;p!0BNi0c=0Ai@6moRhDk9~o7cLlLf+6a2Sr1>B(Hk8VbQ5Jm zP8arBN2a=9*8H)2UZkd7pqw>2Ix2vGSP*FRAGXqYvf{_zO7)r1`d>(uor90_f1%ZX zFkSx#S{+ZYSHLzW?#|-vGpc|xb<({lI16=hVlnmW243@S<%io0mZ%$41{J0a@*Cc( zAW4@t1i}YVPG^5GsM7fH)e4~f2oP4EoXx2^x6mW-FZ)`I6a1q2vSLZEK(OCz`g8L% z?Gl%J{o}hK$k5sR*x}(5W@9;Js$XtEw3r2) z);m;a_>Y)aqeM;Rw<0)3ohvFaewdh<lh^%)5-M05nlb|GNb1 zy`|Pcef>8#4e)MLM86{q#YA3d19IqD^}Y5@J~iyLV5FqUIpPikR0RX_zG>QgTZh|~P<7by0(qN{k(+!6%9u7`$RSx#o5jhQYI_j-r>x6-5 z>4z`zuP_Pf#i;}+62CfDn>iQ9IB(pfwj^r;)60GwN*Rj6wdBc&P^GEX)|2)X1;J9i3W5 zfsB@N75}MW&eM*gg5<3iVm?+@sWMcnR)PWo5lUJ0#r24lD=q@wTIo!-wzmFOa4zJc zBE%Uysr&esjFWb4Y;cPg--b3wGLUVS%B`<5o5TG2H?5B5>(ksB$UxXZ+XTeKR9c8y z-~6SCO#0RQW@nDt1-%{SL)RAg?6^~yJZNo(7k%%>R8`&b9%2S3eyWfQ_*E$SW2c^b z2w`XmF|lD#FyCt)#nX3xgl)_jTG_6g^FBbQ?P%Zpa2Z?rGuQs=aLww%%hzqtu;c-q zi@z62#=~paK03l^&SZm&Zg!aVmYI^+jCYA&|3Jr*bhkd_8FU>?BIxc|&CFa%kfMe7 z%h$rmiRNu(PTlqV=D@w}TwI-YMw#W(Rgq&5vjcw9wakqUG5ULt>+EVWf6Dp9{s|td zYJLC8_jC#`IBjPAH;D1^Wn^S@$(kun`bz2P1?#mvQop9Zn8C`bW52BA6Z6rSY@dOj zq%&J9&_71_?)2MP8=sNl1pEPB2dhmet&KMe5V%q=a{h$okIV+MZ`|7WcgC6bnP~kl z6Il-K|L$Rbzx{PmuqX`7^5U|X$g;r+bjq&Dhm7~;rvZiLv$HEAbPEb$Lk=<^M@A0{ zBqv6$xk3yg$A`up4BXj%?DWer)#`Rs7&G}YqHRBy|5ba+RVy(G^9wtLWad`O5t0~N z)Y@5!1TuYI`WaJSs9|0D5E;z%RA22YWC|%28G3UHk0Gq1?mPHay)br`zPN0<#~0JW zv1wywKWue^KL7xCElIUwW3cBdhjO24_P>m9i_5L}q>qx! z`QD8#3Y(emQ($&xv2ODZx`@d22Di(fJdGT4U)WK8Ayb|s|MJGvw6}kHgvW;o4UIzj z+cx|sME!5MiX1$A|BL(EpD=RP|H1t&c+^@gNE8}3hF~X`1+^v>#fsiS)|?(UJ3K;2 z^8CqP@vyRwHnGV(dB(krAX%?QeKvtoemYZV+E1+QV^BaC0&H|Iu9m4mLSeNJ1MDPs zbFA`IK=)T3snU3jnp~Xe+*}5$teQ&d70n&|%^JHQt~+zzv3=JW3zvYcj}&v2rqLzk z!Zp&D2t;9U%Nrf_vu?ieu6@$xFKo8a1$!Is!ix49#=2?KOLE{cW_0hvL$*B8$}@)o zLRpXbkwHPrfNvO76y3FSUch(R+wsQ8x$NDL4Xe@;U>`K_%XNmy(tJ2lGK{}!X{NG# zpkH?HD&&>1=Y3G#Dc_?U_@HUz=^Q#?E*=v0|JzP_rnUbm^#2j*p7&1*{l87R=lzq6 z|Hm@Izmo3%IPzx+{z|&%WFzPO2M+!(OB7I2{9nlRe~YC5FUa%%7IOZNn*Gbr=i>i6 zq5kz5)<;z_dW;RT`3~4W@~-0o_^$so?)MG(HpBzNPKsO_A{oL$Y{0|S7i05ACag&H zXhBwp{buvRo(@U|Evt0}*ct(A_ec_z1qa#3h?=p7kxsFl5#d4x-i7K{R1EbvGfF~N zSIYbthTS`5CeEf@+WhSy%@>T@0~C{o_(Szstj8^~wV|eQZYZyJv3*VsaX|C5EpDH- ze(xjB7A7O(aP~QsS!Nv8TkdrI$dI**bAr|(6reWFmxqg&hr4P$5eJ!p3NwQ|^(!;R=e z>a)p#4Hq}oZ+_vfN8dBL*l)j%NeC^^W55v?5X=T!N9i#Q0Fwa!1hU88t# zxIDJot?6%L4)Xr0J!*-DS!R%sOdYvL>Ux6@@A*pnbplV{{c=n$ssN4>|CKFgBOFtU zh+A7lP)p>)Sgi|3^*5o+ZIR4W`x&5R$HMKdC?u^Sk4D?^d1sOYPLppOwgD&~LBZTjhmF|$LGSYQV#by`V6RXQX%&jtCKp5saYwR+!>9r9C6)O)K^d z>41Mt`z)n@w)NufVbUJbm!wFSYhh_ghz_NcGJPI?5gGX?c%&fZd6Cd3{l`93c&_3QB@JBlbjNAT54|--(maz1CB_qmUCHG5Qvq zC<8@ujAA$~>BeYkQbDV{l&gb5#~O+N@zqO2UTAI(cnCo#Gr=AlmLcgC(G!eGkrEQ| z@ANU>RrA6>Coy;xE+Lgb;2p*MMpBBp{(SDD4?*QQK`I>a2q8?su-)mcPc)I;ESROn z@%eN#nqs}dF#DwzH0IKF>_-J{tvIX&K)A{F{76i>)nj|<&56!gPNY4ZqX53I16ttiuA0OeX)r(+A*Suz79Bw&3DM&t@)3kw_gF15L1e!M0(etllo6PE#u@ zEe$%gY;0(NE`a&_KmGpw`)q5-+{_FFecnA>XoNl zc$Vv8hG-_j&t8i+n(q!jresSvn@1FYm75C3lo!X9xzeK!3~=5Z2a9B5_Qi?HP!zJAhNZ}Z1VOgwAw=Cq`UA+^zo^W|=eJ6ix6|AU{OpPL&&DkObX9#_BgI-DE-CH{n! zv$IpQeBg5x{R6j){g>Mx43A?TImip0*g(aoKRlItOzndUig@-*E4ojjMJ~jxsg)`H zOO_gWRHt8X&k=2OfH`|*m<*qe@8niGs~%Si)BD7El9Kto5^+rsP(l3f4q-JitA;Qw z)-nV?2DXif8iYS$QK^I=%8fGI1}{K6n^Jec&0=l&vcKJbAAhkLu9c!(Oy=Zwj3ln& zsU(h33YIvumlc2qQ81F#Gs{i34xoCci_=cxCG8I>oGOWIM}_li(qIS+~*noj*o**orVR32s+WX zY|(x@0lU`u>RcSKjI45`HETHM3FuPYe(6>Gk*lFCrL5{{6uP)?*XRWA^u5=vTsplu zi2XiwqEv6>5lx8%ZlH<;T*JFs{7|oE15q;dzx#g^Vb=XTBY;ZVV7BiVKhnwBtENBR% zxqls^nIDL$`kQ_X@E-WBbYWrk(9Zhko&WdKszY7q3c=>e7}(;@buWg3BJ*#6I`7n zfIXpngwJ2KzQLGX<}Yl}@6UQEaG~TDsS(HBV_Sr?_xi^cnWoE_6KHONQ*+@3Vhw&; zjKKn$P!m4SFud2;67RC-l0A>hCiB$a)S{VOB293Um8tgZoLMld?6!%>G&Qw^KHd5= zdW782nWs5%H<@boNAvZ$6JIvZj$wa|fsYZETPkxRYij{&VP%6YcOOf2kZNq>W8}f( zNrG);D&cvAGKci*Uw5p4SHhLcoG769<*^;51e~PIv8=GFGP&ys42_5FEB(i_2{4c| z-r0G~J}Xif?HVqcRG5&E5Q=(J^-zBg_bb`@bc&r_Wkdh%OcU++>XYv$*;GQ-jBE~S zpHA%xK*f{JL;?*~X6}d?Tc3b!AGdAXIIl08VT8cju0zumdI5;k{ib@Kl`;A-sw+eN ztoZxsLZ(scM4fLi*+dNA1=bF}*}t-^=rEHR_<+5ke#^??3a=sZi4vWe5TIGeylR|| zii-!4tr5&meNjFb61kc~uHLhl^s;C7DkbrA)V@-2)P9f_yQJBt^uP`i#Yp8;mM+b_ z`R(vCZd<1yCglhg;;10#JdDk)Gf_8FEGO=Z4Jbs47Qdn=5m&cc@wLxXbe4b z<=-Gs$E>F$Gm|a75>3|;ku-?JZ`!cywzOAu!67HthrUHjPtPRm|9G!I%6$!bI2n3^ z*UNxzo|k4;Mhw^F*XKK9Jv}|66%jez%5K`0-x5}is_>nreUG+Zm-q#V+Qq+1ATEu^ z(`3n`kwZ_yd1{!%DcoLr)ecNjY#pewMSf34yJetw6ox&C`tBAZ-vYv@KGOJ7+3m5~ z)uAj~yxS@#aJRQ%-^7W-x+ADmMM|0pMXqr0dRlUnIj1t5;G2BI%esu+^Sx2YC#n1> zQE_!y2358+YOM^paZT2?r9wTj0`a^~)@iS|N6)MWs=>Wm~QDO7`K_j2tMtq zHLuv_h2>V}tNJfkgl&bnykT2&=FDl7D;M9yyJuUSy$coJ=6>Yh9_t3 z>>9gTIqc!_pRxkZbEH>>ToN)+Ey$t6qPW|AX$O^0*LUzxR7`B7rNm!MyHCCk2@w&? z|5jdRkJaxAxV?LKb(9sUB(m$x!OjkwS6X=8P<3CG(}+>71SCUquj>zs-&TBm-{Is} za0;=C{&g|1DcK{oc;vju02+#7C$%K!x2Xx>oWGjMK%=EX6^-Lse+ZnBHJ6}ZDH#~q z`Z0W#rETgScRFca+xA;E&oE+^QUDUT?#})-L>BLq3=DMZbFlR$R-IX)&@NcFuXlDs zOS!dyF5%oBk7Kz|k1w$xjw&G?6Z;obSdf$_jbE zd!&)C_rgW(15btuJJnp{;qS#*dX^5G^B03vKNN%)Ebu~djH(HGZiCT48p|1cjQN_x zaGsy1PYV$^Gru2g|G2@$n`cdXYK4Yy{h&TY(9NDQn9C_RXjQ^Jp|sScB;vALkk6Un zx2=wZZ}6owm4N%x?8}zV;>cZG89YUj6jnI6$XK~w-Xcgja(-(S^Mwu`qvo!C_GF?3DRa~GW+Ewb z6Ce66k#cvLODc4%wApxs@$%(87mwQ6ytvF>)6LSvoDYHa=w{@(c@ z?rk8Vr2rOWqNI1!mqmN9AiK;6gSYUp*e#XmjeGeT#z%D5xe1UzrAD9R(2SDrcd&FN z<1|YYDQ1ZIkGEm7`;z%W6YsIO%V)xMD|E`9Y&#Gkb#z9^qu;uFEfUAt>PB_NvDLiR zRbX7Z%d1l-ERlc`rpm9@?@A|_Zls9>sD2i^@4Ym?G8BHQ_^8x$YQfZeoXk}08kNfF zmP;%1Aj>~=SeUUjmb_ex&wBXv)SXSpIHrR7nS!GIvHb>iH#ugHKu{-cK! zVY)SN#x3Q$#tw)ou}$=F5pL;khdJ7RB+1a({)}Y^tRAtnvR9ep_ZqZ$Z*uO`R+DLw z;i761q8P;BZ$*#}5#}l(6#L5hYpg%lg2pga{x@A@_eS%b=;Aidg!CLGk&X@XjAMJ} z{KJ%z?)tFo}>8KH)f?ugXIzGMd>gdemCpn3#grgn7gB9WCnhKYOHIx*<&(b}9 zN0;pk1UeZYoa{?1=9+joS5wH>GpYKOICR3u0G%pXa>%Pwmsy+Uxb}ItS&uX4_YbcO z^PvRa8Wu|ZVd*)rPJnNpMq!?|`bqBxc}9?7k8U{Ygy<;_wcbHRquwEG7txM=etvF( zK3%KhnzTZHwt3b~&!}nZ&1D=eE0bQi%}hjcvc1q*KQG!~rry(OXn+6yZ72;8!}(lg zm@P{tduw61bVy6_VwizXreJ>Zz`T2D*w(yDb#BXQP|?7Y>AaqSBRR2V#z*e%7HI@7 z`&c141VV4l&CCh@HWc|@V#@0pa7Y8-+xUqJWQ9jLWjqq?{`FRnSL8$&B3M z_oN8A3dY@&c4`I81YvV&(Vab)xGG`N3MO@}LDJtU7o&6CK&!2FL}9_UPUOAX@={0WEDMR zlG7(M>v%NL6Q^Vynt-QsOqV0+crFDZrZ=#P1r_#2#DP+yJUi7EI8hS}g?-y?jXpPJ zQOkxU_RCNYQ(49)GvwoD;)pdih94R`2t;+yBtejdySj!t_PA|VnDieh!>>`EW0d@c zsTyfo;Wk{eo&?sG={@>NiFXb_z$*U%k!3>8j8V%6qj%dvhK>%dynO>JP9w(nZ#+Fc zb<`FkKBd%JoD97Yda6V~^Z(({ewC?z{;N~oPssmq75Y-kmaqDC%Hp!ig>2LVY&}If zNO8#f^W4E69|3ETmY3Z-M&@>cx>Pawa!f>6$YB7LI~YxS06})2!>oC2g2Y4{)f*sa z)MmX?a?Au;UrKEZU8I&A!L}Hnn99sycJIIw;}?XNXO!hQk;uqQZtvUM<5R?KA(V&* z5;{|-Ns&*#jefy~=0%yVlv<ZSL?$+m<%qlCF4ZCtqgYn{O0x2}k( zU$|J(eir|DDdB{!>#K&oeeA7BrZ{x=g{_pcxj*oN-4%Vf^gQWEonVVA?T3r4@BWza za5@R3A={kzAy>&kT^=m?t0q%Rg8C;-L&&mpR!=;SK&qqjZyc^!?gB+8k~jo+zB}{v z!k=6NZDU)$cQf;Uk6YQPkUuhyaDE#=?c#6=F<_9@s9w@`Y!nSpwRwQ7# z2pafS`-zm_6HV9}E1^*wD`)KF8i44GW?}665m3M>=OaEs@ZFEzTO_y)Q6vP)l;yZF zYCxUkwJmR{NcludxI&j@(4)HymZ5u|!hq-2FkWIKhAm`1b}8HAWiax)G8~N;>E0A^ zouZ1cw78WH(g+|P!ruo{JT1qp6B)c>_m9-TPRrxGyo{d;_(fMl@QA{(hfqlZ`ehe* zSyz9YxFWdxukm(?*!vRX3Y@^cedGOAhA-~n=WN8@Giz9{)Xu3F^zV6&#Q=Xg98rf{yds<$O7;^*z4qW7IRp)|+$UZb9UIn?{TAVTv<#8hCbK+RB zg$3|vOd;bYrL|Mvn$WrT9V_qSf{snYLUye78eVNC@mAYT&$pb2K!LMZ-o@YwM07Fe zy}!ZR>%BB-z)CEVKN%rGopWtL_u9UjV8eovdGxQDwXfum!?{J)7UY+&mdHp6NMNrD z*P2zZRu(@RdY{-=&j$Akd>rw1H*vZ4hi$D@1O(a+elN(vGQY(9Jh{rc`FPs6J^^Y9 zT{sjt8Vq`S5L`AWJs`B~<0?wz3OLB~9~**_TazND>8ezo8WjU%H1ADZK!E~Fn{l`VXpHoB@#%3C(hAO`lpgi!RNkvhj zKL2V`%9$oRvlqMXF5zEn9gFfhB=KE+N#@uhfI2kA zW|{E}tU7wr8W!jXVCP)jb> znk5Ss-(k(8wU&ef9RvQnW&yVyy1o^57A&fSt5@1;xak00z{Ad-oVdRqg+qE?rwlur z7L~!(%SiVMF4(F`f-Xz)MMqK==mMeFnQJUJ^g?%3qD=vyYoRH6b!E@%lKVeh6QJjr zy(t3|54KLT8ZXsE@}Qp`abSAj@_EbAJfR@v8>gQu}mTq_^H=h^w*k+Oc)3ZO|2xu~b|$j{^I zP~w-77X9AIE=kjE>sXe+uM7KN%nI#XT3~56*dqZ`6?`~oD#N!*}Af>R; z&o#3uEA&K&(=wWH_TBi@=G)$1UW-jXfObXt)pH{cdPgIbaee?0oo(+6UzLlJ$s(1p zUqj)TMv|Tv51q81)CQO1OUmk*=|jQj7qhJMHqkr!fs#?^Z2;;#i>=I z@X_aQW%|rZ&597SOTk;C#%YLGqw;RE_5~A&+9V^p>GpC9gGReJ_+5`Ng} z$x&a?iFQM)QLi1n;b@-}`V2(T%A$j?EP`-iRI6#aSZ({xb79G6C8|L8=HB5a3!*+?_(8I((#9| zvi4f-F0vDnygaD(7(gX#y5_sUkv@!oTAAr+|m1r0k#z3I`g_R^S zfkVs9<@N-)a!jp8EBaY(xiq8k z;7Q15;4e6T7tG7j572=@5AD^Zp{z8_>NUX9*a|kXb6E+?0leC6 zjG;rTY0Xox8+a>_mC@Xsac-x<64v=MW6jx^Ku@DWs%LX?u|AV;NuD8T?`VJeJqNIu z?~_u4+o8~8Obo0^bCVbUn^|zVv9qEL-(;jMM@|#r6H&N|5M%ylS+DX$P~_EfZBbup)(7eB zQrkBRUV+`jCh%?w)`e5jWArYda)_bI2cl6{a}!nX0(!V)bjJGXkA>I=ytx_Cx*wbO zfCnIZ&$U62BFk0OnBfLqNWp4@Cit*f+smLyF7(Y`M?_6?aeC41Xr0(V98SNaz^RnO z(kXy z6R_Eb%qx>s?K8mE5saI(XMPJlDfW#UMVu+g)uR6O`E+;nKnj)~;LY(9?0&{TVIos> zYDNG0S@khJphB)A{%uB@QJ1O#GB#p*yVAGe?$FZ#y}FabIZ$5tN8(da*0 zL@eJPj;P!$!|cg1f-(>@qml)^&5wRW-N-mGu)8*QqV{*5dY{mKFW+%`mt1|X-xQ63 z&c>AP4YlC;#AcMq7uSQkrN-_A42{(-xVgZ-Dyo9*%*RLwOh|q%@Oz$T$ zSy69zI21N(#7>Yv0y#atw1i!b;=3xg2fy|7RD+#;NKSu!RzYZqFOilHv@hkVCB3;( znutkj{${wWsk^f}anUvD=zA+RdRqq^^2K%juE!5rZ^_#4pUKZ#iY~WtOv;N4L5@4? zmwHTNj{-V*+yY?2>aL0(yi$*B$|@_oR4VhW@@4bttIyY`W9sW61>WNo-3g5vrOF#x zlSwSG+<6a`K)=EMn68RWJu^xW8=&m8;CAYf4-nQ3hKX`GoJeQK$)g!J1=yu;nrf~A z8b@aZ4kq`5M%Q-sg2GeB3rsKE^c18$A+tI-Em^0gNx$mUGKxt7ETsMUvQrU2*xR;x zpz+6z+rkR>ndDD$GGa-eDoXrqW3wX7#^558h$%eIkVAf!hK-6oOPq z?w+LM_flkz?kEd?m@;K=2)Kf(87^X(kh(TMRhuz`_YPdGcAec57`A3;)d+c8$e=M; zR0?ofvsNoES-QxQ#Nq5oAwPhZ&8Cg#Paol@VP=nuz1R21YNM1GVPR$sGn$LNYf5lk zKA^x1^X%;dU;^&Kbs*BgnBwVPxCX)}$U8g$5ve9rqL23(R|~B%un3T!m~G(PzGVRZ z3y%aBf+kc67)Tt;N1!3{GGNs7xR~hYALiNbW#RMwwMFn)+t_R8tD|sRHvY{G>PAqYGSigwmQ#fTE?Fxb67~dZ8en+Cd?+x8Ry1YH%=Ysn) zrxtVW!aR^7b&3~#^WaxaP!Z9{tRHuc=}MW;hyGWFGz5#Ey{>YgZLRt_*l)tqWG<14;Pg^s2T{4_@jUc!iM(8U z-|_n@zQ=(WsvK<)DLtrQxV_6=&AXuS+!mwo#h+CsQ>!+MrQ|U4c|CpswkpgjEla1? z%g>4^Zvv`w_bHA|s*7migHqz|`Cc{YrWMEiZu*f_(tj}8D*6qlNv`3GGvq}H#ozTY z!%JA`@t2?wisxdtgW2GP#2XYRlwbetRQKyaK?_XJjULr3fZFjp zE4b&l)dL^`tsLk+6v&GPEpq?U45W3Dub3111|Ne5Qq$+fN^J#_B8H=HGJw2@5lKhI z1>F%)74I}6VJ^9(M4qZC5G;eD`T==WSz|Zfau-w3@zFzX?i0m_{fDd43UN3B=}cRInDLb`?>-#mLzi- zV;Qf8e)!qFe|xwd*q5#&iGi)lv$?fDZR(*)17r-=%~MG9DJv_fw(YYEIoU?a$z zz{opp)o5~=ueSBwJU<&o<2?%BlNIKoL2^aZHZ-DT<+OXPEYBK&{kF*8_&yf=wTDo) z%nPY=MzaB3X$(@+1ZQGjwo;{|E68+5W-HHsSPLX z65gOW%riru&$|{4Kz2&t(5k3M{fb>Lm%`+P>nd8NO7mG)iX;YF6-uBA(mI1_#c#kk z>^}}0sC=F2osC#$fcZ@cgcZfBM}>hNhKZ3Xdl3M=9L6LT3`71|7Xe0Voq^$3HeF>x zHEs_;J#==Es$|nqnmM5OjRX#%kd?D`+i6Iu&vIW_+WtBXlpc3VQ=~{{m{lE^uk$?(2*8HcXOW7 zD|xwsUBtYbg(4jbQGC6r@hOl`3?~!sPp_n?$?KZUQ<4UN zaA>7fpOkz9#(RpKPet&gpZn(@Qv0rsvJKQ(gstG6a+qbNrl=dVg0>K>{QM5+|ZG9z=v=&^hCJw`s}q%JFc|K<`#6(?iv!2s34%46L;eD zqROz_(&AM4OuF?ekXxnQYvC`C=^ZEUb;fjYC8|K$B>sGRVltinn?BW-8 z#=GAL8_MA!s`txVvS?ZVmH4Q)V6%HxuH*(Ofbt)ohpSE5H4_% ziMLE2i1t0v_zPYvOQas>`w?d+*W}&l-qO6K=EuiM))uRWeLB>Wezb1=+p)%nMqc}+ zh5^daywhprp`HoD-ENtKD*eY5d$OmkLABy<4J{Q#i3Yb9{-pa<8u3!O@|)Ho!n8m& z-n84B7LN_L5j4%K29J$I?eK{SS3LHD?YNuS%B}U?A9<{0MPn_yi`d1(s`B6Ppf0iT zQvLJ|CM}oy{Ph9~58;(Fy&o12q5lw-|L0{4X{A*g2a9)9(sm=%XVvD=5~UAZUWd`r z#mE@pJTh;qUc`XIW^9&xpWqR&WWW4uMbIlIb-G|nvo*g$L8Xer5AjE9P#0deD&?I! z^?o1KRI7V!{Ke)f>V&eFSuvqeU1NRMkY{f462sW!9!qR zfr=eIbN$zvp>ZkjUHpxkle}6YOWtAI{n5LcyLeq@pURZ)wJudsB59XAm(z!HzK0;V z&)a65Cui*&H^A&xj6A3M)E2n+_X~PpT3WR?)YkKoe^z4S;{yB12>agePa)I4e+pt_ zAL(8^f?0+JG(VxNiBhqnU%l+3rBS_gyXc5r*4=E`y}ar8D&n%QTSr&^n%jJv8OS)A zw=hq_=WIi{NHC%LGZ1dPi^}lxJ@T_WybP+gqtjg951b7+Xxj?aVVj zx9CQ~+ezD%S*j+YsYd2mzT90zIAZ;M>@D)N0srb}K)LR~OrYW7F4+|w4@BC3`~34y z&g!i45I(_#a!L>%xc11|=PR_!88g8v1O_j0v+%Wc-ef?S7+=Q~l@nwgmCE=!aT8(; zR(;Y{bYVRy)4V*irVZO^9y%F0Plu*$V@;%EyxL@}IH(^Lsrzom=h0;7!G0@Jc5nM8 zJL{NS5=)}49Ay8iT{FvDBIAfU@$Cu4r&#twRqY(rTg-kGB(+9!MfcD<0^gwG9i?5) z?JI419bxM~%M=UN5ys8@I0w1uGOD8$e813_O{VH|MW`vcFg-1@J~$HSf8jT$=49ab z=-J1Q?H2`#oi@F2a*ZY_L>f}iF--SjzR-_M9XlI@v20a~Y7GP!hxzR^H7V|xPyW%A zn>IC#jQY{B@|7YOPa)ejgp`*3@2=>ZlZtj;&l~B-r*iTT5RKTSCSLCK)g&#n(sn`aAzwo zcGrE%j0Y$5Oze7Ur*_a)s=CV_Zsn*y50=!*89SDx_kogFImh-Ydn~@Eo6bYcH?kwl z981nl)q_t|@@3Wd>o#g6)f=ThYLd*YW(O~_MOjwt0PmFwDX z@)Hteq-K>5cc-YR>j#SiclzbwE=7N4R5OE@<+*a*dDzP0+YMxMJ}~m?ulgGUe4JpO;b@dZV+q z>4X2n($mE`)an!~-O&XLVBBxA`Y$a$ZmwLu{pXoF2au(?>HFLEr`j6QcRqDz+aq;e z_YZ63*h2S*gM){Mhwg&WZoHGc-4?HRMyI)*aiI15Z{{q2xi?_d-$q}FoIfJM5Pv}( z^(cD*BZ)(L1oJ^y1eFcOn%np99d7=~Gx(qRAv`<$sZ*UfIsJe0L-?of zx`e%ry_1@Qp|R<|;cvjIuFgl!!SU?u0!>$)oelcOKQd8g=OAbQ(^KN_yb}IBcZ7d> zG%J|enM1h@Tzou#=NS4|e}peUdFMH4td=w27gzRWtk+E_`^=0-Z_7INv>h>61j8u! zs9uY~ynzch^z*&tCa3C!I&Dh!D<~_s-tCb+x{?(&>)rb{UmG?@0dglBrEm}pOT@3& zAcf&U;-#ZPbVk*Fy1`bhnm=XnOUE0umw_*k3Oe5$!YR;;; zx7B_m*ip9=Ozeo5d{*@?pI%j`b&d7=6vJ;TO(?=%0e{35eEAT>O;U zWnmoyzzQf)%GIAD!&4!qGQ|U%;z(Me%r+rye4rjjw3uvVUZ!LGEY5t!@w=jlig1`u zAvUHzCb8t6wwafqH~B)OE!&+3n1GP8npHY0MSx)VeYFZXz&N#|ok7F01+`cG!mNCa z$oW1jsv2KG+(N4@I-yfb^E~iN^ z^^2t*t?wi9mj+xEg*6}Cd z_)p{mB0y6lbQL7Qq}ur72;gikiD;AvQb64&PjxjK{{GMJT3dUqTQWGHgKF|zT{(zQn3E z?1=wNscCreF3&kb#CXNLqru&JmxfaoOS-(tnhB>Rwn9pN4xT^&FTT6N9n||Fbn#!> zt6~jJG>8G%5u}~0s`8CEp6R+CZ=%j>Z6es!CELoLp??OfZo9mFp<{hus~*}|qzKoo z&CAZ^9XoZEx8oep6D+FD%ms*`=DKUaMF*2hYzv_V86VqCT76(E9X}MX{YYpRZTaVI^4*j;^20l> zo`7q7afF=5L*tS-Lg8Teo)2I9C-}eooM)6i`jpCRlOSWrHe2Gql2tmSiKI4wBfC@&Nqd0lTEZY8BPwAuqYJ#rm)@29uRhEA&nG^8+KsjeffK7Y#hP{KpO ze;RT$L~si@T-psg_|S@NaWQK(=73Nk#YZdKaUEM)xHKEyi7t~5i%+O+fIS{2wkchM z#lB?VmHV|Pvoo?v9c7(psL8n`ZFZu-T&xF{NhneoZTXRXOM^SjIq8}dn#YRv~ zjF_Rlzy882bdHGp3W{bh19o!DFXmw%AQCm@$tK1lCR&@ryd z-wv-Tg6XJJpeME!bL)_9q2D9cjC`0MGSUOlQ>^Vhzf=YNlTI3dbH1$ zbV{vWj7;22YT(70RqQ9mqlkIf+7*3+h?yf5&s~!)-$BJSlQ56H53RxIDmajLX=z_x z`Y}>3RwlOdxrP3qPeMc~N6lf|2 ziL6JT-;7Y)K{@caHy?76BbdNJE6=2Z|mOvb90+h_E8 z!ZM9zSd90GcP)D)Fuspvu0^i$>Cw-jF!I`}UGiZ98{f^)(Z%qEx)2%YE$)_si;)6~ zir!2Wh3&G3c z(RWXu;walSL$%TSbUq5&_6pjHKckWd932N&Xvx$e(DoBIqiz|XUSyJLkJ%!G!$L46 zy7#l`ALG~+LIyhYAw)OoPz+Obon1fsv6Pfs?gs$5ze2(6(@7`ESd7VwI*SSE)!fiR zKau$BR`_wX3Y7BUuSyX9oG4Rd9B#a02oHZy06+HK6w~R;RyP5OG8!#}kgZ+Dh4b9O;#a{p)-c&*+-^FZ52z&$%MB4BpTr{1o1MwZXe08Wrz@?-i8 zHrbhqv_%zU(b3idav*2iiWNWYY$0i6Hg|~N!6_F z>?H123nB+?_xEzPAnv$I{npGQ8Zk~(oDXc2pagJV zvOOY73l9Gre?x^%&!;(R;NZ?0ITLfI0>gvxHJ9N%_=SFhyEhyj{LA!<;(=*f&{C!W zKKM&ek(~H+qDPW?!^vnb6Z8=^(;N~g(W-~x6~yw*iCz+&wt9l#Z9@y}mmqo#L1&Z> z8UiqFlQ4O1SspUPT!qVJI{ltm)py?A1DK7tFo&8bMtK5bh2BixPAUEbY8XP2H=#DH z9u!>wbH39r0pC1l;HM1hG;pH8%utZ5>jrd}F`d>&*^T`qV(ccz{A-)ay?96KcJ32Rd{>0+;`dZV8k>R%q?p^k}&G z)1=!g8J4taF)EyIt!f(c7l&%(_c5gU1BvNzyn0LO#`<7}dzsIm zXzY;q3#$q)lZoRjFXP$F@P_Q}pK30x6!ax_ZK+ksA|(?}<|>3J1#LXu?iC&T>u)f6 zO+U!Ane7`-ZdB7~CY=dqO!-{DH^vMT=SHv>S*I{cil5AimD(Rc8E8izmM61};1jUQ zBmO>Tv*IR9%ApmwoqA1NwH>XYG<)@wa4Rs?)44=ZFcu?~;ZC<(!;1H8@%^XGX9!Ea zZe;PzE^=J}KT(`a@tet;;AOsv8+3~n74HkNi>HVVu4H;GW>Gh;EiBr05{c-fJzhWetVViVMO-0sw2tl)O#5?(or+vp zqNM`QTTpsZpfXOM1H#s2k6>1Rbh-V#4$IjwN&*zP<6eUpgY`*BeM)i;B@iRj(6Z$Uv5+?oyqD%X?>h1QYC?)m~3?*dS^Bkejg6|~-o z)#NQ2XGbL$4y)+sQF<#<7)RQ1FK8749eIh>=uJt{SUf$2zSzA}797D2LaSo6qEg1Y z>hU<>xy$i5kQo13SvbrOA;%S1Rgyvvz%nfSq9m-_wh#HS%fJXV@~ zICce*>6#(6MnqK|@jl=tc~(fBZ$i}1mZo1X`q?DV!62u zkl5D8(|N<$Wwa9hxd{n-u(7dF6O+IRMFyaX8JUt+C;K$fm3#u zx17^w(>hAiiC_R*SLvIFM;^AC@_2FlM#IRZ%05>%eWp0loQ563x@TB9$4XG8wGVHV zndt|lbbvN65g3XSQb!1*8eZ2Xr+ul{&pjc}Vf#nUwPwD!rA4xwi7Ig-q!IqfYW8Wr zfLhW)Aq(xcjHCm#ybV{ZSQ%P zm2fE}NOHPJCgLVoC}%^*@aR6_x?jR~--N5DigN?-rrpJYd-T!EFXBQJ=}dZor;(=? zy%>T=;(QclmcSB|mom36afEnstv#yfT~9{XI?GkSp2bWYF9X7Nm!$l8mN*+d=+*k} zX&#l3A4C#9{4#Rx1l#UE7t(?tNy>)ljoiWg4F=b=`oybk0W}AX)XVc6eGXaHGBY^89rh0LjI_Lmjj}#P&!Ia7 zBJCA@2(kSgCBl*A6#4R)8|vMG*02d!h<%B(#vOks#DZUp5hkD2dxCet!Z3ss$MpVy zpwam_yI>}yM2|VMJ!)r>4~4OJOq%jUSN3ZT3iBRq>&{6D3FpIW3!)i3IsVLzb1~$% zt1X))0hd5;F70#?|HXAnydSeLd%T;*u!zLCW00&ZVQ=K|&dcrx&U?{dQ|%_RYp1WZY z+WeW(>UA}DGfNfh!ZRNSoT#4*Itvw@jpjjO^ldlHHiq{+t7?saJ`MGZ|>E!Y5t0> zZ&@{wjjUIpru|ImGPI(y8R#~Ejm|-=M}7YSf&4qrkwx0p(A-q)zlA;i zuKr)BP*{22{kO13F4VRojbGd7HO6Gn9p?7mVl9`c)9aK{#R}oR`da)hc0X_wFaRFgWd$>$PBs2|6S z{?|4U{Ly0uN~8P3n|+2il4rF9D7HM2YS_-%@NGjhftC)y82kAFo|$emp#*RBU?-w7 zK^QN$Go4dDzPq{0(i=9rZX-&3tst~&+%ESV8%0l#cKG(@a0XAwva!;|S@tAuTYE#WiKR;QBj@T{{~(=*Gs1m*y7G-z5)AHWb(e$gx$kbScvLbXD~o^I z;o(FHr6wPTOGL1^6LaK82&mI68+;F4D z;*VsO%sD@OIU_xJ$sx<1>IpIiwYTOq!yV~v1-_dMf!-V-#Qym9Yc?;G`B!4P0FgWG zm$e#iIMt7mMvw#sSCgAdLA>|dDpJMv16$8zdB1F1qJH*DJdqQc>@fJ;%Ftn7tQe_( zNYbh9x|&sYkV(em<8Gnh@kBA|JBu<)N+9mdplMbTzoBH?-TPop<(1*%?m*^9rV}&# zuGdkTKjqkv=fs5M(9D7r+Hor51~-tW3f&o|keAsY#ZEo#_*hWlXMmcX-4bW1<brm3Bs*=nw-HC@}-3t}4ELCKD-iWk0gFvHJg z0h=w^8dYc7-4)jJdV^~q#Us{Q#??UGLc>dY$V9arSFyLYwY=o~94bxAJP9pEO^ctX z4ZsXje)F03rzi5tMzA4Vn(*In1s}}Fp%<_|tkt*~bA`VbC}%aEVQRye;oXRg zC=^XliNb@tr7#i}gB-m%Q@l9Ig__T5eBY8|fN_b26+)mhBB@8uO7j7ZyvtFGw`i%L z63wgELc)|b`O26;DZ_=)sG9|;;7 zb=IGgK0>{+MeX?iDoieXmX?6rCD)V(@}*=wqPoH#4P%)_bY6BfMQ7t==+Wge3VCq( z9;04*{p`|+PRbO&VB(|NS?WO-#F8+xed`rIhU1QT*1{TL3@ogI`g0~$sZ z?Kc7F@^{2W^sqMtg4YJT-7xmY*=->y$w*(i;e{nxGv`UX(C5Aw^6r<{dC}G!O(>(W zl@PQ~J}!59@TUolTbkt0e)KA(lchxuGE>ONYa8Ou;8HZ^PLfU3a8P3E=+VySr4;v% z3@E+EB%`ZNz}mdIb#K4>`N3FJfvxm=+(LTjbN!MEf)>8gie$|<;ea)3x4RdgWwcyw zdGuky1^Fkz=_V>OwA(7QZOsW%7FAIn*v**|f!@RD_x0(m%^;)4mxlCb$NI&AvO=F6 z8G5!+&V;%dY7yHO)?J&_VI=7>qB@ol;9Dm3*0e5o0y}5idKY^ao5dEar`;D9 z)qjb?85eAWz0n;%GbEQyl1$S>3QmZrTy^Lc(b@*RJFF*pDz;j4haDB!dk)O>JH*G- z`+h1&Wg^XnCLqZBp^D;8aZ}97ms|2~LVZUO82*;F#wzej())~cy+rEBs-U4t+fVH7 zeI}m+%XfW}2>FjTr#2JCzkV*MWNi7U33YGdt9H5Lp&ZyUv7Rd0X07js<}?J$iZfY6 z2M4#s1(cuhe}`@yW;pRtKlFxh?GvMoe{tew>Vf!#bpLEq{D>aKmaiV0t0h}@n=inY z5>jEtV=3wk?S{X7>79Z*J38B{-WhSk$EmPi#?Zax1ldbR=K@;eroBfsJsm}OPfg*& z``>gbs!n(4W2AF~Z;JUD^_3~BYInIp=MA?Q;IL5OnMpcu^r>ZHN4!w&P_FGUUuy8JXF}I8HPB9;y!gw=~ zq6baR5T%hD<58XY<<`~TPaJdj>A;Hur=jhrpjYHE8snqxRw@!`E_V)%K8bwE0!862 zSL`=Mf2zeY-_l^XfeD0bM*g;Ne0Zg4_n}gggh9L&y+ym4g;Zd|R;tc!e0;m#j3+!v zn_ZkeHj!R^V&r)42kD0e>n`%(WO=v^wED%VH%XbPLkJFQGyW>cX2Q< z_PHpPfyJuwQ?R14mdX{1+(q9b*z@erC=BRRo-E)Nt!sQDAS^pq8?CW4F^eWu>+{xoF zp{ure?tii~2J#}m%^~(JHW{+NXCYuko}C8XL#0A`|Sy@?Z`jT;+D78W?&|H1F?@(iAmz*$Y(qph?hr!E^qMiN8d~6%0 z$<_^{&*umPkncvPe6)%D}R#F}r&V5{?dfy$-?l(s6gLY;euT34D?-6N;c6yG8JW&rN8ycI>LOQ<$O z3;Bi6mpG+w*UuOs<1O;X((Pln8&lWJ1U=MlIncom5pr}Oj?(Jx)y-A|YhYxv75Xr( zilc*}TY;X`3<5t|X(pQCbPAb{nv2}#^+ZR{uZGxIcDzgM=;YnKTUYjc-q^u%@l!4& znU!E_Q0|@lMM}@i58%j60>LKpQt`}`<8|cY%ekKZrRW$G3~e|?$qqRzO@wvR^Quax1>`~9Dm?;)`8gL zYB1ph|8*viCImYS_|t%Ycn|vejc!8=Kfn1?xF=J&MCqws*@u0uYWD7pVRdKlLz|g( z;ciuJIF_Q7w=|w!=wWYo7M2A2E$jAikoI>w_Ar}{-`u3-uwTa+^foPDo^KvuDs-!% zz@_Cv@Q%s=ZH~P(87jS{_zT@H5`J8y{^Rc%3}bUvm+bERe&Y!eeP)F52TT;*3i9I@ zEA%Gxt#NLz&^+yk4jEG4K*#=OymD%J8t;2t3Ft=;WMJ_GkGXqNB39~FQz)UVdHHdb z<%|x@Wl)$6d|vdbnDk2+il&%0`SKC4PKp*L!bx~HJA1L8O)1n$5c zSx}ndlNNq-my1cs%}a|qv`xw%tXA@VplIUTvv}JqUFhH0t71>Ff%dZ6NqADL^R-Z% zbKf-w-s_aIaG-f*!Zr_neU(lGh=F{P{#!@>7l|?3Es6%{dRoThVOKZvy__$~Ngr;X zN#(N6TPd2&2NP)J~huS#bLD2zrG${_t%odEFr&aB!9Kf&1 zcP$T_drVEk`{_e@ivSA-X$)h{IlWic!Os%vyp*1)g*Zapg>*}tl4`VuPf&M!jn(Gs z*64=l4d_njw+vX|L18jbFE&ZS(JGawku2|rrhSJ-FhlM0M|3NQKWc+zu4VXS+io|V zb*&}vJ_j`L{!RI+>pk@hjF2_@yTaV26>+85EKsP3)OAB%!!EyPI#s6tr3ndRdTg%C zl4>Ru&JWP+g-M&Po=v1(=-Dmv%(U*$4~JZ==6T%a^~$|1I_%Jw?8iB7I<)l|A7|`9 zyYI$#Jd9Uw%jV^x_Xzs^4u$S*KqZ zh%~vo$`Z!$xc3|U@2t_Qd#<+{k{wN_@fYijw$;>mRW%EccN@Nrfp@W52i_Suf?ihO zsQe~I8R66D=S!6LX>0AG2?3=$%HB4P9vRp3(pVdq#}^lUdXUmq=#jiluPE3WQ%6;- z${1YLz3UAso?*Op4wAf!WYK(m6@0ILdVXTjt9@EYZ-L<41iPTfLt>p57}% z*-=qWc@S8#{hRp#>X@x#IMZijJAFd*dfKEv%^d#ql)~4}2l~t1nW0eTDR@cgxIJKx zxBV~_&k#u>-0&FK==cG8B^cWIk#%b_S2ADufWFJD{)NmIc){vtf+ozMmGpF-v)C!9W@PyNn`02L zQm=)Jlhftq*CH^I2-M`Xr@_znNo&6Pyk4Vy`ucDTOq=zPDExYvx!UTm0eLL9JiJiE zL}|vNJFV^tx^4$mmR&>6zrO$KXD0^PEQfI5*d*}oU6t44&Dhx3Xeu|5>Geuh|LI~$ zgX?MYEEh@B zM$9-8X3IYG-#WuBJZV`wBuzoXtwf~x+JR%3kO;qoP{}4lK~dZKG^8h-7J z*ZG|4cU8PFatq*x)9$oHOleSVKKxt7naF8z!jyl8c;Bp;cOp3|<-aNDC z=i|bq`Et$6dMuW*`^lr02AjqAhYm}i_;AzrOJACp)_jJ~pj(K>9Dgqa9C4#$_Hc_v z;d}nnX#~kygDq$(UpDh`duVS--7Cj-b_k0>DzN9(WefIrbe3}6Et!Qc-wwQyQj_8y zd(A*OYO5`!<&je|?!LR@pwiKAM*f>>1Qs z0=2f6^%!LKYKxyVEKKWFQZw5J_|U{rQ2p*@I`+@I`;)-oor_n%Z!wK7w&Cv)1IQ}y z&LMwq=ng;q=$k%*kcv;OCHq{T50twjMV07mi;&E*F3-F{0%P5M#}R?&>3l4c6L&p-%q*z8;lstip|Okj^Fj4-;=Pna|WMX zRaIppWn=y0h^(sWKLF!@gA4xw4@>{|;NgE#9{<{+FYv>T6CQE+p@H z{Z2_ooLX`^<(aLyvX&FOmh#KF5a+iwa{St+46)mdFQ;&*aYi(j_JirYB&2WFp@hyx z6?|wL2x>?Y7E^bW*?SW}A9vX18AE*V=_>QgO*iu9ZJNd%8-}r~VoPI~=J6tsY|?7@ zU#xKz(ls$_wp%Bj*pZVRo}PpIHbmB{@y358@{L+mD}GI+bXcwx4w=~M1m)R#<(+;~ zjh)Do*)B4|L}Wm=kNLV}Lh_#AkSvRyqH}IAuRT%NTt-$!YZP0iBnQ&ou9Mdpz7-;Q zM;Om$amcg5A----O$k^ ze-Po7V|q?%OElZ`$m?eJnb^o3WZF(aJsw@9J?O}n{pN@HF7|pJw}Cw~!wyG^EWd9h z#n($&A9$%CtCPE$qosJ-ya->Z@kc|)f}vzs`>&m0iE5pWmV`%Q4f*N1*eAVX48*iV zrgf83dd=@ZN#ONJ-Yqkk@etkN(5O;>H}3V0*M7j6uYmQ3PB;kP-moJSrjhaWh+KC< zqKRsMIIb>gCKp;@Np3{Oe0dO5O9aR9qXX__K}L*<@)#ra_1Zu`4Q}GvWW5Ipe2<{E1A)3TD8kF;13V8g zm!2-KUPp0>a*99ig4?`9$w-J7Jb|g|PX2?8#3zG86D=#xZwH(3Gy5H3bn3-h z)mGe=jAg1{#ba|toLxCYvsIj=99Q7?KwEwV)_(B-=jr^Q6m0F#kUgpQqa9P~k|f(0 z<66&2C>*xw6}DR_U8#1&xe1Hfo3uFRa?J~zJ@>DDH{>mwiZtJ!Q5(E)PZmLTB;ccj zatZSxqsX4-EE_KPrD{7eU6a;d)4LqKs;}`o)Z&!Jbmxzb0Nr?s2-~^&Tzz9|N0}va zQ8*nZr~*-uRFH0G)E6iTELE5IX$*!k?e!Duc|Rw zgCmn7;2PRm zTCyF)OL0BFl?w4RpeIR2!127mU!b>=<;V|bWU%mMSqe>8*@|dC7AuoV)ou&IF9U5f zql~B!DYEI!!yR%sooFhg2(RX@blgULfc%Mu_~lcWvVU>L@G!b>214tUD3;W7I3bG^ ztixsHjp`S5O_7tJ7Vq8ixY;$J@it`W!Dq<;&)~NSJxm#IDG+;9g*K#zai6}2c$2bO z>&$UwTC&ucH&FGRN0qW-6j-Owwj*CBVP4-UB|+lCN=^RsuM(_hQ2WSrbY*4fVNx{U zvaoXo?~(;?g4J$#4K+GdXghcPp#UcHzNrHTPpF%?(yW|z5FDj3l-oD6L(_&weyGLU zq+8P-sPdg^IP>=V^2jllX?L4YtzByc+`AH331|#D1A@6Qn_mm`J!-Cm7FAdx3aIz$ zY&R80c;()H522@uh@K)i4lF(v-N^iIDzwI9`pz#+wg)o}5d-WCWH~9{GZ%}4g(B5^ z`%6UWt!^HxEDu?;+P6N3vOvMqm$LF5jh`3S1f5_!$`gRxk}UUx!DADLTYmZ9j!pl3 zBjRsyJl1z?>|FndN%BEV^^eec|5Yrrzr=^)=HmWO9FGSa?(y$~Jiacxo&ZopP3(CKxr@Nbad;gQe~5fIU^z+{$hv2ZakurM%ianLcr7dj3O0Ur#RyE-$DqzGr6pD!;yWcIR5%%r!WnprLPW_l8?i!`v+-u@KllzjuoU zfP@4~3;nxHaIi3(zl%V|iVh8y;4?V}44Ypx=5G>oDo>uVQyOhJ`p1Z=U>Q4coKwO6 zCIB2YXV(;1h+G^KaWyVy)6IW~@UJDH`KJi4O8_LO-|IvJ2m=mJhq}ishQ_TgQr+4~ zFk_aED)oX!th0Uw6u%&}t$uq2#Mi$9rd|Pqv>Vm!#{EuL=DE7jBQ^;0GNb$Vks~=# zr*+O3bF0Itd98W1mZWyj_1!xg(8C69V*2(UUI9Z(uYd!e?HJIc@I^!WgZ@3G=U`oH zTdK7S9%O74L?gcVlz|VES$ol>hNihpb&E|ywynaiO<6zl=-`2KDOAs+&B_JPKksh1 zQg|w_d`WzfR_-}$Ot`u+Hx>HHw`Lk2sov+u=$U+#4ot7f7^|K-9LL4h*J0-L=x7>6 z_IF0t8^rJTSLc7Bf6=dQ0_OPa*!opZ$vJAB`c!yU4led{n!xrN_xP2`35Qe&hNx ztG2{=F*PK#1AZ)fkB+~>4;IiFp=YppDRwVAjAPl?+4uKY&eh>&f+)uDbzoSDxaQazaZ^xvC|Z`-f#49Jvrhs zm-OS>Eg-=bI>68VY>eh79ZYy{#tJ2WYdi9_4u#evE_93X3rb2E_|*$g+iKL|0EF#v`qTik=_w6Y2lR){U|+df zEqBpOT8J}B9pza#aSBKgPAlW_;^yus^{HGD0>{q*~l_n)%Atl71N|OtCI5{H;$J_ zT8CV7KuY{!UEUL+Yah776Mfl3O?7VKll_f=+tct7Qh!ZD`#$JK0)DTcsZVFb4r2O_V((e+Fr&Z@OS7Un zd67e3-bt2Ab?KScI(Yqg^y;}q2mgXoPvh7w8$1g=c?AfyKhq}uCFNVK-#>g424|r7`Vs4wTQ%(@$sStg7u7j=lGFc1St`(}d zRp2&6*nkUQ_;ZFvjQ00Y||rs^y_;Uru3 zHF+GhN1Y;{9nbdh%2$94)t?h&l0Hk7aNkM~Z|4w+k63zsZfp6)hDV#ub8gHpK&4m{ z=cX(zfAL*7fo%5?JqmlIYQ%hS$8sKK1;$J^yaFZ@I7VI$0#KWM{-xFEIiG&|oW?)3 zvpmlGkL<4~;QuTuG}e;>{`wTMbZQ&na;*nb$)&q~utL_-Ata97mYAMwJ8#^udo3U^ zXX1in#`gW!54weZWe{UqIldX;D}b0oFaLg#m!mB#BJoJY0AyYOSA?78}Suj zu5Q)2zlC38ZfaKWP3V1(2;XzdUBDyS%k73dHpy&Qvs3dY(SrFI5ZlQhcgpaQ*G7wp zI{u1FdJe?tit`pMGz5V9&u;Y>A48uvWx1hPPh5!fxBr(KGxabTOTY~yS2;Pr%Jc`Yw()#!(S5h{~gI^WuHUusK9ney#XqMm!`Kqnffnr zvVTda{Wo;`A9?=0AN`Mg{(ov8IlIE}10#>qNCeOa|fUB65$|d2GWrY|2BJY9PXB6}2mWZa0IF)5z*tzmrK>jEbUQcI3e~vbPARK>mBVt*^_Q@W31pq%!O*d;3=`VgFYCj-J zzSEu2l`jmRDymrKX)pdX;b`wEzm!b2W?qELO0j%8_6p$O7Gp2uW=9C)zIrUR<47qp zt%nQm(<^o-K6#)gxio6O;%&dV;j0vIWM{)F^?_scH4GL=`{ZvYNHwpXspKP%V!Fcf z;G#Qa(@px~w;pM07s}{H>TTbJzao??u~uAG+fPDrel-C%``tud$U4L|wJ2cQ&}z^0 zM^)rUZ?y8dFry`DOO(p_ih>%k(0RoO9vL>ux%!$hYa!k)RKMtT8ZB>GXN5hzS3qEu z&m}0{ldsR`*t1&4z!YD0UfIs33^)9$$ms%EdA<>fRhUfP zuu`AuKqgzT?`7)Hx3AzZ>>gp(D83c{w8n7eqISZZz4aXy)L>u&pA57 zniIggl@zY}x<>^}W0lDvoH!{be7`Z-w&F^ViBdR&;{A{& zTa4loj#<;MUoh{a3CqFv4Xa(7AjJ0O8iA>&h%0z&YxS2a?|AK;Q^YGkf7+%#GvmBJ zk{dkIve}z2RX!3c6dxMOdB?5r59=R1bZcPbr+h_y1?)abbG7r+-5XTZGNuHDUG;{e z&P_3}fe4YRo*(k3_l4{E^g+*=OW)heH8oUj!aP_8^6MKwWu;S2)`m_Cn|mHr#|1!z z!j>T=`XgSHL+s7Pu!kcv(SjDE8W13N?%Oqx<2Gg?T)?RR*Y_2<>oqT6JAJfxL;Exe zlii(gZh1J|Rmi1cjd$hdj*ioD!?fCV)7{0mf>R04i9>?jY)JUz&XA6npH$I8LhpsGhN)?6KHe6CqF z+s)|?ZQAUy@k0$GJyQ{mrYn!6tbmg$0afjN0lVrndM#mHJ~PB*b>sdL*=Moll7{LA zp>h!OPu^F6$SZ)m@g5$++SEWP-j1{31f{oj*1*#DBX;-Ghwj`S7>yeOE&K8x$sv>ULCwZHG`Yxeo-6T?JPd`!*ou)6*sgNAX{fWkY`wugLjnaLATxb$5#<; z`hW*!isOcPoYUqxT^D@(9$S0hezRW7L$AJUPIEn9guFOYL7L)PovGG=`XdCRdHo#k zi3Jn0Z+8~C!snqJzCJTzu`2eGM>8!(jx;V0!{h3PMp>2yT*;h`^1#n$+PsZwyQ*`% zW5w5vT5_`;UiJXrn-dg5bWUirY^_^o#Iy&SQoi#jkeBQw(E-5^aaZ*@)`D0mC?AM` zrXA+P>9Z##z3cdk{>dNqITiz6V@}r01tV_Xm*?wN2bWBUYWYM1J=o8^bSt=j0A+khxK{tBI&$*TjiI|n)ErJ(DZfH?;yOCs8nxIk zoDGUtVqkX0;XVCo=ea7odMg5{yD9H4fHtj0BTX5l93xE`mlq>VMMoJUEh9}C^Z(@s z`LU_506GvDND2XuiGJ3MX>0fLYj!=<4W55BBt;c$Q*I3=zK& z5fd{w{SpLkm@tBW7Sw&V=SbvU0f`=NFIfGr0FVxjQmRvNZ%v=SE;JW!jDfcrwpQpj zsT4HqufBR{CJ-~z3V*qK>hZ1iD_|HO3?*S@-gAuRT#VNf#<2KyZ4i2&64OdDZ;a_H z!gV%^Z*A{Rtb1R}#@+?;CJ&*7Wr=JN>gQw3u$lCBF%pv^6LHbCbg=QUi6oV@?# z-CBC`?MwQaYtt9ZwHO!^SIg3NARz1_RtSp8q05F^Z#x4)g-)b|>CL2yxLr*G*A#BY zTy=PMnETD`yPR7EETz(o_FqP~kys7~z1=bZoq0Ap(=gXQ%-uHb}y-gN9;!LA1#r!QZk^5#;e zIp3CDyC61G%jxmc{7ObK{E;JtDh;?;+?2?6AD>;Tc(%?JaAwXs@{(DdQzEONaPnQ+ zJd?J;gT})C*oTwN!4qzOMWjU*`Mn-;)EYQ@mH8KQ%KoM133QIDbv4c8b9H zc!;L~Mht@GyyNvPTna(#X&0Rdt98N~@v??FjiL8@dk;BXC1DpafmI#2N zBm3#_pAlbX%=(XqL%dj&BtLECy8Y7oliN>oW0dho9dbrf`iR?;c0OHuVoY+tDb7_# zI%OgOAom(uPo`Vaq=hW^AK)HNUje0#jJ71zE|pJJ|LK&nf0W1YM>m?@em3gv8SrL* z7Bi-BFtz)F(N}H>Mzqqu=(qSh*P6eGW3fNt{MJ{%53Aq%O51PBcKzY*NY6H%fEX5l zl|nA~o0hZ2w&e-6>I)OQndFp|g@TRghNCF1Fmo{`aeLs%%RW0n|IuZP|0GSFvb4P00yuWVKa|P85&BbA zR+XO~`r`wa&iQP;8(c0AfVGmRSObgc*NraNTf$|$$qF;7b1joGl-$na>q(9uEEKdK zGJXWYA8cKDM*bVAX5W^+{xA04JF4lWYZ#59SOFVdKm|m)bOa%K5D^hj=_P=MB8E^5 z0R=-8j-b+eFVZ1|P!kB!MCrXG^j;H+LJ}ktzj)fC=Q;QN-gm8g@A~e#&mV!`Z!)uI zX3w5IyG{URD!~NC-PRsQH^h1UntHsEPo-We-#TfN=Botzaf;GE0Wuf85TLsJ;}muzm!hE(=*bFY7EZuL|1*nf52&FK6a!0xBse{7Cg63Px3`mrR7_9L*z zbZybDZRsD7Az#z+J0koUO#RVCZC$p~Kamm7VC*`}V}ByT9yvQei7?Rksib#Xi2>RCVaG%y>H_5Wbw?jNSC@xzqhLV3E<+qDgbxaOif zh|C@YOwhWrimrtU7nRUMcQTRFml|p*uL<0;34>S+~)#tjM%p^|yJ!)Kbz|l!;yZg~aoPa6NDf#J@PhhLqz% za6u_n!8Q`~sS@7+&AHEKT)!CYZ&_{wbO}46gJ2(?T zt-GH{Kug!LzLz*&p2UN(3|>#%bL5dfbs%L9-g>`$K_yiuBNu)r_UcKn7`wtu82=a; z2M1?ScplZap79+mIjA8R5K|s>?$(U;0bZ4HHa&WMd}zPtJ)@4oR?PWN*<6H=^8Aw| zbST=|*w2!%Ab%)cz3r;t=JT)S!@KK-&?Tt1E&a9Y+m3v&Hf9pHHp@>JlA z3kvI%%*nnd3G_?ia512_P~9rH1ss~WmGC%4yg5+`mUM3af+FCH*xJBF(=JrSLqbdy zBN8 zHv`~3Nf~MClB0EW6||Y~D#dcF(B|Ty76;qP405%U;{njGjm>)+B@D}nj~0#$97qIJ zZgr%RfZqTYN@QSe^i<+mZ8MjNwJU7~E*whLntqxYl(EFp3IjWz`c?I0W08zHK zCeSz{@wnoB4V?hLGFg09haARzFOdih8Y$G8j4Rf^fEjD-=3aHaHi;Y}n2$z7YIy@WAc+Q9+qb z$t`dnj2VgY+~I40538%mr9Y*TR(i^3hIA6=uTh(H!0&hglWY0 z=3zu~sancRB?R2+!6(+HD6%9ePDGWLn?ND!Y2J+GD}=lr7ElSzm@NZQLq*c4&RN<` zcG=`zeHbmQ59RaPQ_}U49-VA3221X9lxp6Gjf9jlZS!2(Xp%@*%R8Jh7kl7Kc&dO9jp^@z3r4yjTudcy%&}ldo`wRe1TT%Z~{aD zE9v&)=ENvSUyBjG+M3F8A8?Jc*7(W^Z9#|=_!~eAMGxKy{FU?pr834w#=8g1 zI4{{TN zdj61!N4V#!EWPRwhdt+SfIv=xGA~mDO2)uTh77j0bKZzFVTynBu38}NKB4=T%c5Cv zq0nOMVD}Yu^PJlz=8{2>&jJpf#o9uVoZl5j9ifO@dG$*b1G8{(j0Z;ESRB|QSG5-b zK|#EB4ZYY;nFH@w(66tEXx(mH+J!B1Ukr-%QUX`Ev#HO&R;N#3?Mg?HRZpoQG24kr z^M+5j&Rw-NDSf@Wrl28_bM)0o`UEWS*XG*?hWNt}8ukR4BVJ`d)Z|pr;pn?6;pt;0 ztoYK)g(vtMY*S~Mb!z6Y6*Va8t4ia9FI|{$cVo57I_AB|L`+rEObaNzG~o4@c0c|r zmJdDC0L0F?CwHe_U$wmOh8HycmZ1Z;Lm2ZBWhlV6?=${H#S4Xh*M!3ustb5D( ze|@8(Eo%F_!mRn5!raowsL!aD^&5c5?0-_DW!()+zJvX%+8_PIm?dlN-3NZ*LT-DN z5ghJ)14M=H+!WXw&r~`Jqr2=>_0@hZ1nvzF;;Elz&iYgDh&=Si)26y1kXhfGlG*Zt z(d90LLnUF8G8(UYI;-pa#vyPUU!aHKv%?1>99<7AuLu>Z2;3)`RqI?xOg4%uBM{X( z9yoHCB7z*=FO{9L_m*sJlR#tTAJGDi%pZ;#JgNMKJ=7)GzYi zA2kcJ<~qQB!48l*S@T6!zeyY4*dqpK!WEV3C4)cTjtUmi4gRbHett4bQ2R9a`KiH) z19`W4ZwyWxJY8fe9&Fh=HN_$+usNG|=RTwG09L79?7lG1P;us+7RK499E&`I_^th^ ztP9#eRN#`zH^9A=NF|q2*I~s|d{S||w+6n0Wqix|Cv-yhFw^D-X0stR{O8RrLaREgUq<|~C+ zn*?HjK!=2M{B68wS%gw{*MVxqr{CfJ<751px1W3~20EnpPxSUMIQD(Y&}6Xa{#)NW zV?0KmXFNtS9^)q?!Y&%CU3@CMBv&s~-fOHTw!`jJFdiFVXJl{N7i@ohL_@N;05*0` zgDFXgPwR-NdvxgS+5^>MJEt^2!r)#^!+O?|$<)?;12Z8F=Mx-}5I|G!#(STjI%KW2 zOPL?WR{wS_+sDjo{OztR>wr1k-zzhk_Iz);Nc^p-umj`mi>Q~vS07{Z(Pmu{(B>n)jbA`e}6q%>-psp zw7!=8+U}+Z5)7uv6uN+Ul$>w@8xScpqKv;DQ&M_aIOfkryi=m(gDA zK5L9o+!J={yL;+p>Z#l*s@2P6x2F2ePpuXEXN;6en(Ag(z;AB%cL=+5qc)MJV&8oq zf;gke-`-^_7mc=S-{|~SD>^Sb;(z+C){&ReJ>ll)s+Pv#_YGk9B05hy62*+KDC!s&_mVwJ#vmHn#|4h_IX0Q1Y{m2oHJ-LPE>1vh&<|H1nSZc(sA&19_#DdH&D#@SvX z_>jVf!wjK7U`5FDHvb#{cBczpOtaf@RTqbc&nXaYC>~lZQ>Yb&oTdv4d~x~)$UE#) z=()?Vdu2}SL~u1X=N|P}@2&&zzI?%)niP?kCuR+8`3AWDHFQm9r4qOZJh{7c9$(o< zC@R8`l~-CaXz>-byeu?%^G!rb^2>5(R`>9cXcTQUl_KzZk5V%dx##yqVEmQKv?#D~ zlmi}!;Pi*5TIcYJalmt%c3EkIRvjz3ch%Z$Hp^Bf3XAfop#^5jWxdOK1w=Yrg#dyr zHrg9#hCmM9@sMoX)KD9bL^+08@cs%H`1`mPskQ9xIdP4hIF1}_Qr)KU4q?{zN?GOC zy18Bnw-M8k;!s76vQ_t2u+!3c4puU5bad!PmSzO#muzt5Cbl%RynZ}9(;wedV%{t> zlRvWUtWRhAi1hjk0l$=C_OtImMRb}=#j~evNBFb)iQt**l^v{NtyzDc@tgk0v}?}q zROuk(7Z2osF=`hlvU_M6SgkaSk!GW))tz9Ss`vHY63Sk`9Xs*_+3h2^-TP;kx1BTd z5P#H{#?F2Nr0r;JX68hZ%(9YIr8!p9ybyMkdQG`UbHti#tpu!>;x_rxlx|OMXB(EN zY+BjdyE+@OtG|oj^>u>A5L$;f81_vE=X2f~*z%FoXAe?O?I-#Cu`+-4&94r83$5?; z(F2+_WJu=?l2G_6u5F8u76jE!-XKeoSG#~YG%K%viQP-02Q{(-P&kCuX1F{P21GWFj78eq*M zpkrdcdhAJjfDVjbqUAV$X&r#G2@hb>p5ng$Cyc-Fud}QH7ygS1|HO~5q6{#daSU>F z(Zk;6mWt723ZN$lFL;z#nNvjf{+Q)I6S642WPNx6VeZ*x8$w7I?MYHr_I9!hT^Crw6pCIt?^0&piXS}vj3G}ND=|M z(rmO&-?VZV@_Vw>ZXMAAXLFtCFG{Bna4~F$dnHC>ed_&a!YXBDKH~=3O;Eo-`}F$8@4i3g5?)ehkS;Q${xpD>J$#h+chDL zSu3eG+Ryel^;>%gN^+P5+qm*44p|AS#|lA9nv@%pPGSEfqdzxG4@oZ>$?lGku3zw~ zQg5@iBC(gn3~z)+5#9(FHf0*wr&cUz)kO|50m%aQPU+)VO?8~fx@k1y9p$igm>*h?SS^_!2-Do1d}WU-H*3T`lAj|KSr()Vwh>6TBO zdT0I;^&dHnKk2{Ald?&tYqJ>kA5Mo|qsO&>@UcEb{yIY=(-_?cSUt-nQX6sGMd%;+ zS@!>+7cJj^2au-edupS9cFv$rh2<&ssDLy3aYcWb)qS)n!b;W(FkxeE^I~m2eALo{ zza3{=-CkXVW;Y&AylEiQF*nd_^LEs7-F$vY6|C9wColPn*QV?4mZ)wnQM6UY;4IRp z`1ofC*@ZdVfyClfsF}Q}6lA1KV8JXj*kbDA8?YemT!B9j{m{K8Iug9p29X(EJ}R0; z1+Fl$&&QZ9fF5~Ujy2rGjR_p={kM)Xy$CUYZQ#VUz9!_Sc`p}3ve~P+nfw8$$1u;6 zVryfa5jyWO+Z!A*?mdCYK83Jv|UVs9; zpeUTBG+$ipZ&TSzV7%9 zkneac@Rp{gJxW6(yJV_7C(I5E7g%Cw??)A-qfN!(n05{|zjOXLMl$qbf8A#g&piIqfYAUH8;FnL*S3ROJM**0A1@9X zr8jO)&6+GLRxO@v=Ra^zuw`jil?j+-_Oh3}q+cc3KTJnuXV^KMmg>@N;%l_1!Q%Nw znTDJSj;@ogoSBFZAK2JypRqe$l|4!*`Oswa9+A2~La(W^NSo)23}>wiLw+57{td9( zH2)2-rgHl+bsT4+*Zv8;1qZV&Nai=m6qdhQK|wsp*$b*8m~sVfPZ06RBM*BEO-28K zpmtX`9R!CNTl2PDT7>@ByE)q$Ih?cjR+ZpX$i5hbF`z6HlgF|Xm_RSyo4d}Rc)H;23ZYYYhA-n3KpAGV1ryLz@YK{zs zn08RH;3Xh7qtb1pALir%eb$+d9i5}wNIEZV0q%CsoA#O6 zAG6fah5D|qDnz^R3LZ_=q*bBptc#ZwK`&!-OC9EkuNxKBWGLoWXGyW2fi5?e9Lg8N zc3l@6RFb3(#*jH|(pgm?S5|a(&ajkR1%l%w=4v|i>T;45%9k*NJK6E9rEuSvRDL$! z$6Lc>RrZ^qLxTikx3K|Io^P$Ozs(%8IVpi4LsNdRmR#`Yd?BDQBicb)I&=PNl^}1f zT6RwNJiS)6JJ`eU_za^!zt-S8N@Zi@nuMl?#BceE1k?aC|Kep7mBm{9@)RA`h z8{l#1E_JW*lePJ0iCPifzNgKMl#l(ync>ZS(J9quCYCpUR7 zms%}BxUG9Vt|oI`5$oESUit=DEJf0o7!I6gJ+h&{gq$B$ag^xV`qalT5!y4{M$8U- z8(9p42_8w8nAm;6@YIaED+jn1{&(tC{HNYO;_p9r`DeQN4_^L*m+$=L|EF~Dm2u&e z(!v(|r#F3g0>81HyOEWF)owTRV@qCwe6kZZ=Ca!;x(s^GuO!;o!J~El8(_*3xm#ZD5g51xWMrE&>^Z-?cptBv zh#}qA7V`Z!N5O9e5?uvDO4A4s>DklOAs=-~LjPB0{zgvuhDMrO5G>&3Wz1NKx)^`_PPZiRcQ`hW7YA)XKj?*_3&h+Ev({0e-KXMBw zgqMr~9$E1oWjLtBrTIdhNqOen)a^GuyP)lM+~ySgYO*nMhm89MNYM*m_=*JfZsk$- zDyc4PyuF@g^~Gx?BP&m9vif4IAehHu0*j3e8#;G~jXlvrGP=49BAIuxRIcN=Wo5tF(H+x;Gp;UvBLni2DIvBb-T!2gB{-!ys?ADG&Qp^RCGw>NUL zo3@UGaC4gJI%k#jSzMQvPVv0+(*NZJ4WGsO4@XY%Zn92jb|LRBmCX*1;k-%jp>Xg( z)@t@x0hXVz_F$NwDI<*at$-;Sn~K`iBUzDFFsz$I@DWJDJYo85ufhR#jcn@P8|&dG zFfWXry%l_Z87WIf<1a#pUmbB$>n+&-pGp zll)!qqLPWGA@!`P$c0$7hKnz_T9=_AFq}CXOQ=(HbfDG%UiM%ixmtRdhb7v}Xv}#8 zQstxBbbdUeD~FQySle)hKf4kA;H2^OYI)B^dRL!7XehL?)v39#O4lCs#swv5<3^#3 z&c|TEZZlyadsTh$Mkc2{vs{HtW!5B}`^v{ruiT9LI={Yp6CB+wmW^K}f8|iePM5+Y z&@X~?_`rzlP12+dd0{pmezd00em~Hef;)5!u&tl<4AYNo!_Dj!b?NSXl_JQ5%S|ahj8pq(aIs^w6TI_gL zc%cxsyGuhxR_mdVOT{(W6V^R@EZ!Un9A%yq7Mxa)nQQIUBB?9PKRw3a6=vt7n|$ zVOs)P6sJmuaZ@0OEi@$Ae}tQ==0Qad{E#> zppUUyv>`oSexHOlA2es>lEBDQ90g zlBzv(Y-?JrgC?$1dkF(hUMa*0Hz|*vg2to^58)wi+uubd6Y(AzB=o?&C3XC}Pze}r zwPvhSl{Yuk*Qh*nyjp2I+?+*$Kv}~LQbZ*twz{Z{z&y#KTG|B+Bb03;l|QVY!VON<)5qf=tp`$gv%Rw?#`{G$yKO-4NFPsa@k&RR`{Ni*+wz=Jr{ z8&5PPy?xEP(|dF8lhoET0pd+>^iiR`|Ix2mx$xp_27obc32KGas^waM{vLg z?{unkL7ZvamL8_Rge2}Ar^XxX;(cQoiY_Sr=;P`rbmX(RI4$*dixQoI1cO)ohkcCC zBlIeCozPVJN{a;1N#Mcy7o*f*>aAH@Gi#G21?&ba(S~b5Nd5E5ND0VMIPHBMi{qqo zi1mjfXU!eatOdS;Ft4YM`r0NY>BX8??7OT8MTtIb;YPw;JS<(1M6;_<*u483W8n8f zgLV5=`<3V(#$y=a0hQLl1;BxJ({r%dq77@Ri+H}0GPN+~S_#U&&nW&lJ9L*%iM~P^ zTq(KPsr}`46<%~(RaU*&eOv4!L_AGqpm>Da&Y109)A{<&x9QiITBJ_CBO*}g<0rEh zu6w~rt2S^G`?IPZUhWR}NXCpjDQ_nyPWd&KF!L3)jF64&hB^tHdyl&oGSRXjIuR7I}=YrlSm%<=F z^Wn!v<6)b z6u_$~>Ofdu%dL6ec)l%;5&^!$R|(|A{RNzOiSLes~9=TTmsx^0*|vs52-DZx}T zyPT7qZq43FeWWpb{v^(ESa{+VdD@$e<@u5}nO@(M`Whw>ud6&w>>)AIA}8+sT88sj zj68KUT%7cDegsw7p3(OnY-sgaO{+4fh`If-r`v34z#Y=SNjsw%bNWP7qimZM&*K(k zzJ$>I6^zTlqU!=l@BFBqA~~}``I1nq?{JcYcY`i}w8GWmqA80_qpItxlPQOp(6k+7 z?0S#ZS3H_DCc0W#(EhHo(bf4HM^VD4UN>>OI@^8VGFk0xkMXt6CW7ksea}j?cl?!5#{mFqCY!JO2}T^>|4S)uLQQ+m zYJts#Vo(3D9(;_-GD?nSe8P|FajNzs=NP8llMEdihe|(|OaiVmBF|qpFf!Hp!T6-{ zlv`wkvfrWQ?-Ae7hooJty)WBDQATv8r2E?MZY6?Lmbw};_J%A~V7qBerysc{P^~FM zI%-D(ZibG>GVBfGK(DvjcMYT&hKTn*6vqDkvfY3Gwr{*w=9=aRnb8M-?jcw757@s~BZ&%Mzw;aH-rojtPh0H&h9QKQ{Id8A zS0y5s^Kf?7jCU2Az(`nRIkg}k3HXI`he$7F+}Ohf+-5P^yY9#s;g!@4Yf{&qp$)?> zu3)`&pmx4?Aay6Vo^gmju3bN-E0inBu#YD&WB}xP#vw+Oe?B9`U6`TN?G=0j%-v+$ zYhVZgVdjp)*YzBJhAzE@p*nm6h+Rg~crZJ@eT><`fImS$g6u$|fLr(c80iuN$XSjA z2Fe*r`7>ypJ;*M@F4Gz$u+4nJ%Bq=+k&H=4 z*j-pziZ}wex<8%?W-AL-Az_w*kjmh0^?bYgQmD)a{t?$9Um%c|jsXfCuzd&4xcofh z4`k3Gl`m!(zO9(I9nrRZ#)4-@11c&<_J$OVED%)(t)>d%eG64dyDND(@cm)0S21(+ z`1@-5dJ~oemKU+m(Rsd%P?l4wAl7`c2^CtJhA{Fms>sNgqDK|SDDNi31sj8cq>}f82DL#8bb|5ne{83@60CJDORtR zG`wytk$vn9&0E=4`-P|zPbqYTIlPa%8K4(~9%EcI_7ja*|3r%iEwU)>?Gk~`HKnk} zd0iQhm)_`>3!^bCtNUs*ZQrrkU0$yI`_Zj0GEXS599!6Ln5hK0!q9`c6qr*;--g3 zM-_P*3F=+&nw0ts)=2fczjnq`pD)Ornn1DNmy|wUO?kl6Y$M`s0$B!p1DI5p4}IMP zMfMe-s}e&aoXVO{^l1)szTZw^erwnR!@t@xQG%Eg`hw)uyK=yk8Ccm~^KJiBBmU?? z1h(hXqJYtpd_`i<=LU@lOI4ougmF?Ai`sDT-+7l=7rhn+;e6QJ`o{)5n37ymnajIR zYNWDVRg0hJ(nHE}k`8x#Krbjz)3~@Pn?T}OpE4RSgLsTAlB?gpKXs^n-}D(|VBX(B zYt)h!2HrX%axxxXy?naly?N3MUqW}s?H1&~_PX2pN?V;YzK%s=Lc2U|)*3S0;D9oo z0r_fF7t)13qMeRz(2)b{!>$b_B&dJT#TbGD!q@ign=i zY9MKw?9-Ls?xCrF9LL#R&mphu3~5V#R8YoheIca3v5Ekf zf%f@nY`%=2&X+i;VVW;_uPfY$VK~)xulDntNw0ReU7AB>o^xM5vHW-p6p|s(i|%@6 zujz61n1F>&^>W0tkmuz$0RFd7CDP`Amer11Z;@_!ImX+k!#Mbvt7CF_Vegy2uYsw< zJNPl~q?;$3Y88tXEGJ4U=lsM*oSK9?pN`q-G2JyAjN(-Pa4b7QB_2tLa_$-iKyh6VRV?WaJczdHszq{cV<+Locs3=Jlin$o<#b{r|*+ z-5`g;|0*Ef>ZXX^r>5%2lHpu*=&9a5R><{J$0ehULl-PIcHZ`ec<-J%lV4g=#`rwC z@A{)Q1v>GgV<>~Ke|{3#22%Y)lPV9)v&0_SDgQm&W5g66E#&nLAoZG|SH1nO)u{im z=2fYOm0KZSFGu8OujQw;S|rSy8PEcqsE*|o1J_^ym9K{HkWO60njl%MV%g*bl=v!@ zKXqnp6n8@6E7&^sO=bEGe)bmILO2{cHKWmi9qv9h6skFNFfw<7=CwSehI>*;cY_rR z^emxPsvy}f9Fu|*1G86XtHmjV^|qmt8E1P@aFG$Cn3;)0eZ8mNNrYJk(2E7-;mw*x zy5#=(A+txUQmV=$vL`R%se;QUG=cKv#hRpqL^vC?9B5pfeSJB7^u5FAu$c`!lntf< zKWX77klQyrb1aI?PQ9JbWJpeQd(e#j3hk)L83DIdpQl+s3Y_-UY$s^Ud%Qd^z?9{M zJ8CKS*iK8eUp-s%Mm3Q@r;Sw>N=o)SdGujavM|n@l%soHpGXmwFkb4*t*XiFJ3Hg?<%p* z@-Zg}?wc`W4J`h$R%M8UE3xiZ&1SGgykB2QF4U}H<;)Q6{g z%@q=O)_k7(+39KgmpaX(jI65L5&v}S2%#!>vM2T?JFd9$ncU(%^-bmg<*=RtKp*C? z5w(DEN0C2oSX;`1jDNf3+d-Y{Zh=mD<)8buhO>#XL|5o_iI?tyho%y zpSpHGF9y_)u4#-J2~dqwl{HF({;+__q9x+uHnsuVm6BKNT*c97+pXe<2TMLE#^ElG;CKq5sp(}Z3v!-0 zbt5VvOH31*0yAILR9%i%X^rl#N3veRts>vHdV5Eh1D|~P#lcAcY>d>+Uwz}lq?Ul z%Z&z%`-XO9hHxFQ4-Wm*0!O<$Z}y5(c@9s;e82_7-*i@e;5fkMB5D`EdNsdJpyzI5M?n3c>y6W{h2 zZ0N?!$hMsYL6W3A)UQ3iS>nIB z5Kua`V_1TQ;l@Asbr zk)SrP^V1QEWgNAecb6SZoLSD}7Dfppjv01W+&THmmmx{pYt0T-9z@38jdy}xLP~!! z+NlYB9AV#nq`UE*%J1oZ40`-MeeaLFyoh@{WFKU>xzVFNI7697Us`ve+`6CN+1i`m z+44^N!-7}nPWB&J-0s(Zu%QKc8YKQrTYoYruul9li<_a-8-|m2@Za+Z#s0_4`;X+r zzmN8hBVtZv!n6%lup23$3}&I;bxVb^6pt5nL(>Bu4uR{~=vKMBFMFBO66pCjwQ_0w z(8$n8Yg8~qs!+$1Fgd^KI6Nhpe0}ba63V?WWgZ8V4bn0_VpBsfwmc+L{lP>oFge~= zMM@ABn!WQJInef)>O|#Z-RGZujH}U+E)pOYd#Kg33O(duvdpm4a|nPah{$J8iziFg zu+Hv^$=PY$`wlHVe$%&j$LACB!M0U7p}#e_%iH2EZ}6`#y2tIGz7lSvT1bAXuVoVv zr)j#Rx4F3{E~Xj|F05w8%GAXKS0&y%Sru_E3u#FXYU^MUdz*Z>ndO6`0*#RpGh;OF z=jN&OTc&{|Bh%m(?+%h>K;JfEUaEs^8d^b&w1<(f!;hQ1#dw=PZR?2ip$kU^R!)w@ ztE9PiW)b8hP+V{oG{esaiVUK!TMcC|;H$p@!0BPv!FQmrfQ3iDm~0(E&BM z$GvZkjOeNHzuDIWvt0PnneYz%^b4|sBO~jp$<9Ka_LE8k_)3gjf?STMpO9G}t$!-y zd#cZ8Zjv_^XHrqN+Ea`@f)+-xFOQZi|ECh}CF#0MsVzSn|Q{iPM1S`zg2{OzSou_gBK4 zw#(2EjL#P9$?|ffEZE2g6&&J~bE{S1@~o2ZKp-}FDnQ^|OaSck5I^p0VeTeO@9^LR z6WkBB?E^W7e3UgpN*8;74H&G%ZReo`cV=^nY5VIus`OeVnVQZB@^6ljtrHp_EIZ^# zT;V8t?UE0wOs(bD{^B*6-e|g)KiU~1X@ko(TP%N3g9^-tN6SP9V<1;&>qVI;_x6B( zec7;t#@P4%o%Szp+>{w3LYFbxVv{&3G%5 zGTmt9jOml+i3wPJvu^BGQv77e`KEAt^Sh0b;UxYB=Hpi~{c=qQ)${_U=Balei!IG9 z-aM_BienT)&zBn*OqjV!sW=1OUxX%F8B20;nN~`t4Q|SkhZ#4#y+xN*QG&hgx||}* z#nZGG-=Ps8_gFrpA*pkHOHBAz|V%n_wyQi zJoDg!yHp9DGqNz1w7+q=ItYz+rjML1Sh{#mg@@t!LM-05v>^?7(?gsUZEzP_%@&J0 z^Mar(t@v2m{bJtO{ti!#fG0uFgY6bA*MPG(7LU&*9BCh;Ls^)GxB%84vG;jgQEEE?yt6 zFE6agHoZ2#&-?ZQ-rgCh*SPewJjkU~Jzt`=I67Xc#i!enV7W<{>D-j*@Xpp@x5{0Z z8?x*AfKqR)905i8d3Xaj)nkoJ(H(Z`k!DhJU7x1}Dc#{T@hwD^8p@m?uaKsIK0ycu zFcs-lUL6g|^fI=Wl(JV;Q(nW%af4S8iYko+LI)b|rL?hm^4y8Tuk2HBL|M6l{3Lsm zx7*T4HWfId^dxUm$n7gKx zba2HUgf%75UsNn(8nk=(Se}~u6KC}A=MD81t+YGarJzgPykbKD{6Hw;`hRifU5ts*yMTQ6pf^5WBIfs1Z=ai)<%5hBr7B0M zsOW3&;$1$~H)Xfqj2#LG-GPk3>lUrL`7(r3$p;wHr6wZwYhOvkd@e~%BL~bowq*92 zT&i&iVktRhQ6e=8oxrj-kCe`%!En9wc6yPVKq#!h`yz>pG*Z%9SR}7NFk59#ak%^R z2#cZn4)PFGxMPT@^2zV~*IIj~v;O56{)NgdPO!W}S53?OUh92il@u3WU&^MV5ZHa`(DDRmo<2_Db`q5S3Nnlx+5P)Y->7o3eQZx1hKZR zAJ%??-L)YFy^A#+=6jG;X{3;n!J~HPdEh~p-SZQysJN|L(HSQ9Nk(v$&$45hDX3u$ z5*X#LUNz3mTD(5#NC!391oLL8ib|PMYw|$JS~6L&#lCpAFL4bSW04+mRyu1Cq#}so z@KM--z*=ntFw<4Ay-U{9``i=`f}$sroqT_-6$`=eW ze-h{Z(xHU~I&qAE&a6K*_Rx#p05@KV6)d9}pM*0>KgDaB-1x~|liLKpQt`7WXCnDG zSx=k4wk`ckg!YAh?w%p^{jT@MSf4dz$vfVA9KQ^=Rf2g~rI z_qe(g%JA<#8b7pHzuvM~!L6jSc`Uz}KDhimuy`}<9A}WXIP2vLdPT)_7t@Z0#-%9R znb_Up=$d85rExHwRd+y}WbWlE(0DxTIoH`-YDlSd!RD-mlv8C?$~#Ye2t={wWzoYj zeDAS~O~9L9*TcV{o9R@Ob-KIP`;hp)l4`-&U}NnxO}*;i@{W`TghPB_ql=R^3?E*5 zV_s#bbJMK9JR_HHMLPK7Bh`XCKGg}WP)Z(m#n&LtD%lZ)oEKNhcN2Hn<-T4jZey6K)T={;b&0@kycSW#CO!%R}FZ9h>utb%>w zk-27N(21)4iIcoI@0=#X2DTG`9!*y!9_Gf6#`eWc^C?%^otAgn&5JdkE?0>Ne|qKL z+d4dDu>#DbjNYPYb#F;Htrb*Xo8rCH#I;%T4k3`mdN9TSj#kuV4Uq3gpx23EvB-li zRw~s@DxUfUmF=IhLXbJ{u~^?Vt*yM5h0V0D9`{^ymV&MvjEj<=*B^e3_8W*#HPJ_k zL|dTX-YWKd94es};^$ZLqT~j=Jy&33X!(%`0C|%5*1=>(@KcDsPW9kZ`$V%KvaBw_ zEQFp}9ju^0IrM(}nEzylV3Xz)#kh6W<;?Jid(aFWF<|SHmFN*b6C4_3 z=LCh9$pq~~Lv8?=UjW#7yfC>kwVDEsHOt5>nMHcdszRzxs6yIX21%cb{?m2;Z)(d! zI@vpJp|}w40JnXi13FkT!F1r)c#xBn#3RRNqw9cEi~IH8yeP%TH9HtAdB|NL7;cY& z;#P*mk&DvLt47|}Kk9RTcAL-ij1t;Uvr8HX{*sXT~MP(0Ao>wYsqc%-pk zYYrK#0v0&S{L%mbPNHq!3~^s|-B1nMF>>p{D}VGjQQycF>ahu?-=PH7J}q?~>am-F z7reg>vbR(H!cqyf+slK0?B6b6p#&=Wuh=q?o=3m;DUNwU{?PHsj+;X*U94=lu89Z@ z_LwoUw@*JD8m|NAJWhY1Xhm*e!V>2tp#IvRdkdF-+{3TNl?2KfBrCoa5d#@d{QWr&a(%_rwKii%yN05x20nTYmuO-h*|5T#py@=JRXU5C zT=T5>FQc8&eV>a_xpQ+?3-W<$&saR#q*V)xvG2>PJc5thrYQAjG&Fs7XJtP20#Zym zCx3Z=W8EXxM=oap)9Q{TUOvng0#;TEX2(k(c|*ZgXSuYUCnp^oRU~xO%WM^6ChX5U zEH-MwWeF8ExIQ=<(w0xdKc32Iuxh2MfyGza>)Srr84u2{C=5IC^0!$Lx$|p17hg-x zv}byzXODQ9=s5H=yel`=(DwoCZGb*r%>80_Qz{qvHBWI{;iUf*B)}*pa)n} z9y7Cq5wHe!sEjl=`QcSH-+0DEKyvtt5ld@3cP}Y$%39`b<(aXvlx>^S7_orc^bb=e z`iYEV&Lhz#)jlv%d$Bx+P zxm74%NkON?DJp@-TXD%kJXA00o=0`*7F`S-3f z{R*`4nCN^F)KwsluYxKQ35|wNMB)B1iX`&~1mguurfXryTNdwbH|`x;CZTU8y3=uo z^gfLly!P$@D5h^qJlC*n*;H-|w6be5n0Vpmpt0m}*_dvJF1XLU`5J6We-XAeR{Y_a zVeuaJpX=U< zB@kk#pEnic_<#jVaDjv@czp_G9&!_zP>Jx)=T0@pPT_YfA)1M5=BVo0h8P& zJzfYiq!XB5k_{g0i0!km`aHR*7{SPA$r=f2@J6+zw$b}QV`A+o(MFYQ@+y6HH)9oF zOW7!LT9l8^t1ddveBj6e=>;A0ukQ3Hs;4H7(WGM zFaS{ac+LH~x>%uz^w&wk$b+uiT`KF{}l-}jr2Gw0<0!-)~u)`DswvspzNPU4D?L{)rxYLtVH1^T$lxVc?p{Uo<1SULhFm2IX<`O}~3n&&lb140rS z~6z7 zP!vLKi_-M56xy6!=I2#e8xq^us+Uo}dH+!?tN7-k*u@w>kR`LZ%CfDNc(#eWs`5KW zq4S<7?`s9d`Ttyl>BkC?wtRM%dH=KcJ4jHlWE4Cw4I06N`yLc{Go0F@PgKB^n-m+mrr^f*n)hiN61Sm4(3+W)+6uT05_;j7Wvg&&K;;Q0~> zAxiB zupo5cc%opQLA(hETEEx@LO|e{yk)`@cc)Vnbl=h%mbPCh`oQzSmq7fri#>3{LoD8vi z1^o&lvAM#96oa^mk>pn(Qv%Gkc@?p}mpb>w!yg`#4-~(Uc5GkS$jXh|n7KI(@!F;# zzRIMXXTqb?1AVX>3cE*NX_-&g%O|&%MH;j9Q|xSR>P5zs&9~f&o)T$MN1a;@JwU9y zc%$R>vc74Eo-SVGV%1LshFUsSy1BF_tdmIeOSd13q17K+TW-=yvhvjkw%KnKA^w%j z&;irytWLwPtUbLJO|!9Qdh&QAZwX9mTnnkT=cbF+B+F8%H-3K*uQG zyt>MVYD?^3spDU0&tASTc_5%ZkuEA%FyP7U={c@O;`d>i=}HyIamti^%J8LH)z#_M zz>)CY2_t6xdu$#?nAL6y$--*0C4|Pv40d^d2%*U0-8vTP^{)Q$7(XA>o0(H%gNb_T zy|}mD)c%q3*-H0lft(!IUe(Jbx0f+Y`LL$C9Y+Ny;zVaKb%K&D-JB7$VCG_B{UL<^ zdY6LR-fKLWL+E52bZ;PV?UJ9iWQRvO6?tf~|6PGx+LDCrJwN#lb||Oji%JM?Tx z;HQfYJ1kOBDfm(FALd(qoOpXr{@=}ih0@!&5>lVYVhGxR6x~3ct|qWIAy+&37nTm4 z-Cm~cQ-N8eV}K?2U9qtn)?&JbCDmyBxpn=+V~U;Yu;P`P2(so%P{jnZ!8X1kQ2PwL;3wEKlDaRQ2trYv)}xx%&C=>@daXMtc??zhdc^{=iSn!HuuK)7*~HxFe}@ODPbiC`;|wj{0QCmK zSQ!gTLl~MGmexiFr*kbcM%P|r9xX=43<-}dGcjA7>x-i;xe&({I9ZS2``Gu{ug;z4 zUlMR~evYv5`=j&O9lruacIK6fN&4qE9|}+0o^_%#AXFI0W^uYbb!tJwCn_cM7XH%5 z^-ZE-Nm(rozCrl7rU(-vt8|C@Bm_Qqp+}*pNWgrbC|u)#sR(_6hEq*NU}@loq{>&C zyzj9iY%w**1^ZQRW=YGDy>}4$Cq|Fp?p9ESJxRELP;5#bmyg0e&@Kj z_|?--&GKR1yn}q?+2te(S!SbShz!A8Pqu zpAsc0P#WdS2s$@fD+1$qswj_kWN1bm3HHU5P_YNW2d-Q`CC<&gWR=#-M};r>+f4!ec*W z?Yem8r$~eY7>#-2phsZ_3?p~0)`4r~NmE|y{1}w_gv`a3I~uMYpZ~LDu-efj0sj&# zP}+tP>0}2{$T0Dnq(vX~lHp=G008k1aDzpiZonP5){l`lzraB5?q7zYI2h&)cW+ zm5whKZ9Km6#F4+~_2_2m?vy}L7pu9qG}KT=M|S$_nnM#Q9tN%!(0gr@&s}ZYp&ENN z!Tpw0)4)MR4vu}TgED^$kLy1O&wq%Z$=`S6Oa2{RKPGbV-*)B?{~oOgl-YzX`pRdEV(Hp1$Z7V8r?c&Jg4X!FA52_{*X8fv67#o(sp zZ+RDJ@osu%3Q+N#^k>B4-qp-w6JwNo(o3!eKC>g8ROv03_x6{%<``et#5ek_KsMQ&cR7}njguk^5*URQ;BqjWD@W{4L)Obz_N!&AKe{7YKci1ymGzE|FZe5)YHKR4o5magq zhgU~Yp!oH*Q1S@S=}TJNSA6B@w96v06c@DflG+_G#A#6a|X)b&L!%&iFmFRNu5gd%>+XE6^9^h}XWpaNZrT3VvkXg_b)e)37svvJ|y zIRdNu(+kDiU#H7C1nF#H_#afZrAxz z+yReiF09AC4xxfrhNT39ui&3e#IA~ssIsnnLR-*@7nYL5>%%R~6m*(`Ba3TOhB}KG zEI*pMjm_e=9j^e|WohAHEhRM1$);4yGM!n2=V><#RQ0n{{>kQgf;xgl!xRLZUJq)F ztr-SDO!8>8f%hU0`r8Q%(3z`O((<&L(Q+-+M>;UIAv$9}Q4`dLBryp8=Gg^VP#9|I`-g zf7$YV&ifBB`j=n+_AKxp{h}5e=(rdZlr%eo6m^K2YJggSL6a^89m13o&WAxavh~09 z0Xr7H(ig4Vp`KRmu0Owg{KKxqV)&mCj6$o0|5VEIFap@pzWzT7B>cnW*&o(x-vOl6 z8Dw{0Vf#ciVLi#rMfIP_)fPVLDk}`ho@s&el*_cn*|-eXXzZeqM*NhfGcG-*M_;L zr1fmW=KO0*g`+6t7&B)fOlL=ii@W;``y`BO{YAOrPKP5-w=t!)i3RQ#ES?Uvsp zQ!5%rfT_@uZ9LL9%2pHt(w~BIerWthuOFKF`ps4c1n=R*7ROQyEX0Q5-(z+{>`0gzlnty;cjZ~`1xPk`epm0$e-$8+RYvg0;1M05nX z`ky_A_xZxj5j?!kHE|Vdc;cw4%dmU*G0c*ajXC;$0Q9MNsDxUgl$5(ZH%?j8U54dNh}n zB|!WiyL*ZJ?EFF3yzd@v`ICol|Muc9x$xH*{OgP#bJEgXVtfAketBKhmymM*qjJ=j zkwj%>oLp9lm5~?9RUp;R{?H2-52=E`n`sBG& z460o36}E@Xs1kmP=+1g0V@s@SVMeu}J|DhVm(bTzViN~f10$#^U|f7HwAI3;=-uw= zK=hsW2$#2h41pR(S^v7idc*{0Ix)0pX@4Mpzlr&dcX%_98rJq;-JYbH&7|W3){-P!mZX9en>m~(CrLx-y`R~R z7p+F{5&c&^ev+&wu32GOeNo0vqoq3*SU2H`n~~vMg9~aa`PJ2k6IUM*hFhirZ`utG)E-^rt4vxOre`E3(&G zr3zu87O|F&R*)+6$+ zPcYi4&i*DC;$G>7e88M{;pRBK-OsdN3^^YU5&t|;WleRWtCfr3#1GN9pzn}>IQ0)# zo@2K>_hyFhDe9d!K27@Myl$#o*`t{6Omfroko0+!3T${0BL*NM9rYeHVl_rp*@}kCo+HXNQ%sg{D^#Z^V@7n8T3EJ`TGARg%Q_y*qLdqTh_iUh~G} z;%paq8ya0t^5p&5MUrJ(Q!|+129cnm^($|EvyzB%fG-hn)1xCKMH4LM=TqK=N0Gd6RNQpNNzS@w3d>GkG zn_utd-&QDzX#lTd`0iJj3OT3!bYxNQZ*l!2gABKhGv9bJsqsTBM2O5UAKtz`Gpf|( zM~&O8iX(GLIF zjHEXi<@=ms8aIII_L)qY_h{-$lw4oHS6c@JdaqFKnM`u6DgXTTMG1^G&FR-F$>Yg$ z=@UMpUpob;%b)B!DN;|g zl5>4M*Q*W!Z3k~VwCcgJxtiV|mgeqIqzQ4d<;xu{$Z>%v7ej0%Vt050<}`j?gG*Hs zPe>&V{dp8iTE4qB8yc0gVNu|^zVIoyuIO~K7rEWC6xWfm78IfrAus-s9}TbAd$342 zZSltl^GCLy9?53BOVa;yY%P7Ie>mmer>+Bkj2_Y&Cw|-eQ@)v){U2!HE~1jmRo8WS z^uFB1i+=~_{q#=}-KyFayDh}fzZKaVZ!mhl{)0a6Q&Z$czxvvtNXpl*m+g|64>G;% zmqHYR1WvFd5|@S7Dr@?^crw;si4(cBrPI=ezTUg%gwn=3$~hf3GkY)Z#i6=USsGHQ zU4Kx^dg@tL1`$LYOI@pi>PVg&vx1Vz6sA}DK3J9gkj|>dI1Tk#b=0b5p6R~l2&`14 z0orqoo}qm!1G|j_zjIs$B<$`FTc(jJwF^V6ujCm(Vp~ zr*EjszzQkw*9++1O{zZ0>FF5xBw;DRm$p&TI8Wf%5GI1YfplJvt$H4BxP4wVDb5OP zA#;w@R1e63;-?JL(hn+~IW1P!B1@^w+1A zO)Hn(IuW&Cy4X%<;x(t=IW(&Dzkbu-?NwsWn(leKg?^e3-A;Ad>3BFel`>uaiCI^# zdl_S|D+%jJ#95uS&9HeYetb3{CYCS-iqXTXtJ`MAG?4AG7CbQWnb`RM@q;uq^n z7wBjm=`<}Yoa8$41*ZIEWeU_5V$m$$5IB5)=(Vlb+nOD@H=&=%-rK36I~`T+-?FD1 zqxUM~!?pS_BD@=E(-hlx8w^-Jp#9lQE+PJ%GR&7|1JMjHaGn);kKGnXfZb^8QX5l!#tr%IN#Q-13yUan8J zf*3AW#=P}&pd9A&6nb&>klof;s*u(h3NmxkD#~)TLZ$JinelN)L-%8c!)79zj(nsz z>%BvLmMPm-Cm5i`c#4Mn#Cyzjk;wwu_8%Qyuyq?l0?}Hw_Yu|WI=*J?8#_;U(wL^7 zX<)dIGqZA*FKEhZAiad_G^yn!-8`j@ zmtpojRM1lqHD&P!7)?C7p=9VK*v7_DQI}+oDC|Zv2??BNx2nKz?$%uvfA)IbURH)J zSARol>va!B#4%DQ%(yNyA@y>n**bwW^~G-U>8}F*pV#)jVH3L9NhA7Smo;{K^??q+ zv;p7`J*89MF8$828N(keF1z#Y3i!8Vn-y#>(8cXq=3Rg~Gs4BFl8z6E^A==O@rMUq zd7aMc?RD)gvF{Ij_$U!9u79U#>pnZqAfdC0TNZEKqs;^XRQwT&#vwt?{fsj1la>Ha zbs|&STa$u@p@VpJz@}5g@z1lP)ib>XYrkynoL+11TnSc9)*rJ*bj^9((e~6BL60%D!j0;YS?TAB4O| zeg3i|_9$6t3~_!wu2jo1hJDufC`B@GN&h$I6823X*N{bdC>caA6kfZvu&<2jx}p;+ zZ}{5cRMX;pb{6To@qr1pnqFrZsLvs|sl@SK-H}WlP80S_ujQfNKDkUfUSN&xn8DR; zh4!);rQXASuLTWs5}QW1*v~g#&oXs|O*us`%SNgAHdlc|bT89scCDy0oW2wDGcV4< zN-BawoGWX@8&c)(E5g)2A{4y1kLi7AosgMHX_AnrblklX(g~JM`g1;{{1`s*^($7J zPwx|o<;%ywhJaE@RcLSf_nD&wisauV^a0ZqAb5X&c=O{-d81+H3i7tYH~G%0bE!3K z&zfy@4m(pYv1dY*HeC}Ta1-woUb~u>*^$zMb*m{mQ2##FfI~})9e*;N69q)F)w6tb zS*miWwY#|xe9f_^7Q^8u5An&QaJIpoNFB>!>!?@oW(6ugd@<-SaSjtpj`7u!R{FOj ziY1ty_1|rWl!ygh`mQDbe>)*OV`w7bI?a%E!Vx0(z;3`)8wpIc9;m@DHZA-Tl_V2r zNH<+#8=0}^Cb9RW;0Hf6@t;P|h%1(u%Kez>N6}S5hkh5^GMQaqzTV{ZhH*S_DYxomkz7b*yl9twL-oz|X{K?sK=Ug6~my-Xt zU8B$S|M!-&C@({T0!gtLGkIk4SR_iW>|uSsAI68*Lpb3E$)F!|e#M6J405q)2v`Mz zJBJ@mR_}gB+`h_LiS0@n!uA{PRj|Q+6CXD+#2zLX8XJoqUeUOe)0pdjLM#FrLrQ_p z(=0pru@em|*p6%lN>p@Miwn@igtDQ)6eX|34g;!LpoZBg8!5kY$OFRQTvP0|TdvXb zvJc6dE+5YH+8h#|T&eoP=x*!kC|rPm&=%OnC+74CW^!aL&&}$zPnJt(H}F*RYvsdV zD&+E#{e$HL)H{PwSw6L4X4q0qLNZ)0ZN2BwQY~errL<)m3OvzQr~}hqaBKR&4;C#_IPV9 zv&35oh6X5AJPZV~?|AO;?WTr-9f!u^&pFdZK2xo&EDGQD%5g?`dAcZM&Yb5D_k1rY zm)lgT>E{040EVi|nH9npA;ps@5udgwaMhcFs$zRnGu6th&6~?;@4`7}2l;5xcIX4$ z$K>f&6w0TH(6UvtOuO3w8rj2TMv{4KL)t+c+*xupxuyX2b*q}L%c-?pm*s|mqs{Z9 zDn59?GCLF0p_h6q0W1Dic<)V25NSoq)5w1QH@}Ab@IMvC}Sp_ z*4AXeeU&VBPK4=1cG|^#m--e7-E6Xsy}0iUH;DG|PO1nG5fp^YNy%IhHU79Eqn%#d z=2}zTDCh)Ptk#;$ng8X`Q%O6LVKH)L*B--p#R|E9cs3q-Dmu=5Sr%s79_3Q=#i_nj ze(wI#NJtN>2S9V#I_+?J?`;?h+UZ5^;mA?3LKx8sxy|FP;thAyv7}ZuU6M zP&e7}Qpo5xmRyzgc{4@7R1GfN1ZJ$hRrST7+rBINAHJ8{zBZrxJb3ZU9FZg{hdGh1 zSXFR);5Nc903_c4^)=mW7aGFS_|u6S^sZ&F#!o5SB!qzJ=*Ko#&eN-wJ4$4yot*EP z4(xQU-E)F|cZ1*O7Uq#D_Ud&=jtixH?Z^dY(WsX(dm@=a((48U^!WrC67xp<0swVL z|6>!n@pq24V*l*IA#`diz3w&WOUa+6Ke5;*iFY6i)|;&GnYCfn7RmLn4QnB^hR(OF*AJ2-|I+wh?odYb8A0MM z-^Hv}3fiGG8dcUm07bGA7aWywPfu`)SP7Umat+*SIdQrLGY;I~QVY*lhca}^vJ!jX zdj`sdZq_T|z7I+DTTVL%fm}K3JMgIENvrqRHNKzKCA`0`wC9e2^swt4O$=D+`{J5# z1I54sg2;?Ze(4qSH$5SMXbr2D%e+5(@qKOs!fpKBn!ab%Vhn%9gXG^i{;}nCW=eC!}+9_a0f_QwO{f@K|D{#V&L;L~ySS7>b%c{CJ=HVuOzegJCL=H~VGSnjYRC3@yHqyIF|6ogCPDEZY5-+eGjpr8FXNhkVQt(1e9GVfi5c)%g z-CVIKMR>xhDon43^PR4^3Lv8An$nmOca0B+^E3QZsxEPAcix1P(9Kjy!DG73l|gwq zCcWi09v?3Y|H8CuG6mR(DafNbxaER^`qM3kYn3S~g=$p!b-j)SRa;@*f$Hi=&jYpE z+CF-fmX;UG_4%Q2Uc`!Nrt_f_3+@RacYid;LTK*Lpz!Hpmi@sxN6NzDZkF!K(5 zP7FtL&n)IwHUEP?_=4#^9oI0>He}-dV-ozB?9wX(ZBE~Vo6!H4e)Z$XVLFx*-n^#I zZ6uw=bSiDx)CZQsoPj0f$+;hm0CELA8N&D6RObhu{3Q{U+(M4*H13N1)7*3H-95b- zw55Gfe(i@oD*YEDn$ou9R=<7rzil`5LpuH#nGdMTpKWLh)BnVE34rU$|K++L1Ni@{ z>p&uZ>|{4qY9qyb(`p)&lmy1P7#pN0sD&Q!*e2ALtL1|n-0b;z<+Gb!E@9Evbw~cL z1DdGv-^Zlus?9Vv5FM`SV<1n(@00nKu?^ZK>a5nP5g&*Y-bS2z_-Es1Mi14zq{8nR zLi|LfTJ8b2B?bo}AF3@dl6%t6?_*!P zRc!i*$&xd>7I<;WHn>c@q4M)`d6DJv&~s7QvfNQd$f%?oDr|l4X}$s3`L2UQb9rP^ z3cMBqzBPc&D8b@uJ4G-i3haCnr) z6ZfJyBp;uPByqV6hzS-%6LY)IC~e$P2Vm+<-U-j{D>7z$BM*=@!b?S8*)gKtrRae9 z%C!z`vRg3Xo%(ZXO?fRLy0)>w3n${PbA~$}o802HVQ-IU+N!mljW>mj(;XB#AT+vO z=LGYKCfPsELvjL@+^APII-0uh-jN zq5{A^-S<({4ob_)3FEBck81eP6|*STBesP8Ww{gIvMSS5uhdK{lel_>zcgXdWxK0( zko0RI?K*TO|4R4NV~|hC;I1*4S*jgiq2OH-m;yR~{Xxw5;^|&{!sO|nqV--9eTxso zTWMJf-7N;oaQG=ub}Kl#lSjpt z6SKj&+0>4p4N}A${AnKkdwI%PPqig(2n}%P#Z~JN&uTXA9~k?LewXt+^*#MK7Zhh%=4;e83puud{}zqL#Y=x}@PDYR7;ZzNa;)Hhn^-bw$M zDj%em#(e(BPm0%nnVx0R1WgSTHkYq`39&apHm8)X`2l6m^t&n}%nUya{W86w0d_Ma zDBaMQ7`U-)Zo1iw;|$Q9a!wdMeo)sIeLEv9{(GnZ7F{~S&2*eeRy|$QzTfa#_i`&}`NyPo{PC-(3=Y6yc$aTv>`i~KqX2K&d7JX%x5Fz%Cej(pY+$LZ4ye8$ z;=T8|;Ky&kI5TYG28cl0wXAaS?{!dt1+|NSgz=xh0{zcF;hz`-j7k48=8v)GFJbzZ zXa0Ru{(sRk$V#99>US-}D8V8S1)OHv^X`2~gwB+;RdOThrlDArt@iI67ZmcJN+SPl z5iR_mK(C9=#I3Vp#d7MO#jZ67zpWX|O@TvddcZ#XO{XGd#y?b5g+CQ4_JAy}4hTa4LuvR#4!vL9P% zCXhbYRJW>A!@-;FiYaHc4Cg=tgeQ5ea4*`BWo0CibTqEg8Tt^RfAch`7!BSra!J)V zYJ%&@-povC)SfC>(#|CC!ewp`2IL%&4yMF}yg$`9X>etHo##I*XZAj~y#6C@C3V9@s#n8VIO{;bp{(^K zr|>7^8*Hqxjd|W=OAN~^7rgG|H`?2ne2IXceR8bBLHNLx#RIZ^^elr}-0P@BksU+g zjxSm-&3&B7*b5~+Wp)g-AxIHXmT&xo0`H7?6uj^EJ>B3M?f|G5sng7h(UF2fr@Yug zRb<|m-|>JT|A94nY{Zk=XKeiT1^N|OAb){Mj|!lFj>vOR`VftWzKr6KHbYd&*~ za~H6e2UehGp)R=$%)dV~BHpeG7DaO@XV{4+ zFC;94M3UAwWMV3cyss_Q;-2VbDGSjnyZqAUl~>j?Imf3NpoOhhsuFi%ix_?cK}#($ z!=LavXYo>^&zpi*%O0wI%DAhcT&A$z!(S1vf-2e83bJzB&=x_zns0>6yqH1DJh^?i z^vw93VYYsN^+ug0MZK`TAn&1(F`j@MoKNr7#;dYV?gkz1;5&;dT~BvhU={Rl9{W0A z>gN`amF^KHY_oAQG-b$!(lHT|2CAZ;f`Uw2r1Vt0}*ouYl5kJ*DYL*^ zo65a(t!v^fub=XTz1yXTeC?N?lIBa(iA)sJxfpGKaIK4%txyWL@XxY+J2P}rSTOM^vD5x@3*&lO z@QPl0%jmZ)u;m*kn`_XzdfShTl(})1sX{bLZ12csB!wGx%1u3<03`@4)ZaZVRFxW*xx*}!mYN3g3|ob6QM5NfcJQi~;2J%J6VqIVLX5oDX-R{#a@%5ZMRQZkj1pQv+pYVGo@zBS zgYDJNL^7tno`^z-2~1EYL=~LJMJY|$v_2eP=V8+89ObqPd?}+5%!K?8XESd+Jxl2F zsVr2e5UO7FKgO2)W--6#B`H;Oxj6a>QZEIfq5!pMB8|n;^6-1%n>|epy#g^B*AjC{ zVTQq@s-Tyus?-+}N%2r9xyN?kMvs^STILteJR)8^BgZUR!>E?wY<45MD#cL%A$Osxl5yOskj$mm;041AV=k*5`{hA*T`+ncJ0>qX$Q2^(w#U1mC*@tg^jh1Fb@R;m2L4G2j%#_p#xj_N`2P=z$3(b zpwzC2qS>TRL0n=>*?yf>ry5YffP6X3dck1OSL$lhvlO7vbnvQAhdOu7T3!c$&WIAV zbDL6R90=qn6yq+?5bt#{S!ZzQuO|zdIxgE!vv(pQCc$-Q60faia<4C}cUJbltHDBJ z)UVXHjW-}O@CmC6{`tWhjJpithwj%Br?<}72~g8^RPe!du{+k+YZyoO^}}PT?dNr; zu42yzi9YrKr41881k{kCjhKn~c=Xyi>=<+bNmi#M;}Ju-vNT;8zH~EAG7iTa6P!XW z_#N^?5;{}kJCD4tTc4m$K?1c?1g%}4N@HDSw-qm1KS|VfiVAZlM?V>+uDp|H3w2=u z$pS$#3sF-Rgmk2sIjC;I#vF@Eq3HTlt^1`VR8d-CgINS*3^qQiX0ysZey}kp@qbO? zNd|ptu3`B+*m_|K&Z}9+C`+`aXssdpndo*?P+iYnD(V?O%dqlh z2-ZJRxlGO0RCGavml9k)$>CEwWr>bC_e!8Kp5y+x@~_{lb9z1ubN!P4;t!ps|Gd(m z$%Q{^3CLFeA&Z?Dq`{K2Gm#kJTG2)_w?4yeaAV90f8#TAGm+OSPr_1#d!Z zmV&);Ww}^iqY_ zoFTV8kjpZ}u%AvPeg;2#Dgu6}mp^=HjVlbu!iEN*j-7$2Z$I=R5w2!^)m)>LkU!2>ir*VFH(i58U4gx-mKE~|&Tu$42eOi4=7LI3~I?SjQ6*Wl;q` zTNe|~vl&!CVeGa%C!lk_*B!Ha1IgCwOq{o&OZ<9-nG9%W+*o*4E#&g$M5y{LZFid% zjW@2d!q*F*^e8>4K1rwE@(L~w+|pJ3GHdX3HS#HoW`};kS}RTS>M(s@zB_qUSf+E4 zGz*50ZVOr?AgS|v(GS7UO1wV^~`L{fOydUX8pX$RS?emGNWjtEUZ?%;QMOoDk@gu%7b zFFpA>>yap#NLbnsTY-4#L_G`tI;O&X?A(SwLcQS)v_aO^E^+M|N>>@e0YmfO?1B5} zq=&3O-e7EP+`{Jc;F%S4G3aV>^gE@Z5o9zn1_t)R4aJ@@bu`szTDYb^&V@Bt60@J) zL>DekT^C$E6CpzO?4;7Qux)y2r6;SqUaZpluaUat-$8jR?4Tj}4YIXU;BX479KOC6 zgGFrl#N;2(orgvaf~@t7G>+QS671;uoI-a}lylPDmKAB*abZJ8wAsj|k9iG2d%TF4 z5ec$Sc}a62pOFQO_VTGm5X{T_jT|YtY8;yWY>0>d&HNqz)t4C=DKFEQUppO#48444 zhAUL?{Y37LX@2e*e5@RwZ4aMMXyIMIU*JAjtqms0%fg!%RQ(%+FSO;x26>xv+%`FJ z2XDDX+ysvw7m+B6o$8Xy#S6-mIo+o@8apcR^{Yl&K3{M>(xHLD58{P8*}AS(aZ=vn zTB)1U^=X20AB9(|pZ0St(itMF&e`q){Jz?y>IR;X%jz<|;BcxkDQw<(_ zpU-|3JgF;BPgA=UZ$;5gt`e##Ec$hjoHAQawRq!pa~q?yXv+s#c1GUBHI(?-qFgog zI#Cfd$xEYh=I_eJlH5+L-A-RAer?tOSF0x$>AybooY?++uNDhnV+v!P9C~XrckQ{X z9TlvtU^J$@Z^EV)_Kk+mj=ITyQPhFd$=sx5*z01~k#6NTm0=sViI7tD4^7FCnwfyZ zuz&~8@hQWlU4(|QocI{z&mB>+r%nKCzwAdKqi~VxefeA65iIGrI`EFE0v732!ft-J zVgGhkN$*j0)`ESHCG5s>Im5zQOs;q;E5Tt6ZqfF>3x4MiY*k}z^Iph9Yl5QD7+8|$ z{H8a7E{E$h0P4e@a5ng4D4DN3UlkRPI1D)`Gk7|SgkP+P!c=oev4vzmouU}24gE?5 zn;nG&J*hSjE^=g96GAS?R4}%Vcx>=|E2itJ)!28;IQf+{mzz7zF4CN%cwQZLCVFi% z4Y8RW$S2m?u|^v;Si&w!B&M>=A6K{+`@{~DAJOp5YB&1ESB1`+Pi@~tr1qb!tK2|U z&&Xf2jP5QYOq=Gsm|jRR4lCp3_1gF9kq-K|;2?hB{V5{p8HK4lg(#UP%YT6R@z~1h zMKN?Z?bmJ_p6TyW?!{=*5Di#2-8#yQtM11<%ws=3$O>#8Baa|1)%jiSvaHJcIA(aE zqKSm-DILE)GAYl`#Vt{wd`Q1Sq*`;qwLt+;GD}BG{8fhP9P`Z@v?L)m_)DGJakt%=R? zvsWYHDjfr^SuBm_cp;1f9Iu{LD|=&a0$UwlT)!(~JDPReV@W()Vsy2;;rxqvfymlq zL)h8pt$FDg)eMReO!7oy)WynAt+RDa@xm#}q~)TB;YClwf~|UU7V){9V7hln#gx5x zM~a8txMa-Ar8DR9*>Q~9P%TUL{B zmQgHM1x1@TP%BQy;Se0*7w3{2b(DpVCN~wG-{cYI#0xKsz_DG>X_mciTu@x!m%9(* zFumQK>neV@Rer^d9-5s%4fQI7t`=;7`o#-!eeTS8L<4pH9y{)zwT z>YdcT>0Or${ZS3;*4)(Mi@z7Me)-QNC5nEE($y;ta~Dze&HDb#nthOFQ{tRiFJsvS1h`9e%p3g&!yN!RqvoU7fl5w+T)`eCww>OJ-9oC1l1*s4p) zUPWiUO6Xsxjd9hwvHurs?;X^1`?h(51ylrXQBb>xR}**y-^!O zw`*O!s6on)Pe#1TMmC;`Yv@2>m<2e)_c@|5xnG#)%qndyAwY+zPs$f?4ySrg3t@S} z`fSX80d*B8DW2&8-GsX&MaotMkyNdO8O5Ma-0ihiA{fAxDJRm7;oFHc;3A!*ueI{xx+T?nf|+Z!*+3CDgrEIAGa z=We)cXLSHv5yICM4F4_}tO|G7lma;{@`KOcVMpmhi@a2_d(oDbHv7U3&LZnzzI_G0 zT&y6F=I)(PJrUD(tcEa(LIp0VqB$EGp`vHLfe*+(4j&7p_`Qqj)# zRl1Sc8~ObLq3rzg(KFlG_t)0;D4ZyVN(DUcLUm)Jw!!Fy)Y|BX0eIp$b8HrK%`U>% zr4O$((n|5tgn^%V&V6sitj%=buTVtx?CeoC=9f&(N-%FVmaWc6bn^nBZpPUZSa zjq*%gCi3fyyNvr{g@=#NFI3MU-M_SV7oOXfg|0#sXNr4UgRA`m7aIvk#`BQO)tQp1 z6#Vg(shZtNJp}IeoLp`)VK884ct4c4pI-A@>5g&OZ$@!rM{nC5Vm>jlR94e^F*0Yj3Z zb~x9pj_y4>p**mR(=48h=f|F~05S{CiQaD#v|6{W>osb3b8j5`GUK3@$d zF1{3$8Rg-0-%70S@jjFcq~h|j9V<=hT&XtGrTkp5*?+}?otgcy4Kd{^;_7em@$|d; zah9ac4qXP5k@~S?=`DYOZN=Wd&}20P9$;nKbXE$R2=QAm1XLv8GBVYGj5s9=a856R zYJ{bRm3jKkHC3u(u9oy6TJFSuY$CF?n?6&8CY>+3-hF8-KNP^+g>Z*IOiVb;+mVzI z2`bTeoi6pS(%f1X^TDYr@I7GLdxE3)Pkj_kI((c1a%MTEEXP|)fdKZ#foE%E__59hU zyW!p`q0=426P&4;MH*<UDC18~`ZGcSde=MmL6b^15ikFPYm5Vpcj3^5QForW(IzYw zz!lik7;Y?DWg5SdF8ldX2-O?#l>Dd1*8EawO7e%rK+O8kQFHpZQPtdFL*uj-A1oE& z=*gX4^Y?`BSj8@PN0ovV5mqe*vUeYB;f#EB$rCa?DwD>yf46{3z0+{%%|@%^ban+j z|3Y;83N|i8sy>NxM0E0S`b?b^DS^mH2E7fC&^Y*2s6>a?{O629?5HbuzD=ialy4yi zaGzWmC(_)g50^RTV_khmWxBo;Anl$RMxl+`oFc4kmEkq8?2T7faNP#e_k_KnV}qXH zXEv`eb#5MgU-gU(v7GRr$}#aO;rg^>kQLuG{raz4Rg_&|?IW*|o%igzE1#~@Ox^FF zT@E}m%1`6<-_-fm7nb_CH9OPRBJ!YKbaScpk4%K?Pe7g}myZ$+#d&^e{%TP{2)XHC z>)hC=g;zR;_Z*k?v8AoRZTvl+29|P@TowjOpPH3c>}HqDdchqN0cS&xT)_d)P_%T? zvh(DbxZ58J6Gt>+?uOa)G{xA>2yR?KdQde%@+|k@;5z4!El#z!=kDjeuvHp2tnue@ zgG%K6?!?k7U~}wMd9}{6NKDA*L3_NoS?jVgBEW;jZ2bYc*oL_6IqE-9_u1IQnfXWO zNF|~(A(Dvcttv~w4jvG3qWK@a#yR?=j>AK<#(+`&iMH|?zc9Yujt>dUt<4g{)T*iE zYCq_MCd9xE8Y~$5NF9`Zi1FD>`5-KSeFF!~Nc#gf=i{C#MdC=iV6%wKD z{0{7y)7+f385USnND4!rs}b8)pKH-Y1;&KzUaD-OWG_o%FjS*_Z&Y;UVU_cGoZM$G zh4_**K(1!Z_l21mAmsNbBTocf24SNI1=c2IRTXmtu7!MjmRJ5R_G!)8US@gRG=$Qu zj=HpjpA_f@C+h#*8+LP0>bq2gdZLYyBctUPkAUy`ykJ~;)8tkX^&0C)v%Ystoy2yF zF3`;s^F;3)tO98*`C-^VSLoIL8;KE1xAzWO$H1W<+Y=TSX6t<{XqMRL0Ck0Q!gTi! zW#h^h*|9#rlh=kHu2grW>&QF~2IK#_Eoa;AIgfPg!%z*S=#0+PadK)(0#Ta^00Zk} z15szEVXgpT!kD{}rr}0hYZkzAb2^D)I6h;f6gx$|F4LN}coW(LHu|90sa*%=PFuoU z{YjsV;pA42A1-r-|IAa zLN=yP4w{!_bCAzJm?v~@Yx>A;Pro#XfWmlgj@EcGs!^@muazL@O0Ur|s-c4en@^h4 z61E8!_+8y7JJBv{_&P+hY9nlhmeIH3`)HJnn-g&YgX_7C+qhR{_nEuy;=0FZ5F8p{ z)f0rS4lJRz;%J2U>har3mrj1#lzXB<1DZT8-)#KI$V^S@iq;__s`-;}liaju$|F6^ z!pLvS@L8{ifMC}ZUOsS+0WveAO#3PCOOMC`P6r;o(lVz1D=24y%JonR^2RUB9d$9C z&^^NNE%k?Smt`Lrl-Hs32Xc0@n2^k)%HS*B1)EOGp*$Z#mNp3Q$F7?zgWIHLatW#+ zjp~Z;+*dDmLS1CRUm}!mcXGPfI2?+L@t$UQts%Z2g%hV&{nw<2LsUCHZ)nQFZ$sM z%f^G1>9LpLxtgVL6Dx_hr=+L;pz>*g*UTi_pgFZ_FD5Q3owXWx*tC{jk1dL|ildA{Ss zkLtVGAYX70>Jz;v??8VYskYII-hh{syAe+;NN)E|mQq(L744&1HusLI>;GEMap{A+ zo_CJD58DXxHeUb~-WC3uZ_SbiD5;%|%Q1{l>WnIeq|UWcq1u>XYyz?RmSJSjJ>n7t z2jX4LA*xXpAaVA=+f2M-Gwi69qQsEJ|Ra{RTSutD-_tJflaMnmfkAp zG8LikWu|SnxVJQUC>ov||1M!A00DT&sXMb$OOgh?MKuh{2s2kr3#)w6BWS0v_Rp6m z<4BpXe4iiw1#dR>(*)#x&=ymjccp%eaR!XkO1-n8-q`u6^@;Z#&H$sr72M+yngZV} zBbAUl=4#xT)GPgZBHb%ujJ`$xxhxlbZPXtGsIr`jIw8EYtG0#>3)rLX-kRsRdhe$A ztZvtFt$*RS@2~%IQIgx}+wD54lV2-WgU#Nxh^SjeR{9n)*}Mqb^7R$mG3KUarS`;b z?!VA?(P{4YBXvR*F46M1KKzkPZr@Q)Nm{@$!qZE>oUVMYi@tEr(Z`)_C*|uIEnj=r z-M06iGR`a??~_YQES+vLhF-{&KBZGzuPgNn^1LrC3sT7_)%18!C_`NE@^-nYBSf{j zc?lA5ysE3Ag&1iW$}6L!jwA6q$2{RVas+t`)I$yW@}-lb{&n7=`Yqd9A@X%!Rn;Cc z8{@^lkxI`bJgw5Nlv#5Vn(6V^k6sqh;k?tY$g;@zJLp5l^<;)*LF9MR^O#5P?>2O>AM;RM8ZfD+VO5Lw{+#6?E-y*QG@-2t_{{Uu<6y zb+FS}LbRydFtXD}MxouYO|ZnJ^~Y#buy-{Co9uj42eJE)K$FSnmDx?z+>f`3y(Q}k zkBxKVqnH8{&g@GQ0vS$WyH2D!nI;+54Ih>8`62>z;bF2>o94Uv$g3RRy93(@*jl#L z!bf;yc^&e;5G#w(PM`sR4oI2YE4=mGSezTO}&pEXH zr~f=0Ez11#TyXToe+b5T{!xQ&<;IqRkdC@h{kC>2fLr2V{U#$rS9b*4TA1ghpF+wC zdtq!P%7}JT_friUFN=P0J|9E-Bw`_6{(Zw|l53@&aBkWOWJXvC3LB}79~qa&trzy* zHb~N^rYQVv1{K1Y7LX%ajBa+Kihpy}iD2}|On>MHS~CA0KVFPWTWrAeA=pu6%c`BH zUtS=HW_uS5Z293v8!WGFLNnYC%}nx#&B;&rdA9%kF6jSmZ}6Rf<@fWAZrI@`brD0& z-}yQJb`&?FC(kD_u!6Bd*vuU302>w88s0m<;TR?S`AeVlcwk>{`wY!xe zL~z=&9Vs6W|G_@v%Gy;sr&}t_c)t@{-GT?kkxk!%T^6W-%w(-`*>kWkQSW}uL%FKh z&ldUb+urO^KUu;~?JBA_It>sGma5hzEWo82iyqnsfFNB$B>AW&`A-vKY+x@b>~8&quV~$o%9(li*91y{<)=iqK)q>ebg2^GK_SVtNukWqSEmAWSKP5cDP|U zF+LQ|7Nj^PGUK1Gxo)qNXZ?oeUv}L!(k-9y@R}i$6=btbSrtwBHz2}e-3XUm3f>xr z(}7x5Z%}E;U=6yBN+$<3{iv?&TDCMmH^TlnhR!_&8#gDH2EEvGZ#Vt()L^l4WJ2l5 zq;)^?fKK0o;boDd5PnlZ&NAqweEsi&MR>tGGd=Aeb3XT@N^!lSr}u-idg*3V2V`f* zizCr$x4R=1R8CBKYd7Pla}TY8TXcqodawHE+{5<&+F1f7EpQ$DDw^V@b?=E}K~%*c zQW#JW&+1x8b49?X=@5t@))V#$tu$HfDpBPyk&Z92!Uit0nvLz%=WIH?_)hiwP_=sm znKDx2;xK4pxV6&1f^h2g`TZ)%MvU+8Qbu_3RKRF9q^~L4g?G)O07D#R2ekC534H-7 z7RfD7s)X=d+LA&r`l;9d{BBSK_h)*}Ckg}vmI$69`Z|+u@te-E9~O18*s4&ojOS8V zLRES62%xcpeq-pIu> z{QP1Qfi2bObBTzwW|t7hd`!izS4mLXV%5Bp_J7;9Ltp9cYAc^&#dcCf{J~aXhC1(^ zOBMyh7LIYw_~aN=E=%i)e;KTIMkrUTJVOIz&EWWHTgKH46;18TUsh%72mUO5zAUvX z55Y}he`lVU%?6rktZc;Fplh_hNYb~37DYueOwOvY1EMfFsG1F;1?|y+)y+MU;jTPy zM+&Y57kRv!?IZcoVFK@Epu#DlI8D4tntYMg+CMP#c=+&uLV!YsdeugPFMW^ERAUuL zkEG&^Y#qZEb`SmHd<0vq{`Si?QS5ME3FC{1l195(PQU*&jN3v=Cc3033zS(WdKZm@ z(-A!tlDYo+A{>waQ&(Zqv|_C~)DY-?uWQGfl)9166S<>tV>#8As8N*!+Na?mtqBAMsr~db35BaBoy<|S`iE9*6~^tKbIWnE+Z3bWCsyZlGm%)oVYK?lsub>)S#|DIKkL#@Uh z<9%PgHWtl>5l918wKYwiZEw5@pFKjz4J6&m7z+&-B zcv9QtN!udw$3D5hI?Tk~u-r|35uGCes83k>bxWBGWx^HF*v-8z%R#U!CCPi?z&?uu ztQ+J6mQ@m-wEznS*q>@I{@r&Hg18CirxbKobm=jQn%vq6KZo7wik->4S5KPwb&EE% zy6b)-(_yi>?kqv!U?Qq`ifb7xVUTfa$&Q2LDAqz)gx~k_YXC_ zi5oa~Xm&c=3056Qn^CWuFh2f#I5MlV zdXMma+uG^nvOBQ9`uoB$Y{EkO%6H{UZDbNLO7>b=$c}n|QsBPXVMY)ZHyP&+kWB%% zPqO#mOe6& zE!U%tEqP6{PHLHi!<+zO9{SOwdcf7Y=QErqubuyPyoo>KJUh=HgZ`f+{PPQ_|5oMK zXoJ&aFWD@s-?KJ@~!7Mve)V*@t*u?=H4U@?tv=yzFvUBo#?iMpkWYbxr>H(u`? zDE@^W0B1Ic4+#D!dNsa=xcUd_D=aZ<+K;0TiO>?wXa`furnwO-G$Z_zMqV%stvJlA zWD~$8&;4`avtvuxTn;*qvQDBME0i0lgkNIVr}6(4wl?929Lk(8@cH6(`c^BEr?PK> z=Ike?YH*#QaqME#=D8I|t|E3hfR$_9?6N)yvoWd$E1@ypU1#gX{fz#saf-P+wm1{v zF~!H#1&9g?QdeT=$804+8PF8=pwBxT%dqzD$6wqA+NTfe369~Ka#V^Mu+?Er&$#c7 zXp{57>;bsiHdNK<#=en3`_1g-CLCwZ@UaQz-udU&ke#-DpG?x%Ir0X^wINLt#B}-( z?|=rQk8WHY!X@wuIyJ4t4qM?if<#;UCRyA65LJ7lGh z+;81Y>{Y|>KNbg4=Y&tS`@s~r*U+z_$D7|;$ri%R2_rQ+JF-{WiKWQ9<(sXohDM09EuQww(@mwh|1NG(7yOSBZx^2#^vCGE&9!lSb=j9vPh8H|PitgrPM&Fwg$Rr;w|A zSk79Q(l~H=C_pvnOq(APB#nCY*8-MM*njrMr7~)u_zE`4XU~Mrre?;2S3!!Zok8B~ zheU(H0rB5%avS6&b@&(>HAv#78)XboJ;8%|AOpq*i(1jF7qhPGhJT|H9c(OaHUI$3 zKGw@c9@J9|R0VF)p-D&|_47aftvGYkc$%#7Q+;hcJCIf-E?%&StzqoLrANmeHjF^T z)a3xg#@ z$D^NnjnY~Q64MQl!Y9n&zZBeiKVFUJ?nF(8tn&uMF5V>8yKTQRCHWCse}mtNPWb)n z68D0r`miSnO1WS+s&?Yj&p#fzewU*({UcyI;%^Y6x<2piJMm*IKS@JBLEaH`zjns6 z>H8AAC|38!l+yx7#?P*%VSEZj&NMg0Xik_LBp7}Dto#`#+{Au~W1sG8kT<-iNMh5p zQ4st#hs=w<0H1f+K9ixzO%dao$_BG*&|j9S_Mf$Y5Bg$yD_P@0l~sg_{ajy-Y=y7D zL^qRGiWWL=A@ZrnC%@;y&n@nd|0tAcmqxbLajW^=6FxZPzb-3TRJfds#?n_DS6A&K z^2nvB??a0cGTP5&;6IMEV&C`xf;yf^!zLE4(PEPUhy7I5A*nj8GEoM0lXnP;>0~*g zUVqJ%f!gP{!I6Uq@2P#akJxLFno{xOBXl(V%IBN1IZMczs_Uz!<}P<&f53aZ8*fZE0fRi{I+jNLI3ar*EjW>O+Q_(M*3qWe4IhCDA=2Uu5R&nN#tft z`hop2cUnMCB7E=fH+7M1XJ4edIapgOBjbBc-?@V*yKeVp=Pr}ch{5&KND($nNp-XNhE>ToOs(AHX+E~YT!JFBp9ans@ z0~}vWkJ`qs;D8L;8`IJsv7P|=E8~;K6Is7vYW$FJTJjS16>I}+2%No^`N8MBz+>L- zsr5T$?xLG2t$Caz_5icw6-T*l*uyhzQ2nBdU^(|Fa#2# zl!7gz&F^6{Bpw~+7tTelMgQx9CH~g^->-B2^Jk=Aq40=6pzlh?pN>;}Hd)-ZA0%Nj z^cCcUffPwWAZldu#)Mds_5tdceIvU(;@PvDXIZBu@*K|Nbr==mWND?6L~zd>B3ZE^ZWV=kch z`}@i4O!Lb)Yx8Air=Vj7VabNYnPW|EhfuV}kB?%#Mxp$fyWnyB)8oCJm6whe`ONTH z5w_OVy-(udK<@zXes=LpV^aTcx#&oEaz({XsR!`&uiV%X8c5Sxbs(UAba@$m7mN%D zH#mD>N$YhD1lv~ZmjAMHZO>t2gCDAQz9TB(B3@)SG|)o~b4pn>c=U^0 z1s3Rd=ejmIH)ezdf>nTi$u_=0^#rIFQVW5G5BAPSjv0ANH#`-PLo7E)=?sApK%TA* zb=!9Mnnwk7bMH;uT3=rAJFAHyE{?S9uM&z15(^sQI;#am!YAEgrBi*3@>?oEVu5&QJTrHeuy^NTFL~L4J^6j$1@`9 zQ)xqy?I~E=^&0P|8GT_Di}%e^vposAPNJ&ES18X$WOkEHpo`rum4TIY7WT}i*D2n! z3-?2{HCfZZDtN$)1`fhH(K|BD8}2ra+-73)$u5JPnzt5*~)`mxh;#p~zc7i)rxIQoz%v z%KHT7pns)9(|6n2-4oM?r@yk0x@E#SN1L8>1}XTVagaRSfQyo;?_Q0ee>MH^QMI`U z)um0b*j=7#)$;eW38$U7`aV`S4)`0T(TxOG_tp){&wsdi^}oH@?z(#iz+|?t)wS#@ z2|?H=eyEp+M8!i2Pn(}kTWBIPQLeIWpbDx=8~9Oc5Sm<3GZu^weKnX84K$YRo0DYwcWiVp$X0Mk28;r-&W6FFc!MrH9AMXB8`eG z|2Y%2F7R?vzE4czU%THV1Q)So3e|ivIT~!PIpIX=ALDt?J{Z~^Hoh~UHgN3 zdBQjp@bJ~RM|+G`5?n-9xO`~GaH>2WDXk~1268r&(jcPebSfSrmQ@dSS$A=gj{O4n zb{6gzIeB42R$&2%aOpA{w#TJMCf5WsvOk0tha5IKp;A!z6W=`!Fu9xY$`1H8Q-vfooWc^o<2L@F;#86vaUPmgy2dlcHPoh(?sA<3> zc<%Y$OQvS-t1U;Y;^YBpQTO|aeNuDIRz^~KW9sn*jgAjio}1Z*(le`!-2UGzU_^x6iS;jRUgMwRr<+jUs#QF7{Ds#Vr+s547bpfI)`?)*lA0Cc%EwSp4Nsa z*lCFJoKkP{tOnX zz=94;I@02`B&e}wiP|zNq$()*F$^zzBVnXM0ZoN5tJF7s@b!9c$bg(hBbv@VZs${3 zm+4`au0cZ{6JGO|@mNTkNJM?QZlKFDM2b#+e-)$w0b7Tjgme-{R8%)_T>SDhG4NGV z4Ua_0^s(;y=FtJdT>Zpg)@^*$o|9PR|G)+c@^cc%nQV^;r)^8Rx3eC&?q&kPT;fIf z#uKIxNFv{RSTIJjUnHNNVybMkrgtz(>iUvWw?N!`VTTFUzO2>|l!$Pd2*%?cpKPH_R5m*-{! zUaOMiWwe$utS(vd-8e(Q65hb<;NeKd&IwjgBO!tc@WWAZ?my%=id?|81gOeX+Q_Qi zz5wA2?r%NCg1JR6xFH$xX;!s-4&Qs%LLUfan0s=Ja7n8`uX?ps?i#~oqfTr!Q&(qaHq2Qa{Qh~P=U=TRE2WB| zjxl}nTW#SzFoCJvq~LWiEN9#{=Z?JmrJ}t_-I?#RWS?_ZD||PyHmB)(h?<|+@CVz? zm%!GFv#q2Zf0`xC4z5r@M#pnDs=mQ#1s}Dmr8p?sNvO^$L)Z&K`{jUcD!uQ6bdpZ& zYNQyYz>mTqG;c>I8JT6}t^Kx|Wrhc$EA%5xUg170tSsj~YERm6uM`_~O25>-AthMWA8`ZPr%}uG^N-V`4mz%d zjJVDt)rzTP3`QdYxc~5=)Q^zGk*|VuCI5{a9Wtu>Dy$^DqF95HQIJy4i2 zLK<%eUjNXwDwDxNEsWMMADOD~0kx~p-NH5+4NAmv)* z2RWC3bEX*iPuTkrA5*km3d$Y3@*lHRy}w$`DSu`CyfN(&2>s>Mc>|gDUOI^h*~P@llCayrkR`>mw3 z|C0tCqm07E{&ZVxBIu?!4k+GkdL&kenSL;negayqo_^vchkvXx`uCePYbM^D)UM?O zp{Ir`8M3a=h{F|UI|{3u^jm#xQPIn?kz2B^3l6>6)(5}hrLOC({~4ctch1uBkNbG3 zWs6dYcH>c~ykO(&oRatB2aA5On5&CTcbPzyHwixSqT1?M3gDq2Smp=FXeO-pf8fqGa7G1mo_=z;V8~V#x*&3?Fl6FY zGKddZF}L^0ev&~Hi9N(nD4~51vy1q@57;>@e_5do>t;f-@Cbn>sLQ{+7QENJ7#M0& zG&ixpi&=bNy!h`6q<=BdqW8`A;p;<2Hy zC{1wiG9pyr#vS2qCI6cchngqv*_^5X>lK*%lqX-6>i!}9x+?&^5diK^;K_tgch%@MN(qd zR=@Ht{z}WibddllA38OnT7ySR4SGARj!t}Ta9&#=f%h~waSYf65oe2a_?K5{W8;s8 zq+b&doUjZ@)PURn)VHwwN);DTlm$)~l&5Zg!Xe{jI^H_BJS;IdUfSBM+}za99cpho zOR{oZb{Scqfpa~QJmMM88lC?bS!t^95A{IE-Q7$Cm~ULtVKD#`T=ovPslRS6X>|9~ z?!h9F(_!a+YHeh+sFirW{r0U;4yt2jkIq}yNk`nEXnjO6b9EN&meE(RqlPp~BqSI# z5vI42%s#(-Mv%+c_B|YrXu0%gPLF+ntt#F{zdZxLR_D?+$)7U(YMUwmf!l_a(6pP=TV4}Uu(+f~8#D#HnYR<`-Jhqq$|9$UY*bIuEvdcQZLM>75$QPOF8DGnepC(e zR1%v`P6Ky&Y_LM~^RZ*6kE`xV=WFT1H2urQ;H%-?gE?Ti)gV98#>(es`yUCvIQKkh zBFe2zGP0|1TZcb3emLT@yH~>g9LC<*8cY}r`0e+W-wcmkMsYxS#Ky7Qu@8bOAyTAg zMfDAQ%JN#f<}4nKKBXHt!buH;8AC+^z{GI+lt5U0(Ex6jOad)C-nWi$jTmQ8*m z)^)1>y>eg)?+s*p!P3C$(V=wt6Rqv9xVE*sc{OM@jSGq2!0oM;%7W%F0ldyEBrKM^ z8#*gKVwR|?38@#wj#(#!Vxb|T!V-TytD3E`s#tO{yJHtEJ6sXh>WBeJyYKsXszyrbGGs{sS**3Nojh zPJm|G_A8xbz)XA`RvnK`KkkugDR{2ekH*Eib`h4ezYU&CLW#ii9c{l7s|(Xp5ji7j zEpz-F@McaEk-ko0)3q)r4NaSgiz~JdT|cENSlw0jeCUgatl%fTg65$8Z~v6^Fn>!2 zAfJYhd1>?)u(9#sL7o=~uU_O9Euocp!%1`iGUH8tp|s>E$z_H&ZB4<}s8-UMmC^a4 z2&K`@xEj2su$p8l0F+%%^{)*;s32T@Dt4zopT;L@Bu~B1hVb|4d<(JYexFy8*CO9_ z!768$B)sr%6vrpe4OJ?xT;Gc}Xt{HBBNLsNIYDGc=U>ABH&awAVXL_49M@1vuM#+C zt7*|4dW}o9$`w~(Hza)FlOj>h0pEN~d9Y=JDMoH^(|Z>_Q|}nmTsz7tWIxD>b^tnK z&zGrGRQ^FKygUCQ`O5kK&v54>Uq$!-yl~;)8tM*-i-2D{??)2(zUW(T{*CjS^*^QZ zUEh4b;H625T|nWF%fH4a6J**;v#4!F^G4N^NPA~U9D)ti?8xCF6`Z7)+y_WipvKFiQws1$V@dHw@xA7BDgvxP4>c8w1AfIq~@2`qTnb})0^oZzjbPP z7lqC_Gh-V2Hr`EwNLJ-FBcOf+&SqNGV|`!!gp15}o~&w5qTPqP9if8dLlz!&O}@Zw zh;*jI5RZ>}wYCYR!Q>yR{75sIoL$Ki~3iHOJTozg0kf#n3)UQdeRE%O2y zPIj?|Qg%V|EgbQ#Mn zs9)6rrINXCQYv&_U5UxWNl*s>fjiLQoA&)51!-)8K#1lpyrWq*;;h9 ziRU-S4~laeBG3GyIgNhWuWAnNRv5QeMP+DH@~>ID#_RXBhaChvnbfm&@}> z@RC5oe+0m&Kuab!j!3&5#8NrhH@cTx(3&9(G-~pD2bEI6z7OzWnfcV*PN}UWzDcRy zl|OoWrB1`2C5)OK87NP&mzD&=%E9WfE|1}&qW+Nvx%IqgufZ(Ts6IQRMS}q8tCU)t z^Ae&3qh9oNAzwQf-3}yxooB1o)1EsIDQ=}y=f|w`^go8!PE38qbfUXHrQG zU5s#A2|hEZE<9J9zxjeIviI%Dm5tgbsuw2!kBtjO5pwM*R$;et5Bw>_K6M|dS+^9f zabF2_CjUHjMbsyQtIslDl&=X750(gzl`j>v{C&Nq=4`2kbDCwd<(9;-^J*!!@XhO$ z<{z)XYp`FcJvy`Kn6gJlP8nIbjK~<1;t4@R-?~0v_8I^V(1&?fD&kzKz$)}%-~hZ2 z<~A#*_euH+a33P7HJ;h%d+ST&L(JltwDIp-?=cu9PuLB=ixq6}bw75663^{mD)k{# z%v%>(^2w6RXrMJq=NHXXhS+?b;A92(SZOMn=3A|Um0@m9AyG@atqbkLUZBnDk{#7- z=kA<3q=n8`B8mC5@`iw@gobpP{Cm?N;czPTQNrs#uQr(53Q03|HxE)w-^8m!o_ChQ zKE*HP|9tqTeX#x>(SSYXO7F~6fqH@uS_~sgJ^1>9+aNuf zkY1{%zL40vJa~E>_f&s8}p8*BXz}mo*q78LRz`cSNe2^D14kisK2>H zt{3=6V8jWif^ZE?iJpN4+-xvw}9q)5&uD|8u1P#V*;#@82xAG0aYDJw$mNV(Up ze@7Q&@cLG3bFi+9(M5EA5hj`gPpd`bJ5%whFRt$DN%?+{82|A*&1FP-`P#{AF98NF z?CSM1-xO}W#<#YNVM9Q+mK`N2H#V!PT5x7tlTRnU%1uJi3+IEsqM=5*`uOq5f#S}w z%(I8V8R2_Y?}`7HSv3-93;fS}Yd?36w-s#Qu~l#liUZw6*JMe%235$6WG5VPMqUzD z>D*HP+EKTWO7pf=$lE2jKcp`(LD4by?1hp3oszNrx?@g(C~=TgRrweI=K6)mft#PR zPy=;m)9v3x6O$3~kV#KmuZTB=+1STTzwz_T-)+@MRk}YW%^AT#Z$@bA$I6L%R)@%N zU<#oPf6*rv6*^2sOm~{?Yu4Apz6jhH65GcghyIs>k^lU^NC=BQ{^x+iRF{8~XBcMh zN}TvNo`&CppvI}fe*~`N|Bf@+Z2|t}y2@v|eH`2|SKON_lpmd?ChX)D#w2uLDL;mW zmNIex+HY#YtXQisPDNH_4|WB?-mD7Zg0ZL#LD5T2sTTaAm$a+9 z-)Wig^S5yKBu<#Vc|%q!JU4o3bJl(}tQ0UE(A1Cd9;3(zO&(C1yZNeM?dpGG@4cg% z-nM^H+$z|Bt!@#i7SK%>X#zrYBPbxC(g~p$dI-f3Krlo^L8S>uZz8>hnm{N)K|p#< zAPJy=KtfX>K>~sIb?@^#@3_yo=lt$_W86FLd;1RtV~wou_dC~IYt1#+ET6eLhj7bQ zzd)$;XX?y8kCM!p?y1c%g!LzNnk#iY&Y?*K0m{g#G@Qa0NqFZeOtCGkiYGlys z3UgBNojFG+Tc0&GZ5^jsALKg{*afa$@+en(mkEG-z1T2=bB_bJT=Wa;qG>f2ah^0+0{`bk0PyEKO_7I zt*qpwPt_p2H0PZ&x+9_2j!`Iv+G+(n&syxEl2f%rhD?K_>Y-^H^}~V|sQzBfDEwjG zGDmQ{wjaqN|J4Aemcq z^?w0WqV0FLSJ<*vwxgx6N7|*WuFSEHTZX5SEKGM1#NeP!QDw)ord3Rd@wV~x_g|Gz z>sgU?VZ8ZGDZ-|3?1E=0iT44*qOBsqcxu@Af#y5YSRn2P(LAeoBTRi!OHTE+A4m0*hR> zM6_()EumVx*q>`-b^HjX+(O+vPi@3+m5%XQ^t%Sq)%QEDn~~p&^nB45m>=&D&N=qk zCoU#oG0$lR8V~_DH#N$wS+e&&HaEP1qorGY#E8Xo7=Gd~pP8c!IDPdM@zvp2Pu499 zzUD;6x$gvp8>U9@|HUT_WK66=Vp&b~HdA|em0ld&la)Om#fy%`###r`@Ya2!Iym{! zbSoys_#+Z(1|InX4o_GF|^8p&% z5ohb6-G{9&=_s!n_Rf9F!1A}1E8gICS)s;a#1d-*f29v~(JpVATRy1lEDMBjSK>G< z=;72ZK^e`J2b>N^v-X|Fy&l4@`Pyi2%mf5hN+VQihHIPhiNLu}sm@S-yL=>hP*)bT z|1w*J{;j3UaRrkPFZRpv{-S+SvHmyhruycX^(=gG53L#}5P`n47HwC9?ea?uJ9)XD zBC>g=U!8VnP&Y8uwX*(OjXN!gX`XJ0m@Y`hABbTo8!rxRSg5|L!aJVIn#i7b$C7SK z;G3uTE}ug{3P#UZeP4-R*e_hn2i+-EQUwmPikkHT6diS6e17=8fM3i%2y~)HlS0&} z#HO~UElDi7CA3}b<;R`_F~vCkE71`X-(T=m`}Edv9fRZ}HH!=^t0uBu$cl6c>FWFX zdB|pV@73P0M{Q=rFfJnb6uqymr_Go3c6;JMFoya&`_QLf>4e`r?J#>$ItZrafB>}3}8yV(!V+ zX5nzOI`ZsM!GQwjn^n1{$eK&U1~pdKDR;7d26NF4sw;a%`NT}DLj4djs4Y_Xw0Rg) zy>j_Oj_T8_rQDa~jp|7ommWxXrc{2JdY_ugnT0|3p`kvZ+aohn;wFSGtWvfrw`x}&Cf znQO&7_U4SZ(zZ|@3j7{sGZYv2G;$9m5H|csPTv6yyMl{A{w`-QQ=U$WcP? z#djtbzRH!95MLJQ%)9&Q_b!ru@1lQWt#oro8*bdb^MC;AC_CRVrWbGKYXI2YS{L>A{uv+x3P6YW> zlzZi4x)s-~YM(dNS~o_x;Y3tAaR+lxc@kV^Hwo{BO?*Y(5`2mr_F+JJKYT`h5L09o ze!3sfr(G2B&`k|{f>AFGaXkqXak$TEI0f+^cmv*(6DK5TQH=uUpSE7EA8gEe-GtGr zFQvf!JUeP<)Q2Ce@4VvHl^Ph-|3;2p-JUouC`D(RkRX#5YN+Va+7fD)l$}g#1yP0U z8C1r}(-fqaf4i7IVRw$XqUYsR9#loMfhmI>DPMOvEbK~mzR8AMymB&IEHafK$SNj; zx0w$Il_=FN`hnkhz1hNm@(Vmp1~g61DMp)TipMUf9f!ksZ_~z1YkJO!F#^5a1;I2f zmg0(Cx%rYTEVaJVJSQg%Y~1RMlnsl~eb=_YRuRp&w8*30qgz{bkhOW?BcZ~C2GVcd zL^YJ9-&iCgELTPFY}+WSlmcy)kFPx}nDn;5d0BSMnQh;V+na?vLf3)-2{Je{(g#;0 zTy9VQwdW!dXt^3ACBUC-rm&EMg3{*l2Xalq24!TP!98oKvk6$VGB%yFplHb{LjU-Fiq3-hZFbg){6+?(Oc z9~`BT?p5B^6U|$Y*e_bvffv0>O-GuFjtF{r(7!2u$ z&E0x)Z7<{n2D~^sFrp@p&!1!8qiq_z=h^xdMk}SH4cQhV8lA%kuII@7N^0ImF>>^J z@64#>`cS`V;|Pi%$^Ze;VPkRYVU|9@GkEhWG&>cZkb$BQypP|if?7-nFP!p)KIKmX3$0Q z$hJ2`@^Q32pD~DS_Gbr0OGa3J8XpC+^BiSUjx>akiBvgmZt6gfL+f*^SIC{nAdQm| zo&40i!;-KiJMVqR+m?^Dm^a9T_ zVrw*G{V=L#FcPTu(ZYH=B+=oeG)7memqOb20>{k^acOB>5OAjkuj*f(7;n1~g}NSQ~7q4R6!yELLhn%-(*kp4A90X$NfvwF!}n$u30 z4>D;PeqYMbp!LK!XQ;!hazuE_EiU70rCT8c1q4O&roW#dJ|TOBl>#KPWMD$6zEuEV zn1}W`n0MDY)y4rpM_RgU?uFkNNz>!D#d_H)TRO1cWNm+rs?COsXon!W~PEriOK)Vh%%^UAX? zFJJWey6-_2rLB0OGI^Kd2bTQPC<=^;3i^%i5mv>`$mKT2?%JlFcSBl-=}2h~)t0Kh zU!j;u<3@LCKw-18Em+R67Zn#xzg))fnZo_5 zzL<*(h@uixHPllpf}_a?nTe4+4Y%agzI1dJ3$F{j|5h_Ya{6cmu?vj6viD5M%fN+? zF@xKn#6>O8<^aQamqX?Ynt2|xonpI|P4C+Qe*{Vu8rW_s9uDX;qXauC^J&C0etv6N zCC;eBAdMQrIHxUNA35th6E%@LEZu`VVNYaz9fv$HWK6ZyEy22qOGh3tRs6(z&L81D zuCp+Y`2-yQKk5Rxf1V@l?w%eGqp^S>jRz-{9(NfKQ!I$J3Dq8s=9lZ<=NmNEnU0UJ zo<{kf1rbsK9@KXdfLSG^g-~v+8p*-}D1NhTIE?TIjq)5QH#%y0u z@vArl!TZP<&IqQTXBrhfEIN!wJ&4Yk)_nJcu8-qO(CB`ARTLi|bO@+({qNUP^`Ney z^Y%Qe3aCl{4YYOKe8)iUN4^f}imPV+JJMhVVy|ZZ!`3KOj5P*U-e0u*X)XQ5m*3^` zKMA4#E?*36(n)v`8%O_d={HWE-B=zoH8hWozz{9r{239OyUSxR_>pyz~Dl_Bz*`-r~4N+>HhE zj-;S;5#h~kuJGqO%{$!Hh6HEsl$T11PbrFtZ#kb;`N;T3(QQS=XUA$BWnS@ z5iFbd+~fS2vZ*0B&Njx*UcA&-o9Mu&)cVuM7N_z4^XIt^Os*NxaXZF#=tUXO=03t~ z=7{HZUNi8x6?*lcM0$-W(kO3MxwFL8F}{IIsmJRvX>Zm(>9SPhIM;TU!^I~tABg(1Di*kWG&oBD?>5b?fP|@V3LGUg|Ip9j3Ic990LwYF~ zAA^!@-Ez`jaS{v{p05tAN=chF$PJx?Z_i~I=Af-WUlo7@>`Ro$wfrrJk#7pUHp-GTnwt-`3}1D z=n~5|=U8RfO}df=*_yh^XYP!7vMr|-$WPv1fB)W?w2Q1O4+mRhkNKshQlEyh3bYZ8 zt)6=?!b+m4ef&|^25Y%4xD+Ox?J;?^H_y4+O-i%GZhgB!a;;p=5MoJE7k-nGK^AI1 z1n-!z-ty!*s_QW-)J@xmB*?WmqUCVDeJ1my8B-fRO--33MzwN8DitVt00o60uUGc0 zY=88-*eA}@``mL0w#KVZ+sr8Ku575E0KaS|n)SJC$)r?cuY;D&L9+xve=GRD8Qch~ zhce7>v9ew)BzxX$9oK^S5~l|Bdvd!=<0C7r_0JyLv2{yLQbb00-ZePAzlO4@BJ4iK51v%FwXb>$=Xojwo5c~UJyBw&Fc(x@A z%OcPDxT{e=9)woV65>XeU{9jYhTXWzDn%s{dt*X*G&17m1kw$OWBIse0g&yQ9myv0 z#doZl=pjmo2cM?0rm6ILm3v`uMzOH9rZw^LG@Y}a`g8!lw?gU{$k0Xa^Dzc>wJI9P zywA4jUkm)H*E0vDCf95Mjm5+c&{&jgzwhIJ9Qi?;9ZA=qmdd6=kK44QQ^7=%qh&Im z`jYe!NB7U8*jOve)2wIM^(%2Uszse+a7!mj-c1zO=^6KF8uz(b_3X@IQM0RYgI;#% z@$Y<0yhXD$S9>bz0y1}P&FzNAYi>WZ4YU^HdjWxlW;Xm}j$^nK6QZ8eXl&D#Mav^u zNd_N$ZK?&cQKKIqQorQZueV8{Et$(RXv!8Om$c`_;dgHP|s#f*B z^X>B>lU07w(4ZH!y#lK=>0q}XGg1z**s432+^<;-lI*@ScyVL6&0?DAc28RFCk;Y} zgqxx%<0}^ViQ%3)?|0`H`6O_eO+9hSJF~wOREgU-|ddvr9o*6YeFZE>Jh1d=ttI(&3) z*%LsT?Q#INsBFL%WnTn{Gx1#xrJe701RdU;79i^GrPd}&U6S0#swOE_E04c2HPle5 zH@||7fyuZ|(@6I2okO(IzV~fP7T3J76paS$1kJWpE@#RAFbYGqLE(_D(;p1H^Ir`7 zCu&aT8;Ap%-H#OM@4(o=t)(+UlpPA(T29BND<(K^lfG-2@%*4IZu9R_4f9=lm%NB( z3ShP$>-h{?X8t?29+dcR5F_>%F@LP{f10MhIP*6N@Gm%HE4n$my~}a7wj#jq+Pr^q z{LDR{MeD$^ddC`Lu!wkWo)Gb|7(ZB7La$g|3ivzwALCRN)r__YL+CGMpdB)~UitFoudq9u0FT^ndTfjsAfefYTdS+0 z(J!eb2@?=|UqOCLm@uv1y|k>u+i4an#D4Ugr(Y_5UGzpFSw6s`&8xF)J1D2`x_msR zDZSz~Xv8&$RQ;$!L98t72lBqlL%jLQ9C}#`2-gTW+Ssr^Xhhh9)sS&=B!YMu%kl_J zqldy1gmg?_f>FL|&GHLy>;YH=b&1@1N^*4GjD##{qfLbiToORQP(G~T(RSrDU)9tS zj}LZxy2;~sy?OKx!?9fh=LYTg?aU~kH?nx*=f34J2!e>9GCRoAq2;X6Nk>?Qfl2)k zG#d(*<1a(Why$v*GRF$mkvDrCdwU_-{FdjfR^(5K({bQbcuG&$AOgpY_dwT;w}pfM z-N=rqvE#qp<;+a&nO=8KuKYY(+dOu39xR(7MfI{q0csxi`R87?;{uBW#=jt~`wgf1E+jyMd|Z zdJnD;idAtlbCymTxN-juzoL~2Y$`vqejpE}@N#O*g}lM}_`J_yEzw+?$&z2@6gZ}d z0%L(aV&)e4L+eSdUKLN&69VbmpLoETKQIkb+<0t`+_}_?C_v}CYz29R!C}+Z(Omn2 zM}0-R*6yeTfoia^1(U^%M@a->?3|z*%!bJ(sOvP;D)y1jL7wUniXj4R%Vmr0SbfLF z8;Z|e$)EC!?w#4MeAhIU0n5HpS5hzER#o#6DKuy`&lAGx4Lu+kYN#@D>)!r44Xrvv za^i3aOn@ZNwS@GoHS6iooNMt>n~zO@lA!fvr&K|HG!S2tD8E!XTa2%Xuj%FX;-pW| z+oJYuRWHX|piN6V`6D{$g4C%ti~FoN*FcJTGGw{hWaEIEQtSM~Lwd+T%Wj&exu~Jc zQb(_n^Nq1|=Hf2LL*hbcMng38;D~ukI}4KvJ!Oz?+ElDxgd#DlEWU8AI3{XD_~9(L zo?s{66x2&dM`eaEJPR6BPK;ZGsRX)LE|(fOHpyV;DngwN?p7V9Qxt@s))#BiC&&|S z^~IK8>yIRk1pty%;4*+0jQ>tWyiZ@Tipf?{XEzEt;Vq&Q^biY}$n@<+8lt^-uACVN zV?fXSIz{rk%jb!-XF4#{=!j8$>o$mEWa;d+fwC)Nn9+rt%3oVp6)~^8VfBTF_hvM2 zT?zo=YDbQV5Wjb8g@d%mUp$nSE7~Lqe63Uq_8o#AUS-9@D?(BwkcmpzsyoZ}=k81$ z1C(vUN+4J=4`unG0Xh_)v=Diu>jax{<+#C<&<2kN|A+NO8zhFg(4eTZnb!vxM5_o_ zOeTdXj_!pRryV38jJj)#jqL~$9r1OjIzeI_g?0&EkSbh+mT*)gjL{cMmt(jeaNWtv zI*=DYZ%tE!!2CYRnD;H;&a(38`X9W2PbxJ&5_4_IOp~}!*L25)xb>F-$cFeIcBN! z31wQ9uTV%zOxf1gg&TSJ-IlFrPFO0d2->JkNa8*gDDiQs0Ngy~EhY(n%! zdKx@W%z(k+&IZlD0ea8Xf4dJ~rHg0!-DK71IP$AFepZl^L>)nsRhzOytma|`E?scp zR{Iicc5IhS)OKPm9sxh^NlizKCatKca6(pxweTkTS7X3kA7s5J%0y7 zC+Sqw7uU-J$RD0}dd^z;*1E=xKGQXL6%W%a^>HgkCX6R_jvh|iKnnG92*n!eC4PSa z4G?&L$O;Lyo1*`?q2)G92MK5(Hu?T3!d8E5Tn=C?_(!1(%>56t=Ktf*r~2=5^r-;I zQSZ~A_p1eoXkBs*x>FHX4Ni_nDDB6SkbU-ZwN?`U`xT1+u?~{kqnVLwZtUMUh)7~wT096s@lX=uEl3LT-! zBG5YhM?4&#DA=f)3F>=SXj`5uRN!fdXhCN&Cyj~99=Vi4wnRaBoV5CdbaV6Q_{ezM z;z*br#@mBM6&deQw;pp<3(30LM{7J+powQi$pVNPLUhX*u=MFbzl6hkR+Da~ercMJ z5ClLm9;fjZ6I?Kd&(uU@Cuev+YZ?d~Sh zV(+0P)G7a^XS7cwUM9|~1-s{T2;YHKbG(jsUW85TwslOr)_xWB0sq{3L6Lm2kf3qM z>#NZ4n(3r5U7q-lT%(C8?;NA^b9@F2mI#1lQ4c|@h~JVgZD(3BUrfsSvv?#mKzYa` zRskA7CEHmuGE-fEOy3Jc$cDI!L@E&|r9rDfi7#k_VtXz;c`hcnP`8DCp({2yy1L6@ zF8WGd@;yccv}Di*6EqCkn;dCO7Sv=;-%Er)+e;+%X!t@RiT6WwZ0{5h&f)?rMrEt` zCI{{gu9z<-CWQTbjV+t`f(H984$VHYCiW&VllKW<+b3}@sF)>+9T-}D;A}U02ckTr z9d%0M>XD-6OT;R9A}MH+8-M&$^_Qc+R&4U`a#R*)pQ)4XMfRayK_CXD$xiI4xr!RR zl_Ggs;geLZE(eSzE7$c+s(ll=BX?=Cc+3)|E^QfyF4&l5$MFq-B@3B&It8jP>4>kH zOHAi|YoW?ZPqsLl<{klkJV%LN7-WU$=5=bzAhNK>=GH6`K6B3}bY-9T-}Pkfs5f9` zIiV6x#=llAStRji#2t{4Lx8=o(LQe1rYjzscFM16zGrv|WC&}GdbqlBRxs7aRzy>m zPs7GNiu}i&vp>(&^PW@}*e;qwov>;j9nTY%hJ`;7xidw)u@TA6TzT!v1jZO4(cM`| z$2aruy;KtJfm!-R;BfgehD?z~?xd!?Bfotl?J9QAbvdxg^6BtW4>m1TexTMG8nG zb=pj3>(Ux~JQ~=)=BcTe<(Qgs)L#(gJ${1ZHF(%FZ%SxB(+FXETy1|p6d4qktV=kq zB6>EVu?F8+3MGq7?X|Eb9j#3~aOi=C*50F7klgta-@8OS$%P56 zYS7Ajq|mo zxb(b#kHomX?;;dhvaSwFrK)Ju3rxOIIhl@XkioN7u2&uFCbL4NzDk_I&M4D++`XUi z`1|%Fh2DGwN-hk;kc}Y8w9ZlAx^)YRfbj8s<>`01f(Vqdf*~W&XI;%98}`f1Nm^gt zxAcshWr`qltu|eC;Dp#q2-zYACRMkF4iq$zwAux+b)RM&5IBizY}R@cqv{ z02o&((ZhXNP+)2BoJk<+uHl5~x7d%iAtQ%9YQY(BrCBl&O9?^gVb~^0kzRX8Zz-bA z^nO0~e8dA&U<+H*u4Ul6&ntHoyH?x20(0AY7A}n~T^fx%X%=h#`a~rN*3Jl2sKg^1 zFOt$0#+>XMDjPy;M)(}mUQ&|w+8n7AAc-DWOkbogFT5Hv-87x<5xtk+-|g?KNesxS zpNum-@^EE*p?vJq1s6zwuC1vbYe!Clam!h0Q|s5y78*~+5@ele;#)0l9daCzVk7ni zJ1%bXcXjt8F97Jj|DEawe=GeObI9-^@jKIpA=}n<>^m-jlD3<6p(KH(E(u-Z+U<1W0Ux&LzQ}C(5#O*=j@S{T zv~t5uIYDdX=bVQoewahUnEJ0`?4lh2GeqST27{!iDR#8F zEN%(iv5g*01RP5--+;IgsbPTy*PZq>Tq#nBnuc3XBUInflB++JG?kB?)|a>LeE&2$ zp^kW27{8EpAk#b`)2cK7f|Je#Gijv+jXL!ZeOy2Ua@fw;`q7>vWNXmnN54(}Fchs^ z|2>T5s7&+d=7mg)OCna=WI;G42cjiHS$ZG1Qie05Q^IZ*EFn^{6peh)7l-)Y)z2K;wIQ^4_ftAX7rC(h0N0;gVXUoQMgj!k&P=NGi-Ev8Q z{i{p3>Wh@Rc<>#{g~>(?%fL%OrteRy3)4~({cZ9sXzbf%KIFsDnVA$;)N+<(gTk8t z_lK9T4a4jbm&W=KtEJ_jmW!OFzhxK9IgHsT^I8C~GFZi+0jNBcrfBQRCpUZuFDr7bvz1mmy2*JB zUsMe3UCCX6?HLi|Gw|^Iw$BIQz54ak2sq?Hx?d<1& zOwZ4p1YQ82=tWc+=yu;cTc58xDiyBk*yLD1idEm!C;YeIs~uJ4o$cu>Q? z3c11EA6-2HTipOnF#-R2I!nZ?umR{txGW%OUwX#Om{!Uk19i+!A)=L z*aZ0}doXjq{C&3mCL06&ZKq;A8j2T{*UaaTuPGSM+kslJp2nI(G_vLgbUt{GQleIh z{i<_|n?W}{s<;4RXxWC@lVH>7R`ilo>)`m4v}|cR?CCwgofquLzq7fNc}(PdyG$br$_iNF(~(6n^4bP?9VLz-_z};(u}9S$7sfC zMC_}-WdWYieK!{ny`6`ix(GyYFnq2d8gJ|vgTC^kw*n&kjJ5t8&S7n<3)E?5dG4HO z2Q(D0xyuvW-2`!i4nJZ>p8Q1TBvbmJ^2LT5g_&a*XCOpzZ|QnkZ+83&O+%#sO4@E& zllA>ttAZ~7L=`MpT(aLUM+Cp3_J%XVr798QxSXh}+FkScaJh_%-MVH> zI4re-X#A2+wYsUU>ukg+wjbe1%-jkAOePgL^vX|q2sQSmD7^67w}j6kX#+2T3mc~f zfEfl@%S#RXnIYLPC29HUB{Q?e;m^6dirx-~6RcohQ(kE(>iCjB0OfR9@q%_46Gj@JeMKfI5vKD<(S^#>%<;;Ho#BVB z(C%sKDw^-cVg*yW*Ay@E-dW!AqSW*S3aGDbJiAIq0n5lIb+2ti+vM{&)a!~FqNKF_ z>&)AMWb4_wuN^EY>yL~nD=p7nkU}&*eBux?mFY7BKCgO(6b>{GIn)hn-ouPhxGu%pJBRDZP4(F^l zSUn%74aGac<35mkGximX4+b>u#1OK5QiFP@SSmA(6RFRs)*om)L+2`mZ(lKQ?dv0) z!KqQr?8lHvOYLXgEsd-kqxdB>q(504)xh_r&`a{xC$Q9ZXO$eEilnbKW9KB_x_Uh3 z&aB$d3Bgz37L3?$0gL}Ag#g6z1RD&;%Mh&4%RF2=ZR0@t=pi|f760ILNbuekt%+PwacWebqyc)eKEbJ=P!^y2Q(hKdb!Qed*rK z8&MiV%Qx!##VU737>PR{?a_;H!q&S)a#JPn@DVw7ByN|(|Mte2t+yhJAb+*ze;P(E z6H`Li*n4=F0}2ORNxw991bz9P@Hc-VTmn_RAjfV7jMh`vc3_AL;*|#Jk@~wE2s~zqt6*5w^HhK#UB4l42E3k=rYl7uNFkV>7U!>(5QnIrJLrCYt9}qcjm%DE5Nj# zNN;Wg+K_qa^n&cCgYFMwWTN9Pj17lSPif0Kq~}mS-dsA@FTYV@6UIIcyn&a&%Wmv2 z33{6dga)AyfCDLWyV_iSiOxTaO$h)}a>mpsp;P+L5ovSkigmq+=d#|H4D(I-z%R3o z*Yns&wC*|O8Gv1zOz0L0`&faURnAXyo6Lr|xGL33I~L!ig>c?fPpppv`|3UQ!5Dwe|={ux=EY&2i07pBY1DpRrx5; z()zOt7d7-n*1CEg-14j`CpHhf=J`p~LIVcMakd*8P!RMm)2JreI{oZ|j6m%1ag00m z@HmgEx5e{f=;hDt_s*Awkwhv+@E{A?gIk0_nq1XTm-|m*8P*S2pcoe?%J)P;NKLIK z?&EA7#`Wbj+)oFjqFLi1I~R8#iB*J+K8J#;T=%mGQ)ZEciM#x9g&3$HH+f`(s`*ujQzQ~1fq|(++0ZXXm zW{)ory;f&8&WM&0!@npzQEO@Zb)|HJr?03J`71eO6f;CstDQPYtX| zIr^EyAEjM5d59_^FvMgoCGIH^eT*^EUw7wIpl{p}f6b}1X`&GUv!Mu(M|WOZwS`@D z>F3Nil;fRIp!x7;e5 zsv(i4Wp~eUst$1tM&US%l1rj3kfk29AmfM_`27J-zb+lY7df zSQjXuTCgIcB%j>kBn5kq?J6vL>#=ZnUfB({-lAnKrM8kO9vnlIP&KWW6H_K>X2HV> zC@&=VE?Nt9yQR?6!9V~5j#h8r1AarHD^>dl^}AFs%L9@^MV*%BSe~fQCQ!9>IhWQJ z`e<#>C92-!knru};-!qziY3pNK0N&|gSkFS0<~CkDthS~!&E^T)idj6)bRH{RIQM- zQ!H;&#}YPwVAhvC-=r)dnyG3#DzwU{egmjJ=%rQucdW@Meyvk3E*w|p_nlRd6UWp| zXE`N0+$dJQcPe!8CmyHA>iY#SP5HN(KGI90BLWiMxD%~rOR)!iU6a=-g(GK9?R|Iw zGX=VLS$r%1oV-Cd55b0;M?#$W)#_3{Q- z|LdZ^9D9oNOyMK1Pf*x!uTGG*2l8{>=^4`n65M?cMw)V`Ceqb252pFy_ys)7LdNk3 zdSrX_J+!FZ3wNRnD$=LhtWlRm#`S&G#&0dd;eJ|uE;&cM51pMDmBN0?5|`4nD1X>-+LcQ$4eWY{_!4PbmC-{0sGUK! zXsJKj5KOs4t3$_iS}e%!F!+Iz9FkD;Hot@86~pFYA_f$Z!0#{FUV zS3=UfYRQW+qqU^4F_T4)y8OuZJO{mE-g#tWVk0gLilOBeof-FIY=3L(P#%YmU1m^V z%XrH32XF>@o%?V7-z^^@F~$S{eO@gCDoyIZ+pkMV0hV21&V}Sl7&QE>dnJ%|K@^<2F=m z(>CBcx86Ne0f%l_8eON0FCWEIBLc(0y~KdAmC?!b&HABM0fuR|V8REX<5@Iixdo3Y zeHA9=HW0OHJ-PN}mt&(sj@+mP#QP)AeSrI7qP5QhjW^peW)IRN8;#FWJu+jE7iD0) zd5{7gHN}{Z2Tg%2Oa||EE)W0*;swCLf3B=TT&gH-!@Y49Shj~wbzii9rwDTI&t2-< z(9@9^T~A0)Y8S~UOzDn@LmPsMmpkf4-dixPC^1gfMNyp`a~7_=X7HAt!VaYy@(8wA zbQKrN%DKSfxs;X>JDsjB`^(7MQN(=*FFM_Et#+94vB~z(!Zyu!WL0an)s#+n6I|3V zJwlIjoz!LUT_y9UmX(*OEkU5X!)@)2@u+&J^~YOvuZ0cquXgrAUx@W@n?Doo);)(= zbXvyw8GUG{Ew}TT4Van(@H%oxUkeUyR9Ty}TFmz6Qg4CwJ)k=aCkeaB8rTdbN{x7(jL+?7j=!1La+@QkXo2y9^gdU>^Eq%2Yoj zxnC_9sI*5oA664w1`n>O+5BAMf)HGC*?YZ~=Sk~0dD5LWug;4r_RRb2WTEDyV@%LZ zk31<~ChNouhDz^+afqF~wWrVju)WhXK$UwRwv+@*QQl@`{^36L^_&;li)jN$`PSFi!eh2!f@U_VX`J?9bk(YFD z3_GvzHp<<}Y|vc)wJ=ss^ZPHffC%=dja=roe?rFy(_4!uB%6ILi4XDhYVh!8t%5??4 z${%`>@zjo?Src=^TthaIZ!ETRzgbFGQO@W>%7Vz3(YSJ@Nbiw>Ss*2?SBQ6Ab#iM@ zDquIH=jr(Ad{E`2BdC{(9nE;lXAhi6tSfWnUllq$dl$3cZyT^B)~>&}B=ZhchVM3O zP-|uhZHemZm$($w?+>0B>VbQPIbJa;;Y%wCb-FiWeDeeR2>$I&NAQ?!9%-?U{~QL10sXX!fjgmm(9E&d?oyq5oCLA-rWl{gV;ZVWGN z{N}v(!ho`T2@JyK9UiiiZxR=vblKME;87rFW?nmRomsVEeQhZV)JL5+V@V@}iOR37 z$jgZ2W&a&7#U076po-fnYKzt{Bw+4m=Uz|;Syr}it-+dQ>Uh~w_1nijmg|IE6G7X; zkxXszFhSu_%ir*+U<%Ztzgs7f*Y4Qr6xTjoBl>zAVgfRPx*#ZQ%KfejDv5d>E?wCD z9v<9|sC)2}k6!f_x`RXE&VQlOvuEVv81@R&)Dy~>dPE6UM%ei>9P)Dfb$qa z-HCG$sBU3a!o9m3JnPg!aJ}y&V%oRj_@OdRX8^5|p4OZ7>VBGSjN`cad3W)wut2xg z(oF5wDB-|@j}(SyJ_I#-`PAk1(@GdPL_xBGJ45+i^e+e0NboEDY7gj{#}~L0pvI1) zMD_D@mq2+bm`WWp{2+M)QmIUYET83iFmN7a??RVrL-~d;7G*~dJ%f6V<3G7>TvmZ; zDfzOSxb7&z*zpi)s0{rbJrykRVTt{tTxsf!sG3p9Q6wYeQOJ@nrJz4U-U*@1a7ZbwPn?y^0O8m zSHuI@0q51*dp+Ol)L;bI(KlnecRA87i_Rkm%)LO0!GpmcoBeP8NISah1?rzeFLHYB ztmOh;n15(#8>Z+h?09`dX8}1Cqd*Amoc<3jy%)bHNPPm_23kOnZaEM{+nc!kLo@z_ znyYl*W=rr+7~op910r$L<$h>MO8%Zg6}FenAN2UjMkqY3LtXcZ~D?11kpqV#VJV$^U;?f%#jSy+xyX$&|yaxi<2% z(n^x@l*4e3fFTyF&wqK@Y*6oRQE%s9QE$i73qOQ~jSTGXWr%Lx0*qqz0MaU5e%#Q5 zYrAHM@I8BqVu6qEvO{-4fHnU+5Nl0%;oTdU)%mAlu{XbG;{P2S_FvZ<_@C%eH8w)` zF#Wd4DMDcjoC4cy@V!{5==HMm;Y_422`I+Dt~9y^Q&^^7CMu^jglmfntk#I5#BRvcf+m7?)$2r3!(m_A8= z^zP%%(tREeE{nG?(V>+4Ws@=Gl__0<2FrX2R+K9F55CJnL+vuZnaS2nZvCRN1-f9A z%ZLanxUbnu3cby&!5~DMnT?U$jSPj_u1dD<^^cYJbvT z?Ge4c@KG~*a4jH6wPezA;#YN)ig1}Da>Qkv&P@r?z#mvMFdw1nr5hTb(ho?LX2AR4 zGJF=+Mn!|y#(7}Rj!g?74z{{+8AN}*O(tg-FvwE$#F?3UmbSNe1TCW-9b4~qwS=d? z`nLDsQBfsnLMeaL$&AFr@c4QA@z@RdrD}P`;uv8lC{q1JqbC64NH-0r*wTGJgqt@| z8kk;Y9Uqg;9gOm2V_DjxB)(}!bOc#*u=&~-A^mN)2BDS z4*0BX|4gB6nomBleJOCsO|I-qvzCV52Ui&$u}2RCzEn!E-e)@T8a{BmAa|BEme4OG zK+dpSwxiy9U$Yumdc`otX77>{N3kH!l+dCTo!iBir1U;jh!{CB*|Yf2XFuBf*U}o` zqU%P9XulF%%}(z2KGPVPD!|kD_#7&*4KP38QH0SjxdKMqlkNt6?;=sxErl^SZ>66D zJGpFs-HFz{VmeKFB$J*l+PIjlhmN`&Z()MN7&ui+J3;B`Y?aTWy@WxD`kdYatqlJU zr_`C>9FCM$)Nd)Q8PhEuSiVZ3;qm$q(|A=z>KTS5UAWnzr@8s(vsZ4@c20iEXXYFA zZ3)p?nYTOgg=;nR^JhWlP7mLA$?Yo)u2CBtY;(jzme@PIhg#I~z@F``wPv1MmhV3V zTFut9EUtWjEx3BiBzZhZ8isWS;?dx`>c-7lf@^#A7`RR5abs?DNzDkmBo?)%-lTUU z2QnWPKDMPr+|un(inGN1U+ldFRFzx1D7*j(kybz&rKF`h1OXB0Zjcfd4U61>ihzKC zw6t`0FG{2oq+u-@=>~~KELd<~-SN54+242W8TbC@o`0OZ24gVa`Oas)b3QTi37hPT zp$eMxj2isI)kNdS`F5E$jN{G7%UUb0esc%kf@V#nbfw!=>$-2xx%?}r8fOSWFGfXS zR*fd{$JKXIQVf>}SuhcaA!Ia-DiwM(^_9e{;n715ZDfNQtNKX}!PBq7#d-bXsI>7N zLbr)gy`hj8g4RdIVwtnr^`_PWUX4s4!)-fBBEz;$`J1B6!CFFC8&FUA*y|7^VV@SI zBz}p}#Y_|Lx_MFJ<^?--k3?R@nl`uNvEvD^JA(|VD6~zhr@guW!jY=_Aj#C)#X&Vk zp!D-O-?rQKrwTt}NfWzWmhlTb>M-8>ti_bQQ~Ga@wP4WIgiGI)`q>6-#q>)yhYc|o z$$sE8da63H$tm)|=SiyO@;w{nY$Dg@4 zy|`Gthz#c~FBbj)O-L>h5zMy**yu%TP}d8ki0CaEPdGOGAEf$?<%s zs3K^i+mdG0BAK#(58uIN^fRNrZwWK_eMsF617?q=baX)lqn^%9!NnDlsYzoUfiGo! zI0zaGqb+;~XA7+MU3WtMYNSM?zDiy3q_$94upy1kNrT4Xv5$w7V@C-E!NJSW#F5Jp zH`U_mof;v!^?}*e{HAEB0q3`EUB;@zs#`6biH1r$ZpPBS>4(PYNk^S6CH2-ljoAq` zu_vr6h{%i(n_Rz0gvxAfRTGEH4DITUgM*8x&aOBqyMMW%b5%HR$V6x(;IMbGTk1|Z zxUYo!&Ig}JPAcpqHZ6Di(bO;7GtiydAgHEdVMVu5d-iV4;6{G>XLp(nv4;Fh83-TM92Pm*laJ_$Oy>YqP$9!(l+(<$BA5yWsauDyh{q$E#9 z_kSM$x|nMV;*~M?_hyn69B$_!f^$vd)m5s88IGK z0^QQPG27fA*k?2!cW2Ba+uuFAvTU)rT>Gi@>d?#E-pdHA2OiV`NzvN*U&( zgLKnbu#ig;BnP~W2eRq=*-%kQQGsfY4P(BI)z!Wg-6Mo3v|EWK(Z(?(qkLHVcX+&e>Guuzz1kOzxj-&0I z+NjcKI8xuC48eh4@FdxRs@>V_h`DW4={3ga?5BO)Ic5_{YcW@z8Dq_5bc0nQ10^H4 zz*mtR;%mh0*mRp#w~wZkr7SFz{o@~+jTxymR{4VJ(o5 zk~-VjHiO-e2)G;Cb_QEh-gtBEWrX|Qso+1=>u1b9gMGJ!uPGY7*aBQ98K^JMufP3G z!9P|eHt0`lwe^=jYunx4%?tTA>U0gQv49@v(fkE_6u<&?Wy9AUfrZ*5*8jx1?Dx=7 z|F1xp8Tl3I2}x4M%7KF;65vG1vl>Wb`2M0W7n7(cxO)1ko{$Jg@kia-`0s4c2SgZU zV*S4rlL{b)#veR{!NObOvdeqfPhDu)@+BwXow#b3<-D9#q;Gh5lV#-r^&B{t8lXNHRaYo)y$Xn19iAIt$GtR4H6WIE^ zTN|iwS>z+=J|Po!zE%A_Jy4YLka*A2uoU;k9>J=`CzXd+Ah~C3q&WS>NPxv!i`V~0 z(ty67C(@tcprmgWN%zh`Lb{u;6?jU?*a83Y__6m~>DVD>%@PT?sLioG=PcfBGef&3~F2$545*}?7g^LV=Az*(;Yr+q`FOvLv7HM-f7I-14ixH9sknWb`eN=fwvy3Eq6nomP7q2ia>$42rM z*XxF4{iz?XO-;sVJ|FVVE*?HIE#a(o6g0;Vz^hp&j5Y?nBu^J@!vx>c=|O}&_EIU2(alx%h^pWPC(vDMpOSe%AO#3+6G_WYUg}-FZeBtY<^-_TaoSC%9Q!XQY;=tWN7g z?-b?m2i))aTii!Ga#%~+AI?Tx(XD>f`&ULL`dQt2dY5(`UBGtM= z`ZOF+M43eP;R75}PVL3M%=Zbk9rIH*LE&SH=jNUP)#e!}Aaqn~LPGF6{JU6i0;!TA zGAVWQbC~@k^%tIdKdeerJ(Pl8LRSVwqnSa6Mr|tekk$-Q z|3c}ENY3J%`eAQyi@d_41Pqg-t`H-g*EQ4(3E%F6M@HN<5GcKg6xsN?sQX;}0&tNp!{;_ug@&^F)-^sz!kZbjCQcL~3i zW2OC=@GPG8}Uh?o+n`#DQt>;?t_s#qavkekcFRxal1xM zB@l3-)ai``G>SkiCaIpm&(W9q(bUfMZ?^Z?EJi0bx7-LTKM0gv+r-&^{E}EB!ATu( zsH*xS7+fh+3Sgvu^EV^)!u=W6zRsd1Xe*`%XjP1y_5u8IR8LphM@m)dtKkV|5MY+Y z>Av^t1{TJZljEtWa4e+?ge{(LV3wfEzXD}B&5&+9QTr(y75(Bew9Q#JRGpPI_nZL( zMRfkswCcXpu+T2PHA$ex3OUba67#Qa@oU;DKi$8~;}#S-E!hx3=^V_=(UeD&>fK`M*Bowqeg zQ%cglltRJHO{TAj&w4|?4=RM0 zW@kN-d?!rMy(7o-1ad$rahF>I&>eWwhFVn`-=sSsFAUh0H@!T(V{%7jdH(VZ>N5}} z>3dn0e_oaeC=1^JLUc6kDglPZ>$4{urn&_IGbVt#LM27O`Ip2$!OAzw(3Fo}fwDbk z5`Tr#`?oFS{u6k-SCE(~Fe1wDHFEz7SLtVxc?ELuNxbZ|0yGkMP5wfud?%{uQVT;S+-D+B7{U2FypAKl}U% zwz!jZ3MGXU^85S)WF>qPL3kcM)^^Om4d`&h{25gDwPr0c0Ki|&50F0cpK;9eXUKA* zeDJU6WBLJ-!2Kt*{fRvPNt8csmPz{?u!Z7H%t<-wofmU{ig90T-UPLb@LOj8!F*!i3mPd_dpc|D@$mUKyF z3wF<4MrV)hrJTIaZE*AdG`Y!C^@Tg3Oz+h1WP3x;Bc>&X`d^lwE{vFV`fEKEm{q-+ z#Kp(8a?sXJNE#gWR-gS;@H7P$7m&zDy-OIP73|?>+ zw$vxP_TYA~3pKf%i)dQ6OUag~V$Af8N89|N_`J3Lbe)yHByCht(eXLz?3Z2Wu9vv$ z08Nj1*%nXTg7~y!N}WTpy!tKBa}X$4?bdrnY0L-uovmxcGDI?Q8W+UZ^y+Vg+rE0I zd^0YnkoaPQC+y?8Yh#=?<{cxh#G)b@{VtO`c4R!yj54NdBTWt+(ziNHViu3v_Z z)qcFKGysl^2D;OC1DAq zWLQ=|^EW?Qmg^SjOAQGQ+?Qu={+PExS=SoQ{*r{ke~?fU^3>hi*@|1y!Q95`cY^Zs z^Zf-uxn*qK-PEjHWt|+HogA$k-RXt7Wu5GuTs57|Ev)EyM84Om!L4g+3Gf832=^l^ zTbpO@^t?jcTHn8*r~1^+%EJ9;wsI&862w|%OB@HO@u4+iwvo4JD-{z z>8%P}TrUu*>PzzIFg0<5u7K287TT}E2Y%6$7m~5MlaY}YciUp01`I@ZWveh-%4KRP z+eu+RG-jk=O=qKJo$S1>z6i-{T9(y+D*LAEsWtOi@w(+caWs#$WwnU<$FEGCpRMtR z`J1{{8GR30{QUBf*hV2X$*=1i_TxrDb7l))CO-~|^i*N-Q>iaCcBpYgyh(3!-XB?E zzno~8AmS_)S8p_kDT0@&s?0WsNbreWJ9BNM8fFF8zn6D)_N{QXalG7>cpCK_YIcWN zlsxkxjxkhfQ_Ab~nRgHo)dyGNYWrFhVu`kIURM1quSoB#(OW;McU`=$DCLKhz9$v1 zAM;3CFA=Y^rj&&pA915W(F){ zAMw`WTU$ihPLvlRB4}AfP~WWUQx{|QtAUvN2O?_3thuJgmt2SOck2u|1sE0FZsi6| ztom6fa7;g|nSMPlhrc!?ptSHxZ@S0F^%OFLpLK#-N1{%3Q+kZouRQ2KfEuvDSbxb= zB7g9dtgDl=jFXq)eIQ4WhnHSRgx8o`&D`}n%kbX+UQPpG97lKH*^OR==f|^#lRGeS z(BJ1)wz9M}|98+DR&GuZR|_kk{P$Wleq|{&fM+Eoe;=5By!mxt`i<9sAxhDKkDp$I z?*|N!7N8g5|2-{8FCzFoEh+gE8v`J+Zi4hYLf=O@pqXyG_klM5`c2@02VnCb9RPsj zfi3{WwX}HYd3k>2eJw3PdR_qHM+>!tf%K2w0fp6EodB(TcSCNqhw|K7R$lJEN}TMk z{}he6<-FV#G{55js8T_b2LKiLwQ)an@Ox!{8hLs7?hE{dr2Z^psk+K;OAW*=Te@E# z<#FJl`LDf|`bNKU57Aei}Z5JON`~g&I6P<41@ERy<_&M z1Buf!4t}QR`fMvLmE^`YpO z!L65Suy|SHasNDvk;!M_H{?zoPV2vMG8;HXwcZ)Gdb(v1JE3VqXVTkjl0eIo=xt~E z&7b=hz{}3%J@jmQm8G6x)z5M9Z2D6UE+5t}*z-Ndp%AtOjx9*@PVD;dXPZUCs|tPn z_g&~*uhMWQ=tpF<7aD`7WJ0ZRp)h!7?b*= zM|^d;5u&}hjJ#J9ZS!qs;c*-c1tdbs=El~$wn5zzb$Sa{U5~JwQTaU;-unZ^#Y@sD} ziWQzK`XwBH>&#GJQt2M`IaZ^6E-gG)bgc$6oj>)GvoGbHRSf@dX1JEqr_}X(Jge*s z(GI;q={bvQextm-#KXJAA+ztp7|z;>f@NMM1v*t+$01qA5#+cr5t4Sy51k;{628HE zPbj0xjQ-8a+v}1+ljFjqqtVF>XA}3mt`~Lg#vfc4lB!Y zs6(k$VQi_Brr8mMK<&al&pK=IHnQA!nXob{@ZJ&oYd@V4#&tHg>%AhgY%fC|m^>!S zTB(^iKYCI@d-drCTK2pS#a-(1FbkR&t!9v59OVEqi?8)7{5rHcd%J|@Iddn)0sbu9 zc{TYZ#zS@M$)BFzrNYnjddHP#;|Ak>3%~PorZt*soAlZJRy zq|I(zo62*KsRRtlgW2$#%dC@bgCAW*2?GuoDwj?MnOr(C`gr2rIFw#ny0M!Qbg^6a zP{ZCiZjgq=;Z@F1T?<~SJY;t^M@ACV^jK)zAtfzkp&9FC@ufbNS$$#B%5ulUsAe4r zLdT~G@t?#55W+0P=MjumZzbJx@|}r!LQ@q?jB`-wj|%h+aLV;lA(>-@z#% zNMyouOca+Pl8Aho$9wx*FAU6-xcC+g#q7GlQ4#(1C8nu9k%-YRKB-}On#TRdB0LQZ zGTV8eZ}B(3Dhf@& z*~2wl76_?6*ibh>k)Op>t13?y^(v~(JWw0v^w7KgQb!{67ty=A{q)J`l z;BrcC-GiNkIcclb_q+z_bm&c~W(x0{G`O(?3$4k%t)}i=s}teB(90Mz6>fBGi!EoI zC|;49R`Og+!7L!-84VtucIW0y+~aP+T6;*}_IB9f@QVmd`to3(T(TpT%G3?YIUNwc zNkFDQpNdai%IJn?)z%gEECQ^|J^`s+QFZ5otuSN~_RhKq`lw<84vsWj2-!0ZN4gjl^_}PBClx2 z;hL^&e#4A82_oxI6|5I{9JI@bg6og8%1jnMA_FaOFyP*Z065DLR3ygVRK;Dqs z-Oj@@k~m=uG>z`S5y6WN-2B-02rN8eea&Y*!frg2gz(M{Y9^)J$9$~m58`^poa1~* zo!UQjCxT4U2_j9>d~&`JTQEsUxLnwLh!vjsQ28k|{>ur=olp0e-s1_n-^s}?bW|i? zO4Dw~bd*1i4YoU<9SHR-%S?8}Ix1N@0i}f;(O=M6?6a4w=8r^qu@Q%jD`dnKPntY; z$6YDL&X5I_%tqhoKK!(Fb6*=bG}T^}totz5r)$#2jPzo1B-d6i&C8RG>#Oz9%cdfG z-vlbZ$vx$XJh+u}plr=FIhk!sicWm`V7>$3kyy zVh~R@N$wTXt~7C<9^O?#wnwd1ab{!VF|5E28aYrA?|VW;WBH$8GC;KBGqLCH;CzijOdjWpAunm4mK)`s}mK_3rIHrYSPRl2M7Wxd~8I6(aI z)jGWdBCUphJNfalPR0qZP7`1bHz`rJFaUKkcVDdD4eIlH-MdZi*H!uGAZoZWG+?h* z-_=&6ji>QR3f=qs;8EhW*f7T=uc(9IYwuTxxFqFdXyeJ1P7C$jTAnC{SoCy!H2Z3N ztewlhy3B|hpgk9TGqpRamMzD!N57Co^-CspF$#O@?_3Sm`oqkvX*5-|&z6KBN2iFGfPQN&0O`>1+MQX7Tmw(DU zz`Nd9b$11top36kxg&*+2f|{;WB#j^stE7DT}Fxghx^wzVrU>9JQ?Cp`Zw+kn5;Y` zbUV=t{4*m$%NUHH0THl-SdHQd{J~(s7)duhI%k1k-u9c>$oZzb?+T~`A9MK*+$vVO zo+utg5la2Jd*y(=9E1V-3{?pH%l3U=t^T^q`^(*#ATR%4toiq#KhA^o0P4{xNJoSwKv`bMO;xZ~jJ9bZ) zG?9bO;I>C`@`0sn|e(=d%tJ{x!tjr5~_B91AXyS@I zV?V)~eBMKssONf`yc|O^`U+3`DO|7TSeTr=X|Yrp;nJP;CN55 zGukGK(@pm(zyvZ8bfL)wp_K7c#fO$piu7iMX$5M@*_I~&1wj-eV#!k=%Thzg!s^Hb#8U$

%b*Luzipb~t3mBS6*4_vn-s3whfm}3_XX|DRgnpwT71w8EO!)DLCOn`|0V3U>3<^U);ChlB&6HXNM)$=XY6nD694B!P9>r3BPacew73Pe%{|Dflq|*pNPWM z#MLf{-~n*_Wd*VXPKiKhSJR+ZAUqr#oa;Dv*RSId-@v^=OiGA{M@V}6=1tO@H*b@Z z+yZ_iG5iv2*Et*@m zNN?SuVWK1lew0k~479Yg4D|QzF)`h{2kb3*dH;YHyZQhk#z6~3r^P_K3qmJG!yrbx z>O_+Q+J}ku;|DbL`ws(zhJFnb3mfM;?hUkm`w|U=j`90TA`sd&Gz|1>=$P18IG7lC ze85X$jB9sDcrYKRo8P?a@`4xZR&-{i3e$_DwSvr(wiOUJ9iSHa+KFY1_8ec)^SbGE~M2^$Mj;71eg@Q_>sTHtc`CMNHT=v&`g(5^B3jgRr^ zg6qo|Sxr(4H~xJltnUrLW)}E30yH9<+)_?k(A{eBk0$){7O?!I30G4fJd7XTBnC-= zHtj!k^qch#f)9e`E`E8c1TJgwAb~+|d=kz08d#qdu;LJK)OMg)vB~wZ$MXU|0D<=O zDayQ>CI9I%?zD+=(k*pAM=U`jRC>0=%x#`kob6oF`qy-hulGF#k5n&8%P$iz6**e~ z{S|ib6$rSwjnQtiJ=&|Gb}<*k7I_{vr?*z&2(hmavPcIZ>3cI(P0mdSXiX%T+iF&L zL+W6X7$$3idW*NI{aW%!D)W$Vlk#O-)$?vx<%>)TJy7}g;J<#3P}WCozeJ?(3qE6D7WxE%dGHQ?S4M= zOMqftsEd5Larv2FVKxNV0RCJd(;rxP9MJ;K9hUPnwM9FsJMn=`K67wd7(7Zwy+4k# zhH#}{#D*J3`hBPnDJkp0LPpGeTocHBPdpRn4n;bKk6e~U{EP=BC%`>zFW|3wBVak+ z==^{pDQa||a!jX5>t{Rm~(*Y}!Du2T4KMl zZPBx{1C4c9&p0zQMR8xm82-c)mFruGm4&C4WAoLisll4$a2HzwZ+n5A5+N51mC@c| zC$){i-g5>A6swDwn9=RE8l`vBN**E|O%LKYyijd@(Ab^7thZS08zK)YQCum z@!%<+Vrq}_rGyjDV6a_*GM6LM+2sD<7{z}yjyrQXF>^T~ovr5QX8sAmcagM;KG^M? z;@Z#Z{#tnCj&Mz0D5;Vf{7IyKW~FF9^u+fXqg^`Te~D;DQ|a9GTQ&RIS%2W3@gLtJ zA7b^v{Qv#ue<2y|di0M@{RvfaN8&NS-~Yq{JWlcnwJn@cz5_6x%+8o!BtFfB#8_91 zCx%^0J=(iKJT>qtO=$I`8Pdn!VBg)O4ayQ zJ1rj^j;1vyyVq>MM|E>Lx=*j(l71*r?!< z)H5d~ixO{o-2%`04V9A`oINJ;?Nie;`T29#a@4wh<1R;U>0xn3VmZpYXy?{sqM?+f zA#x2>__1}wMr|}&GovB+ONf9;>u4|jNp};s;+kEEC=&A z`5P`e^>H&d(M%7QyS?isnD*W^K6-t?&X8$AM+ta9wJK$mWz6lqPEMSk%;&oQ%H{Fv zrFi0n<)bu~n`0Y#k&(~JFLOA^Q1X2ee0e%2wMnyrt1VrTl4hVW5(&+_wl3$zva{(#y`}wDY6Jw}yzCZ*w3!V6l zDXz}qJ7@gH$KlK5B&&fDci*oj(s@)b6xll!rJ1Csg^#9Ad3?31Lhh20*cX<&eW`&7 zLTNgqSD{|Wj`N1LwYDqJquhUd;Z|^bUHlbD$cn}ZFv6!hnX}5!_US_zQFU>As1}%v zY>aX%ar0BvkEfh9l!b(fMSYK=o|1H&e86jO|E74idmh|{5{<28PipyQ@ zvprz$WmSOD&2|B9cCSE4xjUl{Qq`yTw)~j^|ALEWJ?a~c#x#2!z0ic}ZDqjSzuwSx z(UxBdg<)w=wQn8KZ0(LS%U9@S=x~{%wW%5>UiY9CVP5s!Zu=6R{>q$Z4-5v2%O>t1 z7KI5g(wEL`HSm!iu3;@c7p9uO0_A92d$Dv87J0l1Q3-i>@x>%}w1Xx#jLxvIw(Ct* zF@u|DZ8;}>4UtE@#%=`S#hDgFXE@@xH_3spOR!mYV`8;2(xEkpseg)PisiG@&%L{$IoL$J;d43kj}UCNbgwR zthR*QSgv-Ux~AUqW!orJO1+JoyzuB3gGu8CIt$?>LCJb8+3@6V3x+2VzR#g+y6`!{ zmUoe~n7e?#V(}apvGy-s_wQjWW$DW&3Pby&)PI-b* zLK1~!PE##pHfJ{RT;c?e8(oTtw2NRvLrZ_@c*2K3^F&9!ujGn9F>dx2;qKxUDE$hA zx|=xJf^xsS4){0bmRdY)0P0DQWRWjit-4HcoA-y`b_3k)3MxHBNq&QJSDZ2ZlUm|4 z2sU*meu+6J1U$3-Rd@8iX|#4MCjv#HN~D^?FMR>6#jt-ARWiNCzAdTf7xMXMqW<); z+J6nM{WtVqjZn3_xd2N41>F)_#>xSz9@8=Y%oA~b=BOFd!yh9892yV21!(tk=1(*< zIQiFW0+{3H+@HCm90Cykafn`lg%IUv{>JN! z2%X~nKbY`A-^VSAnq*$P&Z?>hfmVU)GsJ3lh#;CF@0JonAb3@IdaHq^Wwc-}0^1ND z$%XuvA_I&u#*CYafDO-~$=-QH#CIiGy0cqtt1a^Cfy zwA~L}LR#ml>RA)exF5}qFYDKRnaO|Avgeo?vC8ITezIv~JZyO+K2u`wZLg~XatnwH z-fk5!{ml)Gy{~lzS~Zl~CF8#AvU;ii`zcKbkH<16DviSh{nxn_UI z=gLMsM5=Eofro>P1cT)jNW`Q{$j(R{vZ@ICk|kO8RqUiP)qh(oHBvIKGKV-QoPMB@ z;+kJq(VP-Ayvn5_!KhaWbyv|(SBnnxD9F-V%x|M)(`>xnAjly_ZHc06wy?y%oA zZo(QIcUmXB0+j^pUw~1I@FZZC(mH`or)4K7m<7F$o7|pF9%Bms%9SBe;W9l zeQm`Q>d8}QF=`w?tY%KM231X_6;kgI*@rL!|3;Ht+=Nz^2Kjq)vjWX z8cMxT9NlKw8uGK3*i?Fl>>Bs!pLHYLgg-J^QdgwDkw3m3hSDX3rg7cTj&M`}z+S3EbD zXSy7H40O&7N0_hdCQ7g}PABa}=J;+ev z;;bzd(z^|R*yrxz!ZV>57n)hFw0K#L133H*Zh{o;SIe~a)GB&kfwYjH5jB2#>uEBX zj$*DGf(Y?#Bb^m}HGBdK6nSF_n0C@F%4)<BkpB4{N|@}4^4+6Q)Pmz8V129gUt&fcS6S7zuMl+w0s;mN8b7cvu`j<+U%CRp z0uJG74K#+rDgd_4ZXwR3Q;{y)(jYR(cz48c=^Si2fNxBTAR$ zc5K*XX3SO)(}&vCy65e?*!uAnoApQJKy^~bqZIZz?#ywA+J4gO5C~5yd^wrIySF?K zI^sMHAQ5-UVne0*5_b|=9C$8P*t8&B7wPY9TcK3PcT73*mksj={GJ0IF z)pl^HwFKEKYM^o4{-v1vb9;Z+%#_>x(j!Ma&k^f&=P7@>E(-`c8etjE%~=tw@17!B@ELtU3QxAEohz=U@)cm^7`7Yiw9_UJ;aJ>UVMW)M> z1=DEV^D9uqWzV~f`NfkgGi&u2?k}J7@mIfaP=`mn8xv0=D5@GR_EnVfFWUGIi2>Dh zQP{dXXp3k*(LhFzx;f>u(6RI7E{`g?M9fO=Js2#Eu1xSXBA6IO_37rgr%FbRZf=|^ zJLeVho{&onxN!N-Eq!)-6Ys)U9zg2xO#|=?5*PEx=I+}^Tw~ANSy}HsGPTP-X~RH$ z_A82-yC6Ja%qhI{TaxLxNXqw{)J#lFPS9`3#Hj+*9$*va`uK4S`S0o9YhY#jyR!d6 zoc(!ZvHOi^9B)#JrS$H3Ne-{SGy`lOH*q3cAKM@dkvFbDTXg5PZz9Hg!d-TK?fvB- zF!rdbrPh-~z*C$-ucMf>4gJIQ$ArL=04LL#9pWP+KzH8eclM(r5MVPn0O(=uZWsH(UE)xcPr#nh19>$bKd5-S*WVT4jI5an#s zE<7qUjcEOuN&3oVhe)MjtDyd)$~5_5z?EXDJvg7lNTp>Q+~d;URo2t`C1FXlsWoM* zSyNjzS-;Lx`mX!U-r-`vd|N4Nvn(@VXw#rOc-(Ki^5gs4gF1D36z2FKrS?%dDrX-q z(ugWp0=da{(UdXx9T$CwNXd-BCjA<;bS;iFtT||>Dzz);Niy)P0vuC$eDwSz{T}kcBk$YzUuCKqKlfLwocFpPZL|;&dyV-k7wwQP;Bc?4*I*I~TTDiw%YP z-7qBI3RY24njYoEs~!;^aBi(@FtlK!&ED%Ss@NOBmUHyF57`%(wJ8;yu`BM*YMM^C z_@%eS70h{ys=aKm+EJ9qKM+FPUF2?oGVEa)@ykp}ULA4x4B_DLs%%Z;@-BTY{ETvV z;p6b94H~Jt%C$`{4VF$;QKcV;+I7Be&cF%Hrlf}=)x^AjxI?I-O<$4QD7T_O#|N2- z3)(ND5+2kajqF=w;9CoWL-F^iaVR%Dxr+>)9&LK-z0%7m z&BbD@9TaK8cs&y^o+v+rb}bM`#Kbf`iAC?hS3BG}Md-%HCnBITcD5CZf<5>^ zsPMe{S&L25iOtkiq;Q>(Er$o(V6#2yjjcrcpj%3T3nSfKAj(j2+T8=c#~B0!WITyR z-Qp4hl^?r#yK67k8X`V)uBXp(cwMSr6htkd!Zy1Y6 zTgb#{^F;cOwgvSYE0JP)Q>aL|9ThgCArAi_C|@0?>y8;2a?r##0K3qc;=gF(dEw#wj>c#WBew{Q{z zB?EqRZ!hV^Pwbe15yHtww7OP8^uq`$hw8)8X$IyC#soQS$_|8L-GAyO4NO{x( z|4V#gg)aKJY#rNsK4ZWUozol%q7XQUoNuPj`*&H4e`o!Moc}x~$hDqe*TjB!81_gumeY9XC`f1fYERI;V_NX46+o3c?Cj5p=!Df*{ObBDZlsp?j7w` zXc=DBhX*I(M6!w(Frl}@ON;)Zwz@)vZ8QkpWItK3(b6WlHd>Ro-UiZc_9>lXG&lC^ z3~)dU%l_%{Ezvqj?fRujIj#nt1c7NKG|cWQ$&{4yTqfoXl+2eV&a&PV^}-U*+Lf;% ziILkjyBy_Zx|31ivYVV_B8zp6^KyATaFeAas`$&;sCex&GE=2OLMsQy#gB@%6&df> z{J*Jh&590W8bbs#AmtA&hi1&w`VaHH~>F z&6;thHE}|6cOrV$(^rVww09j;i-+8%!I(PaGbU^I9fw+u$^Bh+)BNu_XCT7b9nPJ% z{ceTJ+D|`A)SwYd-IRNfQ}bLdq%Qs1z?SZUkAI#R?K*cWblxGdG#1};eScA|2Z ziq}o%!=g;v^G8iimdGW#dd3?RdCd&IVYQ-pf)k4~tw;Lfhij|WV52(?J7KNt1V*|8Tlyoa!dwmY1( z`9*>~gye(y1#$-&3mm0>Mhcv){ULM@A)0PK3s#9!(fp7p5F8hK0XCtcA6`Z;`)|SDeQ; zK5GS=VDsVx_nE!LXdkKjwugc0r7@&qo8I5fN;JCNN4b;x{N<89opL{FBvivOV~nG( zYHGW%mNL1=*Te+J+iSPme=*9W`fgcNl83-RcWY6al}80nCmH^XK~KG2BoS1bf`8fM zd;@Y92J2P?=hTn8TsjOy`W81%=$)O`nJa#7ji`ED|LITiMMF1`%jYDROal- zZQ8Hob$Ql1P_>gNF#u8Zn6k~ccme+4+1PRvDHo3DU}4JL*+>Z1-=MY;HZ?Tjtc)jA zKUvb&^W4D5su#a4dJ3#A`!D01tX2|4yM1hC{kqB^Vt!&A=GEXi!6@Gsp2=E%rW;<% z$R{;?ZbnneC!z^t;(GHciF#l&0!pkJFXz`~Eqe#Ls_&l}!+b_dyNjCb*jpN%dcG9H znX85$G*bfZ6P7Zu*M-!n?E-a;HiI{3R%;d{Q?d6DhFjQ{&9x)*)ei2L9@!Ch-KYNL z3Q3DlX2U;M5I2=3vUjUQun)syWCwv=BS}}W-$2)e2E^Pt{iXL3`|y%LUJ8!a9LCk! z8vAw?ciNF(H+~nK4kJ`+B7RRq*MKxBd*0dI{9E|U+FwC^_A=Ou2&IC?&&WUfm zE9K6%jcgp5G>+HdWiR@Ky2)E*&@CI-lhr*#rA3^dPfN|-@Gj1LXvPPPv`)2gz&Dgx zDfRqD>Y^%RlEULjg^sqbNsKWM9)EX|nef}dP)eHSbXa~_c~KB_r|B$3swm)Ya?t#j zNtEWM zM(Ze>3LJ?Cr?Lg3CXns!tcxc_5mCPSN3)Uixznah;c&dd zR@e^aykf@&-EmBgD+clH39;n;r*ToFXmHIgEz$Lu)^a6LYi4WxyI+d7oXZj2^(xKtw&Ij9N&7S1Qh{_QI!jS8sX?NJk0r;V;3+nSelpEfi&sUwK+cD79yn9>UW;8m_q-*B4;UBq3%pPa|@ z;g29a2I`DRGYGEZrhI2t&Ip7>psVLgqOJc z4X&+FgfjNuq6mCr`07N{>hyGpn#u^X-}~qwdDCRW?K%Rh^2_s(Z**ZH`xmsCO#S0S z2Xev)jXrS6m}hFB3UXdH!^ivFB;tnk;t%tl$wk6G(tCvo*uD` zMquY#PDgF=oJol8Rq!M{@1x=?f~V2Wv3j=t?~jWOz}tP_|vLIWf0$v3RXL7+Pu~NoLS1C<^>dS2eeVf*xHJBOceW45{y@ z0P(1ih4&a79O6&c>eBKBtM$wpnRR8 z{9{*7ah_k&Y1|9h0&DVmdOtBbhul4|iNVOI9sz278+*-kD(hItR2!eLcG_S~;CZ{` zS_4nEDv3I|M8E?JsCMQl>GEytP<` zskU%F*U~e;2SEvN|85wC^#<*GEa||`2#wwRQY}@zPW;}=_ML1z@k#&55~S==W^Q${ zO7h8~Sy2n&wc+^KSRLYxcW~aiH<}yhTenS2T^z->Z5l+fte=1#Hd)XhpZCR zRgB3-c7pBeV8*h2#^+z1uuroM;4jolxxs`Ap?*oX1gGy+lL7&5Fm27fPLZmW&MyV?ry5RuXD9gF#)st$b459Bma#rZ}wM&`oC;3TlY zNkpK0 zm1n5_k}&jMWa7B-g%o+dqML*h_Rg#-H_bb2_B*FF^>l1@_}vxIZ`0O&l*b8a)^)L2 zkv8L7X``~31b*ecRWse=>!Q;|+zl`(L&DtlyboXD>tYXNbMu-5;tj_b8wK6PgDuTO zOTchv z2fSN+^4hyqffE&2Fxq*R?HNLEY5zXtM*h<2y`#fRsrI4oGas-_j{Du`^b^)g>$c6P zPX)kDGCLe)Cv`aI)1rDP09?NK%gO&|w^fmqg!PXS13Oh~+dkhsz3@f91G{s)LGsNj z^tk@)ZU9}B*~7T7MYPgR63WFV=u1a5U*UA0FYtKXsN^N!4sH=o+>Upg{}+4j9oN*h zwF^fgP&b{|7-}l}7`_6wWbFG=##~gFaXFP+^&NG5&hhRoFoHrNVak=`% zFOgFJ{h~Tc6ofg`XrrY&x4f=bB!E*Pb}^cv;Bv-vbsX6gKYvx0B2}T49n;tv$B;Qc zR~=91K@BO+^|a|i6W%Rxn1CeLJ=KWEK3>^=^R*Uf{`G2?M&Lm27mHZx}DPf3@eAXbZtOGRdPnyKeV2Q&>1QgYV@8v^%8b^bE)eY{ z1h21qHbSER(h`Xw9WcU#p}R~VsUNoY^-9XF%C40c+f`s0s+7=aS(@I>C#WNJek=RM zV$=0$w))-hxAH6!Tog0Uf`fWX0-1IlZczUA@LU^cdg#!?DM5T2xzQ|lH1VL)qdKv_ ze84N+`gzVpVKq z*XctHa}h?%B&EFaH+bmuVlCcZVOu3su@uTOv68_aCc}A-Iju^--O|vlEVesyo({;Je#p=BB#HZifNxKYD5 zvUVr%#S52NC~3586TXRV9O%ivi>z&j!$@=*dzJa)ryzI4D?ZPRSa#udb;kkY?1c#V zH<1LNYcw0PoTZ(qRjpD?K6lEp8=Prnp407piY@s>%If~5q{%Oq2&Gl`m2ViEAE0}y zF2xj;rzcVugO@a}ai@b&(&U+2g~Kpg=lqCwJzu_9SZot;^6=X=lGC`S51=Gzmm^$1P5@V$5umVM467w_jx1fjD(HNnBZ^I3 zOa@d%zOIs$e&jB?@Dg0{&}B)JoAmTUkK)J>o^M~(#0BO0|&?Z z8rOwdcw+&Q{J)b6|Caj~LGh=At9jo6vtFV4`TzPUQCBGXo>GSz>AVfgX*J;3E@U{r zwRSYjJdBvF*E)BJFthM-FHkjz^`7Vp2FxiP=*z1oqK14!tdN&JU+wOLaqe1I56DUm z602MIg1Y2kLEDN4pI_P~jAyrZ&p`;A3yFJbs;`xv8`jfZOzv70D_FCe(@Va_ot+!v z4_sD&ZC|(GCwjWsW3_h~ZgYo4y~3F@wUe3ANu2@Q#D@W?*2W-gbqCG$(o@Wc(ZHvD zNMAb_6HQs7+fi@T@oL5Dv4U#c{+gRO8~SF0+tdX8zWAxaRaFCGVe^sVid0l<9V+~U z+}PSh+cGWF4lbXV(oScy9seR<;usA6-PCf`+D*B*(^V1Wl!q<~50}GDLQ_B9QeR_! z^P2-xPG3nLnn1CD@Zu$dMIYxaaaeo&Ex8F8&q33%4R9c=KzWZ%7ZcT&&edF&!0wr9qp1lP29w+0+|MeM?M z&`g#D{}Y2=|C(H-%+mKJ

&jJ_6ft0ZqHgrUf#uNpl~ONy|LS4=oQ48*jL_NS}=QDl4oqAasS5R$W-_$c1Gu91wOgcWUS2!r{OC*1Rry* zD%<)Z>Eb2PQ>oDH+5xbFUu*_FkS5p z46ov&ot1XVT~hZd5-&)B3cpw6t<78BHG2vIDR9%T+)Fm!wT18_n?tt9pv zaxbajLfpPAa;UzWfo8j8#099e#p+o$7XpM}<^~cO!0a4;Tfz<<#pCTBmT*Zc8wJ>e!_xZtT0p@_@x z*HS{#s)=hni@^2ikWc+CKsDVozMKU%r`jeG!odoO*TuJW15v z?z9gd#RhCd#r1 zu%XI$!p8Vu(yu78=&@aey8J^?(3g}6!$a=bd1<{=Y*MHc55>newl4wKXYYVJV+1Xx zO-xydx<>htYRisMtdL&*!Hgmjco%=%0H(T7>QLN#* zi{s7|nd+v8DyVtvH&{_0VYoxU;mrsq3gNHwIoMAzP@b{~1|6xpLUOhC5xCdT*ilz* zhwy2PWWz(O@Rb~F&osWlwT~`@&>2c(%{rJsc}K8dClt(nS8k~FPJpit_59HbF04ld zqg}i=3lW#{=85|HyE9o|9y*x&uE(bZPp6woGR60B2hy#R-%UGoxf`!uT>Y(7UTUw9 zQ(M+#-jrHeUdzSCQf=7>s}4I(I5s`7AfA%FU>y_c+DLpS-WUgR?nObgV_KYz+E!}J z)rX-IdfZsnC57mbC8o}WSYOqS8nW)VnSfcHIoB1US5Y7AbyLCv8}f^qjY^n7Rr#~H z-fP;}#i%u}%DU#e9loZIE1c~SevyQkAwrL64c+>fx+m4T!`D&{sj&HSFMoIYU3y$p zOa$V5&!Z`U0A5{Y4<=`oW$msGKS6U)d5g!fy#l7EpO0((MSfqs&MM0o9Q!o4JR@3# zE|qcW_$|lSuqWex90Hw}M$K+OK#;Tl1y*YL3mdQW3H~CLoR{rZ${r{I!^;nkZs=o1qdDW#$ z5`kUqD-~TWxmfOW$`hrR+iN~UlxrTWI#=Z%{V%lR1Vd`(aGB?NW;LVIocsf+I!`wc zdu=f+kqvU1*){SjiRGi(bU|Ys*)kEg@e-{ zJAhBwq^f^E`=(!*MIUg+3V<1>CS_OtQaL<2N4+=GaIAiP9OFRoA14$*IHD<|rSC-7d z-Di6AO~n`a4bSl7kwVzntu^~G5yS+S3{Kv{!4Sg8YBd5H7nb3{RUmE=_8b|Sx=eMd zV&!Y3?8a1{m{zp73EY8K4Tw(Qh(=R$Pgvx zC7&ml>+6?bHX)uK#TBaaK8r1vRy>}YS&)55Cf}~W-h6Uo8h>DJfzGp++7A{%3-(q; z1d85hE*b|nO=m#?<3HYV)sy5VYTpl0RjszNvOuGIt(Fc0cp^LROpV`Q;tp_CG`^yj zbFudI*{bSwKaYJ*f+kr}FLSev5wCZ5rhR-rGEf5Nx~eZ;pNB4V;SW;YmqT(;xO~s$K8;jq!o4D6E-p-iSS#Ln5i6Mlp zv8Bq36s0cdW%RBTF6F-A*SPL2?KbWWvSLW~>nNk`8Q8WS8ncW*jiS%1g}&mGqCHY_ zyQnoFfhI#Mur&+`iv7$&RSZEwTgR7|Rj)emW`cJ)QdA`@XEYv&AJD$odKel$B3W-2(+YE_auS$es0|b z4-Gyu&Mi}5&JEp8-xrGD@8s2}0Ytgh_=1u34&S)t5Jl-|e2vak_^dvC!T%HCLjPse z{g+kuKWEi75>PLl9gUXWWKq~;F7F&CSoUD*Pc+q%7!eg?^1^=eFQF5U4Y7w-oPzI7VKq+s{h{`D)=1w!d zsw82!vY^a`cH_@hA{N&~8CO%T*KSe`oYe(h>bQJ6Fg`uHc7PXP-Y6cIlG0bb*JmF& zLbmK#Mi{6y>G6==^BXWQ7(X6k@U^fu?2VV?Z+%`q$`{d=7POpo=BPLCSqd9ZUUQHr zEF*=!+N`UyYFnDD=&`UXUQeheEXFV>XqIP|dRc;;g+MYOdhc@>TKc@hKyJibKSR^bSnhcVur={L-I09PwWvN6nE6Fcd`0>F3JLINzYXn+cM_wh_KjwmBA=?Lwb^CF|NW=3e z$N3tZ74%{*Uv9g^mH3sKv?oU0412e>GWeOq46?@7x-)mV)q3L)-`0y?1Bm??47C6G z0v8*ZlrC$S|LN15e9?mcCg-QF7;*JXWR^uiAD+Ow1e2VKk{x>O&x3)v^6=Vxa2_5= z8{ntkkcuncn(pN!CoWp=t?FH88Iqq;UcO*F-E2rmICG|Or?0O!L^8yKZZiiHV=+O- zTvZ+50+YnuhqqJC48%GsuSc$Yn>710K^xSo8={KU<+AeFU=@RxWCstoZ*1XPy|Z$? zXOk#f;W~Xvyy^N)r98;gh$)vIjy3U@&13uN;Z3}x=?E`&gDqvGvS&J%PT=7Dp3$CF zV4hZDf_&br!$Nh^`8-SO7zecRJVLg-9}xwAYR)^$gHCIB^nRmYd@{~Pe@%fxwCF13 z9@*4IpIFYAUPQ|u-mSsBbbTo7KJPt{^73vT2Wzs3I6F7F80EHgYP}ew6IA$QireeA ziWHDbd1U@%d6Wla-Xq+c5)HXyc>`=_DYTz|fR*M@M@^13I}shFBMcs+7sn{QoRTCa z)YP(&rDnpD`pb?>PL)L`RiurqJ&K!hS~sB%NfPP$Xc;~zujaSU#oq72Lq?q0AXho` zQeDN0BZar>iF%@tn^n%ZNEMUHsOwc$Q2Q!Pb4&T7%ygtdW_5q1JN(?=i<&a zhSOs7;iPv&J{_n%$}7bsyRo>U%ZDd~DWu&O4yG(ZBv-ug@TBuS&VIRsn}ignT%1~w zb;IG4F+}L=wh7D$<~85@BrPAvgf2n?VufY(jkVMi@M&f{G+GX(*n^Ll*vGo$mT{R2 z=Y$Z3CluNQI<0wCHj2jg`EyLrW-q|n8e2LA3v2nI)Zz~gouNoy!s5G*hqtDScAoBV zK+Gchk|k}eElkT_+X=71BFi`y-R+!_!`m~G19i~xQGd9cHQc-k?{<6teHRW_*S$0* zsFxd%AK1A}Td7>*oX)+x#5oywU9v-Y3XXeMkkE3wcWbNsr{^(#{+b#Cg7*3yoawhFX%k{cmK z9}lg(`eGY72$qpbL&4lUC#iamR*6|Uln*vuqH$7jhk1VL6{gKvdQEq@P?9bIZ~C_Fdxw=L1Kl z2XZuR<<5Ay<|+;T%__YXCJNoQ_acYRLCPqqhbyWx=leB~6dzbWdi2U}O#O|sYi;f5 zO#Lb|hwBF!#eFW$Pc~=hwbuzf)+zz{JL^QO?cCRIX}+sW-`0D4E{I~gW%l3ULmA}9 zt6vlJElleMq1|b(=OeuFgZPODd*#w<#hJXWQtnWmfQ5)QZKhdXH$~r=socIw~HTIT6-X?J=j8uIky-L1#J&u zUJPTTQ`U`+xk>o}f(+c>am$JbLuT*!zCP_{aJ#${zwx1gedI`U)`4rQ@{T%URcRV3 zhHf^fAV<87VLtHeTw;fhdU0)h^?07W@phEoMWQ_u%hma90oM+Q=Fahzb?K59c^sSx zXN-;o5Fy>p<7*M6N)N$R*Y#+|?-u`>6UUG>_*ikrhWLXhmo)Edf#cqukDAKhR!$54Z%vPRy7BQR zCD6gW$LU_)|~kBZcc7Od$nJ?QCiLsMVkfX6RA!wHQjHm zxWYHx_?UdmF9^5g(mDH{Z|7fmx15-0ZZ7MuV7>z}HrOvy}%0)tqd(Tv%-{Z~ql0)$?-6uP-9^#PDrUakejePZ0RgyAar5W-5RM>(> zDWZC8Dx7l^of?qLfJH@JixCl?jt(5vB}}7U*MzPKwS<3bl*pU? z0n);j1g*S6n-1X^WNL|)UG3Kr;xaTc4lJ{`_n_Yc#V?v!4rajhQhe6jy*yA%?#n1Q zRbLr|fJfk*_6F70pzmFgK3$=*8gbPJTt4%Ry0YEQ7wws}QdgH`=OrVxq^vtyGtS4D z9hvT=PgC&WYkl97x}@YI``W2?K>SE%L`1-EqeDv8ij3!8mk&IxdM0Sc#1Y<; zkRnLre37N1+GXw`<~KnAk&!jDU~=@4d!GCykshj7g}b7{&Jfw%gCYGIuRqnvn(<>t^kFe`{;WUwG8O%&n==)x15Wtw2ixW4`8_X3*PJZtiSyeAh_vVYOcca>qE5~@nPpLQ6*~8+{>nR)Y68TZkiNnJ zX;6n|%h{cJ5ZP;cDbpKO1gj&QU+s6RAWu_Kq&r^F0M~+kFDvf3Nf!p0S?!sk{fh*b z%(41WEM&D5hL(x9*qgUmY*3sX7N5SI_E^*O+3x-;Prfn#PzkG^fdLm9pS*?Ejntx} zZ1`|WL`er+KR@BR&pt6oQu#(>I=-%iL0TZ@dE}#FPqEIzz3?fh^O3>VPk00}1qIxO zX@ugN+YKjpmn?K12lSUP3k5HkEwgHNRj=@hWRYj|PD0cz&R6K^_V$Q_TEwQ@NM-B% z-Nc2U3A1aA_(K2Hy?PlIYcfk8dj&c&1!gXHm73z_(p^^7%f!s!=i7`Q%zjj79DtUxaDY8vk3ekzIDxd_`RmQ$-iXL44*;fJVFR z?@mT?>f;+Rk#pn%kJvU`9nlKs@4jP6NZyUd4Si(Bfm8t0wb=I&CBGq>f9<5LC9ssy zd)$TSdI1~#(hpvqq7#HQ_f=b`r%U12-1BjV9~hn)rV|ukOOFFwqD?}H7It1!woZBQ zamEDM*XO&&AsPfN7^Pk-0|WvIG9Tt+3@kht2NuF*J*Al?+kMD)(^mtS?*LJe`GN6` zXwqJP`nYxhOC4o7<{XS&0|dyy;pO3#g6J1cd9W6r@qfp0B)Ev~Bh4%ml?K&-gHycZBfqf#=cOBmQ1)wG)2T zlXkL<0@p_amET$MQMCg!0}Po3#S4T=zcQ|!&D?7uKAuh*KHBfFYcDUr6uLAwTR(a} z*g(;#B2P8e7W_`G&+wJJ>2j9b9+4DDET+lA+5*tA#6&mcqA5fqPguR-t0`SkVypF@ z4TL4rYP!-#+eDEC5moo-!pR|EMO4)DRXNmVW;2yUAN_nt?$Y%Sj^eUsXEF50H6DRv z*LTV>N-5l;-h34GCtvgGj+0q6z6F9W?ruGHosLNHt({P7(%LalC9bO9??%L1(o{E3 zA6efu6Izd=2M3le)V(?w7>;_gSG4}2;dJeI{W^b&&1c_rwd{b~Xz$=U&6pJ%fV}YL&<jWzOD}D;jCI{0TdrWo<52bQ*Or89a7EPvaeV9gAGy<&y}l zrmoJCP81-(Wewv77Y1)T;FKCvOy^F?SEQlkQgO-Gn4#ao4tp<@R0|<7TjRF9pY!Mh zazZ}^C5@&hFPV1TO^=}j2#dLr*J1TdB+;3_ zbvncBKRSU6ot@VL+OhPHR^9ECf_rJWU-oA!JY@R4ir`|pTc4mEGXVL8<} zy2Mp}#$|%fo`drPcwaMmGAQJw^>a? zhf0ZjfP&O<9&koe!_2sp5aq{L({EIo_F8rm*3o)~S0df*wyjQ{8q|8$_?Bvum8yG% zXzd7pc|Mn-9|Z_sISr}H4ngA#08v{pT%XW-$0G;F-Hv`iLf;)3lEeGEXUFOY0~*V% z-{)9m@d5lNE!JCS)G9I!xfAtC^D@(4+&M=T7-g!+M}srCyfhhu8ISbGech#h6C-@I zemCX71>jQ`<_P?X>{tIT1l)@MEAjuL4!I~++jgRbF&5YQJ>b`pra)Q7}lhd!=={d|KC zJ~0L1NQ>ove@3!Df+pC8L{SYWf z;?TNqOPj#0tc$7PGk~2%gD0I<|}c?=JTpodS4~%VzwbiNd#~T>r1DELHn)YtxvVios0E%rHW=a{5eq z5khFJC)|zD_QjC!NZx{c%63(KoaC&m9e*Y_RaB8A&!LuUg3QO^974lkneF=JO<}m@ zkd8J+n7qz`dSvf5F)1b}DnJa;Ujfh~IYV8&BW(bFP3EnqY;TXd6!FL3)jI+=9_pDO z(OC|ISb~!;dFlLwd%XEavN9NuqySd?zs@T0Pya*jSFj51)j;!sSt)f4xzw#Yt=@Irhh1T@k&kGC=2DcH4pFltV6c&qxF zSJz92&iKucyJh!|D0C~4o5p2vene;bV|U1%tu4#mLp6x&xKV{t2pDGQ6<+w1lTwoo zd-j=~ddsui@a`ZY2>@JN&ZUVsvbkpCEVLqvr;FZUCu?bj!vPR|8EI31vBqNj{(Va& z7x?!+`B6PSL~B(jPPc4s&StS59?d{%?qSr*bGoq-?~vNo%LAPfE3YQO;i~H|5O44h zXh0QrZC=pF^b7C3*Is$9c=315$vY~q)Dc`EcJj{Xg!0eVSmmL|kWQ35J$2i)M_=k@ z?)1RiyE+xVz5dYQsD&{nmqJl+Ii>Pz#UpYP-0Oqx2o?MPEh>uo3~$T>dEvftoD2?L zHwSoaH>E{66;yBX+-z*A?-x-k-EMeE75m&AL1uFNr7Q+unf7qR~SEvcvxQAo^7;h z5@UUMl>iGMS5P9}59*!0GrHk|!zD`bv?wd`UC3L|MPuCLPe!bj@6=dwicIl=lV{g> zbhuCVfB=?=Bd`4mKANqpqpUp&9}+}8i^e9bkTiK zmm0-PgO~`9$3BEB?4QV;e;|E6-kk3a6l!0GHzuLj7>`@qqm-Q^hz?={VWXAqG_AgJ zbbP4l7zxfpxX9!DzUu@i?$BuWmS(hmQQnXuZr{~S{Vs-|AU|h%h4|JG_1RXBDau{~ z>u_exBXnwx$E}}PBq^s*PUs+r`Yo?ZF)8*#r8M-VyD2$!EMMnt~*<7sC6?*l5@@hX14G}9l zg&3qiHG-6lSdj7imL8dG(oc5BB5voV-yz@?sL#i*xec-_1tw$u&S&uXKiflfb?cCK zD#d%D6}e*%p?vF){my-wujit@Xw;BHojm!P_=0U7x5}#<#B`?HMCqTY>L0rDE;iqy zY&tGBy9gbFgb*bcS(SfNiLee(muElA?;u!S=So_cSSM8$R3#`6g|!f_y`uSrxWx|)w8ogK_ z>D{wR8?bK*bmv2BH#zRi7?knuh7r0HBbZ05PX6Yd`lPV*Lj~1ZCqNYH%g(B&|7@R8 zc{jNEA1O_B|5BR%yOpM)RfItwuaE!js>vr+)+X!=uUc5G79r(J)XMDaz~b#VBatih z&=cM2E+0rv`PY%CA0RV$#yYpTL9#~`urEwdI&Q|Y;$&nllhv9hMwTB(4J?1N@ZnJE zEr7gRD#Ojq4cDxBfmxq49sk02)+9>HZyN(Mk&!}oU&XyRY>@xrL$EH7<#5?gP09HG zMosCbS^l4|)11Gs9u;Xhf%gD5Jrq*p+-=rhax4u;UkBhwFWMRx%<>bsD0#qF>a`%6e(FYMz?>x zpcI0+899;o)rbaB9|qj$Va>F7_u^)hf0F`|s>D`W_4v(Y{V25bK3_8hcwH;;$DhSQz*U18;D)x0n{OmrYUlX0VLT+Cx% zP0sahpVJB`frqYiw#%&~@%h21^UMYJ(#)KUaS7~}AXcR2!OWxyFJ)pLaQ z(+Ocr?Mxc`Oz`58fb5@pGmNfpkt9oI%eD^^80U_lB$mCAos|dK!nbb!)3X3DrT)!q z^I!eqk5k0X`^r)vLf+~@wZQjH)zjnpfw9CRa_nV|Xz5b{dJov|j}OdE`(|Mnavjtq zYo0wI3}FeXs-49jk%|X(e)Rh+RLO%9bpRD#EJCj6+F)j4y+*G)gngltY;@D{W}!P9 z=UM8ZXBbblyrTNFa^jn>aR<+TfR>~I>Vne!2=pX|)Uc}O5n^$;#wISn zO=hUem6XDUgN3G_pB3>20LZU&rflR)G-17;dF#yX``pc+dE?o&IlDV)7Y(F~i$-CF ztZjH#XSZ1i#;V9!=j<0i?9h5%{K|ZTRB^re%xw@)`^{!82!Evs+t{)=gnQ&BEB$$) z7?Gbc`5&mQ3_eC4pG$i^rl$N!(5DNbhv&bavIyIW?UJ3_b96sML@=redDgFsrAH2b zHaOkr$|A#McH>D(fe6x$+6$~i&t?kO3~eG|LapKlXe!lxKh*bta-ntKc|U*t0M*nr zcPsr*uY@TqsOH^E0B+Jg4Il`9>4CIVe^>+X-Aa_##OD3oOGL=3#C~_z572}Ya`V2G z04|D9qE7Bza}z2!82r6>z*m|A*gZBaZ7UCcRseK4}A<2#Uj+~B$==Wa@ia1gB<2S12LI>2Z4%7EZn6M#b!&>0nVy9eg;$bZWwBG91D zX0e8(?-o4hS)KU~0hU`C5M^Pys@Va)xmW(Pe}B(rtQ^&88X(a6d%?f_0i9fA_2}n~ z0gR}?d6c6P@u8bC*%QLBwEp-*86Dm3y$qjoRyIfKVs&Lp%Rd#LtG^}`qcWKI`MQX% z;V;V};g5xM!ifIOLBBf{*b9Joa=M6LL_qb`f0jw~f0pUbdt^Fz^~#h+$ZO~GCk$ys}%;G>r z$g}Fsk5Q+r7A|JIB1(&(%)hjqNR*Sz^GJ|^C7e-ueB{y+-r8Xkl2T3N#k0$VocTTo zTKQ-kdg%~uf>ITXt3fl2@G3Z8id<1=iY%MJH%56%fic0{M|Wio$oCU5N|@8tQDX5` zlXTAFAWXyV=iB}f`fj`BYxZu7io|Ok(Ii!Z!EE2j{S>#l(-xJV;QG!&Yy266h?= zE$!;~@ij4RR}0!Ok~q~*qnpYa&%VK+H%_*BsXao9yHD-WL$XQl0GgFWBu2MQ@Oy-`BM!3V_RKr z7>?!p34pwH7TiqcMSHHl_OJc{Vi=@Gmp7FmKUf1RRY06ZwLFz>asWD&j}(w6Dr&XR~5Mw#a2qNg$zN6EfrXFGwUbU|rW#_(p8Np^b>O$GSq!9YW&>qyagis zyPUEpf9tPpiFntQ&b3jc>N)q4E<*!|kaZTQer2QQTmn%2S)+fKkWIYqai-hq2k5%= zXdd>0#1D|0o8{RlroJ=1VV^8!%x-U^(|Nu$Qx+E8czwSpy0Uc*jOR^P}K3|gNsCss`#&q|A zi9<<6TNeI7 z#bbJz%|AXYjJ@`m^-2(14Q*=Vf=#c~KuEYFr5?~KuMeQRAR*=uKED9hE9Z+B5jPM6 zB3-tIc^BuSiR)SCMJM4}^@-3O&=q#c^)d60zK6q@gRCuxJNVr3)PXb)IG5oBwxU;Z z*9`WQ-IUz9h!ya_p=;~DW=5#JO>(?>yQ68z4NZU|BA*HmI19B5L(E3gtPd)cLUnfJ zQbPlup_gPcQ>K~JMl6R|@~T8@-Zxl1EHCmD%ZVt?nQGS_mOL7i*|>do#$W&gbR-hT zBk#?ed+A_!0lAcy3rxm5+!f~KMjb z5Tr5?_2RqLd(o6*Lb1o8pB9>)lAbCjs0Bzi>qIqPax5Gc&q(Rk(fw*dGvViNV zz682*pWX1F9k3~7<5Pta@;VK(_N&vEE07d!AaLTv1fs=3_$8oiz=2={I>7p~ZNmqI z!EFn58WZv$PH!DB8fe7Ld`fj^Zj)AUE3Y&>FZfB_1Jf7>0S z!m`foOpIWw=532~g4I(jF1^2Rh`CfG84A#E)3P6g61LM4fLd2;4L+Dur*$Q)S=rLwjyJCZ1JD4C z)|FUM$D5HG)HzD`!~fKXnqL|r7;8I%EGZrL3zV>>ar{!Bv93xWm|Wu6-8Z7BQ}U1n z#g163C57Z2aiQ3TEn$A!M`5*{)>ph0Bt}iC47QUM6SzqmFdrC$he&QRLo;5Uxy#Ec zd%Sew2WVr-7#MFyppnPt?%j^SrAGvgca@fo0FZhjBI;lRZnz)ne(*VmqE4$FSEq0_ z)7om@#NfYsWEl#4AB6pqoG^ji?<1$vPR{JlTHVrx?$wy&MeQwNXn>Yqi!cHvW(v^s z%ZS&=sip#87WM=E#nvGd-`xA$(hmq(7l15}q9y#LjKq(S=E)e}dmplwskV`pcovdp z5mRKyf*EV9~0cqI3$ug~5Drn7Bk zBO0f9~X2126AK4)!o6 z;K}{|LncL8!K;G6gNlm8Z3j0eZ)ZW7t8xiGZTC6BYJy!Hu8$|3rTXgisv6ev4J6D~ zji(-Alt((fi&O7&sJAl?UO091R!;0Fmu7UpSz%|gL%WZg6cEzk*zT^~YBJQvKF&62 zZm?Ku%H}pP{BnMDFdFl5s^d)@N2`>$X|O=fTE7&$Qu3 z!t8t(2qCJ$$8V4h1)P7O9{O$mE=cf=-Higx!&`QoH{1QJreB2!vJ03079`tyUrLev z!dAzbcYc&`@Qv7boyvx$iaBQItYw*}^ac>g+Gykovg-?+=$>2!lH zC;Cler`DL(VEmhPhf6FHw@QlpDR<&~Y&WNqGhM#*)qYjoP2F_2P1|5eP6luLHy(=M zw1jJC9fLXQ1>AIU(qCuy;<>F|#AYoA_EnVwbD(^bc~u(``*a~1vOBvw6a_n9rP)UT zp~twm_|BYvFfs4by0UZsN!wE1o7=~a<^;}kC^Q(29@UX%{q$T&S0#6kqh)Q1cabAF z{M_AVn!Lx4a4eReWxi0+(02L=vQ7MESsj{LvF=<(aAA1Q#1tX4p;Gh|F`Ml3U~OGM z@S=eB+2_W)FW+l2f8vacG(2TAzg6>M{{2Ur2q3ig$(Ne<*vbnF-`|OQNk3r3VV7Wr zSE)Ju`7r|C9bKm%Qhqyr#FfcS>h-y_-k?vL8v=o~&ArkK{OK7kk4+72MnCU;c@=E> zq$n?+?eoEw#f{9*4BEPZQfrv8!lK*h@<^MMN8jsvPZn*n_ zuL3D@l2U^5ic;1RckCbi99*fZ|2Cc)?rz?|Z!f{WjPE^nZ(!{UUX{>yc;I6H?{eRB z@N$Pgf;a%*EBrnmejofh!0b{}`x9{?-|xqx9yKcQLzC60@4*hlqy|7Ktw=9KtMVH zGz7$uPy+&Qh=__vliqui8ft(bhK_V;2@slql+dIF2*v+;cXjXc?!C{w=iU$Zxo16m zSY&0+Io4PsYs}Gp<1dRmmc1+~`KPhK=eK}!i9av?SmGw|&tFGAa&>|jLftLIAKlXs ze++%${%5&Y1B1Ky5HvHWrO$J3@Pi~c5JL+kt=Vn9e=9;wOX*?qHZMhxsb+ z8u&>yzB^U;cA1e`qXH(X((60)>rC^9GzR~?;XTjo2ESs{ZF7_Svh25?9+}&JR~o;x zk))RLg1K<}+KcSKlC&eG{RYae^oJT2FKc6|qG;tTr<`Gi#K0{^FaC^ZY{P zMn(-&#y-lz*W*3uCHCZQ^wybL841ZGZE_Br6kWQ@g6pcIG5f}C6K>0H+!}P|g;v27 zQ+Cs7q4Sy3D-t4K6^DuNb2_)yR6%yP^Lh4IO5euE9x7bB^zP{}AyRQm)iL?WYU1!r zz#S=H2Ir|JR!{X+iR&AZqQQuSg{u;Gl`ld3&%7L1@OTtvtK<9@Pa+ET-EL4Ja_Gf1 zqEsx&(?Z9irf}!zcefCqXG)?wOQ0M2txq_^%4*=0XGQ&eF>Bqs6I^R7fs8qV^6_8Z zSv{TR`=n*ku*||m@N$V@s!z-Z|YFv z$~)!~<#9lsiP4DUOo2SC3pw3;Wb=A6GV`N&^KWenUP0bg?5cv=yyjeZhKyah(8(sy zOk`5(t{<2l@OmzPfT=$aYrFGB;HJfeRu0)Z{{6Gn@PH3Kg3j?A!BEoj_~7k*);5yj zvsV4G70%%OST;@HuW7=J!M95pAIo;KHt5a=iCW)gq$$y#SA)3JI60sGa_vyAb?M@j z9MFQS(77dXiEpn*bGDOSQxjC=`$E;UPkt+Bb?v9#Cs^`(tVR&ZFFyX(;OIcVT*pH5 z_2H7~tKlzuOqOfo#}_&q+K*&B1zVBfBGp|+DBGVHWdfU))7#Y1zRrO`70A7+g%-`_ zyktdd!&e4Ifm&=rh(NwK&!Q+gj2BjE{REimHq}*a#ZP}jsJakO9N00WUqCXgcI#M) zJn&)1HayvT8l(o1>b-TC<>aEDF})Na+ttEKKO7%&hTZ?AlW<@O&*Zx>nY(`G%UT{j zz7fJKdef2{4Ksmnu4L)GO=~G_mVXv7^Yz{P2JKUCUd2l{y(;|t3g%)Ke}9;TF~M)? zRZMck^E>a*9mXe|ULVzayx{se_t4w%4$hfpP=iY|%{N@027D-Rftge@If*}sm#Vv; zt@_EaSH|FU)1yY$9i9Gr_RAk{{Dkek)ex}2tuK7uWZr{!T2D|l z&oMvN#C~)9`_N^Z4)>SIS3d+)uI+7jcLTl?x(g>HKD?y~yjx}aRqB4@WiN$OX_puE z!UrcWxAe5M%kr>W>pWzxJ6AH+Q1h+Ot*VeuUiJNbVR_e7(er07zgiaHTDutAYHC3z*iv68y+{RDkEQjjKK}DEZ4sv?`{#<^|4&=EKdackY~f_2CI7mIlal{eo4B9D zKUYEYs({4+1=+p?%5#qWB!OOo&YwPg`poI`XU?2wJa_gSBMZa%^9(GPn3-9anJ=+1 zT?7s$Ha1Q!9xhHcettngetsD#DJdDnza7Wu&Yh#9r@KH;f8ioM1O3H|7Z@2YT;#rZ zk>%n=ZUGK9;NTFre3gfX=j!F_*98QwUk9|mq~zbmEB>qpF`hmac$|mk7$4|3<1re> zV?UdZsQ~nyJocvpAocfy26XKBiIb;jPoFt^?$|$HJO(;W^Vf?PK*vrTqd9)!_(|GR zr%%$HmjW&_(ww-$Bymzz{|Pgni=X7Fi{a^|cdzoZ7&JVUl6HO7r$#FfVff?QI>b$e zHKWY`+P%ofw(5AfEkob8jqN<%#^hjI z33C)VO%r?1fY{usHsbsaBk1^XfZ7v(qKWp@Ntr*9a7BXY1VDicAM;5`zwnE{Q_x`0 z_d|;R={MI`5o(4k5I5;{fm6Q|KzmK5u^%8Jlg(D$NY))X{WlW+H3foyC*kKP=seAz z)?@^!fXI$tn!0T|dSM%HCJugkstqfy^I#(2&V5lxo${~BK!1m$x9}TUC1kP2HqQe( z^!Bl*PY<7z3+6tZJxj9EiNC0iLY$JdJWR<{8oMMhcX~OSrRp6o;@!HZ?3Ug^5#}iN zNK3Si830uSyg}JOnAQmIu(ejfRnoeKhLe=FkmF7^1R{Pf%ec5&uIlTpsi~$#vHV|lynFs`;*MPSk z@He!J*dZTMh<5PC*eAreWlch>JXYp&ZU#v%k&8QzN%r*~w@*L!lOl*toz%1R64YGl z%dfwowQ>SoG%#Sy9x5*rIiuV9>x2S-EN# zCCUydmU0jo1P(>jm&g|ux1FMfOf=5RWT!EXMY-dsh@k$XqL5$tpzU-I2uqCuPBipv zwB`N=dwkfyI!ABCY{0N%37aHtDWpdfmSCyn47zVnB@oAAtPnKn>xME4&!`*%iYE3y?%b8)!37Qx0{DoP+jZrRbF zDryIY9XanI`0o{%9;)Tqu55`;;=&`8ig`2mt2~O|*0$csaKCoXd359iIF-nNR5g(LMH#6B@= zAw488qXG?KJ{&~GF&ZFTkUkrlBBcH|iP8EyapLK-vFWohDMA&$lKBq|=A-gxdDAwC z-ZpxM{o@~x`qo)1KW#l0^MCkB{VGb~sN=C|1_Ld|L4U|-e(O8g3l}TajWYhmd;Y(# z#rE}v_sRdyFaI0UK+FBV-_$>_N`32g1n~F&$1g}YX~b04iH7;~5G2x@BYso*G7%7A zS27g){z&Ei+QIfy^A~yI%RoFn5KsAzrh+9FAA__ObOsu>QxCaf&3z_=+wix(Ju%iU zr-QE4)x)<)h9j->4mqFh9WvoqH9VIohef^4sY8>`juQ=Oo?y9tf;^MRS5vbz@EwB# zvRf+8oU|c@UYAWidR8s!?o^y!6JT53wcgX1+;_zsE|}G!*oU(Q2lDsGiAu-GD6E?=EYoeDE6GBkQo~@|r6LSG#ic_-P1B*2wk}9L+au|OzF4$AG+`V+*vGXYIC^6oses38Lt!`2PksEP5EgbhhY$KZn1x?o9?a4Cs=>dw$>>Ecl3lA~4e zy){7h-q0lQjsvj@B_PbCeq{izQoehA$rp&!sZ8&+=`YrRx!0OHa53e}I>lpX)33|< zOQ=M4i=wu2AMAzk$`xn9Dcn(DUopbY`jP1Q)?O$>PB~wzW1&QMY1T7U^WK8u;VawI zx9Dk7X7(Hm=&1E4PEEhO#X0$VQ0#=?%)$Fm${bQRAnu^cDtn-bJMulRMP6k~a9P1s zH_u9p=;ewF9?=G?A=`d?kCDbeab-t5oS{YblgZ-nTumtabG$(JsNkqzyVI|Cas3w# z9@hD+<|Zwo4L6;|Z0o{4+Hl={7~q|~RubpGvhyOtJvDz^jX^MnXoQgi4jV*8MH}es2H812=ysUE7W3`}!AKxr?LVRB0=1qtbvUPEx zJSSIyl%d;M1SI7pp`0b$#MlXW7p8)oc6DE0l^L*(s9`FM!508;~yB0Xr_} zUi4A;gI{ETNvlrbNHCDQ&HI4%T&K~tcA-@E^j1G0p>`(W;Knv)=)+P1yHk!Vj)6%t zLDc#&HB&T`aUynD!i_i4>W+(Sb#+~L(NIji|C3mR)D)Z6FM$`R|7t z{qN{MdP7yNW&^N~&z!IM6pP<~6-iVPi=j zgTLuNL$%A+Gqt1VcHbHwnl;0Ajph2)ts&Aw=7gM{?2s+NeYRV-#|q7VthF>DFa89{ zHb6s2Kipun>p-}7&O&9CRs5*g7Cmd^RUglO{A5*$n`!3zOB)&nQ~ZmCIy>}ihTTo= zr8TD8Nj^pN9`L(LSAjUVyj7XpbIaSvIW0n0hH~+g;!bIj@3LZ2sB%te7UP?s%RM#h zCr~Z<6WX|-GMAE6Fi)kiG~w&aqGMT74r}CMFH36ogPT|14VN({#YWAT96^FrtX~-LHny^py^mr3_;iM-!^Zu2?lUpIGSN3Y zWQ?5p3E%kbfOegZ@0pio(B=_?YgeKDq@9!~1d}CA(zZM|%)6zXa6T|ZfW@m)$vzKN zCDs#VX7Y&IJtWfH+*v}4Ep%i(8_8J-(M90^2~H z_zpQA{tj-_?nW1q>AZdJ*r*k|6!W;?_i2-GE74fvu0%iNWBGceZ}|I_uiHa^)J%j> ze}afsRfDHbeLDMbaj-VoX43Oe@MItn*WOGe5)?>xDp26Xp_x95tg01xL`)as3?_nY zW7l6)@i~ODNGUF=UwEpV^gb1^Q`7t@4J=;8K1XE` zq;i-hfs2ewW|8cvbYs_kj?!(;>)C3+Xv(=&@ITDhvM$71y17#A_1%ivo5?1pY~2a& z`)0Z_41HB{GD9zSLCmWm`p37Hkozi%sxp`dN0S|?>RMhCXaYk~>=wYn5^Bf`CApmM zN^w3Pp_pnT7VkUB9BnF_l~Plus){?P4UyZpw`PO7;(CpZn7p|s*cdqE-PX8vp`crp zPqIql`j9jyXvK#2vL@T?MfcB@kS_lwwG|%@*U~a>$g|2ATx`PXd1n_$Yj&7_I`P%} zPn~Cb3+vPm=|3UTCQ|p2d)#Vb`7RDT9g}3qPOh)x`-!Cqn-j*_spbm9Egg$87Wm@H zA;jV?E34Fqp@+qi{7X0=E_LiT!-6Nos&Gb?K>e|!HFUbl2cM`IO~UQaa{p~K-)f{; z7g1krSxXMZVzsP8ck*tXRH6MG^3=BR7FpFpR#$Gg{Cd0F;WZ*$ zrlO=I<-V8732`*}BhBJbX>MPHC4)NoC&;p}H|JAfqN_ytdQll^a=@{*;P_M{1&%5# zv>X{Q%FtrrkcP=38oO1b%^h)H_t*we2a{wkn>G;E9-a*9UUax3Q^(VJ&!R_o5N2 zSiPo>=0k0vlDW##ga&Bh7*Xr(O9tl+ZAH(chIvG%sOwR<($7$p2yQ7p|~eSylaeG;zL ztQ+=_wmCD+`dk!lmGhMjOu(DF^6R@2mc_)~Mky7t50BQSqgC{AN?>u}oJ3bKz=LL% z9FO$dlUsK7v4Dm;^$j>4YfCA}(4s$5ETG)pc|Z;8quQZK@pig~WJrD!MrZ*3VyITl z>K32*RUNIq$AIC%I?l;DW>1VyA(xa{LQqeq^p!i8Fw?`M*B zM?ErIa{+>w`EZPgH>ZKgRpQ_U47EfTRm>vf@c%nz2w2^nzS+A z?K$TSEp$9}4+}+PMO%+FZLRDIZR2^wF`g-lDh3MH54+?8u8J${K)3{JWhc#_i;Z(s zXuhVqS{9~74d|m9BfX-*(dZHXR(fUiiK1H>z1b8G`Oo9hgVB9ifITMueJ=MjN^j9W zUH@xHRV`CuqEFKN%@IhV6NZ)hgDU#wamTg1aTTdNJ0x>tta_c=rD@wCqnD58SQDDC z@}WDYk`=u~XCo92oz^d+Pg+}lPsexH*OF6M%uKnpS@uNR7j`G@TQdsO9dTF&xX1p} zGdyZ7b|@2S)u8oun97ogc{74uSFfDyggL2B9A*Z6vrJiiVZ$NT&hIyvsYi{nQAn+3k5IY~ka0v{)`^qlv=%3yxnVkcs`&ihiFMWvmf=qO8;Q{& zTGPwP3=i$tbejijWe#e;sAxqIs>*;8lu z65>QwLeSZR4VoN zC;fh}^3h!LrQMIjI5F%H2uC*z?(Q4$*6s4HYOg%@-I+qyoXFNX_m@-gzl@2B=Kt&I zUxr5*JpS<4)4z<@0#FJ6X(|DM|DB3<|9`+M2oyaX#(Pu_*qgXlgMZx@*3QMbBp)YR`6(!TODtPDbrN;rHWRS}A?@c58= z1wr-L=s_tLYIhpm7chiu6Ru5ntrwr%IPQuD-mtAQ+u# zGISKHJ_J@1O&_cbq08SdfV{aQky7MXBH73RiuKQV7rZboA9IdVKisPWrV}Ot@1du6 zGX+&RbP{W6Vt|rlWC! z@C$jVm^rrBd!VFoDXBWcSrbHg;%!rx)zRyDuUk9sd)CfEpHF^OFxo1M9i(8Zl)8|{ zBqRSJ#X_e%!_mXy)sax?uUD&bY-GzVZqPvri>C<@r>NMoUqFjh0|@_nZ&1;Dyb8KR6r(b@sJacRRrs!f1q*b7$WxI@Iwl!YU4U79RhegX|(T`pE z3F7_kePPC3VtNafF`?_gwaXWWUhhj#qhnsSn!#?AO|7(iCOASI zV~%#h&zh#1mzO0;#1FjeLWMvs?Mxb3Sc9>Z-}i1sjqqk%UMbvrFy7hF+yyaOR<3j)j(;V^kw=CRIzDW1&E2$$mX z_5y1fe4qQ-8YSdflzG#Iw2WGEbLPPCODO$#IsNRRA&;G#T|T2EEyQOb;xdqv?dk}a z^*~963>zNE&Sus=c!6da0}{4-!qy)|Xj5(gsoS#Xq@SRJ1nW}0!}jund7#?2e`gat z?SKwrm@Yn#p4Z&X*19q@@VtfsBmi@fc^5~oHPDX|TQNVJ4GPX(sTv9GY=B+rlr!z$ zToZRhN$jWG*xi_o$~T1un{+{$RE}fyU$U_W@(il+hokMkqjNDwqbgJ*@sU02MIhN8 z8+H_JC_?4aVx#z)P`!Z)zf2$;ZE%L@H1L}* z@*VX8yKOz|!wNKzp;f+t9{|GCaNa|q2;X-R>c6gt|2v%mC`SJHkjkB;N9Llot6nFt zKzVHWLFqW>Kai`Q@o(sl{Ezfo|H2IIzfKHjxNIhqJ|?ZWmF~#&likjn4x%dWbpNCVMdJW;;7`zZfU!lIM?SsxkcMu*s71#@r(YFcncp}7vhcy+TD4^7 zG1{>os&s;zrW0zKVS&4g*_IPI2cCl+4%>7^Zebt6k54VHLvj}j{u#0A5qWsecrpxn z5jWLpN`#A?VB`2gML4ZSMJ48LpOak1)(XKja!MzNv9EZn6iZX9V@*41nNN(U!r-WA zgEqWz#W+N0LK9V+qnNh!FJMc`Q|&-meaZCsKg><%Vrl88>XmQYXsIp2X9c;m?4hj1 zhoCwISGl)iVrAP_>6@Bj3F>y|gnjE~0>cXT*3x&%b7HDEVrHR1%P0nzb`j)_(a0U2 zu!Zc}CVs|7mp9vxek63~c3n5RaDOA!&9a?NW@4YN@a4>wrM$8Lcj_i8ilpkZ4Bb8} zD*JigirnA@8hPRdc=eYgLp-_hl{$*b)#juPe+47~0tspoqpPb;4dqr$S$?8sKHbQn z-gDcbi!&bu?O05SEeZsOiONEabYe%T`Qvoxg;JhLH`ODTF2`4Lm!btBhvvvCv(JR! zkfTb`DuIgH!3&!UGShkP?TU8D@7fCZf*OilW;ALZi%57}5#4pEs_~YOdnM`ZY6)Usdy~C><_y>uyx_`(az|4emy;8)EQGu29@QIz#iVw zL4Jjb4^AuifE5iE>r|wK2Qm)2mP${0(Vvi0JlQaynL|{(MzmE>YRSUaaGfM%#iBV6 z&;janAnp{gx7+jETrergvX8!FZWgD+z`;Ir54X*CX2!vry(_)T_f_ryTN+;_NQ^2vpDc6VLfOmiq56p+xVjOx!sZGCFPfireA!Qgy9&s(Ap$E*;j&Yn5Wxe zg(hakVqlr4O5NB_YsiVuxNeCuoGSt*=N*c`@?2BAYBnHVS_Dm&$3TGgKSXc-vtu-t z_2()aXdWf9WtqJluTGZyATT}xKFxgt~y4S zvgUy!2TvqNj9HgfTvRUr;$ zdEDE@J6UH`BDo2z{Mo#<^DQX_A6JJDD8)K9tR^jN?CwR-@iwOx1RR<0tN|N=+M0R_qn#m%1$gD8X-^=a+DF3_pjN_tigR zczLl-45-?2Nj^fM_oVgCG7Y&SwXJUlgi&uTNp>A1dJpZ^u$k$CzBuF!eX1CNJRQlPt1$UXV)kYabd zf$Y0oexc9~Zp&popj^>R@;bt>R2aj1eSiY9x^!vMm>}gK1GU^&!d&x^3YFm)24|qPzXyqG1Ryga#s3)>_Mg zVGGS)@(N#I+r~!c2)vKqkJ3d}1UzG?Q9?2I*X*&l=g0rvPp7it&;4|`fA6Pbh}N## zd)STEg_JFE!oKiDLd@+o@E%h#Hy*o>+*_L|SAIjlg<7m)K2niZgtCUvjYj@;69w_7f6Z|Z5qRPT}; zeu5gfa^9$$4GmT9V#LPgFCq0;T|B9J(mFNh9oF8>d|;Cm_?}ZN0{+YY@Xnv0YAib0 z$o?02Bb(n6)D0NBt8REZx=j~pSbsrmx{dLixq`9jx+_sNKTmt}}Rk@&T;Q_~#E zLG80yIWUD^%a;Eyp?IF}v^L_5^Qh@9O02o8wDN?{{R4M~0{50AHAL^j`3oAaS(Cf3 zPTfn(<>f5sgVsYv;^u3XC&rQ#C5ETw%QDx>IpUq^ztZZpgZ~%^@Hq~m1SWvtuX0}z zK4H&*ZgUGe(f?2x`&TI5*Q2j39^UP$6)o;a)XyvQto%L|5F5H|zbcYi+*^};Yec;` zXLPA_ximfN)p%||W%mKgQM87RJlkgg9ImpmG{SsQblVc0=$4s6<~5}nQnSyu4KE2@ zX{;wEbaCSlu!I#z%N1OTqOg=S>j03d7=~oAj@p+Uo@XnUU3N;@AT0FYHV!0 zyP-s8U+MTa*fCb6%8*s;+nc<k;@QC&Ip$*lh97z#$6OGS zebq*lbeG!Fz+E8@Nre=;B`9~0OSx-bY||9GIK)sDAMOl#-CM+a4*3*E9JpO;@R%c& zlA1j3yYZZ+EZhw^81SV|Ql8R@LfBb9$Pzq_x%zAs9cEljX7=%;nD4vQ?uSpm;0i?T zPPWw2EWEW|rFXMfOLC^|PwiXl_w|0kZVhXJ0th8L_Ydh_jUHxIk!*&noGPL0J<2y2TyI=$hb)8ItoA^So{Q$AJoPlEF59hg<|Zt6n}!I zfdIRK(OB=i<~BM|>pqjwW|?(R7@5!j>0Bx*bi*EpmsXx}hGodTxRR*QWIB)MWeI*J z=9V1s1H=)bHxgbXu2*^LjvUita_{h1S|IFs=|nO4`*P8W;zY;Z_MMq%dqOVZ zqLWjh#V3=i9$z6I6Hg8JqUg%C_*E+O@%A6P_p$IXL67l$NE@Pb>XpHt&64oT$MtBU zqOziH;A$74K>yd#uYc|Tss{}&3I$*XBwkt0Ujot3Mn$y?u#Q-C`g3uadH@~qF46mc zOV=-^79oR+`pMw3h7)So%5_ZSs|WZ06pYE}6fUhTaQ3kcbO;w!ygyL?PK#n`+!y`!r;9Z8q*eSt(fIjb1IywS?9sk-TM_Y3+nN99cR3-UPio z3+v!|;&4YhYlOzmsfQc^Vebj1bWLP>Y zJKesb`2V(-{lC{<*7{ujwpF4ogxcLmfXKGV_n&B(Ixb>xmV*^Rn5ht$6{#K2XkcUY6B zI?j+c2gP&BT}5lLayD6HE{}Phwe%WoI=H$gCzg@)zT1RAdhU*Z)Vn=oXQEHa$CoO| z9o7R0nphx48-Djua6OZt+5pB6lA?UIc)S=>zbiwHQ5oeOx-KFsvp1Z+d>mSPvvYR^ z3x!S&coz%5!G0bK>eek@TKBIyOpbl@m7tN)bl)v>+>;HyjC=T-rK2&&dLHz=pbH#+ z{>1vtueTWu14&K02D^(CQrEX>D0B?wwi!Qg=hKW+IbY)a!&8$+Yoa($YN97QX*O+C z3V}I$lr~nSP#D9;%9${?+6>^m8mM8ZIK}%MJrTI5h$GO81?(OnRmabfLGpt|XqB(6uNb<4Kp1tI(i)RbI zT-qYW`ugfJCp+`JksqdYZhj89~&5;gO0?SMGsiHn(o8-C;F`FX_8JN zBv&|@$B{SqbiZ?d68_=Eg~2L^-3`MI1@CLM)vb_OO+oo-qhlTLoME@58C)Cu#PbS; z7v#y(&1E_tg^)sqk9Fx;B+B#GE5FGthP^JD{ji|veEjXy(Ng=g$>3X{`)_-Dt;mRe zGqifIq7=Jd<=xYToma?EPEvdp=2ZP!vG8*f{K}zL-JKcZ<>w?ya#5$-8og}7PtZNi zPYgLIrB6O4HW|W&w}&}s#z1Z}2Ans~Y(#_{^)?u9?nZClJouF47m1A9t{dK+>l7|p z+jhNodd>_hA99*Yhy`M2<{xRLRxT-Fh7esAwL{9jE1{B3sS|7!VHP(T;+SeLepvFg z_N%-d4YUqq-$xfz{sfg#y!Vxytj6&UBp^_%GGABg3)5s^ll+wAm^%`&B+~u`y5h4e z^WJX8dLeMQFVh1j*p1*10W3;&z^QolUt)9pqucR!g?t@~zEexx0zf2N^FIFlJj=sS z@*ljCzv|3|(9aJLDC477K!S1`09Gj)9r9}T)ta;tTvL^(iZf>DHtS`p`U`=Jl`Ad)wr ztu)~O8SH$oF?^v{9OMe#9=a#ej&f{e1wWCI#ZA_Qv@~MB?1YdKL8;k|EMWUQ64GR< z5^ES8CubD?#BMbCbtmO?{;HcCj#PkNGvZ6H8?Q^JNRljoVT;%4ezur(!xEcu}RN7jTK;4^a@odk>Bd;#P za*nJu8$0p|^4X!-UenR0Re1WVG|FoD*1ZcF{rneHFApr@A5-P@+CKZKn;d4bf+3~r z`ECX7zQKnv?>Q{8$V@D|3|09)UNQ1A+qbW1T=h;S;y+rBT7;us>@OaRG2b-J$Hi$U zd_m0N=y4&eF+9o|qGHfJV|#WncnlW%`Ld5*TE{T*=t1FR!MKRNonj)gtD>ZaXlv~@ z3R8@Om60r|ow{iy?-Vlh`*0|p7{c(5zQgCLab(qP(>V_9pj98BHyGcU*NU0t@w$2j z-28`6%jGH3Gx+Q7hf!5r(gdqkCm3DXxSZl3pZ)!>mi8Yn^|`gg)NhMC8zm~%zKjG# znR_!l%;ldovKZBJtK&5vxPy$WYr2H*J4p&|QjC%?a%a$pd23`+hNY*mNTZozG+Dpy zrjiaA3ar3yEuwf1t)NnH@E|+>kp3rVx9TToFxpdUukX-$+Q2YzNCfxkjzh^H&`HoY zQ%&o5XF*ZlC;3meHZDlUjosFS&LSPdv|d-hFE!Upg_q*fhWb_NIP-f)IHriVB@gVY zC5nBpWz>mjj(W={Y01Zn)WN4d=d7lEive5$SR8jyglT8;)(TDEZ2d0kYxb&hD2Oi7 zcI)XED3XI%lfPbERH$iT6hAoWgF%Qk6qVK2ue?owOD$H0eEmexrpbRgKSM;hndHw) zRFdd?=h{Qkl5O-Fj6N4AM1#$$TehTR=PF~&EDAhx9NO~RWUwXdZ>!HR3Ke(@K5lB4 zo1Pf^DvG#+uy~{Eb|^SAJU+Yye>PI`?#Uqg`n^@Bl6|vNlZF&`_f&!c+^b@$mao)T z&5Hb%LWVg*5|sMEQdu51NCcc>X^)}XdZ?nM>C&4n5qcUI2j7J_0xL9``Qu2akXQx+ zBbnqc_BOacNu$Q!3Gb-tKvEVma{q0=JU%t9%R8m9m3py`AO%NSo4yds$Ggb6a2#t_ zOJ7xa4=g=|GeVlVZC-~zzGZ?8t@JDO`i60Fr@@@0y^7h&7s<)BHJ-QaUs?zfKHiE| z_D`Ys8l3((73MZ9r<4WfXm*a<;sFpM*U8c~ z6QM?|PGwCMwq|6BZlAcF+t|yi^YNP6liHZ3-GW^O3K9`*M9@b-S;n=MwDXZb5ADm` zYYy&yv=Ig4#8S2O&tG7jxq=ImMt)sK9{J~4S5GPF@qA%uSbCUwmEn@XXkjU#{IVr= z#baMdlQ1>PU8X8JL1dCYZe;0H5WhW2vYM0jZtQPDj+~&|#atb#s~tb+tl4;=5blH2 zCuyeH>B_wEiz#g-#13*ydCHX5bcf#g@am{w0PvcZOTLxkQSwx1J!Um+Di?t&o6^X~ zJZM14*TmL3e>5epb9}qd#%tbxI~fx8<)npp+62%evB17a7hGe(39tTkR8TZPY~#t~ z#!lQ(KJ8A6U(t;L3nG1^8uWb;iW(Y|ci}dZ_yxxupDK;;j&L$c+SV-Cb&>sI6{;eU zvo838r&9T4Si9Ndt#cNE@utQ3*3rS&VLAj`wH?bH1a6MDn%S0o@jA5z;=01lf?bC3 z`jA{YzYMG#+YcB{BI>JTi6&1t2TraWHKQRoNr}!*0B4$ht5fZDz{(`{w#O3B>7c7L zS>Fv&Y_m#X&JMmB{ScyJy+}+Trz4-2?=R;-f9+||C;Y2ltPe=38T++~jWFl0k;F95-vQPyhL$o^-H-Ke)~m#~Gw&Yw z9KS-iLRn<`@gk5?wa16%4YRoy^?v$TQ8N?A^uyybTijDb-u8p@l5U(DN<_F@$U`^E ziZiW^O9;sZMUVc(XDYDmaC75D9Hn;enhHZ0gg)JHwZ1*46xS)_bLm#Z+=o+nH_|35 zBgw|ZnVT{c$ujk<@VbV`Q|U9)l`%BVRR5wJ7pqq6Xv#dB5lCXiMVWMFN^~n~vj%Ot zd9zi`x2JQ%EP^@`EP`u%4oBjBID_86!`C>gWRIz6zZSyv8e++q2AE^6@J&PkUt@Qr z;+fcGMx)YG;4Ij>Im@9{{y1fu6YOgggCkmmF1c9H!`K&B@~5Y}E3xMDx0u5AX|m6< zt2wv{=dEDtVocj)x@@wuF|ek9h1PyS{SGjL?*(O?dFT-jX4!4sx7^;`0XeQzX=u~x zlOjH5VPz)rab+t}jDhFd%~NTS87ydvRTRZw?22tos%=@-m~bVgCJMni8Kiys@UrJZ zXIm1iLH(`7GWqRmNw#+VF{F{(AQ zUpl40ECgHf%|caiWbDm=ds0x@&FEVOE!%z=T z6Y{N4a<8n;d2tLQ$%4vhrtS$s;R04ww5vmxGJ54~LyN2V%WNe@rF%N(s*~o!|ajCTf(QfM$_#=S_8|XFj~)!9dyI*!38j0E!?lY%P_CG^g9J?JBfvf4 z4jHkJHYOiR*YuQFFSONtGS$Ujq8B6_r4XM!`EFJ#HoC~Bf)WjaLo5kYjn+|n=b>Ox zV)A+3<%7ptH$=33%b5K=)Gv8f&RqKbl-gJ#`iw3Dgw+^tRKup8(F@;>DZCAnbX`C_ zi9M^M=PRT8L_08)(hz0!=H?er}xhwS*mLFSb2cVf{^F5=$)bI#jKKEf{FD@ zsgj$;xGD=nAs6Xzm`M46%M-SGK0Y2*+VBn__gL~}YbI9$yd7OP?|^iK=!CuWl&-FK z@`ci*@o!0EPEoZJ7V&1T;&8okK{kn)vRu<;h29089YU|h$d?j?$0o-s*;EG;i|s_N z(ilZ%A?!rQa_bmDr>L|GGfEh~A7DB%dAdLObqvpcex%Bp*4reLWuVbvqG&5@(_DBf zK@5o?Q8fc1OxL$epFW!S1X~}mChaOZ2%*H5CXFg)@k4l4qQSn+@gE>JF10&Mrr&Pz z88zc4_aFbSivC{}{r{qh9?TS8(s^tQU4CN?cabD`^#`yXtLZE^L8&rg&_xa<1xQX^0)Nt8{B{6XGF>gALCsWAA%r ze*W{6T~s0?dbpGoDP2|K0+hZ1}G0%ILqbeqeMG{ zcVSw8BG8MjGVw|Np4WG`=PlqRgc2kj+rM-S_3)eRucX z``i2beD3{i{+i4@GjrxV=b1Tk=FIs9Z*Z}ck(JHV&J{Rgrf!RpNRy#U&Q}|uXfc>YgGdGqEk?Qr?aVyA-A0Yiw zVwd~#lYTFcvTqu%)Qvu{ntmC*Slv1nZq=M*!qtt&L1a_4bM(8mjfDmG>W9H@?^OoX z^^%Cigqv{h+oJ?Jkg*vPq+t8dRnD^vBxMb@6<-NV+Z1VR<(c6)P1vzxzMhhWuV8db zZLe)h0FO0R&#&$l{e_Q8Ax+PtCyGXg}Rv!38uNG^G?XMv(*tcMXZ2s)Xh z5sr>!s@bvB#$5Xm=}EIr{No+{LB|MRvny2onKvSfC#_C(TbgQe>PGh#yard(?8uEq zMcZHOJQp{{NC!8@X&Do9w#U|}Gs;qf5#4R2!2wYrl;$BNwXuc76<8<7BV&Aj?FUTs zQG1@Gt4%p{?i4Yk79`V27|4Y!jS!G@(O2NJ(wmfTGnaL znUJHnA8Hm~BNCRhE@iqcKYp(;!5s#9gC1M49>kXuMpFn9OW}wqR7dSIGO_ecp;Twy zD7sDE#9!%f(5q>|>}cLHl5pN2pk<}E36#%UK#FUu;)0ce%3lqr8B<$@Tblesw6Fu4 zKY-l&7XU@4$5IZhEf4+xrE+8+NJov{?l_3*_E%Ve zJHr1Mxm_UorZD#-UZ*Gtx)-T1WVF!wchX_CzXp$fDa`tj+T?`*_+tW1+mcdKv1-is z(^dPQ_4xXGEy951{JJF3YvZ;bFHbA?wVX-+7;OkV z?g8nNt6(=D<9*$$bugi!qLS8!uob9Ps3yN}zQF5JL4Ur&=*((r-7gus)XVF|(>A`Wm zmX;)#Lq(5^ATNpT7K>ESz=DD9xTCKaDgu_!q@`t!3uf*Q&%E>QHHK%858+Y4y{Bw3 zvN%hz?kOKw#`xN2H-&9qwx~kamKxm~$IF`XD1Ug!cva}S$bRL-?n+kGwRU%vcBpfe z0nEbv!i0DOTiglqm9_r(NEIPy9e)lu{9(=*cAz!9hb+H3eUogFsMCvKR5egkXLbzB zZ&QfEljF@EK7@@zjGLeljJ9w`r5i7RxQJU>9_xd<#zu8siuFm+%OXxZ=F%(0bGj7I zii%;H6Bkd0&`t_Hr(5B*_w`OiQTs$7-bkbw zYmB+Uc0~g?8MBJt8~3{4++8QE_DRXHw@p`3kx=F`sjjgEcd_>3*85z9yt>znDS>)~ z*3Q~3o)dKzn)of%Gh4$IBYGT?J&V4EGkqEZxTWwr`KP(rb2c})!^Y*9?{hn1Cp7Yn zcljo^DMB*5ksmW<_K+e+@FXNGGT2L>@aD|RsE0}puZ3XvmfVoJ2^t*< z8_)3`Hf`=uNO*0nP{SQ#A}&T5AO&l5+@l*d58{)GA2xJqR`;4TyJ+dYG71%YuTScn zB)Z=W;5uj6hpR3E$(#gnfDS3zXV?F&pWK78zda7Sb>$b=vV%8j{#6RWkd)keFX+rvlBOgxB;0R`#KUM&MXB9e=xn3sxXpGR(!m5;T=&S z)@syR0U~E)g1EHjw!OOf_6Di!=K7$9P}*i~k|PH20wqfR?af?2wp{>>NB{bG;M_AQaeOiav> zi`8L|eUl-9VbE|GrPr0y|7Ab7%(r1~=9w?>{VXh#UaZG*xOiLfxRxOy|00yJ2&>TB zz{*+8s!LT{eae#h9b+7gt?^1Q z!x7t)8y-hIcsn1Yq=q9UT0V9x8*MV>xjRjUuR5{%7g1Ql+lm(=->ouF+?<@ggCC6< zwo8L+*o-5bIz5%XrkbfFKuVdUmE{a{#h9#vOc(7Gy*S>bZAJ~Q;2Uh1nyX}tbl)!C zX+?!?E3`D0OQK4k96oefIehbyaSFTB5F;qg$b=Wzjut10!5v&D;4lrL7Jg%@fmfH! zy%>t%N{UX}n+x+_j4bYWYA*`$V7RqcL4!-wkym_q+3eMlh#cQn?-6{!0x8PX47D{xBfeIo)?P13hBQMVALV z4K1d-b~ISCts{RgR3d9AxD;LKYAH}YqSNQz@K|(vZtzuOXHs>Mufw66+xj!4QElQ;quOTct6HbrjKBTpF?fo(Bm9hV*9Qo?&e%ym*Snz->J{$0vr%2tFaeD zZER#H5lMv^>38&=A6;(Qy@7kAm_4MGR^vx(Oh`^Q?_HiWpgt4%=|h`>epTF~VL$a% zaQUIdRu#s`zE{kZwiKfNJF+=VgnMD;<+=qN-N~!&1)KEeAjX>!toOE@vw|d33!{t# zGrxRc2R&qSl5-mIjI<(dTv-uKqh20XhVPpt(iLyfEif3FXlSDgIZq?BD`nngP@xF0u2)Ltu5jA_l;dg z&GdpsAtt5q&bi9zpG!s_PcY9W@e;Ogwz@S{ zb4YLdl9`-Hvt!|Vg;j~NK@1_FGqLpq#2%GSJcr&j%jg3_i65t{Dn#+cGvi;;=Z53D)(JFeCbEE1Pt0d#V;{e`gYpF_7(r%XE-?=NoM|spy z!=BA)ho11_w6jEqw4j6Pv6ADW;PI*^%7^&>k4a89C?>5!Lae@k^InMH|lNs32hBU^2WkzPhD5AEzk?qMc4K zDD$yq0&Z`2ezJp@axEyNRmW+Ww#ig9b=fg-yy%B+G3O7PsEOjSl<3B7ZvAAfF7{qA4U27t7w6R&iZHQYnhibsInf=8#%UvO2W~t3OK(10 z>8jYeR~-y{OCGI>rk=u{6w;&`<4>PflgJ&~0W}@Ay=pfxpmO-uQP*`$9h)hw@|y_X zlx|{sa~XF8ldp)%u4G<3hzRo7i=FtxyXn~l+0w(4Q0$1vV{usL!&lTz1L&`7)Rd0D zw|Kq0@02%5Xl2^fz*yd|)e#HCnYOCLDuvvEl9mwh~PI;EViN{i>eBCu{lT07e z@_(-KcWzHDU)uv@=8U@+xWw_PCJ$kPXE4YA2%N`KN68s0HgWlhuNw2cb^_-b6kNJ? zD`a`3`L6s({A3k7$gAuPSrM!wRJ6ra>tz)Ff^bIvhA3U0Wj;;?2N}g<>Qb=8@`??c zJ4Xi^03Y{T^=$x9ZE@S>QNlg=ki0@8c-KrjOq_X4j_O@R&I2t)Ih{(5E(3J$oyF3& zDl?daMBydL{Q`5b!#<8f3MZz}eETB%HU%4IgQSTkQmZ$~&LALfYm@x&~*oJXsa8IANWtF=q<--xxFHt^BS zD=vyFA6itXEIUWCka$WNJ@($1*eB#(!wd>rjd{8ULs=LhjA)80-KQ4W!G$mj0=qL4 zCnpoFm5#98UIVM=o@rQWk&$7ySS3^bS~hO@4K%*4Dwa*QhC^kT7%4i zAxl#7UDtbWZ!KbZ?RJGm>zuWqscOWA46?6Ht&pldSu-z|ZL%V8KDB(_sceX^0gEia z^m&Gh32DpgyJMU#B5ng$9Pbqsb~3V!s|6)N5X?pWbT6MXjX6c_A-Uu6mD2pwJS4;2 zB&eecx(_>o=c+4&ad6LpL`7Hz^_9gk;*JvX(qmB=+KLPiFOAHdg;&6bMk8!vvIj(7 zC`5|%|8|Y*g|5kO*WpE0ZN9xDH+;cwA2hBzU3uIeew z^>9#C45*4i_ZZx^fuuh6wzWSJK5jav%SEX%r5fRac#iO@rLG~x4IOmqIX2huanQFPIyqqzVyKEqI9!?d0`VFLf%%qmROk55r1EEY ztc1AY-FaGP<*b$Pm@x;)LpfV?JnHL}lX5V6qzx%YOVwhXn9s5?CQzRuOfjXh3#^gV^hgxNI4^)hr~KMa0Ji8R5BXvRUhfIB$HWy4dmj zZn72wkC=0gRw4L39V4~zW%=s{18W-^Ivl)Xeg8a;&=G_^s-!tncUdpW?9lR{XiUqNkE8J`xJ;5JG8yux{t<3tAt2!}%x z_Be0G08cD5bIG?K6Ll>Z8Znh+c0Cz|wcN!8sj%HkB2B(_P><4h_F8ObXpx-MVC58uam;(@ zQ>Z+JA$!hB`dpkL_gxsw5`%j%S;$Iv)XcI_$u@i(D%KM`SmwN|-i1QP1t||r!a2vz zbJ}LKGJs;J2HV%KztS$q=~KW`9Gq0|Rq~9<&FYJf$LbV*wa{XWw3KLro?3AUnwVwg zPe60S8sS~6V?>9d;t7tq%|vd-1m(}i5f*s0v!k>*%02Fr`1)~+yRvk$-LI<`(5uYS z6`1r8qbn>1D#_-pPOh#&OM<{!_N3)VU8GMA=5lA{ktD;+qD`80il zMd6cj^gBhpaAaY*41=6J;snHmn2cdC8^`e2+-U5swRj~a0Rndeu^`$iGGC3uid##Y z^7?1qJ!%^m9%zUoP5z9`^E)-}w{_*eay|I}LLvNzN@douk|lPedFtNxVeqfXp@99;{H^iHfM@48ZJJ#JN zX?B{jl*UU5$enwdhm1E}R>1!Tx^9kA=)pn>E$iR>; z4Kc|IZadL5a<44-MTG0NFC#Q0xUrB&ia~l&Ax#8B`-C#gl%9;ZTlkaa91FNME4n~Vw#z}wK`F`o zkv(NNpY04)M5 z^f<13s*CTOQT0?4W2^C?pIB{f zDJh>fcBnVLm>=q<{*eBnyX43>iqXLRf2`pdo0wEO_&(xqr-yNHux#;Ktk`*6Zd>$t zB38qY3>`xCx{ttIU2P{k6^dS}SO9^BLPXj!YJE)5`H5$K9xPs`5_)jm>Z(9^k?qJ& z5fu6V?VI~2hLZnPO73}bWxSqYac;0;ch%}xYy6en^Os`EPa6YB@Ff)P1`=?ryCIsg zbcT+jwm?nmQ_j)TBk{bY<&6_puu88b3e4Q)a_6mWzRWu)1&ZSzUP-%@ATiNLT*ckX znV`PMk%y^P$m5@Z>;+0$XR^?WtK^qV!U*lQ@DN-s> z7)5GDzN_3HM{W!LniBZ|vi)|!$fzVc0P1pcdNb#nJ-Vrhd*o!6oZm?ArY8^~&lw14 z`)l&cty&yrSJVU4{vriCX%QJ{$xh^fis(X!VL(UD6f_X7Me|Lpa!Z=L!h0>#fkCxeS)*&v*SW+{IWKM1h~5VfDeD5sUOCcM|@uMUgo=C2SE2WC639MV}z z9p4psmom=fU>R4tYRBC)B(|2HYFMV2!g&WGxPr`-N|ePtrd7Tn6IA8Bdu8uRMIePK z@;e$i^gQp@Zyo?;QL%xL=A`)R*I^K3-BsCEzop%0w+sq`ffuk2#2#$TB76qI($pe% zUGp4lRwJtfQK=Y}nYjFaKk{$B{4WrO^e<*%uDm8vBB(WliE&%-DK?qpL+5|_3a%D$ z1o>|qvCsOQqsl=gO&-3XYmtd=(he+?a18s%GcZb%P~l!xnY=`7%6p^J<#hIpY`G*U zQpXkcn70R6oI<6lwjYKp0OHxB6P9mb3Q;uy0oPwqo%E2LJ$e3h|7a8;spSTZ%2P}6 z37tH`>Y{_^m&@}2R3CDu3&4vM{Q1@Nw%cYyFP z0{*diWu*MtpK-+vQYQ)y&=I{0ZoqTy12MPS&su7yR_HAPQ#9c$_;{OzxJ>78@3e=tHTu;5?afnKKdVd zDR2w$hx${XN5Dw*rzoPo_&oS0zn-`(x-lUq$5UxMqj2_V)&6xhONtdL{BgsXq(;x_ ztGzF|oOZQ@=E|R(dhTpO-A$|4mwKLXD|JMr6qriiI#YtY_DO;y=E8<;A;7QMGWiFn z?!{N6v8uiN4^V*wswz6?_k}MJ0m~AUb|A*ahz)Y>ktr`Wa;#XD(7ECykVpAlk;OxD zCoprnHjvIt?~cUNZM`EEM3PH)IbVt(%l3bEUx=gxsqSLqR{%>~!?q|d(0}CqR#p?m zmXbfWUs&Hddn@&?%63(O-aFcW-T`Y@ot?{1N~``t>0cH40l*Rf0jM7!5)f5)&G>h; zhA|h`ZMgRC2k=ssb@A0YogW>spmFL{GyiOp`W#FSF=5dCHXr2L3a=o&Q9gfnX>`#W z_==y3itMz-#pzp>Dq6;Bys)=3dNMM+1+rhI1%8@f~1b9cyfY2ynl1S2tAE2N7D6Rvl z$xr{O+O6O<<`#Wl-X^J=s->9ieZx8A3jYt#b`b#a?F&=`82n4MSf;sky_B}Ezw~>s zfh*nbiahp|%8EMLJ{6paK#wIwklz|MRqvX+iGdm^L%G~94A}jhGNZL&E8ei1PJQ$O zI?@Z5kKc;c{q2(w{OxnPHq<1jT4u5z)v%Dd7j5zDJWzD|-_{9gcF^Hqhlj*9Z^YoJf`sabz&`gQjM7D>@MK&3fg#E zi{V-L8NnV#6w&vs=TmGPTf)WQid6xZFcFucE_kH3$8JyGXBAH4zUMAYO5G*0&yG}% zpQAd#>ACN^5)!9;?fq=O$s{d3=z2UGbI+=A5-HF}-IIr^&sI|mv|D>!So&x-^{Q($ z?&Qrc#S&lFgk$ue__3Jej%g1yz!4&_}SQ=3Fuxsaj3GEOh;K zbOBA_RNoZ=f908vc^5d6mdN6Q;p63OOIKd>OXp2COs&_YV@|(FHkpB|YqE+oB-(6g z%p2(aIdNSWnCU|PzCURCR>1x>g6enuHFB`{TVDuI5wfWaK$UbZ$` z;@GHnH}xwJ_izY&nIU-C8IRzWFnpY~%*>j+9LZAWIvan~jQ6iHl7WoEq;KS&8+Wu6 zVJJcgeN)64*1Cmd22Lkn!+!=ZLq}CrG0g~;D88)kXK)9)JqkDSn)UfAWpwo+TjLl* z=*YGVanPMXC*>JcB*{BdaH+xQ&5%SXdaa_@T?}@blYG=dUB7$`(V*FLwl-$uiexoF zP_ORbrS&z(?`sGNSkBmWHV3GAR9vbJDyP-Ah}raU#+9YxOXTJjfc(NWQ(y>@EL9Kw zCIc_qXL@+UK(+7oCVu@BFbj?+#RbYyyC2^8yrb_mJg6+5)4EqesjlY8<(1zb@=Mr= zU(tCD$=i(i9AmRTW>u65G=F>U3`Oj_l?k9Byb-|_U%p#F-3gq`KKTKH0045Vu})qF z9bKOaa*QI?<(*jTMp=zuh3`>lwn}I$tqdKr7v_n~P)gOh(GK@zqv*Z2PrAZ{OhKO< zY3tCAoL61YHL^8M(Vry09^=|Gom94EUf@c*%F<>>>xw%X`rM092{YK! zZRR}V3^xnBQ}3p_hoIsI@$FUfvb(mQLP%!!oEA7JR~Xd8eBo^J+>PnYX$Jb96ga-Z zMmooo`-Uz_a;3BjF+Bc|CKiM8Mzu|Vi;A6UmmoS>)<#i-k`mS9Md-w7NE*F+BK;*9 z!{N+JxY^0;zpJn`u2g%Wm-Li-6VVF=95>r#LD?Q49t z&IlH-!LlNNjj3Bf-ILULFMoi_y?J-=ct9BQwnEh~68BH_@aXJ&`$%#`%4mI2x#K^d z2SF;?Y?e&t#4R_mjK%ja0E@w8C1UjNA*S0dB^i zaC&DCW82LYbn_`#jt)p>e-l}uc^@!i28)LL0G0dzA>7&<_60E8-1gb%_I=h;|QX4bJ8as7$RLE1?7e)`6Q@ zzdh-V(e!!pfUGe-`8oCn=smE5$FtP`_GF2iri4yNs)j<(xg(vCd*T44H?8$Shu$V| zFb@Mv8i4hj)BsxV-yiGUG*aDVMDE9E5eos(lo+5jfMa;@BE2AfU3UpM>$4$?rBZ?# zetJ1{sHfV7$T?fEaGL!!$lY&!eR7J%+MunSY|2T%l8z(8afZGd+_iBugo z+7A^1c=xkoJ48k5QYn(e0ca}cYd;IrsfZwWf7i22{ckjxyF~wFQRMIXwKzagiTs}i z`n!H54p4-9D-aL7po~f2qPR+u?I(n%42md^BMk6GE?_m65@Lw$gl_IcVb{o{buPb+ z>cg)Ah*Lzp1c#9dqkP_S!=p!l0$B_w;|{5mIW5w8Kr19nlK>t}fj?zt?Z;5ysrg^` z%xeyo$o#&RX^19Lb05>7_xXFB*UD{+-PqvpOp7Y5t*-Nz4PXOSd-fZP>x_M7DZ#u%K82JCVd zS?vI2O@X-Is=8|N0AQUpF#Mwy5Z-NxeB_EWay!tKUa(~2vwn)|x0LA>$o`kDKlPC< ze|n8%Wj0hQtf&${7gy1|ZED{PN!wxlm>Jj55sP0ZkK^gU&tsP60S3Z2`|K4N!? zaL%(E;OW+k+RuW#IW4|;UT3c$gZ&TVKhchNeQTu}NNm%TbG4HK%7Aq9AD9pDcy=<-d{(w~}#cxvoUjFBMrP=h^jk62GiDngnNnOrdG#>c+)T{mZlF4V(B;_meu5)Xi=6hMPOuWDuz z>W@7%bbnF})X~tDCcIe0+bByKnWwXZ`V z&Q`!E{>;#$H(!PsXu7|>TBZF(kE>}qxyb` zDeRGU=~Lr$KHd~85Vvu6$E(P*dA7~o)j;otot`7RV#K3&kG?O)Ui5g7tCy$|cyHM9 zM8V`EdO4JNUcS+ch<|8Ki$xQik_!B@RJi_C-ozPc3B3e5XW3e`I8s9{Wq8-v6J9mc zbmxN0WPvK}_*}E^XWZNGzDKll=8Xa+OHVgL*#!Mh`BXpPB~D=j)b%wFV|-%wi~Wpj zPYFV;hwf`AiZ>y-j&rL=^?bk1=*eZ)nKYRuyK(L#pCg6lqa@pN(^Er265NLh6Q{^9Z+XQ& z=o;G7{33CDe>$@i>& zZdJUm=5LgQFKT99dzl^=qsbDy@G$tMFzMP>GsAoHtI?$$j~kXg@(+;M4C9aUH$3GC z$RAyN#}Imfne5|XR&d2M7rY{_e~25z5tI(&dO&-NB-ZiGgQi_ZJ^gLQt5O+siNIwQ z1y8P(%QITc-%oNsx^fElB#y!375$C(>{I!-Qj9C$^+PP`PSyi+R;3jW@svxmbDwQF zE8$PmPIL_}4IaLK=t&4E=W0!iyTB^?xJ4-1#Piz#%iY}Bjr?3QLEl27iGC7Oh}{W~ zq*qsZd9TYU#;%QVPp7N#m?kvd;~&r%Q@&K4rKa%BgEm6t8>7XsbXu)T(VxDerg}fg zbsdpFbJGikrOrqx(A{lD^ z`mVMKW@2xiH)%VYpugm0_ZmOWt!6b5qdxBCdYEs3PuoNDSypi6YjgVj)CvKclU*=} z*|YIazun)AY%~4PB2CwIuli89y^4GR-T7CPIo9eS>Jg={Io1-Y=E_wAhYww1HGW?H zsWiV*!z5Dw=C%zq)mvfA6SBzl*!%g68cM$6+7}W#5PZYD|Jb9=2cgtyR8h4hB9apC z+r1j^v>XbUFiFjLh)`5J<#3AXFr9P67f+4h_pmco1~V@1w$%M67C=3;g@)xI-hmI0 zx9iyUp5_Ekv8xY17Anx_q>KhNgbgOLs1R*98fYUs7E`R0(4w<)owdvxON?bRdp^96 zZhBI}>7Sh{JZZTQQ;0z9E)&`DGM-Oq7ff(sC-hZLWLwKXpM?dyqBGI?pgUW*g$QOm zmKZs~tlIQ3goE?c8;98L(5)enFlSa94&#YSBqu}$?GT>}mFPR7YM{y-)S>qMt#X^# zh4?&CA(@7jo>+ecdi|LSu6G}*PQO2KT7SeMPYn_GA@wO(QQN}D_oVIhG)~$L*^tdU zL#Dj%_kT*bFvTN zoQ5=VZ-^?`if^{EZrv!D`s_i=y3``drREqJbJo__Uu0;AG4`z3$Jfv9PMxK*@&0yh zVJNF{$?vYVvQd3XH3=#|LcYWONmaVdsaN;O`C98ReLr_jnKS6?-6l_4bpxeaVaqiJ zA0`>JxLd@VprWiIpO1oHTp0@*nmb`GKQ^$7>LfzDy9bKHAelFAU z2bRgdERYfgc2>ap1(uPLxCynhvGw4SR*;tXWf}hSV*A?~_G9G7Dv0SSpc+6yR!;$c zd#WGfpy!}tM~)n!KXQzo{@4kIqYNilnU5V~W<7oC6zi!|r`b=k0Kb#$?3`RYT%7Cz z0zyIp0$^!rX|U3-KPpBB21X{v<4jD)S(uoaSXhpqIB}eXn}vmyg@s#?gB|#B2=ejs z@bK{SUAQ19c;SMS)FmmYU+XLVXat=&LiO?x4>i>}(4iAl)F-HZe56tZ=%bbm%APk5!sou-5PF>%SRVUvXnr%RqGkBYmcF%TP+T^;6}v!^(=f2{3XadIY{M;X zp8y>?1W@7pt>z*!uEB1vTRc6 z(yqDV3bU&;BU8Xh{w90kQtFP01w~>n+Cee&J!AqT1zXskc3usZ$pY1toKL*PR0P;K0r?>*rC4^YtH~ zjxk`PiJXsh9z!S*>9`EF{d*pstBg}v;Y>CWV;ot0s`5fAR~J{03kZ&n)GQ$?+)gJ} zL_Wn;cgM*G(eXOl1#*YWVKLjI8d_f)nnuR^RX5NLWQ!dE^rp^UQOSP%z9vLE-v(VH z?Zi^URNMAQ1ufZ)D%w(J8?7CgA>NEC7y7h3^=g?B#^H!hQfCZUla-+jm?LY;XoY}% zh{#T&HfITkr|hq-i60!o1IJ~viy@+z-J8r=l{JIKooX;76EYJ=q$__Xo#(MV|JHcL zeU-+)8|o=9H{?WOS11w(Ma;j;!VP+u$8R|}{>oPqAEAAHVAHJyoEzmYPQU8v@=JYz zMdS#mG((?O$Kp(#Tw$gIvszCNU5l+2Ys^OtnGgDIUui3Diw9#?SuYuW1-+bSW)XW# z$^Uz;nhlfnOsog334wD1#hu9OHk+v#kh=P*yAp&XOo}YiS(^9mq*joPz+iOs zYJK*!iIHBUYu=*m6Yz6?RX5Qxm(gffa|dYOEEZD$@@uO8P|4=#9nmew$)oD*IFxii zs-k}t2f;`UixLTjQ|GfOZ|CQw66$M0Z@PC{mN;70yx{Om(GT?rzT;;w%IS>P3Z)vG zX;aQHZ5=Z~^>B|JONX=(_sxb<|F~TP_WaGR8d!d)CVVDQs{j@5*MISt?+CUkV&;qi zg;~I3{r>N`bx`P|5X=H~%mU@>dKteGdO&X3`!=-tROszy3)Cw!kY5~;n++S9ze$Wl z+WpO=#*g#+f6F>3M4?M8b%)|oM9L3l{*KA#$TSjHvT{O-*bcH@@YlX>*86Mq3IEUS zo_Yot{vWe0eLg;Y{(pOEsE46*f!)C*%9Y-P*-_T$FR*ef{h=mFc@`J|^6d_Cs}Q zbq%+?>e4j4FErQyF&R5#fn$PLUYV-QicPXocH({_l#EB=h$}gbt_){N!G>kc=QOUB|Yn2(Grgqq} zYb0Oigx^ddqJcKd`F4G$qQ0(dh}Hx`s*$$>?KC0c&T*BOXylEaHK<6aY!F|U`w|~x z7C~IXRd+$?9Ba2PlCOKSM)jd0!=-^ZSlHL;(f8*LhrU29giX|1a^266|8o7Yx3ZAt z$1O#D{&$H0*YX%>8t#?$-p0q)5v{$nt4mxVkvY&u)Aza*>DL`1^w)0IetIzLQU5fYhZaN0b83gU?^4B%#|AnAc0k3T{9G|_O{+bq)?Q|CqHd= zM8*!y$Lh4Xo4E>EZIgxH?UOhOIR-g7k2V)&ldH}+)Yk+)PZEJmd=m$U7YDlvco(Or zyx(7y*jWSKsPMrq&Sp7gA-hL4Ox7FPDBEvrhRuPKaRb_QtxICvo{(b5#4^{kE*5&D zQonEV(Ve-y2kZOU3yAF6up~}?k=+u=F?7d@C)xiM*pgB7U1XtZP3XQaU<3}iw-vnY zitI%K24;_Oot6EgiqkI}dcW7Z4*574X!w5JD9$R}Jq4@e#mXp&V5Y5G^_N{&rijnw z0L*Lp?-v^~JYY$0;)fX2B+EwC@P(gHNutNx9qc%c>z5Ih(MJ%EBdDJ)R_z-<2=IGP zMOBr?M7#ad*6q*t7>FPFuC6*+H+?}>nmy0sYn#<0*|%$@b1 z<{jdppB}efIRsIfZKAfWUBXKCR49fdIcICSd%h&S+%W0?bqu!-a1ZHhzMHqGXfd=m z!SF@`LO4x#Jm&0Fp6|+ezFoxBg=8T@<=y6XJbD5q{;^3u-ccZVH(_R>Q=@WxeZyq^ z51Taly8L~bvTm@k*AURSu<5Y+Vk*_F`hn#HXI$IVGJ;Jx&QKgigS+SGUPu(5oGIB{ zjT~}rX(1qZ+0X_~bR#|IwIhp$kIydD%Ij0+%x5lE4{vRUmss-$`}@8C0yztVlM!j) z!jHCGplyEu8~y&0#>O%-@g?Av5;wEoMx9R4C!AI=jJNWEzTPBRj&NwIyyG!DcZJlX zCqhmhh7pDqRBF8vrB>>8d|%d&6*0pM@ivu%he2{DzM7dLEGZKf-++UZ%=-rf;Ci(4 zoragQ8m?0fR3A2m5%-sm;UCw@paJoWoi}hneH_&lg9n-5!;1qxMlFOI46EdJ+J5xP zA{{erTfn{I(k{Lz;SPgC-}8+?$HTtU3>=hN0I71fs$mg0djJkUoRMa#&+asI_I|Hj zWgk|_ihS9h?_JoCJ+VDq(aMEGw}waetLoHV3|&#t{CkbqG-F~(yaM&j^RNGSIQmam zO5X1X0?z0-|W1e+<# z!M)iW%jAS-oPEc0A>JWLBM5RlyN8i7vz#bftD9T*Si}S z3YHl54o>>YHayE}$w_x3Z;q<= z7!-z&#WQnzN5ji5L>5#rQC4htYnT@KBl8OF4qHC@Bwc*tDzB@3W%O#s%3B8^oJNse zIJjJ%Y$BE;9GFRVZ?XAyKkUe?tk`qw1xcN;Fv!Itw?4%?HI*H}iz%_(@{37^;Xib@ zb)btJij#~WNrk?NZ70E|s(R>gjKQ6yBHz4sg$uI~sNo=8|1OVoswrvu18OTiW798o zxW0%fI8>kazCstoucxoA=ClkYZ4@o{bV{pYcW^u2Kb{V!jbwYXJfRVZFZt?Q9-lN% zfs)6%I8{&vsdw>RgoxI6If;g5jy!3Z)K0H2U-%ThAs1`cBlQ@Syim(pH|pT*y>c&fU6Rj-8EgqnC>6}9TRfhx^se>B!f5GXe? z2^bewGL@5wNXHy^1x2n9)@D<=i~JFF4T z%R8$2iry_i!dqE`N}#z08QnQo`Rv9{DB;4r$yLrB!vkbz0Ce_+A9I>O z)e2MAR&hiD&IkSmycPNtbtWc^Mm#;NzHi$glF{{|9mw8H#Xf$hw~*Jc3^UVA;MN#= zoY&ih_pVBP)Sh!AP9^fTyy2(|&o(v32Q^)D_PzQRZaQp(IFh}(qqC(seN-XdAY6?f zfv%E#cAMV)1@(hXt9vn860N9s-G`HA6;%omJmT(FtRE?U_&TjZczt+(UN6h+m+Ea* z?jZx1@ycC`WmRvQnKi}{M85wr(r9H#!NQ1a?WwB0L{V6%y%`I_@9OBR7?xc$fUeSn zGd}S}2XM3r1Z4D+aYJrjeGm^GE)2d*j)B0SaVXq`Nlq?7GOuX0V)jN7q=g?s%-^_t zfrAKGH<%>a$9+dlxSSg zn1fSHn8pStVT>*)Q$UVv@fnF$wU3yR)fj<&r$pX$Lj~RZDEr>3I;ge3$|vwCQR3K} zm#eXF42MnhWXC#)wNctmE==CG6Em$b7yXMvpD!Z~$$`oy1r~$jI%6hI66*MP74*sR zVv2YVJjsjbKso8z3)RZqVyf&X6L*v$BK5^<1y#)LZB-90oL^~^4U%ou*Yem{2@E;B z)zIi_x0wlqw^fK>qUDI9PCfXY*G8VYse{Dk5=NqP?&I6xF?v=F~KuxH}<(YGyF(kvlU#WCLCLjf-7O(ROWbayuHw} z34?J%x5(io9_`@ddf>zRWG0^MQ(Q6lwU8j*+K8v96z3#|-T{O4d3MKkkzMORvmmyReam1Fq%He^oUtGX#oVfEBPc`DAY7I1Pls=}qDn_IS4 z3MW`itys3|8G8D-E!y%uJ&FI)kkYnpV7#wawW~HIP>swrv&e;;awU~w!p-#K3_0(p z*~@R2$E_l~SsahqIlLIV{k=H-r09;<6}g>XE-e8ry}!RX_^-$?9JToV4seqN_Kb_g zX=r^}gZ&HZ09dK&&T{TK#U0_^<|Q-L5)V!n_p#XzuG3~=N)E-Xvk=G9N>7&?&E)jZ z0a}B5ZDpeQTLEgzZS6fZ!&Qtqj(R{G=039>??Bi=aFO)0Rb#u4L+;|SHQ(*mQw@+U z(>g6J`1r*dzWGNL@#BM&u6`FfU&5zStDFzFRrHn2Bd+7U8uHkI@Q1}Ekc%B{Y~{ms zk&e-=3K8Kg8P*77dJ)-nQEI zQJr-Xcs1xOF}ibMnKXWNlJ^Y7G1;#7{k&epioSvPX0!RswxaCn1Y|o-w4nue71+AT zexbbFMr2Whu&R&XwW~736nOZQsVxBV$D!vjPHgBl+e1#df5lup&#v1`h^=1zL@UfxA2G5sivmXt}v;)uJHSZ6hfEuK@H z->Vk*mw^B#8ac!oxMg8HaJctOEPXDOGZfAsB#K|{|r$*GyaO#FQ1s~&Z}S7y0=OZSUFOESCa zBHh#XotJBZhy1cUY6+KM&{0FV&9NXA6?5+T@DFK|L6!0{&yGDlJCC@w6xsZtwZ%{8 zPFW6}9Iph^p#F8$oyO&}gS7+?6M*IKwi~D^?TGxysXgXx!CmcKyG@pXB{MpP^f{F< zn{oHm_mfdEuf92AN3L+Lc!xivN;AG`@%vf=nR#db(f}!6)fa$~j*iX@{BtsXESIv@ z2sj(vx)sg-m-Js+5El7&W5897{|=rNI+X0)1H729$Zxp2#;JdLWu5%z3BA~(Jj~@j zdE8awf_qk6@%b18yyyydr@9KkU7CR8woZKMoeK0ajG11yrO7(h*QmqzFhaArwO> zhERl14M9;5se<&TR4EArNJ0li6X`ubLKBn{0w`4i#NT$-%+Yh_oICUV-MM$&yVm>_ zNOpPmyOaGq@AG_$kL<9P=0c8&qzv>p9a-{Pw#50v>t2^C@}*!Dd>gF85zK`3H{c)n?uANzU-J3=1+Evfd8%+-E6*4}erw5VO@FOQm0>JPR zSa9JZfprBzM9`Nz7rn7=n;PPZyxxp{e0#Z6CHsw;vZd+}S2c@@;|qU>sk=QtA9f*-zZ6zY1_)5*cq2v*CCr48A6BE=jHD*S`J=RiEO@9GrOeNKI> z-(-H^PmMEhRW7Okfvw9^s47;rAc2H2=RVkFBHG4`0X}YmIDii|B+JMZEuf>0u@L=n zWsR+SoOW1qrkwjhdv=3=B*?Z^4IO|GRu=j;xl*%_m?*a&KQ< zB-@;YZlb)y3=225r0e0rPORlOK+lqK^H_D>05k&O5F=4Phd2Gm3DuYroPETS{=D&v z>GCCyWzhpwk>yU_jbE&W0{9JvyEMivm-cAifT`DK#(MRBmC&DGC~eCdr}n-+>7C#Y zcQ8t~GH)$T6`(sj7l`0T`-uA8^|C2~)y@)$f za!E6Gzq^MOqsTRIPSUO{VgFu9+pqxkf(55xS%C}r*;j==4ec~qKrwZ1E>3-CdAIbP zML_U9iV(d8KwpnyV)^-{YoCdJ$iGN3fvL}V4GLopA2{A}o^Av@BV7R0;dhn|86+L> zO-w;e0%m!^f*ajT5ksxO_iF3sI+ruQv&7vY9Ey=OVADh zrrVajORfyUgdxBM{4_jv=P`LgX(;C^*wC6#nb~ zfxp~TEyfwG<7@hdm}cw|Gs$ihTt!i3tqr<%JSO;!3;BxJrj z|IbMD{a&)@clr`pN(KK|Q~QY3NoY{;g72x2xQ$}B)7hkVTV6dFH={sh8dQc6Lark9 zNfhq%_Qm$D^jE)A9XVsobx0Mcs0!&%ex+YPxI8FwBb7Y^yF>}Yh4hyyq!q)FkFk3`f(1<(`Z=^#SHFOi z?<^J@id1a%lA}dF;i>UQ9VJpY=(1`26se`|R*KWFOA}_rV?sk4Zh-5u-T?v)e0mF4}ZI z=kkk%F7*TbrZX@AZ~k;`Glgq83Sxh#@?B8}pmH$+C%fRX&!W&eZdDaEeFv9k$^MZo{N{7faqQc*j%DwkT7fIwr*+=(d)Qk)0hpXhtJ|hmS|yh zsKi3yXbiuDAZ2OsLmt5dxgmg8A+}yD2{`F`^?kYf?kQuJXqez;|iOxYXt;5}U~oIdy~&riWj##5=y z=le&q?$5Qhp0)dcuhDUU1gda`S&k?(^?}w`SP8(NDlA=o?MiX4JC_vGWTX)!W5!2wR&kRaddh+OZT^sDtH=S?Ne8fWrC$|lp}G?YVN0EZbao3J07 z)-p=EM1DIT2}_yQqB6A3b!s-X<6A)9)(#rt@VZHaUsA9yf(>u6R^w8|SUBtX;nefS zC;dVxx?_>wSsVvbsU4#{&#H_3VYjpuSLffMlPAyB7I4e1gd#IiBPDuDOp!ZAyB8=G zN)qP~i4gp7Tg}&^FTT-VGHSCDWv|;KVdHWa#<~JPZJUz*bQfez# zJ2#38l(K>fU|XWua!uN9NSXx1aI8pli>OT4c6U213~6 z`*9HzT?;eSPFQn##AKvbI#Q>|_Ot!4OBM~BuB&)Vju0+}z(L41MsFeNu2|#4b3f+e z7iRlmz3(i+`v1%zaE{iricd8GUyHMO7*f&~VFKdVb-5~BX#W{}ustw_oeTOlH&!r# zH^CS4Y@A1+XgKSF_x#c{yO#3fE#tAC#XzIWHoZyoY9eK6PtG7Yxw~Yfl0(~sU(P`J z8@=-t0+XGvSwvG!H^UW|Ldpo2uq6`Fz5WUP?!C7zMau(Qo;hs->S(T|$F z@uFG_{~4gjfYdsQfQ(6)AjzB>B;#tsK>{^%+fyEe6{mTUb_b0pzEQEYpr z;@|eHS`|7tpv=Q4M8s1XNe9j4JzxSOcNMPB8r%0i4_M6Y3kQKt3S(l&Oh_99CB+5I zv>jx6Vkk70k#Dz*6f`N#Tv*|BH)cq^+$ZWYK71QHgB@0#Cdiz>C^t=1L$RjAH+ z=~25&SVyPUdlb1P2M(kqBogv0Pdes!qvoX>{8*v?G?-wb(% zL0w{k`P|9bOvE~ORp0yy9UIbK;!9Ck*gfiOu!_o^jGLA2YH#;+mLH~>n}3BMmB4oB zAO$C$?vHQJRIfKQgH<2C^0AoHBk&Y{eT`ZB+#o1jVwKW*lkE$voKB5;EckNdhDRX> z*t3wg$TOw)F~eQ3q2H~TKXz$AC$JsYyFrPP3G0QO&GFg_lOxX)KR&NZP$leF-wg^b z^0ZP3cHVhi@s7&=T*iyRi|*daqL@;u7zb5{&?nIKEwG6=jylS|z4&oi^qXMkH^md* zS*)a&E>trZdg@7{@XBs$vnou0xyp6AM$py3$yxvEokw`)SBe)YCuBbh-bhT`;Q{zq z2UvmV6|$+7+g(NFv}qlvw~6@&Owrku+bzwolbl=v;k@qfI~o~jzV4Wby9S}^9y7a4 zhg7E(7le`}Jn0giVOL_I{Gw1nz;OPN{STegA7XO<-Ktu*$rkYWf+(0U#!tf8r(66` zcIxJb?<}?enNP2C6L=&5Pk|>wZlwTwF5ht*k6OvH`S)l4)p_|vHd=ZAQ+JQu?Vf|0 z2RR40+qAyu{`5)uw>Q$iy^;QTZ=@0+#VFCum)dst2$M>Mq)n^V?AN)7`N(bZ!ySn$ z64nKnBgvKh154A)+l>6~YJ@&S1T#?A?ul9PnDIN{X-yWy_Ffg|bh>n%U)f1@v?5~! zApzz$lYH%UfQqfIr`IRAjKzhn!9*((_9rVB;!5S=Yj3*2C%4V=r^Z5Orw|Ec&(O!Y zu-G=w5qIU>!I#^I4)(qssL8h*og0G(q{rXM0w}B@G-@?l=!T;~;VI%vF!W8a z*8A194seg@1=0Ojjw`nB?g$BzRb@4I?5~eE$)ePE8}O>cfBsZfK8q`Mr6s#V>d-77 z0JK4`sq)RE1h{czJYFk=K-rb9b1YN1GrhMs{#2 zgr)mDDzWDhEE;2e(tIdtwu#)p6KZ25-}6Jp`(X{-=eV?xW;v`j*M^_t2@_XkHu6Fa z-t3bjuycPKEBLm(!WF;<_EtuLNjI;xY^7`K2LdN0QjFw>5w$xgr-GB~bn0^T)7fxJ zS39&_tdwc=fk=GcOrgU+Pth{SDvfffE);da3R?Gy&9cQh@^1NlHEHHc$^65q8WOTM z2P5)GF7VXwd29*SSr1-7s{P?gh2@6Ix#C(&Y?&*5OjE%>-!_1N?LRzU%<*wM<%mu9 zEFmBnQDHR~qApQP@Dva|x~V=m6=QyeuXp3n)j`np&f*E8Q6Rqr;V>PxhyWt;vFb$G zkh^Q4Y{~3)mvc^NpvW%XipycK=ACy^cUn}GB{Iye1jgEhw&+hiij3>#jR(UUBu{rj zy$v@}H~696#HreS_&}#e6laqhrlC7H6&EA3WHLuf*U7!BEIj(8QiHx-p-#0$=zXYF z8E_R3o_!;bk=6|6R?}~MkDvRBEzF`Px_&6b%SK@->14&1$NBXy1oQH-Jv3s0q^$*L zL_Jt=|8m|V^BKTxVA|Y>70cxH@bD)YmK5~&UIs@8&=HOUucFXT68e!3BVqI9!@W1! zXuXYhveBy#5*^g|D?3U!YXrzAIdN~>Qj*?4iVrw0izl93B%QtOCGm9l);J-5B0`y; zW)UG$(&M?Zu9)f__mX@lwfD0Ar*q0j0pfI^MD zLC=Fa+WZvU=oVE1%H-A!bAV1x#&S3RgBQcUYR8N6{@Ue#>GK1na5U;acn$41O+LLg zd-#iQ*cxHu3`#KC_Qs266RhZWhj}J$@0eWSA0H5G-Z~)d$*Z9<0QZc%?YTDZ&Ti`w zNwr0CqH52W3$Hp~TJlX=tJyfG#uW|uR~egCq0E;r5!C}bTL0~c`v1=nm2k5L9gbxnu>8@2C#3d>9CZwyA!2PQJk;e@Wt3Ve_nYYR)~hAn9sSaMi#41QBGXsa-9{t zacvj;%(Y#IIV93o^>bFX0-Ou#H&+66Zx?ZHm-Uu{dTGSdWkc%vjmSD9YFlMHE!}SJYXtlo5GBEObW;UsNcXQyzDE5a`lo7h7SA2B%2 zPlgwe6E4O2IqezT>fVm>_A#RY4pE(Qx(6gn4pBi2UW=PPEXeB61vQ<@s5yB2My0QE&} z`&?{F4HrWPHBVJr(sEIo6$h9kz$&U)l-su7#IgoD0@k9IBT<-`d!_r3m% zx?00n0U`)7A9K}HOMt~eVf6-Pv_nqZ4&{Raf_2ry%ni&?2&#!vlfAv6sl|KHh?|!84l?5B} zl{TrEvGTI51p9hCWWPjdN-EfGlsNGbWFJ7BZx7P%`M3{L-Zx)e^u>}Y($dCT_@T5M zuJ;zYxy!`mTB0-0mgy6eSs?*gr!im?55?fflhwnfO({hGfP0md<#2dHRmZMuX5;Mj zkUJEs7Fqzj1eze#?s-DQ8Akc?ks(zP)^|Tqee5w8CLy~av}luW%cgjUoC5aIhZ_${ zWlV>!a}OlwTvSG$YYiq<-e!F*H1ouUyqSr7LD*v<;W#9QUf(wlTY&ODAx!kVRnz2W zNPnGvMyBf7g`v-CMOj-{hC|Hu%!$aY^eyAn7^ILnT1s5uTY8M+ZB6&W4J#0NxVt1rw%_n z1B(kCrmFA0Ha~K9=IN=(9L-aYuI2VJUwgUm1vtU4byP+U9l)f4f_7tIAcx)N@6=Pz z)~>66<02HgxmG7iv@r{yD-(8~SFa>qvRO;$H|4Mp3sBhuZGd5_p9%vL0n5AA*jVRvV?7Z$mL94=mei6D;R9 zef$&3#@Dymw$Gn4*r&ZukNeE%z>S`h46(9K2LV7 zlLGmGv&c*$+^uWVBH!f(lH;fnbnTPZ@a^z48+hLUG}@g*!ZU?W%ZX!$*2J;yE`Qq= z#p{FxNjZOOTz$xLfiG!nCRDE+?`VA|Ro8s}sNo3CP|kGd9M723VZ_JN1MmLXb)mL1 zbO2gOmM+SSSP~`}pRgXh{1TTSZ!LT8-8JI*-S zaf~=BHPX$lUp*E4=Cd(MtFbJ>kdaqSTR9=Gz&$X3iH~1;KaYCV!NjF4fN`J)N1CbD zm(p)Pvy^r%%-?4L8&N;O?}42d=xg@wQh8Mt$Wm!0Xt7-O<+3=j3AsC|qk(&l*Aukk zYygG`4S4zCfFwH@VuI-i@1?vQ!C#4OqFErw7P3{H_U4;>+xw#fWj@NPaOL&1-h+s( zxIu~nl`*)L5aooj#9H#3?K_9{GM_U0?WY|LOwVe_dP6^7A;Y+zgRD+$p6`=&Jv+3S zDV**|E&_RLy6!F^k&d%bc-<54@GED~Jv3qAdv;j{IJdc!@8^$vRXUA)(f$J!va_O0 zCu3sTX>ujZWTcDXiN?3%S)bSR7Z9u{VA>wP6_70k+^pyt?N@!%I$Z*C$~sVP%~V(yYMlhwqSi(Vn*15sV-i>0v{2J-teU5aQ&#Kw43N2SnG;QSvxlr{~(5xSGq7B*v z9>g0mOZqO%u9uN-`qW6*y5NU(vs&88GTbh_Abfd6=r6gC>YdD1)|;);tz z+_l5YM(_9#w~~8qg)@O47U_mUH+TvnN^Dmh`(&|e++^_i8J4FdotwwDGb!Y^j5n@k zMhftz3dmwv-Y0s!yh)`(WyEjYqRmwiRV!`}q*5;u`vN1U z_3y+eWcWSDnrXky78&vi7sY<6YJ-!X>7=iu&$zAREa{CRKC7gQ?jQ}X_e*?$B|8t# zt2gm{?1&Y0+sm1_nIkAO!ms>@?|}d|E-cPQXY&|&-zcR_f*bmI9{I2&VZ=cZmbCNT zA{L8D)6T~rEZ4U4LM)&OV6Zr}2^Q4spzPDmAx>?;D*1iIFykN7JMj;pKCL=+qG)uq zcz0gQT!8tu%=*r}XW}#IvIO2IxBUFdI1;!+kK=nR-_D~GOBEVFpRQ~uyi%)%>+m5z zcvgT&KB24yd!maWS%Tp{@+ap{$GcMN#vhSmK^re;D*SI5)Vzi$QL$s;5CL=ZDN2{^ z&Z-W*Wv(db^Z9j3)cCNw%{{MPHQo=;EraIS^!kY#_W@$Ov_XNh*ca#XNr7hSv5f)9nEes@%h^QxgI}NsVvI5@X}p$^JJh3$1&HI zfVyjtb5mC;Wn{}lL-)q|-pMYWwnyGocrnEq4Vxz^VDO0}I?13`mz9$de2rkMiXqP& z!R(J@p~TS4iR>*k_UEm0NHe-1tVSwbHUeJ@s=H;Rg@~70XjWLWCo|TSI$<|sdU$NZ zhO4bpJr`#O2d>oCw~Bc8KV3EdW}fk>JXLKH4lIzPekpvXrvcC>UN`20`!0WT%<0qnAGXOs z|A*AbPQ3{785F4U!f-D5Bm`Vhde91XcDAaa+VD@U5v>Rk#RuKzS0s^rrquoFL961B z1GvVSYjw)?Nmb#5OK}PT*Jv@%OvM=~Di&b>r)_k3XTyT{Dl?~CFhP-7X3z*Nnm7CV8 z)g4&bH0ih{|Kr*%cq%$eqLw@-fnF?Z?`M}I;9JrLWZz)K6Jj8GN8te62%eY1uTyu$ zTeW(P3ekdQcE~Qknlktg&wpwjcyZH7A2pbNXyn%GyQ^)*^r=j2FXDxZKU$ZkqXhF?SR5@h}6aj^XZENhubVmKGYHMK~~>LZ?KHRtZVavb%lK> zokna2;zej;EoFQ{QvwnAQ0O+y`uW>JRrE?J@$zb{s8B^(ZPxgK9qq(!R_J%Gf@q@!TS>|nbHUo)SXZqRvNG?KAdi-j(^06AX zH-$wo?CK}VR;c{pI>5GviCgpK^sQiHMB1La@m1xZG%KLYtFk}uvpF1>z^?Ls&EE%n z$IsLJtr*-?MkU8|3|3(YDEI7O89&|SLo1p8OR2CN%|rlTXtj8!;yF}0YBl=v4H0zm zHqb8o2CVh^;(ab}bZ^^Cn27!TGB`FyC~G}Lrm{Jz$uP@u(|pQ&Br-r#*;@VaH^myw zZ;xVQg-VN1gH8^b@>YwW(-?T-FaSZlzSOmIbc$)qCu0A}5%PJ`0yc|X>xY0~C#L$% zJqy+?7`KjdJ$?|9g@W{72h)gC%Egnf?3JCxQZ6&{G)yAlEO&8h{j??|ro>add3F7y zXJB-m;xtjrTfLfFIGKCDizha{c83tJ=ox5-(6?mup;JNjvQj*-WmIj3%8HWBI9;eJ z9~?)!{F=MpqlouJFKEzuN@;28xOA(;LC54zSD&|3(xZUoZP|YO1m!+oZ&j9G91k@6fAzuZbps)M|&)AbV_<`1uk%?^b2 ze;)3cG7FE?amBsI1avGKMPm3|*q>-;6!d5MHeuuY12Vb5~`6(OX7<*i_x(z z?jIhxI4MNO-flbvE5gUV^D&|62QfXq zvjFO^_3e?&u*|8)e|ug2+eoxsw*i1?8fr;I#O<%cko@;>{@-RtqH^zG@8`-N_s!@W z(7GZAk)v3;F8oq1fHYC~g!Cb=eu<|4f;RI1EFAb6<9)oh0xt;|6sJ;PH?FtM&I91WLB99G)+07!&MVoVRQQnAhRnx|MoRg^O< zIH`wE_E1(UP0*weA7a*v-V}bg5U?Z`Xp&IlX-Nu9D6SUklPa%zcY;SqFMd$4Q-A)> z2)86z_0@~{Bwu(n)!db%`YYH4c8^$Es`x^2?BmK>X3Y3E8w;0KnhXS)T)FZ|DjK~` zf#KU%{inN%`^(5>-Zk*p-d0HJpvv)`yDoRzNkRh?Ur!&_@gA^9zpGhL7YA99NR5nX zduCyaxQ0fD%z=%(OO5$N5Fw@WS@Q4~UKJd;(bQR?*uB4XqQw3hSS&@A#-?qyAsYt! zU=Aqt1}0F(TonelF}+Y`-{N)t-hwkH58ZGTWzn#DP51iPOSR%L#>><*4D9RjGn4p2 z^Eom1-Cg9!cTM)`?Dj7z^PV39X$%~fzm}b@oOY${#l>nL{T#)LiC&QP9$zTj>GYW9 z37)olFBi~3-BHNvlL-TA{Ak$lG!8v#hjzXqD(MU1Ti4<^tbWa-_YHbiW~|TAC$t9! z*N(Vf0{J$(%Iel-?S2)>#lnHDJ|B5BIXr^MGo-_7;l0$@#Wp)qeKwhFV5r%0>we&9 z%c~*5Az<<3e|vCh-|$G*{#{Lbz6?ADXy_R&NVdB@6d$*hC-4KqYRWD*iuMY>mzb`n zy&B^6zz(s-OTEeiaqQUR+AKKKJ07x-88jz~8|+tVxq9phHn)v~aXL>XTG&pgGIw~p z@YPTlrp!u*M~66&blCE|`sae{`8(MKR1WwT2A_rS3@Syp3$|RCJ^k)pF)fAT05d!^ z4YnF|pg3+e#Q55il7;R;0Fcp)#`B6HC{rj_bf-W+R?ncWoFda=Dp6XUv}R}_sJdqbigIm zs#VkOAvk(xp9DN0ji{I%kYYKcl+N~AZ8X&OVb0SVU;NbCFF_(mE7V)!tj8M!aA2q2r7v*A!LyS``QOgBuWw$wog+Hzu{_&A56{=)DceOp^ z1B1TBSYBh><7vG!r|HVdS%w=(;v8x?r zS{3j5DQF${IIQQY_tP1lu2!0?>eWlvcn(_n$V5Lp{3z{#Yst+-)@TPv#&mhWeRnzu z5}eTzUEg*O+NgY$UrpFYzMz4BRXPQ!4zrr19XDaExne%ca4wvUSoN_$;P++hw_F+& zV)^2Qu2ud)&kQvMbS<_5F60idNfT?FZBJE_Z}objyt0f_^H=vv)A2PI;Tn0^(SgKA z0@ljd%*s~-o^Ed%Pac)+^sNqIAcCfARmoCqPTsNOc3imzae6lw>k|#d;V$+G)jCKs z!KvYy>FTaOGB)M^x3THJ*4T7xZn`k-foHFZ-)bl&uzAf5)HCGRwdpofpE0z!x3j-K z_8#;m0dD7aeqNEccy*8DY9?)=fridZ3k{E_9T9U=PtbAc@`*~c1O%i6H; zmlftT^zjsmwH{i+6IsscH7iVgqc85(pRbZIw5E|3I*>5GG$gOIXmqT%W>!Y8X`^1- zB3-R;>=~UkT(I z9ys)nKh@&eC}%<^n^IVmWC!knHb)m_YhyLNzZ}g4@Twv}<>xn#v^?LRVWxMLk8dlj zR`hGx#jIMuBOLmox@QAcbV`w6Mxaa%&aI!8T{8)QLoC0+lGM{cE8(|i1_Ehn)Fo8c zW#+INLswX;Wme6px%_NDmBt4lxR8d>h~b5;`R-3elSu1L)qu;Y-8Imta)%F$TNmCf z02T^rp&1GFV{y!fnQMSWBVe-8aDIEI+I-UwOOAd$#F%MW>wOrp18U+>*0Q8NGdhDv zv>elVONO5%pZegnah_&l%AW~+zit54uS+&Dh>wsK<$hM*@e!gM$z|vI(n%dR!XwT_ z`1GCSrQ>!bY9+wS=Z`#$(}f@sjMpxC2)Cc&Ff_VW2Rq+~ zE+N{&=urD`t+N5a=Qz|!?_pwWA6MBywOrA--3+rLyK2 zv3Vgcm0pl!QWj?c zikN}AepNom()NQJ3;mNAULx#lUgp*8;f?&=f?N6SXnQFBqS<^TlL0#S>&Ckjn0To z{^!fKawS2%_J;Z6(nN~oiFG4HpPN$>JS+T!*pA!m`sd#tz9xssygCh9#a3=>3z^?Z6I>h2(-gmvJO84Op3uW^S(_c(dU*{(mn2Cy{_ zgxd3@tt)o=)XFOzWLk&_l*Pb`fe1KR^`6N4GVw~HVAut&p>IVE zDSuFREcm;{;|t?{!VK4(JoB~4YtRb&DzFSOK6-zNH$2?ih%znxYy^@rIIPa2S; zt6)x#yA82yi&v8#Y3s!nG7EY|eKBp-C)V}I)x;g%3nMHU)Z1J8ROF42x2wZ>;ifE8 z=5P51cD{jyJQm7x{w3!9B?vnE`C{-&q!=&_LjeejO)w2Q!1S|kt{f?6FEaxhE zwEL!hJ<#tizE?}sD0%h=sm$j)OFF<*l>B*mn6407&+$(#87&iw``>=jJCLTqfha!K zBh!WC-@=@>b;(Oq@ggHD!E9xJLy11~!95e?&TU6j|IxCBm*8!G)bgaEvPkmpDf`+# zDQzpaY=q@ii%{24+Yn%#ES1ng{1qvBfxi!Ev+X_u3l=Lqi0s^Tum>d@`ANq2TV_;> zNjuGrguI=Xd51EfzD|+K&7(LvZ;Cmq^(SPsr*-Ob#Rm>VP@f)~B+v0_J>)pjY@+mMRQ(Uc{BsT3Yl{w3 z4bDP)A;DCssl&<_u0(}+~ln6)Vlw&o}Am#^0VNe$T!5nOmIPiX~&iXukj_ims&5vbw{nf>w#$U_j& ze0ueMFtu91QKPZF)+RUmQuZtu+6&d@SUZ9x6HNddmd#Ber;?$2{-+8iJw7mWX-qk z^1l(oe6uFYeWt67LfD*Y27` zo9A{QTs#VE3Q={q2B&SYXy*-yhe9rM6D8|u`vOZo2aG(QQCtJ*h6p{Jg@Rt(s;cKY zG=;177X2y}DM>v?b>a057efY@(mz9mO7bHMfQ*0NZw163OMstHcH9+a61^?W>S1D_ z{E&bP9I-FlT2oAU+p^fF+e4s7@#|GKvL*GNr+Tne4`0tmPH~mAv5^~_);^0SObEbQ z)dm%KDOEoyDg87SAz9SbjEQZen#*&C`p4Hs)^rq~?J)LW>{i%-e{j`Zz!VjKC_2ix zo@e3YTe^7_wH%Qp%Ig44R%(o4AoyOG6)uRI7)=Q3!f@h(DT%NDht%?&o)Q5Z}dsXWf&Q=ZIFlGQ(tUgfLx zv50(1J87yR%3fesIG{QJ8JexG14uCyxFtuueLW38Jl3u!S<>hj(v=~a0isVqu~Bvt ztQ#TDMUiLCj>lW{3+%|Ce>pp z5dXPLPh^&vZ-8kPtxict_RE-3iifFESn<*Yczf7uPQ-)@VU8Od4-QcBgCnX7VQ{>^ zclF%+b9mKqi^1+W^=9d_8u89!X8uM67<58K-?Sp3{LGq-WYG4|fl|x)uJfKXTr3d_ zaY0)!tc?ZIVmF51IXZn@wisqZJMPBG%gf1TuP@@f)o{#v%PJxhZDHOnM&K-5%p2%W zh9=fk#&gTn@Tm5$-Dkz(32v{+d!JuE@`}tzPg0<-Bs-UFI8_&lHy;ZUs%j%aI#(UF zG`B&s=kkm}-sI!4fxXYGJMRGcUlvTv+%<|!X}ZiuXSnMKcK&I!kZ`e+lTjZMh0X0+ z7EJH{Qbw0RBpQ-bI_=Q!-)DOaPT_?%9vu6mbfHM#+1FWD3Q+Wc$J(I}?n*Z}^n6#W z94^}yh_1T|96?(E*0vaRvHNFmcxnXt`%XxqMP?U}=!K)Uwah%#(gpjO!ot8bqby7HGD`Yzna3m&ge{zjGYeE%KE~8n#XuN(t-o_+eu0{+$HP}P;hsN^r zaOF>A&g*?BLeCj{a8RwYff`Q@Gn%O-36M=@Mu2KJaQ4tOx}?dB{sXe$r-h9k744&$i%J?9W3V za2!t+Ew(pysj8tltStoS)ufy^_@b4rz5_5-ZZ2TP`A~85%9b}4y!dxm9p3I;yGU}6 z>q9Z*QQbg7EBxD4#|))Efd=CIj;W$CKCcHV2rwDXoD(7I+FNunyPC6S3PH*aBwV(a zYqSRsvA|t>?(x_?lV>%1RsLX1W+ep^HRswKEkF_w{D6h;i0vR%UbdEb|3P4GI83T( z9#b5VLWM}R5|{YSUwfr?|2!YD_PlLisEG&X?DiiVa7P=1)`H+>Az~x_N~>O~KY9GY zgKyuaHX9e{U2|@tg|~`$9o2&(0ZUs@!R(R~e4P-cLrLa7quKj)NW*~V@aW%esg{5A zcNUFBhT4X(Il|=#vXWV}`$cV8m-QR`N!syiULZ$vRikOijlrKx{#8(wg_9;~Y1d-kOB5+$5knKY8^;CoS=rlQhWhX2%K zqbX69MT~76%dtMMxvcZZraA!lX1ule9&~7bawvIx zDyfS$a_Hcx;9EDSTz|5Mk=E`@e=t`vu||Kshw%UQJ$MCqjA!SIfFHE8P@XKV-Ck*b zP8^?>bgC$0_t-%GcNSGy-CwBTXUme~(@|R`Hmkr?cKXfT_#N8+24cy`^H+{ov0LF- z7eFvG2lUNuL(3kH02sUfkk~8a0Yn~4l|tP`M!5>ee4xCqj6AfKT8An3I0Z>y_`994_suHbd3r=TLitI+ zYs9G-os=o#H6?`8BX!>`0D#EXD|DnM+6H*GAg}MV;oY)IWtf!ExEgHnMJ~|1`w~Tv zB%ZM;bAHgItrF=`8i_p`~829dtd-abV zRkGDf=pxUx7bnQ&^ZMAxTf~AbIELkiyJl5WZ+PsJob`K~U^)=`Xxblr+~Rg49HG`% zP!o2*72Tx;+AF-+@ttLCYu$_`|A=7rw3(5IwaAK3Hw44w@t~_Eq^rrs(?+>c1hR7b z8N3LfYO-fdXI6mkzzSg}b8kCCGp}pRd;vM1T~AA)OZt~ayUK#`PT+@#bgg7tLa%G{ zuH-fRTE^IyS4M;^d+wh7Am0=HlOr}136fhGBE`}txF&QrKGwyvLl(@!kN>*&65E#5 zgVFfpn9adXogQ2V7UP*-dHjyYS_1vdd5g^01bq!8vvhaFam(q2Bd0OMO|>BMgKw72 zXD+vy+giznS}Dpo~U^ zzt}P3G%Bd$b7Fv+)6xeM!>{#`WMc=eB+AsxBs}eI-~NR9MPb6NPU5V@ihueOzt>k; zue~MCteZTUQ79dvL24`YkIKa$&N!|(9J^S$EKM0cZIf?(Of^+vTlP9ht|en=#N=j8 zorF19&};Q~LKXFI;+W}~YXGjaCu}k~rVJtfjthd@e!4~sa$?KWoo$~Tba>_h$FV7q z7JXNXn@6%i!s|H9{M+)GUS?#2yJ_Gr2S5g&-&R(e2iRb_N2L=F39T~0W~|qPLEZV= zyn*A1+4>B*?Kc*iZ2Amu6xH!BYmWn&D|CQ|)5&~sP25c*a|OQn$U0JOhPuAnk$zHb z78n;ibNfQ#pfswtoJmy!6n13mcu?Jhg}weVz(dq+_*mvIGxWPldqG}t27<|0rSN|~ z)Wb&q+yJ$7|E~;C;J7S?;pJc zAWIY$0hYhNA)9~qMgpRtqk%zMLLWeJK6G0C)Bz`-5wR=+8P~w_4viWf5yCzem)>2^_2}YWLI20rG8Z+W%m*DMQy@jx+v=Iwr%$kiw-);L^Ae6P!HJ-|CTahZNN}4~&9JgG9v#oCeL3Co8A3%XKCFS?Bvi5v7m(!7c_GInkuOB3qBQ~vnl=^k8p=Zb(E%BHCeeApZYaTs~I z3XrE1N*35B{QRNR7I{v83I9QM2V>(jYU zdDH!FGm<~neDitIL*`?@aw&HLLh@Rt{;uKu`#1h8cNcpX={`=Da zU)aCA5uUU^IJez>*Ny?jyaW2(XWxj2ZVNZ8&1Y^1%|jDLDM?dhmea9QiO9p;V+Zu9-L`8SnOf$567v3i z{QtxAqesR?a=1o11zmZh_A@;(&HcP8HJvDPMBuKWVIhN^0pzxYBGBJ>%eiJRCqpj}_QlK0Wy082k}>P}E3GOw}srWj=B zFrS2P;53Do6K*Jf!)J>15`!rL#`RG!#bXscE-;NLa}uRh#^cl>&|^WbHT_%HiFp+C zsw=iHh_YUl$I}fv(c|4rp*|e|?^;i)c?o&1krqCK|Nq!~&#^i4g>#F6>x_vk?Wb^)x z2&p4#LI>LZsRk0vLzE85>Mid)!#K)Px7D7edEsFHhb{*P$%kjqCbe~CWuKTKujbHz zgf=w#MAkXO?ALRHgLH|Fbz7rLa+Ps-Lg2N%fvyb44y(3yBwMzTePU8`hmRy^%63k% zPJDjn(q+JV9XNykar6Ov?QO?!ihRqu9zcbqhASf}U-MNON}cn@Aq@^XQH+ohC%_k_ zr)ZG!%?E!t+v{-gKGUR;NCiionybk~JN>=!(D99Q3!PGq<%uJc^2+^+AwC}UbV&i( zhp|@B7`&WrM|WA5HL-fJ{?+CRs`vC!)I5aGc_BDqM55PP_HJi=#M_GulRuUP^XAXmO~7_WNA7uR*Vvm`aG*^Ix+`4$4AJ=sykl141Q{?T zI;L`Jk3fxA)*yTPXR-$5Nw0>h#_qvGI|R(uRfEIBu%uSu4rSd$!&RYs;4j@!n_^2# zYzx%a_j+^2)P@auG1{=j6&7Q|hAuC<;z2r$o_&9FdgOQ;NbHZ} z>9k)EvK-xf+jW01g9OCBoDS7@75`Z!^^-sVpnrv1(*E7P-8iDRW)}xwQ*eHF)_r#Wzj{u)?n$kJC6?xzsAtOk zj}%rV)_q@X9h_v_%#tE`@DI=~{oNHH{ttkgE<9@3TY~%Dw)yq7|8>8Zj#sjxdbTu) z|FQPCqU%T#aESr)GV^i`B?a} z|9G)dZ=WkZS3>-xwjxcD*a9&xUcxVn1H*ST*ZP?chW=@j@SiWlIWxu^_~O$e$Cu1% zxF<{pmwD~mS-pc9YzPT}grbHz4yWGooTBBMH%V}E_C57kjgxhrX#9%vIS2Y-$QGo` zVT&uOd#@1@=APRma^%$ElXT=1?xu0P6#2;mej{Z*yj*+hU6!rGc}>w%Jc@Rp9z8V6H_hu z)0lta2Th&$uj1X#zUuS|8a|W8lS-={@EF87w#FL8Kmvmc>ZwquayRdj+b_q-Al2V| z5?aV{zlsTPU|3*k{ahh$n259I1ju|!8{taB!m4?5Yl58rjk=YYjxo`e$_Dg(&LSAKUc|T1&Nr*`8ELf^WbDjYs6;m|aVGN4+ ze2hqMe(2Dv4u4)8V;-Vv`asM*#JMt_z<$-^qPB3gY^rGH*1602`-BlC3t(H*Z;M|B zPH>FQe7&oK%B)wJjZ44-xSwo6tw;9&5b^SQcCDPutP(4_e^{rAk3{3m+-z@f;Cp9eC& z~kJ}2>h4RsUTb$aru%QjR`)s5Rf zXvP5lT+Ny9dVtQh!h#yxvY5FS$8|gJ8DMRm1>f!dsWSZ!Pb)phmme9Q7i$+2QoB%* zm%ZKC=`O*+cXw7=f$bqoHLX&m$Bm@^gC+&Op%suavxxw5?fld_&l^bz2~ijTYd(OZ zzXVvc-vEpblL1EGg!(T#@CyM)9=xefr|SlpYtCJJb~8@!U#QBi^>(`QoZfZiOpUQ9b?18V&Juo} z;R?0fw7tqaS2TgBF7?FYCp_1oc*V&ERXgveZ_<^2nc+ zOpmc4#{&p{3vkKPA0Mff@>X%dN0LS-wG94CTl4#^B-2xM3 zSq-WCTg2Z6fPwFt+zgrVD`izXm^45(LQ~8F5FZm%0ig^qxv?s>m6x)jO@sq;Cji>! zx9A@TrczOr{iqB90l2E=aXy1e68v%Fd2 zo|TN8SRB(b?ye`Q^73-JA(Py4Eiwg5&&5>rx*xwIQ;}0h?ObWuwT%Q;0IXuVQn)T> zCL~Xbo@iqAgQknohVl$f-O42kmjR*BLdB^cRDUiri`=?yl!5+sCyr&ctO3aMex`+d z1V~yA;KRfk=*H#tk8Wz)VROaGF|)}600ZX#gGR)og?Iv36DDc3tO@7_Ao#a#x5GSk ziuyo17k#woQ`u3?#E^R-JUVdJNhrW2>$CX3<~>V zjAG(f0>BMGxN*dx>*4Dv3^M!Lh5&W(GJGIr3m^^R5cdO<`^6_P+-kD5F~Mo&B;HLB z#S%`bM4JywBhe!6iM5R<<`~kR4WF=Z02@W}m|pih+%C1ox`-&BbJXL@*(0r#G_87i zH-J*++F#hgN&(fl< z3?qNviMu5(*qSM10P?&PF>x0X90_AS#H-T?VqWr;1k&sRw}&ya)O0PEC2-KS8WQz^=e z=k06S?F_Ag%qD54`@gBZn3{3|}(oYzDB!wG+k}y!dW9B@eI7e0?^QJ-TJ` zY!=NJG5sADf~bL5Sw(H8&_0|y%;YQ`pVnICJ2MFYv{Zh~_NOclB z=qsGLe8JCaX8||}2|ZmmQiJNA`nvBGE8=k(i9_>&Ce+DEgds~B{DJBnUu~jL=hb17 z*0&BoYYdez?gPfZ;1NYld@LdQ(_kY3g5|kr6!e8`D60ZT4FG_4)+iQ#aj-WUDnY+V zlRY-Q8c|Y(0VI437UiA69JFB#Qz{$}^ei8h>_umYbOh?EIH;d2qp_C>ww{ndysovd zO0}xdvOlwP#PZUzfjz|oH=4XXYmJRWtpwylmVMnp%KDrJVzAbUcA`|^k(uuaPnv6N zzsO!H13hRvkJRt~Hix|u*>vT64X=O7O&|@BS-*$NG!|^LERPxOc84&6kSx%U9HYj* z0=>F6(=OcR!sJ8FfJ*yY{$d3+o=kzS>E5&}*GFRtPuHxdzCavz)a}4q52Qi^&EP|A@YFaS=@qg zyxYN(H}s;fKXG!gQquo@{(*%8c$?=WBM;aqPvPM^Ol^$Y#z+*y^zm3VTqN3&)5w(@d zz`zh3&?DyLbzQY-il;HrbQTjVAeS8DI#kWve9`DWO((^IYa7GC`BB!HIkZ*%SxvpD zl%KbSZFtpC{u2(kpXzu{At2XMOK5`w60GJrdqA5kjHNtK{XXr7>6~i;>=kD$%iVs^ zB&<-Ycz3@l%efe~<|@t4%MKUKi6XgIVP0b(AbE-bm&dbU{4_1 z;~GB;%(r5ONg5MVp8@{@Qhu9WcG}X3Ltr$O?I)-?lEO3xbnh_H;{iP3 zq?eBJ1EVhk+t86Dl1T||`OVJ~1AhbDbw?pTL*RaY7Pq-mxCyVWps?vtTWx-NjFKU$ z13(g#RcSz9ujBjSx80_-{E0)V}rK=KkwfOLNG0Q!E; zEY&>Tw`rzIW`a}Wt=;3SGf%6;5ckh(vkxMqoYqeiY5Zkg@qG|s(*%B7DP`ZZN&5kU z^s;ILZ)m`^g@=@>Q)#c#z+p-R;z~Fl*Z2+**u0}fT-b7m?m1P9?%9b}^|gF@+tPZm zd4?S!l6g4IaBBv26~1O-3>dBGQP*?HC)ufAU~Xgp1z$N9^z{LpQS19g9tDb9{iVrf zf3LDz0xdZ|Xsm3CzU^5z5HE;RI`K0^0L{}aA3R^qt81{ z@KsCT!aCAI0MORx9N5+dTr;gKsAH<+_PRrH)OZRku();I4|rF#E!)Dy@Co1rJQ}1# z0vE)G^)-}o_%`C)elVCK&?RU2Au@<%)C5!stj3X0COSWh^)*gu6h+ z-lSCr<#j zdH{r+YDWK{@lnX9w#ov_F=34ZZf;_yoB{Sxp756@eexLqA?XGH)ujRm5)RiAg(n@W zTn9oc5r5Etc(=ui0OkR{9U_j3At#Nf63@1fKh!>p!|u8l>+$aPxe>1dh$8(ykpUN@ z4_QJCZ+0r3S9`t7{4=>s+7{LSIATs;+vdyd%^eDKGdSgg*5*Ul51RVlhop33jY5J@UnZb=3Ywa4x1CV*_uaiN1--E(E zgFh+sf9VX-kk9(aUU6yQ3=R$5_wansBR2k_XHho#;AhsG z?u9?bjxikryV`qtJp|iAnShd;-2aGv=bb~zv zfq!<8`K^PYuR9nR)e)?s@(YNcP5%JGRL|}K7~}{ODo(IZud=e5@fA4$up&Q5m>}4T-_olkIA^4FO zFgO5#nw9viM_w8RKUV5 z?gDha2?n{@0}J{cx5qTYEe*R|C$1cCToEQ}9$-_`7vFewUMKb-PWZClMZXu|abr=7 z@S9l8mS%0yFSWYN<`0v)lE<>#RFt$vqXrr-*B4%a5i=mJ8Pq(_<-B6A|L}c}`&I5=1RP^MmZfm|tbHQRj&jMx4pk)wqcK z3nni##Uz7W)?TFLFO1#S*;4#q=vo@h7ILTnNTcXP?v0MuE{sEj>TGB4uB1Vo!Qp2}H{W$f>n$_lyPQJd?5t*Xg9_TOmu8^Qm(7}4v7ev{&7`y-OvfLko&oo)RVibeFGr1$$Y||iss_Y&js3^&OJvF znlq2tdD0=N>4H*(EEsgE3Jzgm7^tGy2EDd(X=f%H`Y3T{N zwo@$RqaksPA~5f)(2I+gUJvE35F%*r=sjjaqS_;0xI`rJ+K!MZYG3awk0xb@1tBpo z2>ywAjBRNAF71rU~3BW`evB(hZn z%QL=A`Yf>Pr0|wedGFD~!&!XxsdCvq9{1*YWJK>pA0_?xO28*aXy2#|X*u)b&>5Pj zN==8qKQ4Z5uYc?X1DG9btt9^Y&XACml#~2pZ`@Qf{Kw7^zv1lVc^CXp%?;}A z=KAwIk=wVQ|JcdmCeHT2=8~3@5Z44dJ34vsNy^t|a`Xt}(W8tf7>+TVIL*Sy$a4D3$&;r~o;<_OdJ6clva@q? z@o;gn3kV1a2?$6_N=iyA{`ot=#K6GB%ygWY`S>Yj7Uol@j-NPj{1o@8Q>Raz;uhp! z2YwuaeEd8-Jp6nYFA54?yeJ`YMMC1w{)#`|(VRGPAp9T??Sb<&2TvTJJ#pa2#{;SW zd~^qX`vIW-{L#`JICzNeF#VCE#~2R$*Tw@h2WkIkJWg}q&;ikw@IySmWJoRG?dkHZU_xm9f=U$%@Lyh9W7s@pM(L|F|J zN1w2y{2DZNY5N4t!Gi#_hkk>J{xF^NZy=nz%6bTZz~lT$I*FjzQ$HbiuRrijQo!!> z!>4g-2B$%uQtN_;e*!>%LHffW07N#s{VgLIFYw%-ApC0xgnohWW1NPO_P04t(5TWh zZMosMZ{pHrQp=ag*3eZJ4@oBGU{?P34+zVdyB0PS@x3?~g~+!kz}JV?hH}mHRg0-h z2X3_PU^O=0;npb|iy%ajs$)T)&tXR2r;5Vzp4wt+N^ufty*ZiF7Y~M}bN4iz1h@&{ zHk|uYEbDgj2TkWVaD@e|!raCK6bbZPraD2r_s`cP%CB;!TZk}?EU2BZN>(N zCB?hed+jtR&YP-z7}sY}3Gx_Uq?2j{e(9K4ZGC-SZcHEccPzkLl|hE9^MUpsxp z^czk10?R3pN0g#}HLBGJ$;iTC$N?WRKUmfUzv;M{`3BU~JbhOjp9(nTGoPbNGJI$Q z&jt6uKrY89ay+wvFW=3_CB*OmypmX_*Ds9z1qWuMO^(NBhvE|;)+>nIV4mW1kF&>3WPLHLZ1*tw1u5cfV^RRXS_s?PKi)jMi*L|pAgZf7I z2y*hMxZFtV%onaj57p5C% zGREnK(~dkaK8sd-vAe)_$Uo4PX&yViBlZH+u6Yp!?{Sy?;ZyU*)LtT=A`%H}Ee| z_-4z7)-Q??f33fH%=}T&z^|(PL=?Gvs_9^2#^uWWm489!7LE}c};y&DPB6Xq|s!Z zqyb+lW*utNg4+-Mpn0hSgn|OttU+AN?biqOZn$Q!00M^Ph5DiCJqP7oG{doSt5*GN6U z&tO#vx~GZp3ZZEcX_Svr>`VlX1DiLOcO>jzB}YMY36qZ-m7jx?a3??dX_#|LqS9sZ zzSg{N%6D zS2Zo7>#|>x;;o_y%hWKNR^KwHP(oXv?Ml zM()eaN50BJS|7I*jQO)u0IU@<(6!tv@4JIbXd*cH=+q%SKr#7XyP1343P;ynqK&_5 zHWW<+={$nw556f9zJQg_sU0xNUq;O|muX;lrvO2OG9di9rBxt18cdW{g>=tSv^&s! z2Z@oW%bx;u*aP0|(tWIZJ+E0HpNpO<*?Ex4iO)C5&$ruLl1Z;U>(bm1@+|c-Wb(VH zG@>lbL%_EzL**@XO?>z3Po{bQ6z6iGx$vGb4U6>_G-W&4am2d(2aU<$b?qx6J>H-) z(Bul&i~$C$USr%pWv4s8XShzyTMWo+j7sI?zf4Ag7^^#1y-7hYq-~jmvtvqB8zQNI za%(f<-d5PQ2fPnXjn(v;&|9S*QF>Dy`c81{2D(eVGaQI=amJ_)Je#Yib$uAgye zH(v2rohCe!h5B0_-4Sbf;{{1gP8w!VyIL`(hAa7mN)=}GbaCc5Zd`$1sXh|$D4O=k zQZ3coFgWn-fdjR#nGbLO6dMNdJp#fyUeN%lgoZ)p3uFbp2*0TLtL7pag%a?&t-SV_Ny~By&8y0|U{P#87-iJN7 zn>D#`Nx^1#Z;~Nd9E3kZe?0!&bfN$11wL}X^u=@`e9hg~4qWvlMD*i(xg@ASI{DS? zVwXnE#QKKC`ri&|_HAWnhO%z5vDXs(ZgJCP?fG=3Rh^;jBxfRedL@8OInh)ULWjKv z^(-NXPR$}W*J6g<+S>2|ylmAbuJoh57j$AuM~=@eHp&@O=B;PN>PEJ<5l9FAups~E zfJf&g>GXit(j_0AxM;S6fFywW%NiRi@RV>2pm&_5qG_`z#`rVxrb+gG;Fp_3+ffcJ zm24iX^Vf*)jV_bYMakANZ%Iqu?fA}^NAY%hY?0@|IYyb z5eNQ-0E)H$&8tMhgn`z8u#Wvi!fOimVc+}hh^Si21scVHm$|QU|4U758vYM23i}_3 z#e7>IproYH$8q~M#IF-k+Zt~Iv;i;sSKWT1flU1*ge=VEGd=Bh$N~Gk){jvMQK8FmC+~hX=yeRkO^OTxMVWRwN>`GWlS8$5$bWE-DY_w;% zK$4b1+-=o8Yy)*31YcFxpxzSSMfy4gkdoNF%#>MVh1nVv*WIUXsrI}z19|UpjlbVB zQr%7LBZou+!tk@ayQi()FQ{J&g06C5F3yE2#lEaPssK3|&>AxQ-F?Hw)mYh)XGJYN z^=^#jm};*{31U2nh1)j{R&g<=xR#l+>d4!`yu=?WxQ%#E#tll;rxpVxP@6(snB_ zJ{^Ml&;tbUEp;hNH3OxV_@|&*r7cyBswe7AbeBv03$sfW=Rjc7A^HI_k7TALapnVR zE9uQ7_TK37bb`^POJ1HoM9;*XqOJ14Oh`}Mh z`Bx^TE>OUv@or8Plu71YTsJ|PvP6?lIVP_M?DrJmhWQ# zLvnZu3NS`??X5#e$Y_K^3*;v4JWtVz(Rb z!V6TISp-jrDq6})#bzCksAW!tV=N~MNHv4yxaD44t=9rfBoAar!7juY41sARs%xeM zf;t@n+*Wo~jTL;`fP$~G2GQRYWP!81>>*ywHN@n}xyI)_enJt8@Fmr{b&d>@02QC? z^FWr@0=28mxm#t?#aKUBvh-HuH`LkqC_2%ssOJ7{lNcrsF=v_wRw@sYhWko*O)KhW zTk+f)!;cF4x^cd>nRXrd>WL~bcjQdR+h z$poRsA5dL;_353Xp3i9wH|_7mYm2v|k__%oSyk1_NArk!+MoVN3B)yNm%y441BHF3 z=DyTzt8x#UK+IR~+N`Mh(#?Kl8Vx84T7jFbF3a1PksQ2Lb(Sgei;ZFlM87W4yrc*U z(FxzRGv4>|;fwPnxRybFZB;|eYbMvQ;Z9ud zUUOR@`EM=7klHX014{z#f9U9#l59T1t5qLFPs?bGLUt%IcORlcH9yL{wXX|pAE@;U zc|s6pOb%a5NH!g@Fp?SXBs9kAxVkg@I!(^D$BPA(MLt`Bo03A5EsAZ1CiKQFT*YtU zl2oc$C(0DZ= zNohv5-ay>#d>b3mG8GYoO;5MD+|>(}Yf|d}uoqEQ1EF0VvcGa>{DQR5`;h|fA2bK` zj*yL~pAoU$M$OS7F$su-yA5m@n|p$9IwyI?oX0=c zBkf|_CIrF_-XbB8ULDfu&A`U{WF?yJS5`IjtpqRH{tib`Da%if)RmSt=GkR44p7dX z_Nlj{e};d;uRV0_anK>^J*^cCf`vP5NvJtrnDZP)CejR2=vy|6re{-nV7jBg{pezG zw?|+(tOm5X%B2yVnT!dc7)Z+U(i3DP@=ZVA0nHox)V+T#zjku5G7}rv2=7rftHowy zS=+YPTzX|cy=vQTWa{nraLI}92`lbPO9pz~#GGnWOIDi}sDl?+*%ZJmxl+sP5mv^D zrkuKJ59GEh6W0QKPeB=-U7nBM*(u9n72fr^CcAqHFgF0)oBm6vj{hAMreiic*?^uA z;2D?7URN8-m{2bQio+Gv-Iap#3cHv3T9>ULJZ7w-6kW>N=RnZ%8gF;? zR#H~v;9-+{=nCPYtzfkkbVqN)NG(%7)TnNPqu*-RHw3aj97)!>+Hvxuh`TsU!_I^C zOcQw9j9yzCE@`QOZ^5oAX<}%~Bk*EZIBYtz)(r?U)Q?;UxQX*=DP*@_lqo}k#5&Pz zl_O0t(71N_Xhho^2e1AcI9BzoriSyCR4X2MDdje<$wrniFC>`{RzTiZad+L+sUm{Q zu?Oi%MB_`O;z17r&aEA?T%65t_=4h*&Beu4&(%qWv^CgNhs9Aosfk^7hS-m?^Fx^v*7OyV-wNMR_obq1(~%;&~~D5OB?n& zz`DtNp@eS-cuXw8}#85>efEt zt&>U{pJE~`P>B0X$5kYX1MZVbL$J`cPc{5P48lhm2jW8YL|N{@M`TCZDp(>BxQbbtRA(k~EpLotE`C7*_;Q+#|I zSqcKgk2PiyOS)4xP`#WF%b{!&I?RXsyjXimdCwyi@qKzQs|!z8l*OJewy@Q?$ag#D zw7OK79`-^QmuuOqsycKcCwA7p`|{pXu=H71WJE*|YFN41qoyMZR`QPH4m52xgG zspE*$Eyesrm`LxNhYy!43P4W#iSJv)?xTc~-_dyDUdRYCu_GnL&O4^>gI=59uOcs&(bBPaEg@zJ@3fE&v(tsmOk z0`+t&^66!H#hHhUZ>sLTTRAt>i1)GpP@cWrLQClgD2kchW7!rY>l8R|o*G=XqG!mO zSBY|*@LYR46&wHJI}|f|jdRr(asR+;b4{DS_7cb`Jom={#3EJyZ>p0(P~4E;i%H`J zl&?QCAKbnj$Noq8j}b0i{-41F|KGt`i3@V?9$=b*fq%!|HP8IVE9>IFfbYW`<6)`v z<9nsLT>livz?@9^m2;UN#`9*!(3Pr0mA5)MCsA$j2eUuVA?<8UBAecSMG>!gPTy>Gps$qj5k5B>aJ_o! z4AS2Uii89gJ>}V!cK5P3%8jfpD$nUn8maE7xLQkpbGdw@KGap!tdf20U0KSl z1Og9wa>ZP9>LhD>)w@>+|I^t+uSjn_aBtbhbc|55M0bz_3;jYyw}`ftXGw`FK{~>X zc~}Ki&tdKr<9m(pCb(}l0Mc1KdB-5k^_r)XgRudmks5~|v-J!RalBXQ7wo-a!GZhO zB%kiX_qmx&{luLbf6rC1xYEMPx*}yl+48;xPvVU8FhsJw)W(El#cl*+tPa!1NXZnh zl}4YYY4@utf7f-y>7X@p$_1a1>6dQM&o$EBbz_VW330F;nj(8F)yc8`&hucQkNLL| z7{H9iE^L)Iu}rkC$&o%Aw8WF`YEZGBW;eckI5n_$FLdl)QBnKA+owF-6H7uAQ16>g z1UbY?9y2uDggCrnrjsP=uuQ{-LiPu((W13Y{LsU3Zov)+k*PzQr_OVh5BRGw9bSe_{EQXgSoJ1?7JQ2yv@R70<|?qbSJJ*9*ZGD>q+ zUS50-9r)Ont~$0X@)lqr`0Fx}`+M-2;#+@)Gdy>PRZCfJdqHxztR2(S>%{Erp{V8j zxo3@4zvDc$53sP)v!PVNH;Zg4Hd=-NwHK6^ayhQ~dE6~ZW&$;%h3o_f_zYVdzrgd6 z)Nxgkkzl|Hf#>cL?*yzYvcCsN2rc1Hi8z?O8YEedkMf&H)yA3gzVq~#6Nt1Duo>I6 z!L0xWW--(RZDODa2{7s+WCJQkeZ2uz&6a%=CavxvHvv*V2t1d|j3qaJ^;a z8hH^tu`)jS!n9|Rv+2XK>-@)proEY+44e7Z9V8LBPNf4rHCBgSEaNH{2D{cPbcRP| zO`vX`uRhOVWj-7eS~UO;Y!|?;3oyTzY63Dh@1($iuEoK;y93lq`nQ>J#Q6zrNMi%W zw}h0MMvv-Cx7kYo?Z=Pd=$A|CUudJKI6kT|n(shC#<>}{o_~X~{OslMe}it5e}!&G z0Nnxry5p}-qzc_&Ncp@tXbwM~{%-;u{j?hYEuPN)T=WBfjje+J&!JUvblky-2U+T7 zpK|Ceq8dYEcu%em-L7lW+4)-datP09zQlXCzJO_L4y`w2ymFlE75+%+CfQ;yRy79w zHfsd6QQE@Oc?tGD3RO04dPGb*c5`xO>e3}yJvN|Cgy+NtZfuH?7};jSpf`AFk7*wDeScEZ|yf z^N|~*W}BkURAY6;6;Uy0%p`YMn0QGJZR9d+xwT|6Fv-`CW5uD9lU zPDNdWSemM7)}ayd!7#m&IxES+EtD|oOI~+TVL92x$RZ0#VdI}zb5iYSa-c{>+Jwd0Bi}UVY=}h#wi5nyOCExK6cg!P}uRuU!B{J=X z#H#h$_E}r;DZnl<8`B)QY2i|Hv=7y`wzWay8GeB?0O5pvcf{ny`Z}&1IhfmER@WCU zG`Y=QyP{Orc7hJzf&LLm>u&;QUAbN%v1*M-fb#a~PlgTiHB4ho7s(n5#GBRcjoeU! z=Iu#m7HM7{p5Kyjr9Inkxx^CiSiWthW$}4g5uU4|zS!>?>=hi+)p9;%%4mDRZ*-ee zq^M~XTt{=Ia-4YpSGlfqeR)OITuh|By8cQzgV@`#0RP}rvts8{14;K?NY5Z{&Km~E ztO!JVS-g?s#S<^g$LR~WKb3Q@C9ma24vMt8PUb2$JcG3{mQ{t7!+g8+>OJ}d*Udar1S^l88H)hn7)to=DX?3-?UiWJWx0lzXh4ZFM zZzqzVf-q#Sstmo-;91sFnb!e;J6P(vi)?rb8 zXpC@4F}qj_if3^Gj6^-Pv2u7dW+g8xo!X=!Yr%4oJGKOuG>R$jO~az1V0R!*taPpi z%I?#RO9d6^{0rP32?rvXuUh&0)&Y`#JViXu&Tw%ke#Lfh)fh9_Y9{{XiKxsZW=y37 z0eOXx=Qv~KxN^E?0Fk6)iab9d3X9^*v~tapG11lOvGplfT(O-4l^c3pMHp4iZ>AI$ z^WECQjB{Y0KleAE^ z`Ka;BCmUzaOg*X)y4)=qg?|YK48w2rRqy)iylNlUVLH7Ek_ixcaLs&oho$XJ>O)f4 zy-t{kOs8mBglm8}BPt$eHwQ%MY^?0M;~i~G(rTjNR-Mt)_n)GeTk&)k`vrJ|jmOt~ z{hxzfbBP{U74-o^@n2RX$M{m z85H|EmtzKW5ZRuV3}?Gu2T1bavbPm-&Dcz|(6*?NvD(VxQlmtw2krMn=&Q4dRjU<; zl&j^G2_6Mu@~EobB)s|n@1f-po@GyzN(IIKQ&yes$Fj!9*?ME8kM4s4EKGZHMiM+% ziH*sly>eJB>~MWGv$0Nlr&#XT@KCG)Noc z(>zq)Wj;B~T<^gbu zJ6N1H_qfZ^=8%hSf;WTZq*zL~apRi5^C=A1V_o#oi}{=dNs-LwWTe=_){3rO(M+ez z3f_C`HMsfxR4}$j`GWcUJT(6Y&7p@Wr%yYY7-Q!e8$8o&M>Oi%W^hUaGG71-eGApz zV&GbG;i5~uR`tFL!5VSu+!z&RL%JtW76+|^Z?pA%F9I~{;m|H1`ARiB-Gus5OFJjk z)rQhmv4;op3s^h^B1?#7E*brd=C6;tFp&ggTLG?S3P{Su#K{(Nq~q?$&vXI*aw0*o z|MiKoL0=0S2xwGPVr65>C(h?iBypj*xa7aMp9A?=_c?10a2rnU&j2FKxnJ=1+DHHY zq7;nTSRidf_M#QS6NN0wH?t~X^q>p&VM7rx{LjP^)OF<9n@LuhRaK}sbDZdwB|OzL zI|IMw&88A4`pWlQdt~SYEe|Q2hZFBHV0vs8`MEgq3P~!MtX=Ou2%F-luq|>!j;h&N0x6d*v0Q zT7??v)=`-kQv36IjAlm0ao9ufeCOyb>)z0GkmU z8?)6aem)Y3%vq3sT0Ma{{l!0JsVaC_?4#2m`ZblL;@4NNmd)JmrDO$L-`mvkbr<3p zh&8EdYwl7rYlxXT)}T`6Rc!(`ii*IOtKRG`NkqMvU0+7k93DC3j6;VVTe~25#!Hsx z$t`I7nrFtGR@{=xhb6iAjtln&tM7gL3iwX{9*_F(*iappf6iL}H`$|J1_|1zUfQXh zE_GpRY_1OS+^vZY*e0l z)n#)A^<_2K%Extb(PWHz?9^6tLhQW;PO-Fz;E8(y;%ra0UtlUp-~oYLbL_^5>_}}~ zWJzfm#Bvs^)Oz5GLGu0`kE;Znh1_-0~L+{+^&9SaR=q~yC_@lT@J%HFlGj$?>{CVh?L6oi@-j=H`I1mE~CyweJaLdV0?;@d-LnSzg-ZpXF zNtkY1Fy^EIq?9~5X({Xy^JuE>?NO5DIU|f;dW}&ag9TXLEEs0S#s)1Mz0-0(qV%~0 zf!`*gABo>G{#sKozOn&$=hjd9SVW9^n)c~IP1xC>rR7-pcQ4_i+!yb5a%v}A=|QVj z%i95KCOT13e`_vPb(vU&X#HjXZ$Vpw!#>}(;GoRNtyF~}?J^vpDD|-9JinGFer6EtCJQDsf3_+O=+1Vp-ZMAVz|pp-TPy9PCvHZk zVWgjCLM*g7WEGd^8v^)ofzGNb%Tg3e+$rU1iDIrrjeNWnEGP&GMnLEi<)pJlDhV9? zxjQzPgdwyZ!P#MJ5>Il~E-9?_ebiUpfY93-$6!sy8H!+01?+6c4-=oT@C6-iW;en& z$)usTQbS7Gq0ydcq*YOoqK0Q?#xnfgwJOp`wcU2F@vh|^Gb3}f6bdu8!f6`NQ+dUZ zXKGO8`O_ogH=iC6;0Tb!XR6~yl%w(*thc3m8wSu>3s-ymO#{(7G?ntN-yiWJye9h% z`oo6nykM5iS^bi(?RauI$*dw!mv^kBY|vE9eys@eZmMR2{+5^HmUU)oAa8y$#=P@# zrKL(c`f4BS-CB}e@a9c5JqGKw^e}&9K-HSJ(Tzw-FK4mqG6(OMboGK@jv!c4C^Zfv zQ&X>7>M%FJ<=mL#JycFVzR@JETDD{^8qjoYct*{$z)kN=E9?}YFTQIzV}n!b?TZ`2 zVJ+Z#ZS~uvBn!ZAd4a}qNs3*8gJyV#&NkDSWMmxqfPCww3(+JguCp%>gK8)OzmFzX z((+s5QguuTr}U?)^kt04E^y2^vBEwp>I7zv=lpXTk$(Z+n*a51+E8+#vJ-;kj)pc7P5^49XJPN{EV zjn4SlgaOdpyxm(YLi?hvVkE@rzEF5*&}>AkLJXd;E8wIwZ3!}6oVNmbW`^i`rbmi( zY)u#xiXI+Nsh%;{XbJsJFj}|5=o*wbj;C~Wal-_YpBSzO+yAH80)`l$rB-Y}x4VJ_Amc;rzA@CVfTCW889U#y2c1s=N^g{fla_7}Wvz_V}o|r4zk5*aX&(C zwmfKfqy#kr8wB5yswtGfuNS*AsG5tMMF^ORFO4axrcrptCZ^ar>w8ScM0pxqP{cHl zwx|eHNT8mwg(1p~nu7D)1zT=#OJZ`uWp{QTq*5}2yEgZ@8Z&iM%fE}ZF*bg3bvVJC z;w{y19&7!zmoI52`e0y+UpT(D_mjMj@(30m78L<0ICdD9*b&1MZ+3O>hh#tyNxn z1E`Mc_GvGwjb-n90r8#k${ zJnzCUo&HE`@mxUq<10G!vf}$P)%cw=fI2wJzifPoc`J*t6mBl|Z5_`>_fBX<1j7 zgMmp$j9?l0&=H%bm@!@B`%}iZLQ)@ipA;WGUu?(NpoyKU6ecwpH4yMJ^?Svlu(BF% z%v?1WMsjGvsI4s(;sV6B5#%M(-##S~I=E_F3N+E0AfT_b%g*sa2bk>Va=C8oSqNKgoD6f3>j z)@FO0%6;#tJm0&a|MXR`Qp9I!;dY2a1_9g4dnw7r++=Y6{hIudC^c|-Xyy~LUw%!p zN9u?|M}4PoPj}1Z&=UxwMKO8H^6d7usp8&Ckx2V@ z91<&M26EgvPJOF)WnB#1u;=3`#|81vdImpmwv#T&ruyVGr(+440HMHrD*rHJdW!5od!@aLfWcKiR~JKy-YLWo`i?S+)~6_LW#`+#8S8b?lEupdUR(84C_9d@*{ zgYExe@4f??%GL$Yqo~*bMMXMF5v2-Jl&T^iBB1mZzzIEs76J+e6ow|fD;<%ZgqqNs zNa!6BNa!dfbfjn~zCCmA8J#(2=AK*Leed4Of7|TDUD#{wz1RA_?-!-Kee5AiK=>=X z0c|6h4*RCblZ9mGnFP|I0z|7Fd%hQCecD~0_P`yD%(Oc)BCS?x3s%>Q7f$42@Oz66 z!WXbA)ea*=NA`rz z@UMDC3m^v>RFnNJq;)nnKR8$tKMYBlc%ZOI7jxB;HnRhrjU{dwg4qb7K5=n11$3Ml ztoM^uuDQy6xlNh3llkINSJd4^=}flGB)D!3s{1l8Kdp0yKC>v!DC@H?m-YO)p2bHa zP8 z)<$mBiKnKzvUs6gUvZF_b;DrX{hPv-_4R~e9LA@ejirZ7bPGM(w=1&nV17D#tF**p z8IF+R#p{g7R$C8)aM_e42qb^$=%6%C=Tz`Qyh*kN%sDU4a~++|Ue!-LNeLjz+Z2H*#^SmbBhJV z=C-Mk4jnAZG5h(toV42_4vsajv+VLxnOn4;eR*MNB{z~0vSdw1fWd-MAb^dR5g5dW)R7XMr4`4rK{@p{K^x=}9Hk_DiC>Gd9QMgB$;u9tFL zlb+`lv=jqFO`ZY}cSZ&^^`G}>WVU_kyyR}3K3!3jK)}}Xgu@-^ZTstgu6h<;q`~U3 z4=e6G-y_soREqB~=A0L+sxy#UDHUBNou8+@k(JO!r-|ptngo5>D2kD~C^T%p`DC$* z1vda>M^v#-?tm_rQ2Fw>8GV&Im1$`V#rIw`g}~$Wwg;`qzKO;pOAScE1c9;rzG(JI z$vv}q$$oV@AXQU_6XXdkdRN>%%d#yo*-aPZwr;V|##PE!x2PSsoG~EkF{9@O(;S+w zY~w%w$>27++N>1n#+?VfS9z*zdE`V8@xtPM&7hO$>)jARSS%#SN=W~s>9p}};pgCq zp}iASJ8t1)gLVp;69%)=ZHnz;Cbra-WYFhGK7sQYCZ*f`y2tl29a zn7_Q4A@nxdirNTf)b7MY+P<|}OU%8p((8|(p>$q9RYflKHs2`FN<7M&%^o{w0F9HV zy5>glC33Lr1%%e`Un|-#a1C+4sH^rfkl2qW&Xn|f=ivtk)mUr*m0RJVk74nX)?JbP zxB${%R~w}_`PFFI#Go!_h_Vj#QcMgo#Sy^XMmw@JvPRSh<-&7ZPg4S!slFh0Q~df} zkdnl9>XfM+IT>`0Yz6WOqhvk{N1uQrhA0H2tRJFsIx{D;slS!`%LL_j3bIu1UxA;u z=kb46Gn_xpdPC+L)zmmpI8Aq?dsb!BJ4p3D!{27g|2EYL+{FK7>ij?XLFVbdl~x~= z_-%0@tj+3o5A7(1AFG|7CA6w{|IUvqs{K)%rh#7r0!i*COtcFg;e<6D5l`&|KcnT4 z=bO%og?S{djcZ@a9+1Rz$*02~v6eK2rDmb?IeY zwcyJP29*|`F@bQ;SJYK%X*r}02(}j!7jrQz3C*6SrpKQ>UB-D$(c=a4i#(oS6QRw{ z*f>@jq_GWT3Cvzx0;&q(9J%)IY_fi`VE!nv%nMt zvf4jRqM-|%aO#Z(rURyC!iI~O%n4;QdqhF$mWtITI}Qud!^R`Qz}OHe0WY(GvFx=< z4^8g6RNu?ximu=H@V4`xEAlGZJe_Ud*a*cF8=atpR|{ZcJqf>;9qB-^Q2OlB-2j^R zly)n##~G}Poz2;oLlBO&{UEGkK0)5k3KfTm#*pmeQjFQg8s^HGE~f;a@D$jnQMnmq zjIHcgU{F$DOyo>=9kKVf&}yg7qlMZ_8Icn)K53I`NQnUG*(&>t%rq!^V;mTqeel~A z_*;0;e?&XI1l(YL&kX)oeGnt|H!xji;J3y9tet+k-AtGDwOd6uDzV~{+|m;+*9i8v z((D^zlu*rx(`S@_W=!tnp17Bm&B>bIYgrE-emz^UI5v_bBRVuOTb!{{!t%z6u7^gm z74(m>b-PNi90(7B`eggytFb4jWZ4BA>3}%SKZ{bi8vF03iWTQ|EczooS272Jjg6Uk z(NW{N&0ou;Z!MRK09VY*cqy3C*3gm2WmLnG^wTo|k7v$*#_s*p+1T7%dVP~ECB1e_ z+gNxb2My3))S*EL(n}{A&s(V(89M78X91g`eoB3YN+^`4${NN2XFz$#9m%;;P(S!l zgq49rH#0Jn@M6~VO1oE)<*+WHBs-2^oR@_qS!YAg)mjknf<$sCN2zQym$=r%<>*-9-&B;q%)h8yxEibyur^F3_S@m<23$54`isp^h~@`BvmQ+w8w zDin=P-+R}7KWmw+so8J2qAQl+ z6<9sODJU&8EV7-5D@q@`ez-VYT>{+KcFi1}m%wbyng%htbZAxk-m>k)$6StP^N7Vrb|M!n}n%ne~FWVzTCLAzlyx{ zUo_jmdVZ5_dpPCB;@bqr;;binZR(aW2INt4#UdgxwRG4^z5eU23ag+)_1ifd(~F_lw~L`LJ!N(cZ=0ZMSB@1agrb{oOV2lYdh+{=W% ze2w+^h&Q?_6e-cl&m==_ zeJ@v2mqhkSd)-TfxJ^5?jJ0zb`=$G!8U`!S91W!})7jGK^OG+bG`~tY>XkxlBAm=Z zy)9#@QTJ;!-#&ZQwP1PQG}D{f%psI6l(24JMw30NZN#Z$hO{u6F@}X6o|X5PN0l9F z47MMk7g{Tw9FPw40$=SeIgGrBjnh}V=Iq&NUtZY{6OutpP>p6MKMX7h@2PZO83!?!l5mOUAM>b&Bvi#m)36uKfzbim^6UU z_%`AaFo3F>-ZShwc9v#vKSqo_!VWevD>s(7gxRDvhuIISr9d1eKFb*AF=fUaQi9D7 zE?UiAWODE^SvT?GNmH<%LhsxB;6nTbQu+9QXm@d?T&(>N&B*Efg5)9^(~#{FHPkfiaxwP(<>XR{cie`u9s4L zA6aqO*tonf%E+E??$&tqh20Q47sy6|!r>hlZIe(W>+rSNqeXrmu(JuTq=fL2!Fd zBUM^#$zJxKGHyTN~IQvW}27y0LY@~Cb9rTgYQ5E&b) z{loJ8#VpI;1t|X^zUFz%UkBI#2YfyVeY&{*&bI6sMb%xrR7CIel$W%vzEo}<`=(d| zLJ?vzO}?mms7lsgo?=Jo`1f8c=>(W#Lp}3(iSDPB{uKC&*=l*bXornk)Wj3TKf7jj z*5+HxEjvf>HP}Nup7~Cm8YxG32cG%KF4Y;7IIXQMot9JK%Wr$)vP%Ou|uxwT1P~ z6x7qgv-4$-KB{;O`F_dYfi|~NNbz@WW@l59m8%5NWIOn_POq_D3Cte%0ozznCV3_8 z79ps39BJsL3tyc7gu#<@QP|;m;zGgsgds|&HCP2j&(jjhqMMBX&1+;;VvYK>lV-*` zf`^~iQg2&`H9*R4CwDE%9==hjLA{1L zJV=dgTh71iB4cPXIAJLI)2e>N+*_oFKyzl5U2b|TR@J}sHUs>g@;!$8M0}_Za1Ap2 zpKEmQ{_?5x|K9WNUq6TcUmKtLbI9P=>*oK`sKy^}&wtl&4!Vxtos$1uU5A!q{xi7l zD{>$VNeWv++PcyggHOoZ@hjMB`$qMvY^MMeSH8R4AYRw`co$|*fG$azQLA?*iR zaK&8;hH%3pOxeoIRJpNSYb@@_N$L|md!2M+OK=uMy~NqPln6K*_(={8#aG+3*&&?0 zNOUH93+D|WfF$p2!Es}6gU#noK*2Fr0W+J=SG5v3?X4*?-b-ab=9}5~#e%JHv3R0v zn@(0UiFrS4d>b#4iWZ5jtMt$$l=s{{U9VAI#MqN}9i#4DDHP!5^6GAf!N9xji6A^E!7tK2x$ zEEd%3HtF;c;<*p^-1g^p6>3C4b(P-qD~~q%Hu`%1^1~C!cY|3ta6?-uY{aoUU(QHq zZQwPOK8>CMm+=nWn<_-)7SeiW(70BG%gY8zXFh;~lC_OY3~i`X_s;EjTj~ISU}%UK z0T^8@m-b8E)Lvk;)^4=zu&4>&@Yhx*u241S;35e03O1a9jD>aSz2B%9yD1T|*S<%F z>A8p%BA>!s<^n_Q9k+9?40VrkI;lR`1Wx_3sls0QK#hsQPJB3ENlFNX?DcLR!QR+b z8DSVa_{PEc_#bwC$mSP?aW7aY>B+6+Lkw1@e!@kk-TU==zb}#Ts7L+|txm=7vP^*) zxgSE*vgv9cKsMrrt`%bZmWp2c5{)mFFrwWVKi9CAOWe5jHS`1b6}-QE@BFfmBlXwr z&Hj46A2=*qecd=ICnuXIDlQFw*}M1p5@f{Ww4dhGXZM`utqR(d1C1<&jbtaKZioPR zy{TV$y?=1*;=gNNbiCSkUA%khc4xdlM*W-L=8(`%A}=||gD;*-k2dUoyfbEblbQC+ zRVS9@Q@5m3yNo!k%J#T{Iy7H-YQM{T&Up#vqWArPM5!CVh+53Y-@HJ9Z&ZKs{j*V9 zwI$k#WYNWusUcRP@f9{rc+pl~_5LU0e|#L&0@~KU=zc(LivooTz3+M%?{~`Y?)yXq zyZr8DwO<*)qGqhPr|K$EW$!C3dZcINtbzx>!`?5yeq!+?B+0DUVp^J5BRQ}pDCCCo zUuIbKyuZx&>b{@&9HgkzD@CS}pM(kBs6SLK?zy2Sx*+iwq~S9oisEs;beBt&;n(;= zV3O$%aqpL`Ev4vB?v~MZHly(6bob4L6(Wzm_BIp*n~LD9R@uvXU{flrwSBE$mN<`0 zvf}GM--&hQYpsmR-l9j=ZS%1Lo&}K1T@!@xT@cx8{iP_IwfD+TvYhyEVweKCebIp@ zckg$r%*-i3u8|9X$T5%a48_xIW^Cn$Q;K(3gZRCFziLPxsOUM8ii>;Hlk%AqN2bV8WR34T6hm~I4 zziz(>K-`!BsKv#pwqVWnBg{xAE0^xpGV0KmH+cNR>&Ao4s3_KhkH*sjL_ z#X)<0jTQbvvVN9eZX36fyPUgYB|g%BoT;aZruD9#UEpW?cllNzPtNf0&@w`MSs$u9 z3Lnu-oV|Jc3aeqC&NnJc`1o#N6L1hJzwFnAkv_-w{XD*ZQ2X{`3Eu0C7l8u@4!*|r z(ca{DbPx19?61K4Q<&60vi@p*K>Pk^{gvqb)ZgIh-Xq_Ji zMq#t2YqJ@zJ9rV2f~l@6!1-x@y3jOXoXZn!w8LT4$69(=^<2l-@FNWGV)nl`yB`G2 z2+Va=&41i*1hkL*$&aG`>PJVDy>|=DHgkYstY-_Vo3+KGA8y{n`CR(&CG}|H_f_-t z%bBhUbIlas^4PHr!w3}W1}@O0CyuBzbQvP(DWdymg?%CzWyeC8j=QO5VtRb-XxCl4 zsA%0sM8sIUsNG!l`iGz{hyrJq2ZAG zLXco{=;cO#pQp>wt3wO4p`JtA=Xk50UQP>#X)b473x?%8vl^_oLewK9eI`zMc6%Rb z&Kbb3cyizvm%+)UG$&~LN8c^8y-&POwls|p78)Ty*b2qz##`?c9D6^9`Jjhe%8_Vj zsthaFs6B){?FkgF5(^>X3iA=w&Q|U{dL2TS7 zlLTPw;4zT==hB;+{`k_%Y}YkDLpsxZgtl5<+*2N{OY-E(41a{YS*o{v$LIE0-X`DA zRdHE+>86pOfETVT3~E&JD`!tWe4qPbC&>cyA?g++cvtp;bHF1WpB0#II2#7nP0tXp zrcJZS0s(Vu#Raqs6rM41i#*x~{wkI=f-QF#TJ79V`FvK)cv_TSxE{HDXvOB~qflLh`UihvQ(XlJ$JYMK@uYY|RtBygYdg5UJ8LCoX9|73F_$EQ=x^tO|BpI$C*# zOZ*|(-Eq6x(Z<1_i%;(h`(rJo2L&^4_8xz|F!-+vXHQy0sdD{!GLQ|z{2Nt7W%&Mu zs{QnKYmTAje6v*`%Q5#9>jKTL-+=cjYJ8JUkK}Yghi~_S_a?38;YlEx+e}3b&vDJ8 zvB}zFx=F<3Y3BQQl|Out4SXPQWp}?MGCHa&VbLT1y%X49$?;j`dmIUaM&mrx57j#e zxi_k-Eref4jqQJf*aGQ+zNA#2j(cQqv{2G#YD=zD#&zU<|7_X|@Lr1T2@esx75vm9 zs%i-~($0cAw(k?)tBaCMb?k!$I`V9tIqd-K5Nu$hL)MezB{Qx@oZpH(n#ipG&N6#= z(RM9mK@ni|BBYN<%NMQzyDuO^01jcgN%+Fwf1qA^@sMn6_r^In>E|wDK#w`|DP6sO zq(QdaOE-DbwOh@0tq!77IP99t@5#yi7gL^et{T$ttfDlnZL8u>U*z!*3 zp~lhWR9Xo>w5*<&iYB8)9Utcn?h^zmG1fZ;&_v}P6Crdbn)I&t^z$Ra=QpkudzEi2 zKHOOqfiw+m*7jpIWXnZUa%pqpr6-rBJy{fvIDT!bH#06=PmCdmVt$I$&$W5#40)|I z_WG=Gcugml#A1oy+)b<_q_|*%ZNc8^ri8yJAprZnkAKX1fNx|9X}LjhakxcWOBCa( ziPtf%@UMGxxEIVZsuV`!bk%9@!eDY8$OCHFF;Ad*9J3eVDOkb@cN;on>3}q~ciyIj zKoSe2nfm7q<1Ab|)Rx^Apjl-@bB9f4d>+y=N+50xjxXHEu?W|;ZLywHbATB!*G%*; z@uH|Go_DKW2{hsIS;`pN42VQfhdA`ynLrlSaV7SR#f4w4z`Z9W?zhQ5c`tFO?0a}P znmo-z{M54?Jn-}9fM}rTuW5*KMkm8p&FHje{08G)!$8#~{i`Vt;-o%fy>;ti+qfzU zqf{?t)tai!(GF2pz-CKWHv)J1+#oFLr#K7<$D|ur@3^YWYI+})aTZezC)shXe@ z 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

;G8MKTcFZ_+c|!a`9BI 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

YXhPv-4YY-=`z|df+zUK>n^pm0HmzBh% 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

KhazHoNe! z7PXay<(jRm3X2ugU&1QL?>UyRD)M{4V8?)M1-DSNW(7Hjb=ZD{20+{{+!}3iur9{q zM!=!1a}@#!FWCGFFf<224kn>Bc2W$lfhi`U`9?7Xt)(cY+UAES>Bsbzu>=goCMYWr z6#sM#-S;VmoeLGn_!mP;(-K{70(60Y~ukKeVq#Ghh&Qfuz*4L z8LErQV?PDgpa=NY`XFmL_DN{LJif`eAJU)4b93Oqfr`* message to the message processor. + +For credential provider plugins, <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> is +guaranteed to be the first message it receives. + +The callback function should return KHM_ERROR_SUCCESS if it +initializes properly or some other value otherwise. If the return +value signals an error, then the plugin is assume to not be loaded and +immediately unregistered. + +The message processor is automatically subscribed to the following +message types: +- ::KMSG_SYSTEM +- ::KMSG_KCDB + +Although a plugin can use the <::KMSG_SYSTEM,::KMSG_SYSTEM_INIT> +message enumerate existing credentials in the system, it should not +obtain new credentials. This is because other plugins that may depend +on the new credential messages may not be loaded at this time. See the +section on \ref cred_msgs for more information. + + +\subsection pi_pt_cred_exit Uninitialization + +When the plugin is to be removed, the module manager sends a +<::KMSG_SYSTEM,::KMSG_SYSTEM_EXIT> to the message processor. The +plugin must perform any necessary shutdown operations, free up +resources and unsubscribe from any messages that it has subscribed to. + +This message is guaranteed to be the last message received by a +credentials manager plugin if the plugin unsubsribes from all +additional message classes that it subsribed to. + +The message types that the message processor is automatically +subscribed to (See \ref pi_pt_cred_init) do not have to be +unsubscribed from as they are automatically removed. + +\subsection pi_pt_cred_other Other Notes + +Since credential managers may receive privileged information, the +signature requirements for credential managers are specially strict. + +\section pi_pt_conf Configuration Provider + +Provides configuration information. +[TODO: fill in] + +\subsection pi_pt_conf_comm Communication +[TODO: fill in] + +\subsection pi_pt_conf_init Initialization +[TODO: fill in] + +\subsection pi_pt_conf_exit Uninitialization +[TODO: fill in] + +\subsection pi_pt_conf_other Other Notes + +*/ + diff --git a/mechglue/src/windows/identity/doc/plugin_structure.h b/mechglue/src/windows/identity/doc/plugin_structure.h new file mode 100644 index 000000000..b41ff3a07 --- /dev/null +++ b/mechglue/src/windows/identity/doc/plugin_structure.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! + +\page pi_structure Structure of a module + +A NetIDMgr module is essentially a dynamically loadable library with a +specific set of exported symbols. Each export symbol and general +notes about writing a plugin module are documented below. + +\section pi_str_init Initialization + +Do not use DllMain or other system specific callback routines to +perform intilization tasks other than creating mutexes, initializing +thread local storage and other tasks that must be performed at that +stage. Specifically, do not call any NetIDMgr API functions from +within DllMain. + +\section pi_str_cb Callbacks + +The callbacks that must be implemented by a module are: + +- init_module() +- exit_module() + + */ diff --git a/mechglue/src/windows/identity/doc/stylesheet.css b/mechglue/src/windows/identity/doc/stylesheet.css new file mode 100644 index 000000000..fc3e0624d --- /dev/null +++ b/mechglue/src/windows/identity/doc/stylesheet.css @@ -0,0 +1,271 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +H1 { + text-align: center; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #000000; + border: 1px solid #000000; + margin: 2px; + padding: 2px; + line-height: 100%; + color: #ffffff +} +DIV.nav { + width: 100%; + background-color: #000000; + border: 1px solid #000000; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 100%; + color: #ffffff; +} +A.qindex { + text-decoration: none; + color: #ffffff; +} +A.qindex:visited { + text-decoration: none; + color: #ffffff; +} +A.qindex:hover { + text-decoration: none; + background-color: #ffffff; + color: #000000 +} +A.qindexHL { + text-decoration: none; + font-weight: bold; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #333333; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #333333; color: #ffffff } +A.el { text-decoration: none; } +A.elRef { } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #cccccc } +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } +TD.md { background-color: #cccccc; font-weight: bold; } +TD.mdname1 { background-color: #cccccc; font-weight: bold; color: #000000; } +TD.mdname { background-color: #cccccc; font-weight: bold; color: #000000; width: 600px; } +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 14px } +BODY { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #cccccc; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #cccccc; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdTable { + border: 1px solid #cccccc; + background-color: #cccccc; +} +.mdRow { + padding: 8px 10px; +} +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 12px; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 12px; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 12px; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 13px; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 12px; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 13px; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 12px; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #ffcc99; +} +TD.tiny { font-size: 75%; +} +a { + color: #0000ff; +} +a:visited { + color: #0000ff; +} +.anchor { + color: #000000; +} \ No newline at end of file diff --git a/mechglue/src/windows/identity/doc/ui_actions.h b/mechglue/src/windows/identity/doc/ui_actions.h new file mode 100644 index 000000000..de4e802e3 --- /dev/null +++ b/mechglue/src/windows/identity/doc/ui_actions.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page khui_actions Actions + + */ diff --git a/mechglue/src/windows/identity/doc/ui_context.h b/mechglue/src/windows/identity/doc/ui_context.h new file mode 100644 index 000000000..b9bfadd6b --- /dev/null +++ b/mechglue/src/windows/identity/doc/ui_context.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page khui_context Contexts + + \section khui_context_contents Contents + + - \ref khui_context_intro "Introduction" + - \subpage khui_context_using + + \section khui_context_intro Introduction + + Several ::KMSG_CRED messages and many messages depend on the + selections that the user has made on the user interface. The UI + context functions and data structures provide access to this + information. + + The NetIDMgr user interface presents an outline view of all the + credentials that were provided by credentials providers. This + view consists of headers representing the outline levels and rows + representing individual credentials. + + Users can make multiple selections of credentials or headers from + this view. If all the credentials and subheaders under a + particular outline level are selected, then the header itself is + automatically selected. There may be multiple disjointed + selections of headers and credentials. + + In addition, the current cursor position also acts as a selector. + The credential or header under the cursor may not actually be + selected. The cursor is not the mouse pointer, but the focus + rectangle that may be moved either using the keyboard or by + clicking on a credential or header. + + Thus there are two independent groups of selections: + + - Credentials and headers which are in a selected state at some + specific point in time (the current selection). + + - The current credential or selection which the cursor is on (the + cursor selection). + + There are a few notes on how credentials are selected: + + - An "empty" header (a header that does not contain any credential + rows) does not appear in a UI context. However they can appear + as the current cursor context. + + - At its current implementation, cursor selections of identity, + credential type, and individual credentials are treated as + special cases since they are the most common. + + How the UI context is used when processing a specific action or + message depends on the action or message. If an action operates + on a group of credentials, then the current selection may be used, + and on the other hand if an action or message relates to just one + credential, identity or credential type is invoked, then the + cursor selection is invoked. + + For example, double-clicking a credential, or right clicking and + selecting 'Properties' from the context menu launches the property + window for a credential. This operates on the cursor selection + since that reflects where the user double clicked. However, + choosing 'Destroy' from the context menu invokes a command that + can be applied to a group of credential, and hence uses the + current selection. + + Next: \ref khui_context_using "Using Contexts" + */ + +/*! \page khui_context_using Using Contexts + + \section khui_context_using_1 Obtaining the context + + Typically, messages sent by actions that rely on UI context will + obtain and store the context in a location that is accessible to + the handlers of the message. + + If a plugin needs to obtain the UI context, it should do so by + calling khui_context_get() and passing in a pointer to a + ::khui_action_context structure. + + Once obtained, the contents of the ::khui_action_context structure + should be considered read-only. When the plugin is done with the + structure, it should call ::khui_context_release(). This cleans + up any additional memory allocated for storing the context as well + as releasing all the objects that were referenced from the + context. + + \section khui_context_sel_ctx Selection context + + The selection context is specified in the ::khui_action_context + structure in the \a sel_creds and \a n_sel_creds fields. These + combined provide an array of handles to credentials which are + selected. + + \note If \a n_sel_creds is zero, then \a sel_creds may be NULL. + + \section khui_context_cur_ctx Cursor context + + The scope of the cursor context is specified in the \a scope field + of the ::khui_action_context strucutre. The scope can be one of: + + - ::KHUI_SCOPE_NONE + - ::KHUI_SCOPE_IDENT + - ::KHUI_SCOPE_CREDTYPE + - ::KHUI_SCOPE_GROUP + - ::KHUI_SCOPE_CRED + + Depending on the scope, several other members of the strucre may + also be set. + + In general, the cursor context can be a single credential or an + entire outline level. Unlike the selection context, since this + specifies a single point of selection it can not be disjointed. + + The contents of the \a identity, \a cred_type, \a cred, \a headers + and \a n_headers are described in the documentation of each of the + scope values above. + + \subsection khui_context_sel_ctx_grp KHUI_SCOPE_GROUP + + The ::KHUI_SCOPE_GROUP scope is the generic scope which describes + a cursor selection that can not be simplified into any other + scope. + + In this case, the selection is described by an array of + ::khui_header elements each of which specify a criterion for + narrowing down the selection of credentials. The ::khui_header + structure specifies an attribute in the \a attr_id field and a + value in the \a data and \a cb_data fields. The credentials that + are selected are those in the root credential set whose repective + attributes contain the values specified in each of the + ::khui_header elements. + + For example, the following selection: + + \image html credview-select-outline.jpg + + will result in the following header specification: + + \code + ctx.n_headers = 3; + + ctx.headers[0].attr_id = KCDB_ATTR_LOCATION; + ctx.headers[0].data = L"grailauth@KHMTEST"; + ctx.headers[0].cb_data = sizeof(L"grailauth@KHMTEST"); + + ctx.headers[1].attr_id = KCDB_ATTR_ID; + ctx.headers[1].data = &handle_to_identity; + ctx.headers[1].cb_data = sizeof(khm_handle); + + ctx.headers[2].attr_id = KCDB_ATTR_TYPE; + ctx.headers[2].data = &kerberos_5_credtype; + ctx.headers[2].cb_data = sizeof(khm_int32); + \endcode + + \note The attribute that is used to specify the header is not the + display attribute, but the canonical attribute. For example, + in the above, the second header was actually + KCDB_ATTR_ID_NAME. But KCDB_ATTR_ID was used since that is + the canonical source for KCDB_ATTR_ID_NAME. See ::kcdb_attrib + for more information on canonical attributes. +*/ diff --git a/mechglue/src/windows/identity/doc/ui_main.h b/mechglue/src/windows/identity/doc/ui_main.h new file mode 100644 index 000000000..8cf735c04 --- /dev/null +++ b/mechglue/src/windows/identity/doc/ui_main.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page khui User Interface Topics + + \section khui_contents Contents + + - \subpage khui_actions + - \subpage khui_menus + - \subpage khui_context + */ diff --git a/mechglue/src/windows/identity/doc/ui_menus.h b/mechglue/src/windows/identity/doc/ui_menus.h new file mode 100644 index 000000000..09cc16e67 --- /dev/null +++ b/mechglue/src/windows/identity/doc/ui_menus.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/*! \page khui_menus Menus + + */ diff --git a/mechglue/src/windows/identity/help/Index.hhk b/mechglue/src/windows/identity/help/Index.hhk new file mode 100644 index 000000000..2e24f6f3e --- /dev/null +++ b/mechglue/src/windows/identity/help/Index.hhk @@ -0,0 +1,9 @@ + + + + + + +

+ diff --git a/mechglue/src/windows/identity/help/Makefile b/mechglue/src/windows/identity/help/Makefile new file mode 100644 index 000000000..c45a83f80 --- /dev/null +++ b/mechglue/src/windows/identity/help/Makefile @@ -0,0 +1,36 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=help +!include <..\config\Makefile.w32> + +CHMFILE=$(BINDIR)\netidmgr.chm + +INCFILES=$(INCDIR)\khhelp.h + +all: mkdirs $(CHMFILE) $(INCFILES) + +$(CHMFILE): netidmgr.hhp + -hhc netidmgr.hhp + $(CP) netidmgr.chm $(CHMFILE) diff --git a/mechglue/src/windows/identity/help/html/about_netidmgr.htm b/mechglue/src/windows/identity/help/html/about_netidmgr.htm new file mode 100644 index 000000000..d6fec057b --- /dev/null +++ b/mechglue/src/windows/identity/help/html/about_netidmgr.htm @@ -0,0 +1,68 @@ + + + About Network Identity Manager + + + + + + +

About Network Identity Manager

+ +

+This is strictly an informative page about the origins of Network +Identity Manager. +

+ +

In the beginning

+ +

+Network Identity Manager was conceived as an identity management +solution to make up for the shortcomings of Leash32 (distributed with +MIT Kerberos for Windows) and AFSCreds (distributed with OpenAFS). +

+ +

+The work started as Unified Credentials Manager, a final project for +the MIT course 6.831 : User Interface Design and Implementation, +taught by Professor Rob +Miller. By the time actual code was written, it was named +Khimaira (which was later changed to Network Identity Manager around +October, 2005). Traces of the name Khimaira might still exist in the +source code. +

+ +

+Khimaira was presented at the AFS and Kerberos Best Practices +Workshop 2005. The slides can be found on the workshop website and here. +

+ +

+The work on Network Identity Manager was supported by MIT Information Services and +Technology, NASA Jet Propulsion Laboratory, +and Secure Endpoints Inc.. +

+ +

Design

+ +

+A plugin based architecture was chosen so that support for additional +credential types and features could be added without making changes to +the mainline code. In addition to making the application easily +extensible, this also allows the AFS plugin to be maintained within +the OpenAFS code base and separates the code supporting Kerberos 5 and +Kerberos 4. Furthermore, it is anticipated that this would encourage +third party developers to develop plugins for NetIDMgr. +

+ +

+More information about the concepts used in the design of Network +Identity Manager can be found here. +

+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/act_chpw.htm b/mechglue/src/windows/identity/help/html/act_chpw.htm new file mode 100644 index 000000000..40f97054a --- /dev/null +++ b/mechglue/src/windows/identity/help/html/act_chpw.htm @@ -0,0 +1,30 @@ + + + Change Password + + + + + + +

Change Password

+ +

The change password dialog can be invoked from the Credentials menu. This is used to +change the password for the primary credentials provider (currently +Kerberos 5). +

+ +

For the default identity provider (Kerberos 5), there are two input +boxes to specify the identity for which the password is to be changed. +The identity uniquely maps to the Kerberos principal of the same name. +Then the current password must be entered along with the new password +twice. +

+ +

Note that currently, when the password for an identity is being +changed, only the associated Kerberos 5 password is changed. +

+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/act_destroy_creds.htm b/mechglue/src/windows/identity/help/html/act_destroy_creds.htm new file mode 100644 index 000000000..ff24561e8 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/act_destroy_creds.htm @@ -0,0 +1,33 @@ + + + Destroy Credentials + + + + + + +

Destroy Credentials

+ +

This action will attempt to destroy the credentials that are +currently selected in the credentials window. How the credentials are +destroyed is up to each credentials provider. +

+ +

In some cases, you may need to select all the credentials of a +specific type for the delete operation to succeed. This happens when +the credentials provider does not support deleting individual +credentials, but supports deleting all the credentials stored in one +specific location. +

+ +

The action can be invoked by selecting the credentials and then +pressing the Delete key or by pressing Ctrl + D. You can also select the Delete credentials action from the context menu +(available via right-clicking inside the credentials window) or the +credentials menu. +

+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/act_import_creds.htm b/mechglue/src/windows/identity/help/html/act_import_creds.htm new file mode 100644 index 000000000..550bb39e2 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/act_import_creds.htm @@ -0,0 +1,27 @@ + + + Import Credentials + + + + + + +

Import Credentials

+ +

Allows you to import credentials from the Windows LSA credentials +cache into any of the caches under the control of any credentials +provider. Currently, the only credentials provider that supports +importing is Kerberos 5. +

+ +

This action can be invoked via the Credentials menu or by pressing Ctrl + I. In addition, the Kerberos 5 +configuration pane accessible via the Options menu provides an options that +control how the importing of credentials happen. +

+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/act_new_creds.htm b/mechglue/src/windows/identity/help/html/act_new_creds.htm new file mode 100644 index 000000000..01917ffdc --- /dev/null +++ b/mechglue/src/windows/identity/help/html/act_new_creds.htm @@ -0,0 +1,114 @@ + + + New Credentials + + + + + + +

New Credentials

+ +

The new credentials dialog can be invoked from the Credentials menu, by typing Ctrl + N, using the context menu in the credentials +window or using the context menu in the NetIDMgr icon in the system +notification area. +

+ +

Once invoked, you will be presented with a dialog similar to the +following: +

+ +

+New credentials dialog +

New credentials dialog with a valid identity +selected.

Note that the above screenshot is +from an instance of NetIDMgr with Kerberos 5, Kerberos 4 and OpenAFS +plugins with a Kerberos 5 identity manager. Actual display may be +different depending on the plugins that are active.

+

+ +

If the Kerberos 5 identity provider is used, the dialog will ask +for a username and a realm to determine the identity for which new +credentials will be obtained for. Depending on the selected identity, +you may be required to provide a password or other form of +authentication for new credentials to be obtained. +

+ +

Below the prompts is the credentials summary window. This window +provides an overview of the credentals that will be obtained when the +dialog is completed. +

+ +

Expanded view

+ +

If you click any of the hyperlinks in the credentials summary +window or select the Options >> button, +the dialog will switch to the exanded view. An example of this is +shown below: +

+ +

+ + +

Expanded view of the new credetials dialog

+

+ +

+The expanded view provides access to additional options available for +each credential provider. For example, the Kerberos 5 credentials +provider allows you to set the lifetime of the obtained Kerberos +ticket as well as ticket flags such as renewable or +forwardable. +

+ +

Credentials summary window

+ +

+The credentials summary window provides an overview of the credentials +that will be obtained after the successful completion of the new +credentials dialog. The window contains hyperlinks that will take you +to the corresponding credentials option panels where you will be able +to set additional options for each type. +

+ +

+If there is a problem with the selected identity, the credentials +window will display a message describing the problem. For example: +

+ +

+Credentials summary window showing an invalid identity +

+ +

+The above is an example of what you would see if the provided identity +is invalid. Once the identity provider (in this case, Kerberos 5) +indicates that the identity is invalid, it will be displayed as above +along with a brief description of why the identity was found to be +invalid. Here, the Kerberos 5 identity provider is reporting that the +specified principal does not exist in the Kerberos database. +

+ +

Additional notes

+ +

+The new credentials dialog can be invoked from the command line using +the -i or --kinit + command line option. Additionally, if you specify the -a or --autoinit +command line option, the new credentials dialog will be displayed if +there are no credentials available. +

+ +

+Setting the Prompt for new credentials if there +aren't any at startup option is set in the General configuration panel, then the behavior is +similar to the --autoinit option. +

+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/act_renew_creds.htm b/mechglue/src/windows/identity/help/html/act_renew_creds.htm new file mode 100644 index 000000000..5e39963da --- /dev/null +++ b/mechglue/src/windows/identity/help/html/act_renew_creds.htm @@ -0,0 +1,11 @@ + + + title + + + + + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/act_set_default.htm b/mechglue/src/windows/identity/help/html/act_set_default.htm new file mode 100644 index 000000000..5e39963da --- /dev/null +++ b/mechglue/src/windows/identity/help/html/act_set_default.htm @@ -0,0 +1,11 @@ + + + title + + + + + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/bugs.htm b/mechglue/src/windows/identity/help/html/bugs.htm new file mode 100644 index 000000000..fcc563c9a --- /dev/null +++ b/mechglue/src/windows/identity/help/html/bugs.htm @@ -0,0 +1,34 @@ + + + Reporting Bugs + + + + + + +

Reporting Bugs

+ +

If you encounter a bug in the software, please email +kfw-bugs@MIT.EDU +and report it. Please include as much information as possible to +enable us to reproduce the problem. +

+ +

kerberos@MIT.EDU +is a mailing list set up for discussing Kerberos issues. It is +gatewayed to the Usenet newsgroup 'comp.protocols.kerberos'. If you +prefer to read it via mail, send a subscription request to +kerberos-request@MIT.EDU +or subscribe via the web page:

+ +

+http://mailman.mit.edu/mailman/listinfo/kerberos

+ +

Information about Kerberos mailing lists can be found at http://web.mit.edu/kerberos/mail-lists.html

+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/concept_cred_pro.htm b/mechglue/src/windows/identity/help/html/concept_cred_pro.htm new file mode 100644 index 000000000..5e39963da --- /dev/null +++ b/mechglue/src/windows/identity/help/html/concept_cred_pro.htm @@ -0,0 +1,11 @@ + + + title + + + + + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/concept_ident_pro.htm b/mechglue/src/windows/identity/help/html/concept_ident_pro.htm new file mode 100644 index 000000000..5e39963da --- /dev/null +++ b/mechglue/src/windows/identity/help/html/concept_ident_pro.htm @@ -0,0 +1,11 @@ + + + title + + + + + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/concept_identity.htm b/mechglue/src/windows/identity/help/html/concept_identity.htm new file mode 100644 index 000000000..5e39963da --- /dev/null +++ b/mechglue/src/windows/identity/help/html/concept_identity.htm @@ -0,0 +1,11 @@ + + + title + + + + + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/concepts.htm b/mechglue/src/windows/identity/help/html/concepts.htm new file mode 100644 index 000000000..5e39963da --- /dev/null +++ b/mechglue/src/windows/identity/help/html/concepts.htm @@ -0,0 +1,11 @@ + + + title + + + + + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/copyright.htm b/mechglue/src/windows/identity/help/html/copyright.htm new file mode 100644 index 000000000..32453f740 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/copyright.htm @@ -0,0 +1,48 @@ + + + License + + + + + + +

Network Identity Manager License

+ +

This software is being provided to you, the LICENSEE, by the +Massachusetts Institute of Technology (M.I.T) under the following +license. By obtaining, using and/or copying this software, you agree +that you have read, understood, and will comply with these terms and +conditions:

+ +

Permission to use, copy, modify and distribute this software and its +documentation for any purpose and without fee or royalty is hereby +granted, provided that you agree to comply with the following +copyright notice and statements, including the disclaimer, and that +the same appear on ALL copies of the software and documentation, +including modifications that you make for internal use or for +distribution:

+ +

Copyright 1992-2005 by the Massachusetts Institute of Technology. All +rights reserved.

+ +

THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS +OR WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not +limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF +MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE +OF THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD +PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.

+ +

The name of the Massachusetts Institute of Technology or M.I.T. may +NOT be used in advertising or publicity pertaining to distribution of +the software. Title to copyright in this software and any associated +documentation shall at all times remain with M.I.T., and USER agrees +to preserve same.

+ +

Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira, +OLC, X Window System, and Zephyr are trademarks of the Massachusetts +Institute of Technology (MIT). No commercial use of these trademarks +may be made without prior written permission of MIT.

+ + + diff --git a/mechglue/src/windows/identity/help/html/howdoi.htm b/mechglue/src/windows/identity/help/html/howdoi.htm new file mode 100644 index 000000000..3995335a4 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/howdoi.htm @@ -0,0 +1,37 @@ + + + How do I ... + + + + + + +

How do I ...

+ +

Startup

+ + +

Credentials related actions

+ + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/images/logo.jpg b/mechglue/src/windows/identity/help/html/images/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1121f6416bf6f1d4bd107d84d10c94fe2dfc6ca0 GIT binary patch literal 2014 zcmbW!X;hPE76R zg?*-W2t|(oq(&6hEH#&f(zLJd#CZ+~w9Er9q{*W3O3DNkZ5>^b-hPV%mR1K39dqeSCw0L(ZKK4GWLH7;`B$E98Dc*Xu4TM~4z zT*x%f8y3|GgVWC?DT)JYd#Aquft7iutws=7q+q5NVB zkG3A$yD1L>wO(~)ev*?j5;zD9-@P8FevzCX{4&!z1?&gfmW#S&_{@o(a$ugu0b zCNQ`zS*%*~0cr~fWK6DT&3CLVl<-^8wpb5GU_0?Yx9w9?ZzD)dH`AlP_vaxqmyM`Z zCt0bk=Jk&OBYnRf&!8S|_dxFoZic43TJz?7x9{`Tq!(rV>-V3q)dJ;8B|e+_&PHKc zebqYUta0Awqj5Hqr!riPFADIZBYZmFtC(FhGl}~!yi(aCYha*e<<5UBu$zxq5j_%b z-D)DN$j2y;OrPi5Q^Tuin^4Xf|tFxCR|u4o$KFfm~fj z5a4_*Inhrc3qU|}^tO`Zq1QUa&ga^Hb{99vTu$%EYO>P3@=eL-S<0a@jd0%-cBJX_ z+;LM7h{J4!O=5qw?!YaW82=oPNV(-05*IjIDS9qgh}$?(d%$+h+a^F*m{Hem%$ay! zNH-+#$>$vg(vxwYO~kKcH;q96)!vX<_iaVI2D2!h(W|T0tTlrC?0PHgKr&%QUzAJb zix;zd30o0Q4TD?jTNn#3eAJ80TePw>Lu^VJZ|W!yvI(5{1R`tU#-0JSv)9P%0DoCQ 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

uWr-BG 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�W84a^04r7+! zZJjruCcI~9tdHeC1t?28w6hYtuma3AY>p`|yT5RQdCoG^)D#2OQ+*Pn|0q(2k>n3% zGaEfi3mX=yfq75X3{aQ${J7X>a(=317;Kmhbn*#Whq99=opa7;Du8FfFq-xQ+!SDM`So94k{til{g~AN+l$KW^`*<&;^G5 zeDS77)3F^eg}H=XkQdlxj;aD&)QsjfHWGHT?<3f@G0e7)ZP6$L54i$uQ^3VXi(ldj zxKN;NpEq8LD?kc3e6)~Ayi-CVpmPX5Iv9~Uquay8&Y0N6(q+@pzc@1&*u{Z~U62>1 zj78G~F{Y0(WKFNjppcd;V~Cs0bT=+qrYY~|y16Q^{H0gm`E7*FYks*EP&QlP5w5_m zRlxpt6<-tkQx literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_menu_bar.bmp b/mechglue/src/windows/identity/help/html/images/screen_menu_bar.bmp new file mode 100644 index 0000000000000000000000000000000000000000..947cd10c61eb1e9b3cb5597848d793a1b69941a7 GIT binary patch literal 12374 zcmeHNOLpWo40P_0MV47+nbjO1`)qUToWwKZCaHFoPN52bK&jpFr#+dMNDrpLB1p;Y zdIgZ`-+uq&*E?RH(Efs-Kk@S;etx+73GLn8&pytMH+|{FT3^~2W)8w}>wSc2igy`M zkTyC@v*fp>n~f&ZIzGhUXZ@wMrJY8#ej2N3!HR^hDHb`$tawBs#=wWk`oriC-R#sG z>|rtvP4O{ZVH%?UwKtfSQv0=cn&DwW&?d5REZ|FTX*Dvz$!YBij8i_h2HTGc_qMms zFh+iEr?5mg+S@%%VfU@=>~!B?Tm0$i>8_9rggba9#vD8o)o#bLzs|#K=`=X(p2y>C z3UhE7kFYs_-Trun+0dD0VQHKAr9XywuqH133_H`7abAu1+Fgg1Wtg4K6z|B=7c-7} zYsefEqhl;EO&NWG`E)u&#?omF9lRV7exY5H05qPeKSrn7ba`tG1ElWL(1bIqbi1ZJ zfbIsllq*iA(4G+L^oqM5Vd}cNGnq);BTRbl@?VuZebcjpXHLX}XEU*kMk-O@u!I0_ zguIt$wQiH2qV+aC+b;;j*9f7f{{0sjTo`Kn(1dD)uAkXl3Zg>U+@?$v5I5@gqRiDKq`>oYX(n8O2R62*^ zED<=Wr4q@m9JClx;#15X5snx}zO+8eV6e@6>Y0{8Yo#17`d*e*KPtJ{p=)nG*Jrs} z)@O;p$@)wn_y-4sKyZdh`Gi|>);(qupfI(SPl+SG;@Qo0Fp8vUc)5Foy}mxf%qu*@ zsHgyvt^QQqU)Tp&uCE`{4=W23roS`W?*MPrCqeSd^L^#E}s!`8y zw1Lr@NzoOemO~P%l(gD4pOMz`s6&pm^>T&{yB#=VEk7b`8T`D0M;>C*24OH+=$Uj~ z1Z>l>He#H4aXbM8ToEqPB$8w@gb7YVDM%()Axr!n&?x&Y_}SdsQnu6KR}?kvG-#Gc$tHv*a0ORXwAap&FCy zd0FOQyf(lS>V1H>K^ii~^P|OF!e@E2PjkaFP)e41CY~9X7sqtYw#kwVV*V_d6nDY& zEbz6AxTUhMLs=;|0B;Z@#Z|kg8D#g@wl$@43S{Ze}QMKn8iNe z{d#8X6bnC6&meEN(zBo)G)zYwE@oiH4fRaKm7WF7@Ve7zRP}7nsy(ub8Rou8&#IWg zw`@qerJiYDSsCWEs1n6PTEy@*dA$F&SLQBGj!%f_#TY7_1dKJAUc=jvgS(t4?Tn1c zT*(xfWU6Vjs+XoL=WgbwWoyC>4l$F8Mb=un(?4FV^GUC{+0iXxRPmgjufjc8>#R#p zeDb{Mnk2?tXq8Vr`#u+J_j87cTb@bzr7rtk*Y>q~&7m3%8pT#ri8V;Z+ROHp@x3ey ztNBq2RzzQU5)xm3vTro;J$iZ9B(@zqJ9y@j#&e2;XSUO{j9IGtL(k%Ss)wGHjlz*P kkGvW6I}5c)sj9bFqD|Ep@d-KVGgWC;v3b4!f3DB|2BtCM0{{R3 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_menu_credential.bmp b/mechglue/src/windows/identity/help/html/images/screen_menu_credential.bmp new file mode 100644 index 0000000000000000000000000000000000000000..eecddd21b1688223fa45685573be53e323fa6f10 GIT binary patch literal 129846 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 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_menu_options.bmp b/mechglue/src/windows/identity/help/html/images/screen_menu_options.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4fba5d6d38ed35d7e34a4f38297f03a698dbcd52 GIT binary patch literal 29494 zcmeI2ZF3V<6vyMY@FVyM_yE3l#!un!!Wj|9QK2FfL70&d6&z?SLdO@t=rGz*U_c5q zg$fifEq$P*Pf63XdD_hrQ0VA?_iRp2c9Rg2y_=-nozvyq|2_BVx2HEZTi$(d+pd6l zZNvQ?{Orch`}lb)@HXzata>WYJyw1#EG$e;C539iQ*nzGK%1 zAARgwlLSB#JV6y~1A$ZLe)UZ$fe%0VwEO6>vlsukbo;K!`#=9uMgUK8XV=~%Cr)0t za_v@V!so4wG<6K#ySoqk(0BT;p`nN2S)aGhTQLD|yZ7_k=j|;4Z%6ayyeZ~6CMf4Ero|@PY1mBes%EV>7TC!hab=5|9?YhW~MfTDAGlJmP*#2@wo`c z89*Y(AfRHHvmq(%c~{AsSInGPspdE%ol3Q~9ih9*8*J#ZEghmwsaBMcz#wutTt?=8Zzo@M&H>!IXc40wNe@ZhO4XRhDAGr6$X^!dcSnQhLVeBRzZ zSD&}f+gk$Oj^^jL&)Zu9-j1dqzwzycFItSV$csePYhw_=Jy1Nia`r>P6?GO{=z#aW zLx+0Kp1nRYGPM|K`aCE}IN3C#5F}?0Qm^f|5Hk<$DsKrJBh=5v){xuMG-YkIK6ycH z?x^7nDs&OKQpxz26sE#TjTl=ewjQ{vj&RiQmP;q1q%d6$sG-P)HR8FdBOLX-fdS;` zA|$1f@h?MSkz=SK7b$>?F%WIvDansT)N_&)|LZyYGKFe}4G> z{io4r)8`Y+kuy~t6?HwUU@ZFtZ@~WZ>eYu66LZVUZt#}fEAl&<_wc>@fISn5L=uS( z;jQQ~deANM`)MRPACCieES>gwD`pPf@r)MNEc1E$ycHAhwtM9Fimt6{hOOwjpWlk{ zSKg`i7am{;Qg9nA9yF!DJO{OQP8vu*-Q*E-sFYjgO2?-VS+f!=XvC z;J*{WM~{P#LYT~E=Y1y>np%ubEJVlW79Y8x&AHl4MMg1NZi=-D)^6b2`y>trOBiqNwu)EWWO%wSVb>e)a5OT-RWX_xXaP4 zmBe&pX>0IKX2HGcRmbOz?c?W-iz}KINhD_?G3H%yHk8ej$CQqwAh@IQ8@yo^xne05 zb$3O47qIazZ4TCsVHKK zvdnME7;TMWZsYfm^4rjbXoj`_{+-I_VVEqald;bZbn+WhoISGw2kh}V{d6f_n>U6w zHW2fp6h4rXV*1wSrJ=O@=VjW2oyz5;Vd5y#o%CiD?m>3Q!(lhWaVY#Iylwf-`#1V; zf8K?Hfx*mjzLO&LCKcHgk3tSod?}p?$5xQvoW9n6!r5HDZ=g5YNhr$={5TkzG3N15 z9tMrmBGnpq^YBQIOP=z|Pl$9{w4WKR7&;*uheRX5Is+OGj(+k~Xq*J;>qP0Ci1$@k zV#ef+ESH7_QQouYmckvfgG7&|GqdHqF`T@JrMZjiS`HKMT;5u-i0Om6G*Ze|YzDAG zPl=jHk#w6PMQS4N0Kc5k=9X7$=Qm(;x5h?pW%GuJTA99-#Fk=ae|zM&UM%Wnife@e z879uY&8bmki>$wx$>;HvXTA>JoZphS#g&MP?V??IXNyG`sB`uhPoRn+hO4B{VgnAI z%!;PZ#}lv3@6E-#0aUIuaq>2}3ZqXuOUW7gcPHm};rVk|zIB#+_AIIAqN^z*zv)Y4 z`JH&v{$Rqkc$anz<1|7Ir9#IKQp%4a*3qJLCUKlbtansW-#Dw34kUOrWu8f_JH4r* zw^QP*LNB*Uk>>fNxVBb&@uJW=!=p~;^08!QYw&*Y>J{uc?B&Z=Sz&E0mCJ7d-uOdS YworJrzW%bMwzj^m<@1=#X5UZ#2j8r?*#H0l literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_menu_view.bmp b/mechglue/src/windows/identity/help/html/images/screen_menu_view.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9dfb871c2be593a5452452e9057199581414e579 GIT binary patch literal 64854 zcmeHNYiu0V6?R_|5^WJeRS~U3tNv)kuS%8rw^C7mw*SlzPzw>^A%s;PA|(xF!H{4# z4q#|XNg5JDd2LXuUz8PMhJPFJ?LPK5~#-%-jnnRy1 z4{1vPXGALA<)jDis23r7_F1yaKIc@xT7Q2(7zB@C8O*}7^n@9UYrDZ(hHC{W^0+ssdmQ+<`%yz}Ujx{fiBbdjMu_ZEelX z&5xNYQWXGe;0_FeN9Om%H{LQ5j|$*s#Cd~93XW*JiP8SOWUg3L0JrGVPd~k7%a-2W zUdysBT)2R=@O~AGUGpHAS8?ZW z%=;H5ugUWleh|gELOx%}7sZ9H5{ud?C`(>l((uEd&Oc-`V;&Xo@~d`P72AsDZn*vC zTW-GvZ|2Jr3Hq>zE@a7#jg7b7+<4>98-MjXMA`7oZ_OiCV>U_LLh*a;kF~Y93xzJq2|6byb>+mp*pdM5mYc|U zy%a4G4p_!tWo(jPxUK&4QNtBiBBZ9oZOM(v)h(;h{V=q6LNUVPFzNI%Ug;~Ru-{rMfQMlNxl$u1!>14_FWER9& zPFze~#^znuf7EMV64Cg@{)O9WJU4vjYAm!o(VpC%?AX75xU=Ka?Y+sZ+d4Wsz;FAS z_GDXoUm{NwQ-4H&kUUremV zbHi2NgNH;S(Yvd6$H^T7seys+eee8lAN1EZz6y%hKC||oL;{asT1c+NIx8HEhH#ga zl9miY(R4!U+ah>*QG|@tB(~b~d-eAbSW}{@?{Hr_mA+(MN~iXxr_$KV9Us39eqU%; zZ`98IwUgmQ(33i4N{Gyw%-C2Cl{EGm@GA9HI0X*Fi||loO6~c*@+w5K^q!^T`SD8y zJE+3ck?|v^w)bv*XKS(}`ONCXy64v|O(ZbZaLsixBdOanXBwZO8KY8K#S=?8t1;${ z&5KmIB=cLV-xnxCb^MN>>KW}pcxbcz*`7nYI`?%Z+tn*pTT5Fz@q5L$Vb7OOF0k<# z^%<&oqL0s74RPY6z^xala;*j8ciF?sx=(glUs#t8q*ObQO1||P9>K}2$xVq(p!lvk z{y^yjkDrSWe9C;6n3v~B7%vdNx7?ms+SbzaP}6g*ZK_?FzH(w~?+h_U;T7D5N5ykJhVc-`rkocstKt&GXHi(T+ z>1DHwiziW7sOIr)Wwk;qkm?@UB~=O6E1v9jgGSKs{i2Rq)~ z^~w8t_Tv|SHZV%0D*%4)edtfkYo2}iKX1Rcd*6 zCW1y~OG7~r%?WoSs>ni>OW`u)7i9@jnQ|2i4<00unDL9^Q`Vfjq>{n#a8yksoT-nK z`0>lh60?$1Lf9bc3iIoeR|xq<**S8iKtm`a2B}NN404woa+eIK8|hZdv}7*fDQg#%1AN%2CQ2|`3;zzF*E$e`yMd- z#-881?|a}cPqnUpBe`|^$DMokZ`;=$9vcx7k?B54gJkq-M@5#>2k3K)N@5IRi zsR6@pocMkCvB#fX_s@>)AMHQh*P9+WIy!FnjT65snw$T&VZ(bncOFcoj*pF<4By{h znftBc`wi#wBh62&-SAT9&aR%+K;PKuflM}R^$c4)6<2%lC)S-`aK{&=&s`{75UB%X z8)=|{)MbOqQwamVvhtG0;JVjRBGP}H^dLD#f?rC6(_sZKxs1OugdN6AK{fa)mm2te^ob{5 z*tluiuHA@mR!aN$}9?%s2BaA+`- z9iE&DaB#Xwq9d7QCe27W39(lty;I~reO8h@T(P*y4=c=0xZ|1A=#3phOh?> zhcP2;BiCAF9Wlg-Us*j_Ua2z$Y%E7fmo1rT2v5;)cFqR8N?jC$5l(&)7zvl90>nF| zoHxx9U06~}Qy3vj8f60ld5EWI2;qy_B7nzRTGqY1dHddwzF#e7HFzzQh4n})NMy}( z&;9GoH+LO4(3c(_nV1|~^!H~JknVG8saxNw#))5$``>NbK09)xe{`%~{Az60y}We~ zKr2YaT_l2?3v&C?>7g^3(aEX0?B9yxHxvCU0Deyn51$$zPiHdNyoO)@az$!S9(|?zCk=ppcmTTR|nmIi(!Gz>UPC0wwovYJ9x= z*s-0Tep*}kq__9@@bFYV51Dktn#{A51bGySGMLC)EMo2q$fHWJY_X?gEeqluCERKA zRu*DgX04nnjM$@jD`N|pWh~1hxr_zz;u@mN&fw%^agI=&r2^zpWlU0X)CDm&hXWbM zvU4DN&*!~|diNeWy1S<~va9DPr0eq|T?Y?$9qc(eG-UX-*{>VF$A*TF3=a1W3>`j| zhCr`I$VpHCVE6IVzN07h^z;~h>&x%RMNpUc|5Wee#}OAjW6 zXDub}^gQ05ad*u;6l$c8Pvr(rXO5>w48M{!x)~(m=nKhjHm_LLt^h9#+WW(-?&(}E zoyqp4N10#EzwFj!|H=SZSKG7H{)Itw_b>Q`R7t2d9WUw{zxKgg;(SKw>cTJ1aObcU zgvOKKLLplyWb9pxmIP&Ig>G-}5D+%wQBrW=r?V4%!(+UEiC=Ps)_M3AW*r^;{3SE+ z4h2NOm?zS+m2ma&wPOIN8IT#Zl1Ij2FLCa&AB^HSRk(2OnnmgPJ25>C0mTR&EeYvf zq@)?oVg)SYRqf=+xa1e!`27kxQLGgA{mKSa7;4CVzk*KODa5`QQA`PbC2_2iB6;K? z_>nkuRqJkN=#pPPpKZ%1@jE#^4MErwHpOUJA&?L+u1%3t z%o_3wpSYOBYWUUmZ-n_R7AK2Elm)w(T2@rC#3gY}M^_3q^2p>=YVGU;M`)FeEsQXU3b7AT8sZJ8wx_!povrGAm_irE3{rP$ z_BpH!Y=m|(z50?3aqS?^M38PBvPf~WPPWahx%k%{uf%=zquBDCB8@2k-q`J;$ zBKkIuJ`*{glGG<7`fknr+$6umQ)x~Wix4QZi+MZCF6(5*U8z84!CuDi%l(VXud`bv zr&6~+1v@tG{eX1%BJLd03l{Kr@S8h(7P%11L^QXgPzA_{d^>Ouzm8t1ze8q7}@XJRuzc{Ifv3eXU`sjQn9RVmrh+`uVIm-MJIEz!?{p&rS z!JT_!fZQ2=XO7}oCvY_Q&D;EfWfGK^7-ysc1vkd&oONnE!}}Nf;^E7?z~**tepN8` z4WKb@_?1sv|K~6Gg;YSI&y;ff%J(ax*x8%*`xWWl-RecE=T~lC=<3w9C4T$2cZ=+` x@%;IT!nEPH?)>J9#S0fNepPEZfAL~&dK!PFqn^3`hciaa`8@kCmuh%E{~!Ck>AwH~ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_new_creds.bmp b/mechglue/src/windows/identity/help/html/images/screen_new_creds.bmp new file mode 100755 index 0000000000000000000000000000000000000000..7d7335ab78e34b5596afd8b79eb9900f0b459ff0 GIT binary patch literal 414558 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 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_new_creds_err01.bmp b/mechglue/src/windows/identity/help/html/images/screen_new_creds_err01.bmp new file mode 100755 index 0000000000000000000000000000000000000000..44bf0f958a7ea304eab5e70b060084a1d87c0c27 GIT binary patch literal 211690 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 J?CND0{|A78Al3i? literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_new_creds_exp.bmp b/mechglue/src/windows/identity/help/html/images/screen_new_creds_exp.bmp new file mode 100755 index 0000000000000000000000000000000000000000..b1711a70fbe1f47fd7c2173c77d142f1a60249bb GIT binary patch literal 534694 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

YH5XUa4*T^C1}+P{8mNk$DUTHpo7v{Kn25Hc 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 Sky%&Uu&$=Bz^HAA#r}U;Ij=YX literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_tb_standard.bmp b/mechglue/src/windows/identity/help/html/images/screen_tb_standard.bmp new file mode 100644 index 0000000000000000000000000000000000000000..bd07cf208dfbd33188909eff0e7c58f5abc447d3 GIT binary patch literal 52634 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 XcYDu-AtB!@_j!pg)XkX(aL)YyWC{cm literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/images/screen_tray_icon.bmp b/mechglue/src/windows/identity/help/html/images/screen_tray_icon.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b2fb1ee863159fc9f106a28b5e3d67aef2873759 GIT binary patch literal 40122 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 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/help/html/menu_all.htm b/mechglue/src/windows/identity/help/html/menu_all.htm new file mode 100644 index 000000000..8118a8116 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/menu_all.htm @@ -0,0 +1,41 @@ + + + The Menu Bar + + + + + +

The Menu Bar

+ +

+Click an item on the menu to go to the description of the submenu, or +choose from the list below. You can activate the menu bar using F10. Alternatively, you can activate each +individual submenu by pressing Alt + +<key> where key is the +highlighted character on the submenu. +

+ + + + + + + + + +

+ +

+ + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/menu_credential.htm b/mechglue/src/windows/identity/help/html/menu_credential.htm new file mode 100644 index 000000000..b17533ea3 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/menu_credential.htm @@ -0,0 +1,86 @@ + + + Credential Menu + + + + + + +

Credential Menu

+ +

+Click an item on the menu to go to the description of the action, or +choose from the list below. You can activate the by pressing Alt + C and you can activate each action by +pressing the highlited character. +

+ +

+Actions which have an associated hot key show this hot key to the +right of the action. You can use the hot key to trigger the action +without invoking the Credential menu. +

+ + + + + + + + + + + +

+ +

+ +
+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/menu_file.htm b/mechglue/src/windows/identity/help/html/menu_file.htm new file mode 100644 index 000000000..91f73dfa8 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/menu_file.htm @@ -0,0 +1,46 @@ + + + File Menu + + + + + + +

File Menu

+ +

+Click an item on the menu to go to the description of the action, or +choose from the list below. You can activate the by pressing Alt + F and you can activate each action by +pressing the highlited character. +

+ +

+Actions which have an associated hot key show this hot key to the +right of the action. You can use the hot key to trigger the action +without invoking the File menu. +

+ + + + + + +

+ +

+ + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/menu_help.htm b/mechglue/src/windows/identity/help/html/menu_help.htm new file mode 100644 index 000000000..bceb2a991 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/menu_help.htm @@ -0,0 +1,57 @@ + + + Help Menu + + + + + + +

Help Menu

+ +

+You can activate the menu by pressing Alt + H +and you can activate each action by pressing the highlighted character. +

+ +

+You can invoke help anytime by pressing the F1 key or if you are in a dialog box, by clicking +the question mark icon in the title bar and then clicking on the +dialog box control that you want help with. +

+ +

+This is the help menu. While it is ironic that the help menu itself +needs to be explained, we have decided to include it here just for +completeness. It is bad enough that it is the last menu on the menu +bar. We didn't want to pile on any more disrespect by not documenting +it. We encourage you to not read this and just go ahead and click any +item on this menu. If anything unexpected happens, please file a bug +report at kfw-bugs@mit.edu. +

+ +

+ +

+ + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/menu_options.htm b/mechglue/src/windows/identity/help/html/menu_options.htm new file mode 100644 index 000000000..2d60f1ae3 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/menu_options.htm @@ -0,0 +1,52 @@ + + + Options Menu + + + + + + +

Options Menu

+ +

+Click an item on the menu to go to the description of the action, or +choose from the list below. You can activate the by pressing Alt + O and you can activate each action by +pressing the highlited character. +

+ +

+Actions which have an associated hot key show this hot key to the +right of the action. You can use the hot key to trigger the action +without invoking the Options menu. +

+ + + + + + + +

+ +

+ +
+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/menu_view.htm b/mechglue/src/windows/identity/help/html/menu_view.htm new file mode 100644 index 000000000..53a46e189 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/menu_view.htm @@ -0,0 +1,86 @@ + + + View Menu + + + + + + +

View Menu

+ +

+Click an item on the menu to go to the description of the action, or +choose from the list below. You can activate the by pressing Alt + V and you can activate each action by +pressing the highlited character. +

+ +

+Actions which have an associated hot key show this hot key to the +right of the action. You can use the hot key to trigger the action +without invoking the View menu. +

+ + + + + + + + + +

+ +

+ +
+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/nidmgr.css b/mechglue/src/windows/identity/help/html/nidmgr.css new file mode 100644 index 000000000..9ace12229 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/nidmgr.css @@ -0,0 +1,72 @@ +BODY { + font-family:helvetica,sans-serif; + font-size:8pt; + font-style:normal; + background-color:white; + margin-top: 0; + margin-left: 0; + margin-right: 0; + } + +H1 { + font-size: 10pt; + border-bottom:1px solid black; + padding:5px; + background-color:#eeeeee; + } + +H2 { + } + +H3 { + font-size: 9pt; + border-bottom: 1px solid lightgrey; + padding: 5px; + } + +H4 { + font-size: 9pt; + font-style: italic; + border-bottom: 1px dashed lightgrey; + margin-left: 10px; + } + +P { + margin-left: 5px; + margin-right: 5px; + } + +P.caption { + margin-left: 5px; + margin-right: 5px; + font-style: italic; +} + +DIV.inline { + float: left; +} + +DIV.sidebar { + float: right; + background-color:#ffffb9; + border: 1px solid #ffff00; +} + +A.external { +} + +A.mail { +} + +IMG { + border: 0; +} + +SPAN.pre { + font-family: courier; +} + +SPAN.title { + font-weight: bold; +} + diff --git a/mechglue/src/windows/identity/help/html/tb_standard.htm b/mechglue/src/windows/identity/help/html/tb_standard.htm new file mode 100644 index 000000000..945063ffc --- /dev/null +++ b/mechglue/src/windows/identity/help/html/tb_standard.htm @@ -0,0 +1,68 @@ + + + Standard Toolbar + + + + + + +

Standard Toolbar

+ +

The standard toolbar appears below along with descriptions of what +each button does. +

+ +

+ +

+ +
    + +
  1. New credentials: Equivalent to + selecting New + credentials... from the Credential menu. +

    + See New Credentials Action for more + information.

  2. + +
  3. Renew credentials: Equivalent to + selecting Renew Credentials from + the Credential menu. +

    + See Renew Credentials Action for + more information.

  4. + +
  5. Import credentials: Equivalent to + selecting Import Credentials from + the Credential menu. +
  6. + +
  7. Destroy credentials: Equivalent to + selecting Destroy Credentials + from the Credential menu.
  8. + +
  9. Change password: Equivalent to + selecting Change Password ... from + the Credential menu.
  10. + +
  11. Refresh view: Equivalent to selecting + Refresh + View from the Credential menu.
  12. + +
  13. Help: Displays documentation
  14. + +
+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/template.htm b/mechglue/src/windows/identity/help/html/template.htm new file mode 100644 index 000000000..5e39963da --- /dev/null +++ b/mechglue/src/windows/identity/help/html/template.htm @@ -0,0 +1,11 @@ + + + title + + + + + + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/use_start.htm b/mechglue/src/windows/identity/help/html/use_start.htm new file mode 100644 index 000000000..979197999 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/use_start.htm @@ -0,0 +1,65 @@ + + + Starting NetIDMgr + + + + + + +

Starting NetIDMgr

+ +

Opening the NetIDMgr window from the notification icon

+ +

Depending on how you have installed NetIDMgr, it may start as soon +as you login, or it may need to be started manually. NetIDMgr is a +tray application. Hence it doesn't appear on your task bar. This is +based on the assumption that you don't need to run NetIDMgr very +often, and helps reduce clutter on the desktop.

+ + + +

When NetIDMgr is running, it places an icon in the system +notification area (sometimes referred to as the "system tray") as +shown in figure 1.

+ +

Clicking on this icon brings up the NetIDMgr window. Right +clicking on the icon, on the other hand, brings up a menu.

+ +

Starting NetIDMgr from the Start Menu or command line

+ + + +

If NetIDMgr was not configured to start automatically when you +login to Windows, then you need to start it either from the +commandline or the start menu. The start menu application icon is +under "Kerberos for Windows" as shown in figure 2.

+ +

Alternatively, you can type 'netidmgr' at a command shell to start +NetIDMgr as well. When starting this way, you may specify additional +command line options.

+ +

Configuring startup options

+ +

+Note that you can configure options related to the startup of NetIDMgr +by using the NetIDMgr configuration dialog box. You can use the menu +items under the Options menu to invoke the +configuration dialog. +

+ +

+Only one instance of NetIDMgr can be running at any one time. +Attempting to start NetIDMgr while it is still running will not do +anything, unless you provide any command line options that trigger +some action in the running application instance. +

+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/using.htm b/mechglue/src/windows/identity/help/html/using.htm new file mode 100644 index 000000000..c3699e841 --- /dev/null +++ b/mechglue/src/windows/identity/help/html/using.htm @@ -0,0 +1,46 @@ + + + Using NetIDMgr + + + + + + +

Using NetIDMgr

+ +

+Depending on how NetIDMgr was installed, it might already be running +in the system notification area or it might need to be started +manually. See the topic starting +NetIDMgr for details. Essentially, to open the NetIDMgr window, +you either have to click the application icon in the system +notification area, select the icon from the start menu, or type +'netidmgr' at a command prompt. +

+ +

+Once you open the NetIDMgr window, you will be presented with a view +of your existing credentials, or a message notifying you that you +don't have any. Details of the credentials view objects can be found here. +

+ +

+Brief overviews of how to perform common tasks are linked below: +

+ + + +

+A more comprehensive list of how-to topics can be found in the How do I... section.

+ + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/welcome.htm b/mechglue/src/windows/identity/help/html/welcome.htm new file mode 100644 index 000000000..7423b848d --- /dev/null +++ b/mechglue/src/windows/identity/help/html/welcome.htm @@ -0,0 +1,70 @@ + + + Welcome to the Network Identity Manager + + + + + +

Welcome to the Network Identity Manager

+ +
+ +
+ +

+The Network Identity Manager (or NetIDMgr for short) allows you to +manage your network identities and the associated credentials +(Kerberos tickets, AFS tokens, etc.). +

+ +

+NetIDMgr is extensible using plugins. In fact, most of the features +are implemented in plugins, some of which are themselves extensible. +Support for additional protocols and credential types can be added by +installing the appropriate plugins. +

+ +

+This version is distributed as a part of the MIT Kerberos for Windows +product along with the Kerberos 5 and Kerberos 4 plugins. The OpenAFS +plugin, which is required for supporting AFS tokens, is +distributed separately. +

+ + + +

Getting started

+ + + +

Information for developers

+ +

+If you are interested in developing plugins or extending the features +of NetIDMgr, your first stop should be the NetIDMgr SDK. This is +included in the Kerberos for Windows SDK, which itself is a part of +the Kerberos for Windows distribution. +

+ +

External links

+ + + + \ No newline at end of file diff --git a/mechglue/src/windows/identity/help/html/wnd_main.htm b/mechglue/src/windows/identity/help/html/wnd_main.htm new file mode 100644 index 000000000..575e7ba3f --- /dev/null +++ b/mechglue/src/windows/identity/help/html/wnd_main.htm @@ -0,0 +1,89 @@ + + + Main Window + + + + + + +

Main Window

+ +

The main window of Network Identity Manager is structured as follows

+ + + + + + + + + + + + + +
    +
  1. Menu bar
  2. +
  3. Tool bar
  4. + +
  5. An identity with a valid Kerberos 5 initial + ticket
  6. + +
  7. An identity with valid Kerberos 5 tickets and + AFS tokens
  8. + +
  9. A set of Kerberos 5 tickets
  10. + +
  11. A set of AFS tokens
  12. + +
  13. An identity with expired Kerberos 5 tickets
  14. + +
+ +

Identity views

+ +

+The default credentials view organizes them grouped by identity name +and then by credential type. Each credential is then shown under each +group heading sorted by the credential name. The default headings for +the credential view provides you with a minimal amount of information +to reduce clutter. If you wish you can add columns to the display +using the Choose columns... action on the +View menu. +

+ +

+The header backgrounds and the credential rows change color if the +credentials are about to expire or are expired. + +

    + +
  • Headers mean that +credentials at that level will expire unless renewed. Credentials +will have a warning icon next to them.
    + +The threshold for this can be set as the Warn +parameter in the Notifications configuration +panel.
  • + +
  • Headers mean that +credentials at that level will expire in a few minutes. Credentials +will have a critical icon next to them.
    + +The threshold for this can be set as the Warn +again parameter in the Notifications +configuration panel.
  • + +
  • Headers mean that +the credentials at that level have expired. Credentials will have an +expired icon next to them.
    + +The threshold for this is always zero. +
  • + +
+

+ + + diff --git a/mechglue/src/windows/identity/help/khhelp.h b/mechglue/src/windows/identity/help/khhelp.h new file mode 100644 index 000000000..88f73c0b3 --- /dev/null +++ b/mechglue/src/windows/identity/help/khhelp.h @@ -0,0 +1,33 @@ +#define IDH_WELCOME 1000 +#define IDH_WIN_MAIN 1001 + +#define IDH_MENU_FILE 1501 +#define IDH_MENU_CRED 1502 +#define IDH_MENU_VIEW 1503 +#define IDH_MENU_OPTIONS 1504 +#define IDH_MENU_HELP 1505 + +#define IDH_ACTION_PROPERTIES 2000 +#define IDH_ACTION_EXIT 2001 +#define IDH_ACTION_NEW_ID 2002 +#define IDH_ACTION_SET_DEF_ID 2003 +#define IDH_ACTION_SET_SRCH_ID 2004 +#define IDH_ACTION_DESTROY_ID 2005 +#define IDH_ACTION_RENEW_ID 2006 +#define IDH_ACTION_PASSWD_ID 2007 +#define IDH_ACTION_NEW_CRED 2008 +#define IDH_ACTION_CHOOSE_COLS 2009 +#define IDH_ACTION_DEBUG_WINDOW 2010 +#define IDH_ACTION_VIEW_REFRESH 2011 +#define IDH_ACTION_OPT_KHIM 2012 +#define IDH_ACTION_OPT_INIT 2013 +#define IDH_ACTION_OPT_NOTIF 2014 + +#define IDH_NC_CREDWND 3000 +#define IDH_NC_OK 3001 +#define IDH_NC_CANCEL 3002 +#define IDH_NC_HELP 3003 +#define IDH_NC_TABBUTTON 3004 +#define IDH_NC_OPTIONS 3005 +#define IDH_NC_TABMAIN 3006 +#define IDH_NC_SETDEF 3007 diff --git a/mechglue/src/windows/identity/help/netidmgr.hhp b/mechglue/src/windows/identity/help/netidmgr.hhp new file mode 100644 index 000000000..9f2ae7332 --- /dev/null +++ b/mechglue/src/windows/identity/help/netidmgr.hhp @@ -0,0 +1,35 @@ +[OPTIONS] +Auto Index=Yes +Compatibility=1.1 or later +Compiled file=netidmgr.chm +Contents file=toc.hhc +Default Window=MainHelpWnd +Default topic=html/welcome.htm +Display compile progress=No +Index file=Index.hhk +Language=0x409 English (United States) +Title=NetIDMgr + +[WINDOWS] +MainHelpWnd="NetIDMgr Help","toc.hhc","Index.hhk","html/welcome.htm","html/welcome.htm",,,,,0x42120,,0x384e,[271,372,593,566],0x830000,,,,,,0 + + +[ALIAS] +IDH_ACTION_NEW_ID=html\act_new_creds.htm +IDH_ACTION_PASSWD_ID=html\act_chpw.htm +IDH_WELCOME=html\welcome.htm + +[MAP] +#include khhelp.h + +[TEXT POPUPS] +khhelp.h +popups_newcreds.txt +popups_password.txt + +[INFOTYPES] +Category:Concepts +CategoryDesc:Authentication, authorization and related concepts. +Category:Usage +CategoryDesc:Usage instructions for NetIDMgr + diff --git a/mechglue/src/windows/identity/help/popups.txt b/mechglue/src/windows/identity/help/popups.txt new file mode 100644 index 000000000..7d58703b1 --- /dev/null +++ b/mechglue/src/windows/identity/help/popups.txt @@ -0,0 +1 @@ +foo diff --git a/mechglue/src/windows/identity/help/popups_newcreds.txt b/mechglue/src/windows/identity/help/popups_newcreds.txt new file mode 100644 index 000000000..52c61244b --- /dev/null +++ b/mechglue/src/windows/identity/help/popups_newcreds.txt @@ -0,0 +1,30 @@ +.topic IDH_NC_TABMAIN +Opens the identity selection panel. + +.topic IDH_NC_TABBUTTON +Opens the option panel for this credentials type. + +.topic IDH_NC_OK +Obtains new credentials using the information that you provided. + +.topic IDH_NC_CANCEL +Cancels the new credentials operation. + +.topic IDH_NC_HELP +Provides help for this dialog box. + +.topic IDH_NC_OPTIONS +Expands the dialog and allows you to set additional +options for the credentials that will be obtained +by this dialog. + +.topic IDH_NC_CREDWND +Provides an overview of the credentials that will be obtained +after the successful completion of the new credentials dialog. +Clicking on the hyperlinks will take you to the corresponding +credentials option panels where you will be able to set +additional options for each type. + +.topic IDH_NC_SETDEF +If checked, once the credentials acquisition operation completes, the +identity will be set as the default. diff --git a/mechglue/src/windows/identity/help/toc.hhc b/mechglue/src/windows/identity/help/toc.hhc new file mode 100644 index 000000000..106c22054 --- /dev/null +++ b/mechglue/src/windows/identity/help/toc.hhc @@ -0,0 +1,130 @@ + + + + + + + + + + + + + +
    +
  • + + + +
  • + + + +
  • + + + +
      +
    • + + + +
    • + + + +
    +
  • + + + +
      +
    • + + + +
    • + + + +
    • + + + +
    +
  • + + + +
      +
    • + + + +
    +
  • + + + +
      +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    +
  • + + +
      +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    • + + + +
    +
  • + + +
      +
    • + + + +
    +
+ diff --git a/mechglue/src/windows/identity/include/Makefile b/mechglue/src/windows/identity/include/Makefile new file mode 100644 index 000000000..be4ddf9a2 --- /dev/null +++ b/mechglue/src/windows/identity/include/Makefile @@ -0,0 +1,38 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=include +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\khdefs.h \ + $(INCDIR)\kherror.h \ + $(INCDIR)\khlist.h \ + $(INCDIR)\khmsgtypes.h \ + $(INCDIR)\netidmgr.h + +all: $(INCFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/mechglue/src/windows/identity/include/khdefs.h b/mechglue/src/windows/identity/include/khdefs.h new file mode 100644 index 000000000..4a0251107 --- /dev/null +++ b/mechglue/src/windows/identity/include/khdefs.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHDEFS_H__ +#define __KHIMAIRA_KHDEFS_H__ + +/*! \defgroup khdef Core definitions + + Key type definitions used throughout NetIDMgr. + */ +/*@{*/ +#include +#include +#include + +/*!\typedef khm_octet + \brief A byte (8 bit unsigned)*/ + +/*!\typedef khm_int16 + \brief A signed 16 bit quantity */ + +/*!\typedef khm_ui_2 + \brief An unsigned 16 bit quantity */ + +/*!\typedef khm_int32 + \brief A signed 32 bit quantity */ + +/*!\typedef khm_ui_4 + \brief An unsigned 32 bit quantity */ + +/*!\typedef khm_int64 + \brief A signed 64 bit quantity */ + +/*!\typedef khm_ui_8 + \brief An unsigned 64 bit quantity */ + +typedef unsigned __int8 khm_octet; + +typedef __int16 khm_int16; +typedef unsigned __int16 khm_ui_2; + +typedef __int32 khm_int32; +typedef unsigned __int32 khm_ui_4; + +typedef __int64 khm_int64; +typedef unsigned __int64 khm_ui_8; + +#define VALID_INT_BITS INT_MAX +#define VALID_UINT_BITS UINT_MAX + +#define KHM_UINT32_MAX 4294967295 + +#define KHM_INT32_MAX 2147483647 +/* this strange form is necessary since - is a unary operator, not a sign + indicator */ +#define KHM_INT32_MIN (-KHM_INT32_MAX-1) + +#define KHM_UINT16_MAX 65535 + +#define KHM_INT16_MAX 32767 +/* this strange form is necessary since - is a unary operator, not a sign + indicator */ +#define KHM_INT16_MIN (-KHM_INT16_MAX-1) + +/*! \brief Generic handle type. + + Handles in NetIDMgr are generic pointers. +*/ +typedef void * khm_handle; + +/*! \brief The invalid handle + + Just used to indicate that this handle does not point to anything useful. + Usually returned by a function that returns a handle as a signal that the + operation failed. +*/ +#define KHM_INVALID_HANDLE ((khm_handle) NULL) + +/*! \brief Boolean. +*/ +typedef khm_int32 khm_boolean; + +/*! \brief A size + */ +typedef size_t khm_size; + +/*! \typedef ssize_t + \brief Signed size specifier + + Just a signed version of size_t + */ + +#ifdef _WIN64 +typedef __int64 ssize_t; +#else +typedef _W64 int ssize_t; +#endif + +typedef ssize_t khm_ssize; + +#if defined(_WIN64) +typedef unsigned __int64 khm_wparm; +/*TODO: is this enough? */ +typedef unsigned __int64 khm_lparm; +#elif defined(_WIN32) +typedef unsigned __int32 khm_wparm; +typedef unsigned __int64 khm_lparm; +#else +#error khm_wparm and khm_lparm need to be defined for this platform +#endif + +/*!\def KHMAPI + \brief Calling convention for NetIDMgr exported functions + + The caling convention for all NetIDMgr exported functions is \b + __stdcall , unless otherwise noted. + */ + +/*!\def KHMEXP + \brief Export prefix for NetIDMgr exported functions + + When compiling source that exports functions, those exported + function declarations will be done as follows: + + \code + __declspec(dllexport) khm_int32 __stdcall function_name(arguments...); + \endcode + + This eliminates the need for a separate exports definition file. + However, it doesn't preserve ordinals, but we aren't guaranteeing + that anyway. + + On the other hand, if a particular function is going to be imported + from a DLL, it should declared as follows: + + \code + __declspec(dllimport) khm_int32 __stdcall function_name(arguments...); + \endcode + + This allows the compiler to properly instrument the import. If the + function is not declared this way, there will be a stub function + generated that will just jump to the proper import, generating + redundant instructions and wasting execution time. + + This macro encapsulates the proper declaration specifier. + */ + +#ifdef _WIN32 +#define KHMAPI __stdcall + +#define KHMEXP_EXP __declspec(dllexport) +#define KHMEXP_IMP __declspec(dllimport) + +#define KHMEXP KHMEXP_EXP +#endif + +/* Generic permission values */ +/*! \brief Generic read permission or request */ +#define KHM_PERM_READ 0x100 + +/*! \brief Generic write permission or request */ +#define KHM_PERM_WRITE 0x200 + +/* Generic flags */ +/*! \brief Generic create request + + For most lookup functions, specifying this flag indicates that if + the requested object is not found it should be created. +*/ +#define KHM_FLAG_CREATE 0x1000 + +/*! \brief Wrap to DWORD boundary + + Returns the smallest integer greater than or equal to the + parameter that is a multiple of 4. + + \note Only use with positive integers. */ +#define UBOUND32(d) ((((d)-1)&~3) + 4) + +/*! \brief Offset a pointer by a number of bytes + + Given a pointer, returns a void pointer that is a given number of + bytes offset from the pointer. + */ +#define BYTEOFFSET(p,off) ((void *)(((char *) (p)) + (off))) + +/*! \brief Check for powers of 2 + + Return TRUE if the operand is a positive power of 2 or 0*/ +#define IS_POW2(d) ((d)>=0 && !((d) & ((d) - 1))) + +/*! \brief Wrap to upper bound based on start and step size + + Return the smallest element in the series s, s+t, s+2*t, + s+3*t, ... that is greater than or equal to \c v. +*/ +#define UBOUNDSS(v,start,step) (((v)<=(start))?(start):(start)+((((v)-((start)+1))/(step))+1)*(step)) + +/* \brief Length of an array +*/ +#define ARRAYLENGTH(x) (sizeof(x)/sizeof(x[0])) + +/*! \brief Generic version type*/ +typedef struct tag_khm_version { + khm_ui_2 major; /*!< Major version number */ + khm_ui_2 minor; /*!< Minor version number */ + khm_ui_2 patch; /*!< Patch level */ + khm_ui_2 aux; /*!< Auxilary level (usually carries a build number) */ +} khm_version; + +/*@}*/ +#endif diff --git a/mechglue/src/windows/identity/include/kherror.h b/mechglue/src/windows/identity/include/kherror.h new file mode 100644 index 000000000..f11e28510 --- /dev/null +++ b/mechglue/src/windows/identity/include/kherror.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Exported */ +#ifndef __KHIMAIRA_KHERROR_H +#define __KHIMAIRA_KHERROR_H + +/*! \defgroup kherror NetIDMgr errors + +@{*/ +/*! \brief Base for error codes + + NetIDMgr errors range from \a KHM_ERROR_BASE to KHM_ERROR_BASE + + KHM_ERROR_RANGE, with the exception of KHM_ERROR_SUCCESS and + KHM_ERROR_NONE. + */ +#define KHM_ERROR_BASE 0x40000000L + +/*! \brief Range for error codes + + NetIDMgr errors range from \a KHM_ERROR_BASE to + KHM_ERROR_BASE + KHM_ERROR_RANGE. +*/ +#define KHM_ERROR_RANGE 256L + +/*! \defgroup kherror_codes Error codes + @{*/ + +/*! \brief No error */ +#define KHM_ERROR_NONE 0x00000000L + +/*! \brief Success. Same as \a KHM_ERROR_NONE */ +#define KHM_ERROR_SUCCESS KHM_ERROR_NONE + +/*! \brief The supplied name was invalid */ +#define KHM_ERROR_INVALID_NAME (KHM_ERROR_BASE + 1) + +/*! \brief Too much data + + A supplied buffer was invalid, was of insufficient size, or a + buffer was of a larger size than expected + */ +#define KHM_ERROR_TOO_LONG (KHM_ERROR_BASE + 2) + +/*! \brief One or more parameters supplied to a function were invalid */ +#define KHM_ERROR_INVALID_PARAM (KHM_ERROR_BASE + 3) + +/*! \brief A duplicate. + + Usually means that something that should have been unique was + found to be not. + */ +#define KHM_ERROR_DUPLICATE (KHM_ERROR_BASE + 4) + +/*! \brief An object was not found + + An object referenced in a parameter was not found. + */ +#define KHM_ERROR_NOT_FOUND (KHM_ERROR_BASE + 5) + +/*! \brief The relevant subsystem is not ready + + Indicates that initialization has not been completed for a + subsystem. + */ +#define KHM_ERROR_NOT_READY (KHM_ERROR_BASE + 6) + +/*! \brief No more resources + + A limited resource has been exhausted. + */ +#define KHM_ERROR_NO_RESOURCES (KHM_ERROR_BASE + 7) + +/*! \brief Type mismatch + */ +#define KHM_ERROR_TYPE_MISMATCH (KHM_ERROR_BASE + 8) + +/*! \brief Already exists + + Usually indicates that an exclusive create operation failed due to + the existence of a similar object. Subtly different from + ::KHM_ERROR_DUPLICATE + */ +#define KHM_ERROR_EXISTS (KHM_ERROR_BASE + 9) + +/*! \brief Operation timed out + */ +#define KHM_ERROR_TIMEOUT (KHM_ERROR_BASE + 10) + +/*! \brief An EXIT message was received + */ +#define KHM_ERROR_EXIT (KHM_ERROR_BASE + 11) + +/*! \brief Unknown or unspecified error + */ +#define KHM_ERROR_UNKNOWN (KHM_ERROR_BASE + 12) + +/*! \brief General error + */ +#define KHM_ERROR_GENERAL KHM_ERROR_UNKNOWN + +/*! \brief An index was out of bounds + */ +#define KHM_ERROR_OUT_OF_BOUNDS (KHM_ERROR_BASE + 13) + +/*! \brief Object already deleted + + One or more objects that were referenced were found to have been + already deleted. + */ +#define KHM_ERROR_DELETED (KHM_ERROR_BASE + 14) + +/*! \brief Invalid operation + + The operation was not permitted to continue for some reason. + Usually because the necessary conditions for the operation haven't + been met yet or the operation can only be performed at certain + times during the execution of NetIDMgr. + */ +#define KHM_ERROR_INVALID_OPERATION (KHM_ERROR_BASE + 15) + +/*! \brief Signature check failed + */ +#define KHM_ERROR_INVALID_SIGNATURE (KHM_ERROR_BASE + 16) + +/*! \brief Not implemented yet + + The operation that was attempted involved invoking functionality + that has not been implemented yet. + */ +#define KHM_ERROR_NOT_IMPLEMENTED (KHM_ERROR_BASE + 17) + +/*! \brief The objects were equivalent + */ +#define KHM_ERROR_EQUIVALENT (KHM_ERROR_BASE + 18) + +/*! \brief No provider exists to service the request +*/ +#define KHM_ERROR_NO_PROVIDER (KHM_ERROR_BASE + 19) + +/*! \brief The operation succeeded, but with errors +*/ +#define KHM_ERROR_PARTIAL (KHM_ERROR_BASE + 20) + +/*! \brief An incompatibility was found */ +#define KHM_ERROR_INCOMPATIBLE (KHM_ERROR_BASE + 21) + +/*@}*/ /*kherror_codes*/ + +/*! \brief Tests whether a return value indicates success */ +#define KHM_SUCCEEDED(rv) ((rv)==KHM_ERROR_NONE) + +/*! \brief Tests whether a return value indicates failure */ +#define KHM_FAILED(rv) ((rv)!=KHM_ERROR_NONE) + +/*@}*/ +#endif diff --git a/mechglue/src/windows/identity/include/khlist.h b/mechglue/src/windows/identity/include/khlist.h new file mode 100644 index 000000000..2eb85864a --- /dev/null +++ b/mechglue/src/windows/identity/include/khlist.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Not exported */ +#ifndef _KHIMAIRA_KHLIST_H +#define _KHIMAIRA_KHLIST_H + +/* Note that most of these are "unsafe" macros. Not for general use */ + +/* LIFO lists */ +#define LDCL(type) \ + type * next; \ + type * prev + +#define LINIT(pe) \ + do { \ + (pe)->next = NULL; \ + (pe)->prev = NULL; } while(0) + +#define LPUSH(pph,pe) \ + do { \ + (pe)->next = *pph; \ + (pe)->prev = NULL; \ + if(*(pph)) (*(pph))->prev = (pe); \ + (*(pph)) = (pe); } while(0) + +#define LPOP(pph,ppe) \ + do { \ + *(ppe) = *(pph); \ + if(*(pph)) *(pph) = (*(pph))->next; \ + if(*(pph)) (*(pph))->prev = NULL; \ + if(*(ppe)) (*(ppe))->next = NULL; \ + } while(0) + +#define LDELETE(pph,pe) \ + do { \ + if((pe)->prev) (pe)->prev->next = (pe)->next; \ + if((pe)->next) (pe)->next->prev = (pe)->prev; \ + if(*(pph) == (pe)) *(pph) = (pe)->next; \ + (pe)->next = (pe)->prev = NULL; \ + } while(0) + +#define LEMPTY(pph) (*(pph) == NULL) + +#define LNEXT(pe) ((pe)?(pe)->next:NULL) + +#define LPREV(pe) ((pe)?(pe)->prev:NULL) + +/* Trees with LIFO child lists */ +#define TDCL(type) \ + LDCL(type); \ + type * children; \ + type * parent + +#define TINIT(pe) \ + do { \ + (pe)->children = NULL; \ + (pe)->parent = NULL; } while(0) + +#define TADDCHILD(pt,pe) \ + do { \ + LPUSH(&((pt)->children),(pe)); \ + (pe)->parent = (pt); } while(0) + +#define TFIRSTCHILD(pt) ((pt)?(pt)->children:NULL) + +#define TPOPCHILD(pt, ppe) \ + do { \ + LPOP(&((pt)->children), ppe); \ + if(*(ppe)) (*(ppe))->parent = NULL; \ + } while(0) + +#define TDELCHILD(pt, pe) \ + do { \ + LDELETE(&((pt)->children), (pe)); \ + (pe)->parent = NULL; } while(0) + +#define TPARENT(pe) ((pe)?(pe)->parent:NULL) + +/* FIFO lists */ +#define QDCL(type) \ + type * head; \ + type * tail + +#define QINIT(pq) \ + do { \ + (pq)->head = (pq)->tail = NULL; \ + } while(0) + +#define QPUT(pq, pe) \ + do { \ + LPUSH(&(pq)->tail, (pe)); \ + if(!(pq)->head) (pq)->head = (pe); \ + } while(0) + +#define QGET(pq, ppe) \ + do { \ + *(ppe) = (pq)->head; \ + if(*(ppe)) { \ + (pq)->head = (*(ppe))->prev; \ + if( (*(ppe))->prev ) (*(ppe))->prev->next = NULL; \ + (*(ppe))->prev = NULL; \ + if( (pq)->tail == *(ppe)) (pq)->tail = NULL; \ + } \ + } while(0) + +#define QDEL(pq, pe) \ + do { \ + if((pq)->head == (pe)) (pq)->head = LPREV(pe); \ + LDELETE(&((pq)->tail), (pe)); \ + } while(0) + + +#define QGETT(pq,ppe) \ + do { \ + *(ppe) = (pq)->tail; \ + if(*(ppe)) { \ + (pq)->tail = (*(ppe))->next; \ + if( (*(ppe))->next ) (*(ppe))->next->prev = NULL; \ + (*(ppe))->next = NULL; \ + if( (pq)->head == *(ppe)) (pq)->head = NULL; \ + } \ + } while(0) + +#define QTOP(pq) ((pq)->head) +#define QBOTTOM(pq) ((pq)->tail) +#define QNEXT(pe) ((pe)->prev) +#define QPREV(pe) ((pe)->next) + +/* Trees with FIFO child lists */ +#define TQDCL(type) \ + LDCL(type); \ + QDCL(type); \ + type * parent + +#define TQINIT(pe) \ + do { \ + QINIT(pe); \ + (pe)->parent = NULL; } while(0) + +#define TQADDCHILD(pt,pe) \ + do { \ + QPUT((pt), (pe)); \ + (pe)->parent = (pt); } while(0) + +#define TQFIRSTCHILD(pt) ((pt)?QTOP(pt):NULL) + +#define TQPARENT(pe) ((pe)?(pe)->parent:NULL) + +#endif diff --git a/mechglue/src/windows/identity/include/khmsgtypes.h b/mechglue/src/windows/identity/include/khmsgtypes.h new file mode 100644 index 000000000..c2237ca19 --- /dev/null +++ b/mechglue/src/windows/identity/include/khmsgtypes.h @@ -0,0 +1,733 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHMSGTYPES_H +#define __KHIMAIRA_KHMSGTYPES_H + +/*! \addtogroup kmq +@{*/ +/*! \defgroup kmq_msg Message Types +@{*/ + +/*! \name Global message types +@{*/ + +/*! \brief System messages. + + All subscribers are subscribed to the system message class by default. + + \see \ref kmq_msg_system +*/ +#define KMSG_SYSTEM 0 + +/*! \brief Ad-hoc messages. + + These are messages that are sent through add hoc publishers and + subscribers. +*/ +#define KMSG_ADHOC 1 + +/*! \brief NetIDMgr Credentials Database messages + + These messages notify subscribers of events related to the + credentials database, such as the registration, unregistration and + modification of identities, attributes, attribute types and + credential types. It also provides notifications of changes to + the root crednetial set. + + \see \ref kmq_msg_kcdb +*/ +#define KMSG_KCDB 2 + +/*! \brief NetIDMgr Module Manager messages + + \see \ref kmq_msg_kmm +*/ +#define KMSG_KMM 3 + +/*! \brief NetIDMgr Credential messages + + Notifications of crednetial events. These are the most important + events that a credentials provider should respond to. The + notifications provide co-oridination between credential providers + for performing basic credentials management tasks such as + obtaining new credentials for an identity, deleting credentials + for an identity, obtaining or deleting credentials of a particular + type for an identity etc. + + \see \ref cred_msgs + \see \ref kmq_msg_cred + */ +#define KMSG_CRED 4 + +/*! \brief Action list messages + + Notifications of changes in action state. + + \see \ref kmq_msg_act + */ +#define KMSG_ACT 5 + +/*! \brief Alert messages + + Notifier is the component which displays alerts and error messages + when the NetIDMgr window is normally in operation and which + displays balloon prompts when the window is minimized to alert the + user to important messages such as credentials expiring etc. + + \note This is an internal message class. Components that are not + the notifier should not be subscribing to alert messages. + + \see \ref kmq_msg_alert + */ +#define KMSG_ALERT 6 + +/*! \brief Identity messages + + These are messages that are sent to the identity provider. These + are generally dispatched through a specific subscription object + and are not broadcast. + + \see \ref kmq_msg_ident + */ +#define KMSG_IDENT 7 + +/*! \brief Base message type ID for customized message types + */ +#define KMSGBASE_USER 16 + +/*@}*/ + +/*! \defgroup kmq_msg_system KMSG_SYSTEM subtypes +@{*/ +/*! \brief Generic initialization message + + This message is used by specific components to signal that the + recipient is to perform initialization tasks. As a convention, + the recipient should return KHM_ERROR_SUCCESS if it successfully + performed the initlization tasks or some other value if it failed + to do so. Failure to successfully initialize is usually taken to + mean that the recipient component is not able to perform its + function. + + Usually this is the first message to be received by the recipient. + + \see \ref pi_pt_cred_init + */ +#define KMSG_SYSTEM_INIT 1 +/*! \brief Generic uninitialization message + + Used by specific components to signal that the recipient should + perform uninitilization tasks in preparation of termination. The + return value of this message is not used. + + Usually this is the last message to be received by the recipient. + + \see \ref pi_pt_cred_exit + */ +#define KMSG_SYSTEM_EXIT 2 + +/*! \brief Message completion + + This is an internal message + */ +#define KMSG_SYSTEM_COMPLETION 3 +/*@}*/ + +/*! \defgroup kmq_msg_kcdb KMSG_KCDB subtypes +@{*/ +#define KMSG_KCDB_IDENT 1 +#define KMSG_KCDB_CREDTYPE 2 +#define KMSG_KCDB_ATTRIB 3 +#define KMSG_KCDB_TYPE 4 + +/*! \brief Generic credentials request + + \see ::kcdb_cred_request for more information + */ +#define KMSG_KCDB_REQUEST 256 +/*@}*/ + +/*! \defgroup kmq_msg_kmm KMSG_KMM subtypes +@{*/ +#define KMSG_KMM_I_REG 1 + +#define KMSG_KMM_I_DONE 2 +/*@}*/ + +/*! \defgroup kmq_msg_act KMSG_ACT subtypes + @{*/ + +/*! \brief One or more actions changed state + + This message is sent in response to a call to + khui_enable_actions() or khui_enable_action() and indicates that + one or more actions have changed their state. + */ +#define KMSG_ACT_ENABLE 1 + +/*! \brief One or more actions changed check state + + Sent in response to khui_check_radio_action() or + khui_check_action() and indicates that one or more actions have + either been checked or unchecked. + */ +#define KMSG_ACT_CHECK 2 + +/*! \brief Refresh action states + + Sent after a batch of modifications were made to action states. + */ +#define KMSG_ACT_REFRESH 3 + +#define KMSG_ACT_BEGIN_CMDLINE 128 + +#define KMSG_ACT_CONTINUE_CMDLINE 129 + +/*@}*/ + +/*! \defgroup kmq_msg_cred KMSG_CRED subtypes + @{*/ +/*! \brief Root credential set changed + + This message is issued when the root credential set successfully + collected credentials from another credential set. + + \a uparam of the message is set to a bitmask indicating the change + that occured. It is a combination of ::KCDB_DELTA_ADD, + ::KCDB_DELTA_DEL and ::KCDB_DELTA_MODIFY. + */ +#define KMSG_CRED_ROOTDELTA 1 + +/*! \brief Re-enumerate credentials + + A notice to all credential providers to re-enumerate their + respective credentials. + + \note May be sent to individual credential subscriptions. +*/ +#define KMSG_CRED_REFRESH 2 + +/*! \brief Change the password + + This message notifies credentials providers that a password change + request has been received. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + */ +#define KMSG_CRED_PASSWORD 16 + +/*! \brief Initiate the process of obtaining new credentials + + The UI sends this message to start the process of obtaining new + credentials. See \ref cred_acq for more information about handling this + message. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \see \ref cred_acq + */ +#define KMSG_CRED_NEW_CREDS 17 + +/*! \brief Renew credentials + + This is a notification sent to individual credentials providers + that a specified identity's credentials should be renewed. + + Message parameters: + - \b vparam : Pointer to a khui_new_creds object + */ +#define KMSG_CRED_RENEW_CREDS 18 + +/*! \brief Dialog setup + + Once KMSG_CRED_NEW_CREDS has been responded to by all the + credential types, the UI creates the dialog windows using the data + supplied in the ::khui_new_creds_by_type structures and issues + this message. Each credentials provider is expected to respond by + finalizing dialog creation operations. + + Message parameters: + - \b vparam : poitner to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_DIALOG_SETUP 19 + +/*! \brief Dialog pre-start + + Sent after all the credentials providers have responded to + KMSG_CRED_DIALOG_SETUP and all the initialization has been + completed. Credentials providers are expected to respond to this + message by loading any default data into the dialog controls for + each credential type. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_DIALOG_PRESTART 20 + +/*! \brief Dialog start + + A notification that the dialog is now in progress. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_DIALOG_START 21 + +/*! \brief The primary identity of the new credentials dialog has changed + + This message is not sent out by the UI, but is reserved here for + use by individual credentials providers. The message may be sent + from the dialog procedure to the plugin. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note Be careful when sending this message. All messages that are + not sent by the system should not be sent via broadcast. + Instead, create a subscription using kmq_create_subscription() + for the individual plugin that you want to send the message + and use one of the per-subscription message functions to send + the actual message. + */ +#define KMSG_CRED_DIALOG_NEW_IDENTITY 22 + +/*! \brief New credentials options have changed. + + This message is not sent out by the UI, but is reserved here for + use by individual credentials providers. The message may be sent + from the dialog procedure to the plugin. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note Be careful when sending this message. All messages that are + not sent by the system should not be sent via broadcast. + Instead, create a subscription using kmq_create_subscription() + for the individual plugin that you want to send the message + and use one of the per-subscription message functions to send + the actual message. + */ +#define KMSG_CRED_DIALOG_NEW_OPTIONS 23 + +/*! \brief Process dialog + + Sent to all the credential providers to look at the contents of + the given ::khui_new_creds structure and do any required + processing. + + If the \a result field in the structure is set to + KHUI_NC_RESULT_GET_CREDS, then new credentials should be obtained + using the given data. + + Set the \a response field in the structure to indicate how the UI + should proceed from here. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_PROCESS 24 + +/*! \brief End a credentials acquisition operation + + A notification that the credentials acquisition operation has + ended. + + Message parameters: + - \b vparam : pointer to a ::khui_new_creds structure + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_END 25 + +/*! \brief Import credentials from the operating system + + Notification to all credentials providers to import any available + credentials from the operating system. + + Message parameters: + - This message does not have any parameters +*/ +#define KMSG_CRED_IMPORT 26 + +/*! \brief Destroy credentials + + Notification that the specified credentials should be destroyed. + Once this message has completed processing a ::KMSG_CRED_REFRESH + message will be issued. + + The credentials that should be destroyed are specified by a + ::khui_action_context structure. The context that should be used + is the selection context. Hence, the credentials that must be + destroyed are the ones lised in the credential set (\a credset). + + Message parameters: + + - \b upram : Unused. Zero. + + - \b vparam : pointer to a ::khui_action_context structure which + describes which credentials need to be destroyed. + + */ +#define KMSG_CRED_DESTROY_CREDS 32 + +#if 0 +/*! \brief Parse an identity + + \note May be sent to individual credential subscriptions. + */ +#define KMSG_CRED_IDENT_PARSE 65 +#endif + +/*! \brief A property page is being launced + + Message parameters: + - \b vparam : pointer to a ::khui_property_sheet structure + */ +#define KMSG_CRED_PP_BEGIN 128 + +/*! \brief A property page is about to be created + + Message parameters: + - \b vparam : pointer to a ::khui_property_sheet structure + + \note This message is merely a notification that the property + sheet is being created. Handlers should not modify the state + of the property sheet or pages at this time. + */ +#define KMSG_CRED_PP_PRECREATE 129 + +/*! \brief A property page has finished processing + + Message parameters: + - \b vparam : pointer to a ::khui_property_sheet structure + */ +#define KMSG_CRED_PP_END 130 + +/*! \brief A property page has been destroyed + + Message parameters: + - \b vparam : pointer to a ::khui_property_sheet structure + */ +#define KMSG_CRED_PP_DESTROY 131 + +/*! \brief An IP address change occurred + + There are no parameters for this message. The NetIDMgr + application handles this message and depending on configuration, + posts message for the individual credentials providers to either + obtain new credentials or renew old ones. + */ +#define KMSG_CRED_ADDR_CHANGE 140 + +/*! \brief Check if a KMSG_CRED subtype is a credentials acquisition message + + Dialog messages are those that deal with the new or initial + credentials acquisition dialog, from initial announcement to + dialog completion. + + Currently, the dialog messages are: + - ::KMSG_CRED_INITIAL_CREDS + - ::KMSG_CRED_NEW_CREDS + - ::KMSG_CRED_RENEW_CREDS + - ::KMSG_CRED_DIALOG_SETUP + - ::KMSG_CRED_DIALOG_PRESTART + - ::KMSG_CRED_DIALOG_START + - ::KMSG_CRED_DIALOG_NEW_IDENTITY + - ::KMSG_CRED_DIALOG_NEW_OPTIONS + - ::KMSG_CRED_PROCESS + - ::KMSG_CRED_END + + All dialog message numbers are allocated in a contigous block. + + Note that while ::KMSG_CRED_PROCESS and ::KMSG_CRED_END are not + specific to dialogs, they are still included in this predicate + because they are also part of the dialog message sequence. + */ +#define IS_CRED_ACQ_MSG(msg) ((msg) >= 16 && (msg) <=31) + +/*@}*/ /* /KMSG_CRED subtypes */ + +/*! \defgroup kmq_msg_alert KMSG_ALERT Subtypes + @{*/ + +/*! \brief Show an alert + + Message parameters: + - \b vparam : held pointer to a ::khui_alert object + + \note The ::khui_alert object will be released when the processing + of this message completes. + */ +#define KMSG_ALERT_SHOW 1 + +/*! \brief Add an alert to the alert queue + + Message parameters: + - \b vparam : held pointer to a ::khui_alert object + + \note the ::khui_alert object will be released when the queued + messages are displayed. + */ +#define KMSG_ALERT_QUEUE 2 + +/*! \brief Show the next queued alert + + There are no message parameters + */ +#define KMSG_ALERT_SHOW_QUEUED 3 + +/*! \brief Check if there are any queued messages and, if so, update the statusbar + + There are no message parameters + */ +#define KMSG_ALERT_CHECK_QUEUE 4 + +/*@}*/ + +/*! \defgroup kmq_msg_ident KMSG_IDENT Subtypes + @{*/ + +/*! \brief Initialize and start the identity provider + + + Sent by the KCDB to notify the identity provider that it is now + the current identity provider. + + Note that unlike regular plugins, an identity provider can be + loaded and inert (not provide any services). Also, the user may + switch between multiple identity providers on the fly. + */ +#define KMSG_IDENT_INIT 1 + +/*! \brief Stop the identity provider + + Sent by the KCDB as notificaton that the identity provider is no + longer the current provider. + */ +#define KMSG_IDENT_EXIT 2 + +/*! \brief Check if an identity name is valid + + This message is sent to the identity provider to verify the syntax + of an identity name. Note that only the syntax of the name is to + be verfied and not the actual physical existence of said identity. + + Message parameters: + + - \b vparam : pointer to ::kcdb_ident_name_xfer object. The + name to be validated will be in the \a name_src member. The + buffer will be NULL terminated with a maximum limit of + KCDB_IDENT_MAXCCH_NAME characters including the terminating + NULL. + The \a result member should be set to one of the following + depending on the result of the validation: + + - KHM_ERROR_SUCCESS : The name was valid + - KHM_ERROR_INVALID_NAME : The name was invalid + */ +#define KMSG_IDENT_VALIDATE_NAME 3 + +/*! \brief Check if an identity is valid + + Sent to the identity provider to verify the validity of the given + identity. The provider should verify that the identity exists and + is in a state where it can be actively used. + + Depending on the result of the validation, the flags of the + identity should be updated. + + Message parameters: + - \b vparam : Handle to an identity cast as a void pointer. + */ +#define KMSG_IDENT_VALIDATE_IDENTITY 4 + +/*! \brief Canonicalize identity name + + The identity provider will be given a name, which it should put in + canonical form, adjusting case and any character replacement or + doing any relevant expansions if applicable, and place it in the + supplied buffer. + + Message parameters: + + - \b vparam : Pointer to a ::kcdb_ident_name_xfer structure + which provides the identity name to canonicalize in the \a + name_src member, and the buffer to store the canonical name + in the \a name_dest member. The \a name_dest buffer is + guaranteed to be at least KCDB_IDENT_MAXCCH_NAME characters + in size. + + If the name cannot be canonicalized for some reason, the + destination buffer should be set to a zero-length string and the + \a result member of the ::kcdb_ident_name_xfer structure should be + set to the error code. If the destination buffer is set to a + zero-length string and \a result is KHM_ERROR_SUCCESS, then the + original name provided in \a name_src is assumed to be already in + canonical form. + */ +#define KMSG_IDENT_CANON_NAME 5 + +/*! \brief Compare names + + Compare two identity names. The names that are given aren't + guaranteed to be in canonical form. The return value should be + akin to strcmp(). + + Message parameters: + + - \b vparam : A pointer to a ::kcdb_ident_name_xfer structure. + The \a name_src member points at the first name, and the \a + name_alt member specifies the second name. The result of the + comparison should be place in \a result. + */ +#define KMSG_IDENT_COMPARE_NAME 6 + +/*! \brief Set the default identity + + Set or unset the default identity. To set the default identity, + the \a uparam parameter will be set to a non-zero value and a + handle to the identity will be specified in \a vparam. To unset + the default identity (i.e. not have a default identity), a zero + value will be specified in \a uparam and no identities will be + specified in \a vparam. + + When setting a default identity, the identity provider will + receive this message prior to the ::KCDB_IDENT_FLAG_DEFAULT bit + being set or reset on any identity. It should return + KHM_ERROR_SUCCESS if the requested operation can be performed. + Returning any other value will abort the operation and will leave + the default identity unchanged. + + When resetting the default identity, this message should be + treated only as a notification. + + Message parameters: + + - \a uparam : Is non-zero if an identity is being made default. If + this is zero, then identity should be the default. + + - \a vparam : A handle to the identity to be made default if \a + uparam is non-zero. NULL otherwise. + + Return value: + + - KHM_ERROR_SUCCESS : The identity should be marked as default + - Any other value : The identity should not be marked as default + + */ +#define KMSG_IDENT_SET_DEFAULT 7 + +/*! \brief Set an identity as searchable + + Set or reset the searchable bit on an identity. If the \a uparam + parameter is non-zero, then the searchable bit is being set. + Otherwise it is being reset. The identity provider should return + KHM_ERROR_SUCCESS in order to indicate that the identity should be + marked as searchable. Any other value will result in the + searchable bit being reset on the identity. + + Message parameters: + + - \a uparam : Is non-zero if the searchable bit is being set. Zero + otherwise. + + - \a vparam : Handle to the identity + + Return value: + + - KHM_ERROR_SUCCESS: The identity should be marked as searchable + - Any other value : The identity should not be marked as default + */ +#define KMSG_IDENT_SET_SEARCHABLE 8 + +/*! \brief Get information about an identity + + */ +#define KMSG_IDENT_GET_INFO 9 + +/*! \brief Enumerate known and accessible identities + */ +#define KMSG_IDENT_ENUM_KNOWN 10 + +/*! \brief Update information about an identity + */ +#define KMSG_IDENT_UPDATE 11 + +/*! \brief Retrieve the user interface callback function + + When obtaining new credentials, the user interface needs to obtain + a callback function which will provide identity selection + controls. + + Message parameters: + + - \a uparam : Not used + + - \a vparam : pointer to a ::khui_ident_new_creds_cb which will + receive the call back. + */ +#define KMSG_IDENT_GET_UI_CALLBACK 12 + +/*! \brief Notification of the creation of an identity + + This should be considered just a notification. The identit + provider does not have an opportunity to veto the creation of an + identity whose name has been found to be valid. However, when + handing this notification, the identity provider can: + + - Change the flags of the identity and/or marking the identity as + invalid. + + - Change the default identity. + + Note that this notification is sent before the general :;KMSG_KCDB + notification of the identity creation is sent. + + Message parameters: + + - \a uparam : Not used. + + - \p vparam : handle to the identity + */ +#define KMSG_IDENT_NOTIFY_CREATE 13 + +/*@}*/ /* /KMSG_IDENT subtypes */ + +/*@}*/ /* / message types */ +/*@}*/ /* / kmq */ + +#endif diff --git a/mechglue/src/windows/identity/include/netidmgr.h b/mechglue/src/windows/identity/include/netidmgr.h new file mode 100644 index 000000000..94e188ff1 --- /dev/null +++ b/mechglue/src/windows/identity/include/netidmgr.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __NETIDMGR_H +#define __NETIDMGR_H + +#include "khdefs.h" + +#include "utils.h" +#include "khuidefs.h" +#include "kmq.h" +#include "khmsgtypes.h" +#include "kcreddb.h" +#include "kherr.h" +#include "kherror.h" +#include "kconfig.h" +#include "kmm.h" +#include "kplugin.h" + +#endif diff --git a/mechglue/src/windows/identity/kconfig/Makefile b/mechglue/src/windows/identity/kconfig/Makefile new file mode 100644 index 000000000..26619c011 --- /dev/null +++ b/mechglue/src/windows/identity/kconfig/Makefile @@ -0,0 +1,51 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=kconfig +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\kconfig.h + +OBJFILES= \ + $(OBJ)\kconfigmain.obj \ + $(OBJ)\api.obj + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) + +# Tests + +test:: util_test + +util_test: $(OBJ)\utiltest.exe + $(OBJ)\utiltest.exe + +$(OBJ)\utiltest.exe: $(OBJ)\utiltest.obj + $(EXECONLINK) $(OBJFILES) + +$(OBJ)\utiltest.obj: test\utiltest.c + $(C2OBJ) diff --git a/mechglue/src/windows/identity/kconfig/api.c b/mechglue/src/windows/identity/kconfig/api.c new file mode 100644 index 000000000..30e5f488f --- /dev/null +++ b/mechglue/src/windows/identity/kconfig/api.c @@ -0,0 +1,2363 @@ +/* +* Copyright (c) 2005 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include +#include + +kconf_conf_space * conf_root = NULL; +kconf_handle * conf_handles = NULL; +kconf_handle * conf_free_handles = NULL; + +CRITICAL_SECTION cs_conf_global; +CRITICAL_SECTION cs_conf_handle; +LONG conf_init = 0; +LONG conf_status = 0; + +void init_kconf(void) { + if(InterlockedIncrement(&conf_init) == 1L) { + /* we are the first */ + InitializeCriticalSection(&cs_conf_global); + EnterCriticalSection(&cs_conf_global); + conf_root = khcint_create_empty_space(); + conf_root->name = PWCSDUP(L"Root"); + conf_root->regpath = PWCSDUP(CONFIG_REGPATHW); + conf_root->refcount++; + conf_status = 1; + InitializeCriticalSection(&cs_conf_handle); + LeaveCriticalSection(&cs_conf_global); + } + /* else assume we are already initialized */ +} + +void exit_kconf(void) { + if(khc_is_config_running()) { + kconf_handle * h; + + EnterCriticalSection(&cs_conf_global); + + conf_init = 0; + conf_status = 0; + + khcint_free_space(conf_root); + + EnterCriticalSection(&cs_conf_handle); + while(conf_free_handles) { + LPOP(&conf_free_handles, &h); + if(h) { + PFREE(h); + } + } + + while(conf_handles) { + LPOP(&conf_handles, &h); + if(h) { + PFREE(h); + } + } + LeaveCriticalSection(&cs_conf_handle); + DeleteCriticalSection(&cs_conf_handle); + + LeaveCriticalSection(&cs_conf_global); + DeleteCriticalSection(&cs_conf_global); + } +} + +kconf_handle * +khcint_handle_from_space(kconf_conf_space * s, khm_int32 flags) +{ + kconf_handle * h; + + EnterCriticalSection(&cs_conf_handle); + LPOP(&conf_free_handles, &h); + if(!h) { + h = PMALLOC(sizeof(kconf_handle)); + assert(h != NULL); + } + ZeroMemory((void *) h, sizeof(kconf_handle)); + + h->magic = KCONF_HANDLE_MAGIC; + khcint_space_hold(s); + h->space = s; + h->flags = flags; + + LPUSH(&conf_handles, h); + LeaveCriticalSection(&cs_conf_handle); + + return h; +} + +/* must be called with cs_conf_global held */ +void +khcint_handle_free(kconf_handle * h) +{ + kconf_handle * lower; + + EnterCriticalSection(&cs_conf_handle); +#ifdef DEBUG + /* check if the handle is actually in use */ + { + kconf_handle * a; + a = conf_handles; + while(a) { + if(h == a) + break; + a = LNEXT(a); + } + + if(a == NULL) { + DebugBreak(); + } + } +#endif + while(h) { + LDELETE(&conf_handles, h); + if(h->space) { + khcint_space_release(h->space); + h->space = NULL; + } + lower = h->lower; + LPUSH(&conf_free_handles, h); + h = lower; + } + LeaveCriticalSection(&cs_conf_handle); +} + +kconf_handle * +khcint_handle_dup(kconf_handle * o) +{ + kconf_handle * h; + kconf_handle * r; + + r = khcint_handle_from_space(o->space, o->flags); + h = r; + + while(o->lower) { + h->lower = khcint_handle_from_space(o->lower->space, o->lower->flags); + + o = o->lower; + h = h->lower; + } + + return r; +} + +void +khcint_space_hold(kconf_conf_space * s) { + InterlockedIncrement(&(s->refcount)); +} + +void +khcint_space_release(kconf_conf_space * s) { + LONG l = InterlockedDecrement(&(s->refcount)); + if(!l) { + EnterCriticalSection(&cs_conf_global); + + /* check again */ + if (!l) { + if(s->regkey_machine) + RegCloseKey(s->regkey_machine); + if(s->regkey_user) + RegCloseKey(s->regkey_user); + s->regkey_machine = NULL; + s->regkey_user = NULL; + + if (s->flags & + (KCONF_SPACE_FLAG_DELETE_M | + KCONF_SPACE_FLAG_DELETE_U)) { + khcint_remove_space(s, s->flags); + } + } + + LeaveCriticalSection(&cs_conf_global); + } +} + +/* case sensitive replacement for RegOpenKeyEx */ +LONG +khcint_RegOpenKeyEx(HKEY hkey, LPCWSTR sSubKey, DWORD ulOptions, + REGSAM samDesired, PHKEY phkResult) { + int i; + wchar_t sk_name[KCONF_MAXCCH_NAME]; + FILETIME ft; + size_t cch; + HKEY hkp = NULL; + const wchar_t * t; + LONG rv = ERROR_SUCCESS; + + hkp = hkey; + t = sSubKey; + + /* check for case insensitive prefix first */ + if (!wcsnicmp(sSubKey, CONFIG_REGPATHW, ARRAYLENGTH(CONFIG_REGPATHW) - 1)) { + HKEY hkt; + + t = sSubKey + (ARRAYLENGTH(CONFIG_REGPATHW) - 1); + +#ifdef DEBUG + assert(*t == L'\0' || *t == L'\\'); +#endif + + rv = RegOpenKeyEx(hkp, + CONFIG_REGPATHW, + ulOptions, + samDesired, + &hkt); + + if (rv != ERROR_SUCCESS) + return rv; + + if (*t == L'\0') { + *phkResult = hkt; + return rv; + } + + t++; + hkp = hkt; + } + + /* descend down the components of the subkey */ + while(TRUE) { + wchar_t * slash; + HKEY hkt; + + slash = wcschr(t, L'\\'); + if (slash == NULL) + break; + + if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name), + t, slash - t))) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + sk_name[slash - t] = L'\0'; + t = slash+1; + + if (khcint_RegOpenKeyEx(hkp, sk_name, ulOptions, samDesired, &hkt) == + ERROR_SUCCESS) { + + if (hkp != hkey) + RegCloseKey(hkp); + hkp = hkt; + + } else { + + rv = ERROR_CANTOPEN; + goto _cleanup; + + } + } + + /* by now hkp is a handle to the parent of the last component in + the subkey. t is a pointer to the last component. */ + + if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + /* go through and find the case sensitive match for the key */ + + for (i=0; ;i++) { + LONG l; + DWORD dw; + + dw = ARRAYLENGTH(sk_name); + l = RegEnumKeyEx(hkp, i, sk_name, &dw, + NULL, NULL, NULL, &ft); + + if (l != ERROR_SUCCESS) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + if (!(wcsncmp(sk_name, t, cch))) { + /* bingo! ?? */ + if (cch < KCONF_MAXCCH_NAME && + (sk_name[cch] == L'\0' || + sk_name[cch] == L'~')) { + rv = RegOpenKeyEx(hkp, sk_name, ulOptions, + samDesired, phkResult); + goto _cleanup; + } + } + } + + _cleanup: + if (hkp != hkey && hkp != NULL) + RegCloseKey(hkp); + + return rv; +} + +LONG +khcint_RegCreateKeyEx(HKEY hKey, + LPCWSTR lpSubKey, + DWORD Reserved, + LPWSTR lpClass, + DWORD dwOptions, + REGSAM samDesired, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + PHKEY phkResult, + LPDWORD lpdwDisposition) { + LONG l; + int i; + long index = 0; + wchar_t sk_name[KCONF_MAXCCH_NAME]; /* hard limit in Windows */ + FILETIME ft; + size_t cch; + const wchar_t * t; + LONG rv = ERROR_SUCCESS; + HKEY hkp = NULL; + + hkp = hKey; + t = lpSubKey; + + /* check for case insensitive prefix first */ + if (!wcsnicmp(lpSubKey, CONFIG_REGPATHW, ARRAYLENGTH(CONFIG_REGPATHW) - 1)) { + HKEY hkt; + + t = lpSubKey + (ARRAYLENGTH(CONFIG_REGPATHW) - 1); + +#ifdef DEBUG + assert(*t == L'\0' || *t == L'\\'); +#endif + + rv = RegCreateKeyEx(hkp, + CONFIG_REGPATHW, + Reserved, + lpClass, + dwOptions, + samDesired, + lpSecurityAttributes, + &hkt, + lpdwDisposition); + + if (rv != ERROR_SUCCESS) + return rv; + + if (*t == L'\0') { + *phkResult = hkt; + return rv; + } + + t++; + hkp = hkt; + } + + while(TRUE) { + wchar_t * slash; + HKEY hkt; + + slash = wcschr(t, L'\\'); + if (slash == NULL) + break; + + if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name), + t, slash - t))) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + sk_name[slash - t] = L'\0'; + t = slash+1; + + if (khcint_RegOpenKeyEx(hkp, sk_name, 0, samDesired, &hkt) == + ERROR_SUCCESS) { + + if (hkp != hKey) + RegCloseKey(hkp); + hkp = hkt; + } else { + + rv = RegCreateKeyEx(hKey, + lpSubKey, + Reserved, + lpClass, + dwOptions, + samDesired, + lpSecurityAttributes, + phkResult, + lpdwDisposition); + goto _cleanup; + } + } + + if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) { + rv = ERROR_CANTOPEN; + goto _cleanup; + } + + for (i=0; ;i++) { + DWORD dw; + + dw = ARRAYLENGTH(sk_name); + l = RegEnumKeyEx(hkp, i, sk_name, &dw, + NULL, NULL, NULL, &ft); + + if (l != ERROR_SUCCESS) + break; + + if (!(wcsncmp(sk_name, t, cch))) { + /* bingo! ?? */ + if (sk_name[cch] == L'\0' || + sk_name[cch] == L'~') { + l = RegOpenKeyEx(hkp, sk_name, 0, + samDesired, phkResult); + if (l == ERROR_SUCCESS && lpdwDisposition) + *lpdwDisposition = REG_OPENED_EXISTING_KEY; + rv = l; + goto _cleanup; + } + } + + if (!wcsnicmp(sk_name, t, cch) && + (sk_name[cch] == L'\0' || + sk_name[cch] == L'~')) { + long new_idx; + + if (sk_name[cch] == L'\0') + new_idx = 1; + else if (cch + 1 < KCONF_MAXCCH_NAME) + new_idx = wcstol(sk_name + (cch + 1), NULL, 10); + else + return ERROR_BUFFER_OVERFLOW; + + assert(new_idx > 0); + + if (new_idx > index) + index = new_idx; + } + } + + if (index != 0) { + if (FAILED(StringCbPrintf(sk_name, sizeof(sk_name), + L"%s~%d", t, index))) + return ERROR_BUFFER_OVERFLOW; + } else { + StringCbCopy(sk_name, sizeof(sk_name), t); + } + + rv = RegCreateKeyEx(hkp, + sk_name, + Reserved, + lpClass, + dwOptions, + samDesired, + lpSecurityAttributes, + phkResult, + lpdwDisposition); + + _cleanup: + + if (hkp != hKey && hkp != NULL) + RegCloseKey(hkp); + + return rv; +} + + +HKEY +khcint_space_open_key(kconf_conf_space * s, khm_int32 flags) { + HKEY hk = NULL; + int nflags = 0; + DWORD disp; + if(flags & KCONF_FLAG_MACHINE) { + if(s->regkey_machine) + return s->regkey_machine; + if((khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0, + KEY_READ | KEY_WRITE, &hk) != + ERROR_SUCCESS) && + !(flags & KHM_PERM_WRITE)) { + + if(khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0, + KEY_READ, &hk) == ERROR_SUCCESS) { + nflags = KHM_PERM_READ; + } + + } + if(!hk && (flags & KHM_FLAG_CREATE)) { + + khcint_RegCreateKeyEx(HKEY_LOCAL_MACHINE, + s->regpath, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk, + &disp); + } + if(hk) { + EnterCriticalSection(&cs_conf_global); + s->regkey_machine = hk; + s->regkey_machine_flags = nflags; + LeaveCriticalSection(&cs_conf_global); + } + + return hk; + } else { + if(s->regkey_user) + return s->regkey_user; + if((khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0, + KEY_READ | KEY_WRITE, &hk) != + ERROR_SUCCESS) && + !(flags & KHM_PERM_WRITE)) { + if(khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0, + KEY_READ, &hk) == ERROR_SUCCESS) { + nflags = KHM_PERM_READ; + } + } + if(!hk && (flags & KHM_FLAG_CREATE)) { + khcint_RegCreateKeyEx(HKEY_CURRENT_USER, + s->regpath, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk, + &disp); + } + if(hk) { + EnterCriticalSection(&cs_conf_global); + s->regkey_user = hk; + s->regkey_user_flags = nflags; + LeaveCriticalSection(&cs_conf_global); + } + + return hk; + } +} + +KHMEXP khm_int32 KHMAPI +khc_shadow_space(khm_handle upper, khm_handle lower) +{ + kconf_handle * h; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(upper)) + return KHM_ERROR_INVALID_PARAM; + + h = (kconf_handle *) upper; + + EnterCriticalSection(&cs_conf_handle); + if(h->lower) { + LeaveCriticalSection(&cs_conf_handle); + EnterCriticalSection(&cs_conf_global); + khcint_handle_free(h->lower); + LeaveCriticalSection(&cs_conf_global); + EnterCriticalSection(&cs_conf_handle); + h->lower = NULL; + } + + if(khc_is_handle(lower)) { + kconf_handle * l; + kconf_handle * lc; + + l = (kconf_handle *) lower; + LeaveCriticalSection(&cs_conf_handle); + lc = khcint_handle_dup(l); + EnterCriticalSection(&cs_conf_handle); + h->lower = lc; + } + LeaveCriticalSection(&cs_conf_handle); + + return KHM_ERROR_SUCCESS; +} + +kconf_conf_space * +khcint_create_empty_space(void) { + kconf_conf_space * r; + + r = PMALLOC(sizeof(kconf_conf_space)); + assert(r != NULL); + ZeroMemory(r,sizeof(kconf_conf_space)); + + return r; +} + +void +khcint_free_space(kconf_conf_space * r) { + kconf_conf_space * c; + + if(!r) + return; + + LPOP(&r->children, &c); + while(c) { + khcint_free_space(c); + LPOP(&r->children, &c); + } + + if(r->name) + PFREE(r->name); + + if(r->regpath) + PFREE(r->regpath); + + if(r->regkey_machine) + RegCloseKey(r->regkey_machine); + + if(r->regkey_user) + RegCloseKey(r->regkey_user); + + PFREE(r); +} + +khm_int32 +khcint_open_space_int(kconf_conf_space * parent, + wchar_t * sname, size_t n_sname, + khm_int32 flags, kconf_conf_space **result) { + kconf_conf_space * p; + kconf_conf_space * c; + HKEY pkey = NULL; + HKEY ckey = NULL; + wchar_t buf[KCONF_MAXCCH_NAME]; + + if(!parent) + p = conf_root; + else + p = parent; + + if(n_sname >= KCONF_MAXCCH_NAME || n_sname <= 0) + return KHM_ERROR_INVALID_PARAM; + + /*SAFE: buf: buffer size == KCONF_MAXCCH_NAME * wchar_t > + n_sname * wchar_t */ + wcsncpy(buf, sname, n_sname); + buf[n_sname] = L'\0'; + + /* see if there is already a config space by this name. if so, + return it. Note that if the configuration space is specified in a + schema, we would find it here. */ + EnterCriticalSection(&cs_conf_global); + c = TFIRSTCHILD(p); + while(c) { + if(c->name && !wcscmp(c->name, buf)) + break; + + c = LNEXT(c); + } + LeaveCriticalSection(&cs_conf_global); + + if(c) { + khcint_space_hold(c); + *result = c; + return KHM_ERROR_SUCCESS; + } + + if(!(flags & KHM_FLAG_CREATE)) { + + /* we are not creating the space, so it must exist in the form of a + registry key in HKLM or HKCU. If it existed as a schema, we + would have already retured it above. */ + + if (flags & KCONF_FLAG_USER) + pkey = khcint_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_USER); + + if((!pkey || + (khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) != + ERROR_SUCCESS)) + && (flags & KCONF_FLAG_MACHINE)) { + + pkey = khcint_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_MACHINE); + if(!pkey || + (khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) != + ERROR_SUCCESS)) { + *result = NULL; + + return KHM_ERROR_NOT_FOUND; + } + } + + if(ckey) { + RegCloseKey(ckey); + ckey = NULL; + } + } + + c = khcint_create_empty_space(); + + /*SAFE: buf: is of known length < KCONF_MAXCCH_NAME */ + c->name = PWCSDUP(buf); + + /*SAFE: p->regpath: is valid since it was set using this same + function. */ + /*SAFE: buf: see above */ + c->regpath = PMALLOC((wcslen(p->regpath) + wcslen(buf) + 2) * sizeof(wchar_t)); + + assert(c->regpath != NULL); + +#pragma warning( push ) +#pragma warning( disable: 4995 ) + /*SAFE: c->regpath: allocated above to be big enough */ + /*SAFE: p->regpath: see above */ + wcscpy(c->regpath, p->regpath); + wcscat(c->regpath, L"\\"); + /*SAFE: buf: see above */ + wcscat(c->regpath, buf); +#pragma warning( pop ) + + khcint_space_hold(c); + + EnterCriticalSection(&cs_conf_global); + TADDCHILD(p,c); + LeaveCriticalSection(&cs_conf_global); + + *result = c; + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khc_open_space(khm_handle parent, wchar_t * cspace, khm_int32 flags, + khm_handle * result) { + kconf_handle * h; + kconf_conf_space * p; + kconf_conf_space * c = NULL; + size_t cbsize; + wchar_t * str; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) { + return KHM_ERROR_NOT_READY; + } + + if(!result || (parent && !khc_is_handle(parent))) + return KHM_ERROR_INVALID_PARAM; + + if(!parent) + p = conf_root; + else { + h = (kconf_handle *) parent; + p = khc_space_from_handle(parent); + } + + khcint_space_hold(p); + + /* if none of these flags are specified, make it seem like all of + them were */ + if(!(flags & KCONF_FLAG_USER) && + !(flags & KCONF_FLAG_MACHINE) && + !(flags & KCONF_FLAG_SCHEMA)) + flags |= KCONF_FLAG_USER | KCONF_FLAG_MACHINE | KCONF_FLAG_SCHEMA; + + if(cspace == NULL) { + khcint_space_release(p); + *result = (khm_handle) khcint_handle_from_space(p, flags); + return KHM_ERROR_SUCCESS; + } + + if(FAILED(StringCbLength(cspace, KCONF_MAXCB_PATH, &cbsize))) { + khcint_space_release(p); + *result = NULL; + return KHM_ERROR_INVALID_PARAM; + } + + str = cspace; + while(TRUE) { + wchar_t * end = NULL; + + if (!(flags & KCONF_FLAG_NOPARSENAME)) { + + end = wcschr(str, L'\\'); /* safe because cspace was + validated above */ +#if 0 + if(!end) + end = wcschr(str, L'/'); /* safe because cspace was + validated above */ +#endif + } + + if(!end) { + if(flags & KCONF_FLAG_TRAILINGVALUE) { + /* we are at the value component */ + c = p; + khcint_space_hold(c); + break; + } else + end = str + wcslen(str); /* safe because cspace was + validated above */ + } + + rv = khcint_open_space_int(p, str, end - str, flags, &c); + + if(KHM_SUCCEEDED(rv) && (*end == L'\\' +#if 0 + || *end == L'/' +#endif + )) { + khcint_space_release(p); + p = c; + c = NULL; + str = end+1; + } + else + break; + } + + khcint_space_release(p); + if(KHM_SUCCEEDED(rv)) { + *result = khcint_handle_from_space(c, flags); + } else + *result = NULL; + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_close_space(khm_handle csp) { + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(csp)) + return KHM_ERROR_INVALID_PARAM; + + khcint_handle_free((kconf_handle *) csp); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khc_read_string(khm_handle pconf, + wchar_t * pvalue, + wchar_t * buf, + khm_size * bufsize) +{ + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + do { + HKEY hku = NULL; + HKEY hkm = NULL; + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + DWORD size; + DWORD type; + LONG hr; + + int i; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + + free_space = 1; +#if 0 + wchar_t * back, * forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; /* works for nulls too */ +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + goto _shadow; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + size = (DWORD) *bufsize; + if(hku) { + hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_SZ) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + *bufsize = size; + /* if buf==NULL, RegQueryValueEx will return success and just return the + required buffer size in 'size' */ + rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG; + goto _exit; + } + } else { + if(hr == ERROR_MORE_DATA) { + *bufsize = size; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + } + } + + size = (DWORD) *bufsize; + if(hkm) { + hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_SZ) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + *bufsize = size; + rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG; + goto _exit; + } + } else { + if(hr == ERROR_MORE_DATA) { + *bufsize = size; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + } + } + + if(c->schema && khc_is_schema_handle(conf)) { + for(i=0;inSchema;i++) { + if(c->schema[i].type == KC_STRING && !wcscmp(value, c->schema[i].name)) { + /* found it */ + size_t cbsize = 0; + + if(!c->schema[i].value) { + rv = KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(FAILED(StringCbLength((wchar_t *) c->schema[i].value, KCONF_MAXCB_STRING, &cbsize))) { + rv = KHM_ERROR_NOT_FOUND; + goto _exit; + } + cbsize += sizeof(wchar_t); + + if(!buf || *bufsize < cbsize) { + *bufsize = cbsize; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + + StringCbCopy(buf, *bufsize, (wchar_t *) c->schema[i].value); + *bufsize = cbsize; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + +_shadow: + if(free_space && conf) + khc_close_space(conf); + + if(khc_is_shadowed(pconf)) { + pconf = khc_shadow(pconf); + continue; + } else { + rv = KHM_ERROR_NOT_FOUND; + break; + } + +_exit: + if(free_space && conf) + khc_close_space(conf); + break; + + } while(TRUE); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_read_int32(khm_handle pconf, wchar_t * pvalue, khm_int32 * buf) { + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!buf || !pvalue) + return KHM_ERROR_INVALID_PARAM; + + do { + DWORD size; + DWORD type; + LONG hr; + HKEY hku = NULL; + HKEY hkm = NULL; + + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + int i; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; +#if 0 + wchar_t * back, * forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf) || !buf) + goto _shadow; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + size = sizeof(DWORD); + if(hku) { + hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_DWORD) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + + size = sizeof(DWORD); + if(hkm) { + hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_DWORD) { + rv= KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + rv= KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + + if(c->schema && khc_is_schema_handle(conf)) { + for(i=0;inSchema;i++) { + if(c->schema[i].type == KC_INT32 && !wcscmp(value, c->schema[i].name)) { + *buf = (khm_int32) c->schema[i].value; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } +_shadow: + if(free_space && conf) + khc_close_space(conf); + + if(khc_is_shadowed(pconf)) { + pconf = khc_shadow(pconf); + continue; + } else { + rv = KHM_ERROR_NOT_FOUND; + break; + } +_exit: + if(free_space && conf) + khc_close_space(conf); + break; + } + while(TRUE); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_read_int64(khm_handle pconf, wchar_t * pvalue, khm_int64 * buf) { + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + do { + DWORD size; + DWORD type; + LONG hr; + HKEY hku = NULL; + HKEY hkm = NULL; + + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + int i; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf) || !buf) + goto _shadow; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + size = sizeof(khm_int64); + if(hku) { + hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_QWORD) { + rv= KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + + size = sizeof(khm_int64); + if(hkm) { + hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_QWORD) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + + if(c->schema && khc_is_schema_handle(conf)) { + for(i=0;inSchema;i++) { + if(c->schema[i].type == KC_INT64 && !wcscmp(value, c->schema[i].name)) { + *buf = (khm_int64) c->schema[i].value; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } + } + +_shadow: + if(free_space && conf) + khc_close_space(conf); + if(khc_is_shadowed(pconf)) { + pconf = khc_shadow(pconf); + continue; + } else { + rv = KHM_ERROR_NOT_FOUND; + break; + } + +_exit: + if(free_space && conf) + khc_close_space(conf); + break; + + } while(TRUE); + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_read_binary(khm_handle pconf, wchar_t * pvalue, + void * buf, khm_size * bufsize) { + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + do { + DWORD size; + DWORD type; + LONG hr; + HKEY hku = NULL; + HKEY hkm = NULL; + + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + goto _shadow; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + goto _shadow; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + + if(khc_is_machine_handle(conf)) + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + size = (DWORD) *bufsize; + if(hku) { + hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_BINARY) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + *bufsize = size; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } else { + if(hr == ERROR_MORE_DATA) { + *bufsize = size; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + } + } + + size = (DWORD) *bufsize; + if(hkm) { + hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size); + if(hr == ERROR_SUCCESS) { + if(type != REG_BINARY) { + rv = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + else { + *bufsize = size; + rv = KHM_ERROR_SUCCESS; + goto _exit; + } + } else { + if(hr == ERROR_MORE_DATA) { + *bufsize = size; + rv = KHM_ERROR_TOO_LONG; + goto _exit; + } + } + } + + /* binary values aren't supported in schema */ +_shadow: + if(free_space && conf) + khc_close_space(conf); + if(khc_is_shadowed(pconf)) { + pconf = khc_shadow(pconf); + continue; + } else { + rv = KHM_ERROR_NOT_FOUND; + break; + } + +_exit: + if(free_space && conf) + khc_close_space(conf); + break; + + }while (TRUE); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_write_string(khm_handle pconf, + wchar_t * pvalue, + wchar_t * buf) +{ + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + size_t cbsize; + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) + return KHM_ERROR_INVALID_OPERATION; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARAM; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf) || !buf) { + rv = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + c = khc_space_from_handle(conf); + + if(FAILED(StringCbLength(buf, KCONF_MAXCB_STRING, &cbsize))) { + rv = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cbsize += sizeof(wchar_t); + + if(khc_is_user_handle(conf)) { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); + } + + hr = RegSetValueEx(pk, value, 0, REG_SZ, (LPBYTE) buf, (DWORD) cbsize); + + if(hr != ERROR_SUCCESS) + rv = KHM_ERROR_INVALID_OPERATION; + +_exit: + if(free_space) + khc_close_space(conf); + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_write_int32(khm_handle pconf, + wchar_t * pvalue, + khm_int32 buf) +{ + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) + return KHM_ERROR_INVALID_OPERATION; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARAM; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle( conf); + + if(khc_is_user_handle(conf)) { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); + } + + hr = RegSetValueEx(pk, value, 0, REG_DWORD, (LPBYTE) &buf, sizeof(khm_int32)); + + if(hr != ERROR_SUCCESS) + rv = KHM_ERROR_INVALID_OPERATION; + + if(free_space) + khc_close_space(conf); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_write_int64(khm_handle pconf, wchar_t * pvalue, khm_int64 buf) { + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) + return KHM_ERROR_INVALID_OPERATION; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARAM; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle( conf); + + if(khc_is_user_handle(conf)) { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); + } + + hr = RegSetValueEx(pk, value, 0, REG_QWORD, (LPBYTE) &buf, sizeof(khm_int64)); + + if(hr != ERROR_SUCCESS) + rv = KHM_ERROR_INVALID_OPERATION; + + if(free_space) + khc_close_space(conf); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_write_binary(khm_handle pconf, + wchar_t * pvalue, + void * buf, khm_size bufsize) { + HKEY pk = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + LONG hr; + wchar_t * value = NULL; + int free_space = 0; + khm_handle conf = NULL; + + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf)) + return KHM_ERROR_INVALID_OPERATION; + + if(wcschr(pvalue, L'\\') +#if 0 + || wcschr(pvalue, L'/') +#endif + ) { + if(KHM_FAILED(khc_open_space( + pconf, + pvalue, + KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0), + &conf))) + return KHM_ERROR_INVALID_PARAM; + free_space = 1; +#if 0 + wchar_t * back, *forward; + + back = wcsrchr(pvalue, L'\\'); + forward = wcsrchr(pvalue, L'/'); + value = (back > forward)?back:forward; +#else + value = wcsrchr(pvalue, L'\\'); +#endif + } else { + value = pvalue; + conf = pconf; + free_space = 0; + } + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(khc_is_user_handle(conf)) { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE); + } else { + pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE); + } + + hr = RegSetValueEx(pk, value, 0, REG_BINARY, buf, (DWORD) bufsize); + + if(hr != ERROR_SUCCESS) + rv = KHM_ERROR_INVALID_OPERATION; + + if(free_space) + khc_close_space(conf); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_get_config_space_name(khm_handle conf, + wchar_t * buf, khm_size * bufsize) { + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(!c->name) { + if(buf && *bufsize > 0) + buf[0] = L'\0'; + else { + *bufsize = sizeof(wchar_t); + rv = KHM_ERROR_TOO_LONG; + } + } else { + size_t cbsize; + + if(FAILED(StringCbLength(c->name, KCONF_MAXCB_NAME, &cbsize))) + return KHM_ERROR_UNKNOWN; + + cbsize += sizeof(wchar_t); + + if(!buf || cbsize > *bufsize) { + *bufsize = cbsize; + rv = KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *bufsize, c->name); + *bufsize = cbsize; + } + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_get_config_space_parent(khm_handle conf, khm_handle * parent) { + kconf_conf_space * c; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(c == conf_root || c->parent == conf_root) + *parent = NULL; + else + *parent = khcint_handle_from_space(c->parent, khc_handle_flags(conf)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khc_get_type(khm_handle conf, wchar_t * value) { + HKEY hkm = NULL; + HKEY hku = NULL; + kconf_conf_space * c; + khm_int32 rv; + LONG hr; + DWORD type = 0; + + if(!khc_is_config_running()) + return KC_NONE; + + if(!khc_is_handle(conf)) + return KC_NONE; + + c = (kconf_conf_space *) conf; + + if(!khc_is_machine_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + if(hku) + hr = RegQueryValueEx(hku, value, NULL, &type, NULL, NULL); + if(!hku || hr != ERROR_SUCCESS) + hr = RegQueryValueEx(hkm, value, NULL, &type, NULL, NULL); + if(((!hku && !hkm) || hr != ERROR_SUCCESS) && c->schema) { + int i; + + for(i=0; inSchema; i++) { + if(!wcscmp(c->schema[i].name, value)) { + return c->schema[i].type; + } + } + + return KC_NONE; + } + + switch(type) { + case REG_MULTI_SZ: + case REG_SZ: + rv = KC_STRING; + break; + case REG_DWORD: + rv = KC_INT32; + break; + case REG_QWORD: + rv = KC_INT64; + break; + case REG_BINARY: + rv = KC_BINARY; + break; + default: + rv = KC_NONE; + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_value_exists(khm_handle conf, wchar_t * value) { + HKEY hku = NULL; + HKEY hkm = NULL; + kconf_conf_space * c; + khm_int32 rv = 0; + DWORD t; + int i; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(!khc_is_machine_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + if(hku && (RegQueryValueEx(hku, value, NULL, &t, NULL, NULL) == ERROR_SUCCESS)) + rv |= KCONF_FLAG_USER; + if(hkm && (RegQueryValueEx(hkm, value, NULL, &t, NULL, NULL) == ERROR_SUCCESS)) + rv |= KCONF_FLAG_MACHINE; + + if(c->schema) { + for(i=0; inSchema; i++) { + if(!wcscmp(c->schema[i].name, value)) { + rv |= KCONF_FLAG_SCHEMA; + break; + } + } + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_remove_value(khm_handle conf, wchar_t * value, khm_int32 flags) { + HKEY hku = NULL; + HKEY hkm = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_NOT_FOUND; + DWORD t; + LONG l; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + if(!khc_is_machine_handle(conf)) + hku = khcint_space_open_key(c, KHM_PERM_READ); + hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE); + + if((flags == 0 || + (flags & KCONF_FLAG_USER)) && + hku && (RegQueryValueEx(hku, value, NULL, + &t, NULL, NULL) == ERROR_SUCCESS)) { + l = RegDeleteValue(hku, value); + if (l == ERROR_SUCCESS) + rv = KHM_ERROR_SUCCESS; + else + rv = KHM_ERROR_UNKNOWN; + } + if((flags == 0 || + (flags & KCONF_FLAG_MACHINE)) && + hkm && (RegQueryValueEx(hkm, value, NULL, + &t, NULL, NULL) == ERROR_SUCCESS)) { + l = RegDeleteValue(hkm, value); + if (l == ERROR_SUCCESS) + rv = (rv == KHM_ERROR_UNKNOWN)?KHM_ERROR_PARTIAL: + KHM_ERROR_SUCCESS; + else + rv = (rv == KHM_ERROR_SUCCESS)?KHM_ERROR_PARTIAL: + KHM_ERROR_UNKNOWN; + } + + return rv; +} + +khm_int32 +khcint_remove_space(kconf_conf_space * c, khm_int32 flags) { + kconf_conf_space * cc; + kconf_conf_space * cn; + + /* TODO: if this is the last child space and the parent is marked + for deletion, delete the parent as well. */ + + cc = TFIRSTCHILD(c); + while (cc) { + cn = LNEXT(cc); + + khcint_remove_space(cc, flags); + + cc = cn; + } + + cc = TFIRSTCHILD(c); + if (!cc) { + kconf_conf_space * p; + + if (c->refcount) { + c->flags |= (flags & + (KCONF_SPACE_FLAG_DELETE_M | + KCONF_SPACE_FLAG_DELETE_U)); + } else { + p = TPARENT(c); + + TDELCHILD(p, c); + + if (c->regpath) { + if (flags & KCONF_SPACE_FLAG_DELETE_U) + RegDeleteKey(HKEY_CURRENT_USER, + c->regpath); + if (flags & KCONF_SPACE_FLAG_DELETE_M) + RegDeleteKey(HKEY_LOCAL_MACHINE, + c->regpath); + } + + khcint_free_space(c); + } + } else { + c->flags |= (flags & + (KCONF_SPACE_FLAG_DELETE_M | + KCONF_SPACE_FLAG_DELETE_U)); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khc_remove_space(khm_handle conf) { + /* + - mark this space as well as all child spaces as + 'delete-on-close' using flags. Mark should indicate which + repository to delete the space from. (user/machine) + + - When each subspace is released, check if it has been marked + for deletion. If so, delete the marked spaces as well as + removing the space from kconf space tree. + + - When removing a subspace from a space, check if the parent + space has any children left. If there are none, check if the + parent space is also marked for deletion. + */ + HKEY hku = NULL; + HKEY hkm = NULL; + kconf_conf_space * c; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_int32 flags = 0; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + c = khc_space_from_handle(conf); + + EnterCriticalSection(&cs_conf_global); + + if (khc_is_machine_handle(conf)) + flags |= KCONF_SPACE_FLAG_DELETE_M; + if (khc_is_user_handle(conf)) + flags |= KCONF_SPACE_FLAG_DELETE_U; + + rv = khcint_remove_space(c, flags); + + LeaveCriticalSection(&cs_conf_global); + + return rv; +} + +khm_boolean +khcint_is_valid_name(wchar_t * name) +{ + size_t cbsize; + if(FAILED(StringCbLength(name, KCONF_MAXCB_NAME, &cbsize))) + return FALSE; + return TRUE; +} + +khm_int32 +khcint_validate_schema(kconf_schema * schema, + int begin, + int *end) +{ + int i; + int state = 0; + int end_found = 0; + + i=begin; + while(!end_found) { + switch(state) { + case 0: /* initial. this record should start a config space */ + if(!khcint_is_valid_name(schema[i].name) || + schema[i].type != KC_SPACE) + return KHM_ERROR_INVALID_PARAM; + state = 1; + break; + + case 1: /* we are inside a config space, in the values area */ + if(!khcint_is_valid_name(schema[i].name)) + return KHM_ERROR_INVALID_PARAM; + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_validate_schema(schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + state = 2; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + } else { + if(schema[i].type != KC_STRING && + schema[i].type != KC_INT32 && + schema[i].type != KC_INT64 && + schema[i].type != KC_BINARY) + return KHM_ERROR_INVALID_PARAM; + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_validate_schema(schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + } else { + return KHM_ERROR_INVALID_PARAM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARAM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +khm_int32 +khcint_load_schema_i(khm_handle parent, kconf_schema * schema, + int begin, int * end) +{ + int i; + int state = 0; + int end_found = 0; + kconf_conf_space * thisconf = NULL; + khm_handle h; + + i=begin; + while(!end_found) { + switch(state) { + case 0: /* initial. this record should start a config space */ + if(KHM_FAILED(khc_open_space(parent, schema[i].name, + KHM_FLAG_CREATE, &h))) + return KHM_ERROR_INVALID_PARAM; + thisconf = khc_space_from_handle(h); + thisconf->schema = schema + (begin + 1); + state = 1; + break; + + case 1: /* we are inside a config space, in the values area */ + if(schema[i].type == KC_SPACE) { + thisconf->nSchema = i - (begin + 1); + if(KHM_FAILED(khcint_load_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + state = 2; + } else if(schema[i].type == KC_ENDSPACE) { + thisconf->nSchema = i - (begin + 1); + end_found = 1; + if(end) + *end = i; + khc_close_space(h); + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_load_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + khc_close_space(h); + } else { + return KHM_ERROR_INVALID_PARAM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARAM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khc_load_schema(khm_handle conf, kconf_schema * schema) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(conf && !khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(khcint_validate_schema(schema, 0, NULL))) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_conf_global); + rv = khcint_load_schema_i(conf, schema, 0, NULL); + LeaveCriticalSection(&cs_conf_global); + + return rv; +} + +khm_int32 +khcint_unload_schema_i(khm_handle parent, kconf_schema * schema, + int begin, int * end) +{ + int i; + int state = 0; + int end_found = 0; + kconf_conf_space * thisconf = NULL; + khm_handle h; + + i=begin; + while(!end_found) { + switch(state) { + case 0: /* initial. this record should start a config space */ + if(KHM_FAILED(khc_open_space(parent, schema[i].name, 0, &h))) + return KHM_ERROR_INVALID_PARAM; + thisconf = khc_space_from_handle(h); + if(thisconf->schema == (schema + (begin + 1))) { + thisconf->schema = NULL; + thisconf->nSchema = 0; + } + state = 1; + break; + + case 1: /* we are inside a config space, in the values area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_unload_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + state = 2; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + khc_close_space(h); + } + break; + + case 2: /* we are inside a config space, in the subspace area */ + if(schema[i].type == KC_SPACE) { + if(KHM_FAILED(khcint_unload_schema_i(h, schema, i, &i))) + return KHM_ERROR_INVALID_PARAM; + } else if(schema[i].type == KC_ENDSPACE) { + end_found = 1; + if(end) + *end = i; + khc_close_space(h); + } else { + return KHM_ERROR_INVALID_PARAM; + } + break; + + default: + /* unreachable */ + return KHM_ERROR_INVALID_PARAM; + } + i++; + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khc_unload_schema(khm_handle conf, kconf_schema * schema) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(conf && !khc_is_handle(conf)) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(khcint_validate_schema(schema, 0, NULL))) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_conf_global); + rv = khcint_unload_schema_i(conf, schema, 0, NULL); + LeaveCriticalSection(&cs_conf_global); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_enum_subspaces(khm_handle conf, + khm_handle prev, + khm_handle * next) +{ + kconf_conf_space * s; + kconf_conf_space * c; + kconf_conf_space * p; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!khc_is_handle(conf) || next == NULL || + (prev != NULL && !khc_is_handle(prev))) + return KHM_ERROR_INVALID_PARAM; + + s = khc_space_from_handle(conf); + + if(prev == NULL) { + /* first off, we enumerate all the registry spaces regardless of + whether the handle is applicable for some registry space or not. + See notes for khc_begin_enum_subspaces() for reasons as to why + this is done (notes are in kconfig.h)*/ + + /* go through the user hive first */ + { + HKEY hk_conf; + + hk_conf = khcint_space_open_key(s, 0); + if(hk_conf) { + wchar_t name[KCONF_MAXCCH_NAME]; + khm_handle h; + int idx; + + idx = 0; + while(RegEnumKey(hk_conf, idx, + name, ARRAYLENGTH(name)) == ERROR_SUCCESS) { + wchar_t * tilde; + tilde = wcschr(name, L'~'); + if (tilde) + *tilde = 0; + if(KHM_SUCCEEDED(khc_open_space(conf, name, 0, &h))) + khc_close_space(h); + idx++; + } + } + } + + /* go through the machine hive next */ + { + HKEY hk_conf; + + hk_conf = khcint_space_open_key(s, KCONF_FLAG_MACHINE); + if(hk_conf) { + wchar_t name[KCONF_MAXCCH_NAME]; + khm_handle h; + int idx; + + idx = 0; + while(RegEnumKey(hk_conf, idx, + name, ARRAYLENGTH(name)) == ERROR_SUCCESS) { + wchar_t * tilde; + tilde = wcschr(name, L'~'); + if (tilde) + *tilde = 0; + + if(KHM_SUCCEEDED(khc_open_space(conf, name, + KCONF_FLAG_MACHINE, &h))) + khc_close_space(h); + idx++; + } + } + } + + /* don't need to go through schema, because that was already + done when the schema was loaded. */ + } + + /* at last we are now ready to return the results */ + EnterCriticalSection(&cs_conf_global); + if(prev == NULL) { + c = TFIRSTCHILD(s); + rv = KHM_ERROR_SUCCESS; + } else { + p = khc_space_from_handle(prev); + if(TPARENT(p) == s) + c = LNEXT(p); + else + c = NULL; + } + LeaveCriticalSection(&cs_conf_global); + + if(prev != NULL) + khc_close_space(prev); + + if(c) { + *next = khcint_handle_from_space(c, khc_handle_flags(conf)); + rv = KHM_ERROR_SUCCESS; + } else { + *next = NULL; + rv = KHM_ERROR_NOT_FOUND; + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_write_multi_string(khm_handle conf, wchar_t * value, wchar_t * buf) +{ + size_t cb; + wchar_t vbuf[KCONF_MAXCCH_STRING]; + wchar_t *tb; + khm_int32 rv; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + if(!khc_is_handle(conf) || buf == NULL || value == NULL) + return KHM_ERROR_INVALID_PARAM; + + if(multi_string_to_csv(NULL, &cb, buf) != KHM_ERROR_TOO_LONG) + return KHM_ERROR_INVALID_PARAM; + + if (cb < sizeof(vbuf)) + tb = vbuf; + else + tb = PMALLOC(cb); + + assert(tb != NULL); + + multi_string_to_csv(tb, &cb, buf); + rv = khc_write_string(conf, value, tb); + + if (tb != vbuf) + PFREE(tb); + return rv; +} + +KHMEXP khm_int32 KHMAPI +khc_read_multi_string(khm_handle conf, wchar_t * value, + wchar_t * buf, khm_size * bufsize) +{ + wchar_t vbuf[KCONF_MAXCCH_STRING]; + wchar_t * tb; + khm_size cbbuf; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!khc_is_config_running()) + return KHM_ERROR_NOT_READY; + + if(!bufsize) + return KHM_ERROR_INVALID_PARAM; + + rv = khc_read_string(conf, value, NULL, &cbbuf); + if(rv != KHM_ERROR_TOO_LONG) + return rv; + + if (cbbuf < sizeof(vbuf)) + tb = vbuf; + else + tb = PMALLOC(cbbuf); + + assert(tb != NULL); + + rv = khc_read_string(conf, value, tb, &cbbuf); + + if(KHM_FAILED(rv)) + goto _exit; + + rv = csv_to_multi_string(buf, bufsize, tb); + +_exit: + if (tb != vbuf) + PFREE(tb); + + return rv; +} diff --git a/mechglue/src/windows/identity/kconfig/kconfig.h b/mechglue/src/windows/identity/kconfig/kconfig.h new file mode 100644 index 000000000..4e9a49e9b --- /dev/null +++ b/mechglue/src/windows/identity/kconfig/kconfig.h @@ -0,0 +1,879 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCONFIG_H +#define __KHIMAIRA_KCONFIG_H + +#include +#include + +/*! \defgroup kconf NetIDMgr Configuration Provider */ +/*@{*/ + +/*! \brief Configuration schema descriptor record + + The schema descriptor is a convenient way to provide a default set + of configuration options for a part of an application. It + describes the configuration spaces and the values and subspaces + contained in each space. + + \see kconf_load_schema() +*/ +typedef struct kconf_schema_t { + wchar_t * name; /*!< name of the object being described. + Optional for KC_ENDSPACE type object, + but required for everything else. + Names can be upto KCONF_MAXCCH_NAME + characters in length. */ + khm_int32 type; /*!< type of the object. Can be one of + KC_SPACE, KC_ENDSPACE, KC_INT32, + KC_INT64, KC_STRING or KC_BINARY */ + khm_ui_8 value; /*!< the value of the object. It is not + used for KC_SPACE and KC_ENDSPACE + typed objects. For a KC_STRING, this + contains a pointer to the string + value. The string should not be + longer than KCONF_MAXCCH_STRING + characters. KC_INT32 and KC_INT64 + objects store the value directly in + this field, while KC_BINARY objects do + not support defining a default value + here. */ + wchar_t * description;/*!< a friendly description of the value + or configuration space */ +} kconf_schema; + +/*! \name Configuration data types + @{*/ +/*! \brief Not a known type */ +#define KC_NONE 0 + +/*! \brief When used as ::kconf_schema \a type, defines the start of a configuration space. + + There should be a subsequent KC_ENDSPACE record in the schema + which defines the end of this configuration space. + + \a name specifies the name of the configuration space. Optionally + use \a description to provide a description.*/ +#define KC_SPACE 1 + +/*! \brief Ends a configuration space started with KC_SPACE */ +#define KC_ENDSPACE 2 + +/*! \brief A 32 bit integer + + Specifies a configuration parameter named \a name which is of this + type. Use \a description to provide an optional description of + the value. + + \a value specifies a default value for this parameter in the lower + 32 bits. +*/ +#define KC_INT32 3 + +/*! \brief A 64 bit integer + + Specifies a configuration parameter named \a name which is of this + type. Use \a description to provide an optional description of + the value. + + \a value specifies a default value for this parameter. +*/ +#define KC_INT64 4 + +/*! \brief A unicode string + + Specifies a configuration parameter named \a name which is of this + type. Use \a description to provide an optional description of + the value. + + \a value specifies a default value for this parameter which should + be a pointer to a NULL terminated unicode string of no more than + ::KCONF_MAXCCH_STRING characters. +*/ +#define KC_STRING 5 + +/*! \brief An unparsed binary stream + + Specifies a configuration parameter named \a name which is of this + type. Use \a description to provide an optional description of + the value. + + Default values are not supported for binary streams. \a value is + ignored. +*/ +#define KC_BINARY 6 +/*@}*/ + +/*! \brief This is the root configuration space */ +#define KCONF_FLAG_ROOT 0x00000001 + +/*! \brief Indicates the configuration store which stores user-specific information */ +#define KCONF_FLAG_USER 0x00000002 + +/*! \brief Indicates the configuration store which stores machine-specific information */ +#define KCONF_FLAG_MACHINE 0x00000004 + +/*! \brief Indicates the configuration store which stores the schema */ +#define KCONF_FLAG_SCHEMA 0x00000008 + +/*! \brief Indicates that the last component of the given configuration path is to be considered to be a configuration value */ +#define KCONF_FLAG_TRAILINGVALUE 0x00000020 + +/*! \brief Do not parse the configuration space name + + If set, disables the parsing of the configuration space for + subspaces. The space name is taken verbatim to be a configuration + space name. This can be used when there can be forward slashes or + backslahes in the name which are not escaped. + + By default, the configuration space name, + + \code + L"foo/bar" + \endcode + + is taken to mean the configuration space \a bar which is a + subspace of \a foo. If ::KCONF_FLAG_NOPARSENAME is set, then this + is taken to mean configuration space \a foo/bar. + */ +#define KCONF_FLAG_NOPARSENAME 0x00000040 + +/*! \brief Maximum number of allowed characters (including terminating NULL) in a name + + \note This is a hard limit in Windows, since we are mapping + configuration spaces to registry keys. +*/ +#define KCONF_MAXCCH_NAME 256 + +/*! \brief Maximum number of allowed bytes (including terminating NULL) in a name */ +#define KCONF_MAXCB_NAME (KCONF_MAXCCH_NAME * sizeof(wchar_t)) + +/*! \brief Maximum level of nesting for configuration spaces + */ +#define KCONF_MAX_DEPTH 16 + +/*! \brief Maximum number of allowed characters (including terminating NULL) in a configuration path */ +#define KCONF_MAXCCH_PATH (KCONF_MAXCCH_NAME * KCONF_MAX_DEPTH) + +/*! \brief Maximum number of allowed bytes (including terminating NULL) in a configuration path */ +#define KCONF_MAXCB_PATH (KCONF_MAXCCH_PATH * sizeof(wchar_t)) + +/*! \brief Maximum number of allowed characters (including terminating NULL) in a string */ +#define KCONF_MAXCCH_STRING KHM_MAXCCH_STRING + +/*! \brief Maximum number of allowed bytes (including terminating NULL) in a string */ +#define KCONF_MAXCB_STRING (KCONF_MAXCCH_STRING * sizeof(wchar_t)) + +/*! \brief Open a configuration space + + Opens the configuration space specified by \a cspace. By default, + the opened space includes user,machine and schema configuration + stores. However, you can specify a subset of these. + + If the configuration space does not exist and the \a flags specify + KHM_FLAG_CREATE, then the configuration space is created. The + stores that are affected by the create operation depend on \a + flags. If the \a flags only specifies ::KCONF_FLAG_MACHINE, then + the configuration space is created in the machine store. If \a + flags specifies any combination of stores including \a + ::KCONF_FLAG_USER, then the configuration space is created in the + user store. Note that ::KCONF_FLAG_SCHEMA is readonly. + + Once opened, use khc_close_space() to close the configuration + space. + + \param[in] parent The parent configuration space. The path + specified in \a cspace is relative to the parent. Set this to + NULL to indicate the root configuration space. + + \param[in] cspace The confiuration path. This can be up to + ::KCONF_MAXCCH_PATH characters in length. Use either + backslashes or forward slashes to specify hiearchy. Set this + to NULL to reopen the parent configuration space. + + \param[in] flags Flags. This can be a combination of KCONF_FLAG_* + constants and KHM_FLAG_CREATE. If none of ::KCONF_FLAG_USER, + ::KCONF_FLAG_MACHINE or ::KCONF_FLAG_SCHEMA is specified, then + it defaults to all three. + + \param[out] result Pointer to a handle which receives the handle + to the opened configuration space if the call succeeds. + + \note You can re-open a configuration space with different flags + such as ::KCONF_FLAG_MACHINE by specifying NULL for \a cspace + and settings \a flags to the required flags. + +*/ +KHMEXP khm_int32 KHMAPI +khc_open_space(khm_handle parent, wchar_t * cspace, khm_int32 flags, + khm_handle * result); + +/*! \brief Set the shadow space for a configuration handle + + The handle specified by \a lower becomes a shadow for the handle + specified by \a upper. Any configuration value that is queried in + \a upper that does not exist in \a upper will be queried in \a + lower. + + If \a upper already had a shadow handle, that handle will be + replaced by \a lower. The handle \a lower still needs to be + closed by a call to khc_close_space(). However, closing \a lower + will not affect \a upper which will still treat the configuration + space pointed to by \a lower to be it's shadow. + + Shadows are specific to handles and not configuration spaces. + Shadowing a configuration space using one handle does not affect + any other handles which may be obtained for the same configuration + space. + + Specify NULL for \a lower to remove any prior shadow. + */ +KHMEXP khm_int32 KHMAPI +khc_shadow_space(khm_handle upper, khm_handle lower); + +/*! \brief Close a handle opened with khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_close_space(khm_handle conf); + +/*! \brief Read a string value from a configuration space + + The \a value parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema + store. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. + + \param[in] buf Buffer to copy the string to. Specify NULL to just + retrieve the number of required bytes. + + \param[in,out] bufsize On entry, specifies the number of bytes of + space available at the location specified by \a buf. On exit + specifies the number of bytes actually copied or the size of + the required buffer if \a buf is NULL or insufficient. + + \retval KHM_ERROR_NOT_READY The configuration provider has not started + \retval KHM_ERROR_INVALID_PARAM One or more of the supplied parameters are not valid + \retval KHM_ERROR_TYPE_MISMATCH The specified value is not a string + \retval KHM_ERROR_TOO_LONG \a buf was NULL or the size of the buffer was insufficient. The required size is in bufsize. + \retval KHM_ERROR_SUCCESS Success. The number of bytes copied is in bufsize. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_string(khm_handle conf, + wchar_t * value, + wchar_t * buf, + khm_size * bufsize); + +/*! \brief Read a multi-string value from a configuration space + + The \a value parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema + store. + + A multi-string is a pseudo data type. The value in the + configuration store should contain a CSV string. Each comma + separated value in the CSV string is considered to be a separate + value. Empty values are not allowed. The buffer pointed to by \a + buf will receive these values in the form of a series of NULL + terminated strings terminated by an empty string (or equivalently, + the last string will be terminated by a double NULL). + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. + + \param[in] buf Buffer to copy the multi-string to. Specify NULL + to just retrieve the number of required bytes. + + \param[in,out] bufsize On entry, specifies the number of bytes of + space available at the location specified by \a buf. On exit + specifies the number of bytes actually copied or the size of + the required buffer if \a buf is NULL or insufficient. + + \retval KHM_ERROR_NOT_READY The configuration provider has not started + \retval KHM_ERROR_INVALID_PARAM One or more of the supplied parameters are not valid + \retval KHM_ERROR_TYPE_MISMATCH The specified value is not a string + \retval KHM_ERROR_TOO_LONG \a buf was NULL or the size of the buffer was insufficient. The required size is in bufsize. + \retval KHM_ERROR_SUCCESS Success. The number of bytes copied is in bufsize. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_multi_string(khm_handle conf, + wchar_t * value, + wchar_t * buf, + khm_size * bufsize); + +/*! \brief Read a 32 bit integer value from a configuration space + + The \a value parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema + store. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. + + \param[in] conf Handle to a configuration space + \param[in] value The value to query + \param[out] buf The buffer to receive the value + + \retval KHM_ERROR_NOT_READY The configuration provider has not started. + \retval KHM_ERROR_SUCCESS Success. The value that was read was placed in \a buf + \retval KHM_ERROR_NOT_FOUND The specified value was not found + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TYPE_MISMATCH The specified value was found but was not of the correct type. + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_int32(khm_handle conf, + wchar_t * value, + khm_int32 * buf); + +/*! \brief Read a 64 bit integer value from a configuration space + + The \a value parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + - Otherwise, if KCONF_FLAG_SCHEMA was specified, the the schema + store. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. + + \param[in] conf Handle to a configuration space + \param[in] value The value to query + \param[out] buf The buffer to receive the value + + \retval KHM_ERROR_NOT_READY The configuration provider has not started + \retval KHM_ERROR_SUCCESS Success. The value that was read was placed in \a buf + \retval KHM_ERROR_NOT_FOUND The specified value was not found + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TYPE_MISMATCH The specified value was found but was not the correct data type. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_int64(khm_handle conf, + wchar_t * value, + khm_int64 * buf); + +/*! \brief Read a binary value from a configuration space + + The \a value parameter specifies the value to read from the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to access the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) does + not support binary values. + + \param[in] buf Buffer to copy the string to. Specify NULL to just + retrieve the number of required bytes. + + \param[in,out] bufsize On entry, specifies the number of bytes of + space available at the location specified by \a buf. On exit + specifies the number of bytes actually copied or the size of + the required buffer if \a buf is NULL or insufficient. + + \retval KHM_ERROR_SUCCESS Success. The data was copied to \a buf. The number of bytes copied is stored in \a bufsize + \retval KHM_ERROR_NOT_FOUND The specified value was not found + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_read_binary(khm_handle conf, + wchar_t * value, + void * buf, + khm_size * bufsize); + +/*! \brief Write a string value to a configuration space + + The \a value parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + \param[in] conf Handle to a configuration space + \param[in] value Name of value to write + \param[in] buf A NULL terminated unicode string not exceeding KCONF_MAXCCH_STRING in characters including terminating NULL + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_string(khm_handle conf, + wchar_t * value, + wchar_t * buf); + +/*! \brief Write a multi-string value to a configuration space + + The \a value parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + A multi-string is a pseudo data type. The buffer pointed to by \a + buf should contain a sequence of NULL terminated strings + terminated by an empty string (or equivalently, the last string + should terminate with a double NULL). This will be stored in the + value as a CSV string. + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_multi_string(khm_handle conf, + wchar_t * value, + wchar_t * buf); + +/*! \brief Write a 32 bit integer value to a configuration space + + The \a value parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_int32(khm_handle conf, + wchar_t * value, + khm_int32 buf); + +/*! \brief Write a 64 bit integer value to a configuration space + + The \a value parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_int64(khm_handle conf, + wchar_t * value, + khm_int64 buf); + +/*! \brief Write a binary value to a configuration space + + The \a value parameter specifies the value to write to the + configuration space. This can be either a value name or a value + path consisting of a series nested configuration space names + followed by the value name all separated by backslashes or forward + slashes. + + For example: If \a conf is a handle to the configuration space \c + 'A/B/C', then the value name \c 'D/E/v' refers to the value named + \c 'v' in the configuration space \c 'A/B/C/D/E'. + + The specific configuration store that is used to write the value + depends on the flags that were specified in the call to + khc_open_space(). The precedence of configuration stores are as + follows: + + - If KCONF_FLAG_USER was specified, then the user configuration + space. + + - Otherwise, if KCONF_FLAG_MACHINE was specified, then the machine + configuration space. + + Note that not specifying any of the configuration store specifiers + in the call to khc_open_space() is equivalent to specifying all + three. Also note that the schema store (KCONF_FLAG_SCHEMA) is + readonly. + + \see khc_open_space() +*/ +KHMEXP khm_int32 KHMAPI +khc_write_binary(khm_handle conf, + wchar_t * value, + void * buf, + khm_size bufsize); + +/*! \brief Get the type of a value in a configuration space + + \return The return value is the type of the specified value, or + KC_NONE if the value does not exist. + */ +KHMEXP khm_int32 KHMAPI +khc_get_type(khm_handle conf, wchar_t * value); + +/*! \brief Check which configuration stores contain a specific value. + + Each value in a configuration space can be contained in zero or + more configuration stores. Use this function to determine which + configuration stores contain the specific value. + + The returned bitmask always indicates a subset of the + configuration stores that were specified when opening the + configuration space corresponding to \a conf. + + \return A combination of ::KCONF_FLAG_MACHINE, ::KCONF_FLAG_USER + and ::KCONF_FLAG_SCHEMA indicating which stores contain the + value. + */ +KHMEXP khm_int32 KHMAPI +khc_value_exists(khm_handle conf, wchar_t * value); + +/*! \brief Remove a value from a configuration space + + Removes a value from one or more configuration stores. + + A value can exist in multiple configuration stores. Only the + values that are stored in writable stores can be removed. When + the function searches for values to remove, it will only look in + configuration stores that are specified in the handle. In + addition, the configuration stores affected can be further + narrowed by specifying them in the \a flags parameter. If \a + flags is zero, then all the stores visible to the handle are + searched. If \a flags specifies ::KCONF_FLAG_USER or + ::KCONF_FLAG_MACHINE or both, then only the specified stores are + searched, provided that the stores are visible to the handle. + + This function only operates on the topmost configuration space + visible to the handle. If the configuration handle is shadowed, + the shadowed configuration spaces are unaffected by the removal. + + \param[in] conf Handle to configuration space to remove value from + + \param[in] value Value to remove + + \param[in] flags Specifies which configuration stores will be + affected by the removal. See above. + + \retval KHM_ERROR_SUCCESS The value was removed from all the + specified configuration stores. + + \retval KHM_ERROR_NOT_FOUND The value was not found. + + \retval KHM_ERROR_UNKNOWN An unknown error occurred while trying + to remove the value. + + \retval KHM_ERROR_PARTIAL The value was successfully removed from + one or more stores, but the operation failed on one or more + other stores. + */ +KHMEXP khm_int32 KHMAPI +khc_remove_value(khm_handle conf, wchar_t * value, khm_int32 flags); + +/*! \brief Get the name of a configuration space + + \param[in] conf Handle to a configuration space + + \param[out] buf The buffer to receive the name. Set to NULL if + only the size of the buffer is required. + + \param[in,out] bufsize On entry, holds the size of the buffer + pointed to by \a buf. On exit, holds the number of bytes + copied into the buffer including the NULL terminator. + */ +KHMEXP khm_int32 KHMAPI +khc_get_config_space_name(khm_handle conf, + wchar_t * buf, + khm_size * bufsize); + +/*! \brief Get a handle to the parent space + + \param[in] conf Handle to a configuration space + + \param[out] parent Handle to the parent configuration space if the + call succeeds. Receives NULL otherwise. The returned handle + must be closed using khc_close_space() + */ +KHMEXP khm_int32 KHMAPI +khc_get_config_space_parent(khm_handle conf, + khm_handle * parent); + +/*! \brief Load a configuration schema into the specified configuration space + + \param[in] conf Handle to a configuration space or NULL to use the + root configuration space. + + \param[in] schema The schema to load. The schema is assumed to be + well formed. + + \see khc_unload_schema() + */ +KHMEXP khm_int32 KHMAPI +khc_load_schema(khm_handle conf, + kconf_schema * schema); + +/*! \brief Unload a schema from a configuration space + */ +KHMEXP khm_int32 KHMAPI +khc_unload_schema(khm_handle conf, + kconf_schema * schema); + +/*! \brief Enumerate the subspaces of a configuration space + + Prepares a configuration space for enumeration and returns the + child spaces in no particular order. + + \param[in] conf The configuration space to enumerate child spaces + + \param[in] prev The previous configuration space returned by + khc_enum_subspaces() or NULL if this is the first call. If + this is not NULL, then the handle passed in \a prev will be + freed. + + \param[out] next If \a prev was NULL, receives the first sub space + found in \a conf. You must \b either call + khc_enum_subspaces() again with the returned handle or call + khc_close_space() to free the returned handle if no more + subspaces are required. \a next can point to the same handle + specified in \a prev. + + \retval KHM_ERROR_SUCCESS The call succeeded. There is a valid + handle to a configuration space in \a first_subspace. + + \retval KHM_ERROR_INVALID_PARAM Either \a conf or \a prev was not a + valid configuration space handle or \a first_subspace is NULL. + Note that \a prev can be NULL. + + \retval KHM_ERROR_NOT_FOUND There were no subspaces in the + configuration space pointed to by \a conf. + + \note The configuration spaces that are enumerated directly belong + to the configuration space given by \a conf. This function + does not enumerate subspaces of shadowed configuration spaces + (see khc_shadow_space()). Even if \a conf was obtained on a + restricted domain (i.e. you specified one or more + configuration stores when you openend the handle and didn't + include all the configuration stores. See khc_open_space()), + the subspaces that are returned are the union of all + configuration spaces in all the configuration stores. This is + not a bug. This is a feature. In NetIDMgr, a configuartion + space exists if some configuration store defines it (or it was + created with a call to khc_open_space() even if no + configuration store defines it yet). This is the tradeoff you + make when using a layered configuration system. + + However, the returned handle has the same domain restrictions + as \a conf. + */ +KHMEXP khm_int32 KHMAPI +khc_enum_subspaces(khm_handle conf, + khm_handle prev, + khm_handle * next); + +/*! \brief Remove a configuration space + + The configuration space will be marked for removal. Once all the + handles for the space have been released, it will be deleted. The + configuration stores that will be affected are the write enabled + configuration stores for the handle. + */ +KHMEXP khm_int32 KHMAPI +khc_remove_space(khm_handle conf); +/*@}*/ + +#endif diff --git a/mechglue/src/windows/identity/kconfig/kconfiginternal.h b/mechglue/src/windows/identity/kconfig/kconfiginternal.h new file mode 100644 index 000000000..64068f4a9 --- /dev/null +++ b/mechglue/src/windows/identity/kconfig/kconfiginternal.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCONFIGINTERNAL_H +#define __KHIMAIRA_KCONFIGINTERNAL_H + +#include +#include +#include +#include +#include +#include + +/* TODO: Implement configuration provider interfaces + +typedef struct kconf_provider_t { + +} kconf_provider; +*/ + +typedef struct kconf_conf_space_t { + wchar_t * name; + + /* kconf_provider * provider; */ + + /* the regpath is the cumulative path starting from a hive root */ + wchar_t * regpath; + HKEY regkey_user; + khm_int32 regkey_user_flags; + HKEY regkey_machine; + khm_int32 regkey_machine_flags; + + khm_int32 refcount; + khm_int32 flags; + + kconf_schema * schema; + khm_int32 nSchema; + + TDCL(struct kconf_conf_space_t); +} kconf_conf_space; + +//#define KCONF_SPACE_FLAG_SCHEMA 0x00000020 +#define KCONF_SPACE_FLAG_DELETE_U 0x00000040 +#define KCONF_SPACE_FLAG_DELETE_M 0x00000080 + +typedef struct kconf_conf_handle_t { + khm_int32 magic; + khm_int32 flags; + kconf_conf_space * space; + + struct kconf_conf_handle_t * lower; + + LDCL(struct kconf_conf_handle_t); +} kconf_handle; + +#define KCONF_HANDLE_MAGIC 0x38eb49d2 +#define khc_is_handle(h) ((h) && ((kconf_handle *)h)->magic == KCONF_HANDLE_MAGIC) +#define khc_shadow(h) (((kconf_handle *)h)->lower) +#define khc_is_shadowed(h) (khc_is_handle(h) && khc_shadow(h) != NULL) + +extern kconf_conf_space * conf_root; +extern kconf_handle * conf_handles; +extern kconf_handle * conf_free_handles; +extern CRITICAL_SECTION cs_conf_global; +extern LONG conf_init; +extern LONG conf_status; + +#define khc_is_config_running() (conf_init && conf_status) + +#define CONFIG_REGPATHW L"Software\\MIT\\NetIDMgr" + +void init_kconf(void); +void exit_kconf(void); + +/* handle operations */ +#define khc_space_from_handle(h) (((kconf_handle *) h)->space) +#define khc_is_schema_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_SCHEMA) +#define khc_is_user_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_USER) +#define khc_is_machine_handle(h) (((kconf_handle *) h)->flags & KCONF_FLAG_MACHINE) +#define khc_handle_flags(h) (((kconf_handle *) h)->flags) + +kconf_handle * +khcint_handle_from_space(kconf_conf_space * s, khm_int32 flags); + +void +khcint_handle_free(kconf_handle * h); + +kconf_conf_space * +khcint_create_empty_space(void); + +void +khcint_free_space(kconf_conf_space * r); + +void +khcint_space_hold(kconf_conf_space * s); + +void +khcint_space_release(kconf_conf_space * s); + +HKEY +khcint_space_open_key(kconf_conf_space * s, khm_int32 flags); + +khm_int32 +khcint_remove_space(kconf_conf_space * c, khm_int32 flags); + +#endif diff --git a/mechglue/src/windows/identity/kconfig/kconfigmain.c b/mechglue/src/windows/identity/kconfig/kconfigmain.c new file mode 100644 index 000000000..c49364ab2 --- /dev/null +++ b/mechglue/src/windows/identity/kconfig/kconfigmain.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +void +kconfig_process_attach(void) { + init_kconf(); +} + +void +kconfig_process_detach(void) { + exit_kconf(); +} diff --git a/mechglue/src/windows/identity/kconfig/registry.c b/mechglue/src/windows/identity/kconfig/registry.c new file mode 100644 index 000000000..03b49b2c0 --- /dev/null +++ b/mechglue/src/windows/identity/kconfig/registry.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + diff --git a/mechglue/src/windows/identity/kconfig/test/utiltest.c b/mechglue/src/windows/identity/kconfig/test/utiltest.c new file mode 100644 index 000000000..0652c63b9 --- /dev/null +++ b/mechglue/src/windows/identity/kconfig/test/utiltest.c @@ -0,0 +1,207 @@ +#include +#include +#include + +struct string_pair { + wchar_t * ms; + wchar_t * csv; +}; + +struct string_pair strings[] = { + {L"foo\0bar\0baz,quux\0ab\"cd\0", L"foo,bar,\"baz,quux\",\"ab\"\"cd\""}, + {L"a\0b\0c\0d\0e\0", L"a,b,c,d,e"}, + {L"1\0", L"1"}, + {L"\0", L""}, + {L"b\0a\0", L"b,a"}, + {L"c\0a\0b\0", L"c,a,b"}, + {L"c\0a\0B\0", L"c,a,B"}, + {L"sdf\0Bar\0Foo\0BBB\0", L"sdf,Bar,Foo,BBB"} +}; + +int n_strings = ARRAYLENGTH(strings); + +void print_ms(wchar_t * ms) { + wchar_t * s; + size_t cch; + + s = ms; + while(*s) { + printf("%S\\0", s); + StringCchLength(s, 512, &cch); + s += cch + 1; + } +} + +int ms_to_csv_test(void) { + wchar_t wbuf[512]; + int i; + khm_int32 code = 0; + size_t cbbuf; + size_t cbr; + size_t cbnull; + + printf("khc_multi_string_to_csv() test:\n"); + + for(i=0; i"); + code = khc_multi_string_to_csv(NULL, &cbnull, strings[i].ms); + code = khc_multi_string_to_csv(wbuf, &cbbuf, strings[i].ms); + if(code) { + printf(" returned %d\n", code); + return code; + } + printf("CSV[%S]", wbuf); + if(wcscmp(wbuf, strings[i].csv)) { + printf(" MISMATCH!"); + return 1; + } + + StringCbLength(wbuf, sizeof(wbuf), &cbr); + cbr+= sizeof(wchar_t); + + if(cbr != cbbuf) { + printf(" Length mismatch"); + return 1; + } + + if(cbnull != cbr) { + printf(" NULL length mismatch"); + return 1; + } + + printf("\n"); + } + + return code; +} + +int csv_to_ms_test(void) { + wchar_t wbuf[512]; + int i; + khm_int32 code = 0; + size_t cbbuf; + size_t cbr; + size_t cbnull; + + printf("khc_csv_to_multi_string() test:\n"); + + for(i=0; i", strings[i].csv); + code = khc_csv_to_multi_string(NULL, &cbnull, strings[i].csv); + code = khc_csv_to_multi_string(wbuf, &cbbuf, strings[i].csv); + if(code) { + printf(" returned %d\n", code); + return code; + } + printf("MS["); + print_ms(wbuf); + printf("]"); + + if(cbnull != cbbuf) { + printf(" NULL length mismatch"); + return 1; + } + + printf("\n"); + + printf(" Byte length:%d\n", cbbuf); + } + + return code; +} + +int ms_append_test(void) +{ + wchar_t wbuf[512]; + size_t cbbuf; + khm_int32 code; + int i; + + printf("khc_multi_string_append() test:\n"); + + for(i=0; i + +INCFILES= \ + $(INCDIR)\kcreddb.h + +OBJFILES= \ + $(OBJ)\buf.obj \ + $(OBJ)\attrib.obj \ + $(OBJ)\credential.obj \ + $(OBJ)\credset.obj \ + $(OBJ)\credtype.obj \ + $(OBJ)\identity.obj \ + $(OBJ)\init.obj \ + $(OBJ)\kcreddbmain.obj \ + $(OBJ)\type.obj \ + $(OBJ)\kcdbconfig.obj + +$(OBJ)\kcdbconfig.c: kcdbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(OBJ)\kcredres.res: lang\en_us\kcredres.rc + $(RC2RES) + +all: mkdirs $(INCFILES) $(OBJ)\kcredres.res $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/mechglue/src/windows/identity/kcreddb/attrib.c b/mechglue/src/windows/identity/kcreddb/attrib.c new file mode 100644 index 000000000..f77ebccf1 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/attrib.c @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +CRITICAL_SECTION cs_attrib; +hashtable * kcdb_attrib_namemap = NULL; +kcdb_attrib_i ** kcdb_attrib_tbl = NULL; +kcdb_attrib_i ** kcdb_property_tbl = NULL; +kcdb_attrib_i * kcdb_attribs = NULL; + +void +kcdb_attrib_add_ref_func(const void * key, void * va) +{ + kcdb_attrib_hold((kcdb_attrib_i *) va); +} + +void +kcdb_attrib_del_ref_func(const void * key, void * va) +{ + kcdb_attrib_release((kcdb_attrib_i *) va); +} + +void +kcdb_attrib_msg_completion(kmq_message * m) +{ + if(m && m->vparam) { + kcdb_attrib_release((kcdb_attrib_i *) m->vparam); + } +} + +khm_int32 +kcdb_attrib_hold(kcdb_attrib_i * ai) +{ + if(!ai) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + ai->refcount++; + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_SUCCESS; +} + +khm_int32 +kcdb_attrib_release(kcdb_attrib_i * ai) +{ + if(!ai) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + ai->refcount--; + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_SUCCESS; +} + +void +kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai) +{ + kcdb_attrib_hold(ai); + kmq_post_message(KMSG_KCDB, KMSG_KCDB_ATTRIB, op, (void *) ai); +} + +khm_int32 KHMAPI +kcdb_attr_sys_cb(khm_handle vcred, + khm_int32 attr, + void * buf, + khm_size * pcb_buf) +{ + kcdb_cred * c; + + c = (kcdb_cred *) vcred; + + switch(attr) { + case KCDB_ATTR_NAME: + return kcdb_cred_get_name(vcred, buf, pcb_buf); + + case KCDB_ATTR_ID: + if(buf && *pcb_buf >= sizeof(khm_ui_8)) { + *pcb_buf = sizeof(khm_int64); + *((khm_ui_8 *) buf) = (khm_ui_8) c->identity; + return KHM_ERROR_SUCCESS; + } else { + *pcb_buf = sizeof(khm_ui_8); + return KHM_ERROR_TOO_LONG; + } + + case KCDB_ATTR_ID_NAME: + return kcdb_identity_get_name((khm_handle) c->identity, + (wchar_t *) buf, pcb_buf); + + case KCDB_ATTR_TYPE: + if(buf && *pcb_buf >= sizeof(khm_int32)) { + *pcb_buf = sizeof(khm_int32); + *((khm_int32 *) buf) = c->type; + return KHM_ERROR_SUCCESS; + } else { + *pcb_buf = sizeof(khm_int32); + return KHM_ERROR_TOO_LONG; + } + + case KCDB_ATTR_TYPE_NAME: + return kcdb_credtype_describe(c->type, buf, + pcb_buf, KCDB_TS_SHORT); + + case KCDB_ATTR_TIMELEFT: + { + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!buf || *pcb_buf < sizeof(FILETIME)) { + *pcb_buf = sizeof(FILETIME); + rv = KHM_ERROR_TOO_LONG; + } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_EXPIRE)) { + *pcb_buf = sizeof(FILETIME); + /* setting the timeleft to _I64_MAX has the + interpretation that this credential does not + expire, which is the default behavior if the + expiration time is not known */ + *((FILETIME *) buf) = IntToFt(_I64_MAX); + } else { + FILETIME ftc; + khm_int64 iftc; + + GetSystemTimeAsFileTime(&ftc); + iftc = FtToInt(&ftc); + + *((FILETIME *) buf) = + IntToFt(FtToInt((FILETIME *) + kcdb_cred_buf_get(c,KCDB_ATTR_EXPIRE)) + - iftc); + *pcb_buf = sizeof(FILETIME); + } + + return rv; + } + + case KCDB_ATTR_RENEW_TIMELEFT: + { + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!buf || *pcb_buf < sizeof(FILETIME)) { + *pcb_buf = sizeof(FILETIME); + rv = KHM_ERROR_TOO_LONG; + } else if(!kcdb_cred_buf_exist(c,KCDB_ATTR_RENEW_EXPIRE)) { + *pcb_buf = sizeof(FILETIME); + /* setting the timeleft to _I64_MAX has the + interpretation that this credential does not + expire, which is the default behavior if the + expiration time is not known */ + *((FILETIME *) buf) = IntToFt(_I64_MAX); + } else { + FILETIME ftc; + + GetSystemTimeAsFileTime(&ftc); + + *((FILETIME *) buf) = + IntToFt(FtToInt(((FILETIME *) + kcdb_cred_buf_get(c,KCDB_ATTR_RENEW_EXPIRE)) + - FtToInt(&ftc))); + *pcb_buf = sizeof(FILETIME); + } + + return rv; + } + + case KCDB_ATTR_FLAGS: + if(buf && *pcb_buf >= sizeof(khm_int32)) { + *pcb_buf = sizeof(khm_int32); + *((khm_int32 *) buf) = c->flags; + return KHM_ERROR_SUCCESS; + } else { + *pcb_buf = sizeof(khm_int32); + return KHM_ERROR_TOO_LONG; + } + + default: + return KHM_ERROR_NOT_FOUND; + } +} + +void +kcdb_attrib_init(void) +{ + kcdb_attrib attrib; + wchar_t sbuf[256]; + + InitializeCriticalSection(&cs_attrib); + kcdb_attrib_namemap = + hash_new_hashtable(KCDB_ATTRIB_HASH_SIZE, + hash_string, + hash_string_comp, + kcdb_attrib_add_ref_func, + kcdb_attrib_del_ref_func); + + kcdb_attrib_tbl = + PMALLOC(sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1)); + assert(kcdb_attrib_tbl != NULL); + ZeroMemory(kcdb_attrib_tbl, + sizeof(kcdb_attrib_i *) * (KCDB_ATTR_MAX_ID + 1)); + + kcdb_property_tbl = + PMALLOC(sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS); + assert(kcdb_property_tbl != NULL); + ZeroMemory(kcdb_property_tbl, + sizeof(kcdb_attrib_i *) * KCDB_ATTR_MAX_PROPS); + + kcdb_attribs = NULL; + + /* register standard attributes */ + + /* Name */ + attrib.id = KCDB_ATTR_NAME; + attrib.name = KCDB_ATTRNAME_NAME; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_NAME, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(wchar_t); + attrib.compute_max_cbsize = KCDB_MAXCB_NAME; + + kcdb_attrib_register(&attrib, NULL); + + /* ID */ + attrib.id = KCDB_ATTR_ID; + attrib.name = KCDB_ATTRNAME_ID; + attrib.type = KCDB_TYPE_INT64; + LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_HIDDEN; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(khm_int32); + attrib.compute_max_cbsize = sizeof(khm_int32); + + kcdb_attrib_register(&attrib, NULL); + + /* ID Name */ + attrib.id = KCDB_ATTR_ID_NAME; + attrib.alt_id = KCDB_ATTR_ID; + attrib.name = KCDB_ATTRNAME_ID_NAME; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_IDENTITY, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_ALTVIEW | + KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(wchar_t); + attrib.compute_max_cbsize = KCDB_IDENT_MAXCB_NAME; + + kcdb_attrib_register(&attrib, NULL); + + /* Type */ + attrib.id = KCDB_ATTR_TYPE; + attrib.name = KCDB_ATTRNAME_TYPE; + attrib.type = KCDB_TYPE_INT32; + LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_HIDDEN; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(khm_int32); + attrib.compute_max_cbsize = sizeof(khm_int32); + + kcdb_attrib_register(&attrib, NULL); + + /* Type Name */ + attrib.id = KCDB_ATTR_TYPE_NAME; + attrib.alt_id = KCDB_ATTR_TYPE; + attrib.name = KCDB_ATTRNAME_TYPE_NAME; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_TYPE, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_ALTVIEW | + KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(wchar_t); + attrib.compute_max_cbsize = KCDB_MAXCB_NAME; + + kcdb_attrib_register(&attrib, NULL); + + /* Parent Name */ + attrib.id = KCDB_ATTR_PARENT_NAME; + attrib.name = KCDB_ATTRNAME_PARENT_NAME; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_PARENT, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Issed On */ + attrib.id = KCDB_ATTR_ISSUE; + attrib.name = KCDB_ATTRNAME_ISSUE; + attrib.type = KCDB_TYPE_DATE; + LoadString(hinst_kcreddb, IDS_ISSUED, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Expires On */ + attrib.id = KCDB_ATTR_EXPIRE; + attrib.name = KCDB_ATTRNAME_EXPIRE; + attrib.type = KCDB_TYPE_DATE; + LoadString(hinst_kcreddb, IDS_EXPIRES, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Renewable Time Expires On */ + attrib.id = KCDB_ATTR_RENEW_EXPIRE; + attrib.name = KCDB_ATTRNAME_RENEW_EXPIRE; + attrib.type = KCDB_TYPE_DATE; + LoadString(hinst_kcreddb, IDS_RENEW_EXPIRES, + sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Time Left */ + attrib.id = KCDB_ATTR_TIMELEFT; + attrib.alt_id = KCDB_ATTR_EXPIRE; + attrib.name = KCDB_ATTRNAME_TIMELEFT; + attrib.type = KCDB_TYPE_INTERVAL; + LoadString(hinst_kcreddb, IDS_TIMELEFT, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_ALTVIEW | + KCDB_ATTR_FLAG_VOLATILE; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(__int64); + attrib.compute_max_cbsize = sizeof(__int64); + + kcdb_attrib_register(&attrib, NULL); + + /* Renewable Time Left */ + attrib.id = KCDB_ATTR_RENEW_TIMELEFT; + attrib.alt_id = KCDB_ATTR_RENEW_EXPIRE; + attrib.name = KCDB_ATTRNAME_RENEW_TIMELEFT; + attrib.type = KCDB_TYPE_INTERVAL; + LoadString(hinst_kcreddb, + IDS_RENEW_TIMELEFT, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_ALTVIEW | + KCDB_ATTR_FLAG_VOLATILE; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(__int64); + attrib.compute_max_cbsize = sizeof(__int64); + + kcdb_attrib_register(&attrib, NULL); + + /* Location of Credential */ + attrib.id = KCDB_ATTR_LOCATION; + attrib.name = KCDB_ATTRNAME_LOCATION; + attrib.type = KCDB_TYPE_STRING; + LoadString(hinst_kcreddb, IDS_LOCATION, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Lifetime */ + attrib.id = KCDB_ATTR_LIFETIME; + attrib.name = KCDB_ATTRNAME_LIFETIME; + attrib.type = KCDB_TYPE_INTERVAL; + LoadString(hinst_kcreddb, IDS_LIFETIME, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Renewable Lifetime */ + attrib.id = KCDB_ATTR_RENEW_LIFETIME; + attrib.name = KCDB_ATTRNAME_RENEW_LIFETIME; + attrib.type = KCDB_TYPE_INTERVAL; + LoadString(hinst_kcreddb, + IDS_RENEW_LIFETIME, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = KCDB_ATTR_FLAG_SYSTEM; + attrib.compute_cb = NULL; + attrib.compute_min_cbsize = 0; + attrib.compute_max_cbsize = 0; + + kcdb_attrib_register(&attrib, NULL); + + /* Flags */ + attrib.id = KCDB_ATTR_FLAGS; + attrib.name = KCDB_ATTRNAME_FLAGS; + attrib.type = KCDB_TYPE_INT32; + LoadString(hinst_kcreddb, IDS_FLAGS, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + attrib.flags = + KCDB_ATTR_FLAG_REQUIRED | + KCDB_ATTR_FLAG_COMPUTED | + KCDB_ATTR_FLAG_SYSTEM | + KCDB_ATTR_FLAG_HIDDEN; + attrib.compute_cb = kcdb_attr_sys_cb; + attrib.compute_min_cbsize = sizeof(khm_int32); + attrib.compute_max_cbsize = sizeof(khm_int32); + + kcdb_attrib_register(&attrib, NULL); +} + +void +kcdb_attrib_exit(void) +{ + DeleteCriticalSection(&cs_attrib); + + if(kcdb_attrib_tbl) + PFREE(kcdb_attrib_tbl); + + if(kcdb_property_tbl) + PFREE(kcdb_property_tbl); +} + +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_id(wchar_t *name, khm_int32 * id) +{ + kcdb_attrib_i * ai; + + if(!name) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + ai = hash_lookup(kcdb_attrib_namemap, (void *) name); + LeaveCriticalSection(&cs_attrib); + + if(ai) { + *id = ai->attr.id; + return KHM_ERROR_SUCCESS; + } else { + *id = KCDB_ATTR_INVALID; + return KHM_ERROR_NOT_FOUND; + } +} + +KHMEXP khm_int32 KHMAPI +kcdb_attrib_register(kcdb_attrib * attrib, khm_int32 * new_id) +{ + kcdb_attrib_i * ai; + size_t cb_name; + size_t cb_short_desc; + size_t cb_long_desc; + khm_int32 attr_id; + khm_boolean prop = FALSE; + + if(!attrib || + KHM_FAILED(kcdb_type_get_info(attrib->type, NULL)) || + !attrib->name) + return KHM_ERROR_INVALID_PARAM; + + if(FAILED(StringCbLength(attrib->name, KCDB_MAXCB_NAME, &cb_name))) + return KHM_ERROR_TOO_LONG; + cb_name += sizeof(wchar_t); + + if(attrib->short_desc) { + if(FAILED(StringCbLength(attrib->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc))) + return KHM_ERROR_TOO_LONG; + cb_short_desc += sizeof(wchar_t); + } else + cb_short_desc = 0; + + if(attrib->long_desc) { + if(FAILED(StringCbLength(attrib->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc))) + return KHM_ERROR_TOO_LONG; + cb_long_desc += sizeof(wchar_t); + } else + cb_long_desc = 0; + + if((attrib->flags & KCDB_ATTR_FLAG_COMPUTED) && + (!attrib->compute_cb || + attrib->compute_min_cbsize <= 0 || + attrib->compute_max_cbsize < attrib->compute_min_cbsize)) + return KHM_ERROR_INVALID_PARAM; + + if ((attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) && + KHM_FAILED(kcdb_attrib_get_info(attrib->alt_id, + NULL))) + return KHM_ERROR_INVALID_PARAM; + + prop = !!(attrib->flags & KCDB_ATTR_FLAG_PROPERTY); + + EnterCriticalSection(&cs_attrib); + + if(!prop && + (attrib->id < 0 || attrib->id > KCDB_ATTR_MAX_ID)) + { + if(KHM_FAILED(kcdb_attrib_next_free_id(&attr_id))) { + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_NO_RESOURCES; + } + } else if (prop && + (attrib->id < KCDB_ATTR_MIN_PROP_ID || + attrib->id > KCDB_ATTR_MAX_PROP_ID)) { + + if(KHM_FAILED(kcdb_attrib_next_free_prop_id(&attr_id))) { + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_NO_RESOURCES; + } + + } else { + attr_id = attrib->id; + } + +#ifdef DEBUG + assert(!prop || (attr_id >= KCDB_ATTR_MIN_PROP_ID && attr_id <= KCDB_ATTR_MAX_PROP_ID)); + assert(prop || (attr_id >= 0 && attr_id <= KCDB_ATTR_MAX_ID)); +#endif + + if((!prop && kcdb_attrib_tbl[attr_id]) || + (prop && kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID])) { + + LeaveCriticalSection(&cs_attrib); + return KHM_ERROR_DUPLICATE; + + } + + ai = PMALLOC(sizeof(kcdb_attrib_i)); + ZeroMemory(ai, sizeof(kcdb_attrib_i)); + + ai->attr.type = attrib->type; + ai->attr.id = attr_id; + ai->attr.alt_id = attrib->alt_id; + ai->attr.flags = attrib->flags; + ai->attr.compute_cb = attrib->compute_cb; + ai->attr.compute_max_cbsize = attrib->compute_max_cbsize; + ai->attr.compute_min_cbsize = attrib->compute_min_cbsize; + ai->attr.name = PMALLOC(cb_name); + StringCbCopy(ai->attr.name, cb_name, attrib->name); + if(cb_short_desc) { + ai->attr.short_desc = PMALLOC(cb_short_desc); + StringCbCopy(ai->attr.short_desc, cb_short_desc, attrib->short_desc); + } + if(cb_long_desc) { + ai->attr.long_desc = PMALLOC(cb_long_desc); + StringCbCopy(ai->attr.long_desc, cb_long_desc, attrib->long_desc); + } + + LINIT(ai); + + if(!prop) + kcdb_attrib_tbl[attr_id] = ai; + else + kcdb_property_tbl[attr_id - KCDB_ATTR_MIN_PROP_ID] = ai; + + LPUSH(&kcdb_attribs, ai); + + hash_add(kcdb_attrib_namemap, (void *) ai->attr.name, ai); + + LeaveCriticalSection(&cs_attrib); + + kcdb_attrib_post_message(KCDB_OP_INSERT, ai); + + if(new_id) + *new_id = attr_id; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_get_info( + khm_int32 id, + kcdb_attrib ** attrib) +{ + kcdb_attrib_i * ai; + khm_boolean prop; + + if(id >= 0 && id <= KCDB_ATTR_MAX_ID) + prop = FALSE; + else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID) + prop = TRUE; + else + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + if(prop) + ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID]; + else + ai = kcdb_attrib_tbl[id]; + LeaveCriticalSection(&cs_attrib); + + if(ai) { + if(attrib) { + *attrib = &(ai->attr); + kcdb_attrib_hold(ai); + } + return KHM_ERROR_SUCCESS; + } else { + if(attrib) + *attrib = NULL; + return KHM_ERROR_NOT_FOUND; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_release_info(kcdb_attrib * attrib) +{ + if(attrib) + kcdb_attrib_release((kcdb_attrib_i *) attrib); + return KHM_ERROR_SUCCESS; +} + + +KHMEXP khm_int32 KHMAPI kcdb_attrib_unregister(khm_int32 id) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_describe( + khm_int32 id, + wchar_t * buffer, + khm_size * cbsize, + khm_int32 flags) +{ + kcdb_attrib_i * ai; + size_t cb_size = 0; + khm_boolean prop = FALSE; + + if(!cbsize) + return KHM_ERROR_INVALID_PARAM; + + if(id >= 0 && id <= KCDB_ATTR_MAX_ID) + prop = FALSE; + else if(id >= KCDB_ATTR_MIN_PROP_ID && id <= KCDB_ATTR_MAX_PROP_ID) + prop = TRUE; + else + return KHM_ERROR_INVALID_PARAM; + + if(prop) + ai = kcdb_property_tbl[id - KCDB_ATTR_MIN_PROP_ID]; + else + ai = kcdb_attrib_tbl[id]; + + if(!ai) + return KHM_ERROR_NOT_FOUND; + + if((flags & KCDB_TS_SHORT) && + ai->attr.short_desc) + { + if(FAILED(StringCbLength(ai->attr.short_desc, KCDB_MAXCB_SHORT_DESC, &cb_size))) + return KHM_ERROR_UNKNOWN; + cb_size += sizeof(wchar_t); + + if(!buffer || *cbsize < cb_size) { + *cbsize = cb_size; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cbsize, ai->attr.short_desc); + + *cbsize = cb_size; + + return KHM_ERROR_SUCCESS; + } else { + if(FAILED(StringCbLength(ai->attr.long_desc, KCDB_MAXCB_LONG_DESC, &cb_size))) + return KHM_ERROR_UNKNOWN; + cb_size += sizeof(wchar_t); + + if(!buffer || *cbsize < cb_size) { + *cbsize = cb_size; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cbsize, ai->attr.long_desc); + + *cbsize = cb_size; + + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id) +{ + int i; + + if(!id) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + for(i=0;i < KCDB_ATTR_MAX_PROPS; i++) { + if(!kcdb_property_tbl[i]) + break; + } + LeaveCriticalSection(&cs_attrib); + + if(i < KCDB_ATTR_MAX_PROPS) { + *id = i + KCDB_ATTR_MIN_PROP_ID; + return KHM_ERROR_SUCCESS; + } else { + *id = KCDB_ATTR_INVALID; + return KHM_ERROR_NO_RESOURCES; + } +} + +khm_int32 kcdb_attrib_next_free_id(khm_int32 * id) +{ + int i; + + if(!id) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_attrib); + for(i=0;i<= KCDB_ATTR_MAX_ID; i++) { + if(!kcdb_attrib_tbl[i]) + break; + } + LeaveCriticalSection(&cs_attrib); + + if(i <= KCDB_ATTR_MAX_ID) { + *id = i; + return KHM_ERROR_SUCCESS; + } else { + *id = KCDB_ATTR_INVALID; + return KHM_ERROR_NO_RESOURCES; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_get_count( + khm_int32 and_flags, + khm_int32 eq_flags, + khm_size * pcount) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size count = 0; + int i; + + if(pcount == NULL) + return KHM_ERROR_INVALID_PARAM; + + eq_flags &= and_flags; + + EnterCriticalSection(&cs_attrib); + for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) { + if(kcdb_attrib_tbl[i] && + (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags) + count++; + } + + for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) { + if(kcdb_property_tbl[i] && + (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags) + count++; + } + LeaveCriticalSection(&cs_attrib); + + *pcount = count; + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_attrib_get_ids( + khm_int32 and_flags, + khm_int32 eq_flags, + khm_int32 * plist, + khm_size * pcsize) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size count = 0; + int i; + + if(plist == NULL || pcsize == NULL) + return KHM_ERROR_INVALID_PARAM; + + eq_flags &= and_flags; + + EnterCriticalSection(&cs_attrib); + for(i = 0; i <= KCDB_ATTR_MAX_ID; i++) { + if(kcdb_attrib_tbl[i] && + (kcdb_attrib_tbl[i]->attr.flags & and_flags) == eq_flags) { + if(count >= *pcsize) { + rv = KHM_ERROR_TOO_LONG; + count++; + } else + plist[count++] = i; + } + } + + for(i = 0; i < KCDB_ATTR_MAX_PROPS; i++) { + if(kcdb_property_tbl[i] && + (kcdb_property_tbl[i]->attr.flags & and_flags) == eq_flags) { + if(count >= *pcsize) { + rv = KHM_ERROR_TOO_LONG; + count++; + } else + plist[count++] = i + KCDB_ATTR_MIN_PROP_ID; + } + } + LeaveCriticalSection(&cs_attrib); + + *pcsize = count; + + return rv; +} diff --git a/mechglue/src/windows/identity/kcreddb/attrib.h b/mechglue/src/windows/identity/kcreddb/attrib.h new file mode 100644 index 000000000..f5647d67a --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/attrib.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCDB_ATTRIB_H +#define __KHIMAIRA_KCDB_ATTRIB_H + +/* Attributes */ + +typedef struct kcdb_attrib_i_t { + kcdb_attrib attr; + + khm_int32 refcount; + + struct kcdb_attrib_i_t * next; + struct kcdb_attrib_i_t * prev; +} kcdb_attrib_i; + +#define KCDB_ATTRIB_HASH_SIZE 31 + +void kcdb_attrib_init(void); +void kcdb_attrib_exit(void); +void kcdb_attrib_add_ref_func(const void * key, void * va); +void kcdb_attrib_del_ref_func(const void * key, void * va); +void kcdb_attrib_msg_completion(kmq_message * m); +khm_int32 kcdb_attrib_next_free_prop_id(khm_int32 * id); +khm_int32 kcdb_attrib_next_free_id(khm_int32 * id); +khm_int32 kcdb_attrib_hold(kcdb_attrib_i * ai); +khm_int32 kcdb_attrib_release(kcdb_attrib_i * ai); +void kcdb_attrib_post_message(khm_int32 op, kcdb_attrib_i * ai); +khm_int32 KHMAPI kcdb_attr_sys_cb(khm_handle cred, khm_int32 attr, void * buf, khm_size * pcb_buf); + +#endif diff --git a/mechglue/src/windows/identity/kcreddb/buf.c b/mechglue/src/windows/identity/kcreddb/buf.c new file mode 100644 index 000000000..1811bc126 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/buf.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +void kcdb_buf_new(kcdb_buf * buf, khm_size n_fields) +{ + buf->buffer = PMALLOC(KCDB_BUF_CBBUF_INITIAL); + buf->cb_buffer = KCDB_BUF_CBBUF_INITIAL; + buf->cb_used = 0; + + if(n_fields == KCDB_BUF_DEFAULT) + n_fields = KCDB_BUF_FIELDS_INITIAL; + + assert(n_fields < KCDB_BUF_MAX_SLOTS); + + buf->n_fields = n_fields; + buf->nc_fields = UBOUNDSS(n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); + buf->fields = PMALLOC(sizeof(buf->fields[0]) * buf->n_fields); + ZeroMemory(buf->fields, sizeof(buf->fields[0]) * buf->n_fields); +} + +void kcdb_buf_delete(kcdb_buf * buf) +{ + buf->cb_buffer = 0; + buf->cb_used = 0; + if(buf->buffer) + PFREE(buf->buffer); + buf->buffer = NULL; + + buf->n_fields = 0; + buf->nc_fields = 0; + if(buf->fields) + PFREE(buf->fields); + buf->fields = NULL; +} + +static void kcdb_buf_assert_size(kcdb_buf * buf, khm_size cbsize) +{ + khm_size new_size; + void * new_buf; + + /* should be less than or equal to the max signed 32 bit int */ + assert(cbsize <= KHM_INT32_MAX); + if(cbsize <= buf->cb_buffer) + return; + + new_size = UBOUNDSS(cbsize, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH); + + assert(new_size > buf->cb_buffer && new_size > 0); + + new_buf = PMALLOC(new_size); + assert(new_buf != NULL); + + memcpy(new_buf, buf->buffer, buf->cb_used); + PFREE(buf->buffer); + buf->buffer = new_buf; +} + +void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize) +{ + khm_size cbnew; + khm_ssize cbdelta; + khm_size cbold; + kcdb_buf_field * f; + + cbnew = UBOUND32(cbsize); + + assert(slot <= KCDB_BUF_APPEND); + + if(slot == KCDB_BUF_APPEND) { + slot = kcdb_buf_slot_by_id(buf, id); + if(slot == KCDB_BUF_INVALID_SLOT) + slot = buf->n_fields; + } + + assert(slot < KCDB_BUF_MAX_SLOTS); + + if((slot + 1) > buf->nc_fields) { + kcdb_buf_field * nf; + khm_size ns; + + ns = UBOUNDSS((slot + 1), KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); + + nf = PMALLOC(sizeof(buf->fields[0]) * ns); + memcpy(nf, buf->fields, sizeof(buf->fields[0]) * buf->n_fields); + + if(ns > buf->n_fields) + memset(&(nf[buf->n_fields]), 0, sizeof(buf->fields[0]) * (ns - buf->n_fields)); + + PFREE(buf->fields); + buf->fields = nf; + buf->nc_fields = ns; + } + + if((slot + 1) > buf->n_fields) + buf->n_fields = slot + 1; + + f = &(buf->fields[slot]); + + if(f->flags & KCDB_CREDF_FLAG_ALLOCD) { + /* there's already an allocation. we have to resize it to + accomodate the new size */ + cbold = UBOUND32(f->cbsize); + /* demote before substraction */ + cbdelta = ((khm_ssize) cbnew) - (khm_ssize) cbold; + + if(cbnew > cbold) { + kcdb_buf_assert_size(buf, buf->cb_used + cbdelta); + } + + if(buf->cb_used > f->offset + cbold) { + int i; + + memmove( + ((BYTE *) buf->buffer) + (f->offset + cbnew), + ((BYTE *) buf->buffer) + (f->offset + cbold), + buf->cb_used - (f->offset + cbold)); + + for(i=0; i < (int) buf->n_fields; i++) { + if(i != slot && + (buf->fields[i].flags & KCDB_CREDF_FLAG_ALLOCD) && + buf->fields[i].offset > f->offset) + { + buf->fields[i].offset = + (khm_ui_4)(((khm_ssize) buf->fields[i].offset) + cbdelta); + } + } + } + + /* demote integer before adding signed quantity */ + buf->cb_used = (khm_size)(((khm_ssize) buf->cb_used) + cbdelta); + + f->cbsize = (khm_ui_4) cbsize; + + } else { + kcdb_buf_assert_size(buf, buf->cb_used + cbnew); + f->offset = (khm_ui_4) buf->cb_used; + f->cbsize = (khm_ui_4) cbsize; + buf->cb_used += cbnew; + } + + if(cbsize == 0) { + f->flags &= ~KCDB_CREDF_FLAG_ALLOCD; + f->flags &= ~KCDB_CREDF_FLAG_DATA; + f->id = KCDB_BUFF_ID_INVALID; + } else { + f->flags |= KCDB_CREDF_FLAG_ALLOCD; + f->id = id; + } +} + +void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src) +{ + khm_size cb_buf; + khm_size nc_fields; + + cb_buf = UBOUNDSS(src->cb_used, KCDB_BUF_CBBUF_INITIAL, KCDB_BUF_CBBUF_GROWTH); +#if 0 + /* replaced by UBOUNDSS() above */ + (src->cb_used <= kcdb_cred_initial_size)? kcdb_cred_initial_size: + kcdb_cred_initial_size + + (((src->cb_used - (kcdb_cred_initial_size + 1)) / kcdb_cred_growth_factor + 1) * kcdb_cred_growth_factor); +#endif + + kcdb_buf_delete(dest); + + dest->cb_buffer = cb_buf; + dest->cb_used = src->cb_used; + dest->buffer = PMALLOC(cb_buf); + memcpy(dest->buffer, src->buffer, src->cb_used); + + nc_fields = UBOUNDSS(src->n_fields, KCDB_BUF_FIELDS_INITIAL, KCDB_BUF_FIELDS_GROWTH); + dest->nc_fields = nc_fields; + dest->n_fields = src->n_fields; + dest->fields = PMALLOC(nc_fields * sizeof(dest->fields[0])); + memcpy(dest->fields, src->fields, src->n_fields * sizeof(dest->fields[0])); + if(dest->n_fields < dest->nc_fields) + memset(&(dest->fields[dest->n_fields]), 0, (src->nc_fields - src->n_fields) * sizeof(dest->fields[0])); +} + +void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src) +{ + void * dest; + kcdb_buf_alloc(buf, slot, id, cb_src); + if(slot == KCDB_BUF_APPEND) { + slot = kcdb_buf_slot_by_id(buf, id); + if(slot == KCDB_BUF_INVALID_SLOT) { +#ifdef DEBUG + assert(FALSE); +#else + return; +#endif + } + } + if(kcdb_buf_exist(buf, slot)) { + dest = kcdb_buf_get(buf, slot); + memcpy(dest, src, cb_src); + + buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA; + } +} + +int kcdb_buf_exist(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields) + return 0; + return (buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD); +} + +int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields) + return 0; + return (buf->fields[slot].flags & KCDB_CREDF_FLAG_DATA); +} + +void * kcdb_buf_get(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields || + !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) + return NULL; + return (((BYTE *) buf->buffer) + buf->fields[slot].offset); +} + +khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields || + !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) + return 0; + return (buf->fields[slot].cbsize); +} + +void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot) +{ + if(slot >= buf->n_fields || + !(buf->fields[slot].flags & KCDB_CREDF_FLAG_ALLOCD)) + return; + + (buf->fields[slot].flags |= KCDB_CREDF_FLAG_DATA); +} + +khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id) +{ + int i; + + for(i=0; i < (int) buf->n_fields; i++) { + if(buf->fields[i].id == id) + break; + } + + if(i < (int) buf->n_fields) + return i; + else + return KCDB_BUF_INVALID_SLOT; +} + +/* API for accessing generic buffers */ + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr( + khm_handle record, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcb_buf) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_get_attr(record, attr_id, attr_type, buffer, pcb_buf); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_get_attr(record, attr_id, attr_type, buffer, pcb_buf); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib( + khm_handle record, + wchar_t * attr_name, + khm_int32 * attr_type, + void * buffer, + khm_size * pcb_buf) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_get_attrib(record, attr_name, attr_type, buffer, pcb_buf); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_get_attrib(record, attr_name, attr_type, buffer, pcb_buf); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attr_string( + khm_handle record, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_get_attr_string(record, attr_id, buffer, pcbbuf, flags); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_get_attr_string(record, attr_id, buffer, pcbbuf, flags); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_get_attrib_string( + khm_handle record, + wchar_t * attr_name, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_get_attrib_string(record, attr_name, buffer, pcbbuf, flags); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_get_attrib_string(record, attr_name, buffer, pcbbuf, flags); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_set_attr( + khm_handle record, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_set_attr(record, attr_id, buffer, cbbuf); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_set_attr(record, attr_id, buffer, cbbuf); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_set_attrib( + khm_handle record, + wchar_t * attr_name, + void * buffer, + khm_size cbbuf) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_set_attrib(record, attr_name, buffer, cbbuf); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_set_attrib(record, attr_name, buffer, cbbuf); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_hold(khm_handle record) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_hold(record); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_hold(record); + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP khm_int32 KHMAPI kcdb_buf_release(khm_handle record) +{ + if(kcdb_cred_is_active_cred(record)) + return kcdb_cred_release(record); + else if(kcdb_is_active_identity(record)) + return kcdb_identity_release(record); + else + return KHM_ERROR_INVALID_PARAM; +} + diff --git a/mechglue/src/windows/identity/kcreddb/buf.h b/mechglue/src/windows/identity/kcreddb/buf.h new file mode 100644 index 000000000..f47bd0a2a --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/buf.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCDB_BUF_H +#define __KHIMAIRA_KCDB_BUF_H + +typedef struct tag_kcdb_buf_field { + khm_ui_2 id; + khm_ui_2 flags; + khm_ui_4 offset; + khm_ui_4 cbsize; +} kcdb_buf_field; + +#define KCDB_CREDF_FLAG_EMPTY 0 +#define KCDB_CREDF_FLAG_DATA 1 +#define KCDB_CREDF_FLAG_INLINE 2 +#define KCDB_CREDF_FLAG_ALLOCD 4 + +#define KCDB_BUFF_ID_INVALID 0xffff + +typedef struct tag_kcdb_buf { + void * buffer; + khm_size cb_buffer; + khm_size cb_used; + + kcdb_buf_field * fields; + khm_size n_fields; + khm_size nc_fields; +} kcdb_buf; + +#define KCDB_BUF_CBBUF_INITIAL 4096 +#define KCDB_BUF_CBBUF_GROWTH 4096 +#define KCDB_BUF_FIELDS_INITIAL 16 +#define KCDB_BUF_FIELDS_GROWTH 16 + +#define KCDB_BUF_APPEND 0x8000 + +#define KCDB_BUF_INVALID_SLOT 0xf0000000 +#define KCDB_BUF_DEFAULT 0xe0000000 + +#define KCDB_BUF_MAX_SLOTS 0x00004000 + +void kcdb_buf_new(kcdb_buf * buf, khm_size n_slots); +void kcdb_buf_delete(kcdb_buf * buf); +void kcdb_buf_alloc(kcdb_buf * buf, khm_size slot, khm_ui_2 id, khm_size cbsize); +void kcdb_buf_dup(kcdb_buf * dest, const kcdb_buf * src); +void kcdb_buf_set_value(kcdb_buf * buf, khm_size slot, khm_ui_2 id, void * src, khm_size cb_src); +int kcdb_buf_exist(kcdb_buf * buf, khm_size slot); +int kcdb_buf_val_exist(kcdb_buf * buf, khm_size slot); +void * kcdb_buf_get(kcdb_buf * buf, khm_size slot); +khm_size kcdb_buf_size(kcdb_buf * buf, khm_size slot); +void kcdb_buf_set_value_flag(kcdb_buf * buf, khm_size slot); +khm_size kcdb_buf_slot_by_id(kcdb_buf * buf, khm_ui_2 id); + +#endif diff --git a/mechglue/src/windows/identity/kcreddb/credential.c b/mechglue/src/windows/identity/kcreddb/credential.c new file mode 100644 index 000000000..37f246534 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/credential.c @@ -0,0 +1,1073 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +/* cs_creds protects the *collection* of credentials, while l_creds + protects the *contents* of individual credentials. */ +CRITICAL_SECTION cs_creds; +kcdb_cred * kcdb_creds = NULL; + +/* a read lock must be obtained when querying any existing credential. + a write lock must be obtained when modifying any existing credential. + */ +RWLOCK l_creds; + +/* serial number */ +khm_ui_8 kcdb_cred_id = 0; + +void kcdb_cred_init(void) +{ + InitializeCriticalSection(&cs_creds); + InitializeRwLock(&l_creds); + kcdb_cred_id = 0; +} + +void kcdb_cred_exit(void) +{ + /*TODO: Free the credentials */ + DeleteCriticalSection(&cs_creds); + DeleteRwLock(&l_creds); +} + +/*! \internal + + can be called by kcdb_cred_dup with a write lock on l_creds and in other + places with a read lock on l_creds. New credentials must be creatable while + holding either lock. */ +KHMEXP khm_int32 KHMAPI +kcdb_cred_create(wchar_t * name, + khm_handle identity, + khm_int32 cred_type, + khm_handle * result) +{ + kcdb_cred * cred; + size_t cb_name; + + if(!name || !result || + FAILED(StringCbLength(name, KCDB_CRED_MAXCB_NAME, &cb_name)) || + KHM_FAILED(kcdb_credtype_get_info(cred_type, NULL)) || + KHM_FAILED(kcdb_identity_hold(identity))) { + return KHM_ERROR_INVALID_PARAM; + } + + cb_name += sizeof(wchar_t); + + cred = PMALLOC(sizeof(kcdb_cred)); + ZeroMemory(cred, sizeof(kcdb_cred)); + + cred->magic = KCDB_CRED_MAGIC; + cred->identity = identity; + cred->name = PMALLOC(cb_name); + StringCbCopy(cred->name, cb_name, name); + cred->type = cred_type; + + cred->refcount = 1; /* initially held */ + + LINIT(cred); + + kcdb_buf_new(&cred->buf, KCDB_ATTR_MAX_ID + 1); + + /* Not obtaining a write lock on l_cred on purpose. + Well, because no one should be referencing this credential until + this function returns. */ + EnterCriticalSection(&cs_creds); + cred->id = kcdb_cred_id++; + LPUSH(&kcdb_creds, cred); + LeaveCriticalSection(&cs_creds); + + *result = cred; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_update(khm_handle vdest, + khm_handle vsrc) +{ + khm_int32 rv = KHM_ERROR_EQUIVALENT; + kcdb_cred * src; + kcdb_cred * dest; + kcdb_type * t; + kcdb_attrib * a; + void * srcbuf; + void * destbuf; + khm_size cbsrcbuf; + khm_size cbdestbuf; + + int i; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vsrc) || + !kcdb_cred_is_active_cred(vdest)) + goto _exit; + + src = (kcdb_cred *) vsrc; + dest = (kcdb_cred *) vdest; + + for(i=0;iflags & KCDB_ATTR_FLAG_COMPUTED) || + KHM_FAILED(kcdb_type_get_info(a->type, &t))) { + kcdb_attrib_release_info(a); + continue; + } + + srcbuf = kcdb_cred_buf_get(src,i); + cbsrcbuf = kcdb_cred_buf_size(src, i); + + if(kcdb_cred_val_exist(dest, i)) { + destbuf = kcdb_cred_buf_get(dest, i); + cbdestbuf = kcdb_cred_buf_size(dest, i); + + if(!t->comp(srcbuf, cbsrcbuf, destbuf, cbdestbuf)) + goto _skip_copy; + } + + kcdb_buf_set_value(&dest->buf, i, i, srcbuf, cbsrcbuf); + rv = KHM_ERROR_SUCCESS; + +_skip_copy: + kcdb_attrib_release_info(a); + kcdb_type_release_info(t); + } + } + + if (dest->flags != src->flags) { + khm_int32 old_flags; + + old_flags = dest->flags; + + dest->flags = (src->flags & ~KCDB_CRED_FLAGMASK_ADDITIVE) | + ((src->flags | dest->flags) & KCDB_CRED_FLAGMASK_ADDITIVE); + + if (dest->flags != old_flags) + rv = KHM_ERROR_SUCCESS; + } + +_exit: + kcdb_cred_unlock_write(); + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_dup( + khm_handle vcred, + khm_handle * pnewcred) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + kcdb_cred * newcred; + khm_handle vnewcred; + + if(!pnewcred) + return KHM_ERROR_INVALID_PARAM; + + *pnewcred = NULL; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(KHM_FAILED(kcdb_cred_create(cred->name, + cred->identity, + cred->type, + &vnewcred))) + { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + newcred = (kcdb_cred *) vnewcred; + + newcred->flags = cred->flags; + + kcdb_buf_dup(&newcred->buf, &cred->buf); + + /* newcred is already held from the call to kcdb_cred_create */ + *pnewcred = (khm_handle) newcred; + +_exit: + kcdb_cred_unlock_write(); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_serial( + khm_handle vcred, + khm_ui_8 * pserial) +{ + kcdb_cred * c; + + if(!pserial) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_read(); + return KHM_ERROR_INVALID_PARAM; + } + + c = (kcdb_cred *) vcred; + + *pserial = c->id; + + kcdb_cred_unlock_read(); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_identity( + khm_handle vcred, + khm_handle id) +{ + kcdb_cred * c; + + if(!kcdb_is_identity(id)) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_write(); + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARAM; + } + + c = (kcdb_cred *) vcred; + + if(c->identity) { + kcdb_identity_release((khm_handle) c->identity); + } + kcdb_identity_hold(id); + c->identity = (kcdb_identity *) id; + + kcdb_cred_unlock_write(); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_type( + khm_handle vcred, + khm_int32 * type) +{ + kcdb_cred * c; + + if(!type) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_read(); + return KHM_ERROR_INVALID_PARAM; + } + + c = (kcdb_cred *) vcred; + + *type = c->type; + + kcdb_cred_unlock_read(); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_attrib( + khm_handle cred, + wchar_t * name, + void * buffer, + khm_size cbbuf) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) + return KHM_ERROR_INVALID_PARAM; + + return kcdb_cred_set_attr( + cred, + attr_id, + buffer, + cbbuf); +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_attr( + khm_handle vcred, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf) +{ + kcdb_cred * cred; + kcdb_type * type = NULL; + kcdb_attrib * attrib = NULL; + khm_size cbdest; + khm_int32 code = KHM_ERROR_SUCCESS; + + if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vcred)) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARAM; + } + + cred = (kcdb_cred *) vcred; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + kcdb_cred_unlock_write(); + return KHM_ERROR_INVALID_PARAM; + } + + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) + { + kcdb_cred_unlock_write(); + kcdb_attrib_release_info(attrib); + return KHM_ERROR_INVALID_OPERATION; + } + + if (buffer == 0) { + /* we are removing the value */ + kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0); + code = KHM_ERROR_SUCCESS; + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + kcdb_cred_unlock_write(); + kcdb_attrib_release_info(attrib); + return KHM_ERROR_INVALID_PARAM; + } + + if(!(type->isValid(buffer,cbbuf))) { + code = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + + if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + kcdb_buf_alloc(&cred->buf, attr_id, attr_id, cbdest); + if(!kcdb_cred_buf_exist(cred, attr_id)) { + code = KHM_ERROR_NO_RESOURCES; + goto _exit; + } + + if(KHM_FAILED(code = + type->dup(buffer, cbbuf, kcdb_cred_buf_get(cred,attr_id), &cbdest))) + { + kcdb_buf_alloc(&cred->buf, attr_id, attr_id, 0); + goto _exit; + } + + kcdb_buf_set_value_flag(&cred->buf, attr_id); + +_exit: + kcdb_cred_unlock_write(); + + if(attrib) + kcdb_attrib_release_info(attrib); + if(type) + kcdb_type_release_info(type); + + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib( + khm_handle cred, + wchar_t * name, + khm_int32 * attr_type, + void * buffer, + khm_size * cbbuf) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) + return KHM_ERROR_NOT_FOUND; + + return kcdb_cred_get_attr( + cred, + attr_id, + attr_type, + buffer, + cbbuf); +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_attrib_string( + khm_handle cred, + wchar_t * name, + wchar_t * buffer, + khm_size * cbbuf, + khm_int32 flags) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) + return KHM_ERROR_NOT_FOUND; + + return kcdb_cred_get_attr_string( + cred, + attr_id, + buffer, + cbbuf, + flags); +} + +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attr(khm_handle vcred, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + + if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + return KHM_ERROR_INVALID_PARAM; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + kcdb_attrib_release_info(attrib); + return KHM_ERROR_UNKNOWN; + } + + if(attr_type) + *attr_type = attrib->type; + + kcdb_cred_lock_read(); + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(!buffer && !pcbbuf) { + /* in this case the caller is only trying to determine if the + field contains data. We assume that computed fields are + always non-null. */ + code = (kcdb_cred_val_exist(cred, attr_id) || + (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { + code = attrib->compute_cb( + vcred, + attr_id, + buffer, + pcbbuf); + } else if (kcdb_cred_val_exist(cred, attr_id)) { + code = type->dup( + kcdb_cred_buf_get(cred, attr_id), + kcdb_cred_buf_size(cred, attr_id), + buffer, + pcbbuf); + } else { + code = KHM_ERROR_NOT_FOUND; + } + +_exit: + kcdb_cred_unlock_read(); + if(type) + kcdb_type_release_info(type); + if(attrib) + kcdb_attrib_release_info(attrib); + + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_attr_string( + khm_handle vcred, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + + if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit_nolock; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + code = KHM_ERROR_UNKNOWN; + goto _exit_nolock; + } + + kcdb_cred_lock_read(); + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(!buffer && !pcbbuf) { + /* in this case the caller is only trying to determine if the + field contains data. We assume that computed fields are + always non-null. */ + code = (kcdb_cred_val_exist(cred, attr_id) || + (attrib->flags & KCDB_ATTR_FLAG_COMPUTED))?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { + void * buf; + khm_size cbbuf; + + code = attrib->compute_cb(vcred, + attr_id, + NULL, + &cbbuf); + if(code == KHM_ERROR_TOO_LONG) { + wchar_t vbuf[KCDB_MAXCCH_NAME]; + + if (cbbuf < sizeof(vbuf)) + buf = vbuf; + else + buf = PMALLOC(cbbuf); + + code = attrib->compute_cb(vcred, + attr_id, + buf, + &cbbuf); + if(KHM_SUCCEEDED(code)) { + code = type->toString(buf, + cbbuf, + buffer, + pcbbuf, + flags); + } + + if (buf != vbuf) + PFREE(buf); + } + } else { + if(kcdb_cred_buf_exist(cred, attr_id)) { + code = type->toString( + kcdb_cred_buf_get(cred, attr_id), + kcdb_cred_buf_size(cred, attr_id), + buffer, + pcbbuf, + flags); + } else + code = KHM_ERROR_NOT_FOUND; + } + + _exit: + kcdb_cred_unlock_read(); + _exit_nolock: + if(type) + kcdb_type_release_info(type); + if(attrib) + kcdb_attrib_release_info(attrib); + + return code; +} + + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_name( + khm_handle vcred, + wchar_t * buffer, + khm_size * cbbuf) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred = NULL; + size_t cbsize; + + if(!cbbuf) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(FAILED(StringCbLength(cred->name, KCDB_CRED_MAXCB_NAME, &cbsize))) { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + cbsize += sizeof(wchar_t); + + if(!buffer || *cbbuf < cbsize) { + *cbbuf = cbsize; + code = KHM_ERROR_TOO_LONG; + goto _exit; + } + + StringCbCopy(buffer, *cbbuf, cred->name); + + *cbbuf = cbsize; + +_exit: + + kcdb_cred_unlock_read(); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_get_identity( + khm_handle vcred, + khm_handle * identity) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + if(!identity) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + kcdb_identity_hold((khm_handle) cred->identity); + + *identity = cred->identity; + +_exit: + kcdb_cred_unlock_read(); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_hold(khm_handle vcred) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + cred->refcount++; + +_exit: + kcdb_cred_unlock_write(); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_release(khm_handle vcred) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + cred->refcount--; + +_exit: + kcdb_cred_unlock_write(); + + kcdb_cred_check_and_delete(vcred); + + return code; +} + +void kcdb_cred_check_and_delete(khm_handle vcred) +{ + kcdb_cred * cred; + + kcdb_cred_lock_read(); + if(!kcdb_cred_is_cred(vcred)) { + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + if(cred->refcount) + goto _exit; + + kcdb_cred_unlock_read(); + kcdb_cred_lock_write(); + if(!kcdb_cred_is_cred(vcred)) { + /* did we lose the race? */ + goto _exit2; + } + + cred->magic = 0; /* no longer a cred */ + kcdb_identity_release(cred->identity); + + EnterCriticalSection(&cs_creds); + LDELETE(&kcdb_creds, cred); + LeaveCriticalSection(&cs_creds); + + kcdb_buf_delete(&cred->buf); + PFREE(cred->name); + PFREE(cred); + + /*TODO: notifications */ + +_exit2: + kcdb_cred_unlock_write(); + return; + +_exit: + kcdb_cred_unlock_read(); +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_delete(khm_handle vcred) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + kcdb_cred_lock_write(); + + if(!kcdb_cred_is_active_cred(vcred)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = (kcdb_cred *) vcred; + + cred->flags |= KCDB_CRED_FLAG_DELETED; + +_exit: + kcdb_cred_unlock_write(); + + kcdb_cred_check_and_delete(vcred); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_creds_comp_attrib(khm_handle cred1, + khm_handle cred2, + wchar_t * name) +{ + khm_int32 attr_id; + + if(KHM_FAILED(kcdb_attrib_get_id(name, &attr_id))) + return 0; + + return kcdb_creds_comp_attr(cred1, cred2, attr_id); +} + +KHMEXP khm_int32 KHMAPI +kcdb_creds_comp_attr(khm_handle vcred1, + khm_handle vcred2, + khm_int32 attr_id) +{ + khm_int32 code = 0; + kcdb_cred * cred1; + kcdb_cred * cred2; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + + if(attr_id < 0 || attr_id > KCDB_ATTR_MAX_ID) + return 0; + + cred1 = (kcdb_cred *) vcred1; + cred2 = (kcdb_cred *) vcred2; + + kcdb_cred_lock_read(); + if( + !kcdb_cred_is_active_cred(vcred1) || + !kcdb_cred_is_active_cred(vcred2)) + goto _exit; + + cred1 = (kcdb_cred *) vcred1; + cred2 = (kcdb_cred *) vcred2; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) + goto _exit; + + if(!(attrib->flags & KCDB_ATTR_FLAG_COMPUTED)) { + int nc = 0; + + if(!kcdb_cred_val_exist(cred1, attr_id)) { + code = -1; + nc = 1; + } + if(!kcdb_cred_val_exist(cred2, attr_id)) { + code += 1; + nc = 1; + } + + if(nc) + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) + goto _exit; + + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { + khm_octet vbuf[KCDB_MAXCB_NAME * 2]; + void * buf1 = NULL; + void * buf2 = NULL; + khm_size cb1; + khm_size cb2; + + code = 0; + + if(attrib->compute_cb(vcred1, attr_id, + NULL, &cb1) != KHM_ERROR_TOO_LONG) + goto _exit_1; + + if(attrib->compute_cb(vcred2, attr_id, + NULL, &cb2) != KHM_ERROR_TOO_LONG) + goto _exit_1; + + if(cb1) { + if (cb1 < sizeof(vbuf)) + buf1 = vbuf; + else + buf1 = PMALLOC(cb1); + + if(KHM_FAILED(attrib->compute_cb(vcred1, attr_id, buf1, &cb1))) + goto _exit_1; + } + + if(cb2) { + if (cb1 + cb2 < sizeof(vbuf)) + buf2 = vbuf + cb1; + else + buf2 = PMALLOC(cb2); + + if(KHM_FAILED(attrib->compute_cb(vcred2, attr_id, buf2, &cb2))) + goto _exit_1; + } + + code = type->comp(buf1, cb1, + buf2, cb2); +_exit_1: + if(buf1 && (buf1 < (void *)vbuf || + buf1 >= (void*)(vbuf + sizeof(vbuf)))) + PFREE(buf1); + if(buf2 && (buf2 < (void *)vbuf || + buf2 >= (void *)(vbuf + sizeof(vbuf)))) + PFREE(buf2); + } else { + code = type->comp( + kcdb_cred_buf_get(cred1, attr_id), + kcdb_cred_buf_size(cred1, attr_id), + kcdb_cred_buf_get(cred2, attr_id), + kcdb_cred_buf_size(cred2, attr_id)); + } + +_exit: + kcdb_cred_unlock_read(); + if(attrib) + kcdb_attrib_release_info(attrib); + if(type) + kcdb_type_release_info(type); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_creds_is_equal(khm_handle vcred1, + khm_handle vcred2) +{ + khm_int32 code = 0; + kcdb_cred * cred1; + kcdb_cred * cred2; + + kcdb_cred_lock_read(); + if(!kcdb_cred_is_active_cred(vcred1) || + !kcdb_cred_is_active_cred(vcred2)) + goto _exit; + + if(vcred1 == vcred2) { + code = TRUE; + goto _exit; + } + + cred1 = vcred1; + cred2 = vcred2; + + if(cred1->identity == cred2->identity && + cred1->type == cred2->type && + !wcscmp(cred1->name, cred2->name)) { + + kcdb_credtype * type; + + code = TRUE; + + if (KHM_SUCCEEDED(kcdb_credtype_get_info(cred1->type, &type))) { + if (type->is_equal && + (*type->is_equal)(vcred1, vcred2, NULL)) + code = 0; + + kcdb_credtype_release_info(type); + } + } + +_exit: + kcdb_cred_unlock_read(); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_flags(khm_handle vcred, + khm_int32 * pflags) +{ + khm_int32 f; + khm_int32 rv = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + int release_lock = TRUE; + + if (pflags == NULL) + return KHM_ERROR_INVALID_PARAM; + + kcdb_cred_lock_read(); + if (!kcdb_cred_is_active_cred(vcred)) { + *pflags = 0; + rv = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = vcred; + f = cred->flags; + + /* Update flags if necessary */ + + if (!(f & KCDB_CRED_FLAG_EXPIRED) && + kcdb_cred_buf_exist(cred, KCDB_ATTR_EXPIRE)) { + + FILETIME ftc; + + GetSystemTimeAsFileTime(&ftc); + if (CompareFileTime(&ftc, ((FILETIME *) + kcdb_cred_buf_get(cred, KCDB_ATTR_EXPIRE))) + >= 0) + f |= KCDB_CRED_FLAG_EXPIRED; + } + +#if 0 + /* Commented out: if the credential has expired, then checking the + renewable time is not useful */ + if (!(f & KCDB_CRED_FLAG_INVALID)) { + if (f & KCDB_CRED_FLAG_RENEWABLE) { + if (kcdb_cred_buf_exist(cred, KCDB_ATTR_RENEW_EXPIRE)) { + FILETIME ftc; + + GetSystemTimeAsFileTime(&ftc); + if (CompareFileTime(&ftc, ((FILETIME *) + kcdb_cred_buf_get(cred, KCDB_ATTR_RENEW_EXPIRE))) >= 0) + f |= KCDB_CRED_FLAG_INVALID; + } + } else { + if (f & KCDB_CRED_FLAG_EXPIRED) + f |= KCDB_CRED_FLAG_INVALID; + } + } + + /* Commented out: this is a read operation. We shouldn't attempt + to lock for writing */ + if (f != cred->flags) { + kcdb_cred_unlock_read(); + kcdb_cred_lock_write(); + /* Did we lose a race? */ + if (kcdb_cred_is_active_cred(vcred)) + cred->flags = f; + else { + rv = KHM_ERROR_INVALID_PARAM; + f = 0; + } + kcdb_cred_unlock_write(); + release_lock = FALSE; + } +#endif + + *pflags = f; + + _exit: + if (release_lock) + kcdb_cred_unlock_read(); + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_set_flags( + khm_handle vcred, + khm_int32 flags, + khm_int32 mask) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + kcdb_cred * cred; + + kcdb_cred_lock_write(); + if(!kcdb_cred_is_active_cred(vcred)) { + rv = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + cred = vcred; + + flags &= ~(KCDB_CRED_FLAG_DELETED); + mask &= ~(KCDB_CRED_FLAG_DELETED); + + cred->flags = + (cred->flags & (~mask)) | + (flags & mask); + + _exit: + kcdb_cred_unlock_write(); + return rv; +} diff --git a/mechglue/src/windows/identity/kcreddb/credential.h b/mechglue/src/windows/identity/kcreddb/credential.h new file mode 100644 index 000000000..9cb70ab4d --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/credential.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCDB_CREDENTIAL_H +#define __KHIMAIRA_KCDB_CREDENTIAL_H + +/* Credentials */ + +typedef struct kcdb_cred_t { + khm_int32 magic; + khm_ui_8 id; /* serial number */ + kcdb_identity * identity; + khm_int32 type; + wchar_t * name; + + khm_int32 flags; + khm_int32 refcount; + + kcdb_buf buf; + + LDCL(struct kcdb_cred_t); +} kcdb_cred; + +#define KCDB_CRED_MAGIC 0x38fb84a6 + +extern CRITICAL_SECTION cs_creds; +extern kcdb_cred * kcdb_creds; +extern RWLOCK l_creds; +extern khm_ui_8 kcdb_cred_id; + +#define kcdb_cred_val_exist(c,a) kcdb_buf_val_exist(&(c)->buf, a) +#define kcdb_cred_buf_exist(c,a) kcdb_buf_exist(&(c)->buf, a) +#define kcdb_cred_buf_get(c,a) kcdb_buf_get(&(c)->buf, a) +#define kcdb_cred_buf_size(c,a) kcdb_buf_size(&(c)->buf, a) + +#define kcdb_cred_is_cred(c) ((c) && ((kcdb_cred *) c)->magic == KCDB_CRED_MAGIC) +#define kcdb_cred_is_active_cred(c) (kcdb_cred_is_cred(c) && !(((kcdb_cred *) c)->flags & KCDB_CRED_FLAG_DELETED)) + +#define kcdb_cred_lock_read() (LockObtainRead(&l_creds)) +#define kcdb_cred_unlock_read() (LockReleaseRead(&l_creds)) +#define kcdb_cred_lock_write() (LockObtainWrite(&l_creds)) +#define kcdb_cred_unlock_write() (LockReleaseWrite(&l_creds)) + +void kcdb_cred_init(void); +void kcdb_cred_exit(void); +void kcdb_cred_check_and_delete(khm_handle vcred); + +#endif diff --git a/mechglue/src/windows/identity/kcreddb/credset.c b/mechglue/src/windows/identity/kcreddb/credset.c new file mode 100644 index 000000000..9be551ba1 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/credset.c @@ -0,0 +1,1151 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +CRITICAL_SECTION cs_credset; +kcdb_credset * kcdb_credsets = NULL; +kcdb_credset * kcdb_root_credset = NULL; + +void kcdb_credset_init(void) +{ + khm_handle rc; + + InitializeCriticalSection(&cs_credset); + kcdb_credsets = NULL; + + kcdb_credset_create(&rc); + kcdb_root_credset = (kcdb_credset *) rc; + kcdb_root_credset->flags |= KCDB_CREDSET_FLAG_ROOT; +} + +void kcdb_credset_exit(void) +{ + /*TODO: free the credsets */ + DeleteCriticalSection(&cs_credset); +} + +/* called on an unreleased credset, or with credset::cs held */ +void kcdb_credset_buf_new(kcdb_credset * cs) +{ + cs->clist = PMALLOC(KCDB_CREDSET_INITIAL_SIZE * + sizeof(kcdb_credset_credref)); + ZeroMemory(cs->clist, + KCDB_CREDSET_INITIAL_SIZE * + sizeof(kcdb_credset_credref)); + cs->nc_clist = KCDB_CREDSET_INITIAL_SIZE; + cs->nclist = 0; +} + +/* called on an unreleased credset, or with credset::cs held */ +void kcdb_credset_buf_delete(kcdb_credset * cs) +{ + PFREE(cs->clist); + cs->nc_clist = 0; + cs->nclist = 0; +} + +void kcdb_credset_buf_assert_size(kcdb_credset * cs, khm_int32 nclist) +{ + if(cs->nc_clist < nclist) { + kcdb_credset_credref * new_clist; + + /* nclist had better be greater than KCDB_CREDSET_INITIAL_SIZE */ + nclist = KCDB_CREDSET_INITIAL_SIZE + + (((nclist - (KCDB_CREDSET_INITIAL_SIZE + 1)) / KCDB_CREDSET_GROWTH_FACTOR) + 1) * + KCDB_CREDSET_GROWTH_FACTOR; + + new_clist = PCALLOC(nclist, sizeof(kcdb_credset_credref)); + + memcpy(new_clist, cs->clist, cs->nclist * sizeof(kcdb_credset_credref)); + + PFREE(cs->clist); + + cs->clist = new_clist; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_create(khm_handle * result) +{ + kcdb_credset * cs; + + cs = PMALLOC(sizeof(kcdb_credset)); + ZeroMemory(cs, sizeof(kcdb_credset)); + + cs->magic = KCDB_CREDSET_MAGIC; + InitializeCriticalSection(&(cs->cs)); + LINIT(cs); + kcdb_credset_buf_new(cs); + cs->version = 0; + cs->seal_count = 0; + + EnterCriticalSection(&cs_credset); + LPUSH(&kcdb_credsets, cs); + LeaveCriticalSection(&cs_credset); + + *result = (khm_handle) cs; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_delete(khm_handle vcredset) +{ + kcdb_credset * cs; + int i; + + if(!kcdb_credset_is_credset(vcredset)) { + return KHM_ERROR_INVALID_PARAM; + } + + cs = (kcdb_credset *) vcredset; + + EnterCriticalSection(&cs_credset); + LDELETE(&kcdb_credsets, cs); + LeaveCriticalSection(&cs_credset); + + EnterCriticalSection(&(cs->cs)); + cs->magic = 0; + + for(i=0;inclist;i++) { + if(cs->clist[i].cred) { + kcdb_cred_release((khm_handle) cs->clist[i].cred); + } + } + kcdb_credset_buf_delete(cs); + + LeaveCriticalSection(&(cs->cs)); + DeleteCriticalSection(&(cs->cs)); + + PFREE(cs); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + +Collect credentials from cs2 to cs1 which have already been selected into +cl1 and cl2. + +- Credentials in cl2 that are not in cl1 will get added to cs1 +- Credentials in cl1 that are not in cl2 will get removed from cs1 +- Credentials in cl1 and cl2 will be updated in cs1 + +cl1 and cl2 will be modified. +*/ +khm_int32 +kcdb_credset_collect_core(kcdb_credset * cs1, + kcdb_cred ** cl1, + khm_int32 ncl1, + kcdb_credset * cs2, + kcdb_cred ** cl2, + khm_int32 ncl2, + khm_int32 * delta) +{ + int i, j; + int ldelta = 0; + khm_int32 rv; + + /* find matching creds and update them */ + for(i=0; ics)); + EnterCriticalSection(&(rcs->cs)); + + /* enumerate through the root and given credential sets and select + the ones we want */ + + if(rcs->nclist > 0) + r_sel = PMALLOC(sizeof(kcdb_cred *) * rcs->nclist); + if(cs->nclist > 0) + c_sel = PMALLOC(sizeof(kcdb_cred *) * cs->nclist); + nr_sel = 0; + nc_sel = 0; + + for(i=0; inclist; i++) { + if(rcs->clist[i].cred && + (!identity || rcs->clist[i].cred->identity == identity) && + (type==KCDB_CREDTYPE_ALL || rcs->clist[i].cred->type == type)) + { + r_sel[nr_sel++] = rcs->clist[i].cred; + } + } + + for(i=0; inclist; i++) { + if(cs->clist[i].cred && + (!identity || cs->clist[i].cred->identity == identity) && + (type==KCDB_CREDTYPE_ALL || cs->clist[i].cred->type == type)) + { + c_sel[nc_sel++] = cs->clist[i].cred; + } + } + + rcs->version++; + + code = kcdb_credset_collect_core( + rcs, + r_sel, + nr_sel, + cs, + c_sel, + nc_sel, + delta); + + LeaveCriticalSection(&(rcs->cs)); + LeaveCriticalSection(&(cs->cs)); + + if(r_sel) + PFREE(r_sel); + if(c_sel) + PFREE(c_sel); + + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_collect_filtered( + khm_handle cs_dest, + khm_handle cs_src, + kcdb_cred_filter_func filter, + void * rock, + khm_int32 * delta) +{ + kcdb_credset * cs; + kcdb_credset * rcs; + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_cred ** r_sel = NULL; + kcdb_cred ** c_sel = NULL; + int nr_sel, nc_sel; + int i; + khm_int32 cs_f = 0; + khm_int32 rcs_f = 0; + + if((cs_src && !kcdb_credset_is_credset(cs_src)) || + (cs_dest && !kcdb_credset_is_credset(cs_dest)) || + (cs_src == cs_dest)) /* works because credsets use shared + handles */ + return KHM_ERROR_INVALID_PARAM; + + if(cs_src) + cs = (kcdb_credset *) cs_src; + else { + cs = kcdb_root_credset; + cs_f = KCDB_CREDCOLL_FILTER_ROOT; + } + + if(cs_dest) + rcs = (kcdb_credset *) cs_dest; + else { + rcs = kcdb_root_credset; + rcs_f = KCDB_CREDCOLL_FILTER_ROOT; + } + + if (kcdb_credset_is_sealed(rcs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + EnterCriticalSection(&(rcs->cs)); + +#ifdef DEBUG + assert(!(rcs->flags & KCDB_CREDSET_FLAG_ENUM)); + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + if(rcs->nclist) + r_sel = PMALLOC(sizeof(kcdb_cred *) * rcs->nclist); + if(cs->nclist) + c_sel = PMALLOC(sizeof(kcdb_cred *) * cs->nclist); + nr_sel = 0; + nc_sel = 0; + + rcs->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(i=0; inclist; i++) { + if(rcs->clist[i].cred && + (*filter)((khm_handle)rcs->clist[i].cred, + KCDB_CREDCOLL_FILTER_DEST | rcs_f, + rock)) + { + r_sel[nr_sel++] = rcs->clist[i].cred; + } + } + + rcs->flags &= ~KCDB_CREDSET_FLAG_ENUM; + cs->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(i=0; inclist; i++) { + if(cs->clist[i].cred && filter((khm_handle)rcs->clist[i].cred, KCDB_CREDCOLL_FILTER_SRC | cs_f, rock)) + { + c_sel[nc_sel++] = cs->clist[i].cred; + } + } + + cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; + + rcs->version++; + + code = kcdb_credset_collect_core( + rcs, + r_sel, + nr_sel, + cs, + c_sel, + nc_sel, + delta); + + LeaveCriticalSection(&(rcs->cs)); + LeaveCriticalSection(&(cs->cs)); + + if(r_sel) + PFREE(r_sel); + if(c_sel) + PFREE(c_sel); + + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_flush(khm_handle vcredset) +{ + int i; + kcdb_credset * cs; + + if(!kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) vcredset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + for(i=0;inclist;i++) { + if(cs->clist[i].cred) { + kcdb_cred_release((khm_handle) cs->clist[i].cred); + } + } + cs->nclist = 0; + LeaveCriticalSection(&(cs->cs)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_extract( + khm_handle destcredset, + khm_handle sourcecredset, + khm_handle identity, + khm_int32 type) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_credset * dest; + kcdb_credset * src; + int isRoot = 0; + khm_size srcSize = 0; + int i; + + if(!kcdb_credset_is_credset(destcredset)) + return KHM_ERROR_INVALID_PARAM; + + if(sourcecredset) { + if(!kcdb_credset_is_credset(sourcecredset)) + return KHM_ERROR_INVALID_PARAM; + } else { + sourcecredset = kcdb_root_credset; + } + + if (sourcecredset == kcdb_root_credset) + isRoot = 1; + + src = (kcdb_credset *) sourcecredset; + dest = (kcdb_credset *) destcredset; + + if (kcdb_credset_is_sealed(dest)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(src->cs)); + EnterCriticalSection(&(dest->cs)); + +#ifdef DEBUG + assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + kcdb_cred_lock_read(); + + for(i=0; i < (int) srcSize; i++) { + kcdb_cred * c; + + c = src->clist[i].cred; + if(kcdb_cred_is_active_cred((khm_handle) c) && + (!identity || c->identity == identity) && + (type==KCDB_TYPE_INVALID || c->type == type)) + { + if(isRoot) { + khm_handle newcred; + + kcdb_cred_unlock_read(); + kcdb_cred_dup((khm_handle) c, &newcred); + kcdb_credset_add_cred(destcredset, newcred, -1); + kcdb_cred_release(newcred); + kcdb_cred_lock_read(); + } else { + kcdb_cred_unlock_read(); + kcdb_credset_add_cred(destcredset, (khm_handle) c, -1); + kcdb_cred_lock_read(); + } + } + } + + kcdb_cred_unlock_read(); + +_exit: + LeaveCriticalSection(&(dest->cs)); + LeaveCriticalSection(&(src->cs)); + + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_extract_filtered( + khm_handle destcredset, + khm_handle sourcecredset, + kcdb_cred_filter_func filter, + void * rock) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_credset * dest; + kcdb_credset * src; + int isRoot = 0; + khm_size srcSize = 0; + int i; + + if(!kcdb_credset_is_credset(destcredset)) + return KHM_ERROR_INVALID_PARAM; + + if(sourcecredset) { + if(!kcdb_credset_is_credset(sourcecredset)) + return KHM_ERROR_INVALID_PARAM; + } else { + sourcecredset = kcdb_root_credset; + isRoot = 1; + } + + src = (kcdb_credset *) sourcecredset; + dest = (kcdb_credset *) destcredset; + + if (kcdb_credset_is_sealed(dest)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(src->cs)); + EnterCriticalSection(&(dest->cs)); + +#ifdef DEBUG + assert(!(dest->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + if(KHM_FAILED(kcdb_credset_get_size(sourcecredset, &srcSize))) { + code = KHM_ERROR_UNKNOWN; + goto _exit; + } + + kcdb_cred_lock_read(); + + dest->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(i=0; i < (int) srcSize; i++) { + kcdb_cred * c; + + c = src->clist[i].cred; + if(kcdb_cred_is_active_cred((khm_handle) c) && + filter(c, 0, rock)) + { + if(isRoot) { + khm_handle newcred; + + kcdb_cred_unlock_read(); + kcdb_cred_dup((khm_handle) c, &newcred); + kcdb_credset_add_cred(destcredset, newcred, -1); + kcdb_cred_release(newcred); + kcdb_cred_lock_read(); + } else { + kcdb_cred_unlock_read(); + kcdb_credset_add_cred(destcredset, (khm_handle) c, -1); + kcdb_cred_lock_read(); + } + } + } + + dest->flags &= ~KCDB_CREDSET_FLAG_ENUM; + + kcdb_cred_unlock_read(); + +_exit: + LeaveCriticalSection(&(dest->cs)); + LeaveCriticalSection(&(src->cs)); + + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_apply(khm_handle vcredset, kcdb_cred_apply_func f, void * rock) +{ + kcdb_credset * cs; + khm_int32 rv = KHM_ERROR_SUCCESS; + int i; + + if(vcredset != NULL && !kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + if(vcredset == NULL) { + cs = kcdb_root_credset; + } else { + cs = (kcdb_credset *) vcredset; + } + + EnterCriticalSection(&cs->cs); + +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + cs->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(i=0; inclist; i++) { + if(!kcdb_cred_is_active_cred(cs->clist[i].cred)) + continue; + + if(KHM_FAILED(f((khm_handle) cs->clist[i].cred, rock))) + break; + } + + cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; + + LeaveCriticalSection(&cs->cs); + + if(inclist) + rv = KHM_ERROR_EXIT; + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_get_cred( + khm_handle vcredset, + khm_int32 idx, + khm_handle * cred) +{ + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + + if(!kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) vcredset; + + *cred = NULL; + + EnterCriticalSection(&(cs->cs)); + if(idx < 0 || idx >= cs->nclist) + code = KHM_ERROR_OUT_OF_BOUNDS; + else if(!cs->clist[idx].cred || !kcdb_cred_is_active_cred((khm_handle) cs->clist[idx].cred)) { + code = KHM_ERROR_DELETED; + if(cs->clist[idx].cred) { + kcdb_cred_release((khm_handle) cs->clist[idx].cred); + cs->clist[idx].cred = NULL; + } + } + else { + kcdb_cred_hold((khm_handle) cs->clist[idx].cred); + *cred = cs->clist[idx].cred; + } + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_find_filtered( + khm_handle credset, + khm_int32 idx_start, + kcdb_cred_filter_func f, + void * rock, + khm_handle * cred, + khm_int32 * idx) +{ + kcdb_credset * cs; + khm_int32 rv = KHM_ERROR_SUCCESS; + int i; + + if((credset && !kcdb_credset_is_credset(credset)) || !f) + return KHM_ERROR_INVALID_PARAM; + + if(credset) + cs = (kcdb_credset *) credset; + else + cs = kcdb_root_credset; + + EnterCriticalSection(&cs->cs); + + if(idx_start < 0) + i = 0; + else + i = idx_start + 1; + +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + cs->flags |= KCDB_CREDSET_FLAG_ENUM; + + for(; i < cs->nclist; i++) { + if(kcdb_cred_is_active_cred(cs->clist[i].cred) && + (*f)((khm_handle) cs->clist[i].cred, 0, rock) != 0) + break; + } + + cs->flags &= ~KCDB_CREDSET_FLAG_ENUM; + + if(i < cs->nclist) { + if (cred) { + *cred = (khm_handle) cs->clist[i].cred; + kcdb_cred_hold(*cred); + } + + if(idx) { + *idx = i; + } + } else { + rv = KHM_ERROR_NOT_FOUND; + } + + LeaveCriticalSection(&cs->cs); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_find_cred(khm_handle vcredset, + khm_handle vcred_src, + khm_handle *cred_dest) { + kcdb_credset * cs; + khm_handle cred = NULL; + int idx; + + if (!kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + if (!kcdb_cred_is_active_cred(vcred_src)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) vcredset; + + EnterCriticalSection(&cs->cs); + for (idx = 0; idx < cs->nclist; idx++) { + if (cs->clist[idx].cred && + kcdb_creds_is_equal(vcred_src, cs->clist[idx].cred)) { + cred = cs->clist[idx].cred; + break; + } + } + + if (cred) + kcdb_cred_hold(cred); + + LeaveCriticalSection(&cs->cs); + + if (cred) { + if (cred_dest) + *cred_dest = cred; + else + kcdb_cred_release(cred); + + return KHM_ERROR_SUCCESS; + } else { + return KHM_ERROR_NOT_FOUND; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred( + khm_handle vcredset, + khm_int32 idx) +{ + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + + if(!kcdb_credset_is_credset(vcredset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) vcredset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + if(idx < 0 || idx >= cs->nclist) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + if(cs->clist[idx].cred) + kcdb_cred_release((khm_handle) cs->clist[idx].cred); + + if (!(cs->flags & KCDB_CREDSET_FLAG_ENUM)) { + + if(idx + 1 < cs->nclist) + memmove(&(cs->clist[idx]), + &(cs->clist[idx+1]), + sizeof(kcdb_credset_credref) * + (cs->nclist - (idx + 1))); + + cs->nclist--; + } else { + cs->clist[idx].cred = NULL; + } + +_exit: + LeaveCriticalSection(&(cs->cs)); + + return code; +} + +khm_int32 kcdb_credset_update_cred_ref( + khm_handle credset, + khm_handle cred) +{ + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + int i; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + EnterCriticalSection(&(cs->cs)); + + for(i=0; inclist; i++) { + if(cs->clist[i].cred == cred) + break; + } + + if(inclist) { + cs->clist[i].version = cs->version; + } else { + code = KHM_ERROR_NOT_FOUND; + } + + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_del_cred_ref( + khm_handle credset, + khm_handle cred) +{ + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + int i; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + + for(i=0; inclist; i++) { + if(cs->clist[i].cred == cred) + break; + } + + if(inclist) { + code = kcdb_credset_del_cred(credset, i); + } else { + code = KHM_ERROR_NOT_FOUND; + } + + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_add_cred( + khm_handle credset, + khm_handle cred, + khm_int32 idx) +{ + int new_idx; + kcdb_credset * cs; + khm_int32 code = KHM_ERROR_SUCCESS; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + + kcdb_credset_buf_assert_size(cs, cs->nclist + 1); + + if(idx < 0 || idx > cs->nclist) + new_idx = cs->nclist; + else if(idx < cs->nclist){ +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + memmove(&(cs->clist[idx+1]), &(cs->clist[idx]), (cs->nclist - idx)*sizeof(cs->clist[0])); + new_idx = idx; + } else + new_idx = idx; + + kcdb_cred_hold(cred); + + cs->clist[new_idx].cred = (kcdb_cred *) cred; + cs->clist[new_idx].version = cs->version; + cs->nclist++; + + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_get_size( + khm_handle credset, + khm_size * size) +{ + kcdb_credset * cs; + + *size = 0; + + /* we don't rely on this working, since we can't purge a sealed + credset, although we can measure its size. */ + kcdb_credset_purge(credset); + + if (credset == NULL) + cs = kcdb_root_credset; + else + cs = (kcdb_credset *) credset; + + EnterCriticalSection(&(cs->cs)); + /* while it may seem a bit redundant to get a lock, it ensures that + that the size that we return is consistent with the current state + of the credential set */ + *size = cs->nclist; + LeaveCriticalSection(&(cs->cs)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_purge(khm_handle credset) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_credset * cs; + int i,j; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + + /* we can't purge a credset while an enumeration operation is in + progress. */ + if (cs->flags & KCDB_CREDSET_FLAG_ENUM) { + code = KHM_ERROR_INVALID_OPERATION; + goto _exit; + } + + for(i=0,j=0; i < cs->nclist; i++) { + if(cs->clist[i].cred) { + if(!kcdb_cred_is_active_cred((khm_handle) cs->clist[i].cred)) { + kcdb_cred_release((khm_handle) cs->clist[i].cred); + } else if(i != j) { + cs->clist[j++] = cs->clist[i]; + } else + j++; + } + } + cs->nclist = j; + + _exit: + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_seal(khm_handle credset) { + kcdb_credset * cs; + + if (!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + EnterCriticalSection(&cs->cs); + cs->seal_count++; + LeaveCriticalSection(&cs->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_credset_unseal(khm_handle credset) { + kcdb_credset * cs; + khm_int32 rv; + + if (!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + EnterCriticalSection(&cs->cs); + if (cs->seal_count > 0) { + cs->seal_count--; + rv = KHM_ERROR_SUCCESS; + } else { + rv = KHM_ERROR_INVALID_OPERATION; + } + LeaveCriticalSection(&cs->cs); + + return rv; +} + + +/* wrapper for qsort and also parameter gobbling FSM. */ +int __cdecl kcdb_creds_comp_wrapper(const void * a, const void * b) +{ + static void * rock = NULL; + static kcdb_cred_comp_func comp = NULL; + + if(!b) { + rock = (void *) a; + return 0; + } + + if(!a) { + comp = (kcdb_cred_comp_func) b; + return 0; + } + + return comp((khm_handle) ((kcdb_credset_credref *)a)->cred, + (khm_handle) ((kcdb_credset_credref *)b)->cred, + rock); +} + +KHMEXP khm_int32 KHMAPI kcdb_credset_sort( + khm_handle credset, + kcdb_cred_comp_func comp, + void * rock) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_credset * cs; + + if(!kcdb_credset_is_credset(credset)) + return KHM_ERROR_INVALID_PARAM; + + cs = (kcdb_credset *) credset; + + if (kcdb_credset_is_sealed(cs)) + return KHM_ERROR_INVALID_OPERATION; + + EnterCriticalSection(&(cs->cs)); + +#ifdef DEBUG + assert(!(cs->flags & KCDB_CREDSET_FLAG_ENUM)); +#endif + + kcdb_creds_comp_wrapper(rock, NULL); + kcdb_creds_comp_wrapper(NULL, (void *) comp); + + qsort(cs->clist, cs->nclist, sizeof(kcdb_credset_credref), kcdb_creds_comp_wrapper); + + LeaveCriticalSection(&(cs->cs)); + return code; +} + +KHMEXP khm_int32 KHMAPI kcdb_cred_comp_generic( + khm_handle cred1, + khm_handle cred2, + void * rock) +{ + kcdb_cred_comp_order * o = (kcdb_cred_comp_order *) rock; + int i; + khm_int32 r = 0; + khm_int32 f1, f2; + khm_int32 t1, t2; + khm_int32 pt; + + for(i=0; inFields; i++) { + if (o->fields[i].order & KCDB_CRED_COMP_INITIAL_FIRST) { + + if (o->fields[i].attrib == KCDB_ATTR_TYPE_NAME || + o->fields[i].attrib == KCDB_ATTR_TYPE) { + + kcdb_cred_get_type(cred1, &t1); + kcdb_cred_get_type(cred2, &t2); + kcdb_identity_get_type(&pt); + + if (t1 == t2) + r = 0; + else if (t1 == pt) + r = -1; + else if (t2 == pt) + r = 1; + else + r = 0; + + } else { + + kcdb_cred_get_flags(cred1, &f1); + kcdb_cred_get_flags(cred2, &f2); + + if (((f1 ^ f2) & KCDB_CRED_FLAG_INITIAL) == 0) + r = 0; + else if (f1 & KCDB_CRED_FLAG_INITIAL) + r = -1; + else + r = 1; + + } + + } else { + r = 0; + } + + if (r == 0) + r = kcdb_creds_comp_attr(cred1,cred2,o->fields[i].attrib); + + if(r != 0) { + if(o->fields[i].order & KCDB_CRED_COMP_DECREASING) + r = -r; + break; + } + } + + return r; +} diff --git a/mechglue/src/windows/identity/kcreddb/credset.h b/mechglue/src/windows/identity/kcreddb/credset.h new file mode 100644 index 000000000..cd216fdd2 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/credset.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCDB_CREDSET_H +#define __KHIMAIRA_KCDB_CREDSET_H + +/* credset */ + +typedef struct kcdb_credset_credref_t { + khm_int32 version; + kcdb_cred * cred; +} kcdb_credset_credref; + +typedef struct kcdb_credset_t { + khm_int32 magic; + khm_int32 flags; + CRITICAL_SECTION cs; + + kcdb_credset_credref * clist; + khm_int32 nc_clist; /* total capacity */ + khm_int32 nclist; /* current load */ + + khm_int32 version; /* data version */ + + khm_int32 seal_count; /* number of seals applied to the + credset */ + + struct kcdb_credset_t * next; + struct kcdb_credset_t * prev; +} kcdb_credset; + +#define KCDB_CREDSET_MAGIC 0x63a84f8b + +#define KCDB_CREDSET_FLAG_ROOT 1 + +/* the credset is in the process of being enumerated */ +#define KCDB_CREDSET_FLAG_ENUM 2 + +#define kcdb_credset_is_credset(c) ((c) && ((kcdb_credset *)c)->magic == KCDB_CREDSET_MAGIC) + +#define kcdb_credset_is_sealed(c) ((c)->seal_count != 0) + +#define KCDB_CREDSET_INITIAL_SIZE 256 +#define KCDB_CREDSET_GROWTH_FACTOR 256 + +void kcdb_credset_init(void); +void kcdb_credset_exit(void); +khm_int32 kcdb_credset_update_cred_ref( + khm_handle credset, + khm_handle cred); + +#endif diff --git a/mechglue/src/windows/identity/kcreddb/credtype.c b/mechglue/src/windows/identity/kcreddb/credtype.c new file mode 100644 index 000000000..e57b22b53 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/credtype.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +CRITICAL_SECTION cs_credtype; +kcdb_credtype_i ** kcdb_credtype_tbl = NULL; +kcdb_credtype_i * kcdb_credtypes = NULL; + +void kcdb_credtype_init(void) +{ + InitializeCriticalSection(&cs_credtype); + kcdb_credtypes = NULL; + + kcdb_credtype_tbl = PMALLOC(sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1)); + ZeroMemory(kcdb_credtype_tbl, sizeof(kcdb_credtype_i *) * (KCDB_CREDTYPE_MAX_ID+1)); +} + +void kcdb_credtype_exit(void) +{ + /*TODO:Free up the cred types */ + PFREE(kcdb_credtype_tbl); + DeleteCriticalSection(&cs_credtype); +} + +/* Called with cs_credtype held */ +void kcdb_credtype_check_and_delete(khm_int32 id) +{ + kcdb_credtype_i * ict; + ict = kcdb_credtype_tbl[id]; + if(!ict) + return; + + if((ict->flags & KCDB_CTI_FLAG_DELETED) && + !ict->refcount) + { + kcdb_credtype_tbl[id] = NULL; + LDELETE(&kcdb_credtypes, ict); + + PFREE(ict->ct.name); + if(ict->ct.short_desc) + PFREE(ict->ct.short_desc); + if(ict->ct.long_desc) + PFREE(ict->ct.long_desc); + if(ict->ct.sub) + kmq_delete_subscription(ict->ct.sub); + + PFREE(ict); + } +} + +KHMEXP khm_int32 KHMAPI +kcdb_credtype_register(kcdb_credtype * type, khm_int32 * new_id) +{ + khm_int32 id; + kcdb_credtype_i * ict; + size_t cb_name; + size_t cb_short_desc; + size_t cb_long_desc; + int i; + + if(!type) + return KHM_ERROR_INVALID_PARAM; + + if(type->id >= KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + if(type->name) { + if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cb_name))) + return KHM_ERROR_TOO_LONG; + cb_name += sizeof(wchar_t); + } else + return KHM_ERROR_INVALID_PARAM; + + if(type->short_desc) { + if(FAILED(StringCbLength(type->short_desc, KCDB_MAXCB_SHORT_DESC, &cb_short_desc))) + return KHM_ERROR_TOO_LONG; + cb_short_desc += sizeof(wchar_t); + } else + cb_short_desc = 0; + + if(type->long_desc) { + if(FAILED(StringCbLength(type->long_desc, KCDB_MAXCB_LONG_DESC, &cb_long_desc))) + return KHM_ERROR_TOO_LONG; + cb_long_desc += sizeof(wchar_t); + } else + cb_long_desc = 0; + + if(type->sub == NULL) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + + if(type->id < 0) { + if(KHM_FAILED(kcdb_credtype_get_next_free_id(&id))) { + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_NO_RESOURCES; + } + } + else + id = type->id; + + if(kcdb_credtype_tbl[id]) { + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_DUPLICATE; + } + + for(i=0;i<=KCDB_CREDTYPE_MAX_ID;i++) { + if(kcdb_credtype_tbl[i] && !wcscmp(kcdb_credtype_tbl[i]->ct.name, type->name)) { + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_DUPLICATE; + } + } + + ict = PMALLOC(sizeof(kcdb_credtype_i)); + ZeroMemory(ict, sizeof(kcdb_credtype_i)); + + ict->ct.name = PMALLOC(cb_name); + StringCbCopy(ict->ct.name, cb_name, type->name); + + if(cb_short_desc) { + ict->ct.short_desc = PMALLOC(cb_short_desc); + StringCbCopy(ict->ct.short_desc, cb_short_desc, type->short_desc); + } + + if(cb_long_desc) { + ict->ct.long_desc = PMALLOC(cb_long_desc); + StringCbCopy(ict->ct.long_desc, cb_long_desc, type->long_desc); + } + + ict->ct.id = id; + + ict->ct.icon = type->icon; + + ict->ct.sub = type->sub; + + ict->ct.is_equal = type->is_equal; + + kcdb_credtype_tbl[id] = ict; + + LPUSH(&kcdb_credtypes, ict); + + LeaveCriticalSection(&cs_credtype); + + kcdb_credtype_post_message(KCDB_OP_INSERT, &(ict->ct)); + + if (new_id) + *new_id = id; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_get_info( + khm_int32 id, + kcdb_credtype ** type) +{ + int found = 0; + + if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + if(kcdb_credtype_tbl[id] && + !(kcdb_credtype_tbl[id]->flags & KCDB_CTI_FLAG_DELETED)) + { + found = 1; + if(type) { + *type = &(kcdb_credtype_tbl[id]->ct); + kcdb_credtype_hold(kcdb_credtype_tbl[id]); + } + } else { + if(type) + *type = NULL; + } + LeaveCriticalSection(&cs_credtype); + + if(found) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_release_info(kcdb_credtype * type) +{ + kcdb_credtype_i * ict; + + if(!type) + return KHM_ERROR_INVALID_PARAM; + + ict = (kcdb_credtype_i *) type; + return kcdb_credtype_release(ict); +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_unregister(khm_int32 id) +{ + kcdb_credtype_i * ict; + + if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + ict = kcdb_credtype_tbl[id]; + ict->flags |= KCDB_CTI_FLAG_DELETED; + kcdb_credtype_check_and_delete(id); + LeaveCriticalSection(&cs_credtype); + + //kcdb_credtype_post_message(KCDB_OP_DELETE, &(ict->ct)); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_handle KHMAPI kcdb_credtype_get_sub(khm_int32 id) +{ + kcdb_credtype_i * t; + khm_handle s; + + if(id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return NULL; + + EnterCriticalSection(&cs_credtype); + t = kcdb_credtype_tbl[id]; + if(t) + s = t->ct.sub; + else + s = NULL; + LeaveCriticalSection(&cs_credtype); + + return s; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_describe( + khm_int32 id, + wchar_t * buf, + khm_size * cbbuf, + khm_int32 flags) +{ + size_t s; + size_t maxs; + wchar_t * str; + kcdb_credtype_i * t; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + t = kcdb_credtype_tbl[id]; + if(t) { + if(flags & KCDB_TS_SHORT) { + str = (t->ct.short_desc)?t->ct.short_desc:t->ct.name; + maxs = (t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME; + } else { + str = (t->ct.long_desc)?t->ct.long_desc:((t->ct.short_desc)?t->ct.short_desc:t->ct.name); + maxs = (t->ct.long_desc)?KCDB_MAXCB_LONG_DESC:((t->ct.short_desc)?KCDB_MAXCB_SHORT_DESC:KCDB_MAXCB_NAME); + } + StringCbLength(str, maxs, &s); + s += sizeof(wchar_t); + if(!buf || *cbbuf < s) { + *cbbuf = s; + rv = KHM_ERROR_TOO_LONG; + } else { +#pragma warning(push) +#pragma warning(disable:4995) + wcscpy(buf, str); /* str is one of the string fields in t->ct which has + been validated when the type was registered. */ +#pragma warning(pop) + *cbbuf = s; + } + } else { + if(buf && *cbbuf > 0) + *buf = L'\0'; + *cbbuf = 0; + rv = KHM_ERROR_NOT_FOUND; + } + LeaveCriticalSection(&cs_credtype); + + return rv; +} + + +KHMEXP khm_int32 KHMAPI kcdb_credtype_get_name( + khm_int32 id, + wchar_t * buf, + khm_size * cbbuf) +{ + size_t s; + kcdb_credtype_i * t; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!cbbuf || id < 0 || id > KCDB_CREDTYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + t = kcdb_credtype_tbl[id]; + if(t) { + StringCbLength(t->ct.name, KCDB_MAXCB_NAME, &s); + s += sizeof(wchar_t); + if(!buf || *cbbuf < s) { + *cbbuf = s; + rv = KHM_ERROR_TOO_LONG; + } else { +#pragma warning(push) +#pragma warning(disable: 4995) + wcscpy(buf, t->ct.name); /* t->ct.name was validated when the type was registered */ +#pragma warning(pop) + *cbbuf = s; + } + } else { + *cbbuf = 0; + rv = KHM_ERROR_NOT_FOUND; + } + LeaveCriticalSection(&cs_credtype); + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_credtype_get_id( + wchar_t * name, + khm_int32 * id) +{ + int i; + + *id = 0; + if(!name) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) { + if(kcdb_credtype_tbl[i] && !wcscmp(name, kcdb_credtype_tbl[i]->ct.name)) + break; + } + LeaveCriticalSection(&cs_credtype); + + if(i <= KCDB_CREDTYPE_MAX_ID) { + *id = i; + return KHM_ERROR_SUCCESS; + } else + return KHM_ERROR_NOT_FOUND; +} + +khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id) +{ + int i; + + EnterCriticalSection(&cs_credtype); + for(i=0;i <= KCDB_CREDTYPE_MAX_ID; i++) { + if(!kcdb_credtype_tbl[i]) + break; + } + LeaveCriticalSection(&cs_credtype); + + if(i <= KCDB_CREDTYPE_MAX_ID) { + *id = i; + return KHM_ERROR_SUCCESS; + } else { + *id = -1; + return KHM_ERROR_NO_RESOURCES; + } +} + +khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict) { + + if(!ict) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + ict->refcount++; + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_SUCCESS; +} + +khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict) { + + if(!ict) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_credtype); + ict->refcount--; + kcdb_credtype_check_and_delete(ict->ct.id); + LeaveCriticalSection(&cs_credtype); + return KHM_ERROR_SUCCESS; +} + +void kcdb_credtype_msg_completion(kmq_message * m) +{ + kcdb_credtype_release((kcdb_credtype_i *) m->vparam); +} + +void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type) +{ + kcdb_credtype_hold((kcdb_credtype_i *) type); + kmq_post_message(KMSG_KCDB, KMSG_KCDB_CREDTYPE, op, (void *) type); +} diff --git a/mechglue/src/windows/identity/kcreddb/credtype.h b/mechglue/src/windows/identity/kcreddb/credtype.h new file mode 100644 index 000000000..aa605d730 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/credtype.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCDB_CREDTYPE_H +#define __KHIMAIRA_KCDB_CREDTYPE_H + +/* credtype */ +typedef struct kcdb_credtype_i_t { + kcdb_credtype ct; + khm_int32 refcount; + khm_int32 flags; + + struct kcdb_credtype_i_t * next; + struct kcdb_credtype_i_t * prev; +} kcdb_credtype_i; + +#define KCDB_CTI_FLAG_DELETED 8 + +extern CRITICAL_SECTION cs_credtype; +extern kcdb_credtype_i * kcdb_credtypes; +extern kcdb_credtype_i ** kcdb_credtype_tbl; + +void kcdb_credtype_init(void); +void kcdb_credtype_exit(void); +void kcdb_credtype_check_and_delete(khm_int32 id); +khm_int32 kcdb_credtype_hold(kcdb_credtype_i * ict); +khm_int32 kcdb_credtype_release(kcdb_credtype_i * ict); +void kcdb_credtype_msg_completion(kmq_message * m); +void kcdb_credtype_post_message(khm_int32 op, kcdb_credtype * type); +khm_int32 kcdb_credtype_get_next_free_id(khm_int32 * id); + +#endif diff --git a/mechglue/src/windows/identity/kcreddb/identity.c b/mechglue/src/windows/identity/kcreddb/identity.c new file mode 100644 index 000000000..e96c99608 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/identity.c @@ -0,0 +1,1582 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +static CRITICAL_SECTION cs_ident; +hashtable * kcdb_identities_namemap = NULL; +khm_int32 kcdb_n_identities = 0; +kcdb_identity * kcdb_identities = NULL; +kcdb_identity * kcdb_def_identity = NULL; +khm_handle kcdb_ident_sub = NULL; /* identity provider */ +khm_int32 kcdb_ident_cred_type = KCDB_CREDTYPE_INVALID; +/* primary credentials type */ +khm_ui_4 kcdb_ident_refresh_cycle = 0; +khm_boolean kcdb_checked_config = FALSE; +khm_boolean kcdb_checking_config = FALSE; + +KHMEXP khm_boolean KHMAPI +kcdb_identity_is_equal(khm_handle identity1, + khm_handle identity2) +{ + + return (identity1 == identity2); + +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_provider(khm_handle sub) +{ + EnterCriticalSection(&cs_ident); + if (sub != kcdb_ident_sub) { + if(kcdb_ident_sub != NULL) { + kmq_post_sub_msg(kcdb_ident_sub, + KMSG_IDENT, + KMSG_IDENT_EXIT, + 0, + 0); + kmq_delete_subscription(kcdb_ident_sub); + } + kcdb_ident_sub = sub; + + if (kcdb_ident_sub) + kmq_post_sub_msg(kcdb_ident_sub, + KMSG_IDENT, + KMSG_IDENT_INIT, + 0, + 0); + } + LeaveCriticalSection(&cs_ident); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_provider(khm_handle * sub) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) + rv = KHM_ERROR_SUCCESS; + else + rv = KHM_ERROR_NOT_FOUND; + if(sub != NULL) + *sub = kcdb_ident_sub; + LeaveCriticalSection(&cs_ident); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_type(khm_int32 cred_type) +{ + EnterCriticalSection(&cs_ident); + kcdb_ident_cred_type = cred_type; + LeaveCriticalSection(&cs_ident); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_type(khm_int32 * ptype) +{ + if (!ptype) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + *ptype = kcdb_ident_cred_type; + LeaveCriticalSection(&cs_ident); + + if (*ptype >= 0) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +/* message completion routine */ +void +kcdbint_ident_msg_completion(kmq_message * m) { + kcdb_identity_release(m->vparam); +} + +void +kcdbint_ident_add_ref(const void * key, void * vid) { + /* References in the hashtable are not refcounted */ + + // kcdb_identity_hold(vid); +} + +void +kcdbint_ident_del_ref(const void * key, void * vid) { + /* References in the hashtable are not refcounted */ + + // kcdb_identity_release(vid); +} + +void +kcdbint_ident_init(void) { + InitializeCriticalSection(&cs_ident); + kcdb_identities_namemap = hash_new_hashtable( + KCDB_IDENT_HASHTABLE_SIZE, + hash_string, + hash_string_comp, + kcdbint_ident_add_ref, + kcdbint_ident_del_ref); +} + +void +kcdbint_ident_exit(void) { + EnterCriticalSection(&cs_ident); + hash_del_hashtable(kcdb_identities_namemap); + LeaveCriticalSection(&cs_ident); + DeleteCriticalSection(&cs_ident); +} + +/* NOT called with cs_ident held */ +KHMEXP khm_boolean KHMAPI +kcdb_identity_is_valid_name(const wchar_t * name) +{ + khm_int32 rv; + + /* special case. Note since the string we are comparing with is + of a known length we don't need to check the length of name. */ + if (!wcscmp(name, L"_Schema")) + return FALSE; + + rv = kcdb_identpro_validate_name(name); + + if(rv == KHM_ERROR_NO_PROVIDER || + rv == KHM_ERROR_NOT_IMPLEMENTED) + return TRUE; + else + return KHM_SUCCEEDED(rv); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_create(const wchar_t *name, + khm_int32 flags, + khm_handle * result) { + kcdb_identity * id = NULL; + kcdb_identity * id_tmp = NULL; + size_t namesize; + + if(!result || !name) + return KHM_ERROR_INVALID_PARAM; + + *result = NULL; + + /* is it there already? */ + EnterCriticalSection(&cs_ident); + id = hash_lookup(kcdb_identities_namemap, (void *) name); + if(id) + kcdb_identity_hold((khm_handle) id); + LeaveCriticalSection(&cs_ident); + + if(id) { + *result = (khm_handle) id; + return KHM_ERROR_SUCCESS; + } else if(!(flags & KCDB_IDENT_FLAG_CREATE)) { + return KHM_ERROR_NOT_FOUND; + } + + flags &= ~KCDB_IDENT_FLAG_CREATE; + + /* nope. create it */ + if((flags & ~KCDB_IDENT_FLAGMASK_RDWR) || + (flags & (KCDB_IDENT_FLAG_DEFAULT | + KCDB_IDENT_FLAG_SEARCHABLE | + KCDB_IDENT_FLAG_STICKY))) { + /* can't specify this flag in create */ + return KHM_ERROR_INVALID_PARAM; + } + + if(!kcdb_identity_is_valid_name(name)) { + return KHM_ERROR_INVALID_NAME; + } + + /* we expect the following will succeed since the above + test passed */ + StringCbLength(name, KCDB_IDENT_MAXCB_NAME, &namesize); + namesize += sizeof(wchar_t); + + id = PMALLOC(sizeof(kcdb_identity)); + ZeroMemory(id, sizeof(kcdb_identity)); + id->magic = KCDB_IDENT_MAGIC; + id->name = PMALLOC(namesize); + StringCbCopy(id->name, namesize, name); + + id->flags = (flags & KCDB_IDENT_FLAGMASK_RDWR); + id->flags |= KCDB_IDENT_FLAG_ACTIVE; + LINIT(id); + + EnterCriticalSection(&cs_ident); + id_tmp = hash_lookup(kcdb_identities_namemap, (void *) id->name); + if(id_tmp) { + /* lost a race */ + kcdb_identity_hold((khm_handle) id_tmp); + *result = (khm_handle) id_tmp; + + PFREE(id->name); + PFREE(id); + + id = NULL; + } else { + khm_handle h_cfg; + + kcdb_identity_hold((khm_handle) id); + hash_add(kcdb_identities_namemap, + (void *) id->name, + (void *) id); + LPUSH(&kcdb_identities, id); + + if(KHM_SUCCEEDED(kcdb_identity_get_config((khm_handle) id, + 0, + &h_cfg))) { + /* don't need to set the KCDB_IDENT_FLAG_CONFIG flags + since kcdb_identity_get_config() sets it for us. */ + khm_int32 sticky; + + if (KHM_SUCCEEDED(khc_read_int32(h_cfg, L"Sticky", &sticky)) && + sticky) { + id->flags |= KCDB_IDENT_FLAG_STICKY; + } + + khc_close_space(h_cfg); + } + } + LeaveCriticalSection(&cs_ident); + + if(id != NULL) { + *result = (khm_handle) id; + + kcdb_identpro_notify_create((khm_handle) id); + + kcdbint_ident_post_message(KCDB_OP_INSERT, id); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_delete(khm_handle vid) { + kcdb_identity * id; + khm_int32 code = KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_ident); + if(!kcdb_is_identity(vid)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + id = (kcdb_identity *) vid; + + if (kcdb_is_active_identity(vid)) { + + id->flags &= ~KCDB_IDENT_FLAG_ACTIVE; + + hash_del(kcdb_identities_namemap, (void *) id->name); + + LeaveCriticalSection(&cs_ident); + + kcdbint_ident_post_message(KCDB_OP_DELETE, id); + + /* Once everybody finishes dealing with the identity deletion, + we will get called again. */ + return KHM_ERROR_SUCCESS; + } else if (id->refcount == 0) { + /* If the identity is not active, it is not in the hashtable + either */ + LDELETE(&kcdb_identities, id); + + if (id->name) + PFREE(id->name); + PFREE(id); + } + /* else, we have an identity that is not active, but has + outstanding references. We have to wait until those references + are freed. Once they are released, kcdb_identity_delete() will + be called again. */ + +#if 0 + EnterCriticalSection(&cs_ident); + if(id->refcount == 0) { + /*TODO: free up the identity */ + } +#endif + _exit: + LeaveCriticalSection(&cs_ident); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_flags(khm_handle vid, + khm_int32 flag, + khm_int32 mask) { + kcdb_identity * id; + khm_int32 oldflags; + khm_int32 newflags; + khm_int32 delta = 0; + khm_int32 rv; + + if (mask == 0) + return KHM_ERROR_SUCCESS; + + if(!kcdb_is_active_identity(vid)) + return KHM_ERROR_INVALID_PARAM; + + id = (kcdb_identity *) vid; + + flag &= mask; + + if((mask & ~KCDB_IDENT_FLAGMASK_RDWR) || + ((flag & KCDB_IDENT_FLAG_INVALID) && (flag & KCDB_IDENT_FLAG_VALID))) + return KHM_ERROR_INVALID_PARAM; + + if((mask & KCDB_IDENT_FLAG_DEFAULT) && + (flag & KCDB_IDENT_FLAG_DEFAULT)) { + /* kcdb_identity_set_default already does checking for + redundant transitions */ + rv = kcdb_identity_set_default(vid); + + if(KHM_FAILED(rv)) + return rv; + + mask &= ~KCDB_IDENT_FLAG_DEFAULT; + flag &= ~KCDB_IDENT_FLAG_DEFAULT; + } + + EnterCriticalSection(&cs_ident); + + if(mask & KCDB_IDENT_FLAG_SEARCHABLE) { + if(!(flag & KCDB_IDENT_FLAG_SEARCHABLE)) { + if(id->flags & KCDB_IDENT_FLAG_SEARCHABLE) { + LeaveCriticalSection(&cs_ident); + rv = kcdb_identpro_set_searchable(vid, FALSE); + EnterCriticalSection(&cs_ident); + if(rv == KHM_ERROR_NO_PROVIDER || + KHM_SUCCEEDED(rv)) { + id->flags &= ~KCDB_IDENT_FLAG_SEARCHABLE; + delta |= KCDB_IDENT_FLAG_SEARCHABLE; + } + } + } else { + if(!(id->flags & KCDB_IDENT_FLAG_SEARCHABLE)) { + LeaveCriticalSection(&cs_ident); + rv = kcdb_identpro_set_searchable(vid, TRUE); + EnterCriticalSection(&cs_ident); + if(rv == KHM_ERROR_NO_PROVIDER || + KHM_SUCCEEDED(rv)) { + id->flags |= KCDB_IDENT_FLAG_SEARCHABLE; + delta |= KCDB_IDENT_FLAG_SEARCHABLE; + } + } + } + + flag &= ~KCDB_IDENT_FLAG_SEARCHABLE; + mask &= ~KCDB_IDENT_FLAG_SEARCHABLE; + } + + if (mask & KCDB_IDENT_FLAG_STICKY) { + if ((flag ^ id->flags) & KCDB_IDENT_FLAG_STICKY) { + khm_handle h_conf; + + if (KHM_SUCCEEDED(kcdb_identity_get_config(vid, + KHM_FLAG_CREATE, + &h_conf))) { + khc_write_int32(h_conf, L"Sticky", + !!(flag & KCDB_IDENT_FLAG_STICKY)); + khc_close_space(h_conf); + } + + id->flags = + ((id->flags & ~KCDB_IDENT_FLAG_STICKY) | + (flag & KCDB_IDENT_FLAG_STICKY)); + + delta |= KCDB_IDENT_FLAG_STICKY; + } + + flag &= ~KCDB_IDENT_FLAG_STICKY; + mask &= ~KCDB_IDENT_FLAG_STICKY; + } + + /* deal with every other flag */ + + oldflags = id->flags; + + id->flags = (id->flags & ~mask) | (flag & mask); + + if (flag & KCDB_IDENT_FLAG_VALID) + id->flags &= ~KCDB_IDENT_FLAG_INVALID; + if (flag & KCDB_IDENT_FLAG_INVALID) + id->flags &= ~KCDB_IDENT_FLAG_VALID; + + newflags = id->flags; + + LeaveCriticalSection(&cs_ident); + + delta |= newflags ^ oldflags; + + if((delta & KCDB_IDENT_FLAG_HIDDEN)) { + kcdbint_ident_post_message( + (newflags & KCDB_IDENT_FLAG_HIDDEN)?KCDB_OP_HIDE:KCDB_OP_UNHIDE, + vid); + } + + if((delta & KCDB_IDENT_FLAG_SEARCHABLE)) { + kcdbint_ident_post_message( + (newflags & KCDB_IDENT_FLAG_SEARCHABLE)?KCDB_OP_SETSEARCH:KCDB_OP_UNSETSEARCH, + vid); + } + + if(delta != 0) + kcdbint_ident_post_message(KCDB_OP_MODIFY, vid); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_flags(khm_handle vid, + khm_int32 * flags) { + kcdb_identity * id; + + *flags = 0; + + if(!kcdb_is_active_identity(vid)) + return KHM_ERROR_INVALID_PARAM; + + id = (kcdb_identity *) vid; + + *flags = id->flags; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_name(khm_handle vid, + wchar_t * buffer, + khm_size * pcbsize) { + size_t namesize; + kcdb_identity * id; + + if(!kcdb_is_active_identity(vid) || !pcbsize) + return KHM_ERROR_INVALID_PARAM; + + id = (kcdb_identity *) vid; + + if(FAILED(StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &namesize))) + return KHM_ERROR_UNKNOWN; + + namesize += sizeof(wchar_t); + + if(!buffer || namesize > *pcbsize) { + *pcbsize = namesize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *pcbsize, id->name); + *pcbsize = namesize; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_default(khm_handle * pvid) { + khm_handle def; + + if (pvid == NULL) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + def = kcdb_def_identity; + if (def != NULL) + kcdb_identity_hold(def); + LeaveCriticalSection(&cs_ident); + + *pvid = def; + + if (def != NULL) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +static khm_int32 +kcdbint_ident_set_default(khm_handle vid, + khm_boolean invoke_identpro) { + kcdb_identity * new_def; + kcdb_identity * old_def; + khm_int32 rv; + + if (vid != NULL && !kcdb_is_active_identity(vid)) + return KHM_ERROR_INVALID_PARAM; + + new_def = (kcdb_identity *)vid; + + if (new_def != NULL && (new_def->flags & KCDB_IDENT_FLAG_DEFAULT)) + return KHM_ERROR_SUCCESS; + + if ((new_def == NULL && kcdb_def_identity == NULL) || + (new_def == kcdb_def_identity)) + return KHM_ERROR_SUCCESS; + + /* first check with the identity provider if this operation + is permitted. */ + if (invoke_identpro) { + rv = kcdb_identpro_set_default(vid); + if(rv != KHM_ERROR_NO_PROVIDER && KHM_FAILED(rv)) + return rv; + } + + EnterCriticalSection(&cs_ident); + + old_def = kcdb_def_identity; + kcdb_def_identity = new_def; + + if(old_def != new_def) { + if(old_def) { + old_def->flags &= ~KCDB_IDENT_FLAG_DEFAULT; + kcdb_identity_release((khm_handle) old_def); + } + + if(new_def) { + new_def->flags |= KCDB_IDENT_FLAG_DEFAULT; + kcdb_identity_hold((khm_handle) new_def); + } + + LeaveCriticalSection(&cs_ident); + + if (invoke_identpro) + kcdbint_ident_post_message(KCDB_OP_NEW_DEFAULT, new_def); + } else { + LeaveCriticalSection(&cs_ident); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_default(khm_handle vid) { + return kcdbint_ident_set_default(vid, TRUE); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_default_int(khm_handle vid) { + return kcdbint_ident_set_default(vid, FALSE); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_config(khm_handle vid, + khm_int32 flags, + khm_handle * result) { + khm_handle hkcdb; + khm_handle hidents = NULL; + khm_handle hident = NULL; + khm_int32 rv; + kcdb_identity * id; + + if(kcdb_is_active_identity(vid)) { + id = (kcdb_identity *) vid; + } else { + return KHM_ERROR_INVALID_PARAM; + } + + hkcdb = kcdb_get_config(); + if(hkcdb) { + rv = khc_open_space(hkcdb, L"Identity", 0, &hidents); + if(KHM_FAILED(rv)) + goto _exit; + + rv = khc_open_space(hidents, + id->name, + flags | KCONF_FLAG_NOPARSENAME, + &hident); + + if(KHM_FAILED(rv)) + goto _exit; + + EnterCriticalSection(&cs_ident); + id->flags |= KCDB_IDENT_FLAG_CONFIG; + LeaveCriticalSection(&cs_ident); + + *result = hident; + } else + rv = KHM_ERROR_UNKNOWN; + +_exit: + if(hidents) + khc_close_space(hidents); + if(hkcdb) + khc_close_space(hkcdb); + return rv; +} + +/*! \note cs_ident must be available. */ +void +kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id) { + kcdb_identity_hold(id); + kmq_post_message(KMSG_KCDB, KMSG_KCDB_IDENT, op, (void *) id); +} + +/*! \note cs_ident must be available. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_hold(khm_handle vid) { + kcdb_identity * id; + if(kcdb_is_active_identity(vid)) { + id = vid; + InterlockedIncrement(&(id->refcount)); + } else + return KHM_ERROR_INVALID_PARAM; + return ERROR_SUCCESS; +} + +/*! \note cs_ident must be available. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_release(khm_handle vid) { + kcdb_identity * id; + khm_int32 refcount; + if(kcdb_is_identity(vid)) { + id = vid; + refcount = InterlockedDecrement(&(id->refcount)); + if(refcount == 0) { + EnterCriticalSection(&cs_ident); + /* We only delete identities which do not have a + configuration. */ + if (id->refcount == 0 && + !(id->flags & KCDB_IDENT_FLAG_CONFIG)) + kcdb_identity_delete(vid); + LeaveCriticalSection(&cs_ident); + } + } else + return KHM_ERROR_INVALID_PARAM; + return ERROR_SUCCESS; +} + +struct kcdb_idref_result { + kcdb_identity * ident; + khm_int32 flags; + khm_size count; +}; + +static khm_int32 KHMAPI +kcdbint_idref_proc(khm_handle cred, void * r) { + khm_handle vid; + struct kcdb_idref_result *result; + khm_int32 flags; + + result = (struct kcdb_idref_result *) r; + + if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, &vid))) { + if (result->ident == (kcdb_identity *) vid) { + + result->count++; + kcdb_cred_get_flags(cred, &flags); + + if (flags & KCDB_CRED_FLAG_RENEWABLE) { + result->flags |= KCDB_IDENT_FLAG_CRED_RENEW; + if (flags & KCDB_CRED_FLAG_INITIAL) { + result->flags |= KCDB_IDENT_FLAG_RENEWABLE; + } + } + + if (flags & KCDB_CRED_FLAG_EXPIRED) { + result->flags |= KCDB_IDENT_FLAG_CRED_EXP; + if (flags & KCDB_CRED_FLAG_INITIAL) { + result->flags |= KCDB_IDENT_FLAG_EXPIRED; + } + } + + if (flags & KCDB_CRED_FLAG_INITIAL) { + result->flags |= KCDB_IDENT_FLAG_VALID; + } + } + + kcdb_identity_release(vid); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_refresh(khm_handle vid) { + kcdb_identity * ident; + khm_int32 code = KHM_ERROR_SUCCESS; + struct kcdb_idref_result result; + + EnterCriticalSection(&cs_ident); + + if (!kcdb_is_active_identity(vid)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + ident = (kcdb_identity *) vid; + + result.ident = ident; + result.flags = 0; + result.count = 0; + + LeaveCriticalSection(&cs_ident); + + kcdb_credset_apply(NULL, kcdbint_idref_proc, &result); + + if (result.count == 0) + result.flags |= KCDB_IDENT_FLAG_EMPTY; + + kcdb_identity_set_flags(vid, result.flags, + KCDB_IDENT_FLAGMASK_RDWR & + ~(KCDB_IDENT_FLAG_DEFAULT | + KCDB_IDENT_FLAG_SEARCHABLE | + KCDB_IDENT_FLAG_STICKY)); + + EnterCriticalSection(&cs_ident); + ident->refresh_cycle = kcdb_ident_refresh_cycle; + + _exit: + LeaveCriticalSection(&cs_ident); + + if (code == 0) + code = kcdb_identpro_update(vid); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_refresh_all(void) { + kcdb_identity * ident; + kcdb_identity * next; + khm_int32 code = KHM_ERROR_SUCCESS; + int hit_count; + + EnterCriticalSection(&cs_ident); + + kcdb_ident_refresh_cycle++; + + /* The do-while loop is here to account for race conditions. We + release cs_ident in the for loop, so we don't actually have a + guarantee that we traversed the whole identity list at the end. + We repeat until all the identities are uptodate. */ + + do { + hit_count = 0; + + for (ident = kcdb_identities; + ident != NULL; + ident = next) { + + next = LNEXT(ident); + + if (!kcdb_is_active_identity(ident) || + ident->refresh_cycle == kcdb_ident_refresh_cycle) + continue; + + kcdb_identity_hold((khm_handle) ident); + + LeaveCriticalSection(&cs_ident); + + kcdb_identity_refresh((khm_handle) ident); + + EnterCriticalSection(&cs_ident); + + kcdb_identity_release((khm_handle) ident); + + hit_count++; + } + + } while (hit_count > 0); + + LeaveCriticalSection(&cs_ident); + + return code; +} + +/*****************************************/ +/* Custom property functions */ + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_attr(khm_handle vid, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf) +{ + kcdb_identity * id = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + khm_size slot; + khm_size cbdest; + khm_int32 code = KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_ident); + if(!kcdb_is_active_identity(vid)) { + LeaveCriticalSection(&cs_ident); + return KHM_ERROR_INVALID_PARAM; + } + + id = (kcdb_identity *) vid; + + if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS)) { + kcdb_buf_new(&id->buf, KCDB_BUF_DEFAULT); + id->flags |= KCDB_IDENT_FLAG_ATTRIBS; + } + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + LeaveCriticalSection(&cs_ident); + return KHM_ERROR_INVALID_PARAM; + } + +#if 0 + /* actually, even if an attribute is computed, we still allow + those values to be set. This is because computing values + is only for credentials. If a computed value is used as a + property in any other object, it is treated as a regular value + */ + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) + { + LeaveCriticalSection(&cs_ident); + kcdb_attrib_release_info(attrib); + return KHM_ERROR_INVALID_OPERATION; + } +#endif + + if (buffer == NULL) { + /* we are removing a value */ + slot = kcdb_buf_slot_by_id(&id->buf, attr_id); + if (slot != KCDB_BUF_INVALID_SLOT && + kcdb_buf_exist(&id->buf, slot)) + kcdb_buf_alloc(&id->buf, slot, attr_id, 0); + code = KHM_ERROR_SUCCESS; + goto _exit; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + LeaveCriticalSection(&cs_ident); + kcdb_attrib_release_info(attrib); + return KHM_ERROR_INVALID_PARAM; + } + + if(!(type->isValid(buffer,cbbuf))) { + code = KHM_ERROR_TYPE_MISMATCH; + goto _exit; + } + + if((type->dup(buffer, cbbuf, NULL, &cbdest)) != KHM_ERROR_TOO_LONG) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + kcdb_buf_alloc(&id->buf, KCDB_BUF_APPEND, attr_id, cbdest); + slot = kcdb_buf_slot_by_id(&id->buf, attr_id); + if(slot == KCDB_BUF_INVALID_SLOT || !kcdb_buf_exist(&id->buf, slot)) { + code = KHM_ERROR_NO_RESOURCES; + goto _exit; + } + + if(KHM_FAILED(code = + type->dup(buffer, cbbuf, kcdb_buf_get(&id->buf, slot), &cbdest))) + { + kcdb_buf_alloc(&id->buf, slot, attr_id, 0); + goto _exit; + } + + kcdb_buf_set_value_flag(&id->buf, slot); + +_exit: + LeaveCriticalSection(&cs_ident); + + if(attrib) + kcdb_attrib_release_info(attrib); + if(type) + kcdb_type_release_info(type); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_attrib(khm_handle vid, + wchar_t * attr_name, + void * buffer, + khm_size cbbuf) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) + return KHM_ERROR_INVALID_PARAM; + + return kcdb_identity_set_attr( + vid, + attr_id, + buffer, + cbbuf); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attr(khm_handle vid, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_identity * id = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + khm_size slot; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + return KHM_ERROR_INVALID_PARAM; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + kcdb_attrib_release_info(attrib); + return KHM_ERROR_UNKNOWN; + } + + if(attr_type) + *attr_type = attrib->type; + + EnterCriticalSection(&cs_ident); + + if(!kcdb_is_active_identity(vid)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + id = (kcdb_identity *) vid; + + if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) || + (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT || + !kcdb_buf_val_exist(&id->buf, slot)) + { + code = KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(!buffer && !pcbbuf) { + /* in this case the caller is only trying to determine if the field + contains data. If we get here, then the value exists. */ + code = KHM_ERROR_SUCCESS; + goto _exit; + } + +#if 0 + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { + /* we should never hit this case */ +#ifdef DEBUG + assert(FALSE); +#else + code = KHM_ERROR_INVALID_OPERATION; +#endif + } else { +#endif + code = type->dup( + kcdb_buf_get(&id->buf, slot), + kcdb_buf_size(&id->buf, slot), + buffer, + pcbbuf); +#if 0 + } +#endif + +_exit: + LeaveCriticalSection(&cs_ident); + if(type) + kcdb_type_release_info(type); + if(attrib) + kcdb_attrib_release_info(attrib); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attrib(khm_handle vid, + wchar_t * attr_name, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) + return KHM_ERROR_NOT_FOUND; + + return kcdb_identity_get_attr(vid, + attr_id, + attr_type, + buffer, + pcbbuf); +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attr_string( + khm_handle vid, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + khm_int32 code = KHM_ERROR_SUCCESS; + kcdb_identity * id = NULL; + kcdb_attrib * attrib = NULL; + kcdb_type * type = NULL; + khm_size slot; + + if(KHM_FAILED(kcdb_attrib_get_info(attr_id, &attrib))) { + return KHM_ERROR_INVALID_PARAM; + } + + if(KHM_FAILED(kcdb_type_get_info(attrib->type, &type))) { + kcdb_attrib_release_info(attrib); + return KHM_ERROR_UNKNOWN; + } + + EnterCriticalSection(&cs_ident); + + if(!kcdb_is_active_identity(vid)) { + code = KHM_ERROR_INVALID_PARAM; + goto _exit; + } + + id = (kcdb_identity *) vid; + + if(!(id->flags & KCDB_IDENT_FLAG_ATTRIBS) || + (slot = kcdb_buf_slot_by_id(&id->buf, attr_id)) == KCDB_BUF_INVALID_SLOT || + !kcdb_buf_val_exist(&id->buf, slot)) + { + code = KHM_ERROR_NOT_FOUND; + goto _exit; + } + + if(!buffer && !pcbbuf) { + /* in this case the caller is only trying to determine if the field + contains data. If we get here, then the value exists */ + code = KHM_ERROR_SUCCESS; + goto _exit; + } + +#if 0 + if(attrib->flags & KCDB_ATTR_FLAG_COMPUTED) { +#ifdef DEBUG + assert(FALSE); +#else + code = KHM_ERROR_INVALID_OPERATION; +#endif + } else { +#endif + if(kcdb_buf_exist(&id->buf, slot)) { + code = type->toString( + kcdb_buf_get(&id->buf, slot), + kcdb_buf_size(&id->buf, slot), + buffer, + pcbbuf, + flags); + } else + code = KHM_ERROR_NOT_FOUND; +#if 0 + } +#endif + +_exit: + LeaveCriticalSection(&cs_ident); + if(type) + kcdb_type_release_info(type); + if(attrib) + kcdb_attrib_release_info(attrib); + + return code; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attrib_string( + khm_handle vid, + wchar_t * attr_name, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags) +{ + khm_int32 attr_id = -1; + + if(KHM_FAILED(kcdb_attrib_get_id(attr_name, &attr_id))) + return KHM_ERROR_NOT_FOUND; + + return kcdb_identity_get_attr_string( + vid, + attr_id, + buffer, + pcbbuf, + flags); +} + +/*****************************************/ +/* Identity provider interface functions */ + +/* NOT called with cs_ident held */ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_validate_name(const wchar_t * name) +{ + kcdb_ident_name_xfer namex; + khm_handle sub; + khm_size cch; + khm_int32 rv = KHM_ERROR_SUCCESS; + + /* we need to verify the length and the contents of the string + before calling the identity provider */ + if(FAILED(StringCchLength(name, KCDB_IDENT_MAXCCH_NAME, &cch))) + return KHM_ERROR_TOO_LONG; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + ZeroMemory(&namex, sizeof(namex)); + + namex.name_src = name; + namex.result = KHM_ERROR_NOT_IMPLEMENTED; + + kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_VALIDATE_NAME, + 0, + (void *) &namex); + + rv = namex.result; + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_validate_identity(khm_handle identity) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle sub; + + if(!kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_VALIDATE_IDENTITY, + 0, + (void *) identity); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_canon_name( + const wchar_t * name_in, + wchar_t * name_out, + khm_size * cb_name_out) +{ + khm_handle sub; + kcdb_ident_name_xfer namex; + wchar_t name_tmp[KCDB_IDENT_MAXCCH_NAME]; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size cch; + + if(cb_name_out == 0 || + FAILED(StringCchLength(name_in, KCDB_IDENT_MAXCCH_NAME, &cch))) + return KHM_ERROR_INVALID_NAME; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + ZeroMemory(&namex, sizeof(namex)); + ZeroMemory(name_tmp, sizeof(name_tmp)); + + namex.name_src = name_in; + namex.name_dest = name_tmp; + namex.cb_name_dest = sizeof(name_tmp); + namex.result = KHM_ERROR_NOT_IMPLEMENTED; + + rv = kmq_send_sub_msg( + sub, + KMSG_IDENT, + KMSG_IDENT_CANON_NAME, + 0, + (void *) &namex); + + if(KHM_SUCCEEDED(namex.result)) { + const wchar_t * name_result; + khm_size cb; + + if(name_in[0] != 0 && name_tmp[0] == 0) + name_result = name_tmp; + else + name_result = name_in; + + if(FAILED(StringCbLength(name_result, KCDB_IDENT_MAXCB_NAME, &cb))) + rv = KHM_ERROR_UNKNOWN; + else { + cb += sizeof(wchar_t); + if(name_out == 0 || *cb_name_out < cb) { + rv = KHM_ERROR_TOO_LONG; + *cb_name_out = cb; + } else { + StringCbCopy(name_out, *cb_name_out, name_result); + *cb_name_out = cb; + rv = KHM_ERROR_SUCCESS; + } + } + } + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_compare_name( + const wchar_t * name1, + const wchar_t * name2) +{ + khm_handle sub; + kcdb_ident_name_xfer namex; + khm_int32 rv = 0; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + /* Generally in kcdb_identpro_* functions we don't emulate + any behavior if the provider is not available, but lacking + a way to make this known, we emulate here */ + rv = wcscmp(name1, name2); + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + ZeroMemory(&namex, sizeof(namex)); + namex.name_src = name1; + namex.name_alt = name2; + + kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_COMPARE_NAME, + 0, + (void *) &namex); + + rv = namex.result; + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_set_default(khm_handle identity) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if((identity != NULL) && + !kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg( + sub, + KMSG_IDENT, + KMSG_IDENT_SET_DEFAULT, + (identity != NULL), + (void *) identity); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_set_searchable( + khm_handle identity, + khm_boolean searchable) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg( + sub, + KMSG_IDENT, + KMSG_IDENT_SET_SEARCHABLE, + searchable, + (void *) identity); + } + + return rv; +} + + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_update(khm_handle identity) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg(sub, + KMSG_IDENT, + KMSG_IDENT_UPDATE, + 0, + (void *) identity); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kcdb_identpro_notify_create(khm_handle identity) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!kcdb_is_active_identity(identity)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg( + sub, + KMSG_IDENT, + KMSG_IDENT_NOTIFY_CREATE, + 0, + (void *) identity); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_identpro_get_ui_cb(void * rock) +{ + khm_handle sub; + khm_int32 rv = KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_ident); + if(kcdb_ident_sub != NULL) { + sub = kcdb_ident_sub; + } else { + sub = NULL; + rv = KHM_ERROR_NO_PROVIDER; + } + LeaveCriticalSection(&cs_ident); + + if(sub != NULL) { + rv = kmq_send_sub_msg( + sub, + KMSG_IDENT, + KMSG_IDENT_GET_UI_CALLBACK, + 0, + rock); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI kcdb_identity_enum( + khm_int32 and_flags, + khm_int32 eq_flags, + wchar_t * name_buf, + khm_size * pcb_buf, + khm_size * pn_idents) +{ + kcdb_identity * id; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size cb_req = 0; + khm_size n_idents = 0; + size_t cb_curr; + size_t cch_curr; + size_t cch_left; + HRESULT hr; + + if ((name_buf == NULL && pcb_buf == NULL && pn_idents == NULL) || + (name_buf != NULL && pcb_buf == NULL)) + return KHM_ERROR_INVALID_PARAM; + + eq_flags &= and_flags; + + EnterCriticalSection(&cs_ident); + + if (!kcdb_checked_config) { + khm_handle h_kcdb = NULL; + khm_handle h_idents = NULL; + khm_handle h_ident = NULL; + + kcdb_checked_config = TRUE; + kcdb_checking_config = TRUE; + + h_kcdb = kcdb_get_config(); + if (!h_kcdb) + goto _config_check_cleanup; + if(KHM_FAILED(khc_open_space(h_kcdb, L"Identity", 0, &h_idents))) + goto _config_check_cleanup; + + while(KHM_SUCCEEDED(khc_enum_subspaces(h_idents, + h_ident, + &h_ident))) { + + wchar_t wname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_handle t_id; + + cb = sizeof(wname); + if (KHM_FAILED(khc_get_config_space_name(h_ident, + wname, + &cb))) + continue; + + LeaveCriticalSection(&cs_ident); + + if (KHM_SUCCEEDED(kcdb_identity_create(wname, + KCDB_IDENT_FLAG_CREATE, + &t_id))) + kcdb_identity_release(t_id); + + EnterCriticalSection(&cs_ident); + } + + _config_check_cleanup: + if (h_kcdb) + khc_close_space(h_kcdb); + if (h_idents) + khc_close_space(h_idents); + + kcdb_checking_config = FALSE; + } + + for ( id = kcdb_identities; + id != NULL; + id = LNEXT(id) ) { + if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) == + KCDB_IDENT_FLAG_ACTIVE) && + ((id->flags & and_flags) == eq_flags)) { + n_idents ++; + hr = StringCbLength(id->name, KCDB_IDENT_MAXCB_NAME, &cb_curr); +#ifdef DEBUG + assert(SUCCEEDED(hr)); +#endif + cb_req += cb_curr + sizeof(wchar_t); + } + } + + cb_req += sizeof(wchar_t); + + if (pn_idents != NULL) + *pn_idents = n_idents; + + if (pcb_buf != NULL && (name_buf == NULL || *pcb_buf < cb_req)) { + *pcb_buf = cb_req; + + rv = KHM_ERROR_TOO_LONG; + } else if(name_buf != NULL) { + cch_left = (*pcb_buf) / sizeof(wchar_t); + + for (id = kcdb_identities; + id != NULL; + id = LNEXT(id)) { + if (((id->flags & KCDB_IDENT_FLAG_ACTIVE) == + KCDB_IDENT_FLAG_ACTIVE) && + ((id->flags & and_flags) == eq_flags)) { + StringCchLength(id->name, KCDB_IDENT_MAXCCH_NAME, + &cch_curr); + cch_curr++; + StringCchCopy(name_buf, cch_left, id->name); + cch_left -= cch_curr; + name_buf += cch_curr; + } + } + + *name_buf = L'\0'; + *pcb_buf = cb_req; + } + + LeaveCriticalSection(&cs_ident); + + return rv; +} diff --git a/mechglue/src/windows/identity/kcreddb/identity.h b/mechglue/src/windows/identity/kcreddb/identity.h new file mode 100644 index 000000000..be0205d96 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/identity.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCDB_IDENTITY_H +#define __KHIMAIRA_KCDB_IDENTITY_H + +/* Identity */ + +#define KCDB_IDENT_HASHTABLE_SIZE 31 + +typedef struct kcdb_identity_t { + khm_int32 magic; + wchar_t * name; + khm_int32 flags; + khm_int32 refcount; + kcdb_buf buf; + khm_ui_4 refresh_cycle; + LDCL(struct kcdb_identity_t); +} kcdb_identity; + +#define KCDB_IDENT_MAGIC 0x31938d4f + +extern hashtable * kcdb_identities_namemap; +extern khm_int32 kcdb_n_identities; +extern kcdb_identity * kcdb_identities; /* all identities */ +extern kcdb_identity * kcdb_def_identity; /* default identity */ +extern khm_ui_4 kcdb_ident_refresh_cycle; + +void kcdbint_ident_init(void); +void kcdbint_ident_exit(void); +void kcdbint_ident_msg_completion(kmq_message * m); +void kcdbint_ident_post_message(khm_int32 op, kcdb_identity * id); + +#define kcdb_is_identity(id) ((id) && ((kcdb_identity *)(id))->magic == KCDB_IDENT_MAGIC) +#define kcdb_is_active_identity(id) (kcdb_is_identity(id) && (((kcdb_identity *)(id))->flags & KCDB_IDENT_FLAG_ACTIVE)) + +#endif diff --git a/mechglue/src/windows/identity/kcreddb/init.c b/mechglue/src/windows/identity/kcreddb/init.c new file mode 100644 index 000000000..13ef4da55 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/init.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +/* set to TRUE when the configuration is loaded */ +static int kcdb_config_loaded = 0; + +/* global state cs */ +static CRITICAL_SECTION cs_kcdb_global; + +/* forward dcl */ +void KHMAPI kcdb_msg_completion(kmq_message * m); + +void kcdb_init(void) { + /* setup the critical sections */ + InitializeCriticalSection(&cs_kcdb_global); + + kmq_set_completion_handler(KMSG_KCDB, kcdb_msg_completion); + + kcdb_credtype_init(); + kcdbint_ident_init(); + kcdb_credset_init(); + kcdb_cred_init(); + kcdb_type_init(); + kcdb_attrib_init(); +} + +void kcdb_exit(void) { + + kcdb_attrib_exit(); + kcdb_type_exit(); + kcdb_cred_exit(); + kcdb_credset_exit(); + kcdbint_ident_exit(); + kcdb_credtype_exit(); + + kmq_set_completion_handler(KMSG_KCDB, NULL); + + DeleteCriticalSection(&cs_kcdb_global); +} + +khm_handle kcdb_get_config(void) { + khm_handle space = NULL; + + EnterCriticalSection(&cs_kcdb_global); + if(!kcdb_config_loaded) { + khc_load_schema(NULL, schema_kcdbconfig); + kcdb_config_loaded = 1; + } + khc_open_space(NULL, L"KCDB", 0, &space); + LeaveCriticalSection(&cs_kcdb_global); + + return space; +} + +void KHMAPI kcdb_msg_completion(kmq_message * m) { + if(!m) + return; + if(m->subtype == KMSG_KCDB_IDENT) + kcdbint_ident_msg_completion(m); + else if(m->subtype == KMSG_KCDB_ATTRIB) + kcdb_attrib_msg_completion(m); + else if(m->subtype == KMSG_KCDB_TYPE) + kcdb_type_msg_completion(m); + else if(m->subtype == KMSG_KCDB_CREDTYPE) + kcdb_credtype_msg_completion(m); +} diff --git a/mechglue/src/windows/identity/kcreddb/kcdbconfig.csv b/mechglue/src/windows/identity/kcreddb/kcdbconfig.csv new file mode 100644 index 000000000..bd1fc6f33 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/kcdbconfig.csv @@ -0,0 +1,15 @@ +Name,Type,Value,Description +KCDB,KC_SPACE,0,Khimaira Configuration DB + Identity,KC_SPACE,0,Configuration space for identities + _Schema,KC_SPACE,0,Schema for identities + Sticky,KC_INT32,0,Boolean. Is this a sticky identity? + Monitor,KC_INT32,1,Boolean. Enables monitoring the identity + WarnThreshold,KC_INT32,900,In seconds + AllowWarn,KC_INT32,1,Boolean. Allow warning. + CriticalThreshold,KC_INT32,60,In seconds + AllowCritical,KC_INT32,1,Boolean. Allow critical. + AutoRenewThreshold,KC_INT32,60,In seconds + AllowAutoRenew,KC_INT32,1,Boolean. + _Schema,KC_ENDSPACE,0, + Identity,KC_ENDSPACE,0, +KCDB,KC_ENDSPACE,0, diff --git a/mechglue/src/windows/identity/kcreddb/kcreddb.h b/mechglue/src/windows/identity/kcreddb/kcreddb.h new file mode 100644 index 000000000..52ca980ef --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/kcreddb.h @@ -0,0 +1,3245 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCREDDB_H__ +#define __KHIMAIRA_KCREDDB_H__ + +#include +#include + + +/*! \defgroup kcdb NetIDMgr Credentials Database */ +/*@{*/ + +/*! \brief Maximum length in characters of short description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCCH_SHORT_DESC 256 + +/*! \brief Maximum length in bytes of short description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCB_SHORT_DESC (sizeof(wchar_t) * KCDB_MAXCCH_SHORT_DESC) + +/*! \brief Maximum length in characters of long description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCCH_LONG_DESC 8192 + +/*! \brief Maximum length in characters of long description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCB_LONG_DESC (sizeof(wchar_t) * KCDB_MAXCCH_LONG_DESC) + +/*! \brief Maximum length in characters of name + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCCH_NAME 256 + +/*! \brief Maximum length in bytes of short description + + The length includes the terminating \a NULL character. + */ +#define KCDB_MAXCB_NAME (sizeof(wchar_t) * KCDB_MAXCCH_NAME) + +/*! \brief Automatically determine the number of bytes required + + Can be used in most places where a count of bytes is required. + For many objects, the number of bytes that are required can be + determined through context and may be ommited. In such cases you + can use the \a KCDB_CBSIZE_AUTO value to specify that the function + is to determine the size automatically. + + \note Not all functions that take a count of bytes support the \a + KCDB_CBSIZE_AUTO value. +*/ +#define KCDB_CBSIZE_AUTO (-1) + +/*! +\defgroup kcdb_ident Identities + +Functions, macros etc. for manipulating identities. +*/ + +/*@{*/ + +/*! \brief The maximum number of characters (including terminator) that can + be specified as an identity name */ +#define KCDB_IDENT_MAXCCH_NAME 256 + +/*! \brief The maximum number of bytes that can be specified as an identity + name */ +#define KCDB_IDENT_MAXCB_NAME (sizeof(wchar_t) * KCDB_IDENT_MAXCCH_NAME) + +/*! +\name Flags for identities */ +/*@{*/ + +/*! \brief Create the identity if it doesn't already exist. + \note Only to be used with kcdb_identity_create() */ +#define KCDB_IDENT_FLAG_CREATE 0x10000000L + +/*! \brief Has configuration information + + Indicates that the identity has persistent configuration + information associated with it. + */ +#define KCDB_IDENT_FLAG_CONFIG 0x00800000L + +/*! \brief Marks the identity as active. + + An active identity is one that is in active use within NetIDMgr. + + \note This flag is readonly and cannot be specified when creating + or modifying an identity. Once an identity is deleted, it will + no longer have this flag. */ +#define KCDB_IDENT_FLAG_ACTIVE 0x02000000L + + +/*! \brief The identity has custom attributes assigned + */ +#define KCDB_IDENT_FLAG_ATTRIBS 0x08000000L + +/*! \brief This is the default identity. + + At most one identity will have this flag set at any given time. + To set or reset the flag, use kcdb_identity_set_default() */ +#define KCDB_IDENT_FLAG_DEFAULT 0x00000001L + +/*! \brief This identity can be searched. + + The meaning of this flag is left to be interpreted by individual + plugins. */ +#define KCDB_IDENT_FLAG_SEARCHABLE 0x00000002L + +/*! \brief Hidden identity. + + The identity will not show up in the identity list window. Once + the hidden is switched off, the identity (and all associated + credentials) will re-appear in the window */ +#define KCDB_IDENT_FLAG_HIDDEN 0x00000004L + +/*! \brief Invalid identity + + For one reason or another, this identity is invalid. This flag + can be set by an identity provider to indicate that this identity + does not correspond to an actual identity because an external + entity (such as a KDC) has denied it's existence. + + The absence of this flag does not imply that the identity is + valid. The ::KCDB_IDENT_FLAG_VALID bit must be set for that to be + the case. If neither flag is set, then the status of the identity + is not known. +*/ +#define KCDB_IDENT_FLAG_INVALID 0x00000008L + +/*! \brief Valid identity + + The identity has been validated through an external entity, or + it's validity implied through the existence of credentials for the + identity. + + The absence of this flag does not imply that the identity is + invalid. The ::KCDB_IDENT_FLAG_INVALID bit must be set for that + to be the case. If neither flag is set, then the status of the + identity is not known. + */ +#define KCDB_IDENT_FLAG_VALID 0x00000010L + +/*! \brief Expired identity + + This identity has expired and can not be actively used to obtain + credentials. This determination is made based on the input of + some external entity. This flag may only be set by an identity + provider. +*/ +#define KCDB_IDENT_FLAG_EXPIRED 0x00000020L + +/*! \brief Empty identity + + The identity does not have actual credentials associated with it. + */ +#define KCDB_IDENT_FLAG_EMPTY 0x00000040L + +/*! \brief Renewable identity + + The initial credentials associated with this identity are + renewable. Thus making the whole identity renewable. + */ +#define KCDB_IDENT_FLAG_RENEWABLE 0x00000080L + +/*! \brief Required user interaction + + The identity is in a state which requires user interaction to + activate. Currently, the identity may not be in a state where it + can be used to obtain credentials. + + A typical example of this is when the primary password for an + identity has expired. + */ +#define KCDB_IDENT_FLAG_INTERACT 0x00000100L + +/*! \brief Has expired credentials + + The identity has expired credentials associated with it. + */ +#define KCDB_IDENT_FLAG_CRED_EXP 0x00000200L + +/*! \brief Has renewable credentials + + The identity has renewable credentials associated with it. If the + initial credentials of the identity are renewable, then identity + is renewable. Hence the ::KCDB_IDENT_FLAG_RENEWABLE should also + be set. + */ +#define KCDB_IDENT_FLAG_CRED_RENEW 0x00000400L + +/*! \brief Sticky identity + + Sticky identities are identities that are always visible in the + credentials display even if no credentials are associated with it. + */ +#define KCDB_IDENT_FLAG_STICKY 0x00000800L + +/*! \brief Read/write flags mask. + + A bitmask that correspond to all the read/write flags in the mask. +*/ +#define KCDB_IDENT_FLAGMASK_RDWR 0x00000fffL + +/*@}*/ + +/*! \name Identity Provider Data Structures +@{*/ + +/*! \brief Name transfer structure + + Used when the KCDB is communicating with the identity provider to + exchange string names of identities. See individual ::KMSG_IDENT + message subtypes for the usage of this structure. + */ +typedef struct tag_kcdb_ident_name_xfer { + const wchar_t * name_src; /*!< An identity name. Does not + exceed KCDB_IDENT_MAXCCH_NAME + characters including terminating + NULL. */ + const wchar_t * name_alt; /*!< An identity name. Does not + exceed KCDB_IDENT_MAXCCH_NAME + characters including terminating + NULL. */ + wchar_t * name_dest; /*!< Pointer to a buffer that is to + receive a response string. The + size of the buffer in bytes is + specified in \a cb_name_dest. */ + khm_size cb_name_dest; /*!< Size of buffer pointed to by \a + name_dest in bytes. */ + khm_int32 result; /*!< Receives a result value, which is + usually an error code defined in + kherror.h, though it is not + always. */ +} kcdb_ident_name_xfer; + +typedef struct tag_kcdb_ident_info { + khm_handle identity; + khm_int32 fields; + + FILETIME expiration; +} kcdb_ident_info; + +/*@}*/ + +/*! \name Identity provider interface functions + + These functions encapsulate safe calls to the current identity + provider. While these functions are exported, applications should + not call these functions directly. They are provided for use by + the NetIDMgr core application. +@{*/ + +/*! \brief Validate an identity name + + The name that is provided will be passed through sets of + validations. One set, which doesn't depend on the identity + provider checks whether the length of the identity name and + whether there are any invalid characters in the identity name. If + the name passes those tests, then the name is passed down to the + identity provider's name validation handler. + + \retval KHM_ERROR_SUCCESS The name is valid + \retval KHM_ERROR_TOO_LONG Too many characters in name + \retval KHM_ERROR_INVALID_NAME There were invalid characters in the name. + \retval KHM_ERROR_NO_PROVIDER There is no identity provider; + however the name passed the length and character tests. + \retval KHM_ERROR_NOT_IMPLEMENTED The identity provider doesn't + implement a name validation handler; however the name passed + the length and character tests. + + \see ::KMSG_IDENT_VALIDATE_NAME + */ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_validate_name(const wchar_t * name); + +/*! \brief Validate an identity + + The identity itself needs to be validated. This may involve + communicating with an external entity. + + \see ::KMSG_IDENT_VALIDATE_IDENTITY + */ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_validate_identity(khm_handle identity); + +/*! \brief Canonicalize the name + + + \see ::KMSG_IDENT_CANON_NAME +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_canon_name(const wchar_t * name_in, + wchar_t * name_out, + khm_size * cb_name_out); + +/*! \brief Compare two identity names + + \see ::KMSG_IDENT_COMPARE_NAME +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_compare_name(const wchar_t * name1, + const wchar_t * name2); + +/*! \brief Set the specified identity as the default + + \see ::KMSG_IDENT_SET_DEFAULT +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_set_default(khm_handle identity); + +/*! \brief Set the specified identity as searchable + + \see ::KMSG_IDENT_SET_SEARCHABLE +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_set_searchable(khm_handle identity, + khm_boolean searchable); + +/*! \brief Update the specified identity + + \see ::KMSG_IDENT_UPDATE +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_update(khm_handle identity); + +/*! \brief Obtain the UI callback + + \a rock is actually a pointer to a ::khui_ident_new_creds_cb which + is to receive the callback. + + \see ::KMSG_IDENT_GET_UI_CALLBACK + */ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_get_ui_cb(void * rock); + +/*! \brief Notify an identity provider of the creation of a new identity + + \see ::KMSG_IDENT_NOTIFY_CREATE +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identpro_notify_create(khm_handle identity); + +/*@}*/ + +/*! \brief Check if the given name is a valid identity name + + \return TRUE or FALSE to the question, is this valid? +*/ +KHMEXP khm_boolean KHMAPI +kcdb_identity_is_valid_name(const wchar_t * name); + +/*! \brief Create or open an identity. + + If the KCDB_IDENT_FLAG_CREATE flag is specified in the flags + parameter a new identity will be created if one does not already + exist with the given name. If an identity by that name already + exists, then the existing identity will be opened. The result + parameter will receive a held reference to the opened identity. + Use kcdb_identity_release() to release the handle. + + \param[in] name Name of identity to create + \param[in] flags If KCDB_IDENT_FLAG_CREATE is specified, then the + identity will be created if it doesn't already exist. + Additional flags can be set here which will be assigned to the + identity if it is created. Additional flags have no effect if + an existing identity is opened. + \param[out] result If the call is successful, this receives a held + reference to the identity. The caller should call + kcdb_identity_release() to release the identity once it is no + longer needed. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_create(const wchar_t *name, + khm_int32 flags, + khm_handle * result); + +/*! \brief Mark an identity for deletion. + + The identity will be marked for deletion. The + KCDB_IDENT_FLAG_ACTIVE will no longer be present for this + identity. Once all references to the identity are released, it + will be removed from memory. All associated credentials will also + be removed. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_delete(khm_handle id); + +/*! \brief Set or unset the specified flags in the specified identity. + + Only flags that are in KCDB_IDENT_FLAGMASK_RDWR can be specifed in + the \a flags parameter or the \a mask parameter. The flags set in + the \a mask parameter of the identity will be set to the + corresponding values in the \a flags parameter. + + If ::KCDB_IDENT_FLAG_INVALID is set using this function, then the + ::KCDB_IDENT_FLAG_VALID will be automatically reset, and vice + versa. Resetting either bit does not undo this change, and will + leave the identity's validity unspecified. + + Note that setting or resetting certain flags have other semantic + side-effects: + + - ::KCDB_IDENT_FLAG_DEFAULT : Setting this is equivalent to + calling kcdb_identity_set_default() with \a id. Resetting this + is equivalent to calling kcdb_identity_set_default() with NULL. + + - ::KCDB_IDENT_FLAG_SEARCHABLE : Setting this will result in the + identity provider getting notified of the change. If the + identity provider indicates that searchable flag should not be + set or reset on the identity, then kcdb_identity_set_flags() + will return an error. + + \note kcdb_identity_set_flags() is not atomic. Even if the + function returns a failure code, some flags in the identity may + have been set. When calling kcdb_identity_set_flags() always + check the flags in the identity using kcdb_identity_get_flags() to + check which flags have been set and which have failed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_flags(khm_handle id, + khm_int32 flags, + khm_int32 mask); + +/*! \brief Return all the flags for the identity + + The returned flags may include internal flags. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_flags(khm_handle id, + khm_int32 * flags); + +/*! \brief Return the name of the identity + + \param[out] buffer Buffer to copy the identity name into. The + maximum size of an identity name is \a KCDB_IDENT_MAXCB_NAME. + If \a buffer is \a NULL, then the required size of the buffer + is returned in \a pcbsize. + + \param[in,out] pcbsize Size of buffer in bytes. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_name(khm_handle id, + wchar_t * buffer, + khm_size * pcbsize); + +/*! \brief Set the specified identity as the default. + + Specifying NULL effectively makes none of the identities the + default. + + \see kcdb_identity_set_flags() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_default(khm_handle id); + +/*! \brief Mark the specified identity as the default. + + This API is reserved for use by identity providers as a means of + specifying which identity is default. The difference between + kcdb_identity_set_default() and kcdb_identity_set_default_int() is + in semantics. + + - kcdb_identity_set_default() is used to request the KCDB to + designate the specified identity as the default. When + processing the request, the KCDB invokes the identity provider + to do the necessary work to make the identity the default. + + - kcdb_identity_set_default_int() is used by the identity provider + to notify the KCDB that the specified identity is the default. + This does not result in the invocation of any other semantics to + make the identity the default other than releasing the previous + defualt identity and making the specified one the default. As + an additional side effect, the notification <::KMSG_KCDB, + ::KMSG_KCDB_IDENT, ::KCDB_OP_NEW_DEFAULT> will also not be sent. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_default_int(khm_handle id); + +/*! \brief Get the default identity + + Obtain a held handle to the default identity if there is one. The + handle must be freed using kcdb_identity_release(). + + If there is no default identity, then the handle pointed to by \a + pvid is set to \a NULL and the function returns + KHM_ERROR_NOT_FOUND. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_default(khm_handle * pvid); + +/*! \brief Get the configuration space for the identity. + + \param[in] id Identity for which the configuraiton space is requested + + \param[in] flags Flags used when calling khc_open_space(). If \a + flags specifies KHM_FLAG_CREATE, then the configuration space + is created. + + \param[out] result The resulting handle. If the call is + successful, this receives a handle to the configuration space. + Use khc_close_space() to close the handle. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_config(khm_handle id, + khm_int32 flags, + khm_handle * result); + +/*! \brief Hold a reference to an identity. + + A reference to an identity (a handle) is only valid while it is + held. \note Once the handle is released, it can not be + revalidated by calling kcdb_identity_hold(). Doing so would lead + to unpredictable consequences. */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_hold(khm_handle id); + +/*! \brief Release a reference to an identity. + \see kcdb_identity_hold() */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_release(khm_handle id); + +/*! \brief Set the identity provider subscription + + If there was a previous subscription, that subscription will be + automatically deleted. + + \param[in] sub New identity provider subscription +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_provider(khm_handle sub); + +/*! \brief Set the primary credentials type + + The primary credentials type is designated by the identity + provider. As such, this function should only be called by an + identity provider. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_type(khm_int32 cred_type); + +/*! \brief Retrieve the identity provider subscription + + \param[out] sub Receives the current identity provider + subscription. Set to NULL if only the existence of an + identity provider needs to be checked. + + \retval KHM_ERROR_SUCCESS An identity provider exists. If \a sub + was not NULL, the subscription has been copied there. + + \retval KHM_ERROR_NOT_FOUND There is currently no registered + identity provider. If \a sub was not NULL, the handle it + points to has been set to NULL. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_provider(khm_handle * sub); + +/*! \brief Retrieve the identity provider credentials type + + This is the credentials type that the identity provider has + designated as the primary credentials type. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_type(khm_int32 * ptype); + +/*! \brief Returns TRUE if the two identities are equal + + Also returns TRUE if both identities are NULL. + */ +KHMEXP khm_boolean KHMAPI +kcdb_identity_is_equal(khm_handle identity1, + khm_handle identity2); + +/*! \brief Set an attribute in an identity by attribute id + + \param[in] buffer A pointer to a buffer containing the data to + assign to the attribute. Setting \a buffer to NULL has the + effect of removing any data that is already assigned to the + attribute. If \a buffer is non-NULL, then \a cbbuf should + specify the number of bytes in \a buffer. + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_attr(khm_handle identity, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf); + +/*! \brief Set an attribute in an identity by name + + The attribute name has to be a KCDB registered attribute or + property. + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_set_attrib(khm_handle identity, + wchar_t * attr_name, + void * buffer, + khm_size cbbuf); + +/*! \brief Get an attribute from an identity by attribute id. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \param[out] attr_type Receives the data type of the attribute. + Set this to NULL if the type is not required. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this identity then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attr(khm_handle identity, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf); + +/*! \brief Get an attribute from an identity by name. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this identity then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attrib(khm_handle identity, + wchar_t * attr_name, + khm_int32 * attr_type, + void * buffer, + khm_size * pcbbuf); + +/*! \brief Get the string representation of an identity attribute. + + A shortcut function which generates the string representation of + an identity attribute directly. + + \param[in] identity A handle to an identity + + \param[in] attr_id The attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \retval KHM_ERROR_SUCCESS Success + \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid + or was not defined for this identity + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the + supplied buffer was insufficient +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attr_string(khm_handle identity, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Get the string representation of an identity attribute by name. + + A shortcut function which generates the string representation of + an identity attribute directly. + + \param[in] identity A handle to an identity + + \param[in] attrib The name of the attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \see kcdb_identity_get_attr_string() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_identity_get_attrib_string(khm_handle identity, + wchar_t * attr_name, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Enumerate identities + + Enumerates all the active identities that match the criteria + specified using \a and_flags and \a eq_flags. The condition is + applied to all active identities as follows: + + \code + (identity->flags & and_flags) == (eq_flags & and_flags) + \endcode + + Essentially, if a flag is set in \a and_flags, then that flag in + the identity should equal the setting in \a eq_flags. + + \param[in] and_flags See above + + \param[in] eq_flags See above + + \param[out] name_buf Buffer to receive the list of identity names. + Can be NULL if only the required size of the buffer or the + number of matching identities is required. The list is + returned as a multi string. + + \param[in,out] pcb_buf Number of bytes in buffer pointed to by \a + name_buf on entry. On exit, will receive the number of bytes + copied. Can be NULL only if \a name_buf is also NULL. If \a + name_buf is NULL or if \a pcb_buf indicates that the buffer is + insufficient, this will receive the number of bytes required + and the return value of the function will be + KHM_ERROR_TOO_LONG + + \param[out] pn_idents Receives the number of identities that match + the given criteria. + + \retval KHM_ERROR_SUCCESS If \a name_buf was valid, the buffer now + contains a multi string of identities that matched. If \a + pn_idents was valid, it contains the number of identities + matched. + + \retval KHM_ERROR_TOO_LONG No buffer was supplied or the supplied + buffer was insufficient. If \a pn_idents was valid, it + contains the number of identities. + + \retval KHM_ERROR_INVALID_PARAM None of the parameters \a name_buf, + \a pcb_buf and \a pn_idents were supplied, or \a pcb_buf was + NULL when \a name_buf was not. + + \note Calling this function to obtain the required size of the + buffer and then calling it with a that sized buffer is not + guaranteed to work since the list of identities may change + between the two calls. + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_enum(khm_int32 and_flags, + khm_int32 eq_flags, + wchar_t * name_buf, + khm_size * pcb_buf, + khm_size * pn_idents); + +/*! \brief Refresh identity attributes based on root credential set + + Several flags in an identity are dependent on the credentials that + are associated with it in the root credential set. In addition, + other flags in an identity depend on external factors that need to + be verfied once in a while. This API goes through the root + credential set as well as consulting the identity provider to + update an identity. + + \see kcdb_identity_refresh() + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_refresh(khm_handle vid); + +/*! \brief Refresh all identities + + Equivalent to calling kcdb_identity_refresh() for all active + identities. + + \see kcdb_identityt_refresh() + */ +KHMEXP khm_int32 KHMAPI +kcdb_identity_refresh_all(void); + +/* KSMG_KCDB_IDENT notifications are structured as follows: + type=KMSG_KCDB + subtype=KMSG_KCDB_IDENT + uparam=one of KCDB_OP_* + blob=handle to identity in question */ + +/*@}*/ + + +/*********************************************************************/ + + +/*! +\defgroup kcdb_creds Credential sets and individual credentials + +@{ +*/ + + +/*! \brief Credentials process function + + This function is called for each credential in a credential set + when supplied to kcdb_credset_apply(). It should return + KHM_ERROR_SUCCESS to continue the operation, or any other value to + terminate the processing. + + \see kcdb_credset_apply() +*/ +typedef khm_int32 +(KHMAPI *kcdb_cred_apply_func)(khm_handle cred, + void * rock); + +/*! \brief Credentials filter function. + + Should return non-zero if the credential passed as \a cred is to + be "accepted". The precise consequence of a non-zero return value + is determined by the individual function that this call back is + passed into. + + This function should not call any other function which may modify + \a cred. + + \see kcdb_credset_collect_filtered() + \see kcdb_credset_extract_filtered() +*/ +typedef khm_int32 +(KHMAPI *kcdb_cred_filter_func)(khm_handle cred, + khm_int32 flags, + void * rock); + +/*! \brief Credentials compare function. + + Asserts a weak ordering on the credentials that are passed in as + \a cred1 and \a cred2. It should return: + + - a negative value if \a cred1 < \a cred2 + - zero if \a cred1 == \a cred2 + - a postive value if \a cred1 > \a cred2 + \see kcdb_credset_sort() + \see ::kcdb_credtype +*/ +typedef khm_int32 +(KHMAPI *kcdb_cred_comp_func)(khm_handle cred1, + khm_handle cred2, + void * rock); + +/*! \defgroup kcdb_credset Credential sets */ +/*@{*/ + +/*! \brief Create a credential set. + + Credential sets are temporary containers for credentials. These + can be used by plug-ins to store credentials while they are being + enumerated from an external source. Once all the credentials have + been collected into the credential set, the plug-in may call + kcdb_credset_collect() to collect the credentials into the root + credential store. + + The user interface will only display credentials that are in the + root credential store. No notifications are generated for changes + to a non-root credential set. + + Use kcdb_credset_delete() to delete the credential set once it is + created. + + \see kcdb_credset_delete() + \see kcdb_credset_collect() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_create(khm_handle * result); + +/** \brief Delete a credential set + + \see kcdb_credset_create() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_delete(khm_handle credset); + +/** \brief Collect credentials from a credential set to another credential set. + + Collecting a subset of credentials from credential set \a cs_src + into credential set \a cs_dest involves the following steps: + + - Select all credentials from \a cs_src that matches the \a + identity and \a type specified in the function call and add them + to the \a cs_dest credential set if they are not there already. + Note that if neither credential set is not the root credential + store, then the credentials will be added by reference, while if + it is the root credential store, the credentials will be + duplicated, and the copies will be added to \a cs_dest. + + - If a selected credential in \a cs_src already exists in \a + cs_dest, then update the credential in \a cs_dest with the + credential fields in \a cs_src. In other words, once a + credential is found to exist in both \a cs_src and \a cs_dest, + all the non-null fields from the credential in \a cs_src will be + copied to the credential in \a cs_dest. Fields which are null + (undefined) in \a cs_src and are non-null in \a cs_dest will be + left unmodified in \a cs_dest. + + One notable exception is the credentials' flags. All flags in + \a cs_src which are not included in + ::KCDB_CRED_FLAGMASK_ADDITIVE will be copied to the + corresponding bits in the flags of \a cs_dest. However, flags + that are included in ::KCDB_CRED_FLAGMASK_ADDITIVE will be added + to the corresponding bits in \a cs_dest. + + (See notes below) + + - Remove all credentials from \a cs_dest that match the \a + identity and \a type that do not appear in \a cs_src. (see notes + below) + + For performance reasons, plugins should use kcdb_credset_collect() + to update the root credentials store instead of adding and + removing individual credentials from the root store. + + Only credentials that are associated with active identities are + affected by kcdb_credset_collect(). + + \param[in] cs_dest A handle to the destination credential set. If + this is \a NULL, then it is assumed to refer to the root + credential store. + + \param[in] cs_src A handle to the source credential set. If this + is NULL, then it is assumed to refer to the root credential + store. + + \param[in] identity A handle to an identity. Setting this to NULL + collects all identities in the credential set. + + \param[in] type A credentials type. Setting this to + KCDB_CREDTYPE_ALL collects all credential types in the set. + + \param[out] delta A bit mask that indicates the modifications that + were made to \a cs_dest as a result of the collect operation. + This is a combination of KCDB_DELTA_* values. This parameter + can be \a NULL if the value is not required. + + \warning If \a identity and \a type is set to a wildcard, all + credentials in the root store that are not in this credentials + set will be deleted. + + \note Two credentials \a A and \a B are considered equal if: + - They refer to the same identity + - Both have the same credential type + - Both have the same name + + \note This is the only supported way of modifying the root + credential store. + + \note \a cs_src and \a cs_dest can not refer to the same + credentials set. + + \note The destination credential set cannot be sealed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_collect(khm_handle cs_dest, + khm_handle cs_src, + khm_handle identity, + khm_int32 type, + khm_int32 * delta); + +/*! \brief Credentials were added + \see kcdb_credset_collect() */ +#define KCDB_DELTA_ADD 1 + +/*! \brief Credentials were deleted + \see kcdb_credset_collect() */ +#define KCDB_DELTA_DEL 2 + +/*! \brief Credentials were modified + \see kcdb_credset_collect() */ +#define KCDB_DELTA_MODIFY 4 + +/*! \brief Indicates that the credential to be filtered is from the root store. + + \see kcdb_credset_collect_filtered() +*/ +#define KCDB_CREDCOLL_FILTER_ROOT 1 + +/*! \brief Indicates that the credential to be filtered is from the source + credential set + + \see kcdb_credset_collect_filtered() */ +#define KCDB_CREDCOLL_FILTER_SRC 2 + +/*! \brief Indicates that the credential to be filtered is from the destination + credential set + + \see kcdb_credset_collect_filtered() */ +#define KCDB_CREDCOLL_FILTER_DEST 4 + +/*! \brief Collect credentials from one credential set to another using a filter. + + Similar to kcdb_credset_collect() except instead of selecting + credentials by matching against an identity and/or type, a filter + function is called. If the filter function returns non-zero for a + credential, that credential is selected. + + Credentials in the source and destination credential sets are + passed into the filter function. Depending on whether the + credential is in the source credential set or destination + credential set, the \a flag parameter may have either \a + KCDB_CREDCOLL_FILTER_SRC or \a KCDB_CREDCOLL_FILTER_DEST bits set. + Also, if either one of the credential sets is the root credential + store, then additionally \a KCDB_CREDCOLL_FILTER_ROOT would also + be set. + + See the kcdb_credset_collect() documentation for explanations of + the \a cs_src, \a cs_dest and \a delta parameters which perform + identical functions. + + \param[in] filter The filter of type ::kcdb_cred_filter_func + \param[in] rock A custom argument to be passed to the filter function. + + \see kcdb_credset_collect() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_collect_filtered(khm_handle cs_dest, + khm_handle cs_src, + kcdb_cred_filter_func filter, + void * rock, + khm_int32 * delta); + +/*! \brief Flush all credentials from a credential set + + Deletes all the crednetials from the credential set. + + \param[in] credset A handle to a credential set. Cannot be NULL. + + \note The credential set cannot be sealed +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_flush(khm_handle credset); + +/*! \brief Extract credentials from one credential set to another + + Credentials from the source credential set are selected based on + the \a identity and \a type arguements. If a credential is + matched, then it is added to the \a destcredset. + + If the \a sourcecredset is the root credential set, the added + credentials are copies of the actual credentials in the root + credential set. Otherwise the credentials are references to the + original credentials in the \a sourcecredset . + + \param[in] destcredset Destination credential set. Must be valid. + + \param[in] sourcecredset The source credential set. If set to + NULL, extracts from the root credential set. + + \param[in] identity The identity to match in the source credential + set. If set to NULL, matches all identities. + + \param[in] type The credential type to match in the source credential set. + If set to KCDB_TYPE_INVALID, matches all types. + + \note This function does not check for duplicate credentials. + + \note The destination credential set cannot be sealed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_extract(khm_handle destcredset, + khm_handle sourcecredset, + khm_handle identity, + khm_int32 type); + +/*! \brief Extract credentials from one credential set to another using a filter. + + Similar to kcdb_credset_extract() except a filter function is used + to determine which credentials should be selected. + + \param[in] rock A custom argument to be passed in to the filter function. + + \note The destination credential set cannot be sealed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_extract_filtered(khm_handle destcredset, + khm_handle sourcecredset, + kcdb_cred_filter_func filter, + void * rock); + +/*! \brief Retrieve a held reference to a credential in a credential set based on index. + + \param[in] idx The index of the credential to retrieve. This is a + zero based index which goes from 0 ... (size of credset - 1). + + \param[out] cred The held reference to a credential. Call + kcdb_cred_release() to release the credential. + + \retval KHM_ERROR_SUCCESS Success. \a cred has a held reference to the credential. + \retval KHM_ERROR_OUT_OF_BOUNDS The index specified in \a idx is out of bounds. + \retval KHM_ERROR_DELETED The credential at index \a idx has been marked as deleted. + + \see kcdb_cred_release() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_get_cred(khm_handle credset, + khm_int32 idx, + khm_handle * cred); + +/*! \brief Search a credential set for a specific credential + + The credential set indicated by \a credset is searched for a + credential that satisfies the predicate function \a f. Each + credential starting at \a idx_start is passed into the predicate + function until it returns a non-zero value. At this point, that + credential is passed in to the \a cred parameter, and the index of + the credential is passed into the \a idx parameter. + + \param[in] credset The credential set to search on. Specify NULL + if you want to search teh root credential set. + + \param[in] idx_start The index at which to start the search after. + The first credential passed to the predicate function will be + at \a idx_start + 1. Specify -1 to start from the beginning + of the credential set. + + \param[in] f The predicate function. The \a flags parameter of + the predicate function will always receive 0. + + \param[in] rock An opaque parameter to be passed to the predicate + function \a f. + + \param[out] cred A held reference to the credential that satisfied + the predicate function or NULL if no such credential was + found. Note that if a valid credential is returned, the + calling function must release the credential using + kcdb_cred_release(). + + \param[out] idx The index of the credential passed in \a cred. + Specify NULL if the index is not required. + + \retval KHM_ERROR_SUCCESS A credential that satisfied the + predicate function was found and was assigned to \a cred. + + \retval KHM_ERROR_NOT_FOUND No credential was found that matched + the predicate function. + + \note When querying credential sets that are shared between + threads, it is possible that another thread modifies the + credential set between successive calls to + kcdb_credset_find_filtered(). Therefore a continued sequences of + searches are not guaranteed to exhastively cover the + credential set nor to not return duplicate matches. Duplicate + matches are possible if the order of the credentials in the + set was changed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_find_filtered(khm_handle credset, + khm_int32 idx_start, + kcdb_cred_filter_func f, + void * rock, + khm_handle * cred, + khm_int32 * idx); + +/*! \brief Find matching credential + + Searches a credential set for a credential that matches the + specified credential. For a credential to be a match, it must + have the same identity, credential type and name. + + \param[in] credset Credential set to search + + \param[in] cred_src Credetial to search on + + \param[out] cred_dest receieves the matching credential if the + search is successful. If a handle is returend, the + kcdb_cred_release() must be used to release the handle. If + the matching credential is not required, you can pass in NULL. + + \retval KHM_ERROR_SUCCESS The search was successful. A credential + was assigned to \a cred_dest + + \retval KHM_ERROR_NOT_FOUND A matching credential was not found. + */ +KHMEXP khm_int32 KHMAPI +kcdb_credset_find_cred(khm_handle credset, + khm_handle cred_src, + khm_handle *cred_dest); + + +/*! \brief Delete a credential from a credential set. + + The credential at index \a idx will be deleted. All the + credentials that are at indices \a idx + 1 and above will be moved + down to fill the gap and the size of the credential set will + decrease by one. + + Use kcdb_credset_del_cred_ref() to delete a credential by + reference. Using kcdb_credset_del_cred() is faster than + kcdb_credset_del_cred_ref(). + + If you call kcdb_credset_del_cred() or kcdb_credset_del_cred_ref() + from within kcdb_credset_apply(), the credential will only be + marked as deleted. They will not be removed. This means that the + size of the credential set will not decrease. To purge the + deleted credentials from the set, call kcdb_credset_purge() after + kcdb_credset_apply() completes. + + \note The credential set cannot be sealed. + + \see kcdb_credset_del_cred_ref() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_del_cred(khm_handle credset, + khm_int32 idx); + +/*! \brief Delete a credential from a credential set by reference. + + See kcdb_credset_del_cred() for description of what happens when a + credential is deleted from a credential set. + + \note The credential set cannot be sealed. + + \see kcdb_credset_del_cred() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_del_cred_ref(khm_handle credset, + khm_handle cred); + +/*! \brief Add a credential to a credential set. + + The credential is added by reference. In other words, no copy of + the credential is made. + + \param[in] idx Index of the new credential. This must be a value + in the range 0..(previous size of credential set) or -1. If + -1 is specifed, then the credential is appended at the end of + the set. + + \note The credential set cannot be sealed. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_add_cred(khm_handle credset, + khm_handle cred, + khm_int32 idx); + +/*! \brief Get the number of credentials in a credential set. + + Credentials in a credential set may be volatile. When + kcdb_credeset_get_size() is called, the credential set is + compacted to only include credentials that are active at the time. + However, when you are iterating through the credential set, it + might be the case that some credentials would get marked as + deleted. These credentials will remain in the credential set + until the credential set is discarded or another call to + kcdb_credset_get_size() or kdcb_credset_purge() is made. + + If the credential set is sealed, then it will not be compacted and + will include deleted credentials as well. + + \see kcdb_credset_purge() + \see kcdb_credset_get_cred() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_get_size(khm_handle credset, + khm_size * size); + +/*! \brief Removes credentials that have been marked as deleted from a credential set. + + See description of \a kcdb_credset_purge() for a description of + what happens when credntials that are contained in a credential + set are deleted by an external entity. + + \note The credential set cannot be sealed. + + \see kcdb_credset_get_size() + \see kcdb_credset_get_cred() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_purge(khm_handle credset); + +/*! \brief Applies a function to all the credentials in a credentials set + + The given function is called for each credential in a credential + set. With each iteration, the function is called with a handle to + the credential and the user defined parameter \a rock. If the + function returns anything other than KHM_ERROR_SUCCESS, the + processing stops. + + \param[in] credset The credential set to apply the function to, or + NULL if you want to apply this to the root credential set. + + \param[in] f Function to call for each credential + + \param[in] rock An opaque parameter which is to be passed to 'f' + as the second argument. + + \retval KHM_ERROR_SUCCESS All the credentials were processed. + + \retval KHM_ERROR_EXIT The supplied function signalled the + processing to be aborted. + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_apply(khm_handle credset, + kcdb_cred_apply_func f, + void * rock); + +/*! \brief Sort the contents of a credential set. + + \param[in] rock A custom argument to be passed in to the \a comp function. + + \note The credential set cannot be sealed. + + \see kcdb_cred_comp_generic() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credset_sort(khm_handle credset, + kcdb_cred_comp_func comp, + void * rock); + +/*! \brief Seal a credential set + + Sealing a credential set makes it read-only. To unseal a + credential set, call kcdb_credset_unseal(). + + Sealing is an additive operation. kcdb_credset_seal() can be + called muliple times. However, for every call to + kcdb_credset_seal() a call to kcdb_credset_unseal() must be made + to undo the seal. The credential set will become unsealed when + all the seals are released. + + Once sealed, the credential set will not allow any operation that + might change its contents. However, a selaed credential set can + still be delted. + + \see kcdb_credset_unseal() + */ +KHMEXP khm_int32 KHMAPI +kcdb_credset_seal(khm_handle credset); + +/*! \brief Unseal a credential set + + Undoes what kcdb_credset_seal() did. This does not guarantee that + the credential set is unsealed since there may be other seals. + + \see kcdb_credset_seal() + */ +KHMEXP khm_int32 KHMAPI +kcdb_credset_unseal(khm_handle credset); + +/*! \brief Defines a sort criterion for kcdb_cred_comp_generic() + + \see kcdb_cred_comp_generic() +*/ +typedef struct tag_kcdb_cred_comp_field { + khm_int32 attrib; /*!< a valid attribute ID */ + khm_int32 order; /*!< one of KCDB_CRED_COMP_INCREASING or + KCDB_CRED_COMP_DECREASING. Optionally, + KCDB_CRED_COMP_INITIAL_FIRST may be combined + with either. */ +} kcdb_cred_comp_field; + +/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field + + Sorts lexicographically ascending by string representation of field. +*/ +#define KCDB_CRED_COMP_INCREASING 0 + +/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field + + Sorts lexicographically descending by string representation of + field. + */ +#define KCDB_CRED_COMP_DECREASING 1 + +/*! \brief Defines the sort order for a field in ::kcdb_cred_comp_field + + Any credentials which have the ::KCDB_CRED_FLAG_INITIAL will be + grouped above any that don't. + + If that does not apply, then credentials from the primary + credentials type will be sorted before others. +*/ +#define KCDB_CRED_COMP_INITIAL_FIRST 2 + +/*! \brief Defines the sort criteria for kcdb_cred_comp_generic() + + \see kcdb_cred_comp_generic() +*/ +typedef struct tag_kcdb_cred_comp_order { + khm_int32 nFields; + kcdb_cred_comp_field * fields; +} kcdb_cred_comp_order; + +/*! \brief A generic compare function for comparing credentials. + + This function can be passed as a parameter to kcdb_credset_sort(). + + The \a rock parameter to this function should be a pointer to a + ::kcdb_cred_comp_order object. The \a fields member of the + ::kcdb_cred_comp_order object should point to an array of + ::kcdb_cred_comp_field objects, each of which specifies the sort + order in decreasing order of priority. The number of + ::kcdb_cred_comp_field objects in the array should correspond to + the \a nFields member in the ::kcdb_cred_comp_order object. + + The array of ::kcdb_cred_comp_field objects define the sort + criteria, in order. The \a attrib member should be a valid + attribute ID, while the \a order member determines whether the + sort order is increasing or decreasing. The exact meaning or + increasing or decreasing depends on the data type of the + attribute. + + \param[in] rock a pointer to a ::kcdb_cred_comp_order object +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_comp_generic(khm_handle cred1, + khm_handle cred2, + void * rock); + +/*@}*/ + +/*! \defgroup kcdb_cred Credentials */ +/*@{*/ + +/*! \brief Maximum number of characters in a credential name */ +#define KCDB_CRED_MAXCCH_NAME 256 + +/*! \brief Maximum number of bytes in a credential name */ +#define KCDB_CRED_MAXCB_NAME (sizeof(wchar_t) * KCDB_CRED_MAXCCH_NAME) + +/*! \brief Marked as deleted */ +#define KCDB_CRED_FLAG_DELETED 0x00000008 + +/*! \brief Renewable */ +#define KCDB_CRED_FLAG_RENEWABLE 0x00000010 + +/*! \brief Initial + + Initial credentials form the basis of an identity. Some + properties of an initial credential, such as being renewable, are + directly inherited by the identity. An identity is also + automatically considered valid if it contains a valid initial + credential. + */ +#define KCDB_CRED_FLAG_INITIAL 0x00000020 + +/*! \brief Expired + + The credential's lifetime has ended. + */ +#define KCDB_CRED_FLAG_EXPIRED 0x00000040 + +/*! \brief Invalid + + The credential can no longer serve its intended function. This + may be because it is expired and is not renewable, or its + renewable time period has also expired, or for some other reason. + */ +#define KCDB_CRED_FLAG_INVALID 0x00000080 + +/*! \brief Credential is selected + + Indicates that the credential is selected. Note that using this + flag may be subject to race conditions. + */ +#define KCDB_CRED_FLAG_SELECTED 0x00000100 + +/*! \brief Bitmask indicating all known credential flags + */ +#define KCDB_CRED_FLAGMASK_ALL 0x0000ffff + +/*! \brief External flags + + These are flags that are provided by the credentials providers. + The other flags are internal to KCDB and should not be modified. + */ +#define KCDB_CRED_FLAGMASK_EXT (KCDB_CRED_FLAG_INITIAL | KCDB_CRED_FLAG_EXPIRED | KCDB_CRED_FLAG_INVALID | KCDB_CRED_FLAG_RENEWABLE) + +/*! \brief Bitmask indicating dditive flags + + Additive flags are special flags which are added to exiting + credentials based on new credentials when doing a collect + operation. See details on kcdb_credset_collect() + + \see kcdb_credset_collect() +*/ +#define KCDB_CRED_FLAGMASK_ADDITIVE KCDB_CRED_FLAG_SELECTED + +/*! \brief Generic credentials request + + This data structure is used as the format for a generic + credentials reqeust for a ::KMSG_KCDB_REQUEST message. A plugin + typically publishes this message so that a credentials provider + may handle it and in response, obtain the specified credential. + + While the \a identity, \a type and \a name members of the + structure are all optional, typically one would specify all three + or at least two for a credential provider to be able to provide + the credential unambigously. + + Credential providers do not need to respond to ::KMSG_KCDB_REQUEST + messages. However, if they do, they should make sure that they + are the only credential provider that is responding by setting the + \a semaphore member to a non-zero value. The \a semaphore is set + to zero when a request is initially sent out. When incrementing + the semaphore, the plugin should use a thread safe mechanism to + ensure that there are no race conditions that would allow more + than one provider to respond to the message. + */ +typedef struct tag_kcdb_cred_request { + khm_handle identity; /*!< Identity of the credential. Set + to NULL if not specified. */ + khm_int32 type; /*!< Type of the credential. Set to + KCDB_CREDTYPE_INVALID if not + specified. */ + wchar_t * name; /*!< Name of the credential. Set to + NULL if not specified. */ + + khm_handle dest_credset; /*!< If non-NULL, instructs whoever is + handling the request that the + credential thus obtained be placed + in this credential set in addition + to whereever it may place newly + acquired credentials. Note that + while this can be NULL if the new + credential does not need to be + placed in a credential set, it can + not equal the root credential + set. */ + + void * vparam; /*!< An unspecified + parameter. Specific credential types + may specify how this field is to be + used. */ + + long semaphore; /*!< Incremented by one when this + request is answered. Only one + credential provider is allowed to + answer a ::KMSG_KCDB_REQUEST + message. Initially, when the + message is sent out, this member + should be set to zero. */ +} kcdb_cred_request; + +/*! \brief Create a new credential + + \param[in] name Name of credential. \a name cannot be NULL and cannot + exceed \a KCDB_CRED_MAXCCH_NAME unicode characters including the + \a NULL terminator. + \param[in] identity A reference to an identity. + \param[in] cred_type A credentials type identifier for the credential. + \param[out] result Gets a held reference to the newly created credential. + Call kcdb_cred_release() or kcdb_cred_delete() to release the + reference. + \see kcdb_cred_release() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_create(wchar_t * name, + khm_handle identity, + khm_int32 cred_type, + khm_handle * result); + +/*! \brief Duplicate an existing credential. + + \param[out] newcred A held reference to the new credential if the call + succeeds. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_dup(khm_handle cred, + khm_handle * newcred); + +/*! \brief Updates one credential using field values from another + + All fields that exist in \a vsrc will get copied to \a vdest and will + overwrite any values that are already there in \a vdest. However any + values that exist in \a vdest taht do not exist in \a vsrc will not be + modified. + + \retval KHM_ERROR_SUCCESS vdest was successfully updated + \retval KHM_ERROR_EQUIVALENT all fields in vsrc were present and equivalent in vdest +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_update(khm_handle vdest, + khm_handle vsrc); + +/*! \brief Set an attribute in a credential by name + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_attrib(khm_handle cred, + wchar_t * name, + void * buffer, + khm_size cbbuf); + +/*! \brief Set an attribute in a credential by attribute id + + \param[in] buffer A pointer to a buffer containing the data to + assign to the attribute. Setting this to NULL has the effect + of removing any data that is already assigned to the + attribute. If \a buffer is non-NULL, then \a cbbuf should + specify the number of bytes in \a buffer. + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_attr(khm_handle cred, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf); + +/*! \brief Get an attribute from a credential by name. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this credential then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attrib(khm_handle cred, + wchar_t * name, + khm_int32 * attr_type, + void * buffer, + khm_size * cbbuf); + +/*! \brief Get an attribute from a credential by attribute id. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \param[out] attr_type Receives the data type of the attribute. + Set this to NULL if the type is not required. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this credential then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attr(khm_handle cred, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * cbbuf); + +/*! \brief Get the name of a credential. + + \param[in] buffer The buffer that is to receive the credential + name. Set this to NULL if only the required buffer size is to + be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_name(khm_handle cred, + wchar_t * buffer, + khm_size * cbbuf); + +/*! \brief Get the string representation of a credential attribute. + + A shortcut function which generates the string representation of a + credential attribute directly. + + \param[in] vcred A handle to a credential + + \param[in] attr_id The attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \retval KHM_ERROR_SUCCESS Success + \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid + or was not defined for this credential + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the + supplied buffer was insufficient +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attr_string(khm_handle vcred, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Get the string representation of a credential attribute by name. + + A shortcut function which generates the string representation of a + credential attribute directly. + + \param[in] vcred A handle to a credential + + \param[in] attrib The name of the attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \see kcdb_cred_get_attr_string() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_attrib_string(khm_handle cred, + wchar_t * name, + wchar_t * buffer, + khm_size * cbbuf, + khm_int32 flags) ; + + +/*! \brief Get a held reference to the identity associated with a credential + + Use kcdb_identity_release() to release the reference that is + returned. + + \see kcdb_identity_relase() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_identity(khm_handle cred, + khm_handle * identity); + +/*! \brief Set the identity of a credential + + While it is ill-advised to change the identity of a credential + that has been placed in one or more credential sets, there can be + legitimate reasons for doing so. Only change the identity of a + credential that is not placed in a credential set or placed in a + credential set that is only used by a single entity. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_identity(khm_handle vcred, + khm_handle id); + +/*! \brief Get the serial number for the credential. + + Each credential gets assigned a serial number at the time it is + created. This will stay with the credential for its lifetime. + + \param[out] pserial Receives the serial number. Cannot be NULL. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_serial(khm_handle cred, + khm_ui_8 * pserial); + +/*! \brief Get the type of the credential. + + The returned type is a credential type. Doh. + + \param[out] type Receives the type. Cannot be NULL. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_type(khm_handle cred, + khm_int32 * type); + +/*! \brief Retrieve flags from a credential + + The flags returned will be place in the location pointed to by \a + flags. Note that the specified credential must be an active + credential for the operation to succeed. This means the + ::KCDB_CRED_FLAG_DELETED will never be retured by this function. + */ +KHMEXP khm_int32 KHMAPI +kcdb_cred_get_flags(khm_handle cred, + khm_int32 * flags); + +/*! \brief Set the flags of a credential + + The flags specified in the \a mask parameter will be set to the + values specified in the \a flags parameter. The flags that are + not included in \a mask will not be modified. + + This function can not be used to set the ::KCDB_CRED_FLAG_DELETED + flag. If this bit is specified in either \a flags or \a mask, it + will be ignored. + + \see ::KCDB_CRED_FLAGMASK_ALL + */ +KHMEXP khm_int32 KHMAPI +kcdb_cred_set_flags(khm_handle cred, + khm_int32 flags, + khm_int32 mask); + +/*! \brief Hold a reference to a credential. + + Use kcdb_cred_release() to release the reference. + + \see kcdb_cred_release() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_hold(khm_handle cred); + +/*! \brief Release a held reference to a credential. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_release(khm_handle cred); + +/*! \brief Delete a credential. + + The credential will be marked for deletion and will continue to + exist until all held references are released. If the credential + is bound to a credential set or the root credential store, it will + be removed from the respective container. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_cred_delete(khm_handle cred); + +/*! \brief Compare an attribute of two credentials by name. + + \return The return value is dependent on the type of the attribute + and indicate a weak ordering of the attribute values of the two + credentials. If one or both credentials do not contain the + attribute, the return value is 0, which signifies that no ordering + can be determined. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_creds_comp_attrib(khm_handle cred1, + khm_handle cred2, + wchar_t * name); + +/*! \brief Compare an attribute of two credentials by attribute id. + + \return The return value is dependent on the type of the attribute + and indicate a weak ordering of the attribute values of the two + credentials. If one or both credentials do not contain the + attribute, the return value is 0, which signifies that no ordering + can be determined. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_creds_comp_attr(khm_handle cred1, + khm_handle cred2, + khm_int32 attr_id); + +/*! \brief Compare two credentials for equivalence + + \return Non-zero if the two credentials are equal. Zero otherwise. + \note Two credentials are considered equal if all the following hold: + - Both refer to the same identity. + - Both have the same name. + - Both have the same type. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_creds_is_equal(khm_handle cred1, + khm_handle cred2); + +/*@}*/ +/*@}*/ + +/********************************************************************/ + +/*! \defgroup kcdb_type Credential attribute types */ +/*@{*/ + +/*! \brief Convert a field to a string + + Provides a string representation of a field in a credential. The + data buffer can be assumed to be valid. + + On entry, \a s_buf can be NULL if only the required size of the + buffer is to be returned. \a pcb_s_buf should be non-NULL and + should point to a valid variable of type ::khm_size that will, on + entry, contain the size of the buffer pointed to by \a s_buf if \a + s_buf is not \a NULL, and on exit will contain the number of bytes + consumed in \a s_buf, or the required size of the buffer if \a + s_buf was NULL or the size of the buffer was insufficient. + + The implementation should verify the parameters that are passed in + to the function. + + The data pointed to by \a data should not be modified in any way. + + \param[in] data Valid pointer to a block of data + + \param[in] cb_data Number of bytes in data block pointed to by \a + data + + \param[out] s_buf Buffer to receive the string representation of + data. If the data type flags has KCDB_TYPE_FLAG_CB_AUTO, then + this parameter could be set to KCDB_CBSIZE_AUTO. In this + case, the function should compute the size of the input buffer + assuming that the input buffer is valid. + + \param[in,out] pcb_s_buf On entry, contains the size of the buffer + pointed to by \a s_buf, and on exit, contains the number of + bytes used by the string representation of the data including + the NULL terminator + + \param[in] flags Flags for formatting the string + + \retval KHM_ERROR_SUCCESS The string representation of the data + field was successfully copied to \a s_buf and the size of the + buffer used was copied to \a pcb_s_buf. + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + + \retval KHM_ERROR_TOO_LONG Either \a s_buf was \a NULL or the size + indicated by \a pcb_s_buf was too small to contain the string + representation of the value. The required size of the buffer + is in \a pcb_s_buf. + + \note This documents the expected behavior of this prototype function + + \see ::kcdb_type + */ +typedef khm_int32 +(KHMAPI *kcdb_dtf_toString)(const void * data, + khm_size cb_data, + wchar_t * s_buf, + khm_size * pcb_s_buf, + khm_int32 flags); + +/*! \brief Verifies whetehr the given buffer contains valid data + + The function should examine the buffer and the size of the buffer + and determine whether or not the buffer contains valid data for + this data type. + + The data field pointed to by \a data should not be modified in any + way. + + \param[in] data A pointer to a data buffer + + \param[in] cb_data The number of bytes in the data buffer. If the + data type flags has KCDB_TYPE_FLAG_CB_AUTO, then this + parameter could be set to KCDB_CBSIZE_AUTO. In this case, the + function should compute the size of the input buffer assuming + that the input buffer is valid. + + \return TRUE if the data is valid, FALSE otherwise. + + \note This documents the expected behavior of this prototype function + + \see ::kcdb_type +*/ +typedef khm_boolean +(KHMAPI *kcdb_dtf_isValid)(const void * data, + khm_size cb_data); + +/*! \brief Compare two fields + + Compare the two data fields and return a value indicating their + relative ordering. The return value follows the same + specification as strcmp(). + + Both data buffers that are passed in can be assumed to be valid. + + None of the data buffers should be modified in any way. + + \param[in] data_l Valid pointer to first data buffer + + \param[in] cb_data_l Number of bytes in \a data_l. If the data + type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter + could be set to KCDB_CBSIZE_AUTO. In this case, the function + should compute the size of the input buffer assuming that the + input buffer is valid. + + \param[in] data_r Valid pointer to second data buffer + + \param[in] cb_data_r Number of bytes in \a data_r. If the data + type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter + could be set to KCDB_CBSIZE_AUTO. In this case, the function + should compute the size of the input buffer assuming that the + input buffer is valid. + + \return The return value should be + - Less than zero if \a data_l < \a data_r + - Equal to zero if \a data_l == \a data_r or if this data type can not be compared + - Greater than zero if \a data_l > \a data_r + + \note This documents the expected behavior of this prototype function + + \see ::kcdb_type +*/ +typedef khm_int32 +(KHMAPI *kcdb_dtf_comp)(const void * data_l, + khm_size cb_data_l, + const void * data_r, + khm_size cb_data_r); + +/*! \brief Duplicate a data field + + Duplicates a data field. The buffer pointed to by \a data_src + contains a valid field. The function should copy the field with + appropriate adjustments to \a data_dst. + + The \a data_dst parameter can be NULL if only the required size of + the buffer is needed. In this case, teh function should set \a + pcb_data_dst to the number of bytes required and then return + KHM_ERROR_TOO_LONG. + + \param[in] data_src Pointer to a valid data buffer + + \param[in] cb_data_src Number of bytes in \a data_src. If the data + type flags has KCDB_TYPE_FLAG_CB_AUTO, then this parameter + could be set to KCDB_CBSIZE_AUTO. In this case, the function + should compute the size of the input buffer assuming that the + input buffer is valid. + + \param[out] data_dst Poitner to destination buffer. Could be NULL + if only the required size of the destination buffer is to be + returned. + + \param[in,out] pcb_data_dst On entry specifies the number of bytes + in \a data_dst, and on exit should contain the number of bytes + copied. + + \retval KHM_ERROR_SUCCESS The data was successfully copied. The + number of bytes copied is in \a pcb_data_dst + + \retval KHM_ERROR_INVALID_PARAM One or more parameters is incorrect. + + \retval KHM_ERROR_TOO_LONG Either \a data_dst was NULL or the size + of the buffer was insufficient. The required size is in \a + pcb_data_dst + + \note This documents the expected behavior of this prototype function + + \see ::kcdb_type + */ +typedef khm_int32 +(KHMAPI *kcdb_dtf_dup)(const void * data_src, + khm_size cb_data_src, + void * data_dst, + khm_size * pcb_data_dst); + +/*! \brief A data type descriptor. + + Handles basic operation for a specific data type. + + \see \ref cred_data_types +*/ +typedef struct tag_kcdb_type { + wchar_t * name; + khm_int32 id; + khm_int32 flags; + + khm_size cb_min; + khm_size cb_max; + + kcdb_dtf_toString toString; + /*!< Provides a string representation for a value. */ + + kcdb_dtf_isValid isValid; + /*!< Returns true of the value is valid for this data type */ + + kcdb_dtf_comp comp; + /*!< Compare two values and return \a strcmp style return value */ + + kcdb_dtf_dup dup; + /*!< Duplicate a value into a secondary buffer */ +} kcdb_type; + +/*! \name Flags for kcdb_type::toString +@{*/ +/*! \brief Specify that the short form of the string representation should be returned. + + Flags for #kcdb_type::toString. The flag specifies how long the + string representation should be. The specific length of a short + or long description is not restricted and it is up to the + implementation to choose how to interpret the flags. + + Usually, KCDB_TS_SHORT is specified when the amount of space that + is available to display the string is very restricted. It may be + the case that the string is truncated to facilitate displaying in + a constrainted space. +*/ +#define KCDB_TS_SHORT 1 + +/*! \brief Specify that the long form of the string representation should be returned + + Flags for #kcdb_type::toString. The flag specifies how long the + string representation should be. The specific length of a short + or long description is not restricted and it is up to the + implementation to choose how to interpret the flags. + +*/ +#define KCDB_TS_LONG 0 +/*@}*/ + +/*! \brief The maximum number of bytes allowed for a value of any type */ +#define KCDB_TYPE_MAXCB 16384 + +/*! \name Flags for kcdb_type +@{*/ + +/*! \brief The type supports KCDB_CBSIZE_AUTO. + + Used for types where the size of the object can be determined + through context or by the object content. Such as for objects + that have a fixed size or unicode strings that have a terminator. + + This implies that ALL the object manipulation callbacks that are + defined in this type definition support the KCDB_CBSIZE_AUTO + value. +*/ +#define KCDB_TYPE_FLAG_CB_AUTO 16 + +/*! \brief The \a cb_min member is valid. + + The \a cb_min member defines the minimum number of bytes that an + object of this type will consume. + + \note If this flag is used in conjunction with \a + KCDB_TYPE_FLAG_CB_MAX then, \a cb_min must be less than or equal + to \a cb_max. +*/ +#define KCDB_TYPE_FLAG_CB_MIN 128 + +/*! \brief The \a cb_max member is valid. + + The \a cb_max member defines the maximum number of bytes that an + object of this type will consume. + + \note If this flag is used in conjunction with \a + KCDB_TYPE_FLAG_CB_MIN then, \a cb_min must be less than or + equal to \a cb_max. */ +#define KCDB_TYPE_FLAG_CB_MAX 256 + +/*! \brief Denotes that objects of this type have a fixed size. + + If this flags is specified, then the type definition must also + specify cb_min and cb_max, which must both be the same value. + + \note Implies \a KCDB_TYPE_FLAG_CB_AUTO, \a KCDB_TYPE_FLAG_CB_MIN + and \a KCDB_TYPE_FLAG_CB_MAX. Pay special attention to the + implication of \a KCDB_TYPE_FLAG_AUTO. +*/ +#define KCDB_TYPE_FLAG_CB_FIXED (KCDB_TYPE_FLAG_CB_AUTO|KCDB_TYPE_FLAG_CB_MIN|KCDB_TYPE_FLAG_CB_MAX) + +/*@}*/ + +KHMEXP khm_int32 KHMAPI +kcdb_type_get_id(wchar_t *name, khm_int32 * id); + +/*! \brief Return the type descriptor for a given type id + + \param[out] info Receives a held reference to a type descriptor. + Use kcdb_type_release_info() to release the handle. If the \a + info parameter is NULL, the function returns KHM_ERROR_SUCCESS + if \a id is a valid type id, and returns KHM_ERROR_NOT_FOUND + otherwise. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_type_get_info(khm_int32 id, kcdb_type ** info); + +KHMEXP khm_int32 KHMAPI +kcdb_type_release_info(kcdb_type * info); + +KHMEXP khm_int32 KHMAPI +kcdb_type_get_name(khm_int32 id, + wchar_t * buffer, + khm_size * cbbuf); + +/*! \brief Register a credentials attribute type + + The credentials type record pointed to by \a type defines a new + credential attribute type. The \a id member of \a type may be set + to KCDB_TYPE_INVALID to indicate that an attribute ID is to be + generated automatically. + + \param[in] type The type descriptor + \param[out] new_id Receives the identifier for the credential attribute type. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_type_register(kcdb_type * type, + khm_int32 * new_id); + +/*! \brief Unregister a credential attribute type + + Removes the registration for the specified credentials attribute + type. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_type_unregister(khm_int32 id); + +KHMEXP khm_int32 KHMAPI +kcdb_type_get_next_free(khm_int32 * id); + +/*! \name Conversion functions +@{*/ +/*! \brief Convert a time_t value to FILETIME +*/ +KHMEXP void KHMAPI +TimetToFileTime( time_t t, LPFILETIME pft ); + +/*! \brief Convert a time_t interval to a FILETIME interval +*/ +KHMEXP void KHMAPI +TimetToFileTimeInterval(time_t t, LPFILETIME pft); + +/*! \brief Convert a FILETIME interval to seconds +*/ +KHMEXP long KHMAPI +FtIntervalToSeconds(LPFILETIME pft); + +/*! \brief Convert a FILETIME interval to milliseconds +*/ +KHMEXP long KHMAPI +FtIntervalToMilliseconds(LPFILETIME pft); + +/*! \brief Compare two FILETIME values + + The return value is similar to the return value of strcmp(), based + on the comparison of the two FILETIME values. + */ +KHMEXP long KHMAPI +FtCompare(LPFILETIME pft1, LPFILETIME pft2); + +/*! \brief Convert a FILETIME to a 64 bit int +*/ +KHMEXP khm_int64 KHMAPI FtToInt(LPFILETIME pft); + +/*! \brief Convert a 64 bit int to a FILETIME +*/ +KHMEXP FILETIME KHMAPI IntToFt(khm_int64 i); + +/*! \brief Calculate the difference between two FILETIMEs + + Returns the value of ft1 - ft2 + */ +KHMEXP FILETIME KHMAPI FtSub(LPFILETIME ft1, LPFILETIME ft2); + +/*! \brief Calculate the sum of two FILETIMEs + + Return the value of ft1 + ft2 + */ +KHMEXP FILETIME KHMAPI FtAdd(LPFILETIME ft1, LPFILETIME ft2); + +/*! \brief Convert a FILETIME inverval to a string +*/ +KHMEXP khm_int32 KHMAPI +FtIntervalToString(LPFILETIME data, + wchar_t * buffer, + khm_size * cb_buf); + +/*! \brief Parse a string representing an interval into a FILETIME interval + + The string is a localized string which should look like the + following: + + \code + [number unit] [number unit]... + \endcode + + where \a number is an integer while \a unit is a localized + (possibly abbreviated) unit specification. The value of the + described interval is calculated as the sum of each \a number in + \a units. For example : + + \code + 1 hour 36 minutes + \endcode + + would result in an interval specification that's equivalent to 1 + hour and 36 minutes. Of course there is no restriction on the + order in which the \a number \a unit specifications are given and + the same unit may be repeated multiple times. + + \retval KHM_ERROR_INVALID_PARAM The given string was invalid or had + a token that could not be parsed. It can also mean that \a + pft was NULL or \a str was NULL. + + \retval KHM_ERROR_SUCCESS The string was successfully parsed and + the result was placed in \a pft. +*/ +KHMEXP khm_int32 KHMAPI +IntervalStringToFt(FILETIME * pft, wchar_t * str); + +/*! \brief Return number of milliseconds till next representation change + + Returns the number of milliseconds that must elapse away from the + interval specified in pft \a for the representation of pft to change + from whatever it is right now. + + Returns 0 if the representation is not expected to change. +*/ +KHMEXP long KHMAPI +FtIntervalMsToRepChange(LPFILETIME pft); + +/*! \brief Convert a safe ANSI string to a Unicode string + + The resulting string is guaranteed to be NULL terminated and + within the size limit set by \a cbwstr. + + If the whole string cannot be converted, \a wstr is set to an + empty string. + + \return the number of characters converted. This is always either + the length of the string \a astr or 0. +*/ +KHMEXP int KHMAPI +AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr); + +/*! \brief Convert a Unicode string to ANSI + + The resulting string is guaranteed to be NULL terminated and + within the size limit set by \a cbdest. + + \return the number of characters converted. This is always either + the length of the string \a src or 0. +*/ +KHMEXP int KHMAPI +UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src); +/*@}*/ + +/*! \name Standard type identifiers and names +@{*/ + +/*! Maximum identifier number */ +#define KCDB_TYPE_MAX_ID 255 + +/*! \brief Invalid type + + Used by functions that return a type identifier to indicate that + the returned type identifier is invalid. Also used to indicate + that a type identifier is not available */ +#define KCDB_TYPE_INVALID (-1) + +/*! \brief All types + + Used by filters to indicate that all types are allowed. +*/ +#define KCDB_TYPE_ALL KCDB_TYPE_INVALID + +#define KCDB_TYPE_VOID 0 +#define KCDB_TYPE_STRING 1 +#define KCDB_TYPE_DATE 2 +#define KCDB_TYPE_INTERVAL 3 +#define KCDB_TYPE_INT32 4 +#define KCDB_TYPE_INT64 5 +#define KCDB_TYPE_DATA 6 + +#define KCDB_TYPENAME_VOID L"Void" +#define KCDB_TYPENAME_STRING L"String" +#define KCDB_TYPENAME_DATE L"Date" +#define KCDB_TYPENAME_INTERVAL L"Interval" +#define KCDB_TYPENAME_INT32 L"Int32" +#define KCDB_TYPENAME_INT64 L"Int64" +#define KCDB_TYPENAME_DATA L"Data" +/*@}*/ +/*@}*/ + +/********************************************************************/ + +/*! \defgroup kcdb_credattr Credential attributes */ +/*@{*/ + +/*! \brief Prototype callback function for computed data types. + + If the flags for a particular attribute specifies that the value + is computed, then a callback function should be specified. The + callback function will be called with a handle to a credential + along with the attribute ID for the requested attribute. The + function should place the computed value in \a buffer. The size + of the buffer in bytes is specifed in \a cbsize. However, if \a + buffer is \a NULL, then the required buffer size should be placed + in \a cbsize. + */ +typedef khm_int32 +(KHMAPI *kcdb_attrib_compute_cb)(khm_handle cred, + khm_int32 id, + void * buffer, + khm_size * cbsize); + +/*! \brief Credential attribute descriptor + + \see kcdb_attrib_register() +*/ +typedef struct tag_kcdb_attrib { + wchar_t * name; /*!< Name. (Not localized, + required) */ + khm_int32 id; /*!< Identifier. When registering, + this can be set to + ::KCDB_ATTR_INVALID if a unique + identifier is to be generated. */ + khm_int32 alt_id; /*!< Alternate identifier. If the \a + flags specify + ::KCDB_ATTR_FLAG_ALTVIEW, then this + field should specify the identifier + of the canonical attribute from + which this attribute is derived. */ + khm_int32 flags; /*!< Flags. Combination of \ref + kcdb_credattr_flags "attribute + flags" */ + + khm_int32 type; /*!< Type of the attribute. Must be valid. */ + + wchar_t * short_desc; /*!< Short description. (Localized, + optional) */ + + wchar_t * long_desc; /*!< Long description. (Localized, + optional) */ + + kcdb_attrib_compute_cb compute_cb; + /*!< Callback. Required if \a flags + specify ::KCDB_ATTR_FLAG_COMPUTED. */ + + khm_size compute_min_cbsize; + /*!< Minimum number of bytes required + to store this attribute. Required + if ::KCDB_ATTR_FLAG_COMPUTED is + specified.*/ + khm_size compute_max_cbsize; + /*!< Maximum number of bytes required + to store this attribute. Required + if ::KCDB_ATTR_FLAG_COMPUTED is + specified.*/ +} kcdb_attrib; + +/*! \brief Retrieve the ID of a named attribute */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_id(wchar_t *name, + khm_int32 * id); + +/*! \brief Register an attribute + + \param[out] new_id Receives the ID of the newly registered + attribute. If the \a id member of the ::kcdb_attrib object is + set to KCDB_ATTR_INVALID, then a unique ID is generated. */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_register(kcdb_attrib * attrib, + khm_int32 * new_id); + +/*! \brief Retrieve the attribute descriptor for an attribute + + The descriptor that is returned must be released through a call to + kcdb_attrib_release_info() + + If only the validity of the attribute identifier needs to be + checked, you can pass in NULL for \a attrib. In this case, if the + identifier is valid, then the funciton will return + KHM_ERROR_SUCCESS, otherwise it will return KHM_ERROR_NOT_FOUND. + + \see kcdb_attrib_release_info() + */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_info(khm_int32 id, + kcdb_attrib ** attrib); + +/*! \brief Release an attribute descriptor + + \see kcdb_attrib_get_info() + */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_release_info(kcdb_attrib * attrib); + +/*! \brief Unregister an attribute + + Once an attribute ID has been unregistered, it may be reclaimed by + a subsequent call to kcdb_attrib_register(). +*/ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_unregister(khm_int32 id); + +/*! \brief Retrieve the description of an attribute + + \param[in] flags Specify \a KCDB_TS_SHORT to retrieve the short description. */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_describe(khm_int32 id, + wchar_t * buffer, + khm_size * cbsize, + khm_int32 flags); + +/*! \brief Count attributes + + Counts the number of attributes that match the given criteria. + The criteria is specified against the flags of the attribute. An + attribute is a match if its flags satisfy the condition below: + + \code + (attrib.flags & and_flags) == (eq_flags & and_flags) + \endcode + + The number of attributes that match are returned in \a pcount. + */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_count(khm_int32 and_flags, + khm_int32 eq_flags, + khm_size * pcount); + +/*! \brief List attribute identifiers + + Lists the identifiers of the attributes that match the given + criteria. The criteria is specified against the flags of the + attribute. An attribute is a match if the following condition is + satisfied: + + \code + (attrib.flags & and_flags) == (eq_flags & and_flags) + \endcode + + The list of attributes found are copied to the \a khm_int32 array + specified in \a plist. The number of elements available in the + buffer \a plist is specified in \a pcsize. On exit, \a pcsize + will hold the actual number of attribute identifiers copied to the + array. + + \param[in] and_flags See above + \param[in] eq_flags See above + \param[in] plist A khm_int32 array + \param[in,out] pcsize On entry, holds the number of elements + available in the array pointed to by \a plist. On exit, holds + the number of elements copied to the array. + + \retval KHM_ERROR_SUCCESS The list of attribute identifiers have + been copied. + \retval KHM_ERROR_TOO_LONG The list was too long to fit in the + supplied buffer. As many elements as possible have been + copied to the \a plist array and the required number of + elements has been written to \a pcsize. + + \note The \a pcsize parameter specifies the number of khm_int32 + elements in the array and not the number of bytes in the + array. This is different from the usual size parameters used + in the NetIDMgr API. + */ +KHMEXP khm_int32 KHMAPI +kcdb_attrib_get_ids(khm_int32 and_flags, + khm_int32 eq_flags, + khm_int32 * plist, + khm_size * pcsize); + +/*! \defgroup kcdb_credattr_flags Attribute flags */ +/*@{*/ +/*! \brief The attribute is required */ +#define KCDB_ATTR_FLAG_REQUIRED 0x00000008 + +/*! \brief The attribute is computed. + + If this flag is set, the \a compute_cb, \a compute_min_cbsize and + \a compute_max_cbsize members of the ::kcdb_attrib attribute + descriptor must be assigned valid values. +*/ +#define KCDB_ATTR_FLAG_COMPUTED 0x00000010 + +/*! \brief System attribute. + + This cannot be specified for a custom attribute. Implies that the + value of the attribute is given by the credentials database + itself. +*/ +#define KCDB_ATTR_FLAG_SYSTEM 0x00000020 + +/*! \brief Hidden + + The attribute is not meant to be displayed to the user. Setting + this flag prevents this attribute from being listed in the list of + available data fields in the UI. +*/ +#define KCDB_ATTR_FLAG_HIDDEN 0x00000040 + +/*! \brief Property + + The attribute is a property. The main difference between regular + attributes and properties are that properties are not allocated + off the credentials record. Hence, a property can not be used as + a credentials field. Other objects such as identities can hold + property sets. A property set can hold both regular attributes as + well as properties. +*/ +#define KCDB_ATTR_FLAG_PROPERTY 0x00000080 + +/*! \brief Volatile + + A volatile property is one whose value changes often, such as + ::KCDB_ATTR_TIMELEFT. Some controls will make use of additional + logic to deal with such values, or not display them at all. + */ +#define KCDB_ATTR_FLAG_VOLATILE 0x00000100 + +/*! \brief Alternate view + + The attribute is actually an alternate representation of another + attribute. The Canonical attribute name is specified in \a + alt_id. + + Sometimes a certain attribute may need to be represented in + different ways. You can register multiple attributes for each + view. However, you should also provide a canonical attribute for + whenever the canonical set of attributes of the credential is + required. + */ +#define KCDB_ATTR_FLAG_ALTVIEW 0x00000200 +/*@}*/ + +/*! \defgroup kcdb_credattr_idnames Standard attribute IDs and names */ +/*@{*/ + +/*! \name Attribute related constants */ +/*@{*/ +/*! \brief Maximum valid attribute ID */ +#define KCDB_ATTR_MAX_ID 255 + +/*! \brief Minimum valid property ID */ +#define KCDB_ATTR_MIN_PROP_ID 4096 + +/*! \brief Maximum number of properties */ +#define KCDB_ATTR_MAX_PROPS 128 + +/*! \brief Maximum valid property ID */ +#define KCDB_ATTR_MAX_PROP_ID (KCDB_ATTR_MIN_PROP_ID + KCDB_ATTR_MAX_PROPS - 1) + +/*! \brief Invalid ID */ +#define KCDB_ATTR_INVALID (-1) + +/*! \brief First custom attribute ID */ +#define KCDB_ATTRID_USER 20 + +/*@}*/ + +/*!\name Attribute identifiers */ +/*@{*/ +/*! \brief Name of the credential + + - \b Type: STRING + - \b Flags: REQUIRED, COMPUTED, SYSTEM + */ +#define KCDB_ATTR_NAME 0 + +/*! \brief The identity handle for the credential + + - \b Type: INT64 + - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN + + \note The handle returned in by specifying this attribute to + kcdb_cred_get_attr() or kcdb_cred_get_attrib() is not held. + While the identity is implicitly held for the duration that + the credential is held, it is not recommended to obtain a + handle to the identity using this method. Use + kcdb_cred_get_identity() instead. +*/ +#define KCDB_ATTR_ID 1 + +/*! \brief The name of the identity + + - \b Type: STRING + - \b Flags: REQUIRED, COMPUTED, SYSTEM + */ +#define KCDB_ATTR_ID_NAME 2 + +/*! \brief The type of the credential + + - \b Type: INT32 + - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN +*/ +#define KCDB_ATTR_TYPE 3 + +/*! \brief Type name for the credential + + - \b Type: STRING + - \b Flags: REQUIRED, COMPUTED, SYSTEM +*/ +#define KCDB_ATTR_TYPE_NAME 4 + +/*! \brief Name of the parent credential + + - \b Type: STRING + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_PARENT_NAME 5 + +/*! \brief Issed on + + - \b Type: DATE + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_ISSUE 6 + +/*! \brief Expires on + + - \b Type: DATE + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_EXPIRE 7 + +/*! \brief Renewable period expires on + + - \b Type: DATE + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_RENEW_EXPIRE 8 + +/*! \brief Time left till expiration + + - \b Type: INTERVAL + - \b Flags: SYSTEM, COMPUTED, VOLATILE +*/ +#define KCDB_ATTR_TIMELEFT 9 + +#define KCDB_ATTR_RENEW_TIMELEFT 10 + +/*! \brief Location of the credential + + - \b Type: STRING + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_LOCATION 11 + +/*! \brief Lifetime of the credential + + - \b Type: INTERVAL + - \b Flags: SYSTEM +*/ +#define KCDB_ATTR_LIFETIME 12 + +#define KCDB_ATTR_RENEW_LIFETIME 13 + +/*! \brief Flags for the credential + + - \b Type: INT32 + - \b Flags: REQUIRED, COMPUTED, SYSTEM, HIDDEN + */ +#define KCDB_ATTR_FLAGS 14 + +/*@}*/ + +/*!\name Attribute names */ +/*@{ */ + +#define KCDB_ATTRNAME_NAME L"Name" +#define KCDB_ATTRNAME_ID L"Identity" +#define KCDB_ATTRNAME_ID_NAME L"IdentityName" +#define KCDB_ATTRNAME_TYPE L"TypeId" +#define KCDB_ATTRNAME_TYPE_NAME L"TypeName" +#define KCDB_ATTRNAME_FLAGS L"Flags" + +#define KCDB_ATTRNAME_PARENT_NAME L"Parent" +#define KCDB_ATTRNAME_ISSUE L"Issed" +#define KCDB_ATTRNAME_EXPIRE L"Expires" +#define KCDB_ATTRNAME_RENEW_EXPIRE L"RenewExpires" +#define KCDB_ATTRNAME_TIMELEFT L"TimeLeft" +#define KCDB_ATTRNAME_RENEW_TIMELEFT L"RenewTimeLeft" +#define KCDB_ATTRNAME_LOCATION L"Location" +#define KCDB_ATTRNAME_LIFETIME L"Lifetime" +#define KCDB_ATTRNAME_RENEW_LIFETIME L"RenewLifetime" + +/*@}*/ + +/*@}*/ + +/*@}*/ + +/*****************************************************************************/ + +/*! \defgroup kcdb_credtype Credential types */ +/*@{*/ + +/*! \brief Credential type descriptor */ +typedef struct tag_kcdb_credtype { + wchar_t * name; /*!< name (less than KCDB_MAXCB_NAME bytes) */ + khm_int32 id; + wchar_t * short_desc; /*!< short localized description (less + than KCDB_MAXCB_SHORT_DESC bytes) */ + wchar_t * long_desc; /*!< long localized descriptionn (less + than KCDB_MAXCB_LONG_DESC bytes) */ + khm_handle sub; /*!< Subscription for credentials type + hander. This should be a valid + subscription constructed through a + call to kmq_create_subscription() + and must handle KMSG_CRED messages + that are marked as being sent to + type specific subscriptions. + + The subscription will be + automatically deleted with a call to + kmq_delete_subscription() when the + credentials type is unregistered.*/ + + kcdb_cred_comp_func is_equal; /*!< Used to as an additional clause + when comparing two credentials for + equality. The function this is + actually a comparison function, it + should return zero if the two + credentials are equal and non-zero + if they are not. The addtional \a + rock parameter is always zero. + + It can be assumed that the identity, + name and credentials have already + been found to be equal among the + credentials and the credential type + is the type that is being + registered.*/ + +#ifdef _WIN32 + HICON icon; +#endif +} kcdb_credtype; + +/*! \brief Maximum value of a credential type identifier + + Credential type identifiers are assigned serially unless the + process registering the credential type sets a specific identity. + The maximum identifier number places a hard limit to the number of + credential types that can be registered at one time, which is + KCDB_CREDTYPE_MAX_ID + 1. + */ +#define KCDB_CREDTYPE_MAX_ID 31 + +/*! \brief Specify all credential types + + This value is used by functions which filter credentials based on + credential types. Specifying this value tells the filter to + accept all credential types. + */ +#define KCDB_CREDTYPE_ALL (-1) + +/*! \brief Automatically determine a credential type identifier + + Used with kcdb_credtype_register() to specify that the credential + type identifier should be automatically determined to avoid + collisions. + */ +#define KCDB_CREDTYPE_AUTO (-2) + +/*! \brief An invalid credential type + + Even though any non positive credential type ID is invalid + anywhere where a specific credential type ID is required, this + value is provided for explicit indication that the credential type + is invalid. Also it makes code more readable to have a constant + that shouts out INVALID. + +*/ +#define KCDB_CREDTYPE_INVALID (-3) + +/*! \brief Macro predicate for testing whether a credtype is valid + + Returns TRUE if the given credtype is valid. This is a safe + macro. +*/ +#define KCDB_CREDTYPE_IS_VALID(t) ((t) >= 0) + +/*! \brief Register a credentials type. + + The information given in the \a type parameter is used to register + a new credential type. Note that the \a name member of the \a + type should be unique among all credential types. + + You can specify ::KCDB_CREDTYPE_AUTO as the \a id member of \a + type to let kcdb_credtype_register() determine a suitable + credential type identifier. You can subsequently call + kcdb_credtype_get_id() to retrieve the generated id or pass a + valid pointer to a khm_int32 type variable as \a new_id. + + \param[in] type Credential type descriptor + + \param[out] new_id The credential type identifier that this type + was registered as. + + \retval KHM_ERROR_SUCCESS The credential type was successfully registered. + + \retval KHM_ERROR_INVALID_PARAM One or more of the parameters were invalid + + \retval KHM_ERROR_TOO_LONG One or more of the string fields in \a + type exceeded the character limit for that field. + + \retval KHM_ERROR_NO_RESOURCES When autogenerating credential type + identifiers, this value indicates that the maximum number of + credential types have been registered. No more registrations + can be accepted unless some credentials type is unregisred. + + \retval KHM_ERROR_DUPLICATE The \a name or \a id that was + specified is already in use. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_register(kcdb_credtype * type, + khm_int32 * new_id); + +/*! \brief Return a held reference to a \a kcdb_credtype object describing the credential type. + + The reference points to a static internal object of type \a + kcdb_credtype. Use the kcdb_credtype_release_info() function to + release the reference. + + Also, the structure passed in as the \a type argument to + kcdb_credtype_register() is not valid as a credential type + descriptor. Use kcdb_credtype_get_info() to obtain the actual + credential type descriptor. + + \param[in] id Credentials type identifier. + + \param[out] type Receives the credentials descriptor handle. If + \a type is NULL, then no handle is returned. However, the + function will still return \a KHM_ERROR_SUCCESS if the \a id + parameter passed in is a valid credentials type identifier. + + \see kcdb_credtype_release_info() + \see kcdb_credtype_register() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_get_info(khm_int32 id, + kcdb_credtype ** type); + +/*! \brief Release a reference to a \a kcdb_credtype object + + Undoes the hold obtained on a \a kcdb_credtype object from a + previous call to kcdb_credtype_get_info(). + + \see kcdb_credtype_get_info() + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_release_info(kcdb_credtype * type); + +/*! \brief Unregister a credentials type + + Undoes the registration performed by kcdb_credtype_register(). + + This should only be done when the credentials provider is being + unloaded. + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_unregister(khm_int32 id); + +/*! \brief Retrieve the name of a credentials type + + Given a credentials type identifier, retrieves the name. The name + is not localized and serves as a persistent identifier of the + credentials type. + + \param[out] buf The buffer to receive the name. Could be \a NULL + if only the length of the buffer is required. + + \param[in,out] cbbuf On entry, specifies the size of the buffer + pointed to by \a buf if \a buf is not NULL. On exit, contains + the number of bytes copied to \a buf or the required size of + the buffer. + + \retval KHM_ERROR_SUCCESS The call succeeded. + + \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied + buffer was not large enough. The required size is in \a cbbuf. + + \retval KHM_ERROR_INVALID_PARAM Invalid parameter. + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_get_name(khm_int32 id, + wchar_t * buf, + khm_size * cbbuf); + +/*! \brief Retrieve the type specific subscription for a type + + Given a credentials type, this function returns the credentials + type specific subcription. It may return NULL if the subscription + is not available. + */ +KHMEXP khm_handle KHMAPI +kcdb_credtype_get_sub(khm_int32 id); + +/*! \brief Get the description of a credentials type + + Unlike the name of a credential type, the description is localized. + + \param[in] id Credentials type identifier + + \param[out] buf Receives the description. Can bet set to NULL if + only the size of the buffer is required. + + \param[in,out] cbbuf On entry, specifies the size of the buffer + pointed to by \a buf. On exit, specifies the required size of + the buffer or the number of bytes copied, depending on whether + the call succeeded or not. + + \param[in] flags Specify ::KCDB_TS_SHORT if the short version of + the description is desired if there is more than one. + + \retval KHM_ERROR_SUCCESS The call succeeded + \retval KHM_ERROR_TOO_LONG Either \a buf was NULL or the supplied buffer was insufficient. The required size is specified in \a cbbuf. + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_describe(khm_int32 id, + wchar_t * buf, + khm_size * cbbuf, + khm_int32 flags); + +/*! \brief Look up the identifier of a credentials type by name + + Given a name, looks up the identifier. + + \param[in] name Name of the credentials type + \param[out] id Receives the identifier if the call succeeds + + */ +KHMEXP khm_int32 KHMAPI +kcdb_credtype_get_id(wchar_t * name, + khm_int32 * id); + +/*@}*/ + +/*********************************************************************/ + +/*! \defgroup kcdb_buf Generic access to buffer + + Currently, credentials and identities both hold record data types. + This set of API's allow an application to access fields in the + records using a single interface. Note that credentials only + accept regular attributes while identities can hold both + attributes and properties. + + Handles to credentials and identities are implicitly also handles + to records. Thus they can be directly used as such. +*/ +/*@{*/ + +/*! \brief Get an attribute from a record by attribute id. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \param[out] attr_type Receives the data type of the attribute. + Set this to NULL if the type is not required. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this record then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_get_attr(khm_handle record, + khm_int32 attr_id, + khm_int32 * attr_type, + void * buffer, + khm_size * pcb_buf); + +/*! \brief Get an attribute from a record by name. + + \param[in] buffer The buffer that is to receive the attribute + value. Set this to NULL if only the required buffer size is + to be returned. + + \param[in,out] cbbuf The number of bytes available in \a buffer. + If \a buffer is not sufficient, returns KHM_ERROR_TOO_LONG and + sets this to the required buffer size. + + \note Set both \a buffer and \a cbbuf to NULL if only the + existence of the attribute is to be checked. If the attribute + exists in this record then the function will return + KHM_ERROR_SUCCESS, otherwise it returns KHM_ERROR_NOT_FOUND. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_get_attrib(khm_handle record, + wchar_t * attr_name, + khm_int32 * attr_type, + void * buffer, + khm_size * pcb_buf); + +/*! \brief Get the string representation of a record attribute. + + A shortcut function which generates the string representation of a + record attribute directly. + + \param[in] record A handle to a record + + \param[in] attr_id The attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \retval KHM_ERROR_SUCCESS Success + \retval KHM_ERROR_NOT_FOUND The given attribute was either invalid + or was not defined for this record + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG Either \a buffer was NULL or the + supplied buffer was insufficient +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_get_attr_string(khm_handle record, + khm_int32 attr_id, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Get the string representation of a record attribute by name. + + A shortcut function which generates the string representation of a + record attribute directly. + + \param[in] record A handle to a record + + \param[in] attrib The name of the attribute to retrieve + + \param[out] buffer A pointer to a string buffer which receives the + string form of the attribute. Set this to NULL if you only + want to determine the size of the required buffer. + + \param[in,out] pcbbuf A pointer to a #khm_int32 that, on entry, + holds the size of the buffer pointed to by \a buffer, and on + exit, receives the actual number of bytes that were copied. + + \param[in] flags Flags for the string conversion. Can be set to + one of KCDB_TS_LONG or KCDB_TS_SHORT. The default is + KCDB_TS_LONG. + + \see kcdb_cred_get_attr_string() +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_get_attrib_string(khm_handle record, + wchar_t * attr_name, + wchar_t * buffer, + khm_size * pcbbuf, + khm_int32 flags); + +/*! \brief Set an attribute in a record by attribute id + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the record. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_set_attr(khm_handle record, + khm_int32 attr_id, + void * buffer, + khm_size cbbuf); + +/*! \brief Set an attribute in a record by name + + \param[in] cbbuf Number of bytes of data in \a buffer. The + individual data type handlers may copy in less than this many + bytes in to the record. +*/ +KHMEXP khm_int32 KHMAPI +kcdb_buf_set_attrib(khm_handle record, + wchar_t * attr_name, + void * buffer, + khm_size cbbuf); + +KHMEXP khm_int32 KHMAPI +kcdb_buf_hold(khm_handle record); + +KHMEXP khm_int32 KHMAPI +kcdb_buf_release(khm_handle record); + +/*@}*/ + +/********************************************************************/ + +/* Notification operation constants */ + +#define KCDB_OP_INSERT 1 +#define KCDB_OP_DELETE 2 +#define KCDB_OP_MODIFY 3 +#define KCDB_OP_ACTIVATE 4 +#define KCDB_OP_DEACTIVATE 5 +#define KCDB_OP_HIDE 6 +#define KCDB_OP_UNHIDE 7 +#define KCDB_OP_SETSEARCH 8 +#define KCDB_OP_UNSETSEARCH 9 +#define KCDB_OP_NEW_DEFAULT 10 + +/*@}*/ + +#endif diff --git a/mechglue/src/windows/identity/kcreddb/kcreddbinternal.h b/mechglue/src/windows/identity/kcreddb/kcreddbinternal.h new file mode 100644 index 000000000..f7bf4e7bd --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/kcreddbinternal.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCREDDBINTERNAL_H__ +#define __KHIMAIRA_KCREDDBINTERNAL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "buf.h" +#include "identity.h" +#include "attrib.h" +#include "type.h" +#include "credential.h" +#include "credset.h" +#include "credtype.h" + +/* globals */ + +extern HINSTANCE hinst_kcreddb; + +kconf_schema schema_kcdbconfig[]; + +void kcdb_init(void); +void kcdb_exit(void); +khm_handle kcdb_get_config(void); + + +#endif diff --git a/mechglue/src/windows/identity/kcreddb/kcreddbmain.c b/mechglue/src/windows/identity/kcreddb/kcreddbmain.c new file mode 100644 index 000000000..8f8a01b06 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/kcreddbmain.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +HINSTANCE hinst_kcreddb; + +void +kcdb_process_attach(HINSTANCE hinstDLL) { + hinst_kcreddb = hinstDLL; + kcdb_init(); +} + +void +kcdb_process_detach(void) { + kcdb_exit(); +} diff --git a/mechglue/src/windows/identity/kcreddb/lang/en_us/kcredres.rc b/mechglue/src/windows/identity/kcreddb/lang/en_us/kcredres.rc new file mode 100644 index 000000000..4c221eeeb --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/lang/en_us/kcredres.rc @@ -0,0 +1,130 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\langres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_CREDDB "Khimaira Credentials Database" + IDS_NAME "Service Name" + IDS_IDENTITY "Identity" + IDS_ISSUED "Issued on" + IDS_EXPIRES "Expires on" + IDS_TIMELEFT "Time Remaining" + IDS_LOCATION "Location" + IDS_PARENT "Parent" + IDS_TYPE "Type" + IDS_IVL_EXPIRED "(Expired)" + IDS_IVL_D_H "%I64u days %I64u hours" +END + +STRINGTABLE +BEGIN + IDS_IVL_H_M "%I64u hours %I64u mins" + IDS_IVL_M_S "%I64u mins %I64u secs" + IDS_IVL_S "%I64u seconds" + IDS_IVL_UNKNOWN "(Unknown)" + IDS_LIFETIME "Lifetime" + IDS_IVL_1D "1 day" + IDS_IVL_1H "1 hour" + IDS_IVL_1M "1 minute" + IDS_IVL_1S "1 second" + IDS_IVL_D "%I64u days" + IDS_IVL_H "%I64u hours" + IDS_IVL_M "%I64u minutes" + IDS_IVL_S_SPEC "s,sec,second,seconds,secs" + IDS_IVL_M_SPEC "m,min,mins,minutes" + IDS_IVL_H_SPEC "h,hrs,hours" + IDS_IVL_D_SPEC "d,day,days,ds" +END + +STRINGTABLE +BEGIN + 128 "w,wk,wks,weeks" + IDS_FLAGS "Flags" + IDS_RENEW_TIMELEFT "Renewable Time left" + IDS_RENEW_EXPIRES "Renewable time expires" + IDS_RENEW_LIFETIME "Renewable lifetime" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/mechglue/src/windows/identity/kcreddb/langres.h b/mechglue/src/windows/identity/kcreddb/langres.h new file mode 100644 index 000000000..417b214e0 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/langres.h @@ -0,0 +1,48 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\kcreddb\lang\en_us\kcredres.rc +// +#define IDS_CREDDB 101 +#define IDS_NAME 102 +#define IDS_IDENTITY 103 +#define IDS_ISSUED 104 +#define IDS_EXPIRES 105 +#define IDS_TIMELEFT 106 +#define IDS_LOCATION 107 +#define IDS_PARENT 108 +#define IDS_TYPE 109 +#define IDS_IVL_EXPIRED 110 +#define IDS_IVL_D_H 111 +#define IDS_IVL_H_M 112 +#define IDS_IVL_M_S 113 +#define IDS_IVL_S 114 +#define IDS_IVL_UNKNOWN 115 +#define IDS_LIFETIME 116 +#define IDS_IVL_1D 117 +#define IDS_IVL_1H 118 +#define IDS_IVL_1M 119 +#define IDS_IVL_1S 120 +#define IDS_IVL_D 121 +#define IDS_IVL_H 122 +#define IDS_IVL_M 123 +#define IDS_IVL_S_SPEC 124 +#define IDS_IVL_M_SPEC 125 +#define IDS_IVL_H_SPEC 126 +#define IDS_IVL_D_SPEC 127 +#define IDS_IVl_W_SPEC 128 +#define IDS_IVL_W_SPEC 128 +#define IDS_FLAGS 129 +#define IDS_RENEW_TIMELEFT 130 +#define IDS_RENEW_EXPIRES 131 +#define IDS_RENEW_LIFETIME 132 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/mechglue/src/windows/identity/kcreddb/resource.h b/mechglue/src/windows/identity/kcreddb/resource.h new file mode 100644 index 000000000..dfb47e0d4 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by kcreddb.rc +// +#define IDS_PROJNAME 100 +#define IDR_WMDMLOGGER 101 +#define IDS_LOG_SEV_INFO 201 +#define IDS_LOG_SEV_WARN 202 +#define IDS_LOG_SEV_ERROR 203 +#define IDS_LOG_DATETIME 204 +#define IDS_LOG_SRCNAME 205 +#define IDS_DEF_LOGFILE 301 +#define IDS_DEF_MAXSIZE 302 +#define IDS_DEF_SHRINKTOSIZE 303 +#define IDS_DEF_LOGENABLED 304 +#define IDS_MUTEX_TIMEOUT 401 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/mechglue/src/windows/identity/kcreddb/type.c b/mechglue/src/windows/identity/kcreddb/type.c new file mode 100644 index 000000000..3df10482c --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/type.c @@ -0,0 +1,1363 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +CRITICAL_SECTION cs_type; +hashtable * kcdb_type_namemap; +kcdb_type_i ** kcdb_type_tbl; +kcdb_type_i * kcdb_types = NULL; + +/* Void */ + +#define GENERIC_VOID_STR L"(Void)" + +khm_int32 KHMAPI kcdb_type_void_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + cbsize = sizeof(GENERIC_VOID_STR); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cb_buf, GENERIC_VOID_STR); + + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_void_isValid( + const void * d, + khm_size cbd) +{ + /* void is always valid, even if d is NULL */ + return TRUE; +} + +khm_int32 KHMAPI kcdb_type_void_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + /* voids can not be compared */ + return 0; +} + +khm_int32 KHMAPI kcdb_type_void_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(!cbd_dst) + return KHM_ERROR_INVALID_PARAM; + + *cbd_dst = 0; + + /* copying a void doesn't do much */ + return KHM_ERROR_SUCCESS; +} + + +/* String */ +khm_int32 KHMAPI kcdb_type_string_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + wchar_t * sd; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + sd = (wchar_t *) d; + + if(FAILED(StringCbLength(sd, KCDB_TYPE_MAXCB, &cbsize))) + return KHM_ERROR_INVALID_PARAM; + + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cb_buf, sd); + + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_string_isValid( + const void * d, + khm_size cbd) +{ + size_t cbsize; + + if(cbd == KCDB_CBSIZE_AUTO) + cbd = KCDB_TYPE_MAXCB; + + if(FAILED(StringCbLength((wchar_t *) d, cbd, &cbsize))) + return FALSE; + else + return TRUE; +} + +khm_int32 KHMAPI kcdb_type_string_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + return wcscmp((const wchar_t *) d1, (const wchar_t *) d2); +} + +khm_int32 KHMAPI kcdb_type_string_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + size_t cbsize; + + if(!cbd_dst) + return KHM_ERROR_INVALID_PARAM; + + if(cbd_src == KCDB_CBSIZE_AUTO) { + cbd_src = KCDB_TYPE_MAXCB; + } + + if(FAILED(StringCbLength((const wchar_t *) d_src, cbd_src, &cbsize))) { + return KHM_ERROR_UNKNOWN; + } + + cbsize += sizeof(wchar_t); + + if(!d_dst || *cbd_dst < cbsize) { + *cbd_dst = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy((wchar_t *) d_dst, *cbd_dst, (const wchar_t *) d_src); + *cbd_dst = cbsize; + + return KHM_ERROR_SUCCESS; +} + +/* Date and time */ + + +khm_int32 KHMAPI kcdb_type_date_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + size_t cchsize; + wchar_t * bufend; + SYSTEMTIME st_now; + SYSTEMTIME st_d; + SYSTEMTIME st_dl; + FILETIME *ft; + int today = 0; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + ft = (FILETIME *) d; + + GetLocalTime(&st_now); + FileTimeToSystemTime(ft, &st_d); + SystemTimeToTzSpecificLocalTime(NULL, &st_d, &st_dl); + if(st_now.wYear == st_dl.wYear && + st_now.wMonth == st_dl.wMonth && + st_now.wDay == st_dl.wDay) + today = 1; + + if(today && (flags & KCDB_TS_SHORT)) { + cbsize = 0; + } else { + cbsize = GetDateFormat( + LOCALE_USER_DEFAULT, + DATE_SHORTDATE, + &st_dl, + NULL, + NULL, + 0) * sizeof(wchar_t); + cbsize += sizeof(wchar_t); + } + + cbsize += GetTimeFormat( + LOCALE_USER_DEFAULT, + 0, + &st_dl, + NULL, + NULL, + 0) * sizeof(wchar_t); + + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + cchsize = cbsize / sizeof(wchar_t); + + if(!today || !(flags & KCDB_TS_SHORT)) { + size_t cch_buf_len; + + GetDateFormat( + LOCALE_USER_DEFAULT, + DATE_SHORTDATE, + &st_dl, + NULL, + buffer, + (int) cchsize); + + StringCchCat(buffer, cchsize, L" "); + + StringCchLength(buffer, cchsize, &cch_buf_len); + + bufend = buffer + cch_buf_len; + cchsize -= cch_buf_len; + } else { + bufend = buffer; + } + + GetTimeFormat( + LOCALE_USER_DEFAULT, + 0, + &st_dl, + NULL, + bufend, + (int) cchsize); + + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_date_isValid( + const void * d, + khm_size cbd) +{ + return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(FILETIME))); +} + +khm_int32 KHMAPI kcdb_type_date_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + return (khm_int32) CompareFileTime((CONST FILETIME *) d1, (CONST FILETIME *) d2); +} + +khm_int32 KHMAPI kcdb_type_date_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(d_dst && *cbd_dst >= sizeof(FILETIME)) { + *cbd_dst = sizeof(FILETIME); + *((FILETIME *) d_dst) = *((FILETIME *) d_src); + return KHM_ERROR_SUCCESS; + } else { + *cbd_dst = sizeof(FILETIME); + return KHM_ERROR_TOO_LONG; + } +} + +/* Interval */ + +/* returns the number of milliseconds that must elapse away from the + interval specified in pft for the representation of pft to change + from whatever it is right now */ +KHMEXP long KHMAPI +FtIntervalMsToRepChange(LPFILETIME pft) +{ + __int64 ms,s,m,h,d; + __int64 ift; + long l; + + ift = FtToInt(pft); + ms = ift / 10000i64; + + if(ms < 0 || ift == _I64_MAX) + return -1; + + s = ms / 1000i64; + m = s / 60; + h = s / 3600; + d = s / (3600*24); + + if (d > 0) { + /* rep change at next hour change */ + l = (long) (ms % (3600*1000i64)); + } else if (h > 0) { + /* rep change at next minute change */ + l = (long) (ms % (60*1000i64)); + } else if (m > 5) { + /* rep change at next minute change */ + l = (long) (ms % (60*1000i64)); + } else { + /* rep change at next second change */ + l = (long) (ms % 1000); + } + + return l; +} + +KHMEXP khm_int32 KHMAPI +FtIntervalToString(LPFILETIME data, wchar_t * buffer, khm_size * cb_buf) +{ + size_t cbsize; + __int64 s,m,h,d; + __int64 ift; + wchar_t ibuf[256]; + wchar_t fbuf[256]; + wchar_t * t; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + ift = FtToInt(data); + s = ift / 10000000i64; + + m = s / 60; + h = s / 3600; + d = s / (3600*24); + + if(ift == _I64_MAX) { + LoadString(hinst_kcreddb, IDS_IVL_UNKNOWN, ibuf, sizeof(ibuf)/sizeof(wchar_t)); + } else if(s < 0) { + LoadString(hinst_kcreddb, IDS_IVL_EXPIRED, ibuf, sizeof(ibuf)/sizeof(wchar_t)); + } else if(d > 0) { + h = (s - (d * 3600 * 24)) / 3600; + if(d == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1D, ibuf, ARRAYLENGTH(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_D, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, d); + } + if(h > 0) { + StringCbCat(ibuf, sizeof(ibuf), L" "); + t = ibuf + wcslen(ibuf); + if(h == 1) + { + LoadString(hinst_kcreddb, IDS_IVL_1H, t, ARRAYLENGTH(ibuf) - wcslen(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, h); + } + } + } else if(h > 0 || m > 5) { + m = (s - (h * 3600)) / 60; + if(h == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1H, ibuf, ARRAYLENGTH(ibuf)); + } else if (h > 1) { + LoadString(hinst_kcreddb, IDS_IVL_H, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, h); + } else { + *ibuf = L'\0'; + } + + if(m > 0 || h == 0) { + if (h >= 1) + StringCbCat(ibuf, sizeof(ibuf), L" "); + + t = ibuf + wcslen(ibuf); + if(m == 1) + { + LoadString(hinst_kcreddb, IDS_IVL_1M, t, ARRAYLENGTH(ibuf) - wcslen(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, m); + } + } + } else if(m > 0) { + s -= m * 60; + if(m == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1M, ibuf, ARRAYLENGTH(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_M, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, m); + } + if(s > 0) { + StringCbCat(ibuf, sizeof(ibuf), L" "); + t = ibuf + wcslen(ibuf); + if(s == 1) + { + LoadString(hinst_kcreddb, IDS_IVL_1S, t, ARRAYLENGTH(ibuf) - wcslen(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(t, sizeof(ibuf) - wcslen(ibuf)*sizeof(wchar_t), fbuf, s); + } + } + } else { + if(s == 1) { + LoadString(hinst_kcreddb, IDS_IVL_1S, ibuf, ARRAYLENGTH(ibuf)); + } else { + LoadString(hinst_kcreddb, IDS_IVL_S, fbuf, sizeof(fbuf)/sizeof(wchar_t)); + StringCbPrintf(ibuf, sizeof(ibuf), fbuf, s); + } + } + + StringCbLength(ibuf, sizeof(ibuf), &cbsize); + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cb_buf, ibuf); + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_int32 KHMAPI +kcdb_type_interval_toString(const void * data, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + return FtIntervalToString((LPFILETIME) data, buffer, cb_buf); +} + +khm_boolean KHMAPI kcdb_type_interval_isValid( + const void * d, + khm_size cbd) +{ + return (d && (cbd == sizeof(FILETIME) || cbd == KCDB_CBSIZE_AUTO)); +} + +khm_int32 KHMAPI kcdb_type_interval_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + __int64 i1, i2; + + i1 = FtToInt((FILETIME *) d1); + i2 = FtToInt((FILETIME *) d2); + + if(i1 < i2) + return -1; + else if(i1 > i2) + return 1; + else + return 0; +} + +khm_int32 KHMAPI kcdb_type_interval_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(d_dst && *cbd_dst >= sizeof(FILETIME)) { + *cbd_dst = sizeof(FILETIME); + *((FILETIME *) d_dst) = *((FILETIME *) d_src); + return KHM_ERROR_SUCCESS; + } else { + *cbd_dst = sizeof(FILETIME); + return KHM_ERROR_TOO_LONG; + } +} + +/* Int32 */ + +khm_int32 KHMAPI kcdb_type_int32_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + wchar_t ibuf[12]; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + StringCbPrintf(ibuf, sizeof(ibuf), L"%d", *((khm_int32 *) d)); + StringCbLength(ibuf, sizeof(ibuf), &cbsize); + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf); + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_int32_isValid( + const void * d, + khm_size cbd) +{ + return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(khm_int32))); +} + +khm_int32 KHMAPI kcdb_type_int32_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + return *((khm_int32 *) d1) - *((khm_int32 *) d2); +} + +khm_int32 KHMAPI kcdb_type_int32_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(d_dst && (*cbd_dst >= sizeof(khm_int32))) { + *cbd_dst = sizeof(khm_int32); + *((khm_int32 *) d_dst) = *((khm_int32 *) d_src); + return KHM_ERROR_SUCCESS; + } else { + *cbd_dst = sizeof(khm_int32); + return KHM_ERROR_TOO_LONG; + } +} + +/* Int64 */ + +khm_int32 KHMAPI kcdb_type_int64_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + wchar_t ibuf[22]; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + StringCbPrintf(ibuf, sizeof(ibuf), L"%I64d", *((__int64 *) d)); + StringCbLength(ibuf, sizeof(ibuf), &cbsize); + cbsize += sizeof(wchar_t); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy((wchar_t *) buffer, *cb_buf, ibuf); + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_int64_isValid( + const void * d, + khm_size cbd) +{ + return (d && (cbd == KCDB_CBSIZE_AUTO || cbd == sizeof(__int64))); +} + +khm_int32 KHMAPI kcdb_type_int64_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + __int64 r = *((__int64 *) d1) - *((__int64 *) d2); + return (r==0i64)?0:((r>0i64)?1:-1); +} + +khm_int32 KHMAPI kcdb_type_int64_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(d_dst && (*cbd_dst >= sizeof(__int64))) { + *cbd_dst = sizeof(__int64); + *((__int64 *) d_dst) = *((__int64 *) d_src); + return KHM_ERROR_SUCCESS; + } else { + *cbd_dst = sizeof(__int64); + return KHM_ERROR_TOO_LONG; + } +} + +/* Data */ +#define GENERIC_DATA_STR L"(Data)" + +khm_int32 KHMAPI kcdb_type_data_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags) +{ + size_t cbsize; + + if(!cb_buf) + return KHM_ERROR_INVALID_PARAM; + + cbsize = sizeof(GENERIC_DATA_STR); + + if(!buffer || *cb_buf < cbsize) { + *cb_buf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cb_buf, GENERIC_DATA_STR); + + *cb_buf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +khm_boolean KHMAPI kcdb_type_data_isValid( + const void * d, + khm_size cbd) +{ + /* data is always valid, even if d is NULL */ + return TRUE; +} + +khm_int32 KHMAPI kcdb_type_data_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2) +{ + /* datas can not be compared */ + return 0; +} + +khm_int32 KHMAPI kcdb_type_data_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst) +{ + if(!cbd_dst) + return KHM_ERROR_INVALID_PARAM; + + *cbd_dst = cbd_src; + + if(!d_dst || *cbd_dst < cbd_src) { + return KHM_ERROR_TOO_LONG; + } else { + memcpy(d_dst, d_src, cbd_src); + return KHM_ERROR_SUCCESS; + } +} + + +void kcdb_type_msg_completion(kmq_message * m) +{ + kcdb_type_release((kcdb_type_i *) m->vparam); +} + +void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t) +{ + kcdb_type_hold(t); + kmq_post_message(KMSG_KCDB, KMSG_KCDB_TYPE, op, (void *) t); +} + +void kcdb_type_init(void) +{ + kcdb_type type; + + InitializeCriticalSection(&cs_type); + kcdb_type_namemap = hash_new_hashtable( + KCDB_TYPE_HASH_SIZE, + hash_string, + hash_string_comp, + kcdb_type_add_ref, + kcdb_type_del_ref); + kcdb_type_tbl = PMALLOC(sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1)); + ZeroMemory(kcdb_type_tbl, sizeof(kcdb_type_i *) * (KCDB_TYPE_MAX_ID + 1)); + kcdb_types = NULL; + + /*TODO: register standard data types */ + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_void_comp; + type.dup = kcdb_type_void_dup; + type.isValid = kcdb_type_void_isValid; + type.toString = kcdb_type_void_toString; + type.name = KCDB_TYPENAME_VOID; + type.id = KCDB_TYPE_VOID; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_string_comp; + type.dup = kcdb_type_string_dup; + type.isValid = kcdb_type_string_isValid; + type.toString = kcdb_type_string_toString; + type.name = KCDB_TYPENAME_STRING; + type.id = KCDB_TYPE_STRING; + type.flags = KCDB_TYPE_FLAG_CB_AUTO; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_date_comp; + type.dup = kcdb_type_date_dup; + type.isValid = kcdb_type_date_isValid; + type.toString = kcdb_type_date_toString; + type.name = KCDB_TYPENAME_DATE; + type.id = KCDB_TYPE_DATE; + type.cb_max = sizeof(FILETIME); + type.cb_min = sizeof(FILETIME); + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_interval_comp; + type.dup = kcdb_type_interval_dup; + type.isValid = kcdb_type_interval_isValid; + type.toString = kcdb_type_interval_toString; + type.name = KCDB_TYPENAME_INTERVAL; + type.id = KCDB_TYPE_INTERVAL; + type.cb_max = sizeof(FILETIME); + type.cb_min = sizeof(FILETIME); + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_int32_comp; + type.dup = kcdb_type_int32_dup; + type.isValid = kcdb_type_int32_isValid; + type.toString = kcdb_type_int32_toString; + type.name = KCDB_TYPENAME_INT32; + type.id = KCDB_TYPE_INT32; + type.cb_max = sizeof(khm_int32); + type.cb_min = sizeof(khm_int32); + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_int64_comp; + type.dup = kcdb_type_int64_dup; + type.isValid = kcdb_type_int64_isValid; + type.toString = kcdb_type_int64_toString; + type.name = KCDB_TYPENAME_INT64; + type.id = KCDB_TYPE_INT64; + type.cb_max = sizeof(__int64); + type.cb_min = sizeof(__int64); + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + + kcdb_type_register(&type, NULL); + + ZeroMemory(&type, sizeof(type)); + type.comp = kcdb_type_data_comp; + type.dup = kcdb_type_data_dup; + type.isValid = kcdb_type_data_isValid; + type.toString = kcdb_type_data_toString; + type.name = KCDB_TYPENAME_DATA; + type.id = KCDB_TYPE_DATA; + + kcdb_type_register(&type, NULL); +} + +void kcdb_type_add_ref(const void *key, void *vt) +{ + kcdb_type_hold((kcdb_type_i *) vt); +} + +void kcdb_type_del_ref(const void *key, void *vt) +{ + kcdb_type_release((kcdb_type_i *) vt); +} + +khm_int32 kcdb_type_hold(kcdb_type_i * t) +{ + if(!t) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_type); + t->refcount++; + LeaveCriticalSection(&cs_type); + + return KHM_ERROR_SUCCESS; +} + +khm_int32 kcdb_type_release(kcdb_type_i * t) +{ + if(!t) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_type); + t->refcount--; + kcdb_type_check_and_delete(t->type.id); + LeaveCriticalSection(&cs_type); + + return KHM_ERROR_SUCCESS; +} + +void kcdb_type_exit(void) +{ + EnterCriticalSection(&cs_type); + PFREE(kcdb_type_tbl); + /*TODO: free up the individual types */ + LeaveCriticalSection(&cs_type); + DeleteCriticalSection(&cs_type); +} + +void kcdb_type_check_and_delete(khm_int32 id) +{ + kcdb_type_i * t; + + if(id < 0 || id > KCDB_TYPE_MAX_ID) + return; + + EnterCriticalSection(&cs_type); + t = kcdb_type_tbl[id]; + if(t && !t->refcount) { + kcdb_type_tbl[id] = NULL; + LDELETE(&kcdb_types, t); + /* must already be out of the hash-table, otherwise refcount should not + be zero */ + PFREE(t->type.name); + PFREE(t); + } + LeaveCriticalSection(&cs_type); +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_id(wchar_t *name, khm_int32 * id) +{ + kcdb_type_i * t; + size_t cbsize; + + if(FAILED(StringCbLength(name, KCDB_MAXCB_NAME, &cbsize))) { + /* also fails of name is NULL */ + return KHM_ERROR_INVALID_PARAM; + } + + EnterCriticalSection(&cs_type); + t = hash_lookup(kcdb_type_namemap, (void*) name); + LeaveCriticalSection(&cs_type); + + if(!t) { + *id = KCDB_TYPE_INVALID; + return KHM_ERROR_NOT_FOUND; + } else { + *id = t->type.id; + return KHM_ERROR_SUCCESS; + } +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_info(khm_int32 id, kcdb_type ** info) +{ + kcdb_type_i * t; + + if(id < 0 || id > KCDB_TYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_type); + t = kcdb_type_tbl[id]; + + if (t) + kcdb_type_hold(t); + LeaveCriticalSection(&cs_type); + + if(info) + *info = (kcdb_type *) t; + else if (t) + kcdb_type_release(t); + + return (t)? KHM_ERROR_SUCCESS : KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI kcdb_type_release_info(kcdb_type * info) +{ + return kcdb_type_release((kcdb_type_i *) info); +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_name(khm_int32 id, wchar_t * buffer, khm_size * cbbuf) +{ + size_t cbsize; + kcdb_type_i * t; + + if(id < 0 || id > KCDB_TYPE_MAX_ID || !cbbuf) + return KHM_ERROR_INVALID_PARAM; + + t = kcdb_type_tbl[id]; + + if(!t) + return KHM_ERROR_NOT_FOUND; + + if(FAILED(StringCbLength(t->type.name, KCDB_MAXCB_NAME, &cbsize))) + return KHM_ERROR_UNKNOWN; + + cbsize += sizeof(wchar_t); + + if(!buffer || *cbbuf < cbsize) { + *cbbuf = cbsize; + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buffer, *cbbuf, t->type.name); + *cbbuf = cbsize; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_type_register(kcdb_type * type, khm_int32 * new_id) +{ + kcdb_type_i *t; + size_t cbsize; + khm_int32 type_id; + + if(!type || + !type->comp || + !type->dup || + !type->isValid || + !type->toString || + !type->name) + return KHM_ERROR_INVALID_PARAM; + + if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && + (type->cb_min < 0 || type->cb_min > KCDB_TYPE_MAXCB)) + { + return KHM_ERROR_INVALID_PARAM; + } + + if((type->flags & KCDB_TYPE_FLAG_CB_MAX) && + (type->cb_max < 0 || type->cb_max > KCDB_TYPE_MAXCB)) + { + return KHM_ERROR_INVALID_PARAM; + } + + if((type->flags & KCDB_TYPE_FLAG_CB_MIN) && + (type->flags & KCDB_TYPE_FLAG_CB_MAX) && + (type->cb_max < type->cb_min)) + { + return KHM_ERROR_INVALID_PARAM; + } + + if(FAILED(StringCbLength(type->name, KCDB_MAXCB_NAME, &cbsize))) + return KHM_ERROR_TOO_LONG; + + cbsize += sizeof(wchar_t); + + EnterCriticalSection(&cs_type); + if(type->id == KCDB_TYPE_INVALID) { + kcdb_type_get_next_free(&type_id); + } else if(type->id < 0 || type->id > KCDB_TYPE_MAX_ID) { + LeaveCriticalSection(&cs_type); + return KHM_ERROR_INVALID_PARAM; + } else if(kcdb_type_tbl[type->id]) { + LeaveCriticalSection(&cs_type); + return KHM_ERROR_DUPLICATE; + } else { + type_id = type->id; + } + + if(type_id == KCDB_TYPE_INVALID) { + LeaveCriticalSection(&cs_type); + return KHM_ERROR_NO_RESOURCES; + } + + t = PMALLOC(sizeof(kcdb_type_i)); + ZeroMemory(t, sizeof(kcdb_type_i)); + + t->type.name = PMALLOC(cbsize); + StringCbCopy(t->type.name, cbsize, type->name); + + t->type.comp = type->comp; + t->type.dup = type->dup; + t->type.flags = type->flags; + t->type.id = type_id; + t->type.isValid = type->isValid; + t->type.toString = type->toString; + + LINIT(t); + + kcdb_type_tbl[type_id] = t; + LPUSH(&kcdb_types, t); + + hash_add(kcdb_type_namemap, (void *) t->type.name, (void *) t); + + LeaveCriticalSection(&cs_type); + + if(new_id) + *new_id = type_id; + + kcdb_type_post_message(KCDB_OP_INSERT, t); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kcdb_type_unregister(khm_int32 id) +{ + kcdb_type_i * t; + + if(id < 0 || id > KCDB_TYPE_MAX_ID) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_type); + t = kcdb_type_tbl[id]; + if(t) { + kcdb_type_post_message(KCDB_OP_DELETE, t); + /* we are going to remove t from the hash table. If no one is holding + a reference to it, then we can free it (actually, the del_ref code + will take care of that anyway). If there is a hold, then it will + get freed when they release it. + + Actually, the post_message call above pretty much guarantees that + the type has a hold on it.*/ + t->type.flags |= KCDB_TYPE_FLAG_DELETED; + hash_del(kcdb_type_namemap, t->type.name); + } + LeaveCriticalSection(&cs_type); + + if(t) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI kcdb_type_get_next_free(khm_int32 * id) +{ + int i; + + if(!id) + return KHM_ERROR_INVALID_PARAM; + + /* do a linear search because this function only gets called a few times */ + EnterCriticalSection(&cs_type); + for(i=0; i <= KCDB_TYPE_MAX_ID; i++) { + if(!kcdb_type_tbl[i]) + break; + } + LeaveCriticalSection(&cs_type); + + if(i <= KCDB_TYPE_MAX_ID) { + *id = i; + return KHM_ERROR_SUCCESS; + } else { + *id = KCDB_TYPE_INVALID; + return KHM_ERROR_NO_RESOURCES; + } +} + +/* Conversion functions */ + +KHMEXP void KHMAPI TimetToFileTime( time_t t, LPFILETIME pft ) +{ + LONGLONG ll; + + if ( sizeof(time_t) == 4 ) + ll = Int32x32To64(t, 10000000) + 116444736000000000i64; + else { + ll = t * 10000000i64 + 116444736000000000i64; + } + pft->dwLowDateTime = (DWORD) ll; + pft->dwHighDateTime = (DWORD) (ll >> 32); +} + +KHMEXP void KHMAPI TimetToFileTimeInterval(time_t t, LPFILETIME pft) +{ + LONGLONG ll; + + if ( sizeof(time_t) == 4 ) + ll = Int32x32To64(t, 10000000); + else { + ll = t * 10000000i64; + } + pft->dwLowDateTime = (DWORD) ll; + pft->dwHighDateTime = (DWORD) (ll >> 32); +} + +KHMEXP long KHMAPI FtIntervalToSeconds(LPFILETIME pft) +{ + __int64 i = FtToInt(pft); + return (long) (i / 10000000i64); +} + +KHMEXP long KHMAPI FtIntervalToMilliseconds(LPFILETIME pft) +{ + __int64 i = FtToInt(pft); + return (long) (i / 10000i64); +} + +KHMEXP khm_int64 KHMAPI FtToInt(LPFILETIME pft) { + LARGE_INTEGER ll; + ll.LowPart = pft->dwLowDateTime; + ll.HighPart = pft->dwHighDateTime; + return ll.QuadPart; +} + +KHMEXP FILETIME KHMAPI IntToFt(khm_int64 i) { + LARGE_INTEGER ll; + FILETIME ft; + + ll.QuadPart = i; + ft.dwLowDateTime = ll.LowPart; + ft.dwHighDateTime = ll.HighPart; + + return ft; +} + +KHMEXP FILETIME KHMAPI FtSub(LPFILETIME ft1, LPFILETIME ft2) { + FILETIME d; + LARGE_INTEGER l1, l2; + + l1.LowPart = ft1->dwLowDateTime; + l1.HighPart = ft1->dwHighDateTime; + l2.LowPart = ft2->dwLowDateTime; + l2.HighPart = ft2->dwHighDateTime; + + l1.QuadPart -= l2.QuadPart; + + d.dwLowDateTime = l1.LowPart; + d.dwHighDateTime = l1.HighPart; + + return d; +} + +KHMEXP FILETIME KHMAPI FtAdd(LPFILETIME ft1, LPFILETIME ft2) { + FILETIME d; + LARGE_INTEGER l1, l2; + + l1.LowPart = ft1->dwLowDateTime; + l1.HighPart = ft1->dwHighDateTime; + l2.LowPart = ft2->dwLowDateTime; + l2.HighPart = ft2->dwHighDateTime; + + l1.QuadPart += l2.QuadPart; + + d.dwLowDateTime = l1.LowPart; + d.dwHighDateTime = l1.HighPart; + + return d; +} + +KHMEXP int KHMAPI AnsiStrToUnicode( wchar_t * wstr, size_t cbwstr, const char * astr) +{ + size_t nc; + + if(cbwstr == 0) + return 0; + + nc = strlen(astr); + if(nc == MultiByteToWideChar( + CP_ACP, + 0, + astr, + (int) nc, + wstr, + (int)(cbwstr / sizeof(wchar_t) - 1))) { + wstr[nc] = L'\0'; + } else { + wstr[0] = L'\0'; + nc = 0; + } + + return (int) nc; +} + +KHMEXP int KHMAPI UnicodeStrToAnsi( char * dest, size_t cbdest, const wchar_t * src) +{ + size_t nc; + + if(cbdest == 0) + return 0; + + dest[0] = 0; + + if(FAILED(StringCchLength(src, cbdest, &nc)) || nc*sizeof(char) >= cbdest) + // note that cbdest counts the terminating NULL, while nc doesn't + return 0; + + nc = WideCharToMultiByte( + CP_ACP, + WC_NO_BEST_FIT_CHARS, + src, + (int) nc, + dest, + (int) cbdest, + NULL, + NULL); + + dest[nc] = 0; + + return (int) nc; +} + +#define MAX_IVL_SPECLIST_LEN 256 +#define MAX_IVL_UNITS 5 + +enum _ivl_indices { + IVL_SECONDS = 0, + IVL_MINUTES, + IVL_HOURS, + IVL_DAYS, + IVL_WEEKS +}; + +typedef struct ivspec_t { + wchar_t str[MAX_IVL_SPECLIST_LEN]; + __int64 mul; +} ivspec; + +static ivspec ivspecs[MAX_IVL_UNITS]; +static BOOL ivspecs_loaded = FALSE; + +int _iv_is_in_spec(wchar_t *s, int n, wchar_t * spec) +{ + /* spec strigns are comma separated */ + wchar_t *b, *e; + + b = spec; + while(*b) { + e = wcschr(b, L','); + if(!e) + e = b + wcslen(b); + + if((e - b) == n && !wcsnicmp(b, s, n)) { + return TRUE; + } + + if(*e) + b = e+1; + else + break; + } + + return FALSE; +} + +KHMEXP khm_int32 KHMAPI IntervalStringToFt(FILETIME * pft, wchar_t * str) +{ + size_t cb; + wchar_t * b; + __int64 t; + + *pft = IntToFt(0); + + /* ideally we should synchronize this, but it doesn't hurt if two + threads do this at the same time, because we only set the ivspecs_loaded + flag when we are done */ + if(!ivspecs_loaded) { + LoadString(hinst_kcreddb, IDS_IVL_S_SPEC, ivspecs[IVL_SECONDS].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_SECONDS].mul = 10000000i64; + LoadString(hinst_kcreddb, IDS_IVL_M_SPEC, ivspecs[IVL_MINUTES].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_MINUTES].mul = ivspecs[IVL_SECONDS].mul * 60; + LoadString(hinst_kcreddb, IDS_IVL_H_SPEC, ivspecs[2].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_HOURS].mul = ivspecs[IVL_MINUTES].mul * 60; + LoadString(hinst_kcreddb, IDS_IVL_D_SPEC, ivspecs[3].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_DAYS].mul = ivspecs[IVL_HOURS].mul * 24; + LoadString(hinst_kcreddb, IDS_IVL_W_SPEC, ivspecs[4].str, MAX_IVL_SPECLIST_LEN); + ivspecs[IVL_WEEKS].mul = ivspecs[IVL_DAYS].mul * 7; + + ivspecs_loaded = TRUE; + } + + if(!str || FAILED(StringCbLength(str, MAX_IVL_SPECLIST_LEN, &cb))) + return KHM_ERROR_INVALID_PARAM; + + b = str; + t = 0; + while(*b) { + __int64 f = 1; + wchar_t *e; + int i; + + while(*b && iswspace(*b)) + b++; + + if(*b && iswdigit(*b)) { + f = _wtoi64(b); + + while(*b && iswdigit(*b)) + b++; + } + + while(*b && iswspace(*b)) + b++; + + if(!*b) /* no unit specified */ + return KHM_ERROR_INVALID_PARAM; + + e = b; + + while(*e && !iswspace(*e)) + e++; + + for(i=0; i < MAX_IVL_UNITS; i++) { + if(_iv_is_in_spec(b, (int)(e-b), ivspecs[i].str)) + break; + } + + if(i==MAX_IVL_UNITS) + return KHM_ERROR_INVALID_PARAM; + + t += f * ivspecs[i].mul; + + b = e; + } + + *pft = IntToFt(t); + + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/kcreddb/type.h b/mechglue/src/windows/identity/kcreddb/type.h new file mode 100644 index 000000000..f7ef26ac4 --- /dev/null +++ b/mechglue/src/windows/identity/kcreddb/type.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KCDB_TYPE_H +#define __KHIMAIRA_KCDB_TYPE_H + +/* Types */ + +typedef struct kcdb_type_i_t { + kcdb_type type; + + khm_int32 refcount; + + struct kcdb_type_i_t * next; + struct kcdb_type_i_t * prev; +} kcdb_type_i; + +#define KCDB_TYPE_HASH_SIZE 31 + +#define KCDB_TYPE_FLAG_DELETED 8 + +void kcdb_type_init(void); +void kcdb_type_exit(void); +void kcdb_type_add_ref(const void *key, void *vt); +void kcdb_type_del_ref(const void *key, void *vt); +void kcdb_type_msg_completion(kmq_message * m); +khm_int32 kcdb_type_hold(kcdb_type_i * t); +khm_int32 kcdb_type_release(kcdb_type_i * t); +void kcdb_type_check_and_delete(khm_int32 id); +void kcdb_type_post_message(khm_int32 op, kcdb_type_i * t); + +khm_int32 KHMAPI kcdb_type_void_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_void_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_void_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_void_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_string_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_string_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_string_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_string_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_date_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_date_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_date_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_date_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_interval_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_interval_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_interval_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_interval_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_int32_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_int32_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_int32_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_int32_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_int64_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_int64_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_int64_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_int64_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +khm_int32 KHMAPI kcdb_type_data_toString( + const void * d, + khm_size cbd, + wchar_t * buffer, + khm_size * cb_buf, + khm_int32 flags); + +khm_boolean KHMAPI kcdb_type_data_isValid( + const void * d, + khm_size cbd); + +khm_int32 KHMAPI kcdb_type_data_comp( + const void * d1, + khm_size cbd1, + const void * d2, + khm_size cbd2); + +khm_int32 KHMAPI kcdb_type_data_dup( + const void * d_src, + khm_size cbd_src, + void * d_dst, + khm_size * cbd_dst); + +#endif diff --git a/mechglue/src/windows/identity/kherr/Makefile b/mechglue/src/windows/identity/kherr/Makefile new file mode 100644 index 000000000..84f9da5ba --- /dev/null +++ b/mechglue/src/windows/identity/kherr/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=kherr +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\kherr.h + +OBJFILES= \ + $(OBJ)\kherrmain.obj \ + $(OBJ)\kherr.obj + +LIBFILES= + +SDKLIBFILES= \ + strsafe.lib + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/mechglue/src/windows/identity/kherr/kherr.c b/mechglue/src/windows/identity/kherr/kherr.c new file mode 100644 index 000000000..d8b145d24 --- /dev/null +++ b/mechglue/src/windows/identity/kherr/kherr.c @@ -0,0 +1,1246 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include + +CRITICAL_SECTION cs_error; +DWORD tls_error = 0; +kherr_context * ctx_free_list = NULL; +kherr_context * ctx_root_list = NULL; +kherr_context * ctx_error_list = NULL; +kherr_event * evt_free_list = NULL; + +kherr_handler_node * ctx_handlers = NULL; +khm_size n_ctx_handlers; +khm_size nc_ctx_handlers; + +kherr_serial ctx_serial = 0; + +#ifdef DEBUG +#define DEBUG_CONTEXT + +KHMEXP void kherr_debug_printf(wchar_t * fmt, ...) { + va_list vl; + wchar_t buf[1024]; + + va_start(vl, fmt); + StringCbVPrintf(buf, sizeof(buf), fmt, vl); + OutputDebugString(buf); + va_end(vl); +} +#endif + +KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h, + khm_int32 filter, + kherr_serial serial) { + + assert(h); + + EnterCriticalSection(&cs_error); + if( ctx_handlers == NULL) { + nc_ctx_handlers = CTX_ALLOC_INCR; + n_ctx_handlers = 0; + ctx_handlers = PMALLOC(sizeof(*ctx_handlers) * nc_ctx_handlers); + /* No need to initialize */ + } else if (n_ctx_handlers == nc_ctx_handlers) { + khm_size new_nc; + kherr_handler_node * new_ctxs; + + new_nc = nc_ctx_handlers + CTX_ALLOC_INCR; + new_ctxs = PMALLOC(sizeof(*new_ctxs) * new_nc); + memcpy(new_ctxs, ctx_handlers, n_ctx_handlers * sizeof(*new_ctxs)); + + PFREE(ctx_handlers); + ctx_handlers = new_ctxs; + nc_ctx_handlers = new_nc; + } + + if (filter == 0) + filter = KHERR_CTX_BEGIN | + KHERR_CTX_DESCRIBE | + KHERR_CTX_END | + KHERR_CTX_ERROR; + + ctx_handlers[n_ctx_handlers].h = h; + ctx_handlers[n_ctx_handlers].filter = filter; + ctx_handlers[n_ctx_handlers].serial = serial; + + n_ctx_handlers++; + + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h, + kherr_serial serial) { + khm_size i; + EnterCriticalSection(&cs_error); + + for (i=0 ; i < n_ctx_handlers; i++) { + if (ctx_handlers[i].h == h && + ctx_handlers[i].serial == serial) { + break; + } + } + + if ( i < n_ctx_handlers ) { + n_ctx_handlers --; + for (; i < n_ctx_handlers; i++) { + ctx_handlers[i] = ctx_handlers[i + 1]; + } + } + + LeaveCriticalSection(&cs_error); +} + +/* Called with cs_error held */ +void notify_ctx_event(enum kherr_ctx_event e, kherr_context * c) { + khm_size i; + + kherr_ctx_handler h; + + for (i=0; iserial)) { + if (IsBadCodePtr((FARPROC) ctx_handlers[i].h)) { + ctx_handlers[i].h = NULL; + } else { + h = ctx_handlers[i].h; + (*h)(e,c); + + /* a context handler is allowed to remove itself + during a callback. It is, however, not allowed to + remove anything else. */ + if (h != ctx_handlers[i].h) + i--; + } + } + } +} + +void attach_this_thread(void) { + kherr_thread * t; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (t) + return; + + t = PMALLOC(sizeof(kherr_thread) + + sizeof(kherr_context *) * THREAD_STACK_SIZE); + t->nc_ctx = THREAD_STACK_SIZE; + t->n_ctx = 0; + t->ctx = (kherr_context **) &t[1]; + + TlsSetValue(tls_error, t); +} + +void detach_this_thread(void) { + kherr_thread * t; + khm_size i; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (t) { + for(i=0; i < t->n_ctx; i++) { + kherr_release_context(t->ctx[i]); + } + PFREE(t); + TlsSetValue(tls_error, 0); + } +} + +kherr_context * peek_context(void) { + kherr_thread * t; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (t) { + if (t->n_ctx > 0) + return t->ctx[t->n_ctx - 1]; + else + return NULL; + } else + return NULL; +} + +void push_context(kherr_context * c) { + kherr_thread * t; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (!t) { + attach_this_thread(); + t = (kherr_thread *) TlsGetValue(tls_error); + assert(t); + } + + if (t->n_ctx == t->nc_ctx) { + khm_size nc_new; + khm_size cb_new; + kherr_thread * nt; + + nc_new = t->nc_ctx + THREAD_STACK_SIZE; + cb_new = sizeof(kherr_thread) + + sizeof(kherr_context *) * nc_new; + + nt = PMALLOC(cb_new); + memcpy(nt, t, sizeof(kherr_thread) + + sizeof(kherr_context *) * t->n_ctx); + nt->ctx = (kherr_context **) &nt[1]; + nt->nc_ctx = nc_new; + + PFREE(t); + t = nt; + TlsSetValue(tls_error, t); + } + + assert(t->n_ctx < t->nc_ctx); + t->ctx[t->n_ctx++] = c; + + kherr_hold_context(c); +} + +/* returned pointer is still held */ +kherr_context * pop_context(void) { + kherr_thread * t; + kherr_context * c; + + t = (kherr_thread *) TlsGetValue(tls_error); + if (t) { + if (t->n_ctx > 0) { + c = t->ctx[--(t->n_ctx)]; + return c; + } else + return NULL; + } else { + return NULL; + } +} + +kherr_event * get_empty_event(void) { + kherr_event * e; + + EnterCriticalSection(&cs_error); + if(evt_free_list) { + LPOP(&evt_free_list, &e); + } else { + e = PMALLOC(sizeof(*e)); + } + LeaveCriticalSection(&cs_error); + ZeroMemory(e, sizeof(*e)); + e->severity = KHERR_NONE; + e->magic = KHERR_EVENT_MAGIC; + + return e; +} + +void free_event_params(kherr_event * e) { + if(parm_type(e->p1) == KEPT_STRINGT) { + assert((void *) parm_data(e->p1)); + PFREE((void*) parm_data(e->p1)); + e->p1 = (kherr_param) 0; + } + if(parm_type(e->p2) == KEPT_STRINGT) { + assert((void *) parm_data(e->p2)); + PFREE((void*) parm_data(e->p2)); + e->p2 = (kherr_param) 0; + } + if(parm_type(e->p3) == KEPT_STRINGT) { + assert((void *) parm_data(e->p3)); + PFREE((void*) parm_data(e->p3)); + e->p3 = (kherr_param) 0; + } + if(parm_type(e->p4) == KEPT_STRINGT) { + assert((void *) parm_data(e->p4)); + PFREE((void*) parm_data(e->p4)); + e->p4 = (kherr_param) 0; + } +} + +void free_event(kherr_event * e) { + + EnterCriticalSection(&cs_error); + + assert(e->magic == KHERR_EVENT_MAGIC); + +#ifdef DEBUG_CONTEXT + kherr_debug_printf(L"Freeing event 0x%x\n", e); + if (!(e->flags & KHERR_RF_STR_RESOLVED)) + resolve_event_strings(e); + if (e->short_desc) + kherr_debug_printf(L" Desc(S):[%s]\n", e->short_desc); + if (e->long_desc) + kherr_debug_printf(L" Desc(L):[%s]\n", e->long_desc); + if (e->suggestion) + kherr_debug_printf(L" Suggest:[%s]\n", e->suggestion); + if (e->facility) + kherr_debug_printf(L" Facility:[%s]\n", e->facility); +#endif + + if(e->flags & KHERR_RF_FREE_SHORT_DESC) { + assert(e->short_desc); + PFREE((void *) e->short_desc); + } + if(e->flags & KHERR_RF_FREE_LONG_DESC) { + assert(e->long_desc); + PFREE((void *) e->long_desc); + } + if(e->flags & KHERR_RF_FREE_SUGGEST) { + assert(e->suggestion); + PFREE((void *) e->suggestion); + } + + free_event_params(e); + + ZeroMemory(e, sizeof(e)); + + LPUSH(&evt_free_list, e); + LeaveCriticalSection(&cs_error); +} + +kherr_context * get_empty_context(void) { + kherr_context * c; + + EnterCriticalSection(&cs_error); + if(ctx_free_list) + LPOP(&ctx_free_list, &c); + else { + c = PMALLOC(sizeof(kherr_context)); + } + + ZeroMemory(c,sizeof(*c)); + c->severity = KHERR_NONE; + c->flags = KHERR_CF_UNBOUND; + c->magic = KHERR_CONTEXT_MAGIC; + c->serial = ++ctx_serial; + + LPUSH(&ctx_root_list, c); + + LeaveCriticalSection(&cs_error); + + return c; +} + + +/* Assumes that the context has been deleted from all relevant + lists */ +void free_context(kherr_context * c) { + kherr_context * ch; + kherr_event * e; + + assert(c->magic == KHERR_CONTEXT_MAGIC); +#ifdef DEBUG_CONTEXT + kherr_debug_printf(L"Freeing context 0x%x\n", c); +#endif + + EnterCriticalSection(&cs_error); + + if (c->desc_event) + free_event(c->desc_event); + c->desc_event = NULL; + + TPOPCHILD(c, &ch); + while(ch) { + free_context(ch); + TPOPCHILD(c, &ch); + } + QGET(c, &e); + while(e) { + free_event(e); + QGET(c, &e); + } + + c->serial = 0; + + LPUSH(&ctx_free_list,c); + LeaveCriticalSection(&cs_error); + +#ifdef DEBUG_CONTEXT + kherr_debug_printf(L"Done with context 0x%x\n", c); +#endif +} + +void add_event(kherr_context * c, kherr_event * e) +{ + EnterCriticalSection(&cs_error); + QPUT(c,e); + if(c->severity >= e->severity) { + if (e->severity <= KHERR_ERROR) + notify_ctx_event(KHERR_CTX_ERROR, c); + + c->severity = e->severity; + c->err_event = e; + c->flags &= ~KHERR_CF_DIRTY; + } + LeaveCriticalSection(&cs_error); +} + +void pick_err_event(kherr_context * c) +{ + kherr_event * e; + kherr_event * ce = NULL; + enum kherr_severity s; + + s = KHERR_RESERVED_BANK; + + EnterCriticalSection(&cs_error); + e = QTOP(c); + while(e) { + if(!(e->flags & KHERR_RF_INERT) && + s >= e->severity) { + ce = e; + s = e->severity; + } + e = QNEXT(e); + } + + if(ce) { + c->err_event = ce; + c->severity = ce->severity; + } else { + c->err_event = NULL; + c->severity = KHERR_NONE; + } + + c->flags &= ~KHERR_CF_DIRTY; + LeaveCriticalSection(&cs_error); +} + +static void arg_from_param(DWORD_PTR ** parm, kherr_param p) { + int t; + + if (p != 0) { + t = parm_type(p); + if (t == KEPT_INT32 || + t == KEPT_UINT32 || + t == KEPT_STRINGC || + t == KEPT_STRINGT) { + + *(*parm)++ = (DWORD_PTR) parm_data(p); + + } else if (t == KEPT_INT64 || + t == KEPT_UINT64) { + *(*parm)++ = (DWORD_PTR) parm_data(p) & 0xffffffff; + *(*parm)++ = (DWORD_PTR) (parm_data(p) >> 32) & 0xffffffff; + } else + *(*parm)++ = 0; + } +} + +/* The 'buf' parameter MUST point to a DWORD_PTR[8] array */ +static void args_from_event(DWORD_PTR * buf, kherr_event * e) { + arg_from_param(&buf, e->p1); + arg_from_param(&buf, e->p2); + arg_from_param(&buf, e->p3); + arg_from_param(&buf, e->p4); +} + +static void resolve_string_resource(kherr_event * e, + const wchar_t ** str, + khm_int32 if_flag, + khm_int32 or_flag) { + wchar_t tfmt[KHERR_MAXCCH_STRING]; + wchar_t tbuf[KHERR_MAXCCH_STRING]; + size_t chars; + size_t bytes; + + if(e->flags & if_flag) { + if(e->h_module != NULL) + chars = LoadString(e->h_module, (UINT)(INT_PTR) *str, + tfmt, ARRAYLENGTH(tbuf)); + if(e->h_module == NULL || chars == 0) + *str = NULL; + else { + wchar_t * s; + DWORD_PTR args[8]; + + args_from_event(args, e); + + chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING | + FORMAT_MESSAGE_ARGUMENT_ARRAY, + tfmt, + 0, + 0, + tbuf, + ARRAYLENGTH(tbuf), + (va_list *) args); + + if (chars == 0) { + *str = NULL; + } else { + bytes = (chars + 1) * sizeof(wchar_t); + s = PMALLOC(bytes); + assert(s); + StringCbCopy(s, bytes, tbuf); + *str = s; + e->flags |= or_flag; + } + } + e->flags &= ~if_flag; + } +} + +static void resolve_msg_resource(kherr_event * e, + const wchar_t ** str, + khm_int32 if_flag, + khm_int32 or_flag) { + wchar_t tbuf[KHERR_MAXCCH_STRING]; + size_t chars; + size_t bytes; + DWORD_PTR args[8]; + + if(e->flags & if_flag) { + if(e->h_module != NULL) { + args_from_event(args, e); + + chars = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_ARGUMENT_ARRAY, + (LPCVOID) e->h_module, + (DWORD)(DWORD_PTR) *str, + 0, + tbuf, + ARRAYLENGTH(tbuf), + (va_list *) args); + } + + if(e->h_module == NULL || chars == 0) { + *str = NULL; + } else { + wchar_t * s; + + /* MC inserts trailing \r\n to each message unless the + message is terminated with a %0. We remove the last + line break since it is irrelevant to our handling of + the string in the UI. */ + if (tbuf[chars-1] == L'\n') + tbuf[--chars] = L'\0'; + if (tbuf[chars-1] == L'\r') + tbuf[--chars] = L'\0'; + + bytes = (chars + 1) * sizeof(wchar_t); + s = PMALLOC(bytes); + assert(s); + StringCbCopy(s, bytes, tbuf); + *str = s; + e->flags |= or_flag; + } + e->flags &= ~if_flag; + } +} + +static void resolve_string(kherr_event * e, + const wchar_t ** str, + khm_int32 mask, + khm_int32 free_if, + khm_int32 or_flag) { + + wchar_t tbuf[KHERR_MAXCCH_STRING]; + size_t chars; + size_t bytes; + DWORD_PTR args[8]; + + if (((e->flags & mask) == 0 || + (e->flags & mask) == free_if) && + *str != NULL) { + + args_from_event(args, e); + chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING | + FORMAT_MESSAGE_ARGUMENT_ARRAY, + (LPCVOID) *str, + 0, + 0, + tbuf, + ARRAYLENGTH(tbuf), + (va_list *) args); + + if ((e->flags & mask) == free_if) { + PFREE((void *) *str); + } + + e->flags &= ~mask; + + if (chars == 0) { + *str = 0; + } else { + wchar_t * s; + + bytes = (chars + 1) * sizeof(wchar_t); + s = PMALLOC(bytes); + assert(s); + StringCbCopy(s, bytes, tbuf); + *str = s; + e->flags |= or_flag; + } + } + +} + +void resolve_event_strings(kherr_event * e) +{ + resolve_string(e, &e->short_desc, + KHERR_RFMASK_SHORT_DESC, + KHERR_RF_FREE_SHORT_DESC, + KHERR_RF_FREE_SHORT_DESC); + + resolve_string(e, &e->long_desc, + KHERR_RFMASK_LONG_DESC, + KHERR_RF_FREE_LONG_DESC, + KHERR_RF_FREE_LONG_DESC); + + resolve_string(e, &e->suggestion, + KHERR_RFMASK_SUGGEST, + KHERR_RF_FREE_SUGGEST, + KHERR_RF_FREE_SUGGEST); + + resolve_string_resource(e, &e->short_desc, + KHERR_RF_RES_SHORT_DESC, + KHERR_RF_FREE_SHORT_DESC); + + resolve_string_resource(e, &e->long_desc, + KHERR_RF_RES_LONG_DESC, + KHERR_RF_FREE_LONG_DESC); + + resolve_string_resource(e, &e->suggestion, + KHERR_RF_RES_SUGGEST, + KHERR_RF_FREE_SUGGEST); + + resolve_msg_resource(e, &e->short_desc, + KHERR_RF_MSG_SHORT_DESC, + KHERR_RF_FREE_SHORT_DESC); + resolve_msg_resource(e, &e->long_desc, + KHERR_RF_MSG_LONG_DESC, + KHERR_RF_FREE_LONG_DESC); + resolve_msg_resource(e, &e->suggestion, + KHERR_RF_MSG_SUGGEST, + KHERR_RF_FREE_SUGGEST); + + /* get rid of dangling reference now that we have done everything + we can with it. Since we have already dealt with all the + parameter inserts, we don't need the parameters anymore + either. */ + free_event_params(e); + + e->h_module = NULL; + e->flags |= KHERR_RF_STR_RESOLVED; +} + + +KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e) { + EnterCriticalSection(&cs_error); + resolve_event_strings(e); + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_evaluate_last_event(void) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + if(!c) + return; + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e) + goto _exit; + + resolve_event_strings(e); + +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP kherr_event * __cdecl +kherr_reportf(const wchar_t * long_desc_fmt, ...) { + va_list vl; + wchar_t buf[1024]; + kherr_event * e; + + va_start(vl, long_desc_fmt); + StringCbVPrintf(buf, sizeof(buf), long_desc_fmt, vl); +#ifdef DEBUG + OutputDebugString(buf); +#endif + va_end(vl); + + e = kherr_report(KHERR_DEBUG_1, + NULL, NULL, NULL, buf, NULL, 0, + KHERR_SUGGEST_NONE, 0, 0, 0, 0, KHERR_RF_CSTR_LONG_DESC +#ifdef _WIN32 + ,NULL +#endif + ); + if (e) { + kherr_evaluate_event(e); + } + + return e; +} + +KHMEXP kherr_event * __cdecl +kherr_reportf_ex(enum kherr_severity severity, + const wchar_t * facility, + khm_int32 facility_id, +#ifdef _WIN32 + HMODULE hModule, +#endif + const wchar_t * long_desc_fmt, ...) { + va_list vl; + wchar_t buf[1024]; + kherr_event * e; + + va_start(vl, long_desc_fmt); + StringCbVPrintf(buf, sizeof(buf), long_desc_fmt, vl); +#ifdef DEBUG + OutputDebugString(buf); +#endif + va_end(vl); + + e = kherr_report(severity, NULL, facility, NULL, buf, NULL, facility_id, + KHERR_SUGGEST_NONE, 0, 0, 0, 0, KHERR_RF_CSTR_LONG_DESC +#ifdef _WIN32 + ,hModule +#endif + ); + if (e) { + kherr_evaluate_event(e); + } + + return e; +} + +KHMEXP kherr_event * KHMAPI +kherr_report(enum kherr_severity severity, + const wchar_t * short_desc, + const wchar_t * facility, + const wchar_t * location, + const wchar_t * long_desc, + const wchar_t * suggestion, + khm_int32 facility_id, + enum kherr_suggestion suggestion_id, + kherr_param p1, + kherr_param p2, + kherr_param p3, + kherr_param p4, + khm_int32 flags +#ifdef _WIN32 + ,HMODULE h_module +#endif + ) { + kherr_context * c; + kherr_event * e; + + /*TODO: sanity check flags (ISPOW2) */ + + e = get_empty_event(); + + e->thread_id = GetCurrentThreadId(); + e->time_ticks = GetTickCount(); + GetSystemTimeAsFileTime(&e->time_ft); + + e->severity = severity; + e->short_desc = short_desc; + e->facility = facility; + e->location = location; + e->long_desc = long_desc; + e->suggestion = suggestion; + e->facility_id = facility_id; + e->suggestion_id = suggestion_id; + e->p1 = p1; + e->p2 = p2; + e->p3 = p3; + e->p4 = p4; + e->flags = flags; +#ifdef _WIN32 + e->h_module = h_module; +#endif + + EnterCriticalSection(&cs_error); + c = peek_context(); + + if(!c) { + /* the reason why we are doing it this way is because p1..p4, + the descriptions and the suggestion may contain allocations + that has to be freed. */ + free_event(e); + e = NULL; + } else { + add_event(c,e); + } + + LeaveCriticalSection(&cs_error); + + return e; +} + +KHMEXP void KHMAPI kherr_suggest(wchar_t * suggestion, + enum kherr_suggestion suggestion_id, + khm_int32 flags) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + if (flags != KHERR_RF_CSTR_SUGGEST && + flags != KHERR_RF_RES_SUGGEST && + flags != KHERR_RF_MSG_SUGGEST && + flags != KHERR_RF_FREE_SUGGEST) + return; + + c = peek_context(); + if(!c) + return; + + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e) + goto _exit; + + /* if strings have already been resolved in this event, we cant + add any more unresolved strings. */ + if ((flags == KHERR_RF_RES_SUGGEST || + flags == KHERR_RF_MSG_SUGGEST) && + (e->flags & KHERR_RF_STR_RESOLVED)) + goto _exit; + + e->suggestion = suggestion; + e->suggestion_id = suggestion_id; + e->flags |= flags; +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_location(wchar_t * location) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + if(!c) + return; + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e) + goto _exit; + e->location = location; +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_facility(wchar_t * facility, + khm_int32 facility_id) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + if(!c) + return; + tid = GetCurrentThreadId(); + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e) + goto _exit; + e->facility = facility; + e->facility_id = facility_id; +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_set_desc_event(void) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + if(!c) + return; + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(!e || c->desc_event) + goto _exit; + + QDEL(c,e); + c->desc_event = e; + e->severity = KHERR_NONE; + resolve_event_strings(e); + + notify_ctx_event(KHERR_CTX_DESCRIBE, c); + +_exit: + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_del_last_event(void) { + kherr_context * c; + kherr_event * e; + DWORD tid; + + c = peek_context(); + + if(!c) + return; + + tid = GetCurrentThreadId(); + + EnterCriticalSection(&cs_error); + e = QBOTTOM(c); + while (e != NULL && e->thread_id != tid) + e = QPREV(e); + + if(e) { + QDEL(c, e); + if(c->err_event == e) { + pick_err_event(c); + } + free_event(e); + } + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_push_context(kherr_context * c) +{ + kherr_context * p; + int new_context = FALSE; + + EnterCriticalSection(&cs_error); + p = peek_context(); + if(p && (c->flags & KHERR_CF_UNBOUND)) { + LDELETE(&ctx_root_list, c); + TADDCHILD(p,c); + c->flags &= ~KHERR_CF_UNBOUND; + kherr_hold_context(p); + new_context = TRUE; + } + push_context(c); + + if (new_context) + notify_ctx_event(KHERR_CTX_BEGIN, c); + + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_push_new_context(khm_int32 flags) +{ + kherr_context * p; + kherr_context * c; + + flags &= KHERR_CFMASK_INITIAL; + + EnterCriticalSection(&cs_error); + p = peek_context(); + c = get_empty_context(); + if(p) { + LDELETE(&ctx_root_list, c); + TADDCHILD(p,c); + c->flags &= ~KHERR_CF_UNBOUND; + kherr_hold_context(p); + } + c->flags |= flags; + push_context(c); + + notify_ctx_event(KHERR_CTX_BEGIN, c); + + LeaveCriticalSection(&cs_error); +} + +kherr_param dup_parm(kherr_param p) { + if(parm_type(p) == KEPT_STRINGT) { + wchar_t * d = PWCSDUP((wchar_t *)parm_data(p)); + return kherr_val(KEPT_STRINGT, d); + } else + return p; +} + +kherr_event * fold_context(kherr_context * c) { + kherr_event * e; + kherr_event * g; + + if (!c) + return NULL; + + EnterCriticalSection(&cs_error); + if(!c->err_event || (c->flags & KHERR_CF_DIRTY)) { + pick_err_event(c); + } + if(c->err_event) { + g = c->err_event; + e = get_empty_event(); + *e = *g; + g->short_desc = NULL; + g->long_desc = NULL; + g->suggestion = NULL; + g->flags &= + ~(KHERR_RF_FREE_SHORT_DESC | + KHERR_RF_FREE_LONG_DESC | + KHERR_RF_FREE_SUGGEST); + LINIT(e); + e->p1 = dup_parm(g->p1); + e->p2 = dup_parm(g->p2); + e->p3 = dup_parm(g->p3); + e->p4 = dup_parm(g->p4); + } else { + e = c->desc_event; + c->desc_event = NULL; + } + + if (e) + e->flags |= KHERR_RF_CONTEXT_FOLD; + + LeaveCriticalSection(&cs_error); + + return e; +} + +KHMEXP void KHMAPI kherr_hold_context(kherr_context * c) { + assert(c && c->magic == KHERR_CONTEXT_MAGIC); + EnterCriticalSection(&cs_error); + c->refcount++; + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_release_context(kherr_context * c) { + assert(c && c->magic == KHERR_CONTEXT_MAGIC); + EnterCriticalSection(&cs_error); + c->refcount--; + if (c->refcount == 0) { + kherr_event * e; + kherr_context * p; + + notify_ctx_event(KHERR_CTX_END, c); + + p = TPARENT(c); + if (p) { + e = fold_context(c); + if (e) + add_event(p, e); + + TDELCHILD(p, c); + kherr_release_context(p); + } else { + LDELETE(&ctx_root_list, c); + } + free_context(c); + } + LeaveCriticalSection(&cs_error); +} + +KHMEXP void KHMAPI kherr_pop_context(void) { + kherr_context * c; + + EnterCriticalSection(&cs_error); + c = pop_context(); + if(c) { + kherr_release_context(c); + } + LeaveCriticalSection(&cs_error); +} + +KHMEXP kherr_context * KHMAPI kherr_peek_context(void) { + kherr_context * c; + + c = peek_context(); + if (c) + kherr_hold_context(c); + + return c; +} + +KHMEXP khm_boolean KHMAPI kherr_is_error(void) { + kherr_context * c = peek_context(); + return kherr_is_error_i(c); +} + +KHMEXP khm_boolean KHMAPI kherr_is_error_i(kherr_context * c) { + if(c && c->severity <= KHERR_ERROR) + return TRUE; + else + return FALSE; +} + +KHMEXP void KHMAPI kherr_clear_error(void) { + kherr_context * c = peek_context(); + if (c) + kherr_clear_error_i(c); +} + +KHMEXP void KHMAPI kherr_clear_error_i(kherr_context * c) { + kherr_event * e; + if (c) { + EnterCriticalSection(&cs_error); + e = QTOP(c); + while(e) { + e->flags |= KHERR_RF_INERT; + e = QNEXT(e); + } + c->severity = KHERR_NONE; + c->err_event = NULL; + c->flags &= ~KHERR_CF_DIRTY; + LeaveCriticalSection(&cs_error); + } +} + +KHMEXP void KHMAPI kherr_set_progress(khm_ui_4 num, khm_ui_4 denom) { + kherr_context * c = peek_context(); + if(c) { + EnterCriticalSection(&cs_error); + c->progress_denom = denom; + c->progress_num = num; + LeaveCriticalSection(&cs_error); + } +} + +KHMEXP void KHMAPI kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom) { + kherr_context * c = peek_context(); + kherr_get_progress_i(c,num,denom); +} + +KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, + khm_ui_4 * num, + khm_ui_4 * denom) { + if(c) { + EnterCriticalSection(&cs_error); + *num = c->progress_num; + *denom = c->progress_denom; + LeaveCriticalSection(&cs_error); + } else { + *num = 0; + *denom = 0; + } +} + +KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c) +{ + kherr_event * e; + EnterCriticalSection(&cs_error); + e = QTOP(c); + LeaveCriticalSection(&cs_error); + return e; +} + +KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e) +{ + kherr_event * ee; + + EnterCriticalSection(&cs_error); + ee = QNEXT(e); + LeaveCriticalSection(&cs_error); + return ee; +} + +KHMEXP kherr_context * KHMAPI kherr_get_first_context(kherr_context * c) +{ + kherr_context * cc; + + EnterCriticalSection(&cs_error); + if (c) { + cc = TFIRSTCHILD(c); + if (cc) + kherr_hold_context(cc); + } else { + cc = ctx_root_list; + if (cc) + kherr_hold_context(cc); + } + LeaveCriticalSection(&cs_error); + return cc; +} + +KHMEXP kherr_context * KHMAPI kherr_get_next_context(kherr_context * c) +{ + kherr_context * cc; + EnterCriticalSection(&cs_error); + cc = LNEXT(c); + if (cc) + kherr_hold_context(cc); + LeaveCriticalSection(&cs_error); + return cc; +} + +KHMEXP kherr_event * KHMAPI kherr_get_err_event(kherr_context * c) +{ + kherr_event * e; + EnterCriticalSection(&cs_error); + if(!c->err_event) { + pick_err_event(c); + } + e = c->err_event; + LeaveCriticalSection(&cs_error); + return e; +} + +KHMEXP kherr_event * KHMAPI kherr_get_desc_event(kherr_context * c) +{ + kherr_event * e; + + EnterCriticalSection(&cs_error); + e = c->desc_event; + LeaveCriticalSection(&cs_error); + return e; +} + +KHMEXP kherr_param kherr_dup_string(const wchar_t * s) +{ + wchar_t * dest; + size_t cb_s; + + if (s == NULL) + return (kherr_param) 0; + + if (FAILED(StringCbLength(s, KHERR_MAXCB_STRING, &cb_s))) + cb_s = KHERR_MAXCB_STRING; + else + cb_s += sizeof(wchar_t); + + dest = PMALLOC(cb_s); + assert(dest != NULL); + dest[0] = L'\0'; + + StringCbCopy(dest, cb_s, s); + + return _tstr(dest); +} diff --git a/mechglue/src/windows/identity/kherr/kherr.h b/mechglue/src/windows/identity/kherr/kherr.h new file mode 100644 index 000000000..6ae943e4e --- /dev/null +++ b/mechglue/src/windows/identity/kherr/kherr.h @@ -0,0 +1,1008 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHERR_H +#define __KHIMAIRA_KHERR_H + +/*! \defgroup kherr NetIDMgr Error Reporting + + Error reporting functions provide a mechanism to construct + meaningful and user friendly error reports for the user. + + Unlike most of the other NetIDMgr API's, the error reporting APIs + are lightweight and usually do not return an error value. This is + mostly because, these functions are called \b after an error + occurs. + + @{*/ +#include +#include + +/*! \name Customizable macros +@{ */ +#ifndef KHERR_FACILITY +/*! \brief The default facility when reporting errors + + When including this header file, if the KHERR_FACILITY macro is + defined to be a wide character string, then it will be used as the + default facility when for the convenience macros. All of the + calls to the convenience macros in the source file would then have + that facility. + + If left undefined, the convenience macros will leave the facility + value undefined. + */ +#define KHERR_FACILITY NULL +#endif + +#ifndef KHERR_FACILITY_ID +/*! \brief The default facility ID when reporting errors + + When including this header file, if the KHERR_FACILITY_ID macro is + defined to be non-zero, then it will be used as the default + facility identifier for the convenience macros. All of the calls + to the convenience macros in the source file would then have that + facility identifier. + + The default value of 0 means that the facility is undefined. + */ +#define KHERR_FACILITY_ID 0 +#endif + +/*! \define KHERR_HMODULE (undefined) + \brief The default module handle + + When including this header file, if the KHERR_HMODULE macro is + defined to be an identifier that holds the module handle, then the + convenience macros that specify a module handle will use it. + + A default value is not defined for KHERR_HMODULE. Any attempt to + invoke any of the convenience macros that use it should generate a + compile time error. + */ +#ifdef _WIN32 +#ifndef KHERR_HMODULE +#endif +#endif +/*@}*/ + +/*! \brief Parameter types + */ +enum kherr_parm_types { + KEPT_INT32 = 1, + KEPT_UINT32, + KEPT_INT64, + KEPT_UINT64, + KEPT_STRINGC, /*!< String constant */ + KEPT_STRINGT /*!< String. Will be freed using + free() when the event is freed */ +}; + +#ifdef _WIN32 +typedef khm_ui_8 kherr_param; +#else +#error kherr_param undefined +#endif + +/*! \brief Severity levels + + Larger the value, the less severe it is. +*/ +enum tag_kherr_severity { + KHERR_FATAL = 0, /*!< Fatal error.*/ + KHERR_ERROR, /*!< Non-fatal error. We'll probably + survive. See the suggested action. */ + KHERR_WARNING, /*!< Warning. Something almost broke + or soon will. See the suggested + action. */ + KHERR_INFO, /*!< Informational. Something happened + that we would like you to know + about. */ + KHERR_DEBUG_3 = 64, /*!< Verbose debug level 3 (high) */ + KHERR_DEBUG_2 = 65, /*!< Verbose debug level 2 (medium) */ + KHERR_DEBUG_1 = 66, /*!< Verbose debug level 1 (low) */ + KHERR_RESERVED_BANK = 127, /*!< Internal use */ + KHERR_NONE = 128 /*!< Nothing interesting has happened + so far */ +}; + +typedef enum tag_kherr_severity kherr_severity; + +/*! \brief Suggestions */ +enum tag_kherr_suggestion { + KHERR_SUGGEST_NONE = 0, /*!< No suggestions. */ + KHERR_SUGGEST_ABORT, /*!< Abort whatever it was you were + trying. It's not gonna work. */ + KHERR_SUGGEST_RETRY, /*!< Retry. It might work the second + or third time over */ + KHERR_SUGGEST_IGNORE, /*!< Ignore. It might go away. */ + KHERR_SUGGEST_INTERACT, /*!< Further user interaction is + necessary to resolve the situation. + The suggest string in the event + should be prompted to the user. */ + KHERR_SUGGEST_OTHER, /*!< Something else. */ +}; + +typedef enum tag_kherr_suggestion kherr_suggestion; + +/*! \brief An event */ +typedef struct tag_kherr_event { + khm_int32 magic; /*!< Magic number. Always set to + KHERR_EVENT_MAGIC */ + DWORD thread_id; /*!< The thread which reported this + event. */ + const wchar_t * short_desc; /*!< Short description or title + (localized) */ + const wchar_t * facility; /*!< Facility name of the reporter + (not localized) */ + const wchar_t * location; /*!< Location. Usually the function + name or such of where the event + occured (not localized) */ + const wchar_t * long_desc; /*!< A long description of what went + wrong (localized, formatted) */ + const wchar_t * suggestion; /*!< A suggested way to fix it + (localized,formatted) */ + + kherr_severity severity; + /*!< Severity level. One of the + severity levels listed in + enumeration ::kherr_severity */ + khm_int32 facility_id; /*!< Left to the application to + interpret */ + kherr_suggestion suggestion_id; + /*!< One of the suggestion ID's from + the enumeration + ::kherr_suggestion */ + + int flags; /*!< Flags. */ + + kherr_param p1; /*!< Parameter 1 for formatting */ + kherr_param p2; /*!< Parameter 2 for formatting */ + kherr_param p3; /*!< Parameter 3 for formatting */ + kherr_param p4; /*!< Parameter 4 for formatting */ + + DWORD time_ticks; /*!< Time at which event was reported + (as returned by GetTickCount(). */ + FILETIME time_ft; /*!< Time at which event was reported. + Current system time as FILETIME. */ + +#ifdef _WIN32 + HMODULE h_module; /*!< Handle to the module which should + resolve any unresolved resources + references above. */ +#endif + + LDCL(struct tag_kherr_event); +} kherr_event; + +#define KHERR_EVENT_MAGIC 0x0423e84f + +/*! \brief Flags for kherr_event + + Each set of flags that define the type of resource for one value + is mutually exclusive. + */ +enum kherr_event_flags { + KHERR_RF_CSTR_SHORT_DESC= 0x00000000, + /*!< Short description is a constant + string */ + KHERR_RF_RES_SHORT_DESC = 0x00000001, + /*!< Short description is a string + resource */ + KHERR_RF_MSG_SHORT_DESC = 0x00000002, + /*!< Short description is a message + resource */ + KHERR_RF_FREE_SHORT_DESC= 0x00000004, + /*!< Short description is an allocated + string */ + KHERR_RFMASK_SHORT_DESC = 0x00000007, + + KHERR_RF_CSTR_LONG_DESC = 0x00000000, + /*!< Long description is a constant + string */ + KHERR_RF_RES_LONG_DESC = 0x00000008, + /*!< Long description is a string + resource */ + KHERR_RF_MSG_LONG_DESC = 0x00000010, + /*!< Long description is a message + resouce */ + KHERR_RF_FREE_LONG_DESC = 0x00000020, + /*!< Long description is an allocated + string */ + KHERR_RFMASK_LONG_DESC = 0x00000038, + + KHERR_RF_CSTR_SUGGEST = 0x00000000, + /*!< Suggestion is a constant + string */ + KHERR_RF_RES_SUGGEST = 0x00000040, + /*!< Suggestion is a string + resource */ + KHERR_RF_MSG_SUGGEST = 0x00000080, + /*!< Suggestion is a message + resource */ + KHERR_RF_FREE_SUGGEST = 0x00000100, + /*!< Suggestion is an allocated + string */ + KHERR_RFMASK_SUGGEST = 0x000001C0, + + KHERR_RF_STR_RESOLVED = 0x00010000, + /*!< The string resources in the event + have been resolved. */ + KHERR_RF_CONTEXT_FOLD = 0x00020000, + /*!< The event is a representation of + a folded context. */ + + KHERR_RF_INERT = 0x00040000 + /*!< Inert event. The event has + already been dealt with and is no + longer considered significant. */ +}; + +/*! \brief Serial number for error contexts */ +typedef khm_ui_4 kherr_serial; + +/*! \brief An error context +*/ +typedef struct tag_kherr_context { + khm_int32 magic; /*!< Magic number. Always set to + KHERR_CONTEXT_MAGIC */ + + kherr_serial serial; /*!< Context instance serial number. + Context objects themselves may be + reused for different contexts as + they are freed and reallocated. + However every instance of a context + is guaranteed to have a unique + serial number as specified in this + field. If an external entity wants + to keep track of the context, it + should keep track of the serial + number as well as the pointer to the + context object. */ + + kherr_severity severity; + /*!< Severity level. One of the + severity levels listed below. This + is the severity level of the context + and is the maximum severity level of + all the events in the queue of + events. */ + + khm_int32 flags; /*!< Flags. Used internally. */ + khm_ui_4 refcount; /*!< Reference count. Used + internally */ + + kherr_event *desc_event; /*!< Description event. The event that + describes the error context. This + points to an event that is not in + the event queue. */ + + kherr_event *err_event; /*!< Significant event. The last one + that caused the severity level to be + what it is right now. This points + to an event that is listed in the + event queue for this context.*/ + + khm_ui_4 progress_num; /*!< Progress numerator */ + khm_ui_4 progress_denom; /*!< Progress denominator */ + + TDCL(struct tag_kherr_context); + QDCL(struct tag_kherr_event); +} kherr_context; + +#define KHERR_CONTEXT_MAGIC 0x34f3238c + +enum kherr_context_flags { + KHERR_CF_NONE = 0x00000000, + /*!< None. */ + + KHERR_CF_DIRTY = 0x00000001, + /*!< Used Internally. Denotes that + the err_event and severity may need + to be recalculated. Cannot be set + as an initial flag. */ + + KHERR_CF_OWN_PROGRESS = 0x00000002, + /*!< The context maintains its own + progress meter as opposed to one + that is derived from child + contexts. */ + + KHERR_CF_UNBOUND = 0x00000004, + /*!< Unbound context. The context + can't be used to log events. Call + kherr_push_context() to associate + the context with the global context + hierarchy. Cannot be set as an + initial flag. */ + + KHERR_CF_TRANSITIVE = 0x00000008, + /*!< Transitive. The context is + automatically made the current + context for all other threads that + handle messages sent or posted by + threads whose current error context + is this one. */ + + KHERR_CFMASK_INITIAL = 0x0000000a, + /*!< Allowed initial flags */ +}; + +/*! \brief Maximum length of a string field in characters including terminating NULL + */ +#define KHERR_MAXCCH_STRING 1024 + +/*! \brief Maximum length of a string field in bytes including terminating NULL + */ +#define KHERR_MAXCB_STRING (KHERR_MAXCCH_STRING * sizeof(wchar_t)) + +/*! \brief Context event + + \see kherr_add_ctx_handler() +*/ +enum kherr_ctx_event { + KHERR_CTX_BEGIN = 0x0001, /*!< A new context was created */ + KHERR_CTX_DESCRIBE=0x0002, /*!< A context was described */ + KHERR_CTX_END = 0x0004, /*!< A context was closed */ + KHERR_CTX_ERROR = 0x0008 /*!< A context switched to an error + state */ +}; + +/*! \brief Context event handler + + Context event handlers are invoked when specific events occur with + respect to an error context. The ::kherr_ctx_event parameter + specifies which event occurred using one of the event values + described in the enumeration. The error context in which this + event occurred is specified by the ::kherr_context pointer. + + Note that if the handler needs to keep track of the error context + for later processing, it also needs to keep track of the \a serial + field of the error context. The same context object may be + reused, but the serial number is guaranteed to be unique. + + \see kherr_add_ctx_handler() + */ +typedef void (KHMAPI * kherr_ctx_handler)(enum kherr_ctx_event, + kherr_context *); + +/*! \brief Add a context event handler + + An application can register an event handler that gets notified of + events that pertain to error contexts. More than one handler can + be registered. The order in which the handlers are called is + undefined for any specific event. + + These event occur in the context of individual application + threads. The handler will be called from within the thread that + caused the event. Therefore it is important that the handler is + both reentrant and returns quickly. + + The events that the handler will be notified of are explained + below: + + KHERR_CTX_BEGIN: Notification that a new context was + created. A pointer to the context will be supplied to the + handler. The supplied pointer should not be used to obtain a hold + on the context, as it will prevent the context from being closed. + + KHERR_CTX_DESCRIBE: The thread called + kherr_set_desc_event() to set the description of a context. Once + again, the pointer should not be used to obtain a hold on the + context. + + KHERR_CTX_ERROR: The last event that was reported for the + context was an error event (the severity was was equal or higher + than KHERR_ERROR). The pointer may be used to obtain a hold on + the context. However, it is the application's resonsibility to + make sure that the hold is released later. Otherwise the event + will never be closed. + + KHERR_CTX_END: Closure. This event is signalled when the + last open handle to the context is closed and there is no thread + that is currently active which has this context in its error + context stack. At the time the handler is invoked, the context is + still intact. The pointer that is supplied should not be used to + obtain a handle on the context. + + \param[in] h Context event handler, of type ::kherr_ctx_handler + + \param[in] filter A combination of ::kherr_ctx_event values + indication which notifications should be sent to the handler. + If a \a filter value of zero is provided, all of the events + will be sent to the handler. + + \param[in] serial The serial number of the error context that + should be tracked. If this is zero, all error contexts can + trigger the handler. + */ +KHMEXP void KHMAPI kherr_add_ctx_handler(kherr_ctx_handler h, + khm_int32 filter, + kherr_serial serial); + +/*! \brief Remove a context event handler + + Undoes what was done with kherr_add_ctx_handler() + + \see kherr_add_ctx_handler() + */ +KHMEXP void KHMAPI kherr_remove_ctx_handler(kherr_ctx_handler h, + kherr_serial serial); + + +/*! \brief Report an error + + Creates an event, fills in the details specified in the arguments, + and adds it to the current error context. + + If the current thread does not have an error context, no reporting + happens. However, if any of the supplied strings or parameters + are marked as allocated, they will be freed before the function + returns. + + Certain parameters that expect strings can instead be given string + resources, message resources or allocated strings in addition to + constant string. By default, the parameters are expected to be + constant strings. + + Allocated strings: The application can allocate memory for + a string. Since the application is not notified when the event is + no longer used and freed, it \b must indicate that the string is + an allocated string by setting the appropriate flag in the \a + flags parameter. When the event is no longer used, the memory + pointed to by the relevant pointer will be freed through a call to + free(). Not all string parameters take allocated strings. See + individual parameter documentation for details. + + String resources: On WIN32, string resources can be passed + in to kherr_report() using the MAKEINTRESOURCE macro. However, + the application \b must specify that the parameter is a string + resource using the appropriate flag in the \a flags parameter. + The error reporting engine will expand the string against the + module handle passed in the \a h_module parameter when the value + of the string is required. Not all string parameters take string + resources. See individual parameter documentation for details. + Strings loaded through string resources cannot be longer than + ::KHERR_MAXCCH_STRING in characters inclusive of terminating NULL. + + Message resources: On WIN32, message resources can be + passed in to kherr_report() by specifying the message ID where it + ordinarily expects a pointer to a constant string. The + application \b must indicate that the string is a message resource + by using the appropriate flag in the \a flags parameter. When the + value of the string is needed, it is expanded against the module + handle passed in the \a h_module parameter using the message ID. + Not all string parameters take message resources. See individual + parameter documentation for details. Note that the facility and + severity values associated with a message resource are ignored. + Strings loaded through message resources cannot be longer than + ::KHERR_MAXCCH_STRING in characters inclusive of terminating NULL. + + Formatted fields: Parameters that are formatted can have + can have parameter inserts like in printf(). However, specifying + inserts is different from printf() and follows the conventions + used in WIN32 API FormatMessage(). This is because for localized + strings, the order of the parameters in the string may be + different. See the documentation for FormatMessage() for details + on the format string. The same set of parameters (i.e. \a p1, \a + p2, \a p3, \a p4) is used for all formatted strings with + appropriate marshalling for 64 bit types. The size of the string + after expansion must not exceed 65536 bytes inclusive of + terminating NULL. + + \param[in] severity One of ::kherr_severity_level + \param[in] short_desc Short description or title (localized). Can + be a string resource, message resource, allocated string or + constant string. The \a flags parameter should indicate the + type of string used. + \param[in] facility Facility name of the reporter (not localized) + \param[in] location Usually the function name or such of where the + event occured (not localized) + \param[in] long_desc Long description of event (localized, + formatted). Can be a string resource, message resource, + allocated string or constant string. The \a flags parameter + should indicate the type of string used. + \param[in] suggestion Suggested action to correct situation, if + applicable (localized). Can be a string resource, message + resource, allocated string or constant string. The \a flags + parameter should indicate the type of string used. + \param[in] facility_id Identifier of facility. Application + defined. + \param[in] suggestion_id One of the suggestion identifiers from + ::kherr_suggestion_ids + \param[in] p1 First parameter. Used for formatting. + \param[in] p2 Second parameter. Used for formatting. + \param[in] p3 Third parameter. Used for formatting. + \param[in] p4 Fourth parameter. Used for formatting. + \param[in] flags Flags. See ::kherr_report_flags + \param[in] h_module Handle to a module that resolves any string or + message resources used for the \a short_description , \a + long_desc or \a suggestion parameters. This parameter is only + available on WIN32. + + \note With the exception of parameters of type KEPT_STRINGT and + parameters which are flagged for freeing using the \a flags + parameter, all other string parameters are assumed to be + pointers to constant strings. The strings are not copied and + the pointers are used as is. Also, no clean-up is performed + when the event is freed other than that implied by \a flags. + */ +KHMEXP kherr_event * KHMAPI kherr_report( + enum kherr_severity severity, + const wchar_t * short_desc, + const wchar_t * facility, + const wchar_t * location, + const wchar_t * long_desC, + const wchar_t * suggestion, + khm_int32 facility_id, + enum kherr_suggestion suggestion_id, + kherr_param p1, + kherr_param p2, + kherr_param p3, + kherr_param p4, + khm_int32 flags +#ifdef _WIN32 + ,HMODULE h_module +#endif +); + +/*! \brief Report a formatted message + + The format string \a long_desc_fmt should be a string constant and + the format specifiers follow that of \a sprintf. This creates an + event with the long description set to the expansion of the format + string against the arguments. + */ +KHMEXP kherr_event * __cdecl +kherr_reportf_ex(enum kherr_severity severity, + const wchar_t * facility, + khm_int32 facility_id, +#ifdef _WIN32 + HMODULE hModule, +#endif + const wchar_t * long_desc_fmt, + ...); + +/*! \brief Report a formatted message + + The format string \a long_desc_fmt should be a string constant and + the format specifiers follow that of \a sprintf. This creates an + event with the long description set to the expansion of the format + string against the arguments. + */ +KHMEXP kherr_event * __cdecl +kherr_reportf(const wchar_t * long_desc_fmt, + ...); + +/*! \brief Create a parameter out of a transient string + + A parameter is created by duplicating the string that is passed + into the function. If the string exceeds KHERR_MAXCCH_STRING, + then only the first part of the string that fits within the limit + is duplicated. + + The resulign ::kherr_param must be passed in to kherr_report(). + The event logging framework will free the duplicated string once + the data is no longer required. + */ +KHMEXP kherr_param kherr_dup_string(const wchar_t * s); + +/* convenience macros for specifying parameters for kherr_report */ +#define kherr_val(type,val) \ + ((((kherr_param)(type)) << ((sizeof(kherr_param)-1)*8)) | (kherr_param) (val)) + +#define _int32(i) kherr_val(KEPT_INT32, i) +#define _uint32(ui) kherr_val(KEPT_UINT32, ui) +#define _int64(i) kherr_val(KEPT_INT64, i) +#define _uint64(ui) kherr_val(KEPT_UINT64, ui) +#define _cstr(cs) kherr_val(KEPT_STRINGC, cs) +#define _tstr(ts) kherr_val(KEPT_STRINGT, ts) +#define _dupstr(s) kherr_dup_string(s) + +/* convenience macros for calling kherr_report */ +#ifdef KHERR_HMODULE + +#define _report_cs0(severity, long_description) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, 0, KHERR_HMODULE) + +#define _report_cs1(severity, long_description, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, 0, KHERR_HMODULE) + +#define _report_cs2(severity, long_description, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, 0, KHERR_HMODULE) + +#define _report_cs3(severity, long_description, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, 0, KHERR_HMODULE) + +#define _report_cs4(severity, long_description, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, 0, KHERR_HMODULE) + +#else + +#define _report_cs0(severity, long_description) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, 0, NULL) + +#define _report_cs1(severity, long_description, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, 0, NULL) + +#define _report_cs2(severity, long_description, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, 0, NULL) + +#define _report_cs3(severity, long_description, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, 0, NULL) + +#define _report_cs4(severity, long_description, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_description), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, 0, NULL) +#endif /* !defined(KHERR_HMODULE) */ + +#ifdef _WIN32 +#define _report_sr0(severity, long_desc_id) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) + +#define _report_sr1(severity, long_desc_id, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) + +#define _report_sr2(severity, long_desc_id, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) + +#define _report_sr3(severity, long_desc_id, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) + +#define _report_sr4(severity, long_desc_id, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, MAKEINTRESOURCE(long_desc_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_RES_LONG_DESC, KHERR_HMODULE) +#endif + +#ifdef _WIN32 +#define _report_mr0(severity, long_desc_msg_id) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) + +#define _report_mr1(severity, long_desc_msg_id, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) + +#define _report_mr2(severity, long_desc_msg_id, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) + +#define _report_mr3(severity, long_desc_msg_id, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) + +#define _report_mr4(severity, long_desc_msg_id, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (wchar_t *)(long_desc_msg_id), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_MSG_LONG_DESC, KHERR_HMODULE) +#endif + +#define _report_ts0(severity, long_desc_ptr) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, 0, 0, 0, 0, KHERR_RF_FREE_LONG_DESC, NULL) + +#define _report_ts1(severity, long_desc_ptr, p1) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, 0, 0, 0, KHERR_RF_FREE_LONG_DESC, NULL) + +#define _report_ts2(severity, long_desc_ptr, p1, p2) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, 0, 0, KHERR_RF_FREE_LONG_DESC, NULL) + +#define _report_ts3(severity, long_desc_ptr, p1, p2, p3) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, 0, KHERR_RF_FREE_LONG_DESC, NULL) + +#define _report_ts4(severity, long_desc_ptr, p1, p2, p3, p4) \ + kherr_report((severity), NULL, KHERR_FACILITY, NULL, (long_desc_ptr), NULL, KHERR_FACILITY_ID, 0, p1, p2, p3, p4, KHERR_RF_FREE_LONG_DESC, NULL) + +/*! \brief Set the suggestion and suggestion identifier for the last event + + The event that will be modified is the last event reported by the + calling thread. + */ +KHMEXP void KHMAPI kherr_suggest(wchar_t * suggestion, khm_int32 suggestion_id, khm_int32 flags); +#define _suggest_cs(cs,sid) kherr_suggest((cs), (sid), KHERR_RF_CSTR_SUGGEST) +#define _suggest_ts(ts,sid) kherr_suggest((ts), (sid), KHERR_RF_FREE_SUGGEST) +#define _suggest_sr(sr,sid) kherr_suggest(MAKEINTRESOURCE(sr), (sid), KHERR_RF_RES_SUGGEST) +#define _suggest_mr(mr,sid) kherr_suggest((wchar_t *)(DWORD_PTR)(mr), (sid), KHERR_RF_MSG_SUGGEST) + +/*! \brief Set the location string for the last event + + The event that will be modified is the last event reported by the + calling thread. + */ +KHMEXP void KHMAPI kherr_location(wchar_t * location); +#define _location(l) kherr_location(l) + +/*! \brief Set the facility string and identifier for the last event + + The event that will be modified is the last event reported by the + calling thread. + */ +KHMEXP void KHMAPI kherr_facility(wchar_t * facility, khm_int32 facility_id); +#define _facility(f,fid) kherr_facility((f),(fid)) + +/*! \brief Marks the last event as the descriptor event for the current error context + + Note that marking an event as the descriptor event has the effect + of removing the event from event queue. The event will henceforth + be used as the descriptor for the context. The only effective + fields of a descriptor event are \a short_desc, \a long_desc, \a + facility, \a facility_id and the parameters which are used for + resolving formatted strings in the aforementioned fields. + + Upon calling kherr_set_desc_event(), the event will be + automatically evaluated as if kherr_evaluate_event() was called. + + The event that will be referenced is the last event reported by + the calling thread. + */ +KHMEXP void KHMAPI kherr_set_desc_event(void); +#define _describe kherr_set_desc_event + +/*! \brief Delete the last event + + The event that will be deleted is the last event reported by the + calling thread. + */ +KHMEXP void KHMAPI kherr_del_last_event(void); +#define _del_event kherr_del_last_event + +/*! \brief Create a new context + + The created context is not bound to any thread or any context + hierarchy. Hence it cannot be used to capture any events until it + is used in a call to kherr_push_context(). + + Release the returned context pointer with a call to + kherr_release_context(). + + \param[in] flags Initial flags for the context. Combination of + ::kherr_context_flags + + \note This function is for internal use only. + */ +KHMEXP kherr_context * KHMAPI kherr_create_new_context(khm_int32 flags); + +/*! \brief Obtain a hold on a context */ +KHMEXP void KHMAPI kherr_hold_context(kherr_context * c); + +/*! \brief Release a context */ +KHMEXP void KHMAPI kherr_release_context(kherr_context * c); + +/*! \brief Push an empty context + + Creates an empty context, adds it as a child of the current + thread's error context. If the current thread does not have an + error context, then the created error context will be a root level + context. + + The new context will be the current error context for the calling + thread. + + \param[in] flags Initial flags for the context. Combination of + ::kherr_context_flags + + \see kherr_push_new_context() for more information about thread + specific context stacks. + + */ +KHMEXP void KHMAPI kherr_push_new_context(khm_int32 flags); +#define _begin_task kherr_push_new_context + +/*! \brief Push a context + + Each thread has a stack of error contexts. The topmost one is + current. The thread can push or pop contexts on to the stack + independently of the hierarchy of contexts (the only exception, as + explained below is when the context that is being pushed is + unbound). + + If the context being pushed by kherr_push_context() is unbound, + then it will be attached to the current context of the thread as a + child. Once the new context is pushed to the top of the stack, it + will become the current context for the thread. + + The calling thread must call kherr_pop_context() to remove the + context from the top of the stack. Each call to + kherr_push_new_context() or kher_push_context() must have a + corresponding kherr_pop_context() call. + + When the thread terminates, all of the contexts in the thread's + context stack will be automatically removed. + + \see kherr_pop_context() + */ +KHMEXP void KHMAPI kherr_push_context(kherr_context * c); + +/*! \brief Pop a context + + Remove the current error context from the thread's context stack. + If no other open handles exist to the error context, this causes + the error context to collapse into it's parent context or vanish + entirely unless the context contains an error. + + \see kherr_push_context() for more information about thread + specific context stacks. + */ +KHMEXP void KHMAPI kherr_pop_context(void); +#define _end_task kherr_pop_context + +/*! \brief Retrieve the current error context + + The returned pointer must be released with a call to + kherr_release_context(). +*/ +KHMEXP kherr_context * KHMAPI kherr_peek_context(void); + +/*! \brief Check if the current error context indicates an error + + \return TRUE if there is an error. FALSE otherwise. + \see kherr_analyze() + */ +KHMEXP khm_boolean KHMAPI kherr_is_error(void); + +/*! \brief Check if an error context indicates an error + + \return TRUE if there is an error. FALSE otherwise. + \see kherr_analyze() + */ +KHMEXP khm_boolean KHMAPI kherr_is_error_i(kherr_context * c); + +/*! \brief Clear the error state of the current context */ +KHMEXP void KHMAPI kherr_clear_error(void); + +/*! \brief Clear the error state of an error context */ +KHMEXP void KHMAPI kherr_clear_error_i(kherr_context * c); + +/*! \brief Set the progress meter of the current error context + + Setting \a denom to zero removes the progress meter. + */ +KHMEXP void KHMAPI kherr_set_progress(khm_ui_4 num, khm_ui_4 denom); +#define _progress(num,denom) kherr_set_progress((num),(denom)) + +/*! \brief Get the progress meter of the current error context + */ +KHMEXP void KHMAPI kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom); + +/*! \brief Get the progress meter of an error context + */ +KHMEXP void KHMAPI kherr_get_progress_i(kherr_context * c, khm_ui_4 * num, khm_ui_4 * denom); + +/*! \brief Get the first event in a context + + The returned pointer is only valid as long as there is a hold on + \a c. Once the context is released with a call to + kherr_release_context() all pointers to events in the context + becomes invalid. + + Use kherr_get_next_event() to obtain the other events. + */ +KHMEXP kherr_event * KHMAPI kherr_get_first_event(kherr_context * c); + +/*! \brief Get the next event + + Call kherr_get_first_event() to obtain the first event in a + context. Subsequent calls to kherr_get_next_event() will yield + other events in the order in which they were reported. The list + ends when kherr_get_next_event() returns NULL. + + The returned pointer is only valid as long as there is a hold on + \a c. Once the context is released with a call to + kherr_release_context() all pointers to events in the context + becomes invalid. + */ +KHMEXP kherr_event * KHMAPI kherr_get_next_event(kherr_event * e); + +/*! \brief Get the first child context of a context + + Contexts are arranged in a hiearchy. This function returns the + first child of an error context. Use kherr_get_next_context() to + obtain the other contexts. If \a c is \a NULL, this returns the + first root level context. + + The returned pointer must be released with a call to + kherr_release_context() + */ +KHMEXP kherr_context * KHMAPI kherr_get_first_context(kherr_context * c); + +/*! \brief Get the next sibling context of a context + + The returned pointer must be released with a call to + kherr_release_context() + + \see kherr_get_first_context() + */ +KHMEXP kherr_context * KHMAPI kherr_get_next_context(kherr_context * c); + +/*! \brief Get the desciption event for the context + + The description event is the event that was denoted using + kherr_set_desc_event() as the event which describes the context. + + The returned pointer is only valid as long as there is a hold on + \a c. Once the context is released with a call to + kherr_release_context() all pointers to events in the context + becomes invalid. + */ +KHMEXP kherr_event * KHMAPI kherr_get_desc_event(kherr_context * c); + +/*! \brief Get the error event for the context + + The error event for a context is the last event that had the + highest severity level. + + The returned pointer is only valid as long as there is a hold on + \a c. Once the context is released with a call to + kherr_release_context() all pointers to events in the context + becomes invalid. + */ +KHMEXP kherr_event * KHMAPI kherr_get_err_event(kherr_context * c); + +/*! \brief Evaluate an event + + When an event is reported, all the parameters and resource + references that were passed to kherr_report() are kept as-is until + the actual string values are required by the error reporting + library. However, if the string fields are required before then, + an application can call kherr_evaluate_event() to get them. + + This function does the following: + + - Load any referenced string or message resources that are + referenced in the event's short description, long description or + suggestion. + + - Expand any inserts using the parameters that were passed in. + + - Free up allocated strings in for the descriptions or suggestion + fields and any parameters. + + - Update the string fields in the event to contain the newly + generated strings. + + */ +KHMEXP void KHMAPI kherr_evaluate_event(kherr_event * e); + +/*! \brief Evaluate the last event + + Same as kherr_evaluate_event(), but operates on the last event + logged by the current thread. + + \see kherr_evaluate_event() + */ +KHMEXP void KHMAPI kherr_evaluate_last_event(void); +#define _resolve kherr_evaluate_last_event + +/*! \defgroup kherr_fids Standard Facility IDs +@{*/ +#define KHM_FACILITY_KMM 1 +#define KHM_FACILITY_KCDB 2 +#define KHM_FACILITY_UI 3 +#define KHM_FACILITY_KRB5 64 +#define KHM_FACILITY_KRB4 65 +#define KHM_FACILITY_AFS 66 +#define KHM_FACILITY_USER 128 +/*@}*/ + +/*@}*/ + +/* In debug mode, outputs the formatted string to the debug console */ +#ifdef DEBUG +KHMEXP void kherr_debug_printf(wchar_t * fmt, ...); +#endif + +#endif diff --git a/mechglue/src/windows/identity/kherr/kherrinternal.h b/mechglue/src/windows/identity/kherr/kherrinternal.h new file mode 100644 index 000000000..2b43fd7f4 --- /dev/null +++ b/mechglue/src/windows/identity/kherr/kherrinternal.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHERRORINTERNAL_H +#define __KHIMAIRA_KHERRORINTERNAL_H + +#include +#include +#include +#include + +typedef struct tag_kherr_thread { + khm_size nc_ctx; + khm_size n_ctx; + kherr_context ** ctx; +} kherr_thread; + +#define THREAD_STACK_SIZE 8 + +typedef struct tag_kherr_handler_node { + khm_int32 filter; + kherr_ctx_handler h; + kherr_serial serial; +} kherr_handler_node; + +#define CTX_ALLOC_INCR 4 + +#define EVENT_MASK_UNRESOLVED \ + (KHERR_RF_RES_SHORT_DESC|KHERR_RF_MSG_SHORT_DESC| \ + KHERR_RF_RES_LONG_DESC|KHERR_RF_MSG_LONG_DESC| \ + KHERR_RF_RES_SUGGEST|KHERR_RF_MSG_SUGGEST) + +extern CRITICAL_SECTION cs_error; +extern DWORD tls_error; +extern kherr_context * ctx_free_list; +extern kherr_event * evt_free_list; +extern kherr_handler_node * ctx_handlers; +extern khm_size n_ctx_handlers; + +#define parm_type(p) ((int) (((p)>>((sizeof(kherr_param) - 1) * 8)) & 0xff)) +#define parm_data(p) ((p) & ~(((kherr_param)0xff)<<((sizeof(kherr_param) - 1) * 8))) + +void resolve_event_strings(kherr_event *); +void attach_this_thread(void); +void detach_this_thread(void); +#endif diff --git a/mechglue/src/windows/identity/kherr/kherrmain.c b/mechglue/src/windows/identity/kherr/kherrmain.c new file mode 100644 index 000000000..0ae229204 --- /dev/null +++ b/mechglue/src/windows/identity/kherr/kherrmain.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +void +kherr_process_attach(void) { + InitializeCriticalSection(&cs_error); + tls_error = TlsAlloc(); +} + +void +kherr_process_detach(void) { + TlsFree(tls_error); + DeleteCriticalSection(&cs_error); +} + +void +kherr_thread_attach(void) { + /* We don't call attach_this_thread() here since we only + want to create a context stack for this thread if + someone wants one. */ + /* attach_this_thread(); */ +} + +void +kherr_thread_detach(void) { + detach_this_thread(); +} diff --git a/mechglue/src/windows/identity/kmm/Makefile b/mechglue/src/windows/identity/kmm/Makefile new file mode 100644 index 000000000..6135cdc4f --- /dev/null +++ b/mechglue/src/windows/identity/kmm/Makefile @@ -0,0 +1,54 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=kmm +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\kmm.h \ + $(INCDIR)\kplugin.h + +OBJFILES= \ + $(OBJ)\kmmmain.obj \ + $(OBJ)\kmm.obj \ + $(OBJ)\kmm_plugin.obj \ + $(OBJ)\kmm_module.obj \ + $(OBJ)\kmm_reg.obj \ + $(OBJ)\kmm_registrar.obj \ + $(OBJ)\kmmconfig.obj + +MSGRESFILE=$(OBJ)\kmm_msgs.res + +$(OBJ)\kmmconfig.c: kmmconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(MSGRESFILE): $(OBJ)\kmm_msgs.rc + +$(OBJ)\kmm_msgs.rc: lang\kmm_msgs.mc + $(MC2RC) + +all: mkdirs $(INCFILES) $(MSGRESFILE) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/mechglue/src/windows/identity/kmm/kmm.c b/mechglue/src/windows/identity/kmm/kmm.c new file mode 100644 index 000000000..5e955953d --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmm.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +khm_boolean kmmint_load_locale_lib(kmm_module_i * m, kmm_module_locale * l) +{ + HMODULE h; + + if(l->filename != NULL) { + wchar_t path[MAX_PATH]; + DWORD dw; + + /* construct the path name */ + assert(m->h_module != NULL); + + dw = PathIsFileSpec(l->filename); + + assert(dw); + if (!dw) + return FALSE; + + dw = GetModuleFileName(m->h_module, path, ARRAYLENGTH(path)); + assert(dw != 0); + if (dw == 0) + return FALSE; + + PathRemoveFileSpec(path); + dw = PathAppend(path, l->filename); + assert(dw); + if (!dw) + return FALSE; + + h = LoadLibrary(path); + if(!h) + return FALSE; + + EnterCriticalSection(&cs_kmm); + m->h_resource = h; + m->lcid_resource = l->language; + LeaveCriticalSection(&cs_kmm); + + return TRUE; + + } else { + /* in this case, the language resources are assumed to be in the + main module library itself. */ + + EnterCriticalSection(&cs_kmm); + m->h_resource = m->h_module; + m->lcid_resource = l->language; + LeaveCriticalSection(&cs_kmm); + + return TRUE; + } +} + + +KHMEXP khm_int32 KHMAPI kmm_set_locale_info(kmm_module module, kmm_module_locale * locales, khm_int32 n_locales) +{ + kmm_module_i * m; + LANGID lcid; + int i; + int * f; + khm_int32 rv = KHM_ERROR_SUCCESS; + + m = kmm_module_from_handle(module); + + if(!m || m->state != KMM_MODULE_STATE_INIT) + return KHM_ERROR_INVALID_OPERATION; + + if(!locales || n_locales < 0) + return KHM_ERROR_INVALID_PARAM; + + f = PMALLOC(n_locales * sizeof(int)); + if(!f) + return KHM_ERROR_UNKNOWN; + ZeroMemory(f, sizeof(int) * n_locales); + + lcid = GetUserDefaultLangID(); + + /* first search for an exact match */ + for(i=0; ih_resource; +} +#endif + +KHMEXP kmm_module KHMAPI +kmm_this_module(void) { + kmm_plugin_i * p; + kmm_module_i * m; + kmm_module vm; + + p = TlsGetValue(tls_kmm); + if (!kmm_is_plugin(p)) + return NULL; + + m = p->module; + vm = kmm_handle_from_module(m); + + kmm_hold_module(vm); + + return vm; +} + +KHMEXP kmm_plugin KHMAPI +kmm_this_plugin(void) { + kmm_plugin_i * p; + kmm_plugin vp; + + p = TlsGetValue(tls_kmm); + if (!kmm_is_plugin(p)) + return NULL; + + vp = kmm_handle_from_plugin(p); + + kmm_hold_plugin(vp); + + return vp; +} diff --git a/mechglue/src/windows/identity/kmm/kmm.h b/mechglue/src/windows/identity/kmm/kmm.h new file mode 100644 index 000000000..0dc7e4cea --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmm.h @@ -0,0 +1,1038 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KMM_H +#define __KHIMAIRA_KMM_H + +#include +#include + +/*! \defgroup kmm NetIDMgr Module Manager +@{*/ + +/*! \brief A handle to a module. +*/ +typedef khm_handle kmm_module; + +/*! \brief A handle to a plugin. + */ +typedef khm_handle kmm_plugin; + +/*! \name Limits + @{*/ + +/*! \brief Maximum number of characters in a name in KMM including the terminating NULL */ +#define KMM_MAXCCH_NAME 256 + +/*! \brief Maximum number of bytes in a name in KMM including the terminating NULL */ +#define KMM_MAXCB_NAME (sizeof(wchar_t) * KMM_MAXCCH_NAME) + +/*! \brief Maximum number of characters in a description in KMM including the terminating NULL */ +#define KMM_MAXCCH_DESC 512 + +/*! \brief Maximum number of bytes in a description in KMM including the terminating NULL */ +#define KMM_MAXCB_DESC (sizeof(wchar_t) * KMM_MAXCCH_NAME) + +/*! \brief Maximum number of characters in a vendor string in KMM including the terminating NULL */ +#define KMM_MAXCCH_VENDOR 256 + +/*! \brief Maximum number of bytes in a vendor string in KMM including the terminating NULL */ +#define KMM_MAXCB_VENDOR (sizeof(wchar_t) * KMM_MAXCCH_VENDOR) + +/*! \brief Maximum number of characters in a support URI in KMM including the terminating NULL */ +#define KMM_MAXCCH_SUPPORT 256 + +/*! \brief Maximum number of bytes in a vendor string in KMM including the terminating NULL */ +#define KMM_MAXCB_SUPPORT (sizeof(wchar_t) * KMM_MAXCCH_SUPPORT) + +/*! \brief Maximum number of dependencies per plugin +*/ +#define KMM_MAX_DEPENDENCIES 8 + +/*! \brief Maximum number of dependants per plugin + */ +#define KMM_MAX_DEPENDANTS 32 + +/*! \brief Maximum number of characters a dependency string including trailing double NULL */ +#define KMM_MAXCCH_DEPS (KMM_MAXCCH_NAME * KMM_MAX_DEPENDENCIES + 1) + +/*! \brief Maximum number of bytes in a dependency string including trailing double NULL */ +#define KMM_MAXCB_DEPS (sizeof(wchar_t) * KMM_MAXCCH_DEPS) +/*@}*/ /* Limits */ + +/*! \brief Plugin registration + + \see ::khm_cred_provider +*/ +typedef struct tag_kmm_plugin_reg { + wchar_t * name; /*!< Name of the plugin. Maximum of + KMM_MAXCCH_NAME characters + including the terminating + NULL. Required. */ + + wchar_t * module; /*!< Name of module that owns the + plugin. Maximum of + KMM_MAXCCH_NAME characters + including terminating NULL. + Required. */ + + khm_int32 type; /*!< Type plugin type. One of + KHM_PITYPE_*. Required. */ + khm_int32 flags; /*!< Unused. Set to 0 */ + kmq_callback_t msg_proc; /*!< Message processor. Required. */ + wchar_t * dependencies; /*!< Dependencies. Note that this is + a multi string. (you can use the + KHC multi string functions to + manipulate multi strings or to + convert a comma separated list of + dependencies to a multi string). + Each string in the multi string + is a name of a plugin that this + plugin depends on. Optional (set + to NULL if this plugin has no + dependencies). Maximum of + KMM_MAXCCH_DEPS characters + including terminating double + NULL.*/ + + wchar_t * description; /*!< Description of the plugin. + Maximum of KMM_MAXCCH_DESC + characters including the + terminating + NULL. Localized. Optional (set to + NULL if not provided) */ +#ifdef _WIN32 + HICON icon; /*!< Icon used to represent the + plugin. Optional. (set to NULL if + not provided) */ +#endif +} kmm_plugin_reg; + +/*! \brief Plugin information +*/ +typedef struct tag_kmm_plugin_info { + kmm_plugin_reg reg; /*!< Registration info */ + + khm_int32 state; /*!< Current status of the plugin. + One of ::_kmm_plugin_states */ + + khm_int32 failure_count; /*!< Number of recorded failures in + the plugin */ + FILETIME failure_time; /*!< Time of first recorded failure */ + khm_int32 failure_reason; /*!< The reason for the first recorded + failure */ + + kmm_plugin h_plugin; /*!< Handle to plugin */ +} kmm_plugin_info; + +/*! \name Plugin types +@{*/ +/*! \brief A credentials provider + + \see \ref pi_pt_cred for more information. + */ +#define KHM_PITYPE_CRED 1 + +/*! \brief A identity provider + + \see \ref pi_pt_cred for more information + */ +#define KHM_PITYPE_IDENT 2 + +/*! \brief A configuration provider + + \see \ref pi_pt_conf for more information. + */ +#define KHM_PITYPE_CONFIG 3 + +/*! \brief Undefined plugin type + + The plugin doesn't provide any credential type. + */ +#define KHM_PITYPE_MISC 4 + +/*@}*/ + +/*! \brief Plugin states */ +enum _kmm_plugin_states { + KMM_PLUGIN_STATE_FAIL_UNKNOWN = -5, /*!< Failed due to unknown + reasons */ + KMM_PLUGIN_STATE_FAIL_MAX_FAILURE = -4, /*!< The plugin has + reached the maximum number + of failures and cannot be + initialized until the + failure count is reset */ + KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED = -3, /*!< Failed because the + plugin was not registered + and automatic registration + failed. */ + KMM_PLUGIN_STATE_FAIL_DISABLED = -2,/*!< Failed because plugin was + disabled by the user. */ + KMM_PLUGIN_STATE_FAIL_LOAD = -1, /*!< The plugin failed to load + due to some unknown + reason. */ + KMM_PLUGIN_STATE_NONE = 0, /*!< Unknown state */ + KMM_PLUGIN_STATE_PLACEHOLDER, /*!< Placeholder. The plugin + hasn't been provided by + anyone yet, but the plugin + record has been created to + keep track of + dependencies. */ + KMM_PLUGIN_STATE_REG, /*!< The plugin is registered + but not initialized */ + KMM_PLUGIN_STATE_PREINIT, /*!< The plugin is in the + process of being + initialized */ + KMM_PLUGIN_STATE_HOLD, /*!< On hold. One or more + dependencies of this plugin + has not been resolved */ + KMM_PLUGIN_STATE_INIT, /*!< The plugin was initialized */ + KMM_PLUGIN_STATE_RUNNING, /*!< The plugin is running */ + KMM_PLUGIN_STATE_EXITED /*!< The plugin has been stopped. */ +}; + +/*! \brief Module registration */ +typedef struct tag_kmm_module_reg { + wchar_t * name; /*!< Identifier for the module */ + wchar_t * path; /*!< Full pathname to module + binary */ + + wchar_t * description; /*!< Description of module */ + + wchar_t * vendor; /*!< Vendor/copyright string */ + + wchar_t * support; /*!< Support URL/contact */ + + khm_int32 n_plugins; /*!< Number of plugins that are + active */ + kmm_plugin_reg * plugin_reg_info; /*!< Array of kmm_plugin_reg + records for each active + plugin */ +} kmm_module_reg; + +/*! \brief Module information record */ +typedef struct tag_kmm_module_info { + kmm_module_reg reg; /*!< Registration info */ + + khm_ui_4 language; /*!< Currently loaded langugage */ + + khm_int32 state; /*!< Current status of the + module */ + + khm_version file_version; /*!< File version for the + module */ + khm_version product_version; /*!< Product version for the + module */ + + khm_int32 failure_count; /*!< Number of times the module + has failed to load */ + FILETIME failure_time; /*!< Time of first recorded + failure */ + khm_int32 failure_reason; /*!< Reason for first failure. + One of the module status + values */ + + kmm_module h_module; /*!< Handle to the module. */ +} kmm_module_info; + +/*! \brief Module states +*/ +enum KMM_MODULE_STATES { + KMM_MODULE_STATE_FAIL_INCOMPAT=-12, /*!< The library containing + the module was not + compatible with this version + of NetIDMgr. */ + KMM_MODULE_STATE_FAIL_INV_MODULE=-11, /*!< The library containing + the module was invalid. */ + KMM_MODULE_STATE_FAIL_UNKNOWN=-10, /*!< Module could not be + loaded due to unknown + reasons. */ + KMM_MODULE_STATE_FAIL_MAX_FAILURE=-9,/*!< The module has failed + too many times already. Not + attempting to restart it + again */ + KMM_MODULE_STATE_FAIL_DUPLICATE=-8, /*!< An attempt was made to + load the same module + twice. */ + KMM_MODULE_STATE_FAIL_NOT_REGISTERED=-7, /*!< The module is not + found among the registered + module list */ + KMM_MODULE_STATE_FAIL_NO_PLUGINS=-6,/*!< The module provided no + plugins, or all the plugins + that are provided are + disabled */ + KMM_MODULE_STATE_FAIL_DISABLED=-5, /*!< Module is disabled and + cannot be loaded */ + KMM_MODULE_STATE_FAIL_LOAD=-4, /*!< The module failed to + initialize */ + KMM_MODULE_STATE_FAIL_INVALID=-3, /*!< The module was invalid. + Typically caused by the + required entrypoints not + being present */ + KMM_MODULE_STATE_FAIL_SIGNATURE=-2, /*!< The module failed to load + due to an unverifiable + signature */ + KMM_MODULE_STATE_FAIL_NOT_FOUND=-1, /*!< The module was not + found */ + KMM_MODULE_STATE_NONE=0, /*!< Unknown state. The handle + is possibly invalid */ + KMM_MODULE_STATE_PREINIT, /*!< The module is being + loaded. init_module() hasn't + been called yet */ + KMM_MODULE_STATE_INIT, /*!< In init_module() */ + KMM_MODULE_STATE_INITPLUG, /*!< Initializing plugins */ + KMM_MODULE_STATE_RUNNING, /*!< Running */ + KMM_MODULE_STATE_EXITPLUG, /*!< Currently exiting plugins */ + KMM_MODULE_STATE_EXIT, /*!< Currently exiting */ + KMM_MODULE_STATE_EXITED /*!< Exited */ +}; + +/*! \brief Start the Module Manager + + \note Only called by the NetIDMgr core. +*/ +KHMEXP void KHMAPI +kmm_init(void); + +/*! \brief Stop the Module Manager + + \note Only called by the NetIDMgr core. +*/ +KHMEXP void KHMAPI +kmm_exit(void); + +/*! \brief Return the plugin handle for the current plugin + + The returned handle represents the plugin which owns the current + thread. The returned handle must be released by calling + kmm_release_plugin(). Returns NULL if the current thread is not + owned by any plugin. + */ +KHMEXP kmm_plugin KHMAPI +kmm_this_plugin(void); + +/*! \brief Return the module handle for the current module + + The returned handle represents the module which owns the current + thread. The returned handle must be released by calling + kmm_release_module() +*/ +KHMEXP kmm_module KHMAPI +kmm_this_module(void); + +/*! \name Flags for kmm_load_module() +@{*/ +/*!\brief Load synchronously + + If this flag is set, then the function waits for the module to be + loaded. The default is to load the module asynchronously. + + When loading a module asynchronously, the kmm_load_module() + function returns KHM_ERROR_SUCCESS and exits without waiting for + the module to load. If \a result is not NULL, it will receive a + valid handle to the module. + + When loading a module synchronously, kmm_load_module() will wait + for the module to completely load. If it fails to load properly, + it will return an error code and set \a result to NULL. +*/ +#define KMM_LM_FLAG_SYNC 1 + +/*! \brief Do not load + + Indicates that the module shouldn't actually be loaded. If the + specified module name identifies a module that has already been + loaded, then the function returns a held handle to the existing + module (use kmm_release_module() to free the handle). Otherwise, + the function returns KHM_ERROR_NOT_FOUND. +*/ +#define KMM_LM_FLAG_NOLOAD 2 +/*@}*/ + +/*! \brief Load a module + + The \a modulename parameter specifies a module to load. Depending + on the configuration, not all of the plugins that are provided by + the module may be loaded. If no plugins are successfully loaded, + the module will be immediately unloaded. + + If the module is currently loaded or is being loaded, then a valid + handle to the existing module is returned. + + When called with KMM_LM_FLAG_SYNC, the function does not return + until the module and the associated plugins are all initialized, + or an error occurs. + + If the KMM_LM_FLAG_NOLOAD flag is set, then a handle to an + existing instance of the module will be returned. If the module + hasn't been loaded yet, then no handle is returned and the + function returns KHM_ERROR_NOT_FOUND. + + See the associated NetIDMgr Module Manager documentation on the + sequence of events associated with loading a module. + + \param[in] modulename Name of the module. The module should have + been registered under this name prior to the call. + \param[in] flags Combination of KMM_LM_FLAG_* + \param[out] result Receives a handle to the loaded module. If the + result is not required, set this to NULL. If \a result is not + NULL, and km_load_module() returns KHM_ERROR_SUCCESS, then + kmm_release_module() must be called to release the handle to + the module. Otherwise, \a result receives NULL. If a handle + is returned, it will be valid regardless of whether the module + fails to load or not. You can use kmm_get_module_state() to + query the progress of the loading process. See + ::KMM_LM_FLAG_SYNC. + + \retval KHM_ERROR_SUCCESS The call succeeded. If \a + KMM_LM_FLAG_SYNC was specified, this means that the module was + successfully loaded. Otherwise, it only means that the module + has been queued up for loading. Use kmm_get_module_state() to + determine if it was successfully loaded. If \a result is not + NULL, a valid handle is returned. + \retval KHM_ERROR_EXISTS The module is already loaded or has been + already queued for loading. If \a result is not NULL, a valid + handle to the existing module instance is returned. + \retval KHM_ERROR_NOT_FOUND If called with KMM_LM_FLAG_NOLOAD, + indicates that the module has not been loaded. Otherwise only + returned when called with KMM_LM_FLAG_SYNC. The module image + was not found. No handle is returned. + \retval KHM_ERROR_INVALID_SIGNATURE Only returned when called with + KMM_LM_FLAG_SYNC. The module was signed with an invalid + certificate. No handle is returned. + \retval KHM_ERROR_UNKNOWN Only returned when called with + KMM_LM_FLAG_SYNC. Some other error has occured. No handle is + returned. + + \see \ref pi_fw_pm_load + \see ::KMM_LM_FLAG_SYNC, ::KMM_LM_FLAG_NOLOAD +*/ +KHMEXP khm_int32 KHMAPI +kmm_load_module(wchar_t * modname, khm_int32 flags, kmm_module * result); + +/*! \brief Hold a handle to a module + + Use kmm_release_module() to release the hold. +*/ +KHMEXP khm_int32 KHMAPI +kmm_hold_module(kmm_module module); + +/*! \brief Release a handle to a module + + Release a held referece to a module that was returned in a call to + kmm_load_module(). +*/ +KHMEXP khm_int32 KHMAPI +kmm_release_module(kmm_module m); + +/*! \brief Query the state of a module + + When loading a module asynchronously you can query the state of + the loading process using this. The return value is a status + indicator. + + \return The return value is one of the ::KMM_MODULE_STATES + enumerations. +*/ +KHMEXP khm_int32 KHMAPI +kmm_get_module_state(kmm_module m); + +/*! \brief Unload a module + + See the associated NetIDMgr Module Manager documentation on the + sequence of events associated with unloading a module. + + \see \ref pi_fw_pm_unload +*/ +KHMEXP khm_int32 KHMAPI +kmm_unload_module(kmm_module module); + +/*! \brief Loads the default modules as specified in the configuration + + The configuration can specify the default set of modules to load. + This function dispatches the necessary message for loading these + modules and reutnrs. +*/ +KHMEXP khm_int32 KHMAPI +kmm_load_default_modules(void); + +/*! \brief Checks whether there are any pending loads + + Returns TRUE if there are modules still waiting to be loaded. +*/ +KHMEXP khm_boolean KHMAPI +kmm_load_pending(void); + +#ifdef _WIN32 + +/*! \brief Returns the Windows module handle from a handle to a NetIDMgr module. + Although it is possible to obtain the Windows module handle and + use it to call Windows API functions, it is not recommended to do + so. This is because that might cause the state of the module to + change in ways which are inconsistent from the internal data + structures that kmm maintains. + */ +KHMEXP HMODULE KHMAPI +kmm_get_hmodule(kmm_module m); +#endif + +/*! \brief Hold a plugin + + Obtains a hold on a plugin. The plugin handle will remain valid + until the hold is released with a call to kmm_release_plugin(). + No guarantees are made on the handle once the handle is released. + */ +KHMEXP khm_int32 KHMAPI +kmm_hold_plugin(kmm_plugin p); + +/*! \brief Release a plugin + + Releases a hold on a plugin obtained through a call to + kmm_hold_plugin(). The plugin handle should no longer be + considered valied once this is called. + */ +KHMEXP khm_int32 KHMAPI +kmm_release_plugin(kmm_plugin p); + +/*! \brief Provide a plugin + + This function must be called for each plugin that the module + provides. + + Note that this function returns immediately and does not + initialize the plugin. All plugins that are provided by a + module will be initialized once the init_module() function + returns. If the plugin has dependencies, it will be kept in a + held state until the plugins that it depends on are successfully + initialized. If the dependencies are not resolved (the dependent + plugins are not loaded), then plugin will not be initialized. + + If the plugin is not registered and \a plugin contains enough + information to perform the registration, then it will be + automatically registered. However, if the plugin is not + registered and cannot be registered using the provided + information, the plugin will not be initialized properly. Note + that automatic registration will always register the plugin in the + user configuration store. + + The \a name and \a msg_proc members of \a plugin are required to + have valid values. The \a icon member may optionally be + specified. The other fields can be specified if the plugin should + be automatically registered, however, the \a module field will be + ignored and will be determined by the \a module handle. + + \param[in] module Handle to this module that is providing the plugin. + \param[in] plugin A plugin descriptor. + + \retval KHM_ERROR_SUCCESS Succeeded. + \retval KHM_ERROR_INVALID_OPERATION The function was not called + during init_module() + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_DUPLICATE The plugin was already provided + + \note This can only be called when handing init_module() +*/ +KHMEXP khm_int32 KHMAPI +kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin); + +/*! \brief Query the state of a plugin. + + \return One of ::_kmm_plugin_states +*/ +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_state(wchar_t * plugin); + +/*! \defgroup kmm_reg Registration + + The functions for managing plugin and module registration. These + functions are also available as static linked libraries for use by + external applications which must register or unregister plugins or + modules. +@{*/ + +/*! \brief Obtain the configuration space for a named plugin + + Note that the named plugin does not have to actually exist. + Configuration spaces for plugins are based solely on the plugin + name and hence can be accessed regardless of whether the specific + plugin is loaded or not. + + \param[in] flags Controls the options for opening the + configuration space. If KHM_FLAG_CREATE is specified, then + the configuration space for the plugin named \a plugin wil be + created if it doesn't already exist. The \a flags parameter + is directly passed into a call to khc_open_space(). + + \param[in] plugin Name of the plugin. The name can not contain + slashes. + + \param[out] result Receives a configuration space handle. The + calling application should free the handle using + khc_close_space(). + + \see khc_open_space() + \see khc_close_space() + */ +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result); + +/*! \brief Obtain the configuration space or a named module + + The named module does not have to actually exist. Configuration + spaces for modules are based on the basename of the module + (including the extension). + + \param[in] module Name of the module. + + \param[in] flags The flags used to call khc_open_space(). You can + use this to specify a particular configuration store if + needed. + + \param[out] result Receives the handle to a configuration space if + successful. Call khc_close_space() to close the handle. + + \see khc_open_space() + \see khc_close_space() +*/ +KHMEXP khm_int32 KHMAPI +kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result); + +/*! \brief Retrieve a handle to the configuration space for plugins + + The configuration space for plugins is a container which holds the + configuration subspaces for all the plugins. This is the config + space which must be used to load a configuration space for a + plugin. + + \param[in] flags The flags to pass in to the call to + khc_open_space(). The flags can be used to select a specific + configuration store if needed. + + \param[out] result Receives a handle to the configuration + space. Call khc_close_space() to close the handle + + \see khc_open_space() + \see khc_close_space() + */ +KHMEXP khm_int32 KHMAPI +kmm_get_plugins_config(khm_int32 flags, khm_handle * result); + +/*! \brief Retrieve the handle to the configuration space for modules + + The configuration space for modules is a container which hold the + configuration subspaces for all the modules. Each module + registration ends up in this subspace. + + \param[in] flags The flags to pass in to the call to + khc_open_space(). The flags can be used to select a specific + configuration store if needed. + + \param[out] result Receives a handle to the configuration space. + Call khc_close_space() to close the handle. + + \see khc_open_space() + \see khc_close_space() + */ +KHMEXP khm_int32 KHMAPI +kmm_get_modules_config(khm_int32 flags, khm_handle * result); + +/*! \brief Return information about a loaded module + + The retrieves a block of information about a module. Refer to + ::kmm_module_info for information about the format of the returned + data. + + Note that the size of the required buffer is actually greater than + the size of the ::kmm_module_info structure and accomodates the + ::kmm_plugin_info structures and strings required to complete the + information block. + + Call the function with \a buffer set to NULL and \a cb_buffer + pointing at a khm_size variable to obtain the required size of the + buffer. + + \param[in] module_name Name of a module + \param[in] flags Flags indicating which types of information to + return + \param[out] buffer Points to a buffer that recieves information. + Set this to NULL if only the size of the buffer is required. + \param[in,out] On entry, contains the size of the buffer pointed + to by \a buffer if \a buffer is not NULL. On exit, contains + the required size of the buffer or the number of actual bytes + copied. + + \retval KHM_ERROR_SUCCESS The requested information was copied + \retval KHM_ERROR_INVALID_PARAM One of the parameters was invalid + \retval KHM_ERROR_TOO_LONG The buffer was not large enough or was + NULL. The number of bytes requied is in \a cb_buffer. + \retval KHM_ERROR_NOT_FOUND The specified module is not a + registered module. + */ +KHMEXP khm_int32 KHMAPI +kmm_get_module_info(wchar_t * module_name, khm_int32 flags, + kmm_module_info * buffer, khm_size * cb_buffer); + +/*! \brief Get information about a module + + Similar to kmm_get_module_info(), but uses a module handle instead + of a name, and uses internal buffers for providing string fields. + + The information that is returned should be freed using a call to + kmm_release_module_info_i(). + + \see kmm_release_module_info_i() + */ +KHMEXP khm_int32 KHMAPI +kmm_get_module_info_i(kmm_module module, kmm_module_info * info); + +/*! \brief Release module information + + Releases the information returned by a previous call to + kmm_get_module_info_i(). The contents of the ::kmm_module_info + structure should not have been modified in any way between calling + kmm_get_module_info_i() and kmm_release_module_info_i(). + */ +KHMEXP khm_int32 KHMAPI +kmm_release_module_info_i(kmm_module_info * info); + +/*! \brief Obtain information about a plugin + + Retrieve a block of information about a plugin. See + ::kmm_plugin_info for details about what information can be + returned. Note that some fields may not be available if the + module is not loaded. + + Note that the size of the required buffer is greater than the size + of the ::kmm_plugin_info structure and accounts for strings as + well. Call kmm_get_plugin_info() with \a buffer set to NULL and + \a cb_buffer set to point to a variable of type \a khm_size to + obtain the required size of the structure. + + \param[in] plugin_name Name of the plugin + \param[out] buffer The buffer to receive the plugin information. + Set to \a NULL if only the size of the buffer is required. + \param[in,out] cb_buffer On entry, points to variable that + specifies the size of the buffer pointed to by \a buffer is \a + buffer is not \a NULL. On exit, holds the number of bytes + copied or the required size of the buffer. + + \retval KHM_ERROR_SUCCESS The requested information was + successfully copied to the \a buffer + \retval KHM_ERROR_TOO_LONG The buffer was either \a NULL or + insufficient to hold the requested information. The required + size of the buffer was stored in \a cb_buffer + \retval KHM_ERROR_INVALID_PARAM One or more parameters were + invlaid. + \retval KHM_ERROR_NOT_FOUND The specified plugin was not found + among the registered plugins. +*/ +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_info(wchar_t * plugin_name, + kmm_plugin_info * buffer, + khm_size * cb_buffer); + +/*! \brief Obtain information about a plugin using a plugin handle + + Similar to kmm_get_plugin_info() but uses a plugin handle instead + of a plugin name. If the call is successful, the \a info + structure will be filled with information about the plugin. The + returned info should not be modified in any way and may contain + pointers to internal buffers. + + The returned information must be released with a call to + kmm_release_plugin_info_i(). + */ +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info); + +/*! \brief Release plugin information returned by kmm_get_plugin_info_i + + The information returned by kmm_get_plugin_info_i() should not be + modified in any way before calling kmm_release_plugin_info_i(). + Once the call completes, the contents of \a info will be + initialized to zero. + */ +KHMEXP khm_int32 KHMAPI +kmm_release_plugin_info_i(kmm_plugin_info * info); + +/*! \brief Enumerates plugins + + Enumerates through known plugins. This list may not include + plugins which were not loaded by NetIDMgr in this session. + + If the call is successful, a handle to the next plugin in the list + will be placed in \a p_next. The returned handle must be freed + with a call to kmm_release_plugin(). + + If the \a p parameter is set to NULL, then the first plugin handle + will be placed in \a p_next. The handles will not be returned in + any specific order. In addition, the enumeration may not include + all known plugins if the list of plugins changes during + enumeration. + */ +KHMEXP khm_int32 KHMAPI +kmm_get_next_plugin(kmm_plugin p, kmm_plugin * p_next); + +/*! \brief Register a plugin + + The \a plugin member defines the plugin to be registered. The \a + msg_proc and \a icon members of the structure are ignored. + + At the time kmm_register_plugin() is called, the module specified + by \a module member of the \a plugin parameter must have been already + registered. Otherwise the function call fails. + + If the plugin has already been registered, then all the fields in + the plugin registration will be updated to be in sync with the + information provided in the \a plugin parameter. The failure + counts and associated statistics will not be reset when the + configuration information is updated. + + If the plugin has not been registered, the a new registration + entry is created in the configuration space indicated by the \a + config_flags parameter. In addition, the plugin will be added to + the list of plugins associated with the owning module. + + Note that the module that owns the plugin must be registered in + the same configuration store as the plugin. + + \param[in] plugin Registration info for the plugin. The \a + msg_proc and \a icon members are ignored. All other fields + are required. The \a description member should be localized + to the system locale when registering a plugin in the machine + configuration store and should be localized to the user locale + when registering a plugin in the user configuration store. + \param[in] config_flags Flags for the configuration provider. + These flags are used verbatim to call khc_open_space(), hence + they may be used to pick whether or not the registration is + per machine or per user. + + \see kmm_register_module() + */ +KHMEXP khm_int32 KHMAPI +kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags); + +/*! \brief Register a module + + The \a module parameter specifies the parameters for the module + registration. + + The \a plugin_info member should point to an array of + ::kmm_plugin_info structures unless the \a n_plugins member is + zero, in which case \a plugin_info can be \a NULL. Plugins can be + registered separately using kmm_register_plugin(). + + \param[in] module Information about the module. The name and path + fields are required. The \a plugin_info field can only be \a + NULL if \a n_plugins is zero. + + \param[in] config_flags Flags used to call khc_open_space(). This + can be used to choose the configuration store in which the + module registration will be performed. + */ +KHMEXP khm_int32 KHMAPI +kmm_register_module(kmm_module_reg * module, khm_int32 config_flags); + +/*! \brief Unregister a plugin + + Registration information associated with the plugin will be + removed. In addtion, the plugin will be removed from the list of + plugins provided by the owner module. + + \param[in] plugin Names the plugin to be removed + \param[in] config_flags Flags used to call khc_open_space(). Can + be used to choose the configuraiton store that is affected by + the call. + + \note kmm_unregister_plugin() has no effect on whether the plugin + is loaded or not. The caller must make sure that the plugin + is unloaded and the associated module is either also unloaded + or in a state where the plugin can be unregistered. + */ +KHMEXP khm_int32 KHMAPI +kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags); + +/*! \brief Unregister a module + + Registration information associated with the module as well as all + the plugins provided by the module will be removed from the + configuration store. + + \param[in] module Names the module to be removed + + \param[in] config_flags Flags used to call khc_open_space(). Can + be used to choose the configuration store affected by the + call. + + \note kmm_unregister_module() has no effect on the loaded state of + the module. The caller should make sure that the module is + unloaded and in a state where it can be unregistered. + */ +KHMEXP khm_int32 KHMAPI +kmm_unregister_module(wchar_t * module, khm_int32 config_flags); + +/*@}*/ /* kmm_reg */ + +/*! \defgroup kmm_loc Internationalization support + + See \ref pi_localization for more information about + internationalization. + +@{*/ + +/*! \brief Locale descriptor record + + See kmm_set_locale() +*/ +typedef struct tag_kmm_module_locale { + khm_ui_4 language; /*!< A language ID. On Windows, you can use the + MAKELANGID macro to generate this value. */ + wchar_t * filename; /*!< The filename corresponding to this language. + Use NULL to indicate that resources for this + language are to be found in the main module. */ + khm_int32 flags; /*!< Flags. Combination of KMM_MLOC_FLAG_* */ +} kmm_module_locale; + +#define LOCALE_DEF(language_id, filename, flags) {language_id, filename, flags} + +/*! \brief Default (fallback) locale +*/ +#define KMM_MLOC_FLAG_DEFAULT 1 + + +/*! \brief Sets the locale for a loaded module. + + The given locale records are searched in the given order until a + locale that matches the current user locale is found. If no + locales match, then the first locale with the + ::KMM_MLOC_FLAG_DEFAULT flag set will be loaded. If no locales + have that flag set, then the first locale is loaded. + + You can obtain a handle to the loaded library using + kmm_get_resource_hmodule(). This function does not return until a + matched library is loaded. + + Note that the ::kmm_module_locale structure only specifies a + module name for the resource module. This resource module must + exist in the same directory as the \a module. + + \param[in] module The module handle + \param[in] locales An array of ::kmm_module_locale objects + \param[in] n_locales The number of objects in the array pointed to by \a locales + + \retval KHM_ERROR_SUCCESS Succeeded. + \retval KHM_ERROR_NOT_FOUND A matching locale resource library was not found. + \retval KHM_ERROR_INVALID_OPERATION The function was called on a module which is currently not being initalized. + + \see \ref pi_localization + \see kmm_get_resource_hmodule() + + \note This can only be called when handing init_module() +*/ +KHMEXP khm_int32 KHMAPI +kmm_set_locale_info(kmm_module module, + kmm_module_locale * locales, + khm_int32 n_locales); + +#ifdef _WIN32 + +/*! \brief Return the Windows module handle of the resource library of a NetIDMgr module. + + NetIDMgr allows the specification of an alternate resource library + that will be used to load localized resources from. This function + returns a handle to this library. + + While you can use the convenience macros to access resources in a + localization library using the module handle, it is recommended, + for performance reasons, to use this function to obtain the handle + to the resource library and then use that handle in calls to + LoadString, LoadImage etc. directly. +*/ +KHMEXP HMODULE KHMAPI +kmm_get_resource_hmodule(kmm_module m); + +/*! \name Convenience Macros +@{*/ +/*! \brief Convenience macro for using calling LoadAccelerators using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadAccelerators(module, lpTableName) \ + (LoadAccelerators(kmm_get_resource_hmodule(module), lpTableName)) + +/*! \brief Convenience macro for using calling LoadBitmap using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadBitmap(module, lpBitmapName) \ + (LoadBitmap(kmm_get_resource_hmodule(module), lpBitmapName)) + +/*! \brief Convenience macro for using calling LoadImage using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadImage(module, lpszName, uType, cxDesired, cyDesired, fuLoad) \ + (LoadImage(kmm_get_resource_hmodule(module), lpszName, uType, cxDesired, cyDesired, fuLoad)) + +/*! \brief Convenience macro for using calling LoadCursor using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadCursor(module, lpCursorName) \ + (LoadCursor(kmm_get_resource_hmodule(module), lpCursorName)) + +/*! \brief Convenience macro for using calling LoadIcon using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadIcon(module, lpIconName) \ + (LoadIcon(kmm_get_resource_hmodule(module), lpIconName)) + +/*! \brief Convenience macro for using calling LoadMenu using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadMenu(module, lpMenuName) \ + (LoadMenu(kmm_get_resource_hmodule(module), lpMenuName)) + +/*! \brief Convenience macro for using calling LoadString using a module handle + + \param[in] module A handle to a loaded module. The corresponding resource + module will be located through a call to kmm_get_resource_hmodule() +*/ +#define kmm_LoadString(module, uID, lpBuffer, nBufferMax) \ + (LoadString(kmm_get_resource_hmodule(module), uID, lpBuffer, nBufferMax)) +/*@}*/ /* Convenience Macros */ +#endif +/*@}*/ /* group kmm_loc */ +/*@}*/ /* group kmm */ +#endif diff --git a/mechglue/src/windows/identity/kmm/kmm_module.c b/mechglue/src/windows/identity/kmm/kmm_module.c new file mode 100644 index 000000000..d5a61c740 --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmm_module.c @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include + +kmm_module_i * kmmint_get_module_i(wchar_t * name) +{ + kmm_module_i * m; + size_t sz; + + if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &sz))) + return NULL; + sz += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmm); + m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name); + + if(m == NULL) { + m = PMALLOC(sizeof(kmm_module_i)); + ZeroMemory(m, sizeof(kmm_module_i)); + + m->magic = KMM_MODULE_MAGIC; + m->name = PMALLOC(sz); + StringCbCopy(m->name, sz, name); + m->state = KMM_MODULE_STATE_NONE; + + hash_add(hash_modules, (void *) m->name, (void *) m); + LPUSH(&kmm_all_modules, m); + } + LeaveCriticalSection(&cs_kmm); + + return m; +} + +kmm_module_i * kmmint_find_module_i(wchar_t * name) +{ + kmm_module_i * m; + + EnterCriticalSection(&cs_kmm); + m = (kmm_module_i *) hash_lookup(hash_modules, (void *) name); + LeaveCriticalSection(&cs_kmm); + + return m; +} + +/* called with cs_kmm held */ +void kmmint_free_module(kmm_module_i * m) +{ + m->magic = 0; + + hash_del(hash_modules, m->name); + LDELETE(&kmm_all_modules, m); + + if (m->name) + PFREE(m->name); + + if (m->description) + PFREE(m->description); + + if (m->path) + PFREE(m->path); + + if (m->vendor) + PFREE(m->vendor); + + if (m->support) + PFREE(m->support); + + if (m->version_info) + PFREE(m->version_info); + + PFREE(m); + + if (kmm_all_modules == NULL) + SetEvent(evt_exit); +} + +KHMEXP khm_int32 KHMAPI kmm_hold_module(kmm_module module) +{ + if(!kmm_is_module(module)) + return KHM_ERROR_INVALID_PARAM; + EnterCriticalSection(&cs_kmm); + kmm_module_from_handle(module)->refcount++; + LeaveCriticalSection(&cs_kmm); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kmm_release_module(kmm_module vm) +{ + kmm_module_i * m; + if(!kmm_is_module(vm)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmm); + m = kmm_module_from_handle(vm); + if(! --(m->refcount)) + { + /* note that a 0 ref count means that there are no active + plugins */ + kmmint_free_module(m); + } + LeaveCriticalSection(&cs_kmm); + return KHM_ERROR_SUCCESS; +} + +khm_int32 +kmmint_check_api_version(DWORD v) { + /* for now, we require an exact match. In the future when we are + swamped with so much time that we don't know what to do with + it, we can actually parse the apiversion.txt file and create a + compatibility table which we can check against the functions + used by the module and decide whether or not it is + compatible. */ + + if (v != KH_VERSION_API) + return KHM_ERROR_INCOMPATIBLE; + else + return KHM_ERROR_SUCCESS; +} + +struct lang_code { + WORD language; + WORD codepage; +}; + +khm_int32 +kmmint_read_module_info(kmm_module_i * m) { + /* the only fields we can count on at this point are m->name and + m->path */ + DWORD t; + size_t cb; + WORD lang; + khm_int32 rv = KHM_ERROR_SUCCESS; + struct lang_code *languages; + int n_languages; + int i; + wchar_t resname[256]; /* the resource names are a lot shorter */ + wchar_t * r; + VS_FIXEDFILEINFO *vff; + + assert(m->name); + assert(m->path); + + t = TRUE; + cb = GetFileVersionInfoSize(m->path, + &t); + /* if successful, cb gets the size in bytes of the version info + structure and sets t to zero */ + if (t) { + return KHM_ERROR_NOT_FOUND; + } else if (cb == 0) { + _report_mr1(KHERR_WARNING, MSG_RMI_NOT_FOUND, _dupstr(m->path)); + return KHM_ERROR_INVALID_PARAM; + } + + if (m->version_info) { + PFREE(m->version_info); + m->version_info = NULL; + } + + m->version_info = PMALLOC(cb); +#ifdef DEBUG + assert(m->version_info); +#endif + + if(!GetFileVersionInfo(m->path, + t, (DWORD) cb, m->version_info)) { + rv = KHM_ERROR_NOT_FOUND; + _report_mr1(KHERR_WARNING, MSG_RMI_NOT_FOUND, _dupstr(m->path)); + _location(L"GetFileVersionInfo"); + goto _cleanup; + } + + if(!VerQueryValue(m->version_info, + L"\\VarFileInfo\\Translation", + (LPVOID*) &languages, + &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_NO_TRANS, _dupstr(m->path)); + _location(L"VerQueryValue"); + goto _cleanup; + } + + n_languages = (int) (cb / sizeof(*languages)); + + /* Try searching for the user's default language first */ + lang = GetUserDefaultLangID(); + for (i = 0; i < n_languages; i++) { + if(languages[i].language == lang) + break; + } + + /* If not, try the system default */ + if (i >= n_languages) { + lang = GetSystemDefaultLangID(); + for (i=0; i= n_languages) { + lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); + for (i=0; i= n_languages) { + lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); + for (i=0; i= n_languages) { + i = 0; + } + + if (i >= n_languages) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr0(KHERR_WARNING, MSG_RMI_NO_LOCAL); + goto _cleanup; + } + + /* check module name */ + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_MODULE), + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(TEXT(NIMV_MODULE))); + goto _cleanup; + } + + if (cb > KMM_MAXCB_NAME || + FAILED(StringCbLength(r, KMM_MAXCB_NAME, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(TEXT(NIMV_MODULE))); + goto _cleanup; + } + + if (wcscmp(r, m->name)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr2(KHERR_WARNING, MSG_RMI_MOD_MISMATCH, + _dupstr(r), _dupstr(m->name)); + goto _cleanup; + } + + /* check API version */ + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_APIVER), + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(TEXT(NIMV_APIVER))); + goto _cleanup; + } + + if (cb > KMM_MAXCB_NAME || + FAILED(StringCbLength(r, KMM_MAXCB_NAME, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(TEXT(NIMV_APIVER))); + goto _cleanup; + } + + t = wcstol(r, NULL, 10); + + rv = kmmint_check_api_version(t); + + if (KHM_FAILED(rv)) { + _report_mr2(KHERR_WARNING, MSG_RMI_API_MISMATCH, + _int32(t), _int32(KH_VERSION_API)); + goto _cleanup; + } + + /* Looks good. Now load the description, copyright, support URI + and file versions */ + if (m->description) { + PFREE(m->description); + m->description = NULL; + } + + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\FileDescription", + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(L"FileDescription")); + goto _cleanup; + } + + if (cb > KMM_MAXCB_DESC || + FAILED(StringCbLength(r, KMM_MAXCB_DESC, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(L"FileDescription")); + goto _cleanup; + } + + cb += sizeof(wchar_t); + + m->description = PMALLOC(cb); +#ifdef DEBUG + assert(m->description); +#endif + StringCbCopy(m->description, cb, r); + + /* on to the support URI */ + if (m->support) { + PFREE(m->support); + m->support = NULL; + } + + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\" TEXT(NIMV_SUPPORT), + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(TEXT(NIMV_SUPPORT))); + goto _cleanup; + } + + if (cb > KMM_MAXCB_SUPPORT || + FAILED(StringCbLength(r, KMM_MAXCB_SUPPORT, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(TEXT(NIMV_SUPPORT))); + goto _cleanup; + } + + cb += sizeof(wchar_t); + + m->support = PMALLOC(cb); +#ifdef DEBUG + assert(m->support); +#endif + StringCbCopy(m->support, cb, r); + + /* the vendor/copyright */ + if (m->vendor) { + PFREE(m->vendor); + m->vendor = NULL; + } + + StringCbPrintf(resname, sizeof(resname), + L"\\StringFileInfo\\%04x%04x\\LegalCopyright", + languages[i].language, + languages[i].codepage); + + if (!VerQueryValue(m->version_info, + resname, (LPVOID *) &r, &cb)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(L"LegalCopyright")); + goto _cleanup; + } + + if (cb > KMM_MAXCB_SUPPORT || + FAILED(StringCbLength(r, KMM_MAXCB_SUPPORT, &cb))) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_TOO_LONG, + _cstr(L"LegalCopyright")); + goto _cleanup; + } + + cb += sizeof(wchar_t); + + m->vendor = PMALLOC(cb); +#ifdef DEBUG + assert(m->vendor); +#endif + StringCbCopy(m->vendor, cb, r); + + if (!VerQueryValue(m->version_info, + L"\\", + (LPVOID *) &vff, + &cb) || + cb != sizeof(*vff)) { + + rv = KHM_ERROR_INVALID_PARAM; + _report_mr1(KHERR_WARNING, MSG_RMI_RES_MISSING, + _cstr(L"Fixed Version Info")); + goto _cleanup; + } + + m->file_version.major = HIWORD(vff->dwFileVersionMS); + m->file_version.minor = LOWORD(vff->dwFileVersionMS); + m->file_version.patch = HIWORD(vff->dwFileVersionLS); + m->file_version.aux = LOWORD(vff->dwFileVersionLS); + + m->prod_version.major = HIWORD(vff->dwProductVersionMS); + m->prod_version.minor = LOWORD(vff->dwProductVersionMS); + m->prod_version.patch = HIWORD(vff->dwProductVersionLS); + m->prod_version.aux = LOWORD(vff->dwProductVersionLS); + + rv = KHM_ERROR_SUCCESS; + + _cleanup: + if (KHM_FAILED(rv)) { + if (m->version_info) { + PFREE(m->version_info); + m->version_info = NULL; + } + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI kmm_load_module(wchar_t * modname, + khm_int32 flags, + kmm_module * result) +{ + kmm_module_i * m = NULL; + kmm_module_i * mi; + size_t cbsize; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(FAILED(StringCbLength(modname, KMM_MAXCB_NAME, &cbsize))) + return KHM_ERROR_INVALID_PARAM; + cbsize += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmm); + mi = kmmint_find_module_i(modname); + + if(mi != NULL) { + kmm_hold_module(kmm_handle_from_module(mi)); + /* check if the module has either failed to load either or if + it has been terminated. If so, we try once again to load the + module. */ + if(!(flags & KMM_LM_FLAG_NOLOAD) && + (mi->state < 0 || mi->state == KMM_MODULE_STATE_EXITED)) + { + mi->state = KMM_MODULE_STATE_PREINIT; + } + } + LeaveCriticalSection(&cs_kmm); + + if(flags & KMM_LM_FLAG_NOLOAD) { + if(result) + *result = mi; + else if(mi) + kmm_release_module(kmm_handle_from_module(mi)); + + return (mi)? KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; + } + + if(mi) { + m = mi; + } else { + m = kmmint_get_module_i(modname); + m->state = KMM_MODULE_STATE_PREINIT; + kmm_hold_module(kmm_handle_from_module(m)); + } + + /* the module is already running or is already being + worked on by the registrar */ + if(m->state != KMM_MODULE_STATE_PREINIT) { + if(result) + *result = kmm_handle_from_module(m); + else + kmm_release_module(kmm_handle_from_module(m)); + + return KHM_ERROR_EXISTS; + } + + kmmint_add_to_module_queue(); + + if(flags & KMM_LM_FLAG_SYNC) { + kmm_hold_module(kmm_handle_from_module(m)); + kmq_send_message(KMSG_KMM, + KMSG_KMM_I_REG, + KMM_REG_INIT_MODULE, + (void*) m); + if(m->state <= 0) { + /* failed to load ? */ + if(m->state == KMM_MODULE_STATE_FAIL_NOT_FOUND) + rv = KHM_ERROR_NOT_FOUND; + else if(m->state == KMM_MODULE_STATE_FAIL_SIGNATURE) + rv = KHM_ERROR_INVALID_SIGNATURE; + else + rv = KHM_ERROR_UNKNOWN; + + kmm_release_module(kmm_handle_from_module(m)); + if(result) + *result = NULL; + } else { + if(result) + *result = kmm_handle_from_module(m); + else + kmm_release_module(kmm_handle_from_module(m)); + } + } else { + kmm_hold_module(kmm_handle_from_module(m)); + kmq_post_message(KMSG_KMM, + KMSG_KMM_I_REG, + KMM_REG_INIT_MODULE, + (void*) m); + if(result) + *result = kmm_handle_from_module(m); + else + kmm_release_module(kmm_handle_from_module(m)); + } + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_module_state(kmm_module m) +{ + if(!kmm_is_module(m)) + return KMM_MODULE_STATE_NONE; + else + return kmm_module_from_handle(m)->state; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_module_info_i(kmm_module vm, kmm_module_info * info) { + kmm_module_i * m; + khm_int32 rv; + + EnterCriticalSection(&cs_kmm); + if (!kmm_is_module(vm) || !info) + rv = KHM_ERROR_INVALID_PARAM; + else { + m = kmm_module_from_handle(vm); + + ZeroMemory(info, sizeof(*info)); + + info->reg.name = m->name; + info->reg.path = m->path; + info->reg.vendor = m->vendor; + + info->reg.n_plugins = m->plugin_count; + + info->state = m->state; + + info->h_module = vm; + kmm_hold_module(vm); + + rv = KHM_ERROR_SUCCESS; + } + LeaveCriticalSection(&cs_kmm); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_release_module_info_i(kmm_module_info * info) { + if (info->h_module) + kmm_release_module(info->h_module); + + ZeroMemory(info, sizeof(*info)); + + return KHM_ERROR_SUCCESS; +} + + +KHMEXP khm_int32 KHMAPI +kmm_unload_module(kmm_module module) { + + if(!kmm_is_module(module)) + return KHM_ERROR_INVALID_PARAM; + + kmm_hold_module(module); + kmq_post_message(KMSG_KMM, + KMSG_KMM_I_REG, + KMM_REG_EXIT_MODULE, + (void *) kmm_module_from_handle(module)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmm_load_default_modules(void) { + khm_handle csm = NULL; + khm_handle cs_mod = NULL; + khm_int32 rv; + wchar_t buf[KMM_MAXCCH_NAME]; + khm_size s; + + rv = kmm_get_modules_config(0, &csm); + if(KHM_FAILED(rv)) + return rv; + + _report_mr0(KHERR_NONE, MSG_LOAD_DEFAULT); + _describe(); + + kmmint_add_to_module_queue(); + + while(KHM_SUCCEEDED(khc_enum_subspaces(csm, cs_mod, &cs_mod))) { + + s = sizeof(buf); + if (KHM_FAILED(khc_get_config_space_name(cs_mod, buf, &s))) + continue; + + /* check for schema subspace. This is not an actual module. */ + if (!wcscmp(buf, L"_Schema")) + continue; + + kmm_load_module(buf, 0, NULL); + } + + kmmint_remove_from_module_queue(); + + if(csm) + khc_close_space(csm); + + return rv; +} + +#ifdef _WIN32 +KHMEXP HMODULE KHMAPI +kmm_get_hmodule(kmm_module m) +{ + if(!kmm_is_module(m)) + return NULL; + else + return kmm_module_from_handle(m)->h_module; +} +#endif diff --git a/mechglue/src/windows/identity/kmm/kmm_plugin.c b/mechglue/src/windows/identity/kmm/kmm_plugin.c new file mode 100644 index 000000000..b8a90c9fe --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmm_plugin.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +/* Called with no locks held to get a kmm_plugin_i structure + that matches the name. First we look in the hash table, and + if one isn't found, we create an empty one. +*/ + +kmm_plugin_i * +kmmint_get_plugin_i(wchar_t * name) +{ + kmm_plugin_i * p; + size_t cb; + + if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &cb))) + return NULL; + cb += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmm); + p = (kmm_plugin_i *) hash_lookup(hash_plugins, (void *) name); + + if(p == NULL) { + p = PMALLOC(sizeof(kmm_plugin_i)); + ZeroMemory(p, sizeof(kmm_plugin_i)); + p->magic = KMM_PLUGIN_MAGIC; + p->p.name = PMALLOC(cb); + StringCbCopy(p->p.name, cb, name); + p->state = KMM_PLUGIN_STATE_NONE; + + hash_add(hash_plugins, (void *) p->p.name, (void *) p); + kmmint_list_plugin(p); + } + LeaveCriticalSection(&cs_kmm); + + return p; +} + +kmm_plugin_i * +kmmint_find_plugin_i(wchar_t * name) +{ + kmm_plugin_i * p; + size_t cb; + + if(FAILED(StringCbLength(name, KMM_MAXCB_NAME, &cb))) + return NULL; + + EnterCriticalSection(&cs_kmm); + p = (kmm_plugin_i *) hash_lookup(hash_plugins, (void *) name); + LeaveCriticalSection(&cs_kmm); + + return p; +} + +/* the plugin must be delisted before calling this */ +void +kmmint_list_plugin(kmm_plugin_i * p) +{ + EnterCriticalSection(&cs_kmm); + if((p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) || + (p->flags & KMM_PLUGIN_FLAG_IN_LIST)) + { + RaiseException(2, EXCEPTION_NONCONTINUABLE, 0, NULL); + } + p->flags |= KMM_PLUGIN_FLAG_IN_LIST; + LPUSH(&kmm_listed_plugins, p); + LeaveCriticalSection(&cs_kmm); +} + +void +kmmint_delist_plugin(kmm_plugin_i * p) +{ + EnterCriticalSection(&cs_kmm); + if(p->flags & KMM_PLUGIN_FLAG_IN_LIST) { + p->flags &= ~KMM_PLUGIN_FLAG_IN_LIST; + LDELETE(&kmm_listed_plugins, p); + } + if(p->flags & KMM_PLUGIN_FLAG_IN_MODLIST) { + p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; + LDELETE(&(p->module->plugins), p); + } + LeaveCriticalSection(&cs_kmm); +} + +KHMEXP khm_int32 KHMAPI +kmm_hold_plugin(kmm_plugin p) +{ + kmm_plugin_i * pi; + + if(!kmm_is_plugin(p)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmm); + pi = kmm_plugin_from_handle(p); + pi->refcount++; + LeaveCriticalSection(&cs_kmm); + + return KHM_ERROR_SUCCESS; +} + +/* called with cs_kmm held */ +void +kmmint_free_plugin(kmm_plugin_i * pi) +{ + int i; + pi->magic = 0; + + hash_del(hash_plugins, (void *) pi->p.name); + + kmmint_delist_plugin(pi); + + for(i=0; in_dependants; i++) { + kmm_release_plugin(kmm_handle_from_plugin(pi->dependants[i])); + pi->dependants[i] = NULL; + } + + if(pi->module) { + kmm_release_module(kmm_handle_from_module(pi->module)); + } + + pi->module = NULL; + pi->p.module = NULL; + + if(pi->p.name) + PFREE(pi->p.name); + pi->p.name = NULL; + + if(pi->p.description) + PFREE(pi->p.description); + pi->p.description = NULL; + + if(pi->p.dependencies) + PFREE(pi->p.dependencies); + pi->p.dependencies = NULL; + + PFREE(pi); +} + +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_info_i(kmm_plugin p, kmm_plugin_info * info) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_i * pi; + khm_handle csp_plugin; + + if (!info) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmm); + if (!kmm_is_plugin(p)) { + rv = KHM_ERROR_INVALID_PARAM; + goto _cleanup; + } + + pi = kmm_plugin_from_handle(p); + + ZeroMemory(info, sizeof(*info)); + + info->reg = pi->p; + info->reg.msg_proc = NULL; + + if (KHM_FAILED(kmm_get_plugin_config(pi->p.name, KHM_PERM_READ, + &csp_plugin))) { + info->failure_count = 0; + *((khm_int64 *)&info->failure_time) = 0; + info->failure_reason = 0; + } else { + if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureCount", + &info->failure_count))) + info->failure_count = 0; + if (KHM_FAILED(khc_read_int64(csp_plugin, L"FailureTime", + (khm_int64 *) &info->failure_time))) + *((khm_int64 *) &info->failure_time) = 0; + if (KHM_FAILED(khc_read_int32(csp_plugin, L"FailureReason", + &info->failure_reason))) + info->failure_reason = 0; + + khc_close_space(csp_plugin); + } + + info->state = pi->state; + + info->h_plugin = p; + kmm_hold_plugin(p); + + _cleanup: + LeaveCriticalSection(&cs_kmm); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_release_plugin_info_i(kmm_plugin_info * info) { + khm_int32 rv; + + if (!info || !info->h_plugin) + return KHM_ERROR_INVALID_PARAM; + + rv = kmm_release_plugin(info->h_plugin); + + ZeroMemory(info, sizeof(info)); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_next_plugin(kmm_plugin p, kmm_plugin * p_next) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_i * pi; + kmm_plugin_i * pi_next = NULL; + kmm_module_i * m; + + EnterCriticalSection(&cs_kmm); + if (p == NULL) { + if (kmm_listed_plugins) + pi_next = kmm_listed_plugins; + else { + for (m = kmm_all_modules; m; m = LNEXT(m)) { + if (m->plugins) { + pi_next = m->plugins; + break; + } + } + } + } else if (kmm_is_plugin(p)) { + pi = kmm_plugin_from_handle(p); + pi_next = LNEXT(pi); + + if (!pi_next) { + /* we have either exhausted the listed plugins or we are + at the end of the module's plugin list */ + if (pi->module) { + m = LNEXT(pi->module); + } else { + m = kmm_all_modules; + } + + for(; m; m = LNEXT(m)) { + if (m->plugins) { + pi_next = m->plugins; + break; + } + } + } + } + + if (pi_next) { + *p_next = kmm_handle_from_plugin(pi_next); + kmm_hold_plugin(*p_next); + } else { + *p_next = NULL; + rv = KHM_ERROR_NOT_FOUND; + } + + LeaveCriticalSection(&cs_kmm); + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_release_plugin(kmm_plugin p) +{ + kmm_plugin_i * pi; + + if(!kmm_is_plugin(p)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmm); + pi = kmm_plugin_from_handle(p); + pi->refcount--; + if(pi->refcount == 0) { + kmmint_free_plugin(pi); + } + LeaveCriticalSection(&cs_kmm); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmm_provide_plugin(kmm_module module, kmm_plugin_reg * plugin) +{ + kmm_module_i * m; + kmm_plugin_i * p; + size_t cb_name = 0; + size_t cb_desc = 0; + size_t cb_dep = 0; + + m = kmm_module_from_handle(module); + + /* can only called when handing init_module() */ + if(m->state != KMM_MODULE_STATE_INIT) + return KHM_ERROR_INVALID_OPERATION; + + if(!plugin || + FAILED(StringCbLength(plugin->name, KMM_MAXCB_NAME - sizeof(wchar_t), + &cb_name)) || + (plugin->description && + FAILED(StringCbLength(plugin->description, + KMM_MAXCB_DESC - sizeof(wchar_t), + &cb_desc))) || + (plugin->dependencies && + KHM_FAILED(multi_string_length_cb(plugin->dependencies, + KMM_MAXCB_DEPS, &cb_dep)))) { + return KHM_ERROR_INVALID_PARAM; + } + + cb_name += sizeof(wchar_t); + cb_desc += sizeof(wchar_t); + + p = kmmint_get_plugin_i(plugin->name); + + /* released below or in kmm_init_module() */ + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + if(p->state != KMM_PLUGIN_STATE_NONE && + p->state != KMM_PLUGIN_STATE_PLACEHOLDER) + { + kmm_release_plugin(kmm_handle_from_plugin(p)); + return KHM_ERROR_DUPLICATE; + } + + /* released when the plugin quits */ + kmm_hold_module(module); + + p->module = m; + p->p.flags = plugin->flags; + p->p.msg_proc = plugin->msg_proc; + p->p.type = plugin->type; + + if(plugin->description) { + p->p.description = PMALLOC(cb_desc); + StringCbCopy(p->p.description, cb_desc, plugin->description); + } else + p->p.description = NULL; + + if(plugin->dependencies) { + p->p.dependencies = PMALLOC(cb_dep); + multi_string_copy_cb(p->p.dependencies, cb_dep, plugin->dependencies); + } else + p->p.dependencies = NULL; + + p->p.module = p->module->name; + + p->p.icon = plugin->icon; + + p->state = KMM_PLUGIN_STATE_REG; + + kmmint_delist_plugin(p); + EnterCriticalSection(&cs_kmm); + LPUSH(&(m->plugins), p); + p->flags |= KMM_PLUGIN_FLAG_IN_MODLIST; + LeaveCriticalSection(&cs_kmm); + + /* leave the plugin held because it is in the module's plugin list */ + return KHM_ERROR_SUCCESS; +} + diff --git a/mechglue/src/windows/identity/kmm/kmm_reg.c b/mechglue/src/windows/identity/kmm/kmm_reg.c new file mode 100644 index 000000000..131cb7514 --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmm_reg.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +KHMEXP khm_int32 KHMAPI +kmm_get_module_info(wchar_t * module_name, khm_int32 flags, + kmm_module_info * buffer, khm_size * cb_buffer) +{ + /*TODO:Implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_info(wchar_t * plugin_name, + kmm_plugin_info * buffer, khm_size * cb_buffer) +{ + /*TODO:Implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +KHMEXP khm_int32 KHMAPI +kmm_get_plugins_config(khm_int32 flags, khm_handle * result) { + khm_handle csp_root; + khm_handle csp_plugins; + khm_int32 rv; + + rv = khc_open_space(KHM_INVALID_HANDLE, KMM_CSNAME_ROOT, flags, &csp_root); + + if(KHM_FAILED(rv)) + return rv; + + rv = khc_open_space(csp_root, KMM_CSNAME_PLUGINS, flags, &csp_plugins); + khc_close_space(csp_root); + + if(KHM_SUCCEEDED(rv)) + *result = csp_plugins; + else + *result = NULL; + + return rv; +} + + +KHMEXP khm_int32 KHMAPI +kmm_get_modules_config(khm_int32 flags, khm_handle * result) { + khm_handle croot; + khm_handle kmm_all_modules; + khm_int32 rv; + + rv = khc_open_space(NULL, KMM_CSNAME_ROOT, flags, &croot); + + if(KHM_FAILED(rv)) + return rv; + + rv = khc_open_space(croot, KMM_CSNAME_MODULES, flags, &kmm_all_modules); + khc_close_space(croot); + + if(KHM_SUCCEEDED(rv)) + *result = kmm_all_modules; + else + *result = NULL; + + return rv; +} + + +KHMEXP khm_int32 KHMAPI +kmm_get_plugin_config(wchar_t * plugin, khm_int32 flags, khm_handle * result) +{ + khm_handle csplugins; + khm_handle csplugin; + khm_int32 rv; + + if(!plugin || wcschr(plugin, L'/') || wcschr(plugin, L'\\')) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(kmm_get_plugins_config(flags, &csplugins))) + return KHM_ERROR_UNKNOWN; + + rv = khc_open_space(csplugins, plugin, flags, &csplugin); + *result = csplugin; + + khc_close_space(csplugins); + + return rv; +} + + +KHMEXP khm_int32 KHMAPI +kmm_get_module_config(wchar_t * module, khm_int32 flags, khm_handle * result) +{ + khm_handle csmodules; + khm_handle csmodule; + khm_int32 rv; + + if(!module || wcschr(module, L'/') || wcschr(module, L'\\')) + return KHM_ERROR_INVALID_PARAM; + + if(KHM_FAILED(kmm_get_modules_config(flags, &csmodules))) + return KHM_ERROR_UNKNOWN; + + rv = khc_open_space(csmodules, module, flags, &csmodule); + *result = csmodule; + + khc_close_space(csmodules); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_register_plugin(kmm_plugin_reg * plugin, khm_int32 config_flags) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle csp_plugin = NULL; + khm_handle csp_module = NULL; + size_t cch; + + /* avoid accidently creating the module key if it doesn't exist */ + config_flags &= ~KHM_FLAG_CREATE; + + if((plugin == NULL) || + (plugin->dependencies && + KHM_FAILED(multi_string_length_cch(plugin->dependencies, + KMM_MAXCCH_DEPS, &cch))) || + FAILED(StringCchLength(plugin->module, KMM_MAXCCH_NAME, &cch)) || + (plugin->description && + FAILED(StringCchLength(plugin->description, + KMM_MAXCCH_DESC, &cch))) || + FAILED(StringCchLength(plugin->name, KMM_MAXCCH_NAME, &cch))) + { + return KHM_ERROR_INVALID_PARAM; + } + + /* note that we are retaining the length of the plugin name in + chars in cch */ + cch ++; + +#define CKRV if(KHM_FAILED(rv)) goto _exit + + rv = kmm_get_plugin_config(plugin->name, + config_flags | KHM_FLAG_CREATE, &csp_plugin); + CKRV; + + /* should fail if the module key doesn't exist */ + rv = kmm_get_module_config(plugin->module, config_flags, &csp_module); + CKRV; + + /*TODO: Make sure that the module registration is in the same + config store as the one in which the plugin is going to be + registered */ + + rv = khc_write_string(csp_plugin, L"Module", plugin->module); + CKRV; + if(plugin->description) { + rv = khc_write_string(csp_plugin, L"Description", plugin->description); + CKRV; + } + + if(plugin->dependencies) { + rv = khc_write_multi_string(csp_plugin, L"Dependencies", + plugin->dependencies); + CKRV; + } + + rv = khc_write_int32(csp_plugin, L"Type", plugin->type); + CKRV; + rv = khc_write_int32(csp_plugin, L"Flags", plugin->flags); + CKRV; + + { + khm_size cb = 0; + wchar_t * pl = NULL; + size_t scb = 0; + + rv = khc_read_multi_string(csp_module, L"PluginList", NULL, &cb); + if(rv != KHM_ERROR_TOO_LONG) + goto _exit; + + cb += cch * sizeof(wchar_t); + scb = cb; + + pl = PMALLOC(cb); + + rv = khc_read_multi_string(csp_module, L"PluginList", pl, &cb); + if(KHM_FAILED(rv)) { + if(pl) + PFREE(pl); + goto _exit; + } + + if(!multi_string_find(pl, plugin->name, 0)) { + multi_string_append(pl, &scb, plugin->name); + rv = khc_write_multi_string(csp_module, L"PluginList", pl); + } + + PFREE(pl); + CKRV; + } + +#undef CKRV + +_exit: + if(csp_plugin) + khc_close_space(csp_plugin); + if(csp_module) + khc_close_space(csp_module); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_register_module(kmm_module_reg * module, khm_int32 config_flags) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle csp_module = NULL; + size_t cch; + int i; + + if((module == NULL) || + FAILED(StringCchLength(module->name, KMM_MAXCCH_NAME, &cch)) || + (module->description && + FAILED(StringCchLength(module->description, + KMM_MAXCCH_DESC, &cch))) || + FAILED(StringCchLength(module->path, MAX_PATH, &cch)) || + (module->n_plugins > 0 && module->plugin_reg_info == NULL)) { + return KHM_ERROR_INVALID_PARAM; + } + +#define CKRV if(KHM_FAILED(rv)) goto _exit + + rv = kmm_get_module_config(module->name, config_flags | KHM_FLAG_CREATE, + &csp_module); + CKRV; + + rv = khc_write_string(csp_module, L"ImagePath", module->path); + CKRV; + + rv = khc_write_int32(csp_module, L"Flags", 0); + CKRV; + + /* FileVersion and ProductVersion will be set when the module + is loaded for the first time */ + + for(i=0; in_plugins; i++) { + rv = kmm_register_plugin(&(module->plugin_reg_info[i]), config_flags); + CKRV; + } + +#undef CKRV +_exit: + if(csp_module) + khc_close_space(csp_module); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +kmm_unregister_plugin(wchar_t * plugin, khm_int32 config_flags) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +KHMEXP khm_int32 KHMAPI +kmm_unregister_module(wchar_t * module, khm_int32 config_flags) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} diff --git a/mechglue/src/windows/identity/kmm/kmm_registrar.c b/mechglue/src/windows/identity/kmm/kmm_registrar.c new file mode 100644 index 000000000..1e632c7ba --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmm_registrar.c @@ -0,0 +1,922 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +static LONG pending_modules = 0; +static LONG pending_plugins = 0; +static LONG startup_signal = 0; +static BOOL load_done = FALSE; + +void +kmmint_check_completion(void) { + if (pending_modules == 0 && + pending_plugins == 0 && + InterlockedIncrement(&startup_signal) == 1) { + + load_done = TRUE; + + /* TODO: check for orphaned plugins */ + + kmq_post_message(KMSG_KMM, KMSG_KMM_I_DONE, 0, 0); + } +} + +void +kmmint_add_to_module_queue(void) { + InterlockedIncrement(&pending_modules); +} + +void +kmmint_remove_from_module_queue(void) { + + InterlockedDecrement(&pending_modules); + + kmmint_check_completion(); +} + +void +kmmint_add_to_plugin_queue(kmm_plugin_i * plugin) { + EnterCriticalSection(&cs_kmm); + if (!(plugin->flags & KMM_PLUGIN_FLAG_IN_QUEUE)) { + InterlockedIncrement(&pending_plugins); + plugin->flags |= KMM_PLUGIN_FLAG_IN_QUEUE; + } + LeaveCriticalSection(&cs_kmm); +} + +void +kmmint_remove_from_plugin_queue(kmm_plugin_i * plugin) { + EnterCriticalSection(&cs_kmm); + + if (plugin->flags & KMM_PLUGIN_FLAG_IN_QUEUE) { + InterlockedDecrement(&pending_plugins); + plugin->flags &= ~KMM_PLUGIN_FLAG_IN_QUEUE; + } + + LeaveCriticalSection(&cs_kmm); + kmmint_check_completion(); +} + +KHMEXP khm_boolean KHMAPI +kmm_load_pending(void) { + return !load_done; +} + +/*! \internal + \brief Message handler for the registrar thread. */ +khm_boolean KHMAPI kmm_reg_cb( + khm_int32 msg_type, + khm_int32 msg_sub_type, + khm_ui_4 uparam, + void *vparam) +{ + /* we should only be getting anyway */ + if(msg_type != KMSG_KMM || msg_sub_type != KMSG_KMM_I_REG) + return FALSE; + + switch(uparam) { + case KMM_REG_INIT_MODULE: + kmm_init_module((kmm_module_i *) vparam); + kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); + break; + + case KMM_REG_EXIT_MODULE: + kmm_exit_module((kmm_module_i *) vparam); + kmm_release_module(kmm_handle_from_module((kmm_module_i *) vparam)); + break; + + case KMM_REG_INIT_PLUGIN: + kmm_init_plugin((kmm_plugin_i *) vparam); + kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); + break; + + case KMM_REG_EXIT_PLUGIN: + kmm_exit_plugin((kmm_plugin_i *) vparam); + kmm_release_plugin(kmm_handle_from_plugin((kmm_plugin_i *) vparam)); + break; + } + return TRUE; +} + +/*! \internal + \brief The registrar thread. + + The only thing this function does is to dispatch messages to the + callback routine ( kmm_reg_cb() ) */ +DWORD WINAPI kmm_registrar( + LPVOID lpParameter +) +{ + tid_registrar = GetCurrentThreadId(); + + kmq_subscribe(KMSG_KMM, kmm_reg_cb); + kmq_subscribe(KMSG_SYSTEM, kmm_reg_cb); + + SetEvent(evt_startup); + + while(KHM_SUCCEEDED(kmq_dispatch(INFINITE))); + + ExitThread(0); + /* not reached */ + return 0; +} + +/*! \internal + \brief Manages a plugin message thread. + + Each plugin gets its own plugin thread which is used to dispatch + messages to the plugin. This acts as the thread function for the + plugin thread.*/ +DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter) +{ + DWORD rv = 0; + kmm_plugin_i * p = (kmm_plugin_i *) lpParameter; + + TlsSetValue(tls_kmm, (LPVOID) p); + + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + p->tid_thread = GetCurrentThreadId(); + + if (IsBadCodePtr(p->p.msg_proc)) { + rv = KHM_ERROR_INVALID_PARAM; + } else { + rv = (p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_INIT, + 0, (void *) &(p->p))); + } + + /* if it fails to initialize, we exit the plugin */ + if(KHM_FAILED(rv)) { + kmmint_remove_from_plugin_queue(p); + rv = 1; + goto _exit; + } + + /* subscribe to default message classes by plugin type */ + if(p->p.type == KHM_PITYPE_CRED) { + kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc); + kmq_subscribe(KMSG_KCDB, p->p.msg_proc); + kmq_subscribe(KMSG_CRED, p->p.msg_proc); + } else if(p->p.type == KHM_PITYPE_IDENT) { + khm_handle h = NULL; + + kmq_subscribe(KMSG_SYSTEM, p->p.msg_proc); + kmq_subscribe(KMSG_KCDB, p->p.msg_proc); + + kmq_create_subscription(p->p.msg_proc, &h); + kcdb_identity_set_provider(h); + /* kcdb deletes the subscription when it's done with it */ + } else if(p->p.type == KHM_PITYPE_CONFIG) { + /*TODO: subscribe to configuration provider messages here */ + } + + p->state = KMM_PLUGIN_STATE_RUNNING; + + /* if there were any plugins that were waiting for this one to + start, we should start them too */ + EnterCriticalSection(&cs_kmm); + do { + kmm_plugin_i * pd; + int i; + + for(i=0; i < p->n_dependants; i++) { + pd = p->dependants[i]; + + pd->n_unresolved--; + + if(pd->n_unresolved == 0) { + kmmint_add_to_plugin_queue(pd); + kmm_hold_plugin(kmm_handle_from_plugin(pd)); + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_INIT_PLUGIN, (void *) pd); + } + } + } while(FALSE); + LeaveCriticalSection(&cs_kmm); + + kmmint_remove_from_plugin_queue(p); + + /* main message loop */ + while(KHM_SUCCEEDED(kmq_dispatch(INFINITE))); + + /* unsubscribe from default message classes by plugin type */ + if(p->p.type == KHM_PITYPE_CRED) { + kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc); + kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc); + kmq_unsubscribe(KMSG_CRED, p->p.msg_proc); + } else if (p->p.type == KHM_PITYPE_IDENT) { + kmq_unsubscribe(KMSG_KCDB, p->p.msg_proc); + kmq_unsubscribe(KMSG_SYSTEM, p->p.msg_proc); + kcdb_identity_set_provider(NULL); + } else if(p->p.type == KHM_PITYPE_CONFIG) { + /*TODO: unsubscribe from configuration provider messages here */ + } + + p->p.msg_proc(KMSG_SYSTEM, KMSG_SYSTEM_EXIT, 0, (void *) &(p->p)); + +_exit: + p->state = KMM_PLUGIN_STATE_EXITED; + + /* the following call will automatically release the plugin */ + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, + KMM_REG_EXIT_PLUGIN, (void *) p); + + TlsSetValue(tls_kmm, (LPVOID) 0); + + ExitThread(rv); + + /* not reached */ + return rv; +} + +/*! \internal + \brief Initialize a plugin + + \note If kmm_init_plugin() is called on a plugin, then kmm_exit_plugin() + \b must be called for the plugin. + + \note Should only be called from the context of the registrar thread */ +void kmm_init_plugin(kmm_plugin_i * p) { + DWORD dummy; + khm_handle csp_plugin = NULL; + khm_handle csp_plugins = NULL; + khm_int32 t; + + /* the following will be undone in kmm_exit_plugin() */ + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + EnterCriticalSection(&cs_kmm); + if(p->state != KMM_PLUGIN_STATE_REG && + p->state != KMM_PLUGIN_STATE_HOLD) + { + LeaveCriticalSection(&cs_kmm); + goto _exit; + } + + _begin_task(0); + _report_mr1(KHERR_NONE, MSG_IP_TASK_DESC, _cstr(p->p.name)); + _describe(); + + if(p->state == KMM_PLUGIN_STATE_HOLD) { + /* if this plugin was held, then we already had a hold + from the initial attempt to start the plugin. Undo + the hold we did a few lines earlier. */ + kmm_release_plugin(kmm_handle_from_plugin(p)); + /* same for the plugin count for the module. */ + p->module->plugin_count--; + } + + p->state = KMM_PLUGIN_STATE_PREINIT; + LeaveCriticalSection(&cs_kmm); + + if(KHM_FAILED(kmm_get_plugins_config(0, &csp_plugins))) { + _report_mr0(KHERR_ERROR, MSG_IP_GET_CONFIG); + + p->state = KMM_PLUGIN_STATE_FAIL_UNKNOWN; + goto _exit; + } + + if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin)) || + KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) { + if(KHM_FAILED(kmm_register_plugin(&(p->p), 0))) { + _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); + + p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + + if(KHM_FAILED(kmm_get_plugin_config(p->p.name, 0, &csp_plugin))) { + _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); + + p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + + if(KHM_FAILED(khc_read_int32(csp_plugin, L"Flags", &t))) { + _report_mr0(KHERR_ERROR, MSG_IP_NOT_REGISTERED); + + p->state = KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + } + + if(t & KMM_PLUGIN_FLAG_DISABLED) { + _report_mr0(KHERR_ERROR, MSG_IP_DISABLED); + + p->state = KMM_PLUGIN_STATE_FAIL_DISABLED; + goto _exit; + } + +#if 0 + /*TODO: check the failure count and act accordingly */ + if(KHM_SUCCEEDED(khc_read_int32(csp_plugin, L"FailureCount", &t)) && (t > 0)) { + } +#endif + + EnterCriticalSection(&cs_kmm); + + p->n_depends = 0; + p->n_unresolved = 0; + + do { + wchar_t * deps = NULL; + wchar_t * d; + khm_size sz = 0; + + if(khc_read_multi_string(csp_plugin, L"Dependencies", + NULL, &sz) != KHM_ERROR_TOO_LONG) + break; + + deps = PMALLOC(sz); + if(KHM_FAILED(khc_read_multi_string(csp_plugin, L"Dependencies", + deps, &sz))) { + if(deps) + PFREE(deps); + break; + } + + for(d = deps; d && *d; d = multi_string_next(d)) { + kmm_plugin_i * pd; + int i; + + pd = kmmint_get_plugin_i(d); + + if(pd->state == KMM_PLUGIN_STATE_NONE) { + /* the dependant was not previously known */ + pd->state = KMM_PLUGIN_STATE_PLACEHOLDER; + } + + for(i=0; i < pd->n_dependants; i++) { + if(pd->dependants[i] == p) + break; + } + + if(i >= pd->n_dependants) { + if( pd->n_dependants >= KMM_MAX_DEPENDANTS ) { + /*TODO: handle this gracefully */ + RaiseException(1, EXCEPTION_NONCONTINUABLE, 0, NULL); + } + + /* released in kmmint_free_plugin() */ + kmm_hold_plugin(kmm_handle_from_plugin(p)); + pd->dependants[pd->n_dependants] = p; + pd->n_dependants++; + } + + p->n_depends++; + + if(pd->state != KMM_PLUGIN_STATE_RUNNING) { + p->n_unresolved++; + } + } + + if(p->n_unresolved > 0) { + p->state = KMM_PLUGIN_STATE_HOLD; + } + + PFREE(deps); + + } while(FALSE); + LeaveCriticalSection(&cs_kmm); + + EnterCriticalSection(&cs_kmm); + p->module->plugin_count++; + kmmint_delist_plugin(p); + kmmint_list_plugin(p); + LeaveCriticalSection(&cs_kmm); + + if(p->state == KMM_PLUGIN_STATE_HOLD) { + _report_mr1(KHERR_INFO, MSG_IP_HOLD, _dupstr(p->p.name)); + + goto _exit_post; + } + + kmmint_add_to_plugin_queue(p); + + p->ht_thread = CreateThread(NULL, + 0, + kmm_plugin_broker, + (LPVOID) p, + CREATE_SUSPENDED, + &dummy); + + p->state = KMM_PLUGIN_STATE_INIT; + + ResumeThread(p->ht_thread); + +_exit_post: + if(csp_plugin != NULL) + khc_close_space(csp_plugin); + + if(csp_plugins != NULL) + khc_close_space(csp_plugins); + + _report_mr2(KHERR_INFO, MSG_IP_STATE, + _dupstr(p->p.name), _int32(p->state)); + + _end_task(); + + return; + + /* jump here if an error condition happens before the plugin + broker thread starts and the plugin should be unloaded */ + +_exit: + if(csp_plugin != NULL) + khc_close_space(csp_plugin); + if(csp_plugins != NULL) + khc_close_space(csp_plugins); + + _report_mr2(KHERR_WARNING, MSG_IP_EXITING, + _dupstr(p->p.name), _int32(p->state)); + _end_task(); + + kmm_hold_plugin(kmm_handle_from_plugin(p)); + + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_PLUGIN, (void *) p); +} + +/*! \internal + \brief Uninitialize a plugin + + In addition to terminating the thread, and removing p from the + linked list and hashtable, it also frees up p. + + \note Should only be called from the context of the registrar thread. */ +void kmm_exit_plugin(kmm_plugin_i * p) { + int np; + + if(p->state == KMM_PLUGIN_STATE_RUNNING || + p->state == KMM_PLUGIN_STATE_INIT) + { + kmq_post_thread_quit_message(p->tid_thread, 0, NULL); + /* when we post the quit message to the plugin thread, the plugin + broker terminates the plugin and posts a EXIT_PLUGIN message, + which calls this function again. We just exit here because + the EXIT_PLUGIN message will end up calling us again momentarily */ + return; + } + + if(p->ht_thread) { + /* wait for the thread to terminate */ + WaitForSingleObject(p->ht_thread, INFINITE); + p->ht_thread = NULL; + } + + EnterCriticalSection(&cs_kmm); + + /* undo reference count done in kmm_init_plugin() */ + if(p->state == KMM_PLUGIN_STATE_EXITED || + p->state == KMM_PLUGIN_STATE_HOLD) + { + np = --(p->module->plugin_count); + } else { + /* the plugin was never active. We can't base a module unload + decision on np */ + np = TRUE; + } + LeaveCriticalSection(&cs_kmm); + + if(!np) { + /* if this is the last plugin to exit, then notify the + registrar that the module should be removed as well */ + kmm_hold_module(kmm_handle_from_module(p->module)); + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, KMM_REG_EXIT_MODULE, (void *) p->module); + } + + /* release the hold obtained in kmm_init_plugin() */ + kmm_release_plugin(kmm_handle_from_plugin(p)); +} + +/*! \internal + \brief Initialize a module + + \a m is not in the linked list yet. + + \note Should only be called from the context of the registrar thread. */ +void kmm_init_module(kmm_module_i * m) { + HMODULE hm; + init_module_t p_init_module; + kmm_plugin_i * pi; + khm_int32 rv; + khm_handle csp_mod = NULL; + khm_handle csp_mods = NULL; + khm_size sz; + khm_int32 i; + + /* error condition handling */ + BOOL exit_module = FALSE; + BOOL release_module = TRUE; + BOOL record_failure = FALSE; + + /* failure handling */ + khm_int32 max_fail_count = 0; + khm_int64 fail_reset_time = 0; + + _begin_task(0); + _report_mr1(KHERR_NONE, MSG_INIT_MODULE, _cstr(m->name)); + _describe(); + + kmm_hold_module(kmm_handle_from_module(m)); + + if(KHM_FAILED(kmm_get_modules_config(0, &csp_mods))) { + _report_mr0(KHERR_ERROR, MSG_IM_GET_CONFIG); + _location(L"kmm_get_modules_config()"); + + m->state = KMM_MODULE_STATE_FAIL_UNKNOWN; + goto _exit; + } + + khc_read_int32(csp_mods, L"ModuleMaxFailureCount", &max_fail_count); + khc_read_int64(csp_mods, L"ModuleFailureCountResetTime", &fail_reset_time); + + /* If the module is not in the pre-init state, we can't + initialize it. */ + if(m->state != KMM_MODULE_STATE_PREINIT) { + _report_mr1(KHERR_INFO, MSG_IM_NOT_PREINIT, _int32(m->state)); + goto _exit; + } + + if(KHM_FAILED(kmm_get_module_config(m->name, 0, &csp_mod))) { + _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED); + + m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + + if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"Flags", &i)) && + (i & KMM_MODULE_FLAG_DISABLED)) { + + _report_mr0(KHERR_INFO, MSG_IM_DISABLED); + + m->state = KMM_MODULE_STATE_FAIL_DISABLED; + goto _exit; + } + + if(KHM_SUCCEEDED(khc_read_int32(csp_mod, L"FailureCount", &i))) { + khm_int64 tm; + khm_int64 ct; + FILETIME fct; + khm_int32 last_reason = 0; + + /* reset the failure count if the failure count reset time + period has elapsed */ + tm = 0; + khc_read_int64(csp_mod, L"FailureTime", &tm); + GetSystemTimeAsFileTime(&fct); + + ct = (FtToInt(&fct) - tm) / 10000000i64; + + if(tm > 0 && + ct > fail_reset_time) { + i = 0; + khc_write_int32(csp_mod, L"FailureCount", 0); + khc_write_int64(csp_mod, L"FailureTime", 0); + } + + khc_read_int32(csp_mod, L"FailureReason", &last_reason); + + /* did we exceed the max failure count? However, we ignore + the max failure count if the reason why it didn't load the + last time was because the module wasn't found. */ + if(i > max_fail_count && + last_reason != KMM_MODULE_STATE_FAIL_NOT_FOUND) { + /* failed too many times */ + _report_mr0(KHERR_INFO, MSG_IM_MAX_FAIL); + + m->state = KMM_MODULE_STATE_FAIL_MAX_FAILURE; + goto _exit; + } + } + + if(khc_read_string(csp_mod, L"ImagePath", NULL, &sz) == + KHM_ERROR_TOO_LONG) { + if(m->path) + PFREE(m->path); + m->path = PMALLOC(sz); + khc_read_string(csp_mod, L"ImagePath", m->path, &sz); + } else { + _report_mr0(KHERR_ERROR, MSG_IM_NOT_REGISTERED); + + m->state = KMM_MODULE_STATE_FAIL_NOT_REGISTERED; + goto _exit; + } + + rv = kmmint_read_module_info(m); + + if (KHM_FAILED(rv)) { + if (rv == KHM_ERROR_INCOMPATIBLE) { + _report_mr0(KHERR_ERROR, MSG_IM_INCOMPATIBLE); + + m->state = KMM_MODULE_STATE_FAIL_INCOMPAT; + } else if (rv == KHM_ERROR_NOT_FOUND) { + _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path)); + + m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; + } else { + _report_mr0(KHERR_ERROR, MSG_IM_INVALID_MODULE); + + m->state = KMM_MODULE_STATE_FAIL_INV_MODULE; + } + goto _exit; + } + + /* check again */ + if(m->state != KMM_MODULE_STATE_PREINIT) { + _report_mr0(KHERR_ERROR, MSG_IM_NOT_PREINIT); + + goto _exit; + } + + /* from this point on, we must record any failure codes */ + record_failure = TRUE; + + hm = LoadLibrary(m->path); + if(!hm) { + m->h_module = NULL; + m->state = KMM_MODULE_STATE_FAIL_NOT_FOUND; + + _report_mr1(KHERR_ERROR, MSG_IM_NOT_FOUND, _dupstr(m->path)); + + goto _exit; + } + + /* from this point on, we need to discard the module through + exit_module */ + release_module = FALSE; + exit_module = TRUE; + + m->flags |= KMM_MODULE_FLAG_LOADED; + m->h_module = hm; + + /* TODO: check signatures */ + + p_init_module = (init_module_t) GetProcAddress(hm, EXP_INIT_MODULE); + + if(!p_init_module) { + _report_mr1(KHERR_ERROR, MSG_IM_NO_ENTRY, _cstr(EXP_INIT_MODULE)); + + m->state = KMM_MODULE_STATE_FAIL_INVALID; + goto _exit; + } + + m->state = KMM_MODULE_STATE_INIT; + + /* call init_module() */ + rv = (*p_init_module)(kmm_handle_from_module(m)); + + m->flags |= KMM_MODULE_FLAG_INITP; + + if(KHM_FAILED(rv)) { + _report_mr1(KHERR_ERROR, MSG_IM_INIT_FAIL, _int32(rv)); + + m->state = KMM_MODULE_STATE_FAIL_LOAD; + goto _exit; + } + + if(!m->plugins) { + _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS); + + m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS; + record_failure = FALSE; + goto _exit; + } + + m->state = KMM_MODULE_STATE_INITPLUG; + + do { + LPOP(&(m->plugins), &pi); + if(pi) { + pi->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; + kmm_init_plugin(pi); + + /* release the hold obtained in kmm_provide_plugin() */ + kmm_release_plugin(kmm_handle_from_plugin(pi)); + } + } while(pi); + + if(!m->plugin_count) { + _report_mr0(KHERR_ERROR, MSG_IM_NO_PLUGINS); + + m->state = KMM_MODULE_STATE_FAIL_NO_PLUGINS; + record_failure = FALSE; + goto _exit; + } + + m->state = KMM_MODULE_STATE_RUNNING; + + exit_module = FALSE; + record_failure = FALSE; + + ResetEvent(evt_exit); + + _exit: + if(csp_mod) { + if(record_failure) { + FILETIME fct; + + i = 0; + khc_read_int32(csp_mod, L"FailureCount", &i); + i++; + khc_write_int32(csp_mod, L"FailureCount", i); + + if(i==1) { /* first fault */ + GetSystemTimeAsFileTime(&fct); + khc_write_int64(csp_mod, L"FailureTime", FtToInt(&fct)); + } + + khc_write_int32(csp_mod, L"FailureReason", m->state); + } + khc_close_space(csp_mod); + } + + if(csp_mods) + khc_close_space(csp_mods); + + _report_mr2(KHERR_INFO, MSG_IM_MOD_STATE, + _dupstr(m->name), _int32(m->state)); + + kmmint_remove_from_module_queue(); + + /* if something went wrong after init_module was called on the + module code, we need to call exit_module */ + if(exit_module) + kmm_exit_module(m); + + if(release_module) + kmm_release_module(kmm_handle_from_module(m)); + + if (kherr_is_error()) { + kherr_context * c; + kherr_event * err_e = NULL; + kherr_event * warn_e = NULL; + kherr_event * e; + + c = kherr_peek_context(); + err_e = kherr_get_err_event(c); + for(e = kherr_get_first_event(c); + e; + e = kherr_get_next_event(e)) { + if (e != err_e && + e->severity == KHERR_WARNING) { + warn_e = e; + break; + } + } + + kherr_evaluate_event(err_e); + if (warn_e) + kherr_evaluate_event(warn_e); + + kherr_clear_error(); + + e = kherr_report(KHERR_ERROR, + (wchar_t *) MSG_IMERR_TITLE, + KHERR_FACILITY, + NULL, + err_e->long_desc, + ((warn_e)? (wchar_t *)MSG_IMERR_SUGGEST: NULL), + KHERR_FACILITY_ID, + KHERR_SUGGEST_NONE, + _cstr(m->name), + ((warn_e)? _cstr(warn_e->long_desc):0), + 0,0, + KHERR_RF_MSG_SHORT_DESC | + ((warn_e)? KHERR_RF_MSG_SUGGEST: 0), + KHERR_HMODULE); + + kherr_evaluate_event(e); + + kherr_release_context(c); + } + + _end_task(); +} + + +/*! \internal + \brief Uninitializes a module + + \note Should only be called from the context of the registrar + thread */ +void kmm_exit_module(kmm_module_i * m) { + kmm_plugin_i * p; + + /* exiting a module happens in two stages. + + If the module state is running (there are active plugins) then + those plugins must be exited. This has to be done from the + plugin threads. The signal for the plugins to exit must be + issued from the registrar. Therefore, we post messages to the + registrar for each plugin we want to remove and exit + kmm_exit_module(). + + When the last plugin is exited, the plugin management code + automatically signalls the registrar to remove the module. + kmm_exit_module() gets called again. This is the second + stage, where we call exit_module() for the module and start + unloading everything. + */ + + EnterCriticalSection(&cs_kmm); + + /* get rid of any dangling uninitialized plugins */ + LPOP(&(m->plugins), &p); + while(p) { + p->flags &= ~KMM_PLUGIN_FLAG_IN_MODLIST; + kmm_exit_plugin(p); + + /* release hold from kmm_provide_plugin() */ + kmm_release_plugin(kmm_handle_from_plugin(p)); + + LPOP(&(m->plugins), &p); + } + + if(m->state == KMM_MODULE_STATE_RUNNING) { + int np = 0; + + m->state = KMM_MODULE_STATE_EXITPLUG; + + p = kmm_listed_plugins; + + while(p) { + if(p->module == m) { + kmm_hold_plugin(kmm_handle_from_plugin(p)); + kmq_post_message(KMSG_KMM, KMSG_KMM_I_REG, + KMM_REG_EXIT_PLUGIN, (void *) p); + np++; + } + + p = LNEXT(p); + } + + if(np > 0) { + /* we have to go back and wait for the plugins to exit. + when the last plugin exits, it automatically posts + EXIT_MODULE. We can pick up from there when this + happens. */ + LeaveCriticalSection(&cs_kmm); + return; + } + } + + if(m->flags & KMM_MODULE_FLAG_INITP) + { + exit_module_t p_exit_module; + + if(m->state > 0) + m->state = KMM_MODULE_STATE_EXIT; + + p_exit_module = + (exit_module_t) GetProcAddress(m->h_module, + EXP_EXIT_MODULE); + if(p_exit_module) { + LeaveCriticalSection(&cs_kmm); + p_exit_module(kmm_handle_from_module(m)); + EnterCriticalSection(&cs_kmm); + } + } + + LeaveCriticalSection(&cs_kmm); + + if(m->state > 0) + m->state = KMM_MODULE_STATE_EXITED; + + if(m->h_module) { + FreeLibrary(m->h_module); + } + + if(m->h_resource && (m->h_resource != m->h_module)) { + FreeLibrary(m->h_resource); + } + + m->h_module = NULL; + m->h_resource = NULL; + m->flags = 0; + + /* release the hold obtained in kmm_init_module() */ + kmm_release_module(kmm_handle_from_module(m)); +} diff --git a/mechglue/src/windows/identity/kmm/kmmconfig.csv b/mechglue/src/windows/identity/kmm/kmmconfig.csv new file mode 100644 index 000000000..171d667dd --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmmconfig.csv @@ -0,0 +1,43 @@ +Name,Type,Value,Description +PluginManager,KC_SPACE,0,Plugin Manager Configuration + Plugins,KC_SPACE,0,Plugin Specific configuration + PluginMaxFailureCount,KC_INT32,3,Maximum number of failure counts before plugin is disabled + PluginFailureCountResetTime,KC_INT64,36000,Time after first failure at which the failure count is reset + _Schema,KC_SPACE,0,Plugin schema + Module,KC_STRING,,The name of the module that registered this plugin + Description,KC_STRING,,Description of the plugin + Dependencies,KC_STRING,,Multi string of plugin names of plugins that this plugin depends on + Type,KC_INT32,0,The type of the plugin + Flags,KC_INT32,0,Flags + FailureCount,KC_INT32,0,Number of failed loads + FailureTime,KC_INT64,0,FILETIME of first failure + FailureReason,KC_INT32,0,Reason for first failure. One of the plugin status values. + Parameters,KC_SPACE,0,Plugin parameters. The schema beyond this is plugin dependent. + Parameters,KC_ENDSPACE,0, + _Schema,KC_ENDSPACE,0, + Plugins,KC_ENDSPACE,0, + Modules,KC_SPACE,0,Module Specific configuration + ModuleMaxFailureCount,KC_INT32,3,Maximum number of failure counts before module is disabled + ModuleFailureCountResetTime,KC_INT64,72000,Time after first failure at which the failure count is reset + _Schema,KC_SPACE,0,Module schema + ImagePath,KC_STRING,,Path to the DLL (including DLL name) + Flags,KC_INT32,0,Flags + FailureCount,KC_INT32,0,Number of failed loads + FailureTime,KC_INT64,0,FILETIME of first failure + FailureReason,KC_INT32,0,Reason for last failure. One of the module status values. + PluginList,KC_STRING,,List of plugins implemented in the module + _Schema,KC_ENDSPACE,0, +# OpenAFS,KC_SPACE,0,OpenAFS Module +# ImagePath,KC_STRING,afscred.dll, +# PluginList,KC_STRING,AfsCred, +# OpenAFS,KC_ENDSPACE,0, + MITKrb5,KC_SPACE,0,MIT Kerberos V + ImagePath,KC_STRING,krb5cred.dll, + PluginList,KC_STRING,Krb5Cred, + MITKrb5,KC_ENDSPACE,0, + MITKrb4,KC_SPACE,0,MIT Kerberos IV + ImagePath,KC_STRING,krb4cred.dll, + PluginList,KC_STRING,Krb4Cred, + MITKrb4,KC_ENDSPACE,0, + Modules,KC_ENDSPACE,0, +PluginManager,KC_ENDSPACE,0, diff --git a/mechglue/src/windows/identity/kmm/kmminternal.h b/mechglue/src/windows/identity/kmm/kmminternal.h new file mode 100644 index 000000000..c4e472387 --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmminternal.h @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KMMINTERNAL_H +#define __KHIMAIRA_KMMINTERNAL_H + +#include +#include +#include + +#define KHERR_FACILITY kmm_facility +#define KHERR_FACILITY_ID KHM_FACILITY_KMM +#define KHERR_HMODULE ((HMODULE) kmm_hInstance) +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct kmm_plugin_i_t; /* forward dcl */ + +typedef struct kmm_module_i_t { + khm_int32 magic; + + wchar_t * name; + wchar_t * path; + wchar_t * description; + wchar_t * vendor; + wchar_t * support; + + khm_version file_version; + khm_version prod_version; + + HMODULE h_module; + + HMODULE h_resource; + WORD lcid_resource; + + khm_int32 flags; + khm_int32 state; + khm_int32 plugin_count; /* number of active plugins */ + + void * version_info; + + khm_int32 refcount; + + struct kmm_plugin_i_t * plugins; /* only used for registration */ + + LDCL(struct kmm_module_i_t); +} kmm_module_i; + +#define KMM_MODULE_MAGIC 0x482f4e88 + +#define kmm_is_module(m) ((m) && ((kmm_module_i *)m)->magic == KMM_MODULE_MAGIC) + +#define kmm_module_from_handle(m) ((kmm_module_i *) m) +#define kmm_handle_from_module(m) ((kmm_module) m) + +/* LoadLibrary succeeded for module */ +#define KMM_MODULE_FLAG_LOADED 1 + +/* init_module entry called */ +#define KMM_MODULE_FLAG_INITP 2 + +/* the resources have been loaded */ +#define KMM_MODULE_FLAG_RES_LOADED 8 + +/* the signature has been verified */ +#define KMM_MODULE_FLAG_SIG 16 + +/* the module is disabled by the user + (option specifed in configuration) */ +#define KMM_MODULE_FLAG_DISABLED 1024 + + +typedef struct kmm_plugin_i_t { + kmm_plugin_reg p; + + khm_int32 magic; + + kmm_module_i * module; + HANDLE ht_thread; + DWORD tid_thread; + + khm_int32 state; + khm_int32 flags; + + int refcount; + + int n_depends; + int n_unresolved; + struct kmm_plugin_i_t * dependants[KMM_MAX_DEPENDANTS]; + int n_dependants; + + LDCL(struct kmm_plugin_i_t); +} kmm_plugin_i; + +#define KMM_PLUGIN_MAGIC 0x320e8fb4 + +#define kmm_is_plugin(p) ((p) && ((kmm_plugin_i *) (p))->magic == KMM_PLUGIN_MAGIC) + +#define kmm_handle_from_plugin(p) ((kmm_plugin) p) +#define kmm_plugin_from_handle(ph) ((kmm_plugin_i *) ph) + +/* the plugin has already been marked for unload */ +#define KMM_PLUGIN_FLAG_UNLOAD 1 + +/* the plugin is disabled by the user + (option specified in configuration) */ +#define KMM_PLUGIN_FLAG_DISABLED 1024 + +/* the plugin is in the kmm_listed_plugins list */ +#define KMM_PLUGIN_FLAG_IN_LIST 2 + +/* the plugin is in the module's plugin list */ +#define KMM_PLUGIN_FLAG_IN_MODLIST 4 + +#define KMM_PLUGIN_FLAG_IN_QUEUE 0x10 + +enum kmm_registrar_uparam_t { + KMM_REG_INIT_MODULE, + KMM_REG_EXIT_MODULE, + KMM_REG_INIT_PLUGIN, + KMM_REG_EXIT_PLUGIN +}; + +extern kmm_module_i * kmm_all_modules; +extern kmm_plugin_i * kmm_listed_plugins; +extern HANDLE ht_registrar; +extern DWORD tid_registrar; +extern DWORD tls_kmm; + +extern hashtable * hash_plugins; +extern hashtable * hash_modules; + +extern CRITICAL_SECTION cs_kmm; +extern int ready; +extern HANDLE evt_startup; +extern HANDLE evt_exit; +extern const wchar_t * kmm_facility; + +extern HINSTANCE kmm_hInstance; + +extern kconf_schema schema_kmmconfig[]; + +/* Registrar */ + +khm_boolean KHMAPI +kmm_reg_cb(khm_int32 msg_type, + khm_int32 msg_sub_type, + khm_ui_4 uparam, + void *vparam); + +DWORD WINAPI kmm_registrar(LPVOID lpParameter); + +DWORD WINAPI kmm_plugin_broker(LPVOID lpParameter); + +void kmm_init_plugin(kmm_plugin_i * p); +void kmm_exit_plugin(kmm_plugin_i * p); +void kmm_init_module(kmm_module_i * m); +void kmm_exit_module(kmm_module_i * m); + +/* Modules */ +kmm_module_i * +kmmint_get_module_i(wchar_t * name); + +kmm_module_i * +kmmint_find_module_i(wchar_t * name); + +void +kmmint_free_module(kmm_module_i * m); + +khm_int32 +kmmint_read_module_info(kmm_module_i * m); + +/* Plugins */ +kmm_plugin_i * +kmmint_get_plugin_i(wchar_t * name); + +kmm_plugin_i * +kmmint_find_plugin_i(wchar_t * name); + +void +kmmint_free_plugin(kmm_plugin_i * pi); + +void +kmmint_list_plugin(kmm_plugin_i * p); + +void +kmmint_delist_plugin(kmm_plugin_i * p); + +khm_boolean +kmmint_load_locale_lib(kmm_module_i * m, kmm_module_locale * l); + +#define KMM_CSNAME_ROOT L"PluginManager" +#define KMM_CSNAME_PLUGINS L"Plugins" +#define KMM_CSNAME_MODULES L"Modules" +#define KMM_VALNAME_LOADLIST L"LoadList" + +void +kmmint_add_to_module_queue(void); + +void +kmmint_remove_from_module_queue(void); + +#define _WAIT_FOR_START \ + do { \ + if(ready) break; \ + WaitForSingleObject(evt_startup, INFINITE); \ + } while(0) + +#endif diff --git a/mechglue/src/windows/identity/kmm/kmmmain.c b/mechglue/src/windows/identity/kmm/kmmmain.c new file mode 100644 index 000000000..6489313f8 --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kmmmain.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +kmm_module_i * kmm_all_modules = NULL; +kmm_plugin_i * kmm_listed_plugins = NULL; + +HANDLE ht_registrar = NULL; +DWORD tid_registrar = 0; +DWORD tls_kmm = 0; + +#define KMM_HASH_SIZE 31 +hashtable * hash_plugins = NULL; +hashtable * hash_modules = NULL; + +CRITICAL_SECTION cs_kmm; +HANDLE evt_startup = NULL; +HANDLE evt_exit = NULL; +int ready = 0; + +HINSTANCE kmm_hInstance; +const wchar_t * kmm_facility = L"KMM"; + +KHMEXP void KHMAPI kmm_init(void) +{ + DWORD dummy; + + EnterCriticalSection(&cs_kmm); + kmm_all_modules = NULL; + kmm_listed_plugins = NULL; + + tls_kmm = TlsAlloc(); + + hash_plugins = hash_new_hashtable( + KMM_HASH_SIZE, + hash_string, + hash_string_comp, + NULL, + NULL); + + hash_modules = hash_new_hashtable( + KMM_HASH_SIZE, + hash_string, + hash_string_comp, + NULL, + NULL); + + ht_registrar = CreateThread( + NULL, + 0, + kmm_registrar, + NULL, + 0, + &dummy); + + _WAIT_FOR_START; + + khc_load_schema(NULL, schema_kmmconfig); + + LeaveCriticalSection(&cs_kmm); +} + +KHMEXP void KHMAPI kmm_exit(void) +{ + kmm_module_i * m; + kmm_plugin_i * p; + + EnterCriticalSection(&cs_kmm); + + p = kmm_listed_plugins; + while(p) { + kmm_plugin_i * pn; + + pn = LNEXT(p); + /* plugins that were never resolved should be kicked off the + list. Flipping the refcount will do that if no other + references exist for the plugin. The plugins that were + waiting for unresolved dependencies will automatically get + freed when the placeholders and other plugins get freed. */ + if(p->state == KMM_PLUGIN_STATE_PLACEHOLDER) { + kmm_hold_plugin(kmm_handle_from_plugin(p)); + kmm_release_plugin(kmm_handle_from_plugin(p)); + } + + p = pn; + } + + m = kmm_all_modules; + while(m) { + kmm_unload_module(kmm_handle_from_module(m)); + m = LNEXT(m); + } + + LeaveCriticalSection(&cs_kmm); + WaitForSingleObject(evt_exit, INFINITE); + EnterCriticalSection(&cs_kmm); + + kmq_post_thread_quit_message(tid_registrar, 0, NULL); + + hash_del_hashtable(hash_plugins); + hash_del_hashtable(hash_modules); + + LeaveCriticalSection(&cs_kmm); + + TlsFree(tls_kmm); + + tls_kmm = 0; +} + +void kmm_dll_init(void) +{ + InitializeCriticalSection(&cs_kmm); + evt_startup = CreateEvent(NULL, TRUE, FALSE, NULL); + evt_exit = CreateEvent(NULL, TRUE, TRUE, NULL); +} + +void kmm_dll_exit(void) +{ + DeleteCriticalSection(&cs_kmm); + if(evt_startup) + CloseHandle(evt_startup); + evt_startup = NULL; +} + +void +kmm_process_attach(HINSTANCE hinstDLL) { + kmm_hInstance = hinstDLL; + kmm_dll_init(); +} + +void +kmm_process_detach(void) { + kmm_dll_exit(); +} + diff --git a/mechglue/src/windows/identity/kmm/kplugin.h b/mechglue/src/windows/identity/kmm/kplugin.h new file mode 100644 index 000000000..99f94f1f4 --- /dev/null +++ b/mechglue/src/windows/identity/kmm/kplugin.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KPLUGIN_H +#define __KHIMAIRA_KPLUGIN_H + +#include +#include + +/*! \addtogroup kmm +@{*/ +/*! \defgroup kplugin NetIDMgr Plugin Callbacks + +See the following related documentation pages for more information +about NetIDMgr plugins. + +These are prototypes of functions that must be implemented by a NetIDMgr +plugin. + +- \ref plugins +@{*/ + +/*! \brief Initialize the module + + This is the first callback function to be called in a module. + Perform all the required intialization when this is called. As + mentioned in \ref plugins, you should not attempt to call any + NetIDMgr API function from DLLMain or other initialization code + other than this one. + + You should use this call back to register the plugins that will be + implemented in this module and to notify the plugin manager of any + resource libraries that this module will use. + + Call: + - kmm_set_locale() : to set the notify the plugin manager of the + locale specifc resource libraries that are used by this module. + - kmm_provide_plugin() : to register each plugin that is + implemented in this module. + + This function is called in the context of the current user, from + the plug-in manager thread. This same thread is used by the + plug-in manager to load and initialize all the modules for a + session. + + The name of the callback must be init_module(). The calling + convention is KHMAPI, which is currently __stdcall. + + If this function does not register any plugins, the plugin manager + will immediately call exit_module() and unload the module even if + the init_module() function completes successfully. + + \return Return the following values to indicate whether the module + successfully initialized or not. + - KHM_ERROR_SUCCESS : Succeeded. The module manager will call + init_plugin() for each of the registered plugins for the + module. + - any other error code: Signals that the module did not + successfully initialize. The plugin manager will + immediately call exit_module() and then unload the module. + + \note This callback is required. +*/ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); + +/*! \brief Type for init_module() */ +typedef khm_int32 (KHMAPI *init_module_t)(kmm_module); + +#if defined(_WIN64) +#define EXP_INIT_MODULE "_init_module@8" +#elif defined(_WIN32) +#define EXP_INIT_MODULE "_init_module@4" +#else +#error EXP_INIT_MODULE not defined for platform +#endif + +/*! \brief Plugin procedure + + This is the message processor for a plugin. See \ref pi_fw_pnm_p + for more information. + + Essentially, this is a message subscriber for KMQ messages. +*/ +KHMEXP khm_int32 KHMAPI _plugin_proc(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); + +/*! \brief Type for init_plugin() */ +typedef kmq_callback_t _plugin_proc_t; + +/*! \brief Exit a module + + This is the last callback function that the NetIDMgr module + manager calls before unloading the module. When this function is + called, all of the plugins for the module have already been + stopped. However, any localization libraries that were loaded as + a result of init_module() calling kmm_set_locale_info() will still + be loaded. These localization libraries will be unloaded + immediately after this callback returns. + + Use this callback to perform any required cleanup tasks. However, + it is advisable that each plugin perform its own cleanup tasks, + since each plugin may be stopped independently of others. + + \return The return value of this function is ignored. + + \note This callback is not required. +*/ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/*! \brief Type for exit_module() */ +typedef khm_int32 (KHMAPI *exit_module_t)(kmm_module); + +#if defined(_WIN64) +#define EXP_EXIT_MODULE "_exit_module@8" +#elif defined(_WIN32) +#define EXP_EXIT_MODULE "_exit_module@4" +#else +#error EXP_EXIT_MODULE not defined for platform +#endif + +/*@}*/ +/*@}*/ + +#endif diff --git a/mechglue/src/windows/identity/kmm/lang/kmm_msgs.mc b/mechglue/src/windows/identity/kmm/lang/kmm_msgs.mc new file mode 100644 index 000000000..17bc6b80e --- /dev/null +++ b/mechglue/src/windows/identity/kmm/lang/kmm_msgs.mc @@ -0,0 +1,214 @@ +; // ** kmm_msgs.mc + +; /* Since .mc files can contain strings from any language, we define +; all our messages in one file in the /lang/ directory instead of +; language specific subdirectories. */ + +; /* The type is set to (wchar_t *) because that's what we will be +; feeding kherr_report() function. */ + +MessageIdTypedef=LPWSTR + +; /* Severity values as defined in the message definition file are +; currently ignored. */ + +SeverityNames=( + Success=0x0 +) + +LanguageNames=( + English=0x409:MSG_ENU +) + +OutputBase=16 + +; /* Actual messages start here */ + +MessageId=1 +Severity=Success +SymbolicName=MSG_INITIAL +Language=English +Initial placeholder message +. + +MessageId= +SymbolicName=MSG_LOAD_DEFAULT +Language=English +Load default modules +. + +MessageId= +SymbolicName=MSG_INIT_MODULE +Language=English +Initializing module [%1] +. + +MessageId= +SymbolicName=MSG_IM_GET_CONFIG +Language=English +Can't get configuration for modules +. + +MessageId= +SymbolicName=MSG_IM_NOT_PREINIT +Language=English +Module is not in PREINIT state. Current state=[%1!d!] +. + +MessageId= +SymbolicName=MSG_IM_NOT_REGISTERED +Language=English +Module is not registered +. + +MessageId= +SymbolicName=MSG_IM_DISABLED +Language=English +Module is disabled +. + +MessageId= +SymbolicName=MSG_IM_MAX_FAIL +Language=English +Module has failed too many times +. + +MessageId= +SymbolicName=MSG_IM_INVALID_MODULE +Language=English +The DLL containing the module was not of the correct format. +. + +MessageId= +SymbolicName=MSG_IM_INCOMPATIBLE +Language=English +The DLL containing the module was not compatible with this version of NetIDMgr. +. + +Messageid= +SymbolicName=MSG_IM_NOT_FOUND +Language=English +Module binary was not found. Checked path [%1] +. + +MessageId= +SymbolicName=MSG_IM_NO_ENTRY +Language=English +Entry point not found. Checked entry point [%1] +. + +MessageId= +SymbolicName=MSG_IM_INIT_FAIL +Language=English +Module initialization entry point returned failure code [%1!d!] +. + +MessageId= +SymbolicName=MSG_IM_NO_PLUGINS +Language=English +No plugins were registerd by the module +. + +MessageId= +SymbolicName=MSG_IM_MOD_STATE +Language=English +Module [%1] is in state [%2!d!] +. + +MessageId= +SymbolicName=MSG_IMERR_TITLE +Language=English +Failed to load module %1!s! +. + +MessageId= +SymbolicName=MSG_IMERR_SUGGEST +Language=English +The following information may help resolve this issue: + +%2!s! +. + +MessageId= +SymbolicName=MSG_IP_TASK_DESC +Language=English +Initializing plugin [%1] +. + +MessageId= +SymbolicName=MSG_IP_GET_CONFIG +Language=English +Can't get configuration for plugins +. + +MessageId= +SymbolicName=MSG_IP_NOT_REGISTERED +Language=English +The plugin is not registered +. + +MessageId= +SymbolicName=MSG_IP_DISABLED +Language=English +The plugin is disabled +. + +MessageId= +SymbolicName=MSG_IP_HOLD +Language=English +Placing plugin [%1] on hold +. + +MessageId= +SymbolicName=MSG_IP_STATE +Language=English +Leaving plugin [%1] in state [%2!d!] +. + +MessageId= +SymbolicName=MSG_IP_EXITING +Language=English +The plugin [%1] is in error state [%2!d!]. Exiting plugin. +. + +MessageId= +SymbolicName=MSG_RMI_NOT_FOUND +Language=English +Can't get file version information for path [%1!s!] +. + +MessageId= +SymbolicName=MSG_RMI_NO_TRANS +Language=English +Can't get version resource tranlations list for path [%1!s!] +. + +MessageId= +SymbolicName=MSG_RMI_NO_LOCAL +Language=English +The list of version translations were empty or did not contain a resource for the current user or system locale. +. + +MessageId= +SymbolicName=MSG_RMI_RES_MISSING +Language=English +Required resource %1!s! missing +. + +MessageId= +SymbolicName=MSG_RMI_MOD_MISMATCH +Language=English +The module name specified in the resource is [%1!s!] while the module name as registered is [%2!s!] +. + +MessageId= +SymbolicName=MSG_RMI_RES_TOO_LONG +Language=English +The resource %1!s! is malformed or too long +. + +MessageId= +SymbolicName=MSG_RMI_API_MISMATCH +Language=English +The module was compile for API version %1!d!. However the current API version is %2!d!. +. diff --git a/mechglue/src/windows/identity/kmq/Makefile b/mechglue/src/windows/identity/kmq/Makefile new file mode 100644 index 000000000..1f11e0fe4 --- /dev/null +++ b/mechglue/src/windows/identity/kmq/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=kmq +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\kmq.h + +OBJFILES= \ + $(OBJ)\kmqmain.obj \ + $(OBJ)\init.obj \ + $(OBJ)\msgtype.obj \ + $(OBJ)\consumer.obj \ + $(OBJ)\publisher.obj \ + $(OBJ)\kmqconfig.obj + +SDKLIBFILES=\ + strsafe.lib + +$(OBJ)\kmqconfig.c: kmqconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/mechglue/src/windows/identity/kmq/consumer.c b/mechglue/src/windows/identity/kmq/consumer.c new file mode 100644 index 000000000..03519bafd --- /dev/null +++ b/mechglue/src/windows/identity/kmq/consumer.c @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +DWORD kmq_tls_queue; + +CRITICAL_SECTION cs_kmq_msg_ref; + +kmq_message_ref * kmq_msg_ref_free = NULL; + +/* ad-hoc subscriptions */ +kmq_msg_subscription * kmq_adhoc_subs = NULL; + +/*! \internal + \brief Get a message ref object + \note called with cs_kmq_msg_ref held */ +kmq_message_ref * kmqint_get_message_ref(void) { + kmq_message_ref * r; + + LPOP(&kmq_msg_ref_free, &r); + if(!r) { + r = PMALLOC(sizeof(kmq_message_ref)); + } + ZeroMemory(r, sizeof(kmq_message_ref)); + + r->msg = NULL; + r->recipient = NULL; + + return r; +} + +/*! \internal + \brief Free a message ref object + \note called with cs_kmq_msg_ref and cs_kmq_msg held */ +void kmqint_put_message_ref(kmq_message_ref * r) { + if(!r) + return; + if(r->msg) { + r->msg->refcount--; + r->msg = NULL; + } + LPUSH(&kmq_msg_ref_free, r); +} + +/*! \internal + \brief Get the queue associated with the current thread + \note Obtains ::cs_kmq_global + */ +kmq_queue * kmqint_get_thread_queue(void) { + kmq_queue * q; + + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + if(!q) { + kmqint_attach_this_thread(); + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + } + + return q; +} + +/*! \internal + \brief Get the topmost message ref for a queue + \note Obtains kmq_queue::cs + */ +void kmqint_get_queue_message_ref(kmq_queue * q, kmq_message_ref ** r) { + EnterCriticalSection(&q->cs); + QGET(q,r); + if(QTOP(q)) + SetEvent(q->wait_o); + LeaveCriticalSection(&q->cs); +} + +/*! \internal + \brief Post a message to a queue + \note Obtains ::cs_kmq_msg_ref, ::cs_kmq_msg, kmq_queue::cs + */ +void kmqint_post_queue(kmq_queue * q, kmq_message *m) { + kmq_message_ref *r; + + EnterCriticalSection(&cs_kmq_msg_ref); + r = kmqint_get_message_ref(); + LeaveCriticalSection(&cs_kmq_msg_ref); + + r->msg = m; + r->recipient = NULL; + + EnterCriticalSection(&cs_kmq_msg); + m->refcount++; + m->nSent++; + LeaveCriticalSection(&cs_kmq_msg); + + EnterCriticalSection(&q->cs); + QPUT(q,r); + SetEvent(q->wait_o); + LeaveCriticalSection(&q->cs); +} + +/*! \internal + \brief Post a message to a subscriber + \note Obtains ::cs_kmq_msg_ref, ::cs_kmq_msg, kmq_queue::cs + \note Should be called with ::cs_kmq_msg held + */ +void kmqint_post(kmq_msg_subscription * s, kmq_message * m, khm_boolean try_send) { + if(s->rcpt_type == KMQ_RCPTTYPE_CB) { + kmq_queue *q; + kmq_message_ref *r; + + q = s->queue; + + if(try_send && q->thread == GetCurrentThreadId()) { + khm_int32 rv; + /* we are sending a message from this thread to this + thread. just call the recipient directly, bypassing + the message queue. */ + m->refcount++; + m->nSent++; + if (IsBadCodePtr(s->recipient.cb)) { + rv = KHM_ERROR_INVALID_OPERATION; + } else { + if (IsBadCodePtr(s->recipient.cb)) + rv = KHM_ERROR_INVALID_OPERATION; + else + rv = s->recipient.cb(m->type, m->subtype, + m->uparam, m->vparam); + } + m->refcount--; + if(KHM_SUCCEEDED(rv)) + m->nCompleted++; + else + m->nFailed++; + } else { + EnterCriticalSection(&cs_kmq_msg_ref); + r = kmqint_get_message_ref(); + LeaveCriticalSection(&cs_kmq_msg_ref); + + r->msg = m; + r->recipient = s->recipient.cb; + + m->refcount++; + m->nSent++; + + EnterCriticalSection(&q->cs); + QPUT(q,r); + SetEvent(q->wait_o); + LeaveCriticalSection(&q->cs); + } + } + +#ifdef _WIN32 + else if(s->rcpt_type == KMQ_RCPTTYPE_HWND) { + m->refcount++; + + if(try_send && + GetCurrentThreadId() == GetWindowThreadProcessId(s->recipient.hwnd, + NULL)) { + /* kmqint_post does not know whether there are any other + messages waiting to be posted at this point. Hence, + simply sending the message is not the right thing to do + as the recipient may incorrectly assume that the + message has completed when (m->nCompleted + m->nFailed + == m->nSent). Therefore, we only increment nSent after + the message is sent. */ + SendMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, + m->type, (LPARAM) m); + m->nSent++; + } else { + m->nSent++; + PostMessage(s->recipient.hwnd, KMQ_WM_DISPATCH, + m->type, (LPARAM) m); + } + } +#endif + + else { + /* This could either be because we were passed in an invalid + subscription or because we lost a race to a thread that + deleted an ad-hoc subscription. */ +#ifdef DEBUG + assert(FALSE); +#else + return; +#endif + } +} + +/*! \internal + \brief Subscribes a window to a message type + \note Obtains ::cs_kmq_types + */ +KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd) { + kmq_msg_subscription * s; + + s = PMALLOC(sizeof(kmq_msg_subscription)); + LINIT(s); + s->queue = NULL; + s->rcpt_type = KMQ_RCPTTYPE_HWND; + s->recipient.hwnd = hwnd; + kmqint_msg_type_add_sub(type, s); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + \note Obtains ::cs_kmq_types, ::cs_kmq_global + */ +KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb) { + kmq_msg_subscription * s; + + s = PMALLOC(sizeof(kmq_msg_subscription)); + LINIT(s); + s->queue = kmqint_get_thread_queue(); + s->rcpt_type = KMQ_RCPTTYPE_CB; + s->recipient.cb = cb; + kmqint_msg_type_add_sub(type, s); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + \note Obtains ::cs_kmq_global +*/ +KHMEXP khm_int32 KHMAPI kmq_create_subscription(kmq_callback_t cb, + khm_handle * result) +{ + kmq_msg_subscription * s; + + s = PMALLOC(sizeof(kmq_msg_subscription)); + LINIT(s); + s->queue = kmqint_get_thread_queue(); + s->rcpt_type = KMQ_RCPTTYPE_CB; + s->recipient.cb = cb; + + EnterCriticalSection(&cs_kmq_global); + LPUSH(&kmq_adhoc_subs, s); + LeaveCriticalSection(&cs_kmq_global); + + *result = (khm_handle) s; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub) +{ + kmq_msg_subscription * s; + + s = (kmq_msg_subscription *) sub; + + s->type = 0; + + EnterCriticalSection(&cs_kmq_global); + LDELETE(&kmq_adhoc_subs, s); + LeaveCriticalSection(&cs_kmq_global); + + PFREE(s); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + \brief Unsubscribes a window from a message type + \note Obtains ::cs_kmq_types + */ +KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd) { + kmq_msg_subscription * s; + + s = kmqint_msg_type_del_sub_hwnd(type, hwnd); + if(s) + PFREE(s); + return (s)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; +} + +/*! \internal + \brief Unsubscribe a callback from a message type + \note Obtains ::cs_kmq_types, ::cs_kmq_global + */ +KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb) { + kmq_msg_subscription * s; + + s = kmqint_msg_type_del_sub_cb(type,cb); + if(s) + PFREE(s); + + return (s)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; +} + +KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m) { + *m = (kmq_message *) lparm; + if ((*m)->err_ctx) { + kherr_push_context((*m)->err_ctx); + } + return TRUE; +} + +/*! \internal + \note Obtains ::cs_kmq_msg + */ +KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv) { + if (m->err_ctx) + kherr_pop_context(); + + EnterCriticalSection(&cs_kmq_msg); + m->refcount--; + if(KHM_SUCCEEDED(rv)) + m->nCompleted++; + else + m->nFailed++; + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return TRUE; +} + +/*! \internal + \note Obtains ::cs_kmq_msg + */ +KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb) { + kmq_message *m; + khm_int32 rv; + + m = (kmq_message *) lparm; + + if (m->err_ctx) + kherr_push_context(m->err_ctx); + + rv = cb(m->type, m->subtype, m->uparam, m->vparam); + + if (m->err_ctx) + kherr_pop_context(); + + EnterCriticalSection(&cs_kmq_msg); + + m->refcount--; + if(KHM_SUCCEEDED(rv)) + m->nCompleted++; + else + m->nFailed++; + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return TRUE; +} + +/*! \internal + + \note Obtains ::cs_kmq_global, kmq_queue::cs, ::cs_kmq_msg_ref, ::cs_kmq_msg, +*/ +KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout) { + kmq_queue * q; + kmq_message_ref * r; + kmq_message *m; + DWORD hr; + + q = kmqint_get_thread_queue(); + + assert(q->wait_o); + + hr = WaitForSingleObject(q->wait_o, timeout); + if(hr == WAIT_OBJECT_0) { + /* signalled */ + kmqint_get_queue_message_ref(q, &r); + + m = r->msg; + + if(m->type != KMSG_SYSTEM || m->subtype != KMSG_SYSTEM_EXIT) { + khm_boolean rv; + + if (m->err_ctx) + kherr_push_context(m->err_ctx); + + /* dispatch */ + rv = r->recipient(m->type, m->subtype, m->uparam, m->vparam); + + if (m->err_ctx) + kherr_pop_context(); + + EnterCriticalSection(&cs_kmq_msg); + EnterCriticalSection(&cs_kmq_msg_ref); + kmqint_put_message_ref(r); + LeaveCriticalSection(&cs_kmq_msg_ref); + + if(KHM_SUCCEEDED(rv)) + m->nCompleted++; + else + m->nFailed++; + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_SUCCESS; + } else { + EnterCriticalSection(&cs_kmq_msg); + EnterCriticalSection(&cs_kmq_msg_ref); + kmqint_put_message_ref(r); + LeaveCriticalSection(&cs_kmq_msg_ref); + m->nCompleted++; + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_EXIT; + } + } else { + return KHM_ERROR_TIMEOUT; + } +} + +/* TODO: rename this file to subscriber.c */ diff --git a/mechglue/src/windows/identity/kmq/init.c b/mechglue/src/windows/identity/kmq/init.c new file mode 100644 index 000000000..f157e6ab2 --- /dev/null +++ b/mechglue/src/windows/identity/kmq/init.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include + +CRITICAL_SECTION cs_kmq_global; +kmq_timer kmq_queue_dead_timeout; +kmq_timer kmq_call_dead_timeout; + +kmq_queue * queues; + +LONG kmq_init_once = 0; + +void kmqint_init(void) { + khm_handle hconfig = NULL; + + queues = NULL; + + InitializeCriticalSection(&cs_kmq_global); + InitializeCriticalSection(&cs_kmq_msg); + InitializeCriticalSection(&cs_kmq_msg_ref); + + EnterCriticalSection(&cs_kmq_global); + khc_load_schema(NULL, schema_kmqconfig); + khc_open_space(NULL, KMQ_CONF_SPACE_NAME, KHM_PERM_READ, &hconfig); + if(hconfig) { + khc_read_int32(hconfig, KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME, &kmq_queue_dead_timeout); + khc_read_int32(hconfig, KMQ_CONF_CALL_DEAD_TIMEOUT_NAME, &kmq_call_dead_timeout); + khc_close_space(hconfig); + } + kmqint_init_msg_types(); + LeaveCriticalSection(&cs_kmq_global); + + kmq_tls_queue = TlsAlloc(); +} + +void kmqint_exit(void) { + EnterCriticalSection(&cs_kmq_global); + kmqint_exit_msg_types(); + LeaveCriticalSection(&cs_kmq_global); + DeleteCriticalSection(&cs_kmq_msg); + DeleteCriticalSection(&cs_kmq_msg_ref); + DeleteCriticalSection(&cs_kmq_global); + + TlsFree(kmq_tls_queue); +} + +/*! \internal + \brief Preps a thread for use with kmq + \note Obtains ::cs_kmq_global + */ +void kmqint_attach_this_thread(void) { + kmq_queue * q; + + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + if(!q) { + EnterCriticalSection(&cs_kmq_global); + + q = PMALLOC(sizeof(kmq_queue)); + + InitializeCriticalSection(&q->cs); + q->thread = GetCurrentThreadId(); + QINIT(q); + LINIT(q); + q->wait_o = CreateEvent(NULL, FALSE, FALSE, NULL); + q->load = 0; + q->last_post = 0; + + LPUSH(&queues, q); + + TlsSetValue(kmq_tls_queue, (LPVOID) q); + + LeaveCriticalSection(&cs_kmq_global); + } +} + +/*! \internal + \brief Detaches the current thread from kmq + \note Obtains ::cs_kmq_global + */ +void kmqint_detach_this_thread(void) { + kmq_queue * q; + + q = (kmq_queue *) TlsGetValue(kmq_tls_queue); + if(q) { + EnterCriticalSection(&cs_kmq_global); + + LDELETE(&queues, q); + + DeleteCriticalSection(&q->cs); + CloseHandle(q->wait_o); + + /* TODO: free up the queued messages */ + + TlsSetValue(kmq_tls_queue, (LPVOID) 0); + + LeaveCriticalSection(&cs_kmq_global); + } +} + +HANDLE kmq_h_compl = NULL; +kmq_thread_id kmq_tid_compl; + +/* Message transfer */ +struct tag_kmq_msg_xfer { + QDCL(kmq_message); +} kmq_completion_xfer; + +HANDLE compl_wx; +BOOL compl_continue; +CRITICAL_SECTION cs_compl; + +DWORD WINAPI kmqint_completion_thread_proc(LPVOID p) { + kmq_message * m; + kherr_context * ctx; + + EnterCriticalSection(&cs_compl); + do { + + if (QTOP(&kmq_completion_xfer) == NULL) { + LeaveCriticalSection(&cs_compl); + WaitForSingleObject(compl_wx, INFINITE); + EnterCriticalSection(&cs_compl); + /* go through the loop again before checking the queue */ + } else { + QGET(&kmq_completion_xfer, &m); + LeaveCriticalSection(&cs_compl); + EnterCriticalSection(&cs_kmq_msg); + + ctx = m->err_ctx; + + if (ctx) + kherr_push_context(ctx); + + kmqint_put_message(m); + + if (ctx) + kherr_pop_context(); + + LeaveCriticalSection(&cs_kmq_msg); + EnterCriticalSection(&cs_compl); + } + + } while(compl_continue); + + LeaveCriticalSection(&cs_compl); + + ExitThread(0); + + /* not reached */ + return 0; +} + +int kmqint_call_completion_handler(kmq_msg_completion_handler h, + kmq_message * m) { + if (h == NULL) + return 0; + + /* We only dispatch to the completion thread if we are not the + completion thread. If calling the completion handler results + in more messages completing, then we just call the completion + handler directly. We also make an exception for completions + that happen before the message queue is properly intiailized. */ + + if (kmq_tid_compl != GetCurrentThreadId() && + kmq_h_compl != NULL) { + + EnterCriticalSection(&cs_compl); + QPUT(&kmq_completion_xfer, m); + SetEvent(compl_wx); + LeaveCriticalSection(&cs_compl); + + return 1; + + } else { + h(m); + + return 0; + } +} + +KHMEXP khm_int32 KHMAPI kmq_init(void) { + if (InterlockedIncrement(&kmq_init_once) == 1) { + EnterCriticalSection(&cs_kmq_global); + + InitializeCriticalSection(&cs_compl); + compl_wx = CreateEvent(NULL, FALSE, FALSE, NULL); + compl_continue = TRUE; + QINIT(&kmq_completion_xfer); + + kmq_h_compl = CreateThread(NULL, + 0, + kmqint_completion_thread_proc, + NULL, + 0, + &kmq_tid_compl); + + assert(kmq_h_compl != NULL); + + LeaveCriticalSection(&cs_kmq_global); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI kmq_exit(void) { + if (InterlockedDecrement(&kmq_init_once) == 0) { + + EnterCriticalSection(&cs_compl); + compl_continue = FALSE; + SetEvent(compl_wx); + LeaveCriticalSection(&cs_compl); + + WaitForSingleObject(kmq_h_compl, INFINITE); + + EnterCriticalSection(&cs_kmq_global); + CloseHandle(kmq_h_compl); + kmq_h_compl = NULL; + kmq_tid_compl = 0; + CloseHandle(compl_wx); + DeleteCriticalSection(&cs_compl); + LeaveCriticalSection(&cs_kmq_global); + } + + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/kmq/kmq.h b/mechglue/src/windows/identity/kmq/kmq.h new file mode 100644 index 000000000..4c8c610cd --- /dev/null +++ b/mechglue/src/windows/identity/kmq/kmq.h @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KMQ_H__ +#define __KHIMAIRA_KMQ_H__ + +/*! \defgroup kmq NetIDMgr Message Queue */ +/*@{*/ + +#include +#include +#include + +/* general */ +#ifdef _WIN32 +typedef DWORD kmq_thread_id; +typedef DWORD kmq_timer; +#endif + +#ifdef _WIN32 +/*! \brief Window message for kmq + + This message is sent to the window procedure of a window if that + window is a subscriber to KMQ messages. + + \see kmq_subscribe_hwnd() for more information about handling this + window message + */ +#define KMQ_WM_DISPATCH (WM_APP+0x100) +#endif + +/* callback */ + +/*! \brief A message callback + + Should return TRUE if the message is properly handled. Otherwise + return FALSE */ +typedef khm_int32 (KHMAPI *kmq_callback_t)(khm_int32 msg_type, + khm_int32 msg_sub_type, + khm_ui_4 uparam, + void * vparam); + +/* message */ + +/*! \brief A single response. + + Certain broadcast messages may user scatter-gather type + notification and result gathering. Individual subscribers to a + message attach their individual responses to a ::kmq_response + object and attach that to the message which can later be read by + the sender of the message. + */ +typedef struct tag_kmq_response { + kmq_thread_id thread; + void * response; + + LDCL(struct tag_kmq_response); +} kmq_response; + +/*! \brief A single message + */ +typedef struct tag_kmq_message { + khm_int32 type; /*!< Type of message */ + khm_int32 subtype; /*!< Subtype of message */ + + khm_ui_4 uparam; /*!< Integer parameter */ + void * vparam; /*!< Pointer to parameter blob */ + + khm_int32 nSent; /*!< Number of instances of message + sent (for broadcast messages) */ + + khm_int32 nCompleted; /*!< Number of instances that have + completed processing (for broadcast + messages) */ + + khm_int32 nFailed; /*!< Number of instances that failed + to process (for broadcast + messages) */ + + kmq_response * responses; /*!< List of responses */ + HANDLE wait_o; /*!< Event to wait on (only valid if + the publisher of the message + requested a handle to the call) */ + + kmq_timer timeSent; /*!< Time at which the message was + sent */ + kmq_timer timeExpire; /*!< Time at which the message + expires */ + + kherr_context * err_ctx; /*!< Error context for the message */ + + khm_int32 refcount; + + LDCL(struct tag_kmq_message); +} kmq_message; + +/*! \brief A handle to a call + */ +typedef kmq_message *kmq_call; + +/*! \brief Message reference */ +typedef struct tag_kmq_message_ref { + kmq_message * msg; /*!< Message that we are referring + to */ + kmq_callback_t recipient; /*!< The recipient of the message */ + + LDCL(struct tag_kmq_message_ref); +} kmq_message_ref; + +/*! \brief Message queue + + Each thread gets its own message queue. When a message is + broadcast to which there is a subscriber in a particular thread, a + reference to the message is placed in the message queue of the + thread. The dispatch procedure then dispatches the message as + described in the message reference. +*/ +typedef struct tag_kmq_queue { + kmq_thread_id thread; /*!< The thread id */ + + CRITICAL_SECTION cs; + HANDLE wait_o; + + khm_int32 load; /*!< Number of messages waiting to be + processed on this message queue. */ + kmq_timer last_post; /*!< Time the last message was + received */ + + /*Q*/ + QDCL(kmq_message_ref); /*!< Queue of message references */ + + /*Lnode*/ + LDCL(struct tag_kmq_queue); +} kmq_queue; + +/*! \brief Message subscription + + A subscription binds a recipient with a message type. These are + specific to a thread. I.e. a subscription that was made in one + thread will not receive messages in the context of another thread. +*/ +typedef struct tag_kmq_msg_subscription { + khm_int32 type; /*!< Type of message */ + khm_int32 rcpt_type; /*!< Type of recipient. One of + ::KMQ_RCPTTYPE_CB or + ::KMQ_RCPTTYPE_HWND */ + union { + kmq_callback_t cb; /*!< Callback if the subscription is + of callback type */ + HWND hwnd; /*!< Window handle if the subscription + is a windows message type */ + } recipient; + + kmq_queue * queue; /*!< Associated queue */ + + /*lnode*/ + LDCL(struct tag_kmq_msg_subscription); +} kmq_msg_subscription; + +/*! \brief Callback recipient type + + The recipient is a callback function */ +#define KMQ_RCPTTYPE_CB 1 + +/*! \brief Windows recipient type + + The recipient is a window */ +#define KMQ_RCPTTYPE_HWND 2 + +/* publishers */ + +/*! \brief A completion handler for a message + + Each message type can have a completion handler. Once a message + of this a specific type has been broadcast and handled by all the + subscripbers, the message will be passed down to the completion + handler before the associated data structures are freed. This + allows applications that define message type to also define clean + up for each message. For example, the completion handler can + initiate another message if the messages form a sequence or free + up blocks of memory that was passed as the parameter to the + message. + */ +typedef void (KHMAPI *kmq_msg_completion_handler)(kmq_message *); + +/*! \brief A message type + */ +typedef struct tag_kmq_msg_type { + khm_int32 id; /*!< Identifier for the message + type. */ + kmq_msg_subscription * subs; /*!< The list of subscriptions */ + kmq_msg_completion_handler completion_handler; /*!< Completion + handler for the message type */ + + wchar_t * name; /*!< Name of the message type for + named types. Message type names are + language independant. */ + + /*Lnode*/ + LDCL(struct tag_kmq_msg_type); +} kmq_msg_type; + +/*! \brief The maximum number of message types + */ +#define KMQ_MSG_TYPE_MAX 255 + +/*! \brief Maximum number of characters in a message type name + + The count includes the terminating NULL + */ +#define KMQ_MAXCCH_TYPE_NAME 256 + +/*! \brief Maximum number of bytes in a message type name + + Type count includes the terminating NULL + */ +#define KMQ_MAXCB_TYPE_NAME (KMQ_MAXCCH_TYPE_NAME * sizeof(wchar_t)) + +KHMEXP khm_int32 KHMAPI kmq_init(void); + +KHMEXP khm_int32 KHMAPI kmq_exit(void); + +/*! \brief Register a message type + + Registers a custom message type. The \a name parameter specifies + a language independent name for the message type and must be + unique and must be less than ::KMQ_MAXCCH_TYPE_NAME characters. + + \param[in] name Name of the message type. Upto + ::KMQ_MAXCCH_TYPE_NAME characters including terminating NULL. + The \a name cannot be a zero length string. + + \param[out] new_id Receives the new message type ID. Specify NULL + if the new message type is not required. + + \see kmq_find_type() and kmq_unregister_type() + + \retval KHM_ERROR_INVALID_PARAM The \a name parameter was invalid. + \retval KHM_ERROR_EXISTS A message type with that name already exists. + \retval KHM_ERROR_NO_RESOURCES Can't register any more message types. + \retval KHM_ERROR_SUCCESS The operation succeeded. + */ +KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, khm_int32 * new_id); + +/*! \brief Find a message type + + Find the message type with the given name. If found, the type ID + is returned in \a id. + + \retval KHM_ERROR_SUCCESS A message type with the given name was + found. + \retval KHM_ERROR_NOT_FOUND A message type with the given name was + not found. + */ +KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id); + +/*! \brief Unregister a message type + + Unregisters a message type that was registered using + kmq_register_type(). + + \retval KHM_ERROR_SUCCESS The specified message type was + successfully unregistered. + + \retval KHM_ERROR_NOT_FOUND The message type was not found. + */ +KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id); + +/*! \brief Subscribte to a message type. + + Adds a subscription to messages of type \a type. Subscriptions + are managed per thread. Therefore the subscription is actually + added to the subscription list for the current thread (the thread + which calls kmq_subscribe()). + + When a message of type \a type is received by the thread, it is + dispatched to the callback function identified by \a cb within the + context of this thread. + + \note Calling kmq_subscribe() from within multiple threads with + the same \a type and \a cb will result in multiple + subscriptions. + + \see kmq_unsubscribe() + \see kmq_dispatch() +*/ +KHMEXP khm_int32 KHMAPI kmq_subscribe(khm_int32 type, kmq_callback_t cb); + +/*! \brief Subscribe a window to a message type + + Adds the window specified by \a hwnd to the subscription list for + the message type \a type. When a message of this type is posted, + then the window procedure of the window \a hwnd receives a message + ::KMQ_WM_DISPATCH. + + When a window receives a ::KMQ_WM_DISPATCH message, it means that + a message has been posted which is of a type that the window has + subscribed for. Because of the way Windows handles window + messages and the way NetIDMgr message queues work, a thread which + has a window (or thread) procedure can not call kmq_dispatch() to + handle these messages. For threads that have window or thread + message loops, they must call kmq_subscribe_hwnd() to subscribe a + particular window (for thread message loops, this would be the + HWND of the message window for the thread) to NetIDMgr messages. + + There are two supported ways of handling the ::KMQ_WM_DISPATCH + message. Examples of both are provided below. + + Handling the message inline: + + \code + LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + kmq_message * m; + khm_int32 rv; + ... + switch(uMsg) { + case WM_CREATE: + ... + kmq_subscribe_hwnd(KMSG_CRED, hwnd); + ... + break; + + case WM_DESTROY: + ... + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); + ... + break; + + ... + case KMQ_WM_DISPATCH: + kmq_wm_begin(lParam,&m); + + if(m->type == KMSG_CRED && m->subtype == KMSG_CRED_ROOTDELTA) { + // do something + rv = KHM_ERROR_SUCCESS; + } + + return kmq_wm_end(m, rv); + ... + }; + ... + } + \endcode + + The other method is to dispatch the ::KMQ_WM_DISPATCH message to a + secondary callback function: + + \code + khm_int32 msg_handler(khm_int32 t, khm_int32 st, khm_ui_4 up, void * pb) { + khm_int32 rv = KHM_ERROR_SUCCESS; + + //handle message + + return rv; + } + + LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + kmq_message * m; + khm_int32 rv; + ... + switch(uMsg) { + ... + + case WM_CREATE: + ... + kmq_subscribe_hwnd(KMSG_CRED, hwnd); + ... + break; + + case WM_DESTROY: + ... + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); + ... + break; + + ... + case KMQ_WM_DISPATCH: + return kmq_wm_dispatch(lParam, msg_handler); + ... + }; + ... + } + \endcode + + \note Make sure you unsubscribe from the message type when the + window is destroyed. + + \see kmq_unsubscribe_hwnd() + \see kmq_wm_begin() + \see kmq_wm_end() + \see kmq_wm_dispatch() + */ +KHMEXP khm_int32 KHMAPI kmq_subscribe_hwnd(khm_int32 type, HWND hwnd); + +#ifdef _WIN32 +/*! \brief Begins handling a KMQ_WM_DISPATCH message + + \return The return value of this function should be ignored. + + \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH + */ +KHMEXP LRESULT KHMAPI kmq_wm_begin(LPARAM lparm, kmq_message ** m); + +/*! \brief Ends handling a KMQ_WM_DISPATCH message + + \return The return value of this function should be the return + value of the window procedure. See kmq_subscribe_hwnd() + documentation for example + + \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH + */ +KHMEXP LRESULT KHMAPI kmq_wm_end(kmq_message *m, khm_int32 rv); + +/*! \brief Dispatches a KMQ_WM_DISPATCH message to a callback + + \return The return value of this function should be the return + value of the window procedure. See kmq_subscribe_hwnd() + documentation for example. + + \see kmq_subscribe_hwnd() for more details about handling ::KMQ_WM_DISPATCH + */ +KHMEXP LRESULT KHMAPI kmq_wm_dispatch(LPARAM lparm, kmq_callback_t cb); +#endif + +/*! \brief Unsubscribe a callback from a message type + + Removes the subscription for message type \a type for callback + function \a cb from the subscription list for the current thread + (the thread that calls kmq_unsubscribe()). + + \note kmq_unsubscribe() can only remove subscriptions for the subscription + list for the current thread. + + \see kmq_subscribe() + \see kmq_dispatch() +*/ +KHMEXP khm_int32 KHMAPI kmq_unsubscribe(khm_int32 type, kmq_callback_t cb); + +/*! \brief Unsubscribe a window from a message type + + Removes the specific window from the subsription list for message + type \a type. + + \see kmq_subscribe_hwnd() +*/ +KHMEXP khm_int32 KHMAPI kmq_unsubscribe_hwnd(khm_int32 type, HWND hwnd); + +/*! \brief Create an ad-hoc subscription + + An ad-hoc subscription describes a callback point in a thread that + can be dispatched messages to individually without broadcasting. + + \see kmq_post_sub_msg(), kmq_post_sub_msg_ex(), + kmq_send_sub_msg(), kmq_post_subs_msg(), + kmq_post_subs_msg_ex(), kmq_send_subs_msg(), + kmq_delete_subscription() +*/ +KHMEXP khm_int32 KHMAPI kmq_create_subscription( + kmq_callback_t cb, + khm_handle * result); + +/*! \brief Delete an ad-hoc subscription + + Deletes a subscriptoin that was created using + kmq_create_subscription() + */ +KHMEXP khm_int32 KHMAPI kmq_delete_subscription(khm_handle sub); + +/*! \brief Post a message to a subscription + + Equivalent of kmq_post_msg() but only posts the message to the + specified subscription. + */ +KHMEXP khm_int32 KHMAPI kmq_post_sub_msg( + khm_handle sub, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam); + +/*! \brief Post a message to a subscription and acquire a handle to the call + */ +KHMEXP khm_int32 KHMAPI kmq_post_sub_msg_ex( + khm_handle sub, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam, + kmq_call * call); + +/*! \brief Send a synchronous message to a subscription + + \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors + \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors + */ +KHMEXP khm_int32 KHMAPI kmq_send_sub_msg( + khm_handle sub, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam); + +/*! \brief Post a message to a group of subscriptions + + The block of memory pointed to by \a subs should be an array of + subscriptions. The number of elements in that array should be \a + n_subs. A message as specified by the remaining parameters will + be dispatched to all of the subscription points in the array. + */ +KHMEXP khm_int32 KHMAPI kmq_post_subs_msg( + khm_handle * subs, + khm_size n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam); + +/*! \brief Post a message to a group of subscriptions and acquire a handle to the call + + The block of memory pointed to by \a subs should be an array of + subscriptions. The number of elements in that array should be \a + n_subs. A message as specified by the remaining parameters will + be dispatched to all of the subscription points in the array, and + a handle to the call will be returned in \a call. + + The returned \a call will reference all of the dispatches that + were made. +*/ +KHMEXP khm_int32 KHMAPI kmq_post_subs_msg_ex( + khm_handle * subs, + khm_int32 n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam, + kmq_call * call); + +/*! \brief Send a synchronous message to a group of subscriptions + + The block of memory pointed to by \a subs should be an array of + subscriptions. The number of elements in that array should be \a + n_subs. A message as specified by the remaining parameters will + be dispatched to all of the subscription points in the array. The + function will not return until all of the calls have succeeded. + + \retval KHM_ERROR_SUCCESS The call succeeded, and no subscribers reported errors + \retval KHM_ERROR_PARTIAL The call succeeded, but at least one subscriber reported errors +*/ +KHMEXP khm_int32 KHMAPI kmq_send_subs_msg( + khm_handle *subs, + khm_int32 n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam); + +/*! \brief Dispatch a message for the current thread. + + This function opens the message list for the current thread and + dispatches the first message instance that is found. Note that if + multiple callbacks subscribe to the same message type in the same + thread, then when a message of that type is received, multiple + message instances are added to the message queue corresponding to + each subscription. + + If no message instances are waiting in the queue, kmq_dispatch() + waits for the \a timeout period for a message. + + \param[in] timeout The timeout period in milliseconds. Specify INFINITE for + kmq_dispatch() to wait indefinitely. + + \retval KHM_ERROR_SUCCESS A message instance was dispatched + \retval KHM_ERROR_TIMEOUT The timeout period elapsed + \retval KHM_ERROR_EXIT The message found on the queue was +*/ +KHMEXP khm_int32 KHMAPI kmq_dispatch(kmq_timer timeout); + +/*! \brief Send a message + + The specified message will be posted to all the subscribers of the + message type. Then the function will wait for all the subscribers + to finish processing the message before returning. + + \param[in] type The type of the message + \param[in] subtype The subtype + \param[in] uparam The khm_ui_4 parameter for the message + \param[in] blob The parameter blob for the message + + \note The internal timeout for this function is INFINITE. If you + it is desirable to use a different timeout, use + kmq_post_message_ex() and kmq_wait() functions. + + \retval KHM_ERROR_SUCCESS The call succeeded and no subscribers returned errors + \retval KHM_ERROR_PARTIAL The call succeeded but at least one subscriber returned an error +*/ +KHMEXP khm_int32 KHMAPI kmq_send_message( + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * blob); + +/*! \brief Post a message + + The specified message will be posted to all the subscribers of the + message type. The function returns immediately. + + If you want to be able to wait for all the subscribers to finish + processing the message, you should use kmq_post_message_ex() + instead. + + \param[in] type The type of the message + \param[in] subtype The subtype + \param[in] uparam The khm_ui_4 parameter for the message + \param[in] blob The parameter blob for the message +*/ +KHMEXP khm_int32 KHMAPI kmq_post_message( + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * blob); + +/*! \brief Post a message and acquire a handle to the call. + + The specified message is posted to all the subscribers. In + addition, a handle is obtained for the call which can be used in + subsequent call to kmq_free_call() or kmq_wait(). + + Call kmq_free_call() to free the handle. + + \param[in] type The type of the message + \param[in] subtype The subtype + \param[in] uparam The khm_ui_4 parameter for the message + \param[in] blob The parameter blob for the message + \param[out] call Receives the call handle. Set to NULL if the call handle is not required. + + \see kmq_free_call() +*/ +KHMEXP khm_int32 KHMAPI kmq_post_message_ex( + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * blob, + kmq_call * call); + +/*! \brief Free a handle to a call obtained through kmq_post_message_ex() + + All call handles obtained through kmq_post_message_ex() must be + freed via a call to kmq_free_call(). +*/ +KHMEXP khm_int32 KHMAPI kmq_free_call(kmq_call call); + +/*! \brief Sends a message to the specified thread. + + The message itself will not be received by any callback function, + however, any kmq_dispatch() function that is currently active of + becomes active will exit with a KHM_ERROR_EXIT code. + kmq_send_thread_quit_message() will wait for this to happen before + returning. + */ +KHMEXP khm_int32 KHMAPI kmq_send_thread_quit_message( + kmq_thread_id thread, + khm_ui_4 uparam); + +/*! \brief Post a message to the specified thread. + + The message itself will not be received by any callback function, + however, any kmq_dispatch() function that is currently active of + becomes active will exit with a KHM_ERROR_EXIT code. + kmq_post_thread_quit_message() will return immediately. + */ +KHMEXP khm_int32 KHMAPI kmq_post_thread_quit_message( + kmq_thread_id thread, + khm_ui_4 uparam, + kmq_call * call); + +KHMEXP khm_int32 KHMAPI kmq_get_next_response(kmq_call call, void ** resp); + +/*! \brief Check if a specific call has completed + + \return TRUE if the call has completed. FALSE otherwise. +*/ +KHMEXP khm_boolean KHMAPI kmq_has_completed(kmq_call call); + +/*! \brief Wait for a call to complete. + + Waits for the specified call to complete. If the call dispatched + to multiple recipients, the function waits for all dispatches to + complete. + + If the call has already completed, then the function returns + immediately. + + If more than one thread is waiting for a single message to + complete, then only one of them will be released when the message + compeltes. Each subsequent thread will be released as each + released thread calls kmq_free_call(). + + \param[in] call A handle to a call. + \param[in] timeout Specifies, in milliseconds, the amount of time + to wait for the call to complete. Specify INFINITE to wait + indefinitely. + + \retval KHM_ERROR_SUCCESS The call completed + \retval KHM_ERROR_TIMEOUT The timeout period expired + \retval KHM_ERROR_INVALID_PARAM One of the parameters were invalid. +*/ +KHMEXP khm_int32 KHMAPI kmq_wait(kmq_call call, kmq_timer timeout); + +/*! \brief Sets the completion handler for a specified message type. + + \note Only one completion handler can exist for one message type. + Calling this function overwrites the previous completion + handler. +*/ +KHMEXP khm_int32 KHMAPI kmq_set_completion_handler( + khm_int32 type, + kmq_msg_completion_handler hander); + +/*@}*/ +#endif diff --git a/mechglue/src/windows/identity/kmq/kmqconfig.csv b/mechglue/src/windows/identity/kmq/kmqconfig.csv new file mode 100644 index 000000000..c6d5ca451 --- /dev/null +++ b/mechglue/src/windows/identity/kmq/kmqconfig.csv @@ -0,0 +1,5 @@ +Name,Type,Value,Description +KMQ,KC_SPACE,0,Options for the credentials window + QueueDeadTimeout,KC_INT32,12000, + CallDeadTimeout,KC_INT32,8000, +KMQ,KC_ENDSPACE,0, diff --git a/mechglue/src/windows/identity/kmq/kmqinternal.h b/mechglue/src/windows/identity/kmq/kmqinternal.h new file mode 100644 index 000000000..aeaf3366c --- /dev/null +++ b/mechglue/src/windows/identity/kmq/kmqinternal.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KMQINTERNAL_H +#define __KHIMAIRA_KMQINTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define KMQ_CONF_SPACE_NAME L"KMQ" +#define KMQ_CONF_QUEUE_DEAD_TIMEOUT_NAME L"QueueDeadTimeout" +#define KMQ_CONF_CALL_DEAD_TIMEOUT_NAME L"CallDeadTimeout" + +extern CRITICAL_SECTION cs_kmq_global; +extern kmq_timer kmq_queue_dead_timeout; +extern kmq_timer kmq_call_dead_timeout; + +extern kmq_queue * queues; + +/* message type */ +extern CRITICAL_SECTION cs_kmq_types; +extern kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX+1]; + +void kmqint_init_msg_types(void); +void kmqint_exit_msg_types(void); +void kmqint_free_msg_type(int t); +void kmqint_msg_type_create(int t); +void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s); +void kmqint_msg_type_del_sub(kmq_msg_subscription *s); +kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd); +kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb); +khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send); +khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler); +int kmqint_notify_msg_completion(kmq_message * m); + +/* consumer */ +extern DWORD kmq_tls_queue; + +void kmqint_post_queue(kmq_queue * q, kmq_message *m); +void kmqint_post(kmq_msg_subscription * s, kmq_message * m, khm_boolean try_send); +kmq_queue * kmqint_get_thread_queue(void); +void kmqint_get_queue_message_ref(kmq_queue * q, kmq_message_ref ** r); + +/* publisher */ +extern CRITICAL_SECTION cs_kmq_msg; +extern CRITICAL_SECTION cs_kmq_msg_ref; + +kmq_message * kmqint_get_message(void); +void kmqint_put_message(kmq_message *m); + +void kmqint_init(void); +void kmqint_exit(void); +void kmqint_attach_this_thread(void); +void kmqint_detach_this_thread(void); + +khm_int32 kmqint_post_message_ex( + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * blob, + kmq_call * call, + khm_boolean try_send); + +int kmqint_call_completion_handler(kmq_msg_completion_handler h, + kmq_message * m); + +/* global */ +extern kconf_schema schema_kmqconfig[]; + +/* Lock hiearchy : + + cs_kmq_types + cs_kmq_msg + cs_kmq_msg_ref + cs_compl + cs_kmq_global + kmq_queue::cs + + If you have a level 'x' lock, you can obtain a level 'x+n' lock. + You can't obtain a 'x-n' lock if you already have a level 'x' lock. + If you don't have any locks, you can obtain any lock. + */ +#endif diff --git a/mechglue/src/windows/identity/kmq/kmqmain.c b/mechglue/src/windows/identity/kmq/kmqmain.c new file mode 100644 index 000000000..3e8176f1b --- /dev/null +++ b/mechglue/src/windows/identity/kmq/kmqmain.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +void +kmq_process_attach(void) { + kmqint_init(); +} + +void +kmq_process_detach(void) { + kmqint_exit(); +} + +void +kmq_thread_attach(void) { + kmqint_attach_this_thread(); +} + +void +kmq_thread_detach(void) { + kmqint_detach_this_thread(); +} diff --git a/mechglue/src/windows/identity/kmq/msgtype.c b/mechglue/src/windows/identity/kmq/msgtype.c new file mode 100644 index 000000000..62a0133d2 --- /dev/null +++ b/mechglue/src/windows/identity/kmq/msgtype.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +CRITICAL_SECTION cs_kmq_types; + +kmq_msg_type *msg_types[KMQ_MSG_TYPE_MAX + 1]; +kmq_msg_type *all_msg_types = NULL; + +/*! \internal + \brief Initializes the message type data structures + \note called with cs_mkq_global held */ +void kmqint_init_msg_types(void) { + ZeroMemory(msg_types, sizeof(kmq_msg_type *) * (KMQ_MSG_TYPE_MAX + 1)); + InitializeCriticalSection(&cs_kmq_types); +} + +/*! \internal + \brief Frees up the message type data structures + \note called with cs_mkq_global held */ +void kmqint_exit_msg_types(void) { + int i; + + EnterCriticalSection(&cs_kmq_types); + for(i=0;itype]; + if(mt == NULL) + return 0; + h = mt->completion_handler; + + /* handler is set to NULL before freeing type */ + if(h == NULL || msg_types[m->type] == NULL) + return 0; + + return kmqint_call_completion_handler(h,m); +} + +/* called with cs_mkq_global && cs_kmq_types held */ +void kmqint_free_msg_type(int t) { + /*TODO: free the message type*/ + /* must set handler to NULL before freeing type */ + /* must set msg_type[t] = NULL before starting to free type */ +} + +/*! \internal + \brief Create a message type + \note Obtains ::cs_kmq_types + */ +void kmqint_msg_type_create(int t) { + if(t < 0 || t > KMQ_MSG_TYPE_MAX) + return; + + EnterCriticalSection(&cs_kmq_types); + if(!msg_types[t]) { + kmq_msg_type * mt; + mt = PMALLOC(sizeof(kmq_msg_type)); + ZeroMemory(mt, sizeof(kmq_msg_type)); + mt->id = t; + LINIT(mt); + mt->subs = NULL; + msg_types[t] = mt; + + LPUSH(&all_msg_types, mt); + } + LeaveCriticalSection(&cs_kmq_types); +} + +KHMEXP khm_int32 KHMAPI kmq_register_type(wchar_t * name, + khm_int32 * new_id) +{ + int i; + khm_int32 rv = KHM_ERROR_SUCCESS; + BOOL registered = FALSE; + int first_free = 0; + size_t sz; + + if(FAILED(StringCbLength(name, KMQ_MAXCB_TYPE_NAME, &sz)) || + sz == 0) + return KHM_ERROR_INVALID_PARAM; + sz += sizeof(wchar_t); + + EnterCriticalSection(&cs_kmq_types); + for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) { + if(msg_types[i] == NULL) { + if(first_free == 0) + first_free = i; + /* continue searching since we might find that this type + is already registered. */ + } else { + if(msg_types[i]->name != NULL && + !wcscmp(msg_types[i]->name, name)) { + + registered = TRUE; + if (new_id) + *new_id = i; + break; + } + } + } + + if(registered) { + rv = KHM_ERROR_EXISTS; + } else if(first_free == 0) { + rv = KHM_ERROR_NO_RESOURCES; + } else { + kmqint_msg_type_create(first_free); + msg_types[first_free]->name = PMALLOC(sz); + StringCbCopy(msg_types[first_free]->name, sz, name); + + if(new_id != NULL) + *new_id = first_free; + } + LeaveCriticalSection(&cs_kmq_types); + + return rv; +} + +KHMEXP khm_int32 KHMAPI kmq_find_type(wchar_t * name, khm_int32 * id) +{ + int i; + + EnterCriticalSection(&cs_kmq_types); + for(i=KMSGBASE_USER; i <= KMQ_MSG_TYPE_MAX; i++) { + if(msg_types[i] != NULL && msg_types[i]->name != NULL) { + if(!wcscmp(msg_types[i]->name, name)) + break; + } + } + LeaveCriticalSection(&cs_kmq_types); + + if(i <= KMQ_MSG_TYPE_MAX) { + if(id != NULL) + *id = i; + return KHM_ERROR_SUCCESS; + } + + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI kmq_unregister_type(khm_int32 id) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(id < KMSGBASE_USER || id > KMQ_MSG_TYPE_MAX) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_kmq_types); + if(msg_types[id] != NULL) { + EnterCriticalSection(&cs_kmq_global); + kmqint_free_msg_type(id); + LeaveCriticalSection(&cs_kmq_global); + } else { + rv = KHM_ERROR_NOT_FOUND; + } + LeaveCriticalSection(&cs_kmq_types); + + return rv; +} + +/*! \internal + \brief Adds a subscription to a message type + \note Obtains ::cs_kmq_types + */ +void kmqint_msg_type_add_sub(int t, kmq_msg_subscription *s) { + kmq_msg_subscription * ts; + + if(t < 0 || t > KMQ_MSG_TYPE_MAX) + return; + + if(!msg_types[t]) + kmqint_msg_type_create(t); + + EnterCriticalSection(&cs_kmq_types); + s->type = t; + /* check if we already have this subscription */ + ts = msg_types[t]->subs; + while(ts) { + if((ts->rcpt_type == s->rcpt_type) && + (((ts->rcpt_type == KMQ_RCPTTYPE_CB) && (ts->recipient.cb == s->recipient.cb)) || + ((ts->rcpt_type == KMQ_RCPTTYPE_HWND) && (ts->recipient.hwnd == s->recipient.hwnd)))) + break; + ts = LNEXT(ts); + } + /* add it if we didn't find it */ + if(!ts) { + LPUSH(&msg_types[t]->subs, s); + } + LeaveCriticalSection(&cs_kmq_types); +} + +/*! \internal + \brief Delete a subscription + \note Obtains ::cs_kmq_types + */ +void kmqint_msg_type_del_sub(kmq_msg_subscription *s) { + int t = s->type; + + EnterCriticalSection(&cs_kmq_types); + if(msg_types[t]) { + LDELETE(&msg_types[t]->subs,s); + } + LeaveCriticalSection(&cs_kmq_types); +} + + +/*! \internal + \brief Deletes a window subscription from a message type + \note Obtains ::cs_kmq_types +*/ +kmq_msg_subscription * kmqint_msg_type_del_sub_hwnd(khm_int32 t, HWND hwnd) { + kmq_msg_subscription *s; + + if(t < 0 || t > KMQ_MSG_TYPE_MAX) + return NULL; + + EnterCriticalSection(&cs_kmq_types); + if(msg_types[t]) { + s = msg_types[t]->subs; + while(s) { + kmq_msg_subscription * n = LNEXT(s); + if(s->rcpt_type == KMQ_RCPTTYPE_HWND && s->recipient.hwnd == hwnd) { + /*TODO: do more here? */ + LDELETE(&msg_types[t]->subs, s); + break; + } + s = n; + } + } + LeaveCriticalSection(&cs_kmq_types); + + return s; +} + +/*! \internal + \brief Delete a callback from a message type + \note Obtains ::cs_kmq_types, ::cs_kmq_global + */ +kmq_msg_subscription * kmqint_msg_type_del_sub_cb(khm_int32 t, kmq_callback_t cb) { + kmq_msg_subscription *s; + kmq_queue *q; + + if(t < 0 || t > KMQ_MSG_TYPE_MAX) + return NULL; + + if(!msg_types[t]) + return NULL; + + q = kmqint_get_thread_queue(); + + EnterCriticalSection(&cs_kmq_types); + s = msg_types[t]->subs; + while(s) { + kmq_msg_subscription * n = LNEXT(s); + if(s->rcpt_type == KMQ_RCPTTYPE_CB && + s->recipient.cb == cb && + s->queue == q) { + /*TODO: do more here? */ + LDELETE(&msg_types[t]->subs, s); + break; + } + s = n; + } + LeaveCriticalSection(&cs_kmq_types); + + return s; +} + +/*! \internal + \brief Publish a message + \note Obtains ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs, ::cs_kmq_msg + */ +khm_int32 kmqint_msg_publish(kmq_message * m, khm_boolean try_send) { + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(msg_types[m->type]) { + kmq_msg_type *t; + kmq_msg_subscription * s; + + EnterCriticalSection(&cs_kmq_types); + EnterCriticalSection(&cs_kmq_msg); + t = msg_types[m->type]; + s = t->subs; + while(s) { + kmqint_post(s, m, try_send); + s = LNEXT(s); + } + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + + LeaveCriticalSection(&cs_kmq_msg); + LeaveCriticalSection(&cs_kmq_types); + + } else { + EnterCriticalSection(&cs_kmq_msg); + kmqint_put_message(m); + LeaveCriticalSection(&cs_kmq_msg); + } + return rv; +} + +/*! \internal + \brief Sets the completion handler for a message type + \note Obtains ::cs_kmq_types + */ +khm_int32 kmqint_msg_type_set_handler(khm_int32 type, kmq_msg_completion_handler handler) { + + if (type == KMSG_SYSTEM) + return KHM_ERROR_INVALID_PARAM; + + if(!msg_types[type]) + kmqint_msg_type_create(type); + + if(!msg_types[type]) + return KHM_ERROR_NO_RESOURCES; + + EnterCriticalSection(&cs_kmq_types); + msg_types[type]->completion_handler = handler; + LeaveCriticalSection(&cs_kmq_types); + + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/kmq/publisher.c b/mechglue/src/windows/identity/kmq/publisher.c new file mode 100644 index 000000000..af1f55566 --- /dev/null +++ b/mechglue/src/windows/identity/kmq/publisher.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +CRITICAL_SECTION cs_kmq_msg; +kmq_message * msg_free = NULL; +kmq_message * msg_active = NULL; + +/*! \internal + \brief Get a message object + \note called with ::cs_kmq_msg held */ +kmq_message * +kmqint_get_message(void) { + kmq_message * m; + + LPOP(&msg_free,&m); + if(!m) { + /* allocate one */ + m = PMALLOC(sizeof(kmq_message)); + } + ZeroMemory((void*)m, sizeof(kmq_message)); + + LPUSH(&msg_active, m); + + return m; +} + +/*! \internal + \brief Frees a message object + \note called with ::cs_kmq_msg held + */ +void +kmqint_put_message(kmq_message *m) { + int queued; + /* we can only free a message if the refcount is zero. + Otherwise we have to wait until the call is freed. */ + if(m->refcount == 0) { + LDELETE(&msg_active, m); + LeaveCriticalSection(&cs_kmq_msg); + queued = kmqint_notify_msg_completion(m); + EnterCriticalSection(&cs_kmq_msg); + if (!queued) { + if(m->err_ctx) { + kherr_release_context(m->err_ctx); + m->err_ctx = NULL; + } + if(m->wait_o) { + CloseHandle(m->wait_o); + m->wait_o = NULL; + } + LPUSH(&msg_free,m); + } + } else if(m->wait_o) { + SetEvent(m->wait_o); + } +} + +/*! \internal + \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs + */ +KHMEXP khm_int32 KHMAPI +kmq_send_message(khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * blob) { + kmq_call c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmqint_post_message_ex(type, subtype, uparam, blob, &c, TRUE); + if(KHM_FAILED(rv)) + return rv; + + rv = kmq_wait(c, INFINITE); + if(KHM_SUCCEEDED(rv) && c->nFailed > 0) + rv = KHM_ERROR_PARTIAL; + + kmq_free_call(c); + + return rv; +} + +/*! \internal + \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs + */ +KHMEXP khm_int32 KHMAPI +kmq_post_message(khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * blob) { + return kmqint_post_message_ex(type, subtype, uparam, blob, NULL, FALSE); +} + +/*! \internal + \brief Frees a call + \note Obtains ::cs_kmq_msg + */ +KHMEXP khm_int32 KHMAPI +kmq_free_call(kmq_call call) { + kmq_message * m; + + m = call; + + EnterCriticalSection(&cs_kmq_msg); + m->refcount--; + if(!m->refcount) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_SUCCESS; +} + +/*! \internal + \note Obtains ::cs_kmq_msg, ::cs_kmq_types, ::cs_kmq_msg_ref, kmq_queue::cs + */ +khm_int32 +kmqint_post_message_ex(khm_int32 type, khm_int32 subtype, khm_ui_4 uparam, + void * blob, kmq_call * call, khm_boolean try_send) +{ + kmq_message * m; + kherr_context * ctx; + + EnterCriticalSection(&cs_kmq_msg); + m = kmqint_get_message(); + LeaveCriticalSection(&cs_kmq_msg); + + m->type = type; + m->subtype = subtype; + m->uparam = uparam; + m->vparam = blob; + + m->timeSent = GetTickCount(); + m->timeExpire = m->timeSent + kmq_call_dead_timeout; + + ctx = kherr_peek_context(); + if (ctx) { + if (ctx->flags & KHERR_CF_TRANSITIVE) { + m->err_ctx = ctx; + /* leave it held */ + } else { + kherr_release_context(ctx); + } + } + + if(call) { + m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); + *call = m; + m->refcount++; + } else + m->wait_o = NULL; + + kmqint_msg_publish(m, try_send); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmq_post_message_ex(khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * blob, kmq_call * call) +{ + return kmqint_post_message_ex(type, subtype, uparam, blob, call, FALSE); +} + + +/*! \internal +*/ +KHMEXP khm_int32 KHMAPI +kmq_post_sub_msg(khm_handle sub, khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * vparam) +{ + return kmq_post_sub_msg_ex(sub, type, subtype, uparam, vparam, NULL); +} + +/*! \internal +*/ +khm_int32 +kmqint_post_sub_msg_ex(khm_handle sub, khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * vparam, + kmq_call * call, khm_boolean try_send) +{ + kmq_message * m; + kherr_context * ctx; + + EnterCriticalSection(&cs_kmq_msg); + m = kmqint_get_message(); + LeaveCriticalSection(&cs_kmq_msg); + + m->type = type; + m->subtype = subtype; + m->uparam = uparam; + m->vparam = vparam; + + m->timeSent = GetTickCount(); + m->timeExpire = m->timeSent + kmq_call_dead_timeout; + + ctx = kherr_peek_context(); + if (ctx) { + if (ctx->flags & KHERR_CF_TRANSITIVE) { + m->err_ctx = ctx; + /* leave it held */ + } else { + kherr_release_context(ctx); + } + } + + if(call) { + m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); + *call = m; + m->refcount++; + } else + m->wait_o = NULL; + + EnterCriticalSection(&cs_kmq_msg); + kmqint_post((kmq_msg_subscription *) sub, m, try_send); + + if(m->nCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmq_post_sub_msg_ex(khm_handle sub, khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * vparam, kmq_call * call) +{ + return kmqint_post_sub_msg_ex(sub, type, subtype, + uparam, vparam, call, FALSE); +} + +khm_int32 +kmqint_post_subs_msg_ex(khm_handle * subs, khm_size n_subs, khm_int32 type, + khm_int32 subtype, khm_ui_4 uparam, void * vparam, + kmq_call * call, khm_boolean try_send) +{ + kmq_message * m; + kherr_context * ctx; + khm_size i; + + if(n_subs == 0) + return KHM_ERROR_SUCCESS; + + EnterCriticalSection(&cs_kmq_msg); + m = kmqint_get_message(); + LeaveCriticalSection(&cs_kmq_msg); + + m->type = type; + m->subtype = subtype; + m->uparam = uparam; + m->vparam = vparam; + + m->timeSent = GetTickCount(); + m->timeExpire = m->timeSent + kmq_call_dead_timeout; + + ctx = kherr_peek_context(); + if (ctx) { + if (ctx->flags & KHERR_CF_TRANSITIVE) { + m->err_ctx = ctx; + /* leave it held */ + } else { + kherr_release_context(ctx); + } + } + + if(call) { + m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); + *call = m; + m->refcount++; + } else + m->wait_o = NULL; + + EnterCriticalSection(&cs_kmq_msg); + for(i=0;inCompleted + m->nFailed == m->nSent) { + kmqint_put_message(m); + } + LeaveCriticalSection(&cs_kmq_msg); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +kmq_post_subs_msg(khm_handle * subs, + khm_size n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam) +{ + return kmqint_post_subs_msg_ex(subs, + n_subs, + type, + subtype, + uparam, + vparam, + NULL, + FALSE); +} + +KHMEXP khm_int32 KHMAPI +kmq_post_subs_msg_ex(khm_handle * subs, + khm_int32 n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam, + kmq_call * call) +{ + return kmqint_post_subs_msg_ex(subs, n_subs, type, subtype, + uparam, vparam, call, FALSE); +} + +KHMEXP khm_int32 KHMAPI +kmq_send_subs_msg(khm_handle *subs, + khm_int32 n_subs, + khm_int32 type, + khm_int32 subtype, + khm_ui_4 uparam, + void * vparam) +{ + kmq_call c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmqint_post_subs_msg_ex(subs, n_subs, type, subtype, + uparam, vparam, &c, TRUE); + if(KHM_FAILED(rv)) + return rv; + + rv = kmq_wait(c, INFINITE); + if(KHM_SUCCEEDED(rv) && c->nFailed > 0) + rv = KHM_ERROR_PARTIAL; + + kmq_free_call(c); + + return rv; +} + +/*! \internal +*/ +KHMEXP khm_int32 KHMAPI +kmq_send_sub_msg(khm_handle sub, khm_int32 type, khm_int32 subtype, + khm_ui_4 uparam, void * vparam) +{ + kmq_call c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmqint_post_sub_msg_ex(sub, type, subtype, uparam, vparam, &c, TRUE); + if(KHM_FAILED(rv)) + return rv; + + rv = kmq_wait(c, INFINITE); + if(KHM_SUCCEEDED(rv) && c->nFailed > 0) + rv = KHM_ERROR_PARTIAL; + + kmq_free_call(c); + + return rv; +} + +/*! \internal + \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs + */ +KHMEXP khm_int32 KHMAPI +kmq_send_thread_quit_message(kmq_thread_id thread, khm_ui_4 uparam) { + kmq_call c; + khm_int32 rv = KHM_ERROR_SUCCESS; + + rv = kmq_post_thread_quit_message(thread, uparam, &c); + if(KHM_FAILED(rv)) + return rv; + + rv = kmq_wait(c, INFINITE); + + kmq_free_call(c); + + return rv; +} + +/*! \internal + \note Obtains ::cs_kmq_global, ::cs_kmq_msg, ::cs_kmq_msg_ref, kmq_queue::cs + */ +KHMEXP khm_int32 KHMAPI +kmq_post_thread_quit_message(kmq_thread_id thread, + khm_ui_4 uparam, kmq_call * call) { + kmq_message * m; + kmq_queue * q; + + EnterCriticalSection(&cs_kmq_global); + q = queues; + while(q) { + if(q->thread == thread) + break; + q = LNEXT(q); + } + LeaveCriticalSection(&cs_kmq_global); + + if(!q) + return KHM_ERROR_NOT_FOUND; + + EnterCriticalSection(&cs_kmq_msg); + m = kmqint_get_message(); + LeaveCriticalSection(&cs_kmq_msg); + + m->type = KMSG_SYSTEM; + m->subtype = KMSG_SYSTEM_EXIT; + m->uparam = uparam; + m->vparam = NULL; + + m->timeSent = GetTickCount(); + m->timeExpire = m->timeSent + kmq_call_dead_timeout; + + if(call) { + m->wait_o = CreateEvent(NULL,FALSE,FALSE,NULL); + *call = m; + m->refcount++; + } else + m->wait_o = NULL; + + kmqint_post_queue(q, m); + + return KHM_ERROR_SUCCESS; +} + +/* TODO:Implement these */ +KHMEXP khm_int32 KHMAPI +kmq_get_next_response(kmq_call call, void ** resp) { + return 0; +} + +KHMEXP khm_boolean KHMAPI +kmq_has_completed(kmq_call call) { + return (call->nCompleted + call->nFailed == call->nSent); +} + +KHMEXP khm_int32 KHMAPI +kmq_wait(kmq_call call, kmq_timer timeout) { + kmq_message * m = call; + DWORD rv; + /*TODO: check for call free */ + + if(m && m->wait_o) { + rv = WaitForSingleObject(m->wait_o, timeout); + if(rv == WAIT_OBJECT_0) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_TIMEOUT; + } else + return KHM_ERROR_INVALID_PARAM; +} + +/*! \internal + \note Obtains ::cs_kmq_types + */ +KHMEXP khm_int32 KHMAPI +kmq_set_completion_handler(khm_int32 type, + kmq_msg_completion_handler handler) { + return kmqint_msg_type_set_handler(type, handler); +} + diff --git a/mechglue/src/windows/identity/nidmgrdll/Makefile b/mechglue/src/windows/identity/nidmgrdll/Makefile new file mode 100644 index 000000000..03d3c3d54 --- /dev/null +++ b/mechglue/src/windows/identity/nidmgrdll/Makefile @@ -0,0 +1,110 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=nidmgrdll +!include <../config/Makefile.w32> + +DLLFILE=$(BINDIR)\nidmgr32.dll + +LIBFILE=$(LIBDIR)\nidmgr32.lib + +UTILDIR=$(OBJDIR)\util + +KHERRDIR=$(OBJDIR)\kherr + +KCONFIGDIR=$(OBJDIR)\kconfig + +KMQDIR=$(OBJDIR)\kmq + +KCDBDIR=$(OBJDIR)\kcreddb + +KMMDIR=$(OBJDIR)\kmm + +UIDIR=$(OBJDIR)\uilib + +OBJFILES= \ + $(OBJ)\dllmain.obj \ + $(UTILDIR)\hashtable.obj \ + $(UTILDIR)\sync.obj \ + $(UTILDIR)\mstring.obj \ + $(UTILDIR)\perfstat.obj \ + $(KHERRDIR)\kherrmain.obj \ + $(KHERRDIR)\kherr.obj \ + $(KCONFIGDIR)\kconfigmain.obj \ + $(KCONFIGDIR)\api.obj \ + $(KMQDIR)\kmqmain.obj \ + $(KMQDIR)\init.obj \ + $(KMQDIR)\msgtype.obj \ + $(KMQDIR)\consumer.obj \ + $(KMQDIR)\publisher.obj \ + $(KMQDIR)\kmqconfig.obj \ + $(KCDBDIR)\buf.obj \ + $(KCDBDIR)\attrib.obj \ + $(KCDBDIR)\credential.obj \ + $(KCDBDIR)\credset.obj \ + $(KCDBDIR)\credtype.obj \ + $(KCDBDIR)\identity.obj \ + $(KCDBDIR)\init.obj \ + $(KCDBDIR)\kcreddbmain.obj \ + $(KCDBDIR)\type.obj \ + $(KCDBDIR)\kcdbconfig.obj \ + $(KMMDIR)\kmmmain.obj \ + $(KMMDIR)\kmm.obj \ + $(KMMDIR)\kmm_plugin.obj \ + $(KMMDIR)\kmm_module.obj \ + $(KMMDIR)\kmm_reg.obj \ + $(KMMDIR)\kmm_registrar.obj \ + $(KMMDIR)\kmmconfig.obj \ + $(UIDIR)\rescache.obj \ + $(UIDIR)\action.obj \ + $(UIDIR)\creddlg.obj \ + $(UIDIR)\alert.obj \ + $(UIDIR)\propsheet.obj \ + $(UIDIR)\propwnd.obj \ + $(UIDIR)\uilibmain.obj \ + $(UIDIR)\actiondef.obj \ + $(UIDIR)\acceldef.obj \ + $(UIDIR)\configui.obj \ + $(UIDIR)\trackerwnd.obj \ + $(UIDIR)\version.obj + +RESFILES= \ + $(OBJ)\nidmgrdll.res \ + $(KCDBDIR)\kcredres.res \ + $(KMMDIR)\kmm_msgs.res \ + +SDKLIBFILES= \ + advapi32.lib \ + strsafe.lib \ + comctl32.lib \ + shlwapi.lib \ + version.lib + +$(DLLFILE): $(OBJFILES) $(RESFILES) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) + +all: mkdirs $(DLLFILE) + +clean:: + $(RM) $(DLLFILE) diff --git a/mechglue/src/windows/identity/nidmgrdll/dllmain.c b/mechglue/src/windows/identity/nidmgrdll/dllmain.c new file mode 100644 index 000000000..e54e28137 --- /dev/null +++ b/mechglue/src/windows/identity/nidmgrdll/dllmain.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include + +/* forward dcls */ +void +kherr_process_attach(void); + +void +kherr_process_detach(void); + +void +kherr_thread_attach(void); + +void +kherr_thread_detach(void); + +void +kconfig_process_attach(void); + +void +kconfig_process_detach(void); + +void +kmq_process_attach(void); + +void +kmq_process_detach(void); + +void +kmq_thread_attach(void); + +void +kmq_thread_detach(void); + +void +kcdb_process_attach(HINSTANCE); + +void +kcdb_process_detach(void); + +void +kmm_process_attach(HINSTANCE); + +void +kmm_process_detach(void); + +void +uilib_process_attach(void); + +void +uilib_process_detach(void); + + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, // handle to DLL module + DWORD fdwReason, // reason for calling function + LPVOID lpReserved ) // reserved +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + kherr_process_attach(); + kconfig_process_attach(); + kmq_process_attach(); + kcdb_process_attach(hinstDLL); + kmm_process_attach(hinstDLL); + uilib_process_attach(); + break; + + case DLL_PROCESS_DETACH: + kherr_process_detach(); + kconfig_process_detach(); + kmq_process_detach(); + kcdb_process_detach(); + kmm_process_detach(); + uilib_process_detach(); + break; + + case DLL_THREAD_ATTACH: + kherr_thread_attach(); + kmq_thread_attach(); + break; + + case DLL_THREAD_DETACH: + kherr_thread_detach(); + kmq_thread_detach(); + break; + } + return TRUE; +} diff --git a/mechglue/src/windows/identity/nidmgrdll/nidmgrdll.rc b/mechglue/src/windows/identity/nidmgrdll/nidmgrdll.rc new file mode 100644 index 000000000..26aeaa691 --- /dev/null +++ b/mechglue/src/windows/identity/nidmgrdll/nidmgrdll.rc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif + +1 VERSIONINFO + FILEVERSION KH_VERSION_LIST + PRODUCTVERSION KH_VERSION_LIST + FILEFLAGSMASK 0x17L + FILEFLAGS KH_VER_FILEFLAGS + FILEOS KH_VER_FILEOS + FILETYPE KH_VER_FILETYPEDLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", KH_VERSTR_COMPANY_1033 + VALUE "FileDescription", "NetIDMgr API" + VALUE "FileVersion", KH_VERSION_STRING + VALUE "InternalName", "nidmgr32" + VALUE "LegalCopyright", KH_VERSTR_COPYRIGHT_1033 + VALUE "OriginalFilename", "nidmgr32.dll" + VALUE "ProductName", KH_VERSTR_PRODUCT_1033 + VALUE "ProductVersion", KH_VERSTR_VERSION_1033 +#ifdef KH_VERSTR_COMMENT_1033 + VALUE "Comments", KH_VERSTR_COMMENT_1033 +#endif +#ifdef KH_VERSTR_PRIVATE_1033 + VALUE "PrivateBuild", KH_VERSTR_PRIVATE_1033 +#endif +#ifdef KH_VERSTR_SPECIAL_1033 + VALUE "SpecialBuild", KH_VERSTR_SPECIAL_1033 +#endif + END + END + +/* Language independent */ + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END + +END diff --git a/mechglue/src/windows/identity/plugins/common/Makefile b/mechglue/src/windows/identity/plugins/common/Makefile new file mode 100644 index 000000000..5107edca4 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/common/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\common +!include <../../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\krb5common.h \ + $(INCDIR)\dynimport.h + +OBJFILES= \ + $(LIBDIR)\krb5common.obj \ + $(LIBDIR)\dynimport.obj + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) + $(RM) $(OBJFILES) + +{}.c{$(LIBDIR)}.obj: + $(C2OBJ) diff --git a/mechglue/src/windows/identity/plugins/common/dynimport.c b/mechglue/src/windows/identity/plugins/common/dynimport.c new file mode 100644 index 000000000..b906b6ae9 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/common/dynimport.c @@ -0,0 +1,436 @@ +/* +* Copyright (c) 2005 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include +#include +#include +#include + +HINSTANCE hKrb4 = 0; +HINSTANCE hKrb5 = 0; +HINSTANCE hKrb524 = 0; +HINSTANCE hSecur32 = 0; +HINSTANCE hComErr = 0; +HINSTANCE hService = 0; +HINSTANCE hProfile = 0; +HINSTANCE hPsapi = 0; +HINSTANCE hToolHelp32 = 0; +HINSTANCE hCCAPI = 0; + +DWORD AfsAvailable = 0; + +// CCAPI +DECL_FUNC_PTR(cc_initialize); +DECL_FUNC_PTR(cc_shutdown); +DECL_FUNC_PTR(cc_get_NC_info); +DECL_FUNC_PTR(cc_free_NC_info); + +// krb4 functions +DECL_FUNC_PTR(get_krb_err_txt_entry); +DECL_FUNC_PTR(k_isinst); +DECL_FUNC_PTR(k_isname); +DECL_FUNC_PTR(k_isrealm); +DECL_FUNC_PTR(kadm_change_your_password); +DECL_FUNC_PTR(kname_parse); +DECL_FUNC_PTR(krb_get_cred); +DECL_FUNC_PTR(krb_get_krbhst); +DECL_FUNC_PTR(krb_get_lrealm); +DECL_FUNC_PTR(krb_get_pw_in_tkt); +DECL_FUNC_PTR(krb_get_tf_realm); +DECL_FUNC_PTR(krb_mk_req); +DECL_FUNC_PTR(krb_realmofhost); +DECL_FUNC_PTR(tf_init); +DECL_FUNC_PTR(tf_close); +DECL_FUNC_PTR(tf_get_cred); +DECL_FUNC_PTR(tf_get_pname); +DECL_FUNC_PTR(tf_get_pinst); +DECL_FUNC_PTR(LocalHostAddr); +DECL_FUNC_PTR(tkt_string); +DECL_FUNC_PTR(krb_set_tkt_string); +DECL_FUNC_PTR(initialize_krb_error_func); +DECL_FUNC_PTR(initialize_kadm_error_table); +DECL_FUNC_PTR(dest_tkt); +DECL_FUNC_PTR(krb_in_tkt); +DECL_FUNC_PTR(krb_save_credentials); +DECL_FUNC_PTR(krb_get_krbconf2); +DECL_FUNC_PTR(krb_get_krbrealm2); +DECL_FUNC_PTR(krb_life_to_time); + +// krb5 functions +DECL_FUNC_PTR(krb5_change_password); +DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +DECL_FUNC_PTR(krb5_get_init_creds_password); +DECL_FUNC_PTR(krb5_get_prompt_types); +DECL_FUNC_PTR(krb5_build_principal_ext); +DECL_FUNC_PTR(krb5_cc_get_name); +DECL_FUNC_PTR(krb5_cc_get_type); +DECL_FUNC_PTR(krb5_cc_resolve); +DECL_FUNC_PTR(krb5_cc_default); +DECL_FUNC_PTR(krb5_cc_default_name); +DECL_FUNC_PTR(krb5_cc_set_default_name); +DECL_FUNC_PTR(krb5_cc_initialize); +DECL_FUNC_PTR(krb5_cc_destroy); +DECL_FUNC_PTR(krb5_cc_close); +DECL_FUNC_PTR(krb5_cc_store_cred); +DECL_FUNC_PTR(krb5_cc_copy_creds); +DECL_FUNC_PTR(krb5_cc_retrieve_cred); +DECL_FUNC_PTR(krb5_cc_get_principal); +DECL_FUNC_PTR(krb5_cc_start_seq_get); +DECL_FUNC_PTR(krb5_cc_next_cred); +DECL_FUNC_PTR(krb5_cc_end_seq_get); +DECL_FUNC_PTR(krb5_cc_remove_cred); +DECL_FUNC_PTR(krb5_cc_set_flags); +// DECL_FUNC_PTR(krb5_cc_get_type); +DECL_FUNC_PTR(krb5_free_context); +DECL_FUNC_PTR(krb5_free_cred_contents); +DECL_FUNC_PTR(krb5_free_principal); +DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +DECL_FUNC_PTR(krb5_init_context); +DECL_FUNC_PTR(krb5_parse_name); +DECL_FUNC_PTR(krb5_timeofday); +DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +DECL_FUNC_PTR(krb5_unparse_name); +DECL_FUNC_PTR(krb5_get_credentials); +DECL_FUNC_PTR(krb5_mk_req); +DECL_FUNC_PTR(krb5_sname_to_principal); +DECL_FUNC_PTR(krb5_get_credentials_renew); +DECL_FUNC_PTR(krb5_free_data); +DECL_FUNC_PTR(krb5_free_data_contents); +// DECL_FUNC_PTR(krb5_get_realm_domain); +DECL_FUNC_PTR(krb5_free_unparsed_name); +DECL_FUNC_PTR(krb5_os_localaddr); +DECL_FUNC_PTR(krb5_copy_keyblock_contents); +DECL_FUNC_PTR(krb5_copy_data); +DECL_FUNC_PTR(krb5_free_creds); +DECL_FUNC_PTR(krb5_build_principal); +DECL_FUNC_PTR(krb5_get_renewed_creds); +DECL_FUNC_PTR(krb5_get_default_config_files); +DECL_FUNC_PTR(krb5_free_config_files); +DECL_FUNC_PTR(krb5_get_default_realm); +DECL_FUNC_PTR(krb5_set_default_realm); +DECL_FUNC_PTR(krb5_free_ticket); +DECL_FUNC_PTR(krb5_decode_ticket); +DECL_FUNC_PTR(krb5_get_host_realm); +DECL_FUNC_PTR(krb5_free_host_realm); +DECL_FUNC_PTR(krb5_c_random_make_octets); +DECL_FUNC_PTR(krb5_free_addresses); +DECL_FUNC_PTR(krb5_free_default_realm); + +// Krb524 functions +DECL_FUNC_PTR(krb524_init_ets); +DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// ComErr functions +DECL_FUNC_PTR(com_err); +DECL_FUNC_PTR(error_message); + +// Profile functions +DECL_FUNC_PTR(profile_init); +DECL_FUNC_PTR(profile_flush); +DECL_FUNC_PTR(profile_release); +DECL_FUNC_PTR(profile_get_subsection_names); +DECL_FUNC_PTR(profile_free_list); +DECL_FUNC_PTR(profile_get_string); +DECL_FUNC_PTR(profile_get_values); +DECL_FUNC_PTR(profile_get_relation_names); +DECL_FUNC_PTR(profile_clear_relation); +DECL_FUNC_PTR(profile_add_relation); +DECL_FUNC_PTR(profile_update_relation); +DECL_FUNC_PTR(profile_release_string); + +// Service functions +DECL_FUNC_PTR(OpenSCManagerA); +DECL_FUNC_PTR(OpenServiceA); +DECL_FUNC_PTR(QueryServiceStatus); +DECL_FUNC_PTR(CloseServiceHandle); +DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +DECL_FUNC_PTR(LsaConnectUntrusted); +DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +DECL_FUNC_PTR(LsaCallAuthenticationPackage); +DECL_FUNC_PTR(LsaFreeReturnBuffer); +DECL_FUNC_PTR(LsaGetLogonSessionData); + +// CCAPI +FUNC_INFO ccapi_fi[] = { + MAKE_FUNC_INFO(cc_initialize), + MAKE_FUNC_INFO(cc_shutdown), + MAKE_FUNC_INFO(cc_get_NC_info), + MAKE_FUNC_INFO(cc_free_NC_info), + END_FUNC_INFO +}; + +FUNC_INFO k4_fi[] = { + MAKE_FUNC_INFO(get_krb_err_txt_entry), + MAKE_FUNC_INFO(k_isinst), + MAKE_FUNC_INFO(k_isname), + MAKE_FUNC_INFO(k_isrealm), + MAKE_FUNC_INFO(kadm_change_your_password), + MAKE_FUNC_INFO(kname_parse), + MAKE_FUNC_INFO(krb_get_cred), + MAKE_FUNC_INFO(krb_get_krbhst), + MAKE_FUNC_INFO(krb_get_lrealm), + MAKE_FUNC_INFO(krb_get_pw_in_tkt), + MAKE_FUNC_INFO(krb_get_tf_realm), + MAKE_FUNC_INFO(krb_mk_req), + MAKE_FUNC_INFO(krb_realmofhost), + MAKE_FUNC_INFO(tf_init), + MAKE_FUNC_INFO(tf_close), + MAKE_FUNC_INFO(tf_get_cred), + MAKE_FUNC_INFO(tf_get_pname), + MAKE_FUNC_INFO(tf_get_pinst), + MAKE_FUNC_INFO(LocalHostAddr), + MAKE_FUNC_INFO(tkt_string), + MAKE_FUNC_INFO(krb_set_tkt_string), + MAKE_FUNC_INFO(initialize_krb_error_func), + MAKE_FUNC_INFO(initialize_kadm_error_table), + MAKE_FUNC_INFO(dest_tkt), + /* MAKE_FUNC_INFO(lsh_LoadKrb4LeashErrorTables), */// XXX + MAKE_FUNC_INFO(krb_in_tkt), + MAKE_FUNC_INFO(krb_save_credentials), + MAKE_FUNC_INFO(krb_get_krbconf2), + MAKE_FUNC_INFO(krb_get_krbrealm2), + MAKE_FUNC_INFO(krb_life_to_time), + END_FUNC_INFO +}; + +FUNC_INFO k5_fi[] = { + MAKE_FUNC_INFO(krb5_change_password), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_init), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list), + MAKE_FUNC_INFO(krb5_get_init_creds_password), + MAKE_FUNC_INFO(krb5_get_prompt_types), + MAKE_FUNC_INFO(krb5_build_principal_ext), + MAKE_FUNC_INFO(krb5_cc_get_name), + MAKE_FUNC_INFO(krb5_cc_get_type), + MAKE_FUNC_INFO(krb5_cc_resolve), + MAKE_FUNC_INFO(krb5_cc_default), + MAKE_FUNC_INFO(krb5_cc_default_name), + MAKE_FUNC_INFO(krb5_cc_set_default_name), + MAKE_FUNC_INFO(krb5_cc_initialize), + MAKE_FUNC_INFO(krb5_cc_destroy), + MAKE_FUNC_INFO(krb5_cc_close), + MAKE_FUNC_INFO(krb5_cc_copy_creds), + MAKE_FUNC_INFO(krb5_cc_store_cred), + MAKE_FUNC_INFO(krb5_cc_retrieve_cred), + MAKE_FUNC_INFO(krb5_cc_get_principal), + MAKE_FUNC_INFO(krb5_cc_start_seq_get), + MAKE_FUNC_INFO(krb5_cc_next_cred), + MAKE_FUNC_INFO(krb5_cc_end_seq_get), + MAKE_FUNC_INFO(krb5_cc_remove_cred), + MAKE_FUNC_INFO(krb5_cc_set_flags), + // MAKE_FUNC_INFO(krb5_cc_get_type), + MAKE_FUNC_INFO(krb5_free_context), + MAKE_FUNC_INFO(krb5_free_cred_contents), + MAKE_FUNC_INFO(krb5_free_principal), + MAKE_FUNC_INFO(krb5_get_in_tkt_with_password), + MAKE_FUNC_INFO(krb5_init_context), + MAKE_FUNC_INFO(krb5_parse_name), + MAKE_FUNC_INFO(krb5_timeofday), + MAKE_FUNC_INFO(krb5_timestamp_to_sfstring), + MAKE_FUNC_INFO(krb5_unparse_name), + MAKE_FUNC_INFO(krb5_get_credentials), + MAKE_FUNC_INFO(krb5_mk_req), + MAKE_FUNC_INFO(krb5_sname_to_principal), + MAKE_FUNC_INFO(krb5_get_credentials_renew), + MAKE_FUNC_INFO(krb5_free_data), + MAKE_FUNC_INFO(krb5_free_data_contents), + // MAKE_FUNC_INFO(krb5_get_realm_domain), + MAKE_FUNC_INFO(krb5_free_unparsed_name), + MAKE_FUNC_INFO(krb5_os_localaddr), + MAKE_FUNC_INFO(krb5_copy_keyblock_contents), + MAKE_FUNC_INFO(krb5_copy_data), + MAKE_FUNC_INFO(krb5_free_creds), + MAKE_FUNC_INFO(krb5_build_principal), + MAKE_FUNC_INFO(krb5_get_renewed_creds), + MAKE_FUNC_INFO(krb5_free_addresses), + MAKE_FUNC_INFO(krb5_get_default_config_files), + MAKE_FUNC_INFO(krb5_free_config_files), + MAKE_FUNC_INFO(krb5_get_default_realm), + MAKE_FUNC_INFO(krb5_set_default_realm), + MAKE_FUNC_INFO(krb5_free_ticket), + MAKE_FUNC_INFO(krb5_decode_ticket), + MAKE_FUNC_INFO(krb5_get_host_realm), + MAKE_FUNC_INFO(krb5_free_host_realm), + MAKE_FUNC_INFO(krb5_c_random_make_octets), + MAKE_FUNC_INFO(krb5_free_default_realm), + END_FUNC_INFO +}; + +FUNC_INFO k524_fi[] = { + MAKE_FUNC_INFO(krb524_init_ets), + MAKE_FUNC_INFO(krb524_convert_creds_kdc), + END_FUNC_INFO +}; + +FUNC_INFO profile_fi[] = { + MAKE_FUNC_INFO(profile_init), + MAKE_FUNC_INFO(profile_flush), + MAKE_FUNC_INFO(profile_release), + MAKE_FUNC_INFO(profile_get_subsection_names), + MAKE_FUNC_INFO(profile_free_list), + MAKE_FUNC_INFO(profile_get_string), + MAKE_FUNC_INFO(profile_get_values), + MAKE_FUNC_INFO(profile_get_relation_names), + MAKE_FUNC_INFO(profile_clear_relation), + MAKE_FUNC_INFO(profile_add_relation), + MAKE_FUNC_INFO(profile_update_relation), + MAKE_FUNC_INFO(profile_release_string), + END_FUNC_INFO +}; + +FUNC_INFO ce_fi[] = { + MAKE_FUNC_INFO(com_err), + MAKE_FUNC_INFO(error_message), + END_FUNC_INFO +}; + +FUNC_INFO service_fi[] = { + MAKE_FUNC_INFO(OpenSCManagerA), + MAKE_FUNC_INFO(OpenServiceA), + MAKE_FUNC_INFO(QueryServiceStatus), + MAKE_FUNC_INFO(CloseServiceHandle), + MAKE_FUNC_INFO(LsaNtStatusToWinError), + END_FUNC_INFO +}; + +FUNC_INFO lsa_fi[] = { + MAKE_FUNC_INFO(LsaConnectUntrusted), + MAKE_FUNC_INFO(LsaLookupAuthenticationPackage), + MAKE_FUNC_INFO(LsaCallAuthenticationPackage), + MAKE_FUNC_INFO(LsaFreeReturnBuffer), + MAKE_FUNC_INFO(LsaGetLogonSessionData), + END_FUNC_INFO +}; + +// psapi functions +DECL_FUNC_PTR(GetModuleFileNameExA); +DECL_FUNC_PTR(EnumProcessModules); + +FUNC_INFO psapi_fi[] = { + MAKE_FUNC_INFO(GetModuleFileNameExA), + MAKE_FUNC_INFO(EnumProcessModules), + END_FUNC_INFO +}; + +// toolhelp functions +DECL_FUNC_PTR(CreateToolhelp32Snapshot); +DECL_FUNC_PTR(Module32First); +DECL_FUNC_PTR(Module32Next); + +FUNC_INFO toolhelp_fi[] = { + MAKE_FUNC_INFO(CreateToolhelp32Snapshot), + MAKE_FUNC_INFO(Module32First), + MAKE_FUNC_INFO(Module32Next), + END_FUNC_INFO +}; + +khm_int32 init_imports(void) { + OSVERSIONINFO osvi; + + LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); + LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); + LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); + LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); + LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); + LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); + LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); + LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); + + memset(&osvi, 0, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + // XXX: We should really use feature testing, first + // checking for CreateToolhelp32Snapshot. If that's + // not around, we try the psapi stuff. + // + // Only load LSA functions if on NT/2000/XP + if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + // Windows 9x + LoadFuncs(TOOLHELPDLL, toolhelp_fi, &hToolHelp32, 0, 1, 0, 0); + hPsapi = 0; + } + else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + // Windows NT + LoadFuncs(PSAPIDLL, psapi_fi, &hPsapi, 0, 1, 0, 0); + hToolHelp32 = 0; + } + + AfsAvailable = TRUE; //afscompat_init(); + + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_imports(void) { + //afscompat_close(); + + if (hKrb4) + FreeLibrary(hKrb4); + if (hKrb5) + FreeLibrary(hKrb5); + if (hProfile) + FreeLibrary(hProfile); + if (hComErr) + FreeLibrary(hComErr); + if (hService) + FreeLibrary(hService); + if (hSecur32) + FreeLibrary(hSecur32); + if (hKrb524) + FreeLibrary(hKrb524); + if (hPsapi) + FreeLibrary(hPsapi); + if (hToolHelp32) + FreeLibrary(hToolHelp32); + + return KHM_ERROR_SUCCESS; +} + +int (*Lcom_err)(LPSTR,long,LPSTR,...); +LPSTR (*Lerror_message)(long); +LPSTR (*Lerror_table_name)(long); + +void Leash_load_com_err_callback(FARPROC ce, + FARPROC em, + FARPROC etn) +{ + (FARPROC)Lcom_err=ce; + (FARPROC)Lerror_message=em; + (FARPROC)Lerror_table_name=etn; +} diff --git a/mechglue/src/windows/identity/plugins/common/dynimport.h b/mechglue/src/windows/identity/plugins/common/dynimport.h new file mode 100644 index 000000000..778bff324 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/common/dynimport.h @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_DYNIMPORT_H +#define __KHIMAIRA_DYNIMPORT_H + +/* Dynamic imports */ +#include +#include +#include + +extern HINSTANCE hKrb4; +extern HINSTANCE hKrb5; +extern HINSTANCE hProfile; + +/////////////////////////////////////////////////////////////////////////////// + +#define CCAPI_DLL "krbcc32.dll" +#define KRBCC32_DLL "krbcc32.dll" +#define SERVICE_DLL "advapi32.dll" +#define SECUR32_DLL "secur32.dll" +#define PROFILE_DLL "xpprof32.dll" + +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +//// CCAPI +/* In order to avoid including the private CCAPI headers */ +typedef int cc_int32; + +#define CC_API_VER_1 1 +#define CC_API_VER_2 2 + +#define CCACHE_API cc_int32 + +/* +** The Official Error Codes +*/ +#define CC_NOERROR 0 +#define CC_BADNAME 1 +#define CC_NOTFOUND 2 +#define CC_END 3 +#define CC_IO 4 +#define CC_WRITE 5 +#define CC_NOMEM 6 +#define CC_FORMAT 7 +#define CC_LOCKED 8 +#define CC_BAD_API_VERSION 9 +#define CC_NO_EXIST 10 +#define CC_NOT_SUPP 11 +#define CC_BAD_PARM 12 +#define CC_ERR_CACHE_ATTACH 13 +#define CC_ERR_CACHE_RELEASE 14 +#define CC_ERR_CACHE_FULL 15 +#define CC_ERR_CRED_VERSION 16 + +enum { + CC_CRED_VUNKNOWN = 0, // For validation + CC_CRED_V4 = 1, + CC_CRED_V5 = 2, + CC_CRED_VMAX = 3 // For validation +}; + +typedef struct opaque_dll_control_block_type* apiCB; +typedef struct _infoNC { + char* name; + char* principal; + cc_int32 vers; +} infoNC; + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_initialize, + ( + apiCB** cc_ctx, // < DLL's primary control structure. + // returned here, passed everywhere else + cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) + cc_int32* api_supported, // < if ~NULL, max ver supported by DLL + const char** vendor // < if ~NULL, vendor name in read only C string + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_shutdown, + ( + apiCB** cc_ctx // <> DLL's primary control structure. NULL after + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_get_NC_info, + ( + apiCB* cc_ctx, // > DLL's primary control structure + struct _infoNC*** ppNCi // < (NULL before call) null terminated, + // list of a structs (free via cc_free_infoNC()) + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_free_NC_info, + ( + apiCB* cc_ctx, + struct _infoNC*** ppNCi // < free list of structs returned by + // cc_get_cache_names(). set to NULL on return + ) +); +//// \CCAPI + +extern DWORD AfsAvailable; + +// service definitions +typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); +typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); +typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); +typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); + +////////////////////////////////////////////////////////////////////////////// + +// CCAPI +extern DECL_FUNC_PTR(cc_initialize); +extern DECL_FUNC_PTR(cc_shutdown); +extern DECL_FUNC_PTR(cc_get_NC_info); +extern DECL_FUNC_PTR(cc_free_NC_info); + +// krb4 functions +extern DECL_FUNC_PTR(get_krb_err_txt_entry); +extern DECL_FUNC_PTR(k_isinst); +extern DECL_FUNC_PTR(k_isname); +extern DECL_FUNC_PTR(k_isrealm); +extern DECL_FUNC_PTR(kadm_change_your_password); +extern DECL_FUNC_PTR(kname_parse); +extern DECL_FUNC_PTR(krb_get_cred); +extern DECL_FUNC_PTR(krb_get_krbhst); +extern DECL_FUNC_PTR(krb_get_lrealm); +extern DECL_FUNC_PTR(krb_get_pw_in_tkt); +extern DECL_FUNC_PTR(krb_get_tf_realm); +extern DECL_FUNC_PTR(krb_mk_req); +extern DECL_FUNC_PTR(krb_realmofhost); +extern DECL_FUNC_PTR(tf_init); +extern DECL_FUNC_PTR(tf_close); +extern DECL_FUNC_PTR(tf_get_cred); +extern DECL_FUNC_PTR(tf_get_pname); +extern DECL_FUNC_PTR(tf_get_pinst); +extern DECL_FUNC_PTR(LocalHostAddr); +extern DECL_FUNC_PTR(tkt_string); +extern DECL_FUNC_PTR(krb_set_tkt_string); +extern DECL_FUNC_PTR(initialize_krb_error_func); +extern DECL_FUNC_PTR(initialize_kadm_error_table); +extern DECL_FUNC_PTR(dest_tkt); +extern DECL_FUNC_PTR(lsh_LoadKrb4LeashErrorTables); // XXX +extern DECL_FUNC_PTR(krb_in_tkt); +extern DECL_FUNC_PTR(krb_save_credentials); +extern DECL_FUNC_PTR(krb_get_krbconf2); +extern DECL_FUNC_PTR(krb_get_krbrealm2); +extern DECL_FUNC_PTR(krb_life_to_time); + +// krb5 functions +extern DECL_FUNC_PTR(krb5_change_password); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +extern DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +extern DECL_FUNC_PTR(krb5_get_init_creds_password); +extern DECL_FUNC_PTR(krb5_get_prompt_types); +extern DECL_FUNC_PTR(krb5_build_principal_ext); +extern DECL_FUNC_PTR(krb5_cc_get_name); +extern DECL_FUNC_PTR(krb5_cc_get_type); +extern DECL_FUNC_PTR(krb5_cc_resolve); +extern DECL_FUNC_PTR(krb5_cc_default); +extern DECL_FUNC_PTR(krb5_cc_default_name); +extern DECL_FUNC_PTR(krb5_cc_set_default_name); +extern DECL_FUNC_PTR(krb5_cc_initialize); +extern DECL_FUNC_PTR(krb5_cc_destroy); +extern DECL_FUNC_PTR(krb5_cc_close); +extern DECL_FUNC_PTR(krb5_cc_copy_creds); +extern DECL_FUNC_PTR(krb5_cc_store_cred); +extern DECL_FUNC_PTR(krb5_cc_retrieve_cred); +extern DECL_FUNC_PTR(krb5_cc_get_principal); +extern DECL_FUNC_PTR(krb5_cc_start_seq_get); +extern DECL_FUNC_PTR(krb5_cc_next_cred); +extern DECL_FUNC_PTR(krb5_cc_end_seq_get); +extern DECL_FUNC_PTR(krb5_cc_remove_cred); +extern DECL_FUNC_PTR(krb5_cc_set_flags); +// extern DECL_FUNC_PTR(krb5_cc_get_type); +extern DECL_FUNC_PTR(krb5_free_context); +extern DECL_FUNC_PTR(krb5_free_cred_contents); +extern DECL_FUNC_PTR(krb5_free_principal); +extern DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +extern DECL_FUNC_PTR(krb5_init_context); +extern DECL_FUNC_PTR(krb5_parse_name); +extern DECL_FUNC_PTR(krb5_timeofday); +extern DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +extern DECL_FUNC_PTR(krb5_unparse_name); +extern DECL_FUNC_PTR(krb5_get_credentials); +extern DECL_FUNC_PTR(krb5_mk_req); +extern DECL_FUNC_PTR(krb5_sname_to_principal); +extern DECL_FUNC_PTR(krb5_get_credentials_renew); +extern DECL_FUNC_PTR(krb5_free_data); +extern DECL_FUNC_PTR(krb5_free_data_contents); +// extern DECL_FUNC_PTR(krb5_get_realm_domain); +extern DECL_FUNC_PTR(krb5_free_unparsed_name); +extern DECL_FUNC_PTR(krb5_os_localaddr); +extern DECL_FUNC_PTR(krb5_copy_keyblock_contents); +extern DECL_FUNC_PTR(krb5_copy_data); +extern DECL_FUNC_PTR(krb5_free_creds); +extern DECL_FUNC_PTR(krb5_build_principal); +extern DECL_FUNC_PTR(krb5_get_renewed_creds); +extern DECL_FUNC_PTR(krb5_free_addresses); +extern DECL_FUNC_PTR(krb5_get_default_config_files); +extern DECL_FUNC_PTR(krb5_free_config_files); +extern DECL_FUNC_PTR(krb5_get_default_realm); +extern DECL_FUNC_PTR(krb5_set_default_realm); +extern DECL_FUNC_PTR(krb5_free_ticket); +extern DECL_FUNC_PTR(krb5_decode_ticket); +extern DECL_FUNC_PTR(krb5_get_host_realm); +extern DECL_FUNC_PTR(krb5_free_host_realm); +extern DECL_FUNC_PTR(krb5_c_random_make_octets); +extern DECL_FUNC_PTR(krb5_free_default_realm); + +// Krb524 functions +extern DECL_FUNC_PTR(krb524_init_ets); +extern DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// ComErr functions +extern DECL_FUNC_PTR(com_err); +extern DECL_FUNC_PTR(error_message); + +// Profile functions +extern DECL_FUNC_PTR(profile_init); +extern DECL_FUNC_PTR(profile_flush); +extern DECL_FUNC_PTR(profile_release); +extern DECL_FUNC_PTR(profile_get_subsection_names); +extern DECL_FUNC_PTR(profile_free_list); +extern DECL_FUNC_PTR(profile_get_string); +extern DECL_FUNC_PTR(profile_get_values); +extern DECL_FUNC_PTR(profile_get_relation_names); +extern DECL_FUNC_PTR(profile_clear_relation); +extern DECL_FUNC_PTR(profile_add_relation); +extern DECL_FUNC_PTR(profile_update_relation); +extern DECL_FUNC_PTR(profile_release_string); + +// Service functions +extern DECL_FUNC_PTR(OpenSCManagerA); +extern DECL_FUNC_PTR(OpenServiceA); +extern DECL_FUNC_PTR(QueryServiceStatus); +extern DECL_FUNC_PTR(CloseServiceHandle); +extern DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +extern DECL_FUNC_PTR(LsaConnectUntrusted); +extern DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +extern DECL_FUNC_PTR(LsaCallAuthenticationPackage); +extern DECL_FUNC_PTR(LsaFreeReturnBuffer); +extern DECL_FUNC_PTR(LsaGetLogonSessionData); + +// toolhelp functions +TYPEDEF_FUNC( + HANDLE, + WINAPI, + CreateToolhelp32Snapshot, + (DWORD, DWORD) + ); +TYPEDEF_FUNC( + BOOL, + WINAPI, + Module32First, + (HANDLE, LPMODULEENTRY32) + ); +TYPEDEF_FUNC( + BOOL, + WINAPI, + Module32Next, + (HANDLE, LPMODULEENTRY32) + ); + +// psapi functions +TYPEDEF_FUNC( + DWORD, + WINAPI, + GetModuleFileNameExA, + (HANDLE, HMODULE, LPSTR, DWORD) + ); + +TYPEDEF_FUNC( + BOOL, + WINAPI, + EnumProcessModules, + (HANDLE, HMODULE*, DWORD, LPDWORD) + ); + +#define pGetModuleFileNameEx pGetModuleFileNameExA +#define TOOLHELPDLL "kernel32.dll" +#define PSAPIDLL "psapi.dll" + +// psapi functions +extern DECL_FUNC_PTR(GetModuleFileNameExA); +extern DECL_FUNC_PTR(EnumProcessModules); + +// toolhelp functions +extern DECL_FUNC_PTR(CreateToolhelp32Snapshot); +extern DECL_FUNC_PTR(Module32First); +extern DECL_FUNC_PTR(Module32Next); + +khm_int32 init_imports(void); +khm_int32 exit_imports(void); + +#endif diff --git a/mechglue/src/windows/identity/plugins/common/krb5common.c b/mechglue/src/windows/identity/plugins/common/krb5common.c new file mode 100644 index 000000000..cb9d86bc5 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/common/krb5common.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#ifdef DEBUG +#include +#endif + +/**************************************/ +/* khm_krb5_error(): */ +/**************************************/ +int +khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context * ctx, + krb5_ccache * cache) +{ +#ifdef NO_KRB5 + return 0; +#else + +#ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY + char message[256]; + const char *errText; + int krb5Error = ((int)(rc & 255)); + + errText = perror_message(rc); + _snprintf(message, sizeof(message), + "%s\n(Kerberos error %ld)\n\n%s failed", + errText, + krb5Error, + FailedFunctionName); + + MessageBoxA(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | + MB_TASKMODAL | + MB_SETFOREGROUND); +#endif + + if (FreeContextFlag == 1) + { + if (*ctx != NULL) + { + if (*cache != NULL) { + pkrb5_cc_close(*ctx, *cache); + *cache = NULL; + } + + pkrb5_free_context(*ctx); + *ctx = NULL; + } + } + + return rc; + +#endif //!NO_KRB5 +} + +int +khm_krb5_initialize(khm_handle ident, + krb5_context *ctx, + krb5_ccache *cache) +{ +#ifdef NO_KRB5 + return(0); +#else + + LPCSTR functionName; + int freeContextFlag; + krb5_error_code rc; + krb5_flags flags = 0; + + if (pkrb5_init_context == NULL) + return 1; + + if (*ctx == 0 && (rc = (*pkrb5_init_context)(ctx))) { + functionName = "krb5_init_context()"; + freeContextFlag = 0; + goto on_error; + } + + if(*cache == 0) { + wchar_t wccname[MAX_PATH]; + khm_size cbwccname; + + if(ident != NULL) { + cbwccname = sizeof(wccname); + do { + char ccname[256]; + + if(KHM_FAILED(kcdb_identity_get_attrib(ident, L"Krb5CCName", + NULL, wccname, + &cbwccname))) { + cbwccname = sizeof(wccname); + if (KHM_FAILED + (khm_krb5_find_ccache_for_identity(ident, + ctx, + wccname, + &cbwccname))) { +#ifdef DEBUG_LIKE_A_MADMAN + assert(FALSE); +#endif + break; + } + } + + if(UnicodeStrToAnsi(ccname, sizeof(ccname), wccname) == 0) + break; + + if((*pkrb5_cc_resolve)(*ctx, ccname, cache)) { + functionName = "krb5_cc_resolve()"; + freeContextFlag = 1; + goto on_error; + } + } while(FALSE); + } + +#ifndef FAILOVER_TO_DEFAULT_CCACHE + rc = 1; +#endif + if (*cache == 0 +#ifdef FAILOVER_TO_DEFAULT_CCACHE + && (rc = (*pkrb5_cc_default)(*ctx, cache)) +#endif + ) { + functionName = "krb5_cc_default()"; + freeContextFlag = 1; + goto on_error; + } + } + +#ifdef KRB5_TC_NOTICKET + flags = KRB5_TC_NOTICKET; +#endif + + if ((rc = (*pkrb5_cc_set_flags)(*ctx, *cache, flags))) + { + if (rc != KRB5_FCC_NOFILE && rc != KRB5_CC_NOTFOUND) + khm_krb5_error(rc, "krb5_cc_set_flags()", 0, ctx, + cache); + else if ((rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) && *ctx != NULL) { + if (*cache != NULL) + (*pkrb5_cc_close)(*ctx, *cache); + } + return rc; + } + return 0; + +on_error: + return khm_krb5_error(rc, functionName, freeContextFlag, ctx, cache); +#endif //!NO_KRB5 +} + +#define TIMET_TOLERANCE (60*5) + +khm_int32 KHMAPI +khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc, + khm_handle ident, + krb5_timestamp * pexpiration) +{ + krb5_principal principal = 0; + char * princ_name = NULL; + krb5_creds creds; + krb5_error_code code; + krb5_error_code cc_code; + krb5_cc_cursor cur; + krb5_timestamp now, expiration = 0; + + wchar_t w_ident_name[KCDB_IDENT_MAXCCH_NAME]; + char ident_name[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + khm_int32 rv = KHM_ERROR_NOT_FOUND; + + if (!ctx || !cc || !ident || !pexpiration) + return KHM_ERROR_GENERAL; + + code = pkrb5_cc_get_principal(ctx, cc, &principal); + + if ( code ) + return KHM_ERROR_INVALID_PARAM; + + cb = sizeof(w_ident_name); + kcdb_identity_get_name(ident, w_ident_name, &cb); + UnicodeStrToAnsi(ident_name, sizeof(ident_name), w_ident_name); + + code = pkrb5_unparse_name(ctx, principal, &princ_name); + + /* compare principal to ident. */ + + if ( code || !princ_name || + strcmp(princ_name, ident_name) ) { + if (princ_name) + pkrb5_free_unparsed_name(ctx, princ_name); + pkrb5_free_principal(ctx, principal); + return KHM_ERROR_UNKNOWN; + } + + pkrb5_free_unparsed_name(ctx, princ_name); + pkrb5_free_principal(ctx, principal); + + code = pkrb5_timeofday(ctx, &now); + + if (code) + return KHM_ERROR_UNKNOWN; + + cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); + + while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { + krb5_data * c0 = krb5_princ_name(ctx, creds.server); + krb5_data * c1 = krb5_princ_component(ctx, creds.server, 1); + krb5_data * r = krb5_princ_realm(ctx, creds.server); + + if ( c0 && c1 && r && c1->length == r->length && + !strncmp(c1->data,r->data,r->length) && + !strncmp("krbtgt",c0->data,c0->length) ) { + + /* we have a TGT, check for the expiration time. + * if it is valid and renewable, use the renew time + */ + + if (!(creds.ticket_flags & TKT_FLG_INVALID) && + creds.times.starttime < (now + TIMET_TOLERANCE) && + (creds.times.endtime + TIMET_TOLERANCE) > now) { + expiration = creds.times.endtime; + + if ((creds.ticket_flags & TKT_FLG_RENEWABLE) && + (creds.times.renew_till > creds.times.endtime)) { + expiration = creds.times.renew_till; + } + } + } + } + + if (cc_code == KRB5_CC_END) { + cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur); + rv = KHM_ERROR_SUCCESS; + *pexpiration = expiration; + } + + return rv; +} + +khm_int32 KHMAPI +khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx, + void * buffer, khm_size * pcbbuf) +{ + krb5_context ctx = 0; + krb5_ccache cache = 0; + krb5_error_code code; + apiCB * cc_ctx = 0; + struct _infoNC ** pNCi = NULL; + int i; + khm_int32 t; + wchar_t * ms = NULL; + khm_size cb; + krb5_timestamp expiration = 0; + krb5_timestamp best_match_expiration = 0; + char best_match_ccname[256] = ""; + khm_handle csp_params = NULL; + khm_handle csp_plugins = NULL; + + if (!buffer || !pcbbuf) + return KHM_ERROR_GENERAL; + + ctx = *pctx; + + code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); + if (code) + goto _exit; + + code = pcc_get_NC_info(cc_ctx, &pNCi); + + if (code) + goto _exit; + + for(i=0; pNCi[i]; i++) { + if (pNCi[i]->vers != CC_CRED_V5) + continue; + + code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache); + if (code) + continue; + + /* need a function to check the cache for the identity + * and determine if it has valid tickets. If it has + * the right identity and valid tickets, store the + * expiration time and the cache name. If it has the + * right identity but no valid tickets, store the ccache + * name and an expiration time of zero. if it does not + * have the right identity don't save the name. + * + * Keep searching to find the best cache available. + */ + + if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, + ident, + &expiration))) { + if ( expiration > best_match_expiration ) { + best_match_expiration = expiration; + StringCbCopyA(best_match_ccname, + sizeof(best_match_ccname), + "API:"); + StringCbCatA(best_match_ccname, + sizeof(best_match_ccname), + pNCi[i]->name); + expiration = 0; + } + } + + if(ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + + if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) { + khc_open_space(csp_plugins, L"Krb5Cred\\Parameters", 0, &csp_params); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + +#ifdef DEBUG + if (csp_params == NULL) { + assert(FALSE); + } +#endif + + if (csp_params && + KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { + code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); + if (code == 0 && cache) { + if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, + ident, + &expiration))) { + if ( expiration > best_match_expiration ) { + best_match_expiration = expiration; + StringCbCopyA(best_match_ccname, sizeof(best_match_ccname), + "MSLSA:"); + expiration = 0; + } + } + } + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + + cache = 0; + } + + if (csp_params && + khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) + == KHM_ERROR_TOO_LONG && + cb > sizeof(wchar_t) * 2) { + + wchar_t * t; + char ccname[MAX_PATH + 6]; + + ms = PMALLOC(cb); + +#ifdef DEBUG + assert(ms); +#endif + + khc_read_multi_string(csp_params, L"FileCCList", ms, &cb); + for(t = ms; t && *t; t = multi_string_next(t)) { + StringCchPrintfA(ccname, ARRAYLENGTH(ccname), + "FILE:%S", t); + + code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); + if (code) + continue; + + if (KHM_SUCCEEDED(khm_get_identity_expiration_time(ctx, cache, + ident, + &expiration))) { + if ( expiration > best_match_expiration ) { + best_match_expiration = expiration; + StringCbCopyA(best_match_ccname, + sizeof(best_match_ccname), + ccname); + expiration = 0; + } + } + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + + PFREE(ms); + } + _exit: + if (csp_params) + khc_close_space(csp_params); + + if (pNCi) + (*pcc_free_NC_info)(cc_ctx, &pNCi); + + if (cc_ctx) + (*pcc_shutdown)(&cc_ctx); + + if (best_match_ccname[0]) { + + if (*pcbbuf = AnsiStrToUnicode((wchar_t *)buffer, + *pcbbuf, + best_match_ccname)) { + + *pcbbuf = (*pcbbuf + 1) * sizeof(wchar_t); + + return KHM_ERROR_SUCCESS; + } + + } + + return KHM_ERROR_GENERAL; +} diff --git a/mechglue/src/windows/identity/plugins/common/krb5common.h b/mechglue/src/windows/identity/plugins/common/krb5common.h new file mode 100644 index 000000000..bd6337192 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/common/krb5common.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5COMMON_H +#define __KHIMAIRA_KRB5COMMON_H + +#include + +#ifndef NO_KRB5 +int khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context *ctx, + krb5_ccache *cache); + + +int khm_krb5_initialize(khm_handle ident, krb5_context *, krb5_ccache *); + +khm_int32 KHMAPI +khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx, + void * buffer, khm_size * pcbbuf); + +khm_int32 KHMAPI +khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc, + khm_handle ident, + krb5_timestamp * pexpiration); +#endif /* NO_KRB5 */ + +#endif diff --git a/mechglue/src/windows/identity/plugins/krb4/Makefile b/mechglue/src/windows/identity/plugins/krb4/Makefile new file mode 100644 index 000000000..2385e6179 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/Makefile @@ -0,0 +1,81 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\krb4 +!include <../../config/Makefile.w32> + +DLLFILE=$(BINDIR)\krb4cred.dll + +LIBFILE=$(LIBDIR)\krb4cred.lib + +OBJFILES= \ + $(LIBDIR)\dynimport.obj \ + $(LIBDIR)\krb5common.obj \ + $(OBJ)\krb4main.obj \ + $(OBJ)\krb4plugin.obj \ + $(OBJ)\krb4funcs.obj \ + $(OBJ)\errorfuncs.obj \ + $(OBJ)\krb4config.obj \ + $(OBJ)\krb4configdlg.obj \ + $(OBJ)\krb4newcreds.obj + +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib \ + $(KFWLIBDIR)\loadfuncs.lib + +SDKLIBFILES= + +VERRESFILE=$(OBJ)\version.res + +$(OBJ)\krb4config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(DLLFILE): $(OBJFILES) $(VERRESFILE) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) + +all: mkdirs $(DLLFILE) lang + +lang:: + +# Repeat this block as necessary redefining LANG for additional +# languages. + +# Begin language block +LANG=en_us + +LANGDLL=$(BINDIR)\krb4cred_$(LANG).dll + +lang:: $(LANGDLL) + +$(LANGDLL): $(OBJ)\langres_$(LANG).res + $(DLLRESLINK) + +$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc + $(RC2RES) +# End language block + +clean:: +!if defined(INCFILES) + $(RM) $(INCFILES) +!endif diff --git a/mechglue/src/windows/identity/plugins/krb4/errorfuncs.c b/mechglue/src/windows/identity/plugins/krb4/errorfuncs.c new file mode 100644 index 000000000..dba9f5dc6 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/errorfuncs.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +extern void (__cdecl *pinitialize_krb_error_func)(); +extern void (__cdecl *pinitialize_kadm_error_table)(); + + +khm_int32 init_error_funcs() +{ + +#if 0 + /*TODO: Do something about this */ + if (plsh_LoadKrb4LeashErrorTables) + plsh_LoadKrb4LeashErrorTables(hLeashInst, 0); +#endif + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +// Global Variables. +static long lsh_errno; +static char *err_context; /* error context */ +extern int (*Lcom_err)(LPSTR,long,LPSTR,...); +extern LPSTR (*Lerror_message)(long); +extern LPSTR (*Lerror_table_name)(long); + +#ifdef WIN16 +#define UNDERSCORE "_" +#else +#define UNDERSCORE +#endif + +HWND GetRootParent (HWND Child) +{ + HWND Last; + while (Child) + { + Last = Child; + Child = GetParent (Child); + } + return Last; +} + + +LPSTR err_describe(LPSTR buf, size_t len, long code) +{ + LPSTR cp, com_err_msg; + int offset; + long table_num; + char *etype; + + offset = (int) (code & 255); + table_num = code - offset; + com_err_msg = Lerror_message(code); + + switch(table_num) + { + case krb_err_base: + case kadm_err_base: + break; + default: + strncpy(buf, com_err_msg, len); + buf[len-1] = '\0'; + return buf; + } + + cp = buf; + if (table_num == krb_err_base) + switch(offset) + { + case KDC_NAME_EXP: /* 001 Principal expired */ + case KDC_SERVICE_EXP: /* 002 Service expired */ + case KDC_AUTH_EXP: /* 003 Auth expired */ + case KDC_PKT_VER: /* 004 Protocol version unknown */ + case KDC_P_MKEY_VER: /* 005 Wrong master key version */ + case KDC_S_MKEY_VER: /* 006 Wrong master key version */ + case KDC_BYTE_ORDER: /* 007 Byte order unknown */ + case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ + case KDC_NULL_KEY: /* 010 Principal has null key */ + case KDC_GEN_ERR: /* 011 Generic error from KDC */ + case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ + case INTK_PROT : /* 063 Protocol Error */ + case INTK_ERR : /* 070 Other error */ + com_err_msg = "Something weird happened... try again, and if Leash" + " continues to fail, contact Network Services as listed in the " + "About box."; + break; + case KDC_PR_UNKNOWN: /* 008 Principal unknown */ + com_err_msg = "You have entered an unknown username/instance/realm" + " combination."; + break; + case GC_TKFIL : /* 021 Can't read ticket file */ + case GC_NOTKT : /* 022 Can't find ticket or TGT */ + com_err_msg = "Something is wrong with the memory where your " + "tickets are stored. Try exiting Windows and restarting your " + "computer."; + break; + case MK_AP_TGTEXP : /* 026 TGT Expired */ + /* no extra error msg */ + break; + case RD_AP_TIME : /* 037 delta_t too big */ + com_err_msg = "Your computer's clock is out of sync with the " + "Kerberos server. Please see the help file about correcting " + "your clock."; + break; + + case RD_AP_UNDEC : /* 031 Can't decode authenticator */ + case RD_AP_EXP : /* 032 Ticket expired */ + case RD_AP_NYV : /* 033 Ticket not yet valid */ + case RD_AP_REPEAT : /* 034 Repeated request */ + case RD_AP_NOT_US : /* 035 The ticket isn't for us */ + case RD_AP_INCON : /* 036 Request is inconsistent */ + case RD_AP_BADD : /* 038 Incorrect net address */ + case RD_AP_VERSION : /* 039 protocol version mismatch */ + case RD_AP_MSG_TYPE : /* 040 invalid msg type */ + case RD_AP_MODIFIED : /* 041 message stream modified */ + case RD_AP_ORDER : /* 042 message out of order */ + case RD_AP_UNAUTHOR : /* 043 unauthorized request */ + /* no extra error msg */ + break; + case GT_PW_NULL: /* 51 Current PW is null */ + case GT_PW_BADPW: /* 52 Incorrect current password */ + case GT_PW_PROT: /* 53 Protocol Error */ + case GT_PW_KDCERR: /* 54 Error returned by KDC */ + case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ + /* no error msg yet */ + break; + + /* Values returned by send_to_kdc */ + case SKDC_RETRY : /* 56 Retry count exceeded */ + case SKDC_CANT : /* 57 Can't send request */ + com_err_msg = "Cannot contact the kerberos server for the selected realm."; + break; + /* no error message on purpose: */ + case INTK_BADPW : /* 062 Incorrect password */ + break; + default: + /* no extra error msg */ + break; + } + else + switch(code) + { + case KADM_INSECURE_PW: + /* if( kadm_info != NULL ){ + * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); + * } else { + * wsprintf(buf, "%s\nPlease see the help file for information " + * "about secure passwords.", com_err_msg); + * } + * com_err_msg = buf; + */ + + /* The above code would be preferred since it allows site specific + * information to be delivered from the Kerberos server. However the + * message box is too small for VGA screens. + * It does work well if we only have to support 1024x768 + */ + + com_err_msg = "You have entered an insecure or weak password."; + + default: + /* no extra error msg */ + break; + } + if(com_err_msg != buf) { + strncpy(buf, com_err_msg, len); + buf[len-1] = '\0'; + } + cp = buf + strlen(buf); + *cp++ = '\n'; + switch(table_num) { + case krb_err_base: + etype = "Kerberos"; + break; + case kadm_err_base: + etype = "Kerberos supplemental"; + break; + default: + etype = Lerror_table_name(table_num); + break; + } + StringCbPrintfA((LPSTR) cp, len - (cp-buf), (LPSTR) "(%s error %d" +#ifdef DEBUG_COM_ERR + " (absolute error %ld)" +#endif + ")", etype, offset + //")\nPress F1 for help on this error.", etype, offset +#ifdef DEBUG_COM_ERR + , code +#endif + ); + + return (LPSTR)buf; +} + diff --git a/mechglue/src/windows/identity/plugins/krb4/errorfuncs.h b/mechglue/src/windows/identity/plugins/krb4/errorfuncs.h new file mode 100644 index 000000000..e339eca4f --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/errorfuncs.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ERR_H +#define __KHIMAIRA_ERR_H + +/* All error handling and reporting related functions for the krb4/5 + and AFS plugins */ + +#include +#include +/* + * This is a hack needed because the real com_err.h does + * not define err_func. We need it in the case where + * we pull in the real com_err instead of the krb4 + * impostor. + */ +#ifndef _DCNS_MIT_COM_ERR_H +typedef LPSTR (*err_func)(int, long); +#endif + +#include +#include + +#define kadm_err_base ERROR_TABLE_BASE_kadm + +#include + +#ifndef KRBERR +#define KRBERR(code) (code + krb_err_base) +#endif + +LPSTR err_describe(LPSTR buf, size_t len, long code); + + +/* */ +khm_int32 init_error_funcs(); + +khm_int32 exit_error_funcs(); + + +#endif diff --git a/mechglue/src/windows/identity/plugins/krb4/images/plugin.ico b/mechglue/src/windows/identity/plugins/krb4/images/plugin.ico new file mode 100644 index 0000000000000000000000000000000000000000..791b359694d86dcdc85bd083d502db8056283771 GIT binary patch literal 7278 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 +#include +#include +#include +#include + +typedef struct tag_k4_ids_data { + khui_config_init_data cfg; + + khm_int32 get_tix; +} k4_ids_data; + +static void +k4_ids_read_params(k4_ids_data * d) { + khm_int32 t; +#ifdef DEBUG + assert(csp_params); +#endif + + t = 1; + khc_read_int32(csp_params, L"Krb4NewCreds", &t); + d->get_tix = !!t; +} + +static void +k4_ids_write_params(HWND hw, k4_ids_data * d) { + khm_int32 nv; + khm_boolean applied = FALSE; + + if (IsDlgButtonChecked(hw, IDC_CFG_GETTIX) == BST_CHECKED) + nv = TRUE; + else + nv = FALSE; + + if (!!nv != !!d->get_tix) { + d->get_tix = !!nv; + khc_write_int32(csp_params, L"Krb4NewCreds", d->get_tix); + applied = TRUE; + } + + khui_cfg_set_flags_inst(&d->cfg, + (applied)?KHUI_CNFLAG_APPLIED:0, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +static void +k4_ids_check_mod(HWND hw, k4_ids_data * d) { + khm_int32 nv; + + if (IsDlgButtonChecked(hw, IDC_CFG_GETTIX) == BST_CHECKED) + nv = TRUE; + else + nv = FALSE; + + khui_cfg_set_flags_inst(&d->cfg, + (!!nv != !!d->get_tix)? KHUI_CNFLAG_MODIFIED: 0, + KHUI_CNFLAG_MODIFIED); +} + +INT_PTR CALLBACK +krb4_ids_config_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k4_ids_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->cfg = *((khui_config_init_data *) lParam); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + k4_ids_read_params(d); + + CheckDlgButton(hwnd, IDC_CFG_GETTIX, + (d->get_tix)? BST_CHECKED: BST_UNCHECKED); + + break; + + case WM_COMMAND: + d = (k4_ids_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == BN_CLICKED) { + k4_ids_check_mod(hwnd, d); + } + break; + + case KHUI_WM_CFG_NOTIFY: + d = (k4_ids_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + k4_ids_write_params(hwnd, d); + } + break; + + case WM_DESTROY: + d = (k4_ids_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + PFREE(d); + break; + } + + return FALSE; +} + +INT_PTR CALLBACK +krb4_id_config_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khui_config_init_data * d; + khm_handle ident = NULL; + khm_int32 gettix = 0; + khm_int32 flags = 0; + + d = (khui_config_init_data *) lParam; + + khc_read_int32(csp_params, L"Krb4NewCreds", &gettix); + if (gettix == 0) + goto set_ui; + + *idname = 0; + cb = sizeof(idname); + khui_cfg_get_name(d->ctx_node, idname, &cb); + + kcdb_identity_create(idname, 0, &ident); + + if (ident == NULL) { + gettix = 0; + goto set_ui; + } + + kcdb_identity_get_flags(ident, &flags); + + kcdb_identity_release(ident); + + if (!(flags & KCDB_IDENT_FLAG_DEFAULT)) + gettix = 0; + + set_ui: + CheckDlgButton(hwnd, IDC_CFG_GETTIX, + (gettix)?BST_CHECKED: BST_UNCHECKED); + } + break; + } + + return FALSE; +} + + +INT_PTR CALLBACK +krb4_confg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + { + wchar_t wbuf[MAX_PATH]; + CHAR krb_path[MAX_PATH]; + CHAR krbrealm_path[MAX_PATH]; + CHAR ticketName[MAX_PATH]; + char * pticketName; + unsigned int krb_path_sz = sizeof(krb_path); + unsigned int krbrealm_path_sz = sizeof(krbrealm_path); + + // Set KRB.CON + memset(krb_path, '\0', sizeof(krb_path)); + if (!pkrb_get_krbconf2(krb_path, &krb_path_sz)) { + // Error has happened + } else { // normal find + AnsiStrToUnicode(wbuf, sizeof(wbuf), krb_path); + SetDlgItemText(hwnd, IDC_CFG_CFGPATH, wbuf); + } + + // Set KRBREALM.CON + memset(krbrealm_path, '\0', sizeof(krbrealm_path)); + if (!pkrb_get_krbrealm2(krbrealm_path, &krbrealm_path_sz)) { + // Error has happened + } else { + AnsiStrToUnicode(wbuf, sizeof(wbuf), krbrealm_path); + SetDlgItemText(hwnd, IDC_CFG_RLMPATH, wbuf); + } + + // Set TICKET.KRB file Editbox + *ticketName = 0; + pkrb_set_tkt_string(0); + + pticketName = ptkt_string(); + if (pticketName) + StringCbCopyA(ticketName, sizeof(ticketName), pticketName); + + if (!*ticketName) { + // error + } else { + AnsiStrToUnicode(wbuf, sizeof(wbuf), ticketName); + SetDlgItemText(hwnd, IDC_CFG_CACHE, wbuf); + } + } + break; + + case WM_DESTROY: + break; + } + return FALSE; +} diff --git a/mechglue/src/windows/identity/plugins/krb4/krb4funcs.c b/mechglue/src/windows/identity/plugins/krb4/krb4funcs.c new file mode 100644 index 000000000..7798e5c9e --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/krb4funcs.c @@ -0,0 +1,801 @@ +/* +* Copyright (c) 2005 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +/* Originally this was krb5routines.c in Leash sources. Subsequently +modified and adapted for NetIDMgr */ + +#include +#include + +#define SECURITY_WIN32 +#include +#include + +#include +#include +#include +#include + + + +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; + // char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); + if ( strcmp(cred.address,loc_addr) != 0) { + /* TODO: do something about this */ + //Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} + + +long +khm_krb4_list_tickets(void) +{ + char ptktname[MAX_PATH + 5]; + char pname[ANAME_SZ]; + char pinst[INST_SZ]; + char prealm[REALM_SZ]; + wchar_t wbuf[256]; + int k_errno = 0; + CREDENTIALS c; + int newtickets = 0; + int open = 0; + khm_handle ident = NULL; + khm_handle cred = NULL; + time_t tt; + FILETIME ft; + + kcdb_credset_flush(krb4_credset); + + // Since krb_get_tf_realm will return a ticket_file error, + // we will call tf_init and tf_close first to filter out + // things like no ticket file. Otherwise, the error that + // the user would see would be + // klist: can't find realm of ticket file: No ticket file (tf_util) + // instead of klist: No ticket file (tf_util) + if (ptf_init == NULL) + goto collect; + + com_addr(); + + // Open ticket file + if ((k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL))) + { + goto cleanup; + } + // Close ticket file + (void) (*ptf_close)(); + + // We must find the realm of the ticket file here before calling + // tf_init because since the realm of the ticket file is not + // really stored in the principal section of the file, the + // routine we use must itself call tf_init and tf_close. + + if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS) + { + goto cleanup; + } + + // Open ticket file + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + + StringCchCopyA(ptktname, ARRAYLENGTH(ptktname), (*ptkt_string)()); + + open = 1; + + // Get principal name and instance + if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) + { + goto cleanup; + } + + // You may think that this is the obvious place to get the + // realm of the ticket file, but it can't be done here as the + // routine to do this must open the ticket file. This is why + // it was done before tf_init. + StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", (LPSTR)pname, + (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst, + (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm); + + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, &ident))) + { + goto cleanup; + } + + // Get KRB4 tickets + while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) + { + StringCbPrintf(wbuf, sizeof(wbuf), L"%S%S%S%S%S", + c.service, + (c.instance[0] ? "." : ""), + c.instance, + (c.realm[0] ? "@" : ""), + c.realm); + + if(KHM_FAILED(kcdb_cred_create(wbuf, ident, credtype_id_krb4, &cred))) + continue; + + tt = c.issue_date + c.lifetime * 5L * 60L; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft)); + + tt = c.issue_date; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); + + tt = c.lifetime * 5L * 60L; + TimetToFileTimeInterval(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ft, sizeof(ft)); + + AnsiStrToUnicode(wbuf, sizeof(wbuf), ptktname); + kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wbuf, KCDB_CBSIZE_AUTO); + + kcdb_credset_add_cred(krb4_credset, cred, -1); + + } // while + +cleanup: + if (ptf_close == NULL) + return(KSUCCESS); + + if (open) + (*ptf_close)(); //close ticket file + + if (k_errno == EOF) + k_errno = 0; + + // XXX the if statement directly below was inserted to eliminate + // an error NO_TKT_FIL on Leash startup. The error occurs from an + // error number thrown from krb_get_tf_realm. We believe this + // change does not eliminate other errors, but it may. + + if (k_errno == NO_TKT_FIL) + k_errno = 0; + + if(ident) + kcdb_identity_release(ident); + +#if 0 + /*TODO: Handle errors here */ + if (k_errno) + { + CHAR message[256]; + CHAR errBuf[256]; + LPCSTR errText; + + if (!Lerror_message) + return -1; + + errText = err_describe(errBuf, KRBERR(k_errno)); + + sprintf(message, "%s\n\n%s failed", errText, functionName); + MessageBox(NULL, message, "Kerberos Four", + MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); + } +#endif + + collect: + kcdb_credset_collect(NULL, krb4_credset, ident, credtype_id_krb4, NULL); + + return k_errno; +} + +#define KRB_FILE "KRB.CON" +#define KRBREALM_FILE "KRBREALM.CON" +#define KRB5_FILE "KRB5.INI" + +BOOL +khm_krb5_get_profile_file(LPSTR confname, UINT szConfname) +{ + char **configFile = NULL; + if (pkrb5_get_default_config_files(&configFile)) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + return FALSE; + } + + *confname = 0; + + if (configFile) + { + strncpy(confname, *configFile, szConfname); + pkrb5_free_config_files(configFile); + } + + if (!*confname) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + } + + return FALSE; +} + +BOOL +khm_get_krb4_con_file(LPSTR confname, UINT szConfname) +{ + if (hKrb5 && !hKrb4) + { // hold krb.con where krb5.ini is located + CHAR krbConFile[MAX_PATH]=""; + LPSTR pFind; + + //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename); + if (khm_krb5_get_profile_file(krbConFile, sizeof(krbConFile))) + { + GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + + pFind = strrchr(krbConFile, '\\'); + if (pFind) + { + *pFind = 0; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + else + krbConFile[0] = 0; + + strncpy(confname, krbConFile, szConfname); + confname[szConfname-1] = '\0'; + } + else if (hKrb4) + { + unsigned int size = szConfname; + memset(confname, '\0', szConfname); + if (!pkrb_get_krbconf2(confname, &size)) + { // Error has happened + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname,KRB_FILE,szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + } + } + return FALSE; +} + +int +readstring(FILE * file, char * buf, int len) +{ + int c,i; + memset(buf, '\0', sizeof(buf)); + for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) + { + if (i < sizeof(buf)) { + if (c == '\n') { + buf[i] = '\0'; + return i; + } else { + buf[i] = c; + } + } else { + if (c == '\n') { + buf[len-1] = '\0'; + return(i); + } + } + } + if (c == EOF) { + if (i > 0 && i < len) { + buf[i] = '\0'; + return(i); + } else { + buf[len-1] = '\0'; + return(-1); + } + } + return(-1); +} + +/*! \internal + \brief Return a list of configured realms + + The string that is returned is a set of null terminated unicode strings, + each of which denotes one realm. The set is terminated by a zero length + null terminated string. + + The caller should free the returned string using free() + + \return The string with the list of realms or NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_realm_list(void) +{ + wchar_t * rlist = NULL; + + if (pprofile_get_subsection_names && pprofile_free_list) { + const char* rootSection[] = {"realms", NULL}; + const char** rootsec = rootSection; + char **sections = NULL, **cpp = NULL, *value = NULL; + + char krb5_conf[MAX_PATH+1]; + + if (!khm_krb5_get_profile_file(krb5_conf,sizeof(krb5_conf))) { + profile_t profile; + long retval; + const char *filenames[2]; + wchar_t * d; + size_t cbsize; + size_t t; + + filenames[0] = krb5_conf; + filenames[1] = NULL; + retval = pprofile_init(filenames, &profile); + if (!retval) { + retval = pprofile_get_subsection_names(profile, rootsec, §ions); + + if (!retval) + { + /* first figure out how much space to allocate */ + cbsize = 0; + for (cpp = sections; *cpp; cpp++) + { + cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); + } + cbsize += sizeof(wchar_t); /* double null terminated */ + + rlist = PMALLOC(cbsize); + d = rlist; + for (cpp = sections; *cpp; cpp++) + { + AnsiStrToUnicode(d, cbsize, *cpp); + t = wcslen(d) + 1; + d += t; + cbsize -= sizeof(wchar_t) * t; + } + *d = L'\0'; + } + + pprofile_free_list(sections); + +#if 0 + retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); + if ( value ) { + disable_noaddresses = config_boolean_to_int(value); + pprofile_release_string(value); + } +#endif + pprofile_release(profile); + } + } + } else { + FILE * file; + char krb_conf[MAX_PATH+1]; + char * p; + size_t cbsize, t; + wchar_t * d; + + if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && + (file = fopen(krb_conf, "rt"))) + { + char lineBuf[256]; + + /*TODO: compute the actual required buffer size instead of hardcoding */ + cbsize = 16384; // arbitrary + rlist = PMALLOC(cbsize); + d = rlist; + + // Skip the default realm + readstring(file,lineBuf,sizeof(lineBuf)); + + // Read the defined realms + while (TRUE) + { + if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) + break; + + if (*(lineBuf + strlen(lineBuf) - 1) == '\r') + *(lineBuf + strlen(lineBuf) - 1) = 0; + + for (p=lineBuf; *p ; p++) + { + if (isspace(*p)) { + *p = 0; + break; + } + } + + if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { + t = strlen(lineBuf) + 1; + if(cbsize > (1 + t*sizeof(wchar_t))) { + AnsiStrToUnicode(d, cbsize, lineBuf); + d += t; + cbsize -= t * sizeof(wchar_t); + } else + break; + } + } + + *d = L'\0'; + + fclose(file); + } + } + + return rlist; +} + +/*! \internal + \brief Get the default realm + + A string will be returned that specifies the default realm. The caller + should free the string using free(). + + Returns NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_default_realm(void) +{ + wchar_t * realm; + size_t cch; + krb5_context ctx=0; + char * def = 0; + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if (def) { + cch = strlen(def) + 1; + realm = PMALLOC(sizeof(wchar_t) * cch); + AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); + pkrb5_free_default_realm(ctx, def); + } else + realm = NULL; + + pkrb5_free_context(ctx); + + return realm; +} + +static +char * +make_postfix(const char * base, + const char * postfix, + char ** rcopy) +{ + int base_size; + int ret_size; + char * copy = 0; + char * ret = 0; + + base_size = (int) strlen(base) + 1; + ret_size = base_size + (int) strlen(postfix) + 1; + copy = malloc(base_size); + ret = malloc(ret_size); + + if (!copy || !ret) + goto cleanup; + + strncpy(copy, base, base_size); + copy[base_size - 1] = 0; + + strncpy(ret, base, base_size); + strncpy(ret + (base_size - 1), postfix, ret_size - (base_size - 1)); + ret[ret_size - 1] = 0; + + cleanup: + if (!copy || !ret) { + if (copy) + free(copy); + if (ret) + free(ret); + copy = ret = 0; + } + // INVARIANT: (ret ==> copy) && (copy ==> ret) + *rcopy = copy; + return ret; +} + + +static +long +make_temp_cache_v4(const char * postfix) +{ + static char * old_cache = 0; + + if (!pkrb_set_tkt_string || !ptkt_string || !pdest_tkt) + return 0; // XXX - is this appropriate? + + if (old_cache) { + pdest_tkt(); + pkrb_set_tkt_string(old_cache); + free(old_cache); + old_cache = 0; + } + + if (postfix) + { + char * tmp_cache = make_postfix(ptkt_string(), postfix, &old_cache); + + if (!tmp_cache) + return KFAILURE; + + pkrb_set_tkt_string(tmp_cache); + free(tmp_cache); + } + return 0; +} + +long +khm_krb4_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + long k_errno; + + if (!pkrb_set_tkt_string || !ptkt_string || !pkadm_change_your_password || + !pdest_tkt) + return KFAILURE; + + k_errno = make_temp_cache_v4("_chgpwd"); + if (k_errno) return k_errno; + k_errno = pkadm_change_your_password(principal, password, newpassword, + error_str); + make_temp_cache_v4(0); + return k_errno; +} + +long +khm_convert524(khm_handle identity) +{ +#ifdef NO_KRB5 + return(0); +#else + krb5_context ctx = 0; + krb5_error_code code = 0; + int icode = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds *v5creds = 0; + krb5_creds increds; + krb5_ccache cc = 0; + CREDENTIALS * v4creds = NULL; + static int init_ets = 1; + + if (!pkrb5_init_context || + !pkrb_in_tkt || + !pkrb524_init_ets || + !pkrb524_convert_creds_kdc) + return 0; + + v4creds = (CREDENTIALS *) malloc(sizeof(CREDENTIALS)); + memset((char *) v4creds, 0, sizeof(CREDENTIALS)); + + memset((char *) &increds, 0, sizeof(increds)); + /* + From this point on, we can goto cleanup because increds is + initialized. + */ + + code = khm_krb5_initialize(identity, &ctx, &cc); + if (code) + goto cleanup; + + if ( init_ets ) { + pkrb524_init_ets(ctx); + init_ets = 0; + } + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + if ((code = pkrb5_build_principal(ctx, + &server, + krb5_princ_realm(ctx, me)->length, + krb5_princ_realm(ctx, me)->data, + "krbtgt", + krb5_princ_realm(ctx, me)->data, + NULL))) { + goto cleanup; + } + + increds.client = me; + increds.server = server; + increds.times.endtime = 0; + increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + if ((code = pkrb5_get_credentials(ctx, 0, + cc, + &increds, + &v5creds))) { + goto cleanup; + } + + if ((icode = pkrb524_convert_creds_kdc(ctx, + v5creds, + v4creds))) { + goto cleanup; + } + + /* initialize ticket cache */ + if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) + != KSUCCESS)) { + goto cleanup; + } + /* stash ticket, session key, etc. for future use */ + if ((icode = pkrb_save_credentials(v4creds->service, + v4creds->instance, + v4creds->realm, + v4creds->session, + v4creds->lifetime, + v4creds->kvno, + &(v4creds->ticket_st), + v4creds->issue_date))) { + goto cleanup; + } + + cleanup: + memset(v4creds, 0, sizeof(v4creds)); + free(v4creds); + + if (v5creds) { + pkrb5_free_creds(ctx, v5creds); + } + if (increds.client == me) + me = 0; + if (increds.server == server) + server = 0; + + if (ctx) + pkrb5_free_cred_contents(ctx, &increds); + + if (server) { + pkrb5_free_principal(ctx, server); + } + + if (me) { + pkrb5_free_principal(ctx, me); + } + + if (ctx && cc) + pkrb5_cc_close(ctx, cc); + + if (ctx) { + pkrb5_free_context(ctx); + } + + return (code || icode); +#endif /* NO_KRB5 */ +} + +long +khm_krb4_kinit(char * aname, + char * inst, + char * realm, + long lifetime, + char * password) { + + wchar_t * functionName = NULL; + wchar_t * err_context = NULL; + int rc4 = 0; + int msg = 0; + + if (pkname_parse == NULL) { + goto cleanup; + } + + err_context = L"getting realm"; + if (!*realm && (rc4 = (int)(*pkrb_get_lrealm)(realm, 1))) { + functionName = L"krb_get_lrealm()"; + msg = IDS_ERR_REALM; + goto cleanup; + } + + err_context = L"checking principal"; + if ((!*aname) || (!(rc4 = (int)(*pk_isname)(aname)))) { + functionName = L"krb_get_lrealm()"; + msg = IDS_ERR_PRINCIPAL; + goto cleanup; + } + + /* optional instance */ + if (!(rc4 = (int)(*pk_isinst)(inst))) { + functionName = L"k_isinst()"; + msg = IDS_ERR_INVINST; + goto cleanup; + } + + if (!(rc4 = (int)(*pk_isrealm)(realm))) { + functionName = L"k_isrealm()"; + msg = IDS_ERR_REALM; + goto cleanup; + } + + err_context = L"fetching ticket"; + rc4 = (*pkrb_get_pw_in_tkt)(aname, inst, realm, "krbtgt", realm, + lifetime, password); + + if (rc4) /* XXX: do we want: && (rc != NO_TKT_FIL) as well? */ { + functionName = L"krb_get_pw_in_tkt()"; + msg = IDS_ERR_PWINTKT; + goto cleanup; + } + + return 0; + + cleanup: + { + _report_sr0(KHERR_ERROR, msg); + _location(functionName); + } + return rc4; +} + + +int khm_krb4_kdestroy(void) { + int k_errno = 0; + + if (pdest_tkt != NULL) + { + k_errno = (*pdest_tkt)(); + if (k_errno && (k_errno != RET_TKFIL)) + return KRBERR(k_errno); + } + + return k_errno; +} diff --git a/mechglue/src/windows/identity/plugins/krb4/krb4funcs.h b/mechglue/src/windows/identity/plugins/krb4/krb4funcs.h new file mode 100644 index 000000000..742036878 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/krb4funcs.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5FUNCS_H +#define __KHIMAIRA_KRB5FUNCS_H + +#include +#include + +#include +#define SECURITY_WIN32 +#include +#include + +#include + +#define LEASH_DEBUG_CLASS_GENERIC 0 +#define LEASH_DEBUG_CLASS_KRB4 1 +#define LEASH_DEBUG_CLASS_KRB4_APP 2 + +#define LEASH_PRIORITY_LOW 0 +#define LEASH_PRIORITY_HIGH 1 + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ + + +long +khm_convert524(khm_handle identity); + +long +khm_krb4_kinit(char * aname, + char * inst, + char * realm, + long lifetime, + char * password); + +long +khm_krb4_list_tickets(void); + +int khm_krb4_kdestroy(void); + +LONG +write_registry_setting( + char* setting, + DWORD type, + void* buffer, + size_t size + ); + +LONG +read_registry_setting_user( + char* setting, + void* buffer, + size_t size + ); + +LONG +read_registry_setting( + char* setting, + void* buffer, + size_t size + ); + +BOOL +get_STRING_from_registry( + HKEY hBaseKey, + char * key, + char * value, + char * outbuf, + DWORD outlen + ); + +BOOL +get_DWORD_from_registry( + HKEY hBaseKey, + char * key, + char * value, + DWORD * result + ); + +int +config_boolean_to_int( + const char *s + ); + +wchar_t * khm_krb5_get_default_realm(void); +wchar_t * khm_krb5_get_realm_list(void); + +#endif diff --git a/mechglue/src/windows/identity/plugins/krb4/krb4main.c b/mechglue/src/windows/identity/plugins/krb4/krb4main.c new file mode 100644 index 000000000..b83cd5eb4 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/krb4main.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; +HMODULE hResModule; /* HMODULE to the resource library */ + +khm_int32 type_id_enctype = -1; +khm_int32 type_id_addr_list = -1; +khm_int32 type_id_krb5_flags = -1; + +khm_int32 attr_id_key_enctype = -1; +khm_int32 attr_id_tkt_enctype = -1; +khm_int32 attr_id_addr_list = -1; +khm_int32 attr_id_krb5_flags = -1; + +khm_handle csp_plugins = NULL; +khm_handle csp_krbcred = NULL; +khm_handle csp_params = NULL; + +kmm_module_locale locales[] = { + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb4cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) +}; + +int n_locales = ARRAYLENGTH(locales); + +/* These two probably should not do anything */ +void init_krb() { +} + +void exit_krb() { +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t buf[256]; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB4_PLUGIN_NAME; + pi.type = KHM_PITYPE_CRED; + pi.icon = NULL; /*TODO: Assign icon */ + pi.flags = 0; + pi.msg_proc = krb4_cb; + pi.dependencies = KRB4_PLUGIN_DEPS; + pi.description = buf; + LoadString(hResModule, IDS_PLUGIN_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + if(KHM_FAILED(rv = init_imports())) + goto _exit; + + if(KHM_FAILED(rv = init_error_funcs())) + goto _exit; + + rv = kmm_get_plugins_config(0, &csp_plugins); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_load_schema(csp_plugins, schema_krbconfig); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_plugins, CSNAME_KRB4CRED, 0, &csp_krbcred); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); + if(KHM_FAILED(rv)) goto _exit; + +_exit: + return rv; +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + exit_imports(); + exit_error_funcs(); + + if(csp_params) { + khc_close_space(csp_params); + csp_params = NULL; + } + if(csp_krbcred) { + khc_close_space(csp_krbcred); + csp_krbcred = NULL; + } + if(csp_plugins) { + khc_unload_schema(csp_plugins, schema_krbconfig); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved +) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + init_krb(); + break; + case DLL_PROCESS_DETACH: + exit_krb(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/mechglue/src/windows/identity/plugins/krb4/krb4newcreds.c b/mechglue/src/windows/identity/plugins/krb4/krb4newcreds.c new file mode 100644 index 000000000..28ae71a1f --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/krb4newcreds.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define K4_METHOD_AUTO 0 +#define K4_METHOD_PASSWORD 1 +#define K4_METHOD_K524 2 + +int method_to_id[] = { + IDC_NCK4_AUTO, + IDC_NCK4_PWD, + IDC_NCK4_K524 +}; + +typedef struct tag_k4_dlg_data { + HWND hwnd; + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + khm_boolean k4_enabled; + khm_int32 method; + time_t lifetime; +} k4_dlg_data; + +void k4_update_display(k4_dlg_data * d) { + CheckDlgButton(d->hwnd, IDC_NCK4_OBTAIN, + (d->k4_enabled)?BST_CHECKED: BST_UNCHECKED); + + if (d->k4_enabled) { + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_AUTO), TRUE); + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_PWD ), TRUE); + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_K524), TRUE); + } else { + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_AUTO), FALSE); + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_PWD ), FALSE); + EnableWindow(GetDlgItem(d->hwnd, IDC_NCK4_K524), FALSE); + } + + CheckRadioButton(d->hwnd, IDC_NCK4_AUTO, IDC_NCK4_PWD, + method_to_id[d->method]); + + khui_cw_enable_type(d->nc, credtype_id_krb4, d->k4_enabled); +} + +void k4_update_data(k4_dlg_data * d) { + int i; + khm_boolean oldstate; + + oldstate = d->k4_enabled; + + if (IsDlgButtonChecked(d->hwnd, IDC_NCK4_OBTAIN) == BST_CHECKED) + d->k4_enabled = TRUE; + else + d->k4_enabled = FALSE; + + if ((oldstate && !d->k4_enabled) || + (!oldstate && d->k4_enabled)) { + + khui_cw_enable_type(d->nc, credtype_id_krb4, d->k4_enabled); + } + + d->method = 0; + + for (i=K4_METHOD_AUTO; i<=K4_METHOD_K524; i++) { + if (IsDlgButtonChecked(d->hwnd, method_to_id[i]) == BST_CHECKED) { + d->method = i; + break; + } + } +} + +khm_boolean k4_should_identity_get_k4(khm_handle ident) { + khm_int32 idflags = 0; + + if (KHM_FAILED(kcdb_identity_get_flags(ident, &idflags))) + return FALSE; + + if (!(idflags & KCDB_IDENT_FLAG_DEFAULT)) { + /* we only support k4 for one identity, and that is the + default identity. If we are trying to get tickets for + a non-default identity, then we start off as + disabled. */ + + khm_handle defident = NULL; + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&defident))) { + kcdb_identity_release(defident); + + return FALSE; + } + } + + return TRUE; +} + +void k4_read_identity_data(k4_dlg_data * d) { + khm_handle csp_ident = NULL; + khm_handle csp_k4 = NULL; + + khm_int32 idflags = 0; + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"Krb4NewCreds", &t))) + d->k4_enabled = !!t; + else + d->k4_enabled = TRUE; + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"Krb4Method", &t))) + d->method = t; + else + d->method = K4_METHOD_AUTO; + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"DefaultLifetime", &t))) + d->lifetime = t; + else + d->lifetime = 10 * 60 * 60; /* 10 hours */ + + if (d->nc->n_identities > 0 && + d->nc->identities[0]) { + + if (KHM_SUCCEEDED(kcdb_identity_get_config(d->nc->identities[0], + 0, + &csp_ident))) { + + khc_open_space(csp_ident, CSNAME_KRB4CRED, 0, &csp_k4); + + if (csp_k4) { + if (KHM_SUCCEEDED(khc_read_int32(csp_k4, L"Krb4NewCreds", &t))) + d->k4_enabled = !!t; + if (KHM_SUCCEEDED(khc_read_int32(csp_k4, L"Krb4Method", &t))) + d->method = t; + khc_close_space(csp_k4); + } + + khc_close_space(csp_ident); + } + + if (d->k4_enabled) { + d->k4_enabled = k4_should_identity_get_k4(d->nc->identities[0]); + } + } else { + d->k4_enabled = FALSE; + } + + if (d->method < 0 || d->method > K4_METHOD_K524) + d->method = K4_METHOD_AUTO; +} + +void k4_write_identity_data(k4_dlg_data * d) { + khm_handle csp_ident = NULL; + khm_handle csp_k4 = NULL; + + if (d->nc->n_identities > 0 && + d->nc->identities[0] && + KHM_SUCCEEDED(kcdb_identity_get_config(d->nc->identities[0], + KHM_FLAG_CREATE, + &csp_ident))) { + khc_open_space(csp_ident, CSNAME_KRB4CRED, KHM_FLAG_CREATE, &csp_k4); + + if (csp_k4) { + khc_write_int32(csp_k4, L"Krb4NewCreds", !!d->k4_enabled); + khc_write_int32(csp_k4, L"Krb4Method", d->method); + + khc_close_space(csp_k4); + } + + khc_close_space(csp_ident); + } +} + +void k4_handle_wmnc_notify(k4_dlg_data * d, + WPARAM wParam, + LPARAM lParam) { + switch(HIWORD(wParam)) { + case WMNC_UPDATE_CREDTEXT: + { + if (d->nct->credtext) { + PFREE(d->nct->credtext); + d->nct->credtext = NULL; + } + + if (d->nc->n_identities > 0 && + d->nc->identities[0]) { + + khm_int32 flags = 0; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * atsign; + wchar_t * realm; + khm_size cb; + + kcdb_identity_get_flags(d->nc->identities[0], &flags); + + if (flags & KCDB_IDENT_FLAG_INVALID) + break; + + cb = sizeof(idname); + kcdb_identity_get_name(d->nc->identities[0], idname, + &cb); + + atsign = wcsrchr(idname, L'@'); + + if (atsign == NULL || !atsign[1]) + break; + + realm = ++atsign; + + if (d->k4_enabled) { + wchar_t wmethod[128]; + wchar_t wfmt[128]; + wchar_t wct[512]; + + LoadString(hResModule, IDS_CT_TGTFOR, + wfmt, ARRAYLENGTH(wfmt)); + + if (d->method == K4_METHOD_AUTO) + LoadString(hResModule, IDS_METHOD_AUTO, wmethod, + ARRAYLENGTH(wmethod)); + else if (d->method == K4_METHOD_PASSWORD) + LoadString(hResModule, IDS_METHOD_PWD, wmethod, + ARRAYLENGTH(wmethod)); + else if (d->method == K4_METHOD_K524) + LoadString(hResModule, IDS_METHOD_K524, wmethod, + ARRAYLENGTH(wmethod)); + else { + assert(FALSE); + } + + StringCbPrintf(wct, sizeof(wct), wfmt, realm, wmethod); + + StringCbLength(wct, sizeof(wct), &cb); + cb += sizeof(wchar_t); + + d->nct->credtext = PMALLOC(cb); + + StringCbCopy(d->nct->credtext, cb, wct); + } else { + wchar_t wct[256]; + + LoadString(hResModule, IDS_CT_DISABLED, + wct, ARRAYLENGTH(wct)); + + StringCbLength(wct, sizeof(wct), &cb); + cb += sizeof(wchar_t); + + d->nct->credtext = PMALLOC(cb); + + StringCbCopy(d->nct->credtext, cb, wct); + } + } + /* no identities were selected. it is not the + responsibility of krb4 to complain about this. */ + } + break; + + case WMNC_IDENTITY_CHANGE: + k4_read_identity_data(d); + k4_update_display(d); + break; + + case WMNC_CREDTEXT_LINK: + { + wchar_t wid[KHUI_MAXCCH_HTLINK_FIELD]; + wchar_t * wids; + khui_htwnd_link * l; + + l = (khui_htwnd_link *) lParam; + + wcsncpy(wid, l->id, l->id_len); + wid[l->id_len] = 0; + wids = wcschr(wid, L':'); + + if (!wids) + break; + else + wids++; + + if (!wcscmp(wids, L"Enable")) { + d->k4_enabled = TRUE; + + k4_update_display(d); + khui_cw_enable_type(d->nc, credtype_id_krb4, TRUE); + } + } + break; + } +} + +INT_PTR CALLBACK k4_nc_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + k4_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + { + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->nc = (khui_new_creds *) lParam; + khui_cw_find_type(d->nc, credtype_id_krb4, &d->nct); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); +#pragma warning(pop) + + d->nct->aux = (LPARAM) d; + d->hwnd = hwnd; + + d->k4_enabled = TRUE; + d->method = K4_METHOD_AUTO; + + k4_update_display(d); + } + break; + + case WM_COMMAND: + { + d = (k4_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + k4_update_data(d); + k4_update_display(d); + } + break; + + case KHUI_WM_NC_NOTIFY: + { + d = (k4_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + k4_handle_wmnc_notify(d, wParam, lParam); + } + break; + + case WM_DESTROY: + { + d = (k4_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + d->nct->aux = 0; + + PFREE(d); + } + break; + } + + return FALSE; +} + +khm_int32 +krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) { + + switch(msg_subtype) { + case KMSG_CRED_NEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + khm_size cbsize; + wchar_t wbuf[256]; + + nc = (khui_new_creds *) vparam; + + nct = PMALLOC(sizeof(*nct)); +#ifdef DEBUG + assert(nct); +#endif + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb4; + nct->ordinal = 3; + LoadString(hResModule, IDS_NC_K4_SHORT, + wbuf, ARRAYLENGTH(wbuf)); + StringCbLength(wbuf, sizeof(wbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->name = PMALLOC(cbsize); + StringCbCopy(nct->name, cbsize, wbuf); + + nct->type_deps[nct->n_type_deps++] = credtype_id_krb5; + + nct->h_module = hResModule; + nct->dlg_proc = k4_nc_dlg_proc; + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB4); + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_RENEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + khm_size cbsize; + wchar_t wbuf[256]; + + nc = (khui_new_creds *) vparam; + + if (!nc->ctx.identity) + break; + + if (!k4_should_identity_get_k4(nc->ctx.identity)) + break; + + nct = PMALLOC(sizeof(*nct)); +#ifdef DEBUG + assert(nct); +#endif + + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb4; + nct->ordinal = 3; + LoadString(hResModule, IDS_NC_K4_SHORT, + wbuf, ARRAYLENGTH(wbuf)); + StringCbLength(wbuf, sizeof(wbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->name = PMALLOC(cbsize); + StringCbCopy(nct->name, cbsize, wbuf); + + nct->type_deps[nct->n_type_deps++] = credtype_id_krb5; + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_DIALOG_SETUP: + break; + + case KMSG_CRED_PROCESS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct = NULL; + khm_handle ident = NULL; + k4_dlg_data * d = NULL; + long code = 0; + + nc = (khui_new_creds *) vparam; + if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct))) + break; + + if (nc->subtype == KMSG_CRED_NEW_CREDS || + nc->subtype == KMSG_CRED_RENEW_CREDS) { + khm_int32 method; + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + + d = (k4_dlg_data *) nct->aux; + if (!d || + nc->n_identities == 0 || + nc->identities[0] == NULL || + nc->result != KHUI_NC_RESULT_GET_CREDS) + break; + + if (!d->k4_enabled) { + k4_write_identity_data(d); + break; + } + + method = d->method; + ident = nc->identities[0]; + + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + + if ((nc->ctx.scope == KHUI_SCOPE_IDENT && + nc->ctx.identity != NULL) || + + (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && + nc->ctx.cred_type == credtype_id_krb4 && + nc->ctx.identity != NULL) || + + (nc->ctx.scope == KHUI_SCOPE_CRED && + nc->ctx.cred_type == credtype_id_krb4 && + nc->ctx.identity != NULL && + nc->ctx.cred != NULL)) { + + ident = nc->ctx.identity; + + } else { + break; + } + + method = K4_METHOD_K524; /* only k524 is supported + for renewals */ + } else { + assert(FALSE); + } + + if ((method == K4_METHOD_AUTO || + method == K4_METHOD_K524) && + khui_cw_type_succeeded(nc, credtype_id_krb5)) { + + code = khm_convert524(ident); + + if (code == 0) { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT); + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + assert(d != NULL); + + k4_write_identity_data(d); + } + break; + } else if (method == K4_METHOD_K524) { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_FAILED | + KHUI_NC_RESPONSE_EXIT); + break; + } + } + + /* only supported for new credentials */ + if (method == K4_METHOD_AUTO || + method == K4_METHOD_PASSWORD) { + + khm_size n_prompts = 0; + khm_size idx; + khm_size cb; + wchar_t wpwd[KHUI_MAXCCH_PROMPT_VALUE]; + char pwd[KHUI_MAXCCH_PROMPT_VALUE]; + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + char idname[KCDB_IDENT_MAXCCH_NAME]; + + char * aname = NULL; + char * inst = NULL; + char * realm = NULL; + + assert(nc->subtype == KMSG_CRED_NEW_CREDS); + + code = TRUE; /* just has to be non-zero */ + + khui_cw_get_prompt_count(nc, &n_prompts); + + if (n_prompts == 0) + goto _skip_pwd; + + for (idx = 0; idx < n_prompts; idx++) { + khui_new_creds_prompt * p; + + if (KHM_FAILED(khui_cw_get_prompt(nc, idx, &p))) + continue; + + if (p->type == KHUI_NCPROMPT_TYPE_PASSWORD) + break; + } + + if (idx >= n_prompts) + goto _skip_pwd; + + khui_cw_sync_prompt_values(nc); + + cb = sizeof(wpwd); + if (KHM_FAILED(khui_cw_get_prompt_value(nc, idx, + wpwd, + &cb))) + goto _skip_pwd; + + UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); + + cb = sizeof(widname); + kcdb_identity_get_name(ident, + widname, + &cb); + + UnicodeStrToAnsi(idname, sizeof(idname), widname); + + { + char * atsign; + + atsign = strchr(idname, '@'); + if (atsign == NULL) + goto _skip_pwd; + + *atsign++ = 0; + + realm = atsign; + } + + { + char * slash; + + slash = strchr(idname, '/'); + if (slash != NULL) { + *slash++ = 0; + inst = slash; + } else { + inst = ""; + } + } + + aname = idname; + + code = khm_krb4_kinit(aname, inst, realm, + (long) d->lifetime, pwd); + _skip_pwd: + + if (code) { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_FAILED); + + } else { + khui_cw_set_response(nc, credtype_id_krb4, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + + assert(d != NULL); + k4_write_identity_data(d); + + } + } + } + } + } + break; + + case KMSG_CRED_END: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct = NULL; + + nc = (khui_new_creds *) vparam; + if (KHM_FAILED(khui_cw_find_type(nc, credtype_id_krb4, &nct))) + break; + + khui_cw_del_type(nc, credtype_id_krb4); + + if (nct->name) + PFREE(nct->name); + + PFREE(nct); + } + break; + } + + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/plugins/krb4/krb4plugin.c b/mechglue/src/windows/identity/plugins/krb4/krb4plugin.c new file mode 100644 index 000000000..23f913bd9 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/krb4plugin.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include +#include + +khm_int32 credtype_id_krb4 = KCDB_CREDTYPE_INVALID; +khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID; + +khm_boolean krb4_initialized = FALSE; +khm_handle krb4_credset = NULL; + +/* Kerberos IV stuff */ +khm_int32 KHMAPI +krb4_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + kcdb_credtype ct; + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + size_t cbsize; + khui_config_node_reg reg; + wchar_t wshort_desc[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong_desc[KHUI_MAXCCH_LONG_DESC]; + + /* perform critical registrations and initialization + stuff */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = KRB4_CREDTYPE_NAME; + + if(LoadString(hResModule, IDS_KRB4_SHORT_DESC, + buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.short_desc = PMALLOC(cbsize); + StringCbCopy(ct.short_desc, cbsize, buf); + } + + /* even though ideally we should be setting limits + based KCDB_MAXCB_LONG_DESC, our long description + actually fits nicely in KCDB_MAXCB_SHORT_DESC */ + if(LoadString(hResModule, IDS_KRB4_LONG_DESC, + buf, ARRAYLENGTH(buf))) + { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.long_desc = PMALLOC(cbsize); + StringCbCopy(ct.long_desc, cbsize, buf); + } + + ct.icon = NULL; /* TODO: set a proper icon */ + kmq_create_subscription(krb4_cb, &ct.sub); + + rv = kcdb_credtype_register(&ct, &credtype_id_krb4); + + if(KHM_SUCCEEDED(rv)) + rv = kcdb_credset_create(&krb4_credset); + + if (KHM_SUCCEEDED(rv)) + rv = kcdb_credtype_get_id(KRB5_CREDTYPE_NAME, + &credtype_id_krb5); + + if(ct.short_desc) + PFREE(ct.short_desc); + + if(ct.long_desc) + PFREE(ct.long_desc); + + if (KHM_SUCCEEDED(rv)) { + khui_config_node idents; + + ZeroMemory(®, sizeof(reg)); + + reg.name = KRB4_CONFIG_NODE_NAME; + reg.short_desc = wshort_desc; + reg.long_desc = wlong_desc; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_KRB4); + reg.dlg_proc = krb4_confg_proc; + reg.flags = 0; + + LoadString(hResModule, IDS_CFG_KRB4_LONG, + wlong_desc, ARRAYLENGTH(wlong_desc)); + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wshort_desc, ARRAYLENGTH(wshort_desc)); + + khui_cfg_register(NULL, ®); + + khui_cfg_open(NULL, L"KhmIdentities", &idents); + + ZeroMemory(®, sizeof(reg)); + + reg.name = KRB4_IDS_CONFIG_NODE_NAME; + reg.short_desc = wshort_desc; + reg.long_desc = wlong_desc; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_KRB4); + reg.dlg_proc = krb4_ids_config_proc; + reg.flags = KHUI_CNFLAG_SUBPANEL; + + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wlong_desc, ARRAYLENGTH(wlong_desc)); + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wshort_desc, ARRAYLENGTH(wshort_desc)); + + khui_cfg_register(idents, ®); + + ZeroMemory(®, sizeof(reg)); + + reg.name = KRB4_ID_CONFIG_NODE_NAME; + reg.short_desc = wshort_desc; + reg.long_desc = wlong_desc; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_KRB4); + reg.dlg_proc = krb4_id_config_proc; + reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL; + + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wlong_desc, ARRAYLENGTH(wlong_desc)); + LoadString(hResModule, IDS_CFG_KRB4_SHORT, + wshort_desc, ARRAYLENGTH(wshort_desc)); + + khui_cfg_register(idents, ®); + + khui_cfg_release(idents); + + krb4_initialized = TRUE; + + khm_krb4_list_tickets(); + } + + /* Lookup common data types */ + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, + &type_id_enctype))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, + &type_id_addr_list))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, + &type_id_krb5_flags))) { + rv = KHM_ERROR_UNKNOWN; + } + + /* Lookup common attributes */ + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, + &attr_id_key_enctype))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, + &attr_id_tkt_enctype))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, + &attr_id_addr_list))) { + rv = KHM_ERROR_UNKNOWN; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, + &attr_id_krb5_flags))) { + rv = KHM_ERROR_UNKNOWN; + } + + } + break; + + case KMSG_SYSTEM_EXIT: + if(credtype_id_krb4 >= 0) + { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb4); + + kcdb_credset_delete(krb4_credset); + } + break; + } + + return rv; +} + +khm_int32 KHMAPI +krb4_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + { + khm_krb4_list_tickets(); + } + break; + + case KMSG_CRED_DESTROY_CREDS: + { + khui_action_context * ctx; + khm_handle credset; + khm_size nc_root = 0; + khm_size nc_sel = 0; + + ctx = (khui_action_context *) vparam; + + /* if all krb4 tickets are selected, then we destroy all + of them. Otherwise, we do nothing. */ + + kcdb_credset_create(&credset); + + kcdb_credset_extract(credset, ctx->credset, + NULL, credtype_id_krb4); + kcdb_credset_get_size(credset, &nc_sel); + + kcdb_credset_flush(credset); + + kcdb_credset_extract(credset, NULL, + NULL, credtype_id_krb4); + kcdb_credset_get_size(credset, &nc_root); + + kcdb_credset_delete(credset); + + if (nc_root == nc_sel) { + khm_krb4_kdestroy(); + } + } + break; + + default: + if (IS_CRED_ACQ_MSG(msg_subtype)) + return krb4_msg_newcred(msg_type, msg_subtype, uparam, vparam); + } + + return rv; +} + +khm_int32 KHMAPI +krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + switch(msg_type) { + case KMSG_SYSTEM: + return krb4_msg_system(msg_type, msg_subtype, uparam, vparam); + case KMSG_CRED: + return krb4_msg_cred(msg_type, msg_subtype, uparam, vparam); + } + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/plugins/krb4/krbconfig.csv b/mechglue/src/windows/identity/plugins/krb4/krbconfig.csv new file mode 100644 index 000000000..9aa7cd944 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/krbconfig.csv @@ -0,0 +1,16 @@ +Name,Type,Value,Description +Krb4Cred,KC_SPACE,0,"Kerberos IV Credentials Provider" + Module,KC_STRING,"MITKrb4", + Description,KC_STRING,"Kerberos IV Credentials Provider", + Dependencies,KC_STRING,Krb5Cred, + Type,KC_INT32,1, + Flags,KC_INT32,0, + Parameters,KC_SPACE,0,Parameters for KrbCred + Krb4NewCreds,KC_INT32,1,Obtain Kerberos 4 tickets + Krb4Method,KC_INT32,0,Method for acquiring K4 tix. 0-Auto;1-Password;2-K524 + CreateMissingConfig,KC_INT32,0,Create missing configuration files + DefaultLifetime,KC_INT32,36000,Default ticket lifetime + MaxLifetime,KC_INT32,86400,Maximum lifetime + MinLifetime,KC_INT32,60,Minimum lifetime + Parameters,KC_ENDSPACE,0, +Krb4Cred,KC_ENDSPACE,0, diff --git a/mechglue/src/windows/identity/plugins/krb4/krbcred.h b/mechglue/src/windows/identity/plugins/krb4/krbcred.h new file mode 100644 index 000000000..9f5d3c932 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/krbcred.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRBAFSCRED_H +#define __KHIMAIRA_KRBAFSCRED_H + +#include + +#define KHERR_FACILITY L"Kerberos4" +#define KHERR_FACILITY_ID 65 +#define KHERR_HMODULE hResModule + +#include + +#include +#include +#include +#include + +#include + +#define TYPENAME_ENCTYPE L"EncType" +#define TYPENAME_ADDR_LIST L"AddrList" +#define TYPENAME_KRB5_FLAGS L"Krb5Flags" + +#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" +#define ATTRNAME_TKT_ENCTYPE L"TktEncType" +#define ATTRNAME_ADDR_LIST L"AddrList" +#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" +#define ATTRNAME_RENEW_TILL L"RenewTill" +#define ATTRNAME_RENEW_FOR L"RenewFor" + +void init_krb(); +void exit_krb(); +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/* globals */ +extern kmm_module h_khModule; +extern HMODULE hResModule; +extern HINSTANCE hInstance; + +extern khm_int32 type_id_enctype; +extern khm_int32 type_id_addr_list; +extern khm_int32 type_id_krb5_flags; + +extern khm_int32 attr_id_key_enctype; +extern khm_int32 attr_id_tkt_enctype; +extern khm_int32 attr_id_addr_list; +extern khm_int32 attr_id_krb5_flags; +extern khm_int32 attr_id_renew_till; +extern khm_int32 attr_id_renew_for; + +/* Configuration spaces */ +#define CSNAME_KRB4CRED L"Krb4Cred" +#define CSNAME_PARAMS L"Parameters" + +/* plugin constants */ +#define KRB4_PLUGIN_NAME L"Krb4Cred" + +#define KRB4_PLUGIN_DEPS L"Krb5Cred\0" + +#define KRB4_CREDTYPE_NAME L"Krb4Cred" + +#define KRB5_CREDTYPE_NAME L"Krb5Cred" + +#define KRB4_CONFIG_NODE_NAME L"Krb4Config" + +#define KRB4_ID_CONFIG_NODE_NAME L"Krb4IdentConfig" +#define KRB4_IDS_CONFIG_NODE_NAME L"Krb4IdentsConfig" + +extern khm_handle csp_plugins; +extern khm_handle csp_krbcred; +extern khm_handle csp_params; + +extern kconf_schema schema_krbconfig[]; + +/* other globals */ +extern khm_int32 credtype_id_krb4; +extern khm_int32 credtype_id_krb5; + +extern khm_boolean krb4_initialized; + +extern khm_handle krb4_credset; + +/* plugin callbacks */ +khm_int32 KHMAPI +krb4_cb(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam); + +INT_PTR CALLBACK +krb4_confg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +krb4_ids_config_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +krb4_id_config_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +khm_int32 +krb4_msg_newcred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam); +#endif diff --git a/mechglue/src/windows/identity/plugins/krb4/lang/en_us/langres.rc b/mechglue/src/windows/identity/plugins/krb4/lang/en_us/langres.rc new file mode 100644 index 000000000..a07dc4b30 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/lang/en_us/langres.rc @@ -0,0 +1,204 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\langres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NC_KRB4 DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Kerberos 4 Ticket Options",IDC_STATIC,"Static", + SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11 + CONTROL "Obtain Kerberos 4 tickets",IDC_NCK4_OBTAIN,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,26,97,10 + CONTROL "Automatically determine method",IDC_NCK4_AUTO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,23,58,119,10 + CONTROL "Kerberos 5 to 4 translation",IDC_NCK4_K524,"Button", + BS_AUTORADIOBUTTON | WS_TABSTOP,23,76,101,10 + CONTROL "Password",IDC_NCK4_PWD,"Button",BS_AUTORADIOBUTTON | + WS_TABSTOP,23,94,47,10 + GROUPBOX "Obtain Kerberos 4 tickets using",IDC_STATIC,7,43,286,72, + WS_GROUP +END + +IDD_CFG_KRB4 DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket cache location",IDC_CFG_LBL_CACHE,7,10,67,8 + EDITTEXT IDC_CFG_CACHE,83,7,165,14,ES_AUTOHSCROLL + LTEXT "Config file path",IDC_CFG_LBL_CFGFILE,7,30,50,8 + EDITTEXT IDC_CFG_CFGPATH,83,27,113,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_CFGBROW,200,27,48,14 + LTEXT "Realm file path",IDC_CFG_LBL_RLMPATH,7,50,48,8 + EDITTEXT IDC_CFG_RLMPATH,83,47,113,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_RLMBROW,200,47,48,14 +END + +IDD_CFG_IDS_KRB4 DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Obtain Kerberos 4 tickets",IDC_CFG_GETTIX,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,7,221,17 + LTEXT "Note that, if enabled, Kerberos 4 tickets will be acquired during initial credential acquisition and during credential renewals.\n\nHowever, currently Kerberos 4 tickets can only be obtained for the default identity.", + IDC_STATIC,7,91,221,53,SS_SUNKEN +END + +IDD_CFG_ID_KRB4 DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Obtain Kerberos 4 tickets for this identity", + IDC_CFG_GETTIX,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,7,7,147,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NC_KRB4, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_CFG_KRB4, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 83 + VERTGUIDE, 196 + VERTGUIDE, 200 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_IDS_KRB4, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_CFG_ID_KRB4, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_PLUGIN_DESC "Kerberos 4 Credentials Provider" + IDS_NC_K4_SHORT "Kerberos 4" + IDS_ERR_REALM "Could not resolve realm" + IDS_ERR_PRINCIPAL "Invalid principal" + IDS_ERR_INVINST "Invalid instance" + IDS_ERR_PWINTKT "Could not get Kerberos 4 tickets" + IDS_CT_DISABLED "

Krb4: Disabled (click here to enable)

" + IDS_CT_TGTFOR "

Krb4: Tickets for realm %s

" + IDS_METHOD_AUTO "Automatically determined method" +END + +STRINGTABLE +BEGIN + IDS_KRB4_SHORT_DESC "Kerberos 4 tickets" + IDS_KRB4_LONG_DESC "Kerberos 4 tickets" + IDS_CFG_KRB4_LONG "Kerberos 4 Configuration" + IDS_CFG_KRB4_SHORT "Kerberos 4" +END + +STRINGTABLE +BEGIN + IDS_METHOD_PWD "Password" + IDS_METHOD_K524 "Kerberos 5 to 4 translation" + IDS_CFG_IDS_KRB4_SHORT "Kerberos 4" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/mechglue/src/windows/identity/plugins/krb4/langres.h b/mechglue/src/windows/identity/plugins/krb4/langres.h new file mode 100644 index 000000000..ceb236007 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/langres.h @@ -0,0 +1,97 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\plugins\krb4\lang\en_us\langres.rc +// +#define IDS_UNK_ADDR_FMT 101 +#define IDS_KRB5_CREDTEXT_0 102 +#define IDD_NC_KRB4 103 +#define IDS_PLUGIN_DESC 103 +#define IDS_KEY_ENCTYPE_SHORT_DESC 104 +#define IDD_CFG_KRB4 104 +#define IDS_NC_K4_SHORT 104 +#define IDS_TKT_ENCTYPE_SHORT_DESC 105 +#define IDS_ERR_REALM 105 +#define IDD_CFG_IDS_KRB4 105 +#define IDS_KEY_ENCTYPE_LONG_DESC 106 +#define IDS_ERR_PRINCIPAL 106 +#define IDD_CFG_ID_KRB4 106 +#define IDS_TKT_ENCTYPE_LONG_DESC 107 +#define IDS_ERR_INVINST 107 +#define IDS_ADDR_LIST_SHORT_DESC 108 +#define IDS_ERR_PWINTKT 108 +#define IDS_ADDR_LIST_LONG_DESC 109 +#define IDS_CT_DISABLED 109 +#define IDS_ETYPE_NULL 110 +#define IDS_CT_TGTFOR 110 +#define IDS_ETYPE_DES_CBC_CRC 111 +#define IDS_METHOD_AUTO 111 +#define IDS_ETYPE_DES_CBC_MD4 112 +#define IDS_METHOD_PWD 112 +#define IDS_ETYPE_DES_CBC_MD5 113 +#define IDS_METHOD_K524 113 +#define IDS_ETYPE_DES_CBC_RAW 114 +#define IDS_CFG_IDS_KRB4_SHORT 114 +#define IDS_ETYPE_DES3_CBC_SHA 115 +#define IDS_ETYPE_DES3_CBC_RAW 116 +#define IDS_ETYPE_DES_HMAC_SHA1 117 +#define IDS_ETYPE_DES3_CBC_SHA1 118 +#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119 +#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120 +#define IDS_ETYPE_ARCFOUR_HMAC 121 +#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122 +#define IDS_ETYPE_UNKNOWN 123 +#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124 +#define IDS_ETYPE_LOCAL_RC4_MD4 125 +#define IDS_KRB5_SHORT_DESC 126 +#define IDS_KRB5_LONG_DESC 127 +#define IDS_KRB4_SHORT_DESC 128 +#define IDS_KRB4_LONG_DESC 129 +#define IDS_KRB5_FLAGS_SHORT_DESC 130 +#define IDS_RENEW_TILL_SHORT_DESC 131 +#define IDS_RENEW_TILL_LONG_DESC 132 +#define IDS_RENEW_FOR_SHORT_DESC 133 +#define IDS_RENEW_FOR_LONG_DESC 134 +#define IDS_CFG_KRB4_LONG 135 +#define IDS_CFG_KRB4_SHORT 136 +#define IDC_NCK5_RENEWABLE 1002 +#define IDC_NCK5_FORWARDABLE 1004 +#define IDC_NCK5_REALM 1005 +#define IDC_NCK5_ADD_REALMS 1006 +#define IDC_NCK5_LIFETIME_EDIT 1008 +#define IDC_NCK5_RENEW_EDIT 1009 +#define IDC_PPK5_CRENEW 1014 +#define IDC_PPK5_CFORWARD 1015 +#define IDC_PPK5_CPROXY 1016 +#define IDC_PPK5_NAME 1017 +#define IDC_PPK5_ISSUE 1018 +#define IDC_PPK5_VALID 1019 +#define IDC_PPK5_RENEW 1020 +#define IDC_CHECK2 1022 +#define IDC_CHECK4 1024 +#define IDC_PPK5_LIFETIME 1024 +#define IDC_CHECK5 1025 +#define IDC_CFG_LBL_CACHE 1025 +#define IDC_CFG_LBL_CFGFILE 1026 +#define IDC_CFG_LBL_RLMPATH 1027 +#define IDC_CFG_CACHE 1028 +#define IDC_CFG_CFGPATH 1029 +#define IDC_CFG_RLMPATH 1030 +#define IDC_CFG_CFGBROW 1031 +#define IDC_CFG_RLMBROW 1032 +#define IDC_NCK4_OBTAIN 1033 +#define IDC_NCK4_PWD 1034 +#define IDC_NCK4_K524 1035 +#define IDC_NCK4_AUTO 1036 +#define IDC_CFG_GETTIX 1037 +#define IDC_CHECK1 1038 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1039 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/mechglue/src/windows/identity/plugins/krb4/version.rc b/mechglue/src/windows/identity/plugins/krb4/version.rc new file mode 100644 index 000000000..3ca6b1cb9 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb4/version.rc @@ -0,0 +1,66 @@ +/* Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* $Id$ */ + +#include + +1 VERSIONINFO + FILEVERSION KH_VERSION_LIST + PRODUCTVERSION KH_VERSION_LIST + FILEFLAGSMASK KH_VER_FILEFLAGMASK + FILEFLAGS KH_VER_FILEFLAGS + FILEOS KH_VER_FILEOS + FILETYPE KH_VER_FILETYPEDLL + FILESUBTYPE 0 + { + + BLOCK "StringFileInfo" + { + BLOCK "040904b0" + { + VALUE "CompanyName", KH_VERSTR_COMPANY_1033 + VALUE "FileDescription", "Kerberos 4 plugin for NetIDMgr" + VALUE "FileVersion", KH_VERSTR_VERSION_1033 + VALUE "InternalName", "krb4cred" + VALUE "LegalCopyright", KH_VERSTR_COPYRIGHT_1033 + VALUE "OriginalFilename", "krb4cred.dll" + VALUE "ProductName", "NetIDMgr" + VALUE "ProductVersion", KH_VERSTR_PRODUCT_1033 +#ifdef KH_VERSTR_COMMENT_1033 + VALUE "Comment", KH_VERSTR_COMMENT_1033 +#endif + VALUE NIMV_MODULE, "MITKrb4" + VALUE NIMV_PLUGINS, "Krb4Cred" + VALUE NIMV_APIVER, KH_VERSION_STRINGAPI + VALUE NIMV_SUPPORT, "http://web.mit.edu/kerberos" + } + } + + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x409, 1200 + } + + } diff --git a/mechglue/src/windows/identity/plugins/krb5/Makefile b/mechglue/src/windows/identity/plugins/krb5/Makefile new file mode 100644 index 000000000..e0553d846 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/Makefile @@ -0,0 +1,98 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=plugins\krb5 +!include <../../config/Makefile.w32> + +DLLFILE=$(BINDIR)\krb5cred.dll + +LIBFILE=$(LIBDIR)\krb5cred.lib + +OBJFILES= \ + $(LIBDIR)\dynimport.obj \ + $(LIBDIR)\krb5common.obj \ + $(OBJ)\krb5main.obj \ + $(OBJ)\datarep.obj \ + $(OBJ)\errorfuncs.obj \ + $(OBJ)\krb5plugin.obj \ + $(OBJ)\krb5props.obj \ + $(OBJ)\krb5newcreds.obj \ + $(OBJ)\krb5funcs.obj \ + $(OBJ)\krb5config.obj \ + $(OBJ)\krb5identpro.obj \ + $(OBJ)\krb5configdlg.obj \ + $(OBJ)\krb5configcc.obj \ + $(OBJ)\krb5configid.obj \ + $(OBJ)\krb5configids.obj + +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib \ + $(KFWLIBDIR)\loadfuncs.lib + +SDKLIBFILES= \ + netapi32.lib \ + shlwapi.lib \ + comctl32.lib + +MSGRESFILE=$(OBJ)\krb5_msgs.res + +VERRESFILE=$(OBJ)\version.res + +$(OBJ)\krb5config.c: krbconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(DLLFILE): $(MSGRESFILE) $(VERRESFILE) $(OBJFILES) + $(DLLGUILINK) $(LIBFILES) $(SDKLIBFILES) + +$(MSGRESFILE): $(OBJ)\krb5_msgs.rc + +$(OBJ)\krb5_msgs.rc: lang\krb5_msgs.mc + $(MC2RC) + +all: mkdirs $(DLLFILE) lang + +lang:: + +# Repeat this block as necessary redefining LANG for additional +# languages. + +# Begin language block +LANG=en_us + +LANGDLL=$(BINDIR)\krb5cred_$(LANG).dll + +lang:: $(LANGDLL) + +$(LANGDLL): $(OBJ)\langres_$(LANG).res + $(DLLRESLINK) + +$(OBJ)\langres_$(LANG).res: lang\$(LANG)\langres.rc + $(RC2RES) + +# End language block + +clean:: +!if defined(INCFILES) + $(RM) $(INCFILES) +!endif diff --git a/mechglue/src/windows/identity/plugins/krb5/datarep.c b/mechglue/src/windows/identity/plugins/krb5/datarep.c new file mode 100644 index 000000000..2c4036083 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/datarep.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Data representation and related functions */ + +#include +#include +#include +#include + +khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags) +{ + int resid = 0; + int etype; + wchar_t buf[256]; + size_t cblength; + + if(cbdata != sizeof(khm_int32)) + return KHM_ERROR_INVALID_PARAM; + + etype = *((khm_int32 *) data); + + switch(etype) { + case ENCTYPE_NULL: + resid = IDS_ETYPE_NULL; + break; + + case ENCTYPE_DES_CBC_CRC: + resid = IDS_ETYPE_DES_CBC_CRC; + break; + + case ENCTYPE_DES_CBC_MD4: + resid = IDS_ETYPE_DES_CBC_MD4; + break; + + case ENCTYPE_DES_CBC_MD5: + resid = IDS_ETYPE_DES_CBC_MD5; + break; + + case ENCTYPE_DES_CBC_RAW: + resid = IDS_ETYPE_DES_CBC_RAW; + break; + + case ENCTYPE_DES3_CBC_SHA: + resid = IDS_ETYPE_DES3_CBC_SHA; + break; + + case ENCTYPE_DES3_CBC_RAW: + resid = IDS_ETYPE_DES3_CBC_RAW; + break; + + case ENCTYPE_DES_HMAC_SHA1: + resid = IDS_ETYPE_DES_HMAC_SHA1; + break; + + case ENCTYPE_DES3_CBC_SHA1: + resid = IDS_ETYPE_DES3_CBC_SHA1; + break; + + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: + resid = IDS_ETYPE_AES128_CTS_HMAC_SHA1_96; + break; + + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: + resid = IDS_ETYPE_AES256_CTS_HMAC_SHA1_96; + break; + + case ENCTYPE_ARCFOUR_HMAC: + resid = IDS_ETYPE_ARCFOUR_HMAC; + break; + + case ENCTYPE_ARCFOUR_HMAC_EXP: + resid = IDS_ETYPE_ARCFOUR_HMAC_EXP; + break; + + case ENCTYPE_UNKNOWN: + resid = IDS_ETYPE_UNKNOWN; + break; + +#if 0 + case ENCTYPE_LOCAL_DES3_HMAC_SHA1: + resid = IDS_ETYPE_LOCAL_DES3_HMAC_SHA1; + break; + + case ENCTYPE_LOCAL_RC4_MD4: + resid = IDS_ETYPE_LOCAL_RC4_MD4; + break; +#endif + } + + if(resid != 0) { + LoadString(hResModule, (UINT) resid, buf, ARRAYLENGTH(buf)); + } else { + StringCbPrintf(buf, sizeof(buf), L"#%d", etype); + } + + StringCbLength(buf, ARRAYLENGTH(buf), &cblength); + cblength += sizeof(wchar_t); + + if(!destbuf || *pcbdestbuf < cblength) { + *pcbdestbuf = cblength; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(destbuf, *pcbdestbuf, buf); + *pcbdestbuf = cblength; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 KHMAPI addr_list_toString(const void *d, khm_size cb_d, wchar_t *buf, khm_size *pcb_buf, khm_int32 flags) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +khm_int32 KHMAPI krb5flags_toString(const void *d, + khm_size cb_d, + wchar_t *buf, + khm_size *pcb_buf, + khm_int32 f) +{ + wchar_t sbuf[32]; + int i = 0; + khm_size cb; + khm_int32 flags; + + flags = *((khm_int32 *) d); + + if (flags & TKT_FLG_FORWARDABLE) + sbuf[i++] = L'F'; + + if (flags & TKT_FLG_FORWARDED) + sbuf[i++] = L'f'; + + if (flags & TKT_FLG_PROXIABLE) + sbuf[i++] = L'P'; + + if (flags & TKT_FLG_PROXY) + sbuf[i++] = L'p'; + + if (flags & TKT_FLG_MAY_POSTDATE) + sbuf[i++] = L'D'; + + if (flags & TKT_FLG_POSTDATED) + sbuf[i++] = L'd'; + + if (flags & TKT_FLG_INVALID) + sbuf[i++] = L'i'; + + if (flags & TKT_FLG_RENEWABLE) + sbuf[i++] = L'R'; + + if (flags & TKT_FLG_INITIAL) + sbuf[i++] = L'I'; + + if (flags & TKT_FLG_HW_AUTH) + sbuf[i++] = L'H'; + + if (flags & TKT_FLG_PRE_AUTH) + sbuf[i++] = L'A'; + + sbuf[i++] = L'\0'; + + cb = i * sizeof(wchar_t); + + if (!buf || *pcb_buf < cb) { + *pcb_buf = cb; + return KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *pcb_buf, sbuf); + *pcb_buf = cb; + return KHM_ERROR_SUCCESS; + } +} + +khm_int32 serialize_krb5_addresses(krb5_address ** a, void ** buf, size_t * pcbbuf) +{ + /*TODO: implement this */ + return KHM_ERROR_NOT_IMPLEMENTED; +} + +#if 0 + +wchar_t * +one_addr(krb5_address *a) +{ + static wchar_t retstr[256]; + struct hostent *h; + int no_resolve = 1; + + retstr[0] = L'\0'; + + if ((a->addrtype == ADDRTYPE_INET && a->length == 4) +#ifdef AF_INET6 + || (a->addrtype == ADDRTYPE_INET6 && a->length == 16) +#endif + ) + { + int af = AF_INET; +#ifdef AF_INET6 + if (a->addrtype == ADDRTYPE_INET6) + af = AF_INET6; +#endif + if (!no_resolve) { +#ifdef HAVE_GETIPNODEBYADDR + int err; + h = getipnodebyaddr(a->contents, a->length, af, &err); + if (h) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); + freehostent(h); + } +#else + h = gethostbyaddr(a->contents, a->length, af); + if (h) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", h->h_name); + } +#endif + if (h) + return(retstr); + } + if (no_resolve || !h) { +#ifdef HAVE_INET_NTOP + char buf[46]; + const char *name = inet_ntop(a->addrtype, a->contents, buf, sizeof(buf)); + if (name) { + StringCbPrintf(retstr, sizeof(retstr), L"%S", name); + return; + } +#else + if (a->addrtype == ADDRTYPE_INET) { + StringCbPrintf(retstr, sizeof(retstr), + L"%d.%d.%d.%d", a->contents[0], a->contents[1], + a->contents[2], a->contents[3]); + return(retstr); + } +#endif + } + } + { + wchar_t tmpfmt[128]; + LoadString(hResModule, IDS_UNK_ADDR_FMT, tmpfmt, sizeof(tmpfmt)/sizeof(wchar_t)); + StringCbPrintf(retstr, sizeof(retstr), tmpfmt, a->addrtype); + } + return(retstr); +} +#endif diff --git a/mechglue/src/windows/identity/plugins/krb5/datarep.h b/mechglue/src/windows/identity/plugins/krb5/datarep.h new file mode 100644 index 000000000..ac6771cb9 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/datarep.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRB_DATAREP_H +#define __KHIMAIRA_KRB_DATAREP_H + + +khm_int32 KHMAPI enctype_toString(const void * data, khm_size cbdata, wchar_t *destbuf, khm_size *pcbdestbuf, khm_int32 flags); +khm_int32 KHMAPI addr_list_toString(const void *, khm_size, wchar_t *, khm_size *, khm_int32); +khm_int32 KHMAPI krb5flags_toString(const void *, khm_size, wchar_t *, khm_size *, khm_int32); +khm_int32 KHMAPI renew_for_cb(khm_handle cred, khm_int32 id, void * buffer, khm_size * pcbsize); + + +#endif diff --git a/mechglue/src/windows/identity/plugins/krb5/errorfuncs.c b/mechglue/src/windows/identity/plugins/krb5/errorfuncs.c new file mode 100644 index 000000000..d2fabbad4 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/errorfuncs.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +extern void (__cdecl *pinitialize_krb_error_func)(); +extern void (__cdecl *pinitialize_kadm_error_table)(); + + +khm_int32 init_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +khm_int32 exit_error_funcs() +{ + return KHM_ERROR_SUCCESS; +} + +#ifdef DEPRECATED_REMOVABLE +HWND GetRootParent (HWND Child) +{ + HWND Last; + while (Child) + { + Last = Child; + Child = GetParent (Child); + } + return Last; +} +#endif + +void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, + DWORD * suggestion, + kherr_suggestion * suggest_code) +{ + const char * com_err_msg; + int offset; + long table_num; + DWORD msg_id = 0; + DWORD sugg_id = 0; + kherr_suggestion sugg_code = KHERR_SUGGEST_NONE; + + if (suggestion == NULL || buf == NULL || cbbuf == 0 || suggest_code == 0) + return; + + *buf = L'\0'; + + offset = (int) (code & 255); + table_num = code - offset; + com_err_msg = perror_message(code); + + *suggestion = 0; + *suggest_code = KHERR_SUGGEST_NONE; + + switch(table_num) + { + case krb_err_base: + case kadm_err_base: + break; + default: + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { + *suggestion = MSG_ERR_S_INTEGRITY; + } + *suggest_code = KHERR_SUGGEST_RETRY; + AnsiStrToUnicode(buf, cbbuf, com_err_msg); + return; + } + + if (table_num == krb_err_base) + switch(offset) + { + case KDC_NAME_EXP: /* 001 Principal expired */ + case KDC_SERVICE_EXP: /* 002 Service expired */ + case KDC_AUTH_EXP: /* 003 Auth expired */ + case KDC_PKT_VER: /* 004 Protocol version unknown */ + case KDC_P_MKEY_VER: /* 005 Wrong master key version */ + case KDC_S_MKEY_VER: /* 006 Wrong master key version */ + case KDC_BYTE_ORDER: /* 007 Byte order unknown */ + case KDC_PR_N_UNIQUE: /* 009 Principal not unique */ + case KDC_NULL_KEY: /* 010 Principal has null key */ + case KDC_GEN_ERR: /* 011 Generic error from KDC */ + case INTK_W_NOTALL : /* 061 Not ALL tickets returned */ + case INTK_PROT : /* 063 Protocol Error */ + case INTK_ERR : /* 070 Other error */ + msg_id = MSG_ERR_UNKNOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case KDC_PR_UNKNOWN: /* 008 Principal unknown */ + msg_id = MSG_ERR_PR_UNKNOWN; + sugg_code = KHERR_SUGGEST_RETRY; + break; + case GC_TKFIL : /* 021 Can't read ticket file */ + case GC_NOTKT : /* 022 Can't find ticket or TGT */ + msg_id = MSG_ERR_TKFIL; + sugg_id = MSG_ERR_S_TKFIL; + sugg_code = KHERR_SUGGEST_RETRY; + break; + case MK_AP_TGTEXP : /* 026 TGT Expired */ + /* no extra error msg */ + break; + + case RD_AP_TIME : /* 037 delta_t too big */ + msg_id = MSG_ERR_CLOCKSKEW; + sugg_id = MSG_ERR_S_CLOCKSKEW; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case RD_AP_UNDEC : /* 031 Can't decode + authenticator */ + case RD_AP_EXP : /* 032 Ticket expired */ + case RD_AP_NYV : /* 033 Ticket not yet valid */ + case RD_AP_REPEAT : /* 034 Repeated request */ + case RD_AP_NOT_US : /* 035 The ticket isn't for us */ + case RD_AP_INCON : /* 036 Request is inconsistent */ + case RD_AP_BADD : /* 038 Incorrect net address */ + case RD_AP_VERSION : /* 039 protocol version mismatch */ + case RD_AP_MSG_TYPE : /* 040 invalid msg type */ + case RD_AP_MODIFIED : /* 041 message stream modified */ + case RD_AP_ORDER : /* 042 message out of order */ + case RD_AP_UNAUTHOR : /* 043 unauthorized request */ + /* no extra error msg */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + + case GT_PW_NULL: /* 51 Current PW is null */ + case GT_PW_BADPW: /* 52 Incorrect current password */ + case GT_PW_PROT: /* 53 Protocol Error */ + case GT_PW_KDCERR: /* 54 Error returned by KDC */ + case GT_PW_NULLTKT: /* 55 Null tkt returned by KDC */ + /* no error msg yet */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + + /* Values returned by send_to_kdc */ + case SKDC_RETRY : /* 56 Retry count exceeded */ + case SKDC_CANT : /* 57 Can't send request */ + msg_id = MSG_ERR_KDC_CONTACT; + break; + /* no error message on purpose: */ + case INTK_BADPW : /* 062 Incorrect password */ + sugg_code = KHERR_SUGGEST_RETRY; + break; + default: + /* no extra error msg */ + break; + } + else + switch(code) + { + case KADM_INSECURE_PW: + /* if( kadm_info != NULL ){ + * wsprintf(buf, "%s\n%s", com_err_msg, kadm_info); + * } else { + * wsprintf(buf, "%s\nPlease see the help file for information " + * "about secure passwords.", com_err_msg); + * } + * com_err_msg = buf; + */ + + /* The above code would be preferred since it allows site + * specific information to be delivered from the Kerberos + * server. However the message box is too small for VGA + * screens. It does work well if we only have to support + * 1024x768 + */ + + msg_id = MSG_ERR_INSECURE_PW; + sugg_code = KHERR_SUGGEST_RETRY; + break; + + default: + /* no extra error msg */ + break; + } + + if (msg_id != 0) { + FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_IGNORE_INSERTS, + KHERR_HMODULE, + msg_id, + 0, + buf, + (int) (cbbuf / sizeof(buf[0])), + NULL); + } + + if (sugg_id != 0) { + *suggestion = sugg_id; + } + + if (sugg_code != KHERR_SUGGEST_NONE) + *suggest_code = sugg_code; +} + +#ifdef DEPRECATED_REMOVABLE +int lsh_com_err_proc (LPSTR whoami, long code, + LPSTR fmt, va_list args) +{ + int retval; + HWND hOldFocus; + char buf[1024], *cp; + WORD mbformat = MB_OK | MB_ICONEXCLAMATION; + + cp = buf; + memset(buf, '\0', sizeof(buf)); + cp[0] = '\0'; + + if (code) + { + err_describe(buf, code); + while (*cp) + cp++; + } + + if (fmt) + { + if (fmt[0] == '%' && fmt[1] == 'b') + { + fmt += 2; + mbformat = va_arg(args, WORD); + /* if the first arg is a %b, we use it for the message + box MB_??? flags. */ + } + if (code) + { + *cp++ = '\n'; + *cp++ = '\n'; + } + wvsprintfA((LPSTR)cp, fmt, args); + } + hOldFocus = GetFocus(); + retval = MessageBoxA(/*GetRootParent(hOldFocus)*/NULL, buf, whoami, + mbformat | MB_ICONHAND | MB_TASKMODAL); + SetFocus(hOldFocus); + return retval; +} +#endif diff --git a/mechglue/src/windows/identity/plugins/krb5/errorfuncs.h b/mechglue/src/windows/identity/plugins/krb5/errorfuncs.h new file mode 100644 index 000000000..86fc5b440 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/errorfuncs.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ERR_H +#define __KHIMAIRA_ERR_H + +/* All error handling and reporting related functions for the krb4/5 + and AFS plugins */ + +#include +#include +/* + * This is a hack needed because the real com_err.h does + * not define err_func. We need it in the case where + * we pull in the real com_err instead of the krb4 + * impostor. + */ +#ifndef _DCNS_MIT_COM_ERR_H +typedef LPSTR (*err_func)(int, long); +#endif + +#include +#include + +#define kadm_err_base ERROR_TABLE_BASE_kadm + +#include + +#ifndef KRBERR +#define KRBERR(code) (code + krb_err_base) +#endif + +/*! \internal + \brief Describe an error + + \param[in] code Error code returned by Kerberos + \param[out] buf Receives the error string + \param[in] cbbuf Size of buffer pointed to by \a buf + \param[out] suggestion Message ID of suggestion + \param[out] suggest_code Suggestion ID +*/ +void khm_err_describe(long code, wchar_t * buf, khm_size cbbuf, + DWORD * suggestion, + kherr_suggestion * suggest_code); + +/* */ +khm_int32 init_error_funcs(); + +khm_int32 exit_error_funcs(); + + +#endif diff --git a/mechglue/src/windows/identity/plugins/krb5/images/deleted.ico b/mechglue/src/windows/identity/plugins/krb5/images/deleted.ico new file mode 100644 index 0000000000000000000000000000000000000000..a8063f9ee72d8b209717fad18acb3384f8309e44 GIT binary patch literal 1406 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 QV|`Z#{_CFnTidPs4kGa7o&W#< literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/plugins/krb5/images/new.ico b/mechglue/src/windows/identity/plugins/krb5/images/new.ico new file mode 100644 index 0000000000000000000000000000000000000000..1049eb2148f1596a26c22ad7e4522af43af9c49c GIT binary patch literal 1406 zcmb7^p-&u95XL`Jnw&s@IfZCZMUPorgC`-mpmCG_2bhXe=q61_o-o2E@jNTAcdPS^g#JLTI z>vFuZOs5iGO{c?!Gega0GtGX^bpPXvR##Uw8jZBJwx*4Z4UNZRZEkLAYimo}+uJ%g zIMCkSo_2S4wX?IM>HF0Fe(Iwxl)pmXFYa`4bE6MmzhPvA6NQK&H8evrG^<(;QyksV z9o^9#y)G;01-+0I^n%Vsfgb3A9teS+LZxk{XnNrQ3lfhsx7z_qOLxRCz zFc=I5gP~!U%^My6f`7rkZc)L%(3=87fuYccx@~l&Jv|Cn z&UG8+5UX-rnlr z;X#j&kGk(upH5Ht9Z%_Q{SDL$^;%Zz*0g5-eXwkC3`>{UvfA^!|06KJpU=q`QeEG7 zUDwZtDK+o9N!Kk_wA+)(r29L6{_Otq^}Xi(Tz##yJf0+oPx7G;{MWtsH-t7_L>({l Kw~X&-U5(!qarT4& literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/plugins/krb5/images/normal.ico b/mechglue/src/windows/identity/plugins/krb5/images/normal.ico new file mode 100644 index 0000000000000000000000000000000000000000..56a702fee1913ebd6925a6d7fcf7f0e123be3062 GIT binary patch literal 1406 zcmd6np>A725Jj(5S2Bo{m>3zfK@A=h8XhUcIBe8E2q`c!u2d<~vVgWyK}o*AsGuI~ zkOl=riYhf>mI|h4$Bk4Kv?}X+p52}6-M#0{K3f`a@9n9smrtb$qZdS%o)H6$Xltf|K#Mr-BQ(5Lk`t#5Dj`ol+zjBuh6u}uxl&}d=JgTY`h7zzmngTY`h z7z~EOgu!4i7z_r3q0nJ47z_r3!C6+AwG^HM|>NHa2N^H@xdO${QX3hJVAqA5p`b%JfFtm$qwO5jAmE73!GqOtvnXH*SOSQ^uwDUJf`!4PKnPg)5bVR51T4|(Q7rv! z=%;`NL&A_SBn$~d!ceah3;{#JkT3)cY(p>~hJ+zuNEq0fK!+h=NEi};#6Q?9S(r?6 z_Hc5CBWv$I$MszAbb5NKv$HcT77Lx9pKG;R>GJYYS65fMzP{GY&5iEv?)32Rpv`8Z z`|qi@7Z?1F=Tx`<271SSmGyml+Oxl1yT4q0?k>xIUc3Kg{u}R~pKn_S{_CFnTRg7& E0S~(Oi~s-t literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5configcc.c b/mechglue/src/windows/identity/plugins/krb5/krb5configcc.c new file mode 100644 index 000000000..66e7a08d0 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5configcc.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#if _WIN32_WINNT < 0x501 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x501 +#endif + +#include +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable: 4995) +#include +#pragma warning(pop) + +typedef struct tag_k5_file_cc { + wchar_t path[MAX_PATH]; + khm_int32 flags; +} k5_file_cc; + +#define K5_FCC_ALLOC_INCR 8 + +#define K5_FCC_FLAG_EXISTS 1 + +typedef struct tag_k5_ccc_data { + khm_boolean inc_api; + khm_boolean inc_mslsa; + k5_file_cc * file_ccs; + khm_size n_file_ccs; + khm_size nc_file_ccs; +} k5_ccc_data; + +typedef struct tag_k5_ccc_dlg_data { + khui_config_node node; + k5_ccc_data save; + k5_ccc_data work; +} k5_ccc_dlg_data; + +void k5_free_file_ccs(k5_ccc_data * d) { + if (d->file_ccs) + PFREE(d->file_ccs); + d->n_file_ccs = 0; + d->nc_file_ccs = 0; +} + +void k5_flush_file_ccs(k5_ccc_data * d) { + d->n_file_ccs = 0; +} + +void k5_del_file_cc(k5_ccc_data * d, khm_size idx) { + if (idx > d->n_file_ccs) + return; + + if (idx < d->n_file_ccs - 1) { + MoveMemory(&d->file_ccs[idx], + &d->file_ccs[idx + 1], + sizeof(d->file_ccs[0]) * (d->n_file_ccs - (idx + 1))); + } + + d->n_file_ccs--; +} + +void k5_add_file_cc(k5_ccc_data * d, wchar_t * path) { + khm_size i; + khm_size cch; + + if (FAILED(StringCchLength(path, MAX_PATH, &cch)) || + cch == 0) + return; + + /* see if it's there first */ + for (i=0; i < d->n_file_ccs; i++) { + if(!wcsicmp(d->file_ccs[i].path, path)) + return; + } + + if (d->n_file_ccs == d->nc_file_ccs) { + k5_file_cc * f; + + d->nc_file_ccs = UBOUNDSS(d->n_file_ccs + 1, + K5_FCC_ALLOC_INCR, + K5_FCC_ALLOC_INCR); +#ifdef DEBUG + assert(d->nc_file_ccs > d->n_file_ccs); +#endif + f = PMALLOC(sizeof(*f) * d->nc_file_ccs); + ZeroMemory(f, sizeof(*f) * d->nc_file_ccs); + + if (d->n_file_ccs > 0) { +#ifdef DEBUG + assert(d->file_ccs != NULL); +#endif + memcpy(f, d->file_ccs, sizeof(*f) * d->n_file_ccs); + } + if (d->file_ccs) + PFREE(d->file_ccs); + d->file_ccs = f; + } + + StringCbCopy(d->file_ccs[d->n_file_ccs].path, + sizeof(d->file_ccs[0].path), + path); + if(PathFileExists(path)) + d->file_ccs[d->n_file_ccs].flags = K5_FCC_FLAG_EXISTS; + else + d->file_ccs[d->n_file_ccs].flags = 0; + + d->n_file_ccs++; +} + +void k5_read_file_cc_data(k5_ccc_data * d) { + khm_int32 t; + wchar_t * fclist = NULL; + wchar_t * fc; + khm_size cb; + +#ifdef DEBUG + assert(csp_params); +#endif + + d->inc_api = TRUE; + t = TRUE; + khc_read_int32(csp_params, L"MsLsaList", &t); + d->inc_mslsa = t; + + if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) + != KHM_ERROR_TOO_LONG || + cb <= sizeof(wchar_t) * 2) { + + k5_flush_file_ccs(d); + } else { + fclist = PMALLOC(cb); +#ifdef DEBUG + assert(fclist); +#endif + khc_read_multi_string(csp_params, L"FileCCList", fclist, &cb); + + for(fc = fclist; fc && *fc; fc = multi_string_next(fc)) { + k5_add_file_cc(d, fc); + } + + PFREE(fclist); + } +} + +void k5_write_file_cc_data(k5_ccc_data * d) { + wchar_t * ms; + khm_size cb; + khm_size cbt; + khm_int32 t; + khm_size i; + +#ifdef DEBUG + assert(csp_params); +#endif + if (KHM_FAILED(khc_read_int32(csp_params, L"MsLsaList", &t)) || + !!t != !!d->inc_mslsa) { + khc_write_int32(csp_params, L"MsLsaList", !!d->inc_mslsa); + } + + if (d->n_file_ccs > 0) { + cb = d->n_file_ccs * MAX_PATH * sizeof(wchar_t); + ms = PMALLOC(cb); +#ifdef DEBUG + assert(ms); +#endif + multi_string_init(ms, cb); + + for(i=0; in_file_ccs; i++) { + cbt = cb; + multi_string_append(ms, &cbt, d->file_ccs[i].path); + } + + khc_write_multi_string(csp_params, L"FileCCList", ms); + + PFREE(ms); + } else { + if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) + != KHM_ERROR_TOO_LONG || + cb != sizeof(wchar_t) * 2) + + khc_write_multi_string(csp_params, L"FileCCList", L"\0\0"); + } +} + +void k5_copy_file_cc_data(k5_ccc_data * dest, const k5_ccc_data * src) { + khm_size i; + + k5_flush_file_ccs(dest); + dest->inc_mslsa = src->inc_mslsa; + dest->inc_api = src->inc_api; + + for (i=0; i < src->n_file_ccs; i++) { + k5_add_file_cc(dest, src->file_ccs[i].path); + } +} + +BOOL k5_ccc_get_mod(k5_ccc_dlg_data * d) { + khm_size i, j; + + if (!!d->work.inc_mslsa != !!d->save.inc_mslsa || + !!d->work.inc_api != !!d->save.inc_api || + d->work.n_file_ccs != d->save.n_file_ccs) + return TRUE; + + for (i=0; i < d->work.n_file_ccs; i++) { + for (j=0; j < d->save.n_file_ccs; j++) { + if (!wcsicmp(d->work.file_ccs[i].path, + d->save.file_ccs[j].path)) + break; + } + if (j >= d->save.n_file_ccs) + return TRUE; + } + + return FALSE; +} + +void k5_ccc_update_ui(HWND hwnd, k5_ccc_dlg_data * d) { + khm_size i; + HWND lv; + + if (d->work.inc_api) + CheckDlgButton(hwnd, IDC_CFG_INCAPI, BST_CHECKED); + else + CheckDlgButton(hwnd, IDC_CFG_INCAPI, BST_UNCHECKED); + if (d->work.inc_mslsa) + CheckDlgButton(hwnd, IDC_CFG_INCMSLSA, BST_CHECKED); + else + CheckDlgButton(hwnd, IDC_CFG_INCMSLSA, BST_UNCHECKED); + + lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); +#ifdef DEBUG + assert(lv); +#endif + ListView_DeleteAllItems(lv); + + for (i=0; iwork.n_file_ccs; i++) { + LVITEM lvi; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_PARAM | LVIF_TEXT; + lvi.lParam = (LPARAM) i; + lvi.pszText = d->work.file_ccs[i].path; + + ListView_InsertItem(lv, &lvi); + } + + if (k5_ccc_get_mod(d)) { + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + } else { + khui_cfg_set_flags(d->node, + 0, + KHUI_CNFLAG_MODIFIED); + } +} + +void k5_ccc_update_data(HWND hwnd, k5_ccc_data * d) { + if (IsDlgButtonChecked(hwnd, IDC_CFG_INCAPI) == BST_CHECKED) + d->inc_api = TRUE; + else + d->inc_api = FALSE; + + if (IsDlgButtonChecked(hwnd, IDC_CFG_INCMSLSA) == BST_CHECKED) + d->inc_mslsa = TRUE; + else + d->inc_mslsa = FALSE; + /* everything else is controlled by buttons */ +} + +INT_PTR CALLBACK +k5_ccconfig_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + k5_ccc_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); + k5_read_file_cc_data(&d->save); + k5_copy_file_cc_data(&d->work, &d->save); + + d->node = (khui_config_node) lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + { + LVCOLUMN lvc; + HWND lv; + wchar_t buf[256]; + RECT r; + + lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); +#ifdef DEBUG + assert(lv); +#endif + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + + LoadString(hResModule, IDS_CFG_FCTITLE, + buf, ARRAYLENGTH(buf)); + + GetWindowRect(lv, &r); + + lvc.pszText = buf; + lvc.cx = (r.right - r.left) * 9 / 10; + + ListView_InsertColumn(lv, 0, &lvc); + } + + SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, EM_SETLIMITTEXT, + MAX_PATH - 1, 0); + + k5_ccc_update_ui(hwnd, d); + break; + + case WM_COMMAND: + d = (k5_ccc_dlg_data *) (DWORD_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + switch(wParam) { + case MAKEWPARAM(IDC_CFG_ADD, BN_CLICKED): + { + wchar_t path[MAX_PATH]; + wchar_t cpath[MAX_PATH]; + khm_size i; + + GetDlgItemText(hwnd, IDC_CFG_FCNAME, + cpath, ARRAYLENGTH(cpath)); + + PathCanonicalize(path, cpath); + + if (!*path) + return TRUE; /* nothing to add */ + + for (i=0; i < d->work.n_file_ccs; i++) { + if (!wcsicmp(path, d->work.file_ccs[i].path)) { + + /* allow the user to correct case, as appropriate */ + StringCbCopy(d->work.file_ccs[i].path, + sizeof(d->work.file_ccs[i].path), + path); + k5_ccc_update_ui(hwnd, d); + return TRUE; + } + } + + /* not there. we need to add. but check a few things + first */ + if (!PathFileExists(path)) { + wchar_t title[64]; + wchar_t text[128]; + + LoadString(hResModule, IDS_CFG_FCN_WARNING, + title, ARRAYLENGTH(title)); + + LoadString(hResModule, IDS_CFG_FCN_W_NOTFOUND, + text, ARRAYLENGTH(text)); +#if _WIN32_WINNT >= 0x501 + if (IS_COMMCTL6()) + { + EDITBALLOONTIP bt; + + bt.cbStruct = sizeof(bt); + bt.pszTitle = title; + bt.pszText = text; + bt.ttiIcon = TTI_WARNING; + + SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, + EM_SHOWBALLOONTIP, + 0, + (LPARAM) &bt); + } else { +#endif + MessageBox(hwnd, text, title, MB_OK | MB_ICONWARNING); +#if _WIN32_WINNT >= 0x501 + } +#endif + } else if (PathIsRelative(path)) { + wchar_t title[64]; + wchar_t text[128]; + + LoadString(hResModule, IDS_CFG_FCN_WARNING, + title, ARRAYLENGTH(title)); + LoadString(hResModule, IDS_CFG_FCN_W_RELATIVE, + text, ARRAYLENGTH(text)); + +#if _WIN32_WINNT >= 0x501 + if (IS_COMMCTL6()) + { + EDITBALLOONTIP bt; + + bt.cbStruct = sizeof(bt); + bt.pszTitle = title; + bt.pszText = text; + bt.ttiIcon = TTI_WARNING; + + SendDlgItemMessage(hwnd, IDC_CFG_FCNAME, + EM_SHOWBALLOONTIP, + 0, + (LPARAM) &bt); + } else { +#endif + MessageBox(hwnd, text, title, MB_OK | MB_ICONWARNING); +#if _WIN32_WINNT >= 0x501 + } +#endif + } + + k5_add_file_cc(&d->work, path); + + k5_ccc_update_ui(hwnd, d); + } + return TRUE; + + case MAKEWPARAM(IDC_CFG_BROWSE, BN_CLICKED): + { + OPENFILENAME ofn; + wchar_t path[MAX_PATH * 8]; + wchar_t title[128]; + + ZeroMemory(&ofn, sizeof(ofn)); + ZeroMemory(path, sizeof(path)); + + GetDlgItemText(hwnd, IDC_CFG_FCNAME, + path, ARRAYLENGTH(path)); + + /* don't pass in invalid paths */ + if (!PathFileExists(path)) + *path = 0; + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = L"All files\0*.*\0\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = path; + ofn.nMaxFile = ARRAYLENGTH(path); + ofn.lpstrTitle = title; + + LoadString(hResModule, IDS_CFG_FCOPENTITLE, + title, ARRAYLENGTH(title)); + + ofn.Flags = OFN_ALLOWMULTISELECT | + OFN_DONTADDTORECENT | + OFN_FORCESHOWHIDDEN | + OFN_EXPLORER; + + if (GetOpenFileName(&ofn)) { + wchar_t * p; + wchar_t spath[MAX_PATH]; + + p = multi_string_next(path); + if (p) { + /* multi select */ + for(;p && *p; p = multi_string_next(p)) { + StringCbCopy(spath, sizeof(spath), path); + PathAppend(spath, p); + + k5_add_file_cc(&d->work, spath); + } + } else { + /* single select */ + k5_add_file_cc(&d->work, path); + } + k5_ccc_update_ui(hwnd, d); + } + } + return TRUE; + + case MAKEWPARAM(IDC_CFG_REMOVE, BN_CLICKED): + { + khm_size i; + int lv_idx; + HWND lv; + wchar_t buf[MAX_PATH]; + + lv = GetDlgItem(hwnd, IDC_CFG_FCLIST); +#ifdef DEBUG + assert(lv); +#endif + + lv_idx = -1; + while((lv_idx = ListView_GetNextItem(lv, lv_idx, + LVNI_SELECTED)) != -1) { + ListView_GetItemText(lv, lv_idx, 0, buf, ARRAYLENGTH(buf)); + for (i=0; i < d->work.n_file_ccs; i++) { + if (!wcsicmp(buf, d->work.file_ccs[i].path)) { + k5_del_file_cc(&d->work, i); + break; + } + } + } + + k5_ccc_update_ui(hwnd, d); + } + return TRUE; + + case MAKEWPARAM(IDC_CFG_INCAPI, BN_CLICKED): + case MAKEWPARAM(IDC_CFG_INCMSLSA, BN_CLICKED): + k5_ccc_update_data(hwnd, &d->work); + k5_ccc_update_ui(hwnd, d); + return TRUE; + } + break; + + case WM_DESTROY: + d = (k5_ccc_dlg_data *) (DWORD_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + k5_free_file_ccs(&d->work); + k5_free_file_ccs(&d->save); + PFREE(d); + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + d = (k5_ccc_dlg_data *) (DWORD_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + switch(HIWORD(wParam)) { + case WMCFG_APPLY: + if (k5_ccc_get_mod(d)) { + k5_write_file_cc_data(&d->work); + k5_copy_file_cc_data(&d->save, &d->work); + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED); + k5_ccc_update_ui(hwnd, d); + + kmq_post_sub_msg(k5_sub, KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + } + break; + } + } + return FALSE; +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5configdlg.c b/mechglue/src/windows/identity/plugins/krb5/krb5configdlg.c new file mode 100644 index 000000000..8cf89c7cd --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5configdlg.c @@ -0,0 +1,1856 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable: 4995) +#include +#pragma warning(pop) + + +typedef struct tag_k5_realm_kdc { + wchar_t name[K5_MAXCCH_HOST]; + khm_boolean admin; /* admin server? */ + khm_boolean master; /* master kdc? */ + khm_int32 flags; +} k5_realm_kdc; + +#define K5_RKFLAG_DELETED 1 +#define K5_RKFLAG_NEW 2 +#define K5_RKFLAG_MOD_ADMIN 4 +#define K5_RKFLAG_MOD_MASTER 8 + +typedef struct tag_k5_domain_map { + wchar_t name[K5_MAXCCH_HOST]; /* name of host that maps to a + realm */ + khm_int32 flags; +} k5_domain_map; + +#define K5_DMFLAG_DELETED 1 +#define K5_DMFLAG_NEW 2 + +typedef struct tag_k5_realm_data { + wchar_t realm[K5_MAXCCH_REALM]; + k5_realm_kdc kdcs[K5_MAX_KDC]; + khm_size n_kdcs; + k5_domain_map domain_maps[K5_MAX_DOMAIN_MAPPINGS]; + khm_size n_domain_maps; + + khm_int32 flags; +} k5_realm_data; + +#define K5_RDFLAG_DELETED 1 +#define K5_RDFLAG_NEW 2 +#define K5_RDFLAG_MODIFED 4 + +#define K5_REALMS_ALLOC_INCR 8 + +typedef struct tag_k5_config_data { + wchar_t def_realm[K5_MAXCCH_REALM]; /* default realm */ + + wchar_t config_file[MAX_PATH]; /* path to configuration file */ + khm_boolean create_config_file; /* create config_file if missing? */ + khm_boolean inc_realms; /* include full realm list in new + credentials dialog? */ + + /* [libdefaults] */ + khm_boolean dns_lookup_kdc; + khm_boolean dns_lookup_realm; + khm_boolean dns_fallback; + + khm_boolean noaddresses; + + k5_lsa_import lsa_import; /* import mslsa creds? */ + + /* [realms] */ + k5_realm_data *realms; + khm_size n_realms; + khm_size nc_realms; + khm_size c_realm; + + khui_config_node node_main; + khui_config_node node_realm; + + khm_int32 flags; +} k5_config_data; + +#define K5_CDFLAG_MOD_DEF_REALM 0x00000001 +#define K5_CDFLAG_MOD_CONF_FILE 0x00000002 +#define K5_CDFLAG_MOD_DNS_LOOKUP_KDC 0x00000004 +#define K5_CDFLAG_MOD_DNS_LOOKUP_RLM 0x00000008 +#define K5_CDFLAG_MOD_DNS_FALLBACK 0x00000010 +#define K5_CDFLAG_MOD_NOADDRESSES 0x00000020 +#define K5_CDFLAG_MOD_LSA_IMPORT 0x00000040 +#define K5_CDFLAG_MOD_CREATE_CONF 0x00000080 +#define K5_CDFLAG_MOD_INC_REALMS 0x00000100 +#define K5_CDFLAG_MOD_REALMS 0x00001000 + +static const char *const conf_yes[] = { + "y", "yes", "true", "t", "1", "on", + 0, +}; + +static const char *const conf_no[] = { + "n", "no", "false", "nil", "0", "off", + 0, +}; + +int +k5_parse_boolean(const char *s) +{ + const char *const *p; + + for(p=conf_yes; *p; p++) { + if (!stricmp(*p,s)) + return 1; + } + + for(p=conf_no; *p; p++) { + if (!stricmp(*p,s)) + return 0; + } + + /* Default to "no" */ + return 0; +} + +void +k5_init_config_data(k5_config_data * d) { + ZeroMemory(d, sizeof(*d)); +} + +void +k5_free_config_data(k5_config_data * d) { + if (d->realms) + PFREE(d->realms); + + k5_init_config_data(d); +} + +static void +k5_assert_n_realms(k5_config_data * d, khm_size n) { + khm_size nc_realms; + + if (n <= d->nc_realms) + return; + + nc_realms = UBOUNDSS(n, K5_REALMS_ALLOC_INCR, K5_REALMS_ALLOC_INCR); + assert(nc_realms > d->nc_realms); + + d->realms = PREALLOC(d->realms, nc_realms * sizeof(*(d->realms))); + d->nc_realms = nc_realms; + + ZeroMemory(&d->realms[d->n_realms], + (d->nc_realms - d->n_realms) * sizeof(*(d->realms))); +} + +void +k5_purge_config_data(k5_config_data * d, + khm_boolean purge_realms, + khm_boolean purge_kdcs, + khm_boolean purge_dmap) { + khm_size r; + khm_size k; + khm_size m; + + for (r=0; r < d->n_realms; r++) { + if (purge_realms && + (d->realms[r].flags & K5_RDFLAG_NEW) && + (d->realms[r].flags & K5_RDFLAG_DELETED)) { + + if (d->n_realms > r+1) + MoveMemory(&d->realms[r], &d->realms[r+1], + sizeof(d->realms[0]) * (d->n_realms - (r+1))); + r--; + d->n_realms--; + continue; + } + + for (k=0; k < d->realms[r].n_kdcs; k++) { + if (purge_kdcs && + (d->realms[r].kdcs[k].flags & K5_RKFLAG_NEW) && + (d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED)) { + if (d->realms[r].n_kdcs > k + 1) + MoveMemory(&d->realms[r].kdcs[k], + &d->realms[r].kdcs[k+1], + sizeof(d->realms[0].kdcs[0]) * + (d->realms[r].n_kdcs - (k+1))); + k--; + d->realms[r].n_kdcs--; + continue; + } + } + + if (K5_MAX_KDC > k+1) + ZeroMemory(&d->realms[r].kdcs[k], + sizeof(d->realms[0].kdcs[0]) * + (K5_MAX_KDC - (k + 1))); + + for (m=0; m < d->realms[r].n_domain_maps; m++) { + if (purge_dmap && + (d->realms[r].domain_maps[m].flags & K5_DMFLAG_NEW) && + (d->realms[r].domain_maps[m].flags & K5_DMFLAG_DELETED)) { + if (d->realms[r].n_domain_maps > m + 1) + MoveMemory(&d->realms[r].domain_maps[m], + &d->realms[r].domain_maps[m+1], + sizeof(d->realms[0].domain_maps[0]) * + (d->realms[r].n_domain_maps - (m+1))); + m--; + d->realms[r].n_domain_maps--; + continue; + } + } + + if (K5_MAX_DOMAIN_MAPPINGS > m+1) + ZeroMemory(&d->realms[r].domain_maps[m], + sizeof(d->realms[0].domain_maps[0]) * + (K5_MAX_DOMAIN_MAPPINGS - (m+1))); + } + + if (d->nc_realms > r + 1) + ZeroMemory(&d->realms[r], + sizeof(d->realms[0]) * + (d->nc_realms - (r + 1))); +} + +static khm_boolean +k5_is_profile_loaded(void) { +#ifdef DEBUG + assert(pprofile_init); + assert(pprofile_get_subsection_names); + assert(pprofile_get_values); + assert(pprofile_get_string); + assert(pprofile_get_relation_names); + assert(pprofile_free_list); + assert(pprofile_release_string); + assert(pprofile_release); + assert(pprofile_clear_relation); + assert(pprofile_add_relation); + assert(pprofile_update_relation); + assert(pprofile_flush); +#endif + + if (!pprofile_init || + !pprofile_get_subsection_names || + !pprofile_get_values || + !pprofile_get_string || + !pprofile_get_relation_names || + !pprofile_free_list || + !pprofile_release_string || + !pprofile_release || + !pprofile_clear_relation || + !pprofile_add_relation || + !pprofile_update_relation || + !pprofile_flush) + + return FALSE; + + return TRUE; +} + +void +k5_read_config_data(k5_config_data * d) { + wchar_t * defrealm; + char config_file[MAX_PATH]; + profile_t profile = NULL; + const char *filenames[2]; + long rv; + khm_size s; + + if (!k5_is_profile_loaded()) + return; + + defrealm = khm_krb5_get_default_realm(); + + if (defrealm) { + StringCbCopy(d->def_realm, sizeof(d->def_realm), defrealm); + PFREE(defrealm); + } else { + StringCbCopy(d->def_realm, sizeof(d->def_realm), L""); + } + + khm_krb5_get_profile_file(config_file, ARRAYLENGTH(config_file)); + + AnsiStrToUnicode(d->config_file, sizeof(d->config_file), config_file); + + filenames[0] = config_file; + filenames[1] = NULL; + + rv = pprofile_init(filenames, &profile); + + if (!rv) { + const char * sec_realms[] = { "realms", NULL }; + const char * sec_domain_realm[] = { "domain_realm", NULL }; + char ** sections; + char ** dr_from; + char * boolv; + + /* first fish out a few values from [libdefaults] */ + + rv = pprofile_get_string(profile, "libdefaults", "dns_lookup_kdc", + NULL, NULL, &boolv); + if (!rv && boolv) { + d->dns_lookup_kdc = k5_parse_boolean(boolv); + pprofile_release_string(boolv); + } else + d->dns_lookup_kdc = FALSE; + + rv = pprofile_get_string(profile, "libdefaults", "dns_lookup_realm", + NULL, NULL, &boolv); + if (!rv && boolv) { + d->dns_lookup_realm = k5_parse_boolean(boolv); + pprofile_release_string(boolv); + } else + d->dns_lookup_realm = FALSE; + + rv = pprofile_get_string(profile, "libdefaults", "dns_fallback", + NULL, NULL, &boolv); + if (!rv && boolv) { + d->dns_fallback = k5_parse_boolean(boolv); + pprofile_release_string(boolv); + } else + d->dns_fallback = FALSE; + + rv = pprofile_get_string(profile, "libdefaults", "noaddresses", + NULL, NULL, &boolv); + if (!rv && boolv) { + d->noaddresses = k5_parse_boolean(boolv); + pprofile_release_string(boolv); + } else + d->noaddresses = TRUE; + + /* now we look at the [realms] section */ + rv = pprofile_get_subsection_names(profile, sec_realms, §ions); + + /* what? no realms? whatever */ + if (rv) goto _skip_realms; + + /* get a count first */ + for (s=0; sections[s] && sections[s][0]; s++); + + k5_assert_n_realms(d, s); + d->n_realms = s; + + /* now go through each and fish out the kdcs, admin_server + and master_kdc. */ + for (s=0; sections[s] && sections[s][0]; s++) { + const char * sec_kdcs[] = + { "realms", sections[s], "kdc", NULL }; + + const char * sec_admin[] = + { "realms", sections[s], "admin_server", NULL }; + + const char * sec_master[] = + { "realms", sections[s], "master_kdc", NULL }; + + char ** values; + + AnsiStrToUnicode(d->realms[s].realm, sizeof(d->realms[s].realm), + sections[s]); + d->realms[s].n_kdcs = 0; + d->realms[s].n_domain_maps = 0; + + rv = pprofile_get_values(profile, sec_kdcs, &values); + if (!rv) { + khm_size i; + + for (i=0 ; values[i] && values[i][0] && i < K5_MAX_KDC; i++) { + AnsiStrToUnicode(d->realms[s].kdcs[i].name, + sizeof(d->realms[s].kdcs[i].name), + values[i]); + + } + d->realms[s].n_kdcs = i; + + pprofile_free_list(values); + } + + rv = pprofile_get_values(profile, sec_admin, &values); + if (!rv) { + khm_size i; + khm_size j; + wchar_t kdc_name[K5_MAXCCH_HOST]; + + for (i=0; values[i] && values[i][0]; i++) { + AnsiStrToUnicode(kdc_name, + sizeof(kdc_name), values[i]); + + for (j=0; j < d->realms[s].n_kdcs; j++) + if (!wcsicmp(kdc_name, d->realms[s].kdcs[j].name)) + break; + + if (j < d->realms[s].n_kdcs) { + d->realms[s].kdcs[j].admin = TRUE; + } else if (d->realms[s].n_kdcs < K5_MAX_KDC) { + j = d->realms[s].n_kdcs; + StringCbCopy(d->realms[s].kdcs[j].name, + sizeof(d->realms[s].kdcs[j].name), + kdc_name); + d->realms[s].kdcs[j].admin = TRUE; + d->realms[s].n_kdcs ++; + } + } + pprofile_free_list(values); + } + + rv = pprofile_get_values(profile, sec_master, &values); + if (!rv) { + khm_size i; + khm_size j; + wchar_t kdc_name[K5_MAXCCH_HOST]; + + for (i=0; values[i] && values[i][0]; i++) { + AnsiStrToUnicode(kdc_name, sizeof(kdc_name), values[i]); + + for (j=0; j < d->realms[s].n_kdcs; j++) + if (!wcsicmp(kdc_name, d->realms[s].kdcs[j].name)) + break; + + if (j < d->realms[s].n_kdcs) { + d->realms[s].kdcs[j].master = TRUE; + } else if (d->realms[s].n_kdcs < K5_MAX_KDC) { + j = d->realms[s].n_kdcs; + StringCbCopy(d->realms[s].kdcs[j].name, + sizeof(d->realms[s].kdcs[j].name), + kdc_name); + d->realms[s].kdcs[j].master = TRUE; + d->realms[s].n_kdcs ++; + } + } + + pprofile_free_list(values); + } + } + pprofile_free_list(sections); + + _skip_realms: + + rv = pprofile_get_relation_names(profile, sec_domain_realm, &dr_from); + if (!rv) { + khm_size i; + khm_size j; + char * dr_to; + wchar_t wdr_from[K5_MAXCCH_HOST]; + wchar_t wdr_to[K5_MAXCCH_HOST]; + + for (i=0; dr_from[i] && dr_from[i][0]; i++) { + AnsiStrToUnicode(wdr_from, sizeof(wdr_from), dr_from[i]); + + rv = pprofile_get_string(profile, "domain_realm", dr_from[i], + NULL, NULL, &dr_to); + + if (rv || !dr_to) + continue; + + AnsiStrToUnicode(wdr_to, sizeof(wdr_to), dr_to); + + for (j=0; j < d->n_realms; j++) { + if (!wcsicmp(wdr_to, d->realms[j].realm)) + break; + } + + if (j >= d->n_realms) { + j = d->n_realms; + k5_assert_n_realms(d, j + 1); + + StringCbCopy(d->realms[j].realm, + sizeof(d->realms[j].realm), + wdr_to); + d->realms[j].n_kdcs = 0; + d->realms[j].n_domain_maps = 0; + + d->n_realms++; + } + + if (d->realms[j].n_domain_maps < K5_MAX_DOMAIN_MAPPINGS) { + khm_size k; + + k = d->realms[j].n_domain_maps; + + StringCbCopy(d->realms[j].domain_maps[k].name, + sizeof(d->realms[j].domain_maps[k].name), + wdr_from); + + d->realms[j].n_domain_maps++; + } + + pprofile_release_string(dr_to); + } + pprofile_free_list(dr_from); + } + pprofile_release(profile); + } + + { + khm_int32 t; + + /* last, read the MSLSA import setting */ + if (KHM_SUCCEEDED(khc_read_int32(csp_params, + L"MsLsaImport", &t))) { + d->lsa_import = t; + } else { + d->lsa_import = K5_LSAIMPORT_ALWAYS; + } + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, + L"UseFullRealmList", &t))) { + d->inc_realms = !!t; + } else { + d->inc_realms = TRUE; + } + } + + d->flags = 0; +} + +void +k5_write_config_data(k5_config_data * d) { + char astr[MAX_PATH * 2]; + char config_file[MAX_PATH]; + profile_t profile = NULL; + const char *filenames[2]; + long rv; + khm_size s; + + if (d->flags == 0) + return; + + if (!k5_is_profile_loaded()) + return; + + if (d->flags & K5_CDFLAG_MOD_DEF_REALM) { + if (SUCCEEDED(StringCbLength(d->def_realm, + sizeof(d->def_realm), &s)) && + s > 0) { + khm_krb5_set_default_realm(d->def_realm); + } + } + + /* write the MSLSA import setting */ + if (d->flags & K5_CDFLAG_MOD_LSA_IMPORT) { + khc_write_int32(csp_params, L"MsLsaImport", d->lsa_import); + } + + if (d->flags & K5_CDFLAG_MOD_INC_REALMS) { + khc_write_int32(csp_params, L"UseFullRealmList", d->inc_realms); + } + + if (!(d->flags & + (K5_CDFLAG_MOD_CONF_FILE | + K5_CDFLAG_MOD_DNS_FALLBACK | + K5_CDFLAG_MOD_DNS_LOOKUP_RLM | + K5_CDFLAG_MOD_DNS_LOOKUP_KDC | + K5_CDFLAG_MOD_NOADDRESSES | + K5_CDFLAG_MOD_CREATE_CONF | + K5_CDFLAG_MOD_REALMS))) { + + d->flags = 0; + return; + + } + + khm_krb5_get_profile_file(config_file, ARRAYLENGTH(config_file)); + + UnicodeStrToAnsi(astr, sizeof(astr), d->config_file); + + if (stricmp(config_file, astr)) { + assert(FALSE); + } + + filenames[0] = config_file; + filenames[1] = NULL; + + rv = pprofile_init(filenames, &profile); + +#if FAILOVER_TO_TEMPORARY_FILE + if (rv) { + char temp_file[MAX_PATH]; + + khm_krb5_get_temp_profile_file(temp_file, + ARRAYLENGTH(temp_file)); + + filenames[0] = temp_file; + + rv = pprofile_init(filenames, &profile); + + ?? TODO: Also warn if we are doing this + } +#endif + + + if (!rv) { + const char * sec_realms[] = { "realms", NULL }; + const char * sec_domain_realm[] = { "domain_realm", NULL }; + const char * sec_libdefaults[] = { "libdefaults", NULL, NULL }; + khm_size r; + + if (d->flags & K5_CDFLAG_MOD_DNS_LOOKUP_KDC) { + + sec_libdefaults[1] = "dns_lookup_kdc"; + + pprofile_clear_relation(profile, sec_libdefaults); + + rv = pprofile_add_relation(profile, sec_libdefaults, + (d->dns_lookup_kdc)? + conf_yes[0]: + conf_no[0]); + } + + + if (d->flags & K5_CDFLAG_MOD_DNS_LOOKUP_RLM) { + + sec_libdefaults[1] = "dns_lookup_realm"; + + pprofile_clear_relation(profile, sec_libdefaults); + + rv = pprofile_add_relation(profile, sec_libdefaults, + (d->dns_lookup_realm)? + conf_yes[0]: + conf_no[0]); + + } + + if (d->flags & K5_CDFLAG_MOD_DNS_FALLBACK) { + + sec_libdefaults[1] = "dns_fallback"; + + pprofile_clear_relation(profile, sec_libdefaults); + + rv = pprofile_add_relation(profile, sec_libdefaults, + (d->dns_fallback)? + conf_yes[0]: + conf_no[0]); + } + + if (d->flags & K5_CDFLAG_MOD_NOADDRESSES) { + + sec_libdefaults[1] = "noaddresses"; + + pprofile_clear_relation(profile, sec_libdefaults); + + rv = pprofile_add_relation(profile, sec_libdefaults, + (d->noaddresses)? + conf_yes[0]: + conf_no[0]); + } + + /* now we look at the [realms] section */ + + for (r=0; r < d->n_realms; r++) { + char realm[K5_MAXCCH_REALM]; + char host[K5_MAXCCH_HOST]; + + const char * sec_kdcs[] = + { "realms", realm, "kdc", NULL }; + + const char * sec_admin[] = + { "realms", realm, "admin_server", NULL }; + + const char * sec_master[] = + { "realms", realm, "master_kdc", NULL }; + + const char * sec_domain_map[] = + { "domain_realm", host, NULL }; + + char ** values; + + UnicodeStrToAnsi(realm, sizeof(realm), + d->realms[r].realm); + + if (!(d->realms[r].flags & K5_RDFLAG_DELETED) && + (d->realms[r].flags & K5_RDFLAG_NEW)) { + + khm_size k; + khm_size m; + + /* this is a new realm */ + + for (k=0; k < d->realms[r].n_kdcs; k++) { + if (!(d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED)) { + UnicodeStrToAnsi(host, sizeof(host), + d->realms[r].kdcs[k].name); + + if (d->realms[r].kdcs[k].master) + pprofile_add_relation(profile, sec_master, + host); + else + pprofile_add_relation(profile, sec_kdcs, + host); + + if (d->realms[r].kdcs[k].admin) + pprofile_add_relation(profile, sec_admin, + host); + } + } + + for (m=0; m < d->realms[r].n_domain_maps; m++) { + + UnicodeStrToAnsi(host, sizeof(host), + d->realms[r].domain_maps[m].name); + + if ((d->realms[r].domain_maps[m].flags & + K5_DMFLAG_DELETED) && + !(d->realms[r].domain_maps[m].flags & + K5_DMFLAG_NEW)) + pprofile_clear_relation(profile, sec_domain_map); + else if (!(d->realms[r].domain_maps[m].flags & + K5_DMFLAG_DELETED) && + (d->realms[r].domain_maps[m].flags & + K5_DMFLAG_NEW)) + pprofile_add_relation(profile, sec_domain_map, + realm); + } + } else if ((d->realms[r].flags & K5_RDFLAG_DELETED) && + !(d->realms[r].flags & K5_RDFLAG_NEW)) { + + const char * sec_all[] = + { "realms", realm, NULL, NULL }; + khm_size v; + + /* this realm should be deleted */ + + rv = pprofile_get_relation_names(profile, sec_all, + &values); + if (!rv) { + for (v=0; values[v] && values[v][0]; v++) { + sec_all[2] = values[v]; + pprofile_clear_relation(profile, sec_all); + } + pprofile_free_list(values); + } + + rv = pprofile_get_relation_names(profile, sec_domain_realm, + &values); + if (!rv) { + char * maprealm; + + for (v=0; values[v] && values[v][0]; v++) { + + rv = pprofile_get_string(profile, "domain_realm", + values[v], NULL, NULL, + &maprealm); + + if (!rv) { + if (!strcmp(maprealm, realm)) { + StringCbCopyA(host, sizeof(host), + values[v]); + pprofile_clear_relation(profile, + sec_domain_map); + } + pprofile_release_string(maprealm); + } + } + + pprofile_free_list(values); + } + } else if (!(d->realms[r].flags & K5_RDFLAG_DELETED)) { + khm_size k; + khm_size m; + + /* same as before. check if we have to update the kdc + list or the domain_realm mappings */ + + for (k=0; k < d->realms[r].n_kdcs; k++) { + UnicodeStrToAnsi(host, sizeof(host), + d->realms[r].kdcs[k].name); + if (d->realms[r].kdcs[k].flags & K5_RKFLAG_DELETED) { + pprofile_update_relation(profile, sec_kdcs, + host, NULL); + pprofile_update_relation(profile, sec_admin, + host, NULL); + pprofile_update_relation(profile, sec_master, + host, NULL); + + continue; + } + + if (d->realms[r].kdcs[k].flags & K5_RKFLAG_NEW) { + if (d->realms[r].kdcs[k].master) + pprofile_add_relation(profile, sec_master, + host); + else + pprofile_add_relation(profile, sec_kdcs, + host); + + if (d->realms[r].kdcs[k].admin) + pprofile_add_relation(profile, sec_admin, + host); + continue; + } + + if (d->realms[r].kdcs[k].flags & K5_RKFLAG_MOD_MASTER) { + if (!d->realms[r].kdcs[k].master) { + pprofile_add_relation(profile, sec_kdcs, + host); + pprofile_update_relation(profile, sec_master, + host, NULL); + } else { + pprofile_add_relation(profile, sec_master, + host); + pprofile_update_relation(profile, sec_kdcs, + host, NULL); + } + } + + if (d->realms[r].kdcs[k].flags & K5_RKFLAG_MOD_ADMIN) { + if (d->realms[r].kdcs[k].admin) + pprofile_add_relation(profile, sec_admin, + host); + else + pprofile_update_relation(profile, sec_admin, + host, NULL); + } + } + + for (m=0; m < d->realms[r].n_domain_maps; m++) { + + UnicodeStrToAnsi(host, sizeof(host), + d->realms[r].domain_maps[m].name); + + if ((d->realms[r].domain_maps[m].flags & + K5_DMFLAG_DELETED) && + !(d->realms[r].domain_maps[m].flags & + K5_DMFLAG_NEW)) + pprofile_clear_relation(profile, sec_domain_map); + else if (!(d->realms[r].domain_maps[m].flags & + K5_DMFLAG_DELETED) && + (d->realms[r].domain_maps[m].flags & + K5_DMFLAG_NEW)) + pprofile_add_relation(profile, sec_domain_map, + realm); + } + } + } + + rv = pprofile_flush(profile); + + pprofile_release(profile); + } + + if (rv) { + khui_alert * alert; + wchar_t title[KHUI_MAXCCH_TITLE]; + wchar_t fmsg[KHUI_MAXCCH_MESSAGE]; + wchar_t msg[KHUI_MAXCCH_MESSAGE]; + wchar_t sugg[KHUI_MAXCCH_SUGGESTION]; + + LoadString(hResModule, IDS_K5ERR_CANTWRITEPROFILE, + title, ARRAYLENGTH(title)); + if (rv) + LoadString(hResModule, IDS_K5ERR_PROFNOWRITE, + fmsg, ARRAYLENGTH(fmsg)); + + LoadString(hResModule, IDS_K5ERR_PROFSUGGEST, + sugg, ARRAYLENGTH(sugg)); + + StringCbPrintf(msg, sizeof(msg), fmsg, config_file); + + khui_alert_create_empty(&alert); + khui_alert_set_severity(alert, (rv)?KHERR_ERROR:KHERR_WARNING); + khui_alert_set_title(alert, title); + khui_alert_set_message(alert, msg); + khui_alert_set_suggestion(alert, sugg); + + khui_alert_show(alert); + } + + d->flags = 0; +} + +/* actual dialog stuff */ + +#define IDX_NORMAL 1 +#define IDX_MODIFIED 2 +#define IDX_NEW 3 +#define IDX_DELETED 4 + +static k5_config_data k5_config_dlg_data; +static khm_boolean k5_dlg_data_valid = FALSE; + +INT_PTR CALLBACK +k5_config_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + switch(uMsg) { + case WM_INITDIALOG: + { + HWND hw; + khm_size i; + k5_config_data * d; + + wchar_t * t; + wchar_t importopts[256]; + WKSTA_INFO_100 * winfo100; + +#ifdef DEBUG + assert(!k5_dlg_data_valid); +#endif + + k5_init_config_data(&k5_config_dlg_data); + k5_read_config_data(&k5_config_dlg_data); + + k5_dlg_data_valid = TRUE; + + d = &k5_config_dlg_data; + + d->node_main = (khui_config_node) lParam; + + CheckDlgButton(hwnd, IDC_CFG_INCREALMS, + (d->inc_realms)? BST_CHECKED: BST_UNCHECKED); + + hw = GetDlgItem(hwnd, IDC_CFG_DEFREALM); +#ifdef DEBUG + assert(hw); +#endif + + SendMessage(hw, CB_RESETCONTENT, 0, 0); + + for (i=0; i < d->n_realms; i++) { + SendMessage(hw, CB_ADDSTRING, 0, + (LPARAM) d->realms[i].realm); + } + + SendMessage(hw, CB_SELECTSTRING, -1, + (LPARAM) d->def_realm); + + SetDlgItemText(hwnd, IDC_CFG_CFGFILE, d->config_file); + + /* hostname/domain */ + if (NetWkstaGetInfo(NULL, 100, (LPBYTE *) &winfo100) == NERR_Success) { + SetDlgItemText(hwnd, IDC_CFG_HOSTNAME, winfo100->wki100_computername); + SetDlgItemText(hwnd, IDC_CFG_DOMAIN, winfo100->wki100_langroup); + NetApiBufferFree(winfo100); + } + + /* and the import ticket options */ + LoadString(hResModule, IDS_K5CFG_IMPORT_OPTIONS, + importopts, ARRAYLENGTH(importopts)); + + hw = GetDlgItem(hwnd, IDC_CFG_IMPORT); +#ifdef DEBUG + assert(hw); +#endif + SendMessage(hw, CB_RESETCONTENT, 0, 0); + + for (t=importopts; + t && *t && *t != L' ' && + t < importopts + ARRAYLENGTH(importopts); + t = multi_string_next(t)) { + + SendMessage(hw, CB_ADDSTRING, 0, (LPARAM) t); + } + + SendMessage(hw, CB_SETCURSEL, 0, d->lsa_import); + t = importopts; + SendMessage(hw, CB_GETLBTEXT, d->lsa_import,(LPARAM) t); + SendMessage(hw, CB_SELECTSTRING, -1, (LPARAM) t); + } + break; + + case WM_COMMAND: + { + k5_config_data * d; + + d = &k5_config_dlg_data; + + if (wParam == MAKEWPARAM(IDC_CFG_IMPORT, CBN_SELCHANGE)) { + int idx; + int modified = FALSE; + + idx = (int) SendDlgItemMessage(hwnd, IDC_CFG_IMPORT, + CB_GETCURSEL, 0, 0); + if (idx != CB_ERR && idx != d->lsa_import) { + d->lsa_import = idx; + d->flags |= K5_CDFLAG_MOD_LSA_IMPORT; + modified = TRUE; + } + + khui_cfg_set_flags(d->node_main, + (modified)?KHUI_CNFLAG_MODIFIED:0, + KHUI_CNFLAG_MODIFIED); + return TRUE; + } + + if (wParam == MAKEWPARAM(IDC_CFG_INCREALMS, BN_CLICKED)) { + if (IsDlgButtonChecked(hwnd, IDC_CFG_INCREALMS) == + BST_CHECKED) { + d->inc_realms = TRUE; + } else { + d->inc_realms = FALSE; + } + d->flags |= K5_CDFLAG_MOD_INC_REALMS; + + khui_cfg_set_flags(d->node_main, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + return TRUE; + } + } + break; + + case KHUI_WM_CFG_NOTIFY: + { + k5_config_data * d; + + d = &k5_config_dlg_data; + + if (HIWORD(wParam) == WMCFG_APPLY) { + khm_int32 oflags; + + oflags = d->flags; + k5_write_config_data(d); + + if (d->flags != oflags) { + khui_cfg_set_flags(d->node_main, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | + KHUI_CNFLAG_MODIFIED); + } + return TRUE; + } + } + break; + + case WM_DESTROY: + { + k5_free_config_data(&k5_config_dlg_data); + k5_dlg_data_valid = FALSE; + } + break; + } + return FALSE; +} + +static HIMAGELIST +k5_get_state_image_list(void) { + HIMAGELIST hil; + HICON hicon; + + hil = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_COLOR | ILC_MASK, + 4, + 2); + + hicon = LoadImage(hResModule, + MAKEINTRESOURCE(IDI_NORMAL), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + ImageList_AddIcon(hil, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(hResModule, + MAKEINTRESOURCE(IDI_MODIFIED), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + ImageList_AddIcon(hil, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(hResModule, + MAKEINTRESOURCE(IDI_NEW), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + ImageList_AddIcon(hil, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(hResModule, + MAKEINTRESOURCE(IDI_DELETED), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + ImageList_AddIcon(hil, hicon); + + DestroyIcon(hicon); + + return hil; +} + +static void +k5_update_realms_display(HWND hw_list, k5_config_data * d) { + khm_size i; + LVITEM lvi; + wchar_t buf[64]; + + ListView_DeleteAllItems(hw_list); + + for (i=0; i < d->n_realms; i++) { + if ((d->realms[i].flags & K5_RDFLAG_DELETED) && + (d->realms[i].flags & K5_RDFLAG_NEW)) + continue; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.pszText = d->realms[i].realm; + lvi.lParam = i; + + if (d->realms[i].flags & K5_RDFLAG_DELETED) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); + } else if (d->realms[i].flags & K5_RDFLAG_NEW) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + } else if (d->realms[i].flags & K5_RDFLAG_MODIFED) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_MODIFIED); + } else { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); + } + lvi.stateMask = LVIS_STATEIMAGEMASK; + + ListView_InsertItem(hw_list, &lvi); + } + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.pszText = buf; + lvi.lParam = (LPARAM) -1; + + LoadString(hResModule, IDS_CFG_RE_NEWREALM, + buf, ARRAYLENGTH(buf)); + + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + lvi.stateMask = LVIS_STATEIMAGEMASK; + + ListView_InsertItem(hw_list, &lvi); + + if (d->flags & K5_CDFLAG_MOD_REALMS) { + khui_cfg_set_flags(d->node_realm, KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + } else { + khui_cfg_set_flags(d->node_realm, 0, + KHUI_CNFLAG_MODIFIED); + } +} + +static void +k5_update_kdcs_display(HWND hw_kdc, k5_config_data * d, khm_size idx_rlm) { + khm_size k; + LVITEM lvi; + int idx_item; + k5_realm_kdc * pkdc; + wchar_t wyes[8]; + wchar_t wno[8]; + wchar_t wbuf[64]; + + ListView_DeleteAllItems(hw_kdc); + + if (d == NULL) + return; + +#ifdef DEBUG + assert(idx_rlm < d->n_realms); +#endif + LoadString(hResModule, IDS_YES, wyes, ARRAYLENGTH(wyes)); + LoadString(hResModule, IDS_NO, wno, ARRAYLENGTH(wno)); + + for (k=0; k < d->realms[idx_rlm].n_kdcs; k++) { + if ((d->realms[idx_rlm].kdcs[k].flags & K5_RKFLAG_DELETED) && + (d->realms[idx_rlm].kdcs[k].flags & K5_RKFLAG_NEW)) + continue; + + pkdc = &(d->realms[idx_rlm].kdcs[k]); + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + lvi.iItem = K5_MAX_KDC; + lvi.iSubItem = 0; + lvi.lParam = k; + lvi.pszText = pkdc->name; + if (pkdc->flags & K5_RKFLAG_DELETED) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); + } else if (pkdc->flags & K5_RKFLAG_NEW) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + } else if ((pkdc->flags & K5_RKFLAG_MOD_ADMIN) || + (pkdc->flags & K5_RKFLAG_MOD_MASTER)) { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_MODIFIED); + } else { + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); + } + lvi.stateMask = LVIS_STATEIMAGEMASK; + + idx_item = ListView_InsertItem(hw_kdc, &lvi); + + lvi.mask = LVIF_TEXT; + lvi.iItem = idx_item; + lvi.iSubItem = 1; + if (pkdc->admin) + lvi.pszText = wyes; + else + lvi.pszText = wno; + ListView_SetItem(hw_kdc, &lvi); + + lvi.iSubItem = 2; + if (pkdc->master) + lvi.pszText = wyes; + else + lvi.pszText = wno; + ListView_SetItem(hw_kdc, &lvi); + } + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = 0; + lvi.iSubItem = 0; + lvi.pszText = wbuf; + lvi.lParam = (LPARAM) -1; + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + lvi.stateMask = LVIS_STATEIMAGEMASK; + + LoadString(hResModule, IDS_CFG_RE_NEWSERVER, + wbuf, ARRAYLENGTH(wbuf)); + + ListView_InsertItem(hw_kdc, &lvi); +} + +static void +k5_update_dmap_display(HWND hw_dm, k5_config_data * d, khm_size idx_rlm) { + khm_size m; + LVITEM lvi; + k5_domain_map * map; + wchar_t wbuf[64]; + + ListView_DeleteAllItems(hw_dm); + + if (d == NULL) + return; + +#ifdef DEBUG + assert(idx_rlm < d->n_realms); +#endif + + for (m=0; m < d->realms[idx_rlm].n_domain_maps; m++) { + map = &(d->realms[idx_rlm].domain_maps[m]); + + if ((map->flags & K5_DMFLAG_NEW) && + (map->flags & K5_DMFLAG_DELETED)) + continue; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM; + lvi.pszText = map->name; + if (map->flags & K5_DMFLAG_DELETED) + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_DELETED); + else if (map->flags & K5_DMFLAG_NEW) + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + else + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NORMAL); + lvi.stateMask = LVIS_STATEIMAGEMASK; + lvi.lParam = m; + + lvi.iItem = K5_MAX_DOMAIN_MAPPINGS; + lvi.iSubItem = 0; + + ListView_InsertItem(hw_dm, &lvi); + } + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; + lvi.pszText = wbuf; + lvi.lParam = (LPARAM) -1; + lvi.state = INDEXTOSTATEIMAGEMASK(IDX_NEW); + lvi.stateMask = LVIS_STATEIMAGEMASK; + lvi.iItem = 0; + lvi.iSubItem = 0; + + LoadString(hResModule, IDS_CFG_RE_NEWDMAP, + wbuf, ARRAYLENGTH(wbuf)); + + ListView_InsertItem(hw_dm, &lvi); +} + +INT_PTR CALLBACK +k5_realms_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_config_data * d; + + d = &k5_config_dlg_data; + + switch(uMsg) { + case WM_INITDIALOG: + { + LVCOLUMN lvc; + HWND hw; + RECT r; + wchar_t buf[256]; + + assert(k5_dlg_data_valid); + + d->node_realm = (khui_config_node) lParam; + + /* set up columns for the Realms list */ + hw = GetDlgItem(hwnd, IDC_CFG_REALMS); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + r.right -= 5; /* shave a few pixels off the width */ + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = buf; + lvc.cx = (r.right - r.left); + LoadString(hResModule, IDS_CFG_RE_REALMS, + buf, ARRAYLENGTH(buf)); + + ListView_InsertColumn(hw, 0, &lvc); + + ListView_SetImageList(hw, + k5_get_state_image_list(), + LVSIL_STATE); + + k5_update_realms_display(hw, d); + + /* set up columns for the servers list */ + hw = GetDlgItem(hwnd, IDC_CFG_KDC); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + r.right -= 5; + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = buf; + lvc.cx = (r.right - r.left) * 2 / 4; + LoadString(hResModule, IDS_CFG_RE_HEAD_SVR, + buf, ARRAYLENGTH(buf)); + + ListView_InsertColumn(hw, 0, &lvc); + + lvc.cx = (r.right - r.left) * 1 / 4; + LoadString(hResModule, IDS_CFG_RE_HEAD_ADMIN, + buf, ARRAYLENGTH(buf)); + ListView_InsertColumn(hw, 1, &lvc); + + LoadString(hResModule, IDS_CFG_RE_HEAD_MASTER, + buf, ARRAYLENGTH(buf)); + ListView_InsertColumn(hw, 2, &lvc); + + ListView_SetImageList(hw, + k5_get_state_image_list(), + LVSIL_STATE); + + /* set up columns for the domain/host mapping list */ + hw = GetDlgItem(hwnd, IDC_CFG_DMAP); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + r.right -= 5; + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + lvc.pszText = buf; + lvc.cx = (r.right - r.left); + LoadString(hResModule, IDS_CFG_RE_HEAD_DOMAIN, + buf, ARRAYLENGTH(buf)); + + ListView_InsertColumn(hw, 0, &lvc); + + + ListView_SetImageList(hw, + k5_get_state_image_list(), + LVSIL_STATE); + } + break; + + case WM_NOTIFY: + { + LPNMHDR pnmh; + HWND hw_rlm = NULL; + HWND hw_kdc = NULL; + HWND hw_dmp = NULL; + int i; + + pnmh = (LPNMHDR) lParam; + + if (pnmh->idFrom == IDC_CFG_REALMS) { + + hw_rlm = pnmh->hwndFrom; + + switch(pnmh->code) { + case LVN_ITEMCHANGED: + i = ListView_GetSelectedCount(hw_rlm); + hw_kdc = GetDlgItem(hwnd, IDC_CFG_KDC); + hw_dmp = GetDlgItem(hwnd, IDC_CFG_DMAP); + + d->c_realm = (khm_size) -1; + + if (i == 1) { + LVITEM lvi; + + i = ListView_GetNextItem(hw_rlm, -1, + LVNI_SELECTED); + if (i == -1) + goto _no_selection; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.iItem = i; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_rlm, &lvi); + + if (lvi.lParam == -1) + goto _no_selection; + + d->c_realm = lvi.lParam; + + k5_update_kdcs_display(hw_kdc, d, lvi.lParam); + k5_update_dmap_display(hw_dmp, d, lvi.lParam); + return TRUE; + } + + _no_selection: + ListView_DeleteAllItems(hw_kdc); + ListView_DeleteAllItems(hw_dmp); + break; + + case LVN_BEGINLABELEDIT: + { + NMLVDISPINFO * pdisp; + LVITEM lvi; + + pdisp = (NMLVDISPINFO *) lParam; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = pdisp->item.iItem; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_rlm, &lvi); + + if (pdisp->item.iItem == -1 || + lvi.lParam != -1) { + SetWindowLongPtr(hwnd, DWL_MSGRESULT, TRUE); + } else { + /* allow editing */ + HWND hw_edit; + + hw_edit = ListView_GetEditControl(hw_rlm); + if (hw_edit != NULL) { + SendMessage(hw_edit, + EM_SETLIMITTEXT, + K5_MAXCCH_REALM - 1, + 0); + } + SetWindowLongPtr(hwnd, DWL_MSGRESULT, FALSE); + } + + return TRUE; + } + break; + + case LVN_ENDLABELEDIT: + { + NMLVDISPINFO * pdisp; + khm_size n; + + pdisp = (NMLVDISPINFO *) lParam; + + if (pdisp->item.pszText) { + n = d->n_realms; + k5_assert_n_realms(d, n+1); + StringCbCopy(d->realms[n].realm, + sizeof(d->realms[n].realm), + pdisp->item.pszText); + d->realms[n].flags = K5_RDFLAG_NEW; + d->n_realms++; + + d->flags |= K5_CDFLAG_MOD_REALMS; + + k5_update_realms_display(hw_rlm, d); + } + + return TRUE; + } + break; + + case LVN_KEYDOWN: + { + NMLVKEYDOWN * pnmk; + LVITEM lvi; + khm_size r; + int idx; + BOOL modified = FALSE; + + pnmk = (NMLVKEYDOWN *) lParam; + + if (pnmk->wVKey == VK_DELETE) { + idx = -1; + while((idx = ListView_GetNextItem(hw_rlm, idx, + LVNI_SELECTED)) + != -1) { + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = idx; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_rlm, &lvi); + + if (lvi.lParam != -1 && + (r = lvi.lParam) < d->n_realms) { + d->realms[r].flags ^= K5_RDFLAG_DELETED; + modified = TRUE; + } + } + + if (modified) { + d->flags |= K5_CDFLAG_MOD_REALMS; + + k5_purge_config_data(d, TRUE, TRUE, TRUE); + k5_update_realms_display(hw_rlm, d); + k5_update_dmap_display(GetDlgItem(hwnd, IDC_CFG_DMAP), NULL, 0); + k5_update_kdcs_display(GetDlgItem(hwnd, IDC_CFG_KDC), NULL, 0); + } + return TRUE; + } + } + break; + } + } else if (pnmh->idFrom == IDC_CFG_KDC) { + hw_kdc = pnmh->hwndFrom; + + switch (pnmh->code) { + case LVN_BEGINLABELEDIT: + { + NMLVDISPINFO * pdisp; + LVITEM lvi; + + pdisp = (NMLVDISPINFO *) lParam; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = pdisp->item.iItem; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_kdc, &lvi); + + if (pdisp->item.iItem == -1 || + lvi.lParam != -1) { + SetWindowLongPtr(hwnd, DWL_MSGRESULT, TRUE); + } else { + /* allow editing */ + HWND hw_edit; + + hw_edit = ListView_GetEditControl(hw_kdc); + if (hw_edit != NULL) { + SendMessage(hw_edit, + EM_SETLIMITTEXT, + K5_MAXCCH_HOST - 1, + 0); + } + SetWindowLongPtr(hwnd, DWL_MSGRESULT, FALSE); + } + return TRUE; + } + break; + + case LVN_ENDLABELEDIT: + { + NMLVDISPINFO * pdisp; + khm_size r; + khm_size k; + + r = d->c_realm; + + pdisp = (NMLVDISPINFO *) lParam; + + if (pdisp->item.pszText) { + k = d->realms[r].n_kdcs; + + if (k >= K5_MAX_KDC) { + SetWindowLongPtr(hwnd, DWL_MSGRESULT, FALSE); + /* TODO: show a message box saying + there are too many KDC's + already. */ + return TRUE; + } + + StringCbCopy(d->realms[r].kdcs[k].name, + sizeof(d->realms[0].kdcs[0].name), + pdisp->item.pszText); + d->realms[r].kdcs[k].flags = K5_RKFLAG_NEW; + d->realms[r].n_kdcs++; + + d->realms[r].flags |= K5_RDFLAG_MODIFED; + + k5_update_kdcs_display(hw_kdc, d, d->c_realm); + } + return TRUE; + } + break; + + case LVN_KEYDOWN: + { +#if 0 + NMLVKEYDOWN * pnmk; + LVITEM lvi; + khm_size r; + int idx; + BOOL modified = FALSE; + + pnmk = (NMLVKEYDOWN *) lParam; + + if (pnmk->wVKey == VK_DELETE) { + idx = -1; + while((idx = ListView_GetNextItem(hw_rlm, idx, + LVNI_SELECTED)) + != -1) { + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = idx; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw_rlm, &lvi); + + if (lvi.lParam != -1 && + (r = lvi.lParam) < d->n_realms) { + d->realms[r].flags ^= K5_RDFLAG_DELETED; + modified = TRUE; + } + } + + if (modified) { + d->flags |= K5_CDFLAG_MOD_REALMS; + + k5_purge_config_data(d, TRUE, TRUE, TRUE); + k5_update_realms_display(hw_rlm, d); + k5_update_dmap_display(GetDlgItem(hwnd, IDC_CFG_DMAP), NULL, 0); + k5_update_kdcs_display(GetDlgItem(hwnd, IDC_CFG_KDC), NULL, 0); + } + return TRUE; + } +#endif + } + break; + } + } + } + break; + + case WM_DESTROY: + break; + } + return FALSE; +} + +void +k5_register_config_panels(void) { + khui_config_node node; + khui_config_node_reg reg; + wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"Kerberos5"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CONFIG); + reg.dlg_proc = k5_config_dlgproc; + reg.flags = 0; + + khui_cfg_register(NULL, ®); + + if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node))) { + node = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + +#ifdef REALM_EDITOR + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5RLM_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5RLM_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosRealms"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_REALMS); + reg.dlg_proc = k5_realms_dlgproc; + reg.flags = 0; + + khui_cfg_register(node, ®); +#endif + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CCC_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CCC_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosCCaches"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_CACHES); + reg.dlg_proc = k5_ccconfig_dlgproc; + reg.flags = 0; + + khui_cfg_register(node, ®); + + khui_cfg_release(node); + + if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &node))) { + node = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_IDS_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_IDS_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosIdentities"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB); + reg.dlg_proc = k5_ids_tab_dlgproc; + reg.flags = KHUI_CNFLAG_SUBPANEL; + + khui_cfg_register(node, ®); + + ZeroMemory(®, sizeof(reg)); + + LoadString(hResModule, IDS_K5CFG_ID_SHORT_DESC, + wshort, ARRAYLENGTH(wshort)); + LoadString(hResModule, IDS_K5CFG_ID_LONG_DESC, + wlong, ARRAYLENGTH(wlong)); + + reg.name = L"KerberosIdentitiesPlural"; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = hResModule; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB); + reg.dlg_proc = k5_id_tab_dlgproc; + reg.flags = KHUI_CNFLAG_SUBPANEL | KHUI_CNFLAG_PLURAL; + + khui_cfg_register(node, ®); + + khui_cfg_release(node); +} + +void +k5_unregister_config_panels(void) { + khui_config_node node_main; +#ifdef REALM_EDITOR + khui_config_node node_realms; +#endif + khui_config_node node_ids; + khui_config_node node_tab; + khui_config_node node_ccaches; + + if (KHM_FAILED(khui_cfg_open(NULL, L"Kerberos5", &node_main))) { + node_main = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + +#ifdef REALM_EDITOR + if (KHM_SUCCEEDED(khui_cfg_open(node_main, L"KerberosRealms", + &node_realms))) { + khui_cfg_remove(node_realms); + khui_cfg_release(node_realms); + } +#ifdef DEBUG + else + assert(FALSE); +#endif +#endif + + if (KHM_SUCCEEDED(khui_cfg_open(node_main, L"KerberosCCaches", + &node_ccaches))) { + khui_cfg_remove(node_ccaches); + khui_cfg_release(node_ccaches); + } +#ifdef DEBUG + else + assert(FALSE); +#endif + + if (node_main) { + khui_cfg_remove(node_main); + khui_cfg_release(node_main); + } + + if (KHM_FAILED(khui_cfg_open(NULL, L"KhmIdentities", &node_ids))) { + node_ids = NULL; +#ifdef DEBUG + assert(FALSE); +#endif + } + + if (KHM_SUCCEEDED(khui_cfg_open(node_ids, L"KerberosIdentities", &node_tab))) { + khui_cfg_remove(node_tab); + khui_cfg_release(node_tab); + } + if (KHM_SUCCEEDED(khui_cfg_open(node_ids, L"KerberosIdentitiesPlural", &node_tab))) { + khui_cfg_remove(node_tab); + khui_cfg_release(node_tab); + } + + if (node_ids) + khui_cfg_release(node_ids); +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5configid.c b/mechglue/src/windows/identity/plugins/krb5/krb5configid.c new file mode 100644 index 000000000..a4e549d3d --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5configid.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable: 4995) +#include +#pragma warning(pop) + +typedef struct tag_k5_id_dlg_data { + khui_config_init_data cfg; + + khm_handle ident; + + khui_tracker tc_life; + khui_tracker tc_renew; + + wchar_t ccache[KRB5_MAXCCH_CCNAME]; + + time_t life; + time_t renew_life; +} k5_id_dlg_data; + +static void +k5_id_read_params(k5_id_dlg_data * d) { + + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_int32 rv; + khm_int32 t; + khm_handle csp_ident; + khm_handle csp_idroot = NULL; + + cb = sizeof(idname); + rv = khui_cfg_get_name(d->cfg.ctx_node, idname, &cb); +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + + rv = kcdb_identity_create(idname, 0, &d->ident); +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + + rv = kcdb_identity_get_config(d->ident, 0, &csp_idroot); + if (KHM_SUCCEEDED(rv) && + KHM_SUCCEEDED(khc_open_space(csp_idroot, CSNAME_KRB5CRED, 0, + &csp_ident))) { + khc_shadow_space(csp_ident, csp_params); + } else { + csp_ident = csp_params; + } + + if (csp_idroot) + khc_close_space(csp_idroot); + + rv = khc_read_int32(csp_ident, L"DefaultLifetime", &t); + if (KHM_SUCCEEDED(rv)) + d->life = t; + else + d->life = 36000; + + rv = khc_read_int32(csp_ident, L"DefaultRenewLifetime", &t); + if (KHM_SUCCEEDED(rv)) + d->renew_life = t; + else + d->renew_life = 604800; + + cb = sizeof(d->ccache); + rv = khc_read_string(csp_ident, L"DefaultCCName", d->ccache, &cb); + if (KHM_FAILED(rv) || cb <= sizeof(wchar_t)) { + cb = sizeof(d->ccache); + if (KHM_FAILED(kcdb_identity_get_attr(d->ident, attr_id_krb5_ccname, + NULL, d->ccache, &cb))) + ZeroMemory(d->ccache, sizeof(d->ccache)); + } + + khui_tracker_initialize(&d->tc_life); + d->tc_life.current = d->life; + d->tc_life.min = 0; + d->tc_life.max = 3600 * 24 * 7; + + khui_tracker_initialize(&d->tc_renew); + d->tc_renew.current = d->renew_life; + d->tc_renew.min = 0; + d->tc_renew.max = 3600 * 24 * 30; + + if (csp_ident != csp_params) + khc_close_space(csp_ident); +} + +static khm_boolean +k5_id_is_mod(HWND hw, k5_id_dlg_data * d) { + wchar_t ccache[KRB5_MAXCCH_CCNAME]; + + GetDlgItemText(hw, IDC_CFG_CCACHE, ccache, ARRAYLENGTH(ccache)); + + if (wcsicmp(ccache, d->ccache) || + d->tc_renew.current != d->renew_life || + d->tc_life.current != d->life) + return TRUE; + return FALSE; +} + +static void +k5_id_check_mod(HWND hw, k5_id_dlg_data * d) { + BOOL modified = k5_id_is_mod(hw, d); + + khui_cfg_set_flags_inst(&d->cfg, + (modified)?KHUI_CNFLAG_MODIFIED:0, + KHUI_CNFLAG_MODIFIED); +} + +static void +k5_id_write_params(HWND hw, k5_id_dlg_data * d) { + + khm_handle csp_idroot = NULL; + khm_handle csp_ident = NULL; + wchar_t ccache[KRB5_MAXCCH_CCNAME]; + khm_size cb; + khm_int32 rv; + + if (!k5_id_is_mod(hw, d)) + return; + + rv = kcdb_identity_get_config(d->ident, KHM_FLAG_CREATE, &csp_idroot); + if (KHM_SUCCEEDED(rv)) { + khc_open_space(csp_idroot, CSNAME_KRB5CRED, + KHM_FLAG_CREATE, + &csp_ident); + } + + if (csp_idroot) + khc_close_space(csp_idroot); + + if (!csp_ident) + return; + + if (d->life != d->tc_life.current) { + d->life = d->tc_life.current; + khc_write_int32(csp_ident, L"DefaultLifetime", (khm_int32) d->life); + } + + if (d->renew_life != d->tc_renew.current) { + d->renew_life = d->tc_renew.current; + khc_write_int32(csp_ident, L"DefaultRenewLifetime", (khm_int32) d->renew_life); + } + + GetDlgItemText(hw, IDC_CFG_CCACHE, ccache, ARRAYLENGTH(ccache)); + + if (SUCCEEDED(StringCbLength(ccache, sizeof(ccache), &cb)) && + wcsicmp(ccache, d->ccache)) { + khc_write_string(csp_ident, L"DefaultCCName", ccache); + StringCbCopy(d->ccache, sizeof(d->ccache), ccache); + } else { + khc_remove_value(csp_ident, L"DefaultCCName", KCONF_FLAG_USER); + } + + if (csp_ident) + khc_close_space(csp_ident); + + khui_cfg_set_flags_inst(&d->cfg, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +INT_PTR CALLBACK +k5_id_tab_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + k5_id_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); + + d->cfg = *((khui_config_init_data *) lParam); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + k5_id_read_params(d); + + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE), + &d->tc_life); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE), + &d->tc_renew); + khui_tracker_refresh(&d->tc_life); + khui_tracker_refresh(&d->tc_renew); + + SetDlgItemText(hwnd, IDC_CFG_CCACHE, d->ccache); + break; + + case WM_COMMAND: + d = (k5_id_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == EN_CHANGE) + k5_id_check_mod(hwnd, d); + break; + + case KHUI_WM_CFG_NOTIFY: + d = (k5_id_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + k5_id_write_params(hwnd, d); + } + break; + + case WM_DESTROY: + d = (k5_id_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + khui_tracker_kill_controls(&d->tc_life); + khui_tracker_kill_controls(&d->tc_renew); + + if (d->ident) + kcdb_identity_release(d->ident); + + PFREE(d); + break; + } + return FALSE; +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5configids.c b/mechglue/src/windows/identity/plugins/krb5/krb5configids.c new file mode 100644 index 000000000..4eebb9c62 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5configids.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable: 4995) +#include +#pragma warning(pop) + +typedef struct tag_k5_ids_dlg_data { + khui_config_init_data cfg; + + khui_tracker tc_life; + khui_tracker tc_renew; + khui_tracker tc_life_min; + khui_tracker tc_life_max; + khui_tracker tc_renew_min; + khui_tracker tc_renew_max; + + time_t life; + time_t renew_life; + time_t life_min; + time_t life_max; + time_t renew_min; + time_t renew_max; +} k5_ids_dlg_data; + +static khm_boolean +k5_ids_is_mod(k5_ids_dlg_data * d) { + if (d->life != d->tc_life.current || + d->renew_life != d->tc_renew.current || + d->life_max != d->tc_life_max.current || + d->life_min != d->tc_life_min.current || + d->renew_max != d->tc_renew_max.current || + d->renew_min != d->tc_renew_min.current) + return TRUE; + return FALSE; +} + +static void +k5_ids_check_mod(k5_ids_dlg_data * d) { + BOOL modified = k5_ids_is_mod(d); + + khui_cfg_set_flags_inst(&d->cfg, + (modified)?KHUI_CNFLAG_MODIFIED:0, + KHUI_CNFLAG_MODIFIED); +} + +static void +k5_ids_write_params(k5_ids_dlg_data * d) { + + khm_int32 rv; + +#ifdef DEBUG + assert(csp_params); +#endif + + if (!k5_ids_is_mod(d)) + return; + +#define WRITEPARAM(po,pn,vn) \ + if (po != pn) { \ + po = pn; \ + rv = khc_write_int32(csp_params, vn, (khm_int32) po); \ + assert(KHM_SUCCEEDED(rv)); \ + } + + WRITEPARAM(d->life,d->tc_life.current, L"DefaultLifetime"); + WRITEPARAM(d->renew_life,d->tc_renew.current, L"DefaultRenewLifetime"); + WRITEPARAM(d->life_max,d->tc_life_max.current, L"MaxLifetime"); + WRITEPARAM(d->life_min,d->tc_life_min.current, L"MinLifetime"); + WRITEPARAM(d->renew_max,d->tc_renew_max.current, L"MaxRenewLifetime"); + WRITEPARAM(d->renew_min,d->tc_renew_min.current, L"MinRenewLifetime"); + +#undef WRITEPARAM + + khui_cfg_set_flags_inst(&d->cfg, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +static void +k5_ids_read_params(k5_ids_dlg_data * d) { + khm_int32 t; + khm_int32 rv; + +#ifdef DEBUG + assert(csp_params); +#endif + + rv = khc_read_int32(csp_params, L"DefaultLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life = t; + + rv = khc_read_int32(csp_params, L"DefaultRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_life = t; + + rv = khc_read_int32(csp_params, L"MaxLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life_max = t; + + rv = khc_read_int32(csp_params, L"MinLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->life_min = t; + + rv = khc_read_int32(csp_params, L"MaxRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_max = t; + + rv = khc_read_int32(csp_params, L"MinRenewLifetime", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew_min = t; + + khui_tracker_initialize(&d->tc_life); + d->tc_life.current = d->life; + d->tc_life.min = 0; + d->tc_life.max = 3600 * 24 * 7; + + khui_tracker_initialize(&d->tc_renew); + d->tc_renew.current = d->renew_life; + d->tc_renew.min = 0; + d->tc_renew.max = 3600 * 24 * 30; + + khui_tracker_initialize(&d->tc_life_min); + d->tc_life_min.current = d->life_min; + d->tc_life_min.min = d->tc_life.min; + d->tc_life_min.max = d->tc_life.max; + + khui_tracker_initialize(&d->tc_life_max); + d->tc_life_max.current = d->life_max; + d->tc_life_max.min = d->tc_life.min; + d->tc_life_max.max = d->tc_life.max; + + khui_tracker_initialize(&d->tc_renew_min); + d->tc_renew_min.current = d->renew_min; + d->tc_renew_min.min = d->tc_renew.min; + d->tc_renew_min.max = d->tc_renew.max; + + khui_tracker_initialize(&d->tc_renew_max); + d->tc_renew_max.current = d->renew_max; + d->tc_renew_max.min = d->tc_renew.min; + d->tc_renew_max.max = d->tc_renew.max; +} + +INT_PTR CALLBACK +k5_ids_tab_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_ids_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + d->cfg = *((khui_config_init_data *) lParam); + + k5_ids_read_params(d); + + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFLIFE), + &d->tc_life); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_DEFRLIFE), + &d->tc_renew); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MIN), + &d->tc_life_min); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_LRNG_MAX), + &d->tc_life_max); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MIN), + &d->tc_renew_min); + khui_tracker_install(GetDlgItem(hwnd, IDC_CFG_RLRNG_MAX), + &d->tc_renew_max); + khui_tracker_refresh(&d->tc_life); + khui_tracker_refresh(&d->tc_life_min); + khui_tracker_refresh(&d->tc_life_max); + khui_tracker_refresh(&d->tc_renew); + khui_tracker_refresh(&d->tc_renew_min); + khui_tracker_refresh(&d->tc_renew_max); + break; + + case WM_COMMAND: + d = (k5_ids_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == EN_CHANGE) { + k5_ids_check_mod(d); + } + break; + + case KHUI_WM_CFG_NOTIFY: + d = (k5_ids_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + if (HIWORD(wParam) == WMCFG_APPLY) { + k5_ids_write_params(d); + } + break; + + case WM_DESTROY: + d = (k5_ids_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + khui_tracker_kill_controls(&d->tc_life); + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_life_min); + khui_tracker_kill_controls(&d->tc_life_max); + khui_tracker_kill_controls(&d->tc_renew_min); + khui_tracker_kill_controls(&d->tc_renew_max); + + PFREE(d); + break; + } + return FALSE; +} + diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5funcs.c b/mechglue/src/windows/identity/plugins/krb5/krb5funcs.c new file mode 100644 index 000000000..5c076951a --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5funcs.c @@ -0,0 +1,2042 @@ +/* +* Copyright (c) 2005 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +/* Originally this was krb5routines.c in Leash sources. Subsequently +modified and adapted for NetIDMgr */ + +#include +#include + +#define SECURITY_WIN32 +#include +#include + +#include +#include +#include +#include + +long +khm_convert524(krb5_context alt_ctx) +{ + krb5_context ctx = 0; + krb5_error_code code = 0; + int icode = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds *v5creds = 0; + krb5_creds increds; + krb5_ccache cc = 0; + CREDENTIALS * v4creds = NULL; + static int init_ets = 1; + + if (!pkrb5_init_context || + !pkrb_in_tkt || + !pkrb524_init_ets || + !pkrb524_convert_creds_kdc) + return 0; + + v4creds = (CREDENTIALS *) PMALLOC(sizeof(CREDENTIALS)); + memset((char *) v4creds, 0, sizeof(CREDENTIALS)); + + memset((char *) &increds, 0, sizeof(increds)); + /* + From this point on, we can goto cleanup because increds is + initialized. + */ + + if (alt_ctx) + { + ctx = alt_ctx; + } + else + { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + + if ( init_ets ) { + pkrb524_init_ets(ctx); + init_ets = 0; + } + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + if ((code = pkrb5_build_principal(ctx, + &server, + krb5_princ_realm(ctx, me)->length, + krb5_princ_realm(ctx, me)->data, + "krbtgt", + krb5_princ_realm(ctx, me)->data, + NULL))) + { + goto cleanup; + } + + increds.client = me; + increds.server = server; + increds.times.endtime = 0; + increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + if ((code = pkrb5_get_credentials(ctx, 0, + cc, + &increds, + &v5creds))) + { + goto cleanup; + } + + if ((icode = pkrb524_convert_creds_kdc(ctx, + v5creds, + v4creds))) + { + goto cleanup; + } + + /* initialize ticket cache */ + if ((icode = pkrb_in_tkt(v4creds->pname, v4creds->pinst, v4creds->realm) + != KSUCCESS)) + { + goto cleanup; + } + /* stash ticket, session key, etc. for future use */ + if ((icode = pkrb_save_credentials(v4creds->service, + v4creds->instance, + v4creds->realm, + v4creds->session, + v4creds->lifetime, + v4creds->kvno, + &(v4creds->ticket_st), + v4creds->issue_date))) + { + goto cleanup; + } + +cleanup: + memset(v4creds, 0, sizeof(v4creds)); + PFREE(v4creds); + + if (v5creds) { + pkrb5_free_creds(ctx, v5creds); + } + if (increds.client == me) + me = 0; + if (increds.server == server) + server = 0; + pkrb5_free_cred_contents(ctx, &increds); + if (server) { + pkrb5_free_principal(ctx, server); + } + if (me) { + pkrb5_free_principal(ctx, me); + } + pkrb5_cc_close(ctx, cc); + + if (ctx && (ctx != alt_ctx)) { + pkrb5_free_context(ctx); + } + return !(code || icode); +} + +#ifdef DEPRECATED_REMOVABLE +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; + // char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + StringCbCopyA(loc_addr, sizeof(loc_addr), inet_ntoa(LocAddr)); + if ( strcmp(cred.address, loc_addr) != 0) { + /* TODO: do something about this */ + //Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} +#endif + +#ifndef ENCTYPE_LOCAL_RC4_MD4 +#define ENCTYPE_LOCAL_RC4_MD4 0xFFFFFF80 +#endif + +static long get_tickets_from_cache(krb5_context ctx, + krb5_ccache cache) +{ + krb5_error_code code; + krb5_principal KRBv5Principal; + krb5_flags flags = 0; + krb5_cc_cursor KRBv5Cursor; + krb5_creds KRBv5Credentials; + krb5_ticket *tkt=NULL; + char *ClientName; + char *PrincipalName; + wchar_t wbuf[256]; /* temporary conversion buffer */ + wchar_t wcc_name[KRB5_MAXCCH_CCNAME]; /* credential cache name */ + char *sServerName; + khm_handle ident = NULL; + khm_handle cred = NULL; + time_t tt; + FILETIME ft, eft; + khm_int32 ti; + + +#ifdef KRB5_TC_NOTICKET + flags = KRB5_TC_NOTICKET; +#else + flags = 0; +#endif + + { + const char * cc_name; + const char * cc_type; + + cc_name = (*pkrb5_cc_get_name)(ctx, cache); + if(cc_name) { + cc_type = (*pkrb5_cc_get_type)(ctx, cache); + if (cc_type) { + StringCbPrintf(wcc_name, sizeof(wcc_name), L"%S:%S", cc_type, cc_name); + } else { + AnsiStrToUnicode(wcc_name, sizeof(wcc_name), cc_name); + khm_krb5_canon_cc_name(wcc_name, sizeof(wcc_name)); + } + } else { + cc_type = (*pkrb5_cc_get_type)(ctx, cache); + if (cc_type) { + StringCbPrintf(wcc_name, sizeof(wcc_name), L"%S:", cc_type); + } else { +#ifdef DEBUG + assert(FALSE); +#endif + StringCbCopy(wcc_name, sizeof(wcc_name), L""); + } + } + } + + if ((code = (*pkrb5_cc_set_flags)(ctx, cache, flags))) + { + if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) + khm_krb5_error(code, "krb5_cc_set_flags()", 0, &ctx, &cache); + + goto _exit; + } + + if ((code = (*pkrb5_cc_get_principal)(ctx, cache, &KRBv5Principal))) + { + if (code != KRB5_FCC_NOFILE && code != KRB5_CC_NOTFOUND) + khm_krb5_error(code, "krb5_cc_get_principal()", 0, &ctx, &cache); + + goto _exit; + } + + PrincipalName = NULL; + ClientName = NULL; + sServerName = NULL; + if ((code = (*pkrb5_unparse_name)(ctx, KRBv5Principal, + (char **)&PrincipalName))) + { + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + goto _exit; + } + + if (!strcspn(PrincipalName, "@" )) + { + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + goto _exit; + } + + AnsiStrToUnicode(wbuf, sizeof(wbuf), PrincipalName); + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, + &ident))) { + /* something bad happened */ + code = 1; + goto _exit; + } + + (*pkrb5_free_principal)(ctx, KRBv5Principal); + + if ((code = (*pkrb5_cc_start_seq_get)(ctx, cache, &KRBv5Cursor))) + { + goto _exit; + } + + memset(&KRBv5Credentials, '\0', sizeof(KRBv5Credentials)); + + ClientName = NULL; + sServerName = NULL; + cred = NULL; + + while (!(code = pkrb5_cc_next_cred(ctx, cache, &KRBv5Cursor, + &KRBv5Credentials))) + { + khm_handle tident = NULL; + khm_int32 cred_flags = 0; + + if(ClientName != NULL) + (*pkrb5_free_unparsed_name)(ctx, ClientName); + if(sServerName != NULL) + (*pkrb5_free_unparsed_name)(ctx, sServerName); + if(cred) + kcdb_cred_release(cred); + + ClientName = NULL; + sServerName = NULL; + cred = NULL; + + if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.client, &ClientName)) + { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); + continue; + } + + if ((*pkrb5_unparse_name)(ctx, KRBv5Credentials.server, &sServerName)) + { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + khm_krb5_error(code, "krb5_free_cred_contents()", 0, &ctx, &cache); + continue; + } + + /* if the ClientName differs from PrincipalName for some + reason, we need to create a new identity */ + if(strcmp(ClientName, PrincipalName)) { + AnsiStrToUnicode(wbuf, sizeof(wbuf), ClientName); + if(KHM_FAILED(kcdb_identity_create(wbuf, KCDB_IDENT_FLAG_CREATE, + &tident))) { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + continue; + } + } else { + tident = ident; + } + + AnsiStrToUnicode(wbuf, sizeof(wbuf), sServerName); + if(KHM_FAILED(kcdb_cred_create(wbuf, tident, credtype_id_krb5, + &cred))) { + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + continue; + } + + if (!KRBv5Credentials.times.starttime) + KRBv5Credentials.times.starttime = KRBv5Credentials.times.authtime; + + tt = KRBv5Credentials.times.starttime; + TimetToFileTime(tt, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft)); + + tt = KRBv5Credentials.times.endtime; + TimetToFileTime(tt, &eft); + kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &eft, sizeof(eft)); + + { + FILETIME ftl; + + ftl = FtSub(&eft, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_LIFETIME, &ftl, sizeof(ftl)); + } + + if (KRBv5Credentials.times.renew_till > 0) { + FILETIME ftl; + + tt = KRBv5Credentials.times.renew_till; + TimetToFileTime(tt, &eft); + kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_EXPIRE, &eft, + sizeof(eft)); + + + ftl = FtSub(&eft, &ft); + kcdb_cred_set_attr(cred, KCDB_ATTR_RENEW_LIFETIME, &ftl, + sizeof(ftl)); + } + + ti = KRBv5Credentials.ticket_flags; + kcdb_cred_set_attr(cred, attr_id_krb5_flags, &ti, sizeof(ti)); + + /* special flags understood by NetIDMgr */ + { + khm_int32 nflags = 0; + + if (ti & TKT_FLG_RENEWABLE) + nflags |= KCDB_CRED_FLAG_RENEWABLE; + if (ti & TKT_FLG_INITIAL) + nflags |= KCDB_CRED_FLAG_INITIAL; + else { + krb5_data * c0, *c1, *r; + + /* these are macros that do not allocate any memory */ + c0 = krb5_princ_component(ctx,KRBv5Credentials.server,0); + c1 = krb5_princ_component(ctx,KRBv5Credentials.server,1); + r = krb5_princ_realm(ctx,KRBv5Credentials.server); + + if ( c0 && c1 && r && c1->length == r->length && + !strncmp(c1->data,r->data,r->length) && + !strncmp("krbtgt",c0->data,c0->length) ) + nflags |= KCDB_CRED_FLAG_INITIAL; + } + + kcdb_cred_set_flags(cred, nflags, KCDB_CRED_FLAGMASK_EXT); + + cred_flags = nflags; + } + + if ( !pkrb5_decode_ticket(&KRBv5Credentials.ticket, &tkt)) { + ti = tkt->enc_part.enctype; + kcdb_cred_set_attr(cred, attr_id_tkt_enctype, &ti, sizeof(ti)); + pkrb5_free_ticket(ctx, tkt); + tkt = NULL; + } + + ti = KRBv5Credentials.keyblock.enctype; + kcdb_cred_set_attr(cred, attr_id_key_enctype, &ti, sizeof(ti)); + kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, wcc_name, + KCDB_CBSIZE_AUTO); + + /*TODO: going here */ +#if 0 + if ( KRBv5Credentials.addresses && KRBv5Credentials.addresses[0] ) { + int n = 0; + while ( KRBv5Credentials.addresses[n] ) + n++; + list->addrList = PCALLOC(1, n * sizeof(char *)); + if (!list->addrList) { + MessageBox(NULL, "Memory Error", "Error", MB_OK); + return ENOMEM; + } + list->addrCount = n; + for ( n=0; naddrCount; n++ ) { + wsprintf(Buffer, "Address: %s", one_addr(KRBv5Credentials.addresses[n])); + list->addrList[n] = (char*) PCALLOC(1, strlen(Buffer)+1); + if (!list->addrList[n]) + { + MessageBox(NULL, "Memory Error", "Error", MB_OK); + return ENOMEM; + } + strcpy(list->addrList[n], Buffer); + } + } +#endif + + if(cred_flags & KCDB_CRED_FLAG_INITIAL) { + FILETIME ft_issue_new; + FILETIME ft_expire_old; + FILETIME ft_expire_new; + khm_size cb; + + /* an initial ticket! If we find one, we generally set + the lifetime, and primary ccache based on this, but + only if this initial cred has a greater lifetime than + the current primary credential. */ + + tt = KRBv5Credentials.times.endtime; + TimetToFileTime(tt, &ft_expire_new); + + tt = KRBv5Credentials.times.starttime; + TimetToFileTime(tt, &ft_issue_new); + + cb = sizeof(ft_expire_old); + if(KHM_FAILED(kcdb_identity_get_attr(tident, + KCDB_ATTR_EXPIRE, + NULL, &ft_expire_old, + &cb)) + || CompareFileTime(&ft_expire_new, &ft_expire_old) > 0) { + + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + wcc_name, KCDB_CBSIZE_AUTO); + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, + &ft_expire_new, + sizeof(ft_expire_new)); + kcdb_identity_set_attr(tident, KCDB_ATTR_ISSUE, + &ft_issue_new, + sizeof(ft_issue_new)); + + if (KRBv5Credentials.times.renew_till > 0) { + tt = KRBv5Credentials.times.renew_till; + TimetToFileTime(tt, &ft); + kcdb_identity_set_attr(tident, + KCDB_ATTR_RENEW_EXPIRE, + &ft, sizeof(ft)); + } else { + kcdb_identity_set_attr(tident, + KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } + + ti = KRBv5Credentials.ticket_flags; + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + &ti, sizeof(ti)); + } + } + + kcdb_credset_add_cred(krb5_credset, cred, -1); + + (*pkrb5_free_cred_contents)(ctx, &KRBv5Credentials); + + if(tident != ident) + kcdb_identity_release(tident); + } + + if (PrincipalName != NULL) + (*pkrb5_free_unparsed_name)(ctx, PrincipalName); + + if (ClientName != NULL) + (*pkrb5_free_unparsed_name)(ctx, ClientName); + + if (sServerName != NULL) + (*pkrb5_free_unparsed_name)(ctx, sServerName); + + if (cred) + kcdb_cred_release(cred); + + if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND)) + { + if ((code = pkrb5_cc_end_seq_get(ctx, cache, &KRBv5Cursor))) + { + goto _exit; + } + + flags = KRB5_TC_OPENCLOSE; +#ifdef KRB5_TC_NOTICKET + flags |= KRB5_TC_NOTICKET; +#endif + if ((code = pkrb5_cc_set_flags(ctx, cache, flags))) + { + goto _exit; + } + } + else + { + goto _exit; + } + +_exit: + + return code; +} + +long +khm_krb5_list_tickets(krb5_context *krbv5Context) +{ + krb5_context ctx; + krb5_ccache cache = 0; + krb5_error_code code; + apiCB * cc_ctx = 0; + struct _infoNC ** pNCi = NULL; + int i; + khm_int32 t; + wchar_t * ms = NULL; + khm_size cb; + + ctx = NULL; + cache = NULL; + + kcdb_credset_flush(krb5_credset); + + code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); + if (code) + goto _exit; + + code = pcc_get_NC_info(cc_ctx, &pNCi); + if (code) + goto _exit; + + if((*krbv5Context == 0) && (code = (*pkrb5_init_context)(krbv5Context))) { + goto _exit; + } + + ctx = (*krbv5Context); + + for(i=0; pNCi[i]; i++) { + if (pNCi[i]->vers != CC_CRED_V5) + continue; + + code = (*pkrb5_cc_resolve)(ctx, pNCi[i]->name, &cache); + + if (code) + continue; + + code = get_tickets_from_cache(ctx, cache); + + if(ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + + cache = 0; + } + + if (KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) { + code = (*pkrb5_cc_resolve)(ctx, "MSLSA:", &cache); + + if (code == 0 && cache) { + code = get_tickets_from_cache(ctx, cache); + } + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + + if (khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb) + == KHM_ERROR_TOO_LONG && + cb > sizeof(wchar_t) * 2) { + wchar_t * t; + char ccname[MAX_PATH + 6]; + + ms = PMALLOC(cb); +#ifdef DEBUG + assert(ms); +#endif + khc_read_multi_string(csp_params, L"FileCCList", ms, &cb); + + for(t = ms; t && *t; t = multi_string_next(t)) { + StringCchPrintfA(ccname, ARRAYLENGTH(ccname), + "FILE:%S", t); + + code = (*pkrb5_cc_resolve)(ctx, ccname, &cache); + + if (code) + continue; + + code = get_tickets_from_cache(ctx, cache); + + if (ctx != NULL && cache != NULL) + (*pkrb5_cc_close)(ctx, cache); + cache = 0; + } + + PFREE(ms); + } + +_exit: + if (pNCi) + (*pcc_free_NC_info)(cc_ctx, &pNCi); + if (cc_ctx) + (*pcc_shutdown)(&cc_ctx); + + kcdb_credset_collect(NULL, krb5_credset, NULL, credtype_id_krb5, NULL); + + return(code); +} + +int +khm_krb5_renew(khm_handle identity) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds my_creds; + krb5_data *realm = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + memset(&my_creds, 0, sizeof(krb5_creds)); + + code = khm_krb5_initialize(identity, &ctx, &cc); + if (code) + goto cleanup; + + code = pkrb5_cc_get_principal(ctx, cc, &me); + if (code) + goto cleanup; + + realm = krb5_princ_realm(ctx, me); + + code = pkrb5_build_principal_ext(ctx, &server, + realm->length,realm->data, + KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, + realm->length,realm->data, + 0); + + if (code) + goto cleanup; + + my_creds.client = me; + my_creds.server = server; + +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, 0); +#endif + code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); +#ifdef KRB5_TC_NOTICKET + pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET); +#endif + if (code) { + if ( code != KRB5KDC_ERR_ETYPE_NOSUPP || + code != KRB5_KDC_UNREACH) + khm_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc); + goto cleanup; + } + + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) goto cleanup; + + code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + if (code) goto cleanup; + +cleanup: + if (my_creds.client == me) + my_creds.client = 0; + if (my_creds.server == server) + my_creds.server = 0; + + pkrb5_free_cred_contents(ctx, &my_creds); + + if (me) + pkrb5_free_principal(ctx, me); + if (server) + pkrb5_free_principal(ctx, server); + if (cc) + pkrb5_cc_close(ctx, cc); + if (ctx) + pkrb5_free_context(ctx); + return(code); +} + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + char * ccache, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + char* name = 0; + krb5_creds my_creds; + krb5_get_init_creds_opt options; + krb5_address ** addrs = NULL; + int i = 0, addr_count = 0; + + if (!pkrb5_init_context) + return 0; + + pkrb5_get_init_creds_opt_init(&options); + memset(&my_creds, 0, sizeof(my_creds)); + + if (alt_ctx) + { + ctx = alt_ctx; + } + else + { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + +// code = pkrb5_cc_default(ctx, &cc); + if (ccache) + code = pkrb5_cc_resolve(ctx, ccache, &cc); + else + code = pkrb5_cc_resolve(ctx, principal_name, &cc); + if (code) goto cleanup; + + code = pkrb5_parse_name(ctx, principal_name, &me); + if (code) goto cleanup; + + code = pkrb5_unparse_name(ctx, me, &name); + if (code) goto cleanup; + + if (lifetime == 0) { + khc_read_int32(csp_params, L"DefaultLifetime", &lifetime); + } + + if (lifetime) + pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime); + pkrb5_get_init_creds_opt_set_forwardable(&options, + forwardable ? 1 : 0); + pkrb5_get_init_creds_opt_set_proxiable(&options, + proxiable ? 1 : 0); + pkrb5_get_init_creds_opt_set_renew_life(&options, + renew_life); + if (addressless) + pkrb5_get_init_creds_opt_set_address_list(&options,NULL); + else { + if (publicIP) + { + // we are going to add the public IP address specified by the user + // to the list provided by the operating system + krb5_address ** local_addrs=NULL; + DWORD netIPAddr; + + pkrb5_os_localaddr(ctx, &local_addrs); + while ( local_addrs[i++] ); + addr_count = i + 1; + + addrs = (krb5_address **) PMALLOC((addr_count+1) * sizeof(krb5_address *)); + if ( !addrs ) { + pkrb5_free_addresses(ctx, local_addrs); + assert(0); + } + memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); + i = 0; + while ( local_addrs[i] ) { + addrs[i] = (krb5_address *)PMALLOC(sizeof(krb5_address)); + if (addrs[i] == NULL) { + pkrb5_free_addresses(ctx, local_addrs); + assert(0); + } + + addrs[i]->magic = local_addrs[i]->magic; + addrs[i]->addrtype = local_addrs[i]->addrtype; + addrs[i]->length = local_addrs[i]->length; + addrs[i]->contents = (unsigned char *)PMALLOC(addrs[i]->length); + if (!addrs[i]->contents) { + pkrb5_free_addresses(ctx, local_addrs); + assert(0); + } + + memcpy(addrs[i]->contents,local_addrs[i]->contents, + local_addrs[i]->length); /* safe */ + i++; + } + pkrb5_free_addresses(ctx, local_addrs); + + addrs[i] = (krb5_address *)PMALLOC(sizeof(krb5_address)); + if (addrs[i] == NULL) + assert(0); + + addrs[i]->magic = KV5M_ADDRESS; + addrs[i]->addrtype = AF_INET; + addrs[i]->length = 4; + addrs[i]->contents = (unsigned char *)PMALLOC(addrs[i]->length); + if (!addrs[i]->contents) + assert(0); + + netIPAddr = htonl(publicIP); + memcpy(addrs[i]->contents,&netIPAddr,4); + + pkrb5_get_init_creds_opt_set_address_list(&options,addrs); + + } + } + + code = pkrb5_get_init_creds_password(ctx, + &my_creds, + me, + password, // password + prompter, // prompter + p_data, // prompter data + 0, // start time + 0, // service name + &options); + if (code) goto cleanup; + + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) goto cleanup; + + code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + if (code) goto cleanup; + +cleanup: + if ( addrs ) { + for ( i=0;icontents ) + PFREE(addrs[i]->contents); + PFREE(addrs[i]); + } + } + } + if (my_creds.client == me) + my_creds.client = 0; + pkrb5_free_cred_contents(ctx, &my_creds); + if (name) + pkrb5_free_unparsed_name(ctx, name); + if (me) + pkrb5_free_principal(ctx, me); + if (cc) + pkrb5_cc_close(ctx, cc); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + return(code); +} + +long +khm_krb5_copy_ccache_by_name(krb5_context in_ctx, + wchar_t * wscc_dest, + wchar_t * wscc_src) { + krb5_context ctx = NULL; + krb5_error_code code = 0; + khm_boolean free_ctx; + krb5_ccache cc_src = NULL; + krb5_ccache cc_dest = NULL; + krb5_principal princ_src = NULL; + char scc_dest[KRB5_MAXCCH_CCNAME]; + char scc_src[KRB5_MAXCCH_CCNAME]; + int t; + + t = UnicodeStrToAnsi(scc_dest, sizeof(scc_dest), wscc_dest); + if (t == 0) + return KHM_ERROR_TOO_LONG; + t = UnicodeStrToAnsi(scc_src, sizeof(scc_src), wscc_src); + if (t == 0) + return KHM_ERROR_TOO_LONG; + + if (in_ctx) { + ctx = in_ctx; + free_ctx = FALSE; + } else { + code = pkrb5_init_context(&ctx); + if (code) { + if (ctx) + pkrb5_free_context(ctx); + return code; + } + free_ctx = TRUE; + } + + code = pkrb5_cc_resolve(ctx, scc_dest, &cc_dest); + if (code) + goto _cleanup; + + code = pkrb5_cc_resolve(ctx, scc_src, &cc_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_get_principal(ctx, cc_src, &princ_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_initialize(ctx, cc_dest, princ_src); + if (code) + goto _cleanup; + + code = pkrb5_cc_copy_creds(ctx, cc_src, cc_dest); + + _cleanup: + if (princ_src) + pkrb5_free_principal(ctx, princ_src); + + if (cc_dest) + pkrb5_cc_close(ctx, cc_dest); + + if (cc_src) + pkrb5_cc_close(ctx, cc_src); + + if (free_ctx && ctx) + pkrb5_free_context(ctx); + + return code; +} + +long +khm_krb5_canon_cc_name(wchar_t * wcc_name, + size_t cb_cc_name) { + size_t cb_len; + wchar_t * colon; + + if (FAILED(StringCbLength(wcc_name, + cb_cc_name, + &cb_len))) { +#ifdef DEBUG + assert(FALSE); +#else + return KHM_ERROR_TOO_LONG; +#endif + } + + cb_len += sizeof(wchar_t); + + colon = wcschr(wcc_name, L':'); + + if (colon) { + /* if the colon is just 1 character away from the beginning, + it's a FILE: cc */ + if (colon - wcc_name == 1) { + if (cb_len + 5 * sizeof(wchar_t) > cb_cc_name) + return KHM_ERROR_TOO_LONG; + + memmove(&wcc_name[5], &wcc_name[0], cb_len); + memmove(&wcc_name[0], L"FILE:", sizeof(wchar_t) * 5); + } + + return 0; + } + + if (cb_len + 4 * sizeof(wchar_t) > cb_cc_name) + return KHM_ERROR_TOO_LONG; + + memmove(&wcc_name[4], &wcc_name[0], cb_len); + memmove(&wcc_name[0], L"API:", sizeof(wchar_t) * 4); + + return 0; +} + +int +khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, + const wchar_t * cc_name_2) { + if (!wcsncmp(cc_name_1, L"API:", 4)) + cc_name_1 += 4; + + if (!wcsncmp(cc_name_2, L"API:", 4)) + cc_name_2 += 4; + + return wcscmp(cc_name_1, cc_name_2); +} + +static khm_int32 KHMAPI +khmint_location_comp_func(khm_handle cred1, + khm_handle cred2, + void * rock) { + return kcdb_creds_comp_attr(cred1, cred2, KCDB_ATTR_LOCATION); +} + +struct khmint_location_check { + khm_handle credset; + khm_handle cred; + wchar_t * ccname; + khm_boolean success; +}; + +static khm_int32 KHMAPI +khmint_find_matching_cred_func(khm_handle cred, + void * rock) { + struct khmint_location_check * lc; + + lc = (struct khmint_location_check *) rock; + + if (!kcdb_creds_is_equal(cred, lc->cred)) + return KHM_ERROR_SUCCESS; + if (kcdb_creds_comp_attr(cred, lc->cred, KCDB_ATTR_LOCATION)) + return KHM_ERROR_SUCCESS; + + /* found it */ + lc->success = TRUE; + + /* break the search */ + return !KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +khmint_location_check_func(khm_handle cred, + void * rock) { + khm_int32 t; + khm_size cb; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check * lc; + + lc = (struct khmint_location_check *) rock; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &t))) + return KHM_ERROR_SUCCESS; + + if (t != credtype_id_krb5) + return KHM_ERROR_SUCCESS; + + cb = sizeof(ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) + return KHM_ERROR_SUCCESS; + + if(wcscmp(ccname, lc->ccname)) + return KHM_ERROR_SUCCESS; + + lc->cred = cred; + + lc->success = FALSE; + + kcdb_credset_apply(lc->credset, + khmint_find_matching_cred_func, + (void *) lc); + + if (!lc->success) + return KHM_ERROR_NOT_FOUND; + else + return KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +khmint_delete_location_func(khm_handle cred, + void * rock) { + wchar_t cc_cred[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check * lc; + khm_size cb; + + lc = (struct khmint_location_check *) rock; + + cb = sizeof(cc_cred); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + cc_cred, + &cb))) + return KHM_ERROR_SUCCESS; + + if (wcscmp(cc_cred, lc->ccname)) + return KHM_ERROR_SUCCESS; + + kcdb_credset_del_cred_ref(lc->credset, + cred); + + return KHM_ERROR_SUCCESS; +} + +int +khm_krb5_destroy_by_credset(khm_handle p_cs) +{ + khm_handle d_cs = NULL; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_size s, cb; + krb5_context ctx; + krb5_error_code code = 0; + int i; + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + struct khmint_location_check lc; + + rv = kcdb_credset_create(&d_cs); + + assert(KHM_SUCCEEDED(rv) && d_cs != NULL); + + kcdb_credset_extract(d_cs, p_cs, NULL, credtype_id_krb5); + + kcdb_credset_get_size(d_cs, &s); + + if (s == 0) { + /* nothing to do */ + kcdb_credset_delete(d_cs); + return 0; + } + + code = pkrb5_init_context(&ctx); + if (code != 0) { + rv = code; + goto _cleanup; + } + + /* we should synchronize the credential lists before we attempt to + make any assumptions on the state of the root credset */ + khm_krb5_list_tickets(&ctx); + + /* so, we need to make a decision about whether to destroy entire + ccaches or just individual credentials. Therefore we first + sort them by ccache. */ + kcdb_credset_sort(d_cs, + khmint_location_comp_func, + NULL); + + /* now, for each ccache we encounter, we check if we have all the + credentials from that ccache in the to-be-deleted list. */ + for (i=0; i < (int) s; i++) { + khm_handle cred; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + + cb = sizeof(ccname); + rv = kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb); + +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + kcdb_cred_release(cred); + + lc.credset = d_cs; + lc.cred = NULL; + lc.ccname = ccname; + lc.success = FALSE; + + kcdb_credset_apply(NULL, + khmint_location_check_func, + (void *) &lc); + + if (lc.success) { + /* ok the destroy the ccache */ + char a_ccname[KRB5_MAXCCH_CCNAME]; + krb5_ccache cc = NULL; + + UnicodeStrToAnsi(a_ccname, + sizeof(a_ccname), + ccname); + + code = pkrb5_cc_resolve(ctx, + a_ccname, + &cc); + if (code) + goto _delete_this_set; + + code = pkrb5_cc_destroy(ctx, cc); + + if (code) { + /*TODO: report error */ + } + + _delete_this_set: + + lc.credset = d_cs; + lc.ccname = ccname; + + /* note that although we are deleting credentials off the + credential set, the size of the credential set does not + decrease since we are doing it from inside + kcdb_credset_apply(). The deleted creds will simply be + marked as deleted until kcdb_credset_purge() is + called. */ + + kcdb_credset_apply(d_cs, + khmint_delete_location_func, + (void *) &lc); + } + } + + kcdb_credset_purge(d_cs); + + /* the remainder need to be deleted one by one */ + + kcdb_credset_get_size(d_cs, &s); + + for (i=0; i < (int) s; ) { + khm_handle cred; + char a_ccname[KRB5_MAXCCH_CCNAME]; + char a_srvname[KCDB_CRED_MAXCCH_NAME]; + wchar_t srvname[KCDB_CRED_MAXCCH_NAME]; + krb5_ccache cc; + krb5_creds in_cred, out_cred; + krb5_principal princ; + khm_int32 etype; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) { + i++; + continue; + } + + cb = sizeof(ccname); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) + goto _done_with_this_cred; + + UnicodeStrToAnsi(a_ccname, + sizeof(a_ccname), + ccname); + + code = pkrb5_cc_resolve(ctx, + a_ccname, + &cc); + + if (code) + goto _skip_similar; + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + + if (code) { + pkrb5_cc_close(ctx, cc); + goto _skip_similar; + } + + _del_this_cred: + + cb = sizeof(etype); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + attr_id_key_enctype, + NULL, + &etype, + &cb))) + goto _do_next_cred; + + cb = sizeof(srvname); + if (KHM_FAILED(kcdb_cred_get_name(cred, + srvname, + &cb))) + goto _do_next_cred; + + UnicodeStrToAnsi(a_srvname, sizeof(a_srvname), srvname); + + ZeroMemory(&in_cred, sizeof(in_cred)); + + code = pkrb5_parse_name(ctx, a_srvname, &in_cred.server); + if (code) + goto _do_next_cred; + in_cred.client = princ; + in_cred.keyblock.enctype = etype; + + code = pkrb5_cc_retrieve_cred(ctx, + cc, + KRB5_TC_MATCH_SRV_NAMEONLY | + KRB5_TC_SUPPORTED_KTYPES, + &in_cred, + &out_cred); + if (code) + goto _do_next_cred_0; + + code = pkrb5_cc_remove_cred(ctx, cc, + KRB5_TC_MATCH_SRV_NAMEONLY | + KRB5_TC_SUPPORTED_KTYPES | + KRB5_TC_MATCH_AUTHDATA, + &out_cred); + + pkrb5_free_cred_contents(ctx, &out_cred); + _do_next_cred_0: + pkrb5_free_principal(ctx, in_cred.server); + _do_next_cred: + + /* check if the next cred is also of the same ccache */ + kcdb_cred_release(cred); + + for (i++; i < (int) s; i++) { + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + } + + if (i < (int) s) { + wchar_t newcc[KRB5_MAXCCH_CCNAME]; + + cb = sizeof(newcc); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + newcc, + &cb)) || + wcscmp(newcc, ccname)) { + i--; /* we have to look at this again */ + goto _done_with_this_set; + } + goto _del_this_cred; + } + + + _done_with_this_set: + pkrb5_free_principal(ctx, princ); + + pkrb5_cc_close(ctx, cc); + + _done_with_this_cred: + kcdb_cred_release(cred); + i++; + continue; + + _skip_similar: + kcdb_cred_release(cred); + + for (++i; i < (int) s; i++) { + wchar_t newcc[KRB5_MAXCCH_CCNAME]; + + if (KHM_FAILED(kcdb_credset_get_cred(d_cs, + i, + &cred))) + continue; + + cb = sizeof(newcc); + if (KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_LOCATION, + NULL, + &newcc, + &cb))) { + kcdb_cred_release(cred); + continue; + } + + if (wcscmp(newcc, ccname)) { + kcdb_cred_release(cred); + break; + } + } + } + + _cleanup: + + if (d_cs) + kcdb_credset_delete(&d_cs); + + return rv; +} + +int +khm_krb5_destroy_identity(khm_handle identity) +{ + krb5_context ctx; + krb5_ccache cache; + krb5_error_code rc; + + ctx = NULL; + cache = NULL; + + if (rc = khm_krb5_initialize(identity, &ctx, &cache)) + return(rc); + + rc = pkrb5_cc_destroy(ctx, cache); + + if (ctx != NULL) + pkrb5_free_context(ctx); + + return(rc); +} + +static BOOL +GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; + HANDLE TokenHandle; + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData) + return FALSE; + *ppSessionData = NULL; + + Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); + if ( !Success ) + return FALSE; + + Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); + CloseHandle( TokenHandle ); + if ( !Success ) + return FALSE; + + Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); + if ( FAILED(Status) || !ppSessionData ) + return FALSE; + + return TRUE; +} + +// IsKerberosLogon() does not validate whether or not there are valid +// tickets in the cache. It validates whether or not it is reasonable +// to assume that if we attempted to retrieve valid tickets we could +// do so. Microsoft does not automatically renew expired tickets. +// Therefore, the cache could contain expired or invalid tickets. +// Microsoft also caches the user's password and will use it to +// retrieve new TGTs if the cache is empty and tickets are requested. + +static BOOL +IsKerberosLogon(VOID) +{ + PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; + BOOL Success = FALSE; + + if ( GetSecurityLogonSessionData(&pSessionData) ) { + if ( pSessionData->AuthenticationPackage.Buffer ) { + WCHAR buffer[256]; + WCHAR *usBuffer; + int usLength; + + Success = FALSE; + usBuffer = (pSessionData->AuthenticationPackage).Buffer; + usLength = (pSessionData->AuthenticationPackage).Length; + if (usLength < 256) + { + lstrcpynW (buffer, usBuffer, usLength); + StringCbCatW (buffer, sizeof(buffer), L""); + if ( !lstrcmpW(L"Kerberos",buffer) ) + Success = TRUE; + } + } + pLsaFreeReturnBuffer(pSessionData); + } + return Success; +} + + +BOOL +khm_krb5_ms2mit(BOOL save_creds) +{ +#ifdef NO_KRB5 + return(FALSE); +#else /* NO_KRB5 */ + krb5_context kcontext = 0; + krb5_error_code code; + krb5_ccache ccache=0; + krb5_ccache mslsa_ccache=0; + krb5_creds creds; + krb5_cc_cursor cursor=0; + krb5_principal princ = 0; + char *cache_name = NULL; + char *princ_name = NULL; + BOOL rc = FALSE; + + kherr_reportf(L"Begin : khm_krb5_ms2mit. save_cred=%d\n", (int) save_creds); + + if ( !pkrb5_init_context ) + goto cleanup; + + if (code = pkrb5_init_context(&kcontext)) + goto cleanup; + + kherr_reportf(L"Resolving MSLSA\n"); + + if (code = pkrb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) + goto cleanup; + + if ( save_creds ) { + kherr_reportf(L"Getting principal\n"); + if (code = pkrb5_cc_get_principal(kcontext, mslsa_ccache, &princ)) + goto cleanup; + + kherr_reportf(L"Unparsing name\n"); + if (code = pkrb5_unparse_name(kcontext, princ, &princ_name)) + goto cleanup; + + kherr_reportf(L"Unparsed [%S]. Resolving target cache\n", princ_name); + /* TODO: actually look up the preferred ccache name */ + if (code = pkrb5_cc_resolve(kcontext, princ_name, &ccache)) { + kherr_reportf(L"Cannot resolve cache [%S] with code=%d. Trying default.\n", princ_name, code); + + if (code = pkrb5_cc_default(kcontext, &ccache)) { + kherr_reportf(L"Failed to resolve default ccache. Code=%d", code); + goto cleanup; + } + } + + kherr_reportf(L"Initializing ccache\n"); + if (code = pkrb5_cc_initialize(kcontext, ccache, princ)) + goto cleanup; + + kherr_reportf(L"Copying credentials\n"); + if (code = pkrb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) + goto cleanup; + + rc = TRUE; + } else { + /* Enumerate tickets from cache looking for an initial ticket */ + if ((code = pkrb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) + goto cleanup; + + while (!(code = pkrb5_cc_next_cred(kcontext, mslsa_ccache, + &cursor, &creds))) { + if ( creds.ticket_flags & TKT_FLG_INITIAL ) { + rc = TRUE; + pkrb5_free_cred_contents(kcontext, &creds); + break; + } + pkrb5_free_cred_contents(kcontext, &creds); + } + pkrb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor); + } + +cleanup: + kherr_reportf(L" Received code=%d", code); + + if (princ_name) + pkrb5_free_unparsed_name(kcontext, princ_name); + if (princ) + pkrb5_free_principal(kcontext, princ); + if (ccache) + pkrb5_cc_close(kcontext, ccache); + if (mslsa_ccache) + pkrb5_cc_close(kcontext, mslsa_ccache); + if (kcontext) + pkrb5_free_context(kcontext); + return(rc); +#endif /* NO_KRB5 */ +} + +#define KRB_FILE "KRB.CON" +#define KRBREALM_FILE "KRBREALM.CON" +#define KRB5_FILE "KRB5.INI" +#define KRB5_TMP_FILE "KRB5.INI.TMP" + +BOOL +khm_krb5_get_temp_profile_file(LPSTR confname, UINT szConfname) +{ + GetTempPathA(szConfname, confname); + confname[szConfname-1] = '\0'; + StringCchCatA(confname, szConfname, KRB5_TMP_FILE); + confname[szConfname-1] = '\0'; + return FALSE; +} + +BOOL +khm_krb5_get_profile_file(LPSTR confname, UINT szConfname) +{ + char **configFile = NULL; + if (pkrb5_get_default_config_files(&configFile)) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + return FALSE; + } + + *confname = 0; + + if (configFile) + { + strncpy(confname, *configFile, szConfname); + pkrb5_free_config_files(configFile); + } + + if (!*confname) + { + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname, KRB5_FILE,sizeof(confname)-strlen(confname)); + confname[szConfname-1] = '\0'; + } + + return FALSE; +} + +BOOL +khm_get_krb4_con_file(LPSTR confname, UINT szConfname) +{ + if (hKrb5 && !hKrb4) { // hold krb.con where krb5.ini is located + CHAR krbConFile[MAX_PATH]=""; + LPSTR pFind; + + //strcpy(krbConFile, CLeashApp::m_krbv5_profile->first_file->filename); + if (khm_krb5_get_profile_file(krbConFile, sizeof(krbConFile))) { + GetWindowsDirectoryA(krbConFile,sizeof(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB5_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + + pFind = strrchr(krbConFile, '\\'); + if (pFind) { + *pFind = 0; + strncat(krbConFile, "\\",sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + strncat(krbConFile, KRB_FILE,sizeof(krbConFile)-strlen(krbConFile)); + krbConFile[MAX_PATH-1] = '\0'; + } + else + krbConFile[0] = 0; + + strncpy(confname, krbConFile, szConfname); + confname[szConfname-1] = '\0'; + } + else if (hKrb4) { + unsigned int size = szConfname; + memset(confname, '\0', szConfname); + if (!pkrb_get_krbconf2(confname, &size)) + { // Error has happened + GetWindowsDirectoryA(confname,szConfname); + confname[szConfname-1] = '\0'; + strncat(confname, "\\",szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + strncat(confname,KRB_FILE,szConfname-strlen(confname)); + confname[szConfname-1] = '\0'; + } + } + return FALSE; +} + +int +readstring(FILE * file, char * buf, int len) +{ + int c,i; + memset(buf, '\0', sizeof(buf)); + for (i=0, c=fgetc(file); c != EOF ; c=fgetc(file), i++) { + if (i < sizeof(buf)) { + if (c == '\n') { + buf[i] = '\0'; + return i; + } else { + buf[i] = c; + } + } else { + if (c == '\n') { + buf[len-1] = '\0'; + return(i); + } + } + } + if (c == EOF) { + if (i > 0 && i < len) { + buf[i] = '\0'; + return(i); + } else { + buf[len-1] = '\0'; + return(-1); + } + } + return(-1); +} + +/*! \internal + \brief Return a list of configured realms + + The string that is returned is a set of null terminated unicode + strings, each of which denotes one realm. The set is terminated + by a zero length null terminated string. + + The caller should free the returned string using free() + + \return The string with the list of realms or NULL if the + operation fails. +*/ +wchar_t * khm_krb5_get_realm_list(void) +{ + wchar_t * rlist = NULL; + + if (pprofile_get_subsection_names && pprofile_free_list) { + const char* rootSection[] = {"realms", NULL}; + const char** rootsec = rootSection; + char **sections = NULL, **cpp = NULL, *value = NULL; + + char krb5_conf[MAX_PATH+1]; + + if (!khm_krb5_get_profile_file(krb5_conf,sizeof(krb5_conf))) { + profile_t profile; + long retval; + const char *filenames[2]; + wchar_t * d; + size_t cbsize; + size_t t; + + filenames[0] = krb5_conf; + filenames[1] = NULL; + retval = pprofile_init(filenames, &profile); + if (!retval) { + retval = pprofile_get_subsection_names(profile, rootsec, + §ions); + + if (!retval) + { + /* first figure out how much space to allocate */ + cbsize = 0; + for (cpp = sections; *cpp; cpp++) + { + cbsize += sizeof(wchar_t) * (strlen(*cpp) + 1); + } + cbsize += sizeof(wchar_t); /* double null terminated */ + + rlist = PMALLOC(cbsize); + d = rlist; + for (cpp = sections; *cpp; cpp++) + { + AnsiStrToUnicode(d, cbsize, *cpp); + t = wcslen(d) + 1; + d += t; + cbsize -= sizeof(wchar_t) * t; + } + *d = L'\0'; + } + + pprofile_free_list(sections); + +#if 0 + retval = pprofile_get_string(profile, "libdefaults","noaddresses", 0, "true", &value); + if ( value ) { + disable_noaddresses = config_boolean_to_int(value); + pprofile_release_string(value); + } +#endif + pprofile_release(profile); + } + } + } else { + FILE * file; + char krb_conf[MAX_PATH+1]; + char * p; + size_t cbsize, t; + wchar_t * d; + + if (!khm_get_krb4_con_file(krb_conf,sizeof(krb_conf)) && + (file = fopen(krb_conf, "rt"))) + { + char lineBuf[256]; + + /*TODO: compute the actual required buffer size instead of hardcoding */ + cbsize = 16384; // arbitrary + rlist = PMALLOC(cbsize); + d = rlist; + + // Skip the default realm + readstring(file,lineBuf,sizeof(lineBuf)); + + // Read the defined realms + while (TRUE) + { + if (readstring(file,lineBuf,sizeof(lineBuf)) < 0) + break; + + if (*(lineBuf + strlen(lineBuf) - 1) == '\r') + *(lineBuf + strlen(lineBuf) - 1) = 0; + + for (p=lineBuf; *p ; p++) + { + if (isspace(*p)) { + *p = 0; + break; + } + } + + if ( strncmp(".KERBEROS.OPTION.",lineBuf,17) ) { + t = strlen(lineBuf) + 1; + if(cbsize > (1 + t*sizeof(wchar_t))) { + AnsiStrToUnicode(d, cbsize, lineBuf); + d += t; + cbsize -= t * sizeof(wchar_t); + } else + break; + } + } + + *d = L'\0'; + + fclose(file); + } + } + + return rlist; +} + +/*! \internal + \brief Get the default realm + + A string will be returned that specifies the default realm. The + caller should free the string using free(). + + Returns NULL if the operation fails. +*/ +wchar_t * khm_krb5_get_default_realm(void) +{ + wchar_t * realm; + size_t cch; + krb5_context ctx=0; + char * def = 0; + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if (def) { + cch = strlen(def) + 1; + realm = PMALLOC(sizeof(wchar_t) * cch); + AnsiStrToUnicode(realm, sizeof(wchar_t) * cch, def); + pkrb5_free_default_realm(ctx, def); + } else + realm = NULL; + + pkrb5_free_context(ctx); + + return realm; +} + +long +khm_krb5_set_default_realm(wchar_t * realm) { + krb5_context ctx=0; + char * def = 0; + long rv = 0; + char astr[K5_MAXCCH_REALM]; + + UnicodeStrToAnsi(astr, sizeof(astr), realm); + + pkrb5_init_context(&ctx); + pkrb5_get_default_realm(ctx,&def); + + if ((def && strcmp(def, astr)) || + !def) { + rv = pkrb5_set_default_realm(ctx, astr); + } + + if (def) { + pkrb5_free_default_realm(ctx, def); + } + + pkrb5_free_context(ctx); + + return rv; +} + +wchar_t * khm_get_realm_from_princ(wchar_t * princ) { + wchar_t * t; + + if(!princ) + return NULL; + + for (t = princ; *t; t++) { + if(*t == L'\\') { /* escape */ + t++; + if(! *t) /* malformed */ + break; + } else if (*t == L'@') + break; + } + + if (*t == '@' && *(t+1) != L'\0') + return (t+1); + else + return NULL; +} + +long +khm_krb5_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + krb5_error_code rc = 0; + int result_code; + krb5_data result_code_string, result_string; + krb5_context context = 0; + krb5_principal princ = 0; + krb5_get_init_creds_opt opts; + krb5_creds creds; + + result_string.data = 0; + result_code_string.data = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (rc = pkrb5_init_context(&context)) { + goto cleanup; + } + + if (rc = pkrb5_parse_name(context, principal, &princ)) { + goto cleanup; + } + + pkrb5_get_init_creds_opt_init(&opts); + pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); + pkrb5_get_init_creds_opt_set_renew_life(&opts, 0); + pkrb5_get_init_creds_opt_set_forwardable(&opts, 0); + pkrb5_get_init_creds_opt_set_proxiable(&opts, 0); + pkrb5_get_init_creds_opt_set_address_list(&opts,NULL); + + if (rc = pkrb5_get_init_creds_password(context, &creds, princ, + password, 0, 0, 0, + "kadmin/changepw", &opts)) { + if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) { +#if 0 + com_err(argv[0], 0, + "Password incorrect while getting initial ticket"); +#endif + } + else { +#if 0 + com_err(argv[0], ret, "getting initial ticket"); +#endif + } + goto cleanup; + } + + if (rc = pkrb5_change_password(context, &creds, newpassword, + &result_code, &result_code_string, + &result_string)) { +#if 0 + com_err(argv[0], ret, "changing password"); +#endif + goto cleanup; + } + + if (result_code) { + int len = result_code_string.length + + (result_string.length ? (sizeof(": ") - 1) : 0) + + result_string.length; + if (len && error_str) { + *error_str = PMALLOC(len + 1); + if (*error_str) + StringCchPrintfA(*error_str, len+1, + "%.*s%s%.*s", + result_code_string.length, + result_code_string.data, + result_string.length?": ":"", + result_string.length, + result_string.data); + } + rc = result_code; + goto cleanup; + } + + cleanup: + if (result_string.data) + pkrb5_free_data_contents(context, &result_string); + + if (result_code_string.data) + pkrb5_free_data_contents(context, &result_code_string); + + if (princ) + pkrb5_free_principal(context, princ); + + if (context) + pkrb5_free_context(context); + + return rc; +} + +khm_int32 KHMAPI +khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy) { + if (kcdb_creds_comp_attr(vcred1, vcred2, KCDB_ATTR_LOCATION) || + kcdb_creds_comp_attr(vcred1, vcred2, attr_id_key_enctype) || + kcdb_creds_comp_attr(vcred1, vcred2, attr_id_tkt_enctype)) + return 1; + else + return 0; +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5funcs.h b/mechglue/src/windows/identity/plugins/krb5/krb5funcs.h new file mode 100644 index 000000000..6c2c3eb6b --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5funcs.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +/* Adapted from multiple Leash header files */ + +#ifndef __KHIMAIRA_KRB5FUNCS_H +#define __KHIMAIRA_KRB5FUNCS_H + +#include +#include + +#include +#define SECURITY_WIN32 +#include +#include + +#include + +#define LEASH_DEBUG_CLASS_GENERIC 0 +#define LEASH_DEBUG_CLASS_KRB4 1 +#define LEASH_DEBUG_CLASS_KRB4_APP 2 + +#define LEASH_PRIORITY_LOW 0 +#define LEASH_PRIORITY_HIGH 1 + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ + +#define KRB5_MAXCCH_CCNAME 1024 + +// Function Prototypes. + +BOOL +khm_krb5_ms2mit(BOOL); + +int +khm_krb5_kinit(krb5_context alt_ctx, + char * principal_name, + char * password, + char * ccache, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP, + krb5_prompter_fct prompter, + void * p_data); + +long +khm_krb5_changepwd(char * principal, + char * password, + char * newpassword, + char** error_str); + +int +khm_krb5_destroy_by_credset(khm_handle p_cs); + +int +khm_krb5_destroy_identity(khm_handle identity); + +long +khm_convert524(krb5_context ctx); + +int +khm_krb5_renew(khm_handle identity); + +wchar_t * +khm_krb5_get_default_realm(void); + +long +khm_krb5_set_default_realm(wchar_t * realm); + +wchar_t * +khm_krb5_get_realm_list(void); + +long +khm_krb5_list_tickets(krb5_context *krbv5Context); + +long +khm_krb4_list_tickets(void); + +wchar_t * +khm_get_realm_from_princ(wchar_t * princ); + +long +khm_krb5_copy_ccache_by_name(krb5_context in_ctx, + wchar_t * wscc_dest, + wchar_t * wscc_src); + +long +khm_krb5_canon_cc_name(wchar_t * wcc_name, + size_t cb_cc_name); + +int +khm_krb5_cc_name_cmp(const wchar_t * cc_name_1, + const wchar_t * cc_name_2); + +BOOL +khm_krb5_get_profile_file(LPSTR confname, UINT szConfname); + +BOOL +khm_krb5_get_temp_profile_file(LPSTR confname, UINT szConfname); + +khm_int32 KHMAPI +khm_krb5_creds_is_equal(khm_handle vcred1, khm_handle vcred2, void * dummy); + +#endif diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5identpro.c b/mechglue/src/windows/identity/plugins/krb5/krb5identpro.c new file mode 100644 index 000000000..2ad904b43 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5identpro.c @@ -0,0 +1,1570 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#include + +#define K5_NCID_UN_LABEL (KHUI_CW_ID_MIN + 0) +#define K5_NCID_UN (KHUI_CW_ID_MIN + 1) +#define K5_NCID_REALM_LABEL (KHUI_CW_ID_MIN + 2) +#define K5_NCID_REALM (KHUI_CW_ID_MIN + 3) + +#define NC_UNCHANGE_TIMEOUT 3000 +#define NC_UNCHANGE_TIMER 2 +#define NC_REALMCHANGE_TIMEOUT NC_UNCHANGE_TIMEOUT +#define NC_REALMCHANGE_TIMER 3 + +typedef struct tag_k5_new_cred_data { + HWND hw_username_label; + HWND hw_username; + HWND hw_realm_label; + HWND hw_realm; +} k5_new_cred_data; + +/* Runs in the UI thread */ +int +k5_get_realm_from_nc(khui_new_creds * nc, + wchar_t * buf, + khm_size cch_buf) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + return GetWindowText(d->hw_realm, buf, (int) cch_buf); +} + +/* set the primary identity of a new credentials dialog depending on + the selection of the username and realm + + Runs in the UI thread +*/ +static void +set_identity_from_ui(khui_new_creds * nc, + k5_new_cred_data * d) { + wchar_t un[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * realm; + khm_size cch; + khm_size cch_left; + khm_handle ident; + LRESULT idx = CB_ERR; + + cch = GetWindowTextLength(d->hw_username); + + /* we already set the max length of the edit control to be this. + shouldn't exceed it unless the edit control is confused. */ + assert(cch < KCDB_IDENT_MAXCCH_NAME - 1); + + GetWindowText(d->hw_username, un, ARRAYLENGTH(un)); + + realm = khm_get_realm_from_princ(un); + if (realm) /* realm was specified */ + goto _set_ident; + + /* the cch we got from GetWindowTextLength can not be trusted to + be exact. For caveats see MSDN for GetWindowTextLength. */ + StringCchLength(un, KCDB_IDENT_MAXCCH_NAME, &cch); + + realm = un + cch; /* now points at terminating NULL */ + cch_left = KCDB_IDENT_MAXCCH_NAME - cch; + + *realm++ = L'@'; + cch_left--; + + cch = GetWindowTextLength(d->hw_realm); + if (cch == 0 || cch >= cch_left) + goto _set_null_ident; + + GetWindowText(d->hw_realm, realm, (int) cch_left); + + _set_ident: + if (KHM_FAILED(kcdb_identity_create(un, + KCDB_IDENT_FLAG_CREATE, + &ident))) + goto _set_null_ident; + + khui_cw_set_primary_id(nc, ident); + + kcdb_identity_release(ident); + return; + + _set_null_ident: + khui_cw_set_primary_id(nc, NULL); + return; +} + +/* runs in the UI thread */ +static BOOL +update_crossfeed(khui_new_creds * nc, + k5_new_cred_data * d, + int ctrl_id_src) { + wchar_t un[KCDB_IDENT_MAXCCH_NAME]; + wchar_t * un_realm; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + khm_size cch; + khm_size cch_left; + int idx; + + cch = (khm_size) GetWindowTextLength(d->hw_username); +#ifdef DEBUG + assert(cch < KCDB_IDENT_MAXCCH_NAME); +#endif + if (cch == 0) + return FALSE; + + GetWindowText(d->hw_username, + un, + ARRAYLENGTH(un)); + + un_realm = khm_get_realm_from_princ(un); + + if (un_realm == NULL) + return FALSE; + + if (ctrl_id_src == K5_NCID_UN) { + + idx = (int)SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) un_realm); + + if (idx != CB_ERR) { + wchar_t srealm[KCDB_IDENT_MAXCCH_NAME]; + + cch = SendMessage(d->hw_realm, + CB_GETLBTEXTLEN, + (WPARAM) idx, + 0); + +#ifdef DEBUG + assert(cch < ARRAYLENGTH(srealm) - 1); +#endif + SendMessage(d->hw_realm, + CB_GETLBTEXT, + (WPARAM) idx, + (LPARAM) srealm); + + if (!wcsicmp(srealm, un_realm) && wcscmp(srealm, un_realm)) { + /* differ only by case */ + + StringCchCopy(un_realm, ARRAYLENGTH(un) - (un_realm - un), + srealm); + + SetWindowText(d->hw_username, un); + } + } + + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) un_realm); + + SetWindowText(d->hw_realm, + un_realm); + + return TRUE; + } + /* else... */ + + cch_left = KCDB_IDENT_MAXCCH_NAME - (un_realm - un); + + cch = (khm_size) GetWindowTextLength(d->hw_realm); + +#ifdef DEBUG + assert(cch < KCDB_IDENT_MAXCCH_NAME); +#endif + if (cch == 0) + return FALSE; + + GetWindowText(d->hw_realm, realm, + ARRAYLENGTH(realm)); + + idx = (int)SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) realm); + + if (idx != CB_ERR) { + wchar_t srealm[KCDB_IDENT_MAXCCH_NAME]; + + SendMessage(d->hw_realm, + CB_GETLBTEXT, + (WPARAM) idx, + (LPARAM) srealm); + + if (!wcsicmp(srealm, realm) && wcscmp(srealm, realm)) { + StringCbCopy(realm, sizeof(realm), srealm); + + SetWindowText(d->hw_realm, srealm); + } + } + + StringCchCopy(un_realm, cch_left, realm); + + SendMessage(d->hw_username, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) un); + + SetWindowText(d->hw_username, un); + + return TRUE; +} + +/* Handle window messages for the identity specifiers + + runs in UI thread */ +static LRESULT +handle_wnd_msg(khui_new_creds * nc, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + + switch(uMsg) { + case WM_COMMAND: + switch(wParam) { + case MAKEWPARAM(K5_NCID_UN, CBN_EDITCHANGE): + /* the username has changed. Instead of handling this + for every keystroke, set a timer that elapses some + time afterwards and then handle the event. */ + SetTimer(hwnd, NC_UNCHANGE_TIMER, + NC_UNCHANGE_TIMEOUT, NULL); + return TRUE; + + case MAKEWPARAM(K5_NCID_UN, CBN_KILLFOCUS): + case MAKEWPARAM(K5_NCID_UN, CBN_CLOSEUP): + KillTimer(hwnd, NC_UNCHANGE_TIMER); + + update_crossfeed(nc,d,K5_NCID_UN); + set_identity_from_ui(nc,d); + return TRUE; + + case MAKEWPARAM(K5_NCID_REALM,CBN_EDITCHANGE): + SetTimer(hwnd, NC_REALMCHANGE_TIMER, + NC_REALMCHANGE_TIMEOUT, NULL); + return TRUE; + + case MAKEWPARAM(K5_NCID_REALM,CBN_KILLFOCUS): + case MAKEWPARAM(K5_NCID_REALM,CBN_CLOSEUP): + KillTimer(hwnd, NC_REALMCHANGE_TIMER); + + update_crossfeed(nc,d,K5_NCID_REALM); + set_identity_from_ui(nc, d); + return TRUE; + } + break; + + case WM_TIMER: + if(wParam == NC_UNCHANGE_TIMER) { + KillTimer(hwnd, NC_UNCHANGE_TIMER); + + update_crossfeed(nc, d, K5_NCID_UN); + set_identity_from_ui(nc,d); + return TRUE; + } else if (wParam == NC_REALMCHANGE_TIMER) { + KillTimer(hwnd, NC_REALMCHANGE_TIMER); + + update_crossfeed(nc, d, K5_NCID_REALM); + set_identity_from_ui(nc, d); + return TRUE; + } + break; + } + return FALSE; +} + +/* UI Callback + + runs in UI thread */ +static LRESULT KHMAPI +ui_cb(khui_new_creds * nc, + UINT cmd, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + k5_new_cred_data * d; + + d = (k5_new_cred_data *) nc->ident_aux; + + switch(cmd) { + case WMNC_IDENT_INIT: + { + wchar_t defident[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wbuf[1024]; + wchar_t * ms = NULL; + wchar_t * t; + wchar_t * defrealm = NULL; + LRESULT lr; + khm_size cb_ms; + khm_size cb; + HWND hw_parent; + khm_int32 rv; + khm_handle hident; + + hw_parent = (HWND) lParam; + defident[0] = L'\0'; + +#ifdef DEBUG + assert(d == NULL); + assert(hw_parent != NULL); +#endif + + d = PMALLOC(sizeof(*d)); + assert(d); + ZeroMemory(d, sizeof(*d)); + + khui_cw_lock_nc(nc); + nc->ident_aux = (LPARAM) d; + khui_cw_unlock_nc(nc); + + LoadString(hResModule, IDS_NC_USERNAME, + wbuf, ARRAYLENGTH(wbuf)); + + d->hw_username_label = CreateWindow + (L"STATIC", + wbuf, + SS_SIMPLE | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, /* bogus values */ + hw_parent, + (HMENU) K5_NCID_UN_LABEL, + hInstance, + NULL); + assert(d->hw_username_label != NULL); + + d->hw_username = CreateWindow + (L"COMBOBOX", + L"", + CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + 0, 0, 100, 100, /* bogus values */ + hw_parent, + (HMENU) K5_NCID_UN, + hInstance, + NULL); + assert(d->hw_username != NULL); + + SendMessage(d->hw_username, + CB_LIMITTEXT, + (WPARAM)(KCDB_IDENT_MAXCCH_NAME - 1), + 0); + + SendMessage(d->hw_username, + CB_SETEXTENDEDUI, + (WPARAM) TRUE, + 0); + + khui_cw_add_control_row(nc, + d->hw_username_label, + d->hw_username, + KHUI_CTRLSIZE_SMALL); + + LoadString(hResModule, IDS_NC_REALM, + wbuf, ARRAYLENGTH(wbuf)); + + d->hw_realm_label = CreateWindow + (L"STATIC", + wbuf, + SS_SIMPLE | WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, /* bogus */ + hw_parent, + (HMENU) K5_NCID_REALM_LABEL, + hInstance, + NULL); + assert(d->hw_realm_label != NULL); + + d->hw_realm = CreateWindow + (L"COMBOBOX", + L"", + CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + 0, 0, 100, 100, /* bogus */ + hw_parent, + (HMENU) K5_NCID_REALM, + hInstance, + NULL); + assert(d->hw_realm != NULL); + + SendMessage(d->hw_realm, + CB_LIMITTEXT, + (WPARAM) (KCDB_IDENT_MAXCCH_NAME - 1), + 0); + + SendMessage(d->hw_realm, + CB_SETEXTENDEDUI, + (WPARAM) TRUE, + 0); + + khui_cw_add_control_row(nc, + d->hw_realm_label, + d->hw_realm, + KHUI_CTRLSIZE_SMALL); + + /* add the LRU realms and principals to the dropdown + lists */ + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + NULL, + &cb_ms); + + if (rv != KHM_ERROR_TOO_LONG || cb_ms <= sizeof(wchar_t) * 2) + goto _add_lru_realms; + + ms = PMALLOC(cb_ms); + assert(ms != NULL); + + cb = cb_ms; + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + ms, + &cb); + + assert(KHM_SUCCEEDED(rv)); + + /* the first of these is considered the default identity + if no other default is known */ + StringCbCopy(defident, sizeof(defident), ms); + + t = ms; + while(t && *t) { + SendMessage(d->hw_username, + CB_ADDSTRING, + 0, + (LPARAM) t); + + t = multi_string_next(t); + } + + _add_lru_realms: + /* add the default realm first */ + defrealm = khm_krb5_get_default_realm(); + if (defrealm) { + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) defrealm); + } + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + NULL, + &cb); + + if (rv != KHM_ERROR_TOO_LONG) + goto _done_adding_lru; + + if (ms != NULL) { + if (cb_ms < cb) { + PFREE(ms); + ms = PMALLOC(cb); + assert(ms); + cb_ms = cb; + } + } else { + ms = PMALLOC(cb); + cb_ms = cb; + } + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + ms, + &cb); + + assert(KHM_SUCCEEDED(rv)); + + for (t = ms; t && *t; t = multi_string_next(t)) { + lr = SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) t); + if (lr != CB_ERR) + continue; + + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) t); + } + _done_adding_lru: + + { + khm_int32 inc_realms = 0; + + if (KHM_FAILED(khc_read_int32(csp_params, + L"UseFullRealmList", + &inc_realms)) || + !inc_realms) + goto _done_adding_all_realms; + } + + if(ms) + PFREE(ms); + + ms = khm_krb5_get_realm_list(); + if(ms) { + for (t = ms; t && *t; t = multi_string_next(t)) { + lr = SendMessage(d->hw_realm, + CB_FINDSTRINGEXACT, + (WPARAM) -1, + (LPARAM) t); + if (lr != CB_ERR) + continue; + + SendMessage(d->hw_realm, + CB_ADDSTRING, + 0, + (LPARAM) t); + } + } + _done_adding_all_realms: + + /* set the current selection of the realms list */ + if (defrealm) { + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defrealm); + } else { + SendMessage(d->hw_realm, + CB_SETCURSEL, + (WPARAM) 0, + (LPARAM) 0); + } + + if (defrealm) + PFREE(defrealm); + + if (ms) + PFREE(ms); + + /* now see about that default identity */ + if (nc->ctx.identity) { + cb = sizeof(defident); + kcdb_identity_get_name(nc->ctx.identity, + defident, + &cb); + } + + if (defident[0] == L'\0' && + KHM_SUCCEEDED(kcdb_identity_get_default(&hident))) { + cb = sizeof(defident); + kcdb_identity_get_name(hident, defident, &cb); + kcdb_identity_release(hident); + } + + if (defident[0] == L'\0') { + DWORD dw; + + dw = ARRAYLENGTH(defident); + GetUserName(defident, &dw); + } + + t = khm_get_realm_from_princ(defident); + if (t) { + /* there is a realm */ + assert(t != defident); + *--t = L'\0'; + t++; + + SendMessage(d->hw_realm, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) t); + + SendMessage(d->hw_realm, + WM_SETTEXT, + 0, + (LPARAM) t); + } + + if (defident[0] != L'\0') { + /* there is a username */ + SendMessage(d->hw_username, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defident); + + SendMessage(d->hw_username, + WM_SETTEXT, + 0, + (LPARAM) defident); + } + + set_identity_from_ui(nc, d); + } + return TRUE; + + case WMNC_IDENT_WMSG: + return handle_wnd_msg(nc, hwnd, uMsg, wParam, lParam); + + case WMNC_IDENT_EXIT: + { +#ifdef DEBUG + assert(d != NULL); +#endif + khui_cw_lock_nc(nc); + nc->ident_aux = 0; + khui_cw_unlock_nc(nc); + + /* since we created all the windows as child windows of + the new creds window, they will be destroyed when that + window is destroyed. */ + PFREE(d); + } + return TRUE; + } + return FALSE; +} + +static khm_int32 +k5_ident_valiate_name(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + krb5_principal princ = NULL; + char princ_name[KCDB_IDENT_MAXCCH_NAME]; + kcdb_ident_name_xfer * nx; + krb5_error_code code; + + nx = (kcdb_ident_name_xfer *) vparam; + + if(UnicodeStrToAnsi(princ_name, sizeof(princ_name), + nx->name_src) == 0) { + nx->result = KHM_ERROR_INVALID_NAME; + return KHM_ERROR_SUCCESS; + } + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_parse_name(k5_identpro_ctx, + princ_name, + &princ); + + if (code) { + nx->result = KHM_ERROR_INVALID_NAME; + return KHM_ERROR_SUCCESS; + } + + if (princ != NULL) + pkrb5_free_principal(k5_identpro_ctx, + princ); + + nx->result = KHM_ERROR_SUCCESS; + + return KHM_ERROR_SUCCESS; +} + +static void +k5_update_last_default_identity(khm_handle ident) { + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + cb = sizeof(idname); + if (KHM_FAILED(kcdb_identity_get_name(ident, idname, &cb))) + return; + + assert(csp_params); + + khc_write_string(csp_params, L"LastDefaultIdent", idname); +} + +static khm_int32 +k5_ident_set_default(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + /* Logic for setting the default identity: + + When setting identity I as the default; + + - If KRB5CCNAME is set + - If I["Krb5CCName"] == %KRB5CCNAME% + - do nothing + - Else + - Copy the contents of I["Krb5CCName"] to %KRB5CCNAME + - Set I["Krb5CCName"] to %KRB5CCNAME + - Else + - Set HKCU\Software\MIT\kerberos5,ccname to + "API:".I["Krb5CCName"] + */ + + if (uparam) { + /* an identity is being made default */ + khm_handle def_ident = (khm_handle) vparam; + wchar_t env_ccname[KRB5_MAXCCH_CCNAME]; + wchar_t id_ccname[KRB5_MAXCCH_CCNAME]; + khm_size cb; + DWORD dw; + LONG l; + +#ifdef DEBUG + assert(def_ident != NULL); +#endif + + cb = sizeof(id_ccname); + if (KHM_FAILED(kcdb_identity_get_attr(def_ident, + attr_id_krb5_ccname, + NULL, + id_ccname, + &cb))) + return KHM_ERROR_UNKNOWN; + + khm_krb5_canon_cc_name(id_ccname, sizeof(id_ccname)); + + StringCbLength(id_ccname, sizeof(id_ccname), &cb); + cb += sizeof(wchar_t); + + dw = GetEnvironmentVariable(L"KRB5CCNAME", + env_ccname, + ARRAYLENGTH(env_ccname)); + + if (dw == 0 && + GetLastError() == ERROR_ENVVAR_NOT_FOUND) { + /* KRB5CCNAME not set */ + HKEY hk_ccname; + DWORD dwType; + DWORD dwSize; + wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; + + l = RegOpenKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + KEY_READ | KEY_WRITE, + &hk_ccname); + + if (l != ERROR_SUCCESS) + l = RegCreateKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk_ccname, + &dw); + + if (l != ERROR_SUCCESS) + return KHM_ERROR_UNKNOWN; + + dwSize = sizeof(reg_ccname); + + l = RegQueryValueEx(hk_ccname, + L"ccname", + NULL, + &dwType, + (LPBYTE) reg_ccname, + &dwSize); + + if (l != ERROR_SUCCESS || + dwType != REG_SZ || + khm_krb5_cc_name_cmp(reg_ccname, id_ccname)) { + + /* we have to write the new value in */ + + l = RegSetValueEx(hk_ccname, + L"ccname", + 0, + REG_SZ, + (BYTE *) id_ccname, + (DWORD) cb); + } + + RegCloseKey(hk_ccname); + + if (l == ERROR_SUCCESS) { + k5_update_last_default_identity(def_ident); + return KHM_ERROR_SUCCESS; + } else + return KHM_ERROR_UNKNOWN; + + } else if (dw > ARRAYLENGTH(env_ccname)) { + /* buffer was not enough */ +#ifdef DEBUG + assert(FALSE); +#else + return KHM_ERROR_UNKNOWN; +#endif + } else { + /* KRB5CCNAME is set */ + long code; + krb5_context ctx; + + /* if the %KRB5CCNAME is the same as the identity + ccache, then it is already the default. */ + if (!khm_krb5_cc_name_cmp(id_ccname, env_ccname)) { + k5_update_last_default_identity(def_ident); + return KHM_ERROR_SUCCESS; + } + + /* if not, we have to copy the contents of id_ccname + to env_ccname */ + code = pkrb5_init_context(&ctx); + if (code) + return KHM_ERROR_UNKNOWN; + + code = khm_krb5_copy_ccache_by_name(ctx, + env_ccname, + id_ccname); + + if (code == 0) { + k5_update_last_default_identity(def_ident); + khm_krb5_list_tickets(&ctx); + } + + if (ctx) + pkrb5_free_context(ctx); + + return (code == 0)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN; + } + } else { + /* the default identity is being forgotten */ + + /* we don't really do anything about this case */ + } + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_get_ui_cb(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + khui_ident_new_creds_cb * cb; + + cb = (khui_ident_new_creds_cb *) vparam; + + *cb = ui_cb; + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_notify_create(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + /* a new identity has been created. What we want to do at + this point is to check if the identity belongs to krb5 + and to see if it is the default. */ + + krb5_ccache cc = NULL; + krb5_error_code code; + krb5_principal princ = NULL; + char * princ_nameA = NULL; + wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + wchar_t id_nameW[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_handle ident; + + /* if there is a default identity already, we assume we don't need + to check this one. */ + + khm_handle def_ident; + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&def_ident))) { + kcdb_identity_release(def_ident); + + return KHM_ERROR_SUCCESS; + } + + ident = (khm_handle) vparam; + + assert(k5_identpro_ctx != NULL); + + code = pkrb5_cc_default(k5_identpro_ctx, &cc); + if (code) + goto _nc_cleanup; + + code = pkrb5_cc_get_principal(k5_identpro_ctx, + cc, + &princ); + if (code) + goto _nc_cleanup; + + code = pkrb5_unparse_name(k5_identpro_ctx, + princ, + &princ_nameA); + if (code) + goto _nc_cleanup; + + AnsiStrToUnicode(princ_nameW, + sizeof(princ_nameW), + princ_nameA); + + cb = sizeof(id_nameW); + + if (KHM_FAILED(kcdb_identity_get_name(ident, + id_nameW, + &cb))) + goto _nc_cleanup; + + if (!wcscmp(id_nameW, princ_nameW)) { + kcdb_identity_set_default_int(ident); + } + + _nc_cleanup: + if (princ_nameA) + pkrb5_free_unparsed_name(k5_identpro_ctx, + princ_nameA); + if (princ) + pkrb5_free_principal(k5_identpro_ctx, + princ); + if (cc) + pkrb5_cc_close(k5_identpro_ctx, cc); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 KHMAPI +k5_ident_update_apply_proc(khm_handle cred, + void * rock) { + wchar_t ccname[KRB5_MAXCCH_CCNAME]; + khm_handle tident = (khm_handle) rock; + khm_handle ident = NULL; + khm_int32 t; + khm_int32 flags; + __int64 t_expire; + __int64 t_cexpire; + __int64 t_rexpire; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &t)) || + t != credtype_id_krb5 || + KHM_FAILED(kcdb_cred_get_identity(cred, &ident))) + return KHM_ERROR_SUCCESS; + + if (!kcdb_identity_is_equal(ident,tident)) + goto _cleanup; + + if (KHM_FAILED(kcdb_cred_get_flags(cred, &flags))) + flags = 0; + + if (flags & KCDB_CRED_FLAG_INITIAL) { + cb = sizeof(t_cexpire); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, + KCDB_ATTR_EXPIRE, + NULL, + &t_cexpire, + &cb))) { + t_expire = 0; + cb = sizeof(t_expire); + if (KHM_FAILED(kcdb_identity_get_attr(tident, + KCDB_ATTR_EXPIRE, + NULL, + &t_expire, + &cb)) || + (t_cexpire > t_expire)) + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, + &t_cexpire, sizeof(t_cexpire)); + } else { + kcdb_identity_set_attr(tident, KCDB_ATTR_EXPIRE, NULL, 0); + } + } else { + goto _cleanup; + } + + cb = sizeof(ccname); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_LOCATION, + NULL, + ccname, + &cb))) { + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + ccname, cb); + } else { + kcdb_identity_set_attr(tident, attr_id_krb5_ccname, + NULL, 0); + } + + cb = sizeof(t); + if (KHM_SUCCEEDED(kcdb_cred_get_attr(cred, + attr_id_krb5_flags, + NULL, + &t, + &cb))) { + + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + &t, sizeof(t)); + + cb = sizeof(t_rexpire); + if (!(t & TKT_FLG_RENEWABLE) || + KHM_FAILED(kcdb_cred_get_attr(cred, + KCDB_ATTR_RENEW_EXPIRE, + NULL, + &t_rexpire, + &cb))) { + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } else { + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + &t_rexpire, sizeof(t_rexpire)); + } + } else { + kcdb_identity_set_attr(tident, attr_id_krb5_flags, + NULL, 0); + kcdb_identity_set_attr(tident, KCDB_ATTR_RENEW_EXPIRE, + NULL, 0); + } + + rv = KHM_ERROR_EXIT; + + _cleanup: + if (ident) + kcdb_identity_release(ident); + + return rv; +} + +static khm_int32 +k5_ident_update(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + khm_handle ident; + khm_handle tident; + krb5_ccache cc = NULL; + char * ccname; + krb5_error_code code; + khm_size cb; + wchar_t wid_ccname[MAX_PATH]; + wchar_t w_ccname[MAX_PATH]; + + ident = (khm_handle) vparam; + if (ident == NULL) + return KHM_ERROR_SUCCESS; + + kcdb_credset_apply(NULL, + k5_ident_update_apply_proc, + (void *) ident); + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&tident))) { + kcdb_identity_release(tident); + goto _iu_cleanup; + } + + cb = sizeof(wid_ccname); + if (KHM_FAILED(kcdb_identity_get_attr(ident, + attr_id_krb5_ccname, + NULL, + wid_ccname, + &cb))) + goto _iu_cleanup; + + if(k5_identpro_ctx == NULL) + goto _iu_cleanup; + + code = pkrb5_cc_default(k5_identpro_ctx, &cc); + if (code) + goto _iu_cleanup; + + ccname = pkrb5_cc_get_name(k5_identpro_ctx, cc); + if (ccname == NULL) + goto _iu_cleanup; + + AnsiStrToUnicode(w_ccname, sizeof(w_ccname), ccname); + + khm_krb5_canon_cc_name(w_ccname, sizeof(w_ccname)); + khm_krb5_canon_cc_name(wid_ccname, sizeof(wid_ccname)); + + if (!wcsicmp(w_ccname, wid_ccname)) + kcdb_identity_set_default_int(ident); + + _iu_cleanup: + if (cc && k5_identpro_ctx) + pkrb5_cc_close(k5_identpro_ctx, cc); + + return KHM_ERROR_SUCCESS; +} + +static khm_boolean +k5_refresh_default_identity(krb5_context ctx) { + /* just like notify_create, except now we set the default identity + based on what we find in the configuration */ + krb5_ccache cc = NULL; + krb5_error_code code; + krb5_principal princ = NULL; + char * princ_nameA = NULL; + wchar_t princ_nameW[KCDB_IDENT_MAXCCH_NAME]; + khm_handle ident = NULL; + khm_boolean found_default = FALSE; + + assert(ctx != NULL); + + code = pkrb5_cc_default(ctx, &cc); + if (code) + goto _nc_cleanup; + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + if (code) + goto _nc_cleanup; + + code = pkrb5_unparse_name(ctx, princ, &princ_nameA); + if (code) + goto _nc_cleanup; + + AnsiStrToUnicode(princ_nameW, sizeof(princ_nameW), princ_nameA); + + if (KHM_FAILED(kcdb_identity_create(princ_nameW, 0, &ident))) + goto _nc_cleanup; + + kcdb_identity_set_default_int(ident); + + found_default = TRUE; + + _nc_cleanup: + if (princ_nameA) + pkrb5_free_unparsed_name(ctx, princ_nameA); + + if (princ) + pkrb5_free_principal(ctx, princ); + + if (cc) + pkrb5_cc_close(ctx, cc); + + if (ident) + kcdb_identity_release(ident); + + return found_default; +} + +static khm_int32 +k5_ident_init(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + + khm_boolean found_default; + khm_handle ident; + + found_default = k5_refresh_default_identity(k5_identpro_ctx); + + if (!found_default) { + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + cb = sizeof(widname); + + assert(csp_params); + + if (KHM_SUCCEEDED(khc_read_string(csp_params, L"LastDefaultIdent", + widname, &cb))) { + ident = NULL; + kcdb_identity_create(widname, KCDB_IDENT_FLAG_CREATE, &ident); + if (ident) { + kcdb_identity_set_default_int(ident); + kcdb_identity_release(ident); + } + } + } + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +k5_ident_exit(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { + /* don't really do anything */ + return KHM_ERROR_SUCCESS; +} + +#if 0 +/* copy and paste template for ident provider messages */ +static khm_int32 +k5_ident_(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) { +} +#endif + +khm_int32 KHMAPI +k5_msg_ident(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) +{ + switch(msg_subtype) { + case KMSG_IDENT_INIT: + return k5_ident_init(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_EXIT: + return k5_ident_exit(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_VALIDATE_NAME: + return k5_ident_valiate_name(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_VALIDATE_IDENTITY: + /* TODO: handle KMSG_IDENT_VALIDATE_IDENTITY */ + break; + + case KMSG_IDENT_CANON_NAME: + /* TODO: handle KMSG_IDENT_CANON_NAME */ + break; + + case KMSG_IDENT_COMPARE_NAME: + /* TODO: handle KMSG_IDENT_COMPARE_NAME */ + break; + + case KMSG_IDENT_SET_DEFAULT: + return k5_ident_set_default(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_SET_SEARCHABLE: + /* TODO: handle KMSG_IDENT_SET_SEARCHABLE */ + break; + + case KMSG_IDENT_GET_INFO: + /* TODO: handle KMSG_IDENT_GET_INFO */ + break; + + case KMSG_IDENT_UPDATE: + return k5_ident_update(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_ENUM_KNOWN: + /* TODO: handle KMSG_IDENT_ENUM_KNOWN */ + break; + + case KMSG_IDENT_GET_UI_CALLBACK: + return k5_ident_get_ui_cb(msg_type, + msg_subtype, + uparam, + vparam); + + case KMSG_IDENT_NOTIFY_CREATE: + return k5_ident_notify_create(msg_type, + msg_subtype, + uparam, + vparam); + } + + return KHM_ERROR_SUCCESS; +} + +khm_int32 KHMAPI +k5_ident_name_comp_func(const void * dl, khm_size cb_dl, + const void * dr, khm_size cb_dr) { + wchar_t * idl = (wchar_t *) dl; + wchar_t * idr = (wchar_t *) dr; + wchar_t * rl; + wchar_t * rr; + khm_int32 r; + + rl = khm_get_realm_from_princ(idl); + rr = khm_get_realm_from_princ(idr); + + if (rl == NULL && rr == NULL) + return wcscmp(idl, idr); + else if (rl == NULL) + return 1; + else if (rr == NULL) + return -1; + + r = wcscmp(rl, rr); + if (r == 0) + return wcscmp(idl, idr); + else + return r; +} + + +/* Identity change notification thread */ + +HANDLE h_ccname_exit_event; +HANDLE h_ccname_thread; + +DWORD WINAPI k5_ccname_monitor_thread(LPVOID lpParameter) { + krb5_context ctx = 0; + + HKEY hk_ccname; + HANDLE h_notify; + HANDLE h_waits[2]; + + khm_int32 rv = KHM_ERROR_SUCCESS; + DWORD dwType; + DWORD dwSize; + DWORD dwDisp; + wchar_t reg_ccname[KRB5_MAXCCH_CCNAME]; + LONG l; + + l = RegOpenKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + KEY_READ | KEY_WRITE, + &hk_ccname); + + if (l != ERROR_SUCCESS) + l = RegCreateKeyEx(HKEY_CURRENT_USER, + L"Software\\MIT\\kerberos5", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hk_ccname, + &dwDisp); + + if (l != ERROR_SUCCESS) { + rv = KHM_ERROR_UNKNOWN; + goto _exit; + } + + dwSize = sizeof(reg_ccname); + + l = RegQueryValueEx(hk_ccname, + L"ccname", + NULL, + &dwType, + (LPBYTE) reg_ccname, + &dwSize); + + if (l != ERROR_SUCCESS || + dwType != REG_SZ) { + + reg_ccname[0] = L'\0'; + } + + l = pkrb5_init_context(&ctx); + + if (l) + goto _exit_0; + + h_notify = CreateEvent(NULL, FALSE, FALSE, L"Local\\Krb5CCNameChangeNotifier"); + + if (h_notify == NULL) + goto _exit_0; + + /* begin wait loop */ + + h_waits[0] = h_ccname_exit_event; + h_waits[1] = h_notify; + + do { + DWORD dwrv; + + l = RegNotifyChangeKeyValue(hk_ccname, FALSE, + REG_NOTIFY_CHANGE_LAST_SET, + h_notify, TRUE); + + if (l != ERROR_SUCCESS) { + rv = KHM_ERROR_UNKNOWN; + break; + } + + dwrv = WaitForMultipleObjects(2, h_waits, FALSE, INFINITE); + + if (dwrv == WAIT_OBJECT_0) { + /* exit! */ + break; + + } else if (dwrv == WAIT_OBJECT_0 + 1) { + /* change notify! */ + wchar_t new_ccname[KRB5_MAXCCH_CCNAME]; + + dwSize = sizeof(new_ccname); + + l = RegQueryValueEx(hk_ccname, + L"ccname", + NULL, + &dwType, + (LPBYTE) new_ccname, + &dwSize); + + if (l != ERROR_SUCCESS || + dwType != REG_SZ) { + new_ccname[0] = L'\0'; + } + + if (wcsicmp(new_ccname, reg_ccname)) { + k5_refresh_default_identity(ctx); + StringCbCopy(reg_ccname, sizeof(reg_ccname), new_ccname); + } + + } else { + /* something went wrong */ + rv = KHM_ERROR_UNKNOWN; + break; + } + + } while (TRUE); + + CloseHandle(h_notify); + + _exit_0: + + RegCloseKey(hk_ccname); + + if (ctx) + pkrb5_free_context(ctx); + + _exit: + ExitThread(rv); + + /* not reached */ + return rv; +} + +khm_int32 +k5_msg_system_idpro(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) { + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + + pkrb5_init_context(&k5_identpro_ctx); + kcdb_identity_set_type(credtype_id_krb5); + + if (KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_PRINC, + &type_id_krb5_princ))) { + kcdb_type dt; + kcdb_type * pstr; + + kcdb_type_get_info(KCDB_TYPE_STRING, &pstr); + + ZeroMemory(&dt, sizeof(dt)); + dt.name = TYPENAME_KRB5_PRINC; + dt.id = KCDB_TYPE_INVALID; + dt.flags = KCDB_TYPE_FLAG_CB_AUTO; + dt.cb_min = pstr->cb_min; + dt.cb_max = pstr->cb_max; + dt.toString = pstr->toString; + dt.isValid = pstr->isValid; + dt.comp = k5_ident_name_comp_func; + dt.dup = pstr->dup; + + kcdb_type_register(&dt, &type_id_krb5_princ); + + type_regd_krb5_princ = TRUE; + + kcdb_type_release_info(pstr); + } + + if (type_id_krb5_princ != -1) { + kcdb_attrib * attr; + + kcdb_attrib_get_info(KCDB_ATTR_ID_NAME, &attr); + + attr->type = type_id_krb5_princ; + + kcdb_attrib_release_info(attr); + } + + h_ccname_exit_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (h_ccname_exit_event) { + h_ccname_thread = CreateThread(NULL, + 200 * 1024, + k5_ccname_monitor_thread, + NULL, + 0, + NULL); + } else { + h_ccname_thread = NULL; + } + } + break; + + case KMSG_SYSTEM_EXIT: + { + + if (h_ccname_thread) { + SetEvent(h_ccname_exit_event); + WaitForSingleObject(h_ccname_thread, INFINITE); + CloseHandle(h_ccname_thread); + CloseHandle(h_ccname_exit_event); + + h_ccname_exit_event = NULL; + h_ccname_thread = NULL; + } + + if (k5_identpro_ctx) { + pkrb5_free_context(k5_identpro_ctx); + k5_identpro_ctx = NULL; + } + + if (type_id_krb5_princ != -1) { + kcdb_attrib * attr; + + kcdb_attrib_get_info(KCDB_ATTR_ID_NAME, &attr); + + attr->type = KCDB_TYPE_STRING; + + kcdb_attrib_release_info(attr); + } + + /* allow a brief moment for any stale references to die */ + Sleep(100); + + if (type_regd_krb5_princ) { + kcdb_type_unregister(type_id_krb5_princ); + } + } + break; + } + + return KHM_ERROR_SUCCESS; +} + +khm_int32 KHMAPI +k5_ident_callback(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) { + switch(msg_type) { + case KMSG_SYSTEM: + return k5_msg_system_idpro(msg_type, msg_subtype, uparam, vparam); + + case KMSG_IDENT: + return k5_msg_ident(msg_type, msg_subtype, uparam, vparam); + } + + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5main.c b/mechglue/src/windows/identity/plugins/krb5/krb5main.c new file mode 100644 index 000000000..d324857fe --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5main.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include + +kmm_module h_khModule; /* KMM's handle to this module */ +HINSTANCE hInstance; +HMODULE hResModule; /* HMODULE to the resource library */ +const wchar_t * k5_facility = L"Krb5"; + +khm_int32 type_id_enctype = -1; +khm_int32 type_id_addr_list = -1; +khm_int32 type_id_krb5_flags = -1; +khm_int32 type_id_krb5_princ = -1; + +BOOL type_regd_enctype = FALSE; +BOOL type_regd_addr_list = FALSE; +BOOL type_regd_krb5_flags = FALSE; +BOOL type_regd_krb5_princ = FALSE; + +khm_int32 attr_id_key_enctype = -1; +khm_int32 attr_id_tkt_enctype = -1; +khm_int32 attr_id_addr_list = -1; +khm_int32 attr_id_krb5_flags = -1; +khm_int32 attr_id_krb5_ccname = -1; + +BOOL attr_regd_key_enctype = FALSE; +BOOL attr_regd_tkt_enctype = FALSE; +BOOL attr_regd_addr_list = FALSE; +BOOL attr_regd_krb5_flags = FALSE; +BOOL attr_regd_krb5_ccname = FALSE; + +khm_handle csp_plugins = NULL; +khm_handle csp_krbcred = NULL; +khm_handle csp_params = NULL; + +BOOL is_k5_identpro = TRUE; + +khm_ui_4 k5_commctl_version; + +kmm_module_locale locales[] = { + LOCALE_DEF(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), L"krb5cred_en_us.dll", KMM_MLOC_FLAG_DEFAULT) +}; +int n_locales = ARRAYLENGTH(locales); + +/* These two should not do anything */ +void init_krb() { +} + +void exit_krb() { +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module) { + khm_int32 rv = KHM_ERROR_SUCCESS; + kmm_plugin_reg pi; + wchar_t buf[256]; + + h_khModule = h_module; + + rv = kmm_set_locale_info(h_module, locales, n_locales); + if(KHM_SUCCEEDED(rv)) { + hResModule = kmm_get_resource_hmodule(h_module); + } else + goto _exit; + + k5_commctl_version = khm_get_commctl_version(NULL); + + /* register the plugin */ + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB5_PLUGIN_NAME; + pi.type = KHM_PITYPE_CRED; + pi.icon = NULL; /*TODO: Assign icon */ + pi.flags = 0; + pi.msg_proc = k5_msg_callback; + pi.description = buf; + LoadString(hResModule, IDS_PLUGIN_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + ZeroMemory(&pi, sizeof(pi)); + pi.name = KRB5_IDENTPRO_NAME; + pi.type = KHM_PITYPE_IDENT; + pi.icon = NULL; /* ignored */ + pi.flags = 0; + pi.msg_proc = k5_ident_callback; + pi.description = buf; + pi.dependencies = KRB5_PLUGIN_NAME L"\0"; + LoadString(hResModule, IDS_IDENTPRO_DESC, + buf, ARRAYLENGTH(buf)); + kmm_provide_plugin(h_module, &pi); + + if(KHM_FAILED(rv = init_imports())) + goto _exit; + + if(KHM_FAILED(rv = init_error_funcs())) + goto _exit; + + /* Register common data types */ + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ENCTYPE, &type_id_enctype))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_ENCTYPE; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = enctype_toString; + + rv = kcdb_type_register(&type, &type_id_enctype); + kcdb_type_release_info(t32); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_ADDR_LIST, &type_id_addr_list))) { + kcdb_type type; + kcdb_type *tdata; + + kcdb_type_get_info(KCDB_TYPE_DATA, &tdata); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_ADDR_LIST; + type.flags = KCDB_TYPE_FLAG_CB_MIN; + type.cb_min = 0; + type.cb_max = 0; + type.isValid = tdata->isValid; + type.comp = tdata->comp; + type.dup = tdata->dup; + type.toString = addr_list_toString; + + rv = kcdb_type_register(&type, &type_id_addr_list); + kcdb_type_release_info(tdata); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_addr_list = TRUE; + } + + if(KHM_FAILED(kcdb_type_get_id(TYPENAME_KRB5_FLAGS, &type_id_krb5_flags))) { + kcdb_type type; + kcdb_type *t32; + + kcdb_type_get_info(KCDB_TYPE_INT32, &t32); + + type.id = KCDB_TYPE_INVALID; + type.name = TYPENAME_KRB5_FLAGS; + type.flags = KCDB_TYPE_FLAG_CB_FIXED; + type.cb_max = t32->cb_max; + type.cb_min = t32->cb_min; + type.isValid = t32->isValid; + type.comp = t32->comp; + type.dup = t32->dup; + type.toString = krb5flags_toString; + + rv = kcdb_type_register(&type, &type_id_krb5_flags); + kcdb_type_release_info(t32); + + if(KHM_FAILED(rv)) + goto _exit; + type_regd_krb5_flags = TRUE; + } + + /* Register common attributes */ + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KEY_ENCTYPE, &attr_id_key_enctype))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KEY_ENCTYPE; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_enctype; + attrib.flags = 0; + LoadString(hResModule, IDS_KEY_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_KEY_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_key_enctype); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_key_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_TKT_ENCTYPE, &attr_id_tkt_enctype))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_TKT_ENCTYPE; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_enctype; + attrib.flags = 0; + LoadString(hResModule, IDS_TKT_ENCTYPE_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_TKT_ENCTYPE_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_tkt_enctype); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_tkt_enctype = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_ADDR_LIST, &attr_id_addr_list))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_ADDR_LIST; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_addr_list; + attrib.flags = 0; + LoadString(hResModule, IDS_ADDR_LIST_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_ADDR_LIST_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_addr_list); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_addr_list = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_FLAGS, &attr_id_krb5_flags))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_FLAGS; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = type_id_krb5_flags; + attrib.flags = 0; + LoadString(hResModule, IDS_KRB5_FLAGS_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = NULL; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_flags); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_flags = TRUE; + } + + if(KHM_FAILED(kcdb_attrib_get_id(ATTRNAME_KRB5_CCNAME, &attr_id_krb5_ccname))) { + kcdb_attrib attrib; + wchar_t sbuf[KCDB_MAXCCH_SHORT_DESC]; + wchar_t lbuf[KCDB_MAXCCH_SHORT_DESC]; + /* although we are loading a long descriptoin, it still fits + in the short descriptoin buffer */ + + ZeroMemory(&attrib, sizeof(attrib)); + + attrib.name = ATTRNAME_KRB5_CCNAME; + attrib.id = KCDB_ATTR_INVALID; + attrib.type = KCDB_TYPE_STRING; + attrib.flags = KCDB_ATTR_FLAG_PROPERTY; + LoadString(hResModule, IDS_KRB5_CCNAME_SHORT_DESC, sbuf, ARRAYLENGTH(sbuf)); + LoadString(hResModule, IDS_KRB5_CCNAME_LONG_DESC, lbuf, ARRAYLENGTH(lbuf)); + attrib.short_desc = sbuf; + attrib.long_desc = lbuf; + + rv = kcdb_attrib_register(&attrib, &attr_id_krb5_ccname); + + if(KHM_FAILED(rv)) + goto _exit; + + attr_regd_krb5_ccname = TRUE; + } + + rv = kmm_get_plugins_config(0, &csp_plugins); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_load_schema(csp_plugins, schema_krbconfig); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_plugins, CSNAME_KRB5CRED, 0, &csp_krbcred); + if(KHM_FAILED(rv)) goto _exit; + + rv = khc_open_space(csp_krbcred, CSNAME_PARAMS, 0, &csp_params); + if(KHM_FAILED(rv)) goto _exit; + +_exit: + return rv; +} + +/* called by the NetIDMgr module manager */ +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module) { + exit_imports(); + exit_error_funcs(); + + if(attr_regd_key_enctype) + kcdb_attrib_unregister(attr_id_key_enctype); + if(attr_regd_tkt_enctype) + kcdb_attrib_unregister(attr_id_tkt_enctype); + if(attr_regd_addr_list) + kcdb_attrib_unregister(attr_id_addr_list); + if(attr_regd_krb5_flags) + kcdb_attrib_unregister(attr_id_krb5_flags); + if(attr_regd_krb5_ccname) + kcdb_attrib_unregister(attr_id_krb5_ccname); + + if(type_regd_enctype) + kcdb_type_unregister(type_id_enctype); + if(type_regd_addr_list) + kcdb_type_unregister(type_id_addr_list); + if(type_regd_krb5_flags) + kcdb_type_unregister(type_id_krb5_flags); + + if(csp_params) { + khc_close_space(csp_params); + csp_params = NULL; + } + + if(csp_krbcred) { + khc_close_space(csp_krbcred); + csp_krbcred = NULL; + } + + if(csp_plugins) { + khc_unload_schema(csp_plugins, schema_krbconfig); + khc_close_space(csp_plugins); + csp_plugins = NULL; + } + + return KHM_ERROR_SUCCESS; /* the return code is ignored */ +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved +) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + hInstance = hinstDLL; + init_krb(); + break; + case DLL_PROCESS_DETACH: + exit_krb(); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5newcreds.c b/mechglue/src/windows/identity/plugins/krb5/krb5newcreds.c new file mode 100644 index 000000000..e6bf6479d --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5newcreds.c @@ -0,0 +1,2240 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include + +#include + +extern LPVOID k5_main_fiber; +extern LPVOID k5_kinit_fiber; + +typedef struct k5_dlg_data_t { + khui_new_creds * nc; + + khui_tracker tc_lifetime; + khui_tracker tc_renew; + + BOOL dirty; + + DWORD renewable; + DWORD forwardable; + DWORD proxiable; + DWORD addressless; + DWORD publicIP; + + wchar_t * cred_message; /* overrides the credential text, if + non-NULL */ +} k5_dlg_data; + + +INT_PTR +k5_handle_wm_initdialog(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + HWND hw; + k5_dlg_data * d; + khui_new_creds_by_type * nct; + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + /* lParam is a pointer to a khui_new_creds structure */ + d->nc = (khui_new_creds *) lParam; + khui_cw_find_type(d->nc, credtype_id_krb5, &nct); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM) d); +#pragma warning(pop) + + nct->aux = (LPARAM) d; + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_initialize(&d->tc_lifetime); + khui_tracker_initialize(&d->tc_renew); + + hw = GetDlgItem(hwnd, IDC_NCK5_LIFETIME_EDIT); + khui_tracker_install(hw, &d->tc_lifetime); + + hw = GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT); + khui_tracker_install(hw, &d->tc_renew); + } + return TRUE; +} + +INT_PTR +k5_handle_wm_destroy(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + k5_dlg_data * d; + khui_new_creds_by_type * nct = NULL; + + d = (k5_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + + khui_cw_find_type(d->nc, credtype_id_krb5, &nct); + +#ifdef DEBUG + assert(nct); +#endif + + nct->aux = 0; + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_lifetime); + } + + PFREE(d); + + return TRUE; +} + +INT_PTR +k5_handle_wmnc_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + switch(HIWORD(wParam)) { + case WMNC_DIALOG_MOVE: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS) { + khui_tracker_reposition(&d->tc_lifetime); + khui_tracker_reposition(&d->tc_renew); + } + + return TRUE; + } + break; + + case WMNC_DIALOG_SETUP: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d->nc->subtype == KMSG_CRED_PASSWORD) + return TRUE; + + /* need to update the controls with d->* */ + if(d->renewable) { + SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_SETCHECK, BST_CHECKED, + 0); + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), + TRUE); + } else { + SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_SETCHECK, BST_UNCHECKED, 0); + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), + FALSE); + } + + khui_tracker_refresh(&d->tc_lifetime); + khui_tracker_refresh(&d->tc_renew); + + if(d->forwardable) { + SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, + BM_SETCHECK, BST_CHECKED, 0); + } else { + SendDlgItemMessage(hwnd, IDC_NCK5_FORWARDABLE, + BM_SETCHECK, BST_UNCHECKED, 0); + } + } + break; + + case WMNC_UPDATE_CREDTEXT: + { + k5_dlg_data * d; + khui_new_creds * nc; + khui_new_creds_by_type * nct; + wchar_t sbuf[1024]; + wchar_t fbuf[256]; + wchar_t tbuf[256]; + size_t cbsize; + khm_int32 flags; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + nc = d->nc; + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(nct == NULL) + break; + + if(nct->credtext) + PFREE(nct->credtext); + nct->credtext = NULL; + + tbuf[0] = L'\0'; + + if (nc->n_identities > 0 && + KHM_SUCCEEDED(kcdb_identity_get_flags(nc->identities[0], + &flags)) && + (flags & KCDB_IDENT_FLAG_VALID) && + nc->subtype == KMSG_CRED_NEW_CREDS) { + + if (is_k5_identpro) + k5_get_realm_from_nc(nc, tbuf, ARRAYLENGTH(tbuf)); + else + GetDlgItemText(hwnd, IDC_NCK5_REALM, tbuf, + ARRAYLENGTH(tbuf)); + + /*TODO: if additional realms were specified, then those + must be listed as well */ + LoadString(hResModule, IDS_KRB5_CREDTEXT_0, + fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(sbuf, sizeof(sbuf), fbuf, + tbuf); + + StringCbLength(sbuf, sizeof(sbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = PMALLOC(cbsize); + + StringCbCopy(nct->credtext, cbsize, sbuf); + } else if (nc->n_identities > 0 && + nc->subtype == KMSG_CRED_PASSWORD) { + cbsize = sizeof(tbuf); + kcdb_identity_get_name(nc->identities[0], tbuf, &cbsize); + + LoadString(hResModule, IDS_KRB5_CREDTEXT_P0, + fbuf, ARRAYLENGTH(fbuf)); + StringCbPrintf(sbuf, sizeof(sbuf), fbuf, tbuf); + + StringCbLength(sbuf, sizeof(sbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = PMALLOC(cbsize); + + StringCbCopy(nct->credtext, cbsize, sbuf); + } else { + if (d->cred_message) { + StringCbLength(d->cred_message, KHUI_MAXCB_BANNER, + &cbsize); + cbsize += sizeof(wchar_t); + + nct->credtext = PMALLOC(cbsize); + + StringCbCopy(nct->credtext, cbsize, d->cred_message); + } + } + } + break; + + case WMNC_IDENTITY_CHANGE: + { + /* There has been a change of identity */ + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + kmq_post_sub_msg(k5_sub, KMSG_CRED, + KMSG_CRED_DIALOG_NEW_IDENTITY, + 0, (void *) d->nc); + } + break; + + case WMNC_DIALOG_PREPROCESS: + { + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if(d->dirty) { + kmq_post_sub_msg(k5_sub, KMSG_CRED, + KMSG_CRED_DIALOG_NEW_OPTIONS, + 0, (void *) d->nc); + + /* the above notification effectively takes + all our changes into account. The data we + have is no longer dirty */ + d->dirty = FALSE; + } + } + break; + } + + return 0; +} + +INT_PTR +k5_handle_wm_command(HWND hwnd, + WPARAM wParam, + LPARAM lParam) +{ + int cid; + int notif; + k5_dlg_data * d; + + d = (k5_dlg_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + cid = LOWORD(wParam); + notif = HIWORD(wParam); + + if(notif == BN_CLICKED && cid == IDC_NCK5_RENEWABLE) { + int c; + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_GETCHECK, 0, 0); + if(c==BST_CHECKED) { + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), TRUE); + d->renewable = TRUE; + } else { + EnableWindow(GetDlgItem(hwnd, IDC_NCK5_RENEW_EDIT), FALSE); + d->renewable = FALSE; + } + d->dirty = TRUE; + } else if(notif == BN_CLICKED && cid == IDC_NCK5_FORWARDABLE) { + int c; + c = (int) SendDlgItemMessage(hwnd, IDC_NCK5_RENEWABLE, + BM_GETCHECK, 0, 0); + if(c==BST_CHECKED) { + d->forwardable = TRUE; + } else { + d->forwardable = FALSE; + } + d->dirty = TRUE; + } else if((notif == CBN_SELCHANGE || + notif == CBN_KILLFOCUS) && + cid == IDC_NCK5_REALM && + !is_k5_identpro) { + /* find out what the realm of the current identity + is, and if they are the same, then we don't do + anything */ + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t realm[KCDB_IDENT_MAXCCH_NAME]; + wchar_t *r; + khm_size cbsize; + khm_handle ident; + int idx; + + if(d->nc->n_identities > 0) { + if(notif == CBN_SELCHANGE) { + idx = (int) SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_GETCURSEL, 0, 0); + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_GETLBTEXT, idx, (LPARAM) realm); + } else { + GetDlgItemText(hwnd, IDC_NCK5_REALM, + realm, ARRAYLENGTH(realm)); + } + cbsize = sizeof(idname); + if(KHM_SUCCEEDED(kcdb_identity_get_name(d->nc->identities[0], + idname, &cbsize))) { + r = wcschr(idname, L'@'); + if(r && !wcscmp(realm, r+1)) + return 0; /* nothing to do */ + + if(!r) { + r = idname + wcslen(idname); + *r++ = L'@'; + *r++ = 0; + } + + /* if we get here, we have a new user */ + StringCchCopy(r+1, + ARRAYLENGTH(idname) - ((r+1) - idname), + realm); + if(KHM_SUCCEEDED(kcdb_identity_create(idname, + KCDB_IDENT_FLAG_CREATE, + &ident))) { + khui_cw_set_primary_id(d->nc, ident); + kcdb_identity_release(ident); + } + return 0; + } + } + + /* if we get here, we have a new realm, but there is no + identity */ + PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + } + + return 0; +} + + +/* Dialog procedure for the Krb5 credentials type panel. + + NOTE: Runs in the context of the UI thread +*/ +INT_PTR CALLBACK +k5_nc_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_INITDIALOG: + return k5_handle_wm_initdialog(hwnd, wParam, lParam); + + case WM_COMMAND: + return k5_handle_wm_command(hwnd, wParam, lParam); + + case KHUI_WM_NC_NOTIFY: + return k5_handle_wmnc_notify(hwnd, wParam, lParam); + + case WM_DESTROY: + return k5_handle_wm_destroy(hwnd, wParam, lParam); + } + return FALSE; +} + +/* forward dcl */ +krb5_error_code KRB5_CALLCONV +k5_kinit_prompter(krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]); + + + +fiber_job g_fjob; /* global fiber job object */ + +static BOOL +k5_cached_kinit_prompter(void); + +static BOOL +k5_cp_check_continue(void); + +/* + Runs in the context of the krb5 plugin's slave fiber +*/ +VOID CALLBACK +k5_kinit_fiber_proc(PVOID lpParameter) +{ + while(TRUE) + { + if(g_fjob.command == FIBER_CMD_KINIT) { + g_fjob.state = FIBER_STATE_KINIT; + + g_fjob.prompt_set = 0; + + if (k5_cached_kinit_prompter()) { + SwitchToFiber(k5_main_fiber); + + if (g_fjob.command != FIBER_CMD_CONTINUE) + goto _switch_to_main; + + if (!k5_cp_check_continue()) { + g_fjob.code = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto _switch_to_main; + } + } + + g_fjob.code = khm_krb5_kinit( + 0, + g_fjob.principal, + g_fjob.password, + g_fjob.ccache, + g_fjob.lifetime, + g_fjob.forwardable, + g_fjob.proxiable, + (g_fjob.renewable ? g_fjob.renew_life : 0), + g_fjob.addressless, + g_fjob.publicIP, + k5_kinit_prompter, + &g_fjob); + } + + _switch_to_main: + g_fjob.state = FIBER_STATE_NONE; + + SwitchToFiber(k5_main_fiber); + } +} + +/* return TRUE if we should go ahead with creds acquisition */ +static BOOL +k5_cp_check_continue(void) { + khm_size i; + khm_size n_p; + khui_new_creds_prompt * p; + size_t cch; + +#ifdef DEBUG + assert(g_fjob.nc); +#endif + + if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, &n_p))) { +#ifdef DEBUG + assert(FALSE); +#endif + return TRUE; + } + + khui_cw_sync_prompt_values(g_fjob.nc); + + g_fjob.null_password = FALSE; + + /* we are just checking whether there was a password field that + was left empty, in which case we can't continue with the + credentials acquisition. */ + for (i=0; i < n_p; i++) { + if(KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, + (int) i, + &p))) + continue; + if(p->type == KHUI_NCPROMPT_TYPE_PASSWORD) { + if (p->value == NULL || + FAILED(StringCchLength(p->value, KHUI_MAXCCH_PROMPT, + &cch)) || + cch == 0) { + g_fjob.null_password = TRUE; + return FALSE; + } else + break; + } + } + + return TRUE; +} + +/* returns true if we find cached prompts */ +static BOOL +k5_cached_kinit_prompter(void) { + BOOL rv = FALSE; + khm_handle ident; + khm_handle csp_idconfig = NULL; + khm_handle csp_k5config = NULL; + khm_handle csp_prcache = NULL; + khm_size cb; + khm_size n_cur_prompts; + khm_int32 n_prompts; + khm_int32 i; + +#ifdef DEBUG + assert(g_fjob.nc); +#endif + + ident = g_fjob.identity; + if (!ident) + return FALSE; + + /* don't need to hold ident, since it is already held in g_fjob + and it doesn't change until we return */ + + if (KHM_FAILED(kcdb_identity_get_config(ident, 0, &csp_idconfig)) || + + KHM_FAILED(khc_open_space(csp_idconfig, CSNAME_KRB5CRED, + 0, &csp_k5config)) || + + KHM_FAILED(khc_open_space(csp_k5config, CSNAME_PROMPTCACHE, + 0, &csp_prcache)) || + + KHM_FAILED(khc_read_int32(csp_prcache, L"PromptCount", + &n_prompts)) || + n_prompts == 0) + + goto _cleanup; + + /* check if there are any prompts currently showing. If there are + we check if they are the same as the ones we are going to show. + In which case we just reuse the exisitng prompts */ + if (KHM_FAILED(khui_cw_get_prompt_count(g_fjob.nc, + &n_cur_prompts)) || + n_prompts != (khm_int32) n_cur_prompts) + goto _show_new_prompts; + + for(i = 0; i < n_prompts; i++) { + wchar_t wsname[8]; + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khm_handle csp_p = NULL; + khm_int32 p_type; + khm_int32 p_flags; + khui_new_creds_prompt * p; + + if (KHM_FAILED(khui_cw_get_prompt(g_fjob.nc, i, &p))) + break; + + StringCbPrintf(wsname, sizeof(wsname), L"%d", i); + + if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) + break; + + cb = sizeof(wprompt); + if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", + wprompt, &cb))) { + khc_close_space(csp_p); + break; + } + + if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) + p_type = 0; + + if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) + p_flags = 0; + + if ( /* if we received a prompt string, + then it should be the same as the + one that is displayed */ + (wprompt[0] && + (p->prompt == NULL || + wcscmp(wprompt, p->prompt))) || + + /* if we didn't receive one, then + there shouldn't be one displayed. + This case really shouldn't happen + in reality, but we check anyway. */ + (!wprompt[0] && + p->prompt != NULL) || + + /* the type should match */ + (p_type != p->type) || + + /* if this prompt should be hidden, + then it must also be so */ + (p_flags != p->flags) + ) { + + khc_close_space(csp_p); + break; + + } + + + khc_close_space(csp_p); + } + + if (i == n_prompts) { + rv = TRUE; + goto _cleanup; + } + + _show_new_prompts: + + khui_cw_clear_prompts(g_fjob.nc); + + { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wpname[KHUI_MAXCCH_PNAME]; + + cb = sizeof(wbanner); + if (KHM_FAILED(khc_read_string(csp_prcache, L"Banner", + wbanner, &cb))) + wbanner[0] = 0; + + cb = sizeof(wpname); + if (KHM_FAILED(khc_read_string(csp_prcache, L"Name", + wpname, &cb))) + wpname[0] = 0; + + khui_cw_begin_custom_prompts(g_fjob.nc, + n_prompts, + (wbanner[0]? wbanner: NULL), + (wpname[0]? wpname: NULL)); + } + + for(i = 0; i < n_prompts; i++) { + wchar_t wsname[8]; + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khm_handle csp_p = NULL; + khm_int32 p_type; + khm_int32 p_flags; + + StringCbPrintf(wsname, sizeof(wsname), L"%d", i); + + if (KHM_FAILED(khc_open_space(csp_prcache, wsname, 0, &csp_p))) + break; + + cb = sizeof(wprompt); + if (KHM_FAILED(khc_read_string(csp_p, L"Prompt", + wprompt, &cb))) { + khc_close_space(csp_p); + break; + } + + if (KHM_FAILED(khc_read_int32(csp_p, L"Type", &p_type))) + p_type = 0; + + if (KHM_FAILED(khc_read_int32(csp_p, L"Flags", &p_flags))) + p_flags = 0; + + khui_cw_add_prompt(g_fjob.nc, p_type, wprompt, NULL, p_flags); + + khc_close_space(csp_p); + } + + if (i < n_prompts) { + khui_cw_clear_prompts(g_fjob.nc); + } else { + rv = TRUE; + } + + _cleanup: + + if (csp_prcache) + khc_close_space(csp_prcache); + + if (csp_k5config) + khc_close_space(csp_k5config); + + if (csp_idconfig) + khc_close_space(csp_idconfig); + + return rv; +} + +/* Runs in the context of the Krb5 plugin's slave fiber */ +krb5_error_code KRB5_CALLCONV +k5_kinit_prompter(krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]) +{ + int i; + khui_new_creds * nc; + krb5_prompt_type * ptypes; + khm_size ncp; + krb5_error_code code = 0; + BOOL new_prompts = TRUE; + + khm_handle csp_prcache = NULL; + + nc = g_fjob.nc; + + if(pkrb5_get_prompt_types) + ptypes = pkrb5_get_prompt_types(context); + else + ptypes = NULL; + + /* check if we are already showing the right prompts */ + khui_cw_get_prompt_count(nc, &ncp); + + if (num_prompts != (int) ncp) + goto _show_new_prompts; + + for (i=0; i < num_prompts; i++) { + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + khui_new_creds_prompt * p; + + if(prompts[i].prompt) { + AnsiStrToUnicode(wprompt, sizeof(wprompt), + prompts[i].prompt); + } else { + wprompt[0] = 0; + } + + if (KHM_FAILED(khui_cw_get_prompt(nc, i, &p))) + break; + + if ( /* if we received a prompt string, + then it should be the same as the + one that is displayed */ + (wprompt[0] && + (p->prompt == NULL || + wcscmp(wprompt, p->prompt))) || + /* if we didn't receive one, then + there shouldn't be one displayed. + This case really shouldn't happen + in reality, but we check anyway. */ + (!wprompt[0] && + p->prompt != NULL) || + /* the type should match */ + (ptypes && + ptypes[i] != p->type) || + (!ptypes && + p->type != 0) || + /* if this prompt should be hidden, + then it must also be so */ + (prompts[i].hidden && + !(p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) || + (!prompts[i].hidden && + (p->flags & KHUI_NCPROMPT_FLAG_HIDDEN)) + ) + break; + } + + if (i < num_prompts) + goto _show_new_prompts; + + new_prompts = FALSE; + + /* ok. looks like we are already showing the same set of prompts + that we were supposed to show. Sync up the values and go + ahead. */ + khui_cw_sync_prompt_values(nc); + goto _process_prompts; + + _show_new_prompts: + /* special case. if there are no actual input controls involved, + then we have to show an alerter window and pass through */ + if (num_prompts == 0) { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wname[KHUI_MAXCCH_PNAME]; + wchar_t wident[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wmsg[KHUI_MAXCCH_MESSAGE]; + wchar_t wfmt[KHUI_MAXCCH_BANNER]; + khm_size cb; + + if (!banner) { + code = 0; + g_fjob.null_password = FALSE; + goto _exit; + } else { + AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); + } + + if (name) { + AnsiStrToUnicode(wname, sizeof(wname), name); + } else { + LoadString(hResModule, + IDS_KRB5_WARNING, + wname, + ARRAYLENGTH(wname)); + } + + cb = sizeof(wident); + if (KHM_FAILED(kcdb_identity_get_name(g_fjob.identity, wident, &cb))) + wident[0] = L'\0'; + + LoadString(hResModule, + IDS_KRB5_WARN_FMT, + wfmt, + ARRAYLENGTH(wfmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), wfmt, wident, wbanner); + + khui_alert_show_simple(wname, wmsg, KHERR_WARNING); + + code = 0; + g_fjob.null_password = FALSE; + goto _exit; + } + + /* in addition to showing new prompts, we also cache the set of + prompts. */ + if(g_fjob.prompt_set == 0) { + khm_handle csp_idconfig = NULL; + khm_handle csp_idk5 = NULL; + + kcdb_identity_get_config(g_fjob.identity, + KHM_FLAG_CREATE, + &csp_idconfig); + + if (csp_idconfig != NULL) + khc_open_space(csp_idconfig, + CSNAME_KRB5CRED, + KHM_FLAG_CREATE, + &csp_idk5); + + if (csp_idk5 != NULL) + khc_open_space(csp_idk5, + CSNAME_PROMPTCACHE, + KHM_FLAG_CREATE, + &csp_prcache); + + khc_close_space(csp_idconfig); + khc_close_space(csp_idk5); + } + + { + wchar_t wbanner[KHUI_MAXCCH_BANNER]; + wchar_t wname[KHUI_MAXCCH_PNAME]; + + if(banner) + AnsiStrToUnicode(wbanner, sizeof(wbanner), banner); + if(name) + AnsiStrToUnicode(wname, sizeof(wname), name); + + khui_cw_clear_prompts(nc); + + khui_cw_begin_custom_prompts( + nc, + num_prompts, + (banner)?wbanner:NULL, + (name)?wname:NULL); + + if (banner && csp_prcache) + khc_write_string(csp_prcache, + L"Banner", + wbanner); + else if (csp_prcache) + khc_write_string(csp_prcache, + L"Banner", + L""); + + if (name && csp_prcache) + khc_write_string(csp_prcache, + L"Name", + wname); + else if (csp_prcache) + khc_write_string(csp_prcache, + L"Name", + L""); + + if (csp_prcache) + khc_write_int32(csp_prcache, + L"PromptCount", + (khm_int32) num_prompts); + } + + for(i=0; i < num_prompts; i++) { + wchar_t wprompt[KHUI_MAXCCH_PROMPT]; + + if(prompts[i].prompt) { + AnsiStrToUnicode(wprompt, sizeof(wprompt), + prompts[i].prompt); + } else { + wprompt[0] = 0; + } + + khui_cw_add_prompt( + nc, + (ptypes?ptypes[i]:0), + wprompt, + NULL, + (prompts[i].hidden?KHUI_NCPROMPT_FLAG_HIDDEN:0)); + + if (csp_prcache) { + khm_handle csp_p = NULL; + wchar_t wnum[8]; /* should be enough for 10 + million prompts */ + + wnum[0] = 0; + StringCbPrintf(wnum, sizeof(wnum), L"%d", i); + + khc_open_space(csp_prcache, wnum, + KHM_FLAG_CREATE, &csp_p); + + if (csp_p) { + khc_write_string(csp_p, L"Prompt", wprompt); + khc_write_int32(csp_p, L"Type", (ptypes?ptypes[i]:0)); + khc_write_int32(csp_p, L"Flags", + (prompts[i].hidden? + KHUI_NCPROMPT_FLAG_HIDDEN:0)); + + khc_close_space(csp_p); + } + } + } + + if (csp_prcache) { + khc_close_space(csp_prcache); + csp_prcache = NULL; + } + + _process_prompts: + /* switch back to main thread if we showed new prompts */ + if (new_prompts) + SwitchToFiber(k5_main_fiber); + + /* we get here after the user selects an action that either + cancles the credentials acquisition operation or triggers the + actual acquisition of credentials. */ + if(g_fjob.command != FIBER_CMD_CONTINUE && + g_fjob.command != FIBER_CMD_KINIT) { + code = -2; + goto _exit; + } + + g_fjob.null_password = FALSE; + + /* otherwise, we need to get the data back from the UI and + return 0 */ + for(i=0; idata, d->length, wbuf); + if(SUCCEEDED(StringCchLengthA(d->data, d->length, &cch))) + d->length = (unsigned int) cch; + else + d->length = 0; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + d->length = 0; + } + + if (ptypes && + ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD && + d->length == 0) + + g_fjob.null_password = TRUE; + } + + _exit: + + g_fjob.prompt_set++; + + /* entering a NULL password is equivalent to cancelling out */ + if (g_fjob.null_password) + return -2; + else + return code; +} + + +void +k5_read_dlg_params(khm_handle conf, + k5_dlg_data * d) +{ + khm_int32 i; + + khc_read_int32(conf, L"Renewable", &d->renewable); + khc_read_int32(conf, L"Forwardable", &d->forwardable); + khc_read_int32(conf, L"Proxiable", &d->proxiable); + khc_read_int32(conf, L"Addressless", &d->addressless); + + khc_read_int32(conf, L"DefaultLifetime", &i); + d->tc_lifetime.current = i; + khc_read_int32(conf, L"MaxLifetime", &i); + d->tc_lifetime.max = i; + khc_read_int32(conf, L"MinLifetime", &i); + d->tc_lifetime.min = i; + + khc_read_int32(conf, L"DefaultRenewLifetime", &i); + d->tc_renew.current = i; + khc_read_int32(conf, L"MaxRenewLifetime", &i); + d->tc_renew.max = i; + khc_read_int32(conf, L"MinRenewLifetime", &i); + d->tc_renew.min = i; + + /* however, if this has externally supplied defaults, we have to + use them too. */ + if (d->nc && d->nc->ctx.vparam && + d->nc->ctx.cb_vparam == sizeof(NETID_DLGINFO)) { + LPNETID_DLGINFO pdlginfo; + + pdlginfo = (LPNETID_DLGINFO) d->nc->ctx.vparam; + if (pdlginfo->size == NETID_DLGINFO_V1_SZ && + pdlginfo->in.use_defaults == 0) { + d->forwardable = pdlginfo->in.forwardable; + d->addressless = pdlginfo->in.noaddresses; + d->tc_lifetime.current = pdlginfo->in.lifetime; + d->tc_renew.current = pdlginfo->in.renew_till; + + if (pdlginfo->in.renew_till == 0) + d->renewable = FALSE; + else + d->renewable = TRUE; + + d->proxiable = pdlginfo->in.proxiable; + d->publicIP = pdlginfo->in.publicip; + } + } + + /* once we read the new data, in, it is no longer considered + dirty */ + d->dirty = FALSE; +} + +void +k5_write_dlg_params(khm_handle conf, + k5_dlg_data * d) +{ + khc_write_int32(conf, L"Renewable", d->renewable); + khc_write_int32(conf, L"Forwardable", d->forwardable); + khc_write_int32(conf, L"Proxiable", d->proxiable); + khc_write_int32(conf, L"Addressless", d->addressless); + + khc_write_int32(conf, L"DefaultLifetime", + (khm_int32) d->tc_lifetime.current); + khc_write_int32(conf, L"MaxLifetime", + (khm_int32) d->tc_lifetime.max); + khc_write_int32(conf, L"MinLifetime", + (khm_int32) d->tc_lifetime.min); + + khc_write_int32(conf, L"DefaultRenewLifetime", + (khm_int32) d->tc_renew.current); + khc_write_int32(conf, L"MaxRenewLifetime", + (khm_int32) d->tc_renew.max); + khc_write_int32(conf, L"MinRenewLifetime", + (khm_int32) d->tc_renew.min); + + /* as in k5_read_dlg_params, once we write the data in, the local + data is no longer dirty */ + d->dirty = FALSE; +} + +void +k5_prep_kinit_job(khui_new_creds * nc) +{ + khui_new_creds_by_type * nct; + k5_dlg_data * d; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cbbuf; + size_t size; + khm_handle ident; + LPNETID_DLGINFO pdlginfo; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + return; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + khui_cw_lock_nc(nc); + ident = nc->identities[0]; + kcdb_identity_hold(ident); + khui_cw_unlock_nc(nc); + + cbbuf = sizeof(idname); + kcdb_identity_get_name(ident, idname, &cbbuf); + StringCchLength(idname, ARRAYLENGTH(idname), &size); + size++; + + ZeroMemory(&g_fjob, sizeof(g_fjob)); + g_fjob.command = FIBER_CMD_KINIT; + g_fjob.nc = nc; + g_fjob.nct = nct; + g_fjob.dialog = nct->hwnd_panel; + g_fjob.principal = PMALLOC(size); + UnicodeStrToAnsi(g_fjob.principal, size, idname); + g_fjob.password = NULL; + g_fjob.lifetime = (krb5_deltat) d->tc_lifetime.current; + g_fjob.forwardable = d->forwardable; + g_fjob.proxiable = d->proxiable; + g_fjob.renewable = d->renewable; + g_fjob.renew_life = (krb5_deltat) d->tc_renew.current; + g_fjob.addressless = d->addressless; + g_fjob.publicIP = 0; + g_fjob.code = 0; + g_fjob.identity = ident; + g_fjob.prompt_set = 0; + + /* if we have external parameters, we should use them as well */ + if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && + (pdlginfo = nc->ctx.vparam) && + pdlginfo->size == NETID_DLGINFO_V1_SZ) { + wchar_t * t; + + if (pdlginfo->in.ccache[0] && + SUCCEEDED(StringCchLength(pdlginfo->in.ccache, + NETID_CCACHE_NAME_SZ, + &size))) { + g_fjob.ccache = PMALLOC(sizeof(char) * (size + 1)); +#ifdef DEBUG + assert(g_fjob.ccache); +#endif + UnicodeStrToAnsi(g_fjob.ccache, size + 1, + pdlginfo->in.ccache); + + /* this is the same as the output cache */ + + StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), + pdlginfo->in.ccache); + } else { + g_fjob.ccache = NULL; + + StringCbCopy(pdlginfo->out.ccache, sizeof(pdlginfo->out.ccache), + idname); + + khm_krb5_canon_cc_name(pdlginfo->out.ccache, + sizeof(pdlginfo->out.ccache)); + } + + t = khm_get_realm_from_princ(idname); + + if (t) { + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + t); + + if ((t - idname) > 1) { + StringCchCopyN(pdlginfo->out.username, + ARRAYLENGTH(pdlginfo->out.username), + idname, + (t - idname) - 1); + } else { + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + L""); + } + } else { + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + idname); + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + L""); + } + } + + /* leave identity held, since we added a reference above */ +} + +void +k5_free_kinit_job(void) +{ + if (g_fjob.principal) + PFREE(g_fjob.principal); + + if (g_fjob.password) + PFREE(g_fjob.password); + + if (g_fjob.identity) + kcdb_identity_release(g_fjob.identity); + + if (g_fjob.ccache) + PFREE(g_fjob.ccache); + + ZeroMemory(&g_fjob, sizeof(g_fjob)); +} + +static khm_int32 KHMAPI +k5_find_tgt_filter(khm_handle cred, + khm_int32 flags, + void * rock) { + khm_handle ident = (khm_handle) rock; + khm_handle cident = NULL; + khm_int32 f; + khm_int32 rv; + + if (KHM_SUCCEEDED(kcdb_cred_get_identity(cred, + &cident)) && + cident == ident && + KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &f)) && + (f & KCDB_CRED_FLAG_INITIAL)) + rv = 1; + else + rv = 0; + + if (cident) + kcdb_identity_release(cident); + + return rv; +} + +/* Handler for CRED type messages + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI +k5_msg_cred_dialog(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + + case KMSG_CRED_PASSWORD: + case KMSG_CRED_NEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + wchar_t wbuf[256]; + size_t cbsize; + + nc = (khui_new_creds *) vparam; + + nct = PMALLOC(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb5; + nct->ordinal = 1; + + LoadString(hResModule, IDS_KRB5_NC_NAME, + wbuf, ARRAYLENGTH(wbuf)); + StringCbLength(wbuf, sizeof(wbuf), &cbsize); + cbsize += sizeof(wchar_t); + + nct->name = PMALLOC(cbsize); + StringCbCopy(nct->name, cbsize, wbuf); + + nct->h_module = hResModule; + nct->dlg_proc = k5_nc_dlg_proc; + if (nc->subtype == KMSG_CRED_PASSWORD) + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5_PASSWORD); + else + nct->dlg_template = MAKEINTRESOURCE(IDD_NC_KRB5); + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_RENEW_CREDS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + nc = (khui_new_creds *) vparam; + + nct = PMALLOC(sizeof(*nct)); + ZeroMemory(nct, sizeof(*nct)); + + nct->type = credtype_id_krb5; + + khui_cw_add_type(nc, nct); + } + break; + + case KMSG_CRED_DIALOG_PRESTART: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + HWND hwnd; + wchar_t * realms; + wchar_t * t; + wchar_t * defrealm; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + hwnd = nct->hwnd_panel; + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + if (!is_k5_identpro) { + + /* enumerate all realms and place in realms combo box */ + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_RESETCONTENT, + 0, 0); + + realms = khm_krb5_get_realm_list(); + if(realms) { + for (t = realms; t && *t; t = multi_string_next(t)) { + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_ADDSTRING, + 0, (LPARAM) t); + } + PFREE(realms); + } + + /* and set the default realm */ + defrealm = khm_krb5_get_default_realm(); + if(defrealm) { + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + CB_SELECTSTRING, + (WPARAM) -1, + (LPARAM) defrealm); + + SendDlgItemMessage(hwnd, IDC_NCK5_REALM, + WM_SETTEXT, + 0, (LPARAM) defrealm); + PFREE(defrealm); + } + } else { /* if krb5 is the identity provider */ + HWND hw_realms; + + /* in this case, the realm selection is done by the + identity provider prompts. */ + + hw_realms = GetDlgItem(hwnd, IDC_NCK5_REALM); +#ifdef DEBUG + assert(hw_realms); +#endif + EnableWindow(hw_realms, FALSE); + } + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + k5_read_dlg_params(csp_params, d); + } + + PostMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); + } + break; + + case KMSG_CRED_DIALOG_NEW_IDENTITY: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + break; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + /* we only load the identity specific defaults if the user + hasn't changed the options */ + khui_cw_lock_nc(nc); + + if(!d->dirty && nc->n_identities > 0 && + nc->subtype == KMSG_CRED_NEW_CREDS) { + + khm_handle h_id = NULL; + khm_handle h_idk5 = NULL; + + do { + if(KHM_FAILED + (kcdb_identity_get_config(nc->identities[0], + 0, + &h_id))) + break; + + if(KHM_FAILED + (khc_open_space(h_id, CSNAME_KRB5CRED, + 0, &h_idk5))) + break; + + if(KHM_FAILED(khc_shadow_space(h_idk5, csp_params))) + break; + + k5_read_dlg_params(h_idk5, d); + + PostMessage(nct->hwnd_panel, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); + } while(FALSE); + + if(h_id) + khc_close_space(h_id); + if(h_idk5) + khc_close_space(h_idk5); + } + + khui_cw_unlock_nc(nc); + } + + /* fallthrough */ + case KMSG_CRED_DIALOG_NEW_OPTIONS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + if (!nct) + break; + + d = (k5_dlg_data *)(LONG_PTR) + GetWindowLongPtr(nct->hwnd_panel, DWLP_USER); + + if (nc->subtype == KMSG_CRED_PASSWORD) { + khm_size n_prompts = 0; + + khui_cw_get_prompt_count(nc, &n_prompts); + + if (nc->n_identities == 0) { + if (n_prompts) + khui_cw_clear_prompts(nc); + } else if (n_prompts != 3) { + wchar_t wbuf[KHUI_MAXCCH_BANNER]; + + khui_cw_clear_prompts(nc); + + LoadString(hResModule, IDS_NC_PWD_BANNER, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_begin_custom_prompts(nc, 3, NULL, wbuf); + + LoadString(hResModule, IDS_NC_PWD_PWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + + LoadString(hResModule, IDS_NC_PWD_NPWD_AGAIN, + wbuf, ARRAYLENGTH(wbuf)); + khui_cw_add_prompt(nc, KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN, + wbuf, NULL, KHUI_NCPROMPT_FLAG_HIDDEN); + } + + return KHM_ERROR_SUCCESS; + } + /* else; nc->subtype == KMSG_CRED_NEW_CREDS */ + + assert(nc->subtype == KMSG_CRED_NEW_CREDS); + + /* if the fiber is already in a kinit, cancel it */ + if(g_fjob.state == FIBER_STATE_KINIT) { + g_fjob.command = FIBER_CMD_CANCEL; + SwitchToFiber(k5_kinit_fiber); + /* we get here when the cancel operation completes */ + k5_free_kinit_job(); + } + + khui_cw_lock_nc(nc); + + if(nc->n_identities > 0) { + khm_handle ident = nc->identities[0]; + + kcdb_identity_hold(ident); + + k5_prep_kinit_job(nc); + khui_cw_unlock_nc(nc); + + SwitchToFiber(k5_kinit_fiber); + /* we get here when the fiber switches back */ + if(g_fjob.state == FIBER_STATE_NONE) { + wchar_t msg[KHUI_MAXCCH_BANNER]; + khm_size cb; + + /* we can't possibly have succeeded without a + password */ + if(g_fjob.code) { + if (is_k5_identpro) + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_INVALID, + KCDB_IDENT_FLAG_INVALID); + + khui_cw_clear_prompts(nc); + } + + if (d->cred_message) { + PFREE(d->cred_message); + d->cred_message = NULL; + } + + msg[0] = L'\0'; + + switch(g_fjob.code) { + case KRB5KDC_ERR_NAME_EXP: + /* principal expired */ + LoadString(hResModule, IDS_K5ERR_NAME_EXPIRED, + msg, ARRAYLENGTH(msg)); + break; + + case KRB5KDC_ERR_KEY_EXP: + /* password needs changing */ + LoadString(hResModule, IDS_K5ERR_KEY_EXPIRED, + msg, ARRAYLENGTH(msg)); + break; + + default: + { + DWORD dw_dummy; + kherr_suggestion sug_dummy; + wchar_t fmt[KHUI_MAXCCH_BANNER]; + wchar_t desc[KHUI_MAXCCH_BANNER]; + + LoadString(hResModule, IDS_K5ERR_FMT, + fmt, ARRAYLENGTH(fmt)); + + khm_err_describe(g_fjob.code, + desc, + sizeof(desc), + &dw_dummy, + &sug_dummy); + + StringCbPrintf(msg, sizeof(msg), fmt, desc); + } + } + + if (msg[0]) { + StringCbLength(msg, sizeof(msg), &cb); + cb += sizeof(wchar_t); + + d->cred_message = PMALLOC(cb); + StringCbCopy(d->cred_message, cb, msg); + } + + k5_free_kinit_job(); + + } else if(g_fjob.state == FIBER_STATE_KINIT) { + /* this is what we want. Leave the fiber there. */ + + if(is_k5_identpro) + kcdb_identity_set_flags(ident, + KCDB_IDENT_FLAG_VALID, + KCDB_IDENT_FLAG_VALID); + } else { + /* huh?? */ +#ifdef DEBUG + assert(FALSE); +#endif + } + + /* since the attributes of the identity have changed, + we should update the cred text as well */ + kcdb_identity_release(ident); + khui_cw_lock_nc(nc); + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + } else { + khui_cw_unlock_nc(nc); + khui_cw_clear_prompts(nc); + khui_cw_lock_nc(nc); + } + + khui_cw_unlock_nc(nc); + } + break; + + case KMSG_CRED_PROCESS: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + k5_dlg_data * d; + + khm_int32 r; + + nc = (khui_new_creds *) vparam; + + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + /* reset the null_password flag, just in case */ + g_fjob.null_password = FALSE; + + if (nc->subtype == KMSG_CRED_NEW_CREDS) { + d = (k5_dlg_data *) nct->aux; + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_INITAL_CREDS); + _describe(); + + if (g_fjob.state == FIBER_STATE_KINIT) { + if(nc->result == KHUI_NC_RESULT_CANCEL) { + g_fjob.command = FIBER_CMD_CANCEL; + SwitchToFiber(k5_kinit_fiber); + + /* if we cancelled out, then we shouldn't care + about the return code. */ +#ifdef DEBUG + assert(g_fjob.state == FIBER_STATE_NONE); +#endif + g_fjob.code = 0; + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) { + khui_cw_sync_prompt_values(nc); + g_fjob.command = FIBER_CMD_CONTINUE; + SwitchToFiber(k5_kinit_fiber); + + /* We get back here once the fiber finishes + processing */ + } +#ifdef DEBUG + else { + assert(FALSE); + } +#endif + } else { + /* we weren't in a KINIT state */ + if (nc->result == KHUI_NC_RESULT_CANCEL) { + /* nothing to report */ + g_fjob.code = 0; + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS) { + /* g_fjob.code should have the result of the + last kinit attempt. We should leave it + as-is */ + } +#ifdef DEBUG + else { + /* unknown result */ + assert(FALSE); + } +#endif + } + + /* special case: if there was no password entered, and + if there is a valid TGT we allow the credential + acquisition to go through */ + if (g_fjob.state == FIBER_STATE_NONE && + g_fjob.code && + g_fjob.null_password && + + (nc->n_identities == 0 || + nc->identities[0] == NULL || + KHM_SUCCEEDED(kcdb_credset_find_filtered + (NULL, + -1, + k5_find_tgt_filter, + nc->identities[0], + NULL, + NULL)))) + g_fjob.code = 0; + + if(g_fjob.code != 0) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion suggest_code; + + khm_err_describe(g_fjob.code, tbuf, sizeof(tbuf), + &suggestion, &suggest_code); + + _report_cs0(KHERR_ERROR, tbuf); + if (suggestion != 0) + _suggest_mr(suggestion, suggest_code); + + _resolve(); + + r = KHUI_NC_RESPONSE_FAILED; + + if (suggest_code == KHERR_SUGGEST_RETRY) { + r |= KHUI_NC_RESPONSE_NOEXIT | + KHUI_NC_RESPONSE_PENDING; + } + +#ifdef DEBUG + assert(g_fjob.state == FIBER_STATE_NONE); +#endif + + } else if (nc->result == KHUI_NC_RESULT_GET_CREDS && + g_fjob.state == FIBER_STATE_NONE) { + khm_handle sp = NULL; + khm_handle ep = NULL; + krb5_context ctx = NULL; + wchar_t * wbuf; + wchar_t * idname; + wchar_t * atsign; + khm_size cb; + khm_size cb_ms; + khm_int32 rv; + + r = KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT; + + /* if we successfully obtained credentials, we + should save the current settings in the + identity config space */ + + assert(nc->n_identities > 0); + assert(nc->identities[0]); + + if(KHM_SUCCEEDED + (kcdb_identity_get_config(nc->identities[0], + KHM_FLAG_CREATE, + &sp)) && + KHM_SUCCEEDED + (khc_open_space(sp, CSNAME_KRB5CRED, + KHM_FLAG_CREATE, &ep))) { + k5_write_dlg_params(ep, d); + } + + if(ep != NULL) + khc_close_space(ep); + if(sp != NULL) + khc_close_space(sp); + + /* We should also quickly refresh the credentials + so that the identity flags and ccache + properties reflect the current state of + affairs. This has to be done here so that + other credentials providers which depend on + Krb5 can properly find the initial creds to + obtain their respective creds. */ + + khm_krb5_list_tickets(&ctx); + + if (nc->set_default) { + kcdb_identity_set_default(nc->identities[0]); + } + + /* If there is no default identity, then make this the default */ + kcdb_identity_refresh(nc->identities[0]); + { + khm_handle tdefault = NULL; + + if (KHM_SUCCEEDED(kcdb_identity_get_default(&tdefault))) { + kcdb_identity_release(tdefault); + } else { + kcdb_identity_set_default(nc->identities[0]); + } + } + + /* also add the principal and the realm in to the + LRU lists */ + rv = kcdb_identity_get_name(nc->identities[0], + NULL, + &cb); + assert(rv == KHM_ERROR_TOO_LONG); + + idname = PMALLOC(cb); + assert(idname); + + rv = kcdb_identity_get_name(nc->identities[0], + idname, + &cb); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + NULL, + &cb_ms); + if (rv != KHM_ERROR_TOO_LONG) + cb_ms = cb + sizeof(wchar_t); + else + cb_ms += cb + sizeof(wchar_t); + + wbuf = PMALLOC(cb_ms); + assert(wbuf); + + cb = cb_ms; + + if (rv == KHM_ERROR_TOO_LONG) { + rv = khc_read_multi_string(csp_params, + L"LRUPrincipals", + wbuf, + &cb); + assert(KHM_SUCCEEDED(rv)); + + if (multi_string_find(wbuf, + idname, + KHM_CASE_SENSITIVE) + != NULL) { + /* it's already there. We remove it here + and add it at the top of the LRU + list. */ + multi_string_delete(wbuf, idname, KHM_CASE_SENSITIVE); + } + } else { + multi_string_init(wbuf, cb_ms); + } + + cb = cb_ms; + rv = multi_string_prepend(wbuf, &cb, idname); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_multi_string(csp_params, + L"LRUPrincipals", + wbuf); + + atsign = wcschr(idname, L'@'); + if (atsign == NULL) + goto _done_with_LRU; + + atsign++; + + if (*atsign == L'\0') + goto _done_with_LRU; + + cb = cb_ms; + rv = khc_read_multi_string(csp_params, + L"LRURealms", + wbuf, + &cb); + + if (rv == KHM_ERROR_TOO_LONG) { + PFREE(wbuf); + wbuf = PMALLOC(cb); + assert(wbuf); + + cb_ms = cb; + + rv = khc_read_multi_string(csp_params, + L"LRURealms", + wbuf, + &cb); + + assert(KHM_SUCCEEDED(rv)); + } else if (rv == KHM_ERROR_SUCCESS) { + if (multi_string_find(wbuf, + atsign, + KHM_CASE_SENSITIVE) + != NULL) { + /* remove the realm and add it at the top + later. */ + multi_string_delete(wbuf, atsign, KHM_CASE_SENSITIVE); + } + } else { + multi_string_init(wbuf, cb_ms); + } + + cb = cb_ms; + rv = multi_string_prepend(wbuf, + &cb, + atsign); + + if (rv == KHM_ERROR_TOO_LONG) { + wbuf = PREALLOC(wbuf, cb); + + rv = multi_string_prepend(wbuf, + &cb, + atsign); + + assert(KHM_SUCCEEDED(rv)); + } + + rv = khc_write_multi_string(csp_params, + L"LRURealms", + wbuf); + assert(KHM_SUCCEEDED(rv)); + + _done_with_LRU: + + if (ctx != NULL) + pkrb5_free_context(ctx); + + if (idname) + PFREE(idname); + + if (wbuf) + PFREE(wbuf); + + } else if (g_fjob.state == FIBER_STATE_NONE) { + /* the user cancelled the operation */ + r = KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS; + } + + if(g_fjob.state == FIBER_STATE_NONE) { + khui_cw_set_response(nc, credtype_id_krb5, r); + + if (r & KHUI_NC_RESPONSE_NOEXIT) { + /* if we are retrying the call, we should + restart the kinit fiber */ +#ifdef DEBUG + assert(r & KHUI_NC_RESPONSE_PENDING); +#endif + + k5_prep_kinit_job(nc); + SwitchToFiber(k5_kinit_fiber); + } else { + /* free up the fiber data fields. */ + k5_free_kinit_job(); + } + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_NOEXIT | + KHUI_NC_RESPONSE_PENDING | r); + } + + _end_task(); + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + + FILETIME ftidexp = {0,0}; + FILETIME ftcurrent; + khm_size cb; + + GetSystemTimeAsFileTime(&ftcurrent); + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_RENEW_CREDS); + _describe(); + + if (nc->ctx.scope == KHUI_SCOPE_IDENT || + (nc->ctx.scope == KHUI_SCOPE_CREDTYPE && + nc->ctx.cred_type == credtype_id_krb5)) { + int code; + + if (nc->ctx.identity != 0) { + /* get the current identity expiration time */ + cb = sizeof(ftidexp); + + kcdb_identity_get_attr(nc->ctx.identity, + KCDB_ATTR_EXPIRE, + NULL, + &ftidexp, + &cb); + + code = khm_krb5_renew(nc->ctx.identity); + } else { + code = 1; /* it just has to be non-zero */ + } + + if (code == 0) { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } else if (nc->ctx.identity == 0) { + + _report_mr0(KHERR_ERROR, MSG_ERR_NO_IDENTITY); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_FAILED); + } else if (CompareFileTime(&ftcurrent, &ftidexp) < 0) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + /* if we failed to get new tickets, but the + identity isstill valid, then we assume that + the current tickets are still good enough + for other credential types to obtain their + credentials. */ + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + + _report_cs0(KHERR_WARNING, tbuf); + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } else { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + + _report_cs0(KHERR_ERROR, tbuf); + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + + khui_cw_set_response(nc, credtype_id_krb5, + ((sug_id == KHERR_SUGGEST_RETRY)?KHUI_NC_RESPONSE_NOEXIT:KHUI_NC_RESPONSE_EXIT) | + KHUI_NC_RESPONSE_FAILED); + } + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_EXIT | + KHUI_NC_RESPONSE_SUCCESS); + } + + _end_task(); + } else if (nc->subtype == KMSG_CRED_PASSWORD && + nc->result == KHUI_NC_RESULT_GET_CREDS) { + + _begin_task(0); + _report_mr0(KHERR_NONE, MSG_CTX_PASSWD); + _describe(); + + khui_cw_lock_nc(nc); + + if (nc->n_identities == 0 || + nc->identities[0] == NULL) { + _report_mr0(KHERR_ERROR, MSG_PWD_NO_IDENTITY); + _suggest_mr(MSG_PWD_S_NO_IDENTITY, KHERR_SUGGEST_RETRY); + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_FAILED | + KHUI_NC_RESPONSE_NOEXIT); + } else { + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + char idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wpwd[KHUI_MAXCCH_PASSWORD]; + char pwd[KHUI_MAXCCH_PASSWORD]; + wchar_t wnpwd[KHUI_MAXCCH_PASSWORD]; + char npwd[KHUI_MAXCCH_PASSWORD]; + wchar_t wnpwd2[KHUI_MAXCCH_PASSWORD]; + wchar_t * wresult; + char * result; + khm_size n_prompts = 0; + khm_size cb; + khm_int32 rv = KHM_ERROR_SUCCESS; + long code = 0; + khm_handle ident; + + khui_cw_get_prompt_count(nc, &n_prompts); + assert(n_prompts == 3); + + ident = nc->identities[0]; + cb = sizeof(widname); + rv = kcdb_identity_get_name(ident, widname, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wpwd); + rv = khui_cw_get_prompt_value(nc, 0, wpwd, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wnpwd); + rv = khui_cw_get_prompt_value(nc, 1, wnpwd, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + cb = sizeof(wnpwd2); + rv = khui_cw_get_prompt_value(nc, 2, wnpwd2, &cb); + if (KHM_FAILED(rv)) { +#ifdef DEBUG + assert(FALSE); +#endif + _report_mr0(KHERR_ERROR, MSG_PWD_UNKNOWN); + goto _pwd_exit; + } + + if (wcscmp(wnpwd, wnpwd2)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr0(KHERR_ERROR, MSG_PWD_NOT_SAME); + _suggest_mr(MSG_PWD_S_NOT_SAME, KHERR_SUGGEST_INTERACT); + goto _pwd_exit; + } + + if (!wcscmp(wpwd, wnpwd)) { + rv = KHM_ERROR_INVALID_PARAM; + _report_mr0(KHERR_ERROR, MSG_PWD_SAME); + _suggest_mr(MSG_PWD_S_SAME, KHERR_SUGGEST_INTERACT); + goto _pwd_exit; + } + + UnicodeStrToAnsi(idname, sizeof(idname), widname); + UnicodeStrToAnsi(pwd, sizeof(pwd), wpwd); + UnicodeStrToAnsi(npwd, sizeof(npwd), wnpwd); + + result = NULL; + + code = khm_krb5_changepwd(idname, + pwd, + npwd, + &result); + + if (code) + rv = KHM_ERROR_UNKNOWN; + + /* result is only set when code != 0 */ + if (code && result) { + size_t len; + + StringCchLengthA(result, KHERR_MAXCCH_STRING, + &len); + wresult = PMALLOC((len + 1) * sizeof(wchar_t)); +#ifdef DEBUG + assert(wresult); +#endif + AnsiStrToUnicode(wresult, (len + 1) * sizeof(wchar_t), + result); + + _report_cs1(KHERR_ERROR, L"%1!s!", _cstr(wresult)); + _resolve(); + + PFREE(result); + PFREE(wresult); + + /* leave wresult. It will get freed when the + reported event is freed. */ + + /* we don't need to report anything more */ + code = 0; + } + + _pwd_exit: + if (KHM_FAILED(rv)) { + if (code) { + wchar_t tbuf[1024]; + DWORD suggestion; + kherr_suggestion sug_id; + + khm_err_describe(code, tbuf, sizeof(tbuf), + &suggestion, &sug_id); + _report_cs0(KHERR_ERROR, tbuf); + + if (suggestion) + _suggest_mr(suggestion, sug_id); + + _resolve(); + } + + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_NOEXIT| + KHUI_NC_RESPONSE_FAILED); + } else { + khui_cw_set_response(nc, credtype_id_krb5, + KHUI_NC_RESPONSE_SUCCESS | + KHUI_NC_RESPONSE_EXIT); + } + } + + khui_cw_unlock_nc(nc); + + _end_task(); + } /* KMSG_CRED_PASSWORD */ + } + break; + + case KMSG_CRED_END: + { + khui_new_creds * nc; + khui_new_creds_by_type * nct; + + nc = (khui_new_creds *) vparam; + khui_cw_find_type(nc, credtype_id_krb5, &nct); + + if(!nct) + break; + + khui_cw_del_type(nc, credtype_id_krb5); + + if (nct->name) + PFREE(nct->name); + if (nct->credtext) + PFREE(nct->credtext); + + PFREE(nct); + } + break; + + case KMSG_CRED_IMPORT: + { + khm_int32 t = 0; + +#ifdef DEBUG + assert(csp_params); +#endif + khc_read_int32(csp_params, L"MsLsaImport", &t); + + if (t == 1) + khm_krb5_ms2mit(TRUE); + } + break; + } + + return rv; +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5plugin.c b/mechglue/src/windows/identity/plugins/krb5/krb5plugin.c new file mode 100644 index 000000000..e58e69f34 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5plugin.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#include +#endif + +khm_int32 credtype_id_krb5 = KCDB_CREDTYPE_INVALID; +khm_boolean krb5_initialized = FALSE; +khm_handle krb5_credset = NULL; + +khm_handle k5_sub = NULL; + +LPVOID k5_main_fiber = NULL; +LPVOID k5_kinit_fiber = NULL; + +VOID CALLBACK k5_kinit_fiber_proc(PVOID lpParameter); + +krb5_context k5_identpro_ctx = NULL; + +/* The system message handler. + + Runs in the context of the plugin thread */ +khm_int32 KHMAPI +k5_msg_system(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_SYSTEM_INIT: + { + kcdb_credtype ct; + wchar_t buf[KCDB_MAXCCH_SHORT_DESC]; + size_t cbsize; + + /* perform critical registrations and initialization + stuff */ + ZeroMemory(&ct, sizeof(ct)); + ct.id = KCDB_CREDTYPE_AUTO; + ct.name = KRB5_CREDTYPE_NAME; + + if(LoadString(hResModule, IDS_KRB5_SHORT_DESC, + buf, ARRAYLENGTH(buf))) { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.short_desc = PMALLOC(cbsize); + StringCbCopy(ct.short_desc, cbsize, buf); + } + + /* even though ideally we should be setting limits + based KCDB_MAXCB_LONG_DESC, our long description + actually fits nicely in KCDB_MAXCB_SHORT_DESC */ + if(LoadString(hResModule, IDS_KRB5_LONG_DESC, + buf, ARRAYLENGTH(buf))) { + StringCbLength(buf, KCDB_MAXCB_SHORT_DESC, &cbsize); + cbsize += sizeof(wchar_t); + ct.long_desc = PMALLOC(cbsize); + StringCbCopy(ct.long_desc, cbsize, buf); + } + + ct.icon = NULL; /* TODO: set a proper icon */ + + kmq_create_subscription(k5_msg_callback, &ct.sub); + + ct.is_equal = khm_krb5_creds_is_equal; + + rv = kcdb_credtype_register(&ct, &credtype_id_krb5); + + if(KHM_SUCCEEDED(rv)) + rv = kcdb_credset_create(&krb5_credset); + + if(ct.short_desc) + PFREE(ct.short_desc); + + if(ct.long_desc) + PFREE(ct.long_desc); + + if(KHM_SUCCEEDED(rv)) { + krb5_context ctx = NULL; + + krb5_initialized = TRUE; + + if(ctx != NULL) + pkrb5_free_context(ctx); + + /* now convert this thread to a fiber and create a + separate fiber to do kinit stuff */ + k5_main_fiber = ConvertThreadToFiber(NULL); + k5_kinit_fiber = CreateFiber(0,k5_kinit_fiber_proc,NULL); + + ZeroMemory(&g_fjob, sizeof(g_fjob)); + + kmq_create_subscription(k5_msg_callback, &k5_sub); + + k5_register_config_panels(); + + khm_krb5_list_tickets(&ctx); + } + } + break; + + case KMSG_SYSTEM_EXIT: + + k5_unregister_config_panels(); + + if(credtype_id_krb5 >= 0) + { + /* basically just unregister the credential type */ + kcdb_credtype_unregister(credtype_id_krb5); + + /* kcdb knows how to deal with bad handles */ + kcdb_credset_delete(krb5_credset); + krb5_credset = NULL; + } + + if(k5_main_fiber != NULL) { + + if (k5_kinit_fiber) { +#ifdef DEBUG + assert(k5_kinit_fiber != GetCurrentFiber()); +#endif +#if CLEANUP_FIBERS_ON_EXIT + DeleteFiber(k5_kinit_fiber); + CloseHandle(k5_kinit_fiber); +#endif + k5_kinit_fiber = NULL; + } + + k5_main_fiber = NULL; + + } + + if(k5_sub != NULL) { + kmq_delete_subscription(k5_sub); + k5_sub = NULL; + } + + break; + } + + return rv; +} + + +/* Handler for CRED type messages + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI +k5_msg_cred(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + switch(msg_subtype) { + case KMSG_CRED_REFRESH: + { + krb5_context ctx = NULL; + + khm_krb5_list_tickets(&ctx); + + if(ctx != NULL) + pkrb5_free_context(ctx); + } + break; + + case KMSG_CRED_DESTROY_CREDS: + { + khui_action_context * ctx; + + ctx = (khui_action_context *) vparam; + + if (ctx->credset) + khm_krb5_destroy_by_credset(ctx->credset); + } + break; + + case KMSG_CRED_PP_BEGIN: + k5_pp_begin((khui_property_sheet *) vparam); + break; + + case KMSG_CRED_PP_END: + k5_pp_end((khui_property_sheet *) vparam); + break; + + default: + if(IS_CRED_ACQ_MSG(msg_subtype)) + return k5_msg_cred_dialog(msg_type, msg_subtype, + uparam, vparam); + } + + return rv; +} + +/* The main message handler. We don't do much here, except delegate + to other message handlers + + Runs in the context of the Krb5 plugin +*/ +khm_int32 KHMAPI +k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, + khm_ui_4 uparam, void * vparam) +{ + switch(msg_type) { + case KMSG_SYSTEM: + return k5_msg_system(msg_type, msg_subtype, uparam, vparam); + case KMSG_CRED: + return k5_msg_cred(msg_type, msg_subtype, uparam, vparam); + } + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5props.c b/mechglue/src/windows/identity/plugins/krb5/krb5props.c new file mode 100644 index 000000000..0d8d27276 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5props.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include +#include +#ifdef DEBUG +#include +#endif + +/* Property page + + Runs in the context of the UI thread. + */ +INT_PTR CALLBACK krb5_pp_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_INITDIALOG: + { + khui_property_sheet * s; + PROPSHEETPAGE * p; + wchar_t buf[512]; + wchar_t unavailable[64]; + khm_size cbsize; + khm_int32 rv; + khm_int32 tflags; + + p = (PROPSHEETPAGE *) lParam; + s = (khui_property_sheet *) p->lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); +#pragma warning(pop) + + LoadString(hResModule, IDS_UNAVAILABLE, + unavailable, ARRAYLENGTH(unavailable)); + + if(s->cred) { + cbsize = sizeof(buf); + kcdb_cred_get_name(s->cred, buf, &cbsize); + SetDlgItemText(hwnd, IDC_PPK5_NAME, buf); + + cbsize = sizeof(buf); + rv = kcdb_cred_get_attr_string(s->cred, + KCDB_ATTR_ISSUE, + buf, &cbsize, 0); + if (KHM_SUCCEEDED(rv)) + SetDlgItemText(hwnd, IDC_PPK5_ISSUE, buf); + else + SetDlgItemText(hwnd, IDC_PPK5_ISSUE, unavailable); + + cbsize = sizeof(buf); + rv = kcdb_cred_get_attr_string(s->cred, + KCDB_ATTR_EXPIRE, + buf, &cbsize, 0); + if (KHM_SUCCEEDED(rv)) + SetDlgItemText(hwnd, IDC_PPK5_VALID, buf); + else + SetDlgItemText(hwnd, IDC_PPK5_VALID, unavailable); + + cbsize = sizeof(buf); + rv = kcdb_cred_get_attr_string(s->cred, + KCDB_ATTR_RENEW_EXPIRE, + buf, &cbsize, 0); + if (KHM_SUCCEEDED(rv)) + SetDlgItemText(hwnd, IDC_PPK5_RENEW, buf); + else + SetDlgItemText(hwnd, IDC_PPK5_RENEW, unavailable); + + tflags = 0; + cbsize = sizeof(tflags); + rv = kcdb_cred_get_attr(s->cred, + attr_id_krb5_flags, + NULL, + &tflags, + &cbsize); + if (KHM_SUCCEEDED(rv)) { + +#define ADDBITFLAG(f,s) \ + if (tflags & f) { \ + LoadString(hResModule, s, buf, ARRAYLENGTH(buf)); \ + SendDlgItemMessage(hwnd, IDC_PPK5_FLAGS, LB_ADDSTRING, 0, (LPARAM) buf); \ + } + + ADDBITFLAG(TKT_FLG_FORWARDABLE, IDS_FLG_FORWARDABLE); + ADDBITFLAG(TKT_FLG_FORWARDED, IDS_FLG_FORWARDED); + ADDBITFLAG(TKT_FLG_PROXIABLE, IDS_FLG_PROXIABLE); + ADDBITFLAG(TKT_FLG_PROXY, IDS_FLG_PROXY); + ADDBITFLAG(TKT_FLG_MAY_POSTDATE, IDS_FLG_MAY_POSTDATE); + ADDBITFLAG(TKT_FLG_POSTDATED, IDS_FLG_POSTDATED); + ADDBITFLAG(TKT_FLG_INVALID, IDS_FLG_INVALID); + ADDBITFLAG(TKT_FLG_RENEWABLE, IDS_FLG_RENEWABLE); + ADDBITFLAG(TKT_FLG_INITIAL, IDS_FLG_INITIAL); + ADDBITFLAG(TKT_FLG_PRE_AUTH, IDS_FLG_PRE_AUTH); + ADDBITFLAG(TKT_FLG_HW_AUTH, IDS_FLG_HW_AUTH); + ADDBITFLAG(TKT_FLG_TRANSIT_POLICY_CHECKED, IDS_FLG_TRANSIT_POL); + ADDBITFLAG(TKT_FLG_OK_AS_DELEGATE, IDS_FLG_OK_DELEGATE); + ADDBITFLAG(TKT_FLG_ANONYMOUS, IDS_FLG_ANONYMOUS); + +#undef ADDBITFLAG + + } + } else { +#ifdef DEBUG + assert(FALSE); +#endif + } + } + return FALSE; + } + + return FALSE; +} + +void k5_pp_begin(khui_property_sheet * s) +{ + PROPSHEETPAGE *p; + + if(s->credtype == credtype_id_krb5 && + s->cred) { + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = hResModule; + p->pszTemplate = MAKEINTRESOURCE(IDD_PP_KRB5C); + p->pfnDlgProc = krb5_pp_proc; + p->lParam = (LPARAM) s; + khui_ps_add_page(s, credtype_id_krb5, 0, p, NULL); + } +} + +void k5_pp_end(khui_property_sheet * s) +{ + khui_property_page * p = NULL; + + khui_ps_find_page(s, credtype_id_krb5, &p); + if(p) { + if(p->p_page) + PFREE(p->p_page); + p->p_page = NULL; + } +} + diff --git a/mechglue/src/windows/identity/plugins/krb5/krb5util.c b/mechglue/src/windows/identity/plugins/krb5/krb5util.c new file mode 100644 index 000000000..7be0f8e26 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krb5util.c @@ -0,0 +1,1362 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include +#include +#include +#include +#include "leashdll.h" +#include +#include +#include + +#include +#include "leasherr.h" +#include "leash-int.h" +#include "leashids.h" + +#include + +#include +#include "reminder.h" + +static char FAR *err_context; + +char KRB_HelpFile[_MAX_PATH] = HELPFILE; + +#define LEN 64 /* Maximum Hostname Length */ + +#define LIFE DEFAULT_TKT_LIFE /* lifetime of ticket in 5-minute units */ + +char * +short_date(dp) + long *dp; +{ + register char *cp; + cp = ctime(dp) + 4; // skip day of week + // cp[15] = '\0'; + cp[12] = '\0'; // Don't display seconds + return (cp); +} + + +static +char* +clean_string( + char* s + ) +{ + char* p = s; + char* b = s; + + if (!s) return s; + + for (p = s; *p; p++) { + switch (*p) { + case '\007': + /* Add more cases here */ + break; + default: + *b = *p; + b++; + } + } + *b = *p; + return s; +} + +static +int +leash_error_message( + const char *error, + int rcL, + int rc4, + int rc5, + int rcA, + char* result_string, + int displayMB + ) +{ + char message[2048]; + char *p = message; + int size = sizeof(message); + int n; + + // XXX: ignore AFS for now. + + if (!rc5 && !rc4 && !rcL) + return 0; + + n = _snprintf(p, size, "%s\n\n", error); + p += n; + size -= n; + + if (rc5 && !result_string) + { + n = _snprintf(p, size, + "Kerberos 5: %s (error %ld)\n", + perror_message(rc5), + rc5 & 255 // XXX: & 255??!!! + ); + p += n; + size -= n; + } + if (rc4 && !result_string) + { + char buffer[1024]; + n = _snprintf(p, size, + "Kerberos 4: %s\n", + err_describe(buffer, rc4) + ); + p += n; + size -= n; + } + if (rcL) + { + char buffer[1024]; + n = _snprintf(p, size, + "\n%s\n", + err_describe(buffer, rcL) + ); + p += n; + size -= n; + } + if (result_string) + { + n = _snprintf(p, size, + "%s\n", + result_string); + p += n; + size -= n; + } + if ( displayMB ) + MessageBox(NULL, message, "Leash", MB_OK | MB_ICONERROR | MB_TASKMODAL | + MB_SETFOREGROUND); + + if (rc5) return rc5; + if (rc4) return rc4; + if (rcL) return rcL; + return 0; +} + + +static +char * +make_postfix( + const char * base, + const char * postfix, + char ** rcopy + ) +{ + int base_size; + int ret_size; + char * copy = 0; + char * ret = 0; + + base_size = strlen(base) + 1; + ret_size = base_size + strlen(postfix) + 1; + copy = PMALLOC(base_size); + ret = PMALLOC(ret_size); + + if (!copy || !ret) + goto cleanup; + + strncpy(copy, base, base_size); + copy[base_size - 1] = 0; + + strncpy(ret, base, base_size); + strncpy(ret + (base_size - 1), postfix, ret_size - (base_size - 1)); + ret[ret_size - 1] = 0; + + cleanup: + if (!copy || !ret) { + if (copy) + PFREE(copy); + if (ret) + PFREE(ret); + copy = ret = 0; + } + // INVARIANT: (ret ==> copy) && (copy ==> ret) + *rcopy = copy; + return ret; +} + +static +long +make_temp_cache_v4( + const char * postfix + ) +{ + static char * old_cache = 0; + + if (!pkrb_set_tkt_string || !ptkt_string || !pdest_tkt) + return 0; // XXX - is this appropriate? + + if (old_cache) { + pdest_tkt(); + pkrb_set_tkt_string(old_cache); + PFREE(old_cache); + old_cache = 0; + } + + if (postfix) + { + char * tmp_cache = make_postfix(ptkt_string(), postfix, &old_cache); + + if (!tmp_cache) + return KFAILURE; + + pkrb_set_tkt_string(tmp_cache); + PFREE(tmp_cache); + } + return 0; +} + +static +long +make_temp_cache_v5( + const char * postfix, + krb5_context * pctx + ) +{ + static krb5_context ctx = 0; + static char * old_cache = 0; + + // INVARIANT: old_cache ==> ctx && ctx ==> old_cache + + if (pctx) + *pctx = 0; + + if (!pkrb5_init_context || !pkrb5_free_context || !pkrb5_cc_resolve || + !pkrb5_cc_default_name || !pkrb5_cc_set_default_name) + return 0; + + if (old_cache) { + krb5_ccache cc = 0; + if (!pkrb5_cc_resolve(ctx, pkrb5_cc_default_name(ctx), &cc)) + pkrb5_cc_destroy(ctx, cc); + pkrb5_cc_set_default_name(ctx, old_cache); + PFREE(old_cache); + old_cache = 0; + } + if (ctx) { + pkrb5_free_context(ctx); + ctx = 0; + } + + if (postfix) + { + char * tmp_cache = 0; + krb5_error_code rc = 0; + + rc = pkrb5_init_context(&ctx); + if (rc) goto cleanup; + + tmp_cache = make_postfix(pkrb5_cc_default_name(ctx), postfix, + &old_cache); + + if (!tmp_cache) { + rc = ENOMEM; + goto cleanup; + } + + rc = pkrb5_cc_set_default_name(ctx, tmp_cache); + + cleanup: + if (rc && ctx) { + pkrb5_free_context(ctx); + ctx = 0; + } + if (tmp_cache) + PFREE(tmp_cache); + if (pctx) + *pctx = ctx; + return rc; + } + return 0; +} + +long +Leash_checkpwd( + char *principal, + char *password + ) +{ + return Leash_int_checkpwd(principal, password, 0); +} + +long +Leash_int_checkpwd( + char * principal, + char * password, + int displayErrors + ) +{ + long rc = 0; + krb5_context ctx = 0; // statically allocated in make_temp_cache_v5 + // XXX - we ignore errors in make_temp_cache_v? This is BAD!!! + make_temp_cache_v4("_checkpwd"); + make_temp_cache_v5("_checkpwd", &ctx); + rc = Leash_int_kinit_ex( ctx, 0, + principal, password, 0, 0, 0, 0, + Leash_get_default_noaddresses(), + Leash_get_default_publicip(), + displayErrors + ); + make_temp_cache_v4(0); + make_temp_cache_v5(0, &ctx); + return rc; +} + +static +long +Leash_changepwd_v5(char * principal, + char * password, + char * newpassword, + char** error_str) +{ + krb5_error_code rc = 0; + int result_code; + krb5_data result_code_string, result_string; + krb5_context context = 0; + krb5_principal princ = 0; + krb5_get_init_creds_opt opts; + krb5_creds creds; + DWORD addressless = 0; + + result_string.data = 0; + result_code_string.data = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + if (rc = pkrb5_init_context(&context)) { +#if 0 + com_err(argv[0], ret, "initializing kerberos library"); +#endif + goto cleanup; + } + + if (rc = pkrb5_parse_name(context, principal, &princ)) { +#if 0 + com_err(argv[0], ret, "parsing client name"); +#endif + goto cleanup; + } + + pkrb5_get_init_creds_opt_init(&opts); + pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60); + pkrb5_get_init_creds_opt_set_renew_life(&opts, 0); + pkrb5_get_init_creds_opt_set_forwardable(&opts, 0); + pkrb5_get_init_creds_opt_set_proxiable(&opts, 0); + + addressless = Leash_get_default_noaddresses(); + if (addressless) + pkrb5_get_init_creds_opt_set_address_list(&opts,NULL); + + + if (rc = pkrb5_get_init_creds_password(context, &creds, princ, password, + 0, 0, 0, "kadmin/changepw", &opts)) { + if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) { +#if 0 + com_err(argv[0], 0, + "Password incorrect while getting initial ticket"); +#endif + } + else { +#if 0 + com_err(argv[0], ret, "getting initial ticket"); +#endif + } + goto cleanup; + } + + if (rc = pkrb5_change_password(context, &creds, newpassword, + &result_code, &result_code_string, + &result_string)) { +#if 0 + com_err(argv[0], ret, "changing password"); +#endif + goto cleanup; + } + + if (result_code) { + int len = result_code_string.length + + (result_string.length ? (sizeof(": ") - 1) : 0) + + result_string.length; + if (len && error_str) { + *error_str = PMALLOC(len + 1); + if (*error_str) + _snprintf(*error_str, len + 1, + "%.*s%s%.*s", + result_code_string.length, result_code_string.data, + result_string.length?": ":"", + result_string.length, result_string.data); + } + rc = result_code; + goto cleanup; + } + + cleanup: + if (result_string.data) + pkrb5_free_data_contents(context, &result_string); + + if (result_code_string.data) + pkrb5_free_data_contents(context, &result_code_string); + + if (princ) + pkrb5_free_principal(context, princ); + + if (context) + pkrb5_free_context(context); + + return rc; +} + +static +long +Leash_changepwd_v4( + char * principal, + char * password, + char * newpassword, + char** error_str + ) +{ + long k_errno; + + if (!pkrb_set_tkt_string || !ptkt_string || !pkadm_change_your_password || + !pdest_tkt) + return KFAILURE; + + k_errno = make_temp_cache_v4("_chgpwd"); + if (k_errno) return k_errno; + k_errno = pkadm_change_your_password(principal, password, newpassword, + error_str); + make_temp_cache_v4(0); + return k_errno; +} + +/* + * Leash_changepwd + * + * Try to change the password using one of krb5 or krb4 -- whichever one + * works. We return ok on the first one that works. + */ +long +Leash_changepwd( + char * principal, + char * password, + char * newpassword, + char** result_string + ) +{ + return Leash_int_changepwd(principal, password, newpassword, result_string, 0); +} + +long +Leash_int_changepwd( + char * principal, + char * password, + char * newpassword, + char** result_string, + int displayErrors + ) +{ + char* v5_error_str = 0; + char* v4_error_str = 0; + char* error_str = 0; + int rc4 = 0; + int rc5 = 0; + int rc = 0; + if (hKrb5) + rc = rc5 = Leash_changepwd_v5(principal, password, newpassword, + &v5_error_str); + if (hKrb4 && + Leash_get_default_use_krb4() && + (!hKrb5 || rc5)) + rc = rc4 = Leash_changepwd_v4(principal, password, newpassword, + &v4_error_str); + if (!rc) + return 0; + if (v5_error_str || v4_error_str) { + int len = 0; + char v5_prefix[] = "Kerberos 5: "; + char sep[] = "\n"; + char v4_prefix[] = "Kerberos 4: "; + + clean_string(v5_error_str); + clean_string(v4_error_str); + + if (v5_error_str) + len += sizeof(sep) + sizeof(v5_prefix) + strlen(v5_error_str) + + sizeof(sep); + if (v4_error_str) + len += sizeof(sep) + sizeof(v4_prefix) + strlen(v4_error_str) + + sizeof(sep); + error_str = PMALLOC(len + 1); + if (error_str) { + char* p = error_str; + int size = len + 1; + int n; + if (v5_error_str) { + n = _snprintf(p, size, "%s%s%s%s", + sep, v5_prefix, v5_error_str, sep); + p += n; + size -= n; + } + if (v4_error_str) { + n = _snprintf(p, size, "%s%s%s%s", + sep, v4_prefix, v4_error_str, sep); + p += n; + size -= n; + } + if (result_string) + *result_string = error_str; + } + } + return leash_error_message("Error while changing password.", + rc4, rc4, rc5, 0, error_str, + displayErrors + ); +} + +int (*Lcom_err)(LPSTR,long,LPSTR,...); +LPSTR (*Lerror_message)(long); +LPSTR (*Lerror_table_name)(long); + + +long +Leash_kinit( + char * principal, + char * password, + int lifetime + ) +{ + return Leash_int_kinit_ex( 0, 0, + principal, + password, + lifetime, + Leash_get_default_forwardable(), + Leash_get_default_proxiable(), + Leash_get_default_renew_till(), + Leash_get_default_noaddresses(), + Leash_get_default_publicip(), + 0 + ); +} + +long +Leash_kinit_ex( + char * principal, + char * password, + int lifetime, + int forwardable, + int proxiable, + int renew_life, + int addressless, + unsigned long publicip + ) +{ + return Leash_int_kinit_ex( 0, /* krb5 context */ + 0, /* parent window */ + principal, + password, + lifetime, + forwardable, + proxiable, + renew_life, + addressless, + publicip, + 0 + ); +} + +long +Leash_int_kinit_ex( + krb5_context ctx, + HWND hParent, + char * principal, + char * password, + int lifetime, + int forwardable, + int proxiable, + int renew_life, + int addressless, + unsigned long publicip, + int displayErrors + ) +{ + LPCSTR functionName; + char aname[ANAME_SZ]; + char inst[INST_SZ]; + char realm[REALM_SZ]; + char first_part[256]; + char second_part[256]; + char temp[1024]; + int count; + int i; + int rc4 = 0; + int rc5 = 0; + int rcA = 0; + int rcL = 0; + + if (lifetime < 5) + lifetime = 1; + else + lifetime /= 5; + + if (renew_life > 0 && renew_life < 5) + renew_life = 1; + else + renew_life /= 5; + + /* This should be changed if the maximum ticket lifetime */ + /* changes */ + + if (lifetime > 255) + lifetime = 255; + + err_context = "parsing principal"; + + memset(temp, '\0', sizeof(temp)); + memset(inst, '\0', sizeof(inst)); + memset(realm, '\0', sizeof(realm)); + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + + sscanf(principal, "%[/0-9a-zA-Z._-]@%[/0-9a-zA-Z._-]", first_part, second_part); + strcpy(temp, first_part); + strcpy(realm, second_part); + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + if (sscanf(temp, "%[@0-9a-zA-Z._-]/%[@0-9a-zA-Z._-]", first_part, second_part) == 2) + { + strcpy(aname, first_part); + strcpy(inst, second_part); + } + else + { + count = 0; + i = 0; + for (i = 0; temp[i]; i++) + { + if (temp[i] == '.') + ++count; + } + if (count > 1) + { + strcpy(aname, temp); + } + else + { + if (pkname_parse != NULL) + { + memset(first_part, '\0', sizeof(first_part)); + memset(second_part, '\0', sizeof(second_part)); + sscanf(temp, "%[@/0-9a-zA-Z_-].%[@/0-9a-zA-Z_-]", first_part, second_part); + strcpy(aname, first_part); + strcpy(inst, second_part); + } + else + { + strcpy(aname, temp); + } + } + } + + memset(temp, '\0', sizeof(temp)); + strcpy(temp, aname); + if (strlen(inst) != 0) + { + strcat(temp, "/"); + strcat(temp, inst); + } + if (strlen(realm) != 0) + { + strcat(temp, "@"); + strcat(temp, realm); + } + + rc5 = Leash_krb5_kinit(ctx, hParent, + temp, password, lifetime, + forwardable, + proxiable, + renew_life, + addressless, + publicip + ); + if ( Leash_get_default_use_krb4() ) { + if ( !rc5 ) { + if (!Leash_convert524(ctx)) + rc4 = KFAILURE; + } else { + if (pkname_parse == NULL) + { + goto cleanup; + } + + err_context = "getting realm"; + if (!*realm && (rc4 = (int)(*pkrb_get_lrealm)(realm, 1))) + { + functionName = "krb_get_lrealm()"; + rcL = LSH_FAILEDREALM; + goto cleanup; + } + + err_context = "checking principal"; + if ((!*aname) || (!(rc4 = (int)(*pk_isname)(aname)))) + { + functionName = "krb_get_lrealm()"; + rcL = LSH_INVPRINCIPAL; + goto cleanup; + } + + /* optional instance */ + if (!(rc4 = (int)(*pk_isinst)(inst))) + { + functionName = "k_isinst()"; + rcL = LSH_INVINSTANCE; + goto cleanup; + } + + if (!(rc4 = (int)(*pk_isrealm)(realm))) + { + functionName = "k_isrealm()"; + rcL = LSH_INVREALM; + goto cleanup; + } + + err_context = "fetching ticket"; + rc4 = (*pkrb_get_pw_in_tkt)(aname, inst, realm, "krbtgt", realm, + lifetime, password); + if (rc4) /* XXX: do we want: && (rc != NO_TKT_FIL) as well? */ + { + functionName = "krb_get_pw_in_tkt()"; + rcL = KRBERR(rc4); + goto cleanup; + } + } + } + +#ifndef NO_AFS + if ( !rc5 || (Leash_get_default_use_krb4() && !rc4) ) { + char c; + char *r; + char *t; + for ( r=realm, t=temp; c=*r; r++,t++ ) + *t = isupper(c) ? tolower(c) : c; + *t = '\0'; + + rcA = Leash_afs_klog("afs", temp, realm, lifetime); + if (rcA) + rcA = Leash_afs_klog("afs", "", realm, lifetime); + } +#endif /* NO_AFS */ + + cleanup: + return leash_error_message("Ticket initialization failed.", + rcL, (rc5 && rc4)?KRBERR(rc4):0, rc5, rcA, 0, + displayErrors); +} + +long FAR +Leash_renew(void) +{ + if ( hKrb5 && !LeashKRB5_renew() ) { + int lifetime; + lifetime = Leash_get_default_lifetime() / 5; + if (hKrb4 && Leash_get_default_use_krb4()) + Leash_convert524(0); +#ifndef NO_AFS + { + TicketList * list = NULL, * token; + afs_get_tokens(NULL,&list,NULL); + for ( token = list ; token ; token = token->next ) + Leash_afs_klog("afs", token->realm, "", lifetime); + not_an_API_LeashFreeTicketList(&list); + } +#endif /* NO_AFS */ + return 1; + } + return 0; +} + +static BOOL +GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; + HANDLE TokenHandle; + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData || !pLsaGetLogonSessionData) + return FALSE; + *ppSessionData = NULL; + + Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); + if ( !Success ) + return FALSE; + + Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); + CloseHandle( TokenHandle ); + if ( !Success ) + return FALSE; + + Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); + if ( FAILED(Status) || !ppSessionData ) + return FALSE; + + return TRUE; +} + +// IsKerberosLogon() does not validate whether or not there are valid tickets in the +// cache. It validates whether or not it is reasonable to assume that if we +// attempted to retrieve valid tickets we could do so. Microsoft does not +// automatically renew expired tickets. Therefore, the cache could contain +// expired or invalid tickets. Microsoft also caches the user's password +// and will use it to retrieve new TGTs if the cache is empty and tickets +// are requested. + +static BOOL +IsKerberosLogon(VOID) +{ + PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; + BOOL Success = FALSE; + + if ( GetSecurityLogonSessionData(&pSessionData) ) { + if ( pSessionData->AuthenticationPackage.Buffer ) { + WCHAR buffer[256]; + WCHAR *usBuffer; + int usLength; + + Success = FALSE; + usBuffer = (pSessionData->AuthenticationPackage).Buffer; + usLength = (pSessionData->AuthenticationPackage).Length; + if (usLength < 256) + { + lstrcpyn (buffer, usBuffer, usLength); + lstrcat (buffer,L""); + if ( !lstrcmp(L"Kerberos",buffer) ) + Success = TRUE; + } + } + pLsaFreeReturnBuffer(pSessionData); + } + return Success; +} + + +// This looks really ugly because it is. The result of IsKerberosLogon() +// does not prove whether or not there are Kerberos tickets available to +// be imported. Only the call to khm_krb5_ms2mit() which actually attempts +// to import tickets can do that. However, calling khm_krb5_ms2mit() can +// result in a TGS_REQ being sent to the KDC and since Leash_importable() +// is called quite often we want to avoid this if at all possible. +// Unfortunately, we have be shown at least one case in which the primary +// authentication package was not Kerberos and yet there were Kerberos +// tickets available. Therefore, if IsKerberosLogon() is not TRUE we +// must call khm_krb5_ms2mit() but we still do not want to call it in a +// tight loop so we cache the response and assume it won't change. +long FAR +Leash_importable(void) +{ + if ( IsKerberosLogon() ) + return TRUE; + else { + static int response = -1; + if (response == -1) { + response = khm_krb5_ms2mit(0); + } + return response; + } +} + +long FAR +Leash_import(void) +{ + if ( khm_krb5_ms2mit(1) ) { + int lifetime; + lifetime = Leash_get_default_lifetime() / 5; + if (hKrb4 && Leash_get_default_use_krb4()) + Leash_convert524(0); +#ifndef NO_AFS + { + char c; + char *r; + char *t; + char cell[256]; + char realm[256]; + int i = 0; + int rcA = 0; + + krb5_context ctx = 0; + krb5_error_code code = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + + if ( !pkrb5_init_context ) + goto cleanup; + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + + if (code = pkrb5_cc_get_principal(ctx, cc, &me)) + goto cleanup; + + for ( r=realm, t=cell, i=0; ilength; r++,t++,i++ ) { + c = krb5_princ_realm(ctx, me)->data[i]; + *r = c; + *t = isupper(c) ? tolower(c) : c; + } + *r = *t = '\0'; + + rcA = Leash_afs_klog("afs", cell, realm, lifetime); + if (rcA) + rcA = Leash_afs_klog("afs", "", realm, lifetime); + + cleanup: + if (me) + pkrb5_free_principal(ctx, me); + if (cc) + pkrb5_cc_close(ctx, cc); + if (ctx) + pkrb5_free_context(ctx); + } +#endif /* NO_AFS */ + return 1; + } + return 0; +} + +long +Leash_kdestroy(void) +{ + int k_errno; + + Leash_afs_unlog(); + khm_krb5_destroy_identity(NULL); + + if (pdest_tkt != NULL) + { + k_errno = (*pdest_tkt)(); + if (k_errno && (k_errno != RET_TKFIL)) + return KRBERR(k_errno); + } + + return 0; +} + +int com_addr(void) +{ + long ipAddr; + char loc_addr[ADDR_SZ]; + CREDENTIALS cred; + char service[40]; + char instance[40]; +// char addr[40]; + char realm[40]; + struct in_addr LocAddr; + int k_errno; + + if (pkrb_get_cred == NULL) + return(KSUCCESS); + + k_errno = (*pkrb_get_cred)(service,instance,realm,&cred); + if (k_errno) + return KRBERR(k_errno); + + + while(1) { + ipAddr = (*pLocalHostAddr)(); + LocAddr.s_addr = ipAddr; + strcpy(loc_addr,inet_ntoa(LocAddr)); + if ( strcmp(cred.address,loc_addr) != 0) { + Leash_kdestroy (); + break; + } + break; + } // while() + return 0; +} + +long FAR +not_an_API_LeashFreeTicketList(TicketList** ticketList) +{ + TicketList* tempList = *ticketList, *killList; + + //if (tempList == NULL) + //return -1; + + while (tempList) + { + killList = tempList; + + tempList = (TicketList*)tempList->next; + PFREE(killList->theTicket); + if (killList->tktEncType) + PFREE(killList->tktEncType); + if (killList->keyEncType) + PFREE(killList->keyEncType); + if (killList->addrCount) { + int n; + for ( n=0; naddrCount; n++) { + if (killList->addrList[n]) + PFREE(killList->addrList[n]); + } + } + if (killList->addrList) + PFREE(killList->addrList); + if (killList->name) + PFREE(killList->name); + if (killList->inst) + PFREE(killList->inst); + if (killList->realm) + PFREE(killList->realm); + PFREE(killList); + } + + *ticketList = NULL; + return 0; +} + + +long FAR Leash_klist(HWND hlist, TICKETINFO FAR *ticketinfo) +{ + // Don't think this function will be used anymore - ADL 5-15-99 + // Old fucntion to put tickets in a listbox control + // Use function "not_an_API_LeashKRB4GetTickets()" instead! + char pname[ANAME_SZ]; + char pinst[INST_SZ]; + char prealm[REALM_SZ]; + char buf[MAX_K_NAME_SZ+40]; + LPSTR cp; + long expdate; + int k_errno; + CREDENTIALS c; + int newtickets = 0; + int open = 0; + + /* + * Since krb_get_tf_realm will return a ticket_file error, + * we will call tf_init and tf_close first to filter out + * things like no ticket file. Otherwise, the error that + * the user would see would be + * klist: can't find realm of ticket file: No ticket file (tf_util) + * instead of + * klist: No ticket file (tf_util) + */ + if (ptf_init == NULL) + return(KSUCCESS); + + if (hlist) + { + SendMessage(hlist, WM_SETREDRAW, FALSE, 0L); + SendMessage(hlist, LB_RESETCONTENT, 0, 0L); + } + com_addr(); + newtickets = NO_TICKETS; + + err_context = (LPSTR)"tktf1"; + + /* Open ticket file */ + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + /* Close ticket file */ + (void) (*ptf_close)(); + /* + * We must find the realm of the ticket file here before calling + * tf_init because since the realm of the ticket file is not + * really stored in the principal section of the file, the + * routine we use must itself call tf_init and tf_close. + */ + err_context = "tf realm"; + if ((k_errno = (*pkrb_get_tf_realm)((*ptkt_string)(), prealm)) != KSUCCESS) + { + goto cleanup; + } + /* Open ticket file */ + err_context = "tf init"; + if (k_errno = (*ptf_init)((*ptkt_string)(), R_TKT_FIL)) + { + goto cleanup; + } + + open = 1; + err_context = "tf pname"; + /* Get principal name and instance */ + if ((k_errno = (*ptf_get_pname)(pname)) || (k_errno = (*ptf_get_pinst)(pinst))) + { + goto cleanup; + } + + /* + * You may think that this is the obvious place to get the + * realm of the ticket file, but it can't be done here as the + * routine to do this must open the ticket file. This is why + * it was done before tf_init. + */ + + wsprintf((LPSTR)ticketinfo->principal,"%s%s%s%s%s", (LPSTR)pname, + (LPSTR)(pinst[0] ? "." : ""), (LPSTR)pinst, + (LPSTR)(prealm[0] ? "@" : ""), (LPSTR)prealm); + newtickets = GOOD_TICKETS; + + err_context = "tf cred"; + while ((k_errno = (*ptf_get_cred)(&c)) == KSUCCESS) + { + expdate = c.issue_date + c.lifetime * 5L * 60L; + + if (!lstrcmp((LPSTR)c.service, (LPSTR)TICKET_GRANTING_TICKET) && !lstrcmp((LPSTR)c.instance, (LPSTR)prealm)) + { + ticketinfo->issue_date = c.issue_date; + ticketinfo->lifetime = c.lifetime * 5L * 60L; + ticketinfo->renew_till = 0; + } + + cp = (LPSTR)buf; + lstrcpy(cp, (LPSTR)short_date(&c.issue_date)); + cp += lstrlen(cp); + wsprintf(cp,"\t%s\t%s%s%s%s%s", + (LPSTR)short_date(&expdate), (LPSTR)c.service, + (LPSTR)(c.instance[0] ? "." : ""), + (LPSTR)c.instance, (LPSTR)(c.realm[0] ? "@" : ""), + (LPSTR) c.realm); + if (hlist) + SendMessage(hlist, LB_ADDSTRING, 0, (LONG)(LPSTR)buf); + } /* WHILE */ + +cleanup: + + if (open) + (*ptf_close)(); /* close ticket file */ + + if (hlist) + { + SendMessage(hlist, WM_SETREDRAW, TRUE, 0L); + InvalidateRect(hlist, NULL, TRUE); + UpdateWindow(hlist); + } + if (k_errno == EOF) + k_errno = 0; + + /* XXX the if statement directly below was inserted to eliminate + an error 20 on Leash startup. The error occurs from an error + number thrown from krb_get_tf_realm. We believe this change + does not eliminate other errors, but it may. */ + + if (k_errno == RET_NOTKT) + k_errno = 0; + + ticketinfo->btickets = newtickets; + if (k_errno != 0) + return KRBERR(k_errno); + return 0; +} + + + +static BOOL CALLBACK +EnumChildProc(HWND hwnd, LPARAM lParam) +{ + HWND * h = (HWND *)lParam; + *h = hwnd; + return FALSE; +} + + +static HWND +FindFirstChildWindow(HWND parent) +{ + HWND hFirstChild = 0; + EnumChildWindows(parent, EnumChildProc, (LPARAM) &hFirstChild); + return hFirstChild; +} + +void FAR +not_an_API_Leash_AcquireInitialTicketsIfNeeded(krb5_context context, krb5_principal desiredKrb5Principal) +{ + krb5_error_code err; + LSH_DLGINFO_EX dlginfo; + HGLOBAL hData; + HWND hLeash; + HWND hForeground; + char *desiredName = 0; + char *desiredRealm = 0; + char *p; + TicketList * list = NULL; + TICKETINFO ticketinfo; + krb5_context ctx; + char newenv[256]; + char * env = 0; + DWORD dwMsLsaImport = Leash_get_default_mslsa_import(); + + char loginenv[16]; + BOOL prompt; + + GetEnvironmentVariable("KERBEROSLOGIN_NEVER_PROMPT", loginenv, sizeof(loginenv)); + prompt = (GetLastError() == ERROR_ENVVAR_NOT_FOUND); + + if ( !prompt || !pkrb5_init_context ) + return; + + ctx = context; + env = getenv("KRB5CCNAME"); + if ( !env && context ) { + sprintf(newenv,"KRB5CCNAME=%s",pkrb5_cc_default_name(ctx)); + env = (char *)putenv(newenv); + } + + not_an_API_LeashKRB5GetTickets(&ticketinfo,&list,&ctx); + not_an_API_LeashFreeTicketList(&list); + + if ( ticketinfo.btickets != GOOD_TICKETS && + Leash_get_default_mslsa_import() && Leash_importable() ) { + // We have the option of importing tickets from the MSLSA + // but should we? Do the tickets in the MSLSA cache belong + // to the default realm used by Leash? If so, import. + int import = 0; + + if ( dwMsLsaImport == 1 ) { /* always import */ + import = 1; + } else if ( dwMsLsaImport == 2 ) { /* import when realms match */ + krb5_error_code code; + krb5_ccache mslsa_ccache=0; + krb5_principal princ = 0; + char ms_realm[128] = "", *def_realm = 0, *r; + int i; + + if (code = pkrb5_cc_resolve(ctx, "MSLSA:", &mslsa_ccache)) + goto cleanup; + + if (code = pkrb5_cc_get_principal(ctx, mslsa_ccache, &princ)) + goto cleanup; + + for ( r=ms_realm, i=0; ilength; r++, i++ ) { + *r = krb5_princ_realm(ctx, princ)->data[i]; + } + *r = '\0'; + + if (code = pkrb5_get_default_realm(ctx, &def_realm)) + goto cleanup; + + import = !strcmp(def_realm, ms_realm); + + cleanup: + if (def_realm) + pkrb5_free_default_realm(ctx, def_realm); + + if (princ) + pkrb5_free_principal(ctx, princ); + + if (mslsa_ccache) + pkrb5_cc_close(ctx, mslsa_ccache); + } + + if ( import ) { + Leash_import(); + + not_an_API_LeashKRB5GetTickets(&ticketinfo,&list,&ctx); + not_an_API_LeashFreeTicketList(&list); + } + } + + if ( ticketinfo.btickets != GOOD_TICKETS ) + { + /* do we want a specific client principal? */ + if (desiredKrb5Principal != NULL) { + err = pkrb5_unparse_name (ctx, desiredKrb5Principal, &desiredName); + if (!err) { + dlginfo.username = desiredName; + for (p = desiredName; *p && *p != '@'; p++); + if ( *p == '@' ) { + *p = '\0'; + desiredRealm = dlginfo.realm = ++p; + } + } + } + +#ifdef COMMENT + memset(&dlginfo, 0, sizeof(LSH_DLGINFO_EX)); + dlginfo.size = sizeof(LSH_DLGINFO_EX); + dlginfo.dlgtype = DLGTYPE_PASSWD; + dlginfo.title = "Obtain Kerberos Ticket Getting Tickets"; + dlginfo.use_defaults = 1; + + err = Leash_kinit_dlg_ex(NULL, &dlginfo); +#else + /* construct a marshalling of data + * <principal><realm> + * then send to Leash + */ + + hData = GlobalAlloc( GHND, 4096 ); + hForeground = GetForegroundWindow(); + hLeash = FindWindow("LEASH.0WNDCLASS", NULL); + SetForegroundWindow(hLeash); + hLeash = FindFirstChildWindow(hLeash); + if ( hData && hLeash ) { + char * strs = GlobalLock( hData ); + if ( strs ) { + strcpy(strs, "Obtain Kerberos Ticket Getting Tickets"); + strs += strlen(strs) + 1; + if ( desiredName ) { + strcpy(strs, desiredName); + strs += strlen(strs) + 1; + if (desiredRealm) { + strcpy(strs, desiredRealm); + strs += strlen(strs) + 1; + } + } else { + *strs = 0; + strs++; + *strs = 0; + strs++; + } + + GlobalUnlock( hData ); + SendMessage(hLeash, 32809, 0, (LPARAM) hData); + } + + GlobalFree( hData ); + } + SetForegroundWindow(hForeground); +#endif + if (desiredName != NULL) + pkrb5_free_unparsed_name(ctx, desiredName); + } + + if ( !env && context ) + putenv("KRB5CCNAME="); + + if ( !context ) + pkrb5_free_context(ctx); +} diff --git a/mechglue/src/windows/identity/plugins/krb5/krbconfig.csv b/mechglue/src/windows/identity/plugins/krb5/krbconfig.csv new file mode 100644 index 000000000..9b849c88f --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krbconfig.csv @@ -0,0 +1,39 @@ +Name,Type,Value,Description +Krb5Cred,KC_SPACE,0,Kerberos V Credentials Provider + Module,KC_STRING,MITKrb5, + Description,KC_STRING,Kerberos V Credentials Provider, + Type,KC_INT32,1, + Flags,KC_INT32,0, + Parameters,KC_SPACE,0,Parameters for KrbCred + CreateMissingConfig,KC_INT32,0,Create missing configuration files + MsLsaImport,KC_INT32,1,Automatically import MSLSA credentials: 0-never 1-always 2-if principle matches + MsLsaList,KC_INT32,1,Include MSLSA in the credentials list + FileCCList,KC_STRING,,List of file CCaches to include in listing + AutoRenewTickets,KC_INT32,1,Automatically renew expiring tickets + DefaultLifetime,KC_INT32,36000,Default ticket lifetime + MaxLifetime,KC_INT32,86400,Maximum lifetime + MinLifetime,KC_INT32,60,Minimum lifetime + Forwardable,KC_INT32,1,Obtain forwardable tickets (boolean) + Proxiable,KC_INT32,0,Obtain proxiable tickets (boolean) + Addressless,KC_INT32,1,Obtain addressless tickets (boolean) + Renewable,KC_INT32,1,Obtain renewable tickets (boolean) + DefaultRenewLifetime,KC_INT32,604800,Default renewable lifetime + MaxRenewLifetime,KC_INT32,2592000,Maximum renewable lifetime + MinRenewLifetime,KC_INT32,60,Maximum renewable lifetime + UseFullRealmList,KC_INT32,0,Use the full list of realms in the New Creds dialog + LRURealms,KC_STRING,, + LRUPrincipals,KC_STRING,, + LastDefaultIdent,KC_STRING,,Last known default identity + DefaultCCName,KC_STRING,,Default CC name (only per identity) + PromptCache,KC_SPACE,0,Cache of prompts (only per identity) + Name,KC_STRING,, + Banner,KC_STRING,, + PromptCount,KC_INT32,0, + (n),KC_SPACE,0,Parameters for each prompt + Prompt,KC_STRING,, + Type,KC_INT32,0, + Flags,KC_INT32,0, + (n),KC_ENDSPACE,0, + PromptCache,KC_ENDSPACE,0, + Parameters,KC_ENDSPACE,0, +Krb5Cred,KC_ENDSPACE,0, diff --git a/mechglue/src/windows/identity/plugins/krb5/krbcred.h b/mechglue/src/windows/identity/plugins/krb5/krbcred.h new file mode 100644 index 000000000..7ab035c8c --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/krbcred.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KRBAFSCRED_H +#define __KHIMAIRA_KRBAFSCRED_H + +#include<windows.h> + +/* While we generally pull resources out of hResModule, the message + strings for all the languages are kept in the main DLL. */ +#define KHERR_HMODULE hInstance +#define KHERR_FACILITY k5_facility +#define KHERR_FACILITY_ID 64 + +#include<khdefs.h> +#include<kcreddb.h> +#include<kmm.h> +#include<kconfig.h> +#include<khuidefs.h> +#include<kherr.h> +#include<utils.h> + +#include<krb5funcs.h> +#include<krb5common.h> +#include<errorfuncs.h> +#include<dynimport.h> + +#include<langres.h> +#include<datarep.h> +#include<krb5_msgs.h> + +typedef enum tag_k5_lsa_import { + K5_LSAIMPORT_NEVER = 0, + K5_LSAIMPORT_ALWAYS = 1, + K5_LSAIMPORT_MATCH = 2, /* only when the principal name matches */ +} k5_lsa_import; + +#define TYPENAME_ENCTYPE L"EncType" +#define TYPENAME_ADDR_LIST L"AddrList" +#define TYPENAME_KRB5_FLAGS L"Krb5Flags" +#define TYPENAME_KRB5_PRINC L"Krb5Principal" + +#define ATTRNAME_KEY_ENCTYPE L"KeyEncType" +#define ATTRNAME_TKT_ENCTYPE L"TktEncType" +#define ATTRNAME_ADDR_LIST L"AddrList" +#define ATTRNAME_KRB5_FLAGS L"Krb5Flags" +#define ATTRNAME_KRB5_CCNAME L"Krb5CCName" + +void init_krb(); +void exit_krb(); +KHMEXP khm_int32 KHMAPI init_module(kmm_module h_module); +KHMEXP khm_int32 KHMAPI exit_module(kmm_module h_module); + +/* globals */ +extern kmm_module h_khModule; +extern HMODULE hResModule; +extern HINSTANCE hInstance; +extern const wchar_t * k5_facility; + +extern khm_int32 type_id_enctype; +extern khm_int32 type_id_addr_list; +extern khm_int32 type_id_krb5_flags; +extern khm_int32 type_id_krb5_princ; + +extern BOOL type_regd_krb5_princ; + +extern khm_int32 attr_id_key_enctype; +extern khm_int32 attr_id_tkt_enctype; +extern khm_int32 attr_id_addr_list; +extern khm_int32 attr_id_krb5_flags; +extern khm_int32 attr_id_krb5_ccname; + +extern khm_ui_4 k5_commctl_version; + +#define IS_COMMCTL6() (k5_commctl_version >= 0x60000) + +/* Configuration spaces */ +#define CSNAME_KRB5CRED L"Krb5Cred" +#define CSNAME_PARAMS L"Parameters" +#define CSNAME_PROMPTCACHE L"PromptCache" + +/* plugin constants */ +#define KRB5_PLUGIN_NAME L"Krb5Cred" +#define KRB5_IDENTPRO_NAME L"Krb5Ident" + +#define KRB5_CREDTYPE_NAME L"Krb5Cred" + +/* limits */ +/* maximum number of characters in a realm name */ +#define K5_MAXCCH_REALM 256 + +/* maximum number of characters in a host name */ +#define K5_MAXCCH_HOST 128 + +/* maximum number of KDC's per realm */ +#define K5_MAX_KDC 64 + +/* maximum number of domains that map to a realm */ +#define K5_MAX_DOMAIN_MAPPINGS 32 + +extern khm_handle csp_plugins; +extern khm_handle csp_krbcred; +extern khm_handle csp_params; + +extern kconf_schema schema_krbconfig[]; + +/* other globals */ +extern khm_int32 credtype_id_krb5; + +extern khm_boolean krb5_initialized; + +extern khm_handle krb5_credset; + +extern khm_handle k5_sub; + +extern krb5_context k5_identpro_ctx; + +extern BOOL is_k5_identpro; + +/* plugin callbacks */ +khm_int32 KHMAPI k5_msg_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); +khm_int32 KHMAPI k5_ident_callback(khm_int32 msg_type, khm_int32 msg_subtype, khm_ui_4 uparam, void * vparam); + +/* kinit fiber */ +typedef struct _fiber_job_t { + int command; + + khui_new_creds * nc; + khui_new_creds_by_type * nct; + HWND dialog; + + khm_handle identity; + char * principal; + char * password; + char * ccache; + krb5_deltat lifetime; + DWORD forwardable; + DWORD proxiable; + DWORD renewable; + krb5_deltat renew_life; + DWORD addressless; + DWORD publicIP; + + int code; + int state; + int prompt_set; + + BOOL null_password; +} fiber_job; + +extern fiber_job g_fjob; /* global fiber job object */ + +#define FIBER_CMD_KINIT 1 +#define FIBER_CMD_CANCEL 2 +#define FIBER_CMD_CONTINUE 3 + +#define FIBER_STATE_NONE 0 +#define FIBER_STATE_KINIT 1 + +void +k5_pp_begin(khui_property_sheet * s); + +void +k5_pp_end(khui_property_sheet * s); + +khm_int32 KHMAPI +k5_msg_cred_dialog(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +khm_int32 KHMAPI +k5_msg_ident(khm_int32 msg_type, + khm_int32 msg_subtype, + khm_ui_4 uparam, + void * vparam); + +int +k5_get_realm_from_nc(khui_new_creds * nc, + wchar_t * buf, + khm_size cch_buf); + +void +k5_register_config_panels(void); + +void +k5_unregister_config_panels(void); + +INT_PTR CALLBACK +k5_ccconfig_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +k5_id_tab_dlgproc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +k5_ids_tab_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +#endif diff --git a/mechglue/src/windows/identity/plugins/krb5/lang/en_us/langres.rc b/mechglue/src/windows/identity/plugins/krb5/lang/en_us/langres.rc new file mode 100644 index 000000000..d54fc101e --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/lang/en_us/langres.rc @@ -0,0 +1,503 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\langres.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\langres.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NC_KRB5 DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Realm",IDC_STATIC,7,25,52,13 + COMBOBOX IDC_NCK5_REALM,60,25,233,17,CBS_DROPDOWN | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Specify &additional realms ...",IDC_NCK5_ADD_REALMS,181, + 43,112,16,BS_NOTIFY | NOT WS_VISIBLE | WS_DISABLED + LTEXT "&Lifetime",IDC_STATIC,7,67,61,12 + EDITTEXT IDC_NCK5_LIFETIME_EDIT,85,67,107,12,ES_AUTOHSCROLL + CONTROL "&Renewable for",IDC_NCK5_RENEWABLE,"Button", + BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,7,87,64,12 + EDITTEXT IDC_NCK5_RENEW_EDIT,85,87,108,12,ES_AUTOHSCROLL + CONTROL "Can be &forwarded to other machines", + IDC_NCK5_FORWARDABLE,"Button",BS_AUTOCHECKBOX | + BS_NOTIFY | WS_TABSTOP,7,107,132,12 + CONTROL "Kerberos 5 Ticket Options",IDC_STATIC,"Static", + SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11 +END + +IDD_PP_KRB5C DIALOGEX 0, 0, 235, 156 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Kerberos 5" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Name",IDC_STATIC,7,7,19,8 + LTEXT "Valid till",IDC_STATIC,7,39,24,8 + LTEXT "Renewable till",IDC_STATIC,7,55,45,12 + LTEXT "Issued on",IDC_STATIC,7,23,32,8 + LTEXT "Ticket flags",IDC_STATIC,7,75,37,8 + EDITTEXT IDC_PPK5_NAME,72,7,156,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_PPK5_ISSUE,72,23,156,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_PPK5_VALID,72,39,156,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_PPK5_RENEW,72,55,156,12,ES_AUTOHSCROLL | ES_READONLY + LISTBOX IDC_PPK5_FLAGS,72,74,156,75,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP +END + +IDD_PP_KRB5 DIALOGEX 0, 0, 235, 156 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Kerberos 5" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Default realm",IDC_STATIC,7,7,44,8 + LTEXT "Default lifetime",IDC_STATIC,7,22,49,8 + LTEXT "Minimum lifetime",IDC_STATIC,7,37,52,8 + LTEXT "Maximum lifetime",IDC_STATIC,7,52,55,8 + LTEXT "Renewable lifetime",IDC_STATIC,7,67,61,8 + LTEXT "Min. Renewable lifetime",IDC_STATIC,7,82,76,8 + LTEXT "Max. Renewable lifetime",IDC_STATIC,7,97,79,8 + GROUPBOX "Default ticket flags",IDC_STATIC,7,113,221,36 + CONTROL "Proxiable",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,129,45,10 + CONTROL "Renewable",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,23,129,51,10 + CONTROL "Forwardable",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,89,129,56,10 + LTEXT "ATHENA.MIT.EDU",IDC_STATIC,95,7,133,11,0, + WS_EX_CLIENTEDGE + LTEXT "10 hours",IDC_STATIC,95,22,133,11,0,WS_EX_CLIENTEDGE + LTEXT "1 minute",IDC_STATIC,95,37,133,11,0,WS_EX_CLIENTEDGE + LTEXT "7 days",IDC_STATIC,95,52,133,11,0,WS_EX_CLIENTEDGE + LTEXT "7 days",IDC_STATIC,95,67,133,11,0,WS_EX_CLIENTEDGE + LTEXT "1 minute",IDC_STATIC,95,82,133,11,0,WS_EX_CLIENTEDGE + LTEXT "21 days",IDC_STATIC,95,97,133,11,0,WS_EX_CLIENTEDGE +END + +IDD_CONFIG DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Default Realm",IDC_CFG_LBL_REALM,13,9,46,8 + COMBOBOX IDC_CFG_DEFREALM,76,7,166,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure Realms ...",IDC_CFG_CFGREALMS,76,25,84,14, + WS_DISABLED + GROUPBOX "Keberos Configuration File",IDC_CFG_CFGFILEGRP,7,45,241, + 61 + LTEXT "Location",IDC_CFG_LBL_CFGFILE,13,61,28,8 + EDITTEXT IDC_CFG_CFGFILE,76,58,119,14,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",IDC_CFG_BROWSE,198,58,44,14 + CONTROL "Create file if missing",IDC_CFG_CREATECONFIG,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,76,76,80,10 + CONTROL "Include realms in New Credentials realm list", + IDC_CFG_INCREALMS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 76,91,153,10 + GROUPBOX "Windows® Options",IDC_CFG_WINGRP,7,110,241,65 + LTEXT "Hostname",IDC_CFG_LBL_HOSTNAME,13,123,33,8 + EDITTEXT IDC_CFG_HOSTNAME,76,120,166,14,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Domain",IDC_CFG_LBL_DOMAIN,13,141,24,8 + EDITTEXT IDC_CFG_DOMAIN,76,138,166,14,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Import tickets",IDC_LBL_IMPORT,13,158,45,8 + COMBOBOX IDC_CFG_IMPORT,76,156,166,30,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +END + +IDD_CFG_REALMS DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_REALMS,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_EDITLABELS | + LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_TABSTOP,7,19,81, + 148 + GROUPBOX "Kerberos Servers",IDC_CFG_SERVERSGRP,93,7,155,91 + GROUPBOX "Domain mappings",IDC_CFG_DOMAINGRP,93,101,155,74 + CONTROL "",IDC_CFG_KDC,"SysListView32",LVS_REPORT | + LVS_EDITLABELS | LVS_ALIGNLEFT | WS_TABSTOP,99,19,143,72 + CONTROL "",IDC_CFG_DMAP,"SysListView32",LVS_REPORT | + LVS_EDITLABELS | LVS_ALIGNLEFT | WS_TABSTOP,99,111,143, + 56 +END + +IDD_CFG_IDS_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 + EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL + LTEXT "Ticket renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80, + 8 + EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL + GROUPBOX "Ticket lifetime range",IDC_CFG_LIFEGRP,7,43,221,49 + LTEXT "Minimum",IDC_STATIC,13,56,28,8 + EDITTEXT IDC_CFG_LRNG_MIN,91,53,131,14,ES_AUTOHSCROLL + LTEXT "Maximum",IDC_STATIC,13,75,30,8 + EDITTEXT IDC_CFG_LRNG_MAX,91,72,131,14,ES_AUTOHSCROLL + GROUPBOX "Ticket renewable lifetime range",IDC_STATIC,7,95,221,49 + LTEXT "Minimum",IDC_STATIC,13,108,28,8 + EDITTEXT IDC_CFG_RLRNG_MIN,91,105,131,14,ES_AUTOHSCROLL + LTEXT "Maximum",IDC_STATIC,13,128,30,8 + EDITTEXT IDC_CFG_RLRNG_MAX,91,125,131,14,ES_AUTOHSCROLL +END + +IDD_CFG_ID_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Ticket lifetime",IDC_CFG_LBL_DEFLIFE,7,10,44,8 + EDITTEXT IDC_CFG_DEFLIFE,91,7,137,14,ES_AUTOHSCROLL + LTEXT "Ticket renewable lifetime",IDC_CFG_LBL_DEFRLIFE,7,29,80, + 8 + EDITTEXT IDC_CFG_DEFRLIFE,91,26,137,14,ES_AUTOHSCROLL + LTEXT "Credentials cache",IDC_STATIC,7,63,58,8 + EDITTEXT IDC_CFG_CCACHE,91,60,137,14,ES_AUTOHSCROLL +END + +IDD_NC_KRB5_PASSWORD DIALOGEX 0, 0, 300, 166 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Kerberos 5 Change Password Options",IDC_STATIC,"Static", + SS_LEFTNOWORDWRAP | SS_SUNKEN | WS_GROUP,7,7,286,11 + LTEXT "Realm",IDC_STATIC,7,25,52,13 + COMBOBOX IDC_NCK5_REALM,60,25,233,17,CBS_DROPDOWN | + CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Specify &additional realms ...",IDC_NCK5_ADD_REALMS,181, + 43,112,16,BS_NOTIFY | WS_DISABLED +END + +IDD_CFG_CACHES DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "File Caches",IDC_CFG_FCGRP,7,38,241,137 + CONTROL "",IDC_CFG_FCLIST,"SysListView32",LVS_REPORT | + LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | + WS_TABSTOP,13,48,229,86 + EDITTEXT IDC_CFG_FCNAME,13,139,173,14,ES_AUTOHSCROLL + PUSHBUTTON "&Browse ...",IDC_CFG_BROWSE,192,139,50,14 + PUSHBUTTON "Add",IDC_CFG_ADD,13,156,50,14 + PUSHBUTTON "Remove Selected",IDC_CFG_REMOVE,88,156,80,14 + CHECKBOX "Include all API: credentials caches",IDC_CFG_INCAPI,13, + 7,125,10 + CONTROL "Include Windows LSA cache (MSLSA:)",IDC_CFG_INCMSLSA, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,22,136,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NC_KRB5, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_PP_KRB5C, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_PP_KRB5, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 13 + VERTGUIDE, 76 + VERTGUIDE, 242 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_REALMS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 93 + VERTGUIDE, 99 + VERTGUIDE, 242 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + HORZGUIDE, 19 + HORZGUIDE, 167 + END + + IDD_CFG_IDS_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + VERTGUIDE, 13 + VERTGUIDE, 91 + VERTGUIDE, 222 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_CFG_ID_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + VERTGUIDE, 91 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_NC_KRB5_PASSWORD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 293 + TOPMARGIN, 7 + BOTTOMMARGIN, 159 + END + + IDD_CFG_CACHES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 7 + VERTGUIDE, 13 + VERTGUIDE, 242 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_PLUGIN ICON "..\\..\\images\\krb5plugin.ico" +IDI_DELETED ICON "..\\..\\images\\deleted.ico" +IDI_NEW ICON "..\\..\\images\\new.ico" +IDI_NORMAL ICON "..\\..\\images\\normal.ico" +IDI_MODIFIED ICON "..\\..\\images\\modified.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_UNK_ADDR_FMT "Unknown address type %d" + IDS_KRB5_CREDTEXT_0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Creds for realm %s</p>" + IDS_KRB5_CCNAME_SHORT_DESC "Krb5 CCache" + IDS_KEY_ENCTYPE_SHORT_DESC "Key EncType" + IDS_TKT_ENCTYPE_SHORT_DESC "Ticket EncType" + IDS_KEY_ENCTYPE_LONG_DESC "Session Key Encryption Type" + IDS_TKT_ENCTYPE_LONG_DESC "Ticket Encryption Type" + IDS_ADDR_LIST_SHORT_DESC "Addresses" + IDS_ADDR_LIST_LONG_DESC "Address List" + IDS_ETYPE_NULL "NULL" + IDS_ETYPE_DES_CBC_CRC "DES-CBC-CRC" +END + +STRINGTABLE +BEGIN + IDS_ETYPE_DES_CBC_MD4 "DES-CBC-MD4" + IDS_ETYPE_DES_CBC_MD5 "DES-CBC-MD5" + IDS_ETYPE_DES_CBC_RAW "DES-CBC-RAW" + IDS_ETYPE_DES3_CBC_SHA "DES3-CBC-SHA" + IDS_ETYPE_DES3_CBC_RAW "DES3-CBC-RAW" + IDS_ETYPE_DES_HMAC_SHA1 "DES-HMAC-SHA1" + IDS_ETYPE_DES3_CBC_SHA1 "DES3-CBC-SHA1" + IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 "AES128_CTS-HMAC-SHA1_96" + IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 "AES256_CTS-HMAC-SHA1_96" + IDS_ETYPE_ARCFOUR_HMAC "RC4-HMAC-NT" + IDS_ETYPE_ARCFOUR_HMAC_EXP "RC4-HMAC-NT-EXP" + IDS_ETYPE_UNKNOWN "(Unknown)" + IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 "LOCAL-DES3-HMAC-SHA1" + IDS_ETYPE_LOCAL_RC4_MD4 "LOCAL-RC4-MD4" + IDS_KRB5_SHORT_DESC "Kerberos 5 tickets" + IDS_KRB5_LONG_DESC "Kerberos 5 tickets" +END + +STRINGTABLE +BEGIN + IDS_KRB4_SHORT_DESC "Kerberos 4" + IDS_KRB4_LONG_DESC "Kerberos 4 tickets" + IDS_KRB5_FLAGS_SHORT_DESC "Flags" + IDS_RENEW_TILL_SHORT_DESC "Renew Till" + IDS_RENEW_TILL_LONG_DESC "Renewable Till" + IDS_RENEW_FOR_SHORT_DESC "Renew for" + IDS_RENEW_FOR_LONG_DESC "Renewable for" + IDS_KRB5_CCNAME_LONG_DESC "Krb5 Primary Credentials Cache" + IDS_NC_USERNAME "Username" + IDS_NC_REALM "Realm" + IDS_KRB5_WARNING "Kerberos 5 Warning" + IDS_K5ERR_NAME_EXPIRED "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: The selected principal name has expired.</p><p><tab> Please contact your system administrator.</p>" + IDS_K5ERR_KEY_EXPIRED "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: The password for the selected identity has expired.</p><p><tab> Click <a id=""Krb5Cred:Passwd"">here</a> to change the password</p>" + IDS_KRB5_WARN_FMT "Kerberos 5: %s\n\n%s" + IDS_K5ERR_FMT "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tag>: %s</p>" + IDS_K5CFG_SHORT_DESC "Kerberos 5" +END + +STRINGTABLE +BEGIN + IDS_K5CFG_LONG_DESC "Kerberos 5 Configuration" + IDS_K5RLM_SHORT_DESC "Realms" + IDS_K5RLM_LONG_DESC "Kerberos Realm Configuration" + IDS_K5CFG_IDS_SHORT_DESC "Kerberos 5" + IDS_K5CFG_IDS_LONG_DESC "Kerberos 5 options for all identities" + IDS_K5CFG_ID_SHORT_DESC "Kerberos 5" + IDS_K5CFG_ID_LONG_DESC "Kerberos 5 options for this identity" + IDS_PLUGIN_DESC "Kerberos 5 Credentials Provider" + IDS_NC_PWD_BANNER "Changing Kerberos 5 Password" + IDS_NC_PWD_PWD "Current Password" + IDS_NC_PWD_NPWD "New Password" + IDS_NC_PWD_NPWD_AGAIN "New Password again" + IDS_KRB5_CREDTEXT_P0 "<p><a id=""SwitchPanel"" param=""Krb5Cred""><b>Krb5</b></a><tab>: Changing password for %s</p>" + IDS_K5CFG_IMPORT_OPTIONS + "Never\000Always\000Only when the principal name matches\000 " + IDS_IDENTPRO_DESC "Kerberos 5 Identity Provider" + IDS_K5CCC_SHORT_DESC "Credentials Caches" +END + +STRINGTABLE +BEGIN + IDS_K5CCC_LONG_DESC "Kerberos 5 Credentials Caches" + IDS_CFG_FCTITLE "File based Credential Caches" + IDS_CFG_FCN_WARNING "Warning:" + IDS_CFG_FCN_W_NOTFOUND "The credentials cache you specified does not exist." + IDS_CFG_FCN_W_RELATIVE "The path you specified not an absolute path." + IDS_CFG_FCOPENTITLE "Select a credential cache to add" + IDS_UNAVAILABLE "(Not available)" + IDS_FLG_FORWARDABLE "Forwardable" + IDS_FLG_FORWARDED "Forwarded" + IDS_FLG_PROXIABLE "Proxiable" + IDS_FLG_PROXY "Proxy" + IDS_FLG_MAY_POSTDATE "May postdate" + IDS_FLG_POSTDATED "Postdated" + IDS_FLG_INVALID "Invalid" + IDS_FLG_RENEWABLE "Renewable" + IDS_FLG_INITIAL "Initial" +END + +STRINGTABLE +BEGIN + IDS_FLG_PRE_AUTH "Pre-authenticated" + IDS_FLG_HW_AUTH "Hardware authentication" + IDS_FLG_TRANSIT_POL "Transit policy checked" + IDS_FLG_OK_DELEGATE "Approved for delegation" + IDS_FLG_ANONYMOUS "Anonymous" + IDS_K5ERR_CANTWRITEPROFILE + "The Kerberos 5 profile file could not be written" + IDS_K5ERR_PROFNOWRITE "The file %s could not be opened as a profile file for writing." + IDS_K5ERR_PROFUSETEMP "The file %s could not be opened for writing. The current changes will be saved to %s temporarily." + IDS_K5ERR_PROFSUGGEST "This may be due to not having privileges to modify the configuration file. Please contact your system administrator to resolve the issue." + IDS_CFG_RE_REALMS "Kerberos Realms" + IDS_CFG_RE_KDCS "Kerberos Servers" + IDS_CFG_RE_DMAPS "Domain mappings" + IDS_CFG_RE_KDCS_R "Kerberos Servers for %s" + IDS_CFG_RE_DMAPS_R "Domains that map to %s" + IDS_CFG_RE_HEAD_SVR "Server" + IDS_CFG_RE_HEAD_ADMIN "Admin" +END + +STRINGTABLE +BEGIN + IDS_CFG_RE_HEAD_MASTER "Master" + IDS_CFG_RE_HEAD_DOMAIN "Domain" + IDS_CFG_RE_NEWREALM "<New realm...>" + IDS_YES "Yes" + IDS_NO "No" + IDS_CFG_RE_NEWSERVER "<New server...>" + IDS_CFG_RE_NEWDMAP "<New domain mapping...>" + IDS_KRB5_NC_NAME "Kerberos 5" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/mechglue/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc b/mechglue/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc new file mode 100644 index 000000000..2b637ac9f --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/lang/krb5_msgs.mc @@ -0,0 +1,158 @@ +; // ** krb5_msgs.mc + +; /* Since .mc files can contain strings from any language, we define +; all our messages in one file in the /lang/ directory instead of +; language specific subdirectories. */ + +; /* The type is set to (wchar_t *) because that's what we will be +; feeding kherr_report() function. */ + +; // MessageIdTypedef=LPWSTR + +; /* Severity values as defined in the message definition file are +; currently ignored. */ + +SeverityNames=( + Success=0x0 +) + +LanguageNames=( + English=0x409:MSG_ENU +) + +OutputBase=16 + +; /* Actual messages start here */ + +MessageId=1 +Severity=Success +SymbolicName=MSG_INITIAL +Language=English +Initial placeholder message +. + +MessageId= +SymbolicName=MSG_CTX_INITAL_CREDS +Language=English +Obtaining initial Krb5 credentials +. + +MessageId= +SymbolicName=MSG_CTX_RENEW_CREDS +Language=English +Renewing Krb5 credentials +. + +MessageId= +SymbolicName=MSG_ERR_UNKNOWN +Language=English +An unknown error has occurred. +. + +MessageId= +SymbolicName=MSG_ERR_PR_UNKNOWN +Language=English +You have entered an unknown username/instance/realm combination. +. + +MessageId= +SymbolicName=MSG_ERR_TKFIL +Language=English +The tickets could not be accessed from the memory location where they were stored. +. + +MessageId= +SymbolicName=MSG_ERR_S_TKFIL +Language=English +This may be due to a problem with the memory where your tickets are stored. Restarting your computer might be worth a try. +. + +MessageId= +SymbolicName=MSG_ERR_CLOCKSKEW +Language=English +Your computer's clock is out of sync with the Kerberos server. +. + +MessageId= +SymbolicName=MSG_ERR_S_CLOCKSKEW +Language=English +Synchronize your clock withe the Kerberos server. +. + +MessageId= +SymbolicName=MSG_ERR_KDC_CONTACT +Language=English +Cannot contact the Kerberos server for the requested realm. +. + +MessageId= +SymbolicName=MSG_ERR_INSECURE_PW +Language=English +You have entered an insecure or weak password. +. + +MessageId= +SymbolicName=MSG_ERR_NO_IDENTITY +Language=English +There were no identities for which to renew credentials. +. + +MessageId= +SymbolicName=MSG_CTX_PASSWD +Language=English +Changing Kerberos 5 Password +. + +MessageId= +SymbolicName=MSG_PWD_UNKNOWN +Language=English +Unknown error +. + +MessageId= +SymbolicName=MSG_PWD_NOT_SAME +Language=English +The new passwords are not the same. +. + +MessageId= +SymbolicName=MSG_PWD_S_NOT_SAME +Language=English +The new password is asked for twice to protect against a mistake when setting the new password. Both instances of the new password must be the same. Please correct this and try again. +. + +MessageId= +SymbolicName=MSG_PWD_SAME +Language=English +The new and the old passwords are the same. +. + +MessageId= +SymbolicName=MSG_PWD_S_SAME +Language=English +Please type a new password to continue. +. + +MessageId= +SymbolicName=MSG_PWD_NO_IDENTITY +Language=English +There are no identities selected. +. + +MessageId= +SymbolicName=MSG_PWD_S_NO_IDENTITY +Language=English +Please select an identity to change the password. +. + +MessageId= +SymbolicName=MSG_ERR_S_INTEGRITY +Language=English +This is commonly caused by an incorrect password. Please verify that the password is correct and note that passwords are case sensitive. +. + + +MessageId= +SymbolicName=MSG_ +Language=English +. diff --git a/mechglue/src/windows/identity/plugins/krb5/langres.h b/mechglue/src/windows/identity/plugins/krb5/langres.h new file mode 100644 index 000000000..6f76cc56b --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/langres.h @@ -0,0 +1,187 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\plugins\krb5\lang\en_us\langres.rc +// +#define IDS_UNK_ADDR_FMT 101 +#define IDD_NC_KRB5 102 +#define IDS_KRB5_CREDTEXT_0 102 +#define IDS_KRB5_CCNAME_SHORT_DESC 103 +#define IDS_KEY_ENCTYPE_SHORT_DESC 104 +#define IDD_CONFIG 104 +#define IDS_TKT_ENCTYPE_SHORT_DESC 105 +#define IDD_CFG_REALMS 105 +#define IDS_KEY_ENCTYPE_LONG_DESC 106 +#define IDD_CFG_IDS_TAB 106 +#define IDS_TKT_ENCTYPE_LONG_DESC 107 +#define IDD_PP_KRB5C 107 +#define IDS_ADDR_LIST_SHORT_DESC 108 +#define IDD_PP_KRB5 108 +#define IDS_ADDR_LIST_LONG_DESC 109 +#define IDD_CFG_ID_TAB 109 +#define IDS_ETYPE_NULL 110 +#define IDD_NC_KRB5_PASSWORD 110 +#define IDS_ETYPE_DES_CBC_CRC 111 +#define IDD_CFG_CACHES 111 +#define IDS_ETYPE_DES_CBC_MD4 112 +#define IDI_PLUGIN 112 +#define IDS_ETYPE_DES_CBC_MD5 113 +#define IDI_DELETED 113 +#define IDS_ETYPE_DES_CBC_RAW 114 +#define IDI_NEW 114 +#define IDS_ETYPE_DES3_CBC_SHA 115 +#define IDI_NORMAL 115 +#define IDS_ETYPE_DES3_CBC_RAW 116 +#define IDI_MODIFIED 116 +#define IDS_ETYPE_DES_HMAC_SHA1 117 +#define IDS_ETYPE_DES3_CBC_SHA1 118 +#define IDS_ETYPE_AES128_CTS_HMAC_SHA1_96 119 +#define IDS_ETYPE_AES256_CTS_HMAC_SHA1_96 120 +#define IDS_ETYPE_ARCFOUR_HMAC 121 +#define IDS_ETYPE_ARCFOUR_HMAC_EXP 122 +#define IDS_ETYPE_UNKNOWN 123 +#define IDS_ETYPE_LOCAL_DES3_HMAC_SHA1 124 +#define IDS_ETYPE_LOCAL_RC4_MD4 125 +#define IDS_KRB5_SHORT_DESC 126 +#define IDS_KRB5_LONG_DESC 127 +#define IDS_KRB4_SHORT_DESC 128 +#define IDS_KRB4_LONG_DESC 129 +#define IDS_KRB5_FLAGS_SHORT_DESC 130 +#define IDS_RENEW_TILL_SHORT_DESC 131 +#define IDS_RENEW_TILL_LONG_DESC 132 +#define IDS_RENEW_FOR_SHORT_DESC 133 +#define IDS_RENEW_FOR_LONG_DESC 134 +#define IDS_KRB5_CCNAME_LONG_DESC 135 +#define IDS_NC_USERNAME 136 +#define IDS_NC_REALM 137 +#define IDS_KRB5_WARNING 138 +#define IDS_K5ERR_NAME_EXPIRED 139 +#define IDS_K5ERR_KEY_EXPIRED 140 +#define IDS_KRB5_WARN_FMT 141 +#define IDS_K5ERR_FMT 142 +#define IDS_K5CFG_SHORT_DESC 143 +#define IDS_K5CFG_LONG_DESC 144 +#define IDS_K5RLM_SHORT_DESC 145 +#define IDS_K5RLM_LONG_DESC 146 +#define IDS_K5CFG_IDS_SHORT_DESC 147 +#define IDS_K5CFG_IDS_LONG_DESC 148 +#define IDS_K5CFG_ID_SHORT_DESC 149 +#define IDS_K5CFG_ID_LONG_DESC 150 +#define IDS_PLUGIN_DESC 151 +#define IDS_NC_PWD_BANNER 152 +#define IDS_NC_PWD_PWD 153 +#define IDS_NC_PWD_NPWD 154 +#define IDS_NC_PWD_NPWD_AGAIN 155 +#define IDS_KRB5_CREDTEXT_P0 156 +#define IDS_K5CFG_IMPORT_OPTIONS 157 +#define IDS_IDENTPRO_DESC 158 +#define IDS_K5CCC_SHORT_DESC 159 +#define IDS_K5CCC_LONG_DESC 160 +#define IDS_CFG_FCTITLE 161 +#define IDS_CFG_FCN_WARNING 162 +#define IDS_CFG_FCN_W_NOTFOUND 163 +#define IDS_CFG_FCN_W_RELATIVE 164 +#define IDS_CFG_FCOPENTITLE 165 +#define IDS_UNAVAILABLE 166 +#define IDS_FLG_FORWARDABLE 167 +#define IDS_FLG_FORWARDED 168 +#define IDS_FLG_PROXIABLE 169 +#define IDS_FLG_PROXY 170 +#define IDS_FLG_MAY_POSTDATE 171 +#define IDS_FLG_POSTDATED 172 +#define IDS_FLG_INVALID 173 +#define IDS_FLG_RENEWABLE 174 +#define IDS_FLG_INITIAL 175 +#define IDS_FLG_PRE_AUTH 176 +#define IDS_FLG_HW_AUTH 177 +#define IDS_FLG_TRANSIT_POL 178 +#define IDS_FLG_OK_DELEGATE 179 +#define IDS_FLG_ANONYMOUS 180 +#define IDS_K5ERR_CANTWRITEPROFILE 181 +#define IDS_K5ERR_PROFNOWRITE 182 +#define IDS_K5ERR_PROFUSETEMP 183 +#define IDS_K5ERR_PROFSUGGEST 184 +#define IDS_CFG_RE_REALMS 185 +#define IDS_CFG_RE_KDCS 186 +#define IDS_CFG_RE_DMAPS 187 +#define IDS_CFG_RE_KDCS_R 188 +#define IDS_CFG_RE_DMAPS_R 189 +#define IDS_CFG_RE_HEAD_SVR 190 +#define IDS_CFG_RE_HEAD_ADMIN 191 +#define IDS_CFG_RE_HEAD_MASTER 192 +#define IDS_CFG_RE_HEAD_DOMAIN 193 +#define IDS_CFG_RE_NEWREALM 194 +#define IDS_YES 195 +#define IDS_NO 196 +#define IDS_CFG_RE_NEWSERVER 197 +#define IDS_CFG_RE_NEWDMAP 198 +#define IDS_KRB5_NC_NAME 199 +#define IDC_NCK5_RENEWABLE 1002 +#define IDC_NCK5_FORWARDABLE 1004 +#define IDC_NCK5_REALM 1005 +#define IDC_NCK5_ADD_REALMS 1006 +#define IDC_NCK5_LIFETIME_EDIT 1008 +#define IDC_NCK5_RENEW_EDIT 1009 +#define IDC_PPK5_CRENEW 1014 +#define IDC_PPK5_CFORWARD 1015 +#define IDC_PPK5_CPROXY 1016 +#define IDC_PPK5_NAME 1017 +#define IDC_PPK5_ISSUE 1018 +#define IDC_PPK5_VALID 1019 +#define IDC_PPK5_RENEW 1020 +#define IDC_CHECK2 1022 +#define IDC_CHECK4 1024 +#define IDC_PPK5_LIFETIME 1024 +#define IDC_CHECK5 1025 +#define IDC_CFG_LBL_REALM 1025 +#define IDC_CFG_DEFREALM 1026 +#define IDC_CFG_LBL_CFGFILE 1029 +#define IDC_CFG_CFGFILE 1030 +#define IDC_CFG_WINGRP 1031 +#define IDC_LBL_IMPORT 1032 +#define IDC_CFG_IMPORT 1033 +#define IDC_CFG_LBL_HOSTNAME 1034 +#define IDC_CFG_HOSTNAME 1035 +#define IDC_CFG_LBL_DOMAIN 1036 +#define IDC_CFG_DOMAIN 1037 +#define IDC_CFG_CREATECONFIG 1038 +#define IDC_CFG_BROWSE 1039 +#define IDC_CFG_CFGFILEGRP 1040 +#define IDC_CFG_CFGREALMS 1041 +#define IDC_CFG_REALMS 1044 +#define IDC_CFG_DOMAINGRP 1045 +#define IDC_CFG_SERVERSGRP 1046 +#define IDC_LIST3 1047 +#define IDC_CFG_KDC 1047 +#define IDC_LIST4 1048 +#define IDC_CFG_DMAP 1048 +#define IDC_CFG_LBL_DEFLIFE 1049 +#define IDC_CFG_DEFLIFE 1050 +#define IDC_CFG_LBL_DEFRLIFE 1051 +#define IDC_CFG_DEFRLIFE 1052 +#define IDC_CFG_LIFEGRP 1053 +#define IDC_CFG_LRNG_MIN 1054 +#define IDC_CFG_LRNG_MAX 1055 +#define IDC_CFG_RLRNG_MIN 1056 +#define IDC_CFG_RLRNG_MAX 1057 +#define IDC_CFG_CCACHE 1058 +#define IDC_CFG_FCGRP 1059 +#define IDC_CFG_FCLIST 1060 +#define IDC_CFG_FCNAME 1062 +#define IDC_CFG_ADD 1064 +#define IDC_CFG_REMOVE 1065 +#define IDC_CFG_INCAPI 1066 +#define IDC_CFG_INCMSLSA 1067 +#define IDC_PPK5_FLAGS 1072 +#define IDC_CHECK1 1073 +#define IDC_CFG_INCREALMS 1073 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 117 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1074 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/mechglue/src/windows/identity/plugins/krb5/version.rc b/mechglue/src/windows/identity/plugins/krb5/version.rc new file mode 100644 index 000000000..10b16dd29 --- /dev/null +++ b/mechglue/src/windows/identity/plugins/krb5/version.rc @@ -0,0 +1,64 @@ +/* Copyright (c) 2004 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* $Id$ */ + +#include<netidmgr_intver.h> + +1 VERSIONINFO + FILEVERSION KH_VERSION_LIST + PRODUCTVERSION KH_VERSION_LIST + FILEFLAGSMASK KH_VER_FILEFLAGMASK + FILEFLAGS KH_VER_FILEFLAGS + FILEOS KH_VER_FILEOS + FILETYPE KH_VER_FILETYPEDLL + FILESUBTYPE 0 + { + BLOCK "StringFileInfo" + { + BLOCK "040904b0" + { + VALUE "CompanyName", KH_VERSTR_COMPANY_1033 + VALUE "FileDescription", "Kerberos 5 plugin for NetIDMgr" + VALUE "FileVersion", KH_VERSTR_VERSION_1033 + VALUE "InternalName", "krb5cred" + VALUE "LegalCopyright", KH_VERSTR_COPYRIGHT_1033 + VALUE "OriginalFilename", "krb5cred.dll" + VALUE "ProductName", "NetIDMgr" + VALUE "ProductVersion", KH_VERSTR_PRODUCT_1033 +#ifdef KH_VERSTR_COMMENT_1033 + VALUE "Comment", KH_VERSTR_COMMENT_1033 +#endif + VALUE NIMV_MODULE, "MITKrb5" + VALUE NIMV_PLUGINS, "Krb5Cred,Krb5Ident" + VALUE NIMV_APIVER, KH_VERSION_STRINGAPI + VALUE NIMV_SUPPORT, "http://web.mit.edu/kerberos" + } + } + + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x409, 0x4b0 + } + } diff --git a/mechglue/src/windows/identity/ui/Makefile b/mechglue/src/windows/identity/ui/Makefile new file mode 100644 index 000000000..7b3acc40f --- /dev/null +++ b/mechglue/src/windows/identity/ui/Makefile @@ -0,0 +1,90 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=ui +!include <../config/Makefile.w32> + +EXEFILE=$(BINDIR)\netidmgr.exe + +MANIFESTFILE=$(BINDIR)\netidmgr.exe.manifest + +OBJFILES= \ + $(OBJ)\main.obj \ + $(OBJ)\mainmenu.obj \ + $(OBJ)\toolbar.obj \ + $(OBJ)\statusbar.obj \ + $(OBJ)\notifier.obj \ + $(OBJ)\timer.obj \ + $(OBJ)\uiconfig.obj \ + $(OBJ)\mainwnd.obj \ + $(OBJ)\credwnd.obj \ + $(OBJ)\htwnd.obj \ + $(OBJ)\passwnd.obj \ + $(OBJ)\newcredwnd.obj \ + $(OBJ)\propertywnd.obj \ + $(OBJ)\credfuncs.obj \ + $(OBJ)\configwnd.obj \ + $(OBJ)\aboutwnd.obj \ + $(OBJ)\reqdaemon.obj \ + $(OBJ)\addrchange.obj \ + $(OBJ)\cfg_general_wnd.obj \ + $(OBJ)\cfg_identities_wnd.obj \ + $(OBJ)\cfg_notif_wnd.obj \ + $(OBJ)\cfg_plugins_wnd.obj + +RESFILES= \ + $(OBJ)\khapp.res \ + $(OBJ)\appver.res + +LIBFILES= \ + $(LIBDIR)\nidmgr32.lib + +SDKLIBFILES= \ + comctl32.lib \ + shell32.lib \ + htmlhelp.lib \ + iphlpapi.lib \ + shlwapi.lib + +$(OBJ)\uiconfig.c: uiconfig.csv $(CONFDIR)\csvschema.cfg + $(CCSV) $** $@ + +$(OBJ)\khapp.res: lang\en_us\khapp.rc + $(RC2RES) + +$(OBJ)\appver.res: appver.rc + $(RC2RES) + +!if "$(KH_BUILD)"=="RETAIL" +$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER) +!else +$(MANIFESTFILE): netidmgr.manifest.$(CPU).$(KH_CLVER).debug +!endif + $(CP) $** $@ + +$(EXEFILE): $(OBJFILES) $(RESFILES) $(LIBFILES) + $(EXEGUILINK) $(SDKLIBFILES) + +all: mkdirs $(EXEFILE) $(MANIFESTFILE) + diff --git a/mechglue/src/windows/identity/ui/aboutwnd.c b/mechglue/src/windows/identity/ui/aboutwnd.c new file mode 100644 index 000000000..da7abdfee --- /dev/null +++ b/mechglue/src/windows/identity/ui/aboutwnd.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<netidmgr_intver.h> +#include<tlhelp32.h> + +#if DEBUG +#include<assert.h> +#endif + +INT_PTR CALLBACK +about_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch(uMsg) { + case WM_INITDIALOG: + { + HANDLE hsnap; + HWND hw; + + SetDlgItemText(hwnd, IDC_PRODUCT, + TEXT(KH_VERSTR_PRODUCT_1033)); + SetDlgItemText(hwnd, IDC_COPYRIGHT, + TEXT(KH_VERSTR_COPYRIGHT_1033)); + SetDlgItemText(hwnd, IDC_BUILDINFO, + TEXT(KH_VERSTR_BUILDINFO_1033)); + + hsnap = + CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, + 0); + + if (hsnap != INVALID_HANDLE_VALUE) { + LVCOLUMN lvc; + MODULEENTRY32 mod; + RECT r; + + hw = GetDlgItem(hwnd, IDC_MODULES); +#ifdef DEBUG + assert(hw != NULL); +#endif + + GetWindowRect(hw, &r); + OffsetRect(&r, -r.left, -r.top); + + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + + lvc.pszText = L"Name"; + lvc.cx = r.right / 4; + + ListView_InsertColumn(hw, 0, &lvc); + + lvc.pszText = L"Path"; + lvc.cx = (r.right * 3) / 4; + ListView_InsertColumn(hw, 1, &lvc); + + ZeroMemory(&mod, sizeof(mod)); + mod.dwSize = sizeof(mod); + + /* done with columns, now for the actual data */ + if (!Module32First(hsnap, &mod)) + goto _done_with_modules; + + do { + + LVITEM lvi; + int idx; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_TEXT; + lvi.pszText = mod.szModule; + idx = ListView_InsertItem(hw, &lvi); + + lvi.mask = LVIF_TEXT; + lvi.iItem = idx; + lvi.iSubItem = 1; + lvi.pszText = mod.szExePath; + ListView_SetItem(hw, &lvi); + + ZeroMemory(&mod, sizeof(mod)); + mod.dwSize = sizeof(mod); + } while(Module32Next(hsnap, &mod)); + + _done_with_modules: + CloseHandle(hsnap); + } + + khm_add_dialog(hwnd); + khm_enter_modal(hwnd); + } + return FALSE; + + case WM_DESTROY: + khm_leave_modal(); + khm_del_dialog(hwnd); + return TRUE; + + case WM_COMMAND: + if (wParam == MAKEWPARAM(IDOK, BN_CLICKED)) + DestroyWindow(hwnd); + return TRUE; + } + + return FALSE; +} + +void +khm_create_about_window(void) { + HWND hwnd; + hwnd = CreateDialog(khm_hInstance, + MAKEINTRESOURCE(IDD_ABOUT), + khm_hwnd_main, + about_dlg_proc); + + ShowWindow(hwnd, SW_SHOW); + /* no need to keep track of the hwnd, since we add it to the + dialog chain in the dialog procedure */ +} diff --git a/mechglue/src/windows/identity/ui/aboutwnd.h b/mechglue/src/windows/identity/ui/aboutwnd.h new file mode 100644 index 000000000..81b7e9047 --- /dev/null +++ b/mechglue/src/windows/identity/ui/aboutwnd.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ABOUTWND_H +#define __KHIMAIRA_ABOUTWND_H + +void +khm_create_about_window(void); + +#endif diff --git a/mechglue/src/windows/identity/ui/addrchange.c b/mechglue/src/windows/identity/ui/addrchange.c new file mode 100644 index 000000000..8a671b3c9 --- /dev/null +++ b/mechglue/src/windows/identity/ui/addrchange.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<iphlpapi.h> + +static HANDLE evt_terminate = NULL; +static HANDLE h_thread = NULL; + +DWORD WINAPI +addr_change_thread(LPVOID dummy) { + + HANDLE h_waits[2]; + HANDLE h_notify; + + OVERLAPPED overlap; + DWORD ret; + + ZeroMemory(&overlap, sizeof(overlap)); + + h_notify = NULL; + overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + do { + ret = NotifyAddrChange(&h_notify, &overlap); + + if (ret != ERROR_IO_PENDING) { + goto _end_thread; /* some error */ + } + + h_waits[0] = overlap.hEvent; + h_waits[1] = evt_terminate; + + ret = WaitForMultipleObjects(2, h_waits, FALSE, INFINITE); + + if ( ret == WAIT_OBJECT_0 ) { + kmq_post_message(KMSG_CRED, KMSG_CRED_ADDR_CHANGE, + 0, 0); + } else { + goto _end_thread; + } + } while(TRUE); + + _end_thread: + ExitThread(0); + return 0; /* unreachable */ +} + +void +khm_addr_change_notifier_init(void) { + evt_terminate = CreateEvent(NULL, FALSE, FALSE, NULL); + h_thread = CreateThread(NULL, + 64 * 4096, + addr_change_thread, + NULL, + 0, + NULL); +} + +void +khm_addr_change_notifier_exit(void) { + if (h_thread && evt_terminate) { + SetEvent(evt_terminate); + WaitForSingleObject(h_thread, INFINITE); + + CloseHandle(h_thread); + CloseHandle(evt_terminate); + } +} diff --git a/mechglue/src/windows/identity/ui/addrchange.h b/mechglue/src/windows/identity/ui/addrchange.h new file mode 100644 index 000000000..08c15041f --- /dev/null +++ b/mechglue/src/windows/identity/ui/addrchange.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __NETIDMGR_ADDRCHANGE_H +#define __NETIDMGR_ADDRCHANGE_H + +void +khm_addr_change_notifier_init(void); + +void +khm_addr_change_notifier_exit(void); + +#endif diff --git a/mechglue/src/windows/identity/ui/appglobal.h b/mechglue/src/windows/identity/ui/appglobal.h new file mode 100644 index 000000000..9baa9b9e2 --- /dev/null +++ b/mechglue/src/windows/identity/ui/appglobal.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_APPGLOBAL_H +#define __KHIMAIRA_APPGLOBAL_H + +/* Helpfile */ +#define NIDM_HELPFILE L"netidmgr.chm" + +/* global data */ +extern HINSTANCE khm_hInstance; +extern int khm_nCmdShow; +extern const wchar_t * khm_facility; +extern kconf_schema schema_uiconfig[]; +extern khm_ui_4 khm_commctl_version; + +#define IS_COMMCTL6() (khm_commctl_version >= 0x60000) + +typedef struct tag_khm_startup_options { + BOOL seen; + BOOL processing; + + BOOL init; + BOOL import; + BOOL renew; + BOOL destroy; + + BOOL autoinit; + BOOL exit; + BOOL error_exit; + + BOOL no_main_window; +} khm_startup_options; + +extern khm_startup_options khm_startup; + +void khm_add_dialog(HWND dlg); +void khm_del_dialog(HWND dlg); +BOOL khm_is_dialog_active(void); + +void khm_enter_modal(HWND hwnd); +void khm_leave_modal(void); + +void khm_add_property_sheet(khui_property_sheet * s); +void khm_del_property_sheet(khui_property_sheet * s); + +void khm_init_gui(void); +void khm_exit_gui(void); + +void khm_parse_commandline(); +void khm_register_window_classes(void); + +HWND khm_html_help(HWND hwnd, wchar_t * suffix, UINT command, DWORD_PTR data); + +#define MAX_RES_STRING 1024 + +#define ELIPSIS L"..." + +#endif diff --git a/mechglue/src/windows/identity/ui/appver.rc b/mechglue/src/windows/identity/ui/appver.rc new file mode 100644 index 000000000..9d2dbc4eb --- /dev/null +++ b/mechglue/src/windows/identity/ui/appver.rc @@ -0,0 +1,40 @@ + +#include<windows.h> +#include<netidmgr_intver.h> + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION KH_VERSION_LIST + PRODUCTVERSION KH_VERSION_LIST + FILEFLAGSMASK 0x17L + FILEFLAGS KH_VER_FILEFLAGS + FILEOS KH_VER_FILEOS + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", KH_VERSTR_COMPANY_1033 + VALUE "FileDescription", "Network Identity Manager" + VALUE "FileVersion", KH_VERSTR_VERSION_1033 + VALUE "InternalName", "NetIDMgr" + VALUE "LegalCopyright", KH_VERSTR_COPYRIGHT_1033 + VALUE "OriginalFilename", "netidmgr.exe" + VALUE "ProductName", "NetIDMgr" + VALUE "ProductVersion", KH_VERSTR_PRODUCT_1033 +#ifdef KH_VERSTR_COMMENT_1033 + VALUE "Comment", KH_VERSTR_COMMENT_1033 +#endif + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/mechglue/src/windows/identity/ui/cfg_general_wnd.c b/mechglue/src/windows/identity/ui/cfg_general_wnd.c new file mode 100644 index 000000000..7b48975a9 --- /dev/null +++ b/mechglue/src/windows/identity/ui/cfg_general_wnd.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +typedef struct tag_cfg_data { + BOOL auto_init; + BOOL auto_start; + BOOL auto_import; + BOOL keep_running; + BOOL auto_detect_net; +} cfg_data; + +typedef struct tag_dlg_data { + khui_config_node node; + cfg_data saved; + cfg_data work; +} dlg_data; + +static void +read_params(dlg_data * dd) { + cfg_data * d; + khm_handle csp_cw; + khm_int32 t; + + d = &dd->saved; + + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, + &csp_cw))) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + khc_read_int32(csp_cw, L"AutoInit", &t); + d->auto_init = !!t; + + khc_read_int32(csp_cw, L"AutoStart", &t); + d->auto_start = !!t; + + khc_read_int32(csp_cw, L"AutoImport", &t); + d->auto_import = !!t; + + khc_read_int32(csp_cw, L"KeepRunning", &t); + d->keep_running = !!t; + + khc_read_int32(csp_cw, L"AutoDetectNet", &t); + d->auto_detect_net = !!t; + + khc_close_space(csp_cw); + + dd->work = *d; +} + +static void +write_params(dlg_data * dd) { + cfg_data * d, * s; + khm_handle csp_cw; + BOOL applied = FALSE; + + d = &dd->work; + s = &dd->saved; + + if (KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, + &csp_cw))) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + if (!!d->auto_init != !!s->auto_init) { + khc_write_int32(csp_cw, L"AutoInit", d->auto_init); + applied = TRUE; + } + + if (!!d->auto_start != !!s->auto_start) { + khc_write_int32(csp_cw, L"AutoStart", d->auto_start); + applied = TRUE; + } + + if (!!d->auto_import != !!s->auto_import) { + khc_write_int32(csp_cw, L"AutoImport", d->auto_import); + applied = TRUE; + } + + if (!!d->keep_running != !!s->keep_running) { + khc_write_int32(csp_cw, L"KeepRunning", d->keep_running); + applied = TRUE; + } + + if (!!d->auto_detect_net != !!s->auto_detect_net) { + khc_write_int32(csp_cw, L"AutoDetectNet", d->auto_detect_net); + applied = TRUE; + } + + khc_close_space(csp_cw); + + khui_cfg_set_flags(dd->node, + (applied) ? KHUI_CNFLAG_APPLIED : 0, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); + + *s = *d; +} + +static void +check_for_modification(dlg_data * dd) { + cfg_data * d, * s; + d = &dd->work; + s = &dd->saved; + + if (!!d->auto_init != !!s->auto_init || + !!d->auto_start != !!s->auto_start || + !!d->auto_import != !!s->auto_import || + !!d->keep_running != !!s->keep_running || + !!d->auto_detect_net != !!s->auto_detect_net) { + + khui_cfg_set_flags(dd->node, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + + } else { + + khui_cfg_set_flags(dd->node, + 0, + KHUI_CNFLAG_MODIFIED); + + } +} + +static void +refresh_view(HWND hwnd, dlg_data * d) { + CheckDlgButton(hwnd, IDC_CFG_AUTOINIT, + (d->work.auto_init?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_AUTOSTART, + (d->work.auto_start?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_AUTOIMPORT, + (d->work.auto_import?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_KEEPRUNNING, + (d->work.keep_running?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_NETDETECT, + (d->work.auto_detect_net?BST_CHECKED:BST_UNCHECKED)); +} + +static void +refresh_data(HWND hwnd, dlg_data * d) { + d->work.auto_init = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOINIT) + == BST_CHECKED); + d->work.auto_start = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOSTART) + == BST_CHECKED); + d->work.auto_import = (IsDlgButtonChecked(hwnd, IDC_CFG_AUTOIMPORT) + == BST_CHECKED); + d->work.keep_running = (IsDlgButtonChecked(hwnd, IDC_CFG_KEEPRUNNING) + == BST_CHECKED); + d->work.auto_detect_net = (IsDlgButtonChecked(hwnd, IDC_CFG_NETDETECT) + == BST_CHECKED); +} + +INT_PTR CALLBACK +khm_cfg_general_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d != NULL); +#endif + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + ZeroMemory(d, sizeof(*d)); + + d->node = (khui_config_node) lParam; + + read_params(d); + + refresh_view(hwnd, d); + + return FALSE; + + case WM_COMMAND: + d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == BN_CLICKED) { + refresh_data(hwnd, d); + check_for_modification(d); + } + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + d = (dlg_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + write_params(d); + } + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + return FALSE; +} diff --git a/mechglue/src/windows/identity/ui/cfg_identities_wnd.c b/mechglue/src/windows/identity/ui/cfg_identities_wnd.c new file mode 100644 index 000000000..0ec3dcbbb --- /dev/null +++ b/mechglue/src/windows/identity/ui/cfg_identities_wnd.c @@ -0,0 +1,1102 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +static khui_config_node +get_window_node(HWND hwnd) { + return (khui_config_node) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +} + +static void +set_window_node(HWND hwnd, khui_config_node node) { +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, + (LONG_PTR) node); +#pragma warning(pop) +} + +static void +add_subpanels(HWND hwnd, + khui_config_node ctx_node, + khui_config_node ref_node) { + + HWND hw_tab; + HWND hw_target; + khui_config_node sub; + khui_config_node_reg reg; + khui_config_init_data idata; + int idx; + + hw_tab = GetDlgItem(hwnd, IDC_CFG_TAB); + hw_target = GetDlgItem(hwnd, IDC_CFG_TARGET); +#ifdef DEBUG + assert(hw_tab); + assert(hw_target); +#endif + + if (KHM_FAILED(khui_cfg_get_first_subpanel(ref_node, &sub))) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + idx = 0; + while(sub) { + HWND hwnd_panel; + TCITEM tci; + int iid; + + khui_cfg_get_reg(sub, ®); + + if ((ctx_node == ref_node && (reg.flags & KHUI_CNFLAG_PLURAL)) || + (ctx_node != ref_node && !(reg.flags & KHUI_CNFLAG_PLURAL))) + goto _next_node; + + idata.ctx_node = ctx_node; + idata.this_node = sub; + idata.ref_node = ref_node; + + hwnd_panel = CreateDialogParam(reg.h_module, + reg.dlg_template, + hwnd, + reg.dlg_proc, + (LPARAM) &idata); + +#ifdef DEBUG + assert(hwnd_panel); +#endif + + ShowWindow(hwnd_panel, SW_HIDE); + + ZeroMemory(&tci, sizeof(tci)); + + tci.mask = TCIF_PARAM | TCIF_TEXT; + tci.lParam = (LPARAM) sub; + tci.pszText = (LPWSTR) reg.short_desc; + + iid = TabCtrl_InsertItem(hw_tab, 0, &tci); + idx++; + + if (reg.flags & KHUI_CNFLAG_PLURAL) { + khui_cfg_set_param_inst(sub, ctx_node, iid); + khui_cfg_set_hwnd_inst(sub, ctx_node, hwnd_panel); + } else { + khui_cfg_set_param(sub, iid); + khui_cfg_set_hwnd(sub, hwnd_panel); + } + + _next_node: + + khui_cfg_get_next_release(&sub); + } + + TabCtrl_SetCurSel(hw_tab, 0); +} + +static void +apply_all(HWND hwnd, + HWND hw_tab, + khui_config_node noderef) { + TCITEM tci; + HWND hw; + khui_config_node_reg reg; + int idx; + int count; + + count = TabCtrl_GetItemCount(hw_tab); + + for (idx = 0; idx < count; idx++) { + + ZeroMemory(&tci, sizeof(tci)); + + tci.mask = TCIF_PARAM; + TabCtrl_GetItem(hw_tab, + idx, + &tci); + +#ifdef DEBUG + assert(tci.lParam); +#endif + khui_cfg_get_reg((khui_config_node) tci.lParam, ®); + if (reg.flags & KHUI_CNFLAG_PLURAL) + hw = khui_cfg_get_hwnd_inst((khui_config_node) tci.lParam, + noderef); + else + hw = khui_cfg_get_hwnd((khui_config_node) tci.lParam); +#ifdef DEBUG + assert(hw); +#endif + + PostMessage(hw, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_APPLY), 0); + } +} + +static void +show_tab_panel(HWND hwnd, + khui_config_node node, + HWND hw_tab, + int idx, + BOOL show) { + TCITEM tci; + HWND hw; + HWND hw_target; + RECT r; + RECT rref; + khui_config_node_reg reg; + + ZeroMemory(&tci, sizeof(tci)); + + tci.mask = TCIF_PARAM; + TabCtrl_GetItem(hw_tab, + idx, + &tci); + +#ifdef DEBUG + assert(tci.lParam); +#endif + khui_cfg_get_reg((khui_config_node) tci.lParam, ®); + if (reg.flags & KHUI_CNFLAG_PLURAL) + hw = khui_cfg_get_hwnd_inst((khui_config_node) tci.lParam, + node); + else + hw = khui_cfg_get_hwnd((khui_config_node) tci.lParam); +#ifdef DEBUG + assert(hw); +#endif + + if (!show) { + ShowWindow(hw, SW_HIDE); + return; + } + + hw_target = GetDlgItem(hwnd, IDC_CFG_TARGET); +#ifdef DEBUG + assert(hw_target); +#endif + GetWindowRect(hwnd, &rref); + GetWindowRect(hw_target, &r); + + OffsetRect(&r, -rref.left, -rref.top); + + SetWindowPos(hw, + hw_tab, + r.left, r.top, + r.right - r.left, r.bottom - r.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_SHOWWINDOW); +} + +static INT_PTR +handle_cfg_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) { + khui_config_node node; + HWND hw; + + node = get_window_node(hwnd); + + if (HIWORD(wParam) == WMCFG_APPLY) { + + hw = GetDlgItem(hwnd, IDC_CFG_TAB); + + apply_all(hwnd, + hw, + node); + } + + return TRUE; +} + +static INT_PTR +handle_notify(HWND hwnd, + WPARAM wParam, + LPARAM lParam) { + LPNMHDR lpnm; + int i; + + + khui_config_node node; + + lpnm = (LPNMHDR) lParam; + node = get_window_node(hwnd); + + if (lpnm->idFrom == IDC_CFG_TAB) { + switch(lpnm->code) { + case TCN_SELCHANGING: + i = TabCtrl_GetCurSel(lpnm->hwndFrom); + + show_tab_panel(hwnd, + node, + lpnm->hwndFrom, + i, + FALSE); + break; + + case TCN_SELCHANGE: + i = TabCtrl_GetCurSel(lpnm->hwndFrom); + + show_tab_panel(hwnd, + node, + lpnm->hwndFrom, + i, + TRUE); + break; + } + return TRUE; + } else { + return FALSE; + } +} + +typedef struct tag_ident_props { + BOOL monitor; + BOOL auto_renew; + BOOL sticky; +} ident_props; + +typedef struct tag_ident_data { + khm_handle ident; + wchar_t * idname; + int lv_idx; + + BOOL removed; + BOOL applied; + + khm_int32 flags; + + ident_props saved; + ident_props work; + + HWND hwnd; +} ident_data; + +typedef struct tag_global_props { + BOOL monitor; + BOOL auto_renew; + BOOL sticky; +} global_props; + +typedef struct tag_idents_data { + BOOL valid; + + ident_data * idents; + khm_size n_idents; + khm_size nc_idents; + + /* global options */ + global_props saved; + global_props work; + BOOL applied; + + int refcount; + + HIMAGELIST hi_status; + int idx_id; + int idx_default; + int idx_modified; + int idx_applied; + int idx_deleted; + + HWND hwnd; + khui_config_init_data cfg; +} idents_data; + +static idents_data cfg_idents = {FALSE, NULL, 0, 0, + {0, 0, 0}, + {0, 0, 0}, + FALSE, + + 0, NULL }; + +static void +read_params_ident(ident_data * d) { + khm_handle csp_ident; + khm_handle csp_cw; + khm_int32 t; + + if (KHM_FAILED(kcdb_identity_get_config(d->ident, + KHM_PERM_READ, + &csp_ident))) { + csp_ident = NULL; + } + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, + &csp_cw))) { + if (csp_ident) { + khc_shadow_space(csp_ident, + csp_cw); + khc_close_space(csp_cw); + } else { + csp_ident = csp_cw; + } + csp_cw = NULL; + } else { +#ifdef DEBUG + assert(FALSE); +#endif + d->saved.monitor = TRUE; + d->saved.auto_renew = TRUE; + d->saved.sticky = FALSE; + d->work = d->saved; + + if (csp_ident) + khc_close_space(csp_ident); + + return; + } + + if (KHM_FAILED(khc_read_int32(csp_ident, L"Monitor", &t))) { +#ifdef DEBUG + assert(FALSE); +#endif + d->saved.monitor = TRUE; + } else { + d->saved.monitor = !!t; + } + + if (KHM_FAILED(khc_read_int32(csp_ident, L"AllowAutoRenew", &t))) { +#ifdef DEBUG + assert(FALSE); +#endif + d->saved.auto_renew = TRUE; + } else { + d->saved.auto_renew = !!t; + } + + if (KHM_FAILED(khc_read_int32(csp_ident, L"Sticky", &t))) { + d->saved.sticky = FALSE; + } else { + d->saved.sticky = !!t; + } + + khc_close_space(csp_ident); + + d->work = d->saved; + d->applied = FALSE; +} + +static void +write_params_ident(ident_data * d) { + khm_handle csp_ident; + + if (d->saved.monitor == d->work.monitor && + d->saved.auto_renew == d->work.auto_renew && + d->saved.sticky == d->work.sticky && + !d->removed) + return; + + if (KHM_FAILED(kcdb_identity_get_config(d->ident, KHM_PERM_WRITE, + &csp_ident))) { +#ifdef DEBUG + assert(FALSE); +#endif + return; + } + + if (d->removed) { + + khc_remove_space(csp_ident); + + } else { + + if (d->saved.monitor != d->work.monitor) + khc_write_int32(csp_ident, L"Monitor", !!d->work.monitor); + + if (d->saved.auto_renew != d->work.auto_renew) + khc_write_int32(csp_ident, L"AllowAutoRenew", + !!d->work.auto_renew); + + if (d->saved.sticky != d->work.sticky) { + kcdb_identity_set_flags(d->ident, + (d->work.sticky)?KCDB_IDENT_FLAG_STICKY:0, + KCDB_IDENT_FLAG_STICKY); + } + } + + khc_close_space(csp_ident); + + d->saved = d->work; + + d->applied = TRUE; + + if (d->hwnd) + PostMessage(d->hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0); +} + +static void +write_params_idents(void) { + int i; + khm_handle csp_cw; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + KHM_FLAG_CREATE, &csp_cw))) { + if (cfg_idents.work.monitor != cfg_idents.saved.monitor) { + khc_write_int32(csp_cw, L"DefaultMonitor", + !!cfg_idents.work.monitor); + cfg_idents.work.monitor = cfg_idents.saved.monitor; + cfg_idents.applied = TRUE; + } + if (cfg_idents.work.auto_renew != cfg_idents.saved.auto_renew) { + khc_write_int32(csp_cw, L"DefaultAllowAutoRenew", + !!cfg_idents.work.auto_renew); + cfg_idents.work.auto_renew = cfg_idents.saved.auto_renew; + cfg_idents.applied = TRUE; + } + if (cfg_idents.work.sticky != cfg_idents.saved.sticky) { + khc_write_int32(csp_cw, L"DefaultMonitor", + !!cfg_idents.work.sticky); + cfg_idents.work.sticky = cfg_idents.saved.sticky; + cfg_idents.applied = TRUE; + } + khc_close_space(csp_cw); + } + + for (i=0; i < (int)cfg_idents.n_idents; i++) { + write_params_ident(&cfg_idents.idents[i]); + } + + if (cfg_idents.hwnd) + PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_UPDATE_STATE), 0); +} + +static void +init_idents_data(void) { + khm_int32 rv; + wchar_t * t; + wchar_t * widnames = NULL; + khm_size cb; + int n_tries = 0; + int i; + khm_handle csp_cw; + + if (cfg_idents.valid) + return; + +#ifdef DEBUG + assert(cfg_idents.idents == NULL); + assert(cfg_idents.n_idents == 0); + assert(cfg_idents.nc_idents == 0); +#endif + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", 0, &csp_cw))) { + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultMonitor", &t))) + cfg_idents.saved.monitor = !!t; + else + cfg_idents.saved.monitor = TRUE; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultAllowAutoRenew", &t))) + cfg_idents.saved.auto_renew = !!t; + else + cfg_idents.saved.auto_renew = TRUE; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"DefaultSticky", &t))) + cfg_idents.saved.sticky = !!t; + else + cfg_idents.saved.sticky = FALSE; + + } else { + + cfg_idents.saved.monitor = TRUE; + cfg_idents.saved.auto_renew = TRUE; + cfg_idents.saved.sticky = FALSE; + + } + + cfg_idents.work = cfg_idents.saved; + cfg_idents.applied = FALSE; + + do { + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, + KCDB_IDENT_FLAG_CONFIG, + NULL, + &cb, + &cfg_idents.n_idents); + + if (rv != KHM_ERROR_TOO_LONG || + cfg_idents.n_idents == 0 || + cb == 0) + break; + + if (widnames) + PFREE(widnames); + widnames = PMALLOC(cb); +#ifdef DEBUG + assert(widnames); +#endif + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, + KCDB_IDENT_FLAG_CONFIG, + widnames, + &cb, + &cfg_idents.n_idents); + n_tries++; + } while(KHM_FAILED(rv) && + n_tries < 5); + + if (KHM_FAILED(rv) || + cfg_idents.n_idents == 0) { + cfg_idents.n_idents = 0; + goto _cleanup; + } + + cfg_idents.idents = PMALLOC(sizeof(*cfg_idents.idents) * + cfg_idents.n_idents); +#ifdef DEBUG + assert(cfg_idents.idents); +#endif + ZeroMemory(cfg_idents.idents, + sizeof(*cfg_idents.idents) * cfg_idents.n_idents); + cfg_idents.nc_idents = cfg_idents.n_idents; + + i = 0; + for (t = widnames; t && *t; t = multi_string_next(t)) { + khm_handle ident; + + if (KHM_FAILED(kcdb_identity_create(t, 0, &ident))) { + cfg_idents.n_idents--; + continue; + } + + StringCbLength(t, KCDB_IDENT_MAXCB_NAME, &cb); + cb += sizeof(wchar_t); + + cfg_idents.idents[i].idname = PMALLOC(cb); +#ifdef DEBUG + assert(cfg_idents.idents[i].idname); +#endif + StringCbCopy(cfg_idents.idents[i].idname, cb, t); + + cfg_idents.idents[i].ident = ident; + cfg_idents.idents[i].removed = FALSE; + + kcdb_identity_get_flags(ident, &cfg_idents.idents[i].flags); + + read_params_ident(&cfg_idents.idents[i]); + + i++; + /* leave identity held */ + } + + _cleanup: + + cfg_idents.valid = TRUE; + + if (widnames) + PFREE(widnames); +} + +static void +free_idents_data(void) { + int i; + + if (!cfg_idents.valid) + return; + + for (i=0; i< (int) cfg_idents.n_idents; i++) { + if (cfg_idents.idents[i].ident) + kcdb_identity_release(cfg_idents.idents[i].ident); + if (cfg_idents.idents[i].idname) + PFREE(cfg_idents.idents[i].idname); + } + + if (cfg_idents.idents) + PFREE(cfg_idents.idents); + + cfg_idents.idents = NULL; + cfg_idents.n_idents = 0; + cfg_idents.nc_idents = 0; + cfg_idents.valid = FALSE; +} + +static void +hold_idents_data(void) { + if (!cfg_idents.valid) + init_idents_data(); +#ifdef DEBUG + assert(cfg_idents.valid); +#endif + cfg_idents.refcount++; +} + +static void +release_idents_data(void) { +#ifdef DEBUG + assert(cfg_idents.valid); +#endif + cfg_idents.refcount--; + + if (cfg_idents.refcount == 0) + free_idents_data(); +} + + +static void +refresh_data_idents(HWND hwnd) { + cfg_idents.work.monitor = + (IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR) == BST_CHECKED); + cfg_idents.work.auto_renew = + (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED); + cfg_idents.work.sticky = + (IsDlgButtonChecked(hwnd, IDC_CFG_STICKY) == BST_CHECKED); +} + +static void +refresh_view_idents_state(HWND hwnd) { + BOOL modified; + BOOL applied; + khm_int32 flags = 0; + + applied = cfg_idents.applied; + modified = (cfg_idents.work.monitor != cfg_idents.saved.monitor || + cfg_idents.work.auto_renew != cfg_idents.saved.auto_renew || + cfg_idents.work.sticky != cfg_idents.saved.sticky); + + if (modified) + flags |= KHUI_CNFLAG_MODIFIED; + if (applied) + flags |= KHUI_CNFLAG_APPLIED; + + khui_cfg_set_flags_inst(&cfg_idents.cfg, flags, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); +} + +INT_PTR CALLBACK +khm_cfg_ids_tab_proc(HWND hwnd, + UINT umsg, + WPARAM wParam, + LPARAM lParam) { + + switch(umsg) { + case WM_INITDIALOG: + { + HICON hicon; + + hold_idents_data(); + + cfg_idents.hwnd = hwnd; + cfg_idents.cfg = *((khui_config_init_data *) lParam); + + /* add the status icons */ + if (cfg_idents.hi_status) + goto _done_with_icons; + + cfg_idents.hi_status = + ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_COLOR8 | ILC_MASK, + 4,4); + + hicon = + LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_ID), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_id = ImageList_AddIcon(cfg_idents.hi_status, + hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_default = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_MODIFIED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_modified = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_applied = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DELETED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + cfg_idents.idx_deleted = ImageList_AddIcon(cfg_idents.hi_status, + hicon) + 1; + + DestroyIcon(hicon); + + _done_with_icons: + + CheckDlgButton(hwnd, IDC_CFG_MONITOR, + (cfg_idents.work.monitor)?BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CFG_RENEW, + (cfg_idents.work.auto_renew)?BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwnd, IDC_CFG_STICKY, + (cfg_idents.work.sticky)?BST_CHECKED:BST_UNCHECKED); + + } + return FALSE; + + case WM_COMMAND: + + if (HIWORD(wParam) == BN_CLICKED) { + UINT ctrl = LOWORD(wParam); + + switch(ctrl) { + case IDC_CFG_MONITOR: + case IDC_CFG_RENEW: + case IDC_CFG_STICKY: + refresh_data_idents(hwnd); + break; + } + + refresh_view_idents_state(hwnd); + } + + khm_set_dialog_result(hwnd, 0); + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + { + switch(HIWORD(wParam)) { + case WMCFG_APPLY: + write_params_idents(); + break; + + case WMCFG_UPDATE_STATE: + refresh_view_idents_state(hwnd); + break; + } + } + return TRUE; + + case WM_DESTROY: + cfg_idents.hwnd = NULL; + + if (cfg_idents.hi_status != NULL) { + ImageList_Destroy(cfg_idents.hi_status); + cfg_idents.hi_status = NULL; + } + release_idents_data(); + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + return FALSE; +} + +INT_PTR CALLBACK +khm_cfg_identities_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + HWND hw; + switch(uMsg) { + case WM_INITDIALOG: + set_window_node(hwnd, (khui_config_node) lParam); + add_subpanels(hwnd, (khui_config_node) lParam, + (khui_config_node) lParam); + hw = GetDlgItem(hwnd, IDC_CFG_TAB); + show_tab_panel(hwnd, + (khui_config_node) lParam, + hw, + TabCtrl_GetCurSel(hw), + TRUE); + return FALSE; + + case WM_DESTROY: + return 0; + + case KHUI_WM_CFG_NOTIFY: + return handle_cfg_notify(hwnd, wParam, lParam); + + case WM_NOTIFY: + return handle_notify(hwnd, wParam, lParam); + } + + return FALSE; +} + +static ident_data * +find_ident_by_node(khui_config_node node) { + khm_size cb; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + int i; + + cb = sizeof(idname); + khui_cfg_get_name(node, idname, &cb); + + for (i=0; i < (int)cfg_idents.n_idents; i++) { + if (!wcscmp(cfg_idents.idents[i].idname, idname)) + break; + } + + if (i < (int)cfg_idents.n_idents) + return &cfg_idents.idents[i]; + else + return NULL; +} + +static void +refresh_view_ident(HWND hwnd, khui_config_node node) { + ident_data * d; + + d = find_ident_by_node(node); +#ifdef DEBUG + assert(d); +#endif + + CheckDlgButton(hwnd, IDC_CFG_MONITOR, + (d->work.monitor? BST_CHECKED: BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_RENEW, + (d->work.auto_renew? BST_CHECKED: BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_CFG_STICKY, + (d->work.sticky? BST_CHECKED: BST_UNCHECKED)); +} + +static void +mark_remove_ident(HWND hwnd, khui_config_init_data * idata) { + ident_data * d; + + d = find_ident_by_node(idata->ctx_node); +#ifdef DEBUG + assert(d); +#endif + + if (d->removed) + return; + + d->removed = TRUE; + + khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + + EnableWindow(GetDlgItem(hwnd, IDC_CFG_REMOVE), FALSE); +} + +static void +refresh_data_ident(HWND hwnd, khui_config_init_data * idata) { + ident_data * d; + + d = find_ident_by_node(idata->ctx_node); +#ifdef DEBUG + assert(d); +#endif + + if (IsDlgButtonChecked(hwnd, IDC_CFG_MONITOR) == BST_CHECKED) + d->work.monitor = TRUE; + else + d->work.monitor = FALSE; + + if (IsDlgButtonChecked(hwnd, IDC_CFG_RENEW) == BST_CHECKED) + d->work.auto_renew = TRUE; + else + d->work.auto_renew = FALSE; + + if (IsDlgButtonChecked(hwnd, IDC_CFG_STICKY) == BST_CHECKED) + d->work.sticky = TRUE; + else + d->work.sticky = FALSE; + + if (d->work.monitor != d->saved.monitor || + d->work.auto_renew != d->saved.auto_renew || + d->work.sticky != d->saved.sticky) { + + khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + + } else { + khui_cfg_set_flags_inst(idata, 0, + KHUI_CNFLAG_MODIFIED); + } +} + +INT_PTR CALLBACK +khm_cfg_id_tab_proc(HWND hwnd, + UINT umsg, + WPARAM wParam, + LPARAM lParam) { + + khui_config_init_data * idata; + + switch(umsg) { + case WM_INITDIALOG: + { + ident_data * d; + + hold_idents_data(); + + idata = (khui_config_init_data *) lParam; + + khui_cfg_init_dialog_data(hwnd, idata, 0, NULL, NULL); + + refresh_view_ident(hwnd, idata->ctx_node); + + d = find_ident_by_node(idata->ctx_node); + if (d) + d->hwnd = hwnd; +#ifdef DEBUG + else + assert(FALSE); +#endif + } + return FALSE; + + case WM_COMMAND: + khui_cfg_get_dialog_data(hwnd, &idata, NULL); + + if (HIWORD(wParam) == BN_CLICKED) { + switch(LOWORD(wParam)) { + case IDC_CFG_MONITOR: + case IDC_CFG_RENEW: + case IDC_CFG_STICKY: + + refresh_data_ident(hwnd, idata); + if (cfg_idents.hwnd) + PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(1, WMCFG_UPDATE_STATE), 0); + break; + + case IDC_CFG_REMOVE: + mark_remove_ident(hwnd, idata); + if (cfg_idents.hwnd) + PostMessage(cfg_idents.hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(1, WMCFG_UPDATE_STATE), 0); + break; + } + } + + khm_set_dialog_result(hwnd, 0); + return TRUE; + + case WM_DESTROY: + { + ident_data * d; + + khui_cfg_get_dialog_data(hwnd, &idata, NULL); + + d = find_ident_by_node(idata->ctx_node); + if (d) + d->hwnd = NULL; + + release_idents_data(); + khui_cfg_free_dialog_data(hwnd); + khm_set_dialog_result(hwnd, 0); + } + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + { + ident_data * d; + + khui_cfg_get_dialog_data(hwnd, &idata, NULL); + + switch (HIWORD(wParam)) { + case WMCFG_APPLY: + d = find_ident_by_node(idata->ctx_node); + write_params_ident(d); + khui_cfg_set_flags_inst(idata, KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | + KHUI_CNFLAG_MODIFIED); + break; + + case WMCFG_UPDATE_STATE: + refresh_view_ident(hwnd, idata->ctx_node); + refresh_data_ident(hwnd, idata); + break; + } + } + return TRUE; + } + + return FALSE; +} + +INT_PTR CALLBACK +khm_cfg_identity_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + HWND hw; + + switch(uMsg) { + case WM_INITDIALOG: + { + khui_config_node refnode = NULL; + + set_window_node(hwnd, (khui_config_node) lParam); + + khui_cfg_open(NULL, L"KhmIdentities", &refnode); +#ifdef DEBUG + assert(refnode != NULL); +#endif + add_subpanels(hwnd, + (khui_config_node) lParam, + refnode); + + hw = GetDlgItem(hwnd, IDC_CFG_TAB); + + show_tab_panel(hwnd, + (khui_config_node) lParam, + hw, + TabCtrl_GetCurSel(hw), + TRUE); + + khui_cfg_release(refnode); + } + return FALSE; + + case WM_DESTROY: + return 0; + + case KHUI_WM_CFG_NOTIFY: + return handle_cfg_notify(hwnd, wParam, lParam); + + case WM_NOTIFY: + return handle_notify(hwnd, wParam, lParam); + } + return FALSE; +} diff --git a/mechglue/src/windows/identity/ui/cfg_notif_wnd.c b/mechglue/src/windows/identity/ui/cfg_notif_wnd.c new file mode 100644 index 000000000..220865113 --- /dev/null +++ b/mechglue/src/windows/identity/ui/cfg_notif_wnd.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +typedef struct tag_notif_data { + khui_config_node node; + + BOOL modified; + + BOOL monitor; + BOOL renew; + BOOL warn1; + BOOL warn2; + + khui_tracker tc_renew; + khui_tracker tc_warn1; + khui_tracker tc_warn2; +} notif_data; + +static void +read_params(notif_data * d) { + khm_handle csp_cw; + khm_int32 rv; + khm_int32 t; + + rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, &csp_cw); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_read_int32(csp_cw, L"Monitor", &t); + assert(KHM_SUCCEEDED(rv)); + d->monitor = !!t; + + rv = khc_read_int32(csp_cw, L"AllowAutoRenew", &t); + assert(KHM_SUCCEEDED(rv)); + d->renew = !!t; + + rv = khc_read_int32(csp_cw, L"AllowWarn", &t); + assert(KHM_SUCCEEDED(rv)); + d->warn1 = !!t; + + rv = khc_read_int32(csp_cw, L"AllowCritical", &t); + assert(KHM_SUCCEEDED(rv)); + d->warn2 = !!t; + + rv = khc_read_int32(csp_cw, L"AutoRenewThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_renew.current = t; + + rv = khc_read_int32(csp_cw, L"WarnThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_warn1.current = t; + + rv = khc_read_int32(csp_cw, L"CriticalThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_warn2.current = t; + + rv = khc_read_int32(csp_cw, L"MaxThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_renew.max = t; + d->tc_warn1.max = t; + d->tc_warn2.max = t; + + rv = khc_read_int32(csp_cw, L"MinThreshold", &t); + assert(KHM_SUCCEEDED(rv)); + d->tc_renew.min = t; + d->tc_warn1.min = t; + d->tc_warn2.min = t; + + khc_close_space(csp_cw); + + d->modified = FALSE; +} + +static void +check_for_modification(notif_data * d) { + notif_data t; + + ZeroMemory(&t, sizeof(t)); + + read_params(&t); + + if ((!!d->monitor) != (!!t.monitor) || + (!!d->renew) != (!!t.renew) || + (!!d->warn1) != (!!t.warn1) || + (!!d->warn2) != (!!t.warn2) || + d->tc_renew.current != t.tc_renew.current || + d->tc_warn1.current != t.tc_warn1.current || + d->tc_warn2.current != t.tc_warn2.current) { + + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_MODIFIED, + KHUI_CNFLAG_MODIFIED); + + d->modified = TRUE; + + } else { + khui_cfg_set_flags(d->node, + 0, + KHUI_CNFLAG_MODIFIED); + + d->modified = FALSE; + } +} + +static void +write_params(notif_data * d) { + khm_handle csp_cw; + khm_int32 rv; + + if (!d->modified) + return; + + rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_WRITE, &csp_cw); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"Monitor", d->monitor); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"AllowAutoRenew", d->renew); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"AllowWarn", d->warn1); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"AllowCritical", d->warn2); + assert(KHM_SUCCEEDED(rv)); + + + rv = khc_write_int32(csp_cw, L"AutoRenewThreshold", + (khm_int32) d->tc_renew.current); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"WarnThreshold", + (khm_int32) d->tc_warn1.current); + assert(KHM_SUCCEEDED(rv)); + + rv = khc_write_int32(csp_cw, L"CriticalThreshold", + (khm_int32) d->tc_warn2.current); + assert(KHM_SUCCEEDED(rv)); + + khc_close_space(csp_cw); + + khui_cfg_set_flags(d->node, + KHUI_CNFLAG_APPLIED, + KHUI_CNFLAG_APPLIED | KHUI_CNFLAG_MODIFIED); + + khm_timer_refresh(hwnd_notifier); +} + +static void +refresh_view(HWND hwnd, notif_data * d) { + CheckDlgButton(hwnd, IDC_NOTIF_MONITOR, + (d->monitor?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_NOTIF_RENEW, + (d->renew?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_NOTIF_WARN1, + (d->warn1?BST_CHECKED:BST_UNCHECKED)); + CheckDlgButton(hwnd, IDC_NOTIF_WARN2, + (d->warn2?BST_CHECKED:BST_UNCHECKED)); + khui_tracker_refresh(&d->tc_renew); + khui_tracker_refresh(&d->tc_warn1); + khui_tracker_refresh(&d->tc_warn2); + if (!d->monitor) { + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR), FALSE); + } else { + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW), TRUE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1), TRUE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2), TRUE); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR), !!(d->renew)); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR), !!(d->warn1)); + EnableWindow(GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR), !!(d->warn2)); + } +} + +static void +refresh_data(HWND hwnd, notif_data * d) { + d->monitor = (IsDlgButtonChecked(hwnd, IDC_NOTIF_MONITOR) + == BST_CHECKED); + d->renew = (IsDlgButtonChecked(hwnd, IDC_NOTIF_RENEW) + == BST_CHECKED); + d->warn1 = (IsDlgButtonChecked(hwnd, IDC_NOTIF_WARN1) + == BST_CHECKED); + d->warn2 = (IsDlgButtonChecked(hwnd, IDC_NOTIF_WARN2) + == BST_CHECKED); + + check_for_modification(d); +} + +INT_PTR CALLBACK +khm_cfg_notifications_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + notif_data * d; + + switch(uMsg) { + case WM_INITDIALOG: { + HWND hw; + + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d != NULL); +#endif + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + ZeroMemory(d, sizeof(*d)); + + d->node = (khui_config_node) lParam; + + khui_tracker_initialize(&d->tc_renew); + khui_tracker_initialize(&d->tc_warn1); + khui_tracker_initialize(&d->tc_warn2); + + read_params(d); + + hw = GetDlgItem(hwnd, IDC_NOTIF_RENEW_THR); + khui_tracker_install(hw, &d->tc_renew); + + hw = GetDlgItem(hwnd, IDC_NOTIF_WARN1_THR); + khui_tracker_install(hw, &d->tc_warn1); + + hw = GetDlgItem(hwnd, IDC_NOTIF_WARN2_THR); + khui_tracker_install(hw, &d->tc_warn2); + + refresh_view(hwnd, d); + + /* normally we should return TRUE, but in this case we return + FALSE since we don't want to inadvertently steal the focus + from the treeview. */ + return FALSE; + } + + case WM_COMMAND: { + d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == BN_CLICKED) { + refresh_data(hwnd, d); + refresh_view(hwnd, d); + + check_for_modification(d); + } else if (HIWORD(wParam) == EN_CHANGE) { + SetTimer(hwnd, 1, 500, NULL); + } + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + case WM_TIMER: { + d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + KillTimer(hwnd, 1); + check_for_modification(d); + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + case WM_DESTROY: { + d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + khui_tracker_kill_controls(&d->tc_renew); + khui_tracker_kill_controls(&d->tc_warn1); + khui_tracker_kill_controls(&d->tc_warn2); + + PFREE(d); + + SetWindowLongPtr(hwnd, DWLP_USER, 0); + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + case KHUI_WM_CFG_NOTIFY: { + d = (notif_data *) (DWORD_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + + if (HIWORD(wParam) == WMCFG_APPLY) { + write_params(d); + } + + khm_set_dialog_result(hwnd, 0); + + return TRUE; + } + + } + + return FALSE; +} diff --git a/mechglue/src/windows/identity/ui/cfg_plugins_wnd.c b/mechglue/src/windows/identity/ui/cfg_plugins_wnd.c new file mode 100644 index 000000000..6dad3698f --- /dev/null +++ b/mechglue/src/windows/identity/ui/cfg_plugins_wnd.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +#define MAX_PLUGINS 256 + +typedef struct tag_plugin_data { + kmm_plugin_info plugin; + kmm_module_info module; +} plugin_data; + +typedef struct tag_plugin_dlg_data { + plugin_data * info[MAX_PLUGINS]; + khm_size n_info; +} plugin_dlg_data; + +INT_PTR CALLBACK +khm_cfg_plugins_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + plugin_dlg_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + { + kmm_plugin p; + kmm_plugin pn; + kmm_module m; + khm_size i; + LVCOLUMN lvc; + RECT r; + HWND hw; + wchar_t buf[256]; + + + d = PMALLOC(sizeof(*d)); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, sizeof(*d)); +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + p = NULL; + i = 0; + do { + if (KHM_FAILED(kmm_get_next_plugin(p, &pn))) + break; + + if (p) + kmm_release_plugin(p); + p = pn; + +#ifdef DEBUG + assert(d->info[i] == NULL); +#endif + d->info[i] = PMALLOC(sizeof(*(d->info[i]))); +#ifdef DEBUG + assert(d->info[i]); +#endif + + if (KHM_FAILED(kmm_get_plugin_info_i(p, &d->info[i]->plugin))) { + PFREE(d->info[i]); + d->info[i] = NULL; + break; + } + + ZeroMemory(&d->info[i]->module, + sizeof(d->info[i]->module)); + + if (KHM_SUCCEEDED(kmm_load_module(d->info[i]->plugin.reg.module, + KMM_LM_FLAG_NOLOAD, + &m))) { + kmm_get_module_info_i(m, &d->info[i]->module); + kmm_release_module(m); + } + + i ++; + + if (i == MAX_PLUGINS) + break; + } while(p); + + if (p) + kmm_release_plugin(p); + + d->n_info = i; + + /* now populate the list view */ + hw = GetDlgItem(hwnd, IDC_CFG_PLUGINS); +#ifdef DEBUG + assert(hw); +#endif + ZeroMemory(&lvc, sizeof(lvc)); + + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + GetWindowRect(hw, &r); + lvc.cx = ((r.right - r.left) * 95) / 100; + lvc.pszText = buf; + + LoadString(khm_hInstance, IDS_CFG_PI_COL_PLUGINS, + buf, ARRAYLENGTH(buf)); + + ListView_InsertColumn(hw, 0, &lvc); + + for(i=0; i<d->n_info; i++) { + LVITEM lvi; + + ZeroMemory(&lvi, sizeof(lvi)); + + lvi.mask = LVIF_PARAM | LVIF_TEXT; + lvi.lParam = (LPARAM) d->info[i]; + lvi.pszText = d->info[i]->plugin.reg.name; + + ListView_InsertItem(hw, &lvi); + } + } + return FALSE; + + case WM_NOTIFY: + { + LPNMHDR lpnm; + HWND hw; + + d = (plugin_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (wParam == IDC_CFG_PLUGINS && + (lpnm = (LPNMHDR) lParam) && + lpnm->code == LVN_ITEMCHANGED) { + + LVITEM lvi; + + hw = GetDlgItem(hwnd, IDC_CFG_PLUGINS); +#ifdef DEBUG + assert(hw); +#endif + if (ListView_GetSelectedCount(hw) != 1) { + SetDlgItemText(hwnd, IDC_CFG_DESC, L""); + SetDlgItemText(hwnd, IDC_CFG_STATE, L""); + SetDlgItemText(hwnd, IDC_CFG_MODULE, L""); + SetDlgItemText(hwnd, IDC_CFG_VENDOR, L""); + EnableWindow(GetDlgItem(hwnd, IDC_CFG_ENABLE), FALSE); + EnableWindow(GetDlgItem(hwnd, IDC_CFG_DISABLE), FALSE); + SendDlgItemMessage(hwnd, IDC_CFG_DEPS, + LB_RESETCONTENT, 0, 0); + } else { + int idx; + plugin_data * info; + wchar_t buf[256]; + UINT resid; + wchar_t * t; + + idx = ListView_GetNextItem(hw, -1, LVNI_SELECTED); +#ifdef DEBUG + assert(idx != -1); +#endif + ZeroMemory(&lvi, sizeof(lvi)); + lvi.iItem = idx; + lvi.iSubItem = 0; + lvi.mask = LVIF_PARAM; + + ListView_GetItem(hw, &lvi); +#ifdef DEBUG + assert(lvi.lParam != 0); +#endif + info = (plugin_data *) lvi.lParam; + + if (info->plugin.reg.description) + SetDlgItemText(hwnd, IDC_CFG_DESC, info->plugin.reg.description); + else + SetDlgItemText(hwnd, IDC_CFG_DESC, L""); + + switch(info->plugin.state) { + case KMM_PLUGIN_STATE_FAIL_UNKNOWN: + resid = IDS_PISTATE_FAILUNK; + break; + + case KMM_PLUGIN_STATE_FAIL_MAX_FAILURE: + resid = IDS_PISTATE_FAILMAX; + break; + + case KMM_PLUGIN_STATE_FAIL_NOT_REGISTERED: + resid = IDS_PISTATE_FAILREG; + break; + + case KMM_PLUGIN_STATE_FAIL_DISABLED: + resid = IDS_PISTATE_FAILDIS; + break; + + case KMM_PLUGIN_STATE_FAIL_LOAD: + resid = IDS_PISTATE_FAILLOD; + break; + + case KMM_PLUGIN_STATE_NONE: + case KMM_PLUGIN_STATE_PLACEHOLDER: + resid = IDS_PISTATE_PLACEHOLD; + break; + + case KMM_PLUGIN_STATE_REG: + case KMM_PLUGIN_STATE_PREINIT: + resid = IDS_PISTATE_REG; + break; + + case KMM_PLUGIN_STATE_HOLD: + resid = IDS_PISTATE_HOLD; + break; + + case KMM_PLUGIN_STATE_INIT: + resid = IDS_PISTATE_INIT; + break; + + case KMM_PLUGIN_STATE_RUNNING: + resid = IDS_PISTATE_RUN; + break; + + case KMM_PLUGIN_STATE_EXITED: + resid = IDS_PISTATE_EXIT; + break; + + default: +#ifdef DEBUG + assert(FALSE); +#endif + resid = IDS_PISTATE_FAILUNK; + } + + LoadString(khm_hInstance, resid, + buf, ARRAYLENGTH(buf)); + + SetDlgItemText(hwnd, IDC_CFG_STATE, buf); + + SendDlgItemMessage(hwnd, IDC_CFG_DEPS, + LB_RESETCONTENT, 0, 0); + + for (t = info->plugin.reg.dependencies; t && *t; + t = multi_string_next(t)) { + SendDlgItemMessage(hwnd, IDC_CFG_DEPS, + LB_INSERTSTRING, + -1, + (LPARAM) t); + } + + if (info->plugin.reg.module) + SetDlgItemText(hwnd, IDC_CFG_MODULE, + info->plugin.reg.module); + else + SetDlgItemText(hwnd, IDC_CFG_MODULE, + L""); + + if (info->module.reg.vendor) + SetDlgItemText(hwnd, IDC_CFG_VENDOR, + info->module.reg.vendor); + else + SetDlgItemText(hwnd, IDC_CFG_VENDOR, + L""); + } + } + } + return TRUE; + + case WM_DESTROY: + { + khm_size i; + + d = (plugin_dlg_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + for (i=0; i<d->n_info; i++) { +#ifdef DEBUG + assert(d->info[i]); +#endif + kmm_release_plugin_info_i(&d->info[i]->plugin); + kmm_release_module_info_i(&d->info[i]->module); + PFREE(d->info[i]); + } + + PFREE(d); + + khm_set_dialog_result(hwnd, 0); + } + return TRUE; + } + return FALSE; +} diff --git a/mechglue/src/windows/identity/ui/configwnd.c b/mechglue/src/windows/identity/ui/configwnd.c new file mode 100644 index 000000000..7441b54f8 --- /dev/null +++ b/mechglue/src/windows/identity/ui/configwnd.c @@ -0,0 +1,861 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +static HWND cfgui_hwnd = NULL; + +typedef struct tag_cfgui_wnd_data { + khui_config_node current; + HWND hw_current; + HWND hw_generic_pane; + HBRUSH hbr_white; + HFONT hf_title; + khui_bitmap kbmp_logo; + HIMAGELIST hi_status; + BOOL modified; + int idx_default; + int idx_modified; + int idx_applied; +} cfgui_wnd_data; + +static cfgui_wnd_data * +cfgui_get_wnd_data(HWND hwnd) { + return (cfgui_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); +} + +static void +cfgui_set_wnd_data(HWND hwnd, cfgui_wnd_data * d) { +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) +} + +static void +cfgui_add_node(cfgui_wnd_data * d, + HWND hwtv, + khui_config_node node, + khui_config_node parent, + BOOL sorted) { + + khui_config_node_reg reg; + khui_config_node c; + wchar_t wbuf[256]; + const wchar_t * short_desc; + TVINSERTSTRUCT s; + HTREEITEM hItem; + + if (node) { + khui_cfg_get_reg(node, ®); + short_desc = reg.short_desc; + } else { + short_desc = wbuf; + LoadString(khm_hInstance, IDS_CFG_ROOT_NAME, + wbuf, ARRAYLENGTH(wbuf)); + reg.flags = 0; + } + + ZeroMemory(&s, sizeof(s)); + + s.hParent = (node)? + (HTREEITEM) khui_cfg_get_param(parent): + TVI_ROOT; + + s.hInsertAfter = (sorted)? TVI_SORT: TVI_FIRST; + + s.itemex.mask = + TVIF_CHILDREN | + TVIF_PARAM | + TVIF_TEXT | + TVIF_STATE; + + { + khui_config_node n; + + if (KHM_SUCCEEDED(khui_cfg_get_first_child(node, + &n))) { + s.itemex.cChildren = 1; + s.itemex.state = TVIS_EXPANDED; + s.itemex.stateMask = TVIS_EXPANDED; + khui_cfg_release(n); + } else { + s.itemex.cChildren = 0; + s.itemex.state = 0; + s.itemex.stateMask = TVIS_EXPANDED; + } + + s.itemex.state |= INDEXTOSTATEIMAGEMASK(d->idx_default); + s.itemex.stateMask |= TVIS_STATEIMAGEMASK; + } + + s.itemex.lParam = (LPARAM) node; + khui_cfg_hold(node); + + s.itemex.pszText = (LPWSTR) short_desc; + + hItem = TreeView_InsertItem(hwtv, &s); + + khui_cfg_set_param(node, (LPARAM) hItem); + + if (KHM_SUCCEEDED(khui_cfg_get_first_child(node, + &c))) { + do { + cfgui_add_node(d, hwtv, c, node, + !!(reg.flags & KHUI_CNFLAG_SORT_CHILDREN)); + } while (KHM_SUCCEEDED(khui_cfg_get_next_release(&c))); + } +} + +static void +cfgui_initialize_dialog(HWND hwnd) { + cfgui_wnd_data * d; + HWND hwtv; + HWND hwtitle; + HFONT hf; + HDC hdc; + HICON hicon; + + d = cfgui_get_wnd_data(hwnd); + + /* create and fill the image list for the treeview */ + + d->hi_status = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + ILC_COLOR8 | ILC_MASK, + 4,4); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_DEFAULT), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + /* note that we can't use index 0 because that is used to indicate + that there is no state image for the node */ + do { + d->idx_default = ImageList_AddIcon(d->hi_status, hicon); + } while(d->idx_default == 0); + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_MODIFIED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + d->idx_modified = ImageList_AddIcon(d->hi_status, hicon); + + DestroyIcon(hicon); + + hicon = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_CFG_APPLIED), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); + + d->idx_applied = ImageList_AddIcon(d->hi_status, hicon); + + DestroyIcon(hicon); + + /* now for the treeview */ + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + + TreeView_SetImageList(hwtv, d->hi_status, TVSIL_STATE); + + cfgui_add_node(d, hwtv, NULL, NULL, FALSE); + + hdc = GetDC(hwnd); + hf = CreateFont(-MulDiv(12, + GetDeviceCaps(hdc, LOGPIXELSY), + 72), + 0, /* nWidth */ + 0, /* nEscapement */ + 0, /* nOrientation */ + FW_BOLD, /* fnWeight */ + TRUE, /* fdwItalic */ + FALSE, /* fdwUnderline */ + FALSE, /* fdwStrikeOut */ + DEFAULT_CHARSET, /* fdwCharSet */ + OUT_DEFAULT_PRECIS, /* fdwOutputPrecision */ + CLIP_DEFAULT_PRECIS, /* fdwClipPrecision */ + DEFAULT_QUALITY, /* fdwQuality */ + FF_SWISS | DEFAULT_PITCH, /* pitch&family */ + NULL); /* face */ + ReleaseDC(hwnd, hdc); + + d->hf_title = hf; + + hwtitle = GetDlgItem(hwnd, IDC_CFG_TITLE); + + SendMessage(hwtitle, + WM_SETFONT, + (WPARAM) hf, + (LPARAM) FALSE); +} + +static void +cfgui_free_node(HWND hwtv, HTREEITEM hItem) { + TVITEMEX iex; + HTREEITEM hChItem; + + ZeroMemory(&iex, sizeof(iex)); + + iex.mask = TVIF_PARAM; + iex.hItem = hItem; + + if (TreeView_GetItem(hwtv, &iex)) { + khui_config_node node; + + node = (khui_config_node) iex.lParam; + khui_cfg_release(node); + } + + hChItem = TreeView_GetChild(hwtv, hItem); + while(hChItem) { + cfgui_free_node(hwtv, hChItem); + + hChItem = TreeView_GetNextSibling(hwtv, hChItem); + } +} + +static void +cfgui_uninitialize_dialog(HWND hwnd) { + cfgui_wnd_data * d; + HWND hwtv; + + d = cfgui_get_wnd_data(hwnd); + + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + + cfgui_free_node(hwtv, TreeView_GetRoot(hwtv)); + + if (d->hf_title) + DeleteObject(d->hf_title); + + if (d->hi_status) + ImageList_Destroy(d->hi_status); +} + +static HWND +cfgui_create_config_node_window(HWND hwnd, khui_config_node node) { + khui_config_node_reg reg; + khm_int32 rv; + HWND hw_new; + + khui_config_node parent; + + if (KHM_SUCCEEDED(khui_cfg_get_parent(node, &parent))) { + HWND hwp; + + hwp = khui_cfg_get_hwnd(parent); + + if (hwp == NULL) + cfgui_create_config_node_window(hwnd, parent); + + khui_cfg_release(parent); + } + + rv = khui_cfg_get_reg(node, ®); +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + hw_new = CreateDialogParam(reg.h_module, + reg.dlg_template, + hwnd, + reg.dlg_proc, + (LPARAM) node); +#ifdef DEBUG + assert(hw_new); +#endif + khui_cfg_set_hwnd(node, hw_new); + + return hw_new; +} + +static void +cfgui_activate_node(HWND hwnd, khui_config_node node) { + + cfgui_wnd_data * d; + HTREEITEM hItem; + HWND hw_new; + HWND hwtv; + + d = cfgui_get_wnd_data(hwnd); + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + hItem = (HTREEITEM) khui_cfg_get_param(node); + +#ifdef DEBUG + assert(hItem); + assert(hwtv); +#endif + + if (node == NULL) { + hw_new = d->hw_generic_pane; + } else { + + hw_new = khui_cfg_get_hwnd(node); + + if (hw_new == NULL) { + hw_new = cfgui_create_config_node_window(hwnd, node); + } + } + + if (hw_new == d->hw_current) + return; /* nothing to do */ + + { + RECT r_title; + RECT r_pane; + HWND hw; + + if (d->hw_current) + ShowWindow(d->hw_current, SW_HIDE); + + hw = GetDlgItem(hwnd, IDC_CFG_TITLE); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r_title); + + hw = GetDlgItem(hwnd, IDC_CFG_PANE); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r_pane); + + OffsetRect(&r_pane, -r_title.left, -r_title.top); + + SetWindowPos(hw_new, + hwtv, + r_pane.left, r_pane.top, + r_pane.right - r_pane.left, + r_pane.bottom - r_pane.top, + SWP_NOOWNERZORDER | + SWP_SHOWWINDOW | + SWP_NOACTIVATE); + } + + if (node == NULL) { + wchar_t wbuf[256]; + + LoadString(khm_hInstance, IDS_CFG_ROOT_TITLE, + wbuf, ARRAYLENGTH(wbuf)); + + SetDlgItemText(hwnd, IDC_CFG_TITLE, wbuf); + } else { + khm_int32 rv; + khui_config_node_reg reg; + + rv = khui_cfg_get_reg(node, ®); +#ifdef DEBUG + assert(KHM_SUCCEEDED(rv)); +#endif + SetDlgItemText(hwnd, IDC_CFG_TITLE, reg.long_desc); + } + + d->hw_current = hw_new; + d->current = node; + + TreeView_SelectItem(hwtv, hItem); +} + +static BOOL +cfgui_check_mod_state(khui_config_node node) { + khm_int32 flags; + khui_config_node c = NULL; + BOOL rv = FALSE; + + flags = khui_cfg_get_flags(node); + + if (flags & KHUI_CNFLAG_MODIFIED) + return TRUE; + + if (KHM_FAILED(khui_cfg_get_first_child(node, &c))) + return FALSE; + + while(c) { + rv = (rv || cfgui_check_mod_state(c)); + khui_cfg_get_next_release(&c); + } + + return rv; +} + +static void +cfgui_apply_settings(khui_config_node node) { + HWND hwnd; + khui_config_node c; + + hwnd = khui_cfg_get_hwnd(node); + + if (hwnd) + SendMessage(hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_APPLY), + (LPARAM) node); + + if (KHM_FAILED(khui_cfg_get_first_child(node, &c))) + return; + + while (c) { + cfgui_apply_settings(c); + khui_cfg_get_next_release(&c); + } +} + +static void +cfgui_update_state(HWND hwnd, + khm_int32 flags, + khui_config_node node) { + cfgui_wnd_data * d; + HWND hwtv; + HTREEITEM hItem; + TVITEMEX itx; + int idx; + + d = cfgui_get_wnd_data(hwnd); + hwtv = GetDlgItem(hwnd, IDC_CFG_NODELIST); + hItem = (HTREEITEM) khui_cfg_get_param(node); + + ZeroMemory(&itx, sizeof(itx)); + + if (flags & KHUI_CNFLAG_MODIFIED) + idx = d->idx_modified; + else if (flags & KHUI_CNFLAG_APPLIED) + idx = d->idx_applied; + else + idx = d->idx_default; + + itx.hItem = hItem; + itx.mask = TVIF_STATE; + itx.state = INDEXTOSTATEIMAGEMASK(idx); + itx.stateMask = TVIS_STATEIMAGEMASK; + + TreeView_SetItem(hwtv, &itx); + + if(cfgui_check_mod_state(NULL)) { + EnableWindow(GetDlgItem(hwnd, IDC_CFG_SUMMARY), TRUE); + EnableWindow(GetDlgItem(hwnd, IDAPPLY), TRUE); + } else { + EnableWindow(GetDlgItem(hwnd, IDC_CFG_SUMMARY), FALSE); + EnableWindow(GetDlgItem(hwnd, IDAPPLY), FALSE); + } +} + + +/* dialog procedure for the generic dialog */ +static INT_PTR CALLBACK +cfgui_dlgproc_generic(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + cfgui_wnd_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + d = (cfgui_wnd_data *) lParam; + cfgui_set_wnd_data(hwnd, d); + return TRUE; + + case WM_CTLCOLORSTATIC: + d = cfgui_get_wnd_data(hwnd); + return (BOOL)(DWORD_PTR) d->hbr_white; + + case WM_ERASEBKGND: + { + HDC hdc = (HDC) wParam; + RECT r_client; + RECT r_logo; + RECT r_fill; + + d = cfgui_get_wnd_data(hwnd); + + GetClientRect(hwnd, &r_client); + SetRectEmpty(&r_logo); + + r_logo.right = d->kbmp_logo.cx; + r_logo.bottom = d->kbmp_logo.cy; + + OffsetRect(&r_logo, + r_client.right - r_logo.right, + r_client.bottom - r_logo.bottom); + + khui_draw_bitmap(hdc, + r_logo.left, + r_logo.top, + &d->kbmp_logo); + + r_fill.left = 0; + r_fill.top = 0; + r_fill.right = r_logo.left; + r_fill.bottom = r_client.bottom; + FillRect(hdc, &r_fill, d->hbr_white); + + r_fill.left = r_logo.left; + r_fill.right = r_client.right; + r_fill.bottom = r_logo.top; + FillRect(hdc, &r_fill, d->hbr_white); + + SetWindowLong(hwnd, DWL_MSGRESULT, (LONG) TRUE); + } + return TRUE; + } + + return FALSE; +} + +static INT_PTR CALLBACK +cfgui_dlgproc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + khui_config_node node; + cfgui_wnd_data * d; + + switch(uMsg) { + case WM_INITDIALOG: + node = (khui_config_node) lParam; + + khui_cfg_clear_params(); + + khui_cfg_set_configui_handle(hwnd); + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->hbr_white = CreateSolidBrush(RGB(255,255,255)); + + d->hw_generic_pane = + CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_CFG_GENERIC), + hwnd, + cfgui_dlgproc_generic, + (LPARAM) d); + + khui_bitmap_from_hbmp(&d->kbmp_logo, + LoadImage( + khm_hInstance, + MAKEINTRESOURCE(IDB_LOGO_OPAQUE), + IMAGE_BITMAP, + 0, + 0, + LR_DEFAULTCOLOR)); + + cfgui_set_wnd_data(hwnd, d); + + cfgui_initialize_dialog(hwnd); + + cfgui_activate_node(hwnd, node); + + khm_add_dialog(hwnd); + khm_enter_modal(hwnd); + + return TRUE; + + case WM_DESTROY: + cfgui_hwnd = NULL; + + khui_cfg_set_configui_handle(NULL); + + cfgui_uninitialize_dialog(hwnd); + + d = cfgui_get_wnd_data(hwnd); + khui_delete_bitmap(&d->kbmp_logo); + DeleteObject(d->hbr_white); + + khm_leave_modal(); + khm_del_dialog(hwnd); + + SetForegroundWindow(khm_hwnd_main); + + return FALSE; + + case WM_NOTIFY: + { + LPNMHDR lpnm; + LPNMTREEVIEW lptv; + + lpnm = (LPNMHDR) lParam; + + switch (lpnm->code) { + case TVN_SELCHANGED: + lptv = (LPNMTREEVIEW) lParam; + cfgui_activate_node(hwnd, + (khui_config_node) + lptv->itemNew.lParam); + return TRUE; + } + } + return TRUE; + + case WM_CTLCOLORSTATIC: + { + d = cfgui_get_wnd_data(hwnd); + return (BOOL)(DWORD_PTR) d->hbr_white; + } + /* implicit break */ + + case WM_COMMAND: + switch(wParam) { + case MAKEWPARAM(IDCANCEL, BN_CLICKED): + DestroyWindow(hwnd); + break; + + case MAKEWPARAM(IDAPPLY, BN_CLICKED): + cfgui_apply_settings(NULL); + break; + + case MAKEWPARAM(IDOK, BN_CLICKED): + cfgui_apply_settings(NULL); + DestroyWindow(hwnd); + break; + } + return TRUE; + + case KHUI_WM_CFG_NOTIFY: + switch(HIWORD(wParam)) { + case WMCFG_SHOW_NODE: + cfgui_activate_node(hwnd, (khui_config_node) lParam); + break; + + case WMCFG_UPDATE_STATE: + cfgui_update_state(hwnd, LOWORD(wParam), + (khui_config_node) lParam); + break; + } + return TRUE; + } + + return FALSE; +} + +static void +cfgui_create_window(khui_config_node node) { +#ifdef DEBUG + assert(cfgui_hwnd == NULL); +#endif + + khm_refresh_config(); + + cfgui_hwnd = CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_CFG_MAIN), + khm_hwnd_main, + cfgui_dlgproc, + (LPARAM) node); +#ifdef DEBUG + assert(cfgui_hwnd != NULL); +#endif + ShowWindow(cfgui_hwnd,SW_SHOW); +} + +static void +cfgui_destroy_window(void) { + if (cfgui_hwnd) + DestroyWindow(cfgui_hwnd); + /* cfgui_hwnd will be set to NULL in the dialog proc */ +} + +void +khm_show_config_pane(khui_config_node node) { + if (cfgui_hwnd != NULL) { + SendMessage(cfgui_hwnd, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM(0, WMCFG_SHOW_NODE), + (LPARAM) node); + } else { + cfgui_create_window(node); + } +} + +void khm_refresh_config(void) { + khm_size cb; + khm_size n_idents; + wchar_t * idents = NULL; + wchar_t * t; + khm_int32 rv; + int n_tries = 0; + khui_config_node cfg_ids = NULL; + + do { + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, + KCDB_IDENT_FLAG_CONFIG, + NULL, + &cb, + &n_idents); + + if (rv != KHM_ERROR_TOO_LONG || + n_idents == 0) + return; + + if (idents) + PFREE(idents); + idents = PMALLOC(cb); +#ifdef DEBUG + assert(idents); +#endif + + rv = kcdb_identity_enum(KCDB_IDENT_FLAG_CONFIG, + KCDB_IDENT_FLAG_CONFIG, + idents, + &cb, + &n_idents); + + n_tries++; + } while(KHM_FAILED(rv) && + n_tries < 5); + + if (KHM_FAILED(rv)) + goto _cleanup; + + if (KHM_FAILED(khui_cfg_open(NULL, + L"KhmIdentities", + &cfg_ids))) + goto _cleanup; + + for(t = idents; t && *t; t = multi_string_next(t)) { + khui_config_node cfg_id = NULL; + + rv = khui_cfg_open(cfg_ids, + t, + &cfg_id); + + if (KHM_FAILED(rv)) { + khui_config_node_reg reg; + wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; + wchar_t wfmt[KHUI_MAXCCH_SHORT_DESC]; + + ZeroMemory(®, sizeof(reg)); + + reg.name = t; + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = khm_hInstance; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDENTITY); + reg.dlg_proc = khm_cfg_identity_proc; + reg.flags = 0; + + LoadString(khm_hInstance, IDS_CFG_IDENTITY_SHORT, + wfmt, ARRAYLENGTH(wfmt)); + StringCbPrintf(wshort, sizeof(wshort), wfmt, t); + + LoadString(khm_hInstance, IDS_CFG_IDENTITY_LONG, + wfmt, ARRAYLENGTH(wfmt)); + StringCbPrintf(wlong, sizeof(wlong), wfmt, t); + + khui_cfg_register(cfg_ids, + ®); + } else { + khui_cfg_release(cfg_id); + } + } + + _cleanup: + if (cfg_ids) + khui_cfg_release(cfg_ids); + + if (idents) + PFREE(idents); +} + +void khm_init_config(void) { + wchar_t wshort[KHUI_MAXCCH_SHORT_DESC]; + wchar_t wlong[KHUI_MAXCCH_LONG_DESC]; + khui_config_node_reg reg; + khui_config_node node; + + reg.short_desc = wshort; + reg.long_desc = wlong; + reg.h_module = khm_hInstance; + reg.flags = 0; + + reg.name = L"KhmGeneral"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_GENERAL); + reg.dlg_proc = khm_cfg_general_proc; + LoadString(khm_hInstance, IDS_CFG_GENERAL_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_GENERAL_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); + + reg.name = L"KhmIdentities"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDENTITIES); + reg.dlg_proc = khm_cfg_identities_proc; + LoadString(khm_hInstance, IDS_CFG_IDENTITIES_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_IDENTITIES_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); + + node = NULL; + khui_cfg_open(NULL, L"KhmIdentities", &node); +#ifdef DEBUG + assert(node); +#endif + + reg.name = L"KhmIdentitiesTab"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_IDS_TAB); + reg.dlg_proc = khm_cfg_ids_tab_proc; + LoadString(khm_hInstance, IDS_CFG_IDS_TAB_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_IDS_TAB_LONG, + wlong, ARRAYLENGTH(wlong)); + reg.flags = KHUI_CNFLAG_SUBPANEL; + + khui_cfg_register(node, ®); + + reg.name = L"KhmIdentitiesTabPlural"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_ID_TAB); + reg.dlg_proc = khm_cfg_id_tab_proc; + LoadString(khm_hInstance, IDS_CFG_ID_TAB_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_ID_TAB_LONG, + wlong, ARRAYLENGTH(wlong)); + reg.flags = KHUI_CNFLAG_PLURAL | KHUI_CNFLAG_SUBPANEL; + + khui_cfg_register(node, ®); + + reg.flags = 0; + khui_cfg_release(node); + + reg.name = L"KhmNotifications"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_NOTIF); + reg.dlg_proc = khm_cfg_notifications_proc; + LoadString(khm_hInstance, IDS_CFG_NOTIF_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_NOTIF_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); + + reg.name = L"KhmPlugins"; + reg.dlg_template = MAKEINTRESOURCE(IDD_CFG_PLUGINS); + reg.dlg_proc = khm_cfg_plugins_proc; + LoadString(khm_hInstance, IDS_CFG_PLUGINS_SHORT, + wshort, ARRAYLENGTH(wshort)); + LoadString(khm_hInstance, IDS_CFG_PLUGINS_LONG, + wlong, ARRAYLENGTH(wlong)); + + khui_cfg_register(NULL, ®); +} + +void khm_exit_config(void) { +} diff --git a/mechglue/src/windows/identity/ui/configwnd.h b/mechglue/src/windows/identity/ui/configwnd.h new file mode 100644 index 000000000..62747fcad --- /dev/null +++ b/mechglue/src/windows/identity/ui/configwnd.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_CONFIGWND_H +#define __KHIMAIRA_CONFIGWND_H + +void +khm_show_config_pane(khui_config_node node); + +void khm_init_config(void); +void khm_exit_config(void); + +void khm_refresh_config(void); + +/* window procedures for other configuration windows */ +INT_PTR CALLBACK +khm_cfg_general_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_identities_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_identity_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_id_tab_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_ids_tab_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_notifications_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +INT_PTR CALLBACK +khm_cfg_plugins_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +#endif diff --git a/mechglue/src/windows/identity/ui/credfuncs.c b/mechglue/src/windows/identity/ui/credfuncs.c new file mode 100644 index 000000000..7e0756fb4 --- /dev/null +++ b/mechglue/src/windows/identity/ui/credfuncs.c @@ -0,0 +1,1029 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +static BOOL in_dialog = FALSE; +static CRITICAL_SECTION cs_dialog; +static HANDLE in_dialog_evt = NULL; +static LONG init_dialog = 0; +static khm_int32 dialog_result = 0; +static wchar_t dialog_identity[KCDB_IDENT_MAXCCH_NAME]; + +static void +dialog_sync_init(void) { + if (InterlockedIncrement(&init_dialog) == 1) { +#ifdef DEBUG + assert(in_dialog_evt == NULL); + assert(in_dialog == FALSE); +#endif + + InitializeCriticalSection(&cs_dialog); + + in_dialog_evt = CreateEvent(NULL, + TRUE, + TRUE, + L"DialogCompletionEvent"); + } else { + InterlockedDecrement(&init_dialog); + if (in_dialog_evt == NULL) { + Sleep(100); + } + } +} + +BOOL +khm_cred_begin_dialog(void) { + BOOL rv; + + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + + if (in_dialog) + rv = FALSE; + else { + rv = TRUE; + in_dialog = TRUE; + ResetEvent(in_dialog_evt); + } + + LeaveCriticalSection(&cs_dialog); + return rv; +} + +void +khm_cred_end_dialog(khui_new_creds * nc) { + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + if (in_dialog) { + in_dialog = FALSE; + SetEvent(in_dialog_evt); + } + dialog_result = nc->result; + if (nc->subtype == KMSG_CRED_NEW_CREDS && + nc->n_identities > 0 && + nc->identities[0]) { + khm_size cb; + + cb = sizeof(dialog_identity); + if (KHM_FAILED(kcdb_identity_get_name(nc->identities[0], + dialog_identity, + &cb))) + dialog_identity[0] = 0; + } else { + dialog_identity[0] = 0; + } + LeaveCriticalSection(&cs_dialog); +} + +BOOL +khm_cred_is_in_dialog(void) { + BOOL rv; + + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + rv = in_dialog; + LeaveCriticalSection(&cs_dialog); + + return rv; +} + +khm_int32 +khm_cred_wait_for_dialog(DWORD timeout, khm_int32 * result, + wchar_t * ident, khm_size cb_ident) { + khm_int32 rv; + + dialog_sync_init(); + + EnterCriticalSection(&cs_dialog); + if (!in_dialog) + rv = KHM_ERROR_NOT_FOUND; + else { + DWORD dw; + + do { + LeaveCriticalSection(&cs_dialog); + + dw = WaitForSingleObject(in_dialog_evt, timeout); + + EnterCriticalSection(&cs_dialog); + + if (!in_dialog) { + rv = KHM_ERROR_SUCCESS; + if (result) { + *result = dialog_result; + } + if (ident) { + StringCbCopy(ident, cb_ident, dialog_identity); + } + break; + } else if(dw == WAIT_TIMEOUT) { + rv = KHM_ERROR_TIMEOUT; + break; + } + } while(TRUE); + } + LeaveCriticalSection(&cs_dialog); + + return rv; +} + +/* completion handler for KMSG_CRED messages */ +void KHMAPI +kmsg_cred_completion(kmq_message *m) +{ + khui_new_creds * nc; + +#ifdef DEBUG + assert(m->type == KMSG_CRED); +#else + if(m->type != KMSG_CRED) + return; /* huh? */ +#endif + + switch(m->subtype) { + case KMSG_CRED_PASSWORD: + /* fallthrough */ + case KMSG_CRED_NEW_CREDS: + /* Cred types have attached themselves. Trigger the next + phase. */ + kmq_post_message(KMSG_CRED, KMSG_CRED_DIALOG_SETUP, 0, + m->vparam); + break; + + case KMSG_CRED_RENEW_CREDS: + nc = (khui_new_creds *) m->vparam; + + /* khm_cred_dispatch_process_message() deals with the case + where there are not credential types that wants to + participate in this operation. */ + khm_cred_dispatch_process_message(nc); + break; + + case KMSG_CRED_DIALOG_SETUP: + nc = (khui_new_creds *) m->vparam; + + khm_prep_newcredwnd(nc->hwnd); + + /* all the controls have been created. Now initialize them */ + if (nc->n_types > 0) { + kmq_post_subs_msg(nc->type_subs, + nc->n_types, + KMSG_CRED, + KMSG_CRED_DIALOG_PRESTART, + 0, + m->vparam); + } else { + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); + } + break; + + case KMSG_CRED_DIALOG_PRESTART: + /* all prestart stuff is done. Now to activate the dialog */ + nc = (khui_new_creds *) m->vparam; + khm_show_newcredwnd(nc->hwnd); + + kmq_post_subs_msg(nc->type_subs, + nc->n_types, + KMSG_CRED, + KMSG_CRED_DIALOG_START, + 0, + m->vparam); + /* at this point, the dialog window takes over. We let it run + the show until KMSG_CRED_DIALOG_END is posted by the dialog + procedure. */ + break; + + case KMSG_CRED_PROCESS: + /* a wave of these messages have completed. We should check + if there's more */ + nc = (khui_new_creds *) m->vparam; + + if(!khm_cred_dispatch_process_level(nc)) { + + if(kherr_is_error()) { + khui_alert * alert; + kherr_event * evt; + kherr_context * ctx; + wchar_t ws_tfmt[512]; + wchar_t w_idname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t ws_title[ARRAYLENGTH(ws_tfmt) + KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + + ctx = kherr_peek_context(); + evt = kherr_get_err_event(ctx); + kherr_evaluate_event(evt); + + khui_alert_create_empty(&alert); + + if (nc->subtype == KMSG_CRED_PASSWORD) + LoadString(khm_hInstance, IDS_NC_PWD_FAILED_TITLE, + ws_tfmt, ARRAYLENGTH(ws_tfmt)); + else if (nc->subtype == KMSG_CRED_RENEW_CREDS) + LoadString(khm_hInstance, IDS_NC_REN_FAILED_TITLE, + ws_tfmt, ARRAYLENGTH(ws_tfmt)); + else + LoadString(khm_hInstance, IDS_NC_FAILED_TITLE, + ws_tfmt, ARRAYLENGTH(ws_tfmt)); + + if (nc->n_identities > 0) { + cb = sizeof(w_idname); + if (KHM_FAILED(kcdb_identity_get_name(nc->identities[0], + w_idname, &cb))) + StringCbCopy(w_idname, sizeof(w_idname), L"(?)"); + } else { + StringCbCopy(w_idname, sizeof(w_idname), L"(?)"); + } + + StringCbPrintf(ws_title, sizeof(ws_title), ws_tfmt, w_idname); + + khui_alert_set_title(alert, ws_title); + khui_alert_set_severity(alert, evt->severity); + if(!evt->long_desc) + khui_alert_set_message(alert, evt->short_desc); + else + khui_alert_set_message(alert, evt->long_desc); + if(evt->suggestion) + khui_alert_set_suggestion(alert, evt->suggestion); + + khui_alert_show(alert); + khui_alert_release(alert); + + kherr_release_context(ctx); + + kherr_clear_error(); + } + + if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, + m->vparam); + } else { + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), + 0); + } + } + break; + + case KMSG_CRED_END: + /* all is done. */ + { + khui_new_creds * nc; + + nc = (khui_new_creds *) m->vparam; + + if (nc->subtype == KMSG_CRED_NEW_CREDS || + nc->subtype == KMSG_CRED_PASSWORD) { + + /* + if (nc->subtype == KMSG_CRED_NEW_CREDS) + khui_context_reset(); + */ + + khm_cred_end_dialog(nc); + } + + khui_cw_destroy_cred_blob(nc); + + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + + kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); + } + break; + + /* property sheet stuff */ + + case KMSG_CRED_PP_BEGIN: + /* all the pages should have been added by now. Just send out + the precreate message */ + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_PRECREATE, 0, + m->vparam); + break; + + case KMSG_CRED_PP_END: + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_DESTROY, 0, + m->vparam); + break; + + case KMSG_CRED_DESTROY_CREDS: +#ifdef DEBUG + assert(m->vparam != NULL); +#endif + khui_context_release((khui_action_context *) m->vparam); + PFREE(m->vparam); + + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + + kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); + break; + + case KMSG_CRED_IMPORT: + kmq_post_message(KMSG_ACT, KMSG_ACT_CONTINUE_CMDLINE, 0, 0); + break; + + case KMSG_CRED_REFRESH: + kcdb_identity_refresh_all(); + break; + } +} + +void khm_cred_import(void) +{ + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_IMPORT); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_IMPORT, 0, 0); + + _end_task(); +} + +void khm_cred_set_default(void) +{ + khui_action_context ctx; + khm_int32 rv; + + khui_context_get(&ctx); + + if (ctx.identity) { + rv = kcdb_identity_set_default(ctx.identity); + } + + khui_context_release(&ctx); +} + +void khm_cred_destroy_creds(void) +{ + khui_action_context * pctx; + + pctx = PMALLOC(sizeof(*pctx)); +#ifdef DEBUG + assert(pctx); +#endif + + khui_context_get(pctx); + + if(pctx->scope == KHUI_SCOPE_NONE) { + /* this really shouldn't be necessary once we start enabling + and disbling actions based on context */ + wchar_t title[256]; + wchar_t message[256]; + + LoadString(khm_hInstance, + IDS_ALERT_NOSEL_TITLE, + title, + ARRAYLENGTH(title)); + + LoadString(khm_hInstance, + IDS_ALERT_NOSEL, + message, + ARRAYLENGTH(message)); + + khui_alert_show_simple(title, + message, + KHERR_WARNING); + + khui_context_release(pctx); + PFREE(pctx); + } else { + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + kmq_post_message(KMSG_CRED, + KMSG_CRED_DESTROY_CREDS, + 0, + (void *) pctx); + + _end_task(); + } +} + +void khm_cred_renew_identity(khm_handle identity) +{ + khui_new_creds * c; + + khui_cw_create_cred_blob(&c); + + c->subtype = KMSG_CRED_RENEW_CREDS; + c->result = KHUI_NC_RESULT_GET_CREDS; + khui_context_create(&c->ctx, + KHUI_SCOPE_IDENT, + identity, + KCDB_CREDTYPE_INVALID, + NULL); + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); + + _end_task(); +} + +void khm_cred_renew_cred(khm_handle cred) +{ + khui_new_creds * c; + + khui_cw_create_cred_blob(&c); + + c->subtype = KMSG_CRED_RENEW_CREDS; + c->result = KHUI_NC_RESULT_GET_CREDS; + khui_context_create(&c->ctx, + KHUI_SCOPE_CRED, + NULL, + KCDB_CREDTYPE_INVALID, + cred); + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); + + _end_task(); +} + +void khm_cred_renew_creds(void) +{ + khui_new_creds * c; + + khui_cw_create_cred_blob(&c); + c->subtype = KMSG_CRED_RENEW_CREDS; + c->result = KHUI_NC_RESULT_GET_CREDS; + khui_context_get(&c->ctx); + + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_RENEW_CREDS); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_RENEW_CREDS, 0, (void *) c); + + _end_task(); +} + +void khm_cred_change_password(wchar_t * title) +{ + khui_new_creds * nc; + LPNETID_DLGINFO pdlginfo; + khm_size cb; + + if (!khm_cred_begin_dialog()) + return; + + khui_cw_create_cred_blob(&nc); + nc->subtype = KMSG_CRED_PASSWORD; + + khui_context_get(&nc->ctx); + + kcdb_identpro_get_ui_cb((void *) &nc->ident_cb); + + assert(nc->ident_cb); + + if (title) { + + if (SUCCEEDED(StringCbLength(title, KHUI_MAXCB_TITLE, &cb))) { + cb += sizeof(wchar_t); + + nc->window_title = PMALLOC(cb); +#ifdef DEBUG + assert(nc->window_title); +#endif + StringCbCopy(nc->window_title, cb, title); + } + } else if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && + (pdlginfo = nc->ctx.vparam) && + pdlginfo->size == NETID_DLGINFO_V1_SZ && + pdlginfo->in.title[0] && + SUCCEEDED(StringCchLength(pdlginfo->in.title, + NETID_TITLE_SZ, + &cb))) { + + cb = (cb + 1) * sizeof(wchar_t); + nc->window_title = PMALLOC(cb); +#ifdef DEBUG + assert(nc->window_title); +#endif + StringCbCopy(nc->window_title, cb, pdlginfo->in.title); + } + + khm_create_newcredwnd(khm_hwnd_main, nc); + + if (nc->hwnd != NULL) { + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_PASSWORD); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_PASSWORD, 0, + (void *) nc); + + _end_task(); + } else { + khui_cw_destroy_cred_blob(nc); + } +} + +void khm_cred_obtain_new_creds(wchar_t * title) +{ + khui_new_creds * nc; + LPNETID_DLGINFO pdlginfo; + khm_size cb; + + if (!khm_cred_begin_dialog()) + return; + + khui_cw_create_cred_blob(&nc); + nc->subtype = KMSG_CRED_NEW_CREDS; + + khui_context_get(&nc->ctx); + + kcdb_identpro_get_ui_cb((void *) &nc->ident_cb); + + if (nc->ident_cb == NULL) { + wchar_t title[256]; + wchar_t msg[512]; + wchar_t suggestion[512]; + khui_alert * a; + + LoadString(khm_hInstance, IDS_ERR_TITLE_NO_IDENTPRO, + title, ARRAYLENGTH(title)); + LoadString(khm_hInstance, IDS_ERR_MSG_NO_IDENTPRO, + msg, ARRAYLENGTH(msg)); + LoadString(khm_hInstance, IDS_ERR_SUGG_NO_IDENTPRO, + suggestion, ARRAYLENGTH(suggestion)); + + khui_alert_create_simple(title, + msg, + KHERR_ERROR, + &a); + khui_alert_set_suggestion(a, suggestion); + + khui_alert_show(a); + + khui_alert_release(a); + + khui_context_release(&nc->ctx); + nc->result = KHUI_NC_RESULT_CANCEL; + khm_cred_end_dialog(nc); + khui_cw_destroy_cred_blob(nc); + return; + } + + if (title) { + if (SUCCEEDED(StringCbLength(title, KHUI_MAXCB_TITLE, &cb))) { + cb += sizeof(wchar_t); + + nc->window_title = PMALLOC(cb); +#ifdef DEBUG + assert(nc->window_title); +#endif + StringCbCopy(nc->window_title, cb, title); + } + } else if (nc->ctx.cb_vparam == sizeof(NETID_DLGINFO) && + (pdlginfo = nc->ctx.vparam) && + pdlginfo->size == NETID_DLGINFO_V1_SZ && + pdlginfo->in.title[0] && + SUCCEEDED(StringCchLength(pdlginfo->in.title, + NETID_TITLE_SZ, + &cb))) { + + cb = (cb + 1) * sizeof(wchar_t); + nc->window_title = PMALLOC(cb); +#ifdef DEBUG + assert(nc->window_title); +#endif + StringCbCopy(nc->window_title, cb, pdlginfo->in.title); + } + + khm_create_newcredwnd(khm_hwnd_main, nc); + + if (nc->hwnd != NULL) { + _begin_task(KHERR_CF_TRANSITIVE); + _report_sr0(KHERR_NONE, IDS_CTX_NEW_CREDS); + _describe(); + + kmq_post_message(KMSG_CRED, KMSG_CRED_NEW_CREDS, 0, + (void *) nc); + + _end_task(); + } else { + khui_context_release(&nc->ctx); + nc->result = KHUI_NC_RESULT_CANCEL; + khm_cred_end_dialog(nc); + khui_cw_destroy_cred_blob(nc); + } +} + +/* this is called by khm_cred_dispatch_process_message and the + kmsg_cred_completion to initiate and continue checked broadcasts of + KMSG_CRED_DIALOG_PROCESS messages. + + Returns TRUE if more KMSG_CRED_DIALOG_PROCESS messages were + posted. */ +BOOL khm_cred_dispatch_process_level(khui_new_creds *nc) +{ + khm_size i,j; + khm_handle subs[KHUI_MAX_NCTYPES]; + int n_subs = 0; + BOOL cont = FALSE; + khui_new_creds_by_type *t, *d; + + /* at each level, we dispatch a wave of notifications to plug-ins + who's dependencies are all satisfied */ + EnterCriticalSection(&nc->cs); + + /* if any types have already completed, we mark them are processed + and skip them */ + for (i=0; i < nc->n_types; i++) { + t = nc->types[i]; + if(t->flags & KHUI_NC_RESPONSE_COMPLETED) + t->flags |= KHUI_NCT_FLAG_PROCESSED; + } + + for(i=0; i<nc->n_types; i++) { + t = nc->types[i]; + + if((t->flags & KHUI_NCT_FLAG_PROCESSED) || + (t->flags & KHUI_NC_RESPONSE_COMPLETED)) + continue; + + for(j=0; j<t->n_type_deps; j++) { + if(KHM_FAILED(khui_cw_find_type(nc, t->type_deps[j], &d))) + break; + + if(!(d->flags & KHUI_NC_RESPONSE_COMPLETED)) + break; + } + + if(j<t->n_type_deps) /* there are unmet dependencies */ + continue; + + /* all dependencies for this type have been met. */ + subs[n_subs++] = kcdb_credtype_get_sub(t->type); + t->flags |= KHUI_NCT_FLAG_PROCESSED; + cont = TRUE; + } + + LeaveCriticalSection(&nc->cs); + + /* the reason why we are posting messages in batches is because + when the message has completed we know that all the types that + have the KHUI_NCT_FLAG_PROCESSED set have completed processing. + Otherwise we have to individually track each message and update + the type */ + if(n_subs > 0) + kmq_post_subs_msg(subs, n_subs, KMSG_CRED, KMSG_CRED_PROCESS, 0, + (void *) nc); + + return cont; +} + +void +khm_cred_dispatch_process_message(khui_new_creds *nc) +{ + khm_size i; + BOOL pending; + wchar_t wsinsert[512]; + khm_size cbsize; + + /* see if there's anything to do. We can check this without + obtaining a lock */ + if(nc->n_types == 0 || + (nc->subtype == KMSG_CRED_NEW_CREDS && + nc->n_identities == 0) || + (nc->subtype == KMSG_CRED_PASSWORD && + nc->n_identities == 0)) + goto _terminate_job; + + /* check dependencies and stuff first */ + EnterCriticalSection(&nc->cs); + for(i=0; i<nc->n_types; i++) { + nc->types[i]->flags &= ~ KHUI_NCT_FLAG_PROCESSED; + } + LeaveCriticalSection(&nc->cs); + + /* Consindering all that can go wrong here and the desire to + handle errors here separately from others, we create a new task + for the purpose of tracking the credentials acquisition + process. */ + _begin_task(KHERR_CF_TRANSITIVE); + + /* Describe the context */ + if(nc->subtype == KMSG_CRED_NEW_CREDS) { + cbsize = sizeof(wsinsert); + kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize); + + _report_sr1(KHERR_NONE, IDS_CTX_PROC_NEW_CREDS, + _cstr(wsinsert)); + _resolve(); + } else if (nc->subtype == KMSG_CRED_RENEW_CREDS) { + cbsize = sizeof(wsinsert); + + if (nc->ctx.scope == KHUI_SCOPE_IDENT) + kcdb_identity_get_name(nc->ctx.identity, wsinsert, &cbsize); + else if (nc->ctx.scope == KHUI_SCOPE_CREDTYPE) { + if (nc->ctx.identity != NULL) + kcdb_identity_get_name(nc->ctx.identity, wsinsert, + &cbsize); + else + kcdb_credtype_get_name(nc->ctx.cred_type, wsinsert, + &cbsize); + } else if (nc->ctx.scope == KHUI_SCOPE_CRED) { + kcdb_cred_get_name(nc->ctx.cred, wsinsert, &cbsize); + } else { + StringCbCopy(wsinsert, sizeof(wsinsert), L"(?)"); + } + + _report_sr1(KHERR_NONE, IDS_CTX_PROC_RENEW_CREDS, + _cstr(wsinsert)); + _resolve(); + } else if (nc->subtype == KMSG_CRED_PASSWORD) { + cbsize = sizeof(wsinsert); + kcdb_identity_get_name(nc->identities[0], wsinsert, &cbsize); + + _report_sr1(KHERR_NONE, IDS_CTX_PROC_PASSWORD, + _cstr(wsinsert)); + _resolve(); + } else { + assert(FALSE); + } + + _describe(); + + pending = khm_cred_dispatch_process_level(nc); + + _end_task(); + + if(!pending) + goto _terminate_job; + + return; + + _terminate_job: + if (nc->subtype == KMSG_CRED_RENEW_CREDS) + kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc); + else + PostMessage(nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_PROCESS_COMPLETE), 0); +} + +void +khm_cred_process_commandline(void) { + khm_handle defident = NULL; + + if (!khm_startup.processing) + return; + + if (khm_startup.init || + khm_startup.renew || + khm_startup.destroy || + khm_startup.autoinit) { + kcdb_identity_get_default(&defident); + } + + do { + if (khm_startup.init) { + if (defident) + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + else + khui_context_reset(); + + khm_cred_obtain_new_creds(NULL); + khm_startup.init = FALSE; + break; + } + + if (khm_startup.import) { + khm_cred_import(); + khm_startup.import = FALSE; + break; + } + + if (khm_startup.renew) { + if (defident) + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + else + khui_context_reset(); + + khm_cred_renew_creds(); + khm_startup.renew = FALSE; + break; + } + + if (khm_startup.destroy) { + if (defident) { + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + + khm_cred_destroy_creds(); + } + + khm_startup.destroy = FALSE; + break; + } + + if (khm_startup.autoinit) { + khm_size count; + + kcdb_credset_get_size(NULL, &count); + + if (count == 0) { + if (defident) + khui_context_set(KHUI_SCOPE_IDENT, + defident, + KCDB_CREDTYPE_INVALID, + NULL, NULL, 0, + NULL); + else + khui_context_reset(); + + khm_cred_obtain_new_creds(NULL); + } + khm_startup.autoinit = FALSE; + break; + } + + if (khm_startup.exit) { + PostMessage(khm_hwnd_main, + WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_EXIT, 0), 0); + khm_startup.exit = FALSE; + break; + } + + khm_startup.processing = FALSE; + } while(FALSE); + + if (defident) + kcdb_identity_release(defident); +} + +void +khm_cred_begin_commandline(void) { + khm_handle csp_cw; + + if (khm_startup.seen) + return; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", 0, &csp_cw))) { + khm_int32 t = 0; + + khc_read_int32(csp_cw, L"Autoinit", &t); + if (t) + khm_startup.autoinit = TRUE; + + t = 0; + khc_read_int32(csp_cw, L"AutoImport", &t); + if (t) + khm_startup.import = TRUE; + + khc_close_space(csp_cw); + + } + + khm_startup.seen = TRUE; + khm_startup.processing = TRUE; + + khm_cred_process_commandline(); +} + +void +khm_cred_refresh(void) { + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, NULL); +} + +void +khm_cred_addr_change(void) { + khm_handle csp_cw = NULL; + khm_int32 check_net = 0; + + wchar_t * ids = NULL; + wchar_t * t; + khm_size cb; + khm_size n_idents; + + FILETIME ft_now; + FILETIME ft_exp; + FILETIME ft_issue; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + 0, &csp_cw))) { + khc_read_int32(csp_cw, L"AutoDetectNet", &check_net); + + khc_close_space(csp_cw); + } + + if (!check_net) + return; + + while(TRUE) { + if (ids) + PFREE(ids); + ids = NULL; + + if (kcdb_identity_enum(KCDB_IDENT_FLAG_VALID | + KCDB_IDENT_FLAG_RENEWABLE, + KCDB_IDENT_FLAG_VALID | + KCDB_IDENT_FLAG_RENEWABLE, + NULL, + &cb, + &n_idents) != KHM_ERROR_TOO_LONG) + break; + + ids = PMALLOC(cb); + + if (KHM_SUCCEEDED + (kcdb_identity_enum(KCDB_IDENT_FLAG_VALID | + KCDB_IDENT_FLAG_RENEWABLE, + KCDB_IDENT_FLAG_VALID | + KCDB_IDENT_FLAG_RENEWABLE, + ids, + &cb, + &n_idents))) + break; + } + + if (!ids) + return; + + GetSystemTimeAsFileTime(&ft_now); + + for (t=ids; t && *t; t = multi_string_next(t)) { + khm_handle ident; + + + if (KHM_FAILED + (kcdb_identity_create(t, 0, &ident))) + continue; + + cb = sizeof(ft_issue); + + if (KHM_SUCCEEDED + (kcdb_identity_get_attr(ident, KCDB_ATTR_ISSUE, NULL, + &ft_issue, &cb)) && + + (cb = sizeof(ft_exp)) && + KHM_SUCCEEDED + (kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, NULL, + &ft_exp, &cb)) && + + CompareFileTime(&ft_now, &ft_exp) < 0) { + + khm_int64 i_issue; + khm_int64 i_exp; + khm_int64 i_now; + + i_issue = FtToInt(&ft_issue); + i_exp = FtToInt(&ft_exp); + i_now = FtToInt(&ft_now); + + if (i_now > (i_issue + i_exp) / 2) { + + khm_cred_renew_identity(ident); + + } + } + + kcdb_identity_release(ident); + } +} diff --git a/mechglue/src/windows/identity/ui/credfuncs.h b/mechglue/src/windows/identity/ui/credfuncs.h new file mode 100644 index 000000000..b9be3d487 --- /dev/null +++ b/mechglue/src/windows/identity/ui/credfuncs.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_CREDFUNCS_H +#define __KHIMAIRA_CREDFUNCS_H + +void KHMAPI +kmsg_cred_completion(kmq_message *m); + +void +khm_cred_destroy_creds(void); + +void +khm_cred_renew_identity(khm_handle identity); + +void +khm_cred_renew_cred(khm_handle cred); + +void +khm_cred_renew_creds(void); + +void +khm_cred_obtain_new_creds(wchar_t * window_title); + +void +khm_cred_set_default(void); + +void +khm_cred_change_password(wchar_t * window_title); + +void +khm_cred_dispatch_process_message(khui_new_creds *nc); + +BOOL +khm_cred_dispatch_process_level(khui_new_creds *nc); + +BOOL +khm_cred_is_in_dialog(void); + +khm_int32 +khm_cred_wait_for_dialog(DWORD timeout, khm_int32 * result, + wchar_t * ident, khm_size cb_ident); + +void +khm_cred_begin_commandline(void); + +void +khm_cred_process_commandline(void); + +void +khm_cred_refresh(void); + +void +khm_cred_addr_change(void); + +void +khm_cred_import(void); + +#endif diff --git a/mechglue/src/windows/identity/ui/credwnd.c b/mechglue/src/windows/identity/ui/credwnd.c new file mode 100644 index 000000000..5211d50b1 --- /dev/null +++ b/mechglue/src/windows/identity/ui/credwnd.c @@ -0,0 +1,3608 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<prsht.h> +#include<assert.h> + +ATOM khui_credwnd_cls; +khm_int32 khui_cw_flag_id; + +khm_int32 +cw_get_custom_attr_id(wchar_t * s) +{ + if(!wcscmp(s, CW_CANAME_FLAGS)) + return CW_CA_FLAGS; + if(!wcscmp(s, CW_CANAME_TYPEICON)) + return CW_CA_TYPEICON; + return 0; +} + +void +cw_load_view(khui_credwnd_tbl * tbl, wchar_t * view, HWND hwnd) { + khm_handle hc_cw = NULL; + khm_handle hc_vs = NULL; + khm_handle hc_v = NULL; + khm_handle hc_cs = NULL; + khm_handle hc_c = NULL; + wchar_t buf[KCONF_MAXCCH_NAME]; + wchar_t * clist = NULL; + khm_size cbsize; + wchar_t * cstr = NULL; + wchar_t * iter = NULL; + int i; + HDC hdc; + + tbl->hwnd = hwnd; + + if(KHM_FAILED(khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, &hc_cw))) + return; + + if(KHM_FAILED(khc_open_space(hc_cw, L"Views", KHM_PERM_READ, &hc_vs))) + goto _exit; + + if(!view) { + cbsize = sizeof(buf); + if(KHM_FAILED(khc_read_string(hc_cw, L"DefaultView", buf, &cbsize))) + goto _exit; + view = buf; + } + + if(KHM_FAILED(khc_open_space(hc_vs, view, KHM_PERM_READ, &hc_v))) + goto _exit; + + if(KHM_FAILED(khc_open_space(hc_v, L"Columns", KHM_PERM_READ, &hc_cs))) + goto _exit; + + cbsize = 0; + if(khc_read_multi_string(hc_v, L"ColumnList", NULL, &cbsize) != KHM_ERROR_TOO_LONG) + goto _exit; + + /* temporary */ + clist = PMALLOC(cbsize); + + if(KHM_FAILED(khc_read_multi_string(hc_v, L"ColumnList", clist, &cbsize))) + goto _exit; + + tbl->n_cols = (int) multi_string_length_n(clist); + tbl->n_total_cols = UBOUNDSS(tbl->n_cols, KHUI_CW_COL_INITIAL, KHUI_CW_COL_INCREMENT); + tbl->cols = PMALLOC(sizeof(khui_credwnd_col) * tbl->n_total_cols); + ZeroMemory(tbl->cols, sizeof(khui_credwnd_col) * tbl->n_total_cols); + + iter = clist; + i = 0; + while(iter) { + khm_int32 attr_id; + + attr_id = cw_get_custom_attr_id(iter); + if(!attr_id) { + /* a KCDB attribute */ + if(KHM_FAILED(kcdb_attrib_get_id(iter, &attr_id))) + goto _skip_col; + if(kcdb_attrib_describe(attr_id, NULL, &cbsize, KCDB_TS_SHORT) != KHM_ERROR_TOO_LONG || + cbsize == 0) + goto _skip_col; + tbl->cols[i].title = PMALLOC(cbsize); + kcdb_attrib_describe(attr_id, tbl->cols[i].title, &cbsize, KCDB_TS_SHORT); + } else { + /* All current custom attributes are represented by icons, + not names */ + tbl->cols[i].title = NULL; + } + + tbl->cols[i].attr_id = attr_id; + + if(KHM_SUCCEEDED(khc_open_space(hc_cs, iter, KHM_PERM_READ, &hc_c))) { + if(KHM_FAILED(khc_read_int32(hc_c, L"Flags", &(tbl->cols[i].flags)))) + tbl->cols[i].flags = 0; + if(KHM_FAILED(khc_read_int32(hc_c, L"Width", &(tbl->cols[i].width)))) + tbl->cols[i].width = -1; + if(KHM_FAILED(khc_read_int32(hc_c, L"SortIndex", &(tbl->cols[i].sort_index)))) + tbl->cols[i].sort_index = -1; + khc_close_space(hc_c); + hc_c = NULL; + } else { + tbl->cols[i].flags = 0; + tbl->cols[i].width = -1; + tbl->cols[i].sort_index = -1; + } + i++; +_skip_col: + iter = multi_string_next(iter); + } + + /* adjust the number of columns. We may have skipped columns due to + inconsistencies above */ + tbl->n_cols = i; + + /* now that all the columns have been loaded, load the view + parameters */ + if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingHorizontal", &(tbl->hpad)))) + khc_read_int32(hc_cw, L"PaddingHorizontal", &(tbl->hpad)); + if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingVertical", &(tbl->vpad)))) + khc_read_int32(hc_cw, L"PaddingVertical", &(tbl->vpad)); + if(KHM_FAILED(khc_read_int32(hc_v, L"PaddingHeader", &(tbl->hpad_h)))) + khc_read_int32(hc_cw, L"PaddingHeader", &(tbl->hpad_h)); + if(KHM_FAILED(khc_read_int32(hc_v, L"WarnThreshold", &(tbl->threshold_warn)))) + khc_read_int32(hc_cw, L"WarnThreshold", &(tbl->threshold_warn)); + if(KHM_FAILED(khc_read_int32(hc_v, L"CriticalThreshold", &(tbl->threshold_critical)))) + khc_read_int32(hc_cw, L"CriticalThreshold", &(tbl->threshold_critical)); + + /* and the font resources and stuff */ + + tbl->flags |= KHUI_CW_TBL_INITIALIZED | KHUI_CW_TBL_COL_DIRTY | KHUI_CW_TBL_ACTIVE; + + /*TODO: the graphics objects should be customizable */ + + hdc = GetWindowDC(hwnd); + + tbl->hf_header = CreateFont( + -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_THIN, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + if(tbl->hf_header && tbl->hwnd_header) + SendMessage(tbl->hwnd_header, WM_SETFONT, (WPARAM) tbl->hf_header, 0); + + tbl->hf_bold_header = CreateFont( + -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_BOLD, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + tbl->hf_normal = CreateFont( + -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_THIN, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + tbl->hf_bold = CreateFont( + -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),0, /* width/height */ + 0,0, /* escapement */ + FW_BOLD, + FALSE, + FALSE, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + L"MS Shell Dlg"); + + ReleaseDC(hwnd, hdc); + + khui_bitmap_from_hbmp(&(tbl->kbm_logo_shade),LoadImage( + khm_hInstance, + MAKEINTRESOURCE(IDB_LOGO_SHADE), + IMAGE_BITMAP, + 0, + 0, + LR_DEFAULTCOLOR)); + + tbl->hb_normal = CreateSolidBrush(RGB(255,255,255)); + tbl->hb_grey = CreateSolidBrush(RGB(240,240,240)); + tbl->hb_sel = CreateSolidBrush(RGB(230,230,255)); + tbl->hb_hdr_bg = CreateSolidBrush(RGB(230,230,230)); + tbl->hb_hdr_bg_sel = CreateSolidBrush(RGB(0,0,255)); + tbl->hb_hdr_bg_crit = CreateSolidBrush(RGB(240,133,117)); + tbl->hb_hdr_bg_warn = CreateSolidBrush(RGB(251,199,77)); + tbl->hb_hdr_bg_exp = CreateSolidBrush(RGB(255,144,144)); + tbl->hb_hdr_bg_def = CreateSolidBrush(RGB(186,254,184)); + + tbl->cr_normal = RGB(0,0,0); + tbl->cr_sel = RGB(0,0,0); + tbl->cr_hdr_outline = RGB(0,0,0); + tbl->cr_hdr_normal = RGB(0,0,0); + tbl->cr_hdr_sel = RGB(255,255,255); + + tbl->ilist = khui_create_ilist(KHUI_SMICON_CX, KHUI_SMICON_CY-1, 20, 8, 0); + { + HBITMAP hbm; + +#define ADD_BITMAP(i) \ + hbm = LoadImage(khm_hInstance, MAKEINTRESOURCE(i), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); \ + if(hbm) { \ + khui_ilist_add_masked_id(tbl->ilist, hbm, KHUI_TOOLBAR_BGCOLOR, i); \ + DeleteObject(hbm); \ + } + + ADD_BITMAP(IDB_WDG_COLLAPSE); + ADD_BITMAP(IDB_WDG_EXPAND); + ADD_BITMAP(IDB_ID_SM); + ADD_BITMAP(IDB_ID_DIS_SM); + ADD_BITMAP(IDB_TK_NEW_SM); + ADD_BITMAP(IDB_TK_REFRESH_SM); + ADD_BITMAP(IDB_WDG_COLLAPSE_HI); + ADD_BITMAP(IDB_WDG_EXPAND_HI); + ADD_BITMAP(IDB_WDG_FLAG); + ADD_BITMAP(IDB_WDG_CREDTYPE); + ADD_BITMAP(IDB_FLAG_WARN); + ADD_BITMAP(IDB_FLAG_EXPIRED); + ADD_BITMAP(IDB_FLAG_CRITICAL); + ADD_BITMAP(IDB_FLAG_RENEW); + ADD_BITMAP(IDB_WDG_STUCK); + ADD_BITMAP(IDB_WDG_STUCK_HI); + ADD_BITMAP(IDB_WDG_STICK); + ADD_BITMAP(IDB_WDG_STICK_HI); + +#undef ADD_BITMAP + } + + tbl->cursor_row = -1; + tbl->scr_left = 0; + tbl->scr_top = 0; + tbl->ext_height = 0; + tbl->ext_width = 0; + +_exit: + if(hc_cw) + khc_close_space(hc_cw); + if(hc_vs) + khc_close_space(hc_vs); + if(hc_v) + khc_close_space(hc_v); + if(hc_cs) + khc_close_space(hc_cs); + if(clist) + PFREE(clist); +} + +void +cw_update_creds(khui_credwnd_tbl * tbl) +{ + kcdb_cred_comp_field * fields; + kcdb_cred_comp_order comp_order; + khm_size i; + khm_int32 n; + khm_int32 delta; + khm_handle hc; + khm_int32 flags; + + if(!tbl->credset) { + if(KHM_FAILED(kcdb_credset_create(&(tbl->credset)))) + return; + } + + kcdb_credset_purge(tbl->credset); + + kcdb_identity_refresh_all(); + + kcdb_credset_collect( + tbl->credset, + NULL, + NULL, + KCDB_CREDTYPE_ALL, + &delta); + + /* now we need to figure out how to sort the credentials */ + fields = PMALLOC(sizeof(kcdb_cred_comp_field) * tbl->n_cols); + ZeroMemory(fields, sizeof(kcdb_cred_comp_field) * tbl->n_cols); + + for(i=0, n=0; i<tbl->n_cols; i++) { + if((tbl->cols[i].flags & KHUI_CW_COL_SORT_INC) || + (tbl->cols[i].flags & KHUI_CW_COL_SORT_DEC) || + (tbl->cols[i].flags & KHUI_CW_COL_GROUP)) + { + int si; + /* we need to sort by this column */ + si = tbl->cols[i].sort_index; + + if(si < 0 || si >= (int) tbl->n_cols) + { + /* this shouldn't happen */ + tbl->cols[i].flags &= ~(KHUI_CW_COL_SORT_INC | + KHUI_CW_COL_SORT_DEC | + KHUI_CW_COL_GROUP); + continue; + } + + fields[si].attrib = tbl->cols[i].attr_id; + if(tbl->cols[i].flags & KHUI_CW_COL_SORT_DEC) + fields[si].order = KCDB_CRED_COMP_DECREASING; + else + fields[si].order = KCDB_CRED_COMP_INCREASING; + + /* special case. if we are sorting by name, we group + initial tickets before non-initial tickets. + + Also, if we are sorting by credential type name, then + we allow the primary credential type first before + others. + */ + + if (fields[si].attrib == KCDB_ATTR_NAME || + fields[si].attrib == KCDB_ATTR_TYPE_NAME) + fields[si].order |= KCDB_CRED_COMP_INITIAL_FIRST; + + if(si >= n) + n = si+1; + } + } + + /* we assume that the sort order is sane */ + /*TODO: don't assume; check if the sort order is sane */ + + comp_order.nFields = n; + comp_order.fields = fields; + + kcdb_credset_sort(tbl->credset, + kcdb_cred_comp_generic, + (void *) &comp_order); + + /* also, if new credentials were added, initialize the UI flag + attribute to 0 */ + if(delta & KCDB_DELTA_ADD) { + khm_size s; + + kcdb_credset_get_size(tbl->credset, &s); + for(i=0;i<s;i++) { + if(KHM_FAILED(kcdb_credset_get_cred(tbl->credset, + (khm_int32) i, &hc))) + continue; /* lost a race */ + if(KHM_FAILED(kcdb_cred_get_attr(hc, khui_cw_flag_id, NULL, + NULL, NULL))) { + flags = 0; + kcdb_cred_set_attr(hc, khui_cw_flag_id, &flags, sizeof(flags)); + } + kcdb_cred_release(hc); + } + } + + if (fields) + PFREE(fields); +} + +void +cw_del_outline(khui_credwnd_outline *o) { + khui_credwnd_outline * c; + if(!o) + return; + + /* the outline object is still in a list */ + if(o->next || o->prev) + return; + + if(o->header) + PFREE(o->header); + if ((o->flags & KHUI_CW_O_DATAALLOC) && + o->data) + PFREE(o->data); + + if ((o->flags & KHUI_CW_O_STICKY) && + o->data) + kcdb_identity_release((khm_handle) o->data); + + LPOP(&(o->children), &c); + while(c) { + cw_del_outline(c); + LPOP(&(o->children), &c); + } + + PFREE(o); +} + +khui_credwnd_outline * +cw_new_outline_node(wchar_t * heading) { + khui_credwnd_outline * o; + size_t cblen; + + o = PMALLOC(sizeof(khui_credwnd_outline)); + ZeroMemory(o, sizeof(khui_credwnd_outline)); + + if(SUCCEEDED(StringCbLength(heading, KHUI_MAXCB_HEADING, &cblen))) { + cblen += sizeof(wchar_t); + o->header = PMALLOC(cblen); + StringCbCopy(o->header, cblen, heading); + } + + return o; +} + +khm_int32 +cw_get_cred_exp_flags(khui_credwnd_tbl * tbl, khm_handle cred) +{ + khm_int32 flags; + long s; + FILETIME ft; + khm_size cbsize; + + cbsize = sizeof(ft); + if(KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize))) + return 0; + + s = FtIntervalToSeconds(&ft); + + flags = 0; + if(s < 0) + flags = CW_EXPSTATE_EXPIRED; + else if(s < tbl->threshold_critical) + flags = CW_EXPSTATE_CRITICAL; + else if(s < tbl->threshold_warn) + flags = CW_EXPSTATE_WARN; + else + flags = CW_EXPSTATE_NONE; + + return flags; +} + +void cw_update_outline(khui_credwnd_tbl * tbl); + +VOID CALLBACK +cw_timer_proc(HWND hwnd, + UINT uMsg, + UINT_PTR idEvent, + DWORD dwTime) +{ + khui_credwnd_tbl * tbl; + khui_credwnd_row * r; + khm_int32 nflags; + khm_size nr; + long ms; + FILETIME ft; + khm_size cbsize; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + r = (khui_credwnd_row *) idEvent; + + nr = r - tbl->rows; + + if(nr < 0 || nr >= tbl->n_rows) + return; + + if(!(r->flags & KHUI_CW_ROW_CRED)) + return; /* we only know what to do with cred rows */ + + nflags = cw_get_cred_exp_flags(tbl, (khm_handle) r->data); + if((r->flags & CW_EXPSTATE_MASK) != nflags) { + /* flags have changed */ + /* the outline needs to be updated */ + cw_update_outline(tbl); + InvalidateRect(tbl->hwnd, NULL, FALSE); + } else { + /* just invalidate the row */ + RECT r,rr,ri; + + GetClientRect(tbl->hwnd, &r); + r.top += tbl->header_height; + rr.top = r.top + (long)nr * tbl->cell_height - tbl->scr_top; + rr.bottom = rr.top + tbl->cell_height; + rr.left = r.left; + rr.right = r.right; + + if(IntersectRect(&ri, &r, &rr)) + InvalidateRect(tbl->hwnd, &ri, FALSE); + } + + cbsize = sizeof(ft); + if(KHM_SUCCEEDED(kcdb_cred_get_attr((khm_handle) r->data, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize))) + { + ms = FtIntervalMsToRepChange(&ft); + if(ms > 0) { + SetTimer(tbl->hwnd, (UINT_PTR) r, ms + 100, cw_timer_proc); + } + } +} + +void +cw_set_tbl_row_cred(khui_credwnd_tbl * tbl, + int row, + khm_handle cred, + int col) +{ + FILETIME ft; + long ms; + khm_size cbsize; + + if((int) tbl->n_total_rows <= row) { + /* we need to resize the allocation */ + khui_credwnd_row * newrows; + khm_size newsize; + + newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); + newrows = PMALLOC(sizeof(khui_credwnd_row) * newsize); + memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows); + PFREE(tbl->rows); + tbl->rows = newrows; + tbl->n_total_rows = newsize; + } + + tbl->rows[row].col = col; + tbl->rows[row].data = cred; + tbl->rows[row].flags = KHUI_CW_ROW_CRED; + + /* Set any required timer events */ + cbsize = sizeof(ft); + if(KHM_SUCCEEDED(kcdb_cred_get_attr(cred, KCDB_ATTR_TIMELEFT, NULL, &ft, &cbsize))) { + ms = FtIntervalMsToRepChange(&ft); + if(ms > 0) { + SetTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[row]), ms + 100, cw_timer_proc); + tbl->rows[row].flags |= KHUI_CW_ROW_TIMERSET; + } + } +} + +void +cw_set_tbl_row_header(khui_credwnd_tbl * tbl, + int row, int col, + khui_credwnd_outline * o) +{ + if((int) tbl->n_total_rows <= row) { + /* we need to resize the allocation */ + khui_credwnd_row * newrows; + khm_size newsize; + + newsize = UBOUNDSS(row+1,KHUI_CW_ROW_INITIAL, KHUI_CW_ROW_INCREMENT); + newrows = PMALLOC(sizeof(khui_credwnd_row) * newsize); + memcpy(newrows, tbl->rows, sizeof(khui_credwnd_row) * tbl->n_rows); + PFREE(tbl->rows); + tbl->rows = newrows; + tbl->n_total_rows = newsize; + } + + tbl->rows[row].col = col; + tbl->rows[row].data = (khm_handle) o; + tbl->rows[row].flags = KHUI_CW_ROW_HEADER; + if(o->flags & KHUI_CW_O_SELECTED) + tbl->rows[row].flags |= KHUI_CW_ROW_SELECTED; +} + +static int +iwcscmp(const void * p1, const void * p2) { + const wchar_t * s1 = *(wchar_t **) p1; + const wchar_t * s2 = *(wchar_t **) p2; + + return wcscmp(s1, s2); +} + +void +cw_update_outline(khui_credwnd_tbl * tbl) +{ + int i,j,n_rows; + int level; + int visible; + khm_size n_creds; + khm_handle prevcred = NULL; + khm_handle thiscred = NULL; + /* grouping[0..n_grouping-1] are the columns that we are going to + group the display by. Say we are grouping by identity and then + by type, then grouping[0]=col# of identity and grouping[1]=col# + of type */ + khm_int32 * grouping = NULL; + khui_credwnd_outline * ol = NULL; + int n_grouping; + wchar_t buf[256]; + khm_size cbbuf; + khm_int32 flags; + int selected; + khm_int32 expstate = 0; + + /* this is called after calling cw_update_creds, so we assume + that the credentials are all loaded and sorted according to + grouping rules */ + + /* if the columns have changed, then any outline info we have + cached are unreliable */ + if(tbl->flags & KHUI_CW_TBL_COL_DIRTY) { + khui_credwnd_outline * o; + LPOP(&(tbl->outline), &o); + while(o) { + cw_del_outline(o); + LPOP(&(tbl->outline), &o); + } + tbl->n_rows = 0; + } + + /* Otherwise, we should reset the outline indices. Just the first + level is enough */ + if (tbl->outline) { + khui_credwnd_outline * o; + + o = tbl->outline; + while(o) { + o->start = -1; + o = LNEXT(o); + } + } + + /* determine the grouping order */ + grouping = PMALLOC(sizeof(khm_int32) * tbl->n_cols); + for(i=0; i < (int) tbl->n_cols; i++) + grouping[i] = -1; + n_grouping = 0; + + for(i=0; i < (int) tbl->n_cols; i++) { + /* since cw_update_creds has run, the KHUI_CW_COL_GROUP flag + only exists for columns that has a valid sort_index */ + if(tbl->cols[i].flags & KHUI_CW_COL_GROUP) { + grouping[tbl->cols[i].sort_index] = i; + if(n_grouping <= tbl->cols[i].sort_index) + n_grouping = tbl->cols[i].sort_index + 1; + } + } + + /* if we have sorted by an index without grouping by it, we can't + establish any grouping beyond that index. */ + for(i=0; i < n_grouping; i++) { + if(grouping[i] == -1) + break; + } + n_grouping = i; + + if(!tbl->rows) { + /* we haven't allocated memory yet */ + tbl->n_total_rows = KHUI_CW_ROW_INITIAL; + tbl->n_rows = 0; + tbl->rows = PMALLOC(sizeof(khui_credwnd_row) * tbl->n_total_rows); + } else { + /* kill any pending timers */ + for(i=0; i < (int) tbl->n_rows; i++) + if(tbl->rows[i].flags & KHUI_CW_ROW_TIMERSET) + { + KillTimer(tbl->hwnd, (UINT_PTR) &(tbl->rows[i])); + tbl->rows[i].flags &= ~KHUI_CW_ROW_TIMERSET; + } + } + + if(KHM_FAILED(kcdb_credset_get_size(tbl->credset, &n_creds))) + goto _exit; + + n_rows = 0; + prevcred = NULL; + ol = NULL; + + for(i=0; i < (int) n_creds; i++) { + if(KHM_FAILED(kcdb_credset_get_cred(tbl->credset, i, &thiscred))) + continue; + + /* if this credential appears to be the same as another for + this view, we skip it */ + if(prevcred) { + for(j=0; j < (int) tbl->n_cols; j++) { + if(kcdb_creds_comp_attr(prevcred, thiscred, + tbl->cols[j].attr_id)) + break; + } + + if(j >= (int) tbl->n_cols) { + if (n_rows > 0) { + tbl->rows[n_rows - 1].idx_end = i; + } + continue; + } + } + + if(!prevcred) + level = 0; + else { + for(j=0; j < n_grouping; j++) { + /* determine the grouping level at which thiscred + differs from prevcred */ + if(kcdb_creds_comp_attr(prevcred,thiscred, + tbl->cols[grouping[j]].attr_id)) + break; + } + level = j; + } + + /* now we have to walk up until we get to the parent of the + outline level we should be in */ + while(ol && ol->level >= level) { + ol->length = n_rows - ol->start; + ol->idx_end = i - 1; + ol = TPARENT(ol); + } + + if(ol) { + visible = (ol->flags & KHUI_CW_O_VISIBLE) && + (ol->flags & KHUI_CW_O_EXPAND); + selected = (ol->flags & KHUI_CW_O_SELECTED); + } else { + visible = TRUE; + selected = FALSE; + } + + /* now ol points to an outline node at the next highest level + or is NULL if level = 0 */ + + for(j=level; j < n_grouping; j++) { + khui_credwnd_outline * to; + /* now we search for an outline object at the next level + which matches the heading */ + cbbuf = sizeof(buf); + buf[0] = L'\0'; + if(KHM_FAILED + (kcdb_cred_get_attr_string(thiscred, + tbl->cols[grouping[j]].attr_id, + buf, &cbbuf, 0))) { + cbbuf = sizeof(wchar_t); + buf[0] = L'\0'; + } + + if(ol) + to = TFIRSTCHILD(ol); + else + to = tbl->outline; + + while(to) { + if(!wcscmp(buf, to->header)) + break; + to = LNEXT(to); + } + + if(to) { + /* found it */ + ol = to; + } else { + /* not found. create */ + to = cw_new_outline_node(buf); + if(ol) { + TADDCHILD(ol, to); + } else { + LPUSH(&(tbl->outline), to); + } + ol = to; + ol->flags = KHUI_CW_O_EXPAND; + ol->level = j; + ol->col = grouping[j]; + + if(tbl->cols[grouping[j]].attr_id == KCDB_ATTR_ID_NAME) { + khm_handle h; + if(KHM_SUCCEEDED(kcdb_identity_create(buf, 0, &h))) { + ol->attr_id = KCDB_ATTR_ID; + ol->data = (void *) h; + + /* the outline only lasts as long as the + credential, and the credential has a hold + on the identity. */ + kcdb_identity_release(h); + } + else + ol->data = 0; + } else if(tbl->cols[grouping[j]].attr_id == + KCDB_ATTR_TYPE_NAME) { + khm_int32 t; + + ol->attr_id = KCDB_ATTR_TYPE; + if(KHM_SUCCEEDED(kcdb_cred_get_type(thiscred, &t))) + ol->data = (void *)(ssize_t) t; + else + ol->data = (void *)(ssize_t) KCDB_CREDTYPE_INVALID; + } else { + khm_int32 rv; + khm_int32 alt_id; + kcdb_attrib * attrib; + + rv = + kcdb_attrib_get_info(tbl->cols[grouping[j]].attr_id, + &attrib); + assert(KHM_SUCCEEDED(rv)); + + if (attrib->flags & KCDB_ATTR_FLAG_ALTVIEW) + alt_id = attrib->alt_id; + else + alt_id = tbl->cols[grouping[j]].attr_id; + + ol->attr_id = alt_id; + + kcdb_attrib_release_info(attrib); + + rv = kcdb_cred_get_attr(thiscred, + alt_id, + NULL, + NULL, + &cbbuf); + if (rv != KHM_ERROR_TOO_LONG || cbbuf == 0) { + ol->data = NULL; + } else { + ol->data = PMALLOC(cbbuf); + assert(ol->data); + rv = kcdb_cred_get_attr(thiscred, + alt_id, + NULL, + ol->data, + &cbbuf); + assert(KHM_SUCCEEDED(rv)); + ol->cb_data = cbbuf; + ol->flags |= KHUI_CW_O_DATAALLOC; + } + } + } + + /* now ol points at the node at level j we want to be + in */ + ol->start = n_rows; + ol->idx_start = i; + ol->length = 0; + ol->flags &= ~CW_EXPSTATE_MASK; + ol->flags &= ~KHUI_CW_O_SHOWFLAG; + ol->flags &= ~KHUI_CW_O_STICKY; + + if(selected) { + ol->flags |= KHUI_CW_O_SELECTED; + } + if(visible) { + cw_set_tbl_row_header(tbl, n_rows, grouping[j], ol); + n_rows ++; + ol->flags |= KHUI_CW_O_VISIBLE; + } else { + ol->flags &= ~KHUI_CW_O_VISIBLE; + } + visible = visible && (ol->flags & KHUI_CW_O_EXPAND); + selected = (selected || (ol->flags & KHUI_CW_O_SELECTED)); + } + + /* we need to do this here too just in case we were already at + the level we were supposed to be in */ + visible = visible && (ol->flags & KHUI_CW_O_EXPAND); + + flags = cw_get_cred_exp_flags(tbl, thiscred); + expstate |= flags; + + if(visible) { + khm_int32 c_flags; + + cw_set_tbl_row_cred(tbl, n_rows, thiscred, + grouping[n_grouping-1]); + kcdb_cred_get_flags(thiscred, &c_flags); + if(flags) { + tbl->rows[n_rows].flags |= flags; + } + if(selected || + (c_flags & KCDB_CRED_FLAG_SELECTED)) + tbl->rows[n_rows].flags |= KHUI_CW_ROW_SELECTED; + tbl->rows[n_rows].idx_start = i; + tbl->rows[n_rows].idx_end = i; + + n_rows++; + } else if(flags) { + khui_credwnd_outline *to; + /* the row that is flagged is not visible. We need to send + the flag upstream until we hit a visible outline node */ + to = ol; + while(to && !(to->flags & KHUI_CW_O_VISIBLE)) { + to = TPARENT(to); + } + if(to) { + to->flags |= KHUI_CW_O_SHOWFLAG; + } + } + + /* and we propagate the flags upstream */ + if(flags) { + khui_credwnd_outline *to; + + to = ol; + while(to) { + if((to->flags & CW_EXPSTATE_MASK) < flags) { + to->flags = (to->flags & ~CW_EXPSTATE_MASK) | flags; + } + to = TPARENT(to); + } + } + + if(prevcred) + kcdb_cred_release(prevcred); + prevcred = thiscred; + } + + while(ol) { + ol->length = n_rows - ol->start; + ol->idx_end = i - 1; + ol = TPARENT(ol); + } + + if(prevcred) { + kcdb_cred_release(prevcred); + prevcred = NULL; + } + + /* Add any sticky identities that we haven't seen yet */ + if (n_grouping > 0 && + tbl->cols[grouping[0]].attr_id == KCDB_ATTR_ID_NAME) { + + khui_credwnd_outline * o; + wchar_t * idnames = NULL; + wchar_t * t; + khm_size n_idents; + khm_size cb_names; + wchar_t ** idarray = NULL; + int i; + + if (kcdb_identity_enum(KCDB_IDENT_FLAG_STICKY, + KCDB_IDENT_FLAG_STICKY, + NULL, + &cb_names, + &n_idents) != KHM_ERROR_TOO_LONG || + n_idents == 0 || + cb_names == 0) + goto _cleanup_sticky; + + idnames = PMALLOC(cb_names); + idarray = PMALLOC(n_idents * sizeof(*idarray)); +#ifdef DEBUG + assert(idnames); + assert(idarray); +#endif + + if (KHM_FAILED(kcdb_identity_enum(KCDB_IDENT_FLAG_STICKY, + KCDB_IDENT_FLAG_STICKY, + idnames, + &cb_names, + &n_idents))) + goto _cleanup_sticky; + + for (i=0, t=idnames; t && *t; t = multi_string_next(t), i++) { + idarray[i] = t; + } + + qsort(idarray, n_idents, sizeof(*idarray), iwcscmp); + + for (i=0; i < (int) n_idents; i++) { + khm_handle h; + + if (KHM_FAILED(kcdb_identity_create(idarray[i], + KCDB_IDENT_FLAG_CREATE, &h))) + continue; + + for (o = tbl->outline; o; o = LNEXT(o)) { + if (!wcscmp(idarray[i], o->header)) + break; + } + + if (o) { + /* found it */ + if (o->start != -1) /* already visible? */ + continue; + o->flags &= KHUI_CW_O_STICKY; + o->flags |= KHUI_CW_O_VISIBLE; + } else { + /* not found. create */ + o = cw_new_outline_node(idarray[i]); + o->flags = KHUI_CW_O_VISIBLE; + o->level = 0; + o->col = grouping[0]; + o->data = (void *) h; + } + + if (o->flags & KHUI_CW_O_STICKY) + kcdb_identity_release(h); + else + /* leave identity held in this case */ + o->flags |= KHUI_CW_O_STICKY; + + o->flags &= ~KHUI_CW_O_EXPAND; + o->start = n_rows; + o->length = 1; + o->idx_start = -1; + + cw_set_tbl_row_header(tbl, n_rows, grouping[0], o); + + n_rows ++; + } + + _cleanup_sticky: + if (idnames) + PFREE(idnames); + if (idarray) + PFREE(idarray); + } + + tbl->n_rows = n_rows; + tbl->flags |= KHUI_CW_TBL_ROW_DIRTY; + + tbl->flags &= ~KHUI_CW_TBL_COL_DIRTY; +_exit: + if(grouping) + PFREE(grouping); + + if (tbl->n_rows == 0) + khm_notify_icon_expstate(KHM_NOTIF_EMPTY); + else if (expstate & CW_EXPSTATE_EXPIRED) + khm_notify_icon_expstate(KHM_NOTIF_EXP); + else if ((expstate & CW_EXPSTATE_WARN) || + (expstate & CW_EXPSTATE_CRITICAL)) + khm_notify_icon_expstate(KHM_NOTIF_WARN); + else + khm_notify_icon_expstate(KHM_NOTIF_OK); +} + +void +cw_unload_view(khui_credwnd_tbl * tbl) +{ +#define SafeDeleteObject(o) \ + do { \ + if(o) { \ + DeleteObject(o); \ + o = NULL; \ + } \ + } while(0) + + SafeDeleteObject(tbl->hf_header); + SafeDeleteObject(tbl->hf_normal); + SafeDeleteObject(tbl->hf_bold); + SafeDeleteObject(tbl->hf_bold_header); + SafeDeleteObject(tbl->hb_grey); + SafeDeleteObject(tbl->hb_normal); + SafeDeleteObject(tbl->hb_sel); + SafeDeleteObject(tbl->hb_hdr_bg); + SafeDeleteObject(tbl->hb_hdr_bg_sel); + SafeDeleteObject(tbl->hb_hdr_bg_crit); + SafeDeleteObject(tbl->hb_hdr_bg_exp); + SafeDeleteObject(tbl->hb_hdr_bg_warn); + SafeDeleteObject(tbl->hb_hdr_bg_def); + +#undef SafeDeleteObject + + if(tbl->credset) { + kcdb_credset_delete(tbl->credset); + tbl->credset = NULL; + } + if(tbl->ilist) { + khui_delete_ilist(tbl->ilist); + tbl->ilist = NULL; + } + + if(tbl->cols) { + khm_size i; + for(i=0; i < tbl->n_cols; i++) { + if(tbl->cols[i].title) + PFREE(tbl->cols[i].title); + Header_DeleteItem(tbl->hwnd_header, 0); + } + PFREE(tbl->cols); + tbl->cols = NULL; + tbl->n_cols = 0; + tbl->n_total_cols = 0; + } + + if(tbl->rows) { + PFREE(tbl->rows); + tbl->rows = NULL; + tbl->n_rows = 0; + tbl->n_total_rows = 0; + } + + khui_delete_bitmap(&tbl->kbm_logo_shade); +} + +void +cw_hditem_from_tbl_col(khui_credwnd_col * col, HDITEM *phi) +{ + size_t cchsize; + + phi->mask = HDI_FORMAT | HDI_LPARAM | HDI_WIDTH; + if(cw_is_custom_attr(col->attr_id)) { + if(col->attr_id == CW_CA_FLAGS) { + phi->fmt = 0; + } else if(col->attr_id == CW_CA_TYPEICON) { + phi->fmt = 0; + } else { + /* what the? */ + /*TODO: throw up and die */ + } + } else { + phi->mask |= HDI_TEXT; + phi->pszText = col->title; + StringCchLength(col->title, KCDB_MAXCCH_SHORT_DESC, &cchsize); + phi->cchTextMax = (int) cchsize; + phi->fmt = HDF_CENTER | HDF_STRING; + } + phi->lParam = col->attr_id; +#if (_WIN32_WINNT >= 0x501) + if (IS_COMMCTL6()) { + if(col->flags & KHUI_CW_COL_SORT_INC) { + phi->fmt |= HDF_SORTUP; + } else if(col->flags & KHUI_CW_COL_SORT_DEC) { + phi->fmt |= HDF_SORTDOWN; + } + } +#endif + if(col->width < 0) { + /*TODO: come up with a better way to handle this case */ + col->width = 200; + } + phi->cxy = col->width; +} + +/* returns a bitmask indicating which measures were changed */ +int +cw_update_extents(khui_credwnd_tbl * tbl, + khm_boolean update_scroll) { + int ext_x, ext_y; + int i; + + ext_x = 0; + for(i=0; i < (int) tbl->n_cols; i++) { + tbl->cols[i].x = ext_x; + ext_x += tbl->cols[i].width; + } + + if(!tbl->cell_height) { + HDC dc; + HFONT hfold; + SIZE size; + size_t cbbuf; + wchar_t buf[64]; + + dc = GetWindowDC(tbl->hwnd); + if(tbl->hf_normal) + hfold = SelectFont(dc, tbl->hf_normal); + + LoadString(khm_hInstance, IDS_SAMPLE_STRING, buf, sizeof(buf)/sizeof(buf[0])); + StringCchLength(buf, sizeof(buf)/sizeof(buf[0]), &cbbuf); + GetTextExtentPoint32(dc, buf, (int) cbbuf, &size); + + if(tbl->hf_normal) + SelectFont(dc,hfold); + ReleaseDC(tbl->hwnd, dc); + + tbl->cell_height = size.cy + tbl->vpad * 2; + } + + ext_y = (int) tbl->n_rows * tbl->cell_height; + + tbl->ext_width = ext_x; + tbl->ext_height = ext_y; + + /* useful in the future when implementing variable height rows. + The KHUI_CW_TBL_ROW_DIRTY bit indicates that the rows have + changed and that the y extent has to be recalculated. */ + tbl->flags &= ~KHUI_CW_TBL_ROW_DIRTY; + + if(update_scroll) { + RECT r; + int cl_w; + int cl_h; + SCROLLINFO si; + WINDOWPOS pw; + HDLAYOUT hdl; + + /* update the header control first */ + +retry_update_scroll: + GetClientRect(tbl->hwnd, &r); + + cl_w = r.right - r.left; + cl_h = (r.bottom - r.top); + cl_h -= tbl->header_height; + + if(tbl->scr_top < 0 || tbl->ext_height < cl_h) + tbl->scr_top = 0; + else if(tbl->scr_top > tbl->ext_height - cl_h) + tbl->scr_top = tbl->ext_height - cl_h; + if(tbl->scr_left < 0 || tbl->ext_width < cl_w) + tbl->scr_left = 0; + else if(tbl->scr_left > tbl->ext_width - cl_w) + tbl->scr_left = tbl->ext_width - cl_w; + + /* adjustments for scrolling */ + r.left -= tbl->scr_left; + r.right = max(tbl->ext_width + r.left, r.right); + + hdl.prc = &r; + hdl.pwpos = &pw; + + Header_Layout(tbl->hwnd_header, &hdl); + + if(tbl->header_height == 0) { + tbl->header_height = pw.cy; + goto retry_update_scroll; + } else + tbl->header_height = pw.cy; + + SetWindowPos( + tbl->hwnd_header, + pw.hwndInsertAfter, + pw.x, + pw.y, + pw.cx, + pw.cy, + pw.flags); + + si.cbSize = sizeof(si); + si.nMin = 0; + si.nMax = tbl->ext_height; + si.nPage = cl_h; + si.nPos = tbl->scr_top; + si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; + SetScrollInfo(tbl->hwnd, SB_VERT, &si, TRUE); + + si.cbSize = sizeof(si); + si.nMin = 0; + si.nMax = tbl->ext_width; + si.nPage = cl_w; + si.nPos = tbl->scr_left; + si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; + SetScrollInfo(tbl->hwnd, SB_HORZ, &si, TRUE); + } + + return 0; +} + +void +cw_insert_header_cols(khui_credwnd_tbl * tbl) { + HWND hdr; + HDITEM hi; + int i; + + hdr = tbl->hwnd_header; + + for(i=0; i < (int) tbl->n_cols; i++) { + cw_hditem_from_tbl_col(&(tbl->cols[i]), &hi); + Header_InsertItem(hdr, 512, &hi); + } +} + +#define CW_ER_BLANK 0 +#define CW_ER_GREY 1 +#define CW_ER_SEL 2 + +void +cw_erase_rect(HDC hdc, + khui_credwnd_tbl * tbl, + RECT * r_wnd, + RECT * r_erase, + int type) +{ + RECT rlogo; + RECT ri; + RECT t; + BOOL rie; + HBRUSH hbr; + + if(RectVisible(hdc, r_erase)) { + + switch(type) { + case CW_ER_BLANK: + hbr = tbl->hb_normal; + break; + + case CW_ER_GREY: + hbr = tbl->hb_grey; + break; + + case CW_ER_SEL: + hbr = tbl->hb_sel; + break; + + default: + return; + } + + if(tbl->kbm_logo_shade.cx != -1 && type == CW_ER_BLANK) { + rlogo.left = r_wnd->right - tbl->kbm_logo_shade.cx; + rlogo.right = r_wnd->right; + rlogo.top = r_wnd->bottom - tbl->kbm_logo_shade.cy; + rlogo.bottom = r_wnd->bottom; + rie = IntersectRect(&ri, r_erase, &rlogo); + } else { + rie = FALSE; + } + + if(!rie) { + FillRect(hdc, r_erase, hbr); + } else { + HDC hdcb = CreateCompatibleDC(hdc); + HBITMAP hbmold = SelectObject(hdcb, tbl->kbm_logo_shade.hbmp); + + BitBlt(hdc, ri.left, ri.top, ri.right - ri.left, ri.bottom - ri.top, + hdcb, ri.left - rlogo.left, ri.top - rlogo.top, SRCCOPY); + + SelectObject(hdcb, hbmold); + DeleteDC(hdcb); + + if(r_erase->top < ri.top && r_erase->left < ri.left) { + t.left = r_erase->left; + t.top = r_erase->top; + t.right = ri.left; + t.bottom = ri.top; + FillRect(hdc, &t, hbr); + } + + if(r_erase->left < ri.left) { + t.left = r_erase->left; + t.top = ri.top; + t.right = ri.left; + t.bottom = ri.bottom; + FillRect(hdc, &t, hbr); + } + + if(r_erase->top < ri.top) { + t.left = ri.left; + t.top = r_erase->top; + t.right = ri.right; + t.bottom = ri.top; + FillRect(hdc, &t, hbr); + } + } + } +} + +void +cw_draw_header(HDC hdc, + khui_credwnd_tbl * tbl, + int row, + RECT * r) +{ + int colattr; + HPEN pl, pold; + khui_credwnd_row * cr; + khui_credwnd_outline * o; + int selected = 0; + khm_int32 idf = 0; + + /* each header consists of a couple of widgets and some text */ + /* we need to figure out the background color first */ + + cr = &(tbl->rows[row]); + o = (khui_credwnd_outline *) cr->data; + + colattr = tbl->cols[cr->col].attr_id; + + if (colattr == KCDB_ATTR_ID_NAME) { + khm_handle ident = o->data; + + kcdb_identity_get_flags(ident, &idf); + } + + selected = o->flags & KHUI_CW_O_SELECTED; + + { + HBRUSH hbr; + if(selected) + hbr = tbl->hb_hdr_bg_sel; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_EXPIRED) + hbr = tbl->hb_hdr_bg_exp; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_CRITICAL) + hbr = tbl->hb_hdr_bg_crit; + else if ((o->flags & CW_EXPSTATE_MASK) == CW_EXPSTATE_WARN) + hbr = tbl->hb_hdr_bg_warn; + else if (idf & KCDB_IDENT_FLAG_DEFAULT) + hbr = tbl->hb_hdr_bg_def; + else + hbr = tbl->hb_hdr_bg; + + FillRect(hdc, r, hbr); + } + + pl = CreatePen(PS_SOLID, 0, tbl->cr_hdr_outline); + pold = SelectObject(hdc, pl); + MoveToEx(hdc, r->left, r->bottom - 1, NULL); + LineTo(hdc,r->right,r->bottom - 1); + SelectObject(hdc, pold); + DeleteObject(pl); + + if (o->flags & KHUI_CW_O_STICKY) { + /* khui_ilist_draw_id(tbl->ilist, IDB_TK_NEW_SM, hdc, + r->left, r->bottom - KHUI_SMICON_CY, 0); */ + } else if((tbl->mouse_state & CW_MOUSE_WOUTLINE) && + tbl->mouse_row == row) { + if(o->flags & KHUI_CW_O_EXPAND) { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND_HI, + hdc, r->left, r->bottom - KHUI_SMICON_CY, 0); + } else { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE_HI, + hdc, r->left, r->bottom - KHUI_SMICON_CY, 0); + } + } else { + if(o->flags & KHUI_CW_O_EXPAND) { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_EXPAND, + hdc, r->left, r->bottom - KHUI_SMICON_CY, 0); + } else { + khui_ilist_draw_id(tbl->ilist, IDB_WDG_COLLAPSE, + hdc, r->left, r->bottom - KHUI_SMICON_CY, 0); + } + } + + r->left += KHUI_SMICON_CX * 3 / 2; + + /* try to draw the icon, if there is one */ + if(colattr == KCDB_ATTR_ID_NAME) { + + khui_ilist_draw_id(tbl->ilist, + (((tbl->mouse_state & CW_MOUSE_WSTICKY) && + tbl->mouse_row == row)? + ((idf & KCDB_IDENT_FLAG_STICKY)? + IDB_WDG_STUCK_HI: + IDB_WDG_STICK_HI): + ((idf & KCDB_IDENT_FLAG_STICKY)? + IDB_WDG_STUCK: + IDB_WDG_STICK)), + hdc, + r->left, r->bottom - KHUI_SMICON_CY, + 0); + + r->left += KHUI_SMICON_CX * 3 / 2; + + khui_ilist_draw_id(tbl->ilist, + ((o->flags & KHUI_CW_O_STICKY)? + IDB_ID_DIS_SM: + IDB_ID_SM), + hdc, + r->left, r->bottom - KHUI_SMICON_CY, + 0); + r->left += KHUI_SMICON_CX * 3 / 2 ; + } + + /* ok, now o->header contains the string representation of the + outline value */ + /* for now just write out the value */ + SetTextAlign(hdc, TA_BOTTOM | TA_LEFT); + + if(selected) + SetTextColor(hdc, tbl->cr_hdr_sel); + else + SetTextColor(hdc, tbl->cr_hdr_normal); + + TextOut(hdc, r->left, r->bottom - tbl->vpad, o->header, (int) wcslen(o->header)); + + if (colattr == KCDB_ATTR_ID_NAME && + (idf & KCDB_IDENT_FLAG_DEFAULT)) { + wchar_t defstr[64]; + SIZE size; + + LoadString(khm_hInstance, IDS_CW_DEFAULT, + defstr, ARRAYLENGTH(defstr)); + + GetTextExtentPoint32(hdc, o->header, (int) wcslen(o->header), + &size); + + r->left += size.cx + KHUI_SMICON_CX * 2; + + TextOut(hdc, r->left, r->bottom - tbl->vpad, + defstr, (int) wcslen(defstr)); + } +} + +LRESULT +cw_handle_header_msg(khui_credwnd_tbl * tbl, LPNMHEADER ph) { + RECT r; + HDITEM hi; + + switch(ph->hdr.code) { + /*TODO:Make it track smoother */ + case HDN_BEGINTRACK: + { + if(tbl->cols[ph->iItem].flags & KHUI_CW_COL_FIXED_WIDTH) + return TRUE; + else + return FALSE; + } + + case HDN_TRACK: + case HDN_ENDTRACK: + { + int width; + hi.mask = HDI_ORDER; + Header_GetItem(ph->hdr.hwndFrom, ph->iItem, &hi); + Header_GetItemRect(ph->hdr.hwndFrom, ph->iItem, &r); + width = r.right - r.left; + if(width != tbl->cols[hi.iOrder].width) { + tbl->cols[hi.iOrder].width = width; + cw_update_extents(tbl, TRUE); + InvalidateRect(tbl->hwnd, NULL, FALSE); + } + } + break; + + case NM_CUSTOMDRAW: + { + LPNMCUSTOMDRAW cd; + int idx; + + cd = (LPNMCUSTOMDRAW) ph; + switch(cd->dwDrawStage) + { + case CDDS_PREPAINT: + return CDRF_NOTIFYITEMDRAW; + + case CDDS_ITEMPREPAINT: + return CDRF_NOTIFYPOSTPAINT; + + case CDDS_ITEMPOSTPAINT: + if(cd->lItemlParam == CW_CA_FLAGS) + idx = IDB_WDG_FLAG; + else if(cd->lItemlParam == CW_CA_TYPEICON) + idx = IDB_WDG_CREDTYPE; + else + idx = -1; + + khui_ilist_draw_id(tbl->ilist, idx, cd->hdc, cd->rc.left, cd->rc.top, 0); + return 0; + } + } + break; + } + return 0; +} + +LRESULT +cw_wm_create(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + + kmq_subscribe_hwnd(KMSG_CRED, hwnd); + kmq_subscribe_hwnd(KMSG_KCDB, hwnd); + + /* freed in cw_wm_destroy */ + tbl = PMALLOC(sizeof(*tbl)); + ZeroMemory(tbl, sizeof(*tbl)); + + /* some versions of VC generate portability warnings for + SetWindowLongPtr */ +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, 0, (LONG_PTR) tbl); +#pragma warning(pop) + + tbl->hwnd_header = CreateWindowEx( + 0, + WC_HEADER, + (LPWSTR) NULL, + WS_CHILD | HDS_BUTTONS | + HDS_FULLDRAG | HDS_HORZ | HDS_HOTTRACK +#if (_WIN32_WINNT >= 0x501) + | ((IS_COMMCTL6())?HDS_FLAT:0) +#endif + , + 0,0,0,0,hwnd, (HMENU) 0, khm_hInstance, NULL); + + cw_load_view(tbl, NULL /* default view */, hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, FALSE); + + { + RECT rect; + WINDOWPOS pw; + HDLAYOUT hdl; + + hdl.prc = ▭ + hdl.pwpos = &pw; + GetClientRect(hwnd, &rect); + + Header_Layout(tbl->hwnd_header, &hdl); + + SetWindowPos( + tbl->hwnd_header, + pw.hwndInsertAfter, + pw.x, + pw.y, + pw.cx, + pw.cy, + pw.flags | SWP_SHOWWINDOW); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT +cw_wm_destroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); + kmq_unsubscribe_hwnd(KMSG_KCDB, hwnd); + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + cw_unload_view(tbl); + + PFREE(tbl); + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT +cw_wm_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + HDC hdc; + PAINTSTRUCT ps; + RECT r,rh; + HFONT hf_old; + int row_s, row_e; + int col_s, col_e; + int i,j,x,y,xs,xe,ys,ye; + int flag_col = -1; + int d_x = -1; + int selected = 0; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(!GetUpdateRect(hwnd, &r, FALSE)) + goto _exit; + + hdc = BeginPaint(hwnd, &ps); + if(tbl->hf_normal) + hf_old = SelectFont(hdc, tbl->hf_normal); + SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP); + SetBkMode(hdc, TRANSPARENT); + + GetClientRect(hwnd,&r); + r.top += tbl->header_height; + + if(tbl->n_rows) { + /* remove the notification window if there is one */ + if(tbl->hwnd_notif) { + DestroyWindow(tbl->hwnd_notif); + tbl->hwnd_notif = NULL; + } + /* we compute the visible area in terms of rows and columns */ + /* row_s : first visible row */ + /* col_s : first visible column */ + /* row_e : last visible row */ + /* col_e : last visible column */ + /* ys : top edge of first visible row */ + /* xs : left edge of first visible column */ + + /* We *NEED* all the meta columns to be on the left */ + + row_s = tbl->scr_top / tbl->cell_height; + ys = row_s * tbl->cell_height; + row_e = (tbl->scr_top + (r.bottom - r.top)) / tbl->cell_height + 1; + if(row_e > (int) tbl->n_rows) + row_e = (int) tbl->n_rows; + x = 0; + col_s = -1; + col_e = -1; + xs = 0; + for(i=0; i < (int) tbl->n_cols; i++) { + if(col_e == -1 && x >= tbl->scr_left + (r.right - r.left)) { + col_e = i; + } + if(tbl->cols[i].attr_id == CW_CA_FLAGS) + flag_col = i; + if(d_x == -1 && !cw_is_custom_attr(tbl->cols[i].attr_id)) + d_x = x; + x += tbl->cols[i].width; + if(col_s == -1 && x > tbl->scr_left) { + col_s = i; + xs = tbl->cols[i].x; + } + } + + if(col_e == -1) + col_e = i; + + if(col_s == -1) + col_s = i; + + if(d_x != -1) + d_x += r.left - tbl->scr_left; + + xs += r.left - tbl->scr_left; + ys += r.top - tbl->scr_top; + xe = r.left + tbl->ext_width - tbl->scr_left; + ye = r.top + tbl->ext_height - tbl->scr_top; + + /* now draw */ + y = ys; + for(i=row_s; i < row_e; i++) { + selected = tbl->rows[i].flags & KHUI_CW_ROW_SELECTED; + + if(tbl->cursor_row == i) + SelectFont(hdc, tbl->hf_bold); + + x = xs; + if(tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { + rh.left = xs; + rh.right = xs; + for(j=col_s; j < tbl->rows[i].col; j++) + rh.right += tbl->cols[j].width; + rh.top = y; + rh.bottom = y + tbl->cell_height; + if(rh.right > rh.left) { + cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); + } + rh.left = rh.right; + rh.right = xe; + + cw_draw_header(hdc, tbl, i, &rh); + } + + if(selected) + SetTextColor(hdc, tbl->cr_sel); + else + SetTextColor(hdc, tbl->cr_normal); + + x = xs; + rh.top = y; + rh.bottom = y + tbl->cell_height; + for(j=col_s; j < col_e; x += tbl->cols[j++].width) { + wchar_t buf[256]; + khm_size cbbuf; + + rh.left = x; + rh.right = x + tbl->cols[j].width; + + if(!RectVisible(hdc, &rh)) + continue; + + if(!cw_is_custom_attr(tbl->cols[j].attr_id)) { + if(!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); + + if(j > tbl->rows[i].col) { + cbbuf = sizeof(buf); + if(KHM_FAILED(kcdb_cred_get_attr_string((khm_handle) tbl->rows[i].data, + tbl->cols[j].attr_id, buf, + &cbbuf, KCDB_TS_SHORT))) + continue; + + rh.left += tbl->hpad; + rh.right -= tbl->hpad; + + SetTextAlign(hdc, 0); + DrawText(hdc, buf, (int)((cbbuf / sizeof(wchar_t)) - 1), &rh, + DT_LEFT | DT_VCENTER | DT_NOCLIP | DT_SINGLELINE | DT_END_ELLIPSIS); + //TextOut(hdc, x, y + tbl->vpad, buf, (cbbuf / sizeof(wchar_t)) - 1); + } + } + } else { + cw_erase_rect(hdc, tbl, &r, &rh, (selected)?CW_ER_SEL:CW_ER_BLANK); + + if(tbl->cols[j].attr_id == CW_CA_FLAGS) { + khui_credwnd_outline * o; + khm_int32 flag; + + if(tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { + o = ((khui_credwnd_outline *) tbl->rows[i].data); + if(o->flags & KHUI_CW_O_SHOWFLAG) + flag = o->flags; + else + flag = 0; + } else { + flag = tbl->rows[i].flags; + } + + flag &= CW_EXPSTATE_MASK; + + if(flag == CW_EXPSTATE_WARN) { + khui_ilist_draw_id(tbl->ilist, IDB_FLAG_WARN, hdc, x, y, 0); + } else if(flag == CW_EXPSTATE_CRITICAL) { + khui_ilist_draw_id(tbl->ilist, IDB_FLAG_CRITICAL, hdc, x, y, 0); + } else if(flag == CW_EXPSTATE_EXPIRED) { + khui_ilist_draw_id(tbl->ilist, IDB_FLAG_EXPIRED, hdc, x, y, 0); + } else { + khm_int32 flags; + + if (KHM_SUCCEEDED(kcdb_cred_get_flags((khm_handle) tbl->rows[i].data, &flags)) && + (flags & KCDB_CRED_FLAG_RENEWABLE)) { + khui_ilist_draw_id(tbl->ilist, + IDB_FLAG_RENEW, + hdc, + x, y, 0); + } + } + } + } + } + + if(tbl->cursor_row == i) { + rh.left = tbl->scr_left; + rh.right = tbl->scr_left + tbl->ext_width; + + DrawFocusRect(hdc, &rh); + + SelectFont(hdc, tbl->hf_normal); + } + + y += tbl->cell_height; + + } + + if(xe < r.right) { + rh.left = xe; + rh.right = r.right; + rh.top = r.top; + rh.bottom = r.bottom; + + cw_erase_rect(hdc, tbl, &r, &rh, CW_ER_BLANK); + } + + if(ye < r.bottom) { + rh.left = r.left; + rh.right = (xe < r.right)?xe:r.right; + rh.top = ye; + rh.bottom = r.bottom; + + cw_erase_rect(hdc, tbl, &r, &rh, CW_ER_BLANK); + } + + } else { + wchar_t buf[512]; + cw_erase_rect(hdc, tbl, &r, &r, CW_ER_BLANK); + + if(tbl->hwnd_notif == NULL) { + LoadString(khm_hInstance, IDS_NO_CREDS, buf, sizeof(buf)/sizeof(buf[0])); + tbl->hwnd_notif = khm_create_htwnd( + tbl->hwnd, + buf, + r.left,r.top,r.right - r.left,(r.bottom - r.top) /2, + WS_EX_TRANSPARENT, + WS_VISIBLE); + if(tbl->hwnd_notif) { + SendMessage(tbl->hwnd_notif, WM_SETFONT, (WPARAM) tbl->hf_normal, (LPARAM) FALSE); + ShowWindow(tbl->hwnd_notif, SW_SHOW); + } + } + } + + if(tbl->hf_normal) + SelectFont(hdc, hf_old); + + EndPaint(hwnd,&ps); +_exit: + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT +cw_wm_size(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RECT rect; + khui_credwnd_tbl * tbl; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + cw_update_extents(tbl, TRUE); + + GetClientRect(hwnd, &rect); + + if(tbl->hwnd_notif) { + SetWindowPos( + tbl->hwnd_notif, + tbl->hwnd_header, + rect.left, + tbl->header_height, + rect.right - rect.left, + (rect.bottom - tbl->header_height) / 2, + 0); + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT +cw_wm_notify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + LPNMHDR pnmh; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + pnmh = (LPNMHDR) lParam; + if(pnmh->hwndFrom == tbl->hwnd_header) { + LPNMHEADER ph; + ph = (LPNMHEADER) lParam; + return cw_handle_header_msg(tbl, ph); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static void cw_pp_begin(khui_property_sheet * s); +static void cw_pp_precreate(khui_property_sheet * s); +static void cw_pp_end(khui_property_sheet * s); +static void cw_pp_destroy(khui_property_sheet *ps); + +LRESULT +cw_kmq_wm_dispatch(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + kmq_message * m; + khm_int32 rv = KHM_ERROR_SUCCESS; + khui_credwnd_tbl * tbl; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + kmq_wm_begin(lParam, &m); + if(m->type == KMSG_CRED) { + switch (m->subtype) { + case KMSG_CRED_ROOTDELTA: + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + InvalidateRect(hwnd, NULL, FALSE); + break; + + case KMSG_CRED_PP_BEGIN: + cw_pp_begin((khui_property_sheet *) m->vparam); + break; + + case KMSG_CRED_PP_PRECREATE: + cw_pp_precreate((khui_property_sheet *) m->vparam); + break; + + case KMSG_CRED_PP_END: + cw_pp_end((khui_property_sheet *) m->vparam); + break; + + case KMSG_CRED_PP_DESTROY: + cw_pp_destroy((khui_property_sheet *) m->vparam); + break; + } + } else if (m->type == KMSG_KCDB) { + if (m->subtype == KMSG_KCDB_IDENT && + m->uparam == KCDB_OP_MODIFY) { + + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + InvalidateRect(hwnd, NULL, FALSE); + } + else if (m->subtype == KMSG_KCDB_IDENT && + m->uparam == KCDB_OP_NEW_DEFAULT) { + + InvalidateRect(hwnd, NULL, FALSE); + } + } + return kmq_wm_end(m, rv); +} + +static void +cw_select_outline_level(khui_credwnd_outline * o, + BOOL select) +{ + while(o) { + if (select) + o->flags |= KHUI_CW_O_SELECTED; + else + o->flags &= ~KHUI_CW_O_SELECTED; + cw_select_outline_level(TFIRSTCHILD(o), select); + o = LNEXT(o); + } +} + +static void +cw_select_outline(khui_credwnd_outline * o, + BOOL select) +{ + if (select) + o->flags |= KHUI_CW_O_SELECTED; + else + o->flags &= ~KHUI_CW_O_SELECTED; +} + +static void +cw_unselect_all(khui_credwnd_tbl * tbl) +{ + khm_size i; + + for(i=0; i<tbl->n_rows; i++) { + tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + 0, + KCDB_CRED_FLAG_SELECTED); + } + + cw_select_outline_level(tbl->outline, FALSE); +} + +static void +cw_update_outline_selection_state(khui_credwnd_tbl * tbl, + khui_credwnd_outline * o) +{ + BOOL select = TRUE; + int j; + + for (j = o->start + 1; j < o->start + o->length; j++) { + if (tbl->rows[j].flags & KHUI_CW_ROW_HEADER) { + cw_update_outline_selection_state(tbl, + (khui_credwnd_outline *) + tbl->rows[j].data); + } + + if (!(tbl->rows[j].flags & KHUI_CW_ROW_SELECTED)) { + select = FALSE; + } + + if (tbl->rows[j].flags & KHUI_CW_ROW_HEADER) { + j += ((khui_credwnd_outline *) tbl->rows[j].data)->length - 1; + } + } + + /* special case : the header has been collapsed and we are just + using one row. In this case, the for loop above will do + nothing. */ + + if (o->length == 1) { + select = (tbl->rows[o->start].flags & KHUI_CW_ROW_SELECTED); + } + + cw_select_outline(o, select); + + if (select) { + tbl->rows[o->start].flags |= KHUI_CW_ROW_SELECTED; + } else { + tbl->rows[o->start].flags &= ~KHUI_CW_ROW_SELECTED; + } +} + +static void +cw_update_selection_state(khui_credwnd_tbl * tbl) +{ + khm_size i; + + cw_select_outline_level(tbl->outline, FALSE); + + for (i=0; i < tbl->n_rows; i++) { + if (tbl->rows[i].flags & KHUI_CW_ROW_HEADER) { + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[i].data; + + cw_update_outline_selection_state(tbl, o); + + i += o->length - 1; + } + } +} + +/* Examine the current row and set the UI context */ +static void +cw_set_row_context(khui_credwnd_tbl * tbl, int row) +{ + khui_credwnd_outline * o; + BOOL set_context = TRUE; + + if (row < 0 || row >= (int) tbl->n_rows) { + if (tbl->n_rows > 0) + row = 0; + else { + khui_context_reset(); + return; + } + } + + if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { + + o = (khui_credwnd_outline *) tbl->rows[row].data; + + if (tbl->cols[o->col].attr_id == KCDB_ATTR_ID_NAME) { + if (TPARENT(o) == NULL) { /* selected an identity */ + khui_context_set(KHUI_SCOPE_IDENT, + (khm_handle) o->data, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + tbl->credset); + } else { + khui_credwnd_outline * op; + + op = TPARENT(o); + + if (tbl->cols[op->col].attr_id == KCDB_ATTR_TYPE_NAME && + TPARENT(op) == NULL) { + /* selected a credential type */ + khui_context_set(KHUI_SCOPE_CREDTYPE, + (khm_handle) o->data, + (khm_int32) (DWORD_PTR) op->data, + NULL, + NULL, + 0, + tbl->credset); + } else { + set_context = FALSE; + } + } + } else if (tbl->cols[o->col].attr_id == KCDB_ATTR_TYPE_NAME) { + if (TPARENT(o) == NULL) { + /* selected an entire cred type */ + khui_context_set(KHUI_SCOPE_CREDTYPE, + NULL, + (khm_int32) (DWORD_PTR) o->data, + NULL, + NULL, + 0, + tbl->credset); + } else { + khui_credwnd_outline * op; + + op = TPARENT(o); + if (tbl->cols[op->col].attr_id == KCDB_ATTR_ID_NAME && + TPARENT(op) == NULL) { + /* credtype under an identity */ + khui_context_set(KHUI_SCOPE_CREDTYPE, + (khm_handle) op->data, + (khm_int32) (DWORD_PTR) o->data, + NULL, + NULL, + 0, + tbl->credset); + } else { + set_context = FALSE; + } + } + } else { + set_context = FALSE; + } + + if (!set_context) { + /* woohoo. cred group. yay. */ + khui_header headers[KHUI_MAX_HEADERS]; + khm_size n_headers = 0; + + do { + headers[n_headers].attr_id = + o->attr_id; + if (tbl->cols[o->col].attr_id == + KCDB_ATTR_ID_NAME) { + headers[n_headers].data = &(o->data); + headers[n_headers].cb_data = sizeof(khm_handle); + } else if (tbl->cols[o->col].attr_id == + KCDB_ATTR_TYPE_NAME) { + headers[n_headers].data = &(o->data); + headers[n_headers].cb_data = sizeof(khm_int32); + } else { + headers[n_headers].data = o->data; + headers[n_headers].cb_data = o->cb_data; + } + + n_headers++; + + o = TPARENT(o); + } while(o); + + khui_context_set(KHUI_SCOPE_GROUP, + NULL, + KCDB_CREDTYPE_INVALID, + NULL, + headers, + n_headers, + tbl->credset); + } + + } else { + khm_handle cred; + + cred = (khm_handle) tbl->rows[row].data; + + khui_context_set(KHUI_SCOPE_CRED, + NULL, + KCDB_CREDTYPE_INVALID, + cred, + NULL, + 0, + tbl->credset); + } +} + +static void +cw_select_all(khui_credwnd_tbl * tbl) +{ + khm_size i; + + for(i=0; i<tbl->n_rows; i++) { + tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + KCDB_CRED_FLAG_SELECTED, + KCDB_CRED_FLAG_SELECTED); + } + + cw_select_outline_level(tbl->outline, TRUE); + + cw_update_selection_state(tbl); + + cw_set_row_context(tbl, tbl->cursor_row); + + InvalidateRect(tbl->hwnd, NULL, FALSE); +} + +static void +cw_select_row(khui_credwnd_tbl * tbl, int row, WPARAM wParam) +{ + int i; + BOOL toggle; + BOOL extend; + int group_begin; + int group_end; + + if (wParam & MK_CONTROL) { + toggle = TRUE; + extend = FALSE; + } else if (wParam & MK_SHIFT) { + toggle = FALSE; + extend = TRUE; + } else { + toggle = FALSE; + extend = FALSE; + } + + if (row < 0 || row >= (int) tbl->n_rows) + return; + + if (tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[row].data; + + group_begin = o->start; + group_end = o->start + o->length - 1; + } else { + group_begin = row; + group_end = row; + } + + if (!toggle && !extend) { + /* selecting a single row */ + cw_unselect_all(tbl); + + tbl->cursor_row = row; + tbl->anchor_row = row; + + for (i = group_begin; i <= group_end; i++) { + tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + KCDB_CRED_FLAG_SELECTED, + KCDB_CRED_FLAG_SELECTED); + } + } + } else if (toggle) { + BOOL select; + + tbl->cursor_row = row; + tbl->anchor_row = row; + + select = !(tbl->rows[row].flags & KHUI_CW_ROW_SELECTED); + + for (i = group_begin; i <= group_end; i++) { + if (select) + tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; + else + tbl->rows[i].flags &= ~KHUI_CW_ROW_SELECTED; + + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + (select)?KCDB_CRED_FLAG_SELECTED:0, + KCDB_CRED_FLAG_SELECTED); + } + + } + } else if (extend) { + int range_begin; + int range_end; + + cw_unselect_all(tbl); + + range_begin = min(row, tbl->anchor_row); + range_end = max(row, tbl->anchor_row); + + for (i = range_begin; i <= range_end; i++) { + tbl->rows[i].flags |= KHUI_CW_ROW_SELECTED; + + if (!(tbl->rows[i].flags & KHUI_CW_ROW_HEADER)) { + kcdb_cred_set_flags((khm_handle) tbl->rows[i].data, + KCDB_CRED_FLAG_SELECTED, + KCDB_CRED_FLAG_SELECTED); + } + } + + tbl->cursor_row = row; + } + + cw_update_selection_state(tbl); + + cw_set_row_context(tbl, tbl->cursor_row); + + InvalidateRect(tbl->hwnd, NULL, FALSE); +} + +static void +cw_toggle_outline_state(khui_credwnd_tbl * tbl, + khui_credwnd_outline * o) { + + int old_range_begin; + int old_range_end; + int new_range_begin; + int new_range_end; + + old_range_begin = o->start; + old_range_end = o->start + o->length - 1; + + o->flags ^= KHUI_CW_O_EXPAND; + + cw_update_outline(tbl); + cw_update_extents(tbl, TRUE); + + new_range_begin = o->start; + new_range_end = o->start + o->length - 1; + + if (tbl->cursor_row > old_range_end) { + tbl->cursor_row -= old_range_end - new_range_end; + } else if (tbl->cursor_row >= old_range_begin && + tbl->cursor_row <= old_range_end) { + tbl->cursor_row = new_range_begin; + } + + if (tbl->anchor_row > old_range_end) { + tbl->anchor_row -= old_range_end - new_range_end; + } else if (tbl->anchor_row >= old_range_begin && + tbl->anchor_row <= old_range_end) { + tbl->anchor_row = new_range_begin; + } + + InvalidateRect(tbl->hwnd, NULL, TRUE); + +} + +LRESULT cw_properties(HWND hwnd); + +LRESULT +cw_wm_mouse(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + int x,y; + RECT r; + int row; + int col; + int i; + int nm_state,nm_row,nm_col; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + /* we are basically trying to capture events where the mouse is + hovering over one of the 'hotspots'. There are two kinds of + hotspots one is the little widget thinggy that you click on to + expand or collapse an outline. The other is a text cell that + is partially concealed. */ + + x = GET_X_LPARAM(lParam); + y = GET_Y_LPARAM(lParam); + x += tbl->scr_left; + y += tbl->scr_top - tbl->header_height; + + row = y / tbl->cell_height; + col = -1; + nm_state = CW_MOUSE_NONE; + nm_row = nm_col = -1; + + for(i=0; i < (int) tbl->n_cols; i++) { + if(x >= tbl->cols[i].x && + x < tbl->cols[i].x + tbl->cols[i].width) { + col = i; + break; + } + } + + if(wParam & MK_LBUTTON) + nm_state = CW_MOUSE_LDOWN; + + if(row >= 0 && row < (int) tbl->n_rows) { + nm_state |= CW_MOUSE_ROW; + nm_row = row; + nm_col = col; + if(tbl->rows[row].flags & KHUI_CW_ROW_HEADER) { + /* are we on a widget then? */ + x -= tbl->cols[tbl->rows[row].col].x; + if(x >= 0 && x < KHUI_SMICON_CX) /* hit */ { + nm_state |= CW_MOUSE_WOUTLINE | CW_MOUSE_WIDGET; + } else if (tbl->cols[tbl->rows[row].col].attr_id == + KCDB_ATTR_ID_NAME && + col == tbl->rows[row].col && + x >= KHUI_SMICON_CX * 3 / 2 && + x < KHUI_SMICON_CX * 5 / 2){ + nm_state |= CW_MOUSE_WSTICKY | CW_MOUSE_WIDGET; + } else if (tbl->cols[tbl->rows[row].col].attr_id == + KCDB_ATTR_ID_NAME && + col == tbl->rows[row].col && + x >= KHUI_SMICON_CX * 3 && + x < KHUI_SMICON_CX * 4) { + nm_state |= CW_MOUSE_WICON | CW_MOUSE_WIDGET; + } + } + } + + /* did the user drag the cursor off the current row? */ + if((tbl->mouse_state & CW_MOUSE_LDOWN) && + (nm_row != tbl->mouse_row)) { + nm_state &= ~CW_MOUSE_WMASK; + } + + if(!(nm_state & CW_MOUSE_LDOWN) && + (tbl->mouse_state & CW_MOUSE_LDOWN) && + tbl->mouse_row == nm_row) { + + if((nm_state & CW_MOUSE_WOUTLINE) && + (tbl->mouse_state & CW_MOUSE_WOUTLINE)) { + /* click on an outline widget */ + khui_credwnd_outline * o; + + o = (khui_credwnd_outline *) tbl->rows[nm_row].data; + tbl->mouse_state = CW_MOUSE_WIDGET | CW_MOUSE_WOUTLINE; + + cw_toggle_outline_state(tbl, o); + + return 0; + } else if ((nm_state & CW_MOUSE_WSTICKY) && + (tbl->mouse_state & CW_MOUSE_WSTICKY)) { + + khui_credwnd_outline * o; + khm_handle ident; + khm_int32 idf = 0; + + o = tbl->rows[nm_row].data; + ident = o->data; + + kcdb_identity_get_flags(ident, &idf); + idf &= KCDB_IDENT_FLAG_STICKY; + kcdb_identity_set_flags(ident, (idf ^ KCDB_IDENT_FLAG_STICKY), + KCDB_IDENT_FLAG_STICKY); + + tbl->mouse_state = CW_MOUSE_WIDGET | CW_MOUSE_WSTICKY; + + return 0; + } else if ((nm_state & CW_MOUSE_WICON) && + (tbl->mouse_state & CW_MOUSE_WICON)) { + /* click on an row icon */ + cw_select_row(tbl, nm_row, wParam); + cw_properties(hwnd); + } else { + /* click on a row */ + cw_select_row(tbl, nm_row, wParam); + } + } + + /* ok, now if we are changing state, we need to invalidate a few + regions */ + if (((tbl->mouse_state ^ nm_state) & (CW_MOUSE_WIDGET | + CW_MOUSE_WOUTLINE | + CW_MOUSE_WSTICKY)) || + tbl->mouse_row != nm_row) { + + if(tbl->mouse_state & CW_MOUSE_WOUTLINE) { + r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left; + r.top = tbl->mouse_row * tbl->cell_height + + tbl->header_height - tbl->scr_top; + r.right = r.left + KHUI_SMICON_CX; + r.bottom = r.top + tbl->cell_height; + InvalidateRect(tbl->hwnd, &r, TRUE); + } + if(tbl->mouse_state & CW_MOUSE_WSTICKY) { + r.left = KHUI_SMICON_CX * 3 / 2 + + tbl->cols[tbl->mouse_col].x - tbl->scr_left; + r.top = tbl->mouse_row * tbl->cell_height + + tbl->header_height - tbl->scr_top; + r.right = r.left + KHUI_SMICON_CX; + r.bottom = r.top + tbl->cell_height; + InvalidateRect(tbl->hwnd, &r, TRUE); + } + + if ((tbl->mouse_state & nm_state) & CW_MOUSE_LDOWN) { + if (tbl->mouse_row == nm_row) + tbl->mouse_col = nm_col; + } else { + tbl->mouse_col = nm_col; + tbl->mouse_row = nm_row; + } + tbl->mouse_state = nm_state; + + /* same code block as above */ + if(tbl->mouse_state & CW_MOUSE_WOUTLINE) { + r.left = tbl->cols[tbl->mouse_col].x - tbl->scr_left; + r.top = tbl->mouse_row * tbl->cell_height + + tbl->header_height - tbl->scr_top; + r.right = r.left + KHUI_SMICON_CX; + r.bottom = r.top + tbl->cell_height; + InvalidateRect(tbl->hwnd, &r, TRUE); + } + if(tbl->mouse_state & CW_MOUSE_WSTICKY) { + r.left = KHUI_SMICON_CX * 3 / 2 + + tbl->cols[tbl->mouse_col].x - tbl->scr_left; + r.top = tbl->mouse_row * tbl->cell_height + + tbl->header_height - tbl->scr_top; + r.right = r.left + KHUI_SMICON_CX; + r.bottom = r.top + tbl->cell_height; + InvalidateRect(tbl->hwnd, &r, TRUE); + } + } else if(tbl->mouse_state != nm_state) { + + if ((tbl->mouse_state & nm_state) & CW_MOUSE_LDOWN) { + if (tbl->mouse_row == nm_row) { + tbl->mouse_col = nm_col; + tbl->mouse_state = nm_state; + } + } else { + tbl->mouse_col = nm_col; + tbl->mouse_row = nm_row; + tbl->mouse_state = nm_state; + } + } + + /* if it was a double click, also show the property + window */ + if (uMsg == WM_LBUTTONDBLCLK) { + cw_properties(hwnd); + } + + return 0; +} + +LRESULT +cw_wm_hscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + SCROLLINFO si; + RECT cr; + RECT lr; + RECT sr; + int dx; + int newpos; + + tbl = (khui_credwnd_tbl *) (LONG_PTR) GetWindowLongPtr(hwnd, 0); + GetClientRect(hwnd, &cr); + dx = tbl->scr_left; + + switch(LOWORD(wParam)) { + case SB_LEFT: + newpos = 0; + break; + + case SB_RIGHT: + newpos = tbl->ext_width; + break; + + case SB_LINELEFT: + newpos = tbl->scr_left - (tbl->ext_width / 12); + break; + + case SB_LINERIGHT: + newpos = tbl->scr_left + (tbl->ext_width / 12); + break; + + case SB_PAGELEFT: + newpos = tbl->scr_left - (cr.right - cr.left); + break; + + case SB_PAGERIGHT: + newpos = tbl->scr_left + (cr.right - cr.left); + break; + + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + GetScrollInfo(hwnd, SB_HORZ, &si); + + newpos = si.nTrackPos; + break; + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + + //cr.top += tbl->header_height; + tbl->scr_left = newpos; + cw_update_extents(tbl, TRUE); + + dx -= tbl->scr_left; + + /* exclude the watermark */ + lr.bottom = cr.bottom; + lr.right = cr.right; + lr.top = max(cr.bottom - tbl->kbm_logo_shade.cy, cr.top); + lr.left = max(cr.right - tbl->kbm_logo_shade.cx, cr.left); + + if(cr.top < lr.top && cr.left < cr.right) { + sr.left = cr.left; + sr.right = cr.right; + sr.top = cr.top; + sr.bottom = lr.top; + ScrollWindowEx( + hwnd, + dx, + 0, + &sr, + &sr, + NULL, + NULL, + SW_INVALIDATE | SW_SCROLLCHILDREN); + } + + if(cr.left < lr.left && lr.top < lr.bottom) { + sr.left = cr.left; + sr.right = lr.left; + sr.top = lr.top; + sr.bottom = lr.bottom; + ScrollWindowEx( + hwnd, + dx, + 0, + &sr, + &sr, + NULL, + NULL, + SW_INVALIDATE | SW_SCROLLCHILDREN); + } + + if(lr.top < lr.bottom && lr.left < lr.right) { + InvalidateRect(hwnd, &lr, FALSE); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static void +cw_vscroll_to_pos(HWND hwnd, khui_credwnd_tbl * tbl, int newpos) { + RECT cr; + RECT sr; + RECT lr; + int dy; + + GetClientRect(hwnd, &cr); + cr.top += tbl->header_height; + dy = tbl->scr_top; + + tbl->scr_top = newpos; + cw_update_extents(tbl, TRUE); + + dy -= tbl->scr_top; + + /* exclude watermark */ + lr.bottom = cr.bottom; + lr.right = cr.right; + lr.top = max(cr.bottom - tbl->kbm_logo_shade.cy, cr.top); + lr.left = max(cr.right - tbl->kbm_logo_shade.cx, cr.left); + + if(cr.left < lr.left && cr.top < cr.bottom) { + sr.left = cr.left; + sr.right = lr.left; + sr.top = cr.top; + sr.bottom = cr.bottom; + ScrollWindowEx( + hwnd, + 0, + dy, + &sr, + &sr, + NULL, + NULL, + SW_INVALIDATE); + } + + if(lr.left < lr.right && cr.top < lr.top) { + sr.left = lr.left; + sr.right = lr.right; + sr.top = cr.top; + sr.bottom = lr.top; + ScrollWindowEx( + hwnd, + 0, + dy, + &sr, + &sr, + NULL, + NULL, + SW_INVALIDATE); + } + + if(lr.top < lr.bottom && lr.left < lr.right) { + InvalidateRect(hwnd, &lr, FALSE); + } +} + +LRESULT +cw_wm_vscroll(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + SCROLLINFO si; + int newpos; + RECT cr; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + GetClientRect(hwnd, &cr); + cr.top += tbl->header_height; + + switch(LOWORD(wParam)) { + case SB_LEFT: + newpos = 0; + break; + + case SB_BOTTOM: + newpos = tbl->ext_height; + break; + + case SB_LINEUP: + newpos = tbl->scr_top - (tbl->ext_height / 12); + break; + + case SB_LINEDOWN: + newpos = tbl->scr_top + (tbl->ext_height / 12); + break; + + case SB_PAGEUP: + newpos = tbl->scr_top - (cr.bottom - cr.top); + break; + + case SB_PAGEDOWN: + newpos = tbl->scr_top + (cr.bottom - cr.top); + break; + + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + ZeroMemory(&si, sizeof(si)); + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + GetScrollInfo(hwnd, SB_VERT, &si); + + newpos = si.nTrackPos; + break; + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + + cw_vscroll_to_pos(hwnd, tbl, newpos); + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static void +cw_ensure_row_visible(HWND hwnd, khui_credwnd_tbl * tbl, int row) { + RECT r; + int newpos; + + if (row < 0) + row = 0; + else if (row >= (int) tbl->n_rows) + row = (int) tbl->n_rows - 1; + + GetClientRect(hwnd, &r); + r.top += tbl->header_height; + + if (row * tbl->cell_height < tbl->scr_top) { + newpos = row * tbl->cell_height; + } else if ((row + 1) * tbl->cell_height + > tbl->scr_top + (r.bottom - r.top)) { + newpos = ((row + 1) * tbl->cell_height) - (r.bottom - r.top); + } else + return; + + cw_vscroll_to_pos(hwnd, tbl, newpos); +} + +static INT_PTR CALLBACK +cw_pp_ident_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_property_sheet * s; + + switch(uMsg) { + case WM_INITDIALOG: + { + PROPSHEETPAGE * p; + khm_handle ident; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size t; + khm_int32 i; + + p = (PROPSHEETPAGE *) lParam; + s = (khui_property_sheet *) p->lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); +#pragma warning(pop) + + ident = s->identity; + + t = sizeof(idname); + kcdb_identity_get_name(ident, idname, &t); + SetDlgItemText(hwnd, IDC_PP_IDNAME, idname); + + kcdb_identity_get_flags(ident, &i); + + CheckDlgButton(hwnd, IDC_PP_IDDEF, + ((i & KCDB_IDENT_FLAG_DEFAULT)?BST_CHECKED: + BST_UNCHECKED)); + + /* if it's default, you can't change it further */ + if (i & KCDB_IDENT_FLAG_DEFAULT) { + EnableWindow(GetDlgItem(hwnd, IDC_PP_IDDEF), FALSE); + } + + CheckDlgButton(hwnd, IDC_PP_IDSEARCH, + ((i & KCDB_IDENT_FLAG_SEARCHABLE)?BST_CHECKED: + BST_UNCHECKED)); + + CheckDlgButton(hwnd, IDC_PP_STICKY, + ((i & KCDB_IDENT_FLAG_STICKY)?BST_CHECKED: + BST_UNCHECKED)); + + khui_property_wnd_set_record(GetDlgItem(hwnd, IDC_PP_PROPLIST), + ident); + } + return TRUE; + + case WM_COMMAND: + s = (khui_property_sheet *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + switch(wParam) { + case MAKEWPARAM(IDC_PP_IDDEF, BN_CLICKED): + /* fallthrough */ + case MAKEWPARAM(IDC_PP_STICKY, BN_CLICKED): + + if (s->status != KHUI_PS_STATUS_NONE) + PropSheet_Changed(s->hwnd, hwnd); + return TRUE; + + case MAKEWPARAM(IDC_PP_CONFIG, BN_CLICKED): + { + khui_config_node cfg_id = NULL; + khui_config_node cfg_ids = NULL; + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + khm_size cb; + khm_int32 rv; + + khm_refresh_config(); + + rv = khui_cfg_open(NULL, + L"KhmIdentities", + &cfg_ids); + + if (KHM_FAILED(rv)) + return TRUE; + + cb = sizeof(idname); + if (KHM_SUCCEEDED(kcdb_identity_get_name(s->identity, + idname, + &cb))) { + rv = khui_cfg_open(cfg_ids, + idname, + &cfg_id); + } + + if (cfg_id) + khm_show_config_pane(cfg_id); + else + khm_show_config_pane(cfg_ids); + + if (cfg_ids) + khui_cfg_release(cfg_ids); + if (cfg_id) + khui_cfg_release(cfg_id); + } + return TRUE; + } + return FALSE; + + case WM_NOTIFY: + { + LPPSHNOTIFY lpp; + khm_int32 flags; + + lpp = (LPPSHNOTIFY) lParam; + s = (khui_property_sheet *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + switch(lpp->hdr.code) { + case PSN_APPLY: + flags = 0; + if (IsDlgButtonChecked(hwnd, IDC_PP_STICKY) == BST_CHECKED) + flags |= KCDB_IDENT_FLAG_STICKY; + if (IsDlgButtonChecked(hwnd, IDC_PP_IDDEF) == BST_CHECKED) + flags |= KCDB_IDENT_FLAG_DEFAULT; + + kcdb_identity_set_flags(s->identity, flags, + KCDB_IDENT_FLAG_STICKY | + KCDB_IDENT_FLAG_DEFAULT); + return TRUE; + + case PSN_RESET: + kcdb_identity_get_flags(s->identity, &flags); + + CheckDlgButton(hwnd, + IDC_PP_IDDEF, + ((flags & KCDB_IDENT_FLAG_DEFAULT)?BST_CHECKED: + BST_UNCHECKED)); + + /* if it's default, you can't change it further */ + if (flags & KCDB_IDENT_FLAG_DEFAULT) { + EnableWindow(GetDlgItem(hwnd, IDC_PP_IDDEF), FALSE); + } + + CheckDlgButton(hwnd, IDC_PP_IDSEARCH, + ((flags & KCDB_IDENT_FLAG_SEARCHABLE)?BST_CHECKED:BST_UNCHECKED)); + + CheckDlgButton(hwnd, IDC_PP_STICKY, + ((flags & KCDB_IDENT_FLAG_STICKY)?BST_CHECKED:BST_UNCHECKED)); + return TRUE; + } + } + break; + } + return FALSE; +} + +static INT_PTR CALLBACK +cw_pp_cred_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_INITDIALOG: + { + khui_property_sheet * s; + PROPSHEETPAGE * p; + khm_handle cred; + + p = (PROPSHEETPAGE *) lParam; + s = (khui_property_sheet *) p->lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR) s); +#pragma warning(pop) + + cred = s->cred; + + khui_property_wnd_set_record( + GetDlgItem(hwnd, IDC_PP_CPROPLIST), + cred); + } + return TRUE; + } + return FALSE; +} + +static void +cw_pp_begin(khui_property_sheet * s) +{ + PROPSHEETPAGE *p; + + if(s->identity) { + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = khm_hInstance; + p->pszTemplate = MAKEINTRESOURCE(IDD_PP_IDENT); + p->pfnDlgProc = cw_pp_ident_proc; + p->lParam = (LPARAM) s; + + khui_ps_add_page(s, KHUI_PPCT_IDENTITY, 129, p, NULL); + } + + if(s->cred) { + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->dwSize = sizeof(*p); + p->dwFlags = 0; + p->hInstance = khm_hInstance; + p->pszTemplate = MAKEINTRESOURCE(IDD_PP_CRED); + p->pfnDlgProc = cw_pp_cred_proc; + p->lParam = (LPARAM) s; + + khui_ps_add_page(s, KHUI_PPCT_CREDENTIAL, 128, p, NULL); + } +} + +static void +cw_pp_precreate(khui_property_sheet * s) +{ + khui_ps_show_sheet(khm_hwnd_main, s); + + khm_add_property_sheet(s); +} + +static void +cw_pp_end(khui_property_sheet * s) +{ + khui_property_page * p = NULL; + + khui_ps_find_page(s, KHUI_PPCT_IDENTITY, &p); + if(p) { + PFREE(p->p_page); + p->p_page = NULL; + } + + p = NULL; + + khui_ps_find_page(s, KHUI_PPCT_CREDENTIAL, &p); + if(p) { + PFREE(p->p_page); + p->p_page = NULL; + } +} + +static void +cw_pp_destroy(khui_property_sheet *ps) +{ + if(ps->ctx.scope == KHUI_SCOPE_CRED) { + if(ps->header.pszCaption) + PFREE((LPWSTR) ps->header.pszCaption); + } + + khui_context_release(&ps->ctx); + + khui_ps_destroy_sheet(ps); + + /* this is pretty weird because ps gets freed when + khui_ps_destroy_sheet() is called. However, since destroying + ps involves sending a WM_DESTROY message to the property sheet, + we still need to keep it on the property sheet chain (or else + the messages will not be delivered). This is only safe because + we are not relinquishing the thread in-between destroying ps + and removing it from the chain. */ + + /* TODO: fix this */ + khm_del_property_sheet(ps); +} + +LRESULT +cw_properties(HWND hwnd) +{ + /* show a property sheet of some sort */ + khui_action_context ctx; + khui_property_sheet * ps; + khui_credwnd_tbl * tbl; + + khui_context_get(&ctx); + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(ctx.scope == KHUI_SCOPE_NONE) { + khui_context_release(&ctx); + return FALSE; + + /* While it seems like a good idea, doing this is not */ +#if 0 + /* try to establish a context based on the current cursor + position */ + if(tbl->cursor_row >= 0 && tbl->cursor_row < (int) tbl->n_rows) { + if(tbl->rows[tbl->cursor_row].flags & KHUI_CW_ROW_HEADER) { + if(tbl->cols[tbl->rows[tbl->cursor_row].col].attr_id == KCDB_ATTR_ID_NAME) { + /* identity context */ + ctx.ctx = KHUI_SCOPE_IDENT; + ctx.identity = (khm_handle) + ((khui_credwnd_outline *) tbl->rows[tbl->cursor_row].data)->data; + } else if(tbl->cols[tbl->rows[tbl->cursor_row].col].attr_id == KCDB_ATTR_TYPE_NAME) { + ctx.ctx = KHUI_SCOPE_CREDTYPE; + ctx.cred_type = (khm_int32) (DWORD_PTR) + ((khui_credwnd_outline *) tbl->rows[tbl->cursor_row].data)->data; + } else { + ctx.ctx = KHUI_SCOPE_GROUP; + //ctx.parm = (khm_lparm) tbl->rows[tbl->cursor_row].data; + /* TODO: Figure out method of establishing a credgroup */ + } + } else { + /* a credential context */ + ctx.ctx = KHUI_SCOPE_CRED; + ctx.cred = (khm_handle) tbl->rows[tbl->cursor_row].data; + } + } +#endif + } + + /* if still no context, then we can't show a property sheet */ + if(ctx.scope == KHUI_SCOPE_NONE) { + khui_context_release(&ctx); + return FALSE; + } + + khui_ps_create_sheet(&ps); + + if(ctx.scope == KHUI_SCOPE_IDENT) { + khm_handle ident; + khm_size t; + + ident = ctx.identity; + + ps->header.hInstance = khm_hInstance; + ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); + + kcdb_identity_get_name(ident, NULL, &t); + + if(t > 0) { + ps->header.pszCaption = PMALLOC(t); + kcdb_identity_get_name(ident, + (wchar_t *) ps->header.pszCaption, &t); + } else { + ps->header.pszCaption = NULL; + } + + ps->ctx = ctx; + ps->identity = ident; + ps->credtype = KCDB_CREDTYPE_INVALID; + + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); + + } else if(ctx.scope == KHUI_SCOPE_CREDTYPE) { + khm_size t = 0; + khm_int32 cred_type; + + cred_type = ctx.cred_type; + + ps->header.hInstance = khm_hInstance; + ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); + + ps->ctx = ctx; + ps->credtype = cred_type; + + if(ctx.identity) { + ps->identity = ctx.identity; + /* also, if there is an associated identity, we assume that + the properties are for the specified credentials type + specific to the identity. Hence we change the title to + something else */ + kcdb_identity_get_name(ctx.identity, NULL, &t); + if (t > 0) { + ps->header.pszCaption = PMALLOC(t); + kcdb_identity_get_name(ctx.identity, (wchar_t *) ps->header.pszCaption, &t); + } else { + ps->header.pszCaption = NULL; + } + } else { + kcdb_credtype_describe(cred_type, NULL, &t, KCDB_TS_LONG); + if(t > 0) { + ps->header.pszCaption = PMALLOC(t); + kcdb_credtype_describe(cred_type, (wchar_t *) ps->header.pszCaption, &t, KCDB_TS_LONG); + } else { + ps->header.pszCaption = NULL; + } + } + + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); + } else if(ctx.scope == KHUI_SCOPE_CRED) { + khm_handle cred; + khm_size t; + + cred = ctx.cred; + + ps->header.hInstance = khm_hInstance; + ps->header.pszIcon = MAKEINTRESOURCE(IDI_MAIN_APP); + ps->ctx = ctx; + + kcdb_cred_get_name(cred, NULL, &t); + ps->header.pszCaption = PMALLOC(t); + kcdb_cred_get_name(cred, (LPWSTR) ps->header.pszCaption, &t); + + kcdb_cred_get_identity(cred, &ps->identity); + kcdb_cred_get_type(cred, &ps->credtype); + ps->cred = cred; + + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_BEGIN, 0, (void *) ps); + } else { + khui_context_release(&ctx); + khui_ps_destroy_sheet(ps); + } + + /* by the way, if we are actually opening a property sheet, we + leave ctx held (which is now copied to ps->ctx). it will be + released when the property sheet is destroyed */ + + return TRUE; +} + +LRESULT +cw_wm_command(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + khui_credwnd_tbl * tbl; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(HIWORD(wParam) == BN_CLICKED && + LOWORD(wParam) == KHUI_HTWND_CTLID) { + + wchar_t wid[256]; + /* a hyperlink was activated */ + khui_htwnd_link * l; + l = (khui_htwnd_link *) lParam; + wcsncpy(wid, l->id, l->id_len); + wid[l->id_len] = 0; + + if(!wcscmp(wid, L"NewCreds")) { + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_NEW_CRED,0), 0); + } + return TRUE; + } + + switch(LOWORD(wParam)) + { + case KHUI_PACTION_ENTER: + /* enter key is a synonym for the default action, on the + context, which is to lauch a property sheet */ + /* fallthrough */ + case KHUI_ACTION_PROPERTIES: + { + return cw_properties(hwnd); + } + break; + + case KHUI_ACTION_LAYOUT_ID: + { + cw_unload_view(tbl); + + cw_load_view(tbl, L"ByIdentity", hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, FALSE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), KHUI_ACTION_LAYOUT_ID); + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); + } + break; + + case KHUI_ACTION_LAYOUT_LOC: + { + cw_unload_view(tbl); + + cw_load_view(tbl, L"ByLocation", hwnd); + cw_insert_header_cols(tbl); + + cw_update_creds(tbl); + cw_update_outline(tbl); + cw_update_extents(tbl, FALSE); + + InvalidateRect(tbl->hwnd, NULL, TRUE); + + khui_check_radio_action(khui_find_menu(KHUI_MENU_LAYOUT), + KHUI_ACTION_LAYOUT_LOC); + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); + } + break; + + case KHUI_PACTION_UP: + case KHUI_PACTION_UP_EXTEND: + case KHUI_PACTION_UP_TOGGLE: + { /* cursor up */ + khm_int32 new_row; + WPARAM wp; + + new_row = tbl->cursor_row - 1; + + /* checking both bounds. we make no assumption about the + value of cursor_row before this message */ + if(new_row < 0) + new_row = 0; + if(new_row >= (int) tbl->n_rows) + new_row = (int) tbl->n_rows - 1; + + if (LOWORD(wParam) == KHUI_PACTION_UP) + wp = 0; + else if (LOWORD(wParam) == KHUI_PACTION_UP_EXTEND) + wp = MK_SHIFT; + else if (LOWORD(wParam) == KHUI_PACTION_UP_TOGGLE) + wp = 0; //MK_CONTROL; +#ifdef DEBUG + else + assert(FALSE); +#endif + + cw_select_row(tbl, new_row, wp); + cw_ensure_row_visible(hwnd, tbl, new_row); + } + break; + + case KHUI_PACTION_DOWN: + case KHUI_PACTION_DOWN_EXTEND: + case KHUI_PACTION_DOWN_TOGGLE: + { /* cursor down */ + khm_int32 new_row; + WPARAM wp; + + new_row = tbl->cursor_row + 1; + + /* checking both bounds. we make no assumption about the + value of cursor_row before this message */ + if(new_row < 0) + new_row = 0; + if(new_row >= (int) tbl->n_rows) + new_row = (int) tbl->n_rows - 1; + + if (LOWORD(wParam) == KHUI_PACTION_DOWN) + wp = 0; + else if (LOWORD(wParam) == KHUI_PACTION_DOWN_EXTEND) + wp = MK_SHIFT; + else if (LOWORD(wParam) == KHUI_PACTION_DOWN_TOGGLE) + wp = 0; //MK_CONTROL; +#ifdef DEBUG + else + assert(FALSE); +#endif + cw_select_row(tbl, new_row, wp); + cw_ensure_row_visible(hwnd, tbl, new_row); + } + break; + + case KHUI_PACTION_SELALL: + { + cw_select_all(tbl); + } + break; + + case KHUI_PACTION_LEFT: + { /* collapse and up*/ + khui_credwnd_outline * o; + int r; + + if(tbl->cursor_row < 0 || tbl->cursor_row >= (int) tbl->n_rows) { + cw_select_row(tbl, 0, 0); + break; + } + + for(r = tbl->cursor_row; + (r >= 0 && !(tbl->rows[r].flags & KHUI_CW_ROW_HEADER)); + r--); + + if(r < 0) + break; + + /* If we were not on a header, we collapse the innermost + outline. Otherwise, we collpase up to the parent + outline level */ + + if(r != tbl->cursor_row) { + o = (khui_credwnd_outline *) tbl->rows[r].data; + + cw_toggle_outline_state(tbl, o); + } else { + o = (khui_credwnd_outline *) tbl->rows[r].data; + + if(o->flags & KHUI_CW_O_EXPAND) { + cw_toggle_outline_state(tbl, o); + } else { + o = TPARENT(o); + if(o) { + cw_toggle_outline_state(tbl, o); + r = o->start; + } else if(r > 0) + r--; + } + } + + cw_select_row(tbl, r, 0); + } + break; + + case KHUI_PACTION_RIGHT: + { /* expand and down*/ + khui_credwnd_outline * o; + int r; + + if(tbl->cursor_row < 0 || + tbl->cursor_row >= (int) tbl->n_rows) { + cw_select_row(tbl, 0, 0); + break; + } + + r = tbl->cursor_row; + + if(tbl->rows[r].flags & KHUI_CW_ROW_HEADER) { + o = (khui_credwnd_outline *) tbl->rows[r].data; + if(!(o->flags & KHUI_CW_O_EXPAND)) { + cw_toggle_outline_state(tbl, o); + } + } + + r++; + + cw_select_row(tbl, r, 0); + } + break; + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT +cw_wm_contextmenu(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + RECT r; + int x,y; + int row; + khui_credwnd_tbl * tbl; + + tbl = (khui_credwnd_tbl *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + GetWindowRect(hwnd, &r); + + x = GET_X_LPARAM(lParam); + y = GET_Y_LPARAM(lParam); + + x += tbl->scr_left - r.left; + y += tbl->scr_top - tbl->header_height - r.top; + + row = y / tbl->cell_height; + + if(row < 0 || row >= (int) tbl->n_rows) + return FALSE; + + cw_set_row_context(tbl, row); + + if((tbl->rows[row].flags & KHUI_CW_ROW_HEADER) && + (tbl->cols[tbl->rows[row].col].attr_id == KCDB_ATTR_ID_NAME)) + { + khm_menu_show_panel(KHUI_MENU_IDENT_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + //khui_context_reset(); + } else { + khm_menu_show_panel(KHUI_MENU_TOK_CTX, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + //khui_context_reset(); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +/* copy and paste template */ +#if 0 +LRESULT +cw_wm_msg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} +#endif + +LRESULT CALLBACK +khm_credwnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_COMMAND: + return cw_wm_command(hwnd, uMsg, wParam, lParam); + + case WM_CREATE: + return cw_wm_create(hwnd, uMsg, wParam, lParam); + + case WM_DESTROY: + return cw_wm_destroy(hwnd, uMsg, wParam, lParam); + + case WM_ERASEBKGND: + /* we don't bother wasting cycles erasing the background + because the foreground elements completely cover the + client area */ + return TRUE; + + case WM_PAINT: + return cw_wm_paint(hwnd, uMsg, wParam, lParam); + + case WM_SIZE: + return cw_wm_size(hwnd, uMsg, wParam, lParam); + + case WM_NOTIFY: + return cw_wm_notify(hwnd, uMsg, wParam, lParam); + + case WM_HSCROLL: + return cw_wm_hscroll(hwnd, uMsg, wParam, lParam); + + case WM_VSCROLL: + return cw_wm_vscroll(hwnd, uMsg, wParam, lParam); + + case KMQ_WM_DISPATCH: + return cw_kmq_wm_dispatch(hwnd, uMsg, wParam, lParam); + + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_MOUSEMOVE: + case WM_LBUTTONUP: + return cw_wm_mouse(hwnd, uMsg, wParam, lParam); + + case WM_CONTEXTMENU: + return cw_wm_contextmenu(hwnd, uMsg, wParam, lParam); + } + + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + +void +khm_register_credwnd_class(void) { + WNDCLASSEX wcx; + kcdb_attrib attrib; + khm_int32 attr_id; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS | CS_OWNDC; + wcx.lpfnWndProc = khm_credwnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wcx.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_CREDWND_CLASS_NAME; + wcx.hIconSm = NULL; + + khui_credwnd_cls = RegisterClassEx(&wcx); + + /* while we are at it, register the credwnd attribute type as well, and + obtain the type ID */ + if(KHM_FAILED(kcdb_attrib_get_id(KHUI_CREDWND_FLAG_ATTRNAME, &attr_id))) { + ZeroMemory(&attrib, sizeof(attrib)); + attrib.id = KCDB_ATTR_INVALID; + attrib.flags = KCDB_ATTR_FLAG_HIDDEN; + attrib.type = KCDB_TYPE_INT32; + attrib.name = KHUI_CREDWND_FLAG_ATTRNAME; + + kcdb_attrib_register(&attrib, &attr_id); + } + + khui_cw_flag_id = attr_id; +} + +void +khm_unregister_credwnd_class(void) { + UnregisterClass(MAKEINTATOM(khui_credwnd_cls), khm_hInstance); +} + +HWND +khm_create_credwnd(HWND parent) { + RECT r; + GetClientRect(parent, &r); + return CreateWindowEx( + 0, + MAKEINTATOM(khui_credwnd_cls), + L"", + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, + r.left, + r.top, + r.right - r.left, + r.bottom - r.top, + parent, + NULL, + khm_hInstance, + NULL); +} diff --git a/mechglue/src/windows/identity/ui/credwnd.h b/mechglue/src/windows/identity/ui/credwnd.h new file mode 100644 index 000000000..33e00bacb --- /dev/null +++ b/mechglue/src/windows/identity/ui/credwnd.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_CREDWND_H +#define __KHIMAIRA_CREDWND_H + +#define KHUI_CREDWND_CLASS_NAME L"NetIDMgrCredWnd" + +#define KHUI_CREDWND_FLAG_ATTRNAME L"CredWndFlags" + +extern khm_int32 khui_cw_flag_id; + +/* The expiration states */ +#define CW_EXPSTATE_NONE 0 +#define CW_EXPSTATE_WARN 1024 +#define CW_EXPSTATE_CRITICAL 2048 +#define CW_EXPSTATE_EXPIRED 3072 + +#define CW_EXPSTATE_MASK 3072 + +typedef struct khui_credwnd_outline_t { + khm_int32 flags; /* combination of KHUI_CW_O_* */ + khm_int32 start; /* first row of outline */ + khm_int32 length; /* number of rows in outline */ + khm_int32 level; /* outline level */ + khm_int32 col; /* outline column */ + wchar_t *header; /* character string associated with header */ + khm_int32 attr_id; + void * data; /* level specific data : + Identity -> handle to identity + Type -> type ID + otherwise -> canonical data buffer + */ + khm_size cb_data; + + khm_size idx_start; /* index of the first cred in the credset */ + khm_size idx_end; /* index of the last cred in the credset */ + TDCL(struct khui_credwnd_outline_t); +} khui_credwnd_outline; + +#define KHUI_CW_O_EXPAND 0x00000001 +#define KHUI_CW_O_STICKY 0x00000002 +#define KHUI_CW_O_VISIBLE 0x00000004 +#define KHUI_CW_O_SHOWFLAG 0x00000008 +#define KHUI_CW_O_SELECTED 0x00000010 +#define KHUI_CW_O_DATAALLOC 0x00000020 + +typedef struct khui_credwnd_row_t { + khm_int32 flags; + khm_int32 col; + khm_handle data; + khm_size idx_start; + khm_size idx_end; +} khui_credwnd_row; + +#define KHUI_CW_ROW_CRED 2 +#define KHUI_CW_ROW_HEADER 4 +#define KHUI_CW_ROW_TIMERSET 8 +#define KHUI_CW_ROW_SELECTED 16 + +/* row allocation */ +/* initial number of rows to be allocated */ +#define KHUI_CW_ROW_INITIAL 512 +/* allocation increment, if we run out of space */ +#define KHUI_CW_ROW_INCREMENT 512 + +typedef struct khui_credwnd_col_t { + khm_int32 attr_id; + khm_int32 width; /* width of the column (screen units) */ + khm_int32 x; /* starting x coordinate (screen units) */ + khm_int32 flags; /* combination of KHUI_CW_COL_* */ + khm_int32 sort_index; + wchar_t * title; +} khui_credwnd_col; + +/* column allocation */ +/* initial number of columns to be allocated */ +#define KHUI_CW_COL_INITIAL 16 +/* allocation increment, if we run out of space */ +#define KHUI_CW_COL_INCREMENT 16 + +#define KHUI_CW_COL_AUTOSIZE 1 +#define KHUI_CW_COL_SORT_INC 2 +#define KHUI_CW_COL_SORT_DEC 4 +#define KHUI_CW_COL_GROUP 8 +#define KHUI_CW_COL_FIXED_WIDTH 16 +#define KHUI_CW_COL_FIXED_POS 32 +#define KHUI_CW_COL_META 64 + +/* Custom column attributes (are not kcdb attributes) */ +#define CW_CA_FLAGS -1 +#define CW_CANAME_FLAGS L"_CWFlags" + +#define CW_CA_TYPEICON -2 +#define CW_CANAME_TYPEICON L"_CWTypeIcon" + +#define cw_is_custom_attr(i) ((i)<0) + +typedef struct khui_credwnd_tbl_t { + HWND hwnd; /* the window that this table belongs to */ + + khm_int32 scr_top; /* screen units */ + khm_int32 scr_left; /* screen units */ + khm_int32 ext_width; /* screen units */ + khm_int32 ext_height; /* screen units */ + khm_int32 cell_height; /* screen units */ + + HWND hwnd_header; /* header control */ + khm_int32 header_height; /* height of the header */ + HWND hwnd_notif; /* notification control */ + + khui_credwnd_col * cols; /* n_cols elements */ + khui_credwnd_row * rows; /* n_rows elements */ + khm_size n_cols; + khm_size n_total_cols; /* number of columns actually + allocated in cols */ + khm_size n_rows; + khm_size n_total_rows; /* number of rows actually allocated + in rows */ + + khui_credwnd_outline * outline; + + khm_int32 flags; /* combo of KHUI_CW_TBL_* */ + + khm_int32 cursor_row; /* cursor and selection */ + khm_int32 anchor_row; /* anchor, for range selections */ + + /* view parameters */ + khm_int32 hpad; + khm_int32 vpad; + khm_int32 hpad_h; /* horizontal padding correction for headers */ + khm_int32 threshold_warn; /* Warning threshold, in seconds*/ + khm_int32 threshold_critical; /* Critical threshold, in seconds */ + + /* graphics objects we are going to need. */ + HFONT hf_normal; /* normal text */ + HFONT hf_header; /* header text */ + HFONT hf_bold; /* bold text */ + HFONT hf_bold_header; /* bold header text */ + HBRUSH hb_normal; /* normal background brush */ + HBRUSH hb_grey; /* normal grey background brush */ + HBRUSH hb_sel; /* selected background brush */ + COLORREF cr_hdr_outline;/* header outline color */ + COLORREF cr_normal; /* normal text color */ + COLORREF cr_sel; /* selected text color */ + COLORREF cr_hdr_normal; /* normal header text color */ + COLORREF cr_hdr_sel; /* selected header text color */ + HBRUSH hb_hdr_bg; /* header background color (normal) */ + HBRUSH hb_hdr_bg_exp; /* header background color (expired) */ + HBRUSH hb_hdr_bg_warn; /* header background color (warn) */ + HBRUSH hb_hdr_bg_crit; /* header background color (critical) */ + HBRUSH hb_hdr_bg_sel; /* header background color (selected) */ + HBRUSH hb_hdr_bg_def; /* header background color (default) */ + HCURSOR hc_hand; /* the HAND cursor */ + khui_ilist * ilist; /* image list */ + +#if 0 + /* icon indices */ + int idx_expand; /* index of 'expanded' icon in image list */ + int idx_expand_hi; /* index of 'expanded' icon (highlighted) in image list */ + int idx_collapse; /* index of 'collapsed' icon in image list */ + int idx_collapse_hi; /* index of 'collapsed' icon (highlighted) in image list */ + int idx_ident; /* index of 'identity' icon in image list */ +#endif + + /* mouse state */ + khm_int32 mouse_state; /* state of the mouse can be combo of CW_MOUSE_* values */ + khm_int32 mouse_row; /* row that the mouse state applies to */ + khm_int32 mouse_col; /* col that the mouse state applies to */ + + khui_bitmap kbm_logo_shade; + + /* the credentials set */ + khm_handle credset; +} khui_credwnd_tbl; + +#define KHUI_MAXCB_HEADING 256 + +/* table flags */ +#define KHUI_CW_TBL_INITIALIZED 0x00000001 +#define KHUI_CW_TBL_COL_DIRTY 0x00000002 +#define KHUI_CW_TBL_ROW_DIRTY 0x00000004 +#define KHUI_CW_TBL_ACTIVE 0x00000100 + +/* mouse_state constants */ +#define CW_MOUSE_NONE 0x00000000 /* nothing interesting */ +#define CW_MOUSE_WIDGET 0x00000001 /* mouse is highlighting a + widget */ +#define CW_MOUSE_LDOWN 0x00000002 /* left button is down */ +#define CW_MOUSE_ROW 0x00000004 /* mouse is acive over a valid + row */ +#define CW_MOUSE_WOUTLINE 0x00000008 /* mouse is highlighting an + outline widget */ +#define CW_MOUSE_WSTICKY 0x00000010 /* mouse is highlighting a + sticky widget */ +#define CW_MOUSE_WICON 0x00000020 /* an icon widget. represents + the icon next to identities + and next to credentials. */ + +#define CW_MOUSE_WMASK 0x00000039 /* all widget bits */ + +void khm_unregister_credwnd_class(void); + +void khm_register_credwnd_class(void); + +HWND khm_create_credwnd(HWND parent); + +LRESULT CALLBACK khm_credwnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ); + +void cw_load_view(khui_credwnd_tbl * tbl, wchar_t * viewname, HWND hwnd); + +void cw_update_creds(khui_credwnd_tbl * tbl); + +void cw_unload_view(khui_credwnd_tbl * tbl); + +void cw_hditem_from_tbl_col(khui_credwnd_col * col, HDITEM *phi); + +int cw_update_extents(khui_credwnd_tbl * tbl, khm_boolean update_scroll); + +void cw_insert_header_cols(khui_credwnd_tbl * tbl); + +#endif diff --git a/mechglue/src/windows/identity/ui/htmlwnd.h b/mechglue/src/windows/identity/ui/htmlwnd.h new file mode 100644 index 000000000..e69de29bb diff --git a/mechglue/src/windows/identity/ui/htwnd.c b/mechglue/src/windows/identity/ui/htwnd.c new file mode 100644 index 000000000..0ad9c880f --- /dev/null +++ b/mechglue/src/windows/identity/ui/htwnd.c @@ -0,0 +1,1070 @@ +/* +* Copyright (c) 2005 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include<khmapp.h> +#include<crtdbg.h> + +ATOM khui_htwnd_cls; + +#define HTW_STYLE_NORMAL 0 + +/* There are currently 4 style "bits" and 3 sizes, which means + there can be 2^4*3=48 possible styles max. If someone is + feeling adventurous you can slightly improve performance of + the parser using this little fact. For now, I don't care. + (hint: combine size and style bits to form a single number + and use it as an index into the styles array) +*/ +#define HTW_STYLE_MAX 48 + +#define HTW_FORMAT_MAX 128 + +#define HTW_TAB_MAX 8 + +#define HTW_DEFAULT (-1) + +#define HTW_NORMAL_SIZE 8 +#define HTW_LARGE_SIZE 12 +#define HTW_HUGE_SIZE 20 + +/* font variant */ +#define FV_ABSOLUTE 0x10000000 + +#define FV_ITALIC 0x00000002 +#define FV_UNDERLINE 0x00000004 +#define FV_STRIKEOUT 0x00000008 +#define FV_BOLD 0x00000010 + +#define FV_NOITALIC 0x00020000 +#define FV_NOUNDERLINE 0x00040000 +#define FV_NOSTRIKEOUT 0x00080000 +#define FV_NOBOLD 0x00100000 + +#define FV_NONE 0x00000000 +#define FV_MASK 0x0000001f + +#define HTW_LINK_ALLOC 8 + +#define ALIGN_LEFT 0 +#define ALIGN_CENTER 1 +#define ALIGN_RIGHT 2 + +struct tx_tbl_t { + wchar_t * string; + LONG value; +} + +htw_color_table[] = { + {L"black", RGB(0,0,0)}, + {L"white", RGB(255,255,255)}, + {L"red", RGB(255,0,0)}, + {L"green", RGB(0,255,0)}, + {L"blue", RGB(0,0,255)}, + {L"grey", RGB(128,128,128)} +}, + +htw_size_table[] = { + {L"normal", HTW_NORMAL_SIZE}, + {L"large", HTW_LARGE_SIZE}, + {L"huge", HTW_HUGE_SIZE} +}, + +htw_align_table[] = { + {L"left", ALIGN_LEFT}, + {L"center", ALIGN_LEFT}, + {L"right", ALIGN_RIGHT} +}; + +typedef struct khui_htwnd_style_t { + LONG height; + LONG variation; /* combination of FV_* */ + + HFONT font; +} khui_htwnd_style; + +typedef struct khui_format_t { + int style_idx; + COLORREF color; +} khui_format; + +typedef struct format_stack_t { + khui_format stack[HTW_FORMAT_MAX]; + int stack_top; +} format_stack; + +typedef struct khui_htwnd_data_t { + int id; /* control ID */ + int flags; + wchar_t * text; + int scroll_left; + int scroll_top; + COLORREF bk_color; + HCURSOR hc_hand; + int l_pixel_y; + + khui_htwnd_style styles[HTW_STYLE_MAX]; + int n_styles; + + khui_htwnd_link ** links; + int n_links; + int max_links; + int active_link; + int md_link; + + int tabs[HTW_TAB_MAX]; + int n_tabs; +} khui_htwnd_data; + +static LONG table_lookup(struct tx_tbl_t * tbl, int n, wchar_t * v, int len) +{ + int i; + + for(i=0; i<n; i++) { + if(!wcsnicmp(tbl[i].string, v, len)) + return tbl[i].value; + } + + return -1; +} + +static void clear_styles(khui_htwnd_data * d) +{ + int i; + + for(i=0; i<d->n_styles; i++) { + if(d->styles[i].font != NULL) { + DeleteObject(d->styles[i].font); + d->styles[i].font = NULL; + } + } + + d->n_styles = 0; +} + +static void format_init(format_stack * s) +{ + s->stack_top = -1; + ZeroMemory(s->stack, sizeof(s->stack)); +} + +static khui_format * format_current(format_stack * s) +{ + if(s->stack_top >= 0) + return &(s->stack[s->stack_top]); + else + return NULL; +} + +static int format_style(format_stack * s) +{ + if(s->stack_top >= 0) + return s->stack[s->stack_top].style_idx; + else + return 0; +} + +static COLORREF format_color(format_stack * s) +{ + if(s->stack_top >= 0) + return s->stack[s->stack_top].color; + else + return 0; +} + +static int format_level(format_stack * s) +{ + return s->stack_top; +} + +static void format_unwind(format_stack * s, int level) +{ + s->stack_top = level; +} + +static void format_push(format_stack * s, khui_htwnd_data * d, LONG height, LONG variation, COLORREF color) +{ + int i; + khui_format * top; + khui_htwnd_style * style; + + _ASSERT(s->stack_top < (HTW_FORMAT_MAX-1)); + + /* formatting is additive unless FV_NORMAL is set in variation */ + top = format_current(s); + if(top) { + style = &(d->styles[top->style_idx]); + if(height == HTW_DEFAULT) + height = style->height; + + if(variation == HTW_DEFAULT) + variation = style->variation; + else if(!(variation & FV_ABSOLUTE)) + variation |= style->variation; + + if(color == HTW_DEFAULT) + color = top->color; + } + + variation &= ~FV_ABSOLUTE; + variation ^= variation & (variation>>16); + variation &= FV_MASK; + + /* now look for an existing style that matches the requested one */ + for(i=0; i<d->n_styles; i++) { + style = &(d->styles[i]); + + if(style->height == height && + style->variation == variation) + break; + } + + s->stack_top++; + + if(i<d->n_styles) { + s->stack[s->stack_top].style_idx = i; + } else { + if(d->n_styles == HTW_STYLE_MAX) { + s->stack[s->stack_top].style_idx = 0; + } else { + s->stack[s->stack_top].style_idx = d->n_styles; + d->styles[d->n_styles].font = NULL; + d->styles[d->n_styles].height = height; + d->styles[d->n_styles].variation = variation; + d->n_styles++; + } + } + s->stack[s->stack_top].color = color; +} + +static void format_pop(format_stack * s) { + if(s->stack_top >= 0) + s->stack_top--; +} + +static wchar_t * token_end(wchar_t * s) { + while(iswalnum(*s) || *s == L'/') + s++; + return s; +} + +static wchar_t * skip_ws(wchar_t * s) { + while(iswspace(*s)) + s++; + return s; +} + +/* s points to something like " = \"value\"" + start and len will point to the start and + length of value. return value will point to the + character following the last double quote. */ +static wchar_t * read_attr(wchar_t * s, wchar_t ** start, int * len) +{ + wchar_t *e; + + *start = NULL; + *len = 0; + + do { + s = skip_ws(s); + if(*s != L'=') + break; + s = skip_ws(++s); + if(*s != L'"') + break; + e = wcschr(++s, L'"'); + if(!e) + break; + + *start = s; + *len = (int) (e - s); + + s = e + 1; + } while(FALSE); + + return s; +} + +/* +We currently support the following tags: + +<a [id="string"] [param="paramstring"]>link text</a> +<b>foo</b> +<u>foo</u> + +<center>foo</center> +<left>foo</left> +<right>foo</right> + +<font [color="color"] [size="normal|large|huge"]>foo</font> +<large>foo</large> +<huge>foo</huge> + +<p [align="left|center|right"]>foo</p> +<settab pos=""> +<tab> +*/ + +static int htw_parse_tag( + wchar_t * start, + wchar_t ** end, + int * align, + khui_htwnd_data * d, + format_stack * s, + PPOINT p_abs, + PPOINT p_rel, + int lh, + BOOL dry_run) +{ + wchar_t * c; + int n = 0; + + /* start initially points to the starting '<' */ + c = token_end(++start); + + if(!wcsnicmp(start,L"a",c-start)) { + /* start of an 'a' tag */ + wchar_t * id_start = NULL; + int id_len = 0; + wchar_t * param_start = NULL; + int param_len = 0; + + /* We don't need to parse the link + if it is just a dry run */ + if(dry_run) { + format_push(s, d, HTW_DEFAULT, HTW_DEFAULT, RGB(0,0,255)); + *end = wcschr(start, L'>'); + return FALSE; + } + + while(c && *c && *c != L'>') { + wchar_t * e; + + c = skip_ws(c); + e = token_end(c); + + if(c==e) + break; + + if(!wcsnicmp(c,L"id",e-c)) { + c = read_attr(e, &id_start, &id_len); + } else if(!wcsnicmp(c,L"param",e-c)) { + c = read_attr(e, ¶m_start, ¶m_len); + } + } + + if(d->active_link == d->n_links) + format_push(s,d, HTW_DEFAULT, FV_UNDERLINE, RGB(0,0,255)); + else + format_push(s,d, HTW_DEFAULT, FV_NONE, RGB(0,0,255)); + + { + khui_htwnd_link * l; + + if(!d->links) { + d->links = PMALLOC(sizeof(khui_htwnd_link *) * HTW_LINK_ALLOC); + ZeroMemory(d->links, sizeof(khui_htwnd_link *) * HTW_LINK_ALLOC); + d->max_links = HTW_LINK_ALLOC; + d->n_links = 0; + } + + if(d->n_links >= d->max_links) { + khui_htwnd_link ** ll; + int n_new; + + n_new = UBOUNDSS(d->n_links + 1, HTW_LINK_ALLOC, HTW_LINK_ALLOC); + + ll = PMALLOC(sizeof(khui_htwnd_link *) * n_new); + ZeroMemory(ll, sizeof(khui_htwnd_link *) * n_new); + memcpy(ll, d->links, sizeof(khui_htwnd_link *) * d->max_links); + PFREE(d->links); + d->links = ll; + d->max_links = n_new; + } + + l = d->links[d->n_links]; + if(!l) { + l = PMALLOC(sizeof(khui_htwnd_link)); + d->links[d->n_links] = l; + } + + l->id = id_start; + l->id_len = id_len; + l->param = param_start; + l->param_len = param_len; + + l->r.left = p_abs->x; + l->r.top = p_abs->y; + + d->n_links++; + } + + } else if(!wcsnicmp(start, L"/a", c - start)) { + khui_htwnd_link * l; + + c = wcschr(c,L'>'); + if(!c) + c = c + wcslen(c); + + format_pop(s); + + if(!dry_run) { + l = d->links[d->n_links - 1]; /* last link */ + l->r.right = p_abs->x; + l->r.bottom = p_abs->y + lh; + } + } else if(!wcsnicmp(start, L"p", c - start)) { + wchar_t * e; + wchar_t * align_s = NULL; + int align_len; + + c = skip_ws(c); + e = token_end(c); + + if(c != e && !wcsnicmp(c,L"align",e-c)) { + c = read_attr(e, &align_s, &align_len); + } + + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + + + if(align_s) + *align = table_lookup(htw_align_table, ARRAYLENGTH(htw_align_table), align_s, align_len); + else + *align = ALIGN_LEFT; + + n = 1; + } else if(!wcsnicmp(start, L"b", c - start)) { + format_push(s,d, HTW_DEFAULT, FV_BOLD, HTW_DEFAULT); + } else if(!wcsnicmp(start, L"/b", c - start)) { + format_pop(s); + } else if(!wcsnicmp(start, L"u", c - start)) { + format_push(s,d, HTW_DEFAULT, FV_UNDERLINE, HTW_DEFAULT); + } else if(!wcsnicmp(start, L"/u", c - start)) { + format_pop(s); + } else if(!wcsnicmp(start, L"large", c - start)) { + format_push(s,d,-MulDiv(HTW_LARGE_SIZE, d->l_pixel_y, 72), HTW_DEFAULT, HTW_DEFAULT); + } else if(!wcsnicmp(start, L"/large", c - start)) { + format_pop(s); + } else if(!wcsnicmp(start, L"huge", c - start)) { + format_push(s,d,-MulDiv(HTW_HUGE_SIZE, d->l_pixel_y, 72), HTW_DEFAULT, HTW_DEFAULT); + } else if(!wcsnicmp(start, L"/huge", c - start)) { + format_pop(s); + } else if(!wcsnicmp(start, L"center", c - start)) { + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + *align = ALIGN_CENTER; + n = 1; + } else if(!wcsnicmp(start, L"left", c - start) || + !wcsnicmp(start, L"p", c - start)) + { + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + *align = ALIGN_LEFT; + n = 1; + } else if(!wcsnicmp(start, L"right", c - start)) { + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + *align = ALIGN_RIGHT; + n = 1; + } else if(!wcsnicmp(start, L"/center", c - start) || + !wcsnicmp(start, L"/left", c - start) || + !wcsnicmp(start, L"/right", c - start) || + !wcsnicmp(start, L"/p", c - start)) + { + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + *align = ALIGN_LEFT; + n = 1; + } else if(!wcsnicmp(start, L"font", c - start)) { + wchar_t * color_s = NULL; + int color_len; + wchar_t * size_s = NULL; + int size_len; + LONG color = HTW_DEFAULT; + LONG h = HTW_DEFAULT; + + while(c && *c && *c != L'>') { + wchar_t * e; + + c = skip_ws(c); + e = token_end(c); + + if(c==e) + break; + + if(!wcsnicmp(c,L"color",e-c)) { + c = read_attr(e, &color_s, &color_len); + } else if(!wcsnicmp(c,L"size",e-c)) { + c = read_attr(e, &size_s, &size_len); + } + } + + if(color_s) + color = table_lookup(htw_color_table, ARRAYLENGTH(htw_color_table), color_s, color_len); + if(size_s) { + h = table_lookup(htw_size_table, ARRAYLENGTH(htw_size_table), size_s, size_len); + if(h) + h = -MulDiv(h, d->l_pixel_y, 72); + else + h = -MulDiv(HTW_NORMAL_SIZE, d->l_pixel_y, 72); + } + + format_push(s,d,h,HTW_DEFAULT,color); + } else if(!wcsnicmp(start, L"/font", c - start)) { + format_pop(s); + } else if(!wcsnicmp(start, L"settab", c - start)) { + wchar_t * e; + wchar_t * pos_s = NULL; + int pos_len; + + c = skip_ws(c); + e = token_end(c); + + if(c != e && !wcsnicmp(c,L"pos",e-c)) { + c = read_attr(e, &pos_s, &pos_len); + } + + c = wcschr(c, L'>'); + if(!c) + c = c + wcslen(c); + + if(pos_s && d->n_tabs < HTW_TAB_MAX && !dry_run) { + wchar_t * dummy; + LONG bu; + int bx; + int dx; + + bu = GetDialogBaseUnits(); + bx = LOWORD(bu); + + dx = wcstol(pos_s, &dummy, 10); + + d->tabs[d->n_tabs++] = MulDiv(dx, bx, 4); + } + } else if(!wcsnicmp(start, L"tab", c - start)) { + int i; + + if(!dry_run) { + for(i=0; i < d->n_tabs; i++) { + if(d->tabs[i] > p_rel->x) { + p_rel->x = d->tabs[i]; + break; + } + } + } + } + + if(*c) + c++; + *end = c; + + return n; +} + +static void htw_assert_style(HDC hdc, khui_htwnd_data * d, int style) +{ + LOGFONT lf; + + if(d->styles[style].font) + return; + + /*TODO: we need select different fonts depending on system locale */ + lf.lfHeight = d->styles[style].height; //-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72); + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + lf.lfWeight = (d->styles[style].variation & FV_BOLD)? FW_BOLD: FW_NORMAL; + lf.lfItalic = !!(d->styles[style].variation & FV_ITALIC); + lf.lfUnderline = !!(d->styles[style].variation & FV_UNDERLINE); + lf.lfStrikeOut = !!(d->styles[style].variation & FV_STRIKEOUT); + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH; + + LoadString(khm_hInstance, IDS_DEFAULT_FONT, lf.lfFaceName, ARRAYLENGTH(lf.lfFaceName)); + + d->styles[style].font = CreateFontIndirect(&lf); +} + +static LRESULT htw_paint(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HBRUSH hbk; + khui_htwnd_data * d; + RECT r; + SIZE s; + HDC hdc; + wchar_t * text; + format_stack s_stack; + + int align; + int y; + wchar_t * par_start; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(!GetUpdateRect(hwnd, &r, !(d->flags & KHUI_HTWND_TRANSPARENT))) + return 0; + + if(d->text == NULL) + return 0; + + text = d->text; + + hdc = BeginPaint(hwnd, &ps); + + GetClientRect(hwnd, &r); + + if(d->flags & KHUI_HTWND_CLIENTEDGE) + DrawEdge(hdc, &r, EDGE_SUNKEN, BF_ADJUST | BF_RECT | BF_FLAT); + + hbk = CreateSolidBrush(RGB(255,255,255)); + FillRect(hdc, &r, hbk); + DeleteObject(hbk); + + /* push the default format */ + format_init(&s_stack); + + d->l_pixel_y = GetDeviceCaps(hdc, LOGPIXELSY); + format_push(&s_stack,d, -MulDiv(HTW_NORMAL_SIZE, d->l_pixel_y, 72), FV_NONE, RGB(0,0,0)); + + y = d->scroll_top + r.top; + + par_start = text; + + align = ALIGN_LEFT; + + SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP); + if(d->flags & KHUI_HTWND_TRANSPARENT) + SetBkMode(hdc, TRANSPARENT); + + d->n_links = 0; + d->n_tabs = 0; + + while(*par_start) { + wchar_t * p = par_start; + wchar_t * c = NULL; + int p_width = 0; + int s_start; + int l_height = 0; + int x = 0; + POINT pt; + POINT pt_rel; + + s_start = format_level(&s_stack); + + /* begin dry run */ + while(*p) { + if(*p == L'<') { + int talign = -1; + int n = htw_parse_tag(p,&c,&talign,d,&s_stack,NULL,NULL,0,TRUE); + + if(n && p_width) + break; + + p = c; + + if(n && talign >= 0) + align = talign; + } else { + HFONT hfold; + c = wcschr(p, L'<'); + if(!c) + c = p + wcslen(p); + + htw_assert_style(hdc, d, format_style(&s_stack)); + hfold = SelectFont(hdc, d->styles[format_style(&s_stack)].font); + GetTextExtentPoint32(hdc, p, (int)(c - p), &s); + SelectFont(hdc, hfold); + + p_width += s.cx; + if(s.cy > l_height) + l_height = s.cy; + + p = c; + } + } + + /* dry run ends */ + + x = r.left - d->scroll_left; + + if(align == ALIGN_CENTER) + x += (r.right - r.left)/2 - p_width / 2; + else if(align == ALIGN_RIGHT) + x += (r.right - r.left) - p_width; + + /* begin wet run */ + p = par_start; + format_unwind(&s_stack, s_start); /* unwind format stack */ + + //MoveToEx(hdc, x, y + l_height, NULL); + + p_width = 0; + + while(*p) { + if(*p == L'<') { + int talign = -1; + int n; + + pt.x = x + p_width; + pt.y = y; + pt_rel.x = p_width; + pt_rel.y = 0; + + n = htw_parse_tag(p, &c, &talign, d, &s_stack, &pt, &pt_rel, l_height, FALSE); + + if(n && p_width) { + break; + } + + p_width = pt_rel.x; + + p = c; + if(n && talign >= 0) + align = talign; + } else { + HFONT hfold; + RECT rd,rt; + + c = wcschr(p, L'<'); + if(!c) + c = p + wcslen(p); + + htw_assert_style(hdc, d, format_style(&s_stack)); + hfold = SelectFont(hdc, d->styles[format_style(&s_stack)].font); + SetTextColor(hdc, format_color(&s_stack)); + + GetTextExtentPoint32(hdc, p, (int)(c - p), &s); + rd.left = x + p_width; + rd.top = y; + rd.right = x + p_width + s.cx; + rd.bottom = y + l_height; + + if(IntersectRect(&rt, &rd, &r)) { + DrawText(hdc, p, (int)(c - p), &rt, DT_BOTTOM | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); + } + + p_width += s.cx; + + SelectFont(hdc, hfold); + p = c; + } + } + + y += l_height; + par_start = p; + } + + EndPaint(hwnd, &ps); + + return 0; +} + +LRESULT CALLBACK khui_htwnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + switch(uMsg) { + case WM_CREATE: + { + CREATESTRUCT * cs; + khui_htwnd_data * d; + size_t cbsize; + + cs = (CREATESTRUCT *) lParam; + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + if(cs->dwExStyle & WS_EX_TRANSPARENT) { + d->flags |= KHUI_HTWND_TRANSPARENT; + } + if(cs->dwExStyle & WS_EX_CLIENTEDGE) { + d->flags |= KHUI_HTWND_CLIENTEDGE; + } + d->id = (int)(INT_PTR) cs->hMenu; + + d->active_link = -1; + d->bk_color = RGB(255,255,255); + d->hc_hand = LoadCursor(NULL, IDC_HAND); + + if(SUCCEEDED(StringCbLength(cs->lpszName, KHUI_HTWND_MAXCB_TEXT, &cbsize))) { + cbsize += sizeof(wchar_t); + d->text = PMALLOC(cbsize); + StringCbCopy(d->text, cbsize, cs->lpszName); + } + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, 0, (LONG_PTR) d); +#pragma warning(pop) + + return 0; + } + break; + + case WM_SETTEXT: + { + wchar_t * newtext; + size_t cbsize; + khui_htwnd_data * d; + BOOL rv; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + newtext = (wchar_t *) lParam; + + if(d->text) { + PFREE(d->text); + d->text = NULL; + } + + if(SUCCEEDED(StringCbLength(newtext, KHUI_HTWND_MAXCB_TEXT, &cbsize))) { + cbsize += sizeof(wchar_t); + d->text = PMALLOC(cbsize); + StringCbCopy(d->text, cbsize, newtext); + rv = TRUE; + } else + rv = FALSE; + + clear_styles(d); + + InvalidateRect(hwnd, NULL, TRUE); + + return rv; + } + break; + + case WM_DESTROY: + { + khui_htwnd_data * d; + int i; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + if(d->text) + PFREE(d->text); + d->text = 0; + + if(d->links) { + for(i=0;i<d->max_links;i++) { + if(d->links[i]) + PFREE(d->links[i]); + } + PFREE(d->links); + } + + clear_styles(d); + + PFREE(d); + } + break; + + case WM_ERASEBKGND: + { + khui_htwnd_data * d; + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(d->flags & KHUI_HTWND_TRANSPARENT) + return TRUE; + + return FALSE; + } + + case WM_PAINT: + htw_paint(hwnd, uMsg, wParam, lParam); + break; + + case WM_SETCURSOR: + { + khui_htwnd_data * d; + + if(hwnd != (HWND)wParam) + break; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(d->active_link >= 0) { + SetCursor(d->hc_hand); + return TRUE; + } + } + break; + + case WM_SETFOCUS: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + d->flags |= KHUI_HTWND_FOCUS; + + InvalidateRect(hwnd, NULL, TRUE); + } + break; + + case WM_KILLFOCUS: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + d->flags &= ~KHUI_HTWND_FOCUS; + + InvalidateRect(hwnd, NULL, TRUE); + } + break; + + case WM_LBUTTONDOWN: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + d->md_link = d->active_link; + + SetCapture(hwnd); + } + break; + + case WM_LBUTTONUP: + { + khui_htwnd_data * d; + + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + if(d->md_link == d->active_link && d->md_link >= 0) { + /* clicked */ + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(d->id, BN_CLICKED), (LPARAM) d->links[d->md_link]); + } + + ReleaseCapture(); + } + break; + + case WM_MOUSEMOVE: + { + khui_htwnd_data * d; + int i; + POINT p; + int nl; + + p.x = GET_X_LPARAM(lParam); + p.y = GET_Y_LPARAM(lParam); + d = (khui_htwnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + + for(i=0; i<d->n_links; i++) { + if(d->links && d->links[i] && PtInRect(&(d->links[i]->r), p)) + break; + } + + if(i == d->n_links) + nl = -1; + else + nl = i; + + if(d->active_link != nl) { + if(d->active_link >= 0) { + if(d->flags & KHUI_HTWND_TRANSPARENT) + { + HWND parent = GetParent(hwnd); + if(parent) { + InvalidateRect(parent, NULL, TRUE); + } + } + /* although we are invalidating the rect before setting active_link, + WM_PAINT will not be issued until wndproc returns */ + InvalidateRect(hwnd, &(d->links[d->active_link]->r), TRUE); + } + d->active_link = nl; + if(d->active_link >= 0) { + /* although we are invalidating the rect before setting active_link, + WM_PAINT will not be issued until wndproc returns */ + if(d->flags & KHUI_HTWND_TRANSPARENT) + { + HWND parent = GetParent(hwnd); + if(parent) { + InvalidateRect(parent, NULL, TRUE); + } + } + InvalidateRect(hwnd, &(d->links[d->active_link]->r), TRUE); + } + } + } + break; + } + + return DefWindowProc(hwnd, uMsg,wParam,lParam); +} + +void khm_register_htwnd_class(void) +{ + WNDCLASSEX wcx; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wcx.lpfnWndProc = khui_htwnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wcx.hbrBackground = CreateSolidBrush(RGB(255,255,255)); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_HTWND_CLASS; + wcx.hIconSm = NULL; + + khui_htwnd_cls = RegisterClassEx(&wcx); +} + +void khm_unregister_htwnd_class(void) +{ + UnregisterClass((LPWSTR) khui_htwnd_cls, khm_hInstance); +} + +HWND khm_create_htwnd(HWND parent, LPWSTR text, int x, int y, int width, int height, DWORD ex_style, DWORD style) +{ + + return CreateWindowEx( + ex_style, + (LPWSTR) khui_htwnd_cls, + text, + style | WS_CHILD, + x,y,width,height, + parent, + (HMENU) KHUI_HTWND_CTLID, + khm_hInstance, + NULL); +} diff --git a/mechglue/src/windows/identity/ui/htwnd.h b/mechglue/src/windows/identity/ui/htwnd.h new file mode 100644 index 000000000..e83dbb684 --- /dev/null +++ b/mechglue/src/windows/identity/ui/htwnd.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_HTWND_H +#define __KHIMAIRA_HTWND_H + +#include<khuidefs.h> + +/* +We currently support the following tags: + +<a [id="string"] [param="paramstring"]>link text</a> +<center>foo</center> +<left>foo</left> +<right>foo</right> +*/ + +#define KHUI_HTWND_TRANSPARENT 1 +#define KHUI_HTWND_CLIENTEDGE 2 +#define KHUI_HTWND_FOCUS 2048 + +#define KHUI_HTWND_CLASS L"KhmHtWnd" +#define KHUI_HTWND_CTLID 2040 + +#define KHUI_HTWND_MAXCCH_TEXT 2048 +#define KHUI_HTWND_MAXCB_TEXT (sizeof(wchar_t) * KHUI_HTWND_MAXCCH_TEXT) + +HWND khm_create_htwnd(HWND parent, LPWSTR text, int x, int y, int width, int height, DWORD ex_style, DWORD style); +void khm_unregister_htwnd_class(void); +void khm_register_htwnd_class(void); + +#endif diff --git a/mechglue/src/windows/identity/ui/images/app_notify_error.ico b/mechglue/src/windows/identity/ui/images/app_notify_error.ico new file mode 100644 index 0000000000000000000000000000000000000000..9fb30c53e792d60a03a03f64d3a94c33968e1bba GIT binary patch literal 2862 zcmeHJZBSHY6h8aGLI`&e<s(oQn3Zr1LR3s7gcYwwN`y(JC1ziGXR<#{P4t5un;i9r zG&Iq~OlCTxBQ`XWVNu#<MY$$F*2b9-*Bxk9-0ZqBwvo)-)AQb4K*?;H@ux5I-1DA~ z=bZDNcZPk53}m9Dq$Ef)<r|1fh@cbnINB6Lv>vvIo=uy~L_HRwd=Ud=1A;es3E$Xq zi48uk=*AUQTrjxZZerobhoc*gDjYEgFIJrD(xs{n2`Q<nZh#O5p$dbl1|WwZ)#m}B zS8Y+7qdE(@eOJU^74fUOln{q-BtrZKQNTh%XiW`+BQ~umWF4{jV?$QA$sg-7xlLqn z0h9iO#Y85Tl}vt{%R18Jx7|3WIFb0qh1rT_G#bg+dV-9eKHBQjC^?{!Wxt1{b{{!m zbNYfLb@@nY36N90M)6)BmG&U6O`}f4)}PfVw@V|3s*$u`qm2QT@}TF{tfy)Z;yN`- zJ)zMn>M)fAH8OVfk~0{l_?;Tbz3}hVsQ5V0xQkNZcZQM2t5G?)1K2ydH7WsLYJsi2 zo9cXFat>>hfm+Em+bFjKId}Ka-U0O8;UPy~fMoO+zgwej^rW0cedI3%M+vG_h~6aR z-YasTb{1+%ts2z~gekWjxoTP{tMeM>Qb)$N9y0d&XeZ{9EAqE{NX85#?*NsfMi;ma z<g3Ry8gV|$aW7Q|F{53miQL7FZIpqS)IOZcqfsENQK2{wxH9Tz;S8zha|`?#=&>BO zEx}>RK)z(XC-hO*LV2B9<g)I3?@Zt}Pe8fZx<BU;>vi@8n^T@ldwASX)=-p^pHnjy zv82ARXmftf?8IU{qEf0aT)Jo~^tBJdkmab{P#AxgWm!&Qp6zMqYbvuJFwUE|>bco@ zwj@QF<|vtEj*;bu%uhUJx<^sc7gd|htE;M3n;*|yxK2^-F143dEPghlF4=B>rd(0% zV$GN3=|UDL%1R+u$Z`V2lvosep}=lmF3U6Q_PA)rkJ=5gJa^`ts0wi((PL5V_WqyE z{y(>qfZ#IVRiHTvu@^SsyVcUU%1_MmzGSZdk@@gN{YUE)klp}pl|$z)?_tjCWX}JT zxuBbQ#ShF~m;N({&MoL-o_T;dw*xtjFyH$bbMbNJCCGV;K6GySKIXI!nP-5X^AYnb z^e_kfxyP7GzF{u=o_WvUP5ZD*?=Vk&k2z%zbLM{L>_f<fy17T0i!g@;Uo$U850xI~ z9T&!Ph?&~sb}%Qr#hmmm_`8|Y!B2eqB1=d5IpI)0&+HuG`EKUY@0csVU)Ia~;yFEs zxSOK5?aWh}nXRqp0re%!%W$fX%^j!M{P8K4ynfCErvyDLImujgnt2WG2V9+R)$1Y0 z`{15oo<77JbKoTWwK`%BdUzV{FzsjNg_yzC^UMQ(Oz@Krqi1ne%tmkpEXTZz-zzrO zwy@=^GrBD^2tLq#h52H5f}euE%0kS}t2pB@?(bLTO_#3lOTiGod^yC8mw)GcHR2aB z<%rz}p#N>a9ATRbN8c~w{cjBX_78sr>VUfr$doUS_D$v+di%%uQ@j^$<X;&bb$ZTy z4z3M|1*m55FIQDa8yU+(ZQqXb4M$H;@cV=3i(hZ91tk$M3hvliHE=b(dT7)wa!~7u zaXx*}!%HuP!(|7*XhCcmfEVb$uUg-qYm-*J3BE~3@oQ~b-pYn@FeD)Qx|-mJtPO+y nSgpxz8nL+yAuEv|XTp1q@Scmr3(oa0x$vrU$GWT`tKarF-a&AK literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/app_notify_info.ico b/mechglue/src/windows/identity/ui/images/app_notify_info.ico new file mode 100644 index 0000000000000000000000000000000000000000..2e4d51960d37cec43364c88a0b30a76eb2d80106 GIT binary patch literal 2862 zcmeHJZA_C_6h2V3bvlY;!Yp*KPCFcnI9QP3V&gyiXaAQter(y|SO%;y1yM`I4H_mi zGm6YDY_f=mA6ZbUGAXq>K8h5?TI8#iLJOtzg92^k_HB3G77TvOY|DNv-sHabp68yA z=bZO#&jpA821G|k<GKQpBLFf0PzID)uxBMeHez8p3HGc2Xj=u4OzYrG!b#gbIq0*c zA*DC?kS=bdi-HsZl}ZIc`Wzp@#Z7Qg2!;Wci#`XCg^qzGlZODAOdiBdL7_~Bddz}C zc@Tkug2H@|2ZIF#^6*+HlZIq@P>KP9g)+o(Wyxgp>OyyDPdk)Jnc)CZW++_v5hxD& z{DMHSFVQb>F@1?DhKnhUP%$tYtjgnqMvQpsVjG#L%?<|rg2(H`dfb4P7QIA9MnXx6 z1k`FJm`o<9t*wFV>}=@k(}JS05!`M!h(x(iRdo~w2lde0tbp?JQqX8LFg0a?hK4$j z6cquV&j*9S06951u&}TIN~IF?dOZ}0#ZXgIgJ*+KSy>5Mtri>(2VA_^0BLDyP+D37 zZEbB}u~?w4t`2SbK%r;^kH-UIu?S9{tirg1=&u>$O<}wSkVuLkH#Zluva*1~;Xr8# z`cSK(uC^9(KK}%{_kmc1wpCTgw;3wS%R!5LO~@}7`2_+2P$R#i$fpnaWMpK(6vkI5 z6tIAC4H(aXu`Xh)5{cyL+Py$tRN#M70bzK=@D?}WC1Eo!Wf|~x)W#Sd_Yn}yjEst7 zq_9{a<mH!EyuLOnW-|hO1m4>9{<id3)_NX?$K|gVzW2dv?+PO0ckWD$Wv~(0wQhAp z8t+w9e22?R;j-2xZA05wq41Ts6c(G!U6-7|;4$Ka!o(Cle?6C*oVA7%!-y9OQ&}to zSi*!=8`p5Qpv>hWLNkb36&L$vbS67xiQyXwYqttlGnS<ky;Zo9R(*Q>xBs(A|LUtS zJ}}5EX7f$E-Om0e4mvwJ*u6d4E5k#B#5_JutX8YZ<#MI|9Uqq)e@kt-{<}%j*+F!= zyTo7^A(Imm1UY!n$4Afe@pH{j*$wq)JWZD`ksGR3a=S}I`up`{bks<utX6{dWY+CI z_M{Ja#gR4Tva;&q$BvRyztoTm=Nrhis|rGM7#SWWg98I(Y;26!Y&J4G>n7L(Zu<TH zP))?5uj9pgMeT=*50Z-S%1QN!<K*<Or--UmN!;!k%fp8cA6P8rh2h~Lg0-acAoKHc z#OL#w&`0W?&py5M)t6t8ed4|3+rx**_wovw`+~f((t-c~^YqNj%=BX4S{OAN$>ih& zaXOte2ZFu_4oMD{9oSc>*(=I-mq;b#mimUrY#txNem9MI(j7cB&!0PIaylJOngjML zkHc>7!Fn_mAJ|`3`pw~{AF7VGcWF9(SZ@=)w}F<H>my6Hn>KCo-qY!ZF#iX0b8|lH z<YbT4I@yFgnk4&+%1&0F=)w2x8#9ek7V|h|8XcX{>+e0XPft(x+H6yHk7u6pdA$_o zPGPUTkF)8=>J#U>yEN3m{eEg>c!<Jpjv5;?Q56+O$Wr|6+qVa1W?a<l>@0<~qr6^E z$cKAo#&Sh*d5gCDcFUdK9!jsf`^ZmTUS43y9{X{?K0Qq#UkYs~%z;8K-B`mNs1q7$ zRcm%vXUBBkonES6ucKO(EmYm<)707edaAkk8ihGi(>5FBbU5tj=irjv@)hmb?QMTl z^lH1QYgeyO@$sAxhy47!0G-o>#c~1bkht9DS$mc8`i`^pXSz3R*buV+c=v7t*5|`# z={^r@Z@ZO?TqO5&cmMMD8xRD2zQjPWi|rQ}@ji#QHN5UU`#wj<QZb|vMkcN4Vh03% F!Ji+wZMOgb literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/app_notify_none.ico b/mechglue/src/windows/identity/ui/images/app_notify_none.ico new file mode 100644 index 0000000000000000000000000000000000000000..8dcb29e7a66f097ad2f67b181bb352fb2421d3d9 GIT binary patch literal 25214 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�Jk?KB_&Y&gD^@AzC#JY_b4$ugpwja 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 Nl|lr5Zx?I${{ZwxG8zB? literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/app_notify_warn.ico b/mechglue/src/windows/identity/ui/images/app_notify_warn.ico new file mode 100644 index 0000000000000000000000000000000000000000..9d43265ef75d08735e0931053b07553fa7c5c04d GIT binary patch literal 2862 zcmeHJZBUd|6h49|lND4NshI>trj>ok^a+8e2<|#UGKRK!%`w|4bS!rrGKQ%c+W4_M zuG12mQtreSJGdyAB|5ygHq3wyC^&x0$3hD%>;g+HuzZ}(eOcZKe`G(L@sD@s?z!jQ z^E~IAd*8X|0!)KI2n`J-IUN>F1BeD79Y_y`?Lhzvnw!wWVf%D|su=)_xDEAi>Ku1# z<7<;Gn-AzO+ds(mE7>$rSy>6l*Xa-a1N196F~L`*rv3)@XtDuBN%m^BTB9MmkNi@t z22m&J=JVTBWIu#tM^dAkz-csOL^x5Bmmv+%Dh)^mb14QQ`a~RCDo!k<$q-mbTNOh6 zKYx|9+8kIJh}axBb)SNzJfs2bEpGt<0T7d;h0Lm2*yiv;jJXsX4hQ7AePA}5L4Mo@ zTCEn63<XeAQv;b~qqLNQ(c^=7YXxk{)xs9L2MQc+$SSXZ45tsgUg9aRz_n}FAd`4f ztmP1|H9`hqZ8jTN2&->&fYI#*g~<YP^Ko#y-C(s^K~YfyN|PDt>+3;9TnfDbRJIyO zBEFQ;3XrR^AUf9o+v@G0=iKF0kYVNVj6;Fb11i$T$H&2Lx062~Xzdgi@uU+rp66Lp z4@!z7iSl$houDNSi^T%zl&8U9fRzRl)YjI5oad(1gOYMnmD^w!ark^bSV?g-Ha0?* zdmNJV1+a^_%-(S@+MQsge9|n(!Q=5jX(`2IG{U7zmmpnl1i8ryX*`Ck98gibCW_Zg z@qR_T_u9Q3xLZ5GZqq{Fe`FP7Pp3TmflRb~ZqcjnF&6&XE2+^zd}7m^Yd0=Vf8qXx z3nJFfS;pA3c?ompE=ipK&Vq=DImwL8OIW;wvBdeCm&V3M%wa5HP0WjoJrp?qv7qSK z^^83_J>+@DV&0ye6fFyirP0dZd5k?d`x$xI1{ryHBmSxT7<>2i882^$3ZoEKKl@g| z11~-CpkiIrtf(-?B4<WE9vwu!lOtBlisBJ1kBlNFa-J-k#dQ|9B5cB9S%j!h`Mb0C zZ1~+e#@qVcoU23C;WErRAt2N4=Y>Y>%Ad@b-`s%*|8ilW(}Oo}-mJTE<Hpik31#ZN zsMwc>s*``>27SJS-*l)5b*(Nu*x84Lt^uTb7u(v}(B*RN_%}yfRt_%D(P5(g0H&1* znEay!*O;uhwV?&SaQux%*C0||z@DBS?Ca~p!NEZs9UT=WIbsOAT$hil@=Uny@Ci&Q zIf<#I6-f6p?sN>G&NYO;5}xXa$T2W5fOKE;IK?)Jr8<JC<ew(R{xRV{ad`3Tt|8pt z<HOF*PO<m)_9E3W37=pv;i`icOg5Kc>K|1S{zH2|Zf*18j`ktk)9n*;Z*6Twsx4w3 ze)kZ2z=AP9mtlPIDWv)(;S-5Z=@`UMJBIPIt`Tf*Zsuno@^p1|N&dNCne`OPe>;P5 zI-`V_{c;R<b`0Terw_k$jpFs|*YWb@%Sbf}sg6td^rNS6<L_rsQE?Vme^(&k(~6Ga z-mYQ%);)sXd&ZFJ6`ntT9<N-vf=x|L68`g(XK=UeEM`_WU}jYvDvOR{MsXSLYih?I zdVP4Pe-zCFV|d}h1+1>F7Uk8eS0#K&Nr|qoun><NIfAE8pT?G!7Hn^C=iiCAPyD=w zhlj<pqxy^V*1(2_1_{sik=`L|^YZd~ii?Z!;>C+o_KBa@B*)0eh?xJmbLXbuIY)ke zehAh3lDfJ&f#MS=4xyu?L!j?Q=<n|r=(`i>yAj65#)R(fZh>R&M3e5B5PHwe{D1Gc MY<kaC`rmW^0DMoEG5`Po literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/app_state_exp.ico b/mechglue/src/windows/identity/ui/images/app_state_exp.ico new file mode 100644 index 0000000000000000000000000000000000000000..b365b6bf3287846dece7a69de55492169119af30 GIT binary patch literal 2862 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 Z1pY-TXM`~L`~9C`;FyhUGAB7@{{*b#F(?24 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/app_state_ok.ico b/mechglue/src/windows/identity/ui/images/app_state_ok.ico new file mode 100644 index 0000000000000000000000000000000000000000..8363fb2c59ba6027c730104215c6e7d883308b1d GIT binary patch literal 2862 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 NP_xehi^K`1<R1!AB?|xm literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/app_state_warn.ico b/mechglue/src/windows/identity/ui/images/app_state_warn.ico new file mode 100644 index 0000000000000000000000000000000000000000..3510e5a5ce79be55a395a1ad97ea8da2a58b70ad GIT binary patch literal 2862 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 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/cfg_applied.ico b/mechglue/src/windows/identity/ui/images/cfg_applied.ico new file mode 100644 index 0000000000000000000000000000000000000000..4fcdf843c8c4a41c4dd55f3e0ce0707f99a6b63c GIT binary patch literal 1406 zcmc(eEpJp&5Qg6-CE1XQ)~u?4Dprpmwd<SIRIi)x4{8vriX|Z_Ij#ao5Sa1@Rw3vl zxUHe8qDiw!Ti2w4;W@KggD2d(b3WcZXWr+|xmQ}_-rQ7OubxOlMlXmiJtNjMpsm5O ze;ltpPNxz-O{dF_mZ4^|nPxv{y8Zr1>+9<p3<lcR*wEJ2mWIQjwzs#nv$LboXrzOK z1MThYX*?clcXwCQ*Qx#e)H}_Ui_o|EjpkQZdi(hcMn*W%h*(Yy&Cm?Zx|Yi&j_&A= z?&yx*w>9*J-k3D>hEAtI5A;9}gg{T`$vmT+jn?ot5*eFJsj{ar7z_r3!C)vP7z_r3 z!C){L3KIr{!C){L42D97!C){L3<iV25)BT6!#YQ1RRD#)-;D?Yy+1N6j=5vxBz0J- z4E*T~92SSA$^wVO;cz${4o8&=4u`>Ea2R^&91e%UVF<jEwn~W4@@8J;?bU$_@5ZVs zHQo)ThH1l~!PM|>{Mks-@NRh5ag;YY{tf?ze?Ovzf1@@Hh6Y2U4*l4uN<BRaJ#9Zm zY7qDZYyn5$S4Z19s6oIHor4Ff<7QL960igifnmJ@uml@}MS&2o@FU2>nFK7+>rpKI zZRn?f21CM-FeD5KL&8w66AS@E!jLco45T4g4@1I`FeD75CeUF>7!rmAAn^~9B^#4P zP7Y`8aAf7~Yh2IuQIp9;hlhtcIy%zv@v+X%&UAWus`K-6U0ht~^72yG*VnqcyVL#s zy>1^;A5KpAj;B<&e*?WEU(I^nK20rF*VEOtu(}riZT=U}Bgen$bwfdZ5O0Y0#7p8U T@vw?t^hEafy^5+`ub=b>y;{N6 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/cfg_default.ico b/mechglue/src/windows/identity/ui/images/cfg_default.ico new file mode 100644 index 0000000000000000000000000000000000000000..d6e7f24e0d3228aa1738113f11352a2ac04cc08f GIT binary patch literal 1406 zcmc(euTNW16vw|LENK=5m@34ETJ=#_JPD>6ce4KgGf{<JvZTp%h;7Nl40@t!VjK-- zC<F;<GU`Ys&OZ0N)-2d%uf4y%z3+TK?|WaREk3)us_X3wY0T^mtxK<HTN=^VWEeN| zt<7>K@zrcL4D?L3SS+;oxzOW}&)VMJ)@U@+&d!eZ_VzR$kF~$QuY-dFO(qjfr&Apt zAM5DoNQZ}qn!QV%oTNVJTDc5;zy77``+L3r@)aYaIjzxRSQ?t48Jcx1hb@lo=#K8_ zj^1x;=ncKGXy^@{L4h9VfgT8fo~)B~MmZb3;cpZ&ZZf6Hp3Yz}7z_r3p^#uO7z_r3 z!C)v%7z_r3!C){L3LOT6!C){L3<gUyI1CQ!9GR5>3S<8?TF}t@Bg5jDJ4Q}XhoxfR zM`z-&I4l(l91e%W;cz${6%`x~gTvr3^ynN8hrwY8ypp~m#Ao=hu6TPoP~qL!RZ-*J zU}~5)3>r)g@5YafA`S0`cO6H0qvPN3Z}|5kYWO#@X)rVx8aec1Bb9o36h``fjARh_ z1#AIF;8#c6ImjU3h|a--)p2uEz!I<o5P@O60<Z)(2AcvQVBt%n4rdauM9-sG`rFV? z0S$(PAz?@u5{87KUMCm=hJ+zu2pA|sV?PWDL&A_SP@0AgL&A_SBmjwjP%ODI+2qu4 z)(%Hj?Y_tLTAy@!daARtGo7EGYd)Xr>gr0DmzTP^xzX+It?usb^ziVY)oP`urzbuB zPJO(%;D0<L-Toiw1NCav>-J@8xxQYmujRM8mj7-27te;{UybWP*7*!kJ*N$MRfOy8 GhWQ`3QQgV_ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/cfg_deleted.ico b/mechglue/src/windows/identity/ui/images/cfg_deleted.ico new file mode 100644 index 0000000000000000000000000000000000000000..2ef11c7d11ada0ecc655db6d6a886301a516cf1f GIT binary patch literal 1406 zcmbW0u}fS*5XL{jz#$ge94Rakt5{DZq_P)mtnG&U2R11#&DDW`u$@H`NRh_B;2@A9 zPOVL>ECe}-c7_y_-|XFsMXKbzo86u7?e6z`v+tx8?u`xg>(vu!%;*JC(lcU3BicS# z^uu^%NGB3MO(u(umZ4^|nP%T-y8HG~tE;OTjYe8uU)Sd5rpDv3wzjsky}hlSogEz> z9%_GoUweCd+TGpN<aO%cAoWfc%6aJP#SdNF-01D6&lnluL?dF68k(UQnw6G|DUR;w zj_&A=UdtMKLvJJvy`j@7&;vct10m3pJjpY<v(Xy<#zw{>Q>xq37z_r3!C)|SBp3_^ zgTY`h7&;~l27|$1Fc=IS9R`EJU@#aA21_(J3=S)f%w7Q$`nnqt1bV$PERMNj<ZSA& z^fK_!88|EsOD_u?4u`|xa5x;jRB$*94uiu`rE@qO28SW=O4?pRd=@u(FK<-`D!d!B zda3blFf~jY1`Vc$cjIAWlZJQ0yB|mQM#sP5-|(*^YWO#5(_m;YH0n^tMpgRTqtMgV zF;auTFJKEe0>6H=#X$`MjwlXZtRFXv0+xU!fCvoxCjd*ZFqjkw0SiBZeK?bVC8{2s zrM`wb1vD5EhJ+zuNEi}^{yD)AFeD5KL%_f`1oL4?7!rnrfvpL27!rnrApuDIgUynK z$s}hFCwDlq?_G0T&-Fn^M@Kq7KGt+P)yc_;&d<+vc6O%A%S&BdUFrJzTDP~iy1&2I z!^4B_ex=@@p7KAQP~G|uRL6cjt9>g?&6n5O@|yqb*Zf~|sa8nCdTc8Flh>GQZFt@v vGUcy);91TeIBIR}@t80ChWvl~WkHtp!QdtFlz2mYSq9@oOP($2_SpXh;Q->| literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/cfg_mod.ico b/mechglue/src/windows/identity/ui/images/cfg_mod.ico new file mode 100644 index 0000000000000000000000000000000000000000..65e3691ffe37eef19d71f7f78ead1365cd01450e GIT binary patch literal 1406 zcmc(fF;7%c5QPs3CL2Nl%{FYIR8mhPEj<YhHQmI2Kx47S1WQd!NNz`=CKfjQ0k^V{ zsiBdIf`n|MbR-tzcjp0OW$D|Ud*7VBch2|b?yj`JYh^`sJ%1#PxqC`<=`pdO5o6s9 z^WFWzT{@L`YdRe!Ms78m%{2Qy)6Z`owYa#b(P*UQ<z=m|u4+6UYciQ=eSKXU8yni) z-PQK?wzjsmw7I#d>5J6PPU@XbmGjWo(;qs$ywuxIpD{ARiAKbb8k(UQnsqIQC64as zj_&A=-nTXMhTcdTdP8SYpa*)O2ST7Hd6H+8voRX}Mj>O9DOL6i27|$1Fc=Jl1cSj~ zFc=I5Lt(;TFc=I5gTYYfFc=I5gTY`hSfasUa9HQatPY?s_g5o=K<|$Xi(~E>IYk|o zY6BlSHx7%#Qf-05;cz${4u_*!1&71nFgOgobq<Ha;4lPU$yhDKXLylUdwX}F!n?7m zT8(#usbShMXfQRr8y_}`G`t($bsXi5j(@|y;opy_;os;@gQ3CD=tDm?x>8S%!pzu@ zksbto0b9Tk_|?&N4tfx9MCaha>bThyummgtL||B70a${K!J<G2Sa=iE;Y<RS==~^` z{%z=|fCfXtkT4_+2}8nAUndv>hJ+zu2pA|supWklAz?@uC{3WlkT4_+2|(f>6iYTH zi<}xx?r>z)?rU66^g(-jd)nXM*TKPo4i67?a&n^M<71tjo$37iTo)G?y1Kg3_4T!G zZf^ARSL*%I5x?Up-R-}DK2fi-Ubm;I`R%ndS*mOPtgiWg%kO#kcNvg|ak93y_E73M m%Kehc|D;Rge-(JRw{N;#sxLI;U-6n=O>g5R^DE*F!M@)yXTp#G literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/cfg_plugin.ico b/mechglue/src/windows/identity/ui/images/cfg_plugin.ico new file mode 100644 index 0000000000000000000000000000000000000000..710a962980673bb3ee124dfabc06edf4958888c0 GIT binary patch literal 10134 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 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/chpw-dis-sm.bmp b/mechglue/src/windows/identity/ui/images/chpw-dis-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..230ad36a406bd2606a792c457e72942867da5bf9 GIT binary patch literal 822 zcmbVH!3}^Q5W~2DPe*V92Jr9vu46+<Lx7ZvBwVh&wg>l<_f$?sy>O3uw{#Xh)j0v{ zyE;LcV*csj8WR|0DlOV*lp4Vj*Xv29X_JjiBW)Mso2edT=js?iHl|KTAjxwJp%@Qg RF#?8|I*u3^{BI{)!VjzPl#&1d literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/chpw-dis.bmp b/mechglue/src/windows/identity/ui/images/chpw-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..43468cb2a9a68415137887abb325a479e485320c GIT binary patch literal 2430 zcmeH_O$q`r429#;8wldw6L<huZoHD$oa-3pbsi;6B2K9&Oraq^uOE-hT<?#)%;%!< ztoNk%sCOp^jUu-)pNkTvF-OK=r;Urn{?Z=sC*>b}jo-0cr6-pC866=>VubGHMy`9g zpZSf{=yNTJ%=eo-&=I(AH2K(_c5&MeVmhWY4xByUK@!`Mfokb+U)|;K!O|#tQ&Ps{ li(K^r%Ta6vw8_NxOCoh`2lQG{=OMQit;jbnmiBjhcmi)E#asXY literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/chpw-sm.bmp b/mechglue/src/windows/identity/ui/images/chpw-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4cc51e5794584f709d9d2c5aab0bb1a1cc92ad69 GIT binary patch literal 822 zcmb7?p>KpR7{ytaOix{=r<MuiNyNm7CEFh`F@ZoLP9P8n1OickoT!+XKq5{c5D3Hs z0#On~#l*yk3IyWBvKM;cs91Kqe0}-)`fH%jho|+WF=`FJ!?-?<3*%<YjpMqSC~w== zUZSn*hGCGLCy;^f7e(<i6XU1JyhjQ$ilVYCC&GO13GM0U0ZC8|=&f{^Rzc!Ls;Zh2 zTJ^*iC|XL@u=>P<WQ^5yJ@II)m=n8F^_+C`C6H<Q(KO9rl=zY~<))L9O{&V;7Hro^ zIVb>RmSvptVHi5GCno)?06-vdWVn=j)cqzzg~{&4eIvIH96gdpJ5c~g905=1bh%zk zRu){3JCG2z<hovMhg_}TdYpq4Lf{CoF3<CDN8oxKgZy47xlp*D>RX-Z;OBqv-~JcJ CM>cW* literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/chpw.bmp b/mechglue/src/windows/identity/ui/images/chpw.bmp new file mode 100644 index 0000000000000000000000000000000000000000..43d0d5ed940f0216e399cacd57c024a82d9e3a60 GIT binary patch literal 2430 zcmcJQA#B?~6ox&s4FpfCRya)q1_c2H0YOux1r`(-6a)kW1Oylu7#J7?1O^xc1Q-Ma z3<MYi1R4yql0iVgfPq1PK|s_my=uL@IMNiizurB)dw1{4*>}D)f4LuxXVvlFX<um< zv=7E-ykY!&8Gr7)xX1UA@jlqc1Fmh~RW@5K^nlxL-&Z%u?RC4|PN%v_Zok*-wA;7U z#IhvUbsb*9a4`6DuBe3|xxVMI-pORLE7NN8n$_di>~2Rb1j!A8fTuX-CfUxKY-^(; zFZK{TF_~jJwI%OiI2^Kd$J}YUHN6aLMLFEYI9J_xz10^>Of3Yt-qC2p)*W*x=uR`U z_kdZ!N(Jsb6Hvv4Ai3l5*y;C6xzt!rV%{y35g$Vp7lPzQQRFxd^sS~mFTz>cau&7L z)NDq|h;4s4jaS;leYjtl<4EpoHgjE<u|m`3O=wz!Q`WeTw7CVf5F~d#|Lu8R7={~7 z9XB$+buSwpfpy~(<B7=-JHbqwyP+0><i>IA`#!suX-d;oyhv2yy45qkwD77+o>6UX zMlA%%T`rd#VNP3mLiOgYS^I%MF`iNjL2{EMA&dBdQe9ouP4g4Jbd;njmt1ZIK5#aa zgK?gyg&?^+9S_2FW}ho+AxQ3ey-w2ycCU&cNbcV^lH}%ZB+1oJc$HXk>5K3Eylx4X UROv<a|49YKAN<e%%T^DJCu(BJmH+?% literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/disabled.ico b/mechglue/src/windows/identity/ui/images/disabled.ico new file mode 100644 index 0000000000000000000000000000000000000000..6b6a9078c1dd7d32ae13c81919d5c85046256023 GIT binary patch literal 2166 zcmbW2ze{9S6vxl31{EY~BPoP&EtXi{N(fA_7q+psyW~HxS#V%MvegI+!i5mFNCGL+ z_!o>UWFTHhr%i+nQ*4kxX1W)4@Z@vOy>B!jMaX?~f1K|<KR)li_f(`KPh@+0U9A1~ zMC2LsdNJjTk3>FR5cw2soBlbyBa4hQeA{O3HH1~)f70*Uiq6GiI2<yYqW%+AThX~p zvf;nAlpgyfZ*yg(*k@HRQ-q-kb%9(Q+Kp-#ceYkafF&!D#UY)wkt?2n&3Q&kh+Q3g z--qg8d8*ik7Q1Gc@7D}wTRt0^=Jl|x#ADkWs$Fi&Zo^mgHgG7JSXjbZf<@KayRr>D z=I-u^RiiD`teVA4+TX3B{jZUCptM;}b-19~@96!)@MP9)db94V*R0)lCri3EeW`=# zCH<Wa#*>rLxap0?v+ihozc!lc(qO7D>6e3vzFTWfCKgG2)3aQb({o#me>8i~*Xi5z zjx00!qRj2O)0%yIx#_&$Hrd6(-t*xvLz(>aoh&Xc%JTBEtgf!g#>R$hZf?rf)|Tw- z?8xr!t{fg7%E7^b?C<Z(-rk<{U#L8PuJT&0MSsuo<MkhM{r<h2eg6X$0zK003Fcx3 zw15`Sf@yq1<`U5(i-;c4Bf5np^n~uu7(JmgNk-4;8K;bp(G^><HGAd27)TyS6bK4@ zw_cthzz|>vFa#JJ35EbefFZyTU~o(r0t^9$kkDapbQl5*0fqoWfFURv9087C9Q=)d z$|)jageAffVewmrB~m<6D3Ub7;>W;dWD#MBu=ugS5#fk%L^vWGepGNo7$OW220OY4 zM}#55ko_-KE=Ne6a$)=N+UY<=?S!8nHMJ8=iK2-D38qBt#HM{miQ0+UOmwS_PW?pv zM16ZiiTcTO7!nMLbFjz8srcQaFf-a?<P0+PGHe-+Og(?J#=#k6II?kYWB#}a%CKZu zG7y=9{tCd73CuWUgbWKmI(c{|8J2A4;Vkwx*i%4*L19oB6b6MsVer=ph75zkpfF?@ zNJGaT28BUkP#8!}M~6XSP#6>drG6%v5~w&uazyM1hk9=FiSkswm7}90IX*s?)6-Kq zKR=hNt1G#<xR9Hh8@au`mGO8icXxL(old1`8ku}h`R2_VzT-ZpYu|uP<a5jNnrYU* zwP)7m8*V))b=3;(%>P@DF}udvY(^`THF+NdmR6?<556wc!9i^8zSY%2=CPKeHOp$g z+Xfe3w;m661hcNlWJ%=Lw<2$+BA0)PeA$S6^+M$9&qM~Fi2VFYWOP}4%-3Qp_AiFw BZvy}T literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/enabled.ico b/mechglue/src/windows/identity/ui/images/enabled.ico new file mode 100644 index 0000000000000000000000000000000000000000..22821a8b78a4e279660ef206e3b920dc4946d893 GIT binary patch literal 2166 zcmbW1KWj5b5Ql#{JFyEBy>46?q_~LV!quX}m4kc3+qibO<QupN=+d|j1Pt4~MG{Dn z#$O;JMT&T9yNSWz!odV0cY+8{p4ro%dqqe>PMY1F-_6cEn%k4qQKf$Wjr{tpl0IR6 z)42Nl1L>nR=~J{m_8HdEIwKdc^UK3$TUgcQtGf0T#)rjdG-7te%2#H-!uYu4!~ePV z_V)VieJg&2zt_6I>ig|>f)&3i{xZR;-`rj%Sn*4^4>JN^_FFzKd&^KFnp>{UHk4JP z&I0<h9+k<jsw|ei%0~Qof~tvH__JM$1jTO=Ec|(b#fIiiGghsNMfo?s;asMu`pflV z#TjU>(a@|uZcIH+M$cZ=EjHDLxlOcIY^;vCJyf#shZ;^cG@N#IJnh!Uuf4iwy;0A8 z9Cghe+&0X{Zfj-}w~pBqe@c<pp`UX<$9=4$O~$fl=J~oacWXb~80Xt3|FH0LKKgZ} z@h{(LeSKY<o15C&+S2y+wsv-Qw7a|O-PXaufzHm(bb5NKlamu29UZCu!u0m7>1*A} ze$V>(_7B}YJ?X3Of1pCZB9^e+xB)Go1+?HA?~sQ?^vEKjNA!s9+Y)+0PdEuZp))C? zXY`Do5i+{r8@}aIIWPv22NDG~1>W0Io*}>xU<fb-7zz>$0fqoWfFZz8FkuKV1Q-Gg z0fvGOLx3T`5MT%}1Ve)(z!98-lK@qrh>Q`I2up;e{A5@n#Uq6xNh2(!4cv?@A}kS> z(iS)(91)HPM}(ua3XTXvgdxJ<t&4C(7$OY0{A1;&h16+2_@%wx9jK_Ch%2q8c7iEU zG*KYIl&GD!nW&wpov2+NN2!fY{Y3pleSbuW`ib5o7!nMLKKNs!E9KXtFf;mNqz9RL z8MX{Zre1lp&Or|{9N9VeVdZhNDZ`Rs$v|WZmLmX5W@9EOBV<_kV&vhOWLUEIqp<jC z@TY(VgTY`h7z_r3!BCD93>gN4!C=TRkOm_j27|$1Fc?UUp~GM>7z_r0Q9qN+*k}Yr zazy+Hhn3tO6ZNsa)%p3kE-o%~d3mX;t1I2y-01rHT6cGMy1&2I<Kv^ApP%*e@}kLP zqVb=mZ{EG*J+A4lzXLvzuXvu<UHAUOwZFgLj@mywJZuT>wuHuA3IlGs&9|@~=sjUT z^0rWF{k`C!^UEXJz6OK$+<DwT&P^Yr39T3prH5nw_j*`Y`e{RYTBA>2Vk7JUd%=jE F+h16w9dZBw literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/flag-critical.bmp b/mechglue/src/windows/identity/ui/images/flag-critical.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d643fb31799d8d6ceac0eae8315e7bef993a5745 GIT binary patch literal 822 zcmbVKA#B_*6iqYfK*2N(RK-I>g@py>D;yXoC@4HoP!LcM5O~1gK!8Dj!2yGSfPjE# zI$&TB;7I`i1_l8J0RaZ5y~~fPk%8^&`{()nXUG5B_up<mM2p=be#Q8-j*IAe;UnaK zexyM}6#e=yd-|I_KE7w(H-6b}i=vq4c?xGgolXzUyvf7OApny#O#>M%Ns<I&<J}bx z&#i|5akCGvY6KR&g99+eNS|fdG)?za*svL{olVpTAo~HB$YvOD2GTRO8^>{Q_Io|W zJO5CJ*4b3MaXSA63}V$AAq43;=V@yiqph`vuJ<S+oXD~ErS8qpBPFFIeJ*&M+Bmb= zit8ajx){Er_fo5ErQwA<ta>Tpw1;0ZpX*_s*A@6Q19(eWCfD<{Z7b^PxR_81wWD1y zfc)5{vby6PmgMDn9;H-W*SwTpcHQPpr?o!zrn5t-b)0k{kwX8mADzb-!$ooV+Q2`* zDOr{`OkZVPS(TU)zZV?ak{-3ApIjT%i)H`=z|mn$0e;jTq;r<^-h0%Dmbm$RxoUKH i3~&INBBEE2k$!0ingLt*dBOwOcka)Npfu_KDgFjV+C<v` literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/flag-warning.bmp b/mechglue/src/windows/identity/ui/images/flag-warning.bmp new file mode 100644 index 0000000000000000000000000000000000000000..edb3fc3c88595f8685a3188ff115b9131611ca2c GIT binary patch literal 822 zcmbV~A#B?~6ox&G1w_+OHBeX$4HgU*RvH~B7zhXq2rLK~2nZ-J2rvi;FfcGMFeo@+ zO$7!91D<4X;DG}VJaFK^fz$r<RawEv_VnNLfA2n@{9bbN<@#;*9M{MnvEIF`H`&E= zJ;V8rxh^ea*{}bK<#O>?Ef(L-_4CE+^{On(5Q2{<rIfw~e-+Z_2>TMo7-0I!W^)gC z^!zELwPz5>;J=H5uY@3&{XSQIyW4v2Z)3XjC-p)gVQL|GEgGTY@u+;BKQOapcNgLZ zNp~T1LOUT2a^({$$c?jARVsft6dQJrb|j*bNrKmpjxplhmB{EUj+&-ceqWb!PIEb3 zbzlN^=GjYW$E7e-JT}Tdm}cf8bSbF-AO7%$E$-3NO>dO%x~>?WG!Aw|?-&;X&z$UP z8ZoySr|s~h{4n$wZ{C^rKFzG$6B(L*I;y5|W<82HLf}H>r*Ygj)qJogS*h9<ji95t zZL!t*uBrQ>S024%o`ti(TFjLh2AbGm3$q9TMdwI)5z!u96ilY~gdZ1z(JeBD226Rt TuS258AD|F|d0mHB{-5%1wIE^R literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/flag_expired.bmp b/mechglue/src/windows/identity/ui/images/flag_expired.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a3a40feecff222d6782d44a2e13ab4b51114b589 GIT binary patch literal 774 zcmX|;A&jFy6o%Q^WW|ZO&5F%t1>!_=L9AF&u>w)CVv{o`Dk>0&6%`0XMFpaw0<oe3 zQGq}p5Qqu{0zoba1i6gpB^4DF2m}IAQ9<q>-tGN)^ZMq!ZyqzRlOH$N%Ahg)cdT2i zuUJ>g1H7XAW{UEQ(;5<Re+JD4nTC{U8t<kF`yUvy8S+HJ&*$%!W$iw-TJ3CG8Uj)r z$IIms7#&&Ic3szf-)C8`jyiTPn3_qu7uX^RozG`r#IGC&Ti?I1yFGi}s;}{UUBJ}W z9eeVTL<xZBZHRYWH_uzf_o%Kt(Y76#w{6%{fDR}L(S|`lJPuB$HDKG#aWT@yJ25SU zz5L8@3P2P^#0S35A4~96btJhThXIZ@UR@L?dC8GTl7x6XpYi-r5BG!Ct{`~pcer-b zv}_bHUSwHDe3~YVr%VgVvUFA@0;WZPF_z2a(siAD1<&$4C%!0(Z=(bs)!*bP*v4zn znRqWa%95U;8}UL2%Ziygj6(Al%k+3W;To7yUNrnAVru9(X;oFk9}b5w44=oC#`eqD zpU$HXFAXALE=sQZ=rft@@J6&H9s|Uu+qO51UjDgSEN2cwaJRQC6s4M`As#QH+ag(2 dz2o${E)4;;BmlsOhyR!T{GqV`fDluf;J+)g&ISMg literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/flag_renewable.bmp b/mechglue/src/windows/identity/ui/images/flag_renewable.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3a9dc386f2892cb8eb1d00d4f93c39a2ae953cc6 GIT binary patch literal 1334 zcmeH^u}d3q6vw|7C2cI_2AdQmt+f?e^TR;UtJrcqLu(-+L{B(DVv#5ZJuodQ88T$J zA%nvWH{6gRLxv1D+;BsN8*aGah731k$dDm}!wnfSWXRx<_E+s7*gwGszu$Y02k*Vl z_ocGz3~r2_2Hw$#`S+&q__i>0>+b%m$|}T`2-CJuDwSaMEhN<>N{tfw{XTSE$7W*_ zrf;Hbm(d&b(DGWS89K`CG9;-0K@*@fst^nTqtOVC<DlJd<NEp<s(OiF5J2-ZG@DIW zt_9BI;Q1aDPeHL*M4?_ls>-406=B;p>h(GlTY>7UP)(Kg9K#>_7!HT%bUOInDnL;x zV09LXp}_N8$g%{nCc-jJY@6FiUMArNE;yA#tyZJESD>3Z-B&`vC}23Iz4{$YCKKqI zhF}=Lc5G-}4VtB)*Xu!cWUvYg%dt?V+O)1(C^yRpf&ewD3ukb!+cwprhN@5bbpdKq zg=mOyT^Ih9Pc@iO4O9#U0~m&Zl$C<-w{dn>gjAQ1zD&cR%*{pvRi_HAL+6_s#^W)% zgDzzrq1)|3wq;Zm1r@VGc|C}A%4%6iTWN3_hYIDBDcfi~x;gIzzwe&;A%0NczY36h z_K9K6lSwAYoHGn9E*7MV3;s=his$*~i-e@5r@sVV$e-|;48KLli@9&H*#1c@vmc8^ zmI>L4XU}r8`(NVgx%CeVge=d$3{7)9ADx}w4y_Tgn@BtfM`<44IX<R!n(u`rnnx0e z#79EJN2jOZIZ1jS{`z`jmypBf3rFmH<nzwV(ZbtPLVoN5OKW=@KbL@KhlGT(;aub( jmkUL5uMV<=#G`zQU&-fJ_!T;Xkmz6IGSl2maF6y6xZV)6 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/help-sm.bmp b/mechglue/src/windows/identity/ui/images/help-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..582bbb0d877a619a830f8696b8c057c04744653f GIT binary patch literal 822 zcmZ8fA&jFy6y;b?PHiqLDpp-iRII3|s93RLldC{hR3H#55ET^&L<M5R3IqayKp+qZ z1OkB|7X$)<pa}v|fj}S-h!Nx-OxwNO%b(`G_g`li_^-cL58R9uet%+pzpiiGkJ;zY z|0A%)433j!NtUjqC`#b_m&;|m0o=B&djRC1D6Cx98HT>@$IoKi1XFFJ(XPgB7~8fb zgs_;VswmI%u%%s6-lR*9YT2~}n=Txhw-j3$hJhr}b<;HazMsOzprsVJJq|Xf+h7o^ zA#Z4hQ*<5wDvF|N2j1vN)(<l_UJt1yUvlYm=tN<N>vUbK#_hsva0<i5ZF$nbWU_2} z$h7Y2x{Bi%`L$ik!3BgBB!8-o;g_>8Y9`YpX_{tj76-osVSwb->_3OeEK709iX@^r z5msSVxk;H6R|)e;i&Z}dK_2%#I<fHKrdbXS?2T}x`F1$901#es!z2eFvn-3^MA&`4 zYj!$=7YXV`v7pd;l8p6X;>hEOvMlkUh~@IH%39VP&zE&;DV^XD%Xt)!&pXWzf+&ir zs$v(!Q@O6I8|LF?$G?crZ~I?cnQ;)?anQxK2zNK&IDBY8Ico1a2_^17RP6-EvMhvI p5MOPYfEk#^AP7$X0AmIR^LC5S^Z9(AmOH8I8t(zIyTb^=e*s`uBF_K- literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/help.bmp b/mechglue/src/windows/identity/ui/images/help.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c7a8a930c47c0741da3b3a968ff26f88d1d9e636 GIT binary patch literal 2430 zcmcgtEsUc;810R_6BR2imt1bes>_OsiWL<V6`RW@x1yqA1)>5`fj}TC5ET^&L<ItY zKvW<Q2t);<xgaVK6}<$3Kp+qZ1fqi6W2a^5ESuaVclYJZbmo2E_vW|E=)3&B^K5sh zzoL9W`Hb?e^9gmQ^9}wVU0R+AR6qZX{TE&CZR2@<xm-}Z9mUm)znCx2PZ`W5$@l$T zlp0|v2PfE3xesH<aRfnN;?bqjFS>#-YeJGl&+{PHvr3}3;L$DpxNu#!nT0m13!xgS zsve?v=#)e|0@v$O@Jo4Ds{5*jV%Mm60NpSQWf==QrL(&5Q7jjWB+GkNm4<xda4cV0 zRzUG2&3VTpiR*M$w?39AihApUXa#EIQwy`B7oSj*V7hu0i7{{tRDso16$QY4$$mjr z`L$7``AHN%lmriKqVs6SBifY2z`CwOfz{PkD<F!~u9gustCEWs$lDww1>+LD%Eh_) ze!qtTtBcWab@U)3N-|uhMV>b?_bQ&k4KG|c49cSc5mwhU&E0PIWG7@9Yr8bRw7Hjp zr*IG1r89r9sx0u>MpoCdti$0jFe0)DoqdvJX%mtggQs}Qix|v|)x{>@CJwYck%Kfz z7)VYCp27~|Rxe_L;FT_xP|bI>BhuCl!uZleYY(2n^4q<LY0<^M76&@kwnT8XO@O)o zzTK;*td@Pi#l~ooxh4GiQFSo}W45<5Tm&(6)$PtKWNrMQMHixg<N4%C1JFQFZ41+- ze0QodE>W*seQAy0mVKbpz^otU1{p8=g0^iKx*#d0idlOM+wD#i@T;{0U5K#vf$k<8 zw&Q*r&&j=bFRGi3OEH)!U?@b@prmQpH&608azhnZ-TM477gaYt45wtk-A+W^Fm2m5 z*VY{;p*s<m=)&g8ipJbL3h)L&KowZs`bxr$yS!9aSA#LRy$6O9o|j~KsZemj{CYH@ zuKt+Ubpv;)PG@zqhNWqW>#VA)(U>FGy;fZHhTKflGz~}6NX=MX<}Z&fmWH&&VljE* z2BU|Y+djqUVa!c=MNtgHz@9RRtS<U5pW8+Yr;JY$UMBhcpx|SO{e@y9>f9`f7F|%U TUYtK8s3_`}_qeA1N~7}&3xJzp literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-delete-dis-sm.bmp b/mechglue/src/windows/identity/ui/images/id-delete-dis-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..68850ab8797e9a8e37eccc9fec3d8f92917612f6 GIT binary patch literal 1014 zcmb_ayJ`YK6g8wz@(C&P1?dDyqlk-@q88#tQP;PKTKHHWprEEmFoI~It%V?1Sc#$_ zDq4sj{z%%Bof|f!SYw1-I5Tq@&bepqohR<&T1D|Ftq&6JB-~24Qr%1ISIlozDh4?Y zhXeit@pv3wuK<t7^9_f?LFaHdjQM<y&1Q457SBJ!<#K^>EEWqi8V&S%J=AJ7bUGaZ zfdFB<-70ECA`#?rIi%BRM59q?wOY!}W;2XNBMOBAg25nGtCb=@n-$S+x6x=cP_0&x zNF+!jpU)H5=ksB?Tq<%||0<OVMxzl1g8{nTE<{m;)oLX!^X2#Z(eL+9@?T%yu-omZ z#&9?U^UXYS97la%daOUQ*-TM`^`%~a$MJZ?WHLdqSR}5=WTIRU1nSLivtF;)sMTKJ zbUI<P*^o>ou~;mq-hRJVtou`sdE<E=p->2RyB!9D0n_R9EKk-bm&@pMI%qbV<lpUf z(;Vdcb9<>&0(--FJSLq~Dn)<h98bPy^I?3JvvVvKL$BBSvwy~GwOaHSGMS7tkNQPi I*~caOClXBQf&c&j literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-delete-dis.bmp b/mechglue/src/windows/identity/ui/images/id-delete-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..11aedd577570da0ec2024610d86ea48b80249fd0 GIT binary patch literal 3186 zcmd^>S4&(`5Xa4X$QKB~zy=W?#D}%uT6R}m%UaeF6?H9WbXQ%wqHFIF3$cM6v0_2R z0%Ad9Ls7wk^$Ykh{<$;Z$|?k0*N}%?m|G5<^E)$V=08^%l=t3>FDKz{E7&K&J_`2E z>a%eFeeHd)vLX|&o0}W_k7h7rAvrn4EHfHQIab%#*RP71RO$qOe}DM-`9Y;p!OP1V za=HA`9335DV`BqPPtV6OnamC6=jR9v3`AL3nb}-7H+N{YTDI8OSVTodAuKEmK|w)~ z$z*VLc1BuS8f<NCh5dNJ+uK_hcY|83MqXYX&#SDgG>a>jD`7AgkeQi@^z?M3rluk( zDG3n~5wNqfLv?jEYHDhr*X!9|ih)G(g?Thi=I-u}&CSghb5$x|l$V!tj7myMP*_-q z?CfmlbUOBv{1(@yJy}~@BR@a?aV#=25^Zg5FXmCrsMUdJX=!0=YHC7VT^;YCsHlkj z_weultt)a(pA?IZjt;YU#MEd)F)%QI{{DXS^z`r=&CSisAiuM+vf%3KikO&~CtQt2 zgZB1zvw6h)`ZW@>v$L3)nZe}bB!-8FnN9H`pL23@U~g}a;^N{bOo~5oFD@?3=4!R^ z*x1;>+S(dcR#q@KH;1vYG4%HKqQ1T!QmOO_k8(+jFYPBdIM{5iPN&EI{yvV5j<CDC z%k262d5$&J3B^}rP>o6?5`=_=JdWk&=JGey>q|9tb#+y!gLK^9-s0@+jQKP+Jv|Ly zUtg{fVk#601Ox=Y$;la|rKMcQG;TB+;p5|j<KyEOGih(%zc*oMXbAWB_c%R0#n#pq z78VxxY?VqSTwGk3p-?E%*Vo5uH#Ro1f20$KhlghI#CQ<*+qYEw{JDdjogFMKEn#$Y z6rG)&NK8x=>fQrCemu?7uC6W|92~rgCvx}p_5>}^3;O26x$5BHAjH>C(5DQXoSay+ zw#az?q#Pm*AWaPq59jlv+NAf_)Wq}kpMO)mkfxIcPz_K`BqSuT-qSec?DIL6erIH4 zpsK2hHIVY7qN0LzJS8QC^`7c<YHI3DxuKz<tOcY8gM)*dJERE(1qDJsPv+hg9Uc9q zOzIyL-}Uu%&e`$taddZgqqeq|`waC~svAq=X*!?I?(*`IbA|GsbZ}&31g)*DtbJl% zH=SeYdqYD5>-@vR1Fo*Fu)V#_T0}KSXG=P?yuAFTe$t-lA7pWH5qEcYti9B4D85uH qq<5D3^{4sNx8vjE5f>N7Eb3Pi6BB=pXSxs4fY<&@ny&M&-hTnh2Waa6 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-delete-sm.bmp b/mechglue/src/windows/identity/ui/images/id-delete-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3447d57a1e559b16e2319b71205f08cf86f98425 GIT binary patch literal 1014 zcmb`FT}YE*6vtod(nzTg46JUVl>`zw5`v(+2*W-GUgS+hS`q}U56pr&nMJy$bJG`e zO|;c0lu^)IO>Og?WHPr&+bp6K2`dVND2Oh8J?|S4$QBDa@IO2Up5Om@&f)B?{I*=u z!zi*rs8FatC{NlT@~===N|L7Ekxr-iA3E98hN<y72QU87zB4wxuDQ_6<YW|8eVX;H z1DD#V@Wv_k#MmN7DLCX|+3FkQ*WO}loeiVWOIcYjkw|8bqb=Rk1YS@*G{athk~I}B zB<VYOg^$Qz+bYgbS~|e+a46#+%nlEh@Ei@Jv(ziEFx?d%Mz`R8=&ZruBNz;4WVQKO zT^?>e|3FXd9aqNZIp&YDYLi!IHIL%rQDk{AEAQx%iOhZC@#{tUrr)!1M~BX?Snp%q zX0tedrKsp0fq;_HBauj8Z+9~F_A^5>A34<%revFoU3FGMV`EfRIfXh&rBWGrt%rC# zj@{|TRDYJrS~I7c+nAVmrr%E{lYeD3KCDLAfBq_aeAATo#@K$s!o%Q5*7ug~oyE~b zOJttQp;?aHf630i1jnt8ocShuCnIkb85I3%KH4rEZoHN=|3FcAqK*??_<}sOK((yU e@4u5Xuk|zFyN#`*n{%yh+@Ah_VwcV%m-;8)z3}1y literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-delete.bmp b/mechglue/src/windows/identity/ui/images/id-delete.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5b1b680300e248f255dbb16f991fd7367d2e6a73 GIT binary patch literal 3186 zcmd^=YfM{Z7{?Dd7Ga|hmlzNi(M^Lg7?6e$gO?e$5i+17vXyHu(2fomV;ckFK*`J` zFeNZ3mr`Vam5C_W!9<6n$faCbC@}5}xnE?{T|TH^{=VmoHsf0x>lb~K|2ZemIeC8P zdCqzM?|Xq~cT&vqCPx>d-9%1A7L+qNK3N?silU`oV`F3ZKPoyd5rGjxlO#+?{ztuX z<M6S&pcgL^y^!C7=kwICztRo6P1#;-gq3>~SlR7{*uG#s!{l(z;>3ybCiA^Q1n?{$ zfJeC&?qyoMUZTOCqCVyw>@yl+=@1Kw8ppO*1qQBbFb_dN$*{80z}osY!oyQd;`)Tf z;E-Y%eqRjZV9gMGt90<L7=)X&2iqNk2=7lK5X}>A4B@I^=X99x1~%h>om~bLidv(& zZ*yZ2_U$;hM4|O#;M9%6|H~1)Q#}M{ejc8&Ei~k&s3lnL3IS!IHN<Rf>v8JTC8K%t z%=kr!kk~SVgzu*zxj7BtjY)(zj5BPy{#OJAgj-->JgJ$k8(^{O5Fc+Ek7fo$$06(I zIegSUhl_2$Af@##!xtzg@jj{huwn!+3-V#Pqi74)#-<SxNv28l>3xC2I|*t3G79^a zk=L_?PdXQnLD*-0m|<!Txjuqjo+8rE(Jf4hT7j1r5B>f9CUd!b5xyGz6}5NPQ8l!N z63q&(s27o`nnU8v2{^IEpe)Cq;_05cUdR6Z(dg~%HHjOal#B-L41T=(8*WV9W7uT_ zE6C}Z$DRXXSXfRN7~6JM!Nw~JHapS`F^bxNt7|0GYPHea&dyFm#)zR^d4!II2WXzY z55>qj3Q50x!!N<gx`oNVomC0vsL$YXBow*1QaCtdZF2vDv$GJlZnYZCq`#}IT#n4k zIT%`d4AtE4_-1?qGE!@H*8<p~S$Nj|4BSQeaO0<;u&kWPU0PZLN5>BdPlD#=7L$1T zf2mw9M>tQ2x~?I7H+c^ggR98xUO?(kv+&Q7<3J!6#WMMp+!YlHD3#4yV)}f>p0!#n z&ZS(y!6N~9!;=jc4>o)c1>kf_I_P`G<}u|tl}ZJlqsOr~wGw*^y5N}Iis!_i;;mpV zG#ZWBnQd)tV3YnGt<fN$c7*X>wtRr`dse0r`}~5T)9K90O(OjhRJY?a@xhbLQ;2Mw zK;ZQ|c=MVLuNC*hUUC)EQkhwq0mma5FQEP4<BoY;Xq|<qX$rx_^L;7@@lt^r{t>Ze zWd=nEP)GcT_N32stHcKvk$!s?LgKshKI1Oa!sl3&S(#z{81yVXMEBxDw9MQ`_3#>U z$gCt0-=)3YyQ~Ksp4hBRX>kdP<kv9&;1BdIKSIOA2IKo_WIiLv-sZtgfU>E{tW0{Q z&Ye#|vAhz4tB;{1zCiCcX|2<EH|_(ZXI(ZsPd~?{G8uTHIE0B4a7-WpCn^SYU)TR@ KJU#cnaQ+)%qlK>k literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-dis-sm.bmp b/mechglue/src/windows/identity/ui/images/id-dis-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ee55b0f20786dd29a2ff11db0c6615bd4f984067 GIT binary patch literal 822 zcmb7?A#TJl5JlZAud1M;;Hn4M0~AK;HFAs`qF`YUU{Fx7pkPsDU=U#7l?)6F3=9Gc z3=FLP*iBVM*^TyVY>k{ZlbO-HyzX}-YmfU0=i&F<k;nW_@csL~obo`(`F7QH{k)~7 zX{xF!xx21QP)sp+&Dn|4(+9<Ur1W#P_rn`P3g7qr#6vNJ(Mrw*W3YiSJ{tm2!jjJ+ zRx80LxEMm<u&?7fpJMb*4MV{|YAL)mc)ZMya^{T`Xlm*$rFA|=XLPQITO~6*bq1~S z(T^x*U>v`IUov0hk<J;xId~;R3Zal!cq3&Q3);kZH~5sCR@3}BLl+p;CJ!cz&O5tE bj=<G^|0i7de|+1vSc&Vxj$tit-{tcUcV1I{ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-dis.bmp b/mechglue/src/windows/identity/ui/images/id-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3c04aa2fa9ce7d3d71eb6a12dcf43521dc09f2e7 GIT binary patch literal 3186 zcmd^=SxZ|{6ou`3=^rSCKK4m`2q_qiNlarj2_z0t(8M8W%wVF418P*9H8^0MaK>32 zP;mfJL5)!n6hv|S1OANFyHB|yEfmVV?MpB0+>nQSXYIZAIx0ipZ4`T?+~+5*K5+G( zt2a>}xz8U@<Xu!07607d-{XHQuh$2g&HhJKT^$tED~Uvk<m6;%wOVL28YCvFp-?D( zTQXUkAZA=#JS-LqtL*G-WM*a}H8m9mgMpnvtybgbijS8IVk#6Wc)eZ}6&1nlcEjOt zAU{7J#7|30LrO}@FHAb85FctZNvN%@MNLf&s;a6`US5vk;$k?RPUPj~G2Nv3wN{}_ zolcL=&Q4aLPzcS<&Fl;n6%|as&1OSZRu=Sn{R>wp(`YndY-|jpqoWua8bWVxFFHCp z(Ae0>bo+ch6ciM|Y&O62Stv6j!;F=c6)Z0=V_{(dlarH--QC^IG*?zuvRUWm=E7t$ zF|9&9WU*MWzrT;&-Cb;NZ)0_J6|=Lm7#<!5aT^*MP*zsPyhS}GPbDR31$oHnbm8RW z1n1}HI6gjR?6tKu%*@PSaBvVb<6tnzv|6oJrqk~a2x9K+?7-!6<Kf`}S65ezPrp&G z$H&K+*82K-`2Bu1SE=+f&d$yRF=@}*+e4U`n84H16D}_=ad2>e_4Rd3O-(URH8nM{ z{wkF!jEsy3=JC5t+^=69I64X=91df1bCdPAzrP=)rKKR>^z?iajmL8%kqDOsE^cOD z5FH(jn3x#m7q{Dki;D}<dBi0T$>nn96F&E1V`EtcUSD5}&ZK>j$z-4mC@Cr7eB}b| zB;`H*o{*3rI@9Cvfc!~0*w)sDy1F_90s+|VcBH4LLn4u2adA;pE@cd50Tt~?Utb?u zT3VQ2DRXr?9m`#Q_F}y0-lYES?d>to&dtqXU|;~WCv?xy-KJ8hMAb>NyScdmdFAx< zl;z;`^fbD<x<HxB-|J%N<Nu?zwUuSh^Yb%qZ*OsUc!;H?CD4A-Y?VqSwzjrJ)k*Ba z!a{6pY~b<nk?jrLH`HI+8_Hb%d}6;T(<#eya&j2UXf$Gee*UlVUZ0=ldUtpCPgt+H HVtxM(Di)S+ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-new-dis-sm.bmp b/mechglue/src/windows/identity/ui/images/id-new-dis-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d2a151c373c1a8ca7de594afd7d0d5548a26598f GIT binary patch literal 1014 zcmb`FJ8QyF7=|s~+x~=({RMT^;Am1&3r=E+w;*0nbP%<IcsD|WQBV<e5Oh!k5f>-x zqzJnBPrAO%IVDpqap(u{NlwV~p7UK8_Ul$h<5^js6g?=qS9GI$RMwyPywmB3)Ht8d z_z%V7arpfLd_LbVg~MUZGkE?DZnqmQmkSPu17@=sCX<PZWm!!=5{V$2%_5abAsUTR zFRRr`d5+^W`Ap^=-EJ4nW)szF70F~0UauDxiv=9_qRCe(6|7b(%;$3q1_Owqh(sbm z&$ruOHTjPZ38&Ku)9Dn8#e&`?m&?ImFdz^JQ2uy4V!2#i^g0|4Xf$Mu$72M8LA2X# zlu9M&^?Gc#TTCVsT9^HPe~~9Mu-olWtBG(ros=W}sMqTt{VSKte{$;lY&IM4JdaQ) z1e?u<*=z<9`FviJB_73M5&eE2k|e=sG(r#rv|26dIUEi(Jqm>aMxzlt9uH($ruAnS zhH_-Dl>@1Luh*mhllNFGM(0S)Z@pgA`>6X%&rYWUG7IT+TIomQ>fA4RUGwc5-XZ3z literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-new-dis.bmp b/mechglue/src/windows/identity/ui/images/id-new-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..61c2fd21abf89d775c0bdca75429c043ff708aa5 GIT binary patch literal 3186 zcmd^BSubN@7&iBlxpE<yOyWw!g&4$$DpgfWks`KGTP-b$3Sy5fb|UsYwjlNpf`~AP zNF)+skKgi4-*<AFL5<}kb2BG-d)n`u?|Z)IeV_OFDi6v3Y{i$G>C@g6-%Rn<6rZeY zO`pH7!!K4=6vB0VeU1My42B$NwW;rl($X?fxpH-NLttPa0s;b{R4U=?tAI=<`)f!f zo}w^4J*CiSG#qhpafptNMtFEQLPA1#4+@0>PeUs85``&~$zd=Uke!{4%*;%rr>7%1 zIT?f>5fOo)prB`%v`;ZQR4V;ZQBi^N@^X}vl%TM%5V^Uz(CKtYN=jnh#Q9IIVlh>! zV6?Wjax^tHp{}lu_fS++#Qe2dEn;F~5F8wA#ubaHR)=ADco;)NL+J1CM`vdzT3T9A zQ&Ypdb8>Q!l9Ga`s3>!u#bQQAMqy!L0rT_on3<Wu*w`3jx3{-5=i=gGuC-dNhFmUZ zu3|N$(IjAJX9wHc+gM*;$I{XgrlzJaFfahZt*)*{K|uj)*u%qvx%&GDh|-Wwr^nIJ z5l&7{aBy(I*vreyn4FwMZ*MQC#${z?jOFF!#XOD1{AZZw=jYGHUefmF<|g#|Ox)bu zpt-r3>$bSK$hjUF8DXwfRaM-tgz4t?1INe5=Jn6c&XAg#%C&z9!_s(TV-rS4M{##| zhrYf(I5;?fbUQvi&YG&Ntwm^PD4d+WV{mZLj5jec0cU4tuD_*qUmGLbw6t{W@Biew z`uX|sdU<(yFdB_;baaG^iwonet*s$8HWofUJ~%u)H1FXx3`@^xKGj#D@M8>ndwW=0 zTeJ64uTUS8FWK7KvUgZo<Go{~AwegC?@^v<FT!<ye~*NO1X0|CeNn$iBodGZP(Jl~ zJrWZWLH)71x+*|oYio=9N0=w(o|Tma(kJDwp`ihlm6h!Cc6N3k4Q*^}nDIzAySuxh zxrT*>u@{gZP>)dlY;0`U3sfo<YngO3H#f&#NZ+Za#PFnZlk&T=vch_#^P4ymM>=OH z@5E2QARnQ#hVmhdz4uPFBfoWbcSl!O7xxSGUt3!n$aAGqDZIVCAFY3Nb;Z6&y?c6k z`smqP@ayaASsM=z54gO%#NOT>=druHo4HUfiLa%#W@l$PHy0Nd7N1+1BaCHaWUxkW zZ*SRq>AdOb>EZtiRBzIj@b1$)?epo_TYr<MlYZjk;~9(2u<7Y(baZsEAHQ{-kGx0c S1l3EJOZECl&4l^?`u+=Yr(8Aw literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-new-sm.bmp b/mechglue/src/windows/identity/ui/images/id-new-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9fb17b98c31a33b7339b15bcc5f97f5c02d1090d GIT binary patch literal 1014 zcmb`FUr1A77>5_#XZPI*5kwK8QDI0I-9&_thGC$Th!G7ETi7UfF^yJowzj!{2V|+0 zWT7E}o`@KzrwIS-oS~hjD?Dtm3L@9A+o!X|M94Z2z3{x>_gy@{mk-`!H9xjmign27 zyA8G*lo@QXlpFn5O>eVU3Y1FIH2w#dy4=)v-sSX--)XYnG@ViB@KM#Ta4;HYk2uE; z-y6z=*F`GY+@^kuD?-y)l7^@6I61s%WU1^7&J_L1cCV>_)f>e*sdGKHf>la!W>lkk zK&3n|!vUM$)b9>PdARU}zW66@ze;oY`Fm=gyk%GWGSwYEQ{NjFk@c_izg%S?@fqio zPV=)R_BLl|bO=R1k<gH&<xR6xRmJ1$<=$A1^R_(QFFtZ{JjK4F3RAMo$jArm_AIlr z$xZ#j4k(I(r#Hl@)=ny`7C6_MLJ-!l*>bqunLm1^{h6GWsl9fG6GI91yB2vox<;V{ zA!q6qGMwHpE;)@|(m7m{<Ls4H{K0Qnt=}0O)J-$GJOTP9ax}K(ag1lEA5L=Qc)aLE zB04=i>Az-7ND_gt%3L;&IG?3KlxVpyzwX3hONipi`n&Y+jpu`*N8Iv9=nz7LqW4W_ JZgl_U{u4v&2L}KE literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-new.bmp b/mechglue/src/windows/identity/ui/images/id-new.bmp new file mode 100644 index 0000000000000000000000000000000000000000..54830c1830327fe089be0aa95f594f863fe5af35 GIT binary patch literal 3186 zcmd^=e^8Tk9LMSZuDZPABIVNL5{8)k5Lag)Wr3Uw5-?!E*k}qDKLn(tfFp}U^3oJ1 z!ccQ&;2?)aR!9NDz{bXp0b{t0O@7G)I$(ln_3ryT-gcf^$9nj$@7?G5-aWT{U(fsV z<NbX-B=boJdij#4D+y;3%Sk-pu#!CQua>7A9H_7^jYfn2W5g$=B7`fjD+DPSjB@1> zmH_7?zhVW6=fAuL$3yLS=3pD1{+C!An!t$ZwVe-7aVOS`RajT1f?KH)tB)z@Z&>!l z<Js<^JVs1*WFp=?r^c4A)d)D-gH30;;d`=+=DUa#a3b0t*36XY7xgZpFAN}xL}ZNy zVbXpCebWnnNe?!h?4)&5d4G`0;xN;>g)2nrk9ws1phNOy9R%MEB1Seqvnl=TQ(a)4 zP-6K5T&B$6_#}LM)r5j(6LK4k$ZjyueEy|DL=fF?o$JL$!gVd}z;lQ1=b6Q@hr)Qf zAnF)HiDC?gu8m@U>oD>Nd-qRzT61`{25*pByBGGsIY&+R^je0wjY<&WeE%&}_L*^} zX9A_laU5(PL4K17>4eL>s0HVIA6S_>tco|niD>nUh-cKd@1<uzrqZL{@Ea}-PSNbL z&T)L+HjEE{G14`D=UWZdWf-s~W)v$vse>Rj^ATou_u@UZwY3$oi94YhpTmCf960f} zA#S^c5|ZzIS8vccj;qzeD`N<(@CmpEMnW!^+n6fV0C+qzva-f(?-t|d<>CtDe^!j1 z2@8(Z%)-rc9?1u$Q6wLxdrCn1$$Pg6YuH^VDHGeymPm~7^qhrAWU{?m4A1%-aYY4U zcmhb}J*ZSo!9Uajk5?_=9v(rss2=VcYT@lYNuOO;r$cP)H2nN#(A=#3PdqDErBWd) z`+Woi27~44gH<o(<Jn~vYz{CZGIAbAkKRR4&}}$7FCZ<=jQ;+`*U-v%cyDTI0(;vI zxO{LLE=S~WDr$hEe+#Z$`2*HvF#Lt+=xIjUtlY-NM)-t8VcS_Hf-8Gz@AawZ#7h1U zs-*X<NHjG3iM+g<OTtXg&H-Q2j5OkdyS~4USkkNhMLM{?ynua0zvIHiyF~9j6cpSc zeY1f2`s<9j!8>AUFQEM3)0P_u*<*&|3-j=eGlP{gh!;1`faNg+snh_Wa1tIKbEv8^ zFyeB!d`O8Ooob)ND}fgHN6aF#&IoEwsC&khI|6s#%Qi+^n-*KQP9rzhzPYs4lG>va z5>Z||2QT&l4oGGoQBR<lcoF4)l-Iin^zeO6W@B3ao0m5V4rdAqh5a)lI$nyboH}Sm z??5p&2bp$~_Wiv-4}nYWw$+=yLP~1iBTR}dlj#u{I0d!Z{@Kaela1pQr_puOLVGWD z-|TJBVRO<)*dA4l!otzVGAS;TSv^r+4xTUx(K}P{Ha{6*afy&t*ARa*qPTeEADPx% UFXgUO4xppM{+cc2H`sI5-<tTzOaK4? literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-refresh-dis.bmp b/mechglue/src/windows/identity/ui/images/id-refresh-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..7d79343691bf8d24897c7d2c6ed7001bfb8728fa GIT binary patch literal 3186 zcmd^B*Gt@K6m{R1#TQ9nSrkhwh;<Z=eVnzf#uf|eNMegUHZ(RATQm{GhBdLoSRxWk z43;3tssV|?nyA5d|BSP9ZkRz_%_s@`vOoCdH(!~1zI)HP_l`2G=vM=ITs5Con(>Eb z{H__l7?@~2zddWe85nSApM!$~{2xbNUOrM&)6N~?;o<Q0_5IggMMdQg#Y&-YMR0I1 zf`Wn&5D)-=f0f`6%f!S4Mn*<(a&pqGaoxki6KiX0n3|fxhYugFjPL2`h2-R98HtIB zh>MFuR8$ng!oqO<`gP>w<jC98(-VGvelRsPmAQk11Kix)U}t9sYin!d<>g^>bMsR8 zzP?I1pPQSD?Cfl0WMtsZojc+;ZB|rNATu*l{JnPVn%srwxR#cdCTDqP-si@R8<?A$ z(~BDr5QysPYE)HK;lYCkC@n2TK|z7UlXtJLuSacdt=y%gqy)vq#li*eqf)7G_wHRC zenLV5EG#VW`t|GY;)aI)g~yK{%V=q7K|@1>+`-)39PRDxXlrXjYilc-o14Y9p`jrx zEiLi(?OXKq^}*56QMlm!=)YR62IIcBw|60KL_{P82L~}QFo53PUUYPHh@XLhf#~n= zM^8@=Iy*ac__nsT8V>Ds_Gp`&=I7^waiAv5%*-$|Gow3mwjSKR9V`1UUcA7>!~}+i zhb4B6jg1%^8<Y9a(2x$FF(I!@OG`SN)US(+3%tF(<+m#<D_B@q(CweaOioryoM>Zy zejc;4v#__f$IF*5!FxP<^hmg5j*u&3V`ErZS>gHf=VEhbXGhMFTX%PNi7T~D?VrWc z&hOpJ!ut9;Ha0e}y1FW{q#w*lV%yl*AR;0{a*15g7nSNy+`4rOuCA^!SUb|w(?x6K zpYx|rpI(T`7-VH-<M8kh+uPgX=aVN-M4#j-K0aRbSy)&o8dWG<#20FuzMhUhHAViZ ztNs1`3o+^M!-p*(&eyMB@$utF@rC)vTEjYX^X5&-Lq9*I@XEN*?z3mlL<{6oi%;!G zM@N4bPa9+6rl)7%{rkT~@6_t<?k={rw(#c78>v5Pb&BvnO?r8GAvQKv_FlbuCH!-p zx}^@acJ;mK7x`5x{iW7UPEO+J=m=lFe8HzrpCoU|E$z}r@=r}OR~Hu-1z(|1;PdCt zm&T-xZyHgFMp(;gYH9@c`1n|dPyczAI&yY)mKw%6xux&=eADjpt{xs9lH2$1-`D6W zOSDS;vnH|cl$V#ItgKA>kB^TJ7zf56BqT(1N)3#Rj9eO%{eyLtInO#r|B8x=q>jhL z#7N%M)zwK%$+7mXd^7IsJJi)x;u;wlDfY+{IiiMGi&)Q6Q&SNd8Y+2n8te3T#)+{x zy{7Lw`zC+4yu1wRaD03m-QC^NSJ-E$8>LctC7b#%Q&Li-7f>I}N!G#9(NXCu<Wbw# z_1U?~ep6GE)XkHV6XE3DyLXtLo<>(!mvGCTtgkO#1y6gHx?`VbPEz~KamJT*rLywJ m{H&U>?Vv6d$#B?%U5fVPL6cm8Ltkyqy4&$Rhp+WH5N!v&ZC literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-refresh-sm-dis.bmp b/mechglue/src/windows/identity/ui/images/id-refresh-sm-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c9d9addf15b1640dd3654fcfea5fe4342a43c086 GIT binary patch literal 1014 zcmcIixr^Fi5H+OF=1)kOb_G+|X>G7jR1m!ISW#3E6>m{c(M_>p1o6PaO7H>&u@J=7 zLczlGKS}%Yn+eLgn~)~?V7_bSy_q+R{OgbRB3@sF{j*>n1-ldMo#>OW|60!<L?W`w zI-k$@7ZwNv@bKV-!{K0)$z(8@Onmoxy?@PNHd|n|S{b9$=^&TOAr^}vl}aIzNTAhf z*_TSCa6BI0@cDc`kS`XC!C)}J@AvatqtU=<G+zH~HXG-8tvQiMqF%3~QmH_%*Q4ET zquFdC9*=V!i^T$VyB(oWi1~`e;!O>OLIIP>1jFGF9*+m(@tFBY`~AHbtJMno{T?cn zifhT`ayR&=rxJF%9R`B|`;|&1)M_>7QYaJ%27}B?`bwn|5{bkOe!JbGT>g&J>BRNV z=W{rnPLTd?w~I(5g6VXM(P)HpI*r+Ec7vyWY&IJ_K7Ql8{eGYQ`FtMHXjI@XGj_RL zGS}<=(VKc?Hk-Ll(n<YlG#aQ@t4Jo32#3SWk;!D<<R(1zq}6J1JjD>+<#J)YUSH!a z77Oe6UH)t~%Nj@<@lf4vxBH4E%;9jjdB5c8^?Hn_Kf2Qlbvm6t#=pc~?zLJCGz&C0 L)U(U~|2lsHLf+7d literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-refresh-sm.bmp b/mechglue/src/windows/identity/ui/images/id-refresh-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..11d1893b4aaaf27f873feb2b411e9500fb8f9639 GIT binary patch literal 1014 zcmb`FT}TsP6owaF1Y!QQbZ$$BW|)OVrD*0~7NijALR`*elo{Ed)zqBJn28#iX_`8S zWm=;w6Di6dTZt}j)NKs4f>I)kC<=mZpSFqOun3_8?>XOr^StM~I6L<IS}Jfwlp}{Z z<n54`LrVlQN1llRPl3Rx*%%)m=YJ@_{0bS`tL!VC(dM)aQcvq#z3P0$KX=G4G!WBf zA<{5PxPBO4c><m(aja0cBTn8%{Qh|4xpFi*4K|x?f#2b(R#ZK2P;^g_)btF$6Ctdw zmLXJzBF>euPPv{n>a~QP3}bIj8e?N)ZXW7-1G@exG^R<S3XT)dAw}F4NI<m|QBpi+ zvl(T+5?N6Qvb<o_rG;+%rRxUn*uQXN^fO^+5)nQLK-ezAw<HMfI2k6B$+a^fGm#Wk zD(W(|8(-g|XK?BpT_f+=crcmZ1F=LL%_F+8k7z|EI}3LaQLqVVX%M0&DcNe38*jB* zscUFt<kJr#kL|{z&j(3K6v?M5=zi2gc;N<CKKFP1%fCiKXIG~i@4Nwv#X?<UGcj3v zS#I!Q**i}pwSmNFW05oj;nCxR*XvbmDc-t(b@KfKgQOQ<CdFt&R;t76TqwRbMfkOe ziPgrDTXqERZXt?`S%2hp^(|Blex&TxB!?cqW&15FIhsm_hKA<m)6S-2d|;gG=ihF5 zT@x=peCOfBSC^0T7P7T9ZnJi~-L0R`Kke=1<$#&t>7VFFrcvm7>9}|Quk-WS+4pVZ VT`I4&QdHYav!P>A?5xLP>Tik!xZMB% literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-refresh.bmp b/mechglue/src/windows/identity/ui/images/id-refresh.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6357fde4f1defcbde2a77393af3c4b5ffb7c7298 GIT binary patch literal 3186 zcmd^=Yfw~W7{_fYQCSvtSzveBg<W=)1;x0vuA-K@UWO4N3kF36xriEgM=`BYGaS)! zbX4S~f)^~ZaJ&>S5^}$zf_KSlrj?bK4}JS}b{!2SFr56-^v?Xx?K$W9o##34`M+aB zmWcXThf&xX1gQnN3VNlFM%X?XRpLH<EP6UFT)4phQM2YI6A~5Mt;SD{#Ng}yw^(e_ z;(ygEpRgFz+Zs>_Qf{rsc}pD*n`^NbG$1q?8@W9LqSsr`E!Qj>5*kBIO$`MF1yod2 zyfEK?>TLXSTJg<kVQ5whUb~vn?P#>VgN?y}ez7P0^-4sG^AK;Wr2mAO*vcKz`g))n zp-1PZLu>G0`poH6R#x_kZwilN{J}QN2ih33|12Z(&tTkr8m~<yi2U5ptr>)Nsh-z0 zYWfcHL@`B!VUagp$%FBpKLqbY9|p(!;1R4trB{=`FaIC8qa)*)_Vq;~1%)5JKv>~< zCKa@!o3#X|Sqiip^?0NW#BG5FO^OcPszE5;RpCBdgWEWFba4Zp@eOf<QF*J`y?gg_ zx#p+@l8ZY?`t~aGzPU>5vCB*^x`@PAcz&ypcbf<9TRhNg)}c;y=T(^)m!bZYmX?y2 zmq*~pK(rw`JePS{>o?5vLgS^Op`oEiZt$$RtgXDknu;5&F27F7$?u6R5av;k8?JlY zQRN8A)S%v>wes!E3KRjRF8KmSy@}g=EdxI=po!NZ*UQPw%ItDaXHN)=PGo1(9kw^# zVN3lFY^c7)_(iLbER!KWq(X5(jWWLzKSM)5t%w5!2cP9ED=S0wh8kD18sl5TC@Cr7 z#EBEn;+=Vx<H(o<zBvCghtB;({@Hu%YW@*bkPou2<Tw>6aop~L{X$2?!7BRus<H9$ zMDDF4V^@YXXIonvMMXt~hKJ%G<d0{d5cgDI8r`)Qow@HXTuf0*2c_Tt#<45+$*Me0 zKbbAkVQQR>24sE)0uom<JpBlMS<NUvJWP<;%%t#1c$y5Tjc%x>sFBTaMzL0H?Y}%q z$%c&^daSd$x|$hrb7=YT5mmPyaIpRon~qeGxNR?vfgae-m*8d|NARI`hV40xVPZJO zaYpRtNpUH3?Y94FlN(J<O+7L#HD~AK@=;nkXYW1c)Q#UUh6UpgCr4Z(Mcg1m6d}j7 zIuoCmRJLd3(AwIH-Z&6xt}{+YlsJFo`i$?A?MlGdfamg__Bkgvm+8^56xN(2e*Gud zt(IYXUV^AiP_2Z1J|d<@g;QQ$PH}ND<HIK4V3y!mDo6H>@a>N&tbFMLC(_c>dd0M` zTUuIJnzEcR6N3?H#n@yFpnr$px0f8SJtx5~-2r)o5|?l}wtF0~ua#k!CqYu~jI_+f z%6A>DqOq~D*UVF=PGOoHfqunabXzL085P89$pZVLh<?|_fANL-Z5terML9EM<PaPa zoUDBNZ)NzI{d&!_^eiwWlF9p<t@Fj=y@9!{$df+h)c_CrPOwF?LWX#i6h(*<-Do`- z*-!qL(CARapGmP>=fJwOk9*Brn6i@D`zlx<_+a9RE6g}@iIC6FF(U5_gEE>B$8IEL zMXJ^Bnwy)u<ZW+n$9IAs(l?~k*VlK6J)JMz?Sms`u(|HGRqLy6vi#&V5{_RXRPcP$ z-qW~mt7B4Be2@9+>gtG?5z%A3JLZ(A*%S(XWbvduXYL9<c$<~qT_g7BW$QXKG`j`U zJ2PJ>XLp>=*QUk9QUAk3YHvTJxZ_v$wcR7V_7)3EI(Sc5<BVDLghkJJsmz@jyV#MN z$IS<S(0Jz&MVEfD`hIHJHKK&I%{MZMqsNcGRHmiorOQ&t$lc57yN@|~`M!0%Nj-U$ wx96^6<=Wo==bii4o8!#vY@!q9GHp&0@64V@*vvQzzdZcX>+8+C{MYXJ6P@PDq5uE@ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id-sm.bmp b/mechglue/src/windows/identity/ui/images/id-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6edfb07d9514fc52ef00b7ce8bf79abbf1303028 GIT binary patch literal 822 zcmb7?p>Kmg6vkQh4@@qICr*&1qN3si0#Sh=*#x2zQHhwCKulIlR8&?@AdwY_$qEFb zk|q-s69`1bi4!L-`wl9aK)dzJ-OD@p@x8}`=`+8#T5-fD?1$67vmV>)*6DtC=;Ho% zoj-m(@4UfiNGe$$(qtZx9Wp|6iN>~#H6fcb2CUCln{+l}fPEtHoD4iM3H5lbgjCJp z6D1gVWEOb%yNqJr?ePk{7NRLOvBx<u@V5OP2HSKczRQdJ?rZM3=mGpk6dtQmi=$S0 zm_OF}YT-MM%h)=OV5_Axb@edc?6&dL<HS&+E_1Y}1o~8iJmy)XE0}|SdkN%Er91e7 zKlo)7wqvAZ7T^dT-^IkCezcI;;x!zPrVeGx#JuKTylUzy&x&l_nq$1if4F~?ysGng LBL9zW|Cjf_TVTQ7 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id.bmp b/mechglue/src/windows/identity/ui/images/id.bmp new file mode 100644 index 0000000000000000000000000000000000000000..72a93c6a947c4446c95f08f3bd3277e74225822a GIT binary patch literal 3186 zcmd^=Yfw~W7{}>*V@}ODkvcWWG=%7&A?`G0S(wg_uxp7fF0dB_VFF1Fg)U51V~$xC zA-CN{6eSZi60x))S%n3HU3M36xr$umVrqH$(6?XjIkq!S(=^kZ)0cW@p7VY<XXbaF z|NDRb@5^!99uARLjCh8Nnk#CysE0zH63_dqX+}thRKXPp1o%HzN=7zuM(aN+Yt~jp zS}o9<nOpc1b3{GyMH{pBw=#2I3y=IwMe59on2TStu*lv?l-<L^au3gzx|w&NUH*s1 zKKpC-e4R-VQ<IR&%IYp+k9M)*h@WMLeZ*9FWqw$3JE5ZYKliMZx!kac#BX{rh)Osa zKwop2)n9e<VwImI6`gY5lI{<3BjT0y8EZ@<``i#&-w%@c-5}O8{cNo5mDy7NnuA^< z%G}I;fUA_LP03)_r4io0IKsP)SIKR-BJ(YE{j3vxzgpeRQo#)`?cnjx@9P|)&_jCD zW{Nu|C~BWzf7>-aZXV-3!G81nklgd@Cjz`8&iXk=Cr=A+NuG{WsI9@A#_`KPbFAk& zhyBx(x+mG!I!=LegdD*&o$e$4c#rI@`9kAR(d+VcDT;jiM$T4hJwyC(<rmHj+?3hn zos)dhGRE5%uF7Y;;Z#8O^<ptob3Uxcn!QaCv$?sMq||gglXqzvyUp3bTU2*nr%34i z!KG1I<K%Dq&>s8aTvsLFa=8>SrM$P<9Te=|i+}na&XHd^)q4Y*=yi{4O!kyj_({@t zfjN(&a=T()@Q$%N9BedMsd4!^-G7q`@06_X&L4+KC_B&6I0Gd%hibea*W>Z9J$DBy zR%wY?6is+kG|N_M*^--&^e*_Fn!D5KM6+f+VLK}cD|8XMr-4V)Kjj6T0k_+&I<v8{ zk!Ydcnj>!6FH-hKi<y-2envqZk+C{_KA)=G9HF13>LOc24sJd>K$7rk+}Axkf5^u( zB^}Jn{F34_o2pFh`Xo6Eq&)bjX_Ore!=%*@pc9#|sr2$>VJoYRn^a}S8!gm`Jd!f$ zpl?d#;5hjghLPq(x@Q*JJZRP?tIA9?r_y%q4lUz%I5%{Qs;+7FiY$`yPs;k3@;3CQ zbXA$fC8Zp29AfnLZ?sR`rMB;eocnoVK8@mTi!x+US6{CxQ<}N$Z{<?rsKh&Uk2;YH w(tVTHFvv?8?~uQ1x9Ys$oR`^bn9?#xOwVGiB@=yeDm5og{%gD-_rI|J4i5k2Jpcdz literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/id.ico b/mechglue/src/windows/identity/ui/images/id.ico new file mode 100644 index 0000000000000000000000000000000000000000..aa15f05fd29d04bf0a23c94c7b63fa59dc369806 GIT binary patch literal 2862 zcmeHJUu;ul6h9pu9f-Dr>1O}jc6U&=>Bdr6SMRn$r_5OmYKePeD7=h5kj%&=zF2u6 zh=x6hZ%X<!_qdo5eOfRMvMfC5P!vK4*3rbNciUatwfE=wZf_lsxgqM4oaXz^_xsNG zJLlK)HTRatLhH!kaIm*hy@e=9#F!XYP=7g5AMX{hkNT}d6YGiU#Tgzx9)fqTiCD=J zV!>0wTqI18;EnO|ae|2R1akosptvET%Z9~DBR4Xp#{jW@Ccj6vQ$>H=NH$;_5<b&X zBk~~Qc-QcYWctdY$0?%@PljKvWUPSivIz^2u>AdxVBOuPihHs%<lYJ^D=VXs6Gtf? z4pMqzl(f`!YIZuQ%P&z>a+0oTbh0l-x;jgWEKyLB=|b`h%}!5}B1!b-z9{LlDGKn} zD93ZEM!9r~V$F@D>pFchc!;J)lN9e(D1G??$F5UvqfFh*)is^8o72n{yc~_4IYIHR zFrWL9y8V7S8}Fl_EYrluSyHb~(qM0tMotgXp|C=!$uY{Y)*x%$XXwn)X+x(<6Ra=H zIp2vzS+A2~tV?HINugzIgtYWc{%*XN(>X3;If`;Ug=?u-FBcp0aDLc<|3L@#u4&Z) zYrE|ko4vezbG<ms_(_jVvWGU;?lG{p%3ZT17z~v^;w;9icC9OGvA486+E~KdnriJE z9^1Iv#FcgaXSX+2R8^bUwRKZd^DbF7v9;B|$>EF0N(t|@?|I4^2}De+Se{t_^u{~z z;~foFB@!_C)ypRGuWtYDbJq7?|6;_O>On?Hm+`VG%r9Ya<_3~)9mY!@7hbKE5S83e z+-|hEUD)ArBH(eOP4<;)t;qjo^c;E{>d+&(@Vw+f2lHDwUx4vWNkXgFyCNS8c`T_J zWM_WFr^gQCMcIR}M?$Bl$vSp8YoOG6aAa@$ihQ9zuP&mXs<?e|6!G0bw6gAy*Ml~f z3&;2O;Hz^VLjC^In*8+C7kHyH#Cp95vHp_>Ucs+dCOQ8su#{h&|I5$#d?<nE{M*o8 zC*z|defa%{DdZP4WLY2b#vcihqhx>fU+ABi8b^Pm6Ct0B*TW&CE}chVZXQc>IppWE zK;f_X;{Lu)4xwkeA8p<`47}Wfg&S9(Gf!{}bD1^y9~|6|4!)xx_wCqgFCg>NHGpdu z7I>^uU!Tu`-=`Q(97U|D0bN@q48Q+23cqpBME(2ZXK&xax95j(@w1Pi-MYs2sqrZC nSNr~=FUHV~b`~eGz7v}vZv0*SH*x7+@7I^^?}7b4ea`#=(=`(R literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/ident.png b/mechglue/src/windows/identity/ui/images/ident.png new file mode 100644 index 0000000000000000000000000000000000000000..904f0239bc7208ecdcbab6e99ad914ed84b24b28 GIT binary patch literal 423 zcmV;Y0a*TtP)<h;3K|Lk000e1NJLTq000mG000jN1^@s6?Q>5r00004b3#c}2nYxW zd<bNS0000PbVXQnQ*UN;cVTj60C#tHE@^ISb7Ns}WiD@WXPfRk8UO$RIY~r8RCt`F zlfO#>Q2@t3cZ!fhaD#`{5agmoSRgewL_<r9)DT29G)WK+4haqhIkbq9+SngZQ-Rno z@kpYj=^%(k^VT4O6JFDm;@K&F*T?6>=RJ6muIqv!CJzI52{cWkTrML-|4|(R!!QVi zLX--5Zf`1s3tTQ2;c%GD(IL|Th0|<?>cib&f>x^qKxBS~RD6T6kp{VwBwFp>Ss=^u zufW>ET!6$*1n*~+>~Wl@dabv>?RIwwtS!#^*<Tyw{V_*6mH1<v3aov7o19-Y@v2KC zV!QSNy8<Bu7Zshi55f9&8bwh$&N~F{j|lMm^2+6Pot4!n%h8~1S=SXz)1=X8k}sSw zITa*!khBGR78Hv`CdU12Ztdamc>aX}r1sBb7zUCg;q&<%LE8dVRr?05{Qw>@XRbF% RR73y(002ovPDHLkV1i0iuBiY3 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/import-dis.bmp b/mechglue/src/windows/identity/ui/images/import-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4257a1ad9ec59d426773ec0d2e6e8c81ea2e367f GIT binary patch literal 2430 zcmeH`F;2uV5JgSN4UiB@i*f+kNK`bGu5%Ndo3I6yFX24^Wu$G8auoAsCae(H*#v2+ z*0M*=Zv5u^&*bs><=W|ZAl|d?ShuVzcSCgUY5rdy=5RRAaOc4uE?hJA-+iE6hGB3` z`?tbY^%~dr!F8=~THpIk36{8TyB#z3L4<eSlb~Ol-~@O7v1i5*nb1+~HGyk<PI2J| zC%8F{NH)48NMn2*ErIwWv+Pfm%Ym4pL16*S8f61r5=0*Y=%VT}m!ffH4x2_mY;5ND zJZ~mNSL#{ia@pVGJ33F2V4Dx<<(hD<8PIMy0Er3Hm?yabK48=~AIt;}TLMG#C}_2! zrqt3@d}vy5S|3r(Ko{`{WzQ#5RJz19goq7aEusBu1tbc$Yl$^<SubLNqLFD$W^Rby zDVs&wWaZ{1S%sU-1Z`WbJH+E9C>m%|V){0{ybVayX^8;I{4tVz7n`}Y11o<o`>^ux N!fO|<nR7NDJ^}lAHRb>S literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/import-sm-dis.bmp b/mechglue/src/windows/identity/ui/images/import-sm-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b9398c3849040fc6db484cecdb33f3d7faf5178f GIT binary patch literal 774 zcmaKqF;2ul3`GZ!XrZJ_i*f+kNc5Cb=O~k#um#mzV)g(O6p_*(%~58b{lh4Lz;e9K z?Em(+C(kdpH^J?R_{ek5bH{TP9*7})T>H<rux%Uf%d*5dg=vh#80X00KL-Bobi(tT zAciSMi1VLB;m@CEJg1C%J6J{xLu@4<+X>&wN(-@!Sl0ZyifB5`cbz1;WP!l|ZXPXx zWyBm)f<hOHGa!em34lc2-rJs3r}!Sg)AY9;DXkh&dce~Typ}^RaRHc^y0&T^(Su;= zkr)m|6opr#xTHR*;fE2J&t+XO>JU4aoU82n)L&LSeXYp%ufd6ipGKl66bDRAT+5Uy zt6!U>`ZD+Bvw0WeYxg~X>`fUK3Z;%86#%Q|qX97gVa4vNk3d2fbH7K5V|}qY@8Apc C>DlD~ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/import-sm.bmp b/mechglue/src/windows/identity/ui/images/import-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..bc7e4f4c91172fc161adb697e3be7a1c8eaf87f0 GIT binary patch literal 822 zcma))p>Kmg6vjK2AP~)hAWH?JqFE*@_yZ~`mds2{R3H!tL`B6!Ma2XHF@dP4Kp+qm z2n1pRQGq}p5Hvv`5C{YUfj~6-;ON#&tow5Ja_`>n-rc>s*|Tsv=p?{Cpx^cVW^mul z5BfN9h&>*UqPVzhk|efGY%Q7ZXF6Ar<)xx*)@$canWm{IGT_x}rK)OO*QaYb96Z3t zY#2uK4;4iL7|F3$S(eo`<#`TR*LBOXFeXA0h%ARCE(xV+y4~tHjBVQ(6J=S3Xx%ip z4bF%$W=JTGW57s`!Wf6xMDr6XNVPDx!vsqRpCk#$D2l=`B(UqcFILQG5iiX7@#AD7 z%;zGORCWDL20`HaJ~De}@kTlnHHKk_?1&#vH+v5W!9WE0>;xBuRrUcb@0eaJHySG+ zCc&^f5t0K&l8qBlZ!XPpJ^uR6O=pt21AtQOFN9kxodht&ury7#{6gh+8SWw(Wd9$F zU2u0!i*R0wqFVTADL6&hoMf-u#?`M6f<J@uCV45W4Q|8(o?0zTRMh8D=cBfGf4m_6 Nb5S*d?g0jKRbMrI9SZ;e literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/import.bmp b/mechglue/src/windows/identity/ui/images/import.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6c1331dcae07b0d682d9a6eda5ecaf4a156b57c8 GIT binary patch literal 2430 zcmcJQA&lZ!7{}R)CR>3(Og3x|fgqO=BUY>&F@ju34lx3OKp+qZ1OkDmK#<J{1frq> zQBhIRWSc#1kG=G=O}2tbm`f+i>@=a-<&q{>QBi@YXzt&>PT_HLm)l(SpV!B0OMm@; z-}~O{#gF{cT%wogzsK<%j^{X@<es6=<$g%-Cnsrl_idE>HrTs8x7BKr)`S|3xHZud zrQ_rZxpmk#(+BZ*=5o(%Cu%er^?I$>>kSj}{1EN$<MdMUga0=!FUjM_T<!JiZnxXU z8ygMBaiXtL5CjOSR;}XcZl^=gso$U8yy^G*Fsm;XU&BoQ3oDg!xmvBlHO2kq?OVjO zTCF_K+tKp>n?zwsvO#fwefMrO8ZDPg*L4xsp|;!YLj>V2@IBY{T^BuCCXBDH#+c{h zJp88XxM3OwD6o7e+qN?<z^>zvwngxcowRs_>BaP5!YRMT`}dQ{MAvmtG8bfk<fPm% zio(!$x6azKt+=fp+SXq8`@K%5Js1oquKD4EAWY};`Fg#E<wGGkdoI9%Z(FO?a!DHA zfj1$JPN&`Lc6pwsxYyU$q9|&b3U{zf6o=<H2qNajX5$}lEz>k~-CQi})e@(;h8wL` zbI|XP$770nb8{ohlA<W4X<CV39Ks703muQeO7h@2Hi!#NvzKN9CGU$a>-FJqh-6aS z+uK`JRTNn^3<H*-j1J2QH6aK7Qr7`B=JTDmjh&`(L>Cw5Bc2xof#R+|e$+Hgk|eAP zScV84mQfoSH}Jf<qH3~YXxiRvoQCMd*%^{Bo6RWh{rx9!%Vt=T9ZuYGQ=1bUG`6iU z{dK_!2->kMWj2#%GhLOBxTmKTBmv2!xSP!eP6yJ05qxIgF!>UfKgpkz^TkuHP~?=v zav0f5LlH$um|FTg+U=rUk_YrrR4SFG(<x?%;(qz^8L<n3sH!S6^_h{&vK*U;DW0;! zb)3f?iXrf9%UPMB@5RsqZl2>%QK(dki-JWeQ|>HaDz%Ku6)SA_VQG+bJl5m$1GAWR zihF;*K}od*HO@oj0?>RO4q%xp6pG-sP@m0KvOCw0RI6c+tb&V5M-@@rjq?Y%1PWpy z5z@e%^T;*JTb}3sOT&uCD@namT=n-q87W}O=kN#t8|St*Va7hww%LjOSm^s}u!(@k z>ZiERU)>>mIEBDvpxTs^JXA3=@fpD-%jD4>;bVuygp+_M?yH|av8bvz11B-}tjmfX ze<h5^SFMR$Fhi_SBJ5a4!p4nS%65N>ixbfafR3T(JgWxVApLBFsID-izajs4Mxf~T k-(#FiET5@Kc@-6(3eapArF#LcJl-<sG57Gs{~YK30vkKMb^rhX literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/khimaira-cfg.bmp b/mechglue/src/windows/identity/ui/images/khimaira-cfg.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d20b9eb3d84f919e2f1b58c32d80043800dafa55 GIT binary patch literal 30056 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 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/logo_shade.bmp b/mechglue/src/windows/identity/ui/images/logo_shade.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2e36b9bf2016cf725357f87b9b43dcc9344137b4 GIT binary patch literal 30056 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 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/main_app.ico b/mechglue/src/windows/identity/ui/images/main_app.ico new file mode 100644 index 0000000000000000000000000000000000000000..8dcb29e7a66f097ad2f67b181bb352fb2421d3d9 GIT binary patch literal 25214 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�Jk?KB_&Y&gD^@AzC#JY_b4$ugpwja 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 Nl|lr5Zx?I${{ZwxG8zB? literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tb-blank-small.bmp b/mechglue/src/windows/identity/ui/images/tb-blank-small.bmp new file mode 100644 index 0000000000000000000000000000000000000000..0718d128bfc245c72044f42207c68ab69361dc78 GIT binary patch literal 774 scmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZm_i}0kAl$<7)Bug0HIx8&j0`b literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tb-blank.bmp b/mechglue/src/windows/identity/ui/images/tb-blank.bmp new file mode 100644 index 0000000000000000000000000000000000000000..01adca9e3d8b78b4beea0a9f9d29954b36234989 GIT binary patch literal 2430 zcmZ?rt>a_>12Z700mQOEEDgkr3=%++fx!bR59W*#qaiRF0;3@?8UmvsFd71*Aut*O H6omi)zup2D literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tb-space.bmp b/mechglue/src/windows/identity/ui/images/tb-space.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d85cc5cd745cc44f4ace1de38f2552bf93294a7e GIT binary patch literal 2430 zcmZ?rt>a_>12Z700mQOEEDgkr3=%++fx!bR59UCL>$Cw3v@!PjsJW1U9Sw)ka6ryt aqv>HZJ&dLY<PaE556Gc0T0YP?JpcfUxVK9H literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-delete-dis-sm.bmp b/mechglue/src/windows/identity/ui/images/tk-delete-dis-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..00adcf44365825b43f9c3dc27c2b4cbd7d07b7e0 GIT binary patch literal 1014 zcmd^6yJ`Ya5Z#bI$tR@r3(^P{K|#c|P*m(>Q4m+f!cM^liXbYA7K<+gABbq77Jh(R zh@e;~{z=-Coe5bq7O7HY;M~2#>^W!d%)9vUC~&-Kr$NJuhGz{A!mD<Eh5952gzvaq zF8C{Kw_9CXRaNZwdp-Znvrs6&@AqT5Tw=4?AQFi%4u`{y#_4pz@p#m6KA%Adg+j<= zG6;vme9z@_%-`*HH~f4)k3=E?S(YJ55>lxY*GbcCHY1zOg18oo1<`2qhD&d#)oP$# zsTK$X;C8!_PN&(+;czgQ`tW!>2nK_9{ARPs9+Sxg?RFd0YLz*5yPdx_n++zDi8Z}m zFVEt7c8a2)TrOk1USm3)qSx!8Uazyi)oSIQTrL-kMkAa~=beA2(?O%rz-qMu^+5be zrGjFyh-5N}SS$vg&j(Qy_1Rqe_xpX`>wG@PU@$;D9>;7p!*Dp{_fk&prv1@euDNul k{gOtv+eNF@!eX(|{~3)&D3waw3+-t<9_zKAI{!8Q1Q|N-3IG5A literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-delete-dis.bmp b/mechglue/src/windows/identity/ui/images/tk-delete-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..844fb23a647397b2a5c3bbe22814dbdc881366fd GIT binary patch literal 3186 zcmeHJM@yqo6wU01`2)kiY}66mh!{kygNo6_-WxWsw<K1?3W61^Sh0els3;<eh#~{l zg<Wvx&Ru@OnVdU(!TF+s;4qtf@bdCq-n-}CbI-lWPlNHZMjoy8^M`ePv#zh!^-1&H z`uXSi^+luMQl9(!dpOqnIJmpJ`zM?&EiEA{D+_A>mzS5&>-A`8X!uavm6a9fbUG9l z7b7(_6}Pvy;{W2}0ud1rFdB`>$jCrbQ`3jw9vvOQ$HxaPEiGtmZAEEmDH0PCaejV| z@bGZKqn*po&kuWhdmn;ZRaJ$|%uMmC;Cgs?z+^JnY>cC~xA#pv#u*e8gyiI8i90?% z9<i~ph>ng%U|^u#-P+n(IjiLKd=Ci;fmW-vyQA*KlamwV=H_B{b{6B~;}{$qL{Co- z+S}WuHbX;0c0OEPU8SCCJWo$giC>MOekW#rem)i#7cn|Iih+Rvba!_PCbi(}>nm~G z+}vP)e_wKRa&iLmeU8cc(jE{HU>D;{nABl&bF*kKJw09gl4J6lkdPoegoTA6G&B_M z?(To#6&4oSu*=HI1o!Id>P=kcSzcZ)d6CoA)m1DkEMR(iTJrAi??+cx7aAKILA}(~ z)!8suZ#OqL7z_rRjlQCyqQHJt=cl|AlYK=#$?MkE7S`6*gzK4^8H|mMiJiFq{{B$% zqV6IiBaxGnBmA>($#s2wJ*cI#v$HobtE;QUFa5J-+uPe%Utb4j&fMG_CMG68Es+P- z%iG%<X=!N^E9=6!<m~J$SS~IuI6gjp6_2?xPsTPfG9rAk_YV#Zu(Pv+jg1W~FE3+$ zejbyPlNcTzmfj;ToDICk-Yh66fR~pSf`fx!>@S5=WhW+UH8nLQb>tkQ?eOprySuyC z+}s3bUPniVU^2G8zCLtzcA~AVP3CK5Wu?q0>YrLue80BSKkGn@l9CdcrHnf-FAv$- z*`ig>Q1)w4QIXV;`lWByjdf+6Ie(}h&cWBP6gx5L&tkFQ>FEiNkB@kGc)<1bwd6?s zD`&Z%o}P+-_55HjvuF9+^8EZu-#PnYVq#!6n?(~96%`;3bB>FPlNqkQS5s3X8cIn? eK~hqZ^f1rT5Bo%Y-tqpv{~->(9DMyx4g3ZJvzf5~ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-delete-sm.bmp b/mechglue/src/windows/identity/ui/images/tk-delete-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b9b604f83b136f3049c22941ea0e26fd4b99cbf2 GIT binary patch literal 822 zcmb7?FKog<6vkQS5X<C(m?X;t0#Sjem_U#WS%H{9R3MNQ6BQK`h>8jXqN1YWM8$~{ zCr+F|R3IU#Kp;+3R7^}vkbV6Vl2x$o%j>0g?|0w5-s{V&e%mRfV|>DMUq3gUhjP7B z=c`FI&i|?9Vqx2Mnx^Ng0syRnDWzB0Iw^#}7T0w-=U*+f+wA~*s}=aHg_0xzyk4)t zpIT_U-2x870EO*aNJ<Gfj$`ns?N0$CgfPZzhxLp|>lZN`b4n8&T?w8Sp=`kKF4qQu zG2y;1%{Q(MH$6ROOd{J5U>pJG(U>8%3B;Wq4W`&0E|y3#^razO5zIYL`abRI0pKkA z9+`4x;j>~wBE&^l!L4Y|(cDVAdN`O0!06?pA#8VFHbiAv9ZIQVsmWa82*7z>^xauy ua1f$+Zz#`mn4C_ZMa_L`%n~>Qc0SaVzvFN?D0Ox{Wm-oBAr04GQ@}rQVK*-T literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-delete.bmp b/mechglue/src/windows/identity/ui/images/tk-delete.bmp new file mode 100644 index 0000000000000000000000000000000000000000..98da87d5501fdce8ca5d2120f2e3460c7a2d5d90 GIT binary patch literal 2430 zcmcJRZA?>F7{|{(EQ`r9mwi#UOlDALqmdAkxy=zb=O&13&a6~mvx2Cb&N*=c>cF5? zH;_P31X>&v9IX{BrCOC<-m11LYwZgyE!4H+rKJ?5ATQ;%z1?%$LcGg9^uzq;e@;(N z@A;kQJg4Wh8xnHop@80ldIglXp}Ym<CA1J~gks_IyRQXHpaZJz7o!)<_51xhzDfBu zB{}Hi?TjQwVmO8;=SBfxE&-u<ft#L|3QkGd{$;`zARf!k4#x)%{P4w=cn1CJ;Bcse zc@1%;(&qi&f0xQ+Zf7KFwOW`ad<_f?q$DSAj*EqO_oSy&xGfl#@zX(oVp3`N#JMNU zX7kd>$j?99n6{Hi;kLK6WoKnRQYuGAMy9D64Nn!NrSxsvQg`m8aAh*tiQJs~3c1Z@ z8w+TBd_36b@9!t$BK(BcJL!7rwAn`NHmDso+t92Xc6-5ZXOoi{d-v?7aOLuQXHT>4 z$U3Z6tJCR(s6o&GnM@{<>mvvc?tbPPcx>)7_x731*4|!=IcT%RY|hI$p32+-+eqO) zxPQO!TtSOe+G8>e4h}-pAZUP;N@a-aB?#Q@?6>r2HAao5Tca^(G<vnVTdT2}x(^>Z zxHmoh$j^r<+|JI<3+GF2N^W%NbQX&Rq6R?&)X~vFrU9T{AEaVtY@}DM`cp1fD&$JJ z{Bf7YW$*J&j_uvO>%jhfIlmmIa8)W5hs_o>HbQhpqY>6VC$U%@;(C09$1~#^R^PiT z!!TKMbC2=?{%jQT<0ptD2IFu>28+d_a5Wlr4Y&HL;EF;ahwm>)H!B{GM{+%oUoSB; zJ!sUmG&MDgL_H7X`1lj(^x<CE)r9!CquH5-1^E;%EdQ!Nz^kjfBa=bM&x^z11h_r| z_f9!&cdv_ub-dQbYm<&X0{8fE==TA4eN4=W+}zR&7bskV!O$cU)o{5OhA9+^ix){> zy9P}~QBe`e#eJU1F`GdptggOX!D$uN<6}?!xECe^19wey^cfbblEbEOO(x^*Ter@a zus_{ek0SVJc`fNk-m(uQ8#h*lxDzgUqoAs|xU#tDHowL*{?tDc;LecTWs#BR^7Aj( z)>64f({*v%;&p7arsCBV{EuR9#?o&sjBY?t9Q0<TT<-A0dfm9XS;Q?YC_8)VQHz+E zp7OiN<PvU@yJ*3JlH%fefq=?2^+tazK~ZH(R`P|yW~mgDVp!I(c0{X&nb12DNB<Mx zdd5d>T@N33w&SD2#57J!dwerqpW6f6dGlT=FE6_;7E`!biv_K!dOb4#(xti^HzX3t z&8*`JMEe8Lu6($u3(#r%^e~uoP|vpmJ#h2#`TX|QRtmR-ZG^!wF(<j)8lh11;~_Dk z)gYRnvg(<|;zBgu8%xTW%w2RkBO##pfa2ofHq8pSa9kg$R21&7B?jQGU7HCPMSfvF zqHz(ezN%)5fN!nGgO-cXqK@I=VTWUAXvjWiyWKWtI-Rc9cfo0*a7)Vn0`AgxPchSK zff#_ggDV~#^~2k!4aQIg{_6$KQ6ioGx77-!a8;@yw5s;y#g`GS0MW`akE#s@c)$dA z*6s`qOd0>xL%m)fJcC-TCTN|GJeC+HWiS#O8XD{YQMhoCZcZlm2k7fJ6z1iz@=l%s zuYNxlMU~E9S$QOrm6MZuG@z`ktRqyxX?i*<3Kte<vrVr4L`R|{q%m7{F$t!{>pD=> z?<fLev!_6lVQ6Av;@@1@AE(oM;<Ri2s(Wa86X}Sy^;-s%N}o48kvly5M<?`q9Gv8T GtkFM0+{8@) literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-dis-sm.bmp b/mechglue/src/windows/identity/ui/images/tk-dis-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9100d9a9c7a568a03c58ff4b5590dc4eb8c89660 GIT binary patch literal 1014 zcmd^*yJ`Ya6h$YbPx1*V)7g!U2&S>p&O!tWQ4oA!F`}X%iXw=LqJ{WE@PUXHYT*y0 z6$BOkB<;%F33DNu9|$?H&$*AY@7?>nyFMQkBUC-V>3Grctm8p>)$@0JJSmER8Q1HT zzl`(w%<*`XxLhvM&*^lM=b}gS-g+&SN@$u!BoZMI2$0L=WRKtP$7Zuhh`w8Xv)QCv zE)$Ez2nK_AJRb7-JgHO)yWNhes#q)*W1UW?@A#cgheDyiVzHp#@6%{BC>Dz(lS#ti zFg~9Tr_+hmYUMY6x7(#wtFhnjSuU51Mk89S7Q&a%Abbf;4u^wGCUf`yU@)NFZnN9% z3=M)`uh*$mDrB=+;_*0MuNSx5{bM%f9LD1@hr@yOdd*}qA(2S1TCJE)r-VWwV=rnn r8a3u(^31y3ZV_(`heLY39-GZZYMjkxRI61(i|{j_&*h!T|L^q+$4mON literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-dis.bmp b/mechglue/src/windows/identity/ui/images/tk-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..558ba9064477a7038033d8ba7df65075db495d3a GIT binary patch literal 3186 zcmeHI$x35U5KZr!{(+{U7cR2Ug$o-Lafq`fCTg4q)Ci75jiQM-$9cpNN7N`Nii#ql zxQIxDC@usA!JRvIe!}UTYSO%P9%!$6lMD6U<-U9CRGm6?pUz<Wtda4<^VE9mo5#L- z?33oZ=lOg5{G!p&yyNNV2>}am5YWK;8o0Z=Lu_m;^78VKlam9p*^JE0Oqfh2#Kgp? z_EASi2O=XQ5gi@vXDKNus%Mn7xVgE3#bSZW<-+pvGG=FIF+M(yfq?-O7Z+o0ZqCmK zvC`Aik(88#`1p7qWBf}0YI9;%R#swXX9tUmi<p_2!PwZCV0LwNNj{9@@$nIEw;LrT zC5VfQLq<jhQd3g}k1^<UI+=eIv$nPt-QC?tOG`shQIYUWj>&I!cDC@4oSZD*i5VUq zj<B#WgocJ9BqRh{trkH+LH~qVUtceIk<){N18i?^V|{&H@}8ca#^~rM`uh67I<~a5 zfcvYes!&!|hJu0uiH*1k2??SNH9nPV<kn`h37_Qk^z;;mhlj%T#>NJgmX`kT-QVAj z&dyG>wzi_7p#jy^)hI777hZycgJCcjgkz<DwK*{vJMrkBH9I>y!_m<Zc6WENxw(mz zl@-y_#KZ&!2M47N4u?ZxWnD^3OND3Zo|;m_QLYiQt*s3U3k$;M_4PF_FE4R^evaeg zW9;qiVQXs(tE;P+pP$F%<RpfMhS1Z~Bj=i$nuKT8m$gnzO#Bcg`C40BlRDnt--B^n zU0vbg;sPfpC)nTL$MEp5U^2F;sVR(%jKJx1qP@Kxjg5_nh=>sVQ)|kc)aLZx+uJJ` zb#-+hSJX#EMTKaDakEd^uQfF_(wAJLZ?9&eqN3zJp|;pRYB<U@V$$E++Z$eAU-9zt zg6HRFJUl!|j#jJH$H(pMt@!`@{$MZL?RMz(dY}DDEbp9mAN#wxxmh$pJrajGXJuu9 t-@SXiZ|b(Nun_tA`N+-9l^*6^`Y{@fe*3-W0`K?#MFEZi9Q|(%`~nsFzajtt literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-new-dis-sm.bmp b/mechglue/src/windows/identity/ui/images/tk-new-dis-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d2e1fcdc4eb0abcbfd3a0c2e22e1cf91ef18b7bf GIT binary patch literal 1014 zcmdT?J8J?#5WbK;$xldmom~_W3q`DgSO``Yq9Q&(!51iqPY^@|72hHVDx%;6w6Y7> zC<-e6leAxMH|*gVFh!~id^@|d^L;xrcbfOlM~>Q?u<`<41Uw6P;9iCG+diH+j)2+a za>0Mb>2$*3a1e1mpT&NT$D<f0IVAVC*K|6KKp+6O+YPJLidZZr=2$Eis8lKuB=44A zEEbW;WZ?CBVYAs_GMNyM#}N*Pp;oKG^E_lS8Qn)BksthWxr{_2f#Gn7X0wTCG>T+0 ziC{1Yr_%|gQVG3Y54l`UW6R}IqEV~Wkk99_TCFe|jcEO(2GU0;6r%5vvqGVOR;$H! zyOr=;trkk95*CXEt)bKDAe+rXr_;f1w<DEG!C)}ZI<9BK=FshSvD@u1nM}~@_2BdQ zFdmOlC=@W8%|OiIaKPj7(77-k^Yi%}M5EnqqtR$k4$(84&2)zKdL2fik!tk&eM#+1 z<JwQBQ~3RUY&IM0_j|ZpF3PD?D#+z>zw!rzfh31~52n9fuTia5#WRcF^W@*ScmLPB EFWo=ve*gdg literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-new-dis.bmp b/mechglue/src/windows/identity/ui/images/tk-new-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c6abc4ec57366faa57c41b232866c822a41de8d9 GIT binary patch literal 3186 zcmeHIM@ytZ5S_g*dlE0}f}-Gn8Dv2*jydOms2EXHRLqJABSypkhJ&I9MNu(ez=I+q zVnD<Qdh+JYpYV2GEhC@1GdsiT(T4uMp0B&>RlQeLqlv2cs*>?j_f+fV58eE(n_pDc zy65kq{iafJ>c{>4JwE3r2cJ1$ItR|r&*AUykJQvuBqt{$F)<PG@$ra_jfJ0|pTRn6 zYHEU)mlu3}egB$aVPOXED782_IYDl2E@o$EF*P-X(a}*13=E*Fs|y(!85kQI`^yHg zqNAe`5)y*Iz`!??{wwVpS`)LNpa2UC3z(Rgz{to5`uqC@v!$g);-McmH#gYd-$!O< zCISKi1jpOkTi*0RqtVFPT+HI)VzjolA|fIJ>FMdhGdU)|Nl8h<LuhEI>=V<&!vl79 zb~2ruoS;^#WzCq)#Vji;leoy~%E}7n=jSmqGb3>i4-ccSuMZs^9iWaiH8tRQ^2+$q z($d5?;syl;y<%QnT^Z$=+*VXn2%qG2YikRutE<8_<ENe8-d@@7?CeByb2DmdYY`b4 zDfV-6a)cL0M@K|OMTsAId3mU>um2||eJ9@J<fLe}v$KP>wKXg*F3Mf<n4h1I!NEav zcXx{padB~iNx!nPvf$?CCVE;}SYUj7+$bJ%ig7kHG{`yfd3=0~gM$O??(SlJeH}|n zOTw{_j}Kg2Tu@R{B05leS65e5R#r-l+1S{?*49?yG?c5#Z^R^D)6>(U<K^Y0_;Gl6 zh`qf%Y;JC1d3hN<Jv|_2mX?;ncT7x-#7tkTtgJw8ng7f+rF}zdVz#xlff$T|Too1; ziv8^DYy<}fOP#V_i;9Zi?(Pn)Rtx=je0+q1gM-A%+zJm5Hw%;YUS3}C{QQikrzbo- zJmC8JT4F3MEq!C7v9S>w8yk8^(SY^DTCS_BliV^CoAMibAM>HAs!H;=yu2L5Vay2$ z3E;l|Jo^SYWd3e%Z-cqU{Is{X2YVjvkaPX{_r6)5*4EabPjho~uf2%5&3bWmb{5^= zi^Kb8XJ^uXQc_ZIdV2aA18cgvy889^(b19A3iI(jxQxNm(^GQ#Pdn_D)KK~T?(R-B zV*giaqC8`2&HtK<i;FjQ^>?UgdwaXVJ?hTB%RJPd|A;qxFnf|QTer8jM)!=}G4*|D XXh{07sdFE>Prd$Evyb${TwA{Y*~5!3 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-new-sm.bmp b/mechglue/src/windows/identity/ui/images/tk-new-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1868eb4c99fb43390fed0f469e484ddca58f8253 GIT binary patch literal 822 zcma))A#8&{6o$LZlLa+3xh#_t6_XQlvlSDFii(Pf3Pi<;2}H$21)>5`fjCitKp;*a zP9RR4XcGhifj}S-h$mk50?n2Y*6@XUdH4RG%e}jMd7EBOTBZ~qXxyB~)#SFVPtJNb z>Eh{hnp@WRZ`rbQ-Si?#DaUchYuhWv);NNys#-Jiyj?R6#@J@F+3)xC?-<DJZnxa` zi=xQ$yo;3l2bn$3I~)!dd;Jy3%sCIkKx<7W@Dsa)Dm^&&!!V4ZNJ{x7w2%oU7YKqN zj>X*9w$RV2T&nb4>UE?<3$4?G%1M&UqRL3|v1!bvF#zpE(>jBY`7=tNL}^ywATmS~ z;6)u>pV}h)9@LjD>U#-hjSEBz(LkI5@~j|<==GarSy`5rY>Xq)PVUGL7{l=6006q6 jx~@NBSf%iq;-bWP0bWkZ0OTa-J$G7=W7gn+?{DcFYfM`k literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-new.bmp b/mechglue/src/windows/identity/ui/images/tk-new.bmp new file mode 100644 index 0000000000000000000000000000000000000000..36f32eccafcea3d46d20b471acef49e5a6570c50 GIT binary patch literal 2430 zcmcgtA&je76zzVu2*ilVW;R=~;%8GaVnjv77bBX@Pqw0>0)eQgs2DM#qM~9%#Rx=2 z1p<MnKp+qmhzhbnAP@*Pc>;lW0)aq0@x;v@%1qnO&Ln@b**&?uz=L-<_q@yH{*Tp< zog?}ff5Y($j-PS-(D?~tr}I1R|EV^|aRS3%{|){ZUR~Fk&?b`)g!ZyZ*Y#8KXT8%S zG))_gMh_43<#z)L#^Z6bd^Vjn)MwuLe2#l~C`l6f2&$@rhT(7sy|dY@&HMQHsB4;O znjhhOdA2OeUaxn5e-CAC-sNJk-|x$^5Z?l8z6Y-3j7Ot4cvq{H=XsoS<aLQW&rcbM zsw_A!Imd`N0q3@5!RI%8Sg+Tf=Yj>25e;y{7<=KB61+Uia>km-GIop%*lsquHo=Cs zeJ~8ebzQKWR5T}16rJ>v6h)q~BtfJXk+bx9y`Jj&VzFrRZnqo9andxY-+qC^;c(_9 zl2yUtI1a-mvNWl9jzm_=B}{;sZC+HuZnwh{NWKJ2fAs;Z61;I31ip`8aU`n}lXw6Q z05G%7Yuh$>!!ShsHt_3o6HL~;SX+nSX>#y9-*Z_M9!Zb$L@)uBy4h^nyf9(6vx6Xj zWMF>aw~+|q<fWpIyrSR%Hg~r>crKi-l{W7qnoP#a<q{9Kd6BPa?|k2fWIIZfkd%Zp z#<8D`UYN+!*tINsYaUz&hP)<G-^cd`b1lni^Mdh<8G^2#Rkul|RD>Ak#Z|~Y6V0Ja zRH5fshG80p@7QM(Aem?|=&zriU|O3O`#v=6T4qUVo~uHrL}OOJ;Hshn77H2suJ!!9 zT|dPKkA%QXEg2)xZLfz-L#4KPk^bDYm4K;2s#0EYJ{01vD8YV{mAtI59vXQXWl<o@ zqNcmx{k7YLWBa|=<~4%sI+QAx5PMx!(@Ho(421Z?vO!*`1ug4z-^I<%jcr@l_BOAw zA;pIS1c7%_W<pj(Yay<PRCpcGr?2#B6rwwSeFgTa0VY&MLEA!Iwt25@uDF%TXn>*- zG9W^XWbFyWg17He2t(chiVQoC530?ZX1Q)UeJ}2E>Pngs^@y&IVv)q6c-H~kz-Ny< zK#I22=0yYBM!Dh=N@5!4(5Rv?vO-O2e;$&e`3V0xLZ+^3sNALnwt3OKbx*+Mu2<bz zff|q+lIo?387Ve>HZx?}08Og}l)<U@w|ViGuu@?$!Adbs1h^E7j8sOYFjC>?-~L73 ixoSu;p8uP;K(}g;p#ZitwCeu#A-v6dn*H}DoxcH%=obnA literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp b/mechglue/src/windows/identity/ui/images/tk-refresh-dis-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2745af15100cfbfccc2099a25c12c08c1fccd889 GIT binary patch literal 1014 zcmd5)OUof(6gJI%W`4pfKYjpNnvE<(Aq&^!vOp=K+;3kJN=R}`xg??7QWi>$g@v*p z|75n$IA>!2O-;?I=Y8LL&w0-CyyyL){PkJDA%3iH4}5#z>jR$z-yiFr`1wU3AUxxK zzvEvZ9*^U6I{h`b*=&ZvV8CLrfW=~gUayDMYDF@c#O-!_@m{Z2TrQUv=x#orBNPfD zl}f>8v%%$Z!DKSQ@At#uaKLW2zv{EuECPW5+-^7LMx#*>27>{*-7cSnLLtOrF=R3s z^OBxIp}-vFavAUM@9=uP%&XJsxZh^8LA%|C$K!!WB!W~bMKBnIMxz0F%jI%hU#rzv z=Xg9utJUIuYPA}2xtu}y5{U!~g@WIKv{fn<(EHNd8jS{u#Ui%bEhdu*_f)A=I2;b_ z)#-FXsZ{cLx7%U8UL&1OW53^XJ!z~~t5~g8APwZ1yeyYXzK_LXFdB`>=kr{9JRT7a zhxv~B_j)~?&u7eLGxYm?_<TN0r&B~C5%ylM*HJ2!Si4rMWsXcH^Qxyl#L?+=&}=q& j-p~Iy91cPK6Nv<9PNUI?XGA`pIUn8WzkIajf6o66A1T;2 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-refresh-dis.bmp b/mechglue/src/windows/identity/ui/images/tk-refresh-dis.bmp new file mode 100644 index 0000000000000000000000000000000000000000..45f8099b9279359191b82f0bfb504313e66214aa GIT binary patch literal 3186 zcmeHJM@waC6m<5(^hy*1ilUek=B!8?+A&AWIR{h}MT{6*K`@{#V#JIYQEXIHYy?Fy zqPTI_JAXorb%yuwwX>S0XEAu;d)NEE@18oRs?K@({#o|Bnp}=ApC&I$_ho6ntl!l1 zUq1i7j{Z<n<5FCAcXxPSsvOMC&7r-${XgX;E-nswdU}|hoqdCQbaVvfbbNgLX76XT zGdDL!K|ujbO--@4w}<odb0j7v!rIyzHa0eJc6Nr9m6hxl6&2z1^z^6j=jZ3)>+6e} zni}Nf<iNth0?Z*aG!*&y`SM+6W+u|o(vXyt1RozC7#ka7ZEfve<1!9&Z*FczLqh|y zv$IiAQGxREas&qlOO1Yhen?MGSK`OV$HU0T2pbz4D!8nlIZ>;am>5JwMIj<00%2ic z@b>mrp0%~LMNdx;y1Tp4+1ZJ<wl<0V;ll@*n3%xH$w_M0)YO#snIG#<PEHoyudc3? zu})4-kdcvriHQje4-ccSuTSE(wzdjK{r&w|TwFv*NC>`s`GSFg0rd9vD)Gs&y}dnH zBbS$#muOmCTr4~!BqYGl&`@G1yhKduLoW^u4N1JNt}YO>zP=vr?(XpS_eV=h3nnKg zF*Y`ak&zK4KF?}sXu!qAMKH-3{p;Z108dX(1O^6TcXt<CTU#o1(u>sS)2C13L-I_H z$!~OYw0L1<Wd#ch3;6u`GqSR>;O6EAeSLjsX=y=6M@N>TPM+i6%!7V5Ffb6lU)Nbu zQX+LxtEHtS%*@P4J*>O3vJ&d*>e3JNDZLmF5CHmv9*vBQgq@w8V6%6*PaT*S>tIYi zkB*M2)LB+m269B5Ha9o1yu2)2kB^Vb+^MUpLrO}D^hRuKtaz)mv=n)Hc}Pu7g|4nH zs;jFpJw2_$KXa!3^xyUMwF)L{As#)#UMKgftE*s764%kuQS#=j;hb@Gb(Lr4N?oW0 zai^xH#4FTOf#1>5AzUbU<((d4pAQZW3ZLJ;eZ&6#KDM{FrJtz{dxtq)US7)VAs1$5 zW(W@tms-g$eZ+IzTVG!X^{3zITl(%tOmauQspG}Ph2(K?aDbhi9qDK0O@4U4zrV-r z?JdsE&LmfQnwYHd@bFMP{q^ft$(i`<qnn$XH<(RLO&~^LVWDu9o0|*89Q*k3qx32J z#?sOf%#XN_kB>@x)=xa1)z;QVZEdYQv$r^BUe~DLmc97={EYA4zvJoY2@eks;N0NM zVs9(n;dhOVjWT!0D`y`y_3-czU(;vox1gXP;f;MyKPcW;+&TMRzfV6Bhc%P4fBJ2x ws;ZJb_8{jzb>vyb;mjxRoF&xbM_v`Uzv50!*-O77_Ipg#|E1pf`2X_p7kq&=RR910 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-refresh-sm.bmp b/mechglue/src/windows/identity/ui/images/tk-refresh-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cfee8f71b7a9e6d9db3697f8a09e9f63cbd120ad GIT binary patch literal 822 zcma))p>Kmg6vn&EO^{`xS&$QC=^s!rF)_Jh6%`c~6%`eTiU~wT1p<LMQGr05IB^1j zIDtSQ5GN`sCTN00R8&+{AP~#G^+>a|S;sH$9=UfP?>@MDdFx)c4s?+pF>dQ|)w(~_ zTlKn{s5~Bzn#X#*o|-0OtSrmVizG<`CBm|-f5obk<2Vr8_I%$AN-4y|b+^rcZHPV3 zE1D4m9AdncWm%r*KQpGPg5r@d3?W8d{lW4#LWnR3;y6muL`pf~CJ{u+R7H9Qlz_&x z?donwG@?(r)u%%ekhmr~JdwWxM}QvjGU|BUXTLW~-GLZuwm$Sm*!l<zE3hvNJ`m&8 zA7n+2Q%g6?cRn}i)Mq}gVVu_iF}}S=`&MEX`wb3pTkZ_@bYtJiTyD-#e_dpePK=p! zoYi8OOyG@uu(CS6PE}Ryc3Xrjq_ODGjKO)Bhnm|KnZW7^a0_rh0i5uRYt9`yU$~@7 F`~_t)MC1Sf literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-refresh.bmp b/mechglue/src/windows/identity/ui/images/tk-refresh.bmp new file mode 100644 index 0000000000000000000000000000000000000000..54f1a01b261c791b9f9d62d88ff498543f7568fa GIT binary patch literal 2430 zcmcgtA<U~*810@|vI;~+vvgU-Fa9hQPdrh9sHkX`Cab7GASx;<5ET^&1fl{_fj}S- z2m}IwKvW<QWI-Sh2$moa2*eeLii!%d)AIkck9EuYvur0HH<t_d-1D9LU6}qR{?NH$ zjP@5?KjZod*LR&C(RMn&;`#4XeccAo{PEx5f8kxN*g9B-`9QF5voN<w{;qd@1Ix0D z#eBQn3f~MUST2|K^v!x*Q{Q<xj>9v&6vuJ(5u8pZXqe4r(EEgUx7$IiX__D5e0#Sn z%h6~wolc>wtykdr<MBucIe!hz`4-rgwOlNo@QR}7I8IR%$m<b#o;MksPbDdevMA6Z z8lZ3JI(*)2Hf_C<Bsq=^7D#?Xk|b}umkW4{EX&ihjx0-?P!(mxGTSZJ=9T4xZQE&@ zHY(~)7>14B>T)J|mc}t6d5Ans4wAH9t$3bq^Qx)>kDv~cvm4L>JkPuHR@LQ1(kP08 zppGnwPeqPIL_vTFFtg38X&Q<FQy>}aXluaqcOSrdxs)UdeBX5uX%t>gB?j>V8~|Wu zo7XT5(=>u0K>a=f<5ynHy~epnV%M<|X&Br{Z{t-36Huuzv&{<=!0Y=yBtHUqG`we0 z_}E<2^c)*bUzOJDRTa)0%!Qe4UgQgDuIoaw8@Q^Y>POx4Jz17(UYJ-Uk)>&ds(H2r zqu-ObKF4_z1OX!2ykOLIoinzs@2RfZl_*N=@dl41P|lzLZ(v)REF)aYxSIgURYlX| z{a(b&ZC>pAOqq2>3e@1G<iYFVvtp}LYepM%k|x#p61ld1kktJ?@|@~?e$@MUG{UCA z%r-C5A0O!MzTcN#Ovj|u;aHxmZH`j=SZu0J3e*$MMG|JAkE*~j*ML~GRW%$Av1!Mn z)8@rq!3S1Z_mx*QFp@0u;$UEou*~={St}b<>^0%PL9f@tbR^y8?aI^_jb^Pi=x~nV zDIujBd0UMaOmS~Xs;Vw-n7;#i)!_S2pRn@~_ZMD~qV@yoFwDyw<quhCJrYvJfKmro zRd9tU3tOkWxy7#lJCCE(=A9e!<$+y@j7jV!SHBFm!R|#Fb;T|haOo*+9zAw&?D3bW zzX5Gt<SqwFPajgoOOmHx^kSc~hO{-)LY=qxmAML|@bM_teaK`O29--lfoSsvdC*m; zuGIgsrzg^!GKY+`qSYxXq`RjWo<Z5;L_GzZZNB|&-jt+MbM~UVDzUl?1uU>Ra^yt% zhatu{-UhyZ{U>>HSCgW>|2J{t<sKjK<V<GAIck<RCNME3G3RqZ@lQoodyRd5&fARs H`%dRiaJALj literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk-sm.bmp b/mechglue/src/windows/identity/ui/images/tk-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c89285c610020899f23ec1e486f0a6b7ea1370fc GIT binary patch literal 1014 zcmd^*%S#(k6viX2ZHpjuqjce-;6muaon5$aQBV*S1VM{f6f}xjTo}<>A8{IRZ1ZXp z^P2IIsHw)Wf@q;qF_fr85)E2v5ftjet=nHG%FLqiA1HqCJD1CMzH_*@tl~P`aHA5n zK2>?7@=ztq@I<Y*+J0a#q|ua0rTCvoCX>YDah>#Cd(XdKB9YKNt!GrU(Pj_QD9%zV z$aIgr*LxaF0{NW|9vkg9yc)3Ro|d0<c^M3TrCF4z6a18S4$(9If%cI}id%;%Fj~oN z5y>$v(Q3A5<ZV+v2HYWh2Y(QMTrjwGM#uUu8di>}oIj*gI-tlNCC})*Gylos$09AF zoLnI%F0sZgc>Dc~?u}ELloP5Jj(F~kQTW<LyWq&!@9_t4%q+0F|C8xx3g^}#=Cxh= zR${b$-lbmN;e~UPXC^OQmX8^ENs>7FeNN<C6nTA{t~X}p7sE`?g?QQjjwaU^YHSgz uXZPrx$jmE>LVAWTAmR1}h$yT2j$n8h!Qo-l=4Qz1Mhb;>Py7G-e*OhgI1!5g literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/tk.bmp b/mechglue/src/windows/identity/ui/images/tk.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e689cb830bde150c95e6390d225620fe65ce655e GIT binary patch literal 3186 zcmeH|T};zw6vo-rZk+qfb^%M=k}YIrUu=O*F}UIQ66gx@VG(Q#<*O~Uw0{`!bB;|E zWQcP_Hz9(e;uMr2O2=T+jxnWBD3l_gAR;O;A=#E?H^05I?1Gdf-OaB0CeM5E=Hxs% z=XuU~-;XI+=Cg1D#qBTfynwI3BR(s{{r9=D+{fo3{y9#k6ED0y@Or>A53C9eCpKNr zdbN%SrH&6aYY9!$5)cxG!{Kn7rLxK@{G$}CjMum!C{pegzmyL0%zR3Jy2XwkCMoQ= zf&S7s8Lgv4?mfk>(lWOktK}*9?eF2~il2GByn7K|-;n7RzZ7RemVx~}Q+#Y0qWHof zhVyo^&-S5g>?JTdkv;n=vD@u*b#<ZA8t_+d<E4sD{PuS6%x4yse<HBEYk}KS&W*W7 zw$!!qZfr6#!%iagJ6NaPPDsvHLh?$8E^lOYawb74Gr?6BUQkH*C7F3H!NgPX1w1A< z@aWo<|HPT9Euf^Kjl9omsqUSjqGy^<uS~JE>n5h}Cdh3YL)9`$a?=R1#$m!523b>Q z=j|hXtUT1qiwCc=EHsTLM4vsaQ>8aie)<y9fuqz7+~tt%4wXH(*=@bWcA>G<F@f&l z80p`RqG%pLetMXQ6AnV^2MDa`=heeDo($WJuh9671kd!;<eNFzWMNx%J!hQvIW~Bg zulnv#^~-Jc2ygBDagw6%Z;&UvrD?s+re+uM-wYFV(!qPj26(5opJyYKyj*>aw-U2F z@=%UZqNb&TlEcTjIR1d9kvSS1_c+o&%NJK?DC?eP*X2oy1+SrfoU9AiNjv8v;f#~$ zQ$vIvAH;XPnm50;5tN+m5vSf%NJCpE<uxa`JT*`I!~@Q`<~TWYk6QaIUtXKRRNqc< zOCMW0Z&F~HAV+AdJntgutdrQrAy&kw2|j9PmBKSlqf~@-&_%k=fKq2<Q?7yJYy%s_ z+y+N|NTO0hY1uxs1!lq%QwfMs5Gd*i5Pf`2%;PI@8iJ$)gf}=?lak|6ol?<9-2d%Q zrsn^^HTOIHv%k_kJx{Z3oNRsmq8v7xjYx%hVSh*q`(um@;jI+mtvI3a+SJ@d@k{N4 zhi@{O46{^-(JYZ~lF%8=<QPoEC2hoNwYudf5xXfaLx)_GhfM6uXtkb5m5wl_mUZ$Z WxA=eK^}c)dH+lQy?bHA1fxiH2|MYzT literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/vw-refresh-sm.bmp b/mechglue/src/windows/identity/ui/images/vw-refresh-sm.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e3d321ca4d7fe336614a6e6b00c56e21147f594f GIT binary patch literal 822 zcmZXSFO1?q6o<K7a-yQSR5X_n6)T#{iV6e*v7(}4l3RhOIB}u^v7({^fv7-KAXZc$ z5C{YUSy6$gKp-kA5Xch<1OkCTAjo}THci?4<#jTB^YzX9Q}<WrYwNBK>rbBVAJ3Q8 zkGsG1ajss}+V2OojmP8ldVOo?a=C0ao8e$kGf@~SD~h54e%|JJ7DZtcMe%Tmm1X&v z`0u@{$~cabB+0Vu`l#da$aSob?(1^7Ow;%C`Fy=zu%cM?dcAKAnWl*czXFJm=Q;f0 za8RW0`!F3#^K4AlG#w8Cf*^o_B=ghh<T#FD7~Aa@zu(q`p=-KnnL;|E{}$0Sg1D{= zx!dh%7ZFr{@DC(WP2I2z(|ME6^3|twYJ{O!_}Og6K21~nwr%%4T{nay+W9cb7U}Ol zA$~|0>aD7ZPgL@wyKKvl9r5(k{#!0?w=I?=@7%~VA>ox^Nrw1jV+kSMXZb4QQQ)*a zVcC<(L}7fw#Hk1|#4rr0tJ`(EFJAXWdeR?_5=yI?{eDkdD5t5_YDLe%lz3IA1ZM<@ w;Pd%>@hGZ8wU4lnj6jL>NU|2~s`u0B6j))+KZJ2`HK+Vns#ol}8nVXz0ojw=N&o-= literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/vw-refresh.bmp b/mechglue/src/windows/identity/ui/images/vw-refresh.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e87aa3cbc0ba1329e76b173ea9089d895e107340 GIT binary patch literal 2430 zcmchYEsPpL6oBaok|I{D*fiS|fglay#0kWT6$sLhw4!1KVg&-R0)be8K%77z5C{a~ z#0mrgfj}TmkOqN3AZUU>AP|TXh!rPDzh%PQX6`O+)1Q~wxp%Ygee>R%H%sAj^KIfR zdFGEiA9&vLyh*%cP9#3@{+lMA^8(ZNe<S~e>$>GX8?H?LDc)+eQmv@N_x<sByxZ+g zF$u$PHk)<3-RJhK2=o)T=6Uhq`}O<#`xxy7_2J>6)9J*$&{eKquglTtw3QfNpk9_n zqY*(w<4jPw%|=6vcDo&h$BWl5{Ux)ekVZr0-d<$C-#z}m42Q#3s|7>l5+=fdD9q7l zh;^}8EEEdNNTpKY(6-x6+%h~KS%jc+S?%|G$K#RXMh=HPnHh$WOeRw=3G3`Jolb>4 zGt~g1a{K-M*$D1&v6yGGS!m20NTisl+hR1TR<ubzpQkS)EtRU*YPc{sY9J~%2!hpW zMZAN-K+`nBVRJf(kgImew^N1&M0akCz%@{UV1PXvu<E)ljtEs&xh!oq8|n*`@5bHT z9j(A-hMwv=QCzSz-DFr<v-Q=?UFR`iV}bTO51ouvE^SC6wrvwB2POI|I<f1db0eW? z-MH5ET(6R217U*~Ibp%gq{J$BGMQ|*+fu27h2uCXS2F;W)A_)0>Rw~i{Q_OsPz_v= z`Fu{gDwnO+>-BQE%w#ecaV)qI0(#(48!C`aX9|bu;1nKKi*CD9!vLsZnAp%^bRKAx z%Mwt~G%T2_t1F@w<;!QaLCq}NX{Tr{r|nZXKRvcir_FdWHPcbs(9t*|i^W3a0+m8K zmK8M=g@YbNq#5Oc>6LSqWzS}%!LVuBB`RZ>nbvJfI-;mtGD3)23il$H%RxVjE=r;4 z8O`9((nMOTMc=%O{R}7sl}nQ$Btox9!Hst2D@>-<D!mka6n($Z>-EovG{ZoOAgEm0 zMF>!O4&l(^Lc_@YQ200gmPm!W%H3atZMh?a`I<a`ODQhidzH)4OQDguX?%vb?>`lw z(h)`FiVH4hEJ&8087XwA)P=&9Bqv>jqH^WuF0LF72kMBw_%+~KBWys4IQ_V#)KxD3 bi+lOnOa>J3wYOqjK$)L@kLA)|Q4&7@PPaZf literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_collapsed.bmp b/mechglue/src/windows/identity/ui/images/wdg_collapsed.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4299854d37656e8af34046a7288c9fdcd5ff0d10 GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZ1H%zM2nGuPiR*(Bz+8ug#&j=G(SO_k y(~oHC8yXsrbq|z!pffN5&|w4R9(b4lT?J<o;~r$iSk(h#5a=mf05g6`5&-}Xj2K=3 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_collapsed_hi.bmp b/mechglue/src/windows/identity/ui/images/wdg_collapsed_hi.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cb06b8acbffb74d8fc7208bcf2044038cf4230b1 GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZ1H%zM2nGuPiR*(Bz+8ug#&j=G(U0x( za3M@T0!4luSr12;Tr?|y3VvTY0!Nr!O!a^6T!bT_dN>=%0CF+a|9$xoD2@pr;+X3H hBLSc;B;J1@cVN{cI|j(cbPv#Zm_CJzpgEpYE&$N+^RoZ| literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_credtype.bmp b/mechglue/src/windows/identity/ui/images/wdg_credtype.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3bac3fe5356ebaa52ba3b32cad80f2f95cde1d3a GIT binary patch literal 1014 zcmZ?r{l?4y24+A~1BeBHm>-B485Dpd1RUXGU;tqlxPJZm|G|bYUcC6fy1wCmWnIJn z^4f;~eUqk;<i?XHPySCXZ~WhP;O778?N|PXW|xwzKeN8`|BSQG|2H3g^gptoYS`;f zNJ#i!R$2AGu&nZbMnTE{>gh}1{`bkP{U4BC_}@FF;J<5P{{Q&AGK}zOZ*Twq>g%un zS6_eqfAHal|7)(lhU?GUdG~+Rh8zD~mtFpEIOp7d_jJtoXliPrNPkI5$^TklnyIL* x|6f{N|G%)Z_J2-!&Hs$js{g6QmH!h9EB?pkm;a9jy1k~o2gCh?Ee{au9stj97JUE! literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_expanded.bmp b/mechglue/src/windows/identity/ui/images/wdg_expanded.bmp new file mode 100644 index 0000000000000000000000000000000000000000..76ee5b016d83fd71f1bcdc92a204eae9607d71b2 GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZ1H%zM2nGuPiR*(Bz+8ug#&j=G(SO_k h(~pBweFHWC^wv;uKdu<SbU!c#fr7XIX8e*Q0stN7Axr=O literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_expanded_hi.bmp b/mechglue/src/windows/identity/ui/images/wdg_expanded_hi.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8180b33337d8a120782268a15105acd581e7e1d5 GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZ1H%zM2nGuPiR*(Bz+8ug#&j=G(U0x( za3M@T0!4luS&s{0RsZ|a5nKqX`agFr;zC%}|9$xoD2@pr;%Ht5D*KNc0A&ZcdZ6<# MeF_&rb3CbB0NpSIU;qFB literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_flag.bmp b/mechglue/src/windows/identity/ui/images/wdg_flag.bmp new file mode 100644 index 0000000000000000000000000000000000000000..c563c56e9f04b8e5cd118bcc4a2728b9d28099f8 GIT binary patch literal 1014 zcmbu6-77<39LFd3_!FeWQbO4-l$c9K@^Ygn%;_u+I~hY>c7e@}Q?eOxv$dv~rLoMi zE2osXn7t)$7mA`xDK5XxIXbI}spD7Q=lAqH&*%I6e$S&)zvs$?P;g@@rvgs-oN{D^ z-1rqIc`_L<F_Ot7{*u$_{PRpU50WGikH;l@xLht+EEdT;UmHOX|Kd$16a0R^WRFNB z0*ay}^L!69O(Pr*OZITP-RRd0WaSS70ijR6Uhz+((I{4|HmJG?6jxNI*TsE4vn-2| zQ9X=|6-Ju_#PkAsMrY7LO`=gdfi`9r?Vcp$>TWO$li|VNMGjJkKcsN>@P?z?6t)x3 zSUZ2jB72Xq<2z^$t^~f;#-dVLlfj$KW?Wp};QHkQr}wY$Uq1cHH#njwQr06F3<@56 zZw7+_F3%ol!xVJ-aZJw6VT7A&^;761Y4qCm)A#edT)%;)mR5nc+wIWlbntq;88wM- ulSm}6yt0bsz9H1nOHj=3plo;<CFNC!#bQ4)BKtjuLLsbgZo%jCrMXXo2o3T8 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_stick.bmp b/mechglue/src/windows/identity/ui/images/wdg_stick.bmp new file mode 100644 index 0000000000000000000000000000000000000000..071a238c4d9fe2ddf0c475d1803a2776db76d5d7 GIT binary patch literal 774 zcmc(ZOA3HM3`47eTU~ktPv8OEdv|vpXABc4bpq0r7Ml6+(q=!#!D?;L6+NRTbY~0H z?Ck6Dkn4{^g8W**r4)wFxSXf!-4bE&v~U+xy~@)?RZE5k6N?$*Sib{nBH`y_K1OZA S@EId%V6`}(fqjL};m-}3SO&fT literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_stick_hi.bmp b/mechglue/src/windows/identity/ui/images/wdg_stick_hi.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8857fec2207fad491c611187501d8dd5e2bcf147 GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZm_i}04+H?ZfOu<xihpdM2XQnpx_~Nw z9a#_8g<lI$+3!n7AX<RBAR2*O2*A_}6#sMQB9H{?!bCuEG%Y}pzb_v`bOAM@A&7b) zi46Y#{}1E>bzvf)IHvg!^*|C6&_X@3Q_&m);Q|!^T>>YuszDZns{}HT#qqH5s009^ C@cUl? literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_stuck.bmp b/mechglue/src/windows/identity/ui/images/wdg_stuck.bmp new file mode 100644 index 0000000000000000000000000000000000000000..68295181d54551f38d7ae37a326dd285cd71542c GIT binary patch literal 774 zcmb`CK@vbP3`K((Tb7RC1P);D?sksD*RP#OwG1+oG)dq8YMkmyTnwl^vPCw?LON8D zxpc>=EPq6Byfq`a`rw#R0r2c`VsptGXRV4Qv}M&K`;WY~)qUPP+-eDWg!x}=%$psx f7wl0DkC9hKm4aXJl<2RZN5n5N8)8pLBTS7O`9Kui literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/images/wdg_stuck_hi.bmp b/mechglue/src/windows/identity/ui/images/wdg_stuck_hi.bmp new file mode 100644 index 0000000000000000000000000000000000000000..3b780712914f23410e4d6925e485edb8cda6f6a2 GIT binary patch literal 774 zcmZ?rWn*Rl12Z700mK48%n!tj3=%++f#CuZm_i}0Qv<+FBxo2!<&W+2APB<6qYJ3u z*OB#b1k?o-!Kxl&)bC42FcGE}pa{gMKX)!-BCP6xZUBn^efba*p{WOQ;cfu3|Dysl z#X!FRMc{4#vVj1u1Hwh~FHjK84G?7zaUhAN9%2RDOk@UD#bl_5XaSlAHyp?Y0!){n Oi9nPQqY_OcE-nE4K?Gj_ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/ui/khmapp.h b/mechglue/src/windows/identity/ui/khmapp.h new file mode 100644 index 000000000..7f12c7ffa --- /dev/null +++ b/mechglue/src/windows/identity/ui/khmapp.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHIMAIRA_H +#define __KHIMAIRA_KHIMAIRA_H + +#include<windows.h> +#include<windowsx.h> +#include<strsafe.h> +#include<commctrl.h> +#include<htmlhelp.h> + +#define KHERR_HMODULE khm_hInstance +#define KHERR_FACILITY khm_facility +#define KHERR_FACILITY_ID 3 + +#include<khdefs.h> +#include<khlist.h> +#include<kherror.h> +#include<kconfig.h> +#include<kcreddb.h> +#include<kmq.h> +#include<khmsgtypes.h> +#include<kmm.h> +#include<khhelp.h> +#include<khuidefs.h> +#include<utils.h> + +#include<resource.h> +#include<credfuncs.h> +#include<appglobal.h> +#include<mainwnd.h> +#include<mainmenu.h> +#include<toolbar.h> +#include<statusbar.h> +#include<credwnd.h> +#include<htwnd.h> +#include<passwnd.h> +#include<newcredwnd.h> +#include<propertywnd.h> +#include<configwnd.h> +#include<aboutwnd.h> + +#include<reqdaemon.h> +#include<notifier.h> +#include<timer.h> +#include<addrchange.h> + +#endif diff --git a/mechglue/src/windows/identity/ui/lang/en_us/khapp.rc b/mechglue/src/windows/identity/ui/lang/en_us/khapp.rc new file mode 100644 index 000000000..b139effdb --- /dev/null +++ b/mechglue/src/windows/identity/ui/lang/en_us/khapp.rc @@ -0,0 +1,712 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\..\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\..\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAIN_APP ICON "..\\..\\images\\main_app.ico" +IDI_ENABLED ICON "..\\..\\images\\enabled.ico" +IDI_DISABLED ICON "..\\..\\images\\disabled.ico" +IDI_NOTIFY_NONE ICON "..\\..\\images\\app_notify_none.ico" +IDI_NOTIFY_INFO ICON "..\\..\\images\\app_notify_info.ico" +IDI_NOTIFY_WARN ICON "..\\..\\images\\app_notify_warn.ico" +IDI_NOTIFY_ERROR ICON "..\\..\\images\\app_notify_error.ico" +IDI_CFG_DEFAULT ICON "..\\..\\images\\cfg_default.ico" +IDI_CFG_MODIFIED ICON "..\\..\\images\\cfg_mod.ico" +IDI_CFG_APPLIED ICON "..\\..\\images\\cfg_applied.ico" +IDI_CFG_DELETED ICON "..\\..\\images\\cfg_deleted.ico" +IDI_ID ICON "..\\..\\images\\id.ico" +IDI_APPICON_WARN ICON "..\\..\\images\\app_state_warn.ico" +IDI_APPICON_EXP ICON "..\\..\\images\\app_state_exp.ico" +IDI_APPICON_OK ICON "..\\..\\images\\app_state_ok.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_TK_REFRESH BITMAP "..\\..\\images\\tk-refresh.bmp" +IDB_ID BITMAP "..\\..\\images\\id.bmp" +IDB_ID_DELETE BITMAP "..\\..\\images\\id-delete.bmp" +IDB_ID_NEW BITMAP "..\\..\\images\\id-new.bmp" +IDB_ID_REFRESH BITMAP "..\\..\\images\\id-refresh.bmp" +IDB_TK BITMAP "..\\..\\images\\tk.bmp" +IDB_TK_DELETE BITMAP "..\\..\\images\\tk-delete.bmp" +IDB_TK_NEW BITMAP "..\\..\\images\\tk-new.bmp" +IDB_VW_REFRESH_SM BITMAP "..\\..\\images\\vw-refresh-sm.bmp" +IDB_TB_BLANK BITMAP "..\\..\\images\\tb-blank.bmp" +IDB_TB_BLANK_SM BITMAP "..\\..\\images\\tb-blank-small.bmp" +IDB_VW_REFRESH BITMAP "..\\..\\images\\vw-refresh.bmp" +IDB_ID_DELETE_DIS BITMAP "..\\..\\images\\id-delete-dis.bmp" +IDB_ID_DELETE_DIS_SM BITMAP "..\\..\\images\\id-delete-dis-sm.bmp" +IDB_ID_DELETE_SM BITMAP "..\\..\\images\\id-delete-sm.bmp" +IDB_ID_DIS BITMAP "..\\..\\images\\id-dis.bmp" +IDB_ID_DIS_SM BITMAP "..\\..\\images\\id-dis-sm.bmp" +IDB_ID_NEW_DIS BITMAP "..\\..\\images\\id-new-dis.bmp" +IDB_ID_NEW_DIS_SM BITMAP "..\\..\\images\\id-new-dis-sm.bmp" +IDB_ID_NEW_SM BITMAP "..\\..\\images\\id-new-sm.bmp" +IDB_ID_REFRESH_DIS BITMAP "..\\..\\images\\id-refresh-dis.bmp" +IDB_ID_REFRESH_SM BITMAP "..\\..\\images\\id-refresh-sm.bmp" +IDB_ID_REFRESH_DIS_SM BITMAP "..\\..\\images\\id-refresh-sm-dis.bmp" +IDB_TK_DELETE_DIS BITMAP "..\\..\\images\\tk-delete-dis.bmp" +IDB_TK_DELETE_DIS_SM BITMAP "..\\..\\images\\tk-delete-dis-sm.bmp" +IDB_TK_DELETE_SM BITMAP "..\\..\\images\\tk-delete-sm.bmp" +IDB_TK_DIS_SM BITMAP "..\\..\\images\\tk-dis-sm.bmp" +IDB_TK_NEW_DIS BITMAP "..\\..\\images\\tk-new-dis.bmp" +IDB_TK_NEW_DIS_SM BITMAP "..\\..\\images\\tk-new-dis-sm.bmp" +IDB_TK_NEW_SM BITMAP "..\\..\\images\\tk-new-sm.bmp" +IDB_TK_REFRESH_DIS BITMAP "..\\..\\images\\tk-refresh-dis.bmp" +IDB_TK_REFRESH_DIS_SM BITMAP "..\\..\\images\\tk-refresh-dis-sm.bmp" +IDB_TK_REFRESH_SM BITMAP "..\\..\\images\\tk-refresh-sm.bmp" +IDB_TK_SM BITMAP "..\\..\\images\\tk-sm.bmp" +IDB_HELP_SM BITMAP "..\\..\\images\\help-sm.bmp" +IDB_HELP BITMAP "..\\..\\images\\help.bmp" +IDB_LOGO_SHADE BITMAP "..\\..\\images\\logo_shade.bmp" +IDB_WDG_EXPAND BITMAP "..\\..\\images\\wdg_expanded.bmp" +IDB_WDG_COLLAPSE BITMAP "..\\..\\images\\wdg_collapsed.bmp" +IDB_ID_SM BITMAP "..\\..\\images\\id-sm.bmp" +IDB_WDG_EXPAND_HI BITMAP "..\\..\\images\\wdg_expanded_hi.bmp" +IDB_WDG_COLLAPSE_HI BITMAP "..\\..\\images\\wdg_collapsed_hi.bmp" +IDB_WDG_CREDTYPE BITMAP "..\\..\\images\\wdg_credtype.bmp" +IDB_WDG_FLAG BITMAP "..\\..\\images\\wdg_flag.bmp" +IDB_FLAG_WARN BITMAP "..\\..\\images\\flag-warning.bmp" +IDB_FLAG_EXPIRED BITMAP "..\\..\\images\\flag_expired.bmp" +IDB_FLAG_CRITICAL BITMAP "..\\..\\images\\flag-critical.bmp" +IDB_LOGO_OPAQUE BITMAP "..\\..\\images\\khimaira-cfg.bmp" +IDB_IMPORT_SM_DIS BITMAP "..\\..\\images\\import-sm-dis.bmp" +IDB_IMPORT BITMAP "..\\..\\images\\import.bmp" +IDB_IMPORT_DIS BITMAP "..\\..\\images\\import-dis.bmp" +IDB_IMPORT_SM BITMAP "..\\..\\images\\import-sm.bmp" +IDB_CHPW_SM BITMAP "..\\..\\images\\chpw-sm.bmp" +IDB_CHPW BITMAP "..\\..\\images\\chpw.bmp" +IDB_CHPW_DIS BITMAP "..\\..\\images\\chpw-dis.bmp" +IDB_CHPW_DIS_SM BITMAP "..\\..\\images\\chpw-dis-sm.bmp" +IDB_TB_SPACE BITMAP "..\\..\\images\\tb-space.bmp" +IDB_WDG_STUCK_HI BITMAP "..\\..\\images\\wdg_stuck_hi.bmp" +IDB_WDG_STICK BITMAP "..\\..\\images\\wdg_stick.bmp" +IDB_WDG_STICK_HI BITMAP "..\\..\\images\\wdg_stick_hi.bmp" +IDB_WDG_STUCK BITMAP "..\\..\\images\\wdg_stuck.bmp" +IDB_FLAG_RENEW BITMAP "..\\..\\images\\flag_renewable.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MENU_BAR ACCELERATORS +BEGIN + VK_F10, IDA_ACTIVATE_MENU, VIRTKEY, NOINVERT + VK_UP, IDA_UP, VIRTKEY, NOINVERT + VK_DOWN, IDA_DOWN, VIRTKEY, NOINVERT + VK_LEFT, IDA_LEFT, VIRTKEY, NOINVERT + VK_RIGHT, IDA_RIGHT, VIRTKEY, NOINVERT + VK_ESCAPE, IDA_ESC, VIRTKEY, NOINVERT + VK_EXECUTE, IDA_ENTER, VIRTKEY, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NC_NEWCRED DIALOGEX 0, 0, 301, 167 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "UI Row2",IDC_NC_TPL_ROW_LG,7,31,287,18,NOT WS_VISIBLE | + WS_BORDER + LTEXT "TplPanel",IDC_NC_TPL_PANEL,7,7,287,153,NOT WS_VISIBLE | + WS_BORDER + LTEXT "UI Row",IDC_NC_TPL_ROW,7,7,287,18,NOT WS_VISIBLE | + WS_BORDER + LTEXT "TplLabel",IDC_NC_TPL_LABEL,7,8,45,10,NOT WS_VISIBLE | + WS_BORDER + LTEXT "TplInput",IDC_NC_TPL_INPUT,54,7,240,13,NOT WS_VISIBLE | + WS_BORDER + LTEXT "TplLabelLg",IDC_NC_TPL_LABEL_LG,7,33,146,10,NOT + WS_VISIBLE | WS_BORDER + LTEXT "TplInputLg",IDC_NC_TPL_INPUT_LG,155,31,139,13,NOT + WS_VISIBLE | WS_BORDER + LTEXT "&Credentials",IDC_NC_CREDTEXT_LABEL,7,66,41,10,NOT + WS_GROUP + CONTROL "",IDC_NC_CREDTEXT,"KhmHtWnd",WS_TABSTOP,54,65,240,73, + WS_EX_CLIENTEDGE + PUSHBUTTON "&Ok",IDOK,57,142,89,18,WS_DISABLED + PUSHBUTTON "&Cancel",IDCANCEL,158,142,54,18 + PUSHBUTTON "&Options >>",IDC_NC_OPTIONS,223,142,71,18 +END + +IDD_NC_BBAR DIALOGEX 0, 0, 60, 181 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "&Ok",IDOK,0,7,53,41,WS_DISABLED + PUSHBUTTON "&Cancel",IDCANCEL,0,58,53,19 + PUSHBUTTON "&Help",IDC_NC_HELP,0,155,53,19 +END + +IDD_NC_TS DIALOGEX 0, 0, 300, 15 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN +END + +IDD_PP_IDENT DIALOGEX 0, 0, 235, 156 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CAPTION +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Identity" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Name",IDC_STATIC,7,8,19,12 + LTEXT "IdentityName",IDC_PP_IDNAME,34,7,194,12,NOT WS_GROUP, + WS_EX_CLIENTEDGE + CONTROL "Default identity",IDC_PP_IDDEF,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,34,22,71,12 + CONTROL "Searchable",IDC_PP_IDSEARCH,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,117,36,74,12 + CONTROL "Custom1",IDC_PP_PROPLIST,"NetIDMgrPropertyWnd", + WS_TABSTOP,7,51,221,80 + CONTROL "Always visible (sticky)",IDC_PP_STICKY,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,117,22,85,12 + PUSHBUTTON "Identity configuration ...",IDC_PP_CONFIG,117,135,111, + 14 +END + +IDD_PP_CRED DIALOGEX 0, 0, 236, 158 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CAPTION +CAPTION "Credential" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "Check1",IDC_PP_DUMMY,"Button",BS_AUTOCHECKBOX | NOT + WS_VISIBLE | WS_TABSTOP,0,1,39,10 + CONTROL "Custom1",IDC_PP_CPROPLIST,"NetIDMgrPropertyWnd", + WS_TABSTOP,7,7,222,144 +END + +IDD_CFG_MAIN DIALOGEX 0, 0, 357, 222 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +EXSTYLE WS_EX_CONTEXTHELP +CAPTION "NetIDMgr Configuration" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Title",IDC_CFG_TITLE,0,0,357,20,SS_CENTERIMAGE + CONTROL "",IDC_CFG_NODELIST,"SysTreeView32",TVS_HASBUTTONS | + TVS_HASLINES | TVS_LINESATROOT | WS_TABSTOP,0,20,100,182 + LTEXT "Static",IDC_CFG_PANE,102,20,255,182,NOT WS_VISIBLE | + WS_BORDER + PUSHBUTTON "&Ok",IDOK,162,205,78,16 + PUSHBUTTON "&Cancel",IDCANCEL,246,205,51,16 + PUSHBUTTON "&Apply",IDAPPLY,303,205,51,16,WS_DISABLED + PUSHBUTTON "C&hange Summary ...",IDC_CFG_SUMMARY,3,205,76,16, + WS_DISABLED +END + +IDD_CFG_GENERIC DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CTEXT "Please select one of the configuration categories on the left.", + IDC_STATIC,21,17,212,18,SS_CENTERIMAGE,WS_EX_TRANSPARENT +END + +IDD_CFG_GENERAL DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Startup",IDC_CFG_STARTUP_GROUP,7,7,241,50 + CONTROL "&Obtain new credentials at startup (if none are present)", + IDC_CFG_AUTOINIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 16,22,196,10 + CONTROL "&Start NetIDMgr during Windows logon",IDC_CFG_AUTOSTART, + "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,16, + 38,135,10 + GROUPBOX "Other",IDC_CFG_OTHER,7,63,241,54 + CONTROL "&Run NetIDMgr in system tray after window close", + IDC_CFG_KEEPRUNNING,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,16,78,170,10 + CONTROL "Monitor network connectivity",IDC_CFG_NETDETECT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,96,106,10 + CONTROL "A&utomatically import Windows logon identity", + IDC_CFG_AUTOIMPORT,"Button",BS_AUTOCHECKBOX | NOT + WS_VISIBLE | WS_TABSTOP,16,147,165,10 +END + +IDD_CFG_IDENTITIES DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_TAB,"SysTabControl32",WS_TABSTOP,7,7,241,168 + LTEXT "Static",IDC_CFG_TARGET,10,21,235,151,NOT WS_VISIBLE | + WS_BORDER +END + +IDD_CFG_NOTIF DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "&Monitor credential expiration",IDC_NOTIF_MONITOR, + "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7, + 111,139,10 + CONTROL "&Renew automatically at",IDC_NOTIF_RENEW,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,9,100,10 + EDITTEXT IDC_NOTIF_RENEW_THR,122,7,126,14,ES_AUTOHSCROLL + CONTROL "Initial warning at",IDC_NOTIF_WARN1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,31,100,10 + EDITTEXT IDC_NOTIF_WARN1_THR,122,29,126,14,ES_AUTOHSCROLL + CONTROL "Final warning at",IDC_NOTIF_WARN2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,53,100,10 + EDITTEXT IDC_NOTIF_WARN2_THR,122,51,126,14,ES_AUTOHSCROLL +END + +IDD_CFG_PLUGINS DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_PLUGINS,"SysListView32",LVS_REPORT | + LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,75,168 + GROUPBOX "Plugin",IDC_CFG_PLUGINGRP,86,7,162,103 + LTEXT "Description",IDC_CFG_LBL_DESC,90,20,36,8 + EDITTEXT IDC_CFG_DESC,134,17,109,14,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Status",IDC_CFG_LBL_STATE,90,38,22,8 + EDITTEXT IDC_CFG_STATE,134,35,109,14,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Depends on",IDC_CFG_LBL_DEPS,90,52,39,8 + LISTBOX IDC_CFG_DEPS,134,52,109,34,LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Enable",IDC_CFG_ENABLE,134,90,50,14 + PUSHBUTTON "Disable",IDC_CFG_DISABLE,193,90,50,14 + GROUPBOX "Provided by",IDC_CFG_PROVGRP,86,111,162,47 + LTEXT "Module",IDC_CFG_LBL_MOD,90,124,24,8 + EDITTEXT IDC_CFG_MODULE,134,121,109,14,ES_AUTOHSCROLL | + ES_READONLY + LTEXT "Vendor",IDC_CFG_LBL_VEN,90,142,24,8 + EDITTEXT IDC_CFG_VENDOR,133,139,110,14,ES_AUTOHSCROLL | + ES_READONLY + PUSHBUTTON "Register new plugin ...",IDC_CFG_REGISTER,163,161,85,14, + WS_DISABLED +END + +IDD_CFG_IDENTITY DIALOGEX 0, 0, 255, 182 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_CFG_TAB,"SysTabControl32",WS_TABSTOP,7,7,241,168 + LTEXT "Static",IDC_CFG_TARGET,10,21,235,151,NOT WS_VISIBLE | + WS_BORDER +END + +IDD_CFG_IDS_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Monitor credential expiration",IDC_CFG_MONITOR,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,7,107,10 + CONTROL "Automatically renew",IDC_CFG_RENEW,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,20,81,10 + CONTROL "Always show in the credentials list (Pinned)", + IDC_CFG_STICKY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7, + 34,151,10 +END + +IDD_CFG_ID_TAB DIALOGEX 0, 0, 235, 151 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Always show in the credentials list (Pinned)", + IDC_CFG_STICKY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7, + 34,151,10 + CONTROL "Monitor credential expiration",IDC_CFG_MONITOR,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,7,107,10 + CONTROL "Automatically renew",IDC_CFG_RENEW,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,20,81,10 + PUSHBUTTON "Remove identity ...",IDC_CFG_REMOVE,139,122,78,14,NOT + WS_VISIBLE +END + +IDD_ABOUT DIALOGEX 0, 0, 268, 170 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "About Network Identity Manager" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,211,7,50,14 + LTEXT "Productname",IDC_PRODUCT,41,7,163,13,NOT WS_GROUP + LTEXT "© 2005 Massachusetts Institute of Technology", + IDC_COPYRIGHT,41,23,220,18,NOT WS_GROUP + LTEXT "BuildInfo",IDC_BUILDINFO,41,41,220,17,NOT WS_GROUP + ICON IDI_MAIN_APP,IDC_STATIC,6,7,21,20 + CONTROL "",IDC_MODULES,"SysListView32",LVS_REPORT | + LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,41,72,220,91 + LTEXT "Loaded modules",IDC_STATIC,41,60,52,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_NC_NEWCRED, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 294 + TOPMARGIN, 7 + BOTTOMMARGIN, 160 + END + + IDD_NC_BBAR, DIALOG + BEGIN + RIGHTMARGIN, 53 + TOPMARGIN, 7 + BOTTOMMARGIN, 174 + END + + IDD_PP_IDENT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + VERTGUIDE, 34 + VERTGUIDE, 117 + TOPMARGIN, 7 + BOTTOMMARGIN, 149 + END + + IDD_PP_CRED, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 229 + TOPMARGIN, 7 + BOTTOMMARGIN, 151 + END + + IDD_CFG_GENERIC, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_GENERAL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 16 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_IDENTITIES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 10 + VERTGUIDE, 244 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + HORZGUIDE, 22 + HORZGUIDE, 171 + END + + IDD_CFG_NOTIF, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 22 + VERTGUIDE, 122 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_PLUGINS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 86 + VERTGUIDE, 90 + VERTGUIDE, 134 + VERTGUIDE, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_IDENTITY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + TOPMARGIN, 7 + BOTTOMMARGIN, 175 + END + + IDD_CFG_IDS_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_CFG_ID_TAB, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 6 + RIGHTMARGIN, 261 + VERTGUIDE, 41 + VERTGUIDE, 204 + TOPMARGIN, 7 + BOTTOMMARGIN, 163 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_MAIN_WINDOW_TITLE "Network Identity Manager" + IDS_MENU_FILE "&File" + IDS_MENU_CRED "&Credential" + IDS_MENU_VIEW "&View" +END + +STRINGTABLE +BEGIN + IDS_MENU_OPTIONS "&Options" + IDS_MENU_HELP "&Help" + IDS_ACTION_PROPERTIES "&Properties ..." + IDS_ACTION_EXIT "E&xit" + IDS_CFG_ROOT_NAME "Network Identity Manager" + IDS_ACTION_SET_DEF_ID "Set as &default" + IDS_ACTION_SET_SRCH_ID "Allow applications to &search" + IDS_CFG_ROOT_TITLE "Network Identity Manager Configuration" + IDS_CFG_GENERAL_SHORT "General" + IDS_ACTION_NEW_CRED "&New credentials ..." + IDS_ACTION_PASSWD_ID "Change &password ..." + IDS_ACTION_CHOOSE_COLS "Choose columns ..." + IDS_ACTION_DEBUG_WINDOW "Debug window ..." + IDS_ACTION_VIEW_REFRESH "Refresh" + IDS_MENU_LAYOUT "Layout" + IDS_MENU_TOOLBARS "Toolbars" +END + +STRINGTABLE +BEGIN + IDS_ACTION_LAYOUT_ID "By identity" + IDS_ACTION_LAYOUT_TYPE "By type" + IDS_ACTION_LAYOUT_LOC "By location" + IDS_ACTION_TB_STANDARD "Standard" + IDS_ACTION_OPT_KHIM "General ..." + IDS_ACTION_OPT_IDENTS "Identities ..." + IDS_ACTION_OPT_NOTIF "Notifications ..." + IDS_ACTION_HELP_CTX "Context" + IDS_ACTION_HELP_CONTENTS "Contents ..." + IDS_ACTION_HELP_INDEX "Index ..." + IDS_ACTION_HELP_ABOUT "About NetIDMgr ..." + IDS_CFG_GENERAL_LONG "General options" + IDS_SAMPLE_STRING "Wxy" + IDS_NO_CREDS "<large><center>You currently have no credentials.Click <a id=""NewCreds"">here</a> to obtain new credentials.</center></large>" + IDS_WT_INIT_CREDS "Obtain initial credentials" + IDS_WT_NEW_CREDS "Obtain new credentials" +END + +STRINGTABLE +BEGIN + IDS_NC_IDENTITY "&Identity" + IDS_NC_IDENTS "&Identities" + IDS_NC_CREDTEXT_ID_NONE "<p><b>(No identities specified)</b></p>" + IDS_NC_CREDTEXT_ID_ONE "<p>Selected identity: <b>%s</b></p>" + IDS_NC_CREDTEXT_ID_MANY "<p>Primary identity: <b>%s</b></p><p>Additional identities: <b>%s</b></p>" + IDS_NC_CREDTEXT_ID_INVALID "<font color=""red"">%s (invalid)</font>" + IDS_WTPOST_INIT_CREDS " - Initial credentials" + IDS_WTPOST_NEW_CREDS " - New credentials" + IDS_ACTION_RENEW_CRED "R&enew credentials" + IDS_ACTION_DESTROY_CRED "De&stroy credentials ..." + IDS_DEFAULT_FONT "MS Shell Dlg" + IDS_NC_CREDTEXT_TABS "<settab pos=""15""><settab pos=""30""><settab pos=""45"">" + IDS_NOTIFY_PREFIX "NetIDMgr - " + IDS_NOTIFY_READY "Ready" + IDS_NOTIFY_ATTENTION "Attention" + IDS_ALERT_DEFAULT "Alert" +END + +STRINGTABLE +BEGIN + IDS_PACTION_OK "&Ok" + IDS_PACTION_CANCEL "&Cancel" + IDS_PACTION_CLOSE "&Close" + IDS_ALERT_NOSEL_TITLE "No credentials selected" + IDS_ALERT_NOSEL "Please select a credential, a credential type or an identity." + IDS_NC_CREDTEXT_ID_VALID "<font color=""blue"">%s</font>" + IDS_NC_CREDTEXT_ID_UNCHECKED "<font color=""grey"">%s (Unverified)</font>" + IDS_PROP_COL_PROPERTY "Property" + IDS_PROP_COL_VALUE "Value" + IDS_NC_NEW_IDENT "( New identity ... )" + IDS_NC_CREDTEXT_ID_CHECKING "<font color=""grey"">%s (Checking...)</font>" + IDS_ACTION_OPEN_APP "Open NetIDMgr ..." + IDS_CTX_NEW_IDENT "Obaining new identity" + IDS_CTX_NEW_CREDS "Obtaining new credentials" + IDS_CTX_RENEW_CREDS "Renewing credentials" + IDS_CTX_PROC_NEW_IDENT "Obtaining initial credentials for %1!s!" +END + +STRINGTABLE +BEGIN + IDS_CTX_PROC_NEW_CREDS "Obtaining new credentials for %1!s!" + IDS_CTX_PROC_RENEW_CREDS "Renewing credentials for %1!s!" + IDS_ACTION_CLOSE_APP "Close NetIDMgr window" + IDS_NC_FAILED_TITLE "Failed to acquire credentials" + IDS_CFG_IDENTITIES_SHORT "Identities" + IDS_CFG_IDENTITIES_LONG "Global Identity settings" + IDS_CFG_NOTIF_SHORT "Notifications" + IDS_CFG_NOTIF_LONG "Notifications" + IDS_CFG_PLUGINS_SHORT "Plugins" + IDS_CFG_PLUGINS_LONG "Plugins and Modules" + IDS_CFG_IDENTITY_SHORT "%s" + IDS_CFG_IDENTITY_LONG "Options for %s" + IDS_CTX_DESTROY_CREDS "Destroying credentials" + IDS_WARN_EXPIRE "Some of your credentials will expire in %s" + IDS_WARN_TITLE "Credentials expiration warning" + IDS_ALERT_MOREINFO "...\nClick here for more..." +END + +STRINGTABLE +BEGIN + IDS_WARN_EXPIRED "Some of your credentials have expired." + IDS_WARN_EXPIRE_ID "Credentials for %.180s will expire in %s" + IDS_WARN_EXPIRED_ID "Credentials for %.220s have expired" + IDS_WARN_WM_TITLE "NetIDMgr is still running" + IDS_WARN_WM_MSG "Click the NetIDMgr icon below to open the application.\n\nOr right click the icon to access the NetIDMgr menu." + IDS_CFG_ID_TAB_SHORT "General" + IDS_CFG_ID_TAB_LONG "General options for this identity" + IDS_CFG_IDS_TAB_SHORT "General" + IDS_CFG_IDS_TAB_LONG "General options for all identities" + IDS_CFG_IDS_IDENTITY "Identity" + IDS_ACTION_IMPORT "Import Credentials" + IDS_CTX_IMPORT "Importing credentials from Windows" + IDS_CFG_PI_COL_PLUGINS "Plugins" + IDS_PISTATE_FAILUNK "Unknown failure" + IDS_PISTATE_FAILMAX "Maximum failure count reached" + IDS_PISTATE_FAILREG "Not properly registered" +END + +STRINGTABLE +BEGIN + IDS_PISTATE_FAILDIS "Disabled" + IDS_PISTATE_FAILLOD "Failed to initialize" + IDS_PISTATE_PLACEHOLD "Not loaded" + IDS_PISTATE_REG "Not initialized" + IDS_PISTATE_HOLD "Waiting for dependencies" + IDS_PISTATE_INIT "Initializing" + IDS_PISTATE_RUN "Running" + IDS_PISTATE_EXIT "Stopped" + IDS_CTX_PASSWORD "Changing password" + IDS_WT_PASSWORD "Changing password" + IDS_WTPOST_PASSWORD " - Changing password" + IDS_CTX_PROC_PASSWORD "Changing password for %1!s!" + IDS_NC_PWD_FAILED_TITLE "Failed to change password" + IDS_CMDLINE_HELP "Command line options for NetIDMgr are :\n\n-a or --autoinit: Auto initialize credentials\n-i or --kinit: Obtain new credentials\n-d or --destroy: Destroy default identity\n-r or --renew: Renew all credentials" + IDS_PACTION_NEXT "Next alert..." + IDS_ERR_TITLE_NO_IDENTPRO "Cannot proceed without identity provider" +END + +STRINGTABLE +BEGIN + IDS_ERR_MSG_NO_IDENTPRO "There is no identity provider currently loaded. The identity provider is the component of Network Identity Manager that verifies and performs operations on actual identities. Without this provider, many critical operations cannot be performed." + IDS_ERR_SUGG_NO_IDENTPRO + "This is quite possibly caused by the identity provider module failing to load properly." + IDS_NC_REN_FAILED_TITLE "Failed to renew credentials" + IDS_CW_DEFAULT "(Default)" + IDS_ACTION_OPT_PLUGINS "Plugins ..." + IDS_NC_SETDEF "&Set as default identity" + IDS_NC_ID_DEF "<p>This identity is the default</p>" + IDS_NC_ID_WDEF "<p>Will be the default. (<a id=""NotDef"">Don't make default</a>)</p>" + IDS_NC_ID_NDEF "<p>Not default identity. (<a id=""MakeDef"">make default</a>)</p>" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/mechglue/src/windows/identity/ui/main.c b/mechglue/src/windows/identity/ui/main.c new file mode 100644 index 000000000..6f7f9bd47 --- /dev/null +++ b/mechglue/src/windows/identity/ui/main.c @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<shlwapi.h> +#include<khmapp.h> + +#if DEBUG +#include<assert.h> +#endif + +HINSTANCE khm_hInstance; +const wchar_t * khm_facility = L"NetIDMgr"; +int khm_nCmdShow; +khm_ui_4 khm_commctl_version = 0; + +khm_startup_options khm_startup; + +void khm_init_gui(void) { + khui_init_actions(); + khui_init_rescache(); + khui_init_menu(); + khui_init_toolbar(); + khm_init_notifier(); + khm_init_config(); +} + +void khm_exit_gui(void) { + khm_exit_config(); + khm_exit_notifier(); + khui_exit_toolbar(); + khui_exit_menu(); + khui_exit_rescache(); + khui_exit_actions(); +} + +void khm_parse_commandline(void) { + LPWSTR wcmdline; + LPWSTR * wargs; + int wargc; + int i; + + ZeroMemory(&khm_startup, sizeof(khm_startup)); + + wcmdline = GetCommandLine(); + wargs = CommandLineToArgvW(wcmdline, &wargc); + + for (i=1; i<wargc; i++) { + if (!wcscmp(wargs[i], L"-i") || + !wcscmp(wargs[i], L"--kinit") || + !wcscmp(wargs[i], L"-kinit")) { + khm_startup.init = TRUE; + khm_startup.exit = TRUE; + khm_startup.no_main_window = TRUE; + } + else if (!wcscmp(wargs[i], L"-m") || + !wcscmp(wargs[i], L"--import") || + !wcscmp(wargs[i], L"-import")) { + khm_startup.import = TRUE; + khm_startup.exit = TRUE; + khm_startup.no_main_window = TRUE; + } + else if (!wcscmp(wargs[i], L"-r") || + !wcscmp(wargs[i], L"--renew") || + !wcscmp(wargs[i], L"-renew")) { + khm_startup.renew = TRUE; + khm_startup.exit = TRUE; + khm_startup.no_main_window = TRUE; + } + else if (!wcscmp(wargs[i], L"-d") || + !wcscmp(wargs[i], L"--destroy") || + !wcscmp(wargs[i], L"-destroy")) { + khm_startup.destroy = TRUE; + khm_startup.exit = TRUE; + khm_startup.no_main_window = TRUE; + } + else if (!wcscmp(wargs[i], L"-a") || + !wcscmp(wargs[i], L"--autoinit") || + !wcscmp(wargs[i], L"-autoinit")) { + khm_startup.autoinit = TRUE; + } + else { + wchar_t help[2048]; + + LoadString(khm_hInstance, IDS_CMDLINE_HELP, + help, ARRAYLENGTH(help)); + + MessageBox(NULL, help, L"NetIDMgr", MB_OK); + + khm_startup.error_exit = TRUE; + break; + } + } +} + +void khm_register_window_classes(void) { + INITCOMMONCONTROLSEX ics; + + ZeroMemory(&ics, sizeof(ics)); + ics.dwSize = sizeof(ics); + ics.dwICC = + ICC_COOL_CLASSES | + ICC_BAR_CLASSES | + ICC_DATE_CLASSES | + ICC_HOTKEY_CLASS | + ICC_LISTVIEW_CLASSES | + ICC_TAB_CLASSES | +#if (_WIN32_WINNT >= 0x501) + ((IS_COMMCTL6())? + ICC_LINK_CLASS | + ICC_STANDARD_CLASSES : + 0) | +#endif + 0; + + InitCommonControlsEx(&ics); + + khm_register_main_wnd_class(); + khm_register_credwnd_class(); + khm_register_htwnd_class(); + khm_register_passwnd_class(); + khm_register_newcredwnd_class(); + khm_register_propertywnd_class(); +} + +void khm_unregister_window_classes(void) { + khm_unregister_main_wnd_class(); + khm_unregister_credwnd_class(); + khm_unregister_htwnd_class(); + khm_unregister_passwnd_class(); + khm_unregister_newcredwnd_class(); + khm_unregister_propertywnd_class(); +} + + +/* we support up to 16 simutaneous dialogs. In reality, more than two + is pretty unlikely. Property sheets are special and are handled + separately. */ +#define MAX_UI_DIALOGS 16 + +typedef struct tag_khui_dialog { + HWND hwnd; + BOOL active; +} khui_dialog; + +static khui_dialog khui_dialogs[MAX_UI_DIALOGS]; +static int n_khui_dialogs = 0; +static HWND khui_modal_dialog = NULL; +static BOOL khui_main_window_active; + +/* should only be called from the UI thread */ +void khm_add_dialog(HWND dlg) { + if(n_khui_dialogs < MAX_UI_DIALOGS - 1) { + khui_dialogs[n_khui_dialogs].hwnd = dlg; + /* we set .active=FALSE for now. We don't need this to have a + meaningful value until we enter a modal loop */ + khui_dialogs[n_khui_dialogs].active = FALSE; + n_khui_dialogs++; + } +#if DEBUG + else { + assert(FALSE); + } +#endif +} + +/* should only be called from the UI thread */ +void khm_enter_modal(HWND hwnd) { + int i; + + for(i=0; i < n_khui_dialogs; i++) { + if(khui_dialogs[i].hwnd != hwnd) { + khui_dialogs[i].active = IsWindowEnabled(khui_dialogs[i].hwnd); + EnableWindow(khui_dialogs[i].hwnd, FALSE); + } + } + + khui_main_window_active = khm_is_main_window_active(); + EnableWindow(khm_hwnd_main, FALSE); + + khui_modal_dialog = hwnd; +} + +/* should only be called from the UI thread */ +void khm_leave_modal(void) { + int i; + + for(i=0; i < n_khui_dialogs; i++) { + if(khui_dialogs[i].hwnd != khui_modal_dialog) { + EnableWindow(khui_dialogs[i].hwnd, khui_dialogs[i].active); + } + } + + EnableWindow(khm_hwnd_main, TRUE); + if (khui_main_window_active) + SetForegroundWindow(khm_hwnd_main); + + khui_modal_dialog = NULL; +} + +/* should only be called from the UI thread */ +void khm_del_dialog(HWND dlg) { + int i; + for(i=0;i < n_khui_dialogs; i++) { + if(khui_dialogs[i].hwnd == dlg) + break; + } + + if(i < n_khui_dialogs) + n_khui_dialogs--; + else + return; + + for(;i < n_khui_dialogs; i++) { + khui_dialogs[i] = khui_dialogs[i+1]; + } +} + +BOOL khm_check_dlg_message(LPMSG pmsg) { + int i; + BOOL found = FALSE; + for(i=0;i<n_khui_dialogs;i++) { + if(IsDialogMessage(khui_dialogs[i].hwnd, pmsg)) { + found = TRUE; + break; + } + } + + return found; +} + +BOOL khm_is_dialog_active(void) { + HWND hwnd; + int i; + + hwnd = GetForegroundWindow(); + + for (i=0; i<n_khui_dialogs; i++) { + if (khui_dialogs[i].hwnd == hwnd) + return TRUE; + } + + return FALSE; +} + +/* We support at most 256 property sheets simultaneously. 256 + property sheets should be enough for everybody. */ +#define MAX_UI_PROPSHEETS 256 + +khui_property_sheet *_ui_propsheets[MAX_UI_PROPSHEETS]; +int _n_ui_propsheets = 0; + +void khm_add_property_sheet(khui_property_sheet * s) { + if(_n_ui_propsheets < MAX_UI_PROPSHEETS) + _ui_propsheets[_n_ui_propsheets++] = s; +#ifdef DEBUG + else + assert(FALSE); +#endif +} + +void khm_del_property_sheet(khui_property_sheet * s) { + int i; + + for(i=0;i < _n_ui_propsheets; i++) { + if(_ui_propsheets[i] == s) + break; + } + + if(i < _n_ui_propsheets) + _n_ui_propsheets--; + else + return; + + for(;i < _n_ui_propsheets; i++) { + _ui_propsheets[i] = _ui_propsheets[i+1]; + } +} + +BOOL khm_check_ps_message(LPMSG pmsg) { + int i; + khui_property_sheet * ps; + for(i=0;i<_n_ui_propsheets;i++) { + if(khui_ps_check_message(_ui_propsheets[i], pmsg)) { + if(_ui_propsheets[i]->status == KHUI_PS_STATUS_DONE) { + ps = _ui_propsheets[i]; + + ps->status = KHUI_PS_STATUS_DESTROY; + kmq_post_message(KMSG_CRED, KMSG_CRED_PP_END, 0, (void *) ps); + + return TRUE; + } + return TRUE; + } + } + + return FALSE; +} + +WPARAM khm_message_loop(void) { + int r; + MSG msg; + HACCEL ha_menu; + + ha_menu = khui_create_global_accel_table(); + while(r = GetMessage(&msg, NULL, 0,0)) { + if(r == -1) + break; + if(!khm_check_dlg_message(&msg) && + !khm_check_ps_message(&msg) && + !TranslateAccelerator(khm_hwnd_main, ha_menu, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + DestroyAcceleratorTable(ha_menu); + return msg.wParam; +} + +void KHMAPI +khm_module_load_ctx_handler(enum kherr_ctx_event evt, + kherr_context * c) { + kherr_event * e; + khui_alert * a; + + for(e = kherr_get_first_event(c); + e; + e = kherr_get_next_event(e)) { + + kherr_evaluate_event(e); + + if ((e->severity == KHERR_ERROR || + e->severity == KHERR_WARNING) && + e->short_desc && + e->long_desc) { + + khui_alert_create_empty(&a); + + khui_alert_set_severity(a, e->severity); + khui_alert_set_title(a, e->short_desc); + khui_alert_set_message(a, e->long_desc); + if (e->suggestion) + khui_alert_set_suggestion(a, e->suggestion); + + khui_alert_queue(a); + + khui_alert_release(a); + } + } + + kherr_remove_ctx_handler(khm_module_load_ctx_handler, + c->serial); +} + +static wchar_t helpfile[MAX_PATH] = L""; + +HWND khm_html_help(HWND hwnd, wchar_t * suffix, + UINT command, DWORD_PTR data) { + + wchar_t gpath[MAX_PATH + MAX_PATH]; + + if (!*helpfile) { + DWORD dw; + wchar_t ppath[MAX_PATH]; + + dw = GetModuleFileName(NULL, ppath, ARRAYLENGTH(ppath)); + + if (dw == 0) { + StringCbCopy(helpfile, sizeof(helpfile), NIDM_HELPFILE); + } else { + PathRemoveFileSpec(ppath); + PathAppend(ppath, NIDM_HELPFILE); + StringCbCopy(helpfile, sizeof(helpfile), ppath); + } + } + + StringCbCopy(gpath, sizeof(gpath), helpfile); + + if (suffix) + StringCbCat(gpath, sizeof(gpath), suffix); + + return HtmlHelp(hwnd, gpath, command, data); +} + +void khm_load_default_modules(void) { + kherr_context * c; + + _begin_task(KHERR_CF_TRANSITIVE); + + kmm_load_default_modules(); + + c = kherr_peek_context(); + kherr_add_ctx_handler(khm_module_load_ctx_handler, + KHERR_CTX_END, + c->serial); + kherr_release_context(c); + + _end_task(); +} + +int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + int rv = 0; + HANDLE h_appmutex; + BOOL slave = FALSE; + + khm_hInstance = hInstance; + khm_nCmdShow = nCmdShow; + + khm_parse_commandline(); + + if (khm_startup.error_exit) + return 0; + + h_appmutex = CreateMutex(NULL, FALSE, L"Local\\NetIDMgr_GlobalAppMutex"); + if (h_appmutex == NULL) + return 5; + if (GetLastError() == ERROR_ALREADY_EXISTS) + slave = TRUE; + + khc_load_schema(NULL, schema_uiconfig); + + if(!slave) { + + /* set this so that we don't accidently invoke an API that + inadvertently puts up the new creds dialog at an + inopportune moment, like, say, during the new creds dialog + is open. This only affects this process, and any child + processes started by plugins. */ + SetEnvironmentVariable(L"KERBEROSLOGIN_NEVER_PROMPT", L"1"); + + khm_version_init(); + + khm_commctl_version = khm_get_commctl_version(NULL); + + /* we only open a main window if this is the only instance + of the application that is running. */ + kmq_init(); + kmm_init(); + khm_init_gui(); + + kmq_set_completion_handler(KMSG_CRED, kmsg_cred_completion); + + /* load the standard plugins */ + khm_load_default_modules(); + + khm_register_window_classes(); + + khm_init_request_daemon(); + + khm_create_main_window(); + + if (!khm_startup.no_main_window) + khm_show_main_window(); + + rv = (int) khm_message_loop(); + + kmq_set_completion_handler(KMSG_CRED, NULL); + + khm_exit_request_daemon(); + + khm_exit_gui(); + khm_unregister_window_classes(); + kmm_exit(); + kmq_exit(); + + CloseHandle(h_appmutex); + } else { + HWND hwnd = NULL; + int retries = 5; + HANDLE hmap; + wchar_t mapname[256]; + DWORD tid; + void * xfer; + + CloseHandle(h_appmutex); + + while (hwnd == NULL && retries) { + hwnd = FindWindowEx(NULL, NULL, KHUI_MAIN_WINDOW_CLASS, NULL); + + if (hwnd) + break; + + retries--; + Sleep(1000); + } + + if (!hwnd) + return 2; + + StringCbPrintf(mapname, sizeof(mapname), + COMMANDLINE_MAP_FMT, + (tid = GetCurrentThreadId())); + + hmap = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, + 4096, + mapname); + + if (hmap == NULL) + return 3; + + xfer = MapViewOfFile(hmap, + FILE_MAP_WRITE, + 0, 0, + sizeof(khm_startup)); + + if (xfer) { + memcpy(xfer, &khm_startup, sizeof(khm_startup)); + + SendMessage(hwnd, WM_KHUI_ASSIGN_COMMANDLINE, + 0, (LPARAM) tid); + } + + if (xfer) + UnmapViewOfFile(xfer); + + if (hmap) + CloseHandle(hmap); + } + +#if 0 + /* writes a report of memory leaks to the specified file. Should + only be enabled on development versions. */ + PDUMP("memleak.txt"); +#endif + + return rv; +} diff --git a/mechglue/src/windows/identity/ui/mainmenu.c b/mechglue/src/windows/identity/ui/mainmenu.c new file mode 100644 index 000000000..10270f2a0 --- /dev/null +++ b/mechglue/src/windows/identity/ui/mainmenu.c @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +HWND khui_main_menu_toolbar; +int mm_last_hot_item = -1; +int mm_next_hot_item = -1; +BOOL mm_hot_track = FALSE; + +#define MAX_ILIST 256 +/* not the same as MENU_SIZE_ICON_* */ +#define ILIST_ICON_X 16 +#define ILIST_ICON_Y 15 + +khui_ilist * il_icon; +int il_icon_id[MAX_ILIST]; + +void khui_init_menu(void) { + int i; + + il_icon = khui_create_ilist(ILIST_ICON_X, + ILIST_ICON_Y, + MAX_ILIST, 5, 0); + for(i=0;i<MAX_ILIST;i++) + il_icon_id[i] = -1; +} + +void khui_exit_menu(void) { + khui_delete_ilist(il_icon); +} + +int khui_get_icon_index(int id) { + int i; + HBITMAP hbm; + + for(i=0;i<MAX_ILIST;i++) + if(il_icon_id[i] == id) { + return i; + } + + hbm = LoadImage(khm_hInstance, + MAKEINTRESOURCE(id), + IMAGE_BITMAP, + ILIST_ICON_X, ILIST_ICON_Y, + LR_DEFAULTCOLOR); + i = khui_ilist_add_masked(il_icon, hbm, KHUI_TOOLBAR_BGCOLOR); + il_icon_id[i] = id; + DeleteObject(hbm); + + return i; +} + +void add_action_to_menu(HMENU hm, khui_action * act, + int idx, int flags) { + MENUITEMINFO mii; + wchar_t buf[MAX_RES_STRING] = L""; + wchar_t accel[MAX_RES_STRING] = L""; + + mii.cbSize = sizeof(mii); + mii.fMask = 0; + + if(act == NULL) { + mii.fMask = MIIM_FTYPE; + mii.fType = MFT_SEPARATOR; + } else { + khui_menu_def * def; + + LoadString(khm_hInstance, + act->is_caption, + buf, ARRAYLENGTH(buf)); + + if(khui_get_cmd_accel_string(act->cmd, accel, + ARRAYLENGTH(accel))) { + StringCbCat(buf, sizeof(buf), L"\t"); + StringCbCat(buf, sizeof(buf), accel); + } + + mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID; + mii.fType = MFT_STRING; + + mii.dwTypeData = buf; + mii.cch = (int) wcslen(buf); + + mii.wID = act->cmd; + + if(act->state & KHUI_ACTIONSTATE_DISABLED) { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } else { + mii.fState = 0; + } + + if((act->type & KHUI_ACTIONTYPE_TOGGLE) && + (act->state & KHUI_ACTIONSTATE_CHECKED)) { + mii.fMask |= MIIM_STATE; + mii.fState |= MFS_CHECKED; + } + + if(act->ib_icon) { + mii.fMask |= MIIM_BITMAP; + mii.hbmpItem = HBMMENU_CALLBACK; + } + + def = khui_find_menu(act->cmd); + if(def) { + mii.fMask |= MIIM_SUBMENU; + mii.hSubMenu = mm_create_menu_from_def(def, FALSE); + } + + if(flags & KHUI_ACTIONREF_DEFAULT) + mii.fState |= MFS_DEFAULT; + } + + InsertMenuItem(hm,idx,TRUE,&mii); +} + +static void refresh_menu(HMENU hm, khui_menu_def * def); + +static void refresh_menu_item(HMENU hm, khui_action * act, + int idx, int flags) { + MENUITEMINFO mii; + + mii.cbSize = sizeof(mii); + mii.fMask = 0; + + if (act == NULL) + return; + else { + khui_menu_def * def; + + if(act->state & KHUI_ACTIONSTATE_DISABLED) { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } else { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_ENABLED; + } + + if(act->type & KHUI_ACTIONTYPE_TOGGLE) { + mii.fMask |= MIIM_STATE; + if (act->state & KHUI_ACTIONSTATE_CHECKED) { + mii.fState |= MFS_CHECKED; + } else { + mii.fState |= MFS_UNCHECKED; + } + } + + SetMenuItemInfo(hm, act->cmd, FALSE, &mii); + + def = khui_find_menu(act->cmd); + if(def) { + MENUITEMINFO mii2; + + mii2.cbSize = sizeof(mii2); + mii2.fMask = MIIM_SUBMENU; + + if (GetMenuItemInfo(hm, act->cmd, FALSE, &mii2)) { + refresh_menu(mii2.hSubMenu, def); + } + } + } +} + +static void refresh_menu(HMENU hm, khui_menu_def * def) { + khui_action_ref * act; + int i; + + act = def->items; + i = 0; + while ((def->n_items == -1 && act->action != KHUI_MENU_END) || + (def->n_items >= 0 && i < (int) def->n_items)) { + refresh_menu_item(hm, khui_find_action(act->action), i, act->flags); + act++; i++; + } +} + +static HMENU mm_create_menu_from_def(khui_menu_def * def, BOOL main) { + HMENU hm; + khui_action_ref * act; + int i; + + if (main) + hm = CreateMenu(); + else + hm = CreatePopupMenu(); + + act = def->items; + i = 0; + while((def->n_items == -1 && act->action != KHUI_MENU_END) || + (def->n_items >= 0 && i < (int) def->n_items)) { + add_action_to_menu(hm,khui_find_action(act->action),i,act->flags); + act++; i++; + } + + return hm; +} + +void mm_begin_hot_track(void); +void mm_end_hot_track(void); + +static void mm_show_panel_def(khui_menu_def * def, LONG x, LONG y) +{ + HMENU hm; + + hm = mm_create_menu_from_def(def, FALSE); + + mm_hot_track = (mm_last_hot_item >= 0); + + if (mm_hot_track) + mm_begin_hot_track(); + + TrackPopupMenuEx(hm, + TPM_LEFTALIGN | TPM_TOPALIGN | + TPM_VERPOSANIMATION, + x, y, khm_hwnd_main, NULL); + + mm_last_hot_item = -1; + + if (mm_hot_track) + mm_end_hot_track(); + + mm_hot_track = FALSE; + + DestroyMenu(hm); +} + +void khm_menu_show_panel(int id, LONG x, LONG y) { + khui_menu_def * def; + + def = khui_find_menu(id); + if(!def) + return; + + mm_show_panel_def(def, x, y); +} + +LRESULT khm_menu_activate(int menu_id) { + khui_menu_def * mmdef; + int nmm; + + mmdef = khui_find_menu(KHUI_MENU_MAIN); + nmm = (int) khui_action_list_length(mmdef->items); + + if(menu_id == MENU_ACTIVATE_DEFAULT) { + if (mm_last_hot_item != -1) + menu_id = mm_last_hot_item; + else + menu_id = 0; + } else if(menu_id == MENU_ACTIVATE_LEFT) { + menu_id = (mm_last_hot_item > 0)? + mm_last_hot_item - 1: + ((mm_last_hot_item == 0)? nmm - 1: 0); + } else if(menu_id == MENU_ACTIVATE_RIGHT) { + menu_id = (mm_last_hot_item >=0 && mm_last_hot_item < nmm - 1)? + mm_last_hot_item + 1: + 0; + } else if(menu_id == MENU_ACTIVATE_NONE) { + menu_id = -1; + } + + SendMessage(khui_main_menu_toolbar, + TB_SETHOTITEM, + menu_id, + 0); + + khm_menu_track_current(); + + return TRUE; +} + +LRESULT khm_menu_measure_item(WPARAM wParam, LPARAM lParam) { + /* all menu icons have a fixed size */ + LPMEASUREITEMSTRUCT lpm = (LPMEASUREITEMSTRUCT) lParam; + lpm->itemWidth = MENU_SIZE_ICON_X; + lpm->itemHeight = MENU_SIZE_ICON_Y; + return TRUE; +} + +LRESULT khm_menu_draw_item(WPARAM wParam, LPARAM lParam) { + LPDRAWITEMSTRUCT lpd; + khui_action * act; + int resid; + int iidx; + UINT style; + + lpd = (LPDRAWITEMSTRUCT) lParam; + act = khui_find_action(lpd->itemID); + + resid = 0; + if((lpd->itemState & ODS_DISABLED) || (lpd->itemState & ODS_GRAYED)) { + resid = act->ib_icon_dis; + } + if(!resid) + resid = act->ib_icon; + + if(!resid) /* nothing to draw */ + return TRUE; + + + iidx = khui_get_icon_index(resid); + if(iidx == -1) + return TRUE; + + + style = ILD_TRANSPARENT; + if(lpd->itemState & ODS_HOTLIGHT || lpd->itemState & ODS_SELECTED) { + style |= ILD_SELECTED; + } + + khui_ilist_draw(il_icon, + iidx, + lpd->hDC, + lpd->rcItem.left, lpd->rcItem.top, style); + + return TRUE; +} + +void khm_track_menu(int menu) { + TBBUTTON bi; + RECT r; + RECT wr; + + if (menu != -1) + mm_last_hot_item = menu; + + if (mm_last_hot_item != -1) { + SendMessage(khui_main_menu_toolbar, + TB_GETBUTTON, + mm_last_hot_item, + (LPARAM) &bi); + + SendMessage(khui_main_menu_toolbar, + TB_GETITEMRECT, + mm_last_hot_item, + (LPARAM) &r); + + GetWindowRect(khui_main_menu_toolbar, &wr); + + khm_menu_show_panel(bi.idCommand, wr.left + r.left, wr.top + r.bottom); + + r.left = 0; + + if (mm_next_hot_item != -1) { + mm_last_hot_item = mm_next_hot_item; + mm_next_hot_item = -1; + + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_PACTION_MENU,0), + MAKELPARAM(mm_last_hot_item,1)); + } + } +} + +void khm_menu_track_current(void) { + khm_track_menu(-1); +} + +LRESULT khm_menu_handle_select(WPARAM wParam, LPARAM lParam) { + if((HIWORD(wParam) == 0xffff && lParam == 0) || + (HIWORD(wParam) & MF_POPUP)) { + /* the menu was closed */ + khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, NULL); + } else { + khui_action * act; + int id; + wchar_t buf[MAX_RES_STRING] = L""; + + id = LOWORD(wParam); + act = khui_find_action(id); + if(act == NULL || act->is_tooltip == 0) + khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, NULL); + else { + LoadString(khm_hInstance, + act->is_tooltip, + buf, ARRAYLENGTH(buf)); + khm_statusbar_set_part(KHUI_SBPART_INFO, NULL, buf); + } + } + return 0; +} + +HHOOK mm_hevt_hook = NULL; +HWND mm_hwnd_menu_panel = NULL; + +LRESULT CALLBACK mm_event_filter(int code, + WPARAM wParam, + LPARAM lParam) { + MSG * m; + RECT r; + int x,y; + + if (code == MSGF_MENU) { + /* do stuff */ + m = (MSG *) lParam; + GetWindowRect(khui_main_menu_toolbar, &r); + + if (m->hwnd != khm_hwnd_main) + mm_hwnd_menu_panel = m->hwnd; + + switch(m->message) { + case WM_MOUSEMOVE: + + x = GET_X_LPARAM(m->lParam); + y = GET_Y_LPARAM(m->lParam); + x -= r.left; + y -= r.top; + + SendMessage(khui_main_menu_toolbar, + m->message, + m->wParam, + MAKELPARAM(x,y)); + break; + } + } + + return CallNextHookEx(mm_hevt_hook, code, wParam, lParam); +} + + +void mm_begin_hot_track(void) { + + if (mm_hevt_hook) + UnhookWindowsHookEx(mm_hevt_hook); + + mm_hevt_hook = SetWindowsHookEx(WH_MSGFILTER, + mm_event_filter, + NULL, + GetCurrentThreadId()); +} + +void mm_end_hot_track(void) { + if (mm_hevt_hook) + UnhookWindowsHookEx(mm_hevt_hook); + + mm_hevt_hook = NULL; + mm_hwnd_menu_panel = NULL; +} + +void mm_cancel_menu(void) { + if (mm_hwnd_menu_panel) + SendMessage(mm_hwnd_menu_panel, WM_CANCELMODE, 0, 0); +} + +LRESULT khm_menu_notify_main(LPNMHDR notice) { + LPNMTOOLBAR nmt; + LRESULT ret = FALSE; + RECT r; + khui_menu_def * mmdef; + khui_action_ref * mm; + int nmm; + + mmdef = khui_find_menu(KHUI_MENU_MAIN); + mm = mmdef->items; + nmm = (int) khui_action_list_length(mm); + + GetWindowRect(khui_main_menu_toolbar, &r); + + nmt = (LPNMTOOLBAR) notice; + switch(notice->code) { + case TBN_DROPDOWN: + khm_track_menu(-1); + /* + khm_menu_show_panel(nmt->iItem, + r.left + nmt->rcButton.left, + r.top + nmt->rcButton.bottom); + */ + ret = TBDDRET_DEFAULT; + break; + + case TBN_HOTITEMCHANGE: + { + LPNMTBHOTITEM nmhi; + int new_item = -1; + + nmhi = (LPNMTBHOTITEM) notice; + + if(nmhi->dwFlags & HICF_LEAVING) + new_item = -1; + else { + int i; + for(i=0; i < nmm; i++) { + if(mm[i].action == nmhi->idNew) { + new_item = i; + break; + } + } + } + + if (mm_hot_track && + new_item != mm_last_hot_item && + new_item != -1 && + mm_last_hot_item != -1) { + + EndMenu(); + mm_next_hot_item = new_item; + + } + + ret = 0; + + if (!mm_hot_track || new_item != -1) + mm_last_hot_item = new_item; + + } break; + + default: + /* hmm. what to do */ + ret = FALSE; + } + return ret; +} + +HMENU khui_hmenu_main = NULL; + +void khm_menu_refresh_items(void) { + khui_menu_def * def; + + if (!khui_hmenu_main) + return; + + def = khui_find_menu(KHUI_MENU_MAIN); + + refresh_menu(khui_hmenu_main, def); + + DrawMenuBar(khm_hwnd_main); +} + +void khm_menu_create_main(HWND parent) { + HMENU hmenu; + khui_menu_def * def; + + def = khui_find_menu(KHUI_MENU_MAIN); + + hmenu = mm_create_menu_from_def(def, TRUE); + + SetMenu(parent, hmenu); + + khui_hmenu_main = hmenu; + + return; + +#ifdef USE_EXPLORER_STYLE_MENU_BAR + HWND hwtb; + REBARBANDINFO rbi; + SIZE sz; + int i; + khui_menu_def * mmdef; + khui_action_ref * mm; + int nmm; + + mmdef = khui_find_menu(KHUI_MENU_MAIN); + mm = mmdef->items; + nmm = (int) khui_action_list_length(mm); + + hwtb = CreateWindowEx(0 +#if (_WIN32_IE >= 0x0501) + | TBSTYLE_EX_MIXEDBUTTONS +#endif + , + TOOLBARCLASSNAME, + (LPWSTR) NULL, + WS_CHILD | + CCS_ADJUSTABLE | + TBSTYLE_FLAT | + TBSTYLE_AUTOSIZE | + TBSTYLE_LIST | + CCS_NORESIZE | + CCS_NOPARENTALIGN | + CCS_NODIVIDER, + 0, 0, 0, 0, rebar, + (HMENU) NULL, khm_hInstance, + NULL); + + if(!hwtb) { +#ifdef DEBUG + assert(FALSE); +#else + return; +#endif + } + + khui_main_menu_toolbar = hwtb; + + SendMessage(hwtb, + TB_BUTTONSTRUCTSIZE, + (WPARAM) sizeof(TBBUTTON), + 0); + + for(i=0; i<nmm; i++) { + khui_add_action_to_toolbar(hwtb, + khui_find_action(mm[i].action), + KHUI_TOOLBAR_ADD_TEXT | + KHUI_TOOLBAR_ADD_DROPDOWN | + KHUI_TOOLBAR_VARSIZE, + NULL); + } + + SendMessage(hwtb, + TB_AUTOSIZE, + 0,0); + + SendMessage(hwtb, + TB_GETMAXSIZE, + 0, + (LPARAM) &sz); + + ZeroMemory(&rbi, sizeof(rbi)); + + rbi.cbSize = sizeof(rbi); + + rbi.fMask = + RBBIM_ID | + RBBIM_STYLE | + RBBIM_CHILD | + RBBIM_CHILDSIZE | + RBBIM_SIZE | + RBBIM_IDEALSIZE; + + rbi.fStyle = + RBBS_USECHEVRON; + + rbi.hwndChild = hwtb; + rbi.wID = KHUI_MENU_MAIN; + rbi.cx = sz.cx; + rbi.cxMinChild = rbi.cx; + rbi.cxIdeal = rbi.cx; + rbi.cyMinChild = sz.cy; + rbi.cyChild = rbi.cyMinChild; + rbi.cyIntegral = rbi.cyMinChild; + rbi.cyMaxChild = rbi.cyMinChild; + + SendMessage(rebar, + RB_INSERTBAND, + 0, + (LPARAM) &rbi); +#endif +} diff --git a/mechglue/src/windows/identity/ui/mainmenu.h b/mechglue/src/windows/identity/ui/mainmenu.h new file mode 100644 index 000000000..7f718c26c --- /dev/null +++ b/mechglue/src/windows/identity/ui/mainmenu.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_MAINMENU_H +#define __KHIMAIRA_MAINMENU_H + +extern HWND khui_main_menu_toolbar; + +#define MENU_ACTIVATE_DEFAULT -1 +#define MENU_ACTIVATE_LEFT -2 +#define MENU_ACTIVATE_RIGHT -3 +#define MENU_ACTIVATE_NONE -4 + +extern int mm_last_hot_item; +extern BOOL mm_hot_track; + +void khm_menu_create_main(HWND rebar); +LRESULT khm_menu_handle_select(WPARAM wParam, LPARAM lParam); +LRESULT khm_menu_notify_main(LPNMHDR notice); +LRESULT khm_menu_activate(int menu_id); +void khm_menu_show_panel(int id, LONG x, LONG y); +void khm_menu_track_current(void); +LRESULT khm_menu_measure_item(WPARAM wParam, LPARAM lparam); +LRESULT khm_menu_draw_item(WPARAM wParam, LPARAM lparam); +void khm_menu_refresh_items(void); + +static HMENU mm_create_menu_from_def(khui_menu_def * def, BOOL main); +static void mm_show_panel_def(khui_menu_def * def, LONG x, LONG y); + +void khui_init_menu(void); +void khui_exit_menu(void); + +#define MENU_SIZE_ICON_X 16 +#define MENU_SIZE_ICON_Y 16 + +#endif diff --git a/mechglue/src/windows/identity/ui/mainwnd.c b/mechglue/src/windows/identity/ui/mainwnd.c new file mode 100644 index 000000000..1e00c6d2a --- /dev/null +++ b/mechglue/src/windows/identity/ui/mainwnd.c @@ -0,0 +1,727 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +ATOM khm_main_window_class; +ATOM khm_null_window_class; +HWND khm_hwnd_null; +HWND khm_hwnd_main; +HWND khm_hwnd_rebar; +HWND khm_hwnd_main_cred; + +#define MW_RESIZE_TIMER 1 +#define MW_RESIZE_TIMEOUT 2000 +#define MW_REFRESH_TIMER 2 +#define MW_REFRESH_TIMEOUT 600 + +void +khm_set_dialog_result(HWND hwnd, LRESULT lr) { +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWL_MSGRESULT, lr); +#pragma warning(pop) +} + +static void +mw_restart_refresh_timer(HWND hwnd) { + khm_handle csp_cw; + khm_int32 timeout; + + KillTimer(hwnd, MW_REFRESH_TIMER); + if (KHM_SUCCEEDED(khc_open_space(NULL, + L"CredWindow", + KHM_PERM_READ, + &csp_cw))) { + if (KHM_FAILED(khc_read_int32(csp_cw, + L"RefreshTimeout", + &timeout))) + timeout = MW_REFRESH_TIMEOUT; + khc_close_space(csp_cw); + } else + timeout = MW_REFRESH_TIMEOUT; + + timeout *= 1000; /* convert to milliseconds */ + + SetTimer(hwnd, MW_REFRESH_TIMER, timeout, NULL); +} + +LRESULT CALLBACK khm_main_wnd_proc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) +{ + LPNMHDR lpnm; + + switch(uMsg) { + case WM_CREATE: + khm_create_main_window_controls(hwnd); + kmq_subscribe_hwnd(KMSG_CRED, hwnd); + kmq_subscribe_hwnd(KMSG_ACT, hwnd); + kmq_subscribe_hwnd(KMSG_KMM, hwnd); + mw_restart_refresh_timer(hwnd); + + if (!kmm_load_pending()) + kmq_post_message(KMSG_ACT, KMSG_ACT_BEGIN_CMDLINE, 0, 0); + break; + + case WM_DESTROY: + kmq_unsubscribe_hwnd(KMSG_ACT, hwnd); + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd); + HtmlHelp(NULL, NULL, HH_CLOSE_ALL, 0); + PostQuitMessage(0); + break; + + case WM_NOTIFY: + lpnm = (LPNMHDR) lParam; + if(lpnm->hwndFrom == khui_main_menu_toolbar) { + return khm_menu_notify_main(lpnm); + } else if(lpnm->hwndFrom == khui_hwnd_standard_toolbar) { + return khm_toolbar_notify(lpnm); + } else if(lpnm->hwndFrom == khm_hwnd_rebar) { + return khm_rebar_notify(lpnm); + } else if(lpnm->hwndFrom == khm_hwnd_statusbar) { + return khm_statusbar_notify(lpnm); + } + break; + + case WM_HELP: + khm_html_help(khm_hwnd_main, NULL, HH_HELP_CONTEXT, IDH_WELCOME); + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + /* general actions */ + case KHUI_ACTION_VIEW_REFRESH: + khm_cred_refresh(); + InvalidateRect(khm_hwnd_main_cred, NULL, FALSE); + return 0; + + case KHUI_ACTION_PASSWD_ID: + khm_cred_change_password(NULL); + return 0; + + case KHUI_ACTION_NEW_CRED: + khm_cred_obtain_new_creds(NULL); + return 0; + + case KHUI_ACTION_RENEW_CRED: + khm_cred_renew_creds(); + return 0; + + case KHUI_ACTION_DESTROY_CRED: + khm_cred_destroy_creds(); + return 0; + + case KHUI_ACTION_SET_DEF_ID: + khm_cred_set_default(); + return 0; + + case KHUI_ACTION_EXIT: + DestroyWindow(hwnd); + break; + + case KHUI_ACTION_OPEN_APP: + khm_show_main_window(); + break; + + case KHUI_ACTION_CLOSE_APP: + khm_hide_main_window(); + break; + + case KHUI_ACTION_OPT_KHIM: + khm_show_config_pane(NULL); + break; + + case KHUI_ACTION_OPT_IDENTS: { + khui_config_node node; + + khui_cfg_open(NULL, L"KhmIdentities", &node); + khm_show_config_pane(node); + } + break; + + case KHUI_ACTION_OPT_NOTIF: { + khui_config_node node; + + khui_cfg_open(NULL, L"KhmNotifications", &node); + khm_show_config_pane(node); + } + break; + + case KHUI_ACTION_OPT_PLUGINS: { + khui_config_node node; + + khui_cfg_open(NULL, L"KhmPlugins", &node); + khm_show_config_pane(node); + } + break; + + case KHUI_ACTION_HELP_CTX: + khm_html_help(khm_hwnd_main, NULL, HH_HELP_CONTEXT, IDH_WELCOME); + break; + + case KHUI_ACTION_HELP_CONTENTS: + khm_html_help(khm_hwnd_main, NULL, HH_DISPLAY_TOC, 0); + break; + + case KHUI_ACTION_HELP_INDEX: + khm_html_help(khm_hwnd_main, NULL, HH_DISPLAY_INDEX, (DWORD_PTR) L""); + break; + + case KHUI_ACTION_HELP_ABOUT: + khm_create_about_window(); + break; + + case KHUI_ACTION_IMPORT: + khm_cred_import(); + break; + + case KHUI_ACTION_PROPERTIES: + /* properties are not handled by the main window. + Just bounce it to credwnd. However, use SendMessage + instead of PostMessage so we don't lose context */ + return SendMessage(khm_hwnd_main_cred, uMsg, + wParam, lParam); + + /* menu commands */ + case KHUI_PACTION_MENU: + if(HIWORD(lParam) == 1) + mm_last_hot_item = LOWORD(lParam); + return khm_menu_activate(MENU_ACTIVATE_DEFAULT); + + /* generic, retargetting */ + case KHUI_PACTION_UP: + case KHUI_PACTION_UP_TOGGLE: + case KHUI_PACTION_UP_EXTEND: + case KHUI_PACTION_DOWN: + case KHUI_PACTION_DOWN_TOGGLE: + case KHUI_PACTION_DOWN_EXTEND: + case KHUI_PACTION_LEFT: + case KHUI_PACTION_RIGHT: + case KHUI_PACTION_ESC: + case KHUI_PACTION_ENTER: + /* menu tracking */ + if(mm_last_hot_item != -1) { + switch(LOWORD(wParam)) { + case KHUI_PACTION_LEFT: + khm_menu_activate(MENU_ACTIVATE_LEFT); + break; + + case KHUI_PACTION_RIGHT: + khm_menu_activate(MENU_ACTIVATE_RIGHT); + break; + + case KHUI_PACTION_ESC: + case KHUI_PACTION_ENTER: + khm_menu_activate(MENU_ACTIVATE_NONE); + break; + + case KHUI_PACTION_DOWN: + khm_menu_track_current(); + break; + } + return 0; + } + + /*FALLTHROUGH*/ + + case KHUI_PACTION_DELETE: + + case KHUI_PACTION_SELALL: + case KHUI_ACTION_LAYOUT_ID: + case KHUI_ACTION_LAYOUT_TYPE: + case KHUI_ACTION_LAYOUT_LOC: + /* otherwise fallthrough and bounce to the creds window */ + return SendMessage(khm_hwnd_main_cred, uMsg, + wParam, lParam); + } + break; /* WM_COMMAND */ + + case WM_SYSCOMMAND: + switch(wParam & 0xfff0) { + case SC_MINIMIZE: + khm_hide_main_window(); + return 0; + + case SC_CLOSE: + { + khm_handle csp_cw; + BOOL keep_running = FALSE; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + KHM_PERM_READ, &csp_cw))) { + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_cw, L"KeepRunning", + &t))) + keep_running = t; +#ifdef DEBUG + else + assert(FALSE); +#endif + + khc_close_space(csp_cw); + } +#ifdef DEBUG + else + assert(FALSE); +#endif + + if (keep_running) + khm_hide_main_window(); + else + DestroyWindow(hwnd); + } + return 0; + } + break; + + case WM_MEASUREITEM: + /* sent to measure the bitmaps associated with a menu item */ + if(!wParam) /* sent by menu */ + return khm_menu_measure_item(wParam, lParam); + break; + + case WM_DRAWITEM: + /* sent to draw a menu item */ + if(!wParam) + return khm_menu_draw_item(wParam, lParam); + break; + + case WM_ERASEBKGND: + /* Don't erase the background. The whole client area is + covered with children. It doesn't need to be erased */ + return TRUE; + break; + + case WM_SIZE: + if(hwnd == khm_hwnd_main && + (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)) { + int cwidth, cheight; + RECT r_rebar, r_status; + + cwidth = LOWORD(lParam); + cheight = HIWORD(lParam); + + /* resize the rebar control */ + SendMessage(khm_hwnd_rebar, WM_SIZE, 0, 0); + + khm_update_statusbar(hwnd); + + GetWindowRect(khm_hwnd_rebar, &r_rebar); + GetWindowRect(khm_hwnd_statusbar, &r_status); + + /* the cred window fills the area between the rebar + and the status bar */ + MoveWindow(khm_hwnd_main_cred, 0, + r_rebar.bottom - r_rebar.top, + r_status.right - r_status.left, + r_status.top - r_rebar.bottom, TRUE); + + SetTimer(hwnd, + MW_RESIZE_TIMER, + MW_RESIZE_TIMEOUT, + NULL); + return 0; + } + break; + + case WM_MOVE: + { + SetTimer(hwnd, + MW_RESIZE_TIMER, + MW_RESIZE_TIMEOUT, + NULL); + } + break; + + case WM_TIMER: + if (wParam == MW_RESIZE_TIMER) { + RECT r; + khm_handle csp_cw; + khm_handle csp_mw; + + KillTimer(hwnd, wParam); + + GetWindowRect(hwnd, &r); + + if (KHM_SUCCEEDED(khc_open_space(NULL, + L"CredWindow", + KHM_PERM_WRITE, + &csp_cw))) { + if (KHM_SUCCEEDED(khc_open_space(csp_cw, + L"Windows\\Main", + KHM_PERM_WRITE, + &csp_mw))) { + khc_write_int32(csp_mw, L"XPos", r.left); + khc_write_int32(csp_mw, L"YPos", r.top); + khc_write_int32(csp_mw, L"Width", + r.right - r.left); + khc_write_int32(csp_mw, L"Height", + r.bottom - r.top); + + khc_close_space(csp_mw); + } + khc_close_space(csp_cw); + } + } else if (wParam == MW_REFRESH_TIMER) { + kmq_post_message(KMSG_CRED, KMSG_CRED_REFRESH, 0, 0); + } + break; + + case WM_MENUSELECT: + return khm_menu_handle_select(wParam, lParam); + break; + + case KMQ_WM_DISPATCH: + { + kmq_message * m; + khm_int32 rv = KHM_ERROR_SUCCESS; + + kmq_wm_begin(lParam, &m); + if (m->type == KMSG_ACT && + m->subtype == KMSG_ACT_REFRESH) { + khm_menu_refresh_items(); + khm_update_standard_toolbar(); + } else if (m->type == KMSG_ACT && + m->subtype == KMSG_ACT_BEGIN_CMDLINE) { + khm_cred_begin_commandline(); + } else if (m->type == KMSG_ACT && + m->subtype == KMSG_ACT_CONTINUE_CMDLINE) { + khm_cred_process_commandline(); + } else if (m->type == KMSG_CRED && + m->subtype == KMSG_CRED_REFRESH) { + mw_restart_refresh_timer(hwnd); + } else if (m->type == KMSG_CRED && + m->subtype == KMSG_CRED_ADDR_CHANGE) { + khm_cred_addr_change(); + } else if (m->type == KMSG_KMM && + m->subtype == KMSG_KMM_I_DONE) { + kmq_post_message(KMSG_ACT, KMSG_ACT_BEGIN_CMDLINE, 0, 0); + } + return kmq_wm_end(m, rv); + } + break; + + case WM_KHUI_ASSIGN_COMMANDLINE: + { + HANDLE hmap; + void * xfer; + wchar_t mapname[256]; + + StringCbPrintf(mapname, sizeof(mapname), + COMMANDLINE_MAP_FMT, (DWORD) lParam); + + hmap = OpenFileMapping(FILE_MAP_READ, FALSE, mapname); + + if (hmap == NULL) + return 1; + + xfer = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, + sizeof(khm_startup)); + + if (xfer) { + memcpy(&khm_startup, xfer, sizeof(khm_startup)); + + UnmapViewOfFile(xfer); + } + + CloseHandle(hmap); + + if(InSendMessage()) + ReplyMessage(0); + + khm_startup.exit = FALSE; + + khm_startup.seen = FALSE; + khm_startup.processing = FALSE; + + khm_cred_begin_commandline(); + } + break; + } + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + +LRESULT CALLBACK khm_null_wnd_proc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) { + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +LRESULT khm_rebar_notify(LPNMHDR lpnm) { + switch(lpnm->code) { +#if (_WIN32_WINNT >= 0x0501) + case RBN_AUTOBREAK: + { + LPNMREBARAUTOBREAK lpra = (LPNMREBARAUTOBREAK) lpnm; + lpra->fAutoBreak = TRUE; + } + break; +#endif + case RBN_BEGINDRAG: + { + LPNMREBAR lprb = (LPNMREBAR) lpnm; + if ((lprb->dwMask & RBNM_ID) && + lprb->wID == 0) + return 1; + else + return 0; + } + break; + + case NM_CUSTOMDRAW: + return CDRF_DODEFAULT; + break; + } + + return 1; +} + +void khm_create_main_window_controls(HWND hwnd_main) { + REBARINFO rbi; + HWND hwRebar; + + khm_menu_create_main(hwnd_main); + + hwRebar = + CreateWindowEx(WS_EX_TOOLWINDOW, + REBARCLASSNAME, + L"Rebar", + WS_CHILD | + WS_VISIBLE| + WS_CLIPSIBLINGS | + WS_CLIPCHILDREN | + CCS_NODIVIDER | + RBS_VARHEIGHT | + RBS_FIXEDORDER, + 0,0,0,0, + hwnd_main, + NULL, + khm_hInstance, + NULL); + + if(!hwRebar) { + DWORD dwe = GetLastError(); + return; + } + + khm_hwnd_rebar = hwRebar; + + rbi.cbSize = sizeof(rbi); + rbi.fMask = 0; + rbi.himl = (HIMAGELIST) NULL; + if(!SendMessage(hwRebar, RB_SETBARINFO, 0, (LPARAM) &rbi)) + return; + + /* self attach */ + khm_create_standard_toolbar(hwRebar); + khm_create_statusbar(hwnd_main); + + /* manual attach */ + khm_hwnd_main_cred = khm_create_credwnd(hwnd_main); +} + +void khm_create_main_window(void) { + wchar_t buf[1024]; + khm_handle csp_cw = NULL; + khm_handle csp_mw = NULL; + int x,y,width,height; + + LoadString(khm_hInstance, IDS_MAIN_WINDOW_TITLE, + buf, ARRAYLENGTH(buf)); + + khm_hwnd_null = + CreateWindow(MAKEINTATOM(khm_null_window_class), + buf, + 0, /* Style */ + 0, 0, /* x, y */ + 100, 100, /* width, height */ + NULL, /* parent */ + NULL, /* menu */ + NULL, /* HINSTANCE */ + 0); /* lparam */ + + if (!khm_hwnd_null) + return; + + x = CW_USEDEFAULT; + y = CW_USEDEFAULT; + width = CW_USEDEFAULT; + height = CW_USEDEFAULT; + + if (KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow", + KHM_PERM_READ, + &csp_cw))) { + if (KHM_SUCCEEDED(khc_open_space(csp_cw, + L"Windows\\Main", + KHM_PERM_READ, + &csp_mw))) { + khm_int32 t; + + if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"XPos", &t))) + x = t; + if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"YPos", &t))) + y = t; + if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"Width", &t))) + width = t; + if (KHM_SUCCEEDED(khc_read_int32(csp_mw, L"Height", &t))) + height = t; + + khc_close_space(csp_mw); + } + khc_close_space(csp_cw); + } + + khm_hwnd_main = + CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, + MAKEINTATOM(khm_main_window_class), + buf, + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | + WS_CLIPSIBLINGS, + x, y, width, height, + khm_hwnd_null, + NULL, + NULL, + NULL); + +} + +void khm_show_main_window(void) { + + if (khm_nCmdShow == SW_RESTORE) { + HWND hw; + + hw = GetForegroundWindow(); + if (hw != khm_hwnd_main) + SetForegroundWindow(khm_hwnd_main); + } + + if (khm_nCmdShow == SW_SHOWMINIMIZED || + khm_nCmdShow == SW_SHOWMINNOACTIVE || + khm_nCmdShow == SW_MINIMIZE) { + khm_hide_main_window(); + } else { + ShowWindow(khm_hwnd_main, khm_nCmdShow); + UpdateWindow(khm_hwnd_main); + } + + khm_nCmdShow = SW_RESTORE; +} + +void khm_hide_main_window(void) { + khm_handle csp_notices = NULL; + khm_int32 show_warning = FALSE; + + if (khm_nCmdShow != SW_MINIMIZE && + KHM_SUCCEEDED(khc_open_space(NULL, L"CredWindow\\Notices", + KHM_PERM_WRITE, &csp_notices)) && + KHM_SUCCEEDED(khc_read_int32(csp_notices, L"MinimizeWarning", + &show_warning)) && + show_warning != 0) { + + khui_alert * alert; + wchar_t title[KHUI_MAXCCH_TITLE]; + wchar_t msg[KHUI_MAXCCH_MESSAGE]; + + LoadString(khm_hInstance, IDS_WARN_WM_TITLE, + title, ARRAYLENGTH(title)); + LoadString(khm_hInstance, IDS_WARN_WM_MSG, + msg, ARRAYLENGTH(msg)); + + khui_alert_create_simple(title, msg, KHERR_INFO, &alert); + khui_alert_set_flags(alert, KHUI_ALERT_FLAG_REQUEST_BALLOON, + KHUI_ALERT_FLAG_REQUEST_BALLOON); + + khui_alert_show(alert); + + khc_write_int32(csp_notices, L"MinimizeWarning", 0); + } + + if (csp_notices != NULL) + khc_close_space(csp_notices); + + ShowWindow(khm_hwnd_main, SW_HIDE); +} + +BOOL khm_is_main_window_visible(void) { + return IsWindowVisible(khm_hwnd_main); +} + +BOOL khm_is_main_window_active(void) { + if (!IsWindowVisible(khm_hwnd_main)) + return FALSE; + if (GetForegroundWindow() == khm_hwnd_main) + return TRUE; + return khm_is_dialog_active(); +} + +void khm_register_main_wnd_class(void) { + WNDCLASSEX wc; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = khm_null_wnd_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = khm_hInstance; + wc.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); + wc.hCursor = LoadCursor((HINSTANCE) NULL, MAKEINTRESOURCE(IDC_ARROW)); + wc.hIconSm = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE); + wc.lpszMenuName = NULL; + wc.lpszClassName = KHUI_NULL_WINDOW_CLASS; + + khm_null_window_class = RegisterClassEx(&wc); + + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = khm_main_wnd_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = khm_hInstance; + wc.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); + wc.hCursor = LoadCursor((HINSTANCE) NULL, MAKEINTRESOURCE(IDC_ARROW)); + wc.hIconSm = LoadImage(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE); + wc.lpszMenuName = NULL; + wc.lpszClassName = KHUI_MAIN_WINDOW_CLASS; + + khm_main_window_class = RegisterClassEx(&wc); +} + +void khm_unregister_main_wnd_class(void) { + UnregisterClass(MAKEINTATOM(khm_main_window_class),khm_hInstance); + UnregisterClass(MAKEINTATOM(khm_null_window_class),khm_hInstance); +} diff --git a/mechglue/src/windows/identity/ui/mainwnd.h b/mechglue/src/windows/identity/ui/mainwnd.h new file mode 100644 index 000000000..95b28b733 --- /dev/null +++ b/mechglue/src/windows/identity/ui/mainwnd.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_MAINWND_H +#define __KHIMAIRA_MAINWND_H + +#define KHUI_MAIN_WINDOW_CLASS L"KhmMainWindowClass" +#define KHUI_NULL_WINDOW_CLASS L"KhmNullWindowClass" + +extern ATOM khm_main_window_class; +extern HWND khm_hwnd_main; +extern HWND khm_hwnd_rebar; + +void khm_register_main_wnd_class(void); +void khm_unregister_main_wnd_class(void); +void khm_create_main_window_controls(HWND); +void khm_create_main_window(void); +void khm_show_main_window(void); +void khm_hide_main_window(void); +BOOL khm_is_main_window_visible(void); +BOOL khm_is_main_window_active(void); +LRESULT khm_rebar_notify(LPNMHDR lpnm); + +void +khm_set_dialog_result(HWND hwnd, LRESULT lr); + +LRESULT CALLBACK +khm_main_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +#define WM_KHUI_ASSIGN_COMMANDLINE 32808 + +#define COMMANDLINE_MAP_FMT L"Local\\NetIDMgr_Cmdline_%lu" + +#endif diff --git a/mechglue/src/windows/identity/ui/makeacceldef.pl b/mechglue/src/windows/identity/ui/makeacceldef.pl new file mode 100644 index 000000000..f13a3ec18 --- /dev/null +++ b/mechglue/src/windows/identity/ui/makeacceldef.pl @@ -0,0 +1,29 @@ +# + +die "Please specify input and output filenames" if($#ARGV != 1); + +open INF, '<', $ARGV[0] or die "Can't open input file"; +open OUF, '>', $ARGV[1] or die "Can't open output file"; + +print OUF <<EOS; +#include<khimaira.h> + + khui_accel_def khui_accel_global[] = { +EOS + +# skip first line + <INF>; + +while(<INF>) { + print OUF "{".$_."},\n"; +} + +print OUF <<EOS; +}; + +int khui_n_accel_global = sizeof(khui_accel_global) / sizeof(khui_accel_def); + +EOS + +close INF; +close OUF; diff --git a/mechglue/src/windows/identity/ui/makeactiondef.pl b/mechglue/src/windows/identity/ui/makeactiondef.pl new file mode 100644 index 000000000..a83325b3a --- /dev/null +++ b/mechglue/src/windows/identity/ui/makeactiondef.pl @@ -0,0 +1,29 @@ +# + +die "Please specify input and output filenames" if($#ARGV != 1); + +open INF, '<', $ARGV[0] or die "Can't open input file"; +open OUF, '>', $ARGV[1] or die "Can't open output file"; + +print OUF <<EOS; +#include<khimaira.h> + + khui_action khui_actions[] = { +EOS + +# skip first line + <INF>; + +while(<INF>) { + print OUF "{".$_."},\n"; +} + +print OUF <<EOS; +}; + +int khui_n_actions = sizeof(khui_actions) / sizeof(khui_action); + +EOS + +close INF; +close OUF; diff --git a/mechglue/src/windows/identity/ui/netidmgr.exe.manifest.i386 b/mechglue/src/windows/identity/ui/netidmgr.exe.manifest.i386 new file mode 100644 index 000000000..5e83258c4 --- /dev/null +++ b/mechglue/src/windows/identity/ui/netidmgr.exe.manifest.i386 @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc7 b/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc7 new file mode 100644 index 000000000..5e83258c4 --- /dev/null +++ b/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc7 @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug b/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug new file mode 100644 index 000000000..5e83258c4 --- /dev/null +++ b/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc7.debug @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc8 b/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc8 new file mode 100644 index 000000000..84d91a339 --- /dev/null +++ b/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc8 @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.VC80.DebugCRT" + version="8.0.50215.4652" + processorArchitecture="x86" + publicKeyToken="1fc8b3b9a1e18e3b" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug b/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug new file mode 100644 index 000000000..84d91a339 --- /dev/null +++ b/mechglue/src/windows/identity/ui/netidmgr.manifest.i386.vc8.debug @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity + version="1.0.0.0" + processorArchitecture="X86" + name="MIT.NetIDMgr.UI" + type="win32" +/> +<description>Khimaira Credentials Manager</description> +<dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.VC80.DebugCRT" + version="8.0.50215.4652" + processorArchitecture="x86" + publicKeyToken="1fc8b3b9a1e18e3b" + /> + </dependentAssembly> +</dependency> +</assembly> diff --git a/mechglue/src/windows/identity/ui/newcredwnd.c b/mechglue/src/windows/identity/ui/newcredwnd.c new file mode 100644 index 000000000..619b79687 --- /dev/null +++ b/mechglue/src/windows/identity/ui/newcredwnd.c @@ -0,0 +1,1858 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +ATOM khui_newcredwnd_cls; + +/* forward dcl */ +static void +nc_position_credtext(khui_nc_wnd_data * d); + +/* Common dialog procedure. Be careful. This is used by more than + one dialog. */ +static INT_PTR CALLBACK +nc_common_dlg_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_INITDIALOG: + { + khui_nc_wnd_data * d; + + d = (khui_nc_wnd_data *) lParam; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, DWLP_USER, lParam); +#pragma warning(pop) + if (d->nc->subtype == KMSG_CRED_PASSWORD) { + ShowWindow(GetDlgItem(hwnd, IDC_NC_OPTIONS), + SW_HIDE); + } + } + return TRUE; + + case WM_COMMAND: + { + int ctrl_id; + + ctrl_id = LOWORD(wParam); + if (ctrl_id < KHUI_CW_ID_MIN || + ctrl_id > KHUI_CW_ID_MAX) { + /* pump it to the parent */ + PostMessage(GetParent(hwnd), WM_COMMAND, wParam, lParam); + return TRUE; + } /* else we allow the message to fall through and get + passed into the identity provider's message + handler. */ + } + break; + +#if 0 + /* someday this will be used to draw custom tab buttons. But + that's not today */ + case WM_DRAWITEM: + { + khui_nc_wnd_data * d; + int id; + LPDRAWITEMSTRUCT ds; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, DWLP_USER); + id = wParam; + ds = (LPDRAWITEMSTRUCT) lParam; + + if(id >= NC_TS_CTRL_ID_MIN && id <= NC_TS_CTRL_ID_MAX) { + /*TODO: custom draw the buttons */ + } + else + return FALSE; + } + break; +#endif + + case KHUI_WM_NC_NOTIFY: + { + khui_nc_wnd_data * d; + d = (khui_nc_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + /* message sent by parent to notify us of something */ + switch(HIWORD(wParam)) { + case WMNC_DIALOG_EXPAND: + if(hwnd == d->dlg_main) { + HWND hw; + + if(hw = GetDlgItem(hwnd, IDOK)) + ShowWindow(hw, SW_HIDE); + if(hw = GetDlgItem(hwnd, IDCANCEL)) + ShowWindow(hw, SW_HIDE); + if(hw = GetDlgItem(hwnd, IDC_NC_OPTIONS)) + ShowWindow(hw, SW_HIDE); + + d->r_credtext.bottom = d->r_area.bottom; + + nc_position_credtext(d); + + return TRUE; + } + } + } + return TRUE; + } + + /* check if we have a wnd_data, and if so pass the message on to + the identity provider callback. */ + { + khui_nc_wnd_data * d; + + d = (khui_nc_wnd_data *) (LONG_PTR) + GetWindowLongPtr(hwnd, DWLP_USER); + + if (d && d->nc && d->nc->ident_cb) { + return d->nc->ident_cb(d->nc, WMNC_IDENT_WMSG, hwnd, uMsg, + wParam, lParam); + } + } + + return FALSE; +} + +static void +nc_position_credtext(khui_nc_wnd_data * d) +{ + HWND hw; + + hw = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT); +#ifdef DEBUG + assert(hw); +#endif + + if (d->r_credtext.bottom < d->r_credtext.top + d->r_row.bottom * 2) { + /* not enough room */ + if (d->nc->mode == KHUI_NC_MODE_MINI && + d->nc->subtype != KMSG_CRED_PASSWORD) { + PostMessage(d->nc->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); + return; + } else { + ShowWindow(hw, SW_HIDE); + return; + } + } else { + ShowWindow(hw, SW_SHOW); + } + + SetWindowPos(hw, NULL, + d->r_credtext.left + d->r_n_input.left, /* x */ + d->r_credtext.top, /* y */ + d->r_n_input.right - d->r_n_input.left, /* width */ + d->r_credtext.bottom - d->r_credtext.top, /* height */ + SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOZORDER); + + hw = GetDlgItem(d->dlg_main, IDC_NC_CREDTEXT_LABEL); + + SetWindowPos(hw, NULL, + d->r_credtext.left + d->r_n_label.left, /* x */ + d->r_credtext.top, /* y */ + d->r_n_label.right - d->r_n_label.left, /* width */ + d->r_n_label.bottom - d->r_n_label.top, /* height */ + SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOZORDER); +} + +/* sorts tab buttons */ +static int __cdecl +nc_tab_sort_func(const void * v1, const void * v2) +{ + /* v1 and v2 and of type : khui_new_creds_by_type ** */ + khui_new_creds_by_type *t1, *t2; + + t1 = *((khui_new_creds_by_type **) v1); + t2 = *((khui_new_creds_by_type **) v2); + + if(t1->ordinal > 0) { + if(t2->ordinal > 0) { + if(t1->ordinal == t2->ordinal) + return wcscmp(t1->name, t2->name); + else + /* safe to convert to an int here */ + return (int) (t1->ordinal - t2->ordinal); + } else + return -1; + } else { + if(t2->ordinal > 0) + return 1; + else if (t1->name && t2->name) + return wcscmp(t1->name, t2->name); + else + return 0; + } +} + +static void +nc_notify_types_async(khui_new_creds * c, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + khm_size i; + + for(i=0; i<c->n_types; i++) { + PostMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam); + } +} + +static void +nc_notify_types(khui_new_creds * c, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + khm_size i; + + for(i=0; i<c->n_types; i++) { + SendMessage(c->types[i]->hwnd_panel, uMsg, wParam, lParam); + } +} + +#define NC_MAXCCH_CREDTEXT 16384 +#define NC_MAXCB_CREDTEXT (NC_MAXCCH_CREDTEXT * sizeof(wchar_t)) + +static void +nc_update_credtext(khui_nc_wnd_data * d) +{ + wchar_t * ctbuf = NULL; + wchar_t * buf; + BOOL okEnable = FALSE; + BOOL validId = FALSE; + HWND hw = NULL; + size_t cch = 0; + + ctbuf = PMALLOC(NC_MAXCB_CREDTEXT); + + assert(ctbuf != NULL); + + LoadString(khm_hInstance, IDS_NC_CREDTEXT_TABS, ctbuf, NC_MAXCCH_CREDTEXT); + StringCchLength(ctbuf, NC_MAXCCH_CREDTEXT, &cch); + buf = ctbuf + cch; + nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_UPDATE_CREDTEXT), 0); + + /* hopefully all the types have updated their credential texts */ + if(d->nc->n_identities == 1) { + wchar_t main_fmt[256]; + wchar_t id_fmt[256]; + wchar_t id_name[KCDB_IDENT_MAXCCH_NAME]; + wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256]; + khm_size cbbuf; + khm_int32 flags; + + + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_ONE, + main_fmt, (int) ARRAYLENGTH(main_fmt)); + + cbbuf = sizeof(id_name); + kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf); + + kcdb_identity_get_flags(d->nc->identities[0], &flags); + + if (flags & KCDB_IDENT_FLAG_INVALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else if(flags & KCDB_IDENT_FLAG_VALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else if(d->nc->subtype == KMSG_CRED_NEW_CREDS) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_CHECKING, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } + + StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); + + StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), + main_fmt, id_string); + + if (flags & KCDB_IDENT_FLAG_VALID) { + if (flags & KCDB_IDENT_FLAG_DEFAULT) + LoadString(khm_hInstance, IDS_NC_ID_DEF, + id_string, ARRAYLENGTH(id_string)); + else if (d->nc->set_default) + LoadString(khm_hInstance, IDS_NC_ID_WDEF, + id_string, ARRAYLENGTH(id_string)); + else + LoadString(khm_hInstance, IDS_NC_ID_NDEF, + id_string, ARRAYLENGTH(id_string)); + + StringCbCat(buf, NC_MAXCB_CREDTEXT - cch * sizeof(wchar_t), + id_string); + } + + } else if(d->nc->n_identities > 1) { + wchar_t *ids_string; + khm_size cb_ids_string; + + wchar_t id_name[KCDB_IDENT_MAXCCH_NAME]; + wchar_t id_fmt[256]; + wchar_t id_string[KCDB_IDENT_MAXCCH_NAME + 256]; + + wchar_t main_fmt[256]; + khm_size cbbuf; + + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_MANY, + main_fmt, (int) ARRAYLENGTH(main_fmt)); + + /* we are going to concatenate all the identity names into + a comma separated string */ + + /* d->nc->n_identities is at least 2 */ + ids_string = PMALLOC((KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * + (d->nc->n_identities - 1)); + cb_ids_string = + (KCDB_IDENT_MAXCB_NAME + sizeof(id_fmt)) * + (d->nc->n_identities - 1); + + assert(ids_string != NULL); + + ids_string[0] = 0; + + { + khm_size i; + khm_int32 flags; + + for(i=1; i<d->nc->n_identities; i++) { + if(i>1) { + StringCbCat(ids_string, cb_ids_string, L","); + } + + flags = 0; + + cbbuf = sizeof(id_name); + kcdb_identity_get_name(d->nc->identities[i], id_name, &cbbuf); + kcdb_identity_get_flags(d->nc->identities[i], &flags); + if(flags & KCDB_IDENT_FLAG_INVALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else if(flags & KCDB_IDENT_FLAG_VALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } + + StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); + StringCbCat(ids_string, cb_ids_string, id_string); + } + + cbbuf = sizeof(id_name); + kcdb_identity_get_name(d->nc->identities[0], id_name, &cbbuf); + kcdb_identity_get_flags(d->nc->identities[0], &flags); + if(flags & KCDB_IDENT_FLAG_INVALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_INVALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else if(flags & KCDB_IDENT_FLAG_VALID) { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_VALID, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } else { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_UNCHECKED, + id_fmt, (int) ARRAYLENGTH(id_fmt)); + } + StringCbPrintf(id_string, sizeof(id_string), id_fmt, id_name); + + StringCbPrintf(buf, NC_MAXCB_CREDTEXT - cch*sizeof(wchar_t), + main_fmt, id_string, ids_string); + + PFREE(ids_string); + } + } else { + LoadString(khm_hInstance, IDS_NC_CREDTEXT_ID_NONE, + buf, (int)(NC_MAXCCH_CREDTEXT - cch)); + } + + /* now, append the credtext string from each of the cred types */ + { + khm_size i; + size_t cb; + wchar_t * buf; + + cb = NC_MAXCB_CREDTEXT; + buf = ctbuf; + + for(i=0; i<d->nc->n_types; i++) { + if(d->nc->types[i]->credtext != NULL) { + StringCbCatEx(buf, cb, + d->nc->types[i]->credtext, + &buf, &cb, + 0); + } + } + } + + SetDlgItemText(d->dlg_main, IDC_NC_CREDTEXT, ctbuf); + + PFREE(ctbuf); + + /* so depending on whether the primary identity was found to be + invalid, we need to disable the Ok button and set the title to + reflect this */ + + if(d->nc->n_identities > 0) { + khm_int32 flags = 0; + + if(KHM_SUCCEEDED(kcdb_identity_get_flags(d->nc->identities[0], + &flags)) && + (flags & KCDB_IDENT_FLAG_VALID)) { + validId = TRUE; + } + } + + if (d->nc->window_title == NULL) { + if(validId) { + wchar_t wpostfix[256]; + wchar_t wtitle[KCDB_IDENT_MAXCCH_NAME + 256]; + khm_size cbsize; + + cbsize = sizeof(wtitle); + kcdb_identity_get_name(d->nc->identities[0], wtitle, &cbsize); + + if (d->nc->subtype == KMSG_CRED_PASSWORD) + LoadString(khm_hInstance, IDS_WTPOST_PASSWORD, + wpostfix, (int) ARRAYLENGTH(wpostfix)); + else + LoadString(khm_hInstance, IDS_WTPOST_NEW_CREDS, + wpostfix, (int) ARRAYLENGTH(wpostfix)); + + StringCbCat(wtitle, sizeof(wtitle), wpostfix); + + SetWindowText(d->nc->hwnd, wtitle); + } else { + wchar_t wtitle[256]; + + if (d->nc->subtype == KMSG_CRED_PASSWORD) + LoadString(khm_hInstance, IDS_WT_PASSWORD, + wtitle, (int) ARRAYLENGTH(wtitle)); + else + LoadString(khm_hInstance, IDS_WT_NEW_CREDS, + wtitle, (int) ARRAYLENGTH(wtitle)); + + SetWindowText(d->nc->hwnd, wtitle); + } + } + + if(validId || d->nc->subtype == KMSG_CRED_PASSWORD) { + /* TODO: check if all the required fields have valid values + before enabling the Ok button */ + okEnable = TRUE; + } + + hw = GetDlgItem(d->dlg_main, IDOK); + EnableWindow(hw, okEnable); + hw = GetDlgItem(d->dlg_bb, IDOK); + EnableWindow(hw, okEnable); +} + +#define CW_PARAM DWLP_USER + +static void +nc_add_control_row(khui_nc_wnd_data * d, + HWND label, + HWND input, + khui_control_size size); + +static LRESULT +nc_handle_wm_create(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LPCREATESTRUCT lpc; + khui_new_creds * c; + khui_nc_wnd_data * ncd; + int x, y; + int width, height; + RECT r; + + lpc = (LPCREATESTRUCT) lParam; + + ncd = PMALLOC(sizeof(*ncd)); + ZeroMemory(ncd, sizeof(*ncd)); + + c = (khui_new_creds *) lpc->lpCreateParams; + ncd->nc = c; + c->hwnd = hwnd; + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, CW_PARAM, (LONG_PTR) ncd); +#pragma warning(pop) + + /* first try to create the main dialog panel */ + + assert(c->subtype == KMSG_CRED_NEW_CREDS || + c->subtype == KMSG_CRED_PASSWORD); + + ncd->dlg_main = CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_NC_PASSWORD), + hwnd, + nc_common_dlg_proc, + (LPARAM) ncd); +#ifdef DEBUG + assert(ncd->dlg_main); +#endif + + { + RECT r_main; + RECT r_area; + RECT r_row; + HWND hw; + + /* pick out metrics for use by the custom prompter stuff */ + GetWindowRect(ncd->dlg_main, &r_main); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_PANEL); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r_area); + OffsetRect(&r_area,-r_main.left, -r_main.top); + CopyRect(&ncd->r_area, &r_area); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + CopyRect(&r_row, &r); + OffsetRect(&r,-r.left, -r.top); + CopyRect(&ncd->r_row, &r); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r,-r_row.left, -r_row.top); + CopyRect(&ncd->r_n_label, &r); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r, -r_row.left, -r_row.top); + CopyRect(&ncd->r_n_input, &r); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_ROW_LG); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r_row); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_LABEL_LG); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r, -r_row.left, -r_row.top); + CopyRect(&ncd->r_e_label, &r); + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_TPL_INPUT_LG); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r, -r_row.left, -r_row.top); + CopyRect(&ncd->r_e_input, &r); + + CopyRect(&ncd->r_credtext, &ncd->r_area); + CopyRect(&ncd->r_idspec, &ncd->r_area); + + ncd->r_idspec.bottom = ncd->r_idspec.top; + + hw = GetDlgItem(ncd->dlg_main, IDC_NC_CREDTEXT); +#ifdef DEBUG + assert(hw); +#endif + GetWindowRect(hw, &r); + OffsetRect(&r, -r_main.left, -r_main.top); + ncd->r_credtext.bottom = r.bottom; + } + + /* if the mode is 'mini'*/ + r.left = 0; + r.top = 0; + if(c->mode == KHUI_NC_MODE_MINI) { + r.right = NCDLG_WIDTH; + r.bottom = NCDLG_HEIGHT; + } else { + r.right = NCDLG_WIDTH + NCDLG_BBAR_WIDTH; + r.bottom = NCDLG_HEIGHT + NCDLG_TAB_HEIGHT; + } + + MapDialogRect(ncd->dlg_main, &r); + + ncd->r_main.left = 0; + ncd->r_main.top = 0; + ncd->r_main.right = NCDLG_WIDTH; + ncd->r_main.bottom = NCDLG_HEIGHT; + + ncd->r_ts.left = 0; + ncd->r_ts.top = ncd->r_main.bottom; + ncd->r_ts.right = ncd->r_main.right; + ncd->r_ts.bottom = ncd->r_ts.top + NCDLG_TAB_HEIGHT; + + ncd->r_bb.left = ncd->r_main.right; + ncd->r_bb.top = 0; + ncd->r_bb.right = ncd->r_bb.left + NCDLG_BBAR_WIDTH; + ncd->r_bb.bottom = ncd->r_ts.bottom; + + MapDialogRect(ncd->dlg_main, &(ncd->r_main)); + MapDialogRect(ncd->dlg_main, &(ncd->r_ts)); + MapDialogRect(ncd->dlg_main, &(ncd->r_bb)); + + /* center the new creds window over the main NetIDMgr window */ + width = r.right - r.left; + height = r.bottom - r.top; + + /* adjust width and height to accomodate NC area */ + { + RECT wr,cr; + + GetWindowRect(hwnd, &wr); + GetClientRect(hwnd, &cr); + + /* the non-client and client areas have already been calculated + at this point. We just use the difference to adjust the width + and height */ + width += (wr.right - wr.left) - (cr.right - cr.left); + height += (wr.bottom - wr.top) - (cr.bottom - cr.top); + } + + GetWindowRect(lpc->hwndParent, &r); + x = (r.right + r.left)/2 - width / 2; + y = (r.top + r.bottom)/2 - height / 2; + + MoveWindow(hwnd, x, y, width, height, FALSE); + + SetWindowPos(ncd->dlg_main, + NULL, + ncd->r_main.left, + ncd->r_main.top, + ncd->r_main.right - ncd->r_main.left, + ncd->r_main.bottom - ncd->r_main.top, + SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOREDRAW | SWP_NOZORDER); + + /* IDD_NC_BBAR is the button bar that sits on the right of the + dialog when the new creds window is in 'expanded' mode. */ + + ncd->dlg_bb = CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_NC_BBAR), + hwnd, + nc_common_dlg_proc, + (LPARAM) ncd); + +#ifdef DEBUG + assert(ncd->dlg_bb); +#endif + + SetWindowPos(ncd->dlg_bb, + NULL, + ncd->r_bb.left, + ncd->r_bb.top, + ncd->r_bb.right - ncd->r_bb.left, + ncd->r_bb.bottom - ncd->r_bb.top, + SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOREDRAW | SWP_NOZORDER); + + /* IDD_NC_TS is the tab strip that sits below the main panel when + the new creds window is in 'expanded' mode */ + + ncd->dlg_ts = CreateDialogParam(khm_hInstance, + MAKEINTRESOURCE(IDD_NC_TS), + hwnd, + nc_common_dlg_proc, + (LPARAM) ncd); + +#ifdef DEBUG + assert(ncd->dlg_ts); +#endif + + SetWindowPos(ncd->dlg_ts, + NULL, + ncd->r_ts.left, + ncd->r_ts.top, + ncd->r_ts.right - ncd->r_ts.left, + ncd->r_ts.bottom - ncd->r_ts.top, + SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | + SWP_NOREDRAW | SWP_NOZORDER); + + if(c->mode == KHUI_NC_MODE_MINI) { + /* hide and show stuff */ + ShowWindow(ncd->dlg_main, SW_SHOW); + ShowWindow(ncd->dlg_bb, SW_HIDE); + ShowWindow(ncd->dlg_ts, SW_HIDE); + + nc_position_credtext(ncd); + + } else { + /* hide and show stuff */ + ShowWindow(ncd->dlg_main, SW_SHOW); + ShowWindow(ncd->dlg_bb, SW_SHOW); + ShowWindow(ncd->dlg_ts, SW_SHOW); + + PostMessage(ncd->dlg_main, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); + } + + /* Call the identity provider callback to set the identity + selector controls */ + c->ident_cb(c, WMNC_IDENT_INIT, NULL, 0, 0, (LPARAM) ncd->dlg_main); + +#if 0 + { + HWND hw; + wchar_t wcaption[64]; + + LoadString(khm_hInstance, IDS_NC_SETDEF, wcaption, + ARRAYLENGTH(wcaption)); + + /* Now create the set as default button */ + hw = CreateWindow + (L"BUTTON", + wcaption, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX, + 0, 0, 100, 100, + ncd->dlg_main, + (HMENU) NC_BN_SET_DEF_ID, + khm_hInstance, + NULL); + + nc_add_control_row(ncd, NULL, hw, KHUI_CTRLSIZE_HALF); + } +#endif + /* we defer the creation of the tab buttons for later */ + + /* add this to the dialog chain */ + khm_add_dialog(hwnd); + + return TRUE; +} + +static void +nc_add_control_row(khui_nc_wnd_data * d, + HWND label, + HWND input, + khui_control_size size) +{ + RECT r_row; + RECT r_label; + RECT r_input; + HFONT hf; + + hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); + SendMessage(label, WM_SETFONT, (WPARAM) hf, FALSE); + SendMessage(input, WM_SETFONT, (WPARAM) hf, FALSE); + + CopyRect(&r_row, &d->r_row); + OffsetRect(&r_row, d->r_idspec.left, d->r_idspec.bottom); + + if (size == KHUI_CTRLSIZE_SMALL) { + CopyRect(&r_label, &d->r_n_label); + CopyRect(&r_input, &d->r_n_input); + OffsetRect(&r_label, r_row.left, r_row.top); + OffsetRect(&r_input, r_row.left, r_row.top); + } else if (size == KHUI_CTRLSIZE_HALF) { + CopyRect(&r_label, &d->r_e_label); + CopyRect(&r_input, &d->r_e_input); + OffsetRect(&r_label, r_row.left, r_row.top); + OffsetRect(&r_input, r_row.left, r_row.top); + } else if (size == KHUI_CTRLSIZE_FULL) { + CopyRect(&r_label, &d->r_n_label); + r_label.right = d->r_row.right; + CopyRect(&r_input, &d->r_n_input); + OffsetRect(&r_input, r_row.left, r_row.top); + OffsetRect(&r_input, 0, r_input.bottom); + r_row.bottom += r_input.bottom; + OffsetRect(&r_label, r_row.left, r_row.top); + } else { +#ifdef DEBUG + assert(FALSE); +#else + return; +#endif + } + + if (label) + SetWindowPos(label, + ((d->hwnd_last_idspec != NULL)? + d->hwnd_last_idspec: + HWND_TOP), + r_label.left, r_label.top, + r_label.right - r_label.left, + r_label.bottom - r_label.top, + SWP_DEFERERASE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER); + + if (input) + SetWindowPos(input, + (label ? label : ((d->hwnd_last_idspec != NULL)? + d->hwnd_last_idspec: + HWND_TOP)), + r_input.left, r_input.top, + r_input.right - r_input.left, + r_input.bottom - r_input.top, + SWP_DEFERERASE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER); + + d->hwnd_last_idspec = input; + + d->r_idspec.bottom = r_row.bottom; + + d->r_credtext.top = r_row.bottom; + + nc_position_credtext(d); +} + + +static LRESULT +nc_handle_wm_destroy(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_nc_wnd_data * d; + khm_size i; + + /* remove self from dialog chain */ + khm_del_dialog(hwnd); + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + d->nc->ident_cb(d->nc, WMNC_IDENT_EXIT, NULL, 0, 0, 0); + + if(d->hwnd_tc_main) + DestroyWindow(d->hwnd_tc_main); + for(i=0;i<d->nc->n_types;i++) { + if(d->nc->types[i]->hwnd_tc) { + DestroyWindow(d->nc->types[i]->hwnd_tc); + d->nc->types[i]->hwnd_tc = NULL; + } + } + + if(d->dlg_bb) + DestroyWindow(d->dlg_bb); + if(d->dlg_main) + DestroyWindow(d->dlg_main); + if(d->dlg_ts) + DestroyWindow(d->dlg_ts); + + d->dlg_bb = NULL; + d->dlg_main = NULL; + d->dlg_ts = NULL; + + PFREE(d); + + return TRUE; +} + +static LRESULT +nc_handle_wm_command(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_nc_wnd_data * d; + int id; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + switch(HIWORD(wParam)) { + case BN_CLICKED: + switch(LOWORD(wParam)) { + + case IDOK: + d->nc->result = KHUI_NC_RESULT_GET_CREDS; + + /* fallthrough */ + + case IDCANCEL: + /* the default value for d->nc->result is set to + KHUI_NC_RESULT_CANCEL */ + d->nc->response = 0; + + nc_notify_types(d->nc, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_PREPROCESS), + 0); + + khui_cw_sync_prompt_values(d->nc); + + khm_cred_dispatch_process_message(d->nc); + + /* we won't know whether to abort or not until we get + feedback from the plugins, even if the command was + to cancel */ + { + HWND hw; + + hw = GetDlgItem(d->dlg_main, IDOK); + EnableWindow(hw, FALSE); + hw = GetDlgItem(d->dlg_main, IDCANCEL); + EnableWindow(hw, FALSE); + hw = GetDlgItem(d->dlg_bb, IDOK); + EnableWindow(hw, FALSE); + hw = GetDlgItem(d->dlg_bb, IDCANCEL); + EnableWindow(hw, FALSE); + } + return FALSE; + + case IDC_NC_HELP: + khm_html_help(hwnd, NULL, HH_HELP_CONTEXT, IDH_ACTION_NEW_ID); + return FALSE; + + case IDC_NC_OPTIONS: + /* the Options button in the main window was clicked. we + respond by expanding the dialog. */ + PostMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_EXPAND), 0); + return FALSE; + + case IDC_NC_CREDTEXT: /* credtext link activated */ + { + khui_htwnd_link * l; + wchar_t sid[KHUI_MAXCCH_HTLINK_FIELD]; + wchar_t sparam[KHUI_MAXCCH_HTLINK_FIELD]; + wchar_t * colon; + + l = (khui_htwnd_link *) lParam; + + /* do we have a valid link? */ + if(l->id == NULL || l->id_len >= ARRAYLENGTH(sid)) + return TRUE; /* nope */ + + StringCchCopyN(sid, ARRAYLENGTH(sid), l->id, l->id_len); + sid[l->id_len] = L'\0'; /* just make sure */ + + if(l->param != NULL && + l->param_len < ARRAYLENGTH(sparam) && + l->param_len > 0) { + + wcsncpy(sparam, l->param, l->param_len); + sparam[l->param_len] = L'\0'; + + } else { + sparam[0] = L'\0'; + } + + /* If the ID is of the form '<credtype>:<link_tag>' + and <credtype> is a valid name of a credentials + type that is participating in the credentials + acquisition process, then we forward the message to + the panel that is providing the UI for that cred + type. We also switch to that panel first. */ + + colon = wcschr(sid, L':'); + if (colon != NULL) { + khm_int32 credtype; + khui_new_creds_by_type * t; + + *colon = L'\0'; + if (KHM_SUCCEEDED(kcdb_credtype_get_id(sid, &credtype)) && + KHM_SUCCEEDED(khui_cw_find_type(d->nc, credtype, &t))){ + *colon = L':'; + + if (t->ordinal != d->ctab) + PostMessage(hwnd, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(t->ordinal, + WMNC_DIALOG_SWITCH_PANEL), + 0); + + return SendMessage(t->hwnd_panel, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_CREDTEXT_LINK), + lParam); + } + } + + /* if it was for us, then we need to process the message */ + if(!wcsicmp(sid, CTLINKID_SWITCH_PANEL)) { + khm_int32 credtype; + khui_new_creds_by_type * t; + + if (KHM_SUCCEEDED(kcdb_credtype_get_id(sparam, + &credtype)) && + KHM_SUCCEEDED(khui_cw_find_type(d->nc, + credtype, &t))) { + if (t->ordinal != d->ctab) + PostMessage(hwnd, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(t->ordinal, + WMNC_DIALOG_SWITCH_PANEL), + 0); + } + } else if (!wcsicmp(sid, L"NotDef")) { + d->nc->set_default = FALSE; + nc_update_credtext(d); + } else if (!wcsicmp(sid, L"MakeDef")) { + d->nc->set_default = TRUE; + nc_update_credtext(d); + } + } + return FALSE; + +#if 0 + case NC_BN_SET_DEF_ID: + { + d->nc->set_default = + (IsDlgButtonChecked(d->dlg_main, NC_BN_SET_DEF_ID) + == BST_CHECKED); + } + return FALSE; +#endif + + default: + /* if one of the tab strip buttons were pressed, then + we should switch to that panel */ + id = LOWORD(wParam); + if(id >= NC_TS_CTRL_ID_MIN && id <= NC_TS_CTRL_ID_MAX) { + id -= NC_TS_CTRL_ID_MIN; + PostMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(id, WMNC_DIALOG_SWITCH_PANEL),0); + return FALSE; + } + } + break; + } + + return TRUE; +} + +static LRESULT nc_handle_wm_moving(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_nc_wnd_data * d; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_MOVE), 0); + + return FALSE; +} + +static LRESULT nc_handle_wm_nc_notify(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_nc_wnd_data * d; + RECT r; + int width, height; + khm_size id; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + switch(HIWORD(wParam)) { + + case WMNC_DIALOG_SWITCH_PANEL: + id = LOWORD(wParam); + if(id >= 0 && id <= d->nc->n_types) { + /* one of the tab buttons were pressed */ + if(d->ctab == id) { + return TRUE; /* nothign to do */ + } + + if(d->ctab == 0) { + ShowWindow(d->dlg_main, SW_HIDE); + SendMessage(d->hwnd_tc_main, + BM_SETCHECK, BST_UNCHECKED, 0); + } else { + ShowWindow(d->nc->types[d->ctab - 1]->hwnd_panel, SW_HIDE); + SendMessage(d->nc->types[d->ctab - 1]->hwnd_tc, + BM_SETCHECK, BST_UNCHECKED, 0); + } + + d->ctab = id; + + if(d->ctab == 0) { + ShowWindow(d->dlg_main, SW_SHOW); + SendMessage(d->hwnd_tc_main, + BM_SETCHECK, BST_CHECKED, 0); + } else { + ShowWindow(d->nc->types[id - 1]->hwnd_panel, SW_SHOW); + SendMessage(d->nc->types[id - 1]->hwnd_tc, + BM_SETCHECK, BST_CHECKED, 0); + } + } + + if(d->nc->mode == KHUI_NC_MODE_EXPANDED) + return TRUE; + /*else*/ + /* fallthrough */ + + case WMNC_DIALOG_EXPAND: + /* we are expanding the dialog box */ + + /* nothing to do? */ + if (d->nc->mode == KHUI_NC_MODE_EXPANDED) + break; + + d->nc->mode = KHUI_NC_MODE_EXPANDED; + + r.top = 0; + r.left = 0; + r.right = NCDLG_WIDTH + NCDLG_BBAR_WIDTH; + r.bottom = NCDLG_HEIGHT + NCDLG_TAB_HEIGHT; + + MapDialogRect(d->dlg_main, &r); + + width = r.right - r.left; + height = r.bottom - r.top; + + /* adjust width and height to accomodate NC area */ + { + RECT wr,cr; + + GetWindowRect(hwnd, &wr); + GetClientRect(hwnd, &cr); + + /* the non-client and client areas have already been + calculated at this point. We just use the difference + to adjust the width and height */ + width += (wr.right - wr.left) - (cr.right - cr.left); + height += (wr.bottom - wr.top) - (cr.bottom - cr.top); + } + + SendMessage(d->dlg_main, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_EXPAND), + 0); + + SetWindowPos(hwnd, + NULL, + 0, 0, + width, height, + SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | + SWP_NOZORDER); + + ShowWindow(d->dlg_bb, SW_SHOW); + ShowWindow(d->dlg_ts, SW_SHOW); + break; + + case WMNC_DIALOG_SETUP: + if(d->nc->n_types > 0) { + khm_size i; + for(i=0; i < d->nc->n_types;i++) { + + if (d->nc->types[i]->dlg_proc == NULL) { + d->nc->types[i]->hwnd_panel = NULL; + } else { + /* Create the dialog panel */ + d->nc->types[i]->hwnd_panel = + CreateDialogParam(d->nc->types[i]->h_module, + d->nc->types[i]->dlg_template, + d->nc->hwnd, + d->nc->types[i]->dlg_proc, + (LPARAM) d->nc); + +#ifdef DEBUG + assert(d->nc->types[i]->hwnd_panel); +#endif + } + } + } + break; + + case WMNC_DIALOG_ACTIVATE: + { + int x,y,width,height; + RECT r; + int id; + wchar_t wbuf[256]; + HFONT hf; + + /* now we create all the tab strip controls */ + r.left = 0; + r.top = 0; + r.right = NCDLG_TAB_WIDTH; + r.bottom = NCDLG_TAB_HEIGHT; + MapDialogRect(d->dlg_main, &r); + + width = r.right - r.left; + height = r.bottom - r.top; + + x = 0; + y = 0; + + id = NC_TS_CTRL_ID_MIN; + + khui_cw_lock_nc(d->nc); + + /* first, the control for the main panel */ + LoadString(khm_hInstance, IDS_NC_IDENTITY, + wbuf, ARRAYLENGTH(wbuf)); + + d->hwnd_tc_main = + CreateWindow(L"BUTTON", + wbuf, + WS_VISIBLE | WS_CHILD | WS_TABSTOP | + BS_PUSHLIKE | BS_CHECKBOX | BS_TEXT, + x,y,width,height, + d->dlg_ts, + (HMENU)(INT_PTR) id, + khm_hInstance, + NULL); + + hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); + SendMessage(d->hwnd_tc_main, WM_SETFONT, (WPARAM) hf, 0); + SendMessage(d->hwnd_tc_main, BM_SETCHECK, BST_CHECKED, 0); + + id++; + x += width; + + if(d->nc->n_types > 0) { + khm_size i; + /* we should sort the tabs first */ + qsort(d->nc->types, + d->nc->n_types, + sizeof(*(d->nc->types)), + nc_tab_sort_func); + + for(i=0; i < d->nc->n_types;i++) { + wchar_t * name; + + d->nc->types[i]->ordinal = i + 1; + + if(d->nc->types[i]->name) + name = d->nc->types[i]->name; + else { + khm_size cbsize; + + if(kcdb_credtype_describe + (d->nc->types[i]->type, + NULL, + &cbsize, + KCDB_TS_SHORT) == KHM_ERROR_TOO_LONG) { + + name = PMALLOC(cbsize); + kcdb_credtype_describe(d->nc->types[i]->type, + name, + &cbsize, + KCDB_TS_SHORT); + } else { +#ifdef DEBUG + assert(FALSE); +#else + continue; +#endif + } + } + + d->nc->types[i]->hwnd_tc = + CreateWindow(L"BUTTON", + name, + WS_VISIBLE | WS_CHILD | WS_TABSTOP | + BS_PUSHLIKE | BS_CHECKBOX | BS_TEXT | + ((d->nc->types[i]->hwnd_panel == NULL)? + WS_DISABLED : 0), + x,y,width,height, + d->dlg_ts, + (HMENU)(INT_PTR) id, + khm_hInstance, + NULL); + + SendMessage(d->nc->types[i]->hwnd_tc, WM_SETFONT, + (WPARAM)hf, 0); + +#if 0 + if(d->nc->types[i]->flags & KHUI_NCT_FLAG_DISABLED) + SendMessage(d->nc->types[i]->hwnd_tc, + BM_SETIMAGE, + IMAGE_ICON, + LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_DISABLED))); + else + SendMessage(d->nc->types[i]->hwnd_tc, + BM_SETIMAGE, + IMAGE_ICON, + LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_ENABLED))); +#endif + + id++; + x += width; + + if(!(d->nc->types[i]->name)) + PFREE(name); + + /* Now set the position of the type panel */ + ShowWindow(d->nc->types[i]->hwnd_panel, SW_HIDE); + SetWindowPos(d->nc->types[i]->hwnd_panel, + NULL, + d->r_main.left, + d->r_main.top, + d->r_main.right - d->r_main.left, + d->r_main.bottom - d->r_main.top, + SWP_DEFERERASE | SWP_NOACTIVATE | + SWP_NOOWNERZORDER | SWP_NOREDRAW | + SWP_NOZORDER); + + } + } + + khui_cw_unlock_nc(d->nc); + + nc_update_credtext(d); + + ShowWindow(hwnd, SW_SHOW); + SetFocus(hwnd); + + if (d->nc->n_identities == 0) + break; + /* else */ + /* fallthrough */ + } + + case WMNC_IDENTITY_CHANGE: + { + BOOL okEnable = FALSE; + + nc_notify_types(d->nc, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), 0); + + if (d->nc->subtype == KMSG_CRED_NEW_CREDS && + d->nc->n_identities > 0 && + d->nc->identities[0]) { + khm_int32 f = 0; + + kcdb_identity_get_flags(d->nc->identities[0], &f); + + if (!(f & KCDB_IDENT_FLAG_DEFAULT)) { + d->nc->set_default = FALSE; + } + } + + nc_update_credtext(d); + + } + break; + + case WMNC_TYPE_STATE: + /* fallthrough */ + case WMNC_UPDATE_CREDTEXT: + nc_update_credtext(d); + break; + + case WMNC_CLEAR_PROMPTS: + { + khm_size i; + + khui_cw_lock_nc(d->nc); + + if(d->hwnd_banner != NULL) { + DestroyWindow(d->hwnd_banner); + d->hwnd_banner = NULL; + } + + if(d->hwnd_name != NULL) { + DestroyWindow(d->hwnd_name); + d->hwnd_name = NULL; + } + + for(i=0;i<d->nc->n_prompts;i++) { + if(!(d->nc->prompts[i]->flags & + KHUI_NCPROMPT_FLAG_STOCK)) { + if(d->nc->prompts[i]->hwnd_static != NULL) + DestroyWindow(d->nc->prompts[i]->hwnd_static); + + if(d->nc->prompts[i]->hwnd_edit != NULL) + DestroyWindow(d->nc->prompts[i]->hwnd_edit); + } + + d->nc->prompts[i]->hwnd_static = NULL; + d->nc->prompts[i]->hwnd_edit = NULL; + } + + khui_cw_unlock_nc(d->nc); + + d->r_credtext.top = d->r_idspec.bottom; + + nc_position_credtext(d); + } + break; + + case WMNC_SET_PROMPTS: + { + khm_size i; + int y; + HWND hw, hw_prev; + HFONT hf, hfold; + HDC hdc; + + /* we assume that WMNC_CLEAR_PROMPTS has already been + received */ + + khui_cw_lock_nc(d->nc); + +#if 0 + /* special case, we have one prompt and it is a password + prompt. very common */ + if(d->nc->n_prompts == 1 && + d->nc->prompts[0]->type == KHUI_NCPROMPT_TYPE_PASSWORD) { + + hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD); + EnableWindow(hw, TRUE); + + d->nc->prompts[0]->flags |= KHUI_NCPROMPT_FLAG_STOCK; + d->nc->prompts[0]->hwnd_edit = hw; + d->nc->prompts[0]->hwnd_static = NULL; /* don't care */ + + khui_cw_unlock_nc(d->nc); + break; + } +#endif + /* for everything else */ + + /* hide the stock password controls */ +#if 0 + /* TAGREMOVE */ + hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD); + ShowWindow(hw, SW_HIDE); + hw = GetDlgItem(d->dlg_main, IDC_NC_PASSWORD_LABEL); + ShowWindow(hw, SW_HIDE); +#endif + + y = d->r_idspec.bottom; + + hf = (HFONT) SendMessage(d->dlg_main, WM_GETFONT, 0, 0); + + if (d->nc->pname != NULL) { + hw = + CreateWindowEx + (0, + L"STATIC", + d->nc->pname, + SS_SUNKEN | WS_CHILD, + d->r_area.left, y, + d->r_row.right, + d->r_n_label.bottom - d->r_n_label.top, + d->dlg_main, + NULL, + khm_hInstance, + NULL); + +#ifdef DEBUG + assert(hw); +#endif + d->hwnd_name = hw; + SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM) TRUE); + ShowWindow(hw, SW_SHOW); + + y += d->r_n_label.bottom - d->r_n_label.top; + } + + if (d->nc->banner != NULL) { + hw = + CreateWindowEx + (0, + L"STATIC", + d->nc->banner, + WS_CHILD, + d->r_area.left, y, + d->r_row.right, d->r_row.bottom, + d->dlg_main, + NULL, + khm_hInstance, + NULL); +#ifdef DEBUG + assert(hw); +#endif + d->hwnd_banner = hw; + SendMessage(hw, WM_SETFONT, (WPARAM)hf, (LPARAM)TRUE); + ShowWindow(hw, SW_SHOW); + y += d->r_row.bottom; + } + + hw_prev = d->hwnd_last_idspec; + + hdc = GetWindowDC(d->dlg_main); + hfold = SelectObject(hdc,hf); + + for(i=0; i<d->nc->n_prompts; i++) { + RECT pr, er; + SIZE s; + int dy; + + if(d->nc->prompts[i]->prompt != NULL) { + GetTextExtentPoint32(hdc, + d->nc->prompts[i]->prompt, + (int) wcslen(d->nc->prompts[i]->prompt), + &s); + if(s.cx < d->r_n_label.right - d->r_n_label.left) { + CopyRect(&pr, &d->r_n_label); + CopyRect(&er, &d->r_n_input); + dy = d->r_row.bottom; + } else if(s.cx < + d->r_e_label.right - d->r_e_label.left) { + CopyRect(&pr, &d->r_e_label); + CopyRect(&er, &d->r_e_input); + dy = d->r_row.bottom; + } else { + /* oops. the prompt doesn't fit in our + controls. we need to use up two lines */ + pr.left = 0; + pr.right = d->r_row.right; + pr.top = 0; + pr.bottom = d->r_n_label.bottom - + d->r_n_label.top; + CopyRect(&er, &d->r_n_input); + OffsetRect(&er, 0, pr.bottom); + dy = er.bottom + (d->r_row.bottom - + d->r_n_input.bottom); + } + } else { + SetRectEmpty(&pr); + CopyRect(&er, &d->r_n_input); + dy = d->r_row.bottom; + } + + if(IsRectEmpty(&pr)) { + d->nc->prompts[i]->hwnd_static = NULL; + } else { + OffsetRect(&pr, d->r_area.left, y); + + hw = CreateWindowEx + (0, + L"STATIC", + d->nc->prompts[i]->prompt, + WS_CHILD, + pr.left, pr.top, + pr.right - pr.left, pr.bottom - pr.top, + d->dlg_main, + NULL, + khm_hInstance, + NULL); +#ifdef DEBUG + assert(hw); +#endif + + SendMessage(hw, WM_SETFONT, + (WPARAM) hf, (LPARAM) TRUE); + + SetWindowPos(hw, hw_prev, + 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | + SWP_NOOWNERZORDER | SWP_NOSIZE | + SWP_SHOWWINDOW); + + d->nc->prompts[i]->hwnd_static = hw; + hw_prev = hw; + } + + OffsetRect(&er, d->r_area.left, y); + + hw = CreateWindowEx + (0, + L"EDIT", + (d->nc->prompts[i]->def ? + d->nc->prompts[i]->def : L""), + WS_CHILD | WS_TABSTOP | + WS_BORDER | + ((d->nc->prompts[i]->flags & + KHUI_NCPROMPT_FLAG_HIDDEN)? ES_PASSWORD:0), + er.left, er.top, + er.right - er.left, er.bottom - er.top, + d->dlg_main, + NULL, + khm_hInstance, + NULL); + +#ifdef DEBUG + assert(hw); +#endif + + SendMessage(hw, WM_SETFONT, + (WPARAM) hf, (LPARAM) TRUE); + + SetWindowPos(hw, hw_prev, + 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | + SWP_NOOWNERZORDER | SWP_NOSIZE | + SWP_SHOWWINDOW); + + SendMessage(hw, EM_SETLIMITTEXT, + KHUI_MAXCCH_PROMPT_VALUE -1, + 0); + + d->nc->prompts[i]->hwnd_edit = hw; + + hw_prev = hw; + + y += dy; + } + + SelectObject(hdc, hfold); + ReleaseDC(d->dlg_main, hdc); + + khui_cw_unlock_nc(d->nc); + + d->r_credtext.top = y; + + nc_position_credtext(d); + } + break; + + case WMNC_DIALOG_PROCESS_COMPLETE: + { + khui_new_creds * nc; + + nc = d->nc; + + if(nc->response & KHUI_NC_RESPONSE_NOEXIT) { + HWND hw; + + /* reset state */ + nc->result = KHUI_NC_RESULT_CANCEL; + + hw = GetDlgItem(d->dlg_main, IDOK); + EnableWindow(hw, TRUE); + hw = GetDlgItem(d->dlg_main, IDCANCEL); + EnableWindow(hw, TRUE); + hw = GetDlgItem(d->dlg_bb, IDOK); + EnableWindow(hw, TRUE); + hw = GetDlgItem(d->dlg_bb, IDCANCEL); + EnableWindow(hw, TRUE); + + return TRUE; + } + + DestroyWindow(hwnd); + + kmq_post_message(KMSG_CRED, KMSG_CRED_END, 0, (void *) nc); + } + break; + + /* MUST be called with SendMessage */ + case WMNC_ADD_CONTROL_ROW: + { + khui_control_row * row; + + row = (khui_control_row *) lParam; + +#ifdef DEBUG + assert(row->label); + assert(row->input); +#endif + + nc_add_control_row(d, row->label, row->input, row->size); + } + break; + } /* switch(HIWORD(wParam)) */ + + return TRUE; +} + +static LRESULT nc_handle_wm_help(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + static DWORD ctxids[] = { + NC_TS_CTRL_ID_MIN, IDH_NC_TABMAIN, + NC_TS_CTRL_ID_MIN + 1, IDH_NC_TABBUTTON, + NC_TS_CTRL_ID_MIN + 2, IDH_NC_TABBUTTON, + NC_TS_CTRL_ID_MIN + 3, IDH_NC_TABBUTTON, + NC_TS_CTRL_ID_MIN + 4, IDH_NC_TABBUTTON, + NC_TS_CTRL_ID_MIN + 5, IDH_NC_TABBUTTON, + NC_TS_CTRL_ID_MIN + 6, IDH_NC_TABBUTTON, + NC_TS_CTRL_ID_MIN + 7, IDH_NC_TABBUTTON, + IDOK, IDH_NC_OK, + IDCANCEL, IDH_NC_CANCEL, + IDC_NC_HELP, IDH_NC_HELP, + IDC_NC_OPTIONS, IDH_NC_OPTIONS, + IDC_NC_CREDTEXT, IDH_NC_CREDWND, + 0 + }; + + HELPINFO * hlp; + HWND hw = NULL; + HWND hw_ctrl; + khui_nc_wnd_data * d; + + d = (khui_nc_wnd_data *)(LONG_PTR) GetWindowLongPtr(hwnd, CW_PARAM); + + hlp = (HELPINFO *) lParam; + + if (d->nc->subtype != KMSG_CRED_NEW_CREDS && + d->nc->subtype != KMSG_CRED_PASSWORD) + return TRUE; + + if (hlp->iContextType != HELPINFO_WINDOW) + return TRUE; + + if (hlp->hItemHandle != NULL && + hlp->hItemHandle != hwnd) { + DWORD id; + int i; + + hw_ctrl =hlp->hItemHandle; + + id = GetWindowLong(hw_ctrl, GWL_ID); + for (i=0; ctxids[i] != 0; i += 2) + if (ctxids[i] == id) + break; + + if (ctxids[i] != 0) + hw = khm_html_help(hw_ctrl, + ((d->nc->subtype == KMSG_CRED_NEW_CREDS)? + L"::popups_newcreds.txt": + L"::popups_password.txt"), + HH_TP_HELP_WM_HELP, + (DWORD_PTR) ctxids); + } + + if (hw == NULL) { + khm_html_help(hwnd, NULL, HH_HELP_CONTEXT, + ((d->nc->subtype == KMSG_CRED_NEW_CREDS)? + IDH_ACTION_NEW_ID: IDH_ACTION_PASSWD_ID)); + } + + return TRUE; +} + +static LRESULT CALLBACK nc_window_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_CREATE: + return nc_handle_wm_create(hwnd, uMsg, wParam, lParam); + + case WM_DESTROY: + return nc_handle_wm_destroy(hwnd, uMsg, wParam, lParam); + + case WM_COMMAND: + return nc_handle_wm_command(hwnd, uMsg, wParam, lParam); + + case WM_MOVE: + case WM_MOVING: + return nc_handle_wm_moving(hwnd, uMsg, wParam, lParam); + + case WM_HELP: + return nc_handle_wm_help(hwnd, uMsg, wParam, lParam); + + case KHUI_WM_NC_NOTIFY: + return nc_handle_wm_nc_notify(hwnd, uMsg, wParam, lParam); + } + + /* Note that this is technically a dialog box */ + return DefDlgProc(hwnd, uMsg, wParam, lParam); +} + +void khm_register_newcredwnd_class(void) +{ + WNDCLASSEX wcx; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS | CS_OWNDC; + wcx.lpfnWndProc = nc_window_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); + wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wcx.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_NEWCREDWND_CLASS; + wcx.hIconSm = NULL; + + khui_newcredwnd_cls = RegisterClassEx(&wcx); +} + +void khm_unregister_newcredwnd_class(void) +{ + UnregisterClass((LPWSTR) khui_newcredwnd_cls, khm_hInstance); +} + +HWND khm_create_newcredwnd(HWND parent, khui_new_creds * c) +{ + wchar_t wtitle[256]; + HWND hwnd; + + if (c->window_title == NULL) { + if (c->subtype == KMSG_CRED_PASSWORD) + LoadString(khm_hInstance, + IDS_WT_PASSWORD, + wtitle, + ARRAYLENGTH(wtitle)); + else + LoadString(khm_hInstance, + IDS_WT_NEW_CREDS, + wtitle, + ARRAYLENGTH(wtitle)); + } + + hwnd = CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP, + MAKEINTATOM(khui_newcredwnd_cls), + ((c->window_title)?c->window_title: wtitle), + WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN, + 0,0,400,400, /* bogus values. the window + is going to resize and + reposition itself + anyway */ + parent, + NULL, + khm_hInstance, + (LPVOID) c); + +#ifdef DEBUG + assert(hwnd != NULL); +#endif + + /* note that the window is not visible yet. That's because, at + this point we don't know what the panels are */ + + return hwnd; +} + +void khm_prep_newcredwnd(HWND hwnd) +{ + SendMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_SETUP), 0); +} + +void khm_show_newcredwnd(HWND hwnd) +{ + /* add all the panels in and prep UI */ + SendMessage(hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_ACTIVATE), 0); +} diff --git a/mechglue/src/windows/identity/ui/newcredwnd.h b/mechglue/src/windows/identity/ui/newcredwnd.h new file mode 100644 index 000000000..7813e1c19 --- /dev/null +++ b/mechglue/src/windows/identity/ui/newcredwnd.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_NEWCREDWND_H +#define __KHIMAIRA_NEWCREDWND_H + +#include<khuidefs.h> + +#define KHUI_NEWCREDWND_CLASS L"KhmNewCredWnd" + +typedef struct khui_nc_wnd_data_t { + khui_new_creds * nc; + + HWND dlg_main; /* main dialog */ + RECT r_main; + HWND dlg_bb; /* button bar */ + RECT r_bb; + HWND dlg_ts; /* tab strip */ + RECT r_ts; + + khm_size ctab; /* current tab */ + + HWND hwnd_tc_main; /* tab control button for main dialog */ + + HWND hwnd_banner; /* static control for banner */ + HWND hwnd_name; /* static control for name */ + + HWND hwnd_last_idspec; /* last identity specifier control */ + + /* metrics for custom prompts and identity specifiers */ + + RECT r_idspec; /* Area used by identity specifiers + (relative to client) */ + RECT r_row; /* Metrics for a control row + (top=0,left=0,right=width, + bottom=height) */ + RECT r_area; /* Area available for controls (relative + to client) */ + RECT r_n_label; /* coords of the static control (relative + to row) */ + RECT r_n_input; /* coords of the edit control (relative to + row) */ + RECT r_e_label; /* coords of the extended edit control + (relative to row) */ + RECT r_e_input; /* coords of the extended edit control + (relative to row) */ + RECT r_credtext; /* Area for credtext window (relative to + row) */ +} khui_nc_wnd_data; + +void khm_register_newcredwnd_class(void); +void khm_unregister_newcredwnd_class(void); +HWND khm_create_newcredwnd(HWND parent, khui_new_creds * c); +void khm_prep_newcredwnd(HWND hwnd); +void khm_show_newcredwnd(HWND hwnd); + +/* This is the first control ID that is created in the custom tabstrip + control buttons. Subsequent buttons get consecutive IDs starting + from this one. */ +#define NC_TS_CTRL_ID_MIN 8001 + +/* Maximum number of controls */ +#define NC_TS_MAX_CTRLS 8 + +/* Maximum control ID */ +#define NC_TS_CTRL_ID_MAX (NC_TS_CTRL_ID_MIN + NC_TS_MAX_CTRLS - 1) + +#define NC_BN_SET_DEF_ID 8012 + +/* the first control ID that may be used by an identity provider */ +#define NC_IS_CTRL_ID_MIN 8016 + +/* the maximum number of controls that may be created by an identity + provider*/ +#define NC_IS_CTRL_MAX_CTRLS 8 + +/* the maximum control ID that may be used by an identity provider */ +#define NC_IS_CTRL_ID_MAX (NC_IS_CTRL_ID_MIN + NC_IS_MAX_CTRLS - 1) + +#endif diff --git a/mechglue/src/windows/identity/ui/notifier.c b/mechglue/src/windows/identity/ui/notifier.c new file mode 100644 index 000000000..b7ac46262 --- /dev/null +++ b/mechglue/src/windows/identity/ui/notifier.c @@ -0,0 +1,1234 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#define OEMRESOURCE + +#include<khmapp.h> +#include<assert.h> + +#define KHUI_NOTIFIER_CLASS L"KhuiNotifierMsgWindowClass" +#define KHUI_ALERTER_CLASS L"KhuiAlerterWindowClass" + +#define KHUI_NOTIFIER_WINDOW L"KhuiNotifierMsgWindow" + +/* notifier message for notification icon */ +#define KHUI_WM_NOTIFIER WM_COMMAND + +#define KHUI_ALERT_QUEUE_MAX 64 + +/* window class registration atom for message only notifier window + class */ +ATOM atom_notifier = 0; + +/* window class registration atom for alert windows */ +ATOM atom_alerter = 0; + +/* notifier message window */ +HWND hwnd_notifier = NULL; + +BOOL notifier_ready = FALSE; + +khui_alert * current_alert = NULL; + +khui_alert * alert_queue[KHUI_ALERT_QUEUE_MAX]; +khm_int32 alert_queue_head = 0; +khm_int32 alert_queue_tail = 0; + +int iid_normal = IDI_NOTIFY_NONE; + +#define is_alert_queue_empty() (alert_queue_head == alert_queue_tail) +#define is_alert_queue_full() (((alert_queue_tail + 1) % KHUI_ALERT_QUEUE_MAX) == alert_queue_head) + +static void +add_to_alert_queue(khui_alert * a) { + if (is_alert_queue_full()) return; + alert_queue[alert_queue_tail++] = a; + khui_alert_hold(a); + alert_queue_tail %= KHUI_ALERT_QUEUE_MAX; +} + +static khui_alert * +del_from_alert_queue(void) { + khui_alert * a; + + if (is_alert_queue_empty()) return NULL; + a = alert_queue[alert_queue_head++]; + alert_queue_head %= KHUI_ALERT_QUEUE_MAX; + + return a; /* held */ +} + +static khui_alert * +peek_alert_queue(void) { + if (is_alert_queue_empty()) return NULL; + return alert_queue[alert_queue_head]; +} + +static void +check_for_queued_alerts(void) { + if (!is_alert_queue_empty()) { + khui_alert * a; + + a = peek_alert_queue(); + + if (a->title) { + HICON hi; + int res; + + if (a->severity == KHERR_ERROR) + res = OIC_ERROR; + else if (a->severity == KHERR_WARNING) + res = OIC_WARNING; + else + res = OIC_INFORMATION; + + hi = LoadImage(0, MAKEINTRESOURCE(res), + IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + LR_SHARED); + + khm_statusbar_set_part(KHUI_SBPART_NOTICE, + hi, + a->title); + } + } else { + khm_statusbar_set_part(KHUI_SBPART_NOTICE, + NULL, NULL); + } +} + + +/* forward dcls */ +static khm_int32 +alert_show(khui_alert * a); + +static khm_int32 +alert_show_minimized(khui_alert * a); + +static khm_int32 +alert_show_normal(khui_alert * a); + +static khm_int32 +alert_enqueue(khui_alert * a); + +/********************************************************************** + Notifier +*********************************************************************** + +The notifier is a message only window that listens for notifier +messages. This window will exist for the lifetime of the application +and will use alerter windows as needed to show application alerts. +*/ + +static LRESULT CALLBACK +notifier_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + kmq_message * m; + khm_int32 rv; + + if(uMsg == KMQ_WM_DISPATCH) { + kmq_wm_begin(lParam, &m); + rv = KHM_ERROR_SUCCESS; + + if(m->type == KMSG_ALERT) { + /* handle notifier messages */ + switch(m->subtype) { + case KMSG_ALERT_SHOW: + rv = alert_show((khui_alert *) m->vparam); + khui_alert_release((khui_alert *) m->vparam); + break; + + case KMSG_ALERT_QUEUE: + rv = alert_enqueue((khui_alert *) m->vparam); + khui_alert_release((khui_alert *) m->vparam); + break; + + case KMSG_ALERT_CHECK_QUEUE: + check_for_queued_alerts(); + break; + + case KMSG_ALERT_SHOW_QUEUED: + if (current_alert == NULL) { + khui_alert * a; + + a = del_from_alert_queue(); + if (a) { + rv = alert_show(a); + check_for_queued_alerts(); + khui_alert_release(a); + } + } + break; + } + } else if (m->type == KMSG_CRED && + m->subtype == KMSG_CRED_ROOTDELTA) { + + KillTimer(hwnd, KHUI_REFRESH_TIMER_ID); + SetTimer(hwnd, KHUI_REFRESH_TIMER_ID, + KHUI_REFRESH_TIMEOUT, + NULL); + + } + + return kmq_wm_end(m, rv); + } else if (uMsg == KHUI_WM_NOTIFIER) { + /* Handle events generated from the notification icon */ + + /* wParam is the identifier of the notify icon, but we only + have one. */ + switch(lParam) { + case WM_CONTEXTMENU: + { + POINT pt; + int menu_id; + + GetCursorPos(&pt); + + if (khm_is_main_window_visible()) + menu_id = KHUI_MENU_ICO_CTX_NORMAL; + else + menu_id = KHUI_MENU_ICO_CTX_MIN; + + SetForegroundWindow(khm_hwnd_main); + + khm_menu_show_panel(menu_id, pt.x, pt.y); + + PostMessage(khm_hwnd_main, WM_NULL, 0, 0); + } + break; + + case WM_LBUTTONDOWN: + /* we actually wait for the WM_LBUTTONUP before doing + anything */ + break; + + case WM_LBUTTONUP: + /* fall through */ + case NIN_SELECT: + /* fall through */ + case NIN_KEYSELECT: + khm_show_main_window(); + break; + +#if (_WIN32_IE >= 0x0501) + case NIN_BALLOONUSERCLICK: + if (current_alert) { + if ((current_alert->flags & KHUI_ALERT_FLAG_DEFACTION) && + current_alert->n_alert_commands > 0) { + PostMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(current_alert->alert_commands[0], + 0), + 0); + } else if (current_alert->flags & + KHUI_ALERT_FLAG_REQUEST_WINDOW) { + khm_show_main_window(); + alert_show_normal(current_alert); + } + } + /* fallthrough */ + case NIN_BALLOONTIMEOUT: + khm_notify_icon_change(KHERR_NONE); + if (current_alert) { + khui_alert_release(current_alert); + current_alert = NULL; + } + break; +#endif + } + } else if (uMsg == WM_TIMER) { + if (wParam == KHUI_TRIGGER_TIMER_ID) { + KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID); + khm_timer_fire(hwnd); + } else if (wParam == KHUI_REFRESH_TIMER_ID) { + KillTimer(hwnd, KHUI_REFRESH_TIMER_ID); + khm_timer_refresh(hwnd); + } + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +ATOM +khm_register_notifier_wnd_class(void) +{ + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.style = 0; + wcx.lpfnWndProc = notifier_wnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = NULL; + wcx.hbrBackground = NULL; + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_NOTIFIER_CLASS; + wcx.hIconSm = NULL; + + atom_notifier = RegisterClassEx(&wcx); + + return atom_notifier; +} + +/********************************************************************* + Alerter +**********************************************************************/ + +typedef struct tag_alerter_wnd_data { + khui_alert * alert; + + HWND hwnd; + HFONT hfont; + + BOOL metrics_done; + + HWND hwnd_buttons[KHUI_MAX_ALERT_COMMANDS]; + + /* various metrics */ + + /* calculated during WM_CREATE and adjusted during WM_PAINT */ + int dy_message; + int dy_suggestion; + + /* calculated during WM_CREATE */ + int dx_button; + int dy_button; + int dx_button_incr; + int dx_margin; + int dy_margin; + int dy_bb; + int x_message; + int dx_message; + int dx_icon; + int dy_icon; + int dx_suggest_pad; + + /* calculated during WM_CREATE and adjusted during WM_PAINT */ + int dx_client; + int dy_client; + + /* calculated during WM_PAINT */ + int y_message; + int y_suggestion; + + LDCL(struct tag_alerter_wnd_data); +} alerter_wnd_data; + +alerter_wnd_data * khui_alerts = NULL; + +#define NTF_PARAM DWLP_USER + +/* dialog sizes in base dialog units */ + +#define NTF_MARGIN 5 +#define NTF_WIDTH 200 + +#define NTF_BB_HEIGHT 15 + +#define NTF_ICON_X NTF_MARGIN +#define NTF_ICON_WIDTH 20 +#define NTF_ICON_HEIGHT 20 + +#define NTF_MSG_X (NTF_ICON_X + NTF_ICON_WIDTH + NTF_MARGIN) +#define NTF_MSG_WIDTH ((NTF_WIDTH - NTF_MARGIN) - NTF_MSG_X) +#define NTF_MSG_HEIGHT 15 + +#define NTF_SUG_X NTF_MSG_X +#define NTF_SUG_WIDTH NTF_MSG_WIDTH +#define NTF_SUG_HEIGHT NTF_MSG_HEIGHT +#define NTF_SUG_PAD 2 + +#define NTF_BUTTON_X NTF_MSG_X + +#define NTF_BUTTON_WIDTH ((NTF_MSG_WIDTH - 3*NTF_MARGIN) / 4) +#define NTF_BUTTON_XINCR (NTF_BUTTON_WIDTH + NTF_MARGIN) +#define NTF_BUTTON_HEIGHT (NTF_BB_HEIGHT - NTF_MARGIN) + +#define NTF_TIMEOUT 20000 + +static khm_int32 +alert_show_minimized(khui_alert * a) { + wchar_t tbuf[64]; + wchar_t mbuf[256]; + + if (a->message == NULL) + return KHM_ERROR_SUCCESS; + + if (a->title == NULL) { + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + tbuf, ARRAYLENGTH(tbuf)); + } else { + StringCbCopy(tbuf, sizeof(tbuf), a->title); + } + + if (FAILED(StringCbCopy(mbuf, sizeof(mbuf), a->message)) || + (!(a->flags & KHUI_ALERT_FLAG_DEFACTION) && + (a->n_alert_commands > 0 || + a->suggestion || + (a->flags & KHUI_ALERT_FLAG_VALID_ERROR)))) { + /* if mbuf wasn't big enough, this should have copied a + truncated version of it */ + size_t cch_m, cch_p; + wchar_t postfix[256]; + + cch_p = LoadString(khm_hInstance, IDS_ALERT_MOREINFO, postfix, + ARRAYLENGTH(postfix)); + cch_p++; /* account for NULL */ + + StringCchLength(mbuf, ARRAYLENGTH(mbuf), &cch_m); + cch_m = min(cch_m, ARRAYLENGTH(mbuf) - cch_p); + + StringCchCopy(mbuf + cch_m, ARRAYLENGTH(mbuf) - cch_m, + postfix); + + a->flags |= KHUI_ALERT_FLAG_REQUEST_WINDOW; + } + + a->flags |= KHUI_ALERT_FLAG_DISPLAY_BALLOON; + +#if (_WIN32_IE >= 0x0501) + current_alert = a; + khui_alert_hold(a); +#endif + + khm_notify_icon_balloon(a->severity, + tbuf, + mbuf, + NTF_TIMEOUT); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +alert_show_normal(khui_alert * a) { + HWND hwa; + wchar_t buf[256]; + wchar_t * title; + + if(a->title == NULL) { + LoadString(khm_hInstance, IDS_ALERT_DEFAULT, + buf, ARRAYLENGTH(buf)); + title = buf; + } else + title = a->title; + + /* if we don't have any commands, we just add a "close" button */ + if (a->n_alert_commands == 0) { + khui_alert_add_command(a, KHUI_PACTION_CLOSE); + } + + if (!is_alert_queue_empty()) { + khui_alert_add_command(a, KHUI_PACTION_NEXT); + } + + /* we don't need to keep track of the window handle + because the window procedure adds it to the dialog + list automatically */ + + hwa = + CreateWindowEx(WS_EX_DLGMODALFRAME | WS_EX_CONTEXTHELP, + MAKEINTATOM(atom_alerter), + title, + WS_DLGFRAME | WS_POPUPWINDOW | WS_CLIPCHILDREN | + WS_VISIBLE, + 0, 0, 300, 300, // bogus values + khm_hwnd_main, + (HMENU) NULL, + khm_hInstance, + (LPVOID) a); + + return KHM_ERROR_SUCCESS; +} + +static khm_int32 +alert_show(khui_alert * a) { + /* is there an alert already? If so, we just enqueue the message + and let it sit. */ + if (current_alert) { + return alert_enqueue(a); + } + + /* the window has already been shown */ + if((a->flags & KHUI_ALERT_FLAG_DISPLAY_WINDOW) || + ((a->flags & KHUI_ALERT_FLAG_DISPLAY_BALLOON) && + !(a->flags & KHUI_ALERT_FLAG_REQUEST_WINDOW))) + return KHM_ERROR_SUCCESS; + + if(a->err_context != NULL || + a->err_event != NULL) { + khui_alert_lock(a); + a->flags |= KHUI_ALERT_FLAG_VALID_ERROR; + khui_alert_unlock(a); + } + + /* depending on the state of the main window, we + need to either show a window or a balloon */ + if(khm_is_main_window_active() && + !(a->flags & KHUI_ALERT_FLAG_REQUEST_BALLOON)) + return alert_show_normal(a); + else + return alert_show_minimized(a); +} + +static khm_int32 +alert_enqueue(khui_alert * a) { + if (is_alert_queue_full()) + return KHM_ERROR_NO_RESOURCES; + + add_to_alert_queue(a); + check_for_queued_alerts(); + + return KHM_ERROR_SUCCESS; +} + +/* the alerter window is actually a dialog */ +static LRESULT CALLBACK +alerter_wnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) { + case WM_CREATE: + { + LONG dlgb; + HWND hwnd_parent; + RECT r_parent; + POINT pos; + SIZE s; + LPCREATESTRUCT lpcs; + khui_alert * a; + alerter_wnd_data * d; + + lpcs = (LPCREATESTRUCT) lParam; + a = (khui_alert *) lpcs->lpCreateParams; + khui_alert_hold(a); + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->alert = a; + d->hwnd = hwnd; + + khui_alert_lock(a); + + a->flags |= KHUI_ALERT_FLAG_DISPLAY_WINDOW; + LPUSH(&khui_alerts, d); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd, NTF_PARAM, (LONG_PTR) d); +#pragma warning(pop) + + khm_add_dialog(hwnd); + khm_enter_modal(hwnd); + + /* now figure out the size and position of the window */ + + hwnd_parent = GetWindow(hwnd, GW_OWNER); + GetWindowRect(hwnd_parent, &r_parent); + + dlgb = GetDialogBaseUnits(); + +#define DLG2SCNX(x) MulDiv((x), LOWORD(dlgb), 4) +#define DLG2SCNY(y) MulDiv((y), HIWORD(dlgb), 8) + + d->dx_margin = DLG2SCNX(NTF_MARGIN); + d->dy_margin = DLG2SCNY(NTF_MARGIN); + + d->x_message = DLG2SCNX(NTF_MSG_X); + d->dx_message = DLG2SCNX(NTF_MSG_WIDTH); + + if (a->message) { + d->dy_message = DLG2SCNY(NTF_MSG_HEIGHT); + } + + if (a->suggestion) { + d->dy_suggestion = DLG2SCNY(NTF_SUG_HEIGHT); + d->dx_suggest_pad = DLG2SCNX(NTF_SUG_PAD); + } + + d->dy_bb = DLG2SCNY(NTF_BB_HEIGHT); + d->dx_button = DLG2SCNX(NTF_BUTTON_WIDTH); + d->dy_button = DLG2SCNY(NTF_BUTTON_HEIGHT); + d->dx_button_incr = DLG2SCNX(NTF_BUTTON_XINCR); + + d->dx_icon = DLG2SCNX(NTF_ICON_WIDTH); + d->dy_icon = DLG2SCNY(NTF_ICON_HEIGHT); + + d->dx_client = DLG2SCNX(NTF_WIDTH); + d->dy_client = max(d->dy_icon, + d->dy_message + + ((d->dy_suggestion > 0)? + (d->dy_suggestion + d->dy_margin): + 0)) + + d->dy_margin * 3 + d->dy_bb; + + /* adjust for client rect */ + s.cx = d->dx_client; + s.cy = d->dy_client; + + { + RECT c_r; + RECT w_r; + + GetWindowRect(hwnd, &w_r); + GetClientRect(hwnd, &c_r); + + s.cx += (w_r.right - w_r.left) - (c_r.right - c_r.left); + s.cy += (w_r.bottom - w_r.top) - (c_r.bottom - c_r.top); + } + + pos.x = (r_parent.left + r_parent.right - s.cx) / 2; + pos.y = (r_parent.top + r_parent.bottom - s.cy) / 2; + + SetWindowPos(hwnd, + HWND_TOP, + pos.x, pos.y, + s.cx, s.cy, + SWP_SHOWWINDOW); + + { + LOGFONT lf; + HDC hdc_dt; + + hdc_dt = GetDC(NULL); + + lf.lfHeight = -MulDiv(8, + GetDeviceCaps(hdc_dt, LOGPIXELSY), + 72); + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + lf.lfWeight = FW_NORMAL; + lf.lfItalic = FALSE; + lf.lfUnderline = FALSE; + lf.lfStrikeOut = FALSE; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH; + + LoadString(khm_hInstance, IDS_DEFAULT_FONT, + lf.lfFaceName, ARRAYLENGTH(lf.lfFaceName)); + + d->hfont = CreateFontIndirect(&lf); + + ReleaseDC(NULL, hdc_dt); + } + + /* create dialog controls now */ + { + int x,y; + int width, height; + int i; + + x = d->x_message; + y = d->dy_client - d->dy_bb; + width = d->dx_button; + height = d->dy_button; + + for(i=0; i<a->n_alert_commands; i++) { + wchar_t caption[256]; + khui_action * action; + HWND hw_button; + + if(a->alert_commands[i] == 0) + continue; + + action = khui_find_action(a->alert_commands[i]); + if(action == NULL) + continue; + + LoadString(khm_hInstance, action->is_caption, + caption, ARRAYLENGTH(caption)); + + hw_button = + CreateWindowEx(0, + L"BUTTON", + caption, + WS_VISIBLE | WS_CHILD, + x,y,width,height, + hwnd, + (HMENU)(INT_PTR) (action->cmd), + khm_hInstance, + NULL); + + SendMessage(hw_button, WM_SETFONT, + (WPARAM) d->hfont, MAKELPARAM(TRUE, 0)); + + d->hwnd_buttons[i] = hw_button; + + x += d->dx_button_incr; + } + } + + khm_notify_icon_change(a->severity); + + khui_alert_unlock(a); + + d->metrics_done = FALSE; + + return TRUE; + } + break; /* not reached */ + + case WM_DESTROY: + { + alerter_wnd_data * d; + + /* khm_leave_modal() could be here, but instead it is in + the WM_COMMAND handler. This is because the modal loop + has to be exited before DestroyWindow() is issued. */ + //khm_leave_modal(); + khm_del_dialog(hwnd); + + d = (alerter_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, NTF_PARAM); + + LDELETE(&khui_alerts, d); + + khui_alert_lock(d->alert); + d->alert->flags &= ~KHUI_ALERT_FLAG_DISPLAY_WINDOW; + khui_alert_unlock(d->alert); + + khui_alert_release(d->alert); + + DeleteObject(d->hfont); + + PFREE(d); + + khm_notify_icon_change(KHERR_NONE); + + return TRUE; + } + break; + + case WM_PAINT: + { + RECT r_update; + PAINTSTRUCT ps; + HDC hdc; + LONG dlgb; + alerter_wnd_data * d; + HFONT hf_old; + BOOL need_resize = FALSE; + + if(!GetUpdateRect(hwnd, &r_update, TRUE)) + return FALSE; + + d = (alerter_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, NTF_PARAM); + + dlgb = GetDialogBaseUnits(); + + hdc = BeginPaint(hwnd, &ps); + + hf_old = SelectFont(hdc, d->hfont); + + khui_alert_lock(d->alert); + + // draw the severity icon + { + HICON hicon; + int x,y; + int iid; + + /* GOINGHERE! If the metrics for the window haven't + been calculated yet, then calculate them. If the + hight needs to be expanded, then do that and wait + for the next repaint cycle. Also move the button + controls down. */ + x = d->dx_margin; + y = d->dy_margin; + + if(d->alert->severity == KHERR_ERROR) + iid = OIC_HAND; + else if(d->alert->severity == KHERR_WARNING) + iid = OIC_BANG; + else + iid = OIC_NOTE; + + hicon = LoadImage(NULL, + MAKEINTRESOURCE(iid), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + LR_SHARED); + + DrawIcon(hdc, x, y, hicon); + } + + // draw the message + if(d->alert->message) { + RECT r; + int width; + int height; + size_t cch; + + r.left = d->x_message; + r.top = d->dy_margin; + width = d->dx_message; + r.right = r.left + width; + height = d->dy_message; + r.bottom = r.top + height; + + StringCchLength(d->alert->message, + KHUI_MAXCCH_MESSAGE, &cch); + + height = DrawText(hdc, + d->alert->message, + (int) cch, + &r, + DT_WORDBREAK | + DT_CALCRECT); + + if (height > d->dy_message) { + d->dy_message = height; + need_resize = TRUE; + } else { + DrawText(hdc, + d->alert->message, + (int) cch, + &r, + DT_WORDBREAK); + } + + d->y_message = r.top; + } + + // and the suggestion + if (d->alert->suggestion) { + RECT r, ro; + int height; + size_t cch; + HICON h_sug_ico; + + r.left = d->x_message; + r.top = d->y_message + d->dy_message + d->dy_margin; + r.right = r.left + d->dx_message; + r.bottom = r.top + d->dy_suggestion; + + CopyRect(&ro, &r); + + // adjust for icon and padding + r.left += GetSystemMetrics(SM_CXSMICON) + d->dx_suggest_pad * 2; + r.top += d->dx_suggest_pad; + r.right -= d->dx_suggest_pad; + r.bottom -= d->dx_suggest_pad; + + StringCchLength(d->alert->suggestion, + KHUI_MAXCCH_SUGGESTION, &cch); + + height = DrawText(hdc, + d->alert->suggestion, + (int) cch, + &r, + DT_WORDBREAK | + DT_CALCRECT); + + if (height > d->dy_suggestion) { + d->dy_suggestion = height; + need_resize = TRUE; + } else { + int old_bk_mode; + + ro.bottom = r.bottom + d->dx_suggest_pad; + + FillRect(hdc, &ro, (HBRUSH) (COLOR_INFOBK + 1)); + DrawEdge(hdc, &ro, EDGE_SUNKEN, BF_FLAT | BF_RECT); + + h_sug_ico = + LoadImage(0, + MAKEINTRESOURCE(OIC_INFORMATION), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + LR_SHARED); + + assert(h_sug_ico != NULL); + + DrawIconEx(hdc, + ro.left + d->dx_suggest_pad, + ro.top + d->dx_suggest_pad, + h_sug_ico, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + 0, NULL, + DI_NORMAL); + + old_bk_mode = SetBkMode(hdc, TRANSPARENT); + + DrawText(hdc, + d->alert->suggestion, + (int) cch, + &r, + DT_WORDBREAK); + + SetBkMode(hdc, old_bk_mode); + } + + d->y_suggestion = r.top; + } + + khui_alert_unlock(d->alert); + + SelectObject(hdc, hf_old); + + EndPaint(hwnd, &ps); + + if (need_resize) { + RECT r; + int x,y; + int width, height; + int i; + + GetClientRect(hwnd, &r); + + height = max(d->dy_icon, + d->dy_message + + ((d->dy_suggestion > 0)? + (d->dy_suggestion + d->dy_margin): + 0)) + + d->dy_margin * 3 + d->dy_bb; + r.bottom = r.top + height; + + d->dy_client = height; + + AdjustWindowRectEx(&r, + GetWindowLongPtr(hwnd, GWL_STYLE), + FALSE, + GetWindowLongPtr(hwnd, GWL_EXSTYLE)); + + SetWindowPos(hwnd, + NULL, + 0, 0, + r.right - r.left, + r.bottom - r.top, + SWP_NOACTIVATE | SWP_NOCOPYBITS | + SWP_NOMOVE | SWP_NOOWNERZORDER | + SWP_NOZORDER); + + x = d->x_message; + y = d->dy_client - d->dy_bb; + width = d->dx_button; + height = d->dy_button; + + for(i=0; i<d->alert->n_alert_commands; i++) { + MoveWindow(d->hwnd_buttons[i], + x,y, + width,height, + TRUE); + + x += d->dx_button_incr; + } + } + + return FALSE; + } + break; /* not reached */ + + case WM_COMMAND: + { + alerter_wnd_data * d; + + d = (alerter_wnd_data *)(LONG_PTR) + GetWindowLongPtr(hwnd, NTF_PARAM); + + if(HIWORD(wParam) == BN_CLICKED) { + khui_alert_lock(d->alert); + d->alert->response = LOWORD(wParam); + khui_alert_unlock(d->alert); + + khm_leave_modal(); + + DestroyWindow(hwnd); + + if (LOWORD(wParam) == KHUI_PACTION_NEXT) + kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW_QUEUED, 0, 0); + return 0; + } + } + break; + } + + return DefDlgProc(hwnd, uMsg, wParam, lParam); + //return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +ATOM khm_register_alerter_wnd_class(void) +{ + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.style = + CS_OWNDC | +#if(_WIN32_WINNT >= 0x0501) + ((IS_COMMCTL6())? CS_DROPSHADOW: 0) | +#endif + 0; + wcx.lpfnWndProc = alerter_wnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(IDI_MAIN_APP)); + wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); + wcx.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_ALERTER_CLASS; + wcx.hIconSm = NULL; + + atom_alerter = RegisterClassEx(&wcx); + + return atom_alerter; +} + +/********************************************************************** + Notification Icon +***********************************************************************/ + +#define KHUI_NOTIFY_ICON_ID 0 + +void khm_notify_icon_add(void) { + NOTIFYICONDATA ni; + wchar_t buf[256]; + + ZeroMemory(&ni, sizeof(ni)); + + ni.cbSize = sizeof(ni); + ni.hWnd = hwnd_notifier; + ni.uID = KHUI_NOTIFY_ICON_ID; + ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid_normal)); + ni.uCallbackMessage = KHUI_WM_NOTIFIER; + LoadString(khm_hInstance, IDS_NOTIFY_PREFIX, buf, ARRAYLENGTH(buf)); + StringCbCopy(ni.szTip, sizeof(ni.szTip), buf); + LoadString(khm_hInstance, IDS_NOTIFY_READY, buf, ARRAYLENGTH(buf)); + StringCbCat(ni.szTip, sizeof(ni.szTip), buf); + + Shell_NotifyIcon(NIM_ADD, &ni); + + ni.cbSize = sizeof(ni); + ni.uVersion = NOTIFYICON_VERSION; + Shell_NotifyIcon(NIM_SETVERSION, &ni); + + DestroyIcon(ni.hIcon); +} + +void +khm_notify_icon_balloon(khm_int32 severity, + wchar_t * title, + wchar_t * msg, + khm_int32 timeout) { + NOTIFYICONDATA ni; + int iid; + + if (!msg || !title) + return; + + ZeroMemory(&ni, sizeof(ni)); + ni.cbSize = sizeof(ni); + + if (severity == KHERR_INFO) { + ni.dwInfoFlags = NIIF_INFO; + iid = IDI_NOTIFY_INFO; + } else if (severity == KHERR_WARNING) { + ni.dwInfoFlags = NIIF_WARNING; + iid = IDI_NOTIFY_WARN; + } else if (severity == KHERR_ERROR) { + ni.dwInfoFlags = NIIF_ERROR; + iid = IDI_NOTIFY_ERROR; + } else { + ni.dwInfoFlags = NIIF_NONE; + iid = iid_normal; + } + + ni.hWnd = hwnd_notifier; + ni.uID = KHUI_NOTIFY_ICON_ID; + ni.uFlags = NIF_INFO | NIF_ICON; + ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid)); + + if (FAILED(StringCbCopy(ni.szInfo, sizeof(ni.szInfo), msg))) { + /* too long? */ + StringCchCopyN(ni.szInfo, ARRAYLENGTH(ni.szInfo), + msg, + ARRAYLENGTH(ni.szInfo) - ARRAYLENGTH(ELIPSIS)); + StringCchCat(ni.szInfo, ARRAYLENGTH(ni.szInfo), + ELIPSIS); + } + + if (FAILED(StringCbCopy(ni.szInfoTitle, sizeof(ni.szInfoTitle), + title))) { + StringCchCopyN(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle), + title, + ARRAYLENGTH(ni.szInfoTitle) - ARRAYLENGTH(ELIPSIS)); + StringCchCat(ni.szInfoTitle, ARRAYLENGTH(ni.szInfoTitle), + ELIPSIS); + } + ni.uTimeout = timeout; + + Shell_NotifyIcon(NIM_MODIFY, &ni); + + DestroyIcon(ni.hIcon); +} + +void khm_notify_icon_expstate(enum khm_notif_expstate expseverity) { + int new_iid; + + if (expseverity == KHM_NOTIF_OK) + new_iid = IDI_APPICON_OK; + else if (expseverity == KHM_NOTIF_WARN) + new_iid = IDI_APPICON_WARN; + else if (expseverity == KHM_NOTIF_EXP) + new_iid = IDI_APPICON_EXP; + else + new_iid = IDI_NOTIFY_NONE; + + if (iid_normal == new_iid) + return; + + iid_normal = new_iid; + + if (current_alert == NULL) + khm_notify_icon_change(KHERR_NONE); +} + +void khm_notify_icon_change(khm_int32 severity) { + NOTIFYICONDATA ni; + wchar_t buf[256]; + int iid; + + if (severity == KHERR_INFO) + iid = IDI_NOTIFY_INFO; + else if (severity == KHERR_WARNING) + iid = IDI_NOTIFY_WARN; + else if (severity == KHERR_ERROR) + iid = IDI_NOTIFY_ERROR; + else + iid = iid_normal; + + ZeroMemory(&ni, sizeof(ni)); + + ni.cbSize = sizeof(ni); + ni.hWnd = hwnd_notifier; + ni.uID = KHUI_NOTIFY_ICON_ID; + ni.uFlags = NIF_ICON | NIF_TIP; + ni.hIcon = LoadIcon(khm_hInstance, MAKEINTRESOURCE(iid)); + LoadString(khm_hInstance, IDS_NOTIFY_PREFIX, buf, ARRAYLENGTH(buf)); + StringCbCopy(ni.szTip, sizeof(ni.szTip), buf); + if(severity == KHERR_NONE) + LoadString(khm_hInstance, IDS_NOTIFY_READY, buf, ARRAYLENGTH(buf)); + else + LoadString(khm_hInstance, IDS_NOTIFY_ATTENTION, buf, ARRAYLENGTH(buf)); + StringCbCat(ni.szTip, sizeof(ni.szTip), buf); + + Shell_NotifyIcon(NIM_MODIFY, &ni); + + DestroyIcon(ni.hIcon); +} + +void khm_notify_icon_remove(void) { + NOTIFYICONDATA ni; + + ZeroMemory(&ni, sizeof(ni)); + + ni.cbSize = sizeof(ni); + ni.hWnd = hwnd_notifier; + ni.uID = KHUI_NOTIFY_ICON_ID; + + Shell_NotifyIcon(NIM_DELETE, &ni); +} + +/********************************************************************* + Initialization +**********************************************************************/ + +void khm_init_notifier(void) +{ + if(!khm_register_notifier_wnd_class()) + return; + + if(!khm_register_alerter_wnd_class()) + return; + + hwnd_notifier = CreateWindowEx(0, + MAKEINTATOM(atom_notifier), + KHUI_NOTIFIER_WINDOW, + 0, + 0,0,0,0, + HWND_MESSAGE, + NULL, + khm_hInstance, + NULL); + + if(hwnd_notifier != NULL) { + kmq_subscribe_hwnd(KMSG_ALERT, hwnd_notifier); + kmq_subscribe_hwnd(KMSG_CRED, hwnd_notifier); + notifier_ready = TRUE; + + khm_notify_icon_add(); + } +#ifdef DEBUG + else { + assert(hwnd_notifier != NULL); + } +#endif + khm_timer_init(); + + khm_addr_change_notifier_init(); +} + +void khm_exit_notifier(void) +{ + khm_addr_change_notifier_exit(); + + khm_timer_exit(); + + if(hwnd_notifier != NULL) { + khm_notify_icon_remove(); + kmq_unsubscribe_hwnd(KMSG_ALERT, hwnd_notifier); + kmq_unsubscribe_hwnd(KMSG_CRED, hwnd_notifier); + DestroyWindow(hwnd_notifier); + hwnd_notifier = NULL; + } + + if(atom_notifier != 0) { + UnregisterClass(MAKEINTATOM(atom_notifier), khm_hInstance); + atom_notifier = 0; + } + + if(atom_alerter != 0) { + UnregisterClass(MAKEINTATOM(atom_alerter), khm_hInstance); + atom_alerter = 0; + } + + notifier_ready = FALSE; +} diff --git a/mechglue/src/windows/identity/ui/notifier.h b/mechglue/src/windows/identity/ui/notifier.h new file mode 100644 index 000000000..140d02c44 --- /dev/null +++ b/mechglue/src/windows/identity/ui/notifier.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_NOTIFIER_H +#define __KHIMAIRA_NOTIFIER_H + +extern HWND hwnd_notifier; + +enum khm_notif_expstate { + KHM_NOTIF_EMPTY, + KHM_NOTIF_OK, + KHM_NOTIF_WARN, + KHM_NOTIF_EXP +}; + +void +khm_init_notifier(void); + +void +khm_exit_notifier(void); + +void +khm_notify_icon_change(khm_int32 severity); + +void +khm_notify_icon_balloon(khm_int32 severity, + wchar_t * title, + wchar_t * msg, + khm_int32 timeout); + +void +khm_notify_icon_expstate(enum khm_notif_expstate expseverity); + +#endif diff --git a/mechglue/src/windows/identity/ui/passwnd.c b/mechglue/src/windows/identity/ui/passwnd.c new file mode 100644 index 000000000..4084ede41 --- /dev/null +++ b/mechglue/src/windows/identity/ui/passwnd.c @@ -0,0 +1,133 @@ +#include<khmapp.h> + +static ATOM sAtom = 0; +static HINSTANCE shInstance = 0; + +/* Callback for the MITPasswordControl +This is a replacement for the normal edit control. It does not show the +annoying password char in the edit box so that the number of chars in the +password are not known. +*/ + +#define PASSWORDCHAR L'#' +#define DLGHT(ht) (HIWORD(GetDialogBaseUnits())*(ht)/8) +#define DLGWD(wd) (LOWORD(GetDialogBaseUnits())*(wd)/4) + +static +LRESULT +CALLBACK +MITPasswordEditProc( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ) +{ + static SIZE pwdcharsz; + BOOL pass_the_buck = FALSE; + + if (message > WM_USER && message < 0x7FFF) + pass_the_buck = TRUE; + + switch(message) + { + case WM_GETTEXT: + case WM_GETTEXTLENGTH: + case WM_SETTEXT: + pass_the_buck = TRUE; + break; + case WM_PAINT: + { + HDC hdc; + PAINTSTRUCT ps; + RECT r; + + hdc = BeginPaint(hWnd, &ps); + GetClientRect(hWnd, &r); + Rectangle(hdc, 0, 0, r.right, r.bottom); + EndPaint(hWnd, &ps); + } + break; + case WM_SIZE: + { + MoveWindow(GetDlgItem(hWnd, 1), DLGWD(2), DLGHT(2), + pwdcharsz.cx / 2, pwdcharsz.cy, TRUE); + } + break; + case WM_LBUTTONDOWN: + case WM_SETFOCUS: + { + SetFocus(GetDlgItem(hWnd, 1)); + } + break; + case WM_CREATE: + { + HWND heditchild; + wchar_t pwdchar = PASSWORDCHAR; + HDC hdc; + /* Create a child window of this control for default processing. */ + hdc = GetDC(hWnd); + GetTextExtentPoint32(hdc, &pwdchar, 1, &pwdcharsz); + ReleaseDC(hWnd, hdc); + + heditchild = + CreateWindow(L"edit", L"", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | + ES_LEFT | ES_PASSWORD | WS_TABSTOP, + 0, 0, 0, 0, + hWnd, + (HMENU)1, + ((LPCREATESTRUCT)lParam)->hInstance, + NULL); + SendMessage(heditchild, EM_SETPASSWORDCHAR, PASSWORDCHAR, 0L); + } + break; + } + + if (pass_the_buck) + return SendMessage(GetDlgItem(hWnd, 1), message, wParam, lParam); + return DefWindowProc(hWnd, message, wParam, lParam); +} + +khm_int32 +khm_register_passwnd_class(void) +{ + if (!sAtom) { + WNDCLASS wndclass; + + memset(&wndclass, 0, sizeof(WNDCLASS)); + + shInstance = khm_hInstance; + + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = (WNDPROC)MITPasswordEditProc; + wndclass.cbClsExtra = sizeof(HWND); + wndclass.cbWndExtra = 0; + wndclass.hInstance = shInstance; + wndclass.hbrBackground = (void *)(COLOR_WINDOW + 1); + wndclass.lpszClassName = MIT_PWD_DLL_CLASS; + wndclass.hCursor = LoadCursor((HINSTANCE)NULL, IDC_IBEAM); + + sAtom = RegisterClass(&wndclass); + } + + return (sAtom)?KHM_ERROR_SUCCESS:KHM_ERROR_UNKNOWN; +} + +khm_int32 +khm_unregister_passwnd_class(void) +{ + BOOL result = TRUE; + + if ((khm_hInstance != shInstance) || !sAtom) { + return KHM_ERROR_INVALID_OPERATION; + } + + result = UnregisterClass(MIT_PWD_DLL_CLASS, khm_hInstance); + if (result) { + sAtom = 0; + shInstance = 0; + return KHM_ERROR_SUCCESS; + } else { + return KHM_ERROR_UNKNOWN; + } +} diff --git a/mechglue/src/windows/identity/ui/passwnd.h b/mechglue/src/windows/identity/ui/passwnd.h new file mode 100644 index 000000000..b0adcf689 --- /dev/null +++ b/mechglue/src/windows/identity/ui/passwnd.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_PASSWND_H +#define __KHIMAIRA_PASSWND_H + +/* Declarations for the MIT password change control. Functionally the + same as the regular Windows password edit control but doesn't + display the '*' password character. */ + +#define MIT_PWD_DLL_CLASS L"MITPasswordWnd" + +khm_int32 khm_unregister_passwnd_class(void); +khm_int32 khm_register_passwnd_class(void); + +#endif diff --git a/mechglue/src/windows/identity/ui/propertywnd.c b/mechglue/src/windows/identity/ui/propertywnd.c new file mode 100644 index 000000000..79a6cc35a --- /dev/null +++ b/mechglue/src/windows/identity/ui/propertywnd.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +typedef struct tag_pw_data { + khm_handle record; + HWND hwnd_lv; +} pw_data; + +ATOM khui_propertywnd_cls; + +#define ID_LISTVIEW 1 + +#define PW_WM_SET_RECORD WM_USER + +void pw_update_property_data(HWND hw, pw_data * d) +{ + HWND hwnd_lv; + khm_int32 * attrs = NULL; + + hwnd_lv = d->hwnd_lv; + + if(hwnd_lv == NULL) + return; + + ListView_DeleteAllItems(hwnd_lv); + + if(d->record != NULL) { + wchar_t * buffer; + khm_size attr_count; + khm_size i; + khm_size cb_buf; + khm_size t; + LVITEM lvi; + int idx; + + if(KHM_FAILED(kcdb_attrib_get_count( + KCDB_ATTR_FLAG_VOLATILE | + KCDB_ATTR_FLAG_HIDDEN, + 0, + &attr_count))) + return; + + attrs = PMALLOC(sizeof(khm_int32) * attr_count); + assert(attrs != NULL); + + kcdb_attrib_get_ids( + KCDB_ATTR_FLAG_VOLATILE | + KCDB_ATTR_FLAG_HIDDEN, + 0, + attrs, + &attr_count); + + cb_buf = sizeof(wchar_t) * 2048; + buffer = PMALLOC(cb_buf); + assert(buffer != NULL); + + for(i=0; i<attr_count; i++) { + if(KHM_FAILED(kcdb_buf_get_attr(d->record, attrs[i], NULL, NULL, NULL))) + continue; + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_TEXT | LVIF_PARAM; + lvi.iItem = (int) i; + lvi.iSubItem = 0; + lvi.pszText = buffer; + lvi.lParam = (LPARAM) attrs[i]; + + t = cb_buf; + kcdb_attrib_describe(attrs[i], buffer, &t, KCDB_TS_SHORT); + + idx = ListView_InsertItem(hwnd_lv, &lvi); + + ZeroMemory(&lvi, sizeof(lvi)); + lvi.mask = LVIF_TEXT; + lvi.iItem = idx; + lvi.iSubItem = 1; + lvi.pszText = buffer; + + t = cb_buf; + kcdb_buf_get_attr_string(d->record, attrs[i], buffer, &t, 0); + + ListView_SetItem(hwnd_lv, &lvi); + } + + PFREE(attrs); + PFREE(buffer); + } +} + +LRESULT CALLBACK khui_property_wnd_proc( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam) +{ + BOOL child_msg = FALSE; + pw_data * child; + + switch(msg) { + case WM_CREATE: + { + CREATESTRUCT * cs; + LVCOLUMN lvc; + wchar_t sz_title[256]; + + cs = (CREATESTRUCT *) lParam; + + child = PMALLOC(sizeof(*child)); + ZeroMemory(child, sizeof(*child)); + +#pragma warning(push) +#pragma warning(disable:4244) + SetWindowLongPtr(hwnd, 0, (LONG_PTR) child); +#pragma warning(pop) + + child->hwnd_lv = CreateWindow( + WC_LISTVIEW, + L"", + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | + LVS_REPORT | LVS_SORTASCENDING, + 0, 0, + cs->cx, cs->cy, + hwnd, + (HMENU) ID_LISTVIEW, + khm_hInstance, + NULL); + + ListView_SetExtendedListViewStyle(child->hwnd_lv, + LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); + + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_TEXT | LVCF_WIDTH; + lvc.fmt = LVCFMT_LEFT; + lvc.cx = (cs->cx * 2)/ 5; + lvc.pszText = sz_title; + lvc.iSubItem = 0; + lvc.iOrder = 0; + LoadString(khm_hInstance, IDS_PROP_COL_PROPERTY, sz_title, ARRAYLENGTH(sz_title)); + + ListView_InsertColumn(child->hwnd_lv, 0, &lvc); + + ZeroMemory(&lvc, sizeof(lvc)); + lvc.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; + lvc.fmt = LVCFMT_LEFT; + lvc.cx = (cs->cx * 3)/ 5; + lvc.pszText = sz_title; + lvc.iSubItem = 1; + lvc.iOrder = 1; + LoadString(khm_hInstance, IDS_PROP_COL_VALUE, sz_title, ARRAYLENGTH(sz_title)); + + ListView_InsertColumn(child->hwnd_lv, 1, &lvc); + + if(cs->lpCreateParams != NULL) { + child->record = cs->lpCreateParams; + kcdb_buf_hold(child->record); + pw_update_property_data(hwnd, child); + } + } + break; + + case PW_WM_SET_RECORD: + { + child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + kcdb_buf_release(child->record); + child->record = (khm_handle) lParam; + kcdb_buf_hold(child->record); + pw_update_property_data(hwnd, child); + } + return 0; + + case WM_DESTROY: + { + child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + kcdb_buf_release(child->record); + PFREE(child); + } + break; + + case WM_PAINT: + break; + + default: + child = (pw_data *)(LONG_PTR) GetWindowLongPtr(hwnd, 0); + child_msg = TRUE; + } + + /* + if(child_msg && child && child->hwnd_lv) + return SendMessage(child->hwnd_lv, msg, wParam, lParam); + else + */ + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +khm_int32 khm_register_propertywnd_class(void) +{ + WNDCLASSEX wcx; + + wcx.cbSize = sizeof(wcx); + wcx.style = CS_DBLCLKS; + wcx.lpfnWndProc = khui_property_wnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = sizeof(LONG_PTR); + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = LoadCursor((HINSTANCE) NULL, IDC_ARROW); + wcx.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_PROPERTYWND_CLASS_NAME; + wcx.hIconSm = NULL; + + khui_propertywnd_cls = RegisterClassEx(&wcx); + + return (khui_propertywnd_cls == 0)?KHM_ERROR_UNKNOWN:KHM_ERROR_SUCCESS; +} + +khm_int32 khm_unregister_propertywnd_class(void) +{ + UnregisterClass(MAKEINTATOM(khui_propertywnd_cls), khm_hInstance); + + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/ui/propertywnd.h b/mechglue/src/windows/identity/ui/propertywnd.h new file mode 100644 index 000000000..89305dd7b --- /dev/null +++ b/mechglue/src/windows/identity/ui/propertywnd.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_PROPERTYWND_H +#define __KHIMAIRA_PROPERTYWND_H + +#define KHUI_PROPERTYWND_CLASS_NAME L"NetIDMgrPropertyWnd" + +khm_int32 khm_register_propertywnd_class(void); + +khm_int32 khm_unregister_propertywnd_class(void); + +#endif diff --git a/mechglue/src/windows/identity/ui/reqdaemon.c b/mechglue/src/windows/identity/ui/reqdaemon.c new file mode 100644 index 000000000..04056566d --- /dev/null +++ b/mechglue/src/windows/identity/ui/reqdaemon.c @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +ATOM reqdaemon_atom = 0; +HANDLE reqdaemon_thread = NULL; +HWND reqdaemon_hwnd = NULL; + +LRESULT CALLBACK +reqdaemonwnd_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) { + + switch(uMsg) { + case WM_CREATE: + break; + + case WM_CLOSE: + DestroyWindow(hwnd); + break; + + case WM_DESTROY: + reqdaemon_hwnd = NULL; + PostQuitMessage(0); + break; + + /* Leash compatibility */ + case ID_OBTAIN_TGT_WITH_LPARAM: + { + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wmapping[ARRAYLENGTH(KHUI_REQD_MAPPING_FORMAT) + 10]; + khm_handle identity = NULL; + LPNETID_DLGINFO pdlginfo; + LRESULT lr = 1; + khm_int32 result; + HANDLE hmap = NULL; + HRESULT hr; + + hr = StringCbPrintf(wmapping, sizeof(wmapping), + KHUI_REQD_MAPPING_FORMAT, (DWORD) lParam); +#ifdef DEBUG + assert(SUCCEEDED(hr)); +#endif + hmap = CreateFileMapping(INVALID_HANDLE_VALUE, + NULL, + PAGE_READWRITE, + 0, 4096, + wmapping); + + if (hmap == NULL) { + return -1; + } else if (hmap != NULL && GetLastError() != ERROR_ALREADY_EXISTS) { + CloseHandle(hmap); + return -1; + } + + pdlginfo = MapViewOfFile(hmap, + FILE_MAP_WRITE, + 0, 0, + sizeof(*pdlginfo)); + + if (pdlginfo == NULL) { + CloseHandle(hmap); + return 1; + } + + if (pdlginfo->in.username[0] && + pdlginfo->in.realm[0] && + SUCCEEDED(StringCbPrintf(widname, + sizeof(widname), + L"%s@%s", + pdlginfo->in.username, + pdlginfo->in.realm))) { + + kcdb_identity_create(widname, + KCDB_IDENT_FLAG_CREATE, + &identity); + } + + widname[0] = 0; + + do { + if (khm_cred_is_in_dialog()) { + khm_cred_wait_for_dialog(INFINITE, NULL, NULL, 0); + } + + if (identity) + khui_context_set_ex(KHUI_SCOPE_IDENT, + identity, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + NULL, + pdlginfo, + sizeof(*pdlginfo)); + else + khui_context_reset(); + + if (pdlginfo->dlgtype == NETID_DLGTYPE_TGT) + SendMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_NEW_CRED, 0), 0); + else if (pdlginfo->dlgtype == NETID_DLGTYPE_CHPASSWD) + SendMessage(khm_hwnd_main, WM_COMMAND, + MAKEWPARAM(KHUI_ACTION_PASSWD_ID, 0), 0); + else + break; + + if (KHM_FAILED(khm_cred_wait_for_dialog(INFINITE, &result, + widname, + sizeof(widname)))) + continue; + else { + lr = (result != KHUI_NC_RESULT_GET_CREDS); + break; + } + } while(TRUE); + +#ifdef DEBUG + assert(lr || pdlginfo->dlgtype != NETID_DLGTYPE_TGT || + widname[0]); +#endif + + if (!lr && pdlginfo->dlgtype == NETID_DLGTYPE_TGT && + widname[0]) { + khm_handle out_ident; + wchar_t * atsign; + + atsign = wcsrchr(widname, L'@'); + + if (atsign == NULL) + goto _exit; + + if (KHM_SUCCEEDED(kcdb_identity_create(widname, + 0, + &out_ident))) { + khm_size cb; + + pdlginfo->out.ccache[0] = 0; + + cb = sizeof(pdlginfo->out.ccache); + kcdb_identity_get_attrib(out_ident, + L"Krb5CCName", + NULL, + pdlginfo->out.ccache, + &cb); + kcdb_identity_release(out_ident); + } +#ifdef DEBUG + else { + assert(FALSE); + } +#endif + + *atsign++ = 0; + + StringCbCopy(pdlginfo->out.username, + sizeof(pdlginfo->out.username), + widname); + + StringCbCopy(pdlginfo->out.realm, + sizeof(pdlginfo->out.realm), + atsign); + } + + _exit: + + if (pdlginfo) + UnmapViewOfFile(pdlginfo); + if (hmap) + CloseHandle(hmap); + if (identity) + kcdb_identity_release(identity); + + return lr; + } + +#ifdef DEPRECATED_REMOTE_CALL + /* deprecated */ + case ID_OBTAIN_TGT_WITH_LPARAM: + { + char * param = (char *) GlobalLock((HGLOBAL) lParam); + char * username = NULL; + char * realm = NULL; + char * title = NULL; + char * ccache = NULL; + wchar_t widname[KCDB_IDENT_MAXCCH_NAME]; + wchar_t wtitle[KHUI_MAXCCH_TITLE]; + size_t cch; + khm_int32 rv = KHM_ERROR_SUCCESS; + khm_handle identity = NULL; + NETID_DLGINFO dlginfo; + + if (param) { + if (*param) + title = param; + + if (FAILED(StringCchLengthA(param, KHUI_MAXCCH_TITLE, &cch))) { +#ifdef DEBUG + assert(FALSE); +#endif + rv = KHM_ERROR_INVALID_PARAM; + goto _exit_tgt_with_lparam; + } + + param += cch + 1; + + if (*param) + username = param; + + if (FAILED(StringCchLengthA(param, KCDB_IDENT_MAXCCH_NAME, &cch))) { +#ifdef DEBUG + assert(FALSE); +#endif + rv = KHM_ERROR_INVALID_PARAM; + goto _exit_tgt_with_lparam; + } + + param += cch + 1; + + if (*param) + realm = param; + + if (FAILED(StringCchLengthA(param, KCDB_IDENT_MAXCCH_NAME, &cch))) { +#ifdef DEBUG + assert(FALSE); +#endif + rv = KHM_ERROR_INVALID_PARAM; + goto _exit_tgt_with_lparam; + } + + param += cch + 1; + + if (*param) + ccache = param; + } + + if (username && realm) { + + if (FAILED(StringCbPrintf(widname, sizeof(widname), + L"%hs@%hs", username, realm))) { + rv = KHM_ERROR_INVALID_PARAM; + goto _exit_tgt_with_lparam; + } + + rv = kcdb_identity_create(widname, + KCDB_IDENT_FLAG_CREATE, + &identity); + if (KHM_FAILED(rv)) { + goto _exit_tgt_with_lparam; + } + } + + ZeroMemory(&dlginfo, sizeof(dlginfo)); + + dlginfo.size = NETID_DLGINFO_V1_SZ; + dlginfo.dlgtype = NETID_DLGTYPE_TGT; + + if (title) + StringCbCopy(dlginfo.in.title, sizeof(dlginfo.in.title), + wtitle); + if (username) + AnsiStrToUnicode(dlginfo.in.username, sizeof(dlginfo.in.username), + username); + if (realm) + AnsiStrToUnicode(dlginfo.in.realm, sizeof(dlginfo.in.realm), + realm); + + if (ccache) + AnsiStrToUnicode(dlginfo.in.ccache, sizeof(dlginfo.in.ccache), + ccache); + + dlginfo.in.use_defaults = TRUE; + + do { + if (khm_cred_is_in_dialog()) { + khm_cred_wait_for_dialog(INFINITE); + } + + khui_context_set_ex(KHUI_SCOPE_IDENT, + identity, + KCDB_CREDTYPE_INVALID, + NULL, + NULL, + 0, + NULL, + &dlginfo, + sizeof(dlginfo)); + + if (title) { + AnsiStrToUnicode(wtitle, sizeof(wtitle), + title); + + khm_cred_obtain_new_creds(wtitle); + } else { + khm_cred_obtain_new_creds(NULL); + } + + if (KHM_FAILED(khm_cred_wait_for_dialog(INFINITE))) + continue; + else + break; + } while(TRUE); + + _exit_tgt_with_lparam: + if (identity) + kcdb_identity_release(identity); + + GlobalUnlock((HGLOBAL) lParam); + } + return 0; +#endif + + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +DWORD WINAPI +khm_reqdaemon_thread_proc(LPVOID vparam) { + BOOL rv; + MSG msg; +#ifdef DEBUG + DWORD dw; +#endif + + khm_register_reqdaemonwnd_class(); + +#ifdef DEBUG + assert(reqdaemon_atom != 0); +#endif + + reqdaemon_hwnd = CreateWindowEx(0, + MAKEINTATOM(reqdaemon_atom), + KHUI_REQDAEMONWND_NAME, + 0, + 0,0,0,0, + HWND_MESSAGE, + NULL, + khm_hInstance, + NULL); + +#ifdef DEBUG + dw = GetLastError(); + assert(reqdaemon_hwnd != NULL); +#endif + + while(rv = GetMessage(&msg, NULL, 0, 0)) { + if (rv == -1) { +#ifdef DEBUG + assert(FALSE); +#endif + break; + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + reqdaemon_thread = NULL; + + khm_unregister_reqdaemonwnd_class(); + + return 0; +} + +void +khm_register_reqdaemonwnd_class(void) { + WNDCLASSEX wcx; + + ZeroMemory(&wcx, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.style = 0; + wcx.lpfnWndProc = reqdaemonwnd_proc; + wcx.cbClsExtra = 0; + wcx.cbWndExtra = 0; + wcx.hInstance = khm_hInstance; + wcx.hIcon = NULL; + wcx.hCursor = NULL; + wcx.hbrBackground = NULL; + wcx.lpszMenuName = NULL; + wcx.lpszClassName = KHUI_REQDAEMONWND_CLASS; + wcx.hIconSm = NULL; + + reqdaemon_atom = RegisterClassEx(&wcx); + +#ifdef DEBUG + assert(reqdaemon_atom != 0); +#endif +} + +void +khm_unregister_reqdaemonwnd_class(void) { + if (reqdaemon_atom != 0) { + UnregisterClass(MAKEINTATOM(reqdaemon_atom), khm_hInstance); + reqdaemon_atom = 0; + } +} + +void +khm_init_request_daemon(void) { +#ifdef DEBUG + assert(reqdaemon_thread == NULL); +#endif + + reqdaemon_thread = CreateThread(NULL, + 0, + khm_reqdaemon_thread_proc, + NULL, + 0, + NULL); + +#ifdef DEBUG + assert(reqdaemon_thread != NULL); +#endif +} + +void +khm_exit_request_daemon(void) { + if (reqdaemon_hwnd == NULL) + return; + + SendMessage(reqdaemon_hwnd, WM_CLOSE, 0, 0); +} diff --git a/mechglue/src/windows/identity/ui/reqdaemon.h b/mechglue/src/windows/identity/ui/reqdaemon.h new file mode 100644 index 000000000..b55e93c99 --- /dev/null +++ b/mechglue/src/windows/identity/ui/reqdaemon.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_REQDAEMON_H +#define __KHIMAIRA_REQDAEMON_H + +void +khm_register_reqdaemonwnd_class(void); + +void +khm_unregister_reqdaemonwnd_class(void); + +void +khm_init_request_daemon(void); + +void +khm_exit_request_daemon(void); + +#endif diff --git a/mechglue/src/windows/identity/ui/resource.h b/mechglue/src/windows/identity/ui/resource.h new file mode 100644 index 000000000..b8060c6a0 --- /dev/null +++ b/mechglue/src/windows/identity/ui/resource.h @@ -0,0 +1,332 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\work\pismere\athena\auth\krb5\src\windows\identity\ui\lang\en_us\khapp.rc +// +#define IDI_MAIN_APP 104 +#define IDD_PROPPAGE_MEDIUM 106 +#define IDD_PP_CRED 106 +#define IDD_PP_IDENT 107 +#define IDB_TK_REFRESH 108 +#define IDS_MAIN_WINDOW_TITLE 108 +#define IDS_MENU_FILE 109 +#define IDB_ID 110 +#define IDS_MENU_IDENTITY 110 +#define IDS_MENU_CRED 110 +#define IDB_ID_DELETE 111 +#define IDS_MENU_VIEW 111 +#define IDB_ID_NEW 112 +#define IDS_MENU_OPTIONS 112 +#define IDB_ID_REFRESH 113 +#define IDS_MENU_HELP 113 +#define IDB_TK 114 +#define IDS_ACTION_PROPERTIES 114 +#define IDB_TK_DELETE 115 +#define IDS_ACTION_EXIT 115 +#define IDB_TK_NEW 116 +#define IDS_ACTION_NEW_ID 116 +#define IDS_CFG_ROOT_NAME 116 +#define IDS_ACTION_SET_DEF_ID 117 +#define IDS_ACTION_SET_SRCH_ID 118 +#define IDB_VW_REFRESH_SM 118 +#define IDS_ACTION_DESTROY_ID 119 +#define IDR_MENU_BAR 119 +#define IDS_CFG_ROOT_TITLE 119 +#define IDS_ACTION_RENEW_ID 120 +#define IDS_CFG_GENERAL_SHORT 120 +#define IDS_ACTION_ADD_CRED 121 +#define IDB_TB_BLANK 121 +#define IDS_ACTION_NEW_CRED 121 +#define IDS_ACTION_PASSWD_ID 122 +#define IDS_ACTION_CHOOSE_COLS 123 +#define IDB_TB_BLANK_SM 123 +#define IDS_ACTION_DEBUG_WINDOW 124 +#define IDB_VW_REFRESH 124 +#define IDS_ACTION_VIEW_REFRESH 125 +#define IDB_ID_DELETE_DIS 125 +#define IDS_MENU_LAYOUT 126 +#define IDB_ID_DELETE_DIS_SM 126 +#define IDS_MENU_TOOLBARS 127 +#define IDB_ID_DELETE_SM 127 +#define IDS_ACTION_LAYOUT_ID 128 +#define IDB_ID_DIS 128 +#define IDS_ACTION_LAYOUT_TYPE 129 +#define IDB_ID_DIS_SM 129 +#define IDS_ACTION_LAYOUT_LOC 130 +#define IDB_ID_NEW_DIS 130 +#define IDS_ACTION_TB_STANDARD 131 +#define IDB_ID_NEW_DIS_SM 131 +#define IDS_ACTION_OPT_KHIM 132 +#define IDB_ID_NEW_SM 132 +#define IDS_ACTION_OPT_INIT 133 +#define IDB_ID_REFRESH_DIS 133 +#define IDS_ACTION_OPT_IDENTS 133 +#define IDS_ACTION_OPT_NOTIF 134 +#define IDB_ID_REFRESH_SM 134 +#define IDS_ACTION_HELP_CTX 135 +#define IDB_ID_REFRESH_DIS_SM 135 +#define IDS_ACTION_HELP_CONTENTS 136 +#define IDB_TK_DELETE_DIS 136 +#define IDS_ACTION_HELP_INDEX 137 +#define IDB_TK_DELETE_DIS_SM 137 +#define IDS_ACTION_HELP_ABOUT 138 +#define IDB_TK_DELETE_SM 138 +#define IDB_TK_DIS_SM 139 +#define IDS_ACTIONINFO_NEW_ID 139 +#define IDS_CFG_GENERAL_LONG 139 +#define IDB_TK_NEW_DIS 140 +#define IDS_SAMPLE_STRING 140 +#define IDB_TK_NEW_DIS_SM 141 +#define IDS_NO_CREDS 141 +#define IDB_TK_NEW_SM 142 +#define IDS_WT_INIT_CREDS 142 +#define IDB_TK_REFRESH_DIS 143 +#define IDS_WT_NEW_CREDS 143 +#define IDB_TK_REFRESH_DIS_SM 144 +#define IDS_NC_PASSWORD 144 +#define IDS_NC_IDENTITY 144 +#define IDB_TK_REFRESH_SM 145 +#define IDS_NC_IDENTS 145 +#define IDB_TK_SM 146 +#define IDS_NC_CREDTEXT_ID_NONE 146 +#define IDB_HELP_SM 147 +#define IDS_NC_CREDTEXT_ID_ONE 147 +#define IDB_HELP 148 +#define IDS_NC_CREDTEXT_ID_MANY 148 +#define IDB_LOGO_SHADE 149 +#define IDS_NC_CREDTEXT_ID_INVALID 149 +#define IDS_WTPOST_INIT_CREDS 150 +#define IDS_WTPOST_NEW_CREDS 151 +#define IDB_WDG_EXPAND 152 +#define IDS_ACTION_RENEW_CRED 152 +#define IDB_WDG_COLLAPSE 153 +#define IDS_ACTION_DESTROY_CRED 153 +#define IDB_ID_SM 154 +#define IDS_DEFAULT_FONT 154 +#define IDB_WDG_EXPAND_HI 155 +#define IDS_NC_CREDTEXT_TABS 155 +#define IDB_WDG_COLLAPSE_HI 156 +#define IDS_NOTIFY_PREFIX 156 +#define IDB_WDG_CREDTYPE 157 +#define IDS_NOTIFY_READY 157 +#define IDB_WDG_FLAG 158 +#define IDS_NOTIFY_ATTENTION 158 +#define IDB_FLAG_WARN 159 +#define IDS_ALERT_DEFAULT 159 +#define IDB_FLAG_EXPIRED 160 +#define IDS_PACTION_OK 160 +#define IDB_FLAG_CRITICAL 161 +#define IDS_PACTION_CANCEL 161 +#define IDD_NC_PASSWORD 162 +#define IDS_PACTION_CLOSE 162 +#define IDD_NC_NEWCRED 162 +#define IDD_NC_BBAR 163 +#define IDS_ALERT_NOSEL_TITLE 163 +#define IDD_NC_TS 164 +#define IDS_ALERT_NOSEL 164 +#define IDI_ENABLED 165 +#define IDS_NC_CREDTEXT_ID_VALID 165 +#define IDI_DISABLED 166 +#define IDS_NC_CREDTEXT_ID_UNCHECKED 166 +#define IDS_PROP_COL_PROPERTY 167 +#define IDS_PROP_COL_VALUE 168 +#define IDI_NOTIFY_NONE 169 +#define IDS_NC_NEW_IDENT 169 +#define IDI_NOTIFY_INFO 170 +#define IDS_NC_CREDTEXT_ID_CHECKING 170 +#define IDI_NOTIFY_WARN 171 +#define IDS_ACTION_OPEN_APP 171 +#define IDI_NOTIFY_ERROR 172 +#define IDS_CTX_NEW_IDENT 172 +#define IDS_CTX_NEW_CREDS 173 +#define IDD_CFG_MAIN 173 +#define IDS_CTX_RENEW_CREDS 174 +#define IDD_CFG_GENERIC 174 +#define IDS_CTX_PROC_NEW_IDENT 175 +#define IDB_LOGO_OPAQUE 175 +#define IDS_CTX_PROC_NEW_CREDS 176 +#define IDD_CFG_GENERAL 176 +#define IDS_CTX_PROC_RENEW_CREDS 177 +#define IDD_CFG_IDENTITIES 177 +#define IDS_ACTION_CLOSE_APP 178 +#define IDD_CFG_NOTIF 178 +#define IDS_NC_FAILED_TITLE 179 +#define IDD_CFG_PLUGINS 179 +#define IDS_CFG_IDENTITIES_SHORT 180 +#define IDD_CFG_IDENTITY 180 +#define IDS_CFG_IDENTITIES_LONG 181 +#define IDI_CFG_DEFAULT 181 +#define IDS_CFG_NOTIF_SHORT 182 +#define IDI_CFG_MODIFIED 182 +#define IDS_CFG_NOTIF_LONG 183 +#define IDI_CFG_APPLIED 183 +#define IDS_CFG_PLUGINS_SHORT 184 +#define IDD_CFG_IDS_TAB 184 +#define IDS_CFG_PLUGINS_LONG 185 +#define IDD_CFG_ID_TAB 185 +#define IDS_CFG_IDENTITY_SHORT 186 +#define IDI_CFG_DELETED 186 +#define IDS_CFG_IDENTITY_LONG 187 +#define IDI_ICON1 187 +#define IDI_ID 187 +#define IDS_CTX_DESTROY_CREDS 188 +#define IDB_IMPORT_SM_DIS 188 +#define IDS_WARN_EXPIRE 189 +#define IDB_IMPORT 189 +#define IDS_WARN_TITLE 190 +#define IDB_IMPORT_DIS 190 +#define IDS_ALERT_MOREINFO 191 +#define IDB_IMPORT_SM 191 +#define IDS_WARN_EXPIRED 192 +#define IDB_CHPW_SM 192 +#define IDS_WARN_EXPIRE_ID 193 +#define IDB_CHPW 193 +#define IDS_WARN_EXPIRED_ID 194 +#define IDB_CHPW_DIS 194 +#define IDS_WARN_WM_TITLE 195 +#define IDB_CHPW_DIS_SM 195 +#define IDS_WARN_WM_MSG 196 +#define IDD_ABOUT 196 +#define IDS_CFG_ID_TAB_SHORT 197 +#define IDB_TB_SPACE 197 +#define IDS_CFG_ID_TAB_LONG 198 +#define IDB_WDG_STUCK_HI 198 +#define IDS_CFG_IDS_TAB_SHORT 199 +#define IDB_WDG_STICK 199 +#define IDS_CFG_IDS_TAB_LONG 200 +#define IDB_WDG_STICK_HI 200 +#define IDS_CFG_IDS_IDENTITY 201 +#define IDB_WDG_STUCK 201 +#define IDS_ACTION_IMPORT 202 +#define IDS_CTX_IMPORT 203 +#define IDB_FLAG_RENEW 203 +#define IDS_CFG_PI_COL_PLUGINS 204 +#define IDI_APPICON_WARN 204 +#define IDS_PISTATE_FAILUNK 205 +#define IDI_APPICON_EXP 205 +#define IDS_PISTATE_FAILMAX 206 +#define IDI_ICON4 206 +#define IDI_APPICON_OK 206 +#define IDS_PISTATE_FAILREG 207 +#define IDS_PISTATE_FAILDIS 208 +#define IDS_PISTATE_FAILLOD 209 +#define IDS_PISTATE_PLACEHOLD 210 +#define IDS_PISTATE_REG 211 +#define IDS_PISTATE_HOLD 212 +#define IDS_PISTATE_INIT 213 +#define IDS_PISTATE_RUN 214 +#define IDS_PISTATE_EXIT 215 +#define IDS_CTX_PASSWORD 216 +#define IDS_WT_PASSWORD 217 +#define IDS_WTPOST_PASSWORD 218 +#define IDS_CTX_PROC_PASSWORD 219 +#define IDS_NC_PWD_FAILED_TITLE 220 +#define IDS_CMDLINE_HELP 221 +#define IDS_PACTION_NEXT 222 +#define IDS_ERR_TITLE_NO_IDENTPRO 223 +#define IDS_ERR_MSG_NO_IDENTPRO 224 +#define IDS_ERR_SUGG_NO_IDENTPRO 225 +#define IDS_NC_REN_FAILED_TITLE 226 +#define IDS_CW_DEFAULT 227 +#define IDS_ACTION_OPT_PLUGINS 228 +#define IDS_NC_SETDEF 229 +#define IDS_NC_ID_DEF 230 +#define IDS_NC_ID_WDEF 231 +#define IDS_NC_ID_NDEF 232 +#define IDC_NC_USERNAME 1007 +#define IDC_NC_PASSWORD 1008 +#define IDC_NC_CREDTEXT_LABEL 1009 +#define IDC_NC_PASSWORD_LABEL 1010 +#define IDC_NC_USERNAME_LABEL 1011 +#define IDC_NC_CREDTEXT 1012 +#define IDC_NC_HELP 1017 +#define IDC_NC_OPTIONS 1019 +#define IDC_PP_IDNAME 1026 +#define IDC_PP_IDDEF 1027 +#define IDC_PP_IDSEARCH 1028 +#define IDC_PP_IDSTATUS 1029 +#define IDC_PP_IDSTATUSIMG 1030 +#define IDC_PP_IDVALID 1031 +#define IDC_PP_IDRENEW 1032 +#define IDC_NC_IDENTITY 1033 +#define IDC_NC_IDENTITY_LABEL 1034 +#define IDC_PP_PROPLIST 1035 +#define IDC_PP_CPROPLIST 1036 +#define IDC_NC_REALM 1037 +#define IDC_NC_REALM_LABEL 1038 +#define IDC_NC_TPL_ROW 1039 +#define IDC_NC_TPL_PANEL 1040 +#define IDC_NC_TPL_LABEL 1041 +#define IDC_NC_TPL_INPUT 1042 +#define IDC_NC_TPL_LABEL_LG 1043 +#define IDC_NC_TPL_INPUT_LG 1044 +#define IDC_NC_TPL_ROW2 1045 +#define IDC_NC_TPL_ROW_LG 1045 +#define IDC_CFG_NODELIST 1045 +#define IDAPPLY 1048 +#define IDC_CFG_SUMMARY 1049 +#define IDC_CFG_TITLE 1050 +#define IDC_CFG_PANE 1051 +#define IDC_NOTIF_MONITOR 1053 +#define IDC_PP_DUMMY 1054 +#define IDC_NOTIF_RENEW 1055 +#define IDC_NOTIF_RENEW_THR 1056 +#define IDC_NOTIF_WARN1 1057 +#define IDC_NOTIF_WARN1_THR 1058 +#define IDC_NOTIF_WARN2 1059 +#define IDC_NOTIF_WARN2_THR 1060 +#define IDC_CFG_KEEPRUNNING 1061 +#define IDC_CFG_STARTUP_GROUP 1062 +#define IDC_CFG_AUTOSTART 1063 +#define IDC_CFG_AUTOIMPORT 1064 +#define IDC_CFG_AUTOINIT 1065 +#define IDC_CFG_OTHER 1066 +#define IDC_CFG_MONITOR 1069 +#define IDC_CFG_STICKY 1070 +#define IDC_CFG_IDENTS 1071 +#define IDC_CFG_IDENTITY 1072 +#define IDC_CFG_RENEW 1075 +#define IDC_CFG_REMOVE 1076 +#define IDC_CFG_TAB 1077 +#define IDC_CFG_TARGET 1078 +#define IDC_CFG_PLUGINS 1079 +#define IDC_CFG_PLUGINGRP 1080 +#define IDC_CFG_LBL_DESC 1083 +#define IDC_CFG_DESC 1084 +#define IDC_CFG_LBL_STATE 1085 +#define IDC_CFG_STATE 1086 +#define IDC_CFG_LBL_DEPS 1087 +#define IDC_CFG_DEPS 1088 +#define IDC_CFG_DISABLE 1089 +#define IDC_CFG_ENABLE 1090 +#define IDC_CFG_PROVGRP 1091 +#define IDC_CFG_LBL_MOD 1092 +#define IDC_CFG_MODULE 1093 +#define IDC_CFG_LBL_VEN 1094 +#define IDC_CFG_VENDOR 1095 +#define IDC_CFG_REGISTER 1097 +#define IDC_CFG_NETDETECT 1098 +#define IDC_PP_STICKY 1099 +#define IDC_PRODUCT 1100 +#define IDC_COPYRIGHT 1101 +#define IDC_BUILDINFO 1102 +#define IDC_LIST1 1103 +#define IDC_MODULES 1103 +#define IDC_PP_CONFIG 1104 +#define IDA_ACTIVATE_MENU 40003 +#define IDA_UP 40004 +#define IDA_DOWN 40005 +#define IDA_LEFT 40006 +#define IDA_RIGHT 40007 +#define IDA_ESC 40008 +#define IDA_ENTER 40009 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 207 +#define _APS_NEXT_COMMAND_VALUE 40010 +#define _APS_NEXT_CONTROL_VALUE 1107 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/mechglue/src/windows/identity/ui/statusbar.c b/mechglue/src/windows/identity/ui/statusbar.c new file mode 100644 index 000000000..9a2f8e79c --- /dev/null +++ b/mechglue/src/windows/identity/ui/statusbar.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> + +khm_statusbar_part khm_statusbar_parts[] = { + {KHUI_SBPART_INFO, 0, KHUI_SB_WTYPE_FILLER}, + {KHUI_SBPART_NOTICE, 40, KHUI_SB_WTYPE_RELATIVE}, + {KHUI_SBPART_LOC, 40, KHUI_SB_WTYPE_ABSOLUTE} +}; + +int khm_n_statusbar_parts = sizeof(khm_statusbar_parts) / sizeof(khm_statusbar_part); + +HWND khm_hwnd_statusbar = NULL; + +LRESULT +khm_statusbar_notify(LPNMHDR nmhdr) { + LPNMMOUSE pnmm; + + switch(nmhdr->code) { + case NM_CLICK: + case NM_DBLCLK: + pnmm = (LPNMMOUSE) nmhdr; + + if (pnmm->dwItemSpec >= (DWORD) khm_n_statusbar_parts) + return TRUE; + + if (khm_statusbar_parts[pnmm->dwItemSpec].id == KHUI_SBPART_NOTICE) { + /* means, show next notification */ + kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW_QUEUED, 0, 0); + } + + return TRUE; + } + + return FALSE; +} + +void +khui_statusbar_set_parts(HWND parent) { + int i; + int fillerwidth; + int staticwidth; + int lastx; + int width; + RECT r; + INT * parts; + + GetClientRect(parent, &r); + width = r.right - r.left; + + /* calculate fillerwidth and staticwidth */ + staticwidth = 0; + for(i=0;i<khm_n_statusbar_parts;i++) { + if(khm_statusbar_parts[i].wtype == KHUI_SB_WTYPE_ABSOLUTE) { + staticwidth += khm_statusbar_parts[i].width; + } else if(khm_statusbar_parts[i].wtype == KHUI_SB_WTYPE_RELATIVE) { + staticwidth += (khm_statusbar_parts[i].width * width) / 100; + } + } + + fillerwidth = width - staticwidth; + + parts = PMALLOC(sizeof(INT) * khm_n_statusbar_parts); + + lastx = 0; + for(i=0;i<khm_n_statusbar_parts;i++) { + int w; + switch(khm_statusbar_parts[i].wtype) { + case KHUI_SB_WTYPE_ABSOLUTE: + w = khm_statusbar_parts[i].width; + break; + + case KHUI_SB_WTYPE_RELATIVE: + w = (khm_statusbar_parts[i].width * width) / 100; + break; + + case KHUI_SB_WTYPE_FILLER: + w = fillerwidth; + break; + } + lastx += w; + + if(i==khm_n_statusbar_parts - 1) + parts[i] = -1; + else + parts[i] = lastx; + } + + SendMessage( + khm_hwnd_statusbar, + SB_SETPARTS, + khm_n_statusbar_parts, + (LPARAM) parts); + + PFREE(parts); +} + +void khm_create_statusbar(HWND parent) { + HWND hwsb; + + hwsb = CreateWindowEx( + 0, + STATUSCLASSNAME, + NULL, + SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE, + 0,0,0,0, + parent, + NULL, + khm_hInstance, + NULL); + + if(!hwsb) + return; + + khm_hwnd_statusbar = hwsb; + + khui_statusbar_set_parts(parent); + + kmq_post_message(KMSG_ALERT, KMSG_ALERT_CHECK_QUEUE, 0, 0); +} + +void khm_update_statusbar(HWND parent) { + MoveWindow(khm_hwnd_statusbar, 0, 0, 0, 0, TRUE); + khui_statusbar_set_parts(parent); +} + +int sb_find_index(int id) { + int i; + + for(i=0;i<khm_n_statusbar_parts;i++) { + if(khm_statusbar_parts[i].id == id) + return i; + } + + return -1; +} + +void khm_statusbar_set_part(int id, HICON icon, wchar_t * text) { + int idx; + + if (!khm_hwnd_statusbar) + return; + + idx = sb_find_index(id); + if(idx < 0) + return; + + SendMessage(khm_hwnd_statusbar, + SB_SETICON, + idx, + (LPARAM) icon); + + SendMessage(khm_hwnd_statusbar, + SB_SETTEXT, + idx, + (LPARAM) text); +} + diff --git a/mechglue/src/windows/identity/ui/statusbar.h b/mechglue/src/windows/identity/ui/statusbar.h new file mode 100644 index 000000000..2fd267e9e --- /dev/null +++ b/mechglue/src/windows/identity/ui/statusbar.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_STATUSBAR_H +#define __KHIMAIRA_STATUSBAR_H + +typedef struct khm_statusbar_part_t { + int id; + int width; + int wtype; /* one of KHUI_SB_WTYPE_* */ +} khm_statusbar_part; + +#define KHUI_SB_WTYPE_RELATIVE 1 +#define KHUI_SB_WTYPE_ABSOLUTE 2 +#define KHUI_SB_WTYPE_FILLER 4 + +/* statusbar parts */ +#define KHUI_SBPART_INFO 1 +#define KHUI_SBPART_NOTICE 2 +#define KHUI_SBPART_LOC 3 + +extern HWND khm_hwnd_statusbar; +extern khm_statusbar_part khm_statusbar_parts[]; +extern int khm_n_statusbar_parts; + +void khm_create_statusbar(HWND p); +void khm_update_statusbar(HWND parent); +void khm_statusbar_set_part(int id, HICON icon, wchar_t * text); +LRESULT khm_statusbar_notify(LPNMHDR nmhdr); + +#endif diff --git a/mechglue/src/windows/identity/ui/timer.c b/mechglue/src/windows/identity/ui/timer.c new file mode 100644 index 000000000..5d28e6a58 --- /dev/null +++ b/mechglue/src/windows/identity/ui/timer.c @@ -0,0 +1,702 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +/* in seconds */ +#if 0 +khm_int32 khui_timeout_warn = KHUI_DEF_TIMEOUT_WARN; +khm_int32 khui_timeout_crit = KHUI_DEF_TIMEOUT_CRIT; +khm_int32 khui_timeout_renew = KHUI_DEF_TIMEOUT_RENEW; + +khm_boolean khui_do_renew = TRUE; +khm_boolean khui_do_warn = TRUE; +khm_boolean khui_do_crit = TRUE; +#endif + +khui_timer_event * khui_timers = NULL; +khm_size khui_n_timers = 0; +khm_size khui_nc_timers = 0; + +CRITICAL_SECTION cs_timers; + +/********************************************************************* + Timers + *********************************************************************/ + + +#define KHUI_TIMER_ALLOC_INCR 16 + +void +khm_timer_init(void) { +#ifdef DEBUG + assert(khui_timers == NULL); +#endif + + khui_nc_timers = KHUI_TIMER_ALLOC_INCR; + khui_n_timers = 0; + khui_timers = PMALLOC(sizeof(*khui_timers) * khui_nc_timers); + +#ifdef DEBUG + assert(khui_timers != NULL); +#endif + + InitializeCriticalSection(&cs_timers); +} + +void +khm_timer_exit(void) { + EnterCriticalSection(&cs_timers); + + if (khui_timers) + PFREE(khui_timers); + khui_timers = NULL; + khui_n_timers = 0; + khui_nc_timers = 0; + + LeaveCriticalSection(&cs_timers); + DeleteCriticalSection(&cs_timers); +} + +/* called with cs_timers held */ +static void +tmr_fire_timer(void) { + int i; + unsigned __int64 curtime; + unsigned __int64 err; + unsigned __int64 next_event; + int tmr_count[KHUI_N_TTYPES]; + unsigned __int64 tmr_offset[KHUI_N_TTYPES]; + int t; + khm_handle eff_ident = NULL; + khui_timer_type eff_type = 0; /* meaningless */ + int fire_count = 0; + FILETIME ft; + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft); + err = FtToInt(&ft); + GetSystemTimeAsFileTime(&ft); + curtime = FtToInt(&ft); + + next_event = 0; + + ZeroMemory(tmr_count, sizeof(tmr_count)); + ZeroMemory(tmr_offset, sizeof(tmr_offset)); + + for (i=0; i < (int) khui_n_timers; i++) { + if (!(khui_timers[i].flags & + (KHUI_TE_FLAG_STALE | KHUI_TE_FLAG_EXPIRED)) && + khui_timers[i].type != KHUI_TTYPE_ID_MARK && + khui_timers[i].expire < curtime + err) { + + t = khui_timers[i].type; + + switch(t) { + case KHUI_TTYPE_ID_RENEW: + khm_cred_renew_identity(khui_timers[i].key); + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + break; + + case KHUI_TTYPE_CRED_RENEW: + /* the equivalence threshold for setting the timer is + a lot larger than what we are testing for here + (KHUI_TIMEEQ_ERROR vs KHUI_TIMEEQ_ERROR_SMALL) so + we assume that it is safe to trigger a renew_cred + call here without checking if there's an imminent + renew_identity call. */ + khm_cred_renew_cred(khui_timers[i].key); + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + break; + + default: + if (t < KHUI_N_TTYPES) { + tmr_count[t]++; + if (tmr_offset[t] == 0 || + tmr_offset[t] > khui_timers[i].offset) + tmr_offset[t] = khui_timers[i].offset; + if (next_event == 0 || + next_event > + khui_timers[i].expire + khui_timers[i].offset) + next_event = khui_timers[i].expire + + khui_timers[i].offset; + + if (eff_ident == NULL && + (t == KHUI_TTYPE_ID_EXP || + t == KHUI_TTYPE_ID_CRIT || + t == KHUI_TTYPE_ID_WARN)) { + /* we don't need a hold since we will be done + with the handle before the marker is + expired (the marker is the timer with the + KHUI_TTYPE_ID_MARK which contains a held + handle and is not really a timer.) */ + eff_ident = khui_timers[i].key; + eff_type = t; + } + + fire_count++; + + khui_timers[i].flags |= KHUI_TE_FLAG_EXPIRED; + } +#ifdef DEBUG + else { + assert(FALSE); + } +#endif + } + } + } + + /* See if we have anything to do */ + if (next_event == 0) + return; + else { + wchar_t fmt[128]; + wchar_t wtime[128]; + wchar_t wmsg[256]; + wchar_t wtitle[64]; + unsigned __int64 second; + khui_alert * alert = NULL; + + khm_size cb; + + next_event -= curtime; + + /* Due to measurement errors we may be slightly off on our + next_event calculation which shows up as '4 mins 59 + seconds' instead of '5 mins' and so on when converting to a + string. So we add half a second to make the message + neater. */ + TimetToFileTimeInterval(1, &ft); + second = FtToInt(&ft); + next_event += second / 2; + + cb = sizeof(wtime); + ft = IntToFt(next_event); + FtIntervalToString(&ft, + wtime, + &cb); + + if (fire_count == 1 && + eff_ident != NULL && + (eff_type == KHUI_TTYPE_ID_EXP || + eff_type == KHUI_TTYPE_ID_CRIT || + eff_type == KHUI_TTYPE_ID_WARN)) { + + wchar_t idname[KCDB_IDENT_MAXCCH_NAME]; + + cb = sizeof(idname); + kcdb_identity_get_name(eff_ident, idname, &cb); + + if (next_event < second) { + LoadString(khm_hInstance, IDS_WARN_EXPIRED_ID, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname); + } else { + LoadString(khm_hInstance, IDS_WARN_EXPIRE_ID, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, idname, wtime); + } + } else { + if (next_event < second) { + LoadString(khm_hInstance, IDS_WARN_EXPIRED, + wmsg, ARRAYLENGTH(wmsg)); + } else { + LoadString(khm_hInstance, IDS_WARN_EXPIRE, + fmt, ARRAYLENGTH(fmt)); + + StringCbPrintf(wmsg, sizeof(wmsg), fmt, wtime); + } + } + + LoadString(khm_hInstance, IDS_WARN_TITLE, + wtitle, ARRAYLENGTH(wtitle)); + + khui_alert_create_simple(wtitle, wmsg, KHERR_WARNING, &alert); + khui_alert_set_flags(alert, KHUI_ALERT_FLAG_REQUEST_BALLOON, + KHUI_ALERT_FLAG_REQUEST_BALLOON); + khui_alert_show(alert); + khui_alert_release(alert); + } +} + +void +khm_timer_fire(HWND hwnd) { + EnterCriticalSection(&cs_timers); + tmr_fire_timer(); + LeaveCriticalSection(&cs_timers); + + khm_timer_refresh(hwnd); +} + +static int +tmr_update(khm_handle key, khui_timer_type type, __int64 expire, + __int64 offset, void * data, khm_boolean reinstate) { + int i; + + for (i=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].key == key && + khui_timers[i].type == type) + break; + } + + if (i >= (int) khui_n_timers) { + i = (int) khui_n_timers; + + if (i >= (int) khui_nc_timers) { + khui_timer_event * nt; +#ifdef DEBUG + assert(khui_timers); +#endif + khui_nc_timers = UBOUNDSS(i+1, KHUI_TIMER_ALLOC_INCR, + KHUI_TIMER_ALLOC_INCR); + nt = PMALLOC(sizeof(*nt) * khui_nc_timers); +#ifdef DEBUG + assert(nt); +#endif + memcpy(nt, khui_timers, sizeof(*nt) * khui_n_timers); + + PFREE(khui_timers); + khui_timers = nt; + } + + khui_timers[i].key = key; + khui_timers[i].type = type; + khui_timers[i].flags = 0; + khui_n_timers++; + } + + khui_timers[i].expire = expire; + khui_timers[i].offset = offset; + khui_timers[i].data = data; + + khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE; + if (reinstate) + khui_timers[i].flags &= ~KHUI_TE_FLAG_EXPIRED; + + return i; +} + +/* called with cs_timers held */ +static int +tmr_find(khm_handle key, khui_timer_type type, + khm_int32 and_flags, khm_int32 eq_flags) { + int i; + + eq_flags &= and_flags; + + for (i=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].key == key && + khui_timers[i].type == type && + (khui_timers[i].flags & and_flags) == eq_flags) + break; + } + + if (i < (int) khui_n_timers) + return i; + else + return -1; +} + +/* called with cs_timers held */ +static khm_int32 KHMAPI +tmr_cred_apply_proc(khm_handle cred, void * rock) { + khm_handle ident = NULL; + int mark_idx; + int idx; + FILETIME ft_expiry; + FILETIME ft_current; + FILETIME ft_creinst; + FILETIME ft_cred_expiry; + FILETIME ft; + FILETIME fte; + FILETIME ft_reinst; + khm_size cb; + + kcdb_cred_get_identity(cred, &ident); +#ifdef DEBUG + assert(ident); +#endif + + /* now get the expiry */ + cb = sizeof(ft_expiry); + if (KHM_FAILED(kcdb_identity_get_attr(ident, KCDB_ATTR_EXPIRE, + NULL, + &ft_expiry, &cb))) + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, + NULL, + &ft_expiry, &cb))) { + /* we don't have an expiry time to work with */ + kcdb_identity_release(ident); + return KHM_ERROR_SUCCESS; + } + + /* and the current time */ + GetSystemTimeAsFileTime(&ft_current); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft_reinst); + + ft_creinst = FtAdd(&ft_current, &ft_reinst); + + mark_idx = tmr_find(ident, KHUI_TTYPE_ID_MARK, 0, 0); + + if (mark_idx < 0) { + mark_idx = tmr_update(ident, KHUI_TTYPE_ID_MARK, 0, 0, 0, FALSE); + kcdb_identity_hold(ident); +#ifdef DEBUG + assert(mark_idx >= 0); +#endif + khui_timers[mark_idx].flags |= KHUI_TE_FLAG_STALE; + } + + if (khui_timers[mark_idx].flags & KHUI_TE_FLAG_STALE) { + /* first time we are touching this */ + khm_handle csp_cw = NULL; + khm_handle csp_id = NULL; + khm_int32 rv; + khm_int32 t; + khm_boolean do_warn = TRUE; + khm_boolean do_crit = TRUE; + khm_boolean do_renew = TRUE; + khm_boolean renew_done = FALSE; + khm_boolean monitor = TRUE; + khm_int32 to_warn = KHUI_DEF_TIMEOUT_WARN; + khm_int32 to_crit = KHUI_DEF_TIMEOUT_CRIT; + khm_int32 to_renew = KHUI_DEF_TIMEOUT_RENEW; + + if (CompareFileTime(&ft_expiry, &ft_current) < 0) + /* already expired */ + goto _done_with_ident; + + rv = khc_open_space(NULL, L"CredWindow", KHM_PERM_READ, + &csp_cw); + + assert(KHM_SUCCEEDED(rv)); + + rv = kcdb_identity_get_config(ident, KHM_PERM_READ, &csp_id); + if (KHM_SUCCEEDED(rv)) { + khc_shadow_space(csp_id, csp_cw); + khc_close_space(csp_cw); + } else { + csp_id = csp_cw; + } + csp_cw = NULL; + + rv = khc_read_int32(csp_id, L"Monitor", &t); + if (KHM_SUCCEEDED(rv)) + monitor = t; + + rv = khc_read_int32(csp_id, L"AllowWarn", &t); + if (KHM_SUCCEEDED(rv)) + do_warn = t; + + rv = khc_read_int32(csp_id, L"AllowCritical", &t); + if (KHM_SUCCEEDED(rv)) + do_crit = t; + + rv = khc_read_int32(csp_id, L"AllowAutoRenew", &t); + if (KHM_SUCCEEDED(rv)) + do_renew = t; + + rv = khc_read_int32(csp_id, L"WarnThreshold", &t); + if (KHM_SUCCEEDED(rv)) + to_warn = t; + + rv = khc_read_int32(csp_id, L"CriticalThreshold", &t); + if (KHM_SUCCEEDED(rv)) + to_crit = t; + + rv = khc_read_int32(csp_id, L"AutoRenewThreshold", &t); + if (KHM_SUCCEEDED(rv)) + to_renew = t; + + khc_close_space(csp_id); + + if (monitor && do_renew) { + int prev; + + TimetToFileTimeInterval(to_renew, &ft); + fte = FtSub(&ft_expiry, &ft); + + prev = + tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0); + + /* we set off a renew notification immediately if the + renew threshold has passed but a renew was never sent. + This maybe because that NetIDMgr was started at the + last minute, or because for some reason the renew timer + could not be triggered earlier. */ + if (CompareFileTime(&fte, &ft_current) > 0 || + prev == -1 || + !(khui_timers[prev].flags & KHUI_TE_FLAG_EXPIRED)) { + + if (CompareFileTime(&fte, &ft_current) < 0) + fte = ft_current; + + tmr_update(ident, KHUI_TTYPE_ID_RENEW, + FtToInt(&fte), FtToInt(&ft), 0, + CompareFileTime(&fte,&ft_creinst) > 0); + renew_done = TRUE; + } else { + /* special case. If the renew timer was in the past + and it was expired, then we retain the record as + long as the credentials are around. If the renewal + failed we don't want to automatically retry + everytime we check the timers. */ + tmr_update(ident, KHUI_TTYPE_ID_RENEW, + FtToInt(&fte), FtToInt(&ft), 0, FALSE); + } + } + + if (monitor && do_warn && !renew_done) { + + TimetToFileTimeInterval(to_warn, &ft); + fte = FtSub(&ft_expiry, &ft); + + if (CompareFileTime(&fte, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_WARN, + FtToInt(&fte), FtToInt(&ft), 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + if (monitor && do_crit && !renew_done) { + TimetToFileTimeInterval(to_crit, &ft); + fte = FtSub(&ft_expiry, &ft); + + if (CompareFileTime(&fte, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_CRIT, + FtToInt(&fte), FtToInt(&ft), 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + if (monitor && !renew_done) { + if (CompareFileTime(&ft_expiry, &ft_current) > 0) + tmr_update(ident, KHUI_TTYPE_ID_EXP, + FtToInt(&ft_expiry), 0, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + } + + _done_with_ident: + khui_timers[mark_idx].flags &= ~KHUI_TE_FLAG_STALE; + } + + cb = sizeof(ft_cred_expiry); + if (KHM_FAILED(kcdb_cred_get_attr(cred, KCDB_ATTR_EXPIRE, + NULL, + &ft_cred_expiry, + &cb))) + goto _cleanup; + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR, &ft); + + { + FILETIME ft_delta; + + ft_delta = FtSub(&ft_expiry, &ft_cred_expiry); + + if (CompareFileTime(&ft_cred_expiry, &ft_expiry) >= 0 || + CompareFileTime(&ft_delta, &ft) < 0) + goto _cleanup; + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_WARN, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + if (CompareFileTime(&fte, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_WARN, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_CRIT, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + if (CompareFileTime(&fte, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_CRIT, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_RENEW, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + fte = IntToFt(FtToInt(&ft_cred_expiry) - khui_timers[idx].offset); + if (CompareFileTime(&fte, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_RENEW, + FtToInt(&fte), + khui_timers[idx].offset, 0, + CompareFileTime(&fte, &ft_creinst) > 0); + kcdb_cred_hold(cred); + } + } + + if ((idx = tmr_find(ident, KHUI_TTYPE_ID_EXP, 0, 0)) >= 0 && + !(khui_timers[idx].flags & KHUI_TE_FLAG_STALE)) { + + if (CompareFileTime(&ft_cred_expiry, &ft_current) > 0) { + tmr_update(cred, KHUI_TTYPE_CRED_EXP, + FtToInt(&ft_cred_expiry), + 0, 0, + CompareFileTime(&ft_cred_expiry, &ft_creinst) > 0); + } + } + + _cleanup: + + if (ident) + kcdb_identity_release(ident); + + return KHM_ERROR_SUCCESS; +} + +/* called with cs_timers held */ +static void +tmr_purge(void) { + int i, j; + + for (i=0,j=0; i < (int) khui_n_timers; i++) { + if (khui_timers[i].flags & KHUI_TE_FLAG_STALE) { + if (khui_timers[i].type == KHUI_TTYPE_ID_MARK) { + kcdb_identity_release(khui_timers[i].key); +#ifdef DEBUG + { + int idx; + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_CRIT, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_RENEW, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_WARN, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + + idx = tmr_find(khui_timers[i].key, + KHUI_TTYPE_ID_EXP, 0, 0); + assert(idx < 0 || + (khui_timers[idx].flags & + KHUI_TE_FLAG_STALE)); + } +#endif + } else if (khui_timers[i].type == KHUI_TTYPE_CRED_WARN || + khui_timers[i].type == KHUI_TTYPE_CRED_CRIT || + khui_timers[i].type == KHUI_TTYPE_CRED_RENEW || + khui_timers[i].type == KHUI_TTYPE_CRED_EXP) { + kcdb_cred_release(khui_timers[i].key); + } + } else { + if (i != j) + khui_timers[j] = khui_timers[i]; + j++; + } + } + + khui_n_timers = j; +} + +/* go through all the credentials and set timers as appropriate. */ +void +khm_timer_refresh(HWND hwnd) { + int i; + unsigned __int64 next_event = 0; + unsigned __int64 curtime; + unsigned __int64 diff; + + EnterCriticalSection(&cs_timers); + + KillTimer(hwnd, KHUI_TRIGGER_TIMER_ID); + + for (i=0; i < (int) khui_n_timers; i++) { +#ifdef NOT_IMPLEMENTED_YET + if (khui_timers[i].type == KHUI_TTYPE_BMSG || + khui_timers[i].type == KHUI_TTYPE_SMSG) { + khui_timers[i].flags &= ~KHUI_TE_FLAG_STALE; + } else +#endif + khui_timers[i].flags |= KHUI_TE_FLAG_STALE; + } + + kcdb_credset_apply(NULL, + tmr_cred_apply_proc, + NULL); + + tmr_purge(); + + _check_next_event: + + next_event = 0; + for (i=0; i < (int) khui_n_timers; i++) { + if (!(khui_timers[i].flags & KHUI_TE_FLAG_EXPIRED) && + khui_timers[i].type != KHUI_TTYPE_ID_MARK && + (next_event == 0 || + next_event > khui_timers[i].expire)) + + next_event = khui_timers[i].expire; + } + + if (next_event != 0) { + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + curtime = FtToInt(&ft); + + TimetToFileTimeInterval(KHUI_TIMEEQ_ERROR_SMALL, &ft); + diff = FtToInt(&ft); + + if (curtime + diff > next_event) { + tmr_fire_timer(); + goto _check_next_event; + } else { + diff = next_event - curtime; + ft = IntToFt(diff); + SetTimer(hwnd, + KHUI_TRIGGER_TIMER_ID, + FtIntervalToMilliseconds(&ft), + NULL); + } + } + + LeaveCriticalSection(&cs_timers); +} diff --git a/mechglue/src/windows/identity/ui/timer.h b/mechglue/src/windows/identity/ui/timer.h new file mode 100644 index 000000000..081d27852 --- /dev/null +++ b/mechglue/src/windows/identity/ui/timer.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_TIMER_H +#define __KHIMAIRA_TIMER_H + +/* note that the ordering of the first few enum constants are + significant. The values of the constants up to KHUI_N_TTYPES are + used as indices. */ +typedef enum tag_khui_timer_type { + KHUI_TTYPE_ID_EXP = 0, /* Identity expiration */ + KHUI_TTYPE_ID_CRIT, /* Identity critical */ + KHUI_TTYPE_ID_WARN, /* Identity warning */ + KHUI_TTYPE_CRED_EXP, /* Credential expiration */ + KHUI_TTYPE_CRED_CRIT, /* Credential critical */ + KHUI_TTYPE_CRED_WARN, /* Credential warning */ + + KHUI_N_TTYPES, /* Count of the timers that we + aggregate for notifications */ + + KHUI_TTYPE_ID_MARK, /* Identity marker */ + + KHUI_TTYPE_ID_RENEW, /* Identity auto renewal */ + KHUI_TTYPE_CRED_RENEW, /* Credential renewal */ + +#if 0 + KHUI_TTYPE_BMSG, /* Custom. Sends broadcast message + when triggered.*/ + KHUI_TTYPE_SMSG, /* Custom. Sends subscription message + when triggered. */ +#endif +} khui_timer_type; + +typedef struct tag_khui_timer_event { + khm_handle key; + khui_timer_type type; + + unsigned __int64 expire; /* time at which the timer expires */ + unsigned __int64 offset; /* time offset at which the event that + the timer warns of happens */ + void * data; + khm_int32 flags; +} khui_timer_event; + +#define KHUI_TRIGGER_TIMER_ID 48 +#define KHUI_REFRESH_TIMER_ID 49 + +#define KHUI_REFRESH_TIMEOUT 5000 + +#define KHUI_TE_FLAG_EXPIRED 0x00000001 +#define KHUI_TE_FLAG_STALE 0x00000002 + +#define KHUI_DEF_TIMEOUT_WARN 900 +#define KHUI_DEF_TIMEOUT_CRIT 300 +#define KHUI_DEF_TIMEOUT_RENEW 60 + +/* the max absolute difference between two timers (in seconds) that + can exist where we consider both timers to be in the same + timeslot. */ +#define KHUI_TIMEEQ_ERROR 20 + +/* the small error. */ +#define KHUI_TIMEEQ_ERROR_SMALL 1 + +void +khm_timer_refresh(HWND hwnd); + +void +khm_timer_fire(HWND hwnd); + +void +khm_timer_init(void); + +void +khm_timer_exit(void); + +#endif diff --git a/mechglue/src/windows/identity/ui/toolbar.c b/mechglue/src/windows/identity/ui/toolbar.c new file mode 100644 index 000000000..801d6cc52 --- /dev/null +++ b/mechglue/src/windows/identity/ui/toolbar.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khmapp.h> +#include<assert.h> + +HWND khui_hwnd_standard_toolbar; +int khui_tb_blank; + +khui_ilist * ilist_toolbar; + +void khui_init_toolbar(void) { + ilist_toolbar = khui_create_ilist(KHUI_TOOLBAR_IMAGE_WIDTH, KHUI_TOOLBAR_IMAGE_HEIGHT, KHUI_TOOLBAR_MAX_BTNS, 5, 0); +} + +void khui_exit_toolbar(void) { + khui_delete_ilist(ilist_toolbar); +} + +LRESULT khm_toolbar_notify(LPNMHDR notice) { + switch(notice->code) { + case NM_CUSTOMDRAW: + { + LPNMTBCUSTOMDRAW nmcd = (LPNMTBCUSTOMDRAW) notice; + if(nmcd->nmcd.dwDrawStage == CDDS_PREPAINT) { + return CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTERASE; + } else if(nmcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { + return CDRF_NOTIFYPOSTPAINT; + } else if(nmcd->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT) { + /* draw the actual icon */ + int iidx; + int ibmp; + HBITMAP hbmp; + RECT r; + + khui_action * act = + khui_find_action((int) nmcd->nmcd.dwItemSpec); + + if(!act || !act->ib_normal) + return CDRF_DODEFAULT; + + if((act->state & KHUI_ACTIONSTATE_DISABLED) && + act->ib_disabled) { + ibmp = act->ib_disabled; + } else if(act->ib_hot && + ((nmcd->nmcd.uItemState & CDIS_HOT) || + (nmcd->nmcd.uItemState & CDIS_SELECTED))){ + ibmp = act->ib_hot; + } else { + ibmp = act->ib_normal; + } + + iidx = khui_ilist_lookup_id(ilist_toolbar, ibmp); + if(iidx < 0) { + hbmp = LoadImage(khm_hInstance, + MAKEINTRESOURCE(ibmp), + IMAGE_BITMAP, + KHUI_TOOLBAR_IMAGE_WIDTH, + KHUI_TOOLBAR_IMAGE_HEIGHT, 0); + iidx = + khui_ilist_add_masked_id(ilist_toolbar, + hbmp, + KHUI_TOOLBAR_BGCOLOR, + ibmp); + DeleteObject(hbmp); + } + + if(iidx < 0) + return CDRF_DODEFAULT; + + CopyRect(&r, &(nmcd->nmcd.rc)); + r.left += ((r.right - r.left) - + KHUI_TOOLBAR_IMAGE_WIDTH) / 2; + r.top += ((r.bottom - r.top) - + KHUI_TOOLBAR_IMAGE_HEIGHT) / 2; + + khui_ilist_draw(ilist_toolbar, + iidx, + nmcd->nmcd.hdc, + r.left, + r.top, + 0); + + return CDRF_DODEFAULT; + } + } + break; + } + return 0; +} + +void khui_add_action_to_toolbar(HWND tb, khui_action *a, int opt, HIMAGELIST hiList) { + wchar_t buf[MAX_RES_STRING] = L""; + int idx_caption = 0; + TBBUTTON bn; + LRESULT lr; + + ZeroMemory(&bn,sizeof(bn)); + + if(opt & KHUI_TOOLBAR_ADD_SEP) { + bn.fsStyle = BTNS_SEP; + bn.iBitmap = 3; + + lr = SendMessage(tb, + TB_ADDBUTTONS, + 1, + (LPARAM) &bn); +#ifdef DEBUG + assert(lr); +#endif + return; + } + + bn.fsStyle = BTNS_BUTTON; + + if(opt & KHUI_TOOLBAR_VARSIZE) { + bn.fsStyle |= BTNS_AUTOSIZE; + } + + if(opt & KHUI_TOOLBAR_ADD_TEXT) { + int sid = 0; + if((opt & KHUI_TOOLBAR_ADD_LONGTEXT) == + KHUI_TOOLBAR_ADD_LONGTEXT) { + sid = a->is_tooltip; + } + if(!sid) + sid = a->is_caption; + if(sid) { + LoadString(khm_hInstance, + sid, + buf, ARRAYLENGTH(buf)); + buf[wcslen(buf) + 1] = L'\0'; + idx_caption = (int) SendMessage(tb, + TB_ADDSTRING, + (WPARAM) NULL, + (LPARAM) buf); +#if (_WIN32_IE >= 0x0501) + bn.fsStyle |= BTNS_SHOWTEXT; +#endif + bn.iString = idx_caption; + } + } + + if(opt & KHUI_TOOLBAR_ADD_DROPDOWN) { + bn.fsStyle |= BTNS_DROPDOWN; + } + + if((opt & KHUI_TOOLBAR_ADD_BITMAP) && a->ib_normal) { + bn.fsStyle |= TBSTYLE_CUSTOMERASE; + bn.iBitmap = khui_tb_blank; + } else { +#if (_WIN32_IE >= 0x0501) + bn.iBitmap = I_IMAGENONE; +#endif + } + + bn.idCommand = a->cmd; + + if(a->state & KHUI_ACTIONSTATE_DISABLED) { + bn.fsState = 0; + } else { + bn.fsState = TBSTATE_ENABLED; + } + + if(a->state & KHUI_ACTIONSTATE_CHECKED) { + bn.fsState |= TBSTATE_CHECKED; + } + + bn.dwData = 0; + + lr = SendMessage( + tb, + TB_ADDBUTTONS, + 1, + (LPARAM) &bn); + +#ifdef DEBUG + assert(lr); +#endif +} + +void khm_update_standard_toolbar(void) +{ + khui_menu_def * def; + khui_action_ref * aref; + khui_action * act; + + def = khui_find_menu(KHUI_TOOLBAR_STANDARD); + + aref = def->items; + + while(aref && aref->action != KHUI_MENU_END) { + if(aref->action == KHUI_MENU_SEP) { + aref++; + continue; + } + + act = khui_find_action(aref->action); + if(act) { + BOOL enable; + + enable = !(act->state & KHUI_ACTIONSTATE_DISABLED); + SendMessage(khui_hwnd_standard_toolbar, + TB_ENABLEBUTTON, + (WPARAM) act->cmd, + MAKELPARAM(enable, 0)); + } + + aref++; + } +} + +void khm_create_standard_toolbar(HWND rebar) { + HWND hwtb; + SIZE sz; + HBITMAP hbm_blank; + HIMAGELIST hiList; + REBARBANDINFO rbi; + khui_menu_def * def; + khui_action * act; + khui_action_ref * aref; + int idx_blank; + + def = khui_find_menu(KHUI_TOOLBAR_STANDARD); + + hwtb = CreateWindowEx(0 +#if (_WIN32_IE >= 0x0501) + | TBSTYLE_EX_MIXEDBUTTONS +#endif + , + TOOLBARCLASSNAME, + (LPWSTR) NULL, + WS_CHILD | + TBSTYLE_FLAT | + TBSTYLE_AUTOSIZE | + TBSTYLE_LIST | + CCS_NORESIZE | + CCS_NOPARENTALIGN | + CCS_ADJUSTABLE | + CCS_NODIVIDER, + 0, 0, 0, 0, rebar, + (HMENU) NULL, khm_hInstance, + NULL); + + if(!hwtb) { +#ifdef DEBUG + assert(FALSE); +#else + return; +#endif + } + + hiList = ImageList_Create( + KHUI_TOOLBAR_IMAGE_WIDTH, + KHUI_TOOLBAR_IMAGE_HEIGHT, + ILC_MASK, + (int) khui_action_list_length(def->items), + 3); + + hbm_blank = LoadImage(khm_hInstance, + MAKEINTRESOURCE(IDB_TB_BLANK), + IMAGE_BITMAP, + KHUI_TOOLBAR_IMAGE_WIDTH, + KHUI_TOOLBAR_IMAGE_HEIGHT, 0); + idx_blank = ImageList_AddMasked(hiList, hbm_blank, RGB(0,0,0)); + + khui_hwnd_standard_toolbar = hwtb; + khui_tb_blank = idx_blank; + + def = khui_find_menu(KHUI_TOOLBAR_STANDARD); + + aref = def->items; + + SendMessage(hwtb, + TB_BUTTONSTRUCTSIZE, + sizeof(TBBUTTON), + 0); + + SendMessage(hwtb, + TB_SETBITMAPSIZE, + 0, + MAKELONG(KHUI_TOOLBAR_IMAGE_WIDTH,KHUI_TOOLBAR_IMAGE_HEIGHT)); + + SendMessage(hwtb, + TB_SETIMAGELIST, + 0, + (LPARAM) hiList); + + SendMessage(hwtb, + TB_SETBUTTONSIZE, + 0, + MAKELONG(KHUI_TOOLBAR_IMAGE_WIDTH,KHUI_TOOLBAR_IMAGE_HEIGHT)); + + while(aref && aref->action != KHUI_MENU_END) { + if(aref->action == KHUI_MENU_SEP) { + khui_add_action_to_toolbar(hwtb, + NULL, + KHUI_TOOLBAR_ADD_SEP, + hiList); + } else { + act = khui_find_action(aref->action); + khui_add_action_to_toolbar(hwtb, + act, + KHUI_TOOLBAR_ADD_BITMAP, + hiList); + } + aref ++; + } + + SendMessage(hwtb, + TB_AUTOSIZE, + 0,0); + + SendMessage(hwtb, + TB_GETMAXSIZE, + 0, + (LPARAM) &sz); + + sz.cy += 5; + + ZeroMemory(&rbi, sizeof(rbi)); + + rbi.cbSize = sizeof(rbi); + rbi.fMask = + RBBIM_ID | + RBBIM_CHILD | + RBBIM_CHILDSIZE | + RBBIM_IDEALSIZE | + RBBIM_SIZE | + RBBIM_STYLE; + rbi.fStyle = + RBBS_USECHEVRON | + RBBS_BREAK; + rbi.hwndChild = hwtb; + + rbi.wID = KHUI_TOOLBAR_STANDARD; + rbi.cx = sz.cx; + rbi.cxMinChild = sz.cx; + rbi.cyMinChild = sz.cy; + rbi.cyChild = rbi.cyMinChild; + rbi.cyMaxChild = rbi.cyMinChild; + rbi.cyIntegral = rbi.cyMinChild; + + rbi.cxIdeal = rbi.cx; + + SendMessage(rebar, + RB_INSERTBAND, + 0, + (LPARAM) &rbi); +} diff --git a/mechglue/src/windows/identity/ui/toolbar.h b/mechglue/src/windows/identity/ui/toolbar.h new file mode 100644 index 000000000..89700f2e4 --- /dev/null +++ b/mechglue/src/windows/identity/ui/toolbar.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_TOOLBAR_H +#define __KHIMAIRA_TOOLBAR_H + +extern HWND khui_hwnd_standard_toolbar; + +void khui_init_toolbar(void); +void khui_exit_toolbar(void); +LRESULT khm_toolbar_notify(LPNMHDR notice); +void khm_create_standard_toolbar(HWND rebar); +void khui_add_action_to_toolbar(HWND toolbar, khui_action * act, int opt, HIMAGELIST hiList); +void khm_update_standard_toolbar(void); + +/* options for khui_add_action_to_toolbar */ +#define KHUI_TOOLBAR_ADD_TEXT 1 +#define KHUI_TOOLBAR_ADD_BITMAP 2 +#define KHUI_TOOLBAR_ADD_LONGTEXT 5 +#define KHUI_TOOLBAR_ADD_DROPDOWN 8 +#define KHUI_TOOLBAR_ADD_SEP 16 +#define KHUI_TOOLBAR_VARSIZE 32 + +#define KHUI_TOOLBAR_IMAGE_WIDTH 29 +#define KHUI_TOOLBAR_IMAGE_HEIGHT 27 +#define KHUI_TOOLBAR_BGCOLOR RGB(0xd7,0xd7,0xd7) +#define KHUI_TOOLBAR_MAX_BTNS 64 + +#endif diff --git a/mechglue/src/windows/identity/ui/uiconfig.csv b/mechglue/src/windows/identity/ui/uiconfig.csv new file mode 100644 index 000000000..14057dded --- /dev/null +++ b/mechglue/src/windows/identity/ui/uiconfig.csv @@ -0,0 +1,114 @@ +Name,Type,Value,Description +CredWindow,KC_SPACE,0,Options for the credentials window + AutoInit,KC_INT32,0,Prompt for creds if there arent any + AutoStart,KC_INT32,0,Start Khimaira when Windows starts + AutoImport,KC_INT32,1,Import Windows creds when Khimaira starts + AutoDetectNet,KC_INT32,1,Automatically detect network connectivity changes + KeepRunning,KC_INT32,1,Keep running after closing Khimaira + DefaultView,KC_STRING,ByIdentity, + ViewList,KC_STRING,"ByIdentity,ByLocation", + PaddingHorizontal,KC_INT32,4, + PaddingVertical,KC_INT32,2, + PaddingHeader,KC_INT32,16, + Monitor,KC_INT32,1,Monitor credentials + DefaultMonitor,KC_INT32,1,Default Monitor value for new identities + RefreshTimeout,KC_INT32,60,In seconds + WarnThreshold,KC_INT32,900,In seconds + AllowWarn,KC_INT32,1,Boolean. Enables warning. + CriticalThreshold,KC_INT32,300,In seconds + AllowCritical,KC_INT32,1,Boolean. Enables critical. + AutoRenewThreshold,KC_INT32,600,In seconds + AllowAutoRenew,KC_INT32,1,Boolean. + DefaultAllowAutoRenew,KC_INT32,1,Default AllowAutoRenew value for new identities + DefaultSticky,KC_INT32,0,Default Sticky value for new identities + MaxThreshold,KC_INT32,86400,Max value for a threshold (1 day) + MinThreshold,KC_INT32,10,Min value for a threshold (0) + Windows,KC_SPACE,0,Window parameters + _Schema,KC_SPACE,0,Schema + Width,KC_INT32,0, + Height,KC_INT32,0, + XPos,KC_INT32,0, + YPos,KC_INT32,0, + _Schema,KC_ENDSPACE,0, + Main,KC_SPACE,0,Main window + Main,KC_ENDSPACE,0, + Windows,KC_ENDSPACE,0, + Views,KC_SPACE,0,Preconfigured views for credentials + Custom_0,KC_SPACE,0,First custom view. Additional views have names of the form Custom_N + Custom_0,KC_ENDSPACE,0, + ByIdentity,KC_SPACE,0,The default view + Description,KC_STRING,View grouped by identity and credential type, + ColumnList,KC_STRING,"_CWFlags,IdentityName,TypeName,Name,TimeLeft", + Columns,KC_SPACE,0,Columns + _CWFlags,KC_SPACE,0, + Width,KC_INT32,20, + Flags,KC_INT32,112, + _CWFlags,KC_ENDSPACE,0, +# _CWTypeIcon,KC_SPACE,0, +# Width,KC_INT32,20, +# Flags,KC_INT32,112, +# _CWTypeIcon,KC_ENDSPACE,0, + IdentityName,KC_SPACE,0, + Width,KC_INT32,100, + SortIndex,KC_INT32,0, + Flags,KC_INT32,11, + IdentityName,KC_ENDSPACE,0 + TypeName,KC_SPACE,0 + Width,KC_INT32,100 + SortIndex,KC_INT32,1 + Flags,KC_INT32,11 + TypeName,KC_ENDSPACE,0 + Name,KC_SPACE,0 + Width,KC_INT32,200 + SortIndex,KC_INT32,2 + Flags,KC_INT32,3 + Name,KC_ENDSPACE,0 + TimeLeft,KC_SPACE,0 + Width,KC_INT32,200 + Flags,KC_INT32,1 + TimeLeft,KC_ENDSPACE,0 + Columns,KC_ENDSPACE,0 + ByIdentity,KC_ENDSPACE,0 + ByLocation,KC_SPACE,0,View by location + Description,KC_STRING,View grouped by location, + ColumnList,KC_STRING,"_CWFlags,Location,IdentityName,TypeName,Name,TimeLeft", + Columns,KC_SPACE,0,Columns + _CWFlags,KC_SPACE,0, + Width,KC_INT32,20, + Flags,KC_INT32,112, + _CWFlags,KC_ENDSPACE,0, +# _CWTypeIcon,KC_SPACE,0, +# Width,KC_INT32,20, +# Flags,KC_INT32,112, +# _CWTypeIcon,KC_ENDSPACE,0, + Location,KC_SPACE,0, + Width,KC_INT32,100, + SortIndex,KC_INT32,0, + Flags,KC_INT32,11, + Location,KC_ENDSPACE,0, + IdentityName,KC_SPACE,0, + Width,KC_INT32,100, + SortIndex,KC_INT32,1, + Flags,KC_INT32,11, + IdentityName,KC_ENDSPACE,0 + TypeName,KC_SPACE,0 + Width,KC_INT32,100 + SortIndex,KC_INT32,2 + Flags,KC_INT32,11 + TypeName,KC_ENDSPACE,0 + Name,KC_SPACE,0 + Width,KC_INT32,200 + SortIndex,KC_INT32,3 + Flags,KC_INT32,3 + Name,KC_ENDSPACE,0 + TimeLeft,KC_SPACE,0 + Width,KC_INT32,200 + Flags,KC_INT32,1 + TimeLeft,KC_ENDSPACE,0 + Columns,KC_ENDSPACE,0 + ByLocation,KC_ENDSPACE,0 + Views,KC_ENDSPACE,0 + Notices,KC_SPACE,0,Notices and alerts + MinimizeWarning,KC_INT32,1,Show the minimize warning? + Notices,KC_ENDSPACE,0 +CredWindow,KC_ENDSPACE,0 diff --git a/mechglue/src/windows/identity/uilib/Makefile b/mechglue/src/windows/identity/uilib/Makefile new file mode 100644 index 000000000..1920d6aa3 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/Makefile @@ -0,0 +1,62 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=uilib +!include <../config/Makefile.w32> + +UIDLLOBJFILES= \ + $(OBJ)\rescache.obj \ + $(OBJ)\action.obj \ + $(OBJ)\creddlg.obj \ + $(OBJ)\alert.obj \ + $(OBJ)\propsheet.obj \ + $(OBJ)\propwnd.obj \ + $(OBJ)\uilibmain.obj \ + $(OBJ)\actiondef.obj \ + $(OBJ)\acceldef.obj \ + $(OBJ)\configui.obj \ + $(OBJ)\trackerwnd.obj \ + $(OBJ)\version.obj + +INCFILES= \ + $(INCDIR)\khuidefs.h \ + $(INCDIR)\khrescache.h \ + $(INCDIR)\khaction.h \ + $(INCDIR)\khactiondef.h \ + $(INCDIR)\khalerts.h \ + $(INCDIR)\khhtlink.h \ + $(INCDIR)\khnewcred.h \ + $(INCDIR)\khprops.h \ + $(INCDIR)\khconfigui.h \ + $(INCDIR)\khtracker.h \ + $(INCDIR)\khremote.h + +$(OBJ)\actiondef.c: actions.csv actiondef.cfg + $(CCSV) $** $@ + +$(OBJ)\acceldef.c: accel.csv acceldef.cfg + $(CCSV) $** $@ + +all: mkdirs $(INCFILES) $(UIDLLOBJFILES) + diff --git a/mechglue/src/windows/identity/uilib/accel.csv b/mechglue/src/windows/identity/uilib/accel.csv new file mode 100644 index 000000000..a97b37ba4 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/accel.csv @@ -0,0 +1,21 @@ +command,mod,key,scope +KHUI_PACTION_MENU,FVIRTKEY,VK_F10,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_UP,FVIRTKEY,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_UP_EXTEND,FVIRTKEY|FSHIFT,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_UP_TOGGLE,FVIRTKEY|FCONTROL,VK_UP,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_DOWN,FVIRTKEY,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_DOWN_EXTEND,FVIRTKEY|FSHIFT,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_DOWN_TOGGLE,FVIRTKEY|FCONTROL,VK_DOWN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_LEFT,FVIRTKEY,VK_LEFT,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_RIGHT,FVIRTKEY,VK_RIGHT,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_ENTER,FVIRTKEY,VK_RETURN,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_ESC,FVIRTKEY,VK_ESCAPE,KHUI_ACCEL_SCOPE_GLOBAL +#KHUI_PACTION_DELETE,FVIRTKEY,VK_DELETE,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_DESTROY_CRED,FVIRTKEY,VK_DELETE,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_EXIT,FCONTROL|FVIRTKEY,\'X\',KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_VIEW_REFRESH,FVIRTKEY,VK_F5,KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_NEW_CRED,FCONTROL|FVIRTKEY,\'N\',KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_RENEW_CRED,FCONTROL|FVIRTKEY,\'R\',KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_IMPORT,FCONTROL|FVIRTKEY,\'I\',KHUI_ACCEL_SCOPE_GLOBAL +KHUI_ACTION_DESTROY_CRED,FCONTROL|FVIRTKEY,\'D\',KHUI_ACCEL_SCOPE_GLOBAL +KHUI_PACTION_SELALL,FCONTROL|FVIRTKEY,\'A\',KHUI_ACCEL_SCOPE_GLOBAL diff --git a/mechglue/src/windows/identity/uilib/acceldef.cfg b/mechglue/src/windows/identity/uilib/acceldef.cfg new file mode 100644 index 000000000..5dc72e610 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/acceldef.cfg @@ -0,0 +1,50 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +$file_prefix = <<EOS; +/* +This file was autogenerated from src/ui/acceldef.cfg and src/ui/accel.csv. + +Do not modify directly. +*/ +#include<khuidefs.h> + +khui_accel_def khui_accel_global[] = { +EOS + +$record_prefix = "{"; + +$record_sep = ",\n"; + +$record_postfix = "}"; + +$file_postfix = <<EOS; + +}; + +int khui_n_accel_global = sizeof(khui_accel_global) / sizeof(khui_accel_def); + +EOS + +$skip_lines = 1; diff --git a/mechglue/src/windows/identity/uilib/action.c b/mechglue/src/windows/identity/uilib/action.c new file mode 100644 index 000000000..b337eb894 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/action.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#define NOEXPORT +#include<khuidefs.h> +#include<utils.h> +#include<assert.h> + +khui_action_ref khui_main_menu[] = { + MENU_ACTION(KHUI_MENU_FILE), + MENU_ACTION(KHUI_MENU_CRED), + MENU_ACTION(KHUI_MENU_VIEW), + MENU_ACTION(KHUI_MENU_OPTIONS), + MENU_ACTION(KHUI_MENU_HELP), + MENU_END() +}; + +khui_action_ref khui_menu_file[] = { + MENU_ACTION(KHUI_ACTION_PROPERTIES), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_EXIT), + MENU_END() +}; + +khui_action_ref khui_menu_cred[] = { + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_IMPORT), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_SET_DEF_ID), + MENU_ACTION(KHUI_ACTION_SET_SRCH_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_PASSWD_ID), + MENU_END() +}; + +khui_action_ref khui_menu_layout[] = { + MENU_ACTION(KHUI_ACTION_LAYOUT_ID), + MENU_ACTION(KHUI_ACTION_LAYOUT_TYPE), + MENU_ACTION(KHUI_ACTION_LAYOUT_LOC), + MENU_END() +}; + +khui_action_ref khui_menu_toolbars[] = { + MENU_ACTION(KHUI_ACTION_TB_STANDARD), + MENU_END() +}; + +khui_action_ref khui_menu_view[] = { + MENU_ACTION(KHUI_ACTION_CHOOSE_COLS), + MENU_ACTION(KHUI_MENU_LAYOUT), + MENU_ACTION(KHUI_MENU_TOOLBARS), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_DEBUG_WINDOW), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_VIEW_REFRESH), + MENU_END() +}; + +khui_action_ref khui_menu_options[] = { + MENU_ACTION(KHUI_ACTION_OPT_KHIM), + MENU_ACTION(KHUI_ACTION_OPT_IDENTS), + MENU_ACTION(KHUI_ACTION_OPT_NOTIF), + MENU_ACTION(KHUI_ACTION_OPT_PLUGINS), + MENU_END() +}; + +khui_action_ref khui_menu_help[] = { + MENU_ACTION(KHUI_ACTION_HELP_CTX), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_HELP_CONTENTS), + MENU_ACTION(KHUI_ACTION_HELP_INDEX), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_HELP_ABOUT), + MENU_END() +}; + +khui_action_ref khui_toolbar_standard[] = { + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_IMPORT), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_PASSWD_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_VIEW_REFRESH), + MENU_ACTION(KHUI_PACTION_BLANK), + MENU_ACTION(KHUI_ACTION_HELP_CTX), + MENU_END() +}; + +khui_action_ref khui_menu_ident_ctx[] = { + MENU_ACTION(KHUI_ACTION_PROPERTIES), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_SET_DEF_ID), + MENU_ACTION(KHUI_ACTION_SET_SRCH_ID), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_END() +}; + +khui_action_ref khui_menu_tok_ctx[] = { + MENU_ACTION(KHUI_ACTION_PROPERTIES), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_END() +}; + +khui_action_ref khui_menu_ico_ctx_min[] = { + MENU_DEFACTION(KHUI_ACTION_OPEN_APP), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_EXIT), + MENU_END() +}; + +khui_action_ref khui_menu_ico_ctx_normal[] = { + MENU_DEFACTION(KHUI_ACTION_CLOSE_APP), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_NEW_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_SEP(), + MENU_ACTION(KHUI_ACTION_EXIT), + MENU_END() +}; + +khui_action_ref khui_pmenu_tok_sel[] = { + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_END() +}; + +khui_action_ref khui_pmenu_id_sel[] = { + MENU_ACTION(KHUI_ACTION_DESTROY_CRED), + MENU_ACTION(KHUI_ACTION_RENEW_CRED), + MENU_END() +}; + +/* all stock menus and toolbars */ +khui_menu_def khui_all_menus[] = { + CONSTMENU(KHUI_MENU_MAIN, KHUI_MENUSTATE_CONSTANT, khui_main_menu), + CONSTMENU(KHUI_MENU_FILE, KHUI_MENUSTATE_CONSTANT, khui_menu_file), + CONSTMENU(KHUI_MENU_CRED, KHUI_MENUSTATE_CONSTANT, khui_menu_cred), + CONSTMENU(KHUI_MENU_VIEW, KHUI_MENUSTATE_CONSTANT, khui_menu_view), + CONSTMENU(KHUI_MENU_LAYOUT, KHUI_MENUSTATE_CONSTANT, khui_menu_layout), + CONSTMENU(KHUI_MENU_TOOLBARS, KHUI_MENUSTATE_CONSTANT, khui_menu_toolbars), + CONSTMENU(KHUI_MENU_OPTIONS, KHUI_MENUSTATE_CONSTANT, khui_menu_options), + CONSTMENU(KHUI_MENU_HELP, KHUI_MENUSTATE_CONSTANT, khui_menu_help), + + /* toolbars */ + CONSTMENU(KHUI_TOOLBAR_STANDARD, KHUI_MENUSTATE_CONSTANT, khui_toolbar_standard), + + /* context menus */ + CONSTMENU(KHUI_MENU_IDENT_CTX, KHUI_MENUSTATE_CONSTANT, khui_menu_ident_ctx), + CONSTMENU(KHUI_MENU_TOK_CTX, KHUI_MENUSTATE_CONSTANT, khui_menu_tok_ctx), + CONSTMENU(KHUI_MENU_ICO_CTX_MIN, KHUI_MENUSTATE_CONSTANT, khui_menu_ico_ctx_min), + CONSTMENU(KHUI_MENU_ICO_CTX_NORMAL, KHUI_MENUSTATE_CONSTANT, khui_menu_ico_ctx_normal), + + /* pseudo menus */ + CONSTMENU(KHUI_PMENU_TOK_SEL, KHUI_MENUSTATE_CONSTANT, khui_pmenu_tok_sel), + CONSTMENU(KHUI_PMENU_ID_SEL, KHUI_MENUSTATE_CONSTANT, khui_pmenu_id_sel) +}; + +int khui_n_all_menus = sizeof(khui_all_menus) / sizeof(khui_menu_def); +CRITICAL_SECTION cs_actions; + +KHMEXP void KHMAPI +khui_init_actions(void) { + InitializeCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_exit_actions(void) { + DeleteCriticalSection(&cs_actions); +} + +#define MENU_NC_ITEMS 8 + +KHMEXP khui_menu_def * KHMAPI +khui_menu_create(int cmd) +{ + khui_menu_def * d; + + d = PMALLOC(sizeof(*d)); + ZeroMemory(d, sizeof(*d)); + + d->cmd = cmd; + d->nc_items = MENU_NC_ITEMS; + d->items = PMALLOC(sizeof(*(d->items)) * d->nc_items); + + d->state = KHUI_MENUSTATE_ALLOCD; + + return d; +} + +KHMEXP khui_menu_def * KHMAPI +khui_menu_dup(khui_menu_def * src) +{ + khui_menu_def * d; + size_t i; + size_t n; + + d = khui_menu_create(src->cmd); + + if(src->n_items == -1) + n = khui_action_list_length(src->items); + else + n = src->n_items; + + for(i=0; i<n; i++) { + if(src->items[i].flags & KHUI_ACTIONREF_PACTION) { + khui_menu_add_paction(d, src->items[i].p_action, src->items[i].flags); + } else { + khui_menu_add_action(d, src->items[i].action); + } + } + + return d; +} + +KHMEXP void KHMAPI +khui_menu_delete(khui_menu_def * d) +{ + int i; + + /* non-allocated menus are assumed to have no pointers to other + allocated blocks */ + if(!(d->state & KHUI_MENUSTATE_ALLOCD)) + return; + + for(i=0; i< (int) d->n_items; i++) { + if(d->items[i].flags & KHUI_ACTIONREF_FREE_PACTION) + PFREE(d->items[i].p_action); + } + + if(d->items) + PFREE(d->items); + PFREE(d); +} + +static void khui_menu_assert_size(khui_menu_def * d, size_t n) +{ + if(n > (int) d->nc_items) { + khui_action_ref * ni; + + d->nc_items = UBOUNDSS(n, MENU_NC_ITEMS, MENU_NC_ITEMS); + ni = PMALLOC(sizeof(*(d->items)) * d->nc_items); + memcpy(ni, d->items, sizeof(*(d->items)) * d->n_items); + PFREE(d->items); + d->items = ni; + } +} + +KHMEXP void KHMAPI khui_menu_add_action(khui_menu_def * d, int id) +{ + khui_menu_assert_size(d, d->n_items + 1); + d->items[d->n_items].flags = 0; + d->items[d->n_items ++].action = id; +} + +KHMEXP void KHMAPI khui_menu_add_paction(khui_menu_def * d, khui_action * act, int flags) +{ + khui_menu_assert_size(d, d->n_items + 1); + d->items[d->n_items].flags = flags | KHUI_ACTIONREF_PACTION; + d->items[d->n_items ++].p_action = act; +} + +KHMEXP khui_menu_def * KHMAPI khui_find_menu(int id) { + khui_menu_def * d; + int i; + + d = khui_all_menus; + for(i=0;i<khui_n_all_menus;i++) { + if(id == d[i].cmd) + return &d[i]; + } + + return NULL; +} + +KHMEXP khui_action * KHMAPI khui_find_action(int id) { + khui_action * act; + int i; + + act = khui_actions; + for(i=0;i<khui_n_actions;i++) { + if(act[i].cmd == id) + return &act[i]; + } + + return NULL; +} + +KHMEXP khui_action * KHMAPI khui_find_named_action(wchar_t * name) { + int i; + khui_action * act; + + if(!name) + return NULL; + + act = khui_actions; + for(i=0;i<khui_n_actions;i++) { + if(!act[i].name) + continue; + if(!wcscmp(act[i].name, name)) + return &act[i]; + } + + return NULL; +} + +KHMEXP size_t KHMAPI khui_action_list_length(khui_action_ref * ref) { + size_t c = 0; + while(ref && ref->action != KHUI_MENU_END) { + c++; + ref++; + } + return c; +} + +KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd) +{ + khui_action_ref * r; + khui_action * act; + + r = d->items; + while(r && r->action != KHUI_MENU_END) { + if(r->flags & KHUI_ACTIONREF_PACTION) { + act = r->p_action; + } else { + act = khui_find_action(r->action); + } + + if(act) { + if(act->cmd == cmd) + act->state |= KHUI_ACTIONSTATE_CHECKED; + else + act->state &= ~KHUI_ACTIONSTATE_CHECKED; + } + r++; + } + + kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); +} + +KHMEXP void KHMAPI khui_check_action(int cmd, khm_boolean check) { + khui_action * act; + + act = khui_find_action(cmd); + if (!act) + return; + + if (check && !(act->state & KHUI_ACTIONSTATE_CHECKED)) + act->state |= KHUI_ACTIONSTATE_CHECKED; + else if (!check && (act->state & KHUI_ACTIONSTATE_CHECKED)) + act->state &= ~KHUI_ACTIONSTATE_CHECKED; + else + return; + + kmq_post_message(KMSG_ACT, KMSG_ACT_CHECK, 0, 0); +} + +KHMEXP void KHMAPI khui_enable_actions(khui_menu_def * d, khm_boolean enable) +{ + khui_action_ref * r; + int delta = FALSE; + khui_action * act; + + r = d->items; + while(r && r->action != KHUI_MENU_END) { + if(r->flags & KHUI_ACTIONREF_PACTION) { + act = r->p_action; + } else { + act = khui_find_action(r->action); + } + + if(act) { + int old_state = act->state; + + if(enable) + act->state &= ~KHUI_ACTIONSTATE_DISABLED; + else + act->state |= KHUI_ACTIONSTATE_DISABLED; + + if(old_state != act->state) + delta = TRUE; + } + r++; + } + + if(delta) { + kmq_post_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); + } +} + +KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable) { + khui_action * act; + + act = khui_find_action(cmd); + if (!act) + return; + + if (enable && (act->state & KHUI_ACTIONSTATE_DISABLED)) { + act->state &= ~KHUI_ACTIONSTATE_DISABLED; + } else if (!enable && !(act->state & KHUI_ACTIONSTATE_DISABLED)) { + act->state |= KHUI_ACTIONSTATE_DISABLED; + } else + return; + + kmq_post_message(KMSG_ACT, KMSG_ACT_ENABLE, 0, 0); +} + +KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void) { + int i; + ACCEL * accels; + HACCEL ha; + + accels = PMALLOC(sizeof(ACCEL) * khui_n_accel_global); + for(i=0;i<khui_n_accel_global;i++) { + accels[i].cmd = khui_accel_global[i].cmd; + accels[i].fVirt = khui_accel_global[i].mod; + accels[i].key = khui_accel_global[i].key; + } + + ha = CreateAcceleratorTable(accels, khui_n_accel_global); + + PFREE(accels); + + return ha; +} + +KHMEXP khm_boolean KHMAPI +khui_get_cmd_accel_string(int cmd, + wchar_t * buf, + size_t bufsiz) { + int i; + khui_accel_def * def; + + /* should at least hold 2 characters */ + if(bufsiz < sizeof(wchar_t) * 2) + return FALSE; + + buf[0] = L'\0'; + + for(i=0;i<khui_n_accel_global;i++) { + if(khui_accel_global[i].cmd == cmd) + break; + } + + if(i==khui_n_accel_global) + return FALSE; + + def = &khui_accel_global[i]; + + if(def->mod & FALT) { + if(FAILED(StringCbCat(buf, bufsiz, L"ALT+"))) + return FALSE; + } + + + if(def->mod & FCONTROL) { + if(FAILED(StringCbCat(buf, bufsiz, L"CTRL+"))) + return FALSE; + } + + if(def->mod & FSHIFT) { + if(FAILED(StringCbCat(buf, bufsiz, L"SHIFT+"))) + return FALSE; + } + + if(def->mod & FVIRTKEY) { + wchar_t mbuf[6]; + wchar_t * ap = NULL; + switch(def->key) { + case VK_TAB: + ap = L"Tab"; + break; + + case VK_ESCAPE: + ap = L"Esc"; + break; + + case VK_RETURN: + ap = L"Enter"; + break; + + case VK_F5: + ap = L"F5"; + break; + + case VK_DELETE: + ap = L"Del"; + break; + + default: + if((def->key >= '0' && + def->key <= '9') || + (def->key >= 'A' && + def->key <= 'Z')) { + ap = mbuf; + mbuf[0] = (wchar_t) def->key; + mbuf[1] = L'\0'; + } + } + if(ap) { + if(FAILED(StringCbCat(buf, bufsiz, ap))) + return FALSE; + } + else { + if(FAILED(StringCbCat(buf, bufsiz,L"???"))) + return FALSE; + } + + } else { + wchar_t mbuf[2]; + + mbuf[0] = def->key; + mbuf[1] = L'\0'; + + if(FAILED(StringCbCat(buf, bufsiz, mbuf))) + return FALSE; + } + + return TRUE; +} + +/******************************************/ +/* contexts */ + +#define KHUI_ACTION_CONTEXT_MAGIC 0x39c49db5 + +static khm_int32 KHMAPI +khuiint_filter_selected(khm_handle cred, + khm_int32 vflags, + void * rock) { + khm_int32 flags; + if (KHM_SUCCEEDED(kcdb_cred_get_flags(cred, &flags)) && + (flags & KCDB_CRED_FLAG_SELECTED)) + return TRUE; + else + return FALSE; +} + +static void +khuiint_context_release(khui_action_context * ctx) { + ctx->scope = KHUI_SCOPE_NONE; + if (ctx->identity) + kcdb_identity_release(ctx->identity); + ctx->identity = NULL; + ctx->cred_type = KCDB_CREDTYPE_INVALID; + if (ctx->cred) + kcdb_cred_release(ctx->cred); + ctx->cred = NULL; + ctx->n_headers = 0; + if (ctx->credset) + kcdb_credset_flush(ctx->credset); + ctx->n_sel_creds = 0; + ctx->int_cb_used = 0; + ctx->vparam = NULL; + ctx->cb_vparam = 0; +} + +static void +khuiint_copy_context(khui_action_context * ctxdest, + const khui_action_context * ctxsrc) +{ + ctxdest->scope = ctxsrc->scope; + + if (ctxsrc->scope == KHUI_SCOPE_IDENT) { + ctxdest->identity = ctxsrc->identity; + kcdb_identity_hold(ctxsrc->identity); + } else if (ctxsrc->scope == KHUI_SCOPE_CREDTYPE) { + ctxdest->identity = ctxsrc->identity; + ctxdest->cred_type = ctxsrc->cred_type; + if (ctxsrc->identity != NULL) + kcdb_identity_hold(ctxsrc->identity); + } else if (ctxsrc->scope == KHUI_SCOPE_CRED) { + kcdb_cred_get_identity(ctxsrc->cred, &ctxdest->identity); + kcdb_cred_get_type(ctxsrc->cred, &ctxdest->cred_type); + ctxdest->cred = ctxsrc->cred; + kcdb_cred_hold(ctxsrc->cred); + } else if (ctxsrc->scope == KHUI_SCOPE_GROUP) { + khm_size cb_total; + int i; + + ctxdest->n_headers = ctxsrc->n_headers; + cb_total = 0; + for (i=0; i < (int) ctxsrc->n_headers; i++) { + cb_total += UBOUND32(ctxsrc->headers[i].cb_data); + } + + if (ctxdest->int_cb_buf < cb_total) { + + if (ctxdest->int_buf) + PFREE(ctxdest->int_buf); + + ctxdest->int_cb_buf = cb_total; + ctxdest->int_buf = PMALLOC(cb_total); + } + +#ifdef DEBUG + assert(ctxdest->int_buf || cb_total == 0); +#endif + ctxdest->int_cb_used = 0; + + for (i=0; i < (int) ctxsrc->n_headers; i++) { + ctxdest->headers[i].attr_id = ctxsrc->headers[i].attr_id; + ctxdest->headers[i].cb_data = ctxsrc->headers[i].cb_data; + if (ctxsrc->headers[i].cb_data > 0) { + ctxdest->headers[i].data = + BYTEOFFSET(ctxdest->int_buf, + ctxdest->int_cb_used); + memcpy(ctxdest->headers[i].data, + ctxsrc->headers[i].data, + ctxsrc->headers[i].cb_data); + ctxdest->int_cb_used += + UBOUND32(ctxsrc->headers[i].cb_data); + } else { + ctxdest->headers[i].data = NULL; + } + } + } + + if (ctxsrc->credset) { + + if (ctxdest->credset == NULL) + kcdb_credset_create(&ctxdest->credset); +#ifdef DEBUG + assert(ctxdest->credset != NULL); +#endif + + kcdb_credset_flush(ctxdest->credset); + + kcdb_credset_extract_filtered(ctxdest->credset, + ctxsrc->credset, + khuiint_filter_selected, + NULL); + + kcdb_credset_get_size(ctxdest->credset, + &ctxdest->n_sel_creds); + } else { + if (ctxdest->credset != NULL) + kcdb_credset_flush(ctxdest->credset); + ctxdest->n_sel_creds = 0; + } + + /* For now, we simply transfer the vparam buffer into the new + context. If we are copying, we also need to modify + khui_context_release() to free the allocated buffer */ +#if 0 + if (ctxsrc->vparam && ctxsrc->cb_vparam) { + ctxdest->vparam = PMALLOC(ctxsrc->cb_vparam); +#ifdef DEBUG + assert(ctxdest->vparam); +#endif + memcpy(ctxdest->vparam, ctxsrc->vparam, ctxsrc->cb_vparam); + ctxdest->cb_vparam = ctxsrc->cb_vparam; + } else { +#endif + ctxdest->vparam = ctxsrc->vparam; + ctxdest->cb_vparam = ctxsrc->cb_vparam; +#if 0 + } +#endif +} + +static void +khuiint_context_init(khui_action_context * ctx) { + ctx->magic = KHUI_ACTION_CONTEXT_MAGIC; + ctx->scope = KHUI_SCOPE_NONE; + ctx->identity = NULL; + ctx->cred_type = KCDB_CREDTYPE_INVALID; + ctx->cred = NULL; + ZeroMemory(ctx->headers, sizeof(ctx->headers)); + ctx->n_headers = 0; + ctx->credset = NULL; + ctx->n_sel_creds = 0; + ctx->int_buf = NULL; + ctx->int_cb_buf = 0; + ctx->int_cb_used = 0; + ctx->vparam = NULL; + ctx->cb_vparam = 0; +} + +khui_action_context khui_ctx = { + KHUI_ACTION_CONTEXT_MAGIC, + KHUI_SCOPE_NONE, + NULL, + KCDB_CREDTYPE_INVALID, + NULL, + { + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0}, + {KCDB_ATTR_INVALID,NULL,0} + }, + 0, + NULL, + 0, + NULL, + 0, + 0, + NULL, + 0}; + +KHMEXP void KHMAPI +khui_context_create(khui_action_context * ctx, + khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred) +{ + khui_action_context tctx; + + khuiint_context_init(&tctx); + khuiint_context_init(ctx); + + tctx.scope = scope; + tctx.identity = identity; + tctx.cred_type = cred_type; + tctx.cred = cred; + + khuiint_copy_context(ctx, &tctx); +} + +KHMEXP void KHMAPI +khui_context_set(khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred, + khui_header *headers, + khm_size n_headers, + khm_handle cs_src) { + + khui_context_set_ex(scope, + identity, + cred_type, + cred, + headers, + n_headers, + cs_src, + NULL, + 0); +} + +KHMEXP void KHMAPI +khui_context_set_ex(khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred, + khui_header *headers, + khm_size n_headers, + khm_handle cs_src, + void * vparam, + khm_size cb_vparam) +{ + khui_action_context tctx; + + EnterCriticalSection(&cs_actions); + + khuiint_context_release(&khui_ctx); + + khuiint_context_init(&tctx); + + tctx.scope = scope; + tctx.identity = identity; + tctx.cred_type = cred_type; + tctx.cred = cred; + if (headers) { + tctx.n_headers = n_headers; + memcpy(tctx.headers, + headers, + sizeof(*headers) * n_headers); + } else { + tctx.n_headers = 0; + } + tctx.credset = cs_src; + tctx.n_sel_creds = 0; /* ignored */ + tctx.vparam = vparam; + tctx.cb_vparam = cb_vparam; + tctx.int_buf = NULL; + tctx.int_cb_buf = 0; + tctx.int_cb_used = 0; + + khuiint_copy_context(&khui_ctx, &tctx); + + khui_context_refresh(); + + LeaveCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_context_refresh(void) { + khm_int32 flags; + + EnterCriticalSection(&cs_actions); + if (khui_ctx.identity) { + /* an identity is selected */ + + if (KHM_SUCCEEDED(kcdb_identity_get_flags(khui_ctx.identity, + &flags)) && + (flags & KCDB_IDENT_FLAG_DEFAULT)) { + khui_check_action(KHUI_ACTION_SET_DEF_ID, TRUE); + khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE); + } else { + khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE); + khui_enable_action(KHUI_ACTION_SET_DEF_ID, TRUE); + } + + khui_enable_action(KHUI_ACTION_PASSWD_ID, TRUE); + } else { + khui_check_action(KHUI_ACTION_SET_DEF_ID, FALSE); + khui_enable_action(KHUI_ACTION_SET_DEF_ID, FALSE); + khui_enable_action(KHUI_ACTION_PASSWD_ID, FALSE); + } + + if (khui_ctx.scope != KHUI_SCOPE_NONE) { + khui_enable_action(KHUI_ACTION_PROPERTIES, TRUE); + khui_enable_action(KHUI_ACTION_DESTROY_CRED, TRUE); + khui_enable_action(KHUI_ACTION_RENEW_CRED, TRUE); + } else { + khui_enable_action(KHUI_ACTION_PROPERTIES, FALSE); + khui_enable_action(KHUI_ACTION_DESTROY_CRED, FALSE); + khui_enable_action(KHUI_ACTION_RENEW_CRED, FALSE); + } + + LeaveCriticalSection(&cs_actions); + + kmq_post_message(KMSG_ACT, KMSG_ACT_REFRESH, 0, 0); +} + +KHMEXP void KHMAPI +khui_context_get(khui_action_context * ctx) +{ + EnterCriticalSection(&cs_actions); + + khuiint_context_init(ctx); + khuiint_copy_context(ctx, &khui_ctx); + + if (ctx->credset) { + kcdb_credset_seal(ctx->credset); + } + + LeaveCriticalSection(&cs_actions); +} + +KHMEXP void KHMAPI +khui_context_release(khui_action_context * ctx) +{ +#ifdef DEBUG + assert(ctx->magic == KHUI_ACTION_CONTEXT_MAGIC); +#endif + + khuiint_context_release(ctx); + if (ctx->credset) { + kcdb_credset_unseal(ctx->credset); + kcdb_credset_delete(ctx->credset); + } + ctx->credset = NULL; + if (ctx->int_buf) + PFREE(ctx->int_buf); + ctx->int_buf = NULL; +#if 0 + if (ctx->vparam && ctx->cb_vparam > 0) { + PFREE(ctx->vparam); + ctx->vparam = NULL; + } + ctx->cb_vparam = 0; +#else + ctx->vparam = 0; + ctx->cb_vparam = 0; +#endif +} + +KHMEXP void KHMAPI +khui_context_reset(void) +{ + EnterCriticalSection(&cs_actions); + + khuiint_context_release(&khui_ctx); + + khui_context_refresh(); + + LeaveCriticalSection(&cs_actions); +} + +KHMEXP khm_int32 KHMAPI +khui_context_cursor_filter(khm_handle cred, + khm_int32 flags, + void * rock) { + khui_action_context * ctx = (khui_action_context *) rock; + khm_int32 rv; + + if (ctx->scope == KHUI_SCOPE_NONE) + return 0; + else if (ctx->scope == KHUI_SCOPE_IDENT) { + khm_handle c_ident; + + if (KHM_FAILED(kcdb_cred_get_identity(cred, &c_ident))) + return 0; + + rv = (c_ident == ctx->identity); + + kcdb_identity_release(c_ident); + + return rv; + } else if (ctx->scope == KHUI_SCOPE_CREDTYPE) { + khm_handle c_ident; + khm_int32 c_type; + + if (KHM_FAILED(kcdb_cred_get_type(cred, &c_type)) || + c_type != ctx->cred_type) + return 0; + + if (ctx->identity == NULL) + return 1; + + if (KHM_FAILED(kcdb_cred_get_identity(cred, &c_ident))) + return 0; + + rv = (c_ident == ctx->identity); + + kcdb_identity_release(c_ident); + + return rv; + } else if (ctx->scope == KHUI_SCOPE_CRED) { + return kcdb_creds_is_equal(cred, ctx->cred); + } else if (ctx->scope == KHUI_SCOPE_GROUP) { + int i; + + rv = 1; + + for (i=0; i < (int) ctx->n_headers && rv; i++) { + kcdb_attrib * pattr; + kcdb_type * ptype; + DWORD buffer[1024]; /* 4096 bytes */ + khm_size cb; + + if (kcdb_cred_get_attr(cred, ctx->headers[i].attr_id, + NULL, + NULL, + &cb) != KHM_ERROR_TOO_LONG) { + /* the header doesn't exist anyway */ + rv = (ctx->headers[i].cb_data == 0); + continue; + } +#ifdef DEBUG + assert(cb <= sizeof(buffer)); +#endif + cb = sizeof(buffer); + + if (KHM_FAILED(kcdb_cred_get_attr(cred, + ctx->headers[i].attr_id, + NULL, + (void *) buffer, + &cb))) { + rv = 0; + continue; + } + + if (KHM_FAILED(kcdb_attrib_get_info(ctx->headers[i].attr_id, + &pattr))) { + rv = 0; + continue; + } + + if (KHM_FAILED(kcdb_type_get_info(pattr->type, &ptype))) { + rv = 0; + kcdb_attrib_release_info(pattr); + continue; + } + + if ((*ptype->comp)(ctx->headers[i].data, + ctx->headers[i].cb_data, + (void *) buffer, + cb) != 0) + rv = 1; + + kcdb_type_release_info(ptype); + kcdb_attrib_release_info(pattr); + } + + return rv; + } else + return 0; +} diff --git a/mechglue/src/windows/identity/uilib/actiondef.cfg b/mechglue/src/windows/identity/uilib/actiondef.cfg new file mode 100644 index 000000000..14600b0b6 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/actiondef.cfg @@ -0,0 +1,64 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +$file_prefix = <<EOS; +/* +This file was autogenerated from src/ui/actiondef.cfg and src/ui/actions.csv. + +Do not modify directly. +*/ + +#include<khuidefs.h> +#include<khhelp.h> +#include"../ui/resource.h" + +khui_action khui_actions [] = { +EOS + +$record_prefix = "{"; + +$record_sep = ",\n"; + +$record_postfix = "}"; + +$file_postfix = <<EOS; + +}; + +int khui_n_actions = sizeof(khui_actions) / sizeof(khui_action); + +EOS + +$skip_lines = 1; + +sub rec_handler { + $arr = shift; + if($$arr[2] =~ /^$/) { + $$arr[2] = "NULL"; + } else { + $$arr[2] = "L\"".$$arr[2]."\""; + } +} + +$record_parser = \&rec_handler; diff --git a/mechglue/src/windows/identity/uilib/actions.csv b/mechglue/src/windows/identity/uilib/actions.csv new file mode 100644 index 000000000..dd4949849 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/actions.csv @@ -0,0 +1,39 @@ +Command,Type,Name,Img Normal,Img Hot,Img Disabled,Ico Normal,Ico Disabled,Caption,Tooltip,Topic,State +KHUI_MENU_FILE,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_FILE,0,IDH_MENU_FILE,0 +KHUI_MENU_CRED,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_CRED,0,IDH_MENU_CRED,0 +KHUI_MENU_VIEW,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_VIEW,0,IDH_MENU_VIEW,0 +KHUI_MENU_OPTIONS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_OPTIONS,0,IDH_MENU_OPTIONS,0 +KHUI_MENU_HELP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_HELP,0,IDH_MENU_HELP,0 +KHUI_MENU_LAYOUT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_LAYOUT,0,0,0 +KHUI_MENU_TOOLBARS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_MENU_TOOLBARS,0,0,0 +KHUI_ACTION_PROPERTIES,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_PROPERTIES,0,IDH_ACTION_PROPERTIES,0 +KHUI_ACTION_EXIT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_EXIT,0,IDH_ACTION_EXIT,0 +KHUI_ACTION_SET_DEF_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_SET_DEF_ID,0,IDH_ACTION_SET_DEF_ID,0 +KHUI_ACTION_SET_SRCH_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_SET_SRCH_ID,0,IDH_ACTION_SET_SRCH_ID,KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_PASSWD_ID,KHUI_ACTIONTYPE_TRIGGER,,IDB_CHPW,0,IDB_CHPW_DIS,IDB_CHPW_SM,IDB_CHPW_DIS_SM,IDS_ACTION_PASSWD_ID,0,IDH_ACTION_PASSWD_ID,0 +KHUI_ACTION_NEW_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_NEW,0,IDB_TK_NEW_DIS,IDB_TK_NEW_SM,IDB_TK_NEW_DIS_SM,IDS_ACTION_NEW_CRED,0,IDH_ACTION_NEW_CRED,0 +KHUI_ACTION_RENEW_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_REFRESH,0,IDB_TK_REFRESH_DIS,IDB_TK_REFRESH_SM,IDB_TK_REFRESH_DIS_SM,IDS_ACTION_RENEW_CRED,0,0,0 +KHUI_ACTION_DESTROY_CRED,KHUI_ACTIONTYPE_TRIGGER,,IDB_TK_DELETE,0,IDB_TK_DELETE_DIS,IDB_TK_DELETE_SM,IDB_TK_DELETE_DIS_SM,IDS_ACTION_DESTROY_CRED,0,0,0 +KHUI_ACTION_LAYOUT_ID,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_ID,0,0,KHUI_ACTIONSTATE_CHECKED +KHUI_ACTION_LAYOUT_TYPE,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_TYPE,0,0,KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_LAYOUT_LOC,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_LAYOUT_LOC,0,0,0 +KHUI_ACTION_TB_STANDARD,KHUI_ACTIONTYPE_TRIGGER | KHUI_ACTIONTYPE_TOGGLE,,0,0,0,0,0,IDS_ACTION_TB_STANDARD,0,0,KHUI_ACTIONSTATE_CHECKED|KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_CHOOSE_COLS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_CHOOSE_COLS,0,IDH_ACTION_CHOOSE_COLS,KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_DEBUG_WINDOW,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_DEBUG_WINDOW,0,IDH_ACTION_DEBUG_WINDOW,KHUI_ACTIONSTATE_DISABLED +KHUI_ACTION_VIEW_REFRESH,KHUI_ACTIONTYPE_TRIGGER,,IDB_VW_REFRESH,0,0,IDB_VW_REFRESH_SM,0,IDS_ACTION_VIEW_REFRESH,0,IDH_ACTION_VIEW_REFRESH,0 +KHUI_ACTION_OPT_IDENTS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_IDENTS,0,IDH_ACTION_OPT_INIT,0 +KHUI_ACTION_OPT_KHIM,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_KHIM,0,IDH_ACTION_OPT_KHIM,0 +KHUI_ACTION_OPT_NOTIF,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_NOTIF,0,IDH_ACTION_OPT_NOTIF,0 +KHUI_ACTION_OPT_PLUGINS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPT_PLUGINS,0,IDH_ACTION_OPT_KHIM,0 +KHUI_ACTION_HELP_CTX,KHUI_ACTIONTYPE_TRIGGER,,IDB_HELP,0,0,IDB_HELP_SM,0,IDS_ACTION_HELP_CTX,0,0,0 +KHUI_ACTION_HELP_CONTENTS,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_CONTENTS,0,0,0 +KHUI_ACTION_HELP_INDEX,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_INDEX,0,0,0 +KHUI_ACTION_HELP_ABOUT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_HELP_ABOUT,0,0,0 +KHUI_ACTION_OPEN_APP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_OPEN_APP,0,0,0 +KHUI_ACTION_CLOSE_APP,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_ACTION_CLOSE_APP,0,0,0 +KHUI_ACTION_IMPORT,KHUI_ACTIONTYPE_TRIGGER,,IDB_IMPORT,0,IDB_IMPORT_DIS,IDB_IMPORT_SM,IDB_IMPORT_SM_DIS,IDS_ACTION_IMPORT,0,0,0 +KHUI_PACTION_OK,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_OK,0,0,0 +KHUI_PACTION_CANCEL,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_CANCEL,0,0,0 +KHUI_PACTION_CLOSE,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_CLOSE,0,0,0 +KHUI_PACTION_BLANK,0,,IDB_TB_SPACE,0,IDB_TB_SPACE,IDB_TB_BLANK_SM,IDB_TB_BLANK_SM,0,0,0,KHUI_ACTIONSTATE_DISABLED +KHUI_PACTION_NEXT,KHUI_ACTIONTYPE_TRIGGER,,0,0,0,0,0,IDS_PACTION_NEXT,0,0,0 diff --git a/mechglue/src/windows/identity/uilib/alert.c b/mechglue/src/windows/identity/uilib/alert.c new file mode 100644 index 000000000..dd096063b --- /dev/null +++ b/mechglue/src/windows/identity/uilib/alert.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<utils.h> +#include<assert.h> + +/*********************************************************************** + Alerter +***********************************************************************/ + +khui_alert * kh_alerts = NULL; +CRITICAL_SECTION cs_alerts; + +void +alert_init(void) +{ + InitializeCriticalSection(&cs_alerts); +} + +void +alert_exit(void) +{ + DeleteCriticalSection(&cs_alerts); +} + +KHMEXP khm_int32 KHMAPI +khui_alert_create_empty(khui_alert ** result) +{ + khui_alert * a; + + a = PMALLOC(sizeof(*a)); + ZeroMemory(a, sizeof(*a)); + + a->magic = KHUI_ALERT_MAGIC; + + /* set defaults */ + a->severity = KHERR_INFO; + a->flags = KHUI_ALERT_FLAG_FREE_STRUCT; + + khui_alert_hold(a); + EnterCriticalSection(&cs_alerts); + LPUSH(&kh_alerts, a); + LeaveCriticalSection(&cs_alerts); + + *result = a; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_create_simple(const wchar_t * title, + const wchar_t * message, + khm_int32 severity, + khui_alert ** result) +{ + khui_alert * a; + + khui_alert_create_empty(&a); + khui_alert_set_title(a, title); + khui_alert_set_message(a, message); + khui_alert_set_severity(a, severity); + + *result = a; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_title(khui_alert * alert, const wchar_t * title) +{ + size_t cb = 0; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + if(title) { + if(FAILED(StringCbLength(title, + KHUI_MAXCB_TITLE, + &cb))) { + return KHM_ERROR_INVALID_PARAM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->title && (alert->flags & KHUI_ALERT_FLAG_FREE_TITLE)) { + PFREE(alert->title); + alert->title = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE; + } + if(title) { + alert->title = PMALLOC(cb); + StringCbCopy(alert->title, cb, title); + alert->flags |= KHUI_ALERT_FLAG_FREE_TITLE; + } + LeaveCriticalSection(&cs_alerts); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_flags(khui_alert * alert, khm_int32 mask, khm_int32 flags) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + if (mask & ~KHUI_ALERT_FLAGMASK_RDWR) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_alerts); + alert->flags = + (alert->flags & ~mask) | + (flags & mask); + LeaveCriticalSection(&cs_alerts); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_severity(khui_alert * alert, khm_int32 severity) +{ + + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + alert->severity = severity; + LeaveCriticalSection(&cs_alerts); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_suggestion(khui_alert * alert, + const wchar_t * suggestion) { + size_t cb = 0; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + if(suggestion) { + if(FAILED(StringCbLength(suggestion, + KHUI_MAXCB_MESSAGE - sizeof(wchar_t), + &cb))) { + return KHM_ERROR_INVALID_PARAM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->suggestion && + (alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST)) { + + PFREE(alert->suggestion); + alert->suggestion = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST; + + } + + if(suggestion) { + alert->suggestion = PMALLOC(cb); + StringCbCopy(alert->suggestion, cb, suggestion); + alert->flags |= KHUI_ALERT_FLAG_FREE_SUGGEST; + } + LeaveCriticalSection(&cs_alerts); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_set_message(khui_alert * alert, const wchar_t * message) +{ + size_t cb = 0; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + if(message) { + if(FAILED(StringCbLength(message, + KHUI_MAXCB_MESSAGE - sizeof(wchar_t), + &cb))) { + return KHM_ERROR_INVALID_PARAM; + } + cb += sizeof(wchar_t); + } + + EnterCriticalSection(&cs_alerts); + if(alert->message && + (alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE)) { + + PFREE(alert->message); + alert->message = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; + + } + + if(message) { + alert->message = PMALLOC(cb); + StringCbCopy(alert->message, cb, message); + alert->flags |= KHUI_ALERT_FLAG_FREE_MESSAGE; + } + LeaveCriticalSection(&cs_alerts); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_clear_commands(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + alert->n_alert_commands = 0; + LeaveCriticalSection(&cs_alerts); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_add_command(khui_alert * alert, khm_int32 command_id) +{ + khm_int32 rv = KHM_ERROR_SUCCESS; + + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + if(alert->n_alert_commands >= KHUI_MAX_ALERT_COMMANDS) + rv = KHM_ERROR_NO_RESOURCES; + else { + alert->alert_commands[alert->n_alert_commands++] = command_id; + } + LeaveCriticalSection(&cs_alerts); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_show(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + khui_alert_hold(alert); + /* the alert will be released when the message is processed */ + kmq_post_message(KMSG_ALERT, KMSG_ALERT_SHOW, 0, (void *) alert); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_queue(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + khui_alert_hold(alert); + kmq_post_message(KMSG_ALERT, KMSG_ALERT_QUEUE, 0, (void *) alert); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_show_simple(const wchar_t * title, + const wchar_t * message, + khm_int32 severity) +{ + khui_alert * a = NULL; + khm_int32 rv; + + rv = khui_alert_create_simple(title, message, severity, &a); + + if(KHM_FAILED(rv)) + return rv; + + rv = khui_alert_show(a); + + khui_alert_release(a); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_alert_hold(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + alert->refcount++; + LeaveCriticalSection(&cs_alerts); + return KHM_ERROR_SUCCESS; +} + +/* called with cs_alert held */ +static void +free_alert(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + LDELETE(&kh_alerts, alert); + + if(alert->flags & KHUI_ALERT_FLAG_FREE_TITLE) { + assert(alert->title); + PFREE(alert->title); + alert->title = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_TITLE; + } + if(alert->flags & KHUI_ALERT_FLAG_FREE_MESSAGE) { + assert(alert->message); + PFREE(alert->message); + alert->message = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_MESSAGE; + } + if(alert->flags & KHUI_ALERT_FLAG_FREE_SUGGEST) { + assert(alert->suggestion); + PFREE(alert->suggestion); + alert->suggestion = NULL; + alert->flags &= ~KHUI_ALERT_FLAG_FREE_SUGGEST; + } + if(alert->flags & KHUI_ALERT_FLAG_FREE_STRUCT) { + alert->flags &= ~KHUI_ALERT_FLAG_FREE_STRUCT; + alert->magic = 0; + PFREE(alert); + } +} + +KHMEXP khm_int32 KHMAPI +khui_alert_release(khui_alert * alert) +{ + assert(alert->magic == KHUI_ALERT_MAGIC); + + EnterCriticalSection(&cs_alerts); + if((--(alert->refcount)) == 0) { + free_alert(alert); + } + LeaveCriticalSection(&cs_alerts); + return KHM_ERROR_SUCCESS; +} + +KHMEXP void KHMAPI khui_alert_lock(khui_alert * alert) +{ + EnterCriticalSection(&cs_alerts); +} + +KHMEXP void KHMAPI khui_alert_unlock(khui_alert * alert) +{ + LeaveCriticalSection(&cs_alerts); +} diff --git a/mechglue/src/windows/identity/uilib/configui.c b/mechglue/src/windows/identity/uilib/configui.c new file mode 100644 index 000000000..51498c0b2 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/configui.c @@ -0,0 +1,1048 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<kmm.h> +#include<configui.h> +#include<utils.h> +#include<assert.h> + +khm_int32 cfgui_node_serial; +LONG init_once = 0; +CRITICAL_SECTION cs_cfgui; +khui_config_node_i * cfgui_root_config; +HWND hwnd_cfgui = NULL; + +static khui_config_node_i * +cfgui_create_new_node(void) { + khui_config_node_i * node; + + node = PMALLOC(sizeof(*node)); +#ifdef DEBUG + assert(node); +#endif + ZeroMemory(node, sizeof(*node)); + node->magic = KHUI_CONFIG_NODE_MAGIC; + + EnterCriticalSection(&cs_cfgui); + node->id = ++cfgui_node_serial; + LeaveCriticalSection(&cs_cfgui); + + return node; +} + +/* called with cs_cfgui held */ +static void +cfgui_free_node(khui_config_node_i * node) { + if (!cfgui_is_valid_node(node)) + return; + + if (node->reg.name) + PFREE((void *) node->reg.name); + + if (node->reg.short_desc) + PFREE((void *) node->reg.short_desc); + + if (node->reg.long_desc) + PFREE((void *) node->reg.long_desc); + + node->magic = 0; + + if (node->owner) + kmm_release_plugin(node->owner); + + ZeroMemory(node, sizeof(*node)); + + PFREE(node); +} + + +static void +cfgui_hold_node(khui_config_node_i * node) { + EnterCriticalSection(&cs_cfgui); + node->refcount++; + LeaveCriticalSection(&cs_cfgui); +} + + +static void +cfgui_release_node(khui_config_node_i * node) { + EnterCriticalSection(&cs_cfgui); + node->refcount--; + if (node->refcount == 0 && + (node->flags & KHUI_CN_FLAG_DELETED)) { + khui_config_node_i * parent; + parent = TPARENT(node); +#ifdef DEBUG + assert(TFIRSTCHILD(node) == NULL); + assert(parent != NULL); +#endif + TDELCHILD(parent, node); + cfgui_free_node(node); + cfgui_release_node(parent); + } + LeaveCriticalSection(&cs_cfgui); +} + +static void +cfgui_init_once(void) { + if (init_once == 0 && + InterlockedIncrement(&init_once) == 1) { + InitializeCriticalSection(&cs_cfgui); + cfgui_root_config = cfgui_create_new_node(); + cfgui_node_serial = 0; + hwnd_cfgui = NULL; + } +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_register(khui_config_node vparent, + const khui_config_node_reg * reg) { + + size_t cb_name; + size_t cb_short_desc; + size_t cb_long_desc; + khui_config_node_i * node; + khui_config_node_i * parent; + khui_config_node t; + wchar_t * name; + wchar_t * short_desc; + wchar_t * long_desc; + + cfgui_init_once(); + + if (!reg || + FAILED(StringCbLength(reg->name, + KHUI_MAXCB_NAME, + &cb_name)) || + FAILED(StringCbLength(reg->short_desc, + KHUI_MAXCB_SHORT_DESC, + &cb_short_desc)) || + FAILED(StringCbLength(reg->long_desc, + KHUI_MAXCB_LONG_DESC, + &cb_long_desc)) || + (vparent && + !cfgui_is_valid_node_handle(vparent))) + return KHM_ERROR_INVALID_PARAM; + + if (KHM_SUCCEEDED(khui_cfg_open(vparent, + reg->name, + &t))) { + khui_cfg_release(t); + return KHM_ERROR_DUPLICATE; + } + + cb_name += sizeof(wchar_t); + cb_short_desc += sizeof(wchar_t); + cb_long_desc += sizeof(wchar_t); + + node = cfgui_create_new_node(); + + node->reg = *reg; + node->reg.flags &= KHUI_CNFLAGMASK_STATIC; + + name = PMALLOC(cb_name); + StringCbCopy(name, cb_name, reg->name); + short_desc = PMALLOC(cb_short_desc); + StringCbCopy(short_desc, cb_short_desc, reg->short_desc); + long_desc = PMALLOC(cb_long_desc); + StringCbCopy(long_desc, cb_long_desc, reg->long_desc); + + node->reg.name = name; + node->reg.short_desc = short_desc; + node->reg.long_desc = long_desc; + node->flags = node->reg.flags; + + if (vparent == NULL) { + parent = cfgui_root_config; + } else { + parent = cfgui_node_i_from_handle(vparent); + } + + //node->owner = kmm_this_plugin(); + + EnterCriticalSection(&cs_cfgui); + TADDCHILD(parent, node); + LeaveCriticalSection(&cs_cfgui); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_open(khui_config_node vparent, + const wchar_t * name, + khui_config_node * result) { + khui_config_node_i * parent; + khui_config_node_i * c; + size_t sz; + + cfgui_init_once(); + + if ((vparent && + !cfgui_is_valid_node_handle(vparent)) || + FAILED(StringCbLength(name, KHUI_MAXCCH_NAME, &sz)) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (vparent) + parent = cfgui_node_i_from_handle(vparent); + else + parent = cfgui_root_config; + + c = TFIRSTCHILD(parent); + while(c) { + if (!(c->flags & KHUI_CN_FLAG_DELETED) && + !wcscmp(c->reg.name, name)) + break; + c = LNEXT(c); + } + + if (c) { + *result = cfgui_handle_from_node_i(c); + cfgui_hold_node(c); + } else { + *result = NULL; + } + LeaveCriticalSection(&cs_cfgui); + + if (*result) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_remove(khui_config_node vnode) { + khui_config_node_i * node; + if (!cfgui_is_valid_node_handle(vnode)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + node = cfgui_node_i_from_handle(vnode); + node->flags |= KHUI_CN_FLAG_DELETED; + LeaveCriticalSection(&cs_cfgui); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_hold(khui_config_node vnode) { + if (!cfgui_is_valid_node_handle(vnode)) + return KHM_ERROR_INVALID_PARAM; + + cfgui_hold_node(cfgui_node_i_from_handle(vnode)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_release(khui_config_node vnode) { + if (!cfgui_is_valid_node_handle(vnode)) + return KHM_ERROR_INVALID_PARAM; + + cfgui_release_node(cfgui_node_i_from_handle(vnode)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_parent(khui_config_node vnode, + khui_config_node * result) { + + khui_config_node_i * node; + khui_config_node_i * parent; + + if(!cfgui_is_valid_node_handle(vnode) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + node = cfgui_node_i_from_handle(vnode); + parent = TPARENT(node); + if (parent == cfgui_root_config) + parent = NULL; + } else { + parent = NULL; + } + if (parent) { + cfgui_hold_node(parent); + } + LeaveCriticalSection(&cs_cfgui); + + *result = parent; + + if (parent) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_first_child(khui_config_node vparent, + khui_config_node * result) { + khui_config_node_i * parent; + khui_config_node_i * c; + + cfgui_init_once(); + + if((vparent && !cfgui_is_valid_node_handle(vparent)) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vparent)) { + parent = cfgui_node_i_from_handle(vparent); + } else if (!vparent) { + parent = cfgui_root_config; + } else { + parent = NULL; + } + + if (parent) { + for(c = TFIRSTCHILD(parent); + c && (c->reg.flags & KHUI_CNFLAG_SUBPANEL); + c = LNEXT(c)); + } else { + c = NULL; + } + + if (c) + cfgui_hold_node(c); + LeaveCriticalSection(&cs_cfgui); + + *result = c; + + if (c) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_first_subpanel(khui_config_node vparent, + khui_config_node * result) { + khui_config_node_i * parent; + khui_config_node_i * c; + + cfgui_init_once(); + + if((vparent && !cfgui_is_valid_node_handle(vparent)) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vparent)) { + parent = cfgui_node_i_from_handle(vparent); + } else if (!vparent) { + parent = cfgui_root_config; + } else { + parent = NULL; + } + + if (parent) { + for(c = TFIRSTCHILD(parent); + c && !(c->reg.flags & KHUI_CNFLAG_SUBPANEL); + c = LNEXT(c)); + } else { + c = NULL; + } + + if (c) + cfgui_hold_node(c); + LeaveCriticalSection(&cs_cfgui); + + *result = c; + + if (c) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_next(khui_config_node vnode, + khui_config_node * result) { + + khui_config_node_i * node; + khui_config_node_i * nxt_node; + + if (!cfgui_is_valid_node_handle(vnode) || + !result) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + node = cfgui_node_i_from_handle(vnode); + for(nxt_node = LNEXT(node); + nxt_node && + ((node->reg.flags ^ nxt_node->reg.flags) & + KHUI_CNFLAG_SUBPANEL); + nxt_node = LNEXT(nxt_node)); + if (nxt_node) + cfgui_hold_node(nxt_node); + } else { + nxt_node = NULL; + } + LeaveCriticalSection(&cs_cfgui); + + *result = cfgui_handle_from_node_i(nxt_node); + + if (nxt_node) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_next_release(khui_config_node * pvnode) { + + khui_config_node_i * node; + khui_config_node_i * nxt_node; + + if (!pvnode || + !cfgui_is_valid_node_handle(*pvnode)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(*pvnode)) { + node = cfgui_node_i_from_handle(*pvnode); + for(nxt_node = LNEXT(node); + nxt_node && + ((node->reg.flags ^ nxt_node->reg.flags) & + KHUI_CNFLAG_SUBPANEL); + nxt_node = LNEXT(nxt_node)); + if (nxt_node) + cfgui_hold_node(nxt_node); + cfgui_release_node(node); + } else { + nxt_node = NULL; + } + LeaveCriticalSection(&cs_cfgui); + + *pvnode = cfgui_handle_from_node_i(nxt_node); + + if (nxt_node) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_reg(khui_config_node vnode, + khui_config_node_reg * reg) { + + khui_config_node_i * node; + + cfgui_init_once(); + + if ((vnode && !cfgui_is_valid_node_handle(vnode)) || + !reg) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) { + node = cfgui_node_i_from_handle(vnode); + *reg = node->reg; + } else if (!vnode) { + node = cfgui_root_config; + *reg = node->reg; + } else { + node = NULL; + ZeroMemory(reg, sizeof(*reg)); + } + LeaveCriticalSection(&cs_cfgui); + + if (node) + return KHM_ERROR_SUCCESS; + else + return KHM_ERROR_INVALID_PARAM; +} + +KHMEXP HWND KHMAPI +khui_cfg_get_hwnd(khui_config_node vnode) { + khui_config_node_i * node; + HWND hwnd; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return NULL; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) + hwnd = node->hwnd; + else + hwnd = NULL; + LeaveCriticalSection(&cs_cfgui); + + return hwnd; +} + +KHMEXP LPARAM KHMAPI +khui_cfg_get_param(khui_config_node vnode) { + khui_config_node_i * node; + LPARAM param; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return 0; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) + param = node->param; + else + param = 0; + LeaveCriticalSection(&cs_cfgui); + + return param; +} + +KHMEXP void KHMAPI +khui_cfg_set_hwnd(khui_config_node vnode, HWND hwnd) { + khui_config_node_i * node; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) + node->hwnd = hwnd; + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP void KHMAPI +khui_cfg_set_param(khui_config_node vnode, LPARAM param) { + khui_config_node_i * node; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) + node->param = param; + LeaveCriticalSection(&cs_cfgui); +} + +static cfg_node_data * +get_node_data(khui_config_node_i * node, + void * key, + khm_boolean create) { + khm_size i; + + for (i=0; i<node->n_data; i++) { + if (node->data[i].key == key) + return &(node->data[i]); + } + + if (!create) + return NULL; + + if (node->n_data + 1 > node->nc_data) { + cfg_node_data * newdata; + + node->nc_data = UBOUNDSS((node->n_data + 1), + KHUI_NODEDATA_ALLOC_INCR, + KHUI_NODEDATA_ALLOC_INCR); +#ifdef DEBUG + assert(node->nc_data >= node->n_data + 1); +#endif + newdata = PMALLOC(sizeof(*newdata) * node->nc_data); +#ifdef DEBUG + assert(newdata); +#endif + ZeroMemory(newdata, sizeof(*newdata) * node->nc_data); + + if (node->data && node->n_data > 0) { + memcpy(newdata, node->data, node->n_data * sizeof(*newdata)); + PFREE(node->data); + } + node->data = newdata; + } + + node->data[node->n_data].key = key; + node->n_data++; + + return &(node->data[node->n_data - 1]); +} + +KHMEXP HWND KHMAPI +khui_cfg_get_hwnd_inst(khui_config_node vnode, + khui_config_node noderef) { + khui_config_node_i * node; + cfg_node_data * data; + HWND hwnd; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return NULL; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) { + data = get_node_data(node, noderef, FALSE); + if (data) + hwnd = data->hwnd; + else + hwnd = NULL; + } else + hwnd = NULL; + LeaveCriticalSection(&cs_cfgui); + + return hwnd; +} + +KHMEXP LPARAM KHMAPI +khui_cfg_get_param_inst(khui_config_node vnode, + khui_config_node noderef) { + khui_config_node_i * node; + cfg_node_data * data; + LPARAM lParam; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return 0; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) { + data = get_node_data(node, noderef, FALSE); + if (data) + lParam = data->param; + else + lParam = 0; + } else + lParam = 0; + LeaveCriticalSection(&cs_cfgui); + + return lParam; +} + +KHMEXP void KHMAPI +khui_cfg_set_hwnd_inst(khui_config_node vnode, + khui_config_node noderef, + HWND hwnd) { + khui_config_node_i * node; + cfg_node_data * data; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) { + data = get_node_data(node, noderef, TRUE); + if (data) + data->hwnd = hwnd; + } + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP void KHMAPI +khui_cfg_set_param_inst(khui_config_node vnode, + khui_config_node noderef, + LPARAM param) { + khui_config_node_i * node; + cfg_node_data * data; + + cfgui_init_once(); + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode)) + node = cfgui_node_i_from_handle(vnode); + else if (!vnode) + node = cfgui_root_config; + else + node = NULL; + + if (node) { + data = get_node_data(node, noderef, TRUE); + if (data) + data->param = param; + } + LeaveCriticalSection(&cs_cfgui); +} + + +/* called with cs_cfgui held */ +static void +cfgui_clear_params(khui_config_node_i * node) { + khui_config_node_i * c; + + node->hwnd = NULL; + node->param = 0; + node->flags &= KHUI_CNFLAGMASK_STATIC; + c = TFIRSTCHILD(node); + while(c) { + cfgui_clear_params(c); + c = LNEXT(c); + } +} + +KHMEXP void KHMAPI +khui_cfg_clear_params(void) { + + cfgui_init_once(); + + EnterCriticalSection(&cs_cfgui); + cfgui_clear_params(cfgui_root_config); + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP void KHMAPI +khui_cfg_set_configui_handle(HWND hwnd) { + EnterCriticalSection(&cs_cfgui); + hwnd_cfgui = hwnd; + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP void KHMAPI +khui_cfg_set_flags(khui_config_node vnode, + khm_int32 flags, + khm_int32 mask) { + khui_config_node_i * node; + khm_int32 newflags; + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return; + + mask &= KHUI_CNFLAGMASK_DYNAMIC; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode) && + hwnd_cfgui != NULL) { + + node = cfgui_node_i_from_handle(vnode); + + newflags = + (flags & mask) | + (node->flags & ~mask); + + if (newflags != node->flags) { + node->flags = newflags; + + if (hwnd_cfgui) + PostMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM((WORD)newflags, WMCFG_UPDATE_STATE), + (LPARAM) vnode); + } + } + LeaveCriticalSection(&cs_cfgui); +} + +/* called with cs_cfgui held */ +static void +recalc_node_flags(khui_config_node vnode, khm_boolean plural) { + khui_config_node_i * node; + khui_config_node_i * parent; + khui_config_node_i * subpanel; + cfg_node_data * data; + khm_int32 flags; + +#ifdef DEBUG + assert(cfgui_is_valid_node_handle(vnode)); +#endif + + node = cfgui_node_i_from_handle(vnode); + + if (plural) + parent = TPARENT(node); + else + parent = node; +#ifdef DEBUG + assert(parent); +#endif + + flags = 0; + + for(subpanel = TFIRSTCHILD(parent); subpanel; + subpanel = LNEXT(subpanel)) { + if (!(subpanel->reg.flags & KHUI_CNFLAG_SUBPANEL) || + (plural && !(subpanel->reg.flags & KHUI_CNFLAG_PLURAL)) || + (!plural && (subpanel->reg.flags & KHUI_CNFLAG_PLURAL))) + continue; + + data = get_node_data(subpanel, + vnode, + FALSE); + + if (data) { + flags |= data->flags; + } + } + + flags &= KHUI_CNFLAGMASK_DYNAMIC; + + if ((node->flags & KHUI_CNFLAGMASK_DYNAMIC) == flags) + return; + + node->flags = (node->flags & ~KHUI_CNFLAGMASK_DYNAMIC) | flags; + + if (hwnd_cfgui) + PostMessage(hwnd_cfgui, KHUI_WM_CFG_NOTIFY, + MAKEWPARAM((WORD) node->flags, WMCFG_UPDATE_STATE), + (LPARAM) vnode); +} + +KHMEXP void KHMAPI +khui_cfg_set_flags_inst(khui_config_init_data * d, + khm_int32 flags, + khm_int32 mask) { + khui_config_node_i * node; + cfg_node_data * data; + + cfgui_init_once(); + if (!cfgui_is_valid_node_handle(d->this_node)) + return; + + mask &= KHUI_CNFLAGMASK_DYNAMIC; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(d->this_node)) + node = cfgui_node_i_from_handle(d->this_node); + else + node = NULL; + + if (node) { + data = get_node_data(node, d->ctx_node, TRUE); + if (data) { + khm_int32 new_flags; + + new_flags = (flags & mask) | + (data->flags & ~mask); + + if (new_flags != data->flags) { + data->flags = new_flags; + + if (d->ctx_node != d->ref_node) + recalc_node_flags(d->ctx_node, TRUE); + else + recalc_node_flags(d->ctx_node, FALSE); + } + } + } + LeaveCriticalSection(&cs_cfgui); +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_flags(khui_config_node vnode) { + khui_config_node_i * node; + khm_int32 flags = 0; + + if (vnode && + !cfgui_is_valid_node_handle(vnode)) + return 0; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode) && + hwnd_cfgui != NULL) { + + node = cfgui_node_i_from_handle(vnode); + + flags = node->flags; + } + LeaveCriticalSection(&cs_cfgui); + + return flags; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_name(khui_config_node vnode, + wchar_t * buf, + khm_size * cb_buf) { + khui_config_node_i * node; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if (!cb_buf || + !cfgui_is_valid_node_handle(vnode)) + return KHM_ERROR_INVALID_PARAM; + + EnterCriticalSection(&cs_cfgui); + if (cfgui_is_valid_node_handle(vnode) && + hwnd_cfgui != NULL) { + khm_size cb; + + node = cfgui_node_i_from_handle(vnode); + + StringCbLength(node->reg.name, KHUI_MAXCCH_NAME, &cb); + + if (buf == NULL || cb > *cb_buf) { + *cb_buf = cb; + rv = KHM_ERROR_TOO_LONG; + } else { + StringCbCopy(buf, *cb_buf, node->reg.name); + *cb_buf = cb; + } + } else { + rv = KHM_ERROR_INVALID_PARAM; + } + LeaveCriticalSection(&cs_cfgui); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_init_dialog_data(HWND hwnd_dlg, + const khui_config_init_data * data, + khm_size cb_extra, + khui_config_init_data ** new_data, + void ** extra) { + khm_size cb; + khui_config_init_data * d; + + cb = sizeof(khui_config_init_data) + cb_extra; + d = PMALLOC(cb); +#ifdef DEBUG + assert(d); +#endif + ZeroMemory(d, cb); + + *d = *data; + + if (d->ctx_node) + khui_cfg_hold(d->ctx_node); + if (d->this_node) + khui_cfg_hold(d->this_node); + if (d->ref_node) + khui_cfg_hold(d->ref_node); + +#pragma warning(push) +#pragma warning(disable: 4244) + SetWindowLongPtr(hwnd_dlg, DWLP_USER, (LONG_PTR) d); +#pragma warning(pop) + + if (new_data) + *new_data = d; + if (extra) + *extra = (void *) (d + 1); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_get_dialog_data(HWND hwnd_dlg, + khui_config_init_data ** data, + void ** extra) { + khui_config_init_data * d; + + d = (khui_config_init_data *) (LONG_PTR) GetWindowLongPtr(hwnd_dlg, + DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + + *data = d; + if (extra) + *extra = (void *) (d + 1); + + return (d)?KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_int32 KHMAPI +khui_cfg_free_dialog_data(HWND hwnd_dlg) { + khui_config_init_data * d; + + d = (khui_config_init_data *) (LONG_PTR) GetWindowLongPtr(hwnd_dlg, + DWLP_USER); +#ifdef DEBUG + assert(d); +#endif + + if (d) { + PFREE(d); + } + + return (d)?KHM_ERROR_SUCCESS: KHM_ERROR_NOT_FOUND; +} diff --git a/mechglue/src/windows/identity/uilib/configui.h b/mechglue/src/windows/identity/uilib/configui.h new file mode 100644 index 000000000..c7ff88bdb --- /dev/null +++ b/mechglue/src/windows/identity/uilib/configui.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_CONFIGUI_H +#define __KHIMAIRA_CONFIGUI_H + +typedef struct tag_cfg_node_data { + void * key; + HWND hwnd; + LPARAM param; + khm_int32 flags; +} cfg_node_data; + +typedef struct tag_khui_config_node_i { + khm_int32 magic; + + khui_config_node_reg reg; + kmm_plugin owner; + khm_int32 id; + + HWND hwnd; + LPARAM param; + + cfg_node_data * data; + khm_size n_data; + khm_size nc_data; + + khm_int32 refcount; + khm_int32 flags; + TDCL(struct tag_khui_config_node_i); +} khui_config_node_i; + +#define KHUI_CONFIG_NODE_MAGIC 0x38f4cb52 + +#define KHUI_NODEDATA_ALLOC_INCR 8 + +#define KHUI_CN_FLAG_DELETED 0x0008 + +#define cfgui_is_valid_node_handle(v) \ +((v) && ((khui_config_node_i *) (v))->magic == KHUI_CONFIG_NODE_MAGIC) + +#define cfgui_is_valid_node(n) \ +((n)->magic == KHUI_CONFIG_NODE_MAGIC) + +#define cfgui_node_i_from_handle(v) \ +((khui_config_node_i *) v) + +#define cfgui_handle_from_node_i(n) \ +((khui_config_node) n) + +#endif diff --git a/mechglue/src/windows/identity/uilib/creddlg.c b/mechglue/src/windows/identity/uilib/creddlg.c new file mode 100644 index 000000000..dae98ff68 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/creddlg.c @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<utils.h> +#include<assert.h> + +#define CW_ALLOC_INCR 8 + +static void cw_free_prompts(khui_new_creds * c); + +static void cw_free_prompt(khui_new_creds_prompt * p); + +static khui_new_creds_prompt * +cw_create_prompt( + khm_size idx, + khm_int32 type, + wchar_t * prompt, + wchar_t * def, + khm_int32 flags); + +KHMEXP khm_int32 KHMAPI +khui_cw_create_cred_blob(khui_new_creds ** ppnc) +{ + khui_new_creds * c; + + c = PMALLOC(sizeof(*c)); + ZeroMemory(c, sizeof(*c)); + + c->magic = KHUI_NC_MAGIC; + InitializeCriticalSection(&c->cs); + c->result = KHUI_NC_RESULT_CANCEL; + c->mode = KHUI_NC_MODE_MINI; + + *ppnc = c; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_destroy_cred_blob(khui_new_creds *c) +{ + khm_size i; + size_t len; + EnterCriticalSection(&c->cs); + for(i=0;i<c->n_identities;i++) { + kcdb_identity_release(c->identities[i]); + } + cw_free_prompts(c); + khui_context_release(&c->ctx); + LeaveCriticalSection(&c->cs); + DeleteCriticalSection(&c->cs); + + if (c->password) { + len = wcslen(c->password); + SecureZeroMemory(c->password, sizeof(wchar_t) * len); + PFREE(c->password); + } + + if (c->identities) + PFREE(c->identities); + + if (c->types) + PFREE(c->types); + + if (c->type_subs) + PFREE(c->type_subs); + + if (c->window_title) + PFREE(c->window_title); + + PFREE(c); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_lock_nc(khui_new_creds * c) +{ + EnterCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_unlock_nc(khui_new_creds * c) +{ + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +#define NC_N_IDENTITIES 4 + +KHMEXP khm_int32 KHMAPI +khui_cw_add_identity(khui_new_creds * c, + khm_handle id) +{ + if(id == NULL) + return KHM_ERROR_SUCCESS; /* we return success because adding + a NULL id is equivalent to adding + nothing. */ + EnterCriticalSection(&(c->cs)); + + if(c->identities == NULL) { + c->nc_identities = NC_N_IDENTITIES; + c->identities = PMALLOC(sizeof(*(c->identities)) * + c->nc_identities); + c->n_identities = 0; + } else if(c->n_identities + 1 > c->nc_identities) { + khm_handle * ni; + + c->nc_identities = UBOUNDSS(c->n_identities + 1, + NC_N_IDENTITIES, + NC_N_IDENTITIES); + ni = PMALLOC(sizeof(*(c->identities)) * c->nc_identities); + memcpy(ni, c->identities, + sizeof(*(c->identities)) * c->n_identities); + PFREE(c->identities); + c->identities = ni; + } + + kcdb_identity_hold(id); + c->identities[c->n_identities++] = id; + LeaveCriticalSection(&(c->cs)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_set_primary_id(khui_new_creds * c, + khm_handle id) +{ + khm_size i; + khm_int32 rv; + + EnterCriticalSection(&c->cs); + + /* no change */ + if((c->n_identities > 0 && c->identities[0] == id) || + (c->n_identities == 0 && id == NULL)) { + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; + } + + for(i=0; i<c->n_identities; i++) { + kcdb_identity_release(c->identities[i]); + } + c->n_identities = 0; + + LeaveCriticalSection(&(c->cs)); + rv = khui_cw_add_identity(c,id); + if(c->hwnd != NULL) { + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_IDENTITY_CHANGE), 0); + } + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_add_type(khui_new_creds * c, + khui_new_creds_by_type * t) +{ + EnterCriticalSection(&c->cs); + + if(c->n_types >= KHUI_MAX_NCTYPES) { + LeaveCriticalSection(&c->cs); + return KHM_ERROR_OUT_OF_BOUNDS; + } + + if(c->types == NULL) { + c->nc_types = CW_ALLOC_INCR; + c->types = PMALLOC(sizeof(*(c->types)) * c->nc_types); + c->type_subs = PMALLOC(sizeof(*(c->type_subs)) * c->nc_types); + c->n_types = 0; + } + + if(c->nc_types < c->n_types + 1) { + void * t; + khm_size n; + + n = UBOUNDSS(c->n_types + 1, CW_ALLOC_INCR, CW_ALLOC_INCR); + + t = PMALLOC(sizeof(*(c->types)) * n); + memcpy(t, (void *) c->types, sizeof(*(c->types)) * c->n_types); + PFREE(c->types); + c->types = t; + + t = PMALLOC(sizeof(*(c->type_subs)) * n); + memcpy(t, (void *) c->type_subs, sizeof(*(c->type_subs)) * c->n_types); + PFREE(c->type_subs); + c->type_subs = t; + + c->nc_types = n; + } + + c->type_subs[c->n_types] = kcdb_credtype_get_sub(t->type); + c->types[c->n_types++] = t; + t->nc = c; + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_del_type(khui_new_creds * c, + khm_int32 type_id) +{ + khm_size i; + + EnterCriticalSection(&c->cs); + for(i=0; i < c->n_types; i++) { + if(c->types[i]->type == type_id) + break; + } + if(i >= c->n_types) { + LeaveCriticalSection(&c->cs); + return KHM_ERROR_NOT_FOUND; + } + c->n_types--; + for(;i < c->n_types; i++) { + c->types[i] = c->types[i+1]; + c->type_subs[i] = c->type_subs[i+1]; + } + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_find_type( + khui_new_creds * c, + khm_int32 type, + khui_new_creds_by_type **t) +{ + khm_size i; + + EnterCriticalSection(&c->cs); + *t = NULL; + for(i=0;i<c->n_types;i++) { + if(c->types[i]->type == type) { + *t = c->types[i]; + break; + } + } + LeaveCriticalSection(&c->cs); + + if(*t) + return KHM_ERROR_SUCCESS; + return KHM_ERROR_NOT_FOUND; +} + + +KHMEXP khm_int32 KHMAPI +khui_cw_enable_type( + khui_new_creds * c, + khm_int32 type, + khm_boolean enable) +{ + khui_new_creds_by_type * t = NULL; + BOOL delta = FALSE; + + EnterCriticalSection(&c->cs); + if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) { + if(enable) { + delta = t->flags & KHUI_NCT_FLAG_DISABLED; + t->flags &= ~KHUI_NCT_FLAG_DISABLED; + } + else { + delta = !(t->flags & KHUI_NCT_FLAG_DISABLED); + t->flags |= KHUI_NCT_FLAG_DISABLED; + } + } + LeaveCriticalSection(&c->cs); + + if(delta) + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, MAKEWPARAM(0,WMNC_TYPE_STATE), (LPARAM) type); + + return (t)?KHM_ERROR_SUCCESS:KHM_ERROR_NOT_FOUND; +} + +KHMEXP khm_boolean KHMAPI +khui_cw_type_succeeded( + khui_new_creds * c, + khm_int32 type) +{ + khui_new_creds_by_type * t; + khm_boolean s; + + EnterCriticalSection(&c->cs); + if(KHM_SUCCEEDED(khui_cw_find_type(c, type, &t))) { + s = (t->flags & KHUI_NCT_FLAG_PROCESSED) && !(t->flags & KHUI_NC_RESPONSE_FAILED); + } else { + s = FALSE; + } + LeaveCriticalSection(&c->cs); + + return s; +} + +static khui_new_creds_prompt * +cw_create_prompt(khm_size idx, + khm_int32 type, + wchar_t * prompt, + wchar_t * def, + khm_int32 flags) +{ + khui_new_creds_prompt * p; + size_t cb_prompt; + size_t cb_def; + + if(prompt && FAILED(StringCbLength(prompt, KHUI_MAXCB_PROMPT, &cb_prompt))) + return NULL; + if(def && FAILED(StringCbLength(def, KHUI_MAXCB_PROMPT_VALUE, &cb_def))) + return NULL; + + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + if(prompt) { + cb_prompt += sizeof(wchar_t); + p->prompt = PMALLOC(cb_prompt); + StringCbCopy(p->prompt, cb_prompt, prompt); + } + + if(def && cb_def > 0) { + cb_def += sizeof(wchar_t); + p->def = PMALLOC(cb_def); + StringCbCopy(p->def, cb_def, def); + } + + p->value = PMALLOC(KHUI_MAXCB_PROMPT_VALUE); + ZeroMemory(p->value, KHUI_MAXCB_PROMPT_VALUE); + + p->type = type; + p->flags = flags; + p->index = idx; + + return p; +} + +static void +cw_free_prompt(khui_new_creds_prompt * p) { + size_t cb; + + if(p->prompt) { + if(SUCCEEDED(StringCbLength(p->prompt, KHUI_MAXCB_PROMPT, &cb))) + SecureZeroMemory(p->prompt, cb); + PFREE(p->prompt); + } + + if(p->def) { + if(SUCCEEDED(StringCbLength(p->def, KHUI_MAXCB_PROMPT, &cb))) + SecureZeroMemory(p->def, cb); + PFREE(p->def); + } + + if(p->value) { + if(SUCCEEDED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) + SecureZeroMemory(p->value, cb); + PFREE(p->value); + } + + PFREE(p); +} + +static void +cw_free_prompts(khui_new_creds * c) +{ + khm_size i; + + if(c->banner != NULL) { + PFREE(c->banner); + c->banner = NULL; + } + + if(c->pname != NULL) { + PFREE(c->pname); + c->pname = NULL; + } + + for(i=0;i < c->n_prompts; i++) { + if(c->prompts[i]) { + cw_free_prompt(c->prompts[i]); + c->prompts[i] = NULL; + } + } + + if(c->prompts != NULL) { + PFREE(c->prompts); + c->prompts = NULL; + } + + c->nc_prompts = 0; + c->n_prompts = 0; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_clear_prompts(khui_new_creds * c) +{ + SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c); + + EnterCriticalSection(&c->cs); + cw_free_prompts(c); + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_begin_custom_prompts(khui_new_creds * c, + khm_size n_prompts, + wchar_t * banner, + wchar_t * pname) +{ + size_t cb; + + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_CLEAR_PROMPTS), (LPARAM) c); + + EnterCriticalSection(&c->cs); +#ifdef DEBUG + assert(c->n_prompts == 0); +#endif + cw_free_prompts(c); + + if(SUCCEEDED(StringCbLength(banner, KHUI_MAXCB_BANNER, &cb)) && + cb > 0) { + cb += sizeof(wchar_t); + c->banner = PMALLOC(cb); + StringCbCopy(c->banner, cb, banner); + } else { + c->banner = NULL; + } + + if(SUCCEEDED(StringCbLength(pname, KHUI_MAXCB_PNAME, &cb)) && + cb > 0) { + + cb += sizeof(wchar_t); + c->pname = PMALLOC(cb); + StringCbCopy(c->pname, cb, pname); + + } else { + + c->pname = NULL; + + } + + if(n_prompts > 0) { + c->prompts = PMALLOC(sizeof(*(c->prompts)) * n_prompts); + ZeroMemory(c->prompts, sizeof(*(c->prompts)) * n_prompts); + c->nc_prompts = n_prompts; + c->n_prompts = 0; + + } else { + + c->prompts = NULL; + c->n_prompts = 0; + c->nc_prompts = 0; + + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c); + } + + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_add_prompt(khui_new_creds * c, + khm_int32 type, + wchar_t * prompt, + wchar_t * def, + khm_int32 flags) +{ + khui_new_creds_prompt * p; + + if(c->nc_prompts == 0 || + c->n_prompts == c->nc_prompts) + return KHM_ERROR_INVALID_OPERATION; + +#ifdef DEBUG + assert(c->prompts != NULL); +#endif + + EnterCriticalSection(&c->cs); + p = cw_create_prompt(c->n_prompts, type, prompt, def, flags); + if(p == NULL) { + LeaveCriticalSection(&c->cs); + return KHM_ERROR_INVALID_PARAM; + } + c->prompts[c->n_prompts++] = p; + LeaveCriticalSection(&c->cs); + + if(c->n_prompts == c->nc_prompts) { + PostMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_SET_PROMPTS), (LPARAM) c); + /* once we are done adding prompts, switch to the auth + panel */ +#if 0 + /* Actually, don't. Doing so can mean an unexpected panel + switch if fiddling on some other panel causes a change in + custom prompts. */ + SendMessage(c->hwnd, KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_DIALOG_SWITCH_PANEL), + (LPARAM) c); +#endif + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt_count(khui_new_creds * c, + khm_size * np) { + + EnterCriticalSection(&c->cs); + *np = c->n_prompts; + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt( + khui_new_creds * c, + khm_size idx, + khui_new_creds_prompt ** prompt) +{ + khm_int32 rv; + + EnterCriticalSection(&c->cs); + if(c->n_prompts <= idx || + c->prompts == NULL) { + + rv = KHM_ERROR_OUT_OF_BOUNDS; + *prompt = NULL; + } else { + + *prompt = c->prompts[idx]; + rv = KHM_ERROR_SUCCESS; + } + LeaveCriticalSection(&c->cs); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_sync_prompt_values(khui_new_creds * c) +{ + khm_size i; + + EnterCriticalSection(&c->cs); + for(i=0;i<c->n_prompts;i++) { + khui_new_creds_prompt * p; + p = c->prompts[i]; + if(p->hwnd_edit) { + /* Ideally, we would retrieve the text to a temporary + buffer with the c->cs released, obtain c->cs and copy the + text to p->value. However, I'm not going to bother as the + code paths we are touching here do not need c->cs while + setting p->value does */ + GetWindowText(p->hwnd_edit, p->value, + KHUI_MAXCCH_PROMPT_VALUE); + } + } + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt_value(khui_new_creds * c, + khm_size idx, + wchar_t * buf, + khm_size *cbbuf) +{ + khui_new_creds_prompt * p; + khm_int32 rv; + size_t cb; + + rv = khui_cw_get_prompt(c, idx, &p); + if(KHM_FAILED(rv)) + return rv; + + EnterCriticalSection(&c->cs); + + if(FAILED(StringCbLength(p->value, KHUI_MAXCB_PROMPT_VALUE, &cb))) { + *cbbuf = 0; + if(buf != NULL) + *buf = 0; + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; + } + cb += sizeof(wchar_t); + + if(buf == NULL || *cbbuf < cb) { + *cbbuf = cb; + LeaveCriticalSection(&c->cs); + return KHM_ERROR_TOO_LONG; + } + + StringCbCopy(buf, *cbbuf, p->value); + *cbbuf = cb; + LeaveCriticalSection(&c->cs); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_cw_set_response(khui_new_creds * c, + khm_int32 type, + khm_int32 response) +{ + khui_new_creds_by_type * t = NULL; + EnterCriticalSection(&c->cs); + khui_cw_find_type(c, type, &t); + c->response |= response & KHUI_NCMASK_RESPONSE; + if(t) { + t->flags &= ~KHUI_NCMASK_RESULT; + t->flags |= (response & KHUI_NCMASK_RESULT); + + if (!(response & KHUI_NC_RESPONSE_NOEXIT) && + !(response & KHUI_NC_RESPONSE_PENDING)) + t->flags |= KHUI_NC_RESPONSE_COMPLETED; + } + LeaveCriticalSection(&c->cs); + return KHM_ERROR_SUCCESS; +} + +/* only called from a identity provider callback */ +KHMEXP khm_int32 KHMAPI +khui_cw_add_control_row(khui_new_creds * c, + HWND label, + HWND input, + khui_control_size size) +{ + if (c && c->hwnd) { + khui_control_row row; + + row.label = label; + row.input = input; + row.size = size; + + SendMessage(c->hwnd, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0, WMNC_ADD_CONTROL_ROW), + (LPARAM) &row); + + return KHM_ERROR_SUCCESS; + } else { + return KHM_ERROR_INVALID_PARAM; + } +} diff --git a/mechglue/src/windows/identity/uilib/khaction.h b/mechglue/src/windows/identity/uilib/khaction.h new file mode 100644 index 000000000..fccdab549 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khaction.h @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ACTION_H +#define __KHIMAIRA_ACTION_H + +/*! \addtogroup khui + @{*/ +/*! \defgroup khui_actions Actions + @{*/ + +/*! \brief An action */ +typedef struct tag_khui_action { + int cmd; /*!< command id */ + int type; /*!< combination of KHUI_ACTIONTYPE_* */ + wchar_t * name; /*!< name for named actions. NULL if not named. */ + + /* normal, hot and disabled are toolbar sized bitmaps */ + int ib_normal; /*!< normal bitmap (index) */ + int ib_hot; /*!< hot bitmap (index) */ + int ib_disabled; /*!< disabled bitmap (index) */ + + int ib_icon; /*!< index of small (16x16) icon (for menu) */ + int ib_icon_dis; /*!< index of disabled (greyed) icon */ + + int is_caption; /*!< index of string resource for caption */ + int is_tooltip; /*!< same for description / tooltip */ + int ih_topic; /*!< help topic */ + int state; /*!< current state. combination of KHUI_ACTIONSTATE_* */ +} khui_action; + +/*! \brief Unknown action type */ +#define KHUI_ACTIONTYPE_NONE 0 + +/*! \brief A trigger type action */ +#define KHUI_ACTIONTYPE_TRIGGER 1 + +/*! \brief A toggle type action + + A toggle type action typically changes the CHECKED state of the + action each time it is invoked. + */ +#define KHUI_ACTIONTYPE_TOGGLE 2 + +/*! \brief The action is enabled */ +#define KHUI_ACTIONSTATE_ENABLED 0 +/*! \brief The action is diabled */ +#define KHUI_ACTIONSTATE_DISABLED 1 +/*! \brief For toggle type actions, the action is checked */ +#define KHUI_ACTIONSTATE_CHECKED 2 +/*! \brief The action is hot + + Typically this means that the user is hovering the pointing device + over a UI element representing the action. + */ +#define KHUI_ACTIONSTATE_HOT 4 + +#ifdef NOEXPORT +#define ACTION_SIMPLE(c,cap,des,top) \ + {c,KHUI_ACTIONTYPE_TRIGGER,0,0,0,0,0,cap,des,top,0} + +#define ACTION_FULL(cmd,type,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state) \ + {cmd,type,inormal,ihot,idis,isml,ismld,capt,toolt,topic,state} + +#define ACTION_SIMPLE_IMAGE(c,inormal, ihot, idis, isml, ismld,cap, des, top) \ + {c,KHUI_ACTIONTYPE_TRIGGER,inormal,ihot,idis,isml,ismld,cap,des,top,0} +#endif + +/*! \brief A reference to an action */ +typedef struct tag_khui_action_ref { + int flags; + union { + int action; + khui_action * p_action; + }; +} khui_action_ref; + +#define KHUI_ACTIONREF_SUBMENU 0x01 +#define KHUI_ACTIONREF_SEP 0x02 +#define KHUI_ACTIONREF_PACTION 0x04 +#define KHUI_ACTIONREF_FREE_PACTION 0x08 +#define KHUI_ACTIONREF_END 0x10 +#define KHUI_ACTIONREF_DEFAULT 0x20 + +#ifdef NOEXPORT +#define MENU_ACTION(c) {0,c} +#define MENU_DEFACTION(c) {KHUI_ACTIONREF_DEFAULT, c} +#define MENU_SUBMENU(s) {KHUI_ACTIONREF_SUBMENU,s} +#define MENU_SEP() {KHUI_ACTIONREF_SEP,KHUI_MENU_SEP} +#define MENU_END() {KHUI_ACTIONREF_END,KHUI_MENU_END} +#endif + +/*! \brief Menu definition */ +typedef struct tag_khui_menu_def { + int cmd; /*!< Action associated with menu */ + int state; /*!< combination of KHUI_MENUSTATE_* */ + size_t n_items; /*!< total number of items or -1 if not + set. If this is -1, then the list of + actions must be terminated with a + ACTION_LIST_END entry. */ + size_t nc_items; /*!< max number of items in the buffer + alocated for items. Ignored if + KHUI_MENUSTATE_CONSTANT is set in \a + state.*/ + khui_action_ref *items; /*!< Action list terminated by, + ACTION_LIST_END. If \a n_items is set + to a value other than -1, the list + doesn't necessarily have to end with a + ACTION_LIST_END. */ +} khui_menu_def; + +#ifdef NOEXPORT +#define CONSTMENU(c,s,i) {c,s,-1,-1,i} +#endif + +#define KHUI_MENU_END -2 +#define KHUI_MENU_SEP -1 + +#define KHUI_MENUSTATE_CONSTANT 0 +#define KHUI_MENUSTATE_ALLOCD 1 + +/*! \brief Accelerator definition */ +typedef struct tag_khui_accel_def { + int cmd; + int mod; + int key; + int scope; +} khui_accel_def; + +#define KHUI_ACCEL_SCOPE_GLOBAL 0 + +#ifdef NOEXPORT + +extern khui_accel_def khui_accel_global[]; +extern int khui_n_accel_global; + +extern khui_action khui_actions[]; +extern int khui_n_actions; + +extern khui_menu_def khui_all_menus[]; +extern int khui_n_all_menus; + +#endif /* NOEXPORT */ + +/* functions */ + +KHMEXP khui_menu_def * KHMAPI khui_menu_create(int cmd); +KHMEXP khui_menu_def * KHMAPI khui_menu_dup(khui_menu_def * src); +KHMEXP void KHMAPI khui_menu_delete(khui_menu_def * d); +KHMEXP void KHMAPI khui_menu_add_action(khui_menu_def * d, int id); +KHMEXP void KHMAPI khui_menu_add_paction(khui_menu_def * d, khui_action * act, int flags); + +/*! \brief Action scope identifiers + + The scope identifier is a value which describes the scope of the + cursor context. See documentation on individual scope identifiers + for details. + + The role of the scope identifier is to provide a summary of the + current cursor context. Specifically, these identify several + special cases of credential selection, such as the selection of an + entire identity, a credential type or a single credential. If + none of these are applicable, then the generic scope identifier + ::KHUI_SCOPE_GROUP is set or ::KHUI_SCOPE_NONE if there is nothing + selected. + + Note that the scope typically only apply to cursor contexts and + not the selection context. Please see + \ref khui_context "UI Contexts" for more information. + + \see \ref khui_context "UI Contexts" +*/ +typedef enum tag_khui_scope { + KHUI_SCOPE_NONE, + /*!< No context. Nothing is selected. */ + + KHUI_SCOPE_IDENT, + /*!< Identity. The selection is the entire identity specified in + the \a identity field of the context. */ + + KHUI_SCOPE_CREDTYPE, + /*!< A credentials type. The selection is an entire credentials + type. If \a identity is non-NULL, then the scope is all the + credentials of type \a cred_type which belong to \a identity. + Otherwise, the selection is all credentials of type \a + cred_type. + + \note The \a identity can be non-NULL even for the case where + all credentials of type \a cred_type under \a identity is the + same scope as all credentials of type \a cred_type under all + identities. */ + + KHUI_SCOPE_GROUP, + /*!< A grouping of credentials. The scope is a group of + credentials which can not be simplified using one of the other + context identifiers. The \a headers array contains \a n_headers + elements describing the outline level that has been selected. + + \see ::khui_header + \see \ref khui_context_sel_ctx_grp "KHUI_SCOPE_GROUP description" */ + + KHUI_SCOPE_CRED + /*!< A single credential. Only a single credential was + selected. The \a cred field of the context specifies the + credential. The \a identity and \a cred_type fields specify the + identity and the credential type respectively. */ +} khui_scope; + + +/*! \brief Outline header + + Describes an outline header in the user interface. + + \see \ref khui_context_sel_ctx_grp "KHUI_SCOPE_GROUP description" + */ +typedef struct tag_khui_header { + khm_int32 attr_id; /*!< Attribute ID */ + void * data; /*!< Value of attribute */ + khm_size cb_data; /*!< Size of the value */ +} khui_header; + +/*! \brief Maximum number of outline headers + + This is the maximum number of fields that the credentials view can + be grouped by. + */ +#define KHUI_MAX_HEADERS 6 + +/*! \brief Action context + + Represents the UI context for an action. + */ +typedef struct tag_khui_action_context { + khm_int32 magic; /*!< Internal. */ + khui_scope scope; /*!< Context scope. One of ::khui_scope*/ + khm_handle identity; /*!< Identity */ + khm_int32 cred_type; /*!< Credential type ID */ + khm_handle cred; /*!< Credential */ + + khui_header headers[KHUI_MAX_HEADERS]; + /*!< The ordered set of outline + headers which define the current + cursor location. */ + + khm_size n_headers; /*!< Number of actual headers defined + above */ + + khm_handle credset; /*!< Handle to a credential set + containing the currently selected + credentials. When the context is + obtained through khui_context_get(), + this credential is returned in a + sealed state. */ + + khm_size n_sel_creds; /*!< Number of selected credentials */ + + void * int_buf; /*!< Internal. Do not use. */ + khm_size int_cb_buf; /*!< Internal. Do not use. */ + khm_size int_cb_used; /*!< Internal. Do not use. */ + + void * vparam; /*!< Optional data */ + khm_size cb_vparam; /*!< Size of optional data */ +} khui_action_context; + +/*! \brief Set the current context + + Changes the UI context to that represented by the parameters to + the function. Note that specifying a valid \a identity or \a cred + parameter will result in an automatic hold on the respective + object. The hold will stay until another call to + khui_context_set() overwrites the identity or credential handle or + a call to khui_context_reset() is made. + + While this API is available, it is only called from the main + NetIDMgr application. Plugins do not have a good reason to call + this API directly and should not do so. + + \param[in] scope The new context scope + + \param[in] identity A handle to an identity. If this is not NULL, + then it should be a valid handle to an identity. Required if + \a scope specifies ::KHUI_SCOPE_IDENT. Optional if \a scope + specifies ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. + + \param[in] cred_type A credentials type. Specify + ::KCDB_CREDTYPE_INVALID if this parameter is not given or not + relevant. Required if \a scope specifies + ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. + + \param[in] cred A handle to a credential. If this parameter is + not NULL it is expected to be a valid handle to a credential. + Required if \a scope specifies ::KHUI_SCOPE_CRED. Ignored + otherwise. + + \param[in] headers An array of headers. The \a n_headers + parameter specifies the number of elements in the array. Set + to NULL if not specified. Required if \a scope specifies + ::KHUI_SCOPE_GROUP. + + \param[in] n_headers Number of elements in \a headers. Must be + less than or equal to ::KHUI_MAX_HEADERS. Required if \a + headers is not NULL. Ignored otherwise. + + \param[in] cs_src A handle to a credential set from which the + selected credentials will be extracted. The credentials that + are selected must have the ::KCDB_CRED_FLAG_SELECTED flag set. + + \note This function should only be called from the UI thread. + */ +KHMEXP void KHMAPI +khui_context_set(khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred, + khui_header *headers, + khm_size n_headers, + khm_handle cs_src); + +/*! \brief Set the current context + + Changes the UI context to that represented by the parameters to + the function. Note that specifying a valid \a identity or \a cred + parameter will result in an automatic hold on the respective + object. The hold will stay until another call to + khui_context_set() overwrites the identity or credential handle or + a call to khui_context_reset() is made. + + While this API is available, it is only called from the main + NetIDMgr application. Plugins do not have a good reason to call + this API directly and should not do so. + + \param[in] scope The new context scope + + \param[in] identity A handle to an identity. If this is not NULL, + then it should be a valid handle to an identity. Required if + \a scope specifies ::KHUI_SCOPE_IDENT. Optional if \a scope + specifies ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. + + \param[in] cred_type A credentials type. Specify + ::KCDB_CREDTYPE_INVALID if this parameter is not given or not + relevant. Required if \a scope specifies + ::KHUI_SCOPE_CREDTYPE. Ignored otherwise. + + \param[in] cred A handle to a credential. If this parameter is + not NULL it is expected to be a valid handle to a credential. + Required if \a scope specifies ::KHUI_SCOPE_CRED. Ignored + otherwise. + + \param[in] headers An array of headers. The \a n_headers + parameter specifies the number of elements in the array. Set + to NULL if not specified. Required if \a scope specifies + ::KHUI_SCOPE_GROUP. + + \param[in] n_headers Number of elements in \a headers. Must be + less than or equal to ::KHUI_MAX_HEADERS. Required if \a + headers is not NULL. Ignored otherwise. + + \param[in] cs_src A handle to a credential set from which the + selected credentials will be extracted. The credentials that + are selected must have the ::KCDB_CRED_FLAG_SELECTED flag set. + + \param[in] vparam Optional parameter blob + + \param[in] cb_vparam Size of parameter blob + + \note This function should only be called from the UI thread. + */ +KHMEXP void KHMAPI +khui_context_set_ex(khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred, + khui_header *headers, + khm_size n_headers, + khm_handle cs_src, + void * vparam, + khm_size cb_vparam); + +/*! \brief Obtain the current UI context + + The parameter specified by \a ctx will receive the current UI + context. If the context contains an identity or a credential + handle, a hold will be obtained on the relevant object. Use + khui_context_release() to release the holds obtained in a prior + call to khui_context_get(). + + \note The returned context should not be modified prior to calling + khui_context_release(). +*/ +KHMEXP void KHMAPI +khui_context_get(khui_action_context * ctx); + +/*! \brief Create a new UI context + + The created context does not have any relation to the current UI + context. This function is provided for use in situations where an + application needs to provide a scope description through a + ::khui_action_context structure. + + Once the application is done with the context, it should call + khui_context_release() to release the created context. + */ +KHMEXP void KHMAPI +khui_context_create(khui_action_context * ctx, + khui_scope scope, + khm_handle identity, + khm_int32 cred_type, + khm_handle cred); + +/*! \brief Release a context obtained using khui_context_get() + + Releases all holds obtained on related objects in a prior call to + khui_context_get() and nullifies the context. + + \note The context should not have been modified between calling + khui_context_get() and khui_context_release() + */ +KHMEXP void KHMAPI +khui_context_release(khui_action_context * ctx); + +/*! \brief Reset the UI context + + Nullifies the current UI context and releases any holds obtained + on objects related to the previous context. +*/ +KHMEXP void KHMAPI +khui_context_reset(void); + +/*! \brief Refresh context data + + Setting the UI context involves other side effects such as + activation of or disabling certain actions based on the selection. + If an operation is performed which may affect the side effects, + khui_context_refresh() is called to refresh them. + + An example is when setting the default identity. The state of the + action ::KHUI_ACTION_SET_DEF_ID depends on whether the currently + selected identity is the default. However, if the currently + selected identity becomes the default after selection, then + khui_context_refresh() should be called to adjust the state of the + ::KHUI_ACTION_SET_DEF_ID action. + */ +KHMEXP void KHMAPI +khui_context_refresh(void); + +/*! \brief A filter function that filters for credentials in the cursor context + + This is a function of type ::kcdb_cred_filter_func which can be + used to filter for credentials that are included in the cursor + context. + + The \a rock parameter should be a pointer to a + ::khui_action_context structure which will be used as the filter. + + For example, the following code will extract the cursor context + credentials into the credential set \a my_credset based on the UI + context \a my context: + + \code + kcdb_credset_extract_filtered(my_credset, + NULL, + khui_context_cursor_filter, + (void *) my_context); + \endcode +*/ +KHMEXP khm_int32 KHMAPI +khui_context_cursor_filter(khm_handle cred, + khm_int32 flags, + void * rock); + +/*! \brief Get a string representation of an accelerator + + \param[in] cmd Command for which to obtain the accelerator string for + \param[out] buf Buffer to receive the accelerator string + \param[in] bufsiz Size of the buffer in bytes. Note that the size of the + buffer must be sufficient to hold at least one character and a + NULL terminator. + + \return TRUE if the operation was successful. FALSE otherwise. + */ +KHMEXP khm_boolean KHMAPI khui_get_cmd_accel_string(int cmd, wchar_t * buf, size_t bufsiz); + +KHMEXP HACCEL KHMAPI khui_create_global_accel_table(void); + +/*! \brief Find a menu by id */ +KHMEXP khui_menu_def * KHMAPI khui_find_menu(int id); + +/*! \brief Find an action by id */ +KHMEXP khui_action * KHMAPI khui_find_action(int id); + +/*! \brief Get the length of the action list */ +KHMEXP size_t KHMAPI khui_action_list_length(khui_action_ref * ref); + +/*! \brief Find an action by name */ +KHMEXP khui_action * KHMAPI khui_find_named_action(wchar_t * name); + +/*! \brief Enables or disables a group of actions + + The group of actions are specified by the menu definition. All + valid action entries in the menu are marked as enabled or disabled + according to the value of \a enable. + */ +KHMEXP void KHMAPI khui_enable_actions(khui_menu_def * d, khm_boolean enable); + +/*! \brief Enables or disables an action + + The action designated by the command \a cmd will either be enabled + or disabled depending on the \a enable parameter. If \a enable is + TRUE then the action is enabled. + */ +KHMEXP void KHMAPI khui_enable_action(int cmd, khm_boolean enable); + +/*! \brief Check an action in an action group + + Marks the action denoted by \a cmd as checked and resets the + checked bit in all other actions. + + \param[in] d A menu definition. + \param[in] cmd A command identifier. Setting this to -1 will + reset the checked bit in all the actions in the menu + definition. + */ +KHMEXP void KHMAPI khui_check_radio_action(khui_menu_def * d, khm_int32 cmd); + +/*!\cond INTERNAL */ + +/*! \brief Initialize actions + + \note Only called by the NetIDMgr application + */ +KHMEXP void KHMAPI khui_init_actions(void); + +/*! \brief Exit actions + + \note Only called by the NetIDMgr application + */ +KHMEXP void KHMAPI khui_exit_actions(void); + +/*! \endcond */ + +/*@}*/ +/*@}*/ +#endif diff --git a/mechglue/src/windows/identity/uilib/khactiondef.h b/mechglue/src/windows/identity/uilib/khactiondef.h new file mode 100644 index 000000000..3f1c43073 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khactiondef.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_ACTIONDEF_H +#define __KHIMAIRA_ACTIONDEF_H + +/*! \ingroup khui_actions + @{*/ +/*! \defgroup khui_std_actions Standard Actions +@{ */ + +/*!\name Standard actions + @{*/ +#define KHUI_ACTION_BASE 50000 + +#define KHUI_ACTION_PROPERTIES (KHUI_ACTION_BASE + 0) +#define KHUI_ACTION_EXIT (KHUI_ACTION_BASE + 1) +#define KHUI_ACTION_SET_DEF_ID (KHUI_ACTION_BASE + 3) +#define KHUI_ACTION_SET_SRCH_ID (KHUI_ACTION_BASE + 4) +#define KHUI_ACTION_PASSWD_ID (KHUI_ACTION_BASE + 7) +#define KHUI_ACTION_NEW_CRED (KHUI_ACTION_BASE + 8) +#define KHUI_ACTION_CHOOSE_COLS (KHUI_ACTION_BASE + 9) +#define KHUI_ACTION_DEBUG_WINDOW (KHUI_ACTION_BASE + 10) +#define KHUI_ACTION_VIEW_REFRESH (KHUI_ACTION_BASE + 11) +#define KHUI_ACTION_LAYOUT_ID (KHUI_ACTION_BASE + 12) +#define KHUI_ACTION_LAYOUT_TYPE (KHUI_ACTION_BASE + 13) +#define KHUI_ACTION_LAYOUT_LOC (KHUI_ACTION_BASE + 14) +#define KHUI_ACTION_TB_STANDARD (KHUI_ACTION_BASE + 15) +#define KHUI_ACTION_OPT_KHIM (KHUI_ACTION_BASE + 16) +#define KHUI_ACTION_OPT_IDENTS (KHUI_ACTION_BASE + 17) +#define KHUI_ACTION_OPT_NOTIF (KHUI_ACTION_BASE + 18) +#define KHUI_ACTION_HELP_CTX (KHUI_ACTION_BASE + 19) +#define KHUI_ACTION_HELP_CONTENTS (KHUI_ACTION_BASE + 20) +#define KHUI_ACTION_HELP_INDEX (KHUI_ACTION_BASE + 21) +#define KHUI_ACTION_HELP_ABOUT (KHUI_ACTION_BASE + 22) +#define KHUI_ACTION_DESTROY_CRED (KHUI_ACTION_BASE + 23) +#define KHUI_ACTION_RENEW_CRED (KHUI_ACTION_BASE + 24) +#define KHUI_ACTION_OPEN_APP (KHUI_ACTION_BASE + 25) +#define KHUI_ACTION_MENU_ACTIVATE (KHUI_ACTION_BASE + 26) +#define KHUI_ACTION_CLOSE_APP (KHUI_ACTION_BASE + 27) +#define KHUI_ACTION_IMPORT (KHUI_ACTION_BASE + 28) +#define KHUI_ACTION_OPT_PLUGINS (KHUI_ACTION_BASE + 29) +/*@}*/ + +/*! \name Pseudo actions + +Pseudo actions do not trigger any specific function, but acts as a +signal of some generic event which will be interpreted based on +context. + +@{*/ +#define KHUI_PACTION_BASE (KHUI_ACTION_BASE + 500) + +#define KHUI_PACTION_MENU (KHUI_PACTION_BASE + 0) +#define KHUI_PACTION_UP (KHUI_PACTION_BASE + 1) +#define KHUI_PACTION_DOWN (KHUI_PACTION_BASE + 2) +#define KHUI_PACTION_LEFT (KHUI_PACTION_BASE + 3) +#define KHUI_PACTION_RIGHT (KHUI_PACTION_BASE + 4) +#define KHUI_PACTION_ENTER (KHUI_PACTION_BASE + 5) +#define KHUI_PACTION_ESC (KHUI_PACTION_BASE + 6) +#define KHUI_PACTION_OK (KHUI_PACTION_BASE + 7) +#define KHUI_PACTION_CANCEL (KHUI_PACTION_BASE + 8) +#define KHUI_PACTION_CLOSE (KHUI_PACTION_BASE + 9) +#define KHUI_PACTION_DELETE (KHUI_PACTION_BASE + 10) +#define KHUI_PACTION_UP_EXTEND (KHUI_PACTION_BASE + 11) +#define KHUI_PACTION_UP_TOGGLE (KHUI_PACTION_BASE + 12) +#define KHUI_PACTION_DOWN_EXTEND (KHUI_PACTION_BASE + 13) +#define KHUI_PACTION_DOWN_TOGGLE (KHUI_PACTION_BASE + 14) +#define KHUI_PACTION_BLANK (KHUI_PACTION_BASE + 15) +#define KHUI_PACTION_NEXT (KHUI_PACTION_BASE + 16) +#define KHUI_PACTION_SELALL (KHUI_PACTION_BASE + 17) +/*@}*/ + +/*! \name Menus + +Stock menus. + +@{*/ +#define KHUI_MENU_BASE (KHUI_ACTION_BASE + 1000) + +#define KHUI_MENU_MAIN (KHUI_MENU_BASE + 0) +#define KHUI_MENU_FILE (KHUI_MENU_BASE + 1) +#define KHUI_MENU_CRED (KHUI_MENU_BASE + 2) +#define KHUI_MENU_VIEW (KHUI_MENU_BASE + 3) +#define KHUI_MENU_OPTIONS (KHUI_MENU_BASE + 4) +#define KHUI_MENU_HELP (KHUI_MENU_BASE + 5) + +#define KHUI_MENU_LAYOUT (KHUI_MENU_BASE + 6) +#define KHUI_MENU_TOOLBARS (KHUI_MENU_BASE + 7) + +#define KHUI_MENU_IDENT_CTX (KHUI_MENU_BASE + 8) +#define KHUI_MENU_TOK_CTX (KHUI_MENU_BASE + 9) +#define KHUI_MENU_ICO_CTX_MIN (KHUI_MENU_BASE + 12) +#define KHUI_MENU_ICO_CTX_NORMAL (KHUI_MENU_BASE + 13) + +#define KHUI_PMENU_TOK_SEL (KHUI_MENU_BASE + 10) +#define KHUI_PMENU_ID_SEL (KHUI_MENU_BASE + 11) + +/* Next menu: 14 */ +/*@}*/ + +/*! \name Toolbars +@{*/ +#define KHUI_TOOLBAR_BASE (KHUI_ACTION_BASE + 2000) + +#define KHUI_TOOLBAR_STANDARD (KHUI_TOOLBAR_BASE + 0) +/*@}*/ + +/* base for user actions */ +#define KHUI_USERACTION_BASE (KHUI_ACTION_BASE + 10000) +/*@}*/ +/*@}*/ + +#endif diff --git a/mechglue/src/windows/identity/uilib/khalerts.h b/mechglue/src/windows/identity/uilib/khalerts.h new file mode 100644 index 000000000..36b13a333 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khalerts.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHALERTS_H +#define __KHIMAIRA_KHALERTS_H + +/********************************************************************* + Alerter and error reporting +**********************************************************************/ + +/*! \addtogroup khui +@{ */ + +/*!\defgroup khui_alert Alerter and Error Reporting +@{*/ + +#define KHUI_MAX_ALERT_COMMANDS 4 + +/*! \brief An alert + + Describes an alert message that will be shown to the user in a + variety of ways depending on the state of the NetIDMgr + application. + */ +typedef struct tag_khui_alert { + khm_int32 magic; /*!< Magic number. Always set to + KHUI_ALERT_MAGIC */ + + khm_int32 severity; /*!< The severity of the alert. One + of KHERR_ERROR, KHERR_WARNING or + KHERR_INFO. The default is + KHERR_INFO. Do not set directly. + Use khui_alert_set_severity(). */ + + khm_int32 alert_commands[KHUI_MAX_ALERT_COMMANDS]; + /*!< The command buttons associated + with the alert. Use + khui_alert_add_command() to add a + command. The buttons will appear in + the order in which they were added. + The first button will be the + default. Each command should be a + known action identifier. */ + khm_int32 n_alert_commands; + + wchar_t * title; /*!< The title of the alert. Subject + to ::KHUI_MAXCCH_TITLE. Use + khui_alert_set_title() to set. Do + not modify directly. */ + + wchar_t * message; /*!< The main message of the alert. + Subject to ::KHUI_MAXCCH_MESSAGE. + Use khui_alert_set_message() to + set. Do not modify direcly. */ + + wchar_t * suggestion; /*!< A suggestion. Appears below + the message text. Use + khui_alert_set_suggestion() to + set. Do not modify directly. */ + +#ifdef _WIN32 + POINT target; +#endif + + khm_int32 flags; /*!< combination of + ::khui_alert_flags. Do not modify + directly. */ + + kherr_context * err_context; + /*!< If non-NULL at the time the alert + window is shown, this indicates that + the alert window should provide an + error viewer for the given error + context. */ + + kherr_event * err_event; + /*!< If non-NULL at the time the alert + window is shown, this indicates that + the alert window should provide an + error viewer for the given error + event. If an \a err_context is also + given, the error viewer for the + context will be below this error. */ + + khm_int32 response; + /*!< Once the alert is displayed to + the user, when the user clicks one + of the command buttons, the command + ID will be assigned here. */ + + int refcount; /* internal */ + + LDCL(struct tag_khui_alert); /* internal */ +} khui_alert; + +#define KHUI_ALERT_MAGIC 0x48c39ce9 + +/*! \brief Maximum number of characters in title including terminating NULL + */ +#define KHUI_MAXCCH_TITLE 256 + +/*! \brief Maximum number of bytes in title including terminating NULL + */ +#define KHUI_MAXCB_TITLE (KHUI_MAXCCH_TITLE * sizeof(wchar_t)) + +/*! \brief Maximum number of characters in message including terminating NULL + */ +#define KHUI_MAXCCH_MESSAGE 1024 + +/*! \brief Maximum number of bytes in message including terminating NULL + */ +#define KHUI_MAXCB_MESSAGE (KHUI_MAXCCH_MESSAGE * sizeof(wchar_t)) + +/*! \brief Maxumum number of characters in a suggestion including terminating NULL */ +#define KHUI_MAXCCH_SUGGESTION 1024 + +/*! \brief Maximum number of bytes in a suggestion, including terminating NULL */ +#define KHUI_MAXCB_SUGGESTION (KHUI_MAXCCH_SUGGESTION * sizeof(wchar_t)) + +/*! \brief Flags for an alert */ +enum khui_alert_flags { + KHUI_ALERT_FLAG_FREE_STRUCT =0x00000001, + /*!< Internal. Free the structure once the alert is done. */ + + KHUI_ALERT_FLAG_FREE_TITLE =0x00000002, + /*!< Internal. Free the \a title field when the alert is done.*/ + + KHUI_ALERT_FLAG_FREE_MESSAGE =0x00000004, + /*!< Internal. Free the \a message field when the alert is done. */ + + KHUI_ALERT_FLAG_FREE_SUGGEST =0x00000008, + /*!< Internal. Free the \a suggest field when the alert is done */ + + KHUI_ALERT_FLAG_DEFACTION =0x00000010, + /*!< If the message is displayed as a balloon prompt, then perform + the default action when it is clicked. The default action is + the first action added to the alert. Cannot be used if there + are no actions or if ::KHUI_ALERT_FLAG_REQUEST_WINDOW is + specified.*/ + + KHUI_ALERT_FLAG_VALID_TARGET =0x00010000, + /*!< There is a valid target for the alert */ + + KHUI_ALERT_FLAG_VALID_ERROR =0x00020000, + /*!< There is a valid error context associated with the alert */ + + KHUI_ALERT_FLAG_DISPLAY_WINDOW =0x01000000, + /*!< The alert has been displayed in a window */ + + KHUI_ALERT_FLAG_DISPLAY_BALLOON =0x02000000, + /*!< The alert has been displayed in a ballon */ + + KHUI_ALERT_FLAG_REQUEST_WINDOW =0x04000000, + /*!< The alert should be displayed in a window */ + + KHUI_ALERT_FLAG_REQUEST_BALLOON =0x08000000, + /*!< The alert should be displayed in a balloon */ + + KHUI_ALERT_FLAGMASK_RDWR =0x0C000010, + /*!< Bit mask of flags that can be set by khui_alert_set_flags() */ +}; + +/*! \brief Create an empty alert object + + The returned result is a held pointer to a ::khui_alert object. + Use khui_alert_release() to release the object. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_create_empty(khui_alert ** result); + +/*! \brief Create a simple alert object + + The returned result is a held pointer to a ::khui_alert object. + Use khui_alert_release() to release the object. + + \param[in] title The title of the alert. (Required, Localized) + Limited by ::KHUI_MAXCCH_TITLE. + + \param[in] message The message. (Required. Localized). Limited + by ::KHUI_MAXCCH_MESSAGE. + + \param[in] severity One of ::tag_kherr_severity + + \param[out] result Receives a held pointer to a ::khui_alert + object upon successful completion. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_create_simple(const wchar_t * title, + const wchar_t * message, + khm_int32 severity, + khui_alert ** result); + +/*! \brief Set the title of an alert object + + The title is limited by ::KHUI_MAXCCH_TITLE. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_title(khui_alert * alert, + const wchar_t * title); + +/*! \brief Set the message of an alert object + + The message is limited by ::KHUI_MAXCCH_MESSAGE. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_message(khui_alert * alert, + const wchar_t * message); + +/*! \brief Set the suggestion of an alert object + + The suggestion is limited by ::KHUI_MAXCCH_SUGGESTION + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_suggestion(khui_alert * alert, + const wchar_t * suggestion); + +/*! \brief Set the severity of the alert object + + The severity value is one of ::tag_kherr_severity + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_severity(khui_alert * alert, + khm_int32 severity); + +/*! \brief Sets the flags of the alert + + The flags are as defined in ::khui_alert_flags. The bits that are + on in \a mask will be set to the corresponding values in \a flags. + Only the bits specified in ::KHUI_ALERT_FLAGMASK_RDWR can be + specified in \a mask. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_set_flags(khui_alert * alert, khm_int32 mask, khm_int32 flags); + +/*! \brief Clear all the commands from an alert object + + \see khui_alert_add_command() + */ +KHMEXP khm_int32 KHMAPI +khui_alert_clear_commands(khui_alert * alert); + +/*! \brief Add a command to an alert object + + The command ID should be a valid registered command. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_add_command(khui_alert * alert, + khm_int32 command_id); + +/*! \brief Display an alert + + The alert must have a valid \a severity, \a title and a \a message + to be displayed. Otherwise the function immediately returns with + a failure code. + + The method used to display the alert is as follows: + + - A balloon alert will be shown if one of the following is true: + - The NetIDMgr application is minimized or in the background. + - ::KHUI_ALERT_FLAG_REQUEST_BALLOON is specified in \a flags. + - Otherwise an alert window will be shown. + + If the message, title of the alert is too long to fit in a balloon + prompt, there's a suggestion or if there are custom commands then + a placeholder balloon prompt will be shown which when clicked on, + shows the actual alert in an alert window. + + An exception is when ::KHUI_ALERT_FLAG_DEFACTION is specified in + flags. In this case instead of a placeholder balloon prompt, one + will be shown with the actual title and message (truncated if + necessary). Clicking on the balloon will have the same effect as + choosing the first command in the action. + + The placeholder balloon prompt will have a title derived from the + first 63 characters of the \a title field in the alert and a + message notifying the user that they should click the balloon + prompt for more information. + + To this end, it is beneficial to limit the length of the title to + 63 characters (64 counting the terminating NULL). This limit is + enforced on Windows. Also, try to make the title descriptive. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_show(khui_alert * alert); + +/*! \brief Queue an alert + + Instead of displaying the alert immediately, the alert is queued + and the status bar updated to notify the user that there is a + pending alert. Once the user activates the pending alert, it will + be displayed as if khui_alert_show() was called. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_queue(khui_alert * alert); + +/*! \brief Display a simple alert + + \see khui_alert_show() + */ +KHMEXP khm_int32 KHMAPI +khui_alert_show_simple(const wchar_t * title, + const wchar_t * message, + khm_int32 severity); + +/*! \brief Obtain a hold on the alert + + An alert structure is only considered valid for the duration that + there is a hold on it. + + Use khui_alert_release() to release the hold. + */ +KHMEXP khm_int32 KHMAPI +khui_alert_hold(khui_alert * alert); + +/*! \brief Release the hold on the alert + + Holds obtained on an alert using any of the functions that either + return a held pointer to an alert or implicitly obtains a hold on + it need to be undone through a call to khui_alert_release(). + */ +KHMEXP khm_int32 KHMAPI +khui_alert_release(khui_alert * alert); + +/*! \brief Lock an alert + + Locking an alert disallows any other thread from accessing the + alert at the same time. NetIDMgr keeps a global list of all alert + objects and the user interface may access any of them at various + points in time. Locking the alert allows a thread to modify an + alert without causing another thread to be exposed to an + inconsistent state. + + Once a thread obtains a lock on the alert, it must call + khui_alert_unlock() to unlock it. Otherwise no other thread will + be able to access the alert. + + \note Currently the alert lock is global. Locking one alert + disallows access to all other alerts as well. + + \note Calling khui_alert_lock() is only necessary if you are + modifying the ::khui_alert structure directly. Calling any of + the khui_alert_* functions to modify the alert does not + require obtaining a lock, as they perform synchronization + internally. +*/ +KHMEXP void KHMAPI +khui_alert_lock(khui_alert * alert); + +/*! \brief Unlock an alert + + \see khui_alert_lock() +*/ +KHMEXP void KHMAPI +khui_alert_unlock(khui_alert * alert); + +/*!@}*/ +/*!@}*/ + +#endif diff --git a/mechglue/src/windows/identity/uilib/khconfigui.h b/mechglue/src/windows/identity/uilib/khconfigui.h new file mode 100644 index 000000000..ac9fc614c --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khconfigui.h @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHCONFIGUI_H +#define __KHIMAIRA_KHCONFIGUI_H + +/*! \addtogroup khui +@{ */ + +/*! \defgroup khui_cfg Configuration Panels + + Configuration panels are the primary means from which the user is + presented with an interface to change NetIDMgr and plugin + configuration. + +@{ */ + +/*! \brief Configuration window notification message + + This is the message that will be used to notify dialog panels. + + The format of the message is : + - uMsg : KHUI_WM_CFG_NOTIFY + - HIWORD(wParam) : one of ::khui_wm_cfg_notifications + + \note This is the same as ::KHUI_WM_NC_NOTIFY + */ +#define KHUI_WM_CFG_NOTIFY (WM_APP + 0x101) + +/*! \brief Configuration notifications + + These are sent thorugh a ::KHUI_WM_CFG_NOTIFY message. + + The format of the message is : + - uMsg : KHUI_WM_CFG_NOTIFY + - HIWORD(wParam) : one of ::khui_wm_cfg_notifications + */ +enum khui_wm_cfg_notifications { + WMCFG_SHOW_NODE = 1, + /*!< Sent to the configuration dialog to request that the panel + for the specified node be shown. The \a lParam message + parameter will contain a held ::khui_config_node handle. The + sender of the mssage is responsible for releasing the handle.*/ + + WMCFG_UPDATE_STATE = 2, + /*!< Sent to the configuration dialog to indicate that the state + flags for the specified configuration node have changed. + + - LOWORD(wParam) : new flags + - lParam : ::khui_config_node for the node*/ + + WMCFG_APPLY = 3, + /*!< Sent to all the configuration panels when the user clicks the + 'Apply' button or the 'Ok' button. The panels are responsible + for applying the configuration changes and updating their flags + using khui_cfg_set_flags(). */ +}; + +/*! \brief Registration information for a configuration node + + \see khui_cfg_register_node() +*/ +typedef struct tag_khui_config_node_reg { + const wchar_t * name; /*!< Internal identifier + (not-localized, required). The name + is required to be unique among + sibling nodes. However it is not + required to be unique globally. The + size of the name is constrained by + ::KHUI_MAXCCH_NAME*/ + + const wchar_t * short_desc; /*!< Short description (Localized, + required). This is the name which + identifies the node within a + collection of siblings. The size of + the string is constrained by + ::KHUI_MAXCCH_SHORT_DESC*/ + + const wchar_t * long_desc; /*!< Global name of the node. + (Localized, required). This + uniquely identifies the node in the + collection of all configuration + nodes. The size of the string is + constrained by + ::KHUI_MAXCCH_LONG_DESC.*/ + + HMODULE h_module; /*!< Module which contains the dialog + resource specified in \a + dlg_template */ + + LPWSTR dlg_template; /*!< Dialog template for the + configuration window */ + + DLGPROC dlg_proc; /*!< Dialog procedure */ + + khm_int32 flags; /*!< Flags. Can be a combination of + ::KHUI_CNFLAG_SORT_CHILDREN and + ::KHUI_CNFLAG_SUBPANEL*/ + +} khui_config_node_reg; + +/*! \brief Sort the child nodes by short description */ +#define KHUI_CNFLAG_SORT_CHILDREN 0x0001 + +/*! \brief Is a subpanel */ +#define KHUI_CNFLAG_SUBPANEL 0x0002 + +/*! \brief Node represents a panel that is replicated for all child nodes */ +#define KHUI_CNFLAG_PLURAL 0x0004 + +#define KHUI_CNFLAG_MODIFIED 0x0010 +#define KHUI_CNFLAG_APPLIED 0x0020 + +#define KHUI_CNFLAGMASK_STATIC 0x000f +#define KHUI_CNFLAGMASK_DYNAMIC 0x00f0 + +/*! \brief Maximum length of the name in characters + + The length includes the terminating NULL + */ +#define KHUI_MAXCCH_NAME 256 + +/*! \brief Maximum length of the name in bytes + + The length includes the terminating NULL + */ +#define KHUI_MAXCB_NAME (KHUI_MAXCCH_NAME * sizeof(wchar_t)) + +/*! \brief Maximum length of the long description in characters + + The length includes the terminating NULL + */ +#define KHUI_MAXCCH_LONG_DESC 1024 + +/*! \brief Maximum length of the long description in bytes + + The length includes the terminating NULL + */ +#define KHUI_MAXCB_LONG_DESC (KHUI_MAXCCH_LONG_DESC * sizeof(wchar_t)) + +/*! \brief Maximum length of the short description in chracters + + The length includes the terminating NULL + */ +#define KHUI_MAXCCH_SHORT_DESC 256 + +/*! \brief Maximum length of the short description in bytes + + The length includes the terminating NULL + */ +#define KHUI_MAXCB_SHORT_DESC (KHUI_MAXCCH_SHORT_DESC * sizeof(wchar_t)) + +/*! \brief Width of a configuration dialog in dialog units + + ::CFGDLG_WIDTH and ::CFGDLG_HEIGHT specify the dimensions of a + configuration dialog width and height in dialog units. The dialog + will be created as a child of the configuration dialog and placed + within it. + */ +#define CFGDLG_WIDTH 255 + +/*! \brief Height of a configuration dialog in dialog units + + \see ::CFGDLG_WIDTH +*/ +#define CFGDLG_HEIGHT 182 + +/*! \brief Width of a configuration tab dialog in dialog units + + ::CFGDLG_TAB_WIDTH and ::CFGDLG_TAB_HEIGHT specify the dimensions + (in dialog units) of a dialog that will be placed within a tab + control for dialogs where multiple display panels need to be + shown. + */ +#define CFGDLG_TAB_WIDTH 235 + +/*! \brief Height of configuration tab dialog in dialog units + + \see ::CFGDLG_TAB_WIDTH + */ +#define CFGDLG_TAB_HEIGHT 151 + +/*! \brief A handle to a configuration node + + \see khui_cfg_open_node(), khui_cfg_close_node() +*/ +typedef khm_handle khui_config_node; + +/*! \brief Initialization data passed in to a subpanel + + When creating a subpanel, a pointer to the following strucutred + will be passed in as the creation parameter for the dialog. +*/ +typedef struct tag_khui_config_init_data { + khui_config_node ctx_node; /*!< The node under which the current + dialog subpanel is being created. */ + + khui_config_node this_node; /*!< The node which provided the + registration information for the + creation of the subpanel. */ + + khui_config_node ref_node; /*!< The parent node of the subpanel + node. In nodes which have the + ::KHUI_CNFLAG_PLURAL, this would be + different from the \a node. This is + the node under which the subpanel + was registered. */ +} khui_config_init_data; + +/*! \brief Register a configuration node + + The caller fills the registration information in the + ::khui_config_node_reg structre. If the call succeeds, the + function will return KHM_ERROR_SUCCESS. + + \param[in] parent Parent of the node to be registered. Set to + NULL if the parent is the root node. + + \param[in] reg Registration information + + \param[out] new_id Receives the new unique identifier of the + configuration node. Pass in NULL if the new identifier is not + required. + + \retval KHM_ERROR_SUCCESS Success + \retval KHM_ERROR_INVALID_PARAM One or more parameters, or fields + of reg were invalid + \retval KHM_ERROR_DUPLICATE A node with the same name exists as a + child of the specified parent node. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_register(khui_config_node parent, + const khui_config_node_reg * reg); + +/*!\brief Open a configuration node by name + + If successful, the \a result parameter will receive a handle to + the configuration node. Use khui_cfg_release() to release + the handle. + + \param[in] parent Parent node. Set to NULL to specify root node. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_open(khui_config_node parent, + const wchar_t * name, + khui_config_node * result); + +/*! \brief Remove a configuration node + + Marks a configuration node as deleted. Once all the handles, + including the handle specified in \a node have been released, it + will be deleted. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_remove(khui_config_node node); + +/*! \brief Hold a handle to a configuration node + + Obtains an additional hold on the handle specified by \a node. + The hold must be released with a call to \a + khui_cfg_release() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_hold(khui_config_node node); + +/*! \brief Release a handle to a configuration node + + \see khui_cfg_hold() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_release(khui_config_node node); + +/*! \brief Get the parent of a node + + Returns a held handle to the parent of the node, or NULL if the + current node is a top level node. The returned handle must be + released with khui_cfg_release(). + + \retval KHM_ERROR_SUCCESS The handle to the parent node is in \a result + \retval KHM_ERROR_NOT_FOUND The node is a top level node + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_parent(khui_config_node vnode, + khui_config_node * result); + +/*! \brief Get a handle to the first child node + + If the call is successful, \a result will receieve a handle to the + first child node of the specified node. The returned handle must + be released with a call to khui_cfg_release() + + If \a parent does not have any child nodes, the function will + return KHM_ERROR_NOT_FOUND and set \a result to NULL. + + \param[in] parent Parent node. Set to NULL to specify root node. + \param[out] result Receives a held handle to the first child node. + + \see khui_cfg_get_next() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_first_child(khui_config_node parent, + khui_config_node * result); + +/*! \brief Get a handle to the first subpanel + + If the call is successful, \a result will receieve a handle to the + first subpanel node of the specified node. The returned handle + must be released with a call to khui_cfg_release() + + If \a parent does not have any subpanels, the function will return + KHM_ERROR_NOT_FOUND and set \a result to NULL. + + A subpanel node is a node which has the ::KHUI_CNFLAG_SUBPANEL + flag set. + + \param[in] parent Parent node. Set to NULL to specify root node. + \param[out] result Receives a held handle to the first subpanel node. + + \see khui_cfg_get_next() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_first_subpanel(khui_config_node vparent, + khui_config_node * result); + +/*! \brief Get a handle to the next sibling node + + If the call is successful, \a result will receive a held handle to + the next sibling node. The returned handle must be released with + a call to khui_cfg_release(). + + If there are no more sibling nodes, then the function return + KHM_ERROR_NOT_FOUND and set \a result to NULL. + + This function can be used to traverse a list of child nodes as + well as a list of subpanel nodes. + + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_next(khui_config_node node, + khui_config_node * result); + +/*! \brief Get a handle to the next sibling node + + Similar to khui_cfg_get_next(), but implicitly releases the handle + that was supplied. Equivalent to doing : + + \code + khui_cfg_get_next(node, &next); + khui_cfg_release(node); + node = next; + \endcode + + \param[in,out] node On entry, specifies the node whose sibling + needs to be fetched. On exit, will have either NULL or a held + handle to the sibling node. The handle which was supplied to + the function is released. + + \retval KHM_ERROR_SUCCESS The next node is now in \a node + \retval KHM_ERROR_INVALID_PARAM \a node was not a valid handle + \retval KHM_ERROR_NOT_FOUND There are no more siblings. \a node + is set to NULL. + + \note Even if there are no more siblings, the handle specified in + \a node on entry is released. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_next_release(khui_config_node * node); + +/*! \brief Get the name of a configuration node + + Gets the name (not the short description or the long description) + of the given configuration node. +*/ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_name(khui_config_node node, + wchar_t * buf, + khm_size * cb_buf); + +/*! \brief Get registration information for a node + + The registration information that is returned is a shallow copy of + the data kept by NetIDMgr. In particular, the strings that will + be returned actually point to internal buffers and should not be + modified. + + No further action is necessary to release the information. + However, the returned data ceases to be valid when \a node is + released with a call to khui_cfg_release(). + + \param[in] node Node for which information is requested. Can be NULL if requesting information about the root node. + \param[out] reg Pointer to a ::khui_config_node_reg structure. + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_reg(khui_config_node node, + khui_config_node_reg * reg); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP HWND KHMAPI +khui_cfg_get_hwnd_inst(khui_config_node node, + khui_config_node noderef); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP LPARAM KHMAPI +khui_cfg_get_param_inst(khui_config_node node, + khui_config_node noderef); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_hwnd_inst(khui_config_node node, + khui_config_node noderef, + HWND hwnd); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_param_inst(khui_config_node node, + khui_config_node noderef, + LPARAM param); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP HWND KHMAPI +khui_cfg_get_hwnd(khui_config_node node); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP LPARAM KHMAPI +khui_cfg_get_param(khui_config_node node); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_hwnd(khui_config_node node, HWND hwnd); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_param(khui_config_node node, LPARAM param); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_clear_params(void); + +/*! \brief Internal use + + This function is used internally by NetIDMgr. Do not use. +*/ +KHMEXP void KHMAPI +khui_cfg_set_configui_handle(HWND hwnd); + +/*! \brief Update the state for the specified node + + \param[in] node ::khui_config_node handle for the configuration node. + + \param[in] flags New flags. Combination of ::KHUI_CNFLAG_APPLIED and ::KHUI_CNFLAG_MODIFIED + + \param[in] mask Valid bits in \a flags + + \note Should only be called from within the dialog procedure for + the configuration node. + */ +KHMEXP void KHMAPI +khui_cfg_set_flags(khui_config_node vnode, khm_int32 flags, khm_int32 mask); + +/*! \brief Retrieve the state flags for the configuration node + + \see khui_cfg_set_flags() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_flags(khui_config_node vnode); + +/*! \brief Utility function: Initialize dialog box window data + + This function initializes the dialog box window data using the + ::khui_config_init_data that was passed into the WM_INITDIALOG + message. + + A new block of memory will be alocated to store the dialog data as + well as any extra space specified. A pointer to this memory block + will be stored in the \a DWLP_USER slot in the dialog box. + + The allocated block of memory must be freed by a call to + khui_cfg_free_dialog_data(). While handling other messages, the + dialog data can be retrieved using khui_cfg_get_dialog_data(). + + \param[in] hwnd_dlg Handle to the dialog box + + \param[in] data Pointer to the ::khui_config_init_data that was + passed in to WM_INITDIALOG (this is the value of \a lParam) + + \param[in] cb_extra Number of extra bytes to allocate, along with + the space required to store the contents of + ::khui_config_init_data. The extra space will be initialized + to zero. + + \param[out] new_data Receives a pointer to the copy of the + initialization data that was allocated. Optional. Pass in + NULL if this value is not required. + + \param[out] extra Receives a pointer to the block of extra memory + allocated as specified in \a cb_extra. If \a cb_extra is 0, + then this receives a NULL. + + \see khui_cfg_get_dialog_data(), khui_cfg_free_dialog_data() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_init_dialog_data(HWND hwnd_dlg, + const khui_config_init_data * data, + khm_size cb_extra, + khui_config_init_data ** new_data, + void ** extra); + +/*! \brief Utility function: Retrieves dialog data + + Retrieves the dialog data previoulsy stored using + khui_cfg_init_dialog_data(). + + \param[in] hwnd_dlg Handle to the dialog box + + \param[out] data Receives a pointer to the ::khui_config_init_data + block. + + \param[out] extra Receives a pointer to the extra memory + allocated. Optional (set to NULL if this value is not needed). +*/ +KHMEXP khm_int32 KHMAPI +khui_cfg_get_dialog_data(HWND hwnd_dlg, + khui_config_init_data ** data, + void ** extra); + +/*! \brief Utility function: Free dialog data + + Deallocates the memory allcated in a previous call to + khui_cfg_init_dialog_data() + */ +KHMEXP khm_int32 KHMAPI +khui_cfg_free_dialog_data(HWND hwnd_dlg); + +/*! \brief Sets the instance flags for a subpanel + + Since there can be more than one subpanel in a configuration + panel, they shouldn't modify the flags of the configuration node + directly. Instead, they should call this function to set the + instance flags. + + The instance flags will be merged with the flags for the + configuration node automatically. + */ +KHMEXP void KHMAPI +khui_cfg_set_flags_inst(khui_config_init_data * d, + khm_int32 flags, + khm_int32 mask); + +/*!@} */ +/*!@} */ +#endif diff --git a/mechglue/src/windows/identity/uilib/khhtlink.h b/mechglue/src/windows/identity/uilib/khhtlink.h new file mode 100644 index 000000000..f5fb3deef --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khhtlink.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHHTLINK_H +#define __KHIMAIRA_KHHTLINK_H + +/*! \addtogroup khui +@{ */ + +/*! \defgroup khui_hyperlink Hyperlink +@{*/ + +/*! \brief A hyperlink + + When a link in a hypertext window is clicked, this structure is + passed along with the message. + + The link text fields do to point to NULL terminated strings. + Instead, the length fields should be used to extract the string. + */ +typedef struct tag_khui_htwnd_link { + RECT r; + wchar_t * id; + int id_len; + wchar_t * param; + int param_len; +} khui_htwnd_link; + +#define KHUI_MAXCCH_HTLINK_FIELD 256 +#define KHUI_MAXCB_HTLINK_FIELD (KHUI_MAXCCH_HTLINK_FIELD * sizeof(wchar_t)) + +/*!@}*/ +/*!@}*/ + +#endif diff --git a/mechglue/src/windows/identity/uilib/khnewcred.h b/mechglue/src/windows/identity/uilib/khnewcred.h new file mode 100644 index 000000000..257434454 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khnewcred.h @@ -0,0 +1,906 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHNEWCRED_H +#define __KHIMAIRA_KHNEWCRED_H + +/******************************************************************** + New credentials windows +*********************************************************************/ + +/*! \addtogroup khui +@{ */ + +/*! \defgroup khui_cred Credentials acquisition + + Declarations associated with credentials acquisition. + +@{ */ + +/*! \brief Window message sent to credentials type panels + + This message is sent to the child windows. + + The format of the message is : + - uMsg : KHUI_WM_NC_NOTIFY + - HIWORD(wParam) : one of ::khui_wm_nc_notifications + - LPARAM : pointer to the ::khui_new_creds structure +*/ +#define KHUI_WM_NC_NOTIFY (WM_APP + 0x101) + +/*! \brief The first control ID that may be used by an identity provider */ +#define KHUI_CW_ID_MIN 8016 + +/*! \brief The maximum number of controls that may be created by an identity provider*/ +#define KHUI_CW_MAX_CTRLS 8 + +/*! \brief The maximum control ID that may be used by an identity provider */ +#define KHUI_CW_ID_MAX (KHUI_CW_ID_MIN + KHUI_CW_MAX_CTRLS - 1) + + +/*! \brief Credentials dialog notifications + + These notifications will be sent to the individual dialog + procedures of the credential type panels as a ::KHUI_WM_NC_NOTIFY + message. +*/ +enum khui_wm_nc_notifications { + WMNC_DIALOG_EXPAND = 1, + /*!< The dialog is getting expanded. + + This message is sent to the new creds dialog to set the dialog + to expanded mode. In expanded mode, all credentials type panels + are visible as opposed to the compressed mode where they are not + visible. The message is not sent to credentials type panels.*/ + + WMNC_DIALOG_SETUP, + /*!< Sent by NetIDMgr to the new creds window to notify it that + the dialog should create all the type configuration panels. + + Until this message is issued, none of the credentials type + panels exist. The credentials type panels will receive + WM_INITDIALOG etc as per the normal dialog creation process. */ + + WMNC_DIALOG_ACTIVATE, + /*!< Sent by NetIDMgr to the new creds window to notify it that + the dialog should do final initialization work and activate. */ + + WMNC_DIALOG_MOVE, + /*!< Sent by the new creds widnow to all the panels notifying them + that the NC window is moving. */ + + WMNC_DIALOG_SWITCH_PANEL, + /*!< Sent to the new creds window to cause it to switch to the + panel identified by LOWORD(wParam). + + Does nothing if the specified panel is already the current + panel. If the dialog is in compact mode and making the + specified panel visible requires switching to expanded mode, the + dialog will do so. */ + + WMNC_UPDATE_CREDTEXT, + /*!< Sent to all the credential type panels for a credentials + window to request them to update the credential text. + + When sent to the new credentials window, causes it to send the + WMNC_UPDATE_CREDTEXT message to all the credential type panels + and update the cred text window.*/ + + WMNC_CREDTEXT_LINK, + /*!< Sent to a panel dialog proc when a user clicks a credtext + embedded link that belongs to that panel */ + + WMNC_IDENTITY_CHANGE, + /*!< The primary identity has changed */ + + WMNC_CLEAR_PROMPTS, + /*!< Sent to the new creds window to clear any custom prompts */ + + WMNC_SET_PROMPTS, + /*!< Sent to the new creds window to set custom prompts */ + + WMNC_DIALOG_PREPROCESS, + /*!< Sent to all the credentials type panels to notify them that + the dialog is about to be processed */ + + WMNC_DIALOG_PROCESS, + /*!< Process the dialog and signal whether to exit the dialog or + not */ + + WMNC_DIALOG_PROCESS_COMPLETE, + /*!< Sent to the new creds window to indicate that the all the + threads have completed processing.*/ + + WMNC_TYPE_STATE, + /*!< Sent to the new creds window as notification that a + particular credentials type has changed state from enabled to + disabled or vice versa. The LPARAM member of the message + specifies the credentials type identifier for the changed + type */ + + WMNC_ADD_CONTROL_ROW, + /*!< Add a row of controls to a new cred dialog. This is an + internal message. */ +}; + +/*! \brief Plugins can use WMNC_NOTIFY message codes from here on up + + \see ::KHUI_WM_NC_NOTIFY + */ +#define WMNC_USER 2048 + +/*! \brief Notifications to the identity provider + + These notifications are sent through to the identity provider's UI + callback that was obtained using a ::KMSG_IDENT_GET_UI_CB message. + + The callback routine is called from the context of the UI thread + and is expected to not make any blocking calls. One of the + following commands will be passed in as the \a cmd parameter to + the callback. + */ +enum khui_wm_nc_ident_notify { + WMNC_IDENT_INIT, + /*!< Initialize an identity selector for a new credentials + dialog. The \a lParam parameter contains a handle to the + dialog window which will contain the identity selector + controls. The identity provider may make use of the \a + ident_aux field of the ::khui_new_creds structure to hold any + data pertaining to the credentials acquisition dialog.*/ + + WMNC_IDENT_WMSG, + /*!< Windows message. Presumably sent from one of the controls + that was created by the identity provider. The callback is + expected to return TRUE if it processed the message or FALSE + if it did not. The \a uMsg, \a wParam and \a lParam + parameters are set to the values passed in by Windows. */ + + WMNC_IDENT_EXIT, + /*!< Terminate a credentials acquisition dialog. Sent just before + the dialog is terminated. */ +}; + +/*! \name Standard credtext link IDs +@{*/ + +/*! \brief Switch the panel + + The \a id attribute of the link specifies the ordinal of the panel + to switch to. +*/ +#define CTLINKID_SWITCH_PANEL L"SwitchPanel" + +/*@}*/ + +/*forward dcl*/ +struct tag_khui_new_creds_by_type; +typedef struct tag_khui_new_creds_by_type khui_new_creds_by_type; +struct tag_khui_new_creds_prompt; +typedef struct tag_khui_new_creds_prompt khui_new_creds_prompt; +struct tag_khui_new_creds; +typedef struct tag_khui_new_creds khui_new_creds; + +typedef LRESULT +(KHMAPI *khui_ident_new_creds_cb)(khui_new_creds * nc, + UINT cmd, + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +/*! \brief New credentials acquisition blob + + A pointer to an object of this type is passed in along with the + credentials acquisition messages. + + \see \ref cred_acq for more information +*/ +typedef struct tag_khui_new_creds { + khm_int32 magic; + + khm_int32 subtype; /*!< Subtype of the request that is + being handled through this object. + One of ::KMSG_CRED_INITIAL_CREDS, + ::KMSG_CRED_NEW_CREDS or + ::KMSG_CRED_RENEW_CREDS */ + + CRITICAL_SECTION cs; + + khm_boolean set_default; /*!< After a successfull credentials + acquisition, set the primary + identity as the default. */ + + khm_handle *identities; /*!< The list of identities associated + with this request. The first + identity in this list (\a + identities[0]) is the primary + identity. */ + + khm_size n_identities; /*!< Number of identities in the list + \a identities */ + + khm_size nc_identities; /*!< Internal use */ + + khui_action_context ctx; /*!< An action context specifying the + context in which the credentials + acquisition operation was + launced. */ + + khm_int32 mode; /*!< The mode of the user interface. + One of ::KHUI_NC_MODE_MINI or + ::KHUI_NC_MODE_EXPANDED. */ + + HWND hwnd; /*!< Handle to the new credentials + window. */ + + struct tag_khui_new_creds_by_type **types; + /*!< Internal use */ + khm_handle *type_subs; /*!< Internal use */ + khm_size n_types; /*!< Internal use */ + khm_size nc_types; /*!< Internal use */ + + khm_int32 result; /*!< One of ::KHUI_NC_RESULT_CANCEL or + ::KHUI_NC_RESULT_GET_CREDS indicating + the result of the dialog with the + user */ + + khm_int32 response; /*!< Response. See individual message + documentation for info on what to do + with this field */ + + wchar_t *password; /*!< Not set until the dialog ends */ + + /* UI stuff */ + + wchar_t *banner; /*!< Internal use */ + wchar_t *pname; /*!< Internal use */ + khm_size n_prompts; /*!< Internal use */ + khm_size nc_prompts; /*!< Internal use */ + struct tag_khui_new_creds_prompt ** prompts; /*!< Internal use */ + + khui_ident_new_creds_cb ident_cb; /*!< Internal use */ + + wchar_t *window_title; /*!< Internal use */ + + LPARAM ident_aux; /*!< Auxilliary field which is + reserved for use by the identity + provider during the course of + conducting this dialog. */ + +} khui_new_creds; + +#define KHUI_NC_MAGIC 0x84270427 + +/*!\name Result values for khui_new_creds_t::result + @{*/ +#define KHUI_NC_RESULT_GET_CREDS 0 +#define KHUI_NC_RESULT_CANCEL 1 +/*@}*/ + +/*!\name Mode values for khui_new_creds_t::mode + @{*/ +#define KHUI_NC_MODE_MINI 0 +#define KHUI_NC_MODE_EXPANDED 1 +/*@}*/ + +/*!\name Response values for khui_new_creds_t::response + @{*/ +/*!\brief No known response */ +#define KHUI_NC_RESPONSE_NONE 0 + +/*!\brief It is okay to exit the dialog now + + This is the default, which is why it has a value of zero. In + order to prevent the dialog from exiting, set the + KHUI_NC_RESPONSE_NOEXIT response bit. */ +#define KHUI_NC_RESPONSE_EXIT 0 + +/*!\brief It is NOT okay to exit the dialog now + + Used to indicate that further user-interaction is necessary to + process the dialog. Usually this is accompanied by setting + necessary custom prompts and notifications so the user knows why + the dialog is prompting for more information. + */ +#define KHUI_NC_RESPONSE_NOEXIT 0x00000002 + +/*!\brief The dialog was processed successfully + + Since this is the default response, the value is zero. Use one of + KHUI_NC_RESPONSE_FAILED or KHUI_NC_RESPONSE_PENDING to indicate an + error or pending status. + */ +#define KHUI_NC_RESPONSE_SUCCESS 0 + +/*!\brief The processing of the dialog failed + + Self explanatory. More information about the failure should have + been reported using the khlog API, however, this response value + indicates to other credential types that depend on this credential + type that whatever it was that this credential type was supposed + to do didn't happen. +*/ +#define KHUI_NC_RESPONSE_FAILED 0x00000008 + +/*!\brief Further interaction required + + Set along with KHUI_NC_RESPONSE_NOEXIT although it is not + required. Setting this bit will automatically add the + KHUI_NC_RESPONSE_NOEXIT. + + If this bit is set, all dependent plugins will be set on hold + until another round of processing clears the pending bit. + */ +#define KHUI_NC_RESPONSE_PENDING 0x00000010 + +/*! \brief Completed + + This is automatically set if the plugin sets a response which does + not indicate either KHUI_NC_RESPONSE_NOEXIT or + KHUI_NC_RESPONSE_PENDING, which is considered to mean that the + plugin is completed processing. + + This flag cannot be explicitly specified in a response. + */ +#define KHUI_NC_RESPONSE_COMPLETED 0x00000020 + +#define KHUI_NCMASK_RESPONSE (KHUI_NC_RESPONSE_EXIT|KHUI_NC_RESPONSE_NOEXIT) +#define KHUI_NCMASK_RESULT (KHUI_NC_RESPONSE_SUCCESS|KHUI_NC_RESPONSE_FAILED|KHUI_NC_RESPONSE_PENDING) +/*@}*/ + +/*!\brief Maximum number of dependencies for a credentials type */ +#define KHUI_MAX_TYPE_DEPS 8 + +/*!\brief Maximum number of credential types for a new creds window */ +#define KHUI_MAX_NCTYPES 16 + +/*!\brief Maximum number of characters in a password + + Length includes the termininating NULL +*/ +#define KHUI_MAXCCH_PASSWORD 512 + +/*! \brief Maximum number of bytes in a password + + Includes terminating NULL +*/ +#define KHUI_MAXCB_PASSWORD (KHUI_MAXCCH_PASSWORD * sizeof(wchar_t)) + +/*! \brief Maximum number of characters in a custom banner + + Length includes terminating NULL +*/ +#define KHUI_MAXCCH_BANNER 256 + + +/*! \brief Maximum number of bytes in a custom banner + + Length includes terminating NULL +*/ +#define KHUI_MAXCB_BANNER (KHUI_MAXCCH_BANNER * sizeof(wchar_t)) + +/*! \brief Maximum number of characters in a panel name + + Length includes terminating NULL +*/ +#define KHUI_MAXCCH_PNAME 256 + +/*! \brief Maximum number of bytes in a panel name + + Length includes terminating NULL +*/ +#define KHUI_MAXCB_PNAME (KHUI_MAXCCH_PNAME * sizeof(wchar_t)) + +/*! \brief A descriptor of a panel in the new credentials acquisition tab +*/ +typedef struct tag_khui_new_creds_by_type { + khui_new_creds * nc; /*!< Internal use. Do not set */ + khm_int32 flags; /*!< Internal use. Do not set */ + + khm_int32 type; /*!< The identifier of the credentials + type */ + + khm_int32 type_deps[KHUI_MAX_TYPE_DEPS]; + /*!< credentials types that this + credential type depends on. Each + element defines a credentials type + identifier that this type depends + on for this operation. */ + + khm_size n_type_deps; /*!< Number of dependencies listed + above. Should be between 0 and + ::KHUI_MAX_TYPE_DEPS */ + + khm_size ordinal; /*!< The requested ordinal. The UI + would attempt to place this panel at + the reqested order in the list of + panels. Set to -1 if the order does + not matter. Once the dialog is + activated this field will be updated + to reflect the actual ordinal of the + panel. */ + + wchar_t *name; /*!< Name of the panel (localized, + optional). If NULL, the localized + name of the credentials type is + used. */ + + HICON icon; /*!< Icon for the panel (optional) */ + + wchar_t *tooltip; /*!< Tooltip for the panel (localized, + optional). If NULL, no tooltip will + be assigned for the panel */ + + HMODULE h_module; /*!< Handle to the module containing + the dialog resource */ + + LPWSTR dlg_template; /*!< The dialog resource */ + DLGPROC dlg_proc; /*!< The dialog procedure */ + + HWND hwnd_panel; /*!< The dialog window */ + HWND hwnd_tc; /*!< Internal use. Do not set */ + + wchar_t *credtext; /*!< A brief description of the + current state of this cred + type. (localized, optional) */ + + LPARAM aux; /*!< auxilliary field. For use by the + credential provider */ +} khui_new_creds_by_type; + +/*!\name Flags for khui_new_creds_by_type + + Note that KHUI_NC_RESPONSE_SUCCESS, KHUI_NC_RESPONSE_FAILED, + KHUI_NC_RESPONSE_PENDING are also stored in the flags. + +@{*/ +#define KHUI_NCT_FLAG_PROCESSED 1024 +#define KHUI_NCT_FLAG_DISABLED 2048 +/*@}*/ + +/*! \brief Width of a new creds dialog panel in dialog units*/ +#define NCDLG_WIDTH 300 +/*! \brief Height of a new creds dialog panel in dialog units*/ +#define NCDLG_HEIGHT 166 + +/*! \brief Width of the button bar in dialog units */ +#define NCDLG_BBAR_WIDTH 60 +/*! \brief Height of a tab button in dialog units */ +#define NCDLG_TAB_HEIGHT 15 +/*! \brief Width of a tab button in dialog units */ +#define NCDLG_TAB_WIDTH 60 + +/*! \brief A custom prompt */ +typedef struct tag_khui_new_creds_prompt { + khm_size index; /*!< Set to the zero based index + of this prompt. */ + + khm_int32 type; /*!< one of KHUI_NCPROMPT_TYPE_* */ + wchar_t * prompt; /*!< prompt string. Cannot exceed + KHUI_MAXCCH_PROMPT */ + wchar_t * def; /*!< default value. Cannot exceed + KHUI_MAXCCH_PROMPT_VALUE */ + wchar_t * value; /*!< On completion, this is set to the + value that the user entered. Will + not exceed + KHUI_MAXCCH_PROMPT_VALUE */ + + khm_int32 flags; /*!< Combination of + KHUI_NCPROMPT_FLAG_* */ + + HWND hwnd_static; /* internal use */ + HWND hwnd_edit; /* internal use */ +} khui_new_creds_prompt; + +/*! \brief The prompt input is hidden + + The input is hidden for prompts which accept passwords. The + control which represents the input will display an asterisk or a + small circle corresponding to each character typed in, but will + not show the actual character. + */ +#define KHUI_NCPROMPT_FLAG_HIDDEN 1 + +/*! \brief Internal use */ +#define KHUI_NCPROMPT_FLAG_STOCK 2 + +/*! \brief Maximum number of characters in a prompt + + Refers to the prompt text that accompanies an input control. THe + length includes the terminating NULL. + */ +#define KHUI_MAXCCH_PROMPT 256 + +/*! \brief Maximum number of bytes in a prompt + + Refers to the prompt text that accompanies an input control. THe + length includes the terminating NULL. + */ +#define KHUI_MAXCB_PROMPT (KHUI_MAXCCH_PROMPT * sizeof(wchar_t)) + +/*! \brief Maximum number of characters that can be entered in an input control + + Refers to the input control of a prompt. The length includes the + terminating NULL. + */ +#define KHUI_MAXCCH_PROMPT_VALUE 256 + +/*! \brief Maximum number of bytes that can be entered in an input control + + Refers to the input control of a prompt. The length includes the + terminating NULL. + */ +#define KHUI_MAXCB_PROMPT_VALUE (KHUI_MAXCCH_PROMPT_VALUE * sizeof(wchar_t)) + +/* from krb5.h. Redefining here because we don't want to depend on + krb5.h for all credential types */ + +/*! \brief A password control */ +#define KHUI_NCPROMPT_TYPE_PASSWORD 1 + +/*! \brief New password control + + Used when changing the password + */ +#define KHUI_NCPROMPT_TYPE_NEW_PASSWORD 2 + +/*! \brief New password again control + + Used when changing the password + */ +#define KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN 3 + +/*! \brief Preauthentication (reserved) */ +#define KHUI_NCPROMPT_TYPE_PREAUTH 4 + +/*! \brief Control sizes */ +typedef enum tag_khui_control_size { + KHUI_CTRLSIZE_SMALL, + /*!< A small control fits in about 1/5 the width of the new + credentials panel */ + KHUI_CTRLSIZE_HALF, + /*!< Half size controls fit in 1/2 the width of the new + credentials panel */ + KHUI_CTRLSIZE_FULL, + /*!< Takes up the whole width of the crednetials panel */ +} khui_control_size; + +/*! \brief Internal use */ +typedef struct tag_khui_control_row { + HWND label; + HWND input; + khui_control_size size; +} khui_control_row; + +/*! \brief Create a ::khui_new_creds object + + Creates and initializes a ::khui_new_creds object. The created + object must be destroyed using the khui_cw_destroy_cred_blob() + function. + + \note Plugins should not call this function directly. The + necessary ::khui_new_creds objects will be created by + NetIDMgr. + + \see khui_cw_destroy_cred_blob() + */ +KHMEXP khm_int32 KHMAPI +khui_cw_create_cred_blob(khui_new_creds ** c); + +/*! \brief Destroy a ::khui_new_creds object + + Destroys a ::khui_new_creds object that was fomerly created using + a call to khui_cw_create_cred_blob(). + + \note Plugins should not call this function directly. The + necessary ::khui_new_creds objects will be created by + NetIDMgr. + + \see khui_cw_create_cred_blob() +*/ +KHMEXP khm_int32 KHMAPI +khui_cw_destroy_cred_blob(khui_new_creds *c); + +/*! \brief Lock the new_creds object + + When a plugin is accessing the fields of a ::khui_new_creds + object, it must first obtain a lock on the object so that other + threads will not modify the fields at the same time. Locking the + object ensures that the fields of the object will be consistent. + + Use khui_cw_unlock_nc() to undo the lock obtained through a call + to khui_cw_lock_nc(). + + It is not necessary to lock a new credentials object when + modifying it using the NetIDMgr API. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_lock_nc(khui_new_creds * c); + +/*! \brief Unlock a new_creds object + + \see khui_cw_lock_nc() + */ +KHMEXP khm_int32 KHMAPI +khui_cw_unlock_nc(khui_new_creds * c); + +/*! \brief Add a new panel to a new credentials acquisition window + + See the description of ::khui_new_cred_panel for information on + how to populate it to describe a credentials type panel. + + \see khui_cw_del_type() + \see \ref cred_acq_panel_spec + \see ::khui_new_cred_panel + \see ::khui_new_creds +*/ +KHMEXP khm_int32 KHMAPI +khui_cw_add_type(khui_new_creds * c, + khui_new_creds_by_type * t); + +/*! \brief Remove a panel from a new credentials acquisition window + + \see khui_cw_add_type() + */ +KHMEXP khm_int32 KHMAPI +khui_cw_del_type(khui_new_creds * c, + khm_int32 type); + +/*! \brief Find the panel belonging to a particular credentials type + + This panel would have been added to the new credentials window + using khui_cw_add_type(). + + \see khui_cw_add_type() + */ +KHMEXP khm_int32 KHMAPI +khui_cw_find_type(khui_new_creds * c, + khm_int32 type, + khui_new_creds_by_type **t); + +/*! \brief Enable/disable a particular credentials type + + Enables or disables the panel associated with a particular + credentials type. Does not preclude the credentials type from + participating in the new credentials acquisition. However, the + user will be prevented from interacting with the specific panel. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_enable_type(khui_new_creds * c, + khm_int32 type, + khm_boolean enable); + +/*! \brief Set the primary identity in a new credentials acuisition + + The primary identity dictates many of the defaults and the + semantics associated with the credentials acquision process. + Setting the primary identity also triggers the + ::WMNC_IDENTITY_CHANGE notification which will be sent to all the + credentials type panels. + + Has no effect if the primary identity is already the same as the + one specified in \a id. Specify NULL for \a id if the current + primary identity is to be cleared. + + If the primary identity is changed, then all the additional + identities associated with the new credentials acquisition dialog + will also be discarded. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_set_primary_id(khui_new_creds * c, + khm_handle id); + +/*! \brief Add an additional identity to the new credentials acquisition + + Individual plugins are free to decide how to handle additional + identities. Generally, they would attempt to obtain credentials + for the primary and additional identities, but would not consider + it an error if an additional identity failed to obtain + credentials. + + Calling this function with \a id of NULL does nothing. +*/ +KHMEXP khm_int32 KHMAPI +khui_cw_add_identity(khui_new_creds * c, + khm_handle id); + +/*! \brief Clear all custom prompts + + Removes all the custom prompts from the new credentials dialog. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_clear_prompts(khui_new_creds * c); + +/*! \brief Synchronize custom prompt values + + It is important to synchronize the values before accessing their + values. The controls associated with custom prompts update the + values in the ::khui_new_creds object periodically. However, the + values may lose sync intermittently. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_sync_prompt_values(khui_new_creds * c); + +/*! \brief Begin custom prompting + + Begins the process of defining custom prompts. Implicity removes + all the custom prompts that are currently being displayed. The \a + banner and \a name will be displayed in separate controls above + the set of new custom prompts. + + The controls associated with the prompts will not actually be + created until all the prompts have been added using + khui_cw_add_prompt(). The number of promtps that can be added + will be exactly \a n_prompts. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_begin_custom_prompts(khui_new_creds * c, + khm_size n_prompts, + wchar_t * banner, + wchar_t * name); + +/*! \brief Add a custom prompt + + After khui_cw_begin_custom_prompts() is called, the plugin should + call khui_cw_add_prompt() to add the actual prompts. The number + of prompts that can be added is the \a n_prompts value specified + in the earlier call to \a khui_cw_begin_custom_prompts(). + + Once \a n_prompts prompts have been added, the new prompts will + automatically be created and shown in the user interface. + However, if less than that prompts are added, nothing is displayed + to the user. + + \param[in] c Pointer to ::khui_new_creds structure + + \param[in] type Type of prompt. One of + ::KHUI_NCPROMPT_TYPE_PREAUTH, ::KHUI_NCPROMPT_TYPE_PASSWORD, + ::KHUI_NCPROMPT_TYPE_NEW_PASSWORD, + ::KHUI_NCPROMPT_TYPE_NEW_PASSWORD_AGAIN + + \param[in] prompt Text of the prompt. Constrained by + ::KHUI_MAXCCH_PROMPT. (Localized, required) + + \param[in] def Default value. (optional). Constrained by + ::KHUI_MAXCCH_PROMPT_VALUE. Set to NULL if not provided. + + \param[in] flags Flags. Combination of + ::KHUI_NCPROMPT_FLAG_HIDDEN + */ +KHMEXP khm_int32 KHMAPI +khui_cw_add_prompt(khui_new_creds * c, + khm_int32 type, + wchar_t * prompt, + wchar_t * def, + khm_int32 flags); + +/*! \brief Retrieve a custom prompt + + Retrieves an individual prompt. The \a idx parameter is a + zero-based index of the prompt to retrieve. The ordering is the + same as the order in which khui_cw_add_prompt() was called. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt(khui_new_creds * c, + khm_size idx, + khui_new_creds_prompt ** prompt); + +/*! \brief Get the number of custom prompts + + Retrieves the number of custom prompts currently displayed. If + this function is called between calling + khui_cw_begin_custom_prompts() and adding all the prompts, the + number returned will be the number of prompts that is expected to + be registered (i.e. the \a n_prompts parameter passed to + khui_cw_begin_custom_prompts()). + */ +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt_count(khui_new_creds * c, + khm_size * np); + + +/*! \brief Get the value of a custom prompt + + Retrieve the value of a specific prompt. The value is the string + that was typed into the input control associated with a custom + prompt. The \a idx parameter is the zero-based index of the + prompt from which to retrieve the value from. The ordering is the + same as the order in which khui_cw_add_prompt() was called. + + It is important to call khui_cw_sync_prompt_values() before + starting to call khui_cw_get_prompt_value() so that the values + returned are up-to-date. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_get_prompt_value(khui_new_creds * c, + khm_size idx, + wchar_t * buf, + khm_size *cbbuf); + +/*! \brief Set the response for a plugin + + When handling ::KMSG_CRED_DIALOG_PROCESS from within the plugin + thread, it is important to set the response by calling this + function. The response can be used to signal whether the plugin + successfully obtained credentials or whether further interaction + is required, or the credentials acquisition failed. + + The response is a combination of : + - ::KHUI_NC_RESPONSE_PENDING + - ::KHUI_NC_RESPONSE_FAILED + - ::KHUI_NC_RESPONSE_PENDING + - ::KHUI_NC_RESPONSE_SUCCESS + - ::KHUI_NC_RESPONSE_NOEXIT + - ::KHUI_NC_RESPONSE_EXIT + */ +KHMEXP khm_int32 KHMAPI +khui_cw_set_response(khui_new_creds * c, + khm_int32 type, + khm_int32 response); + +/*! \brief Check whether a specified credential type panel succeeded + + This is called during the processing of KMSG_CRED_DIALOG_PROCESS + to determine whether a specified credential type succeeded in + obtaining credentials. The credential type that is being queried + should have also been listed as a dependency when adding the + current credentials type, otherwise the type queried may not have + been invoked yet. + + \return TRUE iff the queried type has reported that it successfully + completed the credentials acquision operation. + */ +KHMEXP khm_boolean KHMAPI +khui_cw_type_succeeded(khui_new_creds * c, + khm_int32 type); + +/*! \brief Add a row of controls to the identity specifier area + + Only for use by identity provider callbacks that wish to add an + identity selector control. A row of controls consist of a label + control and some input control. + + When the ::WMNC_IDENT_INIT message is sent to the identity + provider, it receives a handle to the dialog panel in the \a + lParam parameter which should be the parent window of both the + windows specified here. The control ID for any controls created + must fall within the ::KHUI_CW_ID_MIN and ::KHUI_CW_ID_MAX range. + + Both controls will be resized to fit in the row. + + If \a long_label is TRUE then the size of the label will be larger + than normal and will accomodate more text. + */ +KHMEXP khm_int32 KHMAPI +khui_cw_add_control_row(khui_new_creds * c, + HWND label, + HWND input, + khui_control_size size); + +/*!@}*/ /* Credentials acquisition */ +/*!@}*/ + +#endif diff --git a/mechglue/src/windows/identity/uilib/khprops.h b/mechglue/src/windows/identity/uilib/khprops.h new file mode 100644 index 000000000..fc5629dc9 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khprops.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHPROPS_H +#define __KHIMAIRA_KHPROPS_H + +/********************************************************************* + Property sheets +**********************************************************************/ + +/*! \addtogroup khui + +@{*/ + +/*!\defgroup khui_pp Property sheets +@{*/ + +/* forward dcl */ +struct tag_khui_property_page; + +/*! \brief A property sheet + */ +typedef struct tag_khui_property_sheet { + PROPSHEETHEADER header; /*!< property sheet header */ + khm_int32 status; /*!< status of property sheet. One of + ::KHUI_PS_STATUS_NONE, + ::KHUI_PS_STATUS_RUNNING or + ::KHUI_PS_STATUS_DONE */ + + HWND hwnd; /*!< handle to the property sheet window. + Only valid when \a status is NOT + ::KHUI_PS_STATUS_NONE */ + + HWND hwnd_page; /*!< handle to the current page in the + property sheet. Only valid when \a + status is ::KHUI_PS_STATUS_RUNNING */ + + khui_action_context ctx; /*!< Context for the property sheet. See + documentation for + ::khui_action_context */ + + khm_handle identity; /*!< Handle to the associated identity, + if applicable */ + khm_int32 credtype; /*!< Type ID of the credentials type, if + applicable */ + khm_handle cred; /*!< Handle to the associated credential, + if applicable */ + + khm_int32 n_pages; /*!< Number of property pages. + Upperbound of ::KHUI_PS_MAX_PSP */ + + QDCL(struct tag_khui_property_page); +} khui_property_sheet; + +/*! \brief The property sheet hasn't been created yet */ +#define KHUI_PS_STATUS_NONE 0 + +/*! \brief The property sheet is visible and running */ +#define KHUI_PS_STATUS_RUNNING 1 + +/*! \brief The property sheet has completed running. + + At this point, it is safe to call khui_ps_destroy_sheet() to + destroy the property sheet. +*/ +#define KHUI_PS_STATUS_DONE 2 + +/*! \brief The property sheet is in the process of being destroyed + */ +#define KHUI_PS_STATUS_DESTROY 3 + +/*! \brief Maximum number of property sheet pages in a property sheet */ +#define KHUI_PS_MAX_PSP 16 + + +/*! \brief A property sheet page + */ +typedef struct tag_khui_property_page { + HPROPSHEETPAGE h_page; + LPPROPSHEETPAGE p_page; + HWND hwnd; + khm_int32 credtype; + khm_int32 ordinal; + + LDCL(struct tag_khui_property_page); +} khui_property_page; + +/*! \brief Special pseudo credtype for identity page + */ +#define KHUI_PPCT_IDENTITY (-8) + +/*! \brief Special pseudo credtype for credential page + */ +#define KHUI_PPCT_CREDENTIAL (-9) + +/*! \brief Create a property sheet + + \note Only called by the NetIDMgr application. + */ +KHMEXP khm_int32 KHMAPI +khui_ps_create_sheet(khui_property_sheet ** sheet); + +/*! \brief Add a page to a property sheet + + Called by a plugin or the NetIDMgr application to add a page to a + property sheet. + + Pages can only be added before the property sheet is made visible + to the user. + + \param[in] sheet The property sheet to add the page to + + \param[in] credtype The credentials type ID of the owner of the + property page. This should be set to ::KCDB_CREDTYPE_INVALID + if the type is not relevant. + + \param[in] ordinal Requested ordinal. A positive integer which is + used to order the pages in a property sheet. The pages are + ordered based on ordinal first and then alphabetically by + credentials type name. If the type is unavailable, then the + ordering is undefined. Ordinals for credential type property + pages can be in the range from 0 to 127. Ordinals 128 and + above are reserved. Passing in 0 will work for credentials + providers unless they provide more than one property page per + credential, in which case the ordinal should be used to + enforce an order. + + \param[in] ppage Pointer to structure that will be passed to + CreatePropertySheetPage() to create the property page. The + structure is not managed by NetIDMgr at all, and must exist + until the status of the property sheet changes to + ::KHUI_PS_STATUS_RUNNING. The same pointer will be found in + the \a p_page member of the ::khui_property_page structure. + + \param[out] page A pointer will be returned here that will point + to the newly created khui_property_page structure. Specify + NULL if this value is not required. You can use + khui_ps_find_page() to retrieve a pointer to the structure + later. + */ +KHMEXP khm_int32 KHMAPI +khui_ps_add_page(khui_property_sheet * sheet, + khm_int32 credtype, + khm_int32 ordinal, + LPPROPSHEETPAGE ppage, + khui_property_page ** page); + +/*! \brief Retrieve a property page structure from a property sheet + */ +KHMEXP khm_int32 KHMAPI +khui_ps_find_page(khui_property_sheet * sheet, + khm_int32 credtype, + khui_property_page ** page); + +/*! \brief Display the property sheet + + \note Only called by the NetIDMgr application + */ +KHMEXP HWND KHMAPI +khui_ps_show_sheet(HWND parent, + khui_property_sheet * sheet); + +/*! \brief Check if the given message belongs to the property sheet + + \note Only called by the NetIDMgr application + */ +KHMEXP LRESULT KHMAPI +khui_ps_check_message(khui_property_sheet * sheet, + PMSG msg); + +/*! \brief Destroy a property sheet and all associated data structures. + + \note Only called by the NetIDMgr application. +*/ +KHMEXP khm_int32 KHMAPI +khui_ps_destroy_sheet(khui_property_sheet * sheet); + +KHMEXP khm_int32 KHMAPI +khui_property_wnd_set_record(HWND hwnd_pwnd, khm_handle record); + +/*!@}*/ +/*!@}*/ + +#endif diff --git a/mechglue/src/windows/identity/uilib/khremote.h b/mechglue/src/windows/identity/uilib/khremote.h new file mode 100644 index 000000000..5de877da6 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khremote.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_REMOTE_H +#define __KHIMAIRA_REMOTE_H + +/*! \addtogroup khui + @{*/ +/*! \defgroup khui_remote Connecting to NetIDMgr from another process + @{*/ + +/* Leash compatibility */ +#define ID_OBTAIN_TGT_WITH_LPARAM 32810 + +#define KHUI_REQDAEMONWND_CLASS L"IDMgrRequestDaemonCls" +#define KHUI_REQDAEMONWND_NAME L"IDMgrRequestDaemon" + +#define KHUI_REQD_MAPPING_FORMAT L"Local\\NetIDMgr_DlgInfo_%lu" + +#define NETID_USERNAME_SZ 128 +#define NETID_REALM_SZ 192 +#define NETID_TITLE_SZ 256 +#define NETID_CCACHE_NAME_SZ 264 + +#define NETID_DLGTYPE_TGT 0 +#define NETID_DLGTYPE_CHPASSWD 1 +typedef struct { + DWORD size; + DWORD dlgtype; + // Tells whether dialog box is in change pwd mode or init ticket mode + struct { + WCHAR title[NETID_TITLE_SZ]; + WCHAR username[NETID_USERNAME_SZ]; + WCHAR realm[NETID_REALM_SZ]; + WCHAR ccache[NETID_CCACHE_NAME_SZ]; + DWORD use_defaults; + DWORD forwardable; + DWORD noaddresses; + DWORD lifetime; + DWORD renew_till; + DWORD proxiable; + DWORD publicip; + DWORD must_use_specified_principal; + } in; + struct { + WCHAR username[NETID_USERNAME_SZ]; + WCHAR realm[NETID_REALM_SZ]; + WCHAR ccache[NETID_CCACHE_NAME_SZ]; + } out; + // Version 1 of this structure ends here +} NETID_DLGINFO, *LPNETID_DLGINFO; + +#define NETID_DLGINFO_V1_SZ (10 * sizeof(DWORD) \ + + sizeof(WCHAR) * (NETID_TITLE_SZ + \ + 2 * NETID_USERNAME_SZ + 2 * NETID_REALM_SZ + \ + 2 * NETID_CCACHE_NAME_SZ)) + +/*!@} */ +/*!@} */ + +#endif diff --git a/mechglue/src/windows/identity/uilib/khrescache.h b/mechglue/src/windows/identity/uilib/khrescache.h new file mode 100644 index 000000000..eeb4f6585 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khrescache.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_RESCACHE_H +#define __KHIMAIRA_RESCACHE_H + +#include<khdefs.h> + +KHMEXP void KHMAPI +khui_init_rescache(void); + +KHMEXP void KHMAPI +khui_exit_rescache(void); + +KHMEXP void KHMAPI +khui_cache_bitmap(UINT id, HBITMAP hbm); + +KHMEXP HBITMAP KHMAPI +khui_get_cached_bitmap(UINT id); + +typedef struct khui_ilist_t { + int cx; + int cy; + int n; + int ng; + int nused; + HBITMAP img; + HBITMAP mask; + int *idlist; +} khui_ilist; + +typedef struct khui_bitmap_t { + HBITMAP hbmp; + int cx; + int cy; +} khui_bitmap; + +KHMEXP void KHMAPI +khui_bitmap_from_hbmp(khui_bitmap * kbm, HBITMAP hbm); + +KHMEXP void KHMAPI +khui_delete_bitmap(khui_bitmap * kbm); + +KHMEXP void KHMAPI +khui_draw_bitmap(HDC hdc, int x, int y, khui_bitmap * kbm); + +/* image lists */ +KHMEXP khui_ilist * KHMAPI +khui_create_ilist(int cx, int cy, int n, int ng, int opt); + +KHMEXP BOOL KHMAPI +khui_delete_ilist(khui_ilist * il); + +KHMEXP int KHMAPI +khui_ilist_add_masked(khui_ilist * il, HBITMAP hbm, COLORREF cbkg); + +KHMEXP int KHMAPI +khui_ilist_add_masked_id(khui_ilist *il, HBITMAP hbm, + COLORREF cbkg, int id); + +KHMEXP int KHMAPI +khui_ilist_lookup_id(khui_ilist *il, int id); + +KHMEXP void KHMAPI +khui_ilist_draw(khui_ilist * il, int idx, HDC dc, int x, int y, int opt); + +KHMEXP void KHMAPI +khui_ilist_draw_bg(khui_ilist * il, int idx, HDC dc, int x, int y, + int opt, COLORREF bgcolor); + +#define khui_ilist_draw_id(il, id, dc, x, y, opt) \ + khui_ilist_draw((il),khui_ilist_lookup_id((il),(id)),(dc),(x),(y),(opt)) + +#define KHUI_SMICON_CX 16 +#define KHUI_SMICON_CY 16 + +#endif diff --git a/mechglue/src/windows/identity/uilib/khtracker.h b/mechglue/src/windows/identity/uilib/khtracker.h new file mode 100644 index 000000000..c12cd4fac --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khtracker.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_TRACKERWND_H +#define __KHIMAIRA_TRACKERWND_H + +#include<time.h> + +/*! \addtogroup khui + +@{ */ + +/*!\defgroup khui_trk Duration sliders + +The duration sliders in the UI are pseudo-log-scaled. This is based +on the assumption that people don't really need 1 minute accuracy when +setting a duration that's several hours long. As a result, it is +easier to hone in on the duration that you want without having +wizardly mouse maneuvering skillz. + +Following are the duration ranges and the granularity that is offered +in each range: + +<table> +<tr><td> Range </td><td> Increment</td></tr> +<tr><td> 0..5m </td><td> 1 min </td></tr> +<tr><td> 5m..1hr </td><td> 5 min </td></tr> +<tr><td> 1hr..4hr </td><td> 15 min </td></tr> +<tr><td> 4hr..10hr </td><td> 30 min </td></tr> +<tr><td> 10hr..24hr</td><td> 1 hr </td></tr> +<tr><td> 24hr..4d </td><td> 6 hr </td></tr> +<tr><td> 4d.. </td><td> 1 day </td></tr> +</table> + +We don't really adjust for durations over 4 days. The ranges we are +concerned with don't get much larger. + +For the purpose of writing this piece of code, I have chosen the term +"tick" to refer to a period of granularity. The number of periods of +granularity (inclusive) within a certain duration interval is referred +to as the number of ticks in the interval. For example, there are 4 +ticks between the interval of 3 minutes to 10 minutes. Each occuring +at the start of 3min, 4, 5 and 10mins. And thusly the slider control +will display 4 ticks if it is displaying the interval 3-10mins. + +@{*/ + +/*! \brief Tracker data */ +typedef struct tag_khui_tracker { + WNDPROC fn_edit; + WNDPROC fn_tracker; + HWND hw_slider; + HWND hw_edit; + int lbl_y; + int lbl_lx; + int lbl_rx; + DWORD act_time; + + time_t current; /*!< Current selection */ + time_t min; /*!< Minimum (inclusive) */ + time_t max; /*!< Maximum (inclusive) */ +} khui_tracker; + +/*! \brief Install a tracker into an edit control + + Once installed, the edit control becomes a duration editor. The + tracker data structure that is supplied should remain as is for + the lifetime of the edit control. + + The tracker strucutre should have been initialized with a call to + khui_tracker_initialize() and should have valid values in the \a + min, \a max and \a current fields. + */ +KHMEXP void KHMAPI +khui_tracker_install(HWND hwnd_edit, khui_tracker * tc); + +KHMEXP void KHMAPI +khui_tracker_reposition(khui_tracker * tc); + +KHMEXP void KHMAPI +khui_tracker_initialize(khui_tracker * tc); + +KHMEXP void KHMAPI +khui_tracker_refresh(khui_tracker * tc); + +KHMEXP void KHMAPI +khui_tracker_kill_controls(khui_tracker * tc); +/*!@}*/ +/*!@}*/ + +#endif diff --git a/mechglue/src/windows/identity/uilib/khuidefs.h b/mechglue/src/windows/identity/uilib/khuidefs.h new file mode 100644 index 000000000..67d8db33d --- /dev/null +++ b/mechglue/src/windows/identity/uilib/khuidefs.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_KHUIDEFS_H +#define __KHIMAIRA_KHUIDEFS_H + +#include<windows.h> +#include<kmq.h> +#include<kcreddb.h> +#include<kherror.h> +#include<kherr.h> +#include<khmsgtypes.h> + +#include<khaction.h> +#include<khactiondef.h> +#include<khrescache.h> +#include<khhtlink.h> +#include<khnewcred.h> +#include<khprops.h> +#include<khalerts.h> +#include<khconfigui.h> +#include<khtracker.h> + +#include<khremote.h> + +#include<strsafe.h> + +/*! \internal */ +KHMEXP void KHMAPI +khm_version_init(void); + +/*! \defgroup khui User Interface + + Functions and data structures for interacting with the user + interface. + +@{*/ + +/*! \brief Get the version of the NetIDMgr library + + \param[out] libver Receives the version of the library. + + \param[out] apiver Receives the API version of the library. + Optional. Set to NULL if this value is not required. + + \note When the NetIDMgr framework loads a plugin, it checks the + version information of the plugin against the version of the + library to determine if the plugin is compatible. + */ +KHMEXP void KHMAPI +khm_get_lib_version(khm_version * libver, khm_ui_4 * apiver); + +/*! \brief Return the version of Common Control library + + Can be used to check the version of the Windows Common Control + library that is currently loaded. The return value of the + function is the packed version value obatained by the macro : + + \code + MAKELONG(vesion->dwMinorVersion, version->dwMajorVersion); + \endcode + + The \a pdvi parameter is optional. Specify NULL if this is not + required. + */ +KHMEXP khm_ui_4 KHMAPI +khm_get_commctl_version(khm_version * pdvi); + +/*!@}*/ + +#endif diff --git a/mechglue/src/windows/identity/uilib/propsheet.c b/mechglue/src/windows/identity/uilib/propsheet.c new file mode 100644 index 000000000..705dd96a3 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/propsheet.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<utils.h> +#ifdef DEBUG +#include<assert.h> +#endif + +CRITICAL_SECTION cs_props; + +void +ps_init(void) { + InitializeCriticalSection(&cs_props); +} + +void +ps_exit(void) { + DeleteCriticalSection(&cs_props); +} + +KHMEXP khm_int32 KHMAPI +khui_ps_create_sheet(khui_property_sheet ** sheet) +{ + khui_property_sheet * ps; + + ps = PMALLOC(sizeof(*ps)); + ZeroMemory(ps, sizeof(*ps)); + + ps->header.dwSize = sizeof(ps->header); + ps->header.dwFlags = PSH_MODELESS | PSH_PROPTITLE; + ps->status = KHUI_PS_STATUS_NONE; + + *sheet = ps; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_ps_add_page(khui_property_sheet * sheet, + khm_int32 credtype, + khm_int32 ordinal, + LPPROPSHEETPAGE ppage, + khui_property_page ** page) +{ + khui_property_page * p; + + p = PMALLOC(sizeof(*p)); + ZeroMemory(p, sizeof(*p)); + + p->credtype = credtype; + p->ordinal = ordinal; + p->p_page = ppage; + + EnterCriticalSection(&cs_props); + QPUT(sheet, p); + sheet->n_pages++; + LeaveCriticalSection(&cs_props); + + if(page) + *page = p; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +khui_ps_find_page(khui_property_sheet * sheet, + khm_int32 credtype, + khui_property_page ** page) +{ + khui_property_page * p; + + EnterCriticalSection(&cs_props); + p = QTOP(sheet); + + while(p) { + if(p->credtype == credtype) + break; + p = QNEXT(p); + } + LeaveCriticalSection(&cs_props); + + if(p) { + *page = p; + return KHM_ERROR_SUCCESS; + } else { + *page = NULL; + return KHM_ERROR_NOT_FOUND; + } +} + +int __cdecl +ps_order_func(const void *l, const void * r) { + khui_property_page * lp; + khui_property_page * rp; + + lp = *(khui_property_page **)l; + rp = *(khui_property_page **)r; + + if (lp->ordinal == rp->ordinal) + return lp->credtype - rp->credtype; + else + return lp->ordinal - rp->ordinal; +} + +KHMEXP HWND KHMAPI +khui_ps_show_sheet(HWND parent, khui_property_sheet * s) +{ + khui_property_page * p; + HPROPSHEETPAGE phpsp[KHUI_PS_MAX_PSP]; + khui_property_page * ppgs[KHUI_PS_MAX_PSP]; + int i; + INT_PTR prv; + HWND hw; + + EnterCriticalSection(&cs_props); + + s->header.hwndParent = parent; + s->header.nPages = s->n_pages; + + p = QTOP(s); + i = 0; + while(p) { + p->h_page = CreatePropertySheetPage(p->p_page); +#ifdef DEBUG + assert(p->h_page); +#endif + ppgs[i++] = p; + p = QNEXT(p); + } + +#ifdef DEBUG + assert(i == s->n_pages); +#endif + + qsort(ppgs, s->n_pages, sizeof(ppgs[0]), ps_order_func); + + for (i=0; i < s->n_pages; i++) { + phpsp[i] = ppgs[i]->h_page; + } + + s->header.phpage = phpsp; + + prv = PropertySheet(&s->header); + + s->header.phpage = NULL; + + if(prv <= 0) { +#ifdef DEBUG + assert(FALSE); +#endif + /*TODO: better handling for this */ + hw = NULL; + } else { + s->status = KHUI_PS_STATUS_RUNNING; + + hw = (HWND) prv; + s->hwnd = hw; + s->hwnd_page = PropSheet_GetCurrentPageHwnd(hw); + } + LeaveCriticalSection(&cs_props); + + return hw; +} + +KHMEXP LRESULT KHMAPI +khui_ps_check_message(khui_property_sheet * sheet, + PMSG pmsg) +{ + LRESULT lr; + + if(sheet->hwnd == NULL) + return FALSE; + + lr = PropSheet_IsDialogMessage(sheet->hwnd, pmsg); + if(lr) { + sheet->hwnd_page = PropSheet_GetCurrentPageHwnd(sheet->hwnd); + if(sheet->hwnd_page == NULL && + sheet->status == KHUI_PS_STATUS_RUNNING) + + sheet->status = KHUI_PS_STATUS_DONE; + } + + return lr; +} + +KHMEXP khm_int32 KHMAPI +khui_ps_destroy_sheet(khui_property_sheet * sheet) +{ + khui_property_page * p; + + EnterCriticalSection(&cs_props); + + DestroyWindow(sheet->hwnd); + sheet->hwnd = NULL; + + QGET(sheet, &p); + while(p) { + PFREE(p); + QGET(sheet, &p); + } + PFREE(sheet); + + LeaveCriticalSection(&cs_props); + + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/uilib/propwnd.c b/mechglue/src/windows/identity/uilib/propwnd.c new file mode 100644 index 000000000..5ae93a7a5 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/propwnd.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> + + +#define PW_WM_SET_RECORD WM_USER + +KHMEXP khm_int32 KHMAPI khui_property_wnd_set_record(HWND hwnd_pwnd, khm_handle record) +{ + SendMessage(hwnd_pwnd, PW_WM_SET_RECORD, 0, (LPARAM) record); + + return KHM_ERROR_SUCCESS; +} diff --git a/mechglue/src/windows/identity/uilib/rescache.c b/mechglue/src/windows/identity/uilib/rescache.c new file mode 100644 index 000000000..6d5259142 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/rescache.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<utils.h> + +hashtable * h_bitmaps; + +khm_int32 +hash_id(const void *p) { +#pragma warning(push) +#pragma warning(disable: 4311) + return (khm_int32) p; +#pragma warning(pop) +} + +khm_int32 +comp_id(const void *p1, const void *p2) { +#pragma warning(push) +#pragma warning(disable: 4311) + return ((khm_int32)p1) - ((khm_int32)p2); +#pragma warning(pop) +} + +void +del_ref_object(const void *k, void * data) { + DeleteObject((HGDIOBJ) data); +} + +KHMEXP void KHMAPI +khui_init_rescache(void) { + h_bitmaps = hash_new_hashtable(127, hash_id, comp_id, NULL, + del_ref_object); +} + +KHMEXP void KHMAPI +khui_exit_rescache(void) { + hash_del_hashtable(h_bitmaps); +} + +KHMEXP void KHMAPI +khui_cache_bitmap(UINT id, HBITMAP hbm) { + hash_add(h_bitmaps, (void *)(size_t) id, (void *) hbm); +} + +KHMEXP HBITMAP KHMAPI +khui_get_cached_bitmap(UINT id) { + return (HBITMAP) hash_lookup(h_bitmaps, (void *)(size_t) id); +} + +KHMEXP khui_ilist * KHMAPI +khui_create_ilist(int cx, int cy, int n, int ng, int opt) { + BITMAPV5HEADER head; + HDC hdc; + + khui_ilist * il = PMALLOC(sizeof(khui_ilist)); + il->cx = cx; + il->cy = cy; + il->n = n; + il->ng = ng; + il->nused = 0; + hdc = GetDC(NULL); + head.bV5Size = sizeof(head); + head.bV5Width = cx * n; + head.bV5Height = cy; + head.bV5Planes = 1; + head.bV5BitCount = 24; + head.bV5Compression = BI_RGB; + head.bV5SizeImage = 0; + head.bV5XPelsPerMeter = 2835; + head.bV5YPelsPerMeter = 2835; + head.bV5ClrUsed = 0; + head.bV5ClrImportant = 0; + head.bV5AlphaMask = 0; + head.bV5CSType = LCS_WINDOWS_COLOR_SPACE; + head.bV5Intent = LCS_GM_GRAPHICS; + head.bV5ProfileData = 0; + head.bV5ProfileSize = 0; + head.bV5Reserved = 0; + il->img = CreateDIBitmap(hdc, (BITMAPINFOHEADER *) &head, 0, NULL, NULL, DIB_RGB_COLORS); + il->mask = CreateBitmap(cx * n, cy, 1, 1, NULL); + il->idlist = PMALLOC(sizeof(int) * n); + + return il; +} + +KHMEXP BOOL KHMAPI +khui_delete_ilist(khui_ilist * il) { + DeleteObject(il->img); + DeleteObject(il->mask); + PFREE(il->idlist); + PFREE(il); + + return TRUE; +} + +KHMEXP int KHMAPI +khui_ilist_add_masked_id(khui_ilist *il, + HBITMAP hbm, + COLORREF cbkg, + int id) { + int idx; + + idx = khui_ilist_add_masked(il,hbm,cbkg); + if(idx >= 0) { + il->idlist[idx] = id; + } + + return idx; +} + +KHMEXP int KHMAPI +khui_ilist_lookup_id(khui_ilist *il, int id) { + int i; + + for(i=0;i<il->nused;i++) { + if(il->idlist[i] == id) + return i; + } + + return -1; +} + +KHMEXP int KHMAPI +khui_ilist_add_masked(khui_ilist * il, HBITMAP hbm, COLORREF cbkg) { + HDC dcr,dci,dct,dcb; + HBITMAP hb_oldb, hb_oldi, hb_oldt; + int sx, i; + int x,y; + + dcr = GetDC(NULL); + dci = CreateCompatibleDC(dcr); + dct = CreateCompatibleDC(dcr); + dcb = CreateCompatibleDC(dcr); + ReleaseDC(NULL,dcr); + + i = il->nused++; + il->idlist[i] = -1; + sx = i * il->cx; + + hb_oldb = SelectObject(dcb, hbm); + hb_oldi = SelectObject(dci, il->img); + hb_oldt = SelectObject(dct, il->mask); + + SetBkColor(dct, RGB(0,0,0)); + SetTextColor(dct, RGB(255,255,255)); + + BitBlt(dci, sx, 0, il->cx, il->cy, dcb, 0, 0, SRCCOPY); + for(y=0;y < il->cy; y++) + for(x=0; x<il->cx; x++) { + COLORREF c = GetPixel(dcb, x, y); + if(c==cbkg) { + SetPixel(dct, sx + x, y, RGB(255,255,255)); + SetPixel(dci, sx + x, y, RGB(0,0,0)); + } else { + SetPixel(dct, sx + x, y, RGB(0,0,0)); + } + } + + SelectObject(dct, hb_oldt); + SelectObject(dci, hb_oldi); + SelectObject(dcb, hb_oldb); + + DeleteDC(dcb); + DeleteDC(dct); + DeleteDC(dci); + + return i; +} + +KHMEXP void KHMAPI +khui_ilist_draw(khui_ilist * il, + int idx, + HDC dc, + int x, + int y, + int opt) { + HDC dci; + HBITMAP hb_oldi; + + if(idx < 0) + return; + + dci = CreateCompatibleDC(dc); + + hb_oldi = SelectObject(dci, il->img); + + /*BitBlt(dc, x, y, il->cx, il->cy, dci, idx*il->cx, 0, SRCCOPY); */ + MaskBlt(dc, x, y, il->cx, il->cy, dci, idx * il->cx, 0, il->mask, idx * il->cx, 0, MAKEROP4(SRCPAINT, SRCCOPY)); +/* MaskBlt(dc, x, y, il->cx, il->cy, dci, idx * il->cx, 0, il->mask, idx * il->cx, 0, MAKEROP4(SRCINVERT, SRCCOPY)); */ + + SelectObject(dci, hb_oldi); + + DeleteDC(dci); +} + +KHMEXP void KHMAPI +khui_ilist_draw_bg(khui_ilist * il, + int idx, + HDC dc, + int x, + int y, + int opt, + COLORREF bgcolor) { + HDC dcm; + HBITMAP hb_oldm, hb_mem; + HBRUSH hbr; + RECT r; + + dcm = CreateCompatibleDC(dc); + + hb_mem = CreateCompatibleBitmap(dc, il->cx, il->cy); + + hb_oldm = SelectObject(dcm, hb_mem); + + hbr = CreateSolidBrush(bgcolor); + + r.left = 0; + r.top = 0; + r.right = il->cx; + r.bottom = il->cy; + + FillRect(dcm, &r, hbr); + + khui_ilist_draw(il,idx,dcm,0,0,opt); + + BitBlt(dc,x,y,il->cx,il->cy,dcm,0,0,SRCCOPY); + + SelectObject(dcm, hb_oldm); + + DeleteObject(hb_mem); + DeleteObject(hbr); + + DeleteDC(dcm); +} + + +KHMEXP void KHMAPI +khui_bitmap_from_hbmp(khui_bitmap * kbm, HBITMAP hbm) +{ + HDC hdc; + BITMAPINFO bmi; + + hdc = CreateCompatibleDC(NULL); + + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + + kbm->hbmp = hbm; + + if(GetDIBits(hdc, hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS)) { + kbm->cx = bmi.bmiHeader.biWidth; + kbm->cy = bmi.bmiHeader.biHeight; + } else { + kbm->cx = -1; + kbm->cy = -1; + } + + DeleteDC(hdc); +} + +KHMEXP void KHMAPI +khui_delete_bitmap(khui_bitmap * kbm) { + if (kbm->hbmp) + DeleteObject(kbm->hbmp); + kbm->hbmp = NULL; +} + +KHMEXP void KHMAPI +khui_draw_bitmap(HDC hdc, int x, int y, khui_bitmap * kbm) { + HDC hdcb = CreateCompatibleDC(hdc); + HBITMAP hbmold = SelectObject(hdcb, kbm->hbmp); + + BitBlt(hdc, x, y, kbm->cx, kbm->cy, + hdcb, 0, 0, SRCCOPY); + + SelectObject(hdcb, hbmold); + DeleteDC(hdcb); +} diff --git a/mechglue/src/windows/identity/uilib/trackerwnd.c b/mechglue/src/windows/identity/uilib/trackerwnd.c new file mode 100644 index 000000000..814e28808 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/trackerwnd.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> +#include<commctrl.h> +#include<assert.h> + +#define K5_SLIDER_WIDTH 208 +#define K5_SLIDER_HEIGHT 40 + +#define K5_SLIDER_LBL_HPAD 5 +#define K5_SLIDER_LBL_VPAD 22 + +#define KHUI_TRACKER_PROP L"KhmTrackerData" + + +/* Count the number of ticks between tmin and tmax, inclusive +*/ +int time_t_to_ticks(time_t tmin, time_t tmax) +{ + int c = 0; + time_t lo, hi; + + tmin -= tmin % 60; /* our smallest gran is 1 min */ + if(tmax % 60) + tmax += 60 - (tmax % 60); + + lo = tmin; + +#define TFORWARD(limit,gran) \ + if(lo < limit && lo < tmax) { \ + hi = min(tmax, limit); \ + c += (int)((hi - lo) / (gran)); \ + lo = hi; \ + } + + TFORWARD(300,60); + TFORWARD(3600,300); + TFORWARD(3600*4, 60*15); + TFORWARD(3600*10,60*30); + TFORWARD(3600*24,3600); + TFORWARD(3600*24*4,3600*6); + TFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24); + +#undef TFORWARD + + return c; +} + +/* Compute tmax given tmin and ticks such that there are ticks ticks + between tmin and tmax + */ +time_t ticks_to_time_t(int ticks, time_t tmin) +{ + int c = 0; + tmin -= tmin % 60; /* our smallest gran is 1 min */ + +#define SFORWARD(limit,gran) \ + if(tmin < limit && ticks > 0) { \ + c = (int) min(ticks, (limit - tmin) / (gran)); \ + tmin += c * gran; \ + ticks -= c; \ + } + + SFORWARD(300,60); + SFORWARD(3600,300); + SFORWARD(3600*4,60*15); + SFORWARD(3600*10,60*30); + SFORWARD(3600*24,3600); + SFORWARD(3600*24*4,3600*6); + SFORWARD(((time_t)(INFINITE & INT_MAX)),3600*24); + +#undef SFORWARD + + return tmin; +} + +/* Prep a tracker control which works in conjunction with the + duration edit control. + + NOTE: Runs in the context of the UI thread +*/ +void +initialize_tracker(HWND hwnd, + khui_tracker * tc) +{ + RECT r; + FILETIME ft; + wchar_t wbuf[256]; + khm_size cbbuf; + + SendMessage(tc->hw_slider, TBM_SETRANGE, 0, MAKELONG(0, time_t_to_ticks(tc->min, tc->max))); + SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current)); + + r.left = K5_SLIDER_LBL_HPAD; + r.top = K5_SLIDER_LBL_VPAD; + r.right = K5_SLIDER_WIDTH - K5_SLIDER_LBL_HPAD; + r.bottom = r.top; + + MapDialogRect(hwnd, &r); + + tc->lbl_y = r.top; + tc->lbl_lx = r.left; + tc->lbl_rx = r.right; + + TimetToFileTimeInterval(tc->current, &ft); + cbbuf = sizeof(wbuf); + FtIntervalToString(&ft, wbuf, &cbbuf); + + SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf); +} + + +/* We instance-subclass each tracker control to provide the + functionality that we need. This is the replacement window + procedure + + NOTE: Runs in the context of the UI thread + */ +LRESULT CALLBACK +duration_tracker_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_tracker * tc; + + tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP); +#ifdef DEBUG + assert(tc != NULL); +#endif + + switch(uMsg) { + case WM_PAINT: + { + HDC hdc; + HFONT hf, hfold; + LRESULT lr; + FILETIME ft; + wchar_t buf[256]; + khm_size cbbuf; + + lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); + + /* Can't use BeginPaint here, since we already called the + window proc */ + hdc = GetWindowDC(hwnd); + + hf = (HFONT) SendMessage(tc->hw_edit, WM_GETFONT, 0, 0); + + hfold = ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hf))); + + TimetToFileTimeInterval(tc->min, &ft); + cbbuf = sizeof(buf); + FtIntervalToString(&ft, buf, &cbbuf); + + SetTextColor(hdc, RGB(0,0,0)); + SetBkMode(hdc, TRANSPARENT); + + SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP); + TextOut(hdc, tc->lbl_lx, tc->lbl_y, buf, (int) wcslen(buf)); + + TimetToFileTimeInterval(tc->max, &ft); + cbbuf = sizeof(buf); + FtIntervalToString(&ft, buf, &cbbuf); + + SetTextAlign(hdc, TA_RIGHT | TA_TOP | TA_NOUPDATECP); + TextOut(hdc, tc->lbl_rx, tc->lbl_y, buf, (int) wcslen(buf)); + + ((HFONT) SelectObject((hdc), (HGDIOBJ)(HFONT)(hfold))); + + ReleaseDC(hwnd, hdc); + + return lr; + } + break; + + case WM_KILLFOCUS: + { + if((HWND)wParam != tc->hw_edit) + ShowWindow(hwnd, SW_HIDE); + } + break; + + case WM_LBUTTONUP: + case WM_MOUSEMOVE: + { + LRESULT lr; + + lr = CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); + + if(wParam & MK_LBUTTON) { + int c = (int) SendMessage(hwnd, TBM_GETPOS, 0, 0); + time_t t = ticks_to_time_t(c, tc->min); + + if(t != tc->current) { + wchar_t buf[256]; + FILETIME ft; + khm_size cbbuf; + + tc->current = t; + //d->dirty = TRUE; + cbbuf = sizeof(buf); + TimetToFileTimeInterval(t, &ft); + FtIntervalToString(&ft, buf, &cbbuf); + SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM) buf); + } + } + return lr; + } + } + + return CallWindowProc(tc->fn_tracker, hwnd, uMsg, wParam, lParam); +} + + +/* Create the subclassed duration slider on behalf of an edit control */ +void +create_edit_sliders(HWND hwnd, + HWND hwnd_dlg, + khui_tracker * tc) +{ + RECT r; + RECT rs; + + GetWindowRect(hwnd, &r); + + rs.top = 0; + rs.left = 0; + rs.right = K5_SLIDER_WIDTH; + rs.bottom = K5_SLIDER_HEIGHT; + MapDialogRect(hwnd_dlg, &rs); + rs.right -= rs.left; + rs.bottom -= rs.top; + + tc->hw_slider = + CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, + TRACKBAR_CLASS, + L"NetIDMgrTimeTickerTrackbar", + WS_POPUP | TBS_AUTOTICKS | TBS_BOTTOM | +#if (_WIN32_IE >= 0x0501) + TBS_DOWNISLEFT | +#endif + TBS_HORZ | WS_CLIPCHILDREN, + r.left,r.bottom,rs.right,rs.bottom, + hwnd, + NULL, + (HINSTANCE)(DWORD_PTR) + GetWindowLongPtr(hwnd, GWLP_HINSTANCE), + NULL); + + SetProp(tc->hw_slider, KHUI_TRACKER_PROP, + (HANDLE) tc); + +#pragma warning(push) +#pragma warning(disable: 4244) + tc->fn_tracker = (WNDPROC)(LONG_PTR) SetWindowLongPtr(tc->hw_slider, GWLP_WNDPROC, (LONG_PTR) duration_tracker_proc); +#pragma warning(pop) +} + +/* An edit control is instance-subclassed to create an edit control + that holds a duration. Welcome to the window procedure. + + NOTE: Runs in the context of the UI thread + */ +LRESULT CALLBACK +duration_edit_proc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + khui_tracker * tc; + + tc = (khui_tracker *) GetProp(hwnd, KHUI_TRACKER_PROP); + +#ifdef DEBUG + assert(tc != NULL); +#endif + + switch(uMsg) { + case WM_SETFOCUS: + { + HWND p; + + p = GetParent(hwnd); + + /* we are being activated. show the panel */ + if(tc->hw_slider == NULL) { + create_edit_sliders(hwnd, p, tc); + initialize_tracker(p, tc); + } + khui_tracker_reposition(tc); + ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE); + + tc->act_time = GetTickCount(); + //SetActiveWindow(p); + } + break; + + case WM_KILLFOCUS: + { + wchar_t wbuf[256]; + FILETIME ft; + khm_size cbbuf; + + if((HWND) wParam != tc->hw_slider) + ShowWindow(tc->hw_slider, SW_HIDE); + + TimetToFileTimeInterval(tc->current, &ft); + cbbuf = sizeof(wbuf); + FtIntervalToString(&ft, wbuf, &cbbuf); + + SendMessage(tc->hw_edit, WM_SETTEXT, 0, (LPARAM)wbuf); + } + break; + + case KHUI_WM_NC_NOTIFY: + if(HIWORD(wParam) == WMNC_DIALOG_SETUP) + { + HWND p; + + p = GetParent(hwnd); + + if(tc->hw_slider == NULL) { + create_edit_sliders(hwnd,p,tc); + } + + initialize_tracker(p, tc); + } + return TRUE; + + case WM_LBUTTONUP: + if (IsWindowVisible(tc->hw_slider)) { + DWORD tm; + + tm = GetTickCount(); + if (tm - tc->act_time > 500) + ShowWindow(tc->hw_slider, SW_HIDE); + } else { + ShowWindow(tc->hw_slider, SW_SHOWNOACTIVATE); + } + break; + + /* these messages can potentially change the text in the edit + control. We intercept them and see what changed. We may + need to grab and handle them */ + case EM_REPLACESEL: + case EM_UNDO: + case WM_UNDO: + case WM_CHAR: +#if (_WIN32_WINNT >= 0x0501) + case WM_UNICHAR: +#endif + { + wchar_t buf[256]; + size_t nchars; + time_t ts; + FILETIME ft; + BOOL modified; + LRESULT lr = CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam); + + modified = (BOOL) SendMessage(hwnd, EM_GETMODIFY, 0, 0); + if(modified) { + /* parse the string */ + if(nchars = (size_t) SendMessage(hwnd, WM_GETTEXT, ARRAYLENGTH(buf), (LPARAM) buf)) { + buf[nchars] = 0; + + if(KHM_SUCCEEDED(IntervalStringToFt(&ft, buf))) { + ts = FtIntervalToSeconds(&ft); + if(ts >= tc->min && ts <= tc->max) { + tc->current = ts; + //d->dirty = TRUE; + if(tc->hw_slider != NULL) + SendMessage(tc->hw_slider, TBM_SETPOS, TRUE, (LPARAM) time_t_to_ticks(tc->min, tc->current)); + } + } + } + SendMessage(hwnd, EM_SETMODIFY, FALSE, 0); + } + + return lr; + } + } + + return CallWindowProc(tc->fn_edit, hwnd, uMsg, wParam, lParam); +} + +KHMEXP void KHMAPI +khui_tracker_install(HWND hwnd_edit, khui_tracker * tc) { +#ifdef DEBUG + assert(hwnd_edit); + assert(tc); +#endif + + tc->hw_edit = hwnd_edit; + + SetProp(hwnd_edit, KHUI_TRACKER_PROP, (HANDLE) tc); + +#pragma warning(push) +#pragma warning(disable: 4244) + tc->fn_edit = (WNDPROC)(LONG_PTR) + SetWindowLongPtr(hwnd_edit, GWLP_WNDPROC, + (LONG_PTR) duration_edit_proc); +#pragma warning(pop) +} + +KHMEXP void KHMAPI +khui_tracker_reposition(khui_tracker * tc) { + RECT r; + + if(tc->hw_slider && tc->hw_edit) { + GetWindowRect(tc->hw_edit, &r); + SetWindowPos(tc->hw_slider, + NULL, + r.left, r.bottom, + 0, 0, + SWP_NOOWNERZORDER | SWP_NOSIZE | + SWP_NOZORDER | SWP_NOACTIVATE); + } +} + +KHMEXP void KHMAPI +khui_tracker_initialize(khui_tracker * tc) { + ZeroMemory(tc, sizeof(*tc)); +} + +KHMEXP void KHMAPI +khui_tracker_refresh(khui_tracker * tc) { + if (!tc->hw_edit) + return; + + SendMessage(tc->hw_edit, + KHUI_WM_NC_NOTIFY, + MAKEWPARAM(0,WMNC_DIALOG_SETUP), 0); +} + +KHMEXP void KHMAPI +khui_tracker_kill_controls(khui_tracker * tc) { + if (tc->hw_slider) + DestroyWindow(tc->hw_slider); + if (tc->hw_edit) + DestroyWindow(tc->hw_edit); + tc->hw_slider = NULL; + tc->hw_edit = NULL; + tc->fn_edit = NULL; + tc->fn_tracker = NULL; +} + + diff --git a/mechglue/src/windows/identity/uilib/uilibmain.c b/mechglue/src/windows/identity/uilib/uilibmain.c new file mode 100644 index 000000000..4d0b012f1 --- /dev/null +++ b/mechglue/src/windows/identity/uilib/uilibmain.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<khuidefs.h> + +extern void alert_init(void); +extern void alert_exit(void); +extern void ps_init(void); +extern void ps_exit(void); + +void +uilib_process_attach(void) { + alert_init(); + ps_init(); +} + +void +uilib_process_detach(void) { + ps_exit(); + alert_exit(); +} diff --git a/mechglue/src/windows/identity/uilib/version.c b/mechglue/src/windows/identity/uilib/version.c new file mode 100644 index 000000000..cf7f702bf --- /dev/null +++ b/mechglue/src/windows/identity/uilib/version.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<shlwapi.h> +#include<khuidefs.h> +#include<netidmgr_intver.h> + +DLLVERSIONINFO ver_commctl; + +static void +get_dll_version(wchar_t * dllname, DLLVERSIONINFO * pdvi) { + HINSTANCE hdll; + + hdll = LoadLibrary(dllname); + + ZeroMemory(pdvi, sizeof(*pdvi)); + + if(hdll) { + DLLGETVERSIONPROC pDllGetVersion; + + pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hdll, "DllGetVersion"); + if(pDllGetVersion) { + pdvi->cbSize = sizeof(*pdvi); + + (*pDllGetVersion)(pdvi); + } + FreeLibrary(hdll); + } +} + +KHMEXP void KHMAPI +khm_version_init(void) { + get_dll_version(L"comctl32.dll", &ver_commctl); +} + +KHMEXP void KHMAPI +khm_get_lib_version(khm_version * libver, khm_ui_4 * apiver) { + if (!libver) + return; + + libver->major = KH_VERSION_MAJOR; + libver->minor = KH_VERSION_MINOR; + libver->patch = KH_VERSION_PATCH; + libver->aux = KH_VERSION_AUX; + + if (apiver) + *apiver = KH_VERSION_API; +} + +KHMEXP khm_ui_4 KHMAPI +khm_get_commctl_version(khm_version * pdvi) { + if (pdvi) { + pdvi->major = (khm_ui_2) ver_commctl.dwMajorVersion; + pdvi->minor = (khm_ui_2) ver_commctl.dwMinorVersion; + pdvi->patch = (khm_ui_2) ver_commctl.dwBuildNumber; + pdvi->aux = (khm_ui_2) ver_commctl.dwPlatformID; + } + + return MAKELONG(ver_commctl.dwMinorVersion, ver_commctl.dwMajorVersion); +} diff --git a/mechglue/src/windows/identity/util/Makefile b/mechglue/src/windows/identity/util/Makefile new file mode 100644 index 000000000..9d1cad2f0 --- /dev/null +++ b/mechglue/src/windows/identity/util/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (c) 2004 Massachusetts Institute of Technology +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +MODULE=util +!include <../config/Makefile.w32> + +INCFILES= \ + $(INCDIR)\utils.h \ + $(INCDIR)\hashtable.h \ + $(INCDIR)\mstring.h \ + $(INCDIR)\sync.h \ + $(INCDIR)\perfstat.h + +OBJFILES= \ + $(OBJ)\hashtable.obj \ + $(OBJ)\mstring.obj \ + $(OBJ)\sync.obj \ + $(OBJ)\perfstat.obj + +LIBFILES= + +SDKLIBFILES= + +all: mkdirs $(INCFILES) $(OBJFILES) + +clean:: + $(RM) $(INCFILES) diff --git a/mechglue/src/windows/identity/util/hashtable.c b/mechglue/src/windows/identity/util/hashtable.c new file mode 100644 index 000000000..1a4233d51 --- /dev/null +++ b/mechglue/src/windows/identity/util/hashtable.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<perfstat.h> +#include<hashtable.h> +#include<stdlib.h> + +KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n, + hash_function_t hash, + comp_function_t comp, + add_ref_function_t addr, + del_ref_function_t delr) +{ + hashtable * h; + + h = PMALLOC(sizeof(hashtable)); + + h->n = n; + h->addr = addr; + h->comp = comp; + h->delr = delr; + h->hash = hash; + + h->bins = PCALLOC(sizeof(hash_bin *), n); + + return h; +} + +KHMEXP void KHMAPI hash_del_hashtable(hashtable * h) { + hash_bin * b; + int i; + + for(i=0;i<h->n;i++) { + LPOP(&h->bins[i], &b); + while(b) { + if(h->delr) + h->delr(b->key, b->data); + PFREE(b); + LPOP(&h->bins[i], &b); + } + } + + PFREE(h); +} + +KHMEXP void KHMAPI hash_add(hashtable * h, void * key, void * data) { + int hv; + hash_bin * b; + + hv = h->hash(key) % h->n; + b = h->bins[hv]; + while(b) { + if(!h->comp(b->key, key)) { + /* found an existing value */ + if(h->delr) + h->delr(b->key, b->data); + b->key = key; + b->data = data; + if(h->addr) + h->addr(b->key, b->data); + break; + } + b = LNEXT(b); + } + + if(!b) { + b = PMALLOC(sizeof(hash_bin)); + b->data = data; + b->key = key; + LINIT(b); + LPUSH(&h->bins[hv], b); + if(h->addr) + h->addr(b->key, b->data); + } +} + +KHMEXP void KHMAPI hash_del(hashtable * h, void * key) { + hash_bin * b; + int hv; + + hv = h->hash(key) % h->n; + + b = h->bins[hv]; + while(b) { + if(!h->comp(b->key, key)) { + /* found it */ + LDELETE(&h->bins[hv], b); + if(h->delr) + h->delr(b->key, b->data); + PFREE(b); + break; + } + b = LNEXT(b); + } +} + +KHMEXP void * KHMAPI hash_lookup(hashtable * h, void * key) { + hash_bin * b; + int hv; + + hv = h->hash(key) % h->n; + + b = h->bins[hv]; + + while(b) { + if(!h->comp(b->key, key)) { + return b->data; + } + b = LNEXT(b); + } + + return NULL; +} + +KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, void * key) { + hash_bin * b; + int hv; + + hv = h->hash(key) % h->n; + b = h->bins[hv]; + while(b) { + if(!h->comp(b->key, key)) + return 1; + b = LNEXT(b); + } + + return 0; +} + +KHMEXP khm_int32 hash_string(const void *vs) { + /* DJB algorithm */ + + khm_int32 hv = 13331; + wchar_t * c; + + for(c = (wchar_t *) vs; *c; c++) { + hv = ((hv<<5) + hv) + (khm_int32) *c; + } + + return (hv & KHM_INT32_MAX); +} + +KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2) { + return wcscmp((const wchar_t *) vs1, (const wchar_t *) vs2); +} diff --git a/mechglue/src/windows/identity/util/hashtable.h b/mechglue/src/windows/identity/util/hashtable.h new file mode 100644 index 000000000..fc7d829f2 --- /dev/null +++ b/mechglue/src/windows/identity/util/hashtable.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_HASHTABLE_H +#define __KHIMAIRA_HASHTABLE_H + +/*! \addtogroup util + @{ */ + +/*! \defgroup util_ht Hashtable + @{*/ + +#include<khdefs.h> +#include<khlist.h> + +/*! \brief A hash function + + The function should take a key as a parameter and return an + khm_int32 that serves as the hash of the key. + */ +typedef khm_int32 (*hash_function_t)(const void *key); + +/*! \brief A comparison function + + The function takes two keys and returns a value indicating the + relative ordering of the two keys. + + The return value should be: + - \b Zero if \a key1 == \a key2 + - \b Negative if \a key1 < \a key2 + - \b Positive if \a key1 > \a key2 + */ +typedef khm_int32 (*comp_function_t)(const void *key1, const void *key2); + +/*! \brief Add-reference function + + When an object is successfully added to a hashtable, this function + will be called with the \a key and \a data used to add the object. + The function is allowed to modify \a data, however, the + modification should not alter the \a key or the relationship + between \a key and \a data. + */ +typedef void (*add_ref_function_t)(const void *key, void *data); + +/*! \brief Delete-reference function + + When an object is successfully removed from the hashtable, this + function will be called. As with the add-ref function, the object + can be modified, but the \a key and the relationship between \a + key and \a data should remain intact. + + An object is removed if it is explicitly removed from the + hashtable or another object with the same \a key is added to the + hashtable. There should be a 1-1 correspondence with keys and + objects in the hashtable. The delete-reference function will be + called on all the remaining objects in the hashtable when the + hashtable is deleted. + */ +typedef void (*del_ref_function_t)(const void *key, void *data); + +typedef struct tag_hash_bin { + void * data; + void * key; + + LDCL(struct tag_hash_bin); +} hash_bin; + +typedef struct hashtable_t { + khm_int32 n; + hash_function_t hash; + comp_function_t comp; + add_ref_function_t addr; + del_ref_function_t delr; + hash_bin ** bins; +} hashtable; + +/*! \brief Create a new hashtable + + \param[in] n Number of bins in hashtable. + \param[in] hash A hash function. Required. + \param[in] comp A comparator. Required. + \param[in] addr An add-ref function. Optional; can be NULL. + \param[in] delr A del-ref function. Optional; can be NULL. + + */ +KHMEXP hashtable * KHMAPI hash_new_hashtable(khm_int32 n, + hash_function_t hash, + comp_function_t comp, + add_ref_function_t addr, + del_ref_function_t delr); + +/*! \brief Delete a hashtable + + \note Not thread-safe. Applications must serialize calls that + reference the same hashtable. + */ +KHMEXP void KHMAPI hash_del_hashtable(hashtable * h); + +/*! \brief Add an object to a hashtable + + Creates an association between the \a key and \a data in the + hashtable \a h. If there is an add-ref function defined for the + hashtable, it will be called with \a key and \data after the + object is added. If there is already an object with the same key + in the hashtable, that object will be removed (and the del-ref + function called, if appilcable) before adding the new object and + before the add-ref function is called for the new object. + + Note that two keys \a key1 and \a key2 are equal (or same) in a + hashtable if the comparator returns zero when called with \a key1 + and \a key2. + + Also note that all additions and removals to the hashtable are + done by reference. No data is copied. Any objects pointed to are + expected to exist for the duration that the object and key are + contained in the hashtable. + + \param[in] h Hashtable + \param[in] key A key. If \a key points to a location in memory, + it should be within the object pointed to by \a data, or be a + constant. Can be NULL. + \param[in] data Data. Cannot be NULL. + + \note Not thread-safe. Applications must serialize calls that + reference the same hashtable. + */ +KHMEXP void KHMAPI hash_add(hashtable * h, void * key, void * data); + +/*! \brief Delete an object from a hashtable + + Deletes the object in the hashtable \a h that is associated with + key \a key. An object is associated with key \a key if the key \a + key_o that the object is associated with is the same as \a key as + determined by the comparator. If the del-ref function is defined + for the hash-table, it will be called with the \a key_o and \a + data that was used to add the object. + + \note Not thread-safe. Applications must serialize calls that + reference the same hashtable. + */ +KHMEXP void KHMAPI hash_del(hashtable * h, void * key); + +/*! \brief Resolve and association + + Return the object that is associated with key \a key in hashtable + \a h. An object \a data is associated with key \a key in \a h if + the key \a key_o that was used to add \a data to \a h is equal to + \a key as determined by the comparator. + + Returns NULL if no association is found. + + \note Not thread-safe. Applications must serialize calls that + reference the same hashtable. + */ +KHMEXP void * KHMAPI hash_lookup(hashtable * h, void * key); + +/*! \brief Check for the presence of an association + + Returns non-zero if there exists an association between key \a key + and some object in hashtable \a h. See hash_lookup() for + definition of "association". + + Returns zero if there is no association. + + \note (hash_lookup(h,key) == NULL) iff (hash_exist(h,key)==0) + + \note Not thead-safe. Application must serialize calls that + reference the same hashtable. + */ +KHMEXP khm_boolean KHMAPI hash_exist(hashtable * h, void * key); + +/*! \brief Compute a hashvalue for a unicode string + + The hash value is computed using DJB with parameter 13331. + + This function is suitable for use as the hash function for a + hashtable if the keys are NULL terminated safe unicode strings + that are either part of the data objects or are constants. + + \param[in] str A pointer to a NULL terminated wchar_t string cast + as (void *). + */ +KHMEXP khm_int32 hash_string(const void *str); + +/*! \brief Compare two strings + + Compares two strings are returns a value that is in accordance + with the comparator for a hashtable. + + \param[in] vs1 A pointer to a NULL terminated wchar_t string cast + as (void *). + \param[in] vs2 A pointer to a NULL terminated wchar_t string cast + as (void *). + */ +KHMEXP khm_int32 hash_string_comp(const void *vs1, const void *vs2); + +/*@}*/ +/*@}*/ + +#endif diff --git a/mechglue/src/windows/identity/util/mstring.c b/mechglue/src/windows/identity/util/mstring.c new file mode 100644 index 000000000..75bab0174 --- /dev/null +++ b/mechglue/src/windows/identity/util/mstring.c @@ -0,0 +1,510 @@ +/* +* Copyright (c) 2005 Massachusetts Institute of Technology +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* $Id$ */ + +#include<mstring.h> +#include<kherror.h> +#include<strsafe.h> +#include<stdlib.h> + +#define TRUE 1 +#define FALSE 0 + +KHMEXP khm_int32 KHMAPI +multi_string_init(wchar_t * ms, + khm_size cb_ms) { + if (!ms || cb_ms < sizeof(wchar_t) * 2) + return KHM_ERROR_INVALID_PARAM; + + memset(ms, 0, cb_ms); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +multi_string_append(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * str) +{ + wchar_t * s; + size_t cch_s; + size_t cch_t; + size_t cch_r; + + if(!ms || !pcb_ms || !str) + return KHM_ERROR_INVALID_PARAM; + + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0) + return KHM_ERROR_INVALID_PARAM; + cch_s++; + + s = ms; + + while(*s && ((s - ms) < KHM_MAXCCH_STRING)) { + if(FAILED(StringCchLength(s, KHM_MAXCB_STRING, &cch_t))) + return KHM_ERROR_INVALID_PARAM; + s += cch_t + 1; + } + + if(*s || (s - ms) >= KHM_MAXCCH_STRING) { + return KHM_ERROR_INVALID_PARAM; + } + + /* now s points to the second NULL of the terminating double NULL */ + + cch_r = ((s - ms) + cch_s + 1) * sizeof(wchar_t); + if(*pcb_ms < cch_r) { + *pcb_ms = cch_r; + return KHM_ERROR_TOO_LONG; + } + + *pcb_ms = cch_r; + + StringCchCopy(s, cch_s, str); + s += cch_s; + *s = 0; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +multi_string_prepend(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * str) +{ + size_t cch_s; + size_t cch_t; + size_t cch_r; + khm_size cb_r; + + if(!ms || !pcb_ms || !str) + return KHM_ERROR_INVALID_PARAM; + + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s)) || cch_s == 0) + return KHM_ERROR_INVALID_PARAM; + cch_s++; + + if(KHM_FAILED(multi_string_length_cch(ms, + KHM_MAXCCH_STRING, + &cch_r))) + return KHM_ERROR_INVALID_PARAM; + + cch_t = cch_s + cch_r; + cb_r = cch_t * sizeof(wchar_t); + + if (*pcb_ms < cb_r) { + *pcb_ms = cb_r; + return KHM_ERROR_TOO_LONG; + } + + memmove(ms + cch_s, ms, cch_r * sizeof(wchar_t)); + memcpy(ms, str, cch_s * sizeof(wchar_t)); + + *pcb_ms = cb_r; + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +multi_string_delete(wchar_t * ms, + const wchar_t * str, + const khm_int32 flags) +{ + wchar_t * s; + wchar_t * n; + wchar_t * e; + size_t cch; + + if(!ms || !str) + return KHM_ERROR_INVALID_PARAM; + + s = multi_string_find(ms, str, flags); + if(!s) + return KHM_ERROR_NOT_FOUND; + + e = s; + n = NULL; + while(*e && (e - s) < KHM_MAXCCH_STRING) { + if(FAILED(StringCchLength(e, KHM_MAXCCH_STRING, &cch))) + return KHM_ERROR_INVALID_PARAM; + e += cch + 1; + + if(!n) + n = e; + } + + if(*e || (e - s) >= KHM_MAXCCH_STRING) + return KHM_ERROR_INVALID_PARAM; + + if(e == s) + return KHM_ERROR_SUCCESS; + + memmove((void *) s, (void *) n, ((e - n) + 1) * sizeof(wchar_t)); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP wchar_t * KHMAPI +multi_string_find(const wchar_t * ms, + const wchar_t * str, + const khm_int32 flags) +{ + const wchar_t *s; + size_t cch; + size_t cch_s; + + if(!ms || !str) + return NULL; + + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch_s))) + return NULL; + + s = ms; + + while(*s && (s - ms) < KHM_MAXCCH_STRING) { + if(FAILED(StringCchLength(s, KHM_MAXCCH_STRING, &cch))) + return NULL; + /* cch++ at end */ + + if(flags & KHM_PREFIX) { + if(((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch_s)) || + (!(flags & KHM_CASE_SENSITIVE) && !wcsnicmp(s, str, cch_s))) + return (wchar_t *) s; + } else { + if((cch == cch_s) && + ((flags & KHM_CASE_SENSITIVE) && !wcsncmp(s, str, cch)) || + (!(flags & KHM_CASE_SENSITIVE) && !wcsnicmp(s, str, cch))) + return (wchar_t *) s; + } + + s += cch + 1; + } + + return NULL; +} + +KHMEXP khm_int32 KHMAPI +multi_string_to_csv(wchar_t * csvbuf, + khm_size * pcb_csvbuf, + const wchar_t * ms) +{ + size_t cb; + size_t cbt; + const wchar_t * t; + wchar_t * d; + + if(!pcb_csvbuf || !ms) + return KHM_ERROR_INVALID_PARAM; + + /* dry run */ + cbt = 0; + t = ms; + while(*t && cbt <= KHM_MAXCB_STRING) { + khm_boolean quotes = FALSE; + + if(FAILED(StringCbLength(t, KHM_MAXCB_STRING, &cb))) + return KHM_ERROR_INVALID_PARAM; + cb += sizeof(wchar_t); + + cbt += cb; + + if(wcschr(t, L',')) + quotes = TRUE; + + d = (wchar_t *) t; + while(d = wcschr(d, L'"')) { + cbt += sizeof(wchar_t); /* '"'-> '""' */ + d++; + quotes = TRUE; + } + + if(quotes) + cbt += 2*sizeof(wchar_t); /* make room for quotes */ + + t += cb / sizeof(wchar_t); + } + + if(cbt > KHM_MAXCB_STRING) + return KHM_ERROR_INVALID_PARAM; + + /* happens if the multi string contained no strings */ + if(cbt == 0) + cbt = sizeof(wchar_t); + + if(!csvbuf || *pcb_csvbuf < cbt) + { + *pcb_csvbuf = cbt; + return KHM_ERROR_TOO_LONG; + } + + *pcb_csvbuf = cbt; + + /* wet run */ + t = ms; + d = csvbuf; + *csvbuf = 0; + while(*t) { + const wchar_t * s; + + StringCbLength(t, KHM_MAXCB_STRING, &cb); + cb += sizeof(wchar_t); + + if(d != csvbuf) + *d++ = L','; + if(wcschr(t, L',') || wcschr(t, L'"')) { + *d++ = L'"'; + s = t; + while(*s) { + if(*s == L'"') { + *d++ = L'"'; + *d++ = L'"'; + } else + *d++ = *s; + s++; + } + *d++ = L'"'; + *d = 0; + } else { + StringCbCopy(d, cbt - ((d - csvbuf) * sizeof(wchar_t)), t); + d += cb / sizeof(wchar_t) - 1; + } + t += cb / sizeof(wchar_t); + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +csv_to_multi_string(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * csv) +{ + const wchar_t * t; + wchar_t * p; + size_t cchr; + int field = 1; + + + if(!pcb_ms || !csv) + return KHM_ERROR_INVALID_PARAM; + + cchr = 0; + + /* dry run */ + t = csv; + while(*t && (t - csv) < KHM_MAXCCH_STRING) { + if(field && *t == L'"') { + t++; + while(*t && (t - csv) < KHM_MAXCCH_STRING) { + if(*t == L'"') { + t++; + if(*t != L'"') + break; + } + cchr++; + t++; + } + } + + if(*t) { + cchr++; + if(*t == L',') + field = 1; + else + field = 0; + + t++; + } + } + + if((t - csv) >= KHM_MAXCCH_STRING) + return KHM_ERROR_INVALID_PARAM; + + cchr++; /* last string ends */ + cchr++; /* double NULL */ + + if(!ms || *pcb_ms < (cchr * sizeof(wchar_t))) { + *pcb_ms = cchr * sizeof(wchar_t); + return KHM_ERROR_TOO_LONG; + } + + /* wet run */ + t = csv; + p = ms; + field = 1; + while(*t) { + if(field && *t == L'"') { + t++; + while(*t) { + if(*t == L'"') { + t++; + if(*t != L'"') + break; + } + *p++ = *t; + t++; + } + } + + if(*t == L',') { + *p++ = 0; + field = 1; + t++; + } else if(*t) { + *p++ = *t; + field = 0; + t++; + } + } + + *p++ = 0; /* last string ends */ + *p++ = 0; /* double NULL */ + + *pcb_ms = (p - ms) * sizeof(wchar_t); + + return KHM_ERROR_SUCCESS; +} + +KHMEXP wchar_t * KHMAPI +multi_string_next(const wchar_t * str) +{ + size_t cch; + + if(*str) { + if(FAILED(StringCchLength(str, KHM_MAXCCH_STRING, &cch))) + return NULL; + str += cch + 1; + if(*str) + return (wchar_t *) str; + else + return NULL; + } else { + return NULL; + } +} + +KHMEXP khm_size KHMAPI +multi_string_length_n(const wchar_t * str) +{ + size_t n = 0; + const wchar_t * c = str; + + while(c) { + n++; + c = multi_string_next(c); + } + + return n; +} + +KHMEXP khm_int32 KHMAPI +multi_string_length_cb(const wchar_t * str, + khm_size max_cb, + khm_size * len_cb) +{ + khm_size cch; + khm_int32 rv; + + rv = multi_string_length_cch(str, max_cb / sizeof(wchar_t), &cch); + + if(KHM_FAILED(rv)) + return rv; + + if(len_cb) + *len_cb = cch * sizeof(wchar_t); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +multi_string_length_cch(const wchar_t * str, + khm_size max_cch, + khm_size * len_cch) +{ + const wchar_t * s; + khm_size cch; + size_t tcch; + + if(!str) + return KHM_ERROR_INVALID_PARAM; + + s = str; + cch = 0; + while(*s && (cch < max_cch)) { + if(FAILED(StringCchLength(s, max_cch, &tcch))) + return KHM_ERROR_TOO_LONG; + cch += ++tcch; + s += tcch; + } + + if(cch >= max_cch) + return KHM_ERROR_TOO_LONG; + + if(len_cch) { + *len_cch = ++cch; + } + + return KHM_ERROR_SUCCESS; +} + +KHMEXP khm_int32 KHMAPI +multi_string_copy_cb(wchar_t * s_dest, + khm_size max_cb_dest, + const wchar_t * src) +{ + khm_size cb_dest; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!s_dest) + return KHM_ERROR_INVALID_PARAM; + + rv = multi_string_length_cb(src, max_cb_dest, &cb_dest); + if(KHM_FAILED(rv)) + return rv; + + memmove(s_dest, src, cb_dest); + + return rv; +} + +KHMEXP khm_int32 KHMAPI +multi_string_copy_cch(wchar_t * s_dest, + khm_size max_cch_dest, + const wchar_t * src) +{ + khm_size cch_dest; + khm_int32 rv = KHM_ERROR_SUCCESS; + + if(!s_dest) + return KHM_ERROR_INVALID_PARAM; + + rv = multi_string_length_cch(src, max_cch_dest, &cch_dest); + if(KHM_FAILED(rv)) + return rv; + + memmove(s_dest, src, cch_dest * sizeof(wchar_t)); + + return rv; +} diff --git a/mechglue/src/windows/identity/util/mstring.h b/mechglue/src/windows/identity/util/mstring.h new file mode 100644 index 000000000..a7f6cf523 --- /dev/null +++ b/mechglue/src/windows/identity/util/mstring.h @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_MSTRING_H +#define __KHIMAIRA_MSTRING_H + +#include<khdefs.h> + +/*! \addtogroup util + @{ */ + +/*! \defgroup util_mstring Multi String and CSV functions + @{*/ + +#define KHM_PREFIX 8 + +#define KHM_CASE_SENSITIVE 16 + +#define KHM_MAXCCH_STRING 16384 + +#define KHM_MAXCB_STRING (KHM_MAXCCH_STRING * sizeof(wchar_t)) + +/*! \brief Initialize a multi-string + */ +KHMEXP khm_int32 KHMAPI +multi_string_init(wchar_t * ms, + khm_size cb_ms); + +/*! \brief Prepend a string to a multi string + + Adds the string \a str to the beginning of multi-string \a ms. + + \param[in,out] ms The multi-string to be modified. + + \param[in,out] pcb_ms A pointer to the size of the multistring. + On entry this specifies the size of the buffer pointed to by + \a ms. If the call is successful, on exit this will receive + the new size of the multi string in bytes. If the buffer is + insufficient, the function will return KHM_ERROR_TOO_LONG and + set this to the required size of the buffer in bytes. + + \param[in] str The string to prepend to \a ms. This cannot be + longer than KHM_MAXCCH_STRING in characters including the + terminating NULL. + */ +KHMEXP khm_int32 KHMAPI +multi_string_prepend(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * str); + +/*! \brief Append a string to a multi-string + + Appends the string specified by \a str to the multi string + specified by \a ms. The size of the multi string in characters + including terminating NULLs after appending \a str can not exceed + KHM_MAXCCH_STRING. + + \param[in] ms The buffer containing the multi string + + \param[in,out] pcb_ms Points to a khm_int32 indicating the size of + the buffer pointed to by \a ms. On entry this contains the + size (in bytes) of the buffer pointed to by \a ms. On exit, + contains the new size of the multi string in bytes. + + \param[in] str The string to append to the multi string. This + string cannot be NULL or an empty (zero length) string. The + length of \a str cannot exceed KHM_MAXCCH_STRING in + characters including terminating NULL. + + \retval KHM_ERROR_SUCCESS The string was appended to the multi string + + \retval KHM_ERROR_TOO_LONG The buffer pointed to by \a ms was + insufficient. The required size of the buffer is in \a pcb_ms + + \retval KHM_ERROR_INVALID_PARAM One of more of the parameters were invalid. + */ +KHMEXP khm_int32 KHMAPI +multi_string_append(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * str); + +/*! \brief Deletes a string from a multi string + + Deletes the string specified by \a str from the multi string + specified by \a ms. How the string is matched to the strings in + \a ms is determined by \a flags. If more than one match is found, + then only the first match is deleted. + + \param[in] ms The multi string to modify. The length of the multi + string in characters cannot exceed KHM_MAXCCH_STRING. + + \param[in] str The string to search for + + \param[in] flags How \a str is to be matched to existing strings + in \a ms. This could be a combination of KHM_PREFIX and + KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is + searched for a string that begins with \a str. Otherwise, \a + str must match the an entire string in the multi string. If + KHM_CASE_SENSITIVE is specified, then a case sensitive match + is performed. The defualt is to use a case insensitive + search. + + \retval KHM_ERROR_SUCCESS A string was matched and deleted from \a ms + + \retval KHM_ERROR_NOT_FOUND No matches were found + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were incorrect. + + \note The search for the existing string is done with + multi_string_find() + */ +KHMEXP khm_int32 KHMAPI +multi_string_delete(wchar_t * ms, + const wchar_t * str, + const khm_int32 flags); + +/*! \brief Search a multi string for a string + + Searches the string specified by \a ms for a string that matches + \a str. How the match is performed is determined by \a flags. + Returns a poitner to the start of the matched string in \a ms. If + more than one string in \a ms matches \a str, then only the first + match is returned. + + \param[in] ms The multi string to search in. The length of the + multi string cannot exceed KHM_MAXCCH_STRING in characters. + + \param[in] str The string to search for + + \param[in] flags How \a str is to be matched to existing strings + in \a ms. This could be a combination of KHM_PREFIX and + KHM_CASE_SENSITIVE. If KHM_PREFIX is used, then \a ms is + searched for a string that begins with \a str. Otherwise, \a + str must match the an entire string in the multi string. If + KHM_CASE_SENSITIVE is specified, then a case sensitive match + is performed. The defualt is to use a case insensitive + search. + + \return A pointer to the start of the first matched string or + NULL if no matches were found. + + */ +KHMEXP wchar_t * KHMAPI +multi_string_find(const wchar_t * ms, + const wchar_t * str, + const khm_int32 flags); + +/*! \brief Convert a multi string to CSV + + Converts a multi string to a comma separated value string based on + the following rules. + + - Each string in the multi string is treated an individual field + + - A field is quoted if it has double quotes or commas + + - Double quotes within quoted fields are escaped by two + consecutive double quotes. + + For example: + + \code + multi_string = L"foo\0bar\0baz,quux\0ab\"cd\0"; + csv_string = L"foo,bar,\"baz,quux\",\"ab\"\"cd\""; + \endcode + + If multi_string_to_csv() is called on \a multi_string above, + you would obtain \a csv_string. + + \param[out] csvbuf The buffer to place the CSV string in. Can be + NULL if only teh size of the needed buffer is required. + + \param[in,out] pcb_csvbuf On entry, points to a khm_int32 that + holds the size of the buffer pointed to by \a csvbuf. On + exit, gets the number of bytes writted to \a csvbuf or the + required size of \a csvbuf if the buffer is too small or \a + csvbuf is NULL. + + \param[in] ms The mutli string to convert to a CSV. + + \retval KHM_ERROR_SUCCESS The multi string was successfully + converted to a CSV string. The number of bytes written is in + \a pcb_csvbuf. The count includes the terminating NULL. + + \retval KHM_ERROR_TOO_LONG The buffer was too small or \a csvbuf + was NULL. The required number of bytes in the buffer is in \a + pcb_csvbuf. + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were ivnalid. + + \see csv_to_multi_string() +*/ +KHMEXP khm_int32 KHMAPI +multi_string_to_csv(wchar_t * csvbuf, + khm_size * pcb_csvbuf, + const wchar_t * ms); + +/*! \brief Converts a CSV to a multi string + + Undoes what multi_string_to_csv() does. + + \param[out] ms The buffer that recieves the multi string. This + can be NULL if only the size of the buffer is requried. + + \param[in,out] pcb_ms On entry contains the number of bytes ni the + buffer poitned to by \a ms. On exit contains the number of + bytes that were copied to \a ms including terminating NULLs, + or if the buffer was too small or \a ms was NULL, holds the + size in bytes of the requied buffer. + + \param[in] csv The CSV string. + + \retval KHM_ERROR_SUCCESS The CSV string was successfully + converted. The number of bytes written is in \a pcb_ms. + + \retval KHM_ERROR_TOO_LONG The provided buffer was too small or \a + ms was NULL. The required size of the buffer in bytes is in \a + pcb_ms. + + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid. + + */ +KHMEXP khm_int32 KHMAPI +csv_to_multi_string(wchar_t * ms, + khm_size * pcb_ms, + const wchar_t * csv); + +/*! \brief Get the next string in a multi string + + When \a str is pointing to a string that is in a multi string, + this function returns a pointer to the next string in the multi + string. + + Typically, one would start by having \a str point to the start of + the multi string (which is the first string in the multi string), + and then call this function repeatedly, until it returns NULL, at + which point the end of the multi string has been reached. + + \param[in] str Pointer to a string in a multi string. Each string + in a multi string cannot exceed KHM_MAXCCH_STRING in charaters + including the terminating NULL. + + \return A pointer to the start of the next string in the multi + string or NULL if there is no more strings. + */ +KHMEXP wchar_t * KHMAPI +multi_string_next(const wchar_t * str); + +/*! \brief Get the length of a multi string in bytes + + The returned length includes the trailing double \a NULL and any + other \a NULL inbetween. + + \param[in] str Pointer to a multi string. + \param[in] max_cb Maximum size that the str can be. This can not + be larger than KHM_MAXCB_STRING. + \param[out] len_cb The length of the string in bytes if the call + is successful. + + \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cb + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG The multi string is longer than \a + max_cb bytes. + */ +KHMEXP khm_int32 KHMAPI +multi_string_length_cb(const wchar_t * str, + khm_size max_cb, + khm_size * len_cb); + +/*! \brief Get the length of a multi string in characters + + The returned length includes the trailing double \a NULL and any + other \a NULL inbetween. + + \param[in] str Pointer to a multi string. + \param[in] max_cch Maximum size that the str can be. This can not + be larger than KHM_MAXCCH_STRING. + \param[out] len_cch The length of the string in characters if the call + is successful. + + \retval KHM_ERROR_SUCCESS The length of the string is in \a len_cch + \retval KHM_ERROR_INVALID_PARAM One or more parameters were invalid + \retval KHM_ERROR_TOO_LONG The multi string is longer than \a + max_cch characters. + */ +KHMEXP khm_int32 KHMAPI +multi_string_length_cch(const wchar_t * str, + khm_size max_cch, + khm_size * len_cch); + +/*! \brief Get the number of strings in a multi string + */ +KHMEXP khm_size KHMAPI +multi_string_length_n(const wchar_t * str); + +/*! \brief Copy a multi string with byte counts + + Copy a multi string from one location to another. + + \param[out] s_dest Receives a copy of the multi string + \param[in] max_cb_dest Number of bytes in the buffer pointed to by + \a s_dest. + \param[in] src The source multi string + + \retval KHM_ERROR_SUCCESS The multi string was copied successfully + \retval KHM_ERROR_INVALID_PARAM One or more parameters were + invalid. + \retval KHM_ERROR_TOO_LONG The size of the destination buffer was + insufficient. + */ +KHMEXP khm_int32 KHMAPI +multi_string_copy_cb(wchar_t * s_dest, + khm_size max_cb_dest, + const wchar_t * src); + +/*! \brief Copy a multi string with character count + + Copy a multi string from one location to another. + + \param[out] s_dest Receives a copy of the multi string + \param[in] max_cb_dest Number of characters in the buffer pointed + to by \a s_dest. + \param[in] src The source multi string + + \retval KHM_ERROR_SUCCESS The multi string was copied successfully + \retval KHM_ERROR_INVALID_PARAM One or more parameters were + invalid. + \retval KHM_ERROR_TOO_LONG The size of the destination buffer was + insufficient. + */ +KHMEXP khm_int32 KHMAPI +multi_string_copy_cch(wchar_t * s_dest, + khm_size max_cch_dest, + const wchar_t * src); + +/*@}*/ + +#endif diff --git a/mechglue/src/windows/identity/util/perfstat.c b/mechglue/src/windows/identity/util/perfstat.c new file mode 100644 index 000000000..814920dce --- /dev/null +++ b/mechglue/src/windows/identity/util/perfstat.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<windows.h> +#include<utils.h> +#include<malloc.h> +#include<stdio.h> +#include<strsafe.h> +#include<assert.h> + +#define HASHSIZE 1151 +#define ALLOCBLOCK 1024 + +#define HASHPTR(p) (((size_t) (p)) % HASHSIZE) + +typedef struct tag_allocation { + char file[8]; + int line; + size_t size; + void * ptr; + + LDCL(struct tag_allocation); +} allocation; + +static allocation * ht[HASHSIZE]; + +static allocation * next_alloc = NULL; +static size_t idx_next_alloc = 0; +static allocation * free_alloc = NULL; + +static CRITICAL_SECTION cs_alloc; +static LONG ctr = 0; +static int perf_ready = 0; + +static void perf_once(void) { + if (InterlockedIncrement(&ctr) == 1) { + InitializeCriticalSection(&cs_alloc); + ZeroMemory(ht, sizeof(ht)); + + next_alloc = malloc(sizeof(allocation) * ALLOCBLOCK); + assert(next_alloc); + idx_next_alloc = 0; + free_alloc = NULL; + + perf_ready = 1; + } else { + while(!perf_ready) { + Sleep(0); /* relinquish control to the thread + that is initializing the alloc + data. */ + } + } +} + +static allocation * get_allocation(void) { + allocation * a; + + LPOP(&free_alloc, &a); + if (!a) { + if (idx_next_alloc == ALLOCBLOCK) { + next_alloc = malloc(sizeof(allocation) * ALLOCBLOCK); + assert(next_alloc); + idx_next_alloc = 0; + } + + a = &next_alloc[idx_next_alloc]; + idx_next_alloc++; + } + + return a; +} + +#define MAXCB_STR 32768 + +KHMEXP wchar_t * +perf_wcsdup(char * file, int line, const wchar_t * str) { + size_t cb; + wchar_t * dest; + + if (FAILED(StringCbLength(str, MAXCB_STR, &cb))) + return NULL; + cb += sizeof(wchar_t); + + dest = (wchar_t *) perf_malloc(file, line, cb); + StringCbCopy(dest, cb, str); + + return dest; +} + +KHMEXP char * +perf_strdup(char * file, int line, const char * str) { + size_t cb; + char * dest; + + if (FAILED(StringCbLengthA(str, MAXCB_STR, &cb))) + return NULL; + cb += sizeof(char); + + dest = (char *) perf_malloc(file, line, cb); + StringCbCopyA(dest, cb, str); + + return dest; +} + +KHMEXP void * +perf_calloc(char * file, int line, size_t num, size_t size) { + void * ptr; + size_t tsize; + + tsize = num * size; + + ptr = perf_malloc(file,line,tsize); + + if (ptr) { + ZeroMemory(ptr, tsize); + } + + return ptr; +} + +KHMEXP void * +perf_malloc(char * file, int line, size_t s) { + allocation * a; + void * ptr; + size_t h; + + perf_once(); + + assert(s > 0); + + EnterCriticalSection(&cs_alloc); + a = get_allocation(); + + ptr = malloc(s); + + assert(ptr); /* TODO: handle this gracefully */ + + if (file[0] == '.' && file[1] == '\\') + file += 2; + + StringCbCopyA(a->file, sizeof(a->file), file); + a->line = line; + a->size = s; + a->ptr = ptr; + + h = HASHPTR(ptr); + + LPUSH(&ht[h], a); + LeaveCriticalSection(&cs_alloc); + + return ptr; +} + +KHMEXP void * +perf_realloc(char * file, int line, void * data, size_t s) { + void * n_data; + allocation * a; + size_t h; + + if (data == NULL) + return perf_malloc(file, line, s); + + perf_once(); + h = HASHPTR(data); + + n_data = realloc(data, s); + + assert(n_data); + + EnterCriticalSection(&cs_alloc); + for (a = ht[h]; a; a = LNEXT(a)) { + if (a->ptr == data) + break; + } + + assert(a); + + LDELETE(&ht[h], a); + + a->size = s; + a->ptr = n_data; + + h = HASHPTR(n_data); + LPUSH(&ht[h], a); + LeaveCriticalSection(&cs_alloc); + + return n_data; +} + +KHMEXP void +perf_free (void * b) { + size_t h; + allocation * a; + + perf_once(); + h = HASHPTR(b); + + EnterCriticalSection(&cs_alloc); + for(a = ht[h]; a; a = LNEXT(a)) { + if (a->ptr == b) + break; + } + + assert(a); + + LDELETE(&ht[h], a); + LPUSH(&free_alloc, a); + LeaveCriticalSection(&cs_alloc); +} + +KHMEXP void +perf_dump(char * file) { + FILE * f; + size_t i; + allocation * a; + size_t total = 0; + + perf_once(); + + EnterCriticalSection(&cs_alloc); + f = fopen(file, "w"); + if (!f) + return; + + fprintf(f, "Leaked allocations list ....\n"); + fprintf(f, "File\tLine\tSize\n"); + + for (i=0; i < HASHSIZE; i++) { + for (a = ht[i]; a; a = LNEXT(a)) { + fprintf(f, "%s\t%6d\t%6d\n", a->file, a->line, a->size); + total += a->size; + } + } + + fprintf(f, "----------------------------------------\n"); + fprintf(f, "Total\t\t%d\n", total); + fprintf(f, "----------------- End ------------------\n"); + + fclose(f); + + LeaveCriticalSection(&cs_alloc); +} diff --git a/mechglue/src/windows/identity/util/perfstat.h b/mechglue/src/windows/identity/util/perfstat.h new file mode 100644 index 000000000..d8d5951b3 --- /dev/null +++ b/mechglue/src/windows/identity/util/perfstat.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_PERFSTAT_H +#define __KHIMAIRA_PERFSTAT_H + +#include<khdefs.h> + +#ifdef DEBUG +#define PMALLOC(s) perf_malloc(__FILE__,__LINE__,s) +#define PCALLOC(n,s) perf_calloc(__FILE__,__LINE__,n,s) +#define PREALLOC(d,s) perf_realloc(__FILE__,__LINE__,d,s) +#define PFREE(p) perf_free(p) +#define PDUMP(f) perf_dump(f) +#define PWCSDUP(s) perf_wcsdup(__FILE__,__LINE__,s) +#define PSTRDUP(s) perf_strdup(__FILE__,__LINE__,s) +#else +#define PMALLOC(s) malloc(s) +#define PCALLOC(n,s) calloc(n,s) +#define PREALLOC(d,s) realloc(d,s) +#define PFREE(p) free(p) +#define PDUMP(f) ((void) 0) +#define PWCSDUP(s) wcsdup(s) +#define PSTRDUP(s) strdup(s) +#endif + +KHMEXP void * +perf_malloc(char * file, int line, size_t s); + +KHMEXP void * +perf_realloc(char * file, int line, void * data, size_t s); + +KHMEXP void +perf_free (void * b); + +KHMEXP void +perf_dump (char * filename); + +KHMEXP wchar_t * +perf_wcsdup(char * file, int line, const wchar_t * str); + +KHMEXP char * +perf_strdup(char * file, int line, const char * str); + +KHMEXP void * +perf_calloc(char * file, int line, size_t num, size_t size); + +#endif diff --git a/mechglue/src/windows/identity/util/sync.c b/mechglue/src/windows/identity/util/sync.c new file mode 100644 index 000000000..d686a8e80 --- /dev/null +++ b/mechglue/src/windows/identity/util/sync.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#include<windows.h> +#include<sync.h> +#include<assert.h> + +#define LOCK_OPEN 0 +#define LOCK_READING 1 +#define LOCK_WRITING 2 + +KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock) +{ + pLock->locks = 0; + pLock->status = LOCK_OPEN; + InitializeCriticalSection(&(pLock->cs)); + pLock->writewx = CreateEvent(NULL, + FALSE, /* Manual reset */ + TRUE, /* Initial state */ + NULL); + pLock->readwx = CreateEvent(NULL, + TRUE, /* Manual reset */ + TRUE, /* Initial state */ + NULL); +} + +KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock) +{ + DeleteCriticalSection(&(pLock->cs)); + CloseHandle(pLock->readwx); + CloseHandle(pLock->writewx); + pLock->readwx = NULL; + pLock->writewx = NULL; +} + +KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock) +{ + while(1) { + WaitForSingleObject(pLock->readwx, INFINITE); + EnterCriticalSection(&pLock->cs); + if(pLock->status == LOCK_WRITING) { + LeaveCriticalSection(&(pLock->cs)); + continue; + } else + break; + } + pLock->locks ++; + pLock->status = LOCK_READING; + ResetEvent(pLock->writewx); + LeaveCriticalSection(&(pLock->cs)); +} + +KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock) +{ + EnterCriticalSection(&(pLock->cs)); + assert(pLock->status == LOCK_READING); + pLock->locks--; + if(!pLock->locks) { + pLock->status = LOCK_OPEN; + SetEvent(pLock->readwx); + SetEvent(pLock->writewx); + } + LeaveCriticalSection(&(pLock->cs)); +} + +KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock) +{ + EnterCriticalSection(&(pLock->cs)); + if(pLock->status == LOCK_WRITING && + pLock->writer == GetCurrentThreadId()) { + pLock->locks++; + LeaveCriticalSection(&(pLock->cs)); + assert(FALSE); + return; + } + LeaveCriticalSection(&(pLock->cs)); + while(1) { + WaitForSingleObject(pLock->writewx, INFINITE); + EnterCriticalSection(&(pLock->cs)); + if(pLock->status == LOCK_OPEN) + break; + LeaveCriticalSection(&(pLock->cs)); + } + pLock->status = LOCK_WRITING; + pLock->locks++; + pLock->writer = GetCurrentThreadId(); + ResetEvent(pLock->readwx); + LeaveCriticalSection(&(pLock->cs)); +} + +KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock) +{ + EnterCriticalSection(&(pLock->cs)); + assert(pLock->status == LOCK_WRITING); + pLock->locks--; + if(!pLock->locks) { + pLock->status = LOCK_OPEN; + pLock->writer = 0; + SetEvent(pLock->readwx); + SetEvent(pLock->writewx); + } + LeaveCriticalSection(&(pLock->cs)); +} diff --git a/mechglue/src/windows/identity/util/sync.h b/mechglue/src/windows/identity/util/sync.h new file mode 100644 index 000000000..e423e6766 --- /dev/null +++ b/mechglue/src/windows/identity/util/sync.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_SYNC_H +#define __KHIMAIRA_SYNC_H + +#include<khdefs.h> + +/*! \addtogroup util + @{ */ + +/*! \defgroup util_sync Synchronization + @{*/ + +/*! \brief A read/write lock + + A classic read/write lock. Allows multiple readers or a single + writer to access a protected object. Readers will wait for any + pending writer to release the lock, while a writer will wait for + any pending readers to release the lock. +*/ +typedef struct tag_rwlock { + int locks; + int status; + CRITICAL_SECTION cs; + HANDLE readwx; + HANDLE writewx; + + DWORD writer; /* TID of writer thread */ +} rw_lock_t; + +typedef rw_lock_t RWLOCK, *PRWLOCK; + +/*! \brief Initialize a read/write lock. + + A lock <b>must</b> be initialized before it can be used. + Initializing the lock does not grant the caller any locks on the + object. +*/ +KHMEXP void KHMAPI InitializeRwLock(PRWLOCK pLock); + +/*! \brief Delete a read/write lock + + Once the application is done using the read/write lock, it must be + deleted with a call to DeleteRwLock() +*/ +KHMEXP void KHMAPI DeleteRwLock(PRWLOCK pLock); + +/*! \brief Obtains a read lock on the read/write lock + + Multiple readers can obtain read locks on the same r/w lock. + However, if any thread attempts to obtain a write lock on the + object, it will wait until all readers have released the read + locks. + + Call LockReleaseRead() to release the read lock. While the same + thread may obtain multiple read locks on the same object, each + call to LockObtainRead() must have a corresponding call to + LockReleaseRead() to properly relinquish the lock. + + \see LockReleaseRead() +*/ +KHMEXP void KHMAPI LockObtainRead(PRWLOCK pLock); + +/*! \brief Relase a read lock obtained on a read/write lock + + Each call to LockObtainRead() must have a corresponding call to + LockReleaseRead(). Once all read locks are released, any threads + waiting on write locks on the object will be woken and assigned a + write lock. + + \see LockObtainRead() +*/ +KHMEXP void KHMAPI LockReleaseRead(PRWLOCK pLock); + +/*! \brief Obtains a write lock on the read/write lock + + Only a single writer is allowed to lock a single r/w lock. + However, if any thread attempts to obtain a read lock on the + object, it will wait until the writer has released the lock. + + Call LockReleaseWrite() to release the write lock. While the same + thread may obtain multiple write locks on the same object, each + call to LockObtainWrite() must have a corresponding call to + LockReleaseWrite() to properly relinquish the lock. + + \see LockReleaseWrite() +*/ +KHMEXP void KHMAPI LockObtainWrite(PRWLOCK pLock); + +/*! \brief Relase a write lock obtained on a read/write lock + + Each call to LockObtainWrite() must have a corresponding call to + LockReleaseWrite(). Once the write lock is released, any threads + waiting for read or write locks on the object will be woken and + assigned the proper lock. + + \see LockObtainWrite() +*/ +KHMEXP void KHMAPI LockReleaseWrite(PRWLOCK pLock); + +/*@}*/ +/*@}*/ + +#endif diff --git a/mechglue/src/windows/identity/util/utils.h b/mechglue/src/windows/identity/util/utils.h new file mode 100644 index 000000000..4ba86f6ed --- /dev/null +++ b/mechglue/src/windows/identity/util/utils.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* $Id$ */ + +#ifndef __KHIMAIRA_UTIL_H +#define __KHIMAIRA_UTIL_H + +/*! \defgroup util Utilities + */ +#include<hashtable.h> +#include<sync.h> +#include<mstring.h> +#include<perfstat.h> + +#endif diff --git a/mechglue/src/windows/installer/nsis/ChangeLog b/mechglue/src/windows/installer/nsis/ChangeLog new file mode 100644 index 000000000..ca5dde111 --- /dev/null +++ b/mechglue/src/windows/installer/nsis/ChangeLog @@ -0,0 +1,77 @@ +2005-11-29 Jeffrey Altman <jaltman@mit.edu> + +KFW 3.0 Beta 2 + +- adds KFW Logon Network Provider +- adds Documentation links for NetIdMgr.chm + +2005-11-01 Jeffrey Altman <jaltman@mit.edu> + +KFW 3.0 Beta 1 + +- adds support for Network Identity Manager Framework +- removes leash32.exe + +2004-12-18 Jeffrey Altman <jaltman@mit.edu> + +* kfw-fixed.nsi: + Add "Debug Symbols" as a new category. It defaults to on + in debug builds and off in release builds. + +2004-12-15 Jeffrey Altman <jaltman@mit.edu> + +* kfw-fixed.nsi + Add kcpytkt.exe, kdeltkt.exe, k5sprt32.dll, mit2ms.exe + +2004-09-17 Jeffrey Altman <jaltman@mit.edu> + +* kfw-fixed.nsi: + The version of MSIEXEC which ships with Windows 2000 does + not accept the /passive and /promptreboot command line + options. On Windows 2000 only, do not specify them. + +2004-09-13 Jeffrey Altman <jaltman@mit.edu> + +* kfw-fixed.nsi: + + Detect the Wix MSI, the SWRT MSI, and the Pismere MSI + If found, uninstall the MSI before installing NSIS + +2004-09-07 Jeffrey Altman <jaltman@mit.edu> + +* kfw-fixed.nsi: + Include all subdirectories of KFW_INSTALL_DIR + +2004-07-07 Jeffrey Altman <jaltman@mit.edu> + +* kfw-fixed.nsi: + Create registry entries to provide Terminal Service application + compatibility flags for all executables + http://support.microsoft.com/default.aspx?scid=kb;EN-US;186499 + +2004-07-07 Jeffrey Altman <jaltman@mit.edu> + +* kfw-fixed.nsi: + Microsoft did not place the AllowTGTSessionKey in the same place + for both XP SP2 and the server platforms. Even though they said + they would. Modify the installer to set both locations. + +2004-05-17 Jeffrey Altman <jaltman@mit.edu> + +* kfw.nsi, kfw-fixed.nsi, utils.nsi: + - replace the UpdateDLL macro with the ReplaceDLL macro + - use ReplaceDLL to install all .exe and .dll files + this will allow the installer to work even when some files + are loaded by modules which cannot be terminated such as + Network Providers (afslogon.dll for example) + +2004-04-14 Jeffrey Altman <jaltman@mit.edu> + +* nsi-includes.nsi: update version to 2.6.1 + +* kfw-fixed.nsi: add kvno.exe, gss-client.exe, gss-server.exe + +2004-03-31 Jeffrey Altman <jaltman@mit.edu> + +* Add the NSIS installer for KFW 2.6 to the repository + diff --git a/mechglue/src/windows/installer/nsis/KfWConfigPage.ini b/mechglue/src/windows/installer/nsis/KfWConfigPage.ini new file mode 100644 index 000000000..abc0ed63b --- /dev/null +++ b/mechglue/src/windows/installer/nsis/KfWConfigPage.ini @@ -0,0 +1,59 @@ +[Settings] +NumFields=7 + +[Field 1] +Type=label +Text=The Kerberos Client may utilize configuration files to assist in contacting KDCs. Where do you want to get these files? +Left=0 +Right=-1 +Top=0 +Bottom=20 + +[Field 2] +Type=RadioButton +Text=Use existing configuration files from a previous installation. +Left=10 +Right=-1 +Top=25 +Bottom=35 + +[Field 3] +Type=RadioButton +Text=Use packaged configuration files. +Left=10 +Right=-1 +Top=40 +Bottom=50 + +[Field 4] +type=RadioButton +Text=Download from web path: +State=0 +Left=10 +Right=-1 +Top=55 +Bottom=65 + +[Field 5] +type=Text +State= +Left=20 +Right=-1 +Top=70 +Bottom=80 + +[Field 6] +type=radioButton +text=Select a directory +Left=10 +Right=-1 +Top=85 +Bottom=95 + +[Field 7] +type=DirRequest +Flags=PATH_MUST_EXIST +Left=20 +Right=-40 +Top=100 +Bottom=110 diff --git a/mechglue/src/windows/installer/nsis/KfWConfigPage2.ini b/mechglue/src/windows/installer/nsis/KfWConfigPage2.ini new file mode 100644 index 000000000..60c3bfc43 --- /dev/null +++ b/mechglue/src/windows/installer/nsis/KfWConfigPage2.ini @@ -0,0 +1,20 @@ +[Settings] +NumFields=3 + +[Field 1] +Type=label +Text=The Leash ticket manager maybe installed with the following optional functionality. Please check those items you wish activated. +Left=0 +Right=-1 +Top=0 +Bottom=20 + +[Field 2] +Type=CheckBox +Text=Autostart the Leash ticket manager each time you login to Windows. +State=1 +Left=10 +Right=-1 +Top=25 +Bottom=35 + diff --git a/mechglue/src/windows/installer/nsis/kfw-fixed.nsi b/mechglue/src/windows/installer/nsis/kfw-fixed.nsi new file mode 100644 index 000000000..f812e7326 --- /dev/null +++ b/mechglue/src/windows/installer/nsis/kfw-fixed.nsi @@ -0,0 +1,1866 @@ +;----------------------------------------------------------------- +; KfW defines and functionality +; Copyright (c) 2004 Massachusetts Institute of Technology + +!define KFW_VERSION "${KFW_MAJORVERSION}.${KFW_MINORVERSION}.${KFW_PATCHLEVEL}" + +!define PROGRAM_NAME "Kerberos for Windows" +!ifdef RELEASE +!ifndef DEBUG ; !DEBUG on v2.0b4 +Name "MIT ${PROGRAM_NAME} ${KFW_VERSION}" +!else ; DEBUG on v2.0b4 +Name "MIT ${PROGRAM_NAME} ${KFW_VERSION} Checked/Debug" +!endif ; End DEBUG/!DEBUG +!else +!ifdef BETA +!ifndef DEBUG ; !DEBUG on v2.0b4 +Name "MIT ${PROGRAM_NAME} ${KFW_VERSION} Beta ${BETA}" +!else ; DEBUG on v2.0b4 +Name "MIT ${PROGRAM_NAME} ${KFW_VERSION} Beta ${BETA} Checked/Debug" +!endif ; End DEBUG/!DEBUG +!else +!ifndef DEBUG ; !DEBUG on v2.0b4 +Name "MIT ${PROGRAM_NAME} ${KFW_VERSION} ${__DATE__} ${__TIME__}" +!else ; DEBUG on v2.0b4 +Name "MIT ${PROGRAM_NAME} ${KFW_VERSION} ${__DATE__} ${__TIME__} Checked/Debug" +!endif ; End DEBUG/!DEBUG +!endif +!endif +VIProductVersion "${KFW_MAJORVERSION}.${KFW_MINORVERSION}.${KFW_PATCHLEVEL}.00" +VIAddVersionKey "ProductName" "${PROGRAM_NAME}" +VIAddVersionKey "CompanyName" "Massachusetts Institute of Technology" +VIAddVersionKey "ProductVersion" ${VIProductVersion} +VIAddVersionKey "FileVersion" ${VIProductVersion} +VIAddVersionKey "FileDescription" "MIT Kerberos for Windows Installer" +VIAddVersionKey "LegalCopyright" "(C)2004,2005" +!ifdef DEBUG +VIAddVersionKey "PrivateBuild" "Checked/Debug" +!endif ; End DEBUG + + +;-------------------------------- +;Configuration + + ;General + SetCompressor lzma +!ifndef DEBUG + OutFile "MITKerberosForWindows.exe" +!else + OutFile "MITKerberosForWindows-DEBUG.exe" +!endif + SilentInstall normal + ShowInstDetails show + XPStyle on + !define MUI_ICON "kfw.ico" + !define MUI_UNICON "kfw.ico" + !define KFW_COMPANY_NAME "Massachusetts Institute of Technology" + !define KFW_PRODUCT_NAME "${PROGRAM_NAME}" + !define KFW_REGKEY_ROOT "Software\MIT\Kerberos\" + CRCCheck force + !define REPLACEDLL_NOREGISTER + + ;Folder selection page + InstallDir "$PROGRAMFILES\MIT\Kerberos" ; Install to shorter path + + ;Remember install folder + InstallDirRegKey HKLM "${KFW_REGKEY_ROOT}" "" + + ;Remember the installer language + !define MUI_LANGDLL_REGISTRY_ROOT "HKLM" + !define MUI_LANGDLL_REGISTRY_KEY "${KFW_REGKEY_ROOT}" + !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" + + ;Where are the files? + !define KFW_BIN_DIR "${KFW_TARGETDIR}\bin\i386" + !define KFW_DOC_DIR "${KFW_TARGETDIR}\doc" + !define KFW_INC_DIR "${KFW_TARGETDIR}\inc" + !define KFW_LIB_DIR "${KFW_TARGETDIR}\lib\i386" + !define KFW_INSTALL_DIR "${KFW_TARGETDIR}\install" + !define SYSTEMDIR "$%SystemRoot%\System32" + + +;-------------------------------- +;Modern UI Configuration + + !define MUI_LICENSEPAGE + !define MUI_CUSTOMPAGECOMMANDS + !define MUI_WELCOMEPAGE + !define MUI_COMPONENTSPAGE + !define MUI_COMPONENTSPAGE_SMALLDESC + !define MUI_DIRECTORYPAGE + + !define MUI_ABORTWARNING + !define MUI_FINISHPAGE + + !define MUI_UNINSTALLER + !define MUI_UNCONFIRMPAGE + + + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_LICENSE "Licenses.rtf" + !insertmacro MUI_PAGE_COMPONENTS + !insertmacro MUI_PAGE_DIRECTORY + Page custom KFWPageGetConfigFiles + Page custom KFWPageGetStartupConfig + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Language Strings + + ;Descriptions + LangString DESC_SecCopyUI ${LANG_ENGLISH} "${PROGRAM_NAME}: English" + + LangString DESC_secClient ${LANG_ENGLISH} "Client: Allows you to utilize MIT Kerberos from your Windows PC." + + LangString DESC_secDebug ${LANG_ENGLISH} "Debug Symbols: Used for debugging problems with MIT Kerberos for Windows" + + LangString DESC_secSDK ${LANG_ENGLISH} "SDK: Allows you to build MIT Kerberos aware applications." + + LangString DESC_secDocs ${LANG_ENGLISH} "Documentation: Release Notes and User Manuals." + +; Popup error messages + LangString RealmNameError ${LANG_ENGLISH} "You must specify a realm name for your client to use." + + LangString ConfigFileError ${LANG_ENGLISH} "You must specify a valid configuration file location from which files can be copied during the install" + + LangString URLError ${LANG_ENGLISH} "You must specify a URL if you choose the option to download the config files." + +; Upgrade/re-install strings + LangString UPGRADE_CLIENT ${LANG_ENGLISH} "Upgrade Kerberos Client" + LangString REINSTALL_CLIENT ${LANG_ENGLISH} "Re-install Kerberos Client" + LangString DOWNGRADE_CLIENT ${LANG_ENGLISH} "Downgrade Kerberos Client" + + LangString UPGRADE_SDK ${LANG_ENGLISH} "Upgrade Kerberos SDK" + LangString REINSTALL_SDK ${LANG_ENGLISH} "Re-install Kerberos SDK" + LangString DOWNGRADE_SDK ${LANG_ENGLISH} "Downgrade Kerberos SDK" + + LangString UPGRADE_DOCS ${LANG_ENGLISH} "Upgrade Kerberos Documentation" + LangString REINSTALL_DOCS ${LANG_ENGLISH} "Re-install Kerberos Documentation" + LangString DOWNGRADE_DOCS ${LANG_ENGLISH} "Downgrade Kerberos Documentation" + + ReserveFile "${KFW_CONFIG_DIR}\krb.con" + ReserveFile "${KFW_CONFIG_DIR}\krbrealm.con" + ReserveFile "${KFW_CONFIG_DIR}\krb5.ini" + !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS ;InstallOptions plug-in + !insertmacro MUI_RESERVEFILE_LANGDLL ;Language selection dialog + +;-------------------------------- +;Reserve Files + + ;Things that need to be extracted on first (keep these lines before any File command!) + ;Only useful for BZIP2 compression + !insertmacro MUI_RESERVEFILE_LANGDLL + +;-------------------------------- +; Load Macros +!include "utils.nsi" + +;-------------------------------- +;Installer Sections + +;---------------------- +; Kerberos for Windows CLIENT +Section "KfW Client" secClient + + SetShellVarContext all + ; Stop any running services or we can't replace the files + ; Stop the running processes + GetTempFileName $R0 + File /oname=$R0 "Killer.exe" + nsExec::Exec '$R0 netidmgr.exe' + nsExec::Exec '$R0 leash32.exe' + nsExec::Exec '$R0 krbcc32s.exe' + nsExec::Exec '$R0 k95.exe' + nsExec::Exec '$R0 k95g.exe' + nsExec::Exec '$R0 krb5.exe' + nsExec::Exec '$R0 gss.exe' + nsExec::Exec '$R0 afscreds.exe' + + RMDir /r "$INSTDIR\bin" + + ; Do client components + SetOutPath "$INSTDIR\bin" +!ifdef AKLOG + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\aklog.exe" "$INSTDIR\bin\aklog.exe" "$INSTDIR" +!endif + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\comerr32.dll" "$INSTDIR\bin\comerr32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\gss.exe" "$INSTDIR\bin\gss.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\gss-client.exe" "$INSTDIR\bin\gss-client.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\gss-server.exe" "$INSTDIR\bin\gss-server.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\gssapi32.dll" "$INSTDIR\bin\gssapi32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\k524init.exe" "$INSTDIR\bin\k524init.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\kclnt32.dll" "$INSTDIR\bin\kclnt32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\kdestroy.exe" "$INSTDIR\bin\kdestroy.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\kinit.exe" "$INSTDIR\bin\kinit.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\klist.exe" "$INSTDIR\bin\klist.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\kpasswd.exe" "$INSTDIR\bin\kpasswd.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\kvno.exe" "$INSTDIR\bin\kvno.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krb5_32.dll" "$INSTDIR\bin\krb5_32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\k5sprt32.dll" "$INSTDIR\bin\k5sprt32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krb524.dll" "$INSTDIR\bin\krb524.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krbcc32.dll" "$INSTDIR\bin\krbcc32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krbcc32s.exe" "$INSTDIR\bin\krbcc32s.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krbv4w32.dll" "$INSTDIR\bin\krbv4w32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\netidmgr.exe" "$INSTDIR\bin\netidmgr.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\netidmgr.exe.manifest" "$INSTDIR\bin\netidmgr.exe.manifest" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\netidmgr.chm" "$INSTDIR\bin\netidmgr.chm" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\nidmgr32.dll" "$INSTDIR\bin\nidmgr32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krb4cred.dll" "$INSTDIR\bin\krb4cred.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krb5cred.dll" "$INSTDIR\bin\krb5cred.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krb4cred_en_us.dll" "$INSTDIR\bin\krb4cred_en_us.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\krb5cred_en_us.dll" "$INSTDIR\bin\krb5cred_en_us.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\leashw32.dll" "$INSTDIR\bin\leashw32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\ms2mit.exe" "$INSTDIR\bin\ms2mit.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\mit2ms.exe" "$INSTDIR\bin\mit2ms.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\kcpytkt.exe" "$INSTDIR\bin\kcpytkt.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\kdeltkt.exe" "$INSTDIR\bin\kdeltkt.exe" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\wshelp32.dll" "$INSTDIR\bin\wshelp32.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\xpprof32.dll" "$INSTDIR\bin\xpprof32.dll" "$INSTDIR" + +!ifdef DEBUG +!IFDEF CL_1400 + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr80d.dll" "$INSTDIR\bin\msvcr80d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp80d.dll" "$INSTDIR\bin\msvcp80d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc80d.dll" "$INSTDIR\bin\mfc80d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80CHS.DLL" "$INSTDIR\bin\MFC80CHS.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80CHT.DLL" "$INSTDIR\bin\MFC80CHT.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80DEU.DLL" "$INSTDIR\bin\MFC80DEU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ENU.DLL" "$INSTDIR\bin\MFC80ENU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ESP.DLL" "$INSTDIR\bin\MFC80ESP.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80FRA.DLL" "$INSTDIR\bin\MFC80FRA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ITA.DLL" "$INSTDIR\bin\MFC80ITA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80JPN.DLL" "$INSTDIR\bin\MFC80JPN.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80KOR.DLL" "$INSTDIR\bin\MFC80KOR.DLL" "$INSTDIR" +!ELSE +!IFDEF CL_1310 + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr71d.dll" "$INSTDIR\bin\msvcr71d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp71d.dll" "$INSTDIR\bin\msvcp71d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc71d.dll" "$INSTDIR\bin\mfc71d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71CHS.DLL" "$INSTDIR\bin\MFC71CHS.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71CHT.DLL" "$INSTDIR\bin\MFC71CHT.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71DEU.DLL" "$INSTDIR\bin\MFC71DEU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71ENU.DLL" "$INSTDIR\bin\MFC71ENU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71ESP.DLL" "$INSTDIR\bin\MFC71ESP.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71FRA.DLL" "$INSTDIR\bin\MFC71FRA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71ITA.DLL" "$INSTDIR\bin\MFC71ITA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71JPN.DLL" "$INSTDIR\bin\MFC71JPN.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71KOR.DLL" "$INSTDIR\bin\MFC71KOR.DLL" "$INSTDIR" +!ELSE +!IFDEF CL_1300 + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr70d.dll" "$INSTDIR\bin\msvcr70d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp70d.dll" "$INSTDIR\bin\msvcp70d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc70d.dll" "$INSTDIR\bin\mfc70d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70CHS.DLL" "$INSTDIR\bin\MFC70CHS.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70CHT.DLL" "$INSTDIR\bin\MFC70CHT.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70DEU.DLL" "$INSTDIR\bin\MFC70DEU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70ENU.DLL" "$INSTDIR\bin\MFC70ENU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70ESP.DLL" "$INSTDIR\bin\MFC70ESP.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70FRA.DLL" "$INSTDIR\bin\MFC70FRA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70ITA.DLL" "$INSTDIR\bin\MFC70ITA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70JPN.DLL" "$INSTDIR\bin\MFC70JPN.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70KOR.DLL" "$INSTDIR\bin\MFC70KOR.DLL" "$INSTDIR" +!ELSE + !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc42d.dll" "$INSTDIR\bin\mfc42d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp60d.dll" "$INSTDIR\bin\msvcp60d.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcrtd.dll" "$INSTDIR\bin\msvcrtd.dll" "$INSTDIR" +!ENDIF +!ENDIF +!ENDIF +!ELSE +!IFDEF CL_1400 + !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc80.dll" "$INSTDIR\bin\mfc80.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr80.dll" "$INSTDIR\bin\msvcr80.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp80.dll" "$INSTDIR\bin\msvcp80.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80CHS.DLL" "$INSTDIR\bin\MFC80CHS.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80CHT.DLL" "$INSTDIR\bin\MFC80CHT.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80DEU.DLL" "$INSTDIR\bin\MFC80DEU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ENU.DLL" "$INSTDIR\bin\MFC80ENU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ESP.DLL" "$INSTDIR\bin\MFC80ESP.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80FRA.DLL" "$INSTDIR\bin\MFC80FRA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80ITA.DLL" "$INSTDIR\bin\MFC80ITA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80JPN.DLL" "$INSTDIR\bin\MFC80JPN.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC80KOR.DLL" "$INSTDIR\bin\MFC80KOR.DLL" "$INSTDIR" +!ELSE +!IFDEF CL_1310 + !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc71.dll" "$INSTDIR\bin\mfc71.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr71.dll" "$INSTDIR\bin\msvcr71.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp71.dll" "$INSTDIR\bin\msvcp71.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71CHS.DLL" "$INSTDIR\bin\MFC71CHS.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71CHT.DLL" "$INSTDIR\bin\MFC71CHT.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71DEU.DLL" "$INSTDIR\bin\MFC71DEU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71ENU.DLL" "$INSTDIR\bin\MFC71ENU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71ESP.DLL" "$INSTDIR\bin\MFC71ESP.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71FRA.DLL" "$INSTDIR\bin\MFC71FRA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71ITA.DLL" "$INSTDIR\bin\MFC71ITA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71JPN.DLL" "$INSTDIR\bin\MFC71JPN.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC71KOR.DLL" "$INSTDIR\bin\MFC71KOR.DLL" "$INSTDIR" +!ELSE +!IFDEF CL_1300 + !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc70.dll" "$INSTDIR\bin\mfc70.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcr70.dll" "$INSTDIR\bin\msvcr70.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp70.dll" "$INSTDIR\bin\msvcp70.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70CHS.DLL" "$INSTDIR\bin\MFC70CHS.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70CHT.DLL" "$INSTDIR\bin\MFC70CHT.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70DEU.DLL" "$INSTDIR\bin\MFC70DEU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70ENU.DLL" "$INSTDIR\bin\MFC70ENU.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70ESP.DLL" "$INSTDIR\bin\MFC70ESP.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70FRA.DLL" "$INSTDIR\bin\MFC70FRA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70ITA.DLL" "$INSTDIR\bin\MFC70ITA.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70JPN.DLL" "$INSTDIR\bin\MFC70JPN.DLL" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\MFC70KOR.DLL" "$INSTDIR\bin\MFC70KOR.DLL" "$INSTDIR" +!ELSE + !insertmacro ReplaceDLL "${SYSTEMDIR}\mfc42.dll" "$INSTDIR\bin\mfc42.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcp60.dll" "$INSTDIR\bin\msvcp60.dll" "$INSTDIR" + !insertmacro ReplaceDLL "${SYSTEMDIR}\msvcrt.dll" "$INSTDIR\bin\msvcrt.dll" "$INSTDIR" +!ENDIF +!ENDIF +!ENDIF +!ENDIF + !insertmacro ReplaceDLL "${SYSTEMDIR}\psapi.dll" "$INSTDIR\bin\psapi.dll" "$INSTDIR" + + ; Do WINDOWSDIR components + ;SetOutPath "$WINDOWSDIR" +!ifdef DEBUG +!endif + + ; Do Windows SYSDIR (Control panel) + SetOutPath "$SYSDIR" + !insertmacro ReplaceDLL "${KFW_BIN_DIR}\kfwlogon.dll" "$SYSDIR\kfwlogon.dll" "$INSTDIR" + File "${KFW_BIN_DIR}\kfwcpcc.exe" + + ; Get Kerberos config files + Call kfw.GetConfigFiles + + Call KFWCommon.Install + + ; KfW Reg entries + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "VersionString" ${KFW_VERSION} + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "Title" "KfW" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "Description" "${PROGRAM_NAME}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "PathName" "$INSTDIR" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "Software Type" "Authentication" + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "MajorVersion" ${KFW_MAJORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "MinorVersion" ${KFW_MINORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "PatchLevel" ${KFW_PATCHLEVEL} + + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "VersionString" ${KFW_VERSION} + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "Title" "KfW" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "Description" "${PROGRAM_NAME}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "PathName" "$INSTDIR" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "Software Type" "Authentication" + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "MajorVersion" ${KFW_MAJORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "MinorVersion" ${KFW_MINORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "PatchLevel" ${KFW_PATCHLEVEL} + + ; Daemon entries + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\MIT Kerberos" "" "" + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" "ProviderPath" "$SYSDIR\kfwlogon.dll" + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" "AuthentProviderPath" "$SYSDIR\kfwlogon.dll" + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" "Class" 2 + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" "VerboseLogging" 10 + + ; Must also add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\HwOrder + ; and HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order + ; to also include the service name. + Call AddProvider + ReadINIStr $R0 $1 "Field 7" "State" + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" "Name" "MIT Kerberos" + + ; WinLogon Event Notification + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\MIT_KFW" "Asynchronous" 0 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\MIT_KFW" "Impersonate" 0 + WriteRegStr HKLM "Software\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\MIT_KFW" "DLLName" "kfwlogon.dll" + WriteRegStr HKLM "Software\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\MIT_KFW" "Logon" "KFW_Logon_Event" + + ;Write start menu entries + CreateDirectory "$SMPROGRAMS\${PROGRAM_NAME}" + SetOutPath "$INSTDIR\bin" + CreateShortCut "$SMPROGRAMS\${PROGRAM_NAME}\Uninstall ${PROGRAM_NAME}.lnk" "$INSTDIR\Uninstall.exe" + + ReadINIStr $R0 $1 "Field 2" "State" ; startup + + CreateShortCut "$SMPROGRAMS\${PROGRAM_NAME}\Network Identity Manager.lnk" "$INSTDIR\bin\netidmgr.exe" "" "$INSTDIR\bin\netidmgr.exe" + +startshort: + StrCmp $R0 "0" nostart + CreateShortCut "$SMSTARTUP\Network Identity Manager.lnk" "$INSTDIR\bin\netidmgr.exe" "" "$INSTDIR\bin\netidmgr.exe" 0 SW_SHOWMINIMIZED + goto checkconflicts + +nostart: + Delete "$SMSTARTUP\Network Identity Manager.lnk" + +checkconflicts: + Call GetSystemPath + Push "krb5_32.dll" + Call SearchPath + Pop $R0 + StrCmp $R0 "" addpath + + Push $R0 + Call GetParent + Pop $R0 + StrCmp $R0 "$INSTDIR\bin" addpath + MessageBox MB_OK|MB_ICONINFORMATION|MB_TOPMOST "A previous installation of MIT Kerberos for Windows binaries has been found in folder $R0. This may interfere with the use of the current installation." + +addpath: + ; Add kfw bin to path + Push "$INSTDIR\bin" + Call AddToSystemPath + + Call GetWindowsVersion + Pop $R0 + StrCmp $R0 "2003" addAllowTgtKey + StrCmp $R0 "2000" addAllowTgtKey + StrCmp $R0 "XP" addAllowTgtKey + goto skipAllowTgtKey + +addAllowTgtKey: + ReadRegDWORD $R0 HKLM "SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters" "AllowTGTSessionKey" + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "AllowTGTSessionKeyBackup" $R0 + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters" "AllowTGTSessionKey" "1" + ReadRegDWORD $R0 HKLM "SYSTEM\CurrentControlSet\Control\Lsa\Kerberos" "AllowTGTSessionKey" + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "AllowTGTSessionKeyBackup2" $R0 + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\Lsa\Kerberos" "AllowTGTSessionKey" "1" +skipAllowTgtKey: + + ; The following are keys added for Terminal Server compatibility + ; http://support.microsoft.com/default.aspx?scid=kb;EN-US;186499 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\netidmgr" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kinit" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\klist" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kdestroy" "Flags" 0x408 +!ifdef AKLOG + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\aklog" "Flags" 0x408 +!endif + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss-client" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss-server" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\k524init" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kpasswd" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kvno" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\ms2mit" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\mit2ms" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\mit2ms" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kcpytkt" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kdeltkt" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\k95" "Flags" 0x408 + WriteRegDWORD HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\k95g" "Flags" 0x408 + +SectionEnd + +Section "Debug Symbols" secDebug + + SetOutPath "$INSTDIR\bin" +!ifdef AKLOG + File "${KFW_BIN_DIR}\aklog.pdb" +!endif + File "${KFW_BIN_DIR}\comerr32.pdb" + File "${KFW_BIN_DIR}\gss.pdb" + File "${KFW_BIN_DIR}\gss-client.pdb" + File "${KFW_BIN_DIR}\gss-server.pdb" + File "${KFW_BIN_DIR}\gssapi32.pdb" + File "${KFW_BIN_DIR}\k524init.pdb" + File "${KFW_BIN_DIR}\kclnt32.pdb" + File "${KFW_BIN_DIR}\kdestroy.pdb" + File "${KFW_BIN_DIR}\kinit.pdb" + File "${KFW_BIN_DIR}\klist.pdb" + File "${KFW_BIN_DIR}\kpasswd.pdb" + File "${KFW_BIN_DIR}\kvno.pdb" + File "${KFW_BIN_DIR}\krb5_32.pdb" + File "${KFW_BIN_DIR}\k5sprt32.pdb" + File "${KFW_BIN_DIR}\krb524.pdb" + File "${KFW_BIN_DIR}\krbcc32.pdb" + File "${KFW_BIN_DIR}\krbcc32s.pdb" + File "${KFW_BIN_DIR}\krbv4w32.pdb" + File "${KFW_BIN_DIR}\leashw32.pdb" + File "${KFW_BIN_DIR}\netidmgr.pdb" + File "${KFW_BIN_DIR}\nidmgr32.pdb" + File "${KFW_BIN_DIR}\krb4cred.pdb" + File "${KFW_BIN_DIR}\krb5cred.pdb" + File "${KFW_BIN_DIR}\ms2mit.pdb" + File "${KFW_BIN_DIR}\mit2ms.pdb" + File "${KFW_BIN_DIR}\kcpytkt.pdb" + File "${KFW_BIN_DIR}\kdeltkt.pdb" + File "${KFW_BIN_DIR}\wshelp32.pdb" + File "${KFW_BIN_DIR}\xpprof32.pdb" + +!IFDEF DEBUG +!IFDEF CL_1400 + File "${SYSTEMDIR}\msvcr80d.pdb" + File "${SYSTEMDIR}\msvcp80d.pdb" + File "${SYSTEMDIR}\mfc80d.pdb" +!ELSE +!IFDEF CL_1310 + File "${SYSTEMDIR}\msvcr71d.pdb" + File "${SYSTEMDIR}\msvcp71d.pdb" + File "${SYSTEMDIR}\mfc71d.pdb" +!ELSE +!IFDEF CL_1300 + File "${SYSTEMDIR}\msvcr70d.pdb" + File "${SYSTEMDIR}\msvcp70d.pdb" + File "${SYSTEMDIR}\mfc70d.pdb" +!ELSE + File "${SYSTEMDIR}\mfc42d.pdb" + File "${SYSTEMDIR}\msvcp60d.pdb" + File "${SYSTEMDIR}\msvcrtd.pdb" +!ENDIF +!ENDIF +!ENDIF +!ENDIF + + SetOutPath "$SYSDIR" + File "${KFW_BIN_DIR}\kfwlogon.pdb" + File "${KFW_BIN_DIR}\kfwcpcc.pdb" + +SectionEnd + +;---------------------- +; Kerberos for Windows SDK +Section "KfW SDK" secSDK + + RMDir /r "$INSTDIR\inc" + RMDir /r "$INSTDIR\lib" + RMDir /r "$INSTDIR\install" + + SetOutPath "$INSTDIR\doc" + File /r "${KFW_DOC_DIR}\netiddev.chm" + + SetOutPath "$INSTDIR\inc\kclient" + File /r "${KFW_INC_DIR}\kclient\*" + + SetOutPath "$INSTDIR\inc\krb4" + File /r "${KFW_INC_DIR}\krb4\*" + + SetOutPath "$INSTDIR\inc\krb5" + File /r "${KFW_INC_DIR}\krb5\*" + + SetOutPath "$INSTDIR\inc\krbcc" + File /r "${KFW_INC_DIR}\krbcc\*" + + SetOutPath "$INSTDIR\inc\leash" + File /r "${KFW_INC_DIR}\leash\*" + + SetOutPath "$INSTDIR\inc\loadfuncs" + File /r "${KFW_INC_DIR}\loadfuncs\*" + + SetOutPath "$INSTDIR\inc\netidmgr" + File /r "${KFW_INC_DIR}\netidmgr\*" + + SetOutPath "$INSTDIR\inc\wshelper" + File /r "${KFW_INC_DIR}\wshelper\*" + + SetOutPath "$INSTDIR\lib\i386" + File /r "${KFW_LIB_DIR}\*" + + SetOutPath "$INSTDIR\install" + File /r "${KFW_INSTALL_DIR}\*" + + CreateShortCut "$SMPROGRAMS\${PROGRAM_NAME}\Network Identity Developer Documentation.lnk" "$INSTDIR\bin\netiddev.chm" + + Call KFWCommon.Install + + ; KfW Reg entries + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "VersionString" ${KFW_VERSION} + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "Title" "KfW" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "Description" "${PROGRAM_NAME}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "PathName" "$INSTDIR" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "Software Type" "Authentication" + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "MajorVersion" ${KFW_MAJORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "MinorVersion" ${KFW_MINORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "PatchLevel" ${KFW_PATCHLEVEL} + + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "VersionString" ${KFW_VERSION} + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "Title" "KfW" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "Description" "${PROGRAM_NAME}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "PathName" "$INSTDIR" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "Software Type" "Authentication" + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "MajorVersion" ${KFW_MAJORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "MinorVersion" ${KFW_MINORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "PatchLevel" ${KFW_PATCHLEVEL} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\SDK\${KFW_VERSION}" "PatchLevel" ${KFW_PATCHLEVEL} + +SectionEnd + +;---------------------- +; Kerberos for Windows Documentation +Section "KfW Documentation" secDocs + + RMDir /r "$INSTDIR\doc" + + SetOutPath "$INSTDIR\doc" + File "${KFW_DOC_DIR}\relnotes.html" + File "${KFW_DOC_DIR}\netidmgr_userdoc.pdf" + + Call KFWCommon.Install + + ; KfW Reg entries + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "VersionString" ${KFW_VERSION} + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "Title" "KfW" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "Description" "${PROGRAM_NAME}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "PathName" "$INSTDIR" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "Software Type" "Authentication" + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "MajorVersion" ${KFW_MAJORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "MinorVersion" ${KFW_MINORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "PatchLevel" ${KFW_PATCHLEVEL} + + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "VersionString" ${KFW_VERSION} + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "Title" "KfW" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "Description" "${PROGRAM_NAME}" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "PathName" "$INSTDIR" + WriteRegStr HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "Software Type" "Authentication" + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "MajorVersion" ${KFW_MAJORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "MinorVersion" ${KFW_MINORVERSION} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "PatchLevel" ${KFW_PATCHLEVEL} + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\Documentation\${KFW_VERSION}" "PatchLevel" ${KFW_PATCHLEVEL} + + ;Write start menu entries + CreateDirectory "$SMPROGRAMS\${PROGRAM_NAME}" + SetOutPath "$INSTDIR\doc" + CreateShortCut "$SMPROGRAMS\${PROGRAM_NAME}\Release Notes.lnk" "$INSTDIR\doc\relnotes.html" + CreateShortCut "$SMPROGRAMS\${PROGRAM_NAME}\Network Identity Manager User Documentation.lnk" "$INSTDIR\doc\netidmgr_userdoc.pdf" + CreateShortCut "$SMPROGRAMS\${PROGRAM_NAME}\Network Identity Manager Documentation.lnk" "$INSTDIR\bin\netidmgr.chm" +SectionEnd + +;Display the Finish header +;Insert this macro after the sections if you are not using a finish page +;!insertmacro MUI_SECTIONS_FINISHHEADER + +;-------------------------------- +;Installer Functions + +Function .onInit + !insertmacro MUI_LANGDLL_DISPLAY + + ; Set the default install options + Push $0 + + Call IsUserAdmin + Pop $R0 + StrCmp $R0 "true" checkVer + + MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST "You must be an administrator of this machine to install this software." + Abort + +checkVer: + ; Check Version of Windows. Do not install onto Windows 95 + Call GetWindowsVersion + Pop $R0 + StrCmp $R0 "95" wrongVersion + StrCmp $R0 "98" wrongVersion + StrCmp $R0 "ME" wrongVersion + StrCmp $R0 "NT 4.0" wrongVersion + goto checkIPHLPAPI + +wrongVersion: + MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST "MIT ${PROGRAM_NAME} requires Microsoft Windows 2000 or higher." + Abort + +checkIPHLPAPI: + ClearErrors + ReadEnvStr $R0 "WinDir" + GetDLLVersion "$R0\System32\iphlpapi.dll" $R1 $R2 + IfErrors +1 +3 + GetDLLVersion "$R0\System\iphlpapi.dll" $R1 $R2 + IfErrors iphlperror + IntOp $R3 $R2 / 0x00010000 + IntCmpU $R3 1952 iphlpwarning checkprevious checkprevious + +iphlperror: + MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST "MIT ${PROGRAM_NAME} requires Internet Explorer version 5.01 or higher. IPHLPAPI.DLL is missing." + Abort + +iphlpwarning: + MessageBox MB_OK|MB_ICONINFORMATION|MB_TOPMOST "IPHLPAPI.DLL must be upgraded. Please install Internet Explorer 5.01 or higher." + +checkprevious: + ClearErrors + ReadRegStr $R0 HKLM \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" \ + "DisplayVersion" + IfErrors testWIX + StrCmp $R0 "${KFW_VERSION}" contInstall + + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ + "${PROGRAM_NAME} is already installed. $\n$\nClick `OK` to remove the \ + previous version or `Cancel` to cancel this upgrade or downgrade." \ + IDOK uninstNSIS + Abort + +;Run the uninstaller +uninstNSIS: + ReadRegStr $R0 HKLM \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" \ + "UninstallString" + ClearErrors + ExecWait '$R0 _?=$INSTDIR' ;Do not copy the uninstaller to a temp file + + IfErrors no_remove_uninstaller + ;You can either use Delete /REBOOTOK in the uninstaller or add some code + ;here to remove the uninstaller. Use a registry key to check + ;whether the user has chosen to uninstall. If you are using an uninstaller + ;components page, make sure all sections are uninstalled. + + Push $R1 + Call RestartRequired + Pop $R1 + StrCmp $R1 "1" Restart DoNotRestart + +testWIX: + ClearErrors + ReadRegStr $R0 HKLM \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\{FD5B1F41-81BB-4BBC-9F7E-4B971660AE1A}" \ + "DisplayVersion" + IfErrors testSWRT + + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ + "${PROGRAM_NAME} is already installed. $\n$\nClick `OK` to remove the \ + previous version or `Cancel` to cancel this installation." \ + IDOK uninstMSI1 + Abort + +;Run the uninstaller +uninstMSI1: + Call GetWindowsVersion + Pop $R0 + StrCmp $R0 "2000" uninstMSI1_2000 + + ClearErrors + ExecWait 'MSIEXEC /x{FD5B1F41-81BB-4BBC-9F7E-4B971660AE1A} /passive /promptrestart' + + IfErrors no_remove_uninstaller + ;You can either use Delete /REBOOTOK in the uninstaller or add some code + ;here to remove the uninstaller. Use a registry key to check + ;whether the user has chosen to uninstall. If you are using an uninstaller + ;components page, make sure all sections are uninstalled. + + Push $R1 + Call RestartRequired + Pop $R1 + StrCmp $R1 "1" Restart DoNotRestart + +uninstMSI1_2000: + ClearErrors + ExecWait 'MSIEXEC /x{FD5B1F41-81BB-4BBC-9F7E-4B971660AE1A}' + + IfErrors no_remove_uninstaller + ;You can either use Delete /REBOOTOK in the uninstaller or add some code + ;here to remove the uninstaller. Use a registry key to check + ;whether the user has chosen to uninstall. If you are using an uninstaller + ;components page, make sure all sections are uninstalled. + + Push $R1 + Call RestartRequired + Pop $R1 + StrCmp $R1 "1" Restart DoNotRestart + +testSWRT: + ClearErrors + ReadRegStr $R0 HKLM \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\{61211594-AAA1-4A98-A299-757326763CC7}" \ + "DisplayVersion" + IfErrors testPismere + + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ + "${PROGRAM_NAME} is already installed. $\n$\nClick `OK` to remove the \ + previous version or `Cancel` to cancel this installation." \ + IDOK uninstMSI2 + Abort + +;Run the uninstaller +uninstMSI2: + Call GetWindowsVersion + Pop $R0 + StrCmp $R0 "2000" uninstMSI2_2000 + + ClearErrors + ExecWait 'MSIEXEC /x{61211594-AAA1-4A98-A299-757326763CC7} /passive /promptrestart' + + IfErrors no_remove_uninstaller + ;You can either use Delete /REBOOTOK in the uninstaller or add some code + ;here to remove the uninstaller. Use a registry key to check + ;whether the user has chosen to uninstall. If you are using an uninstaller + ;components page, make sure all sections are uninstalled. + + Push $R1 + Call RestartRequired + Pop $R1 + StrCmp $R1 "1" Restart DoNotRestart + +uninstMSI2_2000: + ClearErrors + ExecWait 'MSIEXEC /x{61211594-AAA1-4A98-A299-757326763CC7}' + + IfErrors no_remove_uninstaller + ;You can either use Delete /REBOOTOK in the uninstaller or add some code + ;here to remove the uninstaller. Use a registry key to check + ;whether the user has chosen to uninstall. If you are using an uninstaller + ;components page, make sure all sections are uninstalled. + + Push $R1 + Call RestartRequired + Pop $R1 + StrCmp $R1 "1" Restart DoNotRestart + +testPismere: + ClearErrors + ReadRegStr $R0 HKLM \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\{83977767-388D-4DF8-BB08-3BF2401635BD}" \ + "DisplayVersion" + IfErrors contInstall + + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ + "${PROGRAM_NAME} is already installed. $\n$\nClick `OK` to remove the \ + previous version or `Cancel` to cancel this installation." \ + IDOK uninstPismere + Abort + +;Run the uninstaller +uninstPismere: + Call GetWindowsVersion + Pop $R0 + StrCmp $R0 "2000" uninstPismere_2000 + + ClearErrors + ExecWait 'MSIEXEC /x{83977767-388D-4DF8-BB08-3BF2401635BD} /passive /promptrestart' + + IfErrors no_remove_uninstaller + ;You can either use Delete /REBOOTOK in the uninstaller or add some code + ;here to remove the uninstaller. Use a registry key to check + ;whether the user has chosen to uninstall. If you are using an uninstaller + ;components page, make sure all sections are uninstalled. + + Push $R1 + Call RestartRequired + Pop $R1 + StrCmp $R1 "1" Restart DoNotRestart + +uninstPismere_2000: + ClearErrors + ExecWait 'MSIEXEC /x{83977767-388D-4DF8-BB08-3BF2401635BD}' + + IfErrors no_remove_uninstaller + ;You can either use Delete /REBOOTOK in the uninstaller or add some code + ;here to remove the uninstaller. Use a registry key to check + ;whether the user has chosen to uninstall. If you are using an uninstaller + ;components page, make sure all sections are uninstalled. + + Push $R1 + Call RestartRequired + Pop $R1 + StrCmp $R1 "1" Restart DoNotRestart + + +Restart: + MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST "Please reboot and then restart the installer." + Abort + MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST "Abort failed" + +DoNotRestart: +no_remove_uninstaller: + +contInstall: + ; Never install debug symbols unless explicitly selected, except in DEBUG mode +!IFNDEF DEBUG + SectionGetFlags ${secDebug} $0 + IntOp $0 $0 & ${SECTION_OFF} + SectionSetFlags ${secDebug} $0 +!ELSE + SectionGetFlags ${secDebug} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secDebug} $0 +!ENDIF + + ; Our logic should be like this. + ; 1) If no KfW components are installed, we do a clean install with default options. (Client/Docs) + ; 2) If existing modules are installed, we keep them selected + ; 3) If it is an upgrade, we set the text accordingly, else we mark it as a re-install + ; TODO: Downgrade? + Call IsAnyKfWInstalled + Pop $R0 + StrCmp $R0 "0" DefaultOptions + + Call ShouldClientInstall + Pop $R2 + + StrCmp $R2 "0" NoClient + StrCmp $R2 "1" ReinstallClient + StrCmp $R2 "2" UpgradeClient + StrCmp $R2 "3" DowngradeClient + + SectionGetFlags ${secClient} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secClient} $0 + ;# !insertmacro SelectSection ${secClient} + goto skipClient +NoClient: + ;StrCpy $1 ${secClient} ; Gotta remember which section we are at now... + SectionGetFlags ${secClient} $0 + IntOp $0 $0 & ${SECTION_OFF} + SectionSetFlags ${secClient} $0 + goto skipClient +UpgradeClient: + SectionGetFlags ${secClient} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secClient} $0 + SectionSetText ${secClient} $(UPGRADE_CLIENT) + goto skipClient +ReinstallClient: + SectionGetFlags ${secClient} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secClient} $0 + SectionSetText ${secClient} $(REINSTALL_CLIENT) + goto skipClient +DowngradeClient: + SectionGetFlags ${secClient} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secClient} $0 + SectionSetText ${secClient} $(DOWNGRADE_CLIENT) + goto skipClient + + +skipClient: + + Call ShouldSDKInstall + Pop $R2 + StrCmp $R2 "0" NoSDK + StrCmp $R2 "1" ReinstallSDK + StrCmp $R2 "2" UpgradeSDK + StrCmp $R2 "3" DowngradeSDK + + SectionGetFlags ${secSDK} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secSDK} $0 + ;# !insertmacro UnselectSection ${secSDK} + goto skipSDK + +UpgradeSDK: + SectionGetFlags ${secSDK} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secSDK} $0 + SectionSetText ${secSDK} $(UPGRADE_SDK) + goto skipSDK + +ReinstallSDK: + SectionGetFlags ${secSDK} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secSDK} $0 + SectionSetText ${secSDK} $(REINSTALL_SDK) + goto skipSDK + +DowngradeSDK: + SectionGetFlags ${secSDK} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secSDK} $0 + SectionSetText ${secSDK} $(DOWNGRADE_SDK) + goto skipSDK + +NoSDK: + SectionGetFlags ${secSDK} $0 + IntOp $0 $0 & ${SECTION_OFF} + SectionSetFlags ${secSDK} $0 + ;# !insertmacro UnselectSection ${secSDK} + goto skipSDK + +skipSDK: + + Call ShouldDocumentationInstall + Pop $R2 + StrCmp $R2 "0" NoDocumentation + StrCmp $R2 "1" ReinstallDocumentation + StrCmp $R2 "2" UpgradeDocumentation + StrCmp $R2 "3" DowngradeDocumentation + + SectionGetFlags ${secDocs} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secDocs} $0 + ;# !insertmacro UnselectSection ${secDocs} + goto skipDocumentation + +UpgradeDocumentation: + SectionGetFlags ${secDocs} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secDocs} $0 + SectionSetText ${secDocs} $(UPGRADE_DOCS) + goto skipDocumentation + +ReinstallDocumentation: + SectionGetFlags ${secDocs} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secDocs} $0 + SectionSetText ${secDocs} $(REINSTALL_DOCS) + goto skipDocumentation + +DowngradeDocumentation: + SectionGetFlags ${secDocs} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secDocs} $0 + SectionSetText ${secDocs} $(DOWNGRADE_DOCS) + goto skipDocumentation + +NoDocumentation: + SectionGetFlags ${secDocs} $0 + IntOp $0 $0 & ${SECTION_OFF} + SectionSetFlags ${secDocs} $0 + ;# !insertmacro UnselectSection ${secDocs} + goto skipDocumentation + +skipDocumentation: + goto end + +DefaultOptions: + ; Client Selected + SectionGetFlags ${secClient} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secClient} $0 + + ; SDK NOT selected + SectionGetFlags ${secSDK} $0 + IntOp $0 $0 & ${SECTION_OFF} + SectionSetFlags ${secSDK} $0 + + ; Documentation selected + SectionGetFlags ${secDocs} $0 + IntOp $0 $0 | ${SF_SELECTED} + SectionSetFlags ${secDocs} $0 + goto end + +end: + Pop $0 + + Push $R0 + + ; See if we can set a default installation path... + ReadRegStr $R0 HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" "PathName" + StrCmp $R0 "" TrySDK + StrCpy $INSTDIR $R0 + goto Nope + +TrySDK: + ReadRegStr $R0 HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" "PathName" + StrCmp $R0 "" TryDocs + StrCpy $INSTDIR $R0 + goto Nope + +TryDocs: + ReadRegStr $R0 HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" "PathName" + StrCmp $R0 "" TryRoot + StrCpy $INSTDIR $R0 + goto Nope + +TryRoot: + ReadRegStr $R0 HKLM "${KFW_REGKEY_ROOT}" "InstallDir" + StrCmp $R0 "" Nope + StrCpy $INSTDIR $R0 + +Nope: + Pop $R0 + + GetTempFilename $0 + File /oname=$0 KfWConfigPage.ini + GetTempFilename $1 + File /oname=$1 KfWConfigPage2.ini + +FunctionEnd + + +;-------------------------------- +; These are our cleanup functions +Function .onInstFailed +Delete $0 +Delete $1 +FunctionEnd + +Function .onInstSuccess +Delete $0 +Delete $1 +FunctionEnd + + +;-------------------------------- +;Descriptions + + !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${secClient} $(DESC_secClient) + !insertmacro MUI_DESCRIPTION_TEXT ${secSDK} $(DESC_secSDK) + !insertmacro MUI_DESCRIPTION_TEXT ${secDocs} $(DESC_secDocs) + !insertmacro MUI_DESCRIPTION_TEXT ${secDebug} $(DESC_secDebug) + !insertmacro MUI_FUNCTION_DESCRIPTION_END + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" + ; Make sure the user REALLY wants to do this, unless they did a silent uninstall, in which case...let them! + IfSilent StartRemove ; New in v2.0b4 + MessageBox MB_YESNO "Are you sure you want to remove MIT ${PROGRAM_NAME} from this machine?" IDYES StartRemove + abort + +StartRemove: + + SetShellVarContext all + ; Stop the running processes + GetTempFileName $R0 + File /oname=$R0 "Killer.exe" + nsExec::Exec '$R0 netidmgr.exe' + nsExec::Exec '$R0 krbcc32s.exe' + + Push "$INSTDIR\bin" + Call un.RemoveFromSystemPath + + ; Delete documentation + Delete "$INSTDIR\doc\relnotes.html" + Delete "$INSTDIR\doc\netidmgr_userdoc.pdf" + Delete "$INSTDIR\doc\netiddev.chm" + +!ifdef AKLOG + Delete /REBOOTOK "$INSTDIR\bin\aklog.exe" +!endif + Delete /REBOOTOK "$INSTDIR\bin\comerr32.dll" + Delete /REBOOTOK "$INSTDIR\bin\gss.exe" + Delete /REBOOTOK "$INSTDIR\bin\gss-client.exe" + Delete /REBOOTOK "$INSTDIR\bin\gss-server.exe" + Delete /REBOOTOK "$INSTDIR\bin\gssapi32.dll" + Delete /REBOOTOK "$INSTDIR\bin\k524init.exe" + Delete /REBOOTOK "$INSTDIR\bin\kclnt32.dll" + Delete /REBOOTOK "$INSTDIR\bin\kdestroy.exe" + Delete /REBOOTOK "$INSTDIR\bin\kinit.exe" + Delete /REBOOTOK "$INSTDIR\bin\klist.exe" + Delete /REBOOTOK "$INSTDIR\bin\kpasswd.exe" + Delete /REBOOTOK "$INSTDIR\bin\kvno.exe" + Delete /REBOOTOK "$INSTDIR\bin\krb5_32.dll" + Delete /REBOOTOK "$INSTDIR\bin\k5sprt32.dll" + Delete /REBOOTOK "$INSTDIR\bin\krb524.dll" + Delete /REBOOTOK "$INSTDIR\bin\krbcc32.dll" + Delete /REBOOTOK "$INSTDIR\bin\krbcc32s.exe" + Delete /REBOOTOK "$INSTDIR\bin\krbv4w32.dll" + Delete /REBOOTOK "$INSTDIR\bin\netidmgr.exe" + Delete /REBOOTOK "$INSTDIR\bin\netidmgr.chm" + Delete /REBOOTOK "$INSTDIR\bin\nidmgr32.dll" + Delete /REBOOTOK "$INSTDIR\bin\krb4cred.dll" + Delete /REBOOTOK "$INSTDIR\bin\krb5cred.dll" + Delete /REBOOTOK "$INSTDIR\bin\krb4cred_en_us.dll" + Delete /REBOOTOK "$INSTDIR\bin\krb5cred_en_us.dll" + Delete /REBOOTOK "$INSTDIR\bin\leashw32.dll" + Delete /REBOOTOK "$INSTDIR\bin\ms2mit.exe" + Delete /REBOOTOK "$INSTDIR\bin\mit2ms.exe" + Delete /REBOOTOK "$INSTDIR\bin\kcpytkt.exe" + Delete /REBOOTOK "$INSTDIR\bin\kdeltkt.exe" + Delete /REBOOTOK "$INSTDIR\bin\wshelp32.dll" + Delete /REBOOTOK "$INSTDIR\bin\xpprof32.dll" + Delete /REBOOTOK "$SYSDIR\bin\kfwlogon.dll" + Delete /REBOOTOK "$SYSDIR\bin\kfwcpcc.exe" + +!ifdef AKLOG + Delete /REBOOTOK "$INSTDIR\bin\aklog.pdb" +!endif + Delete /REBOOTOK "$INSTDIR\bin\comerr32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\gss.pdb" + Delete /REBOOTOK "$INSTDIR\bin\gss-client.pdb" + Delete /REBOOTOK "$INSTDIR\bin\gss-server.pdb" + Delete /REBOOTOK "$INSTDIR\bin\gssapi32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\k524init.pdb" + Delete /REBOOTOK "$INSTDIR\bin\kclnt32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\kdestroy.pdb" + Delete /REBOOTOK "$INSTDIR\bin\kinit.pdb" + Delete /REBOOTOK "$INSTDIR\bin\klist.pdb" + Delete /REBOOTOK "$INSTDIR\bin\kpasswd.pdb" + Delete /REBOOTOK "$INSTDIR\bin\kvno.pdb" + Delete /REBOOTOK "$INSTDIR\bin\krb5_32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\k5sprt32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\krb524.pdb" + Delete /REBOOTOK "$INSTDIR\bin\krbcc32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\krbcc32s.pdb" + Delete /REBOOTOK "$INSTDIR\bin\krbv4w32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\netidmgr.pdb" + Delete /REBOOTOK "$INSTDIR\bin\nidmgr32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\krb4cred.pdb" + Delete /REBOOTOK "$INSTDIR\bin\krb5cred.pdb" + Delete /REBOOTOK "$INSTDIR\bin\leashw32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\ms2mit.pdb" + Delete /REBOOTOK "$INSTDIR\bin\mit2ms.pdb" + Delete /REBOOTOK "$INSTDIR\bin\kcpytkt.pdb" + Delete /REBOOTOK "$INSTDIR\bin\kdeltkt.pdb" + Delete /REBOOTOK "$INSTDIR\bin\wshelp32.pdb" + Delete /REBOOTOK "$INSTDIR\bin\xpprof32.pdb" + Delete /REBOOTOK "$SYSDIR\bin\kfwlogon.pdb" + Delete /REBOOTOK "$SYSDIR\bin\kfwcpcc.pdb" + +!IFDEF DEBUG +!IFDEF CL_1400 + Delete /REBOOTOK "$INSTDIR\bin\msvcr80d.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcr80d.pdb" + Delete /REBOOTOK "$INSTDIR\bin\msvcp80d.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcp80d.pdb" + Delete /REBOOTOK "$INSTDIR\bin\mfc80d.dll" + Delete /REBOOTOK "$INSTDIR\bin\mfc80d.pdb" +!ELSE +!IFDEF CL_1310 + Delete /REBOOTOK "$INSTDIR\bin\msvcr71d.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcr71d.pdb" + Delete /REBOOTOK "$INSTDIR\bin\msvcp71d.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcp71d.pdb" + Delete /REBOOTOK "$INSTDIR\bin\mfc71d.dll" + Delete /REBOOTOK "$INSTDIR\bin\mfc71d.pdb" +!ELSE +!IFDEF CL_1300 + Delete /REBOOTOK "$INSTDIR\bin\msvcr70d.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcr70d.pdb" + Delete /REBOOTOK "$INSTDIR\bin\msvcp70d.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcp70d.pdb" + Delete /REBOOTOK "$INSTDIR\bin\mfc70d.dll" + Delete /REBOOTOK "$INSTDIR\bin\mfc70d.pdb" +!ELSE + Delete /REBOOTOK "$INSTDIR\bin\mfc42d.dll" + Delete /REBOOTOK "$INSTDIR\bin\mfc42d.pdb" + Delete /REBOOTOK "$INSTDIR\bin\msvcp60d.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcp60d.pdb" + Delete /REBOOTOK "$INSTDIR\bin\msvcrtd.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcrtd.pdb" +!ENDIF +!ENDIF +!ENDIF +!ELSE +!IFDEF CL_1400 + Delete /REBOOTOK "$INSTDIR\bin\mfc80.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcr80.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcp80.dll" + Delete /REBOOTOK "$INSTDIR\bin\MFC80CHS.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC80CHT.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC80DEU.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC80ENU.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC80ESP.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC80FRA.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC80ITA.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC80JPN.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC80KOR.DLL" +!ELSE +!IFDEF CL_1310 + Delete /REBOOTOK "$INSTDIR\bin\mfc71.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcr71.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcp71.dll" + Delete /REBOOTOK "$INSTDIR\bin\MFC71CHS.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC71CHT.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC71DEU.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC71ENU.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC71ESP.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC71FRA.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC71ITA.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC71JPN.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC71KOR.DLL" +!ELSE +!IFDEF CL_1300 + Delete /REBOOTOK "$INSTDIR\bin\mfc70.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcr70.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcp70.dll" + Delete /REBOOTOK "$INSTDIR\bin\MFC70CHS.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC70CHT.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC70DEU.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC70ENU.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC70ESP.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC70FRA.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC70ITA.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC70JPN.DLL" + Delete /REBOOTOK "$INSTDIR\bin\MFC70KOR.DLL" +!ELSE + Delete /REBOOTOK "$INSTDIR\bin\mfc42.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcp60.dll" + Delete /REBOOTOK "$INSTDIR\bin\msvcrt.dll" +!ENDIF +!ENDIF +!ENDIF +!ENDIF + Delete /REBOOTOK "$INSTDIR\bin\psapi.dll" + + RMDir "$INSTDIR\bin" + RmDir "$INSTDIR\doc" + RmDir "$INSTDIR\lib" + RmDir "$INSTDIR\inc" + RmDir "$INSTDIR\install" + RMDir "$INSTDIR" + + Delete "$SMPROGRAMS\${PROGRAM_NAME}\Uninstall ${PROGRAM_NAME}.lnk" + Delete "$SMPROGRAMS\${PROGRAM_NAME}\Network Identity Manager.lnk" + Delete "$SMPROGRAMS\${PROGRAM_NAME}\Release Notes.lnk" + Delete "$SMPROGRAMS\${PROGRAM_NAME}\Network Identity Manager User Documentation.lnk" + Delete "$SMPROGRAMS\${PROGRAM_NAME}\Network Identity Developer Documentation.lnk" + RmDir "$SMPROGRAMS\${PROGRAM_NAME}" + Delete "$SMSTARTUP\Network Identity Manager.lnk" + + IfSilent SkipAsk +; IfFileExists "$WINDIR\krb5.ini" CellExists SkipDelAsk +; RealmExists: + MessageBox MB_YESNO "Would you like to keep your configuration files?" IDYES SkipDel + SkipAsk: + Delete "$WINDIR\krb5.ini" + Delete "$WINDIR\krb.con" + Delete "$WINDIR\krbrealm.con" + + SkipDel: + Delete "$INSTDIR\Uninstall.exe" + + ; Restore previous value of AllowTGTSessionKey + ReadRegDWORD $R0 HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "AllowTGTSessionKeyBackup" + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters" "AllowTGTSessionKey" $R0 + ReadRegDWORD $R0 HKLM "${KFW_REGKEY_ROOT}\Client\${KFW_VERSION}" "AllowTGTSessionKeyBackup2" + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Control\Lsa\Kerberos" "AllowTGTSessionKey" $R0 + + ; The following are keys added for Terminal Server compatibility + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\netidmgr" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kinit" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\klist" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kdestroy" +!ifdef AKLOG + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\aklog" +!endif + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss-client" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss-server" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\k524init" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kpasswd" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kvno" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\ms2mit" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\mit2ms" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kcpytkt" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kdeltkt" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\k95" + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\k95g" + + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\Client\CurrentVersion" + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\Client" + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\Documentation\CurrentVersion" + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\Documentation" + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\SDK\CurrentVersion" + DeleteRegKey HKLM "${KFW_REGKEY_ROOT}\SDK" + DeleteRegKey /ifempty HKLM "${KFW_REGKEY_ROOT}" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" + + ; WinLogon Event Notification + DeleteRegKey HKLM "Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify\MIT_KFW" + DeleteRegKey HKLM "SYSTEM\CurrentControlSet\Services\MIT Kerberos" + + RMDir "$INSTDIR" + +SectionEnd + +;-------------------------------- +;Uninstaller Functions + +Function un.onInit + + ;Get language from registry + ReadRegStr $LANGUAGE ${MUI_LANGDLL_REGISTRY_ROOT} "${MUI_LANGDLL_REGISTRY_KEY}" "${MUI_LANGDLL_REGISTRY_VALUENAME}" + +FunctionEnd + +Function un.onUninstSuccess + + MessageBox MB_OK "Please reboot your machine to complete uninstallation of the software" + +FunctionEnd + +;------------------------------ +; Get the Configurations files from the Internet + +Function kfw.GetConfigFiles + +;Check if we should download Config Files +ReadINIStr $R0 $0 "Field 4" "State" +StrCmp $R0 "1" DoDownload + +;Do nothing if we're keeping the existing file +ReadINIStr $R0 $0 "Field 2" "State" +StrCmp $R0 "1" done + +ReadINIStr $R0 $0 "Field 3" "State" +StrCmp $R0 "1" UsePackaged + +; If none of these, grab file from other location +goto CheckOther + +DoDownload: + ReadINIStr $R0 $0 "Field 5" "State" + NSISdl::download "$R0/krb5.ini" "$WINDIR\krb5.ini" + NSISdl::download "$R0/krb.con" "$WINDIR\krb.con" + NSISdl::download "$R0/krbrealm.con" "$WINDIR\krbrealm.con" + Pop $R0 ;Get the return value + StrCmp $R0 "success" done + MessageBox MB_OK|MB_ICONSTOP "Download failed: $R0" + goto done + +UsePackaged: + SetOutPath "$WINDIR" + File "${KFW_CONFIG_DIR}\krb5.ini" + File "${KFW_CONFIG_DIR}\krb.con" + File "${KFW_CONFIG_DIR}\krbrealm.con" + goto done + +CheckOther: + ReadINIStr $R0 $0 "Field 7" "State" + StrCmp $R0 "" done + CopyFiles "$R0\krb5.ini" "$WINDIR\krb5.ini" + CopyFiles "$R0\krb.con" "$WINDIR\krb.con" + CopyFiles "$R0\krbrealm.con" "$WINDIR\krbrealm.con" + +done: + +FunctionEnd + + + +;------------------------------- +;Do the page to get the Config files + +Function KFWPageGetConfigFiles + ; Skip this page if we are not installing the client + SectionGetFlags ${secClient} $R0 + IntOp $R0 $R0 & ${SF_SELECTED} + StrCmp $R0 "0" Skip + + ; Set the install options here + +startOver: + WriteINIStr $0 "Field 2" "Flags" "DISABLED" + WriteINIStr $0 "Field 3" "State" "1" + WriteINIStr $0 "Field 4" "State" "0" + WriteINIStr $0 "Field 6" "State" "0" + WriteINIStr $0 "Field 3" "Text" "Use packaged configuration files for the ${SAMPLE_CONFIG_REALM} realm." + WriteINIStr $0 "Field 5" "State" "${HTTP_CONFIG_URL}" + + ; If there is an existing krb5.ini file, allow the user to choose it and make it default + IfFileExists "$WINDIR\krb5.ini" +1 notpresent + WriteINIStr $0 "Field 2" "Flags" "ENABLED" + WriteINIStr $0 "Field 2" "State" "1" + WriteINIStr $0 "Field 3" "State" "0" + + notpresent: + + !insertmacro MUI_HEADER_TEXT "Kerberos Configuration" "Please choose a method for installing the Kerberos Configuration files:" + InstallOptions::dialog $0 + Pop $R1 + StrCmp $R1 "cancel" exit + StrCmp $R1 "back" done + StrCmp $R1 "success" done +exit: Quit +done: + + ; Check that if a file is set, a valid filename is entered... + ReadINIStr $R0 $0 "Field 6" "State" + StrCmp $R0 "1" CheckFileName + + ;Check if a URL is specified, one *IS* specified + ReadINIStr $R0 $0 "Field 4" "State" + StrCmp $R0 "1" CheckURL Skip + + CheckURL: + ReadINIStr $R0 $0 "Field 5" "State" + StrCmp $R0 "" +1 Skip + MessageBox MB_OK|MB_ICONSTOP $(URLError) + WriteINIStr $0 "Field 4" "State" "0" + goto startOver + + CheckFileName: + ReadINIStr $R0 $0 "Field 7" "State" + IfFileExists "$R0\krb5.ini" Skip + + MessageBox MB_OK|MB_ICONSTOP $(ConfigFileError) + WriteINIStr $0 "Field 6" "State" "0" + goto startOver + + Skip: + +FunctionEnd + + +;------------------------------- +;Do the page to get the Startup Configuration + +Function KFWPageGetStartupConfig + ; Skip this page if we are not installing the client + SectionGetFlags ${secClient} $R0 + IntOp $R0 $R0 & ${SF_SELECTED} + StrCmp $R0 "0" Skip + + ; Set the install options here + + !insertmacro MUI_HEADER_TEXT "Network Identity Manager Setup" "Please select Network Identity ticket manager setup options:" + InstallOptions::dialog $1 + Pop $R1 + StrCmp $R1 "cancel" exit + StrCmp $R1 "back" done + StrCmp $R1 "success" done +exit: + Quit +done: +skip: + +FunctionEnd + + +;------------- +; Common install routines for each module +Function KFWCommon.Install + + WriteRegStr HKLM "${KFW_REGKEY_ROOT}" "InstallDir" $INSTDIR + + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" "DisplayName" "${PROGRAM_NAME}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" "UninstallString" "$INSTDIR\uninstall.exe" +!ifndef DEBUG + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" "DisplayVersion" "${KFW_VERSION}" +!else + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" "DisplayVersion" "${KFW_VERSION} Checked/Debug" +!endif + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROGRAM_NAME}" "URLInfoAbout" "http://web.mit.edu/kerberos/" + +!ifdef DEBUG + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\CurrentVersion" "Debug" 1 + WriteRegDWORD HKLM "${KFW_REGKEY_ROOT}\${KFW_VERSION}" "Debug" 1 +!else + ; Delete the DEBUG string + DeleteRegValue HKLM "${KFW_REGKEY_ROOT}\CurrentVersion" "Debug" + DeleteRegValue HKLM "${KFW_REGKEY_ROOT}\${KFW_VERSION}" "Debug" +!endif + + WriteUninstaller "$INSTDIR\Uninstall.exe" +FunctionEnd + + +;------------------------------- +; Check if the client should be checked for default install +Function ShouldClientInstall + Push $R0 + StrCpy $R2 "Client" + Call GetInstalledVersion + Pop $R0 + + StrCmp $R0 "" NotInstalled + ; Now we see if it's an older or newer version + + Call GetInstalledVersionMajor + Pop $R0 + IntCmpU $R0 ${KFW_MAJORVERSION} +1 Upgrade Downgrade + + Call GetInstalledVersionMinor + Pop $R0 + IntCmpU $R0 ${KFW_MINORVERSION} +1 Upgrade Downgrade + + Call GetInstalledVersionPatch + Pop $R0 + IntCmpU $R0 ${KFW_PATCHLEVEL} Reinstall Upgrade Downgrade + +Reinstall: + StrCpy $R0 "1" + Exch $R0 + goto end + +Upgrade: + StrCpy $R0 "2" + Exch $R0 + goto end + +Downgrade: + StrCpy $R0 "3" + Exch $R0 + goto end + +NotInstalled: + StrCpy $R0 "0" + Exch $R0 +end: +FunctionEnd + +;------------------------------- +; Check how the Documentation options should be set +Function ShouldDocumentationInstall + Push $R0 + StrCpy $R2 "Documentation" + Call GetInstalledVersion + Pop $R0 + + StrCmp $R0 "" NotInstalled + ; Now we see if it's an older or newer version + + Call GetInstalledVersionMajor + Pop $R0 + IntCmpU $R0 ${KFW_MAJORVERSION} +1 Upgrade Downgrade + + Call GetInstalledVersionMinor + Pop $R0 + IntCmpU $R0 ${KFW_MINORVERSION} +1 Upgrade Downgrade + + Call GetInstalledVersionPatch + Pop $R0 + IntCmpU $R0 ${KFW_PATCHLEVEL} Reinstall Upgrade Downgrade + +Reinstall: + StrCpy $R0 "1" + Exch $R0 + goto end + +Upgrade: + StrCpy $R0 "2" + Exch $R0 + goto end + +Downgrade: + StrCpy $R0 "3" + Exch $R0 + goto end + + +NotInstalled: + StrCpy $R0 "0" + Exch $R0 +end: +FunctionEnd + + +;------------------------------- +; Check how the SDK options should be set +Function ShouldSDKInstall + Push $R0 + StrCpy $R2 "SDK" + Call GetInstalledVersion + Pop $R0 + + StrCmp $R0 "" NotInstalled + ; Now we see if it's an older or newer version + + Call GetInstalledVersionMajor + Pop $R0 + IntCmpU $R0 ${KFW_MAJORVERSION} +1 Upgrade Downgrade + + Call GetInstalledVersionMinor + Pop $R0 + IntCmpU $R0 ${KFW_MINORVERSION} +1 Upgrade Downgrade + + Call GetInstalledVersionPatch + Pop $R0 + IntCmpU $R0 ${KFW_PATCHLEVEL} Reinstall Upgrade Downgrade + +Reinstall: + StrCpy $R0 "1" + Exch $R0 + goto end + +Upgrade: + StrCpy $R0 "2" + Exch $R0 + goto end + +Downgrade: + StrCpy $R0 "3" + Exch $R0 + goto end + + +NotInstalled: + StrCpy $R0 "0" + Exch $R0 +end: +FunctionEnd + +; See if KfW SDK is installed +; Returns: "1" if it is, 0 if it is not (on the stack) +Function IsSDKInstalled + Push $R0 + StrCpy $R2 "SDK" + Call GetInstalledVersion + Pop $R0 + + StrCmp $R0 "" NotInstalled + + StrCpy $R0 "1" + Exch $R0 + goto end + +NotInstalled: + StrCpy $R0 "0" + Exch $R0 +end: +FunctionEnd + + +; See if KfW Client is installed +; Returns: "1" if it is, 0 if it is not (on the stack) +Function IsClientInstalled + Push $R0 + StrCpy $R2 "Client" + Call GetInstalledVersion + Pop $R0 + + StrCmp $R0 "" NotInstalled + + StrCpy $R0 "1" + Exch $R0 + goto end + +NotInstalled: + StrCpy $R0 "0" + Exch $R0 +end: +FunctionEnd + + + +; See if KfW Documentation is installed +; Returns: "1" if it is, 0 if it is not (on the stack) +Function IsDocumentationInstalled + Push $R0 + StrCpy $R2 "Documentation" + Call GetInstalledVersion + Pop $R0 + + StrCmp $R0 "" NotInstalled + + StrCpy $R0 "1" + Exch $R0 + goto end + +NotInstalled: + StrCpy $R0 "0" + Exch $R0 +end: +FunctionEnd + + + +;Check to see if any KfW component is installed +;Returns: Value on stack: "1" if it is, "0" if it is not +Function IsAnyKfWInstalled + Push $R0 + Push $R1 + Push $R2 + Call IsClientInstalled + Pop $R0 + Call IsSDKInstalled + Pop $R1 + Call IsDocumentationInstalled + Pop $R2 + ; Now we must see if ANY of the $Rn values are 1 + StrCmp $R0 "1" SomethingInstalled + StrCmp $R1 "1" SomethingInstalled + StrCmp $R2 "1" SomethingInstalled + ;Nothing installed + StrCpy $R0 "0" + goto end +SomethingInstalled: + StrCpy $R0 "1" +end: + Pop $R2 + Pop $R1 + Exch $R0 +FunctionEnd + +;-------------------------------- +;Handle what must and what must not be installed +Function .onSelChange + ; If they install the SDK, they MUST install the client + SectionGetFlags ${secSDK} $R0 + IntOp $R0 $R0 & ${SF_SELECTED} + StrCmp $R0 "1" MakeClientSelected + goto end + +MakeClientSelected: + SectionGetFlags ${secClient} $R0 + IntOp $R0 $R0 | ${SF_SELECTED} + SectionSetFlags ${secClient} $R0 + +end: +FunctionEnd + +Function AddProvider + Push $R0 + Push $R1 + ReadRegStr $R0 HKLM "SYSTEM\CurrentControlSet\Control\NetworkProvider\HWOrder" "ProviderOrder" + Push $R0 + StrCpy $R0 "MIT Kerberos" + Push $R0 + Call StrStr + Pop $R0 + StrCmp $R0 "" DoOther +1 + ReadRegStr $R1 HKLM "SYSTEM\CurrentControlSet\Control\NetworkProvider\HWOrder" "ProviderOrder" + StrCpy $R0 "$R1,MIT Kerberos" + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Control\NetworkProvider\HWOrder" "ProviderOrder" $R0 +DoOther: + ReadRegStr $R0 HKLM "SYSTEM\CurrentControlSet\Control\NetworkProvider\Order" "ProviderOrder" + Push $R0 + StrCpy $R0 "MIT Kerberos" + Push $R0 + Call StrStr + Pop $R0 + StrCmp $R0 "" +1 End + ReadRegStr $R1 HKLM "SYSTEM\CurrentControlSet\Control\NetworkProvider\Order" "ProviderOrder" + StrCpy $R0 "$R1,MIT Kerberos" + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Control\NetworkProvider\Order" "ProviderOrder" $R0 +End: + Pop $R1 + Pop $R0 +FunctionEnd + +Function un.RemoveProvider + Push $R0 + StrCpy $R0 "MIT Kerberos" + Push $R0 + StrCpy $R0 "SYSTEM\CurrentControlSet\Control\NetworkProvider\HWOrder" + Call un.RemoveFromProvider + StrCpy $R0 "MIT Kerberos" + Push $R0 + StrCpy $R0 "SYSTEM\CurrentControlSet\Control\NetworkProvider\Order" + Call un.RemoveFromProvider + Pop $R0 +FunctionEnd + +Function un.RemoveFromProvider + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + + ReadRegStr $1 HKLM "$R0" "ProviderOrder" + StrCpy $5 $1 1 -1 # copy last char + StrCmp $5 "," +2 # if last char != , + StrCpy $1 "$1," # append , + Push $1 + Push "$0," + Call un.StrStr ; Find `$0,` in $1 + Pop $2 ; pos of our dir + StrCmp $2 "" unRemoveFromPath_done + ; else, it is in path + # $0 - path to add + # $1 - path var + StrLen $3 "$0," + StrLen $4 $2 + StrCpy $5 $1 -$4 # $5 is now the part before the path to remove + StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove + StrCpy $3 $5$6 + + StrCpy $5 $3 1 -1 # copy last char + StrCmp $5 "," 0 +2 # if last char == , + StrCpy $3 $3 -1 # remove last char + + WriteRegStr HKLM "$R0" "ProviderOrder" $3 + + unRemoveFromPath_done: + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd diff --git a/mechglue/src/windows/installer/nsis/kfw.ico b/mechglue/src/windows/installer/nsis/kfw.ico new file mode 100644 index 0000000000000000000000000000000000000000..9ef4f96ffcb8230f5111a031e4a4bbf17481f5b9 GIT binary patch literal 25214 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 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/nsis/kfw.nsi b/mechglue/src/windows/installer/nsis/kfw.nsi new file mode 100644 index 000000000..a6f2733e1 --- /dev/null +++ b/mechglue/src/windows/installer/nsis/kfw.nsi @@ -0,0 +1,16 @@ +;KfW Install Script for NSIS +; +; Written by Jeffrey Altman <jaltman@mit.edu> +; based on the OpenAFS installer written by Rob Murawski <rsm4@ieee.org> +; +;Based on: +;NSIS Modern User Interface version 1.63 +;MultiLanguage Example Script +;Written by Joost Verburg +; +; This version compiles with NSIS v2.0b4 + +!include site-local.nsi +!include "MUI.nsh" +!include Sections.nsh +!include "kfw-fixed.nsi" diff --git a/mechglue/src/windows/installer/nsis/killer.cpp b/mechglue/src/windows/installer/nsis/killer.cpp new file mode 100644 index 000000000..7ba27fc20 --- /dev/null +++ b/mechglue/src/windows/installer/nsis/killer.cpp @@ -0,0 +1,380 @@ +/* + Process Killer for NSIS script + + Rob Murawski + + Released under terms of IBM Open Source agreement for OpenAFS + + */ + + +#include <windows.h> +#include <stdio.h> +#include <tlhelp32.h> +#include <vdmdbg.h> + +char strProcessName[256]; + +typedef BOOL (CALLBACK *PROCENUMPROC)(DWORD, WORD, LPSTR, LPARAM); + +typedef struct { + DWORD dwPID; + PROCENUMPROC lpProc; + DWORD lParam; + BOOL bEnd; +} EnumInfoStruct; + +BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam); + +BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16, + PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined); + +// +// The EnumProcs function takes a pointer to a callback function +// that will be called once per process with the process filename +// and process ID. +// +// lpProc -- Address of callback routine. +// +// lParam -- A user-defined LPARAM value to be passed to +// the callback routine. +// +// Callback function definition: +// BOOL CALLBACK Proc(DWORD dw, WORD w, LPCSTR lpstr, LPARAM lParam); +// +BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam) { + + OSVERSIONINFO osver; + HINSTANCE hInstLib = NULL; + HINSTANCE hInstLib2 = NULL; + HANDLE hSnapShot = NULL; + LPDWORD lpdwPIDs = NULL; + PROCESSENTRY32 procentry; + BOOL bFlag; + DWORD dwSize; + DWORD dwSize2; + DWORD dwIndex; + HMODULE hMod; + HANDLE hProcess; + char szFileName[MAX_PATH]; + EnumInfoStruct sInfo; + + // ToolHelp Function Pointers. + HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD, DWORD); + BOOL (WINAPI *lpfProcess32First)(HANDLE, LPPROCESSENTRY32); + BOOL (WINAPI *lpfProcess32Next)(HANDLE, LPPROCESSENTRY32); + + // PSAPI Function Pointers. + BOOL (WINAPI *lpfEnumProcesses)(DWORD *, DWORD, DWORD *); + BOOL (WINAPI *lpfEnumProcessModules)(HANDLE, HMODULE *, DWORD, + LPDWORD); + DWORD (WINAPI *lpfGetModuleBaseName)(HANDLE, HMODULE, LPTSTR, DWORD); + + // VDMDBG Function Pointers. + INT (WINAPI *lpfVDMEnumTaskWOWEx)(DWORD, TASKENUMPROCEX, LPARAM); + + // Retrieve the OS version + osver.dwOSVersionInfoSize = sizeof(osver); + if (!GetVersionEx(&osver)) + return FALSE; + + // If Windows NT 4.0 + if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT + && osver.dwMajorVersion == 4) { + + __try { + + // Get the procedure addresses explicitly. We do + // this so we don't have to worry about modules + // failing to load under OSes other than Windows NT 4.0 + // because references to PSAPI.DLL can't be resolved. + hInstLib = LoadLibraryA("PSAPI.DLL"); + if (hInstLib == NULL) + __leave; + + hInstLib2 = LoadLibraryA("VDMDBG.DLL"); + if (hInstLib2 == NULL) + __leave; + + // Get procedure addresses. + lpfEnumProcesses = (BOOL (WINAPI *)(DWORD *, DWORD, DWORD*)) + GetProcAddress(hInstLib, "EnumProcesses"); + + lpfEnumProcessModules = (BOOL (WINAPI *)(HANDLE, HMODULE *, + DWORD, LPDWORD)) GetProcAddress(hInstLib, + "EnumProcessModules"); + + lpfGetModuleBaseName = (DWORD (WINAPI *)(HANDLE, HMODULE, + LPTSTR, DWORD)) GetProcAddress(hInstLib, + "GetModuleBaseNameA"); + + lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX, + LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx"); + + if (lpfEnumProcesses == NULL + || lpfEnumProcessModules == NULL + || lpfGetModuleBaseName == NULL + || lpfVDMEnumTaskWOWEx == NULL) + __leave; + + // + // Call the PSAPI function EnumProcesses to get all of the + // ProcID's currently in the system. + // + // NOTE: In the documentation, the third parameter of + // EnumProcesses is named cbNeeded, which implies that you + // can call the function once to find out how much space to + // allocate for a buffer and again to fill the buffer. + // This is not the case. The cbNeeded parameter returns + // the number of PIDs returned, so if your buffer size is + // zero cbNeeded returns zero. + // + // NOTE: The "HeapAlloc" loop here ensures that we + // actually allocate a buffer large enough for all the + // PIDs in the system. + // + dwSize2 = 256 * sizeof(DWORD); + do { + + if (lpdwPIDs) { + HeapFree(GetProcessHeap(), 0, lpdwPIDs); + dwSize2 *= 2; + } + + lpdwPIDs = (LPDWORD) HeapAlloc(GetProcessHeap(), 0, + dwSize2); + if (lpdwPIDs == NULL) + __leave; + + if (!lpfEnumProcesses(lpdwPIDs, dwSize2, &dwSize)) + __leave; + + } while (dwSize == dwSize2); + + // How many ProcID's did we get? + dwSize /= sizeof(DWORD); + + // Loop through each ProcID. + for (dwIndex = 0; dwIndex < dwSize; dwIndex++) { + + szFileName[0] = 0; + + // Open the process (if we can... security does not + // permit every process in the system to be opened). + hProcess = OpenProcess( + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + FALSE, lpdwPIDs[dwIndex]); + if (hProcess != NULL) { + + // Here we call EnumProcessModules to get only the + // first module in the process. This will be the + // EXE module for which we will retrieve the name. + if (lpfEnumProcessModules(hProcess, &hMod, + sizeof(hMod), &dwSize2)) { + + // Get the module name + if (!lpfGetModuleBaseName(hProcess, hMod, + szFileName, sizeof(szFileName))) + szFileName[0] = 0; + } + CloseHandle(hProcess); + } + // Regardless of OpenProcess success or failure, we + // still call the enum func with the ProcID. + if (!lpProc(lpdwPIDs[dwIndex], 0, szFileName, lParam)) + break; + + // Did we just bump into an NTVDM? + if (_stricmp(szFileName, "NTVDM.EXE") == 0) { + + // Fill in some info for the 16-bit enum proc. + sInfo.dwPID = lpdwPIDs[dwIndex]; + sInfo.lpProc = lpProc; + sInfo.lParam = (DWORD) lParam; + sInfo.bEnd = FALSE; + + // Enum the 16-bit stuff. + lpfVDMEnumTaskWOWEx(lpdwPIDs[dwIndex], + (TASKENUMPROCEX) Enum16, (LPARAM) &sInfo); + + // Did our main enum func say quit? + if (sInfo.bEnd) + break; + } + } + + } __finally { + + if (hInstLib) + FreeLibrary(hInstLib); + + if (hInstLib2) + FreeLibrary(hInstLib2); + + if (lpdwPIDs) + HeapFree(GetProcessHeap(), 0, lpdwPIDs); + } + + // If any OS other than Windows NT 4.0. + } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + || (osver.dwPlatformId == VER_PLATFORM_WIN32_NT + && osver.dwMajorVersion > 4)) { + + __try { + + hInstLib = LoadLibraryA("Kernel32.DLL"); + if (hInstLib == NULL) + __leave; + + // If NT-based OS, load VDMDBG.DLL. + if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { + hInstLib2 = LoadLibraryA("VDMDBG.DLL"); + if (hInstLib2 == NULL) + __leave; + } + + // Get procedure addresses. We are linking to + // these functions explicitly, because a module using + // this code would fail to load under Windows NT, + // which does not have the Toolhelp32 + // functions in KERNEL32.DLL. + lpfCreateToolhelp32Snapshot = + (HANDLE (WINAPI *)(DWORD,DWORD)) + GetProcAddress(hInstLib, "CreateToolhelp32Snapshot"); + + lpfProcess32First = + (BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32)) + GetProcAddress(hInstLib, "Process32First"); + + lpfProcess32Next = + (BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32)) + GetProcAddress(hInstLib, "Process32Next"); + + if (lpfProcess32Next == NULL + || lpfProcess32First == NULL + || lpfCreateToolhelp32Snapshot == NULL) + __leave; + + if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { + lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX, + LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx"); + if (lpfVDMEnumTaskWOWEx == NULL) + __leave; + } + + // Get a handle to a Toolhelp snapshot of all processes. + hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapShot == INVALID_HANDLE_VALUE) { + FreeLibrary(hInstLib); + return FALSE; + } + + // Get the first process' information. + procentry.dwSize = sizeof(PROCESSENTRY32); + bFlag = lpfProcess32First(hSnapShot, &procentry); + + // While there are processes, keep looping. + while (bFlag) { + + // Call the enum func with the filename and ProcID. + if (lpProc(procentry.th32ProcessID, 0, + procentry.szExeFile, lParam)) { + + // Did we just bump into an NTVDM? + if (_stricmp(procentry.szExeFile, "NTVDM.EXE") == 0) { + + // Fill in some info for the 16-bit enum proc. + sInfo.dwPID = procentry.th32ProcessID; + sInfo.lpProc = lpProc; + sInfo.lParam = (DWORD) lParam; + sInfo.bEnd = FALSE; + + // Enum the 16-bit stuff. + lpfVDMEnumTaskWOWEx(procentry.th32ProcessID, + (TASKENUMPROCEX) Enum16, (LPARAM) &sInfo); + + // Did our main enum func say quit? + if (sInfo.bEnd) + break; + } + + procentry.dwSize = sizeof(PROCESSENTRY32); + bFlag = lpfProcess32Next(hSnapShot, &procentry); + + } else + bFlag = FALSE; + } + + } __finally { + + if (hInstLib) + FreeLibrary(hInstLib); + + if (hInstLib2) + FreeLibrary(hInstLib2); + } + + } else + return FALSE; + + // Free the library. + FreeLibrary(hInstLib); + + return TRUE; +} + + +BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16, + PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined) { + + BOOL bRet; + + EnumInfoStruct *psInfo = (EnumInfoStruct *)lpUserDefined; + + bRet = psInfo->lpProc(psInfo->dwPID, hTask16, pszFileName, + psInfo->lParam); + + if (!bRet) + psInfo->bEnd = TRUE; + + return !bRet; +} + + +BOOL CALLBACK MyProcessEnumerator(DWORD dwPID, WORD wTask, + LPCSTR szProcess, LPARAM lParam) { + + /*if (wTask == 0) + printf("%5u %s\n", dwPID, szProcess); + else + printf(" %5u %s\n", wTask, szProcess);*/ + + if(stricmp(szProcess,strProcessName)==0) + { + HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); + if(hProcess!=NULL) + TerminateProcess(hProcess,0); + CloseHandle(hProcess); + } + + return TRUE; +} + + +void main(int argc, char *argv[]) +{ + if(argc<2) + { + printf("Please specify the process name to kill\n"); + + return; + } + + if(strlen((argv[1]))<255) + strcpy(strProcessName,(argv[1])); + else + return; + + EnumProcs((PROCENUMPROC) MyProcessEnumerator, 0); + +} diff --git a/mechglue/src/windows/installer/nsis/licenses.rtf b/mechglue/src/windows/installer/nsis/licenses.rtf new file mode 100644 index 000000000..1ddfcb96d --- /dev/null +++ b/mechglue/src/windows/installer/nsis/licenses.rtf @@ -0,0 +1,98 @@ +{\rtf1\ansi\ansicpg1252\deff0\deflang1033\deflangfe1033{\fonttbl{\f0\fmodern\fprq1\fcharset0 Courier New;}{\f1\froman\fprq2\fcharset0 Times New Roman;}} +{\*\generator Msftedit 5.41.15.1503;}\viewkind4\uc1\pard\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\f0\fs20 Copyright Notice and Legal Administrivia\par +----------------------------------------\par +\par +Copyright (C) 1985-2005 by the Massachusetts Institute of Technology.\par +\par +All rights reserved.\par +\par +Export of this software from the United States of America may require a specific license from the United States Government. It is the responsibility of any person or organization contemplating export to obtain such a license before exporting.\par +\par +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and\par +this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Furthermore if you modify this software you must label your software as modified software and not distribute it in such a fashion that it might be confused with the original MIT software. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.\par +\par +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\par +\par +Individual source code files are copyright MIT, Cygnus Support, OpenVision, Oracle, Sun Soft, FundsXpress, and others.\par +\par +Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira, and Zephyr are trademarks of the Massachusetts Institute of Technology (MIT). No commercial use of these trademarks may be made without prior written permission of MIT.\par +\par +"Commercial use" means use of a name in a product or other for-profit manner. It does NOT prevent a commercial firm from referring to the MIT trademarks in order to convey information (although in doing so, recognition of their trademark status should be given).\par +\par +----\par +\par +The following copyright and permission notice applies to the OpenVision Kerberos Administration system located in kadmin/create, kadmin/dbutil, kadmin/passwd, kadmin/server, lib/kadm5, and portions of lib/rpc:\par +\par +Copyright, OpenVision Technologies, Inc., 1996, All Rights Reserved\par +\par +WARNING: Retrieving the OpenVision Kerberos Administration system source code, as described below, indicates your acceptance of the following terms. If you do not agree to the following terms, do not retrieve the OpenVision Kerberos administration system.\par +\par +You may freely use and distribute the Source Code and Object Code compiled from it, with or without modification, but this Source Code is provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER EXPRESS OR IMPLIED. IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY FOR ANY LOST PROFITS, LOSS OF DATA OR COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, INCLUDING, WITHOUT LIMITATION, THOSE RESULTING FROM THE USE OF THE SOURCE CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR ANY OTHER REASON.\par +\par +OpenVision retains all copyrights in the donated Source Code. OpenVision also retains copyright to derivative works of the Source Code, whether created by OpenVision or by a third party. The OpenVision copyright notice must be preserved if derivative works are made based on the donated Source Code.\par +\par +OpenVision Technologies, Inc. has donated this Kerberos Administration system to MIT for inclusion in the standard Kerberos 5 distribution. This donation underscores our commitment to continuing Kerberos technology development and our gratitude for the valuable work which has been performed by MIT and the Kerberos community.\par +\par +----\par +\par +Portions contributed by Matt Crawford <crawdad@fnal.gov> were work performed at Fermi National Accelerator Laboratory, which is operated by Universities Research Association, Inc., under contract DE-AC02-76CHO3000 with the U.S. Department of Energy.\par +\par +---- The implementation of the Yarrow pseudo-random number generator in src/lib/crypto/yarrow has the following copyright:\par +\par +Copyright 2000 by Zero-Knowledge Systems, Inc.\par +\par +Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Zero-Knowledge Systems, Inc. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Zero-Knowledge Systems, Inc. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.\par +\par +ZERO-KNOWLEDGE SYSTEMS, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ZERO-KNOWLEDGE SYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\par +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\par +\par +---- The implementation of the AES encryption algorithm in src/lib/crypto/aes has the following copyright:\par +\par +Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.\par +All rights reserved.\par +\par +LICENSE TERMS\par +\par +The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that:\par +\par +1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer;\par +\par +2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials;\par +\par +3. the copyright holder's name is not used to endorse products built using this software without specific written permission. \par +\par +DISCLAIMER\par +\par +This software is provided 'as is' with no explcit or implied warranties in respect of any properties, including, but not limited to, correctness and fitness for purpose.\par +\par +\par +\par +Acknowledgements\par +----------------\par +\par +Appreciation Time!!!! There are far too many people to try to thank them all; many people have contributed to the development of Kerberos V5. This is only a partial listing....\par +\par +Thanks to Paul Vixie and the Internet Software Consortium for funding the work of Barry Jaspan. This funding was invaluable for the OV administration server integration, as well as the 1.0 release preparation process.\par +\par +Thanks to John Linn, Scott Foote, and all of the folks at OpenVision Technologies, Inc., who donated their administration server for use in the MIT release of Kerberos.\par +\par +Thanks to Jeff Bigler, Mark Eichin, Marc Horowitz, Nancy Gilman, Ken Raeburn, and all of the folks at Cygnus Support, who provided innumerable bug fixes and portability enhancements to the Kerberos V5 tree. Thanks especially to Jeff Bigler, for the new user and system administrator's documentation.\par +\par +Thanks to Doug Engert from ANL for providing many bug fixes, as well as testing to ensure DCE interoperability.\par +\par +Thanks to Ken Hornstein at NRL for providing many bug fixes and suggestions, and for working on SAM preauthentication.\par +\par +Thanks to Matt Crawford at FNAL for bugfixes and enhancements.\par +\par +Thanks to Sean Mullan and Bill Sommerfeld from Hewlett Packard for their many suggestions and bug fixes.\par +\par +Thanks to Nalin Dahyabhai of RedHat and Chris Evans for locating and providing patches for numerous buffer overruns.\par +\par +Thanks to Christopher Thompson and Marcus Watts for discovering the ftpd security bug.\par +\par +Thanks to Paul Nelson of Thursby Software Systems for implementing the Microsoft set password protocol.\par +\par +Thanks to the members of the Kerberos V5 development team at MIT, both past and present: Danilo Almeida, Jeffrey Altman, Jay Berkenbilt, Richard Basch, Mitch Berger, John Carr, Don Davis, Alexandra Ellwood, Nancy Gilman, Matt Hancher, Sam Hartman, Paul Hill, Marc Horowitz, Eva Jacobus, Miroslav Jurisic, Barry Jaspan, Geoffrey King, John Kohl, Peter Litwack, Scott McGuire, Kevin Mitchell, Cliff Neuman, Paul Park, Ezra Peisach, Chris Provenzano, Ken Raeburn, Jon Rochlis, Jeff Schiller, Jen Selby, Brad Thompson, Harry Tsai, Ted Ts'o, Marshall Vale, Tom Yu.\par +\pard\f1\fs24\par +} +� \ No newline at end of file diff --git a/mechglue/src/windows/installer/nsis/nsi-includes.nsi b/mechglue/src/windows/installer/nsis/nsi-includes.nsi new file mode 100644 index 000000000..275237ae4 --- /dev/null +++ b/mechglue/src/windows/installer/nsis/nsi-includes.nsi @@ -0,0 +1,8 @@ +!define KFW_TARGETDIR c:\temp\kfw\kfw-3.0.0-beta-1 +!define KFW_EXTRADIR c:\temp\kfw\kfw-2.5-extra +!define KFW_VERSION 3.0 +!define KFW_MAJORVERSION 3 +!define KFW_MINORVERSION 0 +!define KFW_PATCHLEVEL 0000 +!define CL_1310 + diff --git a/mechglue/src/windows/installer/nsis/site-local.nsi b/mechglue/src/windows/installer/nsis/site-local.nsi new file mode 100644 index 000000000..62b9b0af1 --- /dev/null +++ b/mechglue/src/windows/installer/nsis/site-local.nsi @@ -0,0 +1,13 @@ +!define KFW_TARGETDIR c:\temp\kfw\kfw-3.0.0 +!define KFW_CONFIG_DIR "c:\temp\kfw\kfw-2.5-extra\sample-config" +!define KFW_MAJORVERSION 3 +!define KFW_MINORVERSION 0 +!define KFW_PATCHLEVEL 0 +!define CL_1310 + +!define RELEASE +!define NOT_DEBUG +!define NOT_BETA +!define SAMPLE_CONFIG_REALM "ATHENA.MIT.EDU" +!define HTTP_CONFIG_URL "[Obtain a URL from your Kerberos administrator]" + diff --git a/mechglue/src/windows/installer/nsis/utils.nsi b/mechglue/src/windows/installer/nsis/utils.nsi new file mode 100644 index 000000000..147f80482 --- /dev/null +++ b/mechglue/src/windows/installer/nsis/utils.nsi @@ -0,0 +1,825 @@ +;----------------------------------------------- +; Common Utility functions not specific to KFW + +;------------------- +; Get the currently installed version and place it on the stack +; Modifies: Nothing +Function GetInstalledVersion + Push $R0 + Push $R1 + Push $R4 + ReadRegStr $R0 HKLM "${KFW_REGKEY_ROOT}\$R2\CurrentVersion" "VersionString" + StrCmp $R0 "" done + +done: + Pop $R4 + Pop $R1 + Exch $R0 +FunctionEnd + +; Functions to get each component of the version number +Function GetInstalledVersionMajor + Push $R0 + Push $R1 + Push $R4 + ReadRegDWORD $R0 HKLM "${KFW_REGKEY_ROOT}\$R2\CurrentVersion" "MajorVersion" + StrCmp $R0 "" done + +done: + Pop $R4 + Pop $R1 + Exch $R0 +FunctionEnd + +Function GetInstalledVersionMinor + Push $R0 + Push $R1 + Push $R4 + ReadRegDWORD $R0 HKLM "${KFW_REGKEY_ROOT}\$R2\CurrentVersion" "MinorVersion" + StrCmp $R0 "" done + +done: + Pop $R4 + Pop $R1 + Exch $R0 +FunctionEnd + +Function GetInstalledVersionPatch + Push $R0 + Push $R1 + Push $R4 + ReadRegDWORD $R0 HKLM "${KFW_REGKEY_ROOT}\$R2\CurrentVersion" "PatchLevel" + StrCmp $R0 "" done + +done: + Pop $R4 + Pop $R1 + Exch $R0 +FunctionEnd + + +;-------------------------------- +; Macros + +;-------------------------------- +; Macros +; Macro - Upgrade DLL File +; Written by Joost Verburg +; ------------------------ +; +; Parameters: +; LOCALFILE - Location of the new DLL file (on the compiler system) +; DESTFILE - Location of the DLL file that should be upgraded +; (on the user's system) +; TEMPBASEDIR - Directory on the user's system to store a temporary file +; when the system has to be rebooted. +; For Win9x support, this should be on the same volume as the +; DESTFILE! +; The Windows temp directory could be located on any volume, +; so you cannot use this directory. +; +; Define REPLACEDLL_NOREGISTER if you want to upgrade a DLL that does not +; have to be registered. +; +; Note: If you want to support Win9x, you can only use +; short filenames (8.3). +; +; Example of usage: +; !insertmacro ReplaceDLL "dllname.dll" "$SYSDIR\dllname.dll" "$SYSDIR" +; + +!macro ReplaceDLL LOCALFILE DESTFILE TEMPBASEDIR + + Push $R0 + Push $R1 + Push $R2 + Push $R3 + Push $R4 + Push $R5 + + ;------------------------ + ;Unique number for labels + + !define REPLACEDLL_UNIQUE ${__LINE__} + + ;------------------------ + ;Copy the parameters used on run-time to a variable + ;This allows the usage of variables as paramter + + StrCpy $R4 "${DESTFILE}" + StrCpy $R5 "${TEMPBASEDIR}" + + ;------------------------ + ;Check file and version + ; + IfFileExists $R4 0 replacedll.copy_${REPLACEDLL_UNIQUE} + + ;ClearErrors + ; GetDLLVersionLocal "${LOCALFILE}" $R0 $R1 + ; GetDLLVersion $R4 $R2 $R3 + ;IfErrors replacedll.upgrade_${REPLACEDLL_UNIQUE} + ; + ;IntCmpU $R0 $R2 0 replacedll.done_${REPLACEDLL_UNIQUE} \ + ; replacedll.upgrade_${REPLACEDLL_UNIQUE} + ;IntCmpU $R1 $R3 replacedll.done_${REPLACEDLL_UNIQUE} \ + ; replacedll.done_${REPLACEDLL_UNIQUE} \ + ; replacedll.upgrade_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;Let's replace the DLL! + + SetOverwrite try + + ;replacedll.upgrade_${REPLACEDLL_UNIQUE}: + !ifndef REPLACEDLL_NOREGISTER + ;Unregister the DLL + UnRegDLL $R4 + !endif + + ;------------------------ + ;Try to copy the DLL directly + + ClearErrors + StrCpy $R0 $R4 + Call :replacedll.file_${REPLACEDLL_UNIQUE} + IfErrors 0 replacedll.noreboot_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;DLL is in use. Copy it to a temp file and Rename it on reboot. + + GetTempFileName $R0 $R5 + Call :replacedll.file_${REPLACEDLL_UNIQUE} + Rename /REBOOTOK $R0 $R4 + + ;------------------------ + ;Register the DLL on reboot + + !ifndef REPLACEDLL_NOREGISTER + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" \ + "Register $R4" 'rundll32.exe "$R4",DllRegisterServer' + !endif + + Goto replacedll.done_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;DLL does not exist - just extract + + replacedll.copy_${REPLACEDLL_UNIQUE}: + StrCpy $R0 $R4 + Call :replacedll.file_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;Register the DLL + + replacedll.noreboot_${REPLACEDLL_UNIQUE}: + !ifndef REPLACEDLL_NOREGISTER + RegDLL $R4 + !endif + + ;------------------------ + ;Done + + replacedll.done_${REPLACEDLL_UNIQUE}: + + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Pop $R1 + Pop $R0 + + ;------------------------ + ;End + + Goto replacedll.end_${REPLACEDLL_UNIQUE} + + ;------------------------ + ;Called to extract the DLL + + replacedll.file_${REPLACEDLL_UNIQUE}: + File /oname=$R0 "${LOCALFILE}" + Return + + replacedll.end_${REPLACEDLL_UNIQUE}: + + ;------------------------ + ;Restore settings + + SetOverwrite lastused + + !undef REPLACEDLL_UNIQUE + +!macroend + + +; GetParameters +; input, none +; output, top of stack (replaces, with e.g. whatever) +; modifies no other variables. + +Function GetParameters + Push $R0 + Push $R1 + Push $R2 + StrCpy $R0 $CMDLINE 1 + StrCpy $R1 '"' + StrCpy $R2 1 + StrCmp $R0 '"' loop + StrCpy $R1 ' ' ; we're scanning for a space instead of a quote + loop: + StrCpy $R0 $CMDLINE 1 $R2 + StrCmp $R0 $R1 loop2 + StrCmp $R0 "" loop2 + IntOp $R2 $R2 + 1 + Goto loop + loop2: + IntOp $R2 $R2 + 1 + StrCpy $R0 $CMDLINE 1 $R2 + StrCmp $R0 " " loop2 + StrCpy $R0 $CMDLINE "" $R2 + Pop $R2 + Pop $R1 + Exch $R0 +FunctionEnd + + +!verbose 3 +!include "WinMessages.NSH" +!verbose 4 + +Function GetSystemPath + Push $0 + + Call IsNT + Pop $0 + StrCmp $0 1 GetPath_NT + ReadEnvStr $0 PATH + goto HavePath +GetPath_NT: + ReadRegStr $0 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" +HavePath: + + Exch $0 +FunctionEnd + +;==================================================== +; AddToSystemPath - Adds the given dir to the search path. +; Input - head of the stack +; Note - Win9x systems requires reboot +;==================================================== +Function AddToSystemPath + Exch $0 + Push $1 + Push $2 + Push $3 + + # don't add if the path doesn't exist + IfFileExists $0 "" AddToPath_done + + Call GetSystemPath + Pop $1 + Push "$1;" + Push "$0;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$0\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + GetFullPathName /SHORT $3 $0 + Push "$1;" + Push "$3;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$3\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + + Call IsNT + Pop $1 + StrCmp $1 1 AddToPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" a + FileSeek $1 -1 END + FileReadByte $1 $2 + IntCmp $2 26 0 +2 +2 # DOS EOF + FileSeek $1 -1 END # write over EOF + FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" + FileClose $1 + SetRebootFlag true + Goto AddToPath_done + + AddToPath_NT: + ReadRegStr $1 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" + StrCpy $2 $1 1 -1 # copy last char + StrCmp $2 ";" 0 +2 # if last char == ; + StrCpy $1 $1 -1 # remove last char + StrCmp $1 "" AddToPath_NTdoIt + StrCpy $0 "$1;$0" + AddToPath_NTdoIt: + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" $0 + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + AddToPath_done: + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +;==================================================== +; RemoveFromPath - Remove a given dir from the path +; Input: head of the stack +;==================================================== +Function un.RemoveFromSystemPath + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + + IntFmt $6 "%c" 26 # DOS EOF + + Call un.IsNT + Pop $1 + StrCmp $1 1 unRemoveFromPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" r + GetTempFileName $4 + FileOpen $2 $4 w + GetFullPathName /SHORT $0 $0 + StrCpy $0 "SET PATH=%PATH%;$0" + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoop: + FileRead $1 $3 + StrCpy $5 $3 1 -1 # read last char + StrCmp $5 $6 0 +2 # if DOS EOF + StrCpy $3 $3 -1 # remove DOS EOF so we can compare + StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "" unRemoveFromPath_dosLoopEnd + FileWrite $2 $3 + Goto unRemoveFromPath_dosLoop + unRemoveFromPath_dosLoopRemoveLine: + SetRebootFlag true + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoopEnd: + FileClose $2 + FileClose $1 + StrCpy $1 $WINDIR 2 + Delete "$1\autoexec.bat" + CopyFiles /SILENT $4 "$1\autoexec.bat" + Delete $4 + Goto unRemoveFromPath_done + + unRemoveFromPath_NT: + ReadRegStr $1 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" + StrCpy $5 $1 1 -1 # copy last char + StrCmp $5 ";" +2 # if last char != ; + StrCpy $1 "$1;" # append ; + Push $1 + Push "$0;" + Call un.StrStr ; Find `$0;` in $1 + Pop $2 ; pos of our dir + StrCmp $2 "" unRemoveFromPath_done + ; else, it is in path + # $0 - path to add + # $1 - path var + StrLen $3 "$0;" + StrLen $4 $2 + StrCpy $5 $1 -$4 # $5 is now the part before the path to remove + StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove + StrCpy $3 $5$6 + + StrCpy $5 $3 1 -1 # copy last char + StrCmp $5 ";" 0 +2 # if last char == ; + StrCpy $3 $3 -1 # remove last char + + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "PATH" $3 + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + unRemoveFromPath_done: + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +;==================================================== +; IsNT - Returns 1 if the current system is NT, 0 +; otherwise. +; Output: head of the stack +;==================================================== +!macro IsNT un +Function ${un}IsNT + Push $0 + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $0 "" 0 IsNT_yes + ; we are not NT. + Pop $0 + Push 0 + Return + + IsNT_yes: + ; NT!!! + Pop $0 + Push 1 +FunctionEnd +!macroend +!insertmacro IsNT "" +!insertmacro IsNT "un." + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Uninstall stuff +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;==================================================== +; StrStr - Finds a given string in another given string. +; Returns -1 if not found and the pos if found. +; Input: head of the stack - string to find +; second in the stack - string to find in +; Output: head of the stack +;==================================================== +!macro StrStr un +Function ${un}StrStr +Exch $R1 ; st=haystack,old$R1, $R1=needle + Exch ; st=old$R1,haystack + Exch $R2 ; st=old$R1,old$R2, $R2=haystack + Push $R3 + Push $R4 + Push $R5 + StrLen $R3 $R1 + StrCpy $R4 0 + ; $R1=needle + ; $R2=haystack + ; $R3=len(needle) + ; $R4=cnt + ; $R5=tmp + loop: + StrCpy $R5 $R2 $R3 $R4 + StrCmp $R5 $R1 done + StrCmp $R5 "" done + IntOp $R4 $R4 + 1 + Goto loop +done: + StrCpy $R1 $R2 "" $R4 + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Exch $R1 +FunctionEnd +!macroend +!insertmacro StrStr "" +!insertmacro StrStr "un." + + +!ifdef ADDSHAREDDLLUSED +; AddSharedDLL + ; + ; Increments a shared DLLs reference count. + ; Use by passing one item on the stack (the full path of the DLL). + ; + ; Usage: + ; Push $SYSDIR\myDll.dll + ; Call AddSharedDLL + ; + + Function AddSharedDLL + Exch $R1 + Push $R0 + ReadRegDword $R0 HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1 + IntOp $R0 $R0 + 1 + WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1 $R0 + Pop $R0 + Pop $R1 + FunctionEnd + + +; un.RemoveSharedDLL + ; + ; Decrements a shared DLLs reference count, and removes if necessary. + ; Use by passing one item on the stack (the full path of the DLL). + ; Note: for use in the main installer (not the uninstaller), rename the + ; function to RemoveSharedDLL. + ; + ; Usage: + ; Push $SYSDIR\myDll.dll + ; Call un.RemoveSharedDLL + ; + + Function un.RemoveSharedDLL + Exch $R1 + Push $R0 + ReadRegDword $R0 HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1 + StrCmp $R0 "" remove + IntOp $R0 $R0 - 1 + IntCmp $R0 0 rk rk uk + rk: + DeleteRegValue HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1 + goto Remove + uk: + WriteRegDWORD HKLM Software\Microsoft\Windows\CurrentVersion\SharedDLLs $R1 $R0 + Goto noremove + remove: + Delete /REBOOTOK $R1 + noremove: + Pop $R0 + Pop $R1 + FunctionEnd +!endif + + +; GetWindowsVersion +; +; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/ +; Updated by Joost Verburg +; +; Returns on top of stack +; +; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003) +; or +; '' (Unknown Windows Version) +; +; Usage: +; Call GetWindowsVersion +; Pop $R0 +; ; at this point $R0 is "NT 4.0" or whatnot + +Function GetWindowsVersion + + Push $R0 + Push $R1 + + ClearErrors + + ReadRegStr $R0 HKLM \ + "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + + IfErrors 0 lbl_winnt + + ; we are not NT + ReadRegStr $R0 HKLM \ + "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber + + StrCpy $R1 $R0 1 + StrCmp $R1 '4' 0 lbl_error + + StrCpy $R1 $R0 3 + + StrCmp $R1 '4.0' lbl_win32_95 + StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98 + + lbl_win32_95: + StrCpy $R0 '95' + Goto lbl_done + + lbl_win32_98: + StrCpy $R0 '98' + Goto lbl_done + + lbl_win32_ME: + StrCpy $R0 'ME' + Goto lbl_done + + lbl_winnt: + + StrCpy $R1 $R0 1 + + StrCmp $R1 '3' lbl_winnt_x + StrCmp $R1 '4' lbl_winnt_x + + StrCpy $R1 $R0 3 + + StrCmp $R1 '5.0' lbl_winnt_2000 + StrCmp $R1 '5.1' lbl_winnt_XP + StrCmp $R1 '5.2' lbl_winnt_2003 lbl_error + + lbl_winnt_x: + StrCpy $R0 "NT $R0" 6 + Goto lbl_done + + lbl_winnt_2000: + Strcpy $R0 '2000' + Goto lbl_done + + lbl_winnt_XP: + Strcpy $R0 'XP' + Goto lbl_done + + lbl_winnt_2003: + Strcpy $R0 '2003' + Goto lbl_done + + lbl_error: + Strcpy $R0 '' + lbl_done: + + Pop $R1 + Exch $R0 + +FunctionEnd + + +; Author: Lilla (lilla@earthlink.net) 2003-06-13 +; function IsUserAdmin uses plugin \NSIS\PlusgIns\UserInfo.dll +; This function is based upon code in \NSIS\Contrib\UserInfo\UserInfo.nsi +; This function was tested under NSIS 2 beta 4 (latest CVS as of this writing). +; +; Usage: +; Call IsUserAdmin +; Pop $R0 ; at this point $R0 is "true" or "false" +; +Function IsUserAdmin +Push $R0 +Push $R1 +Push $R2 + +ClearErrors +UserInfo::GetName +IfErrors Win9x +Pop $R1 +UserInfo::GetAccountType +Pop $R2 + +StrCmp $R2 "Admin" 0 Continue +; Observation: I get here when running Win98SE. (Lilla) +; The functions UserInfo.dll looks for are there on Win98 too, +; but just don't work. So UserInfo.dll, knowing that admin isn't required +; on Win98, returns admin anyway. (per kichik) +; MessageBox MB_OK 'User "$R1" is in the Administrators group' +StrCpy $R0 "true" +Goto Done + +Continue: +; You should still check for an empty string because the functions +; UserInfo.dll looks for may not be present on Windows 95. (per kichik) +StrCmp $R2 "" Win9x +StrCpy $R0 "false" +;MessageBox MB_OK 'User "$R1" is in the "$R2" group' +Goto Done + +Win9x: +; comment/message below is by UserInfo.nsi author: +; This one means you don't need to care about admin or +; not admin because Windows 9x doesn't either +;MessageBox MB_OK "Error! This DLL can't run under Windows 9x!" +StrCpy $R0 "false" + +Done: +;MessageBox MB_OK 'User= "$R1" AccountType= "$R2" IsUserAdmin= "$R0"' + +Pop $R2 +Pop $R1 +Exch $R0 +FunctionEnd + +Function RestartRequired +Push $R1 ;Original Variable +Push $R2 +Push $R3 ;Counter Variable + +StrCpy $R1 "0" 1 ;initialize variable with 0 +StrCpy $R3 "0" 0 ;Counter Variable + +;First Check Current User RunOnce Key +EnumRegValue $R2 HKCU "Software\Microsoft\Windows\CurrentVersion\RunOnce" $R3 +StrCmp $R2 "" 0 FoundRestart + +;Next Check Local Machine RunOnce Key +EnumRegValue $R2 HKLM "Software\Microsoft\Windows\CurrentVersion\RunOnce" $R3 +StrCmp $R2 "" 0 FoundRestart + +EnumRegValue $R2 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\FileRenameOperations" $R3 +StrCmp $R2 "" 0 FoundRestart + +NextValue: +EnumRegValue $R2 HKLM "SYSTEM\CurrentControlSet\Control\Session Manager" $R3 +StrCmp $R2 "" ExitFunc 0 +StrCmp $R2 "PendingFileRenameOperations" FoundRestart 0 +IntOp $R3 $R3 + 1 +Goto NextValue + +FoundRestart: +StrCpy $R1 "1" 1 + +ExitFunc: +Pop $R3 +Pop $R2 +Exch $R1 +FunctionEnd + +; GetParent + ; input, top of stack (e.g. C:\Program Files\Poop) + ; output, top of stack (replaces, with e.g. C:\Program Files) + ; modifies no other variables. + ; + ; Usage: + ; Push "C:\Program Files\Directory\Whatever" + ; Call GetParent + ; Pop $R0 + ; ; at this point $R0 will equal "C:\Program Files\Directory" + +Function GetParent + + Exch $R0 + Push $R1 + Push $R2 + Push $R3 + + StrCpy $R1 0 + StrLen $R2 $R0 + + loop: + IntOp $R1 $R1 + 1 + IntCmp $R1 $R2 get 0 get + StrCpy $R3 $R0 1 -$R1 + StrCmp $R3 "\" get + Goto loop + + get: + StrCpy $R0 $R0 -$R1 + + Pop $R3 + Pop $R2 + Pop $R1 + Exch $R0 + +FunctionEnd + +; SearchPath (path, filename) +; input: +; top of stack is the filename +; top of stack minus one is the path +; output: +; top of stack is a fully qualified path or the number "0" +; +; Usage: +; Push "semicolon delimited path" +; Push "filename" +; Call SearchPath +; Pop $R0 ; fqpn +; StrCmp $R0 "" failed +; +; +Function SearchPath + Exch $R0 ; input - filename + Exch + Exch $R1 ; input - semicolon delimited path + Push $R3 ; worker - index to current end character + Push $R4 ; worker - length of $R1 + Push $R5 ; worker - copy of directory string/fqpn to search for + Push $R6 ; worker - single charcter copy or find handle + + StrCpy $R3 0 ; init character index + StrLen $R4 $R1 ; determine length of semicolon delimited path + StrCpy $R5 "" ; init return value + + findDir: ; find a semi-colon or end of string + IntCmp $R3 $R4 exit 0 exit ; we are done if no unprocessed string left + + loop: + StrCpy $R6 $R1 1 $R3 ; get the next character + StrCmp $R6 ";" foundDir ; if it is semi-colon, we have found a dir + IntOp $R3 $R3 + 1 ; increment index + IntCmp $R3 $R4 foundDir ; if we are at end of string, we have a dir + Goto loop ; still more chars in this dir + + foundDir: + StrCpy $R5 $R1 $R3 ; copy the dir to $R5 + StrCpy $R5 "$R5\$R0" ; construct fqpn + IfFileExists $R5 exit ; if file exists we are done + StrCpy $R5 "" ; reset return value to null string + IntOp $R4 $R4 - $R3 ; compute maxlen of new delimited path + IntCmp $R4 0 exit ; no more path left, exit + IntOp $R3 $R3 + 1 ; Increment $R3 past the semi-colon + StrCpy $R1 $R1 $R4 $R3 ; remove dir from the delimited path + StrCpy $R3 0 ; index back to start of new delimited path + goto findDir ; get another directory to look in + + exit: + Pop $R6 + Exch $R5 ; output - fully qualified pathname + Exch + Pop $R4 + Exch + Pop $R3 + Exch + Pop $R1 + Exch + Pop $R0 +FunctionEnd diff --git a/mechglue/src/windows/installer/wix/Binary/ChangeLog b/mechglue/src/windows/installer/wix/Binary/ChangeLog new file mode 100644 index 000000000..f8aa27c9a --- /dev/null +++ b/mechglue/src/windows/installer/wix/Binary/ChangeLog @@ -0,0 +1,3 @@ +2004-08-20 Asanka Herath <asanka@mit.edu> + + New WiX 2.0 MSI for KFW \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/Binary/bannrbmp.bmp b/mechglue/src/windows/installer/wix/Binary/bannrbmp.bmp new file mode 100644 index 0000000000000000000000000000000000000000..fe26100177d872964fddce9b8ee07addc74414f9 GIT binary patch literal 94554 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 L5<Fp0X2Jggh3MUV literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/completi.ico b/mechglue/src/windows/installer/wix/Binary/completi.ico new file mode 100644 index 0000000000000000000000000000000000000000..93a95a1b190530733b16e26c8f1882e007f43315 GIT binary patch literal 2998 zcmbuBKTKO!6o-!kQasVFkcGvlE8d|UI)In50K11QR0zpZA2L$#LTq=iD@P<nLL@^~ zS|der2mXX1RtAu&CX)w*7%B{QsfC|~QW?~S+wZ*hY)p7w+Vi;Yy?cM(x#ym9uZ=|l za!&>aKNYn<?uiWX930f1$WK9$z8;a!cps#FK?_JPcaa2a%UthPFM-H=BH=!`^D4z+ zk*5mA`4eOGjmD)zdh@kZ;?{7=+I`hA5NtLVUgd8FlG(-G{Q6vbAT{4y$Xo4xFqzCQ ztXuV#9-N<_m-YHhKbcIJzPi=ctw+BbpmzUJ^`#_}$@`XNNh*~J*5mcpmyT{Fvd=Fi z`Lh0cF_}QJ66uvo`L<r$YF^Hfo=L1+eJ{cK?$+XB5Ivd5niY}M?v@vAE|p4u#{jNs zPE7hi^~L5@VI9HuU#fjIFB(t#)o&ht{TqFar~PZ|;Y00fJnh>GD6jEUSAf174_yKJ zn8thmNC8K8<5>!*zZcI^fPO1pYdu~(ce$+Bji<|Y%!{XC+D5z^a~vC=8&mv*YTf5V z^f>KW0_LVk&o#$Tj~_?VZ3&)51{)Iia4CTvpB7-uSNlhL0tEg*yM4}s%+4|Hbsp|5 z(DBZ>)<3^<UOXyF<JTXh)G$&wHj*hBnb|WkwrwPo=bUTH9f`zuM50ecA~BKhgp|tg z`|um^S@;<IH0&g89DW3T7(N8w56`@X0(=I327U}a1S?cX;00db1zskk48IS*0iT7B z!B4|a@);b5AAui+55f1tH{g%qOYnQ}+wgh#JbVs54j+Y&z=z=tyn#3H2HwCM_-n2s zt{twYTrsW*hi||i!<XRq;J4v*_B?bBIu0F$jzEW*zYM<*zX6|xkHJsFPr{GGkH8PZ zhv56+nYU1Y&%n>XkHLq!REO`NGW<UL27DGi20tAVGf6easpbgP9HyEfs@V_UfIo&W z!SBIu!{_1oK03<5$Kj*!5%{ov$H5zT18?9BykR|T*Ad&b!*)GoyJBqD#Dqu#{usUl zzX!h!pNH>qe54G&55EDQg^$5c!*@A8%v+KId<K37ehfYY->pC;Q-<G%-+<4;Q)x3z zV*UjxnFjnZd<lLJejA?RbSY4YPkVuuq0P|7Xdzm+0$p5ONTpJd!^1;)_wJp%dGkg# zH#a4p&&%4{n&fghdHndX#N%<9ot>3vG%8b5Qxb_pWOQ^?!r`zC4Gqb_z<~7i^-1Gz zBR{-&@gM(B@e%Ve+qQL?UCg#mPY-@sPIn>fO2yTmt@=%2SIPeLU^)G4b=40zuL7JN zs9Y}JoxrYQ1bBvu-2v=V2M|Hz%|}0l-~>ypR`b)()Kot?fw=2mF0ZaGFN;*0<^+F@ zhKWvxiCsobpPjv}HY?`j#PzRKYf>{;#?(Y?m47~XTUFq~^>Xy92Uo71PM;kdyk&xB z<$_wN;eYkOJh;MNY{wnF+VtE>MCUgEx@G6*Opo5VKh?jSNG>3MV&~`X)XtrGamSnq zNXG58?iF-*rQVUKncfaFj_&2>5a`!SOKEIjVWHR6z5H5w=1B{1^>%&=;Qyozc>XNL zTfU=b+JL9)0$YIV@6F)qZZ7TodYABbfewGIuNwYKZJ-t3-M<^%0Z7x+Kg#dp`h1jM stF+G3tzSoe?BQ+m>fg%GS%lxs%g;x00{ze5Df)Y)+wT-#t>bsfznDslbN~PV literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/custicon.ico b/mechglue/src/windows/installer/wix/Binary/custicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..878d3ba54b8bfaf2de6ea1e8584bb25726492e5d GIT binary patch literal 2998 zcmc)MKTK*@9Ki9PPm{-FyQ+%|rmO7Q4jq)GF3Qf}Vq;85iorx#6zBjAFKSJUeM3`Q zOkP3<#pm#d113#%Vj#w$5rJ9)mlzu)Z9V;-d-<ncmM;BW5BHw?`<!#{Irnf;q)%SS z=;+6y<M&r0W9&yqbxq_)hsa>R$R`|+Qa+>f$pD`sL2N6m)~#BQB*(#^wd0dRNvG57 zbwZhcqLe<Ou<29!!#2XfC#S>yllNUG9QFFj`$XqND7JQz*k5X&2rt)H68?7G5emgt z_WjjX-m$#AEc?|?JroM6!K%NV_pkn@K<)Z!>79f^q1S%DX&lu+^}~ai_XlIDCZTuL z4{M=dI2^X>UsuaV^@k;fr_8*gdUCY3<{%$3>k>XWYF=$AYz|d7)zP}9L$@W`_506t ze6cM0dLoYd(pU3e{@PW4^v}<C*9{H2^BPdMuIIQnG@x#U<9_uKVCKVS|9%a0`|lpC zx(3uEJ664QKRb<Yb>6yN?l-1(be9as3=SgS=o4M>q;58>eX3OYBWCM0E27^lkJ6_) zMfx9EhI;w2G_4Y3pQhA+57O7)quA#Dmi|62{14^nI%n|{!2xq;ee`u5v##}@-8xTS zrKR@E50b4ZNnR_7W|b^tluV_RI1{XMUE)_FfnyQxmWbOY;+m0c9)E^Ez{l`Dyazi= znZ{4x$MH`55T1UMNqiK)fS<xUvBC@qUhsk!yv#@*e}+H6$M8P92S3Yqa2h{>AICfK zL--p08lS~y@F{!(pTNiQ0lXLQ#=GzeukZ@5@CvW+k8D?L$81|{KDHUt*YMZ)EIxxz z;dSo`bQ~Q(d(m#Ri~jTYGyDNQhWFt;_*wikegZ#^cjAZe^qWlLqxc2<6yDimc6bNn z@n`r0d<^fydz_+XnayctbAs6%XEvS8<`BMyzs6_r8GH(#!1F%3isJ)#FW!xJ>31An z;T2xt6<%>aJgzGq*D;T4i^t{Tam~z#)bQ8%EIxxz;S=~C%SZC~GyDNQhWFt;_#VrL zezTIqNAU~zDZCTkYl5;Wk3Yj7;A41ZT6q|l{RCxsKPA;QK8w%bQ+Ot)#{^~hwkIi3 z$^vDI;-vJNpu4*}DHe-zd3h-p7Z-ARdMby9hmuGnWN&Xz;_<j_Y-~s%5Rk>iMe%yQ zGB-CTZns+|Cnv?_a>>}(m<$gO%i!Rk)c#WP{oA+y@pp=^m`xalp>MNC7)GIx`*}0c zLm0)PmEYdA>%u58`a*6qvc0=&2P!2%A*a*%{L2oE62S$w$r3MsQ80lBNsest1q3Tt z%H^_M{#J+1-`pTxw$JBxcQ-dhN_BNZdwn%RgbCAgX5`66Zg0;^^`g4DvDz0)Wx3Tq z6jTkJ{wa4}(%_Cu5Kr@w$ZalnP6zek9do6ltGyUzbMmEnvpECl^e<AW&^`I?=TrLA z99MHVe-M?5)wTIqe)g!#`er*(B;OpL1<PunE0oT+#%BWZkL&9ZVr6Azz&0O!(*pMS zH*H{_kG4TGuLszATwI@Yvj;2xWQ63`+n}rcZByxd8?>(9Q0htE1Prs8Z;Uj$^UvpJ rWJHZLI_*1?%Ta6oMjEZVtUL?mS4Ri5;In<ZgJ<XUdz|<m|4;cB3zdW( literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/dlgbmp.bmp b/mechglue/src/windows/installer/wix/Binary/dlgbmp.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b67c6c246e1293864b3e5c6346cc060d9ff19db1 GIT binary patch literal 474822 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%0D45f&W1QfIIu_ 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 G`Tqyg)F|r! literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/exclamic.ico b/mechglue/src/windows/installer/wix/Binary/exclamic.ico new file mode 100644 index 0000000000000000000000000000000000000000..906ce3246dba72e290f6a3008b19ea129233f213 GIT binary patch literal 766 zcma))v2KGv42DfF5@Q-6bq#75ItJXmsN}tJkH(`gX3Ur&iu>EX>!nOJ`Z@mdeYQam zRk+&rl{79dL~mF>pcWdTiZ-|tMda2o&ojjsk%TlveEsL0x!;v&m<N7}9dmaoG4{<+ z9G*h<qi;{y^QUcOKl0IhXi~kD@3VJ)?9tyVIgbABr;Mk8!bUfMCx7T*6;FWGpMbmf z{^+iOqu*B6aPt#$#tks<c<~8W!14*t-n(mq;iUaC?i1*@(wv13>%$jca0d$R{t35{ zf4ggmF1@>#Q{c~W=J!KRt=1b+y%2>Nzgb*K_n@%2>MPDdTQI8q-Szb#Ql0VVsYIfx W5}8#&WKq>3SJhVJwimgdMdJrzKB>e2 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/info.bmp b/mechglue/src/windows/installer/wix/Binary/info.bmp new file mode 100644 index 0000000000000000000000000000000000000000..7e0ff7f14c24ace2d59e24260b666ca60ef57482 GIT binary patch literal 1078 zcmbW0y-ve06opR-l9@=}pq)_PqC8SIv&9<=QeMd$43&6=ZZKveLsj!#J1I(4B!t`J z>vMnI>sx818*Mg?Y<=EH56Gq|e7lnFD`|^v10KOjx9n2D_xcJLv4l_rJ4X-{W5kg1 zS1H*E@G+Hb^K$KcD$-x@3wwRR(}KHt!M%rjKNlc%Z+ucX-Eos3KbP#GDUB#{M4>2L zcBr$}wjn#5X(DH<4u0ITvP0`~GzxPggEMIkSvvo;;K6qbKKzec{hViLOa4sQLR;$3 z+^O8}W&dWXk>A_dVTvE%Ibh<s9p+H{&5XmjKhul(q8NYrZI^gHQ$pzd<ebt6##eIy z6gz<t#5^Lqle9icHCJ=gs}77~1cAziUlvoGeX2lQB>q4i;&<ff$j9VWDIM0y=DYzL zFwc49e0_ydl)2^v_?U|APjl`F;y!hjPN{Ha(V9WmM31ajqnqAoFv(lyIXJ%4ppN00 y<bIL_Bzq?GgT2PsBW17fWqC`lQ!kxrX#@jx5B$d?T?z)g7Rz+l4H4gAEqw#;leS<0 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/insticon.ico b/mechglue/src/windows/installer/wix/Binary/insticon.ico new file mode 100644 index 0000000000000000000000000000000000000000..94753ac296389ae5b90e56608a5fd1882692985f GIT binary patch literal 2998 zcmc)MKWH0g9LDjV6N8TqPFH90BGc8{op$J8YpEB<y9O^V!64`f8DcGoWC{`}I9ZIz zQ2IxLfI1l2UPJ~NN|Q;02_AxENp%nT4&!o$1i$^h?@970l}fk1m-p^oJ)ifz_uf0n z5t)!XGCTXZ=<>%MkvWdDv$`envn4WpSL6%MXQ^LNCuEYnNE+KOLGOMmO~`pV9URzm zD%EP0qYjk$CrarvDx3aD?}B1w`)B58Wj2pq2A^bnPb9x(9~FZS@>?5eE9rkYEZPQ; zC#_80KKv<YlV`HYq<?5Xey@SfGnq{Kv&R>v-OKNJ7oCkkZeQH<FuJYt%th+Gl}wsE zue@Zg^U6{ETzQ#n>ca7_lbVapldmq0wze`;HdCN&+d1dR*7LU0LEHNN$lkEB*?#-p zbvB#l_ElQ4*|cpFnZguI+l;Jt8<tYnQ?_LXB}uFSpPHhlU}dvY*45X#d}F2ru&z4a zt$q7@&<0yqH}=|EudOd}<!TV*dW@?Z4MJ^KgHZdi2BEgCLAb3!s2!S*9zQf+nqqE4 z--@W4DOJ6mP}L1l)mho9im6|6998e~`2<xyt!e$5Qm?5WsW(*Kt_gMhFZH9`9e&Sw z`6=m1a|m{N)ImuT(%_vo2lkwr_q=*q74NqnrS2&yH<aY+O4e&i7As03MP{OF;Z!7b zAQFEr5=)3gm!;msALC2-JU)S6#ja47@C*2Pd;~v(XWVibpTn=?7x59SaL0ldyx;{d z%hJRj<4gEFK7n7wukamQ!Y|<G@e%wC-orQWb$kt9!58sGd;y=r$MG?I6tD0KukZ@5 z@Ctv!cFK0Z_M9!jwrsqIZ{X|r8oq+pqZiQybP63u$Iwy6Z{m;fC43&Az^~$0@Jsjw z{5(E_pTRS3xs1=@*YS(^$e7jPH>im}#+UGUd;-535w*f<F0q;mtmZtc8DTYN@E*Q_ zuj6a@3ciRh;tTi`K8}y!qxv@vukZ@5@CvV(50C4V$92Htdd}lY@VJ(jMLc{1U&q(* z6?_pt=Jk;#{up1v=kW>rDt^rC!?<-R<8%0R{31SrAGbht)x;m;OZYsVl~$|V*yshS zD-Ykm*YP!c1<&G)S)e+91IpAKb)C9MjZnue(B<W&wA*cY_wJp%efw5kzkV(I`}<NX z7G-a5PYQ*CJbn69QmK?Ydh|%*@whyE_)uc8m^^s!K%&v8%+1Zo{rmT2dU{&C4@!P` z`SQR1o#H!XitD<1CS!{0wpu5@?raYUr=?o@dn)3#+d=+fH#CGp+!BYl!wt4hcD7&a z?uJ0n-*=?j0klqZ+-%+s(ChEJ9SRqCK}s2bet)-RfCwRHw|Q`VpSdG=NyTxTaBk-B zJMOtIIzKx@{Ih?vxx2fwBhvBJS-8Lc8zA&=l5U@$zv=jGb#@l&uX6{W<6lnRbTk;m z;`I9a?#}l1`N_!}2JqXLtQD^VrI-7@@0#x99p7|scUaX>F5ND}lV4tP1CG;ff08Tp zC#BofS2V@snhL}FdSQl&8J}0eb%R__XQ*`k3NEh<5Uw~>7``{28KGzU7guI_dORn% z1o>pB+~z%?^P4A6wkeyNo0FkD7+L4JXMHe~2lEg$`D_4&b8}m!e;<s_>E8pR^Ctr^ lCLe%txdGhf=zR40^d5?NRR+r&UY{Q5ep2}P`k()w@;93z)Y<?5 literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/new.bmp b/mechglue/src/windows/installer/wix/Binary/new.bmp new file mode 100644 index 0000000000000000000000000000000000000000..27881dfe972209bb5825c15cb7bc00bbde46c7c2 GIT binary patch literal 318 zcmZQzU<5(|0RaXO&|qX>5ChRb3=&ZQVnzlQAj!bc04A{!KpBu^Lj!~Yl0YWIfddDC zG)Uq<7%}|+4`Kl^5Q2n21UlFa1RH>Y#L_VR++bZW9?>+&2@U*cm>0<B24Z#~mIC_Y TIs?PQ)j;>w0`Ys0yAd=1E8#zj literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/removico.ico b/mechglue/src/windows/installer/wix/Binary/removico.ico new file mode 100644 index 0000000000000000000000000000000000000000..097cafe274a9b8e05bd6e4bc6fa92abe56c40b51 GIT binary patch literal 2998 zcmc)ML1^1n7zgk#O+oG@9b|%~8!Qtz?AUmN6-JsJx-Ic3mo%5cz|a_!I1adu=eXFe zx7s<`!G|784`U4HWCm?|7z<_CWt6gm38UmNq}ZyQ$TnW^3vBr9FUd}v#)cgRd&-ma z-uL^S<fo_DL_>6e#>d|xv%J1QG=byzxY;85!9g@KO!Ohn$5B5+9iofa6UAY>#m?@w z;t1kA9=8wJ<CJ!Gc5pNU-1;NV%`;SNW|z4;Uj+2WR!{l`hBjlY)8Pok(B`pF$nJ2Y z5O0Ur;&Z#hinmj1Yn=`|{(5C`aXDoQJ6@@5gzgqYakQ=cTE!a+J-6EC`0W}x*xfhc zcH547aYsGzN(?s?I?eZTcIU>8lYAaU{KYRPaUKn^&|SN2UZ1tKP^i!oXO+tGa!;H` z7Z+dLIn8HmZP{zLQ|5)O(i7))kNNpxU*EX3k%}?1$7~;eiIbswsaQy`+DEtB?bT0X zLmTKY<BheiwBaX>NaUT&D%x}}bo=PtnBe{Si6et1Io@Bp^}*HXTIA199M)61$DTKS z^K<WytJkcy<Gq*=`Pko@9{%0*7@;xxljCjw(Y3hMB!?q@^_!2raBQI2rWik_%e+Cu z{0}S%)M?bqr~>Nne^nb8>lpQK)HcS(%Dc?tG<|lRJIE~Yi`K#34fUK;96_|>ar=Nh zPOWvmv$sQyU%#hPgHvANlrC{vDsY<F=H$%bYG%#u5v@NZ@;o4N2Z&sAR8rxK@LTX1 z_yGI@>^$l${1p5oyc2#59^>Zo@M-uZ_!)R7EM}4jp5O_d;AxIj_#*rkd<H%MzW_gv zcW@Sd3Vssa2|otkfLGv4@CEp7_#Au=J`2AN?}2y2yWlxIhv)Ddp2KtaHnu%%Pq96~ z7Qi-V`3AfKUxF{dZ^N6T=b*FD>(Cx(H?#}mtMEnmE%*$40Db{}9)1>n3Vssa2|osp zar1fjH2f0$47_u|>|nvE@J0A7_zZjie!)q69<w=%*_^^`PGUBln9VWx2D}1af-k^t z!{^|0@LBkEcn`cA-evxegXi!Zp2Kr^j{Cvm+QZ{|ipTW;k1K%3H8)4pfLGv4@CEp7 z_#FIz<wGib5q=9k10R52fFH1YFm8$R@M-uZ_!)R7{GbUcaTUG@zXhLx$4v7De6ao# zRKlB_=L&oYz5u@skI5M@K_z?#<WbY8OQ<ubPSimY)ND4XQmN3ZSFh;h%a`=**)w|l z_%Y>jIePf;A!V~!N+y%EzP?T?D=Xyjc<AQMo8)%8>H78S<Z`)aVq$`>T)9FcBO}!K zi_>?H9{t<zsj9A7rCP<?b*?Z?Ra<6JTB@d<BgaB{Us0^EqN<59J1Y#P$#%Y^v;ZWz zd}a)z+RaZ&iYn=bVU*>bF;4UECtFeq#TU_KjU9IG^EChdrj$yC!#*E?#`LBQdh$1| zuq?@bKY-5$z4^&x*k|6L>^B%Y=)_O%|Ndq>8BY0pk}T-azWMEB%FfrKee%EEOoq+R zk9@gb{$@Cd`LnLCX?^lrWqba75q~tQpTB>l+{usl{r#@rDkpXO`UCP?$&{{3k~}D1 zDdW>eB4)Vn^;;d_k81cK(KCPLeYIQk6w(FR+k5|-U>17`mdi5!&g8Rwb+=O_2@?Y@ zV}iQRkL~J4vsp8+nJZNi1dyKj+clc((mpmVC>o-{%BsY4{Lbm-?>3DZPb3mrU6&<Q z6AeSNMCbkwcZ19X`&QTp)+9+ZbaSD07g$r10qQ|yi{VRQkxNq0sH)usNX9`+HtOs^ z4Av9-2@?dvVevrf<P#aJB{NZ!%Rw=LJGq2Wg0%zTBn}{oOitHFb+O9R807OBtDc52 p!l5zB>rFg7qYlv=Jv59r-{Vm-j8Q=hzOLgH>qP(8-zi5l{SUV)2I>F+ literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/repairic.ico b/mechglue/src/windows/installer/wix/Binary/repairic.ico new file mode 100644 index 0000000000000000000000000000000000000000..6fb68610c9af370020f00cd1d0ff589db8d19b6d GIT binary patch literal 2998 zcmc(hKTI1}9LIkLNO-6SohX@5C8MZPrQ)5mLkI9u7GU>~g(^a_R3jsWTgaIXxN=0Y zpeRGtv_^{L4us$;K_~)IHJLo1hynS}Ij+HWz{R1J{Q7x!ws8_Hb?fi=y?ej=etz%W z{ocDXB8GIy&``f<d)*~6%z0=?M<PFaMEbf#uF)UDzrqdap%pP<o91RWBNLInX}Tv` zy0W#k#aRo=`4gpd59iRAbmLgWY;+o7D7o2o!BeZvZ^kb!SkZ-K{NZftLS(Ks9}hL+ zuD`EYR&@ShsO0Lzb8~a@uyheymZ|zmp_U%Hb*MZrj=|r`KN8EbdP5-?;!?Qu?5(4R zOyVKyQR&%&Wkw<qH~zj<d|Z1w%i}0Ve_KjEURdy;TTXl)Nj`4OHmmc``*o@|=Im0l z=lvd?i|Kp#)F7^Yt?e5fUojSb@Kp2P-T3woC+?Mx(d(fbH{4jn5>K_P0Y{IRI<9Mg z*b*kGplg6QYSltf^jjLxaYU&KaYzHi5s5^4b*uqmZF;<m`w>sbY`<R}ljNGlJvCFG zTJ}NQzS^qtrBYj0s9Z0*p<BJd55;J6={{r&;&O=_haNF14S(~A7~1=ZMLT`%U*HO_ zbFKc7bk~`#>F@4yHa}+eI48F;+WKN55}T%bqNVHX^R0s|sr>$vq$)}hX(h`kB{Mrp z#x|6A<Lq<ou>+Ct6Oq7O5r0s`HzBDE{4V?&d=x$iKMgyHkHe3`kHCB32jLkvk$_)@ zpMf8P_rgjYhZlH(7kHVF4E!$q8hjK!2tN%!$vZd>KMFqr?}Z<PufV6_Q}8?R8}M=X zID8B~3?G2^!~5VByn<Ko3SPl0_&Ub{#}kgb96^o=hp)h=;ZyKC@Eh=Y^f+`3It(3v z_Cxy^KLfuDzXl(L55iBwPr{GGkHU|@d*KJ+88?xDUxuH7AA|RHs1Dzt4E!$q8hjK! z2tVx=HAywcspcrv9HE+CsyPT>fltGy;CJ9R;N$RopAKU1VfX;NAKs_GaqtRW!7F$L zuecwU>wx8Y!gAeZxq>X$#Dqu%J`JCO-+|wNkHdG^K9Ygog<pe@!Uy4};X7;}#!X2A zei?oSehl6V->E<;m4V-dUxSarQ)xBLgI!*r6kn5sO2en%ci=bRDNct1rFiQT_%c3& zkKtatQ-MxSPQ<otdG+d*ynOjmwzs!seSKZx@wnW-e_vv;nB2a7Tf*V6+`M^H0)c=` zO-+g4@0aV>uZz#;li}fExq9`g^!4>g<sT(KK6vmSf2Vk*uyVPqZ=-{i%embCuPaL( zh_Y?F`n}c5hA8KGy4?QC(!JHy_kq2=Jvq(;<o30k$-Fy2^6B<wIgc^HJyh%+Ao=w9 zW;y2oB8c?f)5*`}AlRW&EEYe|$uDTrdNvF3VSXmFy1KF=lCP;O`Fb|YDU~yS26d@W zc#*H!Dw}ol?R-%K`u_LITK;AKMP36ZOo6rZ=UQJ{D(vsSV1Sx^Lans5<qwpdbo6|! zk<Np-<DZc~aDIHu@aXO9lmAQ4f5!X+=bwH4Cw6@74(+r~I{MjfjxI&#$GX+nt}e;s zsiE`Hd)iDj^-B8GPy^?VUSC{X!sh4adoJ|+sTc-7IOH$iX##Ef$*B}=YKDHN1-N>( zT9u=tqiWHn<K#C1S1)AWRA1Y#kE+$Qqm$nN8hW~r&DsFSI)AYRH1xAVA)Vo<y7Mo# zfQDWW(OaXMYw8ZbW4gMt189nR%^APVTF;MMuybsx4)xVK+l~Q_-?QfEQcya-vlY@# Qen&t*!ln8D_x~yX0&_g1<NyEw literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/Binary/up.bmp b/mechglue/src/windows/installer/wix/Binary/up.bmp new file mode 100644 index 0000000000000000000000000000000000000000..86f6b5a84755483dee8175ebc821d3af0ce866b8 GIT binary patch literal 318 zcma)&F%Ez*3<F(>jinPaBfq3iVrS`7_(?ej5C}1lG<M>oRa7bAIcM3XBn@W5%19)2 zpi~0CfR3A`90Zc8)(X4P;;1!e1a8Ujwl!?g%}lJWd!z?T2-Gq9(9iqVy9{0F7kh<5 P<5%!Eb(Xf+-TO;BySGdd literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/installer/wix/ChangeLog b/mechglue/src/windows/installer/wix/ChangeLog new file mode 100644 index 000000000..38f463566 --- /dev/null +++ b/mechglue/src/windows/installer/wix/ChangeLog @@ -0,0 +1,43 @@ +2005-12-30 Jeffrey Altman <jaltman@mit.edu> + + Remove impersonation from the network provider installation + to allow installation on Vista + +2005-11-01 Jeffrey Altman <jaltman@mit.edu> + + Add support for Network Identity Manager Framework + + Move leash32.exe to component that is disabled by default + +2004-12-18 Jeffrey Altman <jaltman@mit.edu> + + Add Debug Symbols as an optional install feature for + release builds of KFW + +2004-12-15 Jeffrey Altman <jaltman@mit.edu> + + Add kcpytkt.exe, kdeltkt.exe, k5sprt32.dll mit2ms.exe + + Update to Wix 2.1 installer + +2004-09-16 Jeffrey Altman <jaltman@mit.edu> + + Remove trailing slash from PATH + + Minimize Leash32.exe on startup + + Update msi-deployment guide to explain how to replace + the configuration files in greater detail + +2004-09-14 Asanka Herath <asanka@mit.edu> + + Change installation default of Documentation to enable it + +2004-09-12 Asanka Herath <asanka@mit.edu> + + Updates to Wix installer to satisfy the needs of MIT SWRT + Add msi-deployment-guide.txt + +2004-08-20 Asanka Herath <asanka@mit.edu> + + New WiX 2.0 MSI for KFW \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/Makefile b/mechglue/src/windows/installer/wix/Makefile new file mode 100644 index 000000000..02de33ca7 --- /dev/null +++ b/mechglue/src/windows/installer/wix/Makefile @@ -0,0 +1,59 @@ + +# Build language +LANG=1033 + +# Program macros +CANDLE=candle -nologo + +LIGHT=light -nologo + +CD=cd + +RM=del + +MAKE=nmake -nologo + + +# Targets + +OUTPATH=. + +OBJFILE=$(OUTPATH)\kfw.wixobj + +MSIFILE=$(OUTPATH)\kfw.msi + +WIXINCLUDES= \ + config.wxi \ + features.wxi \ + files.wxi \ + property.wxi \ + site-local.wxi \ + lang\strings_$(LANG).wxl \ + lang\ui_$(LANG).wxi \ + lang\config_$(LANG).wxi + +CUSTOMDLL=custom\custom.dll + +all: $(MSIFILE) + +$(OBJFILE): kfw.wxs $(WIXINCLUDES) + $(CANDLE) -out $@ kfw.wxs \ + "-dDate=%DATE%" \ + "-dTime=%TIME%" \ + -dBuildLang=$(LANG) + +$(MSIFILE): $(OBJFILE) $(CUSTOMDLL) + $(LIGHT) -out $@ $(OBJFILE) \ + -loc lang\strings_$(LANG).wxl + +$(CUSTOMDLL): custom\custom.cpp + $(CD) custom + $(MAKE) -f custom.cpp + $(CD) .. + +clean: + $(RM) $(OBJFILE) + $(RM) $(MSIFILE) + $(CD) custom + $(MAKE) -f custom.cpp clean + $(CD) .. diff --git a/mechglue/src/windows/installer/wix/config.wxi b/mechglue/src/windows/installer/wix/config.wxi new file mode 100644 index 000000000..fa756bbb2 --- /dev/null +++ b/mechglue/src/windows/installer/wix/config.wxi @@ -0,0 +1,161 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + + Copyright (C) 2004 by the Massachusetts Institute of Technology. + All rights reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization contemplating + export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of M.I.T. not be used in advertising or publicity pertaining + to distribution of the software without specific, written prior + permission. Furthermore if you modify this software you must label + your software as modified software and not distribute it in such a + fashion that it might be confused with the original M.I.T. software. + M.I.T. makes no representations about the suitability of + this software for any purpose. It is provided "as is" without express + or implied warranty. + + --> +<Include xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> + + <!-- include site sepecific customizations --> + <?include site-local.wxi?> + + <!-- Sanity checks --> + <?ifndef var.CL1200?> + <?ifndef var.CL1300?> + <?ifndef var.CL1310?> + <?ifndef var.CL1400?> + <?error Must define one of CL1200, CL1300, CL1310 or CL1400?> + <?endif?> + <?endif?> + <?endif?> + <?endif?> + + + <?define KfwRegRoot="SOFTWARE\MIT\Kerberos"?> + + <?define BinDir="$(var.TargetDir)bin\i386\"?> + <?define DocDir="$(var.TargetDir)doc\"?> + <?define IncDir="$(var.TargetDir)inc\"?> + <?define LibDir="$(var.TargetDir)lib\i386\"?> + <?define InstallDir="$(var.TargetDir)install\"?> + <?define SystemDir="$(env.SystemRoot)\System32\"?> + + <?include lang\config_$(var.BuildLang).wxi?> + + <!-- Parameters for the features containing debug symbols --> + <?ifdef DebugSyms?> + <?ifdef Debug?> + <?define DebugSymInstallDefault="followParent"?> + <?define DebugSymLowLevel="30"?> + <?define DebugSymHighLevel="130"?> + <?else?> + <?define DebugSymInstallDefault="followParent"?> + <?define DebugSymLowLevel="130"?> + <?define DebugSymHighLevel="130"?> + <?endif?> + <?endif?> + + <!-- Configuration macros --> + <?ifndef LeashAfsStatus?> + <?define LeashAfsStatus="1"?> + <?endif?> + <?ifndef LeashCreateMissingConfig?> + <?define LeashCreateMissingConfig="0"?> + <?endif?> + <?ifndef LeashAutoRenewTickets?> + <?define LeashAutoRenewTickets="1"?> + <?endif?> + <?ifndef LeashLockFileLocations?> + <?define LeashLockFileLocations="0"?> + <?endif?> + <?ifndef LeashMsLsaImport?> + <?define LeashMsLsaImport="2"?> + <?endif?> + <?ifndef LeashLifetime?> + <?define LeashLifetime="0"?> + <?endif?> + <?ifndef LeashRenewTill?> + <?define LeashRenewTill="0"?> + <?endif?> + <?ifndef LeashRenewable?> + <?define LeashRenewable="0"?> + <?endif?> + <?ifndef LeashForwardable?> + <?define LeashForwardable="1"?> + <?endif?> + <?ifndef LeashNoAddresses?> + <?define LeashNoAddresses="1"?> + <?endif?> + <?ifndef LeashProxiable?> + <?define LeashProxiable="0"?> + <?endif?> + <?ifndef LeashPublicIp?> + <?define LeashPublicIp="0"?> + <?endif?> + <?ifndef LeashUseKrb4?> + <?define LeashUseKrb4="1"?> + <?endif?> + <?ifndef LeashHideKinitOptions?> + <?define LeashHideKinitOptions="0"?> + <?endif?> + <?ifndef LeashLifeMin?> + <?define LeashLifeMin="5"?> + <?endif?> + <?ifndef LeashLifeMax?> + <?define LeashLifeMax="1440"?> + <?endif?> + <?ifndef LeashRenewMin?> + <?define LeashRenewMin="600"?> + <?endif?> + <?ifndef LeashRenewMax?> + <?define LeashRenewMax="43200"?> + <?endif?> + <?ifndef LeashUppercaseRealm?> + <?define LeashUppercaseRealm="1"?> + <?endif?> + <?ifndef LeashTimeHost?> + <?define LeashTimeHost="time"?> + <?endif?> + <?ifndef LeashPreserveKinitOptions?> + <?define LeashPreserveKinitOptions="0"?> + <?endif?> + <!-- These actually have no defaults. --> + <?ifndef Krb4KrbRealms?> + <?define Krb4KrbRealms=""?> + <?endif?> + <?ifndef Krb4KrbConf?> + <?define Krb4KrbConf=""?> + <?endif?> + <?ifndef Krb4ConfigDir?> + <?define Krb4ConfigDir=""?> + <?endif?> + <?ifndef Krb4TicketFile?> + <?define Krb4TicketFile=""?> + <?endif?> + <?ifndef Krb5Config?> + <?define Krb5Config=""?> + <?endif?> + <?ifndef Krb5CcName?> + <?define Krb5CcName=""?> + <?endif?> + <?ifndef Krb5PreserveIdentity?> + <?define Krb5PreserveIdentity="1"?> + <?endif?> + + <!-- If neither NetIDMgr or Leash is specified, we default to NetIDMgr --> + <?ifndef UseNetIDMgr?> + <?ifndef UseLeash?> + <?define UseNetIDMgr="1"?> + <?endif?> + <?endif?> +</Include> \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/custom/ChangeLog b/mechglue/src/windows/installer/wix/custom/ChangeLog new file mode 100644 index 000000000..f8aa27c9a --- /dev/null +++ b/mechglue/src/windows/installer/wix/custom/ChangeLog @@ -0,0 +1,3 @@ +2004-08-20 Asanka Herath <asanka@mit.edu> + + New WiX 2.0 MSI for KFW \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/custom/custom.cpp b/mechglue/src/windows/installer/wix/custom/custom.cpp new file mode 100644 index 000000000..fdf4bbbd2 --- /dev/null +++ b/mechglue/src/windows/installer/wix/custom/custom.cpp @@ -0,0 +1,741 @@ +#ifdef __NMAKE__ + +# NMAKE portion. +# Build with : nmake /f custom.cpp +# Clean with : nmake /f custom.cpp clean + +# Builds custom.dll + +OUTPATH = . + +# program name macros +CC = cl /nologo + +LINK = link /nologo + +RM = del + +DLLFILE = $(OUTPATH)\custom.dll + +DLLEXPORTS =\ + -EXPORT:EnableAllowTgtSessionKey \ + -EXPORT:RevertAllowTgtSessionKey \ + -EXPORT:AbortMsiImmediate \ + -EXPORT:UninstallNsisInstallation \ + -EXPORT:KillRunningProcesses \ + -EXPORT:ListRunningProcesses \ + -EXPORT:InstallNetProvider \ + -EXPORT:UninstallNetProvider + +$(DLLFILE): $(OUTPATH)\custom.obj + $(LINK) /OUT:$@ /DLL $** $(DLLEXPORTS) + +$(OUTPATH)\custom.obj: custom.cpp custom.h + $(CC) /c /Fo$@ custom.cpp + +all: $(DLLFILE) + +clean: + $(RM) $(DLLFILE) + $(RM) $(OUTPATH)\custom.obj + $(RM) $(OUTPATH)\custom.exp + +!IFDEF __C_TEXT__ +#else +/* + +Copyright 2004,2005 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +/************************************************************** +* custom.cpp : Dll implementing custom action to install Kerberos for Windows +* +* The functions in this file are for use as entry points +* for calls from MSI only. The specific MSI parameters +* are noted in the comments section of each of the +* functions. +* +* rcsid: $Id$ +**************************************************************/ + +#pragma unmanaged + +// Only works for Win2k and above +#define _WIN32_WINNT 0x500 +#include "custom.h" + +// linker stuff +#pragma comment(lib, "msi") +#pragma comment(lib, "advapi32") + + +void ShowMsiError( MSIHANDLE hInstall, DWORD errcode, DWORD param ){ + MSIHANDLE hRecord; + + hRecord = MsiCreateRecord(3); + MsiRecordClearData(hRecord); + MsiRecordSetInteger(hRecord, 1, errcode); + MsiRecordSetInteger(hRecord, 2, param); + + MsiProcessMessage( hInstall, INSTALLMESSAGE_ERROR, hRecord ); + + MsiCloseHandle( hRecord ); +} + +#define LSA_KERBEROS_KEY "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos" +#define LSA_KERBEROS_PARM_KEY "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Parameters" +#define KFW_CLIENT_KEY "SOFTWARE\\MIT\\Kerberos\\Client\\" +#define SESSKEY_VALUE_NAME "AllowTGTSessionKey" + +#define SESSBACKUP_VALUE_NAME "AllowTGTSessionKeyBackup" +#define SESSXPBACKUP_VALUE_NAME "AllowTGTSessionKeyBackupXP" + + +/* Set the AllowTGTSessionKey registry keys on install. Called as a deferred custom action. */ +MSIDLLEXPORT EnableAllowTgtSessionKey( MSIHANDLE hInstall ) { + return SetAllowTgtSessionKey( hInstall, TRUE ); +} + +/* Unset the AllowTGTSessionKey registry keys on uninstall. Called as a deferred custom action. */ +MSIDLLEXPORT RevertAllowTgtSessionKey( MSIHANDLE hInstall ) { + return SetAllowTgtSessionKey( hInstall, FALSE ); +} + +UINT SetAllowTgtSessionKey( MSIHANDLE hInstall, BOOL pInstall ) { + TCHAR tchVersionString[1024]; + TCHAR tchVersionKey[2048]; + DWORD size; + DWORD type; + DWORD value; + HKEY hkKfwClient = NULL; + HKEY hkLsaKerberos = NULL; + HKEY hkLsaKerberosParm = NULL; + UINT rv; + DWORD phase = 0; + + // construct the backup key path + size = sizeof(tchVersionString) / sizeof(TCHAR); + rv = MsiGetProperty( hInstall, _T("CustomActionData"), tchVersionString, &size ); + if(rv != ERROR_SUCCESS) { + if(pInstall) { + ShowMsiError( hInstall, ERR_CUSTACTDATA, rv ); + return rv; + } else { + return ERROR_SUCCESS; + } + } + + _tcscpy( tchVersionKey, _T( KFW_CLIENT_KEY ) ); + _tcscat( tchVersionKey, tchVersionString ); + + phase = 1; + + rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, tchVersionKey, 0, ((pInstall)?KEY_WRITE:KEY_READ), &hkKfwClient ); + if(rv != ERROR_SUCCESS) + goto cleanup; + + phase = 2; + + rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T( LSA_KERBEROS_KEY ), 0, KEY_READ | KEY_WRITE, &hkLsaKerberos ); + if(rv != ERROR_SUCCESS) + goto cleanup; + + phase = 3; + + rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T( LSA_KERBEROS_PARM_KEY ), 0, KEY_READ | KEY_WRITE, &hkLsaKerberosParm ); + if(rv != ERROR_SUCCESS) { + hkLsaKerberosParm = NULL; + } + + if(pInstall) { + // backup the existing values + if(hkLsaKerberosParm) { + phase = 4; + + size = sizeof(value); + rv = RegQueryValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size ); + if(rv != ERROR_SUCCESS) + value = 0; + + phase = 5; + rv = RegSetValueEx( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value)); + if(rv != ERROR_SUCCESS) + goto cleanup; + } + + phase = 6; + size = sizeof(value); + rv = RegQueryValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size ); + if(rv != ERROR_SUCCESS) + value = 0; + + phase = 7; + rv = RegSetValueEx( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value)); + if(rv != ERROR_SUCCESS) + goto cleanup; + + // and now write the actual values + phase = 8; + value = 1; + rv = RegSetValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value)); + if(rv != ERROR_SUCCESS) + goto cleanup; + + if(hkLsaKerberosParm) { + phase = 9; + value = 1; + rv = RegSetValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value)); + if(rv != ERROR_SUCCESS) + goto cleanup; + } + + } else { // uninstalling + // Don't fail no matter what goes wrong. This is also a rollback action. + if(hkLsaKerberosParm) { + size = sizeof(value); + rv = RegQueryValueEx( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size ); + if(rv != ERROR_SUCCESS) + value = 0; + + RegSetValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value)); + } + + size = sizeof(value); + rv = RegQueryValueEx( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size ); + if(rv != ERROR_SUCCESS) + value = 0; + + RegSetValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value)); + + RegDeleteValue( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ) ); + RegDeleteValue( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ) ); + } + + // all done + rv = ERROR_SUCCESS; + +cleanup: + if(rv != ERROR_SUCCESS && pInstall) { + ShowMsiError(hInstall, 4005, phase); + } + if(hkKfwClient) RegCloseKey( hkKfwClient ); + if(hkLsaKerberos) RegCloseKey( hkLsaKerberos ); + if(hkLsaKerberosParm) RegCloseKey( hkLsaKerberosParm ); + + return rv; +} + +/* Abort the installation (called as an immediate custom action) */ +MSIDLLEXPORT AbortMsiImmediate( MSIHANDLE hInstall ) { + DWORD rv; + DWORD dwSize = 0; + LPTSTR sReason = NULL; + LPTSTR sFormatted = NULL; + MSIHANDLE hRecord = NULL; + LPTSTR cAbortReason = _T("ABORTREASON"); + + rv = MsiGetProperty( hInstall, cAbortReason, _T(""), &dwSize ); + if(rv != ERROR_MORE_DATA) goto _cleanup; + + sReason = new TCHAR[ ++dwSize ]; + + rv = MsiGetProperty( hInstall, cAbortReason, sReason, &dwSize ); + + if(rv != ERROR_SUCCESS) goto _cleanup; + + hRecord = MsiCreateRecord(3); + MsiRecordClearData(hRecord); + MsiRecordSetString(hRecord, 0, sReason); + + dwSize = 0; + + rv = MsiFormatRecord(hInstall, hRecord, "", &dwSize); + if(rv != ERROR_MORE_DATA) goto _cleanup; + + sFormatted = new TCHAR[ ++dwSize ]; + + rv = MsiFormatRecord(hInstall, hRecord, sFormatted, &dwSize); + + if(rv != ERROR_SUCCESS) goto _cleanup; + + MsiCloseHandle(hRecord); + + hRecord = MsiCreateRecord(3); + MsiRecordClearData(hRecord); + MsiRecordSetInteger(hRecord, 1, ERR_ABORT); + MsiRecordSetString(hRecord,2, sFormatted); + MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecord); + +_cleanup: + if(sFormatted) delete sFormatted; + if(hRecord) MsiCloseHandle( hRecord ); + if(sReason) delete sReason; + + return ~ERROR_SUCCESS; +} + +/* Kill specified processes that are running on the system */ +/* Uses the custom table KillProcess. Called as an immediate action. */ + +#define MAX_KILL_PROCESSES 255 +#define FIELD_SIZE 256 + +struct _KillProc { + TCHAR * image; + TCHAR * desc; + BOOL found; + DWORD pid; +}; + +#define RV_BAIL if(rv != ERROR_SUCCESS) goto _cleanup + +MSIDLLEXPORT KillRunningProcesses( MSIHANDLE hInstall ) { + return KillRunningProcessesSlave( hInstall, TRUE ); +} + +/* When listing running processes, we populate the ListBox table with + values associated with the property 'KillableProcesses'. If we + actually find any processes worth killing, then we also set the + 'FoundProcceses' property to '1'. Otherwise we set it to ''. +*/ + +MSIDLLEXPORT ListRunningProcesses( MSIHANDLE hInstall ) { + return KillRunningProcessesSlave( hInstall, FALSE ); +} + +UINT KillRunningProcessesSlave( MSIHANDLE hInstall, BOOL bKill ) +{ + UINT rv = ERROR_SUCCESS; + _KillProc * kpList; + int nKpList = 0; + int i; + int rowNum = 1; + DWORD size; + BOOL found = FALSE; + + MSIHANDLE hDatabase = NULL; + MSIHANDLE hView = NULL; + MSIHANDLE hViewInsert = NULL; + MSIHANDLE hRecord = NULL; + MSIHANDLE hRecordInsert = NULL; + + HANDLE hSnapshot = NULL; + + PROCESSENTRY32 pe; + + kpList = new _KillProc[MAX_KILL_PROCESSES]; + memset(kpList, 0, sizeof(*kpList) * MAX_KILL_PROCESSES); + + hDatabase = MsiGetActiveDatabase( hInstall ); + if( hDatabase == NULL ) { + rv = GetLastError(); + goto _cleanup; + } + + // If we are only going to list out the processes, delete all the existing + // entries first. + + if(!bKill) { + + rv = MsiDatabaseOpenView( hDatabase, + _T( "DELETE FROM `ListBox` WHERE `ListBox`.`Property` = 'KillableProcesses'" ), + &hView); RV_BAIL; + + rv = MsiViewExecute( hView, NULL ); RV_BAIL; + + MsiCloseHandle( hView ); + + hView = NULL; + + rv = MsiDatabaseOpenView( hDatabase, + _T( "SELECT * FROM `ListBox` WHERE `Property` = 'KillableProcesses'" ), + &hViewInsert); RV_BAIL; + + MsiViewExecute(hViewInsert, NULL); + + hRecordInsert = MsiCreateRecord(4); + + if(hRecordInsert == NULL) { + rv = GetLastError(); + goto _cleanup; + } + } + + // Open a view + rv = MsiDatabaseOpenView( hDatabase, + _T( "SELECT `Image`,`Desc` FROM `KillProcess`" ), + &hView); RV_BAIL; + + rv = MsiViewExecute( hView, NULL ); RV_BAIL; + + do { + rv = MsiViewFetch( hView, &hRecord ); + if(rv != ERROR_SUCCESS) { + if(hRecord) + MsiCloseHandle(hRecord); + hRecord = NULL; + break; + } + + kpList[nKpList].image = new TCHAR[ FIELD_SIZE ]; kpList[nKpList].image[0] = _T('\0'); + kpList[nKpList].desc = new TCHAR[ FIELD_SIZE ]; kpList[nKpList].desc[0] = _T('\0'); + nKpList++; + + size = FIELD_SIZE; + rv = MsiRecordGetString(hRecord, 1, kpList[nKpList-1].image, &size); RV_BAIL; + + size = FIELD_SIZE; + rv = MsiRecordGetString(hRecord, 2, kpList[nKpList-1].desc, &size); RV_BAIL; + + MsiCloseHandle(hRecord); + } while(nKpList < MAX_KILL_PROCESSES); + + hRecord = NULL; + + // now we have all the processes in the array. Check if they are running. + + hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); + if(hSnapshot == INVALID_HANDLE_VALUE) { + rv = GetLastError(); + goto _cleanup; + } + + pe.dwSize = sizeof( PROCESSENTRY32 ); + + if(!Process32First( hSnapshot, &pe )) { + // technically we should at least find the MSI process, but we let this pass + rv = ERROR_SUCCESS; + goto _cleanup; + } + + do { + for(i=0; i<nKpList; i++) { + if(!_tcsicmp( kpList[i].image, pe.szExeFile )) { + // got one + if(bKill) { + // try to kill the process + HANDLE hProcess = NULL; + + // If we encounter an error, instead of bailing + // out, we continue on to the next process. We + // may not have permission to kill all the + // processes we want to kill anyway. If there are + // any files that we want to replace that is in + // use, Windows Installer will schedule a reboot. + // Also, it's not like we have an exhaustive list + // of all the programs that use Kerberos anyway. + + hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID); + if(hProcess == NULL) { + rv = GetLastError(); + break; + } + + if(!TerminateProcess(hProcess, 0)) { + rv = GetLastError(); + CloseHandle(hProcess); + break; + } + + CloseHandle(hProcess); + + } else { + TCHAR buf[256]; + + // we are supposed to just list out the processes + rv = MsiRecordClearData( hRecordInsert ); RV_BAIL; + rv = MsiRecordSetString( hRecordInsert, 1, _T("KillableProcesses")); + rv = MsiRecordSetInteger( hRecordInsert, 2, rowNum++ ); RV_BAIL; + _itot( rowNum, buf, 10 ); + rv = MsiRecordSetString( hRecordInsert, 3, buf ); RV_BAIL; + if(_tcslen(kpList[i].desc)) { + rv = MsiRecordSetString( hRecordInsert, 4, kpList[i].desc ); RV_BAIL; + } else { + rv = MsiRecordSetString( hRecordInsert, 4, kpList[i].image ); RV_BAIL; + } + MsiViewModify(hViewInsert, MSIMODIFY_INSERT_TEMPORARY, hRecordInsert); RV_BAIL; + + found = TRUE; + } + break; + } + } + } while( Process32Next( hSnapshot, &pe ) ); + + if(!bKill) { + // set the 'FoundProcceses' property + if(found) { + MsiSetProperty( hInstall, _T("FoundProcesses"), _T("1")); + } else { + MsiSetProperty( hInstall, _T("FoundProcesses"), _T("")); + } + } + + // Finally: + rv = ERROR_SUCCESS; + +_cleanup: + + if(hRecordInsert) MsiCloseHandle(hRecordInsert); + if(hViewInsert) MsiCloseHandle(hView); + + if(hSnapshot && hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(hSnapshot); + + while(nKpList) { + nKpList--; + delete kpList[nKpList].image; + delete kpList[nKpList].desc; + } + delete kpList; + + if(hRecord) MsiCloseHandle(hRecord); + if(hView) MsiCloseHandle(hView); + + if(hDatabase) MsiCloseHandle(hDatabase); + + if(rv != ERROR_SUCCESS) { + ShowMsiError(hInstall, ERR_PROC_LIST, rv); + } + + return rv; +} + +/* Uninstall NSIS */ +MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall ) +{ + DWORD rv = ERROR_SUCCESS; + // lookup the NSISUNINSTALL property value + LPTSTR cNsisUninstall = _T("UPGRADENSIS"); + HANDLE hIo = NULL; + DWORD dwSize = 0; + LPTSTR strPathUninst = NULL; + HANDLE hJob = NULL; + STARTUPINFO sInfo; + PROCESS_INFORMATION pInfo; + + pInfo.hProcess = NULL; + pInfo.hThread = NULL; + + rv = MsiGetProperty( hInstall, cNsisUninstall, _T(""), &dwSize ); + if(rv != ERROR_MORE_DATA) goto _cleanup; + + strPathUninst = new TCHAR[ ++dwSize ]; + + rv = MsiGetProperty( hInstall, cNsisUninstall, strPathUninst, &dwSize ); + if(rv != ERROR_SUCCESS) goto _cleanup; + + // Create a process for the uninstaller + sInfo.cb = sizeof(sInfo); + sInfo.lpReserved = NULL; + sInfo.lpDesktop = _T(""); + sInfo.lpTitle = _T("Foo"); + sInfo.dwX = 0; + sInfo.dwY = 0; + sInfo.dwXSize = 0; + sInfo.dwYSize = 0; + sInfo.dwXCountChars = 0; + sInfo.dwYCountChars = 0; + sInfo.dwFillAttribute = 0; + sInfo.dwFlags = 0; + sInfo.wShowWindow = 0; + sInfo.cbReserved2 = 0; + sInfo.lpReserved2 = 0; + sInfo.hStdInput = 0; + sInfo.hStdOutput = 0; + sInfo.hStdError = 0; + + if(!CreateProcess( + strPathUninst, + _T("Uninstall /S"), + NULL, + NULL, + FALSE, + CREATE_SUSPENDED, + NULL, + NULL, + &sInfo, + &pInfo)) { + pInfo.hProcess = NULL; + pInfo.hThread = NULL; + rv = 40; + goto _cleanup; + }; + + // Create a job object to contain the NSIS uninstall process tree + + JOBOBJECT_ASSOCIATE_COMPLETION_PORT acp; + + acp.CompletionKey = 0; + + hJob = CreateJobObject(NULL, _T("NSISUninstallObject")); + if(!hJob) { + rv = 41; + goto _cleanup; + } + + hIo = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0); + if(!hIo) { + rv = 42; + goto _cleanup; + } + + acp.CompletionPort = hIo; + + SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation, &acp, sizeof(acp)); + + AssignProcessToJobObject( hJob, pInfo.hProcess ); + + ResumeThread( pInfo.hThread ); + + DWORD a,b,c; + for(;;) { + if(!GetQueuedCompletionStatus(hIo, &a, (PULONG_PTR) &b, (LPOVERLAPPED *) &c, INFINITE)) { + Sleep(1000); + continue; + } + if(a == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) { + break; + } + } + + rv = ERROR_SUCCESS; + +_cleanup: + if(hIo) CloseHandle(hIo); + if(pInfo.hProcess) CloseHandle( pInfo.hProcess ); + if(pInfo.hThread) CloseHandle( pInfo.hThread ); + if(hJob) CloseHandle(hJob); + if(strPathUninst) delete strPathUninst; + + if(rv != ERROR_SUCCESS) { + ShowMsiError( hInstall, ERR_NSS_FAILED, rv ); + } + return rv; +} + +/* Check and add or remove networkprovider key value + str : target string + str2: string to add/remove + bInst: == 1 if string should be added to target if not already there, + otherwise remove string from target if present. +*/ +int npi_CheckAndAddRemove( LPTSTR str, LPTSTR str2, int bInst ) { + + LPTSTR target, charset, match; + int ret=0; + + target = new TCHAR[lstrlen(str)+3]; + lstrcpy(target,_T(",")); + lstrcat(target,str); + lstrcat(target,_T(",")); + charset = new TCHAR[lstrlen(str2)+3]; + lstrcpy(charset,_T(",")); + lstrcat(charset,str2); + lstrcat(charset,_T(",")); + + match = _tcsstr(target, charset); + + if ((match) && (bInst)) { + ret = INP_ERR_PRESENT; + goto cleanup; + } + + if ((!match) && (!bInst)) { + ret = INP_ERR_ABSENT; + goto cleanup; + } + + if (bInst) // && !match + { + lstrcat(str, _T(",")); + lstrcat(str, str2); + ret = INP_ERR_ADDED; + goto cleanup; + } + + // if (!bInst) && (match) + { + lstrcpy(str+(match-target),match+lstrlen(str2)+2); + str[lstrlen(str)-1]=_T('\0'); + ret = INP_ERR_REMOVED; + goto cleanup; + } + +cleanup: + + delete target; + delete charset; + return ret; +} + +/* Sets the registry keys required for the functioning of the network provider */ + +DWORD InstNetProvider(MSIHANDLE hInstall, int bInst) { + LPTSTR strOrder; + HKEY hkOrder; + LONG rv; + DWORD dwSize; + HANDLE hProcHeap; + + strOrder = (LPTSTR) 0; + + CHECK(rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, STR_KEY_ORDER, 0, KEY_READ | KEY_WRITE, &hkOrder )); + + dwSize = 0; + CHECK(rv = RegQueryValueEx( hkOrder, STR_VAL_ORDER, NULL, NULL, NULL, &dwSize ) ); + + strOrder = new TCHAR[ (dwSize + STR_SERVICE_LEN) * sizeof(TCHAR) ]; + + CHECK(rv = RegQueryValueEx( hkOrder, STR_VAL_ORDER, NULL, NULL, (LPBYTE) strOrder, &dwSize)); + + npi_CheckAndAddRemove( strOrder, STR_SERVICE , bInst); + + dwSize = (lstrlen( strOrder ) + 1) * sizeof(TCHAR); + + CHECK(rv = RegSetValueEx( hkOrder, STR_VAL_ORDER, NULL, REG_SZ, (LPBYTE) strOrder, dwSize )); + + /* everything else should be set by the MSI tables */ + rv = ERROR_SUCCESS; +_cleanup: + + if( rv != ERROR_SUCCESS ) { + ShowMsiError( hInstall, ERR_NPI_FAILED, rv ); + } + + if(strOrder) delete strOrder; + + return rv; +} + +MSIDLLEXPORT InstallNetProvider( MSIHANDLE hInstall ) { + return InstNetProvider( hInstall, 1 ); +} + +MSIDLLEXPORT UninstallNetProvider( MSIHANDLE hInstall) { + return InstNetProvider( hInstall, 0 ); +} + +#endif +#ifdef __NMAKE__ +!ENDIF +#endif diff --git a/mechglue/src/windows/installer/wix/custom/custom.h b/mechglue/src/windows/installer/wix/custom/custom.h new file mode 100644 index 000000000..2e66671a1 --- /dev/null +++ b/mechglue/src/windows/installer/wix/custom/custom.h @@ -0,0 +1,81 @@ +/* + +Copyright 2004 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +/* custom.h + * + * Declarations for Kerberos for Windows MSI setup tools + * + * rcsid : $Id$ + */ + +#pragma once + +#include<windows.h> +#include<setupapi.h> +#include<msiquery.h> +#include<string.h> +#include<tchar.h> +#include<tlhelp32.h> + +#define MSIDLLEXPORT UINT __stdcall + +#define CHECK(x) if((x)) goto _cleanup + +#define CHECKX(x,y) if(!(x)) { msiErr = (y); goto _cleanup; } + +#define CHECK2(x,y) if((x)) { msiErr = (y); goto _cleanup; } + +#define STR_KEY_ORDER _T("SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order") +#define STR_VAL_ORDER _T("ProviderOrder") + +#define STR_SERVICE _T("MIT Kerberos") +#define STR_SERVICE_LEN 12 + + +void ShowMsiError(MSIHANDLE, DWORD, DWORD); +UINT SetAllowTgtSessionKey( MSIHANDLE hInstall, BOOL pInstall ); +UINT KillRunningProcessesSlave( MSIHANDLE hInstall, BOOL bKill ); + +/* exported */ +MSIDLLEXPORT AbortMsiImmediate( MSIHANDLE ); +MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall ); +MSIDLLEXPORT RevertAllowTgtSessionKey( MSIHANDLE hInstall ); +MSIDLLEXPORT EnableAllowTgtSessionKey( MSIHANDLE hInstall ); +MSIDLLEXPORT KillRunningProcesses( MSIHANDLE hInstall ) ; +MSIDLLEXPORT ListRunningProcesses( MSIHANDLE hInstall ); +MSIDLLEXPORT InstallNetProvider( MSIHANDLE ); +MSIDLLEXPORT UninstallNetProvider ( MSIHANDLE ); + +#define INP_ERR_PRESENT 1 +#define INP_ERR_ADDED 2 +#define INP_ERR_ABSENT 3 +#define INP_ERR_REMOVED 4 + +/* Custom errors */ +#define ERR_CUSTACTDATA 4001 +#define ERR_NSS_FAILED 4003 +#define ERR_ABORT 4004 +#define ERR_PROC_LIST 4006 +#define ERR_NPI_FAILED 4007 diff --git a/mechglue/src/windows/installer/wix/features.wxi b/mechglue/src/windows/installer/wix/features.wxi new file mode 100644 index 000000000..68ead13a7 --- /dev/null +++ b/mechglue/src/windows/installer/wix/features.wxi @@ -0,0 +1,277 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + + Copyright (C) 2004 by the Massachusetts Institute of Technology. + All rights reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization contemplating + export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of M.I.T. not be used in advertising or publicity pertaining + to distribution of the software without specific, written prior + permission. Furthermore if you modify this software you must label + your software as modified software and not distribute it in such a + fashion that it might be confused with the original M.I.T. software. + M.I.T. makes no representations about the suitability of + this software for any purpose. It is provided "as is" without express + or implied warranty. + + --> +<Include xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> + <Feature + Id="feaKfw" + AllowAdvertise="no" + Description="$(loc.KerberosDesc)" + InstallDefault="local" + Title="$(loc.KerberosTitle)" + ConfigurableDirectory="KERBEROSDIR" + Level="30"> + <Feature + Id="feaKfwClient" + AllowAdvertise="no" + Description="$(loc.KerberosClientDesc)" + InstallDefault="local" + Title="$(loc.KerberosClientTitle)" + Level="30"> + + <?ifdef DebugSyms?> + <Feature + Id="feaKfwClientDebug" + AllowAdvertise="no" + Description="$(loc.StrKerberosClientDebugDesc)" + Display="expand" + InstallDefault="$(var.DebugSymInstallDefault)" + Level="$(var.DebugSymLowLevel)" + Title="$(loc.StrKerberosClientDebugTitle)"> + <ComponentRef Id="cmf_bin_debug"/> + <ComponentRef Id="cmp_ClientSystemDebug"/> + </Feature> + <?endif?> + + <ComponentRef Id="cmf_leash32_exe" /> + <ComponentRef Id="csc_leash32_exe" /> + + <ComponentRef Id="cmf_aklog_exe" /> + <ComponentRef Id="cmf_comerr32_dll" /> + <ComponentRef Id="cmf_gss_exe" /> + <ComponentRef Id="cmf_gss_client_exe" /> + <ComponentRef Id="cmf_gss_server_exe" /> + <ComponentRef Id="cmf_gssapi32_dll" /> + <ComponentRef Id="cmf_k524init_exe" /> + <ComponentRef Id="cmf_kclnt32_dll" /> + <ComponentRef Id="cmf_kdestroy_exe" /> + <ComponentRef Id="cmf_kcpytkt_exe" /> + <ComponentRef Id="cmf_kdeltkt_exe" /> + <ComponentRef Id="cmf_kinit_exe" /> + <ComponentRef Id="cmf_klist_exe" /> + <ComponentRef Id="cmf_kpasswd_exe" /> + <ComponentRef Id="cmf_kvno_exe" /> + <ComponentRef Id="cmf_krb5_32_dll" /> + <ComponentRef Id="cmf_k5sprt32_dll" /> + <ComponentRef Id="cmf_krb524_dll" /> + <ComponentRef Id="cmf_krbcc32_dll" /> + <ComponentRef Id="cmf_krbcc32s_exe" /> + <ComponentRef Id="cmf_krbv4w32_dll" /> + + <ComponentRef Id="cmf_nidmgr32_dll" /> + <ComponentRef Id="cmf_krb5cred_dll" /> + <ComponentRef Id="cmf_krb5cred_en_us_dll" /> + <ComponentRef Id="cmf_krb4cred_dll" /> + <ComponentRef Id="cmf_krb4cred_en_us_dll" /> + <ComponentRef Id="cmf_netidmgr_exe" /> + + <ComponentRef Id="cmf_kfwlogon_DLL" /> + <ComponentRef Id="cmf_kfwcpcc_EXE" /> + <!-- Kerberos IV options --> + <ComponentRef Id="rcm_krb4_1" /> + <ComponentRef Id="rcm_krb4_2" /> + <ComponentRef Id="rcm_krb4_3" /> + <ComponentRef Id="rcm_krb4_4" /> + + <!-- Kerberos V options --> + <ComponentRef Id="rcm_krb5_1" /> + <ComponentRef Id="rcm_krb5_2" /> + <ComponentRef Id="rcm_krb5_3" /> + + + <!-- Leash config options --> + <ComponentRef Id="rcm_leash_1" /> + <ComponentRef Id="rcm_leash_2" /> + <ComponentRef Id="rcm_leash_3" /> + <ComponentRef Id="rcm_leash_5" /> + <ComponentRef Id="rcm_leash_6" /> + + <?ifdef OldHelp?> + <ComponentRef Id="cmf_leash32_hlp" /> + <?else?> + <ComponentRef Id="cmf_leash32_chm" /> + <?endif?> + <ComponentRef Id="cmf_leashw32_dll" /> + + <!-- Leash dll options --> + <ComponentRef Id="rcm_leashdll_1" /> + <ComponentRef Id="rcm_leashdll_2" /> + <ComponentRef Id="rcm_leashdll_3" /> + <ComponentRef Id="rcm_leashdll_4" /> + <ComponentRef Id="rcm_leashdll_5" /> + <ComponentRef Id="rcm_leashdll_6" /> + <ComponentRef Id="rcm_leashdll_7" /> + <ComponentRef Id="rcm_leashdll_8" /> + <ComponentRef Id="rcm_leashdll_9" /> + <ComponentRef Id="rcm_leashdll_10" /> + <ComponentRef Id="rcm_leashdll_11" /> + <ComponentRef Id="rcm_leashdll_12" /> + <ComponentRef Id="rcm_leashdll_13" /> + <ComponentRef Id="rcm_leashdll_15" /> + <ComponentRef Id="rcm_leashdll_16" /> + <ComponentRef Id="rcm_leashdll_17" /> + + <ComponentRef Id="cmf_ms2mit_exe" /> + <ComponentRef Id="cmf_mit2ms_exe" /> + <ComponentRef Id="cmf_wshelp32_dll" /> + <ComponentRef Id="cmf_xpprof32_dll" /> + + <ComponentRef Id="cmf_psapi_dll" /> + + <?ifndef Debug?> + <?ifdef CL1200?> + <ComponentRef Id="cmf_mfc42_dll" /> + <ComponentRef Id="cmf_msvcp60_dll" /> + <ComponentRef Id="cmf_msvcrt_dll" /> + <?else?> + <?ifdef CL1300?> + <ComponentRef Id="cmf_mfc70_dll" /> + <ComponentRef Id="cmf_msvcr70_dll" /> + <ComponentRef Id="cmf_msvcp70_dll" /> + <ComponentRef Id="cmf_mfc70chs_dll" /> + <ComponentRef Id="cmf_mfc70cht_dll" /> + <ComponentRef Id="cmf_mfc70deu_dll" /> + <ComponentRef Id="cmf_mfc70enu_dll" /> + <ComponentRef Id="cmf_mfc70esp_dll" /> + <ComponentRef Id="cmf_mfc70fra_dll" /> + <ComponentRef Id="cmf_mfc70ita_dll" /> + <ComponentRef Id="cmf_mfc70jpn_dll" /> + <ComponentRef Id="cmf_mfc70kor_dll" /> + <?else?> <!-- 1310 --> + <ComponentRef Id="cmf_mfc71_dll" /> + <ComponentRef Id="cmf_msvcr71_dll" /> + <ComponentRef Id="cmf_msvcp71_dll" /> + <ComponentRef Id="cmf_mfc71chs_dll" /> + <ComponentRef Id="cmf_mfc71cht_dll" /> + <ComponentRef Id="cmf_mfc71deu_dll" /> + <ComponentRef Id="cmf_mfc71enu_dll" /> + <ComponentRef Id="cmf_mfc71esp_dll" /> + <ComponentRef Id="cmf_mfc71fra_dll" /> + <ComponentRef Id="cmf_mfc71ita_dll" /> + <ComponentRef Id="cmf_mfc71jpn_dll" /> + <ComponentRef Id="cmf_mfc71kor_dll" /> + <?endif?> + <?endif?> + <?else?> + <?ifdef CL1200?> + <ComponentRef Id="cmf_mfc42d_dll" /> + <ComponentRef Id="cmf_msvcp60d_dll" /> + <ComponentRef Id="cmf_msvcrtd_dll" /> + <ComponentRef Id="cmf_runtime_debug1200" /> + <?else?> + <?ifdef CL1300?> + <ComponentRef Id="cmf_mfc70d_dll" /> + <ComponentRef Id="cmf_msvcr70d_dll" /> + <ComponentRef Id="cmf_msvcp70d_dll" /> + <ComponentRef Id="cmf_mfc70chs_dll" /> + <ComponentRef Id="cmf_mfc70cht_dll" /> + <ComponentRef Id="cmf_mfc70deu_dll" /> + <ComponentRef Id="cmf_mfc70enu_dll" /> + <ComponentRef Id="cmf_mfc70esp_dll" /> + <ComponentRef Id="cmf_mfc70fra_dll" /> + <ComponentRef Id="cmf_mfc70ita_dll" /> + <ComponentRef Id="cmf_mfc70jpn_dll" /> + <ComponentRef Id="cmf_mfc70kor_dll" /> + <ComponentRef Id="cmf_runtime_debug1300" /> + <?else?> <!-- 1310 --> + <ComponentRef Id="cmf_mfc71d_dll" /> + <ComponentRef Id="cmf_msvcr71d_dll" /> + <ComponentRef Id="cmf_msvcp71d_dll" /> + <ComponentRef Id="cmf_mfc71chs_dll" /> + <ComponentRef Id="cmf_mfc71cht_dll" /> + <ComponentRef Id="cmf_mfc71deu_dll" /> + <ComponentRef Id="cmf_mfc71enu_dll" /> + <ComponentRef Id="cmf_mfc71esp_dll" /> + <ComponentRef Id="cmf_mfc71fra_dll" /> + <ComponentRef Id="cmf_mfc71ita_dll" /> + <ComponentRef Id="cmf_mfc71jpn_dll" /> + <ComponentRef Id="cmf_mfc71kor_dll" /> + <ComponentRef Id="cmf_runtime_debug1310" /> + <?endif?> + <?endif?> + <?endif?> + <ComponentRef Id="cmf_krb5_ini" /> + <ComponentRef Id="cmf_krb_con" /> + <ComponentRef Id="cmf_krbrealm_con" /> + + <ComponentRef Id="rcm_common" /> + <ComponentRef Id="rcm_client" /> + + <Feature Id="feaKfwLeashStartup" AllowAdvertise="no" Display="hidden" Level="130"> + <Condition Level="30">LEASHAUTOSTART = 1</Condition> + <ComponentRef Id="csc_NetIDMgrStartup" /> + <ComponentRef Id="csc_LeashStartup" /> + </Feature> + + </Feature> <!-- /feaKfwClient --> + + <Feature + Id="feaKfwSDK" + AllowAdvertise="no" + Description="$(loc.KerberosSDKDesc)" + InstallDefault="local" + Level="130" + Title="$(loc.KerberosSDKTitle)"> + + <ComponentRef Id="cmp_dirdoc_netid" /> + <ComponentRef Id="cmp_dirinc_kclient" /> + <ComponentRef Id="cmp_dirinc_krb4" /> + <ComponentRef Id="cmp_dirinc_krb5_gssapi" /> + <ComponentRef Id="cmp_dirinc_krb5_KerberosIV" /> + <ComponentRef Id="cmp_dirinc_krb5" /> + <ComponentRef Id="cmp_dirinc_krbcc" /> + <ComponentRef Id="cmp_dirinc_leash" /> + <ComponentRef Id="cmp_dirinc_loadfuncs" /> + <ComponentRef Id="cmp_dirinc_wshelper" /> + <ComponentRef Id="cmp_dirinc_wshelper_arpa" /> + <ComponentRef Id="cmp_dirinc_netidmgr" /> + <ComponentRef Id="cmp_dirlib_i386" /> + <ComponentRef Id="cmp_dirinstall_nsis" /> + <ComponentRef Id="cmp_dirinstall_wix" /> + <ComponentRef Id="cmp_dirinstall_wix_lang" /> + <ComponentRef Id="cmp_dirinstall_wix_Binary" /> + <ComponentRef Id="cmp_dirinstall_wix_custom" /> + <ComponentRef Id="rcm_common" /> + <ComponentRef Id="rcm_sdk" /> + </Feature> <!-- /feaKfwSDK --> + + <Feature + Id="feaKfwDocs" + AllowAdvertise="no" + Description="$(loc.KerberosDocDesc)" + InstallDefault="local" + Level="30" + Title="$(loc.KerberosDocTitle)"> + + <ComponentRef Id="efl_leash_userdoc_pdf" /> + <ComponentRef Id="efl_netidmgr_userdoc_pdf" /> + <ComponentRef Id="efl_relnotes_html" /> + + <ComponentRef Id="rcm_common" /> + <ComponentRef Id="rcm_docs" /> + </Feature> + + </Feature> +</Include> \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/files.wxi b/mechglue/src/windows/installer/wix/files.wxi new file mode 100644 index 000000000..5dad4f17b --- /dev/null +++ b/mechglue/src/windows/installer/wix/files.wxi @@ -0,0 +1,936 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + + Copyright (C) 2004, 2005 by the Massachusetts Institute of Technology. + All rights reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization contemplating + export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of M.I.T. not be used in advertising or publicity pertaining + to distribution of the software without specific, written prior + permission. Furthermore if you modify this software you must label + your software as modified software and not distribute it in such a + fashion that it might be confused with the original M.I.T. software. + M.I.T. makes no representations about the suitability of + this software for any purpose. It is provided "as is" without express + or implied warranty. + + --> +<Include xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> +<Directory Id="TARGETDIR" Name="SourceDir"> + <Directory Id="SystemFolder" SourceName="System"> + <Component Id="cmf_kfwlogon_DLL" Guid="2F104FEB-2D61-458A-BAE3-B153F151E728"> + <File Id="filekfwlogon_DLL" Name="kfwlogon.dll" LongName="kfwlogon.dll" KeyPath="yes" DiskId="1" src="$(var.BinDir)kfwlogon.dll" /> + <Registry Id="reg_kfwlogon01" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\KFWLogon" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_kfwlogon02" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\KFWLogon" /> + <Registry Id="reg_kfwlogon03" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\KFWLogon" Name="Asynchronous" Type="integer" Value="0" /> + <Registry Id="reg_kfwlogon04" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\KFWLogon" Name="Impersonate" Type="integer" Value="0" /> + <Registry Id="reg_kfwlogon05" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\KFWLogon" Name="DLLName" Type="string" Value="[#filekfwlogon_DLL]" /> + <Registry Id="reg_kfwlogon06" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon\Notify\KFWLogon" Name="Logon" Type="string" Value="KFW_Logon_Event" /> + <Registry Id="reg_kfwlogon07" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_kfwlogon08" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" Name="AuthentProviderPath" Type="expandable" Value="[SystemFolder]kfwlogon.dll"/> + <Registry Id="reg_kfwlogon09" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider"/> + <Registry Id="reg_kfwlogon10" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" Name="VerboseLogging" Type="integer" Value="10"/> + <Registry Id="reg_kfwlogon11" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" Name="ProviderPath" Type="expandable" Value="[SystemFolder]kfwlogon.dll"/> + <Registry Id="reg_kfwlogon12" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" Name="Class" Type="integer" Value="2" /> + <Registry Id="reg_kfwlogon13" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\MIT Kerberos\NetworkProvider" Name="Name" Type="string" Value="MIT Kerberos"/> + </Component> + <Component Id="cmf_kfwcpcc_EXE" Guid="C3284E7A-3665-45A6-B64E-C909B1D1BAA6"> + <File Id="filekfwcpcc_EXE" Name="kfwcpcc.exe" LongName="kfwcpcc.exe" DiskId="1" src="$(var.BinDir)kfwcpcc.exe" /> + </Component> + <?ifdef DebugSyms?> + <Component Id="cmp_ClientSystemDebug" Guid="2D13ED48-53C2-4878-B196-2AD7F4100998"> + <File Id="filekfwlogon_PDB" Name="kfwlogon.pdb" LongName="kfwlogon.pdb" KeyPath="yes" DiskId="1" src="$(var.BinDir)kfwlogon.pdb" /> + <File Id="filekfwcpcc_PDB" Name="kfwcpcc.pdb" LongName="kfwcpcc.pdb" DiskId="1" src="$(var.BinDir)kfwcpcc.pdb" /> + </Component> + <?endif?> + </Directory> + <Directory Id="ProgramFilesFolder"> + <Directory Id="dirMIT" Name="MIT" SourceName="."> + <Directory Id="KERBEROSDIR" Name="Kerberos"> + <Directory Id="dirbin" Name="bin" src="$(var.BinDir)"> + + <!-- Kerberos IV options --> + <Component Id="rcm_krb4_1" Guid="34262966-9196-49D6-86C9-AE98D3116DC0" DiskId="1"> + <Registry Id="reg_krb4_1" Root="HKLM" Key="Software\MIT\Kerberos4" Name="krb.realms" Type="string" Value="[KRB4KRBREALMS]" KeyPath="yes"/> + <Condition>KRB4KRBREALMS</Condition> + </Component> + <Component Id="rcm_krb4_2" Guid="812334C6-EBDF-482C-8CB3-A6398AF9EDFC" DiskId="1"> + <Registry Id="reg_krb4_2" Root="HKLM" Key="Software\MIT\Kerberos4" Name="krb.conf" Type="string" Value="[KRB4KRBCONF]" KeyPath="yes"/> + <Condition>KRB4KRBCONF</Condition> + </Component> + <Component Id="rcm_krb4_3" Guid="5556ECD9-8721-41C2-846C-034C239B48F1" DiskId="1"> + <Registry Id="reg_krb4_3" Root="HKLM" Key="Software\MIT\Kerberos4" Name="configdir" Type="string" Value="[KRB4CONFIGDIR]" KeyPath="yes"/> + <Condition>KRB4CONFIGDIR</Condition> + </Component> + <Component Id="rcm_krb4_4" Guid="61371A93-7F59-439D-A89C-070E100F465B" DiskId="1"> + <Registry Id="reg_krb4_4" Root="HKLM" Key="Software\MIT\Kerberos4" Name="ticketfile" Type="string" Value="[KRB4TICKETFILE]" KeyPath="yes"/> + <Condition>KRB4TICKETFILE</Condition> + </Component> + + <!-- Kerberos V options --> + <Component Id="rcm_krb5_1" Guid="E190F8B9-51FA-4FB1-884C-C8AFA37F8653" DiskId="1"> + <Registry Id="reg_krb5_1" Root="HKLM" Key="Software\MIT\kerberos5" Name="config" Type="string" Value="[KRB5CONFIG]" KeyPath="yes" /> + <Condition>KRB5CONFIG</Condition> + </Component> + <Component Id="rcm_krb5_2" Guid="AE7D4305-6193-4094-8C82-73862AE01DCE" DiskId="1"> + <Registry Id="reg_krb5_2" Root="HKLM" Key="Software\MIT\kerberos5" Name="ccname" Type="string" Value="[KRB5CCNAME]" KeyPath="yes" /> + <Condition>KRB5CCNAME</Condition> + </Component> + <Component Id="rcm_krb5_3" Guid="853EE035-99AA-489A-8FB6-74C76624E92A" DiskId="1"> + <Registry Id="reg_krb5_3" Root="HKLM" Key="Software\MIT\kerberos5" Name="PreserveInitialTicketIdentity" Type="integer" Value="[KRB5PRESERVEIDENTITY]" KeyPath="yes" /> + <Condition>KRB5PRESERVEIDENTITY</Condition> + </Component> + + <Component Id="cmf_aklog_exe" Guid="38840074-3D15-45CB-8022-C4A603FC697A" DiskId="1"> + <File Id="fil_aklog_exe" LongName="aklog.exe" Name="aklog.exe" KeyPath="yes" /> + <Registry Id="reg_ts_aklog_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\aklog" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_aklog_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\aklog" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_comerr32_dll" Guid="D8F455F9-E648-4C61-A69D-7116ADEC2DBB" DiskId="1"> + <File Id="fil_comerr32_dll" LongName="comerr32.dll" Name="comerr32.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_gss_exe" Guid="8CAF09C4-68A2-46DC-A618-AEF16D832E54" DiskId="1"> + <File Id="fil_gss_exe" LongName="gss.exe" Name="gss.exe" KeyPath="yes" /> + <Registry Id="reg_ts_gss_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_gss_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_gss_client_exe" Guid="983E0887-0C8B-49AB-8F59-DFE3A4E45E89" DiskId="1"> + <File Id="fil_gss_client_exe" LongName="gss-client.exe" Name="gss-clnt.exe" KeyPath="yes" /> + <Registry Id="reg_ts_gss_client_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss-client" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_gss_client_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss-client" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_gss_server_exe" Guid="B165FE41-D0DD-4DFC-92E6-A99ADA23BE8B" DiskId="1"> + <File Id="fil_gss_server_exe" LongName="gss-server.exe" Name="gss-srvr.exe" KeyPath="yes" /> + <Registry Id="reg_ts_gss_server_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss-server" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_gss_server_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\gss-server" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_gssapi32_dll" Guid="5B0F2989-BB85-40BF-BB7A-E77693972CF9" DiskId="1"> + <File Id="fil_gssapi32_dll" LongName="gssapi32.dll" Name="gssapi32.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_k524init_exe" Guid="20BE4EA5-C465-4AF3-9A4F-BB80934167E3" DiskId="1"> + <File Id="fil_k524init_exe" LongName="k524init.exe" Name="k524init.exe" KeyPath="yes" /> + <Registry Id="reg_ts_k524init_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\k524init" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_k524init_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\k524init" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_kclnt32_dll" Guid="D396C1E7-080E-49F5-92BA-73BCEDF09C8E" DiskId="1"> + <File Id="fil_kclnt32_dll" LongName="kclnt32.dll" Name="kclnt32.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_kdestroy_exe" Guid="D1E9C111-7760-4EE6-86CF-D4B4064B0ABA" DiskId="1"> + <File Id="fil_kdestroy_exe" LongName="kdestroy.exe" Name="kdestroy.exe" KeyPath="yes" /> + <Registry Id="reg_ts_kdestroy_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kdestroy" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_kdestroy_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kdestroy" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_kcpytkt_exe" Guid="6B20E57C-0033-4dcf-B3C9-74ED0B2CF46E" DiskId="1"> + <File Id="fil_kcpytkt_exe" LongName="kcpytkt.exe" Name="kcpytkt.exe" KeyPath="yes" /> + <Registry Id="reg_ts_kcpytkt_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kcpytkt" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_kcpytkt_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kcpytkt" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_kdeltkt_exe" Guid="C7528C87-9B61-439a-8EA8-AD4BE3D758F9" DiskId="1"> + <File Id="fil_kdeltkt_exe" LongName="kdeltkt.exe" Name="kdeltkt.exe" KeyPath="yes" /> + <Registry Id="reg_ts_kdeltkt_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kdeltkt" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_kdeltkt_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kdeltkt" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_kinit_exe" Guid="80643A09-EF28-4714-BC62-B64FC5B17CAA" DiskId="1"> + <File Id="fil_kinit_exe" LongName="kinit.exe" Name="kinit.exe" KeyPath="yes" /> + <Registry Id="reg_ts_kinit_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kinit" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_kinit_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kinit" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_klist_exe" Guid="24FB6003-BC7A-4BF1-9503-82D398EC02D7" DiskId="1"> + <File Id="fil_klist_exe" LongName="klist.exe" Name="klist.exe" KeyPath="yes" /> + <Registry Id="reg_ts_klist_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\klist" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_klist_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\klist" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_kpasswd_exe" Guid="3FA4AB96-FF12-460A-814E-3380E220787C" DiskId="1"> + <File Id="fil_kpasswd_exe" LongName="kpasswd.exe" Name="kpasswd.exe" KeyPath="yes" /> + <Registry Id="reg_ts_kpasswd_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kpasswd" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_kpasswd_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kpasswd" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_kvno_exe" Guid="7759D524-1F88-4483-975F-DDD33A511512" DiskId="1"> + <File Id="fil_kvno_exe" LongName="kvno.exe" Name="kvno.exe" KeyPath="yes" /> + <Registry Id="reg_ts_kvno_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kvno" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_kvno_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\kvno" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_krb5_32_dll" Guid="31E40356-CBAC-4FC6-9A34-C6F6C72A27CA" DiskId="1"> + <File Id="fil_krb5_32_dll" LongName="krb5_32.dll" Name="krb5_32.dll" KeyPath="yes" /> + <Environment Id="env_kclient_path" Action="set" Name="PATH" Part="last" System="yes" Value="[KERBEROSDIR]bin" /> + </Component> + <Component Id="cmf_k5sprt32_dll" Guid="F2381331-9201-4c02-866F-2038676771D4" DiskId="1"> + <File Id="fil_k5sprt32_dll" LongName="k5sprt32.dll" Name="k5sprt32.dll" /> + </Component> + <Component Id="cmf_krb524_dll" Guid="98685874-A9AA-4BC5-9830-271D9CF52C17" DiskId="1"> + <File Id="fil_krb524_dll" LongName="krb524.dll" Name="krb524.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_krbcc32_dll" Guid="A50FA27D-F203-4C19-9047-B7976171FB94" DiskId="1"> + <File Id="fil_krbcc32_dll" LongName="krbcc32.dll" Name="krbcc32.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_krbcc32s_exe" Guid="7D5F0817-DACF-4B54-BB8D-94DD63626DB5" DiskId="1"> + <File Id="fil_krbcc32s_exe" LongName="krbcc32s.exe" Name="krbcc32s.exe" KeyPath="yes" /> + <Registry Id="reg_ts_krbcc32s_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\krbcc32s" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_krbcc32s_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\krbcc32s" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_krbv4w32_dll" Guid="DFA23F6C-5297-4876-AF52-6F7CF2CB34AC" DiskId="1"> + <File Id="fil_krbv4w32_dll" LongName="krbv4w32.dll" Name="krbv4w32.dll" KeyPath="yes" /> + </Component> + + <Component Id="cmf_leash32_exe" Guid="990D5F6B-4CEE-4706-96F4-F7AF12F97DF7" DiskId="1"> + <File Id="fil_leash32_exe" LongName="leash32.exe" Name="leash32.exe" KeyPath="yes" /> + <Registry Id="reg_ts_leash32_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\leash32" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_leash32_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\leash32" Name="Flags" Type="integer" Value="1032" /> + </Component> + + <Component Id="csc_leash32_exe" Guid="8A096700-47B1-4A0B-B7B5-44F75086DEAE" DiskId="1"> + <Shortcut Id="sc_leash32_exe" Advertise="no" Directory="dirShortcut" LongName="Leash Kerberos Ticket Manager.lnk" Name="Leash32.lnk" Arguments="[LEASHAUTOINIT]" Target="[!fil_leash32_exe]" /> + <Condition>USELEASH</Condition> + </Component> + + <!-- Leash32 configuration --> + <Component Id="rcm_leash_1" Guid="B91648A0-26F7-43BB-A954-202FF3811E3C" DiskId="1"> + <Registry Id="reg_leash_1" Root="HKLM" Key="Software\MIT\Leash32\Settings" Name="AfsStatus" Type="integer" Value="[LEASHAFSSTATUS]" KeyPath="yes"/> + <Condition>LEASHAFSSTATUS</Condition> + </Component> + <Component Id="rcm_leash_2" Guid="0D8DCC52-F855-4C46-86A1-198E6EE0CB8A" DiskId="1"> + <Registry Id="reg_leash_2" Root="HKLM" Key="Software\MIT\Leash32\Settings" Name="createmissingconfig" Type="integer" Value="[LEASHCREATEMISSINGCONFIG]" KeyPath="yes"/> + <Condition>LEASHCREATEMISSINGCONFIG</Condition> + </Component> + <Component Id="rcm_leash_3" Guid="9610A7E3-251F-4286-B776-1C3AF5DE7815" DiskId="1"> + <Registry Id="reg_leash_3" Root="HKLM" Key="Software\MIT\Leash32\Settings" Name="AutoRenewTickets" Type="integer" Value="[LEASHAUTORENEWTICKETS]" KeyPath="yes"/> + <Condition>LEASHAUTORENEWTICKETS</Condition> + </Component> + <!-- + <Component Id="rcm_leash_4" Guid="815AED84-2437-4EBC-B561-F847833DB3A5" DiskId="1"> + <Registry Id="reg_leash_4" Root="HKLM" Key="Software\MIT\Leash" Action="createKey" KeyPath="yes"/> + </Component> + --> + <Component Id="rcm_leash_5" Guid="A0D3D75F-762E-4D5C-909B-53E7396CEDB6" DiskId="1"> + <Registry Id="reg_leash_5" Root="HKLM" Key="Software\MIT\Leash" Name="lock_file_locations" Type="integer" Value="[LEASHLOCKFILELOCATIONS]" KeyPath="yes"/> + <Condition>LEASHLOCKFILELOCATIONS</Condition> + </Component> + <Component Id="rcm_leash_6" Guid="F675C145-6F9D-4BC4-9DA0-CAFB47A96A71" DiskId="1"> + <Registry Id="reg_leash_6" Root="HKLM" Key="Software\MIT\Leash" Name="MsLsaImport" Type="integer" Value="[LEASHMSLSAIMPORT]" KeyPath="yes"/> + <Condition>LEASHMSLSAIMPORT</Condition> + </Component> + + <Component Id="csc_NetIDMgrStartup" Guid="669227E3-0ADC-4173-90C3-631FCFC8EBC3" DiskId="1"> + <Registry Id="reg_sc_nidmgr_marker" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="NetIDMgrAutoStart" Type="integer" Value="1" KeyPath="yes" /> + <Shortcut Id="sc_netidmgr_exe_startup" Advertise="no" Directory="StartupFolder" LongName="Network Identity Manager.lnk" Name="netidmgr.lnk" Arguments="" Target="[dirbin]netidmgr.exe" Show="minimized" /> + <Condition>USENETIDMGR</Condition> + </Component> + + <Component Id="csc_LeashStartup" Guid="0DF73BCD-F34E-4B01-AA71-0EE08EB62F70" DiskId="1"> + <Registry Id="reg_sc_leash_marker" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="LeashAutoStart" Type="integer" Value="1" KeyPath="yes" /> + <Shortcut Id="sc_leash_exe_startup" Advertise="no" Directory="StartupFolder" LongName="Leash Credentials Manager.lnk" Name="leash32.lnk" Arguments="[LEASHAUTOINIT]" Target="[dirbin]leash32.exe" Show="minimized" /> + <Condition>USELEASH</Condition> + </Component> + + <?ifdef OldHelp?> + <Component Id="cmf_leash32_hlp" Guid="919616D6-1605-4A79-8E33-C18A0D0F25E3" DiskId="1"> + <File Id="fil_leash32_hlp" LongName="leash32.hlp" Name="leash32.hlp" KeyPath="yes" /> + </Component> + <?else?> + <Component Id="cmf_leash32_chm" Guid="C50E5E0A-B822-4419-855B-1713637BCA6A" DiskId="1"> + <File Id="fil_leash32_chm" LongName="leash32.chm" Name="leash32.chm" KeyPath="yes" /> + </Component> + <?endif?> + <Component Id="cmf_leashw32_dll" Guid="8C145D48-A2FC-4C28-BC05-4368545F1184" DiskId="1"> + <File Id="fil_leashw32_dll" LongName="leashw32.dll" Name="leashw32.dll" KeyPath="yes" /> + </Component> + + <!-- Leash DLL configuration --> + <Component Id="rcm_leashdll_1" Guid="54C949DA-AF1E-4412-81AF-F502BD5904D2" DiskId="1"> + <Registry Id="reg_leashdll_1" Root="HKLM" Key="Software\MIT\Leash" Name="lifetime" Type="integer" Value="[LEASHLIFETIME]" KeyPath="yes"/> + <Condition>LEASHLIFETIME</Condition> + </Component> + <Component Id="rcm_leashdll_2" Guid="9B553794-45E7-49FB-B6D9-1C3C9BB6E00D" DiskId="1"> + <Registry Id="reg_leashdll_2" Root="HKLM" Key="Software\MIT\Leash" Name="renew_till" Type="integer" Value="[LEASHRENEWTILL]" KeyPath="yes"/> + <Condition>LEASHRENEWTILL</Condition> + </Component> + <Component Id="rcm_leashdll_3" Guid="E3D1284C-17F6-41E3-9AA7-2ED05432060F" DiskId="1"> + <Registry Id="reg_leashdll_3" Root="HKLM" Key="Software\MIT\Leash" Name="renewable" Type="integer" Value="[LEASHRENEWABLE]" KeyPath="yes"/> + <Condition>LEASHRENEWABLE</Condition> + </Component> + <Component Id="rcm_leashdll_4" Guid="A02831D5-48B2-4E82-A670-EDCEBC197273" DiskId="1"> + <Registry Id="reg_leashdll_4" Root="HKLM" Key="Software\MIT\Leash" Name="forwardable" Type="integer" Value="[LEASHFORWARDABLE]" KeyPath="yes"/> + <Condition>LEASHFORWARDABLE</Condition> + </Component> + <Component Id="rcm_leashdll_5" Guid="5FDB0C01-6668-43E3-9C83-2CD364D97BF3" DiskId="1"> + <Registry Id="reg_leashdll_5" Root="HKLM" Key="Software\MIT\Leash" Name="noaddresses" Type="integer" Value="[LEASHNOADDRESSES]" KeyPath="yes"/> + <Condition>LEASHNOADDRESSES</Condition> + </Component> + <Component Id="rcm_leashdll_6" Guid="999BD59C-5C1E-446E-9D38-F4E26DD27D09" DiskId="1"> + <Registry Id="reg_leashdll_6" Root="HKLM" Key="Software\MIT\Leash" Name="proxiable" Type="integer" Value="[LEASHPROXIABLE]" KeyPath="yes"/> + <Condition>LEASHPROXIABLE</Condition> + </Component> + <Component Id="rcm_leashdll_7" Guid="C908AA17-DD21-4193-BA1D-535A2FD3D803" DiskId="1"> + <Registry Id="reg_leashdll_7" Root="HKLM" Key="Software\MIT\Leash" Name="publicip" Type="integer" Value="[LEASHPUBLICIP]" KeyPath="yes"/> + <Condition>LEASHPUBLICIP</Condition> + </Component> + <Component Id="rcm_leashdll_8" Guid="02926245-2327-46F9-AEF6-89E2DB0D90E1" DiskId="1"> + <Registry Id="reg_leashdll_8" Root="HKLM" Key="Software\MIT\Leash" Name="usekrb4" Type="integer" Value="[LEASHUSEKRB4]" KeyPath="yes"/> + <Condition>LEASHUSEKRB4</Condition> + </Component> + <Component Id="rcm_leashdll_9" Guid="B45BBA29-7A67-4FF7-AAA4-80044D46C451" DiskId="1"> + <Registry Id="reg_leashdll_9" Root="HKLM" Key="Software\MIT\Leash" Name="hide_kinit_options" Type="integer" Value="[LEASHHIDEKINITOPTIONS]" KeyPath="yes"/> + <Condition>LEASHHIDEKINITOPTIONS</Condition> + </Component> + <Component Id="rcm_leashdll_10" Guid="1DDC4D78-BDB4-48CD-A4E9-024FA9706100" DiskId="1"> + <Registry Id="reg_leashdll_10" Root="HKLM" Key="Software\MIT\Leash" Name="life_min" Type="integer" Value="[LEASHLIFEMIN]" KeyPath="yes"/> + <Condition>LEASHLIFEMIN</Condition> + </Component> + <Component Id="rcm_leashdll_11" Guid="39134333-58C7-4C6B-B690-2322D3AE928A" DiskId="1"> + <Registry Id="reg_leashdll_11" Root="HKLM" Key="Software\MIT\Leash" Name="life_max" Type="integer" Value="[LEASHLIFEMAX]" KeyPath="yes"/> + <Condition>LEASHLIFEMAX</Condition> + </Component> + <Component Id="rcm_leashdll_12" Guid="BBB6F5C3-290F-4A21-A630-E8630C6EAB67" DiskId="1"> + <Registry Id="reg_leashdll_12" Root="HKLM" Key="Software\MIT\Leash" Name="renew_min" Type="integer" Value="[LEASHRENEWMIN]" KeyPath="yes"/> + <Condition>LEASHRENEWMIN</Condition> + </Component> + <Component Id="rcm_leashdll_13" Guid="0F86A73E-DB31-45E7-9156-BE0EC99076A7" DiskId="1"> + <Registry Id="reg_leashdll_13" Root="HKLM" Key="Software\MIT\Leash" Name="renew_max" Type="integer" Value="[LEASHRENEWMAX]" KeyPath="yes"/> + <Condition>LEASHRENEWMAX</Condition> + </Component> + <!-- + <Component Id="rcm_leashdll_14" Guid="FE0F06A2-62E7-46C1-9BFF-337C50DB78C7" DiskId="1"> + <Registry Id="reg_leashdll_14" Root="HKLM" Key="Software\MIT\Leash32\Settings" Action="createKey" /> + </Component> + --> + <Component Id="rcm_leashdll_15" Guid="2DAC4693-6435-4278-A584-3D2B74BE87D5" DiskId="1"> + <Registry Id="reg_leashdll_15" Root="HKLM" Key="Software\MIT\Leash32\Settings" Name="uppercaserealm" Type="integer" Value="[LEASHUPPERCASEREALM]" KeyPath="yes"/> + <Condition>LEASHUPPERCASEREALM</Condition> + </Component> + <Component Id="rcm_leashdll_16" Guid="FE3DDD47-CCDE-44F8-8C86-97F2C3545443" DiskId="1"> + <Registry Id="reg_leashdll_16" Root="HKLM" Key="Software\MIT\Leash32\Settings" Name="timehost" Type="string" Value="[LEASHTIMEHOST]" KeyPath="yes"/> + <Condition>LEASHTIMEHOST</Condition> + </Component> + <Component Id="rcm_leashdll_17" Guid="1B685E1B-32F2-49A5-9B7D-4288741A2C17" DiskId="1"> + <Registry Id="reg_leashdll_17" Root="HKLM" Key="Software\MIT\Leash" Name="preserve_kinit_options" Type="integer" Value="[LEASHPRESERVEKINITOPTIONS]" KeyPath="yes"/> + <Condition>LEASHPRESERVEKINITOPTIONS</Condition> + </Component> + + <Component Id="cmf_ms2mit_exe" Guid="63D189DC-5EE4-49E2-B5E9-6E74A28602C8" DiskId="1"> + <File Id="fil_ms2mit_exe" LongName="ms2mit.exe" Name="ms2mit.exe" KeyPath="yes" /> + <Registry Id="reg_ts_ms2mit_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\ms2mit" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_ms2mit_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\ms2mit" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_mit2ms_exe" Guid="4F487781-5B55-48c1-A3FA-8BC6ECA4FEA1" DiskId="1"> + <File Id="fil_mit2ms_exe" LongName="mit2ms.exe" Name="mit2ms.exe" KeyPath="yes" /> + <Registry Id="reg_ts_mit2ms_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\mit2ms" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_mit2ms_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\mit2ms" Name="Flags" Type="integer" Value="1032" /> + </Component> + <Component Id="cmf_wshelp32_dll" Guid="B9D9F5F1-CA93-4F56-B6F8-343F21484CDE" DiskId="1"> + <File Id="fil_wshelp32_dll" LongName="wshelp32.dll" Name="wshelp32.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_xpprof32_dll" Guid="A7DF8BAF-7188-4C24-89FB-C8EB51571FD2" DiskId="1"> + <File Id="fil_xpprof32_dll" LongName="xpprof32.dll" Name="xpprof32.dll" KeyPath="yes" /> + </Component> + + <!-- NetIDMgr --> + <Component Id="cmf_nidmgr32_dll" Guid="EEBA3A0D-CE3D-42F1-8854-D7F63F597202" DiskId="1"> + <File Id="fil_nidmgr32_dll" LongName="nidmgr32.dll" Name="nidmgr32.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_krb5cred_dll" Guid="27A7723A-F0D9-4F06-892C-54F0AC6014C3" DiskId="1"> + <File Id="fil_krb5cred_dll" LongName="krb5cred.dll" Name="krb5cred.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_krb5cred_en_us_dll" Guid="EA9ABE05-A85B-43BB-8741-50D3C3128632" DiskId="1"> + <File Id="fil_krb5cred_en_us_dll" LongName="krb5cred_en_us.dll" Name="krb5cenu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_krb4cred_dll" Guid="E3B86954-9D5D-4929-A5E6-B22ED03E6D6C" DiskId="1"> + <File Id="fil_krb4cred_dll" LongName="krb4cred.dll" Name="krb4cred.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_krb4cred_en_us_dll" Guid="3FF40A29-E2C3-40F3-B81C-2948494BE4B0" DiskId="1"> + <File Id="fil_krb4cred_en_us_dll" LongName="krb4cred_en_us.dll" Name="krb4cenu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_netidmgr_exe" Guid="AEB06D67-B4F3-45B1-AC1E-5C1AFF747756" DiskId="1"> + <File Id="fil_netidmgr_exe" LongName="netidmgr.exe" Name="netidmgr.exe" KeyPath="yes" /> + <File Id="fil_netidmgr_exe_manifest" LongName="netidmgr.exe.manifest" Name="netidmgr.emn" /> + <File Id="fil_netidmgr_chm" LongName="netidmgr.chm" Name="netidmgr.chm" /> + <Registry Id="reg_ts_netidmgr_0" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\netidmgr" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_ts_netidmgr_1" Root="HKLM" Key="Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Compatibility\Applications\netidmgr" Name="Flags" Type="integer" Value="1032" /> + <Shortcut Id="sc_netidmgr_exe" Advertise="no" Directory="dirShortcut" LongName="Network Identity Manager.lnk" Name="netidmgr.lnk" Arguments="" Target="[dirbin]netidmgr.exe" Show="minimized" WorkingDirectory="[dirbin]"/> + <Shortcut Id="sc_netidmgr_chm" Advertise="no" Directory="dirShortcut" LongName="Network Identity Manager Documentation.lnk" Name="netidchm.lnk" Target="[dirbin]netidmgr.chm" WorkingDirectory="[dirbin]"/> + </Component> + <!-- /NetIDMgr --> + + <!-- Debug symbols --> + <?ifdef DebugSyms?> + <Component Id="cmf_bin_debug" Guid="C8468854-8261-4781-8119-A612636841E3" DiskId="1"> + <File Id="fil_aklog_pdb" LongName="aklog.pdb" Name="aklog.pdb" /> + <File Id="fil_comerr32_pdb" LongName="comerr32.pdb" Name="comerr32.pdb" /> + <File Id="fil_gss_pdb" LongName="gss.pdb" Name="gss.pdb" /> + <File Id="fil_gss_client_pdb" LongName="gss-client.pdb" Name="gss-clnt.pdb" /> + <File Id="fil_gss_server_pdb" LongName="gss-server.pdb" Name="gss-srvr.pdb" /> + <File Id="fil_gssapi32_pdb" LongName="gssapi32.pdb" Name="gssapi32.pdb" /> + <File Id="fil_k524init_pdb" LongName="k524init.pdb" Name="k524init.pdb" /> + <File Id="fil_kclnt32_pdb" LongName="kclnt32.pdb" Name="kclnt32.pdb" /> + <File Id="fil_kdestroy_pdb" LongName="kdestroy.pdb" Name="kdestroy.pdb" /> + <File Id="fil_kcpytkt_pdb" LongName="kcpytkt.pdb" Name="kcpytkt.pdb" /> + <File Id="fil_kdeltkt_pdb" LongName="kdeltkt.pdb" Name="kdeltkt.pdb" /> + <File Id="fil_kinit_pdb" LongName="kinit.pdb" Name="kinit.pdb" /> + <File Id="fil_klist_pdb" LongName="klist.pdb" Name="klist.pdb" /> + <File Id="fil_kpasswd_pdb" LongName="kpasswd.pdb" Name="kpasswd.pdb" /> + <File Id="fil_kvno_pdb" LongName="kvno.pdb" Name="kvno.pdb" /> + <File Id="fil_krb5_32_pdb" LongName="krb5_32.pdb" Name="krb5_32.pdb" KeyPath="yes" /> + <File Id="fil_k5sprt32_pdb" LongName="k5sprt32.pdb" Name="k5sprt32.pdb" /> + <File Id="fil_krb524_pdb" LongName="krb524.pdb" Name="krb524.pdb" /> + <File Id="fil_krbcc32_pdb" LongName="krbcc32.pdb" Name="krbcc32.pdb" /> + <File Id="fil_krbcc32s_pdb" LongName="krbcc32s.pdb" Name="krbcc32s.pdb" /> + <File Id="fil_krbv4w32_pdb" LongName="krbv4w32.pdb" Name="krbv4w32.pdb" /> + <File Id="fil_leash32_pdb" LongName="leash32.pdb" Name="leash32.pdb" /> + <File Id="fil_leashw32_pdb" LongName="leashw32.pdb" Name="leashw32.pdb" /> + <File Id="fil_ms2mit_pdb" LongName="ms2mit.pdb" Name="ms2mit.pdb" /> + <File Id="fil_mit2ms_pdb" LongName="mit2ms.pdb" Name="mit2ms.pdb" /> + <File Id="fil_wshelp32_pdb" LongName="wshelp32.pdb" Name="wshelp32.pdb" /> + <File Id="fil_xpprof32_pdb" LongName="xpprof32.pdb" Name="xpprof32.pdb" /> + <File Id="fil_krb4cred_pdb" LongName="krb4cred.pdb" Name="krb4cred.pdb" /> + <File Id="fil_krb5cred_pdb" LongName="krb5cred.pdb" Name="krb5cred.pdb" /> + <File Id="fil_netidmgr_pdb" LongName="netidmgr.pdb" Name="netidmgr.pdb" /> + <File Id="fil_nidmgr32_pdb" LongName="nidmgr32.pdb" Name="nidmgr32.pdb" /> + </Component> + <?endif?> + + <!-- Runtime --> + <?ifndef Debug?> + <?ifdef CL1200?> + <Component Id="cmf_mfc42_dll" Guid="BE2D0D08-E26E-4906-BEEA-1C550BA9B405" DiskId="1"> + <File Id="fil_mfc42_dll" LongName="mfc42.dll" Name="mfc42.dll" src="$(var.SystemDir)mfc42.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcp60_dll" Guid="7DBB5E61-AA59-4FD8-87CA-7F139D355050" DiskId="1"> + <File Id="fil_msvcp60_dll" LongName="msvcp60.dll" Name="msvcp60.dll" src="$(var.SystemDir)msvcp60.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcrt_dll" Guid="07B1612B-F52B-4A22-BC20-948BB7D50916" DiskId="1"> + <File Id="fil_msvcrt_dll" LongName="msvcrt.dll" Name="msvcrt.dll" src="$(var.SystemDir)msvcrt.dll" KeyPath="yes" /> + </Component> + <?else?> + <?ifdef CL1300?> + <Component Id="cmf_mfc70_dll" Guid="E064D66F-45A5-46FA-A0C0-EE68B5DCA248" DiskId="1"> + <File Id="fil_mfc70_dll" LongName="mfc70.dll" Name="mfc70.dll" src="$(var.SystemDir)mfc70.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcr70_dll" Guid="3489059D-B8C5-4F9A-9DF9-CC8F19B97898" DiskId="1"> + <File Id="fil_msvcr70_dll" LongName="msvcr70.dll" Name="msvcr70.dll" src="$(var.SystemDir)msvcr70.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcp70_dll" Guid="E3E6DC28-A229-45D7-804B-BC5A2CAB86B6" DiskId="1"> + <File Id="fil_msvcp70_dll" LongName="msvcp70.dll" Name="msvcp70.dll" src="$(var.SystemDir)msvcp70.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70chs_dll" Guid="CAFD61A5-8A13-4A7C-AA15-6FEED7D43A3A" DiskId="1"> + <File Id="fil_mfc70chs_dll" LongName="mfc70chs.dll" Name="mfc70chs.dll" src="$(var.SystemDir)mfc70chs.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70cht_dll" Guid="A3F60016-825A-4096-A45F-98B4972FF1CA" DiskId="1"> + <File Id="fil_mfc70cht_dll" LongName="mfc70cht.dll" Name="mfc70cht.dll" src="$(var.SystemDir)mfc70cht.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70deu_dll" Guid="D146EE00-8880-4E39-A131-784B947883DB" DiskId="1"> + <File Id="fil_mfc70deu_dll" LongName="mfc70deu.dll" Name="mfc70deu.dll" src="$(var.SystemDir)mfc70deu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70enu_dll" Guid="11E2059D-62E6-40DF-87C1-B03E425048CE" DiskId="1"> + <File Id="fil_mfc70enu_dll" LongName="mfc70enu.dll" Name="mfc70enu.dll" src="$(var.SystemDir)mfc70enu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70esp_dll" Guid="3D1AAC2A-0FB1-4EF7-8406-1BF771CEB4BB" DiskId="1"> + <File Id="fil_mfc70esp_dll" LongName="mfc70esp.dll" Name="mfc70esp.dll" src="$(var.SystemDir)mfc70esp.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70fra_dll" Guid="36A2B8B3-E6C6-4725-96B8-82905D2ADE4E" DiskId="1"> + <File Id="fil_mfc70fra_dll" LongName="mfc70fra.dll" Name="mfc70fra.dll" src="$(var.SystemDir)mfc70fra.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70ita_dll" Guid="4EE49FC8-ED41-48F4-90A9-1FC06FE6237D" DiskId="1"> + <File Id="fil_mfc70ita_dll" LongName="mfc70ita.dll" Name="mfc70ita.dll" src="$(var.SystemDir)mfc70ita.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70jpn_dll" Guid="A6ADFFF1-C48B-446C-9B7D-6137F00EC0E4" DiskId="1"> + <File Id="fil_mfc70jpn_dll" LongName="mfc70jpn.dll" Name="mfc70jpn.dll" src="$(var.SystemDir)mfc70jpn.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70kor_dll" Guid="720F98E2-5525-41CA-8734-98B0A5756708" DiskId="1"> + <File Id="fil_mfc70kor_dll" LongName="mfc70kor.dll" Name="mfc70kor.dll" src="$(var.SystemDir)mfc70kor.dll" KeyPath="yes" /> + </Component> + <?else?> <!-- CL1310 --> + <Component Id="cmf_mfc71_dll" Guid="6A4854A8-35AE-42CB-9671-9F6F096BE20C" DiskId="1"> + <File Id="fil_mfc71_dll" LongName="mfc71.dll" Name="mfc71.dll" src="$(var.SystemDir)mfc71.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcr71_dll" Guid="C6952DEE-E62A-4635-9CE8-405F1E459FB2" DiskId="1"> + <File Id="fil_msvcr71_dll" LongName="msvcr71.dll" Name="msvcr71.dll" src="$(var.SystemDir)msvcr71.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcp71_dll" Guid="CA7D0EDE-0B81-4709-86E9-31DC8543918F" DiskId="1"> + <File Id="fil_msvcp71_dll" LongName="msvcp71.dll" Name="msvcp71.dll" src="$(var.SystemDir)msvcp71.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71chs_dll" Guid="693F64CF-1AE5-4756-94CC-095ED48C217F" DiskId="1"> + <File Id="fil_mfc71chs_dll" LongName="mfc71chs.dll" Name="mfc71chs.dll" src="$(var.SystemDir)mfc71chs.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71cht_dll" Guid="A5552AAE-048F-41AB-AC2D-6C96411D812D" DiskId="1"> + <File Id="fil_mfc71cht_dll" LongName="mfc71cht.dll" Name="mfc71cht.dll" src="$(var.SystemDir)mfc71cht.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71deu_dll" Guid="E8AE39B8-1B23-4DC9-944F-CA823F53CFF3" DiskId="1"> + <File Id="fil_mfc71deu_dll" LongName="mfc71deu.dll" Name="mfc71deu.dll" src="$(var.SystemDir)mfc71deu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71enu_dll" Guid="1FF5B6B6-4015-40F1-AEFF-004DBCFDB5E7" DiskId="1"> + <File Id="fil_mfc71enu_dll" LongName="mfc71enu.dll" Name="mfc71enu.dll" src="$(var.SystemDir)mfc71enu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71esp_dll" Guid="028AC2DA-B4F9-4A9E-A728-1100B3C7E259" DiskId="1"> + <File Id="fil_mfc71esp_dll" LongName="mfc71esp.dll" Name="mfc71esp.dll" src="$(var.SystemDir)mfc71esp.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71fra_dll" Guid="7D6C3457-F08C-426C-BEE2-8D9F214223C5" DiskId="1"> + <File Id="fil_mfc71fra_dll" LongName="mfc71fra.dll" Name="mfc71fra.dll" src="$(var.SystemDir)mfc71fra.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71ita_dll" Guid="5CE98F88-CD33-4887-9634-B6263B6DB3CB" DiskId="1"> + <File Id="fil_mfc71ita_dll" LongName="mfc71ita.dll" Name="mfc71ita.dll" src="$(var.SystemDir)mfc71ita.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71jpn_dll" Guid="6DE66BB3-5DD2-4D87-89E4-D73FF405932C" DiskId="1"> + <File Id="fil_mfc71jpn_dll" LongName="mfc71jpn.dll" Name="mfc71jpn.dll" src="$(var.SystemDir)mfc71jpn.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71kor_dll" Guid="B7290849-638E-4C39-9E56-0D73CF564D69" DiskId="1"> + <File Id="fil_mfc71kor_dll" LongName="mfc71kor.dll" Name="mfc71kor.dll" src="$(var.SystemDir)mfc71kor.dll" KeyPath="yes" /> + </Component> + <?endif?> + <?endif?> + <?else?> <!-- Debug --> + <?ifdef CL1200?> + <Component Id="cmf_mfc42d_dll" Guid="B7360C15-61FA-409F-8F0A-87B96FB30BBD" DiskId="1"> + <File Id="fil_mfc42d_dll" LongName="mfc42d.dll" Name="mfc42d.dll" src="$(var.SystemDir)mfc42d.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcp60d_dll" Guid="BFF28D63-B60A-48B6-A403-A7DE00BDB37E" DiskId="1"> + <File Id="fil_msvcp60d_dll" LongName="msvcp60d.dll" Name="msvcp60d.dll" src="$(var.SystemDir)msvcp60d.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcrtd_dll" Guid="69069738-3202-43C3-92A3-4139816B6527" DiskId="1"> + <File Id="fil_msvcrtd_dll" LongName="msvcrtd.dll" Name="msvcrtd.dll" src="$(var.SystemDir)msvcrtd.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_runtime_debug1200" Guid="3FAD9513-AB33-4eed-9359-E96F8D5ABD2A" DiskId="1"> + <File Id="fil_mfc42d_pdb" LongName="mfc42d.pdb" Name="mfc42d.pdb" src="$(var.SystemDir)mfc42d.pdb" /> + <File Id="fil_msvcp60d_pdb" LongName="msvcp60d.pdb" Name="msvcp60d.pdb" src="$(var.SystemDir)msvcp60d.pdb" /> + <File Id="fil_msvcrtd_pdb" LongName="msvcrtd.pdb" Name="msvcrtd.pdb" src="$(var.SystemDir)msvcrtd.pdb" KeyPath="yes" /> + </Component> + <?else?> + <?ifdef CL1300?> + <Component Id="cmf_mfc70d_dll" Guid="40C7120A-9B28-4DD1-86D0-9F66056A2463" DiskId="1"> + <File Id="fil_mfc70d_dll" LongName="mfc70d.dll" Name="mfc70d.dll" src="$(var.SystemDir)mfc70d.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcr70d_dll" Guid="D0A7B06E-6F65-4559-A99A-63C4C837BE0E" DiskId="1"> + <File Id="fil_msvcr70d_dll" LongName="msvcr70d.dll" Name="msvcr70d.dll" src="$(var.SystemDir)msvcr70d.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcp70d_dll" Guid="DC82F644-8705-4C89-BE63-4CD6680BF580" DiskId="1"> + <File Id="fil_msvcp70d_dll" LongName="msvcp70d.dll" Name="msvcp70d.dll" src="$(var.SystemDir)msvcp70d.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70chs_dll" Guid="CAFD61A5-8A13-4A7C-AA15-6FEED7D43A3A" DiskId="1"> + <File Id="fil_mfc70chs_dll" LongName="mfc70chs.dll" Name="mfc70chs.dll" src="$(var.SystemDir)mfc70chs.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70cht_dll" Guid="A3F60016-825A-4096-A45F-98B4972FF1CA" DiskId="1"> + <File Id="fil_mfc70cht_dll" LongName="mfc70cht.dll" Name="mfc70cht.dll" src="$(var.SystemDir)mfc70cht.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70deu_dll" Guid="D146EE00-8880-4E39-A131-784B947883DB" DiskId="1"> + <File Id="fil_mfc70deu_dll" LongName="mfc70deu.dll" Name="mfc70deu.dll" src="$(var.SystemDir)mfc70deu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70enu_dll" Guid="11E2059D-62E6-40DF-87C1-B03E425048CE" DiskId="1"> + <File Id="fil_mfc70enu_dll" LongName="mfc70enu.dll" Name="mfc70enu.dll" src="$(var.SystemDir)mfc70enu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70esp_dll" Guid="3D1AAC2A-0FB1-4EF7-8406-1BF771CEB4BB" DiskId="1"> + <File Id="fil_mfc70esp_dll" LongName="mfc70esp.dll" Name="mfc70esp.dll" src="$(var.SystemDir)mfc70esp.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70fra_dll" Guid="36A2B8B3-E6C6-4725-96B8-82905D2ADE4E" DiskId="1"> + <File Id="fil_mfc70fra_dll" LongName="mfc70fra.dll" Name="mfc70fra.dll" src="$(var.SystemDir)mfc70fra.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70ita_dll" Guid="4EE49FC8-ED41-48F4-90A9-1FC06FE6237D" DiskId="1"> + <File Id="fil_mfc70ita_dll" LongName="mfc70ita.dll" Name="mfc70ita.dll" src="$(var.SystemDir)mfc70ita.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70jpn_dll" Guid="A6ADFFF1-C48B-446C-9B7D-6137F00EC0E4" DiskId="1"> + <File Id="fil_mfc70jpn_dll" LongName="mfc70jpn.dll" Name="mfc70jpn.dll" src="$(var.SystemDir)mfc70jpn.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc70kor_dll" Guid="720F98E2-5525-41CA-8734-98B0A5756708" DiskId="1"> + <File Id="fil_mfc70kor_dll" LongName="mfc70kor.dll" Name="mfc70kor.dll" src="$(var.SystemDir)mfc70kor.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_runtime_debug1300" Guid="157D7DE8-6AFE-44b3-A317-840667C76D0D" DiskId="1"> + <File Id="fil_mfc70d_pdb" LongName="mfc70d.pdb" Name="mfc70d.pdb" src="$(var.SystemDir)mfc70d.pdb" /> + <File Id="fil_msvcr70d_pdb" LongName="msvcr70d.pdb" Name="msvcr70d.pdb" src="$(var.SystemDir)msvcr70d.pdb" KeyPath="yes" /> + <File Id="fil_msvcp70d_pdb" LongName="msvcp70d.pdb" Name="msvcp70d.pdb" src="$(var.SystemDir)msvcp70d.pdb" /> + </Component> + <?else?> <!-- CL1310 --> + <Component Id="cmf_mfc71d_dll" Guid="0E0A47A3-892C-4526-8591-C719E1A184F2" DiskId="1"> + <File Id="fil_mfc71d_dll" LongName="mfc71d.dll" Name="mfc71d.dll" src="$(var.SystemDir)mfc71d.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcr71d_dll" Guid="CB2A282D-CF73-4DA8-929D-8035776F4FB8" DiskId="1"> + <File Id="fil_msvcr71d_dll" LongName="msvcr71d.dll" Name="msvcr71d.dll" src="$(var.SystemDir)msvcr71d.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_msvcp71d_dll" Guid="7D6003B6-B3A1-417A-BE16-5DDD52023456" DiskId="1"> + <File Id="fil_msvcp71d_dll" LongName="msvcp71d.dll" Name="msvcp71d.dll" src="$(var.SystemDir)msvcp71d.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71chs_dll" Guid="693F64CF-1AE5-4756-94CC-095ED48C217F" DiskId="1"> + <File Id="fil_mfc71chs_dll" LongName="mfc71chs.dll" Name="mfc71chs.dll" src="$(var.SystemDir)mfc71chs.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71cht_dll" Guid="A5552AAE-048F-41AB-AC2D-6C96411D812D" DiskId="1"> + <File Id="fil_mfc71cht_dll" LongName="mfc71cht.dll" Name="mfc71cht.dll" src="$(var.SystemDir)mfc71cht.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71deu_dll" Guid="E8AE39B8-1B23-4DC9-944F-CA823F53CFF3" DiskId="1"> + <File Id="fil_mfc71deu_dll" LongName="mfc71deu.dll" Name="mfc71deu.dll" src="$(var.SystemDir)mfc71deu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71enu_dll" Guid="1FF5B6B6-4015-40F1-AEFF-004DBCFDB5E7" DiskId="1"> + <File Id="fil_mfc71enu_dll" LongName="mfc71enu.dll" Name="mfc71enu.dll" src="$(var.SystemDir)mfc71enu.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71esp_dll" Guid="028AC2DA-B4F9-4A9E-A728-1100B3C7E259" DiskId="1"> + <File Id="fil_mfc71esp_dll" LongName="mfc71esp.dll" Name="mfc71esp.dll" src="$(var.SystemDir)mfc71esp.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71fra_dll" Guid="7D6C3457-F08C-426C-BEE2-8D9F214223C5" DiskId="1"> + <File Id="fil_mfc71fra_dll" LongName="mfc71fra.dll" Name="mfc71fra.dll" src="$(var.SystemDir)mfc71fra.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71ita_dll" Guid="5CE98F88-CD33-4887-9634-B6263B6DB3CB" DiskId="1"> + <File Id="fil_mfc71ita_dll" LongName="mfc71ita.dll" Name="mfc71ita.dll" src="$(var.SystemDir)mfc71ita.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71jpn_dll" Guid="6DE66BB3-5DD2-4D87-89E4-D73FF405932C" DiskId="1"> + <File Id="fil_mfc71jpn_dll" LongName="mfc71jpn.dll" Name="mfc71jpn.dll" src="$(var.SystemDir)mfc71jpn.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_mfc71kor_dll" Guid="B7290849-638E-4C39-9E56-0D73CF564D69" DiskId="1"> + <File Id="fil_mfc71kor_dll" LongName="mfc71kor.dll" Name="mfc71kor.dll" src="$(var.SystemDir)mfc71kor.dll" KeyPath="yes" /> + </Component> + <Component Id="cmf_runtime_debug1310" Guid="0125814E-9EED-4d57-A4E6-3E685CE5AB5C" DiskId="1"> + <File Id="fil_mfc71d_pdb" LongName="mfc71d.pdb" Name="mfc71d.pdb" src="$(var.SystemDir)mfc71d.pdb" /> + <File Id="fil_msvcr71d_pdb" LongName="msvcr71d.pdb" Name="msvcr71d.pdb" src="$(var.SystemDir)msvcr71d.pdb" KeyPath="yes" /> + <File Id="fil_msvcp71d_pdb" LongName="msvcp71d.pdb" Name="msvcp71d.pdb" src="$(var.SystemDir)msvcp71d.pdb" /> + </Component> + <?endif?> + <?endif?> + <?endif?> + + <Component Id="cmf_psapi_dll" Guid="877F4DD5-8AE0-451C-8F4D-C27F6F30D221" DiskId="1"> + <File Id="fil_psapi_dll" LongName="psapi.dll" Name="psapi.dll" src="$(var.SystemDir)psapi.dll" KeyPath="yes" /> + </Component> + + </Directory> <!-- /bin --> + + <Directory Id="dirinc" Name="inc" src="$(var.IncDir)"> + <Directory Id="dirinc_kclient" Name="kclient" src="$(var.IncDir)kclient\"> + <Component Id="cmp_dirinc_kclient" Guid="96215203-7FF5-4576-AAC5-F5035B64CC37" DiskId="1"> + <File Id="fil_kclient_h" LongName="kclient.h" Name="kclient.h" KeyPath="yes" /> + <File Id="fil_kcmacerr_h" LongName="kcmacerr.h" Name="kcmacerr.h" /> + </Component> + </Directory> + <Directory Id="dirinc_krb4" Name="krb4" src="$(var.IncDir)krb4\"> + <Component Id="cmp_dirinc_krb4" Guid="5D2E3F2E-87AE-4905-84AC-AC503662D1B0" DiskId="1"> + <File Id="fil_com_err_h" LongName="com_err.h" Name="com_err.h" /> + <File Id="fil_conf_pc_h" LongName="conf-pc.h" Name="conf-pc.h" /> + <File Id="fil_conf_h" LongName="conf.h" Name="conf.h" /> + <File Id="fil_des_h" LongName="des.h" Name="des.h" /> + <File Id="fil_kadm_err_h" LongName="kadm_err.h" Name="kadm_err.h" /> + <File Id="fil_krb_h" LongName="krb.h" Name="krb.h" KeyPath="yes" /> + <File Id="fil_krberr_h" LongName="krberr.h" Name="krberr.h" /> + <File Id="fil_mit_copy_h" LongName="mit_copy.h" Name="mit_copy.h" /> + <File Id="fil_osconf_h" LongName="osconf.h" Name="osconf.h" /> + </Component> + </Directory> + <Directory Id="dirinc_krb5" Name="krb5" src="$(var.IncDir)krb5\"> + <Directory Id="dirinc_krb5_gssapi" Name="gssapi" src="$(var.IncDir)\krb5\gssapi\"> + <Component Id="cmp_dirinc_krb5_gssapi" Guid="BD3C190B-1EBB-4d14-81DD-B2000DC4EAC7" DiskId="1"> + <File Id="fil_gssapi_h" LongName="gssapi.h" Name="gssapi.h" KeyPath="yes" /> + <File Id="fil_gssapi_generic_h" LongName="gssapi_generic.h" Name="GSSAPI~1.H" /> + <File Id="fil_gssapi_krb5_h" LongName="gssapi_krb5.h" Name="GSSAPI~2.H" /> + </Component> + </Directory> + <Directory Id="dirinc_krb5_KerberosIV" LongName="KerberosIV" Name="krb4" src="$(var.IncDir)\krb5\KerberosIV\"> + <Component Id="cmp_dirinc_krb5_KerberosIV" Guid="307B8031-2589-4f92-A303-EF4231328490" DiskId="1"> + <File Id="fil_des_.h" LongName="des.h" Name="des.h" /> + <File Id="fil_kadm_err_.h" LongName="kadm_err.h" Name="kadm_err.h" /> + <File Id="fil_krb_.h" LongName="krb.h" Name="krb.h" KeyPath="yes" /> + <File Id="fil_krb_err_.h" LongName="krb_err.h" Name="krb_err.h" /> + <File Id="fil_mit_copyright_.h" LongName="mit-copyright.h" Name="MIT-CO~1.H" /> + </Component> + </Directory> + <Component Id="cmp_dirinc_krb5" Guid="7FD8008B-2F46-4613-8A09-989F643258F1" DiskId="1"> + <File Id="fil_com_err_.h" LongName="com_err.h" Name="com_err.h" /> + <File Id="fil_krb5_.h" LongName="krb5.h" Name="krb5.h" KeyPath="yes" /> + <File Id="fil_profile_.h" LongName="profile.h" Name="profile.h" /> + <File Id="fil_win_mac_.h" LongName="win-mac.h" Name="win-mac.h" /> + </Component> + </Directory> + <Directory Id="dirinc_krbcc" Name="krbcc" src="$(var.IncDir)krbcc\"> + <Component Id="cmp_dirinc_krbcc" Guid="2CE4B708-7D45-41e4-8A53-BF2D78451A81" DiskId="1"> + <File Id="fil_cacheapi_h" LongName="cacheapi.h" Name="cacheapi.h" KeyPath="yes" /> + </Component> + </Directory> + <Directory Id="dirinc_leash" Name="leash" src="$(var.IncDir)leash\"> + <Component Id="cmp_dirinc_leash" Guid="FCF269AB-D9BC-49bd-B9F3-D6EA9697D8D7" DiskId="1"> + <File Id="fil_leasherr_h" LongName="leasherr.h" Name="leasherr.h" /> + <File Id="fil_leashinfo_h" LongName="leashinfo.h" Name="LEASHI~1.H" /> + <File Id="fil_leashwin_h" LongName="leashwin.h" Name="leashwin.h" KeyPath="yes" /> + </Component> + </Directory> + <Directory Id="dirinc_loadfuncs" LongName="loadfuncs" Name="loadfunc" src="$(var.IncDir)loadfuncs\"> + <Component Id="cmp_dirinc_loadfuncs" Guid="C8E59D05-4502-498b-A107-1DF65C3A27D3" DiskId="1"> + <File Id="fil_loadfuncs_afs_h" LongName="loadfuncs-afs.h" Name="LOADFU~1.H" /> + <File Id="fil_loadfuncs_afs36_h" LongName="loadfuncs-afs36.h" Name="LOADFU~2.H" /> + <File Id="fil_loadfuncs_com_err_h" LongName="loadfuncs-com_err.h" Name="LOADFU~3.H" /> + <File Id="fil_loadfuncs_krb_h" LongName="loadfuncs-krb.h" Name="LOADFU~4.H" /> + <File Id="fil_loadfuncs_krb5_h" LongName="loadfuncs-krb5.h" Name="LOC37B~1.H" /> + <File Id="fil_loadfuncs_krb524_h" LongName="loadfuncs-krb524.h" Name="LOCEB8~1.H" /> + <File Id="fil_loadfuncs_leash_h" LongName="loadfuncs-leash.h" Name="LOF608~1.H" /> + <File Id="fil_loadfuncs_lsa_h" LongName="loadfuncs-lsa.h" Name="LO1903~1.H" /> + <File Id="fil_loadfuncs_profile_h" LongName="loadfuncs-profile.h" Name="LOD197~1.H" /> + <File Id="fil_loadfuncs_wshelper_h" LongName="loadfuncs-wshelper.h" Name="LO8FF4~1.H" /> + <File Id="fil_loadfuncs_c" LongName="loadfuncs.c" Name="LOADFU~1.C" /> + <File Id="fil_loadfuncs_h" LongName="loadfuncs.h" Name="LO87BD~1.H" KeyPath="yes" /> + </Component> + </Directory> + <Directory Id="dirinc_netidmgr" Name="netidmgr" src="$(var.IncDir)netidmgr\"> + <Component Id="cmp_dirinc_netidmgr" Guid="EBD8BA04-574A-4081-A994-BCEC8ACBC878" DiskId="1"> + <File Id="fil_hashtable_h" LongName="hashtable.h" Name="HASHTA~1.H" /> + <File Id="fil_kconfig_h" LongName="kconfig.h" Name="kconfig.h" /> + <File Id="fil_kcreddb_h" LongName="kcreddb.h" Name="kcreddb.h" /> + <File Id="fil_khaction_h" LongName="khaction.h" Name="khaction.h" /> + <File Id="fil_khactiondef_h" LongName="khactiondef.h" Name="KHACTI~1.H" /> + <File Id="fil_khalerts_h" LongName="khalerts.h" Name="khalerts.h" /> + <File Id="fil_khconfigui_h" LongName="khconfigui.h" Name="KHCONF~1.H" /> + <File Id="fil_khdefs_h" LongName="khdefs.h" Name="khdefs.h" /> + <File Id="fil_kherr_h" LongName="kherr.h" Name="kherr.h" /> + <File Id="fil_kherror_h" LongName="kherror.h" Name="kherror.h" /> + <File Id="fil_khhtlink_h" LongName="khhtlink.h" Name="khhtlink.h" /> + <File Id="fil_khlist_h" LongName="khlist.h" Name="khlist.h" /> + <File Id="fil_khmsgtypes_h" LongName="khmsgtypes.h" Name="KHMSGT~1.H" /> + <File Id="fil_khnewcred_h" LongName="khnewcred.h" Name="KHNEWC~1.H" /> + <File Id="fil_khprops_h" LongName="khprops.h" Name="khprops.h" /> + <File Id="fil_khremote_h" LongName="khremote.h" Name="khremote.h" /> + <File Id="fil_khrescache_h" LongName="khrescache.h" Name="KHRESC~1.H" /> + <File Id="fil_khtracker_h" LongName="khtracker.h" Name="KHTRAC~1.H" /> + <File Id="fil_khuidefs_h" LongName="khuidefs.h" Name="khuidefs.h" KeyPath="yes" /> + <File Id="fil_kmm_h" LongName="kmm.h" Name="kmm.h" /> + <File Id="fil_kmq_h" LongName="kmq.h" Name="kmq.h" /> + <File Id="fil_kplugin_h" LongName="kplugin.h" Name="kplugin.h" /> + <File Id="fil_mstring_h" LongName="mstring.h" Name="mstring.h" /> + <File Id="fil_sync_h" LongName="sync.h" Name="sync.h" /> + <File Id="fil_utils_h" LongName="utils.h" Name="utils.h" /> + <File Id="fil_perfstat_h" LongName="perfstat.h" Name="perfstat.h" /> + <File Id="fil_netidmgr_h" LongName="netidmgr.h" Name="netidmgr.h" /> + <File Id="fil_netidmgr_version_h" LongName="netidmgr_version.h" Name="netidmvr.h" /> + </Component> + </Directory> + <Directory Id="dirinc_wshelper" Name="wshelper" src="$(var.IncDir)wshelper\"> + <Component Id="cmp_dirinc_wshelper" Guid="5A4FCD76-6DC6-455c-B465-FD8123252EBD" DiskId="1"> + <File Id="fil_hesiod_h" LongName="hesiod.h" Name="hesiod.h" /> + <File Id="fil_mitwhich_h" LongName="mitwhich.h" Name="mitwhich.h" /> + <File Id="fil_resolv_h" LongName="resolv.h" Name="resolv.h" /> + <File Id="fil_wshelper_h" LongName="wshelper.h" Name="wshelper.h" KeyPath="yes" /> + </Component> + <Directory Id="dirinc_wshelper_arpa" Name="arpa" src="$(var.IncDir)\wshelper\arpa\"> + <Component Id="cmp_dirinc_wshelper_arpa" Guid="42A19215-91D6-4cd6-8BE8-95105849B862" DiskId="1"> + <File Id="fil_nameser_h" LongName="nameser.h" Name="nameser.h" KeyPath="yes" /> + </Component> + </Directory> + </Directory> + </Directory> + + <Directory Id="dirlib" Name="lib" src="$(var.LibDir)"> + <Directory Id="dirlib_i386" Name="i386" src="$(var.LibDir)"> + <Component Id="cmp_dirlib_i386" Guid="CFEE3ED4-92D4-49e1-BB78-8BCBC60C3E57" DiskId="1"> + <File Id="fil_comerr32_lib" LongName="comerr32.lib" Name="comerr32.lib" /> + <File Id="fil_delaydlls_lib" LongName="delaydlls.lib" Name="DELAYD~1.LIB" /> + <File Id="fil_getopt_lib" LongName="getopt.lib" Name="getopt.lib" /> + <File Id="fil_gssapi32_lib" LongName="gssapi32.lib" Name="gssapi32.lib" /> + <File Id="fil_kclnt32_lib" LongName="kclnt32.lib" Name="kclnt32.lib" /> + <File Id="fil_krb524_lib" LongName="krb524.lib" Name="krb524.lib" /> + <File Id="fil_krb5_32_lib" LongName="krb5_32.lib" Name="krb5_32.lib" KeyPath="yes" /> + <File Id="fil_krbcc32_lib" LongName="krbcc32.lib" Name="krbcc32.lib" /> + <File Id="fil_krbv4w32_lib" LongName="krbv4w32.lib" Name="krbv4w32.lib" /> + <File Id="fil_leashw32_lib" LongName="leashw32.lib" Name="leashw32.lib" /> + <File Id="fil_loadfuncs_lib" LongName="loadfuncs.lib" Name="LOADFU~1.LIB" /> + <File Id="fil_wshelp32_lib" LongName="wshelp32.lib" Name="wshelp32.lib" /> + <File Id="fil_xpprof32_lib" LongName="xpprof32.lib" Name="xpprof32.lib" /> + <File Id="fil_nidmgr32_lib" LongName="nidmgr32.lib" Name="nidmgr32.lib" /> + </Component> + </Directory> + </Directory> + + <Directory Id="dirinstall" Name="install" src="$(var.InstallDir)"> + <Directory Id="dirinstall_nsis" Name="nsis" src="$(var.InstallDir)nsis\"> + <Component Id="cmp_dirinstall_nsis" Guid="711C3910-5369-44f3-A023-E09E86A1C749" DiskId="1"> + <File Id="fil_kfw_fixed_nsi" LongName="kfw-fixed.nsi" Name="KFW-FI~1.NSI" KeyPath="yes" /> + <File Id="fil_kfw_ico" LongName="kfw.ico" Name="kfw.ico" /> + <File Id="fil_kfw_nsi" LongName="kfw.nsi" Name="kfw.nsi" /> + <File Id="fil_KfWConfigPage_ini" LongName="KfWConfigPage.ini" Name="KFWCON~1.INI" /> + <File Id="fil_KfWConfigPage2_ini" LongName="KfWConfigPage2.ini" Name="KFWCON~2.INI" /> + <File Id="fil_killer_cpp" LongName="killer.cpp" Name="killer.cpp" /> + <File Id="fil_licenses_rtf" LongName="licenses.rtf" Name="licenses.rtf" /> + <File Id="fil_site_local_nsi" LongName="site-local.nsi" Name="SITE-L~1.NSI" /> + <File Id="fil_utils_nsi" LongName="utils.nsi" Name="utils.nsi" /> + </Component> + </Directory> + <Directory Id="dirinstall_wix" Name="wix" src="$(var.InstallDir)wix\"> + <Component Id="cmp_dirinstall_wix" Guid="14DD16AB-6920-4ee1-8B78-623F39DB70BB" DiskId="1"> + <File Id="fil_config_wxi" LongName="config.wxi" Name="config.wxi" /> + <File Id="fil_features_wxi" LongName="features.wxi" Name="features.wxi" /> + <File Id="fil_files_wxi" LongName="files.wxi" Name="files.wxi" /> + <File Id="fil_kfw_wxs" LongName="kfw.wxs" Name="kfw.wxs" KeyPath="yes" /> + <File Id="fil_Makefile_" LongName="Makefile" Name="Makefile" /> + <File Id="fil_property_wxi" LongName="property.wxi" Name="property.wxi" /> + <File Id="fil_site_local_wxi" LongName="site-local.wxi" Name="SITE-L~1.WXI" /> + </Component> + <Directory Id="dirinstall_wix_lang" Name="lang" src="$(var.InstallDir)wix\lang\"> + <Component Id="cmp_dirinstall_wix_lang" Guid="70741A69-1103-4B54-B146-2E14C271945D" DiskId="1"> + <File Id="fil_config_1033_wxi" LongName="config_1033.wxi" Name="CONFIG~1.WXI" KeyPath="yes" /> + <File Id="fil_strings_1033_wxl" LongName="strings_1033.wxl" Name="STRING~1.WXL" /> + <File Id="fil_ui_1033_wxi" LongName="ui_1033.wxi" Name="ui_1033.wxi" /> + </Component> + </Directory> + <Directory Id="dirinstall_wix_Binary" Name="Binary" src="$(var.InstallDir)wix\Binary\"> + <Component Id="cmp_dirinstall_wix_Binary" Guid="5F021D71-A398-41FD-8F9C-9C0665C18660" DiskId="1"> + <File Id="fil_bannrbmp_bmp" LongName="bannrbmp.bmp" Name="bannrbmp.bmp" /> + <File Id="fil_completi_ico" LongName="completi.ico" Name="completi.ico" /> + <File Id="fil_custicon_ico" LongName="custicon.ico" Name="custicon.ico" /> + <File Id="fil_dlgbmp_bmp" LongName="dlgbmp.bmp" Name="dlgbmp.bmp" /> + <File Id="fil_exclamic_ico" LongName="exclamic.ico" Name="exclamic.ico" /> + <File Id="fil_info_bmp" LongName="info.bmp" Name="info.bmp" /> + <File Id="fil_insticon_ico" LongName="insticon.ico" Name="insticon.ico" /> + <File Id="fil_new_bmp" LongName="new.bmp" Name="new.bmp" /> + <File Id="fil_removico_ico" LongName="removico.ico" Name="removico.ico" /> + <File Id="fil_repairic_ico" LongName="repairic.ico" Name="repairic.ico" /> + <File Id="fil_up_bmp" LongName="up.bmp" Name="up.bmp" /> + </Component> + </Directory> + <Directory Id="dirinstall_wix_custom" Name="custom" src="$(var.InstallDir)wix\custom\"> + <Component Id="cmp_dirinstall_wix_custom" Guid="872AA948-39B0-4CDC-B764-7EB69F280E50" DiskId="1"> + <File Id="fil_custom_cpp" LongName="custom.cpp" Name="custom.cpp" KeyPath="yes" /> + <File Id="fil_custom_h" LongName="custom.h" Name="custom.h" /> + </Component> + </Directory> + </Directory> + </Directory> + + <Directory Id="dirdoc" Name="doc" src="$(var.DocDir)"> + <Component Id="efl_leash_userdoc_pdf" Guid="68FB24DD-5EC2-4db1-AD42-5B9DDEC247C5" DiskId="1"> + <File Id="fil_leash_userdoc_pdf" LongName="leash_userdoc.pdf" Name="leash.pdf" KeyPath="yes"> + <Shortcut Id="sc_leash_userdoc_pdf" Advertise="no" Directory="dirShortcut" LongName="Leash User Documentation.lnk" Name="leashdoc.lnk" /> + </File> + <Condition>USELEASH</Condition> + </Component> + <Component Id="efl_netidmgr_userdoc_pdf" Guid="7F5A91C1-C6D3-4F64-A6AC-C0AF337B4ED6" DiskId="1"> + <File Id="fil_netidmgr_userdoc_pdf" LongName="netidmgr_userdoc.pdf" Name="netidmgr.pdf" KeyPath="yes"> + <Shortcut Id="sc_netidmgr_userdoc_pdf" Advertise="no" Directory="dirShortcut" LongName="Network Identity Manager User Documentation.lnk" Name="netiddoc.lnk" /> + </File> + <Condition>USENETIDMGR</Condition> + </Component> + <Component Id="cmp_dirdoc_netid" Guid="D501BAF7-7E63-4864-AFED-1528D1C59B1B" DiskId="1"> + <File Id="fil_netidmgr_devdoc_chm" Name="netiddev.chm" KeyPath="yes"> + <Shortcut Id="sc_netidmgr_devdoc_chm" Advertise="no" Directory="dirShortcut" LongName="Network Identity Manager Developer Documentation.lnk" Name="netiddev.lnk" /> + </File> + <Condition>USENETIDMGR</Condition> + </Component> + <Component Id="efl_relnotes_html" Guid="C65F920A-039D-4839-848F-0AD7B445F376" DiskId="1"> + <File Id="fil_relnotes_html" LongName="relnotes.html" Name="RELNOT~1.HTM" KeyPath="yes"> + <Shortcut Id="sc_relnotes_html" Advertise="no" Directory="dirShortcut" LongName="Release Notes.lnk" Name="relnotes.lnk" /> + </File> + </Component> + </Directory> + + </Directory> <!-- /Kerberos --> + </Directory> <!-- /MIT --> + </Directory> <!-- /Program Files --> + <Directory Id="WindowsFolder"> + <Component Id="cmf_krb5_ini" Guid="C1AF0670-BBF1-4AA6-B2A6-6C8B1584A1F4" NeverOverwrite="yes" Permanent="yes" DiskId="1"> + <File Id="fil_krb5_ini" LongName="krb5.ini" Name="krb5.ini" src="$(var.ConfigDir)krb5.ini" KeyPath="yes" /> + </Component> + <Component Id="cmf_krb_con" Guid="5E91A051-CF14-45FF-BF64-CEE78A7A90C2" NeverOverwrite="yes" Permanent="yes" DiskId="1"> + <File Id="fil_krb_con" LongName="krb.con" Name="krb.con" src="$(var.ConfigDir)krb.con" KeyPath="yes" /> + </Component> + <Component Id="cmf_krbrealm_con" Guid="D667B54F-1C98-43FB-87C6-0F0517623B90" NeverOverwrite="yes" Permanent="yes" DiskId="1"> + <File Id="fil_krbrealm_con" LongName="krbrealm.con" Name="krbrealm.con" src="$(var.ConfigDir)krbrealm.con" KeyPath="yes" /> + </Component> + </Directory> + + <Directory Id="ProgramMenuFolder"> + <Directory Id="dirShortcut" LongName="$(loc.ProductName)" Name="KFW"> + </Directory> + </Directory> + <Directory Id="StartupFolder"> + </Directory> + + <Component Id="rcm_common" Guid="486D84B6-CCE5-4b95-B8E2-7DFBDB4CF9A2"> + <Registry Id="reg_common0" Root="HKLM" Key="$(var.KfwRegRoot)" Action="createKeyAndRemoveKeyOnUninstall" /> + <Registry Id="reg_common1" Root="HKLM" Key="$(var.KfwRegRoot)" KeyPath="yes" /> + <Registry Id="reg_common2" Root="HKLM" Key="$(var.KfwRegRoot)" Name="InstallDir" Type="string" Value="[KERBEROSDIR]"/> + <?ifdef Debug?> + <Registry Id="reg_common3" Root="HKLM" Key="$(var.KfwRegRoot)\CurrentVersion" Action="createKeyAndRemoveKeyOnUninstall"/> + <Registry Id="reg_common4" Root="HKLM" Key="$(var.KfwRegRoot)\CurrentVersion" Name="Debug" Type="integer" Value="1"/> + <Registry Id="reg_common5" Root="HKLM" Key="$(var.KfwRegRoot)\$(var.VersionString)" Action="createKeyAndRemoveKeyOnUninstall"/> + <Registry Id="reg_common6" Root="HKLM" Key="$(var.KfwRegRoot)\$(var.VersionString)" Name="Debug" Type="integer" Value="1"/> + <?else?> + <Registry Id="reg_common7" Root="HKLM" Key="$(var.KfwRegRoot)\CurrentVersion" Action="removeKeyOnInstall"/> + <Registry Id="reg_common8" Root="HKLM" Key="$(var.KfwRegRoot)\$(var.VersionString)" Action="removeKeyOnInstall"/> + <?endif?> + </Component> + + <Component Id="rcm_client" Guid="901179B2-7369-43b1-ACF3-4C7F37482CC7"> + <Registry Id="reg_client0" Root="HKLM" Key="$(var.KfwRegRoot)\Client" Action="createKeyAndRemoveKeyOnUninstall"/> + + <Registry Id="reg_client1" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Action="createKeyAndRemoveKeyOnUninstall"/> + <Registry Id="reg_client2" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" /> + <Registry Id="reg_client3" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Name="VersionString" Type="string" Value="$(var.VersionString)" /> + <Registry Id="reg_client4" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Name="Title" Type="string" Value="KfW" /> + <Registry Id="reg_client5" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Name="Description" Type="string" Value="$(var.ProductFullName)" /> + <Registry Id="reg_client6" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Name="PathName" Type="string" Value="[KERBEROSDIR]" /> + <Registry Id="reg_client7" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Name="Software Type" Type="string" Value="Authentication" /> + <Registry Id="reg_client8" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Name="MajorVersion" Type="integer" Value="$(var.VersionMajor)" /> + <Registry Id="reg_client9" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Name="MinorVersion" Type="integer" Value="$(var.VersionMinor)" /> + <Registry Id="reg_client10" Root="HKLM" Key="$(var.KfwRegRoot)\Client\CurrentVersion" Name="PatchLevel" Type="integer" Value="$(var.VersionPatch)" /> + + <Registry Id="reg_client11" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Action="createKeyAndRemoveKeyOnUninstall"/> + <Registry Id="reg_client12" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" KeyPath="yes" /> + <Registry Id="reg_client13" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="VersionString" Type="string" Value="$(var.VersionString)" /> + <Registry Id="reg_client14" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="Title" Type="string" Value="KfW" /> + <Registry Id="reg_client15" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="Description" Type="string" Value="$(var.ProductFullName)" /> + <Registry Id="reg_client16" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="PathName" Type="string" Value="[KERBEROSDIR]" /> + <Registry Id="reg_client17" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="Software Type" Type="string" Value="Authentication" /> + <Registry Id="reg_client18" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="MajorVersion" Type="integer" Value="$(var.VersionMajor)" /> + <Registry Id="reg_client19" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="MinorVersion" Type="integer" Value="$(var.VersionMinor)" /> + <Registry Id="reg_client20" Root="HKLM" Key="$(var.KfwRegRoot)\Client\$(var.VersionString)" Name="PatchLevel" Type="integer" Value="$(var.VersionPatch)" /> + </Component> + + <Component Id="rcm_sdk" Guid="96AA90C7-8C60-4341-A15B-3DEDF29DA9F1"> + <Registry Id="reg_sdk0" Root="HKLM" Key="$(var.KfwRegRoot)\SDK" Action="createKeyAndRemoveKeyOnUninstall"/> + + <Registry Id="reg_sdk1" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Action="createKeyAndRemoveKeyOnUninstall"/> + <Registry Id="reg_sdk2" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" /> + <Registry Id="reg_sdk3" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Name="VersionString" Type="string" Value="$(var.VersionString)" /> + <Registry Id="reg_sdk4" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Name="Title" Type="string" Value="KfW" /> + <Registry Id="reg_sdk5" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Name="Description" Type="string" Value="$(var.ProductFullName)" /> + <Registry Id="reg_sdk6" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Name="PathName" Type="string" Value="[KERBEROSDIR]" /> + <Registry Id="reg_sdk7" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Name="Software Type" Type="string" Value="Authentication" /> + <Registry Id="reg_sdk8" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Name="MajorVersion" Type="integer" Value="$(var.VersionMajor)" /> + <Registry Id="reg_sdk9" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Name="MinorVersion" Type="integer" Value="$(var.VersionMinor)" /> + <Registry Id="reg_sdk10" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\CurrentVersion" Name="PatchLevel" Type="integer" Value="$(var.VersionPatch)" /> + + <Registry Id="reg_sdk11" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Action="createKeyAndRemoveKeyOnUninstall"/> + <Registry Id="reg_sdk12" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" KeyPath="yes" /> + <Registry Id="reg_sdk13" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Name="VersionString" Type="string" Value="$(var.VersionString)" /> + <Registry Id="reg_sdk14" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Name="Title" Type="string" Value="KfW" /> + <Registry Id="reg_sdk15" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Name="Description" Type="string" Value="$(var.ProductFullName)" /> + <Registry Id="reg_sdk16" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Name="PathName" Type="string" Value="[KERBEROSDIR]" /> + <Registry Id="reg_sdk17" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Name="Software Type" Type="string" Value="Authentication" /> + <Registry Id="reg_sdk18" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Name="MajorVersion" Type="integer" Value="$(var.VersionMajor)" /> + <Registry Id="reg_sdk19" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Name="MinorVersion" Type="integer" Value="$(var.VersionMinor)" /> + <Registry Id="reg_sdk20" Root="HKLM" Key="$(var.KfwRegRoot)\SDK\$(var.VersionString)" Name="PatchLevel" Type="integer" Value="$(var.VersionPatch)" /> + </Component> + + <Component Id="rcm_docs" Guid="C7EADA0F-8FF7-4e7b-9372-5553BDD5812F"> + <Registry Id="reg_docs0" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation" Action="createKeyAndRemoveKeyOnUninstall"/> + + <Registry Id="reg_docs1" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Action="createKeyAndRemoveKeyOnUninstall"/> + <Registry Id="reg_docs2" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" /> + <Registry Id="reg_docs3" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Name="VersionString" Type="string" Value="$(var.VersionString)" /> + <Registry Id="reg_docs4" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Name="Title" Type="string" Value="KfW" /> + <Registry Id="reg_docs5" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Name="Description" Type="string" Value="$(var.ProductFullName)" /> + <Registry Id="reg_docs6" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Name="PathName" Type="string" Value="[KERBEROSDIR]" /> + <Registry Id="reg_docs7" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Name="Software Type" Type="string" Value="Authentication" /> + <Registry Id="reg_docs8" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Name="MajorVersion" Type="integer" Value="$(var.VersionMajor)" /> + <Registry Id="reg_docs9" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Name="MinorVersion" Type="integer" Value="$(var.VersionMinor)" /> + <Registry Id="reg_docs10" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\CurrentVersion" Name="PatchLevel" Type="integer" Value="$(var.VersionPatch)" /> + + <Registry Id="reg_docs11" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Action="createKeyAndRemoveKeyOnUninstall"/> + <Registry Id="reg_docs12" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" KeyPath="yes" /> + <Registry Id="reg_docs13" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Name="VersionString" Type="string" Value="$(var.VersionString)" /> + <Registry Id="reg_docs14" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Name="Title" Type="string" Value="KfW" /> + <Registry Id="reg_docs15" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Name="Description" Type="string" Value="$(var.ProductFullName)" /> + <Registry Id="reg_docs16" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Name="PathName" Type="string" Value="[KERBEROSDIR]" /> + <Registry Id="reg_docs17" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Name="Software Type" Type="string" Value="Authentication" /> + <Registry Id="reg_docs18" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Name="MajorVersion" Type="integer" Value="$(var.VersionMajor)" /> + <Registry Id="reg_docs19" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Name="MinorVersion" Type="integer" Value="$(var.VersionMinor)" /> + <Registry Id="reg_docs20" Root="HKLM" Key="$(var.KfwRegRoot)\Documentation\$(var.VersionString)" Name="PatchLevel" Type="integer" Value="$(var.VersionPatch)" /> + </Component> + +</Directory> +</Include> \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/kfw.wxs b/mechglue/src/windows/installer/wix/kfw.wxs new file mode 100644 index 000000000..667413c9e --- /dev/null +++ b/mechglue/src/windows/installer/wix/kfw.wxs @@ -0,0 +1,237 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + + Copyright (C) 2004,2005 by the Massachusetts Institute of Technology. + All rights reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization contemplating + export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of M.I.T. not be used in advertising or publicity pertaining + to distribution of the software without specific, written prior + permission. Furthermore if you modify this software you must label + your software as modified software and not distribute it in such a + fashion that it might be confused with the original M.I.T. software. + M.I.T. makes no representations about the suitability of + this software for any purpose. It is provided "as is" without express + or implied warranty. + + --> + +<!-- configuration --> +<?include config.wxi?> + +<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> + <Product + Id="$(var.ProductCode)" + Codepage="$(var.CodePage)" + Language="$(var.Language)" + Manufacturer="$(loc.Manufacturer)" + Name="$(var.ProductName)" + UpgradeCode="61211594-AAA1-4A98-A299-757326763CC7" + Version="$(var.VersionString)"> + + <!-- The weird package code results in a new one being generated each time we compile --> + <Package + Id="????????-????-????-????-????????????" + Keywords="Installer,MSI,Database" + Description="$(var.ProductName)" + Comments="$(var.ProductFullName)" + Manufacturer="$(loc.Manufacturer)" + InstallerVersion="110" + Languages="$(var.Language)" + Compressed="yes" + SummaryCodepage="$(var.CodePage)" + /> + + <?include lang\ui_$(var.BuildLang).wxi?> + <?include files.wxi?> + <?include features.wxi?> + <?include property.wxi?> + + <!-- Launch conditions --> + <Condition Message="$(loc.AdminRequired)">Privileged</Condition> + <Condition Message="$(loc.OsVersionRequired)">VersionNT >= 500</Condition> + <Condition Message="$(loc.CMNotSelected)">USELEASH Or USENETIDMGR</Condition> + <Condition Message="$(loc.CMDupSelected)">Not (USELEASH And USENETIDMGR)</Condition> + + <!-- Custom actions --> + <Binary Id="binCustom" src="custom\custom.dll" /> + + <CustomAction + Id="EnableTgtSessionKey" + BinaryKey="binCustom" + DllEntry="EnableAllowTgtSessionKey" + Execute="deferred" + Impersonate="no" + Return="check" /> + <Property Id="EnableTgtSessionKey" Value="$(var.VersionString)" /> + + <CustomAction + Id="RevertTgtSessionKey" + BinaryKey="binCustom" + DllEntry="RevertAllowTgtSessionKey" + Execute="deferred" + Impersonate="no" + Return="check" /> + <Property Id="RevertTgtSessionKey" Value="$(var.VersionString)" /> + + <CustomAction + Id="RollbackTgtSessionKey" + BinaryKey="binCustom" + DllEntry="RevertAllowTgtSessionKey" + Execute="rollback" + Impersonate="no" + Return="check" /> + <Property Id="RollbackTgtSessionKey" Value="$(var.VersionString)" /> + + <CustomAction + Id="RemoveNsisInstallation" + BinaryKey="binCustom" + DllEntry="UninstallNsisInstallation" + Execute="immediate" /> + + <CustomAction + Id="AbortCantRemoveNSIS" + Value="[CantRemoveNSISError]" /> + + <CustomAction + Id="AbortNoIE" + Value="[NoIE501Error]" /> + + <CustomAction + Id="ListRunningProcesses" + BinaryKey="binCustom" + DllEntry="ListRunningProcesses" + Execute="immediate" + Return="ignore" /> + + <CustomAction + Id="KillRunningProcesses" + BinaryKey="binCustom" + DllEntry="KillRunningProcesses" + Execute="immediate" + Return="ignore" /> + + <CustomAction + Id="InstallNetProvider" + BinaryKey="binCustom" + DllEntry="InstallNetProvider" + Impersonate="no" + Execute="deferred" /> + + <CustomAction + Id="RemoveNetProvider" + BinaryKey="binCustom" + DllEntry="UninstallNetProvider" + Impersonate="no" + Return="ignore" + Execute="deferred" /> + + <CustomAction + Id="RollbackNetProvider" + BinaryKey="binCustom" + DllEntry="UninstallNetProvider" + Return="ignore" + Execute="rollback" /> + + <!-- Installation Sequences --> + <AdminExecuteSequence /> + <InstallExecuteSequence> + <RemoveExistingProducts After="InstallValidate">UPGRADEPISMERE Or UPGRADEKFW</RemoveExistingProducts> + <Custom Action="KillRunningProcesses" After="InstallValidate"/> + <!-- When running with a UI, CCP_Success property is not passed down to the server. --> + <Custom Action="AbortNoIE" Before="RemoveNsisInstallation">UILevel = 0 And (Not Installed) And (CCP_Success <> 1)</Custom> + <Custom Action="RemoveNsisInstallation" Before="AbortCantRemoveNSIS">UPGRADENSIS <> "" And UILevel >= 4</Custom> + <Custom Action="AbortCantRemoveNSIS" Before="CostInitialize">UPGRADENSIS <> "" And UILevel < 4</Custom> + <Custom Action="RollbackTgtSessionKey" After="WriteRegistryValues">VersionNT >= 500 And &feaKfwClient=3</Custom> + <Custom Action="EnableTgtSessionKey" After="RollbackTgtSessionKey">VersionNT >= 500 And &feaKfwClient=3</Custom> + <Custom Action="RevertTgtSessionKey" Before="RemoveRegistryValues">VersionNT >= 500 And &feaKfwClient=2</Custom> + + <Custom Action="RollbackNetProvider" After="RollbackTgtSessionKey">&feaKfwClient=3</Custom> + <Custom Action="InstallNetProvider" After="RollbackNetProvider">&feaKfwClient=3</Custom> + <Custom Action="RemoveNetProvider" After="InstallNetProvider">&feaKfwClient=2</Custom> + </InstallExecuteSequence> + + <!-- Upgrade paths --> + + <!-- MIT Project Pismere MSI --> + <Upgrade Id="83977767-388D-4DF8-BB08-3BF2401635BD"> + <UpgradeVersion IgnoreRemoveFailure="no" IncludeMinimum="no" Maximum="4.0.0" MigrateFeatures="no" Property="UPGRADEPISMERE"/> + </Upgrade> + + <!-- KfW MSI --> + <Upgrade Id="61211594-AAA1-4A98-A299-757326763CC7"> + <UpgradeVersion IgnoreRemoveFailure="no" IncludeMinimum="no" Maximum="$(var.VersionString)" IncludeMaximum="yes" MigrateFeatures="yes" Property="UPGRADEKFW" /> + </Upgrade> + + <!-- NSIS installation --> + <!-- The NSIS installation, being non-MSI, is detected and removed through other means. --> + + <!-- Check and warn if we don't have the right version of IE installed --> + <ComplianceCheck> + <DirectorySearch Id="ccd_iphlpapi" Depth="1" Path="[SystemFolder]"> + <FileSearch Id="cc_iphlp" MinDate="1999-04-23T00:00:00-05:00" Name="iphlpapi.dll" /> + </DirectorySearch> + </ComplianceCheck> + + <!-- We embed all the files in a single cabinet. --> + <Media Id="1" Cabinet="Disk1" CompressionLevel="high" EmbedCab="yes" /> + + <!-- Custom table used by KillProcesses custom action --> + <CustomTable Id="KillProcess"> + <Column Id="Id" PrimaryKey="yes" Nullable="no" Type="string" Width="32" /> + <Column Id="Image" Nullable="no" Type="string" Width="255" /> + <Column Id="Desc" Nullable="yes" Type="string" Width="255" /> + + <Row> + <Data Column="Id">kpLeash</Data> + <Data Column="Image">leash32.exe</Data> + <Data Column="Desc">Leash Ticket Manager</Data> + </Row> + <Row> + <Data Column="Id">kpNetIDMgr</Data> + <Data Column="Image">netidmgr.exe</Data> + <Data Column="Desc">Network Identity Manager</Data> + </Row> + <Row> + <Data Column="Id">kpKrbcc</Data> + <Data Column="Image">krbcc32s.exe</Data> + <Data Column="Desc">Kerberos Credential Cache</Data> + </Row> + <Row> + <Data Column="Id">kpK95</Data> + <Data Column="Image">k95.exe</Data> + <Data Column="Desc">Kermit 95</Data> + </Row> + <Row> + <Data Column="Id">kpK95g</Data> + <Data Column="Image">k95g.exe</Data> + <Data Column="Desc">Kermit 95 GUI</Data> + </Row> + <Row> + <Data Column="Id">kpkrb5</Data> + <Data Column="Image">krb5.exe</Data> + <Data Column="Desc">Kerberos Client</Data> + </Row> + <Row> + <Data Column="Id">kpgss</Data> + <Data Column="Image">gss.exe</Data> + <Data Column="Desc">GSSAPI Test Client</Data> + </Row> + <Row> + <Data Column="Id">kpafscreds</Data> + <Data Column="Image">afscreds.exe</Data> + <Data Column="Desc">AFS Credentials Manager</Data> + </Row> + </CustomTable> + </Product> +</Wix> + diff --git a/mechglue/src/windows/installer/wix/lang/ChangeLog b/mechglue/src/windows/installer/wix/lang/ChangeLog new file mode 100644 index 000000000..23a6add21 --- /dev/null +++ b/mechglue/src/windows/installer/wix/lang/ChangeLog @@ -0,0 +1,12 @@ +2004-12-18 Jeffrey Altman <jaltman@mit.edu> + + Add Debug Symbols as an optional install feature for + release builds of KFW2004-08-20 Jeffrey Altman <jaltman@mit.edu> + +2004-12-15 Jeffrey Altman <jaltman@mit.edu> + + Update for WiX 2.1 installer + +2004-08-20 Asanka Herath <asanka@mit.edu> + + New WiX 2.0 MSI for KFW \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/lang/config_1033.wxi b/mechglue/src/windows/installer/wix/lang/config_1033.wxi new file mode 100644 index 000000000..0fc62e3d1 --- /dev/null +++ b/mechglue/src/windows/installer/wix/lang/config_1033.wxi @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + + Copyright (C) 2004 by the Massachusetts Institute of Technology. + All rights reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization contemplating + export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of M.I.T. not be used in advertising or publicity pertaining + to distribution of the software without specific, written prior + permission. Furthermore if you modify this software you must label + your software as modified software and not distribute it in such a + fashion that it might be confused with the original M.I.T. software. + M.I.T. makes no representations about the suitability of + this software for any purpose. It is provided "as is" without express + or implied warranty. + + --> +<Include xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> + + <?define VersionString="$(var.VersionMajor).$(var.VersionMinor).$(var.VersionPatch)"?> + + <?ifdef var.Release?> + <?ifndef var.Debug?> + <?define ProductFullName="$(loc.ProductMIT) $(loc.ProductName) $(var.VersionString)"?> + <?else?> + <?define ProductFullName="$(loc.ProductMIT) $(loc.ProductName) $(var.VersionString) $(loc.ProductDebug)"?> + <?endif?> + <?else?> + <?ifdef var.Beta?> + <?ifndef var.Debug?> + <?define ProductFullName="$(loc.ProductMIT) $(loc.ProductName) $(var.VersionString) $(loc.ProductBeta) $(var.Beta) "?> + <?else?> + <?define ProductFullName="$(loc.ProductMIT) $(loc.ProductName) $(var.VersionString) $(loc.ProductBeta) $(var.Beta) $(loc.ProductDebug)"?> + <?endif?> + <?else?> + + <?ifndef var.Date?> + <?error Date string must be specified?> + <?endif?> + + <?ifndef var.Time?> + <?error Time string must be specified?> + <?endif?> + + <?ifndef var.Debug?> + <?define ProductFullName="$(loc.ProductMIT) $(loc.ProductName) $(var.VersionString) $(var.Date) $(var.Time)"?> + <?else?> + <?define ProductFullName="$(loc.ProductMIT) $(loc.ProductName) $(var.VersionString) $(var.Date) $(var.Time) $(loc.ProductDebug)"?> + <?endif?> + <?endif?> + <?endif?> + + <!-- Language specific configuration (English) --> + <?define ProductName="$(var.ProductFullName)"?> + <?define CodePage="1252"?> + <?define Language="1033"?> + + <?define ARPComments="$(loc.ARPComments) $(var.Date) $(var.Time)"?> +</Include> \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/lang/license.rtf b/mechglue/src/windows/installer/wix/lang/license.rtf new file mode 100644 index 000000000..b28c08026 --- /dev/null +++ b/mechglue/src/windows/installer/wix/lang/license.rtf @@ -0,0 +1,102 @@ +{\rtf1\ansi\ansicpg1252\deff0\deflang1033\deflangfe1033{\fonttbl{\f0\fmodern\fprq1\fcharset0 Courier New;}{\f1\froman\fprq2\fcharset0 Times New Roman;}} +{\*\generator Msftedit 5.41.15.1507;}\viewkind4\uc1\pard\nowidctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\f0\fs20 Copyright Notice and Legal Administrivia\par +----------------------------------------\par +\par +Copyright (C) 1985-2005 by the Massachusetts Institute of Technology.\par +\par +All rights reserved.\par +\par +Export of this software from the United States of America may require a specific license from the United States Government. It is the responsibility of any person or organization contemplating export to obtain such a license before exporting.\par +\par +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and\par +this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Furthermore if you modify this software you must label your software as modified software and not distribute it in such a fashion that it might be confused with the original MIT software. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.\par +\par +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\par +\par +Individual source code files are copyright MIT, Cygnus Support, OpenVision, Oracle, Sun Soft, FundsXpress, and others.\par +\par +Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira, and Zephyr are trademarks of the Massachusetts Institute of Technology (MIT). No commercial use of these trademarks may be made without prior written permission of MIT.\par +\par +"Commercial use" means use of a name in a product or other for-profit manner. It does NOT prevent a commercial firm from referring to the MIT trademarks in order to convey information (although in doing so, recognition of their trademark status should be given).\par +\par +----\par +\par +The following copyright and permission notice applies to the OpenVision Kerberos Administration system located in kadmin/create, kadmin/dbutil, kadmin/passwd, kadmin/server, lib/kadm5, and portions of lib/rpc:\par +\par +Copyright, OpenVision Technologies, Inc., 1996, All Rights Reserved\par +\par +WARNING: Retrieving the OpenVision Kerberos Administration system source code, as described below, indicates your acceptance of the following terms. If you do not agree to the following terms, do not retrieve the OpenVision Kerberos administration system.\par +\par +You may freely use and distribute the Source Code and Object Code compiled from it, with or without modification, but this Source Code is provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER EXPRESS OR IMPLIED. IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY FOR ANY LOST PROFITS, LOSS OF DATA OR COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, INCLUDING, WITHOUT LIMITATION, THOSE RESULTING FROM THE USE OF THE SOURCE CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR ANY OTHER REASON.\par +\par +OpenVision retains all copyrights in the donated Source Code. OpenVision also retains copyright to derivative works of the Source Code, whether created by OpenVision or by a third party. The OpenVision copyright notice must be preserved if derivative works are made based on the donated Source Code.\par +\par +OpenVision Technologies, Inc. has donated this Kerberos Administration system to MIT for inclusion in the standard Kerberos 5 distribution. This donation underscores our commitment to continuing Kerberos technology development and our gratitude for the valuable work which has been performed by MIT and the Kerberos community.\par +\par +----\par +\par +Portions contributed by Matt Crawford <crawdad@fnal.gov> were work performed at Fermi National Accelerator Laboratory, which is operated by Universities Research Association, Inc., under contract DE-AC02-76CHO3000 with the U.S. Department of Energy.\par +\par +\pard ----\f1\fs24\par +\pard\nowidctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\f0\fs20\par +The implementation of the Yarrow pseudo-random number generator in src/lib/crypto/yarrow has the following copyright:\par +\par +Copyright 2000 by Zero-Knowledge Systems, Inc.\par +\par +Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Zero-Knowledge Systems, Inc. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. Zero-Knowledge Systems, Inc. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.\par +\par +ZERO-KNOWLEDGE SYSTEMS, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ZERO-KNOWLEDGE SYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\par +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\par +\par +\pard ----\f1\fs24\par +\pard\nowidctlpar\tx916\tx1832\tx2748\tx3664\tx4580\tx5496\tx6412\tx7328\tx8244\tx9160\tx10076\tx10992\tx11908\tx12824\tx13740\tx14656\f0\fs20\par +The implementation of the AES encryption algorithm in src/lib/crypto/aes has the following copyright:\par +\par +Copyright (c) 2001, Dr Brian Gladman <brg@gladman.uk.net>, Worcester, UK.\par +All rights reserved.\par +\par +LICENSE TERMS\par +\par +The free distribution and use of this software in both source and binary form is allowed (with or without changes) provided that:\par +\par +1. distributions of this source code include the above copyright notice, this list of conditions and the following disclaimer;\par +\par +2. distributions in binary form include the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other associated materials;\par +\par +3. the copyright holder's name is not used to endorse products built using this software without specific written permission. \par +\par +DISCLAIMER\par +\par +This software is provided 'as is' with no explcit or implied warranties in respect of any properties, including, but not limited to, correctness and fitness for purpose.\par +\par +\par +\par +Acknowledgements\par +----------------\par +\par +Appreciation Time!!!! There are far too many people to try to thank them all; many people have contributed to the development of Kerberos V5. This is only a partial listing....\par +\par +Thanks to Paul Vixie and the Internet Software Consortium for funding the work of Barry Jaspan. This funding was invaluable for the OV administration server integration, as well as the 1.0 release preparation process.\par +\par +Thanks to John Linn, Scott Foote, and all of the folks at OpenVision Technologies, Inc., who donated their administration server for use in the MIT release of Kerberos.\par +\par +Thanks to Jeff Bigler, Mark Eichin, Marc Horowitz, Nancy Gilman, Ken Raeburn, and all of the folks at Cygnus Support, who provided innumerable bug fixes and portability enhancements to the Kerberos V5 tree. Thanks especially to Jeff Bigler, for the new user and system administrator's documentation.\par +\par +Thanks to Doug Engert from ANL for providing many bug fixes, as well as testing to ensure DCE interoperability.\par +\par +Thanks to Ken Hornstein at NRL for providing many bug fixes and suggestions, and for working on SAM preauthentication.\par +\par +Thanks to Matt Crawford at FNAL for bugfixes and enhancements.\par +\par +Thanks to Sean Mullan and Bill Sommerfeld from Hewlett Packard for their many suggestions and bug fixes.\par +\par +Thanks to Nalin Dahyabhai of RedHat and Chris Evans for locating and providing patches for numerous buffer overruns.\par +\par +Thanks to Christopher Thompson and Marcus Watts for discovering the ftpd security bug.\par +\par +Thanks to Paul Nelson of Thursby Software Systems for implementing the Microsoft set password protocol.\par +\par +Thanks to the members of the Kerberos V5 development team at MIT, both past and present: Danilo Almeida, Jeffrey Altman, Jay Berkenbilt, Richard Basch, Mitch Berger, John Carr, Don Davis, Alexandra Ellwood, Nancy Gilman, Matt Hancher, Sam Hartman, Paul Hill, Marc Horowitz, Eva Jacobus, Miroslav Jurisic, Barry Jaspan, Geoffrey King, John Kohl, Peter Litwack, Scott McGuire, Kevin Mitchell, Cliff Neuman, Paul Park, Ezra Peisach, Chris Provenzano, Ken Raeburn, Jon Rochlis, Jeff Schiller, Jen Selby, Brad Thompson, Harry Tsai, Ted Ts'o, Marshall Vale, Tom Yu.\par +\pard\nowidctlpar\f1\fs24\par +} +� \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/lang/strings_1033.wxl b/mechglue/src/windows/installer/wix/lang/strings_1033.wxl new file mode 100644 index 000000000..881334376 --- /dev/null +++ b/mechglue/src/windows/installer/wix/lang/strings_1033.wxl @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<WixLocalization> +<!-- + + Copyright (C) 2004 by the Massachusetts Institute of Technology. + All rights reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization contemplating + export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of M.I.T. not be used in advertising or publicity pertaining + to distribution of the software without specific, written prior + permission. Furthermore if you modify this software you must label + your software as modified software and not distribute it in such a + fashion that it might be confused with the original M.I.T. software. + M.I.T. makes no representations about the suitability of + this software for any purpose. It is provided "as is" without express + or implied warranty. + + --> + <String Id="ProductName">Kerberos for Windows</String> + <String Id="ProductNameShort">KFW</String> + <String Id="ProductMIT">MIT</String> + <String Id="ProductDebug">Debug/Checked</String> + <String Id="ProductBeta">Beta</String> + + <String Id="Manufacturer">Massachusetts Institute of Technology</String> + + <String Id="KerberosTitle">Kerberos for Windows</String> + <String Id="KerberosDesc">Kerberos for Windows</String> + + <String Id="KerberosClientTitle">Client</String> + <String Id="KerberosClientDesc">Kerberos client utilities, libraries and documentation</String> + + <String Id="StrKerberosClientDebugTitle">Debug symbols</String> + <String Id="StrKerberosClientDebugDesc">Debugging symbols for Kerberos for Windows components.</String> + + <String Id="StrLeashExeTitle">Leash Credentials Manager</String> + <String Id="StrLeashExeDesc">Leash credentials manager</String> + + <String Id="KerberosSDKTitle">SDK</String> + <String Id="KerberosSDKDesc">Libraries and header files for developing software with Kerberos</String> + + <String Id="KerberosDocTitle">Documentation</String> + <String Id="KerberosDocDesc">Documentation</String> + + <String Id="AdminRequired">You need administrative privileges to install Kerberos for Windows</String> + <String Id="OsVersionRequired">This product requires Windows 2000/XP/2003. The current operating system is not supported.</String> + <String Id="CMNotSelected">Neither Leash nor Network Identity Manager has been selected for this package. Please contact your administrator or the provider of this installation package to resolve this issue.</String> + <String Id="CMDupSelected">Both Leash and Network Identity Manager has been selected for this package. Only one of these can be selected at one time. Please contact your administrator or the provider of this installation package to resolve this issue.</String> + + <String Id="CantRemoveNSIS">The NSIS based installation of Kerberos for Windows could not be uninstalled because the NSIS uninstaller must be run in Full UI mode.</String> + <String Id="IE501Required">Kerberos for Windows requires Microsoft Internet Explorer version 5.01 or higher. Please resolve this and run the installer again.</String> + + <String Id="ARPComments">Build of</String> + +</WixLocalization> \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/lang/ui_1033.wxi b/mechglue/src/windows/installer/wix/lang/ui_1033.wxi new file mode 100644 index 000000000..e3cb3dc55 --- /dev/null +++ b/mechglue/src/windows/installer/wix/lang/ui_1033.wxi @@ -0,0 +1,1243 @@ +<?xml version="1.0" encoding="utf-8"?> +<Include xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> + <UI> + <Dialog Id="AdminWelcomeDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Property="InstallMode" Value="Server Image">1</Publish> + <Publish Event="NewDialog" Value="AdminRegistrationDlg">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Back]" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="30" Transparent="yes" NoPrefix="yes"> + <Text>The [Wizard] will create a server image of [ProductName], at a specified network location. Click Next to continue or Cancel to exit the [Wizard].</Text> + </Control> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\VerdanaBold13}Welcome to the [ProductName] [Wizard]</Text> + </Control> + </Dialog> + <Dialog Id="ExitDialog" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_Finish]"> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Cancel]" /> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Back]" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Click the Finish button to exit the [Wizard].</Text> + </Control> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\VerdanaBold13}Completing the [ProductName] [Wizard]</Text> + </Control> + </Dialog> + <Dialog Id="FatalError" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_Finish]"> + <Publish Event="EndDialog" Value="Exit">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Cancel]" /> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Back]" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\VerdanaBold13}[ProductName] [Wizard] ended prematurely</Text> + </Control> + <Control Id="Description1" Type="Text" X="135" Y="70" Width="220" Height="40" Transparent="yes" NoPrefix="yes"> + <Text>[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.</Text> + </Control> + <Control Id="Description2" Type="Text" X="135" Y="115" Width="220" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Click the Finish button to exit the [Wizard].</Text> + </Control> + </Dialog> + <Dialog Id="PrepareDlg" Width="370" Height="270" Title="[ProductName] [Setup]" Modeless="yes"> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Please wait while the [Wizard] prepares to guide you through the installation.</Text> + </Control> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\VerdanaBold13}Welcome to the [ProductName] [Wizard]</Text> + </Control> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" TabSkip="yes" Text="[ButtonText_Back]" /> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Disabled="yes" TabSkip="yes" Text="[ButtonText_Next]" /> + <Control Id="ActionData" Type="Text" X="135" Y="125" Width="220" Height="30" Transparent="yes" NoPrefix="yes"> + <Subscribe Event="ActionData" Attribute="Text" /> + </Control> + <Control Id="ActionText" Type="Text" X="135" Y="100" Width="220" Height="20" Transparent="yes" NoPrefix="yes"> + <Subscribe Event="ActionText" Attribute="Text" /> + </Control> + </Dialog> + <Dialog Id="ProgressDlg" Width="370" Height="270" Title="[ProductName] [Setup]" Modeless="yes"> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Back]" /> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Next]" /> + <Control Id="Text" Type="Text" X="35" Y="65" Width="300" Height="20"> + <Text>Please wait while the [Wizard] [Progress2] [ProductName]. This may take several minutes.</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Title" Type="Text" X="20" Y="15" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont][Progress1] [ProductName]</Text> + </Control> + <Control Id="ActionText" Type="Text" X="70" Y="100" Width="265" Height="10"> + <Subscribe Event="ActionText" Attribute="Text" /> + </Control> + <Control Id="ProgressBar" Type="ProgressBar" X="35" Y="115" Width="300" Height="10" ProgressBlocks="yes" Text="Progress done"> + <Subscribe Event="SetProgress" Attribute="Progress" /> + </Control> + <Control Id="StatusLabel" Type="Text" X="35" Y="100" Width="35" Height="10" Text="Status:" /> + </Dialog> + <Dialog Id="UserExit" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_Finish]"> + <Publish Event="EndDialog" Value="Exit">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Cancel]" /> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Back]" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\VerdanaBold13}[ProductName] [Wizard] was interrupted</Text> + </Control> + <Control Id="Description1" Type="Text" X="135" Y="70" Width="220" Height="40" Transparent="yes" NoPrefix="yes"> + <Text>[ProductName] setup was interrupted. Your system has not been modified. To install this program at a later time, please run the installation again.</Text> + </Control> + <Control Id="Description2" Type="Text" X="135" Y="115" Width="220" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Click the Finish button to exit the [Wizard].</Text> + </Control> + </Dialog> + <Dialog Id="AdminBrowseDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="PathEdit" Type="PathEdit" X="84" Y="202" Width="261" Height="17" Property="TARGETDIR" /> + <Control Id="OK" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_OK]"> + <Publish Event="SetTargetPath" Value="TARGETDIR">1</Publish> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="240" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="Reset" Value="0">1</Publish> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="ComboLabel" Type="Text" X="25" Y="58" Width="44" Height="10" TabSkip="no" Text="&Look in:" /> + <Control Id="DirectoryCombo" Type="DirectoryCombo" X="70" Y="55" Width="220" Height="80" Property="TARGETDIR" Removable="yes" Fixed="yes" Remote="yes"> + <Subscribe Event="IgnoreChange" Attribute="IgnoreChange" /> + </Control> + <Control Id="Up" Type="PushButton" X="298" Y="55" Width="19" Height="19" ToolTip="Up One Level" Icon="yes" FixedSize="yes" IconSize="16" Text="Up"> + <Publish Event="DirectoryListUp" Value="0">1</Publish> + </Control> + <Control Id="NewFolder" Type="PushButton" X="325" Y="55" Width="19" Height="19" ToolTip="Create A New Folder" Icon="yes" FixedSize="yes" IconSize="16" Text="New"> + <Publish Event="DirectoryListNew" Value="0">1</Publish> + </Control> + <Control Id="DirectoryList" Type="DirectoryList" X="25" Y="83" Width="320" Height="110" Property="TARGETDIR" Sunken="yes" TabSkip="no" /> + <Control Id="PathLabel" Type="Text" X="25" Y="205" Width="59" Height="10" TabSkip="no" Text="&Folder name:" /> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Browse to the destination folder</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Change current destination folder</Text> + </Control> + </Dialog> + <Dialog Id="AdminInstallPointDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Text" Type="Text" X="25" Y="80" Width="320" Height="10" TabSkip="no"> + <Text>&Enter a new network location or click Browse to browse to one.</Text> + </Control> + <Control Id="PathEdit" Type="PathEdit" X="25" Y="93" Width="320" Height="18" Property="TARGETDIR" /> + <Control Id="Browse" Type="PushButton" X="289" Y="119" Width="56" Height="17" Text="[ButtonText_Browse]"> + <Publish Event="SpawnDialog" Value="AdminBrowseDlg">1</Publish> + </Control> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="AdminRegistrationDlg">1</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="SetTargetPath" Value="TARGETDIR">1</Publish> + <Publish Event="NewDialog" Value="VerifyReadyDlg">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="20" Width="280" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Please specify a network location for the server image of [ProductName] product</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Network Location</Text> + </Control> + </Dialog> + <Dialog Id="AdminRegistrationDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="OrganizationLabel" Type="Text" X="45" Y="71" Width="285" Height="30" TabSkip="no"> + <Text>&Please enter the name of your organization in the box below. This will be used as default company name for subsequent installations of [ProductName]:</Text> + </Control> + <Control Id="OrganizationEdit" Type="Edit" X="45" Y="105" Width="220" Height="18" Property="COMPANYNAME" Text="{80}" /> + <Control Id="CDKeyLabel" Type="Text" X="45" Y="130" Width="50" Height="10" TabSkip="no"> + <Text>CD &Key:</Text> + </Control> + <Control Id="CDKeyEdit" Type="MaskedEdit" X="45" Y="143" Width="250" Height="16" Property="PIDKEY" Text="[PIDTemplate]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Image="yes" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="AdminWelcomeDlg">1</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="ValidateProductID" Value="0">0</Publish> + <Publish Event="NewDialog" Value="AdminInstallPointDlg">ProductID</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Please enter your company information</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Company Information</Text> + </Control> + </Dialog> + <Dialog Id="BrowseDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="PathEdit" Type="PathEdit" X="84" Y="202" Width="261" Height="18" Property="_BrowseProperty" Indirect="yes" /> + <Control Id="OK" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_OK]"> + <Publish Event="SetTargetPath" Value="[_BrowseProperty]">1</Publish> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="240" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="Reset" Value="0">1</Publish> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="ComboLabel" Type="Text" X="25" Y="58" Width="44" Height="10" TabSkip="no" Text="&Look in:" /> + <Control Id="DirectoryCombo" Type="DirectoryCombo" X="70" Y="55" Width="220" Height="80" Property="_BrowseProperty" Indirect="yes" Fixed="yes" Remote="yes"> + <Subscribe Event="IgnoreChange" Attribute="IgnoreChange" /> + </Control> + <Control Id="Up" Type="PushButton" X="298" Y="55" Width="19" Height="19" ToolTip="Up One Level" Icon="yes" FixedSize="yes" IconSize="16" Text="Up"> + <Publish Event="DirectoryListUp" Value="0">1</Publish> + </Control> + <Control Id="NewFolder" Type="PushButton" X="325" Y="55" Width="19" Height="19" ToolTip="Create A New Folder" Icon="yes" FixedSize="yes" IconSize="16" Text="New"> + <Publish Event="DirectoryListNew" Value="0">1</Publish> + </Control> + <Control Id="DirectoryList" Type="DirectoryList" X="25" Y="83" Width="320" Height="110" Property="_BrowseProperty" Sunken="yes" Indirect="yes" TabSkip="no" /> + <Control Id="PathLabel" Type="Text" X="25" Y="205" Width="59" Height="10" TabSkip="no" Text="&Folder name:" /> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Browse to the destination folder</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Change current destination folder</Text> + </Control> + </Dialog> + <Dialog Id="CancelDlg" Y="10" Width="260" Height="85" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="No" Type="PushButton" X="132" Y="57" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_No]"> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="Yes" Type="PushButton" X="72" Y="57" Width="56" Height="17" Text="[ButtonText_Yes]"> + <Publish Event="EndDialog" Value="Exit">1</Publish> + </Control> + <Control Id="Text" Type="Text" X="48" Y="15" Width="194" Height="30"> + <Text>Are you sure you want to cancel [ProductName] installation?</Text> + </Control> + <Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24" ToolTip="Information icon" FixedSize="yes" IconSize="32" Text="[InfoIcon]" /> + </Dialog> + <Dialog Id="CustomizeDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes" TrackDiskSpace="yes"> + <Control Id="Tree" Type="SelectionTree" X="25" Y="85" Width="175" Height="95" Property="_BrowseProperty" Sunken="yes" TabSkip="no" Text="Tree of selections" /> + <Control Id="Browse" Type="PushButton" X="304" Y="200" Width="56" Height="17" Text="[ButtonText_Browse]"> + <Publish Event="SelectionBrowse" Value="BrowseDlg">1</Publish> + <Condition Action="hide">Installed</Condition> + </Control> + <Control Id="Reset" Type="PushButton" X="42" Y="243" Width="56" Height="17" Text="[ButtonText_Reset]"> + <Publish Event="Reset" Value="0">1</Publish> + <Subscribe Event="SelectionNoItems" Attribute="Enabled" /> + </Control> + <Control Id="DiskCost" Type="PushButton" X="111" Y="243" Width="56" Height="17"> + <Text>Disk &Usage</Text> + <Publish Event="SpawnDialog" Value="DiskCostDlg">1</Publish> + <Subscribe Event="SelectionNoItems" Attribute="Enabled" /> + </Control> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="MaintenanceTypeDlg">InstallMode = "Change"</Publish> + <Publish Event="NewDialog" Value="SetupTypeDlg">InstallMode = "Custom"</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="NewDialog" Value="VerifyReadyDlg">( &feaKfwClient <> 3 And !feaKfwClient <> 3 ) And Not FoundProcesses</Publish> + <Publish Event="NewDialog" Value="RunningProcessDlg">( &feaKfwClient <> 3 And !feaKfwClient <> 3 ) And FoundProcesses</Publish> + <Publish Event="NewDialog" Value="KerberosOptions">&feaKfwClient = 3 Or !feaKfwClient = 3</Publish> + <Subscribe Event="SelectionNoItems" Attribute="Enabled" /> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Text" Type="Text" X="25" Y="55" Width="320" Height="20"> + <Text>Click on the icons in the tree below to change the way features will be installed.</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Select the way you want features to be installed.</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Custom Setup</Text> + </Control> + <Control Id="Box" Type="GroupBox" X="210" Y="81" Width="140" Height="98" /> + <Control Id="ItemDescription" Type="Text" X="215" Y="90" Width="131" Height="30"> + <Text>Multiline description of the currently selected item.</Text> + <Subscribe Event="SelectionDescription" Attribute="Text" /> + </Control> + <Control Id="ItemSize" Type="Text" X="215" Y="130" Width="131" Height="45"> + <Text>The size of the currently selected item.</Text> + <Subscribe Event="SelectionSize" Attribute="Text" /> + </Control> + <Control Id="Location" Type="Text" X="75" Y="200" Width="215" Height="20"> + <Text><The selection's path></Text> + <Subscribe Event="SelectionPath" Attribute="Text" /> + <Subscribe Event="SelectionPathOn" Attribute="Visible" /> + <Condition Action="hide">Installed</Condition> + </Control> + <Control Id="LocationLabel" Type="Text" X="25" Y="200" Width="50" Height="10" Text="Location:"> + <Subscribe Event="SelectionPathOn" Attribute="Visible" /> + <Condition Action="hide">Installed</Condition> + </Control> + </Dialog> + <Dialog Id="DiskCostDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="OK" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_OK]"> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Text" Type="Text" X="20" Y="53" Width="330" Height="40"> + <Text>The highlighted volumes (if any) do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="20" Y="20" Width="280" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>The disk space required for the installation of the selected features.</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Disk Space Requirements</Text> + </Control> + <Control Id="VolumeList" Type="VolumeCostList" X="20" Y="100" Width="330" Height="120" Sunken="yes" Fixed="yes" Remote="yes"> + <Text>{120}{70}{70}{70}{70}</Text> + </Control> + </Dialog> + <Dialog Id="ErrorDlg" Y="10" Width="270" Height="105" Title="Installer Information" ErrorDialog="yes" NoMinimize="yes"> + <Control Id="ErrorText" Type="Text" X="48" Y="15" Width="205" Height="60" TabSkip="no" Text="Information text" /> + <Control Id="Y" Type="PushButton" X="100" Y="80" Width="56" Height="17" TabSkip="yes" Text="[ButtonText_Yes]"> + <Publish Event="EndDialog" Value="ErrorYes">1</Publish> + </Control> + <Control Id="A" Type="PushButton" X="100" Y="80" Width="56" Height="17" TabSkip="yes" Text="[ButtonText_Cancel]"> + <Publish Event="EndDialog" Value="ErrorAbort">1</Publish> + </Control> + <Control Id="C" Type="PushButton" X="100" Y="80" Width="56" Height="17" TabSkip="yes" Text="[ButtonText_Cancel]"> + <Publish Event="EndDialog" Value="ErrorCancel">1</Publish> + </Control> + <Control Id="ErrorIcon" Type="Icon" X="15" Y="15" Width="24" Height="24" ToolTip="Information icon" FixedSize="yes" IconSize="32" Text="[InfoIcon]" /> + <Control Id="I" Type="PushButton" X="100" Y="80" Width="56" Height="17" TabSkip="yes" Text="[ButtonText_Ignore]"> + <Publish Event="EndDialog" Value="ErrorIgnore">1</Publish> + </Control> + <Control Id="N" Type="PushButton" X="100" Y="80" Width="56" Height="17" TabSkip="yes" Text="[ButtonText_No]"> + <Publish Event="EndDialog" Value="ErrorNo">1</Publish> + </Control> + <Control Id="O" Type="PushButton" X="100" Y="80" Width="56" Height="17" TabSkip="yes" Text="[ButtonText_OK]"> + <Publish Event="EndDialog" Value="ErrorOk">1</Publish> + </Control> + <Control Id="R" Type="PushButton" X="100" Y="80" Width="56" Height="17" TabSkip="yes" Text="[ButtonText_Retry]"> + <Publish Event="EndDialog" Value="ErrorRetry">1</Publish> + </Control> + </Dialog> + <Dialog Id="FilesInUse" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes" KeepModeless="yes"> + <Control Id="Retry" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_Retry]"> + <Publish Event="EndDialog" Value="Retry">1</Publish> + </Control> + <Control Id="Ignore" Type="PushButton" X="235" Y="243" Width="56" Height="17" Text="[ButtonText_Ignore]"> + <Publish Event="EndDialog" Value="Ignore">1</Publish> + </Control> + <Control Id="Exit" Type="PushButton" X="166" Y="243" Width="56" Height="17" Text="[ButtonText_Exit]"> + <Publish Event="EndDialog" Value="Exit">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Text" Type="Text" X="20" Y="55" Width="330" Height="30"> + <Text>The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="20" Y="23" Width="280" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Some files that need to be updated are currently in use.</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Files in Use</Text> + </Control> + <Control Id="List" Type="ListBox" X="20" Y="87" Width="330" Height="130" Property="FileInUseProcess" Sunken="yes" TabSkip="yes" /> + </Dialog> + + <Dialog Id="RunningProcessDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes" KeepModeless="yes"> + + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="CustomizeDlg">(InstallMode = "Custom" OR InstallMode = "Change") AND &feaKfwClient <> 3 And !feaKfwClient <> 3</Publish> + <Publish Event="NewDialog" Value="KerberosOptions">(InstallMode = "Custom" OR InstallMode = "Change") AND ( &feaKfwClient = 3 Or !feaKfwClient = 3 )</Publish> + <Publish Event="NewDialog" Value="MaintenanceTypeDlg">InstallMode = "Repair"</Publish> + <Publish Event="NewDialog" Value="SetupTypeDlg">InstallMode = "Typical" OR InstallMode = "Complete"</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="NewDialog" Value="VerifyReadyDlg">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Text" Type="Text" X="20" Y="55" Width="330" Height="30"> + <Text>The following applications are currently running and need to be closed in order for the installation to progress. Please close them manually or click Next to let [Wizard] close them for you.</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="20" Y="23" Width="280" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Some running processes need to be closed.</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Close Running Proccesses</Text> + </Control> + <Control Id="List" Type="ListBox" X="20" Y="87" Width="330" Height="130" Property="KillableProcesses" Sunken="yes" TabSkip="yes" /> + </Dialog> + + + <Dialog Id="CCPErrorDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes" KeepModeless="yes"> + + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]" Disabled="yes"> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Text="[ButtonText_Finish]"> + <Publish Event="EndDialog" Value="Exit">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Disabled="yes" Text="[ButtonText_Cancel]"> + </Control> + + <Control Id="ErrorText" Type="Text" X="20" Y="70" Width="280" Height="75"> + <Text>[ProductName] requires a newer version of iphlpapi.dll than the one that is currently installed on this computer. This file is included in Microsoft Internet Explorer version 5.01 or later. Please install this and re-run the [ProductName] installer.</Text> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="20" Y="23" Width="280" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>[ProgramName] requires a newer version of iphlpapi.dll</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Compliance Check Failed!</Text> + </Control> + </Dialog> + + <Dialog Id="LicenseAgreementDlg" Width="370" Height="270" Title="[ProductName] License Agreement" NoMinimize="yes"> + <Control Id="Buttons" Type="RadioButtonGroup" X="20" Y="187" Width="330" Height="40" Property="IAgree" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="WelcomeDlg">1</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="NewDialog" Value="UserRegistrationDlg">IAgree = "Yes" AND ShowUserRegistrationDlg = 1</Publish> + <Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">CostingComplete = 1</Publish> + <Publish Event="NewDialog" Value="RemovePreviousDlg">IAgree = "Yes" AND ShowUserRegistrationDlg <> 1 AND (UPGRADEPISMERE OR UPGRADEKFW OR UPGRADENSIS <> "")</Publish> + <Publish Event="NewDialog" Value="SetupTypeDlg">IAgree = "Yes" AND ShowUserRegistrationDlg <> 1 AND NOT (UPGRADEPISMERE OR UPGRADEKFW OR UPGRADENSIS <> "")</Publish> + <Condition Action="disable">IAgree <> "Yes"</Condition> + <Condition Action="enable">IAgree = "Yes"</Condition> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="AgreementText" Type="ScrollableText" X="20" Y="60" Width="330" Height="120" Sunken="yes" TabSkip="no"> + <Text src=".\lang\license.rtf"/> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Please read the following license agreement carefully</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]End-User License Agreement</Text> + </Control> + </Dialog> + <Dialog Id="MaintenanceTypeDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="ChangeLabel" Type="Text" X="105" Y="65" Width="100" Height="10" TabSkip="no"> + <Text>[DlgTitleFont]&Modify</Text> + </Control> + <Control Id="ChangeButton" Type="PushButton" X="50" Y="65" Width="38" Height="38" ToolTip="Modify Installation" Default="yes" Icon="yes" FixedSize="yes" IconSize="32" Text="[CustomSetupIcon]"> + <Publish Property="InstallMode" Value="Change">1</Publish> + <Publish Property="Progress1" Value="Changing">1</Publish> + <Publish Property="Progress2" Value="changes">1</Publish> + <Publish Event="NewDialog" Value="CustomizeDlg">1</Publish> + </Control> + <Control Id="RepairLabel" Type="Text" X="105" Y="114" Width="100" Height="10" TabSkip="no"> + <Text>[DlgTitleFont]Re&pair</Text> + </Control> + <Control Id="RepairButton" Type="PushButton" X="50" Y="114" Width="38" Height="38" ToolTip="Repair Installation" Icon="yes" FixedSize="yes" IconSize="32" Text="[RepairIcon]"> + <Publish Property="InstallMode" Value="Repair">1</Publish> + <Publish Property="Progress1" Value="Repairing">1</Publish> + <Publish Property="Progress2" Value="repaires">1</Publish> + <Publish Event="NewDialog" Value="VerifyRepairDlg">1</Publish> + </Control> + <Control Id="RemoveLabel" Type="Text" X="105" Y="163" Width="100" Height="10" TabSkip="no"> + <Text>[DlgTitleFont]&Remove</Text> + </Control> + <Control Id="RemoveButton" Type="PushButton" X="50" Y="163" Width="38" Height="38" ToolTip="Remove Installation" Icon="yes" FixedSize="yes" IconSize="32" Text="[RemoveIcon]"> + <Publish Property="InstallMode" Value="Remove">1</Publish> + <Publish Property="Progress1" Value="Removing">1</Publish> + <Publish Property="Progress2" Value="removes">1</Publish> + <Publish Event="NewDialog" Value="VerifyRemoveDlg">1</Publish> + </Control> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Next]" /> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Select the operation you wish to perform.</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="240" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Modify, Repair or Remove installation</Text> + </Control> + <Control Id="ChangeText" Type="Text" X="105" Y="78" Width="230" Height="20"> + <Text>Allows users to change the way features are installed.</Text> + </Control> + <Control Id="RemoveText" Type="Text" X="105" Y="176" Width="230" Height="20"> + <Text>Removes [ProductName] from your computer.</Text> + </Control> + <Control Id="RepairText" Type="Text" X="105" Y="127" Width="230" Height="30"> + <Text>Repairs errors in the most recent installation state - fixes missing or corrupt files, shortcuts and registry entries.</Text> + </Control> + </Dialog> + <Dialog Id="MaintenanceWelcomeDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">CostingComplete = 1</Publish> + <Publish Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Back]" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>The [Wizard] will allow you to change the way [ProductName] features are installed on your computer or even to remove [ProductName] from your computer. Click Next to continue or Cancel to exit the [Wizard].</Text> + </Control> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\VerdanaBold13}Welcome to the [ProductName] [Wizard]</Text> + </Control> + </Dialog> + <Dialog Id="OutOfDiskDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="OK" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_OK]"> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Text" Type="Text" X="20" Y="53" Width="330" Height="40"> + <Text>The highlighted volumes do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="20" Y="20" Width="280" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Disk space required for the installation exceeds available disk space.</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Out of Disk Space</Text> + </Control> + <Control Id="VolumeList" Type="VolumeCostList" X="20" Y="100" Width="330" Height="120" Sunken="yes" Fixed="yes" Remote="yes"> + <Text>{120}{70}{70}{70}{70}</Text> + </Control> + </Dialog> + <Dialog Id="OutOfRbDiskDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="No" Type="PushButton" X="304" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_No]"> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="Yes" Type="PushButton" X="240" Y="243" Width="56" Height="17" Text="[ButtonText_Yes]"> + <Publish Event="EnableRollback" Value="False">1</Publish> + <Publish Event="EndDialog" Value="Return">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Text" Type="Text" X="20" Y="53" Width="330" Height="40"> + <Text>The highlighted volumes do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="20" Y="20" Width="280" Height="20" Transparent="yes" NoPrefix="yes"> + <Text>Disk space required for the installation exceeds available disk space.</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Out of Disk Space</Text> + </Control> + <Control Id="VolumeList" Type="VolumeCostList" X="20" Y="140" Width="330" Height="80" Sunken="yes" Fixed="yes" Remote="yes" ShowRollbackCost="yes"> + <Text>{120}{70}{70}{70}{70}</Text> + </Control> + <Control Id="Text2" Type="Text" X="20" Y="94" Width="330" Height="40"> + <Text>Alternatively, you may choose to disable the installer's rollback functionality. This allows the installer to restore your computer's original state should the installation be interrupted in any way. Click Yes if you wish to take the risk to disable rollback.</Text> + </Control> + </Dialog> + <Dialog Id="RemovePreviousDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Confirm" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Confirm"> + <Publish Event="NewDialog" Value="SetupTypeDlg">1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" FixedSize="yes" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="LicenseAgreementDlg">ShowUserRegistrationDlg <> 1</Publish> + <Publish Event="NewDialog" Value="UserRegistrationDlg">ShowUserRegistrationDlg = 1</Publish> + </Control> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Other versions of [ProductName] need to be removed.</Text> + </Control> + <Control Id="Text" Type="Text" X="25" Y="70" Width="320" Height="45"> + <Text>Click Confirm to uninstall the following version of Kerberos for Windows installed on this computer. Installation of [ProductName] cannot continue unless this program is removed.</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Uninstall previous versions</Text> + </Control> + <Control Id="RemoveIcon" Type="Icon" X="25" Y="130" Width="32" Height="32" IconSize="32" Text="[RemoveIcon]" /> + <Control Id="RemoveProductPismere" Type="Text" X="60" Y="146" Width="200" Height="15" Hidden="yes" Transparent="yes" NoPrefix="yes"> + <Text>MIT Project Pismere Kerberos for Windows : Product code [UPGRADEPISMERE]</Text> + <Condition Action="show">UPGRADEPISMERE</Condition> + </Control> + <Control Id="RemoveProductKfw" Type="Text" X="60" Y="146" Width="200" Height="15" Hidden="yes" Transparent="yes" NoPrefix="yes"> + <Text>MIT Kerberos for Windows : Product code [UPGRADEKFW]</Text> + <Condition Action="show">UPGRADEKFW</Condition> + </Control> + <Control Id="RemoveProductKfwNSIS" Type="Text" X="60" Y="146" Width="200" Height="15" Hidden="yes" Transparent="yes" NoPrefix="yes"> + <Text>MIT Kerberos for Windows (NSIS installer): [NSISVERSION]</Text> + <Condition Action="show">UPGRADENSIS <> ""</Condition> + </Control> + </Dialog> + <Dialog Id="ResumeDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Install" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Install]"> + <Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">CostingComplete = 1</Publish> + <Publish Event="EndDialog" Value="Return">OutOfDiskSpace <> 1</Publish> + <Publish Event="SpawnDialog" Value="OutOfRbDiskDlg">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)</Publish> + <Publish Event="EndDialog" Value="Return">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish> + <Publish Event="EnableRollback" Value="False">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish> + <Publish Event="SpawnDialog" Value="OutOfDiskDlg">(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Back]" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="30" Transparent="yes" NoPrefix="yes"> + <Text>The [Wizard] will complete the installation of [ProductName] on your computer. Click Install to continue or Cancel to exit the [Wizard].</Text> + </Control> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\VerdanaBold13}Resuming the [ProductName] [Wizard]</Text> + </Control> + </Dialog> + <Dialog Id="SetupTypeDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="TypicalLabel" Type="Text" X="105" Y="65" Width="100" Height="10" TabSkip="no"> + <Text>[DlgTitleFont]&Typical</Text> + </Control> + <Control Id="TypicalButton" Type="PushButton" X="50" Y="65" Width="38" Height="38" ToolTip="Typical Installation" Default="yes" Icon="yes" FixedSize="yes" IconSize="32" Text="[InstallerIcon]"> + <Publish Property="InstallMode" Value="Typical">1</Publish> + <Publish Event="SetInstallLevel" Value="50">1</Publish> + <Publish Event="NewDialog" Value="VerifyReadyDlg">Not FoundProcesses</Publish> + <Publish Event="NewDialog" Value="RunningProcessDlg">FoundProcesses</Publish> + </Control> + <Control Id="CustomLabel" Type="Text" X="105" Y="118" Width="100" Height="10" TabSkip="no"> + <Text>[DlgTitleFont]C&ustom</Text> + </Control> + <Control Id="CustomButton" Type="PushButton" X="50" Y="118" Width="38" Height="38" ToolTip="Custom Installation" Icon="yes" FixedSize="yes" IconSize="32" Text="[CustomSetupIcon]"> + <Publish Property="InstallMode" Value="Custom">1</Publish> + <Publish Event="NewDialog" Value="CustomizeDlg">1</Publish> + </Control> + <Control Id="CompleteLabel" Type="Text" X="105" Y="171" Width="100" Height="10" TabSkip="no"> + <Text>[DlgTitleFont]C&omplete</Text> + </Control> + <Control Id="CompleteButton" Type="PushButton" X="50" Y="171" Width="38" Height="38" ToolTip="Complete Installation" Icon="yes" FixedSize="yes" IconSize="32" Text="[CompleteSetupIcon]"> + <Publish Property="InstallMode" Value="Complete">1</Publish> + <Publish Event="SetInstallLevel" Value="1000">1</Publish> + <Publish Event="NewDialog" Value="VerifyReadyDlg">Not FoundProcesses</Publish> + <Publish Event="NewDialog" Value="RunningProcessDlg">FoundProcesses</Publish> + </Control> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="LicenseAgreementDlg">ShowUserRegistrationDlg <> 1 AND NOT (UPGRADEPISMERE OR UPGRADEKFW)</Publish> + <Publish Event="NewDialog" Value="UserRegistrationDlg">ShowUserRegistrationDlg = 1 AND NOT (UPGRADEPISMERE OR UPGRADEKFW)</Publish> + <Publish Event="NewDialog" Value="RemovePreviousDlg">UPGRADEPISMERE OR UPGRADEKFW OR UPGRADENSIS <> ""</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Next]" /> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Choose the setup type that best suits your needs</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Choose Setup Type</Text> + </Control> + <Control Id="CompleteText" Type="Text" X="105" Y="184" Width="230" Height="20"> + <Text>All program features will be installed. (Requires most disk space)</Text> + </Control> + <Control Id="CustomText" Type="Text" X="105" Y="131" Width="230" Height="30"> + <Text>Allows users to choose which program features will be installed and where they will be installed. Recommended for advanced users.</Text> + </Control> + <Control Id="TypicalText" Type="Text" X="105" Y="78" Width="230" Height="20"> + <Text>Installs the most common program features. Recommended for most users.</Text> + </Control> + </Dialog> + <Dialog Id="UserRegistrationDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="NameLabel" Type="Text" X="45" Y="73" Width="100" Height="15" TabSkip="no" Text="&User Name:" /> + <Control Id="NameEdit" Type="Edit" X="45" Y="85" Width="220" Height="18" Property="USERNAME" Text="{80}" /> + <Control Id="OrganizationLabel" Type="Text" X="45" Y="110" Width="100" Height="15" TabSkip="no" Text="&Organization:" /> + <Control Id="OrganizationEdit" Type="Edit" X="45" Y="122" Width="220" Height="18" Property="COMPANYNAME" Text="{80}" /> + <Control Id="CDKeyLabel" Type="Text" X="45" Y="147" Width="50" Height="10" TabSkip="no"> + <Text>CD &Key:</Text> + </Control> + <Control Id="CDKeyEdit" Type="MaskedEdit" X="45" Y="159" Width="250" Height="16" Property="PIDKEY" Text="[PIDTemplate]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="LicenseAgreementDlg">1</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="ValidateProductID" Value="0">0</Publish> + <Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">CostingComplete = 1</Publish> + <Publish Event="NewDialog" Value="SetupTypeDlg">ProductID</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Please enter your customer information</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Customer Information</Text> + </Control> + </Dialog> + + <Dialog Id="KerberosOptions" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + + <Control Id="txtLeash" Type="Text" X="25" Y="55" Width="280" Height="30"> + <Text>The Network Identity Manager may be installed with the following optional functionality. Please check those items that you wish to activate.</Text> + </Control> + + <Control Id="koAutoStartText" Type="CheckBox" X="25" Y="95" Width="280" Height="30" CheckBoxValue="1" Property="LEASHAUTOSTART" > + <Text>Autostart the Network Identity Manager each time you login to Windows</Text> + </Control> + + <Control Id="koAutoInitText" Type="CheckBox" X="25" Y="130" Width="280" Height="30" CheckBoxValue="-autoinit" Property="LEASHAUTOINIT" > + <Text>Ensure that the Kerberos tickets are available throughout the Windows login session</Text> + </Control> + + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="CustomizeDlg">1</Publish> + </Control> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="NewDialog" Value="VerifyReadyDlg">Not FoundProcesses</Publish> + <Publish Event="NewDialog" Value="RunningProcessDlg">FoundProcesses</Publish> + <Publish Event="AddLocal" Value="feaKfwLeashStartup">LEASHAUTOSTART = 1</Publish> + <Publish Event="Remove" Value="feaKfwLeashStartup">LEASHAUTOSTART <> 1</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>Network Identity Manager startup options</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Kerberos Options</Text> + </Control> + </Dialog> + + <Dialog Id="VerifyReadyDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes" TrackDiskSpace="yes"> + <Control Id="Install" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Install]"> + <Publish Event="EndDialog" Value="Return">OutOfDiskSpace <> 1</Publish> + <Publish Event="SpawnDialog" Value="OutOfRbDiskDlg">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)</Publish> + <Publish Event="EndDialog" Value="Return">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish> + <Publish Event="EnableRollback" Value="False">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish> + <Publish Event="SpawnDialog" Value="OutOfDiskDlg">(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="AdminInstallPointDlg">InstallMode = "Server Image"</Publish> + <Publish Event="NewDialog" Value="CustomizeDlg">(InstallMode = "Custom" OR InstallMode = "Change") AND &feaKfwClient <> 3 And !feaKfwClient <> 3</Publish> + <Publish Event="NewDialog" Value="KerberosOptions">(InstallMode = "Custom" OR InstallMode = "Change") AND ( &feaKfwClient = 3 Or !feaKfwClient = 3 )</Publish> + <Publish Event="NewDialog" Value="MaintenanceTypeDlg">InstallMode = "Repair"</Publish> + <Publish Event="NewDialog" Value="SetupTypeDlg">InstallMode = "Typical" OR InstallMode = "Complete"</Publish> + </Control> + <Control Id="Text" Type="Text" X="25" Y="70" Width="320" Height="20"> + <Text>Click Install to begin the installation. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>The [Wizard] is ready to begin the [InstallMode] installation</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Ready to Install</Text> + </Control> + </Dialog> + <Dialog Id="VerifyRemoveDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes" TrackDiskSpace="yes"> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish> + </Control> + <Control Id="Remove" Type="PushButton" X="236" Y="243" Width="56" Height="17" Text="[ButtonText_Remove]"> + <Publish Event="Remove" Value="All">OutOfDiskSpace <> 1</Publish> + <Publish Event="EndDialog" Value="Return">OutOfDiskSpace <> 1</Publish> + <Publish Event="SpawnDialog" Value="OutOfRbDiskDlg">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)</Publish> + <Publish Event="EndDialog" Value="Return">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish> + <Publish Event="EnableRollback" Value="False">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish> + <Publish Event="SpawnDialog" Value="OutOfDiskDlg">(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Text" Type="Text" X="25" Y="70" Width="320" Height="30"> + <Text>Click Remove to remove [ProductName] from your computer. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>You have chosen to remove the program from your computer.</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Remove Kerberos for Windows</Text> + </Control> + </Dialog> + <Dialog Id="VerifyRepairDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes" TrackDiskSpace="yes"> + <Control Id="Repair" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Repair]"> + <Publish Event="ReinstallMode" Value="ecmus">OutOfDiskSpace <> 1</Publish> + <Publish Event="Reinstall" Value="All">OutOfDiskSpace <> 1</Publish> + <Publish Event="EndDialog" Value="Return">OutOfDiskSpace <> 1</Publish> + <Publish Event="SpawnDialog" Value="OutOfRbDiskDlg">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)</Publish> + <Publish Event="EndDialog" Value="Return">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish> + <Publish Event="EnableRollback" Value="False">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish> + <Publish Event="SpawnDialog" Value="OutOfDiskDlg">(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="374" Height="44" TabSkip="no" Text="[BannerBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="[ButtonText_Back]"> + <Publish Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish> + </Control> + <Control Id="Text" Type="Text" X="25" Y="70" Width="320" Height="30"> + <Text>Click Repair to repair the installation of [ProductName]. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.</Text> + </Control> + <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="374" Height="0" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>The [Wizard] is ready to begin the repair of [ProductName].</Text> + </Control> + <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes"> + <Text>[DlgTitleFont]Repair Kerberos for Windows</Text> + </Control> + </Dialog> + <Dialog Id="WaitForCostingDlg" Y="10" Width="260" Height="85" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Return" Type="PushButton" X="102" Y="57" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_Return]"> + <Publish Event="EndDialog" Value="Exit">1</Publish> + </Control> + <Control Id="Text" Type="Text" X="48" Y="15" Width="194" Height="30"> + <Text>Please wait while the installer finishes determining your disk space requirements.</Text> + </Control> + <Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24" ToolTip="Exclamation icon" FixedSize="yes" IconSize="32" Text="[ExclamationIcon]" /> + </Dialog> + <Dialog Id="WelcomeDlg" Width="370" Height="270" Title="[ProductName] [Setup]" NoMinimize="yes"> + <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="[ButtonText_Next]"> + <Publish Event="NewDialog" Value="LicenseAgreementDlg">(Installed) Or (CCP_Success = 1)</Publish> + <Publish Event="NewDialog" Value="CCPErrorDlg">(Not Installed) And (CCP_Success <> 1)</Publish> + </Control> + <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="[ButtonText_Cancel]"> + <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish> + </Control> + <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="[DialogBitmap]" /> + <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="[ButtonText_Back]" /> + <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="374" Height="0" /> + <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="30" Transparent="yes" NoPrefix="yes"> + <Text>The [Wizard] will install [ProductName] on your computer. Click Next to continue or Cancel to exit the [Wizard].</Text> + </Control> + <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes"> + <Text>{\VerdanaBold13}Welcome to the [ProductName] [Wizard]</Text> + </Control> + </Dialog> + <RadioGroup Property="IAgree"> + <RadioButton Text="{\DlgFont8}I &accept the terms in the License Agreement" X="5" Y="0" Width="250" Height="15" Value="Yes"></RadioButton> + <RadioButton Text="{\DlgFont8}I &do not accept the terms in the License Agreement" X="5" Y="20" Width="250" Height="15" Value="No"></RadioButton> + </RadioGroup> + <TextStyle Id="DlgFont8" FaceName="Tahoma" Size="8" /> + <TextStyle Id="DlgFontBold8" FaceName="Tahoma" Size="8" Bold="yes" /> + <TextStyle Id="VerdanaBold13" FaceName="Verdana" Size="13" Bold="yes" /> + <UIText Id="AbsentPath" /> + <UIText Id="bytes">bytes</UIText> + <UIText Id="GB">GB</UIText> + <UIText Id="KB">KB</UIText> + <UIText Id="MB">MB</UIText> + <UIText Id="MenuAbsent">Entire feature will be unavailable</UIText> + <UIText Id="MenuAdvertise">Feature will be installed when required</UIText> + <UIText Id="MenuAllCD">Entire feature will be installed to run from CD</UIText> + <UIText Id="MenuAllLocal">Entire feature will be installed on local hard drive</UIText> + <UIText Id="MenuAllNetwork">Entire feature will be installed to run from network</UIText> + <UIText Id="MenuCD">Will be installed to run from CD</UIText> + <UIText Id="MenuLocal">Will be installed on local hard drive</UIText> + <UIText Id="MenuNetwork">Will be installed to run from network</UIText> + <UIText Id="ScriptInProgress">Gathering required information...</UIText> + <UIText Id="SelAbsentAbsent">This feature will remain uninstalled</UIText> + <UIText Id="SelAbsentAdvertise">This feature will be set to be installed when required</UIText> + <UIText Id="SelAbsentCD">This feature will be installed to run from CD</UIText> + <UIText Id="SelAbsentLocal">This feature will be installed on the local hard drive</UIText> + <UIText Id="SelAbsentNetwork">This feature will be installed to run from the network</UIText> + <UIText Id="SelAdvertiseAbsent">This feature will become unavailable</UIText> + <UIText Id="SelAdvertiseAdvertise">Will be installed when required</UIText> + <UIText Id="SelAdvertiseCD">This feature will be available to run from CD</UIText> + <UIText Id="SelAdvertiseLocal">This feature will be installed on your local hard drive</UIText> + <UIText Id="SelAdvertiseNetwork">This feature will be available to run from the network</UIText> + <UIText Id="SelCDAbsent">This feature will be uninstalled completely, you won't be able to run it from CD</UIText> + <UIText Id="SelCDAdvertise">This feature will change from run from CD state to set to be installed when required</UIText> + <UIText Id="SelCDCD">This feature will remain to be run from CD</UIText> + <UIText Id="SelCDLocal">This feature will change from run from CD state to be installed on the local hard drive</UIText> + <UIText Id="SelChildCostNeg">This feature frees up [1] on your hard drive.</UIText> + <UIText Id="SelChildCostPos">This feature requires [1] on your hard drive.</UIText> + <UIText Id="SelCostPending">Compiling cost for this feature...</UIText> + <UIText Id="SelLocalAbsent">This feature will be completely removed</UIText> + <UIText Id="SelLocalAdvertise">This feature will be removed from your local hard drive, but will be set to be installed when required</UIText> + <UIText Id="SelLocalCD">This feature will be removed from your local hard drive, but will be still available to run from CD</UIText> + <UIText Id="SelLocalLocal">This feature will remain on you local hard drive</UIText> + <UIText Id="SelLocalNetwork">This feature will be removed from your local hard drive, but will be still available to run from the network</UIText> + <UIText Id="SelNetworkAbsent">This feature will be uninstalled completely, you won't be able to run it from the network</UIText> + <UIText Id="SelNetworkAdvertise">This feature will change from run from network state to set to be installed when required</UIText> + <UIText Id="SelNetworkLocal">This feature will change from run from network state to be installed on the local hard drive</UIText> + <UIText Id="SelNetworkNetwork">This feature will remain to be run from the network</UIText> + <UIText Id="SelParentCostNegNeg">This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.</UIText> + <UIText Id="SelParentCostNegPos">This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.</UIText> + <UIText Id="SelParentCostPosNeg">This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.</UIText> + <UIText Id="SelParentCostPosPos">This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.</UIText> + <UIText Id="TimeRemaining">Time remaining: {[1] minutes }{[2] seconds}</UIText> + <UIText Id="VolumeCostAvailable">Available</UIText> + <UIText Id="VolumeCostDifference">Difference</UIText> + <UIText Id="VolumeCostRequired">Required</UIText> + <UIText Id="VolumeCostSize">Disk Size</UIText> + <UIText Id="VolumeCostVolume">Volume</UIText> + <ProgressText Action="InstallValidate">Validating install</ProgressText> + <ProgressText Action="InstallFiles" Template="File: [1], Directory: [9], Size: [6]">Copying new files</ProgressText> + <ProgressText Action="InstallAdminPackage" Template="File: [1], Directory: [9], Size: [6]">Copying network install files</ProgressText> + <ProgressText Action="FileCost">Computing space requirements</ProgressText> + <ProgressText Action="CostInitialize">Computing space requirements</ProgressText> + <ProgressText Action="CostFinalize">Computing space requirements</ProgressText> + <ProgressText Action="CreateShortcuts" Template="Shortcut: [1]">Creating shortcuts</ProgressText> + <ProgressText Action="PublishComponents" Template="Component ID: [1], Qualifier: [2]">Publishing Qualified Components</ProgressText> + <ProgressText Action="PublishFeatures" Template="Feature: [1]">Publishing Product Features</ProgressText> + <ProgressText Action="PublishProduct">Publishing product information</ProgressText> + <ProgressText Action="RegisterClassInfo" Template="Class Id: [1]">Registering Class servers</ProgressText> + <ProgressText Action="RegisterExtensionInfo" Template="Extension: [1]">Registering extension servers</ProgressText> + <ProgressText Action="RegisterMIMEInfo" Template="MIME Content Type: [1], Extension: [2]">Registering MIME info</ProgressText> + <ProgressText Action="RegisterProgIdInfo" Template="ProgId: [1]">Registering program identifiers</ProgressText> + <ProgressText Action="AllocateRegistrySpace" Template="Free space: [1]">Allocating registry space</ProgressText> + <ProgressText Action="AppSearch" Template="Property: [1], Signature: [2]">Searching for installed applications</ProgressText> + <ProgressText Action="BindImage" Template="File: [1]">Binding executables</ProgressText> + <ProgressText Action="CCPSearch">Searching for qualifying products</ProgressText> + <ProgressText Action="CreateFolders" Template="Folder: [1]">Creating folders</ProgressText> + <ProgressText Action="DeleteServices" Template="Service: [1]">Deleting services</ProgressText> + <ProgressText Action="DuplicateFiles" Template="File: [1], Directory: [9], Size: [6]">Creating duplicate files</ProgressText> + <ProgressText Action="FindRelatedProducts" Template="Found application: [1]">Searching for related applications</ProgressText> + <ProgressText Action="InstallODBC">Installing ODBC components</ProgressText> + <ProgressText Action="InstallServices" Template="Service: [2]">Installing new services</ProgressText> + <ProgressText Action="LaunchConditions">Evaluating launch conditions</ProgressText> + <ProgressText Action="MigrateFeatureStates" Template="Application: [1]">Migrating feature states from related applications</ProgressText> + <ProgressText Action="MoveFiles" Template="File: [1], Directory: [9], Size: [6]">Moving files</ProgressText> + <ProgressText Action="PatchFiles" Template="File: [1], Directory: [2], Size: [3]">Patching files</ProgressText> + <ProgressText Action="ProcessComponents">Updating component registration</ProgressText> + <ProgressText Action="RegisterComPlus" Template="AppId: [1]{{, AppType: [2], Users: [3], RSN: [4]}}">Registering COM+ Applications and Components</ProgressText> + <ProgressText Action="RegisterFonts" Template="Font: [1]">Registering fonts</ProgressText> + <ProgressText Action="RegisterProduct" Template="[1]">Registering product</ProgressText> + <ProgressText Action="RegisterTypeLibraries" Template="LibID: [1]">Registering type libraries</ProgressText> + <ProgressText Action="RegisterUser" Template="[1]">Registering user</ProgressText> + <ProgressText Action="RemoveDuplicateFiles" Template="File: [1], Directory: [9]">Removing duplicated files</ProgressText> + <ProgressText Action="RemoveEnvironmentStrings" Template="Name: [1], Value: [2], Action [3]">Updating environment strings</ProgressText> + <ProgressText Action="RemoveExistingProducts" Template="Application: [1], Command line: [2]">Removing applications</ProgressText> + <ProgressText Action="RemoveFiles" Template="File: [1], Directory: [9]">Removing files</ProgressText> + <ProgressText Action="RemoveFolders" Template="Folder: [1]">Removing folders</ProgressText> + <ProgressText Action="RemoveIniValues" Template="File: [1], Section: [2], Key: [3], Value: [4]">Removing INI files entries</ProgressText> + <ProgressText Action="RemoveODBC">Removing ODBC components</ProgressText> + <ProgressText Action="RemoveRegistryValues" Template="Key: [1], Name: [2]">Removing system registry values</ProgressText> + <ProgressText Action="RemoveShortcuts" Template="Shortcut: [1]">Removing shortcuts</ProgressText> + <ProgressText Action="RMCCPSearch">Searching for qualifying products</ProgressText> + <ProgressText Action="SelfRegModules" Template="File: [1], Folder: [2]">Registering modules</ProgressText> + <ProgressText Action="SelfUnregModules" Template="File: [1], Folder: [2]">Unregistering modules</ProgressText> + <ProgressText Action="SetODBCFolders">Initializing ODBC directories</ProgressText> + <ProgressText Action="StartServices" Template="Service: [1]">Starting services</ProgressText> + <ProgressText Action="StopServices" Template="Service: [1]">Stopping services</ProgressText> + <ProgressText Action="UnpublishComponents" Template="Component ID: [1], Qualifier: [2]">Unpublishing Qualified Components</ProgressText> + <ProgressText Action="UnpublishFeatures" Template="Feature: [1]">Unpublishing Product Features</ProgressText> + <ProgressText Action="UnregisterClassInfo" Template="Class Id: [1]">Unregister Class servers</ProgressText> + <ProgressText Action="UnregisterComPlus" Template="AppId: [1]{{, AppType: [2]}}">Unregistering COM+ Applications and Components</ProgressText> + <ProgressText Action="UnregisterExtensionInfo" Template="Extension: [1]">Unregistering extension servers</ProgressText> + <ProgressText Action="UnregisterFonts" Template="Font: [1]">Unregistering fonts</ProgressText> + <ProgressText Action="UnregisterMIMEInfo" Template="MIME Content Type: [1], Extension: [2]">Unregistering MIME info</ProgressText> + <ProgressText Action="UnregisterProgIdInfo" Template="ProgId: [1]">Unregistering program identifiers</ProgressText> + <ProgressText Action="UnregisterTypeLibraries" Template="LibID: [1]">Unregistering type libraries</ProgressText> + <ProgressText Action="WriteEnvironmentStrings" Template="Name: [1], Value: [2], Action [3]">Updating environment strings</ProgressText> + <ProgressText Action="WriteIniValues" Template="File: [1], Section: [2], Key: [3], Value: [4]">Writing INI files values</ProgressText> + <ProgressText Action="WriteRegistryValues" Template="Key: [1], Name: [2], Value: [3]">Writing system registry values</ProgressText> + <ProgressText Action="Advertise">Advertising application</ProgressText> + <ProgressText Action="GenerateScript" Template="[1]">Generating script operations for action:</ProgressText> + <ProgressText Action="InstallSFPCatalogFile" Template="File: [1], Dependencies: [2]">Installing system catalog</ProgressText> + <ProgressText Action="MsiPublishAssemblies" Template="Application Context:[1], Assembly Name:[2]">Publishing assembly information</ProgressText> + <ProgressText Action="MsiUnpublishAssemblies" Template="Application Context:[1], Assembly Name:[2]">Unpublishing assembly information</ProgressText> + <ProgressText Action="Rollback" Template="[1]">Rolling back action:</ProgressText> + <ProgressText Action="RollbackCleanup" Template="File: [1]">Removing backup files</ProgressText> + <ProgressText Action="UnmoveFiles" Template="File: [1], Directory: [9]">Removing moved files</ProgressText> + <ProgressText Action="UnpublishProduct">Unpublishing product information</ProgressText> + <Error Id="0">{{Fatal error: }}</Error> + <Error Id="1">{{Error [1]. }}</Error> + <Error Id="2">Warning [1]. </Error> + <Error Id="3" /> + <Error Id="4">Info [1]. </Error> + <Error Id="5">The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is [1]. {{The arguments are: [2], [3], [4]}}</Error> + <Error Id="6" /> + <Error Id="7">{{Disk full: }}</Error> + <Error Id="8">Action [Time]: [1]. [2]</Error> + <Error Id="9">[ProductName]</Error> + <Error Id="10">{[2]}{, [3]}{, [4]}</Error> + <Error Id="11">Message type: [1], Argument: [2]</Error> + <Error Id="12">=== Logging started: [Date] [Time] ===</Error> + <Error Id="13">=== Logging stopped: [Date] [Time] ===</Error> + <Error Id="14">Action start [Time]: [1].</Error> + <Error Id="15">Action ended [Time]: [1]. Return value [2].</Error> + <Error Id="16">Time remaining: {[1] minutes }{[2] seconds}</Error> + <Error Id="17">Out of memory. Shut down other applications before retrying.</Error> + <Error Id="18">Installer is no longer responding.</Error> + <Error Id="19">Installer stopped prematurely.</Error> + <Error Id="20">Please wait while Windows configures [ProductName]</Error> + <Error Id="21">Gathering required information...</Error> + <Error Id="22">Removing older versions of this application...</Error> + <Error Id="23">Preparing to remove older versions of this application...</Error> + <Error Id="32">{[ProductName] }Setup completed successfully.</Error> + <Error Id="33">{[ProductName] }Setup failed.</Error> + <Error Id="1101">Error reading from file: [2]. {{ System error [3].}} Verify that the file exists and that you can access it.</Error> + <Error Id="1301">Cannot create the file '[2]'. A directory with this name already exists. Cancel the install and try installing to a different location.</Error> + <Error Id="1302">Please insert the disk: [2]</Error> + <Error Id="1303">The installer has insufficient privileges to access this directory: [2]. The installation cannot continue. Log on as administrator or contact your system administrator.</Error> + <Error Id="1304">Error writing to file: [2]. Verify that you have access to that directory.</Error> + <Error Id="1305">Error reading from file [2]. {{ System error [3].}} Verify that the file exists and that you can access it.</Error> + <Error Id="1306">Another application has exclusive access to the file '[2]'. Please shut down all other applications, then click Retry.</Error> + <Error Id="1307">There is not enough disk space to install this file: [2]. Free some disk space and click Retry, or click Cancel to exit.</Error> + <Error Id="1308">Source file not found: [2]. Verify that the file exists and that you can access it.</Error> + <Error Id="1309">Error reading from file: [3]. {{ System error [2].}} Verify that the file exists and that you can access it.</Error> + <Error Id="1310">Error writing to file: [3]. {{ System error [2].}} Verify that you have access to that directory.</Error> + <Error Id="1311">Source file not found{{(cabinet)}}: [2]. Verify that the file exists and that you can access it.</Error> + <Error Id="1312">Cannot create the directory '[2]'. A file with this name already exists. Please rename or remove the file and click retry, or click Cancel to exit.</Error> + <Error Id="1313">The volume [2] is currently unavailable. Please select another.</Error> + <Error Id="1314">The specified path '[2]' is unavailable.</Error> + <Error Id="1315">Unable to write to the specified folder: [2].</Error> + <Error Id="1316">A network error occurred while attempting to read from the file: [2]</Error> + <Error Id="1317">An error occurred while attempting to create the directory: [2]</Error> + <Error Id="1318">A network error occurred while attempting to create the directory: [2]</Error> + <Error Id="1319">A network error occurred while attempting to open the source file cabinet: [2]</Error> + <Error Id="1320">The specified path is too long: [2]</Error> + <Error Id="1321">The Installer has insufficient privileges to modify this file: [2].</Error> + <Error Id="1322">A portion of the folder path '[2]' is invalid. It is either empty or exceeds the length allowed by the system.</Error> + <Error Id="1323">The folder path '[2]' contains words that are not valid in folder paths.</Error> + <Error Id="1324">The folder path '[2]' contains an invalid character.</Error> + <Error Id="1325">'[2]' is not a valid short file name.</Error> + <Error Id="1326">Error getting file security: [3] GetLastError: [2]</Error> + <Error Id="1327">Invalid Drive: [2]</Error> + <Error Id="1328">Error applying patch to file [2]. It has probably been updated by other means, and can no longer be modified by this patch. For more information contact your patch vendor. {{System Error: [3]}}</Error> + <Error Id="1329">A file that is required cannot be installed because the cabinet file [2] is not digitally signed. This may indicate that the cabinet file is corrupt.</Error> + <Error Id="1330">A file that is required cannot be installed because the cabinet file [2] has an invalid digital signature. This may indicate that the cabinet file is corrupt.{{ Error [3] was returned by WinVerifyTrust.}}</Error> + <Error Id="1331">Failed to correctly copy [2] file: CRC error.</Error> + <Error Id="1332">Failed to correctly move [2] file: CRC error.</Error> + <Error Id="1333">Failed to correctly patch [2] file: CRC error.</Error> + <Error Id="1334">The file '[2]' cannot be installed because the file cannot be found in cabinet file '[3]'. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package.</Error> + <Error Id="1335">The cabinet file '[2]' required for this installation is corrupt and cannot be used. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package.</Error> + <Error Id="1336">There was an error creating a temporary file that is needed to complete this installation.{{ Folder: [3]. System error code: [2]}}</Error> + <Error Id="1401">Could not create key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. </Error> + <Error Id="1402">Could not open key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. </Error> + <Error Id="1403">Could not delete value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. </Error> + <Error Id="1404">Could not delete key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. </Error> + <Error Id="1405">Could not read value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. </Error> + <Error Id="1406">Could not write value [2] to key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel.</Error> + <Error Id="1407">Could not get value names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.</Error> + <Error Id="1408">Could not get sub key names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.</Error> + <Error Id="1409">Could not read security information for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.</Error> + <Error Id="1410">Could not increase the available registry space. [2] KB of free registry space is required for the installation of this application.</Error> + <Error Id="1500">Another installation is in progress. You must complete that installation before continuing this one.</Error> + <Error Id="1501">Error accessing secured data. Please make sure the Windows Installer is configured properly and try the install again.</Error> + <Error Id="1502">User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product. Your current install will now continue.</Error> + <Error Id="1503">User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product.</Error> + <Error Id="1601">Out of disk space -- Volume: '[2]'; required space: [3] KB; available space: [4] KB. Free some disk space and retry.</Error> + <Error Id="1602">Are you sure you want to cancel?</Error> + <Error Id="1603">The file [2][3] is being held in use{ by the following process: Name: [4], Id: [5], Window Title: '[6]'}. Close that application and retry.</Error> + <Error Id="1604">The product '[2]' is already installed, preventing the installation of this product. The two products are incompatible.</Error> + <Error Id="1605">There is not enough disk space on the volume '[2]' to continue the install with recovery enabled. [3] KB are required, but only [4] KB are available. Click Ignore to continue the install without saving recovery information, click Retry to check for available space again, or click Cancel to quit the installation.</Error> + <Error Id="1606">Could not access network location [2].</Error> + <Error Id="1607">The following applications should be closed before continuing the install:</Error> + <Error Id="1608">Could not find any previously installed compliant products on the machine for installing this product.</Error> + <Error Id="1609">An error occurred while applying security settings. [2] is not a valid user or group. This could be a problem with the package, or a problem connecting to a domain controller on the network. Check your network connection and click Retry, or Cancel to end the install. {{Unable to locate the user's SID, system error [3]}}</Error> + <Error Id="1701">The key [2] is not valid. Verify that you entered the correct key.</Error> + <Error Id="1702">The installer must restart your system before configuration of [2] can continue. Click Yes to restart now or No if you plan to manually restart later.</Error> + <Error Id="1703">You must restart your system for the configuration changes made to [2] to take effect. Click Yes to restart now or No if you plan to manually restart later.</Error> + <Error Id="1704">An installation for [2] is currently suspended. You must undo the changes made by that installation to continue. Do you want to undo those changes?</Error> + <Error Id="1705">A previous installation for this product is in progress. You must undo the changes made by that installation to continue. Do you want to undo those changes?</Error> + <Error Id="1706">An installation package for the product [2] cannot be found. Try the installation again using a valid copy of the installation package '[3]'.</Error> + <Error Id="1707">Installation completed successfully.</Error> + <Error Id="1708">Installation failed.</Error> + <Error Id="1709">Product: [2] -- [3]</Error> + <Error Id="1710">You may either restore your computer to its previous state or continue the install later. Would you like to restore?</Error> + <Error Id="1711">An error occurred while writing installation information to disk. Check to make sure enough disk space is available, and click Retry, or Cancel to end the install.</Error> + <Error Id="1712">One or more of the files required to restore your computer to its previous state could not be found. Restoration will not be possible.</Error> + <Error Id="1713">[2] cannot install one of its required products. Contact your technical support group. {{System Error: [3].}}</Error> + <Error Id="1714">The older version of [2] cannot be removed. Contact your technical support group. {{System Error [3].}}</Error> + <Error Id="1715">Installed [2]</Error> + <Error Id="1716">Configured [2]</Error> + <Error Id="1717">Removed [2]</Error> + <Error Id="1718">File [2] was rejected by digital signature policy.</Error> + <Error Id="1719">The Windows Installer Service could not be accessed. This can occur if you are running Windows in safe mode, or if the Windows Installer is not correctly installed. Contact your support personnel for assistance.</Error> + <Error Id="1720">There is a problem with this Windows Installer package. A script required for this install to complete could not be run. Contact your support personnel or package vendor. {{Custom action [2] script error [3], [4]: [5] Line [6], Column [7], [8] }}</Error> + <Error Id="1721">There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action: [2], location: [3], command: [4] }}</Error> + <Error Id="1722">There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. {{Action [2], location: [3], command: [4] }}</Error> + <Error Id="1723">There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action [2], entry: [3], library: [4] }}</Error> + <Error Id="1724">Removal completed successfully.</Error> + <Error Id="1725">Removal failed.</Error> + <Error Id="1726">Advertisement completed successfully.</Error> + <Error Id="1727">Advertisement failed.</Error> + <Error Id="1728">Configuration completed successfully.</Error> + <Error Id="1729">Configuration failed.</Error> + <Error Id="1730">You must be an Administrator to remove this application. To remove this application, you can log on as an Administrator, or contact your technical support group for assistance.</Error> + <Error Id="1801">The path [2] is not valid. Please specify a valid path.</Error> + <Error Id="1802">Out of memory. Shut down other applications before retrying.</Error> + <Error Id="1803">There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to go back to the previously selected volume.</Error> + <Error Id="1804">There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to return to the browse dialog and select a different volume.</Error> + <Error Id="1805">The folder [2] does not exist. Please enter a path to an existing folder.</Error> + <Error Id="1806">You have insufficient privileges to read this folder.</Error> + <Error Id="1807">A valid destination folder for the install could not be determined.</Error> + <Error Id="1901">Error attempting to read from the source install database: [2].</Error> + <Error Id="1902">Scheduling reboot operation: Renaming file [2] to [3]. Must reboot to complete operation.</Error> + <Error Id="1903">Scheduling reboot operation: Deleting file [2]. Must reboot to complete operation.</Error> + <Error Id="1904">Module [2] failed to register. HRESULT [3]. Contact your support personnel.</Error> + <Error Id="1905">Module [2] failed to unregister. HRESULT [3]. Contact your support personnel.</Error> + <Error Id="1906">Failed to cache package [2]. Error: [3]. Contact your support personnel.</Error> + <Error Id="1907">Could not register font [2]. Verify that you have sufficient permissions to install fonts, and that the system supports this font.</Error> + <Error Id="1908">Could not unregister font [2]. Verify that you that you have sufficient permissions to remove fonts.</Error> + <Error Id="1909">Could not create Shortcut [2]. Verify that the destination folder exists and that you can access it.</Error> + <Error Id="1910">Could not remove Shortcut [2]. Verify that the shortcut file exists and that you can access it.</Error> + <Error Id="1911">Could not register type library for file [2]. Contact your support personnel.</Error> + <Error Id="1912">Could not unregister type library for file [2]. Contact your support personnel.</Error> + <Error Id="1913">Could not update the ini file [2][3]. Verify that the file exists and that you can access it.</Error> + <Error Id="1914">Could not schedule file [2] to replace file [3] on reboot. Verify that you have write permissions to file [3].</Error> + <Error Id="1915">Error removing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel.</Error> + <Error Id="1916">Error installing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel.</Error> + <Error Id="1917">Error removing ODBC driver: [4], ODBC error [2]: [3]. Verify that you have sufficient privileges to remove ODBC drivers.</Error> + <Error Id="1918">Error installing ODBC driver: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it.</Error> + <Error Id="1919">Error configuring ODBC data source: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it.</Error> + <Error Id="1920">Service '[2]' ([3]) failed to start. Verify that you have sufficient privileges to start system services.</Error> + <Error Id="1921">Service '[2]' ([3]) could not be stopped. Verify that you have sufficient privileges to stop system services.</Error> + <Error Id="1922">Service '[2]' ([3]) could not be deleted. Verify that you have sufficient privileges to remove system services.</Error> + <Error Id="1923">Service '[2]' ([3]) could not be installed. Verify that you have sufficient privileges to install system services.</Error> + <Error Id="1924">Could not update environment variable '[2]'. Verify that you have sufficient privileges to modify environment variables.</Error> + <Error Id="1925">You do not have sufficient privileges to complete this installation for all users of the machine. Log on as administrator and then retry this installation.</Error> + <Error Id="1926">Could not set file security for file '[3]'. Error: [2]. Verify that you have sufficient privileges to modify the security permissions for this file.</Error> + <Error Id="1927">Component Services (COM+ 1.0) are not installed on this computer. This installation requires Component Services in order to complete successfully. Component Services are available on Windows 2000.</Error> + <Error Id="1928">Error registering COM+ Application. Contact your support personnel for more information.</Error> + <Error Id="1929">Error unregistering COM+ Application. Contact your support personnel for more information.</Error> + <Error Id="1930">The description for service '[2]' ([3]) could not be changed.</Error> + <Error Id="1931">The Windows Installer service cannot update the system file [2] because the file is protected by Windows. You may need to update your operating system for this program to work correctly. {{Package version: [3], OS Protected version: [4]}}</Error> + <Error Id="1932">The Windows Installer service cannot update the protected Windows file [2]. {{Package version: [3], OS Protected version: [4], SFP Error: [5]}}</Error> + <Error Id="1933">The Windows Installer service cannot update one or more protected Windows files. {{SFP Error: [2]. List of protected files:\r\n[3]}}</Error> + <Error Id="1934">User installations are disabled via policy on the machine.</Error> + <Error Id="1935">An error occured during the installation of assembly component [2]. HRESULT: [3]. {{assembly interface: [4], function: [5], assembly name: [6]}}</Error> + + <Error Id="4001">Custom action data not found. STATUS [2]</Error> + <Error Id="4003">NSIS Uninstallation failed. Status [2]</Error> + <Error Id="4004">ABORT: [2]</Error> + <Error Id="4005">Custom action failed. Phase [2]</Error> + <Error Id="4006">Failed to determine running processes. Status [2]</Error> + <Error Id="4007">Failed to install Kerberos network provider. Status [2]</Error> + <AdminUISequence> + <Show Dialog="FatalError" OnExit="error" /> + <Show Dialog="UserExit" OnExit="cancel" /> + <Show Dialog="ExitDialog" OnExit="success" /> + <Show Dialog="PrepareDlg" Before="CostInitialize" /> + <Show Dialog="AdminWelcomeDlg" After="CostFinalize" /> + <Show Dialog="ProgressDlg" After="AdminWelcomeDlg" /> + </AdminUISequence> + <InstallUISequence> + <Custom Action="ListRunningProcesses" Before="WelcomeDlg" /> + <Show Dialog="FatalError" OnExit="error" /> + <Show Dialog="UserExit" OnExit="cancel" /> + <Show Dialog="ExitDialog" OnExit="success" /> + <Show Dialog="PrepareDlg" After="LaunchConditions" /> + <Show Dialog="WelcomeDlg" After="MigrateFeatureStates">NOT Installed</Show> + <Show Dialog="ResumeDlg" After="WelcomeDlg">Installed AND (RESUME OR Preselected)</Show> + <Show Dialog="MaintenanceWelcomeDlg" After="ResumeDlg">Installed AND NOT RESUME AND NOT Preselected</Show> + <Show Dialog="ProgressDlg" After="MaintenanceWelcomeDlg" /> + </InstallUISequence> + </UI> + <Property Id="ErrorDialog"><![CDATA[ErrorDlg]]></Property> + <Property Id="DefaultUIFont"><![CDATA[DlgFont8]]></Property> + <Property Id="ButtonText_No"><![CDATA[&No]]></Property> + <Property Id="ButtonText_Install"><![CDATA[&Install]]></Property> + <Property Id="ButtonText_Next"><![CDATA[&Next >]]></Property> + <Property Id="Setup"><![CDATA[Setup]]></Property> + <Property Id="ButtonText_Browse"><![CDATA[Br&owse]]></Property> + <Property Id="CustomSetupIcon"><![CDATA[custicon]]></Property> + <Property Id="RepairIcon"><![CDATA[repairic]]></Property> + <Property Id="ExclamationIcon"><![CDATA[exclamic]]></Property> + <Property Id="ButtonText_Repair"><![CDATA[&Repair]]></Property> + <Property Id="ButtonText_Back"><![CDATA[< &Back]]></Property> + <Property Id="InstallMode"><![CDATA[Typical]]></Property> + <Property Id="Progress2"><![CDATA[installs]]></Property> + <Property Id="Progress1"><![CDATA[Installing]]></Property> + <Property Id="Wizard"><![CDATA[Setup Wizard]]></Property> + <Property Id="RemoveIcon"><![CDATA[removico]]></Property> + <Property Id="ButtonText_Yes"><![CDATA[&Yes]]></Property> + <Property Id="ButtonText_Ignore"><![CDATA[&Ignore]]></Property> + <Property Id="ButtonText_Reset"><![CDATA[&Reset]]></Property> + <Property Id="ButtonText_Refresh"><![CDATA[&Refresh]]></Property> + <Property Id="ButtonText_Remove"><![CDATA[&Remove]]></Property> + <Property Id="ShowUserRegistrationDlg"><![CDATA[0]]></Property> + <Property Id="ButtonText_Exit"><![CDATA[&Exit]]></Property> + <Property Id="ButtonText_Return"><![CDATA[&Return]]></Property> + <Property Id="ButtonText_OK"><![CDATA[OK]]></Property> + <Property Id="CompleteSetupIcon"><![CDATA[completi]]></Property> + <Property Id="ButtonText_Resume"><![CDATA[&Resume]]></Property> + <Property Id="ButtonText_Close"><![CDATA[&Close]]></Property> + <Property Id="InstallerIcon"><![CDATA[insticon]]></Property> + <Property Id="ButtonText_Finish"><![CDATA[&Finish]]></Property> + <Property Id="PROMPTROLLBACKCOST"><![CDATA[P]]></Property> + <Property Id="PIDTemplate"><![CDATA[12345<###-%%%%%%%>@@@@@]]></Property> + <Property Id="DlgTitleFont"><![CDATA[{&DlgFontBold8}]]></Property> + <Property Id="ButtonText_Cancel"><![CDATA[Cancel]]></Property> + <Property Id="InfoIcon"><![CDATA[info]]></Property> + <Property Id="ButtonText_Retry"><![CDATA[&Retry]]></Property> + <Property Id="IAgree"><![CDATA[No]]></Property> + <Property Id="BannerBitmap"><![CDATA[bannrbmp]]></Property> + <Property Id="DialogBitmap"><![CDATA[dlgbmp]]></Property> + <Binary Id="bannrbmp" src="Binary\bannrbmp.bmp" /> + <Binary Id="completi" src="Binary\completi.ico" /> + <Binary Id="custicon" src="Binary\custicon.ico" /> + <Binary Id="dlgbmp" src="Binary\dlgbmp.bmp" /> + <Binary Id="exclamic" src="Binary\exclamic.ico" /> + <Binary Id="info" src="Binary\info.bmp" /> + <Binary Id="insticon" src="Binary\insticon.ico" /> + <Binary Id="New" src="Binary\New.bmp" /> + <Binary Id="removico" src="Binary\removico.ico" /> + <Binary Id="repairic" src="Binary\repairic.ico" /> + <Binary Id="Up" src="Binary\up.bmp" /> +</Include> \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/msi-deployment-guide.txt b/mechglue/src/windows/installer/wix/msi-deployment-guide.txt new file mode 100644 index 000000000..15931a807 --- /dev/null +++ b/mechglue/src/windows/installer/wix/msi-deployment-guide.txt @@ -0,0 +1,524 @@ + +Kerberos for Windows + + MSI Deployment Guide + +---------------------------------------------------------------------- + + Contents + + 1. Introduction + 1.1 Requirements + 1.2 Authoring a Transform + 2. Configuration Options + 2.1 Configurable Properties + 2.1.1 Setting Properties + 2.1.2 Leash GUI Properties + 2.1.3 Leash DLL Properties + 2.1.4 Kerberos IV Properties + 2.1.5 Kerberos V Properties + 2.2 Existing Registry Entries + 2.3 Replacing Configuration Files + 3. Additional Resources + 4. Upgrades + 5. FAQ + +---------------------------------------------------------------------- + +1. Introduction + + Beginning with "Kerberos for Windows" version 2.6.5, a MSI installer + option is available for those who wish to use "Windows Installer" + for installing Kerberos and for organizations that wish to deploy + Kerberos through Group Policy. + + This document provides a guide for authoring transforms used to + customize the MSI package for a particular organization. Although + many settings can be deployed via transforms, in an Active + Directory environment it is advisable to deploy registry settings + and configuration files through group policy and/or startup + scripts so that machines where "Kerberos for Windows" is already + installed will pick up these customizations. + +1.1 Requirements + + The information in this document applies to MSI packages + distributed with "Kerberos for Windows" releases from 2.6.5 and + onwards or MSI packages built from corresponding source + releases. Not all releases support all the configuration options + documented here. + + Authoring a "Windows Installer" transform requires additional + software for editing the MSI database tables and generating the + transform from the modified MSI package. ORCA.EXE and MSITRAN.EXE + which are included in the Windows Platform SDK ("Windows Installer" + SDK) can be used for this purpose. + + For reference, the schema for the MSI package is based on + SCHEMA.MSI distributed with the Platform SDK. + + For general information about "Windows Installer", refer to : + + http://msdn.microsoft.com/library/en-us/msi/setup/windows_installer_start_page.asp + + For general information about authoring MSI transforms, refer to : + + http://msdn.microsoft.com/library/en-us/msi/setup/transforms.asp + + The remainder of this document assumes some familiarity with + authoring transforms. While the MSDN documentation for Windows + Installer is a bit dense, it is recommended that you read through + the guide on MSI transforms found at the second link above. Also + MSDN includes a step-by-step example for creating a transform at: + + http://msdn.microsoft.com/library/en-us/msi/setup/a_customization_transform_example.asp + +1.2 Authoring a Transform + + Transforms describe a set of modifications to be performed on an + existing MSI for the purpose of customizing it. This is + ordinarily done by making a copy of the MSI to be customized, + modifying the copy and then using the old and the new MSI to + generate a transform. + + E.g: + > copy kfw.msi kfw-modified.msi + + (edit the kfw-modified.msi to include the necessary changes) + + > msitran -g kfw-modified.msi kfw.msi kfw-transform.mst + + (generates kfw-transform.mst, which is the transform) + + Transforms have an extension of .mst. 'msitran' is a tool + distributed as part of the "Windows Installer" SDK (which in turn is + a part of the Windows Platform SDK). + + You can test a transform by : + + > copy kfw.msi kfw-test.msi + > msitran -a kfw-transform.mst kfw-test.msi + + and then checking the resulting kfw-test.msi to see if all the + changes you have made above to kfw-modified.msi is present in + kfw-test.msi. 'msitran' will complain if some modification in the + transform can not be successfully applied. + + As mentioned above, you can use a tool like ORCA.EXE to edit the + MSI databases directly when editing kfw-modified.msi. More + details are given below. + +---------------------------------------------------------------------- + +2. Configuration Options + + The logic necessary to implement all of the settings described in + the release notes are present in the MSI. Most of these can be + controlled by setting the corresponding properties to the desired + value. Some settings may require modifying existing registry + entries (though not recommended) or adding new resources (like + files or registry keys). Instructions for performing these tasks + are below. + +2.1 Configurable Properties + + Most configurable properties correspond to registry keys or + values. Please refer to the release notes for more information + about how these registry settings are used. + + Due to the logic invoked based on the existence of these registry + keys or values, they are only set if the associated property is + defined to have a non null value. If the associated property is + not defined in the MSI, the registry key or value will not be + touched. By default, the MSI does not contain these properties + and hence will not set the registry keys. You will need to add + properties as needed to the MSI. + + When one of the configurable properties is set, the installer will + use the property value to set the corresponding setting in the + HKEY_LOCAL_MACHINE registry hive. HKEY_CURRENT_USER hive is not + touched by the installer. + + For each property, the associated registry setting is referenced + by the same text used in the release notes ('Registry and + Environment Settings' section). + + Strings are quoted using single quotes (e.g. 'a string'). An empty + string is denoted as ''. Note that you can't author null values + into the 'Property' table. + + Numeric values should be authored as decimal strings. + +2.1.1 Setting Properties + + In order to set a property, + + a. Open the MSI in ORCA.EXE + + b. Select the 'Property' table from the list of tables on the left. + + c. Find the property in the list of properties on the right, + double click the value and type the new value. + + d. If the property does not exist in the property list, right + click the list and select 'Add Row', type the property name + and the desired value. + +2.1.2 Leash GUI properties + + LEASHAFSSTATUS + Setting: afs token retrieval + Values : '0' or '1' + + LEASHCREATEMISSINGCONFIG + Setting: automatic generation of missing configuration files + Values : '0' or '1' + + LEASHAUTORENEWTICKETS + Setting: automatic ticket renewal + Values : '0' or '1' + + LEASHLOCKFILELOCATIONS + Setting: lock configuration files location + Values : '0' or '1' + + LEASHMSLSAIMPORT + Setting: automatic importation of MSLSA credentials + Values : '0', '1' or '2' + +2.1.3 Leash32 DLL properties + + LEASHLIFETIME + Setting: default lifetime (minutes) + Values : numeric + + LEASHRENEWTILL + Setting: default renew till time (minutes) + Values : numeric + + LEASHRENEWABLE + Setting: default renewable tickets setting + Values : '0' or '1' + + LEASHFORWARDABLE + Setting: default forwardable tickets setting + Values : '0' or '1' + + LEASHNOADDRESSES + Setting: default addressless tickets setting + Values : '0' or '1' + + LEASHPROXIABLE + Setting: default proxiable tickets setting + Values : '0' or '1' + + LEASHPUBLICIP + Setting: default public ipv4 address + Values : numeric + + LEASHUSEKRB4 + Setting: request kerberos iv tickets + Values : '0' or '1' + + LEASHHIDEKINITOPTIONS + Setting: hide advanced kinit options in dialog + Values : '0' or '1' + + LEASHLIFEMIN + Setting: minimum kinit dialog lifetime + Values : numeric + + LEASHLIFEMAX + Setting: maximum kinit dialog lifetime + Values : numeric + + LEASHRENEWMIN + Setting: minimum kinit dialog renew till time + Values : numeric + + LEASHRENEWMAX + Setting: maximum kinit dialog renew till time + Values : numeric + + LEASHUPPERCASEREALM + Setting: upper case realm + Values : '0' or '1' + + LEASHTIMEHOST + Setting: timesync host + Values : string + + LEASHPRESERVEKINITOPTIONS + Setting: Preserve ticket initialization dialog options + Values : numeric + +2.1.4 Kerberos 4 properties + + KRB4KRBREALMS (realms full pathname) + KRB4KRBCONF (config full pathname) + KRB4KRBCONFIDIR (dir for both files) + Setting: location of krbrealm & krbconf + Values : string + (note that the three registry settings are conditioned + independently. I.e. If you only set KRB4KRBCONF, only the + krb.conf setting will be written.) + + KRB4TICKETFILE + Setting: ticket file + Values : string + +2.1.5 Kerberos 5 properties + + KRB5CONFIG + Setting: location of krb5.ini + Values : string + + KRB5CCNAME + Setting: Default credentials cache name + Values : string + + KRB5PRESERVEIDENTITY + Setting: MSLSA: credential cache client principal identity generation + Values : '0' or '1' + +2.2 Existing Registry Entries + + You can change existing registry values subject to the + restrictions mentioned in the Windows Platform SDK. Pay special + attention to component keypaths and try to only change the 'Value' + column in the 'Registry' table. If you want to add additional + registry keys please refer to section 3 (Additional Resources). + +2.3 Replacing Configuration Files + + The Kerberos configuration files (krb5.ini, krb.con, krbrealm.con) + can be replaced by your own configuration files. These files are + contained in separate MSI components so that you can disable them + individually. + + The recommended method for replacing these files is to first + disable the components containing the configuration files that you + want to replace, and then add new components for the replacement + files. This is outlined below (assuming you are using ORCA.EXE to + author the transform). + + Note that transforms are not a good way to add a new file as an + embedded stream. The method outlined here places the file in the + same directory as the MSI for deployment. + + The walkthrough below is to add a custom 'krb5.ini' file. + + 1) Disable the component that contains the configuration file that + you want to replace. + + 1.1) Locate and select the 'Component' table in the 'Tables' + list. + + 1.2) In the Component table, locate the component you need to + change ( Ctrl-F invokes the 'Find' dialog). The component + names are listed below in section 2.3.1. For this + example, the component name is 'cmf_krb5_ini'. + + 1.3) Go to the 'Condition' column of the component. + + 1.4) Enter a condition that evaluates to + false. I.e. 'DONOTINSTALL'. (Note that an undefined + property always evaluates to false). + + Note that you can also use this step to disable other + configuration files without providing replacements. + + 2) Add a new component containing the new configuration file. + + 2.1) Select the 'Component' table in the 'Tables' list. + + 2.2) Select 'Tables'->'Add Row' (Ctrl-R). + + 2.3) Enter the following : + + Component : cmf_my_krb5_ini + ComponentId : {835BAAC6-5E54-BFFE-DBCB2F240711} + Directory_ : WindowsFolder + Attributes : 144 + Condition : + KeyPath : fil_my_krb5_ini + + Note that the ComponentId is an uppercase GUID. You can + generate one using GUIDGEN.EXE or UUIDGEN.EXE, both of + which are included in the Platform SDK. + + The Attributes value of 144 is a sum of + msidbComponentAttributesPermanent (16) and + msidbComponentAttributesNeverOverwrite (128). This + ensures that local modifications are not overwritten or + lost during an installation or uninstallation. These are + the same settings used on the default configuration files. + + 'fil_my_krb5_ini' is a key into the 'File' table which we + will fill later. + + 3) Add a new feature to hold the new component. + + 3.1) Select the 'Feature' table. + + 3.2) Add a new row (Ctrl-R or 'Tables'->'Add Row') with the + following values: + + Feature : fea_my_krb5_ini + Feature_Parent: feaKfwClient + Title : + Description : + Display : 0 + Level : 30 + Directory_ : + Attributes : 8 + + It is important to create the new feature under the + 'feaKfwClient' feature, which will ensure that the + configuration file will be installed when the client + binaries are installed. + + Setting 'Display' to 0 will hide this feature from the + feature selection dialog during an interactive + installation. A value of 30 for 'Level' allows this + feature to be installed by default (on a 'Typical' + installation). + + The 'Attributes' value is + msidbFeatureAttributesDisallowAdvertise (8), which is set + on all features in the KfW MSI. The KfW MSI is not + designed for an advertised installation. + + 4) Join the component and the feature. + + 4.1) Select the 'FeatureComponents' table. + + 4.2) Add a new row with the following values: + + Feature : fea_my_krb5_ini + Component : cmf_my_krb5_ini + + 5) Add an entry to the 'File' table. + + 5.1) Select the 'File' table. + + 5.2) Add a new row with the following values: + + File : fil_my_krb5_ini + Component_ : cmf_my_krb5_ini + FileName : krb5.ini + FileSize : (enter file size here) + ... + Attributes : 8192 + Sequence : 1000 + (leave other fields blank) + + The 'Attributes' value is msidbFileAttributesNonCompressed + (8192). This is because we will be placing this file in + the same directory as the MSI instead of embedding the + file in it. Transforms do not support updating compressed + sources or adding new cabinet streams. + + Finally, the 'Sequence' value of 1000 will be used later + to distinguish the file as being in a separate source + location than the other files in the MSI. + + 6) Set a media source for the file. + + 6.1) Select the 'Media' table. + + 6.2) Add a row with the following values : + + DiskId : 2 + LastSequence : 1000 + ... + (leave other fields blank) + + The sequence number of 1000 designates this as the media + source for the newly added file. + +2.3.1 Components for Configuration Files + + krb5.ini : 'cmf_krb5_ini' (ID {C1AF0670-BBF1-4AA6-B2A6-6C8B1584A1F4}) + krb.con : 'cmf_krb_con' (ID {5391A051-CF14-45FF-BF64-CEE78A7A90C2}) + krbrealm.con: 'cmf_krbrealm_con' (ID {D667B54F-1C98-43FB-87C6-0F0517623B90}) + +---------------------------------------------------------------------- + +3 Additional Resources + + If you want to add registry keys or files you need to create new + components and features for those. + + Add new features under the 'feaKfwClient' feature and set the + 'Level' column for those features to equal the 'Level' for their + parent features for consistency. Note that none of the features + in the "Kerberos for Windows" MSI package are designed to be + installed to run from 'source' or 'advertised'. It is recommended + that you set 'msidbFeatureAttributesFavorLocal' (0), + 'msidbFeatureAttributesFollowParent' (2) and + 'msidbFeatureAttributesDisallowAdvertise' (8) attributes for new + features. + + If you are creating new components, retain the same component GUID + when creating new transforms against new releases of the Kerberos + MSI package. + + It is beyond the scope of this document to provide a comprehensive + overview of how to add new resources through a transform. Please + refer to the "Windows Installer" documentation for details. The + relevant section is at : + + http://msdn.microsoft.com/library/en-us/msi/setup/using_transforms_to_add_resources.asp + + A sample walkthrough of adding a new configuration file is in + section 2.3. + +---------------------------------------------------------------------- + +4. Upgrades + + The MSI package is designed to uninstall previous versions of + "Kerberos for Windows" during installation. Note that it doesn't + directly upgrade an existing installation. This is intentional + and ensures that development releases which do not have strictly + increasing version numbers are properly upgraded. + + Versions of Kerberos that are upgraded by the MSI package are : + + 1) "Kerberos for Windows" MSI package + + Upgrade code {61211594-AAA1-4A98-A299-757326763CC7} + Upto current release + + 2) "MIT Project Pismere Kerberos for Windows" MSI package and + "MIT SWRT Kerberos for Windows" MSI + + Upgrade code {83977767-388D-4DF8-BB08-3BF2401635BD} + All versions + + 3) "Kerberos for Windows" NSIS package + + All versions + + Note that versions of the "Kerberos for Windows" NSIS package had + a bug where it couldn't be uninstalled properly in unattended + mode. Therefore the MSI package will not try to uninstall an + "Kerberos for Windows" NSIS package if running unattended. This + means that group policy based deployments will fail on machines + that have the "Kerberos for Windows" NSIS package installed. + + If you have used a different MSI package to install Kerberos for + Windows and wish to upgrade it you can author rows into the + 'Upgrade' table to have the "Kerberos for Windows" MSI replace these + installations for you. + +---------------------------------------------------------------------- + +5. FAQ + + (Q/A's will be added here as needed) + +---------------------------------------------------------------------- +$Id$ + diff --git a/mechglue/src/windows/installer/wix/property.wxi b/mechglue/src/windows/installer/wix/property.wxi new file mode 100644 index 000000000..f969d912b --- /dev/null +++ b/mechglue/src/windows/installer/wix/property.wxi @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + + Copyright (C) 2004 by the Massachusetts Institute of Technology. + All rights reserved. + + Export of this software from the United States of America may + require a specific license from the United States Government. + It is the responsibility of any person or organization contemplating + export to obtain such a license before exporting. + + WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + distribute this software and its documentation for any purpose and + without fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright notice and + this permission notice appear in supporting documentation, and that + the name of M.I.T. not be used in advertising or publicity pertaining + to distribution of the software without specific, written prior + permission. Furthermore if you modify this software you must label + your software as modified software and not distribute it in such a + fashion that it might be confused with the original M.I.T. software. + M.I.T. makes no representations about the suitability of + this software for any purpose. It is provided "as is" without express + or implied warranty. + + --> +<Include xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> + + <!-- Important: This product should only be installed in all-user mode --> + <Property Id="ALLUSERS">1</Property> + + <Property Id="LEASHAUTOINIT" Admin="yes" Secure="yes">-autoinit</Property> + <Property Id="LEASHAUTOSTART" Admin="yes" Secure="yes">1</Property> + + <Property Id="ARPCOMMENTS">$(var.ARPComments)</Property> + <Property Id="ARPCONTACT">kerberos@mit.edu</Property> + <Property Id="ARPURLINFOABOUT">http://web.mit.edu/kerberos</Property> + <Property Id="ARPHELPLINK">http://web.mit.edu/kerberos</Property> + <Property Id="INSTALLLEVEL">50</Property> + <Property Id="ComponentDownload">http://web.mit.edu/kerberos</Property> + + <Property Id="UPGRADENSIS"> + <RegistrySearch Id="regsrch_NSIS" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Kerberos for Windows" Name="UninstallString" Type="registry" /> + </Property> + + <Property Id="NSISVERSION"> + <RegistrySearch Id="regsrch_NSISV" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Kerberos for Windows" Name="DisplayVersion" Type="registry" /> + </Property> + + <Property Id="CantRemoveNSISError">$(loc.CantRemoveNSIS)</Property> + <Property Id="NoIE501Error">$(loc.IE501Required)</Property> + <!-- Additional properties relating to the UI are in the appropriate UI.wxi file --> + + <!-- Configuration properties. If these properties are defined, then + the corresponding component will be enabled. If the corresponding + variable value is the empty string (""), then the properties will + not be defined. --> +<?ifdef UseDefaultProperties?> + <Property Id="LEASHAFSSTATUS" Admin="yes" Secure="yes">$(var.LeashAfsStatus)</Property> + <Property Id="LEASHCREATEMISSINGCONFIG" Admin="yes" Secure="yes">$(var.LeashCreateMissingConfig)</Property> + <Property Id="LEASHAUTORENEWTICKETS" Admin="yes" Secure="yes">$(var.LeashAutoRenewTickets)</Property> + <Property Id="LEASHLOCKFILELOCATIONS" Admin="yes" Secure="yes">$(var.LeashLockFileLocations)</Property> + <Property Id="LEASHMSLSAIMPORT" Admin="yes" Secure="yes">$(var.LeashMsLsaImport)</Property> + <Property Id="LEASHLIFETIME" Admin="yes" Secure="yes">$(var.LeashLifetime)</Property> + <Property Id="LEASHRENEWTILL" Admin="yes" Secure="yes">$(var.LeashRenewTill)</Property> + <Property Id="LEASHRENEWABLE" Admin="yes" Secure="yes">$(var.LeashRenewable)</Property> + <Property Id="LEASHFORWARDABLE" Admin="yes" Secure="yes">$(var.LeashForwardable)</Property> + <Property Id="LEASHNOADDRESSES" Admin="yes" Secure="yes">$(var.LeashNoAddresses)</Property> + <Property Id="LEASHPROXIABLE" Admin="yes" Secure="yes">$(var.LeashProxiable)</Property> + <Property Id="LEASHPUBLICIP" Admin="yes" Secure="yes">$(var.LeashPublicIp)</Property> + <Property Id="LEASHUSEKRB4" Admin="yes" Secure="yes">$(var.LeashUseKrb4)</Property> + <Property Id="LEASHHIDEKINITOPTIONS" Admin="yes" Secure="yes">$(var.LeashHideKinitOptions)</Property> + <Property Id="LEASHLIFEMIN" Admin="yes" Secure="yes">$(var.LeashLifeMin)</Property> + <Property Id="LEASHLIFEMAX" Admin="yes" Secure="yes">$(var.LeashLifeMax)</Property> + <Property Id="LEASHRENEWMIN" Admin="yes" Secure="yes">$(var.LeashRenewMin)</Property> + <Property Id="LEASHRENEWMAX" Admin="yes" Secure="yes">$(var.LeashRenewMax)</Property> + <Property Id="LEASHUPPERCASEREALM" Admin="yes" Secure="yes">$(var.LeashUppercaseRealm)</Property> + <Property Id="LEASHTIMEHOST" Admin="yes" Secure="yes">$(var.LeashTimeHost)</Property> + <Property Id="LEASHPRESERVEKINITOPTIONS" Admin="yes" Secure="yes">$(var.LeashPreserveKinitOptions)</Property> + <Property Id="KRB4KRBREALMS" Admin="yes" Secure="yes">$(var.Krb4KrbRealms)</Property> + <Property Id="KRB4KRBCONF" Admin="yes" Secure="yes">$(var.Krb4KrbConf)</Property> + <Property Id="KRB4CONFIGDIR" Admin="yes" Secure="yes">$(var.Krb4ConfigDir)</Property> + <Property Id="KRB4TICKETFILE" Admin="yes" Secure="yes">$(var.Krb4TicketFile)</Property> + <Property Id="KRB5CONFIG" Admin="yes" Secure="yes">$(var.Krb5Config)</Property> + <Property Id="KRB5CCNAME" Admin="yes" Secure="yes">$(var.Krb5CcName)</Property> + <Property Id="KRB5PRESERVEIDENTITY" Admin="yes" Secure="yes">$(var.Krb5PreserveIdentity)</Property> +<?endif?> +<?ifdef UseLeash?> + <Property Id="USELEASH" Admin="yes" Secure="yes">$(var.UseLeash)</Property> +<?endif?> +<?ifdef UseNetIDMgr?> + <Property Id="USENETIDMGR" Admin="yes" Secure="yes">$(var.UseNetIDMgr)</Property> +<?endif?> +</Include> \ No newline at end of file diff --git a/mechglue/src/windows/installer/wix/site-local.wxi b/mechglue/src/windows/installer/wix/site-local.wxi new file mode 100644 index 000000000..03fadea8c --- /dev/null +++ b/mechglue/src/windows/installer/wix/site-local.wxi @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="utf-8"?> +<Include xmlns="http://schemas.microsoft.com/wix/2003/01/wi"> + + <!-- User configurable options --> + + <!-- TargetDir should point to build target directory and must end with + a backslash. If not specified, assume we are in TargetDir\install --> + + <?define TargetDir="c:\temp\kfw\kfw-3.0.0-beta-2\"?> + + <!-- ConfigDir should point to directory containing configuration files + (krb5.ini, krb.con, krbrealm.con) to be bundled with the installer. + The directory name should end with a backslash. --> + + <?define ConfigDir="c:\temp\kfw\kfw-2.5-extra\sample-config\"?> + + <!-- VersionMajor, VersionMinor and VersionPatch must all be specified, or + none should be specified (in which case, the defaults will be + selected below. --> + + <!-- version defs go here --> + + <!-- BuildLang is the language code for the installation. If you are + changing this, you should also change the ProductCode below. --> + <?ifndef BuildLang?> + <?define BuildLang="1033"?> + <?endif?> + + <!-- ProductCode is an uppercase GUID. Each release should have its + own ProductCode. If one is not defined, we generate a random one. --> + <?ifndef ProductCode?> + <?define ProductCode="????????-????-????-????-????????????"?> + <?endif?> + + <!-- DefaultRealm, is your default realm. Must be uppercase --> + <?define DefaultRealm="ATHENA.MIT.EDU"?> + + <!-- One of the following must be defined and must correspond to the + version of compiler used for building Kerberos for Windows --> + + <!-- <?define CL1200?> --> + <!-- <?define CL1300?> --> + <?define CL1310?> + <!-- <?define CL1400?> --> + + <!-- At most one of the following could be defined and must correspond + to the type of build performed. --> + <!-- <?define Debug?> --> + <?define Release?> + + <!-- We are including debug symbols anyway. Undefine this for a leaner + installer without debug syms. --> + <?define DebugSyms?> + + <!-- Optional defines --> + <!-- <?define Beta="2"?> Numeric Beta identifier --> + <!-- <?define OldHelp?> --> <!-- Specifies the use of the old leash32.hlp file + instead of the new leash32.chm file --> + + + <!-- End of user configurable options --> + + <!-- Assert that required options are defined, or select defaults if + they weren't --> + + <?ifndef TargetDir?> + <?define TargetDir="$(sys.SOURCEFILEDIR)..\"?> + <?endif?> + + <?ifndef ConfigDir?> + <?define ConfigDir="$(env.SystemRoot)\"?> + <?endif?> + + <?ifndef VersionMajor?> + <?define VersionMajor="3"?> + <?define VersionMinor="0"?> + <?define VersionPatch="0"?> + <?else?> + <?if Not ($(var.VersionMinor) And $(var.VersionPatch))?> + <?error VersionMajor, VersionMinor and VersionPatch should be specified together?> + <?endif?> + <?endif?> + + <?ifndef ProductCode?> + <?error Must define ProductCode?> + <?endif?> + + <?ifndef BuildLang?> + <?error Must define BuildLang?> + <?endif?> + + <!-- DefaultRealm. Must be uppercase. --> + <?ifndef DefaultRealm?> + <?error Must define DefaultRealm?> + <?endif?> + + <!-- The build makefile defines 'Date' and 'Time' which are strings that + identify the time at which the build was performed. --> +</Include> \ No newline at end of file diff --git a/mechglue/src/windows/kfwlogon/Makefile.in b/mechglue/src/windows/kfwlogon/Makefile.in new file mode 100644 index 000000000..10e7d4cfb --- /dev/null +++ b/mechglue/src/windows/kfwlogon/Makefile.in @@ -0,0 +1,37 @@ +# Makefile for the KFW Network Provider +# + +thisconfigdir=./.. +myfulldir=windows/nplogon +mydir=. +BUILDTOP=$(REL)..$(S).. +DEFINES = +LOCALINCLUDES = -I$(BUILDTOP) -I$(PISMERE)\athena\util\loadfuncs \ + -I$(PISMERE)\athena\auth\krb5\src\include\kerberosIV \ + -I$(PISMERE)\athena\auth\krb4\include \ + -I$(PISMERE)\athena\auth\leash\include +PROG_LIBPATH=-L$(TOPLIBD) -L$(KRB5_LIBDIR) + +SYSLIBS = kernel32.lib user32.lib advapi32.lib wsock32.lib secur32.lib +RFLAGS = $(LOCALINCLUDES) +RCFLAGS = $(RFLAGS) -D_WIN32 + +all-windows:: $(OUTPRE)kfwlogon.dll $(OUTPRE)kfwcpcc.exe + +$(OUTPRE)kfwlogon.res: kfwlogon.rc ..\version.rc + +$(OUTPRE)kfwcpcc.res: kfwcpcc.rc ..\version.rc + +$(OUTPRE)kfwlogon.dll: $(OUTPRE)kfwlogon.obj $(OUTPRE)kfwcommon.obj $(OUTPRE)kfwlogon.res + link $(DLL_LINKOPTS) -out:$@ $(OUTPRE)kfwlogon.obj $(OUTPRE)kfwcommon.obj -entry:DllEntryPoint -def:kfwlogon.def $(SYSLIBS) $(KLIB) $(CLIB) + +$(OUTPRE)kfwcpcc.exe: $(OUTPRE)kfwcpcc.obj $(OUTPRE)kfwcommon.obj $(OUTPRE)kfwcpcc.res + link $(EXE_LINKOPTS) -out:$@ $(OUTPRE)kfwcpcc.obj $(OUTPRE)kfwcommon.obj $(SYSLIBS) $(KLIB) $(CLIB) + +install:: + copy $(OUTPRE)kfwlogon.dll $(DESTDIR) + copy $(OUTPRE)kfwcpcc.exe $(DESTDIR) + +clean:: + $(RM) $(OUTPRE)*.exe $(OUTPRE)*.dll $(OUTPRE)*.res + diff --git a/mechglue/src/windows/kfwlogon/kfwcommon.c b/mechglue/src/windows/kfwlogon/kfwcommon.c new file mode 100644 index 000000000..251e1436b --- /dev/null +++ b/mechglue/src/windows/kfwlogon/kfwcommon.c @@ -0,0 +1,927 @@ +/* +Copyright 2005 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +#include "kfwlogon.h" +#include <winbase.h> + +#include <io.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> + +#include <winsock2.h> +#include <lm.h> +#include <nb30.h> + +/* Function Pointer Declarations for Delayed Loading */ +// CCAPI +DECL_FUNC_PTR(cc_initialize); +DECL_FUNC_PTR(cc_shutdown); +DECL_FUNC_PTR(cc_get_NC_info); +DECL_FUNC_PTR(cc_free_NC_info); + +// leash functions +DECL_FUNC_PTR(Leash_get_default_lifetime); +DECL_FUNC_PTR(Leash_get_default_forwardable); +DECL_FUNC_PTR(Leash_get_default_renew_till); +DECL_FUNC_PTR(Leash_get_default_noaddresses); +DECL_FUNC_PTR(Leash_get_default_proxiable); +DECL_FUNC_PTR(Leash_get_default_publicip); +DECL_FUNC_PTR(Leash_get_default_use_krb4); +DECL_FUNC_PTR(Leash_get_default_life_min); +DECL_FUNC_PTR(Leash_get_default_life_max); +DECL_FUNC_PTR(Leash_get_default_renew_min); +DECL_FUNC_PTR(Leash_get_default_renew_max); +DECL_FUNC_PTR(Leash_get_default_renewable); +DECL_FUNC_PTR(Leash_get_default_mslsa_import); + +// krb5 functions +DECL_FUNC_PTR(krb5_change_password); +DECL_FUNC_PTR(krb5_get_init_creds_opt_init); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable); +DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list); +DECL_FUNC_PTR(krb5_get_init_creds_password); +DECL_FUNC_PTR(krb5_build_principal_ext); +DECL_FUNC_PTR(krb5_cc_get_name); +DECL_FUNC_PTR(krb5_cc_resolve); +DECL_FUNC_PTR(krb5_cc_default); +DECL_FUNC_PTR(krb5_cc_default_name); +DECL_FUNC_PTR(krb5_cc_set_default_name); +DECL_FUNC_PTR(krb5_cc_initialize); +DECL_FUNC_PTR(krb5_cc_destroy); +DECL_FUNC_PTR(krb5_cc_close); +DECL_FUNC_PTR(krb5_cc_store_cred); +DECL_FUNC_PTR(krb5_cc_copy_creds); +DECL_FUNC_PTR(krb5_cc_retrieve_cred); +DECL_FUNC_PTR(krb5_cc_get_principal); +DECL_FUNC_PTR(krb5_cc_start_seq_get); +DECL_FUNC_PTR(krb5_cc_next_cred); +DECL_FUNC_PTR(krb5_cc_end_seq_get); +DECL_FUNC_PTR(krb5_cc_remove_cred); +DECL_FUNC_PTR(krb5_cc_set_flags); +DECL_FUNC_PTR(krb5_cc_get_type); +DECL_FUNC_PTR(krb5_free_context); +DECL_FUNC_PTR(krb5_free_cred_contents); +DECL_FUNC_PTR(krb5_free_principal); +DECL_FUNC_PTR(krb5_get_in_tkt_with_password); +DECL_FUNC_PTR(krb5_init_context); +DECL_FUNC_PTR(krb5_parse_name); +DECL_FUNC_PTR(krb5_timeofday); +DECL_FUNC_PTR(krb5_timestamp_to_sfstring); +DECL_FUNC_PTR(krb5_unparse_name); +DECL_FUNC_PTR(krb5_get_credentials); +DECL_FUNC_PTR(krb5_mk_req); +DECL_FUNC_PTR(krb5_sname_to_principal); +DECL_FUNC_PTR(krb5_get_credentials_renew); +DECL_FUNC_PTR(krb5_free_data); +DECL_FUNC_PTR(krb5_free_data_contents); +DECL_FUNC_PTR(krb5_free_unparsed_name); +DECL_FUNC_PTR(krb5_os_localaddr); +DECL_FUNC_PTR(krb5_copy_keyblock_contents); +DECL_FUNC_PTR(krb5_copy_data); +DECL_FUNC_PTR(krb5_free_creds); +DECL_FUNC_PTR(krb5_build_principal); +DECL_FUNC_PTR(krb5_get_renewed_creds); +DECL_FUNC_PTR(krb5_get_default_config_files); +DECL_FUNC_PTR(krb5_free_config_files); +DECL_FUNC_PTR(krb5_get_default_realm); +DECL_FUNC_PTR(krb5_free_default_realm); +DECL_FUNC_PTR(krb5_free_ticket); +DECL_FUNC_PTR(krb5_decode_ticket); +DECL_FUNC_PTR(krb5_get_host_realm); +DECL_FUNC_PTR(krb5_free_host_realm); +DECL_FUNC_PTR(krb5_free_addresses); +DECL_FUNC_PTR(krb5_c_random_make_octets); + +// ComErr functions +DECL_FUNC_PTR(com_err); +DECL_FUNC_PTR(error_message); + +// Profile functions +DECL_FUNC_PTR(profile_init); +DECL_FUNC_PTR(profile_release); +DECL_FUNC_PTR(profile_get_subsection_names); +DECL_FUNC_PTR(profile_free_list); +DECL_FUNC_PTR(profile_get_string); +DECL_FUNC_PTR(profile_release_string); + +// Service functions +DECL_FUNC_PTR(OpenSCManagerA); +DECL_FUNC_PTR(OpenServiceA); +DECL_FUNC_PTR(QueryServiceStatus); +DECL_FUNC_PTR(CloseServiceHandle); +DECL_FUNC_PTR(LsaNtStatusToWinError); + +// LSA Functions +DECL_FUNC_PTR(LsaConnectUntrusted); +DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +DECL_FUNC_PTR(LsaCallAuthenticationPackage); +DECL_FUNC_PTR(LsaFreeReturnBuffer); +DECL_FUNC_PTR(LsaGetLogonSessionData); + +// CCAPI +FUNC_INFO ccapi_fi[] = { + MAKE_FUNC_INFO(cc_initialize), + MAKE_FUNC_INFO(cc_shutdown), + MAKE_FUNC_INFO(cc_get_NC_info), + MAKE_FUNC_INFO(cc_free_NC_info), + END_FUNC_INFO +}; + +FUNC_INFO leash_fi[] = { + MAKE_FUNC_INFO(Leash_get_default_lifetime), + MAKE_FUNC_INFO(Leash_get_default_renew_till), + MAKE_FUNC_INFO(Leash_get_default_forwardable), + MAKE_FUNC_INFO(Leash_get_default_noaddresses), + MAKE_FUNC_INFO(Leash_get_default_proxiable), + MAKE_FUNC_INFO(Leash_get_default_publicip), + MAKE_FUNC_INFO(Leash_get_default_use_krb4), + MAKE_FUNC_INFO(Leash_get_default_life_min), + MAKE_FUNC_INFO(Leash_get_default_life_max), + MAKE_FUNC_INFO(Leash_get_default_renew_min), + MAKE_FUNC_INFO(Leash_get_default_renew_max), + MAKE_FUNC_INFO(Leash_get_default_renewable), + END_FUNC_INFO +}; + +FUNC_INFO leash_opt_fi[] = { + MAKE_FUNC_INFO(Leash_get_default_mslsa_import), + END_FUNC_INFO +}; + +FUNC_INFO k5_fi[] = { + MAKE_FUNC_INFO(krb5_change_password), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_init), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable), + MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list), + MAKE_FUNC_INFO(krb5_get_init_creds_password), + MAKE_FUNC_INFO(krb5_build_principal_ext), + MAKE_FUNC_INFO(krb5_cc_get_name), + MAKE_FUNC_INFO(krb5_cc_resolve), + MAKE_FUNC_INFO(krb5_cc_default), + MAKE_FUNC_INFO(krb5_cc_default_name), + MAKE_FUNC_INFO(krb5_cc_set_default_name), + MAKE_FUNC_INFO(krb5_cc_initialize), + MAKE_FUNC_INFO(krb5_cc_destroy), + MAKE_FUNC_INFO(krb5_cc_close), + MAKE_FUNC_INFO(krb5_cc_copy_creds), + MAKE_FUNC_INFO(krb5_cc_store_cred), + MAKE_FUNC_INFO(krb5_cc_retrieve_cred), + MAKE_FUNC_INFO(krb5_cc_get_principal), + MAKE_FUNC_INFO(krb5_cc_start_seq_get), + MAKE_FUNC_INFO(krb5_cc_next_cred), + MAKE_FUNC_INFO(krb5_cc_end_seq_get), + MAKE_FUNC_INFO(krb5_cc_remove_cred), + MAKE_FUNC_INFO(krb5_cc_set_flags), + MAKE_FUNC_INFO(krb5_cc_get_type), + MAKE_FUNC_INFO(krb5_free_context), + MAKE_FUNC_INFO(krb5_free_cred_contents), + MAKE_FUNC_INFO(krb5_free_principal), + MAKE_FUNC_INFO(krb5_get_in_tkt_with_password), + MAKE_FUNC_INFO(krb5_init_context), + MAKE_FUNC_INFO(krb5_parse_name), + MAKE_FUNC_INFO(krb5_timeofday), + MAKE_FUNC_INFO(krb5_timestamp_to_sfstring), + MAKE_FUNC_INFO(krb5_unparse_name), + MAKE_FUNC_INFO(krb5_get_credentials), + MAKE_FUNC_INFO(krb5_mk_req), + MAKE_FUNC_INFO(krb5_sname_to_principal), + MAKE_FUNC_INFO(krb5_get_credentials_renew), + MAKE_FUNC_INFO(krb5_free_data), + MAKE_FUNC_INFO(krb5_free_data_contents), + MAKE_FUNC_INFO(krb5_free_unparsed_name), + MAKE_FUNC_INFO(krb5_os_localaddr), + MAKE_FUNC_INFO(krb5_copy_keyblock_contents), + MAKE_FUNC_INFO(krb5_copy_data), + MAKE_FUNC_INFO(krb5_free_creds), + MAKE_FUNC_INFO(krb5_build_principal), + MAKE_FUNC_INFO(krb5_get_renewed_creds), + MAKE_FUNC_INFO(krb5_free_addresses), + MAKE_FUNC_INFO(krb5_get_default_config_files), + MAKE_FUNC_INFO(krb5_free_config_files), + MAKE_FUNC_INFO(krb5_get_default_realm), + MAKE_FUNC_INFO(krb5_free_default_realm), + MAKE_FUNC_INFO(krb5_free_ticket), + MAKE_FUNC_INFO(krb5_decode_ticket), + MAKE_FUNC_INFO(krb5_get_host_realm), + MAKE_FUNC_INFO(krb5_free_host_realm), + MAKE_FUNC_INFO(krb5_free_addresses), + MAKE_FUNC_INFO(krb5_c_random_make_octets), + END_FUNC_INFO +}; + +FUNC_INFO profile_fi[] = { + MAKE_FUNC_INFO(profile_init), + MAKE_FUNC_INFO(profile_release), + MAKE_FUNC_INFO(profile_get_subsection_names), + MAKE_FUNC_INFO(profile_free_list), + MAKE_FUNC_INFO(profile_get_string), + MAKE_FUNC_INFO(profile_release_string), + END_FUNC_INFO +}; + +FUNC_INFO ce_fi[] = { + MAKE_FUNC_INFO(com_err), + MAKE_FUNC_INFO(error_message), + END_FUNC_INFO +}; + +FUNC_INFO service_fi[] = { + MAKE_FUNC_INFO(OpenSCManagerA), + MAKE_FUNC_INFO(OpenServiceA), + MAKE_FUNC_INFO(QueryServiceStatus), + MAKE_FUNC_INFO(CloseServiceHandle), + MAKE_FUNC_INFO(LsaNtStatusToWinError), + END_FUNC_INFO +}; + +FUNC_INFO lsa_fi[] = { + MAKE_FUNC_INFO(LsaConnectUntrusted), + MAKE_FUNC_INFO(LsaLookupAuthenticationPackage), + MAKE_FUNC_INFO(LsaCallAuthenticationPackage), + MAKE_FUNC_INFO(LsaFreeReturnBuffer), + MAKE_FUNC_INFO(LsaGetLogonSessionData), + END_FUNC_INFO +}; + +/* Static Declarations */ +static int inited = 0; +static HINSTANCE hKrb5 = 0; +static HINSTANCE hKrb524 = 0; +static HINSTANCE hSecur32 = 0; +static HINSTANCE hAdvApi32 = 0; +static HINSTANCE hComErr = 0; +static HINSTANCE hService = 0; +static HINSTANCE hProfile = 0; +static HINSTANCE hLeash = 0; +static HINSTANCE hLeashOpt = 0; +static HINSTANCE hCCAPI = 0; + +static DWORD TraceOption = 0; +static HANDLE hDLL; + +void DebugEvent0(char *a) +{ +#ifdef DEBUG + HANDLE h; char *ptbuf[1]; + + h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); + ptbuf[0] = a; + ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL); + DeregisterEventSource(h); +#endif +} + +#define MAXBUF_ 512 +void DebugEvent(char *b,...) +{ +#ifdef DEBUG + HANDLE h; char *ptbuf[1],buf[MAXBUF_+1]; + va_list marker; + + h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); + va_start(marker,b); + StringCbVPrintf(buf, MAXBUF_+1,b,marker); + buf[MAXBUF_] = '\0'; + ptbuf[0] = buf; + ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL); + DeregisterEventSource(h); + va_end(marker); +#endif +} + +void +UnloadFuncs( + FUNC_INFO fi[], + HINSTANCE h + ) +{ + int n; + if (fi) + for (n = 0; fi[n].func_ptr_var; n++) + *(fi[n].func_ptr_var) = 0; + if (h) FreeLibrary(h); +} + +int +LoadFuncs( + const char* dll_name, + FUNC_INFO fi[], + HINSTANCE* ph, // [out, optional] - DLL handle + int* pindex, // [out, optional] - index of last func loaded (-1 if none) + int cleanup, // cleanup function pointers and unload on error + int go_on, // continue loading even if some functions cannot be loaded + int silent // do not pop-up a system dialog if DLL cannot be loaded + ) +{ + HINSTANCE h; + int i, n, last_i; + int error = 0; + UINT em; + + if (ph) *ph = 0; + if (pindex) *pindex = -1; + + for (n = 0; fi[n].func_ptr_var; n++) + *(fi[n].func_ptr_var) = 0; + + if (silent) + em = SetErrorMode(SEM_FAILCRITICALERRORS); + h = LoadLibrary(dll_name); + if (silent) + SetErrorMode(em); + + if (!h) + return 0; + + last_i = -1; + for (i = 0; (go_on || !error) && (i < n); i++) + { + void* p = (void*)GetProcAddress(h, fi[i].func_name); + if (!p) + error = 1; + else + { + last_i = i; + *(fi[i].func_ptr_var) = p; + } + } + if (pindex) *pindex = last_i; + if (error && cleanup && !go_on) { + for (i = 0; i < n; i++) { + *(fi[i].func_ptr_var) = 0; + } + FreeLibrary(h); + return 0; + } + if (ph) *ph = h; + if (error) return 0; + return 1; +} + +static HANDLE hInitMutex = NULL; +static BOOL bInit = FALSE; + +/* KFW_initialize cannot be called from DllEntryPoint */ +void +KFW_initialize(void) +{ + static int inited = 0; + + if ( !inited ) { + char mutexName[MAX_PATH]; + HANDLE hMutex = NULL; + + sprintf(mutexName, "AFS KFW Init pid=%d", getpid()); + + hMutex = CreateMutex( NULL, TRUE, mutexName ); + if ( GetLastError() == ERROR_ALREADY_EXISTS ) { + if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) { + return; + } + } + if ( !inited ) { + inited = 1; + LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); + LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); + LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); + LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); + LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); + LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0); + LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); + LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0); + } + ReleaseMutex(hMutex); + CloseHandle(hMutex); + } +} + +void +KFW_cleanup(void) +{ + if (hLeashOpt) + FreeLibrary(hLeashOpt); + if (hCCAPI) + FreeLibrary(hCCAPI); + if (hLeash) + FreeLibrary(hLeash); + if (hKrb524) + FreeLibrary(hKrb524); + if (hSecur32) + FreeLibrary(hSecur32); + if (hService) + FreeLibrary(hService); + if (hComErr) + FreeLibrary(hComErr); + if (hProfile) + FreeLibrary(hProfile); + if (hKrb5) + FreeLibrary(hKrb5); +} + + +int +KFW_is_available(void) +{ + KFW_initialize(); + if ( hKrb5 && hComErr && hService && +#ifdef USE_MS2MIT + hSecur32 && +#endif /* USE_MS2MIT */ + hProfile && hLeash && hCCAPI ) + return TRUE; + + return FALSE; +} + +/* Given a principal return an existing ccache or create one and return */ +int +KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc) +{ + krb5_context ctx; + char * pname = 0; + char * ccname = 0; + krb5_error_code code; + + if (!pkrb5_init_context) + return 0; + + if ( alt_ctx ) { + ctx = alt_ctx; + } else { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + + if ( principal ) { + code = pkrb5_unparse_name(ctx, principal, &pname); + if (code) goto cleanup; + + ccname = (char *)malloc(strlen(pname) + 5); + sprintf(ccname,"API:%s",pname); + + DebugEvent0(ccname); + code = pkrb5_cc_resolve(ctx, ccname, cc); + } else { + code = pkrb5_cc_default(ctx, cc); + if (code) goto cleanup; + } + + cleanup: + if (ccname) + free(ccname); + if (pname) + pkrb5_free_unparsed_name(ctx,pname); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + return(code); +} + + +int +KFW_kinit( krb5_context alt_ctx, + krb5_ccache alt_cc, + HWND hParent, + char *principal_name, + char *password, + krb5_deltat lifetime, + DWORD forwardable, + DWORD proxiable, + krb5_deltat renew_life, + DWORD addressless, + DWORD publicIP + ) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + char* name = 0; + krb5_creds my_creds; + krb5_get_init_creds_opt options; + krb5_address ** addrs = NULL; + int i = 0, addr_count = 0; + + if (!pkrb5_init_context) + return 0; + + pkrb5_get_init_creds_opt_init(&options); + memset(&my_creds, 0, sizeof(my_creds)); + + if (alt_ctx) + { + ctx = alt_ctx; + } + else + { + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + } + + if ( alt_cc ) { + cc = alt_cc; + } else { + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + } + + code = pkrb5_parse_name(ctx, principal_name, &me); + if (code) + goto cleanup; + + code = pkrb5_unparse_name(ctx, me, &name); + if (code) + goto cleanup; + + if (lifetime == 0) + lifetime = pLeash_get_default_lifetime(); + lifetime *= 60; + + if (renew_life > 0) + renew_life *= 60; + + if (lifetime) + pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime); + pkrb5_get_init_creds_opt_set_forwardable(&options, + forwardable ? 1 : 0); + pkrb5_get_init_creds_opt_set_proxiable(&options, + proxiable ? 1 : 0); + pkrb5_get_init_creds_opt_set_renew_life(&options, + renew_life); + if (addressless) + pkrb5_get_init_creds_opt_set_address_list(&options,NULL); + else { + if (publicIP) + { + // we are going to add the public IP address specified by the user + // to the list provided by the operating system + krb5_address ** local_addrs=NULL; + DWORD netIPAddr; + + pkrb5_os_localaddr(ctx, &local_addrs); + while ( local_addrs[i++] ); + addr_count = i + 1; + + addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *)); + if ( !addrs ) { + pkrb5_free_addresses(ctx, local_addrs); + goto cleanup; + } + memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); + i = 0; + while ( local_addrs[i] ) { + addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); + if (addrs[i] == NULL) { + pkrb5_free_addresses(ctx, local_addrs); + goto cleanup; + } + + addrs[i]->magic = local_addrs[i]->magic; + addrs[i]->addrtype = local_addrs[i]->addrtype; + addrs[i]->length = local_addrs[i]->length; + addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); + if (!addrs[i]->contents) { + pkrb5_free_addresses(ctx, local_addrs); + goto cleanup; + } + + memcpy(addrs[i]->contents,local_addrs[i]->contents, + local_addrs[i]->length); /* safe */ + i++; + } + pkrb5_free_addresses(ctx, local_addrs); + + addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); + if (addrs[i] == NULL) + goto cleanup; + + addrs[i]->magic = KV5M_ADDRESS; + addrs[i]->addrtype = AF_INET; + addrs[i]->length = 4; + addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); + if (!addrs[i]->contents) + goto cleanup; + + netIPAddr = htonl(publicIP); + memcpy(addrs[i]->contents,&netIPAddr,4); + + pkrb5_get_init_creds_opt_set_address_list(&options,addrs); + + } + } + + code = pkrb5_get_init_creds_password(ctx, + &my_creds, + me, + password, // password + NULL, // no prompter + hParent, // prompter data + 0, // start time + 0, // service name + &options); + if (code) + goto cleanup; + + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) + goto cleanup; + + code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + if (code) + goto cleanup; + + cleanup: + if ( addrs ) { + for ( i=0;i<addr_count;i++ ) { + if ( addrs[i] ) { + if ( addrs[i]->contents ) + free(addrs[i]->contents); + free(addrs[i]); + } + } + } + if (my_creds.client == me) + my_creds.client = 0; + pkrb5_free_cred_contents(ctx, &my_creds); + if (name) + pkrb5_free_unparsed_name(ctx, name); + if (me) + pkrb5_free_principal(ctx, me); + if (cc && (cc != alt_cc)) + pkrb5_cc_close(ctx, cc); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + return(code); +} + + +int +KFW_get_cred( char * username, + char * password, + int lifetime, + char ** reasonP ) +{ + krb5_context ctx = 0; + krb5_ccache cc = 0; + char * realm = 0; + krb5_principal principal = 0; + char * pname = 0; + krb5_error_code code; + + if (!pkrb5_init_context || !username || !password) + return 0; + + DebugEvent0(username); + + code = pkrb5_init_context(&ctx); + if ( code ) goto cleanup; + + code = pkrb5_get_default_realm(ctx, &realm); + + if (realm) { + pname = malloc(strlen(username) + strlen(realm) + 2); + if (!pname) + goto cleanup; + strcpy(pname, username); + strcat(pname, "@"); + strcat(pname, realm); + } else { + goto cleanup; + } + + DebugEvent0(realm); + DebugEvent0(pname); + + code = pkrb5_parse_name(ctx, pname, &principal); + if ( code ) goto cleanup; + + DebugEvent0("parsed name"); + code = KFW_get_ccache(ctx, principal, &cc); + if ( code ) goto cleanup; + + DebugEvent0("got ccache"); + if ( lifetime == 0 ) + lifetime = pLeash_get_default_lifetime(); + + if ( password[0] ) { + code = KFW_kinit( ctx, cc, HWND_DESKTOP, + pname, + password, + lifetime, + pLeash_get_default_forwardable(), + pLeash_get_default_proxiable(), + pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0, + pLeash_get_default_noaddresses(), + pLeash_get_default_publicip()); + DebugEvent0("kinit returned"); + if ( code ) goto cleanup; + } + + cleanup: + if ( pname ) + free(pname); + if ( realm ) + pkrb5_free_default_realm(ctx, realm); + if ( cc ) + pkrb5_cc_close(ctx, cc); + + if ( code && reasonP ) { + *reasonP = (char *)perror_message(code); + } + return(code); +} + +void +KFW_copy_cache_to_system_file(char * user, char * szLogonId) +{ + char filename[256]; + DWORD count; + char cachename[264] = "FILE:"; + krb5_context ctx = 0; + krb5_error_code code; + krb5_principal princ = 0; + krb5_ccache cc = 0; + krb5_ccache ncc = 0; + + if (!pkrb5_init_context) + return; + + count = GetEnvironmentVariable("TEMP", filename, sizeof(filename)); + if ( count > sizeof(filename) || count == 0 ) { + GetWindowsDirectory(filename, sizeof(filename)); + } + + DebugEvent0(filename); + if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) { + DebugEvent0("filename buffer too small"); + return; + } + + strcat(filename, "\\"); + strcat(filename, szLogonId); + + strcat(cachename, filename); + + DeleteFile(filename); + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + code = pkrb5_parse_name(ctx, user, &princ); + if (code) goto cleanup; + + code = KFW_get_ccache(ctx, princ, &cc); + if (code) goto cleanup; + + code = pkrb5_cc_resolve(ctx, cachename, &ncc); + if (code) goto cleanup; + + code = pkrb5_cc_initialize(ctx, ncc, princ); + if (code) goto cleanup; + + code = pkrb5_cc_copy_creds(ctx,cc,ncc); + + cleanup: + if ( cc ) { + pkrb5_cc_close(ctx, cc); + cc = 0; + } + if ( ncc ) { + pkrb5_cc_close(ctx, ncc); + ncc = 0; + } + if ( princ ) { + pkrb5_free_principal(ctx, princ); + princ = 0; + } + + if (ctx) + pkrb5_free_context(ctx); +} + +int +KFW_copy_system_file_to_default_cache(char * filename) +{ + char cachename[264] = "FILE:"; + krb5_context ctx = 0; + krb5_error_code code; + krb5_principal princ = 0; + krb5_ccache cc = 0; + krb5_ccache ncc = 0; + int retval = 1; + + if (!pkrb5_init_context) + return 1; + + if ( strlen(filename) + 6 > sizeof(cachename) ) + return 1; + + strcat(cachename, filename); + + code = pkrb5_init_context(&ctx); + if (code) ctx = 0; + + code = pkrb5_cc_resolve(ctx, cachename, &cc); + if (code) goto cleanup; + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + if (code) goto cleanup; + + code = pkrb5_cc_default(ctx, &ncc); + if (!code) { + code = pkrb5_cc_initialize(ctx, ncc, princ); + + if (!code) + code = pkrb5_cc_copy_creds(ctx,cc,ncc); + } + if ( ncc ) { + pkrb5_cc_close(ctx, ncc); + ncc = 0; + } + + retval=0; /* success */ + + cleanup: + if ( cc ) { + pkrb5_cc_close(ctx, cc); + cc = 0; + } + + DeleteFile(filename); + + if ( princ ) { + pkrb5_free_principal(ctx, princ); + princ = 0; + } + + if (ctx) + pkrb5_free_context(ctx); + + return 0; +} + + +int +KFW_destroy_tickets_for_principal(char * user) +{ + krb5_context ctx = 0; + krb5_error_code code; + krb5_principal princ = 0; + krb5_ccache cc = 0; + + if (!pkrb5_init_context) + return 0; + + code = pkrb5_init_context(&ctx); + if (code) ctx = 0; + + code = pkrb5_parse_name(ctx, user, &princ); + if (code) goto loop_cleanup; + + code = KFW_get_ccache(ctx, princ, &cc); + if (code) goto loop_cleanup; + + code = pkrb5_cc_destroy(ctx, cc); + if (!code) cc = 0; + + loop_cleanup: + if ( cc ) { + pkrb5_cc_close(ctx, cc); + cc = 0; + } + if ( princ ) { + pkrb5_free_principal(ctx, princ); + princ = 0; + } + + pkrb5_free_context(ctx); + return 0; +} + diff --git a/mechglue/src/windows/kfwlogon/kfwcpcc.c b/mechglue/src/windows/kfwlogon/kfwcpcc.c new file mode 100644 index 000000000..4dbace969 --- /dev/null +++ b/mechglue/src/windows/kfwlogon/kfwcpcc.c @@ -0,0 +1,39 @@ +/* + +Copyright 2005 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +#include <windows.h> +#include "kfwlogon.h" + +int main(int argc, char *argv[]) +{ + if ( argc != 2 ) + return 1; + + KFW_initialize(); + + return KFW_copy_system_file_to_default_cache(argv[1]); +} + + diff --git a/mechglue/src/windows/kfwlogon/kfwcpcc.rc b/mechglue/src/windows/kfwlogon/kfwcpcc.rc new file mode 100644 index 000000000..5b0bbf217 --- /dev/null +++ b/mechglue/src/windows/kfwlogon/kfwcpcc.rc @@ -0,0 +1,10 @@ +#include <windows.h> +#include <winver.h> +#include "patchlevel.h" + +#define K5_DESCRIPTION "Kerberos for Windows Logon Network Provider\0" +#define K5_FILETYPE VFT_APP +#define K5_INTERNAL_NAME "KFWLOGON\0" +#define K5_ORIGINAL_NAME "kfwcpcc.exe\0" + +#include "..\version.rc" diff --git a/mechglue/src/windows/kfwlogon/kfwlogon.c b/mechglue/src/windows/kfwlogon/kfwlogon.c new file mode 100644 index 000000000..eddf27341 --- /dev/null +++ b/mechglue/src/windows/kfwlogon/kfwlogon.c @@ -0,0 +1,354 @@ +/* +Copyright 2005 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +#include "kfwlogon.h" + +#include <io.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> + +#include <winsock2.h> +#include <lm.h> +#include <nb30.h> + +static HANDLE hDLL; + +static HANDLE hInitMutex = NULL; +static BOOL bInit = FALSE; + + +BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved) +{ + hDLL = dll; + switch (reason) { + case DLL_PROCESS_ATTACH: + /* Initialization Mutex */ + hInitMutex = CreateMutex(NULL, FALSE, NULL); + break; + + case DLL_PROCESS_DETACH: + CloseHandle(hInitMutex); + break; + + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + default: + /* Everything else succeeds but does nothing. */ + break; + } + + return TRUE; +} + + + +DWORD APIENTRY NPGetCaps(DWORD index) +{ + switch (index) { + case WNNC_NET_TYPE: + /* Don't have our own type; use somebody else's. */ + return WNNC_NET_SUN_PC_NFS; + + case WNNC_START: + /* Say we are already started, even though we might wait after we receive NPLogonNotify */ + return 1; + + default: + return 0; + } +} + +static BOOL +WINAPI +UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen) +{ + CPINFO CodePageInfo; + + GetCPInfo(CP_ACP, &CodePageInfo); + + if (CodePageInfo.MaxCharSize > 1) + // Only supporting non-Unicode strings + return FALSE; + + if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0') + { + // Looks like unicode, better translate it + // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS + WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2, + lpszOutputString, nOutStringLen-1, NULL, NULL); + lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0'; + return TRUE; + } + else + lpszOutputString[0] = '\0'; + return FALSE; +} // UnicodeStringToANSI + + +DWORD APIENTRY NPLogonNotify( + PLUID lpLogonId, + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + LPWSTR *lpLogonScript) +{ + char uname[MAX_USERNAME_LENGTH]=""; + char password[MAX_PASSWORD_LENGTH]=""; + char logonDomain[MAX_DOMAIN_LENGTH]=""; + char szLogonId[128] = ""; + + MSV1_0_INTERACTIVE_LOGON *IL; + + DWORD code = 0; + + char *reason; + char *ctemp; + + BOOLEAN interactive; + HWND hwndOwner = (HWND)StationHandle; + BOOLEAN lowercased_name = TRUE; + + if ( !KFW_is_available() ) + return 0; + + DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart); + + /* Initialize Logon Script to none */ + *lpLogonScript=NULL; + + /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for + * our purposes */ + + if ( wcscmp(lpAuthentInfoType,L"MSV1_0:Interactive") && + wcscmp(lpAuthentInfoType,L"Kerberos:Interactive") ) + { + char msg[64]; + WideCharToMultiByte(CP_ACP, 0, lpAuthentInfoType, 0, + msg, sizeof(msg), NULL, NULL); + msg[sizeof(msg)-1]='\0'; + DebugEvent("NPLogonNotify - Unsupported Authentication Info Type: %s", msg); + return 0; + } + + IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo; + + /* Are we interactive? */ + interactive = (wcscmp(lpStationName, L"WinSta0") == 0); + + /* Convert from Unicode to ANSI */ + + /*TODO: Use SecureZeroMemory to erase passwords */ + UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH); + UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH); + UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH); + + /* Make sure AD-DOMAINS sent from login that is sent to us is stripped */ + ctemp = strchr(uname, '@'); + if (ctemp) *ctemp = 0; + + /* is the name all lowercase? */ + for ( ctemp = uname; *ctemp ; ctemp++) { + if ( !islower(*ctemp) ) { + lowercased_name = FALSE; + break; + } + } + + code = KFW_get_cred(uname, password, 0, &reason); + DebugEvent("NPLogonNotify - KFW_get_cred uname=[%s] code=[%d]",uname, code); + + /* remove any kerberos 5 tickets currently held by the SYSTEM account + * for this user + */ + if (!code) { + sprintf(szLogonId,"kfwlogon-%d.%d",lpLogonId->HighPart, lpLogonId->LowPart); + KFW_copy_cache_to_system_file(uname, szLogonId); + } + + KFW_destroy_tickets_for_principal(uname); + + if (code) { + char msg[128]; + HANDLE h; + char *ptbuf[1]; + + StringCbPrintf(msg, sizeof(msg), "Kerberos ticket acquisition failed: %s", reason); + + h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME); + ptbuf[0] = msg; + ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL, + 1, 0, ptbuf, NULL); + DeregisterEventSource(h); + SetLastError(code); + } + + if (code) + DebugEvent0("NPLogonNotify failure"); + else + DebugEvent0("NPLogonNotify success"); + + return code; +} + + +DWORD APIENTRY NPPasswordChangeNotify( + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + DWORD dwChangeInfo) +{ + return 0; +} + +#include <userenv.h> +#include <Winwlx.h> + +#ifdef COMMENT +typedef struct _WLX_NOTIFICATION_INFO { + ULONG Size; + ULONG Flags; + PWSTR UserName; + PWSTR Domain; + PWSTR WindowStation; + HANDLE hToken; + HDESK hDesktop; + PFNMSGECALLBACK pStatusCallback; +} WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO; +#endif + +VOID KFW_Startup_Event( PWLX_NOTIFICATION_INFO pInfo ) +{ + DebugEvent0("KFW_Startup_Event"); +} + +static BOOL +GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; +#if 0 + HANDLE TokenHandle; +#endif + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData) + return FALSE; + *ppSessionData = NULL; + +#if 0 + Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); + if ( !Success ) + return FALSE; +#endif + + Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); +#if 0 + CloseHandle( TokenHandle ); +#endif + if ( !Success ) + return FALSE; + + Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); + if ( FAILED(Status) || !ppSessionData ) + return FALSE; + + return TRUE; +} + +VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo ) +{ + WCHAR szUserW[128] = L""; + char szUserA[128] = ""; + char szPath[MAX_PATH] = ""; + char szLogonId[128] = ""; + DWORD count; + char filename[256]; + char commandline[512]; + STARTUPINFO startupinfo; + PROCESS_INFORMATION procinfo; + + LUID LogonId = {0, 0}; + PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL; + + HKEY hKey1 = NULL, hKey2 = NULL; + + DebugEvent0("KFW_Logon_Event - Start"); + + GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData ); + + if ( pLogonSessionData ) { + LogonId = pLogonSessionData->LogonId; + DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart); + + sprintf(szLogonId,"kfwlogon-%d.%d",LogonId.HighPart, LogonId.LowPart); + LsaFreeReturnBuffer( pLogonSessionData ); + } else { + DebugEvent0("KFW_Logon_Event - Unable to determine LogonId"); + return; + } + + count = GetEnvironmentVariable("TEMP", filename, sizeof(filename)); + if ( count > sizeof(filename) || count == 0 ) { + GetWindowsDirectory(filename, sizeof(filename)); + } + + if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) { + strcat(filename, "\\"); + strcat(filename, szLogonId); + + sprintf(commandline, "kfwcpcc.exe \"%s\"", filename); + + GetStartupInfo(&startupinfo); + if (CreateProcessAsUser( pInfo->hToken, + "kfwcpcc.exe", + commandline, + NULL, + NULL, + FALSE, + CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, + NULL, + NULL, + &startupinfo, + &procinfo)) + { + WaitForSingleObject(procinfo.hProcess, 30000); + + CloseHandle(procinfo.hThread); + CloseHandle(procinfo.hProcess); + } + } + + DeleteFile(filename); + + DebugEvent0("KFW_Logon_Event - End"); +} + diff --git a/mechglue/src/windows/kfwlogon/kfwlogon.def b/mechglue/src/windows/kfwlogon/kfwlogon.def new file mode 100644 index 000000000..52af99090 --- /dev/null +++ b/mechglue/src/windows/kfwlogon/kfwlogon.def @@ -0,0 +1,12 @@ +LIBRARY KFWLOGON + +EXPORTS + + DllEntryPoint + NPGetCaps + NPLogonNotify + NPPasswordChangeNotify + KFW_Logon_Event + + + diff --git a/mechglue/src/windows/kfwlogon/kfwlogon.h b/mechglue/src/windows/kfwlogon/kfwlogon.h new file mode 100644 index 000000000..34c8cc70c --- /dev/null +++ b/mechglue/src/windows/kfwlogon/kfwlogon.h @@ -0,0 +1,200 @@ +/* + +Copyright 2005 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +/* We only support VC 1200 and above anyway */ +#pragma once + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + +#include <windows.h> +#include <npapi.h> +#define SECURITY_WIN32 +#include <security.h> +#include <ntsecapi.h> +#include <tchar.h> +#include <strsafe.h> + +typedef int errcode_t; + +#include <loadfuncs-lsa.h> +#include <krb5.h> +#include <loadfuncs-com_err.h> +#include <loadfuncs-krb5.h> +#include <loadfuncs-profile.h> +#include <loadfuncs-leash.h> + +// service definitions +#define SERVICE_DLL "advapi32.dll" +typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); +typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); +typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); +typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); + +/* In order to avoid including the private CCAPI headers */ +typedef int cc_int32; + +#define CC_API_VER_1 1 +#define CC_API_VER_2 2 + +#define CCACHE_API cc_int32 + +/* +** The Official Error Codes +*/ +#define CC_NOERROR 0 +#define CC_BADNAME 1 +#define CC_NOTFOUND 2 +#define CC_END 3 +#define CC_IO 4 +#define CC_WRITE 5 +#define CC_NOMEM 6 +#define CC_FORMAT 7 +#define CC_LOCKED 8 +#define CC_BAD_API_VERSION 9 +#define CC_NO_EXIST 10 +#define CC_NOT_SUPP 11 +#define CC_BAD_PARM 12 +#define CC_ERR_CACHE_ATTACH 13 +#define CC_ERR_CACHE_RELEASE 14 +#define CC_ERR_CACHE_FULL 15 +#define CC_ERR_CRED_VERSION 16 + +enum { + CC_CRED_VUNKNOWN = 0, // For validation + CC_CRED_V4 = 1, + CC_CRED_V5 = 2, + CC_CRED_VMAX = 3 // For validation +}; + +typedef struct opaque_dll_control_block_type* apiCB; +typedef struct _infoNC { + char* name; + char* principal; + cc_int32 vers; +} infoNC; + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_initialize, + ( + apiCB** cc_ctx, // < DLL's primary control structure. + // returned here, passed everywhere else + cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) + cc_int32* api_supported, // < if ~NULL, max ver supported by DLL + const char** vendor // < if ~NULL, vendor name in read only C string + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_shutdown, + ( + apiCB** cc_ctx // <> DLL's primary control structure. NULL after + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_get_NC_info, + ( + apiCB* cc_ctx, // > DLL's primary control structure + struct _infoNC*** ppNCi // < (NULL before call) null terminated, + // list of a structs (free via cc_free_infoNC()) + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_free_NC_info, + ( + apiCB* cc_ctx, + struct _infoNC*** ppNCi // < free list of structs returned by + // cc_get_cache_names(). set to NULL on return + ) +); +/* End private ccapiv2 headers */ + +#define CCAPI_DLL "krbcc32.dll" + + +/* */ +#define MAX_USERNAME_LENGTH 256 +#define MAX_PASSWORD_LENGTH 256 +#define MAX_DOMAIN_LENGTH 256 + +#define KFW_LOGON_EVENT_NAME TEXT("KFW Logon") + +BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved); + +DWORD APIENTRY NPGetCaps(DWORD index); + +DWORD APIENTRY NPLogonNotify( + PLUID lpLogonId, + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + LPWSTR *lpLogonScript); + +DWORD APIENTRY NPPasswordChangeNotify( + LPCWSTR lpAuthentInfoType, + LPVOID lpAuthentInfo, + LPCWSTR lpPreviousAuthentInfoType, + LPVOID lpPreviousAuthentInfo, + LPWSTR lpStationName, + LPVOID StationHandle, + DWORD dwChangeInfo); + +#ifdef __cplusplus +extern "C" { +#endif + +void UnloadFuncs(FUNC_INFO [], HINSTANCE); + +int LoadFuncs(const char*, FUNC_INFO [], HINSTANCE*, int*, int, int, int); + +void DebugEvent0(char *a); +void DebugEvent(char *b,...); + +DWORD MapAuthError(DWORD code); + +static BOOL WINAPI UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen); + +int KFW_is_available(void); +int KFW_get_cred( char * username, char * password, int lifetime, char ** reasonP ); +void KFW_copy_cache_to_system_file(char * user, char * szLogonId); +int KFW_destroy_tickets_for_principal(char * user); + +#ifdef __cplusplus +} +#endif diff --git a/mechglue/src/windows/kfwlogon/kfwlogon.rc b/mechglue/src/windows/kfwlogon/kfwlogon.rc new file mode 100644 index 000000000..1a3cb15ee --- /dev/null +++ b/mechglue/src/windows/kfwlogon/kfwlogon.rc @@ -0,0 +1,10 @@ +#include <windows.h> +#include <winver.h> +#include "patchlevel.h" + +#define K5_DESCRIPTION "Kerberos for Windows Logon Network Provider\0" +#define K5_FILETYPE VFT_DLL +#define K5_INTERNAL_NAME "KFWLOGON\0" +#define K5_ORIGINAL_NAME "kfwlogon.dll\0" + +#include "..\version.rc" diff --git a/mechglue/src/windows/lib/ChangeLog b/mechglue/src/windows/lib/ChangeLog new file mode 100644 index 000000000..572f13f3c --- /dev/null +++ b/mechglue/src/windows/lib/ChangeLog @@ -0,0 +1,53 @@ +2001-10-03 Ken Raeburn <raeburn@mit.edu> + + * cacheapi.h: Don't declare pointers FAR any more, nor functions + NEAR. + +2000-04-18 Danilo Almeida <dalmeida@mit.edu> + + * cacheapi.h: Update to v2. + +1999-12-03 Danilo Almeida <dalmeida@mit.edu> + + * Makefile.in: Fix of build flags with updated win-pre.in. + +Mon May 17 14:26:27 1999 Danilo Almeida <dalmeida@mit.edu> + + * Makefile.in: Uncomment BUILDTOP since we always want it. + +Mon May 17 09:22:45 1999 Danilo Almeida <dalmeida@mit.edu> + + * KrbCC32.lib: Remove KrbCC32.lib since we dynamically load the DLL. + +Mon May 10 15:28:40 1999 Danilo Almeida <dalmeida@mit.edu> + + * Makefile.in: Do win32 build in subdir. + +1999-04-01 Theodore Ts'o <tytso@rsts-11.mit.edu> + + * gic.c (gic_prompter), vardlg.c (vardlg_build), gic.h, vardlg.h: + Update to use new prompter prototype which takes an extra + argument for the window titlebar name. (From Frank + Cusack) [krb5-kdc/662] + +Fri Mar 12 15:54:17 1999 Theodore Y. Ts'o <tytso@mit.edu> + + * Makefile.in (clean-windows): Don't blow away Krbcc32.lib by + accident. + +Tue Mar 18 12:08:50 1997 Michael Graff <explorer@flame.org> + + * registry.h, registry.c: add. + +Thu Mar 13 20:17:12 1997 Michael Graff <explorer@flame.org> + + * gic.c, gic.h, vardlg.c, vardlg.h: Finish up the variable dialog box + code. + +Thu Mar 6 21:45:05 1997 Michael Graff <explorer@flame.org> + + * gic.c, gic.h: Added to start using get_init_creds. + + * vardlg.c, vardlg.h: on-the-fly variable dialog building functions. + + diff --git a/mechglue/src/windows/lib/Makefile.in b/mechglue/src/windows/lib/Makefile.in new file mode 100644 index 000000000..c911de701 --- /dev/null +++ b/mechglue/src/windows/lib/Makefile.in @@ -0,0 +1,17 @@ +BUILDTOP = ..\.. + +lib-windows: $(OUTPRE)libwin.lib + +SRCS= vardlg.c gic.c registry.c + +OBJS= $(OUTPRE)vardlg.obj $(OUTPRE)gic.obj $(OUTPRE)registry.obj + +$(OUTPRE)libwin.lib: $(OBJS) + lib /nologo /out:$*.lib $(OBJS) + +all-windows:: lib-windows + +clean-windows:: + $(RM) $(OUTPRE)*.exp $(OUTPRE)*.map $(OUTPRE)libwin.lib $(OUTPRE)*.obj + +install-windows:: diff --git a/mechglue/src/windows/lib/cacheapi.h b/mechglue/src/windows/lib/cacheapi.h new file mode 100644 index 000000000..722eb7e54 --- /dev/null +++ b/mechglue/src/windows/lib/cacheapi.h @@ -0,0 +1,458 @@ +/* + * $Id$ + * + * Copyright 1997 by the Regents of the University of Michigan + * + * This software is being provided to you, the LICENSEE, by the + * Regents of the University of Michigan (UM) under the following + * license. By obtaining, using and/or copying this software, you agree + * that you have read, understood, and will comply with these terms and + * conditions: + * + * Permission to use, copy, modify and distribute this software and its + * documentation for any purpose and without fee or royalty is hereby + * granted, provided that you agree to comply with the following copyright + * notice and statements, including the disclaimer, and that the same + * appear on ALL copies of the software and documentation, including + * modifications that you make for internal use or for distribution: + * + * Copyright 1997 by the Regents of the University of Michigan. + * All rights reserved. + * + * THIS SOFTWARE IS PROVIDED "AS IS", AND UM MAKES NO REPRESENTATIONS + * OR WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not + * limitation, UM MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY + * OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED + * SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, + * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + * + * The name of the University of Michigan or UM may NOT be used in + * advertising or publicity pertaining to distribution of the software. + * Title to copyright in this software and any associated documentation + * shall at all times remain with UM, and USER agrees to preserve same. + * + * The University of Michigan + * c/o Steve Rothwell <sgr@umich.edu> + * 535 W. William Street + * Ann Arbor, Michigan 48013-4943 + * U.S.A. + */ + +/* +** CacheAPI.h +** +** The externally visible functions and data structures +** for the Kerberos Common Cache DLL +** This should be the ONLY externally visible file. +** This is ALL anyone should need to call the API. +** +** +*/ + +#ifndef Krb_CCacheAPI_h_ +#define Krb_CCacheAPI_h_ + +#include <windows.h> + +//typedef int cc_int32; +#define cc_int32 long +#define cc_uint32 unsigned long + +typedef cc_int32 cc_time_t; + +#define CC_API_VER_1 1 +#define CC_API_VER_2 2 + +//enum { +// CC_API_VER_1 = 1, +// CC_API_VER_2 = 2 +//}; + +#define CCACHE_API __declspec(dllexport) cc_int32 + +/* +** The Official Error Codes +*/ +#define CC_NOERROR 0 +#define CC_BADNAME 1 +#define CC_NOTFOUND 2 +#define CC_END 3 +#define CC_IO 4 +#define CC_WRITE 5 +#define CC_NOMEM 6 +#define CC_FORMAT 7 +#define CC_LOCKED 8 +#define CC_BAD_API_VERSION 9 +#define CC_NO_EXIST 10 +#define CC_NOT_SUPP 11 +#define CC_BAD_PARM 12 +#define CC_ERR_CACHE_ATTACH 13 +#define CC_ERR_CACHE_RELEASE 14 +#define CC_ERR_CACHE_FULL 15 +#define CC_ERR_CRED_VERSION 16 + + +/* +** types, structs, & constants +*/ +// Flag bits promised by Ted "RSN" +#define CC_FLAGS_RESERVED 0xFFFFFFFF + +typedef cc_uint32 cc_nc_flags; // set via constants above + +typedef struct opaque_dll_control_block_type* apiCB; +typedef struct opaque_ccache_pointer_type* ccache_p; +typedef struct opaque_credential_iterator_type* ccache_cit; + +#if 0 +enum _cc_data_type { + type_ticket = 0, /* 0 for ticket, second_ticket */ + /* Ted's draft spec says these are to be + "as defined in the Kerberos V5 protocol" + all I can find are typdefs, + can't find an enumerated type or #define + */ + type_address, /* = <"as defined in the Kerberos V5 protocol"> */ + type_authdata, /* = <"as defined in the Kerberos V5 protocol"> */ + type_encryption, /* = <"as defined in the Kerberos V5 protocol"> */ + cc_data_type_max /* for validation */ +}; +#endif + +typedef struct _cc_data +{ + cc_uint32 type; // should be one of _cc_data_type + cc_uint32 length; + unsigned char* data; // the proverbial bag-o-bits +} cc_data; + +// V5 Credentials +typedef struct _cc_creds { + char* client; + char* server; + cc_data keyblock; + cc_time_t authtime; + cc_time_t starttime; + cc_time_t endtime; + cc_time_t renew_till; + cc_uint32 is_skey; + cc_uint32 ticket_flags; + cc_data ** addresses; + cc_data ticket; + cc_data second_ticket; + cc_data ** authdata; +} cc_creds; + + +// begin V4 stuff +// use an enumerated type so all callers infer the same meaning +// these values are what krbv4win uses internally. +#define STK_AFS 0 +#define STK_DES 1 + +// K4 uses a MAX_KTXT_LEN of 1250 to hold a ticket +// K95 uses 256 +// To be safe I'll use the larger number, but a factor of 5!!! +#define MAX_V4_CRED_LEN 1250 + +// V4 Credentials + +enum { + KRB_NAME_SZ = 40, + KRB_INSTANCE_SZ = 40, + KRB_REALM_SZ = 40 +}; + +typedef struct cc_V4credential { + unsigned char kversion; + char principal[KRB_NAME_SZ + 1]; + char principal_instance[KRB_INSTANCE_SZ + 1]; + char service[KRB_NAME_SZ + 1]; + char service_instance[KRB_INSTANCE_SZ + 1]; + char realm[KRB_REALM_SZ + 1]; + unsigned char session_key[8]; + cc_int32 kvno; // k95 used BYTE skvno + cc_int32 str_to_key; // k4 infers dynamically, k95 stores + long issue_date; // k95 called this issue_time + cc_int32 lifetime; // k95 used LONG expiration_time + cc_uint32 address; // IP Address of local host + cc_int32 ticket_sz; // k95 used BYTE, k4 ktext uses int to hold up to 1250 + unsigned char ticket[MAX_V4_CRED_LEN]; + unsigned long oops; // zero to catch runaways +} V4Cred_type; + +enum { + CC_CRED_VUNKNOWN = 0, // For validation + CC_CRED_V4 = 1, + CC_CRED_V5 = 2, + CC_CRED_VMAX = 3 // For validation +}; + +typedef union cred_ptr_union_type { + V4Cred_type* pV4Cred; + cc_creds* pV5Cred; +} cred_ptr_union; + +typedef struct cred_union_type { + cc_int32 cred_type; + cred_ptr_union cred; +} cred_union; + +typedef struct _infoNC { + char* name; + char* principal; + cc_int32 vers; +} infoNC; + + +/* +** The official (externally visible) API +*/ + +#ifdef __cplusplus +extern "C" /* this entire list of functions */ +{ +#endif /* __cplusplus */ + +/* +** Main cache routines : initialize, shutdown, get_cache_names, & get_change_time +*/ +CCACHE_API +cc_initialize( + apiCB** cc_ctx, // < DLL's primary control structure. + // returned here, passed everywhere else + cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) + cc_int32* api_supported, // < if ~NULL, max ver supported by DLL + const char** vendor // < if ~NULL, vendor name in read only C string + ); + +CCACHE_API +cc_shutdown( + apiCB** cc_ctx // <> DLL's primary control structure. NULL after call. + ); + +CCACHE_API +cc_get_change_time( + apiCB* cc_ctx, // > DLL's primary control structure + cc_time_t* time // < time of last change to main cache + ); + + +/* +** Named Cache (NC) routines +** create, open, close, destroy, get_principal, get_cred_version, & +** lock_request +** +** Multiple NCs are allowed within the main cache. Each has a Name +** and kerberos version # (V4 or V5). Caller gets "ccache_ptr"s for +** NCs. +*/ +CCACHE_API +cc_create( + apiCB* cc_ctx, // > DLL's primary control structure + const char* name, // > name of cache to be [destroyed if exists, then] created + const char* principal, + cc_int32 vers, // > ticket version (CC_CRED_V4 or CC_CRED_V5) + cc_uint32 cc_flags, // > options + ccache_p** ccache_ptr // < NC control structure + ); + +CCACHE_API +cc_open( + apiCB* cc_ctx, // > DLL's primary control structure + const char* name, // > name of pre-created cache + cc_int32 vers, // > ticket version (CC_CRED_V4 or CC_CRED_V5) + cc_uint32 cc_flags, // > options + ccache_p** ccache_ptr // < NC control structure + ); + +CCACHE_API +cc_close( + apiCB* cc_ctx, // > DLL's primary control structure + ccache_p** ccache_ptr // <> NC control structure. NULL after call. + ); + +CCACHE_API +cc_destroy( + apiCB* cc_ctx, // > DLL's primary control structure + ccache_p** ccache_ptr // <> NC control structure. NULL after call. + ); + +/* +** Ways to get information about the NCs +*/ + +CCACHE_API +cc_seq_fetch_NCs_begin( + apiCB* cc_ctx, + ccache_cit** itNCs + ); + +CCACHE_API +cc_seq_fetch_NCs_end( + apiCB* cc_ctx, + ccache_cit** itNCs + ); + +CCACHE_API +cc_seq_fetch_NCs_next( + apiCB* cc_ctx, + ccache_p** ccache_ptr, + ccache_cit* itNCs + ); + +CCACHE_API +cc_seq_fetch_NCs( + apiCB* cc_ctx, // > DLL's primary control structure + ccache_p** ccache_ptr, // < NC control structure (free via cc_close()) + ccache_cit** itNCs // <> iterator used by DLL, + // set to NULL before first call + // returned NULL at CC_END + ); + +CCACHE_API +cc_get_NC_info( + apiCB* cc_ctx, // > DLL's primary control structure + struct _infoNC*** ppNCi // < (NULL before call) null terminated, + // list of a structs (free via cc_free_infoNC()) + ); + +CCACHE_API +cc_free_NC_info( + apiCB* cc_ctx, + struct _infoNC*** ppNCi // < free list of structs returned by + // cc_get_cache_names(). set to NULL on return + ); + +/* +** Functions that provide distinguishing characteristics of NCs. +*/ + +CCACHE_API +cc_get_name( + apiCB* cc_ctx, // > DLL's primary control structure + const ccache_p* ccache_ptr, // > NC control structure + char** name // < name of NC associated with ccache_ptr + // (free via cc_free_name()) + ); + +CCACHE_API +cc_set_principal( + apiCB* cc_ctx, // > DLL's primary control structure + const ccache_p* ccache_pointer, // > NC control structure + const cc_int32 vers, + const char* principal // > name of principal associated with NC + // Free via cc_free_principal() + ); + +CCACHE_API +cc_get_principal( + apiCB* cc_ctx, // > DLL's primary control structure + const ccache_p* ccache_pointer, // > NC control structure + char** principal // < name of principal associated with NC + // Free via cc_free_principal() + ); + +CCACHE_API +cc_get_cred_version( + apiCB* cc_ctx, // > DLL's primary control structure + const ccache_p* ccache_ptr, // > NC control structure + cc_int32* vers // < ticket version associated with NC + ); + +#define CC_LOCK_UNLOCK 1 +#define CC_LOCK_READER 2 +#define CC_LOCK_WRITER 3 +#define CC_LOCK_NOBLOCK 16 + +CCACHE_API +cc_lock_request( + apiCB* cc_ctx, // > DLL's primary control structure + const ccache_p* ccache_ptr, // > NC control structure + const cc_int32 lock_type // > one (or combination) of above defined + // lock types + ); + + +/* +** Credentials routines (work within an NC) +** store, remove_cred, seq_fetch_creds +*/ +CCACHE_API +cc_store( + apiCB* cc_ctx, // > DLL's primary control structure + ccache_p* ccache_ptr, // > NC control structure + const cred_union creds // > credentials to be copied into NC + ); + +CCACHE_API +cc_remove_cred( + apiCB* cc_ctx, // > DLL's primary control structure + ccache_p* ccache_ptr, // > NC control structure + const cred_union cred // > credentials to remove from NC + ); + +CCACHE_API +cc_seq_fetch_creds( + apiCB* cc_ctx, // > DLL's primary control structure + const ccache_p* ccache_ptr, // > NC control structure + cred_union** creds, // < filled in by DLL, free via cc_free_creds() + ccache_cit** itCreds // <> iterator used by DLL, set to NULL + // before first call -- Also NULL for final + // call if loop ends before CC_END + ); + +CCACHE_API +cc_seq_fetch_creds_begin( + apiCB* cc_ctx, + const ccache_p* ccache_ptr, + ccache_cit** itCreds + ); + +CCACHE_API +cc_seq_fetch_creds_end( + apiCB* cc_ctx, + ccache_cit** itCreds + ); + +CCACHE_API +cc_seq_fetch_creds_next( + apiCB* cc_ctx, + cred_union** cred, + ccache_cit* itCreds + ); + +/* +** methods of liberation, +** or freeing space via the free that goes with the malloc used to get it +** It's important to use the free carried in the DLL, not the one supplied +** by your compiler vendor. +** +** freeing a NULL pointer is not treated as an error +*/ +CCACHE_API +cc_free_principal( + apiCB* cc_ctx, // > DLL's primary control structure + char** principal // <> ptr to principal to be freed, returned as NULL + // (from cc_get_principal()) + ); + +CCACHE_API +cc_free_name( + apiCB* cc_ctx, // > DLL's primary control structure + char** name // <> ptr to name to be freed, returned as NULL + // (from cc_get_name()) + ); + +CCACHE_API +cc_free_creds( + apiCB* cc_ctx, // > DLL's primary control structure + cred_union** pCred // <> cred (from cc_seq_fetch_creds()) to be freed + // Returned as NULL. + ); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif /* __cplusplus */ + +#endif /* Krb_CCacheAPI_h_ */ diff --git a/mechglue/src/windows/lib/gic.c b/mechglue/src/windows/lib/gic.c new file mode 100644 index 000000000..51e752dc0 --- /dev/null +++ b/mechglue/src/windows/lib/gic.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 1997 Cygnus Solutions. + * + * Author: Michael Graff + */ + +#include <windows.h> +#include <windowsx.h> + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "krb5.h" + +#include "vardlg.h" +#include "gic.h" + +/* + * Steps performed: + * + * 1) Create the dialog with all the windows we will need + * later. This is done by calling vardlg_build() from + * gic_prompter(). + * + * 2) Run the dialog from within gic_prompter(). If the return + * value of the dialog is -1 or IDCANCEL, return an error. + * Otherwise, return success. + * + * 3) From within the dialog initialization code, call + * vardlg_config(), which will: + * + * a) Set all the label strings in all the entry labels and + * the banner. + * + * b) Set the maximum input lengths on the entry fields. + * + * c) Calculate the size of the text used within the banner. + * + * d) Calculate the longest string of text used as a label. + * + * e) Resize each label and each entry within the dialog + * to "look nice." + * + * f) Place the OK and perhaps the Cancel buttons at the bottom + * of the dialog. + * + * 4) When the OK button is clicked, copy all the values from the + * input fields and store them in the pointers we are given. + * Also, set the actual lengths to what we collected from the + * entries. Finally, call EndDialog(IDOK) to end the dialog. + */ + +/* + * Yes, a global. It is a PITA to not use them in windows. + */ +gic_data *gd; + + +/* + * initialize the dialog + */ +static BOOL +gic_dialog_init(HWND hwnd, HWND hwndFocus, LPARAM lParam) +{ + vardlg_config(hwnd, gd->width, gd->banner, gd->num_prompts, + gd->prompts, (WORD)(gd->id)); + + return FALSE; +} + +/* + * process dialog "commands" + */ +static void +gic_dialog_command(HWND hwnd, int cid, HWND hwndCtl, UINT codeNotify) +{ + + int n; + WORD id; + + /* + * We are only interested in button clicks, and then only of + * type IDOK or IDCANCEL. + */ + if (codeNotify != BN_CLICKED) + return; + if (cid != IDOK && cid != IDCANCEL) + return; + + /* + * If we are canceled, wipe all the fields and return IDCANCEL. + */ + if (cid == IDCANCEL) { + EndDialog(hwnd, IDCANCEL); + return; + } + + /* + * must be IDOK... + */ + id = (gd->id + 2); + for (n = 0 ; n < gd->num_prompts ; n++) { + Edit_GetText(GetDlgItem(hwnd, id), gd->prompts[n].reply->data, + gd->prompts[n].reply->length); + gd->prompts[n].reply->length = strlen(gd->prompts[n].reply->data); + id += 2; + } + + EndDialog(hwnd, IDOK); +} + +/* + * The dialog callback. + */ +static BOOL CALLBACK +gic_dialog(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + HANDLE_MSG(hwnd, WM_INITDIALOG, gic_dialog_init); + + HANDLE_MSG(hwnd, WM_COMMAND, gic_dialog_command); + } + + return FALSE; +} + + +/* + * All the disgusting code to use the get_init_creds() functions in a + * broken environment + */ +krb5_error_code KRB5_CALLCONV +gic_prompter(krb5_context ctx, void *data, const char *name, + const char *banner, int num_prompts, krb5_prompt prompts[]) +{ + int rc; + void *dlg; + + gd = data; + + gd->banner = banner; + gd->num_prompts = num_prompts; + gd->prompts = prompts; + if (gd->width == 0) + gd->width = 450; + + dlg = vardlg_build((WORD)(gd->width), name, gd->banner, + (WORD)num_prompts, prompts, (WORD)(gd->id)); + + rc = DialogBoxIndirect(gd->hinstance, (LPDLGTEMPLATE)dlg, gd->hwnd, gic_dialog); + + if (rc != IDOK) + return 1; + + return 0; +} diff --git a/mechglue/src/windows/lib/gic.h b/mechglue/src/windows/lib/gic.h new file mode 100644 index 000000000..23213163d --- /dev/null +++ b/mechglue/src/windows/lib/gic.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 1997 Cygnus Solutions + * + * Author: Michael Graff + */ + +#ifndef _WINDOWS_LIB_GIC_H +#define _WINDOWS_LIB_GIC_H + +#include <windows.h> +#include <windowsx.h> + +#include "krb5.h" + +typedef struct { + HINSTANCE hinstance; /* application instance */ + HWND hwnd; /* parent window */ + WORD id; /* starting ID */ + WORD width; /* max width of the dialog box */ + const char *banner; /* the banner */ + WORD num_prompts; /* the number of prompts we were passed */ + krb5_prompt *prompts; /* the prompts themselves */ +} gic_data; + +krb5_error_code KRB5_CALLCONV gic_prompter(krb5_context, void *, const char *, + const char *, int, krb5_prompt []); + +#endif /* _WINDOWS_LIB_GIC_H */ diff --git a/mechglue/src/windows/lib/registry.c b/mechglue/src/windows/lib/registry.c new file mode 100644 index 000000000..7dfbb5bff --- /dev/null +++ b/mechglue/src/windows/lib/registry.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 1997 Cygnus Solutions + * + * Author: Michael Graff + */ + +#include <windows.h> +#include <windowsx.h> + +#include "registry.h" + +HKEY +registry_open(HKEY hkey, char *base, REGSAM sam) +{ + HKEY k = INVALID_HANDLE_VALUE; + DWORD err; + + /* + * if the base path is null, return the already open key in hkey + */ + if (base == NULL) + return hkey; + + err = RegOpenKeyEx(hkey, base, 0, sam, &hkey); + if (err != ERROR_SUCCESS) + return INVALID_HANDLE_VALUE; + + return hkey; +} + +void +registry_close(HKEY hkey) +{ + CloseHandle(hkey); +} + +HKEY +registry_key_create(HKEY hkey, char *sub, REGSAM sam) +{ + HKEY key; + DWORD err; + DWORD disp; + + err = RegCreateKeyEx(hkey, sub, 0, 0, REG_OPTION_NON_VOLATILE, sam, + NULL, &key, &disp); + if (err != ERROR_SUCCESS) + return INVALID_HANDLE_VALUE; + + return key; +} + +int +registry_key_delete(HKEY hkey, char *sub) +{ + DWORD err; + + err = RegDeleteKey(hkey, sub); + if (err != ERROR_SUCCESS) + return -1; + + return 0; +} + +int +registry_string_get(HKEY hkey, char *sub, char **val) +{ + DWORD err; + DWORD type; + DWORD datasize; + + err = RegQueryValueEx(hkey, sub, 0, &type, 0, &datasize); + if (err != ERROR_SUCCESS || type != REG_SZ) { + *val = NULL; + return -1; + } + + *val = malloc(datasize); + if (*val == NULL) + return -1; + + err = RegQueryValueEx(hkey, sub, 0, &type, *val, &datasize); + if (err != ERROR_SUCCESS) { + free(*val); + *val = NULL; + return -1; + } + + return 0; +} + +int +registry_dword_get(HKEY hkey, char *sub, DWORD *val) +{ + DWORD err; + DWORD type; + DWORD datasize; + + err = RegQueryValueEx(hkey, sub, 0, &type, 0, &datasize); + if (err != ERROR_SUCCESS || type != REG_DWORD) { + *val = 0; + return -1; + } + + err = RegQueryValueEx(hkey, sub, 0, &type, (BYTE *)val, &datasize); + if (err != ERROR_SUCCESS) { + *val = 0; + return -1; + } + + return 0; +} + +int +registry_string_set(HKEY hkey, char *sub, char *x) +{ + DWORD err; + + err = RegSetValueEx(hkey, sub, 0, REG_SZ, (BYTE *)x, strlen(x) + 1); + if (err != ERROR_SUCCESS) + return -1; + + return 0; +} + +int +registry_dword_set(HKEY hkey, char *sub, DWORD x) +{ + DWORD err; + + err = RegSetValueEx(hkey, sub, 0, REG_DWORD, (CONST BYTE *)&x, sizeof(DWORD)); + if (err != ERROR_SUCCESS) + return -1; + + return 0; +} + +int +registry_keyval_dword_set(HKEY hkey, char *base, char *sub, DWORD val) +{ + HKEY k; + int err; + + k = registry_open(hkey, base, KEY_WRITE); + if (k == INVALID_HANDLE_VALUE) + return -1; + + err = registry_dword_set(k, sub, val); + + registry_close(k); + + return err; +} + +int +registry_keyval_dword_get(HKEY hkey, char *base, char *sub, DWORD *val) +{ + HKEY k; + int err; + + k = registry_open(hkey, base, KEY_READ); + if (k == INVALID_HANDLE_VALUE) + return -1; + + err = registry_dword_get(k, sub, val); + + registry_close(k); + + return err; +} + +int +registry_keyval_string_get(HKEY hkey, char *base, char *sub, char **val) +{ + HKEY k; + int err; + + k = registry_open(hkey, base, KEY_READ); + if (k == INVALID_HANDLE_VALUE) { + *val = NULL; + return -1; + } + + err = registry_string_get(k, sub, val); + + registry_close(k); + + return err; +} + +int +registry_keyval_string_set(HKEY hkey, char *base, char *sub, char *val) +{ + HKEY k; + int err; + + k = registry_open(hkey, base, KEY_WRITE); + if (k == INVALID_HANDLE_VALUE) + return -1; + + err = registry_string_set(k, sub, val); + + registry_close(k); + + return err; +} + +int +registry_value_delete(HKEY hkey, char *sub) +{ + if (RegDeleteValue(hkey, sub)) + return -1; + + return 0; +} + +int +registry_keyval_delete(HKEY hkey, char *base, char *sub) +{ + HKEY k; + int err; + + k = registry_open(hkey, base, KEY_WRITE); + if (k == INVALID_HANDLE_VALUE) + return -1; + + err = registry_value_delete(k, sub); + + registry_close(k); + + return err; +} diff --git a/mechglue/src/windows/lib/registry.h b/mechglue/src/windows/lib/registry.h new file mode 100644 index 000000000..d628d2bcb --- /dev/null +++ b/mechglue/src/windows/lib/registry.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 1997 Cygnus Solutions + * + * Author: Michael Graff + */ + +#ifndef LIB_WINDOWS_REGISTRY_H +#define LIB_WINDOWS_REGISTRY_H + +#include <windows.h> +#include <windowsx.h> + +HKEY registry_open(HKEY, char *, REGSAM); +void registry_close(HKEY); +HKEY registry_key_create(HKEY, char *, REGSAM); +int registry_key_delete(HKEY, char *); +int registry_string_get(HKEY, char *, char **); +int registry_dword_get(HKEY, char *, DWORD *); +int registry_string_set(HKEY, char *, char *); +int registry_dword_set(HKEY, char *, DWORD); +int registry_keyval_dword_set(HKEY, char *, char *, DWORD); +int registry_keyval_dword_get(HKEY, char *, char *, DWORD *); +int registry_keyval_string_get(HKEY, char *, char *, char **); +int registry_keyval_string_set(HKEY, char *, char *, char *); +int registry_value_delete(HKEY, char *); +int registry_keyval_delete(HKEY, char *, char *); + +#define CYGNUS_SOLUTIONS "SOFTWARE\\Cygnus Solutions" + +#define KERBNET_SANS_VERSION CYGNUS_SOLUTIONS "\\Kerbnet" +#define KERBNET_BASE KERBNET_SANS_VERSION "\\1" + +#define KERBNET_TELNET_BASE KERBNET_BASE "\\telnet" +#define KERBNET_TELNET_HOST KERBNET_TELNET_BASE "\\hosts" + +#define KERBNET_CNS_BASE KERBNET_BASE "\\cns" + +#define KERBNET_HOME "KERBNET_HOME" + +#endif /* LIB_WINDOWS_REGISTRY_H */ diff --git a/mechglue/src/windows/lib/vardlg.c b/mechglue/src/windows/lib/vardlg.c new file mode 100644 index 000000000..dae8cdbbc --- /dev/null +++ b/mechglue/src/windows/lib/vardlg.c @@ -0,0 +1,453 @@ +/* + * Dialog box building for various numbers of (label, entry) fields. + * + * This code is somewhat hardcoded to build boxes for the krb5_get_init_creds() + * function. + * + * Copyright (C) 1997 Cygnus Solutions. + * + * Author: Michael Graff + */ + +#include <windows.h> +#include <windowsx.h> + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "krb5.h" +#include "vardlg.h" + +/* + * a hack, I know... No error checking below, either. + */ +static unsigned char dlg[DLG_BUF]; + +/* + * Add a WORD (16-bit int) to the buffer. Return the number of characters + * added. + */ +static int +ADD_WORD(unsigned char *p, WORD w) +{ + *((WORD *)p) = w; + + return 2; +} + +static int +ADD_DWORD(unsigned char *p, DWORD dw) +{ + *((DWORD *)p) = dw; + + return 4; +} + +static int +ADD_UNICODE_STRING(unsigned char *p, const char *s) +{ + WORD *w; + int i; + int len; + + w = (WORD *)p; + + len = strlen(s) + 1; /* copy the null, too */ + + for (i = 0 ; i < len ; i++) + *w++ = *s++; + + return (len * 2); +} + +#define DWORD_ALIGN(p) { while ((DWORD)p % 4) *p++ = 0x00; } + +static int +ADD_DLGTEMPLATE(unsigned char *dlg, short x, short y, short cx, short cy, + const char *caption, const char *fontname, WORD fontsize, + WORD n) +{ + unsigned char *p; + DLGTEMPLATE dlt; + + p = dlg; + + dlt.style = (DS_MODALFRAME | WS_POPUP); + if (caption != NULL) + dlt.style |= WS_CAPTION; + if (fontname != NULL) + dlt.style |= DS_SETFONT; + dlt.dwExtendedStyle = 0; + dlt.cdit = n; + dlt.x = x; + dlt.y = y; + dlt.cx = cx; + dlt.cy = cy; + memcpy(p, &dlt, sizeof(dlt)); + p += sizeof(dlt); + + p += ADD_WORD(p, 0x0000); /* menu == none */ + + p += ADD_WORD(p, 0x0000); /* class == default? */ + + if (caption != NULL) + p += ADD_UNICODE_STRING(p, caption); + else + p += ADD_WORD(p, 0x0000); + + if (fontname != NULL) { + p += ADD_WORD(p, fontsize); + p += ADD_UNICODE_STRING(p, fontname); + } + + DWORD_ALIGN(p); + + return (p - dlg); +} + +static int +ADD_DLGITEM(unsigned char *dlg, short x, short y, short cx, short cy, + const char *label, WORD id, WORD type, DWORD style) +{ + unsigned char *p; + DLGITEMTEMPLATE dit; + + p = dlg; + + dit.style = style; + dit.dwExtendedStyle = 0; + dit.x = x; + dit.y = y; + dit.cx = cx; + dit.cy = cy; + dit.id = id; + memcpy(p, &dit, sizeof(dit)); + p += sizeof(dit); + + p += ADD_WORD(p, 0xffff); + p += ADD_WORD(p, type); + + p += ADD_UNICODE_STRING(p, label); + + /* + * creation data? For now, just make this empty, like the resource + * compiler does. + */ + p += ADD_WORD(p, 0x0000); + + DWORD_ALIGN(p); + + return (p - dlg); +} + +#define ADD_DLGITEM_defpushbutton(a, b, c, d, e, f, g) \ + ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0080, 0x50010001); + +#define ADD_DLGITEM_pushbutton(a, b, c, d, e, f, g) \ + ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0080, 0x50010000); + +#define ADD_DLGITEM_left_static(a, b, c, d, e, f, g) \ + ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020000); + +#define ADD_DLGITEM_centered_static(a, b, c, d, e, f, g) \ + ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020001); + +#define ADD_DLGITEM_right_static(a, b, c, d, e, f, g) \ + ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0082, 0x50020002); + +#define ADD_DLGITEM_entry(a, b, c, d, e, f, g) \ + ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0081, 0x50810080); + +#define ADD_DLGITEM_hidden_entry(a, b, c, d, e, f, g) \ + ADD_DLGITEM((a), (b), (c), (d), (e), (f), (g), 0x0081, 0x508100a0); + + +/* + * "build" the dialog box. In this bit of code, we create the dialog box, + * create the OK button, and a static label for the banner text. + * + * If there are items, we also create a Cancel button and one (label, entry) + * fields for each item. + */ +void * +vardlg_build(WORD cx, const char *name, const char *banner, + WORD n, krb5_prompt prompts[], WORD id) +{ + unsigned char *p; + WORD i; + + p = dlg; /* global */ + + if (cx < MIN_WIDTH) + cx = MIN_WIDTH; + if (cx > MAX_WIDTH) + cx = MAX_WIDTH; + + /* + * Store the dialog template + */ + p += ADD_DLGTEMPLATE(p, 0, 0, cx, 0, name ? + strlen(name) < 30 ? name : "Kerberos V5" : + "Kerberos V5", + "MS Sans Serif", 8, + (WORD)(n * 2 + 3)); + + /* + * Create a label for the banner. This will be ID (id). + */ + p += ADD_DLGITEM_left_static(p, 0, 0, 0, 0, "", id++); + + /* + * Each label field is ID (id + 1) + (item * 2), and each entry field + * is (id + 2) + (item * 2) + */ + for (i = 0 ; i < n ; i++) { + p += ADD_DLGITEM_right_static(p, 0, 0, 0, 0, "", id++); + if (prompts[i].hidden) { + p += ADD_DLGITEM_hidden_entry(p, 0, 0, 0, 0, "", id++); + } else { + p += ADD_DLGITEM_entry(p, 0, 0, 0, 0, "", id++); + } + } + + /* + * Create the OK and Cancel buttons. + */ + p += ADD_DLGITEM_defpushbutton(p, 0, 0, 0, 0, + "OK", IDOK); + if (n != 0) + p += ADD_DLGITEM_pushbutton(p, 0, 0, 0, 0, + "Cancel", IDCANCEL); + + return dlg; +} + +#define SPACE_Y 4 /* logical units */ +#define SPACE_X 4 /* logical units */ +#define ENTRY_PX 120 /* pixels */ +#define BUTTON_PX 70 /* pixels */ +#define BUTTON_PY 30 /* pixels */ + +void +vardlg_config(HWND hwnd, WORD width, const char *banner, WORD num_prompts, + krb5_prompt *prompts, WORD id) +{ + int n; + WORD cid; + HDC hdc; + SIZE csize; + SIZE maxsize; + LONG cx, cy; + LONG ccx, ccy; + LONG space_x, space_y; + LONG max_x, max_y; + LONG banner_y; + RECT rect; + int done; + const char *p; + + /* + * First, set the banner's text. + */ + Static_SetText(GetDlgItem(hwnd, id), banner); + + /* + * Next, run through the items and set their static text. + * Also, set the corresponding edit string and set the + * maximum input length. + */ + cid = (id + 1); + + for (n = 0 ; n < num_prompts ; n++) { + Static_SetText(GetDlgItem(hwnd, cid), prompts[n].prompt); + cid++; + Edit_SetText(GetDlgItem(hwnd, cid), ""); + Edit_LimitText(GetDlgItem(hwnd, cid), prompts[n].reply->length); + cid++; + } + + /* + * Now run through the entry fields and find the longest string. + */ + maxsize.cx = maxsize.cy = 0; + cid = (id + 1); + hdc = GetDC(GetDlgItem(hwnd, cid)); /* assume one label is the same as all the others */ + + for (n = 0 ; n < num_prompts ; n++) { + GetTextExtentPoint32(hdc, prompts[n].prompt, strlen(prompts[n].prompt), &csize); + if (csize.cx > maxsize.cx) + maxsize.cx = csize.cx; + if (csize.cy > maxsize.cy) + maxsize.cy = csize.cy; + } + +#if 0 + /* + * convert the maximum values into pixels. Ugh. + */ + rect.left = 0; + rect.top = 0; + rect.right = maxsize.cx; + rect.bottom = maxsize.cy; + MapDialogRect(hwnd, &rect); + + max_x = rect.right; + max_y = rect.bottom; +#else + max_x = maxsize.cx; + max_y = (long)(((double)maxsize.cy) * 1.5); +#endif + + /* + * convert the spacing values, too. Ugh. Ugh. + */ + rect.left = 0; + rect.top = 0; + rect.right = SPACE_X; + rect.bottom = SPACE_Y; + MapDialogRect(hwnd, &rect); + + space_x = rect.right; + space_y = rect.bottom; + + /* + * Now we know the maximum length of the string for the entry labels. Guestimate + * that the entry fields should be ENTRY_PX pixels long and resize the dialog + * window to fit the longest string plus the entry fields (plus a little for the + * spacing between the edges of the windows and the static and edit fields, and + * between the static and edit fields themselves.) + */ + cx = max_x + ENTRY_PX + (space_x * 3); + cy = (max_y + space_y) * num_prompts; + + /* + * resize the dialog box itself (take 1) + */ + SetWindowPos(hwnd, HWND_TOPMOST, + 0, 0, + cx + 10, cy + 30, + SWP_NOMOVE); + + /* + * position the dialog items. First, the banner. (take 1) + */ + SetWindowPos(GetDlgItem(hwnd, id), HWND_BOTTOM, + space_x, space_y, + (cx - space_x * 2), max_y, + 0); + + /* + * Now that the window for the banner is in place, convert the width into logical units + * and find out how many lines we need to reserve room for. + */ + done = 0; + p = banner; + banner_y = 0; + + do { + int nFit; + int pDx[128]; + + hdc = GetDC(GetDlgItem(hwnd, id)); + + GetTextExtentExPoint(hdc, p, strlen(p), cx, &nFit, + pDx, &csize); + + banner_y += csize.cy; + + p += nFit; + + } while (*p != 0); + + banner_y += space_y; + + /* + * position the banner (take 2) + */ + SetWindowPos(GetDlgItem(hwnd, id), HWND_BOTTOM, + space_x, space_y, + (cx - space_x * 2), banner_y, + 0); + + /* + * Don't forget to include the banner estimate and the buttons, too. Once again, + * assume the buttons are BUTTON_PY pixels high. The extra three space_y's are + * for between the top of the dialog and the banner, between the banner and the + * first label, and between the buttons and the bottom of the screen. + */ + cy += banner_y + BUTTON_PY + (space_y * 3); + + /* + * resize the dialog box itself (Again... ugh!) + */ + SetWindowPos(hwnd, HWND_TOPMOST, + 0, 0, + cx + 10, cy + 30, + SWP_NOMOVE); + + cid = (id + 1); + ccy = banner_y + (space_y * 2); + ccx = max_x + (space_x * 2); /* where the edit fields start */ + + for (n = 0 ; n < num_prompts ; n++) { + SetWindowPos(GetDlgItem(hwnd, cid), HWND_BOTTOM, + space_x, ccy, + max_x, max_y, 0); + cid++; + SetWindowPos(GetDlgItem(hwnd, cid), HWND_BOTTOM, + ccx, ccy, + ENTRY_PX, max_y - 3, 0); + cid++; + ccy += (max_y + space_y); + } + + /* + * Now the buttons. If there are any entries we will have both an OK and a + * Cancel button. If we don't have any entries, we will have only an OK. + */ + if (num_prompts == 0) { + SetWindowPos(GetDlgItem(hwnd, IDOK), HWND_BOTTOM, + (cx / 2), cy - space_y - BUTTON_PY, + BUTTON_PX, BUTTON_PY, 0); + } else { + SetWindowPos(GetDlgItem(hwnd, IDOK), HWND_BOTTOM, + space_x, cy - space_y - BUTTON_PY, + BUTTON_PX, BUTTON_PY, 0); + SetWindowPos(GetDlgItem(hwnd, IDCANCEL), HWND_BOTTOM, + cx - space_x - BUTTON_PX, cy - space_y - BUTTON_PY, + BUTTON_PX, BUTTON_PY, 0); + } + + return; +} + +/* + * To use these functions, first create the dialog box and entries. + * You will always get an OK button. If there are at least one item, + * you will also get a cancel button. The OK button is IDOK, and the cancel + * button is IDCANCEL, as usual. + * + * After calling bld_dlg, the banner will have ID "id", and the labels + * will be "1 + id + i * 2" (i is the entry number, starting with zero) and + * the entries will be "2 + id + i * 2". + * + * unsigned char *dlg = vardlg_build(minwidth, banner, num_prompts, + * krb5_prompt[], id); + * + * Then, "run" the dialog using: + * + * rc = DialogBoxIndirect(hinstance, (LPDLGTEMPLATE)dlg, + * HWND_DESKTOP, myDialogProc); + * + * Note that the vardlg_build function uses a static data area and so cannot + * be used more than once before the DialogBoxIndirect() procedure is called. + * I assume windows won't need that area after that call is complete. + * + * In the dialog's _initialization_ procedure, call + * + * vardlg_config(hwnd, banner, num_prompts, krb5_prompt[], id); + * + * This function will resize the various elements of the dialog and fill in the + * labels. + */ diff --git a/mechglue/src/windows/lib/vardlg.h b/mechglue/src/windows/lib/vardlg.h new file mode 100644 index 000000000..e609d4a1d --- /dev/null +++ b/mechglue/src/windows/lib/vardlg.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 1997 Cygnus Solutions + * + * Author: Michael Graff + */ + +#ifndef _WINDOWS_LIB_VARDLG_H +#define _WINDOWS_LIB_VARDLG_H + +#include <windows.h> +#include <windowsx.h> + +#define DLG_BUF 4096 + +/* + * The minimum and maximum dialog box widths we will allow. + */ +#define MIN_WIDTH 350 +#define MAX_WIDTH 600 + +/* + * "build" the dialog box. In this bit of code, we create the dialog box, + * create the OK button, and a static label for the banner text. + * + * If there are items, we also create a Cancel button and one (label, entry) + * fields for each item. + */ +void *vardlg_build(WORD, const char *, const char *, WORD, krb5_prompt *, WORD); + +void vardlg_config(HWND, WORD, const char *, WORD, krb5_prompt *, WORD); + +#endif /* _WINDOWS_LIB_VARDLG_H */ diff --git a/mechglue/src/windows/ms2mit/ChangeLog b/mechglue/src/windows/ms2mit/ChangeLog new file mode 100644 index 000000000..a346c09be --- /dev/null +++ b/mechglue/src/windows/ms2mit/ChangeLog @@ -0,0 +1,113 @@ +2004-09-09 Jeffrey Altman <jaltman@mit.edu> + + * ms2mit.c: apply KRB5_TC_NOTICKET to MSLSA: ccache while + searching for an initial ticket + +2004-08-20 Jeffrey Altman <jaltman@mit.edu> + + * ms2mit.c: add -c ccache command line option + + * mit2ms.c: new command. Copies contents of the mit ccache + to the MSLSA: ccache + +2004-03-08 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in (MY_SUBDIRS): Deleted. + +2004-01-31 Jeffrey Altman <jaltman@mit.edu> + + * ms2mit.c: Do not allow ticket importing of the Initial TGT cannot + be obtained. The MSLSA krb5_ccache will not export the Initial TGT + if the session key enctype is NULL. + +2003-12-11 Jeffrey Altman <jaltman@mit.edu> + + * ms2mit.c, Makefile.in: + + Remove all of the code that manipulates the MS LSA cache. Instead + of reading in the TGT directly we now take advantage of the new + "MSLSA:" krb5_ccache type. We open the MS LSA cache as a read-only + ccache and copy it to the default ccache for the system. + + This removes the dependency on secur32.dll from this file. + +2003-10-21 Jeffrey Altman <jaltman@mit.edu> + + * ms2mit.c: + + Because of the failure of Windows 2000 and Windows XP to perform + proper ticket expiration time management, the MS Kerberos LSA will + return tickets to a calling application with lifetimes as short as + one second. Tickets with lifetimes less than five minutes can cause + problems for most apps. Tickets with lifetimes less than 20 minutes + will trigger the Leash ticket lifetime warnings. + + Instead of accepting whatever tickets are returned by MS LSA from + the cache, if the ticket lifetime is less than 20 minutes force a + retrieval operation bypassing the LSA ticket cache. + + +2003-07-16 Jeffrey Altman <jaltman@mit.edu> + + * ms2mit.c: + + Functional changes: + (1) do not restrict ourselves to DES-CBC-CRC instead support any + ticket with an enctype we support. as of this date (rev 1.3) + this includes all but RC4-MD4. + (2) do not accept invalid tickets + (3) when attempting to retrieve tickets do not specify either the + enctype or cache options (if possible). doing so will force a + TGS request and prevent the results from being stored into the + cache. + (4) when the LSA cache contains a TGT which has expired Microsoft will + not perform a new TGS request until the cache has been purged. + Instead the expired ticket continues to be used along with its + embedded authorization data. When PURGE_ENABLED is defined, if the + tickets are expired, the cache will be purged before requesting + new tickets, else we ignore the contents of the cache and force + a new TGS request. + (5) when the LSA cache is empty do not abort. On XP or 2003, use + the SecurityLogonSessionData to determine the Realm (UserDnsDomain + in MS-speak) and request an appropriate TGT. On 2000, check the + Registry for the HKCU\"Volatile Environment":"USERDNSDOMAIN" + instead. This will allow ms2mit to be used to repopulate the + LSA cache. If the current session is not Kerberos authenticated + an appropriate error message will be generated. + + Code changes: + (1) several memory leaks plugged + (2) several support functions copied from the Leashw32.dll sources + (3) get_STRING_from_registry() uses the ANSI versions of the Registry + functions and should at a later date be converted to use the + Unicode versions. + + Notes: an ms2mit.exe based on the Leash_import() function + should be considered. Leash_import() not only imports the TGT from + the LSA but also performs the krb524 conversion and AFS token retrieval. + Of course, that version of ms2mit.exe could not exist within the krb5 + source tree. + +2003-06-20 Jeffrey Altman <jaltman@mit.edu> + + * ms2mit.c: Windows Credentials are addressless. Do not store the + credentials in the MIT cache with addresses since they do not + contain addresses in the encrypted portion of the credential. + Instead generate a valid empty address list. + +2002-08-29 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in: Revert $(S)=>/ change, for Windows support. + +2002-08-23 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in: Change $(S)=>/ and $(U)=>.. globally. + +2001-11-28 Danilo Almeida <dalmeida@mit.edu> + + * ms2mit.c: Make sure we get a des-cbc-crc session key instead of + potentially getting whatever happens to be in the cache. Remove + unnecessary static variables. Make function headers use a + consistent format. Rename ShowLastError() to ShowWinError() and + ShowNTError() to ShowLsaError(). + diff --git a/mechglue/src/windows/ms2mit/Makefile.in b/mechglue/src/windows/ms2mit/Makefile.in new file mode 100644 index 000000000..b1275bbb4 --- /dev/null +++ b/mechglue/src/windows/ms2mit/Makefile.in @@ -0,0 +1,25 @@ +# Makefile for the Microsoft to MIT cache converter. +# Works for k5 release only. +# + +thisconfigdir=./.. +myfulldir=windows/ms2mit +mydir=. +BUILDTOP=$(REL)..$(S).. +DEFINES = +PROG_LIBPATH=-L$(TOPLIBD) -L$(KRB5_LIBDIR) + +all-windows:: $(OUTPRE)ms2mit.exe $(OUTPRE)mit2ms.exe + +$(OUTPRE)ms2mit.exe: $(OUTPRE)ms2mit.obj + link $(EXE_LINKOPTS) -out:$@ $(OUTPRE)ms2mit.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.obj user32.lib advapi32.lib $(KLIB) $(CLIB) + +$(OUTPRE)mit2ms.exe: $(OUTPRE)mit2ms.obj + link $(EXE_LINKOPTS) -out:$@ $(OUTPRE)mit2ms.obj $(BUILDTOP)\util\windows\$(OUTPRE)getopt.obj user32.lib advapi32.lib $(KLIB) $(CLIB) + +install:: + copy $(OUTPRE)ms2mit.exe $(DESTDIR) + copy $(OUTPRE)mit2ms.exe $(DESTDIR) + +clean:: + $(RM) $(OUTPRE)*.exe diff --git a/mechglue/src/windows/ms2mit/mit2ms.c b/mechglue/src/windows/ms2mit/mit2ms.c new file mode 100644 index 000000000..6f30d9f6d --- /dev/null +++ b/mechglue/src/windows/ms2mit/mit2ms.c @@ -0,0 +1,149 @@ +/* + * mit2ms.c + * + */ +/* + * Copyright (C) 2003,2004 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include "krb5.h" +#include <stdio.h> +#include <string.h> + +extern int optind; +extern char *optarg; + +static char *prog; + +static void +xusage(void) +{ + fprintf(stderr, "xusage: %s [-c ccache]\n", prog); + exit(1); +} + +void +main( + int argc, + char *argv[] + ) +{ + krb5_context kcontext; + krb5_error_code code; + krb5_ccache ccache=NULL; + krb5_ccache mslsa_ccache=NULL; + krb5_cc_cursor cursor; + krb5_creds creds; + krb5_principal princ; + int initial_ticket = 0; + int option; + char * ccachestr = 0; + + prog = strrchr(argv[0], '/'); + prog = prog ? (prog + 1) : argv[0]; + + while ((option = getopt(argc, argv, "c:h")) != -1) { + switch (option) { + case 'c': + ccachestr = optarg; + break; + case 'h': + default: + xusage(); + break; + } + } + + if (code = krb5_init_context(&kcontext)) { + com_err(argv[0], code, "while initializing kerberos library"); + exit(1); + } + + if (ccachestr) + code = krb5_cc_resolve(kcontext, ccachestr, &ccache); + else + code = krb5_cc_default(kcontext, &ccache); + if (code) { + com_err(argv[0], code, "while getting default ccache"); + krb5_free_principal(kcontext, princ); + krb5_free_context(kcontext); + exit(1); + } + + /* Enumerate tickets from cache looking for an initial ticket */ + if ((code = krb5_cc_start_seq_get(kcontext, ccache, &cursor))) { + com_err(argv[0], code, "while initiating the cred sequence of MS LSA ccache"); + krb5_cc_close(kcontext, ccache); + krb5_free_context(kcontext); + exit(1); + } + + while (!(code = krb5_cc_next_cred(kcontext, ccache, &cursor, &creds))) + { + if ( creds.ticket_flags & TKT_FLG_INITIAL ) { + krb5_free_cred_contents(kcontext, &creds); + initial_ticket = 1; + break; + } + krb5_free_cred_contents(kcontext, &creds); + } + krb5_cc_end_seq_get(kcontext, ccache, &cursor); + + if ( !initial_ticket ) { + fprintf(stderr, "%s: Initial Ticket Getting Tickets are not available from the MIT default cache\n", + argv[0]); + krb5_cc_close(kcontext, ccache); + krb5_free_context(kcontext); + exit(1); + } + + if (code = krb5_cc_get_principal(kcontext, ccache, &princ)) { + com_err(argv[0], code, "while obtaining default MIT principal"); + krb5_cc_close(kcontext, ccache); + krb5_free_context(kcontext); + exit(1); + } + + if (code = krb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) { + com_err(argv[0], code, "while opening MS LSA ccache"); + krb5_cc_close(kcontext, ccache); + krb5_free_context(kcontext); + exit(1); + } + + if (code = krb5_cc_copy_creds(kcontext, ccache, mslsa_ccache)) { + com_err (argv[0], code, "while copying default MIT ccache to MSLSA ccache"); + krb5_free_principal(kcontext, princ); + krb5_cc_close(kcontext, ccache); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + exit(1); + } + + krb5_free_principal(kcontext, princ); + krb5_cc_close(kcontext, ccache); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + return(0); +} diff --git a/mechglue/src/windows/ms2mit/ms2mit.c b/mechglue/src/windows/ms2mit/ms2mit.c new file mode 100644 index 000000000..5999a1847 --- /dev/null +++ b/mechglue/src/windows/ms2mit/ms2mit.c @@ -0,0 +1,171 @@ +/* + * ms2mit.c + * + */ +/* + * Copyright (C) 2003 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#include "krb5.h" +#include <stdio.h> +#include <string.h> + +extern int optind; +extern char *optarg; + +static char *prog; + +static void +xusage(void) +{ + fprintf(stderr, "xusage: %s [-c ccache]\n", prog); + exit(1); +} + +void +main( + int argc, + char *argv[] + ) +{ + krb5_context kcontext; + krb5_error_code code; + krb5_ccache ccache=NULL; + krb5_ccache mslsa_ccache=NULL; + krb5_cc_cursor cursor; + krb5_creds creds; + krb5_principal princ; + int initial_ticket = 0; + int option; + char * ccachestr = 0; + + prog = strrchr(argv[0], '/'); + prog = prog ? (prog + 1) : argv[0]; + + while ((option = getopt(argc, argv, "c:h")) != -1) { + switch (option) { + case 'c': + ccachestr = optarg; + break; + case 'h': + default: + xusage(); + break; + } + } + + if (code = krb5_init_context(&kcontext)) { + com_err(argv[0], code, "while initializing kerberos library"); + exit(1); + } + + if (code = krb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) { + com_err(argv[0], code, "while opening MS LSA ccache"); + krb5_free_context(kcontext); + exit(1); + } + + if (code = krb5_cc_set_flags(kcontext, mslsa_ccache, KRB5_TC_NOTICKET)) { + com_err(argv[0], code, "while setting KRB5_TC_NOTICKET flag"); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + exit(1); + } + + /* Enumerate tickets from cache looking for an initial ticket */ + if ((code = krb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) { + com_err(argv[0], code, "while initiating the cred sequence of MS LSA ccache"); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + exit(1); + } + + while (!(code = krb5_cc_next_cred(kcontext, mslsa_ccache, &cursor, &creds))) + { + if ( creds.ticket_flags & TKT_FLG_INITIAL ) { + krb5_free_cred_contents(kcontext, &creds); + initial_ticket = 1; + break; + } + krb5_free_cred_contents(kcontext, &creds); + } + krb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor); + + if (code = krb5_cc_set_flags(kcontext, mslsa_ccache, 0)) { + com_err(argv[0], code, "while clearing flags"); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + exit(1); + } + + if ( !initial_ticket ) { + fprintf(stderr, "%s: Initial Ticket Getting Tickets are not available from the MS LSA\n", + argv[0]); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + exit(1); + } + + if (code = krb5_cc_get_principal(kcontext, mslsa_ccache, &princ)) { + com_err(argv[0], code, "while obtaining MS LSA principal"); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + exit(1); + } + + if (ccachestr) + code = krb5_cc_resolve(kcontext, ccachestr, &ccache); + else + code = krb5_cc_default(kcontext, &ccache); + if (code) { + com_err(argv[0], code, "while getting default ccache"); + krb5_free_principal(kcontext, princ); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + exit(1); + } + if (code = krb5_cc_initialize(kcontext, ccache, princ)) { + com_err (argv[0], code, "when initializing ccache"); + krb5_free_principal(kcontext, princ); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_cc_close(kcontext, ccache); + krb5_free_context(kcontext); + exit(1); + } + + if (code = krb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) { + com_err (argv[0], code, "while copying MS LSA ccache to default ccache"); + krb5_free_principal(kcontext, princ); + krb5_cc_close(kcontext, ccache); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + exit(1); + } + + krb5_free_principal(kcontext, princ); + krb5_cc_close(kcontext, ccache); + krb5_cc_close(kcontext, mslsa_ccache); + krb5_free_context(kcontext); + return(0); +} diff --git a/mechglue/src/windows/version.rc b/mechglue/src/windows/version.rc new file mode 100644 index 000000000..05dba755d --- /dev/null +++ b/mechglue/src/windows/version.rc @@ -0,0 +1,222 @@ +#include <windows.h> +#include <winver.h> +#include "patchlevel.h" + +/* + * BEGIN COMMON VERSION INFO for GSS and Kerberos version resources + */ + +#define XSTR(x) #x +#define STR(x) XSTR(x) + +#define MAJOR_MINOR STR(KRB5_MAJOR_RELEASE) "." STR(KRB5_MINOR_RELEASE) + +#if KRB5_PATCH_LEVEL != 0 +#define MAYBE_PATCH "." STR(KRB5_PATCHLEVEL) +#else +#define MAYBE_PATCH "" +#endif + +#ifdef KRB5_RELTAIL +#define RELTAIL "-" KRB5_RELTAIL +#else +#define RELTAIL "" +#endif + +#ifdef BETA +#define BETA_FLAG VS_FF_PRERELEASE +#else +#define BETA_FLAG 0 +#endif + +#if !defined(_WIN32) +#define Targ_OS VOS__WINDOWS16 +#else +#define Targ_OS VOS__WINDOWS32 +#endif + +/* we're going to stamp all the DLLs with the same version number */ + +#define K5_PRODUCT_VERSION_STRING MAJOR_MINOR MAYBE_PATCH RELTAIL "\0" +#define K5_PRODUCT_VERSION KRB5_MAJOR_RELEASE, KRB5_MINOR_RELEASE, KRB5_PATCHLEVEL, 0 + +#define K5_COPYRIGHT "Copyright (C) 1997-2004 by the Massachusetts Institute of Technology\0" +#define K5_COMPANY_NAME "Massachusetts Institute of Technology.\0" + +/* + * END COMMON VERSION INFO + */ + + +/* + * BEGIN SPECIFIC VERSION INFO for GSS and Kerberos version resources + */ + +#ifdef SUPPORT_LIB +#define K5_DESCRIPTION "Kerberos v5 support - internal support code for MIT Kerberos v5 /GSS distribution" +#define K5_INTERNAL_NAME "krb5support\0" +#define K5_FILETYPE VFT_DLL +#if !defined(_WIN32) +#error not win32?? +#else +#define K5_ORIGINAL_NAME "k5sprt32.dll\0" +#endif +#endif /* support */ + +#ifdef CE_LIB +#define K5_DESCRIPTION "COM_ERR - Common Error Handler for MIT Kerberos v5 / GSS distribution\0" +#define K5_INTERNAL_NAME "comerr\0" +#define K5_FILETYPE VFT_DLL +#if !defined(_WIN32) +#define K5_ORIGINAL_NAME "comerr16.dll\0" +#else +#define K5_ORIGINAL_NAME "comerr32.dll\0" +#endif +#endif /* comerr */ + +#ifdef PROF_LIB +#define K5_DESCRIPTION "PROFILE - Profile Library MIT Kerberos v5 / GSS distribution\0" +#define K5_INTERNAL_NAME "profile\0" +#define K5_FILETYPE VFT_DLL +#if !defined(_WIN32) +#define K5_ORIGINAL_NAME "xpprof16.dll\0" +#else +#define K5_ORIGINAL_NAME "xpprof32.dll\0" +#endif +#endif /* profile */ + +#ifdef KRB5_LIB +#define K5_DESCRIPTION "Kerberos v5 - MIT GSS / Kerberos v5 distribution\0" +#define K5_INTERNAL_NAME "krb5\0" +#define K5_FILETYPE VFT_DLL +#if !defined(_WIN32) +#define K5_ORIGINAL_NAME "krb5_16.dll\0" +#else +#define K5_ORIGINAL_NAME "krb5_32.dll\0" +#endif +#endif /* KRB5 */ + +#ifdef GSSAPI_LIB +#define K5_DESCRIPTION "GSSAPI - GSS API implementation for Kerberos 5 mechanism\0" +#define K5_INTERNAL_NAME "gssapi\0" +#define K5_FILETYPE VFT_DLL +#if !defined(_WIN32) +#define K5_ORIGINAL_NAME "gssapi.dll\0" +#else +#define K5_ORIGINAL_NAME "gssapi32.dll\0" +#endif +#endif /* GSSAPI */ + +#ifdef KRB4_LIB +#define K5_DESCRIPTION "Kerberos v4 - MIT GSS / Kerberos v4 and v5 distribution\0" +#define K5_INTERNAL_NAME "krb4\0" +#define K5_FILETYPE VFT_DLL +#if !defined(_WIN32) +#define K5_ORIGINAL_NAME "krb4_16.dll\0" +#else +#define K5_ORIGINAL_NAME "krb4_32.dll\0" +#endif +#endif /* KRB4 */ + +#ifdef SAPKRB_LIB +#define K5_DESCRIPTION "Kerberos v5 - MIT GSS / Kerberos v5 distribution (for SAP)\0" +#define K5_INTERNAL_NAME "sapkrb5\0" +#define K5_FILETYPE VFT_DLL +#if !defined(_WIN32) +#define K5_ORIGINAL_NAME "sapkrb16.dll\0" +#else +#define K5_ORIGINAL_NAME "sapkrb32.dll\0" +#endif +#endif /* SAPKRB */ + +#ifdef SAPGSS_LIB +#define K5_DESCRIPTION "GSSAPI - GSS API implementation for Kerberos 5 mechanism(for SAP)\0" +#define K5_INTERNAL_NAME "sapgss\0" +#define K5_FILETYPE VFT_DLL +#if !defined(_WIN32) +#define K5_ORIGINAL_NAME "sapgss16.dll\0" +#else +#define K5_ORIGINAL_NAME "sapgss32.dll\0" +#endif +#endif /* SAPGSS */ + +#ifdef KRB5_APP +#define K5_DESCRIPTION "KRB5 Ticket Manager - MIT GSS / Kerberos v5 distribution\0" +#define K5_FILETYPE VFT_APP +#define K5_INTERNAL_NAME "KRB5\0" +#define K5_ORIGINAL_NAME "krb5.exe\0" +#endif /* KRB5_APP */ + +#ifdef GSS_APP +#define K5_DESCRIPTION "GSS - GSS Sample Application for MIT Kerberos v5 / GSS distribution\0" +#define K5_FILETYPE VFT_APP +#define K5_INTERNAL_NAME "GSS\0" +#define K5_ORIGINAL_NAME "gss.exe\0" +#endif + +#ifdef TELNET_APP +#define K5_DESCRIPTION "Telnet - Telnet Application for MIT Kerberos v5 / GSS distribution\0" +#define K5_FILETYPE VFT_APP +#define K5_INTERNAL_NAME "TELNET\0" +#define K5_ORIGINAL_NAME "telnet.exe\0" +#endif + +/* + * END SPECIFIC VERSION INFO + */ + +VS_VERSION_INFO VERSIONINFO +FILEVERSION K5_PRODUCT_VERSION +PRODUCTVERSION K5_PRODUCT_VERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS (VS_FF_DEBUG | VS_FF_PRIVATEBUILD | BETA_FLAG) +FILEOS Targ_OS +FILETYPE K5_FILETYPE +BEGIN + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END + + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN +#if defined(VER_EXTRA_LABEL) && defined(VER_EXTRA_VALUE) + VALUE VER_EXTRA_LABEL, VER_EXTRA_VALUE +#endif +#ifdef VER_COMMENT + VALUE "Comment", VER_COMMENT +#endif +#ifdef VER_USERNAME + VALUE "Built By", VER_USERNAME +#endif +#ifdef VER_HOSTNAME + VALUE "Build Host", VER_HOSTNAME +#endif +#ifdef VER_DATE + VALUE "Build Time", VER_DATE +#endif +#ifdef VER_VENDOR + VALUE "Modified by Vendor", VER_VENDOR +#endif + VALUE "CompanyName", K5_COMPANY_NAME + VALUE "FileDescription", K5_DESCRIPTION + VALUE "FileVersion", K5_PRODUCT_VERSION_STRING + VALUE "InternalName", K5_INTERNAL_NAME +#ifdef VER_LEGALTRADEMARK_STR + VALUE VER_LEGALTRADEMARK_STR +#else + VALUE "LegalTrademarks", "\0" +#endif + VALUE "OriginalFilename", K5_ORIGINAL_NAME + VALUE "ProductName", K5_ORIGINAL_NAME + VALUE "ProductVersion", K5_PRODUCT_VERSION_STRING + + VALUE "LegalCopyright", K5_COPYRIGHT +#ifdef VER_SPECIALBUILD + VALUE "SpecialBuild", VER_SPECIALBUILD +#endif + END + END +END diff --git a/mechglue/src/windows/wintel/.Sanitize b/mechglue/src/windows/wintel/.Sanitize new file mode 100644 index 000000000..ffe992b4f --- /dev/null +++ b/mechglue/src/windows/wintel/.Sanitize @@ -0,0 +1,56 @@ +# Sanitize.in for Kerberos V5 + +# Each directory to survive it's way into a release will need a file +# like this one called "./.Sanitize". All keyword lines must exist, +# and must exist in the order specified by this file. Each directory +# in the tree will be processed, top down, in the following order. + +# Hash started lines like this one are comments and will be deleted +# before anything else is done. Blank lines will also be squashed +# out. + +# The lines between the "Do-first:" line and the "Things-to-keep:" +# line are executed as a /bin/sh shell script before anything else is +# done in this + +Do-first: + +# All files listed between the "Things-to-keep:" line and the +# "Files-to-sed:" line will be kept. All other files will be removed. +# Directories listed in this section will have their own Sanitize +# called. Directories not listed will be removed in their entirety +# with rm -rf. + +Things-to-keep: + +auth.c +auth.h +changelo +dialog.h +edit.c +emul.c +font.c +ini.h +intern.c +k5stream.c +k5stream.h +makefile +ncsa.ico +negotiat.c +screen.c +screen.h +struct.h +telnet.c +telnet.def +telnet.dlg +telnet.h +telnet.rc +telopts.h +terminal.ico +wt-proto.h + +Things-to-lose: + +Do-last: + +# End of file. diff --git a/mechglue/src/windows/wintel/ChangeLog b/mechglue/src/windows/wintel/ChangeLog new file mode 100644 index 000000000..63ad7a421 --- /dev/null +++ b/mechglue/src/windows/wintel/ChangeLog @@ -0,0 +1,213 @@ +2004-09-30 Jeffrey Altman <jaltman@mit.edu> + + * Makefile.in: Add $(BUILDTOP) to include path for patchlevel.h + +2002-06-13 Ken Raeburn <raeburn@mit.edu> + + * Makefile.in (SYSLIBS): Use ws2_32.lib instead of wsock32.lib. + +2001-10-10 Danilo Almeida <dalmeida@mit.edu> + + * intern.c (ScreenInsChar): Return BOOL. + + * enc_des.h: Remove undefined encrypt_send_supprt(). + + + * encrypt.h: Fix parameters in declaration for encrypt_init(). + Remove undefined encrypt_send_supprt(). + + * screen.h: HANDLE -> HINSTANCE. ScreenInsChar() returns BOOL. + + * wt-proto.h: Remove WinMain declaration since that is already in + the standard Windows headers. Update declarations to current + Microsoft Platform SDK definitions. Remove some undefined + functions. + + * telnet.c: Update declarations to use definitions in current + Microsoft Platform SDK (HANDLE -> HINSTANCE, and others). + +2001-10-09 Ken Raeburn <raeburn@mit.edu> + + * enc_des.c, enc_des.h, encrypt.c, encrypt.h: Make prototypes + unconditional. Don't define P(). + +2001-10-05 Ken Raeburn <raeburn@mit.edu> + + * font.c, k5stream.c, k5stream.h, screen.c, screen.h, telnet.c, + wt-proto.h: Don't declare pointers and functions NEAR or FAR any + more. + +2001-10-03 Ken Raeburn <raeburn@mit.edu> + + * encrypt.h: Don't use KRB5_DLLIMP. + +2000-05-08 Nalin Dahyabhai <nalin@redhat.com> + + * auth.c (auth_abort): Don't overflow buffer "strTmp". + (k4_auth_send): Don't overflow buffer "dbgbuf". + * encrypt.c (printsub): Don't overflow buffer "p". + +1999-12-03 Danilo Almeida <dalmeida@mit.edu> + + * Makefile.in: Windows fix for updated win-pre.in. + +Mon May 17 19:54:51 1999 Danilo Almeida <dalmeida@mit.edu> + + * Makefile.in: Add included version resouce script to + resource file dependency. + +Mon May 17 14:23:13 1999 Danilo Almeida <dalmeida@mit.edu> + + * Makefile.in: Remove win16 stuff. Fix resource dependencies. + Link resource file directly instead of explicitly + converting it to an object file. + +1999-04-17 <tytso@rsts-11.mit.edu> + + * screen.c (DeleteTopLine): Free the top line before when we allow + it to scroll out of the Scrollback buffer. Bugfix + suggested by Craig Huckabee <huck@cs.wisc.edu>. + +Mon May 10 15:28:51 1999 Danilo Almeida <dalmeida@mit.edu> + + * Makefile.in: Do win32 build in subdir. + +Fri Feb 5 01:42:07 1999 Theodore Y. Ts'o <tytso@mit.edu> + + * enc_des.c (fb64_session): Call des_init_random_number_generator + instead of des_set_random_generator_seed, since the + compatibility library no longer supports the latter call. + +Wed Feb 3 23:00:05 1999 Theodore Y. Ts'o <tytso@mit.edu> + + * auth.c (auth_send): Increase size of buf so we can handle + mongo-gram sized tickets from Microsoft. [telnet/686] + +Tue Aug 5 18:47:02 1997 Theodore Y. Ts'o <tytso@mit.edu> + + * Makefile.in, telnet.rc: Add version resource to the executable. + +Mon Jul 28 23:35:49 1997 Theodore Y. Ts'o <tytso@mit.edu> + + * Makefile.in: Take out the /nod option, and remove libc.lib from + the list of libraries to be linked. + +Sat Feb 15 12:22:54 1997 Richard Basch <basch@lehman.com> + + * Makefile.in: Link in ComErr library $(CLIB) + +Mon Feb 10 23:18:18 1997 Richard Basch <basch@lehman.com> + + * Makefile.in: Use WLIB definition in config/windows.in + +Wed Feb 5 22:22:24 1997 Richard Basch <basch@lehman.com> + + * Makefile.in: Fixed win16 linking of telnet.exe + * encrypt.c: Do not use printf; use MessageBox and OutputDebugString + * encrypt.h: Fixed des425 library prototypes (win16) + * telnet.c: Removed ^M at end of every line + +Wed Jun 12 00:22:02 1996 Theodore Ts'o <tytso@rsts-11.mit.edu> + + * makefile: Renamed to Makefile.in, so that we can do WIN16/WIN32 + specializations. Remove /nologo option for Win32 RFLAGS, + since RC apparently doesn't support it. + + * changelo: Renamed to ChangeLog, to make life easier. + +Fri Jan 19 23:22:12 1996 Ezra Peisach <epeisach@kangaroo.mit.edu> + + * auth.c (k5_auth_send): krb5_get_credentials does not take the + kdc_options flags. + +Tue Sep 26 20:11:18 1995 <tytso@rsts-11.mit.edu> + + * auth.c: Don't include los-proto.h; it's no longer present. + Don't include des-int.h; it's no longer needed. + +Sat Jun 10 23:09:20 1995 Tom Yu (tlyu@dragons-lair) + + * auth.c: krb5_auth_context redefinitions + +Fri Jun 2 10:51:31 1995 Keith Vetter (keithv@fusion.com) + + Added cursor keys (in two modes) and ctrl-space: the arrow + keys get sent as escape sequences. The actual sequence depends + on the keypad mode which emacs exploits. + Also, ctrl-space now sends a null (for the emacs fans). + + * emul.c: enabled calls to ScreenSetOption to change keyboard modes. + * intern.c: enabled ScreenSetOption but in a limited fashion. + * screen.c: cursor keys now get sent to the host machine. + * screen.h: Added prototype for ScreenSetOption and a new message + type WM_MYCURSORKEY for handling the cursor keys. + * telnet.c: handles WM_MYCURSORKEY and ctrl-space, plus a bug + fix on cancelling from the menu on the opening dialog. + * makefile: cleaned up and made consistent with the cns makefile. + +Thu May 25 12:52:50 1995 Keith Vetter (keithv@fusion.com) + + * auth.c, intern.c, negotiat.c, screen.c, screen.h, telnet.c, + telnet.h, changelo: forgot to specify DOS eol when unzipped + on Unix so had to remove the extra blank lines. + +Thu May 25 11:26:14 1995 John Rivlin <jrvlin@fusion.com> + + * emul.c - make the eol wrapping to work properly. This fixed + numerous seemingly unrelated scrolling bugs. + * auth.c, intern.c, negotiat.c, screen.c, screen.h, telnet.c + telnet.h: removed level of indirection by using pointers rather + than handles; also cleaned up the formatting. + +Thu Apr 27 12:00:00 1995 John Rivlin <jrvlin@fusion.com> + + * edit.c, emul.c, font.c, intern.c, screen.c, telnet.c, screen.h + struct.h, telnet.h, wt-proto.h + Clean up code extensively: + Change memory management to use calloc rather than locking + and unlocking handles everywhere. This makes the code + much easier to understand and maintain. + + Add assertions + + Remove unused global values and scope global values + appropriately to remove accidental overlays of liked + name values (like hInst) + + Make code formatting uniform and remove dead code. + + * screen.c (InitNewScreen, ScreenWndProc): Rearranged window + creation order to so that SCREEN_HANDLE gets set up at the + beginning of the window creation. Thus we can create the + window in the correct size and shape prior to showing it, + eliminating a resize after the window is shown. + +Tue Apr 18 17:11:56 1995 Keith Vetter (keithv@fusion.com) + + * telnet.c: bug fix with saving/restoring delete versus backspace. + +Fri Apr 7 15:14:07 1995 Keith Vetter (keithv@fusion.com) + + * telnet.c, wt-proto.h: port numbers better supported. You can + now specify '<host> <port>' in the initial dialog. This gets + saved in the ini file. + +Wed Apr 5 16:18:30 1995 Keith Vetter (keithv@fusion.com) + + * screen.c, screen.h, dialog.h, telnet.rc: added an about + box with version number. + +Fri Mar 31 16:24:52 1995 Keith Vetter (keithv@fusion.com) + + * telnet.c, wt-proto.h: added command line option to set port number + so port is no longer wired to 13131. + * auth.c: made the k4/k5 separation cleaner + +Mon Mar 27 20:18:41 1995 Keith Vetter (keithv@fusion.com) + + * Initial release based upon the K4 version. + * K4 streams layer is replaced with no-ops in k5stream.c + * only one-way authentication tested since a telnet daemon which + does mutual is not available. + * connect port is hard-wired to 13131 for now since that is the + port of the only available K5 telnet daemon (tsx-11.mit.edu) diff --git a/mechglue/src/windows/wintel/Makefile.in b/mechglue/src/windows/wintel/Makefile.in new file mode 100644 index 000000000..3d2b382f0 --- /dev/null +++ b/mechglue/src/windows/wintel/Makefile.in @@ -0,0 +1,45 @@ +# Makefile for the Kerberos for Windows telnet client +# Works for both k4 and k5 releases. +# +OBJS = $(OUTPRE)telnet.obj $(OUTPRE)negotiat.obj $(OUTPRE)auth.obj \ + $(OUTPRE)edit.obj $(OUTPRE)emul.obj $(OUTPRE)font.obj \ + $(OUTPRE)intern.obj $(OUTPRE)screen.obj $(OUTPRE)encrypt.obj \ + $(OUTPRE)genget.obj + +##### Options +# Set NODEBUG if building release instead of debug +!IF ! defined(KVERSION) +KRBOPT =-DFORWARD -DAUTHENTICATION -DENCRYPTION -DDES_ENCRYPTION +KVERSION= 5 +!endif +KRB = KRB$(KVERSION) + +BUILDTOP=..\.. +LOCALINCLUDES= /I$(BUILDTOP) /I$(BUILDTOP)\include /I$(BUILDTOP)\include\krb5 \ + /I$(BUILDTOP)\lib\crypto\des +RESFILE = $(OUTPRE)telnet.res +XOBJS = $(RESFILE) $(OUTPRE)k5stream.obj $(OUTPRE)enc_des.obj + +DEFINES = /D$(KRB)=1 $(KRBOPT) +RFLAGS = $(LOCALINCLUDES) +RCFLAGS = $(RFLAGS) -D_WIN32 -DTELNET_APP + +##### Linker +LINK = link +LIBS = $(KLIB) $(CLIB) $(WLIB) +SYSLIBS = kernel32.lib ws2_32.lib user32.lib gdi32.lib comdlg32.lib +LFLAGS = /nologo $(LOPTS) + +all:: Makefile $(OUTPRE)telnet.exe + +$(OUTPRE)telnet.exe: telnet.def $(OBJS) $(XOBJS) $(LIBS) + $(LINK) $(LFLAGS) /map:$*.map /out:$@ $(OBJS) $(XOBJS) \ + $(LIBS) $(SYSLIBS) + +install:: + copy $(OUTPRE)telnet.exe $(DESTDIR) + +clean:: + $(RM) $(OUTPRE)*.exe $(OUTPRE)*.res $(OUTPRE)*.map + +$(RESFILE): ..\version.rc diff --git a/mechglue/src/windows/wintel/auth.c b/mechglue/src/windows/wintel/auth.c new file mode 100644 index 000000000..28f515b6c --- /dev/null +++ b/mechglue/src/windows/wintel/auth.c @@ -0,0 +1,867 @@ +/* + * Implements Kerberos 4 authentication + */ + +#ifdef KRB4 +#include <windows.h> +#include <time.h> +#include <string.h> +#include "winsock.h" +#include "kerberos.h" +#endif +#ifdef KRB5 +#include <time.h> +#include <string.h> +#include "krb5.h" +#include "com_err.h" +#endif + +#include "telnet.h" +#include "telnet_arpa.h" + +#ifdef ENCRYPTION +#include "encrypt.h" +#endif + +/* + * Constants + */ +#ifdef KRB4 +#define KRB_AUTH 0 +#define KRB_REJECT 1 +#define KRB_ACCEPT 2 +#define KRB_CHALLENGE 3 +#define KRB_RESPONSE 4 +#endif +#ifdef KRB5 +#define KRB_AUTH 0 /* Authentication data follows */ +#define KRB_REJECT 1 /* Rejected (reason might follow) */ +#define KRB_ACCEPT 2 /* Accepted */ +#define KRB_RESPONSE 3 /* Response for mutual auth. */ + +#define KRB_FORWARD 4 /* Forwarded credentials follow */ +#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ +#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ +#endif + +#ifndef KSUCCESS /* Let K5 use K4 constants */ +#define KSUCCESS 0 +#define KFAILURE 255 +#endif + +/* + * Globals + */ +#ifdef KRB4 +static CREDENTIALS cred; +static KTEXT_ST auth; + +#define KRB_SERVICE_NAME "rcmd" +#define KERBEROS_VERSION KERBEROS_V4 + +static int auth_how; +static int k4_auth_send(kstream); +static int k4_auth_reply(kstream, unsigned char *, int); +#endif + +#ifdef KRB5 +static krb5_data auth; +static int auth_how; +static krb5_auth_context auth_context; +krb5_keyblock *session_key = NULL; +#ifdef FORWARD +void kerberos5_forward(kstream); +#endif + +#define KRB_SERVICE_NAME "host" +#define KERBEROS_VERSION AUTHTYPE_KERBEROS_V5 + +static int k5_auth_send(kstream, int); +static int k5_auth_reply(kstream, int, unsigned char *, int); +#endif + +static int Data(kstream, int, void *, int); + +#ifdef ENCRYPTION +BOOL encrypt_flag = 1; +#endif +#ifdef FORWARD +BOOL forward_flag = 1; /* forward tickets? */ +BOOL forwardable_flag = 1; /* get forwardable tickets to forward? */ +BOOL forwarded_tickets = 0; /* were tickets forwarded? */ +#endif + +static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, + AUTHTYPE_KERBEROS_V5, }; + +static int +Data(kstream ks, int type, void *d, int c) +{ + unsigned char *p = str_data + 4; + unsigned char *cd = (unsigned char *)d; + + if (c == -1) + c = strlen((char *)cd); + + *p++ = AUTHTYPE_KERBEROS_V5; + *p = AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL; +#ifdef ENCRYPTION + *p |= AUTH_ENCRYPT_ON; +#endif + p++; + *p++ = type; + while (c-- > 0) { + if ((*p++ = *cd++) == IAC) + *p++ = IAC; + } + *p++ = IAC; + *p++ = SE; + + return(TelnetSend(ks, (LPSTR)str_data, p - str_data, 0)); +} + +#ifdef ENCRYPTION +/* + * Function: Enable or disable the encryption process. + * + * Parameters: + * enable - TRUE to enable, FALSE to disable. + */ +static void +auth_encrypt_enable(BOOL enable) +{ + encrypt_flag = enable; +} +#endif + +/* + * Function: Abort the authentication process + * + * Parameters: + * ks - kstream to send abort message to. + */ +static void +auth_abort(kstream ks, char *errmsg, long r) +{ + char buf[9]; + + wsprintf(buf, "%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, + TELQUAL_IS, AUTHTYPE_NULL, + AUTHTYPE_NULL, IAC, SE); + TelnetSend(ks, (LPSTR)buf, 8, 0); + + if (errmsg != NULL) { + strTmp[sizeof(strTmp) - 1] = '\0'; + strncpy(strTmp, errmsg, sizeof(strTmp) - 1); + + if (r != KSUCCESS) { + strncat(strTmp, "\n", sizeof(strTmp) - 1 - strlen(strTmp)); +#ifdef KRB4 + lstrcat(strTmp, krb_get_err_text((int)r)); +#endif +#ifdef KRB5 + lstrcat(strTmp, error_message(r)); +#endif + } + + MessageBox(HWND_DESKTOP, strTmp, "Kerberos authentication failed!", + MB_OK | MB_ICONEXCLAMATION); + } +} + + +/* + * Function: Copy data to buffer, doubling IAC character if present. + * + * Parameters: + * kstream - kstream to send abort message to. + */ +static int +copy_for_net(unsigned char *to, unsigned char *from, int c) +{ + int n; + + n = c; + + while (c-- > 0) { + if ((*to++ = *from++) == IAC) { + n++; + *to++ = IAC; + } + } + + return n; +} + + +/* + * Function: Parse authentication send command + * + * Parameters: + * ks - kstream to send abort message to. + * + * parsedat - the sub-command data. + * + * end_sub - index of the character in the 'parsedat' array which + * is the last byte in a sub-negotiation + * + * Returns: Kerberos error code. + */ +static int +auth_send(kstream ks, unsigned char *parsedat, int end_sub) +{ + char buf[2048]; /* be sure that this is > auth.length+9 */ + char *pname; + int plen; + int r; + int i; + + auth_how = -1; + + for (i = 2; i+1 <= end_sub; i += 2) { + if (parsedat[i] == KERBEROS_VERSION) + if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) { + auth_how = parsedat[i+1] & AUTH_HOW_MASK; + break; + } + } + + if (auth_how == -1) { + auth_abort(ks, NULL, 0); + return KFAILURE; + } + +#ifdef KRB4 + r = k4_auth_send(ks); +#endif /* KRB4 */ + +#ifdef KRB5 + r = k5_auth_send(ks, auth_how); +#endif /* KRB5 */ + + if (!r) + return KFAILURE; + + plen = strlen(szUserName); /* Set by k#_send if needed */ + pname = szUserName; + + wsprintf(buf, "%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME); + memcpy(&buf[4], pname, plen); + wsprintf(&buf[plen + 4], "%c%c", IAC, SE); + TelnetSend(ks, (LPSTR)buf, lstrlen(pname)+6, 0); + + wsprintf(buf, "%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_IS, + KERBEROS_VERSION, auth_how | AUTH_WHO_CLIENT, KRB_AUTH); + +#if KRB4 + auth.length = copy_for_net(&buf[7], auth.dat, auth.length); +#endif /* KRB4 */ +#if KRB5 + auth.length = copy_for_net(&buf[7], auth.data, auth.length); +#endif /* KRB5 */ + + wsprintf(&buf[auth.length+7], "%c%c", IAC, SE); + + TelnetSend(ks, (LPSTR)buf, auth.length+9, 0); + + return KSUCCESS; +} + +/* + * Function: Parse authentication reply command + * + * Parameters: + * ks - kstream to send abort message to. + * + * parsedat - the sub-command data. + * + * end_sub - index of the character in the 'parsedat' array which + * is the last byte in a sub-negotiation + * + * Returns: Kerberos error code. + */ +static int +auth_reply(kstream ks, unsigned char *parsedat, int end_sub) +{ + int n; + +#ifdef KRB4 + n = k4_auth_reply(ks, parsedat, end_sub); +#endif + +#ifdef KRB5 + n = k5_auth_reply(ks, auth_how, parsedat, end_sub); +#endif + + return n; +} + +/* + * Function: Parse the athorization sub-options and reply. + * + * Parameters: + * ks - kstream to send abort message to. + * + * parsedat - sub-option string to parse. + * + * end_sub - last charcter position in parsedat. + */ +void +auth_parse(kstream ks, unsigned char *parsedat, int end_sub) +{ + if (parsedat[1] == TELQUAL_SEND) + auth_send(ks, parsedat, end_sub); + + if (parsedat[1] == TELQUAL_REPLY) + auth_reply(ks, parsedat, end_sub); +} + + +/* + * Function: Initialization routine called kstream encryption system. + * + * Parameters: + * str - kstream to send abort message to. + * + * data - user data. + */ +int +auth_init(kstream str, kstream_ptr data) +{ +#ifdef ENCRYPTION + encrypt_init(str, data); +#endif + return 0; +} + + +/* + * Function: Destroy routine called kstream encryption system. + * + * Parameters: + * str - kstream to send abort message to. + * + * data - user data. + */ +void +auth_destroy(kstream str) +{ +} + + +/* + * Function: Callback to encrypt a block of characters + * + * Parameters: + * out - return as pointer to converted buffer. + * + * in - the buffer to convert + * + * str - the stream being encrypted + * + * Returns: number of characters converted. + */ +int +auth_encrypt(struct kstream_data_block *out, + struct kstream_data_block *in, + kstream str) +{ + out->ptr = in->ptr; + + out->length = in->length; + + return(out->length); +} + + +/* + * Function: Callback to decrypt a block of characters + * + * Parameters: + * out - return as pointer to converted buffer. + * + * in - the buffer to convert + * + * str - the stream being encrypted + * + * Returns: number of characters converted. + */ +int +auth_decrypt(struct kstream_data_block *out, + struct kstream_data_block *in, + kstream str) +{ + out->ptr = in->ptr; + + out->length = in->length; + + return(out->length); +} + +#ifdef KRB4 +/* + * + * K4_auth_send - gets authentication bits we need to send to KDC. + * + * Result is left in auth + * + * Returns: 0 on failure, 1 on success + */ +static int +k4_auth_send(kstream ks) +{ + int r; /* Return value */ + char instance[INST_SZ]; + char *realm; + char buf[256]; + + memset(instance, 0, sizeof(instance)); + + if (realm = krb_get_phost(szHostName)) + lstrcpy(instance, realm); + + realm = krb_realmofhost(szHostName); + + if (!realm) { + strcpy(buf, "Can't find realm for host \""); + strncat(buf, szHostName, sizeof(buf) - 1 - strlen(buf)); + strncat(buf, "\"", sizeof(buf) - 1 - strlen(buf)); + auth_abort(ks, buf, 0); + return KFAILURE; + } + + r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0); + + if (r == 0) + r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred); + + if (r) { + strcpy(buf, "Can't get \""); + strncat(buf, KRB_SERVICE_NAME, sizeof(buf) - 1 - strlen(buf)); + if (instance[0] != 0) { + strncat(buf, ".", sizeof(buf) - 1 - strlen(buf)); + lstrcat(buf, instance); + } + strncat(buf, "@", sizeof(buf) - 1 - strlen(buf)); + lstrcat(buf, realm); + strncat(buf, "\" ticket", sizeof(buf) - 1 - strlen(buf)); + auth_abort(ks, buf, r); + + return r; + } + + if (!szUserName[0]) /* Copy if not there */ + strcpy(szUserName, cred.pname); + + return(1); +} + +/* + * Function: K4 parse authentication reply command + * + * Parameters: + * ks - kstream to send abort message to. + * + * parsedat - the sub-command data. + * + * end_sub - index of the character in the 'parsedat' array which + * is the last byte in a sub-negotiation + * + * Returns: Kerberos error code. + */ +static int +k4_auth_reply(kstream ks, unsigned char *parsedat, int end_sub) +{ + time_t t; + int x; + char buf[512]; + int i; + des_cblock session_key; + des_key_schedule sched; + static des_cblock challenge; + + if (end_sub < 4) + return KFAILURE; + + if (parsedat[2] != KERBEROS_V4) + return KFAILURE; + + if (parsedat[4] == KRB_REJECT) { + buf[0] = 0; + + for (i = 5; i <= end_sub; i++) { + if (parsedat[i] == IAC) + break; + buf[i-5] = parsedat[i]; + buf[i-4] = 0; + } + + if (!buf[0]) + strcpy(buf, "Authentication rejected by remote machine!"); + MessageBox(HWND_DESKTOP, buf, NULL, MB_OK | MB_ICONEXCLAMATION); + + return KFAILURE; + } + + if (parsedat[4] == KRB_ACCEPT) { + if ((parsedat[3] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY) + return KSUCCESS; + + if ((parsedat[3] & AUTH_HOW_MASK) != AUTH_HOW_MUTUAL) + return KFAILURE; + + des_key_sched(cred.session, sched); + + t = time(NULL); + memcpy(challenge, &t, 4); + memcpy(&challenge[4], &t, 4); + des_ecb_encrypt(&challenge, &session_key, sched, 1); + + /* + * Increment the challenge by 1, and encrypt it for + * later comparison. + */ + for (i = 7; i >= 0; --i) { + x = (unsigned int)challenge[i] + 1; + challenge[i] = x; /* ignore overflow */ + if (x < 256) /* if no overflow, all done */ + break; + } + + des_ecb_encrypt(&challenge, &challenge, sched, 1); + + wsprintf(buf, "%c%c%c%c%c%c%c", IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_IS, + KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, KRB_CHALLENGE); + memcpy(&buf[7], session_key, 8); + wsprintf(&buf[15], "%c%c", IAC, SE); + TelnetSend(ks, (LPSTR)buf, 17, 0); + + return KSUCCESS; + } + + if (parsedat[4] == KRB_RESPONSE) { + if (end_sub < 12) + return KFAILURE; + + if (memcmp(&parsedat[5], challenge, sizeof(challenge)) != 0) { + MessageBox(HWND_DESKTOP, "Remote machine is being impersonated!", + NULL, MB_OK | MB_ICONEXCLAMATION); + + return KFAILURE; + } + + return KSUCCESS; + } + + return KFAILURE; + +} + +#endif /* KRB4 */ + +#ifdef KRB5 + +/* + * + * K5_auth_send - gets authentication bits we need to send to KDC. + * + * Code lifted from telnet sample code in the appl directory. + * + * Result is left in auth + * + * Returns: 0 on failure, 1 on success + * + */ + +static int +k5_auth_send(kstream ks, int how) +{ + krb5_error_code r; + krb5_ccache ccache; + krb5_creds creds; + krb5_creds * new_creds; + extern krb5_flags krb5_kdc_default_options; + krb5_flags ap_opts; + char type_check[2]; + krb5_data check_data; + int len; +#ifdef ENCRYPTION + krb5_keyblock *newkey = 0; +#endif + + if (r = krb5_cc_default(k5_context, &ccache)) { + com_err(NULL, r, "while authorizing."); + return(0); + } + + memset((char *)&creds, 0, sizeof(creds)); + if (r = krb5_sname_to_principal(k5_context, szHostName, KRB_SERVICE_NAME, + KRB5_NT_SRV_HST, &creds.server)) { + com_err(NULL, r, "while authorizing."); + return(0); + } + + if (r = krb5_cc_get_principal(k5_context, ccache, &creds.client)) { + com_err(NULL, r, "while authorizing."); + krb5_free_cred_contents(k5_context, &creds); + return(0); + } + if (szUserName[0] == '\0') { /* Get user name now */ + len = krb5_princ_component(k5_context, creds.client, 0)->length; + memcpy(szUserName, + krb5_princ_component(k5_context, creds.client, 0)->data, + len); + szUserName[len] = '\0'; + } + + if (r = krb5_get_credentials(k5_context, 0, + ccache, &creds, &new_creds)) { + com_err(NULL, r, "while authorizing."); + krb5_free_cred_contents(k5_context, &creds); + return(0); + } + + ap_opts = 0; + if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) + ap_opts = AP_OPTS_MUTUAL_REQUIRED; + +#ifdef ENCRYPTION + ap_opts |= AP_OPTS_USE_SUBKEY; +#endif + + if (auth_context) { + krb5_auth_con_free(k5_context, auth_context); + auth_context = 0; + } + if ((r = krb5_auth_con_init(k5_context, &auth_context))) { + com_err(NULL, r, "while initializing auth context"); + return(0); + } + + krb5_auth_con_setflags(k5_context, auth_context, + KRB5_AUTH_CONTEXT_RET_TIME); + + type_check[0] = AUTHTYPE_KERBEROS_V5; + type_check[1] = AUTH_WHO_CLIENT| (how & AUTH_HOW_MASK); +#ifdef ENCRYPTION + type_check[1] |= AUTH_ENCRYPT_ON; +#endif + check_data.magic = KV5M_DATA; + check_data.length = 2; + check_data.data = (char *)&type_check; + + r = krb5_mk_req_extended(k5_context, &auth_context, ap_opts, + NULL, new_creds, &auth); + +#ifdef ENCRYPTION + krb5_auth_con_getlocalsubkey(k5_context, auth_context, &newkey); + if (session_key) { + krb5_free_keyblock(k5_context, session_key); + session_key = 0; + } + + if (newkey) { + /* + * keep the key in our private storage, but don't use it + * yet---see kerberos5_reply() below + */ + if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) && + (newkey-> enctype != ENCTYPE_DES_CBC_MD5)) { + if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) || + (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5)) + /* use the session key in credentials instead */ + krb5_copy_keyblock(k5_context, &new_creds->keyblock, &session_key); + else + ; /* What goes here? XXX */ + } else { + krb5_copy_keyblock(k5_context, newkey, &session_key); + } + krb5_free_keyblock(k5_context, newkey); + } +#endif /* ENCRYPTION */ + + krb5_free_cred_contents(k5_context, &creds); + krb5_free_creds(k5_context, new_creds); + + if (r) { + com_err(NULL, r, "while authorizing."); + return(0); + } + + return(1); +} + +/* + * + * K5_auth_reply -- checks the reply for mutual authentication. + * + * Code lifted from telnet sample code in the appl directory. + * + */ +static int +k5_auth_reply(kstream ks, int how, unsigned char *data, int cnt) +{ +#ifdef ENCRYPTION + Session_Key skey; +#endif + static int mutual_complete = 0; + + data += 4; /* Point to status byte */ + + switch (*data++) { + case KRB_REJECT: + if (cnt > 0) { + char *s; + wsprintf(strTmp, "Kerberos V5 refuses authentication because\n\t"); + s = strTmp + strlen(strTmp); + strncpy(s, data, cnt); + s[cnt] = 0; + } else + wsprintf(strTmp, "Kerberos V5 refuses authentication"); + MessageBox(HWND_DESKTOP, strTmp, "", MB_OK | MB_ICONEXCLAMATION); + + return KFAILURE; + + case KRB_ACCEPT: + if (!mutual_complete) { + if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !mutual_complete) { + wsprintf(strTmp, + "Kerberos V5 accepted you, but didn't provide" + " mutual authentication"); + MessageBox(HWND_DESKTOP, strTmp, "", MB_OK | MB_ICONEXCLAMATION); + return KFAILURE; + } +#ifdef ENCRYPTION + if (session_key) { + skey.type = SK_DES; + skey.length = 8; + skey.data = session_key->contents; + encrypt_session_key(&skey, 0); + } +#endif + } + +#ifdef FORWARD + if (forward_flag) + kerberos5_forward(ks); +#endif + + return KSUCCESS; + break; + + case KRB_RESPONSE: + if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { + /* the rest of the reply should contain a krb_ap_rep */ + krb5_ap_rep_enc_part *reply; + krb5_data inbuf; + krb5_error_code r; + + inbuf.length = cnt; + inbuf.data = (char *)data; + + if (r = krb5_rd_rep(k5_context, auth_context, &inbuf, &reply)) { + com_err(NULL, r, "while authorizing."); + return KFAILURE; + } + krb5_free_ap_rep_enc_part(k5_context, reply); + +#ifdef ENCRYPTION + if (encrypt_flag && session_key) { + skey.type = SK_DES; + skey.length = 8; + skey.data = session_key->contents; + encrypt_session_key(&skey, 0); + } +#endif + mutual_complete = 1; + } + return KSUCCESS; + +#ifdef FORWARD + case KRB_FORWARD_ACCEPT: + forwarded_tickets = 1; + return KSUCCESS; + + case KRB_FORWARD_REJECT: + forwarded_tickets = 0; + if (cnt > 0) { + char *s; + + wsprintf(strTmp, + "Kerberos V5 refuses forwarded credentials because\n\t"); + s = strTmp + strlen(strTmp); + strncpy(s, data, cnt); + s[cnt] = 0; + } else + wsprintf(strTmp, "Kerberos V5 refuses forwarded credentials"); + + MessageBox(HWND_DESKTOP, strTmp, "", MB_OK | MB_ICONEXCLAMATION); + return KFAILURE; +#endif /* FORWARD */ + + default: + return KFAILURE; /* Unknown reply type */ + } +} + +#ifdef FORWARD +void +kerberos5_forward(kstream ks) +{ + krb5_error_code r; + krb5_ccache ccache; + krb5_principal client = 0; + krb5_principal server = 0; + krb5_data forw_creds; + + forw_creds.data = 0; + + if ((r = krb5_cc_default(k5_context, &ccache))) { + com_err(NULL, r, "Kerberos V5: could not get default ccache"); + return; + } + + if ((r = krb5_cc_get_principal(k5_context, ccache, &client))) { + com_err(NULL, r, "Kerberos V5: could not get default principal"); + goto cleanup; + } + + if ((r = krb5_sname_to_principal(k5_context, szHostName, KRB_SERVICE_NAME, + KRB5_NT_SRV_HST, &server))) { + com_err(NULL, r, "Kerberos V5: could not make server principal"); + goto cleanup; + } + + if ((r = krb5_auth_con_genaddrs(k5_context, auth_context, ks->fd, + KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) { + com_err(NULL, r, "Kerberos V5: could not gen local full address"); + goto cleanup; + } + + if (r = krb5_fwd_tgt_creds(k5_context, auth_context, 0, client, server, + ccache, forwardable_flag, &forw_creds)) { + com_err(NULL, r, "Kerberos V5: error getting forwarded creds"); + goto cleanup; + } + + /* Send forwarded credentials */ + if (!Data(ks, KRB_FORWARD, forw_creds.data, forw_creds.length)) { + MessageBox(HWND_DESKTOP, + "Not enough room for authentication data", "", + MB_OK | MB_ICONEXCLAMATION); + } + +cleanup: + if (client) + krb5_free_principal(k5_context, client); + if (server) + krb5_free_principal(k5_context, server); +#if 0 /* XXX */ + if (forw_creds.data) + free(forw_creds.data); +#endif + krb5_cc_close(k5_context, ccache); +} +#endif /* FORWARD */ + +#endif /* KRB5 */ diff --git a/mechglue/src/windows/wintel/auth.h b/mechglue/src/windows/wintel/auth.h new file mode 100644 index 000000000..e0f60ec40 --- /dev/null +++ b/mechglue/src/windows/wintel/auth.h @@ -0,0 +1,28 @@ +/* + * Implements Kerberos 4 authentication and ecryption + */ + +#ifndef WINTEL_AUTH_H +#define WINTEL_AUTH_H + +void auth_parse(kstream, unsigned char *, int); + +int auth_init(kstream, kstream_ptr); + +void auth_destroy(kstream); + +int auth_encrypt(struct kstream_data_block *, struct kstream_data_block *, + kstream); + +int auth_decrypt(struct kstream_data_block *, struct kstream_data_block *, + kstream); + +extern BOOL forward_flag; +extern BOOL forwardable_flag; +extern BOOL forwarded_tickets; + +#ifdef ENCRYPTION +extern BOOL encrypt_flag; +#endif + +#endif /* WINTEL_AUTH_H */ diff --git a/mechglue/src/windows/wintel/dialog.h b/mechglue/src/windows/wintel/dialog.h new file mode 100644 index 000000000..c95ec0491 --- /dev/null +++ b/mechglue/src/windows/wintel/dialog.h @@ -0,0 +1,42 @@ +#define IDM_SHOWCONSOLE 700 + +#define IDM_OPENTELNETDLG 200 +#define TEL_CONNECT_NAME 201 +#define TEL_USEDEFAULTS 202 +#define TEL_MANUALCONFIGURE 203 +#define TEL_OK 204 +#define TEL_CANCEL 206 +#define IDC_FORWARD 207 +#define IDC_FORWARDFORWARD 208 +#define IDC_ENCRYPT 210 +#define TEL_CONNECT_USERID 211 + +#define IDM_SEND_IP 800 +#define IDM_SEND_AYT 801 +#define IDM_SEND_ABORT 802 + +#define CON_SESSIONNAME 302 +#define CON_WINDOWTITLE 304 +#define CON_COLUMNS132 305 +#define CON_COLUMNS80 306 +#define CON_BACKSPACE 307 +#define CON_DELETE 308 +#define CON_CRLF 309 +#define CON_CRNUL 310 +#define CON_BUFFERS 311 +#define CON_SENDS 312 +#define CON_OK 320 +#define CON_USEDEFAULTS 321 +#define CONFIGDLG 300 +#define CON_SCRLBCK 317 +#define CON_NUMLINES 318 + +#define PRINTQUEUE 400 + +#define IDM_PRINTQUEUE 500 + +#define TEL_PUSH1 601 +#define TEL_PUSH2 602 +#define TEL_PUSH3 603 +#define TEL_PUSH4 604 +#define TEL_PUSH5 605 diff --git a/mechglue/src/windows/wintel/edit.c b/mechglue/src/windows/wintel/edit.c new file mode 100644 index 000000000..aa230cfc9 --- /dev/null +++ b/mechglue/src/windows/wintel/edit.c @@ -0,0 +1,444 @@ +/* edit.c */ + +#include <windows.h> +#include <commdlg.h> +#include <ctype.h> +#include <assert.h> +#include "screen.h" + +char *cInvertedArray; +int bMouseDown = FALSE; +int bSelection; + +static int iLocStart; +static int iLocEnd; + +void Edit_LbuttonDown( + HWND hWnd, + LPARAM lParam) +{ + SCREEN *pScr; + HMENU hMenu; + int iTmp; + int iXlocStart; + int iYlocStart; + HDC hDC; + + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert(pScr != NULL); + + hDC = GetDC(hWnd); + for (iTmp = 0; iTmp < pScr->width * pScr->height; iTmp++) { + if (cInvertedArray[iTmp]) { + PatBlt(hDC, iTmp % pScr->width * pScr->cxChar, + (int) (iTmp / pScr->width) * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp] = 0; + } + } + bSelection = FALSE; + hMenu = GetMenu(hWnd); + EnableMenuItem(hMenu, IDM_COPY, MF_GRAYED); + ReleaseDC(hWnd, hDC); + iXlocStart = (int) LOWORD(lParam) / pScr->cxChar; + if (iXlocStart >= pScr->width) + iXlocStart = pScr->width - 1; + iYlocStart = (int) HIWORD(lParam) / pScr->cyChar; + if (iYlocStart >= pScr->height) + iYlocStart = pScr->height - 1; + iLocStart = iXlocStart + iYlocStart * pScr->width; + bMouseDown = TRUE; + +} /* Edit_LbuttonDown */ + + +void Edit_LbuttonUp( + HWND hWnd, + LPARAM lParam) +{ + SCREEN *pScr; + int iTmp; + int iTmp2; + HMENU hMenu; + + bMouseDown = FALSE; + if (bSelection) + return; + bSelection = TRUE; + + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert(pScr != NULL); + + iTmp = (int) LOWORD(lParam) / pScr->cxChar; + if (iTmp >= pScr->width) + iTmp = pScr->width - 1; + iTmp2 = (int) HIWORD(lParam) / pScr->cyChar; + if (iTmp2 >= pScr->height) + iTmp2 = pScr->height - 1; + iLocEnd = iTmp + iTmp2 * pScr->width; + if (iLocEnd == iLocStart) { + bSelection = FALSE; + } + else { + hMenu = GetMenu(hWnd); + EnableMenuItem(hMenu, IDM_COPY, MF_ENABLED); + } + +} /* Edit_LbuttonUp */ + + +void Edit_MouseMove(HWND hWnd, LPARAM lParam){ + SCREEN *pScr; + int iTmp; + int iTmp2; + int iXlocCurr; + int iYlocCurr; + int iLocCurr; + int iX; + int iX2; + int iY; + int iY2; + SCREENLINE *pScrLine; + HDC hDC; + + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert(pScr != NULL); + + hDC = GetDC(hWnd); + iXlocCurr = (int) LOWORD(lParam) / pScr->cxChar; + if (iXlocCurr >= pScr->width) + iXlocCurr = pScr->width - 1; + iYlocCurr = (int) HIWORD(lParam) / pScr->cyChar; + if (iYlocCurr >= pScr->height) + iYlocCurr = pScr->height - 1; + iLocCurr = iXlocCurr + (iYlocCurr * pScr->width); + if (iLocCurr > iLocStart) { + for (iTmp=0; iTmp < iLocStart; iTmp++) { + if (cInvertedArray[iTmp]) { + PatBlt(hDC, (iTmp % pScr->width) * pScr->cxChar, + (int) (iTmp / pScr->width) * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp] = 0; + } + } + iX = iLocStart % pScr->width; + iY = (int) (iLocStart / pScr->width); + iX2 = iLocCurr % pScr->width; + iY2 = (int) (iLocCurr / pScr->width); + if (iY == iY2) { + pScrLine = GetScreenLineFromY(pScr, iY); + for (iTmp2 = iX; iTmp2 < iX2; iTmp2++) { + if ((!cInvertedArray[iTmp2 + (pScr->width * iY)]) && pScrLine->text[iTmp2]) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iY * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (pScr->width * iY)] = pScrLine->text[iTmp2]; + } + } + } + else { + pScrLine = GetScreenLineFromY(pScr, iY); + + for (iTmp2 = iX; iTmp2 < pScr->width; iTmp2++) { + if ((!cInvertedArray[iTmp2 + (pScr->width * iY)]) && pScrLine->text[iTmp2]) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iY * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (pScr->width * iY)] = pScrLine->text[iTmp2]; + } + } + + for (iTmp = iY + 1; iTmp < iY2; iTmp++) { + pScrLine = GetScreenLineFromY(pScr, iTmp); + for (iTmp2 = 0; iTmp2 < pScr->width; iTmp2++) { + if ((!cInvertedArray[iTmp2 + (pScr->width * iTmp)]) && pScrLine->text[iTmp2]) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iTmp * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (pScr->width * iTmp)] = pScrLine->text[iTmp2]; + } + } + } + + if (iY2 != iY) { + pScrLine = GetScreenLineFromY(pScr, iY2); + for (iTmp2 = 0; iTmp2 < iX2; iTmp2++) { + if ((!cInvertedArray[iTmp2 + (pScr->width * iY2)]) && pScrLine->text[iTmp2]) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iY2 * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (pScr->width * iY2)] = pScrLine->text[iTmp2]; + } + } + } + } + + for (iTmp = iLocCurr; iTmp < pScr->width * pScr->height; iTmp++) { + if (cInvertedArray[iTmp]) { + PatBlt(hDC, (iTmp % pScr->width) * pScr->cxChar, (int) (iTmp / pScr->width) * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp] = 0; + } + } + } + else { /* going backwards */ + for (iTmp = 0; iTmp < iLocCurr; iTmp++) { + if (cInvertedArray[iTmp]) { + PatBlt(hDC, (iTmp % pScr->width) * pScr->cxChar, (int) (iTmp / pScr->width) * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp] = 0; + } + } + iX = iLocCurr % pScr->width; + iY = (int) (iLocCurr / pScr->width); + iX2 = (iLocStart % pScr->width); + iY2 = (int) (iLocStart / pScr->width); + if (iY == iY2) { + pScrLine = GetScreenLineFromY(pScr, iY); + for (iTmp2= iX; iTmp2 < iX2; iTmp2++) { + if ((!cInvertedArray[iTmp2 + (pScr->width * iY)]) && pScrLine->text[iTmp2]) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iY * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (pScr->width * iY)] = pScrLine->text[iTmp2]; + } + } + } + else { + pScrLine = GetScreenLineFromY(pScr, iY); + for (iTmp2 = iX; iTmp2 < pScr->width; iTmp2++) { + if ((!cInvertedArray[iTmp2 + (pScr->width * iY)]) && pScrLine->text[iTmp2]) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iY * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (pScr->width * iY)] = pScrLine->text[iTmp2]; + } + } + for (iTmp = iY + 1; iTmp < iY2; iTmp++) { + pScrLine = GetScreenLineFromY(pScr, iTmp); + for (iTmp2 = 0; iTmp2 < pScr->width; iTmp2++) { + if ((!cInvertedArray[iTmp2 + (pScr->width * iTmp)]) && pScrLine->text[iTmp2]) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iTmp * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (pScr->width * iTmp)] = pScrLine->text[iTmp2]; + } + } + } + if (iY2 != iY) { + pScrLine = GetScreenLineFromY(pScr, iY2); + for (iTmp2 = 0; iTmp2 < iX2; iTmp2++) { + if ((!cInvertedArray[iTmp2 + (pScr->width * iY2)]) && pScrLine->text[iTmp2]) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iY2 * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (pScr->width * iY2)] = pScrLine->text[iTmp2]; + } + } + } + } + for (iTmp = iLocStart; iTmp < pScr->width * pScr->height; iTmp++) { + if (cInvertedArray[iTmp]) { + PatBlt(hDC, (iTmp % pScr->width) * pScr->cxChar, (int) (iTmp / pScr->width) * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp] = 0; + } + } + } + ReleaseDC(hWnd, hDC); +} /* Edit_MouseMove */ + + +void Edit_ClearSelection( + SCREEN *pScr) +{ + int iTmp; + HDC hDC; + HMENU hMenu; + + hDC = GetDC(pScr->hWnd); + for (iTmp = 0; iTmp < pScr->width * pScr->height; iTmp++) { + if (cInvertedArray[iTmp]) { + PatBlt(hDC, (iTmp % pScr->width) * pScr->cxChar, + (int) (iTmp / pScr->width) * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp] = 0; + } + } + bSelection = FALSE; + hMenu=GetMenu(pScr->hWnd); + EnableMenuItem(hMenu, IDM_COPY, MF_GRAYED); + ReleaseDC(pScr->hWnd, hDC); +} /* Edit_ClearSelection */ + + +void Edit_Copy( + HWND hWnd) +{ + int iTmp,iIdx; + HGLOBAL hCutBuffer; + LPSTR lpCutBuffer; + SCREEN *pScr; + + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert(pScr != NULL); + + hCutBuffer= GlobalAlloc(GHND, (DWORD) (pScr->width * pScr->height + 1)); + lpCutBuffer= GlobalLock(hCutBuffer); + + if (iLocStart > iLocEnd) { /* swap variables */ + iTmp = iLocStart; + iLocStart = iLocEnd; + iLocEnd = iLocStart; + } + iTmp = iLocStart; + iIdx = 0; + while (iTmp < iLocEnd) { + if (!cInvertedArray[iTmp]) { + lpCutBuffer[iIdx++] = '\r'; + lpCutBuffer[iIdx++] = '\n'; + iTmp = (((int) (iTmp / pScr->width)) + 1) * pScr->width; + continue; + } + lpCutBuffer[iIdx++] = cInvertedArray[iTmp++]; + } + lpCutBuffer[iIdx] = 0; + GlobalUnlock(hCutBuffer); + OpenClipboard(hWnd); + EmptyClipboard(); + SetClipboardData(CF_TEXT, hCutBuffer); + CloseClipboard(); + +} /* Edit_Copy */ + + +void Edit_Paste( + HWND hWnd) +{ + HGLOBAL hClipMemory; + static HGLOBAL hMyClipBuffer; + LPSTR lpClipMemory; + LPSTR lpMyClipBuffer; + SCREEN *pScr; + + if (hMyClipBuffer) + GlobalFree(hMyClipBuffer); + OpenClipboard(hWnd); + hClipMemory = GetClipboardData(CF_TEXT); + hMyClipBuffer = GlobalAlloc(GHND, GlobalSize(hClipMemory)); + lpMyClipBuffer = GlobalLock(hMyClipBuffer); + lpClipMemory= GlobalLock(hClipMemory); + + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert(pScr != NULL); + + lstrcpy(lpMyClipBuffer, lpClipMemory); +#if 0 + OutputDebugString(lpMyClipBuffer); +#endif + PostMessage(pScr->hwndTel, WM_MYSCREENBLOCK, (WPARAM) hMyClipBuffer, (LPARAM) pScr); + CloseClipboard(); + GlobalUnlock(hClipMemory); + GlobalUnlock(hMyClipBuffer); + +} /* Edit_Paste */ + + +void Edit_LbuttonDblclk( + HWND hWnd, + LPARAM lParam) +{ + HDC hDC; + SCREEN *pScr; + int iTmp; + int iTmp2; + int iXlocStart; + int iYloc; + SCREENLINE *pScrLine; + + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert(pScr != NULL); + + hDC = GetDC(hWnd); + for (iTmp = 0; iTmp < pScr->width * pScr->height; iTmp++) { + if (cInvertedArray[iTmp]) { + PatBlt(hDC, (iTmp % pScr->width) * pScr->cxChar, + (int) (iTmp / pScr->width) * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp] = 0; + } + } + bSelection = FALSE; + iXlocStart = (int) LOWORD(lParam) / pScr->cxChar; + if (iXlocStart >= pScr->width) + iXlocStart = pScr->width - 1; + iYloc = (int) HIWORD(lParam) / pScr->cyChar; + if (iYloc >= pScr->height) + iYloc = pScr->height - 1; + iLocStart = iXlocStart + (iYloc * pScr->width); + + pScrLine = GetScreenLineFromY(pScr, iYloc); + + iTmp = iXlocStart; + while (isalnum((int) pScrLine->text[iTmp])) { + PatBlt(hDC, iTmp * pScr->cxChar, iYloc * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp + (iYloc * pScr->width)] = pScrLine->text[iTmp]; + iTmp++; + } + iTmp2 = iXlocStart - 1; + while (isalnum((int) pScrLine->text[iTmp2])) { + PatBlt(hDC, iTmp2 * pScr->cxChar, iYloc * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp2 + (iYloc * pScr->width)] = pScrLine->text[iTmp2]; + iTmp2--; + } + iLocStart = (iTmp2 + 1) + (iYloc * pScr->width); + iLocEnd = iTmp + (iYloc * pScr->width); + + bSelection = TRUE; + ReleaseDC(hWnd, hDC); + +} /* Edit_LbuttonDblclk */ + + +void Edit_TripleClick( + HWND hWnd, + LPARAM lParam) +{ + HDC hDC; + SCREEN *pScr; + int iTmp; + int iYloc; + SCREENLINE *pScrLine; + +#if 0 + OutputDebugString("Triple Click \r\n"); +#endif + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert(pScr != NULL); + + hDC = GetDC(hWnd); + for (iTmp = 0; iTmp < pScr->width * pScr->height; iTmp++) { + if (cInvertedArray[iTmp]) { + PatBlt(hDC, (iTmp % pScr->width) * pScr->cxChar, + (int) (iTmp / pScr->width) * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp] = 0; + } + } + bSelection = FALSE; + iYloc = (int) HIWORD(lParam) / pScr->cyChar; + if (iYloc >= pScr->height) + iYloc = pScr->height - 1; + iLocStart = iYloc * pScr->width; + + pScrLine = GetScreenLineFromY(pScr, iYloc); + + for (iTmp = 0; iTmp < pScr->width; iTmp++) { + if (pScrLine->text[iTmp]) { + PatBlt(hDC, iTmp * pScr->cxChar, iYloc * pScr->cyChar, + pScr->cxChar, pScr->cyChar, DSTINVERT); + cInvertedArray[iTmp + (iYloc * pScr->width)] = pScrLine->text[iTmp]; + } + else + break; + } + iLocEnd = iTmp + (iYloc * pScr->width); + + bSelection = TRUE; + ReleaseDC(hWnd, hDC); + +} /* Edit_TripleClick */ diff --git a/mechglue/src/windows/wintel/emul.c b/mechglue/src/windows/wintel/emul.c new file mode 100644 index 000000000..18547ab80 --- /dev/null +++ b/mechglue/src/windows/wintel/emul.c @@ -0,0 +1,766 @@ +/* emul.c */ + +#include "windows.h" +#include "screen.h" + + +static int +ScreenEmChars(SCREEN *pScr, char *c, int len) +{ + /* + * Function: Send a string of characters to the screen. Placement + * continues as long as the stream of characters does not contain any + * control chracters or cause wrapping to another line. When a control + * character is encountered or wrapping occurs, display stops and a + * count of the number of characters is returned. + * + * Parameters: + * pScr - the screen to place the characters on. + * c - the string of characters to place on the screen. + * len - the number of characters contained in the string + * + * Returns: The number of characters actually placed on the screen. + */ + + int insert; + int ocount; + int attrib; + int extra; + int nchars; + char *acurrent; /* place to put attributes */ + char *current; /* place to put characters */ + char *start; + SCREENLINE *pScrLine; + + if (len <= 0) + return(0); + + if (pScr->x != pScr->width - 1) + pScr->bWrapPending = FALSE; + else { + if (pScr->bWrapPending) { + pScr->x = 0; + pScr->bWrapPending = FALSE; + ScreenIndex(pScr); + } + } + + pScrLine = GetScreenLineFromY(pScr, pScr->y); + if (pScrLine == NULL) + return(0); + + current = &pScrLine->text[pScr->x]; + acurrent = &pScrLine->attrib[pScr->x]; + start = current; + ocount = pScr->x; + extra = 0; + + attrib = pScr->attrib; + insert = pScr->IRM; + + for (nchars = 0; nchars < len && *c >= 32; nchars++) { + if (insert) + ScreenInsChar(pScr, 1); + + *current = *c; + *acurrent = (char) attrib; + c++; + if (pScr->x < pScr->width - 1) { + acurrent++; + current++; + pScr->x++; + } + else { + extra = 1; + if (pScr->DECAWM) { + pScr->bWrapPending = TRUE; + nchars++; + break; + } + } + } + + ScreenDraw(pScr, ocount, pScr->y, pScr->attrib, + pScr->x - ocount + extra, start); + + return(nchars); +} + + +void +ScreenEm(LPSTR c, int len, SCREEN *pScr) +{ + int escflg; /* vt100 escape level */ + RECT rc; + unsigned int ic; + char stat[20]; + int i; + int nchars; + + if (pScr->screen_bottom != pScr->buffer_bottom) { + ScreenUnscroll(pScr); + InvalidateRect(pScr->hWnd, NULL, TRUE); + SetScrollPos(pScr->hWnd, SB_VERT, pScr->numlines, TRUE); + } + + ScreenCursorOff(pScr); + escflg = pScr->escflg; + +#ifdef UM + if (pScr->localprint && len > 0) { /* see if printer needs anything */ + pcount = send_localprint(c, len); + len -= pcount; + c += pcount; + } +#endif + + while (len > 0) { + /* + * look at first character in the vt100 string, if it is a + * non-printable ascii code + */ + while((*c < 32) && (escflg == 0) && (len > 0)) { + switch(*c) { + + case 0x1b: /* ESC found (begin vt100 control sequence) */ + escflg++; + break; + + case -1: /* IAC from telnet session */ + escflg = 6; + break; + +#ifdef CISB + case 0x05: /* CTRL-E found (answerback) */ + bp_ENQ(); + break; +#endif + + case 0x07: /* CTRL-G found (bell) */ + ScreenBell(pScr); + break; + + case 0x08: /* CTRL-H found (backspace) */ + ScreenBackspace(pScr); + break; + + case 0x09: /* CTRL-I found (tab) */ + ScreenTab(pScr); /* Later change for versatile tabbing */ + break; + + case 0x0a: /* CTRL-J found (line feed) */ + case 0x0b: /* CTRL-K found (treat as line feed) */ + case 0x0c: /* CTRL-L found (treat as line feed) */ + ScreenIndex(pScr); + break; + + case 0x0d: /* CTRL-M found (carriage feed) */ + ScreenCarriageFeed(pScr); + break; + +#if 0 + case 0x0e: /* CTRL-N found (invoke Graphics (G1) character set) */ + if (pScr->G1) + pScr->attrib = VSgraph(pScr->attrib); + else + pScr->attrib = VSnotgraph(pScr->attrib); + pScr->charset = 1; + break; + + case 0x0f: /* CTRL-O found (invoke 'normal' (G0) character set) */ + if(pScr->G0) + pScr->attrib = VSgraph(pScr->attrib); + else + pScr->attrib = VSnotgraph(pScr->attrib); + pScr->charset = 0; + break; +#endif + +#ifdef CISB + case 0x10: /* CTRL-P found (undocumented in vt100) */ + bp_DLE(c, len); + len = 0; + break; +#endif + +#if 0 + case 0x11: /* CTRL-Q found (XON) (unused presently) */ + case 0x13: /* CTRL-S found (XOFF) (unused presently) */ + case 0x18: /* CTRL-X found (CAN) (unused presently) */ + case 0x1a: /* CTRL-Z found (SUB) (unused presently) */ + break; +#endif + } + + c++; /* advance to the next character in the string */ + len--; /* decrement the counter */ + } + + if (escflg == 0) { /* check for normal character to print */ + nchars = ScreenEmChars(pScr, c, len); + c += nchars; + len -= nchars; + } + + while ((len > 0) && (escflg == 1)) { /* ESC character was found */ + switch(*c) { + + case 0x08: /* CTRL-H found (backspace) */ + ScreenBackspace(pScr); + break; + + /* + * mostly cursor movement options, and DEC private stuff following + */ + case '[': + ScreenApClear(pScr); + escflg = 2; + break; + + case '#': /* various screen adjustments */ + escflg = 3; + break; + + case '(': /* G0 character set options */ + escflg = 4; + break; + + case ')': /* G1 character set options */ + escflg = 5; + break; + + case '>': /* keypad numeric mode (DECKPAM) */ + pScr->DECPAM = 0; + escflg = 0; + break; + + case '=': /* keypad application mode (DECKPAM) */ + pScr->DECPAM = 1; + escflg = 0; + break; + + case '7': /* save cursor (DECSC) */ + ScreenSaveCursor(pScr); + escflg = 0; + break; + + case '8': /* restore cursor (DECRC) */ + ScreenRestoreCursor(pScr); + escflg = 0; + break; + +#if 0 + case 'c': /* reset to initial state (RIS) */ + ScreenReset(pScr); + escflg = 0; + break; +#endif + + case 'D': /* index (move down one line) (IND) */ + ScreenIndex(pScr); + escflg = 0; + break; + + case 'E': /* next line (move down one line and to first column) (NEL) */ + pScr->x = 0; + ScreenIndex(pScr); + escflg = 0; + break; + + case 'H': /* horizontal tab set (HTS) */ + pScr->tabs[pScr->x] = 'x'; + escflg = 0; + break; + +#ifdef CISB + case 'I': /* undoumented in vt100 */ + bp_ESC_I(); + break; +#endif + + case 'M': /* reverse index (move up one line) (RI) */ + ScreenRevIndex(pScr); + escflg = 0; + break; + + case 'Z': /* identify terminal (DECID) */ + escflg = 0; + break; + + default: + /* put the ESC character into the Screen */ + ScreenEmChars(pScr, "\033", 1); + /* put the next character into the Screen */ + ScreenEmChars(pScr, c, 1); + escflg = 0; + break; + + } /* end switch */ + + c++; + len--; + } + + while((escflg == 2) && (len > 0)) { /* '[' handling */ + switch(*c) { + + case 0x08: /* backspace */ + ScreenBackspace(pScr); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': /* numeric parameters */ + if (pScr->parms[pScr->parmptr] < 0) + pScr->parms[pScr->parmptr] = 0; + pScr->parms[pScr->parmptr] *= 10; + pScr->parms[pScr->parmptr] += *c - '0'; + break; + + case '?': /* vt100 mode change */ + pScr->parms[pScr->parmptr++] = -2; + break; + + case ';': /* parameter divider */ + pScr->parmptr++; + break; + + case 'A': /* cursor up (CUU) */ + pScr->bWrapPending = FALSE; + rc.left = pScr->x * pScr->cxChar; + rc.right = (pScr->x + 1) * pScr->cxChar; + rc.top = pScr->cyChar * pScr->y; + rc.bottom = pScr->cyChar * (pScr->y + 1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + if (pScr->parms[0] < 1) + pScr->y--; + else + pScr->y -= pScr->parms[0]; + if(pScr->y < pScr->top) + pScr->y = pScr->top; + ScreenRange(pScr); + escflg = 0; + SendMessage(pScr->hWnd, WM_PAINT, 0, 0); + break; + + case 'B': /* cursor down (CUD) */ + pScr->bWrapPending = FALSE; + rc.left = pScr->x * pScr->cxChar; + rc.right = (pScr->x + 1) * pScr->cxChar; + rc.top = pScr->cyChar * pScr->y; + rc.bottom = pScr->cyChar * (pScr->y + 1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + if (pScr->parms[0] < 1) + pScr->y++; + else + pScr->y += pScr->parms[0]; + if (pScr->y > pScr->bottom) + pScr->y = pScr->bottom; + ScreenRange(pScr); + escflg = 0; + SendMessage(pScr->hWnd, WM_PAINT, 0, 0); + break; + + case 'C': /* cursor forward (right) (CUF) */ + pScr->bWrapPending = FALSE; + rc.left = pScr->x * pScr->cxChar; + rc.right = (pScr->x + 1) * pScr->cxChar; + rc.top = pScr->cyChar * pScr->y; + rc.bottom = pScr->cyChar * (pScr->y +1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + if(pScr->parms[0] < 1) + pScr->x++; + else + pScr->x += pScr->parms[0]; + ScreenRange(pScr); + if (pScr->x > pScr->width) + pScr->x = pScr->width; + escflg = 0; + SendMessage(pScr->hWnd, WM_PAINT, 0, 0); + break; + + case 'D': /* cursor backward (left) (CUB) */ + pScr->bWrapPending = FALSE; + rc.left = pScr->x * pScr->cxChar; + rc.right = (pScr->x + 1) * pScr->cxChar; + rc.top = pScr->cyChar * pScr->y; + rc.bottom = pScr->cyChar * (pScr->y + 1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + if(pScr->parms[0] < 1) + pScr->x--; + else + pScr->x -= pScr->parms[0]; + ScreenRange(pScr); + escflg = 0; + SendMessage(pScr->hWnd, WM_PAINT, 0, 0); + break; + + case 'f': /* horizontal & vertical position (HVP) */ + case 'H': /* cursor position (CUP) */ + pScr->bWrapPending = FALSE; + rc.left = pScr->x * pScr->cxChar; + rc.right = (pScr->x + 1) * pScr->cxChar; + rc.top = pScr->cyChar * pScr->y; + rc.bottom = pScr->cyChar * (pScr->y + 1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + pScr->x = pScr->parms[1] - 1; + pScr->y = pScr->parms[0] - 1; + ScreenRange(pScr); /* make certain the cursor position is valid */ + escflg = 0; + SendMessage(pScr->hWnd, WM_PAINT, 0, 0); + break; + + case 'J': /* erase in display (ED) */ + switch(pScr->parms[0]) { + + case -1: + case 0: /* erase from active position to end of screen */ + ScreenEraseToEndOfScreen(pScr); + break; + case 1: /* erase from start of screen to active position */ +#if 0 + ScreenEraseToPosition(pScr); +#endif + break; + + case 2: /* erase whole screen */ + ScreenEraseScreen(pScr); + break; + + default: + break; + } + + escflg = 0; + break; + + case 'K': /* erase in line (EL) */ + switch(pScr->parms[0]) { + case -1: + case 0: /* erase to end of line */ + ScreenEraseToEOL(pScr); + break; + + case 1: /* erase to beginning of line */ + ScreenEraseToBOL(pScr); + break; + + case 2: /* erase whole line */ + ScreenEraseLine(pScr, -1); + break; + + default: + break; + } + + escflg = 0; + break; + + case 'L': /* insert n lines preceding current line (IL) */ + if (pScr->parms[0] < 1) + pScr->parms[0] = 1; + ScreenInsLines(pScr, pScr->parms[0], -1); + escflg = 0; + break; + + case 'M': /* delete n lines from current position downward (DL) */ + if (pScr->parms[0] < 1) + pScr->parms[0] = 1; + ScreenDelLines(pScr, pScr->parms[0], -1); + escflg = 0; + break; + + case 'P': /* delete n chars from cursor to the left (DCH) */ + if (pScr->parms[0] < 1) + pScr->parms[0] = 1; + ScreenDelChars(pScr, pScr->parms[0]); + escflg = 0; + break; + +#if 0 + case 'R': /* receive cursor position status from host */ + break; +#endif + +#if 0 + case 'c': /* device attributes (DA) */ + ScreenSendIdent(); + escflg = 0; + break; +#endif + + case 'g': /* tabulation clear (TBC) */ + if (pScr->parms[0] == 3)/* clear all tabs */ + ScreenTabClear(pScr); + else + if (pScr->parms[0] <= 0) /* clear tab stop at active position */ + pScr->tabs[pScr->x] = ' '; + escflg = 0; + break; + + case 'h': /* set mode (SM) */ + ScreenSetOption(pScr,1); + escflg = 0; + break; + + case 'i': /* toggle printer */ +#if 0 + if(pScr->parms[pScr->parmptr] == 5) + pScr->localprint = 1; + else if (pScr->parms[pScr->parmptr] == 4) + pScr->localprint = 0; +#endif + escflg = 0; + break; + + case 'l': /* reset mode (RM) */ + ScreenSetOption(pScr,0); + escflg = 0; + break; + + case 'm': /* select graphics rendition (SGR) */ + { + int temp = 0; + + while (temp <= pScr->parmptr) { + if (pScr->parms[temp] < 1) + pScr->attrib &= 128; + else + pScr->attrib |= 1 << (pScr->parms[temp] - 1); + temp++; + } + } + escflg = 0; + break; + + case 'n': /* device status report (DSR) */ + switch (pScr->parms[0]) { +#if 0 + case 0: /* response from vt100; ready, no malfunctions */ + case 3: /* response from vt100; malfunction, retry */ +#endif + case 5: /* send status */ + case 6: /* send active position */ + wsprintf(stat, "\033[%d;%dR", pScr->y + 1, pScr->x + 1); + for (i = 0; stat[i]; i++) + SendMessage(pScr->hwndTel, WM_MYSCREENCHAR, + stat[i], (LPARAM) pScr); + break; + } /* end switch */ + escflg = 0; + break; + + case 'q': /* load LEDs (unsupported) (DECLL) */ + escflg = 0; + break; + + case 'r': /* set top & bottom margins (DECSTBM) */ + if (pScr->parms[0] < 0) + pScr->top = 0; + else + pScr->top = pScr->parms[0] - 1; + if (pScr->parms[1] < 0) + pScr->bottom = pScr->height - 1; + else + pScr->bottom = pScr->parms[1] - 1; + if (pScr->top < 0) + pScr->top = 0; + if (pScr->top > pScr->height-1) + pScr->top = pScr->height-1; + if (pScr->bottom < 1) + pScr->bottom = pScr->height; + if (pScr->bottom >= pScr->height) + pScr->bottom = pScr->height - 1; + if (pScr->top >= pScr->bottom) {/* check for valid scrolling region */ + if (pScr->bottom >= 1) /* + * assume the bottom value has + * precedence, unless it is as the + * top of the screen + */ + pScr->top = pScr->bottom - 1; + else /* totally psychotic case, bottom of screen set to the very top line, move the bottom to below the top */ + pScr->bottom = pScr->top + 1; + } + pScr->x = 0; + pScr->y = 0; +#if 0 + if (pScr->DECORG) + pScr->y = pScr->top; /* origin mode relative */ +#endif + escflg = 0; + break; + +#if 0 + case 'x': /* request/report terminal parameters + (DECREQTPARM/DECREPTPARM) */ + case 'y': /* invoke confidence test (DECTST) */ + break; +#endif + + default: + escflg = 0; + break; + + } + + c++; + len--; + +#if 0 + if (pScr->localprint && (len > 0)) { /* see if printer needs anything */ + pcount = send_localprint(c, len); + len -= pcount; + c += pcount; + } +#endif + } + + while ((escflg == 3) && (len > 0)) { /* # Handling */ + switch (*c) { + case 0x08: /* backspace */ + ScreenBackspace(pScr); + break; + +#if 0 + case '3': /* top half of double line (DECDHL) */ + case '4': /* bottom half of double line (DECDHL) */ + case '5': /* single width line (DECSWL) */ + case '6': /* double width line (DECDWL) */ + break; +#endif + + case '8': /* screen alignment display (DECALN) */ + ScreenAlign(pScr); + escflg = 0; + break; + + default: + escflg = 0; + break; + + } + + c++; + len--; + } + + while ((escflg == 4) && (len > 0)) { /* ( Handling (GO character set) */ + switch (*c) { + + case 0x08: /* backspace */ + ScreenBackspace(pScr); + break; + +#if 0 + case 'A': /* united kingdom character set (unsupported) */ + case 'B': /* ASCII character set */ + case '1': /* choose standard graphics (same as ASCII) */ + pScr->G0 = 0; + if (!pScr->charset) + pScr->attrib = ScreenNotGraph(pScr->attrib); + escflg = 0; + break; + + case '0': /* choose special graphics set */ + case '2': /* alternate character set (special graphics) */ + pScr->G0 = 1; + if(!pScr->charset) + pScr->attrib = ScreenGraph(pScr->attrib); + escflg = 0; + break; +#endif + + default: + escflg = 0; + break; + } + + c++; + len--; + + } /* end while */ + + while((escflg == 5) && (len > 0)) { /* ) Handling (G1 handling) */ + switch (*c) { + + case 0x08: /* backspace */ + ScreenBackspace(pScr); + break; + +#if 0 + case 'A': /* united kingdom character set (unsupported) */ + case 'B': /* ASCII character set */ + case '1': /* choose standard graphics (same as ASCII) */ + pScr->G1 = 0; + if (pScr->charset) + pScr->attrib = ScreenNotGraph(pScr->attrib); + escflg = 0; + break; + + case '0': /* choose special graphics set */ + case '2': /* alternate character set (special graphics) */ + pScr->G1 = 1; + if(pScr->charset) + pScr->attrib = ScreenGraph(pScr->attrib); + escflg = 0; + break; +#endif + + default: + escflg = 0; + break; + } /* end switch */ + + c++; + len--; + } /* end while */ + + while ((escflg >= 6) && (escflg <= 10) && (len > 0)) { /* Handling IAC */ + ic = (unsigned char) *c; + switch (escflg) { + + case 6: /* Handling IAC xx */ + if (ic == 255) /* if IAC */ + escflg = 0; + else if (ic == 250) /* if SB */ + escflg = 7; + else + escflg = 9; + break; + + case 7: /* Handling IAC SB xx */ + if (ic == 255) /* if IAC */ + escflg = 8; + break; + + case 8: /* Handling IAC SB IAC xx */ + if (ic == 255) /* if IAC IAC */ + escflg = 7; + else if (ic == 240) /* if IAC SE */ + escflg = 0; + break; + + case 9: /* IAC xx xx */ + escflg = 0; + break; + } + c++; /* advance to the next character in the string */ + len--; /* decrement the counter */ + } + + if (escflg > 2 && escflg < 6 && len > 0) { + escflg = 0; + c++; + len--; + } + } + pScr->escflg = escflg; + ScreenCursorOn(pScr); +} diff --git a/mechglue/src/windows/wintel/enc_des.c b/mechglue/src/windows/wintel/enc_des.c new file mode 100644 index 000000000..7bf72f488 --- /dev/null +++ b/mechglue/src/windows/wintel/enc_des.c @@ -0,0 +1,725 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* based on @(#)enc_des.c 8.1 (Berkeley) 6/4/93 */ + +#ifdef ENCRYPTION + +#include "telnet_arpa.h" +#include <stdio.h> +#include <stdlib.h> + +#include "telnet.h" + +#include "encrypt.h" + +#define CFB 0 +#define OFB 1 + +#define NO_SEND_IV 1 +#define NO_RECV_IV 2 +#define NO_KEYID 4 +#define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID) +#define SUCCESS 0 +#define xFAILED -1 + + +struct fb { + Block krbdes_key; + Schedule krbdes_sched; + Block temp_feed; + unsigned char fb_feed[64]; + int need_start; + int state[2]; + int keyid[2]; + int once; + struct stinfo { + Block str_output; + Block str_feed; + Block str_iv; + Block str_ikey; + Schedule str_sched; + int str_index; + int str_flagshift; + } streams[2]; +}; + +static struct fb fb[2]; + +struct keyidlist { + char *keyid; + int keyidlen; + char *key; + int keylen; + int flags; +} keyidlist [] = { + { "\0", 1, 0, 0, 0 }, /* default key of zero */ + { 0, 0, 0, 0, 0 } +}; + +#define KEYFLAG_MASK 03 + +#define KEYFLAG_NOINIT 00 +#define KEYFLAG_INIT 01 +#define KEYFLAG_OK 02 +#define KEYFLAG_BAD 03 + +#define KEYFLAG_SHIFT 2 + +#define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2))) + +#define FB64_IV 1 +#define FB64_IV_OK 2 +#define FB64_IV_BAD 3 + +extern kstream EncryptKSGlobalHack; + +void fb64_stream_iv (Block, struct stinfo *); +void fb64_init (struct fb *); +static int fb64_start (struct fb *, int, int); +int fb64_is (unsigned char *, int, struct fb *); +int fb64_reply (unsigned char *, int, struct fb *); +static void fb64_session (Session_Key *, int, struct fb *); +void fb64_stream_key (Block, struct stinfo *); +int fb64_keyid (int, unsigned char *, int *, struct fb *); + + void +cfb64_init(server) + int server; +{ + fb64_init(&fb[CFB]); + fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64; + fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); + fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); +} + + void +ofb64_init(server) + int server; +{ + fb64_init(&fb[OFB]); + fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64; + fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); + fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); +} + + void +fb64_init(fbp) + register struct fb *fbp; +{ + memset((void *)fbp, 0, sizeof(*fbp)); + fbp->state[0] = fbp->state[1] = xFAILED; + fbp->fb_feed[0] = IAC; + fbp->fb_feed[1] = SB; + fbp->fb_feed[2] = TELOPT_ENCRYPT; + fbp->fb_feed[3] = ENCRYPT_IS; +} + +/* + * Returns: + * -1: some error. Negotiation is done, encryption not ready. + * 0: Successful, initial negotiation all done. + * 1: successful, negotiation not done yet. + * 2: Not yet. Other things (like getting the key from + * Kerberos) have to happen before we can continue. + */ + int +cfb64_start(dir, server) + int dir; + int server; +{ + return(fb64_start(&fb[CFB], dir, server)); +} + int +ofb64_start(dir, server) + int dir; + int server; +{ + return(fb64_start(&fb[OFB], dir, server)); +} + + static int +fb64_start(fbp, dir, server) + struct fb *fbp; + int dir; + int server; +{ + int x; + unsigned char *p; + register int state; + + switch (dir) { + case DIR_DECRYPT: + /* + * This is simply a request to have the other side + * start output (our input). He will negotiate an + * IV so we need not look for it. + */ + state = fbp->state[dir-1]; + if (state == xFAILED) + state = IN_PROGRESS; + break; + + case DIR_ENCRYPT: + state = fbp->state[dir-1]; + if (state == xFAILED) + state = IN_PROGRESS; + else if ((state & NO_SEND_IV) == 0) + break; + + if (!VALIDKEY(fbp->krbdes_key)) { + fbp->need_start = 1; + break; + } + state &= ~NO_SEND_IV; + state |= NO_RECV_IV; + /* + * Create a random feed and send it over. + */ + des_new_random_key(fbp->temp_feed); + des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, + fbp->krbdes_sched, 1); + p = fbp->fb_feed + 3; + *p++ = ENCRYPT_IS; + p++; + *p++ = FB64_IV; + for (x = 0; x < sizeof(Block); ++x) { + if ((*p++ = fbp->temp_feed[x]) == IAC) + *p++ = IAC; + } + *p++ = IAC; + *p++ = SE; +#ifdef DEBUG + printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); +#endif + TelnetSend(EncryptKSGlobalHack, fbp->fb_feed, p - fbp->fb_feed, 0); + break; + default: + return(xFAILED); + } + return(fbp->state[dir-1] = state); +} + +/* + * Returns: + * -1: some error. Negotiation is done, encryption not ready. + * 0: Successful, initial negotiation all done. + * 1: successful, negotiation not done yet. + */ + int +cfb64_is(data, cnt) + unsigned char *data; + int cnt; +{ + return(fb64_is(data, cnt, &fb[CFB])); +} + int +ofb64_is(data, cnt) + unsigned char *data; + int cnt; +{ + return(fb64_is(data, cnt, &fb[OFB])); +} + + int +fb64_is(data, cnt, fbp) + unsigned char *data; + int cnt; + struct fb *fbp; +{ + unsigned char *p; + register int state = fbp->state[DIR_DECRYPT-1]; + + if (cnt-- < 1) + goto failure; + + switch (*data++) { + case FB64_IV: + if (cnt != sizeof(Block)) { +#ifdef DEBUG + if (encrypt_debug_mode) + printf("CFB64: initial vector failed on size\r\n"); +#endif + state = xFAILED; + goto failure; + } + +#ifdef DEBUG + if (encrypt_debug_mode) { + printf("CFB64: initial vector received\r\n"); + printf("Initializing Decrypt stream\r\n"); + } +#endif + fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]); + + p = fbp->fb_feed + 3; + *p++ = ENCRYPT_REPLY; + p++; + *p++ = FB64_IV_OK; + *p++ = IAC; + *p++ = SE; +#ifdef DEBUG + printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); +#endif + TelnetSend(EncryptKSGlobalHack, fbp->fb_feed, p - fbp->fb_feed, 0); + + state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS; + break; + + default: +#if 0 + if (encrypt_debug_mode) { + printf("Unknown option type: %d\r\n", *(data-1)); + printd(data, cnt); + printf("\r\n"); + } +#endif + /* FALL THROUGH */ + failure: + /* + * We failed. Send an FB64_IV_BAD option + * to the other side so it will know that + * things failed. + */ + p = fbp->fb_feed + 3; + *p++ = ENCRYPT_REPLY; + p++; + *p++ = FB64_IV_BAD; + *p++ = IAC; + *p++ = SE; +#ifdef DEBUG + printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); +#endif + TelnetSend(EncryptKSGlobalHack, fbp->fb_feed, p - fbp->fb_feed, 0); + + break; + } + return(fbp->state[DIR_DECRYPT-1] = state); +} + +/* + * Returns: + * -1: some error. Negotiation is done, encryption not ready. + * 0: Successful, initial negotiation all done. + * 1: successful, negotiation not done yet. + */ + int +cfb64_reply(data, cnt) + unsigned char *data; + int cnt; +{ + return(fb64_reply(data, cnt, &fb[CFB])); +} + int +ofb64_reply(data, cnt) + unsigned char *data; + int cnt; +{ + return(fb64_reply(data, cnt, &fb[OFB])); +} + + + int +fb64_reply(data, cnt, fbp) + unsigned char *data; + int cnt; + struct fb *fbp; +{ + register int state = fbp->state[DIR_ENCRYPT-1]; + + if (cnt-- < 1) + goto failure; + + switch (*data++) { + case FB64_IV_OK: + fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); + if (state == xFAILED) + state = IN_PROGRESS; + state &= ~NO_RECV_IV; + encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); + break; + + case FB64_IV_BAD: + memset(fbp->temp_feed, 0, sizeof(Block)); + fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); + state = xFAILED; + break; + + default: +#if 0 + if (encrypt_debug_mode) { + printf("Unknown option type: %d\r\n", data[-1]); + printd(data, cnt); + printf("\r\n"); + } +#endif + /* FALL THROUGH */ + failure: + state = xFAILED; + break; + } + return(fbp->state[DIR_ENCRYPT-1] = state); +} + + void +cfb64_session(key, server) + Session_Key *key; + int server; +{ + fb64_session(key, server, &fb[CFB]); +} + + void +ofb64_session(key, server) + Session_Key *key; + int server; +{ + fb64_session(key, server, &fb[OFB]); +} + + static void +fb64_session(key, server, fbp) + Session_Key *key; + int server; + struct fb *fbp; +{ + + if (!key || key->type != SK_DES) { +#ifdef DEBUG + if (encrypt_debug_mode) + printf("Can't set krbdes's session key (%d != %d)\r\n", + key ? key->type : -1, SK_DES); +#endif + return; + } + memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block)); + + fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]); + fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]); + + if (fbp->once == 0) { + des_init_random_number_generator(fbp->krbdes_key); + fbp->once = 1; + } + des_key_sched(fbp->krbdes_key, fbp->krbdes_sched); + /* + * Now look to see if krbdes_start() was was waiting for + * the key to show up. If so, go ahead an call it now + * that we have the key. + */ + if (fbp->need_start) { + fbp->need_start = 0; + fb64_start(fbp, DIR_ENCRYPT, server); + } +} + +/* + * We only accept a keyid of 0. If we get a keyid of + * 0, then mark the state as SUCCESS. + */ + int +cfb64_keyid(dir, kp, lenp) + int dir, *lenp; + unsigned char *kp; +{ + return(fb64_keyid(dir, kp, lenp, &fb[CFB])); +} + + int +ofb64_keyid(dir, kp, lenp) + int dir, *lenp; + unsigned char *kp; +{ + return(fb64_keyid(dir, kp, lenp, &fb[OFB])); +} + + int +fb64_keyid(dir, kp, lenp, fbp) + int dir, *lenp; + unsigned char *kp; + struct fb *fbp; +{ + register int state = fbp->state[dir-1]; + + if (*lenp != 1 || (*kp != '\0')) { + *lenp = 0; + return(state); + } + + if (state == xFAILED) + state = IN_PROGRESS; + + state &= ~NO_KEYID; + + return(fbp->state[dir-1] = state); +} + +#if 0 + void +fb64_printsub(data, cnt, buf, buflen, type) + unsigned char *data, *buf, *type; + int cnt, buflen; +{ + char lbuf[32]; + register int i; + char *cp; + + buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ + buflen -= 1; + + switch(data[2]) { + case FB64_IV: + sprintf(lbuf, "%s_IV", type); + cp = lbuf; + goto common; + + case FB64_IV_OK: + sprintf(lbuf, "%s_IV_OK", type); + cp = lbuf; + goto common; + + case FB64_IV_BAD: + sprintf(lbuf, "%s_IV_BAD", type); + cp = lbuf; + goto common; + + default: + sprintf(lbuf, " %d (unknown)", data[2]); + cp = lbuf; + common: + for (; (buflen > 0) && (*buf = *cp++); buf++) + buflen--; + for (i = 3; i < cnt; i++) { + sprintf(lbuf, " %d", data[i]); + for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) + buflen--; + } + break; + } +} + + void +cfb64_printsub(data, cnt, buf, buflen) + unsigned char *data, *buf; + int cnt, buflen; +{ + fb64_printsub(data, cnt, buf, buflen, "CFB64"); +} + + void +ofb64_printsub(data, cnt, buf, buflen) + unsigned char *data, *buf; + int cnt, buflen; +{ + fb64_printsub(data, cnt, buf, buflen, "OFB64"); +} +#endif + + void +fb64_stream_iv(seed, stp) + Block seed; + register struct stinfo *stp; +{ + + memcpy((void *)stp->str_iv, (void *)seed, sizeof(Block)); + memcpy((void *)stp->str_output, (void *)seed, sizeof(Block)); + + des_key_sched(stp->str_ikey, stp->str_sched); + + stp->str_index = sizeof(Block); +} + + void +fb64_stream_key(key, stp) + Block key; + register struct stinfo *stp; +{ + memcpy((void *)stp->str_ikey, (void *)key, sizeof(Block)); + des_key_sched(key, stp->str_sched); + + memcpy((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block)); + + stp->str_index = sizeof(Block); +} + +/* + * DES 64 bit Cipher Feedback + * + * key --->+-----+ + * +->| DES |--+ + * | +-----+ | + * | v + * INPUT --(--------->(+)+---> DATA + * | | + * +-------------+ + * + * + * Given: + * iV: Initial vector, 64 bits (8 bytes) long. + * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). + * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. + * + * V0 = DES(iV, key) + * On = Dn ^ Vn + * V(n+1) = DES(On, key) + */ + + void +cfb64_encrypt(s, c) + register unsigned char *s; + int c; +{ + register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1]; + register int index; + + index = stp->str_index; + while (c-- > 0) { + if (index == sizeof(Block)) { + Block b; + des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); + memcpy((void *)stp->str_feed,(void *)b,sizeof(Block)); + index = 0; + } + + /* On encryption, we store (feed ^ data) which is cypher */ + *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); + s++; + index++; + } + stp->str_index = index; +} + + int +cfb64_decrypt(data) + int data; +{ + register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1]; + int index; + + if (data == -1) { + /* + * Back up one byte. It is assumed that we will + * never back up more than one byte. If we do, this + * may or may not work. + */ + if (stp->str_index) + --stp->str_index; + return(0); + } + + index = stp->str_index++; + if (index == sizeof(Block)) { + Block b; + des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); + memcpy((void *)stp->str_feed, (void *)b, sizeof(Block)); + stp->str_index = 1; /* Next time will be 1 */ + index = 0; /* But now use 0 */ + } + + /* On decryption we store (data) which is cypher. */ + stp->str_output[index] = data; + return(data ^ stp->str_feed[index]); +} + +/* + * DES 64 bit Output Feedback + * + * key --->+-----+ + * +->| DES |--+ + * | +-----+ | + * +-----------+ + * v + * INPUT -------->(+) ----> DATA + * + * Given: + * iV: Initial vector, 64 bits (8 bytes) long. + * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). + * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. + * + * V0 = DES(iV, key) + * V(n+1) = DES(Vn, key) + * On = Dn ^ Vn + */ + void +ofb64_encrypt(s, c) + register unsigned char *s; + int c; +{ + register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1]; + register int index; + + index = stp->str_index; + while (c-- > 0) { + if (index == sizeof(Block)) { + Block b; + des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); + memcpy((void *)stp->str_feed,(void *)b,sizeof(Block)); + index = 0; + } + *s++ ^= stp->str_feed[index]; + index++; + } + stp->str_index = index; +} + + int +ofb64_decrypt(data) + int data; +{ + register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1]; + int index; + + if (data == -1) { + /* + * Back up one byte. It is assumed that we will + * never back up more than one byte. If we do, this + * may or may not work. + */ + if (stp->str_index) + --stp->str_index; + return(0); + } + + index = stp->str_index++; + if (index == sizeof(Block)) { + Block b; + des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); + memcpy((void *)stp->str_feed, (void *)b, sizeof(Block)); + stp->str_index = 1; /* Next time will be 1 */ + index = 0; /* But now use 0 */ + } + + return(data ^ stp->str_feed[index]); +} + +#endif /* ENCRYPTION */ diff --git a/mechglue/src/windows/wintel/enc_des.h b/mechglue/src/windows/wintel/enc_des.h new file mode 100644 index 000000000..b7f0f95fd --- /dev/null +++ b/mechglue/src/windows/wintel/enc_des.h @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)enc-proto.h 8.1 (Berkeley) 6/4/93 + */ + +/* + * Copyright (C) 1990 by the Massachusetts Institute of Technology + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ +#ifdef ENCRYPTION +void encrypt_init (char *, int); +Encryptions *findencryption (int); +void encrypt_auto (int); +void decrypt_auto (int); +void encrypt_is (unsigned char *, int); +void encrypt_reply (unsigned char *, int); +void encrypt_start_input (int); +void encrypt_session_key (Session_Key *, int); +void encrypt_end_input (void); +void encrypt_start_output (int); +void encrypt_end_output (void); +void encrypt_send_request_start (void); +void encrypt_send_request_end (void); +void encrypt_send_end (void); +void encrypt_wait (void); +int encrypt_is_encrypting (void); +void encrypt_send_support (void); +void encrypt_send_keyid (int, unsigned char *, int, int); +int net_write (unsigned char *, int); + +#ifdef TELENTD +void encrypt_wait (void); +#else +int encrypt_cmd (int, char **); +void encrypt_display (void); +#endif + +void krbdes_encrypt (unsigned char *, int); +int krbdes_decrypt (int); +int krbdes_is (unsigned char *, int); +int krbdes_reply (unsigned char *, int); +void krbdes_init (int); +int krbdes_start (int, int); +void krbdes_session (Session_Key *, int); +void krbdes_printsub (unsigned char *, int, unsigned char *, int); + +void cfb64_encrypt (unsigned char *, int); +int cfb64_decrypt (int); +void cfb64_init (int); +int cfb64_start (int, int); +int cfb64_is (unsigned char *, int); +int cfb64_reply (unsigned char *, int); +void cfb64_session (Session_Key *, int); +int cfb64_keyid (int, unsigned char *, int *); +void cfb64_printsub (unsigned char *, int, unsigned char *, int); + +void ofb64_encrypt (unsigned char *, int); +int ofb64_decrypt (int); +void ofb64_init (int); +int ofb64_start (int, int); +int ofb64_is (unsigned char *, int); +int ofb64_reply (unsigned char *, int); +void ofb64_session (Session_Key *, int); +int ofb64_keyid (int, unsigned char *, int *); +void ofb64_printsub (unsigned char *, int, unsigned char *, int); + +int des_new_random_key (Block); +void des_set_random_generator_seed (Block); +void des_key_sched (Block, Schedule); +void des_ecb_encrypt (Block, Block, Schedule, int); +int des_string_to_key (char *, Block); +#endif /* ENCRYPTION */ diff --git a/mechglue/src/windows/wintel/encrypt.c b/mechglue/src/windows/wintel/encrypt.c new file mode 100644 index 000000000..6d97ccd5d --- /dev/null +++ b/mechglue/src/windows/wintel/encrypt.c @@ -0,0 +1,999 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* based on @(#)encrypt.c 8.1 (Berkeley) 6/4/93 */ + +/* + * Copyright (C) 1990 by the Massachusetts Institute of Technology + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#ifdef ENCRYPTION + +#include <stdio.h> + +#define isprefix(a, b) (!strncmp((a), (b), strlen(b))) + +#ifdef KRB4 +#include <windows.h> +#include <time.h> +#include <string.h> +#include "winsock.h" +#include "kerberos.h" +#endif +#ifdef KRB5 +#include <time.h> +#include <string.h> +#include "krb5.h" +#include "com_err.h" +#endif + +#include "telnet.h" +#include "encrypt.h" + +#define ENCRYPT_NAMES +#include "telnet_arpa.h" + +/* + * These function pointers point to the current routines + * for encrypting and decrypting data. + */ +void (*encrypt_output) (unsigned char *, int); +int (*decrypt_input) (int); + +#ifdef DEBUG +int encrypt_debug_mode = 1; +int encrypt_verbose = 1; +#else +int encrypt_verbose = 0; +#endif + +static char dbgbuf [10240]; + +static int decrypt_mode = 0; +static int encrypt_mode = 0; +static int autoencrypt = 1; +static int autodecrypt = 1; +static int havesessionkey = 0; + +kstream EncryptKSGlobalHack = NULL; + +#define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0) + +static long i_support_encrypt = + typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); +static long i_support_decrypt = + typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); +static long i_wont_support_encrypt = 0; +static long i_wont_support_decrypt = 0; +#define I_SUPPORT_ENCRYPT (i_support_encrypt & ~i_wont_support_encrypt) +#define I_SUPPORT_DECRYPT (i_support_decrypt & ~i_wont_support_decrypt) + +static long remote_supports_encrypt = 0; +static long remote_supports_decrypt = 0; + +static Encryptions encryptions[] = { + { "DES_CFB64", + ENCTYPE_DES_CFB64, + cfb64_encrypt, + cfb64_decrypt, + cfb64_init, + cfb64_start, + cfb64_is, + cfb64_reply, + cfb64_session, + cfb64_keyid, + NULL }, + { "DES_OFB64", + ENCTYPE_DES_OFB64, + ofb64_encrypt, + ofb64_decrypt, + ofb64_init, + ofb64_start, + ofb64_is, + ofb64_reply, + ofb64_session, + ofb64_keyid, + NULL }, + { 0, }, +}; + +static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPT, + ENCRYPT_SUPPORT }; +static unsigned char str_suplen = 0; +static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPT }; +static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPT, 0, IAC, SE }; + +void encrypt_request_end(void); +void encrypt_request_start(unsigned char *, int); +void encrypt_enc_keyid(unsigned char *, int); +void encrypt_dec_keyid(unsigned char *, int); +void encrypt_support(unsigned char *, int); +void encrypt_start(unsigned char *, int); +void encrypt_end(void); + +int encrypt_ks_stream(struct kstream_data_block *, /* output */ + struct kstream_data_block *, /* input */ + struct kstream *); + +int decrypt_ks_stream(struct kstream_data_block *, /* output */ + struct kstream_data_block *, /* input */ + struct kstream *); + +int +encrypt_ks_stream(struct kstream_data_block *i, + struct kstream_data_block *o, + struct kstream *ks) +{ + + /* + * this is really quite bogus, since it does an in-place encryption... + */ + if (encrypt_output) { + encrypt_output(i->ptr, i->length); + return 1; + } + + return 0; +} + + +int +decrypt_ks_stream(struct kstream_data_block *i, + struct kstream_data_block *o, + struct kstream *ks) +{ + unsigned int len; + /* + * this is really quite bogus, since it does an in-place decryption... + */ + if (decrypt_input) { + for (len = 0 ; len < i->length ; len++) + ((unsigned char *)i->ptr)[len] + = decrypt_input(((unsigned char *)i->ptr)[len]); + return 1; + } + + return 0; +} + +int +decrypt_ks_hack(unsigned char *buf, int cnt) +{ + int len; + /* + * this is really quite bogus, since it does an in-place decryption... + */ + for (len = 0 ; len < cnt ; len++) + buf[len] = decrypt_input(buf[len]); + +#ifdef DEBUG + hexdump("hack:", buf, cnt); +#endif + return 1; +} + +#ifdef DEBUG +int +printsub(char c, unsigned char *s, size_t len) +{ + size_t i; + char *p = dbgbuf; + + *p++ = c; + + for (i = 0 ; (i < len) && (p - dbgbuf + 3 < sizeof(dbgbuf)) ; i++) + p += sprintf(p, "%02x ", s[i]); + dbgbuf[sizeof(dbgbuf) - 1] = '\0'; + + strncat(p, "\n", sizeof(dbgbuf) - 1 - (p - dbgbuf)); + + OutputDebugString(dbgbuf); + + return 0; +} +#endif + +/* + * parsedat[0] == the suboption we might be negoating, + */ +void +encrypt_parse(kstream ks, unsigned char *parsedat, int end_sub) +{ + char *p = dbgbuf; + +#ifdef DEBUG + printsub('<', parsedat, end_sub); +#endif + + switch(parsedat[1]) { + case ENCRYPT_START: + encrypt_start(parsedat + 2, end_sub - 2); + break; + case ENCRYPT_END: + encrypt_end(); + break; + case ENCRYPT_SUPPORT: + encrypt_support(parsedat + 2, end_sub - 2); + break; + case ENCRYPT_REQSTART: + encrypt_request_start(parsedat + 2, end_sub - 2); + break; + case ENCRYPT_REQEND: + /* + * We can always send an REQEND so that we cannot + * get stuck encrypting. We should only get this + * if we have been able to get in the correct mode + * anyhow. + */ + encrypt_request_end(); + break; + case ENCRYPT_IS: + encrypt_is(parsedat + 2, end_sub - 2); + break; + case ENCRYPT_REPLY: + encrypt_reply(parsedat + 2, end_sub - 2); + break; + case ENCRYPT_ENC_KEYID: + encrypt_enc_keyid(parsedat + 2, end_sub - 2); + break; + case ENCRYPT_DEC_KEYID: + encrypt_dec_keyid(parsedat + 2, end_sub - 2); + break; + default: + break; + } +} + +/* XXX */ +Encryptions * +findencryption(type) + int type; +{ + Encryptions *ep = encryptions; + + if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type))) + return(0); + while (ep->type && ep->type != type) + ++ep; + return(ep->type ? ep : 0); +} + +Encryptions * +finddecryption(int type) +{ + Encryptions *ep = encryptions; + + if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type))) + return(0); + while (ep->type && ep->type != type) + ++ep; + return(ep->type ? ep : 0); +} + +#define MAXKEYLEN 64 + +static struct key_info { + unsigned char keyid[MAXKEYLEN]; + int keylen; + int dir; + int *modep; + Encryptions *(*getcrypt)(); +} ki[2] = { + { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption }, + { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption }, +}; + +void +encrypt_init(kstream iks, kstream_ptr data) +{ + Encryptions *ep = encryptions; + + i_support_encrypt = i_support_decrypt = 0; + remote_supports_encrypt = remote_supports_decrypt = 0; + encrypt_mode = 0; + decrypt_mode = 0; + encrypt_output = NULL; + decrypt_input = NULL; + + str_suplen = 4; + + EncryptKSGlobalHack = iks; + + while (ep->type) { +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>I will support %s\n", + ENCTYPE_NAME(ep->type)); + OutputDebugString(dbgbuf); + } +#endif + i_support_encrypt |= typemask(ep->type); + i_support_decrypt |= typemask(ep->type); + if ((i_wont_support_decrypt & typemask(ep->type)) == 0) + if ((str_send[str_suplen++] = ep->type) == IAC) + str_send[str_suplen++] = IAC; + if (ep->init) + (*ep->init)(0); + ++ep; + } + str_send[str_suplen++] = IAC; + str_send[str_suplen++] = SE; +} + +void +encrypt_send_support() +{ + if (str_suplen) { + /* + * If the user has requested that decryption start + * immediatly, then send a "REQUEST START" before + * we negotiate the type. + */ + if (autodecrypt) + encrypt_send_request_start(); + TelnetSend(EncryptKSGlobalHack, str_send, str_suplen, 0); + +#ifdef DEBUG + printsub('>', &str_send[2], str_suplen - 2); +#endif + + str_suplen = 0; + } +} + +/* + * Called when ENCRYPT SUPPORT is received. + */ +void +encrypt_support(typelist, cnt) + unsigned char *typelist; + int cnt; +{ + register int type, use_type = 0; + Encryptions *ep; + + /* + * Forget anything the other side has previously told us. + */ + remote_supports_decrypt = 0; + + while (cnt-- > 0) { + type = *typelist++; +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Remote supports %s (%d)\n", + ENCTYPE_NAME(type), type); + OutputDebugString(dbgbuf); + } +#endif + if ((type < ENCTYPE_CNT) && + (I_SUPPORT_ENCRYPT & typemask(type))) { + remote_supports_decrypt |= typemask(type); + if (use_type == 0) + use_type = type; + } + } + if (use_type) { + ep = findencryption(use_type); + if (!ep) + return; + type = ep->start ? (*ep->start)(DIR_ENCRYPT, 0) : 0; +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>(*ep->start)() %s returned %d (%s)\n", + ENCTYPE_NAME(use_type), type, ENCRYPT_NAME(type)); + OutputDebugString(dbgbuf); + } +#endif + if (type < 0) + return; + encrypt_mode = use_type; + if (type == 0) + encrypt_start_output(use_type); + } +} + +void +encrypt_is(data, cnt) + unsigned char *data; + int cnt; +{ + Encryptions *ep; + register int type, ret; + + if (--cnt < 0) + return; + type = *data++; + if (type < ENCTYPE_CNT) + remote_supports_encrypt |= typemask(type); + if (!(ep = finddecryption(type))) { +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>encrypt_reply: " + "Can't find type %s (%d) for initial negotiation\n", + ENCTYPE_NAME_OK(type) + ? ENCTYPE_NAME(type) : "(unknown)", + type); + OutputDebugString(dbgbuf); + } +#endif + return; + } + if (!ep->is) { +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>encrypt_reply: " + "No initial negotiation needed for type %s (%d)\n", + ENCTYPE_NAME_OK(type) + ? ENCTYPE_NAME(type) : "(unknown)", + type); + OutputDebugString(dbgbuf); + } +#endif + ret = 0; + } else { + ret = (*ep->is)(data, cnt); +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, "encrypt_reply: " + "(*ep->is)(%x, %d) returned %s(%d)\n", data, cnt, + (ret < 0) ? "FAIL " : + (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); + OutputDebugString(dbgbuf); + } +#endif + } + if (ret < 0) { + autodecrypt = 0; + } else { + decrypt_mode = type; + if (ret == 0 && autodecrypt) + encrypt_send_request_start(); + } +} + +void +encrypt_reply(data, cnt) + unsigned char *data; + int cnt; +{ + Encryptions *ep; + register int ret, type; + + if (--cnt < 0) + return; + type = *data++; + if (!(ep = findencryption(type))) { +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Can't find type %s (%d) for initial negotiation\n", + ENCTYPE_NAME_OK(type) + ? ENCTYPE_NAME(type) : "(unknown)", + type); + OutputDebugString(dbgbuf); + } +#endif + return; + } + if (!ep->reply) { +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>No initial negotiation needed for type %s (%d)\n", + ENCTYPE_NAME_OK(type) + ? ENCTYPE_NAME(type) : "(unknown)", + type); + OutputDebugString(dbgbuf); + } +#endif + ret = 0; + } else { + ret = (*ep->reply)(data, cnt); +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, "(*ep->reply)(%x, %d) returned %s(%d)\n", + data, cnt, + (ret < 0) ? "FAIL " : + (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); + OutputDebugString(dbgbuf); + } +#endif + } +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>encrypt_reply returned %d\n", ret); + OutputDebugString(dbgbuf); + } +#endif + if (ret < 0) { + autoencrypt = 0; + } else { + encrypt_mode = type; + if (ret == 0 && autoencrypt) + encrypt_start_output(type); + } +} + +/* + * Called when a ENCRYPT START command is received. + */ +void +encrypt_start(data, cnt) + unsigned char *data; + int cnt; +{ + Encryptions *ep; + + if (!decrypt_mode) { + /* + * Something is wrong. We should not get a START + * command without having already picked our + * decryption scheme. Send a REQUEST-END to + * attempt to clear the channel... + */ + /* printf("Warning, Cannot decrypt input stream!!!\n"); */ + encrypt_send_request_end(); + MessageBox(NULL, "Warning, Cannot decrypt input stream!!!", NULL, + MB_OK | MB_ICONEXCLAMATION); + return; + } + + if (ep = finddecryption(decrypt_mode)) { + extern BOOL encrypt_flag; + + decrypt_input = ep->input; + EncryptKSGlobalHack->decrypt = decrypt_ks_stream; + encrypt_flag = 2; /* XXX hack */ + + if (encrypt_verbose) { + sprintf(dbgbuf, "[ Input is now decrypted with type %s ]\n", + ENCTYPE_NAME(decrypt_mode)); + OutputDebugString(dbgbuf); + } +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Start to decrypt input with type %s\n", + ENCTYPE_NAME(decrypt_mode)); + OutputDebugString(dbgbuf); + } +#endif + } else { + char buf[1024]; + wsprintf(buf, "Warning, Cannot decrypt type %s (%d)!!!", + ENCTYPE_NAME_OK(decrypt_mode) + ? ENCTYPE_NAME(decrypt_mode) : "(unknown)", + decrypt_mode); + MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION); + encrypt_send_request_end(); + } +} + +void +encrypt_session_key(key, server) + Session_Key *key; + int server; +{ + Encryptions *ep = encryptions; + + havesessionkey = 1; + + while (ep->type) { + if (ep->session) + (*ep->session)(key, server); +#if defined(notdef) + if (!encrypt_output && autoencrypt && !server) + encrypt_start_output(ep->type); + if (!decrypt_input && autodecrypt && !server) + encrypt_send_request_start(); +#endif + ++ep; + } +} + +/* + * Called when ENCRYPT END is received. + */ +void +encrypt_end() +{ + decrypt_input = NULL; + EncryptKSGlobalHack->decrypt = NULL; +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Input is back to clear text\n"); + OutputDebugString(dbgbuf); + } +#endif + if (encrypt_verbose) { + sprintf(dbgbuf, "[ Input is now clear text ]\n"); + OutputDebugString(dbgbuf); + } +} + +/* + * Called when ENCRYPT REQUEST-END is received. + */ +void +encrypt_request_end() +{ + encrypt_send_end(); +} + +/* + * Called when ENCRYPT REQUEST-START is received. If we receive + * this before a type is picked, then that indicates that the + * other side wants us to start encrypting data as soon as we + * can. + */ +void +encrypt_request_start(data, cnt) + unsigned char *data; + int cnt; +{ + if (encrypt_mode == 0) { + return; + } + encrypt_start_output(encrypt_mode); +} + +static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT }; + +void +encrypt_keyid(); + +void +encrypt_enc_keyid(keyid, len) + unsigned char *keyid; + int len; +{ + encrypt_keyid(&ki[1], keyid, len); +} + +void +encrypt_dec_keyid(keyid, len) + unsigned char *keyid; + int len; +{ + encrypt_keyid(&ki[0], keyid, len); +} + +void +encrypt_keyid(kp, keyid, len) + struct key_info *kp; + unsigned char *keyid; + int len; +{ + Encryptions *ep; + int dir = kp->dir; + register int ret = 0; + + if (!(ep = (*kp->getcrypt)(*kp->modep))) { + if (len == 0) + return; + kp->keylen = 0; + } else if (len == 0) { + /* + * Empty option, indicates a failure. + */ + if (kp->keylen == 0) + return; + kp->keylen = 0; + if (ep->keyid) + (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); + + } else if ((len != kp->keylen) || (memcmp(keyid, kp->keyid, len) != 0)) { + /* + * Length or contents are different + */ + kp->keylen = len; + memcpy(kp->keyid, keyid, len); + if (ep->keyid) + (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); + } else { + if (ep->keyid) + ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen); + if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt) + encrypt_start_output(*kp->modep); + return; + } + + encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0); +} + +void +encrypt_send_keyid(dir, keyid, keylen, saveit) + int dir; + unsigned char *keyid; + int keylen; + int saveit; +{ + unsigned char *strp; + + str_keyid[3] = (dir == DIR_ENCRYPT) + ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID; + if (saveit) { + struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1]; + memcpy(kp->keyid, keyid, keylen); + kp->keylen = keylen; + } + + for (strp = &str_keyid[4]; keylen > 0; --keylen) { + if ((*strp++ = *keyid++) == IAC) + *strp++ = IAC; + } + *strp++ = IAC; + *strp++ = SE; + TelnetSend(EncryptKSGlobalHack, str_keyid, strp - str_keyid, 0); + +#ifdef DEBUG + printsub('>', &str_keyid[2], strp - str_keyid - 2); +#endif + +} + +void +encrypt_auto(on) + int on; +{ + if (on < 0) + autoencrypt ^= 1; + else + autoencrypt = on ? 1 : 0; +} + +void +decrypt_auto(on) + int on; +{ + if (on < 0) + autodecrypt ^= 1; + else + autodecrypt = on ? 1 : 0; +} + +void +encrypt_start_output(type) + int type; +{ + Encryptions *ep; + register unsigned char *p; + register int i; + + if (!(ep = findencryption(type))) { +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Can't encrypt with type %s (%d)\n", + ENCTYPE_NAME_OK(type) + ? ENCTYPE_NAME(type) : "(unknown)", + type); + OutputDebugString(dbgbuf); + } +#endif + return; + } + if (ep->start) { + i = (*ep->start)(DIR_ENCRYPT, 0); +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Encrypt start: %s (%d) %s\n", + (i < 0) ? "failed" : + "initial negotiation in progress", + i, ENCTYPE_NAME(type)); + OutputDebugString(dbgbuf); + } +#endif + if (i) + return; + } + p = str_start + 3; + *p++ = ENCRYPT_START; + for (i = 0; i < ki[0].keylen; ++i) { + if ((*p++ = ki[0].keyid[i]) == IAC) + *p++ = IAC; + } + *p++ = IAC; + *p++ = SE; + TelnetSend(EncryptKSGlobalHack, str_start, p - str_start, 0); +#ifdef DEBUG + printsub('>', &str_start[2], p - &str_start[2]); +#endif + + /* + * If we are already encrypting in some mode, then + * encrypt the ring (which includes our request) in + * the old mode, mark it all as "clear text" and then + * switch to the new mode. + */ + encrypt_output = ep->output; + EncryptKSGlobalHack->encrypt = encrypt_ks_stream; + encrypt_mode = type; +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Started to encrypt output with type %s\n", + ENCTYPE_NAME(type)); + OutputDebugString(dbgbuf); + } +#endif + if (encrypt_verbose) { + sprintf(dbgbuf, "[ Output is now encrypted with type %s ]\n", + ENCTYPE_NAME(type)); + OutputDebugString(dbgbuf); + } +} + +void +encrypt_send_end() +{ + if (!encrypt_output) + return; + + str_end[3] = ENCRYPT_END; + TelnetSend(EncryptKSGlobalHack, str_end, sizeof(str_end), 0); +#ifdef DEBUG + printsub('>', &str_end[2], sizeof(str_end) - 2); +#endif + + /* + * Encrypt the output buffer now because it will not be done by + * netflush... + */ + encrypt_output = 0; + EncryptKSGlobalHack->encrypt = NULL; +#ifdef DEBUG + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Output is back to clear text\n"); + OutputDebugString(dbgbuf); + } +#endif + if (encrypt_verbose) { + sprintf(dbgbuf, "[ Output is now clear text ]\n"); + OutputDebugString(dbgbuf); + } +} + +void +encrypt_send_request_start() +{ + register unsigned char *p; + register int i; + + p = &str_start[3]; + *p++ = ENCRYPT_REQSTART; + for (i = 0; i < ki[1].keylen; ++i) { + if ((*p++ = ki[1].keyid[i]) == IAC) + *p++ = IAC; + } + *p++ = IAC; + *p++ = SE; + TelnetSend(EncryptKSGlobalHack, str_start, p - str_start, 0); +#ifdef DEBUG + printsub('>', &str_start[2], p - &str_start[2]); + + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Request input to be encrypted\n"); + OutputDebugString(dbgbuf); + } +#endif +} + +void +encrypt_send_request_end() +{ + str_end[3] = ENCRYPT_REQEND; + TelnetSend(EncryptKSGlobalHack, str_end, sizeof(str_end), 0); +#ifdef DEBUG + printsub('>', &str_end[2], sizeof(str_end) - 2); + + if (encrypt_debug_mode) { + sprintf(dbgbuf, ">>>Request input to be clear text\n"); + OutputDebugString(dbgbuf); + } +#endif +} + +int encrypt_is_encrypting() +{ + if (encrypt_output && decrypt_input) + return 1; + return 0; +} + +#ifdef DEBUG +void +encrypt_debug(mode) + int mode; +{ + encrypt_debug_mode = mode; +} +#endif + +#if 0 +void +encrypt_gen_printsub(data, cnt, buf, buflen) + unsigned char *data, *buf; + int cnt, buflen; +{ + char tbuf[16], *cp; + + cnt -= 2; + data += 2; + buf[buflen-1] = '\0'; + buf[buflen-2] = '*'; + buflen -= 2;; + for (; cnt > 0; cnt--, data++) { + sprintf(tbuf, " %d", *data); + for (cp = tbuf; *cp && buflen > 0; --buflen) + *buf++ = *cp++; + if (buflen <= 0) + return; + } + *buf = '\0'; +} + +void +encrypt_printsub(data, cnt, buf, buflen) + unsigned char *data, *buf; + int cnt, buflen; +{ + Encryptions *ep; + register int type = data[1]; + + for (ep = encryptions; ep->type && ep->type != type; ep++) + ; + + if (ep->printsub) + (*ep->printsub)(data, cnt, buf, buflen); + else + encrypt_gen_printsub(data, cnt, buf, buflen); +} +#endif + +#endif /* ENCRYPTION */ diff --git a/mechglue/src/windows/wintel/encrypt.h b/mechglue/src/windows/wintel/encrypt.h new file mode 100644 index 000000000..4d7afb176 --- /dev/null +++ b/mechglue/src/windows/wintel/encrypt.h @@ -0,0 +1,178 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)encrypt.h 8.1 (Berkeley) 6/4/93 + */ + +/* + * Copyright (C) 1990 by the Massachusetts Institute of Technology + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#ifdef ENCRYPTION + +#ifndef __ENCRYPTION__ +#define __ENCRYPTION__ + +#define DIR_DECRYPT 1 +#define DIR_ENCRYPT 2 + +typedef unsigned char Block[8]; +typedef unsigned char *BlockT; +typedef struct { Block _; } Schedule[16]; + +#define VALIDKEY(key) ( key[0] | key[1] | key[2] | key[3] | key[4] | key[5] | key[6] | key[7]) + +#define SAMEKEY(k1, k2) (!memcmp((void *)k1, (void *)k2, sizeof(Block))) + +typedef struct { + short type; + int length; + unsigned char *data; +} Session_Key; + +#ifdef DEBUG +int printsub(char, unsigned char *, size_t); +#endif + +void encrypt_parse(kstream, unsigned char *, int); + +typedef struct { + char *name; + int type; + void (*output) (unsigned char *, int); + int (*input) (int); + void (*init) (int); + int (*start) (int, int); + int (*is) (unsigned char *, int); + int (*reply) (unsigned char *, int); + void (*session) (Session_Key *, int); + int (*keyid) (int, unsigned char *, int *); + void (*printsub) (unsigned char *, int, unsigned char *, int); +} Encryptions; + +#define SK_DES 1 /* Matched Kerberos v5 ENCTYPE_DES */ + +void encrypt_init (kstream, kstream_ptr); +Encryptions *findencryption (int); +void encrypt_auto (int); +void decrypt_auto (int); +void encrypt_is (unsigned char *, int); +void encrypt_reply (unsigned char *, int); +void encrypt_start_input (int); +void encrypt_session_key (Session_Key *, int); +void encrypt_end_input (void); +void encrypt_start_output (int); +void encrypt_end_output (void); +void encrypt_send_request_start (void); +void encrypt_send_request_end (void); +void encrypt_send_end (void); +void encrypt_wait (void); +int encrypt_is_encrypting (void); +void encrypt_send_support (void); +void encrypt_send_keyid (int, unsigned char *, int, int); +int net_write (unsigned char *, int); + +int encrypt_cmd (int, char **); +void encrypt_display (void); + +void krbdes_encrypt (unsigned char *, int); +int krbdes_decrypt (int); +int krbdes_is (unsigned char *, int); +int krbdes_reply (unsigned char *, int); +void krbdes_init (int); +int krbdes_start (int, int); +void krbdes_session (Session_Key *, int); +void krbdes_printsub (unsigned char *, int, unsigned char *, int); + +void cfb64_encrypt (unsigned char *, int); +int cfb64_decrypt (int); +void cfb64_init (int); +int cfb64_start (int, int); +int cfb64_is (unsigned char *, int); +int cfb64_reply (unsigned char *, int); +void cfb64_session (Session_Key *, int); +int cfb64_keyid (int, unsigned char *, int *); +void cfb64_printsub (unsigned char *, int, unsigned char *, int); + +void ofb64_encrypt (unsigned char *, int); +int ofb64_decrypt (int); +void ofb64_init (int); +int ofb64_start (int, int); +int ofb64_is (unsigned char *, int); +int ofb64_reply (unsigned char *, int); +void ofb64_session (Session_Key *, int); +int ofb64_keyid (int, unsigned char *, int *); +void ofb64_printsub (unsigned char *, int, unsigned char *, int); + +int KRB5_CALLCONV + des_new_random_key (Block); +void KRB5_CALLCONV + des_set_random_generator_seed (Block); +void KRB5_CALLCONV + des_key_sched (Block, Schedule); +void KRB5_CALLCONV + des_ecb_encrypt (Block, Block, Schedule, int); + +/* int des_string_to_key (char *, Block); */ + + +#ifdef DEBUG +extern int encrypt_debug_mode; +#endif + +extern int (*decrypt_input) (int); +extern void (*encrypt_output) (unsigned char *, int); + +int decrypt_ks_hack(unsigned char *, int); + +#endif /* __ENCRYPTION__ */ + +#endif /* ENCRYPTION */ diff --git a/mechglue/src/windows/wintel/font.c b/mechglue/src/windows/wintel/font.c new file mode 100644 index 000000000..d2858cd10 --- /dev/null +++ b/mechglue/src/windows/wintel/font.c @@ -0,0 +1,100 @@ +/* font.c */ + +#include <windows.h> +#include <commdlg.h> +#include <assert.h> +#include "screen.h" +#include "ini.h" + +void ProcessFontChange( + HWND hWnd) +{ + static DWORD dwFontColor; /* Color of font if one has been selected */ + CHOOSEFONT cf; + HDC hDC; + SCREEN *pScr; + TEXTMETRIC tm; + char buf[16]; + char szStyle[LF_FACESIZE]; + + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert(pScr != NULL); + + cf.lStructSize = sizeof(cf); + cf.hwndOwner = hWnd; + cf.lpLogFont = (LPLOGFONT) &(pScr->lf); + cf.lpszStyle = szStyle; + cf.Flags = CF_INITTOLOGFONTSTRUCT; /* | CF_USESTYLE; */ + cf.Flags |= CF_SCREENFONTS; +#if 0 + cf.Flags |= CF_ANSIONLY; +#endif + cf.Flags |= CF_FORCEFONTEXIST; + cf.Flags |= CF_FIXEDPITCHONLY; + cf.Flags |= CF_NOSIMULATIONS; + + if (ChooseFont(&cf)) { + if (pScr->hSelectedFont) + DeleteObject(pScr->hSelectedFont); + + pScr->hSelectedFont = CreateFontIndirect(&(pScr->lf)); + pScr->lf.lfUnderline = TRUE; + pScr->hSelectedULFont = CreateFontIndirect(&(pScr->lf)); + pScr->lf.lfUnderline = FALSE; + hDC = GetDC(hWnd); + SelectObject(hDC, pScr->hSelectedFont); + GetTextMetrics(hDC, &tm); + pScr->cxChar = tm.tmAveCharWidth; + pScr->cyChar = tm.tmHeight + tm.tmExternalLeading; + ReleaseDC(hWnd, hDC); + SetWindowPos(hWnd, NULL, 0, 0, pScr->cxChar * pScr->width + + FRAME_WIDTH, pScr->cyChar * pScr->height + + FRAME_HEIGHT, SWP_NOMOVE | SWP_NOZORDER); + + dwFontColor = RGB(255, 255, 255); + InvalidateRect(hWnd, NULL, TRUE); + } + + WritePrivateProfileString(INI_FONT, "FaceName", pScr->lf.lfFaceName, TELNET_INI); + wsprintf(buf, "%d", (int) pScr->lf.lfHeight); + WritePrivateProfileString(INI_FONT, "Height", buf, TELNET_INI); + wsprintf(buf, "%d", (int) pScr->lf.lfWidth); + WritePrivateProfileString(INI_FONT, "Width", buf, TELNET_INI); + wsprintf(buf, "%d", (int) pScr->lf.lfEscapement); + WritePrivateProfileString(INI_FONT, "Escapement", buf, TELNET_INI); + wsprintf(buf, "%d", (int) pScr->lf.lfCharSet); + WritePrivateProfileString(INI_FONT, "CharSet", buf, TELNET_INI); + wsprintf(buf, "%d", (int) pScr->lf.lfPitchAndFamily); + WritePrivateProfileString(INI_FONT, "PitchAndFamily", buf, TELNET_INI); + + return; + +} /* ProcessFontChange */ + + +void InitializeStruct( + WORD wCommDlgType, + LPSTR lpStruct, + HWND hWnd) +{ + LPCHOOSEFONT lpFontChunk; + + if (wCommDlgType == IDC_FONT) { + lpFontChunk = (LPCHOOSEFONT) lpStruct; + + lpFontChunk->lStructSize = sizeof(CHOOSEFONT); + lpFontChunk->hwndOwner = hWnd; + lpFontChunk->Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY + | CF_INITTOLOGFONTSTRUCT | CF_APPLY; + lpFontChunk->rgbColors = RGB(0, 0, 255); + lpFontChunk->lCustData = 0L; + lpFontChunk->lpfnHook = NULL; + lpFontChunk->lpTemplateName = NULL; + lpFontChunk->hInstance = NULL; + lpFontChunk->lpszStyle = NULL; + lpFontChunk->nFontType = SCREEN_FONTTYPE; + lpFontChunk->nSizeMin = 0; + lpFontChunk->nSizeMax = 0; + } + +} /* InitialiseStruct */ diff --git a/mechglue/src/windows/wintel/genget.c b/mechglue/src/windows/wintel/genget.c new file mode 100644 index 000000000..4e760d72e --- /dev/null +++ b/mechglue/src/windows/wintel/genget.c @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* based on @(#)genget.c 8.1 (Berkeley) 6/4/93 */ + +#include <ctype.h> + +#define LOWER(x) (isupper(x) ? tolower(x) : (x)) +/* + * The prefix function returns 0 if *s1 is not a prefix + * of *s2. If *s1 exactly matches *s2, the negative of + * the length is returned. If *s1 is a prefix of *s2, + * the length of *s1 is returned. + */ + int +isprefix(s1, s2) + register char *s1, *s2; +{ + char *os1; + register char c1, c2; + + if (*s1 == '\0') + return(-1); + os1 = s1; + c1 = *s1; + c2 = *s2; + while (LOWER(c1) == LOWER(c2)) { + if (c1 == '\0') + break; + c1 = *++s1; + c2 = *++s2; + } + return(*s1 ? 0 : (*s2 ? (s1 - os1) : (os1 - s1))); +} + +static char *ambiguous; /* special return value for command routines */ + + char ** +genget(name, table, stlen) + char *name; /* name to match */ + char **table; /* name entry in table */ + int stlen; +{ + register char **c, **found; + register int n; + + if (name == 0) + return 0; + + found = 0; + for (c = table; *c != 0; c = (char **)((char *)c + stlen)) { + if ((n = isprefix(name, *c)) == 0) + continue; + if (n < 0) /* exact match */ + return(c); + if (found) + return(&ambiguous); + found = c; + } + return(found); +} + +/* + * Function call version of Ambiguous() + */ + int +Ambiguous(s) + char *s; +{ + return((char **)s == &ambiguous); +} diff --git a/mechglue/src/windows/wintel/ini.h b/mechglue/src/windows/wintel/ini.h new file mode 100644 index 000000000..f26c162e3 --- /dev/null +++ b/mechglue/src/windows/wintel/ini.h @@ -0,0 +1,16 @@ +/* Defines INI file vocabulary */ +#define TELNET_INI "kerberos.ini" + +#define INI_TELNET "Telnet" +#define INI_FONT "Font" +#define INI_WIDTH "Width" +#define INI_HEIGHT "Height" +#define INI_POSITION "Position" +#define INI_BACKSPACE "Backspace" +#define INI_BACKSPACE_BS "BS" +#define INI_BACKSPACE_DEL "DEL" + +#define INI_HOSTS "Telnet Hosts" +#define INI_HOST "Host" +#define INI_HOST_BS "BS" +#define INI_HOST_DEL "DEL" diff --git a/mechglue/src/windows/wintel/intern.c b/mechglue/src/windows/wintel/intern.c new file mode 100644 index 000000000..0cdd5537d --- /dev/null +++ b/mechglue/src/windows/wintel/intern.c @@ -0,0 +1,815 @@ +/* intern.c */ + +#include <windows.h> +#include <string.h> +#include <assert.h> +#include "screen.h" + +#define ScreenClearAttrib 0 + +SCREENLINE * +GetScreenLineFromY(SCREEN *pScr, int y) +{ + SCREENLINE *pScrLine; + int idx; + + pScrLine = pScr->screen_top; + for (idx = 0; idx < pScr->height; idx++) { + if (idx == y) + return(pScrLine); + if (pScrLine == NULL) + return(NULL); + pScrLine = pScrLine->next; + } + + return(NULL); +} + + +SCREENLINE * +ScreenClearLine(SCREEN *pScr, SCREENLINE *pScrLine) +{ + memset(pScrLine->attrib, ScreenClearAttrib, pScr->width); + memset(pScrLine->text, ' ', pScr->width); + return(pScrLine); +} + + +void +ScreenUnscroll(SCREEN *pScr) +{ + int idx; + SCREENLINE *pScrLine; + + if (pScr->screen_bottom == pScr->buffer_bottom) + return; + + pScr->screen_bottom = pScr->buffer_bottom; + pScrLine = pScr->screen_bottom; + for (idx = 1; idx < pScr->height; idx++) { + if (pScrLine == NULL) + return; + pScrLine = pScrLine->prev; + } + pScr->screen_top = pScrLine; +} + + +void +ScreenCursorOn(SCREEN *pScr) +{ + int y; + int nlines; + + if (pScr->screen_bottom != pScr->buffer_bottom) + nlines = pScr->numlines - GetScrollPos(pScr->hWnd, SB_VERT); + else + nlines = 0; + + y = pScr->y + nlines; + SetCaretPos(pScr->x * pScr->cxChar, (y+1) * pScr->cyChar); + ShowCaret(pScr->hWnd); +} + + +void +ScreenCursorOff(SCREEN *pScr) +{ + HideCaret(pScr->hWnd); +} + + +void +ScreenELO(SCREEN *pScr, int s) +{ + SCREENLINE *pScrLine; + RECT rc; + + if (s < 0) + s = pScr->y; + + pScrLine = GetScreenLineFromY(pScr,s); + memset(pScrLine->attrib, ScreenClearAttrib, pScr->width); + memset(pScrLine->text, ' ', pScr->width); + rc.left = 0; + rc.right = pScr->width * pScr->cxChar; + rc.top = pScr->cyChar * s; + rc.bottom = pScr->cyChar * (s+1); + InvalidateRect(pScr->hWnd, &rc, TRUE); +} + +void +ScreenEraseScreen(SCREEN *pScr) +{ + int i; + int x1 = 0; + int y1 = 0; + int x2 = pScr->width; + int y2 = pScr->height; + int n = -1; + + for(i = 0; i < pScr->height; i++) + ScreenELO(pScr,i); + + InvalidateRect(pScr->hWnd, NULL, TRUE); + UpdateWindow(pScr->hWnd); +} + + +void +ScreenTabClear(SCREEN *pScr) +{ + int x = 0; + + while(x <= pScr->width) { + pScr->tabs[x] = ' '; + x++; + } +} + + +void +ScreenTabInit(SCREEN *pScr) +{ + int x = 0; + + ScreenTabClear(pScr); + + while(x <= pScr->width) { + pScr->tabs[x] = 'x'; + x += 8; + } + pScr->tabs[pScr->width] = 'x'; +} + + +void +ScreenReset(SCREEN *pScr) +{ + pScr->top = 0; + pScr->bottom = pScr->height-1; + pScr->parmptr = 0; + pScr->escflg = 0; + pScr->DECAWM = 1; + pScr->bWrapPending = FALSE; + pScr->DECCKM = 0; + pScr->DECPAM = 0; + /* pScr->DECORG = 0; */ + /* pScr->Pattrib = -1; */ + pScr->IRM = 0; + pScr->attrib = 0; + pScr->x = 0; + pScr->y = 0; + /* pScr->charset = 0; */ + ScreenEraseScreen(pScr); + ScreenTabInit(pScr); +#if 0 + /* + * QAK - 7/27/90: added because resetting the virtual screen's + * wrapping flag doesn't reset telnet window's wrapping + */ + set_vtwrap(pScrn, pScr->DECAWM); +#endif +} + + +void +ScreenListMove(SCREENLINE *TD, SCREENLINE *BD, SCREENLINE *TI, SCREENLINE *BI) +{ + if (TD->prev != NULL) + TD->prev->next = BD->next; /* Maintain circularity */ + + if (BD->next != NULL) + BD->next->prev = TD->prev; + + TD->prev = TI; /* Place the node in its new home */ + BD->next = BI; + + if (TI != NULL) + TI->next = TD; /* Ditto prev->prev */ + + if (BI != NULL) + BI->prev = BD; +} + + +void +ScreenDelLines(SCREEN *pScr, int n, int s) +{ + SCREENLINE *BI; + SCREENLINE *TI; + SCREENLINE *TD; + SCREENLINE *BD; + SCREENLINE *pLine; + int idx; + RECT rc; + HDC hDC; + + pScr->bWrapPending = FALSE; + + if (s < 0) + s = pScr->y; + + if (s + n - 1 > pScr->bottom) + n = pScr->bottom - s + 1; + + TD = GetScreenLineFromY(pScr, s); + BD = GetScreenLineFromY(pScr, s + n - 1); + TI = GetScreenLineFromY(pScr, pScr->bottom); + BI = TI->next; + + /* + * Adjust the top of the screen and buffer if they will move. + */ + if (TD == pScr->screen_top) { + if (pScr->screen_top == pScr->buffer_top) + pScr->buffer_top = BD->next; + pScr->screen_top = BD->next; + } + + /* + * Adjust the bottom of the screen and buffer if they will move. + */ + if (TI == pScr->screen_bottom) { + if (pScr->screen_bottom == pScr->buffer_bottom) + pScr->buffer_bottom = BD; + pScr->screen_bottom = BD; + } + + if (TI != BD) + ScreenListMove(TD, BD, TI, BI); + + /* + * Clear the lines moved from the deleted area to the + * bottom of the scrolling area. + */ + pLine = TI; + + for (idx = 0; idx < n; idx++) { + pLine = pLine->next; + ScreenClearLine(pScr, pLine); + } + + /* CheckScreen(pScr); */ + + /* + * Scroll the affected area on the screen. + */ + rc.left = 0; + rc.right = pScr->width * pScr->cxChar; + rc.top = s * pScr->cyChar; + rc.bottom = (pScr->bottom + 1) * pScr->cyChar; + + hDC = GetDC(pScr->hWnd); + + ScrollDC(hDC, 0, -pScr->cyChar * n, &rc, &rc, NULL, NULL); + + PatBlt(hDC, 0, (pScr->bottom - n + 1) * pScr->cyChar, + pScr->width * pScr->cxChar, n * pScr->cyChar, WHITENESS); + + ReleaseDC(pScr->hWnd, hDC); +} + + +void +ScreenInsertLine(SCREEN *pScr, int s) +{ + ScreenInsLines(pScr, 1, s); +} + + +void +ScreenInsLines(SCREEN *pScr, int n, int s) +{ + SCREENLINE *TI; + SCREENLINE *BI; + SCREENLINE *TD; + SCREENLINE *BD; + SCREENLINE *pLine; + int idx; + RECT rc; + HDC hDC; + + pScr->bWrapPending = FALSE; + + if (s < 0) + s = pScr->y; + + if (s + n - 1 > pScr->bottom) + n = pScr->bottom - s + 1; + + /* + * Determine the top and bottom of the insert area. Also determine + * the top and bottom of the area to be deleted and moved to the + * insert area. + */ + BI = GetScreenLineFromY(pScr, s); + TI = BI->prev; + TD = GetScreenLineFromY(pScr, pScr->bottom - n + 1); + BD = GetScreenLineFromY(pScr, pScr->bottom); + + /* + * Adjust the top of the screen and buffer if they will move. + */ + if (BI == pScr->screen_top) { + if (pScr->screen_top == pScr->buffer_top) + pScr->buffer_top = TD; + pScr->screen_top = TD; + } + + /* + * Adjust the bottom of the screen and buffer if they will move. + */ + if (BD == pScr->screen_bottom) { + if (pScr->screen_bottom == pScr->buffer_bottom) + pScr->buffer_bottom = TD->prev; + pScr->screen_bottom = TD->prev; + } + + /* + * Move lines from the bottom of the scrolling region to the insert area. + */ + if (TD != BI) + ScreenListMove(TD,BD,TI,BI); + + /* + * Clear the inserted lines + */ + pLine = GetScreenLineFromY(pScr, s); + + for (idx = 0; idx < n; idx++) { + ScreenClearLine(pScr, pLine); + pLine = pLine->next; + } + + /* CheckScreen(pScr); */ + + /* + * Scroll the affected area on the screen. + */ + rc.left = 0; + rc.right = pScr->width * pScr->cxChar; + rc.top = s * pScr->cyChar; + rc.bottom = (pScr->bottom + 1) * pScr->cyChar; + + hDC = GetDC(pScr->hWnd); + + ScrollDC(hDC, 0, pScr->cyChar * n, &rc, &rc, NULL, NULL); + + PatBlt(hDC, 0, s * pScr->cyChar, + pScr->width * pScr->cxChar, n * pScr->cyChar, WHITENESS); + + ReleaseDC(pScr->hWnd, hDC); +} + + +void +ScreenIndex(SCREEN * pScr) +{ + if (pScr->y >= pScr->bottom) + ScreenScroll(pScr); + else + pScr->y++; + + pScr->bWrapPending = FALSE; +} + + +void +ScreenWrapNow(SCREEN *pScr, int *xp, int *yp) +{ + if (pScr->bWrapPending && pScr->x >= pScr->width - 1) { + pScr->x = 0; + ScreenIndex(pScr); + } + + pScr->bWrapPending = FALSE; + + *xp = pScr->x; + *yp = pScr->y; +} + + +void +ScreenEraseToEOL(SCREEN *pScr) +{ + int x1 = pScr->x; + int y1 = pScr->y; + int x2 = pScr->width; + int y2 = pScr->y; + int n = -1; + SCREENLINE *pScrLine; + RECT rc; + + ScreenWrapNow(pScr, &x1, &y1); + + y2 = y1; +#if 0 + wsprintf(strTmp,"[EraseEOL:%d]",y2); + OutputDebugString(strTmp); +#endif + pScrLine = GetScreenLineFromY(pScr,y2); + memset(&pScrLine->attrib[x1], ScreenClearAttrib, pScr->width-x1+1); + memset(&pScrLine->text[x1], ' ', pScr->width - x1 + 1); + rc.left = x1 * pScr->cxChar; + rc.right = pScr->width * pScr->cxChar; + rc.top = pScr->cyChar * y1; + rc.bottom = pScr->cyChar * (y1 + 1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + UpdateWindow(pScr->hWnd); +} + + +void +ScreenDelChars(SCREEN *pScr, int n) +{ + int x = pScr->x; + int y = pScr->y; + int width; + SCREENLINE *pScrLine; + RECT rc; + + pScr->bWrapPending = FALSE; + + pScrLine = GetScreenLineFromY(pScr, y); + + width = pScr->width - x - n; + + if (width > 0) { + memmove(&pScrLine->attrib[x], &pScrLine->attrib[x + n], width); + memmove(&pScrLine->text[x], &pScrLine->text[x + n], width); + } + + memset(&pScrLine->attrib[pScr->width - n], ScreenClearAttrib, n); + memset(&pScrLine->text[pScr->width - n], ' ', n); + + rc.left = x * pScr->cxChar; + rc.right = pScr->width * pScr->cxChar; + rc.top = pScr->cyChar * y; + rc.bottom = pScr->cyChar * (y + 1); + + InvalidateRect(pScr->hWnd, &rc, TRUE); + + UpdateWindow(pScr->hWnd); +} + + +void +ScreenRevIndex(SCREEN *pScr) +{ + SCREENLINE *pScrLine; + SCREENLINE *pTopLine; + + pScr->bWrapPending = FALSE; + pScrLine = GetScreenLineFromY(pScr, pScr->y); + pTopLine = GetScreenLineFromY(pScr, pScr->top); + + if(pScrLine == pTopLine) + ScreenInsertLine(pScr, pScr->y); + else + pScr->y--; +} + + +void +ScreenEraseToBOL(SCREEN *pScr) +{ + int x1 = 0; + int y1 = pScr->y; + int x2 = pScr->x; + int y2 = pScr->y; + int n = -1; + SCREENLINE *pScrLine; + + pScrLine = GetScreenLineFromY(pScr, pScr->y); + + ScreenWrapNow(pScr, &x2, &y1); + y2 = y1; + memset(pScrLine->attrib, ScreenClearAttrib, x2); + memset(pScrLine->text, ' ', x2); +} + + +void +ScreenEraseLine(SCREEN *pScr, int s) +{ + int x1 = 0; + int y1 = s; + int x2 = pScr->width; + int y2 = s; + int n = -1; + SCREENLINE *pScrLine; + RECT rc; + + if (s < 0) { + ScreenWrapNow(pScr, &x1, &y1); + s = y2 = y1; + x1 = 0; + } + + pScrLine = GetScreenLineFromY(pScr,y1); + memset(pScrLine->attrib, ScreenClearAttrib, pScr->width); + memset(pScrLine->text, ' ', pScr->width); + rc.left = 0; + rc.right = pScr->width * pScr->cxChar; + rc.top = pScr->cyChar * y1; + rc.bottom = pScr->cyChar * (y1+1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + SendMessage(pScr->hWnd, WM_PAINT, 0, 0); +} + + +void +ScreenEraseToEndOfScreen(SCREEN *pScr) +{ + int i; + int x1 = 0; + int y1 = pScr->y+1; + int x2 = pScr->width; + int y2 = pScr->height; + int n = -1; + + ScreenWrapNow(pScr, &x1, &y1); + y1++; + x1 = 0; + i = y1; + ScreenEraseToEOL(pScr); + while (i < pScr->height) { + ScreenELO(pScr, i); + ScreenEraseLine(pScr, i); + i++; + } +} + + +void +ScreenRange(SCREEN *pScr) +{ + if (pScr->x < 0) + pScr->x = 0; + + if (pScr->x >= pScr->width) + pScr->x = pScr->width - 1; + + if (pScr->y < 0) + pScr->y = 0; + + if (pScr->y >= pScr->height) + pScr->y = pScr->height - 1; +} + + +void +ScreenAlign(SCREEN *pScr) /* vt100 alignment, fill screen with 'E's */ +{ + char *tt; + int i; + int j; + SCREENLINE *pScrLine; + + pScrLine = GetScreenLineFromY(pScr, pScr->top); + ScreenEraseScreen(pScr); + + for(j = 0; j < pScr->height; j++) { + tt = &pScrLine->text[0]; + for(i = 0; i <= pScr->width; i++) + *tt++ = 'E'; + pScrLine = pScrLine->next; + } +} + + +void +ScreenApClear(SCREEN *pScr) +{ + /* + * reset all the ANSI parameters back to the default state + */ + for(pScr->parmptr=5; pScr->parmptr>=0; pScr->parmptr--) + pScr->parms[pScr->parmptr] = -1; + + pScr->parmptr = 0; +} + + +void +ScreenSetOption(SCREEN *pScr, int toggle) +{ + if (pScr->parms[0] == -2 && pScr->parms[1] == 1) + pScr->DECCKM = toggle; + +#if 0 + switch(pScr->parms[0]) { + + case -2: /* Set on the '?' char */ + switch(pScr->parms[1]) { + + case 1: /* set/reset cursor key mode */ + pScr->DECCKM = toggle; + break; + +#ifdef NOT_SUPPORTED + case 2: /* set/reset ANSI/vt52 mode */ + break; +#endif + + case 3: /* set/reset column mode */ + pScr->x = pScr->y = 0; /* Clear the screen, mama! */ + ScreenEraseScreen(pScr); +#if 0 /* removed for variable screen size */ + if (toggle) /* 132 column mode */ + pScr->width = pScr->allwidth; + else + pScr->width = 79; +#endif + break; + +#ifdef NOT_SUPPORTED + case 4: /* set/reset scrolling mode */ + case 5: /* set/reset screen mode */ + case 6: /* set/rest origin mode */ + pScr->DECORG = toggle; + break; +#endif + + case 7: /* set/reset wrap mode */ + pScr->DECAWM = toggle; +#if 0 + /* + * QAK - 7/27/90: added because resetting the virtual screen's + * wrapping flag doesn't reset telnet window's wrapping + */ + set_vtwrap(pScrn, fpScr->DECAWM); +#endif + break; + +#ifdef NOT_SUPPORTED + case 8: /* set/reset autorepeat mode */ + case 9: /* set/reset interlace mode */ + break; +#endif + + default: + break; + } /* end switch */ + break; + + case 4: + pScr->IRM=toggle; + break; + + default: + break; + + } /* end switch */ +#endif +} + + +#ifdef NOT_SUPPORTED +void +ScreenTab(SCREEN *pScr) +{ + if (pScr->x> = pScr->width) + pScr->x = pScr->width; + pScr->x++; + while (pScr->tabs[fpScr->x] != 'x' && pScr->x < pScr->width) + pScr->x++; +} +#endif + + +BOOL +ScreenInsChar(SCREEN *pScr, int x) +{ + int i; + SCREENLINE *pScrLine; + RECT rc; + + pScrLine = GetScreenLineFromY(pScr, pScr->y); + if (pScrLine == NULL) + return(FALSE); + + for(i = pScr->width - x; i >= pScr->x; i--) { + pScrLine->text[x+i] = pScrLine->text[i]; + pScrLine->attrib[x+i] = pScrLine->attrib[i]; + } + + memset(&pScrLine->attrib[pScr->x], ScreenClearAttrib, x); + memset(&pScrLine->text[pScr->x], ' ', x); + rc.left = pScr->cxChar * x; + rc.right = pScr->cxChar * (x + pScr->x); + rc.top = pScr->cyChar * (pScr->y - 1); + rc.bottom = pScr->cyChar * pScr->y; + InvalidateRect(pScr->hWnd, &rc, TRUE); + SendMessage(pScr->hWnd, WM_PAINT, 0, 0); + return(TRUE); +} + + +void +ScreenSaveCursor(SCREEN *pScr) +{ + pScr->Px = pScr->x; + pScr->Py = pScr->y; + pScr->Pattrib = pScr->attrib; +} + + +void +ScreenRestoreCursor(SCREEN *pScr) +{ + pScr->x = pScr->Px; + pScr->y = pScr->Py; + ScreenRange(pScr); +} + + +void +ScreenDraw(SCREEN *pScr, int x, int y, int a, int len, char *c) +{ + int idx; + SCREENLINE *pScrLine; + RECT rc; + + pScrLine = GetScreenLineFromY(pScr, y); + assert(pScrLine != NULL); + + for(idx = x; idx < x + len; idx++) { + pScrLine->text[idx] = c[idx - x]; + pScrLine->attrib[idx - x] = a; + } + + rc.left = pScr->cxChar * x; + rc.right = pScr->cxChar * (x + len); + rc.top = pScr->cyChar * pScr->y; + rc.bottom = pScr->cyChar * (pScr->y + 1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + SendMessage(pScr->hWnd, WM_PAINT, 0, 0); +} + + +#if ! defined(NDEBUG) + +BOOL +CheckScreen(SCREEN *pScr) +{ + SCREENLINE *pLinePrev; + SCREENLINE *pLine; + int nscreen = 0; + int nbuffer = 0; + int topline = 0; + char buf[512]; + BOOL bBottom; + BOOL bOK; + + pLine = pScr->buffer_top; + + if (pLine == NULL) { + OutputDebugString("CheckScreen: buffer_top invalid"); + MessageBox(NULL, "buffer_top invalid", "CheckScreen", MB_OK); + return(FALSE); + } + + bBottom = FALSE; + while (TRUE) { + pLinePrev = pLine; + if (nscreen > 0 || pLine == pScr->screen_top) + if (!bBottom) + nscreen++; + nbuffer++; + if (pLine == pScr->screen_top) + topline = nbuffer - 1; + if (pLine == pScr->screen_bottom) + bBottom = TRUE; + pLine = pLine->next; + if (pLine == NULL) + break; + if (pLine->prev != pLinePrev) { + wsprintf(buf, + "Previous ptr of line %d does not match next ptr of line %d", + nbuffer, nbuffer - 1); + OutputDebugString(buf); + MessageBox(NULL, buf, "CheckScreen", MB_OK); + } + } + + if (pLinePrev == pScr->buffer_bottom && nscreen == pScr->height) + bOK = TRUE; + else { + OutputDebugString("CheckScreen: Invalid number of lines on screen"); + bOK = FALSE; + } + + wsprintf(buf, "screen.width = %d\nscreen.height = %d\nscreen.maxlines = %d\nscreen.numlines = %d\nscreen.x = %d\nscreen.y = %d\nscreen.top = %d\nscreen.bottom = %d\nActual top line = %d\nActual buffer lines = %d\nActual screen lines = %d\nBottom of buffer is %s", + pScr->width, pScr->height, pScr->maxlines, pScr->numlines, + pScr->x, pScr->y, pScr->top, pScr->bottom, + topline, nbuffer, nscreen, + (pLinePrev == pScr->buffer_bottom) ? "valid" : "invalid"); + + MessageBox(NULL, buf, "CheckScreen", MB_OK); + + return(bOK); +} + +#endif diff --git a/mechglue/src/windows/wintel/k5stream.c b/mechglue/src/windows/wintel/k5stream.c new file mode 100644 index 000000000..a31538518 --- /dev/null +++ b/mechglue/src/windows/wintel/k5stream.c @@ -0,0 +1,119 @@ +/* + * + * K5stream + * + * Emulates the kstream package in Kerberos 4 + * + */ + +#include <stdio.h> +#include <io.h> +#include <malloc.h> +#include "telnet.h" +#include "k5stream.h" +#include "auth.h" + +int +kstream_destroy(kstream ks) +{ + if (ks != NULL) { + auth_destroy(ks); /* Destroy authorizing */ + + closesocket(ks->fd); /* Close the socket??? */ + free(ks); + } + return 0; +} + +void +kstream_set_buffer_mode(kstream ks, int mode) +{ +} + + +kstream +kstream_create_from_fd(int fd, + const struct kstream_crypt_ctl_block *ctl, + kstream_ptr data) +{ + kstream ks; + int n; + BOOL on = 1; + + ks = malloc(sizeof(struct kstream_int)); + if (ks == NULL) + return NULL; + + ks->fd = fd; + + setsockopt(ks->fd, SOL_SOCKET, SO_OOBINLINE, (const char *)&on, sizeof(on)); + + n = auth_init(ks, data); /* Initialize authorizing */ + if (n) { + free(ks); + return NULL; + } + + ks->encrypt = NULL; + ks->decrypt = NULL; + + return ks; +} + +int +kstream_write(kstream ks, void *p_data, size_t p_len) +{ + int n; + struct kstream_data_block i; + +#ifdef DEBUG + hexdump("plaintext:", p_data, p_len); +#endif + + if (ks->encrypt) { + i.ptr = p_data; + i.length = p_len; + ks->encrypt(&i, NULL, NULL); +#ifdef DEBUG + hexdump("cyphertext:", p_data, p_len); +#endif + } + + n = send(ks->fd, p_data, p_len, 0); /* Write the data */ + + return n; /* higher layer does retries */ +} + + +int +kstream_read(kstream ks, void *p_data, size_t p_len) +{ + int n; + struct kstream_data_block i; + + n = recv(ks->fd, p_data, p_len, 0); /* read the data */ + + if (n < 0) + return n; + +#ifdef DEBUG + hexdump("input data:", p_data, n); +#endif + + if (ks->decrypt) { + extern int encrypt_flag; + + if (encrypt_flag == 2) + encrypt_flag = 1; + + i.ptr = p_data; + i.length = n; + ks->decrypt(&i, NULL, NULL); +#ifdef DEBUG + hexdump("decrypted data:", p_data, n); +#endif + } + + return n; /* higher layer does retries */ +} + diff --git a/mechglue/src/windows/wintel/k5stream.h b/mechglue/src/windows/wintel/k5stream.h new file mode 100644 index 000000000..3a63ca1d8 --- /dev/null +++ b/mechglue/src/windows/wintel/k5stream.h @@ -0,0 +1,57 @@ +/* Header file for encrypted-stream library. + * Written by Ken Raeburn (Raeburn@Cygnus.COM). + * Copyright (C) 1991, 1992, 1994 by Cygnus Support. + * + * Permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation. + * Cygnus Support makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#ifndef K5STREAM_H +#define K5STREAM_H + +typedef struct kstream_int { /* Object we pass around */ + int fd; /* Open socket descriptor */ + int (*encrypt)(struct kstream_data_block *, /* output */ + struct kstream_data_block *, /* input */ + struct kstream *kstream); + int (*decrypt)(struct kstream_data_block *, /* output */ + struct kstream_data_block *, /* input */ + struct kstream *kstream); +} *kstream; + +typedef void *kstream_ptr; /* Data send on the kstream */ + +struct kstream_data_block { + kstream_ptr ptr; + size_t length; +}; + +struct kstream_crypt_ctl_block { + int (*encrypt)(struct kstream_data_block *, /* output */ + struct kstream_data_block *, /* input */ + kstream); + int (*decrypt)(struct kstream_data_block *, /* output */ + struct kstream_data_block *, /* input */ + kstream); + int (*init)(kstream, kstream_ptr); + void (*destroy)(kstream); +}; + + +/* Prototypes */ + +int kstream_destroy(kstream); +void kstream_set_buffer_mode(kstream, int); +kstream kstream_create_from_fd(int fd, + const struct kstream_crypt_ctl_block *, + kstream_ptr); +int kstream_write(kstream, void *, size_t); +int kstream_read(kstream, void *, size_t); + +#endif /* K5STREAM_H */ diff --git a/mechglue/src/windows/wintel/ktelnet.doc b/mechglue/src/windows/wintel/ktelnet.doc new file mode 100644 index 0000000000000000000000000000000000000000..64e4f452697bdd664faa1be51e115c9506bf784a GIT binary patch literal 16384 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 Ycp}u;e@5B}^l_zsi(h;8@Y|&S2Q5ZA<p2Nx literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/wintel/ktelnet.hlp b/mechglue/src/windows/wintel/ktelnet.hlp new file mode 100644 index 0000000000000000000000000000000000000000..e44cebfe574db2e6254ed0e249edcfd70b10f3eb GIT binary patch literal 9204 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 DM|puD literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/wintel/ktelnet.hpj b/mechglue/src/windows/wintel/ktelnet.hpj new file mode 100644 index 000000000..d69185cd8 --- /dev/null +++ b/mechglue/src/windows/wintel/ktelnet.hpj @@ -0,0 +1,92 @@ +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; Help Project File for KTELNET +; +; This file is maintained by RoboHELP. Do not modify this file directly. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[OPTIONS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Options section contains the following information: +; +; The optional BMROOT= entry sets the directories in which the Help Compiler +; will look for graphics. +; +; The CONTENTS= tells WinHelp which topic contains the contents. +; +; The TITLE= is displayed in the Title Bar of WINHELP.EXE +; +; The BUILD= setting allows you to create different Help systems from +; the same source file. +; +; The COMPRESS= option tells the Help Compiler how much to compress +; the Help file. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +;BMROOT=C:\WINDOWS\DESKTOP\KERBEROS 5\WIN95 GUI\CNS HELP +TITLE=Kerb*Net Telnet for Windows +BUILD=WINDOWS +NOTES=1 + + +OLDKEYPHRASE=NO +OPTCDROM=0 +REPORT=YES +COMPRESS=12 +ERRORLOG=C:\windows\desktop\kerberos 5\win95 gui\cns help\KTELNET.ERR +[BUILDTAGS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Build Tags section specifies to the Help Compiler the names +; of all the valid build tags used in this Help project. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +WINDOWS + + +[CONFIG] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Config section defines macros which will run at startup. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + + + +[FILES] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Files section specifies the RTF files for a project. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +KTELNET.RTF +[ALIAS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Alias section sets up aliases for Topic IDs in your Help system. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[MAP] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Map section specifies the project HH files. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[BITMAPS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Bitmaps section specifies the referenced bitmaps used in +; your help system. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + + +[WINDOWS] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Windows section contains all of the information about the windows +; in a Help project. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +;Gloss = "Glossary",(100,100,350,350),0,(255,255,255),(255,255,255) +main=,,29188,, +(w95sec)=,,20740,(r14745599),(r14745599),f2 + + +[BAGGAGE] +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; The Baggage section specifies any additional files. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + diff --git a/mechglue/src/windows/wintel/ncsa.ico b/mechglue/src/windows/wintel/ncsa.ico new file mode 100644 index 0000000000000000000000000000000000000000..8a6cb6a564b581cb96115998f13bc864e432c31b GIT binary patch literal 766 zcmZvaF?NJ73`B=)-h<Am(n6VAY>u=yh;Oi0;wULox(h|#bN<M%u$u_RwyYV+GDscI zG`-07^(4JAzkvz7gHF$kQYQAl%@VKXxlN2L!K|D!ff}!B^$PHKi=iaO)d(GJF!yLf z(UD)2q;yD7?C*jPvhN<Nn(q==drYvX9uxGn*xwDh{jFdbS~wcWgL_M^XP-IMMvpeL zG}I;JRCVv(4*DOzlxq!sqp46Z@<m$Hk-A><Rcc=E(CwJ+Q{0Ru>SgnYAiu8n9ZV0a z&xtwr!?h>X?@f++@89)ZiqEj=TY|jPW94q{>_!iM{1RsfBS^WSpC#k;xq?C`&@T<? a2OjIuVE+t8xJE)}Jm%=&7(yfTQTP|72n06( literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/wintel/negotiat.c b/mechglue/src/windows/wintel/negotiat.c new file mode 100644 index 000000000..685092df5 --- /dev/null +++ b/mechglue/src/windows/wintel/negotiat.c @@ -0,0 +1,865 @@ +/* + * negotiat.c + * + * Telnet option negotiation functions + * + +/* + * Includes + */ + +/* #define USETEK */ +/* #define USERAS */ + +#ifdef DEBUG /* define this to print the raw network data to debuging monitor */ +#define NEGOTIATEDEBUG +#endif + +#if 0 +#define PRINT_EVERYTHING /* talk a lot */ +#endif + +#include <time.h> +#include "telnet.h" +#include "telnet_arpa.h" +#include "auth.h" +#include "encrypt.h" + +#define STNORM 0 +#define NEGOTIATE 1 +#define ESCFOUND 5 +#define IACFOUND 6 + +unsigned char parsedat[256]; + +/* Local functions */ +static void parse_subnegotiat(kstream ks,int end_sub); + +/* Local variables */ +static char *telstates[]={ + "EOF", + "Suspend Process", + "Abort Process", + "Unknown (239)", + "Subnegotiation End", + "NOP", + "Data Mark", + "Break", + "Interrupt Process", + "Abort Output", + "Are You There", + "Erase Character", + "Erase Line", + "Go Ahead", + "Subnegotiate", + "Will", + "Won't", + "Do", + "Don't" +}; + +static char *teloptions[256]={ /* ascii strings for Telnet options */ + "Binary", /* 0 */ + "Echo", + "Reconnection", + "Supress Go Ahead", + "Message Size Negotiation", + "Status", /* 5 */ + "Timing Mark", + "Remote Controlled Trans and Echo", + "Output Line Width", + "Output Page Size", + "Output Carriage-Return Disposition", /* 10 */ + "Output Horizontal Tab Stops", + "Output Horizontal Tab Disposition", + "Output Formfeed Disposition", + "Output Vertical Tabstops", + "Output Vertical Tab Disposition", /* 15 */ + "Output Linefeed Disposition", + "Extended ASCII", + "Logout", + "Byte Macro", + "Data Entry Terminal", /* 20 */ + "SUPDUP", + "SUPDUP Output", + "Send Location", + "Terminal Type", + "End of Record", /* 25 */ + "TACACS User Identification", + "Output Marking", + "Terminal Location Number", + "3270 Regime", + "X.3 PAD", /* 30 */ + "Negotiate About Window Size", + "Terminal Speed", + "Toggle Flow Control", + "Linemode", + "X Display Location", /* 35 */ + "Environment", + "Authentication", + "Data Encryption", + "39", + "40","41","42","43","44","45","46","47","48","49", + "50","51","52","53","54","55","56","57","58","59", + "60","61","62","63","64","65","66","67","68","69", + "70","71","72","73","74","75","76","77","78","79", + "80","81","82","83","84","85","86","87","88","89", + "90","91","92","93","94","95","96","97","98","99", + "100","101","102","103","104","105","106","107","108","109", + "110","111","112","113","114","115","116","117","118","119", + "120","121","122","123","124","125","126","127","128","129", + "130","131","132","133","134","135","136","137","138","139", + "140","141","142","143","144","145","146","147","148","149", + "150","151","152","153","154","155","156","157","158","159", + "160","161","162","163","164","165","166","167","168","169", + "170","171","172","173","174","175","176","177","178","179", + "180","181","182","183","184","185","186","187","188","189", + "190","191","192","193","194","195","196","197","198","199", + "200","201","202","203","204","205","206","207","208","209", + "210","211","212","213","214","215","216","217","218","219", + "220","221","222","223","224","225","226","227","228","229", + "230","231","232","233","234","235","236","237","238","239", + "240","241","242","243","244","245","246","247","248","249", + "250","251","252","253","254", + "Extended Options List" /* 255 */ +}; + +static char *LMoptions[]={ /* ascii strings for Linemode sub-options */ + "None", "MODE", "FORWARDMASK", "SLC" +}; + +static char *ModeOptions[]={ /* ascii strings for Linemode edit options */ + "None", "EDIT", "TRAPSIG", "ACK", "SOFT TAB", "LIT ECHO" +}; + +static char *SLCoptions[]={ /* ascii strings for Linemode SLC characters */ + "None", "SYNCH", "BREAK", "IP", "ABORT OUTPUT", + "AYT", "EOR", "ABORT", "EOF", "SUSP", + "EC", "EL", "EW", "RP", "LNEXT", + "XON", "XOFF", "FORW1", "FORW2", "MCL", + "MCR", "MCWL", "MCWR", "MCBOL", "MCEOL", + "INSRT", "OVER", "ECR", "EWR", "EBOL", + "EEOL" +}; + +static char *SLCflags[]={ /* ascii strings for Linemode SLC flags */ + "SLC_NOSUPPORT", "SLC_CANTCHANGE", "SLC_VALUE", "SLC_DEFAULT" +}; + +/* Linemode default character for each function */ +static unsigned char LMdefaults[NTELOPTS + 1]={ + (unsigned char)-1, /* zero isn't used */ + (unsigned char)-1, /* we don't support SYNCH */ + 3, /* ^C is default for BRK */ + 3, /* ^C is default for IP */ + 15, /* ^O is default for AO */ + 25, /* ^Y is default for AYT */ /* 5 */ + (unsigned char)-1, /* we don't support EOR */ + 3, /* ^C is default for ABORT */ + 4, /* ^D is default for EOF */ + 26, /* ^Z is default for SUSP */ + 8, /* ^H is default for EC */ /* 10 */ + 21, /* ^U is default for EL */ + 23, /* ^W is default for EW */ + 18, /* ^R is default for RP */ + 22, /* ^V is default for LNEXT */ + 17, /* ^Q is default for XON */ /* 15 */ + 19, /* ^S is default for XOFF */ + 22, /* ^V is default for FORW1 */ + 5, /* ^E is default for FORW2 */ + (unsigned char)-1, /* we don't support MCL */ + (unsigned char)-1, /* we don't support MCR */ /* 20 */ + (unsigned char)-1, /* we don't support MCWL */ + (unsigned char)-1, /* we don't support MCWR */ + (unsigned char)-1, /* we don't support MCBOL */ + (unsigned char)-1, /* we don't support MCEOL */ + (unsigned char)-1, /* we don't support INSRT */ /* 25 */ + (unsigned char)-1, /* we don't support OVER */ + (unsigned char)-1, /* we don't support ECR */ + (unsigned char)-1, /* we don't support EWR */ + (unsigned char)-1, /* we don't support EBOL */ + (unsigned char)-1 /* we don't support EEOL */ /* 30 */ +}; + + +/* + * Function : start_negotiation() + * Purpose : Send the initial negotiations on the network and print + * the negotitations to the console screen. + * Parameters : + * dat - the port number to write to + * cvs - the console's virtual screen + * Returns : none + * Calls : tprintf(), netprintf() + * Called by : dosessions() + */ +void +start_negotiation(kstream ks) +{ + char buf[128]; + + /* Send the initial telnet negotiations */ +#ifdef ENCRYPTION /* XXX */ + if (encrypt_flag) + wsprintf(buf,"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", + IAC, WILL, TELOPT_AUTHENTICATION, + IAC, WILL, TELOPT_ENCRYPT, + IAC, DO, TELOPT_SGA, + IAC, DO, TELOPT_ECHO, + IAC, WILL, TELOPT_NAWS + ); + else +#endif + wsprintf(buf,"%c%c%c%c%c%c%c%c%c%c%c%c", + IAC, WILL, TELOPT_AUTHENTICATION, + IAC, DO, TELOPT_SGA, + IAC, DO, TELOPT_ECHO, + IAC, WILL, TELOPT_NAWS + ); + TelnetSend(ks,buf,lstrlen(buf),0); + +#ifdef NOT + /* check whether we are going to be output mapping */ + if(tw->mapoutput) { + netprintf(tw->pnum,"%c%c%c",IAC,DO,TELOPT_BINARY); + /* set the flag indicating we wanted server to start transmitting binary */ + tw->uwantbinary=1; + netprintf(tw->pnum,"%c%c%c",IAC,WILL,TELOPT_BINARY); + /* set the flag indicating we want to start transmitting binary */ + tw->iwantbinary=1; + } /* end if */ +#endif + + /* Print to the console what we just did */ +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n",telstates[DO - TELCMD_FIRST], + teloptions[TELOPT_ECHO]); + OutputDebugString(strTmp); + wsprintf(strTmp,"SEND: %s %s\r\n",telstates[DO - TELCMD_FIRST], + teloptions[TELOPT_SGA]); + OutputDebugString(strTmp); + wsprintf(strTmp,"SEND: %s %s\r\n",telstates[WILL - TELCMD_FIRST], + teloptions[TELOPT_NAWS]); + OutputDebugString(strTmp); + +#ifdef NOT + tprintf(cvs,"SEND: %s %s\r\n",telstates[DO - TELCMD_FIRST], + teloptions[BINARY]); + tprintf(cvs,"SEND: %s %s\r\n",telstates[WILL - TELCMD_FIRST], + teloptions[BINARY]); +#endif +#endif +} /* end start_negotiation() */ + +/* + * parse + * Do the telnet negotiation parsing. + * + * look at the string which has just come in from outside and + * check for special sequences that we are interested in. + * + * Tries to pass through routine strings immediately, waiting for special + * characters ESC and IAC to change modes. + */ +void +parse(CONNECTION *con,unsigned char *st,int cnt) +{ + static int sub_pos; /* the position we are in the subnegotiation parsing */ + static int end_sub; /* index of last byte in parsedat in a subnegotiation */ + unsigned char *mark, *orig; + char buf[256]; + kstream ks; + + ks = con->ks; + +#ifdef PRINT_EVERYTHING + hexdump("Options to process:", st, cnt); +#endif /* PRINT_EVERYTHING */ + + orig = st; /* remember beginning point */ + mark = st + cnt; /* set to end of input string */ + +#ifdef HUH + netpush(tw->pnum); +#endif + + /* + * traverse string, looking for any special characters which indicate that + * we need to change modes. + */ + while(st < mark) { + + while(con->telstate != STNORM && st < mark) { + switch(con->telstate) { + case IACFOUND: /* telnet option negotiation */ + if(*st == IAC) { /* real data=255 */ + st++; /* real 255 will get sent */ + con->telstate = STNORM; + break; + } /* end if */ + + if(*st > 239) { + con->telstate = *st++; /* by what the option is */ + break; + } /* end if */ + +#ifdef NEGOTIATEDEBUG + wsprintf(buf, "\r\n strange telnet option"); + OutputDebugString(buf); +#endif + orig=++st; + con->telstate=STNORM; + break; + + case EL: /* received a telnet erase line command */ + case EC: /* received a telnet erase character command */ + case AYT: /* received a telnet Are-You-There command */ + case AO: /* received a telnet Abort Output command */ + case IP: /* received a telnet Interrupt Process command */ + case BREAK: /* received a telnet Break command */ + case DM: /* received a telnet Data Mark command */ + case NOP: /* received a telnet No Operation command */ + case SE: /* received a telnet Subnegotiation End command */ + case ABORT: /* received a telnet Abort Process command */ + case SUSP: /* received a telnet Suspend Process command */ + case xEOF: /* received a telnet EOF command */ +#ifdef NEGOTIATEDEBUG + wsprintf(buf,"RECV: %s\r\n", + telstates[con->telstate-TELCMD_FIRST]); + OutputDebugString(buf); +#endif + con->telstate=STNORM; + orig=++st; + break; + + case GA: /* telnet go ahead option*/ +#ifdef NEGOTIATEDEBUG + wsprintf(buf,"RECV: %s\r\n", + telstates[con->telstate-TELCMD_FIRST]); + OutputDebugString(buf); +#endif + con->telstate=STNORM; + orig=++st; + break; + + case DO: /* received a telnet DO negotiation */ +#ifdef NEGOTIATEDEBUG + wsprintf(buf,"RECV: %s %s\r\n", + telstates[con->telstate-TELCMD_FIRST],teloptions[*st]); + OutputDebugString(buf); +#endif + switch(*st) { +#ifdef NOT + case TELOPT_BINARY: /* DO: binary transmission */ + if(!tw->ibinary) { /* binary */ + if(!tw->iwantbinary) { + netprintf(tw->pnum,"%c%c%c", + IAC,WILL,BINARY); + if(tw->condebug>0) + tprintf(cv,"SEND: %s %s\r\n", + telstates[WILL - TELCMD_FIRST], + teloptions[BINARY]); + } /* end if */ + else + tw->iwantbinary=0; /* turn off this now */ + tw->ibinary=1; + } /* end if */ + else { + if(tw->condebug>0) + tprintf(cv,"NO REPLY NEEDED: %s %s\r\n", + telstates[WILL - TELCMD_FIRST], + teloptions[BINARY]); + } /* end else */ + break; +#endif + + case TELOPT_SGA: /* DO: Suppress go-ahead */ + if(!con->igoahead) { /* suppress go-ahead */ + wsprintf(buf,"%c%c%c",IAC,WILL,TELOPT_SGA); + TelnetSend(ks,buf,lstrlen(buf),0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[WILL - TELCMD_FIRST], + teloptions[TELOPT_SGA]); + OutputDebugString(strTmp); + OutputDebugString("igoahead"); +#endif + con->igoahead=1; + } /* end if */ + else { +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp, + "NO REPLY NEEDED: %s %s\r\n", + telstates[WILL - TELCMD_FIRST], + teloptions[TELOPT_SGA]); + OutputDebugString(strTmp); +#endif + } /* end else */ + break; + + case TELOPT_TTYPE: /* DO: terminal type negotiation */ + if(!con->termsent) { + con->termsent=TRUE; + wsprintf(buf,"%c%c%c",IAC,WILL,TELOPT_TTYPE); + TelnetSend(ks,buf,lstrlen(buf),0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[WILL - TELCMD_FIRST], + teloptions[TELOPT_TTYPE]); + OutputDebugString(strTmp); +#endif + } /* end if */ + else { +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"NO REPLY NEEDED: %s %s\r\n", + telstates[WILL - TELCMD_FIRST], + teloptions[TELOPT_TTYPE]); + OutputDebugString(strTmp); +#endif + } /* end else */ + break; + +#ifdef LATER + case TELOPT_LINEMODE: /* DO: linemode negotiation */ + tw->lmflag=1; /* set the linemode flag */ + netprintf(tw->pnum,"%c%c%c",IAC,WILL,TELOPT_LINEMODE); + /* + * Tell the other side to send us + * its default character set + */ + netprintf(tw->pnum,"%c%c%c%c", + IAC,SB,TELOPT_LINEMODE,SLC,0,SLC_DEFAULT,0,IAC,SE); + if(tw->condebug>0) { + tprintf(cv,"SEND: %s %s\r\n", + telstates[WILL - TELCMD_FIRST], + teloptions[TELOPT_LINEMODE]); + tprintf(cv, + "SEND: SB LINEMODE SLC 0 SLC_DEFAULT 0 IAC SE\r\n"); + } /* end if */ + break; +#endif + case TELOPT_NAWS: /* DO: Negotiate About Window Size */ + con->bResizeable=TRUE; + send_naws(con); + break; + + case TELOPT_AUTHENTICATION: /* DO: Authentication requested */ + wsprintf(buf, "%c%c%c", IAC, WILL, TELOPT_AUTHENTICATION); + TelnetSend(ks, buf, lstrlen(buf), 0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[WILL - TELCMD_FIRST], + teloptions[TELOPT_AUTHENTICATION]); + OutputDebugString(strTmp); +#endif + break; + +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: /* DO: Remote is willing to receive encrypted */ + wsprintf(buf, "%c%c%c", IAC, + (encrypt_flag ? WILL : WONT), TELOPT_ENCRYPT); + TelnetSend(ks, buf, lstrlen(buf), 0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[(encrypt_flag ? WILL : WONT) + - TELCMD_FIRST], + teloptions[TELOPT_ENCRYPT]); + OutputDebugString(strTmp); +#endif + break; +#endif /* ENCRYPTION */ + + default: /* DO: */ + wsprintf(buf, "%c%c%c", IAC, WONT, *st); + TelnetSend(ks, buf, lstrlen(buf), 0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[WONT - TELCMD_FIRST], teloptions[*st]); + OutputDebugString(strTmp); +#endif + break; + + } /* end switch */ + con->telstate = STNORM; + orig = ++st; + break; + + case DONT: /* Received a telnet DONT option */ + switch (*st) { + case TELOPT_NAWS: + con->bResizeable=FALSE; +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"RECV: %s %s\r\n", + telstates[con->telstate-TELCMD_FIRST],teloptions[*st]); + OutputDebugString(strTmp); +#endif + break; + +#ifdef NOT + case BINARY: /* DONT: check for binary neg. */ + if(tw->ibinary) { /* binary */ + if(!tw->iwantbinary) { + netprintf(tw->pnum,"%c%c%c",IAC,WONT,BINARY); + if(tw->condebug>0) + tprintf(cv,"SEND: %s %s\r\n", + telstates[WONT-TELCMD_FIRST], + teloptions[BINARY]); + } /* end if */ + else + tw->iwantbinary=0; /* turn off this now */ + tw->ibinary=0; + tw->mapoutput=0; /* turn output mapping off */ + } /* end if */ +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"NO REPLY NEEDED: %s %s\r\n", + telstates[WONT-TELCMD_FIRST], + teloptions[BINARY]); + OutputDebugString(strTmp); +#endif + break; +#endif +#ifdef ENCRYPTION + case ENCRYPTION: + break; +#endif + } + + /* all these just fall through to here... */ + + con->telstate=STNORM; + orig=++st; + break; + + case WILL: /* received a telnet WILL option */ +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"RECV: %s %s\r\n", + telstates[con->telstate-TELCMD_FIRST], + teloptions[*st]); + OutputDebugString(strTmp); +#endif + switch(*st) { +#ifdef NOT + case TELOPT_BINARY: /* WILL: binary */ + if(!tw->ubinary) { /* binary */ + if(!tw->uwantbinary) { + netprintf(tw->pnum,"%c%c%c", + IAC,DO,TELOPT_BINARY); + if(tw->condebug>0) + tprintf(cv,"SEND: %s %s\r\n", + telstates[DO - TELCMD_FIRST], + teloptions[TELOPT_BINARY]); + } /* end if */ + else + tw->uwantbinary=0; /* turn off this now */ + tw->ubinary=1; + } /* end if */ + else { + if(tw->condebug>0) + tprintf(cv,"NO REPLY NEEDED: %s %s\r\n", + telstates[DO - TELCMD_FIRST], + teloptions[TELOPT_BINARY]); + } /* end else */ + break; +#endif + + case TELOPT_SGA: /* WILL: suppress go-ahead */ + if(!con->ugoahead) { + con->ugoahead=1; + wsprintf(buf,"%c%c%c",IAC,DO,TELOPT_SGA); /* ack */ + TelnetSend(ks,buf,lstrlen(buf),0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[DO - TELCMD_FIRST], + teloptions[TELOPT_SGA]); + OutputDebugString(strTmp); +#endif + } /* end if */ + break; + + case TELOPT_ECHO: /* WILL: echo */ + if(!con->echo) { + con->echo = 1; + wsprintf(buf, "%c%c%c", IAC, DO, TELOPT_ECHO); /* ack */ + TelnetSend(ks, buf, lstrlen(buf), 0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[DO - TELCMD_FIRST], + teloptions[TELOPT_ECHO]); + OutputDebugString(strTmp); +#endif + } /* end if */ + break; + + case TELOPT_TM: /* WILL: Timing mark */ + con->timing=0; + break; +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: /* WILL: decrypt our input */ + wsprintf(buf, "%c%c%c", IAC, + (encrypt_flag ? DO : DONT), TELOPT_ENCRYPT); + TelnetSend(ks, buf, lstrlen(buf), 0); + if (encrypt_flag) + encrypt_send_support(); + +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[(encrypt_flag ? DO : DONT) - TELCMD_FIRST], + teloptions[TELOPT_ENCRYPT]); + OutputDebugString(strTmp); +#endif + break; +#endif + + default: + wsprintf(buf,"%c%c%c",IAC,DONT,*st); + TelnetSend(ks,buf,lstrlen(buf),0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[DONT-TELCMD_FIRST],teloptions[*st]); + OutputDebugString(strTmp); +#endif + break; + } /* end switch */ + con->telstate=STNORM; + orig=++st; + break; + + case WONT: /* Received a telnet WONT option */ +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"RECV: %s %s\r\n", + telstates[con->telstate-TELCMD_FIRST],teloptions[*st]); + OutputDebugString((LPSTR)strTmp); +#endif + con->telstate=STNORM; + switch(*st++) { /* which option? */ +#ifdef NOT + case BINARY: /* WONT: binary */ + if(tw->ubinary) { /* binary */ + if(!tw->uwantbinary) { + netprintf(tw->pnum,"%c%c%c", + IAC,DONT,BINARY); + if(tw->condebug>0) + tprintf(cv,"SEND: %s %s\r\n", + telstates[DONT-TELCMD_FIRST], + teloptions[BINARY]); + } /* end if */ + else + tw->uwantbinary=0; /* turn off this now */ + tw->ubinary=0; + tw->mapoutput=0; /* turn output mapping off */ + } /* end if */ + else { + if(tw->condebug>0) + tprintf(cv,"NO REPLY NEEDED: %s %s\r\n", + telstates[DONT-TELCMD_FIRST], + teloptions[BINARY]); + } /* end else */ + break; + +#endif + case TELOPT_ECHO: /* WONT: echo */ + if(con->echo) { + con->echo=0; + wsprintf(buf,"%c%c%c",IAC,DONT,TELOPT_ECHO); + TelnetSend(ks,buf,lstrlen(buf),0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SEND: %s %s\r\n", + telstates[DONT-TELCMD_FIRST], + teloptions[TELOPT_ECHO]); + OutputDebugString(strTmp); + OutputDebugString("Other side won't echo!"); +#endif + } /* end if */ + break; + + case TELOPT_TM: /* WONT: Telnet timing mark option */ + con->timing=0; + break; + +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: /* WONT: don't encrypt our input */ + break; +#endif + + default: + break; + } /* end switch */ + orig=st; + break; + + case SB: /* telnet sub-options negotiation */ + con->telstate=NEGOTIATE; + orig=st; + end_sub=0; + sub_pos=con->substate=0; /* Defined for each */ +#ifdef OLD_WAY + break; +#endif + + case NEGOTIATE: + /* until we change sub-negotiation states, accumulate bytes */ + if(con->substate==0) { + if(*st==IAC) { /* check if we found an IAC byte */ + if(*(st+1)==IAC) { /* skip over double IAC's */ + st++; + parsedat[sub_pos++]=*st++; + } /* end if */ + else { + end_sub=sub_pos; + con->substate=*st++; + } /* end else */ + } /* end if */ + else /* otherwise, just stash the byte */ + parsedat[sub_pos++]=*st++; + } /* end if */ + else { + con->substate=*st++; + /* check if we've really ended the sub-negotiations */ + if(con->substate==SE) + parse_subnegotiat(ks,end_sub); + + orig=st; + /* + * XXX hack to decrypt the rest of the buffer + */ + if (encrypt_flag == 2) { + decrypt_ks_hack(orig, mark - orig); + encrypt_flag = 1; + } + + con->telstate=STNORM; + } /* end else */ + break; + + default: + con->telstate=STNORM; + break; + } /* end switch */ + } /* end while */ + + /* + * quick scan of the remaining string, skip chars while they are + * uninteresting + */ + if(con->telstate==STNORM && st<mark) { + /* + * skip along as fast as possible until an interesting character is found + */ + while(st<mark && *st!=27 && *st!=IAC) { +#if 0 + if(!tw->ubinary) + *st&=127; /* mask off high bit */ +#endif + st++; + } /* end while */ +#if 0 + if(!tw->timing) + parsewrite(tw,orig,st-orig); +#endif + orig=st; /* forget what we have sent already */ + if(st<mark) + switch(*st) { + case IAC: /* telnet IAC */ + con->telstate=IACFOUND; + st++; + break; + + default: +#ifdef NEGOTIATEDEBUG + wsprintf(buf," strange char>128 0x%x\r\n", *st); + OutputDebugString(buf); +#endif + st++; + break; + } /* end switch */ + } /* end if */ + } /* end while */ +} /* end parse() */ + +/* + * Function : parse_subnegotiat() + * Purpose : Parse the telnet sub-negotiations read into the parsedat + * array. + * Parameters : + * end_sub - index of the character in the 'parsedat' array which + * is the last byte in a sub-negotiation + * Returns : none + * Calls : + * Called by : parse() + */ +static void +parse_subnegotiat(kstream ks, int end_sub) +{ + char buf[128]; + + switch(parsedat[0]) { + case TELOPT_TTYPE: + if(parsedat[1]==1) { + /* QAK!!! */ wsprintf(buf,"%c%c%c%cvt100%c%c",IAC,SB,TELOPT_TTYPE, + 0,IAC,SE); + TelnetSend(ks,(LPSTR)buf,11,0); +#ifdef NEGOTIATEDEBUG + wsprintf(strTmp,"SB TERMINAL-TYPE SEND\r\n" + "SEND: SB TERMINAL-TYPE IS vt100 \r\n len=%d \r\n", + lstrlen((LPSTR)buf)); + OutputDebugString(strTmp); +#endif + } + break; + + case TELOPT_AUTHENTICATION: + auth_parse(ks, parsedat, end_sub); + break; +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: + if (encrypt_flag) + encrypt_parse(ks, parsedat, end_sub); + break; +#endif + default: + break; + } /* end switch */ +} /* parse_subnegotiat */ + + +/* + * Function : send_naws + * Purpose : Send a window size sub-negotiation. + * Parameters : + * ks - the kstream to send to. + * Returns : none + */ +void +send_naws(CONNECTION *con) +{ + unsigned char buf[40]; + int len; + + wsprintf(buf, "%c%c%c", IAC, SB, TELOPT_NAWS); + len = 3; + + buf[len++] = HIBYTE(con->width); + if (buf[len-1] == IAC) buf[len++] = IAC; + + buf[len++] = LOBYTE(con->width); + if (buf[len-1] == IAC) buf[len++] = IAC; + + buf[len++] = HIBYTE(con->height); + if (buf[len-1] == IAC) buf[len++] = IAC; + + buf[len++] = LOBYTE(con->height); + if (buf[len-1] == IAC) buf[len++] = IAC; + + buf[len++] = IAC; + buf[len++] = SE; + + TelnetSend(con->ks, buf, len, 0); + +#ifdef NEGOTIATEDEBUG + wsprintf(buf, "SEND: SB NAWS %d %d %d %d IAC SE\r\n", + HIBYTE(con->width), LOBYTE(con->width), + HIBYTE(con->height), LOBYTE(con->height)); + OutputDebugString(buf); +#endif + +} /* send_naws */ diff --git a/mechglue/src/windows/wintel/resource.h b/mechglue/src/windows/wintel/resource.h new file mode 100644 index 000000000..0d39d5ca0 --- /dev/null +++ b/mechglue/src/windows/wintel/resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by telnet.rc +// +#define IDD_DIALOG1 101 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40005 +#define _APS_NEXT_CONTROL_VALUE 1002 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/mechglue/src/windows/wintel/screen.c b/mechglue/src/windows/wintel/screen.c new file mode 100644 index 000000000..206c97c89 --- /dev/null +++ b/mechglue/src/windows/wintel/screen.c @@ -0,0 +1,1147 @@ +/* screen.c */ + +#include <windows.h> +#include <commdlg.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "telnet.h" +#include "ini.h" +#include "auth.h" + +extern char *encrypt_output; /* XXX hack... I wonder if this will work. These are */ +extern char *decrypt_input; /* XXX really functions... */ + +extern char *cInvertedArray; +extern int bMouseDown; +extern int bSelection; + +static SCREEN *ScreenList; +static HINSTANCE hInst; +static char szScreenClass[] = "ScreenWClass"; +static char szScreenMenu[] = "ScreenMenu"; +static char cursor_key[8][4] = { /* Send for cursor keys */ + "\x1B[D", "\x1B[A", "\x1B[C", "\x1B[B", /* Normal mode */ + "\x1BOD", "\x1BOA", "\x1BOC", "\x1BOB", /* Numpad on mode */ +}; + +void +ScreenInit(HINSTANCE hInstance) +{ + BOOL b; + WNDCLASS wc; + + hInst = hInstance; + + ScreenList = NULL; + + wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; /* Class style(s) */ + wc.lpfnWndProc = ScreenWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(long); + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(hInstance, "TERMINAL"); + wc.hCursor = LoadCursor(NULL, IDC_IBEAM); + wc.hbrBackground = GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = szScreenMenu; + wc.lpszClassName = szScreenClass; + + b = RegisterClass(&wc); + assert(b); +} + + +void +SetScreenInstance(HINSTANCE hInstance) +{ + hInst = hInstance; +} + +int +GetNewScreen(void) +{ + SCREEN *pScr; + static int id = 0; + + pScr = (SCREEN *) calloc(sizeof(SCREEN), 1); + if (pScr == NULL) + return(-1); + + if (ScreenList == NULL) { + pScr->next = NULL; + pScr->prev = NULL; + } + else { + if (ScreenList->next == NULL) { + ScreenList->next = ScreenList; + ScreenList->prev = ScreenList; + } + pScr->next = ScreenList; + pScr->prev = ScreenList->prev; + ScreenList->prev->next = pScr; + ScreenList->prev = pScr; + } + + ScreenList = pScr; + return(id++); +} + +SCREENLINE * +ScreenNewLine(void) +{ + SCREENLINE *pScrLine; + + pScrLine = calloc(sizeof(SCREENLINE) + 2*MAX_LINE_WIDTH, 1); + if (pScrLine == NULL) + return (NULL); + pScrLine->text = &pScrLine->buffer[0]; + pScrLine->attrib = &pScrLine->buffer[MAX_LINE_WIDTH]; + return(pScrLine); +} + +static void +MakeWindowTitle(char *host, int width, int height, char *title, int nchars) +{ + char buf[128]; + int hlen; + + hlen = strlen(host); + + title[0] = 0; + + if (hlen + 1 > nchars) + return; + + strcpy(title, host); + + wsprintf(buf, " (%dh x %dw)", height, width); + + if ((int) strlen(buf) + hlen + 1 > nchars) + return; + + strcat(title, buf); +} + + +SCREEN * +InitNewScreen(CONFIG *Config) +{ + TEXTMETRIC tm; + HMENU hMenu = NULL; + SCREEN *scr = NULL; + SCREENLINE *pScrLine; + SCREENLINE *pScrLineLast; + int id; + int idx = 0; + char title[128]; + HDC hDC; + HFONT hFont; + + id = GetNewScreen(); + if (id == -1) + return(0); + + scr = ScreenList; + assert(scr != NULL); + + hMenu = LoadMenu(hInst, szScreenMenu); + assert(hMenu != NULL); + + scr->title = Config->title; + MakeWindowTitle(Config->title, Config->width, Config->height, + title, sizeof(title)); + + scr->hwndTel = Config->hwndTel; /* save HWND of calling window */ + + if (Config->backspace) { + CheckMenuItem(hMenu, IDM_BACKSPACE, MF_CHECKED); + CheckMenuItem(hMenu, IDM_DELETE, MF_UNCHECKED); + } else { + CheckMenuItem(hMenu, IDM_BACKSPACE, MF_UNCHECKED); + CheckMenuItem(hMenu, IDM_DELETE, MF_CHECKED); + } + + hDC = GetDC(NULL); + assert(hDC != NULL); + + scr->lf.lfPitchAndFamily = FIXED_PITCH; + GetPrivateProfileString(INI_FONT, "FaceName", "Courier", scr->lf. + lfFaceName, LF_FACESIZE, TELNET_INI); + scr->lf.lfHeight = (int) GetPrivateProfileInt(INI_FONT, "Height", 0, TELNET_INI); + scr->lf.lfWidth = (int) GetPrivateProfileInt(INI_FONT, "Width", 0, TELNET_INI); + scr->lf.lfPitchAndFamily = (BYTE) GetPrivateProfileInt(INI_FONT, "PitchAndFamily", 0, TELNET_INI); + scr->lf.lfCharSet = (BYTE) GetPrivateProfileInt(INI_FONT, "CharSet", 0, TELNET_INI); + scr->lf.lfEscapement = (BYTE) GetPrivateProfileInt(INI_FONT, "Escapement", 0, TELNET_INI); + scr->lf.lfQuality = PROOF_QUALITY; + scr->hSelectedFont = CreateFontIndirect((LPLOGFONT) &(scr->lf)); + hFont = SelectObject(hDC, scr->hSelectedFont); + GetTextMetrics(hDC, (LPTEXTMETRIC) &tm); + SelectObject(hDC, hFont); + scr->cxChar = tm.tmAveCharWidth; + scr->cyChar = tm.tmHeight + tm.tmExternalLeading; + + ReleaseDC(NULL, hDC); + + scr->width = Config->width; + scr->height = Config->height; + scr->ID = id; + scr->x = 0; + scr->y = 0; + scr->Oldx = 0; + scr->Oldy = 0; + scr->attrib = 0; + scr->DECAWM = 1; + scr->bWrapPending = FALSE; + scr->top = 0; + scr->bottom = scr->height-1; + scr->parmptr = 0; + scr->escflg = 0; + scr->bAlert = FALSE; + scr->numlines = 0; + scr->maxlines = 150; + + cInvertedArray = calloc(scr->width * scr->height, 1); + + pScrLineLast = ScreenNewLine(); + if (pScrLineLast == NULL) + return(NULL); + scr->screen_top = scr->buffer_top = pScrLineLast; + + for (idx = 0; idx < scr->height - 1; idx++) { + pScrLine = ScreenNewLine(); + if (pScrLine == NULL) + return(NULL); + pScrLine->prev = pScrLineLast; + pScrLineLast->next = pScrLine; + pScrLineLast = pScrLine; + } + + scr->screen_bottom = scr->buffer_bottom = pScrLine; + + scr->hWnd = CreateWindow(szScreenClass, title, WS_OVERLAPPEDWINDOW | WS_VSCROLL, + CW_USEDEFAULT, CW_USEDEFAULT, + scr->cxChar * scr->width + FRAME_WIDTH, + scr->cyChar * scr->height + FRAME_HEIGHT, + NULL, hMenu, hInst, scr); + assert(scr->hWnd != NULL); + + ShowWindow(scr->hWnd, SW_SHOW); + + CreateCaret(scr->hWnd, NULL, scr->cxChar, 2); + SetCaretPos(scr->x*scr->cxChar, (scr->y+1) * scr->cyChar); + ShowCaret(scr->hWnd); + + return(ScreenList); +} + + +void DeleteTopLine( + SCREEN *pScr) +{ + assert(pScr->buffer_top != NULL); + + pScr->buffer_top = pScr->buffer_top->next; + assert(pScr->buffer_top != NULL); + + free(pScr->buffer_top->prev); + pScr->buffer_top->prev = NULL; + + pScr->numlines--; + +} /* DeleteTopLine */ + + +static void SetScreenScrollBar( + SCREEN *pScr) +{ + if (pScr->numlines <= 0) { + SetScrollRange(pScr->hWnd, SB_VERT, 0, 100, FALSE); + SetScrollPos(pScr->hWnd, SB_VERT, 0, TRUE); + EnableScrollBar(pScr->hWnd, SB_VERT, ESB_DISABLE_BOTH); + } + else { + SetScrollRange(pScr->hWnd, SB_VERT, 0, pScr->numlines, FALSE); + SetScrollPos(pScr->hWnd, SB_VERT, pScr->numlines, TRUE); + EnableScrollBar(pScr->hWnd, SB_VERT, ESB_ENABLE_BOTH); + } + +} /* SetScreenScrollBar */ + + +int ScreenScroll( + SCREEN *pScr) +{ + SCREENLINE *pScrLine; + SCREENLINE *pPrev; + SCREENLINE *pNext; + SCREENLINE *pScrollTop; + SCREENLINE *pScrollBottom; + BOOL bFullScreen = TRUE; + HDC hDC; + RECT rc; + + Edit_ClearSelection(pScr); + + pScrollTop = GetScreenLineFromY(pScr, pScr->top); + + pScrollBottom = GetScreenLineFromY(pScr, pScr->bottom); + + if (pScrollTop != pScr->screen_top) { + bFullScreen = FALSE; + rc.left = 0; + rc.right = pScr->cxChar * pScr->width; + rc.top = pScr->cyChar * (pScr->top); + rc.bottom = pScr->cyChar * (pScr->bottom+1); + + pNext = pScrollTop->next; + pPrev = pScrollTop->prev; + + pPrev->next = pNext; + pNext->prev = pPrev; + + pScrLine = pScrollTop; + ScreenClearLine(pScr, pScrLine); + } + else { + pScr->numlines++; + pScrLine = ScreenNewLine(); + if (pScrLine == NULL) + return(0); + pScr->screen_top = pScrollTop->next; + } + + if (pScrLine == NULL) + return(0); + + pNext = pScrollBottom->next; + pScrollBottom->next = pScrLine; + pScrLine->next = pNext; + pScrLine->prev = pScrollBottom; + if (pNext != NULL) + pNext->prev = pScrLine; + + if (pScrollBottom != pScr->screen_bottom) { + bFullScreen = FALSE; + rc.left = 0; + rc.right = pScr->cxChar * pScr->width; + rc.top = pScr->cyChar * pScr->top; + rc.bottom = pScr->cyChar * (pScr->bottom+1); + } + else { + if (pScr->screen_bottom == pScr->buffer_bottom) + pScr->buffer_bottom = pScrLine; + pScr->screen_bottom = pScrLine; + } + +#if 0 + CheckScreen(fpScr); +#endif + + pScr->y++; + + if (pScr->y > pScr->bottom) + pScr->y = pScr->bottom; + + hDC = GetDC(pScr->hWnd); + assert(hDC != NULL); + + if (bFullScreen) + ScrollDC(hDC, 0, -pScr->cyChar, NULL, NULL, NULL, NULL); + else + ScrollDC(hDC, 0, -pScr->cyChar, &rc, &rc, NULL, NULL); + + PatBlt(hDC, 0, pScr->bottom * pScr->cyChar, + pScr->width * pScr->cxChar, pScr->cyChar, WHITENESS); + + ReleaseDC(pScr->hWnd, hDC); + + if (pScr->numlines == pScr->maxlines) + DeleteTopLine(pScr); + else + SetScreenScrollBar(pScr); + + return(1); + +} /* ScreenScroll */ + + +int DrawTextScreen( + RECT rcInvalid, + SCREEN *pScr, + HDC hDC) +{ + SCREENLINE *pScrLineTmp; + SCREENLINE *pScrLine; + int x = 0; + int y = 0; + int left = 0; + int right = 0; + int i; + int len; + char attrib; +#define YPOS (y*pScr->cyChar) + + pScrLine = pScr->screen_top; + + for (y = 0; y < pScr->height; y++) { + if (!pScrLine) + continue; + + if (YPOS >= rcInvalid.top - pScr->cyChar && + YPOS <= rcInvalid.bottom + pScr->cyChar) { + + if (y < 0) + y = 0; + + if (y >= pScr->height) + y = pScr->height - 1; + + left = (rcInvalid.left / pScr->cxChar) - 1; + + right = (rcInvalid.right / pScr->cxChar) + 1; + + if (left < 0) + left = 0; + + if (right > pScr->width - 1) + right = pScr->width - 1; + + x = left; + + while (x <= right) { + if (!pScrLine->text[x]) { + x++; + continue; + } + + if (SCR_isrev(pScrLine->attrib[x])) { + SelectObject(hDC, pScr->hSelectedFont); + SetTextColor(hDC, RGB(255, 255, 255)); + SetBkColor(hDC, RGB(0, 0, 0)); + } + else if (SCR_isblnk(pScrLine->attrib[x])) { + SelectObject(hDC, pScr->hSelectedFont); + SetTextColor(hDC, RGB(255, 0, 0)); + SetBkColor(hDC, RGB(255, 255, 255)); + } + else if (SCR_isundl(pScrLine->attrib[x])) { + SetTextColor(hDC, RGB(255, 0, 0)); + SetBkColor(hDC, RGB(255, 255, 255)); + SelectObject(hDC, pScr->hSelectedULFont); + } + else { + SelectObject(hDC,pScr->hSelectedFont); + SetTextColor(hDC, RGB(0, 0, 0)); + SetBkColor(hDC, RGB(255, 255, 255)); + } + + len = 1; + attrib = pScrLine->attrib[x]; + for (i = x + 1; i <= right; i++) { + if (pScrLine->attrib[i] != attrib || !pScrLine->text[i]) + break; + len++; + } + + TextOut(hDC, x*pScr->cxChar, y*pScr->cyChar, &pScrLine->text[x], len); + x += len; + } + } + pScrLineTmp = pScrLine->next; + pScrLine = pScrLineTmp; + } + + return(0); + +} /* DrawTextScreen */ + + +static BOOL SetInternalScreenSize( + SCREEN *pScr, + int width, + int height) +{ + RECT rc; + char *p; + int idx; + int n; + int newlines; + SCREENLINE *pNewLine; + SCREENLINE *pTopLine; + SCREENLINE *pBottomLine; +#if 0 + int col; + int row; + int dydestbottom; +#endif + + GetClientRect(pScr->hWnd, &rc); + + width = (rc.right - rc.left) / pScr->cxChar; + height = (rc.bottom - rc.top) / pScr->cyChar; + + if (pScr->height == height && pScr->width == width) + return(FALSE); + + pScr->Oldx = 0; + pScr->Oldy = 0; + pScr->attrib = 0; + + /* + Reallocate the inverted array of bytes and copy the values + from the old screen to the new screen. + */ + p = calloc(width * height, 1); + + ScreenCursorOff(pScr); + +#if 0 /* Copy inversion array to desitination */ + for (col = 0; col < width; col++) { + for (row = 0; row < height; row++) { + dydestbottom = height - 1 - row; + if (col < pScr->width && dydestbottom < pScr->height - 1) + p[row * width + col] = + cInvertedArray[(pScr->height - 1 - dydestbottom) * pScr->width + col]; + } + } +#endif + + free(cInvertedArray); + cInvertedArray = p; + + /* + Append any new lines which need to be added to accomodate the new + screen size. + */ + pBottomLine = pScr->buffer_bottom; + newlines = height - (pScr->height + pScr->numlines); + + if (newlines > 0) { + pScr->y += pScr->numlines; + pScr->numlines = 0; + + for (idx = 0; idx < newlines; idx++) { + pNewLine = ScreenNewLine(); + if (pNewLine == NULL) + return(FALSE); + pNewLine->prev = pBottomLine; + if (pBottomLine == NULL) + return(FALSE); + pBottomLine->next = pNewLine; + pBottomLine = pNewLine; + } + } + + /* + If we already have plenty of lines, then we need to get rid of the + scrollback lines, if too many exist. The cursor should end up + the same distance from the bottom of the screen as is started out + in this instance. + */ + if (newlines < 0) { + pScr->y = (height - 1) - (pScr->bottom - pScr->y); + if (pScr->y < 0) + pScr->y = 0; + pScr->numlines = -newlines; + n = pScr->numlines - pScr->maxlines; + for (idx = 0; idx < n; idx++) + DeleteTopLine(pScr); + } + + /* + Calculate the position of the buffer relative to the screen. + */ + pScr->screen_bottom = pBottomLine; + pScr->buffer_bottom = pBottomLine; + + pTopLine = pBottomLine; + + for (idx = 1; idx < height; idx++) { + pTopLine = pTopLine->prev; + } + + pScr->screen_top = pTopLine; + pScr->width = width; + pScr->height = height; + pScr->top = 0; + pScr->bottom = height - 1; + + if (pScr->x >= width) + pScr->x = width - 1; + + if (pScr->y >= height) + pScr->y = height - 1; + + SetScreenScrollBar(pScr); + ScreenCursorOn(pScr); + return(TRUE); + +} /* SetInternalScreenSize */ + + +static int ScreenAdjustUp( + SCREEN *pScr, + int n) +{ + int idx; + SCREENLINE *pLine1; + SCREENLINE *pLine2; + + for (idx = 0; idx < n; idx++) { + if (pScr->screen_top == pScr->buffer_top) + return(-idx); + pLine1 = pScr->screen_top->prev; + if (pLine1 == NULL) + return(-idx); + pLine2 = pScr->screen_bottom->prev; + if (pLine2 == NULL) + return(-idx); + pScr->screen_top = pLine1; + pScr->screen_bottom = pLine2; + } + + return(idx); + +} /* ScreenAdjustUp */ + + +static int ScreenAdjustDown( + SCREEN *pScr, + int n) +{ + int idx; + SCREENLINE *pLine1; + SCREENLINE *pLine2; + + for (idx = 0; idx < n; idx++) { + if (pScr->screen_bottom == pScr->buffer_bottom) + return(-idx); + pLine1 = pScr->screen_top->next; + if (pLine1 == NULL) + return(-idx); + pLine2 = pScr->screen_bottom->next; + if (pLine2 == NULL) + return(-idx); + pScr->screen_top = pLine1; + pScr->screen_bottom = pLine2; + } + + return(idx); + +} /* ScreenAdjustDown */ + + +long PASCAL ScreenWndProc( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + MINMAXINFO *lpmmi; + SCREEN *pScr; + HMENU hMenu; + PAINTSTRUCT ps; + int x = 0; + int y = 0; + int ScrollPos; + int tmpScroll = 0; + int idx; + HDC hDC; + RECT rc; + char title[128]; + static int bDoubleClick = FALSE; + + switch (message) { + + case WM_COMMAND: + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + + switch (wParam) { + + case IDM_EXIT: + if (MessageBox(hWnd, "Terminate this connection?", "Telnet", MB_OKCANCEL) == IDOK) { + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + SendMessage(pScr->hwndTel, WM_MYSCREENCLOSE, 0, (LPARAM) pScr); + } + break; + + case IDM_BACKSPACE: + hMenu = GetMenu(hWnd); + CheckMenuItem(hMenu, IDM_BACKSPACE, MF_CHECKED); + CheckMenuItem(hMenu, IDM_DELETE, MF_UNCHECKED); + SendMessage(pScr->hwndTel, WM_MYSCREENCHANGEBKSP, VK_BACK, (LPARAM) pScr); + break; + + case IDM_DELETE: + hMenu = GetMenu(hWnd); + CheckMenuItem(hMenu, IDM_BACKSPACE, MF_UNCHECKED); + CheckMenuItem(hMenu, IDM_DELETE, MF_CHECKED); + SendMessage(pScr->hwndTel, WM_MYSCREENCHANGEBKSP, 0x7f, (LPARAM) pScr); + break; + + case IDM_FONT: + ScreenCursorOff(pScr); + ProcessFontChange(hWnd); + ScreenCursorOn(pScr); + break; + + case IDM_COPY: + Edit_Copy(hWnd); + hMenu=GetMenu(hWnd); + Edit_ClearSelection(pScr); + break; + + case IDM_PASTE: + Edit_Paste(hWnd); + break; + + case IDM_HELP_INDEX: + WinHelp(hWnd, HELP_FILE, HELP_INDEX, 0); + break; + + case IDM_ABOUT: +#ifdef CYGNUS +#ifdef KRB4 + strcpy(strTmp, " Kerberos 4 for Windows\n"); +#endif +#ifdef KRB5 + strcpy(strTmp, " KerbNet for Windows\n"); +#endif + strcat(strTmp, "\n Version 1.00\n\n"); + strcat(strTmp, " For support, contact:\n"); + strcat(strTmp, " Cygnus Support - (415) 903-1400\n"); +#else /* CYGNUS */ + strcpy(strTmp, " Kerberos 5 Telnet for Windows\n"); + strcat(strTmp, " ALPHA SNAPSHOT 2\n\n"); +#endif /* CYGNUS */ + if (encrypt_flag) { + strcat(strTmp, "\n[Encryption of output requested. State: "); + strcat(strTmp, (encrypt_output ? "encrypting]" : "INACTIVE]")); + strcat(strTmp, "\n[Decryption of input requested. State: "); + strcat(strTmp, (decrypt_input ? "decrypting]\n" : "INACTIVE]\n")); + } + MessageBox(NULL, strTmp, "Kerberos", MB_OK); + break; + +#if defined(DEBUG) + case IDM_DEBUG: + CheckScreen(pScr); + break; +#endif + } + + break; + + case WM_NCCREATE: + pScr = (SCREEN *) ((LPCREATESTRUCT) lParam)->lpCreateParams; + pScr->hWnd = hWnd; + SetWindowLong(hWnd, SCREEN_HANDLE, (LONG) pScr); + SetScrollRange(hWnd, SB_VERT, 0, 100, FALSE); + SetScrollPos(hWnd, SB_VERT, 0, TRUE); + EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH); + return(TRUE); + + case WM_VSCROLL: + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + + ScreenCursorOff(pScr); + + switch(wParam) { + + case SB_LINEDOWN: + if (ScreenAdjustDown(pScr, 1) <= 0) + break; + hDC = GetDC(hWnd); + assert(hDC != NULL); + rc.left = 0; + rc.right = pScr->cxChar * pScr->width; + rc.top = 0; + rc.bottom = pScr->cyChar * (pScr->bottom + 1); + ScrollDC(hDC, 0, -pScr->cyChar, &rc, &rc, NULL, NULL); + ReleaseDC(hWnd, hDC); + rc.top = pScr->cyChar * pScr->bottom; + InvalidateRect(hWnd, &rc, TRUE); + ScrollPos = GetScrollPos(hWnd, SB_VERT); + SetScrollPos(hWnd, SB_VERT, ScrollPos + 1, TRUE); + UpdateWindow(hWnd); + break; + + case SB_LINEUP: + if (ScreenAdjustUp(pScr, 1) <= 0) + break; + hDC = GetDC(hWnd); + assert(hDC != NULL); + rc.left = 0; + rc.right = pScr->cxChar * pScr->width; + rc.top = 0; + rc.bottom = pScr->cyChar * (pScr->bottom + 1); + ScrollDC(hDC, 0, pScr->cyChar, &rc, &rc, NULL, NULL); + ReleaseDC(hWnd, hDC); + rc.bottom = pScr->cyChar; + InvalidateRect(hWnd, &rc, TRUE); + ScrollPos = GetScrollPos(pScr->hWnd, SB_VERT); + SetScrollPos(hWnd,SB_VERT, ScrollPos - 1, TRUE); + UpdateWindow(hWnd); + break; + + case SB_PAGEDOWN: + idx = abs(ScreenAdjustDown(pScr, pScr->height)); + hDC = GetDC(hWnd); + assert(hDC != NULL); + rc.left = 0; + rc.right = pScr->cxChar * pScr->width; + rc.top = 0; + rc.bottom = pScr->cyChar * (pScr->bottom+1); + ScrollDC(hDC, 0, -idx * pScr->cyChar, &rc, &rc, NULL, NULL); + ReleaseDC(hWnd, hDC); + rc.top = pScr->cyChar * (pScr->bottom - idx + 1); + InvalidateRect(hWnd, &rc, TRUE); + ScrollPos=GetScrollPos(hWnd, SB_VERT); + SetScrollPos(hWnd, SB_VERT, ScrollPos + idx, TRUE); + break; + + case SB_PAGEUP: + idx = abs(ScreenAdjustUp(pScr, pScr->height)); + hDC = GetDC(hWnd); + assert(hDC != NULL); + rc.left = 0; + rc.right = pScr->cxChar * pScr->width; + rc.top = 0; + rc.bottom = pScr->cyChar * (pScr->bottom + 1); + ScrollDC(hDC, 0, idx * pScr->cyChar, &rc, &rc, NULL, NULL); + ReleaseDC(hWnd, hDC); + rc.bottom = idx * pScr->cyChar; + InvalidateRect(hWnd, &rc, TRUE); + ScrollPos=GetScrollPos(hWnd, SB_VERT); + SetScrollPos(hWnd, SB_VERT, ScrollPos - idx, TRUE); + break; + + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + ScrollPos = GetScrollPos(hWnd, SB_VERT); + tmpScroll = ScrollPos - LOWORD(lParam); + if (tmpScroll == 0) + break; + if (tmpScroll > 0) + ScreenAdjustUp(pScr, tmpScroll); + else + ScreenAdjustDown(pScr, -tmpScroll); + if (abs(tmpScroll) < pScr->height) { + hDC = GetDC(hWnd); + assert(hDC != NULL); + rc.left = 0; + rc.right = pScr->cxChar * pScr->width; + rc.top = 0; + rc.bottom = pScr->cyChar * (pScr->bottom + 1); + ScrollDC(hDC, 0, tmpScroll * pScr->cyChar, &rc, &rc, NULL, NULL); + ReleaseDC(hWnd, hDC); + if (tmpScroll > 0) { + rc.bottom = tmpScroll * pScr->cyChar; + InvalidateRect(hWnd, &rc, TRUE); + } + else { + rc.top = (pScr->bottom + tmpScroll + 1) * pScr->cyChar; + InvalidateRect(hWnd, &rc, TRUE); + } + } + else + InvalidateRect(hWnd, NULL, TRUE); + + SetScrollPos(hWnd, SB_VERT, LOWORD(lParam), TRUE); + UpdateWindow(hWnd); + break; + } + + ScreenCursorOn(pScr); + break; + + case WM_KEYDOWN: + if (wParam == VK_INSERT) { + if (GetKeyState(VK_SHIFT) < 0) + PostMessage(hWnd, WM_COMMAND, IDM_PASTE, 0); + else if (GetKeyState(VK_CONTROL) < 0) + PostMessage(hWnd, WM_COMMAND, IDM_COPY, 0); + break; + } + /* + ** Check for cursor keys. With control pressed, we treat as + ** keyboard equivalents to scrolling. Otherwise, we send + ** a WM_MYCURSORKEY message with the appropriate string + ** to be sent. Sending the actual string allows the upper + ** level to be ignorant of keyboard modes, etc. + */ + if (wParam < VK_PRIOR || wParam > VK_DOWN) /* Is it a cursor key? */ + break; + + if (GetKeyState (VK_CONTROL) >= 0) { /* No control key */ + if (wParam >= VK_LEFT && wParam <= VK_DOWN) { + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + wParam = wParam - VK_LEFT + (pScr->DECCKM ? 4 : 0); + SendMessage (pScr->hwndTel, WM_MYCURSORKEY, + strlen(cursor_key[wParam]), + (LPARAM) (char *) cursor_key[wParam]); + } + } else { /* Control is down */ + switch (wParam) { + case VK_PRIOR: /* Page up */ + SendMessage(hWnd, WM_VSCROLL, SB_PAGEUP, 0); + break; + case VK_NEXT: /* Page down */ + SendMessage(hWnd, WM_VSCROLL, SB_PAGEDOWN, 0); + break; + case VK_UP: /* Line up */ + SendMessage(hWnd, WM_VSCROLL, SB_LINEUP, 0); + break; + case VK_DOWN: /* Line down */ + SendMessage(hWnd, WM_VSCROLL, SB_LINEDOWN, 0); + break; + } + } + UpdateWindow(hWnd); + break; + + case WM_CHAR: + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + SendMessage(pScr->hwndTel, WM_MYSCREENCHAR, wParam, (LPARAM) pScr); + break; + + case WM_INITMENU: + if (IsClipboardFormatAvailable(CF_TEXT)) + EnableMenuItem((HMENU) wParam, IDM_PASTE, MF_ENABLED); + else + EnableMenuItem((HMENU) wParam, IDM_PASTE, MF_GRAYED); + if (bSelection) + EnableMenuItem((HMENU) wParam, IDM_COPY, MF_ENABLED); + else + EnableMenuItem((HMENU) wParam, IDM_COPY, MF_GRAYED); + break; + + case WM_GETMINMAXINFO: + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + if (pScr == NULL) /* Used on creation when window word not set */ + pScr = ScreenList; + lpmmi = (MINMAXINFO *) lParam; + if (FRAME_WIDTH + MAX_LINE_WIDTH * pScr->cxChar < lpmmi->ptMaxSize.x) + lpmmi->ptMaxSize.x = FRAME_WIDTH + MAX_LINE_WIDTH * pScr->cxChar; + lpmmi->ptMaxTrackSize.x = lpmmi->ptMaxSize.x; + lpmmi->ptMinTrackSize.x = FRAME_WIDTH + 20 * pScr->cxChar; + lpmmi->ptMinTrackSize.y = FRAME_HEIGHT + 4 * pScr->cyChar; + break; + + case WM_LBUTTONDOWN: + if (bDoubleClick) + Edit_TripleClick(hWnd, lParam); + else + Edit_LbuttonDown(hWnd, lParam); + break; + + case WM_LBUTTONUP: + Edit_LbuttonUp(hWnd, lParam); + break; + + case WM_LBUTTONDBLCLK: + bDoubleClick = TRUE; + SetTimer(hWnd, TIMER_TRIPLECLICK, GetDoubleClickTime(), NULL); + Edit_LbuttonDblclk(hWnd, lParam); + break; + + case WM_TIMER: + if (wParam == TIMER_TRIPLECLICK) + bDoubleClick = FALSE; + break; + + case WM_RBUTTONUP: + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + Edit_Copy(hWnd); + Edit_ClearSelection(pScr); + Edit_Paste(hWnd); + break; + + case WM_MOUSEMOVE: + if (bMouseDown) + Edit_MouseMove(hWnd, lParam); + break; + + case WM_RBUTTONDOWN: +#if 0 + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + wsprintf(strTmp,"fp->x=%d fp->y=%d text=%s \r\n", + pScr->screen_top->x, pScr->screen_top->y, pScr->screen_top->text); + OutputDebugString(strTmp); +#endif + break; + + case WM_PAINT: + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + BeginPaint (hWnd, &ps); + SelectObject(ps.hdc, pScr->hSelectedFont); + if (pScr->screen_bottom != NULL) + DrawTextScreen(ps.rcPaint, pScr, ps.hdc); + else + OutputDebugString("screen_bottom is NULL.\r\n"); + EndPaint(hWnd, &ps); + break; + + case WM_CLOSE: + if (MessageBox(hWnd, "Terminate this connection?", "Telnet", MB_OKCANCEL) == IDOK) { + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + SendMessage(pScr->hwndTel, WM_MYSCREENCLOSE, 0, (LPARAM) pScr); + return (DefWindowProc(hWnd, message, wParam, lParam)); + } + break; + + case WM_DESTROY: + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + if (pScr != NULL) + DeleteObject(pScr->hSelectedFont); + return (DefWindowProc(hWnd, message, wParam, lParam)); + + case WM_ACTIVATE: + if (wParam != WA_INACTIVE) { + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + if (pScr->bAlert) { + char strTitle[128]; + int idx; + + GetWindowText(hWnd, strTitle, sizeof(strTitle)); + if (strTitle[0] == ALERT) { + idx = lstrlen(strTitle); + strTitle[idx - 2] = 0; + SetWindowText(hWnd, &strTitle[2]); + pScr->bAlert = FALSE; + } + } + } + return (DefWindowProc(hWnd, message, wParam, lParam)); + + case WM_SIZE: + if (wParam == SIZE_MINIMIZED) + break; + + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + + if (SetInternalScreenSize(pScr, LOWORD(lParam), HIWORD(lParam))) { + SendMessage(pScr->hwndTel, WM_MYSCREENSIZE, 0, + MAKELONG(pScr->width, pScr->height)); + } + MakeWindowTitle(pScr->title, pScr->width, pScr->height, + title, sizeof(title)); + SetWindowText(hWnd, title); + break; + + case WM_SETFOCUS: + pScr = (SCREEN *) GetWindowLong(hWnd, SCREEN_HANDLE); + assert (pScr != NULL); + CreateCaret(hWnd, NULL, pScr->cxChar, 2); + ScreenCursorOn(pScr); + break; + + case WM_KILLFOCUS: + DestroyCaret(); + break; + + default: + return(DefWindowProc(hWnd, message, wParam, lParam)); + } + + return(0); + +} /* ScreenWndProc */ + + +void ScreenBell( + SCREEN *pScr) +{ + char strTitle[128]; + int idx; + + MessageBeep(MB_ICONEXCLAMATION); + if (pScr->hWnd != GetActiveWindow()) { + FlashWindow(pScr->hWnd, TRUE); + if (!pScr->bAlert) { + strTitle[0] = ALERT; + strTitle[1] = SPACE; + GetWindowText(pScr->hWnd, &strTitle[2], sizeof(strTitle) - 2); + idx = lstrlen(strTitle); + strTitle[idx] = SPACE; + strTitle[idx+1] = ALERT; + strTitle[idx+2] = 0; + SetWindowText(pScr->hWnd, strTitle); + } + FlashWindow(pScr->hWnd, FALSE); + pScr->bAlert = TRUE; + } + +} /* ScreenBell */ + + +void ScreenBackspace(SCREEN *pScr) +{ + RECT rc; + + pScr->bWrapPending = FALSE; + rc.left = pScr->x * pScr->cxChar; + rc.right = (pScr->x + 1) * pScr->cxChar; + rc.top = pScr->cyChar * pScr->y; + rc.bottom = pScr->cyChar * (pScr->y + 1); + InvalidateRect(pScr->hWnd, &rc, TRUE); + pScr->x--; + if (pScr->x < 0) + pScr->x = 0; + UpdateWindow(pScr->hWnd); + +} /* ScreenBackspace */ + + +void ScreenTab( + SCREEN *pScr) +{ + int num_spaces; + int idx; + SCREENLINE *pScrLine; + int iTest = 0; + HDC hDC; + + num_spaces = TAB_SPACES - (pScr->x % TAB_SPACES); + if (pScr->x + num_spaces >= pScr->width) + num_spaces = pScr->width - pScr->x; + pScrLine = GetScreenLineFromY(pScr, pScr->y); + if (pScrLine == NULL) + return; + for (idx = 0; idx < num_spaces; idx++, pScr->x++) { + if (!pScrLine->text[pScr->x]) + iTest=1; + if (iTest) + pScrLine->text[pScr->x] = SPACE; + } + hDC = GetDC(pScr->hWnd); + assert(hDC != NULL); + SelectObject(hDC, pScr->hSelectedFont); + TextOut(hDC, (pScr->x - num_spaces) * pScr->cxChar, pScr->y * pScr->cyChar, + pScrLine->text + pScr->x - num_spaces, num_spaces); + ReleaseDC(pScr->hWnd, hDC); + if (pScr->x >= pScr->width) + pScr->x = pScr->width - 1; + pScr->bWrapPending = FALSE; + +} /* ScreenTab */ + + +void ScreenCarriageFeed( + SCREEN *pScr) +{ + pScr->bWrapPending = FALSE; + pScr->x = 0; + +} /* ScreenCarriageFeed */ diff --git a/mechglue/src/windows/wintel/screen.h b/mechglue/src/windows/wintel/screen.h new file mode 100644 index 000000000..7cba678ce --- /dev/null +++ b/mechglue/src/windows/wintel/screen.h @@ -0,0 +1,325 @@ +extern long PASCAL ScreenWndProc(HWND,UINT,WPARAM,LPARAM); + +/* +* Definition of attribute bits in the Virtual Screen +* +* 0 - Bold +* 1 - +* 2 - +* 3 - Underline +* 4 - Blink +* 5 - +* 6 - Reverse +* 7 - Graphics character set +* +*/ +#define SCR_isbold(x) (x & 0x01) +#define SCR_isundl(x) (x & 0x08) +#define SCR_isblnk(x) (x & 0x10) +#define SCR_isrev(x) (x & 0x40) +#define SCR_setrev(x) (x ^= 0x40) +#define SCR_isgrph(x) (x & 0x80) +#define SCR_inattr(x) (x & 0xd9) +#define SCR_graph(x) (x | 0x80) +#define SCR_notgraph(x) (x & 0x7F) + +#define SCREEN_HANDLE 0 /* offset in extra window info */ + +#define WM_MYSCREENCHAR (WM_USER+1) +#define WM_MYSCREENBLOCK (WM_USER+2) +#define WM_MYSYSCHAR (WM_USER+3) +#define WM_MYSCREENCLOSE (WM_USER+4) +#define WM_MYSCREENCHANGEBKSP (WM_USER+5) +#define WM_MYSCREENSIZE (WM_USER+6) +#define WM_NETWORKEVENT (WM_USER+7) +#define WM_HOSTNAMEFOUND (WM_USER+8) +#define WM_MYCURSORKEY (WM_USER+9) + +#define FRAME_HEIGHT ((2* GetSystemMetrics(SM_CYFRAME))+GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYMENU)+3) +#define FRAME_WIDTH (2*GetSystemMetrics(SM_CXFRAME)+GetSystemMetrics(SM_CXVSCROLL)) +#define TAB_SPACES 8 +#define SPACE 32 +#define ALERT 0x21 +#define MAX_LINE_WIDTH 512 /* not restricted to 1 byte */ + +typedef struct SCREENLINE { + struct SCREENLINE *next; + struct SCREENLINE *prev; + int width; + char *text; + char *attrib; + char buffer[0]; +} SCREENLINE; + +typedef struct SCREEN { + LPSTR title; + HWND hWnd; + HWND hwndTel; + SCREENLINE *screen_top; + SCREENLINE *screen_bottom; + SCREENLINE *buffer_top; + SCREENLINE *buffer_bottom; + int ID; + int type; + int width; + int height; + int maxlines; /* Maximum number of scrollback lines */ + int numlines; /* Current number of scrollback lines */ + int savelines; /* Save lines off top? */ + int ESscroll; /* Scroll screen when ES received */ + int attrib; /* current attribute */ + int x; /* current cursor position */ + int y; /* current cursor position */ + int Oldx; /* internally used to redraw cursor */ + int Oldy; + int Px; /* saved cursor pos and attribute */ + int Py; + int Pattrib; + int VSIDC; /* Insert/Delete character mode 0=draw line */ + int DECAWM; /* AutoWrap mode 0=off */ + BOOL bWrapPending; /* AutoWrap mode is on - wrap on next character */ + int DECCKM; /* Cursor key mode */ + int DECPAM; /* keyPad Application mode */ + int IRM; /* Insert/Replace mode */ + int escflg; /* Current Escape level */ + int top; /* Vertical bounds of screen */ + int bottom; + int parmptr; + int cxChar; /* Width of the current font */ + int cyChar; /* Height of the current font */ + BOOL bAlert; + int parms[6]; /* Ansi Params */ + LOGFONT lf; + HFONT hSelectedFont; + HFONT hSelectedULFont; + char tabs[MAX_LINE_WIDTH]; + struct SCREEN *next; + struct SCREEN *prev; +} SCREEN; + +typedef struct CONFIG { + LPSTR title; + HWND hwndTel; + int ID; + int type; + int height; + int width; + int maxlines; /* Maximum number of scrollback lines */ + int backspace; + int ESscroll; /* Scroll screen when ES received */ + int VSIDC; /* Insert/Delete character mode 0=draw line */ + int DECAWM; /* AutoWrap mode 0=off */ + int IRM; /* Insert/Replace mode */ +} CONFIG; + +#define TELNET_SCREEN 0 +#define CONSOLE_SCREEN 1 + +#define IDM_FONT 100 +#define IDM_BACKSPACE 101 +#define IDM_DELETE 102 +#define IDM_ABOUT 103 +#define IDM_HELP_INDEX 104 +#define IDM_EXIT 105 + +#define HELP_FILE "ktelnet.hlp" + +#define IDM_COPY 200 +#define IDM_PASTE 201 +#define IDM_DEBUG 202 + +#define TIMER_TRIPLECLICK 1000 + +#define IDC_ALLOCFAIL 1 +#define IDC_LOCKFAIL 2 +#define IDC_LOADSTRINGFAIL 3 +#define IDC_FONT 6 + +#define DESIREDPOINTSIZE 12 + +/* +Prototypes +*/ + void NEAR InitializeStruct( + WORD wCommDlgType, + LPSTR lpStruct, + HWND hWnd); + + void ScreenInit( + HINSTANCE hInstance); + + void SetScreenInstance( + HINSTANCE hInstance); + + SCREENLINE *ScreenNewLine(); + + void ScreenBell( + SCREEN *pScr); + + void ScreenBackspace( + SCREEN *pScr); + + void ScreenTab( + SCREEN *pScr); + + void ScreenCarriageFeed( + SCREEN *pScr); + + int ScreenScroll( + SCREEN *pScr); + + void DeleteTopLine( + SCREEN *pScr); + +/* +emul.c +*/ + void ScreenEm( + LPSTR c, + int len, + SCREEN *pScr); + +/* +intern.c +*/ + SCREENLINE *GetScreenLineFromY( + SCREEN *pScr, + int y); + + SCREENLINE *ScreenClearLine( + SCREEN *pScr, + SCREENLINE *pScrLine); + + void ScreenUnscroll( + SCREEN *pScr); + + void ScreenELO( + SCREEN *pScr, + int s); + + void ScreenEraseScreen( + SCREEN *pScr); + + void ScreenTabClear( + SCREEN *pScr); + + void ScreenTabInit( + SCREEN *pScr); + + void ScreenReset( + SCREEN *pScr); + + void ScreenIndex( + SCREEN *pScr); + + void ScreenWrapNow( + SCREEN *pScr, + int *xp, + int *yp); + + void ScreenEraseToEOL( + SCREEN *pScr); + + void ScreenEraseToBOL( + SCREEN *pScr); + + void ScreenEraseLine( + SCREEN *pScr, + int s); + + void ScreenEraseToEndOfScreen( + SCREEN *pScr); + + void ScreenRange( + SCREEN *pScr); + + void ScreenAlign( + SCREEN *pScr); + + void ScreenApClear( + SCREEN *pScr); + + void ScreenSetOption( + SCREEN *pScr, + int toggle); + + BOOL ScreenInsChar( + SCREEN *pScr, + int x); + + void ScreenSaveCursor( + SCREEN *pScr); + + void ScreenRestoreCursor( + SCREEN *pScr); + + void ScreenDraw( + SCREEN *pScr, + int x, + int y, + int a, + int len, + char *c); + + void ScreenCursorOff( + SCREEN *pScr); + + void ScreenCursorOn( + SCREEN *pScr); + + void ScreenDelChars( + SCREEN *pScr, + int n); + + void ScreenRevIndex( + SCREEN *pScr); + + void ScreenDelLines( + SCREEN *pScr, + int n, + int s); + + void ScreenInsLines( + SCREEN *pScr, + int n, + int s); + + #if ! defined(NDEBUG) + BOOL CheckScreen( + SCREEN *pScr); + #endif + + void ProcessFontChange( + HWND hWnd); + + void Edit_LbuttonDown( + HWND hWnd, + LPARAM lParam); + + void Edit_LbuttonDblclk( + HWND hWnd, + LPARAM lParam); + + void Edit_LbuttonUp( + HWND hWnd, + LPARAM lParam); + + void Edit_TripleClick( + HWND hWnd, + LPARAM lParam); + + void Edit_MouseMove( + HWND hWnd, + LPARAM lParam); + + void Edit_ClearSelection( + SCREEN *pScr); + + void Edit_Copy( + HWND hWnd); + + void Edit_Paste( + HWND hWnd); + + SCREEN *InitNewScreen( + CONFIG *Config); diff --git a/mechglue/src/windows/wintel/struct.h b/mechglue/src/windows/wintel/struct.h new file mode 100644 index 000000000..bc1cc4912 --- /dev/null +++ b/mechglue/src/windows/wintel/struct.h @@ -0,0 +1,29 @@ +#include "winsock.h" +#ifdef KRB4 + #include "kstream.h" +#endif +#ifdef KRB5 + #include "k5stream.h" +#endif + +#define HCONNECTION HGLOBAL + +typedef struct CONNECTION { + SCREEN *pScreen; /* handle to screen associated with connection */ + kstream ks; + SOCKET socket; + int pnum; /* port number associated with connection */ + int telstate; /* telnet state for this connection */ + int substate; /* telnet subnegotiation state */ + int termsent; + int echo; + int ugoahead; + int igoahead; + int timing; + int backspace; + int ctrl_backspace; + int termstate; /* terminal type for this connection */ + int width; + int height; + BOOL bResizeable; +} CONNECTION; diff --git a/mechglue/src/windows/wintel/telnet.c b/mechglue/src/windows/wintel/telnet.c new file mode 100644 index 000000000..449471b7b --- /dev/null +++ b/mechglue/src/windows/wintel/telnet.c @@ -0,0 +1,904 @@ +/**************************************************************************** + + Program: telnet.c + + PURPOSE: Windows networking kernel - Telnet + + FUNCTIONS: + + WinMain() - calls initialization function, processes message loop + InitApplication() - initializes window data and registers window + InitInstance() - saves instance handle and creates main window + MainWndProc() - processes messages + About() - processes messages for "About" dialog box + + COMMENTS: + + Windows can have several copies of your application running at the + same time. The variable hInst keeps track of which instance this + application is so that processing will be to the correct window. + + ****************************************************************************/ + +#include <windows.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "telnet.h" +#include "auth.h" + +static HANDLE hInst; +static HWND hWnd; +static CONFIG *tmpConfig; +static CONNECTION *con = NULL; +static char hostdata[MAXGETHOSTSTRUCT]; +static SCREEN *pScr; +static int debug = 1; + +char strTmp[1024]; /* Scratch buffer */ +BOOL bAutoConnection = FALSE; +short port_no = 23; +char szUserName[64]; /* Used in auth.c */ +char szHostName[64]; + +#ifdef KRB4 +#define WINDOW_CLASS "K4_telnetWClass" +#endif + +#ifdef KRB5 +krb5_context k5_context; +#define WINDOW_CLASS "K5_telnetWClass" +#endif + +/* + * + * FUNCTION: WinMain(HINSTANCE, HINSTANCE, LPSTR, int) + * + * PURPOSE: calls initialization function, processes message loop + * + * COMMENTS: + * + * Windows recognizes this function by name as the initial entry point + * for the program. This function calls the application initialization + * routine, if no other instance of the program is running, and always + * calls the instance initialization routine. It then executes a message + * retrieval and dispatch loop that is the top-level control structure + * for the remainder of execution. The loop is terminated when a WM_QUIT + * message is received, at which time this function exits the application + * instance by returning the value passed by PostQuitMessage(). + * + * If this function must abort before entering the message loop, it + * returns the conventional value NULL. + */ + +int PASCAL +WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + MSG msg; + + if (!hPrevInstance) + if (!InitApplication(hInstance)) + return(FALSE); + + /* + * Perform initializations that apply to a specific instance + */ + bAutoConnection = parse_cmdline(lpCmdLine); + + if (!InitInstance(hInstance, nCmdShow)) + return(FALSE); + +#ifdef _WIN32 + SetDebugErrorLevel(SLE_WARNING); +#endif + + /* + * Acquire and dispatch messages until a WM_QUIT message is received. + */ + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + + /* Process all non-network messages */ + while (PeekMessage(&msg, NULL, 0, WM_NETWORKEVENT-1, PM_REMOVE) || + PeekMessage(&msg, NULL, WM_NETWORKEVENT+1, (UINT)-1, PM_REMOVE)) + { + if (msg.message == WM_QUIT) // Special case: WM_QUIT -- return + return msg.wParam; // the value from PostQuitMessage + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return (msg.wParam); /* Returns the value from PostQuitMessage */ +} + +/* + * FUNCTION: InitApplication(HINSTANCE) + * + * PURPOSE: Initializes window data and registers window class + * + * COMMENTS: + * + * This function is called at initialization time only if no other + * instances of the application are running. This function performs + * initialization tasks that can be done once for any number of running + * instances. + * + * In this case, we initialize a window class by filling out a data + * structure of type WNDCLASS and calling the Windows RegisterClass() + * function. Since all instances of this application use the same window + * class, we only need to do this when the first instance is initialized. + */ + +BOOL +InitApplication(HINSTANCE hInstance) +{ + WNDCLASS wc; + + ScreenInit(hInstance); + + /* + * Fill in window class structure with parameters that describe the + * main window. + */ + wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */ + wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for + * windows of this class. + */ + wc.cbClsExtra = 0; /* No per-class extra data. */ + wc.cbWndExtra = 0; /* No per-window extra data. */ + wc.hInstance = hInstance; /* Application that owns the class. */ + wc.hIcon = NULL; /* LoadIcon(hInstance, "NCSA"); */ + wc.hCursor = NULL; /* Cursor(NULL, IDC_ARROW); */ + wc.hbrBackground = NULL; /* GetStockObject(WHITE_BRUSH); */ + wc.lpszMenuName = NULL; /* Name of menu resource in .RC file. */ + wc.lpszClassName = WINDOW_CLASS; /* Name used in call to CreateWindow. */ + + return(RegisterClass(&wc)); +} + + +/* + * FUNCTION: InitInstance(HANDLE, int) + * + * PURPOSE: Saves instance handle and creates main window + * + * COMMENTS: + * + * This function is called at initialization time for every instance of + * this application. This function performs initialization tasks that + * cannot be shared by multiple instances. + * + * In this case, we save the instance handle in a static variable and + * create and display the main program window. + */ +BOOL +InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + int xScreen = 0; + int yScreen = 0; + WSADATA wsaData; + + SetScreenInstance(hInstance); + + /* + * Save the instance handle in static variable, which will be used in + * many subsequence calls from this application to Windows. + */ + hInst = hInstance; + + /* + * Create a main window for this application instance. + */ + hWnd = CreateWindow( + WINDOW_CLASS, /* See RegisterClass() call. */ + "TCPWin", /* Text for window title bar. */ + WS_SYSMENU, /* Window style. */ + xScreen / 3, /* Default horizontal position. */ + yScreen / 3, /* Default vertical position. */ + xScreen / 3, /* Default width. */ + yScreen / 3, /* Default height. */ + NULL, /* Overlapped windows have no parent */ + NULL, /* Use the window class menu. */ + hInstance, /* This instance owns this window. */ + NULL); /* Pointer not needed. */ + + if (!hWnd) + return (FALSE); + + if (WSAStartup(0x0101, &wsaData) != 0) { /* Initialize the network */ + MessageBox(NULL, "Couldn't initialize Winsock!", NULL, + MB_OK | MB_ICONEXCLAMATION); + return(FALSE); + } + + if (!OpenTelnetConnection()) { + WSACleanup(); + return(FALSE); + } + +#ifdef KRB5 + krb5_init_context(&k5_context); +#endif + + return (TRUE); +} + +char buf[2048]; + +/* + * FUNCTION: MainWndProc(HWND, UINT, WPARAM, LPARAM) + * + * PURPOSE: Processes messages + * + * MESSAGES: + * + * WM_COMMAND - application menu (About dialog box) + * WM_DESTROY - destroy window + */ +LRESULT CALLBACK +MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HGLOBAL hBuffer; + LPSTR lpBuffer; + int iEvent, cnt, ret; + char *tmpCommaLoc; + struct sockaddr_in remote_addr; + struct hostent *remote_host; + + switch (message) { + case WM_MYSCREENCHANGEBKSP: + if (!con) + break; + con->backspace = wParam; + if (con->backspace == VK_BACK) { + con->ctrl_backspace = 0x7f; + WritePrivateProfileString(INI_TELNET, INI_BACKSPACE, + INI_BACKSPACE_BS, TELNET_INI); + } + else { + con->ctrl_backspace = VK_BACK; + WritePrivateProfileString(INI_TELNET, INI_BACKSPACE, + INI_BACKSPACE_DEL, TELNET_INI); + } + GetPrivateProfileString(INI_HOSTS, INI_HOST "0", "", buf, 128, TELNET_INI); + tmpCommaLoc = strchr(buf, ','); + if (tmpCommaLoc == NULL) { + strcat (buf, ","); + tmpCommaLoc = strchr(buf, ','); + } + if (tmpCommaLoc) { + tmpCommaLoc++; + if (con->backspace == VK_BACK) + strcpy(tmpCommaLoc, INI_HOST_BS); + else + strcpy(tmpCommaLoc, INI_HOST_DEL); + } + WritePrivateProfileString(INI_HOSTS, INI_HOST "0", buf, TELNET_INI); + break; + + case WM_MYSCREENCHAR: + { + unsigned char c; + + if (!con) + break; + if (wParam == VK_BACK) + c = con->backspace; + else if (wParam == 0x7f) + c = con->ctrl_backspace; + else if (wParam == VK_SPACE && GetKeyState(VK_CONTROL) < 0) + c = 0; + else + c = wParam; + TelnetSend(con->ks, &c, 1, 0); + } + break; + + case WM_MYCURSORKEY: + /* Acts as a send through: buffer is lParam and length in wParam */ + if (!con) + break; + memcpy(buf, (char *)lParam, wParam); + TelnetSend (con->ks, buf, wParam, 0); + break; + + case WM_MYSCREENBLOCK: + if (!con) + break; + hBuffer = (HGLOBAL) wParam; + lpBuffer = GlobalLock(hBuffer); + TelnetSend(con->ks, lpBuffer, lstrlen(lpBuffer), 0); + GlobalUnlock(hBuffer); + break; + + case WM_MYSCREENCLOSE: +#if 0 + if (con) + { + kstream_destroy(con->ks); + con->ks = NULL; + } +#endif + DestroyWindow(hWnd); + break; + + case WM_QUERYOPEN: + return(0); + break; + + case WM_DESTROY: /* message: window being destroyed */ + if (con) + { + kstream_destroy(con->ks); + free(con); + WSACleanup(); + } + PostQuitMessage(0); + break; + + case WM_NETWORKEVENT: + iEvent = WSAGETSELECTEVENT(lParam); + + switch (iEvent) { + + case FD_READ: + if (con == NULL) + break; + cnt = kstream_read(con->ks, buf, 1500); + buf[cnt] = 0; + parse((CONNECTION *)con, (unsigned char *)buf, cnt); + ScreenEm(buf, cnt, con->pScreen); + break; + + case FD_CLOSE: + kstream_destroy(con->ks); + free(con); + con = NULL; + WSACleanup(); + PostQuitMessage(0); + break; + + case FD_CONNECT: + ret = WSAGETSELECTERROR(lParam); + if (ret) { + wsprintf(buf, "Error %d on Connect", ret); + MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION); + kstream_destroy(con->ks); + free(con); + WSACleanup(); + PostQuitMessage(0); + break; + } + start_negotiation(con->ks); + break; + } + + break; + + case WM_HOSTNAMEFOUND: + ret = WSAGETASYNCERROR(lParam); + if (ret) { + wsprintf(buf, "Error %d on GetHostbyName", ret); + MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION); + kstream_destroy(con->ks); + free(con); + WSACleanup(); + PostQuitMessage(0); + break; + } + + remote_host = (struct hostent *)hostdata; + remote_addr.sin_family = AF_INET; + memcpy(&(remote_addr.sin_addr), &(remote_host->h_addr[0]), 4); + remote_addr.sin_port = htons(port_no); + + connect(con->socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)); + break; + + case WM_MYSCREENSIZE: + con->width = LOWORD(lParam); /* width in characters */ + con->height = HIWORD(lParam); /* height in characters */ + if (con->bResizeable && con->ks) + send_naws(con); + wsprintf(buf, "%d", con->height); + WritePrivateProfileString(INI_TELNET, INI_HEIGHT, buf, TELNET_INI); + wsprintf(buf, "%d", con->width); + WritePrivateProfileString(INI_TELNET, INI_WIDTH, buf, TELNET_INI); + break; + + default: /* Passes it on if unproccessed */ + return(DefWindowProc(hWnd, message, wParam, lParam)); + } + return (0); +} + + +/* + * + * FUNCTION: SaveHostName(hostname, port) + * + * PURPOSE: Saves the currently selected host name and port number + * in the KERBEROS.INI file and returns the preferred backspace + * setting if one exists for that host. + * + * RETURNS: VK_BACK or 0x7f depending on the desired backspace setting. + */ +int +SaveHostName(char *host, int port) +{ + char buf[128]; /* Scratch buffer */ + char fullhost[128]; /* Host & port combination */ + char hostName[10][128]; /* Entries from INI files */ + char *comma; /* For parsing del/bs info */ + int len; /* Length of fullhost */ + int n; /* Number of items written */ + int i; /* Index */ + int bs; /* What we return */ + + if (port == 23) /* Default telnet port */ + strcpy(fullhost, host); /* ...then don't add it on */ + else + wsprintf(fullhost, "%s %d", host, port); + len = strlen(fullhost); + + comma = NULL; + for (i = 0; i < 10; i++) { + wsprintf(buf, INI_HOST "%d", i); /* INI item to fetch */ + GetPrivateProfileString(INI_HOSTS, buf, "", hostName[i], + 128, TELNET_INI); + + if (!hostName[i][0]) + break; + + if (strncmp (hostName[i], fullhost, len)) /* A match?? */ + continue; /* Nope, keep going */ + comma = strchr (hostName[i], ','); + } + + if (comma) { + ++comma; /* Past the comma */ + while (*comma == ' ') /* Past leading white space */ + ++comma; + bs = VK_BACK; /* Default for unknown entry */ + if (_stricmp(comma, INI_HOST_DEL) == 0) + bs = 0x7f; + } + else { /* No matching entry */ + GetPrivateProfileString(INI_TELNET, INI_BACKSPACE, INI_BACKSPACE_BS, + buf, sizeof(buf), TELNET_INI); + bs = VK_BACK; /* Default value */ + if (_stricmp(buf, INI_BACKSPACE_DEL) == 0) + bs = 0x7f; + } + + /* + * Build up default host name + */ + strcpy(buf, fullhost); + strcat(buf, ", "); + strcat(buf, (bs == VK_BACK) ? INI_BACKSPACE_BS : INI_BACKSPACE_DEL); + WritePrivateProfileString(INI_HOSTS, INI_HOST "0", buf, TELNET_INI); + + n = 0; + for (i = 0; i < 10; i++) { + if (!hostName[i][0]) /* End of the list? */ + break; + if (strncmp(hostName[i], fullhost, len) != 0) { + wsprintf(buf, INI_HOST "%d", ++n); + WritePrivateProfileString(INI_HOSTS, buf, hostName[i], TELNET_INI); + } + } + return(bs); +} + + +int +OpenTelnetConnection(void) +{ + int nReturn, ret; + struct sockaddr_in sockaddr; + char *p; + static struct kstream_crypt_ctl_block ctl; + char buf[128]; + + tmpConfig = calloc(sizeof(CONFIG), 1); + + if (bAutoConnection) { + tmpConfig->title = calloc(lstrlen(szHostName), 1); + lstrcpy(tmpConfig->title, (char *) szHostName); + } else { + nReturn = DoDialog("OPENTELNETDLG", OpenTelnetDlg); + if (nReturn == FALSE) + return(FALSE); + } + + con = (CONNECTION *) GetNewConnection(); + if (con == NULL) + return(0); + + tmpConfig->width = + GetPrivateProfileInt(INI_TELNET, INI_WIDTH, DEF_WIDTH, TELNET_INI); + + tmpConfig->height = + GetPrivateProfileInt(INI_TELNET, INI_HEIGHT, DEF_HEIGHT, TELNET_INI); + con->width = tmpConfig->width; + con->height = tmpConfig->height; + + con->backspace = SaveHostName(tmpConfig->title, port_no); + + if (con->backspace == VK_BACK) { + tmpConfig->backspace = TRUE; + con->ctrl_backspace = 0x7f; + } else { + tmpConfig->backspace = FALSE; + con->ctrl_backspace = 0x08; + } + + tmpConfig->hwndTel = hWnd; + con->pScreen = InitNewScreen(tmpConfig); + if (!con->pScreen) { + assert(FALSE); + free(con->pScreen); + free(con); + free(tmpConfig); + return(-1); + } + + ret = (SOCKET) socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (ret == SOCKET_ERROR) { + wsprintf(buf, "Socket error on socket = %d!", WSAGetLastError()); + MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION); + if (con->pScreen != NULL) + DestroyWindow(con->pScreen->hWnd); + free(con); + free(tmpConfig); + return(-1); + } + + con->socket = ret; + + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); + sockaddr.sin_port = htons(0); + + ret = bind(con->socket, (struct sockaddr *) &sockaddr, + (int) sizeof(struct sockaddr_in)); + + if (ret == SOCKET_ERROR) { + wsprintf(buf, "Socket error on bind!"); + MessageBox(NULL, buf, NULL, MB_OK | MB_ICONEXCLAMATION); + if (con->pScreen != NULL) + DestroyWindow(con->pScreen->hWnd); + free(con); + free(tmpConfig); + return(-1); + } + + WSAAsyncSelect(con->socket, hWnd, WM_NETWORKEVENT, + FD_READ | FD_CLOSE | FD_CONNECT); + + lstrcpy(szHostName, tmpConfig->title); + p = strchr(szHostName, '@'); + if (p != NULL) { + *p = 0; + strcpy (szUserName, szHostName); + strcpy(szHostName, ++p); + } + + WSAAsyncGetHostByName(hWnd, WM_HOSTNAMEFOUND, szHostName, hostdata, + MAXGETHOSTSTRUCT); + + ctl.encrypt = auth_encrypt; + ctl.decrypt = auth_decrypt; + ctl.init = auth_init; + ctl.destroy = auth_destroy; + + con->ks = kstream_create_from_fd(con->socket, &ctl, NULL); + + if (con->ks == NULL) + return(-1); + + kstream_set_buffer_mode(con->ks, 0); + + return(1); +} + + +CONNECTION * +GetNewConnection(void) +{ + CONNECTION *pCon; + + pCon = calloc(sizeof(CONNECTION), 1); + if (pCon == NULL) + return NULL; + pCon->backspace = TRUE; + pCon->bResizeable = TRUE; + return(pCon); +} + + +int +DoDialog(char *szDialog, DLGPROC lpfnDlgProc) +{ + int nReturn; + + nReturn = DialogBox(hInst, szDialog, hWnd, lpfnDlgProc); + return (nReturn); +} + + +/* + * FUNCTION: OpenTelnetDlg(HWND, unsigned, WORD, LONG) + * + * PURPOSE: Processes messages for "Open New Telnet Connection" dialog box + * + * MESSAGES: + * + * WM_INITDIALOG - initialize dialog box + * WM_COMMAND - Input received + */ +INT_PTR CALLBACK +OpenTelnetDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char szConnectName[256]; + HDC hDC; + int xExt, yExt; + DWORD Ext; + HWND hEdit; + int n; + int iHostNum = 0; + char tmpName[128]; + char tmpBuf[80]; + char *tmpCommaLoc; + + switch (message) { + case WM_INITDIALOG: + hDC = GetDC(hDlg); + Ext = GetDialogBaseUnits(); + xExt = (190 *LOWORD(Ext)) /4 ; + yExt = (72 * HIWORD(Ext)) /8 ; + GetPrivateProfileString(INI_HOSTS, INI_HOST "0", "", tmpName, + 128, TELNET_INI); + if (tmpName[0]) { + tmpCommaLoc = strchr(tmpName, ','); + if (tmpCommaLoc) + *tmpCommaLoc = '\0'; + SetDlgItemText(hDlg, TEL_CONNECT_NAME, tmpName); + } + hEdit = GetWindow(GetDlgItem(hDlg, TEL_CONNECT_NAME), GW_CHILD); + while (TRUE) { + wsprintf(tmpBuf, INI_HOST "%d", iHostNum++); + GetPrivateProfileString(INI_HOSTS, tmpBuf, "", tmpName, + 128, TELNET_INI); + tmpCommaLoc = strchr(tmpName, ','); + if (tmpCommaLoc) + *tmpCommaLoc = '\0'; + if (tmpName[0]) + SendDlgItemMessage(hDlg, TEL_CONNECT_NAME, CB_ADDSTRING, 0, + (LPARAM) ((LPSTR) tmpName)); + else + break; + } +#ifdef FORWARD + EnableWindow(GetDlgItem(hDlg, IDC_FORWARD), 1); + SendDlgItemMessage(hDlg, IDC_FORWARD, BM_SETCHECK, forward_flag, 0); + if (forward_flag) + EnableWindow(GetDlgItem(hDlg, IDC_FORWARDFORWARD), 1); + else + EnableWindow(GetDlgItem(hDlg, IDC_FORWARDFORWARD), 0); + SendDlgItemMessage(hDlg, IDC_FORWARDFORWARD, BM_SETCHECK, + forwardable_flag, 0); +#endif + +#ifdef ENCRYPTION + EnableWindow(GetDlgItem(hDlg, IDC_ENCRYPT), 1); + SendDlgItemMessage(hDlg, IDC_ENCRYPT, + BM_SETCHECK, encrypt_flag, 0); +#endif + + EnableWindow(GetDlgItem(hDlg, TEL_CONNECT_USERID), 1); + + SetWindowPos(hDlg, NULL, + (GetSystemMetrics(SM_CXSCREEN)/2)-(xExt/2), + (GetSystemMetrics(SM_CYSCREEN)/2)-(yExt/2), + 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); + ReleaseDC(hDlg, hDC); + SendMessage(hEdit, WM_USER + 1, 0, 0); + SendMessage(hDlg, WM_SETFOCUS, 0, 0); + return (TRUE); + + case WM_COMMAND: + switch (wParam) { + case TEL_CANCEL: + case IDCANCEL: /* From the menu */ + EndDialog(hDlg, FALSE); + break; + +#ifdef FORWARD + case IDC_FORWARD: + forward_flag = (BOOL)SendDlgItemMessage(hDlg, IDC_FORWARD, + BM_GETCHECK, 0, 0); + if (forward_flag) + EnableWindow(GetDlgItem(hDlg, IDC_FORWARDFORWARD), 1); + else + EnableWindow(GetDlgItem(hDlg, IDC_FORWARDFORWARD), 0); + break; + + case IDC_FORWARDFORWARD: + forwardable_flag = (BOOL)SendDlgItemMessage(hDlg, IDC_FORWARDFORWARD, + BM_GETCHECK, 0, 0); + break; +#endif + +#if ENCRYPTION + case IDC_ENCRYPT: + encrypt_flag = (BOOL)SendDlgItemMessage(hDlg, IDC_ENCRYPT, + BM_GETCHECK, 0, 0); + break; +#endif + case TEL_CONNECT_USERID: + GetDlgItemText(hDlg, TEL_CONNECT_USERID, szUserName, sizeof(szUserName)); + break; + + case TEL_OK: + GetDlgItemText(hDlg, TEL_CONNECT_NAME, szConnectName, 256); + + n = parse_cmdline (szConnectName); + if (! n) { + MessageBox(hDlg, "You must enter a session name!", + NULL, MB_OK); + break; + } + tmpConfig->title = calloc(lstrlen(szHostName) + 1, 1); + lstrcpy(tmpConfig->title, szConnectName); + EndDialog(hDlg, TRUE); + break; + } + return (FALSE); + } + return(FALSE); +} + + +/* + * + * FUNCTION: TelnetSend(kstream ks, char *buf, int len, int flags) + * + * PURPOSE: This is a replacement for the WinSock send() function, to + * send a buffer of characters to an output socket. It differs + * by retrying endlessly if sending the bytes would cause + * the send() to block. <gnu@cygnus.com> observed EWOULDBLOCK + * errors when running using TCP Software's PC/TCP 3.0 stack, + * even when writing as little as 109 bytes into a socket + * that had no more than 9 bytes queued for output. Note also + * that a kstream is used during output rather than a socket + * to facilitate encryption. + * + * Eventually, for cleanliness and responsiveness, this + * routine should not loop; instead, if the send doesn't + * send all the bytes, it should put them into a buffer + * and return. Message handling code would send out the + * buffer whenever it gets an FD_WRITE message. + */ +int +TelnetSend(kstream ks, char *buf, int len, int flags) +{ + int writelen; + int origlen = len; + + while (TRUE) { + writelen = kstream_write(ks, buf, len); + + if (writelen == len) /* Success, first or Nth time */ + return (origlen); + + if (writelen == SOCKET_ERROR) { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return (SOCKET_ERROR); /* Some error */ + /* For WOULDBLOCK, immediately repeat the send. */ + } + else { + /* Partial write; update the pointers and retry. */ + len -= writelen; + buf += writelen; + } + } +} + + +/* + * Function: Trim leading and trailing white space from a string. + * + * Parameters: + * s - the string to trim. + */ +void +trim(char *s) +{ + int l; + int i; + + for (i = 0; s[i]; i++) + if (s[i] != ' ' && s[i] != '\t') + break; + + l = strlen(&s[i]); + memmove(s, &s[i], l + 1); + + for (l--; l >= 0; l--) { + if (s[l] != ' ' && s[l] != '\t') + break; + } + s[l + 1] = 0; +} + + +/* + * + * Parse_cmdline + * + * Reads hostname and port number off the command line. + * + * Formats: telnet + * telnet <host> + * telnet <host> <port no> + * telnet -p <port no> + * + * Returns: TRUE if we have a hostname + */ +BOOL +parse_cmdline(char *cmdline) +{ + char *ptr; + + *szHostName = '\0'; /* Nothing yet */ + if (*cmdline == '\0') /* Empty command line? */ + return(FALSE); + + trim (cmdline); /* Remove excess spaces */ + ptr = strchr (cmdline, ' '); /* Find 2nd token */ + + if (ptr != NULL) { /* Port number given */ + *ptr++ = '\0'; /* Separate into 2 words */ + port_no = atoi (ptr); + } + + if (*cmdline != '-' && *cmdline != '/') { /* Host name given */ + lstrcpy (szHostName, cmdline); + return(TRUE); + } + + return(FALSE); +} + +#ifdef DEBUG +void +hexdump(char *msg, unsigned char *st, int cnt) +{ + int i; + char strTmp[128]; + + OutputDebugString("\r\n"); + if (msg != NULL) { + OutputDebugString(msg); + OutputDebugString("\r\n"); + } + for(i = 0 ; i < cnt ; i++) { + int j; + + for(j = 0 ; (j < 16) && ((i + j) < cnt) ; j++) { + wsprintf(strTmp,"%02x ", st[i + j]); + if (j == 8) + OutputDebugString("| "); + OutputDebugString(strTmp); + } + i += j - 1; + OutputDebugString("\r\n"); + } /* end for */ +} +#endif diff --git a/mechglue/src/windows/wintel/telnet.def b/mechglue/src/windows/wintel/telnet.def new file mode 100644 index 000000000..e2d2ab93f --- /dev/null +++ b/mechglue/src/windows/wintel/telnet.def @@ -0,0 +1,39 @@ +; module-definition file for testdll -- used by LINK.EXE +NAME TELNET +DESCRIPTION 'Sample Microsoft Windows Application' +EXETYPE WINDOWS +STUB 'WINSTUB.EXE' +SEGMENTS _TEXT CLASS 'CODE' PRELOAD +CODE DISCARDABLE +DATA PRELOAD MOVEABLE MULTIPLE +HEAPSIZE 10240 + +; All functions that will be called by any Windows routine +; MUST be exported. + +EXPORTS + MainWndProc @1 ; name of window processing function + OpenTelnetDlg @3 ; name of "Open New Telnet Connection" Dialog Function + +IMPORTS + WINSOCK.WSAStartup + WINSOCK.WSACleanup + WINSOCK.WSAAsyncSelect + WINSOCK.WSAGetLastError + WINSOCK.WSAAsyncGetHostByName + WINSOCK.listen + WINSOCK.accept + WINSOCK.__wsafdisset + WINSOCK.socket + WINSOCK.bind + WINSOCK.gethostbyname + WINSOCK.getsockname + WINSOCK.htons + WINSOCK.connect + WINSOCK.recv + WINSOCK.send + WINSOCK.htonl + WINSOCK.closesocket + WINSOCK.select + WINSOCK.ioctlsocket + WINSOCK.getpeername diff --git a/mechglue/src/windows/wintel/telnet.h b/mechglue/src/windows/wintel/telnet.h new file mode 100644 index 000000000..cd1904a14 --- /dev/null +++ b/mechglue/src/windows/wintel/telnet.h @@ -0,0 +1,41 @@ +#ifndef TELNET_H_INC +#define TELNET_H_INC + +#include <windows.h> +#include <stdarg.h> + +#ifdef KRB5 +#include "krb5.h" +#include "k5stream.h" +#endif + +#include "dialog.h" +#include "screen.h" +#include "struct.h" +#include "wt-proto.h" +#include "winsock.h" +#include "ini.h" + +/* globals */ +extern char szAutoHostName[64]; +extern char szUserName[64]; +extern char szHostName[64]; + +#ifdef KRB5 +extern krb5_context k5_context; +#endif + +extern void parse(CONNECTION *, unsigned char *, int); + +extern void send_naws(CONNECTION *); + +extern char strTmp[1024]; + +#define DEF_WIDTH 80 +#define DEF_HEIGHT 24 + +#ifdef DEBUG +void hexdump(char *, unsigned char *, int); +#endif + +#endif /* TELNET_H_INC */ diff --git a/mechglue/src/windows/wintel/telnet.rc b/mechglue/src/windows/wintel/telnet.rc new file mode 100644 index 000000000..6fd62c21e --- /dev/null +++ b/mechglue/src/windows/wintel/telnet.rc @@ -0,0 +1,247 @@ +//Microsoft Developer Studio generated resource script. +// +// XXX since modified by hand... + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "dialog.h" +#include "screen.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +OPENTELNETDLG DIALOG DISCARDABLE 63, 65, 175, 129 +#ifdef _WIN32 +STYLE DS_ABSALIGN | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION | + WS_SYSMENU +#else +STYLE DS_ABSALIGN | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +#endif +CAPTION "Open New Telnet Connection" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "To Host:",IDC_STATIC,3,10,33,10,NOT WS_GROUP + COMBOBOX TEL_CONNECT_NAME,37,9,128,76,CBS_DROPDOWN | WS_VSCROLL | + WS_GROUP | WS_TABSTOP + CONTROL "Forward credentials",IDC_FORWARD,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,37,28,77,10 + CONTROL "Forward remote credentials",IDC_FORWARDFORWARD,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,37,44,101,10 + CONTROL "Enable encryption",IDC_ENCRYPT,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,37,60,73,10 + CONTROL "Connect as userid",IDC_STATIC,"Static", + SS_LEFTNOWORDWRAP,15,84,58,8 + EDITTEXT TEL_CONNECT_USERID,77,82,80,13,ES_AUTOHSCROLL | + WS_DISABLED + DEFPUSHBUTTON "OK",TEL_OK,20,106,51,14,WS_GROUP + PUSHBUTTON "Cancel",TEL_CANCEL,106,106,51,14 +END + +ABOUTBOX DIALOG DISCARDABLE 69, 33, 175, 148 +STYLE DS_ABSALIGN | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "About TCPwin" +BEGIN + ICON "NCSA",-1,15,12,16,16 + CTEXT "Microsoft Windows",-1,48,11,93,8 + CTEXT "NCSA TCP/IP Networking Kernel",-1,38,21,120,8 + CTEXT "Version 1.0b2",-1,20,31,144,8 + PUSHBUTTON "OK",IDOK,72,126,39,14,WS_GROUP | NOT WS_TABSTOP + CTEXT "Written By:",606,20,50,144,8 + CTEXT "Jon Mittelhauser (jonm@ncsa.uiuc.edu)",607,20,61,144,8 + CTEXT "Chris Wilson (cwilson@ncsa.uiuc.edu)",608,20,71,144,8 + CTEXT "Special Thanks to:",609,21,97,143,8 + CTEXT "Joe Lepore for DPMI interface code",610,20,107,144,8 + CTEXT "Keberized by: Cygnus Support",611,20,82,144,8 +END + +CONFIG_DLG DIALOG DISCARDABLE 6, 18, 160, 130 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Configure Session" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "Session Name:",301,1,5,54,8 + LTEXT "Default Session",CON_SESSIONNAME,55,5,105,8 + LTEXT "Window Title:",303,1,17,49,8 + EDITTEXT CON_WINDOWTITLE,53,15,102,12,ES_AUTOHSCROLL + CONTROL "132",CON_COLUMNS132,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,53,33,39,10 + CONTROL "80",CON_COLUMNS80,"Button",BS_AUTORADIOBUTTON,110,33,39, + 10 + CONTROL "Backspace",CON_BACKSPACE,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,53,46,49,10 + CONTROL "Delete",CON_DELETE,"Button",BS_AUTORADIOBUTTON,110,46, + 39,10 + CONTROL "CRLF",CON_CRLF,"Button",BS_AUTORADIOBUTTON | WS_GROUP, + 53,59,39,10 + CONTROL "CR-NUL",CON_CRNUL,"Button",BS_AUTORADIOBUTTON,110,59,39, + 10 + CONTROL "Buffers",CON_BUFFERS,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,53,72,39,10 + CONTROL "Sends",CON_SENDS,"Button",BS_AUTORADIOBUTTON,110,72,39, + 10 + LTEXT "Columns",313,1,33,49,8 + LTEXT "Backspace is",314,1,46,51,8 + LTEXT "Return Sends",315,1,59,49,8 + LTEXT "Echo Mode",316,1,72,49,8 + CONTROL "Scrollback",CON_SCRLBCK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,1,86,50,10 + EDITTEXT CON_NUMLINES,53,85,28,12,ES_AUTOHSCROLL + LTEXT "lines",319,85,86,33,8 + DEFPUSHBUTTON "OK",CON_OK,20,108,50,14,WS_GROUP + PUSHBUTTON "Use Defaults",CON_USEDEFAULTS,90,108,50,14 +END + +IDM_PRINTQUEUE DIALOG DISCARDABLE 69, 25, 160, 80 +STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | + WS_VSCROLL | WS_HSCROLL | WS_SYSMENU +CAPTION "Print Queue" +FONT 8, "MS Sans Serif" +BEGIN +END + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 183, 92 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,126,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,126,24,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +NCSA ICON DISCARDABLE "ncsa.ico" +TERMINAL ICON DISCARDABLE "terminal.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +SCREENMENU MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit Alt+F4", IDM_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Copy Cltr+Ins", IDM_COPY + MENUITEM "&Paste Shift+Ins", IDM_PASTE + END + POPUP "&Options" + BEGIN + MENUITEM "&Backspace", IDM_BACKSPACE + MENUITEM "&Delete", IDM_DELETE, CHECKED + MENUITEM SEPARATOR + MENUITEM "&Font...", IDM_FONT + END +#if 0 + POPUP "&Send", GRAYED + BEGIN + MENUITEM "&Interrupt Process", IDM_SEND_IP + MENUITEM "&Are You There?", IDM_SEND_AYT + MENUITEM "A&bort Process", IDM_SEND_ABORT + END +#endif + POPUP "&Help" + BEGIN + MENUITEM "&Index...", IDM_HELP_INDEX + MENUITEM SEPARATOR + MENUITEM "&About...", IDM_ABOUT + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""dialog.h""\r\n" + "#include ""screen.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 176 + TOPMARGIN, 7 + BOTTOMMARGIN, 85 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + +#include "..\version.rc" diff --git a/mechglue/src/windows/wintel/telnet_arpa.h b/mechglue/src/windows/wintel/telnet_arpa.h new file mode 100644 index 000000000..f6d0eb566 --- /dev/null +++ b/mechglue/src/windows/wintel/telnet_arpa.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)telnet.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _TELNET_H_ +#define _TELNET_H_ + +/* + * Definitions for the TELNET protocol. + */ +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ +#define SB 250 /* interpret as subnegotiation */ +#define GA 249 /* you may reverse the line */ +#define EL 248 /* erase the current line */ +#define EC 247 /* erase the current character */ +#define AYT 246 /* are you there */ +#define AO 245 /* abort output--but let prog finish */ +#define IP 244 /* interrupt process--permanently */ +#define BREAK 243 /* break */ +#define DM 242 /* data mark--for connect. cleaning */ +#define NOP 241 /* nop */ +#define SE 240 /* end sub negotiation */ +#define EOR 239 /* end of record (transparent mode) */ +#define ABORT 238 /* Abort process */ +#define SUSP 237 /* Suspend process */ +#define xEOF 236 /* End of file: EOF is already used... */ + +#define SYNCH 242 /* for telfunc calls */ + +#ifdef TELCMDS +char *telcmds[] = { + "EOF", "SUSP", "ABORT", "EOR", + "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0, +}; +#else +extern char *telcmds[]; +#endif + +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ + (unsigned int)(x) >= TELCMD_FIRST) +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */ +#define TELOPT_EXOPL 255 /* extended-options-list */ + + +#define NTELOPTS (1+TELOPT_NEW_ENVIRON) +#ifdef TELOPTS +char *telopts[NTELOPTS+1] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", + "ENCRYPT", "NEW-ENVIRON", + 0, +}; +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_NEW_ENVIRON +#define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] +#endif + +/* sub-option qualifiers */ +#define TELQUAL_IS 0 /* option is... */ +#define TELQUAL_SEND 1 /* send option */ +#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ +#define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ +#define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ + +#define LFLOW_OFF 0 /* Disable remote flow control */ +#define LFLOW_ON 1 /* Enable remote flow control */ +#define LFLOW_RESTART_ANY 2 /* Restart output on any char */ +#define LFLOW_RESTART_XON 3 /* Restart output only on XON */ + +/* + * LINEMODE suboptions + */ + +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 +#define MODE_SOFT_TAB 0x08 +#define MODE_LIT_ECHO 0x10 + +#define MODE_MASK 0x1f + +/* Not part of protocol, but needed to simplify things... */ +#define MODE_FLOW 0x0100 +#define MODE_ECHO 0x0200 +#define MODE_INBIN 0x0400 +#define MODE_OUTBIN 0x0800 +#define MODE_FORCE 0x1000 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 + +#define NSLC 18 + +/* + * For backwards compatability, we define SLC_NAMES to be the + * list of names if SLC_NAMES is not defined. + */ +#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ + "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, +#ifdef SLC_NAMES +char *slc_names[] = { + SLC_NAMELIST +}; +#else +extern char *slc_names[]; +#define SLC_NAMES SLC_NAMELIST +#endif + +#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) +#define SLC_NAME(x) slc_names[x] + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 + +#define OLD_ENV_VAR 1 +#define OLD_ENV_VALUE 0 +#define NEW_ENV_VAR 0 +#define NEW_ENV_VALUE 1 +#define ENV_ESC 2 +#define ENV_USERVAR 3 + +/* + * AUTHENTICATION suboptions + */ + +/* + * Who is authenticating who ... + */ +#define AUTH_WHO_CLIENT 0 /* Client authenticating server */ +#define AUTH_WHO_SERVER 1 /* Server authenticating client */ +#define AUTH_WHO_MASK 1 + +/* + * amount of authentication done + */ +#define AUTH_HOW_ONE_WAY 0 +#define AUTH_HOW_MUTUAL 2 +#define AUTH_HOW_MASK 2 + +/* + * should we be encrypting? (not yet formally standardized) + */ +#define AUTH_ENCRYPT_OFF 0 +#define AUTH_ENCRYPT_ON 4 +#define AUTH_ENCRYPT_MASK 4 + +#define AUTHTYPE_NULL 0 +#define AUTHTYPE_KERBEROS_V4 1 +#define AUTHTYPE_KERBEROS_V5 2 +#define AUTHTYPE_SPX 3 +#define AUTHTYPE_MINK 4 +#define AUTHTYPE_CNT 5 + +#define AUTHTYPE_TEST 99 + +#ifdef AUTH_NAMES +char *authtype_names[] = { + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, +}; +#else +extern char *authtype_names[]; +#endif + +#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) +#define AUTHTYPE_NAME(x) authtype_names[x] + +/* + * ENCRYPTion suboptions + */ +#define ENCRYPT_IS 0 /* I pick encryption type ... */ +#define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ +#define ENCRYPT_REPLY 2 /* Initial setup response */ +#define ENCRYPT_START 3 /* Am starting to send encrypted */ +#define ENCRYPT_END 4 /* Am ending encrypted */ +#define ENCRYPT_REQSTART 5 /* Request you start encrypting */ +#define ENCRYPT_REQEND 6 /* Request you send encrypting */ +#define ENCRYPT_ENC_KEYID 7 +#define ENCRYPT_DEC_KEYID 8 +#define ENCRYPT_CNT 9 + +#define ENCTYPE_ANY 0 +#define ENCTYPE_DES_CFB64 1 +#define ENCTYPE_DES_OFB64 2 +#define ENCTYPE_CNT 3 + +#ifdef ENCRYPT_NAMES +char *encrypt_names[] = { + "IS", "SUPPORT", "REPLY", "START", "END", + "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", + 0, +}; +char *enctype_names[] = { + "ANY", "DES_CFB64", "DES_OFB64", 0, +}; +#else +extern char *encrypt_names[]; +extern char *enctype_names[]; +#endif + + +#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) +#define ENCRYPT_NAME(x) encrypt_names[x] + +#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) +#define ENCTYPE_NAME(x) enctype_names[x] + +#endif /* !_TELNET_H_ */ diff --git a/mechglue/src/windows/wintel/telopts.h b/mechglue/src/windows/wintel/telopts.h new file mode 100644 index 000000000..54d67cde3 --- /dev/null +++ b/mechglue/src/windows/wintel/telopts.h @@ -0,0 +1,164 @@ +/* + * telopts.h + * Used for telnet options + **************************************************************************** + * * + * * + * NCSA Telnet * + * by Tim Krauskopf, VT100 by Gaige Paulsen, Tek by Aaron Contorer * + * Additions by Kurt Mahan, Heeren Pathak, & Quincey Koziol * + * * + * National Center for Supercomputing Applications * + * 152 Computing Applications Building * + * 605 E. Springfield Ave. * + * Champaign, IL 61820 * + * * + **************************************************************************** + * Quincey Koziol + * Defines for telnet options and related things + */ + +#ifndef TELOPTS_H +#define TELOPTS_H + +#define NUMLMODEOPTIONS 30 + +/* Definitions for telnet protocol */ + +#define STNORM 0 + +/* Definition of the lowest telnet byte following an IAC byte */ +#define LOW_TEL_OPT 236 + +#define TEL_EOF 236 +#define SUSP 237 +#define ABORT 238 + +#define SE 240 +#define NOP 241 +#define DM 242 +#define BREAK 243 +#define IP 244 +#define AO 245 +#define AYT 246 +#define EC 247 +#define EL 248 +#define GOAHEAD 249 +#define SB 250 +#define WILLTEL 251 +#define WONTTEL 252 +#define DOTEL 253 +#define DONTTEL 254 +#define IAC 255 + +/* Assigned Telnet Options */ +#define BINARY 0 +#define ECHO 1 +#define RECONNECT 2 +#define SGA 3 +#define AMSN 4 +#define STATUS 5 +#define TIMING 6 +#define RCTAN 7 +#define OLW 8 +#define OPS 9 +#define OCRD 10 +#define OHTS 11 +#define OHTD 12 +#define OFFD 13 +#define OVTS 14 +#define OVTD 15 +#define OLFD 16 +#define XASCII 17 +#define LOGOUT 18 +#define BYTEM 19 +#define DET 20 +#define SUPDUP 21 +#define SUPDUPOUT 22 +#define SENDLOC 23 +#define TERMTYPE 24 +#define EOR 25 +#define TACACSUID 26 +#define OUTPUTMARK 27 +#define TERMLOCNUM 28 +#define REGIME3270 29 +#define X3PAD 30 +#define NAWS 31 +#define TERMSPEED 32 +#define TFLOWCNTRL 33 +#define LINEMODE 34 + +#define MODE 1 +#define MODE_EDIT 1 +#define MODE_TRAPSIG 2 +#define MODE_ACK 4 +#define MODE_SOFT_TAB 8 +#define MODE_LIT_ECHO 16 + +#define FORWARDMASK 2 + +#define SLC 3 +#define SLC_DEFAULT 3 +#define SLC_VALUE 2 +#define SLC_CANTCHANGE 1 +#define SLC_NOSUPPORT 0 +#define SLC_LEVELBITS 3 + +#define SLC_ACK 128 +#define SLC_FLUSHIN 64 +#define SLC_FLUSHOUT 32 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 +#define SLC_MCL 19 +#define SLC_MCR 20 +#define SLC_MCWL 21 +#define SLC_MCWR 22 +#define SLC_MCBOL 23 +#define SLC_MCEOL 24 +#define SLC_INSRT 25 +#define SLC_OVER 26 +#define SLC_ECR 27 +#define SLC_EWR 28 +#define SLC_EBOL 29 +#define SLC_EEOL 30 + +#define XDISPLOC 35 +#define ENVIRONMENT 36 +#define AUTHENTICATION 37 +#define TELOPT_AUTHENTICATION AUTHENTICATION +#define DATA_ENCRYPTION 38 +#define XOPTIONS 255 + +#define LINEMODE_MODES_SUPPORTED 0x1B +/* + * set this flag for linemode special functions which are supported by + * Telnet, even though they are not currently active. This is to allow + * the other side to negotiate to a "No Support" state for an option + * and then change later to supporting it, so we know it's ok to change + * our "No Support" state to something else ("Can't Change", "Value", + * whatever) + */ +#define SLC_SUPPORTED 0x10 + +#define ESCFOUND 5 +#define IACFOUND 6 +#define NEGOTIATE 1 + +#endif /* telopts.h */ diff --git a/mechglue/src/windows/wintel/terminal.ico b/mechglue/src/windows/wintel/terminal.ico new file mode 100644 index 0000000000000000000000000000000000000000..7ec59e980f2318ce2d830297ae2bc2813aa3ddb6 GIT binary patch literal 766 zcmb_aF%rTs3{!zSMl-RJk!SF<{H%EjBV$IkAhlPpbKQayIg#x|aj(F{k<taS*8#Y4 zy%ULe5ED-HKxS^=W`Gm(ye{<IqLhN1GZSr@XiYnULm|0;n>DN7S*7OqBK8Zc+C3kC z5gTig_GXTlI`0aqFW_;D1*HCfsOLeBDSsJD0|jaL@|_e|5Z@n<vk^7u`We{jrp+>c YHID)upTL=o+8elO6<2%&+nv(=0AA{XzyJUM literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/wintel/wt-proto.h b/mechglue/src/windows/wintel/wt-proto.h new file mode 100644 index 000000000..15b9c1a8e --- /dev/null +++ b/mechglue/src/windows/wintel/wt-proto.h @@ -0,0 +1,63 @@ +/* wt-proto.h */ +BOOL +InitApplication( + HINSTANCE + ); + +BOOL +InitInstance( + HINSTANCE, + int + ); + +LRESULT +CALLBACK +MainWndProc( + HWND, + UINT, + WPARAM, + LPARAM + ); + +INT_PTR +CALLBACK +OpenTelnetDlg( + HWND, + UINT, + WPARAM, + LPARAM + ); + +int +TelnetSend( + kstream, + char *, + int, + int + ); + +int +OpenTelnetConnection( + void + ); + +int +DoDialog( + char *szDialog, + DLGPROC lpfnDlgProc + ); + +BOOL +parse_cmdline( + char *cmdline + ); + +CONNECTION * +GetNewConnection( + void + ); + +void +start_negotiation( + kstream ks + ); -- 2.26.2

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 z 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¬3+6fAnPI1&RW!Qs4;$7+^s{$Uq3Flau@v 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 ZSMC)qtDcwp>hCP;=4ChObK-O0e*o9!c)I`q literal 0 HcmV?d00001 diff --git a/mechglue/src/windows/identity/doc/netidmgr.pdf b/mechglue/src/windows/identity/doc/netidmgr.pdf new file mode 100755 index 0000000000000000000000000000000000000000..0e6ab029768c0915b8890b341cbc6dfa401c3634 GIT binary patch literal 1070358 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%0D*V3ZU^y7#8nxRM`Ms%tA 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